Posterior Summarization

Overview

Posterior distributions are the central object in Bayesian analysis because they convert prior beliefs and observed data into updated uncertainty about unknown quantities. Posterior summarization turns that full distribution into practical outputs for reporting and decision-making: point estimates, interval estimates, uncertainty measures, and threshold probabilities. In applied statistics, machine learning, and engineering, these summaries are what teams actually compare across models, communicate to stakeholders, and use in downstream risk decisions.

The unifying ideas in this category are Bayesian updating, discrete or sample-based approximation, and numerically stable computation. Conceptually, inference starts from p(\theta\mid x) \propto p(x\mid\theta)p(\theta), then extracts actionable summaries such as means, variances, entropy, MAP estimates, and tail probabilities. Many workflows operate on weighted posterior samples, where normalized weights \tilde{w}_i = w_i / \sum_j w_j define empirical expectations like \mathbb{E}[g(\theta)] \approx \sum_i \tilde{w}_i g(\theta_i). This makes summarization tools essential bridges between posterior computation and final analytical conclusions.

Implementation relies primarily on SciPy, especially scipy.stats and scipy.special. The category uses SciPy primitives such as bayes_mvs, entropy, logsumexp, and xlogy, with Excel-oriented wrappers for consistent 2D I/O and robust input handling.

For posterior location and spread, POSTERIOR_BMV and POSTERIOR_WMEANVAR provide complementary summaries. POSTERIOR_BMV targets continuous-sample Bayesian summaries for mean, variance, and standard deviation with credible intervals, making it useful when interval reporting is required. POSTERIOR_WMEANVAR focuses on weighted discrete posteriors or weighted samples, returning mean, variance, standard deviation, and effective sample size for diagnostic interpretation. Together, they support both model-based interval inference and sample/weight-based posterior moment analysis.

For information-theoretic and log-domain computations, POSTERIOR_ENTROPY, POSTERIOR_XLOGY, and POSTERIOR_LOGSUMEXP form a coherent toolkit. POSTERIOR_ENTROPY quantifies posterior uncertainty with Shannon entropy and compares distributions with KL divergence, which is central to model comparison and information gain analysis. POSTERIOR_XLOGY provides stable x\log(y) terms (including the important 0\log y = 0 convention), a building block for entropy and cross-entropy style expressions. POSTERIOR_LOGSUMEXP stabilizes computations of \log\sum_i e^{a_i} and weighted variants, which is critical for normalizing log-posteriors and aggregating log-weights without overflow or underflow.

For decision-oriented posterior reporting, POSTERIOR_MAP and POSTERIOR_TAILPROB summarize where posterior mass is concentrated and how much mass lies beyond a practical threshold. POSTERIOR_MAP returns the maximum a posteriori support value and its normalized probability, giving a direct “most plausible” point estimate for discrete support grids. POSTERIOR_TAILPROB computes exceedance or lower-tail probability under flexible inequality choices, which is especially useful for Bayesian go/no-go criteria and risk thresholds. Used together, these functions translate posterior distributions into explicit decisions with interpretable probability statements.

POSTERIOR_BMV

This function summarizes posterior uncertainty for the mean, variance, and standard deviation of a continuous sample using a Bayesian model with Jeffrey’s prior, following SciPy’s bayes_mvs implementation.

For each target quantity, it returns a posterior center estimate and a central credible interval with probability level \alpha.

If \theta denotes one of the target parameters and p(\theta \mid x) is the posterior density given data x, the reported center is the posterior mean:

\mathbb{E}[\theta \mid x]

and the interval is a central posterior interval satisfying:

P(\theta_{\text{lower}} \le \theta \le \theta_{\text{upper}} \mid x) = \alpha

Excel Usage

=POSTERIOR_BMV(data, alpha)
  • data (list[list], required): 2D array of numeric sample observations.
  • alpha (float, optional, default: 0.9): Credible interval probability level (unitless, between 0 and 1).

Returns (list[list]): 2D table containing statistic name, posterior center, and credible interval bounds.

Example 1: Posterior summaries for balanced sample with default alpha

Inputs:

data
6 9 12
7 8 13

Excel formula:

=POSTERIOR_BMV({6,9,12;7,8,13})

Expected output:

