高维数据聚类的基础(3D 点云)
3D 地理数据
为什么无监督的分割和聚类是“人工智能的主体”?使用它们时要注意什么?如何评价表演?三维点云数据的解释和说明。
聚类算法允许以无人监管的方式将数据划分为子组或聚类。直观上,这些片段将相似的观察结果组合在一起。因此,聚类算法在很大程度上取决于如何定义相似性这一概念,这通常是特定于应用领域的。
不同的聚类策略应用于这个房间的噪声点云。可以看出,空间邻近性似乎是定义这种相似性以构成片段的选择标准。弗洛伦特·普克斯博士
什么是集群?
聚类算法通常用于探索性数据分析。它们也构成了人工智能分类管道中的大部分过程,以无监督/自学的方式创建良好标记的数据集。
在 NIPS 2016 上展示的原始 LeCun 蛋糕模拟幻灯片,突出显示的区域现已更新。
在 3D 地理数据的范围内,聚类算法(也被定义为无监督分割)允许获得片段汤,该片段汤成为若干过程的主干,例如特征提取、分类或 3D 建模,如下图所示。
在这里,您可以看到一个自动建模过程,该过程利用分段信息来很好地提取 3D 网格。弗洛朗·普克斯博士
除了地理数据应用之外,它们还用于识别:
- 行为相似的客户(市场细分);
- 对某个工具有类似使用的用户;
- 社交网络中的社区;
- 金融交易中的循环模式。
它们通常是降维算法的补充,降维算法允许在二维或三维中查看不同的属性(称为维度)。如果“视图”表现出足够的去相关性,可以使用聚类算法来形成这些点的子组,即聚类,如下图所示。
通过创建一条线将数据集分成两个子组来查找两个分类的简单示例。
这样,点之间的关系可以直观地表示出来。或者,不是表示整个数据,而是每个聚类仅显示一个代表点。
一旦识别出聚类,也可以只使用每个聚类的一个代表来查看数据,而丢弃其他的。
确定两个聚类的质心作为新的基数据。弗洛伦特·普克斯博士
这为什么有用?
聚类算法在标记数据代价昂贵的常见情况下特别有用。以注释大型点云为例。根据每个点所代表的内容对其进行注释可能是一项漫长而乏味的工作(参见我在这里所做的)😄)这样做的人可能会由于疏忽或疲劳而无意中引入错误。让聚类算法将相似的点分组在一起,然后在给聚类分配标签时只需要人工操作,这样更便宜,甚至可能更有效。
语义分割工作流程中一个优势的简单说明。弗洛朗·普克斯博士
因此,聚类算法可以用于将同一聚类中的一个点的属性扩展到同一聚类中的所有点(在前面的例子中,表示的椅子对象。).
在地理数据范围之外,推断数据属性有助于:
- 找到相似的图像,可能代表相同的物体、相同的动物或相同的人;
- 提取可能谈论同一主题的相似文本;
- 在图像中搜索属于同一对象的像素(这被称为分割)。
在上面的例子中,主题(图像、文本、像素)被表示为 2D/3D/nD 点,然后被分组为簇。然后,足以推断,如果一个群集中的一个图像代表一只鸭子,则该群集中的所有图像部分都可能代表鸭子。
我们将定义几个需要优化的标准,以定义一个有趣的数据分区。这些然后被用来派生一些最著名的聚类算法,将在另一篇文章中讨论,否则阅读会有点密集😇。
如何知道聚类是否具有代表性?
在无监督算法的情况下,算法的目的不像在有监督算法的情况下那样明显,在有监督算法的情况下,有明确的任务要完成(例如分类或回归)。因此,该模式的成功更加主观。任务更难定义的事实并不妨碍我在下面详述的各种性能测量。
距离和相似性
聚类意味着将最接近或最相似的点组合在一起。聚类的概念很大程度上依赖于距离和相似性的概念。
这些概念对于形式化非常有用:
- (1)两个观测值彼此接近的程度;
- (2)观测值与群集的接近程度;
- (3)两个星团之间的距离。
简单说明两个观测值之间的一些距离(1),一个观测值和一个集群(2),两个集群(3)。弗洛伦特·普克斯博士
最常用的距离示例是欧几里德距离和曼哈顿距离。欧几里得距离是欧几里得空间中两点之间的“普通”直线距离。曼哈顿距离之所以被称为曼哈顿距离,是因为它在两个维度上对应于出租车在曼哈顿街道上行驶的距离,这两个维度要么相互平行,要么相互垂直。
欧几里德距离和曼哈顿距离的简单说明。弗洛朗·普克斯博士
因此,距离可以用来定义相似性:两个点离得越远,它们就越不相似,反之亦然。为了注入一点数学知识,我们可以非常简单地将 x 和 y 之间的距离 d 转换为相似性度量 s,例如:s(x,y)=1/1+d(x,y)。
定义相似性的另一种常见方法是使用皮尔逊相关,它测量当基础数据居中时由向量 x 和 y 形成的角度的余弦。
皮尔逊相关系数的简单说明。弗洛朗·普克斯博士
但不要太深入,重要的是要注意皮尔逊相关性将考虑分布的形状,而不是它们的振幅,欧几里德距离主要考虑的是振幅。因此,距离度量的选择是重要的。
集群形状
簇的形状是一个重要的元素,我们最初描述为:
- (1)自我收紧:两个接近的点必须属于同一个群集
- (2)相距较远:相距较远的两个点必定属于不同的簇。
紧密程度可以提示凝聚簇的形成。弗洛伦特·普克斯博士
通常,我们寻找自身紧密的星团。让我们用一个例子来解释这些性质,使用欧几里得距离。首先,我们可以很容易地计算一个簇的质心(这个簇的点的重心)。然后,聚类的均匀性可以定义为该聚类中包含的每个点到质心的距离的平均值。以这种方式,紧密的集群将比分散的点的集群具有更低的异质性。然后,为了表征数据集中的所有聚类,而不是一个聚类,我们可以计算每个聚类的同质性的平均值。
简单说明同质性如何提供直观的感觉来更好地表征集群。弗洛伦特·普克斯博士
其次,我们希望集群彼此远离。为了量化这一点,我们通常将两个聚类的间距定义为它们的质心之间的距离。再一次,我们可以计算得到的所有成对簇上这些量的平均值。
一个简单的例子展示了如何使用分离来获得一个好的聚类。弗洛朗·普克斯博士
我们现在有两个优化标准:同质性和分离性。为了方便起见,我们可以将它们归为一个标准,即戴维斯-波尔丁指数。该指数的思想是比较类内距离(同质性)——我们希望它低——和类间距离(分离性)——我们希望它高。对于一个给定的集群,这个指数更弱,因为所有的集群都是同类的,并且分离得很好。
另一种量化聚类满足这两个要求(同质性和分离性)的方式是测量所谓的轮廓系数。对于给定点 p,轮廓系数 s§用于评估该点是否属于“正确的”聚类。为此,我们尝试回答两个问题:
- p 靠近它所属的簇的点吗?我们可以计算 p 到它所属的簇中所有其他点的平均距离 a§。
- 这个点离其他点远吗?如果 p 被分配给另一个簇,我们计算 a§可以取的最小值 b§。如果 p 已经被正确赋值,那么 a(x) < b(x)。轮廓系数由 s(x)= b(x)-a(x)/max(a(x),b(x))给出,范围在-1 和 1 之间。它越接近 1,p 对其簇的分配就越令人满意。
💡 提示: 对一个聚类进行评估,其平均轮廓系数可以计算出来,例如使用 scikit-learn
和 sklearn.metrics.silhouette_score.
命令
集群稳定性
另一个重要的标准是聚类的稳定性:如果我用不同的初始化对相同的数据,或者对数据的不同子集,或者对相同的稍微有噪声的数据运行该算法几次,我会得到相同的结果吗?这个标准在选择分类数时特别重要:如果选择的分类数符合数据的自然结构,则分类将比不符合数据的自然结构更稳定。
寻找集群的“参数监督”及其影响的一个例子。弗洛朗·普克斯博士
在上面的例子中,试图确定 3 个聚类的算法将合理地找到我们看到的 3 个聚类。但是如果要求确定 4 个群,这 4 个群中的分布将更加随机,并且不一定是相同的两倍。这是确定 3 是比 4 更好的聚类数的一种方法。
与特定领域知识的兼容性
很多时候,我们还会“用眼睛”评估一个聚类算法,看看建议的聚类是否有意义。这个集群中分组的点都代表同一个对象吗?这两个集群中的点代表不同的对象吗?
请注意下图中的各个群集。它们有直观意义吗?中央灯柱是否应该用一簇来描述?3 簇?更多?弗洛朗·普克斯博士
为了更灵活地做到这一点,我们可以在一个数据集上工作,在这个数据集上我们知道数据的合理分区。然后,我们将这个分区与我们的聚类算法返回的分区进行比较。例如,我们可以处理由平面形状分割的点云。下一步是评估由聚类算法形成的组是否对应于那些预先定义的组。
获取点云的一部分,并创建“平面标记”数据集以与聚类结果进行比较的示例。弗洛朗·普克斯博士
很简单!就像评价一个多类分类算法。但没那么快:如果我们感兴趣的是相同的对象是否属于同一个集群,那么这个集群是第一个、第二个还是第 k 个集群都无关紧要。因此,必须使用特定的性能指标来评估数据集的两个分区的一致性。
💡 ***提示:***这些可以在 sklearn.metrics.
中找到
这些措施的一个例子是兰德指数。Rand 指数是在两个分区中以相同方式分组的点对(p1,p2)的比例:或者因为在这两种情况下,P1 和 p2 属于相同的聚类,或者因为在这两种情况下,P1 和 p2 属于不同的聚类。
Rand 指数可以通过预测大量的聚类来人为地膨胀:属于不同聚类的点对将是众多的,并且很有可能两个标记不同的点将在两个不同的聚类中。调整后的 Rand 指数(ARI)通过归一化 Rand 指数(RI)来校正这种影响:ARI=RI-E(RI)/max(RI)-E(RI),其中 E(RI)是 Rand 指数的期望值,即通过随机划分数据获得的指数。对于随机聚类,该调整后的索引接近于 0,并且仅当聚类恰好对应于初始分区时,该索引才等于 1。
💡 提示: 在 scikit-learn
中可以算出感谢 sklearn.metrics.adjusted_rand_score
结论
无监督和自学习方法对于解决自动化挑战非常重要。特别是,在深度学习时代,手动创建标记数据集是乏味的,缓解这一过程的方法非常受欢迎。聚类算法为此提供了至关重要的解决方案,用于将数据集划分为相似观察值的子组:
- 它们可以用来更好地理解数据;
- 它们可用于促进数据可视化;
- 它们可用于推断数据属性。
然后,为了评估聚类算法,我们可以考虑:
- 它产生的簇的形状(它们是否密集、分离良好)。这里经常用到剪影系数;
- 算法的稳定性;
- 结果与特定领域知识的兼容性,可以使用丰富的度量来评估。
更进一步
在本文中,我介绍了集群的基本原理,特别是在 3D 点云上。下一步是非常自然的,包括直接进入代码,并查看可以用来开始的最突出的方法。这将在下一篇文章和使用 Python 中讨论。
如果您想扩展阅读范围并获得有关 Python 和使用 3D 数据(点云、网格)的基础知识,我建议您深入了解 3D 地理数据学院的信息:
编队学习先进的点云处理和三维自动化。开发新的 python 地理数据技能和开源…
learngeodata.eu](https://learngeodata.eu/point-cloud-processor-formation/)
或者你可以阅读以下内容:
被称为点云的离散空间数据集通常为决策应用奠定基础。但是他们能不能…
towardsdatascience.com](/the-future-of-3d-point-clouds-a-new-perspective-125b35b558b9) [## 使用 Python 探索 3D 点云处理
教程简单地设置 python 环境,开始处理和可视化 3D 点云数据。
towardsdatascience.com](/discover-3d-point-cloud-processing-with-python-6112d9ee38e7) [## 使用 Python 从点云生成 3D 网格的 5 步指南
生成 3D 网格的教程(。obj,。ply,。stl,。gltf)自动从三维点云使用 python。(奖金)…
towardsdatascience.com](/5-step-guide-to-generate-3d-meshes-from-point-clouds-with-python-36bad397d8ba)
参考文献和相关作品
集群应用和智能点云概念的简要概述
科技文章:
-
Poux,F. ,& Billen,R. (2019)。基于体素的三维点云语义分割:无监督的几何和关系特征与深度学习方法。 ISPRS 国际地理信息杂志。8(5), 213;https://doi.org/10.3390/ijgi8050213
-
Poux,F. ,纽维尔,r .,纽约,g .-a .&比伦,R. (2018)。三维点云语义建模:室内空间和家具的集成框架。遥感、 10 (9)、1412。https://doi.org/10.3390/rs10091412
-
Poux,F. ,Neuville,r .,Van Wersch,l .,Nys,g .-a .&Billen,R. (2017)。考古学中的 3D 点云:应用于准平面物体的获取、处理和知识集成的进展。地学, 7 (4),96。https://doi.org/10.3390/GEOSCIENCES7040096*
互联和自动驾驶汽车网络安全的未来
介绍自动驾驶汽车面临的不同安全挑战以及应对这些挑战的机器学习方法。
介绍
自动驾驶汽车利用传感器和复杂的算法来检测和响应周围的环境。自动驾驶汽车常用技术的一些例子有:计算机视觉、激光雷达、全球定位系统等
由于这些技术,自动驾驶汽车不需要司机来完成甚至复杂的旅程。此外,多辆自动驾驶汽车可以相互通信,以改善交通和避障。
图 1 总结了汽车自动化水平的发展。许多公司,如 Waymo 和特斯拉,现在都在大力投资于自动驾驶汽车(自动驾驶汽车)的未来领先地位。
图 1:自动驾驶汽车的自动化水平[1]
“交通部的研究人员估计,全自动驾驶汽车,也称为自动驾驶汽车,可以通过消除这些由于人为错误造成的事故,将交通死亡人数减少高达 94%。”
-兹德涅特,蒂娜·马多克斯[2]
网络安全
由查理·米勒和克里斯·沃洛塞克最近进行的一项研究表明,一辆吉普切诺基只需通过互联网连接就能被黑客攻击(让汽车停在高速公路上!).此外,其他类型的车辆已被证明对有线或无线攻击敏感(如丰田普锐斯、福特 Escape)。在这些情况下,黑客已经能够:激活/禁用车辆刹车、方向盘并提高车辆速度。
图 2:自动驾驶汽车中的网络安全[3]
黑客可以尝试以许多可能的方式利用自动驾驶汽车的漏洞[4]:
- 云计算:自动驾驶汽车每秒钟都会产生和存储新数据,并利用云计算进行快速存储/检索(例如识别 GPS 位置以预测交通流量)。如果黑客能够访问汽车的云数据库,就能够操纵汽车的许多功能(例如,关闭安全设备)。此外,因为信息传输必须尽可能快,所以很难对发送的信息进行高度加密。
- 多种编码语言:现在的汽车是由不同制造商制造的许多部件组装而成的。为了确保汽车完美运行,所有不同的部件都需要完美地相互通信。如果不能确保安全通信,黑客可能会试图利用这一点。汽车制造商通常会进行渗透测试来确保他们车辆的安全性。
黑客攻击自动驾驶汽车有两个主要风险:
- 黑客也许能远程控制这辆车。
- 黑客可能能够访问用户的个人信息。
像美国和英国这样的国家已经实施立法,以确保汽车制造商保持最低的网络安全标准。
确保自动驾驶汽车的高安全性也可以增加公众对投资这项新技术的信任。
如果你有兴趣了解更多关于自动驾驶汽车网络安全的信息,这篇研究论文是一个很好的起点。
机器学习
如前所述,车辆总是产生和存储大量数据,然后就轮到我们来决定如何充分利用这些数据。
机器学习有可能被用来识别和防止异常行为(例如,在高速公路上高速行驶时让汽车进入停车模式)[5]。通过这种方式,可以阻止黑客攻击的发生。
研究人员现在仍在进行,以提高预测的准确性。事实上,为了创建能够区分正常和异常驾驶行为的模型,必须考虑与汽车及其周围环境相关的许多因素。
此外,如果驾驶员根据自己的判断认为有必要,可以增加一个功能,使其允许“异常”行为。
图 3:自动驾驶汽车中的机器学习[6]
法律含义
随着自动驾驶汽车变得越来越受欢迎,机构现在开始担心是否有必要制定新的法律来规范它们的使用。
例如,2018 年在美国亚利桑那州,第一起自动驾驶汽车撞死行人的案件已经登记。根据警方的报告,行人可能有过错。在这种情况下,应该认定谁有过错?
- 是车里的司机吗?(事故发生时没有控制车辆的人)。
- 是软件开发商吗?(谁开发了处理这类情况的软件)。
- 是汽车制造商吗?(谁在设计和供应车辆时没有采取足够的预防措施)。
- 谁应该负责汽车保险?(因为在大多数情况下驾驶员不控制车辆)。
- 如果发生不可避免的碰撞,汽车应该优先考虑自身安全还是其他车辆/行人的安全?
这些问题中的大多数仍然没有答案,可能会采取不同的方法来解决它们(取决于监管国家和文化相对主义)。
联系人
如果你想了解我最新的文章和项目,请通过媒体关注我,并订阅我的邮件列表。以下是我的一些联系人详细信息:
文献学
[1]这就是自动驾驶汽车进化的样子。商业内幕。访问:https://www . business insider . com/what-the-different-levels-of-drilling-cars-2016-10?r=US & IR=T
[2]自动驾驶汽车如何在美国拯救超过 35 万人的生命,在全球拯救数百万人的生命。兹德涅特,蒂娜·马多克斯。访问:https://www . zdnet . com/article/how-autonomous-vehicles-can-save-over-35 万-lifes-in-the-us-and-millions-world wide/
[3]宾夕法尼亚州关于自动驾驶汽车的公众意见。可查阅:https://sites . PSU . edu/mihiryouthere/2017/03/03/关于自动驾驶汽车的公众意见/
[4]自动驾驶汽车:汽车制造商如何克服网络安全问题。杰迈玛·迈耶斯,绊网。可查阅:https://www . tripwire . com/state-security/featured/auto-drive-cars-cyber security-issues/
[5]机器学习如何增强自动驾驶汽车的网络安全。DINO CAUSEVIC,toptal。访问网址:https://www . top tal . com/insights/innovation/how-machine-learning-can-enhanced-cyber safety-for-autonomous-cars
[6]安全测试自动驾驶汽车需要考虑潜在的深层学习弱点,下一个大未来。可查阅:https://www . next big future . com/2016/10/safety-testing-auto-drive-cars-needs . html
基于向量自回归的未来价格预测
预测分析和时间序列数据
多步未来预测的简单步骤
作者图片
向量自回归(VAR)具有易于实施的优势。VAR 中的每个方程在右边有相同数量的变量,整个系统的系数{α1,α2,…,β11,β21,…, γ 11, γ 21,… }可以通过对每个方程单独应用(OLS)回归来容易地估计。我们可以使用普通的最小二乘(OLS)估计器从每个方程中分别计算出这个模型。由于 OLS 估计量具有标准的渐近性质,因此可以用标准的 t 和 F 统计量来检验一个方程或多个方程中的任何线性约束。VAR 模型相对于传统机器学习模型的优势在于,结果不会被庞大复杂的结构(“黑盒”)所隐藏,而是易于解释和获得。
格兰杰因果关系测试有助于了解一个或多个变量是否具有预测内容,脉冲响应函数和方差分解通常用于量化长期影响。我已经在过去的中写过关于 VAR 的以及多元时间序列如何被拟合以生成涵盖两者的预测。
在这里,我将讨论使用 VAR 预测未知未来的简单步骤。
stock = ['^RUT', '^GSPC', '^DJI', '^IXIC' ]
start = pd.to_datetime('1990-01-03')
df = web.DataReader(stock, data_source = 'yahoo', start = start);
print(df.tail());
这里,我们有来自罗素 2000 (^RUT)、标准普尔 500 (GSPC)、纳斯达克综合指数(IXIC)和道琼斯工业平均指数(^DJI).)的数据让我们为所有变量分离 Adj Close 列。
data = df['Adj Close']
data.tail()
让我们在应用标准化后在一个图表中直观地比较这些系列。我们可以看到这里选择的所有变量之间的高度相关性。这是多元 VAR 的一个很好的候选。
scaler = MinMaxScaler(feature_range=(0, 1))
sdf_np = scaler.fit_transform(data)
sdf = DataFrame(sdf_np, columns=data.columns, index=data.index)
plt.figure(figsize=(12,6))
plt.grid()
plt.plot(sdf)
plt.legend(sdf.columns)
plt.show()
我们的目标是预测^RUT 的预期未来价格,选择 DJI、GSPC 和 IXIC 的动机是它们与 RUT 的高度相关性。
我们还可以通过测量滚动窗口大小函数中的滚动窗口上的平均线性相关性来诊断相关性;在这里,我选择了 5 天和 20 天的窗口大小进行可视化显示。
blue, orange, red = '#1f77b4', '#ff7f0e', '#d62728' # color codes
plt.figure(figsize=(12,4))
plt.grid()
cor1, cor2, cor3 = list(), list(), list()
# average correlation for increasing rolling window size
for win in range(5, 20): # Days
cor1.append(data['^GSPC'].rolling(win).corr(data['^RUT']) \
.replace([np.inf, -np.inf], np.nan).dropna().mean())
cor2.append(data['^DJI'].rolling(win).corr(data['^RUT']) \
.replace([np.inf, -np.inf], np.nan).dropna().mean())
cor3.append(data['^IXIC'].rolling(win).corr(data['^RUT']) \
.replace([np.inf, -np.inf], np.nan).dropna().mean())plt.plot(range(5, 20), cor1, '.-', color=blue, label='RUT vs GSPC')
plt.plot(range(5, 20), cor2, '.-', color=orange, label='DJI vs RUT')
plt.plot(range(5, 20), cor3, '.-', color=red, label='IXIC vs RUT')
plt.legend()
plt.xlabel('Rolling Window Length [Days]', fontsize=12)
plt.ylabel('Average Correlation', fontsize=12)
plt.show()
在变量或特征选择的上下文中,我们需要决定将哪些变量包含到模型中。由于我们不能也不应该包括所有潜在利益的变量,我们在选择变量时必须有一个先验的想法。
ADFuller 测试平稳性
我们需要消除数据中的趋势,让模型进行预测。让我们检查一下数据集的平稳性。
def adfuller_test(series, signif=0.05, name='', verbose=False):
r = adfuller(series, autolag='AIC')
output = {'test_statistic':round(r[0], 4), 'pvalue':round(r[1], 4), 'n_lags':round(r[2], 4), 'n_obs':r[3]}
p_value = output['pvalue']
def adjust(val, length= 6): return str(val).ljust(length)print(f'Augmented Dickey-Fuller Test on "{name}"', "\n ", '-'*47)
print(f'Null Hypothesis: Data has unit root. Non-Stationary.')
print(f'Significance Level = {signif}')
print(f'Test Statistic = {output["test_statistic"]}')
print(f'No. Lags Chosen = {output["n_lags"]}')for key,val in r[4].items():
print(f' Critical value {adjust(key)} = {round(val, 3)}')
if p_value <= signif:
print(f" => P-Value = {p_value}. Rejecting Null Hypothesis.")
print(f" => Series is Stationary.")
else:
print(f" => P-Value = {p_value}. Weak evidence to reject the Null Hypothesis.")
print(f" => Series is Non-Stationary.")# ADF test on each column
for name, column in data.iteritems():
adfuller_test(column, name = column.name)
很明显,我们现有的数据集是不稳定的。让我们取一阶差分,再次检查平稳性。
nobs = int(10) # number of future steps to predict# differenced train data
data_diff = data.diff()
data_diff.dropna(inplace=True)
print('Glimpse of differenced data:')
print(data_diff.head())# plotting differenced data
data_diff.plot(figsize=(10,6), linewidth=5, fontsize=20)
plt.title('Differenced data')
plt.show()
从图中,我们可以评估一阶差分使数据稳定。然而,让我们运行 ADF 测试增益来验证。
# ADF Test on each column
for name, column in data_diff.iteritems():
adfuller_test(column, name=column.name)
我们的数据是平稳的,以适应回归模型。
向量自动回归
指定了一个模型,就必须决定 VAR 模型的适当滞后长度。在决定滞后的数量时,通常使用统计方法,如 Akaike 信息标准。
var_model = smt.VAR(data_diff)
res = var_model.select_order(maxlags=15)
print(res.summary())results = var_model.fit(maxlags=15, ic='aic')
print(results.summary())
未来预测
既然模型已经拟合好了,让我们来预测一下。
# make predictions
pred = results.forecast(results.y, steps=nobs)
pred = DataFrame(pred, columns = data.columns+ '_pred')
print(pred)
使用下面几行代码可以获得类似的观察结果。在这两种情况下,我们都得到了输出,但规模不同,因为我们的输入数据是不同的,以便稳定。
将转换数据反转为原始形状
pred = DataFrame(pred, columns=data.columns+ '_pred')def invert_transformation(data_diff, pred):
forecast = pred.copy()
columns = data.columns
for col in columns:
forecast[str(col)+'_pred'] = data[col].iloc[-1] + forecast[str(col) +'_pred'].cumsum()
return forecastoutput = invert_transformation(data_diff, pred)
print(output.loc[:, ['^RUT_pred']])
output = DataFrame(output['^RUT_pred'])
print(output)
以上是未来 10 天的预测;让我们为这些值指定未来的日期。
分配未来日期
d = data.tail(nobs)
d.reset_index(inplace = True)
d = d.append(DataFrame({'Date': pd.date_range(start = d.Date.iloc[-1], periods = (len(d)+1), freq = 'd', closed = 'right')}))
d.set_index('Date', inplace = True)
d = d.tail(nobs)
output.index = d.index
print(output)
所以,这里我们可以看到未来的预测。让我们用历史数据画一个图表来形象化。
fig = go.Figure()
n = output.index[0]
fig.add_trace(go.Scatter(x = data.index[-200:], y = data['^RUT'][-200:], marker = dict(color ="red"), name = "Actual close price"))
fig.add_trace(go.Scatter(x = output.index, y = output['^RUT_pred'], marker=dict(color = "green"), name = "Future prediction"))
fig.update_xaxes(showline = True, linewidth = 2, linecolor='black', mirror = True, showspikes = True,)
fig.update_yaxes(showline = True, linewidth = 2, linecolor='black', mirror = True, showspikes = True,)
fig.update_layout(title= "10 days days RUT Forecast", yaxis_title = 'RUTC (US$)', hovermode = "x", hoverdistance = 100, # Distance to show hover label of data point spikedistance = 1000,shapes = [dict( x0 = n, x1 = n, y0 = 0, y1 = 1, xref = 'x', yref = 'paper', line_width = 2)], annotations = [dict(x = n, y = 0.05, xref = 'x', yref = 'paper', showarrow = False, xanchor = 'left', text = 'Prediction')])
fig.update_layout(autosize = False, width = 1000, height = 400,)fig.show()
在这里,我们可以看到风险值预测未来价格的接近程度。
关键要点
VAR 很容易估计。具有良好的预测能力;VAR 模型能够捕捉时间序列变量的动态结构,通常将所有变量视为先验内生变量。然而,将标准风险值模型拟合到大维时间序列可能具有挑战性,主要是因为涉及大量参数。
我们在这里讨论了如何找到最大滞后,以及如何用转换后的数据拟合 VAR 模型。模型拟合后,下一步是预测多步未来价格,并将转换后的数据转换回原始形状,以查看实际预测价格。
在最后一个阶段,绘制历史价格和预测价格可以清晰直观地展示我们的预测。
注意: 此处描述的程序是实验性的,在用于任何商业目的时都应谨慎使用。所有此类使用风险自负。
面向未来的 2020 年分析工作:雇佣多元化团队
在之前的一篇文章中,我们讨论了人工智能领域一些最紧迫的问题,例如自动化系统对糟糕或不道德的决策缺乏人类问责,对偏见来源的理解不足,以及这些问题是如何因过度依赖“黑盒”方法和所谓的“客观”数据而加剧的。随着消费者越来越了解分析对他们生活的影响,行业将目光转向联邦和自我监管,以提供针对这些问题的安全网,任何分析企业都必须将这些问题放在战略的最前沿,以此为基础设施、方法和考虑事项的转变做好准备,一旦这些问题的影响完全确立,就必须考虑这些转变。
在这种情况下,我想重点谈谈上述文章末尾列出的建议之一;雇佣多元化团队。雇佣多元化团队的好处已经广为人知;麦肯锡在 2015 年发布的报告《多样性至关重要》(T4)中发现,性别多样性排名前四分之一的公司,其财务回报比全国行业中值高出 15%。考虑到种族/民族多样性,这一比例上升至 35%。与此同时,与数据集中的平均公司相比,性别和民族/种族均处于底部四分之一的公司在统计上不太可能实现高于平均水平的财务回报。
Sanford C. Bernstein & Co .领导和道德中心主任 Katherine W. Phillips 在《科学美国人》上发表的一篇文章强调了长达几十年的研究表明,多样性通过消除我们如何与人交往的隐藏偏见,如期望与我们有相似背景的人得出相同的结论,或分享对我们仅有的信息的看法,来促进创新、创造力和信息共享。
在分析领域,当涉及到处理数据和设计有偏见的决策系统时,很容易在上述问题和考虑多元化团队构成的好处之间划出一条线。作为一个领域,在真正理解和利用其方法和技术所需的专业知识领域(软件工程和架构、统计学、甚至社会学)中已经存在重要的交叉点,因此,考虑其他不太明显的多样性轴心(如性别、种族、民族和性取向)将导致创新、信息共享和事实核查的激增,这在行业的当前状态下是非常需要的。没有培育和培养多元化环境的公司,在处理数据、数据处理以及最终如何输入预测或分析系统方面,陷入偏见陷阱的风险更高。他们还错过了可能带来新机会的重要见解,特别是当这些数据来自一个异构和多样化的背景,团队甚至在分析的初始探索阶段都不准备识别或考虑这些背景时。
非多样化分析团队的高风险不仅仅是猜测。英伟达人工智能总监、加州理工学院教授阿尼玛·阿南德·库马尔(Anima Anandkumar)表示,当研究团队是同质的时候,人工智能系统对某些群体造成伤害的风险就更高:“(T4)多样化的团队更有可能在产品推出之前就发现可能产生负面社会后果的问题,”她说。在《与像我一样的人合作:美国的种族合作》一书中,作者理查德·弗里曼和黄伟分析了 1985 年至 2008 年间发表的 150 万篇科学论文,发现由不同种族的作者撰写的论文被引用的次数更多,影响因子也更高。证据很明显:多样性阻止偏见,鼓励好奇、怀疑和分析性思维;任何分析企业都会高度重视的属性。
来源:Kaggle 数据调查 2019 年数据集
然而,像 2018 年 Burtch Works 关于数据科学工作需求和薪酬的研究报告指出,只有 15%的数据科学家、22%的早期职业数据科学家和少得可怜的 10%的数据科学执行领导者是女性。 2019 年 Kaggle State of Data 调查显示了同样令人担忧的性别差距,84%的受访者认为自己是男性,这一数字与之前的调查相比几乎没有变化。对少数群体的研究更难获得;咨询公司 Priceonomics 的一篇 2017 年文章使用大会的学生入学数据发现,数据科学课程迄今为止西班牙裔/拉美裔和非裔美国学生的总比例最低。
哥斯达黎加 Granadilla 的 GAP 办事处
随着越来越多的证据表明多元化分析团队可以识别和处理偏见,产生强大的数据管道,并利用多元化数据集提供的文化和行为洞察,更令人失望的是,大多数企业数据工作仍未利用这些优势。
在我任职于 Growth Acceleration Partners 期间,我发现“投资于人”的价值不仅仅是其品牌材料中的一个要点。毫无疑问,我们的近岸性质鼓励并使我们能够与我有幸与之互动的极其多样化的员工接触,但偶然发现多样性的公司与真正理解多样性不仅是一种文化资产或“值得拥有的东西”,而且是其成长和创新框架不可或缺的一部分的公司之间是有区别的。在 Ideas to Invoices 播客中,首席执行官乔伊斯·德斯特(Joyce Durst)被引用说“让女性在公司各个级别的各个岗位上工作的关键在于思想的多样性。(……)我们可以有多样性,让最好的想法、创新和想法摆在桌面上(……),包括性别、年龄和多元文化的多样性。GAP 最近获得了全国妇女商业企业理事会颁发的妇女商业企业证书。
这种对多样性的理解和依赖使得我们构建和改进分析工作和产品的工作对于经验丰富的领导和新员工来说都更加容易。作为一家专注于软件的公司,建立一个强大的分析实践提出了在我们习惯的领域之外招聘的挑战。我们第一次接触到其他领域的精算学家、经济学家和专业人士,这些人与我们过去很少接触的学术机构的工作和项目有关。所有这些迫使我们修改我们的招聘和入职流程,但将它作为多元化思想的另一个来源被证明是一个成功的战略,并导致了一个强大的人才和机会渠道的创建,通过我们在行业内取得的有意义的成功提升了我们的地位。
对新员工如何融入公司其他部门的担忧,变成了一个例子,说明一家为欢迎各种风格的多样性而成立的公司如何能够轻松地融合来自意想不到背景的人,并发现自己在短期内获得技术和文化上的好处,不仅对他们受雇的特定团队,而且对整个公司都是如此。
多元化的价值已被充分研究和理解。鉴于上述优势以及分析行业及其消费者越来越意识到的关于偏见的特定陷阱,多元化团队已被证明是对这些偏见的有效威慑,这使得多元化必然是行业必须努力改善的领域之一这一结论成为定局。通过分析招聘实践中可能影响少数族裔招聘差距的偏见,从非常规背景中招聘,并将这些实践作为公司增长和创新战略的组成部分,我们不仅将开始理解和缓解这些问题的漫长道路,还将准备好应对和解决这十年不可避免地要面临的道德、问责和隐私挑战。在她为 2019 年最具影响力的 10 位女性领导人所做的简介中,阿尼玛·阿南德·库玛(Anima Anandkumar)对这一概念给予了肯定:“我希望这是人工智能革命的开始,它促进了多样性和包容性。我坚信这将是我们开发更好的人工智能技术的关键因素,这些技术可以促进公平性、可解释性、透明度和鲁棒性。”
模糊推理系统的 Python 实现
“一个故事在远处听起来总是很清楚,但你越靠近事件现场,它就变得越模糊。”― 乔治·奥威尔
照片由卡梅尔·加法拍摄
介绍
在以前的文章中,我们讨论了模糊集和模糊推理的基础。该报告还说明了使用模糊推理方法构建可能的控制应用程序。在本文中,我们将使用 Python 编程语言构建一个多输入/多输出模糊推理系统。假设读者对模糊推理有清晰的理解,并且已经阅读了前面提到的文章。
本文列出的所有代码都可以在 Github 上获得。
系统结构
下图说明了应用程序的结构。该设计基于对模糊推理系统的几个考虑,一些是:
- 模糊推理系统需要输入和输出变量以及一组模糊规则。
- 如果模糊推理系统是 Mamdani 类型的,则输入和输出变量都将包含模糊集的集合。
- 输入和输出变量非常相似,但是它们被模糊规则不同地使用。在执行过程中,输入变量使用系统的输入值来模糊化它们的集合,也就是说,它们确定该输入值属于变量的所有模糊集合的程度。每个规则在一定程度上对输出变量有贡献;这种贡献的总和将决定系统的输出。
- 模糊规则具有以下形式的结构:
**if** {antecedent clauses} **then** {consequent clauses}
因此,一个规则将包含几个先行类型的子句和一些结果类型的子句。条款将采用以下形式:
{variable name} **is** {set name}
系统图
我们将在以下部分讨论为该系统开发的类的一些实现细节:
模糊集类
模糊集 需要以下参数才能启动:
- 名称— 集合的名称
- 最小值— 集合的最小值
- 最大值— 集合的最大值
- 分辨率— 最小值和最大值之间的步数
因此,有可能通过使用两个 numpy 数组来表示模糊集;一个保存域值,另一个保存隶属度值。最初,所有隶属度值都将被设置为零。可以认为,如果最小值和最大值以及集合的分辨率可用,则不需要域 numpy 数组,因为可以计算相应的值。虽然这是完全正确的,但是在这个示例项目中,域数组是首选的,这样代码更加易读和简单。
模糊集初始化
在模糊变量的上下文中,所有集合将具有相同的最小值、最大值和分辨率值。
当我们处理一个离散化的域时,有必要将用于设置或检索隶属度的任何值调整为域数组中最接近的值。
模糊集域值调整
该类包含一些方法,通过这些方法,可以在给定相应数量的参数的情况下构造一组给定的形状。例如,在三角形集合的情况下,提供三个参数,两个定义集合的范围,一个定义顶点。通过使用这三个参数可以构建一个三角形集合,如下图所示。
三角模糊集方程
因为集合是基于 numpy 数组的,所以上面的等式可以直接转换成代码,如下所示。可以使用类似的方法构建具有不同形状的集合。
三角形集合创建
FuzzySet 类还包含联合、交集和非运算符,这些运算符是进行推理所必需的。所有运算符方法都返回一个新的模糊集,其中包含所发生运算的结果。
两个模糊集对象的并集
最后,我们实现了使用重心法从模糊集获得清晰结果的能力,这在上一篇文章中有详细介绍。值得一提的是,文献中有大量的去模糊化方法。尽管如此,由于重心法非常流行,所以在这个实现中使用了它。
重心去模糊化
模糊可变类
模糊可变类
如前所述,变量可以是输入或输出类型,其不同会影响模糊推理计算。 模糊变量 是保存在 python 字典中的集合的集合,该字典以集合名作为关键字。有一些方法可以将模糊集添加到变量中,这些模糊集将接受变量的限制和分辨率。
对于输入变量,通过检索给定域值的变量中所有集合的隶属度来进行模糊化。隶属度存储在集合中,因为规则在评估时需要它。
输入变量的模糊化
输出变量将最终产生模糊推理迭代的结果。这意味着,对于 Mamdani 类型的系统,正如我们在这里所构建的,输出变量将保存所有规则的模糊贡献的联合,并随后将该结果去模糊化,以获得可以在实际应用中使用的清晰值。
因此,输出变量将需要一个额外的 模糊集 属性来保存该变量的输出分布,其中的贡献是由每个规则产生的,并使用集合联合运算符相加。然后,通过调用输出分布集的重心法可以获得反模糊化结果。
模糊输出变量输出分布及反模糊化方法
模糊规则类
FuzzyClause 类需要两个属性;一个模糊变量和一个模糊集
variable **is** set
可以被创造出来。子句用于实现语句,这些语句可以链接在一起,形成规则的先行部分和后续部分。
当用作先行子句时, FuzzyClause 返回集合的最后一个隶属度值,该值是在模糊化阶段计算的,如前所述。
该规则将使用 min 运算符组合来自各种前提子句的隶属度值,获得规则激活,该规则激活然后与结果子句一起使用,以获得规则对输出变量的贡献。该操作分为两步:
- 使用最小操作符将激活值与结果 模糊集 相结合,这将作为模糊集的隶属度值的阈值。
- 使用联合运算符,将结果 模糊集 与从其他规则获得的 模糊集 组合,获得该变量的输出分布。
模糊子句作为前提或结果的执行方法
因此, 模糊规则 类需要两个属性:
- 包含先行子句和的列表
- 包含结果从句的列表
在执行 模糊规则 的过程中,执行上述程序。 模糊规则 通过适当地利用所有各种 模糊子句 来协调所有任务。
\规则执行
模糊系统类——将所有这些集合在一起。
在这个架构的最顶层,我们有 模糊系统 ,它协调模糊变量和模糊规则之间的所有活动。因此,系统包含输入和输出变量,它们存储在 python 字典中,使用变量名作为关键字和一个规则列表。
此阶段面临的挑战之一是最终用户将用来添加规则的方法,该方法应该理想地抽象出 FuzzyClause 类的实现细节。实现的方法包括提供两个 python 字典,其中包含以下格式的规则的前提和结果子句;
variable name : set name
一种更加用户友好的方法是以字符串的形式提供规则,然后解析该字符串来创建规则,但是对于演示应用程序来说,这似乎是一种不必要的开销。
向模糊系统添加新规则
推理过程的执行可以通过给定这种结构的几行代码来实现,其中执行以下步骤;
- 所有输出变量的输出分布集被清除。
- 系统的输入值被传递给相应的输入变量,以便变量中的每个集合可以确定其对于该输入值的隶属度。
- 模糊规则的执行发生了,这意味着所有输出变量的输出分布集现在将包含来自每个规则的贡献的并集。
- 使用重心去模糊化器对输出分布集进行去模糊化,以获得清晰的结果。
最后要注意的是,这里实现的模糊推理系统包含额外的函数来绘制模糊集和变量,并获取关于推理步骤执行的信息。
图书馆使用示例
在这一节中,我们将讨论模糊推理系统的使用。特别是,我们将实现在本系列的前一篇文章中设计的风扇速度案例研究。
模糊系统首先考虑输入和输出变量,然后设计模糊集来解释这些变量。
变量将需要一个下限和上限,正如我们将要处理的离散模糊集,系统的分辨率。因此,变量定义将如下所示
temp = FuzzyInputVariable('Temperature', 10, 40, 100)
其中变量’温度的范围在 10 到 40 度之间,并在 100 个箱中离散化。
根据变量的形状,为变量定义的模糊集需要不同的参数。例如,在三角形集合的情况下,需要三个参数,两个参数用于隶属度为 0 的上下极值,一个参数用于隶属度为 1 的顶点。因此,变量’温度’的三角形集合定义如下:
temp.add_triangular('Cold', 10, 10, 25)
其中被称为“T2”的集合“冷”在 10 度和 25 度具有极值,在 10 度具有顶点。在我们的系统中,我们考虑了两个输入变量,“T4”温度“T5”和“T6”湿度“T7”,以及一个输出变量“T8”速度“T9”。每个变量由三个模糊集描述。输出变量’速度’的定义如下:
motor_speed = FuzzyOutputVariable('Speed', 0, 100, 100) motor_speed.add_triangular('Slow', 0, 0, 50) motor_speed.add_triangular('Moderate', 10, 50, 90) motor_speed.add_triangular('Fast', 50, 100, 100)
正如我们之前看到的,模糊系统是包含这些变量和模糊规则的实体。因此,必须将变量添加到系统中,如下所示:
system = FuzzySystem()
system.add_input_variable(temp)
system.add_input_variable(humidity)
system.add_output_variable(motor_speed)
模糊规则
一个模糊系统执行模糊规则操作的形式
If x1 is S and x2 is M then y is S
其中,规则的 If 部分包含几个先行子句,then 部分将包含几个结果子句。为了简单起见,我们假设规则要求每个输入变量都有一个 antecedent 子句,并且只通过“and”语句连接在一起。可以用“or”连接语句,语句也可以包含集合上的运算符,如“not”。
向我们的系统添加模糊规则的最简单的方法是提供先行子句和结果子句的列表。一种方法是使用包含以下内容的 python 字典
Variable:Set
条款集的条目。因此,上述规则可以实现如下:
system.add_rule(
{ 'Temperature':'Cold',
'Humidity':'Wet' },{ 'Speed':'Slow'})
系统的执行包括输入所有输入变量的值,并获得输出值的值作为回报。同样,这是通过使用字典来实现的,字典使用变量的名称作为关键字。
output = system.evaluate_output({
'Temperature':18,
'Humidity':60 })
系统将返回一个字典,其中包含作为关键字的输出变量的名称,以及作为值的反模糊结果。
结论
在本文中,我们研究了模糊推理系统的实际实现。虽然这里介绍的库还需要进一步的工作,以便可以在实际项目中使用,包括验证和异常处理,但它可以作为需要模糊推理的项目的基础。还建议看看一些可用的开源项目,特别是 SciPy 的模糊逻辑工具箱 skfuzzy 。
在下一篇文章中,我们将研究从数据集创建模糊系统的方法,以便在机器学习场景中使用模糊逻辑。类似于模糊逻辑概念的介绍,接下来是一篇实用的文章。
使用 Splink 对数亿条记录进行模糊匹配和重复数据删除
支持 Python、PySpark 和 AWS Athena 的快速、准确和可扩展的记录链接
摘要
Splink 是一个用于概率记录链接(实体解析)的 Python 库。它支持使用Apache Spark
、AWS Athena
或DuckDB
后端运行记录链接工作负载。
其主要特点是:
- 它非常快。使用
DuckDB
后端,它能够在两分钟内连接现代笔记本电脑上的一百万条记录。 - 它非常精确,支持词频调整和复杂的模糊匹配逻辑。
- 它能够使用
Spark
或AWS Athena
后端链接非常大的数据集(超过 1 亿条记录)。 - 具有简单但高度可定制的界面,因此用户可以解决大多数记录链接和重复数据删除问题
- 不需要训练数据,因为可以使用无监督的方法来训练模型。
- 支持从探索性分析师到模型预测、诊断和质量保证的数据链接的完整工作流程。
- 是健壮的,有一套自动化的单元和集成测试。
问题陈述
一个常见的数据质量问题是有多个不同的记录引用同一个实体,但没有唯一的标识符将这些实体联系在一起。
例如,客户数据可能已经被多次输入到多个不同的计算机系统中,具有不同的姓名拼写、不同的地址和其他打字错误。缺乏唯一的客户标识符给数据分析的所有阶段带来了挑战,从计算唯一客户的数量等基本问题,到用于机器学习目的的客户详细信息的特征工程。
对这个问题有大量的理论和实证研究。该解决方案通常涉及使用统计估计、机器学习和/或基于规则的逻辑来计算新的唯一标识符列,该唯一标识符列允许实体被链接和分组。
然而,缺乏能够在数百万条记录的规模上解决这个问题的自由软件——这是大型组织中常见的规模。解决这个问题通常需要生成大量的记录比较,因此不适合 R 或 Python 中的内存解决方案。像 Apache Spark 这样的分布式计算框架,或者像 DuckDB 这样并行化且不受内存限制的后端,是更好的选择。
我们发布了一个名为splink
的免费开源库,实现了 fell egi-Sunter/期望最大化方法,这是数据链接文献的关键统计模型之一。这是一种无监督的学习算法,它为每对记录比较产生一个匹配分数。
尝试一下
你可以使用我们的活页夹链接在这里在 Jupyter 笔记本上试试这个图书馆。
这些演示说明了如何使用这个库,但是请注意,它们是在免费服务器上以本地模式运行的,所以不要期望有很好的性能。
您也可以访问我们的文档网站。
它是如何工作的
Splink 是 Fellegi-Sunter 模型的一个实现。该软件使用一种称为阻塞的方法生成成对记录比较,并为每对记录计算匹配分数,量化两个记录之间的相似性。
匹配分数由称为部分匹配权重的参数确定。这些量化了比较的不同方面的重要性。
例如,出生日期匹配比性别匹配更有利于两个记录匹配。邮政编码的不匹配可能提供不匹配的弱证据,因为人们搬家了,而出生日期的不匹配可能是不匹配记录的强有力证据。
这个简单的想法有很大的力量来构建高度微妙的模型。可以为任意数量的用户定义的场景计算部分匹配权重,而不仅仅是匹配或不匹配。例如,对于邮政编码不匹配但彼此相距在 10 英里以内的情况,可以估计部分匹配权重。
这些部分匹配权重被组合成一个总匹配分数,该分数表示两个记录匹配的证据的权重。
该库使用无监督学习(期望最大化算法)来估计这些匹配权重。你可以在我的互动培训材料中了解更多关于理论的内容。
关于这一切如何工作的更详细的视频描述可以在这里找到。
Splink 的一些图形输出
样本代码
我们试图设计一个简单的界面,但仍然可以适应大多数记录链接和重复数据删除问题。
在下面的代码中,我们:
- 指定数据链接模型
- 估计它的参数
- 使用该模型计算成对匹配分数
- 将匹配分数分组以产生估计的唯一个人 id
from splink.duckdb.duckdb_linker import DuckDBLinker
from splink.duckdb.duckdb_comparison_library import (
exact_match,
levenshtein_at_thresholds,
)
import pandas as pd
df = pd.read_csv("./tests/datasets/fake_1000_from_splink_demos.csv")
*# Specify a data linkage model*
settings = {
"link_type": "dedupe_only",
"blocking_rules_to_generate_predictions": [
"l.first_name = r.first_name",
"l.surname = r.surname",
],
"comparisons": [
levenshtein_at_thresholds("first_name", 2),
exact_match("surname"),
exact_match("dob"),
exact_match("city", term_frequency_adjustments=True),
exact_match("email"),
],
}
linker = DuckDBLinker(df, settings)
*# Estimate its parameters*
linker.estimate_u_using_random_sampling(target_rows=1e6)
blocking_rule_for_training = "l.first_name = r.first_name and l.surname = r.surname"
linker.estimate_parameters_using_expectation_maximisation(blocking_rule_for_training)
blocking_rule_for_training = "l.dob = r.dob"
linker.estimate_parameters_using_expectation_maximisation(blocking_rule_for_training)
*# Use the model to compute pairwise match scores*
pairwise_predictions = linker.predict()
*# Cluster the match scores into groups to produce an estimated unique person id*
clusters = linker.cluster_pairwise_predictions_at_threshold(pairwise_predictions, 0.95)
clusters.as_pandas_dataframe(limit=5)
反馈
我们感谢所有做出贡献并提供反馈的用户。请通过以下方式继续这样做:
或者我是推特上的 @robinlinacre 。
基于机器学习的模糊姓名匹配
用于语义名称匹配的堆叠语音算法、字符串度量和字符嵌入
在 GitHub 上查看完整代码
由 Thom Masat 在 Unsplash 上拍摄的照片
在处理外部数据时,通常情况下不存在一个公共标识符,如数字键。代替唯一标识符,一个人的全名可以用作链接数据的通用或复合密钥的一部分,但是,这不是一个万无一失的解决方案。
让我们以名字 艾伦图灵 为例;不同的数据源可能已经记录了呼叫名字。数据录入可能会无意中记录:艾伦、艾伦,或者更糟,未被发现的错别字( Alam Turing )到他们的数据库中。企业文档扫描解决方案(OCR)也充斥着误读。
通过应用软逻辑来近似拼写和语音(声音)特征的认知过程,人类代理可以直观地将这些变化分配给艾伦·图灵的同一实体。通常简称为的伪君子并不总是具有这些特征,而是代理人习得联想的一部分,即 Charles → Chip 。
接下来的研究是应用机器学习来实现替代名称识别的类人逻辑和语义的外观。
数据收集
我搜集了许多名字的常用替代拼法,大约有 17500 对。这些名字被限制为 ASCII 码,并包括许多 Unicode 编码的跨文化例子,以避免过度适应西方的命名惯例。
使用名字作为我们的模型的核心数据的直觉是在名字成分上集成集成方法,要求姓氏的精确或语音匹配,以确保更高的精确度/更少的误报,代价是一些回忆。
我决定使类不平衡(1:4 ),因为对负类的欠采样会导致对正类的明显的人为偏向。很难近似每一类的先验概率,但是假设这些类是不平衡的,有利于负类。
特征选择
有许多字符串度量和语音算法可用作特征,基本级别模型使用 20 多种特征,包括:
- 莱文斯坦距离
- 二元模型相似性
- Jaro 距离
- 编辑距离
- Soundex 编码
字符嵌入
深层的 LSTM 暹罗网络已经被证明在学习文本相似性方面是有效的。我使用 TensorFlow 在名字对上训练这些网络,并使用非折叠预测作为元模型的一个特征。
深层架构包括一个字符嵌入层,后面是一个 biLSTM 和能量损耗层。
原始变换
名称可以被转换,以帮助我们的模型从相同的数据中学习新的模式。转换包括:
- 将名称分割成音节以获得有意义的多记号串度量(例如,来自 fuzzywuzzy 包的记号排序和记号集)
- 移除高频名称结尾
- 去除元音
- 转换为国际音标
模型结构
我使用 AutoML 软件包 TPOT 来帮助选择一个优化的管道和超参数,以 F1 作为评分标准。
基本模型和字符嵌入网络通过分层 10 折交叉验证进行堆叠,以训练一个逻辑回归元模型。基础模型中的一些特性被包含进来,为元模型提供额外的上下文和维度。网格搜索用于选择最佳参数和特征,优先考虑精度。
估价
国际备选名测试集的评估指标:
这个模型是专门训练来处理替代名称的,但也能很好地正确分类所有上述变体,包括印刷错误。
所用的方法和由此产生的模型从此被戏称为 HMNI(你好我的名字是)。我已经开源了这个项目(处于测试阶段),作为一个 Python 包,使用了相同的名字。
如何在你的项目中使用 HMNI
通过 PyPI 使用 PIP 安装
pip install hmni
快速使用指南—配对相似性、记录关联、重复数据删除和标准化
更多即将推出……
我会在HMNI 的未来版本中更新这篇文章;包括最佳性能模型、特定语言配置和数据处理优化。
来自数据的模糊系统
从传感器信息中生成人类可读的知识
介绍
模糊逻辑理论引入了一个框架,通过这个框架,人类的知识可以被形式化,并由机器在从相机到火车的各种应用中使用。我们在以前的帖子中讨论的基本思想只涉及到使用基于模糊逻辑的系统的这一方面;这是人类经验在机器驱动的应用中的应用。虽然有许多这样的技术相关的例子;也有一些应用程序,在这些应用程序中,人类用户很难清楚地表达他们所掌握的知识。这些应用包括驾驶汽车或识别图像。机器学习技术在这种情况下提供了一个极好的平台,在这种情况下,输入和相应的输出集合是可用的,建立一个模型,使用可用的数据提供从输入数据到输出的转换。
在这篇文章中,我们将讨论一种算法,这种算法是由李教授和 Jerry Mendel 教授提出的从数据中构造模糊系统。这种技术和类似技术的一个令人兴奋的方面是能够从数据中以模糊集和规则的形式获得人类容易理解的知识。
程序
正如我们在简介中所解释的,本练习的目标是,给定一组输入/输出组合,我们将生成一个规则集,确定输入和输出之间的映射。在这个讨论中,我们将考虑一个双输入单输出系统。对于读者来说,将这个过程扩展到更复杂的系统应该是一项简单的任务。
步骤 1-将输入和输出空间划分为模糊区域。
我们首先给每个输入和输出空间分配一些模糊集。王和孟德尔指定了奇数个均匀间隔的模糊区域,由 2N+1 决定,其中 N 为整数。正如我们将在后面看到的, N 的值会影响我们模型的性能,有时会导致欠拟合/过拟合。 N 因此是我们用来调整该系统性能的超参数之一。
将输入空间划分成模糊区域,其中 N=2
第二步——从数据中生成模糊规则。
我们可以使用我们的输入和输出空间,以及我们刚刚定义的模糊区域和应用程序的数据集来生成以下形式的模糊规则:
**If** {antecedent clauses} **then** {consequent clauses}
我们首先确定数据集中每个样本对该空间中不同模糊区域的隶属度。例如,我们考虑下面描述的一个例子:
科雷斯
我们获得以下隶属度值。
样本 1 的隶属度值
然后,我们将具有最大隶属度的区域分配给空间,这由上表中突出显示的元素表示,以便可以获得一个规则:
sample 1 => **If** x1 is b1 and x2 is s1 **then** y is ce => Rule 1
下图显示了第二个示例,以及它生成的隶属度结果。
因此,该示例将产生以下规则:
sample 2=> **If** x1 is b1 **and** x2 is ce **then** y is b1 => Rule 2
步骤 3-为每个规则分配一个等级。
步骤 2 实现起来非常简单,但是它有一个问题;它将生成冲突的规则,即具有相同的前置子句但不同的后置子句的规则。Wang 和 Medel 通过给每个规则分配一个度来解决这个问题,使用乘积策略,使得度是来自形成规则的前件和后件空间的所有隶属度值的乘积。我们保留具有最重要程度的规则,而我们丢弃具有相同前提但具有较小程度的规则。
如果我们参考前面的例子,规则 1 的度数将等于:
对于规则 2,我们得到:
我们注意到,这个过程在实践中极大地减少了规则的数量。
还可以通过将人的因素引入到规则程度来将人的知识融合到从数据获得的知识中,这在实践中具有很高的适用性,因为人的监督可以评估数据的可靠性,因此可以直接从数据中生成规则。在不需要人工干预的情况下,对于所有规则,该因子都设置为 1。因此,规则 1 可以定义如下:
步骤 4-创建一个组合模糊规则库
组合模糊规则库的概念在之前的文章中已经讨论过了。它是一个矩阵,保存系统的模糊规则库信息。组合的模糊规则库可以包含使用上述过程以数字方式生成的规则,也可以包含从人类经验中获得的规则。
本系统的组合模糊规则库。注意规则 1 和规则 2。
步骤 5-基于组合的模糊规则库确定映射。
该过程的最后一步解释了用于确定给定的 y,(x1,x2)的值的去模糊化策略。王和孟德尔提出了一种不同于马姆达尼使用的最大最小计算方法。我们必须考虑到,在实际应用中,与通常使用模糊逻辑的典型控制应用相比,输入空间的数量是很大的。此外,此过程将生成大量规则,因此使用“正常”方法计算输出是不切实际的。
对于给定的输入组合(x1,x2),我们结合给定规则的前件,使用乘积运算符确定对应于(x1,x2)的输出控制程度。如果
是第 I 条规则的输出控制程度,
因此对于规则 1
**If** x1 is b1 and x2 is s1 **then** y is ce
我们现在将模糊区域的中心定义为在该区域的隶属函数等于 1 的所有点中具有最小绝对值的点,如下所示;
模糊区域的中心
因此,给定(x1,x2)组合的 y 值为
其中 K 是规则数。
测试
用 Python 开发了上述算法的一个(非常脏的)实现,用真实数据集进行测试。使用的代码和数据可以在 Github 中找到。对该系统的一些考虑包括。
- 模糊系统直接由测试数据生成。
- 这些集合是使用原始论文中的建议创建的,即均匀分布。然而,有趣的是看到改变这种方法的效果。一种想法是围绕数据集平均值创建集合,其分布与标准差相关,这可能会在未来的帖子中进行调查。
- 所创建的系统没有隐式地迎合分类数据,这是将来的改进,可以在现实生活场景中相当大地影响系统的性能。
测试指标
我们将使用决定系数(R 平方)来评估该系统的性能,并调整被识别的超参数,即生成的模糊集的数量。
要解释 R-Squared,首先要定义平方和 total 和平方和残差。
平方和总和是因变量(y)和观察到的因变量平均值之间的平方差总和。
残差平方和是因变量的实际值和估计值之差的平方和。
r 平方可以通过下式计算
我们注意到 R 平方的值在 0 和 1 之间,越大越好。如果 R 平方=1,则没有误差,估计值将等于实际值。
案例研究 1——噪声传感器
我们用一个简单的应用程序开始测试这个过程;一个单输入单输出系统,代表一个具有指数响应的假想传感器。让事情变得复杂一点,我们在传感器数据中添加了一些噪声,如下图所示:
我们首先检查 x 和 y 的 N 的不同值的各种结果。下图显示了在搜索最佳值的过程中获得的结果。
当 N_x 设置为 4,N_y 设置为 3 时,获得最佳响应,R 平方值为 0.985。由该系统生成的规则是特别令人感兴趣的,因为它们可以以容易理解的方式解释该系统如何工作;
If x is s4 then Y is s3
If x is s3 then Y is s3
If x is s2 then Y is s3
If x is s1 then Y is s3
If x is ce then Y is s2
If x is b1 then Y is s2
If x is b2 then Y is s1
If x is b3 then Y is ce
If x is b4 then Y is b3
我们注意到显示指数性质的系统的特征被清楚地解释。对于所有小的输入值,输出值保持最小,随着输入值的进一步增加,输出值迅速增加。
系统也容易出现过拟合,例如 N_x=5 和 N_y=2。
案例研究 2 —温度
对于第二个测试,我们使用了 2006-2016 年 Szeged 的天气。该数据集包含超过 96,000 个由 12 个特征组成的训练示例。
Formatted Date object
Summary object
Precip Type object
Temperature (C) float64
Apparent Temperature (C) float64
Humidity float64
Wind Speed (km/h) float64
Wind Bearing (degrees) float64
Visibility (km) float64
Loud Cover float64
Pressure (millibars) float64
Daily Summary object
在这个练习中,我们将放弃这些特征中的大部分,并评估我们是否可以预测给定月份的温度和湿度。
在检查数据时,我们注意到平均温度在 1 到 23 摄氏度之间变化,每月变化约 20 度。
平均湿度在 0.63 和 0.85 之间变化,但我们也注意到它总是可能达到 100%,与月份无关。
被测试的最佳模糊系统由用于输入变量的 3 个模糊空间( N =1)和用于温度的 9 个模糊空间( N =4)组成。系统生成了下面的模糊分布图中描述的九条规则,并使用 20%的测试样本获得了 0.75 的 R 平方值。
结论
上述系统从数据中产生人类可读的规则,可以帮助我们获得对复杂系统的洞察力。以下是对未来工作的几点看法和想法:
- 该系统需要一个相当大的数据集,需要覆盖所有可能产生的规则。因此,随着要素数量的增加,需要更大的数据集,因为所需的规则数量将呈指数增长。
- 也许可以通过检查相邻的规则来生成缺失的规则。如果一个不存在的规则可以在一个由相同的输出空间包围的组合模糊规则库中被说明,则该规则可能属于相同的空间。这一想法将在未来得到检验。
- 模糊空间的分布影响系统的性能,尽管像标准化和规范化这样的预处理有助于限制数据分布对系统的影响。
- 必须调查手工制定的规则的影响。验证人类经验是否真的可以增强机器生成系统的性能是一件有趣的事情。
- 检查负责规则的数据并使用信息来确定为什么测试样本会产生重大错误也是很有趣的。
FuzzyWuzzy:用 Python 在一列中查找相似的字符串
马特&克里斯·普阿在 Unsplash 上的照片
令牌排序比率与令牌集比率
使数据变脏的方法有很多种,数据录入不一致就是其中之一。不一致的值比重复的值更糟糕,有时很难检测到。本文介绍了我如何应用 FuzzyWuzzy 包在一个拉面评论数据集中查找相似的拉面品牌名称(完整的 Jupyter 笔记本可以在我的 GitHub 中找到)。你也可以在这里找到缩短代码的函数。
数据
import pandas as pd
import numpy as np
from fuzzywuzzy import process, fuzzramen = pd.read_excel('The-Ramen-Rater-The-Big-List-1-3400-Current- As-Of-Jan-25-2020.xlsx')
ramen.head()
数据集的前几行
ramen.info()**<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3400 entries, 0 to 3399
Data columns (total 6 columns):
Review # 3400 non-null int64
Brand 3400 non-null object
Variety 3400 non-null object
Style 3400 non-null object
Country 3400 non-null object
Stars 3400 non-null object
dtypes: int64(1), object(5)
memory usage: 159.5+ KB**
这个数据集非常简单,容易理解。在搬到 FuzzyWuzzy 之前,我想再核实一些信息。首先,我删除了每一列中的前导空格和尾随空格(如果有的话),然后打印出它们的唯一值的数量。
for col in ramen[['Brand','Variety','Style','Country']]:
ramen[col] = ramen[col].str.strip()
print('Number of unique values in ' + str(col) +': ' + str(ramen[col].nunique()))**Number of unique values in Brand: 499
Number of unique values in Variety: 3170
Number of unique values in Style: 8
Number of unique values in Country: 48**
通过对独特的品牌名称进行排序,可以看出是否有相似的。结果只显示前 20 个品牌。
unique_brand = ramen['Brand'].unique().tolist()
sorted(unique_brand)[:20]**['1 To 3 Noodles',
'7 Select',
'7 Select/Nissin',
'7-Eleven / Nissin',
'A-One',
'A-Sha',
'A-Sha Dry Noodle',
'A1',
'ABC',
'Acecook',
'Adabi',
'Ah Lai',
'Aji-no-men',
'Ajinatori',
'Ajinomoto',
'Alhami',
'Amianda',
'Amino',
"Annie Chun's",
'Aroi']**
我们可以在一开始就看到一些可疑的名字。接下来,让我们用 FuzzyWuzzy 做一些测试。
快速模糊测试
FuzzyWuzzy 有四个记分员选项来查找两个字符串之间的 Levenshtein 距离。在本例中,我将检查标记排序比率和标记集比率,因为我认为它们更适合这个可能有混合单词顺序和重复单词的数据集。
我挑选了四个品牌名称,并在品牌栏中找到了它们相似的名称。因为我们将 Brand 列与其自身进行匹配,所以结果将始终包括得分为 100 的所选名称。
令牌排序比率
token sort ratio scorer 对字符串进行标记化,并通过将这些字符串还原为小写字母、删除标点符号,然后按字母顺序排序来清理它们。之后,它会找到 Levenshtein 距离并返回相似度百分比。
process.extract('7 Select', unique_brand, scorer=fuzz.token_sort_ratio)**[('7 Select', 100),
('7 Select/Nissin', 70),
('Jinbo Selection', 61),
('Seven & I', 53),
('Lele', 50)]**
这个结果意味着 7 Select/Nissin 在参考 7 Select 时有 70%的相似度。如果我将阈值设置为 70%以获得 7 Select-7 Select/Nissin 对,这还不错。
process.extract('A-Sha', unique_brand, scorer=fuzz.token_sort_ratio)**[('A-Sha', 100), ('Shan', 67), ('Nasoya', 55), ('Alhami', 55), ('Ah Lai', 55)]**
低于 70%就不是阿沙的对手了。
process.extract('Acecook', unique_brand, scorer=fuzz.token_sort_ratio)**[('Acecook', 100),
('Vina Acecook', 74),
('Yatekomo', 53),
('Sahmyook', 53),
('Panco', 50)]**
仍然擅长 70%的阈值。
process.extract("Chef Nic's Noodles", unique_brand, scorer=fuzz.token_sort_ratio)**[("Chef Nic's Noodles", 100),
("Mr. Lee's Noodles", 71),
('Fantastic Noodles', 69),
('1 To 3 Noodles', 62),
("Mom's Dry Noodle", 59)]**
现在,我们有一个问题。如果我设置 70%的阈值,令牌排序比率计分器将得到错误的一对厨师 Nic 的面条-李先生的面条。
process.extract('Chorip Dong', unique_brand, scorer=fuzz.token_sort_ratio)**[('Chorip Dong', 100),
('ChoripDong', 95),
('Hi-Myon', 56),
('Mr. Udon', 56),
('Maison de Coree', 54)]**
这个看起来足够好了。
令牌集比率
标记集比率计分器还对字符串进行标记化,并遵循与标记排序比率一样的处理步骤。然后,它收集两个字符串之间的公共标记,并执行成对比较以找到相似性百分比。
process.extract('7 Select', unique_brand, scorer=fuzz.token_set_ratio)**[('7 Select', 100),
('7 Select/Nissin', 100),
('The Ramen Rater Select', 86),
('Jinbo Selection', 61),
('Seven & I', 53)]**
由于令牌集比例更加灵活,7 Select — 7 Select/Nissin 的分数从 70%提高到了 100%。
process.extract('A-Sha', unique_brand, scorer=fuzz.token_set_ratio)**[('A-Sha', 100),
('A-Sha Dry Noodle', 100),
('Shan', 67),
('Nasoya', 55),
('Alhami', 55)]**
现在我们看到阿沙还有另外一个名字叫阿沙挂面。而我们只有通过使用令牌集比率才能看到这一点。
process.extract('Acecook', unique_brand, scorer=fuzz.token_set_ratio)**[('Acecook', 100),
('Vina Acecook', 100),
('Yatekomo', 53),
('Sahmyook', 53),
('Panco', 50)]**
这一个得到 100%就像 7 选择的情况。
process.extract("Chef Nic's Noodles", unique_brand, scorer=fuzz.token_set_ratio)**[("Chef Nic's Noodles", 100),
('S&S', 100),
('Mr. Noodles', 82),
("Mr. Lee's Noodles", 72),
('Tseng Noodles', 70)]**
当 Nic 主厨的面条 S&S 的令牌集比率返回 100%时,情况会变得更糟。
process.extract('Chorip Dong', unique_brand, scorer=fuzz.token_set_ratio)**[('Chorip Dong', 100),
('ChoripDong', 95),
('Hi-Myon', 56),
('Mr. Udon', 56),
('Maison de Coree', 54)]**
我们对这个有相同的结果。
尽管标记集比率比标记排序比率更灵活,并且可以检测到更多的相似字符串,但它也可能会带来更多的错误匹配。
应用 FuzzyWuzzy
在这一部分中,我首先使用了 token sort ratio,并创建了一个表来显示品牌名称、它们的相似性以及它们的得分。
*#Create tuples of brand names, matched brand names, and the score*
score_sort = [(x,) + i
for x in unique_brand
for i in process.extract(x, unique_brand, scorer=fuzz.token_sort_ratio)]*#Create a dataframe from the tuples*
similarity_sort = pd.DataFrame(score_sort, columns=['brand_sort','match_sort','score_sort'])
similarity_sort.head()
数据帧的第一行
因为我们在同一列中寻找匹配的值,所以一个值对会有另一个顺序相反的相同值对。例如,我们会找到一对江户包—高户,和另一对高户—江户包。为了稍后消除其中一个,我们需要为相同的对找到“代表”值。
similarity_sort['sorted_brand_sort'] = np.minimum(similarity_sort['brand_sort'], similarity_sort['match_sort'])similarity_sort.head()
基于上面的测试,我只关心那些至少有 80%相似度的配对。我也排除那些与自己匹配的(品牌价值和匹配价值完全相同)和那些重复的配对。
high_score_sort =
similarity_sort[(similarity_sort['score_sort'] >= 80) &
(similarity_sort['brand_sort'] != similarity_sort['match_sort']) &
(similarity_sort['sorted_brand_sort'] != similarity_sort['match_sort'])]high_score_sort = high_score_sort.drop('sorted_brand_sort',axis=1).copy()
现在,让我们看看结果。
high_score_sort.groupby(['brand_sort','score_sort']).agg(
{'match_sort': ', '.join}).sort_values(
['score_sort'], ascending=False)
使用令牌排序比的模糊匹配
从 95 分及以上的分数来看,一切都很好。在每一对中,这两个值可能有拼写错误、缺少一个字符或格式不一致,但总体来说,它们显然是相互引用的。低于 95 就不好说了。我们可以通过列出每一对的数据来看一些例子。
*#Souper - Super - 91%*
ramen[(ramen['Brand'] == 'Souper') | (ramen['Brand'] == 'Super')].sort_values(['Brand'])
汤和超级
对于这一对,我们看到这两个品牌来自不同的制造商/国家,他们的拉面类型或风格也没有相似之处。我会说这些品牌不一样。
*#Ped Chef - Red Chef - 88%*
ramen[(ramen['Brand'] == 'Ped Chef') | (ramen['Brand'] == 'Red Chef')].sort_values(['Brand'])
Ped 厨师和 Red 厨师
在这里,我们只有 Ped Chef 品牌的一个记录,我们也在它的品种名称中看到了与 Red Chef 品牌相同的模式。我很确定这两个牌子是一样的。
对于像这样的小数据集,我们可以通过相同的方法继续检查其他对。从 84%及以下的阈值开始,我们可以忽略一些明显不同的对,或者我们可以如上快速检查。
要应用令牌集比率,我可以只重复相同的步骤;这部分可以在我的 Github 上找到。
令牌排序比率与令牌集比率
比较结果包括姓名、使用标记排序比和标记集比的匹配以及相应的分数。
这不是完整的数据集
现在我们可以看到两个得分手之间有多么不同。不出所料,记号集比率匹配高分数的错误名字(例如 S&S,面条先生)。然而,与令牌排序比相比,它确实带来了更多的匹配(例如 7 Select/Nissin、Sugakiya Foods、Vina Acecook)。这意味着要得到最多的匹配,应该使用两个记分员。
以你的拉面知识和模糊的思维,你能挑出任何正确的搭配吗?
FuzzyWuzzy:Python 中的模糊字符串匹配,初学者指南
以及在真实世界数据集上的实践
介绍
如果您以前处理过文本数据,您会知道它的问题是最难处理的。对于文本问题,没有一个放之四海而皆准的解决方案,对于每个数据集,你必须想出新的方法来清理你的数据。在我之前的一篇文章中,我谈到了这类问题的最坏情况:
例如,考虑这种最坏的情况:您正在处理一个在美国进行的调查数据,数据集中每个观察的状态都有一个 state 列。美国有 50 个州,想象一下人们能想出的各种州名。如果数据收集者决定使用缩写:ca,Ca,CA,Caliphornia,Californa,California,calipornia,calipornia,CAL,CALI,你的问题就更大了……这样的栏目总是充满了错别字、错误和不一致。
由于数据收集过程中的自由文本,经常会出现与文本相关的问题。它们将充满错别字,不一致,无论你能说出什么。当然,最基本的问题可以使用简单的正则表达式或内置的 Python 函数来解决,但是对于上面这种经常发生的情况,您必须用更复杂的工具来武装自己。
今天的特色是fuzzywuzzy
,这是一个带有非常简单的 API 的包,可以帮助我们计算字符串相似度。
[## 通过我的推荐链接加入 Medium-BEXGBoost
获得独家访问我的所有⚡premium⚡内容和所有媒体没有限制。支持我的工作,给我买一个…
ibexorigin.medium.com](https://ibexorigin.medium.com/membership)
获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:
留在循环中,不用花无数时间浏览下一个突破;我们的算法识别…
alphasignal.ai](https://alphasignal.ai/?referrer=Bex)
设置
字符串匹配是如何执行的
为了理解字符串匹配,让我们用最小编辑距离来帮助您加快速度。作为人类,如果两个或更多的字符串相似或不相似,我们没有任何问题。为了在计算机中创造这种能力,人们创造了许多算法,几乎所有的算法都依赖于最小编辑距离。
最小编辑距离(MED)是从一个字符串过渡到另一个字符串所需的最少可能的步数。MED 仅使用 4 种运算来计算:
- 插入
- 删除
- 代替
- 替换连续字符
考虑这两个词:程序和声谱图:
图片由 作者
从程序到声谱图,我们需要 3 个步骤:
- 在“Program”的开头加上字母“S”。
- 用 O 代替 P。
- 用 N 代替 R。
最小编辑距离为 3。图片由 作者 提供。
我说过,有很多算法可以计算 MED:
- 达默劳-莱文斯坦
- 莱文斯坦
- 加重平均
- Jaro 距离
此外,还有使用这些算法的软件包:nltk
、fuzzywuzzy
、textdistance
、difflib
,…
在本文中,我们将只涉及fuzzywuzzy
。
模糊不清:安装
尽管使用pip
可以轻松完成基本安装,但对于fuzzwuzzy
的安装还有一些其他选项或注意事项:
- 通过 PyPI 使用 PIP(标准):
pip install fuzzywuzzy
上述方法安装软件包的默认最新版本。起初,我用这种方法安装它。但是每当我导入它的时候,它就开始给出警告,说这个包本身很慢,我应该安装python-Levenshtein
包来加快速度。如果你像我一样讨厌 Jupyter 笔记本上的警告,下面是你安装额外依赖项的方法:
- 直接安装
python-Levenshtein
:
pip install python-Levenshtein
或者
pip install fuzzywuzzy[speedup]
对 Windows 用户的警告:如果没有安装 Microsoft Visual Studio 构建工具,安装python-Levenshtein
会失败。你可以从这里下载 MVS 构建工具。
FuzzyWuzzy:WRatio 的基础
为了从fuzzywuzzy
开始,我们首先导入fuzz
子模块:
from fuzzywuzzy import fuzz
在这个子模块中,有 5 个函数用于两个字符串之间不同的比较方法。日常使用最灵活最好的是WRatio
(加权比率)功能:
在这里,我们将“Python”与“Cython”进行比较。输出返回 0 到 100 之间的百分比,0 表示完全不相似,100 表示完全相同:
fuzzywuzzy
的所有函数都不区分大小写:
WRatio
对于不同排序的部分字符串也很好:
模糊:不同方法的比较
除了WRatio
之外,还有 4 个函数可以计算字符串相似度:
- 模糊比率
- 模糊.部分 _ 比率
- fuzz.token_sort_ratio
- fuzz.token_set_ratio
fuzz.ratio
非常适合长度和顺序相似的字符串:
对于不同长度的字符串,最好使用“fuzz.patial_ratio”:
如果字符串含义相同,但顺序不同,使用fuzz.token_sort_ratio
:
更多边缘情况,有fuzz.token_set_ratio
:
如你所见,这 5 个函数充满了警告。他们的比较完全是另一个话题,所以我给你留了一个由软件包创建者写的文章的链接,这篇文章很好地解释了他们的区别。
我想你已经看到了
WRatio
函数为fuzzywuzzy
的所有函数提供了中间基础。对于许多边缘情况和不同问题,最好使用WRatio
以获得最佳效果。
使用fuzzywuzzy.process
从选项列表中提取字符串的最佳匹配
现在我们对fuzzywuzzy
的不同功能有了一些了解,我们可以继续处理更复杂的问题。对于现实生活中的数据,大多数时候您必须从选项列表中找到与您的字符串最相似的值。考虑这个例子:
我们必须找到与Mercedez-Benz
最匹配的,用汽车的正确拼法替换它们。我们可以对每个值进行循环,但是如果有数百万个选项可供选择,这样的过程会花费很长时间。由于这个操作非常常用,fuzzywuzzy
为我们提供了一个有用的子模块:
from fuzzywuzzy import process
使用这个子模块,您可以从一系列字符串中提取与您的字符串最匹配的内容。让我们解决我们最初的问题:
process.extract
中感兴趣的参数有query
、choices
和limit
。该函数根据choices
中给出的一系列选项计算query
中给出的字符串的相似度,并返回一个元组列表。limit
控制返回的元组数量。每个元组包含两个元素,第一个是匹配字符串,第二个是相似性得分。
在引擎盖下,process.extract
使用默认的WRatio
功能。但是,根据您的情况和了解 5 个功能之间的差异,您可以使用scorer
更改评分功能:
如果你有很多选择,最好坚持使用WRatio
,因为它最灵活。
在process
模块中,有其他功能执行类似的操作。process.extractOne
仅返回一个包含最高匹配分数的字符串的输出:
真实数据集上的模糊文本清理
现在我们准备解决一个现实世界的问题。我将加载原始数据进行练习:
cars.shape(8504, 4)
我在我的一个个人项目中使用了这个数据集,任务是根据另一个文件中给出的正确值来纠正每个车辆品牌和型号的拼写:
加载 pickle 文件后,make_model
现在是一个字典,包含每个汽车品牌的正确拼写和每个关键字下的车型的正确拼写。
例如,让我们看看Toyota
汽车品牌和型号的拼法:
现在,让我们对Toyota
汽车的原始数据进行子集划分:
>>> cars[cars['vehicle_make'] == 'TOYOTA']
该数据集包含多达 100 个独特的汽车品牌,如奥迪、宾利、宝马,每一个都包含几个充满边缘案例的模型。我们不能把每一个都转换成大写或小写。我们也不知道这些是否包含任何拼写错误或不一致,视觉搜索对于这样的大数据集不是一个选项。也有一些情况下,使用多于一个单词的 make 标签用一个space
来分隔名称,而其他标签用一个dash
来分隔名称。如果有这么多的不一致,并且没有一个清晰的模式,请使用字符串匹配。
让我们从清理标签开始。为了便于比较,以下是两个数据集中的制作标签:
我认为差异是显而易见的。我们将使用process.extract
将每个品牌与正确的拼写相匹配:
如您所见,存在于make_model
中的品牌标签被转换成了正确的拼写。现在,是时候给模特贴标签了:
最后两个代码片段有点吓人。为了充分理解它们是如何工作的,你应该在
process.extract
上做一些练习。
这就对了。如果你不知道字符串匹配,这个任务就不可能完成,甚至正则表达式也不能帮助你。
如果你喜欢这篇文章,请分享并留下反馈。作为一名作家,你的支持对我来说意味着一切!
阅读更多与主题相关的文章:
用 Pandas 清理分类数据
towardsdatascience.com](/master-the-most-hated-task-in-ds-ml-3b9779276d7c) [## 认识熊猫最难的功能,第一部分
掌握 pivot_table()、stack()、unstack()的时机和方式
towardsdatascience.com](/meet-the-hardest-functions-of-pandas-part-i-7d1f74597e92)
牛虻. JL——来自你梦中的纯朱莉娅绘图库
看看朱莉娅对 2020 年统计绘图的最佳选择
(图片由作者提供)
介绍
如果您使用 Julia 的时间很短,您可能会熟悉一个名为 Plots.jl 的绘图库。Plots.jl 是一个简单的库,它通过 Plot()和 scatter()等简单的函数方法为 Plot.ly 和 Matplotlib 等 Python 库提供了端口。虽然这无疑是创建一个全新的用于 Julia 编程语言的库的好方法,但它也存在一些问题。
首先也是最重要的,用 Julia 解释 Python 会产生很多性能问题。从只是简单地导入 Plots.jl 到实际绘制值,Plots.jl 的性能绝对糟糕透顶!除了不是 Julian 之外,很多软件在 Julia 版本中是缺失的,并且很多特性完全被忽略了。虽然 GR 可能是 Plots.jl 最有前途的后端,但它缺少 Pythonic 库可能提供的许多优秀特性。尽管如此,我确实有一篇文章,你可以看看,以提高你的图形 GR 可视化技能。
没错,又是 Julia,我保证 R,Scala,Python 还在这个爱情圈里
towardsdatascience.com](/spruce-up-your-gr-visualizations-in-julia-88a964450a7)
因此,有了 Plots.jl 的这些严重的基本缺陷,很容易理解为什么科学家们在别处寻找 Julia 语言中的伟大的统计可视化。我看到的最好的选择之一是一个叫做
牛虻. jl。
首先,需要注意的是,牛虻与我为其创建的另一个名为 Hone.jl 的库非常相似。这两个库都使用相同的后端 Compose.jl 来在 Julia 中绘制矢量图形。相似之处可能不止于此,但它们之间也有很多关键的差异,例如 Hone 的面向对象和模块化方法与牛虻的根本不一致。尽管如此,牛虻本身确实采用了一种非常有趣的方法,并且与其他绘图库的工作方式非常不同,您可能会从中得出一些相似之处。
为什么用牛虻?
有了这些替代品,而且通常更受 Julia 用户的欢迎,你为什么还要使用牛虻呢?首先,牛虻是朱利安。这当然意味着它不仅速度快,而且非常适合 Julia 语言——这一点对于它的 Plots.jl 对应物来说就不一样了。对我来说,这是一个巨大的优势,因为你不仅不需要处理 Plots.jl 声称的性能问题,而且还变得相对简单。
牛虻的另一个伟大之处是它的开箱即用的交互性。情节本质上是互动的,可以与 Plot.ly 相提并论。这是一个在朱莉娅语言中很少见的概念,所以拥有它对牛虻来说是大胆而独特的。
牛虻简介
牛虻. jl 表面上遵循了大多数 Julia 用户熟悉的简单方法论。我们可以使用 plot()方法创建一个简单的绘图,带有两个关键字参数,X 和 y。
using Gadfly
data = Dict([:X => [5,10,32,31,51,43], :Y => [82, 33, 21, 26, 11, 22]])plot(x=data[:X], y=data[:Y])
(图片由作者提供)
这是事情变得有点不同的地方。在牛虻中,有一个名为“Geom.jl”的导出模块。与其使用单独的方法来创建线图,我们可以简单地使用相同的方法,只是从该模块添加几何图形。
plot(x=rand(10), y=rand(10), Geom.point, Geom.line)
(图片由作者提供)
同样,我们可以添加一个颜色关键字参数来改变几何图形的颜色。
plot(x=data[:X], y=data[:Y], color=data[:Y])
(图片由作者提供)
此外,我们可以使用 Geom.jl 模块中的更多几何图形,例如直方图:
data = Dict(:Location => ["Africa", "Europe", "Africa", "Americas", "Asia", "Europe"],
:Income => [29000, 83000, 56000, 76000, 52000, 46000])plot(x=data[:Income], color=data[:Location], Geom.histogram)
(图片由作者提供)
您还可以使用牛虻快速绘制语法结果,这样可以快速得到如下结果:
plot([sin, cos], 0, 25)
(图片由作者提供)
结论
jl 是一个非常棒的绘图库,它采用了一种有趣的方法来解决我们以前见过的用其他方法解决的问题。在我个人看来,该模块采用的方法使它比许多竞争对手更好用,也更容易使用。最重要的是,它当然是用纯 Julia 编写的,这给了它速度和易用性,这是该语言中类似包无法比拟的。
总的来说,我想说如果你正在用 Julia 语言处理大量的数据,那么牛虻绝对值得一个 Pkg.add()。它将为您提供查看数据的方法,这将大大提高您对 Plots.jl 等工具的理解和分析能力。虽然我肯定会说 Plots.jl 仍然可能有它的位置,而且肯定有它的用途,但我也想暗示牛虻作为朱莉娅梦想的绘图库完全超过了它。
乳腺癌风险的盖尔模型
乳腺癌是全世界女性中诊断最多的癌症,每年有超过 200 万新病例。患者的治疗通常会给妇女及其家人带来巨大的压力。这种疾病的存活率在世界范围内各不相同。晚期和转移性乳腺癌目前无法治愈,而早期诊断的局部癌症有 99%的存活率。因此,早期发现仍然是降低乳腺癌发病率和死亡率的最佳途径。
来源:http://mammalive . net/research/global-breast-cancer-incidence-2018/
成功预防乳腺癌的第一步是了解患者的风险。网上有很多工具,但并不是所有的工具都有高质量的研究支持。在这篇文章中,我展示了 Gail 模型的 Python 实现,该模型允许妇女估计她们在特定时期内患浸润性乳腺癌的风险。
盖尔模型基于乳腺癌筛查研究的数据,该研究涉及超过 280,000 名不同年龄和种族的女性。该工具根据以下个人和家庭信息评估患者的风险:
- 年龄
- 月经开始时的年龄
- 第一次活产婴儿的年龄
- 患乳腺癌的一级亲属人数
- 先前乳房活检的数量
- 活检中存在非典型增生
盖尔模型已经在大规模人群中进行了测试,并已被证明可以提供乳腺癌风险的准确估计,特别是在白人女性中。它也被美国国家乳腺癌研究所以及其他知名机构和医院使用。该模型的源代码可以从癌症流行病学和遗传学分部网站获得。然而,它们只提供了 R 和 SAS 宏实现,这对于所有 Python 爱好者来说都是一个遗憾。
因此,我把最新版本的 BRCA 包翻译成了 Python。这一更新版本包括一个基于旧金山湾区乳腺癌研究(SFBCS)的新的西班牙裔模型。据我所知,这是 Gail 模型扩展版本的第一个 Python 实现。这个包的代码可以在这个库中找到。
该软件包包含几个函数,用于计算乳腺癌的相对和绝对风险。这个包里的主要功能是absolute_risk
。它使用患者数据来预测特定时间段内患乳腺癌的概率。它还可以用来预测平均人群风险,并将其与患者的结果进行比较。recode_check
将输入数据重新编码为适合absolute_risk
的格式。relative_risk
功能估计风险因素组合的相对风险。它将年龄分为两组:50 岁以上和 50 岁以下。最后,risk_summary
创建一个包含所有相对风险和绝对风险的数据框架。其输出可用于进一步分析。
在工作中可以随意使用这个包!请注意,对软件包的任何更改/修改都将由您自己承担风险。我确保当前版本产生与官方 Python 实现相同的结果。如果您有任何问题,请查看 BRCA 官方文档或给我发邮件!
页(page 的缩写)虽然一个人的风险可能很高,但这并不一定意味着他们会患乳腺癌。一些没有患乳腺癌的女性比一些患乳腺癌的女性有更高的风险评估。因此,所有女性在 45 岁以后都必须每年进行一次乳房 x 光检查。保持健康!
获得对你的模型的信任,用石灰和 SHAP 做出解释
模型可解释性
使用机器学习来自动化流程在全球许多组织中被广泛采用。作为戴尔数据科学工厂团队的一员,我们与不同的业务部门合作,提供基于数据的创新解决方案来优化现有流程。
在我们与定价业务部门的一次合作中,我们专注于改进导致许多延迟的手动密集型流程。手动流程包括审计销售代表提交的交易(其中一些产品的价格低于某一点),并根据交易的特点决定是批准还是拒绝交易(您可以在此处阅读更多信息)。如果交易被拒绝,定价分析师应向销售代表提供解释。提供解释可以帮助销售代表调整交易,使其获得批准,这对双方都有利。
由于这非常耗时,并可能导致失去机会,我们希望通过减少需要手动审查的交易量来优化它。为了实现这一点,我们使用机器学习来自动批准和自动拒绝较简单的案例,这使得分析师可以专注于更复杂的交易,从而产生更多价值。
为了保持相同的质量水平,并在用户之间建立信任(这在实现机器学习模型时非常关键),我们必须了解决策是如何做出的。考虑到这一点,我寻找现有的工具来支持我们正在进行的转型,我遇到了莱姆和 SHAP。在整个过程中,我检查了两种方法的数据,以了解哪种方法更适合我,我获得了很多知识,我想分享。在这篇博文中,我将分享我所学到的东西,并分享一些帮助我更好地理解每个工具如何工作的细节。
这篇博文将涵盖以下内容:
1.SHAP 和莱姆-背景
2.例子
3.摘要
4.进一步阅读
1.SHAP 和莱姆-背景
LIME(局部可解释模型不可知解释)提供局部解释;它可以帮助解释为什么单个数据点被归类为特定的类。LIME 将模型视为黑盒;它不区分随机森林、决策树或神经网络。它使用线性模型来提供局部解释。围绕 LIME 的主要概念是,即使线性模型不能很好地解释复杂的数据/模型,但当试图解释局部观察时,它可以提供足够的解释。下面你可以看到一个解释石灰直觉的图。这是摘自论文:“我为什么要相信你?”解释任何分类器的预测。
LIME 提供了三种不同的解释器:表格解释器(将重点介绍)、图像解释器和文本解释器来处理不同类型的数据。
从上面提到的论文中,有一个例子证明了关于石灰的直觉
SHAP(SHapley Additive explaints)旨在通过计算每个特征对预测的贡献来解释单个数据点的预测。生成的解释是基于从联盟博弈论中计算 Shapley 值(你可以在这里阅读更多信息)。它基于下面的场景:假设你作为团队的一员玩某个游戏,团队赢了,结果赚了一些钱(支出)。在玩家之间分配奖金的最佳方式是什么,以最好地反映每个玩家对游戏的贡献?在我们的案例中,我们希望了解如何在模型中的不同特征(玩家)之间划分预测(支出),以最好地反映每个特征所做的贡献。
一般来说,要计算某个特征对预测的贡献,应该获取不包含该特征的所有子集,并计算添加该特征前后的预测之间的差异,然后对不同的子集进行平均。
所描述的过程可能计算量很大,而且运行一个没有某个特征的模型会创建一个全新的模型,这不是我们想要解释/理解的(你可以在 Adi Watzman 的这个精彩讲座中听到更多)。幸运的是,SHAP 使用不同的近似和优化方法克服了这些困难。
SHAP 提供了三种不同的解释器:KernalSHAP,它与 LIME 类似,是模型不可知的,TreeSHAP 是针对基于树的模型优化的,DeepSHAP 是深度学习模型中 SHAP 值的高速近似算法。
在这篇文章中,我将重点介绍树解释器,因为我们在项目中使用了基于树的模型。
一个展示 SHAP 输入和输出的例子,摘自 SHAP 的 GitHub 页面
2.例子
继续看一些基于我们使用案例的例子,使用石灰和 SHAP。
石灰
为了提供一个解释,首先我们必须创建一个解释器。解释者应该得到以下信息:
- 我们应该指定我们是在处理回归模型还是分类模型。
- 我们应该传递我们的训练数据、特性名和类名(这是可选的,默认为 0 和 1)。
- Verbose-表示我们是否希望在解释中提供更多的细节。
- 因为在这个过程中有一些随机性,为了能够重现结果,您还应该设置 random_state 变量。
from lime.lime_tabular import LimeTabularExplainerlime_explainer = LimeTabularExplainer(train_data.values,
mode = ’classification’, feature_names = new_feature_names, class_names = [‘Deny’, ’Approve’], verbose=True,
random_state = 42)
关于分类特征的补充说明 -如果你的模型包含分类变量,事情会变得复杂一些。这里有一个简短的解释:为了提供解释,LIME 使用原始数据集对我们想要解释的观察周围的数据点进行采样。如果我们提供的数据中的分类变量采用统一的编码格式,那么采样过程可能会创建不太可能出现在数据中的样本,并且生成的解释不会代表实际数据。为了克服这一点,分类特征应该被转换成整数标签,为了了解更多关于如何使用带有分类特征的 LIME,我鼓励你观看凯文·勒芒恩的演讲,或者访问他的 GitHub 页面。
解释器设置好之后,让我们生成一个解释。要获得解释,您应该提供以下信息:
- 你想解释的例子。
- 生成概率的函数(在分类模型的情况下),或者预测数据集的函数(在回归模型的情况下)(在我们的情况下是 predict_proba)。
- 您还可以指定用于构建局部线性模型的最大要素数,目前我们使用默认值 10。
exp = lime_explainer.explain_instance(instance, trained_model.predict_proba)exp.show_in_notebook(show_table=True)
接下来,让我们检查输出:
作者图片
在顶部,呈现了由 LIME 创建的线性模型的截距,随后是由线性模型生成的局部预测,以及来自我们的模型的实际预测(这是将 explainer 中的 verbose 设置为 True 的结果)。如您所见,线性模型生成的预测和我们的模型生成的结果非常接近。接下来,您可以看到每个类别的概率,就像原始模型预测的那样。
作者图片
在最右边,您可以看到特定观察的每个特性的值。这些特征根据其所属的类别进行颜色编码;橙色的特征促成了交易的批准,而蓝色的特征促成了交易的拒绝。此外,它们按对预测的影响进行排序,影响最大的要素位于顶部。在中间的图表中,您还可以看到每个类别中每个特征的大小。理解这一点也很重要,为了提供更直观的解释,数值被离散化成几组,这就是为什么在中间的图表中,特征沿着一定的范围提供。这是 LIME 中的默认值,可以通过将变量 dicretize_continuous 设置为 false 来更改。
作者图片
您可以通过运行以下代码获得有关生成的本地模型的更多信息:
print(‘R²: ‘+str(exp.score))
作者图片
这会给我们本地模型的 R 平方,我们可以用分数来决定我们是否可以相信某个解释。
此外,您可以使用以下代码访问模型中每个特性的权重:
exp.local_exp
作者图片
对权重和截距求和将导致由 LIME 生成的局部预测。
exp.intercept[1] + sum([weight[1] for weight in exp.local_exp[1]])
作者图片
SHAP
转到 TreeSHAP,让我们为我们用于 LIME 的同一个实例生成一个解释。
首先,与 LIME 类似,我们应该导入 SHAP,创建解释器并传入训练好的模型:
import shap
shap.initjs() #This is for us to be able to see the visualizations
explainer = shap.TreeExplainer(trained_model)
接下来,让我们生成一个解释并将其可视化。第一行计算我们提供的实例的 SHAP 值,下一行生成一个图,该图将显示每个特征对最终预测的贡献。SHAP 所做的计算是针对两个类别进行的,这里您应该使用索引选择您想要引用的类别(在回归模型中不需要),在这种情况下,我想探究批准类别(类别 1)的结果。
为了计算我们想要解释的实例的 SHAP 值,您应该提供实例本身,并且为了生成绘图,您应该提供以下内容:
- 解释器生成的期望值,本质上是训练集预测的平均值,也称为基值。
- 接下来,您应该提供在前一行中计算的 SHAP 值(这些是每个要素对模型预测的贡献)。
- 您要解释的实例和功能名称。
shap_values = explainer.shap_values(instance)shap.force_plot(base_value=explainer.expected_value[1], shap_values[1], features=instance, feature_names=new_feature_names)
下图中的粗体数字是我们的预测。在左侧,您可以看到基值,如前所述,它是我们训练集中预测的平均值。顾名思义,这是我们预测的起始值,将模型中各要素的贡献相加,将得到我们的最终预测。
作者图片
特征以这样的方式排列,使得促成交易批准(类别 1)的所有特征在左边,并且用红色着色,并且促成交易拒绝(类别 0)的所有特征在右边,用蓝色着色。请注意,每一侧的要素都是按大小排序的,这在每个要素所占的空间中也很明显。您可能还会注意到,在图表的边缘,有一些附加要素也对不同的类有所贡献,但它们的贡献远远小于所显示的那些,您可以将鼠标悬停在图中的边缘,您将能够看到这些要素的名称及其值。
TreeSHAP 利用树的结构,可以计算精确值而不是近似值。将预期/基础值相加将生成准确的预测,如下所示。
explainer.expected_value[1] + sum(shap_values[1])
作者图片
SHAP 还提供了不同的可视化效果,可以根据您选择的类为您提供每个功能行为的总体概述。为此,首先您应该计算整个测试数据的 SHAP 值(注意这可能需要一些时间),让我们看一个例子:
test_shap_values = explainer.shap_values(test_data.values)
shap.summary_plot(shap_values[1], test_data.values)
作者图片
让我们检查图表的不同方面:
- x 轴代表对预测的贡献,这些是 SHAP 值。
- 左侧的 y 轴显示影响最大的特征(您可以指定想要显示的特征数量-默认值为 20)。这些特征按其对预测的影响进行排序,其中影响最大的位于顶部。
- 右侧的 y 轴表示如何解释每个特征的原始值。在每一行中,数据点用蓝色或红色着色,蓝色表示该特征的低值,红色表示该特征的高值。
- 该图由一条水平线分隔,在图的右侧,您可以看到促成交易批准的数据点,在图的左侧,您可以看到促成交易否决的数据点。
- 例如,特征 x_29 中的低值将有助于批准类,而高值将有助于拒绝类。
这可以帮助您了解功能是否像 SME(主题专家)期望的那样运行,并且可以帮助我们找到以前没有注意到的与数据相关的问题。
在 SHAP 还有其他的全球可视化选项,查看作者的 GitHub 页面可以看到不同的选项。
3.摘要
在这篇博文中,我与你分享了我使用工具来解释 ML 模型的动机,我们回顾了莱姆和 SHAP 的基础知识,并给出了基于我们用例的例子。
回顾我们所做的工作,我觉得这些工具的使用在我们的业务合作伙伴之间产生了信任,这使得我们构建的模型的实施更加顺利。此外,使用这些工具确实帮助我们发现了一些与数据相关的问题,并最终得以解决。
莱姆和 SHAP 都是很好的工具,你可以用来建立信任,也可以用来解释你所做的某个决定。当我们在相同的情况下检查两者时,我们注意到大多数影响变量在石灰和 SHAP 中几乎是相同的。但是,两者之间的顺序有点不同。
LIME 的主要优点是速度更快(至少对于表格数据来说是这样),而且它的工作方式非常直观。然而,生成的解释有时可能不可靠,为了使用它,需要做一些预处理。SHAP 易于使用,还可以提供要素的总体视图,以及要素值对模型预测的影响。此外,TreeSHAP 利用了树的结构,并计算精确的值,而不是近似值,但是在向业务合作伙伴解释时不太直观。
如果你想了解更多关于这两个工具的知识,我鼓励你看看这篇文章中嵌入的链接,以及下面的链接。
4.进一步阅读
以下是一些额外的阅读推荐:
- 用 SHAP 价值观解释你的模型——这是一篇很棒的博客文章,用一个数字例子来解释 SHAP。
- 一个让黑盒模型变得可解释的指南 -提供了可解释模型、石灰、SHAP 等等的全面补偿!
- 本地可解释的模型不可知解释(LIME):介绍——LIME 作者写的博客文章。
特别感谢 Or Herman-Saffar 和 Idan Richman-Goshen 对这篇博文的评论和宝贵反馈。
从 16 行代码中获得神经网络的直觉
艾莉娜·格鲁布尼亚克在 Unsplash 上的照片
神经网络相当令人困惑,尤其是当你从头开始编程的时候。本文将通过创建和训练一个单变量回归模型(在输入和输出之间有一个突触),让您直观地了解神经网络工作所需的相关概念。
神经网络是如何工作的?
假设你是一名医生,你希望找到身高和体重之间的定量关系:也就是说,你希望能够可靠地预测某人的体重,给定他们的身高。
到目前为止,你有 5 个人的身高和体重数据。这是在笛卡尔平面上绘制数据时的图表:
作者图片
当我们看这个图表时,我们可以想象出一条线来最好地解释这些数据,但是我们想对此进行量化。这就是使用神经网络的地方,或者在这种情况下,我们的单变量回归模型。
神经网络保存一个奇异变量α,当乘以给定的身高时,给出预测的体重。让我们随机生成α,并将其绘制在我们的图表上:
我们可以看到这条线没有很好地包含数据。它对数据的量化有多糟糕?测量蓝点和这条线之间的距离,并将它们相加。平方这个值。为什么值是平方?两个原因:
- 为了防止负数不受惩罚
距离较远的负数(线下的点)仍然是不准确的预测。当我们平方它们时,它们变成正数
- 惩罚更大的距离
100–3 = 97,但是 100–3 = 9991。距离越大,网络受到的惩罚就越多。
这是均方误差损失函数,衡量网络预测数据的好坏。这个值越大,模型越差。
神经网络的目标是减少这种损失函数,从而使预测更加准确。我们如何做到这一点?我们不能改变数据,我们唯一能改变的值是α。
现在,我们不太确定α的最佳值是多少,所以我们测试了不同的α值,记录了损失值,并绘制在图表上。因为我们想找到α的哪个值使损失值最低,所以需要找到最低点。在这种情况下,介于 0 和 0.5 之间。
我们如何让计算机来做这件事?我们发现了一种叫做导数的东西。导数是图形在某一点的陡度。也是图形的梯度。我们要计算的是损失对α的导数,也就是说,当给定点 a 时,图有多陡。
但是我们不能把这两个变量直接联系起来,因为它们之间没有直接关系。我们用高度值乘以α,然后用它来计算损失。
为了计算α和损失之间的导数,我们必须计算损失和预测值之间的导数,然后计算预测值和α之间的导数。最后,我们将它们相乘,找出损失值与α之间的导数。
损失值和预测值(高度* α)之间的导数是 2 *(真实-预测),因为 x 的导数是 2x。预测值和 alpha 之间的导数就是数据,因为 alpha 要乘以数据。
为了简单起见,不使用列表,我将体重身高的例子改为只预测值 2,作为 alpha。代码如下:
import numpy as np
x = 2
y = x*2alpha = np.random.randn()for i in range(100):
pred = alpha*x
loss = np.square((y-pred))dloss_dpred = 2*(y-pred)
dpred_dalpha = x
dloss_dalpha = dloss_dpred * dpred_dalphaalpha += dloss_dalpha*0.1
alpha
第 1 行:Python 中的一个有用工具。在这种情况下,它用于生成随机值。
第 2–3 行:网络试图计算出 x 乘以多少得到 y。它应该趋向于 2。
第 5 行:这是变量 alpha 的随机生成。
第 7–12 行:这段代码计算导数并将它们相乘。
第 15 行:Alpha 向正确的方向变化,一点一点,直到趋于最佳值。
这个程序应该输出 2 作为结果。
直观了解精确度、召回率和曲线下面积
理解精确度和召回率的友好方法
在这篇文章中,我们将首先解释精确和召回的概念。我们将尝试不只是扔给你一个公式,而是使用一个更直观的方法。通过这种方式,我们希望对这两个概念有一个更直观的理解,并提供一个很好的记忆技巧,让你再也不会忘记它们。我们将以对精确回忆曲线的解释和曲线下面积的含义来结束这篇文章。这篇文章是为初学者和高级机器学习实践者准备的,他们想更新他们的理解。在这篇文章的最后,你应该对什么是精确和召回有一个清晰的理解。
我们将从二元分类任务的情况开始解释。二进制意味着每个样本只能属于两个类别,例如狗和猫。我们将用 0 标记属于第一类(猫)的样品,用 1 标记属于第二类(狗)的样品。
从https://www.pexels.com/获得的图像
在分类问题中,神经网络是在标记数据上训练的。这意味着来自训练、验证和测试集的每个样本都由人来标记。由人类赋予的标签被称为地面真相。
在分类任务中,数据成对提供:
- 输入数据
- 地面真实标签
输入数据不一定是图像,也可以是文本、声音、坐标等。
输入数据接下来被馈送到神经网络,并且我们获得样本属于哪个类别的预测。请注意,精确召回曲线只能为输出概率(也称为置信度)的神经网络类型(或更一般的分类器)计算。在二元分类任务中,输出样本属于类别 1 的概率就足够了。让我们称这个概率为 p 。样本属于 0 类的概率正好是:1 - p 。
因此,如果神经网络输出 p =0.99,则相当有把握,馈送的输入数据属于类别 1,即输入数据是狗的图像。如果网络输出 p =0.01,则可以确信输入数据不属于第 1 类。这相当于美联储输入数据属于概率 1 - p = 0.99 的 0 类。
为了获得给定样本的具体类别预测,我们通常使用阈值 0.5 来设定神经网络输出的阈值。这意味着高于 0.5 的值被认为属于类别 1,而低于 0.5 的值表示类别 0。
有了所有的定义,我们接下来可以定义真阳性、假阳性、真阴性和假阴性的概念。
真阳性、假阳性等。
现在基于神经网络的输出,我们得到以下四种情况:
情况 1 :真阳性
输入样本属于类别 1,并且神经网络正确地输出 1。
由于历史原因,这被称为真正的积极。记住:正= 1。
案例二:假阳性
输入样本属于类 0。然而,神经网络错误地输出 1。
情况 3 :真阴性
输入样本属于类别 0,并且神经网络正确地输出 0。
同样,由于历史原因,这被称为真正的否定。记住:负= 0。
情况 4 :假阴性
输入样本属于类别 1。然而,神经网络错误地输出 0。
我们将数据集中的真阳性数表示为 TP,假阳性数表示为 FP,依此类推。在继续阅读之前,请真正熟悉 TP、FP、TN 和 FN 的概念。
接下来,我们将定义精度的概念。
精确
我们有以下由 10 个样本组成的数据集:
从https://www.pexels.com/获得的图像
请注意,所选的数据集是不平衡的,即与具有 7 个实例的猫类相比,狗类仅具有 3 个实例。在处理真实数据集时,几乎总是会遇到数据不平衡的问题。相比之下,像 CIFAR-10 的 MNIST 这样的玩具数据集具有均等的类分布。精确度和召回率作为评估神经网络在不平衡数据集上的性能的度量特别有用。
我们将上述每个输入数据输入神经网络,并获得每个样本的概率/置信度:
接下来,我们根据预测的置信度对表格进行排序。我们将实际阳性样品涂上绿色,将实际阴性样品涂上红色。相同的颜色方案应用于正面和负面预测。我们再次假设阈值为 0.5。
阈值 0.5 →精度= 3/6 = 0.5
正面预测可以分成一组 TP 和一组 FP。
我们将精度定义为以下比率:
因此,精度衡量你的正面预测有多准确,也就是说,你的正面预测正确的百分比。请注意,总和 TP+FP 对应于被分类器预测为阳性的样本总数。
记住精度的定义是一件困难的事情,在几周内记住它就更难了。对我帮助很大的是记住了上面的彩色表格。请记住,精度是第一行上方箭头的长度(实际值)除以第二行下方箭头的长度(预测值),并且记住绿色代表 1(或正值)。
请注意,在精度的定义中没有使用 FN。
为了更深入地了解精确度的概念,让我们改变定义样本被分类为阳性还是阴性的阈值。
如果我们将阈值降低到 0.3,我们会得到 0.375 的精度。记住,阈值为 0.5 时,精度为 0.5。
阈值 0.3 →精度= 3/8 = 0.375
如果我们将阈值进一步降低到 0.0,我们会得到 0.3 的精度。重要提示:这对应于我们数据集中狗的比例,因为 10 个样本中有 3 个属于狗类。
我们观察到,降低阈值也会降低精度。
接下来,我们将阈值增加到 0.7,并获得 0.75 的精度。
阈值 0.7 →精度= 3/4 = 0.75
最后但同样重要的是,我们将阈值增加到 0.9,并获得 1.0 的精度。请注意,在这种情况下,我们没有任何误报。我们得到一个假阴性,如上所述,在精度计算中不考虑这个假阴性。
阈值 0.9 →精度= 2/2 = 1.0
收集所有的结果,我们得到下面的图表:
我们看到精度在 0 和 1 之间。当阈值增加时,它增加。我们还注意到,只要阈值足够大,精度可以变得任意好。因此,精度不能单独用来评估分类器的性能。我们需要第二个指标:召回率。
回忆
我们有以下由 10 个样本组成的数据集:
从https://www.pexels.com/获得的图像
请注意,为了解释清楚,我们使用了不同于以前的数据集。dog 类现在有 7 个实例,而 cat 类只有 3 个实例。
我们将上述每个输入数据输入神经网络,并获得以下置信度:
我们再次根据获得的置信度值对表格进行排序。我们使用与之前相同的颜色方案,并再次假设阈值为 0.5。
阈值 0.5 →回忆= 5/7 = 0.714
这一次,我们将实际阳性分为一组 TP 和一组 FN,并将召回率定义为以下比率:
因此,召回衡量的是你发现所有实际阳性样本有多好,即实际阳性样本被正确分类的百分比。请注意,总和 TP+FN 对应于数据集中实际阳性样本的总数。
为了记住回忆的定义,你可以再次使用上面的彩色表格。回忆是第二行下面箭头的长度(预测)除以第一行上面箭头的长度(实际),记住绿色代表 1(或正)。
为了更深入地理解回忆的概念,让我们再次改变定义样本被分类为阳性还是阴性的阈值。
如果我们将阈值降低到 0.3,我们将得到 1.0 的召回。请记住,对于 0.5 的阈值,召回率为 0.714。与精确度相反,当阈值降低时,回忆似乎增加。
阈值 0.3 →回忆= 7/7 = 1.0
请注意,在上述情况下,我们没有任何假阴性。我们得到一个误报,如上所述,在召回的计算中不考虑它。如果我们将阈值进一步降低到 0.0,我们仍然得到 1.0 的召回。这是因为对于阈值 0.3,所有实际阳性都被预测为阳性。我们还注意到,只要阈值足够小,回忆可以是任意好的。这与 precision 的行为是相反的,也是这两个指标如此好地一起工作的原因。
接下来,我们将阈值提高到 0.7,得到 0.571 的召回率。
阈值 0.7 →回忆= 4/7 = 0.571
最后但同样重要的是,我们将阈值提高到 0.9,并获得 0.285 的召回率。
阈值 0.9 →回忆= 2/7 = 0.285
收集所有的结果,我们得到下面的图表:
我们看到召回率在 0 和 1 之间。当阈值增加时,它减小。我们还注意到,只要阈值足够小,回忆可以是任意好的。
接下来,我们将结合精度和召回率,得出精度-召回率曲线(PR-curve)。
精确回忆曲线
对于 0 和 1 之间的所有阈值,通过在 y 轴上绘制精度,在 x 轴上绘制召回,获得精度-召回曲线。典型的(理想化的)精确召回曲线如下图所示:
我们已经看到,对于非常高的阈值(高意味着略小于 1.0),精度非常高,召回率非常低。这由图表左上角的红点表示。
对于非常低的阈值(略大于 0.0),我们已经表明,召回率几乎为 1.0,精度与数据集中阳性样本的比率相同。).图中右下角的红点显示了这一点。
完美分类器的精度-召回曲线如下所示:
一个非常差的分类器(随机分类器)的精确召回曲线看起来像这样:
有了这些知识,你现在应该能够判断一个任意的精确召回曲线属于一个好的还是一个坏的二元分类器。请注意,要正确解释精密度-召回率曲线,您还需要知道阳性样本与所有样本的比率。
1.1 精确召回曲线下面积(PR-AUC)
最后,我们得出度量 PR-AUC 的定义。PR-AUC 的一般定义是找到精确度-召回曲线下的面积:
如下图所示:
因此,PR-AUC 将精度-召回曲线总结为单个分数,并且可以用于容易地比较不同的二元神经网络模型。请注意,完美分类器的 PR-AUC 值总计为 1.0。随机分类器的 PR-AUC 值等于数据集中阳性样品与所有样品的比率。
在我们的下一篇文章中,我们将展示如何使用 Python 轻松实现 PR-AUC。
找到甘了吗?保持可解释性的灵活建模方法
在许多社会科学和商业问题中,解释现象发生的原因往往比提高模型对事件发生的可预测性更重要。因此,拥有一个可解释的模型对于理解不同因素如何与感兴趣的结果相互作用是至关重要的。
该模型的可解释性在高度监管的业务环境中也很重要,例如贷款审批决策。即使在预测准确性比“为什么”更重要的情况下,可解释的模型也可以帮助调试更复杂的模型,并指导特征工程和数据预处理的新方法。
游戏——引擎盖下
在这种情况下,广义加法模型(GAM)在简单模型(如我们用线性回归拟合的模型)和更复杂的机器学习模型(如神经网络)之间提供了一个中间地带,神经网络通常承诺比简单模型具有更好的预测性能。GAM 还可以用于各种任务:回归、分类、二元选择。
在线性回归中,我们将结果 y 建模为两个输入 X₁和 X₂的函数,如下所示:
y = β₁X₁ + β₂ X₂ + u
在 GAM 中,β Xᵢ被 f(Xᵢ代替,其中 f()可以是任意非线性函数。换句话说,GAM 由输入上的光滑函数 f()的和组成。想法仍然是,每个输入特征对响应做出单独的贡献,这些只是相加,但是这些贡献不必与输入严格成比例。这种方法的美妙之处在于,类似于线性回归中的β,部分响应函数 f()仍然捕捉结果 y 的变化以改变输入。预测的变化取决于 Xᵢ.的初始值
处理回归模型中非线性关系的一种常用方法是创建多项式要素。对于预测因子 Xᵢ,我们加入了二次项(Xᵢ)、三次项(Xᵢ)等,以获得更好的拟合。GAM 包含了这个想法,但是还包含了一个额外的方面:惩罚估计。这个想法类似于脊或套索回归,其中添加了惩罚项以帮助避免过度拟合。
创建变量变换的另一种方法是将变量切割成不同的区域,并分别适合这些区域。然而,不同的拟合可能是不相关的,导致有时对相近值的预测明显不同。GAM 允许用户在变量中指定knots
的数量,用于创建分段,在每个分段上分别拟合三次多项式,然后连接起来创建一条连续曲线。
那么应该用什么平滑函数呢?
在 R 中的 mgcv 包中有很多 smooth,可以通过 smooth.terms ( 链接)的帮助文件了解更多。默认的是薄板回归样条(TPRS),它在一般情况下性能很好。三次样条也是一种常见的基础,反映了为协变量添加多项式项。
在 R 中实现
我们使用“r”中的mgcv
包来实现 gam,并使用来自包[catdata](https://cran.r-project.org/web/packages/catdata/catdata.pdf)
的内置数据集medcare
来说明 gam,并使用逻辑回归与性能进行比较。
medcare
数据收集自 4406 名年龄在 66 岁及以上的个人,他们都有公共保险计划。结果变量是healthpoor
,这是一个二元变量,如果个人报告健康状况不佳,则等于 1,否则等于 0。我们很想知道ofp
,医生诊所就诊的次数,可能与健康结果有什么关联。人们可以假设这两个变量之间的非线性关系:一个健康的人去看医生的次数很少,但是看更多的医生也可以让病人变得更健康。所以我们对更灵活的建模方法感兴趣。
mgcv 将gam
视为glm
的一般化版本,因此可以直接调用gam
方法来使用glm
方法,例如线性和逻辑回归。
library(catdata)
library(mgcv)
library(Metrics)
library(ggplot2)
library(visreg)data(medcare)#### logit model (same as running glm with family set to "binomial")
lm <- gam(healthpoor ~ male+ age + ofp, family = binomial, data = medcare)
pred <- predict(lm, type="response")
lm_auc <- Metrics::auc(medcare$healthpoor, pred)
lm_auc#### generalized additive model
gam <- gam(healthpoor ~ male+s(age)+s(ofp), family = binomial, data = medcare)
pred <- predict(gam, type="response")
gam_auc <- Metrics::auc(medcare$healthpoor, pred)
gam_auc
gam 公式中的 s() 项表示要平滑的项。有几个选项可以传递给 s()术语—例如,您可以指定不同的平滑函数bs
和不同的结数k
。
如果唯一值的数量小于基数的数量(例如,当您试图将s()
添加到类似male
的二进制变量时),该函数将返回以下错误:
一个项的唯一协变量组合比指定的最大自由度少。
使用visreg
来可视化ofp
的拟合项,我们可以看到gam
产生了对ofp
更加细致入微的预测,而逻辑回归的预测更加线性。
visreg(gam, "ofp", jitter=TRUE, line=list(col="red"),
fill=list(col="green"))
gam
模型也产生了略好的 AUC,0.679,相比之下,逻辑回归模型的 AUC 为 0.673。
基于 ofp 的 I 预测:gam(左),logistic 回归(右)。作者法师。
解释
我们最终感兴趣的是估计ofp
在healthpoor
概率上的变化。为此,我们需要将其他特性的值固定为它们的平均值或模式(如果该特性是一个分类变量)。然后,我们创建一个测试数据帧,其中包含一系列可能的值ofp
。
# function to get mode of an array of values
getmode <- function(v) {
uniqv <- unique(v)
uniqv[which.max(tabulate(match(v, uniqv)))]
}testdata = data.frame(ofp = seq(0, 100, length = 101),
male = getmode(gam$model$male),
age = mean(gam$model$age))
使用predict
函数,我们可以将之前拟合的 gam 模型外推至测试数据。该图显示,在保持其他变量不变的情况下,ofp
与报告健康状况不佳的可能性呈非线性关系。此外,在 ofp 较高的地区,置信区间不太紧。
fits = predict(gam, newdata=testdata, type='response', se=T)### create a confidence interval for the fits
predicts = data.frame(testdata, fits) %>%
mutate(lower = fit - 1.96*se.fit,
upper = fit + 1.96*se.fit)ggplot(aes(x=ofp,y=fit), data=predicts) +
geom_ribbon(aes(ymin = lower, ymax=upper), fill='gray90') +
geom_line(color='#00aaff') +theme_bw()
图片作者。
参考
有关 GAM 的更多信息:
- https://m-clark.github.io/generalized-additive-models
- https://www . rdocumentation . org/packages/mgcv/versions/1.8-31/topics/gam
- https://noamross.github.io/gams-in-r-course/
用统计学家的大脑赌博。
利用蒙特卡洛模拟分析赌场的胜算
我在澳门威尼斯人赌场外徘徊(赌场内禁止拍照)
让我从我在 赌场的经历 说起,让它变得更有趣。2016 年,我在威尼斯人的世界第二大赌场澳门那里,在不同的游戏上试试运气,直到我到达轮盘老虎机。你可以想象,这里的气氛是超现实的,灯光闪烁,富人聚精会神地坐着,眼睛盯着老虎机和摆满“免费酒瓶”的桌子。
这是我的故事,我在赌场有 1000 美元(港币)可以花。在两个小时内,我在轮盘赌机器上赚了大约 3500 美元(港币),但是谁在赢了之后停下来。在看了一段时间人们玩不同的游戏后,我开始玩轮盘赌是在晚上 8 点(当地时间)。但是,我最终在赌场呆到了第二天早上 5 点,净赚了 1000 港币。我所有的钱都浪费在享受 9 个小时的“蒙特卡洛模拟”上了,赢的几率还不到 0.5%。玩笑归玩笑,我的一个统计学家朋友总是告诉我,赌博是零和/负和游戏,但是在赌场里,像我这样天真的人/游客很容易被显示器上显示的最后 20 个结果所诱惑(赌徒谬误)。
现在,至少我们有统计学和蒙特卡罗模拟来分析同样的问题。
现在,让我从解释赌场游戏的赔率开始。我将尝试解释一个游戏,并使它简单化,便于我们的计算。让我们选择游戏大和小(原文如此)。庄家将洗牌 3 个骰子,这可能导致从(1,1,1)到(6,6,6)的任何组合。有两个选项可供选择,小(4 到 10 之和)或大(11 到 17 之和)。我会解释为什么我有一段时间没有包括 3 和 18 的总和(类似的游戏在印度到处都很常见,被称为 7 上 7 下)。现在,我们可以选择小的或大的。让我们假设支出是 1:1,这意味着如果你赢了,你可以拿回你的赌注,如果你输了,你会失去同样的金额。到目前为止,你可能会认为小企业和大企业的几率是一样的,但这是几率发生变化的地方。对于三胞胎来说,支付模式有所调整,这使得游戏更有利于玩家。为了我们的计算,让我们假设在三胞胎的情况下我们不会得到报酬。选小选大和我们差不多。因此,让我们选择小的计算。
https://www . thoughtco . com/probabilities-for-rolling three-dice-3126558
如果我们选择小,我们的胜算将是 105/216(不包括三胞胎(1,1,1)和(2,2,2))。即 48.61%。所以,因此,房子赔率将是 51.39%。即使这样,你也会想,这么少的钱会对我有什么影响呢?对吗?嗯,我会通过蒙特卡洛模拟给你看。
事实:
- 欧洲轮盘赌的最低赔率是 2.7% ( 52.7%的人看好房子)。
- 与其他赌场游戏相比,二十一点是我们胜算较大的游戏之一。
进入蒙特卡洛世界
举例来说,我假设我有 50000 美元,我将在每场比赛中下注 500 美元。现在,首先,让我们考虑上面计算的赔率值为 48.6%,让我们计算一下,如果我分别玩 5 场、50 场、5000 场、1000 场和 10000 场游戏,我最终可能会有多少钱。
让我们导入库并创建一个输赢函数。我们将使用均匀随机生成一个介于 0 和 1 之间的概率,然后使用 win_odds 概率来决定我们是赢还是输(根据赔率)。
注意:即使你对 python 或编程不熟悉,也可以试着只阅读文本并理解故事。
#Import required librariesimport randomimport pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport seaborn as sns#win_odds take the probability of winning, returns true if prob lies between 0 and win_oddsdef win_or_lose(win_odds):dice = random.uniform(0,1)if dice <=win_odds:return Trueelif dice > win_odds:return False
下面的 play 函数将接受输入—手中的筹码(此处为 50000 美元)、下注金额(500 美元)、总下注数和 win_odds 概率,并在游戏结束后返回最终更新的金额(使用赢/输赔率)。
#chips_in_hand is the amount of chips a player has in hand#betting amount is the amount a player bets in each game#total_bets is the number of bets in one seatingdef play(chips_in_hand, betting_amount, total_bets, win_odds):game_num = []updated_chips = []game = 1#lets bet for the number of bets we have in the argument and append the value of chips in hand after each bet in updated_chips listwhile game <= total_bets:#If we winif win_or_lose(win_odds):#Add the win amount to our chips valuechips_in_hand = chips_in_hand + betting_amountgame_num.append(game)#Append the updated_chips value after each gameupdated_chips.append(chips_in_hand)#If the house winselse:#Add the money to our fundschips_in_hand = chips_in_hand — betting_amountgame_num.append(game)#Append the updated_chips value after each gameupdated_chips.append(chips_in_hand)game = game + 1return(game_num,updated_chips,updated_chips[-1])
现在,我们将模拟和调用 play 5000 次(模拟次数),并分析最终金额值的统计(在 5000 次模拟中)。简单来说,由于我们是做 5000 次模拟,所以玩游戏后会有 5000 个不同的最终值。(1 场游戏基本上由投注数组成,如果投注数是 5,1 场游戏由 5 个投注组成)
ending_fund= []#lets try 5000 simulations to get a good mean value ( Monte Carlo Simulation)#Let’s start with $50000 and bet $500 bets each time for simplicity#Lets play 5 times and see the final chips amount possible through monte carlo simulationplt.figure(figsize=(12,6))for x in range(1,5001):game_num,updated_chips,fund = play(50000 ,500, 5, win_odds)ending_fund.append(fund)plt.plot(game_num,updated_chips)plt.title(‘Final chips value vs number of bets (After a player starts with $5000)’)plt.ylabel(‘Final chips value’)plt.xlabel(‘Number of bets’)plt.show()#Lets print the statistics of the final_chips valuemean_final = sum(ending_fund)/len(ending_fund)variance_final_funds = sum([((x — mean_final) ** 2) for x in ending_fund]) / len(ending_fund)res_final = variance_final_funds ** 0.5min_final = min(ending_fund)max_final = max(ending_fund)print(“The player starts the game with $50000 and ends with $” + str(mean_final))print(“The standard deviation is $” + str(res_final))print(‘The minimum anad maximum funds that a player can possible end with are: {} and {}’.format(min_final,max_final))
案例 1:下注数= 5
如果只是玩 5 次,不确定性就太高了,无法在一些统计上决定。即使这样,我们也可以看到玩家最终的平均金额是 49916 美元,比他实际拥有的要少。因为他每次下注只有$500,所以他在 5 次下注中只能输掉$2500。因此,让我们将下注数量增加到 50、500、1000 和 10000,并对其进行分析。没有人离开赌场时只下 4-5 次注。即使是我,在我的一生中也会下超过 500 次的赌注。
案例 2:下注数= 50
案例 3:下注数= 500
案例 4:下注数= 1000
案例 5:下注数= 10000
模拟图
分布图
从上面的模拟图和分布图中,你可以看到一个有趣的趋势。让我给你解释其中的一个,然后你就可以对正在发生的事情有直觉了。
在案例 5 中(下注数= 10,000),您可以在模拟图中看到,随着下注数的增加,该图向下。另外,在模拟图下方的分布图中,您可以看到平均最终金额约为-100,000 美元。想象一下,有人带着一袋 5 万美元来到这里,最后却给了房子 10 万美元。
现在你已经了解了赌博的赔率,让我们对最终金额与 odds_probability 的统计数据进行敏感性分析。
我们将从 0.45(对我们不利)到 0.495(良好的回报,如二十一点,但仍低于 0.505 的赔率)等间距小数,看看最终金额的平均值、标准差、最小值和最大值是什么样子的。
我们将赌注的数量定为 1000,这对于正常的赌徒来说是非常现实的。
win_odds_list = np.linspace(.45, .495, num=100)
col_names = ['win_odds', 'mean_final', 'std_final', 'min_final', 'max_final']final_coins = pd.DataFrame(columns = col_names)for odds in win_odds_list:mean_val, std_val, min_val, max_val = simulate_bets(50000, 500, 1000, odds, 5000)final_coins = final_coins.append({'win_odds': odds, 'mean_final': mean_val, 'std_final': std_val, 'min_final':min_val , 'max_final':max_val }, ignore_index=True)
在对我们上面生成的 100 个等间距赔率中的每一个进行 5000 次模拟后,我们得到了下面的数据框。
从上面 4 个图可以看出这么多有趣的趋势。即使赢了 50000 美元,玩了 1000 次,最大价值也只有 100000 美元左右(赔率为 0.495)。
下次当你去拉斯维加斯、大西洋城或澳门时,让你的统计员的大脑保持活跃。如果你打算待很久,至少试着玩赔率最高的游戏。
谢了。
在 Linkedin 上帮我联系:
T3【https://www.linkedin.com/in/saket-garodia/】T5
参考文献:
https://pythonprogramming.net/monte-carlo-simulator-python/
http://math.info/Misc/House_Edge/
https://wizardofodds . com/games/sic-bo/
https://towards data science . com/the-house-always-wins-Monte-Carlo-simulation-EB 82787 da 2 a 3
回到 2018 年,那是我第一次在澳门的赌场体验(是专门从香港过来的一日游)。我们选择了…
medium.com](https://medium.com/eatpredlove/casinos-big-and-small-using-monte-carlo-simulation-3936f9bcf4bf) [## 赌场总是赢家:蒙特卡洛模拟
赌场是怎么挣钱的?诀窍很简单——你玩的时间足够长,输钱的概率就会增加。让我们…
towardsdatascience.com](/the-house-always-wins-monte-carlo-simulation-eb82787da2a3)
注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。