monoid-statistics 0.3 → 0.3.1
raw patch · 3 files changed
+97/−21 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- Data/Monoid/Statistics.hs +54/−10
- Data/Monoid/Statistics/Numeric.hs +36/−9
- monoid-statistics.cabal +7/−2
Data/Monoid/Statistics.hs view
@@ -9,13 +9,17 @@ -- Maintainer : Alexey Khudyakov <alexey.skladnoy@gmail.com> -- Stability : experimental -- -module Data.Monoid.Statistics ( StatMonoid(..)- , evalStatistic- -- * Statistic monoids- , TwoStats(..)- -- * Additional information- -- $info- ) where+module Data.Monoid.Statistics ( + -- * Type class+ StatMonoid(..)+ , evalStatistic+ -- ** Examples+ -- $examples+ -- * Generic monoid+ , TwoStats(..)+ -- * Additional information+ -- $info+ ) where import Data.Monoid@@ -32,6 +36,7 @@ -- -- Statistic could be calculated with fold over sample. Since -- accumulator is 'Monoid' such fold could be easily parralelized.+-- Check examples section for more information. -- -- Instance must satisfy following law: --@@ -92,9 +97,48 @@ -- This indeed proves that monoid could be constructed. Monoid above -- is completely impractical. It runs in O(n) space. However for some -- statistics monoids which runs in O(1) space could be--- implemented. For example mean. +-- implemented. Simple examples of such statistics are number of+-- elements in sample or mean of a sample. -- -- On the other hand some statistics could not be implemented in such -- way. For example calculation of median require O(n) space. Variance--- could be implemented in O(1) but such implementation won't be--- numerically stable. +-- could be implemented in O(1) but such implementation will have+-- problems with numberical stability.++++-- $examples+--+-- These examples show how to find maximum and minimum of a sample in+-- one pass over data.+-- +-- This is test data. It's not limited to list but could be anything+-- what could be folded.+--+-- > > let xs = [1..100] :: [Double]+-- +-- Now let calculate maximum of test sample using two methods. First+-- one is to use generic function 'evalStatistic' and another one is+-- fold.+--+-- > > evalStatistic xs :: Max+-- > Max {calcMax = 100.0}+-- > > foldl (flip pappend) mempty xs :: Max+-- > Max {calcMax = 100.0}+--+-- More complicated example allows to combine several monoids+-- together. It allows to calculate two statistics in one pass:+--+-- > > evalStatistic xs :: TwoStats Min Max+-- > TwoStats {calcStat1 = Min {calcMin = 1.0}, calcStat2 = Max {calcMax = 100.0}}+--+-- Last example shows how to calculate nuber of elements, mean and+-- variance at once:+--+-- > > let v = evalStatistic xs :: Variance+-- > > calcCount v+-- > 100+-- > > calcMean v+-- > 50.5+-- > > calcStddev v+-- > 28.86607004772212
Data/Monoid/Statistics/Numeric.hs view
@@ -12,6 +12,7 @@ , Variance(..) , asVariance -- ** Ad-hoc accessors+ -- $accessors , CalcCount(..) , CalcMean(..) , CalcVariance(..)@@ -22,10 +23,6 @@ , Min(..) ) 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 import Data.Typeable (Typeable)@@ -158,7 +155,10 @@ -- 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+ mappend !(Min x) !(Min y) + | isNaN x = Min y+ | isNaN y = Min x+ | otherwise = Min (min x y) {-# INLINE mempty #-} {-# INLINE mappend #-} @@ -166,9 +166,6 @@ 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 }@@ -176,7 +173,10 @@ instance Monoid Max where mempty = Max (0/0)- mappend !(Max x) !(Max y) = Max $ if x >= y then x else y+ mappend !(Max x) !(Max y) + | isNaN x = Max y+ | isNaN y = Max x+ | otherwise = Max (max x y) {-# INLINE mempty #-} {-# INLINE mappend #-} @@ -191,14 +191,41 @@ -- Ad-hoc type class ---------------------------------------------------------------- +-- $accessors+--+-- Monoids 'Count', 'Mean' and 'Variance' form some kind of tower.+-- Every successive monoid can calculate every statistics previous+-- monoids can. So to avoid replicating accessors for each statistics+-- a set of ad-hoc type classes was added. +--+-- This approach have deficiency. It becomes to infer type of monoidal+-- accumulator from accessor function so following expression will be+-- rejected:+-- +-- > calcCount $ evalStatistics xs+--+-- Indeed type of accumulator is:+--+-- > forall a . (StatMonoid a, CalcMean a) => a+--+-- Therefore it must be fixed by adding explicit type annotation. For+-- example:+--+-- > calcMean (evalStatistics xs :: Mean)++ ++-- | Statistics which could count number of elements in the sample class CalcCount m where -- | Number of elements in sample calcCount :: m -> Int +-- | Statistics which could estimate mean of sample class CalcMean m where -- | Calculate esimate of mean of a sample calcMean :: m -> Double +-- | Statistics which could estimate variance of sample class CalcVariance m where -- | Calculate biased estimate of variance calcVariance :: m -> Double
monoid-statistics.cabal view
@@ -1,5 +1,7 @@++ Name: monoid-statistics-Version: 0.3+Version: 0.3.1 Cabal-Version: >= 1.6 License: BSD3 License-File: LICENSE@@ -19,7 +21,10 @@ This packages is quite similar to monoids package but limited to calculation on statistics. In particular it makes use of commutatitvity of statistical monoids.-+ .+ Changes:+ .+ * 0.3.1 Better documentation; Fix in Min/Max monoids source-repository head type: hg