MCMCChains.jl

repository·main·Indexed 42 days ago

https://github.com/turinglang/mcmcchains.jl

A Julia package for summarizing Markov Chain Monte Carlo (MCMC) simulations. It provides the `Chains` data type for storing samples, tools for calculating posterior statistics (such as `autocor`, `hpd`, and `summarystats`), and integration with StatsPlots.jl and Makie.jl for diagnostics and visualizations. It supports multiple serialization formats including JSON, CSV, and StanCSV for interoperability with the Stan ecosystem.

Tokens
5.5K
Snippets
23
Records
26
Agent score
55%

What's inside MCMCChains.jl

  1. Overview of MCMCChains.jl

    main

    MCMCChains.jl provides specialized Julia types designed for summarizing Markov Chain Monte Carlo (MCMC) simulations. It serves as a central hub for handling MCMC data and provides integrated utilities for:

    • Diagnostics: Tools to evaluate the quality and convergence of your chains.
    • Visualizations: Integration with StatsPlots.jl for plotting MCMC results.
    • Serialization: Capabilities to save and load MCMC chains efficiently.
  2. Organize parameters into Sections

    main

    Parameters in a Chains object can be grouped into sections. By default, all unassigned parameters belong to a :parameters section.

    Use set_section to create a new Chains object where specific parameters are assigned to a named section (e.g., :internals).

    When calling summary functions like describe or summarize, you can use the sections keyword argument to target specific groups or sections = nothing to include all variables.

    # Create chains with named parameters
    chn = Chains(rand(100, 4, 2), [:a, :b, :c, :d])
    
    # Assign :c and :d to a new section called :internals
    chn2 = set_section(chn, Dict(:internals => [:c, :d]))
    
    # Retrieve statistics for only the :internals section
    stats = describe(chn2; sections = :internals)
  3. Generate Energy Plots for HMC diagnostics

    main

    Energy plots are diagnostic tools for HMC-based samplers (like NUTS) to visualize energy and energy transition distributions. This requires the Chains object to contain the internal sampler statistics :hamiltonian_energy and :hamiltonian_energy_error.

    # Requires a Chains object with :hamiltonian_energy and :hamiltonian_energy_error
    # Example setup with section_map
    section_map = (
        parameters=[:a, :b],
        internals=[:hamiltonian_energy, :hamiltonian_energy_error],
    )
    chn_energy = Chains(full_val, parameter_names, section_map)
    
    # Generate density energy plot
    energyplot(chn_energy)
    
    # Generate histogram energy plot
    energyplot(chn_energy, kind=:histogram)
  4. Export Chains to CSV

    main

    MCMCChains implements the Tables.jl interface, allowing you to use CSV.jl for simple tabular data export.

    Note: Simple CSV export flattens all chains into rows and adds iteration and chain columns. While the multi-chain structure can be reconstructed on reload, other metadata such as parameter sections, info, and log evidence are not preserved.

    using MCMCChains, CSV
    
    chn = Chains(rand(100, 2, 2), [:a, :b])
    
    # Save (includes iteration and chain columns)
    CSV.write("chains.csv", chn)
    
    # Load
    chn_loaded = Chains(CSV.File("chains.csv"))
  5. Plot density estimates for MCMC samples

    main

    To visualize the distribution of samples, you can add a second column of plots showing the density estimate for each parameter.

    Using density!(ax, values; label=string(chain)) allows you to overlay the density of each chain on the same axis. To ensure the plots are comparable, you can use linkxaxes! on the collection of axes created for the density plots.

    # Assuming 'fig', 'params', 'n_chains', and 'chns' are already defined from the previous step
    
    for (i, param) in enumerate(params)
        ax = Axis(fig[i, 2]; ylabel=string(param))
        for chain in 1:n_chains
            values = chns[:, param, chain]
            density!(ax, values; label=string(chain))
        end
    
        hideydecorations!(ax)
        if i < length(params)
            hidexdecorations!(ax; grid=false)
        else
            ax.xlabel = "Parameter estimate"
        end
    end
    
    # Link the x-axes of the density plots
    axes = [only(contents(fig[i, 2])) for i in 1:length(params)]
    linkxaxes!(axes...)
    
    fig
  6. Export Chains to Array or DataFrame

    main

    You can convert Chains objects into standard Julia data structures:

    1. Array: Use Array(chn). By default, chains are appended. To get a separate matrix for each chain, set append_chains=false.
    2. DataFrame: Use DataFrame(chn) (requires the DataFrames package).

    Example:

    using MCMCChains
    using DataFrames
    
    chn = Chains(rand(3, 2, 2), [:a, :b])
    
    # Convert to a single appended Array
    arr = Array(chn)
    
    # Convert to an Array where each chain is its own matrix
    arr_separate = Array(chn, append_chains=false)
    # Access the second chain's matrix:
    # arr_separate[2]
    
    # Convert to a DataFrame
    df = DataFrame(chn)
  7. Interoperate with Stan using StanCSV

    main

    For compatibility with the Stan ecosystem (CmdStan, ArviZ, etc.), use the dedicated write_stancsv and read_stancsv functions. This format handles Stan-specific requirements like comment headers, parameter naming conventions, and column ordering.

    Compatibility Note: Tested with CmdStan v2.38. The format is not formally versioned and may change in future releases.

  8. Construct and index Chains objects

    main

    A Chains object stores MCMC samples. You can construct it by providing a raw array of values and an optional vector of parameter names. If names are not provided, parameters are named param_i (where i is the index).

    Indexing: Chains supports standard Julia indexing. You can slice by samples, parameters, and chains using the format chn[samples, parameters, chains].

    Example of creating a Chains object with 500 samples, 2 named parameters (:a and :b), and 3 chains:

    using MCMCChains
    using Random
    Random.seed!(0)
    
    val = rand(500, 2, 3)
    chn = Chains(val, [:a, :b])
    
    # Accessing specific slices
    chn_param2 = chn[1:5, 2, :]
    
    # Assigning values to a specific parameter index
    chn[:, 2, :] = fill(4, 100, 1, 2)
  9. Save and load Chains using Serialization

    main

    You can persist Chains objects using Julia's built-in Serialization module.

    Warning: Serialization may fail if loading the file in a different version of Julia or a different system image. For cross-version compatibility, consider using MCMCChainsStorage.jl (for HDF5) or JLSO.jl (for metadata preservation).

    using Serialization
    
    # Save to file
    serialize("chain-file.jls", chn)
    
    # Load from file
    chn2 = deserialize("chain-file.jls")
  10. Plot MCMCChains.jl samples using Makie.jl

    main

    You can visualize MCMC chains by plotting the drawn samples at each iteration using Makie.jl (or CairoMakie.jl for SVG output). This involves iterating through the parameters and chains in a Chains object and using lines! to plot the values over the iteration index.

    To implement this, you typically:

    1. Extract parameter names using names(chns, :parameters).
    2. Determine the number of chains and samples using length(chains(chns)) and length(chns).
    3. Loop through parameters to create an Axis for each, then loop through chains to plot chns[:, param, chain] against the iteration range 1:n_samples.
    using MCMCChains
    using CairoMakie
    
    # Setup sample data
    chns = Chains(randn(300, 5, 3), [:A, :B, :C, :D, :E])
    CairoMakie.activate!(; type="svg")
    
    params = names(chns, :parameters)
    n_chains = length(chains(chns))
    n_samples = length(chns)
    
    fig = Figure(; resolution=(1_000, 800))
    
    for (i, param) in enumerate(params)
        ax = Axis(fig[i, 1]; ylabel=string(param))
        for chain in 1:n_chains
            values = chns[:, param, chain]
            lines!(ax, 1:n_samples, values; label=string(chain))
        end
        hideydecorations!(ax; label=false)
        if i < length(params)
            hidexdecorations!(ax; grid=false)
        else
            ax.xlabel = "Iteration"
        end
    end
    
    fig
  11. Visualize MCMC simulation results with StatsPlots.jl

    main

    MCMCChains integrates with StatsPlots.jl to provide high-level plotting functions for Chains objects. You can use the generic plot() function with various seriestype arguments or use specialized shorthand functions for specific diagnostic plots.

    using MCMCChains
    using StatsPlots
    
    # Assuming 'chn' is a Chains object
    plot(chn; size=(840, 600))
    
    # Color by parameter
    plot(chn, colordim = :parameter; size=(840, 400))
  12. Install and use MCMCChains.jl for basic plotting

    main

    MCMCChains.jl provides Julia types for summarizing MCMC (Markov Chain Monte Carlo) simulations, along with utility functions for diagnostics and visualizations. To perform basic plotting of your chains, you need both MCMCChains and StatsPlots loaded in your environment.

    using MCMCChains
    using StatsPlots
    
    # Assuming 'chn' is an instance of a MCMCChains object
    plot(chn)