daru 0.1.4.1 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/.travis.yml +3 -0
  4. data/CONTRIBUTING.md +27 -3
  5. data/Guardfile +7 -0
  6. data/History.md +39 -1
  7. data/README.md +1 -1
  8. data/daru.gemspec +9 -2
  9. data/lib/daru.rb +4 -1
  10. data/lib/daru/accessors/gsl_wrapper.rb +93 -91
  11. data/lib/daru/accessors/nmatrix_wrapper.rb +109 -107
  12. data/lib/daru/category.rb +22 -15
  13. data/lib/daru/core/group_by.rb +13 -2
  14. data/lib/daru/core/merge.rb +37 -31
  15. data/lib/daru/core/query.rb +10 -2
  16. data/lib/daru/dataframe.rb +95 -34
  17. data/lib/daru/date_time/index.rb +15 -16
  18. data/lib/daru/date_time/offsets.rb +14 -11
  19. data/lib/daru/formatters/table.rb +2 -2
  20. data/lib/daru/index/categorical_index.rb +201 -0
  21. data/lib/daru/index/index.rb +289 -0
  22. data/lib/daru/index/multi_index.rb +266 -0
  23. data/lib/daru/maths/statistics/vector.rb +13 -9
  24. data/lib/daru/monkeys.rb +0 -7
  25. data/lib/daru/plotting/gruff/category.rb +1 -0
  26. data/lib/daru/plotting/gruff/dataframe.rb +3 -3
  27. data/lib/daru/plotting/nyaplot/dataframe.rb +1 -1
  28. data/lib/daru/vector.rb +36 -21
  29. data/lib/daru/version.rb +1 -1
  30. data/spec/accessors/array_wrapper_spec.rb +3 -0
  31. data/spec/accessors/{wrappers_spec.rb → gsl_wrapper_spec.rb} +0 -35
  32. data/spec/accessors/nmatrix_wrapper_spec.rb +32 -0
  33. data/spec/{categorical_spec.rb → category_spec.rb} +3 -0
  34. data/spec/core/group_by_spec.rb +17 -1
  35. data/spec/core/merge_spec.rb +38 -1
  36. data/spec/core/query_spec.rb +5 -0
  37. data/spec/dataframe_spec.rb +230 -57
  38. data/spec/date_time/offsets_spec.rb +84 -3
  39. data/spec/formatters/table_formatter_spec.rb +9 -0
  40. data/spec/index/categorical_index_spec.rb +2 -0
  41. data/spec/index/index_spec.rb +17 -2
  42. data/spec/{math → maths}/arithmetic/dataframe_spec.rb +0 -0
  43. data/spec/{math → maths}/arithmetic/vector_spec.rb +0 -0
  44. data/spec/{math → maths}/statistics/dataframe_spec.rb +1 -1
  45. data/spec/{math → maths}/statistics/vector_spec.rb +7 -12
  46. data/spec/plotting/gruff/category_spec.rb +44 -0
  47. data/spec/plotting/gruff/dataframe_spec.rb +84 -0
  48. data/spec/plotting/gruff/vector_spec.rb +70 -0
  49. data/spec/plotting/nyaplot/category_spec.rb +51 -0
  50. data/spec/plotting/{dataframe_spec.rb → nyaplot/dataframe_spec.rb} +0 -83
  51. data/spec/plotting/nyaplot/vector_spec.rb +66 -0
  52. data/spec/spec_helper.rb +3 -2
  53. data/spec/vector_spec.rb +68 -1
  54. metadata +53 -24
  55. data/lib/daru/index.rb +0 -761
  56. data/spec/plotting/vector_spec.rb +0 -230
@@ -54,6 +54,72 @@ describe DateOffset do
54
54
  end
55
55
  end
56
56
 
