LOGSER
Overview
The LOGSER function computes values for the logarithmic distribution (also known as the logarithmic series distribution or log-series distribution), a discrete probability distribution commonly used in ecology to model relative species abundance. The distribution was first described by R. A. Fisher in 1943 to analyze the relationship between the number of species and the number of individuals in random samples of animal populations.
The logarithmic distribution is derived from the Maclaurin series expansion of the natural logarithm. The probability mass function (PMF) is defined as:
f(k) = \frac{-1}{\ln(1-p)} \cdot \frac{p^k}{k}
for k \geq 1 and 0 < p < 1, where p is the shape parameter. The normalization comes from the identity:
-\ln(1-p) = p + \frac{p^2}{2} + \frac{p^3}{3} + \cdots
This distribution has interesting properties: the mode is always 1 (the smallest possible value), and the distribution is highly right-skewed. A notable characteristic is that when Poisson-distributed random variables are compounded with log-series distributed random variables, the result follows a negative binomial distribution.
This implementation uses SciPy’s logser function from the scipy.stats module. The function supports multiple calculation modes including PMF, CDF, survival function (SF), inverse CDF (ICDF), inverse survival function (ISF), and summary statistics (mean, variance, standard deviation, median). A loc parameter allows shifting the distribution along the x-axis. For more details on the logarithmic distribution, see the Wikipedia article on the logarithmic distribution.
This example function is provided as-is without any representation of accuracy.
Excel Usage
=LOGSER(k, p, logser_mode, loc)
k(list[list], required): Value(s) at which to evaluate the distribution. For statistics modes (mean, var, std, median), this is ignored.p(float, required): Probability parameter (0 < p < 1).logser_mode(str, optional, default: “pmf”): Output type for the Log-Series distribution calculation.loc(float, optional, default: 0): Location parameter that shifts the distribution.
Returns (float): Distribution result (float), or error message string.
Examples
Example 1: PMF with required arguments only
Inputs:
| k | p |
|---|---|
| 3 | 0.5 |
Excel formula:
=LOGSER(3, 0.5)
Expected output:
0.0601
Example 2: CDF with some optional arguments
Inputs:
| k | p | logser_mode |
|---|---|---|
| 3 | 0.5 | cdf |
Excel formula:
=LOGSER(3, 0.5, "cdf")
Expected output:
0.9618
Example 3: Survival function with all arguments
Inputs:
| k | p | logser_mode | loc |
|---|---|---|---|
| 3 | 0.5 | sf | 0 |
Excel formula:
=LOGSER(3, 0.5, "sf", 0)
Expected output:
0.0382
Example 4: Inverse CDF for probability
Inputs:
| k | p | logser_mode | loc |
|---|---|---|---|
| 0.5 | 0.5 | icdf | 0 |
Excel formula:
=LOGSER(0.5, 0.5, "icdf", 0)
Expected output:
1
Example 5: Array input for PMF
Inputs:
| k | p | |
|---|---|---|
| 1 | 2 | 0.5 |
| 3 | 4 |
Excel formula:
=LOGSER({1,2;3,4}, 0.5)
Expected output:
| Result | |
|---|---|
| 0.7213 | 0.1803 |
| 0.0601 | 0.0225 |
Python Code
from scipy.stats import logser as scipy_logser
def logser(k, p, logser_mode='pmf', loc=0):
"""
Compute Log-Series distribution values: PMF, CDF, SF, ICDF, ISF, mean, variance, std, or median.
See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.logser.html
This example function is provided as-is without any representation of accuracy.
Args:
k (list[list]): Value(s) at which to evaluate the distribution. For statistics modes (mean, var, std, median), this is ignored.
p (float): Probability parameter (0 < p < 1).
logser_mode (str, optional): Output type for the Log-Series distribution calculation. Valid options: pmf, cdf, sf, icdf, isf, mean, var, std, median. Default is 'pmf'.
loc (float, optional): Location parameter that shifts the distribution. Default is 0.
Returns:
float: Distribution result (float), or error message string.
"""
# Helper to normalize 2D list args
def to2d(x):
return [[x]] if not isinstance(x, list) else x
# Validate p
try:
p_val = float(p)
if not (0 < p_val < 1):
return "Invalid input: p must be between 0 (exclusive) and 1 (exclusive)."
except Exception:
return "Invalid input: p must be a number."
# Validate loc
try:
loc_val = float(loc)
except Exception:
return "Invalid input: loc must be a number."
# Validate logser_mode
valid_modes = {"pmf", "cdf", "sf", "icdf", "isf", "mean", "var", "std", "median"}
if not isinstance(logser_mode, str) or logser_mode not in valid_modes:
return f"Invalid input: logser_mode must be one of {sorted(valid_modes)}."
# Handle statistics (ignore k)
if logser_mode in ["mean", "var", "std", "median"]:
if logser_mode == "mean":
return float(scipy_logser.mean(p_val, loc=loc_val))
if logser_mode == "var":
return float(scipy_logser.var(p_val, loc=loc_val))
if logser_mode == "std":
return float(scipy_logser.std(p_val, loc=loc_val))
if logser_mode == "median":
return float(scipy_logser.median(p_val, loc=loc_val))
# For other modes, k is required
k_is_scalar = not isinstance(k, list)
k_norm = to2d(k)
result = []
for row in k_norm:
if not isinstance(row, list):
return "Invalid input: k must be a scalar or 2D list."
result_row = []
for val in row:
try:
kval = float(val)
except Exception:
return "Invalid input: k must be a number."
if logser_mode == "pmf":
res = float(scipy_logser.pmf(kval, p_val, loc=loc_val))
elif logser_mode == "cdf":
res = float(scipy_logser.cdf(kval, p_val, loc=loc_val))
elif logser_mode == "sf":
res = float(scipy_logser.sf(kval, p_val, loc=loc_val))
elif logser_mode == "icdf":
res = float(scipy_logser.ppf(kval, p_val, loc=loc_val))
elif logser_mode == "isf":
res = float(scipy_logser.isf(kval, p_val, loc=loc_val))
result_row.append(res)
result.append(result_row)
if k_is_scalar and len(result) == 1 and len(result[0]) == 1:
return result[0][0]
return result