packages feed

diversity 0.6.0.2 → 0.6.2.0

raw patch · 4 files changed

+222/−70 lines, 4 filesdep +data-ordlistPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: data-ordlist

API changes (from Hackage documentation)

+ Math.Diversity.Diversity: chao1 :: Ord a => Map a Int -> Double
+ Math.Diversity.Diversity: chao2 :: (Ord a, Ord b) => Map (a, b) Int -> Double
+ Math.Diversity.Diversity: individualG :: Double -> Map (Sample, Fragment) Int -> Double
+ Math.Diversity.Diversity: minRarefaction :: Bool -> Bool -> Int -> Map (Sample, Fragment) Int -> Double -> Int -> IO Int
+ Math.Diversity.Diversity: richness :: (Ord a, Ord b) => Map (a, b) c -> Int
+ Math.Diversity.Diversity: sampleG :: Double -> Map (Sample, Fragment) Int -> Double
- Math.Diversity.Diversity: diversity :: Ord b => Double -> [b] -> Double
+ Math.Diversity.Diversity: diversity :: Ord a => Double -> [a] -> Double
- Math.Diversity.Diversity: diversityOfMap :: Double -> Map (Sample, Fragment) Int -> Double
+ Math.Diversity.Diversity: diversityOfMap :: Ord a => Double -> Map a Int -> Double
- Math.Diversity.Diversity: rarefactionCurve :: Bool -> Int -> Integer -> Integer -> Map (Sample, Fragment) Int -> IO [(Int, (Double, Double))]
+ Math.Diversity.Diversity: rarefactionCurve :: Bool -> Int -> Integer -> Integer -> Integer -> Map (Sample, Fragment) Int -> IO [(Int, (Double, Double))]
- Math.Diversity.Diversity: rarefactionSampleCurve :: Bool -> Int -> Int -> Map (Sample, Fragment) Int -> IO [(Int, (Double, Double))]
+ Math.Diversity.Diversity: rarefactionSampleCurve :: Bool -> Int -> Int -> Int -> Map (Sample, Fragment) Int -> IO [(Int, (Double, Double))]
- Math.Diversity.Print: printRarefaction :: Bool -> Bool -> Int -> Int -> Int -> Label -> Window -> PositionMap -> IO String
+ Math.Diversity.Print: printRarefaction :: Bool -> Bool -> Int -> Int -> Int -> Int -> Double -> Label -> Window -> PositionMap -> IO String
- Math.Diversity.Print: printRarefactionCurve :: Bool -> Bool -> Bool -> Int -> Int -> Int -> Label -> Window -> PositionMap -> IO String
+ Math.Diversity.Print: printRarefactionCurve :: Bool -> Bool -> Bool -> Int -> Int -> Int -> Int -> Label -> Window -> PositionMap -> IO String

Files

