Skip to content

Summarising

In general a FlexiChain contains data in matrices of size (niters, nchains). Often it is useful to summarise this data along one or both dimensions.

FlexiChains therefore allows you to calculate one or more statistics for each variable stored in a FlexiChain. The result is a FlexiSummary object, which can be indexed into in a very similar way to FlexiChains: see the Indexing page for full details, or the examples on this page.

Unsupported data types

Before we launch into the available summary statistics, it is worth mentioning one point about data types. Since FlexiChains allows for storage of completely arbitrary data types, it can contain data for which the mean (or other statistic) is not defined. For example, the mean of String values is not defined. Thus, when calculating mean(chain), any String-valued parameters will be dropped from the result.

If multiple summary statistics are requested (e.g. with summarystats), the key is only dropped if all of them fail. If at least one statistic is successfully computed for a key, that key will be included in the result, with missing values for the statistics that failed.

To give a flavour of how this works, here is an example of a model that generates parameters of different types:

julia
using FlexiChains, Turing

@model function f()
    f ~ Normal()               # float
    v ~ MvNormal(zeros(2), I)  # vector
    s := "a string"            # string
end

chain = sample(f(), MH(), MCMCThreads(), 20, 3; chain_type=VNChain)
╭─FlexiChain (20 iterations, 3 chains) ────────────────────────────────────────
 ↓ iter  = 1:20
 → chain = 1:3

 Parameters (3) ── VarName
  Float64          f                                                          
  Vector{Float64}  v (2,)
  String           s                                                          

 Extras (4)
  Bool     accepted                                                           
  Float64  logprior, loglikelihood, logjoint                                  
╰──────────────────────────────────────────────────────────────────────────────╯

Over the course of this page we will see what happens to each of these parameters when we try to compute summary statistics.

Overall summary statistics

If you want a quick overview of what's in your chain, summarystats provides a handy selection of commonly used statistics:

StatsBase.summarystats Method
julia
StatsBase.summarystats(
    chain::FlexiChain{TKey};
    split_varnames::Bool=true,
    warn::Bool=true,
) where {TKey}

Compute a standard set of summary statistics for each key in the chain. The statistics include:

The split_varnames keyword argument, if true, will first split up variables in the chain such that each key corresponds to a single scalar value. The splitting is only supported for chains with TKey<:VarName or TKey==Symbol; for other key types, this will be a no-op as long as the data already contain scalar values for every key, but will error if the data contain non-scalar values.

If any of the statistics cannot be computed for a key, a missing value is returned. If none of the statistics can be computed for a key, that key will be dropped from the resulting FlexiSummary, and a warning issued. The warning can be suppressed by setting warn=false.

source
julia
st = summarystats(chain)
╭─FlexiSummary (9 statistics) ─────────────────────────────────────────────────
   iter    collapsed
   chain   collapsed
 ↓ stat  = [mean, std, mcse, ess_bulk, ess_tail, rhat, q5, q50, q95]

 Parameters (3) ── VarName
  Float64  f, v[1], v[2]                                                      

 Extras (4)
  Float64  accepted, logprior, loglikelihood, logjoint                        

 Summary
   param     mean     std    mcse  ess_bulk  ess_tail    rhat       q5
       f  -0.0267  0.9731  0.1061   92.5113   64.4285  0.9879  -1.6506
    v[1]   0.0014  0.8604  0.1010   71.1998   37.5486  0.9941  -1.4380
    v[2]   0.2013  1.0990  0.1360   68.9064   23.2807  1.0017  -1.6600
╰──────────────────────────────────────────────────────────────────────────────╯

