timeseries (empty) → 0.1.0
raw patch · 14 files changed
+596/−0 lines, 14 filesdep +Cabaldep +QuickCheckdep +basesetup-changed
Dependencies added: Cabal, QuickCheck, base, bytestring, bytestring-time, cassava, hspec, text, time, vector
Files
- CHANGES.md +9/−0
- LICENSE +27/−0
- README.md +36/−0
- Setup.hs +2/−0
- benchmark/Benchmarks.hs +28/−0
- src/Data/TimeSeries.hs +9/−0
- src/Data/TimeSeries/CSVReader.hs +37/−0
- src/Data/TimeSeries/Series.hs +107/−0
- test-src/Data/TimeSeries/CSVSpec.hs +17/−0
- test-src/Data/TimeSeries/SeriesSpec.hs +49/−0
- test-src/Spec.hs +9/−0
- testdata/co2.csv +193/−0
- testdata/small.csv +5/−0
- timeseries.cabal +68/−0
+ CHANGES.md view
@@ -0,0 +1,9 @@+# Version 0.1 (2016-12-13)++ * Implemented functions+ * slice+ * max+ * min+ * Implemented CSV reader+ * Implemented size function+ * Implemented valueAt function
+ LICENSE view
@@ -0,0 +1,27 @@+Copyright (c) 2014 Krzysztof Langner+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+
+ README.md view
@@ -0,0 +1,36 @@+[](https://travis-ci.org/klangner/time-series-lib)+[](https://hackage.haskell.org/package/timeseries)++# Welcome to Haskell Time Series library++Implemented functionality:+ * Base operations on time series (get value, slice, max etc.)+ * Reading from CSV file++++## Installation++```sh+stack setup+stack build+stack test+```+++# Join in!++We are happy to receive bug reports, fixes, documentation enhancements,+and other improvements.++Please report bugs via the+[github issue tracker](http://github.com/klangner/time-series-lib/issues).++Master [git repository](http://github.com/klangner/time-series-lib):++* `git clone https://github.com/klangner/time-series-lib.git`+++# Redistributing++time-series-lib source code is distributed under the BSD3 License.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ benchmark/Benchmarks.hs view
@@ -0,0 +1,28 @@++import Criterion.Main+import Data.Time (UTCTime)+import Data.Time.Clock.POSIX (posixSecondsToUTCTime)+import qualified Data.TimeSeries as TS+++seriesSize :: Integer+seriesSize = 10^6++index :: Integer -> UTCTime+index n = posixSecondsToUTCTime (fromIntegral n)++lastIndex :: UTCTime+lastIndex = index (seriesSize - 1)++bigSeries :: TS.Series+bigSeries = TS.tsSeries [1..seriesSize] [1..]+++main :: IO ()+main = defaultMain+ [ bgroup "Big series"+ [ bench "size" $ nf TS.size bigSeries+ , bench "valueAt" $ nf (\xs -> TS.valueAt xs lastIndex) bigSeries+ , bench "slice" $ nf (\xs -> TS.valueAt (TS.slice xs (index 2) lastIndex) (index 1)) bigSeries+ ]+ ]
+ src/Data/TimeSeries.hs view
@@ -0,0 +1,9 @@+-- | TimeSeries library+module Data.TimeSeries+ ( module Data.TimeSeries.Series+ , module Data.TimeSeries.CSVReader+ ) where+++import Data.TimeSeries.Series+import Data.TimeSeries.CSVReader
+ src/Data/TimeSeries/CSVReader.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE OverloadedStrings #-}++module Data.TimeSeries.CSVReader+ ( load+ )where+++import qualified Data.ByteString.Lazy as BS+import qualified Data.Text as T+import Data.Csv+import qualified Data.Vector as V+import Data.Time (UTCTime)++import Data.TimeSeries.Series ( Series+ , emptySeries+ , series+ )+++-- | Load data from CSV file and create Time Series from it+-- As a first argument provide function to convert date from ByteString to UTCTime+load :: (T.Text -> UTCTime) -> FilePath -> IO Series+load ft filePath = do+ csvData <- BS.readFile filePath+ case decode HasHeader csvData of+ Left err -> do+ _ <- putStrLn err+ return emptySeries++ Right vs -> do+ let vs' = V.map (parseLine ft) vs+ return $ series (V.toList vs')+++parseLine :: (T.Text -> UTCTime) -> (T.Text, Double) -> (UTCTime, Double)+parseLine ft (date, value) = (ft date, value)
+ src/Data/TimeSeries/Series.hs view
@@ -0,0 +1,107 @@+{-# OPTIONS_GHC -funbox-strict-fields #-}+{-|+Module: Data.TimeSeries.Series+Copyright: (c) 2016 Krzysztof Langner+License: BSD3+Stability: experimental+Portability: portable+Definition and basic operation on Series.+-}++module Data.TimeSeries.Series+ ( DataPoint+ , Series+ , Value+ , emptySeries+ , max+ , min+ , series+ , size+ , slice+ , tsSeries+ , valueAt+ ) where++import Prelude hiding (max, min)+import Data.Time (UTCTime)+import Data.Time.Clock.POSIX (posixSecondsToUTCTime)+++type Value = Double+data DataPoint = DP !UTCTime !Value+ deriving (Show, Eq)++data Series = Series [DataPoint]+ deriving (Show, Eq)+++-- | Create empty series+emptySeries :: Series+emptySeries = Series []+++-- | Create empty series+series :: [(UTCTime, Double)] -> Series+series xs = Series $ map (\(x, y) -> DP x y) xs+++-- | Create time series from timestamps and values+--+-- >seriesFromSeconds [1, 2, 3] [41.3, 52.22, 3.0] == Series [DP 1970-01-01 00:00:01 UTC 2.3,DP 1970-01-01 00:00:02 UTC 4.5]+--+tsSeries :: [Integer] -> [Value] -> Series+tsSeries ts vs = Series (zipWith DP idx vs)+ where idx = map (posixSecondsToUTCTime . fromIntegral) ts+++-- | Get series size.+-- Complexity O(n)+--+-- >size (Series [DP 1 41.3, DP 2 52.22, DP 3 3.0]) == 3+--+size :: Series -> Int+size (Series xs) = length xs+++-- | Return data point value at given index+-- Complexity O(n)+--+-- >valueAt (Series [DP 1 41.3, DP 2 52.22, DP 3 3.0]) 2 == Just 52.22+-- >valueAt (Series [DP 1 41.3, DP 2 52.22, DP 3 3.0]) 5 == Nothing+--+valueAt :: Series -> UTCTime -> Maybe Value+valueAt (Series xs) ts = safeHead [y | DP x y <- xs, x == ts]+ where safeHead [] = Nothing+ safeHead (a:_) = Just a+++-- | Return series subset+-- Complexity O(n)+--+-- >slice (Series [DP 1 41.3, DP 2 52.22, DP 3 3.0]) 2 3 == Series [DP 2 52.22, DP 3 3.0]+-- >slice (Series [DP 1 41.3, DP 2 52.22, DP 3 3.0]) 5 23 == Series []+--+slice :: Series -> UTCTime -> UTCTime -> Series+slice (Series xs) start end = Series [DP x y | DP x y <- xs, x >= start && x <= end]+++-- | Return maximum value in the series+-- Complexity O(n)+--+-- >max (Series [DP 1 41.3, DP 2 52.22, DP 3 3.0]) == 52.22+-- >max (Series []) == 0+--+max :: Series -> Value+max (Series xs) = foldl (\d (DP _ y) -> max' d y) 0.0 xs+ where max' a b = if a > b then a else b++-- | Return maximum value in the series+-- Complexity O(n)+--+-- >min (Series [DP 1 41.3, DP 2 52.22, DP 3 3.0]) == 3.0+-- >min (Series []) == 0+--+min :: Series -> Value+min (Series xs) = foldl (\d (DP _ y) -> min' d y) maxValue xs+ where min' a b = if a < b then a else b+ maxValue = fromIntegral (maxBound :: Int)
+ test-src/Data/TimeSeries/CSVSpec.hs view
@@ -0,0 +1,17 @@+module Data.TimeSeries.CSVSpec (spec) where++import Test.Hspec+import Data.ByteString.Time (parseISODateTime)++import qualified Data.TimeSeries as TS+import qualified Data.TimeSeries.CSVReader as CSV+++spec :: Spec+spec = do++ describe "Reader" $ do++ it "co2 test data" $ do+ xs <- CSV.load parseISODateTime "testdata/co2.csv"+ TS.size xs `shouldBe` 192
+ test-src/Data/TimeSeries/SeriesSpec.hs view
@@ -0,0 +1,49 @@+module Data.TimeSeries.SeriesSpec (spec) where++import Test.Hspec+import Data.Time.Clock.POSIX (posixSecondsToUTCTime)++import qualified Data.TimeSeries as TS+++spec :: Spec+spec = do++ describe "Basic operations" $ do++ it "return series size" $ do+ let idx = [1, 2, 3]+ let values = [1.0, 2.0, 3.0]+ TS.size (TS.tsSeries idx values) `shouldBe` 3++ it "return data point value at given index" $ do+ let idx = [10, 20, 30]+ let values = [10.0, 12.0, 32.4]+ let pos = posixSecondsToUTCTime $ fromIntegral 20+ TS.valueAt (TS.tsSeries idx values) pos `shouldBe` Just 12.0++ it "return Nothing value if wrong index" $ do+ let idx = [10, 20, 30]+ let values = [10.0, 12.0, 32.4]+ let pos = posixSecondsToUTCTime $ fromIntegral 1234+ TS.valueAt (TS.tsSeries idx values) pos `shouldBe` Nothing++ it "return subset" $ do+ let xs = TS.tsSeries [1..5] [10.0, 1.2, 32.4, 0.65, 11.0]+ let start = posixSecondsToUTCTime $ fromIntegral 2+ let end = posixSecondsToUTCTime $ fromIntegral 3+ TS.size (TS.slice xs start end) `shouldBe` 2++ it "return empty subset" $ do+ let xs = TS.tsSeries [1..5] [10.0, 1.2, 32.4, 0.65, 11.0]+ let start = posixSecondsToUTCTime $ fromIntegral 12+ let end = posixSecondsToUTCTime $ fromIntegral 34+ TS.slice xs start end `shouldBe` TS.emptySeries++ it "maximum value" $ do+ let xs = TS.tsSeries [1..5] [10.0, 1.2, 32.4, 0.65, 11.0]+ TS.max xs `shouldBe` 32.4++ it "minimum value" $ do+ let xs = TS.tsSeries [1..5] [10.0, 1.2, 32.4, 0.65, 11.0]+ TS.min xs `shouldBe` 0.65
+ test-src/Spec.hs view
@@ -0,0 +1,9 @@+import Test.Hspec+import qualified Data.TimeSeries.SeriesSpec+import qualified Data.TimeSeries.CSVSpec+++main :: IO ()+main = hspec $ do+ describe "Series" Data.TimeSeries.SeriesSpec.spec+ describe "CSV" Data.TimeSeries.CSVSpec.spec
+ testdata/co2.csv view
@@ -0,0 +1,193 @@+"Month","CO2 (ppm) mauna loa, 1965-1980" +"1965-01",319.32 +"1965-02",320.36 +"1965-03",320.82 +"1965-04",322.06 +"1965-05",322.17 +"1965-06",321.95 +"1965-07",321.20 +"1965-08",318.81 +"1965-09",317.82 +"1965-10",317.37 +"1965-11",318.93 +"1965-12",319.09 +"1966-01",319.94 +"1966-02",320.98 +"1966-03",321.81 +"1966-04",323.03 +"1966-05",323.36 +"1966-06",323.11 +"1966-07",321.65 +"1966-08",319.64 +"1966-09",317.86 +"1966-10",317.25 +"1966-11",319.06 +"1966-12",320.26 +"1967-01",321.65 +"1967-02",321.81 +"1967-03",322.36 +"1967-04",323.67 +"1967-05",324.17 +"1967-06",323.39 +"1967-07",321.93 +"1967-08",320.29 +"1967-09",318.58 +"1967-10",318.60 +"1967-11",319.98 +"1967-12",321.25 +"1968-01",321.88 +"1968-02",322.47 +"1968-03",323.17 +"1968-04",324.23 +"1968-05",324.88 +"1968-06",324.75 +"1968-07",323.47 +"1968-08",321.34 +"1968-09",319.56 +"1968-10",319.45 +"1968-11",320.45 +"1968-12",321.92 +"1969-01",323.40 +"1969-02",324.21 +"1969-03",325.33 +"1969-04",326.31 +"1969-05",327.01 +"1969-06",326.24 +"1969-07",325.37 +"1969-08",323.12 +"1969-09",321.85 +"1969-10",321.31 +"1969-11",322.31 +"1969-12",323.72 +"1970-01",324.60 +"1970-02",325.57 +"1970-03",326.55 +"1970-04",327.80 +"1970-05",327.80 +"1970-06",327.54 +"1970-07",326.28 +"1970-08",324.63 +"1970-09",323.12 +"1970-10",323.11 +"1970-11",323.99 +"1970-12",325.09 +"1971-01",326.12 +"1971-02",326.61 +"1971-03",327.16 +"1971-04",327.92 +"1971-05",329.14 +"1971-06",328.80 +"1971-07",327.52 +"1971-08",325.62 +"1971-09",323.61 +"1971-10",323.80 +"1971-11",325.10 +"1971-12",326.25 +"1972-01",326.93 +"1972-02",327.83 +"1972-03",327.95 +"1972-04",329.91 +"1972-05",330.22 +"1972-06",329.25 +"1972-07",328.11 +"1972-08",326.39 +"1972-09",324.97 +"1972-10",325.32 +"1972-11",326.54 +"1972-12",327.71 +"1973-01",328.73 +"1973-02",329.69 +"1973-03",330.47 +"1973-04",331.69 +"1973-05",332.65 +"1973-06",332.24 +"1973-07",331.03 +"1973-08",329.36 +"1973-09",327.60 +"1973-10",327.29 +"1973-11",328.28 +"1973-12",328.79 +"1974-01",329.45 +"1974-02",330.89 +"1974-03",331.63 +"1974-04",332.85 +"1974-05",333.28 +"1974-06",332.47 +"1974-07",331.34 +"1974-08",329.53 +"1974-09",327.57 +"1974-10",327.57 +"1974-11",328.53 +"1974-12",329.69 +"1975-01",330.45 +"1975-02",330.97 +"1975-03",331.64 +"1975-04",332.87 +"1975-05",333.61 +"1975-06",333.55 +"1975-07",331.90 +"1975-08",330.05 +"1975-09",328.58 +"1975-10",328.31 +"1975-11",329.41 +"1975-12",330.63 +"1976-01",331.63 +"1976-02",332.46 +"1976-03",333.36 +"1976-04",334.45 +"1976-05",334.82 +"1976-06",334.32 +"1976-07",333.05 +"1976-08",330.87 +"1976-09",329.24 +"1976-10",328.87 +"1976-11",330.18 +"1976-12",331.50 +"1977-01",332.81 +"1977-02",333.23 +"1977-03",334.55 +"1977-04",335.82 +"1977-05",336.44 +"1977-06",335.99 +"1977-07",334.65 +"1977-08",332.41 +"1977-09",331.32 +"1977-10",330.73 +"1977-11",332.05 +"1977-12",333.53 +"1978-01",334.66 +"1978-02",335.07 +"1978-03",336.33 +"1978-04",337.39 +"1978-05",337.65 +"1978-06",337.57 +"1978-07",336.25 +"1978-08",334.39 +"1978-09",332.44 +"1978-10",332.25 +"1978-11",333.59 +"1978-12",334.76 +"1979-01",335.89 +"1979-02",336.44 +"1979-03",337.63 +"1979-04",338.54 +"1979-05",339.06 +"1979-06",338.95 +"1979-07",337.41 +"1979-08",335.71 +"1979-09",333.68 +"1979-10",333.69 +"1979-11",335.05 +"1979-12",336.53 +"1980-01",337.81 +"1980-02",338.16 +"1980-03",339.88 +"1980-04",340.57 +"1980-05",341.19 +"1980-06",340.87 +"1980-07",339.25 +"1980-08",337.19 +"1980-09",335.49 +"1980-10",336.63 +"1980-11",337.74 +"1980-12",338.36
+ testdata/small.csv view
@@ -0,0 +1,5 @@+"Month","CO2 (ppm) mauna loa, 1965-1980" +"1965-01",319.32 +"1965-02",320.36 +"1965-03",320.82 +"1965-04",322.06
+ timeseries.cabal view
@@ -0,0 +1,68 @@+name: timeseries+version: 0.1.0+synopsis: Library for Time Series processing+License: BSD3+License-file: LICENSE+Copyright: (c) 2016 Krzysztof Langner+Extra-Source-Files:+ README.md,+ CHANGES.md,+ LICENSE,+ benchmark/*.hs,+ testdata/*.csv+description:+ Library for processing time series data.++homepage: https://github.com/klangner/timeseries+author: Krzysztof Langner+maintainer: klangner@gmail.com+category: Data+build-type: Simple+cabal-version: >=1.10++source-repository head+ type: git+ location: https://github.com/klangner/timeseries++library+ hs-source-dirs: src+ default-language: Haskell2010+ ghc-options: -Wall+ build-depends:+ base >= 4.7 && < 5,+ bytestring < 0.11,+ bytestring-time < 1,+ cassava >= 0.4 && < 0.5,+ text < 2,+ time >= 1.5 && < 2,+ vector < 0.12+ exposed-modules:+ Data.TimeSeries+ other-modules:+ Data.TimeSeries.Series,+ Data.TimeSeries.CSVReader++test-suite unit-tests+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ default-language: Haskell2010+ build-depends:+ base >= 4 && <5,+ Cabal <2,+ hspec >=2 && <3,+ QuickCheck >=2.6 && <3,+ bytestring < 0.11,+ bytestring-time < 1,+ cassava >= 0.4 && < 0.5,+ text < 2,+ time >= 1.5 && < 2,+ vector < 0.12+ other-modules:+ Data.TimeSeries,+ Data.TimeSeries.Series,+ Data.TimeSeries.SeriesSpec+ Data.TimeSeries.CSVReader+ Data.TimeSeries.CSVSpec+ hs-source-dirs:+ src,+ test-src