nimbus 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Juanjo Bazán & Oscar González Recio
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1 @@
1
+ = Nimbus
data/bin/nimbus ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #--
4
+ # Copyright (c) 2011 Juanjo Bazan
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files (the "Software"), to
8
+ # deal in the Software without restriction, including without limitation the
9
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10
+ # sell copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22
+ # IN THE SOFTWARE.
23
+ #++
24
+
25
+ require 'nimbus'
26
+ Nimbus.application.run
@@ -0,0 +1,77 @@
1
+ module Nimbus
2
+
3
+ #####################################################################
4
+ # Nimbus main application object. When invoking +nimbus+ from the
5
+ # command line, a Nimbus::Application object is created and run.
6
+ #
7
+ class Application
8
+ attr_accessor :config
9
+
10
+ # Initialize a Nimbus::Application object.
11
+ # Check and load the configuration options.
12
+ #
13
+ def initialize
14
+ nimbus_exception_handling do
15
+ config.load
16
+ end
17
+ end
18
+
19
+ # Run the Nimbus application. The run method performs the following
20
+ # two steps:
21
+ #
22
+ # * Creates a Nimbus::Forest object.
23
+ # * Writes results to output files.
24
+ def run
25
+ nimbus_exception_handling do
26
+ forest = ::Nimbus::Forest.new @config
27
+ forest.grow if @config.do_training && @config.load_training_data
28
+ output_random_forest_file(forest)
29
+ end
30
+ end
31
+
32
+ # Createas an instance of Nimbus::Configuration if it does not exist.
33
+ def config
34
+ @config ||= ::Nimbus::Configuration.new
35
+ end
36
+
37
+ # Provide exception handling for the given block.
38
+ def nimbus_exception_handling
39
+ begin
40
+ yield
41
+ rescue SystemExit => ex
42
+ raise
43
+ rescue OptionParser::InvalidOption => ex
44
+ display_error_message(Nimbus::InvalidOptionError ex.message)
45
+ Nimbus.stop
46
+ rescue Nimbus::Error => ex
47
+ display_error_message(ex)
48
+ Nimbus.stop
49
+ rescue Exception => ex
50
+ display_error_message(ex)
51
+ Nimbus.stop
52
+ end
53
+ end
54
+
55
+ # Display the error message that caused the exception.
56
+ def display_error_message(ex)
57
+ Nimbus.error_message "* Nimbus encountered an error! The random forest was not generated *"
58
+ Nimbus.error_message "#{ex.class}: #{ex.message}"
59
+ # if config.trace
60
+ Nimbus.error_message ex.backtrace.join("\n")
61
+ # else
62
+ # Nimbus.error_message "(See full error trace by running Nimbus with --trace)"
63
+ # end
64
+ end
65
+
66
+ protected
67
+ def output_random_forest_file(forest)
68
+ File.open(@config.output_forest_file , 'w') {|f| f.write(forest.to_yaml) }
69
+ Nimbus.message "* Resulting forest structure be saved to:"
70
+ Nimbus.message "* Output forest file: #{@config.output_forest_file}"
71
+ Nimbus.message "*" * 50
72
+
73
+ end
74
+
75
+ end
76
+
77
+ end
@@ -0,0 +1,153 @@
1
+ module Nimbus
2
+ class Configuration
3
+ attr_accessor(
4
+ :training_file,
5
+ :testing_file,
6
+ :forest_file,
7
+ :config_file,
8
+ :forest_size,
9
+ :tree_SNP_sample_size,
10
+ :tree_SNP_total_count,
11
+ :tree_max_branches,
12
+ :tree_node_min_size,
13
+ :loss_function_discrete,
14
+ :loss_function_continuous,
15
+ :do_training,
16
+ :do_testing,
17
+ :training_set,
18
+ :output_forest_file
19
+ )
20
+
21
+ DEFAULTS = {
22
+ :forest_size => 500,
23
+ :tree_SNP_sample_size => 60,
24
+ :tree_SNP_total_count => 200,
25
+ :tree_max_branches => 2000,
26
+ :tree_node_min_size => 5,
27
+
28
+ :loss_function_discrete => 'majority_class',
29
+ :loss_function_continuous => 'mean',
30
+
31
+ :training_file => 'training.data',
32
+ :testing_file => 'testing.data',
33
+ :forest_file => 'forest.yml',
34
+ :config_file => 'config.yml',
35
+
36
+ :output_forest_file => 'random_forest.yml'
37
+ }
38
+
39
+
40
+ def initialize
41
+ @do_training = false
42
+ @do_testing = false
43
+
44
+ @forest_size = DEFAULTS[:forest_size]
45
+ @tree_SNP_sample_size = DEFAULTS[:tree_SNP_sample_size]
46
+ @tree_SNP_total_count = DEFAULTS[:tree_SNP_total_count]
47
+ @tree_max_branches = DEFAULTS[:tree_max_branches]
48
+ @tree_node_min_size = DEFAULTS[:tree_node_min_size]
49
+ @loss_function_discrete = DEFAULTS[:loss_function_discrete]
50
+ @loss_function_continuous = DEFAULTS[:loss_function_continuous]
51
+
52
+ @output_forest_file = File.expand_path(DEFAULTS[:output_forest_file], Dir.pwd)
53
+ end
54
+
55
+ def tree
56
+ {
57
+ :snp_sample_size => @tree_SNP_sample_size,
58
+ :snp_total_count => @tree_SNP_total_count,
59
+ :tree_max_branches => @tree_max_branches,
60
+ :tree_node_min_size => @tree_node_min_size
61
+ }
62
+ end
63
+
64
+ def load(config_file = DEFAULTS[:config_file])
65
+ user_config_params = {}
66
+ if File.exists?(File.expand_path(config_file, Dir.pwd))
67
+ begin
68
+ user_config_params = YAML.load(File.open(File.expand_path config_file, Dir.pwd))
69
+ rescue ArgumentError => e
70
+ raise Nimbus::WrongFormatFileError, "It was not posible to parse the config file (#{config_file}): \r\n#{e.message} "
71
+ end
72
+ end
73
+
74
+ if user_config_params['input']
75
+ @training_file = File.expand_path(user_config_params['input']['training'], Dir.pwd) if user_config_params['input']['training']
76
+ @testing_file = File.expand_path(user_config_params['input']['testing' ], Dir.pwd) if user_config_params['input']['testing']
77
+ @forest_file = File.expand_path(user_config_params['input']['forest' ], Dir.pwd) if user_config_params['input']['forest']
78
+ else
79
+ @training_file = File.expand_path(DEFAULTS[:training_file], Dir.pwd) if File.exists? File.expand_path(DEFAULTS[:training_file], Dir.pwd)
80
+ @testing_file = File.expand_path(DEFAULTS[:testing_file ], Dir.pwd) if File.exists? File.expand_path(DEFAULTS[:testing_file ], Dir.pwd)
81
+ @forest_file = File.expand_path(DEFAULTS[:forest_file ], Dir.pwd) if File.exists? File.expand_path(DEFAULTS[:forest_file ], Dir.pwd)
82
+ end
83
+
84
+ @do_training = true if @training_file
85
+ @do_testing = true if @testing_file
86
+
87
+ if @do_testing && !@do_training && !@forest_file
88
+ raise Nimbus::InputFileError, "There is not random forest data (training file not defined, and forest file not found)."
89
+ end
90
+
91
+ if user_config_params['forest']
92
+ @forest_size = user_config_params['forest']['forest_size'].to_i if user_config_params['forest']['forest_size']
93
+ @tree_SNP_total_count = user_config_params['forest']['SNP_total_count'].to_i if user_config_params['forest']['SNP_total_count']
94
+ @tree_SNP_sample_size = user_config_params['forest']['SNP_sample_size_mtry'].to_i if user_config_params['forest']['SNP_sample_size_mtry']
95
+ @tree_max_branches = user_config_params['forest']['max_branches'].to_i if user_config_params['forest']['max_branches']
96
+ @tree_node_min_size = user_config_params['forest']['node_min_size'].to_i if user_config_params['forest']['node_min_size']
97
+ end
98
+
99
+ check_configuration
100
+ log_configuration
101
+ end
102
+
103
+ def load_training_data
104
+ File.open(@training_file) {|file|
105
+ @training_set = Nimbus::TrainingSet.new({}, {})
106
+ file.each do |line|
107
+ next if line.strip == ''
108
+ data_feno, data_id, *snp_list = line.strip.split
109
+ raise Nimbus::InputFileError, "Individual ##{data_id} from training set has no value for all #{@tree_SNP_total_count} SNPs" unless snp_list.size == @tree_SNP_total_count
110
+ @training_set.individuals[data_id.to_i] = Nimbus::Individual.new(data_id.to_i, data_feno.to_f, snp_list.map{|snp| snp.to_i})
111
+ @training_set.ids_fenotypes[data_id.to_i] = data_feno.to_f
112
+ end
113
+ }
114
+ end
115
+
116
+ def load_testing_data
117
+ end
118
+
119
+ def load_forest_data
120
+ end
121
+
122
+ def check_configuration
123
+ raise Nimbus::ConfigurationError, "The mtry sample size must be smaller than the total SNPs count." if @tree_SNP_sample_size > @tree_SNP_total_count
124
+ end
125
+
126
+ def log_configuration
127
+ Nimbus.message "*" * 50
128
+ Nimbus.message "* Nimbus configured with the following parameters: "
129
+ Nimbus.message "* Forest size: #{@forest_size} trees"
130
+ Nimbus.message "* Total SNP count: #{@tree_SNP_total_count}"
131
+ Nimbus.message "* SNPs sample size (mtry): #{@SNP_sample_size}"
132
+ Nimbus.message "* Maximum number of branches per tree: #{@tree_max_branches}"
133
+ Nimbus.message "* Minimun node size in tree: #{@tree_node_min_size}"
134
+ Nimbus.message "*" * 50
135
+ if @do_training
136
+ Nimbus.message "* Training data:"
137
+ Nimbus.message "* Training file: #{@training_file}"
138
+ Nimbus.message "*" * 50
139
+ end
140
+
141
+ if @do_testing
142
+ Nimbus.message "* Data to be tested:"
143
+ Nimbus.message "* Testing file: #{@testing_file}"
144
+ if @forest_file && !@do_training
145
+ Nimbus.message "* using the structure of the random forest stored in:"
146
+ Nimbus.message "* Random forest file: #{@forest_file}"
147
+ end
148
+ Nimbus.message "*" * 50
149
+ end
150
+ end
151
+
152
+ end
153
+ end
@@ -0,0 +1,10 @@
1
+ module Nimbus
2
+ class Error < StandardError; end
3
+ class InvalidOptionError < Error; end
4
+ class InputFileError < Error; end
5
+ class WrongFormatFileError < Error; end
6
+ class ConfigurationError < Error; end
7
+ class ForestError < Error; end
8
+ class TreeError < Error; end
9
+ class IndividualError < Error; end
10
+ end
@@ -0,0 +1,38 @@
1
+ module Nimbus
2
+
3
+ class Forest
4
+ attr_accessor :size, :trees
5
+ attr_accessor :options
6
+
7
+ def initialize(config)
8
+ @trees = []
9
+ @options = config
10
+ @size = config.forest_size
11
+ raise Nimbus::ForestError, "Forest size parameter (#{@size}) is invalid. You need at least one tree." if @size < 1
12
+ end
13
+
14
+ def grow
15
+ i=0
16
+ @size.times do
17
+ i+=1
18
+ tree = Tree.new @options.tree
19
+ @trees << tree.seed(@options.training_set.individuals, individuals_random_sample, @options.training_set.ids_fenotypes)
20
+ #OOB << Tree.traverse OOB por el tree.
21
+ end
22
+ end
23
+
24
+ def to_yaml
25
+ @trees.to_yaml
26
+ end
27
+
28
+
29
+ private
30
+
31
+ def individuals_random_sample
32
+ bag = (1..@options.training_set.individuals.size).to_a
33
+ individuals_sample = bag.inject([]){|items, i| items << bag.sample }.sort
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,13 @@
1
+ module Nimbus
2
+
3
+ class Individual
4
+ attr_accessor :id, :fenotype, :prediction, :snp_list
5
+
6
+ def initialize(i, fen, snps={})
7
+ self.id = i
8
+ self.fenotype = fen
9
+ self.snp_list = snps
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,23 @@
1
+ module Nimbus
2
+ module LossFunctions
3
+
4
+ class << self
5
+
6
+ def average(ids, value_table)
7
+ ids.inject(0.0){|sum, i| sum + value_table[i]} / ids.size
8
+ end
9
+
10
+ def mean_squared_error(ids, value_table, mean = nil)
11
+ mean ||= self.average ids, value_table
12
+ ids.inject(0.0){|sum, i| sum + ((value_table[i] - mean)**2) }
13
+ end
14
+
15
+ def quadratic_loss(ids, value_table, mean = nil)
16
+ self.mean_squared_error(ids, value_table, mean) / ids.size
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+ end
23
+
@@ -0,0 +1,12 @@
1
+ module Nimbus
2
+
3
+ class TrainingSet
4
+ attr_accessor :individuals, :ids_fenotypes
5
+
6
+ def initialize(individuals, ids_fenotypes)
7
+ @individuals = individuals
8
+ @ids_fenotypes = ids_fenotypes
9
+ end
10
+ end
11
+
12
+ end
@@ -0,0 +1,84 @@
1
+ module Nimbus
2
+
3
+ class Tree
4
+ attr_accessor :snp_sample_size, :snp_total_count, :node_min_size, :max_branches, :structure
5
+ attr_accessor :individuals, :id_to_fenotype
6
+
7
+ def initialize(options)
8
+ @snp_total_count = options[:snp_total_count]
9
+ @snp_sample_size = options[:snp_sample_size]
10
+ @node_min_size = options[:tree_node_min_size]
11
+ @max_branches = options[:tree_max_branches]
12
+ end
13
+
14
+ def seed(all_individuals, individuals_sample, ids_fenotypes)
15
+ @individuals = all_individuals
16
+ @id_to_fenotype = ids_fenotypes
17
+
18
+ @structure = build_node individuals_sample, Nimbus::LossFunctions.average(individuals_sample, @id_to_fenotype)
19
+ end
20
+
21
+ def build_node(individuals_ids, y_hat)
22
+ # General loss function value for the node
23
+ individuals_count = individuals_ids.size
24
+ return y_hat.round(5) if individuals_count < @node_min_size
25
+ node_loss_function = Nimbus::LossFunctions.quadratic_loss individuals_ids, @id_to_fenotype, y_hat
26
+
27
+ # Finding the SNP that minimizes loss function
28
+ snps = snps_random_sample
29
+ min_loss, min_SNP, split, means = node_loss_function, nil, nil, nil
30
+
31
+ snps.each do |snp|
32
+ individuals_split_by_snp_value = split_by_snp_value individuals_ids, snp
33
+ mean_0 = Nimbus::LossFunctions.average individuals_split_by_snp_value[0], @id_to_fenotype
34
+ mean_1 = Nimbus::LossFunctions.average individuals_split_by_snp_value[1], @id_to_fenotype
35
+ mean_2 = Nimbus::LossFunctions.average individuals_split_by_snp_value[2], @id_to_fenotype
36
+ loss_0 = Nimbus::LossFunctions.mean_squared_error individuals_split_by_snp_value[0], @id_to_fenotype, mean_0
37
+ loss_1 = Nimbus::LossFunctions.mean_squared_error individuals_split_by_snp_value[1], @id_to_fenotype, mean_1
38
+ loss_2 = Nimbus::LossFunctions.mean_squared_error individuals_split_by_snp_value[2], @id_to_fenotype, mean_2
39
+ loss_snp = (loss_0 + loss_1 + loss_2) / individuals_count
40
+
41
+ min_loss, min_SNP, split, means = loss_snp, snp, individuals_split_by_snp_value, [mean_0, mean_1, mean_2] if loss_snp < min_loss
42
+ end
43
+
44
+
45
+ return build_branch(min_SNP, split, means, y_hat) if min_loss < node_loss_function
46
+ return y_hat.round(5)
47
+ end
48
+
49
+ def build_branch(snp, split, y_hats, parent_y_hat)
50
+ node_0 = split[0].size == 0 ? parent_y_hat.round(5) : build_node(split[0], y_hats[0])
51
+ node_1 = split[1].size == 0 ? parent_y_hat.round(5) : build_node(split[1], y_hats[1])
52
+ node_2 = split[2].size == 0 ? parent_y_hat.round(5) : build_node(split[2], y_hats[2])
53
+
54
+ return { snp => [node_0, node_1, node_2] }
55
+ end
56
+
57
+ def traverse
58
+
59
+ end
60
+
61
+ def self.traverse(structure, data)
62
+
63
+ end
64
+
65
+
66
+ private
67
+
68
+ def snps_random_sample
69
+ (1..@snp_total_count).to_a.sample(@snp_sample_size).sort
70
+ end
71
+
72
+ def split_by_snp_value(ids, snp)
73
+ split = [[], [], []]
74
+ ids.each do |i|
75
+ split[ @individuals[i].snp_list[snp-1] ] << @individuals[i].id
76
+ end
77
+ split
78
+ rescue => ex
79
+ raise Nimbus::TreeError, "Values for SNPs columns must be in [0, 1, 2]"
80
+ end
81
+
82
+ end
83
+
84
+ end
data/lib/nimbus.rb ADDED
@@ -0,0 +1,48 @@
1
+ require 'yaml'
2
+ require 'optparse'
3
+ require 'nimbus/exceptions'
4
+ require 'nimbus/training_set'
5
+ require 'nimbus/configuration'
6
+ require 'nimbus/loss_functions'
7
+ require 'nimbus/individual'
8
+ require 'nimbus/tree'
9
+ require 'nimbus/forest'
10
+ require 'nimbus/application'
11
+
12
+ module Nimbus
13
+
14
+ STDERR = $stderr
15
+ STDOUT = $stdout
16
+
17
+ # Nimbus module singleton methods.
18
+ #
19
+ class << self
20
+ # Current Nimbus Application
21
+ def application
22
+ @application ||= ::Nimbus::Application.new
23
+ end
24
+
25
+ # Set the current Nimbus application object.
26
+ def application=(app)
27
+ @application = app
28
+ end
29
+
30
+ # Stops the execution of the Nimbus application.
31
+ def stop(msg = "Error: Nimbus finished.") # :nodoc:
32
+ STDERR.puts msg
33
+ exit(false)
34
+ end
35
+
36
+ # Writes message to the standard output
37
+ def message(msg)
38
+ STDOUT.puts msg
39
+ end
40
+
41
+ # Writes message to the error output
42
+ def error_message(msg)
43
+ STDERR.puts msg
44
+ end
45
+
46
+ end
47
+
48
+ end
@@ -0,0 +1,14 @@
1
+ #Input files
2
+ input:
3
+ training: Rtraining.h40
4
+ testing: Rtesting.h40
5
+
6
+ #Forest parameters
7
+ forest:
8
+ forest_size: 500 #how many trees
9
+ SNP_sample_size_mtry: 60 #mtry
10
+ SNP_total_count: 200
11
+ max_branches: 2000
12
+ node_min_size: 5
13
+ loss_function_discrete: 2
14
+ loss_function_cont: 2
@@ -0,0 +1,2 @@
1
+ # encoding: UTF-8
2
+ require File.dirname(__FILE__) + '/spec_helper'
@@ -0,0 +1,2 @@
1
+ # encoding: UTF-8
2
+ require File.dirname(__FILE__) + '/../lib/nimbus'
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nimbus
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: "0.1"
6
+ platform: ruby
7
+ authors:
8
+ - "Juanjo Baz\xC3\xA1n"
9
+ - "Oscar Gonz\xC3\xA1lez Recio"
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2011-08-01 00:00:00 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rspec
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 2.5.0
25
+ type: :development
26
+ version_requirements: *id001
27
+ description: Nimbus is a Ruby gem to implement Random Forest in a genomic selection context.
28
+ email:
29
+ - jjbazan@gmail.com
30
+ executables:
31
+ - nimbus
32
+ extensions: []
33
+
34
+ extra_rdoc_files: []
35
+
36
+ files:
37
+ - MIT-LICENSE.txt
38
+ - README.rdoc
39
+ - lib/nimbus/application.rb
40
+ - lib/nimbus/configuration.rb
41
+ - lib/nimbus/exceptions.rb
42
+ - lib/nimbus/forest.rb
43
+ - lib/nimbus/individual.rb
44
+ - lib/nimbus/loss_functions.rb
45
+ - lib/nimbus/training_set.rb
46
+ - lib/nimbus/tree.rb
47
+ - lib/nimbus.rb
48
+ - spec/fixtures/config.yml
49
+ - spec/nimbus_spec.rb
50
+ - spec/spec_helper.rb
51
+ - bin/nimbus
52
+ homepage: http://github.com/xuanxu/nimbus
53
+ licenses: []
54
+
55
+ post_install_message:
56
+ rdoc_options:
57
+ - --main
58
+ - README.rdoc
59
+ - --charset=UTF-8
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: "0"
74
+ requirements: []
75
+
76
+ rubyforge_project:
77
+ rubygems_version: 1.8.6
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: Random Forest algorithm for Genomics
81
+ test_files:
82
+ - spec/fixtures/config.yml
83
+ - spec/nimbus_spec.rb
84
+ - spec/spec_helper.rb