跳至主要内容

Python 概率分布教程

在本教程中,您将学习机器学习文献中常被引用的概率分布,以及如何用 Python 编码实现它们。
· 15分钟 阅读

使用 AI 探索

简介

概率与统计是数据科学的基石。事实上,机器学习与人工智能的底层原理离不开数理统计与线性代数。在数据科学中,您常常会遇到需要阅读包含大量数学内容的研究论文,以便理解某个特定主题。因此,如果您想提升数据科学能力,扎实的数学功底至关重要。本教程将介绍机器学习文献中常用的概率分布。如果您是初学者,这里就是理想的起点。在本教程中,您将:

  • 了解随机变量、密度曲线、概率函数等概率领域术语。
  • 了解不同的概率分布及其分布函数,以及它们的一些性质。
  • 学习在 Python 中创建并绘制这些分布。

在开始之前,您需要熟悉一些数学术语,下一节将对此进行介绍。

随机变量

随机变量是其可能取值为随机现象数值结果的变量。随机变量分为两类:离散型和连续型。

离散型随机变量只能取可数个不同的值,因此可以量化。举例来说,您可以将随机变量 $X$ 定义为掷一枚公平骰子时出现的点数。$X$ 可取值为 $[1,2,3,4,5,6]$,因此是离散型随机变量。

离散型随机变量的概率分布是该变量每个可能取值对应的概率列表,有时也称为概率函数或概率质量函数。形式化地,设随机变量 $X$ 可取 $k$ 个不同的值,且 $X = x_{i}$ 的概率为 $P(X = x_{i}) = p_{i}$。则这些概率 $p_{i}$ 必须满足:

1:对每个 $i$,0 < $p_{i}$ < 1

2:$p_{1} + p_{2} + ... + p_{k} = 1$。

常见的离散型概率分布包括伯努利分布、二项分布、泊松分布等。

连续型随机变量可以取无限多个可能值。比如,您可以将随机变量 $X$ 定义为某个班级学生的身高。由于连续型随机变量是在一个区间上定义的,通常用曲线下的面积(或积分)来表示。

连续型随机变量的概率分布称为概率分布函数,其取值是连续的。观察到任一单个值的概率等于 $0$,因为随机变量可能取值的数量是无限的。举例来说,随机变量 $X$ 可以在实数区间上取所有值。则 $X$ 落在结果集合 $A$ 中的概率 $P(A)$ 定义为 $A$ 上方且曲线下方的面积。该曲线表示函数 $p(x)$,并需满足:

