packages feed

foldl-statistics 0.1.0.0 → 0.1.1.0

raw patch · 3 files changed

+228/−104 lines, 3 filesdep ~math-functionsPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: math-functions

API changes (from Hackage documentation)

+ Control.Foldl.Statistics: LinRegResult :: {-# UNPACK #-} !Int -> {-# UNPACK #-} !Double -> {-# UNPACK #-} !Double -> {-# UNPACK #-} !Double -> LinRegResult
+ Control.Foldl.Statistics: Stats4 :: {-# UNPACK #-} !Int -> {-# UNPACK #-} !Double -> {-# UNPACK #-} !Double -> {-# UNPACK #-} !Double -> {-# UNPACK #-} !Double -> Stats4
+ Control.Foldl.Statistics: [lrrCorrelation] :: LinRegResult -> {-# UNPACK #-} !Double
+ Control.Foldl.Statistics: [lrrCount] :: LinRegResult -> {-# UNPACK #-} !Int
+ Control.Foldl.Statistics: [lrrIntercept] :: LinRegResult -> {-# UNPACK #-} !Double
+ Control.Foldl.Statistics: [lrrSlope] :: LinRegResult -> {-# UNPACK #-} !Double
+ Control.Foldl.Statistics: [stats4Count] :: Stats4 -> {-# UNPACK #-} !Int
+ Control.Foldl.Statistics: [stats4Kurtosis] :: Stats4 -> {-# UNPACK #-} !Double
+ Control.Foldl.Statistics: [stats4Mean] :: Stats4 -> {-# UNPACK #-} !Double
+ Control.Foldl.Statistics: [stats4Skewness] :: Stats4 -> {-# UNPACK #-} !Double
+ Control.Foldl.Statistics: [stats4Variance] :: Stats4 -> {-# UNPACK #-} !Double
+ Control.Foldl.Statistics: data LinRegResult
+ Control.Foldl.Statistics: data Stats4
+ Control.Foldl.Statistics: fastLMVSK :: Fold Double Stats4
+ Control.Foldl.Statistics: fastLinearReg :: Fold (Double, Double) LinRegResult
+ Control.Foldl.Statistics: instance GHC.Classes.Eq Control.Foldl.Statistics.LinRegResult
+ Control.Foldl.Statistics: instance GHC.Classes.Eq Control.Foldl.Statistics.Stats4
+ Control.Foldl.Statistics: instance GHC.Show.Show Control.Foldl.Statistics.LinRegResult
+ Control.Foldl.Statistics: instance GHC.Show.Show Control.Foldl.Statistics.Stats4

Files

bench/Main.hs view
@@ -15,6 +15,9 @@ sample :: U.Vector Double sample = runST $ flip uniformVector 10000 =<< create +sample2 :: U.Vector (Double,Double)+sample2 = runST $ flip uniformVector 10000 =<< create+ absSample = U.map abs sample  -- Weighted test sample@@ -30,106 +33,112 @@  main :: IO () main = defaultMain-        [ bgroup "Statistics of location"-            [ bgroup "mean"-                [ bench "C.F.Statistics"      $ nf (\vec -> F.fold mean (U.toList vec)) sample-                , bench "Statistics.Sample"   $ nf S.mean sample-                ]-            , bgroup "meanWeighted"-                [ bench "C.F.Statistics"      $ nf (\vec -> F.fold meanWeighted (U.toList vec)) sampleW-                , bench "Statistics.Sample"   $ nf S.meanWeighted sampleW-                ]-            , bgroup "welfordMean"-                [ bench "C.F.Statistics"      $ nf (\vec -> F.fold welfordMean (U.toList vec)) sample-                , bench "Statistics.Sample"   $ nf S.welfordMean sample-                ]-            , bgroup "harmonicMean"-                [ bench "C.F.Statistics"      $ nf (\vec -> F.fold harmonicMean (U.toList vec)) sample-                , bench "Statistics.Sample"   $ nf S.harmonicMean sample-                ]-            , bgroup "geometricMean"-                [ bench "C.F.Statistics"      $ nf (\vec -> F.fold geometricMean (U.toList vec)) absSample-                , bench "Statistics.Sample"   $ nf S.geometricMean absSample-                ]-            ]-        , bgroup "Single-pass functions"-            [ bgroup "fastVariance"-                [ bench "C.F.Statistics"    $ nf (\vec -> F.fold fastVariance (U.toList vec)) sample-                , bench "Statistics.Sample" $ nf S.fastVariance sample-                ]-            , bgroup "fastVarianceUnbiased"-                [ bench "C.F.Statistics"    $ nf (\vec -> F.fold fastVarianceUnbiased (U.toList vec)) sample-                , bench "Statistics.Sample" $ nf S.fastVarianceUnbiased sample-                ]-            , bgroup "fastStdDev"-                [ bench "C.F.Statistics"    $ nf (\vec -> F.fold fastStdDev (U.toList vec)) sample-                , bench "Statistics.Sample" $ nf S.fastStdDev sample-                ]-            ]--        , bgroup "Functions requiring the mean"-            [ bgroup "variance"-                [ bench "C.F.Statistics"    $ nf (\vec -> F.fold (variance m) (U.toList vec)) sample-                , bench "C.F.S(comp mean)"  $ nf (\vec -> F.fold (variance (F.fold mean (U.toList vec))) (U.toList vec)) sample-                , bench "Statistics.Sample" $ nf S.variance sample-                ]-            , bgroup "varianceUnbiased"-                [ bench "C.F.Statistics"    $ nf (\vec -> F.fold (varianceUnbiased m) (U.toList vec)) sample-                , bench "C.F.S(comp mean)"  $ nf (\vec -> F.fold (varianceUnbiased (F.fold mean (U.toList vec))) (U.toList vec)) sample-                , bench "Statistics.Sample" $ nf S.varianceUnbiased sample-                ]-            , bgroup "stdDev"-                [ bench "C.F.Statistics"    $ nf (\vec -> F.fold (stdDev m) (U.toList vec)) sample-                , bench "C.F.S(comp mean)"  $ nf (\vec -> F.fold (stdDev (F.fold mean (U.toList vec))) (U.toList vec)) sample-                , bench "Statistics.Sample" $ nf S.stdDev sample-                ]-            , bgroup "varianceWeighted"-                [ bench "C.F.Statistics"    $ nf (\vec -> F.fold (varianceWeighted m) (U.toList vec)) sampleW-                , bench "C.F.S(comp mean)"  $ nf (\vec -> F.fold (varianceWeighted (F.fold meanWeighted (U.toList vec))) (U.toList vec)) sampleW-                , bench "Statistics.Sample" $ nf S.varianceWeighted sampleW-                ]-            ]+    [ bgroup "Statistics of location"+      [ bgroup "mean"+        [ bench "C.F.Statistics"     $ nf (\vec -> F.fold mean (U.toList vec)) sample+        , bench "Statistics.Sample"  $ nf S.mean sample+        ]+      , bgroup "meanWeighted"+        [ bench "C.F.Statistics"     $ nf (\vec -> F.fold meanWeighted (U.toList vec)) sampleW+        , bench "Statistics.Sample"  $ nf S.meanWeighted sampleW+        ]+      , bgroup "welfordMean"+        [ bench "C.F.Statistics"     $ nf (\vec -> F.fold welfordMean (U.toList vec)) sample+        , bench "Statistics.Sample"  $ nf S.welfordMean sample+        ]+      , bgroup "harmonicMean"+        [ bench "C.F.Statistics"     $ nf (\vec -> F.fold harmonicMean (U.toList vec)) sample+        , bench "Statistics.Sample"  $ nf S.harmonicMean sample+        ]+      , bgroup "geometricMean"+        [ bench "C.F.Statistics"     $ nf (\vec -> F.fold geometricMean (U.toList vec)) absSample+        , bench "Statistics.Sample"  $ nf S.geometricMean absSample+        ]+      ]+    , bgroup "Single-pass functions"+      [ bgroup "fastVariance"+        [ bench "C.F.Statistics"     $ nf (\vec -> F.fold fastVariance (U.toList vec)) sample+        , bench "Statistics.Sample"  $ nf S.fastVariance sample+        ]+      , bgroup "fastVarianceUnbiased"+        [ bench "C.F.Statistics"     $ nf (\vec -> F.fold fastVarianceUnbiased (U.toList vec)) sample+        , bench "Statistics.Sample"  $ nf S.fastVarianceUnbiased sample+        ]+      , bgroup "fastStdDev"+        [ bench "C.F.Statistics"     $ nf (\vec -> F.fold fastStdDev (U.toList vec)) sample+        , bench "Statistics.Sample"  $ nf S.fastStdDev sample+        ]+      , bgroup "fastLMVSK"+                       -- T4 is strict in all arguments, so WHNF ok here+        [bench "C.F.Statistics"      $ whnf (\vec -> F.fold fastLMVSK (U.toList vec)) sample+        ]+      , bgroup "fastLinearReg"+        [bench "fastLinearReg"       $ whnf (\vec -> F.fold fastLinearReg (U.toList vec)) sample2+        ]+      ] -        , bgroup "Functions over central moments"-            [ bgroup "skewness"-                [ bench "C.F.Statistics"    $ nf (\vec -> F.fold (skewness m) (U.toList vec)) sample-                , bench "C.F.S(comp mean)"  $ nf (\vec -> F.fold (skewness (F.fold mean (U.toList vec))) (U.toList vec)) sample-                , bench "Statistics.Sample" $ nf S.skewness sample-                ]-            , bgroup "kurtosis"-                [ bench "C.F.Statistics"    $ nf (\vec -> F.fold (kurtosis m) (U.toList vec)) sample-                , bench "C.F.S(comp mean)"  $ nf (\vec -> F.fold (kurtosis (F.fold mean (U.toList vec))) (U.toList vec)) sample-                , bench "Statistics.Sample" $ nf S.kurtosis sample-                ]-            , bgroup "centralMoment 2"-                [ bench "C.F.Statistics"    $ nf (\vec -> F.fold (centralMoment 2 m) (U.toList vec)) sample-                , bench "C.F.S(comp mean)"  $ nf (\vec -> F.fold (centralMoment 2 (F.fold mean (U.toList vec))) (U.toList vec)) sample-                , bench "Statistics.Sample" $ nf (S.centralMoment 2) sample-                ]-            , bgroup "centralMoment 3"-                [ bench "C.F.Statistics"    $ nf (\vec -> F.fold (centralMoment 3 m) (U.toList vec)) sample-                , bench "C.F.S(comp mean)"  $ nf (\vec -> F.fold (centralMoment 3 (F.fold mean (U.toList vec))) (U.toList vec)) sample-                , bench "Statistics.Sample" $ nf (S.centralMoment 3) sample-                ]-            , bgroup "centralMoment 4"-                [ bench "C.F.Statistics"    $ nf (\vec -> F.fold (centralMoment 4 m) (U.toList vec)) sample-                , bench "C.F.S(comp mean)"  $ nf (\vec -> F.fold (centralMoment 4 (F.fold mean (U.toList vec))) (U.toList vec)) sample-                , bench "Statistics.Sample" $ nf (S.centralMoment 4) sample-                ]-            , bgroup "centralMoment 7"-                [ bench "C.F.Statistics"    $ nf (\vec -> F.fold (centralMoment 7 m) (U.toList vec)) sample-                , bench "C.F.S(comp mean)"  $ nf (\vec -> F.fold (centralMoment 7 (F.fold mean (U.toList vec))) (U.toList vec)) sample-                , bench "Statistics.Sample" $ nf (S.centralMoment 7) sample-                ]-            , bgroup "centralMoments 4 9"-                [ bench "C.F.Statistics"    $ nf (\vec -> F.fold (centralMoments 4 9 m) (U.toList vec)) sample-                , bench "C.F.S(comp mean)"  $ nf (\vec -> F.fold (centralMoments 4 9 (F.fold mean (U.toList vec))) (U.toList vec)) sample-                , bench "Statistics.Sample" $ nf (S.centralMoments 4 9) sample-                ]-            , bgroup "centralMoments' 4 9"-                [ bench "C.F.Statistics"    $ nf (\vec -> F.fold (centralMoments' 4 9 m) (U.toList vec)) sample-                , bench "C.F.S(comp mean)"  $ nf (\vec -> F.fold (centralMoments' 4 9 (F.fold mean (U.toList vec))) (U.toList vec)) sample-                ]-            ]+    , bgroup "Functions requiring the mean"+      [ bgroup "variance"+        [ bench "C.F.Statistics"     $ nf (\vec -> F.fold (variance m) (U.toList vec)) sample+        , bench "C.F.S(comp mean)"   $ nf (\vec -> F.fold (variance (F.fold mean (U.toList vec))) (U.toList vec)) sample+        , bench "Statistics.Sample"  $ nf S.variance sample         ]+      , bgroup "varianceUnbiased"+        [ bench "C.F.Statistics"     $ nf (\vec -> F.fold (varianceUnbiased m) (U.toList vec)) sample+        , bench "C.F.S(comp mean)"   $ nf (\vec -> F.fold (varianceUnbiased (F.fold mean (U.toList vec))) (U.toList vec)) sample+        , bench "Statistics.Sample"  $ nf S.varianceUnbiased sample+        ]+      , bgroup "stdDev"+        [ bench "C.F.Statistics"     $ nf (\vec -> F.fold (stdDev m) (U.toList vec)) sample+        , bench "C.F.S(comp mean)"   $ nf (\vec -> F.fold (stdDev (F.fold mean (U.toList vec))) (U.toList vec)) sample+        , bench "Statistics.Sample"  $ nf S.stdDev sample+        ]+      , bgroup "varianceWeighted"+        [ bench "C.F.Statistics"     $ nf (\vec -> F.fold (varianceWeighted m) (U.toList vec)) sampleW+        , bench "C.F.S(comp mean)"   $ nf (\vec -> F.fold (varianceWeighted (F.fold meanWeighted (U.toList vec))) (U.toList vec)) sampleW+        , bench "Statistics.Sample"  $ nf S.varianceWeighted sampleW+        ]+      ] +    , bgroup "Functions over central moments"+      [ bgroup "skewness"+        [ bench "C.F.Statistics"     $ nf (\vec -> F.fold (skewness m) (U.toList vec)) sample+        , bench "C.F.S(comp mean)"   $ nf (\vec -> F.fold (skewness (F.fold mean (U.toList vec))) (U.toList vec)) sample+        , bench "Statistics.Sample"  $ nf S.skewness sample+        ]+      , bgroup "kurtosis"+        [ bench "C.F.Statistics"     $ nf (\vec -> F.fold (kurtosis m) (U.toList vec)) sample+        , bench "C.F.S(comp mean)"   $ nf (\vec -> F.fold (kurtosis (F.fold mean (U.toList vec))) (U.toList vec)) sample+        , bench "Statistics.Sample"  $ nf S.kurtosis sample+        ]+      , bgroup "centralMoment 2"+        [ bench "C.F.Statistics"     $ nf (\vec -> F.fold (centralMoment 2 m) (U.toList vec)) sample+        , bench "C.F.S(comp mean)"   $ nf (\vec -> F.fold (centralMoment 2 (F.fold mean (U.toList vec))) (U.toList vec)) sample+        , bench "Statistics.Sample"  $ nf (S.centralMoment 2) sample+        ]+      , bgroup "centralMoment 3"+        [ bench "C.F.Statistics"     $ nf (\vec -> F.fold (centralMoment 3 m) (U.toList vec)) sample+        , bench "C.F.S(comp mean)"   $ nf (\vec -> F.fold (centralMoment 3 (F.fold mean (U.toList vec))) (U.toList vec)) sample+        , bench "Statistics.Sample"  $ nf (S.centralMoment 3) sample+        ]+      , bgroup "centralMoment 4"+        [ bench "C.F.Statistics"     $ nf (\vec -> F.fold (centralMoment 4 m) (U.toList vec)) sample+        , bench "C.F.S(comp mean)"   $ nf (\vec -> F.fold (centralMoment 4 (F.fold mean (U.toList vec))) (U.toList vec)) sample+        , bench "Statistics.Sample"  $ nf (S.centralMoment 4) sample+        ]+      , bgroup "centralMoment 7"+        [ bench "C.F.Statistics"     $ nf (\vec -> F.fold (centralMoment 7 m) (U.toList vec)) sample+        , bench "C.F.S(comp mean)"   $ nf (\vec -> F.fold (centralMoment 7 (F.fold mean (U.toList vec))) (U.toList vec)) sample+        , bench "Statistics.Sample"  $ nf (S.centralMoment 7) sample+        ]+      , bgroup "centralMoments 4 9"+        [ bench "C.F.Statistics"     $ nf (\vec -> F.fold (centralMoments 4 9 m) (U.toList vec)) sample+        , bench "C.F.S(comp mean)"   $ nf (\vec -> F.fold (centralMoments 4 9 (F.fold mean (U.toList vec))) (U.toList vec)) sample+        , bench "Statistics.Sample"  $ nf (S.centralMoments 4 9) sample+        ]+      , bgroup "centralMoments' 4 9"+        [ bench "C.F.Statistics"     $ nf (\vec -> F.fold (centralMoments' 4 9 m) (U.toList vec)) sample+        , bench "C.F.S(comp mean)"   $ nf (\vec -> F.fold (centralMoments' 4 9 (F.fold mean (U.toList vec))) (U.toList vec)) sample+        ]+      ]+    ]
foldl-statistics.cabal view
@@ -1,5 +1,5 @@ name:                foldl-statistics-version:             0.1.0.0+version:             0.1.1.0 synopsis:            Statistical functions from the statistics package implemented as                      Folds. description:         The use of this package allows statistics to be computed using at most two@@ -26,7 +26,7 @@   default-language:    Haskell2010   build-depends:       base >= 4.7 && < 5                        , foldl >= 1.1 && < 1.3-                       , math-functions >= 0.1 && < 0.2+                       , math-functions >= 0.1 && < 0.3                        , profunctors >= 5.2 && < 5.3  test-suite foldl-statistics-test
src/Control/Foldl/Statistics.hs view
@@ -44,8 +44,12 @@     , fastVariance     , fastVarianceUnbiased     , fastStdDev+    , fastLMVSK+    , Stats4(..)+    , fastLinearReg+    , LinRegResult(..) -    -- $correlation+     , correlation      -- * References@@ -349,9 +353,117 @@ fastStdDev = sqrt fastVariance  --- $correlation++-- | When returned by `fastLMVSK`, contains the count, mean,+--  variance, skewness and kurtosis of a series of samples. --+-- _Since: 0.1.1.0_+data Stats4  = Stats4+  { stats4Count    :: {-# UNPACK #-}!Int+  , stats4Mean     :: {-# UNPACK #-}!Double+  , stats4Variance :: {-# UNPACK #-}!Double+  , stats4Skewness :: {-# UNPACK #-}!Double+  , stats4Kurtosis :: {-# UNPACK #-}!Double+  } deriving (Show, Eq)++-- | Efficiently compute the+-- __length, mean, variance, skewness and kurtosis__ with a single pass. --+-- _Since: 0.1.1.0_+{-# INLINE fastLMVSK #-}+fastLMVSK :: Fold Double Stats4+fastLMVSK = finalStats4 <$> foldStats4+++{-# INLINE stats40 #-}+stats40 = Stats4 0 0 0 0 0++-- This performs the grunt work of the fastLMVSK function above.+-- Note: The Stats4 returned by this doesn't contain the actual statistics+-- you're likely after, you must apply `finalStats4' to compute those.+--+-- See details on John Cook's article in the references below for+-- details.+{-# INLINE foldStats4 #-}+foldStats4 :: Fold Double Stats4+foldStats4 = Fold stepStats4 stats40 id++{-# INLINE stepStats4 #-}+stepStats4 :: Stats4 -> Double -> Stats4+stepStats4 (Stats4 n1 m1 m2 m3 m4) x = Stats4 n' m1' m2' m3' m4' where+  n' = n1+1+  delta = x - m1+  delta_n = delta / fromIntegral n'+  delta_n2 = delta_n * delta_n+  term1 = delta * delta_n * fromIntegral n1+  m1' = m1 + delta_n+  m4' = m4 + term1 * delta_n2 * fromIntegral (n'*n' - 3*n' + 3) + 6 * delta_n2 * m2 - 4 * delta_n * m3+  m3' = m3 + term1 * delta_n  * fromIntegral (n' - 2)           - 3 * delta_n  * m2+  m2' = m2 + term1+finalStats4 :: Stats4 -> Stats4+finalStats4 (Stats4 n m1 m2 m3 m4) = Stats4 n m1 m2' m3' m4' where+  nd = fromIntegral n+  m2' = m2 / (nd-1)+  m3' = sqrt nd * m3 * (m2 ** (-1.5))+  m4' = nd*m4 / (m2*m2) - 3.0++-- | When returned by `fastLinearReg`, contains the count,+--   slope, intercept and correlation of combining @(x,y)@ pairs.+--+-- _Since: 0.1.1.0_+data LinRegResult = LinRegResult+  {lrrCount       :: {-# UNPACK #-}!Int+  ,lrrSlope       :: {-# UNPACK #-}!Double+  ,lrrIntercept   :: {-# UNPACK #-}!Double+  ,lrrCorrelation :: {-# UNPACK #-}!Double+  } deriving (Show, Eq)++-- | Computes the __count, slope, (Y) intercept and correlation__ of @(x,y)@+--   pairs.+--+-- >>> F.fold fastLinearReg $ map (\x -> (x,3*x+7)) [1..100]+-- LinRegResult {lrrCount = 100, lrrSlope = 3.0,+--               lrrIntercept = 7.0, lrrCorrelation = 1.0}+--+-- >>> F.fold fastLinearReg $ map (\x -> (x,0.005*x*x+3*x+7)) [1..100]+-- LinRegResult {+--    lrrCount = 100,+--    lrrSlope = 3.5049999999999994,+--    lrrIntercept = -1.5849999999999795,+--    lrrCorrelation = 0.9993226275740273}+--+-- _Since: 0.1.1.0_+{-# INLINE fastLinearReg #-}+fastLinearReg :: Fold (Double,Double) LinRegResult+fastLinearReg = Fold step (V2 0 (V 0 0) (V 0 0) 0) final where+  step (V2 n v1@(V xMean xVar) v2@(V yMean _) s_xy) (x,y) = V2 (n+1) v1' v2' s_xy' where+    nd = fromIntegral n+    nd1 = fromIntegral (n+1)+    s_xy' = s_xy + (xMean - x)*(yMean - y)*nd/nd1+    v1' = stepV v1 n x+    v2' = stepV v2 n y+  final (V2 n v1@(V xMean xVar) v2@(V yMean yVar)  s_xy) = LinRegResult n slope intercept correlation where+    ndm1 = fromIntegral (n-1)+    slope = s_xy / xVar+    intercept = yMean - slope*xMean+    t = sqrt (xVar/ndm1) * sqrt (yVar/ndm1); -- stddev x * stddev y+    correlation = s_xy / (ndm1 * t)++data V2 = V2 {-# UNPACK #-}!Int {-# UNPACK #-}!V {-# UNPACK #-}!V {-# UNPACK #-}!Double++{-# INLINE stepV #-}+stepV :: V -> Int -> Double -> V+stepV (V m1 m2) n1 x = V m1' m2' where+  delta = x - m1+  delta_n = delta / fromIntegral (n1+1)+  term1 = delta * delta_n * fromIntegral n1+  m1' = m1 + delta_n+  m2' = m2 + term1++++-- | Given the mean and standard deviation of two distributions, computes+--   the correlation between them. correlation :: (Double, Double) -> (Double, Double) -> Fold (Double,Double) Double correlation (m1,m2) (s1,s2) = Fold step (TS zero 0) final where     step  (TS s n) (x1,x2) = TS (add s $ ((x1-m1)/s1) * ((x2-m2)/s2)) (n+1)@@ -376,6 +488,9 @@ -- * West, D.H.D. (1979) Updating mean and variance estimates: an --   improved method. /Communications of the ACM/ --   22(9):532&#8211;535. <http://doi.acm.org/10.1145/359146.359153>+--+-- * John D. Cook. Computing skewness and kurtosis in one pass+--   <http://www.johndcook.com/blog/skewness_kurtosis/>