{-# LANGUAGE BangPatterns #-}
{- |

Basic statistics for lists.

-}

module Moo.GeneticAlgorithm.Statistics
  ( average
  , variance
  , quantiles
  , median
  , iqr
  ) where

import Data.List (sort, foldl')

-- |Average

average :: (Num a, Fractional a) => [a] -> a
average :: [a] -> a
average = (a -> a -> a) -> (a, a) -> a
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry a -> a -> a
forall a. Fractional a => a -> a -> a
(/) ((a, a) -> a) -> ([a] -> (a, a)) -> [a] -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((a, a) -> a -> (a, a)) -> (a, a) -> [a] -> (a, a)
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (\(!a
s, !a
c) a
x -> (a
sa -> a -> a
forall a. Num a => a -> a -> a
+a
x, a
ca -> a -> a
forall a. Num a => a -> a -> a
+a
1)) (a
0, a
0)

-- |Population variance (divided by n).

variance :: (Floating a) => [a] -> a
variance :: [a] -> a
variance [a]
xs = let (Int
n, a
_, a
q) = (a -> (Int, a, a) -> (Int, a, a))
-> (Int, a, a) -> [a] -> (Int, a, a)
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr a -> (Int, a, a) -> (Int, a, a)
forall a. Floating a => a -> (Int, a, a) -> (Int, a, a)
go (Int
0, a
0, a
0) [a]
xs
              in  a
q a -> a -> a
forall a. Fractional a => a -> a -> a
/ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
    where
    -- Algorithm by Chan et al.

    -- ftp://reports.stanford.edu/pub/cstr/reports/cs/tr/79/773/CS-TR-79-773.pdf

    go :: Floating a => a -> (Int, a, a) -> (Int, a, a)
    go :: a -> (Int, a, a) -> (Int, a, a)
go a
x (Int
n, a
sa, a
qa)
        | Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = (Int
1, a
x, a
0)
        | Bool
otherwise =
            let na :: a
na = Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
                delta :: a
delta = a
x a -> a -> a
forall a. Num a => a -> a -> a
- a
saa -> a -> a
forall a. Fractional a => a -> a -> a
/a
na
                sa' :: a
sa' = a
sa a -> a -> a
forall a. Num a => a -> a -> a
+ a
x
                qa' :: a
qa' = a
qa a -> a -> a
forall a. Num a => a -> a -> a
+ a
deltaa -> a -> a
forall a. Num a => a -> a -> a
*a
deltaa -> a -> a
forall a. Num a => a -> a -> a
*a
naa -> a -> a
forall a. Fractional a => a -> a -> a
/(a
naa -> a -> a
forall a. Num a => a -> a -> a
+a
1)
            in  (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1, a
sa', a
qa')


-- | Compute empirical qunatiles (using R type 7 continuous sample quantile).

quantiles :: (Real a, RealFrac a)
             => [a]  -- ^ samples

             -> [a]  -- ^ probabilities in the range (0, 1)

             -> [a]  -- ^ estimated quantiles' values

quantiles :: [a] -> [a] -> [a]
quantiles [a]
xs [a]
probs =
    let xs' :: [a]
xs' = [a] -> [a]
forall a. Ord a => [a] -> [a]
sort [a]
xs
        n :: Int
n = [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
xs'
    in  (a -> a) -> [a] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> [a] -> a -> a
forall a. (Real a, RealFrac a) => Int -> [a] -> a -> a
quantile7 Int
n [a]
xs') [a]
probs

-- | Estimate continuous quantile (like R's default type 7, SciPy (1,1), Excel).

quantile7 :: (Real a, RealFrac a)
             => Int       -- ^ @n@ the number of samples

             -> [a]       -- ^ @xs@ samples

             -> a         -- ^ @prob@ numeric probability (0, 1)

             -> a         -- ^ estimated quantile value

quantile7 :: Int -> [a] -> a -> a
quantile7 Int
n [a]
xs a
prob =
    let h :: a
h = Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) a -> a -> a
forall a. Num a => a -> a -> a
* a
prob a -> a -> a
forall a. Num a => a -> a -> a
+ a
1
        i :: Int
i = a -> Int
forall a b. (RealFrac a, Integral b) => a -> b
floor a
h
        x1 :: a
x1 = [a]
xs [a] -> Int -> a
forall a. [a] -> Int -> a
!! (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1)
        x2 :: a
x2 = [a]
xs [a] -> Int -> a
forall a. [a] -> Int -> a
!! (Int
i)
    in  case (Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
n, Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
1) of
          (Bool
True, Bool
_) -> [a]
xs [a] -> Int -> a
forall a. [a] -> Int -> a
!! (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) -- prob >= 1

          (Bool
_, Bool
True) -> [a]
xs [a] -> Int -> a
forall a. [a] -> Int -> a
!! Int
0     -- prob < 0

          (Bool, Bool)
_         -> a
x1 a -> a -> a
forall a. Num a => a -> a -> a
+ (a
h a -> a -> a
forall a. Num a => a -> a -> a
- Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
i)a -> a -> a
forall a. Num a => a -> a -> a
*(a
x2 a -> a -> a
forall a. Num a => a -> a -> a
-a
x1)


-- | Median

median :: (Real a, RealFrac a) => [a] -> a
median :: [a] -> a
median [a]
xs = [a] -> a
forall a. [a] -> a
head ([a] -> a) -> [a] -> a
forall a b. (a -> b) -> a -> b
$ [a] -> [a] -> [a]
forall a. (Real a, RealFrac a) => [a] -> [a] -> [a]
quantiles [a]
xs [a
0.5]


-- | Interquartile range.

iqr :: (Real a, RealFrac a) => [a] -> a
iqr :: [a] -> a
iqr [a]
xs =
    let [a
q1,a
q2] = [a] -> [a] -> [a]
forall a. (Real a, RealFrac a) => [a] -> [a] -> [a]
quantiles [a]
xs [a
0.25, a
0.75]
    in  a
q2 a -> a -> a
forall a. Num a => a -> a -> a
- a
q1