ai4r 1.3 → 1.4

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 (35) hide show
  1. data/README.rdoc +6 -12
  2. data/examples/neural_network/backpropagation_example.rb +18 -16
  3. data/examples/neural_network/xor_example.rb +30 -20
  4. data/lib/ai4r/classifiers/classifier.rb +15 -4
  5. data/lib/ai4r/classifiers/id3.rb +31 -31
  6. data/lib/ai4r/clusterers/clusterer.rb +5 -24
  7. data/lib/ai4r/clusterers/k_means.rb +7 -38
  8. data/lib/ai4r/data/data_set.rb +4 -2
  9. data/lib/ai4r/data/parameterizable.rb +64 -0
  10. data/lib/ai4r/neural_network/backpropagation.rb +233 -210
  11. data/site/build/site/en/downloads.html +3 -3
  12. data/site/build/site/en/geneticAlgorithms.html +3 -3
  13. data/site/build/site/en/index.html +32 -15
  14. data/site/build/site/en/index.pdf +126 -100
  15. data/site/build/site/en/linkmap.html +7 -9
  16. data/site/build/site/en/linkmap.pdf +12 -12
  17. data/site/build/site/en/machineLearning.html +7 -6
  18. data/site/build/site/en/machineLearning.pdf +29 -29
  19. data/site/build/site/en/neuralNetworks.html +164 -127
  20. data/site/build/site/en/neuralNetworks.pdf +267 -200
  21. data/site/build/site/en/svn.html +4 -4
  22. data/site/build/tmp/cocoon-work/cache-dir/cocoon-ehcache-1.data +0 -0
  23. data/site/build/tmp/cocoon-work/cache-dir/cocoon-ehcache-1.index +0 -0
  24. data/site/build/tmp/projfilters.properties +1 -1
  25. data/site/build/webapp/WEB-INF/logs/core.log +670 -489
  26. data/site/build/webapp/WEB-INF/logs/error.log +213 -364
  27. data/site/build/webapp/WEB-INF/logs/sitemap.log +0 -368
  28. data/site/src/documentation/content/xdocs/index.xml +1 -1
  29. data/site/src/documentation/content/xdocs/neuralNetworks.xml +118 -90
  30. data/site/src/documentation/content/xdocs/site.xml +2 -3
  31. data/test/neural_network/backpropagation_test.rb +23 -0
  32. metadata +5 -7
  33. data/site/build/site/en/forum.html +0 -197
  34. data/site/build/site/en/forum.pdf +0 -151
  35. data/site/build/site/en/wholesite.pdf +0 -1915
@@ -16,18 +16,12 @@ http://ai4r.rubyforge.org
16
16
  2. Include require statements in your code:
17
17
 
18
18
  require "rubygems"
19
- require "ai4r/classifiers/id3"en
20
- require "ai4r/classifiers/prism"
21
- require "ai4r/classifiers/one_r"
22
- require "ai4r/classifiers/zero_r"
23
- require "ai4r/neural_network/backpropagation"
24
- require "ai4r/genetic_algorithm/genetic_algorithm"
25
-
26
- = Feedback
27
-
28
- If you have questions or constructive comments about this project,
29
- please post them in the forum. If you do not want to make it public,
30
- send it to me: Sergio Fierens (sergio(dot)fierens(at)gmail(dot)com)
19
+ require "ai4r"
20
+
21
+ = More Info
22
+
23
+ * AI4R wiki: http://wiki.jadeferret.com/Category:AI4R
24
+ * AI4R Project site: http://ai4r.rubyforge.org
31
25
 
32
26
  = Warranty
33
27
 
@@ -15,25 +15,28 @@ require 'benchmark'
15
15
 
16
16
  times = Benchmark.measure do
17
17
 
18
+ srand 1
19
+
18
20
  net = Ai4r::NeuralNetwork::Backpropagation.new([256, 3])
21
+
22
+ tr_input = TRIANGLE.flatten.collect { |input| input.to_f / 5.0}
23
+ sq_input = SQUARE.flatten.collect { |input| input.to_f / 5.0}
24
+ cr_input = CROSS.flatten.collect { |input| input.to_f / 5.0}
19
25
 