Statistic Center Lower Upper
Mean 9.16667 6.87407 11.4593
Variance 12.9444 3.50782 33.9015
StdDev 3.31475 1.87292 5.8225
Example 2: Posterior summaries with 95 percent credible interval

Inputs:

data alpha
5 8 9 10 12 0.95

Excel formula:

=POSTERIOR_BMV({5,8,9,10,12}, 0.95)

Expected output:

Statistic Center Lower Upper
Mean 8.8 5.58603 12.014
Variance 13.4 2.40504 55.3241
StdDev 3.24412 1.55082 7.43801
Example 3: Scalar input is normalized to one-cell 2D data with extra point

Inputs:

data alpha
4 6 0.9

Excel formula:

=POSTERIOR_BMV({4,6}, 0.9)

Expected output:

Statistic Center Lower Upper
Mean Infinity -1.31375 11.3138
Variance Infinity 0.520636 508.629
StdDev Infinity 0.721551 22.5528
Example 4: Integer and decimal observations are both processed

Inputs:

data
1 2.5
3 4.75
6 8

Excel formula:

=POSTERIOR_BMV({1,2.5;3,4.75;6,8})

Expected output:

Statistic Center Lower Upper
Mean 4.20833 2.10932 6.30734
Variance 10.8507 2.94044 28.4179
StdDev 3.03486 1.71477 5.33085

Python Code

Show Code
import numpy as np
from scipy.stats import bayes_mvs as scipy_bayes_mvs

def posterior_bmv(data, alpha=0.9):
    """
    Compute Bayesian posterior summaries for mean, variance, and standard deviation.

    See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.bayes_mvs.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        data (list[list]): 2D array of numeric sample observations.
        alpha (float, optional): Credible interval probability level (unitless, between 0 and 1). Default is 0.9.

    Returns:
        list[list]: 2D table containing statistic name, posterior center, and credible interval bounds.
    """
    try:
        def to2d(x):
            return [[x]] if not isinstance(x, list) else x

        data = to2d(data)

        if not isinstance(data, list) or not all(isinstance(row, list) for row in data):
            return "Error: data must be a 2D list"

        try:
            alpha = float(alpha)
        except (TypeError, ValueError):
            return "Error: alpha must be numeric"

        if alpha <= 0 or alpha >= 1:
            return "Error: alpha must be between 0 and 1"

        flat = []
        for row in data:
            for value in row:
                try:
                    flat.append(float(value))
                except (TypeError, ValueError):
                    continue

        if len(flat) < 2:
            return "Error: data must contain at least two numeric values"

        mean_res, var_res, std_res = scipy_bayes_mvs(flat, alpha=alpha)

        return [
            ["Statistic", "Center", "Lower", "Upper"],
            ["Mean", float(mean_res.statistic), float(mean_res.minmax[0]), float(mean_res.minmax[1])],
            ["Variance", float(var_res.statistic), float(var_res.minmax[0]), float(var_res.minmax[1])],
            ["StdDev", float(std_res.statistic), float(std_res.minmax[0]), float(std_res.minmax[1])]
        ]
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

2D array of numeric sample observations.
Credible interval probability level (unitless, between 0 and 1).

POSTERIOR_ENTROPY

This function computes Shannon entropy for a posterior probability distribution, or relative entropy (Kullback-Leibler divergence) when a reference distribution is also provided.

For posterior probabilities p_i, Shannon entropy is:

H(p) = -\sum_i p_i \log(p_i)

For posterior probabilities p_i and reference probabilities q_i, relative entropy is:

D_{\mathrm{KL}}(p\|q) = \sum_i p_i \log\left(\frac{p_i}{q_i}\right)

Inputs are normalized internally by SciPy when needed, and the logarithm base can be configured to report units such as nats or bits.

Excel Usage

=POSTERIOR_ENTROPY(pk, qk, base, axis, nan_policy, keepdims)
  • pk (list[list], required): 2D array of posterior probabilities or nonnegative weights.
  • qk (list[list], optional, default: null): 2D array of reference probabilities for relative entropy (unitless).
  • base (float, optional, default: null): Logarithm base for entropy units (unitless).
  • axis (int, optional, default: 0): Axis along which entropy is computed (dimensionless index).
  • nan_policy (str, optional, default: “propagate”): Rule for handling NaN values.
  • keepdims (bool, optional, default: false): Keep reduced dimensions in output shape.

