SciPy 离散拉普拉斯分布(discrete Laplace / dwaplace)完整指南:定义、性质与 scipy.stats.dlaplace 实战
2026/9/23 15:24:44 网站建设 项目流程

SciPy 离散拉普拉斯分布(discrete Laplace / dwaplace)完整指南:定义、性质与 scipy.stats.dlaplace 实战

【免费下载链接】scipySciPy library main repository项目地址: https://gitcode.com/gh_mirrors/sc/scipy

离散拉普拉斯分布(Discrete Laplacian / Two-sided Geometric Distribution)是定义在全体整数上的双尾几何型分布,在差分隐私、整数噪声建模等领域有直接应用。本文以 doc/source/tutorial/stats/discrete_dlaplace.rst 为骨架,结合 scipy/stats/_discrete_distns.py 中dlaplace_gen的完整实现与测试用例,系统讲解其概率质量函数、分布函数、分位数、矩母函数、矩、熵等全部数学定义,并给出可复制的 SciPy 实战代码。读完本文,你将能熟练使用scipy.stats.dlaplace完成概率计算、随机抽样、矩与熵的求解,并理解其与几何分布之间的深层联系。

分布定义:定义在全体整数上的双尾分布

离散拉普拉斯分布对全体整数 :math:k \in \mathbb{Z}定义,形状参数满足 :math:a>0。其概率质量函数(PMF)为:

p(k) = \tanh\left(\frac{a}{2}\right)\, e^{-a|k|}, \qquad k \in \mathbb{Z},\ a > 0

其中 :math:\tanh(a/2)是归一化常数。由于 :math:p(k) = p(-k),该分布关于 0 对称,且在 :math:k=0处取得最大概率 :math:p(0)=\tanh(a/2)。参数 :math:a越大,概率质量越向 0 集中,分布尾部越薄;:math:a越小,分布越平缓、尾部越厚。

这一点在源码中有直接印证。scipy/stats/_discrete_distns.py 中dlaplace_gen._pmf的实现与文档公式逐字对应:

def _pmf(self, k, a): # dlaplace.pmf(k) = tanh(a/2) * exp(-a*abs(k)) return tanh(a/2.0) * exp(-a * abs(k))

同时,_shape_info(L1510-L1511)将形状参数声明为严格正的开区间(0, inf),即a <= 0时分布不合法。这也解释了 scipy/stats/_distr_params.py 中把(-0.5,)列入该分布非法参数集(invaliddistparams)的测试原因。

累积分布函数(CDF)

记 :math:\lfloor x \rfloor为向下取整,CDF 为分段形式:

F(x) = \begin{cases} \dfrac{e^{a(\lfloor x \rfloor + 1)}}{e^{a} + 1}, & \lfloor x \rfloor < 0,\\[8pt] 1 - \dfrac{e^{-a \lfloor x \rfloor}}{e^{a} + 1}, & \lfloor x \rfloor \geq 0. \end{cases}

源码实现见 L1517-L1526,其中f1对应 :math:\lfloor x\rfloor \ge 0的分支,f2对应 :math:\lfloor x\rfloor < 0的分支,并通过xpx.apply_where(k >= 0, ...)按条件逐元素选择:

def _cdf(self, x, a): k = floor(x) def f1(k, a): return 1.0 - exp(-a * k) / (exp(a) + 1) def f2(k, a): return exp(a * (k + 1)) / (exp(a) + 1) return xpx.apply_where(k >= 0, (k, a), f1, f2)

分位函数(PPF / 逆 CDF)

分位函数同样为分段形式,:math:G(q) = F^{-1}(q)

G(q) = \begin{cases} \left\lceil \frac{1}{a}\log\left[q(e^{a}+1)\right] - 1 \right\rceil, & q < \frac{1}{1+e^{-a}},\\[8pt] \left\lceil -\frac{1}{a}\log\left[(1-q)(1+e^{a})\right] \right\rceil, & q \geq \frac{1}{1+e^{-a}}. \end{cases}

由于分布是离散的,CDF 存在平台区间,直接取整得到的候选值可能并非精确分位数。源码 L1528-L1534 因此在取整后额外做了一步校验:先计算valsvals - 1,再通过self._cdf(vals1, a) >= q判断是否取vals1,保证返回的是严格满足分位数定义的最小整数:

