daru_lite 0.1
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 +7 -0
- data/.github/ISSUE_TEMPLATE.md +18 -0
- data/.github/workflows/ci.yml +33 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.rubocop.yml +27 -0
- data/.rubocop_todo.yml +137 -0
- data/CONTRIBUTING.md +47 -0
- data/Gemfile +2 -0
- data/History.md +4 -0
- data/LICENSE +24 -0
- data/README.md +218 -0
- data/Rakefile +69 -0
- data/ReleasePolicy.md +20 -0
- data/benchmarks/TradeoffData.csv +65 -0
- data/benchmarks/csv_reading.rb +22 -0
- data/benchmarks/dataframe_creation.rb +39 -0
- data/benchmarks/db_loading.rb +34 -0
- data/benchmarks/duplicating.rb +45 -0
- data/benchmarks/group_by.rb +32 -0
- data/benchmarks/joining.rb +52 -0
- data/benchmarks/row_access.rb +41 -0
- data/benchmarks/row_assign.rb +36 -0
- data/benchmarks/sorting.rb +51 -0
- data/benchmarks/statistics.rb +28 -0
- data/benchmarks/vector_access.rb +31 -0
- data/benchmarks/vector_assign.rb +42 -0
- data/benchmarks/where_clause.rb +48 -0
- data/benchmarks/where_vs_filter.rb +28 -0
- data/daru_lite.gemspec +55 -0
- data/images/README.md +5 -0
- data/images/con0.png +0 -0
- data/images/con1.png +0 -0
- data/images/init0.png +0 -0
- data/images/init1.png +0 -0
- data/images/man0.png +0 -0
- data/images/man1.png +0 -0
- data/images/man2.png +0 -0
- data/images/man3.png +0 -0
- data/images/man4.png +0 -0
- data/images/man5.png +0 -0
- data/images/man6.png +0 -0
- data/lib/daru_lite/accessors/array_wrapper.rb +109 -0
- data/lib/daru_lite/accessors/dataframe_by_row.rb +25 -0
- data/lib/daru_lite/accessors/mdarray_wrapper.rb +7 -0
- data/lib/daru_lite/category.rb +929 -0
- data/lib/daru_lite/configuration.rb +34 -0
- data/lib/daru_lite/core/group_by.rb +403 -0
- data/lib/daru_lite/core/merge.rb +270 -0
- data/lib/daru_lite/core/query.rb +109 -0
- data/lib/daru_lite/dataframe.rb +3080 -0
- data/lib/daru_lite/date_time/index.rb +569 -0
- data/lib/daru_lite/date_time/offsets.rb +397 -0
- data/lib/daru_lite/exceptions.rb +2 -0
- data/lib/daru_lite/extensions/which_dsl.rb +53 -0
- data/lib/daru_lite/formatters/table.rb +52 -0
- data/lib/daru_lite/helpers/array.rb +53 -0
- data/lib/daru_lite/index/categorical_index.rb +201 -0
- data/lib/daru_lite/index/index.rb +374 -0
- data/lib/daru_lite/index/multi_index.rb +374 -0
- data/lib/daru_lite/io/csv/converters.rb +21 -0
- data/lib/daru_lite/io/io.rb +294 -0
- data/lib/daru_lite/io/sql_data_source.rb +97 -0
- data/lib/daru_lite/iruby/helpers.rb +38 -0
- data/lib/daru_lite/iruby/templates/dataframe.html.erb +5 -0
- data/lib/daru_lite/iruby/templates/dataframe_mi.html.erb +5 -0
- data/lib/daru_lite/iruby/templates/dataframe_mi_tbody.html.erb +35 -0
- data/lib/daru_lite/iruby/templates/dataframe_mi_thead.html.erb +21 -0
- data/lib/daru_lite/iruby/templates/dataframe_tbody.html.erb +28 -0
- data/lib/daru_lite/iruby/templates/dataframe_thead.html.erb +21 -0
- data/lib/daru_lite/iruby/templates/multi_index.html.erb +12 -0
- data/lib/daru_lite/iruby/templates/vector.html.erb +5 -0
- data/lib/daru_lite/iruby/templates/vector_mi.html.erb +5 -0
- data/lib/daru_lite/iruby/templates/vector_mi_tbody.html.erb +26 -0
- data/lib/daru_lite/iruby/templates/vector_mi_thead.html.erb +8 -0
- data/lib/daru_lite/iruby/templates/vector_tbody.html.erb +17 -0
- data/lib/daru_lite/iruby/templates/vector_thead.html.erb +8 -0
- data/lib/daru_lite/maths/arithmetic/dataframe.rb +91 -0
- data/lib/daru_lite/maths/arithmetic/vector.rb +117 -0
- data/lib/daru_lite/maths/statistics/dataframe.rb +202 -0
- data/lib/daru_lite/maths/statistics/vector.rb +1019 -0
- data/lib/daru_lite/monkeys.rb +56 -0
- data/lib/daru_lite/vector.rb +1678 -0
- data/lib/daru_lite/version.rb +3 -0
- data/lib/daru_lite.rb +99 -0
- data/profile/_base.rb +23 -0
- data/profile/df_to_a.rb +10 -0
- data/profile/filter.rb +13 -0
- data/profile/joining.rb +13 -0
- data/profile/sorting.rb +12 -0
- data/profile/vector_each_with_index.rb +9 -0
- data/profile/vector_new.rb +9 -0
- data/spec/accessors/array_wrapper_spec.rb +3 -0
- data/spec/category_spec.rb +1741 -0
- data/spec/core/group_by_spec.rb +655 -0
- data/spec/core/merge_spec.rb +179 -0
- data/spec/core/query_spec.rb +347 -0
- data/spec/daru_lite_spec.rb +22 -0
- data/spec/dataframe_spec.rb +4330 -0
- data/spec/date_time/data_spec.rb +197 -0
- data/spec/date_time/date_time_index_helper_spec.rb +72 -0
- data/spec/date_time/index_spec.rb +588 -0
- data/spec/date_time/offsets_spec.rb +465 -0
- data/spec/extensions/which_dsl_spec.rb +38 -0
- data/spec/fixtures/bank2.dat +200 -0
- data/spec/fixtures/boolean_converter_test.csv +5 -0
- data/spec/fixtures/countries.json +7794 -0
- data/spec/fixtures/duplicates.csv +32 -0
- data/spec/fixtures/eciresults.html +394 -0
- data/spec/fixtures/empties.dat +2 -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 +100 -0
- data/spec/fixtures/moneycontrol.html +6812 -0
- data/spec/fixtures/music_data.tsv +2501 -0
- data/spec/fixtures/repeated_fields.csv +7 -0
- data/spec/fixtures/sales-funnel.csv +18 -0
- data/spec/fixtures/scientific_notation.csv +4 -0
- data/spec/fixtures/string_converter_test.csv +5 -0
- data/spec/fixtures/strings.dat +2 -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 +137 -0
- data/spec/helpers_spec.rb +8 -0
- data/spec/index/categorical_index_spec.rb +170 -0
- data/spec/index/index_spec.rb +417 -0
- data/spec/index/multi_index_spec.rb +680 -0
- data/spec/io/io_spec.rb +373 -0
- data/spec/io/sql_data_source_spec.rb +56 -0
- data/spec/iruby/dataframe_spec.rb +170 -0
- data/spec/iruby/helpers_spec.rb +49 -0
- data/spec/iruby/multi_index_spec.rb +37 -0
- data/spec/iruby/vector_spec.rb +105 -0
- data/spec/maths/arithmetic/dataframe_spec.rb +148 -0
- data/spec/maths/arithmetic/vector_spec.rb +165 -0
- data/spec/maths/statistics/dataframe_spec.rb +178 -0
- data/spec/maths/statistics/vector_spec.rb +756 -0
- data/spec/monkeys_spec.rb +42 -0
- data/spec/shared/vector_display_spec.rb +213 -0
- data/spec/spec_helper.rb +87 -0
- data/spec/support/database_helper.rb +30 -0
- data/spec/support/matchers.rb +5 -0
- data/spec/vector_spec.rb +2293 -0
- metadata +571 -0
|
@@ -0,0 +1,588 @@
|
|
|
1
|
+
include DaruLite
|
|
2
|
+
|
|
3
|
+
describe DateTimeIndex do
|
|
4
|
+
context ".initialize" do
|
|
5
|
+
it "creates DateTimeIndex from Time objects" do
|
|
6
|
+
index = DateTimeIndex.new([
|
|
7
|
+
DateTime.new(2014,7,1),DateTime.new(2014,7,2),
|
|
8
|
+
DateTime.new(2014,7,3),DateTime.new(2014,7,4)])
|
|
9
|
+
expect(index.class).to eq(DateTimeIndex)
|
|
10
|
+
expect(index['2014-7-2']).to eq(1)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "attempts conversion to Time from strings" do
|
|
14
|
+
index = DateTimeIndex.new([
|
|
15
|
+
'2014-7-1','2014-7-2','2014-7-3','2014-7-4'], freq: :infer)
|
|
16
|
+
expect(index.class).to eq(DateTimeIndex)
|
|
17
|
+
expect(index['2014-7-2']).to eq(1)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "tries to automatically infer the frequency of the data" do
|
|
21
|
+
index = DateTimeIndex.new([
|
|
22
|
+
DateTime.new(2012,1,1), DateTime.new(2012,1,2), DateTime.new(2012,1,3),
|
|
23
|
+
DateTime.new(2012,1,4), DateTime.new(2012,1,5)], freq: :infer)
|
|
24
|
+
expect(index.frequency).to eq('D')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "lets setting of string time format" do
|
|
28
|
+
pending
|
|
29
|
+
DaruLite::DateTimeIndex.format = 'some-date-time-format'
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
context '.try_create' do
|
|
34
|
+
it 'creates index from array of dates' do
|
|
35
|
+
index = DateTimeIndex.try_create([
|
|
36
|
+
DateTime.new(2014,7,1),DateTime.new(2014,7,2),
|
|
37
|
+
DateTime.new(2014,7,3),DateTime.new(2014,7,4)])
|
|
38
|
+
expect(index.class).to eq(DateTimeIndex)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'does not creates index from anything else' do
|
|
42
|
+
index = DateTimeIndex.try_create([:a, :b, :c])
|
|
43
|
+
expect(index).to be_nil
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
context ".date_range" do
|
|
48
|
+
it "creates DateTimeIndex with default options" do
|
|
49
|
+
index = DateTimeIndex.date_range(:start => DateTime.new(2014,5,3),
|
|
50
|
+
:end => DateTime.new(2014,5,10))
|
|
51
|
+
|
|
52
|
+
expect(index).to eq(DateTimeIndex.new([
|
|
53
|
+
DateTime.new(2014,5,3),DateTime.new(2014,5,4),DateTime.new(2014,5,5),
|
|
54
|
+
DateTime.new(2014,5,6),DateTime.new(2014,5,7),DateTime.new(2014,5,8),
|
|
55
|
+
DateTime.new(2014,5,9),DateTime.new(2014,5,10)]))
|
|
56
|
+
expect(index.frequency).to eq('D')
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "accepts start and end as strings with default options" do
|
|
60
|
+
index = DateTimeIndex.date_range(start: '2014-5-3', end: '2014-5-10')
|
|
61
|
+
|
|
62
|
+
expect(index).to eq(DateTimeIndex.new([
|
|
63
|
+
DateTime.new(2014,5,3),DateTime.new(2014,5,4),DateTime.new(2014,5,5),
|
|
64
|
+
DateTime.new(2014,5,6),DateTime.new(2014,5,7),DateTime.new(2014,5,8),
|
|
65
|
+
DateTime.new(2014,5,9),DateTime.new(2014,5,10)]))
|
|
66
|
+
expect(index.frequency).to eq('D')
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it 'fails on wrong string format' do
|
|
70
|
+
expect{DateTimeIndex.date_range(start: '2014/5/3', end: '2014/5/10')}
|
|
71
|
+
.to raise_error(ArgumentError, /Unacceptable date string/)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it "creates DateTimeIndex of per minute frequency between start and end" do
|
|
75
|
+
index = DateTimeIndex.date_range(start: '2015-7-1',freq: 'M', periods: 10)
|
|
76
|
+
|
|
77
|
+
expect(index).to eq(DateTimeIndex.new([
|
|
78
|
+
DateTime.new(2015,7,1,0,0,0),DateTime.new(2015,7,1,0,1,0),DateTime.new(2015,7,1,0,2,0),
|
|
79
|
+
DateTime.new(2015,7,1,0,3,0),DateTime.new(2015,7,1,0,4,0),DateTime.new(2015,7,1,0,5,0),
|
|
80
|
+
DateTime.new(2015,7,1,0,6,0),DateTime.new(2015,7,1,0,7,0),DateTime.new(2015,7,1,0,8,0),
|
|
81
|
+
DateTime.new(2015,7,1,0,9,0)]))
|
|
82
|
+
expect(index.frequency).to eq('M')
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "creates a DateTimeIndex of hourly frequency between start and end" do
|
|
86
|
+
index = DateTimeIndex.date_range(start: '2015-7-1',freq: 'H', periods: 10)
|
|
87
|
+
|
|
88
|
+
expect(index).to eq(DateTimeIndex.new([
|
|
89
|
+
DateTime.new(2015,7,1,0,0,0),DateTime.new(2015,7,1,1,0,0),DateTime.new(2015,7,1,2,0,0),
|
|
90
|
+
DateTime.new(2015,7,1,3,0,0),DateTime.new(2015,7,1,4,0,0),DateTime.new(2015,7,1,5,0,0),
|
|
91
|
+
DateTime.new(2015,7,1,6,0,0),DateTime.new(2015,7,1,7,0,0),DateTime.new(2015,7,1,8,0,0),
|
|
92
|
+
DateTime.new(2015,7,1,9,0,0)]))
|
|
93
|
+
expect(index.frequency).to eq('H')
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "creates a DateTimeIndex of daily frequency for specified periods" do
|
|
97
|
+
index = DateTimeIndex.date_range(start: '2015-7-29',freq: 'D',periods: 10)
|
|
98
|
+
|
|
99
|
+
expect(index).to eq(DateTimeIndex.new([
|
|
100
|
+
DateTime.new(2015,7,29,0,0,0),DateTime.new(2015,7,30,0,0,0),DateTime.new(2015,7,31,0,0,0),
|
|
101
|
+
DateTime.new(2015,8,1,0,0,0),DateTime.new(2015,8,2,0,0,0),DateTime.new(2015,8,3,0,0,0),
|
|
102
|
+
DateTime.new(2015,8,4,0,0,0),DateTime.new(2015,8,5,0,0,0),DateTime.new(2015,8,6,0,0,0),
|
|
103
|
+
DateTime.new(2015,8,7,0,0,0)]))
|
|
104
|
+
expect(index.frequency).to eq('D')
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it "creates a DateTimeIndex of (sunday) weekly frequency" do
|
|
108
|
+
index = DateTimeIndex.date_range(start: '2014-8-2', end: '2014-9-8',
|
|
109
|
+
freq: 'W')
|
|
110
|
+
|
|
111
|
+
expect(index).to eq(DateTimeIndex.new([
|
|
112
|
+
DateTime.new(2014,8,3) ,DateTime.new(2014,8,10),DateTime.new(2014,8,17),
|
|
113
|
+
DateTime.new(2014,8,24),DateTime.new(2014,8,31),DateTime.new(2014,9,7)]))
|
|
114
|
+
expect(index.frequency).to eq('W-SUN')
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "creates a DateTimeIndex of (monday) weekly frequency" do
|
|
118
|
+
index = DateTimeIndex.date_range(:start => '2015-7-6', :periods => 5,
|
|
119
|
+
:freq => 'W-MON')
|
|
120
|
+
expect(index).to eq(DateTimeIndex.new([
|
|
121
|
+
DateTime.new(2015,7,6), DateTime.new(2015,7,13), DateTime.new(2015,7,20),
|
|
122
|
+
DateTime.new(2015,7,27), DateTime.new(2015,8,3)]))
|
|
123
|
+
expect(index.frequency).to eq('W-MON')
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it "creates a DateTimeIndex of month begin frequency" do
|
|
127
|
+
index = DateTimeIndex.date_range(
|
|
128
|
+
:start => '2017-4-14', :freq => 'MB', :periods => 5)
|
|
129
|
+
expect(index).to eq(DateTimeIndex.new([
|
|
130
|
+
DateTime.new(2017,5,1), DateTime.new(2017,6,1),
|
|
131
|
+
DateTime.new(2017,7,1), DateTime.new(2017,8,1),DateTime.new(2017,9,1)]))
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it "creates a DateTimeIndex of month end frequency" do
|
|
135
|
+
index = DateTimeIndex.date_range(
|
|
136
|
+
:start => '2014-2-22', freq: 'ME', periods: 6)
|
|
137
|
+
expect(index).to eq(DateTimeIndex.new([
|
|
138
|
+
DateTime.new(2014,2,28), DateTime.new(2014,3,31), DateTime.new(2014,4,30),
|
|
139
|
+
DateTime.new(2014,5,31), DateTime.new(2014,6,30), DateTime.new(2014,7,31)]))
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it "creates a DateTimeIndex of year begin frequency" do
|
|
143
|
+
index = DateTimeIndex.date_range(:start => '2014-4-2', periods: 3, freq: 'YB')
|
|
144
|
+
expect(index).to eq(DateTimeIndex.new([
|
|
145
|
+
DateTime.new(2015,1,1), DateTime.new(2016,1,1), DateTime.new(2017,1,1)]))
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it "creates a DateTimeIndex of year end frequency" do
|
|
149
|
+
index = DateTimeIndex.date_range(start: '2014-9',end: '2018-1',freq: 'YE')
|
|
150
|
+
|
|
151
|
+
expect(index).to eq(DateTimeIndex.new([
|
|
152
|
+
DateTime.new(2014,12,31), DateTime.new(2015,12,31),DateTime.new(2016,12,31),
|
|
153
|
+
DateTime.new(2017,12,31)]))
|
|
154
|
+
expect(index.frequency).to eq('YE')
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
it "creates only specfied number of periods taking precendence over end" do
|
|
158
|
+
index = DateTimeIndex.date_range(start: '2014-5-5', end: '2015-3',
|
|
159
|
+
periods: 5, freq: 'YB')
|
|
160
|
+
expect(index).to eq(DateTimeIndex.new([
|
|
161
|
+
DateTime.new(2015,1,1),DateTime.new(2016,1,1),DateTime.new(2017,1,1),
|
|
162
|
+
DateTime.new(2018,1,1),DateTime.new(2019,1,1)]))
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
it "does not increment start date if it satisifies the anchor" do
|
|
166
|
+
index = DateTimeIndex.date_range(:start => '2012-1-1', freq: 'MB', periods: 4)
|
|
167
|
+
expect(index).to eq(DateTimeIndex.new(
|
|
168
|
+
[DateTime.new(2012,1,1), DateTime.new(2012,2,1),
|
|
169
|
+
DateTime.new(2012,3,1), DateTime.new(2012,4,1)]))
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it "raises error for different start and end timezones" do
|
|
173
|
+
expect {
|
|
174
|
+
DateTimeIndex.date_range(
|
|
175
|
+
:start => DateTime.new(2012,3,4,12,5,4,"+5:30"),
|
|
176
|
+
:end => DateTime.new(2013,3,4,12,5,4,"+7:30"), freq: 'M')
|
|
177
|
+
}.to raise_error(ArgumentError)
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
context '#inspect' do
|
|
182
|
+
subject { index.inspect }
|
|
183
|
+
|
|
184
|
+
context 'with known frequency' do
|
|
185
|
+
let(:index){
|
|
186
|
+
DateTimeIndex.new([
|
|
187
|
+
DateTime.new(2014,7,1),DateTime.new(2014,7,2),DateTime.new(2014,7,3),
|
|
188
|
+
DateTime.new(2014,7,4)], freq: :infer)
|
|
189
|
+
}
|
|
190
|
+
it { is_expected.to eq \
|
|
191
|
+
"#<DaruLite::DateTimeIndex(4, frequency=D) 2014-07-01T00:00:00+00:00...2014-07-04T00:00:00+00:00>"
|
|
192
|
+
}
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
context 'with unknown frequency' do
|
|
196
|
+
let(:index){
|
|
197
|
+
DateTimeIndex.new([
|
|
198
|
+
DateTime.new(2014,7,1),DateTime.new(2014,7,2),DateTime.new(2014,7,3),
|
|
199
|
+
DateTime.new(2014,7,4)])
|
|
200
|
+
}
|
|
201
|
+
it { is_expected.to eq \
|
|
202
|
+
"#<DaruLite::DateTimeIndex(4) 2014-07-01T00:00:00+00:00...2014-07-04T00:00:00+00:00>"
|
|
203
|
+
}
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
context 'empty index' do
|
|
207
|
+
let(:index){ DateTimeIndex.new([]) }
|
|
208
|
+
it { is_expected.to eq "#<DaruLite::DateTimeIndex(0)>" }
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
context "#frequency" do
|
|
213
|
+
it "reports the frequency of when a period index is specified" do
|
|
214
|
+
index = DateTimeIndex.new([
|
|
215
|
+
DateTime.new(2014,7,1),DateTime.new(2014,7,2),DateTime.new(2014,7,3),
|
|
216
|
+
DateTime.new(2014,7,4)], freq: :infer)
|
|
217
|
+
expect(index.frequency).to eq('D')
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
it "reports frequency as nil for non-periodic index" do
|
|
221
|
+
index = DateTimeIndex.new([
|
|
222
|
+
DateTime.new(2014,7,1),DateTime.new(2014,7,2),DateTime.new(2014,7,3),
|
|
223
|
+
DateTime.new(2014,7,10)], freq: :infer)
|
|
224
|
+
expect(index.frequency).to eq(nil)
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
context "#[]" do
|
|
229
|
+
it "accepts complete time as a string" do
|
|
230
|
+
index = DateTimeIndex.new([
|
|
231
|
+
DateTime.new(2014,3,3),DateTime.new(2014,3,4),DateTime.new(2014,3,5),DateTime.new(2014,3,6)],
|
|
232
|
+
freq: :infer)
|
|
233
|
+
expect(index.frequency).to eq('D')
|
|
234
|
+
expect(index['2014-3-5']).to eq(2)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
it "accepts complete time as a DateTime object" do
|
|
238
|
+
index = DateTimeIndex.new([
|
|
239
|
+
DateTime.new(2014,3,3),DateTime.new(2014,3,4),DateTime.new(2014,3,5),DateTime.new(2014,3,6)],
|
|
240
|
+
freq: :infer)
|
|
241
|
+
expect(index[DateTime.new(2014,3,6)]).to eq(3)
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
it "accepts only year specified as a string" do
|
|
245
|
+
index = DateTimeIndex.new([
|
|
246
|
+
DateTime.new(2014,5),DateTime.new(2018,6),DateTime.new(2014,7),DateTime.new(2016,7),
|
|
247
|
+
DateTime.new(2015,7),DateTime.new(2013,7)])
|
|
248
|
+
expect(index['2014']).to eq(DateTimeIndex.new([
|
|
249
|
+
DateTime.new(2014,5),DateTime.new(2014,7)]))
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
it 'does not fail on absent data' do
|
|
253
|
+
index = DateTimeIndex.new([
|
|
254
|
+
DateTime.new(2014,5),DateTime.new(2018,6),DateTime.new(2014,7),DateTime.new(2016,7),
|
|
255
|
+
DateTime.new(2013,7)])
|
|
256
|
+
p DateTimeIndex.new([])
|
|
257
|
+
expect(index['2015']).to eq(DateTimeIndex.new([]))
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
it "accepts only year for frequency data" do
|
|
261
|
+
index = DateTimeIndex.date_range(:start => DateTime.new(2012,3,2),
|
|
262
|
+
periods: 1000, freq: '5D')
|
|
263
|
+
expect(index['2012']).to eq(DateTimeIndex.date_range(
|
|
264
|
+
:start => DateTime.new(2012,3,2), :end => DateTime.new(2012,12,27), freq: '5D'))
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
it "accepts year and month specified as a string" do
|
|
268
|
+
index = DateTimeIndex.new([
|
|
269
|
+
DateTime.new(2014,5,3),DateTime.new(2014,5,4),DateTime.new(2014,5,5),
|
|
270
|
+
DateTime.new(2014,6,3),DateTime.new(2014,7,4),DateTime.new(2014,6,5),
|
|
271
|
+
DateTime.new(2014,7,3),DateTime.new(2014,7,4),DateTime.new(2014,7,5)])
|
|
272
|
+
expect(index['2014-6']).to eq(DateTimeIndex.new([
|
|
273
|
+
DateTime.new(2014,6,3),DateTime.new(2014,6,5)]))
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
it "accepts year and month for frequency data" do
|
|
277
|
+
index = DateTimeIndex.date_range(start: '2014-1-1', periods: 100, freq: 'MB')
|
|
278
|
+
expect(index['2015-3']).to eq(14)
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
it "accepts year, month and date specified as a string" do
|
|
282
|
+
index = DateTimeIndex.new([
|
|
283
|
+
DateTime.new(2012,2,28,0,0,1),DateTime.new(2012,2,25,0,0,1),
|
|
284
|
+
DateTime.new(2012,2,29,0,1,1),DateTime.new(2012,2,29,0,1,3),
|
|
285
|
+
DateTime.new(2012,2,29,0,1,5)])
|
|
286
|
+
expect(index['2012-2-29']).to eq(DateTimeIndex.new([
|
|
287
|
+
DateTime.new(2012,2,29,0,1,1),DateTime.new(2012,2,29,0,1,3),
|
|
288
|
+
DateTime.new(2012,2,29,0,1,5)]))
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
it "accepts year, month, date for frequency data" do
|
|
292
|
+
index = DateTimeIndex.date_range(:start => DateTime.new(2012,2,29),
|
|
293
|
+
periods: 1000, freq: 'M')
|
|
294
|
+
expect(index['2012-2-29']).to eq(DateTimeIndex.date_range(
|
|
295
|
+
:start => DateTime.new(2012,2,29),
|
|
296
|
+
:end => DateTime.new(2012,2,29,16,39,00), freq: 'M'))
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
it "accepts year, month, date and specific time as a string" do
|
|
300
|
+
index = DateTimeIndex.date_range(
|
|
301
|
+
:start => DateTime.new(2015,5,3),:end => DateTime.new(2015,5,5), freq: 'M')
|
|
302
|
+
expect(index['2015-5-3 00:04:00']).to eq(4)
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
it "accepts with seconds accuracy" do
|
|
306
|
+
index = DateTimeIndex.date_range(
|
|
307
|
+
:start => DateTime.new(2012,3,2,21,4,2), :end => DateTime.new(2012,3,2,21,5,2),
|
|
308
|
+
:freq => 'S')
|
|
309
|
+
expect(index['2012-3-2 21:04:04']).to eq(2)
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
it "supports completely specified time ranges" do
|
|
313
|
+
index = DateTimeIndex.date_range(start: '2011-4-1', periods: 50, freq: 'D')
|
|
314
|
+
expect(index['2011-4-5'..'2011-5-3']).to eq(
|
|
315
|
+
DateTimeIndex.date_range(:start => '2011-4-5', :end => '2011-5-3', freq: 'D'))
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
it "supports time ranges with only year specified" do
|
|
319
|
+
index = DateTimeIndex.date_range(start: '2011-5-5', periods: 50, freq: 'MONTH')
|
|
320
|
+
expect(index['2011'..'2012']).to eq(
|
|
321
|
+
DateTimeIndex.date_range(:start => '2011-5-5', :end => '2012-12-5',
|
|
322
|
+
:freq => 'MONTH'))
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
it "supports time ranges with year and month specified" do
|
|
326
|
+
index = DateTimeIndex.date_range(:start => '2016-4-3', periods: 100, freq: 'D')
|
|
327
|
+
expect(index['2016-4'..'2016-5']).to eq(
|
|
328
|
+
DateTimeIndex.date_range(:start => '2016-4-3', periods: 59, freq: 'D'))
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
it "supports time range with year, month and date specified" do
|
|
332
|
+
index = DateTimeIndex.date_range(:start => '2015-7-4', :end => '2015-12-3')
|
|
333
|
+
expect(index['2015-7-4'..'2015-9-3']).to eq(
|
|
334
|
+
DateTimeIndex.date_range(:start => '2015-7-4', :end => '2015-9-3'))
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
it "supports time range with year, month, date and hours specified" do
|
|
338
|
+
index = DateTimeIndex.date_range(:start => '2015-4-2', periods: 120, freq: 'H')
|
|
339
|
+
expect(index['2015-4-3 00:00'..'2015-4-3 12:00']).to eq(
|
|
340
|
+
DateTimeIndex.date_range(:start => '2015-4-3', freq: 'H', periods: 13))
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
it "returns slice upto last element if overshoot in partial date" do
|
|
344
|
+
index = DateTimeIndex.date_range(:start => '2012-4-2', periods: 100, freq: 'M')
|
|
345
|
+
expect(index['2012-4-2']).to eq(DateTimeIndex.date_range(
|
|
346
|
+
:start => '2012-4-2', periods: 100, freq: 'M'))
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
it "returns slice upto last element if overshoot in range" do
|
|
350
|
+
index = DateTimeIndex.date_range(:start => '2012-2-2', :periods => 50,
|
|
351
|
+
freq: 'M')
|
|
352
|
+
expect(index['2012'..'2013']).to eq(DateTimeIndex.date_range(
|
|
353
|
+
:start => '2012-2-2',:periods => 50, freq: 'M'))
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
it "returns a slice when given a numeric range" do
|
|
357
|
+
index = DateTimeIndex.date_range(
|
|
358
|
+
:start => DateTime.new(2012,3,1), :periods => 50)
|
|
359
|
+
expect(index[4..10]).to eq(
|
|
360
|
+
DateTimeIndex.date_range(:start => DateTime.new(2012,3,5), :periods => 7))
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
it "raises error if key out of bounds" do
|
|
364
|
+
index = DateTimeIndex.date_range(:start => '2012-1', :periods => 5)
|
|
365
|
+
expect{
|
|
366
|
+
index['2011']
|
|
367
|
+
}.to raise_error(ArgumentError)
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
it "raises error if date not present (exact date)" do
|
|
371
|
+
expect {
|
|
372
|
+
index = DateTimeIndex.date_range(:start => '2011', :periods => 5, :freq => 'MONTH')
|
|
373
|
+
index[DateTime.new(2013,1,4)]
|
|
374
|
+
}.to raise_error(ArgumentError)
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
it "raises error if date not present (string)" do
|
|
378
|
+
expect {
|
|
379
|
+
index = DateTimeIndex.date_range(:start => '2012-2-3', :periods => 10)
|
|
380
|
+
index['2012-2-4 12']
|
|
381
|
+
}.to raise_error(ArgumentError)
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
it "raises error for out of bounds range" do
|
|
385
|
+
expect {
|
|
386
|
+
index = DateTimeIndex.date_range(:start => '2012', :periods => 100)
|
|
387
|
+
index['2001'..'2005']
|
|
388
|
+
}.to raise_error(ArgumentError)
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
context "#pos" do
|
|
393
|
+
let(:idx) do
|
|
394
|
+
described_class.new([
|
|
395
|
+
DateTime.new(2014,3,3),
|
|
396
|
+
DateTime.new(2014,3,4),
|
|
397
|
+
DateTime.new(2014,3,5),
|
|
398
|
+
DateTime.new(2014,3,6)
|
|
399
|
+
], freq: :infer
|
|
400
|
+
)
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
context "single index" do
|
|
404
|
+
it { expect(idx.pos '2014-3-4').to eq 1 }
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
context "multiple indexes" do
|
|
408
|
+
subject { idx.pos '2014' }
|
|
409
|
+
|
|
410
|
+
it { is_expected.to be_a Array }
|
|
411
|
+
its(:size) { is_expected.to eq 4 }
|
|
412
|
+
it { is_expected.to eq [0, 1, 2, 3] }
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
context "single positional index" do
|
|
416
|
+
it { expect(idx.pos 1).to eq 1 }
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
context "multiple positional indexes" do
|
|
420
|
+
subject { idx.pos 0, 2 }
|
|
421
|
+
|
|
422
|
+
it { is_expected.to be_a Array }
|
|
423
|
+
its(:size) { is_expected.to eq 3 }
|
|
424
|
+
it { is_expected.to eq [0, 1, 2] }
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
context "#subset" do
|
|
429
|
+
let(:idx) do
|
|
430
|
+
described_class.new([
|
|
431
|
+
DateTime.new(2014,3,3),
|
|
432
|
+
DateTime.new(2014,3,4),
|
|
433
|
+
DateTime.new(2014,3,5),
|
|
434
|
+
DateTime.new(2014,3,6)
|
|
435
|
+
], freq: :infer
|
|
436
|
+
)
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
context "multiple indexes" do
|
|
440
|
+
subject { idx.subset '2014' }
|
|
441
|
+
|
|
442
|
+
it { is_expected.to be_a described_class }
|
|
443
|
+
its(:size) { is_expected.to eq 4 }
|
|
444
|
+
it { is_expected.to eq idx }
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
context "multiple positional indexes" do
|
|
448
|
+
subject { idx.subset 0, 2 }
|
|
449
|
+
|
|
450
|
+
it { is_expected.to be_a described_class }
|
|
451
|
+
its(:size) { is_expected.to eq 3 }
|
|
452
|
+
its(:to_a) { is_expected.to eq [DateTime.new(2014, 3, 3),
|
|
453
|
+
DateTime.new(2014, 3, 4), DateTime.new(2014, 3, 5)] }
|
|
454
|
+
end
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
context "#slice" do
|
|
458
|
+
it "supports both DateTime objects" do
|
|
459
|
+
index = DateTimeIndex.date_range(:start => '2012', :periods => 50,
|
|
460
|
+
:freq => 'M')
|
|
461
|
+
expect(index.slice(DateTime.new(2012,1,1), DateTime.new(2012,1,1,0,6))).to eq(
|
|
462
|
+
DateTimeIndex.date_range(:start => '2012', :periods => 7, :freq => 'M'))
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
it "supports single DateTime object on the left" do
|
|
466
|
+
index = DateTimeIndex.date_range(:start => '2012', :periods => 40, :freq => 'M')
|
|
467
|
+
expect(index.slice('2012', DateTime.new(2012,1,1,0,20))).to eq(
|
|
468
|
+
DateTimeIndex.date_range(:start => '2012', :periods => 21, :freq => 'M'))
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
it "supports single DateTime object on the right" do
|
|
472
|
+
index = DateTimeIndex.date_range(:start => '2012', :periods => 40, :freq => 'MONTH')
|
|
473
|
+
expect(index.slice(DateTime.new(2012), '2013')).to eq(
|
|
474
|
+
DateTimeIndex.date_range(:start => '2012', :periods => 24, :freq => 'MONTH'))
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
it "supports two strings" do
|
|
478
|
+
index = DateTimeIndex.date_range(:start => '2012', :periods => 40, :freq => 'MONTH')
|
|
479
|
+
expect(index.slice('2012', '2013')).to eq(
|
|
480
|
+
DateTimeIndex.date_range(:start => '2012', :periods => 24, :freq => 'MONTH'))
|
|
481
|
+
|
|
482
|
+
# FIXME: It works this way now, yet I'm faithfully not sure that is most
|
|
483
|
+
# reasonable behavior. At least MY expectation is "slice(2012, 2013)" returns
|
|
484
|
+
# "from start of 2012 to start of 2013"... Or am I missing something?.. - zverok
|
|
485
|
+
end
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
context "#size" do
|
|
489
|
+
it "returns the size of the DateTimeIndex" do
|
|
490
|
+
index = DateTimeIndex.date_range start: DateTime.new(2014,5,3), periods: 100
|
|
491
|
+
expect(index.size).to eq(100)
|
|
492
|
+
end
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
context "#add" do
|
|
496
|
+
before { skip }
|
|
497
|
+
let(:idx) { DaruLite::Index.new [:a, :b, :c] }
|
|
498
|
+
|
|
499
|
+
context "single index" do
|
|
500
|
+
subject { idx }
|
|
501
|
+
before { idx.add :d }
|
|
502
|
+
|
|
503
|
+
its(:to_a) { is_expected.to eq [:a, :b, :c, :d] }
|
|
504
|
+
end
|
|
505
|
+
|
|
506
|
+
context "mulitple indexes" do
|
|
507
|
+
subject { idx }
|
|
508
|
+
before { idx.add :d, :e }
|
|
509
|
+
|
|
510
|
+
its(:to_a) { is_expected.to eq [:a, :b, :c, :d, :e] }
|
|
511
|
+
end
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
context "#to_a" do
|
|
515
|
+
it "returns an Array of ruby Time objects" do
|
|
516
|
+
index = DateTimeIndex.date_range(
|
|
517
|
+
start: DateTime.new(2012,2,1), :end => DateTime.new(2012,2,4))
|
|
518
|
+
expect(index.to_a).to eq([
|
|
519
|
+
DateTime.new(2012,2,1),DateTime.new(2012,2,2),DateTime.new(2012,2,3),DateTime.new(2012,2,4)])
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
context 'empty index' do
|
|
523
|
+
subject(:index) { DateTimeIndex.new([]) }
|
|
524
|
+
its(:to_a) { is_expected.to eq [] }
|
|
525
|
+
end
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
context "#shift" do
|
|
529
|
+
it "shifts all dates to the future by specified value (with offset)" do
|
|
530
|
+
index = DateTimeIndex.date_range(
|
|
531
|
+
:start => '2012-1-1', :freq => 'MB', :periods => 10)
|
|
532
|
+
expect(index.shift(3)).to eq(DateTimeIndex.date_range(
|
|
533
|
+
:start => '2012-4-1', :freq => 'MB', :periods => 10))
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
it "shifts all dates by the given offset" do
|
|
537
|
+
offset = DaruLite::Offsets::Minute.new
|
|
538
|
+
index = DateTimeIndex.date_range(
|
|
539
|
+
:start => '2012-3-1', :freq => 'D', :periods => 10)
|
|
540
|
+
expect(index.shift(offset)).to eq(
|
|
541
|
+
DateTimeIndex.date_range(
|
|
542
|
+
:start => '2012-3-1 00:01', :freq => 'D', :periods => 10))
|
|
543
|
+
end
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
context "#lag" do
|
|
547
|
+
it "shifts all dates to the past by specified value (with offset)" do
|
|
548
|
+
index = DateTimeIndex.date_range(
|
|
549
|
+
:start => '2012-5-5', :freq => 'D', :periods => 5)
|
|
550
|
+
expect(index.lag(2)).to eq(DateTimeIndex.date_range(
|
|
551
|
+
:start => '2012-5-3', :freq => 'D', :periods => 5))
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
it "lags all dates by the given offset" do
|
|
555
|
+
offset = DaruLite::Offsets::Month.new
|
|
556
|
+
index = DateTimeIndex.date_range(
|
|
557
|
+
:start => '2012-4-5', :freq => 'MONTH', :periods => 10)
|
|
558
|
+
expect(index.lag(offset)).to eq(
|
|
559
|
+
DateTimeIndex.date_range(:start => '2012-3-5', :periods => 10, freq: offset))
|
|
560
|
+
end
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
[:year, :month, :day, :hour, :min, :sec].each do |meth|
|
|
564
|
+
dates = [
|
|
565
|
+
DateTime.new(2012,5,1,12,5,4), DateTime.new(2015,5,1,13,5),
|
|
566
|
+
DateTime.new(2012,8,1,12,5,3), DateTime.new(2015,1,4,16,5,44)
|
|
567
|
+
]
|
|
568
|
+
curated = dates.inject([]) do |arr, e|
|
|
569
|
+
arr << e.send(meth)
|
|
570
|
+
arr
|
|
571
|
+
end
|
|
572
|
+
|
|
573
|
+
context "##{meth}" do
|
|
574
|
+
it "returns #{meth} of all dates as an Array" do
|
|
575
|
+
index = DateTimeIndex.new(dates)
|
|
576
|
+
expect(index.send(meth)).to eq(curated)
|
|
577
|
+
end
|
|
578
|
+
end
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
context "#include?" do
|
|
582
|
+
it "returns true if an index is present" do
|
|
583
|
+
index = DateTimeIndex.date_range(:start => '2012-1-4', :periods => 100, :freq => 'D')
|
|
584
|
+
expect(index.include?(DateTime.new(2012,1,6))).to eq(true)
|
|
585
|
+
expect(index.include?(DateTime.new(2011,4,2))).to eq(false)
|
|
586
|
+
end
|
|
587
|
+
end
|
|
588
|
+
end
|