Returns (list[list]): Entropy result returned as a 2D array for Excel compatibility.

Example 1: Shannon entropy in bits for a fair binary posterior

Inputs:

pk base
0.5 0.5 2

Excel formula:

=POSTERIOR_ENTROPY({0.5,0.5}, 2)

Expected output:

Result
0 0
Example 2: Relative entropy against a biased reference distribution

Inputs:

pk qk base
0.5 0.5 0.9 0.1 2

Excel formula:

=POSTERIOR_ENTROPY({0.5,0.5}, {0.9,0.1}, 2)

Expected output:

Result
0 0
Example 3: Entropy along columns for a two-row posterior table

Inputs:

pk axis
0.2 0.8 0
0.6 0.4

Excel formula:

=POSTERIOR_ENTROPY({0.2,0.8;0.6,0.4}, 0)

Expected output:

Result
0.562335 0.636514
Example 4: Entropy with retained dimensions for broadcast compatibility

Inputs:

pk axis keepdims
0.25 0.25 0.5 1 true

Excel formula:

=POSTERIOR_ENTROPY({0.25,0.25,0.5}, 1, TRUE)

Expected output:

1.03972

Python Code

Show Code
import numpy as np
from scipy.stats import entropy as scipy_entropy

def posterior_entropy(pk, qk=None, base=None, axis=0, nan_policy='propagate', keepdims=False):
    """
    Compute Shannon or relative entropy for posterior probability tables.

    See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.entropy.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        pk (list[list]): 2D array of posterior probabilities or nonnegative weights.
        qk (list[list], optional): 2D array of reference probabilities for relative entropy (unitless). Default is None.
        base (float, optional): Logarithm base for entropy units (unitless). Default is None.
        axis (int, optional): Axis along which entropy is computed (dimensionless index). Default is 0.
        nan_policy (str, optional): Rule for handling NaN values. Valid options: Propagate, Omit, Raise. Default is 'propagate'.
        keepdims (bool, optional): Keep reduced dimensions in output shape. Default is False.

    Returns:
        list[list]: Entropy result returned as a 2D array for Excel compatibility.
    """
    try:
        def to2d(x):
            return [[x]] if not isinstance(x, list) else x

        def to_excel_2d(value):
            arr = np.asarray(value)
            if arr.ndim == 0:
                return [[float(arr)]]
            if arr.ndim == 1:
                return [[float(v) for v in arr.tolist()]]
            if arr.ndim == 2:
                return [[float(v) for v in row] for row in arr.tolist()]
            flat = arr.ravel()
            return [[float(v) for v in flat.tolist()]]

        pk = to2d(pk)
        qk = None if qk is None else to2d(qk)

        if not isinstance(pk, list) or not all(isinstance(row, list) for row in pk):
            return "Error: pk must be a 2D list"

        try:
            pk_arr = np.array(pk, dtype=float)
        except Exception:
            return "Error: pk must contain numeric values"

        qk_arr = None
        if qk is not None:
            if not isinstance(qk, list) or not all(isinstance(row, list) for row in qk):
                return "Error: qk must be a 2D list"
            try:
                qk_arr = np.array(qk, dtype=float)
            except Exception:
                return "Error: qk must contain numeric values"

        axis_arg = None if axis is None else int(axis)
        base_arg = None if base is None else float(base)

        result = scipy_entropy(
            pk_arr,
            qk=qk_arr,
            base=base_arg,
            axis=axis_arg,
            nan_policy=nan_policy,
            keepdims=bool(keepdims)
        )

        return to_excel_2d(result)
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

2D array of posterior probabilities or nonnegative weights.
2D array of reference probabilities for relative entropy (unitless).
Logarithm base for entropy units (unitless).
Axis along which entropy is computed (dimensionless index).
Rule for handling NaN values.
Keep reduced dimensions in output shape.

POSTERIOR_LOGSUMEXP

This function computes the logarithm of summed exponentials in a numerically stable way, which is essential for posterior normalization in log space and aggregation of log-weights.

The core operation is:

\log\left(\sum_i e^{a_i}\right)

and with optional weights b_i:

\log\left(\sum_i b_i e^{a_i}\right)

Working in log space helps avoid overflow and underflow when posterior log densities span large ranges.

