packages feed

integreat-0.2.2.1: src/Edge/Correlation.hs

{- Edge.Correlation
Gregory W. Schwartz

Collections the functions pertaining to the generation of edges in a similarity
matrix using different kinds of correlations as weights.
-}

{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE GADTs #-}

module Edge.Correlation
    ( getSimMatCorrelation
    , correlate
    ) where

-- Standard
import Control.Monad
import Data.Bool
import Data.List
import Data.Maybe
import qualified Data.Foldable as F
import qualified Data.IntMap.Strict as IMap
import qualified Data.Map.Strict as Map
import qualified Data.Sequence as Seq
import qualified Data.Set as Set

-- Cabal
import Control.Monad.Trans
import Data.Graph.Inductive
import Statistics.Correlation
import Statistics.Distribution
import Statistics.Distribution.StudentT
import qualified Control.Foldl as Fold
import qualified Control.Lens as L
import qualified Data.Vector.Unboxed as VU
import qualified Numeric.LinearAlgebra as N

-- Local
import Types
import Utility

getSimMatCorrelation :: EdgeMethod -> StandardLevel -> EdgeSimMatrix
getSimMatCorrelation edgeMethod (StandardLevel level) = do
    EdgeSimMatrix
        . Fold.fold (Fold.Fold step begin extract)
        . pairs (,)
        . fmap (L.over L._2 F.toList)
        . Map.toList
        $ level
  where
      n = fromIntegral . Map.size $ level
      step acc x =
        case uncurry getCorr x of
            ((_, _), Nothing) -> acc
            ((!idx1, !idx2), (Just !val)) ->
                alterMap idx1 idx2 val
                    . alterMap idx2 idx1 val
                    $ acc
      begin      = IMap.empty
      extract    = id
      alterMap new query val =
            IMap.alter ( maybe (Just . IMap.singleton new $ val)
                               (Just . IMap.insert new val)
                       )
                        query
      getCorr ((!id1, !idx1), !x) ((!id2, !idx2), !y) =
            ((idx1, idx2), correlateEntities edgeMethod x y)

-- | Correlate two groups of entities, where each group is a collection of
-- measurements (specifically for a single type of entity, for instance
-- a single protein).
correlateEntities :: EdgeMethod
                  -> [Maybe Entity]
                  -> [Maybe Entity]
                  -> Maybe Double
correlateEntities edgeMethod e1 e2 = do
    let joined = VU.fromList . catMaybes . zipWith groupDataSets e1 $ e2

    guard $ (VU.length joined > 2)
         && (not . VU.all (== (fst . VU.head $ joined)) . VU.map fst $ joined)
         && (not . VU.all (== (snd . VU.head $ joined)) . VU.map snd $ joined)

    let (Rho !coeff, P !pVal) = correlate edgeMethod joined

    guard $ pVal < 0.05

    return coeff

-- | Correlate two lists with p values.
correlate :: EdgeMethod -> VU.Vector (Double, Double) -> (Rho, P)
correlate method xs =
    (Rho (coeff method), P (pVal s))
  where
    n     = fromIntegral . VU.length $ xs
    coeff SpearmanCorrelation = spearman xs
    coeff PearsonCorrelation  = pearson xs
    s     = coeff method * ((sqrt (n - 2)) / (1 - (coeff method ^ 2)))
    pVal stat = 2 * (complCumulative (studentT (fromIntegral $ VU.length xs - 2)) . abs $ stat)