Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 29 |
|
0.00% |
0 / 4 |
CRAP | |
0.00% |
0 / 1 |
BayesianPersonalizedRanking | |
0.00% |
0 / 29 |
|
0.00% |
0 / 4 |
110 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
generateRandomFactors | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
predict | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
updateFactors | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
30 |
1 | <?php |
2 | /** |
3 | * Jingga |
4 | * |
5 | * PHP Version 8.1 |
6 | * |
7 | * @package phpOMS\Business\Recommendation |
8 | * @copyright Dennis Eichhorn |
9 | * @license OMS License 2.0 |
10 | * @version 1.0.0 |
11 | * @link https://jingga.app |
12 | */ |
13 | declare(strict_types=1); |
14 | |
15 | namespace phpOMS\Business\Recommendation; |
16 | |
17 | /** |
18 | * Bayesian Personalized Ranking (BPR) |
19 | * |
20 | * @package phpOMS\Business\Recommendation |
21 | * @license OMS License 2.0 |
22 | * @link https://jingga.app |
23 | * @see https://arxiv.org/ftp/arxiv/papers/1205/1205.2618.pdf |
24 | * @since 1.0.0 |
25 | * |
26 | * @todo Implement, current implementation probably wrong |
27 | */ |
28 | final class BayesianPersonalizedRanking |
29 | { |
30 | private int $numFactors; |
31 | |
32 | private float $learningRate; |
33 | |
34 | private float $regularization; |
35 | |
36 | private array $userFactors = []; |
37 | |
38 | private array $itemFactors = []; |
39 | |
40 | // num_factors determines the dimensionality of the latent factor space. |
41 | // learning_rate controls the step size for updating the latent factors during optimization. |
42 | // regularization prevents overfitting by adding a penalty for large parameter values. |
43 | public function __construct(int $numFactors, float $learningRate, float $regularization) |
44 | { |
45 | $this->numFactors = $numFactors; |
46 | $this->learningRate = $learningRate; |
47 | $this->regularization = $regularization; |
48 | } |
49 | |
50 | private function generateRandomFactors() |
51 | { |
52 | $factors = []; |
53 | for ($i = 0; $i < $this->numFactors; ++$i) { |
54 | $factors[$i] = \mt_rand() / \mt_getrandmax(); |
55 | } |
56 | |
57 | return $factors; |
58 | } |
59 | |
60 | public function predict($userId, $itemId) { |
61 | $userFactor = $this->userFactors[$userId]; |
62 | $itemFactor = $this->itemFactors[$itemId]; |
63 | $score = 0; |
64 | |
65 | for ($i = 0; $i < $this->numFactors; ++$i) { |
66 | $score += $userFactor[$i] * $itemFactor[$i]; |
67 | } |
68 | |
69 | return $score; |
70 | } |
71 | |
72 | public function updateFactors($userId, $posItemId, $negItemId) : void |
73 | { |
74 | if (!isset($this->userFactors[$userId])) { |
75 | $this->userFactors[$userId] = $this->generateRandomFactors(); |
76 | } |
77 | |
78 | if (!isset($this->itemFactors[$posItemId])) { |
79 | $this->itemFactors[$posItemId] = $this->generateRandomFactors(); |
80 | } |
81 | |
82 | if (!isset($this->itemFactors[$negItemId])) { |
83 | $this->itemFactors[$negItemId] = $this->generateRandomFactors(); |
84 | } |
85 | |
86 | $userFactor = $this->userFactors[$userId]; |
87 | $posItemFactor = $this->itemFactors[$posItemId]; |
88 | $negItemFactor = $this->itemFactors[$negItemId]; |
89 | |
90 | for ($i = 0; $i < $this->numFactors; ++$i) { |
91 | $userFactor[$i] += $this->learningRate * ($posItemFactor[$i] - $negItemFactor[$i]) - $this->regularization * $userFactor[$i]; |
92 | $posItemFactor[$i] += $this->learningRate * $userFactor[$i] - $this->regularization * $posItemFactor[$i]; |
93 | $negItemFactor[$i] += $this->learningRate * (-$userFactor[$i]) - $this->regularization * $negItemFactor[$i]; |
94 | } |
95 | |
96 | $this->userFactors[$userId] = $userFactor; |
97 | $this->itemFactors[$posItemId] = $posItemFactor; |
98 | $this->itemFactors[$negItemId] = $negItemFactor; |
99 | } |
100 | } |