57
+ describe NegativeDateOffset do
58
+ context "#initialize, #+, #-" do
59
+ it "creates a seconds offset" do
60
+ offset = -DateOffset.new(secs: 5)
61
+ expect(offset + DateTime.new(2012,3,4,23,4,05)).to eq(
62
+ DateTime.new(2012,3,4,23,4,00))
63
+ expect(offset - DateTime.new(2012,4,2,22,4,18)).to eq(
64
+ DateTime.new(2012,4,2,22,4,23))
65
+ end
66
+
67
+ it "creates a minutes offset" do
68
+ offset = -DateOffset.new(mins: 2)
69
+ expect(offset + DateTime.new(2013,4,5,12,47,44)).to eq(
70
+ DateTime.new(2013,4,5,12,45,44))
71
+ end
72
+
73
+ it "creates an hours offset" do
74
+ offset = -DateOffset.new(hours: 3)
75
+ expect(offset + DateTime.new(2024,3,2,3)).to eq(
76
+ DateTime.new(2024,3,2,0))
77
+ end
78
+
79
+ it "creates a days offset" do
80
+ offset = -DateOffset.new(days: 12)
81
+ expect(offset + DateTime.new(2012,5,16)).to eq(
82
+ DateTime.new(2012,5,4))
83
+ end
84
+
85
+ it "creates a weeks offset" do
86
+ offset = -DateOffset.new(weeks: 2)
87
+ expect(offset + DateTime.new(2012,3,15)).to eq(
88
+ DateTime.new(2012,3,1))
89
+ end
90
+
91
+ it "creates a months offset" do
92
+ offset = -DateOffset.new(months: 1)
93
+ expect(offset + DateTime.new(2012,4,1)).to eq(
94
+ DateTime.new(2012,3,1))
95
+ end
96
+
97
+ it "creates a years offset" do
98
+ offset = -DateOffset.new(years: 2)
99
+ expect(offset + DateTime.new(2014,5,30)).to eq(
100
+ DateTime.new(2012,5,30))
101
+ end
102
+
103
+ it "supports 'n' option to apply same offset multiple times" do
104
+ offset = -DateOffset.new(days: 3, n: 4)
105
+ expect(offset + DateTime.new(2012,3,13)).to eq(
106
+ DateTime.new(2012,3,1))
107
+ end
108
+ end
109
+
110
+ context "#-@" do
111
+ it "creates a date offset" do
112
+ negative_offset = -DateOffset.new(secs: 5)
113
+ offset = -negative_offset
114
+
115
+ expect(offset + DateTime.new(2012,3,4,23,4,0)).to eq(
116
+ DateTime.new(2012,3,4,23,4,5))
117
+ expect(offset - DateTime.new(2012,4,2,22,4,23)).to eq(
118
+ DateTime.new(2012,4,2,22,4,18))
119
+ end
120
+ end
121
+ end
122
+
57
123
  include Daru::Offsets
58
124
  describe Offsets do
59
125
  describe Second do
@@ -68,9 +134,6 @@ describe Offsets do
68
134
  end
69
135
  end
70
136
 
71
- context "#on_offset?" do
72
- end
73
-
74
137
  context "#-" do
75
138
  it "reduces by seconds" do
76
139
  expect(@offset - DateTime.new(2012,2,3,12,4,23)).to eq(
@@ -212,6 +275,10 @@ describe Offsets do
212
275
  it "returns true if date is on the offset" do
213
276
  expect(@offset.on_offset?(DateTime.new(2012,4,1))).to eq(true)
214
277
  end
278
+
279
+ it "returns false if date is not on the offset" do
280
+ expect(@offset.on_offset?(DateTime.new(2012,4,30))).to eq(false)
281
+ end
215
282
  end
216
283
 
217
284
  context "#-" do
@@ -266,6 +333,16 @@ describe Offsets do
266
333
  DateTime.new(2015,1,31))
267
334
  end
268
335
  end
336
+
337
+ context "#on_offset?" do
338
+ it "returns true if date is on the offset" do
339
+ expect(@offset.on_offset?(DateTime.new(2012,4,30))).to eq(true)
340
+ end
341
+
342
+ it "returns false if date is not on the offset" do
343
+ expect(@offset.on_offset?(DateTime.new(2012,4,1))).to eq(false)
344
+ end
345
+ end
269
346
  end
