hybridforest 0.9.0

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 (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +89 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +13 -0
  5. data/CHANGELOG.md +33 -0
  6. data/Gemfile +22 -0
  7. data/Gemfile.lock +92 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +96 -0
  10. data/Rakefile +12 -0
  11. data/bin/console +15 -0
  12. data/bin/setup +8 -0
  13. data/hybridforest.gemspec +44 -0
  14. data/lib/hybridforest/errors/invalid_state_error.rb +9 -0
  15. data/lib/hybridforest/forests/forest_growers/cart_grower.rb +19 -0
  16. data/lib/hybridforest/forests/forest_growers/hybrid_grower.rb +46 -0
  17. data/lib/hybridforest/forests/forest_growers/id3_grower.rb +19 -0
  18. data/lib/hybridforest/forests/grower_factory.rb +29 -0
  19. data/lib/hybridforest/forests/random_forest.rb +84 -0
  20. data/lib/hybridforest/trees/cart_tree.rb +18 -0
  21. data/lib/hybridforest/trees/feature_selectors/all_features.rb +14 -0
  22. data/lib/hybridforest/trees/feature_selectors/max_one_split_per_feature.rb +21 -0
  23. data/lib/hybridforest/trees/feature_selectors/random_feature_subspace.rb +27 -0
  24. data/lib/hybridforest/trees/id3_tree.rb +18 -0
  25. data/lib/hybridforest/trees/impurity_metrics/entropy.rb +21 -0
  26. data/lib/hybridforest/trees/impurity_metrics/gini_impurity.rb +17 -0
  27. data/lib/hybridforest/trees/impurity_metrics/impurity.rb +28 -0
  28. data/lib/hybridforest/trees/nodes/binary_node.rb +37 -0
  29. data/lib/hybridforest/trees/nodes/leaf_node.rb +31 -0
  30. data/lib/hybridforest/trees/nodes/multiway_node.rb +45 -0
  31. data/lib/hybridforest/trees/split.rb +30 -0
  32. data/lib/hybridforest/trees/tests/equal.rb +37 -0
  33. data/lib/hybridforest/trees/tests/equal_or_greater.rb +37 -0
  34. data/lib/hybridforest/trees/tests/less.rb +37 -0
  35. data/lib/hybridforest/trees/tests/not_equal.rb +37 -0
  36. data/lib/hybridforest/trees/tests/test.rb +28 -0
  37. data/lib/hybridforest/trees/tree.rb +46 -0
  38. data/lib/hybridforest/trees/tree_growers/cart_grower.rb +76 -0
  39. data/lib/hybridforest/trees/tree_growers/id3_grower.rb +161 -0
  40. data/lib/hybridforest/utilities/utils.rb +206 -0
  41. data/lib/hybridforest/version.rb +5 -0
  42. data/lib/hybridforest.rb +46 -0
  43. metadata +285 -0
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "observer"
4
+ require_relative "../../utilities/utils"
5
+ require_relative "../split"
6
+ require_relative "../feature_selectors/random_feature_subspace"
7
+ require_relative "../feature_selectors/all_features"
8
+ require_relative "../feature_selectors/max_one_split_per_feature"
9
+ require_relative "../impurity_metrics/gini_impurity"
10
+ require_relative "../impurity_metrics/entropy"
11
+ require_relative "../nodes/binary_node"
12
+ require_relative "../nodes/multiway_node"
13
+ require_relative "../nodes/leaf_node"
14
+ require_relative "../tests/less"
15
+ require_relative "../tests/equal"
16
+ require_relative "../tests/equal_or_greater"
17
+
18
+ module HybridForest
19
+ module Trees
20
+ module TreeGrowers
21
+ class ID3Grower
22
+ include Observable
23
+
24
+ def initialize(feature_selector: MaxOneSplitPerFeature.new, impurity_metric: Entropy.new)
25
+ @impurity_metric = impurity_metric
26
+ @feature_selector = feature_selector
27
+ add_observer(@feature_selector)
28
+ end
29
+
30
+ def grow_tree(instances, parent_instances = nil)
31
+ features = remaining_features(instances)
32
+
33
+ if instances.count == 0
34
+ LeafNode.new(parent_instances)
35
+ elsif instances.pure? || features.count == 0
36
+ LeafNode.new(instances)
37
+ else
38
+ try_to_split_dataset(instances, features)
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def try_to_split_dataset(instances, features)
45
+ split = find_best_split(instances, features)
46
+
47
+ if split.info_gain == 0
48
+ LeafNode.new(instances)
49
+ elsif split.binary?
50
+ branch_binary(instances, split.subsets, split.feature, split.value)
51
+ else
52
+ branch_multiway(instances, split.subsets, split.feature)
53
+ end
54
+ end
55
+
56
+ def find_best_split(instances, features)
57
+ current_impurity = @impurity_metric.compute(instances)
58
+ best_split = default_split(instances, features)
59
+
60
+ features.each do |feature|
61
+ best_split = if instances[feature].numeric?
62
+ best_binary_split(instances, feature, current_impurity, best_split)
63
+ else
64
+ best_multiway_split(instances, feature, current_impurity, best_split)
65
+ end
66
+ end
67
+
68
+ mark_as_used(best_split.feature)
69
+
70
+ best_split
71
+ end
72
+
73
+ def branch_binary(instances, subsets, feature, value)
74
+ true_instances, false_instances = subsets
75
+ true_branch = grow_tree(true_instances, instances)
76
+ false_branch = grow_tree(false_instances, instances)
77
+ test = Tests::EqualOrGreater.new(feature, value)
78
+ BinaryNode.new(test, true_branch, false_branch)
79
+ end
80
+
81
+ def branch_multiway(instances, subsets, feature)
82
+ branches = subsets.collect do |subset|
83
+ grow_tree(subset, instances)
84
+ end
85
+ paths = map_tests_to_branches(branches, subsets, feature)
86
+ MultiwayNode.new(paths, instances)
87
+ end
88
+
89
+ def map_tests_to_branches(branches, subsets_of_instances, feature)
90
+ paths = {}
91
+ branches.zip(subsets_of_instances) do |branch, subset|
92
+ value = subset[feature][0]
93
+ test = Tests::Equal.new(feature, value)
94
+ paths[test] = branch
95
+ end
96
+ paths
97
+ end
98
+
99
+ def best_binary_split(instances, feature, initial_impurity, best_split)
100
+ candidate_values = potential_split_values(feature, instances)
101
+
102
+ candidate_values.each do |value|
103
+ subsets = instances.equal_or_greater_split(feature, value)
104
+ info_gain = @impurity_metric.information_gain(subsets, initial_impurity)
105
+
106
+ split = Split.new(feature, info_gain: info_gain, subsets: subsets, value: value)
107
+ if split.better_than? best_split
108
+ best_split = split
109
+ end
110
+ end
111
+
112
+ best_split
113
+ end
114
+
115
+ def best_multiway_split(instances, feature, initial_impurity, best_split)
116
+ subsets = instances.multiway_equal_split(feature)
117
+ info_gain = @impurity_metric.information_gain(subsets, initial_impurity)
118
+
119
+ split = Split.new(feature, info_gain: info_gain, subsets: subsets)
120
+ if split.better_than? best_split
121
+ best_split = split
122
+ end
123
+
124
+ best_split
125
+ end
126
+
127
+ def potential_split_values(feature, instances)
128
+ label = instances.label
129
+ sorted = instances.sort_by { |instance| instance[feature] }
130
+ candidates = Set.new
131
+
132
+ sorted.each_row.each_cons(2) do |first, second|
133
+ next if first[label] == second[label]
134
+ candidates << second[feature]
135
+ end
136
+ candidates
137
+ end
138
+
139
+ def default_split(instances, features)
140
+ first_feature = features.first
141
+
142
+ if instances[first_feature].numeric?
143
+ value = instances[first_feature].first
144
+ Split.new(first_feature, value: value)
145
+ else
146
+ Split.new(first_feature)
147
+ end
148
+ end
149
+
150
+ def remaining_features(instances)
151
+ @feature_selector.select_features(instances.features)
152
+ end
153
+
154
+ def mark_as_used(feature)
155
+ changed
156
+ notify_observers(feature)
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,206 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rover"
4
+ require "rover-df"
5
+ require "rumale"
6
+
7
+ module HybridForest
8
+ module Utils
9
+ extend self
10
+ ##
11
+ # Partitions +dataset+ into training and testing datasets, and splits the testing dataset into a dataframe
12
+ # of independent features and an array of labels. Returns [+training_set+, +testing_set+, +testing_set_labels+]
13
+ #
14
+ def self.train_test_split(dataset, test_set_size = 0.20)
15
+ # TODO: Shuffle and stratify samples
16
+ dataset = to_dataframe(dataset)
17
+
18
+ test_set_count = (dataset.count * test_set_size).floor
19
+ test_set_indices = 0..test_set_count
20
+ test_set = dataset[test_set_indices]
21
+ test_set_labels = test_set.class_labels
22
+ test_set.except!(test_set.label)
23
+
24
+ train_set_indices = test_set_count + 1...dataset.count
25
+ train_set = dataset[train_set_indices]
26
+
27
+ [train_set, test_set, test_set_labels]
28
+ end
29
+
30
+ ##
31
+ # Partitions +dataset+ into training and testing datasets, drawing with replacement to the training set,
32
+ # and using the not drawn instances as the testing dataset. Then, splits the testing dataset into a dataframe of
33
+ # independent features and an array of labels.
34
+ # Returns [+training_set+, +testing_set+, +testing_set_labels+]
35
+ #
36
+ def self.train_test_bootstrap_split(dataset)
37
+ dataset = to_dataframe(dataset)
38
+ all_rows = (0...dataset.count).to_a
39
+
40
+ train_set = Rover::DataFrame.new
41
+ train_set_rows = []
42
+ dataset.count.times do
43
+ row = all_rows.sample
44
+ train_set_rows << row
45
+ train_set.concat(dataset[row])
46
+ end
47
+
48
+ return train_test_split(dataset) if train_set_rows.sort == all_rows
49
+
50
+ test_set_rows = all_rows - train_set_rows
51
+ test_set = dataset[test_set_rows]
52
+ test_set_labels = test_set.class_labels
53
+ test_set.except!(test_set.label)
54
+
55
+ [train_set, test_set, test_set_labels]
56
+ end
57
+
58
+ #
59
+ # Turns +instances+ into a dataframe prepared for fitting and applying models.
60
+ # Instances can be an array of hashes:
61
+ #
62
+ # [{a: 1, b: "one"},
63
+ # {a: 2, b: "two"},
64
+ # {a: 3, b: "three"}]
65
+ #
66
+ # or a hash of arrays:
67
+ #
68
+ # {a: [1, 2, 3],
69
+ # b: ["one", "two", "three"]}
70
+ #
71
+ # or the path to a CSV file:
72
+ #
73
+ # "dataset.csv"
74
+ #
75
+ # Accepts an optional hash for specifying feature data types:
76
+ # to_dataframe("dataset.csv", types: {"a" => :int, "b" => :float})
77
+ #
78
+ # Raises ArgumentError if given an invalid dataset.
79
+ def self.to_dataframe(instances, types: nil)
80
+ return instances if instances.is_a? Rover::DataFrame
81
+ return instances if success? { instances = Rover::DataFrame.new(instances, types: types) }
82
+ return instances if success? { instances = Rover.read_csv(instances, types: types) }
83
+ raise ArgumentError, @error
84
+ end
85
+
86
+ # Draws a random sample of +size+ from +data+.
87
+ #
88
+ def self.random_sample(data:, size:, with_replacement: true)
89
+ raise ArgumentError, "Invalid sample size" if size < 1 || size > data.count
90
+
91
+ if with_replacement
92
+ rows = size.times.collect { rand(0...data.count) }
93
+ data[rows]
94
+ else
95
+ rows = Set.new
96
+ until rows.size == size
97
+ rows << rand(0...data.count)
98
+ end
99
+ data[rows.to_a]
100
+ end
101
+ end
102
+
103
+ # Outputs a report of common prediction metrics.
104
+ # +actual+ and +predicted+ are expected to be equal sized arrays of class labels.
105
+ def self.prediction_report(actual, predicted)
106
+ Rumale::EvaluationMeasure.classification_report(
107
+ actual,
108
+ predicted
109
+ )
110
+ end
111
+
112
+ # Given an array of predicted labels and an array of actual labels, returns the accuracy of the predictions.
113
+ #
114
+ def self.accuracy(predicted, actual)
115
+ accurate = predicted.zip(actual).count { |p, a| equal_labels?(p, a) }
116
+ accurate.to_f / predicted.count.to_f
117
+ end
118
+
119
+ # Extensions to simplify common dataframe operations.
120
+ #
121
+ module DataFrameExtensions
122
+ class Rover::DataFrame
123
+ def equal_split(feature, value)
124
+ equal = self[self[feature] == value]
125
+ not_equal = self[!self[feature].in?([value])]
126
+ [equal, not_equal]
127
+ end
128
+
129
+ def equal_or_greater_split(feature, value)
130
+ equal_or_greater = self[self[feature] >= value]
131
+ less = self[self[feature] < value]
132
+ [equal_or_greater, less]
133
+ end
134
+
135
+ def multiway_equal_split(feature)
136
+ subsets = []
137
+ self[feature].uniq.each do |value|
138
+ subsets << self[self[feature] == value]
139
+ end
140
+ subsets
141
+ end
142
+
143
+ def column_by_index(index)
144
+ where = @vectors.keys[index]
145
+ @vectors[where]
146
+ end
147
+
148
+ def feature_count(without_label: true)
149
+ without_label ? names.count - 1 : names.count
150
+ end
151
+
152
+ def pure?
153
+ column_by_index(-1).uniq.size == 1
154
+ end
155
+
156
+ def features
157
+ names[0...-1]
158
+ end
159
+
160
+ def count_labels
161
+ column_by_index(-1).tally
162
+ end
163
+
164
+ def label
165
+ names[-1]
166
+ end
167
+
168
+ def class_labels
169
+ self[label].to_a
170
+ end
171
+ end
172
+ end
173
+
174
+ private
175
+
176
+ # Yields to the given block and rescues any errors.
177
+ # Returns +true+ if no exceptions were raised, +false+ otherwise.
178
+ def success?
179
+ yield
180
+ true
181
+ rescue => e
182
+ @error ||= e.to_s
183
+ false
184
+ end
185
+
186
+ def equal_labels?(a, b)
187
+ a == b || both_true?(a, b) || both_false?(a, b)
188
+ end
189
+
190
+ def both_true?(a, b)
191
+ true_label?(a) && true_label?(b)
192
+ end
193
+
194
+ def both_false?(a, b)
195
+ false_label?(a) && false_label?(b)
196
+ end
197
+
198
+ def true_label?(label)
199
+ [true, 1].include? label
200
+ end
201
+
202
+ def false_label?(label)
203
+ [false, 0].include? label
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HybridForest
4
+ VERSION = "0.9.0"
5
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support"
4
+ require "require_all"
5
+ require "rover"
6
+ require "rspec"
7
+ require "rumale"
8
+ require "set"
9
+ require "terminal-table"
10
+
11
+ require_relative "hybridforest/version"
12
+ require_relative "hybridforest/errors/invalid_state_error"
13
+ require_relative "hybridforest/forests/forest_growers/hybrid_grower"
14
+ require_relative "hybridforest/forests/forest_growers/cart_grower"
15
+ require_relative "hybridforest/forests/forest_growers/id3_grower"
16
+ require_relative "hybridforest/forests/grower_factory"
17
+ require_relative "hybridforest/forests/random_forest"
18
+ require_relative "hybridforest/trees/tree"
19
+ require_relative "hybridforest/trees/cart_tree"
20
+ require_relative "hybridforest/trees/id3_tree"
21
+ require_relative "hybridforest/trees/split"
22
+ require_relative "hybridforest/trees/feature_selectors/all_features"
23
+ require_relative "hybridforest/trees/feature_selectors/max_one_split_per_feature"
24
+ require_relative "hybridforest/trees/feature_selectors/random_feature_subspace"
25
+ require_relative "hybridforest/trees/impurity_metrics/impurity"
26
+ require_relative "hybridforest/trees/impurity_metrics/entropy"
27
+ require_relative "hybridforest/trees/impurity_metrics/gini_impurity"
28
+ require_relative "hybridforest/trees/nodes/binary_node"
29
+ require_relative "hybridforest/trees/nodes/leaf_node"
30
+ require_relative "hybridforest/trees/nodes/multiway_node"
31
+ require_relative "hybridforest/trees/tests/test"
32
+ require_relative "hybridforest/trees/tests/less"
33
+ require_relative "hybridforest/trees/tests/equal"
34
+ require_relative "hybridforest/trees/tests/equal_or_greater"
35
+ require_relative "hybridforest/trees/tests/not_equal"
36
+ require_relative "hybridforest/trees/tree_growers/cart_grower"
37
+ require_relative "hybridforest/trees/tree_growers/id3_grower"
38
+ require_relative "hybridforest/utilities/utils"
39
+
40
+ module HybridForest
41
+ FOREST_TYPES = [
42
+ :hybrid,
43
+ :cart,
44
+ :id3
45
+ ].freeze
46
+ end
metadata ADDED
@@ -0,0 +1,285 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hybridforest
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ platform: ruby
6
+ authors:
7
+ - hi-tech-jazz
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-12-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '13.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '13.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.7'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.7'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rumale
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: activesupport
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '6.1'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '6.1'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rover-df
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.2.6
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.2.6
97
+ - !ruby/object:Gem::Dependency
98
+ name: require_all
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: terminal-table
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '3.0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '3.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rake
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '13.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '13.0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rspec
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '3.0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '3.0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rubocop
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '1.7'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '1.7'
167
+ - !ruby/object:Gem::Dependency
168
+ name: rumale
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: activesupport
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: '6.1'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: '6.1'
195
+ - !ruby/object:Gem::Dependency
196
+ name: rover-df
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - "~>"
200
+ - !ruby/object:Gem::Version
201
+ version: 0.2.6
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - "~>"
207
+ - !ruby/object:Gem::Version
208
+ version: 0.2.6
209
+ description: HybridForest provides random forests built upon combinations of different
210
+ decision tree algorithms to enable diverse tree ensembles. Until version 1.0.0,
211
+ please expect breaking changes.
212
+ email:
213
+ - jazztechhi@gmail.com
214
+ executables: []
215
+ extensions: []
216
+ extra_rdoc_files: []
217
+ files:
218
+ - ".gitignore"
219
+ - ".rspec"
220
+ - ".rubocop.yml"
221
+ - CHANGELOG.md
222
+ - Gemfile
223
+ - Gemfile.lock
224
+ - LICENSE.txt
225
+ - README.md
226
+ - Rakefile
227
+ - bin/console
228
+ - bin/setup
229
+ - hybridforest.gemspec
230
+ - lib/hybridforest.rb
231
+ - lib/hybridforest/errors/invalid_state_error.rb
232
+ - lib/hybridforest/forests/forest_growers/cart_grower.rb
233
+ - lib/hybridforest/forests/forest_growers/hybrid_grower.rb
234
+ - lib/hybridforest/forests/forest_growers/id3_grower.rb
235
+ - lib/hybridforest/forests/grower_factory.rb
236
+ - lib/hybridforest/forests/random_forest.rb
237
+ - lib/hybridforest/trees/cart_tree.rb
238
+ - lib/hybridforest/trees/feature_selectors/all_features.rb
239
+ - lib/hybridforest/trees/feature_selectors/max_one_split_per_feature.rb
240
+ - lib/hybridforest/trees/feature_selectors/random_feature_subspace.rb
241
+ - lib/hybridforest/trees/id3_tree.rb
242
+ - lib/hybridforest/trees/impurity_metrics/entropy.rb
243
+ - lib/hybridforest/trees/impurity_metrics/gini_impurity.rb
244
+ - lib/hybridforest/trees/impurity_metrics/impurity.rb
245
+ - lib/hybridforest/trees/nodes/binary_node.rb
246
+ - lib/hybridforest/trees/nodes/leaf_node.rb
247
+ - lib/hybridforest/trees/nodes/multiway_node.rb
248
+ - lib/hybridforest/trees/split.rb
249
+ - lib/hybridforest/trees/tests/equal.rb
250
+ - lib/hybridforest/trees/tests/equal_or_greater.rb
251
+ - lib/hybridforest/trees/tests/less.rb
252
+ - lib/hybridforest/trees/tests/not_equal.rb
253
+ - lib/hybridforest/trees/tests/test.rb
254
+ - lib/hybridforest/trees/tree.rb
255
+ - lib/hybridforest/trees/tree_growers/cart_grower.rb
256
+ - lib/hybridforest/trees/tree_growers/id3_grower.rb
257
+ - lib/hybridforest/utilities/utils.rb
258
+ - lib/hybridforest/version.rb
259
+ homepage: https://github.com/hi-tech-jazz/hybridforest
260
+ licenses:
261
+ - MIT
262
+ metadata:
263
+ homepage_uri: https://github.com/hi-tech-jazz/hybridforest
264
+ source_code_uri: https://github.com/hi-tech-jazz/hybridforest
265
+ changelog_uri: https://github.com/hi-tech-jazz/hybridforest/blob/master/CHANGELOG.md
266
+ post_install_message:
267
+ rdoc_options: []
268
+ require_paths:
269
+ - lib
270
+ required_ruby_version: !ruby/object:Gem::Requirement
271
+ requirements:
272
+ - - ">="
273
+ - !ruby/object:Gem::Version
274
+ version: 3.0.2
275
+ required_rubygems_version: !ruby/object:Gem::Requirement
276
+ requirements:
277
+ - - ">="
278
+ - !ruby/object:Gem::Version
279
+ version: '0'
280
+ requirements: []
281
+ rubygems_version: 3.3.3
282
+ signing_key:
283
+ specification_version: 4
284
+ summary: Hybrid random forest for binary classification tasks.
285
+ test_files: []