正文
python概率分布函数 python概率分布函数拟合
小程序:扫一扫查出行
【扫一扫了解最新限行尾号】
复制小程序
【扫一扫了解最新限行尾号】
复制小程序
python没有直接生成服从泊松分布随机数的函数吗
首先是泊松分布,这是一个离散型的随机变量分布,比较好弄,此外例如考察一些到达事件的概率时,通常服从泊松分布,因此该分布相当实用。在开始编写之前,先感谢知乎一位大神的科普知识,假设有一个服从均匀分布的随机变量,u~U[0,1],F(x)为随机变量x的累计分布函数,那么F-1(u)的变量服从F分布,即F的逆函数是服从F的随机变量。代码如下:
[java] view plain copy print?
span style="white-space:pre" /spanprivate static int getPossionVariable(double lamda) {
int x = 0;
double y = Math.random(), cdf = getPossionProbability(x, lamda);
while (cdf y) {
x++;
cdf += getPossionProbability(x, lamda);
}
return x;
}
private static double getPossionProbability(int k, double lamda) {
double c = Math.exp(-lamda), sum = 1;
for (int i = 1; i = k; i++) {
建议收藏!10 种 Python 聚类算法完整操作示例
聚类或聚类分析是无监督学习问题。它通常被用作数据分析技术,用于发现数据中的有趣模式,例如基于其行为的客户群。有许多聚类算法可供选择,对于所有情况,没有单一的最佳聚类算法。相反,最好探索一系列聚类算法以及每种算法的不同配置。在本教程中,你将发现如何在 python 中安装和使用顶级聚类算法。完成本教程后,你将知道:
聚类分析,即聚类,是一项无监督的机器学习任务。它包括自动发现数据中的自然分组。与监督学习(类似预测建模)不同,聚类算法只解释输入数据,并在特征空间中找到自然组或群集。
群集通常是特征空间中的密度区域,其中来自域的示例(观测或数据行)比其他群集更接近群集。群集可以具有作为样本或点特征空间的中心(质心),并且可以具有边界或范围。
聚类可以作为数据分析活动提供帮助,以便了解更多关于问题域的信息,即所谓的模式发现或知识发现。例如:
聚类还可用作特征工程的类型,其中现有的和新的示例可被映射并标记为属于数据中所标识的群集之一。虽然确实存在许多特定于群集的定量措施,但是对所识别的群集的评估是主观的,并且可能需要领域专家。通常,聚类算法在人工合成数据集上与预先定义的群集进行学术比较,预计算法会发现这些群集。
有许多类型的聚类算法。许多算法在特征空间中的示例之间使用相似度或距离度量,以发现密集的观测区域。因此,在使用聚类算法之前,扩展数据通常是良好的实践。
一些聚类算法要求您指定或猜测数据中要发现的群集的数量,而另一些算法要求指定观测之间的最小距离,其中示例可以被视为“关闭”或“连接”。因此,聚类分析是一个迭代过程,在该过程中,对所识别的群集的主观评估被反馈回算法配置的改变中,直到达到期望的或适当的结果。scikit-learn 库提供了一套不同的聚类算法供选择。下面列出了10种比较流行的算法:
每个算法都提供了一种不同的方法来应对数据中发现自然组的挑战。没有最好的聚类算法,也没有简单的方法来找到最好的算法为您的数据没有使用控制实验。在本教程中,我们将回顾如何使用来自 scikit-learn 库的这10个流行的聚类算法中的每一个。这些示例将为您复制粘贴示例并在自己的数据上测试方法提供基础。我们不会深入研究算法如何工作的理论,也不会直接比较它们。让我们深入研究一下。
在本节中,我们将回顾如何在 scikit-learn 中使用10个流行的聚类算法。这包括一个拟合模型的例子和可视化结果的例子。这些示例用于将粘贴复制到您自己的项目中,并将方法应用于您自己的数据。
1.库安装
首先,让我们安装库。不要跳过此步骤,因为你需要确保安装了最新版本。你可以使用 pip Python 安装程序安装 scikit-learn 存储库,如下所示:
接下来,让我们确认已经安装了库,并且您正在使用一个现代版本。运行以下脚本以输出库版本号。
运行该示例时,您应该看到以下版本号或更高版本。
2.聚类数据集
我们将使用 make _ classification ()函数创建一个测试二分类数据集。数据集将有1000个示例,每个类有两个输入要素和一个群集。这些群集在两个维度上是可见的,因此我们可以用散点图绘制数据,并通过指定的群集对图中的点进行颜色绘制。这将有助于了解,至少在测试问题上,群集的识别能力如何。该测试问题中的群集基于多变量高斯,并非所有聚类算法都能有效地识别这些类型的群集。因此,本教程中的结果不应用作比较一般方法的基础。下面列出了创建和汇总合成聚类数据集的示例。
运行该示例将创建合成的聚类数据集,然后创建输入数据的散点图,其中点由类标签(理想化的群集)着色。我们可以清楚地看到两个不同的数据组在两个维度,并希望一个自动的聚类算法可以检测这些分组。
已知聚类着色点的合成聚类数据集的散点图接下来,我们可以开始查看应用于此数据集的聚类算法的示例。我已经做了一些最小的尝试来调整每个方法到数据集。3.亲和力传播亲和力传播包括找到一组最能概括数据的范例。
它是通过 AffinityPropagation 类实现的,要调整的主要配置是将“ 阻尼 ”设置为0.5到1,甚至可能是“首选项”。下面列出了完整的示例。
运行该示例符合训练数据集上的模型,并预测数据集中每个示例的群集。然后创建一个散点图,并由其指定的群集着色。在这种情况下,我无法取得良好的结果。
数据集的散点图,具有使用亲和力传播识别的聚类
4.聚合聚类
聚合聚类涉及合并示例,直到达到所需的群集数量为止。它是层次聚类方法的更广泛类的一部分,通过 AgglomerationClustering 类实现的,主要配置是“ n _ clusters ”集,这是对数据中的群集数量的估计,例如2。下面列出了完整的示例。
运行该示例符合训练数据集上的模型,并预测数据集中每个示例的群集。然后创建一个散点图,并由其指定的群集着色。在这种情况下,可以找到一个合理的分组。
使用聚集聚类识别出具有聚类的数据集的散点图
5.BIRCHBIRCH
聚类( BIRCH 是平衡迭代减少的缩写,聚类使用层次结构)包括构造一个树状结构,从中提取聚类质心。
它是通过 Birch 类实现的,主要配置是“ threshold ”和“ n _ clusters ”超参数,后者提供了群集数量的估计。下面列出了完整的示例。
运行该示例符合训练数据集上的模型,并预测数据集中每个示例的群集。然后创建一个散点图,并由其指定的群集着色。在这种情况下,可以找到一个很好的分组。
使用BIRCH聚类确定具有聚类的数据集的散点图
6.DBSCANDBSCAN
聚类(其中 DBSCAN 是基于密度的空间聚类的噪声应用程序)涉及在域中寻找高密度区域,并将其周围的特征空间区域扩展为群集。
它是通过 DBSCAN 类实现的,主要配置是“ eps ”和“ min _ samples ”超参数。下面列出了完整的示例。
运行该示例符合训练数据集上的模型,并预测数据集中每个示例的群集。然后创建一个散点图,并由其指定的群集着色。在这种情况下,尽管需要更多的调整,但是找到了合理的分组。
使用DBSCAN集群识别出具有集群的数据集的散点图
7.K均值
K-均值聚类可以是最常见的聚类算法,并涉及向群集分配示例,以尽量减少每个群集内的方差。
它是通过 K-均值类实现的,要优化的主要配置是“ n _ clusters ”超参数设置为数据中估计的群集数量。下面列出了完整的示例。
运行该示例符合训练数据集上的模型,并预测数据集中每个示例的群集。然后创建一个散点图,并由其指定的群集着色。在这种情况下,可以找到一个合理的分组,尽管每个维度中的不等等方差使得该方法不太适合该数据集。
使用K均值聚类识别出具有聚类的数据集的散点图
8.Mini-Batch
K-均值Mini-Batch K-均值是 K-均值的修改版本,它使用小批量的样本而不是整个数据集对群集质心进行更新,这可以使大数据集的更新速度更快,并且可能对统计噪声更健壮。
它是通过 MiniBatchKMeans 类实现的,要优化的主配置是“ n _ clusters ”超参数,设置为数据中估计的群集数量。下面列出了完整的示例。
运行该示例符合训练数据集上的模型,并预测数据集中每个示例的群集。然后创建一个散点图,并由其指定的群集着色。在这种情况下,会找到与标准 K-均值算法相当的结果。
带有最小批次K均值聚类的聚类数据集的散点图
9.均值漂移聚类
均值漂移聚类涉及到根据特征空间中的实例密度来寻找和调整质心。
它是通过 MeanShift 类实现的,主要配置是“带宽”超参数。下面列出了完整的示例。
运行该示例符合训练数据集上的模型,并预测数据集中每个示例的群集。然后创建一个散点图,并由其指定的群集着色。在这种情况下,可以在数据中找到一组合理的群集。
具有均值漂移聚类的聚类数据集散点图
10.OPTICSOPTICS
聚类( OPTICS 短于订购点数以标识聚类结构)是上述 DBSCAN 的修改版本。
它是通过 OPTICS 类实现的,主要配置是“ eps ”和“ min _ samples ”超参数。下面列出了完整的示例。
运行该示例符合训练数据集上的模型,并预测数据集中每个示例的群集。然后创建一个散点图,并由其指定的群集着色。在这种情况下,我无法在此数据集上获得合理的结果。
使用OPTICS聚类确定具有聚类的数据集的散点图
11.光谱聚类
光谱聚类是一类通用的聚类方法,取自线性线性代数。
它是通过 Spectral 聚类类实现的,而主要的 Spectral 聚类是一个由聚类方法组成的通用类,取自线性线性代数。要优化的是“ n _ clusters ”超参数,用于指定数据中的估计群集数量。下面列出了完整的示例。
运行该示例符合训练数据集上的模型,并预测数据集中每个示例的群集。然后创建一个散点图,并由其指定的群集着色。在这种情况下,找到了合理的集群。
使用光谱聚类聚类识别出具有聚类的数据集的散点图
12.高斯混合模型
高斯混合模型总结了一个多变量概率密度函数,顾名思义就是混合了高斯概率分布。它是通过 Gaussian Mixture 类实现的,要优化的主要配置是“ n _ clusters ”超参数,用于指定数据中估计的群集数量。下面列出了完整的示例。
运行该示例符合训练数据集上的模型,并预测数据集中每个示例的群集。然后创建一个散点图,并由其指定的群集着色。在这种情况下,我们可以看到群集被完美地识别。这并不奇怪,因为数据集是作为 Gaussian 的混合生成的。
使用高斯混合聚类识别出具有聚类的数据集的散点图
在本文中,你发现了如何在 python 中安装和使用顶级聚类算法。具体来说,你学到了:
高中就开始学的正态分布,原来如此重要
我们从高中就开始学正态分布,现在做数据分析、机器学习还是离不开它,那你有没有想过正态分布有什么特别之处?为什么那么多关于数据科学和机器学习的文章都围绕正态分布展开?本文作者专门写了一篇文章,试着用易于理解的方式阐明正态分布的概念。
机器学习的世界是以概率分布为中心的,而概率分布的核心是正态分布。本文说明了什么是正态分布,以及为什么正态分布的使用如此广泛,尤其是对数据科学家和机器学习专家来说。
我们会从最基础的内容开始解释,以便读者们理解为什么正态分布如此重要。
目录:
Unsplash,由 timJ 发布。
先让我们来看一点背景知识:
1. 首先,要注意的最重要的一点是,正态分布也被称为高斯分布。
2. 它是以天才卡尔·弗里德里希·高斯(Carl Friedrich Gauss)的名字命名的。
3. 最后需要注意的是,简单的预测模型一般都是最常用的模型,因为它们易于解释,也易于理解。现在补充一点:正态分布因为简单而流行。
因此,正态概率分布很值得我们去花时间了解。
什么是概率分布?
想象我们正在自己的数据科学项目中构建感兴趣的预测模型:
概率越高,事件发生的可能性就越大。
Unsplash,Brett Jordan 发布
举个例子,我们可以大量重复一个实验,并记录我们检索到的变量值,这样概率分布就会慢慢展现在我们的面前。
每次实验产生一个值,这些值可以分配到类别/桶中了。对每个桶来说,我们可以记录变量值出现在桶里的次数。例如,我们可以扔 10,000 次骰子,每次骰子会产生 6 个可能的值,我们可以创建 6 个桶。并记录每个值出现的次数。
我们可以根据这些值作图。所作曲线就是概率分布曲线,目标变量得到一个值的概率就是该变量的概率分布。
理解了值的分布方式后,就可以开始估计事件的概率了,甚至可以使用公式(概率分布函数)。因此,我们可以更好地理解它的行为。概率分布依赖于样本的矩,比如平均值、标准差、偏度及峰度。如果对所有概率求和,总和为 100%。
现实世界中存在很多概率分布,最常用的是「正态分布」。
什么是正态概率分布
如果对概率分布作图,得到一条倒钟形曲线,样本的平均值、众数以及中位数是相等的,那么该变量就是正态分布的。
这是正态分布钟形曲线的示例:
上面是一个变量的高斯分布图形,像神经网络那样上百万的参数量,每个参数都有自己独立的分布形状,还有极其恐怖的联合分布形状。这种高维联合分布就主导了不同任务的表现,因此理解和估计目标变量的概率分布是很重要的。
以下变量非常接近正态分布:
1. 人群的身高
2. 成年人的血压
3. 扩散后的粒子的位置
4. 测量误差
5. 人群的鞋码
6. 员工回家所需时间
此外,我们周围的大部分变量都呈置信度为 x% 的正态分布(x100)。所以说,生活中经常出现的各种变量,差不多都能用高斯分布描述。
好理解的正态分布
正态分布是只依赖数据集中两个参数的分布,这两个参数分别是:样本的平均值和标准差。
分布的这一特性让统计人员省事不少,因此预测任何呈正态分布的变量准确率通常都很高。值得注意的是,一旦你研究过自然界中大多数变量的概率分布,你会发现它们都大致遵循正态分布。
正态分布很好解释。因为:
1. 分布的均值、众数和中位数是相等的;
2. 我们只要用平均值和标准差就可以解释整个分布。
为什么这么多变量近似正态分布?
为什么样本一多,那么总会有一堆样本都非常普通?这个想法背后有这样一个定理:你在大量随机变量上多次重复一个实验时,它们的分布总和将非常接近正态性(normality)。
人的身高是一个基于其他随机变量(比如一个人所消耗的营养量、他们居住的环境以及他们的基因等)的随机变量,这些随机变量的分布总和最终是非常接近正态的。这就是中心极限定理。
我们从前文了解到,正态分布是许多随机分布的和。如果我们对正态分布密度函数作图,那所作曲线有如下特性:
这个钟形曲线平均值为 100,标准差为 1。
上图介绍了非常出名的 3σ原则,即:
这样我们就可以轻松地估计出变量的波动性,还可以给出一个置信水平,估计它可能取的值是多少。例如,在上面的灰色钟型曲线中,变量值出现在 101~99 之间的概率约为 68.2%。想象一下,当你根据这样的信息做决定时,你的信心有多充足。
概率分布函数
正态分布的概率密度函数是:
概率密度函数本质上是连续随机变量取某些值的概率。例如想知道变量出现在 0 到 1 之间,它的概率就能通过概率密度函数求出。
如何用 Python 找出特征分布?
我用过的最简单的方法是在 Pandas 的 DataFrame 中加载所有特征,然后直接调用它的方法找出特征的概率分布:
这里的 bins 表示分布的柱状数量。当然上面并不是一个正态分布,那么当变量满足正态分布时,它意味着什么?
这意味着,如果你把大量分布不同的随机变量加在一起,你的新变量最终也服从正态分布,这就是中心极限定理的魅力。此外,服从正态分布的变量会一直服从正态分布。举个例子,如果 A 和 B 是两个服从正态分布的变量,那么:
变量还是乖乖地变成正态分布吧
如果样本满足某个未知的分布,那么通过一系列操作,它总是能变成正态分布。相反,标准正态分布的叠加与转换,也一定能变化为任意未知分布。从标准正态转换到未知分布,就是很多机器学习模型希望做到的,不论是视觉中的 VAE 或 GAN,还是其它领域的模型。
但对于传统统计学,我们更希望将特征的分布转换成正态分布,因为正态分布简单又好算呀。下面展示了几种转换为标准正态的方法,像相信变换什么的,在高中都有学过。
1. 线性变换
我们收集到作为变量的样本后,就可以用下面的公式对样本做线性变换,从而计算出
用下式根据每一个值 x 计算出 Z
以前 x 可能服从某个未知分布,但是归一化后的 Z 是服从正态分布的。嗯,这就是做批量归一化或其它归一化的好处吧。
2.Box-cox 变换
你可以用 Python 的 SciPy 包将数据转换成正态分布:
3.YEO-JOHBSON 变换
此外,也可以用强大的 yeo-johnson 变换。Python 的 sci-kit learn 提供了合适的函数:
最后,非常重要的一点是,在没有做任何分析的情况下假设变量服从正态分布是很不明智的。
以遵循泊松分布(Poisson distribution)、t 分布(student-t 分布)或二项分布(Binomial distribution)的样本为例,如果错误地假设变量服从正态分布可能会得到错误的结果。
以上就是关于正态分布的一些讨论。
如果文章对你有帮助,欢迎转发/点赞/收藏~
用python生成随机数的几种方法
1 从给定参数的正态分布中生成随机数
当考虑从正态分布中生成随机数时,应当首先知道正态分布的均值和方差(标准差),有了这些,就可以调用python中现有的模块和函数来生成随机数了。这里调用了Numpy模块中的random.normal函数,由于逻辑非参简单,所有直接贴上代码如下:
import numpy as np# 定义从正态分布中获取随机数的函数def get_normal_random_number(loc, scale): """ :param loc: 正态分布的均值 :param scale: 正态分布的标准差 :return:从正态分布中产生的随机数 """ # 正态分布中的随机数生成 number = np.random.normal(loc=loc, scale=scale) # 返回值 return number# 主模块if __name__ == "__main__": # 函数调用 n = get_normal_random_number(loc=2, scale=2) # 打印结果 print(n) # 结果:3.275192443463058
2 从给定参数的均匀分布中获取随机数的函数
考虑从均匀分布中获取随机数的时候,要事先知道均匀分布的下界和上界,然后调用Numpy模块的random.uniform函数生成随机数。
import numpy as np# 定义从均匀分布中获取随机数的函数def get_uniform_random_number(low, high): """ :param low: 均匀分布的下界 :param high: 均匀分布的上界 :return: 从均匀分布中产生的随机数 """ # 均匀分布的随机数生成 number = np.random.uniform(low, high) # 返回值 return number# 主模块if __name__ == "__main__": # 函数调用 n = get_uniform_random_number(low=2, high=4) # 打印结果 print(n) # 结果:2.4462417140153114
3 按照指定概率生成随机数
有时候我们需要按照指定的概率生成随机数,比如已知盒子中每种颜色的球的比例,猜测下一次取出的球的颜色。在这里介绍的问题和上面的例子相似,要求给定一个概率列表,从列表对应的数字列表或区间列表中生成随机数,分两部分讨论。
3.1 按照指定概率从数字列表中随机抽取数字
假设给定一个数字列表和一个与之对应的概率列表,两个列表对应位置的元素组成的元组即表示该数字在数字列表中以多大的概率出现,那么如何根据这些已知条件从数字列表中按概率抽取随机数呢?在这里我们考虑用均匀分布来模拟概率,代码如下:
import numpy as npimport random# 定义从均匀分布中获取随机数的函数def get_uniform_random_number(low, high): """ :param low: 均匀分布的下界 :param high: 均匀分布的上界 :return: 从均匀分布中产生的随机数 """ # 均匀分布的随机数生成 number = np.random.uniform(low, high) # 返回值 return number# 定义从一个数字列表中以一定的概率取出对应区间中数字的函数def get_number_by_pro(number_list, pro_list): """ :param number_list:数字列表 :param pro_list:数字对应的概率列表 :return:按概率从数字列表中抽取的数字 """ # 用均匀分布中的样本值来模拟概率 x = random.uniform(0, 1) # 累积概率 cum_pro = 0.0 # 将可迭代对象打包成元组列表 for number, number_pro in zip(number_list, pro_list): cum_pro += number_pro if x cum_pro: # 返回值 return number# 主模块if __name__ == "__main__": # 数字列表 num_list = [1, 2, 3, 4, 5] # 对应的概率列表 pr_list = [0.1, 0.3, 0.1, 0.4, 0.1] # 函数调用 n = get_number_by_pro(number_list=num_list, pro_list=pr_list) # 打印结果 print(n) # 结果:1
3.2 按照指定概率从区间列表中的某个区间内生成随机数
给定一个区间列表和一个与之对应的概率列表,两个列表相应位置的元素组成的元组即表示某数字出现在某区间内的概率是多少,已知这些,我们如何生成随机数呢?这里我们通过两次使用均匀分布达到目的,代码如下:
import numpy as npimport random# 定义从均匀分布中获取随机数的函数def get_uniform_random_number(low, high): """ :param low: 均匀分布的下界 :param high: 均匀分布的上界 :return: 从均匀分布中产生的随机数 """ # 均匀分布的随机数生成 number = np.random.uniform(low, high) # 返回值 return number# 定义从一个数字列表中以一定的概率取出对应区间中数字的函数def get_number_by_pro(number_list, pro_list): """ :param number_list:数字列表 :param pro_list:数字对应的概率列表 :return:按概率从数字列表中抽取的数字 """ # 用均匀分布中的样本值来模拟概率 x = random.uniform(0, 1) # 累积概率 cum_pro = 0.0 # 将可迭代对象打包成元组列表 for number, number_pro in zip(number_list, pro_list): cum_pro += number_pro if x cum_pro: # 从区间[number. number - 1]上随机抽取一个值 num = get_uniform_random_number(number, number - 1) # 返回值 return num# 主模块if __name__ == "__main__": # 数字列表 num_list = [1, 2, 3, 4, 5] # 对应的概率列表 pr_list = [0.1, 0.3, 0.1, 0.4, 0.1] # 函数调用 n = get_number_by_pro(number_list=num_list, pro_list=pr_list) # 打印结果 print(n) # 结果:3.49683787011193
如何利用python中的威布尔分布numpy.random.weibull()函数生成三参数的随机数序列
你好,有两个办法:
一个是自己写一个函数
def Nweibull(a,size, scale)
return scale*numpy.random.weibull(a,size)
另外一个是换一个库, 用scipy.stats.weibull_min, 他需要三个参数:
from scipy.stats import weibull_min
n = 100 # number of samples
k = 2.4 # shape
lam = 5 # scale
x = weibull_min.rvs(k, loc=0, scale=lam, size=n)
如何根据概率密度函数生成随机数
如何根据概率密度函数生成随机数
我这里并不是要讲“伪随机”、“真随机”这样python概率分布函数的问题python概率分布函数,而是关于如何生成服从某个概率分布的随机数(或者说 sample)的问题。比如,python概率分布函数你想要从一个服从正态分布的随机变量得到 100 个样本,那么肯定抽到接近其均值的样本的概率要大许多,从而导致抽到的样本很多是集中在那附近的。当然,要解决这个问题,我们通常都假设我们已经有python概率分布函数了一个 生成 0 到 1 之间均匀分布的随机数的工具,就好像 random.org 给我们的结果那样,事实上许多时候我们也并不太关心它们是真随机数还是伪随机数,看起来差不多就行了。 :p
现在再回到我们的问题,看起来似乎是很简单的,按照概率分布的话,只要在概率密度大的地方多抽一些样本不就行了吗?可是具体要怎么做呢?要真动起手 来,似乎有不是那么直观了。实际上,这个问题曾经也是困扰了我很久,最近又被人问起,那我们不妨在这里一起来总结一下。为了避免一下子就陷入抽象的公式推 导,那就还是从一个简单的具体例子出发好了,假设我们要抽样的概率分布其概率密度函数为 p(x) = \frac{1}{9}x^2 ,并且被限制在区间 [0, 3] 上,如右上图所示。
好了,假设现在我们要抽 100 个服从这个分布的随机数,直观上来讲,抽出来的接近 3 的数字肯定要比接近 0 的数字要多。那究竟要怎样抽才能得到这样的结果呢?由于我们实际上是不能控制最原始的随机数生成过程的,我们只能得到一组均匀分布的随机数,而这组随机数 的生成过程对于我们完全是透明的,所以,我们能做的只有把这组均匀分布的随机数做一些变换让他符合我们的需求。找到下手的点了,可是究竟要怎样变换呢?有 一个变换相信大家都是很熟悉的,假设我们有一组 [0,1] 之间的均匀分布的随机数 X_0 ,那么令 X_1=3X_0 的话,X_1 就是一组在 [0,3] 之间均匀分布的随机数了,不难想象,X_1 等于某个数 x^* 的概率就是 X_0 等于 x^*/3 的概率(“等于某个数的概率”这种说法对于连续型随机变量来说其实是不合适的,不过大概可以理解所表达的意思啦)。似乎有一种可以“逆转回去”的感觉了。
于是让我们来考虑更一般的变换。首先,我们知道 X_1 的概率密度函数是 f(x) = 1/3, x\in[0,3] ,假设现在我们令 Y = \phi (X_1) ,不妨先假定 \phi(\cdot) 是严格单调递增的函数,这样我们可以求其逆函数 \phi^{-1}(\cdot) (也是严格单调递增的)。现在来看变换后的随机变量 Y 会服从一个什么样的分布呢?
这里需要小心,因为这里都是连续型的随机变量,并不像离散型随机变量那样可以说成“等于某个值的概率”,因此我们需要转换为概率分布函数来处理,也就是求一个积分啦:
\displaystyle F(x) = P(X \leq x) = \int_{-\infty}^x f(t)dt
那么 X_1 的概率分布函数为 F(x) = \frac{1}{3}x 。很显然 Y 小于或等于某个特定的值 y^* 这件事情是等价于 X_1=\phi^{-1}(Y)\leq\phi^{-1}(y^*) 这件事情的。换句话说,P(Y\leq y^*) 等于 P(X_1 \leq \phi^{-1}(y^*)) 。于是,Y 的概率分布函数就可以得到了:
\displaystyle G(y) = P(Y \leq y) = P(X_1 \leq \phi^{-1}(y)) = F(\phi^{-1}(y))
再求导我们就能得到 Y 的概率密度函数:
\displaystyle g(y) = \frac{dG(y)}{dy} = f(\phi^{-1}(y))\frac{d}{dy}\phi^{-1}(y)
这样一来,我们就得到了对于一个随机变量进行一个映射 \phi(\cdot) 之后得到的随即变量的分布,那么,回到我们刚才的问题,我们想让这个结果分布就是我们所求的,然后再反推得 \phi(\cdot) 即可:
\displaystyle \frac{1}{9}y^2 = g(y) = f(\phi^{-1}(y))\frac{d}{dy}\phi^{-1}(y) = \frac{1}{3}\frac{d}{dy}\phi^{-1}(y)
经过简单的化简就可以得到 \phi^{-1}(y) = \frac{1}{9} y^3 ,亦即 \phi(x) = (9x)^{1/3} 。也就是说,把得到的随机数 X_1 带入到到函数 \phi(\cdot) 中所得到的结果,就是符合我们预期要求的随机数啦python概率分布函数! :D 让我们来验证一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#!/usr/bin/python import numpy as np import matplotlib.pyplot as plot N = 10000 X0 = np.random.rand(N) X1 = 3*X0 Y = np.power(9*X1, 1.0/3) t = np.arange(0.0, 3.0, 0.01) y = t*t/9 plot.plot(t, y, 'r-', linewidth=1) plot.hist(Y, bins=50, normed=1, facecolor='green', alpha=0.75)plot.show()
这就没错啦,目的达成啦!让我们来总结一下。问题是这样的,我们有一个服从均匀分布的随机变量 X ,它的概率密度函数为一个常数 f(x)=C ,如果是 [0,1] 上的分布,那么常数 C 就直接等于 1 了。现在我们要得到一个随机变量 Y 使其概率密度函数为 g(y) ,做法就是构造出一个函数 \phi(\cdot) 满足(在这里加上了绝对值符号,这是因为 \phi(\cdot) 如果不是递增而是递减的话,推导的过程中有一处就需要反过来)
\displaystyle g(y) = f(\phi^{-1}(y))\left|\frac{d}{dy}\phi^{-1}(y)\right| = C\left|\frac{d}{dy}\phi^{-1}(y)\right|
反推过来就是,对目标 y 的概率密度函数求一个积分(其实就是得到它的概率分布函数 CDF ,如果一开始就拿到的是 CDF 当然更好),然后求其反函数就可以得到需要的变换 \phi(\cdot) 了。实际上,这种方法有一个听起来稍微专业一点的名字:Inverse Transform Sampling Method 。不过,虽然看起来很简单,但是实际操作起来却比较困难,因为对于许多函数来说,求逆是比较困难的,求积分就更困难了,如果写不出解析解,不得已只能用数 值方法来逼近的话,计算效率就很让人担心了。可事实上也是如此,就连我们最常见的一维标准正态分布,也很难用这样的方法来抽样,因为它的概率密度函数
\displaystyle g(y) = \frac{1}{\sqrt{2\pi}}e^{-\frac{1}{2}y^2}
的不定积分没有一个解析形式。这可真是一点也不好玩,费了这么大劲,结果好像什么都干不了。看来这个看似简单的问题似乎还是比较复杂的,不过也不要灰心,至少对于高斯分布来说,我们还有一个叫做 Box Muller 的方法可以专门来做这个事情。因为高斯分布比较奇怪,虽然一维的时候概率分布函数无法写出解析式,但是二维的情况却可以通过一些技巧得出一个解析式来。
首先我们来考虑一个二维的且两个维度相互独立的高斯分布,它的概率密度函数为
\displaystyle f(x,y) = \frac{1}{\sqrt{2\pi}}e^{-\frac{x^2}{2}}\cdot\frac{1}{\sqrt{2\pi}}e^{-\frac{y^2}{2}} = \frac{1}{2\pi}e^{-\frac{x^2+y^2}{2}}
这个分布是关于原点对称的,如果考虑使用极坐标 (\theta,r) (其中 \theta\in[0,2\pi), r\in[0,\infty) )的话,我们有 x = r\cos\theta,y=r\sin\theta 这样的变换。这样,概率密度函数是写成:
\displaystyle f(\theta,r) = \frac{1}{2\pi}e^{-\frac{r^2}{2}}
注意到在给定 r 的情况下其概率密度是不依赖于 \theta 的,也就是说对于 \theta 来说是一个均匀分布,这和我们所了解的标准正态分布也是符合的:在一个圆上的点的概率是相等的。确定了 \theta 的分布,让我们再来看 r,用类似于前面的方法:
\displaystyle \begin{aligned} P(rR) = \int_0^{2\pi}\int_0^R\frac{1}{2\pi}e^{\frac{r^2}{2}}rdrd\theta \ = \int_0^Re^{-\frac{r^2}{2}}rdr \ = 1-e^{-\frac{R^2}{2}} \end{aligned}
根据前面得出的结论,我现在得到了 r 的概率分布函数,是不是只要求一下逆就可以得到一个 \phi(\cdot) 了?亦即 \phi(t) = \sqrt{-2\log (1-t)} 。
现在只要把这一些线索串起来,假设我们有两个相互独立的平均分布在 [0,1] 上的随机变量 T_1 和 T_2 ,那么 2\pi T_1 就可以得到 \theta 了,而 \phi(T_2) = \sqrt{-2\log(1-T_2)} 就得到 r 了(实际上,由于 T_2 和 1-T_2 实际上是相同的分布,所以通常直接写为 \sqrt{-2\log T_2})。再把极坐标换回笛卡尔坐标:
\displaystyle \begin{aligned} x = r\cos\theta = \sqrt{-2\log T_2}\cdot \cos(2\pi T_1) \ y = r\sin\theta = \sqrt{-2\log T_2}\cdot \sin(2\pi T_1) \end{aligned}
这样我们就能得到一个二维的正态分布的抽样了。可以直观地验证一下,二维不太好画,就画成 heatmap 了,看着比较热的区域就是概率比较大的,程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#!/usr/bin/python import numpy as np import matplotlib.pyplot as plot N = 50000 T1 = np.random.rand(N) T2 = np.random.rand(N) r = np.sqrt(-2*np.log(T2)) theta = 2*np.pi*T1 X = r*np.cos(theta) Y = r*np.sin(theta) heatmap, xedges, yedges = np.histogram2d(X, Y, bins=80) extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]] plot.imshow(heatmap, extent=extent) plot.show()
画出来的图像这个样子:
不太好看,但是大概的形状是可以看出来的。其实有了二维的高斯分布,再注意到两个维度在我们这里是相互独立的,那么直接取其中任意一个维度,就是一个一维高斯分布了。如下:
如果 X\sim N(0,1) 即服从标准正态分布的话,则有 \sigma X+\mu \sim N(\mu, \sigma^2) ,也就是说,有了标准正态分布,其他所有的正态分布的抽样也都可以完成了。这下总算有点心满意足了。不过别急,还有最后一个问题:多元高斯分布。一般最常 用不就是二元吗?二元不是我们一开始就推出来了吗?推出来了确实没错,不过我们考虑的是最简单的情形,当然同样可以通过 \sigma X+\mu 这样的方式来处理每一个维度,不过高维的情形还有一个需要考虑的就是各个维度之间的相关性——我们之前处理的都是两个维度相互独立的情况。对于一般的多维正态分布 X\sim N(\mathbf{\mu}, \Sigma) ,如果各个维度之间是相互独立的,就对应于协方差矩阵 \Sigma 是一个对角阵,但是如果 \Sigma 在非对角线的地方存在非零元素的话,就说明对应的两个维度之间存在相关性。
这个问题还是比较好解决的,高斯分布有这样的性质:类似于一维的情况,对于多维正态分布 X\sim N(\mathbf{\mu}, \Sigma),那么新的随机变量 X_1=\mathbf{\mu}_1 + LX 将会满足
\displaystyle X_1 \sim N(\mathbf{\mu}_1+L\mu, L\Sigma L^T)
所以,对于一个给定的高斯分布 N(\mathbf{\mu}, \Sigma) 来说,只要先生成一个对应维度的标准正态分布 X\sim N(0, I) ,然后令 X_1 = \mu+LX 即可,其中 L 是对 \Sigma 进行 Cholesky Decomposition 的结果,即 \Sigma = LL^T 。
结束之前让我们来看看 matlab 画个 3D 图来改善一下心情:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
N = 50000; T1 = rand(1, N); T2 = rand(1, N); r = sqrt(-2*log(T2)); theta = 2*pi*T1; X =[r.*cos(theta); r.*sin(theta)]; mu = [1; 2]; Sigma = [5 2; 2 1]; L = chol(Sigma); X1 = repmat(mu,1, N) + L*X; nbin = 30; hist3(X1', [nbin nbin]); set(gcf, 'renderer', 'opengl'); set(get(gca,'child'), 'FaceColor', 'interp', 'CDataMode', 'auto'); [z c] = hist3(X1', [nbin nbin]); [x y] =meshgrid(c{1}, c{2}); figure; surfc(x,y,-z);
下面两幅图,哪幅好看一些(注意坐标比例不一样,所以看不出形状和旋转了)?似乎都不太好看,不过感觉还是比前面的 heatmap 要好一点啦!
然后,到这里为止,我们算是把高斯分布弄清楚了,不过这只是给一个介绍性的东西,里面的数学推导也并不严格,而 Box Muller 也并不是最高效的高斯采样的算法,不过,就算我们不打算再深入讨论高斯采样,采样这个问题本身也还有许多不尽人意的地方,我们推导出来的结论可以说只能用 于一小部分简单的分布,连高斯分布都要通过 trick 来解决,另一些本身连概率密度函数都写不出来或者有各种奇怪数学特性的分布就更难处理了。所以本文的标题里也说了,这是上篇,如果什么时候有机会抽出时间 来写下篇的话,我将会介绍一些更加通用和强大的方法,诸如 Rejection Sampling 、Gibbs Sampling 以及 Markov Chain Monte Carlo (MCMC) 等方法。如果你比较感兴趣,可以先自行 Google 一下解馋! :D
python概率分布函数的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于python概率分布函数拟合、python概率分布函数的信息别忘了在本站进行查找喔。