270
347
 
271
348
  describe Year do
@@ -305,6 +382,9 @@ describe Offsets do
305
382
  it "checks if date is on the offset" do
306
383
  expect(@offset.on_offset?(DateTime.new(2012,1,1))).to eq(
307
384
  true)
385
+
386
+ expect(@offset.on_offset?(DateTime.new(2012,12,31))).to eq(
387
+ false)
308
388
  end
309
389
  end
310
390
 
@@ -364,6 +444,7 @@ describe Offsets do
364
444
  context "#on_offset?" do
365
445
  it "reports whether on offset or not" do
366
446
  expect(@offset.on_offset?(DateTime.new(2012,12,31))).to eq(true)
447
+ expect(@offset.on_offset?(DateTime.new(2012,1,1))).to eq(false)
367
448
  end
368
449
  end
369
450
  end
@@ -74,6 +74,15 @@ describe Daru::Formatters::Table do
74
74
  }.unindent}
75
75
  end
76
76
 
77
+ context 'with empty data' do
78
+ let(:data) { [] }
79
+ let(:headers) { [] }
80
+ let(:row_headers) { [] }
81
+
82
+ it { is_expected.to eq '' }
83
+ end
84
+
85
+
77
86
  context '<more> threshold' do
78
87
  let(:options) { {threshold: threshold} }
79
88
  context 'lower than data size' do
@@ -142,12 +142,14 @@ describe Daru::CategoricalIndex do
142
142
  subject { idx.add :c }
143
143
 
144
144
  its(:to_a) { is_expected.to eq [:a, 1, :a, 1, :c] }
145
+ its(:categories) { is_expected.to eq [:a, 1, :c] }
145
146
  end
146
147
 
147
148
  context "multiple indexes" do
148
149
  subject { idx.add :c, :d }
149
150
 
150
151
  its(:to_a) { is_expected.to eq [:a, 1, :a, 1, :c, :d] }
152
+ its(:categories) { is_expected.to eq [:a, 1, :c, :d] }
151
153
  end
152
154
  end
153
155
 
@@ -54,7 +54,7 @@ describe Daru::Index do
54
54
  end
55
55
  end
56
56
 
57
- context '#keys' do
57
+ context '#key' do
58
58
  subject(:idx) { Daru::Index.new ['speaker', 'mic', 'guitar', 'amp'] }
59
59
 
60
60
  it 'returns key by position' do
@@ -280,4 +280,19 @@ describe Daru::Index do
280
280
  it { expect { idx.at 2, 3 }.to raise_error IndexError }
281
281
  end
282
282
  end
283
- end
283
+
284
+ # This context validate Daru::Index is like an enumerable.
285
+ # #map and #select are samples and we do not need tests all
286
+ # enumerable methods.
287
+ context "Enumerable" do
288
+ let(:idx) { Daru::Index.new ['speaker', 'mic', 'guitar', 'amp'] }
289
+
290
+ context "#map" do
291
+ it { expect(idx.map(&:upcase)).to eq(['SPEAKER', 'MIC', 'GUITAR', 'AMP']) }
292
+ end
293
+
294
+ context "select" do
295
+ it { expect(idx.select {|w| w[0] == 'g' }).to eq(['guitar']) }
296
+ end
297
+ end
298
+ end
@@ -48,7 +48,7 @@ describe Daru::DataFrame do
48
48
 
49
49
  context "#mode" do
50
50
  it "calculates mode of single level numeric only vectors and returns values in a Vector" do
51
- expect(@df.mode).to eq(Daru::Vector.new([2, 4, 20], index: [:d, :e, :f]))
51
+ expect(@df.mode).to eq(Daru::Vector.new([Daru::Vector.new([2,3]), Daru::Vector.new([4,6]), Daru::Vector.new([20,30])], index: [:d, :e, :f]))
52
52
  end
53
53
  end
54
54
 
@@ -103,10 +103,15 @@ describe Daru::Vector do
103
103
  end
