daru 0.1.2 → 0.1.3

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rubocop.yml +99 -0
  4. data/.rubocop_todo.yml +44 -0
  5. data/.travis.yml +3 -1
  6. data/CONTRIBUTING.md +5 -1
  7. data/History.md +43 -0
  8. data/README.md +3 -4
  9. data/benchmarks/duplicating.rb +45 -0
  10. data/benchmarks/group_by.rb +7 -7
  11. data/benchmarks/joining.rb +52 -0
  12. data/benchmarks/sorting.rb +9 -2
  13. data/benchmarks/statistics.rb +39 -0
  14. data/daru.gemspec +4 -4
  15. data/lib/daru.rb +9 -9
  16. data/lib/daru/accessors/array_wrapper.rb +15 -11
  17. data/lib/daru/accessors/dataframe_by_row.rb +1 -1
  18. data/lib/daru/accessors/gsl_wrapper.rb +30 -19
  19. data/lib/daru/accessors/mdarray_wrapper.rb +1 -3
  20. data/lib/daru/accessors/nmatrix_wrapper.rb +15 -15
  21. data/lib/daru/core/group_by.rb +69 -16
  22. data/lib/daru/core/merge.rb +135 -151
  23. data/lib/daru/core/query.rb +9 -30
  24. data/lib/daru/dataframe.rb +476 -439
  25. data/lib/daru/date_time/index.rb +150 -137
  26. data/lib/daru/date_time/offsets.rb +45 -41
  27. data/lib/daru/extensions/rserve.rb +4 -4
  28. data/lib/daru/index.rb +88 -64
  29. data/lib/daru/io/io.rb +33 -34
  30. data/lib/daru/io/sql_data_source.rb +11 -11
  31. data/lib/daru/maths/arithmetic/dataframe.rb +19 -19
  32. data/lib/daru/maths/arithmetic/vector.rb +9 -14
  33. data/lib/daru/maths/statistics/dataframe.rb +89 -61
  34. data/lib/daru/maths/statistics/vector.rb +226 -97
  35. data/lib/daru/monkeys.rb +23 -30
  36. data/lib/daru/plotting/dataframe.rb +27 -28
  37. data/lib/daru/plotting/vector.rb +12 -13
  38. data/lib/daru/vector.rb +221 -330
  39. data/lib/daru/version.rb +2 -2
  40. data/spec/core/group_by_spec.rb +16 -0
  41. data/spec/core/merge_spec.rb +30 -14
  42. data/spec/dataframe_spec.rb +268 -14
  43. data/spec/index_spec.rb +23 -5
  44. data/spec/io/io_spec.rb +37 -16
  45. data/spec/math/statistics/dataframe_spec.rb +40 -8
  46. data/spec/math/statistics/vector_spec.rb +135 -10
  47. data/spec/monkeys_spec.rb +3 -3
  48. data/spec/vector_spec.rb +157 -25
  49. metadata +41 -21
@@ -37,6 +37,16 @@ describe Daru::Index do
37
37
  expect(idx.to_a).to eq(['speaker', 'mic', 'guitar', 'amp'])
38
38
  end
39
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
+
40
50
  it "accepts all sorts of objects for Indexing" do
41
51
  idx = Daru::Index.new [:a, 'a', :hello, '23', 23]
42
52
 
@@ -76,7 +86,7 @@ describe Daru::Index do
76
86
  context "#[]" do
77
87
  before do
78
88
  @id = Daru::Index.new [:one, :two, :three, :four, :five, :six, :seven]
79
- @mixed_id = Daru::Index.new ['a','b','c',:d,:a,0,3,5]
89
+ @mixed_id = Daru::Index.new ['a','b','c',:d,:a,8,3,5]
80
90
  end
81
91
 
82
92
  it "works with ranges" do
@@ -88,12 +98,12 @@ describe Daru::Index do
88
98
  expect(@mixed_id[0..2]).to eq(Daru::Index.new(['a','b','c']))
89
99
 
90
100
  # If atleast one is a number then refer to actual indexing
91
- expect(@mixed_id.slice('b',0)).to eq(Daru::Index.new(['b','c',:d,:a,0]))
101
+ expect(@mixed_id.slice('b',8)).to eq(Daru::Index.new(['b','c',:d,:a,8]))
92
102
  end
93
103
 
94
104
  it "returns multiple keys if specified multiple indices" do