20
- tr_input = TRIANGLE.flatten.collect { |input| input.to_f / 10}
21
- sq_input = SQUARE.flatten.collect { |input| input.to_f / 10}
22
- cr_input = CROSS.flatten.collect { |input| input.to_f / 10}
23
-
24
- tr_with_noise = TRIANGLE_WITH_NOISE.flatten.collect { |input| input.to_f / 10}
25
- sq_with_noise = SQUARE_WITH_NOISE.flatten.collect { |input| input.to_f / 10}
26
- cr_with_noise = CROSS_WITH_NOISE.flatten.collect { |input| input.to_f / 10}
26
+ tr_with_noise = TRIANGLE_WITH_NOISE.flatten.collect { |input| input.to_f / 5.0}
27
+ sq_with_noise = SQUARE_WITH_NOISE.flatten.collect { |input| input.to_f / 5.0}
28
+ cr_with_noise = CROSS_WITH_NOISE.flatten.collect { |input| input.to_f / 5.0}
27
29
 
28
- tr_with_base_noise = TRIANGLE_WITH_BASE_NOISE.flatten.collect { |input| input.to_f / 10}
29
- sq_with_base_noise = SQUARE_WITH_BASE_NOISE.flatten.collect { |input| input.to_f / 10}
30
- cr_with_base_noise = CROSS_WITH_BASE_NOISE.flatten.collect { |input| input.to_f / 10}
30
+ tr_with_base_noise = TRIANGLE_WITH_BASE_NOISE.flatten.collect { |input| input.to_f / 5.0}
31
+ sq_with_base_noise = SQUARE_WITH_BASE_NOISE.flatten.collect { |input| input.to_f / 5.0}
32
+ cr_with_base_noise = CROSS_WITH_BASE_NOISE.flatten.collect { |input| input.to_f / 5.0}
31
33
 
32
34
  puts "Training the network, please wait."
33
- 200.times do
34
- net.train(tr_input, [1,0,0])
35
- net.train(sq_input, [0,1,0])
36
- net.train(cr_input, [0,0,1])
35
+ 101.times do |i|
36
+ error = net.train(tr_input, [1,0,0])
37
+ error = net.train(sq_input, [0,1,0])
38
+ error = net.train(cr_input, [0,0,1])
39
+ puts "Error after iteration #{i}:\t#{error}" if i%20 == 0
37
40
  end
38
41
 
39
42
  def result_label(result)
@@ -58,8 +61,7 @@ times = Benchmark.measure do
58
61
  puts "#{net.eval(tr_with_base_noise).inspect} => #{result_label(net.eval(tr_with_base_noise))}"
59
62
  puts "#{net.eval(sq_with_base_noise).inspect} => #{result_label(net.eval(sq_with_base_noise))}"
60
63
  puts "#{net.eval(cr_with_base_noise).inspect} => #{result_label(net.eval(cr_with_base_noise))}"
61
-
62
64
 
63
65
  end
64
66
 
65
- puts "Elapsed time: #{times}"
67
+ puts "Elapsed time: #{times}"
@@ -1,25 +1,35 @@
1
- require File.dirname(__FILE__) + '/training_patterns'
2
- require File.dirname(__FILE__) + '/patterns_with_noise'
3
- require File.dirname(__FILE__) + '/patterns_with_base_noise'
4
- require File.dirname(__FILE__) + '/../../lib/ai4r/neural_network/backpropagation'
1
+ # Author:: Sergio Fierens
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
5
9
 
6
- examples = [
7
- [[0, 0], [0, 1]],
8
- [[0, 1], [1, 0]],
9
- [[1, 0], [1, 0]],
10
- [[1, 1], [0, 0]]
11
- ]
10
+ require File.dirname(__FILE__) + '/../../lib/ai4r/neural_network/backpropagation'
11
+ require 'benchmark'
12
12
 
13
- net = Ai4r::NeuralNetwork::Backpropagation.new([2, 1, 2, 1])
13
+ times = Benchmark.measure do
14
14
 
15
- i=0
16
- 200.times {
17
- examples.each do |ex|
18
- 2000.times {net.train(ex[0], [ex[1].first])}
15
+ srand 1
16
+
17
+ net = Ai4r::NeuralNetwork::Backpropagation.new([2, 2, 1])
18
+
19
+ puts "Training the network, please wait."
20
+ 2001.times do |i|
21
+ net.train([0,0], [0])
22
+ net.train([0,1], [1])
23
+ net.train([1,0], [1])
24
+ error = net.train([1,1], [0])
25
+ puts "Error after iteration #{i}:\t#{error}" if i%200 == 0
19
26
  end
20
- puts(i=i+1)
21
- }
27
+
28
+ puts "Test data"
29
+ puts "[0,0] = > #{net.eval([0,0]).inspect}"
30
+ puts "[0,1] = > #{net.eval([0,1]).inspect}"
31
+ puts "[1,0] = > #{net.eval([1,0]).inspect}"
32
+ puts "[1,1] = > #{net.eval([1,1]).inspect}"
33
+ end
22
34
 
