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

Online Calculator