-
Notifications
You must be signed in to change notification settings - Fork 0
/
stats.hs
70 lines (56 loc) · 2.61 KB
/
stats.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
{-# LANGUAGE OverloadedStrings #-}
import qualified Statistics.Quantile as S
import qualified Statistics.Sample as SS
import qualified Data.Char as C
import qualified Data.Function as F
import qualified Data.List as L
import Data.String (IsString)
import qualified Data.String as Str
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
import Data.Vector (Vector)
import qualified Data.Vector as V
import Control.Applicative ((<$>))
import qualified Control.Monad as M
newtype Stat = Stat (Text, Vector Double -> Double)
numSamples, average, minimumStat, first, median, third, ninetieth, ninetyNinth, oneNine, maximumStat :: Stat
numSamples = Stat ("Samples: ", fromIntegral . V.length)
average = Stat ("Average: ", SS.mean)
minimumStat = Stat ("Minimum: ", V.minimum)
first = Stat ("25th percentile: ", quantile 1)
median = Stat ("50th percentile: ", quantile 2)
third = Stat ("75th percentile: ", quantile 3)
ninetieth = Stat ("90th percentile: ", S.weightedAvg 9 10)
ninetyNinth = Stat ("99th percentile: ", S.weightedAvg 99 100)
oneNine = Stat ("99.9th percentile: ", S.weightedAvg 999 1000)
maximumStat = Stat ("Maximum: ", V.maximum)
quantile :: Int -> Vector Double -> Double
quantile q xs = S.weightedAvg q 4 xs
allStats :: [Stat]
allStats = [numSamples, average, minimumStat, first, median, third, ninetieth, ninetyNinth, oneNine, maximumStat]
headerAndStats :: Text -> Vector Double -> IO ()
headerAndStats header samples = do
M.unless (T.strip header == "") (TIO.putStrLn header)
mapM_ (\(Stat (text, stat)) -> TIO.putStrLn (T.append text ((tshow . stat) samples))) allStats
stringOfList :: (IsString s) => [s] -> s
stringOfList = foldr (\hd _ -> hd) (Str.fromString "")
headerAndSamples :: [(Text, Double)] -> (Text, Vector Double)
headerAndSamples tds =
(stringOfList headers, V.fromList samples)
where (headers, samples) = unzip tds
tshow :: (Show a) => a -> Text
tshow = T.pack . show
dropLastWord :: Text -> Text
dropLastWord s = T.dropWhileEnd (not . C.isSpace) (T.stripEnd s)
parseLine :: Text -> (Text, Double)
parseLine s = (T.strip header, (read . T.unpack) measurement)
where header = dropLastWord s
measurement = last $ T.words s
main :: IO ()
main = do
ls <- T.lines <$> TIO.getContents
let parsedLines = map parseLine ls
let groupedLines = L.groupBy ((==) `F.on` fst) parsedLines
let headersAndSamples = map headerAndSamples groupedLines
sequence_ (L.intersperse (putStrLn "") (map (uncurry headerAndStats) headersAndSamples))