23
- examples.each do |ex|
24
- print ex[0], ' => ', net.eval(ex[0]).inspect, ', should be ', ex[1].first, "\n"
25
- end
35
+ puts "Elapsed time: #{times}"
@@ -1,19 +1,23 @@
1
1
  # Author:: Sergio Fierens
2
2
  # License:: MPL 1.1
3
3
  # Project:: ai4r
4
- # Url:: http://ai4r.rubyforge.org/
4
+ # Url:: http://ai4r.rubyforge.org
5
5
  #
6
6
  # You can redistribute it and/or modify it under the terms of
7
7
  # the Mozilla Public License version 1.1 as published by the
8
8
  # Mozilla Foundation at http://www.mozilla.org/MPL/MPL-1.1.txt
9
9
 
10
+ require File.dirname(__FILE__) + '/../data/parameterizable'
11
+
10
12
  module Ai4r
11
13
  module Classifiers
12
-
13
- # The only purpose of this class is to define a common API for classifiers.
14
+
15
+ # This class defines a common API for classifiers.
14
16
  # All methods in this class must be implemented in subclasses.
15
17
  class Classifier
16
18
 
19
+ include Ai4r::Data::Parameterizable
20
+
17
21
  # Build a new classifier, using data examples found in data_set.
18
22
  def build(data_set)
19
23
  raise NotImplementedError
@@ -30,9 +34,16 @@ module Ai4r
30
34
  # e.g.
31
35
  #
32
36
  # classifier.get_rules
33
- # # => marketing_target='Y'
37
+ # # => if age_range=='<30' then marketing_target='Y'
38
+ # elsif age_range=='[30-50)' and city=='Chicago' then marketing_target='Y'
39
+ # elsif age_range=='[30-50)' and city=='New York' then marketing_target='N'
40
+ # elsif age_range=='[50-80]' then marketing_target='N'
41
+ # elsif age_range=='>80' then marketing_target='Y'
42
+ # else raise 'There was not enough information during training to do a proper induction for this data element' end
34
43
  #
35
44
  # It is a nice way to inspect induction results, and also to execute them:
45
+ # age_range = '<30'
46
+ # city='New York'
36
47
  # marketing_target = nil
37
48
  # eval classifier.get_rules
38
49
  # puts marketing_target
@@ -28,24 +28,26 @@ module Ai4r
28
28
  #
29
29
  # DATA_LABELS = [ 'city', 'age_range', 'gender', 'marketing_target' ]
30
30
  #
31
- # DATA_SET = [ ['New York', '<30', 'M', 'Y'],
32
- # ['Chicago', '<30', 'M', 'Y'],
33
- # ['Chicago', '<30', 'F', 'Y'],
34
- # ['New York', '<30', 'M', 'Y'],
35
- # ['New York', '<30', 'M', 'Y'],
36
- # ['Chicago', '[30-50)', 'M', 'Y'],
37
- # ['New York', '[30-50)', 'F', 'N'],
38
- # ['Chicago', '[30-50)', 'F', 'Y'],
39
- # ['New York', '[30-50)', 'F', 'N'],
40
- # ['Chicago', '[50-80]', 'M', 'N'],
41
- # ['New York', '[50-80]', 'F', 'N'],
42
- # ['New York', '[50-80]', 'M', 'N'],
43
- # ['Chicago', '[50-80]', 'M', 'N'],
44
- # ['New York', '[50-80]', 'F', 'N'],
45
- # ['Chicago', '>80', 'F', 'Y']
46
- # ]
31
+ # DATA_ITEMS = [
32
+ # ['New York', '<30', 'M', 'Y'],
33
+ # ['Chicago', '<30', 'M', 'Y'],
34
+ # ['Chicago', '<30', 'F', 'Y'],
35
+ # ['New York', '<30', 'M', 'Y'],
36
+ # ['New York', '<30', 'M', 'Y'],
37
+ # ['Chicago', '[30-50)', 'M', 'Y'],
38
+ # ['New York', '[30-50)', 'F', 'N'],
39
+ # ['Chicago', '[30-50)', 'F', 'Y'],
40
+ # ['New York', '[30-50)', 'F', 'N'],
41
+ # ['Chicago', '[50-80]', 'M', 'N'],
42
+ # ['New York', '[50-80]', 'F', 'N'],
43
+ # ['New York', '[50-80]', 'M', 'N'],
44
+ # ['Chicago', '[50-80]', 'M', 'N'],
45
+ # ['New York', '[50-80]', 'F', 'N'],
46
+ # ['Chicago', '>80', 'F', 'Y']
47
+ # ]
47
48
  #
