daru 0.1.0 → 0.1.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 +4 -4
- data/.build.sh +6 -6
- data/.gitignore +2 -0
- data/CONTRIBUTING.md +7 -3
- data/History.md +36 -0
- data/README.md +21 -13
- data/Rakefile +16 -1
- data/benchmarks/TradeoffData.csv +65 -0
- data/benchmarks/dataframe_creation.rb +39 -0
- data/benchmarks/group_by.rb +32 -0
- data/benchmarks/row_access.rb +41 -0
- data/benchmarks/row_assign.rb +36 -0
- data/benchmarks/sorting.rb +44 -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.gemspec +29 -5
- data/lib/daru.rb +30 -1
- data/lib/daru/accessors/array_wrapper.rb +2 -2
- data/lib/daru/accessors/nmatrix_wrapper.rb +6 -6
- data/lib/daru/core/group_by.rb +112 -31
- data/lib/daru/core/merge.rb +170 -0
- data/lib/daru/core/query.rb +95 -0
- data/lib/daru/dataframe.rb +335 -223
- data/lib/daru/date_time/index.rb +550 -0
- data/lib/daru/date_time/offsets.rb +397 -0
- data/lib/daru/index.rb +266 -54
- data/lib/daru/io/io.rb +1 -2
- data/lib/daru/maths/arithmetic/dataframe.rb +2 -2
- data/lib/daru/maths/arithmetic/vector.rb +2 -2
- data/lib/daru/maths/statistics/dataframe.rb +58 -8
- data/lib/daru/maths/statistics/vector.rb +229 -0
- data/lib/daru/vector.rb +230 -80
- data/lib/daru/version.rb +1 -1
- data/spec/core/group_by_spec.rb +16 -16
- data/spec/core/merge_spec.rb +52 -0
- data/spec/core/query_spec.rb +171 -0
- data/spec/dataframe_spec.rb +278 -280
- data/spec/date_time/data_spec.rb +199 -0
- data/spec/date_time/index_spec.rb +433 -0
- data/spec/date_time/offsets_spec.rb +371 -0
- data/spec/fixtures/stock_data.csv +500 -0
- data/spec/index_spec.rb +317 -11
- data/spec/io/io_spec.rb +18 -17
- data/spec/math/arithmetic/dataframe_spec.rb +3 -3
- data/spec/math/statistics/dataframe_spec.rb +39 -1
- data/spec/math/statistics/vector_spec.rb +163 -1
- data/spec/monkeys_spec.rb +4 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/vector_spec.rb +125 -60
- metadata +71 -14
- data/lib/daru/accessors/dataframe_by_vector.rb +0 -17
- data/lib/daru/multi_index.rb +0 -216
- data/spec/multi_index_spec.rb +0 -216
@@ -0,0 +1,199 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Daru::Vector do
|
4
|
+
context "#initialize" do
|
5
|
+
it "accepts DateTimeIndex in index option" do
|
6
|
+
index = Daru::DateTimeIndex.date_range(:start => DateTime.new(2012,2,1), periods: 100)
|
7
|
+
vector = Daru::Vector.new [1,2,3,4,5]*20, index: index
|
8
|
+
|
9
|
+
expect(vector.class).to eq(Daru::Vector)
|
10
|
+
expect(vector['2012-2-3']).to eq(3)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context "#[]" do
|
15
|
+
before do
|
16
|
+
index = Daru::DateTimeIndex.date_range(
|
17
|
+
:start => DateTime.new(2012,4,4), :end => DateTime.new(2012,4,7), freq: 'H')
|
18
|
+
@vector = Daru::Vector.new([23]*index.size, index: index)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "returns the element when complete date" do
|
22
|
+
expect(@vector['2012-4-4 22:00:00']).to eq(23)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "accepts DateTime object for [] argument" do
|
26
|
+
expect(@vector[DateTime.new(2012,4,4,22)]).to eq(23)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "returns slice when partial date" do
|
30
|
+
slice_index = Daru::DateTimeIndex.date_range(
|
31
|
+
:start => DateTime.new(2012,4,4), :periods => 24, freq: 'H')
|
32
|
+
expect(@vector['2012-4-4']).to eq(
|
33
|
+
Daru::Vector.new([23]*slice_index.size, index: slice_index))
|
34
|
+
end
|
35
|
+
|
36
|
+
it "returns a slice when range" do
|
37
|
+
slice_index = Daru::DateTimeIndex.date_range(
|
38
|
+
:start => DateTime.new(2012,4,4), :end => DateTime.new(2012,4,5,23,), freq: 'H')
|
39
|
+
expect(@vector['2012-4-4'..'2012-4-5']).to eq(
|
40
|
+
Daru::Vector.new([23]*slice_index.size, index: slice_index))
|
41
|
+
end
|
42
|
+
|
43
|
+
it "returns a slice when numeric range" do
|
44
|
+
slice_index = Daru::DateTimeIndex.date_range(
|
45
|
+
:start => DateTime.new(2012,4,4), :periods => 20, :freq => 'H')
|
46
|
+
expect(@vector[0..19]).to eq(
|
47
|
+
Daru::Vector.new([23]*slice_index.size, index: slice_index))
|
48
|
+
end
|
49
|
+
|
50
|
+
it "returns the element when number" do
|
51
|
+
expect(@vector[32]).to eq(23)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "#[]=" do
|
56
|
+
it "assigns a single element when index complete" do
|
57
|
+
index = Daru::DateTimeIndex.date_range(:start => '2012', :periods => 5, :freq => 'D')
|
58
|
+
vector = Daru::Vector.new([1,2,3,4,5], index: index)
|
59
|
+
vector['2012-1-4'] = 666
|
60
|
+
expect(vector).to eq(Daru::Vector.new([1,2,3,666,5], index: index))
|
61
|
+
end
|
62
|
+
|
63
|
+
it "assigns single element when specified a number for indexing" do
|
64
|
+
index = Daru::DateTimeIndex.date_range(:start => '2012', :periods => 5, :freq => 'D')
|
65
|
+
vector = Daru::Vector.new([1,2,3,4,5], index: index)
|
66
|
+
|
67
|
+
vector[2] = 666
|
68
|
+
expect(vector).to eq(
|
69
|
+
Daru::Vector.new([1,2,666,4,5], index: index))
|
70
|
+
end
|
71
|
+
|
72
|
+
it "assigns multiple elements when index incomplete" do
|
73
|
+
index = Daru::DateTimeIndex.date_range(:start => '2012', :periods => 100,
|
74
|
+
:freq => 'MB')
|
75
|
+
vector = Daru::Vector.new([1,2,3,4,5,6,7,8,9,10]*10, index: index)
|
76
|
+
vector['2012'] = 666
|
77
|
+
arr = [666]*12 + [3,4,5,6,7,8,9,10] + [1,2,3,4,5,6,7,8,9,10]*8
|
78
|
+
expect(vector).to eq(Daru::Vector.new(arr, index: index))
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe Daru::DataFrame do
|
84
|
+
before :each do
|
85
|
+
@index = Daru::DateTimeIndex.date_range(:start => '2012-2-1', periods: 100)
|
86
|
+
@order = Daru::DateTimeIndex.new([
|
87
|
+
DateTime.new(2012,1,3),DateTime.new(2013,2,3),DateTime.new(2012,3,3)])
|
88
|
+
@a = [1,2,3,4,5]*20
|
89
|
+
@b = @a.map { |e| e*3 }
|
90
|
+
@c = @a.map(&:to_s)
|
91
|
+
@df = Daru::DataFrame.new([@a, @b, @c], index: @index, order: @order)
|
92
|
+
end
|
93
|
+
|
94
|
+
context "#initialize" do
|
95
|
+
it "accepts DateTimeIndex for index and order options" do
|
96
|
+
expect(@df.index).to eq(@index)
|
97
|
+
expect(@df['2013-2-3']).to eq(
|
98
|
+
Daru::Vector.new(@b, index: @index))
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context "#[]" do
|
103
|
+
it "returns one Vector when complete index" do
|
104
|
+
expect(@df['2012-3-3']).to eq(Daru::Vector.new(@c, index: @index))
|
105
|
+
end
|
106
|
+
|
107
|
+
it "returns a Vector when DateTime object specified" do
|
108
|
+
expect(@df[DateTime.new(2012,3,3)]).to eq(
|
109
|
+
Daru::Vector.new(@c, index: @index))
|
110
|
+
end
|
111
|
+
|
112
|
+
it "returns DataFrame when incomplete index" do
|
113
|
+
answer = Daru::DataFrame.new(
|
114
|
+
[@a, @c], index: @index, order: Daru::DateTimeIndex.new([
|
115
|
+
DateTime.new(2012,1,3),DateTime.new(2012,3,3)]))
|
116
|
+
expect(@df['2012']).to eq(answer)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "returns Vector when single index specified as a number" do
|
120
|
+
expect(@df[1]).to eq(Daru::Vector.new(@b, index: @index))
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "#[]=" do
|
125
|
+
it "assigns one Vector when complete index" do
|
126
|
+
answer = Daru::DataFrame.new([@a, @b, @a], index: @index, order: @order)
|
127
|
+
@df['2012-3-3'] = @a
|
128
|
+
expect(@df).to eq(answer)
|
129
|
+
end
|
130
|
+
|
131
|
+
it "assigns one Vector when index as DateTime object" do
|
132
|
+
answer = Daru::DataFrame.new([@a, @b, @a], index: @index, order: @order)
|
133
|
+
@df[DateTime.new(2012,3,3)] = @a
|
134
|
+
expect(@df).to eq(answer)
|
135
|
+
end
|
136
|
+
|
137
|
+
it "assigns multiple vectors when incomplete index" do
|
138
|
+
answer = Daru::DataFrame.new([@b,@b,@b], index: @index, order: @order)
|
139
|
+
@df['2012'] = @b
|
140
|
+
expect(@df).to eq(answer)
|
141
|
+
end
|
142
|
+
|
143
|
+
it "assigns Vector when specified position index" do
|
144
|
+
answer = Daru::DataFrame.new([@a, @b, @a], index: @index, order: @order)
|
145
|
+
@df[2] = @a
|
146
|
+
expect(@df).to eq(answer)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
context "#row[]" do
|
151
|
+
it "returns one row Vector when complete index" do
|
152
|
+
expect(@df.row['2012-2-1']).to eq(Daru::Vector.new([1,3,"1"], index: @order))
|
153
|
+
end
|
154
|
+
|
155
|
+
it "returns one row when complete DateTime specified" do
|
156
|
+
expect(@df.row[DateTime.new(2012,2,1)]).to eq(
|
157
|
+
Daru::Vector.new([1,3,"1"], index: @order))
|
158
|
+
end
|
159
|
+
|
160
|
+
it "returns DataFrame when incomplete index" do
|
161
|
+
range = 0..28
|
162
|
+
a = @a[range]
|
163
|
+
b = @b[range]
|
164
|
+
c = @c[range]
|
165
|
+
i = Daru::DateTimeIndex.date_range(:start => '2012-2-1', periods: 29)
|
166
|
+
answer = Daru::DataFrame.new([a,b,c], index: i, order: @order)
|
167
|
+
|
168
|
+
expect(@df.row['2012-2']).to eq(answer)
|
169
|
+
end
|
170
|
+
|
171
|
+
it "returns one row Vector when position index" do
|
172
|
+
expect(@df.row[2]).to eq(Daru::Vector.new([3,9,'3'], index: @order))
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
context "#row[]=" do
|
177
|
+
it "assigns one row Vector when complete index" do
|
178
|
+
@df.row['2012-2-4'] = [666,999,0]
|
179
|
+
expect(@df.row['2012-2-4']).to eq(Daru::Vector.new([666,999,0], index: @order))
|
180
|
+
end
|
181
|
+
|
182
|
+
it "assigns one row Vector when complete index as DateTime" do
|
183
|
+
@df.row[DateTime.new(2012,2,5)] = [1,2,3]
|
184
|
+
expect(@df.row[DateTime.new(2012,2,5)]).to eq(
|
185
|
+
Daru::Vector.new([1,2,3], index: @order))
|
186
|
+
end
|
187
|
+
|
188
|
+
it "assigns multiple rows when incomplete index" do
|
189
|
+
a = [666]*29
|
190
|
+
b = [999]*29
|
191
|
+
c = [0]*29
|
192
|
+
index = Daru::DateTimeIndex.date_range(:start => '2012-2-1', :periods => 29)
|
193
|
+
answer = Daru::DataFrame.new([a,b,c], index: index, order: @order)
|
194
|
+
@df.row['2012-2'] = [666,999,0]
|
195
|
+
|
196
|
+
expect(@df.row['2012-2']).to eq(answer)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,433 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
include Daru
|
4
|
+
|
5
|
+
describe DateTimeIndex do
|
6
|
+
context ".initialize" do
|
7
|
+
it "creates DateTimeIndex from Time objects" do
|
8
|
+
index = DateTimeIndex.new([
|
9
|
+
DateTime.new(2014,7,1),DateTime.new(2014,7,2),
|
10
|
+
DateTime.new(2014,7,3),DateTime.new(2014,7,4)])
|
11
|
+
expect(index.class).to eq(DateTimeIndex)
|
12
|
+
expect(index['2014-7-2']).to eq(1)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "attempts conversion to Time from strings" do
|
16
|
+
index = DateTimeIndex.new([
|
17
|
+
'2014-7-1','2014-7-2','2014-7-3','2014-7-4'], freq: :infer)
|
18
|
+
expect(index.class).to eq(DateTimeIndex)
|
19
|
+
expect(index['2014-7-2']).to eq(1)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "tries to automatically infer the frequency of the data" do
|
23
|
+
index = DateTimeIndex.new([
|
24
|
+
DateTime.new(2012,1,1), DateTime.new(2012,1,2), DateTime.new(2012,1,3),
|
25
|
+
DateTime.new(2012,1,4), DateTime.new(2012,1,5)], freq: :infer)
|
26
|
+
expect(index.frequency).to eq('D')
|
27
|
+
end
|
28
|
+
|
29
|
+
it "lets setting of string time format" do
|
30
|
+
pending
|
31
|
+
Daru::DateTimeIndex.format = 'some-date-time-format'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context ".date_range" do
|
36
|
+
it "creates DateTimeIndex with default options" do
|
37
|
+
index = DateTimeIndex.date_range(:start => DateTime.new(2014,5,3),
|
38
|
+
:end => DateTime.new(2014,5,10))
|
39
|
+
|
40
|
+
expect(index).to eq(DateTimeIndex.new([
|
41
|
+
DateTime.new(2014,5,3),DateTime.new(2014,5,4),DateTime.new(2014,5,5),
|
42
|
+
DateTime.new(2014,5,6),DateTime.new(2014,5,7),DateTime.new(2014,5,8),
|
43
|
+
DateTime.new(2014,5,9),DateTime.new(2014,5,10)]))
|
44
|
+
expect(index.frequency).to eq('D')
|
45
|
+
end
|
46
|
+
|
47
|
+
it "accepts start and end as strings with default options" do
|
48
|
+
index = DateTimeIndex.date_range(start: '2014-5-3', end: '2014-5-10')
|
49
|
+
|
50
|
+
expect(index).to eq(DateTimeIndex.new([
|
51
|
+
DateTime.new(2014,5,3),DateTime.new(2014,5,4),DateTime.new(2014,5,5),
|
52
|
+
DateTime.new(2014,5,6),DateTime.new(2014,5,7),DateTime.new(2014,5,8),
|
53
|
+
DateTime.new(2014,5,9),DateTime.new(2014,5,10)]))
|
54
|
+
expect(index.frequency).to eq('D')
|
55
|
+
end
|
56
|
+
|
57
|
+
it "creates DateTimeIndex of per minute frequency between start and end" do
|
58
|
+
index = DateTimeIndex.date_range(start: '2015-7-1',freq: 'M', periods: 10)
|
59
|
+
|
60
|
+
expect(index).to eq(DateTimeIndex.new([
|
61
|
+
DateTime.new(2015,7,1,0,0,0),DateTime.new(2015,7,1,0,1,0),DateTime.new(2015,7,1,0,2,0),
|
62
|
+
DateTime.new(2015,7,1,0,3,0),DateTime.new(2015,7,1,0,4,0),DateTime.new(2015,7,1,0,5,0),
|
63
|
+
DateTime.new(2015,7,1,0,6,0),DateTime.new(2015,7,1,0,7,0),DateTime.new(2015,7,1,0,8,0),
|
64
|
+
DateTime.new(2015,7,1,0,9,0)]))
|
65
|
+
expect(index.frequency).to eq('M')
|
66
|
+
end
|
67
|
+
|
68
|
+
it "creates a DateTimeIndex of hourly frequency between start and end" do
|
69
|
+
index = DateTimeIndex.date_range(start: '2015-7-1',freq: 'H', periods: 10)
|
70
|
+
|
71
|
+
expect(index).to eq(DateTimeIndex.new([
|
72
|
+
DateTime.new(2015,7,1,0,0,0),DateTime.new(2015,7,1,1,0,0),DateTime.new(2015,7,1,2,0,0),
|
73
|
+
DateTime.new(2015,7,1,3,0,0),DateTime.new(2015,7,1,4,0,0),DateTime.new(2015,7,1,5,0,0),
|
74
|
+
DateTime.new(2015,7,1,6,0,0),DateTime.new(2015,7,1,7,0,0),DateTime.new(2015,7,1,8,0,0),
|
75
|
+
DateTime.new(2015,7,1,9,0,0)]))
|
76
|
+
expect(index.frequency).to eq('H')
|
77
|
+
end
|
78
|
+
|
79
|
+
it "creates a DateTimeIndex of daily frequency for specified periods" do
|
80
|
+
index = DateTimeIndex.date_range(start: '2015-7-29',freq: 'D',periods: 10)
|
81
|
+
|
82
|
+
expect(index).to eq(DateTimeIndex.new([
|
83
|
+
DateTime.new(2015,7,29,0,0,0),DateTime.new(2015,7,30,0,0,0),DateTime.new(2015,7,31,0,0,0),
|
84
|
+
DateTime.new(2015,8,1,0,0,0),DateTime.new(2015,8,2,0,0,0),DateTime.new(2015,8,3,0,0,0),
|
85
|
+
DateTime.new(2015,8,4,0,0,0),DateTime.new(2015,8,5,0,0,0),DateTime.new(2015,8,6,0,0,0),
|
86
|
+
DateTime.new(2015,8,7,0,0,0)]))
|
87
|
+
expect(index.frequency).to eq('D')
|
88
|
+
end
|
89
|
+
|
90
|
+
it "creates a DateTimeIndex of (sunday) weekly frequency" do
|
91
|
+
index = DateTimeIndex.date_range(start: '2014-8-2', end: '2014-9-8',
|
92
|
+
freq: 'W')
|
93
|
+
|
94
|
+
expect(index).to eq(DateTimeIndex.new([
|
95
|
+
DateTime.new(2014,8,3) ,DateTime.new(2014,8,10),DateTime.new(2014,8,17),
|
96
|
+
DateTime.new(2014,8,24),DateTime.new(2014,8,31),DateTime.new(2014,9,7)]))
|
97
|
+
expect(index.frequency).to eq('W-SUN')
|
98
|
+
end
|
99
|
+
|
100
|
+
it "creates a DateTimeIndex of (monday) weekly frequency" do
|
101
|
+
index = DateTimeIndex.date_range(:start => '2015-7-6', :periods => 5,
|
102
|
+
:freq => 'W-MON')
|
103
|
+
expect(index).to eq(DateTimeIndex.new([
|
104
|
+
DateTime.new(2015,7,6), DateTime.new(2015,7,13), DateTime.new(2015,7,20),
|
105
|
+
DateTime.new(2015,7,27), DateTime.new(2015,8,3)]))
|
106
|
+
expect(index.frequency).to eq('W-MON')
|
107
|
+
end
|
108
|
+
|
109
|
+
it "creates a DateTimeIndex of month begin frequency" do
|
110
|
+
index = DateTimeIndex.date_range(
|
111
|
+
:start => '2017-4-14', :freq => 'MB', :periods => 5)
|
112
|
+
expect(index).to eq(DateTimeIndex.new([
|
113
|
+
DateTime.new(2017,5,1), DateTime.new(2017,6,1),
|
114
|
+
DateTime.new(2017,7,1), DateTime.new(2017,8,1),DateTime.new(2017,9,1)]))
|
115
|
+
end
|
116
|
+
|
117
|
+
it "creates a DateTimeIndex of month end frequency" do
|
118
|
+
index = DateTimeIndex.date_range(
|
119
|
+
:start => '2014-2-22', freq: 'ME', periods: 6)
|
120
|
+
expect(index).to eq(DateTimeIndex.new([
|
121
|
+
DateTime.new(2014,2,28), DateTime.new(2014,3,31), DateTime.new(2014,4,30),
|
122
|
+
DateTime.new(2014,5,31), DateTime.new(2014,6,30), DateTime.new(2014,7,31)]))
|
123
|
+
end
|
124
|
+
|
125
|
+
it "creates a DateTimeIndex of year begin frequency" do
|
126
|
+
index = DateTimeIndex.date_range(:start => '2014-4-2', periods: 3, freq: 'YB')
|
127
|
+
expect(index).to eq(DateTimeIndex.new([
|
128
|
+
DateTime.new(2015,1,1), DateTime.new(2016,1,1), DateTime.new(2017,1,1)]))
|
129
|
+
end
|
130
|
+
|
131
|
+
it "creates a DateTimeIndex of year end frequency" do
|
132
|
+
index = DateTimeIndex.date_range(start: '2014-9',end: '2018-1',freq: 'YE')
|
133
|
+
|
134
|
+
expect(index).to eq(DateTimeIndex.new([
|
135
|
+
DateTime.new(2014,12,31), DateTime.new(2015,12,31),DateTime.new(2016,12,31),
|
136
|
+
DateTime.new(2017,12,31)]))
|
137
|
+
expect(index.frequency).to eq('YE')
|
138
|
+
end
|
139
|
+
|
140
|
+
it "creates only specfied number of periods taking precendence over end" do
|
141
|
+
index = DateTimeIndex.date_range(start: '2014-5-5', end: '2015-3',
|
142
|
+
periods: 5, freq: 'YB')
|
143
|
+
expect(index).to eq(DateTimeIndex.new([
|
144
|
+
DateTime.new(2015,1,1),DateTime.new(2016,1,1),DateTime.new(2017,1,1),
|
145
|
+
DateTime.new(2018,1,1),DateTime.new(2019,1,1)]))
|
146
|
+
end
|
147
|
+
|
148
|
+
it "does not increment start date if it satisifies the anchor" do
|
149
|
+
index = DateTimeIndex.date_range(:start => '2012-1-1', freq: 'MB', periods: 4)
|
150
|
+
expect(index).to eq(DateTimeIndex.new(
|
151
|
+
[DateTime.new(2012,1,1), DateTime.new(2012,2,1),
|
152
|
+
DateTime.new(2012,3,1), DateTime.new(2012,4,1)]))
|
153
|
+
end
|
154
|
+
|
155
|
+
it "raises error for different start and end timezones" do
|
156
|
+
expect {
|
157
|
+
DateTimeIndex.date_range(
|
158
|
+
:start => DateTime.new(2012,3,4,12,5,4,"+5:30"),
|
159
|
+
:end => DateTime.new(2013,3,4,12,5,4,"+7:30"), freq: 'M')
|
160
|
+
}.to raise_error(ArgumentError)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
context "#frequency" do
|
165
|
+
it "reports the frequency of when a period index is specified" do
|
166
|
+
index = DateTimeIndex.new([
|
167
|
+
DateTime.new(2014,7,1),DateTime.new(2014,7,2),DateTime.new(2014,7,3),
|
168
|
+
DateTime.new(2014,7,4)], freq: :infer)
|
169
|
+
expect(index.frequency).to eq('D')
|
170
|
+
end
|
171
|
+
|
172
|
+
it "reports frequency as nil for non-periodic index" do
|
173
|
+
index = DateTimeIndex.new([
|
174
|
+
DateTime.new(2014,7,1),DateTime.new(2014,7,2),DateTime.new(2014,7,3),
|
175
|
+
DateTime.new(2014,7,10)], freq: :infer)
|
176
|
+
expect(index.frequency).to eq(nil)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context "#[]" do
|
181
|
+
it "accepts complete time as a string" do
|
182
|
+
index = DateTimeIndex.new([
|
183
|
+
DateTime.new(2014,3,3),DateTime.new(2014,3,4),DateTime.new(2014,3,5),DateTime.new(2014,3,6)],
|
184
|
+
freq: :infer)
|
185
|
+
expect(index.frequency).to eq('D')
|
186
|
+
expect(index['2014-3-5']).to eq(2)
|
187
|
+
end
|
188
|
+
|
189
|
+
it "accepts complete time as a DateTime object" do
|
190
|
+
index = DateTimeIndex.new([
|
191
|
+
DateTime.new(2014,3,3),DateTime.new(2014,3,4),DateTime.new(2014,3,5),DateTime.new(2014,3,6)],
|
192
|
+
freq: :infer)
|
193
|
+
expect(index[DateTime.new(2014,3,6)]).to eq(3)
|
194
|
+
end
|
195
|
+
|
196
|
+
it "accepts only year specified as a string" do
|
197
|
+
index = DateTimeIndex.new([
|
198
|
+
DateTime.new(2014,5),DateTime.new(2018,6),DateTime.new(2014,7),DateTime.new(2016,7),
|
199
|
+
DateTime.new(2015,7),DateTime.new(2013,7)])
|
200
|
+
expect(index['2014']).to eq(DateTimeIndex.new([
|
201
|
+
DateTime.new(2014,5),DateTime.new(2014,7)]))
|
202
|
+
end
|
203
|
+
|
204
|
+
it "accepts only year for frequency data" do
|
205
|
+
index = DateTimeIndex.date_range(:start => DateTime.new(2012,3,2),
|
206
|
+
periods: 1000, freq: '5D')
|
207
|
+
expect(index['2012']).to eq(DateTimeIndex.date_range(
|
208
|
+
:start => DateTime.new(2012,3,2), :end => DateTime.new(2012,12,27), freq: '5D'))
|
209
|
+
end
|
210
|
+
|
211
|
+
it "accepts year and month specified as a string" do
|
212
|
+
index = DateTimeIndex.new([
|
213
|
+
DateTime.new(2014,5,3),DateTime.new(2014,5,4),DateTime.new(2014,5,5),
|
214
|
+
DateTime.new(2014,6,3),DateTime.new(2014,7,4),DateTime.new(2014,6,5),
|
215
|
+
DateTime.new(2014,7,3),DateTime.new(2014,7,4),DateTime.new(2014,7,5)])
|
216
|
+
expect(index['2014-6']).to eq(DateTimeIndex.new([
|
217
|
+
DateTime.new(2014,6,3),DateTime.new(2014,6,5)]))
|
218
|
+
end
|
219
|
+
|
220
|
+
it "accepts year and month for frequency data" do
|
221
|
+
index = DateTimeIndex.date_range(start: '2014-1-1', periods: 100, freq: 'MB')
|
222
|
+
expect(index['2015-3']).to eq(14)
|
223
|
+
end
|
224
|
+
|
225
|
+
it "accepts year, month and date specified as a string" do
|
226
|
+
index = DateTimeIndex.new([
|
227
|
+
DateTime.new(2012,2,28,0,0,1),DateTime.new(2012,2,25,0,0,1),
|
228
|
+
DateTime.new(2012,2,29,0,1,1),DateTime.new(2012,2,29,0,1,3),
|
229
|
+
DateTime.new(2012,2,29,0,1,5)])
|
230
|
+
expect(index['2012-2-29']).to eq(DateTimeIndex.new([
|
231
|
+
DateTime.new(2012,2,29,0,1,1),DateTime.new(2012,2,29,0,1,3),
|
232
|
+
DateTime.new(2012,2,29,0,1,5)]))
|
233
|
+
end
|
234
|
+
|
235
|
+
it "accepts year, month, date for frequency data" do
|
236
|
+
index = DateTimeIndex.date_range(:start => DateTime.new(2012,2,29),
|
237
|
+
periods: 1000, freq: 'M')
|
238
|
+
expect(index['2012-2-29']).to eq(DateTimeIndex.date_range(
|
239
|
+
:start => DateTime.new(2012,2,29),
|
240
|
+
:end => DateTime.new(2012,2,29,16,39,00), freq: 'M'))
|
241
|
+
end
|
242
|
+
|
243
|
+
it "accepts year, month, date and specific time as a string" do
|
244
|
+
index = DateTimeIndex.date_range(
|
245
|
+
:start => DateTime.new(2015,5,3),:end => DateTime.new(2015,5,5), freq: 'M')
|
246
|
+
expect(index['2015-5-3 00:04:00']).to eq(4)
|
247
|
+
end
|
248
|
+
|
249
|
+
it "accepts with seconds accuracy" do
|
250
|
+
index = DateTimeIndex.date_range(
|
251
|
+
:start => DateTime.new(2012,3,2,21,4,2), :end => DateTime.new(2012,3,2,21,5,2),
|
252
|
+
:freq => 'S')
|
253
|
+
expect(index['2012-3-2 21:04:04']).to eq(2)
|
254
|
+
end
|
255
|
+
|
256
|
+
it "supports completely specified time ranges" do
|
257
|
+
index = DateTimeIndex.date_range(start: '2011-4-1', periods: 50, freq: 'D')
|
258
|
+
expect(index['2011-4-5'..'2011-5-3']).to eq(
|
259
|
+
DateTimeIndex.date_range(:start => '2011-4-5', :end => '2011-5-3', freq: 'D'))
|
260
|
+
end
|
261
|
+
|
262
|
+
it "supports time ranges with only year specified" do
|
263
|
+
index = DateTimeIndex.date_range(start: '2011-5-5', periods: 50, freq: 'MONTH')
|
264
|
+
expect(index['2011'..'2012']).to eq(
|
265
|
+
DateTimeIndex.date_range(:start => '2011-5-5', :end => '2012-12-5',
|
266
|
+
:freq => 'MONTH'))
|
267
|
+
end
|
268
|
+
|
269
|
+
it "supports time ranges with year and month specified" do
|
270
|
+
index = DateTimeIndex.date_range(:start => '2016-4-3', periods: 100, freq: 'D')
|
271
|
+
expect(index['2016-4'..'2016-5']).to eq(
|
272
|
+
DateTimeIndex.date_range(:start => '2016-4-3', periods: 59, freq: 'D'))
|
273
|
+
end
|
274
|
+
|
275
|
+
it "supports time range with year, month and date specified" do
|
276
|
+
index = DateTimeIndex.date_range(:start => '2015-7-4', :end => '2015-12-3')
|
277
|
+
expect(index['2015-7-4'..'2015-9-3']).to eq(
|
278
|
+
DateTimeIndex.date_range(:start => '2015-7-4', :end => '2015-9-3'))
|
279
|
+
end
|
280
|
+
|
281
|
+
it "supports time range with year, month, date and hours specified" do
|
282
|
+
index = DateTimeIndex.date_range(:start => '2015-4-2', periods: 120, freq: 'H')
|
283
|
+
expect(index['2015-4-3 00:00'..'2015-4-3 12:00']).to eq(
|
284
|
+
DateTimeIndex.date_range(:start => '2015-4-3', freq: 'H', periods: 13))
|
285
|
+
end
|
286
|
+
|
287
|
+
it "returns slice upto last element if overshoot in partial date" do
|
288
|
+
index = DateTimeIndex.date_range(:start => '2012-4-2', periods: 100, freq: 'M')
|
289
|
+
expect(index['2012-4-2']).to eq(DateTimeIndex.date_range(
|
290
|
+
:start => '2012-4-2', periods: 100, freq: 'M'))
|
291
|
+
end
|
292
|
+
|
293
|
+
it "returns slice upto last element if overshoot in range" do
|
294
|
+
index = DateTimeIndex.date_range(:start => '2012-2-2', :periods => 50,
|
295
|
+
freq: 'M')
|
296
|
+
expect(index['2012'..'2013']).to eq(DateTimeIndex.date_range(
|
297
|
+
:start => '2012-2-2',:periods => 50, freq: 'M'))
|
298
|
+
end
|
299
|
+
|
300
|
+
it "returns a slice when given a numeric range" do
|
301
|
+
index = DateTimeIndex.date_range(
|
302
|
+
:start => DateTime.new(2012,3,1), :periods => 50)
|
303
|
+
expect(index[4..10]).to eq(
|
304
|
+
DateTimeIndex.date_range(:start => DateTime.new(2012,3,5), :periods => 7))
|
305
|
+
end
|
306
|
+
|
307
|
+
it "raises error if key out of bounds" do
|
308
|
+
index = DateTimeIndex.date_range(:start => '2012-1', :periods => 5)
|
309
|
+
expect{
|
310
|
+
index['2011']
|
311
|
+
}.to raise_error(ArgumentError)
|
312
|
+
end
|
313
|
+
|
314
|
+
it "raises error if date not present (exact date)" do
|
315
|
+
expect {
|
316
|
+
index = DateTimeIndex.date_range(:start => '2011', :periods => 5, :freq => 'MONTH')
|
317
|
+
index[DateTime.new(2013,1,4)]
|
318
|
+
}.to raise_error(ArgumentError)
|
319
|
+
end
|
320
|
+
|
321
|
+
it "raises error if date not present (string)" do
|
322
|
+
expect {
|
323
|
+
index = DateTimeIndex.date_range(:start => '2012-2-3', :periods => 10)
|
324
|
+
index['2012-2-4 12']
|
325
|
+
}.to raise_error(ArgumentError)
|
326
|
+
end
|
327
|
+
|
328
|
+
it "raises error for out of bounds range" do
|
329
|
+
expect {
|
330
|
+
index = DateTimeIndex.date_range(:start => '2012', :periods => 100)
|
331
|
+
index['2001'..'2005']
|
332
|
+
}.to raise_error(ArgumentError)
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
context "#slice" do
|
337
|
+
it "supports both DateTime objects" do
|
338
|
+
index = DateTimeIndex.date_range(:start => '2012', :periods => 50,
|
339
|
+
:freq => 'M')
|
340
|
+
expect(index.slice(DateTime.new(2012,1,1), DateTime.new(2012,1,1,0,6))).to eq(
|
341
|
+
DateTimeIndex.date_range(:start => '2012', :periods => 7, :freq => 'M'))
|
342
|
+
end
|
343
|
+
|
344
|
+
it "supports single DateTime object on the left" do
|
345
|
+
index = DateTimeIndex.date_range(:start => '2012', :periods => 40, :freq => 'M')
|
346
|
+
expect(index.slice('2012', DateTime.new(2012,1,1,0,20))).to eq(
|
347
|
+
DateTimeIndex.date_range(:start => '2012', :periods => 21, :freq => 'M'))
|
348
|
+
end
|
349
|
+
|
350
|
+
it "supports single DateTime object on the right" do
|
351
|
+
index = DateTimeIndex.date_range(:start => '2012', :periods => 40, :freq => 'MONTH')
|
352
|
+
expect(index.slice(DateTime.new(2012), '2013')).to eq(
|
353
|
+
DateTimeIndex.date_range(:start => '2012', :periods => 24, :freq => 'MONTH'))
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
context "#size" do
|
358
|
+
it "returns the size of the DateTimeIndex" do
|
359
|
+
index = DateTimeIndex.date_range start: DateTime.new(2014,5,3), periods: 100
|
360
|
+
expect(index.size).to eq(100)
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
context "#to_a" do
|
365
|
+
it "returns an Array of ruby Time objects" do
|
366
|
+
index = DateTimeIndex.date_range(
|
367
|
+
start: DateTime.new(2012,2,1), :end => DateTime.new(2012,2,4))
|
368
|
+
expect(index.to_a).to eq([
|
369
|
+
DateTime.new(2012,2,1),DateTime.new(2012,2,2),DateTime.new(2012,2,3),DateTime.new(2012,2,4)])
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
context "#shift" do
|
374
|
+
it "shifts all dates to the future by specified value (with offset)" do
|
375
|
+
index = DateTimeIndex.date_range(
|
376
|
+
:start => '2012-1-1', :freq => 'MB', :periods => 10)
|
377
|
+
expect(index.shift(3)).to eq(DateTimeIndex.date_range(
|
378
|
+
:start => '2012-4-1', :freq => 'MB', :periods => 10))
|
379
|
+
end
|
380
|
+
|
381
|
+
it "shifts all dates by the given offset" do
|
382
|
+
offset = Daru::Offsets::Minute.new
|
383
|
+
index = DateTimeIndex.date_range(
|
384
|
+
:start => '2012-3-1', :freq => 'D', :periods => 10)
|
385
|
+
expect(index.shift(offset)).to eq(
|
386
|
+
DateTimeIndex.date_range(
|
387
|
+
:start => '2012-3-1 00:01', :freq => 'D', :periods => 10))
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
context "#lag" do
|
392
|
+
it "shifts all dates to the past by specified value (with offset)" do
|
393
|
+
index = DateTimeIndex.date_range(
|
394
|
+
:start => '2012-5-5', :freq => 'D', :periods => 5)
|
395
|
+
expect(index.lag(2)).to eq(DateTimeIndex.date_range(
|
396
|
+
:start => '2012-5-3', :freq => 'D', :periods => 5))
|
397
|
+
end
|
398
|
+
|
399
|
+
it "lags all dates by the given offset" do
|
400
|
+
offset = Daru::Offsets::Month.new
|
401
|
+
index = DateTimeIndex.date_range(
|
402
|
+
:start => '2012-4-5', :freq => 'MONTH', :periods => 10)
|
403
|
+
expect(index.lag(offset)).to eq(
|
404
|
+
DateTimeIndex.date_range(:start => '2012-3-5', :periods => 10, freq: offset))
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
[:year, :month, :day, :hour, :min, :sec].each do |meth|
|
409
|
+
dates = [
|
410
|
+
DateTime.new(2012,5,1,12,5,4), DateTime.new(2015,5,1,13,5),
|
411
|
+
DateTime.new(2012,8,1,12,5,3), DateTime.new(2015,1,4,16,5,44)
|
412
|
+
]
|
413
|
+
curated = dates.inject([]) do |arr, e|
|
414
|
+
arr << e.send(meth)
|
415
|
+
arr
|
416
|
+
end
|
417
|
+
|
418
|
+
context "##{meth}" do
|
419
|
+
it "returns #{meth} of all dates as an Array" do
|
420
|
+
index = DateTimeIndex.new(dates)
|
421
|
+
expect(index.send(meth)).to eq(curated)
|
422
|
+
end
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
context "#include?" do
|
427
|
+
it "returns true if an index is present" do
|
428
|
+
index = DateTimeIndex.date_range(:start => '2012-1-4', :periods => 100, :freq => 'D')
|
429
|
+
expect(index.include?(DateTime.new(2012,1,6))).to eq(true)
|
430
|
+
expect(index.include?(DateTime.new(2011,4,2))).to eq(false)
|
431
|
+
end
|
432
|
+
end
|
433
|
+
end
|