cmfrec 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +11 -11
- data/lib/cmfrec/recommender.rb +46 -18
- data/lib/cmfrec/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2091fae505c3d98468c6cfa08e0f80c6e97804fe8558bea97191336fa0179423
|
4
|
+
data.tar.gz: b66cece9f8659a6f79ac6ee302a1d2068d9a8b89b8903b2182f0fa8be6838869
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5feed4c89f6249646b61d0713bcbc83725561942437ba3abdf2ca70a82a8f76d4a614b4f47a2c07e158a7155442f31b730b1d759234520bd34e50cae7e723b16
|
7
|
+
data.tar.gz: 649ce14693b2b7cfcc6039d4e39d94c3e3dce695e32b62f6c8c94c2751621622c519e5b536c917446e781b1acbadd3a511789efaae3ffc4aa2062738697f975f
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -6,8 +6,6 @@
|
|
6
6
|
- Works with explicit and implicit feedback
|
7
7
|
- Uses high-performance matrix factorization
|
8
8
|
|
9
|
-
Not available for Windows yet
|
10
|
-
|
11
9
|
[](https://github.com/ankane/cmfrec/actions)
|
12
10
|
|
13
11
|
## Installation
|
@@ -18,6 +16,8 @@ Add this line to your application’s Gemfile:
|
|
18
16
|
gem 'cmfrec'
|
19
17
|
```
|
20
18
|
|
19
|
+
Not available for Windows yet
|
20
|
+
|
21
21
|
## Getting Started
|
22
22
|
|
23
23
|
Create a recommender
|
@@ -48,7 +48,7 @@ recommender.fit([
|
|
48
48
|
|
49
49
|
> Use `value` instead of rating for implicit feedback
|
50
50
|
|
51
|
-
Get recommendations
|
51
|
+
Get recommendations for a user in the training data
|
52
52
|
|
53
53
|
```ruby
|
54
54
|
recommender.user_recs(user_id)
|
@@ -69,10 +69,10 @@ Use the `count` option to specify the number of recommendations (default is 5)
|
|
69
69
|
recommender.user_recs(user_id, count: 3)
|
70
70
|
```
|
71
71
|
|
72
|
-
Get predicted ratings for specific items
|
72
|
+
Get predicted ratings for specific users and items
|
73
73
|
|
74
74
|
```ruby
|
75
|
-
recommender.
|
75
|
+
recommender.predict([{user_id: 1, item_id: 2}, {user_id: 2, item_id: 4}])
|
76
76
|
```
|
77
77
|
|
78
78
|
## Side Information
|
@@ -81,12 +81,12 @@ Add side information about users, items, or both
|
|
81
81
|
|
82
82
|
```ruby
|
83
83
|
user_info = [
|
84
|
-
{user_id: 1,
|
85
|
-
{user_id: 2,
|
84
|
+
{user_id: 1, cats: 1, dogs: 0},
|
85
|
+
{user_id: 2, cats: 2, dogs: 1},
|
86
86
|
]
|
87
87
|
item_info = [
|
88
|
-
{item_id: 1,
|
89
|
-
{item_id: 2,
|
88
|
+
{item_id: 1, genre_comedy: 1, genre_drama: 0},
|
89
|
+
{item_id: 2, genre_comedy: 0, genre_drama: 1},
|
90
90
|
]
|
91
91
|
recommender.fit(ratings, user_info: user_info, item_info: item_info)
|
92
92
|
```
|
@@ -98,13 +98,13 @@ ratings = [
|
|
98
98
|
{item_id: 1, rating: 5},
|
99
99
|
{item_id: 2, rating: 3}
|
100
100
|
]
|
101
|
-
recommender.new_user_recs(ratings, user_info: {
|
101
|
+
recommender.new_user_recs(ratings, user_info: {cats: 0, dogs: 2})
|
102
102
|
```
|
103
103
|
|
104
104
|
Get recommendations with only side information
|
105
105
|
|
106
106
|
```ruby
|
107
|
-
recommender.new_user_recs([], user_info: {
|
107
|
+
recommender.new_user_recs([], user_info: {cats: 0, dogs: 2})
|
108
108
|
```
|
109
109
|
|
110
110
|
## Options
|
data/lib/cmfrec/recommender.rb
CHANGED
@@ -172,6 +172,49 @@ module Cmfrec
|
|
172
172
|
self
|
173
173
|
end
|
174
174
|
|
175
|
+
def predict(data)
|
176
|
+
check_fit
|
177
|
+
|
178
|
+
data = to_dataset(data)
|
179
|
+
|
180
|
+
u = data.map { |v| @user_map[v[:user_id]] || -1 }
|
181
|
+
i = data.map { |v| @item_map[v[:item_id]] || -1 }
|
182
|
+
|
183
|
+
pred_a = int_ptr(u)
|
184
|
+
pred_b = int_ptr(i)
|
185
|
+
nnz = data.size
|
186
|
+
outp = Fiddle::Pointer.malloc(nnz * Fiddle::SIZEOF_DOUBLE)
|
187
|
+
|
188
|
+
FFI.predict_multiple(
|
189
|
+
@a, @k_user,
|
190
|
+
@b, @k_item,
|
191
|
+
@bias_a, @bias_b,
|
192
|
+
@global_mean,
|
193
|
+
@k, @k_main,
|
194
|
+
@m, @n,
|
195
|
+
pred_a, pred_b, nnz,
|
196
|
+
outp,
|
197
|
+
@nthreads
|
198
|
+
)
|
199
|
+
|
200
|
+
predictions = real_array(outp)
|
201
|
+
|
202
|
+
nan_index = predictions.each_index.select { |j| predictions[j].nan? }
|
203
|
+
if nan_index.any?
|
204
|
+
# TODO improve performance
|
205
|
+
user_bias = send(:user_bias)
|
206
|
+
item_bias = send(:item_bias)
|
207
|
+
nan_index.each do |j|
|
208
|
+
v = @global_mean
|
209
|
+
v += user_bias[u[j]] if user_bias && u[j] != -1
|
210
|
+
v += item_bias[i[j]] if item_bias && i[j] != -1
|
211
|
+
predictions[j] = v
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
predictions
|
216
|
+
end
|
217
|
+
|
175
218
|
def user_recs(user_id, count: 5, item_ids: nil)
|
176
219
|
check_fit
|
177
220
|
user = @user_map[user_id]
|
@@ -181,24 +224,9 @@ module Cmfrec
|
|
181
224
|
# remove missing ids
|
182
225
|
item_ids = item_ids.select { |v| @item_map[v] }
|
183
226
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
outp = Fiddle::Pointer.malloc(nnz * Fiddle::SIZEOF_DOUBLE)
|
188
|
-
|
189
|
-
FFI.predict_multiple(
|
190
|
-
@a, @k_user,
|
191
|
-
@b, @k_item,
|
192
|
-
@bias_a, @bias_b,
|
193
|
-
@global_mean,
|
194
|
-
@k, @k_main,
|
195
|
-
@m, @n,
|
196
|
-
pred_a, pred_b, nnz,
|
197
|
-
outp,
|
198
|
-
@nthreads
|
199
|
-
)
|
200
|
-
|
201
|
-
scores = real_array(outp)
|
227
|
+
data = item_ids.map { |v| {user_id: user_id, item_id: v} }
|
228
|
+
scores = predict(data)
|
229
|
+
|
202
230
|
item_ids.zip(scores).map do |item_id, score|
|
203
231
|
{item_id: item_id, score: score}
|
204
232
|
end
|
data/lib/cmfrec/version.rb
CHANGED