module Data.Monoid.Statistics.Numeric (
Count(..)
, asCount
, Mean(..)
, asMean
, Variance(..)
, asVariance
, CalcCount(..)
, CalcMean(..)
, CalcVariance(..)
, calcStddev
, calcStddevUnbiased
, Max(..)
, Min(..)
, 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
newtype Count a = Count { calcCountI :: a }
deriving Show
asCount :: Count a -> Count a
asCount = id
instance Integral a => Monoid (Count a) where
mempty = Count 0
(Count i) `mappend` (Count j) = Count (i + j)
instance (Integral a) => StatMonoid (Count a) b where
pappend _ !(Count n) = Count (n + 1)
instance CalcCount (Count Int) where
calcCount = calcCountI
data Mean = Mean !Int
!Double
deriving Show
asMean :: Mean -> Mean
asMean = id
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
instance ConvertibleToDouble a => StatMonoid Mean a where
pappend !x !(Mean n m) = Mean n' (m + (toDouble x m) / fromIntegral n') where n' = n+1
instance CalcCount Mean where
calcCount (Mean n _) = n
instance CalcMean Mean where
calcMean (Mean _ m) = m
data Variance = Variance !Int
!Double
!Double
deriving Show
asVariance :: Variance -> Variance
asVariance = id
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
| otherwise = sa + sb + nom / ((na + nb) * na * nb)
instance ConvertibleToDouble a => StatMonoid Variance a where
pappend !x !s = s `mappend` (Variance 1 (toDouble x) 0)
instance CalcCount Variance where
calcCount (Variance n _ _) = n
instance CalcMean Variance where
calcMean (Variance n t _) = t / fromIntegral n
instance CalcVariance Variance where
calcVariance (Variance n _ s) = s / fromIntegral n
calcVarianceUnbiased (Variance n _ s) = s / fromIntegral (n1)
newtype Min = Min { calcMin :: Double }
deriving Show
instance Monoid Min where
mempty = Min (0/0)
mappend !(Min x) !(Min y) = Min $ if x <= y then x else y
instance StatMonoid Min Double where
pappend !x m = mappend (Min x) m
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
instance StatMonoid Max Double where
pappend !x m = mappend (Max x) m
class CalcCount m where
calcCount :: m -> Int
class CalcMean m where
calcMean :: m -> Double
class CalcVariance m where
calcVariance :: m -> Double
calcVarianceUnbiased :: m -> Double
calcStddev :: CalcVariance m => m -> Double
calcStddev = sqrt . calcVariance
calcStddevUnbiased :: CalcVariance m => m -> Double
calcStddevUnbiased = sqrt . calcVarianceUnbiased
class ConvertibleToDouble a where
toDouble :: a -> Double
instance ConvertibleToDouble Double where
toDouble = id
instance ConvertibleToDouble Float where
toDouble = float2Double
instance ConvertibleToDouble Integer where
toDouble = fromIntegral
instance ConvertibleToDouble Int where
toDouble = fromIntegral
instance ConvertibleToDouble Word where
toDouble = fromIntegral
instance ConvertibleToDouble Int8 where
toDouble = fromIntegral
instance ConvertibleToDouble Int16 where
toDouble = fromIntegral
instance ConvertibleToDouble Int32 where
toDouble = fromIntegral
instance ConvertibleToDouble Int64 where
toDouble = fromIntegral
instance ConvertibleToDouble Word8 where
toDouble = fromIntegral
instance ConvertibleToDouble Word16 where
toDouble = fromIntegral
instance ConvertibleToDouble Word32 where
toDouble = fromIntegral
instance ConvertibleToDouble Word64 where
toDouble = fromIntegral
sqr :: Double -> Double
sqr x = x * x