95
- expect(@id[0,1,3,4]).to eq(Daru::Index.new([0,1,3,4]))
96
- expect(@mixed_id[0,5,3,2]).to eq(Daru::Index.new([5, 7, 6, 2]))
105
+ expect(@id[0,1,3,4]).to eq(Daru::Index.new([:one, :two, :four, :five]))
106
+ expect(@mixed_id[0,5,3,2]).to eq(Daru::Index.new(['a', 8, :d, 'c']))
97
107
  end
98
108
 
99
109
  it "returns correct index position for non-numeric index" do
@@ -102,7 +112,7 @@ describe Daru::Index do
102
112
  end
103
113
 
104
114
  it "returns correct index position for mixed index" do
105
- expect(@mixed_id[0]).to eq(5)
115
+ expect(@mixed_id[8]).to eq(5)
106
116
  expect(@mixed_id['c']).to eq(2)
107
117
  end
108
118
  end
@@ -204,6 +214,14 @@ describe Daru::MultiIndex do
204
214
  ]))
205
215
  end
206
216
 
217
+ it "raises error when specifying invalid index" do
218
+ expect { @multi_mi[:a, :three] }.to raise_error IndexError
219
+ expect { @multi_mi[:a, :one, :xyz] }.to raise_error IndexError
220
+ expect { @multi_mi[:x] }.to raise_error IndexError
221
+ expect { @multi_mi[:x, :one] }.to raise_error IndexError
222
+ expect { @multi_mi[:x, :one, :bar] }.to raise_error IndexError
223
+ end
224
+
207
225
  it "works with numerical first levels" do