104
104
 
105
105
  context "#mode" do
106
- it "returns the mode" do
106
+ it "returns the single modal value as a numeric" do
107
107
  mode_test_example = Daru::Vector.new [1,2,3,2,4,4,4,4], dtype: dtype
108
108
  expect(mode_test_example.mode).to eq(4)
109
109
  end
110
+
111
+ it "returns multiple modal values as a vector" do
112
+ mode_test_example = Daru::Vector.new [1,2,2,2,3,2,4,4,4,4], dtype: dtype
113
+ expect(mode_test_example.mode).to eq(Daru::Vector.new [2,4], dtype: dtype)
114
+ end
110
115
  end
111
116
 
112
117
  context "#describe" do
@@ -230,18 +235,8 @@ describe Daru::Vector do
230
235
  end
231
236
 
232
237
  context "#frequencies" do
233
- it "calculates frequencies" do
234
- vector = Daru::Vector.new([5,5,5,5,5,6,6,7,8,9,10,1,2,3,4,nil,-99,-99])
235
- expect(vector.frequencies).to eq({
236
- 1=>1, 2=>1, 3=>1, 4=>1, 5=>5,
237
- 6=>2, 7=>1, 8=>1, 9=>1,10=>1, -99=>2
238
- })
239
- end
240
- end
241
-
242
- context "#freqs" do
243
238
  let(:vector) { Daru::Vector.new([5,5,5,5,5,6,6,7,8,9,10,1,2,3,4,nil,-99,-99]) }
