rumale 0.17.3 → 0.18.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/CHANGELOG.md +5 -0
- data/README.md +3 -4
- data/lib/rumale.rb +3 -0
- data/lib/rumale/metric_learning/fisher_discriminant_analysis.rb +113 -0
- data/lib/rumale/metric_learning/neighbourhood_component_analysis.rb +183 -0
- data/lib/rumale/model_selection/function.rb +42 -0
- data/lib/rumale/pairwise_metric.rb +9 -8
- data/lib/rumale/version.rb +1 -1
- data/rumale.gemspec +5 -2
- metadata +24 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7caefe8d0715984980daede523f1944460bcff7dd782c431b7e95d851ddfbf82
|
4
|
+
data.tar.gz: 05ba1863410dcaabd31dc281c921011a9625f75980c137ab8c88f302c33042b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 06a95f1fda83e546954e235f06c5b487cc393a340c48b1316b9ef2d0fafbb5be4bb4de02681c6b7b013915695ecd06a04a8692c9df2ba9822e3ba4e01925c0df
|
7
|
+
data.tar.gz: 0e5e1ae19fbb420cba2914f251b8ba44de29f4eb9feed31d5bcdb0dc4003a9221053bedddc3214faf8803282965c9dbd51c1e3e81df94fe6bb4fa8c6afbfe277
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
# 0.18.0
|
2
|
+
- Add transformer class for [FisherDiscriminantAnalysis](https://yoshoku.github.io/rumale/doc/Rumale/MetricLearning/FisherDiscriminantAnalysis.html).
|
3
|
+
- Add transformer class for [NeighbourhoodComponentAnalysis](https://yoshoku.github.io/rumale/doc/Rumale/MetricLearning/NeighbourhoodComponentAnalysis.html).
|
4
|
+
- Add [module function](https://yoshoku.github.io/rumale/doc/Rumale/ModelSelection.html#train_test_split-class_method) for hold-out validation.
|
5
|
+
|
1
6
|
# 0.17.3
|
2
7
|
- Add pipeline class for [FeatureUnion](https://yoshoku.github.io/rumale/doc/Rumale/Pipeline/FeatureUnion.html).
|
3
8
|
- Fix to use mmh3 gem for generating hash value on [FeatureHasher](https://yoshoku.github.io/rumale/doc/Rumale/FeatureExtraction/FeatureHasher.html).
|
data/README.md
CHANGED
@@ -15,12 +15,11 @@ Logistic Regression, Ridge, Lasso, Factorization Machine,
|
|
15
15
|
Multi-layer Perceptron,
|
16
16
|
Naive Bayes, Decision Tree, Gradient Tree Boosting, Random Forest,
|
17
17
|
K-Means, Gaussian Mixture Model, DBSCAN, Spectral Clustering,
|
18
|
-
Mutidimensional Scaling, t-SNE,
|
18
|
+
Mutidimensional Scaling, t-SNE,
|
19
|
+
Fisher Discriminant Analysis, Neighbourhood Component Analysis,
|
20
|
+
Principal Component Analysis, Non-negative Matrix Factorization,
|
19
21
|
and many other algorithms.
|
20
22
|
|
21
|
-
This project was formerly known as "SVMKit".
|
22
|
-
If you are using SVMKit, please install Rumale and replace `SVMKit` constants with `Rumale`.
|
23
|
-
|
24
23
|
## Installation
|
25
24
|
|
26
25
|
Add this line to your application's Gemfile:
|
data/lib/rumale.rb
CHANGED
@@ -78,6 +78,8 @@ require 'rumale/decomposition/factor_analysis'
|
|
78
78
|
require 'rumale/decomposition/fast_ica'
|
79
79
|
require 'rumale/manifold/tsne'
|
80
80
|
require 'rumale/manifold/mds'
|
81
|
+
require 'rumale/metric_learning/fisher_discriminant_analysis'
|
82
|
+
require 'rumale/metric_learning/neighbourhood_component_analysis.rb'
|
81
83
|
require 'rumale/neural_network/adam'
|
82
84
|
require 'rumale/neural_network/base_mlp'
|
83
85
|
require 'rumale/neural_network/mlp_regressor'
|
@@ -100,6 +102,7 @@ require 'rumale/model_selection/shuffle_split'
|
|
100
102
|
require 'rumale/model_selection/stratified_shuffle_split'
|
101
103
|
require 'rumale/model_selection/cross_validation'
|
102
104
|
require 'rumale/model_selection/grid_search_cv'
|
105
|
+
require 'rumale/model_selection/function'
|
103
106
|
require 'rumale/evaluation_measure/accuracy'
|
104
107
|
require 'rumale/evaluation_measure/precision'
|
105
108
|
require 'rumale/evaluation_measure/recall'
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rumale/base/base_estimator'
|
4
|
+
require 'rumale/base/transformer'
|
5
|
+
|
6
|
+
module Rumale
|
7
|
+
# Module for metric learning algorithms.
|
8
|
+
module MetricLearning
|
9
|
+
# FisherDiscriminantAnalysis is a class that implements Fisher Discriminant Analysis.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# transformer = Rumale::MetricLearning::FisherDiscriminantAnalysis.new
|
13
|
+
# transformer.fit(training_samples, traininig_labels)
|
14
|
+
# low_samples = transformer.transform(testing_samples)
|
15
|
+
#
|
16
|
+
# *Reference*
|
17
|
+
# - Fisher, R. A., "The use of multiple measurements in taxonomic problems," Annals of Eugenics, vol. 7, pp. 179--188, 1936.
|
18
|
+
# - Sugiyama, M., "Local Fisher Discriminant Analysis for Supervised Dimensionality Reduction," Proc. ICML'06, pp. 905--912, 2006.
|
19
|
+
class FisherDiscriminantAnalysis
|
20
|
+
include Base::BaseEstimator
|
21
|
+
include Base::Transformer
|
22
|
+
|
23
|
+
# Returns the transform matrix.
|
24
|
+
# @return [Numo::DFloat] (shape: [n_components, n_features])
|
25
|
+
attr_reader :components
|
26
|
+
|
27
|
+
# Returns the mean vector.
|
28
|
+
# @return [Numo::DFloat] (shape: [n_features])
|
29
|
+
attr_reader :mean
|
30
|
+
|
31
|
+
# Returns the class mean vectors.
|
32
|
+
# @return [Numo::DFloat] (shape: [n_classes, n_features])
|
33
|
+
attr_reader :class_means
|
34
|
+
|
35
|
+
# Return the class labels.
|
36
|
+
# @return [Numo::Int32] (shape: [n_classes])
|
37
|
+
attr_reader :classes
|
38
|
+
|
39
|
+
# Create a new transformer with FisherDiscriminantAnalysis.
|
40
|
+
#
|
41
|
+
# @param n_components [Integer] The number of components.
|
42
|
+
# If nil is given, the number of components will be set to [n_features, n_classes - 1].min
|
43
|
+
def initialize(n_components: nil)
|
44
|
+
check_params_numeric_or_nil(n_components: n_components)
|
45
|
+
@params = {}
|
46
|
+
@params[:n_components] = n_components
|
47
|
+
end
|
48
|
+
|
49
|
+
# Fit the model with given training data.
|
50
|
+
#
|
51
|
+
# @param x [Numo::DFloat] (shape: [n_samples, n_features]) The training data to be used for fitting the model.
|
52
|
+
# @param y [Numo::Int32] (shape: [n_samples]) The labels to be used for fitting the model.
|
53
|
+
# @return [FisherDiscriminantAnalysis] The learned classifier itself.
|
54
|
+
def fit(x, y)
|
55
|
+
x = check_convert_sample_array(x)
|
56
|
+
y = check_convert_label_array(y)
|
57
|
+
check_sample_label_size(x, y)
|
58
|
+
raise 'FisherDiscriminatAnalysis#fit requires Numo::Linalg but that is not loaded.' unless enable_linalg?
|
59
|
+
|
60
|
+
# initialize some variables.
|
61
|
+
n_features = x.shape[1]
|
62
|
+
@classes = Numo::Int32[*y.to_a.uniq.sort]
|
63
|
+
n_classes = @classes.size
|
64
|
+
n_components = if @params[:n_components].nil?
|
65
|
+
[n_features, n_classes - 1].min
|
66
|
+
else
|
67
|
+
[n_features, @params[:n_components]].min
|
68
|
+
end
|
69
|
+
|
70
|
+
# calculate within and between scatter matricies.
|
71
|
+
within_mat = Numo::DFloat.zeros(n_features, n_features)
|
72
|
+
between_mat = Numo::DFloat.zeros(n_features, n_features)
|
73
|
+
@class_means = Numo::DFloat.zeros(n_classes, n_features)
|
74
|
+
@mean = x.mean(0)
|
75
|
+
@classes.each_with_index do |label, i|
|
76
|
+
mask_vec = y.eq(label)
|
77
|
+
sz_class = mask_vec.count
|
78
|
+
class_samples = x[mask_vec, true]
|
79
|
+
class_mean = class_samples.mean(0)
|
80
|
+
within_mat += (class_samples - class_mean).transpose.dot(class_samples - class_mean)
|
81
|
+
between_mat += sz_class * (class_mean - @mean).expand_dims(1) * (class_mean - @mean)
|
82
|
+
@class_means[i, true] = class_mean
|
83
|
+
end
|
84
|
+
|
85
|
+
# calculate components.
|
86
|
+
_, evecs = Numo::Linalg.eigh(between_mat, within_mat, vals_range: (n_features - n_components)...n_features)
|
87
|
+
comps = evecs.reverse(1).transpose.dup
|
88
|
+
@components = n_components == 1 ? comps[0, true].dup : comps.dup
|
89
|
+
self
|
90
|
+
end
|
91
|
+
|
92
|
+
# Fit the model with training data, and then transform them with the learned model.
|
93
|
+
#
|
94
|
+
# @param x [Numo::DFloat] (shape: [n_samples, n_features]) The training data to be used for fitting the model.
|
95
|
+
# @param y [Numo::Int32] (shape: [n_samples]) The labels to be used for fitting the model.
|
96
|
+
# @return [Numo::DFloat] (shape: [n_samples, n_components]) The transformed data
|
97
|
+
def fit_transform(x, y)
|
98
|
+
x = check_convert_sample_array(x)
|
99
|
+
y = check_convert_label_array(y)
|
100
|
+
fit(x, y).transform(x)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Transform the given data with the learned model.
|
104
|
+
#
|
105
|
+
# @param x [Numo::DFloat] (shape: [n_samples, n_features]) The data to be transformed with the learned model.
|
106
|
+
# @return [Numo::DFloat] (shape: [n_samples, n_components]) The transformed data.
|
107
|
+
def transform(x)
|
108
|
+
x = check_convert_sample_array(x)
|
109
|
+
x.dot(@components.transpose)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rumale/base/base_estimator'
|
4
|
+
require 'rumale/base/transformer'
|
5
|
+
require 'mopti/scaled_conjugate_gradient'
|
6
|
+
|
7
|
+
module Rumale
|
8
|
+
module MetricLearning
|
9
|
+
# NeighbourhoodComponentAnalysis is a class that implements Neighbourhood Component Analysis.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# transformer = Rumale::MetricLearning::NeighbourhoodComponentAnalysis.new
|
13
|
+
# transformer.fit(training_samples, traininig_labels)
|
14
|
+
# low_samples = transformer.transform(testing_samples)
|
15
|
+
#
|
16
|
+
# *Reference*
|
17
|
+
# - Goldberger, J., Roweis, S., Hinton, G., and Salakhutdinov, R., "Neighbourhood Component Analysis," Advances in NIPS'17, pp. 513--520, 2005.
|
18
|
+
class NeighbourhoodComponentAnalysis
|
19
|
+
include Base::BaseEstimator
|
20
|
+
include Base::Transformer
|
21
|
+
|
22
|
+
# Returns the neighbourhood components.
|
23
|
+
# @return [Numo::DFloat] (shape: [n_components, n_features])
|
24
|
+
attr_reader :components
|
25
|
+
|
26
|
+
# Return the number of iterations run for optimization
|
27
|
+
# @return [Integer]
|
28
|
+
attr_reader :n_iter
|
29
|
+
|
30
|
+
# Return the random generator.
|
31
|
+
# @return [Random]
|
32
|
+
attr_reader :rng
|
33
|
+
|
34
|
+
# Create a new transformer with NeighbourhoodComponentAnalysis.
|
35
|
+
#
|
36
|
+
# @param n_components [Integer] The number of components.
|
37
|
+
# @param init [String] The initialization method for components ('random' or 'pca').
|
38
|
+
# @param max_iter [Integer] The maximum number of iterations.
|
39
|
+
# @param tol [Float] The tolerance of termination criterion.
|
40
|
+
# @param verbose [Boolean] The flag indicating whether to output loss during iteration.
|
41
|
+
# @param random_seed [Integer] The seed value using to initialize the random generator.
|
42
|
+
def initialize(n_components: nil, init: 'random', max_iter: 100, tol: 1e-6, verbose: false, random_seed: nil)
|
43
|
+
check_params_numeric_or_nil(n_components: n_components, random_seed: random_seed)
|
44
|
+
check_params_numeric(max_iter: max_iter, tol: tol)
|
45
|
+
check_params_string(init: init)
|
46
|
+
check_params_boolean(verbose: verbose)
|
47
|
+
@params = {}
|
48
|
+
@params[:n_components] = n_components
|
49
|
+
@params[:init] = init
|
50
|
+
@params[:max_iter] = max_iter
|
51
|
+
@params[:tol] = tol
|
52
|
+
@params[:verbose] = verbose
|
53
|
+
@params[:random_seed] = random_seed
|
54
|
+
@params[:random_seed] ||= srand
|
55
|
+
@components = nil
|
56
|
+
@n_iter = nil
|
57
|
+
@rng = Random.new(@params[:random_seed])
|
58
|
+
end
|
59
|
+
|
60
|
+
# Fit the model with given training data.
|
61
|
+
#
|
62
|
+
# @param x [Numo::DFloat] (shape: [n_samples, n_features]) The training data to be used for fitting the model.
|
63
|
+
# @param y [Numo::Int32] (shape: [n_samples]) The labels to be used for fitting the model.
|
64
|
+
# @return [NeighbourhoodComponentAnalysis] The learned classifier itself.
|
65
|
+
def fit(x, y)
|
66
|
+
x = check_convert_sample_array(x)
|
67
|
+
y = check_convert_label_array(y)
|
68
|
+
check_sample_label_size(x, y)
|
69
|
+
n_features = x.shape[1]
|
70
|
+
n_components = if @params[:n_components].nil?
|
71
|
+
n_features
|
72
|
+
else
|
73
|
+
[n_features, @params[:n_components]].min
|
74
|
+
end
|
75
|
+
@components, @n_iter = optimize_components(x, y, n_features, n_components)
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
# Fit the model with training data, and then transform them with the learned model.
|
80
|
+
#
|
81
|
+
# @param x [Numo::DFloat] (shape: [n_samples, n_features]) The training data to be used for fitting the model.
|
82
|
+
# @param y [Numo::Int32] (shape: [n_samples]) The labels to be used for fitting the model.
|
83
|
+
# @return [Numo::DFloat] (shape: [n_samples, n_components]) The transformed data
|
84
|
+
def fit_transform(x, y)
|
85
|
+
x = check_convert_sample_array(x)
|
86
|
+
y = check_convert_label_array(y)
|
87
|
+
fit(x, y).transform(x)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Transform the given data with the learned model.
|
91
|
+
#
|
92
|
+
# @param x [Numo::DFloat] (shape: [n_samples, n_features]) The data to be transformed with the learned model.
|
93
|
+
# @return [Numo::DFloat] (shape: [n_samples, n_components]) The transformed data.
|
94
|
+
def transform(x)
|
95
|
+
x = check_convert_sample_array(x)
|
96
|
+
x.dot(@components.transpose)
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def init_components(x, n_features, n_components)
|
102
|
+
if @params[:init] == 'pca'
|
103
|
+
pca = Rumale::Decomposition::PCA.new(n_components: n_components, solver: 'evd')
|
104
|
+
pca.fit(x).components.flatten.dup
|
105
|
+
else
|
106
|
+
Rumale::Utils.rand_normal([n_features, n_components], @rng.dup).flatten.dup
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def optimize_components(x, y, n_features, n_components)
|
111
|
+
# initialize components.
|
112
|
+
comp_init = init_components(x, n_features, n_components)
|
113
|
+
# initialize optimization results.
|
114
|
+
res = {}
|
115
|
+
res[:x] = comp_init
|
116
|
+
res[:n_iter] = 0
|
117
|
+
# perform optimization.
|
118
|
+
optimizer = Mopti::ScaledConjugateGradient.new(
|
119
|
+
fnc: method(:nca_loss), jcb: method(:nca_dloss),
|
120
|
+
x_init: comp_init, args: [x, y],
|
121
|
+
max_iter: @params[:max_iter], ftol: @params[:tol]
|
122
|
+
)
|
123
|
+
fold = 0.0
|
124
|
+
dold = 0.0
|
125
|
+
optimizer.each do |prm|
|
126
|
+
res = prm
|
127
|
+
puts "[NeighbourhoodComponentAnalysis] The value of objective function after #{res[:n_iter]} epochs: #{x.shape[0] - res[:fnc]}" if @params[:verbose]
|
128
|
+
break if (fold - res[:fnc]).abs <= @params[:tol] && (dold - res[:jcb]).abs <= @params[:tol]
|
129
|
+
fold = res[:fnc]
|
130
|
+
dold = res[:jcb]
|
131
|
+
end
|
132
|
+
# return the results.
|
133
|
+
n_iter = res[:n_iter]
|
134
|
+
comps = n_components == 1 ? res[:x].dup : res[:x].reshape(n_components, n_features)
|
135
|
+
[comps, n_iter]
|
136
|
+
end
|
137
|
+
|
138
|
+
def nca_loss(w, x, y)
|
139
|
+
# initialize some variables.
|
140
|
+
n_samples, n_features = x.shape
|
141
|
+
n_components = w.size / n_features
|
142
|
+
# projection.
|
143
|
+
w = w.reshape(n_components, n_features)
|
144
|
+
z = x.dot(w.transpose)
|
145
|
+
# calculate probability matrix.
|
146
|
+
prob_mat = probability_matrix(z)
|
147
|
+
# calculate loss.
|
148
|
+
# NOTE:
|
149
|
+
# NCA attempts to maximize its objective function.
|
150
|
+
# For the minization algorithm, the objective function value is subtracted from the maixmum value (n_samples).
|
151
|
+
mask_mat = y.expand_dims(1).eq(y)
|
152
|
+
masked_prob_mat = prob_mat * mask_mat
|
153
|
+
n_samples - masked_prob_mat.sum
|
154
|
+
end
|
155
|
+
|
156
|
+
def nca_dloss(w, x, y)
|
157
|
+
# initialize some variables.
|
158
|
+
n_features = x.shape[1]
|
159
|
+
n_components = w.size / n_features
|
160
|
+
# projection.
|
161
|
+
w = w.reshape(n_components, n_features)
|
162
|
+
z = x.dot(w.transpose)
|
163
|
+
# calculate probability matrix.
|
164
|
+
prob_mat = probability_matrix(z)
|
165
|
+
# calculate gradient.
|
166
|
+
mask_mat = y.expand_dims(1).eq(y)
|
167
|
+
masked_prob_mat = prob_mat * mask_mat
|
168
|
+
weighted_prob_mat = masked_prob_mat - prob_mat * masked_prob_mat.sum(1).expand_dims(1)
|
169
|
+
weighted_prob_mat += weighted_prob_mat.transpose
|
170
|
+
weighted_prob_mat[weighted_prob_mat.diag_indices] = -weighted_prob_mat.sum(0)
|
171
|
+
gradient = 2 * z.transpose.dot(weighted_prob_mat).dot(x)
|
172
|
+
-gradient.flatten.dup
|
173
|
+
end
|
174
|
+
|
175
|
+
def probability_matrix(z)
|
176
|
+
prob_mat = Numo::NMath.exp(-Rumale::PairwiseMetric.squared_error(z))
|
177
|
+
prob_mat[prob_mat.diag_indices] = 0.0
|
178
|
+
prob_mat /= prob_mat.sum(1).expand_dims(1)
|
179
|
+
prob_mat
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rumale/model_selection/shuffle_split'
|
4
|
+
require 'rumale/model_selection/stratified_shuffle_split'
|
5
|
+
|
6
|
+
module Rumale
|
7
|
+
module ModelSelection
|
8
|
+
module_function
|
9
|
+
|
10
|
+
# Split randomly data set into test and train data.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# x_train, x_test, y_train, y_test = Rumale::ModelSelection.train_test_split(x, y, test_size: 0.2, stratify: true, random_seed: 1)
|
14
|
+
#
|
15
|
+
# @param x [Numo::DFloat] (shape: [n_samples, n_features]) The dataset to be used to generate data indices.
|
16
|
+
# @param y [Numo::Int32] (shape: [n_samples]) The labels to be used to generate data indices for stratified random permutation.
|
17
|
+
# If stratify = false, this parameter is ignored.
|
18
|
+
# @param test_size [Float] The ratio of number of samples for test data.
|
19
|
+
# @param train_size [Float] The ratio of number of samples for train data.
|
20
|
+
# If nil is given, it sets to 1 - test_size.
|
21
|
+
# @param stratify [Boolean] The flag indicating whether to perform stratify split.
|
22
|
+
# @param random_seed [Integer] The seed value using to initialize the random generator.
|
23
|
+
# @return [Array<Numo::NArray>] The set of training and testing data.
|
24
|
+
def train_test_split(x, y = nil, test_size: 0.1, train_size: nil, stratify: false, random_seed: nil)
|
25
|
+
splitter = if stratify
|
26
|
+
Rumale::ModelSelection::StratifiedShuffleSplit.new(
|
27
|
+
n_splits: 1, test_size: test_size, train_size: train_size, random_seed: random_seed
|
28
|
+
)
|
29
|
+
else
|
30
|
+
Rumale::ModelSelection::ShuffleSplit.new(
|
31
|
+
n_splits: 1, test_size: test_size, train_size: train_size, random_seed: random_seed
|
32
|
+
)
|
33
|
+
end
|
34
|
+
train_ids, test_ids = splitter.split(x, y).first
|
35
|
+
x_train = x[train_ids, true].dup
|
36
|
+
y_train = y[train_ids].dup
|
37
|
+
x_test = x[test_ids, true].dup
|
38
|
+
y_test = y[test_ids].dup
|
39
|
+
[x_train, x_test, y_train, y_test]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -42,15 +42,16 @@ module Rumale
|
|
42
42
|
# @param y [Numo::DFloat] (shape: [n_samples_y, n_features])
|
43
43
|
# @return [Numo::DFloat] (shape: [n_samples_x, n_samples_x] or [n_samples_x, n_samples_y] if y is given)
|
44
44
|
def squared_error(x, y = nil)
|
45
|
-
|
45
|
+
y_not_given = y.nil?
|
46
|
+
y = x if y_not_given
|
46
47
|
x = Rumale::Validation.check_convert_sample_array(x)
|
47
|
-
y = Rumale::Validation.check_convert_sample_array(y)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
48
|
+
y = Rumale::Validation.check_convert_sample_array(y) unless y_not_given
|
49
|
+
sum_x_vec = (x**2).sum(1).expand_dims(1)
|
50
|
+
sum_y_vec = y_not_given ? sum_x_vec.transpose : (y**2).sum(1).expand_dims(1).transpose
|
51
|
+
err_mat = -2 * x.dot(y.transpose)
|
52
|
+
err_mat += sum_x_vec
|
53
|
+
err_mat += sum_y_vec
|
54
|
+
err_mat.class.maximum(err_mat, 0)
|
54
55
|
end
|
55
56
|
|
56
57
|
# Calculate the rbf kernel between x and y.
|
data/lib/rumale/version.rb
CHANGED
data/rumale.gemspec
CHANGED
@@ -20,7 +20,9 @@ Gem::Specification.new do |spec|
|
|
20
20
|
Multi-layer Perceptron,
|
21
21
|
Naive Bayes, Decision Tree, Gradient Tree Boosting, Random Forest,
|
22
22
|
K-Means, Gaussian Mixture Model, DBSCAN, Spectral Clustering,
|
23
|
-
Mutidimensional Scaling, t-SNE,
|
23
|
+
Mutidimensional Scaling, t-SNE,
|
24
|
+
Fisher Discriminant Analysis, Neighbourhood Component Analysis,
|
25
|
+
Principal Component Analysis, Non-negative Matrix Factorization,
|
24
26
|
and many other algorithms.
|
25
27
|
MSG
|
26
28
|
spec.homepage = 'https://github.com/yoshoku/rumale'
|
@@ -45,13 +47,14 @@ Gem::Specification.new do |spec|
|
|
45
47
|
spec.required_ruby_version = '>= 2.3'
|
46
48
|
|
47
49
|
spec.add_runtime_dependency 'numo-narray', '>= 0.9.1'
|
50
|
+
spec.add_runtime_dependency 'mopti', '~> 0.1'
|
48
51
|
spec.add_runtime_dependency 'mmh3', '~> 0.1'
|
49
52
|
|
50
53
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
51
54
|
spec.add_development_dependency 'coveralls', '~> 0.8'
|
52
55
|
spec.add_development_dependency 'numo-linalg', '>= 0.1.4'
|
53
56
|
spec.add_development_dependency 'parallel', '>= 1.17.0'
|
54
|
-
spec.add_development_dependency 'rake', '~>
|
57
|
+
spec.add_development_dependency 'rake', '~> 12.0'
|
55
58
|
spec.add_development_dependency 'rake-compiler', '~> 1.0'
|
56
59
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
57
60
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rumale
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.18.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- yoshoku
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-02
|
11
|
+
date: 2020-03-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: numo-narray
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.9.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mopti
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.1'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.1'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: mmh3
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -100,14 +114,14 @@ dependencies:
|
|
100
114
|
requirements:
|
101
115
|
- - "~>"
|
102
116
|
- !ruby/object:Gem::Version
|
103
|
-
version: '
|
117
|
+
version: '12.0'
|
104
118
|
type: :development
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
122
|
- - "~>"
|
109
123
|
- !ruby/object:Gem::Version
|
110
|
-
version: '
|
124
|
+
version: '12.0'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: rake-compiler
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -144,7 +158,9 @@ description: |
|
|
144
158
|
Multi-layer Perceptron,
|
145
159
|
Naive Bayes, Decision Tree, Gradient Tree Boosting, Random Forest,
|
146
160
|
K-Means, Gaussian Mixture Model, DBSCAN, Spectral Clustering,
|
147
|
-
Mutidimensional Scaling, t-SNE,
|
161
|
+
Mutidimensional Scaling, t-SNE,
|
162
|
+
Fisher Discriminant Analysis, Neighbourhood Component Analysis,
|
163
|
+
Principal Component Analysis, Non-negative Matrix Factorization,
|
148
164
|
and many other algorithms.
|
149
165
|
email:
|
150
166
|
- yoshoku@outlook.com
|
@@ -239,7 +255,10 @@ files:
|
|
239
255
|
- lib/rumale/linear_model/svr.rb
|
240
256
|
- lib/rumale/manifold/mds.rb
|
241
257
|
- lib/rumale/manifold/tsne.rb
|
258
|
+
- lib/rumale/metric_learning/fisher_discriminant_analysis.rb
|
259
|
+
- lib/rumale/metric_learning/neighbourhood_component_analysis.rb
|
242
260
|
- lib/rumale/model_selection/cross_validation.rb
|
261
|
+
- lib/rumale/model_selection/function.rb
|
243
262
|
- lib/rumale/model_selection/grid_search_cv.rb
|
244
263
|
- lib/rumale/model_selection/k_fold.rb
|
245
264
|
- lib/rumale/model_selection/shuffle_split.rb
|