cmfrec 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://github.com/ankane/cmfrec/workflows/build/badge.svg?branch=master)](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