Class: Rumale::Manifold::LaplacianEigenmaps

Inherits:
Base::Estimator
  • Object
show all
Includes:
Base::Transformer
Defined in:
lib/rumale/manifold/laplacian_eigenmaps.rb

Overview

LaplacianEigenmaps is a class that implements Laplacian Eigenmaps.

Reference

  • Belkin, M., and Niyogi, P., “Laplacian Eigenmaps and Spectral Techniques for Embedding and Clustering,” Proc. NIPS’01, pp. 585–591, 2001.

Examples:

require 'numo/linalg/autoloader'
require 'rumale/manifold/laplacian_eigenmaps'

lem = Rumale::Manifold::LaplacianEigenmaps.new(n_components: 2, n_neighbors: 15)
z = lem.fit_transform(x)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(n_components: 2, gamma: nil, n_neighbors: 10) ⇒ LaplacianEigenmaps

Create a new transformer with Laplacian Eigenmaps.

Parameters:

  • n_components (Integer) (defaults to: 2)

    The number of dimensions on representation space.

  • gamma (Nil/Float) (defaults to: nil)

    The parameter of RBF kernel. If nil is given, the weight of affinity matrix sets to 1.

  • n_neighbors (Integer) (defaults to: 10)

    The number of nearest neighbors for k-nearest neighbor graph construction.



33
34
35
36
37
38
39
40
# File 'lib/rumale/manifold/laplacian_eigenmaps.rb', line 33

def initialize(n_components: 2, gamma: nil, n_neighbors: 10)
  super()
  @params = {
    n_components: n_components,
    gamma: gamma,
    n_neighbors: [1, n_neighbors].max
  }
end

Instance Attribute Details

#embeddingNumo::DFloat (readonly)

Return the data in representation space.

Returns:

  • (Numo::DFloat)

    (shape: [n_samples, n_components])



26
27
28
# File 'lib/rumale/manifold/laplacian_eigenmaps.rb', line 26

def embedding
  @embedding
end

Instance Method Details

#fit(x) ⇒ LaplacianEigenmaps

Fit the model with given training data.

Returns The learned transformer itself.

Parameters:

  • x (Numo::DFloat)

    (shape: [n_samples, n_features]) The training data to be used for fitting the model.

Returns:



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/rumale/manifold/laplacian_eigenmaps.rb', line 47

def fit(x, _y = nil)
  raise 'LaplacianEigenmaps#fit requires Numo::Linalg but that is not loaded' unless enable_linalg?(warning: false)

  x = Rumale::Validation.check_convert_sample_array(x)

  distance_mat = Rumale::PairwiseMetric.squared_error(x)
  neighbor_graph = k_neighbor_graph(distance_mat, @params[:n_neighbors], true)
  affinity_mat = if @params[:gamma].nil?
                   neighbor_graph
                 else
                   neighbor_graph * Numo::NMath.exp(-@params[:gamma] * distance_mat)
                 end
  degree_mat = affinity_mat.sum(axis: 1).diag
  laplacian_mat = degree_mat - affinity_mat

  _, eig_vecs = Numo::Linalg.eigh(laplacian_mat, degree_mat, vals_range: 1...(1 + @params[:n_components]))

  @embedding = @params[:n_components] == 1 ? eig_vecs[true, 0].dup : eig_vecs.dup
  @x_train = x.dup

  self
end

#fit_transform(x) ⇒ Numo::DFloat

Fit the model with training data, and then transform them with the learned model.

Returns (shape: [n_samples, n_components]) The transformed data.

Parameters:

  • x (Numo::DFloat)

    (shape: [n_samples, n_features]) The training data to be used for fitting the model.

Returns:

  • (Numo::DFloat)

    (shape: [n_samples, n_components]) The transformed data



75
76
77
78
79
80
81
# File 'lib/rumale/manifold/laplacian_eigenmaps.rb', line 75

def fit_transform(x, _y = nil)
  unless enable_linalg?(warning: false)
    raise 'LaplacianEigenmaps#fit_transform requires Numo::Linalg but that is not loaded'
  end

  fit(x).transform(x)
end

#transform(x) ⇒ Numo::DFloat

Transform the given data with the learned model.

Parameters:

  • x (Numo::DFloat)

    (shape: [n_samples, n_features]) The data to be transformed with the learned model.

Returns:

  • (Numo::DFloat)

    (shape: [n_samples, n_components]) The transformed data.



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/rumale/manifold/laplacian_eigenmaps.rb', line 87

def transform(x)
  x = Rumale::Validation.check_convert_sample_array(x)

  distance_mat = Rumale::PairwiseMetric.squared_error(x, @x_train)
  neighbor_graph = k_neighbor_graph(distance_mat, @params[:n_neighbors], false)
  affinity_mat = if @params[:gamma].nil?
                   neighbor_graph
                 else
                   neighbor_graph * Numo::NMath.exp(-@params[:gamma] * distance_mat)
                 end
  normalizer = Numo::NMath.sqrt(affinity_mat.mean * affinity_mat.mean(axis: 1))
  n_train_samples = @x_train.shape[0]
  weight_mat = 1.fdiv(n_train_samples) * (affinity_mat.transpose / normalizer).transpose
  weight_mat.dot(@embedding)
end