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
    try:
        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 "Error: 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 "Error: 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 "Error: Invalid input: df must be an integer."
        if df < len(scale):
            return "Error: 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"Error: 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 "Error: Invalid input: size must be an integer."
        if wishart_method == 'rvs' and size < 1:
            return "Error: 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 "Error: Invalid input: scale and x must contain numeric values."
        # Check positive definiteness
        try:
            np.linalg.cholesky(scale_np)
        except Exception:
            return "Error: 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 "Error: 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"Error: 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 "Error: 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"Error: scipy.stats.wishart error: {e}"
            return arrays_to_2dlist(samples)
        return "Error: Unknown error."
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator