module Statistics.Test.MannWhitneyU (
mannWhitneyUtest
, mannWhitneyU
, mannWhitneyUCriticalValue
, mannWhitneyUSignificant
, wilcoxonRankSums
, module Statistics.Test.Types
) where
import Data.List (findIndex)
import Data.Ord (comparing)
import Numeric.SpecFunctions (choose)
import Prelude hiding (sum)
import Statistics.Distribution (quantile)
import Statistics.Distribution.Normal (standard)
import Statistics.Function (sortBy)
import Statistics.Sample.Internal (sum)
import Statistics.Test.Internal (rank, splitByTags)
import Statistics.Test.Types (TestResult(..), PositionTest(..), significant)
import Statistics.Types (PValue,pValue)
import qualified Data.Vector.Unboxed as U
wilcoxonRankSums :: (Ord a, U.Unbox a) => U.Vector a -> U.Vector a -> (Double, Double)
wilcoxonRankSums :: forall a.
(Ord a, Unbox a) =>
Vector a -> Vector a -> (Double, Double)
wilcoxonRankSums Vector a
xs1 Vector a
xs2 = (Vector Double -> Double
forall (v :: * -> *). Vector v Double => v Double -> Double
sum Vector Double
ranks1, Vector Double -> Double
forall (v :: * -> *). Vector v Double => v Double -> Double
sum Vector Double
ranks2)
where
(Vector Double
ranks1,Vector Double
ranks2) = Vector (Bool, Double) -> (Vector Double, Vector Double)
forall (v :: * -> *) a.
(Vector v a, Vector v (Bool, a)) =>
v (Bool, a) -> (v a, v a)
splitByTags (Vector (Bool, Double) -> (Vector Double, Vector Double))
-> Vector (Bool, Double) -> (Vector Double, Vector Double)
forall a b. (a -> b) -> a -> b
$ Vector Bool -> Vector Double -> Vector (Bool, Double)
forall a b.
(Unbox a, Unbox b) =>
Vector a -> Vector b -> Vector (a, b)
U.zip Vector Bool
tags ((a -> a -> Bool) -> Vector a -> Vector Double
forall (v :: * -> *) a.
(Vector v a, Vector v Double) =>
(a -> a -> Bool) -> v a -> v Double
rank a -> a -> Bool
forall a. Eq a => a -> a -> Bool
(==) Vector a
joinSample)
(Vector Bool
tags,Vector a
joinSample) = Vector (Bool, a) -> (Vector Bool, Vector a)
forall a b.
(Unbox a, Unbox b) =>
Vector (a, b) -> (Vector a, Vector b)
U.unzip
(Vector (Bool, a) -> (Vector Bool, Vector a))
-> Vector (Bool, a) -> (Vector Bool, Vector a)
forall a b. (a -> b) -> a -> b
$ Comparison (Bool, a) -> Vector (Bool, a) -> Vector (Bool, a)
forall (v :: * -> *) e. Vector v e => Comparison e -> v e -> v e
sortBy (((Bool, a) -> a) -> Comparison (Bool, a)
forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing (Bool, a) -> a
forall a b. (a, b) -> b
snd)
(Vector (Bool, a) -> Vector (Bool, a))
-> Vector (Bool, a) -> Vector (Bool, a)
forall a b. (a -> b) -> a -> b
$ Bool -> Vector a -> Vector (Bool, a)
forall {b} {a}.
(Unbox b, Unbox a) =>
a -> Vector b -> Vector (a, b)
tagSample Bool
True Vector a
xs1 Vector (Bool, a) -> Vector (Bool, a) -> Vector (Bool, a)
forall a. Unbox a => Vector a -> Vector a -> Vector a
U.++ Bool -> Vector a -> Vector (Bool, a)
forall {b} {a}.
(Unbox b, Unbox a) =>
a -> Vector b -> Vector (a, b)
tagSample Bool
False Vector a
xs2
tagSample :: a -> Vector b -> Vector (a, b)
tagSample a
t = (b -> (a, b)) -> Vector b -> Vector (a, b)
forall a b. (Unbox a, Unbox b) => (a -> b) -> Vector a -> Vector b
U.map (\b
x -> (a
t,b
x))
mannWhitneyU :: (Ord a, U.Unbox a) => U.Vector a -> U.Vector a -> (Double, Double)
mannWhitneyU :: forall a.
(Ord a, Unbox a) =>
Vector a -> Vector a -> (Double, Double)
mannWhitneyU Vector a
xs1 Vector a
xs2
= ((Double, Double) -> Double
forall a b. (a, b) -> a
fst (Double, Double)
summedRanks Double -> Double -> Double
forall a. Num a => a -> a -> a
- (Double
n1Double -> Double -> Double
forall a. Num a => a -> a -> a
*(Double
n1 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
1))Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/Double
2
,(Double, Double) -> Double
forall a b. (a, b) -> b
snd (Double, Double)
summedRanks Double -> Double -> Double
forall a. Num a => a -> a -> a
- (Double
n2Double -> Double -> Double
forall a. Num a => a -> a -> a
*(Double
n2 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
1))Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/Double
2)
where
n1 :: Double
n1 = Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Double) -> Int -> Double
forall a b. (a -> b) -> a -> b
$ Vector a -> Int
forall a. Unbox a => Vector a -> Int
U.length Vector a
xs1
n2 :: Double
n2 = Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Double) -> Int -> Double
forall a b. (a -> b) -> a -> b
$ Vector a -> Int
forall a. Unbox a => Vector a -> Int
U.length Vector a
xs2
summedRanks :: (Double, Double)
summedRanks = Vector a -> Vector a -> (Double, Double)
forall a.
(Ord a, Unbox a) =>
Vector a -> Vector a -> (Double, Double)
wilcoxonRankSums Vector a
xs1 Vector a
xs2
mannWhitneyUCriticalValue
:: (Int, Int)
-> PValue Double
-> Maybe Int
mannWhitneyUCriticalValue :: (Int, Int) -> PValue Double -> Maybe Int
mannWhitneyUCriticalValue (Int
m, Int
n) PValue Double
p
| Int
m Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
1 Bool -> Bool -> Bool
|| Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
1 = Maybe Int
forall a. Maybe a
Nothing
| Double
p' Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
<= Double
1 = Maybe Int
forall a. Maybe a
Nothing
| Bool
otherwise = (Double -> Bool) -> [Double] -> Maybe Int
forall a. (a -> Bool) -> [a] -> Maybe Int
findIndex (Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
>= Double
p')
([Double] -> Maybe Int) -> [Double] -> Maybe Int
forall a b. (a -> b) -> a -> b
$ Int -> [Double] -> [Double]
forall a. Int -> [a] -> [a]
take (Int
mInt -> Int -> Int
forall a. Num a => a -> a -> a
*Int
n)
([Double] -> [Double]) -> [Double] -> [Double]
forall a b. (a -> b) -> a -> b
$ [Double] -> [Double]
forall a. HasCallStack => [a] -> [a]
tail
([Double] -> [Double]) -> [Double] -> [Double]
forall a b. (a -> b) -> a -> b
$ [[[Double]]]
alookup [[[Double]]] -> Int -> [[Double]]
forall a. HasCallStack => [a] -> Int -> a
!! (Int
mInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
2) [[Double]] -> Int -> [Double]
forall a. HasCallStack => [a] -> Int -> a
!! (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
m Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
where
mnCn :: Double
mnCn = (Int
mInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
n) Int -> Int -> Double
`choose` Int
n
p' :: Double
p' = Double
mnCn Double -> Double -> Double
forall a. Num a => a -> a -> a
* PValue Double -> Double
forall a. PValue a -> a
pValue PValue Double
p
alookup :: [[[Double]]]
alookup :: [[[Double]]]
alookup = Int -> [[Double]] -> [[[Double]]]
gen Int
2 [Double
1 Double -> [Double] -> [Double]
forall a. a -> [a] -> [a]
: Double -> [Double]
forall a. a -> [a]
repeat Double
2]
where
gen :: Int -> [[Double]] -> [[[Double]]]
gen Int
bigN [[Double]]
predBigNList
= let bigNlist :: [[Double]]
bigNlist = [ [ Int -> Int -> Double
amemoed Int
u Int
m
| Int
u <- [Int
0 .. Int
mInt -> Int -> Int
forall a. Num a => a -> a -> a
*(Int
bigNInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
m)]
] [Double] -> [Double] -> [Double]
forall a. [a] -> [a] -> [a]
++ Double -> [Double]
forall a. a -> [a]
repeat (Int
bigN Int -> Int -> Double
`choose` Int
m)
| Int
m <- [Int
1 .. (Int
bigNInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1)]]
in [[Double]]
bigNlist [[Double]] -> [[[Double]]] -> [[[Double]]]
forall a. a -> [a] -> [a]
: Int -> [[Double]] -> [[[Double]]]
gen (Int
bigNInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) [[Double]]
bigNlist
where
amemoed :: Int -> Int -> Double
amemoed :: Int -> Int -> Double
amemoed Int
u Int
m
| Int
m Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 Bool -> Bool -> Bool
|| Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 = Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
u Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
| Bool
otherwise = [Double]
mList [Double] -> Int -> Double
forall a. HasCallStack => [a] -> Int -> a
!! Int
u
Double -> Double -> Double
forall a. Num a => a -> a -> a
+ if Int
u Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
n then Double
0 else [Double]
predmList [Double] -> Int -> Double
forall a. HasCallStack => [a] -> Int -> a
!! (Int
uInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
n)
where
n :: Int
n = Int
bigN Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
m
([Double]
predmList : [Double]
mList : [[Double]]
_) = Int -> [[Double]] -> [[Double]]
forall a. Int -> [a] -> [a]
drop (Int
mInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
2) [[Double]]
predBigNList
mannWhitneyUSignificant
:: PositionTest
-> (Int, Int)
-> PValue Double
-> (Double, Double)
-> Maybe TestResult
mannWhitneyUSignificant :: PositionTest
-> (Int, Int)
-> PValue Double
-> (Double, Double)
-> Maybe TestResult
mannWhitneyUSignificant PositionTest
test (Int
in1, Int
in2) PValue Double
pVal (Double
u1, Double
u2)
| Int
in1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
20 Bool -> Bool -> Bool
|| Int
in2 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
20 =
let mean :: Double
mean = Double
n1 Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
n2 Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
2
sigma :: Double
sigma = Double -> Double
forall a. Floating a => a -> a
sqrt (Double -> Double) -> Double -> Double
forall a b. (a -> b) -> a -> b
$ Double
n1Double -> Double -> Double
forall a. Num a => a -> a -> a
*Double
n2Double -> Double -> Double
forall a. Num a => a -> a -> a
*(Double
n1 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
n2 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
1) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
12
z :: Double
z = (Double
mean Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
u1) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
sigma
in TestResult -> Maybe TestResult
forall a. a -> Maybe a
Just (TestResult -> Maybe TestResult) -> TestResult -> Maybe TestResult
forall a b. (a -> b) -> a -> b
$ case PositionTest
test of
PositionTest
AGreater -> Bool -> TestResult
significant (Bool -> TestResult) -> Bool -> TestResult
forall a b. (a -> b) -> a -> b
$ Double
z Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
< NormalDistribution -> Double -> Double
forall d. ContDistr d => d -> Double -> Double
quantile NormalDistribution
standard Double
p
PositionTest
BGreater -> Bool -> TestResult
significant (Bool -> TestResult) -> Bool -> TestResult
forall a b. (a -> b) -> a -> b
$ (-Double
z) Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
< NormalDistribution -> Double -> Double
forall d. ContDistr d => d -> Double -> Double
quantile NormalDistribution
standard Double
p
PositionTest
SamplesDiffer -> Bool -> TestResult
significant (Bool -> TestResult) -> Bool -> TestResult
forall a b. (a -> b) -> a -> b
$ Double -> Double
forall a. Num a => a -> a
abs Double
z Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double -> Double
forall a. Num a => a -> a
abs (NormalDistribution -> Double -> Double
forall d. ContDistr d => d -> Double -> Double
quantile NormalDistribution
standard (Double
pDouble -> Double -> Double
forall a. Fractional a => a -> a -> a
/Double
2))
| Bool
otherwise = do Double
crit <- Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Double) -> Maybe Int -> Maybe Double
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Int, Int) -> PValue Double -> Maybe Int
mannWhitneyUCriticalValue (Int
in1, Int
in2) PValue Double
pVal
TestResult -> Maybe TestResult
forall a. a -> Maybe a
forall (m :: * -> *) a. Monad m => a -> m a
return (TestResult -> Maybe TestResult) -> TestResult -> Maybe TestResult
forall a b. (a -> b) -> a -> b
$ case PositionTest
test of
PositionTest
AGreater -> Bool -> TestResult
significant (Bool -> TestResult) -> Bool -> TestResult
forall a b. (a -> b) -> a -> b
$ Double
u2 Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
<= Double
crit
PositionTest
BGreater -> Bool -> TestResult
significant (Bool -> TestResult) -> Bool -> TestResult
forall a b. (a -> b) -> a -> b
$ Double
u1 Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
<= Double
crit
PositionTest
SamplesDiffer -> Bool -> TestResult
significant (Bool -> TestResult) -> Bool -> TestResult
forall a b. (a -> b) -> a -> b
$ Double -> Double -> Double
forall a. Ord a => a -> a -> a
min Double
u1 Double
u2 Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
<= Double
crit
where
n1 :: Double
n1 = Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
in1
n2 :: Double
n2 = Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
in2
p :: Double
p = PValue Double -> Double
forall a. PValue a -> a
pValue PValue Double
pVal
mannWhitneyUtest
:: (Ord a, U.Unbox a)
=> PositionTest
-> PValue Double
-> U.Vector a
-> U.Vector a
-> Maybe TestResult
mannWhitneyUtest :: forall a.
(Ord a, Unbox a) =>
PositionTest
-> PValue Double -> Vector a -> Vector a -> Maybe TestResult
mannWhitneyUtest PositionTest
ontTail PValue Double
p Vector a
smp1 Vector a
smp2 =
PositionTest
-> (Int, Int)
-> PValue Double
-> (Double, Double)
-> Maybe TestResult
mannWhitneyUSignificant PositionTest
ontTail (Int
n1,Int
n2) PValue Double
p ((Double, Double) -> Maybe TestResult)
-> (Double, Double) -> Maybe TestResult
forall a b. (a -> b) -> a -> b
$ Vector a -> Vector a -> (Double, Double)
forall a.
(Ord a, Unbox a) =>
Vector a -> Vector a -> (Double, Double)
mannWhitneyU Vector a
smp1 Vector a
smp2
where
n1 :: Int
n1 = Vector a -> Int
forall a. Unbox a => Vector a -> Int
U.length Vector a
smp1
n2 :: Int
n2 = Vector a -> Int
forall a. Unbox a => Vector a -> Int
U.length Vector a
smp2