svmkit 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,17 +4,17 @@ require 'svmkit/base/classifier'
4
4
  module SVMKit
5
5
  # This module consists of the classes that implement generalized linear models.
6
6
  module LinearModel
7
- # PegasosSVC is a class that implements Support Vector Classifier with the Pegasos algorithm.
7
+ # SVC is a class that implements Support Vector Classifier with the Pegasos algorithm.
8
8
  #
9
9
  # @example
10
10
  # estimator =
11
- # SVMKit::LinearModel::PegasosSVC.new(reg_param: 1.0, max_iter: 100, batch_size: 20, random_seed: 1)
11
+ # SVMKit::LinearModel::SVC.new(reg_param: 1.0, max_iter: 100, batch_size: 20, random_seed: 1)
12
12
  # estimator.fit(training_samples, traininig_labels)
13
13
  # results = estimator.predict(testing_samples)
14
14
  #
15
15
  # *Reference*
16
16
  # 1. S. Shalev-Shwartz and Y. Singer, "Pegasos: Primal Estimated sub-GrAdient SOlver for SVM," Proc. ICML'07, pp. 807--814, 2007.
17
- class PegasosSVC
17
+ class SVC
18
18
  include Base::BaseEstimator
19
19
  include Base::Classifier
20
20
 
@@ -29,7 +29,7 @@ module SVMKit
29
29
  }.freeze
30
30
 
31
31
  # Return the weight vector for SVC.
32
- # @return [NMatrix] (shape: [1, n_features])
32
+ # @return [Numo::DFloat] (shape: [n_features])
33
33
  attr_reader :weight_vec
34
34
 
35
35
  # Return the bias term (a.k.a. intercept) for SVC.
@@ -42,17 +42,20 @@ module SVMKit
42
42
 
43
43
  # Create a new classifier with Support Vector Machine by the Pegasos algorithm.
44
44
  #
45
- # @overload new(reg_param: 1.0, max_iter: 100, batch_size: 50, random_seed: 1) -> PegasosSVC
46
- #
47
- # @param params [Hash] The parameters for SVC.
48
- # @option params [Float] :reg_param (1.0) The regularization parameter.
49
- # @option params [Boolean] :fit_bias (false) The flag indicating whether to fit the bias term.
50
- # @option params [Float] :bias_scale (1.0) The scale of the bias term.
51
- # @option params [Integer] :max_iter (100) The maximum number of iterations.
52
- # @option params [Integer] :batch_size (50) The size of the mini batches.
53
- # @option params [Integer] :random_seed (nil) The seed value using to initialize the random generator.
54
- def initialize(params = {})
55
- self.params = DEFAULT_PARAMS.merge(Hash[params.map { |k, v| [k.to_sym, v] }])
45
+ # @param reg_param [Float] The regularization parameter.
46
+ # @param fit_bias [Boolean] The flag indicating whether to fit the bias term.
47
+ # @param bias_scale [Float] The scale of the bias term.
48
+ # @param max_iter [Integer] The maximum number of iterations.
49
+ # @param batch_size [Integer] The size of the mini batches.
50
+ # @param random_seed [Integer] The seed value using to initialize the random generator.
51
+ def initialize(reg_param: 1.0, fit_bias: false, bias_scale: 1.0, max_iter: 100, batch_size: 50, random_seed: nil)
52
+ self.params = {}
53
+ self.params[:reg_param] = reg_param
54
+ self.params[:fit_bias] = fit_bias
55
+ self.params[:bias_scale] = bias_scale
56
+ self.params[:max_iter] = max_iter
57
+ self.params[:batch_size] = batch_size
58
+ self.params[:random_seed] = random_seed
56
59
  self.params[:random_seed] ||= srand
57
60
  @weight_vec = nil
58
61
  @bias_term = 0.0
@@ -61,38 +64,41 @@ module SVMKit
61
64
 
62
65
  # Fit the model with given training data.
63
66
  #
