daru 0.1.4.1 → 0.1.5

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 (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