daru_lite 0.1
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.
- checksums.yaml +7 -0
- data/.github/ISSUE_TEMPLATE.md +18 -0
- data/.github/workflows/ci.yml +33 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.rubocop.yml +27 -0
- data/.rubocop_todo.yml +137 -0
- data/CONTRIBUTING.md +47 -0
- data/Gemfile +2 -0
- data/History.md +4 -0
- data/LICENSE +24 -0
- data/README.md +218 -0
- data/Rakefile +69 -0
- data/ReleasePolicy.md +20 -0
- data/benchmarks/TradeoffData.csv +65 -0
- data/benchmarks/csv_reading.rb +22 -0
- data/benchmarks/dataframe_creation.rb +39 -0
- data/benchmarks/db_loading.rb +34 -0
- data/benchmarks/duplicating.rb +45 -0
- data/benchmarks/group_by.rb +32 -0
- data/benchmarks/joining.rb +52 -0
- data/benchmarks/row_access.rb +41 -0
- data/benchmarks/row_assign.rb +36 -0
- data/benchmarks/sorting.rb +51 -0
- data/benchmarks/statistics.rb +28 -0
- data/benchmarks/vector_access.rb +31 -0
- data/benchmarks/vector_assign.rb +42 -0
- data/benchmarks/where_clause.rb +48 -0
- data/benchmarks/where_vs_filter.rb +28 -0
- data/daru_lite.gemspec +55 -0
- data/images/README.md +5 -0
- data/images/con0.png +0 -0
- data/images/con1.png +0 -0
- data/images/init0.png +0 -0
- data/images/init1.png +0 -0
- data/images/man0.png +0 -0
- data/images/man1.png +0 -0
- data/images/man2.png +0 -0
- data/images/man3.png +0 -0
- data/images/man4.png +0 -0
- data/images/man5.png +0 -0
- data/images/man6.png +0 -0
- data/lib/daru_lite/accessors/array_wrapper.rb +109 -0
- data/lib/daru_lite/accessors/dataframe_by_row.rb +25 -0
- data/lib/daru_lite/accessors/mdarray_wrapper.rb +7 -0
- data/lib/daru_lite/category.rb +929 -0
- data/lib/daru_lite/configuration.rb +34 -0
- data/lib/daru_lite/core/group_by.rb +403 -0
- data/lib/daru_lite/core/merge.rb +270 -0
- data/lib/daru_lite/core/query.rb +109 -0
- data/lib/daru_lite/dataframe.rb +3080 -0
- data/lib/daru_lite/date_time/index.rb +569 -0
- data/lib/daru_lite/date_time/offsets.rb +397 -0
- data/lib/daru_lite/exceptions.rb +2 -0
- data/lib/daru_lite/extensions/which_dsl.rb +53 -0
- data/lib/daru_lite/formatters/table.rb +52 -0
- data/lib/daru_lite/helpers/array.rb +53 -0
- data/lib/daru_lite/index/categorical_index.rb +201 -0
- data/lib/daru_lite/index/index.rb +374 -0
- data/lib/daru_lite/index/multi_index.rb +374 -0
- data/lib/daru_lite/io/csv/converters.rb +21 -0
- data/lib/daru_lite/io/io.rb +294 -0
- data/lib/daru_lite/io/sql_data_source.rb +97 -0
- data/lib/daru_lite/iruby/helpers.rb +38 -0
- data/lib/daru_lite/iruby/templates/dataframe.html.erb +5 -0
- data/lib/daru_lite/iruby/templates/dataframe_mi.html.erb +5 -0
- data/lib/daru_lite/iruby/templates/dataframe_mi_tbody.html.erb +35 -0
- data/lib/daru_lite/iruby/templates/dataframe_mi_thead.html.erb +21 -0
- data/lib/daru_lite/iruby/templates/dataframe_tbody.html.erb +28 -0
- data/lib/daru_lite/iruby/templates/dataframe_thead.html.erb +21 -0
- data/lib/daru_lite/iruby/templates/multi_index.html.erb +12 -0
- data/lib/daru_lite/iruby/templates/vector.html.erb +5 -0
- data/lib/daru_lite/iruby/templates/vector_mi.html.erb +5 -0
- data/lib/daru_lite/iruby/templates/vector_mi_tbody.html.erb +26 -0
- data/lib/daru_lite/iruby/templates/vector_mi_thead.html.erb +8 -0
- data/lib/daru_lite/iruby/templates/vector_tbody.html.erb +17 -0
- data/lib/daru_lite/iruby/templates/vector_thead.html.erb +8 -0
- data/lib/daru_lite/maths/arithmetic/dataframe.rb +91 -0
- data/lib/daru_lite/maths/arithmetic/vector.rb +117 -0
- data/lib/daru_lite/maths/statistics/dataframe.rb +202 -0
- data/lib/daru_lite/maths/statistics/vector.rb +1019 -0
- data/lib/daru_lite/monkeys.rb +56 -0
- data/lib/daru_lite/vector.rb +1678 -0
- data/lib/daru_lite/version.rb +3 -0
- data/lib/daru_lite.rb +99 -0
- data/profile/_base.rb +23 -0
- data/profile/df_to_a.rb +10 -0
- data/profile/filter.rb +13 -0
- data/profile/joining.rb +13 -0
- data/profile/sorting.rb +12 -0
- data/profile/vector_each_with_index.rb +9 -0
- data/profile/vector_new.rb +9 -0
- data/spec/accessors/array_wrapper_spec.rb +3 -0
- data/spec/category_spec.rb +1741 -0
- data/spec/core/group_by_spec.rb +655 -0
- data/spec/core/merge_spec.rb +179 -0
- data/spec/core/query_spec.rb +347 -0
- data/spec/daru_lite_spec.rb +22 -0
- data/spec/dataframe_spec.rb +4330 -0
- data/spec/date_time/data_spec.rb +197 -0
- data/spec/date_time/date_time_index_helper_spec.rb +72 -0
- data/spec/date_time/index_spec.rb +588 -0
- data/spec/date_time/offsets_spec.rb +465 -0
- data/spec/extensions/which_dsl_spec.rb +38 -0
- data/spec/fixtures/bank2.dat +200 -0
- data/spec/fixtures/boolean_converter_test.csv +5 -0
- data/spec/fixtures/countries.json +7794 -0
- data/spec/fixtures/duplicates.csv +32 -0
- data/spec/fixtures/eciresults.html +394 -0
- data/spec/fixtures/empties.dat +2 -0
- data/spec/fixtures/empty_rows_test.csv +17 -0
- data/spec/fixtures/macau.html +3691 -0
- data/spec/fixtures/macd_data.csv +150 -0
- data/spec/fixtures/matrix_test.csv +100 -0
- data/spec/fixtures/moneycontrol.html +6812 -0
- data/spec/fixtures/music_data.tsv +2501 -0
- data/spec/fixtures/repeated_fields.csv +7 -0
- data/spec/fixtures/sales-funnel.csv +18 -0
- data/spec/fixtures/scientific_notation.csv +4 -0
- data/spec/fixtures/string_converter_test.csv +5 -0
- data/spec/fixtures/strings.dat +2 -0
- data/spec/fixtures/test_xls.xls +0 -0
- data/spec/fixtures/test_xls_2.xls +0 -0
- data/spec/fixtures/url_test.txt~ +0 -0
- data/spec/fixtures/valid_markup.html +62 -0
- data/spec/fixtures/wiki_climate.html +1243 -0
- data/spec/fixtures/wiki_table_info.html +631 -0
- data/spec/formatters/table_formatter_spec.rb +137 -0
- data/spec/helpers_spec.rb +8 -0
- data/spec/index/categorical_index_spec.rb +170 -0
- data/spec/index/index_spec.rb +417 -0
- data/spec/index/multi_index_spec.rb +680 -0
- data/spec/io/io_spec.rb +373 -0
- data/spec/io/sql_data_source_spec.rb +56 -0
- data/spec/iruby/dataframe_spec.rb +170 -0
- data/spec/iruby/helpers_spec.rb +49 -0
- data/spec/iruby/multi_index_spec.rb +37 -0
- data/spec/iruby/vector_spec.rb +105 -0
- data/spec/maths/arithmetic/dataframe_spec.rb +148 -0
- data/spec/maths/arithmetic/vector_spec.rb +165 -0
- data/spec/maths/statistics/dataframe_spec.rb +178 -0
- data/spec/maths/statistics/vector_spec.rb +756 -0
- data/spec/monkeys_spec.rb +42 -0
- data/spec/shared/vector_display_spec.rb +213 -0
- data/spec/spec_helper.rb +87 -0
- data/spec/support/database_helper.rb +30 -0
- data/spec/support/matchers.rb +5 -0
- data/spec/vector_spec.rb +2293 -0
- metadata +571 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
describe DaruLite::DataFrame do
|
|
2
|
+
context "#join" do
|
|
3
|
+
before do
|
|
4
|
+
@left = DaruLite::DataFrame.new({
|
|
5
|
+
:id => [1,2,3,4],
|
|
6
|
+
:name => ['Pirate', 'Monkey', 'Ninja', 'Spaghetti']
|
|
7
|
+
})
|
|
8
|
+
@right = DaruLite::DataFrame.new({
|
|
9
|
+
:id => [1,2,3,4],
|
|
10
|
+
:name => ['Rutabaga', 'Pirate', 'Darth Vader', 'Ninja']
|
|
11
|
+
})
|
|
12
|
+
@right_many = DaruLite::DataFrame.new({
|
|
13
|
+
:id => [1,1,1,1],
|
|
14
|
+
:name => ['Rutabaga', 'Pirate', 'Darth Vader', 'Ninja']
|
|
15
|
+
})
|
|
16
|
+
@empty = DaruLite::DataFrame.new({
|
|
17
|
+
:id => [],
|
|
18
|
+
:name => []
|
|
19
|
+
})
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "performs an inner join of two dataframes" do
|
|
23
|
+
answer = DaruLite::DataFrame.new({
|
|
24
|
+
:id_1 => [3,1],
|
|
25
|
+
:name => ['Ninja', 'Pirate'],
|
|
26
|
+
:id_2 => [4,2]
|
|
27
|
+
}, order: [:id_1, :name, :id_2])
|
|
28
|
+
expect(@left.join(@right, how: :inner, on: [:name])).to eq(answer)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "performs an inner join of two dataframes that has one to many mapping" do
|
|
32
|
+
answer = DaruLite::DataFrame.new({
|
|
33
|
+
:name_1 => ['Pirate', 'Pirate', 'Pirate', 'Pirate'],
|
|
34
|
+
:id => [1,1,1,1],
|
|
35
|
+
:name_2 => ['Rutabaga', 'Pirate', 'Darth Vader', 'Ninja']
|
|
36
|
+
}, order: [:name_1, :id, :name_2])
|
|
37
|
+
expect(@left.join(@right_many, how: :inner, on: [:id])).to eq(answer)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "performs an inner join of two dataframes that has many to one mapping" do
|
|
41
|
+
left_many = @right_many
|
|
42
|
+
right = @left
|
|
43
|
+
|
|
44
|
+
answer = DaruLite::DataFrame.new({
|
|
45
|
+
:name_2 => ['Pirate', 'Pirate', 'Pirate', 'Pirate'],
|
|
46
|
+
:id => [1,1,1,1],
|
|
47
|
+
:name_1 => ['Rutabaga', 'Pirate', 'Darth Vader', 'Ninja']
|
|
48
|
+
}, order: [:name_1, :id, :name_2])
|
|
49
|
+
expect(left_many.join(right, how: :inner, on: [:id])).to eq(answer)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "performs an inner join of two dataframes that has many to many mapping" do
|
|
53
|
+
@left[:id].recode! { |v| v == 2 ? 1 : v }
|
|
54
|
+
answer = DaruLite::DataFrame.new({
|
|
55
|
+
:name_1 => ['Pirate', 'Pirate', 'Pirate', 'Pirate', 'Monkey', 'Monkey', 'Monkey', 'Monkey'],
|
|
56
|
+
:id => [1,1,1,1,1,1,1,1],
|
|
57
|
+
:name_2 => ['Rutabaga', 'Pirate', 'Darth Vader', 'Ninja', 'Rutabaga', 'Pirate', 'Darth Vader', 'Ninja']
|
|
58
|
+
}, order: [:name_1, :id, :name_2])
|
|
59
|
+
expect(@left.join(@right_many, how: :inner, on: [:id])).to eq(answer)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "performs a full outer join" do
|
|
63
|
+
answer = DaruLite::DataFrame.new({
|
|
64
|
+
:id_1 => [nil,2,3,1,nil,4],
|
|
65
|
+
:name => ["Darth Vader", "Monkey", "Ninja", "Pirate", "Rutabaga", "Spaghetti"],
|
|
66
|
+
:id_2 => [3,nil,4,2,1,nil]
|
|
67
|
+
}, order: [:id_1, :name, :id_2])
|
|
68
|
+
expect(@left.join(@right, how: :outer, on: [:name])).to eq(answer)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "adds a left/right indicator" do
|
|
72
|
+
answer = DaruLite::DataFrame.new({
|
|
73
|
+
:id_1 => [nil,2,3,1,nil,4],
|
|
74
|
+
:name => ["Darth Vader", "Monkey", "Ninja", "Pirate", "Rutabaga", "Spaghetti"],
|
|
75
|
+
:id_2 => [3,nil,4,2,1,nil]
|
|
76
|
+
}, order: [:id_1, :name, :id_2])
|
|
77
|
+
|
|
78
|
+
outer = @left.join(@right, how: :outer, on: [:name], indicator: :my_indicator)
|
|
79
|
+
expect(outer[:my_indicator].to_a).to eq [:right_only, :left_only, :both, :both, :right_only, :left_only]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
it "performs a full outer join when the right join keys have nils" do
|
|
84
|
+
@right[:name].recode! { |v| v == 'Rutabaga' ? nil : v }
|
|
85
|
+
answer = DaruLite::DataFrame.new({
|
|
86
|
+
:id_1 => [nil, nil,2,3,1,4],
|
|
87
|
+
:name => [nil, "Darth Vader", "Monkey", "Ninja", "Pirate", "Spaghetti"],
|
|
88
|
+
:id_2 => [1,3,nil,4,2,nil]
|
|
89
|
+
}, order: [:id_1, :name, :id_2])
|
|
90
|
+
expect(@left.join(@right, how: :outer, on: [:name])).to eq(answer)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "performs a full outer join when the left join keys have nils" do
|
|
94
|
+
@left[:name].recode! { |v| v == 'Monkey' ? nil : v }
|
|
95
|
+
answer = DaruLite::DataFrame.new({
|
|
96
|
+
:id_1 => [2,nil,3,1,nil,4],
|
|
97
|
+
:name => [nil, "Darth Vader", "Ninja", "Pirate", "Rutabaga", "Spaghetti"],
|
|
98
|
+
:id_2 => [nil,3,4,2,1,nil]
|
|
99
|
+
}, order: [:id_1, :name, :id_2])
|
|
100
|
+
expect(@left.join(@right, how: :outer, on: [:name])).to eq(answer)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "performs a full outer join when both left and right join keys have nils" do
|
|
104
|
+
@left[:name].recode! { |v| v == 'Monkey' ? nil : v }
|
|
105
|
+
@right[:name].recode! { |v| v == 'Rutabaga' ? nil : v }
|
|
106
|
+
|
|
107
|
+
answer = DaruLite::DataFrame.new({
|
|
108
|
+
:id_1 => [nil,2,nil,3,1,4],
|
|
109
|
+
:name => [nil, nil, "Darth Vader", "Ninja", "Pirate", "Spaghetti"],
|
|
110
|
+
:id_2 => [1,nil,3,4,2,nil]
|
|
111
|
+
}, order: [:id_1, :name, :id_2])
|
|
112
|
+
expect(@left.join(@right, how: :outer, on: [:name])).to eq(answer)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "performs a left outer join" do
|
|
116
|
+
answer = DaruLite::DataFrame.new({
|
|
117
|
+
:id_1 => [2,3,1,4],
|
|
118
|
+
:name => ["Monkey", "Ninja", "Pirate", "Spaghetti"],
|
|
119
|
+
:id_2 => [nil,4,2,nil]
|
|
120
|
+
}, order: [:id_1, :name, :id_2])
|
|
121
|
+
expect(@left.join(@right, how: :left, on: [:name])).to eq(answer)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
it "performs a left join with an empty dataframe" do
|
|
125
|
+
|
|
126
|
+
answer = DaruLite::DataFrame.new({
|
|
127
|
+
:id_1 => [2,3,1,4],
|
|
128
|
+
:name => ["Monkey", "Ninja", "Pirate", "Spaghetti"],
|
|
129
|
+
:id_2 => [nil,nil,nil,nil]
|
|
130
|
+
}, order: [:id_1, :name, :id_2])
|
|
131
|
+
|
|
132
|
+
expect(@left.join(@empty, how: :left, on: [:name])).to eq(answer)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it "performs a right outer join" do
|
|
136
|
+
answer = DaruLite::DataFrame.new({
|
|
137
|
+
:id_1 => [nil,3,1,nil],
|
|
138
|
+
:name => ["Darth Vader", "Ninja", "Pirate", "Rutabaga"],
|
|
139
|
+
:id_2 => [3,4,2,1]
|
|
140
|
+
}, order: [:id_1, :name, :id_2])
|
|
141
|
+
expect(@left.join(@right, how: :right, on: [:name])).to eq(answer)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "doesn't convert false into nil when joining boolean values" do
|
|
145
|
+
left = DaruLite::DataFrame.new({ key: [1,2,3], left_value: [true, false, true] })
|
|
146
|
+
right = DaruLite::DataFrame.new({ key: [1,2,3], right_value: [true, false, true] })
|
|
147
|
+
|
|
148
|
+
answer = DaruLite::DataFrame.new({
|
|
149
|
+
left_value: [true, false, true],
|
|
150
|
+
key: [1,2,3],
|
|
151
|
+
right_value: [true, false, true]
|
|
152
|
+
}, order: [:left_value, :key, :right_value] )
|
|
153
|
+
|
|
154
|
+
expect(left.join(right, on: [:key], how: :inner)).to eq answer
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
it "raises if :on field are absent in one of dataframes" do
|
|
158
|
+
@right.vectors = DaruLite::Index.new [:id, :other_name]
|
|
159
|
+
expect { @left.join(@right, how: :right, on: [:name]) }.to \
|
|
160
|
+
raise_error(ArgumentError, /Both dataframes expected .* :name/)
|
|
161
|
+
|
|
162
|
+
expect { @left.join(@right, how: :right, on: [:other_name]) }.to \
|
|
163
|
+
raise_error(ArgumentError, /Both dataframes expected .* :other_name/)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
it "is able to join by several :on fields" do
|
|
167
|
+
@left.gender = ['m', 'f', 'm', nil]
|
|
168
|
+
@right.gender = ['m', 'm', nil, 'f']
|
|
169
|
+
|
|
170
|
+
answer = DaruLite::DataFrame.new({
|
|
171
|
+
id_1: [1],
|
|
172
|
+
name: ['Pirate'],
|
|
173
|
+
gender: ['m'],
|
|
174
|
+
id_2: [2]
|
|
175
|
+
}, order: [:id_1, :name, :gender, :id_2])
|
|
176
|
+
expect(@left.join(@right, how: :inner, on: [:name, :gender])).to eq(answer)
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
describe DaruLite::Core::Query::BoolArray do
|
|
2
|
+
before do
|
|
3
|
+
@klass = DaruLite::Core::Query::BoolArray
|
|
4
|
+
@left = @klass.new([true, true, true, false, false, true])
|
|
5
|
+
@right = @klass.new([false, false, false, false, true, false])
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
context "#&" do
|
|
9
|
+
it "computes and logic of each element in the array" do
|
|
10
|
+
expect(@left & @right).to eq(
|
|
11
|
+
@klass.new([false, false, false, false, false, false]))
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
context "#|" do
|
|
16
|
+
it "computes or logic of each element in arrays" do
|
|
17
|
+
expect(@left | @right).to eq(
|
|
18
|
+
@klass.new([true, true, true, false, true, true]))
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
context "#!" do
|
|
23
|
+
it "computes not logic of each element" do
|
|
24
|
+
expect(!@left).to eq(
|
|
25
|
+
@klass.new([false, false, false, true, true, false])
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
context '#inspect' do
|
|
31
|
+
it 'is reasonable' do
|
|
32
|
+
expect(@left.inspect).to eq "#<DaruLite::Core::Query::BoolArray:#{@left.object_id} bool_arry=[true, true, true, false, false, true]>"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
describe "Arel-like syntax" do
|
|
38
|
+
describe "comparison operators" do
|
|
39
|
+
describe DaruLite::Vector do
|
|
40
|
+
describe "non-categorical type" do
|
|
41
|
+
before do
|
|
42
|
+
@vector = DaruLite::Vector.new([23,51,1214,352,32,11])
|
|
43
|
+
@comparator = DaruLite::Vector.new([45,22,1214,55,32,9])
|
|
44
|
+
@klass = DaruLite::Core::Query::BoolArray
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
context "#eq" do
|
|
48
|
+
it "accepts scalar value" do
|
|
49
|
+
expect(@vector.eq(352)).to eq(
|
|
50
|
+
@klass.new([false,false,false,true,false,false]))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "accepts vector and compares corrensponding elements" do
|
|
54
|
+
expect(@vector.eq(@comparator)).to eq(
|
|
55
|
+
@klass.new([false,false,true,false,true,false]))
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
context "#not_eq" do
|
|
60
|
+
it "accepts scalar value" do
|
|
61
|
+
expect(@vector.not_eq(51)).to eq(
|
|
62
|
+
@klass.new([true, false, true, true, true, true]))
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "accepts vector and compares corrensponding elements" do
|
|
66
|
+
expect(@vector.not_eq(@comparator)).to eq(
|
|
67
|
+
@klass.new([true, true, false, true, false, true]))
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
context "#lt" do
|
|
72
|
+
it "accepts scalar value" do
|
|
73
|
+
expect(@vector.lt(51)).to eq(
|
|
74
|
+
@klass.new([true, false, false, false, true, true]))
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "accepts vector and compares corrensponding elements" do
|
|
78
|
+
expect(@vector.lt(@comparator)).to eq(
|
|
79
|
+
@klass.new([true,false,false,false,false,false]))
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
context "#lteq" do
|
|
84
|
+
it "accepts scalar value" do
|
|
85
|
+
expect(@vector.lteq(51)).to eq(
|
|
86
|
+
@klass.new([true, true, false, false, true, true]))
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it "accepts vector and compares corrensponding elements" do
|
|
90
|
+
expect(@vector.lteq(@comparator)).to eq(
|
|
91
|
+
@klass.new([true,false,true,false,true,false]))
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
context "#mt" do
|
|
96
|
+
it "accepts scalar value" do
|
|
97
|
+
expect(@vector.mt(51)).to eq(
|
|
98
|
+
@klass.new([false, false, true, true, false, false]))
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "accepts vector and compares corrensponding elements" do
|
|
102
|
+
expect(@vector.mt(@comparator)).to eq(
|
|
103
|
+
@klass.new([false,true,false,true,false,true]))
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
context "#mteq" do
|
|
108
|
+
it "accepts scalar value" do
|
|
109
|
+
expect(@vector.mteq(51)).to eq(
|
|
110
|
+
@klass.new([false, true, true, true, false, false]))
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "accepts vector and compares corrensponding elements" do
|
|
114
|
+
expect(@vector.mteq(@comparator)).to eq(
|
|
115
|
+
@klass.new([false,true,true,true,true,true]))
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
context "#in" do
|
|
120
|
+
it "checks if any of elements in the arg are present in the vector" do
|
|
121
|
+
expect(@vector.in([23,55,1,33,32])).to eq(
|
|
122
|
+
@klass.new([true, false, false, false, true, false]))
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
describe "categorical type" do
|
|
128
|
+
let(:dv) { DaruLite::Vector.new ['e', 'd', 'd', 'x', 'x'],
|
|
129
|
+
categories: ['a', 'x', 'c', 'd', 'e'], type: :category }
|
|
130
|
+
let(:comp) { DaruLite::Vector.new ['a', 'd', 'x', 'e', 'x'],
|
|
131
|
+
categories: ['a', 'x', 'c', 'd', 'e'], type: :category }
|
|
132
|
+
let(:query_bool_class) { DaruLite::Core::Query::BoolArray }
|
|
133
|
+
|
|
134
|
+
context "#eq" do
|
|
135
|
+
context "scalar" do
|
|
136
|
+
subject { dv.eq 'd' }
|
|
137
|
+
|
|
138
|
+
it { is_expected.to be_a query_bool_class }
|
|
139
|
+
its(:to_a) { is_expected.to eq [false, true, true, false, false] }
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
context "vector" do
|
|
143
|
+
subject { dv.eq comp }
|
|
144
|
+
|
|
145
|
+
it { is_expected.to be_a query_bool_class }
|
|
146
|
+
its(:to_a) { is_expected.to eq [false, true, false, false, true] }
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
context "#not_eq" do
|
|
151
|
+
context "scalar" do
|
|
152
|
+
subject { dv.not_eq 'd' }
|
|
153
|
+
|
|
154
|
+
it { is_expected.to be_a query_bool_class }
|
|
155
|
+
its(:to_a) { is_expected.to eq [true, false, false, true, true] }
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
context "vector" do
|
|
159
|
+
subject { dv.not_eq comp }
|
|
160
|
+
|
|
161
|
+
it { is_expected.to be_a query_bool_class }
|
|
162
|
+
its(:to_a) { is_expected.to eq [true, false, true, true, false] }
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
context "#lt" do
|
|
167
|
+
context "scalar" do
|
|
168
|
+
subject { dv.lt 'd' }
|
|
169
|
+
|
|
170
|
+
it { is_expected.to be_a query_bool_class }
|
|
171
|
+
its(:to_a) { is_expected.to eq [false, false, false, true, true] }
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
context "vector" do
|
|
175
|
+
subject { dv.lt comp }
|
|
176
|
+
|
|
177
|
+
it { is_expected.to be_a query_bool_class }
|
|
178
|
+
its(:to_a) { is_expected.to eq [false, false, false, true, false] }
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
context "#lteq" do
|
|
183
|
+
context "scalar" do
|
|
184
|
+
subject { dv.lteq 'd' }
|
|
185
|
+
|
|
186
|
+
it { is_expected.to be_a query_bool_class }
|
|
187
|
+
its(:to_a) { is_expected.to eq [false, true, true, true, true] }
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
context "vector" do
|
|
191
|
+
subject { dv.lteq comp }
|
|
192
|
+
|
|
193
|
+
it { is_expected.to be_a query_bool_class }
|
|
194
|
+
its(:to_a) { is_expected.to eq [false, true, false, true, true] }
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
context "#mt" do
|
|
199
|
+
context "scalar" do
|
|
200
|
+
subject { dv.mt 'd' }
|
|
201
|
+
|
|
202
|
+
it { is_expected.to be_a query_bool_class }
|
|
203
|
+
its(:to_a) { is_expected.to eq [true, false, false, false, false] }
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
context "vector" do
|
|
207
|
+
subject { dv.mt comp }
|
|
208
|
+
|
|
209
|
+
it { is_expected.to be_a query_bool_class }
|
|
210
|
+
its(:to_a) { is_expected.to eq [true, false, true, false, false] }
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
context "#mteq" do
|
|
215
|
+
context "scalar" do
|
|
216
|
+
subject { dv.mteq 'd' }
|
|
217
|
+
|
|
218
|
+
it { is_expected.to be_a query_bool_class }
|
|
219
|
+
its(:to_a) { is_expected.to eq [true, true, true, false, false] }
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
context "vector" do
|
|
223
|
+
subject { dv.mteq comp }
|
|
224
|
+
|
|
225
|
+
it { is_expected.to be_a query_bool_class }
|
|
226
|
+
its(:to_a) { is_expected.to eq [true, true, true, false, true] }
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# context "#in" do
|
|
231
|
+
# subject { dv.in ['b', 'd'] }
|
|
232
|
+
# it { is_expected.to be_a query_bool_class }
|
|
233
|
+
# its(:to_a) { is_expected.to eq [false, true, true, true, true] }
|
|
234
|
+
# end
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
describe "where clause" do
|
|
240
|
+
context DaruLite::DataFrame do
|
|
241
|
+
before do
|
|
242
|
+
@df = DaruLite::DataFrame.new({
|
|
243
|
+
number: [1,2,3,4,5,6,Float::NAN],
|
|
244
|
+
sym: [:one, :two, :three, :four, :five, :six, :seven],
|
|
245
|
+
names: ['sameer', 'john', 'james', 'omisha', 'priyanka', 'shravan',nil]
|
|
246
|
+
})
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
it "accepts simple single eq statement" do
|
|
250
|
+
answer = DaruLite::DataFrame.new({
|
|
251
|
+
number: [4],
|
|
252
|
+
sym: [:four],
|
|
253
|
+
names: ['omisha']
|
|
254
|
+
}, index: DaruLite::Index.new([3])
|
|
255
|
+
)
|
|
256
|
+
expect(@df.where(@df[:number].eq(4))).to eq(answer)
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
it "accepts somewhat complex comparison operator chaining" do
|
|
260
|
+
answer = DaruLite::DataFrame.new({
|
|
261
|
+
number: [3,4],
|
|
262
|
+
sym: [:three, :four],
|
|
263
|
+
names: ['james', 'omisha']
|
|
264
|
+
}, index: DaruLite::Index.new([2,3]))
|
|
265
|
+
expect(
|
|
266
|
+
@df.where (@df[:names].eq('james') | @df[:sym].eq(:four))
|
|
267
|
+
).to eq(answer)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
let(:dv) { DaruLite::Vector.new([1,11,32,Float::NAN,nil]) }
|
|
271
|
+
it "handles empty data" do
|
|
272
|
+
expect(dv.where(dv.lt(14))).to eq(DaruLite::Vector.new([1,11]))
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
it "does not give SystemStackError" do
|
|
276
|
+
v = DaruLite::Vector.new [1]*300_000
|
|
277
|
+
expect { v.where v.eq(1) }.not_to raise_error
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
context DaruLite::Vector do
|
|
282
|
+
context "non-categorical type" do
|
|
283
|
+
before do
|
|
284
|
+
@vector = DaruLite::Vector.new([2,5,1,22,51,4,nil,Float::NAN])
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
it "accepts a simple single statement" do
|
|
288
|
+
expect(@vector.where(@vector.lt(10))).to eq(
|
|
289
|
+
DaruLite::Vector.new([2,5,1,4], index: DaruLite::Index.new([0,1,2,5])))
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
it "accepts somewhat complex operator chaining" do
|
|
293
|
+
expect(@vector.where((@vector.lt(6) | @vector.eq(51)))).to eq(
|
|
294
|
+
DaruLite::Vector.new([2,5,1,51,4], index: DaruLite::Index.new([0,1,2,4,5])))
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
context "categorical type" do
|
|
299
|
+
let(:dv) { DaruLite::Vector.new ['a', 'c', 'x', 'x', 'c'],
|
|
300
|
+
categories: ['a', 'x', 'c'], type: :category }
|
|
301
|
+
|
|
302
|
+
context "simple single statement" do
|
|
303
|
+
subject { dv.where(dv.lt('x')) }
|
|
304
|
+
|
|
305
|
+
it { is_expected.to be_a DaruLite::Vector }
|
|
306
|
+
its(:type) { is_expected.to eq :category }
|
|
307
|
+
its(:to_a) { is_expected.to eq ['a'] }
|
|
308
|
+
its(:'index.to_a') { is_expected.to eq [0] }
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
context "complex operator chaining" do
|
|
312
|
+
subject { dv.where((dv.lt('x') | dv.eq('c'))) }
|
|
313
|
+
|
|
314
|
+
it { is_expected.to be_a DaruLite::Vector }
|
|
315
|
+
its(:type) { is_expected.to eq :category }
|
|
316
|
+
its(:to_a) { is_expected.to eq ['a', 'c', 'c'] }
|
|
317
|
+
its(:'index.to_a') { is_expected.to eq [0, 1, 4] }
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
context "preserve categories" do
|
|
321
|
+
subject { dv.where((dv.lt('x') | dv.eq('c'))) }
|
|
322
|
+
|
|
323
|
+
it { is_expected.to be_a DaruLite::Vector }
|
|
324
|
+
its(:type) { is_expected.to eq :category }
|
|
325
|
+
its(:to_a) { is_expected.to eq ['a', 'c', 'c'] }
|
|
326
|
+
its(:'index.to_a') { is_expected.to eq [0, 1, 4] }
|
|
327
|
+
its(:categories) { is_expected.to eq ['a', 'x', 'c'] }
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
it "preserves name" do
|
|
332
|
+
named_vector = DaruLite::Vector.new([1,2,3], name: 'named')
|
|
333
|
+
expect(named_vector.where(named_vector.lteq(2)).name).to eq('named')
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
describe "apply_where" do
|
|
339
|
+
context "matches regexp with block input" do
|
|
340
|
+
subject { dv.apply_where(dv.match /weeks/) { |x| "#{x.split.first.to_i * 7} days" } }
|
|
341
|
+
|
|
342
|
+
let(:dv) { DaruLite::Vector.new ['3 days', '5 weeks', '2 weeks'] }
|
|
343
|
+
|
|
344
|
+
it { is_expected.to eq(DaruLite::Vector.new ['3 days', '35 days', '14 days']) }
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe '#error' do
|
|
4
|
+
context 'by default' do
|
|
5
|
+
it { expect { DaruLite.error('test') }.to output("test\n").to_stderr_from_any_process }
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
context 'when set to nil' do
|
|
9
|
+
before { DaruLite.error_stream = nil }
|
|
10
|
+
it { expect { DaruLite.error('test') }.not_to output('test').to_stderr_from_any_process }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
context 'when set to instance of custom class' do
|
|
14
|
+
let(:custom_stream) { double(puts: nil) }
|
|
15
|
+
before { DaruLite.error_stream = custom_stream }
|
|
16
|
+
|
|
17
|
+
it 'calls puts' do
|
|
18
|
+
expect { DaruLite.error('test') }.not_to output('test').to_stderr_from_any_process
|
|
19
|
+
expect(custom_stream).to have_received(:puts).with('test')
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|