Class: KMeans::Node
Instance Attribute Summary collapse
-
#centroid ⇒ Object
Records which centroid the node is assigned to.
-
#position ⇒ Object
readonly
The position on every dimension.
Class Method Summary collapse
-
.add_node(node) ⇒ Object
Adds a node, clears the cache, asserts that the parameter is a node.
-
.add_nodes(*nodes) ⇒ Object
Instantiates the node object and adds them to the list.
-
.clear_nodes! ⇒ Object
Clears out all nodes.
-
.cluster_to(centroids, scaling = nil) ⇒ Object
Returns the number of re-assignments made.
- .dimension_size ⇒ Object
- .dimension_size=(val) ⇒ Object
-
.find_boundaries ⇒ Object
(also: boundaries)
Gets the max and min on every dimension for every node.
-
.nodes ⇒ Object
A list of nodes initialized.
-
.random_centroid ⇒ Object
A centroid that fits between the boundaries on each dimension.
Instance Method Summary collapse
- #distance(centroid = nil, scaling = nil) ⇒ Object
-
#initialize(*position) ⇒ Node
constructor
Creates a node based only on the position.
- #move_to(centroid) ⇒ Object
Constructor Details
#initialize(*position) ⇒ Node
Creates a node based only on the position. The dimension cardinality is enforced on the class level (I.e., all nodes must have the same number of position.)
97 98 99 100 |
# File 'lib/kmeans/node.rb', line 97 def initialize(*position) @position = position Node.add_node(self) end |
Instance Attribute Details
#centroid ⇒ Object
Records which centroid the node is assigned to
103 104 105 |
# File 'lib/kmeans/node.rb', line 103 def centroid @centroid end |
#position ⇒ Object (readonly)
The position on every dimension
92 93 94 |
# File 'lib/kmeans/node.rb', line 92 def position @position end |
Class Method Details
.add_node(node) ⇒ Object
Adds a node, clears the cache, asserts that the parameter is a node.
67 68 69 70 71 72 73 74 75 |
# File 'lib/kmeans/node.rb', line 67 def add_node(node) node = new(*node) unless node.is_a?(Node) self.dimension_size = node.position.size if self.nodes.empty? raise ArgumentError, "Node does not have the right number of positions" unless node.position.size == self.dimension_size self.nodes << node @@boundaries = nil node end |
.add_nodes(*nodes) ⇒ Object
Instantiates the node object and adds them to the list. Example: Node.add_nodes [1,2,3], [4,5,3], [2,1,3] Node.add_nodes *node_list
60 61 62 63 64 |
# File 'lib/kmeans/node.rb', line 60 def add_nodes(*nodes) nodes.each do |node| node = new(*node) end end |
.clear_nodes! ⇒ Object
Clears out all nodes. Don’t do this while working on a specific problem, but in-between problems. This nodes-on-the-Node stuff needs to be adjusted when I have some time.
8 9 10 |
# File 'lib/kmeans/node.rb', line 8 def clear_nodes! self.nodes.clear end |
.cluster_to(centroids, scaling = nil) ⇒ Object
Returns the number of re-assignments made
13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/kmeans/node.rb', line 13 def cluster_to(centroids, scaling=nil) n = 0 self.nodes.each do |node| position = centroids.map { |centroid| node.distance(centroid, scaling) }.min_position target_centroid = centroids[position] next if target_centroid == node.centroid node.move_to(target_centroid) n += 1 end n end |
.dimension_size ⇒ Object
49 50 51 |
# File 'lib/kmeans/node.rb', line 49 def dimension_size @@dimension_size end |
.dimension_size=(val) ⇒ Object
53 54 55 |
# File 'lib/kmeans/node.rb', line 53 def dimension_size=(val) @@dimension_size = val end |
.find_boundaries ⇒ Object Also known as: boundaries
Gets the max and min on every dimension for every node
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/kmeans/node.rb', line 26 def find_boundaries return nil if self.nodes.empty? return @@boundaries if @@boundaries # Building this long-hand for good reason... dimensional_array = [] self.dimension_size.times {dimensional_array << [nil, nil]} @@boundaries = self.nodes.inject(dimensional_array) do |list, node| node.position.each_with_index do |dimension, i| list[i][0] ||= dimension list[i][1] ||= dimension list[i][0] = dimension if dimension < list[i][0] list[i][1] = dimension if dimension > list[i][1] end list end end |
.nodes ⇒ Object
A list of nodes initialized
45 46 47 |
# File 'lib/kmeans/node.rb', line 45 def nodes @@nodes ||= [] end |
.random_centroid ⇒ Object
A centroid that fits between the boundaries on each dimension. The boundaries for a 3-dimensional model might look like:
- [1,5], [0,10], [1,100]
-
This means that the first dimension can be between 1 and 5, the second between 0 and 10, and the third between 1 and 100.
82 83 84 85 86 87 |
# File 'lib/kmeans/node.rb', line 82 def random_centroid position = (0...self.dimension_size).inject([]) do |list, i| list << rand_between(self.boundaries[i].first, self.boundaries[i].last) end Centroid.new(position) end |
Instance Method Details
#distance(centroid = nil, scaling = nil) ⇒ Object
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/kmeans/node.rb', line 105 def distance(centroid=nil, scaling=nil) centroid ||= self.centroid op = centroid.position map = self.position.map_with_index do |e, i| if scaling ( (op[i] * scaling[i]) - (e * scaling[i]) ) ** 2 else (op[i] - e) ** 2 end end Math.sqrt(map.sum) end |
#move_to(centroid) ⇒ Object
121 122 123 124 |
# File 'lib/kmeans/node.rb', line 121 def move_to(centroid) self.centroid.remove_node(self) if self.centroid centroid.add_node(self) end |