Excel Usage

=POSTERIOR_LOGSUMEXP(a, axis, b, keepdims, return_sign)
  • a (list[list], required): 2D array of log-space values.
  • axis (int, optional, default: null): Axis along which to aggregate (dimensionless index).
  • b (list[list], optional, default: null): Optional 2D array of linear-space scaling weights.
  • keepdims (bool, optional, default: false): Keep reduced dimensions in output shape.
  • return_sign (bool, optional, default: false): Return sign information for weighted sums that may be negative.

Returns (list[list]): Log-sum-exp result as a 2D array, or paired log-value/sign rows when return_sign is true.

Example 1: Stable aggregate for a single row of log values

Inputs:

a
0 1 2

Excel formula:

=POSTERIOR_LOGSUMEXP({0,1,2})

Expected output:

2.40761

Example 2: Weighted aggregate using posterior scaling factors

Inputs:

a b
0 1 2 1 2 1

Excel formula:

=POSTERIOR_LOGSUMEXP({0,1,2}, {1,2,1})

Expected output:

2.62652

Example 3: Axis reduction with retained dimensions

Inputs:

a axis keepdims
0 1 1 true
2 3

Excel formula:

=POSTERIOR_LOGSUMEXP({0,1;2,3}, 1, TRUE)

Expected output:

Result
1.31326
3.31326
Example 4: Signed output for mixed-sign weighted terms

Inputs:

a b return_sign
1 2 1 -1 true

Excel formula:

=POSTERIOR_LOGSUMEXP({1,2}, {1,-1}, TRUE)

Expected output:

Result
1.54132
-1

Python Code

Show Code
import numpy as np
from scipy.special import logsumexp as scipy_logsumexp

def posterior_logsumexp(a, axis=None, b=None, keepdims=False, return_sign=False):
    """
    Compute stable log-sum-exp aggregates for posterior normalization and evidence calculations.

    See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.logsumexp.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        a (list[list]): 2D array of log-space values.
        axis (int, optional): Axis along which to aggregate (dimensionless index). Default is None.
        b (list[list], optional): Optional 2D array of linear-space scaling weights. Default is None.
        keepdims (bool, optional): Keep reduced dimensions in output shape. Default is False.
        return_sign (bool, optional): Return sign information for weighted sums that may be negative. Default is False.

    Returns:
        list[list]: Log-sum-exp result as a 2D array, or paired log-value/sign rows when return_sign is true.
    """
    try:
        def to2d(v):
            return [[v]] if not isinstance(v, list) else v

        def to_excel_2d(value):
            arr = np.asarray(value)
            if arr.ndim == 0:
                return [[float(arr)]]
            if arr.ndim == 1:
                return [[float(val) for val in arr.tolist()]]
            if arr.ndim == 2:
                return [[float(val) for val in row] for row in arr.tolist()]
            flat = arr.ravel()
            return [[float(val) for val in flat.tolist()]]

        a = to2d(a)
        if not isinstance(a, list) or not all(isinstance(row, list) for row in a):
            return "Error: a must be a 2D list"

        try:
            a_arr = np.array(a, dtype=float)
        except Exception:
            return "Error: a must contain numeric values"

        b_arr = None
        if b is not None:
            b = to2d(b)
            if not isinstance(b, list) or not all(isinstance(row, list) for row in b):
                return "Error: b must be a 2D list"
            try:
                b_arr = np.array(b, dtype=float)
            except Exception:
                return "Error: b must contain numeric values"

        axis_arg = None if axis is None else int(axis)

        if return_sign:
            log_val, sign_val = scipy_logsumexp(
                a_arr,
                axis=axis_arg,
                b=b_arr,
                keepdims=bool(keepdims),
                return_sign=True
            )
            log_row = to_excel_2d(log_val)
            sign_row = to_excel_2d(sign_val)
            width = max(len(log_row[0]), len(sign_row[0])) if log_row and sign_row else 1
            padded_log = (log_row[0] + [""] * (width - len(log_row[0]))) if log_row else [""] * width
            padded_sign = (sign_row[0] + [""] * (width - len(sign_row[0]))) if sign_row else [""] * width
            return [padded_log, padded_sign]

        result = scipy_logsumexp(
            a_arr,
            axis=axis_arg,
            b=b_arr,
            keepdims=bool(keepdims),
            return_sign=False
        )
        return to_excel_2d(result)
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

