time-series 0.0.0
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/.gitignore +29 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +5 -0
- data/lib/time_series.rb +2 -0
- data/lib/time_series/data_point.rb +18 -0
- data/lib/time_series/time_series.rb +59 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/time_series/data_point_spec.rb +35 -0
- data/spec/time_series/time_series_spec.rb +90 -0
- data/time_series.gemspec +20 -0
- metadata +72 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 578adee8d18e4e1b562993e5e5f23e3559428b62
|
4
|
+
data.tar.gz: 5df89148bb67007fccd86f0d973cfe10cadb1711
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4a5aaca0c7de2c0455c8da001f764280198375e2da18676763450593acb878ae2f0185db6d43193b7f74c01cadb164aec83956db4649f1679ebe0fe6d73b57d6
|
7
|
+
data.tar.gz: e8962857d566436ec59aca2c38bbfef3391a0d3cb140f8cea4d0ea8f89eafdcb1ecc1fa83fae55b9fad868b3ad1e9b2d54c47fbec26b038daf74fec94cbb56cd
|
data/.gitignore
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/test/tmp/
|
9
|
+
/test/version_tmp/
|
10
|
+
/tmp/
|
11
|
+
|
12
|
+
## Documentation cache and generated files:
|
13
|
+
/.yardoc/
|
14
|
+
/_yardoc/
|
15
|
+
/doc/
|
16
|
+
/rdoc/
|
17
|
+
|
18
|
+
## Environment normalisation:
|
19
|
+
/.bundle/
|
20
|
+
/lib/bundler/man/
|
21
|
+
|
22
|
+
# for a library or gem, you might want to ignore these files since the code is
|
23
|
+
# intended to run in multiple environments; otherwise, check them in:
|
24
|
+
Gemfile.lock
|
25
|
+
.ruby-version
|
26
|
+
.ruby-gemset
|
27
|
+
|
28
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
29
|
+
.rvmrc
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Eric L. Yan
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,5 @@
|
|
1
|
+
# time-series
|
2
|
+
|
3
|
+
This library provides a basic data structure that can represent time series data. It is originally designed for the representation of stock market data, but it is suitable (and extensible) for other purposes.
|
4
|
+
|
5
|
+
It keeps data points in a Hash and requires Ruby version >= 1.9.2, as it turns out in Ruby 1.9, a Hash is also a [doubly-circular linked list](http://www.igvita.com/2009/02/04/ruby-19-internals-ordered-hash/).
|
data/lib/time_series.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
class DataPoint
|
2
|
+
include Comparable
|
3
|
+
|
4
|
+
attr_reader :timestamp, :data
|
5
|
+
|
6
|
+
def initialize(timestamp, data)
|
7
|
+
timestamp = timestamp.to_time unless timestamp.kind_of? Time
|
8
|
+
@timestamp, @data = timestamp, data
|
9
|
+
end
|
10
|
+
|
11
|
+
def <=>(another)
|
12
|
+
result = @timestamp <=> another.timestamp
|
13
|
+
end
|
14
|
+
|
15
|
+
def ==(another)
|
16
|
+
@timestamp == another.timestamp and @data == another.data
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
class TimeSeries
|
2
|
+
include Enumerable
|
3
|
+
|
4
|
+
attr_reader :data_points
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
case args.length
|
8
|
+
when 1 then data_points = args[0]
|
9
|
+
when 2 then data_points = args[0].zip(args[1]).collect { |dp| DataPoint.new(dp[0], dp[1]) }
|
10
|
+
else data_points = []
|
11
|
+
end
|
12
|
+
|
13
|
+
@data_points = {}
|
14
|
+
self << data_points
|
15
|
+
end
|
16
|
+
|
17
|
+
def <<(*data_points)
|
18
|
+
data_points.flatten.each do |data_point|
|
19
|
+
@data_points[data_point.timestamp] = data_point
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def at(*timestamps)
|
24
|
+
results = @data_points.values_at(*timestamps)
|
25
|
+
results = results[0] if results.length == 1
|
26
|
+
|
27
|
+
return results
|
28
|
+
end
|
29
|
+
|
30
|
+
def slice(timeframe)
|
31
|
+
from, to = timeframe[:from], timeframe[:to]
|
32
|
+
|
33
|
+
data_points = @data_points.select do |t, data|
|
34
|
+
case [!from.nil?, !to.nil?]
|
35
|
+
when [true, true] then t >= from and t <= to
|
36
|
+
when [true, false] then t >= from
|
37
|
+
when [false, true] then t <= to
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
return self.class.new data_points.keys, data_points.values
|
42
|
+
end
|
43
|
+
|
44
|
+
def each(&block)
|
45
|
+
Hash[@data_points.sort].values.each(&block)
|
46
|
+
end
|
47
|
+
|
48
|
+
def last(n = 1)
|
49
|
+
Hash[@data_points.sort.last(n)].values
|
50
|
+
end
|
51
|
+
|
52
|
+
def length
|
53
|
+
@data_points.length
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_a
|
57
|
+
Hash[@data_points.sort].values
|
58
|
+
end
|
59
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'time_series'
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
describe DataPoint do
|
5
|
+
let(:data) { { a: 1, b:2, c:3 } }
|
6
|
+
|
7
|
+
describe "#new" do
|
8
|
+
it "takes a Time object" do
|
9
|
+
data_point = DataPoint.new(Time.new, data)
|
10
|
+
data_point.timestamp.should be_a_kind_of Time
|
11
|
+
data_point.data.should eql data
|
12
|
+
end
|
13
|
+
|
14
|
+
it "takes a Date object" do
|
15
|
+
data_point = DataPoint.new(Date.today, data)
|
16
|
+
data_point.timestamp.should be_a_kind_of Time
|
17
|
+
data_point.data.should eql data
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "is comparable" do
|
22
|
+
it "Two DataPoints are equal given the same timestamp and data" do
|
23
|
+
one = DataPoint.new(Time.at(1000000000), "The first UNIX billennium".gsub('UNIX', 'Unix'))
|
24
|
+
another = DataPoint.new(Time.new(2001, 9, 9, 9, 46, 40, '+08:00'), "The first Unix billennium")
|
25
|
+
one.should eq another
|
26
|
+
end
|
27
|
+
|
28
|
+
it "DataPoints are compared by its timestamp" do
|
29
|
+
first = DataPoint.new(Time.at(1000000000), "The first Unix billennium")
|
30
|
+
second = DataPoint.new(Time.at(2000000000), "The second Unix billennium")
|
31
|
+
first.should < second
|
32
|
+
second.should > first
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TimeSeries do
|
4
|
+
let(:data_points) do
|
5
|
+
data_points = {
|
6
|
+
Time.at(2000000000) => "The second Unix billennium",
|
7
|
+
Time.at(1234567890) => "Let's go party",
|
8
|
+
Time.at(1000000000) => "The first Unix billennium",
|
9
|
+
Time.at(2147485547) => "Year 2038 problem"
|
10
|
+
}
|
11
|
+
data_points.keys.zip(data_points.values).collect { |dp| DataPoint.new(dp[0], dp[1]) }
|
12
|
+
end
|
13
|
+
let(:time_series) { TimeSeries.new(data_points) }
|
14
|
+
|
15
|
+
describe "#new" do
|
16
|
+
it "takes a array of DataPoints" do
|
17
|
+
time_series.length.should eql 4
|
18
|
+
end
|
19
|
+
|
20
|
+
it "takes a array of timestamps and a array of data" do
|
21
|
+
data_points = time_series.data_points
|
22
|
+
time_series = TimeSeries.new(data_points.keys, data_points.values)
|
23
|
+
time_series.length.should eql 4
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#<<" do
|
28
|
+
it "adds a new data point" do
|
29
|
+
time_series << DataPoint.new(Time.now, "Knock knock")
|
30
|
+
time_series.length.should eql 5
|
31
|
+
end
|
32
|
+
|
33
|
+
it "update the existing data point" do
|
34
|
+
time_series << DataPoint.new(Time.at(1234567890), 'PARTY TIME!')
|
35
|
+
time_series.length.should eql 4
|
36
|
+
time_series.at(Time.at(1234567890)).data.should eql 'PARTY TIME!'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#at" do
|
41
|
+
it "returns data associated with the given timestamp" do
|
42
|
+
time_series.at(Time.at(1000000000)).data.should eql "The first Unix billennium"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "returns data in array if two or more timestamps are given" do
|
46
|
+
time_series.at(Time.at(1000000000), Time.at(2000000000))
|
47
|
+
.collect { |data_point| data_point.data }.should
|
48
|
+
eql(["The first Unix billennium", "The second Unix billennium"])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#slice" do
|
53
|
+
it "returns all data points in the given timeframe" do
|
54
|
+
ts = time_series.slice from: Time.at(1000000000), to: Time.at(2000000000)
|
55
|
+
ts.length.should eql 3
|
56
|
+
ts.at(Time.at 2147485547).should eql nil
|
57
|
+
end
|
58
|
+
|
59
|
+
it "returns all data points after the from time" do
|
60
|
+
ts = time_series.slice from: Time.at(2000000000)
|
61
|
+
ts.length.should eql 2
|
62
|
+
ts.at(Time.at(1000000000), Time.at(1234567890)).should eql [nil, nil]
|
63
|
+
end
|
64
|
+
|
65
|
+
it "returns all data points before the to time" do
|
66
|
+
ts = time_series.slice to: Time.at(1234567890)
|
67
|
+
ts.length.should eql 2
|
68
|
+
ts.at(Time.at(2000000000), Time.at(2147485547)).should eql [nil, nil]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "is enumerable" do
|
73
|
+
it "returns the first data point(s) according to its timestamp" do
|
74
|
+
time_series.first(2).collect { |data_point| data_point.data }.should
|
75
|
+
eql ["The first Unix billennium", "Let's go party"]
|
76
|
+
end
|
77
|
+
|
78
|
+
it "returns the last data point(s) according to its timestamp" do
|
79
|
+
time_series.last(2).collect { |data_point| data_point.data }.should
|
80
|
+
eql ["The second Unix billennium", "Year 2038 problem"]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "#to_a" do
|
85
|
+
it "returns a array of sorted DataPoints" do
|
86
|
+
time_series.to_a.should be_a_kind_of Array
|
87
|
+
time_series.to_a.should eql data_points.sort
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/time_series.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Gem::Specification.new do |spec|
|
2
|
+
spec.name = 'time-series'
|
3
|
+
spec.version = '0.0.0'
|
4
|
+
spec.author = 'Eric Yan'
|
5
|
+
spec.email = 'long@ericyan.me'
|
6
|
+
spec.homepage = 'https://github.com/ericyan/time-series'
|
7
|
+
spec.summary = 'A Ruby library for dealing with time series data'
|
8
|
+
spec.description = 'This library provides a basic data structure that can represent time series data. Requires Ruby version >= 1.9.2.'
|
9
|
+
spec.license = 'MIT'
|
10
|
+
|
11
|
+
# Starting 1.9.2 hash insert order will be preserved
|
12
|
+
spec.required_ruby_version = '>= 1.9.2'
|
13
|
+
|
14
|
+
spec.add_development_dependency 'rspec'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.test_files = spec.files.grep(%r{^spec/})
|
18
|
+
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: time-series
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Eric Yan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-02-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: This library provides a basic data structure that can represent time
|
28
|
+
series data. Requires Ruby version >= 1.9.2.
|
29
|
+
email: long@ericyan.me
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- .gitignore
|
35
|
+
- Gemfile
|
36
|
+
- LICENSE
|
37
|
+
- README.md
|
38
|
+
- lib/time_series.rb
|
39
|
+
- lib/time_series/data_point.rb
|
40
|
+
- lib/time_series/time_series.rb
|
41
|
+
- spec/spec_helper.rb
|
42
|
+
- spec/time_series/data_point_spec.rb
|
43
|
+
- spec/time_series/time_series_spec.rb
|
44
|
+
- time_series.gemspec
|
45
|
+
homepage: https://github.com/ericyan/time-series
|
46
|
+
licenses:
|
47
|
+
- MIT
|
48
|
+
metadata: {}
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 1.9.2
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
requirements: []
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 2.0.3
|
66
|
+
signing_key:
|
67
|
+
specification_version: 4
|
68
|
+
summary: A Ruby library for dealing with time series data
|
69
|
+
test_files:
|
70
|
+
- spec/spec_helper.rb
|
71
|
+
- spec/time_series/data_point_spec.rb
|
72
|
+
- spec/time_series/time_series_spec.rb
|