def _ppf(self, q, a): const = 1 + exp(a) vals = ceil(np.where(q < 1.0 / (1 + exp(-a)), log(q*const) / a - 1, -log((1-q) * const) / a)) vals1 = vals - 1 return np.where(self._cdf(vals1, a) >= q, vals1, vals)

矩母函数与矩:从 MGF 到多对数函数

矩母函数定义为 :math:M(t) = E[e^{tX}],对全部整数求和:

M(t) = \tanh\left(\frac{a}{2}\right)\sum_{k=-\infty}^{\infty} e^{tk} e^{-a|k|}

利用对称性拆分为正负两个几何级数后化简,得到闭式表达式:

M(t) = \frac{\tanh\left(\frac{a}{2}\right)\sinh a}{\cosh a - \cosh t}

由矩母函数在 0 处的导数可得 :math:n阶原点矩:

\mu_{n}' = M^{(n)}(0) = \left[1 + (-1)^{n}\right] \operatorname{Li}_{-n}\left(e^{-a}\right)

其中 :math:\operatorname{Li}_{-n}(z)是阶数为 :math:-n、在 :math:z处求值的多对数函数(polylogarithm)。由于因子 :math:[1+(-1)^n]在 :math:n为奇数时取 0,所有奇数阶矩恒为零——这正是对称分布的直接体现。

SciPy 并未逐阶求多对数,而是直接给出了前四阶累积量的闭式结果。源码 L1536-L1540:

def _stats(self, a): ea = exp(a) mu2 = 2.*ea/(ea-1.)**2 mu4 = 2.*ea*(ea**2+10.*ea+1.) / (ea-1.)**4 return 0., mu2, 0., mu4/mu2**2 - 3.

即:

  • 均值 :math:\mu = 0
  • 方差 :math:\operatorname{Var}(X) = \dfrac{2e^a}{(e^a - 1)^2}
  • 偏度 :math:0
  • 超额峰度 :math:\dfrac{\mu_4}{\mu_2^2} - 3 = \dfrac{e^{2a}+10e^a+1}{2e^a} - 3

测试 scipy/stats/tests/test_distributions.py 将上述闭式结果与"直接对 PMF 求和"的数值结果互验(a=1时在atol=1e-14, rtol=1e-8内一致),且断言(m, s) == (0, 0);L3338-L3343 还验证了特例:当 :math:a = \ln 2时方差恰为 :math:4、超额峰度恰为 :math:3.25,可作为手工核对公式的便捷锚点。

分布的(Shannon)熵为:

h[X] = -\log\left(\tanh\left(\frac{a}{2}\right)\right) + \frac{a}{\sinh a}

源码 L1542-L1543 与其完全一致:

def _entropy(self, a): return a / sinh(a) - log(tanh(a/2.0))

scipy.stats.dlaplace 实战用法

在 SciPy 中,该分布以stats.dlaplace形式暴露,并在 scipy/stats/init.py 的分布清单中列出("Discrete Laplacian")。所有离散分布统一支持loc位移参数与标准化的pmf/logpmf/cdf/ppf/isf/rvs/stats/entropy/moment/fit等接口。下面给出可直接运行的完整示例:

import numpy as np from scipy import stats a = 1.0 # 形状参数,必须 a > 0 k = np.arange(-5, 6) # 支持域为全体整数 # 概率质量函数与分布函数 pmf = stats.dlaplace.pmf(k, a) # tanh(a/2) * exp(-a|k|) cdf = stats.dlaplace.cdf(k, a) # 分段闭式公式 logpmf = stats.dlaplace.logpmf(k, a) # 数值更稳定的对数形式 # 分位数(离散分布经过最小整数校验) q = np.array([0.1, 0.5, 0.9]) ppf = stats.dlaplace.ppf(q, a) # 前四阶矩:均值、方差、偏度、峰度 mean, var, skew, kurt = stats.dlaplace.stats(a, moments='mvsk') # 期望结果:mean=0, skew=0 # var = 2*exp(a)/(exp(a)-1)**2 ≈ 3.16395(a=1 时) # 任意阶原点矩(n 为偶数时非零) m2 = stats.dlaplace.moment(2, a) # 与 var 一致 m4 = stats.dlaplace.moment(4, a) # 熵 ent = stats.dlaplace.entropy(a) # -log(tanh(a/2)) + a/sinh(a) # 随机抽样:固定随机种子保证可复现,返回整数数组 rng = np.random.default_rng(42) samples = stats.dlaplace.rvs(a, size=10000, random_state=rng) assert np.issubdtype(samples.dtype, np.integer) # 结果必为整数