Notice that the string-valued parameter s has been dropped from the result, since no statistics could be computed for it. (If you run this in the terminal, you will see a warning about this, so it is not completely silent; it's just not shown in the docs.)

You can index with a variable name (or names!) and the stat dimension:

julia
st[@varname(v[1]), stat=:mean]  # Mean of first element of vector v
0.0013661554201467344

Named statistic shorthand

Passing a Symbol to stat is shorthand for a named lookup: stat=:mean is equivalent to stat=At(:mean). Other selectors follow DimensionalData.jl's usual behaviour; for example, stat=1 selects the first statistic by position.

For more details on indexing, please see the Indexing page.

In the result above, the vector-valued v has been broken up into its individual elements v[1] and v[2]. This happens automatically for chains with VarName keys; you can disable this behaviour by passing split_varnames=false:

julia
st2 = summarystats(chain; split_varnames=false)
╭─FlexiSummary (9 statistics) ─────────────────────────────────────────────────
   iter    collapsed
   chain   collapsed
 ↓ stat  = [mean, std, mcse, ess_bulk, ess_tail, rhat, q5, q50, q95]

 Parameters (2) ── VarName
  Float64                          f                                          
  Union{Missing, Vector{Float64}}  v                                          

 Extras (4)
  Float64  accepted, logprior, loglikelihood, logjoint                        

 Summary
   param       mean        std     mcse  ess_bulk  ess_tail     rhat
       f    -0.0267     0.9731   0.1061   92.5113   64.4285   0.9879
       v  [0.0,0.2]  [0.9,1.1]  missing   missing   missing  missing
╰──────────────────────────────────────────────────────────────────────────────╯

Now, the summary statistics are calculated with each vector v being a single entity. The key v is still present in the result (since mean and std could be computed for it). However, notice that other statistics such as ess are no longer defined, and so return missing values. Just like before, the string s is dropped since no statistics could be computed for it.

Individual statistics

Sometimes you may only want to calculate a single statistic.

The following functions are all overloaded to accept FlexiChain objects. In all cases, they can be called with dims=:both, dims=:iter, or dims=:chain to specify the dimension over which to compute the statistic; the default is dims=:both.

All of these functions return a FlexiSummary where the :stat dimension has already been collapsed. That means that if you want to access the mean of a variable @varname(a) you don't need to further use the stat dimension:

julia
mn = mean(chain)
# Not needed: mean_f = m[@varname(f), stat=:mean]
# Just do:
mean_f = mn[@varname(f)]
-0.02668494343427702

In fact, behind the scenes, the actual name of the statistic is retained. This means that, for example, if you convert the result to a DataFrame, the column will be named mean rather than stat:

julia
using DataFrames;
DataFrame(mn)
3×2 DataFrame
Rowparamstat
VarNameFloat64
1f-0.0266849
2v[1]0.00136616
3v[2]0.201306
Statistics.mean Method
julia
Statistics.mean(
    chain::FlexiChain{TKey};
    dims::Symbol=:both,
    warn::Bool=true,
    split_varnames::Bool=true,
    kwargs...
) where {TKey}

Calculate the mean across all iterations and chains for each key in the chain. If the statistic cannot be computed for a key, that key is skipped and a warning is issued (which can be suppressed by setting warn=false).

The dims keyword argument specifies which dimensions to collapse. The default value of :both collapses both the iteration and chain dimensions. Other valid values are :iter or :chain, which respectively collapse only the iteration or chain dimension.

The split_varnames keyword argument, if true, will first split up variables in the chain such that each key corresponds to a single scalar value. This is only supported for chains with TKey<:VarName or TKey==Symbol; for other key types this will be a no-op as long as the data already contain scalar values for every key, but will error if the data contain non-scalar values.

Other keyword arguments are forwarded to Statistics.mean; please see its documentation for details of supported keyword arguments.

source
Statistics.median Method
julia
Statistics.median(
    chain::FlexiChain{TKey};
    dims::Symbol=:both,
    warn::Bool=true,
    split_varnames::Bool=true,
    kwargs...
) where {TKey}

Calculate the median across all iterations and chains for each key in the chain. If the statistic cannot be computed for a key, that key is skipped and a warning is issued (which can be suppressed by setting warn=false).

The dims keyword argument specifies which dimensions to collapse. The default value of :both collapses both the iteration and chain dimensions. Other valid values are :iter or :chain, which respectively collapse only the iteration or chain dimension.

The split_varnames keyword argument, if true, will first split up variables in the chain such that each key corresponds to a single scalar value. This is only supported for chains with TKey<:VarName or TKey==Symbol; for other key types this will be a no-op as long as the data already contain scalar values for every key, but will error if the data contain non-scalar values.

Other keyword arguments are forwarded to Statistics.median; please see its documentation for details of supported keyword arguments.

source
Statistics.std Method
julia
Statistics.std(
    chain::FlexiChain{TKey};
    dims::Symbol=:both,
    warn::Bool=true,
    split_varnames::Bool=true,
    kwargs...
) where {TKey}

Calculate the standard deviation across all iterations and chains for each key in the chain. If the statistic cannot be computed for a key, that key is skipped and a warning is issued (which can be suppressed by setting warn=false).

The dims keyword argument specifies which dimensions to collapse. The default value of :both collapses both the iteration and chain dimensions. Other valid values are :iter or :chain, which respectively collapse only the iteration or chain dimension.

The split_varnames keyword argument, if true, will first split up variables in the chain such that each key corresponds to a single scalar value. This is only supported for chains with TKey<:VarName or TKey==Symbol; for other key types this will be a no-op as long as the data already contain scalar values for every key, but will error if the data contain non-scalar values.

Other keyword arguments are forwarded to Statistics.std; please see its documentation for details of supported keyword arguments.

source
Statistics.var Method
julia
Statistics.var(
    chain::FlexiChain{TKey};
    dims::Symbol=:both,
    warn::Bool=true,
    split_varnames::Bool=true,
    kwargs...
) where {TKey}

Calculate the variance across all iterations and chains for each key in the chain. If the statistic cannot be computed for a key, that key is skipped and a warning is issued (which can be suppressed by setting warn=false).

The dims keyword argument specifies which dimensions to collapse. The default value of :both collapses both the iteration and chain dimensions. Other valid values are :iter or :chain, which respectively collapse only the iteration or chain dimension.

The split_varnames keyword argument, if true, will first split up variables in the chain such that each key corresponds to a single scalar value. This is only supported for chains with TKey<:VarName or TKey==Symbol; for other key types this will be a no-op as long as the data already contain scalar values for every key, but will error if the data contain non-scalar values.

Other keyword arguments are forwarded to Statistics.var; please see its documentation for details of supported keyword arguments.

source
Statistics.quantile Method
julia
Statistics.quantile(
    chain::FlexiChain{TKey},
    p;
    dims::Symbol=:both,
    warn::Bool=true,
    split_varnames::Bool=true,
    kwargs...
) where {TKey}

Calculate the quantile across all iterations and chains for each key in the chain. If it cannot be computed for a key, that key is skipped and a warning is issued (which can be suppressed by setting warn=false).

The dims keyword argument specifies which dimensions to collapse.

  • :iter: collapse the iteration dimension only

  • :chain: collapse the chain dimension only

  • :both: collapse both the iteration and chain dimensions (default)

The argument p specifies the quantile to compute, and is forwarded to Statistics.quantile, along with any other keyword arguments.

source
Base.minimum Method
julia
Base.minimum(
    chain::FlexiChain{TKey};
    dims::Symbol=:both,
    warn::Bool=true,
    split_varnames::Bool=true,
    kwargs...
) where {TKey}

Calculate the minimum across all iterations and chains for each key in the chain. If the statistic cannot be computed for a key, that key is skipped and a warning is issued (which can be suppressed by setting warn=false).

The dims keyword argument specifies which dimensions to collapse. The default value of :both collapses both the iteration and chain dimensions. Other valid values are :iter or :chain, which respectively collapse only the iteration or chain dimension.

The split_varnames keyword argument, if true, will first split up variables in the chain such that each key corresponds to a single scalar value. This is only supported for chains with TKey<:VarName or TKey==Symbol; for other key types this will be a no-op as long as the data already contain scalar values for every key, but will error if the data contain non-scalar values.

Other keyword arguments are forwarded to Base.minimum; please see its documentation for details of supported keyword arguments.

source
Base.maximum Method
julia
Base.maximum(
    chain::FlexiChain{TKey};
    dims::Symbol=:both,
    warn::Bool=true,
    split_varnames::Bool=true,
    kwargs...
) where {TKey}

Calculate the maximum across all iterations and chains for each key in the chain. If the statistic cannot be computed for a key, that key is skipped and a warning is issued (which can be suppressed by setting warn=false).

The dims keyword argument specifies which dimensions to collapse. The default value of :both collapses both the iteration and chain dimensions. Other valid values are :iter or :chain, which respectively collapse only the iteration or chain dimension.

The split_varnames keyword argument, if true, will first split up variables in the chain such that each key corresponds to a single scalar value. This is only supported for chains with TKey<:VarName or TKey==Symbol; for other key types this will be a no-op as long as the data already contain scalar values for every key, but will error if the data contain non-scalar values.

Other keyword arguments are forwarded to Base.maximum; please see its documentation for details of supported keyword arguments.

source
Base.sum Method
julia
Base.sum(
    chain::FlexiChain{TKey};
    dims::Symbol=:both,
    warn::Bool=true,
    split_varnames::Bool=true,
    kwargs...
) where {TKey}

Calculate the sum across all iterations and chains for each key in the chain. If the statistic cannot be computed for a key, that key is skipped and a warning is issued (which can be suppressed by setting warn=false).

The dims keyword argument specifies which dimensions to collapse. The default value of :both collapses both the iteration and chain dimensions. Other valid values are :iter or :chain, which respectively collapse only the iteration or chain dimension.

The split_varnames keyword argument, if true, will first split up variables in the chain such that each key corresponds to a single scalar value. This is only supported for chains with TKey<:VarName or TKey==Symbol; for other key types this will be a no-op as long as the data already contain scalar values for every key, but will error if the data contain non-scalar values.

Other keyword arguments are forwarded to Base.sum; please see its documentation for details of supported keyword arguments.

source
Base.prod Method
julia
Base.prod(
    chain::FlexiChain{TKey};
    dims::Symbol=:both,
    warn::Bool=true,
    split_varnames::Bool=true,
    kwargs...
) where {TKey}

Calculate the product across all iterations and chains for each key in the chain. If the statistic cannot be computed for a key, that key is skipped and a warning is issued (which can be suppressed by setting warn=false).

The dims keyword argument specifies which dimensions to collapse. The default value of :both collapses both the iteration and chain dimensions. Other valid values are :iter or :chain, which respectively collapse only the iteration or chain dimension.

The split_varnames keyword argument, if true, will first split up variables in the chain such that each key corresponds to a single scalar value. This is only supported for chains with TKey<:VarName or TKey==Symbol; for other key types this will be a no-op as long as the data already contain scalar values for every key, but will error if the data contain non-scalar values.

Other keyword arguments are forwarded to Base.prod; please see its documentation for details of supported keyword arguments.

source
MCMCDiagnosticTools.ess Method
julia
MCMCDiagnosticTools.ess(
    chain::FlexiChain{TKey};
    dims::Symbol=:both,
    warn::Bool=true,
    split_varnames::Bool=true,
    kwargs...
) where {TKey}

Calculate the effective sample size across all iterations and chains for each key in the chain. If the statistic cannot be computed for a key, that key is skipped and a warning is issued (which can be suppressed by setting warn=false).

The dims keyword argument specifies which dimensions to collapse. The default value of :both collapses both the iteration and chain dimensions. Other valid values are :iter or :chain, which respectively collapse only the iteration or chain dimension.

The split_varnames keyword argument, if true, will first split up variables in the chain such that each key corresponds to a single scalar value. This is only supported for chains with TKey<:VarName or TKey==Symbol; for other key types this will be a no-op as long as the data already contain scalar values for every key, but will error if the data contain non-scalar values.

Other keyword arguments are forwarded to MCMCDiagnosticTools.ess; please see its documentation for details of supported keyword arguments.

source
MCMCDiagnosticTools.rhat Method
julia
MCMCDiagnosticTools.rhat(
    chain::FlexiChain{TKey};
    dims::Symbol=:both,
    warn::Bool=true,
    split_varnames::Bool=true,
    kwargs...
) where {TKey}

Calculate the R-hat diagnostic across all iterations and chains for each key in the chain. If the statistic cannot be computed for a key, that key is skipped and a warning is issued (which can be suppressed by setting warn=false).

The dims keyword argument specifies which dimensions to collapse. The default value of :both collapses both the iteration and chain dimensions. Other valid values are :iter or :chain, which respectively collapse only the iteration or chain dimension.

The split_varnames keyword argument, if true, will first split up variables in the chain such that each key corresponds to a single scalar value. This is only supported for chains with TKey<:VarName or TKey==Symbol; for other key types this will be a no-op as long as the data already contain scalar values for every key, but will error if the data contain non-scalar values.

Other keyword arguments are forwarded to MCMCDiagnosticTools.rhat; please see its documentation for details of supported keyword arguments.

source
MCMCDiagnosticTools.mcse Method
julia
MCMCDiagnosticTools.mcse(
    chain::FlexiChain{TKey};
    dims::Symbol=:both,
    warn::Bool=true,
    split_varnames::Bool=true,
    kwargs...
) where {TKey}

Calculate the Monte Carlo standard error across all iterations and chains for each key in the chain. If the statistic cannot be computed for a key, that key is skipped and a warning is issued (which can be suppressed by setting warn=false).

The dims keyword argument specifies which dimensions to collapse. The default value of :both collapses both the iteration and chain dimensions. Other valid values are :iter or :chain, which respectively collapse only the iteration or chain dimension.

The split_varnames keyword argument, if true, will first split up variables in the chain such that each key corresponds to a single scalar value. This is only supported for chains with TKey<:VarName or TKey==Symbol; for other key types this will be a no-op as long as the data already contain scalar values for every key, but will error if the data contain non-scalar values.

Other keyword arguments are forwarded to MCMCDiagnosticTools.mcse; please see its documentation for details of supported keyword arguments.

source
StatsBase.mad Method
julia
StatsBase.mad(
    chain::FlexiChain{TKey};
    dims::Symbol=:both,
    warn::Bool=true,
    split_varnames::Bool=true,
    kwargs...
) where {TKey}

Calculate the median absolute deviation across all iterations and chains for each key in the chain. If the statistic cannot be computed for a key, that key is skipped and a warning is issued (which can be suppressed by setting warn=false).

The dims keyword argument specifies which dimensions to collapse. The default value of :both collapses both the iteration and chain dimensions. Other valid values are :iter or :chain, which respectively collapse only the iteration or chain dimension.

The split_varnames keyword argument, if true, will first split up variables in the chain such that each key corresponds to a single scalar value. This is only supported for chains with TKey<:VarName or TKey==Symbol; for other key types this will be a no-op as long as the data already contain scalar values for every key, but will error if the data contain non-scalar values.

Other keyword arguments are forwarded to StatsBase.mad; please see its documentation for details of supported keyword arguments.

source
StatsBase.geomean Method
julia
StatsBase.geomean(
    chain::FlexiChain{TKey};
    dims::Symbol=:both,
    warn::Bool=true,
    split_varnames::Bool=true,
    kwargs...
) where {TKey}

Calculate the geometric mean across all iterations and chains for each key in the chain. If the statistic cannot be computed for a key, that key is skipped and a warning is issued (which can be suppressed by setting warn=false).

The dims keyword argument specifies which dimensions to collapse. The default value of :both collapses both the iteration and chain dimensions. Other valid values are :iter or :chain, which respectively collapse only the iteration or chain dimension.

The split_varnames keyword argument, if true, will first split up variables in the chain such that each key corresponds to a single scalar value. This is only supported for chains with TKey<:VarName or TKey==Symbol; for other key types this will be a no-op as long as the data already contain scalar values for every key, but will error if the data contain non-scalar values.

Other keyword arguments are forwarded to StatsBase.geomean; please see its documentation for details of supported keyword arguments.

source
StatsBase.harmmean Method
julia
StatsBase.harmmean(
    chain::FlexiChain{TKey};
    dims::Symbol=:both,
    warn::Bool=true,
    split_varnames::Bool=true,
    kwargs...
) where {TKey}

Calculate the harmonic mean across all iterations and chains for each key in the chain. If the statistic cannot be computed for a key, that key is skipped and a warning is issued (which can be suppressed by setting warn=false).

The dims keyword argument specifies which dimensions to collapse. The default value of :both collapses both the iteration and chain dimensions. Other valid values are :iter or :chain, which respectively collapse only the iteration or chain dimension.

The split_varnames keyword argument, if true, will first split up variables in the chain such that each key corresponds to a single scalar value. This is only supported for chains with TKey<:VarName or TKey==Symbol; for other key types this will be a no-op as long as the data already contain scalar values for every key, but will error if the data contain non-scalar values.

Other keyword arguments are forwarded to StatsBase.harmmean; please see its documentation for details of supported keyword arguments.

source
StatsBase.iqr Method
julia
StatsBase.iqr(
    chain::FlexiChain{TKey};
    dims::Symbol=:both,
    warn::Bool=true,
    split_varnames::Bool=true,
    kwargs...
) where {TKey}

Calculate the interquartile range across all iterations and chains for each key in the chain. If the statistic cannot be computed for a key, that key is skipped and a warning is issued (which can be suppressed by setting warn=false).

The dims keyword argument specifies which dimensions to collapse. The default value of :both collapses both the iteration and chain dimensions. Other valid values are :iter or :chain, which respectively collapse only the iteration or chain dimension.

The split_varnames keyword argument, if true, will first split up variables in the chain such that each key corresponds to a single scalar value. This is only supported for chains with TKey<:VarName or TKey==Symbol; for other key types this will be a no-op as long as the data already contain scalar values for every key, but will error if the data contain non-scalar values.

Other keyword arguments are forwarded to StatsBase.iqr; please see its documentation for details of supported keyword arguments.

source

There are also similar overloads for PosteriorStats.hdi and PosteriorStats.eti, which calculate highest density intervals and equal-tailed intervals, respectively. Please see the PosteriorStats integration section for details.

Custom statistics

There are two scenarios where the above are not enough: 2. you want to calculate a specific set of statistics that is not the same as what summarystats does; or

  1. you want to calculate a completely custom statistic, which is not implemented above.

In both cases, you can directly use [FlexiChains.collapse] to achieve this. (But in the latter case, please do also consider opening an issue so that we can implement it!)

FlexiChains.collapse Function
julia
FlexiChains.collapse(
    chain::FlexiChain,
    funcs::AbstractVector;
    dims::Symbol=:both,
    warn::Bool=true,
    drop_stat_dim::Bool=false,
)

Low-level function to collapse one or both dimensions of a FlexiChain by applying a list of summary functions.

The funcs argument must be a vector which contains either:

  • tuples of the form (statistic_name::Symbol, func::Function); or

  • just functions, in which case the statistic name is obtained from the function name.

The dims keyword argument specifies which dimensions to collapse. By default, dims is :both, which collapses both the iteration and chain dimensions. Other valid values are :iter or :chain, which respectively collapse only the iteration or chain dimension.

The functions in funcs must map a vector to a single value. For example, both Statistics.mean and Statistics.std satisfy this:

julia
using FlexiChains: collapse
using Statistics: mean, std

collapse(chn, [mean, std]; dims=:both)

If dims=:iter or dims=:chain are selected, then the functions are automatically applied to each column or row as appropriate. No adjustment to the functions is necessary:

julia
collapse(chn, [mean, std]; dims=:iter)
collapse(chn, [mean, std]; dims=:chain)

For dims=:both, the function is applied to all the samples stacked together as a single vector.

Sometimes, for more complicated functions like quantile, you have to pass an anonymous function (such as x -> quantile(x, 0.05) or a closure (such as Base.Fix2(quantile, 0.05)). In this case, to get a sensible statistic name, instead of just passing the function you can pass a tuple of the form (statistic_name::Symbol, func::Function).

julia
collapse(chn, [
    mean,
    std,
    (:q5, x -> quantile(x, 0.05)),
    (:q95, x -> quantile(x, 0.95)),
])

If a statistic function errors when applied to a key, that key is skipped and a warning is issued. The warning can be suppressed by setting warn=false.

If the drop_stat_dim keyword argument is true and only one function is provided in funcs, then the resulting FlexiSummary will have the stat dimension dropped. This allows for easier indexing into the result when only one statistic is computed. It is an error to set drop_stat_dim=true when more than one function is provided.

source

As an example, suppose you have a statistic that calculates the sum of the mean and standard deviation. (This is of course quite contrived: if you have a real example, again, please do open an issue!)

We start by defining our own function:

julia
using Statistics

function mean_std_sum(x::AbstractVector{<:Real})
    return mean(x) + std(x)
end
mean_std_sum (generic function with 1 method)

As noted in the docstring of FlexiChains.collapse, the function you provide must accept a vector argument and return a single value. Of course, it can also have other methods, but this is the one which collapse uses.

Now we can use collapse to apply this function to all variables in the chain. The second argument is a vector, which in this case will only contain our one function:

julia
custom_stat = FlexiChains.collapse(chain, [mean_std_sum]; dims=:both)
╭─FlexiSummary (1 statistic) ──────────────────────────────────────────────────
   iter    collapsed
   chain   collapsed
 ↓ stat  = [mean_std_sum]

 Parameters (3) ── VarName
  Float64  f, v[1], v[2]                                                      

 Extras (4)
  Float64  accepted, logprior, loglikelihood, logjoint                        

 Summary
   param  mean_std_sum
       f        0.9464                                                        
    v[1]        0.8618                                                        
    v[2]        1.3003                                                        
╰──────────────────────────────────────────────────────────────────────────────╯

There are two things worth mentioning, which we will note in passing here without demonstrating (since they are also covered in the docstring): 2. If there is only one function provided, you can additionally pass drop_stat_dim=true to remove the :stat dimension from the result, much like what mean(chain) et al. do.

  1. The name of the statistic is inferred from the function. Sometimes this doesn't work out nicely, for example if you pass an anonymous function. In this case you can provide a tuple of (:name, function) instead of just the function.

Merging summaries

As an alternative to using collapse, you can also calculate separate summaries and then merge them.

julia
mn = mean(chain)
sd = std(chain)

merge(mn, sd)
╭─FlexiSummary (2 statistics) ─────────────────────────────────────────────────
   iter    collapsed
   chain   collapsed
 ↓ stat  = [mean, std]

 Parameters (3) ── VarName
  Float64  f, v[1], v[2]                                                      

 Extras (4)
  Float64  accepted, logprior, loglikelihood, logjoint                        

 Summary
   param     mean     std
       f  -0.0267  0.9731                                                     
    v[1]   0.0014  0.8604                                                     
    v[2]   0.2013  1.0990                                                     
╰──────────────────────────────────────────────────────────────────────────────╯
Base.merge Method
julia
Base.merge(
    s1::FlexiSummary{TKey1},
    s2::FlexiSummary{TKey2},
) where {TKey1,TKey2}

Merge two FlexiSummarys along both the key and statistic dimensions.

The two summaries must have the same iteration and chain indices.

The merged result contains the union of keys and the union of stat names from both summaries. For each (key, stat) pair, the value from s2 takes priority over s1. Pairs that exist in neither summary are filled with missing.

If the key types are different, the resulting FlexiSummary will have a promoted key type, and a warning will be issued.

source

Density intervals

It is worth just noting briefly here that FlexiChains has a PosteriorStats extension which allows you to calculate highest density intervals and equal-tailed intervals. Please see the PosteriorStats integration section for details.

MCMC diagnostics

There are a number of functions in MCMCDiagnosticTools.jl which do not nicely fit the notion of 'collapse over one or more dimensions'. For example, quantities like the Gelman diagnostic are calculated over the entire dataset.

For these functions, you can simply pass a FlexiChain to them. For example:

julia
gelmandiag(chain)
╭─FlexiSummary (2 statistics) ─────────────────────────────────────────────────
   iter    collapsed
   chain   collapsed
 ↓ stat  = [psrf, psrfci]

 Parameters (3) ── VarName
  Float64  f, v[1], v[2]                                                      

 Extras (0)
  (none)

 Summary
   param    psrf  psrfci
       f  0.9879  0.9990                                                      
    v[1]  0.9986  1.0403                                                      
    v[2]  1.0394  1.1790                                                      
╰──────────────────────────────────────────────────────────────────────────────╯

The available functions are as follows (and FlexiChains reexports all of these too, for convenience).

MCMCDiagnosticTools.gelmandiag Function
julia
MCMCDiagnosticTools.gelmandiag(
    chain::FlexiChain{TKey};
    warn::Bool=true,
    kwargs...
) where {TKey}

Compute the Gelman–Rubin–Brooks diagnostic (Potential Scale Reduction Factor, PSRF) for each parameter in the chain.

Returns a FlexiSummary with two statistics per parameter: :psrf (the point estimate) and :psrfci (the upper confidence limit).

The FlexiChain must contain at least 2 chains. Array-valued parameters are automatically split into their constituent scalars. Non-Real-valued keys are skipped with a warning (which can be suppressed via warn=false).

Other keyword arguments are forwarded to MCMCDiagnosticTools.gelmandiag.

source
MCMCDiagnosticTools.gelmandiag_multivariate Function
julia
MCMCDiagnosticTools.gelmandiag_multivariate(
    chain::FlexiChain{TKey};
    warn::Bool=true,
    kwargs...
) where {TKey}

Compute the multivariate Gelman–Rubin–Brooks diagnostic for the chain. This requires at least 2 parameters and at least 2 chains.

Returns a NamedTuple with two fields:

  • summary: a FlexiSummary with :psrf and :psrfci statistics (same as what gelmandiag returns)

  • psrf_multivariate: the multivariate potential scale reduction factor (Float64)

Array-valued parameters are automatically split into their constituent scalars. Non-Real-valued keys are skipped with a warning (which can be suppressed via warn=false).

Other keyword arguments are forwarded to MCMCDiagnosticTools.gelmandiag_multivariate.

source
MCMCDiagnosticTools.discretediag Function
julia
MCMCDiagnosticTools.discretediag(
    chain::FlexiChain{TKey};
    warn::Bool=true,
    kwargs...
) where {TKey}

Compute the discrete diagnostic for each parameter in the chain. This diagnostic is designed for discrete (categorical) MCMC samples.

Returns a NamedTuple with two fields:

  • between: a FlexiSummary with between-chain diagnostics (:stat, :df, :pvalue) per parameter

  • within: a FlexiSummary with within-chain diagnostics (:stat, :df, :pvalue) per parameter and per chain

The FlexiChain must contain at least 2 chains. Array-valued parameters are automatically split into their constituent scalars. Non-Integer-valued keys are skipped with a warning (which can be suppressed via warn=false).

Other keyword arguments are forwarded to MCMCDiagnosticTools.discretediag.

source
MCMCDiagnosticTools.bfmi Function
julia
MCMCDiagnosticTools.bfmi(
    chain::FlexiChain,
    energy_key
)

Calculate the Bayesian fraction of missing information (BFMI) from the given chain, using the specified energy_key to identify the key in the chain that corresponds to the Hamiltonian energy. Returns a DimVector of BFMI values, one per chain (note that even if there is only one chain, the result will still be a vector of length 1).

For chains sampled with Turing.jl's HMC/NUTS, the energy key is :hamiltonian_energy.

source

Flattening summaries

Finally, FlexiSummary objects can be converted to DimArrays or DataFrames, just like FlexiChains. This is useful for various analyses and visualisations.

julia
st = summarystats(chain)
DimArray(st)
9×3 DimArray{Float64, 2}
├──────────────────────────┴──────────────────────── dims ┐
stat Categorical{Symbol} [:mean, …, :q95] Unordered,
param Categorical{VarName} [f, …, v[2]] Unordered
└─────────────────────────────────────────────────────────┘
           f           v[1]         v[2]
  :mean      -0.0266849   0.00136616   0.201306
  :std        0.973082    0.860395     1.09896
  :mcse       0.106082    0.101039     0.135994
  :ess_bulk  92.5113     71.1998      68.9064
  :ess_tail  64.4285     37.5486      23.2807
  :rhat       0.98788     0.994136     1.00172
  :q5        -1.65059    -1.43801     -1.66004
  :q50        0.133813   -0.0701984    0.256264
  :q95        1.40124     1.24931      2.13617
julia
using DataFrames

DataFrame(st)
3×10 DataFrame
Rowparammeanstdmcseess_bulkess_tailrhatq5q50q95
VarNameFloat64Float64Float64Float64Float64Float64Float64Float64Float64
1f-0.02668490.9730820.10608292.511364.42850.98788-1.650590.1338131.40124
2v[1]0.001366160.8603950.10103971.199837.54860.994136-1.43801-0.07019841.24931
3v[2]0.2013061.098960.13599468.906423.28071.00172-1.660040.2562642.13617