HORIZON HASKELLDocslts/ghc-9.10.xc74966e2026-09-27Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · c74966e · 2026-09-27

Moduletdigest-0.3Haskell2010

Data.TDigest.Vector

A new data structure for accurate on-line accumulation of rank-based statistics such as quantiles and trimmed means. . See original paper: "Computing extremely accurate quantiles using t-digest" by Ted Dunning and Otmar Ertl for more details https://github.com/tdunning/t-digest/blob/master/docs/t-digest-paper/histo.pdf.

Examples
Example1 expression
quantile 0.99 (tdigest [1..1000] :: TDigest 25)Just 990.5
Example1 expression
quantile 0.99 (tdigest [1..1000] :: TDigest 3)Just 990.3...

t-Digest is more precise in tails, especially median is imprecise:

Example1 expression
median (forceCompress $ tdigest [1..1000] :: TDigest 10)Just 500.5
Semigroup

This operation isn't strictly associative, but statistical variables shouldn't be affected.

Example1 expression
let td xs = tdigest xs :: TDigest 10
Example1 expression
median (td [1..500] <> (td [501..1000] <> td [1001..1500]))Just 750.5
Example1 expression
median ((td [1..500] <> td [501..1000]) <> td [1001..1500])Just 750.5

The linear is worst-case scenario:

Example1 expression
let td' xs = tdigest (fairshuffle xs) :: TDigest 10
Example1 expression
median (td' [1..500] <> (td' [501..1000] <> td' [1001..1500]))Just 750.5
Example1 expression
median ((td' [1..500] <> td' [501..1000]) <> td' [1001..1500])Just 750.5
  • 1 type
  • 18 values
  • Packagetdigest-0.3
  • Exports19
  • LanguageHaskell2010
  • LicenceBSD-3-Clause
  • SourceVector.hs

Construction

2 declarations
datadata TDigest (compression :: Nat)
#

TDigest is a vector of centroids plus not yet merged elements.

The size of structure is dictated by compression, *𝛿*. And is *O(𝛿)*.

Instances6Reducer, Show, Semigroup, Monoid, NFData, HasHistogram

Population

valueinsert'
  1. :: KnownNat comp
  2. => Double

    element

  3. -> TDigest comp
  4. -> TDigest comp
#

Insert single value, don't compress TDigest even if needed.

This may violate the insertion buffer size invariant.

For sensibly bounded input, it makes sense to let TDigest grow (it might grow linearly in size), and after that compress it once.

Compression

2 declarations
Example2 expressions
let digest = foldl' (flip insert') mempty [0..1000] :: TDigest 5(size digest, size $ compress digest)(1001,173)
Example1 expression
(quantile 0.1 digest, quantile 0.1 $ compress digest)(Just 99.6...,Just 99.6...)

Statistics

2 declarations
valueminimumValue :: KnownNat comp => TDigest comp -> Mean
#

Center of left-most centroid. Note: may be different than min element inserted.

Example1 expression
minimumValue (tdigest [1..100] :: TDigest 3)1.0
valuemaximumValue :: KnownNat comp => TDigest comp -> Mean
#

Center of right-most centroid. Note: may be different than max element inserted.

Example1 expression
maximumValue (tdigest [1..100] :: TDigest 3)100.0

Percentile

Mean & Variance

Example1 expression
stddev (tdigest $ fairshuffle [0..100] :: TDigest 10)Just 29.0...
valuemean :: KnownNat comp => TDigest comp -> Maybe Double
#

Mean.

Example1 expression
mean (tdigest [1..100] :: TDigest 10)Just 50.5

Note: if you only need the mean, calculate it directly.

CDF

valuecdf :: KnownNat comp => Double -> TDigest comp -> Double
#

Cumulative distribution function.

Note: if this is the only thing you need, it's more efficient to count this directly.

Debug

3 declarations