ai4ruby 1.11

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.
Files changed (79) hide show
  1. data/README.rdoc +47 -0
  2. data/examples/classifiers/id3_data.csv +121 -0
  3. data/examples/classifiers/id3_example.rb +29 -0
  4. data/examples/classifiers/naive_bayes_data.csv +11 -0
  5. data/examples/classifiers/naive_bayes_example.rb +16 -0
  6. data/examples/classifiers/results.txt +31 -0
  7. data/examples/genetic_algorithm/genetic_algorithm_example.rb +37 -0
  8. data/examples/genetic_algorithm/travel_cost.csv +16 -0
  9. data/examples/neural_network/backpropagation_example.rb +67 -0
  10. data/examples/neural_network/patterns_with_base_noise.rb +68 -0
  11. data/examples/neural_network/patterns_with_noise.rb +66 -0
  12. data/examples/neural_network/training_patterns.rb +68 -0
  13. data/examples/neural_network/xor_example.rb +35 -0
  14. data/examples/som/som_data.rb +156 -0
  15. data/examples/som/som_multi_node_example.rb +22 -0
  16. data/examples/som/som_single_example.rb +24 -0
  17. data/lib/ai4r.rb +33 -0
  18. data/lib/ai4r/classifiers/classifier.rb +62 -0
  19. data/lib/ai4r/classifiers/hyperpipes.rb +118 -0
  20. data/lib/ai4r/classifiers/ib1.rb +121 -0
  21. data/lib/ai4r/classifiers/id3.rb +326 -0
  22. data/lib/ai4r/classifiers/multilayer_perceptron.rb +135 -0
  23. data/lib/ai4r/classifiers/naive_bayes.rb +259 -0
  24. data/lib/ai4r/classifiers/one_r.rb +110 -0
  25. data/lib/ai4r/classifiers/prism.rb +197 -0
  26. data/lib/ai4r/classifiers/zero_r.rb +73 -0
  27. data/lib/ai4r/clusterers/average_linkage.rb +59 -0
  28. data/lib/ai4r/clusterers/bisecting_k_means.rb +93 -0
  29. data/lib/ai4r/clusterers/centroid_linkage.rb +66 -0
  30. data/lib/ai4r/clusterers/clusterer.rb +61 -0
  31. data/lib/ai4r/clusterers/complete_linkage.rb +67 -0
  32. data/lib/ai4r/clusterers/diana.rb +139 -0
  33. data/lib/ai4r/clusterers/k_means.rb +126 -0
  34. data/lib/ai4r/clusterers/median_linkage.rb +61 -0
  35. data/lib/ai4r/clusterers/single_linkage.rb +194 -0
  36. data/lib/ai4r/clusterers/ward_linkage.rb +64 -0
  37. data/lib/ai4r/clusterers/ward_linkage_hierarchical.rb +31 -0
  38. data/lib/ai4r/clusterers/weighted_average_linkage.rb +61 -0
  39. data/lib/ai4r/data/data_set.rb +266 -0
  40. data/lib/ai4r/data/parameterizable.rb +64 -0
  41. data/lib/ai4r/data/proximity.rb +100 -0
  42. data/lib/ai4r/data/statistics.rb +77 -0
  43. data/lib/ai4r/experiment/classifier_evaluator.rb +95 -0
  44. data/lib/ai4r/genetic_algorithm/genetic_algorithm.rb +270 -0
  45. data/lib/ai4r/neural_network/backpropagation.rb +326 -0
  46. data/lib/ai4r/neural_network/hopfield.rb +149 -0
  47. data/lib/ai4r/som/layer.rb +68 -0
  48. data/lib/ai4r/som/node.rb +96 -0
  49. data/lib/ai4r/som/som.rb +155 -0
  50. data/lib/ai4r/som/two_phase_layer.rb +90 -0
  51. data/test/classifiers/hyperpipes_test.rb +84 -0
  52. data/test/classifiers/ib1_test.rb +78 -0
  53. data/test/classifiers/id3_test.rb +208 -0
  54. data/test/classifiers/multilayer_perceptron_test.rb +79 -0
  55. data/test/classifiers/naive_bayes_test.rb +43 -0
  56. data/test/classifiers/one_r_test.rb +62 -0
  57. data/test/classifiers/prism_test.rb +85 -0
  58. data/test/classifiers/zero_r_test.rb +49 -0
  59. data/test/clusterers/average_linkage_test.rb +51 -0
  60. data/test/clusterers/bisecting_k_means_test.rb +66 -0
  61. data/test/clusterers/centroid_linkage_test.rb +53 -0
  62. data/test/clusterers/complete_linkage_test.rb +57 -0
  63. data/test/clusterers/diana_test.rb +69 -0
  64. data/test/clusterers/k_means_test.rb +100 -0
  65. data/test/clusterers/median_linkage_test.rb +53 -0
  66. data/test/clusterers/single_linkage_test.rb +122 -0
  67. data/test/clusterers/ward_linkage_hierarchical_test.rb +61 -0
  68. data/test/clusterers/ward_linkage_test.rb +53 -0
  69. data/test/clusterers/weighted_average_linkage_test.rb +53 -0
  70. data/test/data/data_set_test.rb +96 -0
  71. data/test/data/proximity_test.rb +81 -0
  72. data/test/data/statistics_test.rb +65 -0
  73. data/test/experiment/classifier_evaluator_test.rb +76 -0
  74. data/test/genetic_algorithm/chromosome_test.rb +58 -0
  75. data/test/genetic_algorithm/genetic_algorithm_test.rb +81 -0
  76. data/test/neural_network/backpropagation_test.rb +82 -0
  77. data/test/neural_network/hopfield_test.rb +72 -0
  78. data/test/som/som_test.rb +97 -0
  79. metadata +168 -0