48
- # id3 = Ai4r::Classifiers::ID3.new(DATA_SET, DATA_LABELS)
49
+ # data_set = DataSet.new(:data_items=>DATA_SET, :data_labels=>DATA_LABELS)
50
+ # id3 = Ai4r::Classifiers::ID3.new.build(data_set)
49
51
  #
50
52
  # id3.get_rules
51
53
  # # => if age_range=='<30' then marketing_target='Y'
@@ -64,22 +66,20 @@ module Ai4r
64
66
  # attributes. Consider moving your data to an external CSV (comma separate
65
67
  # values) file.
66
68
  #
67
- # data_set = []
68
- # CSV::Reader.parse(File.open("#{File.dirname(__FILE__)}/data_set.csv", 'r')) do |row|
69
- # data_set << row
70
- # end
71
- # data_labels = data_set.shift
72
- #
73
- # id3 = Ai4r::Classifiers::ID3.new(data_set, data_labels)
69
+ # data_file = "#{File.dirname(__FILE__)}/data_set.csv"
70
+ # data_set = DataSet.load_data_and_labels_from_csv data_file
71
+ # id3 = Ai4r::Classifiers::ID3.new.build(data_set)
74
72
  #
75
73
  # = A nice tip for data evaluation
76
74
  #
77
- # id3 = Ai4r::Classifiers::ID3.new(DATA_SET, DATA_LABELS)
78
- # age_range = '<30'
79
- # marketing_target = nil
80
- # eval id3.get_rules
81
- # puts marketing_target
82
- # # => 'Y'
75
+ # id3 = Ai4r::Classifiers::ID3.new.build(data_set)
76
+ #
77
+ # age_range = '<30'
78
+ # marketing_target = nil
79
+ # eval id3.get_rules
80
+ # puts marketing_target
81
+ # # => 'Y'
82
+ #
83
83
  # = More about ID3 and decision trees
84
84
  #
85
85
  # * http://en.wikipedia.org/wiki/Decision_tree
@@ -92,7 +92,7 @@ module Ai4r
92
92
  class ID3 < Classifier
93
93
 
94
94
  attr_reader :data_set
95
-
95
+
96
96
  # Create a new ID3 classifier. You must provide a DataSet instance
97
97
  # as parameter.
98
98
  def build(data_set)
@@ -7,6 +7,8 @@
7
7
  # the Mozilla Public License version 1.1 as published by the
8
8
  # Mozilla Foundation at http://www.mozilla.org/MPL/MPL-1.1.txt
9
9
 
10
+ require File.dirname(__FILE__) + '/../data/parameterizable'
11
+
10
12
  module Ai4r
11
13
  module Clusterers
12
14
 
@@ -14,7 +16,9 @@ module Ai4r
14
16
  # All methods in this class (other than eval) must be implemented in
15
17
  # subclasses.
16
18
  class Clusterer
17
-
19
+
20
+ include Ai4r::Data::Parameterizable
21
+
18
22
  # Build a new clusterer, using data examples found in data_set.
19
23
  # Data items will be clustered in "number_of_clusters" different
20
24
  # clusters.
@@ -27,29 +31,6 @@ module Ai4r
27
31
  raise NotImplementedError
28
32
  end
29
33
 
30
- # Get info on what can be parameterized on this clusterer.
31
- # It returns a hash with the following format:
32
- # { :param_name => "Info on the parameter" }
33
- def get_parameters_info
34
- raise NotImplementedError
35
- end
36
-
37
- # Set parameter values on this clusterer instance.
38
- # You must provide a hash with the folowing format:
39
- # { :param_name => parameter_value }
40
- def set_parameters(parameters)
41
- raise NotImplementedError
42
- end
43
-
44
- # Get parameter values on this clusterer instance.
45
- # Returns a hash with the folowing format:
46
- # { :param_name => parameter_value }
47
- def get_parameters
48
- raise NotImplementedError
49
- end
50
-
51
-
52
34
  end
53
-
54
35
  end
55
36
  end
@@ -23,8 +23,13 @@ module Ai4r
23
23
 
24
24
  attr_reader :data_set, :number_of_clusters
25
25
  attr_reader :clusters, :centroids, :iterations
