module Factory.Math.Statistics(
getMean,
getVariance,
getStandardDeviation,
getAverageAbsoluteDeviation,
getCoefficientOfVariance,
nCr,
nPr
) where
import Control.Arrow((***))
import Control.Parallel(par, pseq)
import qualified Data.Foldable
import qualified Data.List
import qualified Data.Ratio
import qualified Factory.Math.Factorial as Math.Factorial
import qualified Factory.Math.Implementations.Factorial as Math.Implementations.Factorial
import qualified Factory.Math.Power as Math.Power
getMean :: (Data.Foldable.Foldable f, Real r, Fractional result) => f r -> result
getMean x
| denominator == 0 = error "Factory.Math.Statistics.getMean:\tno data => undefined result."
| otherwise = realToFrac numerator / fromIntegral denominator
where
(numerator, denominator) = Data.Foldable.foldr (\s -> (+ s) *** succ) (0, 0 :: Int) x
getDispersionFromMean :: (
Data.Foldable.Foldable f,
Fractional result,
Functor f,
Real r
) => (Data.Ratio.Rational -> Data.Ratio.Rational) -> f r -> result
getDispersionFromMean weight x = getMean $ fmap (weight . (+ negate mean) . toRational) x where
mean :: Data.Ratio.Rational
mean = getMean x
getVariance :: (
Data.Foldable.Foldable f,
Fractional variance,
Functor f,
Real r
) => f r -> variance
getVariance = getDispersionFromMean Math.Power.square
getStandardDeviation :: (
Data.Foldable.Foldable f,
Floating result,
Functor f,
Real r
) => f r -> result
getStandardDeviation = sqrt . getVariance
getAverageAbsoluteDeviation :: (
Data.Foldable.Foldable f,
Fractional result,
Functor f,
Real r
) => f r -> result
getAverageAbsoluteDeviation = getDispersionFromMean abs
getCoefficientOfVariance :: (
Data.Foldable.Foldable f,
Eq result,
Floating result,
Functor f,
Real r
) => f r -> result
getCoefficientOfVariance l
| mean == 0 = error "Factory.Math.Statistics.getCoefficientOfVariance:\tundefined if mean is zero."
| otherwise = getStandardDeviation l / abs mean
where
mean = getMean l
nCr :: (Math.Factorial.Algorithmic factorialAlgorithm, Integral i, Show i)
=> factorialAlgorithm
-> i
-> i
-> i
nCr _ 0 _ = 1
nCr _ _ 0 = 1
nCr factorialAlgorithm n r
| n < 0 = error $ "Factory.Math.Statistics.nCr:\tinvalid n; " ++ show n
| r < 0 = error $ "Factory.Math.Statistics.nCr:\tinvalid r; " ++ show r
| n < r = 0
| otherwise = numerator `par` (denominator `pseq` numerator `div` denominator)
where
[smaller, bigger] = Data.List.sort [r, n r]
numerator = Math.Implementations.Factorial.risingFactorial (succ bigger) (n bigger)
denominator = Math.Factorial.factorial factorialAlgorithm smaller
nPr :: (Integral i, Show i)
=> i
-> i
-> i
nPr 0 _ = 1
nPr _ 0 = 1
nPr n r
| n < 0 = error $ "Factory.Math.Statistics.nPr:\tinvalid n; " ++ show n
| r < 0 = error $ "Factory.Math.Statistics.nPr:\tinvalid r; " ++ show r
| n < r = 0
| otherwise = Math.Implementations.Factorial.fallingFactorial n r