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.
Files changed (149) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE.md +18 -0
  3. data/.github/workflows/ci.yml +33 -0
  4. data/.gitignore +10 -0
  5. data/.rspec +2 -0
  6. data/.rubocop.yml +27 -0
  7. data/.rubocop_todo.yml +137 -0
  8. data/CONTRIBUTING.md +47 -0
  9. data/Gemfile +2 -0
  10. data/History.md +4 -0
  11. data/LICENSE +24 -0
  12. data/README.md +218 -0
  13. data/Rakefile +69 -0
  14. data/ReleasePolicy.md +20 -0
  15. data/benchmarks/TradeoffData.csv +65 -0
  16. data/benchmarks/csv_reading.rb +22 -0
  17. data/benchmarks/dataframe_creation.rb +39 -0
  18. data/benchmarks/db_loading.rb +34 -0
  19. data/benchmarks/duplicating.rb +45 -0
  20. data/benchmarks/group_by.rb +32 -0
  21. data/benchmarks/joining.rb +52 -0
  22. data/benchmarks/row_access.rb +41 -0
  23. data/benchmarks/row_assign.rb +36 -0
  24. data/benchmarks/sorting.rb +51 -0
  25. data/benchmarks/statistics.rb +28 -0
  26. data/benchmarks/vector_access.rb +31 -0
  27. data/benchmarks/vector_assign.rb +42 -0
  28. data/benchmarks/where_clause.rb +48 -0
  29. data/benchmarks/where_vs_filter.rb +28 -0
  30. data/daru_lite.gemspec +55 -0
  31. data/images/README.md +5 -0
  32. data/images/con0.png +0 -0
  33. data/images/con1.png +0 -0
  34. data/images/init0.png +0 -0
  35. data/images/init1.png +0 -0
  36. data/images/man0.png +0 -0
  37. data/images/man1.png +0 -0
  38. data/images/man2.png +0 -0
  39. data/images/man3.png +0 -0
  40. data/images/man4.png +0 -0
  41. data/images/man5.png +0 -0
  42. data/images/man6.png +0 -0
  43. data/lib/daru_lite/accessors/array_wrapper.rb +109 -0
  44. data/lib/daru_lite/accessors/dataframe_by_row.rb +25 -0
  45. data/lib/daru_lite/accessors/mdarray_wrapper.rb +7 -0
  46. data/lib/daru_lite/category.rb +929 -0
  47. data/lib/daru_lite/configuration.rb +34 -0
  48. data/lib/daru_lite/core/group_by.rb +403 -0
  49. data/lib/daru_lite/core/merge.rb +270 -0
  50. data/lib/daru_lite/core/query.rb +109 -0
  51. data/lib/daru_lite/dataframe.rb +3080 -0
  52. data/lib/daru_lite/date_time/index.rb +569 -0
  53. data/lib/daru_lite/date_time/offsets.rb +397 -0
  54. data/lib/daru_lite/exceptions.rb +2 -0
  55. data/lib/daru_lite/extensions/which_dsl.rb +53 -0
  56. data/lib/daru_lite/formatters/table.rb +52 -0
  57. data/lib/daru_lite/helpers/array.rb +53 -0
  58. data/lib/daru_lite/index/categorical_index.rb +201 -0
  59. data/lib/daru_lite/index/index.rb +374 -0
  60. data/lib/daru_lite/index/multi_index.rb +374 -0
  61. data/lib/daru_lite/io/csv/converters.rb +21 -0
  62. data/lib/daru_lite/io/io.rb +294 -0
  63. data/lib/daru_lite/io/sql_data_source.rb +97 -0
  64. data/lib/daru_lite/iruby/helpers.rb +38 -0
  65. data/lib/daru_lite/iruby/templates/dataframe.html.erb +5 -0
  66. data/lib/daru_lite/iruby/templates/dataframe_mi.html.erb +5 -0
  67. data/lib/daru_lite/iruby/templates/dataframe_mi_tbody.html.erb +35 -0
  68. data/lib/daru_lite/iruby/templates/dataframe_mi_thead.html.erb +21 -0
  69. data/lib/daru_lite/iruby/templates/dataframe_tbody.html.erb +28 -0
  70. data/lib/daru_lite/iruby/templates/dataframe_thead.html.erb +21 -0
  71. data/lib/daru_lite/iruby/templates/multi_index.html.erb +12 -0
  72. data/lib/daru_lite/iruby/templates/vector.html.erb +5 -0
  73. data/lib/daru_lite/iruby/templates/vector_mi.html.erb +5 -0
  74. data/lib/daru_lite/iruby/templates/vector_mi_tbody.html.erb +26 -0
  75. data/lib/daru_lite/iruby/templates/vector_mi_thead.html.erb +8 -0
  76. data/lib/daru_lite/iruby/templates/vector_tbody.html.erb +17 -0
  77. data/lib/daru_lite/iruby/templates/vector_thead.html.erb +8 -0
  78. data/lib/daru_lite/maths/arithmetic/dataframe.rb +91 -0
  79. data/lib/daru_lite/maths/arithmetic/vector.rb +117 -0
  80. data/lib/daru_lite/maths/statistics/dataframe.rb +202 -0
  81. data/lib/daru_lite/maths/statistics/vector.rb +1019 -0
  82. data/lib/daru_lite/monkeys.rb +56 -0
  83. data/lib/daru_lite/vector.rb +1678 -0
  84. data/lib/daru_lite/version.rb +3 -0
  85. data/lib/daru_lite.rb +99 -0
  86. data/profile/_base.rb +23 -0
  87. data/profile/df_to_a.rb +10 -0
  88. data/profile/filter.rb +13 -0
  89. data/profile/joining.rb +13 -0
  90. data/profile/sorting.rb +12 -0
  91. data/profile/vector_each_with_index.rb +9 -0
  92. data/profile/vector_new.rb +9 -0
  93. data/spec/accessors/array_wrapper_spec.rb +3 -0
  94. data/spec/category_spec.rb +1741 -0
  95. data/spec/core/group_by_spec.rb +655 -0
  96. data/spec/core/merge_spec.rb +179 -0
  97. data/spec/core/query_spec.rb +347 -0
  98. data/spec/daru_lite_spec.rb +22 -0
  99. data/spec/dataframe_spec.rb +4330 -0
  100. data/spec/date_time/data_spec.rb +197 -0
  101. data/spec/date_time/date_time_index_helper_spec.rb +72 -0
  102. data/spec/date_time/index_spec.rb +588 -0
  103. data/spec/date_time/offsets_spec.rb +465 -0
  104. data/spec/extensions/which_dsl_spec.rb +38 -0
  105. data/spec/fixtures/bank2.dat +200 -0
  106. data/spec/fixtures/boolean_converter_test.csv +5 -0
  107. data/spec/fixtures/countries.json +7794 -0
  108. data/spec/fixtures/duplicates.csv +32 -0
  109. data/spec/fixtures/eciresults.html +394 -0
  110. data/spec/fixtures/empties.dat +2 -0
  111. data/spec/fixtures/empty_rows_test.csv +17 -0
  112. data/spec/fixtures/macau.html +3691 -0
  113. data/spec/fixtures/macd_data.csv +150 -0
  114. data/spec/fixtures/matrix_test.csv +100 -0
  115. data/spec/fixtures/moneycontrol.html +6812 -0
  116. data/spec/fixtures/music_data.tsv +2501 -0
  117. data/spec/fixtures/repeated_fields.csv +7 -0
  118. data/spec/fixtures/sales-funnel.csv +18 -0
  119. data/spec/fixtures/scientific_notation.csv +4 -0
  120. data/spec/fixtures/string_converter_test.csv +5 -0
  121. data/spec/fixtures/strings.dat +2 -0
  122. data/spec/fixtures/test_xls.xls +0 -0
  123. data/spec/fixtures/test_xls_2.xls +0 -0
  124. data/spec/fixtures/url_test.txt~ +0 -0
  125. data/spec/fixtures/valid_markup.html +62 -0
  126. data/spec/fixtures/wiki_climate.html +1243 -0
  127. data/spec/fixtures/wiki_table_info.html +631 -0
  128. data/spec/formatters/table_formatter_spec.rb +137 -0
  129. data/spec/helpers_spec.rb +8 -0
  130. data/spec/index/categorical_index_spec.rb +170 -0
  131. data/spec/index/index_spec.rb +417 -0
  132. data/spec/index/multi_index_spec.rb +680 -0
  133. data/spec/io/io_spec.rb +373 -0
  134. data/spec/io/sql_data_source_spec.rb +56 -0
  135. data/spec/iruby/dataframe_spec.rb +170 -0
  136. data/spec/iruby/helpers_spec.rb +49 -0
  137. data/spec/iruby/multi_index_spec.rb +37 -0
  138. data/spec/iruby/vector_spec.rb +105 -0
  139. data/spec/maths/arithmetic/dataframe_spec.rb +148 -0
  140. data/spec/maths/arithmetic/vector_spec.rb +165 -0
  141. data/spec/maths/statistics/dataframe_spec.rb +178 -0
  142. data/spec/maths/statistics/vector_spec.rb +756 -0
  143. data/spec/monkeys_spec.rb +42 -0
  144. data/spec/shared/vector_display_spec.rb +213 -0
  145. data/spec/spec_helper.rb +87 -0
  146. data/spec/support/database_helper.rb +30 -0
  147. data/spec/support/matchers.rb +5 -0
  148. data/spec/vector_spec.rb +2293 -0
  149. metadata +571 -0
