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 | |
| 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 | |
| 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."