需要位移时,直接传loc即可,例如stats.dlaplace.pmf(k, a, loc=5)将分布整体右移 5 个单位;抽样、矩与分位数均会自动按loc平移。

随机数生成原理:两个独立几何分布之差

dlaplace的随机抽样(L1545-L1564)没有使用通用的逆变换采样,而是利用了它与几何分布的结构等价性。源码注释给出了完整推导链条:

  1. 离散拉普拉斯分布等价于双面几何分布(two-sided geometric distribution),其 PMF 可写成:
    f(k) = \frac{1-\alpha}{1+\alpha}\,\alpha^{|k|}, \qquad \alpha = e^{-a}
  2. 双面几何分布又等价于两个独立同分布几何分布之差:若 :math:X, Y \overset{\text{iid}}{\sim} \mathrm{Geom}(p),则 :math:X - Y服从上述分布;
  3. 由此,Bernoulli 成功概率取 :math:p = 1 - e^{-a}(源码用-np.expm1(-a)数值稳定地计算 :math:1-e^{-a}),生成两个几何随机数并相减即可。

对应实现为:

def _rvs(self, a, size=None, random_state=None): probOfSuccess = -np.expm1(-np.asarray(a)) x = random_state.geometric(probOfSuccess, size=size) y = random_state.geometric(probOfSuccess, size=size) return x - y

由于 NumPy 的geometric返回正整数(成功次数),两者之差 :math:x-y天然覆盖全部整数,且分布关于 0 对称。测试 scipy/stats/tests/test_distributions.py 专门验证了rvs的结果形状、标量/数组两种调用方式,以及返回类型必须是整型(typecodes['AllInteger']),从侧面确认了这一实现路径。

易错点与注意事项

  • 形状参数必须严格为正a > 0。传入a <= 0会被_argcheck拒绝并抛出ValueError,scipy/stats/_distr_params.py 中的非法参数回归用例覆盖了该场景。
  • 离散分位数的平台问题:离散 CDF 是阶梯函数,直接对闭式公式取整可能落在平台内部;_ppf中"候选值与候选值减一"的两步校验(L1533-L1534)确保返回严格满足 :math:F(x-1) < q \le F(x)的整数。
  • fit的适用性dlaplace支持最大似然拟合,但由于支持域为全体整数且形状参数区间开放,建议结合实际数据分布先做目视检查;更稳妥的做法是使用stats.dlaplace.fit(data)后通过stats输出的矩信息交叉验证。
  • 默认形状参数哨兵值:源码末尾实例化为dlaplace = dlaplace_gen(a=-np.inf, name='dlaplace', ...)(L1567-L1568)。-inf仅为占位默认值,实际使用时必须显式传入合法的正形状参数a

进一步阅读

  • 相邻分布的教程页(在 doc/source/tutorial/stats/discrete.rst 的分发 toctree 中与discrete_dlaplace并列):discrete_geom(几何分布)、discrete_laplace的连续版laplace,以及同为长尾整数分布的discrete_zipfdiscrete_yulesimon
  • 核心实现:scipy/stats/_discrete_distns.py(dlaplace_gen类定义与实例化)。
  • 测试用例:scipy/stats/tests/test_distributions.py(TestDLaplacervs、矩公式互验与数值特例),以及 scipy/stats/tests/test_discrete_basic.py 中将其纳入全部离散分布通用测试套件(支持域、参数校验、冻结对象等)。

【免费下载链接】scipySciPy library main repository项目地址: https://gitcode.com/gh_mirrors/sc/scipy

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询