WISHART

Overview

The WISHART function computes the probability density function (PDF), log-PDF, or draws random samples from the Wishart distribution, a multivariate generalization of the chi-squared distribution to multiple dimensions. Named after statistician John Wishart who first formulated it in 1928, this distribution is defined over symmetric, positive-definite random matrices and plays a central role in multivariate statistical analysis.

The Wishart distribution is denoted W_p(\nu, \Sigma) where \nu represents the degrees of freedom and \Sigma is the p \times p positive-definite scale matrix. The distribution arises naturally as the sampling distribution of the sample covariance matrix for data drawn from a multivariate normal distribution. In Bayesian statistics, the Wishart distribution serves as the conjugate prior for the precision matrix (inverse of the covariance matrix) of a multivariate normal distribution.

For a random matrix S \sim W_p(\nu, \Sigma), the probability density function is:

f(S) = \frac{|S|^{(\nu - p - 1)/2}}{2^{\nu p/2} |\Sigma|^{\nu/2} \Gamma_p(\nu/2)} \exp\left(-\frac{1}{2} \text{tr}(\Sigma^{-1} S)\right)

where |S| denotes the determinant of S, \text{tr}(\cdot) is the trace function, and \Gamma_p(\cdot) is the multivariate gamma function. The degrees of freedom \nu must satisfy \nu \geq p for the distribution to have a density.

The Wishart distribution has important connections to other distributions. When p = 1 and \Sigma = 1, it reduces to the chi-squared distribution with \nu degrees of freedom. The inverse of a Wishart-distributed matrix follows the inverse-Wishart distribution. This implementation uses the scipy.stats.wishart module from the SciPy library, which employs the Bartlett decomposition algorithm for efficient random variate generation.

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

Excel Usage

=WISHART(x, df, scale, wishart_method, size)
  • x (list[list], required): Square matrix at which to evaluate the PDF or log-PDF.
  • df (int, required): Degrees of freedom, must be >= dimension of the scale matrix.
  • scale (list[list], required): Symmetric positive definite scale matrix.
  • wishart_method (str, optional, default: “pdf”): Method to compute - pdf, logpdf, or rvs.
  • size (int, optional, default: 1): Number of random samples to draw when method is rvs.

Returns (list[list]): 2D list of results, or error message string.

Examples

Example 1: PDF evaluation

Inputs:

x df scale wishart_method
2 0.5 4 1 0.2 pdf
0.5 1 0.2 0.5

Excel formula:

=WISHART({2,0.5;0.5,1}, 4, {1,0.2;0.2,0.5}, "pdf")

Expected output:

Result
0.0352

Example 2: PDF with different parameters

Inputs:

x df scale wishart_method
1 0.1 3 2 0.5 pdf
0.1 0.8 0.5 1

Excel formula:

=WISHART({1,0.1;0.1,0.8}, 3, {2,0.5;0.5,1}, "pdf")

Expected output:

Result
0.0168

Example 3: Log-PDF evaluation

Inputs:

x df scale wishart_method
2 0.5 4 1 0.2 logpdf
0.5 1 0.2 0.5

Excel formula:

=WISHART({2,0.5;0.5,1}, 4, {1,0.2;0.2,0.5}, "logpdf")

Expected output:

Result
-3.3478

Example 4: Log-PDF with different parameters

Inputs:

x df scale wishart_method
1 0.1 3 2 0.5 logpdf
0.1 0.8 0.5 1

Excel formula:

=WISHART({1,0.1;0.1,0.8}, 3, {2,0.5;0.5,1}, "logpdf")

Expected output:

Result
-4.0847

Python Code

import numpy as np
from scipy.stats import wishart as scipy_wishart

def wishart(x, df, scale, wishart_method='pdf', size=1):
    """
    Computes the PDF, log-PDF, or draws random samples from the Wishart distribution using scipy.stats.wishart.

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

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

    Args:
        x (list[list]): Square matrix at which to evaluate the PDF or log-PDF.
        df (int): Degrees of freedom, must be >= dimension of the scale matrix.
        scale (list[list]): Symmetric positive definite scale matrix.
        wishart_method (str, optional): Method to compute - pdf, logpdf, or rvs. Valid options: PDF, Log-PDF, Random samples. Default is 'pdf'.
        size (int, optional): Number of random samples to draw when method is rvs. Default is 1.

    Returns:
        list[list]: 2D list of results, or error message string.
    """
    def to2d(val):
        return [[val]] if not isinstance(val, list) else val

    def arrays_to_2dlist(arr):
      arr = np.asarray(arr, dtype=float)
      if arr.ndim == 2:
        mats = [arr]
      elif arr.ndim == 3:
        mats = [arr[i] for i in range(arr.shape[0])]
      else:
        return "Invalid output: unexpected sample shape from scipy.stats.wishart."

      out = []
      for mat in mats:
        for row in mat:
          out.append([float(v) if np.isfinite(v) else None for v in row])
      return out

    x = to2d(x)
    scale = to2d(scale)

    # Validate scale matrix
    if not isinstance(scale, list) or len(scale) < 2 or not all(isinstance(row, list) and len(row) == len(scale) for row in scale):
        return "Invalid input: scale must be a 2D square list with at least two rows."
    # Validate x
    if not isinstance(x, list) or len(x) < 2 or not all(isinstance(row, list) and len(row) == len(x) for row in x):
        return "Invalid input: x must be a 2D square list with at least two rows."
    # Validate df (Excel may pass float for int)
    try:
        df = int(df)
    except (TypeError, ValueError):
        return "Invalid input: df must be an integer."
    if df < len(scale):
        return "Invalid input: df must be >= dimension of scale matrix."
    # Validate method
    valid_methods = {'pdf', 'logpdf', 'rvs'}
    if wishart_method not in valid_methods:
        return f"Invalid input: wishart_method must be one of {sorted(valid_methods)}."
    # Validate size (Excel may pass float for int)
    try:
        size = int(size)
    except (TypeError, ValueError):
        return "Invalid input: size must be an integer."
    if wishart_method == 'rvs' and size < 1:
        return "Invalid input: size must be a positive integer."
    try:
        scale_np = np.array(scale, dtype=float)
        x_np = np.array(x, dtype=float)
    except Exception:
        return "Invalid input: scale and x must contain numeric values."
    # Check positive definiteness
    try:
        np.linalg.cholesky(scale_np)
    except Exception:
        return "Invalid input: scale matrix must be symmetric positive definite."
    # PDF and logPDF require x to be a square matrix of same dimension as scale
    if wishart_method in ['pdf', 'logpdf']:
        if x_np.shape != scale_np.shape:
            return "Invalid input: x and scale must be square matrices of the same dimension."
        dist = scipy_wishart(df, scale_np)
        try:
            if wishart_method == 'pdf':
                val = dist.pdf(x_np)
            else:
                val = dist.logpdf(x_np)
        except Exception as e:
            return f"scipy.stats.wishart error: {e}"
        try:
          val_f = float(val)
        except Exception:
          return [[str(val)]]
        if np.isnan(val_f) or np.isinf(val_f):
          return "Invalid output: result is NaN or Inf."
        return [[val_f]]
    elif wishart_method == 'rvs':
        dist = scipy_wishart(df, scale_np)
        try:
            samples = dist.rvs(size=size)
        except Exception as e:
            return f"scipy.stats.wishart error: {e}"
        return arrays_to_2dlist(samples)
    return "Unknown error."

Online Calculator