1:曲线没有负值(对所有 $x$ 有 $(p(x) > 0$)

2:曲线下的总面积等于 $1$。

满足这些条件的曲线通常称为密度曲线。常见的连续型概率分布包括正态分布、指数分布、Beta 分布等。

还有一种在文献中经常出现、值得了解的分布,称为累计分布函数。所有随机变量(离散与连续)都有累计分布函数。它给出对于每个 $x$,随机变量 $X$ 小于或等于 $x$ 的概率。对于离散型随机变量,累计分布函数通过对概率求和得到。

下一节中,您将探讨一些重要分布,并尝试在 Python 中实现它们。在此之前,先导入将要用到的所有必要库。

# for inline plots in jupyter
%matplotlib inline
# import matplotlib
import matplotlib.pyplot as plt
# for latex equations
from IPython.display import Math, Latex
# for displaying images
from IPython.core.display import Image
# import seaborn
import seaborn as sns
# settings for seaborn plotting style
sns.set(color_codes=True)
# settings for seaborn plot sizes
sns.set(rc={'figure.figsize':(5,5)})

在线运行和编辑此教程中的代码

运行代码

均匀分布函数

或许最简单也最实用的分布之一就是均匀分布。连续型均匀分布的概率分布函数为:

Continuous Uniform Distribution Function

由于任意等宽区间被观察到的概率相同,描述该分布的曲线是一个矩形:在区间上高度为常数,其他地方高度为 0。因为曲线下的面积必须等于 1,区间的长度决定了曲线的高度。下图展示了区间 (a,b) 上的均匀分布。注意由于面积需要为 $1$,高度设为 $1/(b-a)$。

Visualize Uniform Distribution in Interval (A,B)

Python 中的均匀分布

您可以借助在区间 (a,b) 上取值的随机数生成器,在 Python 中可视化均匀分布。需要从 scipy.stats 模块导入 uniform 函数。

# import uniform distribution
from scipy.stats import uniform

uniform 函数通过其 loc 与 scale 参数在指定区间内生成连续的均匀随机变量。该分布在 loc 与 loc + scale 之间为常数。size 参数表示随机样本数量。若要保证结果可复现,可传入数值给 random_state 参数。

# random numbers from uniform distribution
n = 10000
start = 10
width = 20
data_uniform = uniform.rvs(size=n, loc = start, scale=width)

您可以使用 Seaborn 的 distplot 绘制刚创建分布的直方图。distplot 支持多个参数以自定义图形。首先创建一个绘图对象 ax。在这里,您可以指定直方图的 bins 数量、直方图的 color,并通过 kde 开启密度曲线,通过 hist_kws 设置线宽。还可以用 xlabel 与 ylabel 参数设置横纵轴标签。

ax = sns.distplot(data_uniform,
                  bins=100,
                  kde=True,
                  color='skyblue',
                  hist_kws={"linewidth": 15,'alpha':1})
ax.set(xlabel='Uniform Distribution ', ylabel='Frequency')
[Text(0,0.5,u'Frequency'), Text(0.5,0,u'Uniform Distribution ')]
Graphed Visualization of Uniform Distribution in Python

正态分布函数

正态分布(又称高斯分布)在数据科学中无处不在。尤其在统计推断等主题中您会频繁遇到它。许多数据科学算法也将其作为假设之一。

正态分布具有由其均值 $μ$ 与标准差 $σ$ 描述的钟形密度曲线。密度曲线关于均值对称,分散程度由标准差决定,表明靠近均值的数据出现更频繁,远离均值的数据出现较少。均值为 $μ$、标准差为 $σ$ 的正态密度曲线在给定点 $x$ 处的概率分布函数为:

Normal Distribution Function

下图展示了该分布的形状:

Visualization of Normal Distribution

约有 68% 的数据落在均值两侧一个标准差范围内,95% 落在两个标准差范围内。还值得一提的是,均值为 $0$、标准差为 $1$ 的分布称为标准正态分布。

Python 中的正态分布

您可以使用 scipy.stats 模块的 norm.rvs() 方法生成服从正态分布的随机变量。loc 参数对应分布的均值,scale 对应标准差,size 对应随机样本数量。若要保证结果可复现,可传入数值给 random_state 参数。

from scipy.stats import norm
# generate random numbers from N(0,1)
data_normal = norm.rvs(size=10000,loc=0,scale=1)

您可以像可视化均匀分布那样,使用 seaborn 的 distplot 来可视化该分布。参数含义与前一例相同。

ax = sns.distplot(data_normal,
                  bins=100,
                  kde=True,
                  color='skyblue',
                  hist_kws={"linewidth": 15,'alpha':1})
ax.set(xlabel='Normal Distribution', ylabel='Frequency')
[Text(0,0.5,u'Frequency'), Text(0.5,0,u'Normal Distribution')]
Graphed Visualization of Normal Distribution in Python

Gamma 分布函数

Gamma 分布是一类具有两个参数的连续概率分布。尽管其原始形式使用较少,但许多常用分布(如指数分布、卡方分布、Erlang 分布)都是 Gamma 分布的特例。Gamma 分布可用形状参数 $α = k$ 和逆尺度参数 $β = 1/θ$(也称速率参数)来参数化;符号 $Γ(n)$ 表示伽马函数,定义为 $(n-1)!$:

Gamma Distribution Function

典型的 Gamma 分布形状如下:

Visualization of Gamma Distribution

Python 中的 Gamma 分布

您可以使用 scipy.stats 模块的 gamma.rvs() 方法生成服从 Gamma 分布的随机变量,该方法以形状参数 $a$ 作为参数。当 $a$ 为整数时,Gamma 分布退化为 Erlang 分布;当 $a=1$ 时为指数分布。通过 loc 参数可平移分布,通过 scale 参数可缩放分布,size 决定样本数量。若要保证结果可复现,可传入数值给 random_state 参数。

from scipy.stats import gamma
data_gamma = gamma.rvs(a=5, size=10000)

您可以像在均匀分布部分所示那样,使用 seaborn 的 distplot 来可视化该分布。参数含义与均匀分布部分一致。

ax = sns.distplot(data_gamma,
                  kde=True,
                  bins=100,
                  color='skyblue',
                  hist_kws={"linewidth": 15,'alpha':1})
ax.set(xlabel='Gamma Distribution', ylabel='Frequency')
[Text(0,0.5,u'Frequency'), Text(0.5,0,u'Gamma Distribution')]
Graphed Visualization of Gamma Distribution in Python

指数分布函数

指数分布描述了泊松过程事件之间的时间间隔,即事件以恒定的平均速率连续且独立地发生。它具有参数 $λ$(称为速率参数),其公式为:

Exponential Distribution Function

一个递减的指数分布如下所示:

Visualization of Exponential Distribution

Python 中的指数分布

您可以使用 scipy.stats 模块的 expon.rvs() 方法生成服从指数分布的随机变量。该方法以形状参数 scale 作为参数,即公式中的 1/lambda。通过 loc 参数可平移分布,size 决定样本数量。若要保证结果可复现,可传入数值给 random_state 参数。

from scipy.stats import expon
data_expon = expon.rvs(scale=1,loc=0,size=1000)

再次使用 seaborn 可视化该分布,将得到如下曲线:

ax = sns.distplot(data_expon,
                  kde=True,
                  bins=100,
                  color='skyblue',
                  hist_kws={"linewidth": 15,'alpha':1})
ax.set(xlabel='Exponential Distribution', ylabel='Frequency')
[Text(0,0.5,u'Frequency'), Text(0.5,0,u'Exponential Distribution')]
Graphed Visualization of Exponential Distribution in Python

泊松分布

泊松随机变量通常用于建模在某个时间区间内事件发生的次数。例如,某段时间访问网站的用户数量可视为一个泊松过程。泊松分布用事件发生的速率($μ$)来描述。一个事件在区间内可能发生 0、1、2、… 次。区间内事件的平均发生次数记为 $λ$(lambda)。Lambda 是事件速率,也称速率参数。在区间内观察到 $k$ 次事件的概率为:

Poisson Distribution Function

注意,当参数 $λ →∞$ 时,正态分布是泊松分布的极限情形。此外,若随机事件之间的间隔时间服从参数为 $λ$ 的指数分布,则长度为 $t$ 的时间段内事件总数服从参数为 $λt$ 的泊松分布。

下图展示了典型的泊松分布:

Visualization of Poisson Distribution

Python 中的泊松分布

您可以使用 scipy.stats 模块的 poisson.rvs() 方法生成服从泊松分布的离散随机变量。该方法以 $μ$ 作为形状参数,即公式中的 $λ$。通过 loc 参数可平移分布,size 决定样本数量。若要保证结果可复现,可传入数值给 random_state 参数。

from scipy.stats import poisson
data_poisson = poisson.rvs(mu=3, size=10000)

您可以像可视化均匀分布那样,使用 seaborn 的 distplot 来可视化该分布。参数含义相同。

ax = sns.distplot(data_poisson,
                  bins=30,
                  kde=False,
                  color='skyblue',
                  hist_kws={"linewidth": 15,'alpha':1})
ax.set(xlabel='Poisson Distribution', ylabel='Frequency')
[Text(0,0.5,u'Frequency'), Text(0.5,0,u'Poisson Distribution')]
Graphed Visualization of Poisson Distribution in Python

二项分布函数

当一次试验只有两种可能结果(如成功或失败、盈利或亏损、胜或负),且每次试验成功与失败的概率相同,则该分布称为二项分布。不过,结果不必等可能,且各次试验彼此独立。二项分布的参数为 $n$ 和 $p$,其中 $n$ 为试验总次数,$p$ 为每次试验成功的概率。其概率分布函数为:

Binomial Distribution Function

其中:

Binomial Distribution Constant Function

Python 中的二项分布

您可以使用 scipy.stats 模块的 binom.rvs() 方法生成服从二项分布的离散随机变量。该方法以 $n$(试验次数)与 $p$(成功概率)作为形状参数。通过 loc 参数可平移分布,size 决定重复试验的次数。若要保证结果可复现,可传入数值给 random_state 参数。

from scipy.stats import binom
data_binom = binom.rvs(n=10,p=0.8,size=10000)

使用 seaborn 的 distplot 可视化该分布,会得到如下直方图:

ax = sns.distplot(data_binom,
                  kde=False,
                  color='skyblue',
                  hist_kws={"linewidth": 15,'alpha':1})
ax.set(xlabel='Binomial Distribution', ylabel='Frequency')
[Text(0,0.5,u'Frequency'), Text(0.5,0,u'Binomial Distribution')]
Graphed Visualization of Binomial Distribution in Python

注意,由于成功概率大于 $0.5$,该分布向右偏斜。此外,在以下条件下,泊松分布是二项分布的极限情形:

  1. 试验次数无限大,即 $n → ∞$。
  2. 每次试验成功的概率相同且无限小,即 $p →0$。
  3. $np = λ$ 为有限常数。

在以下条件下,正态分布是二项分布的另一种极限形式:

  1. 试验次数无限大,$n → ∞$。
  2. $p$ 与 $q$ 均非无限小。

伯努利分布函数

伯努利分布只有两种可能结果,即 $1$(成功)与 $0$(失败),且只有一次试验,例如一次抛硬币。因此,服从伯努利分布的随机变量 $X$ 以成功概率 $p$ 取值 $1$,以失败概率 $q$ 或 $1-p$ 取值 $0$。成功与失败的概率不必等可能。伯努利分布是二项分布在单次试验($n=1$)情形下的特例。其概率质量函数为:

Bernoulli Distribution Function

Python 中的伯努利分布

您可以使用 scipy.stats 模块的 bernoulli.rvs() 方法生成服从伯努利分布的离散随机变量。该方法以 $p$(成功概率)作为形状参数。通过 loc 参数可平移分布,size 决定重复试验的次数。若要保证结果可复现,可传入数值给 random_state 参数。

from scipy.stats import bernoulli
data_bern = bernoulli.rvs(size=10000,p=0.6)

再次对该分布进行可视化,您会看到只有两种可能结果:

ax= sns.distplot(data_bern,
                 kde=False,
                 color="skyblue",
                 hist_kws={"linewidth": 15,'alpha':1})
ax.set(xlabel='Bernoulli Distribution', ylabel='Frequency')
[Text(0,0.5,u'Frequency'), Text(0.5,0,u'Bernoulli Distribution')]
Graphed Visualization of Bernoulli Distribution in Python

结语

恭喜您读完本教程!在本教程中,您了解了几种常用概率分布,并学习了如何在 Python 中创建并绘制它们。虽然还有许多其他分布有待探索,但这些内容足以帮助您入门。别忘了查看 Python 的 scipy 库,它还提供了许多有趣的统计功能。祝您探索愉快!

如果您想进一步学习 Python 中的概率,请参加 DataCamp 的 Statistical Simulation in Python 课程。

查看我们的 Poker Probability and Statistics with Python 教程。

参考文献

主题