libmf 0.2.4 → 0.2.5

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: ca5a2bbda585f7e2f57630d20dfb6cf6091ab33e90227edd277c457af7f8dac7
4
- data.tar.gz: 3f8a1612c831223e552cf5af4172f31080d297f2e3f059624d66790613333890
3
+ metadata.gz: 499cc67221be5e767caa7257e69c23a2b17c537c5950e2eeebb7de21d5bec1f0
4
+ data.tar.gz: 9345dc3804dfc928bbdb03b588e64f20fbb3ddb5a3674b65972c122842bef60e
5
5
  SHA512:
6
- metadata.gz: 6d8cf1bf142c4e365c2b01a10c5e407d331d24d8410f8ee2b262c6ca6c94dfe129c5ac0a3dc6ae97e0739884aaeec9483c39546714975a8e9929c8a63799f15c
7
- data.tar.gz: 80356261c846d506160df89424b9f67d070908e1cc1f9c583e83cbbec5b7ebce272acb5146e447dd1394bb7c5d3268bf00837dc0814eb5ccb23d8c23c53efae3
6
+ metadata.gz: 6cd517a3e7eb418390012352a62de72aa9e3a4077b08c5d8602e89a9a8af0dcdc654a51359641e374d263804189a814afffa8e2f55db52ef7506e222e2143e5f
7
+ data.tar.gz: 5dad62dd22cd82499d4f0c2b2c06792945c50065a2517d89baeec8d00c62e2628d62d3702cc3964344c3e437f4281afd1f79f58291efca12f3c788e5ed07d0e1
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.2.5 (2021-10-18)
2
+
3
+ - Added named loss functions
4
+ - Added `Matrix` class
5
+ - Improved error checking for `fit`, `cv`, `save_model`, and `load_model`
6
+
1
7
  ## 0.2.4 (2021-08-05)
2
8
 
3
9
  - Fixed memory leak
data/README.md CHANGED
@@ -90,7 +90,7 @@ Pass parameters - default values below
90
90
 
91
91
  ```ruby
92
92
  Libmf::Model.new(
93
- loss: 0, # loss function
93
+ loss: :real_l2, # loss function
94
94
  factors: 8, # number of latent factors
95
95
  threads: 12, # number of threads used
96
96
  bins: 25, # number of bins
@@ -111,21 +111,21 @@ Libmf::Model.new(
111
111
 
112
112
  For real-valued matrix factorization
113
113
 
114
- - 0 - squared error (L2-norm)
115
- - 1 - absolute error (L1-norm)
116
- - 2 - generalized KL-divergence
114
+ - `:real_l2` - squared error (L2-norm)
115
+ - `:real_l1` - absolute error (L1-norm)
116
+ - `:real_kl` - generalized KL-divergence
117
117
 
118
118
  For binary matrix factorization
119
119
 
120
- - 5 - logarithmic error
121
- - 6 - squared hinge loss
122
- - 7 - hinge loss
120
+ - `:binary_log` - logarithmic error
121
+ - `:binary_l2` - squared hinge loss
122
+ - `:binary_l1` - hinge loss
123
123
 
124
124
  For one-class matrix factorization
125
125
 
126
- - 10 - row-oriented pair-wise logarithmic loss
127
- - 11 - column-oriented pair-wise logarithmic loss
128
- - 12 - squared error (L2-norm)
126
+ - `:one_class_row` - row-oriented pair-wise logarithmic loss
127
+ - `:one_class_col` - column-oriented pair-wise logarithmic loss
128
+ - `:one_class_l2` - squared error (L2-norm)
129
129
 
130
130
  ## Performance
131
131
 
@@ -0,0 +1,13 @@
1
+ module Libmf
2
+ class Matrix
3
+ attr_reader :data
4
+
5
+ def initialize
6
+ @data = []
7
+ end
8
+
9
+ def push(row_index, column_index, value)
10
+ @data << [row_index, column_index, value]
11
+ end
12
+ end
13
+ end
data/lib/libmf/model.rb CHANGED
@@ -14,6 +14,7 @@ module Libmf
14
14
  else
15
15
  FFI.mf_train(train_set, param)
16
16
  end
17
+ raise Error, "fit failed" if @model.null?
17
18
 
18
19
  nil
19
20
  end
@@ -24,15 +25,20 @@ module Libmf
24
25
 
25
26
  def cv(data, folds: 5)
26
27
  problem = create_problem(data)
27
- FFI.mf_cross_validation(problem, folds, param)
28
+ # TODO update fork to differentiate between bad parameters and zero error
29
+ res = FFI.mf_cross_validation(problem, folds, param)
30
+ raise Error, "cv failed" if res == 0
31
+ res
28
32
  end
29
33
 
30
34
  def save_model(path)
31
- FFI.mf_save_model(model, path)
35
+ status = FFI.mf_save_model(model, path)
36
+ raise Error, "Cannot save model" if status != 0
32
37
  end
33
38
 
34
39
  def load_model(path)
35
40
  @model = FFI.mf_load_model(path)
41
+ raise Error, "Cannot open model" if @model.null?
36
42
  end
37
43
 
38
44
  def rows
@@ -80,6 +86,22 @@ module Libmf
80
86
  def param
81
87
  param = FFI.mf_get_default_param
82
88
  options = @options.dup
89
+
90
+ if options[:loss].is_a?(Symbol)
91
+ loss_map = {
92
+ real_l2: 0,
93
+ real_l1: 1,
94
+ real_kl: 2,
95
+ binary_log: 5,
96
+ binary_l2: 6,
97
+ binary_l1: 7,
98
+ one_class_row: 10,
99
+ one_class_col: 11,
100
+ one_class_l2: 12
101
+ }
102
+ options[:loss] = loss_map[options[:loss]] || (raise ArgumentError, "Unknown loss")
103
+ end
104
+
83
105
  # silence insufficient blocks warning with default params
84
106
  options[:bins] ||= 25 unless options[:nr_bins]
85
107
  options[:copy_data] = false unless options.key?(:copy_data)
@@ -107,6 +129,10 @@ module Libmf
107
129
  return FFI.mf_read_problem(File.expand_path(data))
108
130
  end
109
131
 
132
+ if data.is_a?(Matrix)
133
+ data = data.data
134
+ end
135
+
110
136
  raise Error, "No data" if data.empty?
111
137
 
112
138
  # TODO do in C for better performance
data/lib/libmf/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Libmf
2
- VERSION = "0.2.4"
2
+ VERSION = "0.2.5"
3
3
  end
data/lib/libmf.rb CHANGED
@@ -2,6 +2,7 @@
2
2
  require "ffi"
3
3
 
4
4
  # modules
5
+ require "libmf/matrix"
5
6
  require "libmf/model"
6
7
  require "libmf/version"
7
8
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libmf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-06 00:00:00.000000000 Z
11
+ date: 2021-10-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -35,6 +35,7 @@ files:
35
35
  - README.md
36
36
  - lib/libmf.rb
37
37
  - lib/libmf/ffi.rb
38
+ - lib/libmf/matrix.rb
38
39
  - lib/libmf/model.rb
39
40
  - lib/libmf/version.rb
40
41
  - vendor/COPYRIGHT