rumale-linear_model 0.24.0 → 0.26.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 +4 -4
- data/LICENSE.txt +1 -1
- data/lib/rumale/linear_model/base_estimator.rb +46 -0
- data/lib/rumale/linear_model/elastic_net.rb +112 -61
- data/lib/rumale/linear_model/lasso.rb +107 -61
- data/lib/rumale/linear_model/linear_regression.rb +39 -104
- data/lib/rumale/linear_model/logistic_regression.rb +36 -119
- data/lib/rumale/linear_model/nnls.rb +14 -46
- data/lib/rumale/linear_model/ridge.rb +39 -108
- data/lib/rumale/linear_model/sgd_classifier.rb +262 -0
- data/lib/rumale/linear_model/{base_sgd.rb → sgd_estimator.rb} +36 -21
- data/lib/rumale/linear_model/sgd_regressor.rb +138 -0
- data/lib/rumale/linear_model/svc.rb +60 -68
- data/lib/rumale/linear_model/svr.rb +54 -52
- data/lib/rumale/linear_model/version.rb +1 -1
- data/lib/rumale/linear_model.rb +2 -1
- metadata +8 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 68480352c1ab25d2242da8364a3377ee6ef0a1241c3299b5ffda0d3b699e81be
|
4
|
+
data.tar.gz: c02626de09115b2ce65dd6d4174d89fe1854a8385c33fa0c942822ba6d0a4c54
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 23ed6fe1871d0fc6e8f10e32076257624683954f6f13fbd164289297ca845eaceb9829ae64e5a2af66b119bfa9a13cc3d609a767d9e97fc39ec88a59fcceaa7f
|
7
|
+
data.tar.gz: ab43f09a3fcecbe7b8c82a29f33380d363a4bfa056392f83cca931a4d839805250ad05640b0f1219cd78b72e824c6303427b62c02a362a26d08a1c0f9b220bfe
|
data/LICENSE.txt
CHANGED
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rumale/base/estimator'
|
4
|
+
|
5
|
+
module Rumale
|
6
|
+
# This module consists of the classes that implement generalized linear models.
|
7
|
+
module LinearModel
|
8
|
+
# BaseEstimator is an abstract class for implementation of linear model. This class is used internally.
|
9
|
+
class BaseEstimator < Rumale::Base::Estimator
|
10
|
+
# Return the weight vector.
|
11
|
+
# @return [Numo::DFloat] (shape: [n_outputs/n_classes, n_features])
|
12
|
+
attr_reader :weight_vec
|
13
|
+
|
14
|
+
# Return the bias term (a.k.a. intercept).
|
15
|
+
# @return [Numo::DFloat] (shape: [n_outputs/n_classes])
|
16
|
+
attr_reader :bias_term
|
17
|
+
|
18
|
+
# Create an initial linear model.
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def expand_feature(x)
|
23
|
+
n_samples = x.shape[0]
|
24
|
+
Numo::NArray.hstack([x, Numo::DFloat.ones([n_samples, 1]) * @params[:bias_scale]])
|
25
|
+
end
|
26
|
+
|
27
|
+
def split_weight(w)
|
28
|
+
if w.ndim == 1
|
29
|
+
if fit_bias?
|
30
|
+
[w[0...-1].dup, w[-1]]
|
31
|
+
else
|
32
|
+
[w, 0.0]
|
33
|
+
end
|
34
|
+
elsif fit_bias?
|
35
|
+
[w[true, 0...-1].dup, w[true, -1].dup]
|
36
|
+
else
|
37
|
+
[w, Numo::DFloat.zeros(w.shape[0])]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def fit_bias?
|
42
|
+
@params[:fit_bias] == true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -1,48 +1,34 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'rumale/base/regressor'
|
4
|
+
require 'rumale/utils'
|
4
5
|
require 'rumale/validation'
|
5
|
-
|
6
|
+
|
7
|
+
require_relative 'base_estimator'
|
6
8
|
|
7
9
|
module Rumale
|
8
10
|
module LinearModel
|
9
|
-
# ElasticNet is a class that implements Elastic-net Regression
|
10
|
-
# with stochastic gradient descent (SGD) optimization.
|
11
|
+
# ElasticNet is a class that implements Elastic-net Regression with cordinate descent optimization.
|
11
12
|
#
|
12
13
|
# @example
|
13
14
|
# require 'rumale/linear_model/elastic_net'
|
14
15
|
#
|
15
|
-
# estimator =
|
16
|
-
# Rumale::LinearModel::ElasticNet.new(reg_param: 0.1, l1_ratio: 0.5, max_iter: 1000, batch_size: 50, random_seed: 1)
|
16
|
+
# estimator = Rumale::LinearModel::ElasticNet.new(reg_param: 0.1, l1_ratio: 0.5)
|
17
17
|
# estimator.fit(training_samples, traininig_values)
|
18
18
|
# results = estimator.predict(testing_samples)
|
19
19
|
#
|
20
20
|
# *Reference*
|
21
|
-
# -
|
22
|
-
# -
|
23
|
-
|
24
|
-
|
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
|
21
|
+
# - Friedman, J., Hastie, T., and Tibshirani, R., "Regularization Paths for Generalized Linear Models via Coordinate Descent," Journal of Statistical Software, 33 (1), pp. 1--22, 2010.
|
22
|
+
# - Simon, N., Friedman, J., and Hastie, T., "A Blockwise Descent Algorithm for Group-penalized Multiresponse and Multinomial Regression," arXiv preprint arXiv:1311.6529, 2013.
|
23
|
+
class ElasticNet < Rumale::LinearModel::BaseEstimator
|
24
|
+
include Rumale::Base::Regressor
|
34
25
|
|
35
|
-
# Return the
|
36
|
-
# @return [
|
37
|
-
attr_reader :
|
26
|
+
# Return the number of iterations performed in coordinate descent optimization.
|
27
|
+
# @return [Integer]
|
28
|
+
attr_reader :n_iter
|
38
29
|
|
39
30
|
# Create a new Elastic-net regressor.
|
40
31
|
#
|
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
32
|
# @param reg_param [Float] The regularization parameter.
|
47
33
|
# @param l1_ratio [Float] The elastic-net mixing parameter.
|
48
34
|
# If l1_ratio = 1, the regularization is similar to Lasso.
|
@@ -52,25 +38,17 @@ module Rumale
|
|
52
38
|
# @param bias_scale [Float] The scale of the bias term.
|
53
39
|
# @param max_iter [Integer] The maximum number of epochs that indicates
|
54
40
|
# how many times the whole data is given to the training process.
|
55
|
-
# @param batch_size [Integer] The size of the mini batches.
|
56
41
|
# @param tol [Float] The tolerance of loss for terminating optimization.
|
57
|
-
|
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)
|
42
|
+
def initialize(reg_param: 1.0, l1_ratio: 0.5, fit_bias: true, bias_scale: 1.0, max_iter: 1000, tol: 1e-4)
|
67
43
|
super()
|
68
|
-
@params
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
44
|
+
@params = {
|
45
|
+
reg_param: reg_param,
|
46
|
+
l1_ratio: l1_ratio,
|
47
|
+
fit_bias: fit_bias,
|
48
|
+
bias_scale: bias_scale,
|
49
|
+
max_iter: max_iter,
|
50
|
+
tol: tol
|
51
|
+
}
|
74
52
|
end
|
75
53
|
|
76
54
|
# Fit the model with given training data.
|
@@ -79,25 +57,19 @@ module Rumale
|
|
79
57
|
# @param y [Numo::DFloat] (shape: [n_samples, n_outputs]) The target values to be used for fitting the model.
|
80
58
|
# @return [ElasticNet] The learned regressor itself.
|
81
59
|
def fit(x, y)
|
82
|
-
x =
|
83
|
-
y =
|
84
|
-
|
60
|
+
x = Rumale::Validation.check_convert_sample_array(x)
|
61
|
+
y = Rumale::Validation.check_convert_target_value_array(y)
|
62
|
+
Rumale::Validation.check_sample_size(x, y)
|
85
63
|
|
86
|
-
|
87
|
-
|
64
|
+
@n_iter = 0
|
65
|
+
x = expand_feature(x) if fit_bias?
|
66
|
+
|
67
|
+
@weight_vec, @bias_term = if single_target?(y)
|
68
|
+
partial_fit(x, y)
|
69
|
+
else
|
70
|
+
partial_fit_multi(x, y)
|
71
|
+
end
|
88
72
|
|
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
73
|
self
|
102
74
|
end
|
103
75
|
|
@@ -106,10 +78,89 @@ module Rumale
|
|
106
78
|
# @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to predict the values.
|
107
79
|
# @return [Numo::DFloat] (shape: [n_samples, n_outputs]) Predicted values per sample.
|
108
80
|
def predict(x)
|
109
|
-
x =
|
81
|
+
x = Rumale::Validation.check_convert_sample_array(x)
|
110
82
|
|
111
83
|
x.dot(@weight_vec.transpose) + @bias_term
|
112
84
|
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def partial_fit(x, y)
|
89
|
+
l1_reg = @params[:reg_param] * @params[:l1_ratio]
|
90
|
+
l2_reg = @params[:reg_param] * (1.0 - @params[:l1_ratio])
|
91
|
+
n_features = x.shape[1]
|
92
|
+
w = Numo::DFloat.zeros(n_features)
|
93
|
+
x_norms = (x**2).sum(axis: 0)
|
94
|
+
residual = y - x.dot(w)
|
95
|
+
|
96
|
+
@params[:max_iter].times do |iter|
|
97
|
+
w_err = 0.0
|
98
|
+
n_features.times do |j|
|
99
|
+
next if x_norms[j].zero?
|
100
|
+
|
101
|
+
w_prev = w[j]
|
102
|
+
|
103
|
+
residual += w[j] * x[true, j]
|
104
|
+
z = x[true, j].dot(residual)
|
105
|
+
w[j] = soft_threshold(z, l1_reg).fdiv(x_norms[j] + l2_reg)
|
106
|
+
residual -= w[j] * x[true, j]
|
107
|
+
|
108
|
+
w_err = [w_err, (w[j] - w_prev).abs].max
|
109
|
+
end
|
110
|
+
|
111
|
+
@n_iter = iter + 1
|
112
|
+
|
113
|
+
break if w_err <= @params[:tol]
|
114
|
+
end
|
115
|
+
|
116
|
+
split_weight(w)
|
117
|
+
end
|
118
|
+
|
119
|
+
def partial_fit_multi(x, y)
|
120
|
+
l1_reg = @params[:reg_param] * @params[:l1_ratio]
|
121
|
+
l2_reg = @params[:reg_param] * (1.0 - @params[:l1_ratio])
|
122
|
+
n_features = x.shape[1]
|
123
|
+
n_outputs = y.shape[1]
|
124
|
+
w = Numo::DFloat.zeros(n_outputs, n_features)
|
125
|
+
x_norms = (x**2).sum(axis: 0)
|
126
|
+
residual = y - x.dot(w.transpose)
|
127
|
+
|
128
|
+
@params[:max_iter].times do |iter|
|
129
|
+
w_err = 0.0
|
130
|
+
n_features.times do |j|
|
131
|
+
next if x_norms[j].zero?
|
132
|
+
|
133
|
+
w_prev = w[true, j]
|
134
|
+
|
135
|
+
residual += x[true, j].expand_dims(1) * w[true, j]
|
136
|
+
z = x[true, j].dot(residual)
|
137
|
+
w[true, j] = [1.0 - l1_reg.fdiv(Math.sqrt((z**2).sum)), 0.0].max.fdiv(x_norms[j] + l2_reg) * z
|
138
|
+
residual -= x[true, j].expand_dims(1) * w[true, j]
|
139
|
+
|
140
|
+
w_err = [w_err, (w[true, j] - w_prev).abs.max].max
|
141
|
+
end
|
142
|
+
|
143
|
+
@n_iter = iter + 1
|
144
|
+
|
145
|
+
break if w_err <= @params[:tol]
|
146
|
+
end
|
147
|
+
|
148
|
+
split_weight(w)
|
149
|
+
end
|
150
|
+
|
151
|
+
def soft_threshold(z, threshold)
|
152
|
+
sign(z) * [z.abs - threshold, 0].max
|
153
|
+
end
|
154
|
+
|
155
|
+
def sign(z)
|
156
|
+
return 0.0 if z.zero?
|
157
|
+
|
158
|
+
z.positive? ? 1.0 : -1.0
|
159
|
+
end
|
160
|
+
|
161
|
+
def single_target?(y)
|
162
|
+
y.ndim == 1
|
163
|
+
end
|
113
164
|
end
|
114
165
|
end
|
115
166
|
end
|
@@ -1,72 +1,49 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'rumale/base/estimator'
|
3
4
|
require 'rumale/base/regressor'
|
4
5
|
require 'rumale/validation'
|
5
|
-
|
6
|
+
|
7
|
+
require_relative 'base_estimator'
|
6
8
|
|
7
9
|
module Rumale
|
8
10
|
module LinearModel
|
9
|
-
# Lasso is a class that implements Lasso Regression
|
10
|
-
# with stochastic gradient descent (SGD) optimization.
|
11
|
+
# Lasso is a class that implements Lasso Regression with coordinate descent optimization.
|
11
12
|
#
|
12
13
|
# @example
|
13
14
|
# require 'rumale/linear_model/lasso'
|
14
15
|
#
|
15
|
-
# estimator =
|
16
|
-
# Rumale::LinearModel::Lasso.new(reg_param: 0.1, max_iter: 1000, batch_size: 20, random_seed: 1)
|
16
|
+
# estimator = Rumale::LinearModel::Lasso.new(reg_param: 0.1)
|
17
17
|
# estimator.fit(training_samples, traininig_values)
|
18
18
|
# results = estimator.predict(testing_samples)
|
19
19
|
#
|
20
20
|
# *Reference*
|
21
|
-
# -
|
22
|
-
# -
|
23
|
-
|
24
|
-
|
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
|
21
|
+
# - Friedman, J., Hastie, T., and Tibshirani, R., "Regularization Paths for Generalized Linear Models via Coordinate Descent," Journal of Statistical Software, 33 (1), pp. 1--22, 2010.
|
22
|
+
# - Simon, N., Friedman, J., and Hastie, T., "A Blockwise Descent Algorithm for Group-penalized Multiresponse and Multinomial Regression," arXiv preprint arXiv:1311.6529, 2013.
|
23
|
+
class Lasso < Rumale::LinearModel::BaseEstimator
|
24
|
+
include Rumale::Base::Regressor
|
34
25
|
|
35
|
-
# Return the
|
36
|
-
# @return [
|
37
|
-
attr_reader :
|
26
|
+
# Return the number of iterations performed in coordinate descent optimization.
|
27
|
+
# @return [Integer]
|
28
|
+
attr_reader :n_iter
|
38
29
|
|
39
30
|
# Create a new Lasso regressor.
|
40
31
|
#
|
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
32
|
# @param reg_param [Float] The regularization parameter.
|
47
33
|
# @param fit_bias [Boolean] The flag indicating whether to fit the bias term.
|
48
34
|
# @param bias_scale [Float] The scale of the bias term.
|
49
35
|
# @param max_iter [Integer] The maximum number of epochs that indicates
|
50
36
|
# how many times the whole data is given to the training process.
|
51
|
-
# @param batch_size [Integer] The size of the mini batches.
|
52
37
|
# @param tol [Float] The tolerance of loss for terminating optimization.
|
53
|
-
|
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)
|
38
|
+
def initialize(reg_param: 1.0, fit_bias: true, bias_scale: 1.0, max_iter: 1000, tol: 1e-4)
|
63
39
|
super()
|
64
|
-
@params
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
40
|
+
@params = {
|
41
|
+
reg_param: reg_param,
|
42
|
+
fit_bias: fit_bias,
|
43
|
+
bias_scale: bias_scale,
|
44
|
+
max_iter: max_iter,
|
45
|
+
tol: tol
|
46
|
+
}
|
70
47
|
end
|
71
48
|
|
72
49
|
# Fit the model with given training data.
|
@@ -75,25 +52,19 @@ module Rumale
|
|
75
52
|
# @param y [Numo::DFloat] (shape: [n_samples, n_outputs]) The target values to be used for fitting the model.
|
76
53
|
# @return [Lasso] The learned regressor itself.
|
77
54
|
def fit(x, y)
|
78
|
-
x =
|
79
|
-
y =
|
80
|
-
|
55
|
+
x = Rumale::Validation.check_convert_sample_array(x)
|
56
|
+
y = Rumale::Validation.check_convert_target_value_array(y)
|
57
|
+
Rumale::Validation.check_sample_size(x, y)
|
81
58
|
|
82
|
-
|
83
|
-
|
59
|
+
@n_iter = 0
|
60
|
+
x = expand_feature(x) if fit_bias?
|
61
|
+
|
62
|
+
@weight_vec, @bias_term = if single_target?(y)
|
63
|
+
partial_fit(x, y)
|
64
|
+
else
|
65
|
+
partial_fit_multi(x, y)
|
66
|
+
end
|
84
67
|
|
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
68
|
self
|
98
69
|
end
|
99
70
|
|
@@ -102,10 +73,85 @@ module Rumale
|
|
102
73
|
# @param x [Numo::DFloat] (shape: [n_samples, n_features]) The samples to predict the values.
|
103
74
|
# @return [Numo::DFloat] (shape: [n_samples, n_outputs]) Predicted values per sample.
|
104
75
|
def predict(x)
|
105
|
-
x =
|
76
|
+
x = Rumale::Validation.check_convert_sample_array(x)
|
106
77
|
|
107
78
|
x.dot(@weight_vec.transpose) + @bias_term
|
108
79
|
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def partial_fit(x, y)
|
84
|
+
n_features = x.shape[1]
|
85
|
+
w = Numo::DFloat.zeros(n_features)
|
86
|
+
x_norms = (x**2).sum(axis: 0)
|
87
|
+
residual = y - x.dot(w)
|
88
|
+
|
89
|
+
@params[:max_iter].times do |iter|
|
90
|
+
w_err = 0.0
|
91
|
+
n_features.times do |j|
|
92
|
+
next if x_norms[j].zero?
|
93
|
+
|
94
|
+
w_prev = w[j]
|
95
|
+
|
96
|
+
residual += w[j] * x[true, j]
|
97
|
+
z = x[true, j].dot(residual)
|
98
|
+
w[j] = soft_threshold(z, @params[:reg_param]).fdiv(x_norms[j])
|
99
|
+
residual -= w[j] * x[true, j]
|
100
|
+
|
101
|
+
w_err = [w_err, (w[j] - w_prev).abs].max
|
102
|
+
end
|
103
|
+
|
104
|
+
@n_iter = iter + 1
|
105
|
+
|
106
|
+
break if w_err <= @params[:tol]
|
107
|
+
end
|
108
|
+
|
109
|
+
split_weight(w)
|
110
|
+
end
|
111
|
+
|
112
|
+
def partial_fit_multi(x, y)
|
113
|
+
n_features = x.shape[1]
|
114
|
+
n_outputs = y.shape[1]
|
115
|
+
w = Numo::DFloat.zeros(n_outputs, n_features)
|
116
|
+
x_norms = (x**2).sum(axis: 0)
|
117
|
+
residual = y - x.dot(w.transpose)
|
118
|
+
|
119
|
+
@params[:max_iter].times do |iter|
|
120
|
+
w_err = 0.0
|
121
|
+
n_features.times do |j|
|
122
|
+
next if x_norms[j].zero?
|
123
|
+
|
124
|
+
w_prev = w[true, j]
|
125
|
+
|
126
|
+
residual += x[true, j].expand_dims(1) * w[true, j]
|
127
|
+
z = x[true, j].dot(residual)
|
128
|
+
w[true, j] = [1.0 - @params[:reg_param].fdiv(Math.sqrt((z**2).sum)), 0.0].max.fdiv(x_norms[j]) * z
|
129
|
+
residual -= x[true, j].expand_dims(1) * w[true, j]
|
130
|
+
|
131
|
+
w_err = [w_err, (w[true, j] - w_prev).abs.max].max
|
132
|
+
end
|
133
|
+
|
134
|
+
@n_iter = iter + 1
|
135
|
+
|
136
|
+
break if w_err <= @params[:tol]
|
137
|
+
end
|
138
|
+
|
139
|
+
split_weight(w)
|
140
|
+
end
|
141
|
+
|
142
|
+
def soft_threshold(z, threshold)
|
143
|
+
sign(z) * [z.abs - threshold, 0].max
|
144
|
+
end
|
145
|
+
|
146
|
+
def sign(z)
|
147
|
+
return 0.0 if z.zero?
|
148
|
+
|
149
|
+
z.positive? ? 1.0 : -1.0
|
150
|
+
end
|
151
|
+
|
152
|
+
def single_target?(y)
|
153
|
+
y.ndim == 1
|
154
|
+
end
|
109
155
|
end
|
110
156
|
end
|
111
157
|
end
|