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
@@ -0,0 +1,8 @@
1
+ describe Daru::ArrayHelper do
2
+ context '#recode_repeated' do
3
+ let(:source) { [1,'a',1,'a','b',:c,2] }
4
+ subject { described_class.recode_repeated(source) }
5
+
6
+ it { is_expected.to eq ['1_1','a_1', '1_2','a_2','b',:c,2] }
7
+ end
8
+ end
@@ -0,0 +1,168 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Daru::CategoricalIndex do
4
+ context "#pos" do
5
+ context "when the category is non-numeric" do
6
+ let(:idx) { described_class.new [:a, :b, :a, :a, :c] }
7
+
8
+ context "single category" do
9
+ subject { idx.pos :a }
10
+
11
+ it { is_expected.to eq [0, 2, 3] }
12
+ end
13
+
14
+ context "multiple categories" do
15
+ subject { idx.pos :a, :c }
16
+
17
+ it { is_expected.to eq [0, 2, 3, 4] }
18
+ end
19
+
20
+ context "invalid category" do
21
+ it { expect { idx.pos :e }.to raise_error IndexError }
22
+ end
23
+
24
+ context "positional index" do
25
+ it { expect(idx.pos 0).to eq 0 }
26
+ end
27
+
28
+ context "invalid positional index" do
29
+ it { expect { idx.pos 5 }.to raise_error IndexError }
30
+ end
31
+
32
+ context "multiple positional indexes" do
33
+ subject { idx.pos 0, 1, 2 }
34
+
35
+ it { is_expected.to be_a Array }
36
+ its(:size) { is_expected.to eq 3 }
37
+ it { is_expected.to eq [0, 1, 2] }
38
+ end
39
+ end
40
+
41
+ context "when the category is numeric" do
42
+ let(:idx) { described_class.new [0, 1, 0, 0, 2] }
43
+
44
+ context "first preference to category" do
45
+ subject { idx.pos 0 }
46
+
47
+ it { is_expected.to be_a Array }
48
+ its(:size) { is_expected.to eq 3 }
49
+ it { is_expected.to eq [0, 2, 3] }
50
+ end
51
+
52
+ context "second preference to positional index" do
53
+ subject { idx.pos 3 }
54
+
55
+ it { is_expected.to eq 3 }
56
+ end
57
+ end
58
+ end
59
+
60
+ context "#subset" do
61
+ let(:idx) { described_class.new [:a, 1, :a, 1, :c] }
62
+
63
+ context "single index" do
64
+ context "multiple instances" do
65
+ subject { idx.subset :a }
66
+
67
+ it { is_expected.to be_a described_class }
68
+ its(:size) { is_expected.to eq 2 }
69
+ its(:to_a) { is_expected.to eq [:a, :a] }
70
+ end
71
+ end
72
+
73
+ context "multiple indexes" do
74
+ subject { idx.subset :a, 1 }
75
+
76
+ it { is_expected.to be_a described_class }
77
+ its(:size) { is_expected.to eq 4 }
78
+ its(:to_a) { is_expected.to eq [:a, 1, :a, 1] }
79
+ end
80
+
81
+ context "multiple positional indexes" do
82
+ subject { idx.subset 0, 2 }
83
+
84
+ it { is_expected.to be_a described_class }
85
+ its(:size) { is_expected.to eq 2 }
86
+ its(:to_a) { is_expected.to eq [:a, :a] }
87
+ end
88
+ end
89
+
90
+ context "#at" do
91
+ let(:idx) { described_class.new [:a, :a, :a, 1, :c] }
92
+
93
+ context "single position" do
94
+ it { expect(idx.at 1).to eq :a }
95
+ end
96
+
97
+ context "multiple positions" do
98
+ subject { idx.at 0, 2, 3 }
99
+
100
+ it { is_expected.to be_a described_class }
101
+ its(:size) { is_expected.to eq 3 }
102
+ its(:to_a) { is_expected.to eq [:a, :a, 1] }
103
+ end
104
+
105
+ context "range" do
106
+ subject { idx.at 2..3 }
107
+
108
+ it { is_expected.to be_a described_class }
109
+ its(:size) { is_expected.to eq 2 }
110
+ its(:to_a) { is_expected.to eq [:a, 1] }
111
+ end
112
+
113
+ context "range with negative integers" do
114
+ subject { idx.at 2..-2 }
115
+
116
+ it { is_expected.to be_a described_class }
117
+ its(:size) { is_expected.to eq 2 }
118
+ its(:to_a) { is_expected.to eq [:a, 1] }
119
+ end
120
+
121
+ context "rangle with single element" do
122
+ subject { idx.at 2..2 }
123
+
124
+ it { is_expected.to be_a described_class }
125
+ its(:size) { is_expected.to eq 1 }
126
+ its(:to_a) { is_expected.to eq [:a] }
127
+ end
128
+
129
+ context "invalid position" do
130
+ it { expect { idx.at 5 }.to raise_error IndexError }
131
+ end
132
+
133
+ context "invalid positions" do
134
+ it { expect { idx.at 2, 5 }.to raise_error IndexError }
135
+ end
136
+ end
137
+
138
+ context "#add" do
139
+ let(:idx) { described_class.new [:a, 1, :a, 1] }
140
+
141
+ context "single index" do
142
+ subject { idx.add :c }
143
+
144
+ its(:to_a) { is_expected.to eq [:a, 1, :a, 1, :c] }
145
+ end
146
+
147
+ context "multiple indexes" do
148
+ subject { idx.add :c, :d }
149
+
150
+ its(:to_a) { is_expected.to eq [:a, 1, :a, 1, :c, :d] }
151
+ end
152
+ end
153
+
154
+ context "#valid?" do
155
+ let(:idx) { described_class.new [:a, 1, :a, 1] }
156
+
157
+ context "single index" do
158
+ it { expect(idx.valid? :a).to eq true }
159
+ it { expect(idx.valid? 2).to eq true }
160
+ it { expect(idx.valid? 4).to eq false }
161
+ end
162
+
163
+ context "multiple indexes" do
164
+ it { expect(idx.valid? :a, 1).to eq true }
165
+ it { expect(idx.valid? :a, 1, 5).to eq false }
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,283 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Daru::Index do
4
+ context ".new" do
5
+ it "creates an Index object if Index-like data is supplied" do
6
+ i = Daru::Index.new [:one, 'one', 1, 2, :two]
7
+ expect(i.class).to eq(Daru::Index)
8
+ expect(i.to_a) .to eq([:one, 'one', 1, 2, :two])
9
+ end
10
+
11
+ it "creates a MultiIndex if tuples are supplied" do
12
+ i = Daru::Index.new([
13
+ [:b,:one,:bar],
14
+ [:b,:two,:bar],
15
+ [:b,:two,:baz],
16
+ [:b,:one,:foo]
17
+ ])
18
+
19
+ expect(i.class).to eq(Daru::MultiIndex)
20
+ expect(i.levels).to eq([[:b], [:one, :two], [:bar, :baz, :foo]])
21
+ expect(i.labels).to eq([[0,0,0,0],[0,1,1,0],[0,0,1,2]])
22
+ end
23
+
24
+ it "creates DateTimeIndex if date-like objects specified" do
25
+ i = Daru::Index.new([
26
+ DateTime.new(2012,2,4), DateTime.new(2012,2,5), DateTime.new(2012,2,6)])
27
+ expect(i.class).to eq(Daru::DateTimeIndex)
28
+ expect(i.to_a).to eq([DateTime.new(2012,2,4), DateTime.new(2012,2,5), DateTime.new(2012,2,6)])
29
+ expect(i.frequency).to eq('D')
30
+ end
31
+ end
32
+
33
+ context "#initialize" do
34
+ it "creates an Index from Array" do
35
+ idx = Daru::Index.new ['speaker', 'mic', 'guitar', 'amp']
36
+
37
+ expect(idx.to_a).to eq(['speaker', 'mic', 'guitar', 'amp'])
38
+ end
39
+
40
+ it "creates an Index from Range" do
41
+ idx = Daru::Index.new 1..5
42
+
43
+ expect(idx).to eq(Daru::Index.new [1, 2, 3, 4, 5])
44
+ end
45
+
46
+ it "raises ArgumentError on invalid input type" do
47
+ expect { Daru::Index.new 'foo' }.to raise_error ArgumentError
48
+ end
49
+
50
+ it "accepts all sorts of objects for Indexing" do
51
+ idx = Daru::Index.new [:a, 'a', :hello, '23', 23]
52
+
53
+ expect(idx.to_a).to eq([:a, 'a', :hello, '23', 23])
54
+ end
55
+ end
56
+
57
+ context '#keys' do
58
+ subject(:idx) { Daru::Index.new ['speaker', 'mic', 'guitar', 'amp'] }
59
+
60
+ it 'returns key by position' do
61
+ expect(idx.key(2)).to eq 'guitar'
62
+ end
63
+
64
+ it 'returns nil on too large pos' do
65
+ expect(idx.key(20)).to be_nil
66
+ end
67
+
68
+ it 'returns nil on wrong arg type' do
69
+ expect(idx.key(nil)).to be_nil
70
+ end
71
+ end
72
+
73
+ context "#size" do
74
+ it "correctly returns the size of the index" do
75
+ idx = Daru::Index.new ['speaker', 'mic', 'guitar', 'amp']
76
+
77
+ expect(idx.size).to eq(4)
78
+ end
79
+ end
80
+
81
+ context "#valid?" do
82
+ let(:idx) { Daru::Index.new [:a, :b, :c] }
83
+
84
+ context "single index" do
85
+ it { expect(idx.valid? 2).to eq true }
86
+ it { expect(idx.valid? :d).to eq false }
87
+ end
88
+
89
+ context "multiple indexes" do
90
+ it { expect(idx.valid? :a, 1).to eq true }
91
+ it { expect(idx.valid? :a, 3).to eq false }
92
+ end
93
+ end
94
+
95
+ context '#inspect' do
96
+ context 'small index' do
97
+ subject { Daru::Index.new ['one', 'two', 'three'] }
98
+ its(:inspect) { is_expected.to eq "#<Daru::Index(3): {one, two, three}>" }
99
+ end
100
+
101
+ context 'large index' do
102
+ subject { Daru::Index.new ('a'..'z').to_a }
103
+ its(:inspect) { is_expected.to eq "#<Daru::Index(26): {a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t ... z}>" }
104
+ end
105
+ end
106
+
107
+ context "#&" do
108
+ before :each do
109
+ @left = Daru::Index.new [:miles, :geddy, :eric]
110
+ @right = Daru::Index.new [:geddy, :richie, :miles]
111
+ end
112
+
113
+ it "intersects 2 indexes and returns an Index" do
114
+ expect(@left & @right).to eq([:miles, :geddy].to_index)
115
+ end
116
+
117
+ it "intersects an Index and an Array to return an Index" do
118
+ expect(@left & [:bob, :geddy, :richie]).to eq([:geddy].to_index)
119
+ end
120
+ end
121
+
122
+ context "#|" do
123
+ before :each do
124
+ @left = Daru::Index.new [:miles, :geddy, :eric]
125
+ @right = Daru::Index.new [:bob, :jimi, :richie]
126
+ end
127
+
128
+ it "unions 2 indexes and returns an Index" do
129
+ expect(@left | @right).to eq([:miles, :geddy, :eric, :bob, :jimi, :richie].to_index)
130
+ end
131
+
132
+ it "unions an Index and an Array to return an Index" do
133
+ expect(@left | [:bob, :jimi, :richie]).to eq([:miles, :geddy, :eric,
134
+ :bob, :jimi, :richie].to_index)
135
+ end
136
+ end
137
+
138
+ context "#[]" do
139
+ before do
140
+ @id = Daru::Index.new [:one, :two, :three, :four, :five, :six, :seven]
141
+ @mixed_id = Daru::Index.new ['a','b','c',:d,:a,8,3,5]
142
+ end
143
+
144
+ it "works with ranges" do
145
+ expect(@id[:two..:five]).to eq(Daru::Index.new([:two, :three, :four, :five]))
146
+
147
+ expect(@mixed_id['a'..'c']).to eq(Daru::Index.new(['a','b','c']))
148
+
149
+ # If both start and end are numbers then refer to numerical indexes
150
+ expect(@mixed_id[0..2]).to eq(Daru::Index.new(['a','b','c']))
151
+
152
+ # If atleast one is a number then refer to actual indexing
153
+ expect(@mixed_id.slice('b',8)).to eq(Daru::Index.new(['b','c',:d,:a,8]))
154
+ end
155
+
156
+ it "returns multiple keys if specified multiple indices" do
157
+ expect(@id[0,1,3,4]).to eq(Daru::Index.new([:one, :two, :four, :five]))
158
+ expect(@mixed_id[0,5,3,2]).to eq(Daru::Index.new(['a', 8, :d, 'c']))
159
+ end
160
+
161
+ it "returns correct index position for non-numeric index" do
162
+ expect(@id[:four]).to eq(3)
163
+ expect(@id[3]).to eq(3)
164
+ end
165
+
166
+ it "returns correct index position for mixed index" do
167
+ expect(@mixed_id[8]).to eq(5)
168
+ expect(@mixed_id['c']).to eq(2)
169
+ end
170
+ end
171
+
172
+ context "#pos" do
173
+ let(:idx) { described_class.new [:a, :b, 1, 2] }
174
+
175
+ context "single index" do
176
+ it { expect(idx.pos :a).to eq 0 }
177
+ end
178
+
179
+ context "multiple indexes" do
180
+ subject { idx.pos :a, 1 }
181
+
182
+ it { is_expected.to be_a Array }
183
+ its(:size) { is_expected.to eq 2 }
184
+ it { is_expected.to eq [0, 2] }
185
+ end
186
+
187
+ context "single positional index" do
188
+ it { expect(idx.pos 0).to eq 0 }
189
+ end
190
+
191
+ context "multiple positional index" do
192
+ subject { idx.pos 0, 3 }
193
+
194
+ it { is_expected.to be_a Array }
195
+ its(:size) { is_expected.to eq 2 }
196
+ it { is_expected.to eq [0, 3] }
197
+ end
198
+
199
+ context "range" do
200
+ subject { idx.pos 1..3 }
201
+
202
+ it { is_expected.to be_a Array }
203
+ its(:size) { is_expected.to eq 3 }
204
+ it { is_expected.to eq [1, 2, 3] }
205
+ end
206
+ end
207
+
208
+ context "#subset" do
209
+ let(:idx) { described_class.new [:a, :b, 1, 2] }
210
+
211
+ context "multiple indexes" do
212
+ subject { idx.subset :a, 1 }
213
+
214
+ it { is_expected.to be_a described_class }
215
+ its(:size) { is_expected.to eq 2 }
216
+ its(:to_a) { is_expected.to eq [:a, 1] }
217
+ end
218
+
219
+ context "multiple positional indexes" do
220
+ subject { idx.subset 0, 3 }
221
+
222
+ it { is_expected.to be_a described_class }
223
+ its(:size) { is_expected.to eq 2 }
224
+ its(:to_a) { is_expected.to eq [:a, 2] }
225
+ end
226
+
227
+ context "range" do
228
+ subject { idx.subset 1..3 }
229
+
230
+ it { is_expected.to be_a described_class }
231
+ its(:size) { is_expected.to eq 3 }
232
+ its(:to_a) { is_expected.to eq [:b, 1, 2] }
233
+ end
234
+ end
235
+
236
+ context "#at" do
237
+ let(:idx) { described_class.new [:a, :b, 1 ] }
238
+
239
+ context "single position" do
240
+ it { expect(idx.at 1).to eq :b }
241
+ end
242
+
243
+ context "multiple positions" do
244
+ subject { idx.at 1, 2 }
245
+
246
+ it { is_expected.to be_a described_class }
247
+ its(:size) { is_expected.to eq 2 }
248
+ its(:to_a) { is_expected.to eq [:b, 1] }
249
+ end
250
+
251
+ context "range" do
252
+ subject { idx.at 1..2 }
253
+
254
+ it { is_expected.to be_a described_class }
255
+ its(:size) { is_expected.to eq 2 }
256
+ its(:to_a) { is_expected.to eq [:b, 1] }
257
+ end
258
+
259
+ context "range with negative integer" do
260
+ subject { idx.at 1..-1 }
261
+
262
+ it { is_expected.to be_a described_class }
263
+ its(:size) { is_expected.to eq 2 }
264
+ its(:to_a) { is_expected.to eq [:b, 1] }
265
+ end
266
+
267
+ context "rangle with single element" do
268
+ subject { idx.at 1..1 }
269
+
270
+ it { is_expected.to be_a described_class }
271
+ its(:size) { is_expected.to eq 1 }
272
+ its(:to_a) { is_expected.to eq [:b] }
273
+ end
274
+
275
+ context "invalid position" do
276
+ it { expect { idx.at 3 }.to raise_error IndexError }
277
+ end
278
+
279
+ context "invalid positions" do
280
+ it { expect { idx.at 2, 3 }.to raise_error IndexError }
281
+ end
282
+ end
283
+ end