VONMISES_FISHER
Overview
The VONMISES_FISHER
function computes the probability density function (PDF), log-PDF, entropy, or draws random samples from the von Mises-Fisher distribution on the unit hypersphere. This distribution is widely used in directional statistics for modeling data distributed on the surface of a sphere or hypersphere, such as orientations, directions, or unit vectors in 3D or higher dimensions. The PDF is given by:
where is a unit vector, is the mean direction (unit vector), is the concentration parameter (), and is a normalization constant depending on the dimension and . For more details, see the scipy.stats.vonmises_fisher documentation .
This wrapper exposes only the most commonly used parameters: mean direction (mu
), concentration (kappa
), evaluation points (x
), method, and sample size. Parameters for random state and fitting are not supported. This example function is provided as-is without any representation of accuracy.
Usage
To use the function in Excel:
=VONMISES_FISHER(x, mu, kappa, [method], [size])
x
(2D list, required for ‘pdf’ and ‘logpdf’): Table of points (each row is a unit vector) at which to evaluate the function. Each row must have the same dimension asmu
.mu
(2D column vector, required): Mean direction of the distribution. Must be a unit vector (norm = 1), shape is{d,1}
.kappa
(float, required): Concentration parameter. Must be positive.method
(string, optional, default=pdf
): Which method to compute:pdf
,logpdf
,entropy
, orrvs
.size
(integer, optional, only forrvs
): Number of samples to draw if method isrvs
.
The function returns a 2D list of results for each input point (for pdf
and logpdf
), a single value for entropy
, or a 2D list of samples for rvs
. If the input is invalid, an error message (string) is returned.
Examples
Example 1: PDF at a Point
Inputs:
x | mu | kappa | method | ||||
---|---|---|---|---|---|---|---|
1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 2.0 |
Excel formula:
=VONMISES_FISHER({1,0,0}, {1;0;0}, 2, "pdf")
Expected output:
Result |
---|
0.324 |
Example 2: Log-PDF at a Point
Inputs:
x | mu | kappa | method | ||||
---|---|---|---|---|---|---|---|
1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 2.0 | logpdf |
Excel formula:
=VONMISES_FISHER({1,0,0}, {1;0;0}, 2, "logpdf")
Expected output:
Result |
---|
-1.126 |
Example 3: Entropy of the Distribution
Inputs:
mu | kappa | method | ||
---|---|---|---|---|
1.0 | 0.0 | 0.0 | 2.0 | entropy |
Excel formula:
=VONMISES_FISHER(, {1;0;0}, 2, "entropy")
Expected output:
Result |
---|
2.052 |
Example 4: Draw a Random Sample
Inputs:
mu | kappa | method | size | ||
---|---|---|---|---|---|
1.0 | 0.0 | 0.0 | 2.0 | rvs | 1 |
Excel formula:
=VONMISES_FISHER(, {1;0;0}, 2, "rvs", 1)
Expected output:
Result (sample) | ||
---|---|---|
(varies) |
The output for rvs
is a random unit vector sampled from the distribution; values will vary each time the function is called.
Python Code
from scipy.stats import vonmises_fisher as scipy_vonmises_fisher
from typing import List, Optional, Union
def vonmises_fisher(x: Optional[List[List[float]]] = None, mu: Optional[List[List[float]]] = None, kappa: Optional[float] = None, method: str = 'pdf', size: Optional[int] = None) -> Union[List[List[Optional[float]]], str]:
"""
Computes the PDF, log-PDF, entropy, or draws random samples from a von Mises-Fisher distribution on the unit hypersphere.
Args:
x: 2D list of float values. Points at which to evaluate the function (required for 'pdf' and 'logpdf').
mu: 2D list of float values (column vector). Mean direction of the distribution. Must be a unit vector. Required.
kappa: Concentration parameter (float). Must be positive. Required.
method: Which method to compute (str): 'pdf', 'logpdf', 'entropy', 'rvs'. Default is 'pdf'.
size: Number of samples to draw if method is 'rvs'. Optional.
Returns:
2D list of results for each input point, or an error message (str) if input is invalid.
This example function is provided as-is without any representation of accuracy.
"""
# Validate method
valid_methods = {'pdf', 'logpdf', 'entropy', 'rvs'}
if method not in valid_methods:
return f"Invalid method: {method}. Must be one of {valid_methods}."
# Validate mu
if mu is None or not isinstance(mu, list) or not all(isinstance(row, list) and len(row) == 1 for row in mu):
return "Invalid input: mu must be a 2D list (column vector) with shape (d, 1)."
try:
mu_vec = [float(row[0]) for row in mu]
except Exception:
return "Invalid input: mu must contain numeric values."
# Check if mu is a unit vector
import math
norm_mu = math.sqrt(sum(x**2 for x in mu_vec))
if not math.isclose(norm_mu, 1.0, rel_tol=1e-5):
return "Invalid input: mu must be a unit vector (norm = 1)."
# Validate kappa
if kappa is None:
return "Invalid input: kappa (concentration) must be specified."
try:
kappa_val = float(kappa)
except Exception:
return "Invalid input: kappa must be a float."
if kappa_val <= 0:
return "Invalid input: kappa must be positive."
dist = scipy_vonmises_fisher(mu=mu_vec, kappa=kappa_val)
import numpy as np
def to_native_float(val):
if isinstance(val, (float, int)):
return float(val)
if hasattr(val, 'item'):
return float(val.item())
return val
if method == 'entropy':
try:
ent = dist.entropy()
except Exception as e:
return f"scipy_vonmises_fisher entropy error: {e}"
return [[to_native_float(ent)]]
if method == 'rvs':
if size is None:
size_val = 1
else:
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 positive."
try:
samples = dist.rvs(size=size_val)
except Exception as e:
return f"scipy_vonmises_fisher rvs error: {e}"
arr = np.array(samples)
if arr.ndim == 1:
return [[to_native_float(x) for x in arr.tolist()]]
elif arr.ndim == 2:
return [[to_native_float(x) for x in row] for row in arr.tolist()]
else:
return "Invalid output shape from rvs."
# For pdf/logpdf, x is required
if x is None or not isinstance(x, list) or not all(isinstance(row, list) for row in x):
return "Invalid input: x must be a 2D list of points."
# Check each row in x matches mu dimension
if any(len(row) != len(mu_vec) for row in x):
return "Invalid input: each row in x must have the same dimension as mu."
results = []
for row in x:
try:
point = [float(val) for val in row]
except Exception:
results.append([None])
continue
try:
if method == 'pdf':
val = dist.pdf(point)
else:
val = dist.logpdf(point)
# Disallow nan/inf
val_native = to_native_float(val)
if isinstance(val_native, float) and (math.isnan(val_native) or math.isinf(val_native)):
results.append([None])
else:
results.append([val_native])
except Exception:
results.append([None])
return results