26
- attr_accessor :max_iterations
27
- attr_accessor :distance_function
26
+
27
+ parameters_info :max_iterations => "Maximum number of iterations to " +
28
+ "build the clusterer. By default it is uncapped.",
29
+ :distance_function => "Custom implementation of distance function. " +
30
+ "It must be a closure receiving two data items and return the " +
31
+ "distance bewteen them. By default, this algorithm uses " +
32
+ "ecuclidean distance of numeric attributes to the power of 2."
28
33
 
29
34
  # Build a new clusterer, using data examples found in data_set.
30
35
  # Items will be clustered in "number_of_clusters" different
@@ -50,42 +55,6 @@ module Ai4r
50
55
  distance(data_item, centroid)})
51
56
  end
52
57
 
53
- # Get info on what can be parameterized on this clusterer algorithm.
54
- # It returns a hash with the following format:
55
- # { :param_name => "Info on the parameter" }
56
- def get_parameters_info
57
- { :max_iterations => "Maximum number of iterations to build the " +
58
- "clusterer. By default it is uncapped.",
59
- :distance_function => "Custom implementation of distance function. " +
60
- "It must be a closure receiving two data items and return the " +
61
- "distance bewteen them. By default, this algorithm uses " +
62
- "ecuclidean distance of numeric attributes to the power of 2."
63
- }
64
- end
65
-
66
- # Set parameters on this clusterer instance.
67
- # You must provide a hash with the folowing format:
68
- # { :param_name => parameter_value }
69
- #
70
- # Use get_parameters_info to know what parameters are accepted.
71
- def set_parameters(parameters)
72
- if parameters.has_key?(:max_iterations)
73
- @max_iterations = parameters[:max_iterations]
74
- end
75
- if parameters.has_key?(:distance_function)
76
- @distance_function = parameters[:distance_function]
77
- end
78
- return self
79
- end
80
-
81
- # Get parameter values on this clusterer instance.
82
- # Returns a hash with the folowing format:
83
- # { :param_name => parameter_value }
84
- def get_parameters
85
- { :max_iterations => @max_iterations,
86
- :distance_function => @distance_function }
87
- end
88
-
89
58
  # This function calculates the distance between 2 different
90
59
  # instances. By default, it returns the euclidean distance to the
91
60
  # power of 2.
@@ -30,9 +30,11 @@ module Ai4r
30
30
  set_data_items(options[:data_items]) if options[:data_items]
31
31
  end
32
32
 
33
- # Retrieve data item(s) by index. You can specify a an index range, too.
33
+ # Retrieve a new DataSet, with the item(s) selected by the provided
34
+ # index. You can specify an index range, too.
34
35
  def [](index)
35
- return @data_items[index]
36
+ return DataSet.new(:data_items=>@data_items[index],
37
+ :data_labels =>@data_labels)
36
38
  end
37
39
 
38
40
  # Load data items from csv file
@@ -0,0 +1,64 @@
1
+ # Author:: Sergio Fierens
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
+ module Ai4r
11
+ module Data
12
+ module Parameterizable
13
+
14
+ module ClassMethods
15
+
16
+ # Get info on what can be parameterized on this algorithm.
17
+ # It returns a hash with the following format:
18
+ # { :param_name => "Info on the parameter" }
19
+ def get_parameters_info
20
+ return @_params_info_ || {}
21
+ end
22
+
23
+ # Set info on what can be parameterized on this algorithm.
24
+ # You must provide a hash with the following format:
25
+ # { :param_name => "Info on the parameter" }
26
+ def parameters_info(params_info)
27
+ @_params_info_ = params_info
28
+ params_info.keys.each do |param|
29
+ attr_accessor param
30
+ end
31
+ end
32
+ end
33
+
34
+ # Set parameter values on this algorithm instance.
35
+ # You must provide a hash with the folowing format:
36
+ # { :param_name => parameter_value }
37
+ def set_parameters(params)
38
+ self.class.get_parameters_info.keys.each do | key |
39
+ if self.respond_to?("#{key}=".to_sym)
40
+ send("#{key}=".to_sym, params[key]) if params.has_key? key
41
+ end
42
+ end
43
+ return self
44
+ end
45
+
46
+ # Get parameter values on this algorithm instance.
47
+ # Returns a hash with the folowing format:
48
+ # { :param_name => parameter_value }
49
+ def get_parameters
50
+ params = {}
51
+ self.class.get_parameters_info.keys.each do | key |
52
+ params[key] = send(key) if self.respond_to?(key)
53
+ end
54
+ return params
55
+ end
56
+
57
+ def self.included(base)
58
+ base.extend(ClassMethods)
59
+ end
60
+
61
+ end
62
+ end
63
+ end
64
+