rumale-svm 0.7.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ec0ef314d44123fa222655004b099652d244c7fb9bea73569a4fe701974e43b1
4
- data.tar.gz: ccaca04e1b3fe7691467a26a678f8978bc2f77e5a1b2e094b1af08923779588b
3
+ metadata.gz: 8853a60f150df418c30832c66b04f6531a1f3fa16f96ed3cb2286ca88a553dbe
4
+ data.tar.gz: aded967a3b1f82ded39b07ef3e1f435959f26c8d8392fb212acee3fcd006366f
5
5
  SHA512:
6
- metadata.gz: 44b1ab01d131133ef5d9fb32ae4dfaff5ca1187e45c5a1b4f4ec3b198f515020baf85b5bb4a1bb110ae6e85d74f521af86661b4741a63828bd49288a138c9513
7
- data.tar.gz: af83ab927ed5fbd630880b51fa2a0bf25c9aaad066a603d1ce6bf178c873ed669461eb46cdb23003b888799f11a5114fdf5405288d8129783c9495ec74799fd5
6
+ metadata.gz: 3f2ff48c445b9b5cfc804a17acb3f0c2563512eca01482c81c18fa8e662f9855e45abaede8ab5d7a8b087de84c131f2863f730d0313374b6af97480509fdd18f
7
+ data.tar.gz: 53747b28e162327cb11a9a5db9343d6baaad09e636909d8149c8ced58ba930a757b6251252968ddc7a7187c651abc56fb0ed046fde3ec6fcdc6a0d718404f420
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ # 0.9.0
2
+ - Add Rumale::SVM::LocallyLinearSVC that is classifier with locally linear support vector machine.
3
+
4
+ # 0.8.0
5
+ - Refactor to support the new Rumale API.
6
+
1
7
  # 0.7.0
2
8
  - Support for probabilistic outputs with Rumale::SVM::OneClassSVM.
3
9
  - Update numo-libsvm depedency to v2.1 or higher.
@@ -6,7 +12,7 @@
6
12
  - Update numo-libsvm and numo-liblinear depedency to v2.0 or higher.
7
13
 
8
14
  # 0.5.1
9
- - Refator specs and config files.
15
+ - Refactor specs and config files.
10
16
 
11
17
  # 0.5.0
12
18
  - Add type declaration files.
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2019-2022 Atsushi Tatsuma
1
+ Copyright (c) 2019-2023 Atsushi Tatsuma
2
2
  All rights reserved.
3
3
 
4
4
  Redistribution and use in source and binary forms, with or without
data/README.md CHANGED
@@ -1,18 +1,13 @@
1
1
  # Rumale::SVM
2
2
 