244
- subject { vector.freqs }
239
+ subject { vector.frequencies }
245
240
  it { is_expected.to eq Daru::Vector.new(
246
241
  [5,2,1,1,1,1,1,1,1,1,2],
247
242
  index: [5,6,7,8,9,10,1,2,3,4,-99]
@@ -0,0 +1,44 @@
1
+ describe Daru::Vector, 'plotting category vector with gruff' do
2
+ before { Daru.plotting_library = :gruff }
3
+ let(:dv) { Daru::Vector.new [1, 2, 3], type: :category }
4
+
5
+ context 'bar' do
6
+ let(:plot) { instance_double 'Gruff::Bar' }
7
+ before { allow(Gruff::Bar).to receive(:new).and_return(plot) }
8
+ it 'plots bar graph' do
9
+ expect(plot).to receive :labels=
10
+ expect(plot).to receive :data
11
+ dv.plot type: :bar
12
+ end
13
+
14
+ it 'plots bar graph with block' do
15
+ expect(plot).to receive :labels=
16
+ expect(plot).to receive :data
17
+ expect(plot).to receive :title=
18
+ dv.plot(type: :bar) { |p| p.title = 'hello' }
19
+ end
20
+ end
21
+
22
+ context 'pie' do
23
+ let(:plot) { instance_double 'Gruff::Pie' }
24
+ before { allow(Gruff::Pie).to receive(:new).and_return(plot) }
25
+ it 'plots pie graph' do
26
+ expect(plot).to receive(:data).exactly(3).times
27
+ dv.plot type: :pie
28
+ end
29
+ end
30
+
31
+ context 'sidebar' do
32
+ let(:plot) { instance_double 'Gruff::SideBar' }
33
+ before { allow(Gruff::SideBar).to receive(:new).and_return(plot) }
34
+ it 'plots sidebar graph' do
35
+ expect(plot).to receive :labels=
36
+ expect(plot).to receive(:data).exactly(3).times
37
+ dv.plot type: :sidebar
38
+ end
39
+ end
40
+
41
+ context 'invalid type' do
42
+ it { expect { dv.plot type: :lol }.to raise_error ArgumentError }
43
+ end
44
+ end
@@ -0,0 +1,84 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Daru::DataFrame, 'plotting dataframe using gruff' do
4
+ before { Daru.plotting_library = :gruff }
5
+ let(:df) do
6
+ Daru::DataFrame.new({
7
+ a: [1, 3, 5, 2, 5, 0],
8
+ b: [1, 5, 2, 5, 1, 0],
9
+ c: [1, 6, 7, 2, 6, 0]
10
+ }, index: 'a'..'f')
11
+ end
12
+
13
+ context 'bar' do
14
+ let(:plot) { instance_double 'Gruff::Bar' }
15
+ before { allow(Gruff::Bar).to receive(:new).and_return(plot) }
16
+ it 'plots bar graph' do
17
+ expect(plot).to receive :labels=
18
+ expect(plot).to receive(:data).exactly(3).times
19
+ df.plot type: :bar
20
+ end
21
+
22
+ it 'plots bar graph with block' do
23
+ expect(plot).to receive :labels=
24
+ expect(plot).to receive(:data).exactly(3).times
25
+ expect(plot).to receive :title=
26
+ df.plot(type: :bar) { |p| p.title = 'hello' }
27
+ end
28
+
29
+ it 'plots with specified columns' do
30
+ expect(plot).to receive :labels=
31
+ expect(plot).to receive(:data).exactly(2).times
32
+ df.plot type: :bar, y: [:a, :b]
33
+ end
34
+ end
35
+
36
+ context 'line' do
37
+ let(:plot) { instance_double 'Gruff::Line' }
38
+ before { allow(Gruff::Line).to receive(:new).and_return(plot) }
39
+ it 'plots line graph' do
40
+ expect(plot).to receive :labels=
41
+ expect(plot).to receive(:data).exactly(3).times
42
+ df.plot type: :line
43
+ end
44
+ end
45
+
46
+ context 'scatter' do
47
+ let(:plot) { instance_double 'Gruff::Scatter' }
48
+ before { allow(Gruff::Scatter).to receive(:new).and_return(plot) }
49
+ it 'plots scatter graph' do
50
+ expect(plot).to receive(:data).exactly(3).times
51
+ df.plot type: :scatter
52
+ end
53
+
54
+ it 'plots with specified columns' do
55
+ expect(plot).to receive(:data).exactly(1).times
56
+ df.plot type: :scatter, x: :c, y: :a
57
+ end
58
+ end
59
+
60
+ context 'invalid type' do
61
+ it { expect { df.plot type: :lol }.to raise_error ArgumentError }
62
+ end
63
+ end
64
+
65
+ describe Daru::DataFrame, 'dataframe category plotting with gruff' do
66
+ before { Daru.plotting_library = :gruff }
67
+ let(:df) do
68
+ Daru::DataFrame.new({
69
+ a: [1, 3, 5, 2, 5, 0],
70
+ b: [1, 5, 2, 5, 1, 0],
71
+ c: [:a, :b, :a, :a, :b, :a]
72
+ }, index: 'a'..'f')
73
+ end
74
+ before { df.to_category :c }
75
+
76
+ context 'scatter' do
77
+ let(:plot) { instance_double 'Gruff::Scatter' }
78
+ before { allow(Gruff::Scatter).to receive(:new).and_return(plot) }
79
+ it 'plots scatter plot categorized by category vector' do
80
+ expect(plot).to receive(:data).exactly(2).times
81
+ df.plot type: :scatter, x: :a, y: :b, categorized: { by: :c }
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Daru::Vector, 'plotting vector with gruff' do
4
+ let(:dv) { Daru::Vector.new [1, 2, 3] }
5
+ before { Daru.plotting_library = :gruff }
6
+
7
+ context 'line' do
8
+ let(:plot) { instance_double 'Gruff::Line' }
9
+ before { allow(Gruff::Line).to receive(:new).and_return(plot) }
10
+
11
+ it 'plots line graph without block' do
12
+ expect(plot).to receive(:labels=)
13
+ expect(plot).to receive(:data)
14
+ dv.plot type: :line
15
+ end
16
+
17
+ it 'plots line graph with block' do
18
+ expect(plot).to receive :labels=
19
+ expect(plot).to receive :data
20
+ expect(plot).to receive :title=
21
+ dv.plot(type: :line) { |p| p.title = 'hello' }
22
+ end
23
+ end
24
+
25
+ context 'bar' do
26
+ let(:plot) { instance_double 'Gruff::Bar' }
27
+ before { allow(Gruff::Bar).to receive(:new).and_return(plot) }
28
+
29
+ it 'plots bar graph' do
30
+ expect(plot).to receive :labels=
31
+ expect(plot).to receive :data
32
+ dv.plot type: :bar
33
+ end
34
+ end
35
+
36
+ context 'pie' do
37
+ let(:plot) { instance_double 'Gruff::Pie' }
38
+ before { allow(Gruff::Pie).to receive(:new).and_return(plot) }
39
+
40
+ it 'plots pie graph' do
41
+ expect(plot).to receive(:data).exactly(3).times
42
+ dv.plot type: :pie
43
+ end
44
+ end
45
+
46
+ context 'scatter' do
47
+ let(:plot) { instance_double 'Gruff::Scatter' }
48
+ before { allow(Gruff::Scatter).to receive(:new).and_return(plot) }
49
+
50
+ it 'plots scatter graph' do
51
+ expect(plot).to receive :data
52
+ dv.plot type: :scatter
53
+ end
54
+ end
55
+
56
+ context 'sidebar' do
57
+ let(:plot) { instance_double 'Gruff::SideBar' }
58
+ before { allow(Gruff::SideBar).to receive(:new).and_return(plot) }
59
+
60
+ it 'plots sidebar' do
61
+ expect(plot).to receive :labels=
62
+ expect(plot).to receive(:data).exactly(3).times
63
+ dv.plot type: :sidebar
64
+ end
65
+ end
66
+
67
+ context 'invalid type' do
68
+ it { expect { dv.plot type: :lol }.to raise_error ArgumentError }
69
+ end
70
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Daru::Vector, 'plotting category' do
4
+ let(:plot) { instance_double('Nyaplot::Plot') }
5
+ let(:diagram) { instance_double('Nyaplot::Diagram') }
6
+ let(:dv) do
7
+ Daru::Vector.new ['III']*10 + ['II']*5 + ['I']*5,
8
+ type: :category,
9
+ categories: ['I', 'II', 'III']
10
+ end
11
+ before do
12
+ Daru.plotting_library = :nyaplot
13
+ allow(Nyaplot::Plot).to receive(:new).and_return(plot)
14
+ end
15
+ context 'bar' do
16
+ it 'plots bar graph taking a block' do
17
+ expect(plot).to receive(:add).with(:bar, ['I', 'II', 'III'], [5, 5, 10])
18
+ expect(plot).to receive :x_label
19
+ expect(plot).to receive :y_label
20
+ expect(plot).to receive(:show)
21
+ dv.plot(type: :bar) do |p|
22
+ p.x_label 'Categories'
23
+ p.y_label 'Frequency'
24
+ end
25
+ end
26
+
27
+ it 'plots bar graph without taking a block' do
28
+ expect(plot).to receive(:add).with(:bar, ["I", "II", "III"], [5, 5, 10])
29
+ expect(plot).to receive(:show)
30
+ dv.plot(type: :bar)
31
+ end
32
+
33
+ it 'plots bar graph with percentage' do
34
+ expect(plot).to receive(:add).with(:bar, ["I", "II", "III"], [25, 25, 50])
35
+ expect(plot).to receive(:yrange).with [0, 100]
36
+ expect(plot).to receive(:show)
37
+ dv.plot(type: :bar, method: :percentage)
38
+ end
39
+
40
+ it 'plots bar graph with fraction' do
41
+ expect(plot).to receive(:add).with(:bar, ["I", "II", "III"], [0.25, 0.25, 0.50])
42
+ expect(plot).to receive(:yrange).with [0, 1]
43
+ expect(plot).to receive(:show)
44
+ dv.plot(type: :bar, method: :fraction)
45
+ end
46
+ end
47
+
48
+ context 'other type' do
49
+ it { expect { dv.plot(type: :scatter) }.to raise_error ArgumentError }
50
+ end
51
+ end