daru 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.build.sh +6 -6
  3. data/.gitignore +2 -0
  4. data/CONTRIBUTING.md +7 -3
  5. data/History.md +36 -0
  6. data/README.md +21 -13
  7. data/Rakefile +16 -1
  8. data/benchmarks/TradeoffData.csv +65 -0
  9. data/benchmarks/dataframe_creation.rb +39 -0
  10. data/benchmarks/group_by.rb +32 -0
  11. data/benchmarks/row_access.rb +41 -0
  12. data/benchmarks/row_assign.rb +36 -0
  13. data/benchmarks/sorting.rb +44 -0
  14. data/benchmarks/vector_access.rb +31 -0
  15. data/benchmarks/vector_assign.rb +42 -0
  16. data/benchmarks/where_clause.rb +48 -0
  17. data/benchmarks/where_vs_filter.rb +28 -0
  18. data/daru.gemspec +29 -5
  19. data/lib/daru.rb +30 -1
  20. data/lib/daru/accessors/array_wrapper.rb +2 -2
  21. data/lib/daru/accessors/nmatrix_wrapper.rb +6 -6
  22. data/lib/daru/core/group_by.rb +112 -31
  23. data/lib/daru/core/merge.rb +170 -0
  24. data/lib/daru/core/query.rb +95 -0
  25. data/lib/daru/dataframe.rb +335 -223
  26. data/lib/daru/date_time/index.rb +550 -0
  27. data/lib/daru/date_time/offsets.rb +397 -0
  28. data/lib/daru/index.rb +266 -54
  29. data/lib/daru/io/io.rb +1 -2
  30. data/lib/daru/maths/arithmetic/dataframe.rb +2 -2
  31. data/lib/daru/maths/arithmetic/vector.rb +2 -2
  32. data/lib/daru/maths/statistics/dataframe.rb +58 -8
  33. data/lib/daru/maths/statistics/vector.rb +229 -0
  34. data/lib/daru/vector.rb +230 -80
  35. data/lib/daru/version.rb +1 -1
  36. data/spec/core/group_by_spec.rb +16 -16
  37. data/spec/core/merge_spec.rb +52 -0
  38. data/spec/core/query_spec.rb +171 -0
  39. data/spec/dataframe_spec.rb +278 -280
  40. data/spec/date_time/data_spec.rb +199 -0
  41. data/spec/date_time/index_spec.rb +433 -0
  42. data/spec/date_time/offsets_spec.rb +371 -0
  43. data/spec/fixtures/stock_data.csv +500 -0
  44. data/spec/index_spec.rb +317 -11
  45. data/spec/io/io_spec.rb +18 -17
  46. data/spec/math/arithmetic/dataframe_spec.rb +3 -3
  47. data/spec/math/statistics/dataframe_spec.rb +39 -1
  48. data/spec/math/statistics/vector_spec.rb +163 -1
  49. data/spec/monkeys_spec.rb +4 -0
  50. data/spec/spec_helper.rb +3 -0
  51. data/spec/vector_spec.rb +125 -60
  52. metadata +71 -14
  53. data/lib/daru/accessors/dataframe_by_vector.rb +0 -17
  54. data/lib/daru/multi_index.rb +0 -216
  55. 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