------------------------------------------------------------------------
-- |
-- Module      :  Math.Statistics
-- Copyright   :  (c) Johan Tibell 2008
-- License     :  BSD3-style (see LICENSE)
--
-- Maintainer  :  me@willsewell.com
-- Stability   :  experimental
-- Portability :  portable
--
-- Common statistical functions.
--
------------------------------------------------------------------------

module Math.Statistics
    ( mean
    , median
    , stddev
    , variance
    ) where

import Data.List (sort)

-- | Numerically stable mean.
mean :: Floating a => [a] -> a
mean :: forall a. Floating a => [a] -> a
mean = forall a. Floating a => a -> Int -> [a] -> a
go a
0 Int
0
    where
      go :: Floating a => a -> Int -> [a] -> a
      go :: forall a. Floating a => a -> Int -> [a] -> a
go a
m Int
_ []     = a
m
      go a
m Int
n (a
x:[a]
xs) = forall a. Floating a => a -> Int -> [a] -> a
go (a
m forall a. Num a => a -> a -> a
+ (a
x forall a. Num a => a -> a -> a
- a
m) forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
n forall a. Num a => a -> a -> a
+ Int
1)) (Int
n forall a. Num a => a -> a -> a
+ Int
1) [a]
xs

-- | Median.
median :: (Floating a, Ord a) => [a] -> a
median :: forall a. (Floating a, Ord a) => [a] -> a
median [a]
xs
    | forall a. Integral a => a -> Bool
odd Int
n     = forall a. [a] -> a
head forall a b. (a -> b) -> a -> b
$ forall a. Int -> [a] -> [a]
drop (Int
n forall a. Integral a => a -> a -> a
`div` Int
2) [a]
xs'
    | Bool
otherwise = forall a. Floating a => [a] -> a
mean forall a b. (a -> b) -> a -> b
$ forall a. Int -> [a] -> [a]
take Int
2 forall a b. (a -> b) -> a -> b
$ forall a. Int -> [a] -> [a]
drop Int
i [a]
xs'
    where
      i :: Int
i   = (forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
xs' forall a. Integral a => a -> a -> a
`div` Int
2) forall a. Num a => a -> a -> a
- Int
1
      xs' :: [a]
xs' = forall a. Ord a => [a] -> [a]
sort [a]
xs
      n :: Int
n   = forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
xs

-- | Standard deviation.
stddev :: Floating a => [a] -> a
stddev :: forall a. Floating a => [a] -> a
stddev [a]
xs = forall a. Floating a => a -> a
sqrt forall a b. (a -> b) -> a -> b
$ forall a. Floating a => [a] -> a
variance [a]
xs

-- | Numerically stable sample variance.
variance :: Floating a => [a] -> a
variance :: forall a. Floating a => [a] -> a
variance [a]
xs = forall a. Floating a => a -> Int -> a -> [a] -> a
go a
0 Int
0 a
0 [a]
xs forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
xs forall a. Num a => a -> a -> a
- Int
1)
    where
      go :: Floating a => a -> Int -> a -> [a] -> a
      go :: forall a. Floating a => a -> Int -> a -> [a] -> a
go a
_ Int
_ a
s [] = a
s
      go a
m Int
n a
s (a
x:[a]
xs') = forall a. Floating a => a -> Int -> a -> [a] -> a
go a
nm (Int
n forall a. Num a => a -> a -> a
+ Int
1) (a
s forall a. Num a => a -> a -> a
+ a
delta forall a. Num a => a -> a -> a
* (a
x forall a. Num a => a -> a -> a
- a
nm)) [a]
xs'
         where
           delta :: a
delta = a
x forall a. Num a => a -> a -> a
- a
m
           nm :: a
nm = a
m forall a. Num a => a -> a -> a
+ a
delta forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
n forall a. Num a => a -> a -> a
+ Int
1)