64
- # @param x [NMatrix] (shape: [n_samples, n_features]) The training data to be used for fitting the model.
65
- # @param y [NMatrix] (shape: [1, n_samples]) The labels to be used for fitting the model.
66
- # @return [PegasosSVC] The learned classifier itself.
67
+ # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The training data to be used for fitting the model.
68
+ # @param y [Numo::Int32] (shape: [n_samples]) The labels to be used for fitting the model.
69
+ # @return [SVC] The learned classifier itself.
67
70
  def fit(x, y)
68
71
  # Generate binary labels
69
- negative_label = y.uniq.sort.shift
70
- bin_y = y.to_flat_a.map { |l| l != negative_label ? 1 : -1 }
72
+ negative_label = y.to_a.uniq.sort.shift
73
+ bin_y = y.to_a.map { |l| l != negative_label ? 1 : -1 }
71
74
  # Expand feature vectors for bias term.
72
75
  samples = x
73
- samples = samples.hconcat(NMatrix.ones([x.shape[0], 1]) * params[:bias_scale]) if params[:fit_bias]
76
+ if params[:fit_bias]
77
+ samples = Numo::NArray.hstack(
78
+ [samples, Numo::DFloat.ones([x.shape[0], 1]) * params[:bias_scale]]
79
+ )
80
+ end
74
81
  # Initialize some variables.
75
82
  n_samples, n_features = samples.shape
76
83
  rand_ids = [*0..n_samples - 1].shuffle(random: @rng)
77
- weight_vec = NMatrix.zeros([1, n_features])
84
+ weight_vec = Numo::DFloat.zeros(n_features)
78
85
  # Start optimization.
79
86
  params[:max_iter].times do |t|
80
87
  # random sampling
81
88
  subset_ids = rand_ids.shift(params[:batch_size])
82
89
  rand_ids.concat(subset_ids)
83
- target_ids = subset_ids.map do |n|
84
- n if weight_vec.dot(samples.row(n).transpose) * bin_y[n] < 1
85
- end
90
+ target_ids = subset_ids.map { |n| n if weight_vec.dot(samples[n, true]) * bin_y[n] < 1 }.compact
86
91
  n_subsamples = target_ids.size
87
92
  next if n_subsamples.zero?
88
93
  # update the weight vector.
89
94
  eta = 1.0 / (params[:reg_param] * (t + 1))
90
- mean_vec = NMatrix.zeros([1, n_features])
91
- target_ids.each { |n| mean_vec += samples.row(n) * bin_y[n] }
95
+ mean_vec = Numo::DFloat.zeros(n_features)
96
+ target_ids.each { |n| mean_vec += samples[n, true] * bin_y[n] }
92
97
  mean_vec *= eta / n_subsamples
93
98
  weight_vec = weight_vec * (1.0 - eta * params[:reg_param]) + mean_vec
94
99
  # scale the weight vector.
95
- scaler = (1.0 / params[:reg_param]**0.5) / weight_vec.norm2
100
+ norm = Math.sqrt(weight_vec.dot(weight_vec))
101
+ scaler = (1.0 / params[:reg_param]**0.5) / (norm + 1.0e-12)
96
102
  weight_vec *= [1.0, scaler].min
97
103
  end
98
104
  # Store the learned model.
@@ -108,42 +114,42 @@ module SVMKit
108
114
 
109
115
  # Calculate confidence scores for samples.
110
116
  #
111
- # @param x [NMatrix] (shape: [n_samples, n_features]) The samples to compute the scores.
112
- # @return [NMatrix] (shape: [1, n_samples]) Confidence score per sample.
117
+ # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to compute the scores.
118
+ # @return [Numo::DFloat] (shape: [n_samples]) Confidence score per sample.
113
119
  def decision_function(x)
114
120
  @weight_vec.dot(x.transpose) + @bias_term
115
121
  end
116
122
 
117
123
  # Predict class labels for samples.
118
124
  #
119
- # @param x [NMatrix] (shape: [n_samples, n_features]) The samples to predict the labels.
120
- # @return [NMatrix] (shape: [1, n_samples]) Predicted class label per sample.
125
+ # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to predict the labels.
126
+ # @return [Numo::Int32] (shape: [n_samples]) Predicted class label per sample.
121
127
  def predict(x)