208
226
  mi = Daru::MultiIndex.from_tuples([
209
227
  [2000, 'M'],
@@ -4,7 +4,7 @@ describe Daru::IO do
4
4
  describe Daru::DataFrame do
5
5
  context ".from_csv" do
6
6
  it "loads from a CSV file" do
7
- df = Daru::DataFrame.from_csv('spec/fixtures/matrix_test.csv',
7
+ df = Daru::DataFrame.from_csv('spec/fixtures/matrix_test.csv',
8
8
  col_sep: ' ', headers: true)
9
9
 
10
10
  df.vectors = [:image_resolution, :mls, :true_transform].to_index
@@ -15,7 +15,7 @@ describe Daru::IO do
15
15
 
16
16
  it "works properly for repeated headers" do
17
17
  df = Daru::DataFrame.from_csv('spec/fixtures/repeated_fields.csv',header_converters: :symbol)
18
- expect(df.vectors.to_a).to eq(['a1', 'age_1', 'age_2', 'city', 'id', 'name_1', 'name_2'])
18
+ expect(df.vectors.to_a).to eq(["id", "name_1", "age_1", "city", "a1", "name_2", "age_2"])
19
19
 
20
20
  age = Daru::Vector.new([3, 4, 5, 6, nil, 8])
21
21
  expect(df['age_2']).to eq(age)
@@ -29,20 +29,41 @@ describe Daru::IO do
29
29
  expect(y_ds).to be_within(0.001).of(y_expected)
30
30
  end
31
31
  end
32
+
33
+ it "follows the order of columns given in CSV" do
34
+ df = Daru::DataFrame.from_csv 'spec/fixtures/sales-funnel.csv'
35
+ expect(df.vectors.to_a).to eq(%W[Account Name Rep Manager Product Quantity Price Status])
36
+ end
32
37
  end
33
38
 
34
39
  context "#write_csv" do
35
- it "writes DataFrame to a CSV file" do
36
- df = Daru::DataFrame.new({
37
- 'a' => [1,2,3,4,5],
40
+ before do
41
+ @df = Daru::DataFrame.new({
42
+ 'a' => [1,2,3,4,5],
38
43
  'b' => [11,22,33,44,55],
39
44
  'c' => ['a', 'g', 4, 5,'addadf'],
40
45
  'd' => [nil, 23, 4,'a','ff']})
41
- t = Tempfile.new('data.csv')
42
- df.write_csv t.path
46
+ @tempfile = Tempfile.new('data.csv')
43
47
 
44
- expect(Daru::DataFrame.from_csv(t.path)).to eq(df)
45
48
  end
49
+
50
+ it "writes DataFrame to a CSV file" do
51
+ @df.write_csv @tempfile.path
52
+ expect(Daru::DataFrame.from_csv(@tempfile.path)).to eq(@df)
53
+ end
54
+
55
+ it "will write headers unless headers=false" do
56
+ @df.write_csv @tempfile.path
57
+ first_line = File.open(@tempfile.path, &:readline).chomp.split(',', -1)
58
+ expect(first_line).to eq @df.vectors.to_a
59
+ end
60
+
61
+ it "will not write headers when headers=false" do
62
+ @df.write_csv @tempfile.path, { headers: false }
63
+ first_line = File.open(@tempfile.path, &:readline).chomp.split(',', -1)
64
+ expect(first_line).to eq @df.head(1).map { |v| (v.first || '').to_s }
65
+ end
66
+
46
67
  end
47
68
 
48
69
  context ".from_excel" do
@@ -52,8 +73,8 @@ describe Daru::IO do
52
73
  age = Daru::Vector.new( [20, 23, 25, nil, 5.5, nil])
53
74
  city = Daru::Vector.new(['New York', 'London', 'London', 'Paris', 'Tome', nil])
54
75
  a1 = Daru::Vector.new(['a,b', 'b,c', 'a', nil, 'a,b,c', nil])
55
- @expected = Daru::DataFrame.new({
56
- :id => id, :name => name, :age => age, :city => city, :a1 => a1
76
+ @expected = Daru::DataFrame.new({
77
+ :id => id, :name => name, :age => age, :city => city, :a1 => a1
57
78
  }, order: [:id, :name, :age, :city, :a1])
58
79
  end
59
80
 
@@ -190,8 +211,8 @@ describe Daru::IO do
190
211
  df = Daru::DataFrame.new JSON.parse(json)
191
212
 
192
213
  expect(df.vectors).to eq([
193
- 'name', 'nativeName', 'tld', 'cca2', 'ccn3', 'cca3', 'currency', 'callingCode',
194
- 'capital', 'altSpellings', 'relevance', 'region', 'subregion', 'language',
214
+ 'name', 'nativeName', 'tld', 'cca2', 'ccn3', 'cca3', 'currency', 'callingCode',
215
+ 'capital', 'altSpellings', 'relevance', 'region', 'subregion', 'language',
195
216
  'languageCodes', 'translations', 'latlng', 'demonym', 'borders', 'area'].to_index)
196
217
 
197
218
  expect(df.row[0]['name']).to eq("Afghanistan")
@@ -208,9 +229,9 @@ describe Daru::IO do
208
229
 
209
230
  context "#save" do
210
231
  before do
211
- @data_frame = Daru::DataFrame.new({b: [11,12,13,14,15], a: [1,2,3,4,5],
212
- c: [11,22,33,44,55]},
213
- order: [:a, :b, :c],
232
+ @data_frame = Daru::DataFrame.new({b: [11,12,13,14,15], a: [1,2,3,4,5],
233
+ c: [11,22,33,44,55]},
234
+ order: [:a, :b, :c],
214
235
  index: [:one, :two, :three, :four, :five])
215
236
  end
216
237
 
@@ -235,7 +256,7 @@ describe Daru::IO do
235
256
  ALL_DTYPES.each do |dtype|
236
257
  it "saves to a file and returns the same Vector of type #{dtype}" do
237
258
  vector = Daru::Vector.new(
238
- [5, 5, 5, 5, 5, 6, 6, 7, 8, 9, 10, 1, 2, 3, 4, 11, -99, -99],
259
+ [5, 5, 5, 5, 5, 6, 6, 7, 8, 9, 10, 1, 2, 3, 4, 11, -99, -99],
239
260
  dtype: dtype)
240
261
  outfile = Tempfile.new('vector.vec')
241
262
  vector.save(outfile.path)
@@ -24,28 +24,40 @@ describe Daru::DataFrame do
24
24
  end
25
25
  end
26
26
 
27
+ context "#variance_sample" do
28
+ it "calculates variance of single level numeric only vectors and returns values in a Vector" do
29
+ expect(@df.variance_sample).to eq(Daru::Vector.new([4.0, 16.0, 400.0], index: [:d, :e, :f]))
30
+ end
31
+ end
32
+
27
33
  context "#std" do
28
- it "calculates standard deviation of single leavel numeric only vectors and returns values in a Vector" do
34
+ it "calculates standard deviation of single level numeric only vectors and returns values in a Vector" do
29
35
  expect(@df.std).to eq(Daru::Vector.new([2, 4, 20], index: [:d, :e, :f]))
30
36
  end
31
37
  end
32
38
 
33
39
  context "#sum" do
34
40
  it "calculates sum of single level numeric only vectors and returns values in a Vector" do
35
- # TODO - write tests
41
+ expect(@df.sum).to eq(Daru::Vector.new([33, 66, 330], index: [:d, :e, :f]))
36
42
  end
37
43
  end
38
44
 
39
45
  context "#count" do
40
- # TODO
46
+ it "counts number of non-nil single level numeric only vectors and returns values in a Vector" do
47
+ expect(@df.count).to eq(Daru::Vector.new([9, 9, 9], index: [:d, :e, :f]))
48
+ end
41
49
  end
42
50
 
43
51
  context "#mode" do
44
- # TODO
52
+ it "calculates mode of single level numeric only vectors and returns values in a Vector" do
53
+ expect(@df.mode).to eq(Daru::Vector.new([2, 4, 20], index: [:d, :e, :f]))
54
+ end
45
55
  end
46
56
 
47
57
  context "#median" do
48
- # TODO
58
+ it "calculates median of single level numeric only vectors and returns values in a Vector" do
59
+ expect(@df.median).to eq(Daru::Vector.new([3, 6, 30], index: [:d, :e, :f]))
60
+ end
49
61
  end
50
62
 
51
63
  context "#max" do
@@ -61,11 +73,21 @@ describe Daru::DataFrame do
61
73
  end
62
74
 
63
75
  context "#min" do
64
- # TODO
76
+ it "calculates mininum of single level numeric only vectors and returns values in a Vector" do
77
+ expect(@df.min).to eq(Daru::Vector.new([1, 2, 10], index: [:d, :e, :f]))
78
+ end
79
+ end
80
+
81
+ context "#range" do
82
+ it "calculates range of single level numeric only vectors and returns values in a Vector" do
83
+ expect(@df.range).to eq(Daru::Vector.new([6, 12, 60], index: [:d, :e, :f]))
84
+ end
65
85
  end
66
86
 
67
87
  context "#product" do
68
- # TODO
88
+ it "calculates product of single level numeric only vectors and returns values in a Vector" do
89
+ expect(@df.product).to eq(Daru::Vector.new([30240, 15482880, 30240000000000], index: [:d, :e, :f]))
90
+ end
69
91
  end
70
92
 
71
93
  context "#describe" do
@@ -79,6 +101,16 @@ describe Daru::DataFrame do
79
101
  end
80
102
  end
81
103
 
104
+ context "percent_change" do
105
+ it "calculates percent change of numeric vectors" do
106
+ expect(@df.percent_change.round(2)).to eq(Daru::DataFrame.new({
107
+ d: [nil, 1.0, 0.0, 0.5, 0.0, 0.33, 0.25, 0.2, 0.17],
108
+ e: [nil, 1.0, 0.0, 0.5, 0.0, 0.33, 0.25, 0.2, 0.17],
109
+ f: [nil, 1.0, 0.0, 0.5, 0.0, 0.33, 0.25, 0.2, 0.17] }
110
+ ))
111
+ end
112
+ end
113
+
82
114
  context "#cov" do
83
115
  it "calculates the variance covariance of the numeric vectors of DataFrame" do
84
116
  expect(@df.cov).to eq(Daru::DataFrame.new({
@@ -145,4 +177,4 @@ describe Daru::DataFrame do
145
177
  @df.standardize
146
178
  end
147
179
  end
148
- end
180
+ end
@@ -6,12 +6,15 @@ describe Daru::Vector do
6
6
  before do
7
7
  @dv = Daru::Vector.new [323, 11, 555, 666, 234, 21, 666, 343, 1, 2], dtype: dtype
8
8
  @dv_with_nils = Daru::Vector.new [323, 11, 555, nil, 666, 234, 21, 666, 343, nil, 1, 2]
9
+ @dv_with_missing = Daru::Vector.new [1, 2, 3, 3], missing_values: [3], dtype: dtype
10
+ @dv_with_all_missing = Daru::Vector.new [3, 3], missing_values: [3], dtype: dtype
9
11
  end
10
12
 
11
13
  context "#mean" do
12
14
  it "calculates mean" do
13
15
  expect(@dv.mean).to eq(282.2)
14
- expect(@dv_with_nils.mean).to eq(282.2)
16
+ expect(@dv_with_missing.mean).to eq(1.5)
17
+ expect(@dv_with_all_missing.mean).to eq(nil)
15
18
  end
16
19
  end
17
20
 
@@ -46,6 +49,22 @@ describe Daru::Vector do
46
49
  end
47
50
  end
48
51
 
52
+ context "#covariance_sample" do
53
+ it "calculates sample covariance" do
54
+ @dv_1 = Daru::Vector.new [323, 11, 555, 666, 234, 21, 666, 343, 1, 2]
55
+ @dv_2 = Daru::Vector.new [123, 22, 444, 555, 324, 21, 666, 434, 5, 8]
56
+ expect(@dv_1.covariance @dv_2).to be_within(0.00001).of(65603.62222)
57
+ end
58
+ end
59
+
60
+ context "#covariance_population" do
61
+ it "calculates population covariance" do
62
+ @dv_1 = Daru::Vector.new [323, 11, 555, 666, 234, 21, 666, 343, 1, 2]
63
+ @dv_2 = Daru::Vector.new [123, 22, 444, 555, 324, 21, 666, 434, 5, 8]
64
+ expect(@dv_1.covariance_population @dv_2).to be_within(0.01).of(59043.26)
65
+ end
66
+ end
67
+
49
68
  context "#sum_of_squared_deviation" do
50
69
  it "calculates sum of squared deviation" do
51
70
  expect(@dv.sum_of_squared_deviation).to eq(676069.6)
@@ -60,20 +79,44 @@ describe Daru::Vector do
60
79
 
61
80
  context "#max" do
62
81
  it "returns the max value" do
63
- @dv.max
82
+ expect(@dv.max).to eq(666)
64
83
  end
84
+
85
+ it "returns the max value without considering values set as missing" do
86
+ expect(@dv_with_missing.max).to eq(2)
87
+ end
88
+
89
+ it "returns nil when all values are set missing" do
90
+ expect(@dv_with_all_missing.max).to eq(nil)
91
+ end
65
92
  end
66
93
 
67
94
  context "#min" do
68
95
  it "returns the min value" do
69
- @dv.min
96
+ expect(@dv.min).to eq(1)
97
+ end
98
+
99
+ it "returns the min value without considering values set as missing" do
100
+ expect(@dv_with_missing.min).to eq(1)
70
101
  end
102
+
103
+ it "returns nil when all values are set missing" do
104
+ expect(@dv_with_all_missing.min).to eq(nil)
105
+ end
71
106
  end
72
107
 
73
108
  context "#sum" do
74
109
  it "returns the sum" do
75
- @dv.sum
110
+ expect(@dv.sum).to eq(2822)
111
+ end
112
+
113
+ it "returns the sum without considering values set as missing" do
114
+ expect(@dv_with_missing.sum).to eq(3)
76
115
  end
116
+
117
+ it "returns nil when all values are set missing" do
118
+ expect(@dv_with_all_missing.sum).to eq(nil)
119
+ end
77
120
  end
78
121
 
79
122
  context "#product" do
@@ -81,6 +124,14 @@ describe Daru::Vector do
81
124
  v = Daru::Vector.new [1, 2, 3, 4, 5], dtype: dtype
82
125
  expect(v.product).to eq(120)
83
126
  end
127
+
128
+ it "returns the product without considering values set as missing" do
129
+ expect(@dv_with_missing.product).to eq(2)
130
+ end
131
+
132
+ it "returns nil when all values are set missing" do
133
+ expect(@dv_with_all_missing.product).to eq(nil)
134
+ end
84
135
  end
85
136
 
86
137
  context "#median" do
@@ -91,7 +142,17 @@ describe Daru::Vector do
91
142
 
92
143
  context "#mode" do
93
144
  it "returns the mode" do
94
- @dv.mode
145
+ mode_test_example = Daru::Vector.new [1,2,3,2,4,4,4,4], dtype: dtype
146
+ expect(mode_test_example.mode).to eq(4)
147
+ end
148
+ end
149
+
150
+ context "#describe" do
151
+ it "generates count, mean, std, min and max of vectors in one shot" do
152
+ expect(@dv.describe.round(2)).to eq(Daru::Vector.new([10.00, 282.20, 274.08, 1.00, 666.00],
153
+ index: [:count, :mean, :std, :min, :max],
154
+ name: :statistics
155
+ ))
95
156
  end
96
157
  end
97
158
 
@@ -373,6 +434,20 @@ describe Daru::Vector do
373
434
  expect(acf[3]).to be_within(0.001) .of(0.486)
374
435
  end
375
436
  end
437
+
438
+ context "#percent_change" do
439
+ it "calculates percent change" do
440
+ vector = Daru::Vector.new([4,6,6,8,10],index: ['a','f','t','i','k'])
441
+ expect(vector.percent_change).to eq(
442
+ Daru::Vector.new([nil, 0.5, 0.0, 0.3333333333333333, 0.25], index: ['a','f','t','i','k']))
443
+ end
444
+
445
+ it "tests for numerical vectors with nils" do
446
+ vector2 = Daru::Vector.new([nil,6,nil,8,10],index: ['a','f','t','i','k'])
447
+ expect(vector2.percent_change).to eq(
448
+ Daru::Vector.new([nil, nil, nil, 0.3333333333333333, 0.25], index: ['a','f','t','i','k']))
449
+ end
450
+ end
376
451
 
377
452
  context "#diff" do
378
453
  it "performs the difference of the series" do
@@ -463,12 +538,12 @@ describe Daru::Vector do
463
538
  expect(ema10[-5]) .to be_within(0.00001).of( 17.19187)
464
539
  expect(ema10[-10]).to be_within(0.00001).of( 17.54918)
465
540
 
466
- # test with a different lookback period
541
+ # test with a different loopback period
467
542
  ema5 = @shares.ema 5
468
543
 
469
- expect(ema5[-1]) .to be_within( 0.0001).of(16.71299)
470
- expect(ema5[-10]).to be_within( 0.0001).of(17.49079)
471
- expect(ema5[-15]).to be_within( 0.0001).of(17.70067)
544
+ expect(ema5[-1]) .to be_within( 0.00001).of(16.71299)
545
+ expect(ema5[-10]).to be_within( 0.00001).of(17.49079)
546
+ expect(ema5[-15]).to be_within( 0.00001).of(17.70067)
472
547
 
473
548
  # test with a different smoother
474
549
  ema_w = @shares.ema 10, true
@@ -479,6 +554,56 @@ describe Daru::Vector do
479
554
  end
480
555
  end
481
556
 
557
+ context "#emv" do
558
+ it "calculates exponential moving variance" do
559
+ # test default
560
+ emv10 = @shares.emv
561
+
562
+ expect(emv10[-1]) .to be_within(0.00001).of(0.14441)
563
+ expect(emv10[-5]) .to be_within(0.00001).of(0.10797)
564
+ expect(emv10[-10]).to be_within(0.00001).of(0.03979)
565
+
566
+ # test with a different loopback period
567
+ emv5 = @shares.emv 5
568
+
569
+ expect(emv5[-1]) .to be_within(0.00001).of(0.05172)
570
+ expect(emv5[-10]).to be_within(0.00001).of(0.01736)
571
+ expect(emv5[-15]).to be_within(0.00001).of(0.04410)
572
+
573
+ # test with a different smoother
574
+ emv_w = @shares.emv 10, true
575
+
576
+ expect(emv_w[-1]) .to be_within(0.00001).of(0.20318)
577
+ expect(emv_w[-5]) .to be_within(0.00001).of(0.11319)
578
+ expect(emv_w[-10]).to be_within(0.00001).of(0.04289)
579
+ end
580
+ end
581
+
582
+ context "#emsd" do
583
+ it "calculates exponential moving standard deviation" do
584
+ # test default
585
+ emsd10 = @shares.emsd
586
+
587
+ expect(emsd10[-1]) .to be_within(0.00001).of(0.38002)
588
+ expect(emsd10[-5]) .to be_within(0.00001).of(0.32859)
589
+ expect(emsd10[-10]).to be_within(0.00001).of(0.19947)
590
+
591
+ # test with a different loopback period
592
+ emsd5 = @shares.emsd 5
593
+
594
+ expect(emsd5[-1]) .to be_within(0.00001).of(0.22742)
595
+ expect(emsd5[-10]).to be_within(0.00001).of(0.13174)
596
+ expect(emsd5[-15]).to be_within(0.00001).of(0.21000)
597
+
598
+ # test with a different smoother
599
+ emsd_w = @shares.emsd 10, true
600
+
601
+ expect(emsd_w[-1]) .to be_within(0.00001).of(0.45076)
602
+ expect(emsd_w[-5]) .to be_within(0.00001).of(0.33644)
603
+ expect(emsd_w[-10]).to be_within(0.00001).of(0.20710)
604
+ end
605
+ end
606
+
482
607
  context "#macd" do
483
608
  it "calculates moving average convergence divergence" do
484
609
  # MACD uses a lot more data than the other ones, so we need a bigger vector
@@ -506,4 +631,4 @@ describe Daru::Vector do
506
631
  Daru::Vector.new([1,3,6,10,15,21,28,36,45,55]))
507
632
  end
508
633
  end
509
- end
634
+ end