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, seed)
  • 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.
  • seed (int, optional, default: null): Random seed for reproducibility.

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

Example 1: PDF at origin with 2D standard t-distribution

Inputs:

x loc shape df mvt_method
0 0 0 1 0 2 pdf
0 0 1

Excel formula:

=MULTIVARIATE_T({0,0}, {0;0}, {1,0;0,1}, 2, "pdf")

Expected output:

0.159155

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:

0.25

Example 3: Draw random samples from 2D t-distribution

Inputs:

x loc shape df mvt_method size seed
0 0 0 1 0 2 rvs 2 42
0 0 1

Excel formula:

=MULTIVARIATE_T({0,0}, {0;0}, {1,0;0,1}, 2, "rvs", 2, 42)

Expected output:

Result
0.945487 2.2233
-0.134961 -0.134952
Example 4: PDF with default location and shape parameters

Inputs:

x mvt_method
1 1 pdf

Excel formula:

=MULTIVARIATE_T({1,1}, "pdf")

Expected output:

0.0306294

Python Code

Show 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, seed=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.
        seed (int, optional): Random seed for reproducibility. 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

    try:
        x = to2d(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 "Error: Invalid input: x must be a 2D list of floats."
        if len(x) == 0 or len(x[0]) == 0:
            return "Error: Invalid input: x must be a non-empty 2D list."
        dim = len(x[0])

        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 "Error: Invalid input: loc must be a 2D column vector (list of lists with one float each)."
            if len(loc) != dim:
                return "Error: Invalid input: loc must have the same number of rows as columns in x."
            loc_vec = [float(row[0]) for row in loc]
        else:
            loc_vec = [0.0] * dim

        if shape is not None:
            shape = to2d(shape)
            if not (
                isinstance(shape, list)
                and len(shape) == dim
                and all(
                    isinstance(row, list)
                    and len(row) == dim
                    and all(isinstance(val, (int, float)) for val in row)
                    for row in shape
                )
            ):
                return "Error: Invalid input: shape must be a 2D list of floats with shape (dim, dim)."
            shape_mat = [[float(val) for val in row] for row in shape]
        else:
            shape_mat = [[float(i == j) for j in range(dim)] for i in range(dim)]

        try:
            df_val = float(df) if df is not None else 1.0
        except Exception:
            return "Error: Invalid input: df must be a number."
        if df_val <= 0:
            return "Error: Invalid input: df must be greater than zero."

        valid_methods = {"pdf", "cdf", "rvs"}
        if mvt_method not in valid_methods:
            return f"Error: Invalid input: mvt_method must be one of {sorted(valid_methods)}."

        size_val = None
        if mvt_method == "rvs":
            if size is None:
                return "Error: Invalid input: size must be specified for 'rvs' method."
            try:
                size_val = int(size)
            except Exception:
                return "Error: Invalid input: size must be an integer."
            if size_val <= 0:
                return "Error: Invalid input: size must be a positive integer."

        try:
            dist = scipy_multivariate_t(loc=loc_vec, shape=shape_mat, df=df_val)
        except Exception as e:
            return f"Error: scipy.stats.multivariate_t error: {e}"

        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":
                rng_seed = int(seed) if seed is not None else None
                samples = dist.rvs(size=size_val, random_state=rng_seed)
                if dim == 1:
                    result = [[float(val)] for val in samples]
                else:
                    result = [[float(val) for val in row] for row in samples]
            else:
                return "Error: Invalid method."
        except Exception as e:
            return f"Error: scipy.stats.multivariate_t {mvt_method} error: {e}"

        for row in result:
            for val in row:
                if isinstance(val, float) and (math.isnan(val) or math.isinf(val)):
                    return "Error: Invalid output: result contains NaN or infinite values."
        return result
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

Points at which to evaluate the distribution. Each row is a point, each column is a dimension.
Location (mean) vector of the distribution as a column vector. Default is zero vector.
Positive semidefinite shape (covariance) matrix of the distribution. Default is identity matrix.
Degrees of freedom. Must be greater than zero.
Computation method to use.
Number of random samples to draw when method is rvs.
Random seed for reproducibility.