@@ -0,0 +1,85 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../../lib/ai4r/classifiers/prism'
3
+
4
+
5
+ class PrismTest < Test::Unit::TestCase
6
+
7
+ include Ai4r::Classifiers
8
+ include Ai4r::Data
9
+
10
+ @@data_examples = [ ['New York', '<30', 'M', 'Y'],
11
+ ['Chicago', '<30', 'M', 'Y'],
12
+ ['Chicago', '<30', 'F', 'Y'],
13
+ ['New York', '<30', 'M', 'Y'],
14
+ ['New York', '<30', 'M', 'Y'],
15
+ ['Chicago', '[30-50)', 'M', 'Y'],
16
+ ['New York', '[30-50)', 'F', 'N'],
17
+ ['Chicago', '[30-50)', 'F', 'Y'],
18
+ ['New York', '[30-50)', 'F', 'N'],
19
+ ['Chicago', '[50-80]', 'M', 'N'],
20
+ ['New York', '[50-80]', 'F', 'N'],
21
+ ['New York', '[50-80]', 'M', 'N'],
22
+ ['Chicago', '[50-80]', 'M', 'N'],
23
+ ['New York', '[50-80]', 'F', 'N'],
24
+ ['Chicago', '>80', 'F', 'Y']
25
+ ]
26
+
27
+ @@data_labels = [ 'city', 'age_range', 'gender', 'marketing_target' ]
28
+
29
+ def test_build
30
+ assert_raise(ArgumentError) { Prism.new.build(DataSet.new) }
31
+ classifier = Prism.new.build(DataSet.new(:data_items=>@@data_examples))
32
+ assert_not_nil(classifier.data_set.data_labels)
33
+ assert_not_nil(classifier.rules)
34
+ assert_equal("attribute_1", classifier.data_set.data_labels.first)
35
+ assert_equal("class_value", classifier.data_set.data_labels.last)
36
+ classifier = Prism.new.build(DataSet.new(:data_items => @@data_examples,
37
+ :data_labels => @@data_labels))
38
+ assert_not_nil(classifier.data_set.data_labels)
39
+ assert_not_nil(classifier.rules)
40
+ assert_equal("city", classifier.data_set.data_labels.first)
41
+ assert_equal("marketing_target", classifier.data_set.data_labels.last)
42
+ assert !classifier.rules.empty?
43
+
44
+ Prism.send(:public, *Prism.protected_instance_methods)
45
+ Prism.send(:public, *Prism.private_instance_methods)
46
+ end
47
+
48
+ def test_eval
49
+ classifier = Prism.new.build(DataSet.new(:data_items=>@@data_examples))
50
+ @@data_examples.each do |data|
51
+ assert_equal(data.last, classifier.eval(data[0...-1]))
52
+ end
53
+ end
54
+
55
+ def test_get_rules
56
+ classifier = Prism.new.build(DataSet.new(:data_items => @@data_examples,
57
+ :data_labels => @@data_labels))
58
+ marketing_target = nil
59
+ age_range = nil
60
+ city = 'Chicago'
61
+ eval(classifier.get_rules)
62
+ age_range = '<30'
63
+ eval(classifier.get_rules)
64
+ assert_equal("Y", marketing_target)
65
+ age_range = '[30-50)'
66
+ eval(classifier.get_rules)
67
+ assert_equal("Y", marketing_target)
68
+ age_range = '[30-50)'
69
+ city = 'New York'
70
+ eval(classifier.get_rules)
71
+ assert_equal("N", marketing_target)
72
+ age_range = '[50-80]'
73
+ eval(classifier.get_rules)
74
+ assert_equal("N", marketing_target)
75
+ end
76
+
77
+ def test_matches_conditions
78
+ classifier = Prism.new.build(DataSet.new(:data_labels => @@data_labels,
79
+ :data_items => @@data_examples))
80
+
81
+ assert classifier.matches_conditions(['New York', '<30', 'M', 'Y'], {"age_range" => "<30"})
82
+ assert !classifier.matches_conditions(['New York', '<30', 'M', 'Y'], {"age_range" => "[50-80]"})
83
+ end
84
+ end
85
+
@@ -0,0 +1,49 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../../lib/ai4r/classifiers/zero_r'
3
+ require File.dirname(__FILE__) + '/../../lib/ai4r/data/data_set'
4
+
5
+ class ZeroRTest < Test::Unit::TestCase
6
+
7
+ include Ai4r::Classifiers
8
+ include Ai4r::Data
9
+
10
+ @@data_examples = [ ['New York', '<30', 'M', 'Y'],
11
+ ['Chicago', '<30', 'M', 'Y'],
12
+ ['New York', '<30', 'M', 'Y'],
13
+ ['New York', '[30-50)', 'F', 'N'],
14
+ ['Chicago', '[30-50)', 'F', 'Y'],
15
+ ['New York', '[30-50)', 'F', 'N'],
16
+ ['Chicago', '[50-80]', 'M', 'N'],
17
+ ]
18
+
19
+ @@data_labels = [ 'city', 'age_range', 'gender', 'marketing_target' ]
20
+
21
+ def test_build
22
+ assert_raise(ArgumentError) { ZeroR.new.build(DataSet.new) }
23
+ classifier = ZeroR.new.build(DataSet.new(:data_items => @@data_examples))
24
+ assert_equal("Y", classifier.class_value)
25
+ assert_equal("attribute_1", classifier.data_set.data_labels.first)
26
+ assert_equal("class_value", classifier.data_set.data_labels.last)
27
+ classifier = ZeroR.new.build(DataSet.new(:data_items => @@data_examples,
28
+ :data_labels => @@data_labels))
29
+ assert_equal("Y", classifier.class_value)
30
+ assert_equal("city", classifier.data_set.data_labels.first)
31
+ assert_equal("marketing_target", classifier.data_set.data_labels.last)
32
+ end
33
+
34
+ def test_eval
35
+ classifier = ZeroR.new.build(DataSet.new(:data_items => @@data_examples))
36
+ assert_equal('Y', classifier.eval(@@data_examples.first) )
37
+ assert_equal('Y', classifier.eval(@@data_examples.last) )
38
+ end
39
+
40
+ def test_get_rules
41
+ classifier = ZeroR.new.build(DataSet.new(:data_items => @@data_examples,
42
+ :data_labels => @@data_labels))
43
+ marketing_target = nil
44
+ eval(classifier.get_rules)
45
+ assert_equal('Y', marketing_target)
46
+ end
47
+
48
+ end
49
+
@@ -0,0 +1,51 @@
1
+ # Author:: Sergio Fierens (implementation)
2
+ # License:: MPL 1.1
3
+ # Project:: ai4r
4
+ # Url:: http://ai4r.rubyforge.org/
5
+ #
6
+ # You can redistribute it and/or modify it under the terms of
7
+ # the Mozilla Public License version 1.1 as published by the
8
+ # Mozilla Foundation at http://www.mozilla.org/MPL/MPL-1.1.txt
9
+
10
+ require 'test/unit'
11
+ require File.dirname(__FILE__) + '/../../lib/ai4r/clusterers/average_linkage'
12
+
13
+ class Ai4r::Clusterers::AverageLinkage < Ai4r::Clusterers::SingleLinkage
14
+ attr_accessor :data_set, :number_of_clusters, :clusters, :distance_matrix
15
+ end
16
+
17
+ class AverageLinkageTest < Test::Unit::TestCase
18
+
19
+ include Ai4r::Clusterers
20
+ include Ai4r::Data
21
+
22
+ @@data = [ [10, 3], [3, 10], [2, 8], [2, 5], [3, 8], [10, 3],
23
+ [1, 3], [8, 1], [2, 9], [2, 5], [3, 3], [9, 4]]
24
+
25
+ @@expected_distance_matrix = [
26
+ [98.0],
27
+ [89.0, 5.0],
28
+ [68.0, 26.0, 9.0],
29
+ [74.0, 4.0, 1.0, 10.0],
30
+ [0.0, 98.0, 89.0, 68.0, 74.0],
31
+ [81.0, 53.0, 26.0, 5.0, 29.0, 81.0],
32
+ [8.0, 106.0, 85.0, 52.0, 74.0, 8.0, 53.0],
33
+ [100.0, 2.0, 1.0, 16.0, 2.0, 100.0, 37.0, 100.0],
34
+ [68.0, 26.0, 9.0, 0.0, 10.0, 68.0, 5.0, 52.0, 16.0],
35
+ [49.0, 49.0, 26.0, 5.0, 25.0, 49.0, 4.0, 29.0, 37.0, 5.0],
36
+ [2.0, 72.0, 65.0, 50.0, 52.0, 2.0, 65.0, 10.0, 74.0, 50.0, 37.0]]
37
+
38
+ def setup
39
+ Ai4r::Clusterers::AverageLinkage.send(:public,
40
+ *Ai4r::Clusterers::AverageLinkage.protected_instance_methods)
41
+ end
42
+
43
+ def test_linkage_distance
44
+ clusterer = Ai4r::Clusterers::AverageLinkage.new
45
+ clusterer.distance_matrix = @@expected_distance_matrix
46
+ assert_equal 93.5, clusterer.linkage_distance(0,1,2)
47
+ assert_equal 37.5, clusterer.linkage_distance(4,2,5)
48
+ end
49
+
50
+ end
51
+
@@ -0,0 +1,66 @@
1
+ # Author:: Sergio Fierens (implementation)
2
+ # License:: MPL 1.1
3
+ # Project:: ai4r
4
+ # Url:: http://ai4r.rubyforge.org/
5
+ #
6
+ # You can redistribute it and/or modify it under the terms of
7
+ # the Mozilla Public License version 1.1 as published by the
8
+ # Mozilla Foundation at http://www.mozilla.org/MPL/MPL-1.1.txt
9
+
10
+ require 'test/unit'
11
+ require File.dirname(__FILE__) + '/../../lib/ai4r/clusterers/bisecting_k_means'
12
+
13
+ class BisectingKMeansTest < Test::Unit::TestCase
14
+
15
+ include Ai4r::Clusterers
16
+ include Ai4r::Data
17
+
18
+ @@data = [ [10, 3], [3, 10], [2, 8], [2, 5], [3, 8], [10, 3],
19
+ [1, 3], [8, 1], [2, 9], [2, 5], [3, 3], [9, 4]]
20
+
21
+ def test_build_without_refine
22
+ build(false)
23
+ end
24
+
25
+ def test_build_with_refine
26
+ build(true)
27
+ end
28
+
29
+ protected
30
+ def build(refine)
31
+ data_set = DataSet.new(:data_items => @@data, :data_labels => ["X", "Y"])
32
+ clusterer = BisectingKMeans.new
33
+ clusterer.set_parameters :refine => refine
34
+ clusterer.build(data_set, 4)
35
+ #draw_map(clusterer)
36
+ # Verify that all 4 clusters are created
37
+ assert_equal 4, clusterer.clusters.length
38
+ assert_equal 4, clusterer.centroids.length
39
+ # The addition of all instances of every cluster must be equal than
40
+ # the number of data points
41
+ total_length = 0
42
+ clusterer.clusters.each do |cluster|
43
+ total_length += cluster.data_items.length
44
+ end
45
+ assert_equal @@data.length, total_length
46
+ # Data inside clusters must be the same as orifinal data
47
+ clusterer.clusters.each do |cluster|
48
+ cluster.data_items.each do |data_item|
49
+ assert @@data.include?(data_item)
50
+ end
51
+ end
52
+ end
53
+
54
+ private
55
+ def draw_map(clusterer)
56
+ map = Array.new(11) {Array.new(11, 0)}
57
+ clusterer.clusters.each_index do |i|
58
+ clusterer.clusters[i].data_items.each do |point|
59
+ map[point.first][point.last]=(i+1)
60
+ end
61
+ end
62
+ map.each { |row| puts row.inspect}
63
+ end
64
+
65
+ end
66
+
@@ -0,0 +1,53 @@
1
+ # Author:: Sergio Fierens (implementation)
2
+ # License:: MPL 1.1
3
+ # Project:: ai4r
4
+ # Url:: http://ai4r.rubyforge.org/
5
+ #
6
+ # You can redistribute it and/or modify it under the terms of
7
+ # the Mozilla Public License version 1.1 as published by the
8
+ # Mozilla Foundation at http://www.mozilla.org/MPL/MPL-1.1.txt
9
+
10
+ require 'test/unit'
11
+ require File.dirname(__FILE__) + '/../../lib/ai4r/clusterers/centroid_linkage'
12
+
13
+ class Ai4r::Clusterers::CentroidLinkage
14
+ attr_accessor :data_set, :number_of_clusters, :clusters, :distance_matrix, :index_clusters
15
+ end
16
+
17
+ class Ai4r::Clusterers::CentroidLinkageTest < Test::Unit::TestCase
18
+
19
+ include Ai4r::Clusterers
20
+ include Ai4r::Data
21
+
22
+ @@data = [ [10, 3], [3, 10], [2, 8], [2, 5], [3, 8], [10, 3],
23
+ [1, 3], [8, 1], [2, 9], [2, 5], [3, 3], [9, 4]]
24
+
25
+ @@expected_distance_matrix = [
26
+ [98.0],
27
+ [89.0, 5.0],
28
+ [68.0, 26.0, 9.0],
29
+ [74.0, 4.0, 1.0, 10.0],
30
+ [0.0, 98.0, 89.0, 68.0, 74.0],
31
+ [81.0, 53.0, 26.0, 5.0, 29.0, 81.0],
32
+ [8.0, 106.0, 85.0, 52.0, 74.0, 8.0, 53.0],
33
+ [100.0, 2.0, 1.0, 16.0, 2.0, 100.0, 37.0, 100.0],
34
+ [68.0, 26.0, 9.0, 0.0, 10.0, 68.0, 5.0, 52.0, 16.0],
35
+ [49.0, 49.0, 26.0, 5.0, 25.0, 49.0, 4.0, 29.0, 37.0, 5.0],
36
+ [2.0, 72.0, 65.0, 50.0, 52.0, 2.0, 65.0, 10.0, 74.0, 50.0, 37.0]]
37
+
38
+ def setup
39
+ Ai4r::Clusterers::CentroidLinkage.send(:public,
40
+ *Ai4r::Clusterers::CentroidLinkage.protected_instance_methods)
41
+ end
42
+
43
+ def test_linkage_distance
44
+ clusterer = Ai4r::Clusterers::CentroidLinkage.new
45
+ clusterer.data_set = DataSet.new :data_items => @@data
46
+ clusterer.index_clusters = clusterer.create_initial_index_clusters
47
+ clusterer.distance_matrix = @@expected_distance_matrix
48
+ assert_equal 92.25, clusterer.linkage_distance(0,1,2)
49
+ assert_equal 15.25, clusterer.linkage_distance(4,2,5)
50
+ end
51
+
52
+ end
53
+
@@ -0,0 +1,57 @@
1
+ # Author:: Sergio Fierens (implementation)
2
+ # License:: MPL 1.1
3
+ # Project:: ai4r
4
+ # Url:: http://ai4r.rubyforge.org/
5
+ #
6
+ # You can redistribute it and/or modify it under the terms of
7
+ # the Mozilla Public License version 1.1 as published by the
8
+ # Mozilla Foundation at http://www.mozilla.org/MPL/MPL-1.1.txt
9
+
10
+ require 'test/unit'
11
+ require File.dirname(__FILE__) + '/../../lib/ai4r/clusterers/complete_linkage'
12
+
13
+ class Ai4r::Clusterers::CompleteLinkage
14
+ attr_accessor :data_set, :number_of_clusters, :clusters, :distance_matrix
15
+ end
16
+
17
+ class CompleteLinkageTest < Test::Unit::TestCase
18
+
19
+ include Ai4r::Clusterers
20
+ include Ai4r::Data
21
+
22
+ @@data = [ [10, 3], [3, 10], [2, 8], [2, 5], [3, 8], [10, 3],
23
+ [1, 3], [8, 1], [2, 9], [2, 5], [3, 3], [9, 4]]
24
+
25
+ @@expected_distance_matrix = [
26
+ [98.0],
27
+ [89.0, 5.0],
28
+ [68.0, 26.0, 9.0],
29
+ [74.0, 4.0, 1.0, 10.0],
30
+ [0.0, 98.0, 89.0, 68.0, 74.0],
31
+ [81.0, 53.0, 26.0, 5.0, 29.0, 81.0],
32
+ [8.0, 106.0, 85.0, 52.0, 74.0, 8.0, 53.0],
33
+ [100.0, 2.0, 1.0, 16.0, 2.0, 100.0, 37.0, 100.0],
34
+ [68.0, 26.0, 9.0, 0.0, 10.0, 68.0, 5.0, 52.0, 16.0],
35
+ [49.0, 49.0, 26.0, 5.0, 25.0, 49.0, 4.0, 29.0, 37.0, 5.0],
36
+ [2.0, 72.0, 65.0, 50.0, 52.0, 2.0, 65.0, 10.0, 74.0, 50.0, 37.0]]
37
+
38
+ def setup
39
+ Ai4r::Clusterers::CompleteLinkage.send(:public,
40
+ *Ai4r::Clusterers::CompleteLinkage.protected_instance_methods)
41
+ end
42
+
43
+ def test_linkage_distance
44
+ clusterer = Ai4r::Clusterers::CompleteLinkage.new
45
+ clusterer.distance_matrix = @@expected_distance_matrix
46
+ assert_equal 98, clusterer.linkage_distance(0,1,2)
47
+ assert_equal 74, clusterer.linkage_distance(4,2,5)
48
+ end
49
+
50
+ def test_distance_between_item_and_cluster
51
+ clusterer = CompleteLinkage.new
52
+ assert_equal 32.0, clusterer.distance_between_item_and_cluster([1,2],
53
+ DataSet.new(:data_items => [[3,4],[5,6]]))
54
+ end
55
+
56
+ end
57
+
@@ -0,0 +1,69 @@
1
+ # Author:: Sergio Fierens (implementation)
2
+ # License:: MPL 1.1
3
+ # Project:: ai4r
4
+ # Url:: http://ai4r.rubyforge.org/
5
+ #
6
+ # You can redistribute it and/or modify it under the terms of
7
+ # the Mozilla Public License version 1.1 as published by the
8
+ # Mozilla Foundation at http://www.mozilla.org/MPL/MPL-1.1.txt
9
+
10
+ require 'test/unit'
11
+ require File.dirname(__FILE__) + '/../../lib/ai4r/clusterers/diana'
12
+
13
+ class Ai4r::Clusterers::Diana
14
+ attr_accessor :data_set, :number_of_clusters, :clusters
15
+ end
16
+
17
+ class DianaTest < Test::Unit::TestCase
18
+
19
+ @@data = [ [10, 3], [3, 10], [2, 8], [2, 5], [3, 8], [10, 3],
20
+ [1, 3], [8, 1], [2, 9], [2, 5], [3, 3], [9, 4]]
21
+
22
+ include Ai4r::Clusterers
23
+ include Ai4r::Data
24
+
25
+ def setup
26
+ Diana.send(:public, *Diana.protected_instance_methods)
27
+ @data_set = DataSet.new(:data_items => @@data.clone)
28
+ end
29
+
30
+ def test_build
31
+ clusterer = Diana.new.build(@data_set, 4)
32
+ assert_equal 4, clusterer.clusters.length
33
+ end
34
+
35
+ def test_eval
36
+ clusterer = Diana.new.build(@data_set, 4)
37
+ assert_equal 0, clusterer.eval([0, 0])
38
+ assert_equal 1, clusterer.eval([9, 3])
39
+ assert_equal 2, clusterer.eval([0,10])
40
+ assert_equal 3, clusterer.eval([8, 0])
41
+ end
42
+
43
+ def test_cluster_diameter
44
+ clusterer = Diana.new
45
+ assert_equal 106, clusterer.cluster_diameter(@data_set)
46
+ assert_equal 98, clusterer.cluster_diameter(@data_set[0..2])
47
+ end
48
+
49
+ def test_max_diameter_cluster
50
+ clusterer = Diana.new
51
+ assert_equal 0, clusterer.max_diameter_cluster([@data_set, @data_set[0..2]])
52
+ assert_equal 1, clusterer.max_diameter_cluster([@data_set[0..2], @data_set])
53
+ end
54
+
55
+ def test_init_splinter_cluster
56
+ clusterer = Diana.new
57
+ assert_equal [10,3], clusterer.
58
+ init_splinter_cluster(@data_set).data_items[0]
59
+ end
60
+
61
+ def test_max_distance_difference
62
+ clusterer = Diana.new
63
+ data_set_a = @data_set[1..-1]
64
+ data_set_b = @data_set[0]
65
+ assert_equal [63.7, 4], clusterer.
66
+ max_distance_difference(data_set_a, data_set_b)
67
+ end
68
+
69
+ end
@@ -0,0 +1,100 @@
1
+ # Author:: Sergio Fierens (implementation)
2
+ # License:: MPL 1.1
3
+ # Project:: ai4r
4
+ # Url:: http://ai4r.rubyforge.org/
5
+ #
6
+ # You can redistribute it and/or modify it under the terms of
7
+ # the Mozilla Public License version 1.1 as published by the
8
+ # Mozilla Foundation at http://www.mozilla.org/MPL/MPL-1.1.txt
9
+
10
+ require 'test/unit'
11
+ require File.dirname(__FILE__) + '/../../lib/ai4r/clusterers/k_means'
12
+
13
+ class KMeansTest < Test::Unit::TestCase
14
+
15
+ include Ai4r::Clusterers
16
+ include Ai4r::Data
17
+
18
+ @@data = [ [10, 3], [3, 10], [2, 8], [2, 5], [3, 8], [10, 3],
19
+ [1, 3], [8, 1], [2, 9], [2, 5], [3, 3], [9, 4]]
20
+
21
+ def test_build
22
+ data_set = DataSet.new(:data_items => @@data, :data_labels => ["X", "Y"])
23
+ clusterer = KMeans.new.build(data_set, 4)
24
+ #draw_map(clusterer)
25
+ # Verify that all 4 clusters are created
26
+ assert_equal 4, clusterer.clusters.length
27
+ assert_equal 4, clusterer.centroids.length
28
+ # The addition of all instances of every cluster must be equal than
29
+ # the number of data points
30
+ total_length = 0
31
+ clusterer.clusters.each do |cluster|
32
+ total_length += cluster.data_items.length
33
+ end
34
+ assert_equal @@data.length, total_length
35
+ # Data inside clusters must be the same as orifinal data
36
+ clusterer.clusters.each do |cluster|
37
+ cluster.data_items.each do |data_item|
38
+ assert @@data.include?(data_item)
39
+ end
40
+ end
41
+ end
42
+
43
+ def test_eval
44
+ data_set = DataSet.new(:data_items => @@data, :data_labels => ["X", "Y"])
45
+ clusterer = KMeans.new.build(data_set, 4)
46
+ item = [10,0]
47
+ cluster_index = clusterer.eval(item)
48
+ # Must return a valid cluster index [0-3]
49
+ assert cluster_index >= 0 && cluster_index < 4
50
+ # Distance to cluster centroid must be less than distance to any other
51
+ # centroid
52
+ min_distance = clusterer.distance(clusterer.centroids[cluster_index], item)
53
+ clusterer.centroids.each do |centroid|
54
+ assert clusterer.distance(centroid, item) >= min_distance
55
+ end
56
+ end
57
+
58
+ def test_distance
59
+ clusterer = KMeans.new
60
+ # By default, distance returns the eucledian distance to the power of 2
61
+ assert_equal 2385, clusterer.distance(
62
+ [1, 10, "Chicago", 2],
63
+ [10, 10, "London", 50])
64
+ # Test new distance definition
65
+ manhattan_distance = lambda do |a, b|
66
+ dist = 0.0
67
+ a.each_index do |index|
68
+ if a[index].is_a?(Numeric) && b[index].is_a?(Numeric)
69
+ dist = dist + (a[index]-b[index]).abs
70
+ end
71
+ end
72
+ dist
73
+ end
74
+ clusterer.set_parameters({:distance_function => manhattan_distance})
75
+ assert_equal 57, clusterer.distance(
76
+ [1, 10, "Chicago", 2],
77
+ [10, 10, "London", 50])
78
+ end
79
+
80
+ def test_max_iterations
81
+ data_set = DataSet.new(:data_items => @@data, :data_labels => ["X", "Y"])
82
+ clusterer = KMeans.new.
83
+ set_parameters({:max_iterations=>1}).
84
+ build(data_set, 4)
85
+ assert_equal 1, clusterer.iterations
86
+ end
87
+
88
+ private
89
+ def draw_map(clusterer)
90
+ map = Array.new(11) {Array.new(11, 0)}
91
+ clusterer.clusters.each_index do |i|
92
+ clusterer.clusters[i].data_items.each do |point|
93
+ map[point.first][point.last]=(i+1)
94
+ end
95
+ end
96
+ map.each { |row| puts row.inspect}
97
+ end
98
+
99
+ end
100
+