packages feed

ideas-statistics-1.0: src/Domain/Statistics/Data.hs

-----------------------------------------------------------------------------
-- Copyright 2020, Ideas project team. This file is distributed under the
-- terms of the Apache License 2.0. For more information, see the files
-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution.
-----------------------------------------------------------------------------
module Domain.Statistics.Data
   ( Data (..)
   , isSingleSample
   , sampleSize
   , sampleSum
   , sampleMean
   , sampleVariance
   ) where

import Ideas.Common.Rewriting
import Domain.Statistics.Symbols

-- | Data component
data Data
  = SingleSample [Double]               -- Single sample
  | TwoSample    [Double] [Double] Bool -- Two samples, either paired or not
  deriving (Eq, Show, Read)

instance IsTerm Data where
  toTerm (SingleSample xs)   = unary singleSampleSymbol (toTerm xs)
  toTerm (TwoSample xs ys b) =
     ternary twoSampleSymbol (toTerm xs) (toTerm ys) (toTermBool b)

  fromTerm (TCon s [x])
     | s == singleSampleSymbol = 
          SingleSample <$> fromTerm x
  fromTerm (TCon s [xs, ys, b]) 
     | s == twoSampleSymbol = 
          TwoSample <$> fromTerm xs <*> fromTerm ys <*> fromTermBool b
  fromTerm t = fail $ "Invalid term: " ++ show t ++ " not Data"
  
-- | Utility functions
isSingleSample :: Data -> Bool
isSingleSample (SingleSample _) = True
isSingleSample _                = False

-- |
sampleSize :: Data -> Int
sampleSize (SingleSample xs)     = length xs
sampleSize (TwoSample xs _ True) = length xs -- Both samples should have the same sample size
sampleSize _                     = error "two sample sizes for unpaired samples"

-- |
sampleSum :: Data -> [Double]
sampleSum (SingleSample xs)      = [sum xs]
sampleSum (TwoSample xs ys _)    = [sum xs, sum ys]

-- |
sampleMean :: Data -> [Double]
sampleMean (SingleSample xs)     = [ sum xs / fromIntegral (length xs) ]
sampleMean (TwoSample xs ys _)   = [ sum xs / fromIntegral (length xs)
                                   , sum ys / fromIntegral (length ys)
                                   ]

-- |
sampleVariance :: Bool -> Data -> [Double]
sampleVariance True  = sampleVarianceT
sampleVariance False = sampleVarianceZ

-- |
sampleVarianceZ :: Data -> [Double]
sampleVarianceZ (SingleSample xs) =
  let mean = head $ sampleMean (SingleSample xs)
  in  [foldr (\x r -> r + (x - mean) ** 2) 0 xs / fromIntegral (length xs)]
sampleVarianceZ (TwoSample xs ys _) =
  let (mean1:mean2:_) = sampleMean (TwoSample xs ys False)
  in  [ foldr (\x r -> r + (x - mean1) ** 2) 0 xs / fromIntegral (length xs)
      , foldr (\x r -> r + (x - mean2) ** 2) 0 ys / fromIntegral (length ys)
      ]

-- |
sampleVarianceT :: Data -> [Double]
sampleVarianceT (SingleSample xs)   =
  let mean = head $ sampleMean (SingleSample xs)
  in  [foldr (\x r -> r + (x - mean) ** 2) 0 xs / fromIntegral (length xs - 1)]
sampleVarianceT (TwoSample  xs ys _) =
  let (mean1:mean2:_) = sampleMean (TwoSample xs ys False)
  in  [ foldr (\x r -> r + (x - mean1) ** 2) 0 xs / fromIntegral (length xs - 1)
      , foldr (\x r -> r + (x - mean2) ** 2) 0 ys / fromIntegral (length ys - 1)
      ]