122
- decision_function(x).map { |v| v >= 0 ? 1 : -1 }
128
+ Numo::Int32.cast(decision_function(x).map { |v| v >= 0 ? 1 : -1 })
123
129
  end
124
130
 
125
131
  # Claculate the mean accuracy of the given testing data.
126
132
  #
127
- # @param x [NMatrix] (shape: [n_samples, n_features]) Testing data.
128
- # @param y [NMatrix] (shape: [1, n_samples]) True labels for testing data.
133
+ # @param x [Numo::DFloat] (shape: [n_samples, n_features]) Testing data.
134
+ # @param y [Numo::Int32] (shape: [n_samples]) True labels for testing data.
129
135
  # @return [Float] Mean accuracy
130
136
  def score(x, y)
131
137
  p = predict(x)
132
- n_hits = (y.to_flat_a.map.with_index { |l, n| l == p[n] ? 1 : 0 }).inject(:+)
138
+ n_hits = (y.to_a.map.with_index { |l, n| l == p[n] ? 1 : 0 }).inject(:+)
133
139
  n_hits / y.size.to_f
134
140
  end
135
141
 
136
142
  # Dump marshal data.
137
- # @return [Hash] The marshal data about PegasosSVC.
143
+ # @return [Hash] The marshal data about SVC.
138
144
  def marshal_dump
139
- { params: params, weight_vec: Utils.dump_nmatrix(@weight_vec), bias_term: @bias_term, rng: @rng }
145
+ { params: params, weight_vec: @weight_vec, bias_term: @bias_term, rng: @rng }
140
146
  end
141
147
 
142
148
  # Load marshal data.
143
149
  # @return [nil]
144
150
  def marshal_load(obj)
145
151
  self.params = obj[:params]
146
- @weight_vec = Utils.restore_nmatrix(obj[:weight_vec])
152
+ @weight_vec = obj[:weight_vec]
147
153
  @bias_term = obj[:bias_term]
148
154
  @rng = obj[:rng]
149
155
  nil
@@ -16,40 +16,34 @@ module SVMKit
16
16
  include Base::BaseEstimator
17
17
  include Base::Classifier
18
18
 
19
- # @!visibility private
20
- DEFAULT_PARAMS = {
21
- estimator: nil
22
- }.freeze
23
-
24
19
  # Return the set of estimators.
25
20
  # @return [Array<Classifier>]
26
21
  attr_reader :estimators
27
22
 
28
23
  # Return the class labels.
29
- # @return [NMatrix] (shape: [1, n_classes])
24
+ # @return [Numo::Int32] (shape: [n_classes])
30
25
  attr_reader :classes
31
26
 
32
27
  # Create a new multi-label classifier with the one-vs-rest startegy.
33
28
  #
34
- # @overload new(estimator: base_estimator) -> OneVsRestClassifier
35
- #
36
- # @param params [Hash] The parameters for OneVsRestClassifier.
37
- # @option params [Classifier] :estimator (nil) The (binary) classifier for construction a multi-label classifier.
38
- def initialize(params = {})
39
- self.params = DEFAULT_PARAMS.merge(Hash[params.map { |k, v| [k.to_sym, v] }])
29
+ # @param estimator [Classifier] The (binary) classifier for construction a multi-label classifier.
30
+ def initialize(estimator: nil)
31
+ self.params = {}
32
+ self.params[:estimator] = estimator
40
33
  @estimators = nil
41
34
  @classes = nil
42
35
  end
43
36
 
44
37
  # Fit the model with given training data.
45
38
  #
46
- # @param x [NMatrix] (shape: [n_samples, n_features]) The training data to be used for fitting the model.
47
- # @param y [NMatrix] (shape: [1, n_samples]) The labels to be used for fitting the model.
39
+ # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The training data to be used for fitting the model.
40
+ # @param y [Numo::Int32] (shape: [n_samples]) The labels to be used for fitting the model.
48
41
  # @return [OneVsRestClassifier] The learned classifier itself.
