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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2e9f45e0c3826b90788782ac8a0838476fc7849e75d91f2d5949b08b382a28c3
4
- data.tar.gz: 2f44b988001bf2b23e3c5938b4c5e7b9089e8943d86aa42c86e72be0ff558ea1
3
+ metadata.gz: 2091fae505c3d98468c6cfa08e0f80c6e97804fe8558bea97191336fa0179423
4
+ data.tar.gz: b66cece9f8659a6f79ac6ee302a1d2068d9a8b89b8903b2182f0fa8be6838869
5
5
  SHA512:
6
- metadata.gz: 592ef4363bc016da1a35a958f99dd13a0fc7e900ecbe77b3ba95fc4b4cbbe151397924ff90aab2e326ac3369ac07c0380c76b1d3a2ac71b390664118de0f8611
7
- data.tar.gz: 27d3e1ce80e88af9e8b062837f68329b10718372be15c08d4cd2e056619d1cd9e5ed906e6070798c32993ccea2f617b706af5e6afb7cba4f3cfc70ea22393ba6
6
+ metadata.gz: 5feed4c89f6249646b61d0713bcbc83725561942437ba3abdf2ca70a82a8f76d4a614b4f47a2c07e158a7155442f31b730b1d759234520bd34e50cae7e723b16
7
+ data.tar.gz: 649ce14693b2b7cfcc6039d4e39d94c3e3dce695e32b62f6c8c94c2751621622c519e5b536c917446e781b1acbadd3a511789efaae3ffc4aa2062738697f975f
@@ -1,3 +1,7 @@
1
+ ## 0.1.1 (2020-11-28)
2
+
3
+ - Added `predict` method
4
+
1
5
  ## 0.1.0 (2020-11-27)
2
6
 
3
7
  - First release
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 - “users like you also liked”
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.user_recs(user_id, item_ids: [1, 2, 3])
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, a: 1, b: 1},
85
- {user_id: 2, a: 1, b: 1},
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, c: 1, d: 1},
89
- {item_id: 2, c: 1, d: 1},
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: {a: 1, b: 1})
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: {a: 1, b: 1})
107
+ recommender.new_user_recs([], user_info: {cats: 0, dogs: 2})
108
108
  ```
109
109
 
110
110
  ## Options
@@ -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
- pred_a = int_ptr([@user_map[user_id]] * item_ids.size)
185
- pred_b = int_ptr(item_ids.map { |v| @item_map[v] })
186
- nnz = item_ids.size
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
@@ -1,3 +1,3 @@
1
1
  module Cmfrec
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cmfrec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane