Class: ClusterKit::Dimensionality::SVD
- Inherits:
-
Object
- Object
- ClusterKit::Dimensionality::SVD
- Defined in:
- lib/clusterkit/dimensionality/svd.rb
Overview
Singular Value Decomposition Decomposes a matrix into U, S, V^T components
Instance Attribute Summary collapse
-
#n_components ⇒ Object
readonly
Returns the value of attribute n_components.
-
#n_features ⇒ Object
readonly
Returns the value of attribute n_features.
-
#n_iter ⇒ Object
readonly
Returns the value of attribute n_iter.
-
#random_seed ⇒ Object
readonly
Returns the value of attribute random_seed.
-
#s ⇒ Object
readonly
Returns the value of attribute s.
-
#u ⇒ Object
readonly
Returns the value of attribute u.
-
#vt ⇒ Object
readonly
Returns the value of attribute vt.
Class Method Summary collapse
-
.randomized_svd(matrix, k, n_iter: 2) ⇒ Array
Class method for randomized SVD (kept for compatibility).
Instance Method Summary collapse
-
#components_u ⇒ Array<Array<Float>>
Get the U matrix (left singular vectors).
-
#components_vt ⇒ Array<Array<Float>>
Get the V^T matrix (right singular vectors, transposed).
-
#fit(data) ⇒ self
Fit the model to data.
-
#fit_transform(data) ⇒ Array
Fit the model and transform data in one step.
-
#fitted? ⇒ Boolean
Check if the model has been fitted.
-
#initialize(n_components: nil, n_iter: 2, random_seed: nil) ⇒ SVD
constructor
Initialize a new SVD instance.
-
#inverse_transform(transformed_data) ⇒ Array<Array<Float>>
Inverse transform (reconstruct from components).
-
#singular_values ⇒ Array<Float>
Get the singular values.
-
#transform(data) ⇒ Array<Array<Float>>
Transform data using fitted SVD (project onto components).
Constructor Details
#initialize(n_components: nil, n_iter: 2, random_seed: nil) ⇒ SVD
Initialize a new SVD instance
18 19 20 21 22 23 |
# File 'lib/clusterkit/dimensionality/svd.rb', line 18 def initialize(n_components: nil, n_iter: 2, random_seed: nil) @n_components = n_components @n_iter = n_iter @random_seed = random_seed @fitted = false end |
Instance Attribute Details
#n_components ⇒ Object (readonly)
Returns the value of attribute n_components.
11 12 13 |
# File 'lib/clusterkit/dimensionality/svd.rb', line 11 def n_components @n_components end |
#n_features ⇒ Object (readonly)
Returns the value of attribute n_features.
12 13 14 |
# File 'lib/clusterkit/dimensionality/svd.rb', line 12 def n_features @n_features end |
#n_iter ⇒ Object (readonly)
Returns the value of attribute n_iter.
11 12 13 |
# File 'lib/clusterkit/dimensionality/svd.rb', line 11 def n_iter @n_iter end |
#random_seed ⇒ Object (readonly)
Returns the value of attribute random_seed.
11 12 13 |
# File 'lib/clusterkit/dimensionality/svd.rb', line 11 def random_seed @random_seed end |
#s ⇒ Object (readonly)
Returns the value of attribute s.
12 13 14 |
# File 'lib/clusterkit/dimensionality/svd.rb', line 12 def s @s end |
#u ⇒ Object (readonly)
Returns the value of attribute u.
12 13 14 |
# File 'lib/clusterkit/dimensionality/svd.rb', line 12 def u @u end |
#vt ⇒ Object (readonly)
Returns the value of attribute vt.
12 13 14 |
# File 'lib/clusterkit/dimensionality/svd.rb', line 12 def vt @vt end |
Class Method Details
.randomized_svd(matrix, k, n_iter: 2) ⇒ Array
Class method for randomized SVD (kept for compatibility)
128 129 130 |
# File 'lib/clusterkit/dimensionality/svd.rb', line 128 def self.randomized_svd(matrix, k, n_iter: 2) ::ClusterKit::SVD.randomized_svd_rust(matrix, k, n_iter) end |
Instance Method Details
#components_u ⇒ Array<Array<Float>>
Get the U matrix (left singular vectors)
55 56 57 58 |
# File 'lib/clusterkit/dimensionality/svd.rb', line 55 def components_u raise RuntimeError, "Model must be fitted first" unless fitted? @u end |
#components_vt ⇒ Array<Array<Float>>
Get the V^T matrix (right singular vectors, transposed)
69 70 71 72 |
# File 'lib/clusterkit/dimensionality/svd.rb', line 69 def components_vt raise RuntimeError, "Model must be fitted first" unless fitted? @vt end |
#fit(data) ⇒ self
Fit the model to data
48 49 50 51 |
# File 'lib/clusterkit/dimensionality/svd.rb', line 48 def fit(data) fit_transform(data) self end |
#fit_transform(data) ⇒ Array
Fit the model and transform data in one step
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/clusterkit/dimensionality/svd.rb', line 28 def fit_transform(data) validate_input(data) # Store data characteristics for later transform operations @n_features = data.first.size @original_data_id = data.object_id # Determine n_components if not set n_comp = @n_components || [data.size, data.first.size].min # Call the Rust implementation @u, @s, @vt = self.class.randomized_svd(data, n_comp, n_iter: @n_iter) @fitted = true [@u, @s, @vt] end |
#fitted? ⇒ Boolean
Check if the model has been fitted
76 77 78 |
# File 'lib/clusterkit/dimensionality/svd.rb', line 76 def fitted? @fitted end |
#inverse_transform(transformed_data) ⇒ Array<Array<Float>>
Inverse transform (reconstruct from components)
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/clusterkit/dimensionality/svd.rb', line 103 def inverse_transform(transformed_data) raise RuntimeError, "Model must be fitted first" unless fitted? # Reconstruction: (U * S) * V^T # transformed_data should be U * S # We multiply by V^T to reconstruct result = [] transformed_data.each do |row| reconstructed = Array.new(@vt.first.size, 0.0) row.each_with_index do |val, i| @vt[i].each_with_index do |v, j| reconstructed[j] += val * v end end result << reconstructed end result end |
#singular_values ⇒ Array<Float>
Get the singular values
62 63 64 65 |
# File 'lib/clusterkit/dimensionality/svd.rb', line 62 def singular_values raise RuntimeError, "Model must be fitted first" unless fitted? @s end |
#transform(data) ⇒ Array<Array<Float>>
Transform data using fitted SVD (project onto components)
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/clusterkit/dimensionality/svd.rb', line 83 def transform(data) raise RuntimeError, "Model must be fitted first" unless fitted? validate_transform_input(data) if data.object_id == @original_data_id # Same data that was fitted - return U * S @u.map.with_index do |row, i| row.map.with_index { |val, j| val * @s[j] } end else # New data - project onto V components: data × V # Since we have V^T, we need to transpose it back to V # V = V^T^T, so we project: data × V^T^T transform_new_data(data) end end |