2D array of log-space values.
Axis along which to aggregate (dimensionless index).
Optional 2D array of linear-space scaling weights.
Keep reduced dimensions in output shape.
Return sign information for weighted sums that may be negative.

POSTERIOR_MAP

This function finds the maximum a posteriori (MAP) estimate from discrete posterior support values and their associated probabilities or weights.

Let x_i be support values and p_i be nonnegative posterior weights normalized so that \sum_i p_i = 1. The MAP estimate is:

x_{\mathrm{MAP}} = x_{k}, \quad k = \arg\max_i p_i

The function returns both the MAP support value and its normalized posterior probability.

Excel Usage

=POSTERIOR_MAP(values, posterior)
  • values (list[list], required): 2D array of posterior support values.
  • posterior (list[list], required): 2D array of nonnegative posterior probabilities or weights.

Returns (list[list]): 2D table containing MAP value and MAP probability.

Example 1: MAP estimate from a unimodal posterior table

Inputs:

values posterior
1 2 3 4 0.1 0.2 0.5 0.2

Excel formula:

=POSTERIOR_MAP({1,2,3,4}, {0.1,0.2,0.5,0.2})

Expected output:

MAP Value MAP Probability
3 0.5
Example 2: Non-normalized posterior weights are normalized internally

Inputs:

values posterior
10 20 30 1 4 2

Excel formula:

=POSTERIOR_MAP({10,20,30}, {1,4,2})

Expected output:

MAP Value MAP Probability
20 0.571429
Example 3: Matrix-shaped support and posterior values are flattened consistently

Inputs:

values posterior
0 1 0.1 0.6
2 3 0.2 0.1

Excel formula:

=POSTERIOR_MAP({0,1;2,3}, {0.1,0.6;0.2,0.1})

Expected output:

MAP Value MAP Probability
1 0.6
Example 4: Scalar support with scalar posterior returns the same support value

Inputs:

values posterior
7 1

Excel formula:

=POSTERIOR_MAP(7, 1)

Expected output:

MAP Value MAP Probability
7 1

Python Code

Show Code
import numpy as np

def posterior_map(values, posterior):
    """
    Extract the MAP estimate from a tabulated posterior distribution.

    See: https://en.wikipedia.org/wiki/Maximum_a_posteriori_estimation

    This example function is provided as-is without any representation of accuracy.

    Args:
        values (list[list]): 2D array of posterior support values.
        posterior (list[list]): 2D array of nonnegative posterior probabilities or weights.

    Returns:
        list[list]: 2D table containing MAP value and MAP probability.
    """
    try:
        def to2d(v):
            return [[v]] if not isinstance(v, list) else v

        values = to2d(values)
        posterior = to2d(posterior)

        if not isinstance(values, list) or not all(isinstance(row, list) for row in values):
            return "Error: values must be a 2D list"
        if not isinstance(posterior, list) or not all(isinstance(row, list) for row in posterior):
            return "Error: posterior must be a 2D list"

        value_flat = []
        for row in values:
            for value in row:
                try:
                    value_flat.append(float(value))
                except (TypeError, ValueError):
                    continue

        posterior_flat = []
        for row in posterior:
            for prob in row:
                try:
                    posterior_flat.append(float(prob))
                except (TypeError, ValueError):
                    continue

        if len(value_flat) == 0:
            return "Error: values must contain at least one numeric value"
        if len(posterior_flat) == 0:
            return "Error: posterior must contain at least one numeric value"
        if len(value_flat) != len(posterior_flat):
            return "Error: values and posterior must contain the same number of numeric entries"

        posterior_arr = np.array(posterior_flat, dtype=float)
        if np.any(posterior_arr < 0):
            return "Error: posterior values must be nonnegative"

        total_prob = float(np.sum(posterior_arr))
        if total_prob <= 0:
            return "Error: posterior sum must be positive"

        posterior_arr = posterior_arr / total_prob
        value_arr = np.array(value_flat, dtype=float)

        map_idx = int(np.argmax(posterior_arr))
        map_value = float(value_arr[map_idx])
        map_prob = float(posterior_arr[map_idx])

        return [
            ["MAP Value", "MAP Probability"],
            [map_value, map_prob]
        ]
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

