Class: Rumale::Manifold::MDS
- Inherits:
-
Base::Estimator
- Object
- Base::Estimator
- Rumale::Manifold::MDS
- Includes:
- Base::Transformer
- Defined in:
- rumale-manifold/lib/rumale/manifold/mds.rb
Overview
MDS is a class that implements Metric Multidimensional Scaling (MDS) with Scaling by MAjorizing a COmplicated Function (SMACOF) algorithm.
Reference
-
Groenen, P J. F. and van de Velden, M., “Multidimensional Scaling by Majorization: A Review,” J. of Statistical Software, Vol. 73 (8), 2016.
Instance Attribute Summary collapse
-
#embedding ⇒ Numo::DFloat
readonly
Return the data in representation space.
-
#n_iter ⇒ Integer
readonly
Return the number of iterations run for optimization.
-
#rng ⇒ Random
readonly
Return the random generator.
-
#stress ⇒ Float
readonly
Return the stress function value after optimization.
Attributes inherited from Base::Estimator
Instance Method Summary collapse
-
#fit(x) ⇒ MDS
Fit the model with given training data.
-
#fit_transform(x) ⇒ Numo::DFloat
Fit the model with training data, and then transform them with the learned model.
-
#initialize(n_components: 2, metric: 'euclidean', init: 'random', max_iter: 300, tol: nil, verbose: false, random_seed: nil) ⇒ MDS
constructor
Create a new transformer with MDS.
Constructor Details
#initialize(n_components: 2, metric: 'euclidean', init: 'random', max_iter: 300, tol: nil, verbose: false, random_seed: nil) ⇒ MDS
Create a new transformer with MDS.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'rumale-manifold/lib/rumale/manifold/mds.rb', line 56 def initialize(n_components: 2, metric: 'euclidean', init: 'random', max_iter: 300, tol: nil, verbose: false, random_seed: nil) super() @params = { n_components: n_components, max_iter: max_iter, tol: tol, metric: metric, init: init, verbose: verbose, random_seed: random_seed || srand } @rng = Random.new(@params[:random_seed]) end |
Instance Attribute Details
#embedding ⇒ Numo::DFloat (readonly)
Return the data in representation space.
28 29 30 |
# File 'rumale-manifold/lib/rumale/manifold/mds.rb', line 28 def @embedding end |
#n_iter ⇒ Integer (readonly)
Return the number of iterations run for optimization
36 37 38 |
# File 'rumale-manifold/lib/rumale/manifold/mds.rb', line 36 def n_iter @n_iter end |
#rng ⇒ Random (readonly)
Return the random generator.
40 41 42 |
# File 'rumale-manifold/lib/rumale/manifold/mds.rb', line 40 def rng @rng end |
#stress ⇒ Float (readonly)
Return the stress function value after optimization.
32 33 34 |
# File 'rumale-manifold/lib/rumale/manifold/mds.rb', line 32 def stress @stress end |
Instance Method Details
#fit(x) ⇒ MDS
Fit the model with given training data.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'rumale-manifold/lib/rumale/manifold/mds.rb', line 77 def fit(x, _not_used = nil) x = ::Rumale::Validation.check_convert_sample_array(x) if @params[:metric] == 'precomputed' && x.shape[0] != x.shape[1] raise ArgumentError, 'Expect the input distance matrix to be square.' end # initialize some varibales. n_samples = x.shape[0] hi_distance_mat = @params[:metric] == 'precomputed' ? x : ::Rumale::PairwiseMetric.euclidean_distance(x) @embedding = (x) lo_distance_mat = ::Rumale::PairwiseMetric.euclidean_distance(@embedding) @stress = calc_stress(hi_distance_mat, lo_distance_mat) @n_iter = 0 # perform optimization. @params[:max_iter].times do |t| # guttman tarnsform. ratio = hi_distance_mat / lo_distance_mat ratio[ratio.diag_indices] = 0.0 ratio[lo_distance_mat.eq(0)] = 0.0 tmp_mat = -ratio tmp_mat[tmp_mat.diag_indices] += ratio.sum(axis: 1) @embedding = 1.fdiv(n_samples) * tmp_mat.dot(@embedding) lo_distance_mat = ::Rumale::PairwiseMetric.euclidean_distance(@embedding) # check convergence. new_stress = calc_stress(hi_distance_mat, lo_distance_mat) if terminate?(@stress, new_stress) @stress = new_stress break end # next step. @n_iter = t + 1 @stress = new_stress puts "[MDS] stress function after #{@n_iter} iterations: #{@stress}" if @params[:verbose] && (@n_iter % 100).zero? end self end |
#fit_transform(x) ⇒ Numo::DFloat
Fit the model with training data, and then transform them with the learned model.
120 121 122 123 124 125 |
# File 'rumale-manifold/lib/rumale/manifold/mds.rb', line 120 def fit_transform(x, _not_used = nil) x = ::Rumale::Validation.check_convert_sample_array(x) fit(x) @embedding.dup end |