MULTIVARIATE_T
Overview
The MULTIVARIATE_T function computes the probability density function (PDF), cumulative distribution function (CDF), or draws random samples from a multivariate t-distribution. This distribution is a generalization of the univariate Student’s t-distribution to multiple dimensions and is commonly used in robust statistical inference, portfolio modeling, and Bayesian analysis where heavier tails are needed compared to the multivariate normal distribution.
The multivariate t-distribution is characterized by three parameters: a location vector \mu (the mean), a positive semidefinite shape matrix \Sigma (analogous to a covariance matrix), and the degrees of freedom \nu. When \nu \to \infty, the distribution converges to a multivariate normal distribution. Lower values of \nu produce heavier tails, making the distribution more robust to outliers.
This implementation uses the scipy.stats.multivariate_t class from SciPy, which provides efficient computation via scipy.stats. The source code is available in the SciPy GitHub repository.
The probability density function for a p-dimensional multivariate t-distribution is:
f(x) = \frac{\Gamma\left(\frac{\nu + p}{2}\right)}{\Gamma\left(\frac{\nu}{2}\right) \nu^{p/2} \pi^{p/2} |\Sigma|^{1/2}} \left[1 + \frac{1}{\nu}(x - \mu)^\top \Sigma^{-1} (x - \mu)\right]^{-(\nu + p)/2}
where \Gamma is the gamma function, \nu is the degrees of freedom (must be greater than zero), and |\Sigma| is the determinant of the shape matrix. The function supports three computation methods: pdf for probability density, cdf for cumulative probability, and rvs for generating random samples.
This example function is provided as-is without any representation of accuracy.
Excel Usage
=MULTIVARIATE_T(x, loc, shape, df, mvt_method, size)
x(list[list], optional, default: null): Points at which to evaluate the distribution. Each row is a point, each column is a dimension.loc(list[list], optional, default: null): Location (mean) vector of the distribution as a column vector. Default is zero vector.shape(list[list], optional, default: null): Positive semidefinite shape (covariance) matrix of the distribution. Default is identity matrix.df(float, optional, default: 1): Degrees of freedom. Must be greater than zero.mvt_method(str, optional, default: “pdf”): Computation method to use.size(int, optional, default: null): 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 at origin with 2D standard t-distribution
Inputs:
| x | loc | shape | df | mvt_method | ||
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 1 | 0 | 2 | |
| 0 | 0 | 1 |
Excel formula:
=MULTIVARIATE_T({0,0}, {0;0}, {1,0;0,1}, 2, "pdf")
Expected output:
| Result |
|---|
| 0.1592 |
Example 2: CDF at origin with 2D standard t-distribution
Inputs:
| x | loc | shape | df | mvt_method | ||
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 1 | 0 | 2 | cdf |
| 0 | 0 | 1 |
Excel formula:
=MULTIVARIATE_T({0,0}, {0;0}, {1,0;0,1}, 2, "cdf")
Expected output:
| Result |
|---|
| 0.25 |
Example 3: Draw random samples from 2D t-distribution
Inputs:
| x | loc | shape | df | mvt_method | size | ||
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 1 | 0 | 2 | rvs | 2 |
| 0 | 0 | 1 |
Excel formula:
=MULTIVARIATE_T({0,0}, {0;0}, {1,0;0,1}, 2, "rvs", 2)
Expected output:
"non-error"
Example 4: PDF with default location and shape parameters
Inputs:
| x | mvt_method | |
|---|---|---|
| 1 | 1 |
Excel formula:
=MULTIVARIATE_T({1,1}, "pdf")
Expected output:
| Result |
|---|
| 0.03063 |
Python Code
import math
from scipy.stats import multivariate_t as scipy_multivariate_t
def multivariate_t(x=None, loc=None, shape=None, df=1, mvt_method='pdf', size=None):
"""
Computes the PDF, CDF, or draws random samples from a multivariate t-distribution.
See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.multivariate_t.html
This example function is provided as-is without any representation of accuracy.
Args:
x (list[list], optional): Points at which to evaluate the distribution. Each row is a point, each column is a dimension. Default is None.
loc (list[list], optional): Location (mean) vector of the distribution as a column vector. Default is zero vector. Default is None.
shape (list[list], optional): Positive semidefinite shape (covariance) matrix of the distribution. Default is identity matrix. Default is None.
df (float, optional): Degrees of freedom. Must be greater than zero. Default is 1.
mvt_method (str, optional): Computation method to use. Valid options: PDF, CDF, RVS. Default is 'pdf'.
size (int, optional): Number of random samples to draw when method is rvs. Default is None.
Returns:
list[list]: 2D list of results, or error message string.
"""
def to2d(val):
return [[val]] if not isinstance(val, list) else val
# Normalize x
x = to2d(x)
# Validate x
if not isinstance(x, list) or not all(isinstance(row, list) and all(isinstance(val, (int, float)) for val in row) for row in x):
return "Invalid input: x must be a 2D list of floats."
if len(x) == 0 or len(x[0]) == 0:
return "Invalid input: x must be a non-empty 2D list."
dim = len(x[0])
# Validate loc
if loc is not None:
loc = to2d(loc)
if not (isinstance(loc, list) and all(isinstance(row, list) and len(row) == 1 and isinstance(row[0], (int, float)) for row in loc)):
return "Invalid input: loc must be a 2D column vector (list of lists with one float each)."
if len(loc) != dim:
return "Invalid input: loc must have the same number of rows as columns in x."
loc_vec = [row[0] for row in loc]
else:
loc_vec = [0.0] * dim
# Validate shape
if shape is not None:
shape = to2d(shape)
if not (isinstance(shape, list) and all(isinstance(row, list) and len(row) == dim and all(isinstance(val, (int, float)) for val in row) for row in shape)):
return "Invalid input: shape must be a 2D list of floats with shape (dim, dim)."
if len(shape) != dim:
return "Invalid input: shape must have the same number of rows as columns in x."
shape_mat = shape
else:
shape_mat = [[float(i == j) for j in range(dim)] for i in range(dim)]
# Validate df
try:
df_val = float(df) if df is not None else 1.0
except Exception:
return "Invalid input: df must be a number."
if df_val <= 0:
return "Invalid input: df must be greater than zero."
# Validate mvt_method
valid_methods = {'pdf', 'cdf', 'rvs'}
if mvt_method not in valid_methods:
return f"Invalid input: mvt_method must be one of {sorted(valid_methods)}."
# Validate size
if mvt_method == 'rvs':
if size is None:
return "Invalid input: size must be specified for 'rvs' method."
try:
size_val = int(size)
except Exception:
return "Invalid input: size must be an integer."
if size_val <= 0:
return "Invalid input: size must be a positive integer."
# Create distribution
try:
dist = scipy_multivariate_t(loc=loc_vec, shape=shape_mat, df=df_val)
except Exception as e:
return f"scipy.stats.multivariate_t error: {e}"
# Compute result
try:
if mvt_method == 'pdf':
result = [[float(dist.pdf(row))] for row in x]
elif mvt_method == 'cdf':
result = [[float(dist.cdf(row))] for row in x]
elif mvt_method == 'rvs':
samples = dist.rvs(size=size_val)
# If samples is 1D, wrap as 2D list
if dim == 1:
result = [[float(val)] for val in samples]
else:
result = [[float(val) for val in row] for row in samples]
except Exception as e:
return f"scipy.stats.multivariate_t {mvt_method} error: {e}"
# Check for invalid output values
for row in result:
for val in row:
if isinstance(val, float) and (math.isnan(val) or math.isinf(val)):
return "Invalid output: result contains NaN or infinite values."
return result