rumale-svm 0.7.0 → 0.9.0

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: 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: []