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.
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