@@ -0,0 +1,1741 @@
1
+ describe DaruLite::Vector, "categorical" do
2
+ context "initialize" do
3
+ context "default parameters" do
4
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category }
5
+ subject { dv }
6
+
7
+ it { is_expected.to be_a DaruLite::Vector }
8
+ its(:size) { is_expected.to eq 5 }
9
+ its(:type) { is_expected.to eq :category }
10
+ its(:ordered?) { is_expected.to eq false }
11
+ its(:to_a) { is_expected.to eq [:a, 1, :a, 1, :c] }
12
+ its(:base_category) { is_expected.to eq :a }
13
+ its(:coding_scheme) { is_expected.to eq :dummy }
14
+ its(:index) { is_expected.to be_a DaruLite::Index }
15
+ its(:'index.to_a') { is_expected.to eq [0, 1, 2, 3, 4] }
16
+ end
17
+
18
+ context "with index" do
19
+ context "as array" do
20
+ let(:dv) do
21
+ DaruLite::Vector.new [:a, 1, :a, 1, :c],
22
+ type: :category,
23
+ index: ['a', 'b', 'c', 'd', 'e']
24
+ end
25
+ subject { dv }
26
+
27
+ its(:index) { is_expected.to be_a DaruLite::Index }
28
+ its(:'index.to_a') { is_expected.to eq ['a', 'b', 'c', 'd', 'e'] }
29
+ end
30
+
31
+ context "as range" do
32
+ let(:dv) do
33
+ DaruLite::Vector.new [:a, 1, :a, 1, :c],
34
+ type: :category,
35
+ index: 'a'..'e'
36
+ end
37
+ subject { dv }
38
+
39
+ its(:index) { is_expected.to be_a DaruLite::Index }
40
+ its(:'index.to_a') { is_expected.to eq ['a', 'b', 'c', 'd', 'e'] }
41
+ end
42
+
43
+ context "as index object" do
44
+ let(:tuples) do
45
+ [
46
+ [:one, :tin, :bar],
47
+ [:one, :pin, :bar],
48
+ [:two, :pin, :bar],
49
+ [:two, :tin, :bar],
50
+ [:thr, :pin, :foo]
51
+ ]
52
+ end
53
+ let(:idx) { DaruLite::MultiIndex.from_tuples tuples }
54
+ let(:dv) do
55
+ DaruLite::Vector.new [:a, 1, :a, 1, :c],
56
+ type: :category,
57
+ index: idx
58
+ end
59
+ subject { dv }
60
+
61
+ its(:index) { is_expected.to be_a DaruLite::MultiIndex }
62
+ its(:'index.to_a') { is_expected.to eq tuples }
63
+ end
64
+
65
+ context "invalid index" do
66
+ it { expect { DaruLite::Vector.new [1, 1, 2],
67
+ type: :category,
68
+ index: [1, 2]
69
+ }.to raise_error ArgumentError }
70
+ end
71
+ end
72
+
73
+ context '#category?' do
74
+ let(:non_cat) { DaruLite::Vector.new [1, 2, 3] }
75
+ let(:cat) { DaruLite::Vector.new [1, 2, 3], type: :category }
76
+ it { expect(non_cat.category?).to eq false }
77
+ it { expect(cat.category?).to eq true }
78
+ end
79
+
80
+ context "with categories" do
81
+ context "extra categories" do
82
+ subject { DaruLite::Vector.new [:a, 1, :a, 1, :c],
83
+ type: :category, categories: [:a, :b, :c, 1] }
84
+
85
+ it { is_expected.to be_a DaruLite::Vector }
86
+ its(:type) { is_expected.to eq :category }
87
+ its(:size) { is_expected.to eq 5 }
88
+ its(:order) { is_expected.to eq [:a, :b, :c, 1] }
89
+ its(:categories) { is_expected.to eq [:a, :b, :c, 1] }
90
+ end
91
+
92
+ context "incomplete" do
93
+ it do
94
+ expect { DaruLite::Vector.new [:a, 1, :a, 1, :c],
95
+ type: :category, categories: [:b, :c, 1] }.
96
+ to raise_error ArgumentError
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ context "#rename" do
103
+ let(:dv) { DaruLite::Vector.new [1, 2, 1], type: :category }
104
+ subject { dv.rename 'hello' }
105
+
106
+ it { is_expected.to be_a DaruLite::Vector }
107
+ its(:name) { is_expected.to eq 'hello' }
108
+ end
109
+
110
+ context '#index=' do
111
+ context DaruLite::Index do
112
+ let(:idx) { DaruLite::Index.new [1, 2, 3] }
113
+ let(:dv) { DaruLite::Vector.new ['a', 'b', 'c'], type: :category }
114
+ before { dv.index = idx }
115
+ subject { dv }
116
+
117
+ it { is_expected.to be_a DaruLite::Vector }
118
+ its(:index) { is_expected.to be_a DaruLite::Index }
119
+ its(:'index.to_a') { is_expected.to eq [1, 2, 3] }
120
+ end
121
+
122
+ context Range do
123
+ let(:dv) { DaruLite::Vector.new ['a', 'b', 'c'], type: :category }
124
+ before { dv.index = 1..3 }
125
+ subject { dv }
126
+
127
+ it { is_expected.to be_a DaruLite::Vector }
128
+ its(:index) { is_expected.to be_a DaruLite::Index }
129
+ its(:'index.to_a') { is_expected.to eq [1, 2, 3] }
130
+ end
131
+
132
+ context DaruLite::MultiIndex do
133
+ let(:idx) { DaruLite::MultiIndex.from_tuples [[:a, :one], [:a, :two], [:b, :one]] }
134
+ let(:dv) { DaruLite::Vector.new ['a', 'b', 'c'], type: :category }
135
+ before { dv.index = idx }
136
+ subject { dv }
137
+
138
+ it { is_expected.to be_a DaruLite::Vector }
139
+ its(:index) { is_expected.to be_a DaruLite::MultiIndex }
140
+ its(:'index.to_a') { is_expected.to eq [[:a, :one], [:a, :two], [:b, :one]] }
141
+ end
142
+ end
143
+
144
+ context "#cut" do
145
+ context "close at right end" do
146
+ let(:dv) { DaruLite::Vector.new [1, 2, 5, 14] }
147
+ subject { dv.cut (0..20).step(5) }
148
+
149
+ it { is_expected.to be_a DaruLite::Vector }
150
+ its(:type) { is_expected.to eq :category }
151
+ its(:size) { is_expected.to eq 4 }
152
+ its(:categories) { is_expected.to eq ['0-4', '5-9', '10-14', '15-19'] }
153
+ its(:to_a) { is_expected.to eq ['0-4', '0-4', '5-9', '10-14'] }
154
+ end
155
+
156
+ context "close at left end" do
157
+ let(:dv) { DaruLite::Vector.new [1, 2, 5, 14] }
158
+ subject { dv.cut (0..20).step(5), close_at: :left }
159
+
160
+ it { is_expected.to be_a DaruLite::Vector }
161
+ its(:type) { is_expected.to eq :category }
162
+ its(:size) { is_expected.to eq 4 }
163
+ its(:categories) { is_expected.to eq ['1-5', '6-10', '11-15', '16-20'] }
164
+ its(:to_a) { is_expected.to eq ['1-5', '1-5', '1-5', '11-15'] }
165
+ end
166
+
167
+ context "labels" do
168
+ let(:dv) { DaruLite::Vector.new [1, 2, 5, 14] }
169
+ subject { dv.cut (0..20).step(5), close_at: :left, labels: [:a, :b, :c, :d] }
170
+
171
+ it { is_expected.to be_a DaruLite::Vector }
172
+ its(:type) { is_expected.to eq :category }
173
+ its(:size) { is_expected.to eq 4 }
174
+ its(:categories) { is_expected.to eq [:a, :b, :c, :d] }
175
+ its(:to_a) { is_expected.to eq [:a, :a, :a, :c] }
176
+ end
177
+ end
178
+
179
+ context "#each" do
180
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c] }
181
+ subject { dv.each }
182
+
183
+ it { is_expected.to be_a Enumerator }
184
+ its(:to_a) { is_expected.to eq [:a, 1, :a, 1, :c] }
185
+ end
186
+
187
+ context "#to_a" do
188
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c] }
189
+ subject { dv.to_a }
190
+
191
+ it { is_expected.to be_a Array }
192
+ its(:size) { is_expected.to eq 5 }
193
+ it { is_expected.to eq [:a, 1, :a, 1, :c] }
194
+ end
195
+
196
+ context "#dup" do
197
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category }
198
+ before do
199
+ dv.categories = [:a, :b, :c, 1]
200
+ dv.name = 'daru'
201
+ dv.ordered = true
202
+ end
203
+ subject { dv.dup }
204
+
205
+ its(:type) { is_expected.to eq :category }
206
+ its(:ordered?) { is_expected.to eq true }
207
+ its(:categories) { is_expected.to eq [:a, :b, :c, 1] }
208
+ its(:name) { is_expected.to eq 'daru' }
209
+ end
210
+
211
+ context "#add_category" do
212
+ context "single category" do
213
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category }
214
+ subject { dv }
215
+ before { dv.add_category :b }
216
+
217
+ its(:categories) { is_expected.to eq [:a, 1, :c, :b] }
218
+ its(:order) { is_expected.to eq [:a, 1, :c, :b] }
219
+ end
220
+
221
+ context "multiple categories" do
222
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category }
223
+ subject { dv }
224
+ before { dv.add_category :b, :d }
225
+
226
+ its(:categories) { is_expected.to eq [:a, 1, :c, :b, :d] }
227
+ its(:order) { is_expected.to eq [:a, 1, :c, :b, :d] }
228
+ end
229
+ end
230
+
231
+ context '#remove_unused_categories' do
232
+ context 'base category not removed' do
233
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category }
234
+ before do
235
+ dv.categories = [:a, :b, :c, 1]
236
+ dv.base_category = 1
237
+ dv.remove_unused_categories
238
+ end
239
+ subject { dv }
240
+
241
+ its(:categories) { is_expected.to eq [:a, :c, 1] }
242
+ its(:to_a) { is_expected.to eq [:a, 1, :a, 1, :c] }
243
+ its(:base_category) { is_expected.to eq 1 }
244
+ end
245
+
246
+ context 'base category removed' do
247
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category }
248
+ before do
249
+ dv.categories = [:a, :b, :c, 1]
250
+ dv.base_category = :b
251
+ dv.remove_unused_categories
252
+ end
253
+ subject { dv }
254
+
255
+ its(:to_a) { is_expected.to eq [:a, 1, :a, 1, :c] }
256
+ its(:categories) { is_expected.to eq [:a, :c, 1] }
257
+ its(:base_category) { is_expected.to eq :a }
258
+ end
259
+ end
260
+
261
+ context "count" do
262
+ context "existant category" do
263
+ context "more than 0" do
264
+ subject(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category }
265
+
266
+ it { expect(dv.count :a).to eq 2 }
267
+ end
268
+
269
+ context "equal to 0" do
270
+ subject(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category }
271
+ before { dv.add_category :b }
272
+
273
+ it { expect(dv.count :b).to eq 0 }
274
+ end
275
+ end
276
+
277
+ context "non existant category" do
278
+ subject(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category }
279
+
280
+ it { expect { dv.count :k }.to raise_error ArgumentError }
281
+ end
282
+ end
283
+
284
+ context "#frequencies" do
285
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c],
286
+ type: :category,
287
+ name: :hello,
288
+ categories: [:a, :b, :c, :d, 1] }
289
+ context "counts" do
290
+ subject { dv.frequencies }
291
+
292
+ its(:'index.to_a') { is_expected.to eq [:a, :b, :c, :d, 1] }
293
+ its(:to_a) { is_expected.to eq [2, 0, 1, 0, 2] }
294
+ its(:name) { is_expected.to eq :hello }
295
+ end
296
+ context "percentage" do
297
+ subject { dv.frequencies :percentage }
298
+
299
+ its(:'index.to_a') { is_expected.to eq [:a, :b, :c, :d, 1] }
300
+ its(:to_a) { is_expected.to eq [40, 0, 20, 0, 40] }
301
+ end
302
+ context "fraction" do
303
+ subject { dv.frequencies :fraction }
304
+
305
+ its(:'index.to_a') { is_expected.to eq [:a, :b, :c, :d, 1] }
306
+ its(:to_a) { is_expected.to eq [0.4, 0, 0.2, 0, 0.4] }
307
+ end
308
+ context "invalid argument" do
309
+ it { expect { dv.frequencies :hash }.to raise_error ArgumentError }
310
+ end
311
+ end
312
+
313
+ context "#to_category" do
314
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], index: 1..5 }
315
+ subject { dv.to_category ordered: true, categories: [:a, :b, :c, 1] }
316
+
317
+ it { is_expected.to be_a DaruLite::Vector }
318
+ its(:size) { is_expected.to eq 5 }
319
+ its(:type) { is_expected.to eq :category }
320
+ its(:'index.to_a') { is_expected.to eq [1, 2, 3, 4, 5] }
321
+ its(:ordered?) { is_expected.to eq true }
322
+ its(:to_a) { is_expected.to eq [:a, 1, :a, 1, :c] }
323
+ its(:categories) { is_expected.to eq [:a, :b, :c, 1] }
324
+ end
325
+
326
+ context "#categories" do
327
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category }
328
+ subject { dv.categories }
329
+
330
+ it { is_expected.to be_a Array }
331
+ its(:size) { is_expected.to eq 3 }
332
+ its(:'to_a') { is_expected.to eq [:a, 1, :c] }
333
+ end
334
+
335
+ context "#categories=" do
336
+ context "extra categories" do
337
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c],
338
+ type: :category }
339
+ before { dv.categories = [:c, :b, :a, 1] }
340
+ subject { dv }
341
+
342
+ it { is_expected.to be_a DaruLite::Vector }
343
+ its(:type) { is_expected.to eq :category }
344
+ its(:categories) { is_expected.to eq [:c, :b, :a, 1] }
345
+ its(:to_a) { is_expected.to eq [:a, 1, :a, 1, :c] }
346
+ its(:base_category) { is_expected.to eq :a }
347
+ end
348
+
349
+ context "incomplete" do
350
+ subject { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category }
351
+
352
+ it do
353
+ expect { subject.categories = [:b, :c, 1] }.
354
+ to raise_error ArgumentError
355
+ end
356
+ end
357
+ end
358
+
359
+ context "#base_category" do
360
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category }
361
+ subject { dv }
362
+ before { dv.base_category = 1 }
363
+
364
+ its(:base_category) { is_expected.to eq 1 }
365
+ end
366
+
367
+ context "#coding_scheme" do
368
+ context "valid coding scheme" do
369
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category }
370
+ subject { dv }
371
+ before { dv.coding_scheme = :deviation }
372
+
373
+ its(:coding_scheme) { is_expected.to eq :deviation }
374
+ end
375
+
376
+ context "invalid coding scheme" do
377
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category }
378
+
379
+ it { expect { dv.coding_scheme = :foo }.to raise_error ArgumentError }
380
+ end
381
+ end
382
+
383
+ context "#rename_categories" do
384
+ context 'rename base category' do
385
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category,
386
+ categories: [:a, :x, :y, :c, :b, 1]}
387
+ subject { dv.rename_categories :a => 1, 1 => 2 }
388
+
389
+ it { is_expected.to be_a DaruLite::Vector }
390
+ its(:to_a) { is_expected.to eq [1, 2, 1, 2, :c] }
391
+ its(:categories) { is_expected.to eq [:x, :y, :c, :b, 1, 2] }
392
+ its(:base_category) { is_expected.to eq 1 }
393
+ end
394
+
395
+ context 'rename non-base category' do
396
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category,
397
+ categories: [:a, :b, :c, 1] }
398
+ subject { dv.rename_categories 1 => 2 }
399
+
400
+ it { is_expected.to be_a DaruLite::Vector }
401
+ its(:to_a) { is_expected.to eq [:a, 2, :a, 2, :c] }
402
+ its(:categories) { is_expected.to eq [:a, :b, :c, 2] }
403
+ its(:base_category) { is_expected.to eq :a }
404
+ end
405
+
406
+ context 'merge' do
407
+ let(:dv) { DaruLite::Vector.new [:a, :b, :c, :b, :e], type: :category }
408
+ before { dv.categories = [:a, :b, :c, :d, :e, :f] }
409
+ subject { dv.rename_categories :d => :a, :c => 1, :e => 1 }
410
+
411
+ it { is_expected.to be_a DaruLite::Vector }
412
+ its(:categories) { is_expected.to eq [:a, :b, :f, 1] }
413
+ its(:to_a) { is_expected.to eq [:a, :b, 1, :b, 1] }
414
+ end
415
+ end
416
+
417
+ context '#to_non_category' do
418
+ let(:dv) { DaruLite::Vector.new [1, 2, 3], type: :category,
419
+ index: [:a, :b, :c], name: :hello }
420
+ subject { dv.to_non_category }
421
+
422
+ it { is_expected.to be_a DaruLite::Vector }
423
+ its(:type) { is_expected.not_to eq :category }
424
+ its(:to_a) { is_expected.to eq [1, 2, 3] }
425
+ its(:'index.to_a') { is_expected.to eq [:a, :b, :c] }
426
+ its(:name) { is_expected.to eq :hello }
427
+ end
428
+
429
+ context '#to_category' do
430
+ let(:dv) { DaruLite::Vector.new [1, 2, 3], type: :category }
431
+ it { expect(dv.to_category).to eq dv }
432
+ end
433
+
434
+ context '#reindex!' do
435
+ context DaruLite::Index do
436
+ let(:dv) { DaruLite::Vector.new [3, 2, 1, 3, 2, 1],
437
+ index: 'a'..'f', type: :category, categories: [1, 2, 3, 4] }
438
+ before { dv.reindex! ['e', 'f', 'a', 'b', 'c', 'd'] }
439
+ subject { dv }
440
+
441
+ it { is_expected.to be_a DaruLite::Vector }
442
+ its(:categories) { is_expected.to eq [1, 2, 3, 4] }
443
+ its(:to_a) { is_expected.to eq [2, 1, 3, 2, 1, 3] }
444
+ end
445
+
446
+ context DaruLite::MultiIndex do
447
+ let(:tuples) do
448
+ [
449
+ [:a,:one,:baz],
450
+ [:a,:two,:bar],
451
+ [:a,:two,:baz],
452
+ [:b,:one,:bar],
453
+ [:b,:two,:bar],
454
+ [:b,:two,:baz]
455
+ ]
456
+ end
457
+ let(:idx) { DaruLite::MultiIndex.from_tuples tuples }
458
+ let(:dv) { DaruLite::Vector.new [3, 2, 1, 3, 2, 1],
459
+ index: idx, type: :category, categories: [1, 2, 3, 4] }
460
+ before { dv.reindex! [4, 5, 0, 1, 2, 3].map { |i| tuples[i] } }
461
+ subject { dv }
462
+
463
+ it { is_expected.to be_a DaruLite::Vector }
464
+ its(:categories) { is_expected.to eq [1, 2, 3, 4] }
465
+ its(:to_a) { is_expected.to eq [2, 1, 3, 2, 1, 3] }
466
+ its(:'index.to_a') { is_expected.to eq [4, 5, 0, 1, 2, 3]
467
+ .map { |i| tuples[i] } }
468
+ end
469
+
470
+ context 'invalid index' do
471
+ let(:dv) { DaruLite::Vector.new [1, 2, 3], type: :category }
472
+
473
+ it { expect { dv.reindex! [1, 1, 1] }.to raise_error ArgumentError }
474
+ end
475
+ end
476
+
477
+ context '#reorder!' do
478
+ context 'valid order' do
479
+ let(:dv) { DaruLite::Vector.new [3, 2, 1, 3, 2, 1], index: 'a'..'f', type: :category }
480
+ before { dv.reorder! [5, 4, 3, 2, 1, 0] }
481
+ subject { dv }
482
+
483
+ it { is_expected.to be_a DaruLite::Vector }
484
+ its(:categories) { is_expected.to eq [1, 2, 3] }
485
+ its(:to_a) { is_expected.to eq [1, 2, 3, 1, 2, 3] }
486
+ end
487
+
488
+ context 'invalid order' do
489
+ let(:dv) { DaruLite::Vector.new [1, 2, 3], type: :category }
490
+
491
+ it { expect { dv.reorder! [1, 1, 1] }.to raise_error ArgumentError }
492
+ end
493
+ end
494
+
495
+ context "#min" do
496
+ context "ordered" do
497
+ context "default ordering" do
498
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, ordered: true }
499
+
500
+ it { expect(dv.min).to eq :a }
501
+ end
502
+
503
+ context "reorder" do
504
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, ordered: true }
505
+ before { dv.categories = [1, :a, :c] }
506
+
507
+ it { expect(dv.min).to eq 1 }
508
+ end
509
+ end
510
+
511
+ context "unordered" do
512
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category }
513
+
514
+ it { expect { dv.min }.to raise_error ArgumentError }
515
+ end
516
+ end
517
+
518
+ context "#max" do
519
+ context "ordered" do
520
+ context "default ordering" do
521
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, ordered: true }
522
+
523
+ it { expect(dv.max).to eq :c }
524
+ end
525
+
526
+ context "reorder" do
527
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, ordered: true }
528
+ before { dv.categories = [1, :c, :a] }
529
+
530
+ it { expect(dv.max).to eq :a }
531
+ end
532
+ end
533
+
534
+ context "unordered" do
535
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c, :a], type: :category }
536
+
537
+ it { expect { dv.max }.to raise_error ArgumentError }
538
+ end
539
+ end
540
+
541
+ context "summary" do
542
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c, :a], type: :category }
543
+ subject { dv.describe }
544
+
545
+ it { is_expected.to be_a DaruLite::Vector }
546
+ its(:categories) { is_expected.to eq 3 }
547
+ its(:max_freq) { is_expected.to eq 3 }
548
+ its(:max_category) { is_expected.to eq :a }
549
+ its(:min_freq) { is_expected.to eq 1 }
550
+ its(:min_category) { is_expected.to eq :c }
551
+ end
552
+
553
+ context "#sort!" do
554
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, ordered: true }
555
+ subject { dv }
556
+ before { dv.categories = [:c, :a, 1]; dv.sort! }
557
+
558
+ it { is_expected.to be_a DaruLite::Vector }
559
+ its(:size) { is_expected.to eq 5 }
560
+ its(:to_a) { is_expected.to eq [:c, :a, :a, 1, 1] }
561
+ its(:'index.to_a') { is_expected.to eq [4, 0, 2, 1, 3] }
562
+ end
563
+
564
+ context "#sort" do
565
+ context 'return sorted vector' do
566
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, ordered: true }
567
+ subject { dv.sort }
568
+ before { dv.categories = [:c, :a, 1] }
569
+
570
+ it { is_expected.to be_a DaruLite::Vector }
571
+ its(:size) { is_expected.to eq 5 }
572
+ its(:to_a) { is_expected.to eq [:c, :a, :a, 1, 1] }
573
+ its(:'index.to_a') { is_expected.to eq [4, 0, 2, 1, 3] }
574
+ end
575
+
576
+ context 'original vector unaffected' do
577
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, ordered: true }
578
+ subject { dv }
579
+ before { dv.categories = [:c, :a, 1]; dv.sort }
580
+
581
+ it { is_expected.to be_a DaruLite::Vector }
582
+ its(:size) { is_expected.to eq 5 }
583
+ its(:to_a) { is_expected.to eq [:a, 1, :a, 1, :c] }
584
+ its(:'index.to_a') { is_expected.to eq [0, 1, 2, 3, 4] }
585
+ end
586
+ end
587
+
588
+ context "#[]" do
589
+ context DaruLite::Index do
590
+ before :each do
591
+ @dv = DaruLite::Vector.new [1,2,3,4,5], name: :yoga,
592
+ index: [:yoda, :anakin, :obi, :padme, :r2d2], type: :category
593
+ end
594
+
595
+ it "returns an element after passing an index" do
596
+ expect(@dv[:yoda]).to eq(1)
597
+ end
598
+
599
+ it "returns an element after passing a numeric index" do
600
+ expect(@dv[0]).to eq(1)
601
+ end
602
+
603
+ it "returns a vector with given indices for multiple indices" do
604
+ expect(@dv[:yoda, :anakin]).to eq(DaruLite::Vector.new([1,2], name: :yoda,
605
+ index: [:yoda, :anakin], type: :category))
606
+ end
607
+
608
+ it "returns a vector with given indices for multiple numeric indices" do
609
+ expect(@dv[0,1]).to eq(DaruLite::Vector.new([1,2], name: :yoda,
610
+ index: [:yoda, :anakin], type: :category))
611
+ end
612
+
613
+ it "returns a vector when specified symbol Range" do
614
+ expect(@dv[:yoda..:anakin]).to eq(DaruLite::Vector.new([1,2],
615
+ index: [:yoda, :anakin], name: :yoga, type: :category))
616
+ end
617
+
618
+ it "returns a vector when specified numeric Range" do
619
+ expect(@dv[3..4]).to eq(DaruLite::Vector.new([4,5], name: :yoga,
620
+ index: [:padme, :r2d2], type: :category))
621
+ end
622
+
623
+ it "returns correct results for index of multiple index" do
624
+ v = DaruLite::Vector.new([1,2,3,4], index: ['a','c',1,:a], type: :category)
625
+ expect(v['a']).to eq(1)
626
+ expect(v[:a]).to eq(4)
627
+ expect(v[1]).to eq(3)
628
+ expect(v[0]).to eq(1)
629
+ end
630
+
631
+ it "raises exception for invalid index" do
632
+ expect { @dv[:foo] }.to raise_error(IndexError)
633
+ expect { @dv[:obi, :foo] }.to raise_error(IndexError)
634
+ end
635
+
636
+ context "preserves old categories" do
637
+ let(:dv) do
638
+ DaruLite::Vector.new [:a, :a, :b, :c, :b],
639
+ type: :category,
640
+ categories: [:c, :b, :a, :e]
641
+ end
642
+ subject { dv[0, 1, 4] }
643
+
644
+ it { is_expected.to be_a DaruLite::Vector }
645
+ its(:categories) { is_expected.to eq [:c, :b, :a, :e] }
646
+ its(:to_a) { is_expected.to eq [:a, :a, :b] }
647
+ end
648
+ end
649
+
650
+ context DaruLite::MultiIndex do
651
+ before do
652
+ @tuples = [
653
+ [:a,:one,:bar],
654
+ [:a,:one,:baz],
655
+ [:a,:two,:bar],
656
+ [:a,:two,:baz],
657
+ [:b,:one,:bar],
658
+ [:b,:two,:bar],
659
+ [:b,:two,:baz],
660
+ [:b,:one,:foo],
661
+ [:c,:one,:bar],
662
+ [:c,:one,:baz],
663
+ [:c,:two,:foo],
664
+ [:c,:two,:bar],
665
+ [:d,:one,:foo]
666
+ ]
667
+ @multi_index = DaruLite::MultiIndex.from_tuples(@tuples)
668
+ @vector = DaruLite::Vector.new(
669
+ Array.new(13) { |i| i }, index: @multi_index,
670
+ name: :mi_vector, type: :category)
671
+ end
672
+
673
+ it "returns a single element when passed a row number" do
674
+ expect(@vector[1]).to eq(1)
675
+ end
676
+
677
+ it "returns a single element when passed the full tuple" do
678
+ expect(@vector[:a, :one, :baz]).to eq(1)
679
+ end
680
+
681
+ it "returns sub vector when passed first layer of tuple" do
682
+ mi = DaruLite::MultiIndex.from_tuples([
683
+ [:one,:bar],
684
+ [:one,:baz],
685
+ [:two,:bar],
686
+ [:two,:baz]])
687
+ expect(@vector[:a]).to eq(DaruLite::Vector.new([0,1,2,3], index: mi,
688
+ name: :sub_vector, type: :category))
689
+ end
690
+
691
+ it "returns sub vector when passed first and second layer of tuple" do
692
+ mi = DaruLite::MultiIndex.from_tuples([
693
+ [:foo],
694
+ [:bar]])
695
+ expect(@vector[:c,:two]).to eq(DaruLite::Vector.new([10,11], index: mi,
696
+ name: :sub_sub_vector, type: :category))
697
+ end
698
+
699
+ it "returns sub vector not a single element when passed the partial tuple" do
700
+ mi = DaruLite::MultiIndex.from_tuples([[:foo]])
701
+ expect(@vector[:d, :one]).to eq(DaruLite::Vector.new([12], index: mi,
702
+ name: :sub_sub_vector, type: :category))
703
+ end
704
+
705
+ it "returns a vector with corresponding MultiIndex when specified numeric Range" do
706
+ mi = DaruLite::MultiIndex.from_tuples([
707
+ [:a,:two,:baz],
708
+ [:b,:one,:bar],
709
+ [:b,:two,:bar],
710
+ [:b,:two,:baz],
711
+ [:b,:one,:foo],
712
+ [:c,:one,:bar],
713
+ [:c,:one,:baz]
714
+ ])
715
+ expect(@vector[3..9]).to eq(DaruLite::Vector.new([3,4,5,6,7,8,9], index: mi,
716
+ name: :slice, type: :category))
717
+ end
718
+
719
+ it "raises exception for invalid index" do
720
+ expect { @vector[:foo] }.to raise_error(IndexError)
721
+ expect { @vector[:a, :two, :foo] }.to raise_error(IndexError)
722
+ expect { @vector[:x, :one] }.to raise_error(IndexError)
723
+ end
724
+ end
725
+
726
+ context DaruLite::CategoricalIndex do
727
+ context "non-numerical index" do
728
+ let (:idx) { DaruLite::CategoricalIndex.new [:a, :b, :a, :a, :c] }
729
+ let (:dv) { DaruLite::Vector.new 'a'..'e', index: idx, type: :category }
730
+
731
+ context "single category" do
732
+ context "multiple instances" do
733
+ subject { dv[:a] }
734
+
735
+ it { is_expected.to be_a DaruLite::Vector }
736
+ its(:type) { is_expected.to eq :category }
737
+ its(:size) { is_expected.to eq 3 }
738
+ its(:to_a) { is_expected.to eq ['a', 'c', 'd'] }
739
+ its(:index) { is_expected.to eq(
740
+ DaruLite::CategoricalIndex.new([:a, :a, :a])) }
741
+ end
742
+
743
+ context "single instance" do
744
+ subject { dv[:c] }
745
+
746
+ it { is_expected.to eq 'e' }
747
+ end
748
+ end
749
+
750
+ context "multiple categories" do
751
+ subject { dv[:a, :c] }
752
+
753
+ it { is_expected.to be_a DaruLite::Vector }
754
+ its(:type) { is_expected.to eq :category }
755
+ its(:size) { is_expected.to eq 4 }
756
+ its(:to_a) { is_expected.to eq ['a', 'c', 'd', 'e'] }
757
+ its(:index) { is_expected.to eq(
758
+ DaruLite::CategoricalIndex.new([:a, :a, :a, :c])) }
759
+ end
760
+
761
+ context "multiple positional indexes" do
762
+ subject { dv[0, 1, 2] }
763
+
764
+ it { is_expected.to be_a DaruLite::Vector }
765
+ its(:type) { is_expected.to eq :category }
766
+ its(:size) { is_expected.to eq 3 }
767
+ its(:to_a) { is_expected.to eq ['a', 'b', 'c'] }
768
+ its(:index) { is_expected.to eq(
769
+ DaruLite::CategoricalIndex.new([:a, :b, :a])) }
770
+ end
771
+
772
+ context "single positional index" do
773
+ subject { dv[1] }
774
+
775
+ it { is_expected.to eq 'b' }
776
+ end
777
+
778
+ context "invalid category" do
779
+ it { expect { dv[:x] }.to raise_error IndexError }
780
+ end
781
+
782
+ context "invalid positional index" do
783
+ it { expect { dv[30] }.to raise_error IndexError }
784
+ end
785
+ end
786
+
787
+ context "numerical index" do
788
+ let (:idx) { DaruLite::CategoricalIndex.new [1, 1, 2, 2, 3] }
789
+ let (:dv) { DaruLite::Vector.new 'a'..'e', index: idx, type: :category }
790
+
791
+ context "single category" do
792
+ context "multiple instances" do
793
+ subject { dv[1] }
794
+
795
+ it { is_expected.to be_a DaruLite::Vector }
796
+ its(:type) { is_expected.to eq :category }
797
+ its(:size) { is_expected.to eq 2 }
798
+ its(:to_a) { is_expected.to eq ['a', 'b'] }
799
+ its(:index) { is_expected.to eq(
800
+ DaruLite::CategoricalIndex.new([1, 1])) }
801
+ end
802
+
803
+ context "single instance" do
804
+ subject { dv[3] }
805
+
806
+ it { is_expected.to eq 'e' }
807
+ end
808
+ end
809
+ end
810
+ end
811
+ end
812
+
813
+ context "#[]=" do
814
+ context DaruLite::Index do
815
+ before :each do
816
+ @dv = DaruLite::Vector.new [1,2,3,4,5], name: :yoga,
817
+ index: [:yoda, :anakin, :obi, :padme, :r2d2], type: :category
818
+ @dv.add_category 666
819
+ end
820
+
821
+ it "assigns at the specified index" do
822
+ @dv[:yoda] = 666
823
+ expect(@dv[:yoda]).to eq(666)
824
+ end
825
+
826
+ it "assigns at the specified Integer index" do
827
+ @dv[0] = 666
828
+ expect(@dv[:yoda]).to eq(666)
829
+ end
830
+
831
+ it "assigns correctly for a mixed index Vector" do
832
+ v = DaruLite::Vector.new [1,2,3,4], index: ['a',:a,0,66], type: :category
833
+ v.add_category 666
834
+ v['a'] = 666
835
+ expect(v['a']).to eq(666)
836
+
837
+ v[0] = 666
838
+ expect(v[0]).to eq(666)
839
+
840
+ v[3] = 666
841
+ expect(v[3]).to eq(666)
842
+
843
+ expect(v).to eq(DaruLite::Vector.new([666,2,666,666],
844
+ index: ['a',:a,0,66], type: :category))
845
+ end
846
+ end
847
+
848
+ context DaruLite::MultiIndex do
849
+ before :each do
850
+ @tuples = [
851
+ [:a,:one,:bar],
852
+ [:a,:one,:baz],
853
+ [:a,:two,:bar],
854
+ [:a,:two,:baz],
855
+ [:b,:one,:bar],
856
+ [:b,:two,:bar],
857
+ [:b,:two,:baz],
858
+ [:b,:one,:foo],
859
+ [:c,:one,:bar],
860
+ [:c,:one,:baz],
861
+ [:c,:two,:foo],
862
+ [:c,:two,:bar]
863
+ ]
864
+ @multi_index = DaruLite::MultiIndex.from_tuples(@tuples)
865
+ @vector = DaruLite::Vector.new Array.new(12) { |i| i }, index: @multi_index,
866
+ type: :category, name: :mi_vector
867
+ @vector.add_category 69
868
+ end
869
+
870
+ it "assigns all lower layer indices when specified a first layer index" do
871
+ @vector[:b] = 69
872
+ expect(@vector).to eq(DaruLite::Vector.new([0,1,2,3,69,69,69,69,8,9,10,11],
873
+ index: @multi_index, name: :top_layer_assignment, type: :category
874
+ ))
875
+ end
876
+
877
+ it "assigns all lower indices when specified first and second layer index" do
878
+ @vector[:b, :one] = 69
879
+ expect(@vector).to eq(DaruLite::Vector.new([0,1,2,3,69,5,6,69,8,9,10,11],
880
+ index: @multi_index, name: :second_layer_assignment, type: :category))
881
+ end
882
+
883
+ it "assigns just the precise value when specified complete tuple" do
884
+ @vector[:b, :one, :foo] = 69
885
+ expect(@vector).to eq(DaruLite::Vector.new([0,1,2,3,4,5,6,69,8,9,10,11],
886
+ index: @multi_index, name: :precise_assignment, type: :category))
887
+ end
888
+
889
+ it "assigns correctly when numeric index" do
890
+ @vector[7] = 69
891
+ expect(@vector).to eq(DaruLite::Vector.new([0,1,2,3,4,5,6,69,8,9,10,11],
892
+ index: @multi_index, name: :precise_assignment, type: :category))
893
+ end
894
+
895
+ it "fails predictably on unknown index" do
896
+ expect { @vector[:d] = 69 }.to raise_error(IndexError)
897
+ expect { @vector[:b, :three] = 69 }.to raise_error(IndexError)
898
+ expect { @vector[:b, :two, :test] = 69 }.to raise_error(IndexError)
899
+ end
900
+ end
901
+
902
+ context DaruLite::CategoricalIndex do
903
+ context "non-numerical index" do
904
+ let (:idx) { DaruLite::CategoricalIndex.new [:a, :b, :a, :a, :c] }
905
+ let (:dv) { DaruLite::Vector.new 'a'..'e', index: idx, type: :category }
906
+ before { dv.add_category 'x' }
907
+
908
+ context "single category" do
909
+ context "multiple instances" do
910
+ subject { dv }
911
+ before { dv[:a] = 'x' }
912
+
913
+ its(:size) { is_expected.to eq 5 }
914
+ its(:to_a) { is_expected.to eq ['x', 'b', 'x', 'x', 'e'] }
915
+ its(:index) { is_expected.to eq idx }
916
+ end
917
+
918
+ context "single instance" do
919
+ subject { dv }
920
+ before { dv[:b] = 'x' }
921
+
922
+ its(:size) { is_expected.to eq 5 }
923
+ its(:to_a) { is_expected.to eq ['a', 'x', 'c', 'd', 'e'] }
924
+ its(:index) { is_expected.to eq idx }
925
+ end
926
+ end
927
+
928
+ context "multiple categories" do
929
+ subject { dv }
930
+ before { dv[:a, :c] = 'x' }
931
+
932
+ its(:size) { is_expected.to eq 5 }
933
+ its(:to_a) { is_expected.to eq ['x', 'b', 'x', 'x', 'x'] }
934
+ its(:index) { is_expected.to eq idx }
935
+ end
936
+
937
+ context "multiple positional indexes" do
938
+ subject { dv }
939
+ before { dv[0, 1, 2] = 'x' }
940
+
941
+ its(:size) { is_expected.to eq 5 }
942
+ its(:to_a) { is_expected.to eq ['x', 'x', 'x', 'd', 'e'] }
943
+ its(:index) { is_expected.to eq idx }
944
+ end
945
+
946
+ context "single positional index" do
947
+ subject { dv }
948
+ before { dv[1] = 'x' }
949
+
950
+ its(:size) { is_expected.to eq 5 }
951
+ its(:to_a) { is_expected.to eq ['a', 'x', 'c', 'd', 'e'] }
952
+ its(:index) { is_expected.to eq idx }
953
+ end
954
+
955
+ context "invalid category" do
956
+ it { expect { dv[:x] = 'x' }.to raise_error IndexError }
957
+ end
958
+
959
+ context "invalid positional index" do
960
+ it { expect { dv[30] = 'x'}.to raise_error IndexError }
961
+ end
962
+ end
963
+
964
+ context "numerical index" do
965
+ let (:idx) { DaruLite::CategoricalIndex.new [1, 1, 2, 2, 3] }
966
+ let (:dv) { DaruLite::Vector.new 'a'..'e', index: idx, type: :category }
967
+ before { dv.add_category 'x' }
968
+
969
+ context "single category" do
970
+ subject { dv }
971
+ before { dv[1] = 'x' }
972
+
973
+ its(:size) { is_expected.to eq 5 }
974
+ its(:to_a) { is_expected.to eq ['x', 'x', 'c', 'd', 'e'] }
975
+ its(:index) { is_expected.to eq idx }
976
+ end
977
+
978
+ context "multiple categories" do
979
+ subject { dv }
980
+ before { dv[1, 2] = 'x' }
981
+
982
+ its(:size) { is_expected.to eq 5 }
983
+ its(:to_a) { is_expected.to eq ['x', 'x', 'x', 'x', 'e'] }
984
+ its(:index) { is_expected.to eq idx }
985
+ end
986
+ end
987
+ end
988
+ end
989
+
990
+ context "#at" do
991
+ context DaruLite::Index do
992
+ let (:idx) { DaruLite::Index.new [1, 0, :c] }
993
+ let (:dv) { DaruLite::Vector.new ['a', 'b', 'c'], index: idx, type: :category }
994
+
995
+ context "single position" do
996
+ it { expect(dv.at 1).to eq 'b' }
997
+ end
998
+
999
+ context "multiple positions" do
1000
+ subject { dv.at 0, 2 }
1001
+
1002
+ it { is_expected.to be_a DaruLite::Vector }
1003
+ its(:type) { is_expected.to eq :category }
1004
+ its(:size) { is_expected.to eq 2 }
1005
+ its(:to_a) { is_expected.to eq ['a', 'c'] }
1006
+ its(:'index.to_a') { is_expected.to eq [1, :c] }
1007
+ end
1008
+
1009
+ context "invalid position" do
1010
+ it { expect { dv.at 3 }.to raise_error IndexError }
1011
+ end
1012
+
1013
+ context "invalid positions" do
1014
+ it { expect { dv.at 2, 3 }.to raise_error IndexError }
1015
+ end
1016
+
1017
+ context "range" do
1018
+ subject { dv.at 0..1 }
1019
+
1020
+ it { is_expected.to be_a DaruLite::Vector }
1021
+ its(:type) { is_expected.to eq :category }
1022
+ its(:size) { is_expected.to eq 2 }
1023
+ its(:to_a) { is_expected.to eq ['a', 'b'] }
1024
+ its(:'index.to_a') { is_expected.to eq [1, 0] }
1025
+ end
1026
+
1027
+ context "range with negative end" do
1028
+ subject { dv.at 0..-2 }
1029
+
1030
+ it { is_expected.to be_a DaruLite::Vector }
1031
+ its(:type) { is_expected.to eq :category }
1032
+ its(:size) { is_expected.to eq 2 }
1033
+ its(:to_a) { is_expected.to eq ['a', 'b'] }
1034
+ its(:'index.to_a') { is_expected.to eq [1, 0] }
1035
+ end
1036
+
1037
+ context "range with single element" do
1038
+ subject { dv.at 0..0 }
1039
+
1040
+ it { is_expected.to be_a DaruLite::Vector }
1041
+ its(:type) { is_expected.to eq :category }
1042
+ its(:size) { is_expected.to eq 1 }
1043
+ its(:to_a) { is_expected.to eq ['a'] }
1044
+ its(:'index.to_a') { is_expected.to eq [1] }
1045
+ end
1046
+
1047
+ context "preserves old categories" do
1048
+ let(:dv) do
1049
+ DaruLite::Vector.new [:a, :a, :b, :c, :b],
1050
+ type: :category,
1051
+ categories: [:c, :b, :a, :e]
1052
+ end
1053
+ subject { dv.at 0, 1, 4 }
1054
+
1055
+ it { is_expected.to be_a DaruLite::Vector }
1056
+ its(:categories) { is_expected.to eq [:c, :b, :a, :e] }
1057
+ its(:to_a) { is_expected.to eq [:a, :a, :b] }
1058
+ end
1059
+ end
1060
+
1061
+ context DaruLite::MultiIndex do
1062
+ let (:idx) do
1063
+ DaruLite::MultiIndex.from_tuples [
1064
+ [:a,:one,:bar],
1065
+ [:a,:one,:baz],
1066
+ [:b,:two,:bar],
1067
+ [:a,:two,:baz],
1068
+ ]
1069
+ end
1070
+ let (:dv) { DaruLite::Vector.new 1..4, index: idx, type: :category }
1071
+
1072
+ context "single position" do
1073
+ it { expect(dv.at 1).to eq 2 }
1074
+ end
1075
+
1076
+ context "multiple positions" do
1077
+ subject { dv.at 2, 3 }
1078
+
1079
+ it { is_expected.to be_a DaruLite::Vector }
1080
+ its(:type) { is_expected.to eq :category }
1081
+ its(:size) { is_expected.to eq 2 }
1082
+ its(:to_a) { is_expected.to eq [3, 4] }
1083
+ its(:'index.to_a') { is_expected.to eq [[:b, :two, :bar],
1084
+ [:a, :two, :baz]] }
1085
+ end
1086
+
1087
+ context "invalid position" do
1088
+ it { expect { dv.at 4 }.to raise_error IndexError }
1089
+ end
1090
+
1091
+ context "invalid positions" do
1092
+ it { expect { dv.at 2, 4 }.to raise_error IndexError }
1093
+ end
1094
+
1095
+ context "range" do
1096
+ subject { dv.at 2..3 }
1097
+
1098
+ it { is_expected.to be_a DaruLite::Vector }
1099
+ its(:type) { is_expected.to eq :category }
1100
+ its(:size) { is_expected.to eq 2 }
1101
+ its(:to_a) { is_expected.to eq [3, 4] }
1102
+ its(:'index.to_a') { is_expected.to eq [[:b, :two, :bar],
1103
+ [:a, :two, :baz]] }
1104
+ end
1105
+
1106
+ context "range with negative end" do
1107
+ subject { dv.at 2..-1 }
1108
+
1109
+ it { is_expected.to be_a DaruLite::Vector }
1110
+ its(:type) { is_expected.to eq :category }
1111
+ its(:size) { is_expected.to eq 2 }
1112
+ its(:to_a) { is_expected.to eq [3, 4] }
1113
+ its(:'index.to_a') { is_expected.to eq [[:b, :two, :bar],
1114
+ [:a, :two, :baz]] }
1115
+ end
1116
+
1117
+ context "range with single element" do
1118
+ subject { dv.at 2..2 }
1119
+
1120
+ it { is_expected.to be_a DaruLite::Vector }
1121
+ its(:type) { is_expected.to eq :category }
1122
+ its(:size) { is_expected.to eq 1 }
1123
+ its(:to_a) { is_expected.to eq [3] }
1124
+ its(:'index.to_a') { is_expected.to eq [[:b, :two, :bar]] }
1125
+ end
1126
+ end
1127
+
1128
+ context DaruLite::CategoricalIndex do
1129
+ let (:idx) { DaruLite::CategoricalIndex.new [:a, 1, 1, :a, :c] }
1130
+ let (:dv) { DaruLite::Vector.new 'a'..'e', index: idx, type: :category }
1131
+
1132
+ context "multiple positional indexes" do
1133
+ subject { dv.at 0, 1, 2 }
1134
+
1135
+ it { is_expected.to be_a DaruLite::Vector }
1136
+ its(:type) { is_expected.to eq :category }
1137
+ its(:size) { is_expected.to eq 3 }
1138
+ its(:to_a) { is_expected.to eq ['a', 'b', 'c'] }
1139
+ its(:index) { is_expected.to eq(
1140
+ DaruLite::CategoricalIndex.new([:a, 1, 1])) }
1141
+ end
1142
+
1143
+ context "single positional index" do
1144
+ subject { dv.at 1 }
1145
+
1146
+ it { is_expected.to eq 'b' }
1147
+ end
1148
+
1149
+ context "invalid position" do
1150
+ it { expect { dv.at 5 }.to raise_error IndexError }
1151
+ end
1152
+
1153
+ context "invalid positions" do
1154
+ it { expect { dv.at 2, 5 }.to raise_error IndexError }
1155
+ end
1156
+
1157
+ context "range" do
1158
+ subject { dv.at 0..2 }
1159
+
1160
+ it { is_expected.to be_a DaruLite::Vector }
1161
+ its(:type) { is_expected.to eq :category }
1162
+ its(:size) { is_expected.to eq 3 }
1163
+ its(:to_a) { is_expected.to eq ['a', 'b', 'c'] }
1164
+ its(:index) { is_expected.to eq(
1165
+ DaruLite::CategoricalIndex.new([:a, 1, 1])) }
1166
+ end
1167
+
1168
+ context "range with negative end" do
1169
+ subject { dv.at 0..-3 }
1170
+
1171
+ it { is_expected.to be_a DaruLite::Vector }
1172
+ its(:type) { is_expected.to eq :category }
1173
+ its(:size) { is_expected.to eq 3 }
1174
+ its(:to_a) { is_expected.to eq ['a', 'b', 'c'] }
1175
+ its(:index) { is_expected.to eq(
1176
+ DaruLite::CategoricalIndex.new([:a, 1, 1])) }
1177
+ end
1178
+
1179
+ context "range with single element" do
1180
+ subject { dv.at 0..0 }
1181
+
1182
+ it { is_expected.to be_a DaruLite::Vector }
1183
+ its(:type) { is_expected.to eq :category }
1184
+ its(:size) { is_expected.to eq 1 }
1185
+ its(:to_a) { is_expected.to eq ['a'] }
1186
+ its(:index) { is_expected.to eq(
1187
+ DaruLite::CategoricalIndex.new([:a])) }
1188
+ end
1189
+ end
1190
+ end
1191
+
1192
+ context "#set_at" do
1193
+ context DaruLite::Index do
1194
+ let (:idx) { DaruLite::Index.new [1, 0, :c] }
1195
+ let (:dv) { DaruLite::Vector.new ['a', 'b', 'c'], index: idx, type: :category }
1196
+ before { dv.add_category 'x' }
1197
+
1198
+ context "single position" do
1199
+ subject { dv }
1200
+ before { dv.set_at [1], 'x' }
1201
+
1202
+ its(:to_a) { is_expected.to eq ['a', 'x', 'c'] }
1203
+ end
1204
+
1205
+ context "multiple positions" do
1206
+ subject { dv }
1207
+ before { dv.set_at [0, 2], 'x' }
1208
+
1209
+ its(:to_a) { is_expected.to eq ['x', 'b', 'x'] }
1210
+ end
1211
+
1212
+ context "invalid position" do
1213
+ it { expect { dv.set_at [3], 'x' }.to raise_error IndexError }
1214
+ end
1215
+
1216
+ context "invalid positions" do
1217
+ it { expect { dv.set_at [2, 3], 'x' }.to raise_error IndexError }
1218
+ end
1219
+ end
1220
+
1221
+ context DaruLite::MultiIndex do
1222
+ let(:idx) do
1223
+ DaruLite::MultiIndex.from_tuples [
1224
+ [:a,:one,:bar],
1225
+ [:a,:one,:baz],
1226
+ [:b,:two,:bar],
1227
+ [:a,:two,:baz],
1228
+ ]
1229
+ end
1230
+ let(:dv) { DaruLite::Vector.new 1..4, index: idx, type: :category }
1231
+ before { dv.add_category 'x' }
1232
+
1233
+ context "single position" do
1234
+ subject { dv }
1235
+ before { dv.set_at [1], 'x' }
1236
+
1237
+ its(:to_a) { is_expected.to eq [1, 'x', 3, 4] }
1238
+ end
1239
+
1240
+ context "multiple positions" do
1241
+ subject { dv }
1242
+ before { dv.set_at [2, 3], 'x' }
1243
+
1244
+ its(:to_a) { is_expected.to eq [1, 2, 'x', 'x'] }
1245
+ end
1246
+
1247
+ context "invalid position" do
1248
+ it { expect { dv.set_at [4], 'x' }.to raise_error IndexError }
1249
+ end
1250
+
1251
+ context "invalid positions" do
1252
+ it { expect { dv.set_at [2, 4], 'x' }.to raise_error IndexError }
1253
+ end
1254
+ end
1255
+
1256
+ context DaruLite::CategoricalIndex do
1257
+ let (:idx) { DaruLite::CategoricalIndex.new [:a, 1, 1, :a, :c] }
1258
+ let (:dv) { DaruLite::Vector.new 'a'..'e', index: idx, type: :category }
1259
+ before { dv.add_category 'x' }
1260
+
1261
+ context "multiple positional indexes" do
1262
+ subject { dv }
1263
+ before { dv.set_at [0, 1, 2], 'x' }
1264
+
1265
+ its(:to_a) { is_expected.to eq ['x', 'x', 'x', 'd', 'e'] }
1266
+ end
1267
+
1268
+ context "single positional index" do
1269
+ subject { dv }
1270
+ before { dv.set_at [1], 'x' }
1271
+
1272
+ its(:to_a) { is_expected.to eq ['a', 'x', 'c', 'd', 'e'] }
1273
+ end
1274
+
1275
+ context "invalid position" do
1276
+ it { expect { dv.set_at [5], 'x' }.to raise_error IndexError }
1277
+ end
1278
+
1279
+ context "invalid positions" do
1280
+ it { expect { dv.set_at [2, 5], 'x' }.to raise_error IndexError }
1281
+ end
1282
+ end
1283
+ end
1284
+
1285
+ context "#contrast_code" do
1286
+ context "dummy coding" do
1287
+ context "default base category" do
1288
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, name: :abc }
1289
+ subject { dv.contrast_code }
1290
+
1291
+ it { is_expected.to be_a DaruLite::DataFrame }
1292
+ its(:shape) { is_expected.to eq [5, 2] }
1293
+ its(:'abc_1.to_a') { is_expected.to eq [0, 1, 0, 1, 0] }
1294
+ its(:'abc_c.to_a') { is_expected.to eq [0, 0, 0, 0, 1] }
1295
+ end
1296
+
1297
+ context "manual base category" do
1298
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, name: :abc }
1299
+ before { dv.base_category = :c }
1300
+ subject { dv.contrast_code }
1301
+
1302
+ it { is_expected.to be_a DaruLite::DataFrame }
1303
+ its(:shape) { is_expected.to eq [5, 2] }
1304
+ its(:'abc_a.to_a') { is_expected.to eq [1, 0, 1, 0, 0] }
1305
+ its(:'abc_1.to_a') { is_expected.to eq [0, 1, 0, 1, 0] }
1306
+ end
1307
+ end
1308
+
1309
+ context "simple coding" do
1310
+ context "default base category" do
1311
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, name: :abc }
1312
+ subject { dv.contrast_code }
1313
+ before { dv.coding_scheme = :simple }
1314
+
1315
+ it { is_expected.to be_a DaruLite::DataFrame }
1316
+ its(:shape) { is_expected.to eq [5, 2] }
1317
+ its(:'abc_1.to_a') { is_expected.to eq [-1/3.0, 2/3.0, -1/3.0, 2/3.0, -1/3.0] }
1318
+ its(:'abc_c.to_a') { is_expected.to eq [-1/3.0, -1/3.0, -1/3.0, -1/3.0, 2/3.0] }
1319
+ end
1320
+
1321
+ context "manual base category" do
1322
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, name: :abc }
1323
+ subject { dv.contrast_code }
1324
+ before do
1325
+ dv.coding_scheme = :simple
1326
+ dv.base_category = :c
1327
+ end
1328
+
1329
+ it { is_expected.to be_a DaruLite::DataFrame }
1330
+ its(:shape) { is_expected.to eq [5, 2] }
1331
+ its(:'abc_a.to_a') { is_expected.to eq [2/3.0, -1/3.0, 2/3.0, -1/3.0, -1/3.0] }
1332
+ its(:'abc_1.to_a') { is_expected.to eq [-1/3.0, 2/3.0, -1/3.0, 2/3.0, -1/3.0] }
1333
+ end
1334
+ end
1335
+
1336
+ context "helmert coding" do
1337
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, name: :abc }
1338
+ subject { dv.contrast_code }
1339
+ before { dv.coding_scheme = :helmert }
1340
+
1341
+ it { is_expected.to be_a DaruLite::DataFrame }
1342
+ its(:shape) { is_expected.to eq [5, 2] }
1343
+ its(:'abc_a.to_a') { is_expected.to eq [2/3.0, -1/3.0, 2/3.0, -1/3.0, -1/3.0] }
1344
+ its(:'abc_1.to_a') { is_expected.to eq [0, 1/2.0, 0, 1/2.0, -1/2.0] }
1345
+ end
1346
+
1347
+ context "deviation coding" do
1348
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, name: :abc }
1349
+ subject { dv.contrast_code }
1350
+ before { dv.coding_scheme = :deviation }
1351
+
1352
+ it { is_expected.to be_a DaruLite::DataFrame }
1353
+ its(:shape) { is_expected.to eq [5, 2] }
1354
+ its(:'abc_a.to_a') { is_expected.to eq [1, 0, 1, 0, -1] }
1355
+ its(:'abc_1.to_a') { is_expected.to eq [0, 1, 0, 1, -1] }
1356
+ end
1357
+
1358
+ context "user-defined coding" do
1359
+ let(:df) do
1360
+ DaruLite::DataFrame.new({
1361
+ rank_level1: [1, -2, -3],
1362
+ rank_level2: [-4, 2, -1],
1363
+ rank_level3: [-3, -1, 5]
1364
+ }, index: ['I', 'II', 'III'])
1365
+ end
1366
+ let(:dv) { DaruLite::Vector.new ['III', 'II', 'I', 'II', 'II'],
1367
+ name: :rank, type: :category }
1368
+ subject { dv.contrast_code user_defined: df }
1369
+
1370
+ it { is_expected.to be_a DaruLite::DataFrame }
1371
+ its(:shape) { is_expected.to eq [5, 3] }
1372
+ its(:'rank_level1.to_a') { is_expected.to eq [-3, -2, 1, -2, -2] }
1373
+ its(:'rank_level2.to_a') { is_expected.to eq [-1, 2, -4, 2, 2] }
1374
+ its(:'rank_level3.to_a') { is_expected.to eq [5, -1, -3, -1, -1] }
1375
+ end
1376
+
1377
+ context 'naming' do
1378
+ context "string" do
1379
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, name: 'abc' }
1380
+ subject { dv.contrast_code }
1381
+
1382
+ it { is_expected.to be_a DaruLite::DataFrame }
1383
+ its(:'vectors.to_a') { is_expected.to eq ['abc_1', 'abc_c'] }
1384
+ end
1385
+
1386
+ context "symbol" do
1387
+ let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, name: :abc }
1388
+ subject { dv.contrast_code }
1389
+
1390
+ it { is_expected.to be_a DaruLite::DataFrame }
1391
+ its(:'vectors.to_a') { is_expected.to eq [:abc_1, :abc_c] }
1392
+ end
1393
+ end
1394
+ end
1395
+
1396
+ context '#reject_values'do
1397
+ let(:dv) { DaruLite::Vector.new [1, nil, 3, :a, Float::NAN, nil, Float::NAN, 1],
1398
+ index: 11..18, type: :category }
1399
+ context 'reject only nils' do
1400
+ subject { dv.reject_values nil }
1401
+
1402
+ it { is_expected.to be_a DaruLite::Vector }
1403
+ its(:type) { is_expected.to eq :category }
1404
+ its(:to_a) { is_expected.to eq [1, 3, :a, Float::NAN, Float::NAN, 1] }
1405
+ its(:'index.to_a') { is_expected.to eq [11, 13, 14, 15, 17, 18] }
1406
+ end
1407
+
1408
+ context 'reject only float::NAN' do
1409
+ subject { dv.reject_values Float::NAN }
1410
+
1411
+ it { is_expected.to be_a DaruLite::Vector }
1412
+ its(:type) { is_expected.to eq :category }
1413
+ its(:to_a) { is_expected.to eq [1, nil, 3, :a, nil, 1] }
1414
+ its(:'index.to_a') { is_expected.to eq [11, 12, 13, 14, 16, 18] }
1415
+ end
1416
+
1417
+ context 'reject both nil and float::NAN' do
1418
+ subject { dv.reject_values nil, Float::NAN }
1419
+
1420
+ it { is_expected.to be_a DaruLite::Vector }
1421
+ its(:type) { is_expected.to eq :category }
1422
+ its(:to_a) { is_expected.to eq [1, 3, :a, 1] }
1423
+ its(:'index.to_a') { is_expected.to eq [11, 13, 14, 18] }
1424
+ end
1425
+
1426
+ context 'reject any other value' do
1427
+ subject { dv.reject_values 1, 3, 20 }
1428
+
1429
+ it { is_expected.to be_a DaruLite::Vector }
1430
+ its(:type) { is_expected.to eq :category }
1431
+ its(:to_a) { is_expected.to eq [nil, :a, Float::NAN, nil, Float::NAN] }
1432
+ its(:'index.to_a') { is_expected.to eq [12, 14, 15, 16, 17] }
1433
+ end
1434
+
1435
+ context 'when resultant vector has only one value' do
1436
+ subject { dv.reject_values 1, :a, nil, Float::NAN }
1437
+
1438
+ it { is_expected.to be_a DaruLite::Vector }
1439
+ its(:to_a) { is_expected.to eq [3] }
1440
+ its(:'index.to_a') { is_expected.to eq [13] }
1441
+ end
1442
+
1443
+ context 'when resultant vector has no value' do
1444
+ subject { dv.reject_values 1, 3, :a, nil, Float::NAN, 5 }
1445
+
1446
+ it { is_expected.to be_a DaruLite::Vector }
1447
+ its(:to_a) { is_expected.to eq [] }
1448
+ its(:'index.to_a') { is_expected.to eq [] }
1449
+ end
1450
+ end
1451
+
1452
+ context '#include_values?' do
1453
+ context 'only nils' do
1454
+ context 'true' do
1455
+ let(:dv) { DaruLite::Vector.new [1, 2, 3, :a, 'Unknown', nil],
1456
+ type: :category }
1457
+ it { expect(dv.include_values? nil).to eq true }
1458
+ end
1459
+
1460
+ context 'false' do
1461
+ let(:dv) { DaruLite::Vector.new [1, 2, 3, :a, 'Unknown'],
1462
+ type: :category }
1463
+ it { expect(dv.include_values? nil).to eq false }
1464
+ end
1465
+ end
1466
+
1467
+ context 'only Float::NAN' do
1468
+ context 'true' do
1469
+ let(:dv) { DaruLite::Vector.new [1, nil, 2, 3, Float::NAN],
1470
+ type: :category}
1471
+ it { expect(dv.include_values? Float::NAN).to eq true }
1472
+ end
1473
+
1474
+ context 'false' do
1475
+ let(:dv) { DaruLite::Vector.new [1, nil, 2, 3],
1476
+ type: :category }
1477
+ it { expect(dv.include_values? Float::NAN).to eq false }
1478
+ end
1479
+ end
1480
+
1481
+ context 'both nil and Float::NAN' do
1482
+ context 'true with only nil' do
1483
+ let(:dv) { DaruLite::Vector.new [1, Float::NAN, 2, 3],
1484
+ type: :category}
1485
+ it { expect(dv.include_values? nil, Float::NAN).to eq true }
1486
+ end
1487
+
1488
+ context 'true with only Float::NAN' do
1489
+ let(:dv) { DaruLite::Vector.new [1, nil, 2, 3],
1490
+ type: :category}
1491
+ it { expect(dv.include_values? nil, Float::NAN).to eq true }
1492
+ end
1493
+
1494
+ context 'false' do
1495
+ let(:dv) { DaruLite::Vector.new [1, 2, 3],
1496
+ type: :category}
1497
+ it { expect(dv.include_values? nil, Float::NAN).to eq false }
1498
+ end
1499
+ end
1500
+
1501
+ context 'any other value' do
1502
+ context 'true' do
1503
+ let(:dv) { DaruLite::Vector.new [1, 2, 3, 4, nil],
1504
+ type: :category }
1505
+ it { expect(dv.include_values? 1, 2, 3, 5).to eq true }
1506
+ end
1507
+
1508
+ context 'false' do
1509
+ let(:dv) { DaruLite::Vector.new [1, 2, 3, 4, nil],
1510
+ type: :category }
1511
+ it { expect(dv.include_values? 5, 6).to eq false }
1512
+ end
1513
+ end
1514
+ end
1515
+
1516
+ context '#count_values' do
1517
+ let(:dv) { DaruLite::Vector.new [1, 2, 3, 1, 2, nil, nil], type: :category }
1518
+ it { expect(dv.count_values 1, 2).to eq 4 }
1519
+ it { expect(dv.count_values nil).to eq 2 }
1520
+ it { expect(dv.count_values 3, Float::NAN).to eq 1 }
1521
+ it { expect(dv.count_values 4).to eq 0 }
1522
+ end
1523
+
1524
+ context '#indexes' do
1525
+ context DaruLite::Index do
1526
+ let(:dv) { DaruLite::Vector.new [1, 2, 1, 2, 3, nil, nil, Float::NAN],
1527
+ index: 11..18, type: :category }
1528
+
1529
+ subject { dv.indexes 1, 2, nil, Float::NAN }
1530
+ it { is_expected.to be_a Array }
1531
+ it { is_expected.to eq [11, 12, 13, 14, 16, 17, 18] }
1532
+ end
1533
+
1534
+ context DaruLite::MultiIndex do
1535
+ let(:mi) do
1536
+ DaruLite::MultiIndex.from_tuples([
1537
+ ['M', 2000],
1538
+ ['M', 2001],
1539
+ ['M', 2002],
1540
+ ['M', 2003],
1541
+ ['F', 2000],
1542
+ ['F', 2001],
1543
+ ['F', 2002],
1544
+ ['F', 2003]
1545
+ ])
1546
+ end
1547
+ let(:dv) { DaruLite::Vector.new [1, 2, 1, 2, 3, nil, nil, Float::NAN],
1548
+ index: mi, type: :category }
1549
+
1550
+ subject { dv.indexes 1, 2, Float::NAN }
1551
+ it { is_expected.to be_a Array }
1552
+ it { is_expected.to eq(
1553
+ [
1554
+ ['M', 2000],
1555
+ ['M', 2001],
1556
+ ['M', 2002],
1557
+ ['M', 2003],
1558
+ ['F', 2003]
1559
+ ]) }
1560
+ end
1561
+ end
1562
+
1563
+ context '#replace_values' do
1564
+ subject do
1565
+ DaruLite::Vector.new(
1566
+ [1, 2, 1, 4, nil, Float::NAN, nil, Float::NAN],
1567
+ index: 11..18, type: :category
1568
+ )
1569
+ end
1570
+
1571
+ context 'replace nils and NaNs' do
1572
+ before { subject.replace_values [nil, Float::NAN], 10 }
1573
+ its(:type) { is_expected.to eq :category }
1574
+ its(:to_a) { is_expected.to eq [1, 2, 1, 4, 10, 10, 10, 10] }
1575
+ end
1576
+
1577
+ context 'replace arbitrary values' do
1578
+ before { subject.replace_values [1, 2], 10 }
1579
+ its(:type) { is_expected.to eq :category }
1580
+ its(:to_a) { is_expected.to eq(
1581
+ [10, 10, 10, 4, nil, Float::NAN, nil, Float::NAN]) }
1582
+ end
1583
+
1584
+ context 'works for single value' do
1585
+ before { subject.replace_values nil, 10 }
1586
+ its(:type) { is_expected.to eq :category }
1587
+ its(:to_a) { is_expected.to eq(
1588
+ [1, 2, 1, 4, 10, Float::NAN, 10, Float::NAN]) }
1589
+ end
1590
+ end
1591
+ end
1592
+
1593
+ describe DaruLite::DataFrame, "categorical" do
1594
+ context "#to_category" do
1595
+ let(:df) do
1596
+ DaruLite::DataFrame.new({
1597
+ a: [1, 2, 3, 4, 5],
1598
+ b: ['first', 'second', 'first', 'second', 'third'],
1599
+ c: ['a', 'b', 'a', 'b', nil]
1600
+ })
1601
+ end
1602
+ before { df.to_category :b, :c }
1603
+ subject { df }
1604
+
1605
+ it { is_expected.to be_a DaruLite::DataFrame }
1606
+ its(:'b.type') { is_expected.to eq :category }
1607
+ its(:'c.type') { is_expected.to eq :category }
1608
+ its(:'a.count') { is_expected.to eq 5 }
1609
+ its(:'c.count') { is_expected.to eq 5 }
1610
+ it { expect(df.c.count('a')).to eq 2 }
1611
+ it { expect(df.c.count(nil)).to eq 1 }
1612
+ end
1613
+
1614
+ context "#interact_code" do
1615
+ context "two vectors" do
1616
+ let(:df) do
1617
+ DaruLite::DataFrame.new({
1618
+ a: [1, 2, 3, 4, 5],
1619
+ b: ['first', 'second', 'first', 'second', 'third'],
1620
+ c: ['a', 'b', 'a', 'b', 'c']
1621
+ })
1622
+ end
1623
+ before do
1624
+ df.to_category :b, :c
1625
+ df[:b].categories = ['first', 'second', 'third']
1626
+ df[:c].categories = ['a', 'b', 'c']
1627
+ end
1628
+
1629
+ context "both full" do
1630
+ subject { df.interact_code [:b, :c], [true, true] }
1631
+
1632
+ it { is_expected.to be_a DaruLite::DataFrame }
1633
+ its(:shape) { is_expected.to eq [5, 9] }
1634
+ it { expect(subject['b_first:c_a'].to_a).to eq [1, 0, 1, 0, 0] }
1635
+ it { expect(subject['b_first:c_b'].to_a).to eq [0, 0, 0, 0, 0] }
1636
+ it { expect(subject['b_first:c_c'].to_a).to eq [0, 0, 0, 0, 0] }
1637
+ it { expect(subject['b_second:c_a'].to_a).to eq [0, 0, 0, 0, 0] }
1638
+ it { expect(subject['b_second:c_b'].to_a).to eq [0, 1, 0, 1, 0] }
1639
+ it { expect(subject['b_second:c_c'].to_a).to eq [0, 0, 0, 0, 0] }
1640
+ it { expect(subject['b_third:c_a'].to_a).to eq [0, 0, 0, 0, 0] }
1641
+ it { expect(subject['b_third:c_b'].to_a).to eq [0, 0, 0, 0, 0] }
1642
+ it { expect(subject['b_third:c_c'].to_a).to eq [0, 0, 0, 0, 1] }
1643
+ end
1644
+
1645
+ context "one full" do
1646
+ subject { df.interact_code [:b, :c], [true, false] }
1647
+
1648
+ it { is_expected.to be_a DaruLite::DataFrame }
1649
+ its(:shape) { is_expected.to eq [5, 6] }
1650
+ it { expect(subject['b_first:c_b'].to_a).to eq [0, 0, 0, 0, 0] }
1651
+ it { expect(subject['b_first:c_c'].to_a).to eq [0, 0, 0, 0, 0] }
1652
+ it { expect(subject['b_second:c_b'].to_a).to eq [0, 1, 0, 1, 0] }
1653
+ it { expect(subject['b_second:c_c'].to_a).to eq [0, 0, 0, 0, 0] }
1654
+ it { expect(subject['b_third:c_b'].to_a).to eq [0, 0, 0, 0, 0] }
1655
+ it { expect(subject['b_third:c_c'].to_a).to eq [0, 0, 0, 0, 1] }
1656
+ end
1657
+
1658
+ context "none full" do
1659
+ subject { df.interact_code [:b, :c], [false, false] }
1660
+
1661
+ it { is_expected.to be_a DaruLite::DataFrame }
1662
+ its(:shape) { is_expected.to eq [5, 4] }
1663
+ it { expect(subject['b_second:c_b'].to_a).to eq [0, 1, 0, 1, 0] }
1664
+ it { expect(subject['b_second:c_c'].to_a).to eq [0, 0, 0, 0, 0] }
1665
+ it { expect(subject['b_third:c_b'].to_a).to eq [0, 0, 0, 0, 0] }
1666
+ it { expect(subject['b_third:c_c'].to_a).to eq [0, 0, 0, 0, 1] }
1667
+ end
1668
+ end
1669
+
1670
+ context "more than two vectors" do
1671
+ let(:df) do
1672
+ DaruLite::DataFrame.new({
1673
+ a: [1, 1, 2],
1674
+ b: [2, 2, 3],
1675
+ c: [3, 3, 4]
1676
+ })
1677
+ end
1678
+ before { df.to_category :a, :b, :c }
1679
+ subject { df.interact_code [:a, :b, :c], [false, false, true] }
1680
+
1681
+ it { is_expected.to be_a DaruLite::DataFrame }
1682
+ its(:shape) { is_expected.to eq [3, 2] }
1683
+ it { expect(subject['a_2:b_3:c_3'].to_a).to eq [0, 0, 0] }
1684
+ it { expect(subject['a_2:b_3:c_4'].to_a).to eq [0, 0, 1] }
1685
+ end
1686
+ end
1687
+
1688
+ context "#sort!" do
1689
+ let(:df) do
1690
+ DaruLite::DataFrame.new({
1691
+ a: [1, 2, 1, 4, 5],
1692
+ b: ['II', 'I', 'III', 'II', 'I'],
1693
+ })
1694
+ end
1695
+ before do
1696
+ df[:b] = df[:b].to_category ordereed: true, categories: ['I', 'II', 'III']
1697
+ df.sort! [:a, :b]
1698
+ end
1699
+ subject { df }
1700
+
1701
+ its(:shape) { is_expected.to eq [5, 2] }
1702
+ its(:'a.to_a') { is_expected.to eq [1, 1, 2, 4, 5] }
1703
+ its(:'b.to_a') { is_expected.to eq ['II', 'III', 'I', 'II', 'I'] }
1704
+ end
1705
+
1706
+ context "#split_by_category" do
1707
+ let(:df) do
1708
+ DaruLite::DataFrame.new({
1709
+ a: [1, 2, 3, 4, 5, 6, 7],
1710
+ b: [3, 2, 2, 35, 3, 2, 5],
1711
+ cat: [:I, :II, :I, :III, :I, :III, :II]
1712
+ })
1713
+ end
1714
+ let(:df1) do
1715
+ DaruLite::DataFrame.new({
1716
+ a: [1, 3, 5],
1717
+ b: [3, 2, 3]
1718
+ }, name: :I, index: [0, 2, 4])
1719
+ end
1720
+ let(:df2) do
1721
+ DaruLite::DataFrame.new({
1722
+ a: [2, 7],
1723
+ b: [2, 5]
1724
+ }, name: :II, index: [1, 6])
1725
+ end
1726
+ let(:df3) do
1727
+ DaruLite::DataFrame.new({
1728
+ a: [4, 6],
1729
+ b: [35, 2]
1730
+ }, name: :III, index: [3, 5])
1731
+ end
1732
+ before { df.to_category :cat }
1733
+ subject { df.split_by_category :cat }
1734
+
1735
+ it { is_expected.to be_a Array }
1736
+ its(:size) { is_expected.to eq 3 }
1737
+ its(:first) { is_expected.to eq df1 }
1738
+ it { expect(subject[1]).to eq df2 }
1739
+ its(:last) { is_expected.to eq df3 }
1740
+ end
1741
+ end