Python 中的私有“受保护”属性——一劳永逸地去神秘化
所有关于私有和“受保护”属性的知识都在 748 个单词中
永远不要使用两个前导下划线。这是令人讨厌的隐私。—伊恩·比金,pip、virtualenv 和许多其他软件的创作者
H 这些词你在 Python 的世界里遇到过多少次:公有、私有、受保护?有多少次,那些一个前导下划线_
,两个前导下划线__
让你困惑,试图理解它们?
好吧,让我们一劳永逸地揭开它们的神秘面纱。私有和“受保护”的属性有什么用。以及它们在 Python 世界中的样子。
私有属性到底有什么意义?
考虑这个场景:你有一个名为Vehicle
的类,它在内部使用一个名为 horn 的实例属性,并且不想公开它。现在,你想要子类化Vehicle
并将你自己的类命名为MyCar.
**
如果您在类MyCar
中创建自己的horn
实例属性,您将覆盖Vehicle
的horn
实例属性。结果是,你将粉碎Vehicle
类中所有使用horn
属性的方法。更糟糕的是,调试随之而来的问题将是一件令人头疼的事情。
为了防止这种情况发生,Vehicle
类的开发人员会将horn
属性设为私有属性,以防止这种意外事故。**
Python 中的私有属性
在 Python 的世界里,不像 Java,没有办法创建一个私有的修饰符。python 给你的是一个简单的机制,防止意外覆盖你的类中的属性,如果有人想从你的类继承。****
在前面的例子中,如果您想将horn
属性设为 private,您需要在它前面加上两个下划线:__horn
。这样,Python 将把这个属性名存储在实例__dict__
中,以下划线和类名为前缀。这样,在Vehicle
类中,你的__horn
属性就变成了_vehicle__horn
而在 *MyCar*
类中就变成了_MyCar__horn
。python 的这个特性被冠以一个微妙的名字 名为 mangling 。下面是我们目前讨论的代码:
示例 01 —私有属性,其中名称被篡改****
这里需要注意的是,名称篡改完全是关于 安全而不是安全。它不会保护你免受故意的错误行为;只是,偶然的超越。在上面的例子中,您可以简单地通过这样做来改变私有属性的值:v1._vehicle__horn = 'new value'
。
Python 中的“受保护”属性
无论是名字的乱涂乱画,还是把名字写成self.__horn
的歪歪扭扭的样子,都不为皮达尼斯所喜爱。在公共存储库中,您会注意到开发人员通常更喜欢遵循这样的惯例:只给添加一个前导下划线(self._horn
),以防止它们被无意中修改。****
批评者建议,为了防止属性混乱,只需简单地遵循在属性前加一个下划线的惯例就足够了。这是我在文章开头引用的伊恩·比金的话全文;
永远不要使用两个前导下划线。这是令人讨厌的隐私。如果担心名称冲突,请使用显式名称混淆(例如 _MyThing_balabla)。这和双下划线本质上是一样的,只是在双下划线模糊的地方是透明的。
我必须注意,带有单个前导下划线_
的属性对于 python 解释器来说没有任何特殊意义。但是,这是皮托尼斯塔世界里的一个很强的惯例。如果您看到一个,这意味着您不应该从类外部访问这样的属性。您甚至可以观察到,甚至在官方 Python 文档的某些角落中,带有单个前导下划线_
的属性也被称为“受保护的”
尽管使用单个前导下划线来“保护”属性的做法很常见,但很少听到它们被称为“受保护的”属性。有些人甚至称之为“私人”
总而言之
将属性设为私有的主要目的是防止子类意外覆盖该属性。在 python 中,使变量私有的官方方法是添加两个下划线,例如self.__privateattr.
,但是,在 python 社区中,当使变量私有时,强烈倾向于只添加一个前导下划线。您可能经常听到或看到这样的属性被称为“受保护的”
因此,只需知道在 python 中将变量设为私有是为了安全,只需添加一个前导下划线就足以保护它们不被无意中覆盖:例如self._protected
。
如果你喜欢我的文章并想阅读更多,考虑注册成为一名媒体会员。每月 5 美元,你可以无限制地阅读媒体上的故事。通过使用下面的链接,你也将支持我作为一个作家。
******** [## 通过我的推荐链接加入 Medium-Amir AFI anian
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
7sapien.medium.com](https://7sapien.medium.com/membership)********
在 Colab 环境中下载自定义数据集的提示
萨姆·丹·张在 Unsplash 上的照片
通常,当数据科学家需要使用他们的自定义数据集进行深度学习或任何推理时,他们需要将数据下载到他们的环境中。这对任何使用 Colab 的人来说都特别有用。我基本上使用 Colab 来完成我的深度学习任务,因为我没有硬件来支持我的计算。
我想快速分享我是如何在 google Colab 环境中为我们工作和使用数据集的。事实上,这个过程应该是非常简单的,但是有时候,我们很难做到。实际上我花了一段时间才弄明白。因此,我写这篇文章的原因是。
实际上有几个选项可供选择。
- 把你的数据推送到 Github,克隆到 google。我个人不喜欢这样。此外,你仍然需要做一些调整,尤其是如果你有一个非常大的数据集,因为 GitHub 不会直接支持你推这些数据集(图像)
- 另一种选择是手动上传到 Colab。这本来很好,但上传时间太长。因此,如果你需要节省时间,我既不使用它也不建议它。
- 将您的数据上传到 google drive,并将文件夹安装到您的环境中。这也是一个很好的选择,除了第三方不能使用您的笔记本电脑,因为在安装过程中需要驱动器认证。
- 第四种选择是上传压缩版本的数据,不管有多少。在这种情况下,数据也可以是预训练的模型或任何其他形式的数据集(通常是图像)。在接下来的文章中,我会专注于此
怎么会?
Colab 以不同的方式处理大数据集和小数据集。在这种情况下,大型数据集通常是 100mb 以上的任何数据,小型数据集通常是 100mb 以下的数据。
基本步骤是:
- 在本地计算机上压缩文件,然后上传到 google drive
- 右键单击 zip 文件或文件夹(如果没有压缩),然后选择获取可共享链接
- 通过将链接的权限更改为**任何人来公开:**如果不公开,文件将不会被下载到 Colab。我在第一次尝试中错过了这一步。
4.您现在可以复制链接并提取 d 和视图之间的字母数字。这只是您需要的文件 ID。
比如这个链接:https://drive . Google . com/file/d/1 tjpao 4 hjqe 97 b 6 xddy 9 ZD 5 i5 xmu _ 2RJ/view?usp =共享,
1tjpao 4 hjqe 97 b 6 xddy 9 z D5 I 05 xmu _ 2RJ是文件 id
5.对于小型数据集,复制下面的命令并粘贴到您的 Colab 笔记本中。导入 Ipython display clear output 方法来清除下载的输出。显示的输出有时会很大,这会占用不必要的屏幕空间。
下载文件
下载小文件
对于大文件,请复制下面的命令。注意,有两个位置会替换文件 ID
下载大文件
提取文件
如果下载的文件是压缩的,您需要执行以下步骤。检查您合适的文件类型(zip、7z、tar)并复制合适的代码或命令来提取它们以供使用。对于 zip 文件,您只需将 zipfile 作为一个类导入并完成工作。对于其他文件类型,需要安装一个 p7zip
一旦你完成了这些,你就可以开始你的机器学习任务了。获取数据是第一步,也是最基本的一步。
使用上面的过程,你可以在 Colab 中使用你的文件。唯一的缺点是,每次重启运行时,你都需要下载。
希望这能帮助到某个人。干杯。
概率线性判别分析(PLDA)解释
入门
来源:图片由作者提供。具有不同平均值(中心)的高斯分布(椭圆)的等高线用不同的颜色表示。每个轮廓对应于不同类别。
以简化的方式讲解概率线性判别分析(PLDA)** 的**概念和应用。
介绍
顾名思义,概率线性判别分析是线性判别分析的概率版本,能够处理更复杂的数据。尽管 PLDA 在包括计算机视觉、语音处理、自然语言处理(NLP)在内的许多研究领域有着广泛的应用,但它仍然没有以一种能够达到广泛受众的方式进行解释。PLDA 已被用于识别、验证、生成用于聚类的相似性分数、特定于类别的特征提取。
我这里的目的是讨论介绍和应用了 PLDA** 的研究论文**。我将使用等式、图表和易于实现的代码来解释这些概念,以便所有数据科学领域的人都可以理解。
这里介绍的推导需要有基本概率和线性代数的先验知识。可以参考参考文献中提到的来源。
为什么是 PLDA?
在我继续之前,我想给出使用 PLDA 而不是 LDA 的动机。
LDA 是一种监督降维技术。LDA 将数据投影到较低维度的子空间,使得在投影的子空间中,与每个类内的分布(最小化类内协方差 Sw )相比,属于不同类的点更加分散(最大化类间协方差 Sb )。下图展示了这一点。
来源:毕晓普著*模式识别与机器学习 。每种颜色代表一个阶层。m1 和 m2 分别是类别 1 和类别 2 平均值。左图显示了 m1 和 m2 连线上的数据投影。两个类别的样本有很多重叠。右图显示了使用 LDA 的数据投影,从而最大限度地减少了两个类别之间的重叠*
当我们有来自所见类的数据时,这对于分类很有用。但是,当观察到的数据来自看不见的类时,我们如何执行类似的任务呢?例如,考虑人脸识别的任务,我们使用不同的人脸图像训练模型,使得每个唯一的人脸代表一个类别。
现在给定两个图像,我们想要找出它们是否属于同一个人,即使模型以前没有见过那个人的任何图像。常见的方法是将两幅图像投影到低维空间,并找出它们之间的距离。如果距离很小,这意味着他们来自同一个班级。LDA 会将图像投影到从训练数据获得的子空间中,因此不是最佳的。因此,我们需要一个更灵活的模型来寻找投影的最佳方向。解决这个问题的一种方法是使用概率方法,而不像 LDA 是确定性的。它被称为概率 LDA。
PLDA 的优势
- 我们可以使用连续的非线性函数来生成类中心,即使是从看不见的类的单个例子中。
- 在假设检验中,我们可以比较以前从未见过的类中的两个例子,以确定它们是否属于同一类。
- 对来自未知类别的样本执行聚类
什么是概率 LDA?
设 x={x₁,x₂,…,xₙ} 为 D 维观测值或数据样本。概率 LDA 或 PLDA 是一个生成模型,它假设给定的数据样本是从分布中生成的。我们需要找到最能描述训练数据的模型参数。假设产生数据的分布的选择基于两个因素:(1)它应该代表不同类型的数据(2)参数的计算简单而快速。满足这些条件的最流行的分布是高斯分布。下图显示了高斯分布的概率分布函数(pdf)、等高线以及从中生成的样本。
来源:作者的情节
[**show code**](https://gist.github.com/prachiisc/a5f193212f90c8f82e84b5fe9dcf85d4)
为了将数据聚类成类,我们需要用单独的高斯分布来表示每个类,因此我们可以使用高斯混合模型(GMM)。GMM 是高斯的加权混合,每个高斯具有不同的均值和协方差,其中每个混合可以代表每个类别。
GMM 的概率分布函数(pdf)为:
来源:作者的情节。具有 πₖ、μₖ、φₖ的 GMM 的 pdf 为 k- 次高斯的权重、均值和协方差
[**show code**](https://gist.github.com/prachiisc/4668febcef55f6d857863ca9ffd920bd)
设 y 为潜在(隐藏)类变量代表 GMM 某类/混合的意思。现在给定这个类变量y*,产生数据样本**x的概率为:*******
其中φw 表示给定类的类内协方差。这表明,一旦我们知道了高斯的类参数,我们就可以生成这个类的样本。这里**类变量y本身假设是从单独分布中产生的。从假定的分布中产生代表一个类别的特定实例 y 的概率被称为先验概率。**
LDA 也被建模为 GMM,其中每个混合的高斯均值是属于各自类别的训练数据的样本均值,并且 y 的先验概率是离散的,其中 y 只能取离散值,给出如下
*这将产生上面讨论的 GMM。最大化该模型关于参数的可能性{ **πₖ,μₖ,*φw }恢复标准 LDA 投影。但是,为了处理在训练期间没有看到的类,我们需要修改 prior 并使其连续,其中 y 可以取从给定的分布中生成的任何实数值
这表明,每个类别的潜在变量 y 可以使用高斯分布生成,具有**均值m*和类别间协方差φb .,因此它被称为*概率 LDA。使用下图可以更好地解释这一点:
来源:图片由作者提供。小椭圆代表每个类别的高斯分布等值线,平均值位于中心。数据点由十字标记表示。灰色椭圆根据高斯分布生成每一类的平均值。
来源:人物图片来自 LFW 数据集,由作者代表。情节是为了说明。
样本 y 1 和 y 2 由高斯分布 eq (2)生成,代表人物身份。我们对每个类(人)的示例 x 1 和 x 2 进行采样,用等式(1)以 y 1 和 y 2 为均值来表示人的不同取向。
潜在空间
PLDA的目标是将数据样本投影到潜在空间中,使得来自同一类的样本使用相同的分布建模。这些预测用潜在变量*表示,这将在本节中讨论。*
如前所述,isφb是类间协方差半正定矩阵而φw 是类内协方差正定矩阵。我们得到一个变换矩阵 V,它将φw 和φb 同时转换成对角矩阵,给出如下:
其中 I 是单位矩阵,ψ是对角矩阵*。因此,我们对数据样本的每个维度去相关。现在 PLDA 模型的参数是{ m ,A,ψ}。***
你可以参考下面的推导来得到上面的方程。它需要了解线性代数概念,如矩阵的 特征值和特征向量特征值分解 。
[**show derivation**](http://leap.ee.iisc.ac.in/prachi/medium/Eigen_value_derivation.pdf)
设 u,v 是潜在空间中的高斯随机变量定义为,
我们可以发现数据样本* x ,类变量 y 与这些潜在变量之间的关系如下:***
因此 u 表示类的实例,而 v 表示类变量在投影空间中。等式(5)和等式(6)中的关系以流程图的形式表示,如下所示:**
来源:图片由作者提供。PLDA 在变量独立的潜在空间中对分类中心 v 和示例 u1、u2 进行建模。原始特征空间中的示例 x1、x2 通过可逆变换 A 与其潜在表示 u 相关联
有兴趣的可以参考下面的推导:
应用程序
PLDA 允许对训练中没有出现的课程进行推断。一个例子是说话人识别。模型参数从训练数据中学习,但是模型应该处理来自训练期间不在场的说话者的例子。这里讨论了可以使用 PLDA 的一些任务。
分类:
我们有一组示例 xg∈(x₁***,x₂,…,x** M 每个 M 类一个。现在给出一个探针例子 x p,任务是找到它属于哪个类。这是通过最大化可能性来确定的。首先,使用等式(6)将示例投影到潜在空间中*****
****当 u 的协方差为 I 时,对数据进行去相关。P(uP│ug)给出来自与已知集合中的样本相同类别的探针样本的概率。
因此,分配给探针示例的 C 类为
[**Computation of P(up|ug)**](http://leap.ee.iisc.ac.in/prachi/medium/computation_of_p.pdf)
类推断:
PLDA 的一个优点是,我们可以从类的单个例子中找到类变量 y 。对于示例 x,我们计算给定 x 的 y 的后验概率,表示为 p(y|x),这将再次是高斯分布。y 的估计是通过将 p(y|x)相对于 y 最大化得到的。无非是高斯 p 的均值(y|x)。可以这样写:
假设检验:
给定两个来自未知类的例子( u 1, u 2),如果我们需要判断它们是否属于同一类,那么我们基于两个假设计算 似然比 R 。
聚类:
PLDA 也用于将示例分组。基于 对数似然比 R 或 PLDA 分数 ,我们将每个例子与所有其他例子进行比较。这将创建一个 PLDA 得分矩阵,类似于一个相似性得分矩阵,可用于使用 k-means、凝聚聚类等可用算法执行聚类。
例子
****说话者二分化:基于说话者源将输入音频流分割成片段的任务。
该过程如下
- 将音频分成小段,每个小段只包含一个扬声器。
- 提取每个线段的特征
- 使用预先训练的 PLDA 计算 PLDA 分数矩阵
- 使用分数矩阵执行聚类
来源:图片由作者提供。扬声器双音化管道。
我使用语音识别工具包 Kaldi 完成第 1 步和第 2 步,并训练 PLDA 如下。
以下代码涉及:读取特征->应用主成分分析-> PLDA 潜在空间项目->计算 PLDA 得分矩阵。带有特性和预训练模型的完整代码可以在 GitHub 中找到。
[**show code**](https://gist.github.com/prachiisc/81f1d845b02ae1a7103580c74f260a4b)
分析
- PLDA 潜在表象(u): 下图显示了将数据投射到 PLDA 潜在空间的效果。我们可以看到,当我们将数据投影到 PLDA 潜像中时,它就变成了可分离的扬声器,即使 PLDA 模型从未见过来自这些扬声器的音频。
128 维特征的 2d 投影。左侧图是 PCA 转化的嵌入。左侧情节是 PLDA 潜在的表述。每种颜色代表一个扬声器。由作者策划。
[**show code**](https://gist.github.com/prachiisc/5ec4c485c62a1b07eee65745b9d4621f)
****2。对数似然比或 PLDA 得分矩阵:我们可以通过找到从音频中提取的所有 I 和 j 片段的 x ᵢ 和 x ⱼ 之间的相似性得分 S(i,j)来计算相似性得分矩阵 s。下图显示了标准化余弦得分矩阵和 PLDA 得分矩阵,通过除以矩阵中的最高得分进行标准化。它描绘了在 PLDA 分数中的较高对比,显示了在对相同和不同说话者做出决定时的较高信心。浅色(黄色阴影)表示高分,而深色(蓝色阴影)表示低分。我们可以看到光块和色块,这有助于轻松识别同一扬声器和不同的扬声器区域。
余弦亲和度矩阵和 PLDA 亲和度矩阵的比较。由作者策划。
[**show code**](https://gist.github.com/prachiisc/3519554beccf61275495940890c674b5)
****3。直方图:下图显示了 PLDA 分数的分布。更高的计数出现在极端情况下,这有助于更好的聚类。
x 轴:标准化的 PLDA 分数,y 轴:计数。由作者策划。
[**show code**](https://gist.github.com/prachiisc/0c0875217f50781735b0c734d4e72824)
总结
- PLDA 是一个生成模型,其中我们假设一个类的数据样本 X 是从高斯分布生成的。高斯平均值代表类别变量 y 是从另一个被称为先验的高斯分布生成的。
- 对于识别的任务,我们可以通过比较来自相同类别的样本的可能性与来自不同类别的样本的可能性,使用 PLDA 分数来比较两个未知类别的样本。
- 我们可以使用整组样本中所有样本对之间的 PLDA 分数将样本聚类成类。
参考
- 约夫,谢尔盖。"概率线性判别分析."在欧洲计算机视觉会议 ,第 531–542 页。施普林格,柏林,海德堡,2006。
- 普林斯、西蒙·杰狄和詹姆斯·埃尔德。"概率线性鉴别分析对身份的推断"2007 年 IEEE 第 11 届计算机视觉国际会议,第 1–8 页。IEEE,2007 年。
- 毕晓普,克里斯托弗 M. 模式识别与机器学习 。斯普林格,2006 年。
- 杜达,杰瑞克。“高斯自动编码器。” arXiv 预印本 arXiv:1811.04751 ,2018
- 斯特朗吉尔伯特。线性代数入门。第五版。韦尔斯利-剑桥出版社,2016 年。国际标准书号:9780980232776
权重不确定的概率线性回归
用张量流概率实现贝叶斯线性回归预测汽车的 MPG
线性回归可能是你在学习数据科学和机器学习时遇到的第一种统计方法。所以,我会抓住机会猜测这不是你第一次处理线性回归。因此,在本文中,我想讨论概率线性回归,而不是典型/确定性线性回归。
但是在此之前,让我们简单地讨论一下确定性线性回归的概念,让我们快速了解本文的主要观点。
线性回归是一种基本的统计方法,用于模拟一个或多个输入变量(或自变量)与一个或多个输出变量(或因变量)之间的线性关系。
上式中,a
称为截距,b
称为斜率。x
是我们的自变量,y
是我们的因变量,也就是我们试图预测的值。
需要使用梯度下降算法来优化a
和b
的值。然后,我们得到一条回归线,显示自变量和因变量之间的最佳拟合。有了回归线,我们可以用任何给定的x
输入来预测y
的值。这些是典型或确定性线性回归算法通常是如何构建的步骤。
确定性线性回归方法中最佳拟合线的典型图
然而,这种确定性的线性回归算法并不能真正说明数据和模型的全部情况。这是为什么呢?
实际上,当我们进行线性回归分析时,会出现两种类型的不确定性:
- 随机不确定性,即由数据产生的不确定性。
- 认知不确定性,这是由回归模型产生的不确定性。
在我们阅读这篇文章的时候,我将详细阐述这些不确定性。为了考虑这些不确定性,应使用概率线性回归代替确定性线性回归。
在本文中,我们将讨论概率线性回归以及它与确定性线性回归的区别。我们将首先看到如何在 TensorFlow 中构建确定性线性回归,然后我们将继续构建具有 TensorFlow 概率的概率性线性回归模型。
首先,让我们从加载我们将在本文中使用的数据集开始。
加载和预处理数据
本文将使用的数据集是汽车的 MPG 数据集。像往常一样,我们可以用熊猫加载数据。
下面是数据的统计汇总。
接下来,我们可以用下面的代码来看看数据集中变量之间的相关性。
现在,如果我们看看相关性,汽车的每加仑英里数(MPG)和汽车的重量有很强的负相关性。
在本文中,我将做一个简单的线性回归分析,以实现可视化。自变量将是汽车的重量,因变量将是汽车的英里数。
现在,让我们用 Scikit-learn 将数据拆分为训练数据和测试数据。拆分数据后,我们现在可以缩放因变量和自变量。这是为了确保这两个变量将在相同的规模,这也将提高我们的线性回归模型的收敛速度。
现在,如果我们将训练数据可视化,我们会得到以下可视化结果:
厉害!接下来,让我们继续用 TensorFlow 构建确定性线性回归模型。
张量流的确定性线性回归
用 TensorFlow 建立一个简单的线性回归模型是非常容易的。我们所要做的就是建立一个没有任何激活函数的单一致密层。对于成本函数,通常使用均方误差。在这个例子中,我将使用 RMSprop 作为优化器,模型将在 100 个时期内被训练。我们可以用下面几行代码来构建和训练模型。
在我们训练了模型之后,让我们看看模型的损失历史来检查损失收敛。
损失 v 历元数
损失似乎已经收敛了。现在,如果我们使用训练好的模型来预测测试集,我们可以看到下面的回归线。
仅此而已。我们完了!
正如我前面提到的,用 TensorFlow 建立一个简单的线性回归模型是非常容易的。有了回归线,我们现在可以在任何给定的汽车重量输入下近似汽车的 MPG。举个例子,假设汽车在特征缩放后的重量是 0.64。我们可以通过将此值传递给训练好的模型来获得汽车的 MPG 的相应值,如下所示。
现在你可以看到,模型预测汽车的 MPG 将是 0.21。简单地说,对于任何给定的汽车重量,我们得到一个单一的确定性的汽车的 MPG 值
然而,这个产值并不能真正说明全部情况。这里有两点需要注意。首先,我们只有有限的数据点。第二,从线性回归图可以看出,大部分数据点并没有真正位于回归线上。
虽然我们得到的输出值是 0.21,但我们知道实际汽车的 MPG 并不精确地是 0.21。可能略低于这个数字,也可能略高于这个数字。换句话说,有一种不确定性需要考虑进去。这种不确定性被称为任意不确定性。
确定性线性回归无法捕捉数据的这种任意不确定性。为了捕捉这种随机的不确定性,可以改为应用概率线性回归。
具有张量流概率的概率线性回归
得益于 TensorFlow Probability,建立概率线性回归模型也非常容易。但是,你需要先安装tensorflow_probability
库。您可以使用 pip 命令进行安装,如下所示:
pip install tensorflow_probability
安装这个库的先决条件是需要有 TensorFlow 版本 2.3.0。因此,请确保在安装 TensorFlow Probability 之前升级您的 TensorFlow 版本。
建立随机不确定性的概率线性回归模型
在这一节中,我们将建立一个概率线性回归模型,将随机不确定性考虑在内。
该模型非常类似于确定性线性回归。然而,不是像以前一样只使用一个单一的致密层,我们需要增加一层作为最终层。最后一层将最终输出值从确定性分布转换为概率分布。
在本例中,我们将创建一个最终图层,将输出值转换为正态分布的概率值。下面是它的实现。
注意,我们在张量流概率层的最后增加了一层。该层将把先前密集层的两个输出(一个用于平均值,一个用于标准偏差)转换成概率值,该概率值正态分布有可训练的平均值( loc )和标准偏差(标度)。
我们可以使用 RMSprop 作为优化器,但是如果您愿意,也可以使用其他优化器。对于损失函数,我们需要使用负对数似然。
但是为什么我们使用负对数似然作为损失函数呢?
负对数似然作为成本函数
为了使分布符合某些数据,我们需要使用似然函数。利用似然函数,我们尝试根据我们在数据中看到的模式来估计未知参数 θ (例如,正态分布数据的平均值和标准差)。
在我们的概率回归模型中,优化器的工作是找到未知参数的最大似然估计。换句话说,模型被训练以从我们的数据中找到给定模式的最可能的参数值。
最大化似然估计与最小化负对数似然是一样的。在优化领域,目标通常是最小化成本,而不是最大化成本。这就是为什么我们使用负对数似然作为我们的成本函数。
下面是负对数似然作为我们的自定义损失函数的实现。
任意不确定性概率线性回归模型的训练和预测结果
既然我们已经构建了模型并定义了优化器和损失函数,让我们编译和训练模型。
现在我们可以从训练好的模型中抽取样本。我们可以用下面的代码来可视化测试集和从模型中生成的样本之间的比较。
测试数据 v 从概率线性回归模型生成的样本
从上面的可视化中可以看出,对于任何给定的输入值,模型都不会返回确定性的值。相反,它将返回一个分布,并根据该分布绘制一个样本。
如果将测试集的数据点(蓝点)与训练模型预测的数据点(绿点)进行比较,您可能会认为绿点与蓝点来自相同的分布。
接下来,在给定训练集中的数据的情况下,我们还可以可视化由训练模型生成的分布的均值和标准差。我们可以通过应用下面的代码来做到这一点。
我们可以看到,概率线性回归模型给我们的不仅仅是回归线。它还给出数据标准偏差的近似值。可以看出,测试集的大约 95%的数据点位于两个标准偏差内。
建立随机和认知不确定性的概率线性回归模型
到目前为止,我们已经建立了一个概率回归模型,它考虑了来自数据的不确定性,或者我们称之为随机不确定性。
然而,在现实中,我们还需要处理来自回归模型本身的不确定性。由于数据的不完善,回归参数的权重或斜率也存在不确定性。这种不确定性被称为认知不确定性。
到目前为止,我们建立的概率模型只考虑了一个确定性权重。正如您从可视化中看到的,该模型仅生成一条回归线,通常这并不完全准确。
在这一节中,我们将改进我们的概率回归模型,将任意的和认知的不确定性都考虑在内。我们可以使用贝叶斯观点来引入回归权重的不确定性。
首先,在我们看到数据之前,我们需要定义我们对体重分布的先验信念。通常,我们不知道会发生什么,对吗?为了简单起见,让我们假设权重的分布是正态分布,平均值等于 0,标准差等于 1。
因为我们硬编码了均值和标准差,这种先验信念是不可训练的。
接下来,我们需要定义回归权重的后验分布。后验分布显示了在看到数据中的模式后,我们的信念是如何改变的。因此,这个后验分布中的参数是可训练的。下面是定义后验分布的代码实现。
现在的问题是,上面后验函数中定义的这个VariableLayers
是什么?这个可变层背后的想法是,我们试图近似真实的后验分布。通常,不可能得到真实的后验分布,因此我们需要近似它。
在定义了先验和后验函数之后,现在我们可以建立权重不确定的概率线性回归模型。下面是它的代码实现。
你可能注意到了,这个模型和之前的概率回归模型唯一的区别只是第一层。我们使用DenseVariational
层,而不是普通的密集层。在这一层,我们将先验和后验函数作为自变量传递。第二层和前面的模型一模一样。
随机和认知不确定性的概率线性回归模型的训练和预测结果
现在是我们编译和训练模型的时候了。
优化器和成本函数仍然与之前的模型相同。我们使用 RMSprop 作为优化器,使用负对数似然作为成本函数。我们来编译训练或者建模。
现在是时候让我们可视化回归模型的权重或斜率不确定性了。下面是可视化结果的代码实现。
在上面的可视化中,您可以看到线性线(平均值)以及由训练模型的后验分布生成的标准偏差在每次迭代中都是不同的。所有这些线都是拟合测试集中数据点的合理解决方案。然而,由于认知的不确定性,我们不知道哪条线是最好的。
通常,我们拥有的数据点越多,我们将看到的回归线的不确定性就越小。
最后的想法
就是这样!现在,您已经看到了概率线性回归与确定性线性回归的不同之处。使用概率线性回归,可以考虑由数据(任意的)和回归模型(认知的)产生的两种不确定性。
如果我们想要建立一个深度学习模型,其中不准确的预测会导致非常严重的负面后果,例如在自动驾驶和医疗诊断领域,考虑这些不确定性是非常重要的。
通常,当我们有更多的数据点时,模型的认知不确定性会降低。
交易的概率机器学习方法+ MACD 商业理解
在文章的最后,你会知道如何用概率的方式构造一个交易问题。此外,您将通过听取专家的意见来学习如何改进特征工程流程。最后,我们将用真实数据训练一个随机森林来应用这些概念!。(奖励音轨:很酷的可视化效果)。
0)我们的动机
故事是这样的:我们是投资者,我们有,比如说,1,199 美元(很快你就会明白为什么我用的是 1,199 美元而不是 1,000 美元),我们的目标是最大限度地利用它们(我们会想要别的吗?).我们决定进入加密市场,因为它的波动性。为了维持我们的合作关系,我们需要持续盈利。我们希望使用机器学习,同时不忘记交易者使用的业务理解。现在,我们唯一需要知道的是如何做到的(哇…我肯定会在我的下一场自由泳比赛中使用它)。我们能做到吗?我们来想办法吧!
0.a)我能从这里学到新的东西吗?
快速回答:是的,那是我的本意。我邀请你在接下来的 18 分钟里——根据中等估计——和我在一起。如果你现在没有时间,就把这个链接加到你的记事本上,但是为了充分利用这里,我希望你能集中所有的注意力。我知道我要求很多,但我向你保证这是值得的。那么,我为什么要写这个呢?:
第一个:我看过很多与交易相关的文章,这些文章用令人难以置信的模型训练,使用令人印象深刻的算法,很酷的可视化,以及出色的写作风格。但我没有找到更详细的解释,这是一个简单的例子,基本理解如何在现实世界中使用它们。
第二个:大量的这些文章可以归类如下:“用你自己的交易机器人设定你的策略”和“预测股票价格的最佳机器学习模型”
“交易机器人”类型很好理解能够充分反映指标和可观察图表行为之间的相互作用的逻辑:**商业理解。**另一方面,机器学习模型非常擅长使用指标作为变量来捕捉更广泛的市场场景:数据科学知识。
从夹住。
然而,我错过的是这些概念的融合。交易机器人的问题是,简单的刚性策略可能没有其他指标的支持。另一方面,“股票价格”类型关注指标,但它们缺乏背景,没有背景,它们通常是无用的,或者至少不太有效。
0.b)议程
正如你所看到的,我会试着给你我对如何解决这些问题的看法。为了将重点放在最近暴露的概念上,我将留下模型训练部分的一些细节(如模型选择或超参数调整)。测试的想法将是,如果我们设法抓住这些业务概念并将它们与我们的数据科学知识相结合,我们可以在多大程度上提高我们的准确性。我们的议程:
- 我将首先向你介绍一些必要的概念。在开始考虑训练我们的模型之前,只是一些基本的东西。
- 我们将讨论费用如何通过影响我们的预期回报来影响我们的决策。
- 我们将讨论捕获风险管理程序的候选模型的要求。
- 最后,我们将描述如何获取市场的商业解释,然后用它来增强我们的模型。这里是工作完成的地方,最令人兴奋的部分!如果你了解背景,你可以快速阅读其他部分,但重点是这里。你不会后悔的。
- 我们将简要回顾一下我们的主要观点。
1)风险管理
首先,让我们从它在交易环境中的定义开始。
风险管理 :“是用于减轻或保护您的个人交易账户免受失去所有账户余额的危险的过程。”
这个过程涉及不同的决策,如果你愿意,它可以获得难以置信的复杂性。目前,这超出了我们的范围,所以我们将只关注其中的两个:
- 预期收益 : 是交易收益的期望值。
- 最大风险:你愿意为一笔交易放弃的总资金的最大数额。
1.a)预期回报
要将我们的赌注转化为计算好的走势,我们需要评估这种情况,以了解我们的胜算。因为我们不是赌徒,我们需要定义我们的止损点 (S/L)和止盈点 (T/P)。这些是我们定义的结束我们交易的价值观。
想象一个乌托邦世界,新冠肺炎被根除,以太坊再次达到 1000 美元。那时,我们决定买一些。此外,我们认为,如果价格下跌超过 20%,我们可能处于危险的境地,所以如果价格超过 800 美元,我们将出售它。另一方面,如果价格上涨超过 25%,我们会很乐意卖掉它,获得 250 美元的利润。
情绪状态,S/L 红线和 T/P 绿线。此处代码。
如果我们忘记了时间变量,在每笔交易中,我们只有两种结果,我们可以赢,也可以输,取决于哪个价格先到达(S/L 或 T/P)。想象一下,我们认为我们有 45%的机会赢,55%的机会输。预期回报计算如下。
来自维基百科的公式。
这是我自己做的。
你可以看到,这是所有给定案例的概率和它们的回报的乘积之和。在我们的例子中,每笔交易的预期回报是 2.5 美元。这意味着,如果机会是正确的,我们重复这个过程,例如,100 次,我们将获得大约 250 美元的利润。
1.b)最大风险
另一个重要的任务是确定我们愿意在一次交易中损失的最大金额。这是因为,如果我们在一次交易中冒险投入 20%的资金,我们很有可能会输掉前三次交易。我们最终会拿走一半的钱,热泪盈眶,我们美好的友谊也可能就此结束。
为了避免这种情况,因为从这样的损失中恢复是困难的,也因为我非常珍惜我们的友谊,我建议你使用典型的 1%法则。这意味着,如果我们有 1,199 美元,我们不允许每笔交易损失超过 11.99 美元。
我是一个喜欢冒险的人,所以我强迫你在每笔交易中,我们的亏损场景将是定义的最大 1%的亏损(这是为了我们的例子简单起见,我没有那么糟糕)。在这样做的时候,有一些重要的事情需要考虑,独立于我们的结果,我们需要支付费用。多么痛苦的现实啊!
2)现实生活
假设我们为菜鸟交易者使用市场上最好的费用。我们选择币安。他们对接受者和制造者收取 0.1%的佣金。这意味着,如果我们用 1.000 USDT (这里是为什么 USDT 而不是美元)购买以太坊,我们需要支付 1 USDT 费用,仅仅是为了购买。
来自币安的费用表。
我们的 S/L 和 T/P 将分别为-1%和 1%(请记住,它可以是您想要评估的任何 S/L 和 T/P 点)。如果价值达到 990,我们有义务出售,但是不要忘记,我们需要为第二次交易支付 0.99 USDT。在这种情况下,我们损失了 11.99 USDT,这是我们 1,199 美元初始资本所能承受的最大金额,现在完全说得通了。
如果价格首先到达 T/P 点,我们得到 10 USDT 的利润和 2.01 USDT 的费用,这意味着我们将得到 7.99 USDT 的正结余。鉴于这种情况,我们需要在这方面投资的积极成果的可能性有多大?如果你快速回答了 60%,说明你拥有令人印象深刻的快速计算技能,下面是数学程序,假设 P(n)是负面结果的概率,P§是正面结果的概率,并且
1-P(n)=P§。
这也是我自己做的
我们需要我们的预期收益(1)大于或等于零。否则,我们将持续亏损。由此得出的一个重要结论是,如果我们提高 S/L 和 T/P 百分比,我们不需要 P§那么高。例如,如果我们用 3%和-3%来评估我们的最后一个场景,我们只需要 53.3%来进行交易。
这就是为什么我羡慕每一个能在 RobinHood 上创建账户的人。我不被允许,因为我“来自美国之外”如你所见,无费用交易让你处于更有利的位置。你不会开始输。不过,我已经抱怨够了,让我们去看看是什么让我们来到这里。
3)使用机器学习定义赔率
我们谈了很多关于预期回报的问题,所以我们肯定会使用这种方法,但这不是唯一的方法。事实上,我见过的最常见的方法是使用波动性的测量值(在这里有清楚的解释)来估计交易的风险。我告诉你这个是因为这是标准的近似值——这里不会用来维护结构——但也是一个很好的选择。
我们都很聪明,但在密码市场没有多少经验。所以我们明白,我们的勇气和我们曾经看过的布林线文章,不足以定义与我们的 S/L 和 T/P 点相关的概率。现在我们的目标是思考哪种机器学习算法最适合这个问题。
我们看到这个问题由一个积极的和一个消极的结果组成。因此,我们可以断言这是一个标准的二进制分类问题。此外,我们需要一个分类器,能够给出在特定情况下每种结果的概率。理想情况下是这样的:
在理想世界中,你的模型给出了每一点的 P§。这里的代码。
为什么那样?因为我们需要知道几率来检查我们交易的预期收益是否为正。对我们来说,一个简单的“将要上涨”的信号是不够的。这种类型的模型被归类为一类概率估计。交易不是赢得所有的进场。这是概率问题!
尽管我们可以出于不同的动机(KNN,SVM,所有不同的自回归模型,K-Means,以及许多其他模型)放弃许多选项,但我们仍然有一些优秀的候选人。
我们的一些选择是朴素贝叶斯分类器、逻辑回归、决策树、随机森林或不同类型的神经网络。候选人少了,工作量也就少了。测试他们所有人的结果将会是惊人的。正如我之前告诉您的,这超出了本文定义的范围。但是对于我们的例子,我们将训练一个随机森林。
4)如何捕捉交易逻辑作为机器学习问题的变量?
我想用一个例子让你们对此有所了解。主要的想法是理解我们的专家提供的见解:交易者!如果他们一整天都在做这些,我们需要保持谦卑,听听他们要告诉我们什么。这是这个问题中的关键过程,也是你愿意解决的任何问题中的关键过程**。我们需要这样的商业环境。**
我们的目标是做最好的功能工程!。创建变量的过程需要基于商业概念。只有在这之后,我们才能应用所有常见的转换,如标准化或规范化(只有最后一部分才有意义!).
这一部分的目标是比较第一种简单方法的性能,然后是交易机器人近似方法的性能,最后,尝试将所有部分结合在一起。我们将假设我们只能持有多头头寸,正因为如此,我们只对正面结果的预测感兴趣。
PS:我会把这部分代码全部留在我的github上。尽管有一些例外,代码将是通用的,以获得流动性。此外,由于抽样的随机性,一些结果可能会发生变化(我测试过,变化不是很大)。
4.1)我们的数据
我们将从币安检索我们的数据,你可以阅读这个博客来创建你的 API-KEY。这里的是 python-币安的文档。我们将使用 5 分钟间隔的数据。下面是收集数据的代码(3 行数据,我正在转换成 Flash?).
来自币安的 5 分钟间隔数据。(我们的例外)。
4.2)我们如何标记我们的 0 和 1?
我做了一个方法,决定先发生什么:增加 0.5%还是减少 0.5%。逻辑如下:该方法寻找接下来的 100 个时间段(对于 5 分钟的数据,超过 8 小时)并检查价格是否超出我们定义的阈值,仅考虑第一个达到的值。
我只是使用了接近的价格,因为高值和低值可能同时高于或低于我们的目标,给我们带来一些麻烦。不出所料,并不是在所有的情况下,都有结果,但是百分比并不高,我们可以去掉那些数据。
技术说明:收集的数据涵盖了截至 2020 年 4 月 22 日的前 500 天。我用 1 标记+0.5%的结果,用 0 标记-0.5%的结果。如你所见,数据没有明显的不平衡。在总共 143,542 个数据点(120,245 个用于训练,23,297 个用于测试结果)中,数据点 49.85%为阴性,49.82%为阳性,1.26%没有结果。
4.3)指示器
TA 包有一个方法可以构造很多有用的指标。最棒的是,我们需要选择的所有参数都有自己的默认值。然而,如果我们愿意,我们可以改变它们。
import pandas as pd
import numpy as np
import ta
df=pd.read_csv('Binance-ETHUSDT-22-04-2020')
df['timestamp']=pd.to_datetime(df['timestamp'],format='%Y-%m-%d %H:%M:%S')
df.set_index('timestamp',inplace=True)
df=df.astype(float)
df1 = ta.add_all_ta_features(
df, open="open", high="high", low="low", close="close", volume="volume")
4.4) MACD
交易者是业务理解者,如果我们的模型仅仅基于技术分析——这可能反映了新闻——我们需要了解指标!。但是正如我之前告诉你的,这些人如此努力地将他们联系起来定义策略,以至于他们最终获得了对组合的直觉。我们的工作是将直觉转化为数学!。
作为一个例子,我想和你谈谈移动平均线收敛发散( MACD )指标。这是交易者之间最常见和广泛传播的方式之一。MACD 的计算方法是从短期均线中减去长期指数移动平均线(均线)。之后,你创建一条“信号线”,这是 MACD 的均线。最常用的参数分别是 26、12 和 9。
4 月 10 日和 11 日以太坊价格和指标。
使用 mplfinance 你可以像交易者一样实现可视化。上图中,你可以在主面板上看到一个普通的 OHLC 烛台。在下面的面板中,我们有两件事情正在进行,直方图上的量,以及用虚线表示的指标(灰色的 MACD 和青色的 MACD _ 信号)。
你可能会感到困惑,因为通常的表示法是用两根 MACDs 的差值来创建柱状图。但是不要觉得失落!直方图是体积。我只是将图表中的信息量最大化(我们不需要线条上包含信息的直方图,不是吗?).
4.5)我们能单独相处吗?
好吧,很酷的指示器,很酷的可视化,但是如何使用它们呢?这是我们必须尝试一些策略的部分。有了我们的数据科学,知识就足够了?我们来想办法吧!下面的部分是给你一些变量的背景。我把一些箱子里的指示器分开了。我们可以检查这些值本身是否在这些范围内给了我们积极或消极结果的线索。
MACD 宾斯,分开的结果。
MACD _ 信号仓,由结果分开。
MACD 信号和 MACD 的区别
在左侧的箱上出现正面结果而在右侧出现负面结果的概率似乎更高。但似乎没有什么是防弹系统。我们看到了这一点,并且我们确信我们能够有所作为。所以我们可以继续前进。
是时候训练我们的第一个模型了!假设我们认为结果只取决于我们刚刚看到的三个测量值(显然不是),但我们仍然可以训练我们的模型,看看它如何发展。首先,我们将平衡积极和消极的结果,然后,使用我们钟爱的标准标度转换我们的变量。培训数据将一直使用到 2020 年 2 月 1 日。其余的将用于测试结果。
技术说明:“初始”将是 2 月之前的指标数据框架,“指标”是整个数据框架,但对于[120245:]它只是测试数据。
Initial = Initial.sample(frac=1)
X_train = Initial[["trend_macd", "trend_macd_signal", "trend_macd_diff"]]
y_train = np.where(Initial["Outcome"] == "+0.5%", 1, 0)
X_test = indicator[120245:][["trend_macd", "trend_macd_signal", "trend_macd_diff"]]
y_test = np.where(indicator[120245:]["Outcome"] == "+0.5%", 1, 0)
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import confusion_matrix
sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)Classifier1 = RandomForestClassifier(
max_depth=2,
min_samples_leaf=400,
max_features=2,
min_samples_split=4,
n_estimators=1000,
random_state=28,
)
Classifier1 = Classifier1.fit(X_train, y_train)
y_pred1 = Classifier1.predict(X_test)confusion_matrix(y_test, y_pred1)
混淆矩阵
垂直的数字代表真实的结果,水平的数字代表预测。例如,在这种情况下,我们预测了 9505 个积极的结果,其中 53.8%的预测是正确的。正确分配坏的结果有一些小麻烦,但是我们可以暂时忘记它。
你还记得我们讨论预期收益的所有前奏吗?现在是时候使用它了!。我们可以使用 predict_proba 来获取正面结果的概率。下图显示了给定某个 P§的成功概率,在这种情况下,我们知道 P§>0.5=0.538。理论上讲,预测概率越高,我们的胜算就越大。
在每个矩形的顶部,您可以看到满足该条件的案例数量。概率越大,涉及的案例越少。但总的来说,我们找到了我们所期望的!P§越大,成功率越大。如果我们每次都用这个策略进去,P§>0.6,我们最终会得到131235 的正确条目!。
4.6)贸易-Bot 战略方法
每个指标都有不同的使用方法,这取决于和你交谈的交易者。但是,有一个话题有一些共识。协议规定,当 MACD 越过信号线上方,也就是最后一条线低于零时,就是进场信号。如果你走得更远,他们也会告诉你这只是一个进场信号,如果市场的趋势和信号的方向一致。
还有多种方法可以检验市场趋势,我们会坚持其中一种。比较 200 周期均线和收盘价。如果价格高于均线,我们认为这是一个上升趋势。对于相同的测试数据,这是一个简单的过滤器,可以过滤出满足这三个条件的情况。
为了让这变得更有挑战性,我将向您展示我们测试数据的前 4 天(对于 GIF 大小来说不会更多)。下面你可以看到两个新的东西。首先是 200 期均线虚红线。另一个新的事情是,我会标记进场点,只要它们满足所有条件(如果交易结果是负面的,用红色表示,如果是正面的,用绿色表示)。
这—不太好— 4 天反映了整个期间最终发生的事情。204 次符合条件, 97 次符合正面结果。这不是我们所期望的,但我们不必忘记这只是硬性规定。在下一节中,我们将更深入地探讨这一战略的精神。
4.7)将所有功能整合在一起!
好吧,我们的近似有体面的结果,而交易机器人不是那么好。但是如果我们想用真正的费用投资,那些结果是不够的。我们能改进吗?这就是我们在这里的原因!我们的工作是了解正在发生的事情,也许如果我们停下来想一想,我们的结果会更好。
规则背后的直觉是什么?我听一些交易者说,预期 MACD 信号在零线后面的原因是因为他们预期有一个更高斜率的交叉。因此,如果我们加入一个变量来反映 MACD 上升的力度,我们可能会得到一些更好的结果。
这可以通过将指标与最近时期之间的差异作为一个变量来实现。为了反映这一点,我们将使用移位方法来减去实际值与之前的 1、3 和 5 个周期。但是这些概念也适用于其他两个组件。所以我们会对每个变量都这样做。这将为我们提供 9 个额外的变量,它们的任务是反映这些指标的来源。
同样,我们可以理解趋势也很重要,但也许没有必要把它作为一个二元变量。相反,我们可以用收盘价减去 200 均线,然后除以收盘价,得到它们之间的百分比差。让我们看看会发生什么!
indicator['trend_macd_diff1']=indicator['trend_macd_diff']-indicator['trend_macd_diff'].shift(1)
indicator['trend_macd_diff3']=indicator['trend_macd_diff']-indicator['trend_macd_diff'].shift(3)
indicator['trend_macd_diff5']=indicator['trend_macd_diff']-indicator['trend_macd_diff'].shift(5)
indicator['trend_macd_signal1']=indicator['trend_macd_signal']-indicator['trend_macd_signal'].shift(1)
indicator['trend_macd_signal3']=indicator['trend_macd_signal']-indicator['trend_macd_signal'].shift(3)
indicator['trend_macd_signal5']=indicator['trend_macd_signal']-indicator['trend_macd_signal'].shift(5)
indicator['trend_macd1']=indicator['trend_macd']-indicator['trend_macd'].shift(1)
indicator['trend_macd3']=indicator['trend_macd']-indicator['trend_macd'].shift(3)
indicator['trend_macd5']=indicator['trend_macd']-indicator['trend_macd'].shift(5)
indicator['trend']=(indicator['200MA']-indicator['Close'])/indicator['Close']
Initial = Initial.sample(frac=1)
X_train = Initial[
[
"trend_macd",
"trend_macd_signal",
"trend_macd_diff",
"trend_macd_diff1",
"trend_macd_diff3",
"trend_macd_diff5",
"trend_macd_signal1",
"trend_macd_signal3",
"trend_macd_signal5",
"trend_macd1",
"trend_macd3",
"trend_macd5",
"trend",
]
]
y_train = np.where(Initial["Outcome"] == "+0.5%", 1, 0)
X_test = indicator[120245:][
[
"trend_macd",
"trend_macd_signal",
"trend_macd_diff",
"trend_macd_diff1",
"trend_macd_diff3",
"trend_macd_diff5",
"trend_macd_signal1",
"trend_macd_signal3",
"trend_macd_signal5",
"trend_macd1",
"trend_macd3",
"trend_macd5",
"trend",
]
]
y_test = np.where(indicator[120245:]["Outcome"] == "+0.5%", 1, 0)
from sklearn.preprocessing import StandardScalersc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)
from sklearn.ensemble import RandomForestClassifierClassifier = RandomForestClassifier(
max_depth=11,
min_samples_leaf=400,
max_features=11,
min_samples_split=4,
n_estimators=500,
random_state=28,
)
Classifier.fit(X_train, y_train)
y_pred = Classifier.predict(X_test)from sklearn.metrics import confusion_matrixconfusion_matrix(y_test, y_pred, normalize="true")
在不利结果方面,它似乎做得更好,但在积极结果方面,我们的表现稍好一些(53.98%的真阳性)。嗯……这可能会令人沮丧,但是嘿!不要在看 P§图之前就放弃。也许会给我们带来好消息,谁知道呢?
我就知道!!这个柱状图的出现是为了拯救世界!。不出所料,成功率越来越高!我们可以看到,与我们制作的第一个相比,这个模型有了明显的改进。为什么?因为它可以更好地分离出具有更高成功率的条目概率的情况。
假设我们选择策略:在 P§>0.62 时买入。我们的计划会成为一个炸弹!我们得到了 188 个信号,其中 124 个成功(有效 65.95% )。重要的是,我们利用所学的一切,设法制定出一个好的策略!。好了,我要放松了,今天太兴奋了。
我们做到了这一点,只用了一个指标!如果我们认为模型可以包含其他具有不同概念的基本指标,如交易量或波动性,这是有希望的。但是那个家伙,那是完全不同的故事。
5)后会有期!
我度过了一段美好的时光,并与你分享,我希望这对你有所帮助。如果你因为结束而高兴,给我你的最后一分钟!我喜欢仪式,用我们的主要外卖做一个结束仪式会提升我的精神:
- 我们定义了风险管理程序的一小部分,理解了预期回报的重要性。
- 我们遭受了费用对我们决策的影响。
- 我们看到了为这项任务选择类别概率估计模型的重要性。
- 我们知道如何根据业务概念改进我们的功能工程,在关键的地方获得更高的成功率。
- 你现在可以做酷酷的动作可视化了!
这就是我给你的全部内容,我知道这是基本概念,但主要目的是即使你对交易了解不多,你也能理解这一点。现实生活中的系统也有很多方法可以使这些策略更加稳健。此外,我做的很多决定都会引发争论,这是我所期待的!我很乐意讨论你的不同想法,给我一个你的想法的回复!
如果我感受到你的热情支持,我会带着新鲜的内容回来!
由于你给了我很大的支持,我想出了一个延续:
我们的目标是静态的吗?
towardsdatascience.com](/optimizing-the-target-variable-an-example-for-trading-machine-learning-models-48a1587d7b9a)
这是强制性的,你不要用这个策略投资或交易,因为这篇文章的主要目的是谈论商业理解。使用交易的想法:它只是一个工具,用来访问真实的问题和真实的数据。如果你遵循这个未经证实的系统,你很容易失去你的存款!。
如果你喜欢,就在 Medium 和 Linkedin 上关注我。如果你想给我写信,我最近在推特上。我很乐意与你交谈!
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指南 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
用于乳腺癌检测的概率深度学习
来源: Unsplash
在本文中,我将演示使用变分推理来量化深度神经网络权重的不确定性,并为乳腺癌分类数据集做出更明智的预测。
我将在 PyMC3 中构建一个概率神经网络,它使用 ADVI 来优化我们模型的参数。我们将更多地考虑神经网络权重的后验分布,以及我们可以从中获得的见解。
目标
这里的目标是建立一种算法,可以分析关于乳腺癌细胞的信息和指标,以预测细胞中的癌症是“良性”还是“恶性”
乳腺癌的分类是一个二元分类问题,其中我们将细胞分类为良性或恶性。良性肿瘤是一种不会扩散到身体其他部位的非侵袭性肿瘤。恶性肿瘤是一种侵袭性和癌性肿瘤,可以通过血液扩散到身体的其他部位。如果被确定为“恶性”,乳腺癌需要更有效的治疗。
犯假阴性的代价
在这个分类问题中,有两种错误——假阴性和假阳性。假阳性(良性癌症被归类为恶性癌症)将导致我们最终给患者服用更强的药物。虽然这会带来额外的成本和风险,但不会危及生命。任何假阴性(恶性癌症被错误地归类为良性)都可能是致命的,我们应该不惜一切代价避免它。
我们来量化一下这个损失。假阴性会危及生命。因此,假阴性的代价等于一个人生命的价值。虽然对生命的代价存在重大争议,但人类生命的代价大约是 1000 万美元。(注:我不完全同意给生命贴上价格标签,但你应该读一下的这篇文章。)与此同时,导致更多医疗费用的假阳性的成本约为 8 万美元。这两个错误的比例是 125。因此,提交一个假阴性与提交 125 个假阳性是一样的。
使用整体准确性作为衡量标准来微调算法是没有意义的,因为它掩盖了假阴性和假阳性的分布。因此,我们需要一种算法来将假阴性的数量减少到绝对最小值。因此,我们希望根据假阴性的数量来优化我们的模型。
在这个算法中有很多地方,我们可以改变参数来影响结果。在这种情况下,我们将微调算法中的一切,以减少假阴性的数量。
数据
我从加州大学欧文分校的机器学习库中获得了这些数据。在数据集中,科学家将肿瘤细胞的图像转换成九个基本指标:
- 半径,
- 纹理(灰度值的标准偏差),
- 周界,
- 面积,
- 平滑度,
- 紧凑性,
- 凹度,
- 凹点
- 对称。
因此,图像被简化以供我们使用。因此,我们需要更少的预处理来使我们的数据为分析做好准备。
数据清理
原始数据文件是未经处理的字符串数据,其中每个值都必须进行分离和处理。一些列有空值。我们清理数据,并在 NumPy 数组中将它转换成可供分析的格式。(注意:大多数 ML/AI 算法接受 NumPy 数组作为输入,因为 NumPy 数组作为矩阵工作。因此,对数据执行线性代数(如点积/投影/乘法)变得容易多了。)
下面是获取原始数据的代码。数据文件并将其合并到干净的 NumPy 数组中。请注意,我故意编写了比平时更长的代码,因为我想演示实际的处理和转换。通过 pandas/NumPy 内置函数,同样的过程更加简单,尽管它们可能不会更快。
*""" This section extracts and cleans all the data in the .data file """***def** extraction(pathname):
initial = open(pathname)
image_data = []**for** line **in** initial:
image_data.append(line.strip())
*#Extracting data line by line*
final_data = []
target = []
*# Each line is a record that contains the attributes, delimited by a comma*
**for** string **in** image_data:
string2 = list(string)
bad_data = **False**
indexes = [-1]
**for** (index,element) **in** enumerate(string2):
**if** element == ',':
indexes.append(index)*# Finding the indexes where the string needs to be be cut*
indexes.append(len(string))
data = []
**for** i **in** range(1,len(indexes)):
*# For each split by a comma, we extract the element*
element = string[indexes[i-1]+1:indexes[i]]
**try**:
*# If the data is float, we extract it*
element = float(element)
data.append(element)
**except**:
*# Otherwise it's bad data.*
*# This includes inputs like missing data, 'NA' or 'nan'*
bad_data = **True**
**if** **not** bad_data:
final_data.append(data[1:len(data)-1])
target.append(data[-1])*# Appending the data and the class to the data list and target list*
**return** np.array(final_data), np.array(target).reshape(len(target))
我们将继续把这段代码放在一个 Python 类中。python 类帮助我们将所有相关的函数和数据保存在一个对象中。
这里的输出是两个 NumPy 数组。一个是维数(或形状)为(683,9)的特征数组。因此,它有 683 条记录,每行有九个属性或维度。第二个是 shape (683,1)数组,这是我们的目标。在目标类别中,1 表示恶性,0 表示良性癌症。让我们来处理我们的实际数据:
特征工程和数据整合
在这一点上,有人可能认为我们应该投入到模型中,并尝试对其进行调整。但是这种方法的问题很简单:
输出结果中的偏差是数据和算法的函数。如果数据的结构、规模和清理不当,算法只能起到减少偏差的作用,但无法弥补数据缺乏一致性的问题。
所以让我们开始吧。首先,我们检查要素之间的多重共线性。我们将使用关联热图来检查:
使用上述代码生成的关联热图。来源:自己的作品。
在此热图中,重点关注任意两个变量之间过度相关的非对角线元素。我把极端相关度定义为 80%,但也要看问题的语境。在这里,纹理和参数似乎是极其相关的(91%)。但是我不会移除这个变量,因为这两个变量实际上都很重要。这两个参数在肿瘤细胞的生物学中是必不可少的,因此即使我们没有看到非常统计上的好处,因为 90%的变异是相同的,另外 10%可能有一种模式,这将提高我们算法的能力。
值得在没有任何参数的情况下重复分析(就像 A/B 测试实验一样),但是移除变量需要理论证明。我删除了凹度,因为它提高了我的模型的性能。
下一步是正常化。数据的比例不正确,一些参数的比例与其他参数的比例不同,这可能会使算法偏向一个要素。因此,我们使用标准缩放器来重新缩放所有特征,这将所有特征转换为均值为 0、标准差为 1 的新分布。
**注:**欢迎大家进一步进行数据整理和理解。这里没有限制!我还测试了一个 PCA 和一个 LDA ,试图减少我的数据集中的维数。有趣的是,它没有影响维度,这证明了一个事实,即每个特征都有其变化,不能组合成另一个。主成分分析确实重新排列了维度,这使我们在准确性和假阴性数量方面有了微小的提高。我们将在最后考虑这个问题,但是欢迎您在这里执行自己的 A/B 测试。你也可以在这里下载处理后的数据。
神经网络
如果你不知道什么是神经网络,你可以在这里了解更多。我们试图在多个层中构建“决策节点”,接受数据并进行转换。这些转换有助于对数据做出决策。多个层次做出越来越多的决定,共同导致最终的答案。这就像建立一个规则图,让算法用给定数据后有意义的法律来填补空白。每个节点都有一个激活函数,它采用输入的加权和并提供一个输出,该输出成为神经网络下一层的输入。本文的重点是构建网络并使用它来获得结果的过程。你可以在这里了解更多关于建立神经网络的想法。
概率神经网络
在上面链接的文章中, Marco Peixeiro 谈到了位于神经网络每一层的节点所使用的函数形式。这些“激活函数”在技术上是固定的,并且每个节点的输入权重在网络中被优化。但是简单的神经网络是确定性算法。它给了我们一个重量的估计,你可以用它来做预测。但是没有关于这些估计的不确定性或最终预测的不确定性的信息。这些估计以预测概率或我们估计的置信区间的形式出现。因此,探索贝叶斯推理和神经网络的结合来帮助我们识别这些算法中的不确定性是有价值的。
具体来说,我们希望提取以下信息:
- **我们预测的不确定性:**这是以“恶性”对“良性”的概率的形式出现的,而不仅仅是二分法。
- **权重中的不确定性:**对于神经网络的每一层,我们希望了解这些权重中的不确定性,并使用它来评估我们的神经网络的质量。
- **赋予权重先验的能力:**还记得贝叶斯推理吗?我们将初始化参数的先验,并获得基于先验和给定先验的数据的似然性的后验样本/估计。这些估计将为我们提供不确定性估计。因此,将 a 置于神经网络中节点权重之前的能力将增加我们分析的价值。
- **分层建模:**神经网络的一个重要方面是理解和汇集基于子群的参数的能力。例如,我们可以估计癌症样本的种族的不同权重(这可能非常重要,因为已经有大量研究证明种族影响乳腺癌的死亡率)。
- 建模的灵活性:贝叶斯推理带来了建模的灵活性和主观性。虽然这种灵活性可能会威胁到模型的可靠性,但如果您是专家,并且了解我们数据的不同输入之间的交互的本质细节,这将是有益的。
自动微分变分推理
如果你对 MCMC 或者变分推理(VI)不太了解,你应该看看这篇文章。总而言之,VI 对给定的参数进行分布,然后优化这些分布。例如,网络某一层的权重具有正态分布的先验,我们使用 VI 来找到该分布的最佳平均值和标准偏差。
VI 使用 KL-Divergence,这是一个成本函数,帮助我们了解我们的目标概率分布和当前分布之间的距离。但是 VI 不是全自动的,需要微调。因此,我们将使用一个称为自动微分变分推理(ADVI)的 VI 版本,它优化了一个不同的参数(类似于 KL-Divergence,但更容易优化)。该算法使用各种库来区分 ELBO(我们这里的度量)并找到最大值来更新参数。它使用坐标下降(沿坐标轴优化)来实现参数更新方程。我知道这是很多信息,但是我推荐你阅读这篇文章来熟悉它。
用 PyMC3 中的 ADVI 构建神经网络
对于这个实现,我们不会从头开始构建 ADVI 算法。相反,我们将使用 PyMC3 的内置特性来开发我们的模型,并指定我们想要实现的参数、先验和网络层。
对于这个特定的实现,我将构建一个具有三层的神经网络。最后一层是感知器,也是最后的决策层。我将为它使用一个 sigmoid 函数,这样它就像一个逻辑回归。内部的两个隐藏层将使用“双曲正切”函数。您可以在这里使用 PyMC3 文档中您喜欢的任何函数。我用‘tanh’是因为它的灵活性。在 3.14 弧度的旋转中,Tanh '可以从-无穷大到+无穷大,因此,它可以很容易地模拟不同种类的渐变。
对于每一层,我们必须对每个网络的权重进行先验分布。这些权重处理输入并帮助函数做出决策。我使用标准正态分布(均值为 0,标准差为 1)来构建权重矩阵。请注意,这是一个不知情的先验。如果您有相关的知识来支持您的选择,您可以使用不同的发行版。
**对于我的网络架构:**每一层接受输入并产生输出。输出的维度比前一个维度少一个。因此,层 1 与 9 维的整个数据集一致,并产生 8 维的隐藏和处理输出,该输出被馈送到第二层。第二层输出七个维度,然后由感知器(基础层)作为逻辑回归进行处理。使用伯努利可能性将最终输出建模为二进制结果。看看下面的代码,跟着注释走:(注意,这个实现的基本结构是受托马斯·威茨基的帖子这里的启发。我已经采取了骨架结构,并实现了一个新的,有组织的和知情的神经网络)
import numpy as np
floatX = theano.config.floatX
import pymc3 as pm
import theano.tensor as Tdef build_network(X_train, Y_train):
**# We're initialising the weights here
(the parameters we need to optimise)****# Note that the shape of the distribution
should match the dimension of the layer.
# So, first distribution should go from X.shape[1] = 9 to 8**initial_weights_1 = np.random.randn(X.shape[1],8).astype(floatX)
initial_weights_2 = np.random.randn(8, 7).astype(floatX)
initial_weights_p = np.random.randn(7).astype(floatX)**# Initialising a model**
with pm.Model() as neural_network:**# Denoting input data** features = pm.Data('ann_input', X_train)
output = pm.Data('ann_output', Y_train) **# Denoting targets**
** # We're now taking the set of parameters and
assigning a prior distribution to them.
# The pm.Normal assigns a Normal distribution
with mean 0 and standard deviation 1**
prior_1 = pm.Normal('w_in_1', 0 , **#mean**
sigma=1, **# standard deviation**
shape=(X.shape[1], 8), **#shape of set of parameters**
testval=initial_weights_1) **#initialised parameters**
prior_2 = pm.Normal('w_1_2', 0, sigma=1, shape=(8, 7),
testval=initial_weights_2)prior_perceptron = pm.Normal('w_3_out', 0, sigma=1,
shape=(7,), testval=initial_weights_p)
**# Now, we'll assign the functional form of each layer
# tanh for the first three and sigmoid for the perceptron**layer_1 = pm.math.tanh(pm.math.dot(features, prior_1))
layer_2 = pm.math.tanh(pm.math.dot(layer_1, prior_2))
perceptron = pm.math.sigmoid( pm.math.dot(layer_2,
prior_perceptron))
**# A bernoulli distribution as the likelihood
helps model the 0,1 target data as pass/fails**likelihood = pm.Bernoulli('out', output, observed=output,
total_size=Y_train.shape[0])return neural_network
让我们现在构建网络,并在其上放置一个随机种子,以消除任何起始偏差。
**from** sklearn.model_selection **import** train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size= .5)neural_network = build_network(X_train, Y_train)from pymc3.theanof import set_tt_rng, MRG_RandomStreams
set_tt_rng(MRG_RandomStreams(101))
网络权重的含义
神经网络中每个连接的权重示例。来源 : 黑客月
简单地说,每个节点都有一个处理数据的激活函数(就像我们使用的 tanh 函数一样)。该数据然后被加权,然后提交给下一层中的每个节点。这些权重决定了一个节点对下一层中每个节点的影响。通过提取每个权重的不确定性,我们可以了解总体预测不确定性的根源,并将其追溯到数据特征。因此,这些不确定性在用户和神经网络之间提供了急需的透明度,神经网络的隐藏层(节点前后的垂直堆叠变换)更难解释。
优化时间!
我们将使用内置的 ADVI 算法来优化神经网络的权重分布。PyMC3 使它的实现变得非常简单:
with neural_network:inference_method = pm.ADVI()
approx = pm.fit(n=30000, method= inference_method)**# n is the number of iterations for ADVI**
**# method is where we denote the ADVI() from PyMC3**plt.figure(figsize=(12,6))
plt.plot(-inference.hist, label='new ADVI', alpha=.3)
plt.plot(approx.hist, label='old ADVI', alpha=.3)
plt.legend()
plt.ylabel('ELBO')
plt.xlabel('iteration');
尽管 PyMC3 屏蔽了 ADVI 代码,但还是有必要查看一下后端代码来理解这个过程。您将在 PyMC3 Github 存储库的这个 python 文件中找到 ADVI 代码。复习第 323 行的 ADVI 类。ADVI 职能部门的以下文件至关重要:
ADVI 代码进一步依赖于从推理. py 文件导入的平均场推理函数。它执行简单的平均场推断。同时,它分析输入参数并相应地采取行动。在这种情况下,MeanField()的* *参数还包括一个 ELBO 自动优化的注释。默认为 KL-Divergence。
ELBO 随迭代次数的变化。**来源:**自己的作品
ELBO 的优化在 19 秒内完成。但是关于这个模型有一些事情会导致 ELBO 收敛的问题,包括我们在 500 次迭代后观察到的收敛中的噪声。首先,它是一种神经网络,不总是能很好地处理小数据集。训练数据集只有大约 342 个数据点。因此,网络发现在只有 342 个数据点的情况下训练自己并解释所有的复杂性是一项挑战。因此,ELBO 的优化并不简单。
其次,神经网络很难建立。要知道创建正确网络所需的隐藏层数并不容易。因此,模型规范中也存在不确定性。让我们试着解决这些问题:
微调 ELBO 的优化
有多种方法可以确保模型的 ELBO 优化不会发散。这些指标定义了每个神经元处理的不确定性和方差的数量。值得注意的是,模型的收敛取决于数据变化的精确建模。很有可能,您对神经网络的第一次尝试将导致对数据变化的过度建模或建模不足。网络的结构及其参数必须相应地调整。我们可以对该模型的两个主要特性进行微调,以获得更好的结果:
微调神经网络
我们可以控制两个主要指标:隐藏层的数量和每个网络中神经元(节点)的数量。
- 隐藏层数:在较小的数据集(比如我的)中,较高的层数会导致数据中方差的损失,从而影响模型的准确性。在我的实验中,我发现两个隐藏层最适合这个数据集。该指标随着数据集的大小和结构而变化。
- *神经元数量:*每个隐藏层有几个在初始权值部分指定的神经元。您可以选择这些数字来减少、增加或保持层的数量不变。目标是以尽可能好的方式解包数据。因此,这一步取决于每个特征所代表的数据的变化。对于我的数据集,不同特征之间存在高度相关性,每层神经元数量的减少会导致整体准确性的增加。
使用微型批次进行可扩展优化
为了使推断更快,我们将在 PyMC3 中使用迷你批处理。迷你批次减少了训练数据集的大小。在初始设置中,参数更新将要求参数查看整个训练数据集。他们创建一个小批量的训练数据集(大小为“b”),每次更新的训练都在小批量上进行。每次迭代后,批次都会更新。
经过大量的迭代,微型批次在优化 ELBO 方面变得非常高效,因为更新方程可以查看几乎每一个数据点,但不是同时查看所有数据点,这使得该过程更具可扩展性。
X_new = pm.MiniBatch(X_train, b=50)
Y_new = pm.MiniBatch(Y_train, b=50)neural_network = build_network(X_train, Y_train)with neural_network:
inference = pm.ADVI()
approx = pm.fit(n=30000, method=inference, callbacks=
[CheckParametersConvergence()])
要使用迷你批次检查结果的收敛性,我们使用相同的绘图算法:
使用小批量优化的 ELBO 变量。来源:自己的工作
使用迷你批处理,我们在 12 秒内达到收敛,但优化似乎不太顺利(初始收敛后发散更多)。我使用了来自大小为 340 的训练数据集的批量大小 50。因此,大小是一个限制,训练批次的减少导致了权重收敛的不稳定性。在结果部分,我们将比较假阴性的实际数量,以确定这种方法在乳腺癌检测中的有效性。
结果的概率
为了预测结果,我们首先生成后验样本,这些样本可用于构建预测测试结果的函数。注意,给定模型权重的估计,这些样本对应于结果的后验概率。这些样本不是参数的后验样本,因为我们没有进行 MCMC 采样。
PyMC3 没有给我们提供预测类。对于每一行,它为我们提供了结果为“1”的概率。我们必须定义一个决策边界。完成这项任务的代码如下:(这段代码的灵感来自 Thomas Wiecki 的博客,虽然我已经简化了代码,减少了一些技术术语)。
对于计算优化,我不会使用内置的 sample_posterior_predictive 函数,因为它很慢,并且不允许我们初始化预测的先验,这是我们可以手动完成的事情,以实现测试预测的加速。
**# Setting initial values**x = T.matrix('X') **# create symbolic input**
n = T.iscalar('n') **# number of samples**
x.tag.test_value = np.empty_like(X_train[:10])
n.tag.test_value = 100 **#initialising test values****# We now have to generate samples from our nodes
# that'll help us make the test predictions**_sample_proba =approx.sample_node(neural_network.out.distribution.p,
size=n,
more_replacements=
{neural_network['ann_input']: x})**# Converting the samples into a workable function**
sample_proba = theano.function([x, n], _sample_proba)**# The function for prediction of posterior probabilities:****# Predicts the outcomes (True/False) given a decision boundary**
def predict(decision_boundary):
pred = sample_proba(X_test, 500).mean(0) > decision_boundary
return pred**# Compares the outcome to the Y_test values and checks for false-negatives/ false-positives**def false_results(pred):
false_neg = 0
false_pos = 0
for i in range(len(pred)):
if pred[i] == 0 and list(Y_test)[i] == 1:
false_neg+=1
elif pred[i] == 1 and list(Y_test)[i] == 0:
false_pos+=1return false_neg, false_pos
在收集了测试预测之后,我们处理它们以收集总错误数、总假阴性和总假阳性。
boundaries = np.linspace(0,1,101)
false_negative_num = []
false_positive_num = []
total_errors = []for i in boundaries:
pred = predict(i)
n, p = false_negatives(pred)
false_negative_num.append(n*100/len(pred))
total_errors.append((n+p)*100/len(pred))
false_positive_num.append(p*100/len(pred))plt.figure(figsize=(20,10))
plt.plot(boundaries, false_negative_num, label='False Negative Rate(%)', color='red')
plt.plot(boundaries, false_positive_num, label='False Positive Rate(%)')
plt.plot(boundaries, total_errors, label='Total Error Rate(%)', color='orange')
plt.xlabel('Decision Boundary', fontsize=20)
plt.ylabel('Percentage Cases', fontsize=20)
plt.legend(fontsize=20)
plt.show()
优化决策边界
误差百分比随决策边界的变化。**来源:**自己的作品
这里的决策边界是结果被分类为恶性和非良性的结果的概率。
对于非常低的决策边界,假阳性的数量非常高(这很直观,因为我们将一切都归类为恶性)。随着决策边界的上升,我们在 0.3 的决策边界处看到最初的几个假阴性。随着我们进一步深入,上升是缓慢的,直到 0.6 的决策边界,在那里我们看到大约 2%的假阴性率,在那之后急剧上升(如预期的)。因此,理想的决策边界位于 0.3 和 0.6 之间,尽管它可能因训练数据集的不同片段而改变。从这个网络中,对于 0.4 的判定边界,我们实现了大约 97.3%的准确度。
如果我们只考虑假阴性的数量,很容易说我们应该将决策边界设为 0,但这将不再有用,因此我们将告诉每个人他们患有恶性癌症,这将使算法无用。因此,我们需要小心我们整体预测的质量以及关注的指标。
解释模型的权重
生成重量分布图的一种简单方法是构建参数的轨迹图。
trace = approx.sample(draws=5000)
pm.traceplot(trace)
参数样本的轨迹图。来源:自己的工作
请注意,这不是一个非常清晰的可视化,但是我们可以从中获得一些见解:(在下一节中,我们将更深入地研究权重,并通过每个节点对它们进行剖析)
大多数权重被建模为高斯分布,这与我们之前的假设和初始分布非常吻合。
最后一组权重(w_2_out)是一组较小的分布,因为这是映射到感知器节点(做出最终决策的 sigmoid 曲线)的七个权重(来自最终层的七个神经元)。权重有一个平衡分布,这意味着对最终概率有正面和负面影响的分量数量相等。这些是经过两个隐藏层后的转换组件,所以很难谈论它们的“实际”意义,但可以认为它们是一个中间结果。
这些分布中的大多数在 w_2_out 中似乎与 0 有统计上的显著差异,除了在中间的几个。这意味着有一些特定组件的变换在统计上没有显著的权重,因此,它们对我们最终结果的影响并不显著。(作为一项带回家的任务,读者应尽量减少最后一层的神经元数量,以观察变化。)
w _ 1 _ 2 分析:这些权重代表了从第一层到第二层的成果映射。第一层有八个神经元,第二层有七个神经元。因此,这里的神经元总数是 8*7 = 56。(权重聚类的原因)。这些权重中的大部分似乎在统计上不显著(基于分布与 0 的重叠),这表明第二层对于模型来说不像我们想象的那样信息丰富。
另一个重要的注意事项是,这里的权重分布更广。这意味着这些权重存在很大的不确定性。(这是在确定性神经网络中永远无法分辨的事情)
**w _ in _ 1 分析:**这些权重表示数据到第一层八个节点上的映射。数据中有九个维度,第一层有八个神经元。因此,这里的神经元总数是 9*8 = 72。(权重聚类的原因)。在这种情况下,还存在权重统计不显著的问题。
但是这个分析需要更多的深度。让我们按每个节点分解权重并绘制它们。我们将使用以下代码获得每个重量的平均值和标准偏差:
means = approx.bij.rmap(approx.mean.eval())
sds = approx.bij.rmap(approx.std.eval())
解释每个节点的权重
对于第一个映射(w_in_1):
从数据到第一层映射的模型权重的分割分布。**来源:**自己的作品
我们可以从上图中获得以下见解:
- 特征 2、3、4 和 5 具有大量统计上不显著的权重(平均值接近于 0),因此,它们不会持续地影响模型中的方差。(这意味着它们的影响在某些情况下是积极的,在其他情况下是消极的)
- 特征 1、6、7 和 8 的权重具有更大的可变性和更小的不重要权重。因此,它们以更大的一致性(更可能停留在正面或负面)对模型的方差做出贡献。
- 虽然大多数分布都一样宽(平均标准偏差为 1),但特征 6 和 7 的分布似乎更宽。相反,特征 4 和 5 具有最平坦的曲线,具有较小的标准偏差。
对于第二个映射(w_1_2):
从第一层到第二层映射的模型权重的分割分布。**来源:**自己的作品
我们可以从上图中获得以下见解:
- 节点 2-6 具有大量统计上不显著的权重(平均值接近于 0),因此,它们不会持续地影响模型中的方差。
- 其余节点的权重具有更大的可变性和更小的无关紧要的权重。因此,它们以更大的一致性(更可能停留在正面或负面)对模型的方差做出贡献。
- 特征 7 和 8 似乎是变化的最佳贡献者,而节点 4 似乎是最不相关的贡献者,大多数平均权重为 0。
根据此信息采取行动:
通过理解第一层对数据建模的影响较小,而第二层的影响较大,我们可以得出两个结果:
- 减少一层网络以观察对权重一致性的影响是值得的。这可能有助于将差异合并到较少数量的更重要的节点中。
- 减少节点的数量也是值得的,看看它是否有助于将差异合并到更少的节点中。
最终要点:
- 使用该模型,我们能够在测试数据集上实现大约 97%的准确率。我们还能够了解这种准确性随不同决策边界的变化,并确定最适合我们目标的决策边界范围。
- 我们能够仔细检查神经网络中的每一个权重,以及每个节点权重的不确定性。这些信息有助于优化网络并增加模型的可靠性。
未来的改进:
- 值得收集更大的数据集来提高我们模型的质量。如果首先没有足够的数据来分析,神经网络只能增加这么多的价值。
- 我们可以用多种激活函数和大小来增强神经网络,作为 A/B 测试,以找到最佳匹配。
如果你想探索这个模型,我已经在这里的笔记本中将整个工作流程构建成一个易于使用的 Python 类。
如果您有任何问题或想要联系,我的 LinkedIn 个人资料是这里。在推特上联系我这里。
概率预测
拥抱不确定性,做出更好的决策
安妮·斯普拉特在 Unsplash 上的照片
在数据科学中,处理预测错误的传统方法让我想起了冰山的比喻。我们的模型不能完美地预测未来,所以我们优化它们,尽可能地降低预测误差。更好的模型有望导致更小的误差。但是有一个下限是任何模型都无法超越的:贝叶斯误差。贝叶斯误差是潜在问题固有的随机性的表现,这种随机性通常是相当大的。
一旦我们接近了这种贝叶斯表现,我们就很想宣布胜利并结束我们的工作。通过这样做,我们处理了冰山的可见部分。但是,我们可以做得更好,通过深入研究并建立一个模型来解决问题的不确定部分,即我们看不到的冰山区域。量化不确定性将允许我们用偏差估计修正点预测(=最佳猜测),并最终导致我们可以信赖的更好、更稳健的模型。
在本文中,我将讨论概率预测,它将点预测和不确定性建模统一在一个一致的框架中。使用概率预测模型,我们可以计算最佳猜测预测,并推导出“安全缓冲区”,共同形成明智的决策和我们的想法。让我们开始吧!
俄罗斯轮盘赌和概率论
这可能是一个有点极端的机会游戏的例子,但它是解释我将在本文中使用的概率论的一些基本概念的理想场所。如果你不熟悉这个“游戏”,我建议你参考下面的维基百科文章。
给枪装上一发子弹,旋转圆筒,扣动扳机的动作就是随机实验的一个例子。随机实验的定义属性是这样一个事实,即这种实验的每次重复可能会导致不同的结果,但结果集是预先知道的。
在俄罗斯轮盘赌中,实验有两种可能的结果:枪是否开火。将一个数学对象 Y 分配给一个随机实验的结果是很方便的。y 称为结果集的一个随机元素。(有时人们称 Y 为随机变量。)这意味着 Y =‘枪发射了’,如果那是我们扣动扳机后观察到的事件,否则,Y 的值就是‘枪没有发射’。如果你是一个程序员,你可能会认为 Y 是一个没有参数的函数,如果对它求值,它会返回实验的结果。
如果我们给枪装上一发子弹,旋转枪管,试着射击,它可能不会开火。更准确地说,枪开火的概率是⅙.让我们庆祝这个罕见的时刻:我们的直觉与事物的数学定义完全吻合。事件的概率是一个介于 0 和 1 之间的数字。零表示“不会发生”。我们给一个确定的事件分配一个。严格介于 0 和 1 之间的数字表示不同程度的“可能性”。
一个概率分布,通常用 F 表示,编码了随机实验结果的概率,或者,等价地,一个随机元素 Y 的可能值的概率。所以你可能会问 F,Y =“枪开火”的概率是多少。而 f 会给你答案:F(Y =“枪火”)= ⅙.因为 F 回答这些问题太靠谱了,所以人们有时会把 F 叫做 y 的定律。
数学的任务是归纳思想并将结果应用于新问题。它通常是这样工作的:现在我们几乎知道了关于经典和古老的俄罗斯轮盘赌的一切,让我们更进一步,定义一下广义俄罗斯轮盘赌的游戏。
不如这样,我们可以用 n 发子弹,而不是只用一发子弹,然后把这 n 发子弹放进一把有 m 膛的枪里。显然,我们必须要求 n 在 0 和 m 之间,m 是正整数。(通常 m=6)。
给定一把 m=6 的枪,Y 的概率分布由我们放入枪中的子弹数 X 决定。如果 X=2(我们用两轮)呢?什么是 F(Y = “炮火”)?
如果 X=2(我们用两发子弹),那么 F(Y =“枪响”)= ⅓.
换句话说,不同的 X 值产生不同的 y 定律。
广义俄罗斯轮盘赌游戏是概率分类问题的一个例子。对于输入参数 X 的不同值,我们询问结果 Y 作为 X 的函数的概率分布。结果集是固定的,对于所有 X 值都是相同的,只是这些结果的概率不同。
通常,在一个概率分类问题中,Y 的概率分布是不给出的,我们被要求以某种方式猜测或估计它。例如,给定某人签名的照片(X),我们被要求估计该签名是真实的(Y=“真实签名”)或伪造的(Y=“伪造签名”)的概率。
对于刚刚描述的两个分类问题,产生不同结果的概率比简单地给出一个最可能的结果作为答案要有用得多,典型的分类算法就是这样做的。设想一个为检查签名而建立的业务流程。初始处理步骤可能涉及概率分类算法。如果算法几乎确定签名 X 不是伪造的,即 F(Y=“真实签名”)> 0.95,我们可以将其标记为真实的。对于任何低于 0.95 的值,我们采用进一步的、更昂贵的检查来调查签名的有效性。
俄罗斯轮盘赌的例子更加清楚地阐明了这一点。任何一个“枪会开火”/“枪不会开火”的答案都不能说明问题。我们真正想知道的是那些结果概率。
战略投标
几年前,我在易贝购买了目前的笔记本电脑。这是一台二手的联想 Thinkpad,我支付的价格远远低于同类新机型的价格。二手商用笔记本电脑的市场很大,因为许多公司定期购买新硬件并淘汰旧机器。这个市场提出了一个有趣的问题。假设我们想买一台硬件参数在一定范围内的笔记本电脑。拍卖投标的最佳策略是什么,它会导致较低的购买价格?
我们可以把这种情况描述为一个回归问题。给定一台笔记本电脑的硬件参数 X(可能结合了关于笔记本电脑状态的数据和卖家的信誉评分),我们可以说这台机器的价格 Y 是多少?y 是一个随机量:它不仅由特征值 X 驱动,还由随机和不可预测的因素驱动,如用户对特定拍卖的兴趣、可能的其他正在进行的类似模型的拍卖、机器的感知价值、拍卖结束的时间等。
要想出一个最佳的投标策略,我们需要具体说明我们购买一台笔记本电脑的迫切程度。如果我们急需一台新机器,那么我们应该愿意出高价,因此出价高于 EY 的最佳猜测价格。另一方面,如果我们可以坐在那里观察市场几个星期,等待一个“异常”价格,我们应该出价大大低于点预测价格 EY。
但出价明显低于 EY 的价格意味着什么呢?要回答这个问题,我们需要了解 Y 的预测分布和,并根据特定价格范围的概率重新表述我们的问题。例如,异常价格可能是以 1%的概率低于价格 q0 的价格。阈值价格 q0 是 Y 分布的分位数,也就是说,对于给定的概率 p0=0.01,我们预计平均只有 1/100 售出的笔记本电脑的价格低于 q。这个陈述相当于公式 F(Y < q0) = 0.01,其中 F 是 Y 的法则。按照同样的思路,我们可以以价格 q1 投标,这样,以概率 0.9,购买价格低于 q1。这种方法会很快导致问题的解决。
让我们强调,分位数 q0 和 q1 取决于 Y 的分布 F(其取决于特征向量 X),以及置信概率水平 p0 = 0.01 和 p1= 0.9。同样,我们可以把计算分位数 q0 和 q1 的问题看作是估计单侧预测区间 (-∞,q0】和(-∞,q1)的问题。
一旦我们有了对分布 f 的估计,这就很容易了。
许多批发市场使用拍卖作为价格发现机制,因此上述讨论也适用于许多公司。例如,在德国电力批发市场,买方和卖方都参与拍卖,拍卖的结果是前一天的价格计算。电力生产商指定价量对(p,v ),并通过这样做,设置他们愿意以不低于 p 的价格出售的电量 v(MW)。类似地,电力消费者指定价量对(p,v ),指示他们愿意以不高于 p 的价格购买的电量 v。使用拍卖机制找到一个用于所有结算交易的价格,可确保交易尽可能多的电量。符合该价格的所有订单(p,v)都被结算,其余订单被丢弃。
“M5 预测—不确定性”竞赛
Makridakis 竞赛是由预测研究人员 Spyros Makridakis 组织的一系列竞赛,旨在评估和推动适用于现实世界问题的预测方法的研究。最近,比赛的第五部分正在 Kaggle 平台上进行,ka ggle 平台在数据科学研究人员和爱好者中都很有名。
其中提出的问题是预测未来连续 28 天在 10 个选定的沃尔玛商店中三个产品类别(食品、家庭和爱好)的各种产品的销售数量。训练数据由几年来所有产品和商店组合的历史销售数字的时间序列组成。
今年比赛的一个有趣的方面是它有两种变体:预测预期的销售数量(M5 预测-准确性)和估计销售数量 50%,67%,95%和 99%的预测区间(M5 预测-不确定性)。
今年的问题似乎非常困难,不仅因为涉及的时间序列数量巨大(约 30,000),还因为提供的训练数据非常“嘈杂”。让我们来看看训练数据集中的一个时间序列示例:
商店层面的购买行为似乎非常不稳定,难以预测。很有可能是一些季节性因素(每周、每年、节假日)推动了销售数字的强度。在大多数情况下,销售数字的峰值无法用所提供的数据来解释。这是有道理的:我们的生活充满了我们不公开分享的细节。比方说,我们和我们所在地区的大约 20 个人最近看了一个烹饪节目,决定尝试烤香橼馅饼。一家出售制作这种馅饼所需原料的零售商对我们的计划一无所知,也没有任何有用的数据来解释柠檬需求的突然飙升。
从零售商的角度来看,更有用的是尽可能精确地知道未来销售数字的分布,而不是试图计算点预测。上面的例子说明了预期的销售数量对于处理不可预测的需求高峰毫无帮助。
作为零售商,我们希望我们的货架上有足够的商品来应对这些意想不到的需求高峰,并防止客户不得不在其他地方寻找他们需要的产品。另一方面,每家店的展示空间都是有限的,有些产品容易腐烂,不可能无限期保存。此外,储存易腐产品的成本通常不可忽略——想想超市里的巨型冰箱。
因此,最终,最大化客户满意度(和我们的收入)的问题是对我们提供的每种产品的需求的概率回归问题。我们可以为不同的需求场景分配概率(例如柠檬的需求高峰),并将这些场景与结果的成本影响联系起来。成本的例子包括:由于对产品的需求得不到满足而导致的收入减少,或者失去一个客户的成本。
这是一个典型的不确定情况下的决策问题。我们关注不同的有利或不利事件,将收入或成本因素与它们相关联,并优化反映业务成果的指标。
结论
在本文中,我们讨论了通过概率预测获得对数据科学问题更全面的理解。我们已经表明,许多现实世界问题的潜在部分,即不确定性,与可见的贝叶斯性能元素一样重要。揭示这种不确定性可以带来更稳健、更可信的模型,并为开发能够应对各种未来情景的战略决策系统开辟了一条至关重要的道路。
非常感谢 Sarah Khatry 阅读了这篇博文的草稿,并提供了无数的改进意见和更正。
Python 中时间序列分析和预测的概率规划和贝叶斯推理
Python 中时间序列数据分析和预测的贝叶斯方法
作者照片
如[1][2]所述,时间序列数据包括来自金融、医学、科学研究(如全球变暖、语音分析、地震)等不同领域的多种真实实验数据。时间序列预测在各个领域都有很多实际应用,例如商业预测(如销售、股票)、天气、死亡等[2]。统计建模和推理(如 ARIMA 模型)[1][2]是时间序列分析和预测的流行方法之一。
有两种统计推断方法:
贝叶斯推理的哲学是将概率视为事件可信度的度量[3][4][5],并使用贝叶斯定理随着更多证据或信息变得可用来更新概率,而频率主义推理的哲学将概率视为事件的长期频率[3]。
一般来说,只有在大量数据样本可用的情况下,我们才能使用 Frequentist 推断。相比之下,贝叶斯推理可以应用于大数据集和小数据集。
在本文中,我使用 Kaggle [6]的一个小的(只有 36 个数据样本)洗发水销售时间序列数据集来演示如何使用概率编程来实现贝叶斯分析和推理,用于时间序列分析和预测。
文章的其余部分安排如下:
- 贝叶斯定理
- MCMC 基础知识(马尔可夫链蒙特卡罗)
- 概率规划
- 时间序列模型和预测[3]
- 摘要
1.贝叶斯定理
设 H 为事件将发生的假设, D 为新观察到的数据(即证据),而 p 为概率,贝叶斯定理可描述如下[5]:
p(H | D) = p(H) x p(D | H) / p(D)
- p(H):在我们看到任何数据之前,假设的先验概率
- p(H | D):我们观察新数据后假设的后验概率
- p(D | H):似然,假设下数据的概率
- p(D):任何假设下数据的概率
2.MCMC 基础
MCMC 由一类算法组成,用于从概率分布中取样。广泛使用的算法之一是Metropolis–Hastings 算法。基本思想是随机生成大量代表性样本,以逼近多维连续参数空间上的连续分布[4]。
Metropolis 算法的高级描述可以表示如下[3]:
- 步骤 1:从 n 参数空间中的当前位置(即,n 参数值的向量)开始
- 步骤 2:建议移动到新位置(n 参数值的新向量)
- 步骤 3:基于先前位置的先验概率、数据以及根据贝叶斯定理[3]从数据及其先验分布计算的后验概率,接受或拒绝提议的移动。
- 第四步:如果提议被接受,那就去新的职位。否则,不要动。
- 步骤 5:如果尚未达到预先指定的步骤数,请返回步骤 1 重复该过程。否则,返回所有接受的位置。
MCMC 的基础是贝叶斯定理。从假设和数据的给定先验分布开始,上述 Metropolis 过程的每次迭代都会积累新数据,并使用它来更新假设,以随机行走的方式选择下一步[4]。接受的步骤是假设的后验分布的样本。
3.概率规划
有多个 Python 库可用于编程贝叶斯分析和推理[3][5][7][8]。这种类型的编程称为概率编程[3][8],相应的库称为概率编程语言。PyMC [3][7]和张量流概率[8]就是两个例子。
在这篇文章中,我使用 PyMC [3][7]作为概率编程语言来分析和预测洗发水的销售[6]作为演示目的。
4.时间序列模型与预测
本节描述了如何使用 PyMC [7]对时间序列预测的贝叶斯分析和推理进行编程。
4.1 数据加载
一旦 Kaggle [6]三年洗发水销售的数据集下载到本地机器上,数据集 csv 文件就可以加载到 Pandas 数据帧中,如下所示:
df = pd.read_csv('./data/sales-of-shampoo-over-a-three-ye.csv')
df.head(12)
数据框架中的销售列可以提取为时间序列数据集:
sales = df['Sales of shampoo over a three year period']
sales.plot(figsize=(16,5))
下面这个图是三年(36 个月)洗发水的销量:
图 1: 三年(36 个月)洗发水销量。
4.2 建模
贝叶斯建模的良好开端[3]是考虑一个给定的数据集可能是如何生成的。以图 1 中洗发水时间序列数据的销售为例,我们可以从思考开始:
- 由于数据集从左下角到右上角大致形成一条直线,因此数据集可能是由销售中带有随机误差的时间线性函数生成的。
- 随机误差可能遵循均值为零且标准偏差未知的正态分布 std 。
销售 = 贝塔 x t + 阿尔法 + 误差
为了估计时间的线性函数可能是什么,我们可以将线性回归机器学习模型拟合到给定的数据集中,以找到斜率和截距:
import numpy as np
from sklearn.linear_model import LinearRegressionX1 = sales.index.values
Y1 = sales.values
X = X1.reshape(-1, 1)
Y = Y1.reshape(-1, 1)
reg = LinearRegression().fit(X, Y)reg.coef_, reg.intercept_
其中 reg.coef_ = 12.08 为斜率, reg.intercept_ = 101.22 为截距。
Y_reg = 12.08 * X1 + 101.22def plot_df(x, y, y_reg, title="", xlabel='Date', ylabel='Value', dpi=100):
plt.figure(figsize=(16,5), dpi=dpi)
plt.plot(x, y, color='tab:blue')
plt.plot(x, y_reg, color='tab:red')
plt.gca().set(title=title, xlabel=xlabel, ylabel=ylabel)
plt.show()plot_df(x=X1, y=Y1, y_reg=Y_reg, title='Sales')
上面的代码在蓝色销售曲线上绘制了红色回归线:
图 2: 三年(36 个月)洗发水销量,回归线为红色。
回归线的斜率和截距只是基于有限数据的估计。考虑到不确定性,我们可以将它们表示为正态随机变量,将确定的斜率和截距表示为平均值。这在 PyMC [7]中实现如下:
beta = pm.Normal("beta", mu=12, sd=10)
alpha = pm.Normal("alpha", mu=101, sd=10)
同样,为了处理不确定性,我们可以使用 PyMC 将误差的标准偏差表示为在[0,100]范围内的均匀随机变量:
std = pm.Uniform("std", 0, 100)
有了随机变量 std 、 beta 、 alpha ,具有不确定性的回归线可以用 PyMC [7]表示:
mean = pm.Deterministic("mean", alpha + beta * X)
利用具有不确定性的回归线,洗发水销售时间序列数据的先验分布可以在 PyMC 中编程:
obs = pm.Normal("obs", mu=mean, sd=std, observed=Y)
使用上述先验分布作为参数(即α、β、 std )空间中的起始位置,我们可以使用 PyMC 中的Metropolis–Hastings 算法执行 MCMC:
import pymc3 as pmwith pm.Model() as model:
std = pm.Uniform("std", 0, 100)
beta = pm.Normal("beta", mu=12, sd=10)
alpha = pm.Normal("alpha", mu=101, sd=10)
mean = pm.Deterministic("mean", alpha + beta * X)
obs = pm.Normal("obs", mu=mean, sd=std, observed=Y)
trace = pm.sample(100000, step=pm.Metropolis())
burned_trace = trace[20000:]
总共有 100,000 个被接受的步骤,称为跟踪。我们忽略前 20,000 个可接受的步骤,以避免收敛前的磨合阶段[3][4]。换句话说,我们只使用磨合期后的公认步骤进行贝叶斯推断。
4.3 后验分析
以下代码描绘了老化期后 std 、 alpha 和 beta 的轨迹:
pm.plots.traceplot(burned_trace, varnames=["std", "beta", "alpha"])
**图 3:**STD、alpha、beta 的痕迹。
std 、 alpha 和 beta 的后验分布可以绘制如下:
pm.plot_posterior(burned_trace, varnames=["std", "beta", "alpha"])
**图 4:**STD、alpha、beta 的后验分布。
std 、 alpha 和 beta 的个别痕迹可以提取进行分析:
std_trace = burned_trace['std']
beta_trace = burned_trace['beta']
alpha_trace = burned_trace['alpha']
我们可以用任何指定的步数(如 1000)放大 std 的轨迹细节:
pd.Series(std_trace[:1000]).plot()
图 5: 放大 std 的痕迹。
同样,我们可以分别放大 alpha 和 beta 的轨迹细节:
pd.Series(beta_trace[:1000]).plot()
图 6: 放大贝塔的踪迹。
pd.Series(alpha_trace[:1000]).plot()
图 7: 放大 alpha 的痕迹。
图 5、6 和 7 显示 std 、 alpha 和 beta 的后验分布具有良好的混合频率,因此自相关性较低,这表明 MCMC 收敛【3】。
4.4 预测
可以计算出 std 、 alpha 和 beta 的后验分布的平均值:
std_mean = std_trace.mean()
beta_mean = beta_trace.mean()
alpha_mean = alpha_trace.mean()
- 标准平均值 = 79.41
- beta_mean = 12.09
- alpha_mean = 101.03
洗发水销售的预测可以建模如下:
Sale(t)=beta _ meanxt+alpha _ mean+误差
其中误差服从正态分布,均值为 0,标准差为 std_mean 。
使用上面的模型,给定任意数量的时间步长(例如 72),我们可以生成销售的时间序列:
length = 72
x1 = np.arange(length)
mean_trace = alpha_mean + beta_mean * x1
normal_dist = pm.Normal.dist(0, sd=std_mean)
errors = normal_dist.random(size=length)
Y_gen = mean_trace + errors
Y_reg1 = mean_trace
给定 36 个月的数据,下面的代码绘制了未来 36 个月(从第 37 个月到第 72 个月)的销售预测。
plot_df(x=x1, y=Y_gen, y_reg=Y_reg1, title='Sales')
图 8: 预测未来 36 个月(从第 37 个月到第 72 个月)的销售额。
5.摘要
在本文中,我使用来自 Kaggle [6]的小型洗发水【6】时间序列数据集来展示如何使用 PyMC [3][7]作为 Python 概率编程语言来实现时间序列预测的贝叶斯分析和推理。
概率编程语言的另一种选择是张量流概率【8】。我在本文中选择 PyMC 有两个原因。一个是 PyMC 比张量流概率更容易理解。另一个原因是 Tensorflow probability 正在从 Tensorflow 1.x 迁移到 Tensorflow 2.x 的过程中,缺少 Tensorflow 2.x 的 Tensorflow probability 文档。
参考
- Python 中常用的时间序列数据分析方法和预测模型
- R.H. Shumway 和 D.S. Stoffer,时间序列分析及其应用,第 4 版,施普林格,2017 年
- C.戴维森-皮隆,《黑客的贝叶斯方法,概率编程和贝叶斯推理》,艾迪森-韦斯利,2016 年
- J.K. Kruschke,《做贝叶斯数据分析》,与 R、JAGS 和斯坦合著,学术出版社,2015 年
- A.B .唐尼,思考贝氏,奥赖利,2013
- 三年内洗发水的销售额
- PyMC3
- 张量流概率
- Github中的 Jupyter 笔记本
用 Pyro 和厨房秤进行概率编程
最近感兴趣的技术之一是概率规划的使用。如果你以前从未听说过概率编程,你可能会认为它只是用概率编程。这是正确的,但只是故事的一部分。
在其核心,概率规划是关于寻找潜在的分布,影响感兴趣的过程。你定义一个过程和它是如何工作的,然后让你选择的概率编程语言(PPL)来推断影响你的过程的因素的可能值,以及它们的可能性有多大。
最好用一个例子来解释这一点,对于这个例子,我将使用 Pyro 作为 PPL 的选择,以及一个简单的案例研究,主要灵感来自官方的 Pyro 示例。
构建我们的过程——神奇的厨房秤
想象你有一个厨房秤,你把一个物体放在上面,秤告诉你它的重量。但是想象的尺度相当古老,而且不是很准确。每次你把同样的物体放在上面,它会给你一个稍微不同的测量值。然而,您观察到,这种秤以某种神奇的方式产生误差,在物品的真实重量周围形成正态分布,标准偏差为 0.1 千克
让我们来描述这个过程(我们将使用 PyTorch,Pyro 使用它作为底层张量计算引擎)。
首先,我们将导入我们需要的库
让我们来定义我们的厨房秤,或者更具体地说,它用来给我们观察的过程
现在让我们问自己一个简单的问题;
“如果我们将一件 0.5 千克的物品放在秤上,我们会得到哪些可能的值?”
tensor(0.6541)
tensor(0.4707)
tensor(0.2821)
我们得到了 3 个值的集合。每次我们要求我们的秤给出答案,我们都会得到一个稍微不同的值。有时值会非常接近 0.5(大多数情况下会出现这种情况),有时会非常远。虽然这很容易实现,但就编程而言并不新鲜。
我们来试试稍微难一点的问题;
“如果我将一件重 0.5 千克的物品放在磅秤上,观察到高于 0.63 千克的值的概率是多少?”
我们也可以通过编程来回答这个问题。我们将只生成许多值,统计我们生成的所有值,统计所有大于 0.63 的值,并找出它们的比率:
rough estimate: 0.097
reasonable estimate: 0.101
good estimate: 0.09691
true estimate: 0.0968004845856103
如果我们运行这个过程足够多次,我们将得到一个对所有意图和目的都好的估计。这需要更多的工作和时间,但是总的来说这个工作流程也不是太难。
让我们试试一个更难的问题:
“我观察到一个 0.63 千克的值,该物品最可能的真实重量是多少?”
这可能会让你大吃一惊,但稍加思考后,你可能会想起你神奇的不准确但性能良好的秤报告了该物品真实重量的正态分布,因此在没有进一步信息的情况下,最有可能的重量实际上是 0.63 千克
然而,这在很大程度上是容易的,因为我们知道围绕秤的真实重量的分布是正态的。如果不正常呢?如果它甚至不是预先内置到 Python 中的东西呢?
现在让我们尝试一个难题,它将激励我们使用概率规划:
“让我们想象一下,从我们的秤中得到以下一组观察值:0.74 千克、0.98 千克、0.66 千克、0.75 千克、0.84 千克和 0.74 千克,物体最可能的真实重量是多少?”
我用来生成这些值的真实重量是 0.8 千克,但是让我们看看如何才能发现它
在 Pyro 中构建我们的流程
上一节中的问题正是概率规划要回答的问题。一般的形式是“给定一些观察,以及对过程的良好理解,我能推断出一些关于我的过程中隐藏的值或初始条件吗?”
现在我们想知道,我们的产品最可能的重量是多少。我们现在将使用 Pyro 来回答这个问题。
The mean of the observations is: 0.7850000262260437.
首先,让我们再次定义我们的过程,但是有一些变化。我们还会将函数从process
重命名为model
,因为这通常是 Pyro 代码的编写方式:
这可能看起来很多,所以让我们解开这个函数是如何工作的。
给定我们的观察值,我们试图找到一个可能的权重值的分布。
- 我们首先定义这些值的先验分布,这是我们对概率分布的最佳猜测,在(1)。
- 然后,我们从(2)的分布中取样。然而,现在这是一个命名的发行版(我们将其命名为
"weight1"
)。这是我们告诉 Pyro 优化权重来源分布的方式。在幕后,Pyro 将修改这个分布,使之更符合我们的观察。 - 在(3)中,我们定义了秤的工作方式。回想一下,为了进行测量,秤返回以重量为中心的正态分布值,标准偏差为 0.1。
- 最后,在(4)中,我们从我们在(3)中定义的分布中取样。请注意,这些也是命名样本,但它们取决于观察结果。这就是我们告诉 Pyro 我们的
"weight1"
值与观察值的关系。
使用抽样技术估算我们的体重
现在,我们将使用我们的模型来找到一个合适的估计重量的项目,给我们的测量。我们将使用一个称为马尔可夫链蒙特卡罗(MCMC)的算法家族,以及一个称为哈密顿蒙特卡罗(HMC)的特定实例。关于 MCMC 和原始 Metropolis 采样算法的深入解释(HMC 就是建立在这个基础上的),我鼓励你去看看扎克·安临来的演讲
本质上,该算法将基于我们定义的分布影响的观察值(我们命名为"obs_{i}"
的变量),构建我们命名的分布“weight1”
的概率分布。
Sample: 100%|██████████| 20100/20100 [02:03, 163.05it/s, step size=1.55e+00, acc. prob=0.902]
让我们看看这里发生了什么:
- 在(1)处,我们从我们的 Pyro 存储器中清除所有命名的样本。Pyro 使用一个特殊的、内置的、类似字典的对象来跟踪我们请求的项目的估计值。清楚这一点很重要,这样如果我们多次运行这段代码,前面的运行就不会扭曲我们的结果。
- 在(2)和(3)中,我们定义了一种 MCMC 算法,该算法使用 HMC 实现来估计命名变量
"weight1"
的分布。MCMC 算法运行一定次数的迭代,在本例中为 20,100 次迭代。然而,它得出的前几个估计值对初始随机条件非常敏感,所以我们倾向于丢弃这些估计值(我们将丢弃前 100 个)。所有剩余的 20,000 个样本将用于构建我们对"weight1"
的后验估计 - 最后在(4)中,我们运行我们的 MCMC 算法。注意,我们必须将我们的观察结果发送到
model
函数中(因为我们之前定义它接受一系列观察结果)。这是我们将所有变量发送给model
函数的地方。
现在,让我们画出估算"weight1"
时得到的所有样本,将这些样本转换成一个 NumPy 数组(它们作为 PyTorch 张量返回),并绘制成直方图。
array([0.8106951 , 0.77260906, 0.79576313, ..., 0.86141765, 0.7857265 , 0.7469458 ], dtype=float32)
具有正态先验的 HMC 算法生成的权重值的样本分布
我们还可以绘制摘要,并查看该分布的平均值,以找到最可能的值以及 90%的可信区间。
mean std median 5.0% 95.0% n_eff r_hat
weight1 0.78 0.04 0.79 0.72 0.85 29855.87 1.00Number of divergences: 0
因此,我们看到平均值约为 0.78 千克,我们 90%确信该物品的重量值在 0.72 千克到 0.85 千克之间(这也是我们判断是否对这 90%范围满意的空间)。
你现在可能会说 “嗯,你有一个很好的先验,你的平均值非常接近 0.8 公斤的真实值。如果你使用一个信息量较少的先验呢?”
让我们也来探索一下这个场景。这一次我们将使用 0.0(重量不能为负)和 2kg(看起来是一个很好的上限)之间的均匀分布。
Sample: 100%|██████████| 20100/20100 [03:20, 100.21it/s, step size=8.57e-01, acc. prob=0.978]
mean std median 5.0% 95.0% n_eff r_hat
weight2 0.78 0.04 0.78 0.72 0.85 1059.35 1.00
Number of divergences: 0
有这样一个信息不丰富的先验并没有造成多大的不同。该算法 90%确信体重在 0.72 千克和 0.85 千克之间,并且这些值的平均值仍然集中在 0.78 千克(非常接近使用的 0.8 千克)。
我们可以再次获取这个新近似值的样本,再次将它们转换为 NumPy 数组,并将结果绘制成分布图。你会看到分布重叠得非常厉害,即使使用了两个非常不同的先验。
由具有正态先验的 HMC 算法以及具有均匀先验的 HMC 算法生成的权重值的样本分布
使用随机变分推断来近似我们的重量
如果您运行上面的代码,您会注意到使用 MCMC 方法绘制所有的样本需要相当多的时间。Pyro 提供了一种评估隐藏参数的替代方法,这种方法更快,并且可以为一些问题提供同样好的结果:随机变分推断(SVI)。
SVI 方法把这个推理问题当作一个最优化问题。在 SVI 方法中,我们选择由一些参数定义的另一种分布(例如,正态分布由其均值和标准差定义),并优化这些参数,直到我们选择的分布提供“足够接近”我们观察结果的结果。
这种评估后验概率的替代方法需要一个额外的函数,它被称为引导函数。这个函数定义了我们的参数,以及我们建议的与观察值相匹配的分布。
让我们再次定义我们的模型:
现在,让我们定义我们的向导函数:
- 首先,向导和模型函数必须接受相同的输入,即使向导根本不使用它们中的任何一个。
- 在(2)和(3)中,我们说取一个正态分布,并调整它的参数(平均值和标准偏差),以便它更有可能产生观察到的观察值。在(2)中,我们必须提供这些参数的初始猜测(注意
pyro.param
语句,它与pyro.sample
不同,因为它注册的是参数,而不是分布)。 - 在(4)中,我们从(3)中定义的分布中提取一个权重。我们实际上不需要将该值存储到 python 变量中,我们只需要与模型函数中的名称完全相同的
pyro.sample
语句。这只适用于未观察到的样本(没有obs=
附加参数的样本)
现在这变成了一个优化问题,我们只需要优化"mu"
和"sigma"
,使它们定义的正态分布更接近我们观察到的值。
iter: 9900, loss: -2.031
在执行优化之后,我们可以向 Pyro 请求找到的"mu"
和"sigma"
的值
"mu" is 0.7845805883407593
"sigma" is 0.040342673659324646
我们还可以要求与之前相同的关于“weight3”
的统计数据,例如 90%的可信区间,但是我们必须为此做更多的工作。
我们需要使用我们发现的值来生成新的样本(MCMC 通过生成样本来工作,因此在算法运行之后我们不需要额外的步骤):
weight_mean weight_5% weight_95%
0 0.784121 0.717712 0.850685
Run time for SVI algorithm and result extraction: 19.51 seconds
我们可以看到,我们得到的结果与使用 MCMC 模型时观察到的结果非常相似,但只是运行时间的一小部分。
SVI 方法旨在提高执行速度。但是,由于它们需要预定义的配送作为指导,因此对于某些配送(例如多式联运)来说,可能很难选择这些配送。对于可以由预定义分布近似的分布,它们是理想的,因为它们提供了实质性的性能提升。
我们还可以将通过 SVI 算法采样获得的结果分布与之前的样本进行比较:
由两种 HMC 算法生成的权重值的样本分布,以及由 SVI 算法生成的样本分布,
使用自动导向装置
我想在这里介绍的最后一个功能是在 Pyro 中使用自动引导。当构建你自己的指南是一项费力的任务时,Pyro 提供了使用预建自动指南功能的能力。
Optimizing...
iter: 9900, loss: -1.88
Parameters:
"mu" is [0.77290195]
"sigma" is [0.04055462]
Predicting...
weight_mean weight_5% weight_95%
0 0.773199 0.706324 0.8403
Run time for SVI algorithm and result extraction: 23.17 seconds
我们还可以绘制这些结果,并比较两种 SVI 方法的分布:
具有自定义向导和自动分类的 SVI 算法生成的权重值的样本分布
这篇文章展示了 Pyro 在推断模型中隐藏的参数值时提供的基本功能。
我鼓励大家探讨扎克·安临来 的 演讲,讨论概率编程应用(示例使用 PyMC3 进行探讨,但现在应该更容易翻译成 Pyro),以及 Chi Nhan Nguyen 的演讲,展示如何使用 Pyro 为过度自信的神经网络引入不确定性(演讲使用 Pyro 的旧版本)。
在以后的文章中,我将探索如何将 Pyro 用于更真实的应用程序,但是当开始使用任何新的库时,一个容易理解的简单示例对于解释库的工作方式非常有用。
这篇文章的笔记本版本,请访问 这里
知识图上的概率推理
知识图表和推理
希望,感谢*‘神话般的五人组’,*会有事情发生!
不加推理地使用知识图表就像吃了一块诱人的蛋糕,然后把它留在那里欣赏:美学上很吸引人,但浪费了美味的配料,从长远来看,毫无意义!
推理使知识图的“知识部分”成为可能,如果没有它,可以更像是一个数据库而不是知识模型。
简而言之,区别就在这里。
虽然关系数据库的中心点是用关系对现实建模、存储到表中以及用 SQL 查询感兴趣的领域,但是知识图更多的是关于类似图形的数据(而不仅仅是图形数据库中的数据)。
有了知识图,你就可以为你拥有图状数据的感兴趣的现实建模(所谓的地面扩展组件)。你可以抽象地描述这样的现实是如何运作的,即:底层业务的规则是什么,人类知道的东西是什么,但程序和数据库都不知道。最后,通过推理过程,你可以为你的图生成新的节点和边形式的新知识,即派生的外延组件,又名推理组件【1】。
关于知识图表推理的简单例子,你可以在 Medium 上查看。
到目前为止,一切顺利。
但是现实是不确定的,数据是不确定的,领域知识是不确定的,甚至我们的人脑推理过程也是被设计成不确定的。所以推理需要包含和处理各种不确定性。
因此,如果你想在知识图上进行尖端的推理,如果你想对现实进行更合理和可靠的描述,而不是一种机器人/木偶版的人类推理,你需要考虑不确定性,并将其纳入你的推理。
如何在 KGs 上进行概率推理
照片由 Calum Lewis 在 Unsplash 上拍摄
在使用 KGs 的概率推理中,我们当然需要执行“概率部分”。然而,坏消息是,如果我们想明智地实现它,我们也需要同时满足标准对 KGs [2]推理的要求。
例如,我们不希望能够处理空值,但不能遍历图形,对吗?因此,我们需要的四种关键成分作为基本配方:
- 全递归
如果你想探索图形结构,至少你会期望遍历这些图形!当然不仅仅是遍历:您希望用多种算法探索图形数据,其中路径的范围和形式事先并不知道。
对于图形数据库,您可能习惯于像 Neo4J 中那样对语言进行模式匹配。这里的世界是不同的:知识图通常不做模式匹配,而是依赖于一种更强大的工具:递归。
所以,我很抱歉地告诉你,因为你想在 kg 上推理,你需要递归。
而且它必须是完全的,也就是说,我们不能摆脱许多现有形式的部分递归,因为我们想要一个我们可以编写的图形算法的完整选择。
让我们以一个基本的图问题为例,如ST-连通性(在一个有向图中询问 t 是否从 s 可达的决策问题)。它可以通过左递归来表达。但是有许多基本但重要的问题是不可能陈述的,即使用线性递归也不行。这就是为什么完全递归是必须的。
我认为仅仅了解递归是远远不够的,所以如果你同意我的观点,也读读这个或者这个,或者回到计算机科学的第一年,重读一本像这个一样精彩的书!
2。归纳(不,这不是递归了…也读成分 2!)
一种语言,或者如果你想更非正式和轻松,一个旨在推理(在知识图上)并准备进行概率推理的系统必须能够表达非基础归纳定义【3,4】。
归纳定义是就其本身给出的定义,它必须是合理的。必须有一个或多个非递归基础案例+一个或多个递归案例,最终导致回到基础案例。
非常著名的归纳定义的例子是斐波那契数列和阶乘。归纳定义最简单的例子可能是传递闭包。如果一个系统连一个二元关系的非地(仅用基格)传递闭包都做不到。这是推理的本质,因为:
如果一个系统甚至不能计算出传递闭包,你可以肯定它不会帮助你进行推理!
3。语义
推理过程必须追溯到特定的语义,即赋予内涵成分和查询答案意义的成分。
对于语义,您有许多不同的选择,在这种情况下,语言语义:稳定模型语义、有根据的语义、最少模型语义以及它们的所有变体,等等。就性能而言,它们提供了或多或少有效的推理过程。
在这种情况下,合理的选择是使用有理有据的语义。
让我们来回答一个连接查询。使用稳定模型语义,解决方案的构造需要考虑满足您的内涵组件和查询的所有可能解释中出现的事实。相反,在有充分根据的语义学中,对查询的正确回答包含了任何真实解释的所有事实。就性能而言,节省是不言而喻的。
这个和其他理论基础[5]是这样的,你可以使用良好的语义开发更快的推理机,因此它是一个更好的选择!
4。本体推理
我们正在谈论推理 ok,但是它有点模糊,哪种推理?我希望有一个强大的推理版本,当然,它允许我查询我的知识图表,以获得意想不到的、新的和重要的见解!
所以,至少我们希望有本体推理,用哲学术语来说,可以被看作是“对现存事物”进行推理的能力。而在数学术语中则意味着特定运算符的存在,如包含、泛量化和存在量化等。
在计算机科学中,本体推理通常对应于系统在推理规则下支持 SPARQL (查询语言)的能力,这种推理规则被称为‘蕴涵机制’, 的OWL 2 QL 概要**** (语义 web 社区中一种众所周知的语言中的概念和推理规则的复合体)。
这个“轮廓”是一种工具箱,包含了推理的所有要素:只要想想它包括对称的、自反的和非自反的属性,不相交的属性,或者简单地定义类和子类。
这种模式下的本体推理也提供了出色的性能,在表达能力和计算复杂性之间有一个很好的平衡;例如,当假设查询是固定的时,在 AC0 复杂性类中。
准备工作:
由aaron Blanco Tejedor在 Unsplash 上拍摄的照片
我们刚刚看到的四种成分是基础配方:推理。但是对于高级配方,概率推理,你将需要所有’*神话般的五’*的共同努力。你至少需要另一个关键因素,第五个因素:现在,你必须决定你希望如何管理不确定性。
科学家们想出了最不同的方法来处理涉及不完善或未知信息的各种情况:概率论、模糊逻辑、主观逻辑、证据理论等。
如果把它保持在地面上,参考不确定性的概率论,我们可以用什么样的模型/系统对 KGs 进行概率推理?
很多人都在研究概率推理。涉及的人如此之多,以至于至少存在 **三个主要的相关研究领域:**概率逻辑编程、概率编程语言、统计关系学习。
为了这个目标,我花了一段时间去钻研不同的科学分支。毫无疑问,很多时间去真正理解在知识图上概率推理的最新技术水平。现在我可以向你报告我的发现了。
概率逻辑编程是一组非常好的语言,允许你定义非常紧凑和优雅简单的逻辑程序。此外,他们使用 Sato 语义,这是一种定义语义的简单而紧凑的方法。
概率编程语言是优雅的,因为它们让你可以自然地处理所有的统计分布,这对统计学家来说是如此的有吸引力和舒适。
统计关系学习允许我们使用像马尔可夫逻辑网络这样的概率图形模型,因此人们在机器学习环境中拥有的所有能力都可以立即投入使用(例如 PGM 中的概率推理)。您可以创建非常接近您感兴趣的现实的 PGM,并以最小的努力对实体和关系进行建模。
所有愉快和积极的点,没有缺点!那么,我应该追求什么呢?
所有这些技术都只关注配方的第五个成分:如何管理不确定性。但是他们几乎完全避开其他四个。
换句话说,它们提供了一种处理不确定性的特定方法,但没有知识图上推理的所有其他基本特征。
它们不适用于知识图上的概率推理。
这就好像他们研究并开发了最好的咖喱粉,有时忘记了蔬菜、鸡肉甚至火。那你怎么做咖喱呢?
注意到这一点后,我试图为绘制概率知识图做出自己的贡献,付出额外的努力,研究什么是必需的,并去杂货店购买所有必需的原料。这是我在知识图上进行概率推理的秘方。
我渴望听你的!
结论
没有推理,知识图是半生不熟的(在这里了解更多信息),处理不确定性对于原则性推理是至关重要的。然而,要做到这一点,有五个基本原则。分别是全递归、归纳、语义、本体推理、概率论。更多的现有方法忽略了这五个令人难以置信的因素中的大部分,只关注其中的一个“成分”。然而有人尝试过:这里用了所有的’神话般的五’ 。
如果您想通过金融情报行业的真实案例了解更多关于知识图上的概率推理:
如何使用人工智能帮助打击有组织犯罪。
towardsdatascience.com](/reasoning-on-financial-intelligence-3e40db6c2b5)
关注我的 Medium 了解更多信息。
让我们也在 Linkedin 上保持联系吧!
参考
[1] L. Bellomarini 等人,知识图和企业人工智能:使能技术的承诺 (2019),ICDE
[2] L .贝洛玛里尼等,知识图中不确定性下的推理 (2020),RuleML+RR 2020
[3] D. Fierens 等,概率逻辑程序设计中的推理与学习加权布尔公式 (2015),《逻辑程序设计理论与实践》
[4] J. Lee 和 Y. Wang,稳定模型语义下的加权规则 (2016),KR。第 145-154 页。AAAI 出版社
[5] M. Denecker 等著,逻辑程序再探:作为归纳定义的逻辑程序 (2001),美国计算机学会译。计算机。日志。
概率导论
统计 101
通过圆周率实验定义
概率是一个多方面的概念;在一个小实验的帮助下,我们将尝试对他的方面给出一个完整的解释。
实验
想象一个 1x1 的盒子,里面有四分之一的圆(图 1)。半径是 1,所以面积当然是π/4。我们将尝试通过概率的不同定义来估计这一领域,提供概念的可视化和理论结论的经验证据。
图 1 —实验(作者)
经典解释
概率的一个定义,被称为经典,是从概率游戏(即轮盘赌、掷骰子、掷硬币等)的理论发展而来的。).该理论指出,在没有任何随机事件信息的情况下,或者当我们知道所有机会都是均等分布的(就像我们掷骰子一样)时,将所有事件简化为所有可能积极结果的基数是正确的,概率是比率:
一个典型的例子:我们掷一个公平的骰子,我们想知道这个数字是质数的可能性。我们知道 2、3、5 是质数,所以我们总共有 6 次机会中有 3 次“赢”(有利事件发生)。所以:
在实验中,我们建立了一个点的网格,在 0 和 1 之间均匀分布在 x 和 y 中。这样,我们可以模拟任何事件的等效发生。什么时候一个事件是有利的?我们要估计曲线下的面积,所以任何对 E 中的 (x,y) ,这样:
是有利的事件。这个想法就是简单地计算点在 E 和点在ω。它们的比率是概率(根据定义)和曲线下面积的估计值。
在 Python 中,我们可以定义一个简单的函数:
def classic_ex(n):
xl = []
yl = []
color = []
e = 0
for i in range(n+1):
for j in range(n+1):
x = 1/n * i;
y = 1/n * j;
if ((x**2 + y**2) <= 1):
e = e + 1;
color.append('blue')
else:
color.append('lightgray')
xl.append(x)
yl.append(y)
return e/(n**2), xl, yl, color;
用 matplotlib plt 函数散点调用函数 end graph it:
e1, x1, y1, c1 = classic_ex(n);
plt.scatter(x1,y1,color=c1)
plt.set_title('p=' + str(e1))
通过用 n = (10,33,100,333)重复这个过程,我们得到了下图中的结果(图 2):
图 2-该区域的经典概率估计(作者)
可以看到,当 n 越来越大时,E(曲线下面积)的概率越来越接近 pi/4 的预期结果,这就导致了冯米塞斯的假设:
如果我们尝试的次数足够多,实验比会收敛到概率。
概率的经典定义在以下条件下成立:
- 这些事件是互斥的
- 事件的并集是可能事件ω的总和
- 每一个结果(事件)都被认为是同样可能的
条件 3 在某种程度上是“循环的”,因为可能性既是一种假设,也是概率度量的对象。在我们的实验中,我们强迫事件平均分布(均匀分布);在没有任何其他数据信息的情况下,在实际情况下,这并不总是一个有效的假设;我们需要概率的另一个定义。
频繁主义
在频率主义下,我们对事件的等可能性没有任何假设。相反,我们认为概率是一个随机事件的总体趋势,它会发生很多次。我们测量有利事件(计数发生)的频率,没有任何概率分布的假设。
在实验中,我们假设点是均匀分布的,但不是事件的均匀分布。这是因为我们想要模拟随机选择点的情况,这些点有助于概率的估计(曲线下的面积)。随着 N 变大,我们陷入了冯·米塞斯的假设:
在 Python 中:
def freq_ex(n):
xl = []
yl = []
color = []
e = 0
for i in range(n):
x = np.random.uniform(0,1)
y = np.random.uniform(0,1)
if ((x**2 + y**2) <= 1):
e = e + 1;
color.append('blue')
else:
color.append('lightgray')
xl.append(x)
yl.append(y)
return e/n, xl, yl, color;
再次为了形象化:
e1, x1, y1, c1 = classic_ex(n);
plt.scatter(x1,y1,color=c1)
plt.set_title('p=' + str(e1))
运行 n = (100,1000,10000,100000)的实验,最后可视化我们得到的结果(图 3):
图 3——该地区的常客概率估计(按作者)
同样,估计的概率趋向于π/4 的预期结果。
为了实证检验这种集中趋势,让我们尝试另一个实验:重复频率测试 a 1000 次,并查看估计区域的分布。
在 Python 中:
ex = []
for i in range(1000):
e1, x1, y1, c1 = freq_ex(1000);
ex.append(e1)fig = plt.figure(figsize=(15,15))
plt.hist(ex, bins=20)
plt.vlines(np.pi/4,0,150)
我们得到(图 4):
图 4——区域估计的主要趋势(按作者)
我们看到这个奇怪的钟形曲线,它定义了概率的预期估计的分布。这条曲线决定了一个高斯或正态分布,但这也是后话。现在,我们看到我们概率的中心趋势对应于π/4 曲线下的期望面积。
Kolmogorov 和公理化定义
俄罗斯数学家安德烈·尼古拉耶维奇·科尔莫戈罗夫(Andrej Nikolaevič Kolmogorov)定义了现在所谓的概率公理化解释的基础。
(来自维基百科):
设(ω, F , P )为测度空间,其中 P 为某事件 E 的概率,记为 P(E) ,P(ω)= 1。那么(ω, F , P )就是一个概率空间,样本空间ω,事件空间 *F,*和概率测度 P.
Kolmogorov 理论基于三个公理。让我们在实验中使用它们。
第一公理
这个公理说明事件 E 的概率总是一个正实数。
第二公理
整个样本空间的概率等于 1(这意味着至少有一个基本事件肯定发生)。
第三公理
当我们有可计数数量的互斥事件 E1 , E2 ,…那么事件联合的概率等于每个事件的概率之和。这个性质被称为σ-additivity,,对于有限数量的事件,他的解释很简单。对于无限多的事件来说并不相同,但这超出了本文的范围。
回到我们的实验,我们有:
E1 和 E2 是互斥的,E1 和 E2 的和等于整个ω。从 Kolmogorov 公理出发,利用集合代数,在下一篇文章中,我们将定义概率的一些基本性质。
我希望你喜欢这篇文章,并随时留下评论,关注我未来在 Medium 上的帖子。感谢大家,很快再见。
数据科学家必须知道概率分布
常见的概率分布:二项式分布和正态(高斯)分布。
我是一名移动应用程序的数据科学家。作为一名数据科学家,您经常会从总体中随机抽取一个样本来进行实验或分析。有了随机样本,你就可以对更大的群体进行统计推断。
例如,作为一名移动应用程序数据科学家,在一次 AB 测试中,我将随机抽取所有安装了该移动应用程序的用户,并量化用户在安装该应用程序一周后回来的概率。
我用的这个概率很可能是一个期望值,也就是一个随机变量的平均值。理解这个叫做随机变量的术语很重要。简单地说,随机变量意味着量化随机过程的结果。那么这和一篇关于概率分布的文章有什么关系呢?
一个随机变量的所有可能值的列表,以及它们的概率,称为概率分布。——假人统计要点
概率分布会因分布类型的不同而不同。我不会涵盖所有类型的发行版,但我会涵盖我认为最常见的发行版。有两种主要类型,称为离散型和连续型。我将介绍属于每种类型的概率分布。
- **离散->-**二项分布
- 连续 - >正态分布
二项式分布
让我们首先从二项分布开始。要知道一个分布是否是二项式的,你需要确保它满足以下条件。
- 固定数量的试验/事件—固定(n)
- 每个试验/事件有两种可能的结果——0(失败)或 1(成功)
- 概率 *P(假)/P(真)*对于每次试验都是相同的
- 每个试验/事件都是相互独立的
注:事件和审判这两个术语可以互换。
对于二项式分布,有一个公式可以用来预测随机变量的概率,通常用变量 X. 表示
公式是:
由 Kenny Kim 在 PowerPoint 中创建的图像
回到上面陈述的条件,这里是公式的分解。
- n =固定数量的试验/事件
- ×成功次数= 。因此, n -x 为失败次数
- p = 成功的概率。因此,1- p = 故障概率
另一个可能令人困惑的关键部分是公式的左边部分。
由 Kenny Kim 在 PowerPoint 中创建的图像
这意味着在 n 次试验中安排 x 次成功的方法的数量。F
让我们通过一个例子来说明这一点。
问题:
四个用户安装一个应用程序并在一周后回来的概率分布会是什么样的?
注意:我们假设每个用户一周后回来的概率是相同的。不现实。
- p = 0.40
- 4
回答:
为了找到概率分布,你要使用公式计算所有可能的 x (0,1,2,3,4)。
由 Kenny Kim 在 PowerPoint 中创建的图像
例子的概率分布。由 Kenny Kim 在 PowerPoint 中创建的图像
通常情况下,你永远都不需要手动计算这些,所有的工具都可以帮助你。然而,对于一名优秀的数据科学家来说,掌握您正在使用的工具的基础知识并了解其背后发生的事情是很好的。
正态分布又名高斯分布
正态分布可能是你会看到的最常见的分布之一。它有你所说的钟形分布,如下所示。实际的分布可能看起来不完全相同,但您会看到分布有一个主峰,两边是圆滑的曲线。
标记为重复使用,图片由 Kenny Kim 在 PowerPoint 中修改
它是最重要的分布之一,因为许多真实世界的实验都使用正态分布,无论是企业中的 AB 测试还是研究机构中的实验。这很大程度上是由于 中心极限定理所假设的随着样本量变得越来越大,分布将呈现正态分布。
现在让我们通过一个例子来更好地理解这种分布。我相信分布是非常简单的。
下面是正态分布的一些重要特征
- 平均值将代表曲线的中间(峰值)
- 这种分布通常用标准差来表示
- 分布是对称的
注意:如果您不理解上面的一些概念,我建议您查看我的另一篇文章,它涵盖了基本的统计概念:
下图对理解正态分布的工作原理非常有帮助。
标记为可从维基共享资源中重复使用
就像二项式分布一样,正态分布也有一个公式来计算 x 的概率,但我不确定这在现实世界中有多大帮助…如果你真的想看,就去看这个视频,但我真的相信所有读者需要知道的是,在正态分布中:
- 68.3%的数值在 1 个标准偏差内
- 所有值的 95.4%在 2 个标准偏差内
- 所有值的 99.7%在 3 个标准偏差内
许多公司利用两个标准差来表示一个值在统计上是显著的。我将在下一篇文章中介绍一个使用标准化正态分布公式的 z 检验或 t 检验的例子。
资源
如果您有任何问题或反馈,请随时在下面留下您的问题或反馈,或者在 LinkedIn 上联系我。
中:https://medium.com/@测试操作学习
领英:https://www.linkedin.com/in/kennyk1m/
概率:从苹果到黑天鹅
你认为宇宙总是混乱的,难以预测的,并且“估计”在实践中是没有用的吗?
赫梅尔森·科埃略在 Unsplash 拍摄的照片
直到 20 世纪初,人们还认为宇宙是在一定的规则下运行的。大多数科学家为决定论辩护,认为一切都是可以预测的。随着牛顿的发展,许多支持决定论的观点被提出,也许直到爱因斯坦之前,这一观点从未受到质疑。其中之一是皮埃尔·西蒙·拉普拉斯在 19 世纪初提出的理论。
拉普拉斯说:“我们可以把宇宙现在的状态看作是过去的结果和未来的原因。一个在任何给定时刻都知道驱动自然的所有力量和组成自然的生物的相互位置的智力,如果这个智力足够大,足以提交数据进行分析,可以将宇宙中最大的物体的运动和最轻的原子的运动浓缩成一个公式;对于这样的智力来说,没有什么是不确定的,未来就像过去一样呈现在眼前”。
举例说明;一枚硬币的尾部或头部是一种假设,即考虑到它将出现的所有变量,它可以被找到。这些变量是钱离地面的高度,硬币的翻转速度,旋转的角度,空气中的摩擦力,风的方向和力量等。如果计算成千上万个变量,就可以知道这笔钱是有头还是有尾。这个理论后来被称为拉普拉斯恶魔。这些类型的思想是常见的,并被接受,直到爱因斯坦的物理学。
随着爱因斯坦物理学带来的新理论,牛顿物理学变得过时,在某种程度上说,决定论的方法远离了一切都是可预测的观点,概率观点开始传播。在薛定谔的实验中,他通过用他的名言“量子猫可以既是活着的也是死了的,并且可以同时在两个地方”的表达来支持概率方法,从而得到了发展。然而,一个新的时代已经进入,科学的基础已经改变。
认为用决定论者的方法预测未来是不可能的,但用概率方法预测未来的观点已经开始流行。概率方法已被用于许多科学领域,并开始进入全盛时期。到 20 世纪中后期,反对概率方法的新论点开始出现。
我们经常听到的名字就是混沌理论。混沌理论认为宇宙具有不规则(混沌)的结构。认为它在这种无序中有自己的顺序,但不可能找到这种顺序。这个理论与蝴蝶效应紧密交织在一起;“根据混沌理论,真正改变世界的是那些微小的事情。一只蝴蝶在亚马逊丛林中扇动翅膀,随后一场风暴蹂躏了半个欧洲”。它因这个例子而出名。
混沌理论的主要观点是,它试图解释由于概率方法,结果可能是不可预测的,具有非常非常小的偏差。他试图指出,被概率方法忽略的小错误实际上非常重要。
纳西姆·尼古拉斯·塔勒布在 2007 年出版的《黑天鹅:极不可能事件的影响》一书中,他强烈反对概率方法,并用黑天鹅的例子来解释。在澳大利亚被发现之前,所有的天鹅都被认为是白色的。简而言之,“所有的天鹅都是白色的”这个命题被接受了。澳大利亚被发现后,几个世纪以来被接受的所有天鹅都应该是白色的命题被颠覆了。他认为,不能用过去的信息预测的未来是完全不确定的。他想说,任何事情都可能在任何时候发生,即使是最不可能的事情也可能发生。当然,在这样做的时候,他严厉批评了发展概率方法并将其应用于现实生活问题的统计学家,甚至更进一步,暗示不需要统计学家。
从决定论到《黑天鹅》做了一个大概的讨论后,我想以我自己的看法来结束。当然,从统计学角度来看,做出完美的预测是不可能的。然而,估计近似结果在实践中是有用的。因为“生活是相似性的总和,而不是同一性的总和,没有哪一种观察是普遍的完美例子。”每个观察值都有各自独立的特征。然而,统计学关注的是相似性而不是差异,尽管存在一定的误差,但它能找到近似的结果。
由于未来是不确定的和混乱的,并不意味着它不能以可接受的误差被预测。为了给未来做一些计划,需要从今天开始做一个决定。我想用艾萨克·阿西莫夫的一句话来结束我的演讲;“当人们认为地球是平的时,他们错了。当人们认为地球是球形的时候,他们错了。但是如果你认为认为地球是球形的和认为地球是平的是一样错误的,那么你的观点比两者加起来还要错误”。
概率学习:蒙特卡罗方法
用三个简单的例子学习蒙特卡罗方法
图片来自 Unsplash
朋友们你们好! 欢迎来到概率学习! 在本帖中我们将看到什么是蒙特卡罗方法,它们不同的用例,以及它们在现实世界中是如何应用的。我们开始吧!
*Awesome Machine Learning Resources:**- For* ***learning resources*** *go to* [***How to Learn Machine Learning***](https://howtolearnmachinelearning.com/books/machine-learning-books/)*!* *- For* ***professional******resources*** *(jobs, events, skill tests) go to* [***AIgents.co — A career community for Data Scientists & Machine Learning Engineers***](https://aigents.co/)***.***
蒙特卡洛不是一个城镇吗?这是怎么回事?
来自 Unsplash 的蒙特卡洛图像
你问这个问题是对的。蒙特卡洛是摩纳哥的一部分,以其令人惊叹的世界级豪华赌场而闻名。如果你在这个地方走一走,你会看到数以千计的船只和令人惊叹的汽车,还有一些漂亮的酒店和顶级餐厅。
然而,这不是我们今天在这里的原因。 蒙特卡洛方法或蒙特卡洛实验 是计量经济学、机器学习和统计学中使用的工具,目的是为了获得某些问题的数值结果。为此,蒙特卡罗方法使用了我们世界的一个关键特征:R 和记忆。
啊?你这话是什么意思?我们一会儿就会看到它,但在本文的其余部分请记住这一点:
蒙特卡罗方法利用随机性获得特定问题的数值解 。
很棒吧?让我们看看他们是如何做到这一点的。
什么是蒙特卡罗方法?
这是一种使用推理统计来估计未知量的值的方法。蒙特卡洛的主要元素包括:
- 总体:所有的选择或可能性。
- **样本:**该人群的子集。
蒙特卡罗背后的主要思想是,如果我们随机选择一个样本,它将表现出与从中抽取样本的总体相同的特性。如前所述,这里的关键是随机性。如果我们不采取随机抽样,就没有理由假设这个小的子集将具有与初始群体相同的性质。
此外,为了表示初始群体的属性,样本需要足够大。让我们用一个简单的例子来看看我的意思。
抛硬币模拟
来自平面图标的图标。
想象一下,我们正在向一个从未见过硬币的人解释正面和反面的游戏。游戏的目标是预测硬币落地时是正面还是反面。然而,这个游戏有一个快速捕捉:我们永远不会在硬币落地前给他们看,只会在它落地后才给他们看。
他挑尾巴,我们挑头。
我们抛一次硬币,它正面朝上。我们再扔一次,这次也是正面。我们扔第三次,它又露出了头。现在,我们这位不寻常的朋友可能认为硬币只有一个头。我们不断重复这个过程,到第 10 次翻转时,我们得到了 8 个正面和 2 个反面,如下图所示。
10 次投掷后正面和反面数量的演变。来自 Shutterstock 的硬币。
我们的朋友已经看到了尾巴也能出现,但是他相当厌烦,因为他认为硬币落在头上的机会比落在尾巴上的机会大。他不想继续玩了。我们告诉他,这只是一个运气的例子,这一切都是随机的,但他走开了,留下我们一个人。如果他能多扔几次,比如说 990 次,那么正面和反面的数量就会持平,让他对比赛更加满意…
为了说服他回来,我们编写了一个抛硬币的模拟器,向他展示正面和反面的概率完全相同,他只是运气不好。
我们准备代码,并对 2、5、10、20、50、100、500、1000、10000、100000 和 1000000 次投掷进行仿真。
结果如下面的代码片段所示:
硬币仿真笔记本
在我们 10 次投掷的模拟中,我们得到了与现实生活中我们的朋友完全相反的结果:2 个正面和 8 个反面。我们 80%的投掷都显示了同样的结果。这是否意味着如果我们投掷 10 次,有 80%的概率是正面或反面?当然不是!
正如我之前所说的,我们模拟一个事件的次数(或者人口样本的大小)必须足够大,才能真实地反映现实。在前面的片段中,我们可以看到,随着模拟次数的增加,实验结果越来越接近我们所知道的结果:50%的时间是正面,50%的时间是反面。
我们带着这个代码去找我们的朋友,给他看结果,他同意再玩一次。被蒙特卡洛救了!
前面的例子强调了蒙特卡罗是怎么一回事:对某一特定情况进行大量模拟,以便能够预测其最可能的结果。因为我们的朋友从来没有玩过正面或反面,也没有见过硬币,他可能不知道 1/2 和 1/2 的真实概率,但是,通过详尽地模拟正面和反面,我们向他证明了这一点!
让我们看看另一个例子:著名的轮盘赌。
轮盘赌游戏
你听过典型的短语 【赌场常胜】 ?在这个例子中,我们将使用蒙特卡罗方法解释为什么这是真的。
我们的轮盘赌游戏将按以下方式进行:我们将从 1 到 36 中选择一个数字(在我们的例子中是 7),并模拟 3 种不同的场景,在特定的旋转次数下,每次旋转持续下注 1 美元。我们将针对 2、5、10、20、100、10000 和 1000000 次旋转进行此操作。我们的轮盘没有 0 口袋,我们从不玩黑或白,只玩 7 号。
注: 如果我们也随机生成我们下注的号码,结果将是相同的,但为了简单起见,我们选择始终下注相同的号码。
再一次,我们使用蒙特卡罗的优势进行解释:随机模拟游戏的结果特定次数,以了解其性质。让我们看看下面的代码片段会发生什么!
轮盘模拟
这段代码实现了我们上面描述的内容。它模拟了我们在不同的场景下对 7 号下注 1 美元。我们从 2 次旋转开始,然后到 5 次旋转,然后到 10 次,以此类推…每次模拟我们做 3 次。
正如我们所见,对于低次数的旋转,我们几乎总是输掉所有的钱。然而,在 10 次旋转中,我们幸运地获得了 260%的回报。这表明,对于少量的旋转,结果是相当不稳定的:我们可以失去一切或赢得很多。结果变化很大。
这是赌一晚上的乐趣之一,结果完全出乎意料,你可能会输(这很可能会发生),但你也可能会赢!
然而,需要观察的重要事情是随着我们旋转次数的增加,预期收益开始收敛到 0 。如果我们仔细观察,我们会发现现在结果几乎没有变化。结果不仅更接近 0,而且更接近在一起。
这才是赌场在乎的。他们不关心 20 次、50 次甚至 100 次旋转会发生什么。他们关心一百万次旋转会发生什么。他们关心每天晚上什么时候有很多人去玩和下注。
赌场总是赢。来自平板图标的图标
这里重要的一点是,对于单个玩家来说,投掷的次数很少,结果是高度可变的:他的回报率可以从-100%到非常高的数字,如 260%甚至更高。然而,随着许多玩家聚在一起玩游戏,在几天、几周、几个月的时间里,上亿次的投入,所有玩家的预期回报将是高度可预测的,并且非常非常接近于零:赌场确切地知道长期会发生什么。
所以即使一个玩家赢了,也是可以的。他们知道所有玩家的复合平均回报非常接近于零:他们不会损失任何钱,而你可能要支付门票、饮料、演出的费用,并在其他游戏上输掉你的钱。
让我们看最后一个最后一个例子如何使用蒙特卡罗来估算某个平面形状的面积。
周长的面积:
我们要用蒙特卡罗方法的最后一件事,是估计某个形状内部的面积,在我们的例子中是一个圆周。
来自平板图标的图标。
具体来说,我们要用它来计算一个正方形和一个圆形的面积之间的关系。我们得到了下图:
我们有一个边长为 L 的正方形,周长为 L/2
我们知道正方形的面积是 L 乘以 L,但是,我们完全不知道圆的面积。然而,我们听说过蒙特卡罗方法,并设计了一个程序来使用这个统计工具计算它!
我们要做的是在正方形内随机生成点,在模拟结束时,计算我们在圆内得到的点的总数,以及生成的点的总数,并用它来计算圆内的面积。为了简单起见,我们将使用一个大小为 L = 1 的正方形。
以下代码显示了为发现圆的面积而实现的蒙特卡罗模拟:我们随机生成形状右上象限的点,并使用已知的正方形面积、落入圆内的点数以及生成的总点数,精确计算圆的面积。
模拟计算圆的面积
在下图中,您可以看到一个接一个生成的图像。它展示了蒙特卡洛的魔力。使用随机生成的点,我们画一个圆,随着我们运行更多的模拟,我们变得越来越精确。我们生成的随机点越多,我们的模拟就越好。我们可以在前面的代码中看到,随着模拟次数的增加,圆的估计面积变得越来越接近真实面积。
随着我们进行越来越多的模拟,圆的形状也在演变。
**酷吧?**蒙特卡罗可用于获得令人惊叹的数值结果的另一种情况。这也可以用来计算我们想要的任何奇怪形状的面积。
结论
通过三个非常简单的例子,我们对蒙特卡洛方法或蒙特卡洛实验有了一种直觉。这些方法的关键要素,被一遍又一遍地重复:随机抽样。这篇文章中展示的例子是这些统计方法的非常简单的应用,然而它们可以用于许多其他领域,如物理学、人工智能或市场营销。
点击这里查看我的其他概率学习帖子:
我强烈建议你阅读它们,因为它们很有趣,充满了关于概率机器学习的有用信息。
就这些,我希望你喜欢这个帖子。请随时在 Twitter 上关注我,地址: @jaimezorno 。还有,你可以在这里 看看我在数据科学、统计学、机器学习的帖子。好好读!