49
42
  def fit(x, y)
50
- @classes = y.uniq.sort
51
- @estimators = @classes.map do |label|
52
- bin_y = y.map { |l| l == label ? 1 : -1 }
43
+ y_arr = y.to_a
44
+ @classes = Numo::Int32.asarray(y_arr.uniq.sort)
45
+ @estimators = @classes.to_a.map do |label|
46
+ bin_y = Numo::Int32.asarray(y_arr.map { |l| l == label ? 1 : -1 })
53
47
  params[:estimator].dup.fit(x, bin_y)
54
48
  end
55
49
  self
@@ -57,36 +51,31 @@ module SVMKit
57
51
 
58
52
  # Calculate confidence scores for samples.
59
53
  #
60
- # @param x [NMatrix] (shape: [n_samples, n_features]) The samples to compute the scores.
61
- # @return [NMatrix] (shape: [n_samples, n_classes]) Confidence scores per sample for each class.
54
+ # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to compute the scores.
55
+ # @return [Numo::DFloat] (shape: [n_samples, n_classes]) Confidence scores per sample for each class.
62
56
  def decision_function(x)
63
- n_samples, = x.shape
64
57
  n_classes = @classes.size
65
- NMatrix.new(
66
- [n_classes, n_samples],
67
- Array.new(n_classes) { |m| @estimators[m].decision_function(x).to_a }.flatten
68
- ).transpose
58
+ Numo::DFloat.asarray(Array.new(n_classes) { |m| @estimators[m].decision_function(x).to_a }).transpose
69
59
  end
70
60
 
71
61
  # Predict class labels for samples.
72
62
  #
73
- # @param x [NMatrix] (shape: [n_samples, n_features]) The samples to predict the labels.
74
- # @return [NMatrix] (shape: [1, n_samples]) Predicted class label per sample.
63
+ # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to predict the labels.
64
+ # @return [Numo::Int32] (shape: [n_samples]) Predicted class label per sample.
75
65
  def predict(x)
76
66
  n_samples, = x.shape
77
67
  decision_values = decision_function(x)
78
- NMatrix.new([1, n_samples],
79
- decision_values.each_row.map { |vals| @classes[vals.to_a.index(vals.to_a.max)] })
68
+ Numo::Int32.asarray(Array.new(n_samples) { |n| @classes[decision_values[n, true].max_index] })
80
69
  end
81
70
 
82
71
  # Claculate the mean accuracy of the given testing data.
83
72
  #
84
- # @param x [NMatrix] (shape: [n_samples, n_features]) Testing data.
85
- # @param y [NMatrix] (shape: [1, n_samples]) True labels for testing data.
73
+ # @param x [Numo::DFloat] (shape: [n_samples, n_features]) Testing data.
74
+ # @param y [Numo::Int32] (shape: [n_samples]) True labels for testing data.
86
75
  # @return [Float] Mean accuracy
87
76
  def score(x, y)
88
77
  p = predict(x)
89
- n_hits = (y.to_flat_a.map.with_index { |l, n| l == p[n] ? 1 : 0 }).inject(:+)
78
+ n_hits = (y.to_a.map.with_index { |l, n| l == p[n] ? 1 : 0 }).inject(:+)
90
79
  n_hits / y.size.to_f
91
80
  end
92
81
 
@@ -4,38 +4,38 @@ module SVMKit
4
4
  class << self
5
5
  # Calculate the pairwise euclidean distances between x and y.
6
6
  #
7
- # @param x [NMatrix] (shape: [n_samples_x, n_features])
8
- # @param y [NMatrix] (shape: [n_samples_y, n_features])
9
- # @return [NMatrix] (shape: [n_samples_x, n_samples_x] or [n_samples_x, n_samples_y] if y is given)
7
+ # @param x [Numo::DFloat] (shape: [n_samples_x, n_features])
8
+ # @param y [Numo::DFloat] (shape: [n_samples_y, n_features])
9
+ # @return [Numo::DFloat] (shape: [n_samples_x, n_samples_x] or [n_samples_x, n_samples_y] if y is given)
10
10
  def euclidean_distance(x, y = nil)
