daru 0.1.3.1 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rspec +2 -1
  4. data/.rspec_formatter.rb +33 -0
  5. data/.rubocop.yml +26 -2
  6. data/History.md +38 -0
  7. data/README.md +22 -13
  8. data/Rakefile +50 -2
  9. data/benchmarks/csv_reading.rb +22 -0
  10. data/daru.gemspec +9 -2
  11. data/lib/daru.rb +36 -4
  12. data/lib/daru/accessors/array_wrapper.rb +6 -1
  13. data/lib/daru/accessors/dataframe_by_row.rb +10 -2
  14. data/lib/daru/accessors/gsl_wrapper.rb +1 -3
  15. data/lib/daru/accessors/nmatrix_wrapper.rb +9 -0
  16. data/lib/daru/category.rb +935 -0
  17. data/lib/daru/core/group_by.rb +29 -38
  18. data/lib/daru/core/merge.rb +186 -145
  19. data/lib/daru/core/query.rb +22 -11
  20. data/lib/daru/dataframe.rb +976 -885
  21. data/lib/daru/date_time/index.rb +166 -166
  22. data/lib/daru/date_time/offsets.rb +66 -77
  23. data/lib/daru/formatters/table.rb +54 -0
  24. data/lib/daru/helpers/array.rb +40 -0
  25. data/lib/daru/index.rb +476 -73
  26. data/lib/daru/io/io.rb +66 -45
  27. data/lib/daru/io/sql_data_source.rb +33 -62
  28. data/lib/daru/iruby/helpers.rb +38 -0
  29. data/lib/daru/iruby/templates/dataframe.html.erb +52 -0
  30. data/lib/daru/iruby/templates/dataframe_mi.html.erb +58 -0
  31. data/lib/daru/iruby/templates/multi_index.html.erb +12 -0
  32. data/lib/daru/iruby/templates/vector.html.erb +27 -0
  33. data/lib/daru/iruby/templates/vector_mi.html.erb +36 -0
  34. data/lib/daru/maths/arithmetic/dataframe.rb +16 -18
  35. data/lib/daru/maths/arithmetic/vector.rb +4 -6
  36. data/lib/daru/maths/statistics/dataframe.rb +8 -15
  37. data/lib/daru/maths/statistics/vector.rb +120 -98
  38. data/lib/daru/monkeys.rb +12 -40
  39. data/lib/daru/plotting/gruff.rb +3 -0
  40. data/lib/daru/plotting/gruff/category.rb +49 -0
  41. data/lib/daru/plotting/gruff/dataframe.rb +91 -0
  42. data/lib/daru/plotting/gruff/vector.rb +57 -0
  43. data/lib/daru/plotting/nyaplot.rb +3 -0
  44. data/lib/daru/plotting/nyaplot/category.rb +34 -0
  45. data/lib/daru/plotting/nyaplot/dataframe.rb +187 -0
  46. data/lib/daru/plotting/nyaplot/vector.rb +46 -0
  47. data/lib/daru/vector.rb +694 -421
  48. data/lib/daru/version.rb +1 -1
  49. data/profile/_base.rb +23 -0
  50. data/profile/df_to_a.rb +10 -0
  51. data/profile/filter.rb +13 -0
  52. data/profile/joining.rb +13 -0
  53. data/profile/sorting.rb +12 -0
  54. data/profile/vector_each_with_index.rb +9 -0
  55. data/spec/accessors/wrappers_spec.rb +2 -4
  56. data/spec/categorical_spec.rb +1734 -0
  57. data/spec/core/group_by_spec.rb +52 -2
  58. data/spec/core/merge_spec.rb +63 -2
  59. data/spec/core/query_spec.rb +236 -80
  60. data/spec/dataframe_spec.rb +1373 -79
  61. data/spec/date_time/data_spec.rb +3 -5
  62. data/spec/date_time/index_spec.rb +154 -17
  63. data/spec/date_time/offsets_spec.rb +3 -4
  64. data/spec/fixtures/empties.dat +2 -0
  65. data/spec/fixtures/strings.dat +2 -0
  66. data/spec/formatters/table_formatter_spec.rb +99 -0
  67. data/spec/helpers_spec.rb +8 -0
  68. data/spec/index/categorical_index_spec.rb +168 -0
  69. data/spec/index/index_spec.rb +283 -0
  70. data/spec/index/multi_index_spec.rb +570 -0
  71. data/spec/io/io_spec.rb +31 -4
  72. data/spec/io/sql_data_source_spec.rb +0 -1
  73. data/spec/iruby/dataframe_spec.rb +172 -0
  74. data/spec/iruby/helpers_spec.rb +49 -0
  75. data/spec/iruby/multi_index_spec.rb +37 -0
  76. data/spec/iruby/vector_spec.rb +107 -0
  77. data/spec/math/arithmetic/dataframe_spec.rb +71 -13
  78. data/spec/math/arithmetic/vector_spec.rb +8 -10
  79. data/spec/math/statistics/dataframe_spec.rb +3 -5
  80. data/spec/math/statistics/vector_spec.rb +45 -55
  81. data/spec/monkeys_spec.rb +32 -9
  82. data/spec/plotting/dataframe_spec.rb +386 -0
  83. data/spec/plotting/vector_spec.rb +230 -0
  84. data/spec/shared/vector_display_spec.rb +215 -0
  85. data/spec/spec_helper.rb +23 -0
  86. data/spec/vector_spec.rb +905 -138
  87. metadata +143 -11
  88. data/.rubocop_todo.yml +0 -44
  89. data/lib/daru/plotting/dataframe.rb +0 -104
  90. data/lib/daru/plotting/vector.rb +0 -38
  91. data/spec/daru_spec.rb +0 -58
  92. data/spec/index_spec.rb +0 -375
