Skip to content

Commit 714128f

Browse files
authored
Add an integration test & Update docs (#5)
1 parent 43b5ab1 commit 714128f

File tree

8 files changed

+117
-60
lines changed

8 files changed

+117
-60
lines changed

.github/workflows/cron.yml

+1-4
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,11 @@ jobs:
1717
name: PHP${{ matrix.php }} - ${{ matrix.stability }} - ${{ matrix.os }}
1818

1919
steps:
20-
- name: Checkout code
21-
uses: actions/checkout@v2
22-
2320
- name: Setup PHP
2421
uses: shivammathur/setup-php@v2
2522
with:
2623
php-version: ${{ matrix.php }}
2724
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap
2825

2926
- name: Install package
30-
run: composer require phpjuice/opencf
27+
run: composer global require phpjuice/opencf

README.md

+23-24
Original file line numberDiff line numberDiff line change
@@ -43,29 +43,28 @@ Adding a dataset to the recommender can be done using the constructor or can be
4343
users ratings via the `setDataset()` method:
4444

4545
```php
46-
47-
$dataset =[
48-
[
49-
"squid" => 1,
50-
"cuttlefish" => 0.5,
51-
"octopus" => 0.2
52-
],
53-
[
54-
"squid" => 1,
55-
"octopus" => 0.5,
56-
"nautilus" => 0.2
57-
],
58-
[
59-
"squid" => 0.2,
60-
"octopus" => 1,
61-
"cuttlefish" => 0.4,
62-
"nautilus" => 0.4
63-
],
64-
[
65-
"cuttlefish" => 0.9,
66-
"octopus" => 0.4,
67-
"nautilus" => 0.5
68-
]
46+
$dataset = [
47+
"squid" => [
48+
"user1" => 1,
49+
"user2" => 1,
50+
"user3" => 0.2,
51+
],
52+
"cuttlefish" => [
53+
"user1" => 0.5,
54+
"user3" => 0.4,
55+
"user4" => 0.9,
56+
],
57+
"octopus" => [
58+
"user1" => 0.2,
59+
"user2" => 0.5,
60+
"user3" => 1,
61+
"user4" => 0.4,
62+
],
63+
"nautilus" => [
64+
"user2" => 0.2,
65+
"user3" => 0.4,
66+
"user4" => 0.5,
67+
],
6968
];
7069

7170
$recommenderService->setDataset($dataset);
@@ -95,7 +94,7 @@ This should produce the following results when using `WeightedSlopeone` recommen
9594
```php
9695
[
9796
"cuttlefish" => 0.25,
98-
"octopus" => 0.23333333333333,
97+
"octopus" => 0.23,
9998
"nautilus" => 0.1
10099
];
101100
```

src/Algorithms/Recommender.php

+13-17
Original file line numberDiff line numberDiff line change
@@ -8,41 +8,29 @@
88
use OpenCF\Contracts\IRecommender;
99
use OpenCF\Contracts\ISimilarity;
1010
use OpenCF\Contracts\IVector;
11+
use OpenCF\Exceptions\EmptyDatasetException;
12+
use OpenCF\Exceptions\EmptyModelException;
1113
use OpenCF\Support\Vector;
1214

1315
abstract class Recommender implements IRecommender
1416
{
15-
/**
16-
* training set.
17-
*
18-
* @var array[][]
19-
*/
17+
/** @var array */
2018
protected array $dataset;
2119

22-
/**
23-
* model.
24-
*
25-
* @var array[][]
26-
*/
20+
/** @var array|null */
2721
protected ?array $model;
2822

2923
/**
30-
* a measure function to calculate similarity.
31-
*
3224
* @var ISimilarity
3325
*/
3426
protected ISimilarity $similarityFunction;
3527

3628
/**
37-
* Predictor.
38-
*
3929
* @var IPredictor
4030
*/
4131
protected IPredictor $predictor;
4232

4333
/**
44-
* vector calculations provider.
45-
*
4634
* @var IVector
4735
*/
4836
protected IVector $vector;
@@ -63,6 +51,10 @@ public function __construct(
6351
/** @inheritdoc */
6452
public function buildModel(): self
6553
{
54+
if (empty($this->dataset)) {
55+
throw new EmptyDatasetException();
56+
}
57+
6658
foreach ($this->dataset as $k1 => $r1) {
6759
foreach ($this->dataset as $k2 => $r2) {
6860
// if we are comparing the item
@@ -92,8 +84,12 @@ public function buildModel(): self
9284
/** @inheritdoc */
9385
public function predict(array $userRatings): array
9486
{
87+
if (empty($this->model)) {
88+
throw new EmptyModelException();
89+
}
90+
9591
$predictions = [];
96-
foreach ($this->model ?? [] as $key => $items) {
92+
foreach ($this->model as $key => $items) {
9793
// if the rating is present in the
9894
// evaluation given by the user we skip
9995
if (isset($userRatings[$key])) {

src/Algorithms/Slopeone/WeightedSlopeone.php

+1-3
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66

77
class WeightedSlopeone extends Recommender
88
{
9-
/**
10-
* @inheritdoc
11-
*/
9+
/** @inheritdoc */
1210
public function name(): string
1311
{
1412
return 'WeightedSlopeone';
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace OpenCF\Exceptions;
4+
5+
use InvalidArgumentException;
6+
7+
class EmptyModelException extends InvalidArgumentException
8+
{
9+
}

tests/Algorithms/Slopeone/WeightedSlopeoneTest.php

+12-12
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@
7979
'Hulk' => 2,
8080
];
8181
$expected = [
82-
'Batman V Superman' => 2,
82+
'Batman V Superman' => 2.0,
8383
];
84-
expect($scheme->predict($user1))->toEqual($expected);
84+
expect($scheme->predict($user1))->toBe($expected);
8585

8686
$user2 = [
8787
'Batman V Superman' => 2,
@@ -92,7 +92,7 @@
9292
$expected = [
9393
'Avatar' => 2.13,
9494
];
95-
expect($scheme->predict($user2))->toEqual($expected);
95+
expect($scheme->predict($user2))->toBe($expected);
9696

9797
$user3 = [
9898
'Batman V Superman' => 5,
@@ -103,7 +103,7 @@
103103
$expected = [
104104
'Iron Man' => 3.88,
105105
];
106-
expect($scheme->predict($user3))->toEqual($expected);
106+
expect($scheme->predict($user3))->toBe($expected);
107107

108108
$user4 = [
109109
'Batman V Superman' => 5,
@@ -112,9 +112,9 @@
112112
'Hulk' => 4,
113113
];
114114
$expected = [
115-
'Spider man' => 4,
115+
'Spider man' => 4.0,
116116
];
117-
expect($scheme->predict($user4))->toEqual($expected);
117+
expect($scheme->predict($user4))->toBe($expected);
118118

119119
$user5 = [
120120
'Batman V Superman' => 5,
@@ -125,7 +125,7 @@
125125
$expected = [
126126
'Hulk' => 3.75,
127127
];
128-
expect($scheme->predict($user5))->toEqual($expected);
128+
expect($scheme->predict($user5))->toBe($expected);
129129

130130
$user6 = [
131131
'Avatar' => 4,
@@ -136,7 +136,7 @@
136136
$expected = [
137137
'Batman V Superman' => 4.25,
138138
];
139-
expect($scheme->predict($user6))->toEqual($expected);
139+
expect($scheme->predict($user6))->toBe($expected);
140140

141141
$user7 = [
142142
'Batman V Superman' => 1,
@@ -147,7 +147,7 @@
147147
$expected = [
148148
'Avatar' => 2.88,
149149
];
150-
expect($scheme->predict($user7))->toEqual($expected);
150+
expect($scheme->predict($user7))->toBe($expected);
151151

152152
$user8 = [
153153
'Batman V Superman' => 3,
@@ -158,7 +158,7 @@
158158
$expected = [
159159
'Iron Man' => 2.13,
160160
];
161-
expect($scheme->predict($user8))->toEqual($expected);
161+
expect($scheme->predict($user8))->toBe($expected);
162162

163163
$user8 = [
164164
'Batman V Superman' => 2,
@@ -169,7 +169,7 @@
169169
$expected = [
170170
'Spider man' => 2.75,
171171
];
172-
expect($scheme->predict($user8))->toEqual($expected);
172+
expect($scheme->predict($user8))->toBe($expected);
173173

174174
$user10 = [
175175
'Batman V Superman' => 4,
@@ -180,5 +180,5 @@
180180
$expected = [
181181
'Hulk' => 3.25,
182182
];
183-
expect($scheme->predict($user10))->toEqual($expected);
183+
expect($scheme->predict($user10))->toBe($expected);
184184
});

tests/IntegrationTest.php

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
use OpenCF\RecommenderService;
4+
5+
it('tests predictions with real data', function () {
6+
$dataset = transpose([
7+
"user1" => [
8+
"squid" => 1,
9+
"cuttlefish" => 0.5,
10+
"octopus" => 0.2
11+
],
12+
"user2" => [
13+
"squid" => 1,
14+
"octopus" => 0.5,
15+
"nautilus" => 0.2
16+
],
17+
"user3" => [
18+
"squid" => 0.2,
19+
"octopus" => 1,
20+
"cuttlefish" => 0.4,
21+
"nautilus" => 0.4
22+
],
23+
"user4" => [
24+
"cuttlefish" => 0.9,
25+
"octopus" => 0.4,
26+
"nautilus" => 0.5
27+
]
28+
]);
29+
30+
// Create an instance
31+
$recommenderService = new RecommenderService($dataset);
32+
33+
// Get a recommender
34+
$recommender = $recommenderService->weightedSlopeone();
35+
36+
// Predict future ratings
37+
$results = $recommender->predict([
38+
'squid' => 0.4
39+
]);
40+
41+
expect($results)->toBe([
42+
"cuttlefish" => 0.25,
43+
"octopus" => 0.23,
44+
"nautilus" => 0.1
45+
]);
46+
});

tests/Pest.php

+12
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,15 @@
3434
| global functions to help you to reduce the number of lines of code in your test files.
3535
|
3636
*/
37+
function transpose(array $dataset): array
38+
{
39+
$transposed = [];
40+
41+
foreach ($dataset as $item => $ratings) {
42+
foreach ($ratings as $key => $value) {
43+
$transposed[$key][$item] = $value;
44+
}
45+
}
46+
47+
return $transposed;
48+
}

0 commit comments

Comments
 (0)