packages feed

monoid-statistics 0.1 → 0.2

raw patch · 3 files changed

+287/−99 lines, 3 files

Files

Data/Monoid/Statistics.hs view
@@ -11,20 +11,17 @@ module Data.Monoid.Statistics ( StatMonoid(..)                               , evalStatistic                                 -- * Statistic monoids-                              , Count(..)-                              , Mean(..)+                              , TwoStats(..)                                 -- * Additional information                                 -- $info                               ) where  -import Data.Int     (Int8, Int16, Int32, Int64)-import Data.Word    (Word8,Word16,Word32,Word64,Word) import Data.Monoid import qualified Data.Foldable as F -import GHC.Float (float2Double) + -- | Monoid which corresponds to some stattics. In order to do so it --   must be commutative. In many cases it's not practical to --   construct monoids for each element so 'papennd' was added.@@ -38,6 +35,9 @@ -- --   > pappend x (pappend y mempty) == pappend x mempty `mappend` pappend y mempty --   > mappend x y == mappend y x+--+--   It is very similar to Reducer type class from monoids package but+--   require commutative monoids class Monoid m => StatMonoid m a where   -- | Add one element to monoid accumulator. P stands for point in   --   analogy for Pointed.@@ -47,106 +47,15 @@ --   foldl'. evalStatistic :: (F.Foldable d, StatMonoid m a) => d a -> m evalStatistic = F.foldl' (flip pappend) mempty---------------------------------------------------------------------- Data types--------------------------------------------------------------------- | Simplest statistics. Number of elements in the sample-newtype Count a = Count { calcCount :: a }-                  deriving Show--instance Integral a => Monoid (Count a) where-  mempty = Count 0-  (Count i) `mappend` (Count j) = Count (i + j)-  {-# INLINE mempty  #-}-  {-# INLINE mappend #-}   -instance (Integral a) => StatMonoid (Count a) b where-  pappend _ !(Count n) = Count (n + 1)-  {-# INLINE pappend #-}-  -  -  --- | Mean of sample. Samples of Double,Float and bui;t-in integral---   types are supported------ Numeric stability of 'mappend' is not proven.-data Mean = Mean { calcMean      :: Double -- ^ Current mean-                 , calcCountMean :: Int    -- ^ Number of entries-                 }-            deriving Show -instance Monoid Mean where-  mempty = Mean 0 0-  mappend !(Mean x n) !(Mean y k) = Mean ((x*n' + y*k') / (n' + k')) (n + k)-    where-      n' = fromIntegral n-      k' = fromIntegral k-  {-# INLINE mempty  #-}-  {-# INLINE mappend #-}---- Add one sample elemnt to Mean-addValueToMean :: (a -> Double) -> a -> Mean -> Mean-addValueToMean f !x !(Mean m n) = Mean (m + (f x - m) / fromIntegral n') n' where n' = n+1-{-# INLINE addValueToMean #-}---- Floating point-instance StatMonoid Mean Double where-  pappend = addValueToMean id-  {-# INLINE pappend #-}-instance StatMonoid Mean Float where-  pappend = addValueToMean float2Double-  {-# INLINE pappend #-}---- Basic integrals-instance StatMonoid Mean Integer where-  pappend = addValueToMean fromIntegral-  {-# INLINE pappend #-}-instance StatMonoid Mean Int where-  pappend = addValueToMean fromIntegral-  {-# INLINE pappend #-}-instance StatMonoid Mean Word where-  pappend = addValueToMean fromIntegral-  {-# INLINE pappend #-}---- Fixed size ints-instance StatMonoid Mean Int8 where-  pappend = addValueToMean fromIntegral-  {-# INLINE pappend #-}-instance StatMonoid Mean Int16 where-  pappend = addValueToMean fromIntegral-  {-# INLINE pappend #-}-instance StatMonoid Mean Int32 where-  pappend = addValueToMean fromIntegral-  {-# INLINE pappend #-}-instance StatMonoid Mean Int64 where-  pappend = addValueToMean fromIntegral-  {-# INLINE pappend #-}---- Fixed size Words-instance StatMonoid Mean Word8 where-  pappend = addValueToMean fromIntegral-  {-# INLINE pappend #-}-instance StatMonoid Mean Word16 where-  pappend = addValueToMean fromIntegral-  {-# INLINE pappend #-}-instance StatMonoid Mean Word32 where-  pappend = addValueToMean fromIntegral-  {-# INLINE pappend #-}-instance StatMonoid Mean Word64 where-  pappend = addValueToMean fromIntegral-  {-# INLINE pappend #-}-- ---------------------------------------------------------------- -- Generic monoids ----------------------------------------------------------------  -- | Monoid which allows to calculate two statistics in parralel-data TwoStats a b = TwoStats { calcStat1 :: a-                             , calcStat2 :: b+data TwoStats a b = TwoStats { calcStat1 :: !a+                             , calcStat2 :: !b                              }  instance (Monoid a, Monoid b) => Monoid (TwoStats a b) where
+ Data/Monoid/Statistics/Numeric.hs view
@@ -0,0 +1,278 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+module Data.Monoid.Statistics.Numeric ( +    -- * Mean and variance+    Count(..)+  , asCount+  , Mean(..)+  , asMean+  , Variance(..)+  , asVariance+    -- ** Ad-hoc accessors+  , CalcCount(..)+  , CalcMean(..)+  , CalcVariance(..)+  , calcStddev+  , calcStddevUnbiased+    -- * Maximum and minimum+  , Max(..)+  , Min(..)+    -- * Conversion to Double+  , ConvertibleToDouble(..)+  ) where++import Data.Int     (Int8, Int16, Int32, Int64)+import Data.Word    (Word8,Word16,Word32,Word64,Word)+import GHC.Float    (float2Double)++import Data.Monoid+import Data.Monoid.Statistics+++----------------------------------------------------------------+-- Statistical monoids+----------------------------------------------------------------++-- | Simplest statistics. Number of elements in the sample+newtype Count a = Count { calcCountI :: a }+                  deriving Show++-- | Fix type of monoid+asCount :: Count a -> Count a+asCount = id+{-# INLINE asCount #-}++instance Integral a => Monoid (Count a) where+  mempty = Count 0+  (Count i) `mappend` (Count j) = Count (i + j)+  {-# INLINE mempty  #-}+  {-# INLINE mappend #-}+  +instance (Integral a) => StatMonoid (Count a) b where+  pappend _ !(Count n) = Count (n + 1)+  {-# INLINE pappend #-}++instance CalcCount (Count Int) where+  calcCount = calcCountI+  {-# INLINE calcCount #-}+++++-- | Mean of sample. Samples of Double,Float and bui;t-in integral+--   types are supported+--+-- Numeric stability of 'mappend' is not proven.+data Mean = Mean {-# UNPACK #-} !Int    -- Number of entries+                 {-# UNPACK #-} !Double -- Current mean+            deriving Show++-- | Fix type of monoid+asMean :: Mean -> Mean+asMean = id+{-# INLINE asMean #-}++instance Monoid Mean where+  mempty = Mean 0 0+  mappend !(Mean n x) !(Mean k y) = Mean (n + k) ((x*n' + y*k') / (n' + k')) +    where+      n' = fromIntegral n+      k' = fromIntegral k+  {-# INLINE mempty  #-}+  {-# INLINE mappend #-}++instance ConvertibleToDouble a => StatMonoid Mean a where+  pappend !x !(Mean n m) = Mean n' (m + (toDouble x - m) / fromIntegral n') where n' = n+1+  {-# INLINE pappend #-}++instance CalcCount Mean where+  calcCount (Mean n _) = n+  {-# INLINE calcCount #-}+instance CalcMean Mean where+  calcMean (Mean _ m) = m+  {-# INLINE calcMean #-}+++++-- | Intermediate quantities to calculate the standard deviation.+data Variance = Variance {-# UNPACK #-} !Int    --  Number of elements in the sample+                         {-# UNPACK #-} !Double -- Current sum of elements of sample+                         {-# UNPACK #-} !Double -- Current sum of squares of deviations from current mean+                deriving Show++-- | Fix type of monoid+asVariance :: Variance -> Variance+asVariance = id+{-# INLINE asVariance #-}++-- | Using parallel algorithm from:+-- +-- Chan, Tony F.; Golub, Gene H.; LeVeque, Randall J. (1979),+-- Updating Formulae and a Pairwise Algorithm for Computing Sample+-- Variances., Technical Report STAN-CS-79-773, Department of+-- Computer Science, Stanford University. Page 4.+-- +-- <ftp://reports.stanford.edu/pub/cstr/reports/cs/tr/79/773/CS-TR-79-773.pdf>+--+instance Monoid Variance where+  mempty = Variance 0 0 0+  mappend !(Variance n1 ta sa) !(Variance n2 tb sb) = Variance (n1+n2) (ta+tb) sumsq+    where+      na = fromIntegral n1+      nb = fromIntegral n2+      nom = sqr (ta * nb - tb * na)+      sumsq+        | n1 == 0 || n2 == 0 = sa + sb  -- because either sa or sb should be 0+        | otherwise          = sa + sb + nom / ((na + nb) * na * nb)+  {-# INLINE mempty #-}+  {-# INLINE mappend #-}++instance ConvertibleToDouble a => StatMonoid Variance a where+  -- Can be implemented directly as in Welford-Knuth algorithm.+  pappend !x !s = s `mappend` (Variance 1 (toDouble x) 0)+  {-# INLINE pappend #-}++instance CalcCount Variance where+  calcCount (Variance n _ _) = n+  {-# INLINE calcCount #-}+instance CalcMean Variance where+  calcMean (Variance n t _) = t / fromIntegral n+  {-# INLINE calcMean #-}+instance CalcVariance Variance where+  calcVariance (Variance n _ s) = s / fromIntegral n+  calcVarianceUnbiased (Variance n _ s) = s / fromIntegral (n-1)+  {-# INLINE calcVariance         #-}+  {-# INLINE calcVarianceUnbiased #-}++++++-- | Calculate minimum of sample. For empty sample returns NaN. Any+-- NaN encountedred will be ignored. +newtype Min = Min { calcMin :: Double }+              deriving Show++-- N.B. forall (x :: Double) (x <= NaN) == False+instance Monoid Min where+  mempty = Min (0/0)+  mappend !(Min x) !(Min y) = Min $ if x <= y then x else y+  {-# INLINE mempty  #-}+  {-# INLINE mappend #-}  ++instance StatMonoid Min Double where+  pappend !x m = mappend (Min x) m+  {-# INLINE pappend #-}+++++-- | Calculate maximum of sample. For empty sample returns NaN. Any+-- NaN encountedred will be ignored. +newtype Max = Max { calcMax :: Double }+              deriving Show++instance Monoid Max where+  mempty = Max (0/0)+  mappend !(Max x) !(Max y) = Max $ if x >= y then x else y+  {-# INLINE mempty  #-}+  {-# INLINE mappend #-}  ++instance StatMonoid Max Double where+  pappend !x m = mappend (Max x) m+  {-# INLINE pappend #-}+++++----------------------------------------------------------------+-- Ad-hoc type class+----------------------------------------------------------------+  +class CalcCount m where+  -- | Number of elements in sample+  calcCount :: m -> Int++class CalcMean m where+  -- | Calculate esimate of mean of a sample+  calcMean :: m -> Double+  +class CalcVariance m where+  -- | Calculate biased estimate of variance+  calcVariance         :: m -> Double+  -- | Calculate unbiased estimate of the variance, where the+  --   denominator is $n-1$.+  calcVarianceUnbiased :: m -> Double++-- | Calculate sample standard deviation (biased estimator, $s$, where+--   the denominator is $n-1$).+calcStddev :: CalcVariance m => m -> Double+calcStddev = sqrt . calcVariance+{-# INLINE calcStddev #-}++-- | Calculate standard deviation of the sample+-- (unbiased estimator, $\sigma$, where the denominator is $n$).+calcStddevUnbiased :: CalcVariance m => m -> Double+calcStddevUnbiased = sqrt . calcVarianceUnbiased+{-# INLINE calcStddevUnbiased #-}++++----------------------------------------------------------------+-- Conversion to Double+----------------------------------------------------------------++-- | Data type which could be convered to Double+class ConvertibleToDouble a where+  toDouble :: a -> Double+  +-- Floating point+instance ConvertibleToDouble Double where+  toDouble = id+  {-# INLINE toDouble #-}+instance ConvertibleToDouble Float where+  toDouble = float2Double+  {-# INLINE toDouble #-}+-- Basic integral types+instance ConvertibleToDouble Integer where+  toDouble = fromIntegral+  {-# INLINE toDouble #-}+instance ConvertibleToDouble Int where+  toDouble = fromIntegral+  {-# INLINE toDouble #-}+instance ConvertibleToDouble Word where+  toDouble = fromIntegral+  {-# INLINE toDouble #-}+-- Integral types with fixed size+instance ConvertibleToDouble Int8 where+  toDouble = fromIntegral+  {-# INLINE toDouble #-}+instance ConvertibleToDouble Int16 where+  toDouble = fromIntegral+  {-# INLINE toDouble #-}+instance ConvertibleToDouble Int32 where+  toDouble = fromIntegral+  {-# INLINE toDouble #-}+instance ConvertibleToDouble Int64 where+  toDouble = fromIntegral+  {-# INLINE toDouble #-}+instance ConvertibleToDouble Word8 where+  toDouble = fromIntegral+  {-# INLINE toDouble #-}+instance ConvertibleToDouble Word16 where+  toDouble = fromIntegral+  {-# INLINE toDouble #-}+instance ConvertibleToDouble Word32 where+  toDouble = fromIntegral+  {-# INLINE toDouble #-}+instance ConvertibleToDouble Word64 where+  toDouble = fromIntegral+  {-# INLINE toDouble #-}++ +sqr :: Double -> Double+sqr x = x * x+{-# INLINE sqr #-}
monoid-statistics.cabal view
@@ -1,5 +1,5 @@ Name:           monoid-statistics-Version:        0.1+Version:        0.2 Cabal-Version:  >= 1.6 License:        BSD3 License-File:   LICENSE@@ -23,3 +23,4 @@ Library   Build-Depends:   base >=3 && <5   Exposed-modules: Data.Monoid.Statistics+                   Data.Monoid.Statistics.Numeric