11
11
  y = x if y.nil?
12
12
  sum_x_vec = (x**2).sum(1)
13
13
  sum_y_vec = (y**2).sum(1)
14
14
  dot_xy_mat = x.dot(y.transpose)
15
15
  distance_matrix = dot_xy_mat * -2.0 +
16
- sum_x_vec.repeat(y.shape[0], 1) +
17
- sum_y_vec.transpose.repeat(x.shape[0], 0)
18
- distance_matrix.abs.sqrt
16
+ sum_x_vec.tile(y.shape[0], 1).transpose +
17
+ sum_y_vec.tile(x.shape[0], 1)
18
+ Numo::NMath.sqrt(distance_matrix.abs)
19
19
  end
20
20
 
21
21
  # Calculate the rbf kernel between x and y.
22
22
  #
23
- # @param x [NMatrix] (shape: [n_samples_x, n_features])
24
- # @param y [NMatrix] (shape: [n_samples_y, n_features])
23
+ # @param x [Numo::DFloat] (shape: [n_samples_x, n_features])
24
+ # @param y [Numo::DFloat] (shape: [n_samples_y, n_features])
25
25
  # @param gamma [Float] The parameter of rbf kernel, if nil it is 1 / n_features.
26
- # @return [NMatrix] (shape: [n_samples_x, n_samples_x] or [n_samples_x, n_samples_y] if y is given)
26
+ # @return [Numo::DFloat] (shape: [n_samples_x, n_samples_x] or [n_samples_x, n_samples_y] if y is given)
27
27
  def rbf_kernel(x, y = nil, gamma = nil)
28
28
  y = x if y.nil?
29
29
  gamma ||= 1.0 / x.shape[1]
30
30
  distance_matrix = euclidean_distance(x, y)
31
- ((distance_matrix**2) * -gamma).exp
31
+ Numo::NMath.exp((distance_matrix**2) * -gamma)
32
32
  end
33
33
 
34
34
  # Calculate the linear kernel between x and y.
35
35
  #
36
- # @param x [NMatrix] (shape: [n_samples_x, n_features])
37
- # @param y [NMatrix] (shape: [n_samples_y, n_features])
38
- # @return [NMatrix] (shape: [n_samples_x, n_samples_x] or [n_samples_x, n_samples_y] if y is given)
36
+ # @param x [Numo::DFloat] (shape: [n_samples_x, n_features])
37
+ # @param y [Numo::DFloat] (shape: [n_samples_y, n_features])
38
+ # @return [Numo::DFloat] (shape: [n_samples_x, n_samples_x] or [n_samples_x, n_samples_y] if y is given)
39
39
  def linear_kernel(x, y = nil)
40
40
  y = x if y.nil?
41
41
  x.dot(y.transpose)
@@ -43,12 +43,12 @@ module SVMKit
43
43
 
44
44
  # Calculate the polynomial kernel between x and y.
45
45
  #
46
- # @param x [NMatrix] (shape: [n_samples_x, n_features])
47
- # @param y [NMatrix] (shape: [n_samples_y, n_features])
46
+ # @param x [Numo::DFloat] (shape: [n_samples_x, n_features])
47
+ # @param y [Numo::DFloat] (shape: [n_samples_y, n_features])
48
48
  # @param degree [Integer] The parameter of polynomial kernel.
49
49
  # @param gamma [Float] The parameter of polynomial kernel, if nil it is 1 / n_features.
50
50
  # @param coef [Integer] The parameter of polynomial kernel.
51
- # @return [NMatrix] (shape: [n_samples_x, n_samples_x] or [n_samples_x, n_samples_y] if y is given)
51
+ # @return [Numo::DFloat] (shape: [n_samples_x, n_samples_x] or [n_samples_x, n_samples_y] if y is given)
52
52
  def polynomial_kernel(x, y = nil, degree = 3, gamma = nil, coef = 1)
53
53
  y = x if y.nil?
54
54
  gamma ||= 1.0 / x.shape[1]
