daru 0.1.5 → 0.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.
- checksums.yaml +5 -5
- data/.github/ISSUE_TEMPLATE.md +18 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +21 -7
- data/.travis.yml +10 -5
- data/CONTRIBUTING.md +15 -10
- data/History.md +124 -2
- data/README.md +37 -9
- data/ReleasePolicy.md +20 -0
- data/benchmarks/db_loading.rb +34 -0
- data/benchmarks/statistics.rb +6 -6
- data/benchmarks/where_clause.rb +1 -1
- data/benchmarks/where_vs_filter.rb +1 -1
- data/daru.gemspec +17 -41
- data/lib/daru.rb +10 -13
- data/lib/daru/accessors/gsl_wrapper.rb +1 -1
- data/lib/daru/accessors/nmatrix_wrapper.rb +2 -0
- data/lib/daru/category.rb +29 -15
- data/lib/daru/configuration.rb +34 -0
- data/lib/daru/core/group_by.rb +158 -77
- data/lib/daru/core/merge.rb +12 -3
- data/lib/daru/core/query.rb +20 -4
- data/lib/daru/dataframe.rb +692 -118
- data/lib/daru/date_time/index.rb +14 -11
- data/lib/daru/date_time/offsets.rb +9 -1
- data/lib/daru/extensions/which_dsl.rb +55 -0
- data/lib/daru/formatters/table.rb +3 -5
- data/lib/daru/index/categorical_index.rb +4 -4
- data/lib/daru/index/index.rb +131 -42
- data/lib/daru/index/multi_index.rb +118 -10
- data/lib/daru/io/csv/converters.rb +21 -0
- data/lib/daru/io/io.rb +105 -33
- data/lib/daru/io/sql_data_source.rb +10 -0
- data/lib/daru/iruby/templates/dataframe.html.erb +4 -51
- data/lib/daru/iruby/templates/dataframe_mi.html.erb +3 -56
- data/lib/daru/iruby/templates/dataframe_mi_tbody.html.erb +35 -0
- data/lib/daru/iruby/templates/dataframe_mi_thead.html.erb +21 -0
- data/lib/daru/iruby/templates/dataframe_tbody.html.erb +28 -0
- data/lib/daru/iruby/templates/dataframe_thead.html.erb +21 -0
- data/lib/daru/iruby/templates/vector.html.erb +3 -25
- data/lib/daru/iruby/templates/vector_mi.html.erb +3 -34
- data/lib/daru/iruby/templates/vector_mi_tbody.html.erb +26 -0
- data/lib/daru/iruby/templates/vector_mi_thead.html.erb +8 -0
- data/lib/daru/iruby/templates/vector_tbody.html.erb +17 -0
- data/lib/daru/iruby/templates/vector_thead.html.erb +8 -0
- data/lib/daru/maths/arithmetic/vector.rb +38 -2
- data/lib/daru/maths/statistics/dataframe.rb +28 -30
- data/lib/daru/maths/statistics/vector.rb +295 -41
- data/lib/daru/plotting/gruff/dataframe.rb +13 -15
- data/lib/daru/plotting/nyaplot/category.rb +1 -1
- data/lib/daru/plotting/nyaplot/dataframe.rb +15 -4
- data/lib/daru/plotting/nyaplot/vector.rb +1 -2
- data/lib/daru/vector.rb +308 -96
- data/lib/daru/version.rb +1 -1
- data/profile/vector_new.rb +9 -0
- data/spec/accessors/gsl_wrapper_spec.rb +38 -35
- data/spec/accessors/nmatrix_wrapper_spec.rb +25 -22
- data/spec/category_spec.rb +24 -20
- data/spec/core/group_by_spec.rb +238 -4
- data/spec/core/merge_spec.rb +1 -1
- data/spec/core/query_spec.rb +65 -50
- data/spec/daru_spec.rb +22 -0
- data/spec/dataframe_spec.rb +473 -16
- data/spec/date_time/date_time_index_helper_spec.rb +72 -0
- data/spec/date_time/index_spec.rb +34 -16
- data/spec/date_time/offsets_spec.rb +14 -0
- data/spec/extensions/rserve_spec.rb +1 -1
- data/spec/extensions/which_dsl_spec.rb +38 -0
- data/spec/fixtures/boolean_converter_test.csv +5 -0
- data/spec/fixtures/duplicates.csv +32 -0
- data/spec/fixtures/eciresults.html +394 -0
- data/spec/fixtures/empty_rows_test.csv +17 -0
- data/spec/fixtures/macau.html +3691 -0
- data/spec/fixtures/macd_data.csv +150 -0
- data/spec/fixtures/matrix_test.csv +55 -55
- data/spec/fixtures/moneycontrol.html +6812 -0
- data/spec/fixtures/string_converter_test.csv +5 -0
- data/spec/fixtures/test_xls.xls +0 -0
- data/spec/fixtures/test_xls_2.xls +0 -0
- data/spec/fixtures/url_test.txt~ +0 -0
- data/spec/fixtures/valid_markup.html +62 -0
- data/spec/fixtures/wiki_climate.html +1243 -0
- data/spec/fixtures/wiki_table_info.html +631 -0
- data/spec/formatters/table_formatter_spec.rb +29 -0
- data/spec/index/categorical_index_spec.rb +33 -33
- data/spec/index/index_spec.rb +160 -41
- data/spec/index/multi_index_spec.rb +143 -33
- data/spec/io/io_spec.rb +246 -2
- data/spec/io/sql_data_source_spec.rb +31 -41
- data/spec/iruby/dataframe_spec.rb +17 -19
- data/spec/iruby/vector_spec.rb +26 -28
- data/spec/maths/arithmetic/dataframe_spec.rb +1 -1
- data/spec/maths/arithmetic/vector_spec.rb +18 -0
- data/spec/maths/statistics/vector_spec.rb +153 -15
- data/spec/plotting/gruff/category_spec.rb +3 -3
- data/spec/plotting/gruff/dataframe_spec.rb +14 -4
- data/spec/plotting/gruff/vector_spec.rb +9 -9
- data/spec/plotting/nyaplot/category_spec.rb +5 -9
- data/spec/plotting/nyaplot/dataframe_spec.rb +95 -47
- data/spec/plotting/nyaplot/vector_spec.rb +5 -11
- data/spec/shared/vector_display_spec.rb +12 -14
- data/spec/spec_helper.rb +30 -7
- data/spec/support/matchers.rb +5 -0
- data/spec/vector_spec.rb +306 -72
- metadata +96 -55
- data/spec/fixtures/stock_data.csv +0 -500
|
@@ -5,62 +5,52 @@ require 'active_record'
|
|
|
5
5
|
|
|
6
6
|
RSpec.describe Daru::IO::SqlDataSource do
|
|
7
7
|
include_context 'with accounts table in sqlite3 database'
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
|
|
9
|
+
let(:query) do
|
|
10
|
+
'select * from accounts'
|
|
10
11
|
end
|
|
11
12
|
|
|
12
|
-
let(:
|
|
13
|
+
let(:source) do
|
|
13
14
|
ActiveRecord::Base.establish_connection("sqlite3:#{db_name}")
|
|
14
15
|
ActiveRecord::Base.connection
|
|
15
16
|
end
|
|
16
17
|
|
|
17
|
-
let(:query) do
|
|
18
|
-
'select * from accounts'
|
|
19
|
-
end
|
|
20
|
-
|
|
21
18
|
describe '.make_dataframe' do
|
|
22
|
-
|
|
23
|
-
it 'returns a dataframe' do
|
|
24
|
-
result = Daru::IO::SqlDataSource.make_dataframe(dbi_handle, query)
|
|
25
|
-
expect(result).to be_a(Daru::DataFrame)
|
|
26
|
-
expect(result.nrows).to eq(2)
|
|
27
|
-
expect(result.row[0][:id]).to eq(1)
|
|
28
|
-
expect(result.row[0][:name]).to eq('Homer')
|
|
29
|
-
end
|
|
19
|
+
subject(:df) { Daru::IO::SqlDataSource.make_dataframe(source, query) }
|
|
30
20
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
end
|
|
37
|
-
end
|
|
21
|
+
context 'with DBI::DatabaseHandle' do
|
|
22
|
+
let(:source) { DBI.connect("DBI:SQLite3:#{db_name}") }
|
|
23
|
+
it { is_expected.to be_a(Daru::DataFrame) }
|
|
24
|
+
it { expect(df.row[0]).to have_attributes(id: 1, age: 20) }
|
|
25
|
+
its(:nrows) { is_expected.to eq 2 }
|
|
38
26
|
end
|
|
39
27
|
|
|
40
28
|
context 'with ActiveRecord::Connection' do
|
|
41
|
-
it
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
expect(result.row[0][:id]).to eq(1)
|
|
46
|
-
expect(result.row[0][:name]).to eq('Homer')
|
|
47
|
-
end
|
|
29
|
+
it { is_expected.to be_a(Daru::DataFrame) }
|
|
30
|
+
it { expect(df.row[0]).to have_attributes(id: 1, age: 20) }
|
|
31
|
+
its(:nrows) { is_expected.to eq 2 }
|
|
32
|
+
end
|
|
48
33
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
34
|
+
context 'with path to sqlite3 file' do
|
|
35
|
+
let(:source) { db_name }
|
|
36
|
+
it { is_expected.to be_a(Daru::DataFrame) }
|
|
37
|
+
it { expect(df.row[0]).to have_attributes(id: 1, age: 20) }
|
|
38
|
+
its(:nrows) { is_expected.to eq 2 }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
context 'with an object not a string as a query' do
|
|
42
|
+
let(:query) { Object.new }
|
|
43
|
+
it { expect { df }.to raise_error(ArgumentError) }
|
|
56
44
|
end
|
|
57
45
|
|
|
58
46
|
context 'with an object not a database connection' do
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
47
|
+
let(:source) { Object.new }
|
|
48
|
+
it { expect { df }.to raise_error(ArgumentError) }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
context 'with path to unsupported db file' do
|
|
52
|
+
let(:source) { 'spec/fixtures/bank2.dat' }
|
|
53
|
+
it { expect { df }.to raise_error(ArgumentError) }
|
|
64
54
|
end
|
|
65
55
|
end
|
|
66
56
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
describe Daru::DataFrame, '#to_html' do
|
|
2
2
|
let(:doc) { Nokogiri::HTML(df.to_html) }
|
|
3
3
|
subject(:table) { doc.at('table') }
|
|
4
|
-
let(:header) {
|
|
4
|
+
let(:header) { doc.at('b')}
|
|
5
5
|
let(:name) { 'test' }
|
|
6
6
|
|
|
7
7
|
let(:splitted_row) { row.inner_html.scan(/<t[dh].+?<\/t[dh]>/) }
|
|
@@ -13,18 +13,17 @@ describe Daru::DataFrame, '#to_html' do
|
|
|
13
13
|
subject { header }
|
|
14
14
|
|
|
15
15
|
it { is_expected.not_to be_nil }
|
|
16
|
-
its(
|
|
17
|
-
its(:text) { is_expected.to eq "Daru::DataFrame: test (3x3)" }
|
|
16
|
+
its(:text) { is_expected.to eq " Daru::DataFrame: test (3x3) " }
|
|
18
17
|
|
|
19
18
|
context 'without name' do
|
|
20
19
|
let(:name) { nil }
|
|
21
20
|
|
|
22
|
-
its(:text) { is_expected.to eq "Daru::DataFrame(3x3)" }
|
|
21
|
+
its(:text) { is_expected.to eq " Daru::DataFrame(3x3) " }
|
|
23
22
|
end
|
|
24
23
|
end
|
|
25
24
|
|
|
26
25
|
describe 'column headers' do
|
|
27
|
-
subject(:columns) { table.search('tr:nth-child(
|
|
26
|
+
subject(:columns) { table.search('tr:nth-child(1) th').map(&:text) }
|
|
28
27
|
its(:size) { is_expected.to eq df.ncols + 1 }
|
|
29
28
|
it { is_expected.to eq ['', 'a', 'b', 'c'] }
|
|
30
29
|
end
|
|
@@ -34,7 +33,7 @@ describe Daru::DataFrame, '#to_html' do
|
|
|
34
33
|
|
|
35
34
|
subject { splitted_row }
|
|
36
35
|
describe 'first row' do
|
|
37
|
-
let(:row) { table.search('tr:nth-child(
|
|
36
|
+
let(:row) { table.search('thead > tr:nth-child(1)') }
|
|
38
37
|
|
|
39
38
|
it { is_expected.to eq [
|
|
40
39
|
'<th rowspan="2"></th>',
|
|
@@ -44,7 +43,7 @@ describe Daru::DataFrame, '#to_html' do
|
|
|
44
43
|
end
|
|
45
44
|
|
|
46
45
|
describe 'next row' do
|
|
47
|
-
let(:row) { table.search('tr:nth-child(
|
|
46
|
+
let(:row) { table.search('thead > tr:nth-child(2)') }
|
|
48
47
|
|
|
49
48
|
it { is_expected.to eq [
|
|
50
49
|
'<th colspan="1">foo</th>',
|
|
@@ -62,7 +61,7 @@ describe Daru::DataFrame, '#to_html' do
|
|
|
62
61
|
|
|
63
62
|
describe 'values' do
|
|
64
63
|
subject(:values) {
|
|
65
|
-
table.search('tr')[
|
|
64
|
+
table.search('tr')[1..-1]
|
|
66
65
|
.map { |tr| tr.search('td')[1..-1].map(&:text) }
|
|
67
66
|
}
|
|
68
67
|
its(:count) { is_expected.to eq df.nrows }
|
|
@@ -76,21 +75,21 @@ describe Daru::DataFrame, '#to_html' do
|
|
|
76
75
|
describe 'header' do
|
|
77
76
|
subject { header }
|
|
78
77
|
|
|
79
|
-
its(:text) { is_expected.to eq "Daru::DataFrame: test (300x3)" }
|
|
78
|
+
its(:text) { is_expected.to eq " Daru::DataFrame: test (300x3) " }
|
|
80
79
|
end
|
|
81
80
|
|
|
82
|
-
it 'has only 30 rows (+
|
|
83
|
-
expect(table.search('tr').size).to eq
|
|
81
|
+
it 'has only 30 rows (+ 1 header rows, + 2 finishing rows)' do
|
|
82
|
+
expect(table.search('tr').size).to eq 33
|
|
84
83
|
end
|
|
85
84
|
|
|
86
85
|
describe '"skipped" row' do
|
|
87
|
-
subject(:row) { table.search('tr:nth-child(
|
|
86
|
+
subject(:row) { table.search('tr:nth-child(31) td').map(&:text) }
|
|
88
87
|
its(:count) { is_expected.to eq df.ncols + 1 }
|
|
89
88
|
it { is_expected.to all eq '...' }
|
|
90
89
|
end
|
|
91
90
|
|
|
92
91
|
describe 'last row' do
|
|
93
|
-
subject(:row) { table.search('tr:nth-child(
|
|
92
|
+
subject(:row) { table.search('tr:nth-child(32) td').map(&:text) }
|
|
94
93
|
its(:count) { is_expected.to eq df.ncols + 1 }
|
|
95
94
|
it { is_expected.to eq ['299', *df.row[-1].map(&:to_s)] }
|
|
96
95
|
end
|
|
@@ -119,12 +118,11 @@ describe Daru::DataFrame, '#to_html' do
|
|
|
119
118
|
subject { header }
|
|
120
119
|
|
|
121
120
|
it { is_expected.not_to be_nil }
|
|
122
|
-
its(
|
|
123
|
-
its(:text) { is_expected.to eq "Daru::DataFrame: test (7x2)" }
|
|
121
|
+
its(:text) { is_expected.to eq " Daru::DataFrame: test (7x2) " }
|
|
124
122
|
end
|
|
125
123
|
|
|
126
124
|
describe 'column headers' do
|
|
127
|
-
let(:row) { table.search('tr:nth-child(
|
|
125
|
+
let(:row) { table.search('thead > tr:nth-child(1)') }
|
|
128
126
|
subject { splitted_row }
|
|
129
127
|
|
|
130
128
|
it { is_expected.to eq [
|
|
@@ -139,7 +137,7 @@ describe Daru::DataFrame, '#to_html' do
|
|
|
139
137
|
|
|
140
138
|
subject { splitted_row }
|
|
141
139
|
describe 'first row' do
|
|
142
|
-
let(:row) { table.search('tr:nth-child(
|
|
140
|
+
let(:row) { table.search('thead > tr:nth-child(1)') }
|
|
143
141
|
|
|
144
142
|
it { is_expected.to eq [
|
|
145
143
|
'<th colspan="2" rowspan="2"></th>',
|
|
@@ -148,7 +146,7 @@ describe Daru::DataFrame, '#to_html' do
|
|
|
148
146
|
end
|
|
149
147
|
|
|
150
148
|
describe 'next row' do
|
|
151
|
-
let(:row) { table.search('tr:nth-child(
|
|
149
|
+
let(:row) { table.search('thead > tr:nth-child(2)') }
|
|
152
150
|
|
|
153
151
|
it { is_expected.to eq [
|
|
154
152
|
'<th colspan="1">foo</th>',
|
|
@@ -158,7 +156,7 @@ describe Daru::DataFrame, '#to_html' do
|
|
|
158
156
|
end
|
|
159
157
|
|
|
160
158
|
describe 'first row' do
|
|
161
|
-
let(:row) { table.search('tr:nth-child(
|
|
159
|
+
let(:row) { table.search('tbody > tr:nth-child(1)') }
|
|
162
160
|
subject { splitted_row }
|
|
163
161
|
|
|
164
162
|
it { is_expected.to eq [
|
data/spec/iruby/vector_spec.rb
CHANGED
|
@@ -2,65 +2,64 @@ describe Daru::Vector, '#to_html' do
|
|
|
2
2
|
[nil, :category].each do |type|
|
|
3
3
|
let(:doc) { Nokogiri::HTML(vector.to_html) }
|
|
4
4
|
subject(:table) { doc.at('table') }
|
|
5
|
-
let(:header) {
|
|
6
|
-
|
|
5
|
+
let(:header) { doc.at('b') }
|
|
6
|
+
|
|
7
7
|
context 'simple' do
|
|
8
8
|
let(:vector) { Daru::Vector.new [1,nil,3],
|
|
9
9
|
index: [:a, :b, :c], name: 'test', type: type }
|
|
10
10
|
it { is_expected.not_to be_nil }
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
describe 'header' do
|
|
13
13
|
subject { header }
|
|
14
14
|
it { is_expected.not_to be_nil }
|
|
15
|
-
its(
|
|
16
|
-
|
|
17
|
-
"#{":category" if type == :category}" }
|
|
15
|
+
its(:text) { is_expected.to eq " Daru::Vector(3)"\
|
|
16
|
+
"#{":category" if type == :category} " }
|
|
18
17
|
end
|
|
19
|
-
|
|
18
|
+
|
|
20
19
|
describe 'name' do
|
|
21
|
-
subject(:name) { table.at('tr:nth-child(
|
|
20
|
+
subject(:name) { table.at('tr:nth-child(1) > th:nth-child(2)') }
|
|
22
21
|
it { is_expected.not_to be_nil }
|
|
23
22
|
its(:text) { is_expected.to eq 'test' }
|
|
24
|
-
|
|
23
|
+
|
|
25
24
|
context 'withought name' do
|
|
26
25
|
let(:vector) { Daru::Vector.new [1,nil,3], index: [:a, :b, :c], type: type }
|
|
27
|
-
|
|
26
|
+
|
|
28
27
|
it { is_expected.to be_nil }
|
|
29
28
|
end
|
|
30
29
|
end
|
|
31
|
-
|
|
30
|
+
|
|
32
31
|
describe 'index' do
|
|
33
32
|
subject(:indexes) { table.search('tr > td:first-child').map(&:text) }
|
|
34
33
|
its(:count) { is_expected.to eq vector.size }
|
|
35
34
|
it { is_expected.to eq vector.index.to_a.map(&:to_s) }
|
|
36
35
|
end
|
|
37
|
-
|
|
36
|
+
|
|
38
37
|
describe 'values' do
|
|
39
38
|
subject(:indexes) { table.search('tr > td:last-child').map(&:text) }
|
|
40
39
|
its(:count) { is_expected.to eq vector.size }
|
|
41
40
|
it { is_expected.to eq vector.to_a.map(&:to_s) }
|
|
42
41
|
end
|
|
43
42
|
end
|
|
44
|
-
|
|
43
|
+
|
|
45
44
|
context 'large vector' do
|
|
46
45
|
subject(:vector) { Daru::Vector.new [1,2,3] * 100, name: 'test', type: type }
|
|
47
|
-
it 'has only 30 rows (+
|
|
48
|
-
expect(table.search('tr').size).to eq
|
|
46
|
+
it 'has only 30 rows (+ 1 header rows, + 2 finishing rows)' do
|
|
47
|
+
expect(table.search('tr').size).to eq 33
|
|
49
48
|
end
|
|
50
|
-
|
|
49
|
+
|
|
51
50
|
describe '"skipped" row' do
|
|
52
|
-
subject(:row) { table.search('tr:nth-child(
|
|
51
|
+
subject(:row) { table.search('tr:nth-child(31) td').map(&:text) }
|
|
53
52
|
its(:count) { is_expected.to eq 2 }
|
|
54
53
|
it { is_expected.to eq ['...', '...'] }
|
|
55
54
|
end
|
|
56
|
-
|
|
55
|
+
|
|
57
56
|
describe 'last row' do
|
|
58
|
-
subject(:row) { table.search('tr:nth-child(
|
|
57
|
+
subject(:row) { table.search('tr:nth-child(32) td').map(&:text) }
|
|
59
58
|
its(:count) { is_expected.to eq 2 }
|
|
60
59
|
it { is_expected.to eq ['299', '3'] }
|
|
61
60
|
end
|
|
62
61
|
end
|
|
63
|
-
|
|
62
|
+
|
|
64
63
|
context 'multi-index' do
|
|
65
64
|
subject(:vector) {
|
|
66
65
|
Daru::Vector.new(
|
|
@@ -78,23 +77,22 @@ describe Daru::Vector, '#to_html' do
|
|
|
78
77
|
]),
|
|
79
78
|
)
|
|
80
79
|
}
|
|
81
|
-
|
|
80
|
+
|
|
82
81
|
describe 'header' do
|
|
83
82
|
subject { header }
|
|
84
83
|
it { is_expected.not_to be_nil }
|
|
85
|
-
its(
|
|
86
|
-
|
|
87
|
-
"#{":category" if type == :category}" }
|
|
84
|
+
its(:text) { is_expected.to eq " Daru::Vector(7)"\
|
|
85
|
+
"#{":category" if type == :category} " }
|
|
88
86
|
end
|
|
89
|
-
|
|
87
|
+
|
|
90
88
|
describe 'name row' do
|
|
91
|
-
subject(:row) { table.at('tr:nth-child(
|
|
89
|
+
subject(:row) { table.at('tr:nth-child(1)').search('th') }
|
|
92
90
|
its(:count) { should == 2 }
|
|
93
91
|
it { expect(row.first['colspan']).to eq '2' }
|
|
94
92
|
end
|
|
95
|
-
|
|
93
|
+
|
|
96
94
|
describe 'first data row' do
|
|
97
|
-
let(:row) { table.at('tr:
|
|
95
|
+
let(:row) { table.at('tbody > tr:first-child') }
|
|
98
96
|
subject { row.inner_html.scan(/<t[dh].+?<\/t[dh]>/) }
|
|
99
97
|
it { is_expected.to eq [
|
|
100
98
|
'<th rowspan="3">foo</th>',
|
|
@@ -78,6 +78,24 @@ describe Daru::Vector do
|
|
|
78
78
|
end
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
+
context "#add" do
|
|
82
|
+
|
|
83
|
+
it "adds two vectors with nils as 0 if skipnil is true" do
|
|
84
|
+
expect(@with_md1.add(@with_md2, skipnil: true)).to eq(Daru::Vector.new(
|
|
85
|
+
[1, 7, 3, 3, 1, 7],
|
|
86
|
+
name: :missing,
|
|
87
|
+
index: [:a, :b, :c, :corona, :obi, :wan]))
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "adds two vectors same as :+ if skipnil is false" do
|
|
91
|
+
expect(@with_md1.add(@with_md2, skipnil: false)).to eq(Daru::Vector.new(
|
|
92
|
+
[nil, 7, nil, nil, nil, 7],
|
|
93
|
+
name: :missing,
|
|
94
|
+
index: [:a, :b, :c, :corona, :obi, :wan]))
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
end
|
|
98
|
+
|
|
81
99
|
context "#abs" do
|
|
82
100
|
it "calculates abs value" do
|
|
83
101
|
@with_md1.abs
|
|
@@ -12,6 +12,128 @@ describe Daru::Vector do
|
|
|
12
12
|
end
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
let(:dv) { dv = Daru::Vector.new (["Tyrion", "Daenerys", nil, "Jon Starkgaryen"]), index: Daru::Index.new([:t, :d, :n, :j]) }
|
|
16
|
+
|
|
17
|
+
context "#max" do
|
|
18
|
+
it "returns max value" do
|
|
19
|
+
expect(dv.max).to eq("Tyrion")
|
|
20
|
+
end
|
|
21
|
+
it "returns N max values" do
|
|
22
|
+
expect(dv.max(2)).to eq(["Tyrion","Jon Starkgaryen"])
|
|
23
|
+
end
|
|
24
|
+
it "returns max value, sorted by comparitive block input" do
|
|
25
|
+
expect(dv.max { |a,b| a.size <=> b.size }).to eq("Jon Starkgaryen")
|
|
26
|
+
end
|
|
27
|
+
it "returns N max values, sorted by comparitive block input" do
|
|
28
|
+
expect(dv.max(2) {|a,b| a.size <=> b.size}).to eq(["Jon Starkgaryen","Daenerys"])
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
context "#max_by" do
|
|
33
|
+
it "raises error without object block" do
|
|
34
|
+
expect { dv.max_by }.to raise_error(ArgumentError)
|
|
35
|
+
end
|
|
36
|
+
it "raises error without object block when N is given" do
|
|
37
|
+
expect { dv.max_by(2) }.to raise_error(ArgumentError)
|
|
38
|
+
end
|
|
39
|
+
it "returns max value, sorted by object block input" do
|
|
40
|
+
expect(dv.max_by { |x| x.size }).to eq("Jon Starkgaryen")
|
|
41
|
+
end
|
|
42
|
+
it "returns N max values, sorted by object block input" do
|
|
43
|
+
expect(dv.max_by(2) {|x| x.size }).to eq(["Jon Starkgaryen","Daenerys"])
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
context "#index_of_max" do
|
|
48
|
+
it "returns index_of_max value" do
|
|
49
|
+
expect(dv.index_of_max).to eq(:t)
|
|
50
|
+
end
|
|
51
|
+
it "returns N index_of_max values" do
|
|
52
|
+
expect(dv.index_of_max(2)).to eq([:t, :j])
|
|
53
|
+
end
|
|
54
|
+
it "returns index_of_max value, sorted by comparitive block input" do
|
|
55
|
+
expect(dv.index_of_max { |a,b| a.size <=> b.size }).to eq(:j)
|
|
56
|
+
end
|
|
57
|
+
it "returns N index_of_max values, sorted by comparitive block input" do
|
|
58
|
+
expect(dv.index_of_max(2) {|a,b| a.size <=> b.size}).to eq([:j, :d])
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
context "#index_of_max_by" do
|
|
63
|
+
it "raises error without object block" do
|
|
64
|
+
expect { dv.index_of_max_by }.to raise_error(ArgumentError)
|
|
65
|
+
end
|
|
66
|
+
it "raises error without object block when N is given" do
|
|
67
|
+
expect { dv.index_of_max_by(2) }.to raise_error(ArgumentError)
|
|
68
|
+
end
|
|
69
|
+
it "returns index_of_max value, sorted by object block input" do
|
|
70
|
+
expect(dv.index_of_max_by { |x| x.size }).to eq(:j)
|
|
71
|
+
end
|
|
72
|
+
it "returns N index_of_max values, sorted by object block input" do
|
|
73
|
+
expect(dv.index_of_max_by(2) {|x| x.size }).to eq([:j, :d])
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
context "#min" do
|
|
78
|
+
it "returns min value" do
|
|
79
|
+
expect(dv.min).to eq("Daenerys")
|
|
80
|
+
end
|
|
81
|
+
it "returns N min values" do
|
|
82
|
+
expect(dv.min(2)).to eq(["Daenerys","Jon Starkgaryen"])
|
|
83
|
+
end
|
|
84
|
+
it "returns min value, sorted by comparitive block input" do
|
|
85
|
+
expect(dv.min { |a,b| a.size <=> b.size }).to eq("Tyrion")
|
|
86
|
+
end
|
|
87
|
+
it "returns N min values, sorted by comparitive block input" do
|
|
88
|
+
expect(dv.min(2) {|a,b| a.size <=> b.size}).to eq(["Tyrion","Daenerys"])
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
context "#min_by" do
|
|
93
|
+
it "raises error without object block" do
|
|
94
|
+
expect { dv.min_by }.to raise_error(ArgumentError)
|
|
95
|
+
end
|
|
96
|
+
it "raises error without object block when N is given" do
|
|
97
|
+
expect { dv.min_by(2) }.to raise_error(ArgumentError)
|
|
98
|
+
end
|
|
99
|
+
it "returns min value, sorted by object block input" do
|
|
100
|
+
expect(dv.min_by { |x| x.size }).to eq("Tyrion")
|
|
101
|
+
end
|
|
102
|
+
it "returns N min values, sorted by object block input" do
|
|
103
|
+
expect(dv.min_by(2) {|x| x.size }).to eq(["Tyrion","Daenerys"])
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
context "#index_of_min" do
|
|
108
|
+
it "returns index of min value" do
|
|
109
|
+
expect(dv.index_of_min).to eq(:d)
|
|
110
|
+
end
|
|
111
|
+
it "returns N index of min values" do
|
|
112
|
+
expect(dv.index_of_min(2)).to eq([:d, :j])
|
|
113
|
+
end
|
|
114
|
+
it "returns index of min value, sorted by comparitive block input" do
|
|
115
|
+
expect(dv.index_of_min { |a,b| a.size <=> b.size }).to eq(:t)
|
|
116
|
+
end
|
|
117
|
+
it "returns N index of min values, sorted by comparitive block input" do
|
|
118
|
+
expect(dv.index_of_min(2) {|a,b| a.size <=> b.size}).to eq([:t, :d])
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
context "#index_of_min_by" do
|
|
123
|
+
it "raises error without object block" do
|
|
124
|
+
expect { dv.index_of_min_by }.to raise_error(ArgumentError)
|
|
125
|
+
end
|
|
126
|
+
it "raises error without object block when N is given" do
|
|
127
|
+
expect { dv.index_of_min_by(2) }.to raise_error(ArgumentError)
|
|
128
|
+
end
|
|
129
|
+
it "returns index of min value, sorted by object block input" do
|
|
130
|
+
expect(dv.index_of_min_by { |x| x.size }).to eq(:t)
|
|
131
|
+
end
|
|
132
|
+
it "returns N index of min values, sorted by object block input" do
|
|
133
|
+
expect(dv.index_of_min_by(2) {|x| x.size }).to eq([:t, :d])
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
15
137
|
context "#sum_of_squares" do
|
|
16
138
|
it "calcs sum of squares, omits nil values" do
|
|
17
139
|
v = Daru::Vector.new [1,2,3,4,5,6], dtype: dtype
|
|
@@ -189,7 +311,11 @@ describe Daru::Vector do
|
|
|
189
311
|
|
|
190
312
|
context "#proportions" do
|
|
191
313
|
it "calculates proportions" do
|
|
192
|
-
|
|
314
|
+
actual_proportions = {
|
|
315
|
+
array: {323=>0.1,11=>0.1,555=>0.1,666=>0.2,234=>0.1,21=>0.1,343=>0.1,1=>0.1,2=>0.1},
|
|
316
|
+
gsl: {323.0=>0.1, 11.0=>0.1, 555.0=>0.1, 666.0=>0.2, 234.0=>0.1, 21.0=>0.1, 343.0=>0.1, 1.0=>0.1, 2.0=>0.1}
|
|
317
|
+
}
|
|
318
|
+
expect(@dv.proportions).to eq(actual_proportions[dtype])
|
|
193
319
|
end
|
|
194
320
|
end
|
|
195
321
|
|
|
@@ -583,24 +709,36 @@ describe Daru::Vector do
|
|
|
583
709
|
end
|
|
584
710
|
end
|
|
585
711
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
# MACD uses a lot more data than the other ones, so we need a bigger vector
|
|
589
|
-
data = Daru::Vector.new(
|
|
590
|
-
File.readlines("spec/fixtures/stock_data.csv").map(&:to_f))
|
|
712
|
+
RSpec.shared_examples 'correct macd' do |*args|
|
|
713
|
+
let(:source) { Daru::DataFrame.from_csv('spec/fixtures/macd_data.csv') }
|
|
591
714
|
|
|
592
|
-
|
|
715
|
+
# skip initial records during compare as ema is sensitive to
|
|
716
|
+
# period used.
|
|
717
|
+
# http://ta-lib.org/d_api/ta_setunstableperiod.html
|
|
718
|
+
let(:stability_offset) { 90 }
|
|
719
|
+
let(:delta) { 0.001 }
|
|
720
|
+
let(:desc) { args.empty? ? '12_26_9' : args.join('_') }
|
|
593
721
|
|
|
594
|
-
|
|
595
|
-
expect(macd[-1]).to be_within(1e-6).of(3.12e-4)
|
|
596
|
-
expect(macd[-10]).to be_within(1e-4).of(-1.07e-2)
|
|
597
|
-
expect(macd[-20]).to be_within(1e-5).of(-5.65e-3)
|
|
722
|
+
subject { source['price'].macd(*args) }
|
|
598
723
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
724
|
+
%w[ macd macdsig macdhist ].each_with_index do |field, i|
|
|
725
|
+
it do
|
|
726
|
+
act = subject[i][stability_offset..-1]
|
|
727
|
+
exp = source["#{field}_#{desc}"][stability_offset..-1]
|
|
728
|
+
expect(act).to be_all_within(delta).of(exp)
|
|
729
|
+
end
|
|
730
|
+
end
|
|
731
|
+
end
|
|
732
|
+
|
|
733
|
+
describe '#macd' do
|
|
734
|
+
context 'by default' do
|
|
735
|
+
it_should_behave_like 'correct macd'
|
|
603
736
|
end
|
|
737
|
+
|
|
738
|
+
context 'custom values for fast, slow, signal' do
|
|
739
|
+
it_should_behave_like 'correct macd', 6, 13, 4
|
|
740
|
+
end
|
|
741
|
+
|
|
604
742
|
end
|
|
605
743
|
|
|
606
744
|
context "#cumsum" do
|