2D array of posterior support values.
2D array of nonnegative posterior probabilities or weights.

POSTERIOR_TAILPROB

This function calculates posterior exceedance or lower-tail probabilities from discrete posterior support values and associated probabilities.

For support values x_i with normalized posterior probabilities p_i, the exceedance probability above threshold t is:

P(X > t) = \sum_{i: x_i > t} p_i

Alternative tails such as X \ge t, X < t, and X \le t are also available for decision-oriented Bayesian summaries.

Excel Usage

=POSTERIOR_TAILPROB(values, posterior, threshold, tail)
  • values (list[list], required): 2D array of posterior support values.
  • posterior (list[list], required): 2D array of nonnegative posterior probabilities or weights.
  • threshold (float, required): Decision threshold for tail probability evaluation.
  • tail (str, optional, default: “greater”): Tail direction relative to threshold.

Returns (float): Posterior probability mass in the selected tail region.

Example 1: Exceedance probability above threshold

Inputs:

values posterior threshold tail
1 2 3 4 0.1 0.2 0.3 0.4 2.5 greater

Excel formula:

=POSTERIOR_TAILPROB({1,2,3,4}, {0.1,0.2,0.3,0.4}, 2.5, "greater")

Expected output:

0.7

Example 2: Lower-tail probability below threshold

Inputs:

values posterior threshold tail
1 2 3 4 0.1 0.2 0.3 0.4 2.5 less

Excel formula:

=POSTERIOR_TAILPROB({1,2,3,4}, {0.1,0.2,0.3,0.4}, 2.5, "less")

Expected output:

0.3

Example 3: Inclusive upper-tail probability at threshold value

Inputs:

values posterior threshold tail
0 1 2 1 2 3 1 greater_equal

Excel formula:

=POSTERIOR_TAILPROB({0,1,2}, {1,2,3}, 1, "greater_equal")

Expected output:

0.833333

Example 4: Scalar support and posterior with threshold comparison

Inputs:

values posterior threshold tail
5 1 4 greater

Excel formula:

=POSTERIOR_TAILPROB(5, 1, 4, "greater")

Expected output:

1

Python Code

Show Code
import numpy as np

def posterior_tailprob(values, posterior, threshold, tail='greater'):
    """
    Compute posterior tail probabilities relative to a decision threshold.

    See: https://en.wikipedia.org/wiki/Cumulative_distribution_function

    This example function is provided as-is without any representation of accuracy.

    Args:
        values (list[list]): 2D array of posterior support values.
        posterior (list[list]): 2D array of nonnegative posterior probabilities or weights.
        threshold (float): Decision threshold for tail probability evaluation.
        tail (str, optional): Tail direction relative to threshold. Valid options: Greater Than, Greater Than Or Equal, Less Than, Less Than Or Equal. Default is 'greater'.

    Returns:
        float: Posterior probability mass in the selected tail region.
    """
    try:
        def to2d(v):
            return [[v]] if not isinstance(v, list) else v

        values = to2d(values)
        posterior = to2d(posterior)

        if not isinstance(values, list) or not all(isinstance(row, list) for row in values):
            return "Error: values must be a 2D list"
        if not isinstance(posterior, list) or not all(isinstance(row, list) for row in posterior):
            return "Error: posterior must be a 2D list"

        value_flat = []
        for row in values:
            for value in row:
                try:
                    value_flat.append(float(value))
                except (TypeError, ValueError):
                    continue

        posterior_flat = []
        for row in posterior:
            for prob in row:
                try:
                    posterior_flat.append(float(prob))
                except (TypeError, ValueError):
                    continue

        if len(value_flat) == 0:
            return "Error: values must contain at least one numeric value"
        if len(posterior_flat) == 0:
            return "Error: posterior must contain at least one numeric value"
        if len(value_flat) != len(posterior_flat):
            return "Error: values and posterior must contain the same number of numeric entries"

        posterior_arr = np.array(posterior_flat, dtype=float)
        if np.any(posterior_arr < 0):
            return "Error: posterior values must be nonnegative"

        total_prob = float(np.sum(posterior_arr))
        if total_prob <= 0:
            return "Error: posterior sum must be positive"

        posterior_arr = posterior_arr / total_prob
        value_arr = np.array(value_flat, dtype=float)
        threshold = float(threshold)

        if tail == "greater":
            mask = value_arr > threshold
        elif tail == "greater_equal":
            mask = value_arr >= threshold
        elif tail == "less":
            mask = value_arr < threshold
        elif tail == "less_equal":
            mask = value_arr <= threshold
        else:
            return "Error: tail must be one of greater, greater_equal, less, less_equal"

        return float(np.sum(posterior_arr[mask]))
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

