rumale-linear_model 0.24.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3a7999fbdb27dc6ed43710083da0cecf2336bfb08277fa4240be7b56c2603c9f
4
+ data.tar.gz: 6bc61b3d80fe71c1d7ed806c810a0eb454244033506ab2078ccd0987e7891455
5
+ SHA512:
6
+ metadata.gz: 4c73e2b03dfb0f14c94b880769103bbb05f77de7ac08f8b9af2dddc0ab6bcada758c0c7c51353a79e052e051999b4afc7610012caf4dbb7c4edc505152fdf1d6
7
+ data.tar.gz: 91ce194539b8abc95fb3ec7335bd4843aea126774ebb566eb9953955f775427afd032f9d02894c8507337d20f03baafa39903eb9dd9f9157ccf6a8d22028fe8b
data/LICENSE.txt ADDED
@@ -0,0 +1,27 @@
1
+ Copyright (c) 2022 Atsushi Tatsuma
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ * Neither the name of the copyright holder nor the names of its
15
+ contributors may be used to endorse or promote products derived from
16
+ this software without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # Rumale::LinearModel
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/rumale-linear_model.svg)](https://badge.fury.io/rb/rumale-linear_model)
4
+ [![BSD 3-Clause License](https://img.shields.io/badge/License-BSD%203--Clause-orange.svg)](https://github.com/yoshoku/rumale/blob/main/rumale-linear_model/LICENSE.txt)
5
+ [![Documentation](https://img.shields.io/badge/api-reference-blue.svg)](https://yoshoku.github.io/rumale/doc/Rumale/LinearModel.html)
6
+
7
+ Rumale is a machine learning library in Ruby.
8
+ Rumale::LinearModel provides linear model algorithms,
9
+ such as Logistic Regression, Support Vector Machine, Lasso, and Ridge Regression
10
+ with Rumale interface.
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ ```ruby
17
+ gem 'rumale-linear_model'
18
+ ```
19
+
20
+ And then execute:
21
+
22
+ $ bundle install
23
+
24
+ Or install it yourself as:
25
+
26
+ $ gem install rumale-linear_model
27
+
28
+ ## Documentation
29
+
30
+ - [Rumale API Documentation - LinearModel](https://yoshoku.github.io/rumale/doc/Rumale/LinearModel.html)
31
+
32
+ ## License
33
+
34
+ The gem is available as open source under the terms of the [BSD-3-Clause License](https://opensource.org/licenses/BSD-3-Clause).
@@ -0,0 +1,275 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rumale/base/estimator'
4
+
5
+ module Rumale
6
+ module LinearModel
7
+ # @!visibility private
8
+ # This module consists of the classes that implement penalty (regularization) term.
9
+ module Penalty
10
+ # @!visibility private
11
+ # L2Penalty is a class that applies L2 penalty to weight vector of linear model.
12
+ # This class is used internally.
13
+ class L2Penalty
14
+ # @!visibility private
15
+ def initialize(reg_param:)
16
+ @reg_param = reg_param
17
+ end
18
+
19
+ # @!visibility private
20
+ def call(weight, lr)
21
+ weight - @reg_param * lr * weight
22
+ end
23
+ end
24
+
25
+ # @!visibility private
26
+ # L1Penalty is a class that applies L1 penalty to weight vector of linear model.
27
+ # This class is used internally.
28
+ class L1Penalty
29
+ # @!visibility private
30
+ def initialize(reg_param:)
31
+ @u = 0.0
32
+ @reg_param = reg_param
33
+ end
34
+
35
+ # @!visibility private
36
+ def call(weight, lr)
37
+ @q_vec ||= Numo::DFloat.zeros(weight.shape[0])
38
+ @u += @reg_param * lr
39
+ z = weight.dup
40
+ gt = weight.gt(0)
41
+ lt = weight.lt(0)
42
+ weight[gt] = Numo::DFloat.maximum(0.0, weight[gt] - (@u + @q_vec[gt])) if gt.count.positive?
43
+ weight[lt] = Numo::DFloat.minimum(0.0, weight[lt] + (@u - @q_vec[lt])) if lt.count.positive?
44
+ @q_vec += weight - z
45
+ weight
46
+ end
47
+ end
48
+ end
49
+
50
+ # @!visibility private
51
+ # This module consists of the class that implements stochastic gradient descent (SGD) optimizer.
52
+ module Optimizer
53
+ # @!visibility private
54
+ # SGD is a class that implements SGD optimizer.
55
+ # This class is used internally.
56
+ class SGD
57
+ # @!visibility private
58
+ # Create a new SGD optimizer.
59
+ # @param learning_rate [Float] The initial value of learning rate.
60
+ # @param momentum [Float] The initial value of momentum.
61
+ # @param decay [Float] The smooting parameter.
62
+ def initialize(learning_rate: 0.01, momentum: 0.0, decay: 0.0)
63
+ @learning_rate = learning_rate
64
+ @momentum = momentum
65
+ @decay = decay
66
+ @iter = 0
67
+ end
68
+
69
+ # @!visibility private
70
+ def current_learning_rate
71
+ @learning_rate / (1.0 + @decay * @iter)
72
+ end
73
+
74
+ # @!visibility private
75
+ def call(weight, gradient)
76
+ @update ||= Numo::DFloat.zeros(weight.shape[0])
77
+ @update = @momentum * @update - current_learning_rate * gradient
78
+ @iter += 1
79
+ weight + @update
80
+ end
81
+ end
82
+ end
83
+
84
+ # @!visibility private
85
+ # This module consists of the classes that implement loss function for linear model.
86
+ module Loss
87
+ # @!visibility private
88
+ # MeanSquaredError is a class that calculates mean squared error for linear regression model.
89
+ class MeanSquaredError
90
+ # @!visibility private
91
+ def loss(out, y)
92
+ ((out - y)**2).sum.fdiv(y.shape[0])
93
+ end
94
+
95
+ # @!visibility private
96
+ def dloss(out, y)
97
+ 2.fdiv(y.shape[0]) * (out - y)
98
+ end
99
+ end
100
+
101
+ # @!visibility private
102
+ # LogLoss is a class that calculates logistic loss for logistic regression.
103
+ class LogLoss
104
+ # @!visibility private
105
+ def loss(out, y)
106
+ Numo::NMath.log(1 + Numo::NMath.exp(-y * out)).sum.fdiv(y.shape[0])
107
+ end
108
+
109
+ # @!visibility private
110
+ def dloss(out, y)
111
+ y / (1 + Numo::NMath.exp(-y * out)) - y
112
+ end
113
+ end
114
+
115
+ # @!visibility private
116
+ # HingeLoss is a class that calculates hinge loss for support vector classifier.
117
+ class HingeLoss
118
+ # @!visibility private
119
+ def loss(out, y)
120
+ out.class.maximum(0.0, 1 - y * out).sum.fdiv(y.shape[0])
121
+ end
122
+
123
+ # @!visibility private
124
+ def dloss(out, y)
125
+ tids = (y * out).lt(1)
126
+ d = Numo::DFloat.zeros(y.shape[0])
127
+ d[tids] = -y[tids] if tids.count.positive?
128
+ d
129
+ end
130
+ end
131
+
132
+ # @!visibility private
133
+ # EpsilonInsensitive is a class that calculates epsilon insensitive for support vector regressor.
134
+ class EpsilonInsensitive
135
+ # @!visibility private
136
+ def initialize(epsilon: 0.1)
137
+ @epsilon = epsilon
138
+ end
139
+
140
+ # @!visibility private
141
+ def loss(out, y)
142
+ out.class.maximum(0.0, (y - out).abs - @epsilon).sum.fdiv(y.shape[0])
143
+ end
144
+
145
+ # @!visibility private
146
+ def dloss(out, y)
147
+ d = Numo::DFloat.zeros(y.shape[0])
148
+ tids = (out - y).gt(@epsilon)
149
+ d[tids] = 1 if tids.count.positive?
150
+ tids = (y - out).gt(@epsilon)
151
+ d[tids] = -1 if tids.count.positive?
152
+ d
153
+ end
154
+ end
155
+ end
156
+
157
+ # BaseSGD is an abstract class for implementation of linear model with mini-batch stochastic gradient descent (SGD) optimization.
158
+ # This class is used internally.
159
+ class BaseSGD < ::Rumale::Base::Estimator
160
+ # Create an initial linear model.
161
+ def initialize
162
+ super()
163
+ @params = {
164
+ learning_rate: 0.01,
165
+ decay: nil,
166
+ momentum: 0.0,
167
+ bias_scale: 1.0,
168
+ fit_bias: true,
169
+ reg_param: 0.0,
170
+ l1_ratio: 0.0,
171
+ max_iter: 1000,
172
+ batch_size: 50,
173
+ tol: 0.0001,
174
+ verbose: false
175
+ }
176
+ end
177
+
178
+ private
179
+
180
+ L2_PENALTY = 'l2'
181
+ L1_PENALTY = 'l1'
182
+ ELASTICNET_PENALTY = 'elasticnet'
183
+
184
+ private_constant :L2_PENALTY, :L1_PENALTY, :ELASTICNET_PENALTY
185
+
186
+ def partial_fit(x, y)
187
+ class_name = self.class.to_s.split('::').last if @params[:verbose]
188
+ narr = x.class
189
+ # Expand feature vectors for bias term.
190
+ x = expand_feature(x) if fit_bias?
191
+ # Initialize some variables.
192
+ sub_rng = @rng.dup
193
+ n_samples, n_features = x.shape
194
+ weight = Numo::DFloat.zeros(n_features)
195
+ optimizer = ::Rumale::LinearModel::Optimizer::SGD.new(
196
+ learning_rate: @params[:learning_rate], momentum: @params[:momentum], decay: @params[:decay]
197
+ )
198
+ l2_penalty = ::Rumale::LinearModel::Penalty::L2Penalty.new(reg_param: l2_reg_param) if apply_l2_penalty?
199
+ l1_penalty = ::Rumale::LinearModel::Penalty::L1Penalty.new(reg_param: l1_reg_param) if apply_l1_penalty?
200
+ # Optimization.
201
+ @params[:max_iter].times do |t|
202
+ sample_ids = Array(0...n_samples)
203
+ sample_ids.shuffle!(random: sub_rng)
204
+ until (subset_ids = sample_ids.shift(@params[:batch_size])).empty?
205
+ # sampling
206
+ sub_x = x[subset_ids, true]
207
+ sub_y = y[subset_ids]
208
+ # calculate gradient
209
+ dloss = @loss_func.dloss(sub_x.dot(weight), sub_y)
210
+ dloss = narr.minimum(1e12, narr.maximum(-1e12, dloss))
211
+ gradient = dloss.dot(sub_x)
212
+ # update weight
213
+ lr = optimizer.current_learning_rate
214
+ weight = optimizer.call(weight, gradient)
215
+ # l2 regularization
216
+ weight = l2_penalty.call(weight, lr) if apply_l2_penalty?
217
+ # l1 regularization
218
+ weight = l1_penalty.call(weight, lr) if apply_l1_penalty?
219
+ end
220
+ loss = @loss_func.loss(x.dot(weight), y)
221
+ puts "[#{class_name}] Loss after #{t + 1} epochs: #{loss}" if @params[:verbose]
222
+ break if loss < @params[:tol]
223
+ end
224
+ split_weight(weight)
225
+ end
226
+
227
+ def expand_feature(x)
228
+ n_samples = x.shape[0]
229
+ Numo::NArray.hstack([x, Numo::DFloat.ones([n_samples, 1]) * @params[:bias_scale]])
230
+ end
231
+
232
+ def split_weight(weight)
233
+ if fit_bias?
234
+ [weight[0...-1].dup, weight[-1]]
235
+ else
236
+ [weight, 0.0]
237
+ end
238
+ end
239
+
240
+ def fit_bias?
241
+ @params[:fit_bias] == true
242
+ end
243
+
244
+ def apply_l2_penalty?
245
+ @penalty_type == L2_PENALTY || @penalty_type == ELASTICNET_PENALTY
246
+ end
247
+
248
+ def apply_l1_penalty?
249
+ @penalty_type == L1_PENALTY || @penalty_type == ELASTICNET_PENALTY
250
+ end
251
+
252
+ def l2_reg_param
253
+ case @penalty_type
254
+ when ELASTICNET_PENALTY
255
+ @params[:reg_param] * (1.0 - @params[:l1_ratio])
256
+ when L2_PENALTY
257
+ @params[:reg_param]
258
+ else
259
+ 0.0
260
+ end
261
+ end
262
+
263
+ def l1_reg_param
264
+ case @penalty_type
265
+ when ELASTICNET_PENALTY
266
+ @params[:reg_param] * @params[:l1_ratio]
267
+ when L1_PENALTY
268
+ @params[:reg_param]
269
+ else
270
+ 0.0
271
+ end
272
+ end
273
+ end
274
+ end
275
+ end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rumale/base/regressor'
4
+ require 'rumale/validation'
5
+ require 'rumale/linear_model/base_sgd'
6
+
7
+ module Rumale
8
+ module LinearModel
9
+ # ElasticNet is a class that implements Elastic-net Regression
10
+ # with stochastic gradient descent (SGD) optimization.
11
+ #
12
+ # @example
13
+ # require 'rumale/linear_model/elastic_net'
14
+ #
15
+ # estimator =
16
+ # Rumale::LinearModel::ElasticNet.new(reg_param: 0.1, l1_ratio: 0.5, max_iter: 1000, batch_size: 50, random_seed: 1)
17
+ # estimator.fit(training_samples, traininig_values)
18
+ # results = estimator.predict(testing_samples)
19
+ #
20
+ # *Reference*
21
+ # - Shalev-Shwartz, S., and Singer, Y., "Pegasos: Primal Estimated sub-GrAdient SOlver for SVM," Proc. ICML'07, pp. 807--814, 2007.
22
+ # - Tsuruoka, Y., Tsujii, J., and Ananiadou, S., "Stochastic Gradient Descent Training for L1-regularized Log-linear Models with Cumulative Penalty," Proc. ACL'09, pp. 477--485, 2009.
23
+ # - Bottou, L., "Large-Scale Machine Learning with Stochastic Gradient Descent," Proc. COMPSTAT'10, pp. 177--186, 2010.
24
+ class ElasticNet < BaseSGD
25
+ include ::Rumale::Base::Regressor
26
+
27
+ # Return the weight vector.
28
+ # @return [Numo::DFloat] (shape: [n_outputs, n_features])
29
+ attr_reader :weight_vec
30
+
31
+ # Return the bias term (a.k.a. intercept).
32
+ # @return [Numo::DFloat] (shape: [n_outputs])
33
+ attr_reader :bias_term
34
+
35
+ # Return the random generator for random sampling.
36
+ # @return [Random]
37
+ attr_reader :rng
38
+
39
+ # Create a new Elastic-net regressor.
40
+ #
41
+ # @param learning_rate [Float] The initial value of learning rate.
42
+ # The learning rate decreases as the iteration proceeds according to the equation: learning_rate / (1 + decay * t).
43
+ # @param decay [Float] The smoothing parameter for decreasing learning rate as the iteration proceeds.
44
+ # If nil is given, the decay sets to 'reg_param * learning_rate'.
45
+ # @param momentum [Float] The momentum factor.
46
+ # @param reg_param [Float] The regularization parameter.
47
+ # @param l1_ratio [Float] The elastic-net mixing parameter.
48
+ # If l1_ratio = 1, the regularization is similar to Lasso.
49
+ # If l1_ratio = 0, the regularization is similar to Ridge.
50
+ # If 0 < l1_ratio < 1, the regularization is a combination of L1 and L2.
51
+ # @param fit_bias [Boolean] The flag indicating whether to fit the bias term.
52
+ # @param bias_scale [Float] The scale of the bias term.
53
+ # @param max_iter [Integer] The maximum number of epochs that indicates
54
+ # how many times the whole data is given to the training process.
55
+ # @param batch_size [Integer] The size of the mini batches.
56
+ # @param tol [Float] The tolerance of loss for terminating optimization.
57
+ # @param n_jobs [Integer] The number of jobs for running the fit method in parallel.
58
+ # If nil is given, the method does not execute in parallel.
59
+ # If zero or less is given, it becomes equal to the number of processors.
60
+ # This parameter is ignored if the Parallel gem is not loaded.
61
+ # @param verbose [Boolean] The flag indicating whether to output loss during iteration.
62
+ # @param random_seed [Integer] The seed value using to initialize the random generator.
63
+ def initialize(learning_rate: 0.01, decay: nil, momentum: 0.9,
64
+ reg_param: 1.0, l1_ratio: 0.5, fit_bias: true, bias_scale: 1.0,
65
+ max_iter: 1000, batch_size: 50, tol: 1e-4,
66
+ n_jobs: nil, verbose: false, random_seed: nil)
67
+ super()
68
+ @params.merge!(method(:initialize).parameters.to_h { |_t, arg| [arg, binding.local_variable_get(arg)] })
69
+ @params[:decay] ||= @params[:reg_param] * @params[:learning_rate]
70
+ @params[:random_seed] ||= srand
71
+ @rng = Random.new(@params[:random_seed])
72
+ @penalty_type = ELASTICNET_PENALTY
73
+ @loss_func = ::Rumale::LinearModel::Loss::MeanSquaredError.new
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::DFloat] (shape: [n_samples, n_outputs]) The target values to be used for fitting the model.
80
+ # @return [ElasticNet] The learned regressor itself.
81
+ def fit(x, y)
82
+ x = ::Rumale::Validation.check_convert_sample_array(x)
83
+ y = ::Rumale::Validation.check_convert_target_value_array(y)
84
+ ::Rumale::Validation.check_sample_size(x, y)
85
+
86
+ n_outputs = y.shape[1].nil? ? 1 : y.shape[1]
87
+ n_features = x.shape[1]
88
+
89
+ if n_outputs > 1
90
+ @weight_vec = Numo::DFloat.zeros(n_outputs, n_features)
91
+ @bias_term = Numo::DFloat.zeros(n_outputs)
92
+ if enable_parallel?
93
+ models = parallel_map(n_outputs) { |n| partial_fit(x, y[true, n]) }
94
+ n_outputs.times { |n| @weight_vec[n, true], @bias_term[n] = models[n] }
95
+ else
96
+ n_outputs.times { |n| @weight_vec[n, true], @bias_term[n] = partial_fit(x, y[true, n]) }
97
+ end
98
+ else
99
+ @weight_vec, @bias_term = partial_fit(x, y)
100
+ end
101
+ self
102
+ end
103
+
104
+ # Predict values for samples.
105
+ #
106
+ # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to predict the values.
107
+ # @return [Numo::DFloat] (shape: [n_samples, n_outputs]) Predicted values per sample.
108
+ def predict(x)
109
+ x = ::Rumale::Validation.check_convert_sample_array(x)
110
+
111
+ x.dot(@weight_vec.transpose) + @bias_term
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rumale/base/regressor'
4
+ require 'rumale/validation'
5
+ require 'rumale/linear_model/base_sgd'
6
+
7
+ module Rumale
8
+ module LinearModel
9
+ # Lasso is a class that implements Lasso Regression
10
+ # with stochastic gradient descent (SGD) optimization.
11
+ #
12
+ # @example
13
+ # require 'rumale/linear_model/lasso'
14
+ #
15
+ # estimator =
16
+ # Rumale::LinearModel::Lasso.new(reg_param: 0.1, max_iter: 1000, batch_size: 20, random_seed: 1)
17
+ # estimator.fit(training_samples, traininig_values)
18
+ # results = estimator.predict(testing_samples)
19
+ #
20
+ # *Reference*
21
+ # - Shalev-Shwartz, S., and Singer, Y., "Pegasos: Primal Estimated sub-GrAdient SOlver for SVM," Proc. ICML'07, pp. 807--814, 2007.
22
+ # - Tsuruoka, Y., Tsujii, J., and Ananiadou, S., "Stochastic Gradient Descent Training for L1-regularized Log-linear Models with Cumulative Penalty," Proc. ACL'09, pp. 477--485, 2009.
23
+ # - Bottou, L., "Large-Scale Machine Learning with Stochastic Gradient Descent," Proc. COMPSTAT'10, pp. 177--186, 2010.
24
+ class Lasso < BaseSGD
25
+ include ::Rumale::Base::Regressor
26
+
27
+ # Return the weight vector.
28
+ # @return [Numo::DFloat] (shape: [n_outputs, n_features])
29
+ attr_reader :weight_vec
30
+
31
+ # Return the bias term (a.k.a. intercept).
32
+ # @return [Numo::DFloat] (shape: [n_outputs])
33
+ attr_reader :bias_term
34
+
35
+ # Return the random generator for random sampling.
36
+ # @return [Random]
37
+ attr_reader :rng
38
+
39
+ # Create a new Lasso regressor.
40
+ #
41
+ # @param learning_rate [Float] The initial value of learning rate.
42
+ # The learning rate decreases as the iteration proceeds according to the equation: learning_rate / (1 + decay * t).
43
+ # @param decay [Float] The smoothing parameter for decreasing learning rate as the iteration proceeds.
44
+ # If nil is given, the decay sets to 'reg_param * learning_rate'.
45
+ # @param momentum [Float] The momentum factor.
46
+ # @param reg_param [Float] The regularization parameter.
47
+ # @param fit_bias [Boolean] The flag indicating whether to fit the bias term.
48
+ # @param bias_scale [Float] The scale of the bias term.
49
+ # @param max_iter [Integer] The maximum number of epochs that indicates
50
+ # how many times the whole data is given to the training process.
51
+ # @param batch_size [Integer] The size of the mini batches.
52
+ # @param tol [Float] The tolerance of loss for terminating optimization.
53
+ # @param n_jobs [Integer] The number of jobs for running the fit method in parallel.
54
+ # If nil is given, the method does not execute in parallel.
55
+ # If zero or less is given, it becomes equal to the number of processors.
56
+ # This parameter is ignored if the Parallel gem is not loaded.
57
+ # @param verbose [Boolean] The flag indicating whether to output loss during iteration.
58
+ # @param random_seed [Integer] The seed value using to initialize the random generator.
59
+ def initialize(learning_rate: 0.01, decay: nil, momentum: 0.9,
60
+ reg_param: 1.0, fit_bias: true, bias_scale: 1.0,
61
+ max_iter: 1000, batch_size: 50, tol: 1e-4,
62
+ n_jobs: nil, verbose: false, random_seed: nil)
63
+ super()
64
+ @params.merge!(method(:initialize).parameters.to_h { |_t, arg| [arg, binding.local_variable_get(arg)] })
65
+ @params[:decay] ||= @params[:reg_param] * @params[:learning_rate]
66
+ @params[:random_seed] ||= srand
67
+ @rng = Random.new(@params[:random_seed])
68
+ @penalty_type = L1_PENALTY
69
+ @loss_func = ::Rumale::LinearModel::Loss::MeanSquaredError.new
70
+ end
71
+
72
+ # Fit the model with given training data.
73
+ #
74
+ # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The training data to be used for fitting the model.
75
+ # @param y [Numo::DFloat] (shape: [n_samples, n_outputs]) The target values to be used for fitting the model.
76
+ # @return [Lasso] The learned regressor itself.
77
+ def fit(x, y)
78
+ x = ::Rumale::Validation.check_convert_sample_array(x)
79
+ y = ::Rumale::Validation.check_convert_target_value_array(y)
80
+ ::Rumale::Validation.check_sample_size(x, y)
81
+
82
+ n_outputs = y.shape[1].nil? ? 1 : y.shape[1]
83
+ n_features = x.shape[1]
84
+
85
+ if n_outputs > 1
86
+ @weight_vec = Numo::DFloat.zeros(n_outputs, n_features)
87
+ @bias_term = Numo::DFloat.zeros(n_outputs)
88
+ if enable_parallel?
89
+ models = parallel_map(n_outputs) { |n| partial_fit(x, y[true, n]) }
90
+ n_outputs.times { |n| @weight_vec[n, true], @bias_term[n] = models[n] }
91
+ else
92
+ n_outputs.times { |n| @weight_vec[n, true], @bias_term[n] = partial_fit(x, y[true, n]) }
93
+ end
94
+ else
95
+ @weight_vec, @bias_term = partial_fit(x, y)
96
+ end
97
+ self
98
+ end
99
+
100
+ # Predict values for samples.
101
+ #
102
+ # @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to predict the values.
103
+ # @return [Numo::DFloat] (shape: [n_samples, n_outputs]) Predicted values per sample.
104
+ def predict(x)
105
+ x = ::Rumale::Validation.check_convert_sample_array(x)
106
+
107
+ x.dot(@weight_vec.transpose) + @bias_term
108
+ end
109
+ end
110
+ end
111
+ end