@@ -1,5 +1,3 @@
1
- require 'spec_helper.rb'
2
-
3
1
  describe Daru::Core::GroupBy do
4
2
  before do
5
3
  @df = Daru::DataFrame.new({
@@ -140,6 +138,44 @@ describe Daru::Core::GroupBy do
140
138
  end
141
139
  end
142
140
 
141
+ context '#each_group' do
142
+ it 'enumerates groups' do
143
+ ret = []
144
+ @dl_group.each_group { |g| ret << g }
145
+ expect(ret.count).to eq 6
146
+ expect(ret).to all be_a(Daru::DataFrame)
147
+ expect(ret.first).to eq(Daru::DataFrame.new({
148
+ a: ['bar'],
149
+ b: ['one'],
150
+ c: [2],
151
+ d: [22]
152
+ }, index: [1]
153
+ ))
154
+ end
155
+ end
156
+
157
+ context '#first' do
158
+ it 'gets the first row from each group' do
159
+ expect(@dl_group.first).to eq(Daru::DataFrame.new({
160
+ a: %w{bar bar bar foo foo foo },
161
+ b: %w{one three two one three two },
162
+ c: [2 ,1 ,6 ,1 ,8 ,3 ],
163
+ d: [22 ,44 ,66 ,11 ,88 ,33 ]
164
+ }, index: [1,3,5,0,7,2]))
165
+ end
166
+ end
167
+
168
+ context '#last' do
169
+ it 'gets the last row from each group' do
170
+ expect(@dl_group.last).to eq(Daru::DataFrame.new({
171
+ a: %w{bar bar bar foo foo foo },
172
+ b: %w{one three two one three two },
173
+ c: [2 ,1 ,6 ,3 ,8 ,3 ],
174
+ d: [22 ,44 ,66 ,77 ,88 ,55 ]
175
+ }, index: [1,3,5,6,7,4]))
176
+ end
177
+ end
178
+
143
179
  context "#aggregate" do
144
180
  pending
145
181
  end
@@ -191,6 +227,14 @@ describe Daru::Core::GroupBy do
191
227
  end
192
228
  end
193
229
 
230
+ [:median, :std, :max, :min].each do |numeric_method|
231
+ it "works somehow" do
232
+ expect(@sl_group.send(numeric_method).index).to eq @sl_index
233
+ expect(@dl_group.send(numeric_method).index).to eq @dl_multi_index
234
+ expect(@tl_group.send(numeric_method).index).to eq @tl_multi_index
235
+ end
236
+ end
237
+
194
238
  context "#product" do
195
239
  it "calculates product for single layer groups" do
196
240
  # TODO
@@ -351,5 +395,11 @@ describe Daru::Core::GroupBy do
351
395
  string_concat = lambda { |result, row| result += row[:b] }
352
396
  expect(@sl_group.reduce('', &string_concat)).to eq(Daru::Vector.new(['onethreetwo', 'onetwotwoonethree'], index: @sl_index))
353
397
  end
398
+
399
+ it "works with multi-indexes" do
400
+ string_concat = lambda { |result, row| result += row[:b] }
401
+ expect(@dl_group.reduce('', &string_concat)).to eq \
402
+ Daru::Vector.new(['one', 'three', 'two', 'oneone', 'three', 'twotwo'], index: @dl_multi_index)
403
+ end
354
404
  end
355
405
  end
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
1
  describe Daru::DataFrame do
4
2
  context "#join" do
5
3
  before do
@@ -39,6 +37,16 @@ describe Daru::DataFrame do
39
37
  expect(@left.join(@right_many, how: :inner, on: [:id])).to eq(answer)
40
38
  end
41
39
 
40
+ it "performs an inner join of two dataframes that has many to many mapping" do
41
+ @left[:id].recode! { |v| v == 2 ? 1 : v }
42
+ answer = Daru::DataFrame.new({
43
+ :name_1 => ['Pirate', 'Pirate', 'Pirate', 'Pirate', 'Monkey', 'Monkey', 'Monkey', 'Monkey'],
44
+ :id => [1,1,1,1,1,1,1,1],
45
+ :name_2 => ['Rutabaga', 'Pirate', 'Darth Vader', 'Ninja', 'Rutabaga', 'Pirate', 'Darth Vader', 'Ninja']
46
+ }, order: [:name_1, :id, :name_2])
47
+ expect(@left.join(@right_many, how: :inner, on: [:id])).to eq(answer)
48
+ end
49
+
42
50
  it "performs a full outer join" do
43
51
  answer = Daru::DataFrame.new({
44
52
  :id_1 => [nil,2,3,1,nil,4],
@@ -48,6 +56,38 @@ describe Daru::DataFrame do
48
56
  expect(@left.join(@right, how: :outer, on: [:name])).to eq(answer)
49
57
  end
50
58
 
59
+ it "performs a full outer join when the right join keys have nils" do
60
+ @right[:name].recode! { |v| v == 'Rutabaga' ? nil : v }
61
+ answer = Daru::DataFrame.new({
62
+ :id_1 => [nil, nil,2,3,1,4],
63
+ :name => [nil, "Darth Vader", "Monkey", "Ninja", "Pirate", "Spaghetti"],
64
+ :id_2 => [1,3,nil,4,2,nil]
65
+ }, order: [:id_1, :name, :id_2])
66
+ expect(@left.join(@right, how: :outer, on: [:name])).to eq(answer)
67
+ end
68
+
69
+ it "performs a full outer join when the left join keys have nils" do
70
+ @left[:name].recode! { |v| v == 'Monkey' ? nil : v }
71
+ answer = Daru::DataFrame.new({
72
+ :id_1 => [2,nil,3,1,nil,4],
73
+ :name => [nil, "Darth Vader", "Ninja", "Pirate", "Rutabaga", "Spaghetti"],
74
+ :id_2 => [nil,3,4,2,1,nil]
75
+ }, order: [:id_1, :name, :id_2])
76
+ expect(@left.join(@right, how: :outer, on: [:name])).to eq(answer)
77
+ end
78
+
79
+ it "performs a full outer join when both left and right join keys have nils" do
80
+ @left[:name].recode! { |v| v == 'Monkey' ? nil : v }
81
+ @right[:name].recode! { |v| v == 'Rutabaga' ? nil : v }
82
+
83
+ answer = Daru::DataFrame.new({
84
+ :id_1 => [nil,2,nil,3,1,4],
85
+ :name => [nil, nil, "Darth Vader", "Ninja", "Pirate", "Spaghetti"],
86
+ :id_2 => [1,nil,3,4,2,nil]
87
+ }, order: [:id_1, :name, :id_2])
88
+ expect(@left.join(@right, how: :outer, on: [:name])).to eq(answer)
89
+ end
90
+
51
91
  it "performs a left outer join", focus: true do
52
92
  answer = Daru::DataFrame.new({
53
93
  :id_1 => [2,3,1,4],
@@ -77,5 +117,26 @@ describe Daru::DataFrame do
77
117
  expect(@left.join(@right, how: :right, on: [:name])).to eq(answer)
78
118
  end
79
119
 
120
+ it "raises if :on field are absent in one of dataframes" do
121
+ @right.vectors = [:id, :other_name]
122
+ expect { @left.join(@right, how: :right, on: [:name]) }.to \
123
+ raise_error(ArgumentError, /Both dataframes expected .* :name/)
124
+
125
+ expect { @left.join(@right, how: :right, on: [:other_name]) }.to \
126
+ raise_error(ArgumentError, /Both dataframes expected .* :other_name/)
127
+ end
128
+
129
+ it "is able to join by several :on fields" do
130
+ @left.gender = ['m', 'f', 'm', nil]
131
+ @right.gender = ['m', 'm', nil, 'f']
132
+
133
+ answer = Daru::DataFrame.new({
134
+ id_1: [1],
135
+ name: ['Pirate'],
136
+ gender: ['m'],
137
+ id_2: [2]
138
+ }, order: [:id_1, :name, :gender, :id_2])
139
+ expect(@left.join(@right, how: :inner, on: [:name, :gender])).to eq(answer)
140
+ end
80
141
  end
81
142
  end
@@ -1,8 +1,6 @@
1
- require 'spec_helper'
2
-
3
1
  describe Daru::Core::Query::BoolArray do
4
2
  before do
5
- @klass = Daru::Core::Query::BoolArray
3
+ @klass = Daru::Core::Query::BoolArray
6
4
  @left = @klass.new([true, true, true, false, false, true])
7
5
  @right = @klass.new([false, false, false, false, true, false])
8
6
  end
@@ -28,94 +26,212 @@ describe Daru::Core::Query::BoolArray do
28
26
  )
29
27
  end
30
28
  end
29
+
30
+ context '#inspect' do
31
+ it 'is reasonable' do
32
+ expect(@left.inspect).to eq "#<Daru::Core::Query::BoolArray:#{@left.object_id} bool_arry=[true, true, true, false, false, true]>"
33
+ end
34
+ end
31
35
  end
32
36
 
33
37
  describe "Arel-like syntax" do
34
38
  describe "comparison operators" do
35
39
  describe Daru::Vector do
36
- before do
37
- @vector = Daru::Vector.new([23,51,1214,352,32,11])
38
- @comparator = Daru::Vector.new([45,22,1214,55,32,9])
39
- @klass = Daru::Core::Query::BoolArray
40
- end
41
-
42
- context "#eq" do
43
- it "accepts scalar value" do
44
- expect(@vector.eq(352)).to eq(
45
- @klass.new([false,false,false,true,false,false]))
40
+ describe "non-categorical type" do
41
+ before do
42
+ @vector = Daru::Vector.new([23,51,1214,352,32,11])
43
+ @comparator = Daru::Vector.new([45,22,1214,55,32,9])
44
+ @klass = Daru::Core::Query::BoolArray
46
45
  end
47
-
48
- it "accepts vector and compares corrensponding elements" do
49
- expect(@vector.eq(@comparator)).to eq(
50
- @klass.new([false,false,true,false,true,false]))
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
51
57
  end
52
- end
53
-
54
- context "#not_eq" do
55
- it "accepts scalar value" do
56
- expect(@vector.not_eq(51)).to eq(
57
- @klass.new([true, false, true, true, true, true]))
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
58
69
  end
59
-
60
- it "accepts vector and compares corrensponding elements" do
61
- expect(@vector.not_eq(@comparator)).to eq(
62
- @klass.new([true, true, false, true, false, true]))
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
63
81
  end
64
- end
65
-
66
- context "#lt" do
67
- it "accepts scalar value" do
68
- expect(@vector.lt(51)).to eq(
69
- @klass.new([true, false, false, false, true, true]))
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
70
93
  end
71
-
72
- it "accepts vector and compares corrensponding elements" do
73
- expect(@vector.lt(@comparator)).to eq(
74
- @klass.new([true,false,false,false,false,false]))
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
75
105
  end
76
- end
77
-
78
- context "#lteq" do
79
- it "accepts scalar value" do
80
- expect(@vector.lteq(51)).to eq(
81
- @klass.new([true, true, false, false, true, true]))
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
82
117
  end
83
-
84
- it "accepts vector and compares corrensponding elements" do
85
- expect(@vector.lteq(@comparator)).to eq(
86
- @klass.new([true,false,true,false,true,false]))
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
87
124
  end
88
125
  end
126
+
127
+ describe "categorical type" do
128
+ let(:dv) { Daru::Vector.new ['e', 'd', 'd', 'x', 'x'],
129
+ categories: ['a', 'x', 'c', 'd', 'e'], type: :category }
130
+ let(:comp) { Daru::Vector.new ['a', 'd', 'x', 'e', 'x'],
131
+ categories: ['a', 'x', 'c', 'd', 'e'], type: :category }
132
+ let(:query_bool_class) { Daru::Core::Query::BoolArray }
89
133
 
90
- context "#mt" do
91
- it "accepts scalar value" do
92
- expect(@vector.mt(51)).to eq(
93
- @klass.new([false, false, true, true, false, false]))
94
- end
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
95
141
 
96
- it "accepts vector and compares corrensponding elements" do
97
- expect(@vector.mt(@comparator)).to eq(
98
- @klass.new([false,true,false,true,false,true]))
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
99
148
  end
100
- end
101
-
102
- context "#mteq" do
103
- it "accepts scalar value" do
104
- expect(@vector.mteq(51)).to eq(
105
- @klass.new([false, true, true, true, false, false]))
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
106
164
  end
107
-
108
- it "accepts vector and compares corrensponding elements" do
109
- expect(@vector.mteq(@comparator)).to eq(
110
- @klass.new([false,true,true,true,true,true]))
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
111
180
  end
112
- end
113
-
114
- context "#in" do
115
- it "checks if any of elements in the arg are present in the vector" do
116
- expect(@vector.in([23,55,1,33,32])).to eq(
117
- @klass.new([true, false, false, false, true, false]))
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
118
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
119
235
  end
120
236
  end
121
237
  end
@@ -153,18 +269,58 @@ describe "Arel-like syntax" do
153
269
  end
154
270
 
155
271
  context Daru::Vector do
156
- before do
157
- @vector = Daru::Vector.new([2,5,1,22,51,4])
272
+ context "non-categorical type" do
273
+ before do
274
+ @vector = Daru::Vector.new([2,5,1,22,51,4])
275
+ end
276
+
277
+ it "accepts a simple single statement" do
278
+ expect(@vector.where(@vector.lt(10))).to eq(
279
+ Daru::Vector.new([2,5,1,4], index: Daru::Index.new([0,1,2,5])))
280
+ end
281
+
282
+ it "accepts somewhat complex operator chaining" do
283
+ expect(@vector.where((@vector.lt(6) | @vector.eq(51)))).to eq(
284
+ Daru::Vector.new([2,5,1,51,4], index: Daru::Index.new([0,1,2,4,5])))
285
+ end
158
286
  end
159
-
160
- it "accepts a simple single statement" do
161
- expect(@vector.where(@vector.lt(10))).to eq(
162
- Daru::Vector.new([2,5,1,4], index: Daru::Index.new([0,1,2,5])))
287
+
288
+ context "categorical type" do
289
+ let(:dv) { Daru::Vector.new ['a', 'c', 'x', 'x', 'c'],
290
+ categories: ['a', 'x', 'c'], type: :category }
291
+
292
+ context "simple single statement" do
293
+ subject { dv.where(dv.lt('x')) }
294
+
295
+ it { is_expected.to be_a Daru::Vector }
296
+ its(:type) { is_expected.to eq :category }
297
+ its(:to_a) { is_expected.to eq ['a'] }
298
+ its(:'index.to_a') { is_expected.to eq [0] }
299
+ end
300
+
301
+ context "complex operator chaining" do
302
+ subject { dv.where((dv.lt('x') | dv.eq('c'))) }
303
+
304
+ it { is_expected.to be_a Daru::Vector }
305
+ its(:type) { is_expected.to eq :category }
306
+ its(:to_a) { is_expected.to eq ['a', 'c', 'c'] }
307
+ its(:'index.to_a') { is_expected.to eq [0, 1, 4] }
308
+ end
309
+
310
+ context "preserve categories" do
311
+ subject { dv.where((dv.lt('x') | dv.eq('c'))) }
312
+
313
+ it { is_expected.to be_a Daru::Vector }
314
+ its(:type) { is_expected.to eq :category }
315
+ its(:to_a) { is_expected.to eq ['a', 'c', 'c'] }
316
+ its(:'index.to_a') { is_expected.to eq [0, 1, 4] }
317
+ its(:categories) { is_expected.to eq ['a', 'x', 'c'] }
318
+ end
163
319
  end
164
320
 
165
- it "accepts somewhat complex operator chaining" do
166
- expect(@vector.where((@vector.lt(6) | @vector.eq(51)))).to eq(
167
- Daru::Vector.new([2,5,1,51,4], index: Daru::Index.new([0,1,2,4,5])))
321
+ it "preserves name" do
322
+ named_vector = Daru::Vector.new([1,2,3], name: 'named')
323
+ expect(named_vector.where(named_vector.lteq(2)).name).to eq('named')
168
324
  end
169
325
  end
170
326
  end