2D array of posterior support values.
2D array of nonnegative posterior probabilities or weights.
Decision threshold for tail probability evaluation.
Tail direction relative to threshold.

POSTERIOR_WMEANVAR

This function computes weighted posterior moments for a discrete approximation to a posterior distribution or weighted posterior samples.

Given values x_i and nonnegative weights w_i, normalized weights are:

\tilde{w}_i = \frac{w_i}{\sum_j w_j}

The posterior weighted mean and variance are:

\mu = \sum_i \tilde{w}_i x_i, \qquad \sigma^2 = \sum_i \tilde{w}_i (x_i - \mu)^2

The function also reports posterior standard deviation and effective sample size based on normalized weights.

Excel Usage

=POSTERIOR_WMEANVAR(values, weights)
  • values (list[list], required): 2D array of posterior support values.
  • weights (list[list], optional, default: null): 2D array of nonnegative posterior weights aligned with values.

Returns (list[list]): 2D table of weighted posterior summary metrics and values.

Example 1: Unweighted posterior moments from a symmetric support

Inputs:

values
1 2 3 4

Excel formula:

=POSTERIOR_WMEANVAR({1,2,3,4})

Expected output:

Metric Value
Mean 2.5
Variance 1.25
StdDev 1.11803
EffectiveSampleSize 4
Example 2: Weighted posterior mean shifts toward larger support values

Inputs:

values weights
1 2 3 4 1 1 2 4

Excel formula:

=POSTERIOR_WMEANVAR({1,2,3,4}, {1,1,2,4})

Expected output:

Metric Value
Mean 3.125
Variance 1.10938
StdDev 1.05327
EffectiveSampleSize 2.90909
Example 3: Matrix-shaped values and weights are flattened consistently

Inputs:

values weights
0 1 1 2
2 3 3 4

Excel formula:

=POSTERIOR_WMEANVAR({0,1;2,3}, {1,2;3,4})

Expected output:

Metric Value
Mean 2
Variance 1
StdDev 1
EffectiveSampleSize 3.33333
Example 4: Scalar posterior support with implicit unit weight

Inputs:

values
5

Excel formula:

=POSTERIOR_WMEANVAR(5)

Expected output:

Metric Value
Mean 5
Variance 0
StdDev 0
EffectiveSampleSize 1

Python Code

Show Code
import numpy as np

def posterior_wmeanvar(values, weights=None):
    """
    Compute posterior weighted mean and variance summaries from values and weights.

    See: https://en.wikipedia.org/wiki/Weighted_arithmetic_mean

    This example function is provided as-is without any representation of accuracy.

    Args:
        values (list[list]): 2D array of posterior support values.
        weights (list[list], optional): 2D array of nonnegative posterior weights aligned with values. Default is None.

    Returns:
        list[list]: 2D table of weighted posterior summary metrics and values.
    """
    try:
        def to2d(v):
            return [[v]] if not isinstance(v, list) else v

        values = to2d(values)
        weights = None if weights is None else to2d(weights)

        if not isinstance(values, list) or not all(isinstance(row, list) for row in values):
            return "Error: values must be a 2D list"

        val_flat = []
        for row in values:
            for value in row:
                try:
                    val_flat.append(float(value))
                except (TypeError, ValueError):
                    continue

        if len(val_flat) == 0:
            return "Error: values must contain at least one numeric value"

        val_arr = np.array(val_flat, dtype=float)

        if weights is None:
            weight_arr = np.ones_like(val_arr)
        else:
            if not isinstance(weights, list) or not all(isinstance(row, list) for row in weights):
                return "Error: weights must be a 2D list"

            weight_flat = []
            for row in weights:
                for value in row:
                    try:
                        weight_flat.append(float(value))
                    except (TypeError, ValueError):
                        continue

            if len(weight_flat) != len(val_flat):
                return "Error: weights must contain the same number of numeric entries as values"

            weight_arr = np.array(weight_flat, dtype=float)

        if np.any(weight_arr < 0):
            return "Error: weights must be nonnegative"

        total_weight = float(np.sum(weight_arr))
        if total_weight <= 0:
            return "Error: sum of weights must be positive"

        norm_weights = weight_arr / total_weight
        mean_val = float(np.sum(norm_weights * val_arr))
        var_val = float(np.sum(norm_weights * (val_arr - mean_val) ** 2))
        std_val = float(np.sqrt(var_val))
        ess_val = float(1.0 / np.sum(norm_weights ** 2))

        return [
            ["Metric", "Value"],
            ["Mean", mean_val],
            ["Variance", var_val],
            ["StdDev", std_val],
            ["EffectiveSampleSize", ess_val]
        ]
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