diversity.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/  name:                diversity-version:             0.6.0.2+version:             0.6.2.0 synopsis:            Return the diversity at each position for all sequences in a fasta file description:         Find the diversity of a collection of entities, mainly for use with fasta sequences. Produces a binary which works on fasta files to find the diversity of any order and rarefaction curves for a sliding window across all positions in the sequences. To analyze just a collection of entities, just use the whole sequences and list flag. homepage:            https://github.com/GregorySchwartz/diversity@@ -20,7 +20,7 @@   hs-source-dirs:      src/src-lib   exposed-modules:     Math.Diversity.Types, Math.Diversity.Diversity, Math.Diversity.GenerateDiversity, Math.Diversity.Print, Math.Diversity.Statistics, Math.Diversity.RandomSampling   -- other-modules:-  build-depends:       base >=4.6 && <4.9, containers >=0.5 && <0.6, split >=0.2 && <0.3, parsec >=3.1 && <4.0, fasta >=0.6.1 && <0.7, math-functions >=0.1 && <0.2, scientific >= 0.3 && < 0.4, random-shuffle >=0.0 && < 0.1, MonadRandom >=0.3 && <0.4+  build-depends:       base >=4.6 && <4.9, containers >=0.5 && <0.6, split >=0.2 && <0.3, parsec >=3.1 && <4.0, fasta >=0.6.1 && <0.7, math-functions >=0.1 && <0.2, scientific >= 0.3 && < 0.4, random-shuffle >=0.0 && < 0.1, MonadRandom >=0.3 && <0.4, data-ordlist >= 0.4 && < 0.5  executable diversity   ghc-options: -O2
src/src-exec/Main.hs view
@@ -5,11 +5,9 @@ window length (to split into fragments) by position. -} -{-# LANGUAGE BangPatterns #-}- -- Built-in import Data.List-import Control.Monad (forever)+import Control.Monad (forever, unless) import qualified Data.Map.Strict as Map import qualified System.IO as IO @@ -31,6 +29,7 @@                        , inputFasta             :: String                        , inputSampleField       :: Int                        , inputSubsampling       :: String+                       , inputG                 :: Double                        , fastBin                :: Bool                        , runs                   :: Int                        , removeNBool            :: Bool@@ -82,13 +81,25 @@       <*> strOption           ( long "input-subsampling"          <> short 'I'-         <> metavar "INT INT"+         <> metavar "INT INT (INT)"          <> value "1 1"-         <> help "The start point and interval of subsamples in the\-                 \ rarefaction curve. For instance, '1 1' would be 1, 2, 3, ...\-                 \ '2 6' would be 2, 8, 14, ... Note: input is a string so\-                 \ use quotations around the entry and it always has the\-                 \ number of subsamples overall as the last point" )+         <> help "The start point, interval, and optional endpoint of\+                 \ subsamples in the rarefaction curve.\+                 \ For instance, '1 1 4' would be 1, 2, 3, 4\+                 \ '2 6 14' would be 2, 8, 14, ... Note: input is a string so\+                 \ use quotations around the entry and it always includes the\+                 \ number of subsamples overall in the result. Excluding the\+                 \ endpoint results in the number of samples the endpoint, so\+                 \ '1 1' would be 1, 2, 3, ..., N " )+      <*> option auto+          ( long "input-g"+         <> short 'g'+         <> metavar "Double"+         <> value 0.95+         <> help "Used for calculating the number of individuals\+                 \ (or samples) needed before the proportion g of the total\+                 \ number of estimated species is reached.\+                 \ Sobs / Sest < g < 1" )       <*> switch           ( long "fast-bin"          <> short 'f'@@ -159,6 +170,12 @@          <> help "The csv file containing the diversities at each position.\                  \ expects a string, so you need a string wven with std" ) +parseSampling :: (Num a, Read a) => String -> [a]+parseSampling = map read . parsing . words+  where+    parsing [x, y] = [x, y, "0"]+    parsing x      = x+ pipesPositionMap :: Options -> IO PositionMap pipesPositionMap opts = do     h <- if null . inputFasta $ opts@@ -188,33 +205,31 @@         window       = inputWindow opts         nFlag        = removeNBool opts         whole        = wholeSeq opts-        start        = read . head . words . inputSubsampling $ opts-        interval     = read . last . words . inputSubsampling $ opts+        [start, interval, end] = parseSampling . inputSubsampling $ opts         howToOutput x = if std opts then putStrLn else writeFile x      positionMap <- pipesPositionMap opts -    if (null . output $ opts)-        then return ()-        else howToOutput (output opts)-           . printDiversity label order window-           $ positionMap-    if (null . outputRarefaction $ opts)-        then return ()-        else do+    unless (null . output $ opts)+         $ howToOutput (output opts)+         . printDiversity label order window+         $ positionMap+    unless (null . outputRarefaction $ opts)+         $ do             s <- printRarefaction                  (sample opts)                  (fastBin opts)                  (runs opts)                  start                  interval+                 end+                 (inputG opts)                  label                  window                  positionMap             howToOutput (outputRarefaction opts) s-    if (null . outputRarefactionCurve $ opts)-        then return ()-        else do+    unless (null . outputRarefactionCurve $ opts)+         $ do             s <- printRarefactionCurve                  (rarefactionDF opts)                  (sample opts)@@ -222,6 +237,7 @@                  (runs opts)                  start                  interval+                 end                  label                  window                  positionMap
src/src-lib/Math/Diversity/Diversity.hs view
@@ -7,19 +7,27 @@ {-# LANGUAGE BangPatterns #-}  module Math.Diversity.Diversity ( hamming+                                , richness                                 , diversity                                 , diversityOfMap+                                , chao1+                                , chao2                                 , rarefactionCurve                                 , rarefactionSampleCurve-                                , rarefactionViable ) where+                                , rarefactionViable+                                , individualG+                                , sampleG+                                , minRarefaction ) where  -- Built-in import Data.List import qualified Data.Set as Set import qualified Data.Map.Strict as Map import Numeric.SpecFunctions (choose)-import Data.Function (on) +-- Cabal+import qualified Data.List.Ordered as LO+ -- Local import Math.Diversity.RandomSampling import Math.Diversity.Types@@ -39,7 +47,7 @@     | otherwise = (fromInteger x / fromInteger y) * productDivision acc xs ys  -- | Returns the diversity of a list of things-diversity :: (Ord b) => Double -> [b] -> Double+diversity :: (Ord a) => Double -> [a] -> Double diversity order sample     | null sample        = 0     | order == 1         = exp . h . speciesList $ sample@@ -57,8 +65,9 @@                    ((Map.foldl' (+) 0 . speciesList $ sample) :: Double)     speciesList  = Map.fromListWith (+) . map (\x -> (x, 1)) --- | Returns the diversity of a map of things-diversityOfMap :: Double -> Map.Map (Sample, Fragment) Int -> Double+-- | Returns the diversity of a map of the species and how many times it+-- appears+diversityOfMap :: (Ord a) => Double -> Map.Map a Int -> Double diversityOfMap order sample     | Map.null sample    = 0     | order == 1         = exp . h $ sample@@ -70,11 +79,50 @@     pow          = 1 / (1 - order)     h            = negate                  . Map.foldl' (+) 0-                 . Map.map ( \x -> p_i (fromIntegral x)-                           * log (p_i (fromIntegral x)))-    p_i x        = (fromIntegral x :: Double) /-                   (fromIntegral (Map.foldl' (+) 0 sample) :: Double)+                 . Map.map ( \x -> p_i x * log (p_i x))+    p_i x        = fromIntegral x / fromIntegral (Map.foldl' (+) 0 sample) +-- | Returns the richness of the observed data+richness :: (Ord a, Ord b) => Map.Map (a, b) c -> Int+richness = Map.size . Map.mapKeys snd++-- | Returns the map of species with how many samples they appear in+overlapSampleMap :: (Ord a, Ord b) => Map.Map (a, b) Int -> Map.Map b Int+overlapSampleMap = Map.mapKeysWith (+) snd . Map.map (const 1)++-- | Returns the number of a that appear x times+abundanceFreq :: (Ord a) => Int -> Map.Map a Int -> Int+abundanceFreq x = Map.size . Map.filter (== x)++-- | Returns the number of b that appear in x number of a+overlapFreq :: (Ord a, Ord b) => Int -> Map.Map (a, b) Int -> Int+overlapFreq x = Map.size . Map.filter (== x) . overlapSampleMap++-- | Returns the chao1 estimator of a map of the species and how many times+-- it appears+chao1 :: (Ord a) => Map.Map a Int -> Double+chao1 sample+    | f2 > 0    = (f1 ** 2) / (2 * f2)+    | otherwise = (f1 * (f1 - 1)) / (2 * (f2 + 1))+  where+    f1  = fromIntegral . abundanceFreq 1 $ sample+    f2  = fromIntegral . abundanceFreq 2 $ sample++-- | Returns the chao2 estimator of a map of the sample labeled species+-- (sample, species) and how many times it appears. This will calculate the+-- overlap for you, so if you don't have the number of times it appears it+-- does not matter, you can set it to 1 and get the same result as it's all+-- about overlapping samples.+chao2 :: (Ord a, Ord b) => Map.Map (a, b) Int -> Double+chao2 samples+    | q2 > 0    = ((t - 1) / t) * ((q1 ** 2) / (2 * q2))+    | otherwise = ((t - 1) / t) * ((q1 * (q1 - 1)) / (2 * (q2 + 1)))+  where+    q1  = fromIntegral . overlapFreq 1 $ samples+    q2  = fromIntegral . overlapFreq 2 $ samples+    -- Saves time so don't have to recalculate+    t   = fromIntegral . Map.size . Map.mapKeys fst $ samples+ -- | Binomial for small or large numbers (slow but works for big numbers, -- fast but works for small numbers) specialBinomial :: Bool -> Integer -> Integer -> Integer -> Double@@ -91,25 +139,29 @@                  -> Int                  -> Integer                  -> Integer+                 -> Integer                  -> Map.Map (Sample, Fragment) Int                  -> IO [(Int, (Double, Double))]-rarefactionCurve !fastBin !runs !start !interval !xs =-        mapM rarefact $ [start,(start + interval)..(n_total - 1)] ++ [n_total]+rarefactionCurve !fastBin !runs !start !interval !end !sample =+        mapM rarefact+      . LO.nubSort+      $ n_total : [start,(start + interval)..finish]   where     rarefact !n         | n == 0       = return (fromIntegral n, (0, 0))         | n == 1       = return (fromIntegral n, (1, 0))         | n == n_total = return (fromIntegral n, (k, 0))+        | n > n_total  = return (fromIntegral n, (estimation n, 0))         | runs == 0    = return (fromIntegral n, (k - inner n, 0))-        | otherwise    = do+        | otherwise    = do  -- Empirical version             statTuple <- subsampleES                          runs                          (fromIntegral n_total)                          (fromIntegral n)                        . concatMap snd                        . Map.toAscList-                       . Map.mapWithKey (\(s, f) x -> replicate x f)-                       $ xs+                       . Map.mapWithKey (\(_, f) x -> replicate x f)+                       $ sample             return (fromIntegral n, statTuple)     inner n = ( \x -> if fastBin                         then x / choose (fromIntegral n_total) (fromIntegral n)@@ -117,9 +169,12 @@             . sum             . map (\g -> specialBinomial fastBin n_total (fromIntegral g) n)             $ grouped-    n_total = fromIntegral . Map.foldl' (+) 0 $ xs-    k       = fromIntegral . Map.size $ xs-    grouped = Map.elems xs+    -- Unreadable unless I break the 80 column rule+    estimation n = fromIntegral n_total + (chao1 sample * (1 - exp (((fromIntegral n - fromIntegral n_total) / (- fromIntegral n_total)) * (fromIntegral (abundanceFreq 1 sample) / chao1 sample))))+    finish       = if end == 0 then n_total else end+    n_total      = fromIntegral . Map.foldl' (+) 0 $ sample+    k            = fromIntegral . Map.size $ sample+    grouped      = Map.elems sample  -- | Each sample has a collection of species, return a list of these maps getSampleContents :: Map.Map (Sample, Fragment) Int -> [Set.Set Fragment]@@ -132,30 +187,37 @@ rarefactionSampleCurve :: Bool                        -> Int                        -> Int+                       -> Int                        -> Map.Map (Sample, Fragment) Int                        -> IO [(Int, (Double, Double))]-rarefactionSampleCurve !fastBin !start !interval !ls =-    mapM rarefact $ [start,(start + interval)..(t_total - 1)] ++ [t_total]+rarefactionSampleCurve !fastBin !start !interval !end !ls =+    mapM rarefact+  . LO.nubSort+  $ t_total : [start,(start + interval)..finish]   where     rarefact !t         | t == 0       = return (t, (0, 0))-        | t == t_total = return (t, (richness, 0))-        | otherwise    = return (t, (richness - inner t, 0))-    inner t     = ( \x -> if fastBin-                            then x / choose t_total t-                            else x )-                . sum-                . map ( \s -> specialBinomial-                              fastBin-                              (fromIntegral t_total)-                              (numHave s samples)-                              (fromIntegral t) )-                $ speciesList-    numHave s   = genericLength . filter (Set.member s)-    richness    = genericLength speciesList-    speciesList = Map.keys . Map.mapKeys snd $ ls-    t_total     = genericLength samples-    samples     = getSampleContents ls+        | t == t_total = return (t, (sobs, 0))+        | t > t_total  = return (t, (estimation t, 0))+        | otherwise    = return (t, (sobs - inner t, 0))+    inner t      = ( \x -> if fastBin+                             then x / choose t_total t+                             else x )+                 . sum+                 . map ( \s -> specialBinomial+                               fastBin+                               (fromIntegral t_total)+                               (numHave s samples)+                               (fromIntegral t) )+                 $ speciesList+    -- Unreadable unless I break the 80 column rule+    estimation t = sobs + (chao2 ls * (1 - exp ((- (fromIntegral t - fromIntegral t_total) * fromIntegral (overlapFreq 1 ls)) / (fromIntegral (overlapFreq 1 ls) + (fromIntegral t_total * chao2 ls)))))+    finish       = if end == 0 then t_total else end+    numHave s    = genericLength . filter (Set.member s)+    sobs         = fromIntegral $ richness ls+    speciesList  = Map.keys . Map.mapKeys snd $ ls+    t_total      = genericLength samples+    samples      = getSampleContents ls  -- | Calculates the percent of the curve that is above 95% of height of the -- curve@@ -163,3 +225,54 @@ rarefactionViable !xs = (genericLength valid / genericLength xs) * 100   where     valid = dropWhile (< (0.95 * last xs)) xs++-- | Returns the number of individuals needed to get the proportion g of+-- the estimated total richness of the assemblage. Sobs / Sest < g < 1+individualG :: Double -> Map.Map (Sample, Fragment) Int -> Double+individualG g sample = ((sobs * f1) / (2 * f2)) * log (f0 / ((1 - g) * sest))+  where+    sest = sobs + f0+    sobs = fromIntegral $ richness sample+    f2   = fromIntegral . abundanceFreq 2 $ sample+    f1   = fromIntegral . abundanceFreq 1 $ sample+    f0   = chao1 sample++-- | Returns the number of samples needed to get the proportion g of+-- the estimated total richness of the assemblage. Sobs / Sest < g < 1+sampleG :: Double -> Map.Map (Sample, Fragment) Int -> Double+sampleG g sample = log (1 - ((t / (t - 1)) * ((2 * q2) / (q1 ** 2)) * ((g * sest) - sobs)))+                 / log (1 - ((2 * q2) / (((t - 1) * q1) + (2 * q2))))+  where+    t    = fromIntegral . Map.size . Map.mapKeys fst $ sample+    sest = sobs + q0+    sobs = fromIntegral $ richness sample+    q2   = fromIntegral . overlapFreq 2 $ sample+    q1   = fromIntegral . overlapFreq 1 $ sample+    q0   = chao2 sample++-- | Returns the number of samples needed before a new sample returns less+-- than x new species. Warning, goes forever until threshold is met!+minRarefaction :: Bool+               -> Bool+               -> Int+               -> Map.Map (Sample, Fragment) Int+               -> Double+               -> Int+               -> IO Int+minRarefaction _ _ (-1) _ _ _ = return (-1)+minRarefaction bySample fastBin threshold sample !oldRare !count = do+    newRare <- fmap (fst . snd . head)+             . rarefaction bySample count+             $ sample+    if newRare - oldRare < fromIntegral threshold+        then return count+        else minRarefaction True fastBin threshold sample newRare (count + 1)+  where+    rarefaction True x  = rarefactionSampleCurve fastBin x 1 x+    rarefaction False x = rarefactionCurve+                          fastBin+                          0+                          (fromIntegral x)+                          1+                          (fromIntegral x)+
src/src-lib/Math/Diversity/Print.hs view
@@ -45,28 +45,46 @@                  -> Int                  -> Int                  -> Int+                 -> Int+                 -> Double                  -> Label                  -> Window                  -> PositionMap                  -> IO String printRarefaction-    sample fastBin runs start interval label window positionMap = do+    bySample fastBin runs start interval end g label window positionMap = do     body <- fmap unlines . mapM mapLine . Map.toAscList $ positionMap     return (header ++ body)   where-    header           = "label,window,position,weight,percent_above\n"+    header           = "label,window,position,weight,percent_above,\+                       \additional_sampling,g_proportion,richness,S_est\n"     mapLine (p, xs)  = fmap (intercalate ",") . line p $ xs     line p xs        = do-        curve <- getRarefactionCurve sample xs+        curve   <- getRarefactionCurve bySample xs+        -- The minimum number of samples needed before any additional+        -- sampling returns less than the threshold (min) number of species         return [ label                , show window                , show p                , show . Map.foldl' (+) 0 $ xs                , show . rarefactionViable . map (snd . snd) $ curve+               , show . additionalSampling bySample $ xs+               , show g+               , show . sobs $ xs+               , show . sest bySample $ xs                ]-    getRarefactionCurve True = rarefactionSampleCurve fastBin start interval+    sest True xs  = sobs xs + chao2 xs+    sest False xs = sobs xs + chao1 xs+    sobs = fromIntegral . richness+    additionalSampling True  = sampleG g+    additionalSampling False = individualG g+    getRarefactionCurve True = rarefactionSampleCurve fastBin start interval end     getRarefactionCurve False = rarefactionCurve-        fastBin runs (fromIntegral start) (fromIntegral interval)+                                fastBin+                                runs+                                (fromIntegral start)+                                (fromIntegral interval)+                                (fromIntegral end)  -- Return the results of the rarefaction analysis of the entire curve in -- string form for saving to a file@@ -76,12 +94,13 @@                       -> Int                       -> Int                       -> Int+                      -> Int                       -> Label                       -> Window                       -> PositionMap                       -> IO String printRarefactionCurve-    asDF sample fastBin runs start interval label window positionMap = do+    asDF bySample fastBin runs start interval end label window positionMap = do     body <- fmap unlines . mapM mapLine . Map.toAscList $ positionMap      return (header asDF ++ body)@@ -92,7 +111,7 @@                         \expected_richness,mad\n"     mapLine (!p, !xs) = line asDF p xs     line False p xs   = do-        curve <- getRarefactionCurve sample xs+        curve <- getRarefactionCurve bySample xs         return . intercalate "," $ [ label                                    , show window                                    , show p@@ -105,7 +124,7 @@                                    $ curve                                    ]     line True p xs    = do-        curve <- getRarefactionCurve sample xs+        curve <- getRarefactionCurve bySample xs         return . intercalate "\n"                . map ( \(!x, (!y, !z))                      -> intercalate "," [ label@@ -117,6 +136,10 @@                                         , show z                                         ] )                $ curve-    getRarefactionCurve True = rarefactionSampleCurve fastBin start interval+    getRarefactionCurve True = rarefactionSampleCurve fastBin start interval end     getRarefactionCurve False = rarefactionCurve-        fastBin runs (fromIntegral start) (fromIntegral interval)+                                fastBin+                                runs+                                (fromIntegral start)+                                (fromIntegral interval)+                                (fromIntegral end)