3
3
  [![Build Status](https://github.com/yoshoku/rumale-svm/workflows/build/badge.svg)](https://github.com/yoshoku/rumale-svm/actions?query=workflow%3Abuild)
4
- [![Coverage Status](https://coveralls.io/repos/github/yoshoku/rumale-svm/badge.svg?branch=main)](https://coveralls.io/github/yoshoku/rumale-svm?branch=main)
5
4
  [![Gem Version](https://badge.fury.io/rb/rumale-svm.svg)](https://badge.fury.io/rb/rumale-svm)
6
5
  [![BSD 3-Clause License](https://img.shields.io/badge/License-BSD%203--Clause-orange.svg)](https://github.com/yoshoku/rumale-svm/blob/main/LICENSE.txt)
7
6
  [![Documentation](https://img.shields.io/badge/api-reference-blue.svg)](https://yoshoku.github.io/rumale-svm/doc/)
8
7
 
9
- Rumale::SVM provides support vector machine algorithms in
8
+ Rumale::SVM provides support vector machine algorithms using
10
9
  [LIBSVM](https://www.csie.ntu.edu.tw/~cjlin/libsvm/) and [LIBLINEAR](https://www.csie.ntu.edu.tw/~cjlin/liblinear/)
11
10
  with [Rumale](https://github.com/yoshoku/rumale) interface.
12
- Many machine learning libraries use LIBSVM and LIBLINEAR as background libraries of support vector machine algorithms.
13
- On the other hand, Rumale implements support vector machine algorithms based on the mini-batch stochastic gradient descent method
14
- implemented in Ruby.
15
- Rumale::SVM adds the functions of support vector machine similar to general machine learning libraries to Rumale.
16
11
 
17
12
  ## Installation
18
13
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'numo/liblinear'
4
- require 'rumale/base/base_estimator'
4
+ require 'rumale/base/estimator'
5
5
  require 'rumale/validation'
6
6
 
7
7
  module Rumale
@@ -12,10 +12,7 @@ module Rumale
12
12
  # estimator = Rumale::SVM::LinearOneClassSVM.new(nu: 0.05, random_seed: 1)
13
13
  # estimator.fit(training_samples, traininig_labels)
14
14
  # results = estimator.predict(testing_samples)
15
- class LinearOneClassSVM
16
- include Base::BaseEstimator
17
- include Validation
18
-
15
+ class LinearOneClassSVM < Rumale::Base::Estimator
19
16
  # Return the weight vector for LinearOneClassSVM.
20
17
  # @return [Numo::DFloat] (shape: [n_features])
21
18
  attr_reader :weight_vec
@@ -32,9 +29,7 @@ module Rumale
32
29
  # @param verbose [Boolean] The flag indicating whether to output learning process message
33
30
  # @param random_seed [Integer/Nil] The seed value using to initialize the random generator.
34
31
  def initialize(nu: 0.05, reg_param: 1.0, tol: 1e-3, verbose: false, random_seed: nil)
35
- check_params_numeric(nu: nu, reg_param: reg_param, tol: tol)
36
- check_params_boolean(verbose: verbose)
37
- check_params_numeric_or_nil(random_seed: random_seed)
32
+ super()
38
33
  @params = {}
39
34
  @params[:nu] = nu.to_f
40
35
  @params[:reg_param] = reg_param.to_f
@@ -50,7 +45,7 @@ module Rumale
50
45
  #
51
46
  # @return [LinearOneClassSVM] The learned estimator itself.
52
47
  def fit(x, _y = nil)
53
- x = check_convert_sample_array(x)
48
+ x = Rumale::Validation.check_convert_sample_array(x)
54
49
  dummy = Numo::DFloat.ones(x.shape[0])
55
50
  @model = Numo::Liblinear.train(x, dummy, liblinear_params)
56
51
  @weight_vec = @model[:w].dup
@@ -63,8 +58,8 @@ module Rumale
63
58
  # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to compute the scores.
64
59
  # @return [Numo::DFloat] (shape: [n_samples, n_classes]) Confidence score per sample.
65
60
  def decision_function(x)
66
- raise "#{self.class.name}\##{__method__} expects to be called after training the model with the fit method." unless trained?
67
- x = check_convert_sample_array(x)
61
+ raise "#{self.class.name}##{__method__} expects to be called after training the model with the fit method." unless trained?
62
+ x = Rumale::Validation.check_convert_sample_array(x)
68
63
  Numo::Liblinear.decision_function(x, liblinear_params, @model)
69
64
  end
70
65
 
@@ -73,8 +68,8 @@ module Rumale
73
68
  # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to predict the labels.
74
69
  # @return [Numo::Int32] (shape: [n_samples]) Predicted label per sample.
75
70
  def predict(x)
76
- raise "#{self.class.name}\##{__method__} expects to be called after training the model with the fit method." unless trained?
77
- x = check_convert_sample_array(x)
71
+ raise "#{self.class.name}##{__method__} expects to be called after training the model with the fit method." unless trained?
72
+ x = Rumale::Validation.check_convert_sample_array(x)
78
73
  Numo::Int32.cast(Numo::Liblinear.predict(x, liblinear_params, @model))
79
74
  end
80
75
 
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'numo/liblinear'
4
- require 'rumale/base/base_estimator'
4
+ require 'rumale/base/estimator'
5
5
  require 'rumale/base/classifier'
6
6
  require 'rumale/probabilistic_output'
7
+ require 'rumale/validation'
7
8
 
8
9
  module Rumale
9
10
  module SVM
@@ -13,9 +14,8 @@ module Rumale
13
14
  # estimator = Rumale::SVM::LinearSVC.new(penalty: 'l2', loss: 'squared_hinge', reg_param: 1.0, random_seed: 1)
14
15
  # estimator.fit(training_samples, traininig_labels)
15
16
  # results = estimator.predict(testing_samples)
16
- class LinearSVC
17
- include Base::BaseEstimator
18
- include Base::Classifier
17
+ class LinearSVC < Rumale::Base::Estimator
18
+ include Rumale::Base::Classifier
19
19
 
20
20
  # Return the weight vector for LinearSVC.
21
21
  # @return [Numo::DFloat] (shape: [n_classes, n_features])
@@ -43,10 +43,7 @@ module Rumale
43
43
  # @param random_seed [Integer/Nil] The seed value using to initialize the random generator.
44
44
  def initialize(penalty: 'l2', loss: 'squared_hinge', dual: true, reg_param: 1.0,
45
45
  fit_bias: true, bias_scale: 1.0, probability: false, tol: 1e-3, verbose: false, random_seed: nil)
46
- check_params_string(penalty: penalty, loss: loss)
47
- check_params_numeric(reg_param: reg_param, bias_scale: bias_scale, tol: tol)
48
- check_params_boolean(dual: dual, fit_bias: fit_bias, probability: probability, verbose: verbose)
49
- check_params_numeric_or_nil(random_seed: random_seed)
46
+ super()
50
47
  @params = {}
51
48
  @params[:penalty] = penalty == 'l1' ? 'l1' : 'l2'
52
49
  @params[:loss] = loss == 'hinge' ? 'hinge' : 'squared_hinge'
@@ -66,9 +63,9 @@ module Rumale
66
63
  # @param y [Numo::Int32] (shape: [n_samples]) The labels to be used for fitting the model.
67
64
  # @return [LinearSVC] The learned classifier itself.
68
65
  def fit(x, y)
69
- x = check_convert_sample_array(x)
70
- y = check_convert_label_array(y)
71
- check_sample_label_size(x, y)
66
+ x = Rumale::Validation.check_convert_sample_array(x)
67
+ y = Rumale::Validation.check_convert_label_array(y)
68
+ Rumale::Validation.check_sample_size(x, y)
72
69
  xx = fit_bias? ? expand_feature(x) : x
73
70
  @model = Numo::Liblinear.train(xx, y, liblinear_params)
74
71
  @weight_vec, @bias_term = weight_and_bias(@model[:w])
@@ -81,8 +78,8 @@ module Rumale
81
78
  # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to compute the scores.
82
79
  # @return [Numo::DFloat] (shape: [n_samples, n_classes]) Confidence score per sample.
83
80
  def decision_function(x)
84
- raise "#{self.class.name}\##{__method__} expects to be called after training the model with the fit method." unless trained?
85
- x = check_convert_sample_array(x)
81
+ raise "#{self.class.name}##{__method__} expects to be called after training the model with the fit method." unless trained?
82
+ x = Rumale::Validation.check_convert_sample_array(x)
86
83
  xx = fit_bias? ? expand_feature(x) : x
87
84
  Numo::Liblinear.decision_function(xx, liblinear_params, @model)
88
85
  end
@@ -92,8 +89,8 @@ module Rumale
92
89
  # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to predict the labels.
93
90
  # @return [Numo::Int32] (shape: [n_samples]) Predicted class label per sample.
94
91
  def predict(x)
95
- raise "#{self.class.name}\##{__method__} expects to be called after training the model with the fit method." unless trained?
96
- x = check_convert_sample_array(x)
92
+ raise "#{self.class.name}##{__method__} expects to be called after training the model with the fit method." unless trained?
93
+ x = Rumale::Validation.check_convert_sample_array(x)
97
94
  xx = fit_bias? ? expand_feature(x) : x
98
95
  Numo::Int32.cast(Numo::Liblinear.predict(xx, liblinear_params, @model))
99
96
  end
@@ -104,8 +101,8 @@ module Rumale
104
101
  # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to predict the probailities.
105
102
  # @return [Numo::DFloat] (shape: [n_samples, n_classes]) Predicted probability of each class per sample.
106
103
  def predict_proba(x)
107
- raise "#{self.class.name}\##{__method__} expects to be called after training the model with the fit method." unless trained?
108
- x = check_convert_sample_array(x)
104
+ raise "#{self.class.name}##{__method__} expects to be called after training the model with the fit method." unless trained?
105
+ x = Rumale::Validation.check_convert_sample_array(x)
109
106
  if binary_class?
110
107
  probs = Numo::DFloat.zeros(x.shape[0], 2)
111
108
  probs[true, 0] = 1.0 / (Numo::NMath.exp(@prob_param[0] * decision_function(x) + @prob_param[1]) + 1.0)
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'numo/libsvm'
4
- require 'rumale/base/base_estimator'
4
+ require 'rumale/base/estimator'
5
5
  require 'rumale/base/regressor'
6
+ require 'rumale/validation'
6
7
 
7
8
  module Rumale
8
9
  module SVM
@@ -12,9 +13,8 @@ module Rumale
12
13
  # estimator = Rumale::SVM::LinearSVR.new(reg_param: 1.0, random_seed: 1)
13
14
  # estimator.fit(training_samples, traininig_target_values)
14
15
  # results = estimator.predict(testing_samples)
15
- class LinearSVR
16
- include Base::BaseEstimator
17
- include Base::Regressor
16
+ class LinearSVR < Rumale::Base::Estimator
17
+ include Rumale::Base::Regressor
18
18
 
19
19
  # Return the weight vector for LinearSVR.
20
20
  # @return [Numo::DFloat] (shape: [n_classes, n_features])
@@ -40,10 +40,7 @@ module Rumale
40
40
  # @param random_seed [Integer/Nil] The seed value using to initialize the random generator.
41
41
  def initialize(loss: 'squared_epsilon_insensitive', dual: true, reg_param: 1.0, epsilon: 0.1,
42
42
  fit_bias: true, bias_scale: 1.0, tol: 1e-3, verbose: false, random_seed: nil)
43
- check_params_string(loss: loss)
44
- check_params_numeric(reg_param: reg_param, epsilon: epsilon, bias_scale: bias_scale, tol: tol)
45
- check_params_boolean(dual: dual, fit_bias: fit_bias, verbose: verbose)
46
- check_params_numeric_or_nil(random_seed: random_seed)
43
+ super()
47
44
  @params = {}
48
45
  @params[:loss] = loss == 'epsilon_insensitive' ? 'epsilon_insensitive' : 'squared_epsilon_insensitive'
49
46
  @params[:dual] = dual
@@ -62,9 +59,9 @@ module Rumale
62
59
  # @param y [Numo::DFloat] (shape: [n_samples]) The target values to be used for fitting the model.
63
60
  # @return [LinearSVR] The learned regressor itself.
64
61
  def fit(x, y)
65
- x = check_convert_sample_array(x)
66
- y = check_convert_tvalue_array(y)
67
- check_sample_tvalue_size(x, y)
62
+ x = Rumale::Validation.check_convert_sample_array(x)
63
+ y = Rumale::Validation.check_convert_target_value_array(y)
64
+ Rumale::Validation.check_sample_size(x, y)
68
65
  xx = fit_bias? ? expand_feature(x) : x
69
66
  @model = Numo::Liblinear.train(xx, y, liblinear_params)
70
67
  @weight_vec, @bias_term = weight_and_bias(@model[:w])
@@ -76,8 +73,8 @@ module Rumale
76
73
  # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to predict the labels.
77
74
  # @return [Numo::DFloat] (shape: [n_samples]) Predicted value per sample.
78
75
  def predict(x)
79
- raise "#{self.class.name}\##{__method__} expects to be called after training the model with the fit method." unless trained?
80
- x = check_convert_sample_array(x)
76
+ raise "#{self.class.name}##{__method__} expects to be called after training the model with the fit method." unless trained?
77
+ x = Rumale::Validation.check_convert_sample_array(x)
81
78
  xx = fit_bias? ? expand_feature(x) : x
82
79
  Numo::Liblinear.predict(xx, liblinear_params, @model)
83
80
  end
@@ -0,0 +1,261 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rumale/base/estimator'
4
+ require 'rumale/base/classifier'
5
+ require 'rumale/pairwise_metric'
6
+ require 'rumale/utils'
7
+ require 'rumale/validation'
8
+
9
+ module Rumale
10
+ module SVM
11
+ # LocallyLinearSVC is a class that implements Locally Linear Support Vector Classifier with the squared hinge loss.
12
+ # This classifier requires Numo::Linalg (or Numo::TinyLinalg) and Lbfgsb gems,
13
+ # but they are listed in the runtime dependencies of Rumale::SVM.
14
+ # Therefore, you should install and load Numo::Linalg and Lbfgsb gems explicitly to use this classifier.
15
+ #
16
+ # @example
17
+ # require 'numo/linalg/autoloader'
18
+ # require 'lbfgsb'
19
+ # require 'rumale/svm'
20
+ #
21
+ # estimator = Rumale::SVM::LocallyLinearSVC.new(reg_param: 1.0, n_anchors: 128)
22
+ # estimator.fit(training_samples, traininig_labels)
23
+ # results = estimator.predict(testing_samples)
24
+ #
25
+ # *Reference*
26
+ # - Ladicky, L., and Torr, P H.S., "Locally Linear Support Vector Machines," Proc. ICML'11, pp. 985--992, 2011.
27
+ class LocallyLinearSVC < Rumale::Base::Estimator
28
+ include Rumale::Base::Classifier
29
+
30
+ # Return the class labels.
31
+ # @return [Numo::Int32] (size: n_classes)
32
+ attr_reader :classes
33
+
34
+ # Return the anchor vectors.
35
+ # @return [Numo::DFloat] (shape: [n_anchors, n_features])
36
+ attr_reader :anchors
37
+
38
+ # Return the weight vector.
39
+ # @return [Numo::DFloat] (shape: [n_classes, n_anchors, n_features])
40
+ attr_reader :weight_vec
41
+
42
+ # Return the bias term (a.k.a. intercept).
43
+ # @return [Numo::DFloat] (shape: [n_classes, n_anchors])
44
+ attr_reader :bias_term
45
+
46
+ # Create a new classifier with Locally Linear Support Vector Machine.
47
+ #
48
+ # @param reg_param [Float] The regularization parameter for weight vector.
49
+ # @param reg_param_local [Float] The regularization parameter for local coordinate.
50
+ # @param max_iter [Integer] The maximum number of iterations.
51
+ # @param tol [Float] The tolerance of termination criterion for finding anchors with k-means algorithm.
52
+ # @param n_anchors [Integer] The number of anchors.
53
+ # @param n_neighbors [Integer] The number of neighbors.
54
+ # @param fit_bias [Boolean] The flag indicating whether to fit bias term.
55
+ # @param bias_scale [Float] The scale parameter for bias term.
56
+ # @param random_seed [Integer] The seed value using to initialize the random generator.
57
+ def initialize(reg_param: 1.0, reg_param_local: 1e-4, max_iter: 100, tol: 1e-4,
58
+ n_anchors: 128, n_neighbors: 10, fit_bias: true, bias_scale: 1.0, random_seed: nil)
59
+ raise 'LocallyLinearSVC requires Numo::Linalg but that is not loaded' unless enable_linalg?(warning: false)
60
+
61
+ super()
62
+ @params = {
63
+ reg_param: reg_param,
64
+ reg_param_local: reg_param_local,
65
+ max_iter: max_iter,
66
+ n_anchors: n_anchors,
67
+ tol: tol,
68
+ n_neighbors: n_neighbors,
69
+ fit_bias: fit_bias,
70
+ bias_scale: bias_scale,
71
+ random_seed: random_seed || srand
72
+ }
73
+ @rng = Random.new(@params[:random_seed])
74
+ end
75
+
76
+ # Fit the model with given training data.
77
+ #
78
+ # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The training data to be used for fitting the model.
79
+ # @param y [Numo::Int32] (shape: [n_samples]) The labels to be used for fitting the model.
80
+ # @return [LocallyLinearSVC] The learned classifier itself.
81
+ def fit(x, y)
82
+ x = Rumale::Validation.check_convert_sample_array(x)
83
+ y = Rumale::Validation.check_convert_label_array(y)
84
+ Rumale::Validation.check_sample_size(x, y)
85
+ raise 'LocallyLinearSVC#fit requires Lbfgsb but that is not loaded' unless defined?(Lbfgsb)
86
+
87
+ @classes = Numo::Int32[*y.to_a.uniq.sort]
88
+
89
+ find_anchors(x)
90
+ n_samples, n_features = x.shape
91
+ @coeff = Numo::DFloat.zeros(n_samples, @params[:n_anchors])
92
+ n_samples.times do |i|
93
+ xi = x[i, true]
94
+ @coeff[i, true] = local_coordinates(xi)
95
+ end
96
+
97
+ x = expand_feature(x) if fit_bias?
98
+
99
+ if multiclass_problem?
100
+ n_classes = @classes.size
101
+ @weight_vec = Numo::DFloat.zeros(n_classes, @params[:n_anchors], n_features)
102
+ @bias_term = Numo::DFloat.zeros(n_classes, @params[:n_anchors])
103
+ n_classes.times do |n|
104
+ bin_y = Numo::Int32.cast(y.eq(@classes[n])) * 2 - 1
105
+ w, b = partial_fit(x, bin_y)
106
+ @weight_vec[n, true, true] = w
107
+ @bias_term[n, true] = b
108
+ end
109
+ else
110
+ negative_label = @classes[0]
111
+ bin_y = Numo::Int32.cast(y.ne(negative_label)) * 2 - 1
112
+ @weight_vec, @bias_term = partial_fit(x, bin_y)
113
+ end
114
+
115
+ self
116
+ end
117
+
118
+ # Calculate confidence scores for samples.
119
+ #
120
+ # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to compute the scores.
121
+ # @return [Numo::DFloat] (shape: [n_samples, n_classes]) Confidence score per sample.
122
+ def decision_function(x)
123
+ x = Rumale::Validation.check_convert_sample_array(x)
124
+ n_samples = x.shape[0]
125
+
126
+ if multiclass_problem?
127
+ n_classes = @classes.size
128
+ df = Numo::DFloat.zeros(n_samples, n_classes)
129
+ n_samples.times do |i|
130
+ xi = x[i, true]
131
+ coeff = local_coordinates(xi)
132
+ n_classes.times do |j|
133
+ df[i, j] = coeff.dot(@weight_vec[j, true, true]).dot(xi) + coeff.dot(@bias_term[j, true])
134
+ end
135
+ end
136
+ else
137
+ df = Numo::DFloat.zeros(n_samples)
138
+ n_samples.times do |i|
139
+ xi = x[i, true]
140
+ coeff = local_coordinates(xi)
141
+ df[i] = coeff.dot(@weight_vec).dot(xi) + coeff.dot(@bias_term)
142
+ end
143
+ end
144
+ df
145
+ end
146
+
147
+ # Predict class labels for samples.
148
+ #
149
+ # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to predict the labels.
150
+ # @return [Numo::Int32] (shape: [n_samples]) Predicted class label per sample.
151
+ def predict(x)
152
+ x = Rumale::Validation.check_convert_sample_array(x)
153
+ n_samples = x.shape[0]
154
+
155
+ if multiclass_problem?
156
+ df = decision_function(x)
157
+ predicted = Array.new(n_samples) { |n| @classes[df[n, true].max_index] }
158
+ else
159
+ df = decision_function(x).ge(0.0).to_a
160
+ predicted = Array.new(n_samples) { |n| @classes[df[n]] }
161
+ end
162
+ Numo::Int32.asarray(predicted)
163
+ end
164
+
165
+ private
166
+
167
+ def partial_fit(base_x, bin_y) # rubocop:disable Metrics/AbcSize
168
+ fnc = proc do |w, x, y, coeff, reg_param|
169
+ n_anchors = coeff.shape[1]
170
+ n_samples, n_features = x.shape
171
+ w = w.reshape(n_anchors, n_features)
172
+ z = (coeff * x.dot(w.transpose)).sum(axis: 1)
173
+ t = 1 - y * z
174
+ indices = t.gt(0)
175
+ grad = reg_param * w
176
+ if indices.count.positive?
177
+ sx = x[indices, true]
178
+ sy = y[indices]
179
+ sc = coeff[indices, true]
180
+ sz = z[indices]
181
+ grad += 2.fdiv(n_samples) * (sc.transpose * (sz - sy)).dot(sx)
182
+ end
183
+ loss = 0.5 * reg_param * w.dot(w.transpose).trace + (x.class.maximum(0, t)**2).sum.fdiv(n_samples)
184
+ [loss, grad.reshape(n_anchors * n_features)]
185
+ end
186
+
187
+ n_features = base_x.shape[1]
188
+ sub_rng = @rng.dup
189
+ w_init = 2.0 * ::Rumale::Utils.rand_uniform(@params[:n_anchors] * n_features, sub_rng) - 1.0
190
+
191
+ res = Lbfgsb.minimize(
192
+ fnc: fnc, jcb: true, x_init: w_init, args: [base_x, bin_y, @coeff, @params[:reg_param]],
193
+ maxiter: @params[:max_iter], factr: @params[:tol] / Lbfgsb::DBL_EPSILON,
194
+ verbose: @params[:verbose] ? 1 : -1
195
+ )
196
+
197
+ w = res[:x].reshape(@params[:n_anchors], n_features)
198
+
199
+ if fit_bias?
200
+ [w[true, 0...-1].dup, w[true, -1].dup]
201
+ else
202
+ [w, Numo::DFloat.zeros(@params[:n_anchors])]
203
+ end
204
+ end
205
+
206
+ def local_coordinates(xi)
207
+ neighbor_ids = find_neighbors(xi)
208
+ diff = @anchors[neighbor_ids, true] - xi
209
+ gram_mat = diff.dot(diff.transpose)
210
+ gram_mat[gram_mat.diag_indices] += @params[:reg_param_local].fdiv(@params[:n_neighbors]) * gram_mat.trace
211
+ local_coeff = Numo::Linalg.solve(gram_mat, Numo::DFloat.ones(@params[:n_neighbors]))
212
+ local_coeff /= local_coeff.sum # + 1e-8
213
+ coeff = Numo::DFloat.zeros(@params[:n_anchors])
214
+ coeff[neighbor_ids] = local_coeff
215
+ coeff
216
+ end
217
+
218
+ def find_neighbors(xi)
219
+ diff = @anchors - xi
220
+ dist = (diff**2).sum(axis: 1)
221
+ dist.sort_index.to_a[0...@params[:n_neighbors]]
222
+ end
223
+
224
+ def find_anchors(x)
225
+ n_samples = x.shape[0]
226
+ sub_rng = @rng.dup
227
+ rand_id = Array.new(@params[:n_anchors]) { |_v| sub_rng.rand(0...n_samples) }
228
+ @anchors = x[rand_id, true].dup
229
+
230
+ @params[:max_iter].times do |_t|
231
+ center_ids = assign_anchors(x)
232
+ old_anchors = @anchors.dup
233
+ @params[:n_anchors].times do |n|
234
+ assigned_bits = center_ids.eq(n)
235
+ @anchors[n, true] = x[assigned_bits.where, true].mean(axis: 0) if assigned_bits.count.positive?
236
+ end
237
+ error = Numo::NMath.sqrt(((old_anchors - @anchors)**2).sum(axis: 1)).mean
238
+ break if error <= @params[:tol]
239
+ end
240
+ end
241
+
242
+ def assign_anchors(x)
243
+ distance_matrix = ::Rumale::PairwiseMetric.euclidean_distance(x, @anchors)
244
+ distance_matrix.min_index(axis: 1) - Numo::Int32[*0.step(distance_matrix.size - 1, @anchors.shape[0])]
245
+ end
246
+
247
+ def fit_bias?
248
+ @params[:fit_bias] == true
249
+ end
250
+
251
+ def expand_feature(x)
252
+ n_samples = x.shape[0]
253
+ Numo::NArray.hstack([x, Numo::DFloat.ones([n_samples, 1]) * @params[:bias_scale]])
254
+ end
255
+
256
+ def multiclass_problem?
257
+ @classes.size > 2
258
+ end
259
+ end
260
+ end
261
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'numo/liblinear'
4
- require 'rumale/base/base_estimator'
4
+ require 'rumale/base/estimator'
5
5
  require 'rumale/base/classifier'
6
6
 
7
7
  module Rumale
@@ -12,9 +12,8 @@ module Rumale
12
12
  # estimator = Rumale::SVM::LogisticRegression.new(penalty: 'l2', dual: false, reg_param: 1.0, random_seed: 1)
13
13
  # estimator.fit(training_samples, traininig_labels)
14
14
  # results = estimator.predict(testing_samples)
15
- class LogisticRegression
16
- include Base::BaseEstimator
17
- include Base::Classifier
15
+ class LogisticRegression < Rumale::Base::Estimator
16
+ include Rumale::Base::Classifier
18
17
 
19
18
  # Return the weight vector for LogisticRegression.
20
19
  # @return [Numo::DFloat] (shape: [n_classes, n_features])
@@ -39,10 +38,7 @@ module Rumale
39
38
  # @param random_seed [Integer/Nil] The seed value using to initialize the random generator.
40
39
  def initialize(penalty: 'l2', dual: true, reg_param: 1.0,
41
40
  fit_bias: true, bias_scale: 1.0, tol: 1e-3, verbose: false, random_seed: nil)
42
- check_params_string(penalty: penalty)
43
- check_params_numeric(reg_param: reg_param, bias_scale: bias_scale, tol: tol)
44
- check_params_boolean(dual: dual, fit_bias: fit_bias, verbose: verbose)
45
- check_params_numeric_or_nil(random_seed: random_seed)
41
+ super()
46
42
  @params = {}
47
43
  @params[:penalty] = penalty == 'l1' ? 'l1' : 'l2'
48
44
  @params[:dual] = dual
@@ -60,9 +56,9 @@ module Rumale
60
56
  # @param y [Numo::Int32] (shape: [n_samples]) The labels to be used for fitting the model.
61
57
  # @return [LogisticRegression] The learned classifier itself.
62
58
  def fit(x, y)
63
- x = check_convert_sample_array(x)
64
- y = check_convert_label_array(y)
65
- check_sample_label_size(x, y)
59
+ x = Rumale::Validation.check_convert_sample_array(x)
60
+ y = Rumale::Validation.check_convert_label_array(y)
61
+ Rumale::Validation.check_sample_size(x, y)
66
62
  xx = fit_bias? ? expand_feature(x) : x
67
63
  @model = Numo::Liblinear.train(xx, y, liblinear_params)
68
64
  @weight_vec, @bias_term = weight_and_bias(@model[:w])
@@ -74,8 +70,8 @@ module Rumale
74
70
  # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to compute the scores.
75
71
  # @return [Numo::DFloat] (shape: [n_samples, n_classes]) Confidence score per sample.
76
72
  def decision_function(x)
77
- raise "#{self.class.name}\##{__method__} expects to be called after training the model with the fit method." unless trained?
78
- x = check_convert_sample_array(x)
73
+ raise "#{self.class.name}##{__method__} expects to be called after training the model with the fit method." unless trained?
74
+ x = Rumale::Validation.check_convert_sample_array(x)
79
75
  xx = fit_bias? ? expand_feature(x) : x
80
76
  Numo::Liblinear.decision_function(xx, liblinear_params, @model)
81
77
  end
@@ -85,8 +81,8 @@ module Rumale
85
81
  # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to predict the labels.
86
82
  # @return [Numo::Int32] (shape: [n_samples]) Predicted class label per sample.
87
83
  def predict(x)
88
- raise "#{self.class.name}\##{__method__} expects to be called after training the model with the fit method." unless trained?
89
- x = check_convert_sample_array(x)
84
+ raise "#{self.class.name}##{__method__} expects to be called after training the model with the fit method." unless trained?
85
+ x = Rumale::Validation.check_convert_sample_array(x)
90
86
  xx = fit_bias? ? expand_feature(x) : x
91
87
  Numo::Int32.cast(Numo::Liblinear.predict(xx, liblinear_params, @model))
92
88
  end
@@ -97,8 +93,8 @@ module Rumale
97
93
  # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to predict the probailities.
98
94
  # @return [Numo::DFloat] (shape: [n_samples, n_classes]) Predicted probability of each class per sample.
99
95
  def predict_proba(x)
100
- raise "#{self.class.name}\##{__method__} expects to be called after training the model with the fit method." unless trained?
101
- x = check_convert_sample_array(x)
96
+ raise "#{self.class.name}##{__method__} expects to be called after training the model with the fit method." unless trained?
97
+ x = Rumale::Validation.check_convert_sample_array(x)
102
98
  xx = fit_bias? ? expand_feature(x) : x
103
99
  Numo::Liblinear.predict_proba(xx, liblinear_params, @model)
104
100
  end
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'numo/libsvm'
4
- require 'rumale/base/base_estimator'
4
+ require 'rumale/base/estimator'
5
5
  require 'rumale/base/classifier'
6
+ require 'rumale/validation'
6
7
 
7
8
  module Rumale
8
9
  module SVM
@@ -12,9 +13,8 @@ module Rumale
12
13
  # estimator = Rumale::SVM::NuSVC.new(nu: 0.5, kernel: 'rbf', gamma: 10.0, random_seed: 1)
13
14
  # estimator.fit(training_samples, traininig_labels)
14
15
  # results = estimator.predict(testing_samples)
15
- class NuSVC
16
- include Base::BaseEstimator
17
- include Base::Classifier
16
+ class NuSVC < Rumale::Base::Estimator
17
+ include Rumale::Base::Classifier
18
18
 
19
19
  # Create a new classifier with Kernel Nu-Support Vector Classifier.
20
20
  #
@@ -31,10 +31,7 @@ module Rumale
31
31
  # @param random_seed [Integer/Nil] The seed value using to initialize the random generator.
32
32
  def initialize(nu: 0.5, kernel: 'rbf', degree: 3, gamma: 1.0, coef0: 0.0,
33
33
  shrinking: true, probability: true, cache_size: 200.0, tol: 1e-3, verbose: false, random_seed: nil)
34
- check_params_numeric(nu: nu, degree: degree, gamma: gamma, coef0: coef0, cache_size: cache_size, tol: tol)
35
- check_params_string(kernel: kernel)
36
- check_params_boolean(shrinking: shrinking, probability: probability, verbose: verbose)
37
- check_params_numeric_or_nil(random_seed: random_seed)
34
+ super()
38
35
  @params = {}
39
36
  @params[:nu] = nu.to_f
40
37
  @params[:kernel] = kernel
@@ -56,9 +53,9 @@ module Rumale
56
53
  # @param y [Numo::Int32] (shape: [n_samples]) The labels to be used for fitting the model.
57
54
  # @return [NuSVC] The learned classifier itself.
58
55
  def fit(x, y)
59
- x = check_convert_sample_array(x)
60
- y = check_convert_label_array(y)
61
- check_sample_label_size(x, y)
56
+ x = Rumale::Validation.check_convert_sample_array(x)
57
+ y = Rumale::Validation.check_convert_label_array(y)
58
+ Rumale::Validation.check_sample_size(x, y)
62
59
  xx = precomputed_kernel? ? add_index_col(x) : x
63
60
  @model = Numo::Libsvm.train(xx, y, libsvm_params)
64
61
  self
@@ -70,8 +67,8 @@ module Rumale
70
67
  # If the kernel is 'precomputed', the shape of x must be [n_samples, n_training_samples].
71
68
  # @return [Numo::DFloat] (shape: [n_samples, n_classes]) Confidence score per sample.
72
69
  def decision_function(x)
73
- raise "#{self.class.name}\##{__method__} expects to be called after training the model with the fit method." unless trained?
74
- x = check_convert_sample_array(x)
70
+ raise "#{self.class.name}##{__method__} expects to be called after training the model with the fit method." unless trained?
71
+ x = Rumale::Validation.check_convert_sample_array(x)
75
72
  xx = precomputed_kernel? ? add_index_col(x) : x
76
73
  Numo::Libsvm.decision_function(xx, libsvm_params, @model)
77
74
  end
@@ -82,8 +79,8 @@ module Rumale
82
79
  # If the kernel is 'precomputed', the shape of x must be [n_samples, n_training_samples].
83
80
  # @return [Numo::Int32] (shape: [n_samples]) Predicted class label per sample.
84
81
  def predict(x)
85
- raise "#{self.class.name}\##{__method__} expects to be called after training the model with the fit method." unless trained?
86
- x = check_convert_sample_array(x)
82
+ raise "#{self.class.name}##{__method__} expects to be called after training the model with the fit method." unless trained?
83
+ x = Rumale::Validation.check_convert_sample_array(x)
87
84
  xx = precomputed_kernel? ? add_index_col(x) : x
88
85
  Numo::Int32.cast(Numo::Libsvm.predict(xx, libsvm_params, @model))
89
86
  end
@@ -95,8 +92,8 @@ module Rumale
95
92
  # If the kernel is 'precomputed', the shape of x must be [n_samples, n_training_samples].
96
93
  # @return [Numo::DFloat] (shape: [n_samples, n_classes]) Predicted probability of each class per sample.
97
94
  def predict_proba(x)
98
- raise "#{self.class.name}\##{__method__} expects to be called after training the model with the fit method." unless trained?
99
- x = check_convert_sample_array(x)
95
+ raise "#{self.class.name}##{__method__} expects to be called after training the model with the fit method." unless trained?
96
+ x = Rumale::Validation.check_convert_sample_array(x)
100
97
  xx = precomputed_kernel? ? add_index_col(x) : x
101
98
  Numo::Libsvm.predict_proba(xx, libsvm_params, @model)
102
99
  end
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'numo/libsvm'
4
- require 'rumale/base/base_estimator'
4
+ require 'rumale/base/estimator'
5
5
  require 'rumale/base/regressor'
6
+ require 'rumale/validation'
6
7
 
7
8
  module Rumale
8
9
  module SVM
@@ -12,9 +13,8 @@ module Rumale
12
13
  # estimator = Rumale::SVM::NuSVR.new(nu: 0.5, kernel: 'rbf', gamma: 10.0, random_seed: 1)
13
14
  # estimator.fit(training_samples, traininig_target_values)
14
15
  # results = estimator.predict(testing_samples)
15
- class NuSVR
16
- include Base::BaseEstimator
17
- include Base::Regressor
16
+ class NuSVR < Rumale::Base::Estimator
17
+ include Rumale::Base::Regressor
18
18
 
19
19
  # Create a new regressor with Kernel Nu-Support Vector Regressor.
20
20
  #
@@ -30,10 +30,7 @@ module Rumale
30
30
  # @param random_seed [Integer/Nil] The seed value using to initialize the random generator.
31
31
  def initialize(nu: 0.5, kernel: 'rbf', degree: 3, gamma: 1.0, coef0: 0.0,
32
32
  shrinking: true, cache_size: 200.0, tol: 1e-3, verbose: false, random_seed: nil)
33
- check_params_numeric(nu: nu, degree: degree, gamma: gamma, coef0: coef0, cache_size: cache_size, tol: tol)
34
- check_params_string(kernel: kernel)
35
- check_params_boolean(shrinking: shrinking, verbose: verbose)
36
- check_params_numeric_or_nil(random_seed: random_seed)
33
+ super()
37
34
  @params = {}
38
35
  @params[:nu] = nu.to_f
39
36
  @params[:kernel] = kernel
@@ -54,9 +51,9 @@ module Rumale
54
51
  # @param y [Numo::DFloat] (shape: [n_samples]) The target values to be used for fitting the model.
55
52
  # @return [NuSVR] The learned regressor itself.
56
53
  def fit(x, y)
57
- x = check_convert_sample_array(x)
58
- y = check_convert_tvalue_array(y)
59
- check_sample_tvalue_size(x, y)
54
+ x = Rumale::Validation.check_convert_sample_array(x)
55
+ y = Rumale::Validation.check_convert_target_value_array(y)
56
+ Rumale::Validation.check_sample_size(x, y)
60
57
  xx = precomputed_kernel? ? add_index_col(x) : x
61
58
  @model = Numo::Libsvm.train(xx, y, libsvm_params)
62
59
  self
@@ -68,8 +65,8 @@ module Rumale
68
65
  # If the kernel is 'precomputed', the shape of x must be [n_samples, n_training_samples].
69
66
  # @return [Numo::DFloat] (shape: [n_samples]) Predicted value per sample.
70
67
  def predict(x)
71
- raise "#{self.class.name}\##{__method__} expects to be called after training the model with the fit method." unless trained?
72
- x = check_convert_sample_array(x)
68
+ raise "#{self.class.name}##{__method__} expects to be called after training the model with the fit method." unless trained?
69
+ x = Rumale::Validation.check_convert_sample_array(x)
73
70
  xx = precomputed_kernel? ? add_index_col(x) : x
74
71
  Numo::Libsvm.predict(xx, libsvm_params, @model)
75
72
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'numo/libsvm'
4
- require 'rumale/base/base_estimator'
4
+ require 'rumale/base/estimator'
5
5
  require 'rumale/validation'
6
6
 
7
7
  module Rumale
@@ -12,10 +12,7 @@ module Rumale
12
12
  # estimator = Rumale::SVM::OneClassSVM.new(nu: 0.5, kernel: 'rbf', gamma: 10.0, random_seed: 1)
13
13
  # estimator.fit(training_samples, traininig_labels)
14
14
  # results = estimator.predict(testing_samples)
15
- class OneClassSVM
16
- include Base::BaseEstimator
17
- include Validation
18
-
15
+ class OneClassSVM < Rumale::Base::Estimator
19
16
  # Create a new estimator with One-class Support Vector Machine.
20
17
  #
21
18
  # @param nu [Float] The regularization parameter. The interval of nu is (0, 1].
@@ -31,10 +28,7 @@ module Rumale
31
28
  # @param random_seed [Integer/Nil] The seed value using to initialize the random generator.
32
29
  def initialize(nu: 1.0, kernel: 'rbf', degree: 3, gamma: 1.0, coef0: 0.0,
33
30
  shrinking: true, probability: true, cache_size: 200.0, tol: 1e-3, verbose: false, random_seed: nil)
34
- check_params_numeric(nu: nu, degree: degree, gamma: gamma, coef0: coef0, cache_size: cache_size, tol: tol)
35
- check_params_string(kernel: kernel)
36
- check_params_boolean(shrinking: shrinking, probability: probability, verbose: verbose)
37
- check_params_numeric_or_nil(random_seed: random_seed)
31
+ super()
38
32
  @params = {}
39
33
  @params[:nu] = nu.to_f
40
34
  @params[:kernel] = kernel
@@ -56,7 +50,7 @@ module Rumale
56
50
  # If the kernel is 'precomputed', x must be a square distance matrix (shape: [n_samples, n_samples]).
57
51
  # @return [OneClassSVM] The learned estimator itself.
58
52
  def fit(x, _y = nil)
59
- x = check_convert_sample_array(x)
53
+ x = Rumale::Validation.check_convert_sample_array(x)
60
54
  dummy = Numo::DFloat.ones(x.shape[0])
61
55
  @model = Numo::Libsvm.train(x, dummy, libsvm_params)
62
56
  self
@@ -68,8 +62,8 @@ module Rumale
68
62
  # If the kernel is 'precomputed', the shape of x must be [n_samples, n_training_samples].
69
63
  # @return [Numo::DFloat] (shape: [n_samples, n_classes]) Confidence score per sample.
70
64
  def decision_function(x)
71
- raise "#{self.class.name}\##{__method__} expects to be called after training the model with the fit method." unless trained?
72
- x = check_convert_sample_array(x)
65
+ raise "#{self.class.name}##{__method__} expects to be called after training the model with the fit method." unless trained?
66
+ x = Rumale::Validation.check_convert_sample_array(x)
73
67
  Numo::Libsvm.decision_function(x, libsvm_params, @model)
74
68
  end
75
69
 
@@ -79,8 +73,8 @@ module Rumale
79
73
  # If the kernel is 'precomputed', the shape of x must be [n_samples, n_training_samples].
80
74
  # @return [Numo::Int32] (shape: [n_samples]) Predicted label per sample.
81
75
  def predict(x)
82
- raise "#{self.class.name}\##{__method__} expects to be called after training the model with the fit method." unless trained?
83
- x = check_convert_sample_array(x)
76
+ raise "#{self.class.name}##{__method__} expects to be called after training the model with the fit method." unless trained?
77
+ x = Rumale::Validation.check_convert_sample_array(x)
84
78
  Numo::Int32.cast(Numo::Libsvm.predict(x, libsvm_params, @model))
85
79
  end
86
80
 
@@ -91,9 +85,9 @@ module Rumale
91
85
  # If the kernel is 'precomputed', the shape of x must be [n_samples, n_training_samples].
92
86
  # @return [Numo::DFloat] (shape: [n_samples, n_classes]) Predicted probability of each class per sample.
93
87
  def predict_proba(x)
94
- raise "#{self.class.name}\##{__method__} expects to be called after training the model with the fit method." unless trained?
95
- raise "#{self.class.name}\##{__method__} expects to be called after training the probablity parameters." unless trained_probs?
96
- x = check_convert_sample_array(x)
88
+ raise "#{self.class.name}##{__method__} expects to be called after training the model with the fit method." unless trained?
89
+ raise "#{self.class.name}##{__method__} expects to be called after training the probablity parameters." unless trained_probs?
90
+ x = Rumale::Validation.check_convert_sample_array(x)
97
91
  Numo::Libsvm.predict_proba(x, libsvm_params, @model)
98
92
  end
99
93
 
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'numo/libsvm'
4
- require 'rumale/base/base_estimator'
4
+ require 'rumale/base/estimator'
5
5
  require 'rumale/base/classifier'
6
+ require 'rumale/validation'
6
7
 
7
8
  module Rumale
8
9
  module SVM
@@ -12,9 +13,8 @@ module Rumale
12
13
  # estimator = Rumale::SVM::SVC.new(reg_param: 1.0, kernel: 'rbf', gamma: 10.0, random_seed: 1)
13
14
  # estimator.fit(training_samples, traininig_labels)
14
15
  # results = estimator.predict(testing_samples)
15
- class SVC
16
- include Base::BaseEstimator
17
- include Base::Classifier
16
+ class SVC < Rumale::Base::Estimator
17
+ include Rumale::Base::Classifier
18
18
 
19
19
  # Create a new classifier with Kernel C-Support Vector Classifier.
20
20
  #
@@ -31,10 +31,7 @@ module Rumale
31
31
  # @param random_seed [Integer/Nil] The seed value using to initialize the random generator.
32
32
  def initialize(reg_param: 1.0, kernel: 'rbf', degree: 3, gamma: 1.0, coef0: 0.0,
33
33
  shrinking: true, probability: true, cache_size: 200.0, tol: 1e-3, verbose: false, random_seed: nil)
34
- check_params_numeric(reg_param: reg_param, degree: degree, gamma: gamma, coef0: coef0, cache_size: cache_size, tol: tol)
35
- check_params_string(kernel: kernel)
36
- check_params_boolean(shrinking: shrinking, probability: probability, verbose: verbose)
37
- check_params_numeric_or_nil(random_seed: random_seed)
34
+ super()
38
35
  @params = {}
39
36
  @params[:reg_param] = reg_param.to_f
40
37
  @params[:kernel] = kernel
@@ -56,9 +53,9 @@ module Rumale
56
53
  # @param y [Numo::Int32] (shape: [n_samples]) The labels to be used for fitting the model.
57
54
  # @return [SVC] The learned classifier itself.
58
55
  def fit(x, y)
59
- x = check_convert_sample_array(x)
60
- y = check_convert_label_array(y)
61
- check_sample_label_size(x, y)
56
+ x = Rumale::Validation.check_convert_sample_array(x)
57
+ y = Rumale::Validation.check_convert_label_array(y)
58
+ Rumale::Validation.check_sample_size(x, y)
62
59
  xx = precomputed_kernel? ? add_index_col(x) : x
63
60
  @model = Numo::Libsvm.train(xx, y, libsvm_params)
64
61
  self
@@ -70,8 +67,8 @@ module Rumale
70
67
  # If the kernel is 'precomputed', the shape of x must be [n_samples, n_training_samples].
71
68
  # @return [Numo::DFloat] (shape: [n_samples, n_classes]) Confidence score per sample.
72
69
  def decision_function(x)
73
- raise "#{self.class.name}\##{__method__} expects to be called after training the model with the fit method." unless trained?
74
- x = check_convert_sample_array(x)
70
+ raise "#{self.class.name}##{__method__} expects to be called after training the model with the fit method." unless trained?
71
+ x = Rumale::Validation.check_convert_sample_array(x)
75
72
  xx = precomputed_kernel? ? add_index_col(x) : x
76
73
  Numo::Libsvm.decision_function(xx, libsvm_params, @model)
77
74
  end
@@ -82,8 +79,8 @@ module Rumale
82
79
  # If the kernel is 'precomputed', the shape of x must be [n_samples, n_training_samples].
83
80
  # @return [Numo::Int32] (shape: [n_samples]) Predicted class label per sample.
84
81
  def predict(x)
85
- raise "#{self.class.name}\##{__method__} expects to be called after training the model with the fit method." unless trained?
86
- x = check_convert_sample_array(x)
82
+ raise "#{self.class.name}##{__method__} expects to be called after training the model with the fit method." unless trained?
83
+ x = Rumale::Validation.check_convert_sample_array(x)
87
84
  xx = precomputed_kernel? ? add_index_col(x) : x
88
85
  Numo::Int32.cast(Numo::Libsvm.predict(xx, libsvm_params, @model))
89
86
  end
@@ -95,8 +92,8 @@ module Rumale
95
92
  # If the kernel is 'precomputed', the shape of x must be [n_samples, n_training_samples].
96
93
  # @return [Numo::DFloat] (shape: [n_samples, n_classes]) Predicted probability of each class per sample.
97
94
  def predict_proba(x)
98
- raise "#{self.class.name}\##{__method__} expects to be called after training the model with the fit method." unless trained?
99
- x = check_convert_sample_array(x)
95
+ raise "#{self.class.name}##{__method__} expects to be called after training the model with the fit method." unless trained?
96
+ x = Rumale::Validation.check_convert_sample_array(x)
100
97
  xx = precomputed_kernel? ? add_index_col(x) : x
101
98
  Numo::Libsvm.predict_proba(xx, libsvm_params, @model)
102
99
  end
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'numo/libsvm'
4
- require 'rumale/base/base_estimator'
4
+ require 'rumale/base/estimator'
5
5
  require 'rumale/base/regressor'
6
+ require 'rumale/validation'
6
7
 
7
8
  module Rumale
8
9
  module SVM
@@ -12,9 +13,8 @@ module Rumale
12
13
  # estimator = Rumale::SVM::SVR.new(reg_param: 1.0, kernel: 'rbf', gamma: 10.0, random_seed: 1)
13
14
  # estimator.fit(training_samples, traininig_target_values)
14
15
  # results = estimator.predict(testing_samples)
15
- class SVR
16
- include Base::BaseEstimator
17
- include Base::Regressor
16
+ class SVR < Rumale::Base::Estimator
17
+ include Rumale::Base::Regressor
18
18
 
19
19
  # Create a new regressor with Kernel Epsilon-Support Vector Regressor.
20
20
  #
@@ -31,11 +31,7 @@ module Rumale
31
31
  # @param random_seed [Integer/Nil] The seed value using to initialize the random generator.
32
32
  def initialize(reg_param: 1.0, epsilon: 0.1, kernel: 'rbf', degree: 3, gamma: 1.0, coef0: 0.0,
33
33
  shrinking: true, cache_size: 200.0, tol: 1e-3, verbose: false, random_seed: nil)
34
- check_params_numeric(reg_param: reg_param, degree: degree, epsilon: epsilon, gamma: gamma, coef0: coef0,
35
- cache_size: cache_size, tol: tol)
36
- check_params_string(kernel: kernel)
37
- check_params_boolean(shrinking: shrinking, verbose: verbose)
38
- check_params_numeric_or_nil(random_seed: random_seed)
34
+ super()
39
35
  @params = {}
40
36
  @params[:reg_param] = reg_param.to_f
41
37
  @params[:epsilon] = epsilon.to_f
@@ -57,9 +53,9 @@ module Rumale
57
53
  # @param y [Numo::DFloat] (shape: [n_samples]) The target values to be used for fitting the model.
58
54
  # @return [SVR] The learned regressor itself.
59
55
  def fit(x, y)
60
- x = check_convert_sample_array(x)
61
- y = check_convert_tvalue_array(y)
62
- check_sample_tvalue_size(x, y)
56
+ x = Rumale::Validation.check_convert_sample_array(x)
57
+ y = Rumale::Validation.check_convert_target_value_array(y)
58
+ Rumale::Validation.check_sample_size(x, y)
63
59
  xx = precomputed_kernel? ? add_index_col(x) : x
64
60
  @model = Numo::Libsvm.train(xx, y, libsvm_params)
65
61
  self
@@ -71,8 +67,8 @@ module Rumale
71
67
  # If the kernel is 'precomputed', the shape of x must be [n_samples, n_training_samples].
72
68
  # @return [Numo::DFloat] (shape: [n_samples]) Predicted value per sample.
73
69
  def predict(x)
74
- raise "#{self.class.name}\##{__method__} expects to be called after training the model with the fit method." unless trained?
75
- x = check_convert_sample_array(x)
70
+ raise "#{self.class.name}##{__method__} expects to be called after training the model with the fit method." unless trained?
71
+ x = Rumale::Validation.check_convert_sample_array(x)
76
72
  xx = precomputed_kernel? ? add_index_col(x) : x
77
73
  Numo::Libsvm.predict(xx, libsvm_params, @model)
78
74
  end
@@ -2,9 +2,9 @@
2
2
 
3
3
  # Rumale is a machine learning library in Ruby.
4
4
  module Rumale
5
- # This module consists of Rumale interfaces for suppor vector machine algorithms with LIBSVM and LIBLINEAR.
5
+ # This module consists of Rumale interfaces for suppor vector machine algorithms using LIBSVM and LIBLINEAR.
6
6
  module SVM
7
7
  # The version of Rumale::SVM you are using.
8
- VERSION = '0.7.0'
8
+ VERSION = '0.9.0'
9
9
  end
10
10
  end
data/lib/rumale/svm.rb CHANGED
@@ -10,3 +10,4 @@ require 'rumale/svm/linear_svc'
10
10
  require 'rumale/svm/linear_svr'
11
11
  require 'rumale/svm/logistic_regression'
12
12
  require 'rumale/svm/linear_one_class_svm'
13
+ require 'rumale/svm/locally_linear_svc'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rumale-svm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - yoshoku
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-10-15 00:00:00.000000000 Z
11
+ date: 2023-11-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: numo-liblinear
@@ -39,13 +39,10 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.1'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rumale
42
+ name: rumale-core
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '0.14'
48
- - - "<"
49
46
  - !ruby/object:Gem::Version
50
47
  version: '0.24'
51
48
  type: :runtime
@@ -53,13 +50,10 @@ dependencies:
53
50
  version_requirements: !ruby/object:Gem::Requirement
54
51
  requirements:
55
52
  - - "~>"
56
- - !ruby/object:Gem::Version
57
- version: '0.14'
58
- - - "<"
59
53
  - !ruby/object:Gem::Version
60
54
  version: '0.24'
61
- description: 'Rumale::SVM provides support vector machine algorithms of LIBSVM and
62
- LIBLINEAR with Rumale interface.
55
+ description: 'Rumale::SVM provides support vector machine algorithms using LIBSVM
56
+ and LIBLINEAR with Rumale interface.
63
57
 
64
58
  '
65
59
  email:
@@ -75,6 +69,7 @@ files:
75
69
  - lib/rumale/svm/linear_one_class_svm.rb
76
70
  - lib/rumale/svm/linear_svc.rb
77
71
  - lib/rumale/svm/linear_svr.rb
72
+ - lib/rumale/svm/locally_linear_svc.rb
78
73
  - lib/rumale/svm/logistic_regression.rb
79
74
  - lib/rumale/svm/nu_svc.rb
80
75
  - lib/rumale/svm/nu_svr.rb
@@ -116,9 +111,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
116
111
  - !ruby/object:Gem::Version
117
112
  version: '0'
118
113
  requirements: []
119
- rubygems_version: 3.3.7
114
+ rubygems_version: 3.4.20
120
115
  signing_key:
121
116
  specification_version: 4
122
- summary: Rumale::SVM provides support vector machine algorithms of LIBSVM and LIBLINEAR
117
+ summary: Rumale::SVM provides support vector machine algorithms using LIBSVM and LIBLINEAR
123
118
  with Rumale interface.
124
119
  test_files: []