2D array of posterior support values.
2D array of nonnegative posterior weights aligned with values.

POSTERIOR_XLOGY

This function computes x \log(y) with numerical protection at x=0, where the term is defined to be zero instead of producing undefined arithmetic.

The stabilized elementwise transformation is:

f(x, y) = x\log(y), \quad \text{with } f(0, y)=0

This is useful in posterior information summaries such as entropy and cross-entropy terms where zero-probability weights should contribute exactly zero.

Excel Usage

=POSTERIOR_XLOGY(x, y)
  • x (list[list], required): 2D array of multipliers (unitless).
  • y (list[list], required): 2D array of logarithm arguments (unitless).

Returns (list[list]): Elementwise xlogy values as a 2D array.

Example 1: Stable xlogy terms for binary posterior probabilities

Inputs:

x y
0.5 0.5 0.5 0.5

Excel formula:

=POSTERIOR_XLOGY({0.5,0.5}, {0.5,0.5})

Expected output:

Result
-0.346574 -0.346574
Example 2: Zero multipliers produce zero contributions

Inputs:

x y
0 1 0.2 0.8

Excel formula:

=POSTERIOR_XLOGY({0,1}, {0.2,0.8})

Expected output:

Result
0 -0.223144
Example 3: Matrix input shape is preserved in output

Inputs:

x y
0.1 0.2 0.9 0.8
0.3 0.4 0.7 0.6

Excel formula:

=POSTERIOR_XLOGY({0.1,0.2;0.3,0.4}, {0.9,0.8;0.7,0.6})

Expected output:

Result
-0.0105361 -0.0446287
-0.107002 -0.20433
Example 4: Scalar inputs are normalized to single-cell 2D arrays

Inputs:

x y
0.25 0.5

Excel formula:

=POSTERIOR_XLOGY(0.25, 0.5)

Expected output:

-0.173287

Python Code

Show Code
import numpy as np
from scipy.special import xlogy as scipy_xlogy

def posterior_xlogy(x, y):
    """
    Compute numerically stable x times log y terms for posterior information calculations.

    See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.xlogy.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        x (list[list]): 2D array of multipliers (unitless).
        y (list[list]): 2D array of logarithm arguments (unitless).

    Returns:
        list[list]: Elementwise xlogy values as a 2D array.
    """
    try:
        def to2d(v):
            return [[v]] if not isinstance(v, list) else v

        def to_excel_2d(value):
            arr = np.asarray(value)
            if arr.ndim == 0:
                return [[float(arr)]]
            if arr.ndim == 1:
                return [[float(val) for val in arr.tolist()]]
            if arr.ndim == 2:
                return [[float(val) for val in row] for row in arr.tolist()]
            flat = arr.ravel()
            return [[float(val) for val in flat.tolist()]]

        x = to2d(x)
        y = to2d(y)

        if not isinstance(x, list) or not all(isinstance(row, list) for row in x):
            return "Error: x must be a 2D list"
        if not isinstance(y, list) or not all(isinstance(row, list) for row in y):
            return "Error: y must be a 2D list"

        try:
            x_arr = np.array(x, dtype=float)
            y_arr = np.array(y, dtype=float)
        except Exception:
            return "Error: x and y must contain numeric values"

        result = scipy_xlogy(x_arr, y_arr)
        return to_excel_2d(result)
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

2D array of multipliers (unitless).
2D array of logarithm arguments (unitless).