@@ -57,15 +57,15 @@ module SVMKit
57
57
 
58
58
  # Calculate the sigmoid kernel between x and y.
59
59
  #
60
- # @param x [NMatrix] (shape: [n_samples_x, n_features])
61
- # @param y [NMatrix] (shape: [n_samples_y, n_features])
60
+ # @param x [Numo::DFloat] (shape: [n_samples_x, n_features])
61
+ # @param y [Numo::DFloat] (shape: [n_samples_y, n_features])
62
62
  # @param gamma [Float] The parameter of polynomial kernel, if nil it is 1 / n_features.
63
63
  # @param coef [Integer] The parameter of polynomial kernel.
64
- # @return [NMatrix] (shape: [n_samples_x, n_samples_x] or [n_samples_x, n_samples_y] if y is given)
64
+ # @return [Numo::DFloat] (shape: [n_samples_x, n_samples_x] or [n_samples_x, n_samples_y] if y is given)
65
65
  def sigmoid_kernel(x, y = nil, gamma = nil, coef = 1)
66
66
  y = x if y.nil?
67
67
  gamma ||= 1.0 / x.shape[1]
68
- (x.dot(y.transpose) * gamma + coef).tanh
68
+ Numo::NMath.tanh(x.dot(y.transpose) * gamma + coef)
69
69
  end
70
70
  end
71
71
  end
@@ -14,13 +14,12 @@ module SVMKit
14
14
  include Base::Transformer
15
15
 
16
16
  # Return the vector consists of L2-norm for each sample.
17
- # @return [NMatrix] (shape: [1, n_samples])
17
+ # @return [Numo::DFloat] (shape: [n_samples])
18
18
  attr_reader :norm_vec # :nodoc:
19
19
 
20
20
  # Create a new normalizer for normaliing to unit L2-norm.
21
- #
22
- # @overload new() -> L2Normalizer
23
- def initialize(_params = {})
21
+ def initialize()
22
+ self.params = {}
24
23
  @norm_vec = nil
25
24
  end
26
25
 
@@ -28,24 +27,22 @@ module SVMKit
28
27
  #
29
28
  # @overload fit(x) -> L2Normalizer
30
29
  #
31
- # @param x [NMatrix] (shape: [n_samples, n_features]) The samples to calculate L2-norms.
30
+ # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to calculate L2-norms.
32
31
  # @return [L2Normalizer]
33
32
  def fit(x, _y = nil)
34
- n_samples, = x.shape
35
- @norm_vec = NMatrix.new([1, n_samples],
36
- Array.new(n_samples) { |n| x.row(n).norm2 })
33
+ @norm_vec = Numo::NMath.sqrt((x**2).sum(1))
37
34
  self
38
35
  end
39
36
 
40
37
  # Calculate L2-norms of each sample, and then normalize samples to unit L2-norm.
41
38
  #
42
- # @overload fit_transform(x) -> NMatrix
39
+ # @overload fit_transform(x) -> Numo::DFloat
43
40
  #
44
- # @param x [NMatrix] (shape: [n_samples, n_features]) The samples to calculate L2-norms.
45
- # @return [NMatrix] The normalized samples.
41
+ # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to calculate L2-norms.
42
+ # @return [Numo::DFloat] The normalized samples.
46
43
  def fit_transform(x, _y = nil)
47
44
  fit(x)
48
- x / @norm_vec.transpose.repeat(x.shape[1], 1)
45
+ x / @norm_vec.tile(x.shape[1], 1).transpose
49
46
  end
50
47
  end
51
48
  end
@@ -14,27 +14,20 @@ module SVMKit
14
14
  include Base::BaseEstimator
15
15
  include Base::Transformer
16
16
 
17
- # @!visibility private
18
- DEFAULT_PARAMS = {
19
- feature_range: [0.0, 1.0]
20
- }.freeze
21
-
22
17
  # Return the vector consists of the minimum value for each feature.
23
- # @return [NMatrix] (shape: [1, n_features])
18
+ # @return [Numo::DFloat] (shape: [n_features])
24
19
  attr_reader :min_vec
