module HMath.TimeSeries.Diagnostics (
Deterministic (..),
Stationarity (..),
augmentedDickeyFuller,
kpss,
changePoints,
cusum,
anomalies,
DTWResult (..),
dynamicTimeWarping,
spectrum,
ForecastMetric (..),
forecastError,
) where
import Control.Monad (foldM)
import Data.Array (Array, array, (!))
import Data.Complex (Complex ((:+)), magnitude)
import Data.List (minimumBy, transpose)
import Data.Ord (comparing)
import HMath.Error
import qualified HMath.Fourier as F
import qualified HMath.Matrix as M
import qualified HMath.Matrix.LU as LU
import qualified HMath.Matrix.QR as QR
import qualified HMath.Statistics.Advanced as Stats
import HMath.TimeSeries.Core
data Deterministic = Level | LinearTrend deriving (Deterministic -> Deterministic -> Bool
(Deterministic -> Deterministic -> Bool)
-> (Deterministic -> Deterministic -> Bool) -> Eq Deterministic
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Deterministic -> Deterministic -> Bool
== :: Deterministic -> Deterministic -> Bool
$c/= :: Deterministic -> Deterministic -> Bool
/= :: Deterministic -> Deterministic -> Bool
Eq, Int -> Deterministic -> ShowS
[Deterministic] -> ShowS
Deterministic -> String
(Int -> Deterministic -> ShowS)
-> (Deterministic -> String)
-> ([Deterministic] -> ShowS)
-> Show Deterministic
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Deterministic -> ShowS
showsPrec :: Int -> Deterministic -> ShowS
$cshow :: Deterministic -> String
show :: Deterministic -> String
$cshowList :: [Deterministic] -> ShowS
showList :: [Deterministic] -> ShowS
Show)
data Stationarity = Stationarity
{ Stationarity -> Double
stationarityStatistic :: Double
, Stationarity -> [(Double, Double)]
stationarityCriticalValues :: [(Double, Double)]
, Stationarity -> Int
stationarityObservations :: Int
, Stationarity -> String
stationarityNull :: String
}
deriving (Stationarity -> Stationarity -> Bool
(Stationarity -> Stationarity -> Bool)
-> (Stationarity -> Stationarity -> Bool) -> Eq Stationarity
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Stationarity -> Stationarity -> Bool
== :: Stationarity -> Stationarity -> Bool
$c/= :: Stationarity -> Stationarity -> Bool
/= :: Stationarity -> Stationarity -> Bool
Eq, Int -> Stationarity -> ShowS
[Stationarity] -> ShowS
Stationarity -> String
(Int -> Stationarity -> ShowS)
-> (Stationarity -> String)
-> ([Stationarity] -> ShowS)
-> Show Stationarity
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Stationarity -> ShowS
showsPrec :: Int -> Stationarity -> ShowS
$cshow :: Stationarity -> String
show :: Stationarity -> String
$cshowList :: [Stationarity] -> ShowS
showList :: [Stationarity] -> ShowS
Show)
augmentedDickeyFuller :: Deterministic -> Int -> [Double] -> Either MathError Stationarity
augmentedDickeyFuller :: Deterministic -> Int -> [Double] -> Either MathError Stationarity
augmentedDickeyFuller Deterministic
deterministic Int
lags [Double]
xs = do
Int -> [Double] -> Either MathError ()
validate Int
4 [Double]
xs
Bool -> String -> Either MathError ()
require (Int
lags Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0 Bool -> Bool -> Bool
&& Int
lags Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
64 Bool -> Bool -> Bool
&& [Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
xs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
4096) String
"ADF lag/sample limit"
let deltas :: [Double]
deltas = (Double -> Double -> Double) -> [Double] -> [Double] -> [Double]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (-) ((Int -> [Double] -> [Double]
forall a. Int -> [a] -> [a]
drop Int
1) [Double]
xs) [Double]
xs
rows :: [[Double]]
rows =
[ [Double]
xs [Double] -> Int -> Double
forall a. HasCallStack => [a] -> Int -> a
!! Int
t
Double -> [Double] -> [Double]
forall a. a -> [a] -> [a]
: Deterministic -> Double -> [Double]
deterministicRow Deterministic
deterministic (Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
t Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1))
[Double] -> [Double] -> [Double]
forall a. [a] -> [a] -> [a]
++ [[Double]
deltas [Double] -> Int -> Double
forall a. HasCallStack => [a] -> Int -> a
!! (Int
t Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
j) | Int
j <- [Int
1 .. Int
lags]]
| Int
t <- [Int
lags .. [Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
deltas Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1]
]
target :: [Double]
target = Int -> [Double] -> [Double]
forall a. Int -> [a] -> [a]
drop Int
lags [Double]
deltas
n :: Int
n = [Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
target
width :: Int
width = Int
lags Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ if Deterministic
deterministic Deterministic -> Deterministic -> Bool
forall a. Eq a => a -> a -> Bool
== Deterministic
LinearTrend then Int
1 else Int
0
Bool -> String -> Either MathError ()
require (Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
width) String
"insufficient ADF residual degrees of freedom"
(b, residual, gramInverse) <- [[Double]]
-> [Double] -> Either MathError ([Double], [Double], [[Double]])
regression [[Double]]
rows [Double]
target
let variance = [Double] -> Double
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ((Double -> Double) -> [Double] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map (Double -> Int -> Double
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int
2 :: Int)) [Double]
residual) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
width)
se = Double -> Double
forall a. Floating a => a -> a
sqrt (Double
variance Double -> Double -> Double
forall a. Num a => a -> a -> a
* ([Double] -> Int -> Double
forall a. HasCallStack => [a] -> Int -> a
!! Int
0) (([[Double]] -> Int -> [Double]
forall a. HasCallStack => [a] -> Int -> a
!! Int
0) [[Double]]
gramInverse))
require (finite se && se > 0) "degenerate ADF residual variance"
stat <- (!! 0) <$> checked [(!! 0) b / se]
let coefficients =
if Deterministic
deterministic Deterministic -> Deterministic -> Bool
forall a. Eq a => a -> a -> Bool
== Deterministic
Level
then
[ [-Double
3.43035, -Double
6.5393, -Double
16.786, -Double
79.433]
, [-Double
2.86154, -Double
2.8903, -Double
4.234, -Double
40.040]
, [-Double
2.56677, -Double
1.5384, -Double
2.809, Double
0]
]
else
[ [-Double
3.95877, -Double
9.0531, -Double
28.428, -Double
134.155]
, [-Double
3.41049, -Double
4.3904, -Double
9.036, -Double
45.374]
, [-Double
3.12705, -Double
2.5856, -Double
3.925, -Double
22.380]
]
critical [a]
row = [a] -> a
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [a
v a -> a -> a
forall a. Fractional a => a -> a -> a
/ (Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n a -> Int -> a
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
k) | (Int
k, a
v) <- [Int] -> [a] -> [(Int, a)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0 :: Int ..] [a]
row]
Right (Stationarity stat (zip [0.01, 0.05, 0.1] (map critical coefficients)) n "unit root")
kpss :: Deterministic -> Int -> [Double] -> Either MathError Stationarity
kpss :: Deterministic -> Int -> [Double] -> Either MathError Stationarity
kpss Deterministic
deterministic Int
lags [Double]
xs = do
Int -> [Double] -> Either MathError ()
validate Int
4 [Double]
xs
Bool -> String -> Either MathError ()
require
( Int
lags Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0
Bool -> Bool -> Bool
&& Int
lags Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< [Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
xs
Bool -> Bool -> Bool
&& [Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
xs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
4096
Bool -> Bool -> Bool
&& Int -> Integer
forall a. Integral a => a -> Integer
toInteger Int
lags Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Int -> Integer
forall a. Integral a => a -> Integer
toInteger ([Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
xs) Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= Integer
4000000
)
String
"KPSS lag/sample limit"
let n :: Int
n = [Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
xs; nf :: Double
nf = Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
residual <- case Deterministic
deterministic of
Deterministic
Level -> [Double] -> Either MathError [Double]
forall a b. b -> Either a b
Right ((Double -> Double) -> [Double] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map (Double -> Double -> Double
forall a. Num a => a -> a -> a
subtract ([Double] -> Double
average [Double]
xs)) [Double]
xs)
Deterministic
LinearTrend -> do
(_, rs, _) <- [[Double]]
-> [Double] -> Either MathError ([Double], [Double], [[Double]])
regression [Deterministic -> Double -> [Double]
deterministicRow Deterministic
deterministic (Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
i) | Int
i <- [Int
1 .. Int
n]] [Double]
xs
Right rs
let energy = [Double] -> Double
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ((Double -> Double) -> [Double] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map (Double -> Int -> Double
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int
2 :: Int)) [Double]
residual)
longRun =
( Double
energy
Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
2
Double -> Double -> Double
forall a. Num a => a -> a -> a
* [Double] -> Double
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum
[ (Double
1 Double -> Double -> Double
forall a. Num a => a -> a -> a
- Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
k Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
lags Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)) Double -> Double -> Double
forall a. Num a => a -> a -> a
* [Double] -> Double
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ((Double -> Double -> Double) -> [Double] -> [Double] -> [Double]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Double -> Double -> Double
forall a. Num a => a -> a -> a
(*) (Int -> [Double] -> [Double]
forall a. Int -> [a] -> [a]
drop Int
k [Double]
residual) [Double]
residual)
| Int
k <- [Int
1 .. Int
lags]
]
)
Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
nf
partial = (Int -> [Double] -> [Double]
forall a. Int -> [a] -> [a]
drop Int
1) ((Double -> Double -> Double) -> Double -> [Double] -> [Double]
forall b a. (b -> a -> b) -> b -> [a] -> [b]
scanl Double -> Double -> Double
forall a. Num a => a -> a -> a
(+) Double
0 [Double]
residual)
require (finite longRun && longRun > 1e-28 * max 1 energy) "degenerate KPSS long-run variance"
stat <- (!! 0) <$> checked [sum (map (^ (2 :: Int)) partial) / (nf * nf * longRun)]
let critical = if Deterministic
deterministic Deterministic -> Deterministic -> Bool
forall a. Eq a => a -> a -> Bool
== Deterministic
Level then [Double
0.347, Double
0.463, Double
0.574, Double
0.739] else [Double
0.119, Double
0.146, Double
0.176, Double
0.216]
Right (Stationarity stat (zip [0.1, 0.05, 0.025, 0.01] critical) n "stationarity")
deterministicRow :: Deterministic -> Double -> [Double]
deterministicRow :: Deterministic -> Double -> [Double]
deterministicRow Deterministic
Level Double
_ = [Double
1]
deterministicRow Deterministic
LinearTrend Double
t = [Double
1, Double
t]
regression :: [[Double]] -> [Double] -> Either MathError ([Double], [Double], [[Double]])
regression :: [[Double]]
-> [Double] -> Either MathError ([Double], [Double], [[Double]])
regression [[Double]]
rows [Double]
target = do
let n :: Int
n = [[Double]] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [[Double]]
rows; p :: Int
p = [Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (([[Double]] -> Int -> [Double]
forall a. HasCallStack => [a] -> Int -> a
!! Int
0) [[Double]]
rows)
matrix <- Int -> Int -> [Double] -> Either MathError (Matrix Double)
forall a. Int -> Int -> [a] -> Either MathError (Matrix a)
M.fromListChecked Int
n Int
p ([[Double]] -> [Double]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Double]]
rows)
b <- QR.leastSquares matrix target
let residual = (Double -> Double -> Double) -> [Double] -> [Double] -> [Double]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (-) [Double]
target [[Double] -> Double
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ((Double -> Double -> Double) -> [Double] -> [Double] -> [Double]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Double -> Double -> Double
forall a. Num a => a -> a -> a
(*) [Double]
row [Double]
b) | [Double]
row <- [[Double]]
rows]
gram = [[[Double] -> Double
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ((Double -> Double -> Double) -> [Double] -> [Double] -> [Double]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Double -> Double -> Double
forall a. Num a => a -> a -> a
(*) [Double]
a [Double]
c) | [Double]
c <- [[Double]] -> [[Double]]
forall a. [[a]] -> [[a]]
transpose [[Double]]
rows] | [Double]
a <- [[Double]] -> [[Double]]
forall a. [[a]] -> [[a]]
transpose [[Double]]
rows]
gm <- M.fromListChecked p p (concat gram)
inverse <- LU.inverse gm
let iv = [Int -> [Double] -> [Double]
forall a. Int -> [a] -> [a]
take Int
p (Int -> [Double] -> [Double]
forall a. Int -> [a] -> [a]
drop (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
p) (Matrix Double -> [Double]
forall a. Matrix a -> [a]
M.toList Matrix Double
inverse)) | Int
i <- [Int
0 .. Int
p Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1]]
_ <- checked (b ++ residual ++ concat iv)
Right (b, residual, iv)
changePoints :: Double -> Int -> [Double] -> Either MathError [Int]
changePoints :: Double -> Int -> [Double] -> Either MathError [Int]
changePoints Double
penalty Int
minSegment [Double]
xs = do
Int -> [Double] -> Either MathError ()
validate Int
1 [Double]
xs
let n :: Int
n = [Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
xs
Bool -> String -> Either MathError ()
require
(Double -> Bool
finite Double
penalty Bool -> Bool -> Bool
&& Double
penalty Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
>= Double
0 Bool -> Bool -> Bool
&& Int
minSegment Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
1 Bool -> Bool -> Bool
&& Int
minSegment Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
n Bool -> Bool -> Bool
&& Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
2048)
String
"change-point configuration/sample limit"
let centered :: [Double]
centered = (Double -> Double) -> [Double] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map (Double -> Double -> Double
forall a. Num a => a -> a -> a
subtract ([Double] -> Double
average [Double]
xs)) [Double]
xs
sums :: Array Int Double
sums = [Double] -> Array Int Double
forall {a}. Num a => [a] -> Array Int a
prefix [Double]
centered
squares :: Array Int Double
squares = [Double] -> Array Int Double
forall {a}. Num a => [a] -> Array Int a
prefix ((Double -> Double) -> [Double] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map (Double -> Int -> Double
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int
2 :: Int)) [Double]
centered)
cost :: Int -> Int -> Double
cost Int
i Int
j =
let s :: Double
s = Array Int Double
sums Array Int Double -> Int -> Double
forall i e. Ix i => Array i e -> i -> e
! Int
j Double -> Double -> Double
forall a. Num a => a -> a -> a
- Array Int Double
sums Array Int Double -> Int -> Double
forall i e. Ix i => Array i e -> i -> e
! Int
i; q :: Double
q = Array Int Double
squares Array Int Double -> Int -> Double
forall i e. Ix i => Array i e -> i -> e
! Int
j Double -> Double -> Double
forall a. Num a => a -> a -> a
- Array Int Double
squares Array Int Double -> Int -> Double
forall i e. Ix i => Array i e -> i -> e
! Int
i
in Double -> Double -> Double
forall a. Ord a => a -> a -> a
max Double
0 (Double
q Double -> Double -> Double
forall a. Num a => a -> a -> a
- (Double
s Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double -> Double
forall a. Floating a => a -> a
sqrt (Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
j Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
i))) Double -> Int -> Double
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int
2 :: Int))
solution :: Array Int (Double, [Int])
solution :: Array Int (Double, [Int])
solution = (Int, Int) -> [(Int, (Double, [Int]))] -> Array Int (Double, [Int])
forall i e. Ix i => (i, i) -> [(i, e)] -> Array i e
array (Int
0, Int
n) [(Int
j, Int -> (Double, [Int])
entry Int
j) | Int
j <- [Int
0 .. Int
n]]
entry :: Int -> (Double, [Int])
entry Int
0 = (-Double
penalty, [])
entry Int
j = case [ (Double
base Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Int -> Int -> Double
cost Int
i Int
j Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
penalty, if Int
i Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 then [] else [Int]
breaks [Int] -> [Int] -> [Int]
forall a. [a] -> [a] -> [a]
++ [Int
i])
| Int
i <- [Int
0 .. Int
j Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
minSegment]
, Int
i Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 Bool -> Bool -> Bool
|| Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
minSegment
, let (Double
base, [Int]
breaks) = Array Int (Double, [Int])
solution Array Int (Double, [Int]) -> Int -> (Double, [Int])
forall i e. Ix i => Array i e -> i -> e
! Int
i
, Double -> Bool
finite Double
base
] of
[] -> (Double
1 Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
0, [])
[(Double, [Int])]
candidates -> ((Double, [Int]) -> (Double, [Int]) -> Ordering)
-> [(Double, [Int])] -> (Double, [Int])
forall (t :: * -> *) a.
Foldable t =>
(a -> a -> Ordering) -> t a -> a
minimumBy (((Double, [Int]) -> Double)
-> (Double, [Int]) -> (Double, [Int]) -> Ordering
forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing (Double, [Int]) -> Double
forall a b. (a, b) -> a
fst) [(Double, [Int])]
candidates
_ <- [Double] -> Either MathError [Double]
checked ([Double]
centered [Double] -> [Double] -> [Double]
forall a. [a] -> [a] -> [a]
++ Array Int Double -> [Double]
forall {a}. Array Int a -> [a]
elemsOf Array Int Double
sums [Double] -> [Double] -> [Double]
forall a. [a] -> [a] -> [a]
++ Array Int Double -> [Double]
forall {a}. Array Int a -> [a]
elemsOf Array Int Double
squares)
let (value, breaks) = solution ! n
_ <- checked [value]
Right breaks
where
prefix :: [a] -> Array Int a
prefix [a]
ys = (Int, Int) -> [(Int, a)] -> Array Int a
forall i e. Ix i => (i, i) -> [(i, e)] -> Array i e
array (Int
0, [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
ys) ([Int] -> [a] -> [(Int, a)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0 ..] ((a -> a -> a) -> a -> [a] -> [a]
forall b a. (b -> a -> b) -> b -> [a] -> [b]
scanl a -> a -> a
forall a. Num a => a -> a -> a
(+) a
0 [a]
ys))
elemsOf :: Array Int a -> [a]
elemsOf Array Int a
a = [Array Int a
a Array Int a -> Int -> a
forall i e. Ix i => Array i e -> i -> e
! Int
i | Int
i <- [Int
0 .. [Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
xs]]
cusum :: Double -> Double -> Double -> Double -> [Double] -> Either MathError [Int]
cusum :: Double
-> Double -> Double -> Double -> [Double] -> Either MathError [Int]
cusum Double
mean Double
sd Double
drift Double
threshold [Double]
xs = do
Int -> [Double] -> Either MathError ()
validate Int
0 [Double]
xs
Bool -> String -> Either MathError ()
require
((Double -> Bool) -> [Double] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Double -> Bool
finite [Double
mean, Double
sd, Double
drift, Double
threshold] Bool -> Bool -> Bool
&& Double
sd Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
0 Bool -> Bool -> Bool
&& Double
drift Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
>= Double
0 Bool -> Bool -> Bool
&& Double
threshold Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
0)
String
"invalid CUSUM parameters"
let step :: (a, b, [a])
-> (a, Double) -> Either MathError (Double, Double, [a])
step (a
plus, b
minus, [a]
alerts) (a
i, Double
x) = do
let z :: Double
z = (Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
mean) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
sd
_ <- [Double] -> Either MathError [Double]
checked [Double
z]
let score a
old a
delta = Rational -> a
forall a. Fractional a => Rational -> a
fromRational (Rational -> Rational -> Rational
forall a. Ord a => a -> a -> a
max Rational
0 (a -> Rational
forall a. Real a => a -> Rational
toRational a
old Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
+ a -> Rational
forall a. Real a => a -> Rational
toRational a
delta Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
- Double -> Rational
forall a. Real a => a -> Rational
toRational Double
drift))
p = a -> Double -> Double
forall {a} {a} {a}. (Fractional a, Real a, Real a) => a -> a -> a
score a
plus Double
z
m = b -> Double -> Double
forall {a} {a} {a}. (Fractional a, Real a, Real a) => a -> a -> a
score b
minus (-Double
z)
_ <- checked [p, m]
Right (if max p m > threshold then (0, 0, i : alerts) else (p, m, alerts))
(_, _, finalAlerts) <- ((Double, Double, [Int])
-> (Int, Double) -> Either MathError (Double, Double, [Int]))
-> (Double, Double, [Int])
-> [(Int, Double)]
-> Either MathError (Double, Double, [Int])
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM (Double, Double, [Int])
-> (Int, Double) -> Either MathError (Double, Double, [Int])
forall {a} {b} {a}.
(Real a, Real b) =>
(a, b, [a])
-> (a, Double) -> Either MathError (Double, Double, [a])
step (Double
0, Double
0, []) ([Int] -> [Double] -> [(Int, Double)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0 ..] [Double]
xs)
Right (reverse finalAlerts)
anomalies :: Double -> [Double] -> Either MathError [Int]
anomalies :: Double -> [Double] -> Either MathError [Int]
anomalies Double
threshold [Double]
xs = do
Int -> [Double] -> Either MathError ()
validate Int
1 [Double]
xs
Bool -> String -> Either MathError ()
require (Double -> Bool
finite Double
threshold Bool -> Bool -> Bool
&& Double
threshold Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
0) String
"positive anomaly threshold required"
median <- [Double] -> Either MathError Double
Stats.median [Double]
xs
mad <- Stats.median (map (abs . subtract median) xs)
differences <- checked (map (subtract median) xs)
scores <-
if mad == 0
then Right (replicate (length xs) 0)
else checked [abs delta / mad / 1.4826022185 | delta <- differences]
Right
[i | (i, (x, z)) <- zip [0 ..] (zip xs scores), if mad == 0 then x /= median else z > threshold]
data DTWResult = DTWResult
{ DTWResult -> Double
dtwDistance :: Double
, DTWResult -> [(Int, Int)]
dtwPath :: [(Int, Int)]
}
deriving (DTWResult -> DTWResult -> Bool
(DTWResult -> DTWResult -> Bool)
-> (DTWResult -> DTWResult -> Bool) -> Eq DTWResult
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: DTWResult -> DTWResult -> Bool
== :: DTWResult -> DTWResult -> Bool
$c/= :: DTWResult -> DTWResult -> Bool
/= :: DTWResult -> DTWResult -> Bool
Eq, Int -> DTWResult -> ShowS
[DTWResult] -> ShowS
DTWResult -> String
(Int -> DTWResult -> ShowS)
-> (DTWResult -> String)
-> ([DTWResult] -> ShowS)
-> Show DTWResult
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> DTWResult -> ShowS
showsPrec :: Int -> DTWResult -> ShowS
$cshow :: DTWResult -> String
show :: DTWResult -> String
$cshowList :: [DTWResult] -> ShowS
showList :: [DTWResult] -> ShowS
Show)
dynamicTimeWarping :: Int -> [Double] -> [Double] -> Either MathError DTWResult
dynamicTimeWarping :: Int -> [Double] -> [Double] -> Either MathError DTWResult
dynamicTimeWarping Int
radius [Double]
xs [Double]
ys = do
Int -> [Double] -> Either MathError ()
validate Int
1 [Double]
xs
Int -> [Double] -> Either MathError ()
validate Int
1 [Double]
ys
let n :: Int
n = [Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
xs; m :: Int
m = [Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
ys
Bool -> String -> Either MathError ()
require (Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
512 Bool -> Bool -> Bool
&& Int
m Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
512 Bool -> Bool -> Bool
&& Int
radius Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int -> Int
forall a. Num a => a -> a
abs (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
m) Bool -> Bool -> Bool
&& Int
radius Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
16384) String
"DTW size/radius limit"
let table :: Array (Int, Int) (Double, (Int, Int))
table :: Array (Int, Int) (Double, (Int, Int))
table = ((Int, Int), (Int, Int))
-> [((Int, Int), (Double, (Int, Int)))]
-> Array (Int, Int) (Double, (Int, Int))
forall i e. Ix i => (i, i) -> [(i, e)] -> Array i e
array ((Int
0, Int
0), (Int
n, Int
m)) [((Int
i, Int
j), Int -> Int -> (Double, (Int, Int))
entry Int
i Int
j) | Int
i <- [Int
0 .. Int
n], Int
j <- [Int
0 .. Int
m]]
entry :: Int -> Int -> (Double, (Int, Int))
entry Int
0 Int
0 = (Double
0, (Int
0, Int
0))
entry Int
i Int
j
| Int
i Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 Bool -> Bool -> Bool
|| Int
j Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 Bool -> Bool -> Bool
|| Int -> Int
forall a. Num a => a -> a
abs (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
j) Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
radius = (Double
1 Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
0, (Int
0, Int
0))
| Bool
otherwise =
let choices :: [(Double, (Int, Int))]
choices = [((Double, (Int, Int)) -> Double
forall a b. (a, b) -> a
fst (Array (Int, Int) (Double, (Int, Int))
table Array (Int, Int) (Double, (Int, Int))
-> (Int, Int) -> (Double, (Int, Int))
forall i e. Ix i => Array i e -> i -> e
! (Int
a, Int
b)), (Int
a, Int
b)) | (Int
a, Int
b) <- [(Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1, Int
j Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1), (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1, Int
j), (Int
i, Int
j Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)]]
(Double
cost, (Int, Int)
predecessor) = ((Double, (Int, Int)) -> (Double, (Int, Int)) -> Ordering)
-> [(Double, (Int, Int))] -> (Double, (Int, Int))
forall (t :: * -> *) a.
Foldable t =>
(a -> a -> Ordering) -> t a -> a
minimumBy (((Double, (Int, Int)) -> Double)
-> (Double, (Int, Int)) -> (Double, (Int, Int)) -> Ordering
forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing (Double, (Int, Int)) -> Double
forall a b. (a, b) -> a
fst) [(Double, (Int, Int))]
choices
in (Double
cost Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double -> Double
forall a. Num a => a -> a
abs ([Double]
xs [Double] -> Int -> Double
forall a. HasCallStack => [a] -> Int -> a
!! (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Double -> Double -> Double
forall a. Num a => a -> a -> a
- [Double]
ys [Double] -> Int -> Double
forall a. HasCallStack => [a] -> Int -> a
!! (Int
j Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)), (Int, Int)
predecessor)
trace :: (Int, Int) -> [(Int, Int)] -> [(Int, Int)]
trace (Int
0, Int
0) [(Int, Int)]
acc = [(Int, Int)]
acc
trace ij :: (Int, Int)
ij@(Int
i, Int
j) [(Int, Int)]
acc = (Int, Int) -> [(Int, Int)] -> [(Int, Int)]
trace ((Double, (Int, Int)) -> (Int, Int)
forall a b. (a, b) -> b
snd (Array (Int, Int) (Double, (Int, Int))
table Array (Int, Int) (Double, (Int, Int))
-> (Int, Int) -> (Double, (Int, Int))
forall i e. Ix i => Array i e -> i -> e
! (Int, Int)
ij)) ((Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1, Int
j Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) (Int, Int) -> [(Int, Int)] -> [(Int, Int)]
forall a. a -> [a] -> [a]
: [(Int, Int)]
acc)
distance :: Double
distance = (Double, (Int, Int)) -> Double
forall a b. (a, b) -> a
fst (Array (Int, Int) (Double, (Int, Int))
table Array (Int, Int) (Double, (Int, Int))
-> (Int, Int) -> (Double, (Int, Int))
forall i e. Ix i => Array i e -> i -> e
! (Int
n, Int
m))
_ <- [Double] -> Either MathError [Double]
checked [Double
distance]
Right (DTWResult distance (trace (n, m) []))
spectrum :: Double -> [Double] -> Either MathError [(Double, Double)]
spectrum :: Double -> [Double] -> Either MathError [(Double, Double)]
spectrum Double
sampleRate [Double]
xs = do
Int -> [Double] -> Either MathError ()
validate Int
1 [Double]
xs
Bool -> String -> Either MathError ()
require (Double -> Bool
finite Double
sampleRate Bool -> Bool -> Bool
&& Double
sampleRate Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
0) String
"positive sample rate required"
bins <- [Complex Double] -> Either MathError [Complex Double]
F.fft ((Double -> Complex Double) -> [Double] -> [Complex Double]
forall a b. (a -> b) -> [a] -> [b]
map (Double -> Double -> Complex Double
forall a. a -> a -> Complex a
:+ Double
0) [Double]
xs)
let n = [Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
xs
density =
[ ( Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
k Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
sampleRate Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
, Complex Double -> Double
forall a. RealFloat a => Complex a -> a
magnitude ([Complex Double]
bins [Complex Double] -> Int -> Complex Double
forall a. HasCallStack => [a] -> Int -> a
!! Int
k) Double -> Int -> Double
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int
2 :: Int)
Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ (Double
sampleRate Double -> Double -> Double
forall a. Num a => a -> a -> a
* Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n)
Double -> Double -> Double
forall a. Num a => a -> a -> a
* (if Int
k Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 Bool -> Bool -> Bool
|| Int -> Bool
forall a. Integral a => a -> Bool
even Int
n Bool -> Bool -> Bool
&& Int
k Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
n Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2 then Double
1 else Double
2)
)
| Int
k <- [Int
0 .. Int
n Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2]
]
_ <- checked (concatMap (\(Double
a, Double
b) -> [Double
a, Double
b]) density)
Right density
data ForecastMetric = MAE | MSE | RMSE | MAPE | SMAPE | MASE Int [Double] deriving (ForecastMetric -> ForecastMetric -> Bool
(ForecastMetric -> ForecastMetric -> Bool)
-> (ForecastMetric -> ForecastMetric -> Bool) -> Eq ForecastMetric
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ForecastMetric -> ForecastMetric -> Bool
== :: ForecastMetric -> ForecastMetric -> Bool
$c/= :: ForecastMetric -> ForecastMetric -> Bool
/= :: ForecastMetric -> ForecastMetric -> Bool
Eq, Int -> ForecastMetric -> ShowS
[ForecastMetric] -> ShowS
ForecastMetric -> String
(Int -> ForecastMetric -> ShowS)
-> (ForecastMetric -> String)
-> ([ForecastMetric] -> ShowS)
-> Show ForecastMetric
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ForecastMetric -> ShowS
showsPrec :: Int -> ForecastMetric -> ShowS
$cshow :: ForecastMetric -> String
show :: ForecastMetric -> String
$cshowList :: [ForecastMetric] -> ShowS
showList :: [ForecastMetric] -> ShowS
Show)
forecastError :: ForecastMetric -> [Double] -> [Double] -> Either MathError Double
forecastError :: ForecastMetric -> [Double] -> [Double] -> Either MathError Double
forecastError ForecastMetric
metric [Double]
actual [Double]
predicted = do
Int -> [Double] -> Either MathError ()
validate Int
1 [Double]
actual
Int -> [Double] -> Either MathError ()
validate Int
1 [Double]
predicted
Bool -> String -> Either MathError ()
require ([Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
actual Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== [Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
predicted) String
"forecast metric length mismatch"
let errors :: [Double]
errors = (Double -> Double -> Double) -> [Double] -> [Double] -> [Double]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (-) [Double]
predicted [Double]
actual; mse :: Double
mse = [Double] -> Double
average ((Double -> Double) -> [Double] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map (Double -> Int -> Double
forall a b. (Num a, Integral b) => a -> b -> a
^ (Int
2 :: Int)) [Double]
errors)
value <- case ForecastMetric
metric of
ForecastMetric
MAE -> Double -> Either MathError Double
forall a b. b -> Either a b
Right ([Double] -> Double
average ((Double -> Double) -> [Double] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map Double -> Double
forall a. Num a => a -> a
abs [Double]
errors))
ForecastMetric
MSE -> Double -> Either MathError Double
forall a b. b -> Either a b
Right Double
mse
ForecastMetric
RMSE -> Double -> Either MathError Double
forall a b. b -> Either a b
Right (Double -> Double
forall a. Floating a => a -> a
sqrt Double
mse)
ForecastMetric
MAPE -> do
Bool -> String -> Either MathError ()
require ((Double -> Bool) -> [Double] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
/= Double
0) [Double]
actual) String
"MAPE actual values must be nonzero"
Double -> Either MathError Double
forall a b. b -> Either a b
Right (Double
100 Double -> Double -> Double
forall a. Num a => a -> a -> a
* [Double] -> Double
average ((Double -> Double -> Double) -> [Double] -> [Double] -> [Double]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (\Double
e Double
x -> Double -> Double
forall a. Num a => a -> a
abs (Double
e Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
x)) [Double]
errors [Double]
actual))
ForecastMetric
SMAPE ->
Double -> Either MathError Double
forall a b. b -> Either a b
Right
( Double
100
Double -> Double -> Double
forall a. Num a => a -> a -> a
* [Double] -> Double
average
[ if Double
x Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
== Double
0 Bool -> Bool -> Bool
&& Double
y Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
== Double
0
then Double
0
else Double
2 Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double -> Double
forall a. Num a => a -> a
abs (Double
x Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
scale Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
y Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
scale) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ (Double -> Double
forall a. Num a => a -> a
abs (Double
x Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
scale) Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double -> Double
forall a. Num a => a -> a
abs (Double
y Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
scale))
| (Double
x, Double
y) <- [Double] -> [Double] -> [(Double, Double)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Double]
actual [Double]
predicted
, let scale :: Double
scale = Double -> Double -> Double
forall a. Ord a => a -> a -> a
max (Double -> Double
forall a. Num a => a -> a
abs Double
x) (Double -> Double
forall a. Num a => a -> a
abs Double
y)
]
)
MASE Int
lag [Double]
training -> do
deltas <- Int -> Int -> [Double] -> Either MathError [Double]
difference Int
1 Int
lag [Double]
training
let scale = [Double] -> Double
average ((Double -> Double) -> [Double] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map Double -> Double
forall a. Num a => a -> a
abs [Double]
deltas)
require (finite scale && scale > 0) "MASE requires nonzero training scale"
Right (average (map abs errors) / scale)
(!! 0) <$> checked [value]