ai4r 1.3 → 1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +6 -12
- data/examples/neural_network/backpropagation_example.rb +18 -16
- data/examples/neural_network/xor_example.rb +30 -20
- data/lib/ai4r/classifiers/classifier.rb +15 -4
- data/lib/ai4r/classifiers/id3.rb +31 -31
- data/lib/ai4r/clusterers/clusterer.rb +5 -24
- data/lib/ai4r/clusterers/k_means.rb +7 -38
- data/lib/ai4r/data/data_set.rb +4 -2
- data/lib/ai4r/data/parameterizable.rb +64 -0
- data/lib/ai4r/neural_network/backpropagation.rb +233 -210
- data/site/build/site/en/downloads.html +3 -3
- data/site/build/site/en/geneticAlgorithms.html +3 -3
- data/site/build/site/en/index.html +32 -15
- data/site/build/site/en/index.pdf +126 -100
- data/site/build/site/en/linkmap.html +7 -9
- data/site/build/site/en/linkmap.pdf +12 -12
- data/site/build/site/en/machineLearning.html +7 -6
- data/site/build/site/en/machineLearning.pdf +29 -29
- data/site/build/site/en/neuralNetworks.html +164 -127
- data/site/build/site/en/neuralNetworks.pdf +267 -200
- data/site/build/site/en/svn.html +4 -4
- data/site/build/tmp/cocoon-work/cache-dir/cocoon-ehcache-1.data +0 -0
- data/site/build/tmp/cocoon-work/cache-dir/cocoon-ehcache-1.index +0 -0
- data/site/build/tmp/projfilters.properties +1 -1
- data/site/build/webapp/WEB-INF/logs/core.log +670 -489
- data/site/build/webapp/WEB-INF/logs/error.log +213 -364
- data/site/build/webapp/WEB-INF/logs/sitemap.log +0 -368
- data/site/src/documentation/content/xdocs/index.xml +1 -1
- data/site/src/documentation/content/xdocs/neuralNetworks.xml +118 -90
- data/site/src/documentation/content/xdocs/site.xml +2 -3
- data/test/neural_network/backpropagation_test.rb +23 -0
- metadata +5 -7
- data/site/build/site/en/forum.html +0 -197
- data/site/build/site/en/forum.pdf +0 -151
- data/site/build/site/en/wholesite.pdf +0 -1915
data/README.rdoc
CHANGED
@@ -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
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
21
|
-
|
22
|
-
|
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 /
|
29
|
-
sq_with_base_noise = SQUARE_WITH_BASE_NOISE.flatten.collect { |input| input.to_f /
|
30
|
-
cr_with_base_noise = CROSS_WITH_BASE_NOISE.flatten.collect { |input| input.to_f /
|
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
|
-
|
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
|
-
|
67
|
+
puts "Elapsed time: #{times}"
|
@@ -1,25 +1,35 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
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
|
-
|
7
|
-
|
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
|
-
|
13
|
+
times = Benchmark.measure do
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
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
|
-
|
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
|
-
#
|
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
|
data/lib/ai4r/classifiers/id3.rb
CHANGED
@@ -28,24 +28,26 @@ module Ai4r
|
|
28
28
|
#
|
29
29
|
# DATA_LABELS = [ 'city', 'age_range', 'gender', 'marketing_target' ]
|
30
30
|
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
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
|
-
#
|
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
|
-
#
|
68
|
-
#
|
69
|
-
#
|
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(
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
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
|
-
|
27
|
-
|
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.
|
data/lib/ai4r/data/data_set.rb
CHANGED
@@ -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
|
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
|
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
|
+
|