25
20
 
26
21
  # Return the vector consists of the maximum value for each feature.
27
- # @return [NMatrix] (shape: [1, n_features])
22
+ # @return [Numo::DFloat] (shape: [n_features])
28
23
  attr_reader :max_vec
29
24
 
30
25
  # Creates a new normalizer for scaling each feature to a given range.
31
26
  #
32
- # @overload new(feature_range: [0.0, 1.0]) -> MinMaxScaler
33
- #
34
- # @param params [Hash] The parameters for MinMaxScaler.
35
- # @option params [Array<Float>] :feature_range ([0.0, 1.0]) The desired range of samples.
36
- def initialize(params = {})
37
- @params = DEFAULT_PARAMS.merge(Hash[params.map { |k, v| [k.to_sym, v] }])
27
+ # @param feature_range [Array<Float>] The desired range of samples.
28
+ def initialize(feature_range: [0.0, 1.0])
29
+ self.params = {}
30
+ self.params[:feature_range] = feature_range
38
31
  @min_vec = nil
39
32
  @max_vec = nil
40
33
  end
@@ -43,7 +36,7 @@ module SVMKit
43
36
  #
44
37
  # @overload fit(x) -> MinMaxScaler
45
38
  #
46
- # @param x [NMatrix] (shape: [n_samples, n_features]) The samples to calculate the minimum and maximum values.
39
+ # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to calculate the minimum and maximum values.
47
40
  # @return [MinMaxScaler]
48
41
  def fit(x, _y = nil)
49
42
  @min_vec = x.min(0)
@@ -53,22 +46,22 @@ module SVMKit
53
46
 
54
47
  # Calculate the minimum and maximum values, and then normalize samples to feature_range.
55
48
  #
56
- # @overload fit_transform(x) -> NMatrix
49
+ # @overload fit_transform(x) -> Numo::DFloat
57
50
  #
58
- # @param x [NMatrix] (shape: [n_samples, n_features]) The samples to calculate the minimum and maximum values.
59
- # @return [NMatrix] The scaled samples.
51
+ # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to calculate the minimum and maximum values.
52
+ # @return [Numo::DFloat] The scaled samples.
60
53
  def fit_transform(x, _y = nil)
61
54
  fit(x).transform(x)
62
55
  end
63
56
 
64
57
  # Perform scaling the given samples according to feature_range.
65
58
  #
66
- # @param x [NMatrix] (shape: [n_samples, n_features]) The samples to be scaled.
67
- # @return [NMatrix] The scaled samples.
59
+ # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to be scaled.
60
+ # @return [Numo::DFloat] The scaled samples.
68
61
  def transform(x)
69
62
  n_samples, = x.shape
70
63
  dif_vec = @max_vec - @min_vec
71
- nx = (x - @min_vec.repeat(n_samples, 0)) / dif_vec.repeat(n_samples, 0)
64
+ nx = (x - @min_vec.tile(n_samples, 1)) / dif_vec.tile(n_samples, 1)
72
65
  nx * (@params[:feature_range][1] - @params[:feature_range][0]) + @params[:feature_range][0]
73
66
  end
74
67
 
@@ -76,16 +69,16 @@ module SVMKit
76
69
  # @return [Hash] The marshal data about MinMaxScaler.
77
70
  def marshal_dump
78
71
  { params: @params,
79
- min_vec: Utils.dump_nmatrix(@min_vec),
80
- max_vec: Utils.dump_nmatrix(@max_vec) }
72
+ min_vec: @min_vec,
73
+ max_vec: @max_vec }
81
74
  end
82
75
 
83
76
  # Load marshal data.
84
77
  # @return [nil]
85
78
  def marshal_load(obj)
86
79
  @params = obj[:params]
87
- @min_vec = Utils.restore_nmatrix(obj[:min_vec])
88
- @max_vec = Utils.restore_nmatrix(obj[:max_vec])
80
+ @min_vec = obj[:min_vec]
81
+ @max_vec = obj[:max_vec]
89
82
  nil
90
83
  end
91
84
  end