TowardsDataScience 博客中文翻译 2019(三百八十七)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

免费在云上练习 R 和 Python

原文:https://towardsdatascience.com/practice-r-and-python-on-the-cloud-for-free-103e9d26902a?source=collection_archive---------21-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

r 和 Python,数据科学的“动态二人组”,都是免费的开源编程语言。这意味着没有所谓的“供应商”,比如说,微软拥有 Excel。这使得开始使用这些程序变得有点棘手:有几种安装它们的方法,通常需要多个步骤,令人困惑,并且耗费大量资源。

对于一个全新的程序员来说,放弃那些甚至连安装都如此复杂的工具是很容易的——“如果来说很难,想象一下试图使用它们!”

幸运的是,免费的基于云的应用程序可以让你试验这些程序,不需要安装。这为您节省了磁盘空间和麻烦,并允许您深入代码——和可能性——而不是逻辑。

对于 R: RStudio 云

RStudio Cloud 来自 RStudio,它是主流的 RStudio 集成开发环境的供应商。(我在中使用 RStudio 来教授我的 R 课程。)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

暗示创建一个 RStudio 帐户并开始使用。您可以创建一个新项目,并从浏览器运行 RStudio 会话。代码将在 RStudio 服务器上执行。

您的初始工作区将如下所示。这是 RStudio 界面的“虚拟”实例:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这是你第一次在 RStudio 工作,看看我下面的“RStudio 之旅”。

要继续涉猎 R,请查看我的帖子。您的 R 会话将像在您的计算机上一样运行,但这一次 RStudio 将负责软件。

对于 Python: Google 联合实验室

谷歌托管免费的协作服务,使用修改过的 Jupyter 笔记本运行 Python。Colab 的确切“外观和感觉”与使用像 PyCharm (我最喜欢的 Python 工作环境)这样的代码编辑器或者甚至是一个“普通”的 Jupyter 笔记本是不一样的,但是功能是存在的,而且你不必处理软件和软件包的维护。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

要访问 Colab,请登录您的 Google 帐户,查看包含以下视频的 Google Colab starter 笔记本

谷歌 Colab 让你可以直接访问谷歌的超级计算机——你可以在这里做一些非常严肃的数据,正如来自 TensorFlow 的认可所表明的那样(这是谷歌开发人员为深度学习开发的一个受欢迎的包)。你甚至可以完全从云端执行你的 Google Drive 文件

我写的 Python 不如 r 多,如果你想对这种语言有个大概的了解,可以看看 DataCamp 的免费课程,Python 中的数据科学简介

结论:快速编码

有没有尝试过 RStudio Cloud 和 Google Colab?对你来说哪个看起来更人性化?学 R 和 Python 你更兴奋?

或者,您更喜欢使用不同的免费在线资源来练习 R 和/或 Python 吗?比如最近了解到的微软 Azure 笔记本,可以让你从 Jupyter 笔记本上免费练习 R 和 Python 两种语言。

在评论里说吧。

实践数据科学

原文:https://towardsdatascience.com/practicing-data-science-5487e9f88aad?source=collection_archive---------20-----------------------

在数据科学项目中询问方向

数据科学项目的倾斜有很多:有无标注数据;停止数据争论或涉及机器学习算法;预测类别或预测数字;不均匀分布的类,二进制类,甚至没有一个类的例子;结构化数据和非结构化数据;利用过去的样本或者仅仅停留在现在;要求实时或接近实时执行或具有可接受的较慢性能;在光鲜亮丽的报告中展示结果,或者在中立的 IT 架构背后隐藏事实;有大量预算或者根本没有预算。

CRISP-DM 循环够用吗?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The CRISP-DM cycle chart as from Wikipedia

虽然数据科学项目的一般开发是相对标准的,例如遵循 CRISP-DM 周期,但每个项目通常需要一些特殊的定制,即特殊的成分以适应特定的数据、目标、约束、领域知识,甚至项目的预算。

CRISP-DM 周期为任何数据科学项目推荐以下阶段:数据和业务理解、数据准备、模型训练、模型优化、模型评估,以及最后的模型部署。关于他们的实际实施的更多细节可以在“分析和超越!”

通过 CRISP-DM 循环提供的这些指南对于标准项目非常有用;也就是一个训练数据充足,类分布均匀,对速度或最终可视化没有特殊要求等等的项目。指南没有提供任何细节来处理数据、项目特征和最终用户请求的细节。

定制 CRISP-DM 周期以适应您的项目

即使我们清楚这个过程,如果没有合适的方向图,在许多机器学习算法和部署选项中进行选择可能会很困难。我们希望画出这样一张地图,以帮助理解根据手头的数据科学项目的特点应该朝哪个方向前进。

我们用一系列越来越复杂的问题来组织我们的定向之旅。我们从解决关于项目类型的基本疑问开始,然后我们转移到项目生产性实现的执行和部署选项。

我需要机器学习模型吗?

在我们碰巧工作的学科的命名混乱中,我们经常将数据科学、数据挖掘、人工智能、商业智能以及可能其他一些“数据”、“科学”和“智能”的排列放在同一个桶中。我不完全清楚每一个名字的细微差别和涵盖范围。

然而,我知道并不是所有与数据相关的项目都需要预测模型。通常,数据混合、清洗和转换;KPI 的计算;或者在仪表板或 BI 报告中组织成功的度量标准。在这种情况下,纯粹的数据转换和数学运算就足够了,不应该使用机器学习模型。

分类还是数量预测?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第二个问题指的是要预测的变量的性质。我们要预测一个类还是一个数?例如,我们是否希望预测客户将购买的下一个产品(类别)或明年的头发颜色(类别)趋势?还是我们要预测未来两周一台洗衣机的价格(数字)或者今晚伦敦金融城要消耗的千瓦(数字)?

请注意,有时数值预测问题可以简化为分类任务。例如,如果我想预测洗衣机价格的上涨或下跌(而不是以美元为单位的实际价格),我可以定义三个类别(“价格上涨”、“价格相同”、“价格下跌”),因此,这就变成了一个分类问题。

最常见和最容易的分类问题包括一个二元分类系统:“真”或“假”,“疾病”或“健康”,“低于”或“高于”某个值,等等。

一旦我们决定了我们是在处理分类还是数值预测问题,我们就可以从两个不同的机器学习算法库中进行选择。训练后,分类算法输出一组标称值(字符串),而数值算法输出数字(整数或双精度)。

数字预测和时间序列分析一样吗?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数值预测的算法不一定实现时间序列分析。顾名思义,时间序列分析需要一个额外的约束:时间。以随机顺序预测数字,就像线性回归一样,只是将数字输出与输入要素的向量相关联。另一方面,时间序列预测算法接受按特定时间顺序排列的输入向量。

尽管在时间序列分析中也经常使用相同的数值预测技术,但是已经设计了专用算法来考虑训练期间输入数据的时间顺序。在时间序列项目的情况下,记住数据划分为训练集和测试集不能是随机的,但它必须符合过去和未来的概念。

监督与非监督训练算法

现在,让我们进入数据集的细节。对于分类问题,很多机器学习算法需要一个带标签的数据集;也就是说,数据集提供了示例向量,并且每个示例都标记了正确的类别。这种算法被称为“有监督的”,当出现特定的输入向量时,它使用这种训练集的标记样本来定义内部规则,以输出正确的类。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然而,通常有标签的数据集是一种奢侈。除非标签以某种方式自动可用,否则贴标签过程通常在时间和金钱上是昂贵的。如果没有可用的标记数据集,我们可以解决聚类过程,其中模式根据距离和规则分组在一起。

如果我们仍然坚持一个有标签的数据集,可以使用主动学习程序。在这种情况下,我们从一个带有标签的数据集开始。在接下来的几次迭代中,临界点的数据子集被手动标记,并且它们的类别以“无监督”的方式自动扩展到相邻点。

分布不均匀、不常见和稀有类

当训练数据集充分覆盖各种类的所有不同类型和子类型时,监督分类算法工作得最好。在一个完美的项目中,数据均匀地分布在所有的类中。

然而,有时数据远非均匀分布。在这种情况下,每个类都需要足够数量的代表性数据示例才能出现在最终预测中。当类别分布不均匀时,我们可能希望模型输出反映原始的先验类别概率。为了迫使模型学习各种先验概率,我们可以划分原始数据集,对类列应用分层采样。分层采样生成与原始数据集具有相同类别分布的训练集。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

有时一个类比数据集中的其他类更不常见。在这种情况下,不平衡的类别分布可能会使模型产生偏差,并遮蔽不经常出现的类别。这里,我们需要在训练期间用一个人为的更频繁的类来强制输入模型。这是通过对最频繁的类进行下采样(如果不太频繁的类的例子数量足够的话)或者对最不频繁的类进行过采样(引导)来获得的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在极端情况下,原始数据集中完全缺少一个类。例如,物联网中的异常检测就是这种情况。这个场景需要稍微改变一下视角。在这种情况下,机器学习模型仅在可用类的数据上训练,计算预测值和真实值之间的距离,并且从距离值中扣除可能的异常。

在某些情况下,一个类可能是罕见的,但充满了后果,如投资中的金钱损失或医疗程序中的死亡。然后,只有在绝对确定的情况下,我们才应该强制模型决定支持这个类。这通常通过在模型部署期间应用权重或更改阈值来实现。

结构化数据与非结构化数据

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

传统上,数据的分析是指数值或标称值。在数据库领域,我们称这样的数据架构为结构化的。然而,在过去的几年里,数据分析领域注入了一些不太传统的数据。文字、网络图、推文、评论等。已经成为我们数据库和数据湖的一部分。

特殊类型的数据需要特殊类型的处理。例如,文本和网络图需要一套特殊的工具来进行解析、清理、矢量化,当然还有可视化。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图一。数据科学项目中的培训选项

闪亮的报告、休息和普通的后台执行

一旦模型被训练、测试和接受,它就进入部署。部署工作流将模型应用于新的真实数据,并生成相应的预测。预测然后被返回给最终用户。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在一些项目中,部署工作流需要为结果呈现提供一个漂亮的交互式图形仪表板。可以安排部署工作流的执行,以便定期生成设计的仪表板。

然而,有时结果只需要传递给 web 服务网络中的下一个应用程序。这里,部署工作流需要被部署为 REST 服务本身。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在某些情况下,输出结果只是保存在一个文件(或数据库)中,不需要其他可视化或 REST 接口。

执行选项:大数据、实时、流

现在是最后一个问题。我们需要大数据平台吗?我们需要流媒体吗?我们需要实时执行吗?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们从实时执行开始。我们认为的实时有时仅仅是人类感知的实时。先说清楚,等待几秒钟对于人类来说是完全可以接受的,但不一定是真正的时间。

当然,执行性能取决于平台。然而,并不是所有的项目都需要高性能的执行。在开始对分布式平台进行大规模投资之前,要考虑执行需求是什么。如果最终用户可以等待几秒钟,那么在快速机器上的经典执行是可以接受的。

如果数据量很大,等待时间变长,那么并行执行就变得很有必要。

流也可能是您的项目的一个特定需求,即使大多数时候刷新从文件中读取的数据足以保持结果最新。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图二。数据科学项目中的部署选项

作者注:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们已经在电子书“实践数据科学”中收集了一系列用例及其实现的经验。案例研究集。”这本书是按应用领域组织的。它从最古老的数据科学领域(CRM 数据分析)开始,然后转移到零售商店的推荐引擎。接下来,它涵盖了金融行业、社交媒体和物联网时间序列分析中的项目,最后以几个网络安全项目结束。

电子书中报道的所有例子都引用了一个(或两个)工作流,这些工作流位于 KNIME EXAMPLES 服务器上,在每一节的开头都会如实报道。

我们希望这些数据科学经验将有助于培养下一代数据科学家的实用数据科学技能。如需免费下载,请访问https://www.knime.com/knimepress/practicing-data-science,并使用以下促销代码: MEDIUM-0519

— — — — -

为首次发表于data versity

布拉格步行无障碍。

原文:https://towardsdatascience.com/prague-walking-accessibility-8c0954e83bea?source=collection_archive---------43-----------------------

1.摘要

在这项研究中,我们试图分析 10 至 16 岁儿童的城市步行能力。我们使用一些数据来源和网络分析来构建所选城市的可达性地图。使用 K 最近邻技术,我们执行聚类以选择具有不同步行能力分数的区域。我们根据可步行性得分和 poi 密度分析这些杂乱数据,并确定在步行可达性方面需要改进的区域。

这项研究的笔记本可以在 GitHub 上免费获得:

数据采集和清理

探索性数据分析和可视化

建模和聚类

关键词

可达性聚类分析网络分析城市规划

2.介绍

步行是最可靠、最轻松、最健康的旅行方式。然而,今天步行上学的儿童数量正在下降。这对我们儿童的健康、安全和福祉造成了破坏性后果。今天,超过 70%的父母在他们还是孩子的时候步行上学,但是现在只有不到一半的孩子步行上学。与此同时,开车上学的儿童数量正在增加,对交通拥堵、健康和社区产生了越来越大的负面影响[1]。

步行是一种简单,自由和健康的方式,让孩子们去学校或其他活动,如图书馆,文化和爱好中心,操场等。步行为每个人提供了很多好处。

行人无障碍是什么意思?对我们来说,它意味着在合理的时间内到达特定的日常生活兴趣点(POI)的能力。我们所说的合理时间是指儿童行走 1300 米所需的时间。对于选定的年龄范围,这个距离是合理的。[2]10 至 16 岁儿童的常见兴趣点有:学校、业余爱好和休闲设施、图书馆、体育设施和户外游乐场。

因此,本研究的目的是:(1)根据人口密度和兴趣点密度分析当前城市的儿童基础设施。(2)构建可步行路线网络。(3)定义可步行性集群

通过对相关文献的讨论,本部分介绍了本文的研究目的和范围。研究区域和数据部分进入研究区域和数据源。方法在方法部分介绍。结果部分展示了结果,并说明了如何将结果应用于规划实践。结论和政策建议见讨论和结论部分。

报告全文可在 GitHib 上获得

3.研究区域和数据

布拉格是捷克共和国最大的城市,总面积 298 平方公里,人口 130 万,是欧盟第 14 大城市。它是著名的经济和文化中心,位于捷克共和国的中部地区。作为一个拥有超过 14 个世纪历史的城市,它拥有古典的中世纪城市中心,有许多历史建筑和小街道。市中心的周围更加现代化,外围则是小排屋和私人住宅。下图显示了布拉格市辖区的行政边界和每个区的总人口。

在我们的研究中,我们使用的数据类型包括所选 POI 的人口和地理数据。所有数据均来自公开数据来源:人口数据来自捷克统计局,教育设施数据来自捷克共和国教育、青年和体育部。其他数据集来自布拉格的开放数据门户和其他网络资源。

3.1 人口

作为人口数据集,我们使用捷克统计局的人口普查数据。捷克统计局的整个数据集包含捷克共和国公民的人口、性别和年龄数据。特征名称已编码。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因为我们的研究区域是布拉格,所以我们只对具有 uzcis = 44 的行政区的人口感兴趣。我们根据这个参数从原始数据集中过滤数据,删除不必要的列并执行重命名。

3.2 地理形状

IPR Praha 获取行政区边界数据集。这是 json 数据,包含一组地区属性,如名称、形状、面积等。

"type" : "FeatureCollection",
	"name" : "TMMESTSKECASTI_P",
	"features" : [
		{
			"type" : "Feature",
			"geometry" : {
				"type" : "Polygon",
				"coordinates" : [
					[
						[ 14.535485616000074, 50.01175081800005 ],
						...
						[ 14.535067366000021, 50.011918405000074 ]
				]
			},
			"properties" : {
				"OBJECTID" : 1,
				"DAT_VZNIK" : "20171204150607",
				"DAT_ZMENA" : "20171204154726",
				"PLOCHA" : 3703180.2199999997,
				"ID" : 34,
				"KOD_MC" : 539791,
				"NAZEV_MC" : "Praha-Újezd",
				"KOD_MO" : 43,
				"KOD_SO" : "116",
				"TID_TMMESTSKECASTI_P" : 34,
				"POSKYT" : "HMP-IPR",
				"ID_POSKYT" : 43,
				"STAV_ZMENA" : "U",
				"NAZEV_1" : "Újezd",
				"Shape_Length" : 0.11393431835892182,
				"Shape_Area" : 3703180.22185
			}
		},

从这些数据中,我们感兴趣的是面积和几何形状,我们还得到一个区的名称作为唯一键。

我们通过地区名称来比较人口数据集和地区边界数据集。我们在这两个数据集中获得了 57 个唯一的记录。我们通过 name this 来执行连接,以将集合合并成结果集合。结果数据集被保存到 IBM 云存储中,命名为布拉格 _ 区 _ 人口. csv 。此外,还可以在我们的 GitHub 库上访问它

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3.3 兴趣点

在我们的研究中,我们对一些类型的点感兴趣,如:学校、教育和爱好中心、图书馆、体育设施和操场。我们决定只使用这 5 种类型,因为这些类型是 10-16 岁儿童最常见的类型。数据是从许多数据源获得的。我们不使用任何类型的地理 API,如 Google Places 或 Foursquare,因为我们需要全面覆盖我们的研究领域。所有知名 API 都没有为免费账号提供这样的设施。

学校和教育中心

我们从教育、青年和体育部获得学校和教育中心的数据。这个 xml 数据集包含布拉格所有州立教育机构的信息。在我们的研究中,我们只对 poi 类型、地区和地理坐标感兴趣。

从原始教育数据集中,我们提取了教育设施的地址和类型,总共有 2273 行。类型是编码的。由于我们没有找到这个数据集的任何未来描述,我们必须决定什么类型的教育设施适合我们的研究。我们从检索到的数据中获得独特的类型:

Types in XML file
A00 Mateřská škola
L11 Školní jídelna
L13 Školní jídelna - výdejna
B00 Základní škola
M60 Přípravný stupeň základní školy speciální
G21 Školní družina
G22 Školní klub
F10 Základní umělecká škola
C00 Střední škola
D00 Konzervatoř
M20 Školní knihovna
E00 Vyšší odborná škola
M79 Jiné účelové zařízení
H22 Domov mládeže
G11 Dům dětí a mládeže
G40 Zařízení pro další vzdělávání pedagogických pracovníků
M40 Středisko praktického vyučování
H21 Internát
K20 Speciálně pedagogické centrum
G12 Stanice zájmových činností
K10 Pedagogicko-psychologická poradna
F20 Jazyková škola s právem státní jazykové zkoušky
J12 Dětský domov se školou
J21 Středisko výchovné péče
J14 Diagnostický ústav
J11 Dětský domov
J13 Výchovný ústav
L12 Školní jídelna - vývařovna
H10 Škola v přírodě
A15 Mateřská škola (lesní mateřská škola)
Schools and educational centers count 560
Unique types ['school' 'educatioanal center']

我们可以看到我们感兴趣的类型有:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对于建模步骤,我们对实际的场地地址不感兴趣,而是对坐标感兴趣。我们使用 ArcGis api 检索纬度和经度。学校和教育中心的结果数据集包含 560 行

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图书馆的数据从网站被废弃。作为数据清洗过程中,我们提取的地址和地区名称从原来的 html 页面。对于 html 解析,我们使用 BeautifulSoup 库。使用 ArcGis api 将地址转换为纬度和经度。结果数据集包含 41 个库。

体育中心、俱乐部和游乐场。

布拉格开放数据门户网站检索了体育设施和操场的数据。对于这些数据,我们执行与前面的数据集相同的步骤:提取地址和地区名称,将地址转换为纬度和经度。

我们将所有五个数据集合并成一个有 1623 行的数据集。数据集可在外部 GitHub 存储库上访问

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从开放街道地图(OSM)获得的街道网络数据 OSM 数据包含布拉格道路网络和周围连接的道路,这些是以长度为特征的线几何。这些可以用来构建一个可路由的拓扑图(有向的、加权的和连通的),它由节点和边组成,因此任何众所周知的路由搜索算法都可以应用[3]。布拉格的步行网络包含 140 822 个节点和 204 575 条链路。预处理数据我们存储在 IBM 云对象存储和 GitHub

4.探索性数据分析

布拉格的总人口约为 130 万。最高值在南区,从 110K 到 130K。所有人口高于平均值的地区都位于历史中心区周围。这些地区的平均人口是 7 万人。这是意料之中的。在像布拉格这样的城市里,大多数人离开市中心很近,但不在市中心。北部两个人口从 9 万到 10 万的最大地区向我们展示了布拉格新的发展区域。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从另一个角度分析布拉格的人口,我们可以注意到每 1000 名成人中儿童的分布与之前的情况相关。在这张图中,我们可以清楚地看到主要受家庭欢迎的地区。中心区和郊区的儿童死亡率最低,而中心附近但离中心不远的地区的儿童死亡率平均为每 1000 名成人 160 至 180 名儿童。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

儿童人口最多的前 10 个地区是以前图片中的前 10 个地区的重复。在布拉格,我们最多只有 8%。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

名胜古迹也集中在历史中心周围。按地区的分布与地区人口相关。这是预期值。我们在人口前 10 名的所有地区都有大致相等数量的点,在南部有一个异常的高度值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

兴趣点的总数并不能全面反映每个地区对儿童的益处。对我们来说,更有趣的是研究兴趣点的数量与 1000 名儿童之间的关系。比如我们看学校/1000 的直方图。我们注意到最高值与儿童数量无关。我们可以看到布拉格 1 的值最高,但如果我们看一下以前的图表,我们可以看到布拉格的儿童百分比甚至没有进入前 10 名。另一方面,布拉格 4 区的人口数值最高,学校/1000 的平均值也最高。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们可以在接下来的直方图中看到同样的图片。中心区的 POIs/1000 值最高,郊区最低。一方面,这是因为城市中心的儿童人口较少,另一方面,其他城市正从其历史中心发展起来,那里的学校和其他设施的密度通常较高。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.方法学

5.1 网络分析

这项研究的空间框架需要使用基于点的无障碍措施。常用的空间单位是行政区划和格网单元。由于研究区域从一个城市到一个国家,甚至整个世界,空间单元的类型、形状和大小因研究目的不同而有所差异,并且没有达成共识。在我们的研究中,使用布拉格的边界框作为空间框架。我们不能在研究中使用更小的框架,如行政区划,因为我们必须处理边界条件。如果儿童离开自己的地区,而最近的 POI 位于另一个地区。在这种情况下,父母通常会决定去最近的 POI。

第一步,我们将 OSM 街道网络转换成图形对象。对于构建图形,我们使用 Pandana 框架。Pandana 的主要用例是沿着网络执行聚合,即缓冲区查询。该 api 旨在以多线程方式(使用底层 C 库)同时为网络中的所有节点执行聚合。大多数步行规模的可访问性查询可以在不到一秒钟的时间内执行,甚至对于成千上万的节点也是如此。[4]

在“清理”中,我们指的是移除不代表实际交点的点(因此不是图论意义上的节点)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

街道图[6]

因为第二步是从上一步到网络图定位兴趣点并计算可达性矩阵。在可达性矩阵中,我们指的是从在数据采集步骤中采集的预定义兴趣点阵列到前 3 个兴趣点的距离阵列。因为我们想研究可达性的平均值,所以我们计算了每种兴趣点的平均步行距离:学校、图书馆和其他儿童设施。并将其存储到数据集。这个数据集稍后将用于聚类。我们总共得到 140877 条边

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们将使用 K-Means 聚类算法。这是一种矢量量化的方法,最初来自信号处理,在数据挖掘的聚类分析中很流行。k-means 聚类旨在将 n 个观察值划分为 k 个聚类,其中每个观察值属于具有最近均值的聚类,作为该聚类的原型。这导致将数据空间划分成 Voronoi 单元。k-Means 最小化类内方差(平方欧几里得距离)。确定我们使用的最佳聚类数和肘方法。

肘方法是一种启发式方法,用于解释和验证聚类分析中的一致性,旨在帮助在数据集中找到适当数量的聚类。它通常是不明确的并且不是非常可靠,因此用于确定聚类数量的其他方法,例如剪影方法是优选的。

这种方法将方差的百分比解释为聚类数的函数:应该选择多个聚类,这样添加另一个聚类不会提供更好的数据建模。更准确地说,如果绘制由聚类相对于聚类数量解释的方差的百分比,第一个聚类将增加很多信息(解释很多方差),但是在某个点,边际增益将下降,在图中给出一个角度。在这一点上选择簇的数量,因此称为“肘形标准”。这个“肘”不能总是被明确地识别。[1]解释的方差百分比是组间方差与总方差的比率,也称为 f 检验。该方法的一个微小变化是绘制组内方差的曲率。[2]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.2 可步行性集群

因此,我们有 4 个集群。我们计算每个集群的距离、可步行性核心和时间的平均值。我们所说的合理时间是指儿童行走 1300 米所需的时间。计算出每个聚类中每种类型的可步行性得分。分数=实际距离/1300。作为平均步行速度,我们得到 4 公里/小时[4]。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

通过重新定义行走图上边的权重,我们可以在布拉格地图上可视化聚类。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

此外,我们还为每种类型的兴趣点建立了可步行性热图。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.结果

因此,我们在布拉格有 4 个步行性集群。聚类 2 具有最佳步行性得分 1。这意味着,从这个集群内的每一个点,儿童都可以在平均大约 15 分钟内到达所有必要的兴趣点。学校在这个集群内是最容易到达的,这是一个非常好的结果。另一方面,集群 2 主要覆盖中心历史区,我们知道该区的儿童人口低于周边地区。第二组是 0 号。它的可行走性得分约为 1.3。学校和体育设施不到 10 分钟就能到达。这是非常好的结果。

这两个集群中可访问性得分最低的是图书馆和业余爱好中心。平均大约需要 30 分钟的步行时间。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们在第三组得到的最低值。该集群主要覆盖远离市中心的小郊区和地区,主要是小村庄。第三产业群内部的另一部分也坐落着许多新的开发项目

群组 1 我们决定将它算作噪声值,因为在这个群组中,我们主要有公园、墓地和工业区,换句话说就是非生活区。

最容易到达的兴趣点是学校,这是非常好的结果,因为根据不同的研究,到学校的步行距离在测量区域行人可达性方面具有最重要的价值。

结果也很好,我们有运动设施。除了第一组,其他组平均步行 10 分钟就能到达。

最低的可及性得分有业余爱好中心和图书馆,这是可预期的结果,因为我们像往常一样每个地区有一个这种类型的场所。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

7.讨论和结论

在这项研究中,我们分析了布拉格的步行性。我们主要关注 10-16 岁儿童的步行无障碍性。我们确定了所选焦点组的共同兴趣点,并对所有所选兴趣点的最短距离进行了测量。利用无监督聚类算法,我们将研究区域划分为 4 类。用统计分析的方法检验了聚类的结果。

在未来的研究中,我们计划对每种类型进行更详细的分析。我们必须根据地势给街道图的边缘增加权重。此外,我们不仅从最短路线的角度,也从最安全的角度来看待行人可达性。

8.参考

  1. 活生生的街道(行人协会)一份活生生的街道报告
  2. 比利时大龄青少年主动上学的标准距离和相关因素。德尔菲恩·范·戴克,伊尔莎·德·布尔多胡伊,问候卡顿
  3. 瑙曼和科瓦廖夫(2017 年)。基于 OpenStreetMap 的行人路径搜索。在智能交通系统和出行行为(第 87-96 页)。湛:斯普林格。
  4. pandanahttps://udst . github . io/pandana/introduction . html #简介
  5. 儿童行走的力学https://phys oc . online library . Wiley . com/doi/pdf/10.1113/jphysiol . 1983 . sp 014895
  6. OS mnx:Python for Street Networkshttps://geoffboeing . com/2016/11/OS mnx-Python-Street-Networks/

9.版权信息

安东·艾尔明 2019

开架借阅

本文根据知识共享署名 4.0 国际许可证(http://creativecommons.org/licenses/by/4.0/)的条款分发,该许可证允许在任何媒体上不受限制地使用、分发和复制,前提是您适当注明原作者和来源,提供知识共享许可证的链接,并指出是否进行了更改。

降低神经网络复杂性的预定义稀疏度

原文:https://towardsdatascience.com/pre-defined-sparsity-for-reducing-complexity-in-neural-networks-55b0e85a1b54?source=collection_archive---------16-----------------------

预定义稀疏度

神经网络现在非常流行。它们使深度学习成为可能,这为语音识别和无人驾驶汽车等智能系统提供了动力。这些酷的最终结果并没有真正反映大多数现代神经网络的血淋淋的复杂性,这些网络有数百万个参数需要被训练以使系统变得智能。训练需要时间和大量的计算资源,而这些资源通常会转化为金钱。这在富人和穷人之间形成了一个障碍,富人是拥有大量计算能力的大型科技公司,穷人是像我这样的博士生,他们负担不起在几天内培训几十个网络的费用。嗯,研究通常是出于需要。

我的博士工作试图以最小的性能下降来降低神经网络的复杂性。这是通过使用预定义稀疏度来完成的,从一开始,即在训练之前,就以低复杂度网络开始。

本文将解释和描述预定义的稀疏性。也鼓励你参考我最近的论文了解更多细节:

基本概念

神经网络由节点(或神经元)组成,这些节点被分组到中,并使用加权边填充层之间的结点进行连接。本文的大部分内容将涉及多层感知器(MLPs),而我正在进行的工作是扩展到卷积神经网络(CNN)。如图所示,如果一个层中的每个节点都连接到其相邻层中的每个节点,则 MLP 是全连接的 (FC)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

A fully connected MLP with neuronal configuration Nnet = (8,4,4) denoting the number of neurons in each layer. Each edge has an associated weight value, only a few of them are shown for clarity.

文献中的几种复杂性降低技术训练 FC 网络,然后删除它的一些权重,以获得用于测试阶段的更简单的网络。相比之下,我的预定义稀疏性工作中的“前”来自于这样一个事实:稀疏连接模式在训练之前是固定的。因此,对于训练和推断都获得了复杂度降低,并且可以通过查看稀疏网络相对于 FC 的权重密度来量化复杂度降低。例如,下面的网络在交叉点 1 的 ρ₁ = 25%密度,在交叉点 2 的 ρ₂ = 50%,在整个网络中 ρ net = 33% 总密度。这意味着 FC 网络将具有 48 个权重,而预定义的稀疏网络具有 16 个权重。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

请注意,特定层中的每个节点都有相同数量的向右连接(出度 dout ) —第一个结点为 1,第二个结点为 2,并且两个结点都有相同数量的来自左侧的连接(入度 din ) — 2。这意味着稀疏连接模式是结构化的,而不是随机分配权重,冒着让一些节点完全断开的风险。事实上,我的结果表明结构化稀疏比随机稀疏表现更好。

有用吗?如果是,为什么?它有什么独特之处?

我用来测试我的工作的分类数据集是 MNIST 手写数字,路透社 RCV1 新闻文章, TIMIT 语音音素识别,以及 CIFAR -10,-100 图像识别。预定义的稀疏度给出了有希望的结果,如下所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

旁边的结果是 MNIST(上)和路透社(下)。x 轴是总密度,因此最右边 100%的圆圈点是 FC 网络。y 轴是测试准确度,这是神经网络常用的性能指标。请注意,20%密度点的精度仅比 FC 低 1%左右。换句话说,权重的数量可以减少 5 倍,而性能下降很少,这正是我的研究旨在实现的目标。

现在让我们来解决一个更大的问题:为什么预定义的稀疏性有效。这不可能是一种魔法,它使我们能够从一开始就将 FC 网络的重量减少 80%,同时几乎没有性能损失(补充说明:深度学习中的许多东西看起来确实像魔法,但电视刚推出时也是如此)。为了理解这一点,我在对一个全连接网络进行训练直至其收敛后,绘制了该网络不同连接点的权值直方图。请注意大多数权重都接近 0 。这表明一个网络可能不需要太多的权重就能变好。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们暂时考虑一下正则化的标准技术。这对网络的权重施加了惩罚,使得它们在训练期间受到限制。预定义的稀疏度也施加约束,除了它对权重的数量施加约束,并且在训练之前施加约束。另一种流行的技术——辍学——也在训练期间删除连接。然而,它在不同的随机配置中这样做,并在组合它们进行测试之前训练所有这些候选网络。相比之下,预定义的稀疏度只在一个网络上训练和测试,这个网络恰好具有少得多的权重。

表征预定义的稀疏性

预定义的稀疏连接模式——哪些节点连接到哪些节点——是要在训练之前设置的超参数。我的研究发现了几个趋势,作为选择这个超参数的指南。

首先,预定义的稀疏性利用了数据集中的冗余。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

首先,大多数机器学习数据集都有冗余。以经典的 MNIST 为例,每幅图像有 28×28 = 784 个像素。做一个主成分分析表明只有中心像素是有趣特征集中的地方,这并不奇怪。这意味着,通过考虑,比如说,每幅图像中心附近的 200 个承载最多信息的像素,可以获得修改的减少冗余的 MNIST 数据集。

下图比较了原始数据集(黑色)的预定义稀疏性与增加(红色)或减少(蓝色)冗余的相同数据集的修改版本的性能。请注意,稀疏网络对于减少冗余的情况并不那么有效,即蓝线在密度减少的情况下向左侧下降。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Tokens for Reuters and MFCCs for TIMIT serve as features. For CIFAR, the depth of the pre-processing CNN before the MLP serves as redundancy.

其次,后面的连接需要更高的密度。

这是我们之前在重量直方图中看到的。与 W 4 相比,更早的连接( W 1、 W 2、 W 3)在量值上具有更多接近 0 的权重,这表明稀疏连接模式应该尝试在更晚的连接中具有更多权重,在更早的连接中具有更少权重。实验结果证实了这一点,为了简洁起见,我没有在这里展示。

第三,“大而稀疏”的网络比具有相同数量参数的“小而密集”的网络表现更好。

之前,当我提到“一个网络可能不需要太多权重就能变好”时,您可能会想,如果我们从一个小型 FC 网络开始,即拥有较少节点,会发生什么情况?答案是,它的性能将不如预定义的具有更多节点和相同数量权重的稀疏网络。这表明,小网络不是解决方案,最好有大的传统网络,并消除重量。

下图显示了在 MNIST 进行的 4 结点网络培训。根据输入要素和输出标注的数量,输入和输出图层分别具有 784 个和 10 个结点。3 个隐藏层具有相同的节点数 x ,这是可变的。这些预定义稀疏网络的总密度被设置为使得对于不同的 x 值,不同的网络具有相同数量的权重。例如, x =14 的 FC 网络与 x =28 的 50%密集网络、 x =56 的 22%密集网络和 x =112 的 10%密集网络具有相同的权重数(大约 11000)。这些是蓝色椭圆内的点。请注意 x =112 的情况如何在这些情况中表现最佳。然而,这种趋势在密度非常低的情况下失败了(意味着密度为 4%且 x =224 的网络表现稍差),然而,一般来说,在参数数量相同的情况下,“大而稀疏”的网络比“小而密集”的网络表现更好。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Each line with a single color denotes a particular value of x, i.e. a particular network architecture. The shading denotes 90% confidence intervals, since test accuracies are not exactly the same across different runs. Each marker of a certain shape denotes a particular number of total weights (i.e. trainable parameters) in the network.

预定义稀疏性的应用和扩展

我们的一些前期工作详细介绍了一种硬件架构,该架构利用预定义稀疏性减少的存储和计算复杂性来训练和测试 FPGAs 上的网络。从机器学习的硬件加速的角度来看,这是有前途的。

我个人的努力已经转向模型搜索领域。模型搜索,包括神经结构搜索(NAS) 和超参数搜索,基本上试图自动发现一个给定问题的好的神经网络。虽然“好”通常指的是高精度,但这种网络通常非常复杂,有几十层。我目前的研究集中在低复杂度网络的模型搜索,它也表现良好。换句话说,这是一个优化问题,目标 f 为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

fp and fc are functions to measure the performance and complexity of a network. wc denotes the amount of importance given to minimizing complexity. Its effect is shown below.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个领域还扩展了低复杂度的技术来考虑 CNN。例如,可以将滤波器核预定义为稀疏的,或者可以增加步长以减少训练时间。这些细节将在另一篇研究文章中介绍。

伙计们,现在就到这里吧!如果你对预定义稀疏度及其应用感兴趣,可以在这里找到代码。为了直观地了解我在神经网络方面的研究,请看这个视频

Sourya Dey 是南加州大学的博士生。他的研究涉及探索深度学习中的复杂性降低。你可以在他的网站上了解更多关于他的信息。

使用管道预处理数据,以防止交叉验证期间的数据泄漏。

原文:https://towardsdatascience.com/pre-process-data-with-pipeline-to-prevent-data-leakage-during-cross-validation-e3442cca7fdc?source=collection_archive---------7-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

image source: http://www.securitymea.com/2018/04/25/data-leakage-has-gone-up-by-four-times/

在机器学习中, K 重交叉验证是一种常用的验证技术,用于评估统计模型的结果如何推广到一个未知的数据集。它通常用于估计模型的预测能力。今天我想讨论一下使用 StandardScaler 等数据预处理器进行交叉验证时的一个常见错误。

错误

让我们通过检查下面的代码来识别错误。我用两个红框突出了要讨论的部分。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在第一个红色框中,使用标准缩放器对训练集进行拟合和转换,对测试集进行转换(不拟合)。这似乎是正确的,因为训练集和测试集都是由标准定标器仅使用来自训练集的信息进行标准化的(测试集是不可见的)。

第二个红框突出显示了由 GridSearchCV 执行的 5 重交叉验证,以在拟合数据时基于标准化的训练集选择最佳模型。问题来了,但是让我先后退一步,简单回顾一下 GridSearchCV 是如何执行交叉验证的。 GridSearchCV 将训练集分为内部训练集和验证集。对于 5 重交叉验证,内部训练集与验证集的数据比为 4: 1。该过程重复四次,从而覆盖整个列车组(见下图)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

https://scikit-learn.org/stable/modules/cross_validation.html

现在让我分四步来讨论这个问题:

  1. 交叉验证的目的是估计预测能力,因此验证集应被视为临时的不可见测试集。
  2. 标准刻度不应与临时测试装置相匹配。然而,因为我们给 GridSearchCV 配备了一个预处理过的列车组,不幸的是,临时测试组配备了标准刻度,因此泄露了。
  3. 临时测试集的方差被人为地去除,因此得到的交叉验证分数是有偏差的。
  4. GridSearchCV 根据交叉验证分数决定模型参数,可能无法找到减轻过拟合的最佳模型。

我从我在大会上学习的数据科学沉浸式项目的顶点项目中注意到了这个问题的重要性。该项目旨在使用 Kaggle 提供的经典威斯康星大学乳腺癌细胞(诊断)数据集建立分类模型,对乳腺癌细胞进行分类。该项目的第一部分是复制 1994 年由威斯康星大学教授 Olvi L. Mangasarian、W. Nick Street 和 William H. Wolberg 出版的《通过线性规划进行乳腺癌诊断和预后》中讨论的乳腺癌诊断模型。因为数据集很小(即 569 个样本),所以模型的预测能力仅基于交叉验证分数进行估计(而不是分成训练集、开发集和测试集三部分)。

解决方案

幸运的是,有一个简单的解决方案。通过简单地将预处理器和估计器放入流水线,我们可以避免 GridSearchCV 的这种不希望的结果。参见下面的代码:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为了演示 Pipeline 如何正确地解决问题(fit _ transform only the inner train set withstandard scaler),我想引用 Shihab Shahriar(经他允许)对我在 Stackoverflow.com 上发布的问题的惊人回应。通过使用 cross_val_score 仅查看 GridSearchCV 的交叉验证部分,进一步简化了响应。该演示使用了乳腺癌数据集(569 个样本)。

1.子类 StandardScaler 打印发送给 fit_transform 方法的数据集的大小。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.将类放到管道中,并通过 cross_val_score 进行 5 重交叉验证。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3.输出显示,只有 80%的数据集(569 * 80%)符合 cross_validation_score 并已转换。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我要特别感谢 Shihab,他的解决方案让读者受益匪浅。我在 Stackoverflows.com 上发布的最初的问题集中在交叉验证期间管道是否与预处理程序一起正常工作。Shihab 不仅给出了解决方案,还讨论了不同估计器对预处理器输出的敏感性,这也可能回答您的一些其他问题。如果你感兴趣,点击此处查看整个讨论。

结论

这篇博客文章的要点是,每当需要数据预处理程序如标准缩放器PCA (即主成分分析)来构建机器学习模型时,确保使用管道来进行模型调整的交叉验证。同样,我们的最终目标是建立一个机器学习模型,它将推广到一个看不见的数据集。因此,我认为在交叉验证过程中防止数据泄漏确实很重要。希望这个帖子有帮助~。

为 NLP 模型训练预处理 Wikipedia 转储—书面报告

原文:https://towardsdatascience.com/pre-processing-a-wikipedia-dump-for-nlp-model-training-a-write-up-3b9176fdf67?source=collection_archive---------18-----------------------

下载、提取、清理和预处理 NLP 模型的维基百科转储(例如,像 BERT、RoBERTa 等的变压器)。)培训

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Wikipedia entry for Bert (from Sesame Street)

Wikipedia dumps在现代 NLP 研究中被频繁用于模型训练,尤其是与变形金刚如 BERT、RoBERTa、XLNet、XLM 等。因此,对于任何有志于掌握这些模型的 NLP 研究人员来说,这篇文章展示了下载、提取、清理和预处理维基百科转储所涉及的一切(和代码)。

📥下载维基百科转储

维基百科转储以多种语言的多种格式免费提供。对于英语维基百科,最新转储的所有可用格式的完整列表可以在这里找到。

因为我们主要对文本数据感兴趣,所以为了本文的目的,我们将使用下面的代码下载这样一个压缩 XML 格式的转储(只包含页面和文章):

Simple bash script to download the latest Wikipedia dump in the chosen language

例如,要下载最新的英语维基百科转储,只需在终端中运行以下命令:./download_wiki_dump.sh en

🗜️提取和清理维基百科转储

我们刚刚下载的维基百科转储还不能进行预处理(句子标记和每行一句)。首先,我们需要提取并清理转储,这可以通过使用下面的代码使用 WikiExtractor轻松完成:

Simple bash script to extract and clean a Wikipedia dump

例如,要提取并清理我们刚刚下载的 Wikipedia 转储,只需在您的终端中运行以下命令:./extract_and_clean_wiki_dump.shenwiki-latest-pages-articles.xml.bz2

⚙️预处理维基百科转储

既然我们已经成功地下载、提取和清理了维基百科转储,我们可以开始预处理它了。实际上,这意味着对文章进行句子标记,以及将它们每行一句地写到一个文本文件中,这可以使用微软速度惊人的bling fire tokenizer来完成,使用下面的代码:

例如,要预处理我们刚刚提取和清理的 Wikipedia 转储,只需在您的终端中运行以下命令:python3 preprocess_wiki_dump.pyenwiki-latest-pages-articles.txt

****就这样,大功告成!🙌现在,您可以使用自己新创建的维基百科语料库,亲自尝试 NLP 中最新最棒的内容。🤗

OCR 中的预处理!!!

原文:https://towardsdatascience.com/pre-processing-in-ocr-fc231c6035a7?source=collection_archive---------0-----------------------

OCR 系统最广泛使用的预处理技术的基本解释。

欢迎来到关于 OCR 系统工作的系列第二部分 。在 之前的文章 中,我们简要讨论了 OCR 系统的不同阶段。

在 OCR 的所有阶段中, 预处理分割 是最重要的阶段,因为 OCR 系统的准确性很大程度上取决于预处理分割的执行情况。因此,在这里我们将学习一些最基本和最常用的图像预处理技术。

我们走吧…

预处理阶段的主要目的是 使 OCR 系统尽可能容易地 从背景中辨别出字符/单词。

一些最基本和最重要的预处理 技术有

1)二值化
2) 倾斜校正
3) 去噪
4) 细化和骨架化

在讨论这些技术之前,让我们先了解一下 OCR 系统是如何理解图像的。对于 OCR 系统,图像是多维数组(如果图像是灰度(或)二进制,则为 2D 数组,如果图像是彩色的,则为 3D 数组)。矩阵中的每个单元称为一个像素,它可以存储 8 位整数,这意味着像素范围是 0-255。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Internal Representation of RGB image with Red, Green and Blue Channels. Source: left image from semantics scholar, right image from researchgate.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Internal Representation of Grayscale image. It has only one channel. Source: ekababisong.org

让我们逐一检查上面提到的每一种预处理技术

  1. 二值化: 通俗地说二值化就是将彩色图像转换成只由黑白像素组成的图像(黑色像素值=0,白色像素值=255)。作为一个基本规则,这可以通过固定一个阈值来实现(通常阈值=127,因为它正好是像素范围 0–255 的一半)。如果像素值大于阈值,则认为是白色像素,否则认为是黑色像素。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Binarization conditions. Source: Image by author

但是这种策略并不总是给我们想要的结果。在图像中光照条件不均匀的情况下,这种方法会失败。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Binarization using a threshold on the image captured under non-uniform lighting. Source: left image from this post and right image binarised by author.

所以,二值化的关键部分是确定 阈值 。这可以通过使用各种技术来完成。

局部最大最小值法:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Imax= Maximum pixel value in the image, Imin= Minimum pixel value in the image, E = Constant value Source: Reference [2]

C(i,j) 是图像中局部 定义尺寸阈值(如 10x10 尺寸的零件)。使用这种策略,我们将为图像的不同部分设置不同的阈值,这取决于周围的光照条件,但是过渡并不平滑。

Otsu 的二值化:该方法考虑到整个图像的各种特征(如光照条件、对比度、锐度等),为整个图像给出一个阈值,该阈值用于二值化图像。
这可以通过以下方式使用 OpenCV python 来实现:

ret, imgf = cv2.threshold(img, 0, 255,cv2.THRESH_BINARY,cv2.THRESH_OTSU) #imgf contains Binary image

-> 自适应阈值处理:这种方法根据图像的局部和邻居的特征,为图像的一小部分给出一个阈值,也就是说,对于整个图像没有单一的固定阈值,但是图像的每一小部分根据局部都有不同的阈值,并且还提供平滑过渡。

imgf = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2) #imgf contains Binary image
  1. 歪斜校正: 扫描文件时,有时可能会出现轻微歪斜(图像与水平面成一定角度)。从扫描图像中提取信息时,检测&校正倾斜是至关重要的。
    多种技术用于倾斜校正。

→投影轮廓法
→霍夫变换法
→背线法
→扫描线法

然而,投影轮廓方法是确定文件倾斜的最简单、最容易和最广泛使用的方法。

在这个方法中,首先,我们将二进制图像,然后

  • 将其水平投影(取图像矩阵各行的像素总和)以获得图像高度的像素直方图,即每行的前景像素计数。
  • 现在,图像以各种角度旋转(以称为 Delta 的小角度间隔),并且将计算峰值之间的差异(方差也可以用作度量之一)。找到峰值之间的最大差(或方差)的角度,该对应角度将是图像的倾斜角度
  • 找到歪斜角后,我们可以通过在歪斜的 相反方向 旋转图像一个等于歪斜角的角度来校正歪斜。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Correcting skew using the Projection Profile method. Source: Reference[1]

import sys
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image as im
from scipy.ndimage import interpolation as interinput_file = sys.argv[1]img = im.open(input_file)# convert to binary
wd, ht = img.size
pix = np.array(img.convert('1').getdata(), np.uint8)
bin_img = 1 - (pix.reshape((ht, wd)) / 255.0)
plt.imshow(bin_img, cmap='gray')
plt.savefig('binary.png')def find_score(arr, angle):
    data = inter.rotate(arr, angle, reshape=False, order=0)
    hist = np.sum(data, axis=1)
    score = np.sum((hist[1:] - hist[:-1]) ** 2)
    return hist, scoredelta = 1
limit = 5
angles = np.arange(-limit, limit+delta, delta)
scores = []
for angle in angles:
    hist, score = find_score(bin_img, angle)
    scores.append(score)best_score = max(scores)
best_angle = angles[scores.index(best_score)]
print('Best angle: {}'.formate(best_angle))# correct skew
data = inter.rotate(bin_img, best_angle, reshape=False, order=0)
img = im.fromarray((255 * data).astype("uint8")).convert("RGB")
img.save('skew_corrected.png')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Skew Correction. Source: pyimagesearch.com by Adrian Rosebrock

  1. 噪声去除:噪声去除阶段的主要目的是通过去除比图像其余部分具有更高亮度的小点/小块来平滑图像。可以对彩色二进制图像进行噪声去除。
    使用 OpenCV
    fastNlMeansDenoisingColored
    函数进行去噪的一种方法。
import numpy as np 
import cv2 
from matplotlib import pyplot as plt 
# Reading image from folder where it is stored 
img = cv2.imread('bear.png') 
# denoising of image saving it into dst image 
dst = cv2.fastNlMeansDenoisingColored(img, None, 10, 10, 7, 15) 
# Plotting of source and destination image 
plt.subplot(121), plt.imshow(img) 
plt.subplot(122), plt.imshow(dst) 
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Smoothening and Denoising of image. Source: Reference [4]

更多关于去噪&图像平滑的技巧可以在 这篇 的精彩文章中找到

  1. 细化和骨架化 :这是一个可选的预处理任务,取决于使用 OCR 的上下文。
    →如果我们对打印文本使用 OCR 系统,则无需执行此任务,因为打印文本始终具有统一的笔画宽度。
    →如果我们使用 OCR 系统处理手写文本,则必须执行此任务*,因为不同的书写者有不同的书写风格,因此笔画宽度也不同*。所以为了使笔画的宽度一致,我们必须执行细化和

这可以通过以下方式使用 OpenCV 来实现

import cv2
import numpy as npimg = cv2.imread('j.png',0)
kernel = np.ones((5,5),np.uint8)
erosion = cv2.erode(img,kernel,iterations = 1)

在上面的代码中,图像的细化取决于内核大小和迭代次数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Before and After Thinning and Skeletonization. Source: datacamp

在本文中,我们看到了一些基本的和最广泛使用的 预处理 技术,这让我们对 OCR 系统内部发生的事情有了一个基本的了解。下图是 预处理 工作流程的一个例子。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Source: Reference [5]

我希望你已经了解了在 OCR 中 预处理 是如何执行的。

延伸阅读:

part-III中,我们将看到 OCR 系统所使用的分割技术。

快乐学习!!!!

欢迎任何疑问、建议和更正。😃

参考资料:

*[1] Shafii,m .,Sid-Ahmed,m .基于轴平行包围盒的倾斜检测和校正。伊达尔 **18,*59–71(2015)。https://doi.org/10.1007/s10032-014-0230-y

[2] Jyotsna,S. Chauhan,E. Sharma 和 A. Doegar,“退化文档图像的二值化技术——综述”, 2016 年第五届可靠性、信息通信技术和优化国际会议(趋势和未来方向)(I rito),诺伊达,2016,第 163–166 页,doi:10.11109/I rito . 20136106

[3] A. Papandreou 和 B. Gatos,“一种基于垂直投影的新型倾斜检测技术”, 2011 年国际文档分析与识别会议,北京,2011,第 384–388 页,doi: 10.1109/ICDAR.2011.85

[4] K. Lin,T. H. Li,S. Liu 和 G. Li,“使用噪声域适应和注意力生成对抗网络的真实照片去噪”, 2019 年 IEEE/CVF 计算机视觉和模式识别研讨会会议(CVPRW) ,美国加利福尼亚州长滩,2019 年,第 1717-1721 页,doi: 10.1109/CVPRW.2019.00221

[5] Choudhary,Amit & Rishi,Rahul & Savita,Ahlawat。(2013).一种新的脱机手写草书字符分割方法。计算机科学。17.88–95.10.1016 年 5 月 13 日

预先训练的语言模型:简化

原文:https://towardsdatascience.com/pre-trained-language-models-simplified-b8ec80c62217?source=collection_archive---------18-----------------------

NLP 世界的芝麻街

什么是预训练语言模型?

预先训练的语言模型背后的直觉是创建一个黑盒,让理解该语言,然后可以要求它用该语言做任何特定的任务。这个想法是创造一个相当于“博学”的人的机器。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

语言模型首先被输入大量未标注的数据(例如,完整的维基百科转储)。这让模型学习各种单词的用法以及语言的一般写法。该模型现在被转移到 NLP 任务,在那里它被馈送给另一个更小的特定于任务的数据集,该数据集用于微调和创建能够执行前述任务的最终模型。

为什么它们比以任务为中心的模型更好?

一句话:*他们更好读!!*仅在特定于任务的数据集上训练的模型需要使用相对较小的数据集来理解语言和任务。另一方面,语言模型已经理解该语言,因为它在预训练期间已经“读取”了大量的语言转储。因此,语言模型可以直接微调自身以匹配所需的任务,并且比现有的 SOTA 执行得更好。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

嵌入与微调

NLP 中的每个单词都需要用数学表示,以便让机器做进一步的处理。你可以通过我之前关于分布式向量表示的博客获得更多的直觉…

[## 分布式矢量表示:简化

可以说是机器学习中最基本的特征表示方法

towardsdatascience.com](/distributed-vector-representation-simplified-55bd2965333e)

已经提出了许多不同的算法来创建这些嵌入,通过在单独的较大数据集上预先训练模型来捕捉语言的本质。例如,Word2Vec 嵌入获得了难以置信的流行,这些嵌入直接用于 NLP 中的许多任务。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然而,这些单词表征是在广义的上下文中学习的,并不代表特定任务的信息。这就是语言模型的微调部分要考虑的地方。直接使用预先训练的嵌入可以减小整个模型的大小,但是迫使我们只能使用一般化的单词表示。另一方面,语言模型微调允许用户通过在特定于任务的数据集上进行训练来微调这些单词嵌入/表示。

例如,在广义的上下文中,单词“当前”的表示可能与“新闻”和“电”都有良好的关系。然而,对于涉及电路的特定任务,允许模型微调单词表示,使得“电流”和“电”更好地匹配,可以帮助提高模型性能。

伯特

BERT(变形金刚的双向编码器表示)是由 Google 在去年提出的,它能够单枪匹马地在 11 个独立的 NLP 任务上实现 SOTA 性能!!从那以后,它成为了多种语言模型的来源。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

该模型的成功主要归功于文中提出的训练方法。这两个训练协议,即“掩蔽 LM”和“NSP:下一句预测”(后来被改进为“SOP:句序预测”),帮助 BERT 从可用的庞大语言语料库中学习。

“屏蔽 LM”任务是通过在每个句子中随机屏蔽 15%的单词并训练模型来预测它们来实现的。“SOP”任务是具有两个句子输入的分类任务,并且该模型被期望识别这两个句子之间的原始顺序,这增加了它的文档级理解。这些训练任务产生的影响和 BERT 的内部工作需要更详细的分析,我现在不打算深入讨论。

下一步是什么?

虽然语言模型的不同变体开始主导各种 NLP 任务,但每个人都开始意识到两个重要的事实。第一,尽管最初的伯特模型有正确的想法,但它缺乏训练,因此具有难以置信的未开发的潜力。第二,像 BERT 这样的预训练语言模型的巨大规模是这些模型未来研究和部署的一大障碍。看来这两个主要问题需要在这个领域向前发展之前得到回答。

这个博客是努力创建机器学习领域简化介绍的一部分。点击此处查看完整系列

[## 机器学习:简化

在你一头扎进去之前就知道了

towardsdatascience.com](/machine-learning-simplified-1fe22fec0fac)

或者干脆阅读系列的下一篇博客

[## 卷积核的类型:简化

对迷人的 CNN 层的不同变化的直观介绍

towardsdatascience.com](/types-of-convolution-kernels-simplified-f040cb307c37)

参考

[1]瓦斯瓦尼、阿希什等,“你所需要的只是关注。”神经信息处理系统进展。2017.
【2】Devlin,Jacob 等《Bert:语言理解的深度双向变换器预训练》。arXiv 预印本 arXiv:1810.04805 (2018)。
[3]彼得斯、马修·e 等,“深度语境化的词语表征”arXiv 预印本 arXiv:1802.05365 (2018)。
[4] Mikolov,Tomas 等,“单词和短语的分布式表示及其组合性”神经信息处理系统进展。2013.
[5]刘,,等.“Roberta:一种鲁棒优化的 bert 预训练方法”arXiv 预印本 arXiv:1907.11692 (2019)。

预训练单词嵌入还是嵌入层?—进退两难

原文:https://towardsdatascience.com/pre-trained-word-embeddings-or-embedding-layer-a-dilemma-8406959fd76c?source=collection_archive---------5-----------------------

预训练单词嵌入和嵌入层对语义 NLP 任务绩效影响的比较

当单词嵌入在近十年前变得可用时,它们永远地改变了自然语言处理(NLP)。正如 Ronan Colobert 等人在他们 2008 年著名的 JMLR 论文中所说,他们“几乎从零开始”重新开发了 NLP。几年后,在 2013 年,随着 Mikolov 等人(2013)word2vec 库的发布,它们迅速成为文本数据矢量化的主导方法。基于传统矢量化方法(如 LSI 和 TF-IDF)已经得到充分研究的 NLP 模型正在接受单词嵌入的测试,在大多数情况下,单词嵌入处于领先地位。此后,开发了许多嵌入方法。此外,主要的深度学习(DL)包包含一个学习特定任务嵌入的嵌入层。

虽然我找到了一些比较不同类型的预训练单词嵌入的性能的研究,但我找不到任何将预训练单词嵌入的性能与嵌入层的性能进行比较的综合研究。然而,当我开始为 NLP 实现一个新的 DL 模型时,这是我问自己的第一个问题。为了回答这个问题,我进行了几个实验,以便比较预训练的单词嵌入和嵌入层对 DL 模型在两个语义任务(即情感分析和问题分类)上的性能的影响。但是首先,让我们回顾一下单词嵌入背后的基本思想,并简要回顾一下它们的历史。

根据一个人交的朋友来判断这个人

为什么单词嵌入比传统的单词向量更好,这超出了本文的范围。然而,它们是基于 20 世纪 50 年代发明的丰富的语言学理论,叫做分布假设。该理论通过观察上下文来定义一个词的语义。

“从一个人交的朋友,你就可以知道这个人是谁。”约翰·r·弗斯(20 世纪语言学的领军人物)

林(1998 )用一个很少见的专有名词 T ezgüino 来说明这个概念,很多人都不熟悉。然而,只要我们在上下文中看到它,就很容易推断出来:“桌子上有一瓶 T ezgüino 。Tezgü ino 让你醉了。换句话说,即使你不知道tez guino的意思,它的上下文也阐明了它的意思。

单词嵌入简史

传统上,提出了许多基于统计和规则的模型,试图对分布语义进行建模。主要地,为语料库中出现的所有单词创建共现矩阵,然后使用诸如 LSA 的方法将该矩阵投影到小得多的空间中。传统模型的详细讨论超出了本文的范围,但是,它可以为单词和短语的语义以及无监督单词向量的底层概念提供有价值的见解。相关工作见 Mitchell 和 Lapata (2008)Katrin Erk (2010 ),以及 Katz 和 Giesbrecht (2006 )。

直到 2003 年,Yoshua Bengio et al. (2003) 研究了学习半监督单词嵌入的想法。在他们的工作中,作者提出了一种神经网络,它学习单词序列的概率函数(语言模型的主要目标),同时学习每个单词的分布表示。他们将输入的权重作为单词嵌入引入神经网络的隐藏层。然而,主要由于 Softmax 输出层,他们的模型在计算上是昂贵的,并且远离实际。该模型的目标是学习一个函数,该函数在给定观察到的单词序列的情况下预测良好的条件概率分布:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

网络的架构如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure from Bengio et al. 2003. The proposed architecture for learning word representations.

其中 C(i) 是词汇表中 i^th 单词的表示。输出层会计算每个单词在整个词汇表中的条件概率分布,这导致模型不切实际:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其中 N 是 Softmax 层之前的网络。这个模型的计算复杂性问题由 Collobert 等人(2008) 提出,他们提出了一个使用不同目标函数的卷积神经网络。与 Bengio 等人(2003) 不同,他们主要关心的不是语言建模,而是学习好的单词嵌入。因此,他们有更多的自由来达到这个目标。他们受益于正在学习的单词前后的上下文。尽管该模型产生了(第一个)无监督的单词嵌入,其结合了语义和句法信息,但是它仍然是计算昂贵的。由于之前模型的高计算成本,直到 2013 年 Mikolov 等人(2013) 提出了他们简单而有效的模型,普及了单词嵌入,并开始渗透到 NLP 中。

他们提出了两种计算单词嵌入的架构:连续词袋(CBOW)和跳格(SG)模型。下图说明了 CBOW 模型,其中使用上下文( w_{i-2},w_{i-1},w_{i+1},w_{i+2} )来预测目标单词( w_i ):

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The architecture of CBOW word embedding model

另一方面,SG 模型试图从给定的单词中预测上下文。如上所述, Mikolov 等人(2013) 的 CBOW 模型与之前的工作相比具有更简单的架构,从而降低了该模型的计算成本。这个模型的实现( word2vec )促进了跨 NLP 不同领域的单词嵌入的广泛实验。显示使用单词嵌入的实验导致了大多数 NLP 任务的改善(巴隆尼等人(2014)米科洛夫等人(2013)亚兹达尼和波佩斯库-贝利(2013) )。在过去的几年中,提出了许多其他嵌入方法,如手套、ELMO 和多义词嵌入,以及许多其他模型。

那么…嵌入层还是预先训练的单词嵌入?

今天,我们可以通过高效的工具,如 fastText 立即创建特定于语料库的单词嵌入。我们也可以在我们的网络中使用一个嵌入层来训练关于手边问题的嵌入。

然而,每当我必须为一个特定的 NLP 任务建立一个新的模型时,我首先想到的问题之一是我是否应该使用预先训练的单词嵌入或嵌入层。

虽然类似于人工智能中的大多数问题,这个问题可能没有在每个场景中都适用的普遍正确的答案,但在这里,我试图根据经验回答这个问题。

我研究了上述两种嵌入对两种语义 NLP 任务绩效的影响。即情感分析问题分类并提供预训练单词嵌入和嵌入层之间的比较。

模型架构

我创建了一个具有两个卷积层的 CNN,并在下面的实验中使用了这个架构。对于预训练的嵌入实验,我用预训练的嵌入替换这一层的参数,维护索引并冻结这一层,防止它在梯度下降的过程中被更新。

超参数

为了能够仅控制嵌入类型,我修正了以下超参数,并使用完全相同的超参数进行实验:

数据

情感分析:IMDB 数据集
问题分类:TREC 数据集

预训练向量

  1. GloVe ( glove.42B.300d ):在 42B 令牌通用抓取语料库上训练的 300 维向量
  2. fast text WIKI(WIKI-news-300d-1M):在 16B 令牌维基百科 2017 转储上训练的 300 维向量

估价

我用(I)训练损失,(ii)混淆矩阵,(iii)精确度(宏观平均),回忆(宏观平均)和不同类型嵌入的 F1 分数来说明我的发现。

任务 1:情感分析

情感分析(也称为极性检测和观点挖掘),是指识别给定文本的极性或情感。情感通常用积极、消极和中性的标签来量化。我正在用来自 torchtext.datasets 的 IMDB 数据集进行实验,其中情感用 0 和 1 表示。下图显示了不同模型的训练损失和混淆矩阵结果。

嵌入层

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Confusion Matrix and Training Loss for the Model with an Embedding Layer

预训练单词嵌入

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Confusion Matrix and Training Loss for the Model with Pre-trained IMDB vectors

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Confusion Matrix and Training Loss for the Model with Pre-trained Glove vectors

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Confusion Matrix and Training Loss for the Model with Pre-trained WIKI vectors

如上所述,**与基于嵌入层的模型相比,所有三个预训练的基于嵌入的模型的训练损失衰减得更快。**此外,对于类别 1,预训练的基于嵌入的模型的精度始终较高。总精确度和召回率,以及 F1 分数如表 1 所示。如所见,预训练的基于嵌入的模型始终优于基于嵌入层的模型,尽管差距很小。

Table 1. The overall precision, recall, and F1 score for Sentiment Analysis task

任务 2:问题分类

问题分类的任务是给问题分配一个语义类别标签,以便更容易找到问题的答案。我使用了来自 torchtext.datasets 的 TREC 数据集,该数据集包括来自 6 个 TREC 类的问题,即缩写、实体、描述、位置和数值。

下图说明了不同模型的训练损失以及测试集在混淆矩阵方面的性能:

嵌入层

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

预训练单词嵌入

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Confusion Matrix and Training Loss for the Model with Pre-trained TREC vectors

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Confusion Matrix and Training Loss for the Model with Pre-trained Glove vectors

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Confusion Matrix and Training Loss for the Model with Pre-trained WIKI vectors

基于嵌入层的模型和预训练的基于嵌入的模型的训练损失衰减相对较快并且没有太多波动。没有观察到训练损失之间的显著差异。另一方面,除了在 TREC 问题数据集上训练的嵌入之外,所有基于预训练嵌入的模型的总体精度、召回率和 F1 分数都有所提高。这是意料之中的,因为 TREC 是一个包含简短问题的小数据集,因此,在该数据集上训练的向量可能不会携带太多语义信息。对于其他预训练的基于嵌入的模型,即 Glove 4B 和 fastText WIKI,几个类的性能都有相当大的提高。例如,在 ABBR,正确分类实例的百分比从 82%增加到 92-93%。或 LOC,其中正确分类的实例的百分比从 84%增加到 90-96%。下表列出了不同模型的总体精度、召回率和 F1 值。

在家上课

查看 IMDB 情感分析任务的结果,**似乎预先训练的单词嵌入导致更快的训练和更低的最终训练损失。**可以解释为,与通过嵌入层从训练数据中提取的语义信号相比,该模型可以从预训练的嵌入中提取更多的语义信号。

我们从 TREC 问题分类任务的结果中看到,在小语料库上训练的 向量将比嵌入层具有更差的性能。然而,就精确度和召回率而言,在大型语料库上训练的向量以相当大的优势击败了嵌入层。

一致 **对于两个任务,当我们使用预训练的单词嵌入(在足够大的语料库上训练)**时, 精度和召回率提高。然而,对于情感分析任务,这种改善很小,而对于句子分类任务,这种改善要大得多。

这可能意味着对于解决 语义 NLP 任务,当手头的训练集足够大时(如情感分析实验中的情况),最好使用预训练的单词嵌入。尽管如此,出于任何原因,你仍然可以使用一个嵌入层,并期待可比较的结果。然而,训练集很小,上述实验强烈鼓励使用预先训练的单词嵌入。

最终注释

与可根据实数值直接获得并因此可由机器学习模型直接解释的图像数据不同,文本数据需要被转换成一种表示,使得每个单词所承载的广泛知识的至少一部分可被带入这种表示。只有到那时,我们才能期望拥有在某种程度上理解人类语言的智能模型。学习词语的语义表征有着相对悠久的历史,并且一直是语言学和自然语言处理的核心研究课题。单词嵌入提供了一种表示单词的有效方式,然而,它们当前的能力在捕获每个单词所承载的语义、句法和搭配信息方面是有限的。这意味着在我们能够开发出能够理解和生成文本级别的自然语言的智能系统之前,在表示文本数据方面仍有很大的改进空间。

用云 TPU 从头开始预训练伯特

原文:https://towardsdatascience.com/pre-training-bert-from-scratch-with-cloud-tpu-6e2f71028379?source=collection_archive---------1-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Google Cloud TPUv2

在这个实验中,我们将使用谷歌云基础设施对任意文本数据预先训练一个最先进的自然语言理解模型 BERT

本指南涵盖程序的所有阶段,包括:

  1. 设置培训环境
  2. 下载原始文本数据
  3. 预处理文本数据
  4. 学习新词汇
  5. 创建分片的预训练数据
  6. 为数据和模型设置 GCS 存储
  7. 在云 TPU 上训练模型

几个问题

这本指南有什么用?

有了这个指南,你将能够在任意文本数据上训练一个 BERT 模型。如果您的语言或用例的预训练模型在开源中不可用,这将非常有用。

这本指南是给谁的?

本指南面向那些对 BERT 技术感到兴奋,但对现有的
开源模型的性能不满意的 NLP 研究人员。

我如何开始?

对于训练数据和模型的持久存储,您将需要一个 Google 云存储桶。请按照谷歌云 TPU 快速入门创建一个 GCP 帐户和 GCS 桶。新的谷歌云用户可以获得 300 美元的免费积分来开始使用任何 GCP 产品。

出于演示目的,本教程的步骤 1-5 可以在没有 GCS 铲斗的情况下运行。但是,在这种情况下,您将无法训练该模型。

需要什么?

在 TPUv2 上对基于 BERT 的模型进行预训练需要大约 54 个小时。Google Colab 不是为执行这种长时间运行的作业而设计的,大约每 8 小时就会中断一次训练过程。对于不间断的训练,考虑使用付费的可抢占的 TPUv2 实例。

也就是说,在撰写本文时(2019 年 5 月 9 日),使用 Colab TPU,可以从零开始预先训练 BERT 模型,而将所述模型和数据存储在 GCS 中的成本可以忽略不计(约 1 美元)。

我如何跟随指南?

下面的代码是 Python 和 Bash 的结合。
它被设计为在 Colab Jupyter 环境中运行。
因此,在那里运行它是最方便的。

但是,除了实际的培训部分,本指南的所有步骤都可以在单独的机器上运行。如果您的数据集太大
(或太私有)而无法在 Colab 环境中进行预处理,这可能会很有用。

好吧,给我看看代码。

给你。

我需要修改代码吗?

您真正需要设置的唯一参数是您的 GCS BUCKET_NAME。其他一切都有默认值,这应该适用于大多数用例。

现在,让我们进入正题。

步骤 1:设置培训环境

首先,我们得到了训练模型所需的包。Jupyter 环境允许使用感叹号“!”直接从笔记本上执行 bash 命令,像这样:

!pip install sentencepiece
!git clone [https://github.com/google-research/bert](https://github.com/google-research/bert)

在整个实验中,我将利用这种方法来使用其他几个 bash 命令。
现在,让我们导入包并在 Google Cloud 中授权我们自己。

Setting up BERT training environment

步骤 2:获取数据

我们继续获取文本数据的语料库。在这个实验中,我们将使用open 字幕数据集,该数据集可用于 65 种语言这里是

与更常用的文本数据集(如维基百科)不同,它不需要任何复杂的预处理。它还预先格式化为每行一个句子,这是进一步处理步骤的要求。

通过设置相应的语言代码,您可以随意使用您的语言的数据集。

Download OPUS data

出于演示的目的,默认情况下,我们将只使用整个语料库的一小部分。

训练真实模型时,请确保取消选中 DEMO_MODE 复选框,以使用 100 倍大的数据集。

请放心,100 米的线完全足以训练一个相当好的 BERT-base 模型。

Truncate dataset

步骤 3:预处理文本

我们下载的原始文本数据包含标点符号、大写字母和非 UTF 符号,我们将在继续之前删除它们。在推理过程中,我们将对新数据应用同样的过程。

如果您的用例需要不同的预处理(例如,如果在推断过程中需要大写字母或标点符号),请随意修改下面的函数以满足您的需求。

Define preprocessing routine

现在让我们预处理整个数据集。

Apply preprocessing

第四步:积累词汇

下一步,我们将学习一个新的词汇来表示我们的数据集。

BERT 论文使用了一个 WordPiece tokenizer,这在 opensource 中是没有的。相反,我们将在单字模式下使用句子片断标记器。虽然它不能直接与 BERT 兼容,但只要稍加修改,我们就能让它工作。

SentencePiece 需要相当多的 RAM,所以在 Colab 的完整数据集上运行它会使内核崩溃。为了避免这种情况,我们将随机对数据集的一部分进行二次抽样,以构建词汇表。另一种选择是使用内存更大的机器来完成这一步——这取决于您。

另外,缺省情况下,SentencePiece 将 BOS 和 EOS 控制符号添加到词汇表中。我们通过将它们的索引设置为-1 来显式禁用它们。

VOC_SIZE 的典型值介于 32000 和 128000 之间。我们保留 NUM_PLACEHOLDERS 标记,以防在预训练阶段结束后,有人想要更新词汇表和微调模型。

Learn SentencePiece vocabulary

现在,让我们看看如何让句子片段为 BERT 模型工作。

下面是一个句子,使用了来自官方回购
预训英语伯特基础模型的词块词汇。

>>> wordpiece.tokenize("Colorless geothermal substations are generating furiously")

['color',
 '##less',
 'geo',
 '##thermal',
 'sub',
 '##station',
 '##s',
 'are',
 'generating',
 'furiously']

正如我们所看到的,单词块标记器将出现在单词中间的子单词添加到带有“##”的单词前面。出现在单词开头的子单词不变。如果子词同时出现在单词的开头和中间,则两个版本(带和不带’ ## ')都被添加到词汇表中。

SentencePiece 创建了两个文件:tokenizer.model 和 tokenizer.vocab,我们来看看学过的词汇:

Read the learned SentencePiece vocabulary

这给出了:

Learnt vocab size: 31743 
Sample tokens: ['▁cafe', '▁slippery', 'xious', '▁resonate', '▁terrier', '▁feat', '▁frequencies', 'ainty', '▁punning', 'modern']

正如我们所观察到的,句子成分与单词成分正好相反。来自文档:

句子片断首先用元符号“▁”(u+2581)转义空格,如下所示:

Hello▁World

然后,该文本被分割成小块,例如:

[Hello] [▁Wor] [ld] [.]

出现在空格之后的子词(也是大多数单词开始的地方)被加上’▁’,而其他的则保持不变。这不包括只出现在句首而不在其他地方的子词。然而,这些情况应该非常罕见。

因此,为了获得一个类似于 WordPiece 的词汇表,我们需要执行一个简单的转换,从包含“▁”的标记中删除它,并将“##”添加到不包含它的标记中。

我们还添加了一些特殊的控制符号,这些符号是 BERT 体系结构所需要的。按照惯例,我们把它们放在词汇表的开头。

此外,我们将一些占位符标记添加到词汇表中。
如果希望用新的
任务特定的令牌更新预训练的模型,这些是有用的。在这种情况下,占位符标记会被新的真实标记替换,预训练数据会重新生成,并且模型会根据新数据进行微调。

Convert the vocabulary to use for BERT

最后,我们将获得的词汇写入文件。

Dump vocabulary to file

现在让我们看看新词汇在实践中是如何工作的:

>>> testcase = "Colorless geothermal substations are generating furiously"
>>> bert_tokenizer = tokenization.FullTokenizer(VOC_FNAME)
>>> bert_tokenizer.tokenize(testcase)['color',  
 '##less',  
 'geo',  
 '##ther',  
 '##mal',  
 'sub',  
 '##station',  
 '##s',  
 'are',  
 'generat',  
 '##ing',  
 'furious',  
 '##ly']

看起来不错!

步骤 5:生成训练前数据

有了这些词汇,我们就可以为 BERT 模型生成预训练数据了。
由于我们的数据集可能相当大,我们将把它分成若干片段:

Split the dataset

现在,对于每个碎片,我们需要从 BERT repo 中调用create _ pre training _ data . py脚本。为此,我们将使用 xargs 命令。

在开始生成之前,我们需要设置一些参数传递给脚本。你可以在自述中找到更多关于它们的含义。

Define parameters for pre-training data

根据数据集的大小,运行此操作可能需要相当长的时间。

Create pre-training data

步骤 6:设置持久存储

为了保护我们来之不易的资产,我们将把它们保存到谷歌云存储中。假设您已经创建了 GCS bucket,这应该很容易。

我们将在 GCS 中创建两个目录,一个用于数据,一个用于模型。在模型目录中,我们将放入模型词汇表和配置文件。

在继续之前,请在此配置 BUCKET_NAME 变量,否则您将无法训练模型。

Configure GCS bucket name

下面是 BERT-base 的超参数配置示例。更改风险自担!

Configure BERT hyperparameters and save to disk

现在,我们准备将我们的资产推向 GCS

Upload assets to GCS

步骤 7:训练模型

我们几乎准备好开始训练我们的模型。

请注意,前面步骤中的一些参数在此处重复,以便方便地重新开始训练程序。

确保参数设置在整个实验中完全相同。

Configure training run

准备训练运行配置,构建估计器和
输入函数,启动低音加农炮。

Build estimator model and input function

执行!

Execute BERT training procedure

使用 100 万步
的默认参数训练模型需要大约 54 小时的运行时间。万一内核因为某种原因重启,你可以从最近的检查点继续训练。

这就结束了在云 TPU 上从头开始预训练 BERT 的指南。

后续步骤

好了,我们已经训练好了模型,现在做什么?

这是一个全新讨论的话题。你可以做几件事:

  1. 将预训练模型用作通用 NLU 模块
  2. 针对某些特定的分类任务对模型进行微调
  3. 使用 BERT 作为构建块创建另一个 DL 模型
  4. ???

真正有趣的事情还在后面,所以保持清醒。与此同时,查看令人敬畏的 bert-as-a-service 项目,并开始在生产中为您新培训的模型提供服务。

继续学习!

本系列中的其他指南

  1. 用云 TPU 从头开始预训练 BERT【你在这里】
  2. 用 BERT 和 Tensorflow 构建搜索引擎
  3. 用 Keras 和 tf 微调 BERT。模块
  4. 使用 BERT 和表征学习改进句子嵌入

精确度和召回率

原文:https://towardsdatascience.com/precision-and-recall-1af0a478fc7e?source=collection_archive---------20-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Hush Naidoo on Unsplash

假设我想建立一个系统来判断一个人是否患有肺结核。我们收集了包括 50,000 幅图像的数据集。这些图像中有 49.950 个是反面例子,其余的是正面例子。

在我们的数据集中,只有 50 人患有肺结核,而我们有 50,000 张图像。(50/50.000)** 100*= 0.1*%*都是肺结核。我们称之为不平衡数据集。即使没有构建深度学习算法,通过一个简单的语句,也可以达到大约%99 的准确率。也就是说,你希望你的算法预测某人是结核病,而我们不知道我们的算法是否能正确预测某人是否是结核病。我们只知道准确性,仅此而已!在这种情况下,您可以使用精度和召回评估指标。别担心,我也会提到 F1 的分数。

深入研究指标之前的一些关键词

正的;
实际:肺结核|预测:肺结核

TrueNnegative;
实际:非肺结核|预测:非肺结核

阳性:实际:非结核病,预测:非结核病

阴性:实际:不是肺结核,预测:不是肺结核

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Confusion Matrix

精确

我们预测的肺结核患者中有多少是真正的肺结核?让我们看看混淆矩阵,看看我们的算法在哪里说某人是结核病(蓝色矩形),什么是实际的(红色矩形)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Precision

我们可以像上面这样写下来。

回忆

我们正确预测了多少肺结核患者?让我们看看混淆矩阵,看看我们的算法在哪里正确地检测到患有结核病的人(橙色矩形)和所有实际患有结核病的人(蓝色矩形)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Recall

F1 分数

要说某人是不是肺结核,我们要确保我们的算法做得非常好。判断算法是否有效的一个方法是,我们可以看看精度和召回率。在精确度和召回率之间有一个权衡。

你有 5 种算法,每一种都有不同精度和召回率。我们如何判断哪种算法更好?在这种情况下,F1 分数开始起作用。所以我们可以用 F1 的分数来决定,是哪个算法在做。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

F1 score

感谢您的阅读!我希望你喜欢它。请关注即将推出的 Python 和深度学习部分。别忘了关注我的 GitHub

精确度和召回率—一个简化的视图

原文:https://towardsdatascience.com/precision-and-recall-a-simplified-view-bc25978d81e6?source=collection_archive---------8-----------------------

理解精确度和召回率对于完善任何机器学习模型都是至关重要的。这是微调模型以产生准确结果所需的技能。少数型号需要更高的精度,而少数型号可能需要更高的召回率。在文章的最后,我们还将讨论我们需要什么。这篇文章旨在减少苹果和橘子的精确度和召回率。我是认真的,所以让我们举一个苹果分类器的例子。其主要目的是对苹果和橘子进行分类。

假设有一个巨大的农场,里面种满了苹果树和橘子树。农场的主人想要建立一个能够正确预测苹果和橙子的分类器,这样他就可以对它们进行分类并出售。此外,与橙子相比,苹果的价格要高得多,因此他特别希望构建一个能够检测苹果的分类器。在这一过程中,他建造了一个能够对苹果和橘子进行分类的探测器,并随机抽取了 13 种水果样本进行分类。因为他更专注于预测苹果(因为它们很贵),该模型将苹果归类为阳性,将橙子归类为阴性。

他制作了如下图表来检查模型的表现:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

confusion matrix

真正的肯定:这些是模型正确预测的苹果。

误报:有模型预测为苹果的橙子。

假阴性:有模型预测为橙子的苹果。

真正的否定:有模型正确预测的橙子。

从图表中我们可以得出以下推论:

  1. 模型将两个橙子归类为苹果
  2. 模型把 3 个苹果归类为橘子
  3. 模型正确地分类了 5 个苹果
  4. 模型正确地分类了三个橙子

让我们修改图表,以理解精确度并正确回忆

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

modified confusion matrix

图像的左侧包含实际苹果的预测结果。图像的右侧包含实际橙子的预测结果。

上图帮助我们从不同的角度了解模型的预测:

  1. 在它归类为苹果的 8 个价值中,只有 5 个是真正的苹果,3 个是橙子。
  2. 在它归类为橙子的 5 个值中,只有 2 个是真正的橙子,3 个是苹果。

现在,让我们深入精确地回忆一下。关于上图。

精确

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

precision

这是模型做出的正确预测的数量。简单来说,就是:

模型预测正确的苹果数量/模型预测正确的苹果和橙子数量

它不考虑模型所做的错误预测。

精度公式:

真阳性数/(真阳性数+假阳性数)

苹果预测值的精度:5/(5+2) = 5/7 = 0.714

回忆

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

recall

它是模型对当前正值总数做出的正确预测的数量。简单来说,就是:

模型正确预测的苹果数量/苹果总数

苹果总数是发送到系统的苹果数量,即 8 个。

它考虑了模型做出的错误预测。召回的公式:

真阳性数/(假阴性数+真阳性数)

对于上面的例子,它是:5/(5+3) = 5/8 = 0.625

所以,我们知道农场主人创建的模型精度高,但召回率低!

什么时候我们需要高精度或者高召回率?

当您需要对输出敏感的预测时,模型需要高召回率。例如,预测癌症或预测恐怖分子需要高召回率,换句话说,你也需要覆盖假阴性。如果非癌性肿瘤被标记为癌性,这是可以的,但是癌性肿瘤不应该被标记为非癌性的。

同样,在推荐引擎、垃圾邮件检测等地方,我们也需要高精度。你不在乎假阴性,而是更关注真阳性和假阳性。如果垃圾邮件进入收件箱文件夹是可以的,但是真正重要的邮件不应该进入垃圾邮件文件夹。

关于开头提到的例子,为了使农场主人的利润最大化,他不应该让苹果被误归类为橘子。所以,模型需要苹果的高召回率。

如何调优一个机器学习模型来调整到高精度或者召回?

如果它是一个神经网络,分配一个适当的损失函数,该函数对变化敏感,不会对值进行不必要的舍入。主要关键是您分配给神经网络最后一层的阈值。如果是二元分类的情况,阈值需要以最大化召回或精确度的方式设置,无论哪种需要。如果您想最大化召回率,请将阈值设置为低于 0.5,即大约 0.2。比如大于 0.3 是苹果,0.1 不是苹果。这样会增加系统的召回。为了精确起见,可以将阈值设置为更高的值,例如 0.6 或 0.7。这样你就可以调整神经网络的精确度和召回率。

如果是任何其他机器学习模型,您需要调整超参数和概率阈值,以实现更高的精度或召回率。

感谢您的阅读!☺

制造业中的精确度和召回率:案例研究

原文:https://towardsdatascience.com/precision-and-recall-in-manufacturing-a-case-study-4cbb4c352bcd?source=collection_archive---------19-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

A Fully Automated Assembly Line

任何即将开始机器学习项目的组织都会很快遇到定义适当的评估指标的问题。不幸的是(或者幸运的是,取决于你的观点),有大量的度量标准;从常见的准确度、精确度、召回率、f1 分数到不太为人所知的马修斯相关系数。

选择正确的评估指标与选择正确的算法同样重要。

我参加过太多会议,在这些会议上,这种度量标准成为每个人困惑的来源。在本文中,我想讨论其中的两个:精确度和召回率,使用制造业的一个案例研究。

自动测试设备

除非你在制造业工作过,否则你很可能不熟悉自动测试设备。但即便如此,你也可能间接受益于它们。不相信我?如果你正在电子设备上阅读这篇文章,那就是了;该设备很可能已经在工厂中由这样的设备进行了自动测试,如下图所示。这台机器确保你的设备可以安全使用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

A sample circuit board tester machine

然而在现实中,并不是工厂生产线上的所有测试都是自动完成的。案例研究是这样的:假设我们正在开始一个新的概念验证实验,来自动化生产线上的一个测试系统。这种新的自动测试设备的工作是检查产品,通常被称为被测设备(DUT),并决定它是通过(质量良好)还是失败(有缺陷)。在这种情况下,我们假设自动测试设备已经装载了某种算法。

算法要求

让我们假设我们的算法有以下要求。

  1. 让不良 dut 进入下一个生产线的成本很高,例如,我们不能容忍逃亡者。我们希望避免任何受伤的 DUT 成为下游的退货授权。约束:最小化风险。
  2. 尽管如此,我们也不希望算法在每个 DUT 都失败。这是因为任何失败的 DUT 通常将由人类技术人员手动重新检查。为了使算法成功,它必须减少人工检查的次数。目标:储蓄最大化。

因此,我们收集了 1000 个样本 dut(900 个好的,100 个坏的)。然后,我们用设备的算法对所有 1000 个 dut 进行分类。为了衡量后者的性能,我们使用 python scikit-learn 的分类报告

**from** **sklearn.metrics** **import** classification_report# 'labels' is an array of 1000 groundtruth labels
# 'preds' is an array of 1000 outputs from the algorithm  
print(classification_report(labels, preds, target_names=["fail", "pass"]))

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Sample Classification Report from Scikit-Learn

那么,我们该如何解读这份报告呢?要记住的关键是,召回率和精确度都衡量**条件精确度。**它们的区别在于衡量绩效的条件。这种说法现在可能没有意义,但希望在阅读完本文的其余部分后,您可以再次重温这一点。

回忆:以基础事实标签为条件

请记住,在实验的最开始,我们选择了 1000 个 dut,其中 900 个是好的(通过),100 个是差的(失败)。我们可以计算每个标签的召回,例如一次召回合格的和一次召回不合格的

召回通过回答了这个问题:在我测试过的 900 个良好/通过 dut 中,有多少被算法准确分类?在我们的报告示例中,我们看到 pass 的召回率是 0.67(或 67%)。这意味着 900 个通过测试的 dut 中有 67%也被正确分类为通过。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Visualizing Recall with a Tree

同样的逻辑可以通过遍历上面的决策树来解释。在根部,我们有一个装有 1000 个 dut 的盒子。然后,盒子被分成 2 个子节点(一个盒子用于 100 个坏的/失败的 dut,另一个盒子用于 900 个通过的 dut)。这种分裂对应于地面真相标签。我们可以进一步将 900 个通过的 dut 分成两个框,一个框用于算法标记为失败的 dut(300 个 dut),另一个框用于被认为通过的 dut(600 个 dut)。我们看到,对于通过测试的 dut 子集,该算法的精确度仅为 600 / 900 ~= 0.67 或 67%。

召回失败查看树的另一边,回答这个问题:在 100 个失败的 dut 中,算法设法捕获了多少个?在这种情况下,只有 80 / 100 = 0.8 或其中的 80%被正确分类。

我们可以使用召回来量化我们在多大程度上满足了前面列出的两个产品要求。

  1. 最小化逃脱者的风险相当于最大化失败召回
  2. 最大化节省等同于最大化通过的召回。

精度:以算法标签为条件

现在假设我们已经在生产中部署了该算法。最有可能的是,我们的客户( OEM / CM )会开始询问他们是否可以信任这个新系统。精确可以用来回答这样的问题。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Visualizing Precision with Recall

通过精度回答了这个问题:如果算法通过了 DUT,我们能在多大程度上信任这个决定?换句话说,从常客的角度来看,如果算法通过了 620 个 dut,其中有多少是真正好的?在我们的例子中,600/620 ~= 0.97 或 97%的时间判断是正确的。

同样,我们可以通过遍历树得到相同的数字。唯一的区别是,我们根据算法的判断而不是地面真实标签来分割根节点(1000 个 dut)。

通过使用相同的方法,我们得到了失败的精度为 80 / 380 ~= 21%。这意味着,当算法说 DUT 是坏的,只有 21%的时间是正确的。

这告诉我们,这种算法在识别好的 dut(通过)方面是有用的,但在识别坏的 dut(失败)方面不是有用的。

结论

总之,我们需要在以下方面改进算法:

  1. 改进召回故障以防止逃逸
  2. 提高对通行证的召回,以增加成本节约,从而缩短投资回收期(如果我们要向客户销售该产品,我们最好确保投资回报的计算是合理的)。
  3. 保持/提高通过的精度,这样我们可以确保模型在通过 DUT 时非常自信

我们关于精度和召回率的讨论到此结束。请记住,这 4 个数字不是独立的,即增加一个数字会减少其他数字(根据贝叶斯法则,查看附录以了解精确度与回忆的关系)。因此,简单地偏置算法的决策边界是行不通的。人们可以尝试摆弄算法的超参数,或者尝试一种完全不同的架构。这最好留给另一个讨论话题。

因此,我希望这个小案例研究能让我们从制造分析的角度更好地了解每个指标所传达的信息。

附录:用贝叶斯法则连接精确度和召回率

用条件概率定义召回率和精确度

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

应用贝叶斯规则找出特定类别(失败)的召回率和精确度之间的关系

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

替换案例研究中的值来证明等号。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

精确度和召回率的权衡和多重假设检验

原文:https://towardsdatascience.com/precision-and-recall-trade-off-and-multiple-hypothesis-testing-family-wise-error-rate-vs-false-71a85057ca2b?source=collection_archive---------13-----------------------

现实世界中的数据科学

家族错误率(FWE)与错误发现率(FDR)

在我之前作为天体物理学家的工作中,我致力于探测释放出惊人能量的大恒星 (GRBs)的爆炸。我们的自动分析管道到处搜寻伽玛暴,因为无法预测何时何地会发生这样的爆炸。这提出了一个重要的挑战,与我们检测过程的统计性质有关:多重假设检验。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Left: a map of the sky in Gamma-Rays showing the position of the stellar explosions (GRBs) detected by the Fermi Space Telescope. The map is in Galactic coordinates, and the bright stripe going across the map from left to right corresponds to the cosmic dust contained in the Galactic plane of our Milky Way galaxy and glowing in gamma-rays. Right: an animation of our current picture of how a GRB might look like if seen up close. Credits: NASA (reproduced according to NASA Media Usage guidelines from https://nasa.tumblr.com/post/176492220069/gamma-ray-bursts-black-hole-birth-announcements).

在我目前作为数据科学家的工作中也可以发现同样的挑战,例如在多个数据集中搜索异常或执行许多 A/B 测试时。

让我们从基础开始,说明多重测试意味着什么。

注意:这篇文章在我的 GitHub 库中作为一个可运行的 Jupyter 笔记本提供。我在整篇文章中使用的函数和类可以在文章结尾的代码单元中找到。

在这篇文章中,我假设大家熟悉一些概念,特别是统计检验、零假设与替代假设、p 值、I 型错误和 II 型错误

粗略地说,统计检验能够拒绝或不拒绝具有给定的 I 型错误概率α(假阳性的概率)和 II 型错误概率β(假阴性的概率)的零假设。

我们的玩具问题

让我们考虑确定两个总体是否具有相同平均值的问题。零假设是平均值是相同的,另一个假设是平均值不相同。

请注意,您可以用任何其他可以通过统计测试回答的问题来代替这个问题,这里的所有讨论仍然成立(但是当然您需要重新编写代码)。

简单的例子:一个测试

最适合手头问题的测试是学生的 T-test 。让我们编写一个计算 p 值的函数和一个根据 p 值决定是否拒绝空值的函数:

# Let's write so that w1 and w2 can be lists of n
# datasets, from 1 to as much as needed

**def** apply_ttest(w1, w2):

    ts, pvalues = scipy.stats.ttest_ind(w1, w2, axis=1)

    # np.squeeze is necessary so we can use this
    # function both for single and for multiple tests

    **return** np.squeeze(pvalues)

**def** null_hyp_status(pvalue, alpha):

    # We write it using np.all so we can use the same function
    # for both single and multiple tests

    **return** np.all(pvalue > alpha)

我们现在生成一个合成数据集,将零假设设置为真,然后进行测试。我们将使用类型 I 错误概率α=0.05:

# Let's get a dataset with 1 group and
# the null hypothesis is true

w1, w2, ground_truth = generate_dataset(n_datasets=1, 
                             n_null_true=1)
# Let's now apply the test
alpha = 0.05
pvalue = apply_ttest(w1, w2)

**if** null_hyp_status(pvalue, alpha) **is** True:

    **print**("We do not reject the null hyp.")

**else**:

    **print**("We reject the null hyp.")

> We do **not** reject the null hyp.

测试如预期的那样工作,没有拒绝零假设(我们知道这是真的)。让我们验证测试的性能是名义上的,也就是说,通过重复相同实验的大量独立实现,我们偶然拒绝了名义 I 型错误概率为α的零假设:

# Let's perform 5000 independent simulations
type_I_error_p = measure_rejection_prob(5000, 
                                        apply_ttest, 
                                        null_hyp_status,
                                        alpha, 
                                        n_datasets=1,
                                        n_null_true=1)

**print**("\nMeasured chance probability of rejecting the "
      "null: %.3f (should be %.3f)" % (type_I_error_p, alpha))

> 5000 out of 5000 completed (fraction of rejections so far: 0.05)
> Measured chance probability of rejecting the null: 0.05 (should be 0.050)

好了,果然有效。当然,如果你运行它,你可能会得到一个稍微不同的值,因为生成过程是随机的,但是它应该接近 0.05。

多重测试

现在让我们假设我们有 m 对群体,我们想要找出是否一对或多对群体之间有显著差异。

这里的零假设是“在所有对中,两个群体具有相同的平均值”,另一个是“至少有一个对中两个群体的平均值不同。”

我们能不能只对每一对分别进行测试,看看是否至少有一对被拒绝?(剧透:答案是否定的!还有,我们忽略一个事实,就是还有其他针对这种情况设计的测试)。让我们看看:

# Generate m=50 pairs of populations, all with the same
# average between the populations (the null hypothesis is true)
w1, w2, _ = generate_dataset(n_datasets=50, n_null_true=50)
pvalues = apply_ttest(w1, w2)

**if** null_hyp_status(pvalues, alpha) **is** True:

    **print**("We do not reject the null hyp.")

**else**:

    **print**("We reject the null hyp.")

> We reject the null hyp.

起初,这个结果可能会令人惊讶。毕竟我们知道零假设是真的!

然而,如果你还记得类型 I 错误概率的定义,通过固定α=0.05,我们设置了测试,这样它将错误地以 5%的概率拒绝空值。因此,通过重复测试 50 次(每对一次),我们每次都有 5%的机会出现 I 型错误。因此,至少有一次拒绝的概率由二项式分布给出:

# probability of having one or more rejections in 50 trials
m = 50
binomial_distr = scipy.stats.binom(m, alpha)

# NOTE: the .sf method gives the probability of obtaining > 1,
# while we need >= 1, so we add the pmf at 1
prob = binomial_distr.sf(1) + binomial_distr.pmf(1)

**print**("The prob. of >= 1 false positives in %i "
      "trials is %.3f" % (m, prob))

> The prob. of >= 1 false positives **in** 50 trials **is** 0.923

在我们的设置中有超过 90%的机会得到至少一个假阳性。在同一个问题中多次测试一个假设被称为“多重测试”,需要更多的思考。

邦费罗尼/西达克校正

Bonferroni (1936)对这种情况引入了一个简单的修正。处方是用修正的 I 型错误概率代替复合试验中的每一个独立试验的α,该概率由西达克公式α′=1−(1−α)^(1/m给出(对于大的m通常近似为α′=α/m)

有时,在文献中,校正α′=α/m 被称为“邦费罗尼校正”,而校正α′=1−(1−α)^(1/m 被称为“西达克校正”在这里,我们将使用后一种表述方式,但是可以互换使用这个名称,因为在所有实际应用中,这种差异非常小

西达克公式的理由可以很容易地推导出来,它是我们刚刚在二项分布中发现的观察的直接结果。在概率为α’的 m 次试验中获得 1 次或多次成功的概率α由 1b(mp=α’,k=0)给出,其中 B( mp=α’,k=0)是由二项式分布给出的获得 0 次成功的概率。

我们有:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这里,我们刚刚替换了 k = 0。通过求解α’,我们获得了需要在每个 m 测试中使用的 I 型误差概率,以获得α的全局 I 型误差概率,这就是 Bonferroni/Sidak 校正。

注意:我们假设独立测试。如果不同的测试之间存在相关性,这里介绍的方法可能适用,也可能不适用,您需要仔细查看相关的论文。

让我们看看这是否能解决我们的问题。我们只需要改变用于决定是否拒绝空值的标准。不需要改变 p 值的计算:

# Test if any of the pvalues is lower than alpha',
# if the answer yes, the null hyp. is deemed False

**def** null_hyp_status_bonferroni(pvalues, alpha):

    # Number of tests
    m = pvalues.shape[0]

    # Bonferroni/Sidak correction
    alpha_prime = 1 - (1-alpha)**(1.0/m)

    # Test whether *all* null hypothesis in the subtests are
    # true or not
    **return** np.all(pvalues > alpha_prime)

w1, w2, _ = generate_dataset(n_datasets=50, n_null_true=50)
pvalues = apply_ttest(w1, w2)

**if** null_hyp_status_bonferroni(pvalues, alpha) **is** True:

    **print**("We do not reject the null hyp.")

**else**:

    **print**("We reject the null hyp.")

> We do **not** reject the null hyp.

看起来好多了。为了确保这一点,让我们生成许多合成数据集,看看我们的 Bonferroni 校正测试是否提供了名义 I 型错误概率α=0.05。

# Let's do again 5000 realization of datasets with 50
# pairs where the null is true for all pairs,
# and study the performance of the new procedure

type_I_error_p = measure_rejection_prob(5000, 
                                        apply_ttest, 
                                        null_hyp_status_bonferroni,
                                        alpha, 
                                        n_datasets=50,
                                        n_null_true=50)

**print**("\nMeasured chance probability of rejecting the "
      "null: %.3f (should be %.3f)" % (type_I_error_p, alpha))

> 5000 out of 5000 completed (fraction of rejections so far: 0.05)
> Measured chance probability of rejecting the null: 0.047 (should be 0.050)

成功了。第一类错误概率确实非常接近名义上的 5%。

类 Bonferroni 修正的问题:全局与局部假说

到目前为止,我们一直在处理这个问题的“全局”零假设“是否存在两个群体的平均值不同的配对?”无效假设是所有对在群体之间具有相同的平均值,或者是至少有一个不具有相同的平均值。

然而,我们经常对另一个问题感兴趣:“找出平均值不同的所有配对*”。或者,“找到所有恒星爆炸”,就像我的天体物理学问题一样。在第二种情况下,每一对都有自己的无效假设和替代假设,我们感兴趣的是有多少无效假设被拒绝。*

很明显,Bonferroni 校正将仍然保证偶然拒绝一个或多个零值的全局αI 型误差概率,但是它为了这样做而惩罚所有测试,因为每个测试的α由 Sidak 公式和 1−(1−α)^(1/ m ) < α给定,用于 m > 1。

此外,随着 m 的增长,全局无效假设仍然以相同的 I 型错误概率进行测试,但是 m 无效假设中的每一个都得到越来越严格的测试,并且随着 m →∞我们有α′→0,因此很难找到与无效假设的任何偏差。换句话说,“看的越多,发现的越少。”

让我们通过考虑一个单一测试的类型 II 错误来说明这一点,即而不是在我们应该拒绝空值时拒绝空值的概率。首先,让我们生成并测试一个空值为假的对:

*# Let's get a dataset with 1 group and
# the null hypothesis is False

w1, w2, ground_truth = generate_dataset(n_datasets=1, n_null_true=0)

# Let's now apply the test
alpha = 0.05
pvalue = apply_ttest(w1, w2)

**if** null_hyp_status(pvalue, alpha) **is** True:

    **print**("We do not reject the null hyp.")

**else**:

    **print**("We reject the null hyp.")

> We reject the null hyp.*

我们已经正确地拒绝了无效假设。现在让我们看看,在多次重复相同的实验后,我们有多少次未能拒绝空值,即使它是假的(类型 II 错误概率):

*type_II_error_p = 1 - measure_rejection_prob(5000, 
                                             apply_ttest, 
                                             null_hyp_status,
                                             alpha, 
                                             n_datasets=1,
                                             n_null_true=0)
**print**("\nMeasured chance probability of *not* rejecting the "
      "null: %.3f" % (type_II_error_p))

> 5000 out of 5000 completed (fraction of rejections so far: 0.94)
> Measured chance probability of ***not*** rejecting the null: 0.062*

因此,对于一个测试,我们有大约 6% (β=0.06)的概率而不是拒绝空值,即使它是假的(当然,β取决于α,以及效果的大小——在这种情况下,是两个平均值之间的差异)。

现在,让我们看看如果对 50 对进行 Bonferroni 校正测试会发生什么,其中只有一对的零假设为假:

*type_II_error_p = 1 - measure_rejection_prob(5000, 
                                             apply_ttest, 
                                             null_hyp_status_bonferroni,
                                             alpha, 
                                             n_datasets=50,
                                             n_null_true=49)

**print**("\nMeasured chance probability of *not* rejecting the "
      "null: %.3f" % (type_II_error_p))

> 5000 out of 5000 completed (fraction of rejections so far: 0.59)
> Measured chance probability of ***not*** rejecting the null: 0.410*

现在我们有 41%的概率没有在我们应该拒绝 null 的时候拒绝它。很明显,我们已经失去了很多敏感性,因为一对样本中的差异被 50 对样本所掩盖。

从某种程度上来说,这是不可避免的,也是我们不知道具体去哪里寻找所付出的代价。

然而,当试图测试所有的局部无效假设而不是全局无效假设时,事情会很快失控。为了得到一个概念,让我们制作几个越来越大的数据集,每个数据集有 50 个假零假设,并看看类型 II 误差如何作为配对/测试数量 m 的函数而变化:

注意:从现在开始,我们将重复使用精度和召回的概念。前者描述了所有检测中正确“检测”(即拒绝零假设)的比例,即描述了我们程序的输出样品的纯度。后者描述了空 hyp 的分数。我们已经拒绝了我们应该拒绝的(例如,我们输出样本的完整性)。

*# Test the Bonferroni method with alpha=0.05
methods = [('bonferroni', 0.05)]

# Number of pairs per dataset
ms = np.array([70, 80, 90, 100, 120, 150, 175, 220, 280, 350, 500, 700, 1000])
**print**("Generating %s datasets" % len(ms))

# Pairs with a false null hypothesis for each dataset
n_false = 50

(selections, 
 false_positives, 
 false_negatives, 
 global_typeI) = characterize_methods(apply_ttest, 
                                      methods, 
                                      ms, 
                                      [n_false] * ms.shape[0], 
                                      niter=800,
                                      plot=True)

> Generating 13 datasets
> Method bonferroni **with** alpha 0.05.............completed*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们可以看到,输出样本的纯度恒定为 1.0,但完整性很小,并且随着测试次数的增加,其下降速度也很快。换句话说,随着 m 的增加,我们检测到的异常越来越少,但是我们检测到的异常总是正确的。检测任何假阳性的 I 类错误概率总是低于声明的α水平,尽管对于小的 m 来说非常保守。我们能做得更好吗?

答案是,幸运的是,是的!

霍尔姆-西达克方法

对 vanilla Bonferroni/Sidak 方法提出了几个修正。你可以在这里找到他们描述的。不去探究它们中每一个的细节(参见维基百科页面),让我们来测试它们:

*# Test different Bonferroni-like methods with alpha=0.05

methods = [('bonferroni', 0.05), 
           ('holm', 0.05), 
           ('holm-sidak', 0.05),
           ('simes-hochberg', 0.05)]

# Number of pairs per dataset
ms = np.array([70, 80, 90, 100, 120, 150, 175, 220, 280, 350, 500, 700, 1000])
**print**("Generating %s datasets" % len(ms))

# Pairs with a false null hypothesis for each dataset
n_false = 50
(selections, 
 false_positives, 
 false_negatives, 
 global_typeI) = characterize_methods(apply_ttest, 
                                      methods, 
                                      ms, 
                                      [n_false] * ms.shape[0], 
                                      niter=800,
                                      plot=True)

> Generating 13 datasets
> Method bonferroni **with** alpha 0.05.............completed
> Method holm **with** alpha 0.05.............completed
> Method holm-sidak **with** alpha 0.05.............completed
> Method simes-hochberg **with** alpha 0.05.............completed*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

新方法保持了 vanilla Bonferroni 的绝对纯度和低于或等于标称值的 I 型误差,但稍微提高了完整性。但是,我们可以做得比这好得多!让我们看看怎么做。

错误发现率与家庭错误率

到目前为止,我们对多重假设检验问题的解决方案一直试图将家族错误率(FWER)控制在可控范围内,即在整个 m 检验集中出现的 I 类错误率(在上面的图中我们称之为全局α)。

然而,在我们期望几个“检测”(即几个错误的零假设)的情况下,我们可以稍微牺牲我们对完全纯度的渴望,并且决定我们可以接受受控数量的假阳性,如果这有助于提高完整性的话。对于数据科学从业者来说,这是一个非常熟悉的想法:我们可以用一些精确度来换取更多的召回。换句话说,我们可以接受在检测的输出样本中有一定数量的“冒名顶替者”。这是罗斯福背后的理念。

Benjamini 和 Holdberg (1995) 提出了一种方法。这里,α不再代表 I 型误差概率,而是控制输出样本的纯度(即直接影响精度,而不是像我们以前的方法那样影响全局α)。(预期)精度保证为>1α。

如前所述,我们参考该文件了解详情。这里我想说明一下与我们以前的方法的不同之处。让我们使用和以前一样的程序。为了简单起见,根据前面的图(“holm-sidak”),让我们在类似 Bonferroni 的方法中只考虑我们问题的最佳方法:

*# Let's use two values of alpha per method to illustrate
# what they affect
methods = [('holm-sidak', 0.1), 
           ('holm-sidak', 0.05), 
           ('fdr_bh', 0.1), 
           ('fdr_bh', 0.05)]

# Number of tests
ms = np.array([70, 80, 90, 100, 120, 150, 175, 220, 280, 350, 500, 700, 1000])

# False null hypothesis that we are going to generate

n_false = 50
(selections, 
 false_positives, 
 false_negatives, 
 global_typeI) = characterize_methods(apply_ttest, 
                                      methods, 
                                      ms, 
                                      [n_false] * ms.shape[0], 
                                      niter=800,
                                      plot=True)

> Method holm-sidak **with** alpha 0.10.............completed
> Method holm-sidak **with** alpha 0.05.............completed
> Method fdr_bh **with** alpha 0.10.............completed
> Method fdr_bh **with** alpha 0.05.............completed*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们可以立即看到,BH 方法通过牺牲一定数量的精确度(“纯度”)来提供更大的召回(“完整性”,第二个面板)。事实上,正如承诺的那样,精度大于 1α。在 BH 方法中,从α=0.01 到α=0.05 增加了预期的纯度,但降低了完整性。此外,BH 方法的全局α(下图)很大,接近 1,这意味着在任何实验中,获得一个或多个假阳性的概率都很高。这是增加完整性的代价,我们几乎获得了 2 倍的收益,特别是对于大量甚至非常大量的测试 m 关于类似 Bonferroni 的方法。

现在,我们了解了 FWER 控制方法和 FDR 控制方法之间的关键区别:前者对 FWER 设置了上限α(“全局”α,下图),而后者对精度设置了下限 1α(“纯度”,上图)。

到目前为止,我们已经研究了假零假设数不变而检验数增加的情况。当错误假设的数量随着测试次数的增加而增加时会发生什么?例如,当我们将搜索扩展到参数空间的先前未探索的部分时,当我们期望错误的零假设/异常(或恒星爆炸,如在我们的天文学例子中)具有与先前相同的密度时,这种情况就会发生。

*# This time we have 30% of false hypothesis for each m
(selections, 
 false_positives, 
 false_negatives, 
 global_typeI) = characterize_methods(apply_ttest, 
                                      methods, 
                                      ms, 
                                      np.ceil(0.3 * ms).astype(int), 
                                      niter=800)

> Method holm-sidak **with** alpha 0.10.............completed
> Method holm-sidak **with** alpha 0.05.............completed
> Method fdr_bh **with** alpha 0.10.............completed
> Method fdr_bh **with** alpha 0.05.............completed*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结果与之前相似,但是现在 BH 方法的完整性(回忆)基本上是恒定的(中间的图),独立于 m

结论

我们已经用多重假设检验和两种非常不同的处理方法说明了这个问题。

  • 控制 FWER 的方法(如 Bonferroni 校正)以牺牲召回率(“完整性”和灵敏度)为代价最大化了精确度(“纯度”)。当预期的假零假设、异常或检测的数量很少,并且为假阳性付出的代价很高时,它们是合适的,因此纯度比完整性更重要。例如,当第一次寻找新效应/新物理时,它们是非常合适的,因为假零假设的预期数量最多是一个,而全局零假设真的很重要。在这种情况下,即使是一个错误的主张,当然也是非常重要的。然而,使用 FWER 会引入显著的 Malmquist 偏差,在这种情况下只能看到非常强的影响。
  • 控制 FDR 的方法(如 Benjamini-hoch Berg)通过允许受控数量的假阳性混入(即以受控的方式牺牲精度)而相对于 FWER 控制方法显著提高了完整性(召回)。当我们预期会有几个错误的零假设、异常或检测,并且我们可以承受一些错误的声明时,它们是合适的。

注:在这个说明性的例子中,我们对所有错误的零假设使用了一个单一的效应大小。这种情况几乎从未出现过,因此效应大小的分布(在我们的 t 检验示例中,两个群体的平均值之间的差异大小,或者在我们的天体物理学示例中,恒星爆炸的亮度)将明显影响异常/探测的数量。然而,这里提出的一般思想仍然成立。使用 FDR 代替 FWER 允许检测更多和更小的效应大小(增加灵敏度/召回),代价是一些假阳性。

密码

***import** numpy **as** np
**import** pandas **as** pd
**import** scipy.stats
**import** matplotlib.pyplot **as** plt
**import** sys
**import** multiprocessing
**import** itertools
**import** functools
**from** statsmodels.stats.multitest **import** multipletests
#Let's set the random seed so the results of the notebook
# are always the same at every run
np.random.seed(0)
%matplotlib inline
**def** generate_dataset(n_datasets, n_null_true, n_samples=100, seed=0):

    # This is to make the results predictable
    np.random.seed(seed)

    n_null_false = n_datasets - n_null_true

    w1 = []
    w2 = []
    null_status = []

    **for** i **in** range(n_null_true):

        wn_1 = np.random.normal(loc=90, scale=10, size=n_samples)
        wn_2 = np.random.normal(loc=90, scale=10, size=n_samples)

        w1.append(wn_1)
        w2.append(wn_2)

        null_status.append(True)

    **for** i **in** range(n_null_false):

        wn_1 = np.random.normal(loc=95, scale=10, size=n_samples)
        wn_2 = np.random.normal(loc=90, scale=10, size=n_samples)

        w1.append(wn_1)
        w2.append(wn_2)
        null_status.append(False)

    **return** w1, w2, np.array(null_status)

**def** worker_function(i, generate_dataset_kw, test, null_hyp_status):

    generate_dataset_kw['seed'] = (i+1) * 1000
    w1, w2, _ = generate_dataset(**generate_dataset_kw)
    pvalue = test(w1, w2)
    **return** null_hyp_status(pvalue, alpha) 

**def** measure_rejection_prob(n_iter, test, null_hyp_status, 
                           alpha, **generate_dataset_kw):       

    n_rejected = 0

    worker = functools.partial(worker_function, generate_dataset_kw=generate_dataset_kw,
                              test=test, null_hyp_status=null_hyp_status)

    pool = multiprocessing.Pool()

    **try**:

        **for** i, res **in** enumerate(pool.imap(worker, range(n_iter), chunksize=100)):
            **if** **not** res:
                n_rejected += 1
            **if** (i+1) % 100 == 0:
                sys.stderr.write("\r%i out of %i completed (fraction of "
                                 "rejections so far: %.2f)" % (i+1, n_iter, 
                                                               n_rejected / float(i+1)))
        sys.stderr.write("\n")
        sys.stderr.flush()

    **except**:

        **raise**

    **finally**:

        pool.close()
        pool.join()

    **return** n_rejected / float(n_iter)

**def** worker_function2(i, generate_dataset_kw, test, method, alpha):

    generate_dataset_kw['seed'] = (i+1) * 1000
    w1, w2, null_hyp = generate_dataset(**generate_dataset_kw)
    pvalues = test(w1, w2)

    reject, _, _, _ = multipletests(pvalues, alpha, 
                                    method=method, 
                                    is_sorted=False, 
                                    returnsorted=False)

    # False positives: I rejected when I shouldn't have
    n_false_pos = np.sum((reject == True) & (null_hyp==True))

    # False negatives: I didn't reject when I should have
    n_false_neg = np.sum((reject == False) & (null_hyp==False))

    **return** np.sum(reject), n_false_pos, n_false_neg
**def** measure_detections(n_iter, test, method, 
                       alpha, **generate_dataset_kw):       

    n_false_pos = []
    n_false_neg = []
    n_selected = []

    worker = functools.partial(worker_function2, generate_dataset_kw=generate_dataset_kw,
                              test=test, method=method, alpha=alpha)

    pool = multiprocessing.Pool()

    **try**:
        **for** i, (s, fp, fn) **in** enumerate(pool.imap(worker, 
                                                  range(n_iter), 
                                                  chunksize=100)):

            n_selected.append(s)
            n_false_pos.append(fp)
            n_false_neg.append(fn)
    **except**:

        **raise**

    **finally**:

        pool.close()
        pool.join()

    global_typeI = np.sum(np.array(n_false_pos) > 0) / float(n_iter)

    **return** (np.average(n_selected), 
            np.average(n_false_pos), 
            np.average(n_false_neg), 
            global_typeI)
**def** characterize_methods(test, methods, ms, n_false, niter=800, plot=True):

    selections = {}
    false_positives = {}
    false_negatives = {}
    global_typeI = {}

    **for** method, alpha **in** methods:

        # Clear output
        sys.stderr.write("Method %s with alpha %.2f" % (method, alpha))
        s = np.zeros(len(ms), int)
        fp = np.zeros_like(s)
        fn = np.zeros_like(s)
        gtI = np.zeros(s.shape[0], float)
        **for** i, (m, nf) **in** enumerate(zip(ms, n_false)):
            s[i], fp[i], fn[i], gtI[i] = measure_detections(niter, 
                                                test, 
                                                method,
                                                alpha, 
                                                n_datasets=m,
                                                n_null_true=m - nf)
            sys.stderr.write(".")

        selections[(method, alpha)] = s
        false_positives[(method, alpha)] = fp
        false_negatives[(method, alpha)] = fn
        global_typeI[(method, alpha)] = gtI

        sys.stderr.write("completed\n")

    **if** plot:

        fig, subs = plt.subplots(3, 1, sharex=True, 
                             figsize=(4,10), 
                             gridspec_kw={'hspace': 0.0, 'top': 0.95})
        **for** key **in** methods:
            true_positives = selections[key] - false_positives[key]
            precision = true_positives.astype(float) / selections[key]
            recall = true_positives / (true_positives + false_negatives[key]).astype(float)

            label = r"%s ($\alpha$=%.2f)" % (key[0], key[1])

            _ = subs[0].plot(ms, precision, label=label)
            _ = subs[1].plot(ms, recall, label=label)
            _ = subs[2].plot(ms, global_typeI[key], label=label)

        subs[0].set_ylabel("Precision\n(purity)")
        subs[1].set_ylabel("Recall\n(completeness)")
        subs[2].set_ylabel(r"Global $\alpha$")
        subs[2].set_xlabel("Number of tests")
        subs[2].set_xscale("log")

        plt.axes(subs[0])
        plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)

    **return** selections, false_positives, false_negatives, global_typeI*

使用签名时间序列模型预测比特币价格

原文:https://towardsdatascience.com/predict-bitcoin-prices-by-using-signature-time-series-modelling-cf3100a882cc?source=collection_archive---------13-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Pixabay

操纵数据流的新方法

路径签名简介

首先,我想简单介绍一下签名方法。根据维基百科,粗糙路径是平滑路径概念的概括,允许构建由经典不规则信号驱动的受控微分方程的鲁棒解理论,例如,维纳过程。这个理论是由特里·莱昂斯在 20 世纪 90 年代提出的。数学的目的是有效地描述一条平滑但可能高度振荡的多维路径 X。

签名是从路的幺半群(在级联下)到自由张量代数的群状元素的同态。它提供了路径 x 的分级总结。这里是签名变换的正式数学定义,来自《机器学习中的签名方法入门》。

为了一条路

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如下定义路径的签名

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在哪里

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

长话短说,签名是将路径转换成封装路径摘要的序列。

这些路径的分级总结或特征是粗略路径定义的核心;在本地,它们消除了查看路径的精细结构的需要。泰勒定理解释了任何光滑函数如何局部地表示为某些特殊函数(基于该点的单项式)的线性组合。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Taylor expansion of a function f(x,y)

坐标迭代积分(签名项)形成了更微妙的特征代数,可以以类似的方式描述流或路径;它们允许定义粗糙路径,并为路径上的连续函数形成自然的线性“基础”。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Expansion to signature

使用签名作为路径函数的基础有很多好处。首先,签名特征对于粗糙路径更鲁棒。第二,虽然路径的签名是无限长的序列,但我们可以使用它的截断版本作为基础来近似连续函数,而不会丢失太多信息。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

An approximation of a function f(X) with level 1 truncated signature features

此外,签名功能是可扩展的。举例来说,如果我们想将未来原油价格建模为历史原油价格的函数。

  1. 我们可以用过去的油价作为特征。我们使用的价格越多,关于其行为的信息就越多,模型就越精确,但计算成本也更高。也就是说,1000 个历史价格导致 1000 个特征,100 万个历史价格导致 100 万个特征。
  2. 或者,我们可以从过去的油价构建一条路径,并使用该路径的截断签名作为特征。即使我们对路径使用更多的过去价格,特征的数量也是一样的。例如,假设 X 是 2 维的路径,X 的 2 级截断签名只包括 7 个元素。也就是说,使用 1,000 个过去的价格或 1,000,000 个过去的价格将给我们 7 个特征。这将有助于计算时间(如果我们考虑到计算路径签名所花费的时间),并潜在地给我们关于数据的洞察力(一个签名特征可能是重要的)。然而,我们需要小心使用太低水平的截断,这可能导致拟合不足。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

A level 2 truncated signature of a path X with dimension 2

如果你想了解更多关于签名背后的数学知识,我推荐你去阅读

以下是签名功能的应用示例

我们想在这里做什么

最近,我们看到了加密货币交易的显著增长,其中最受欢迎的货币比特币在 2017 年底达到了近 20,000 美元/BTC 的峰值,而在 2018 年 11 月则暴跌至约 3000 美元/BTC。数字货币在金融市场上相当新,我们可以说它的行为几乎是不可预测的。知道了签名可以捕获路径的有意义的属性,并且可以用作线性基来近似路径的连续函数,作者想要探索当我们使用它来预测比特币价格时,这种有前途的方法会如何表现。我们将该结果与当前最先进的机器学习算法 XGBoost 算法进行比较。

我们将使用每日比特币兑换来自 https://www.cryptodatadownload.com/的价格数据。我们将使用美国最大的加密货币交易平台之一 Gemini 的数据。我们的目标是使用 30 天的窗口来预测未来 10 天的平均价格。对于签名方法,我们将使用 30 天价格的截断签名作为特征+ Lasso 线性回归,而对于 XGBoost,我们将使用 30 天价格作为特征。

数据预处理

我们使用熊猫来探索数据集。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们需要删除数据帧的第一行,反转数据帧并使用日期作为索引。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

所以现在我们已经准备好处理数据帧了。让我们先画出收盘价来形象化价格。

#Plot to visualise data
import matplotlib.pyplot as pltax = BTC_price.plot(y= 'Close', figsize=(12,6), legend=True, grid=True, use_index=True)
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们可能会对几个有趣的时期感兴趣,2017 年 10 月的繁荣以及 2018 年 1 月和 2018 年 10 月的崩溃。首先,我们将使用 2017 年 1 月至 2017 年 11 月的数据,看看该模型是否可以预测繁荣期。

#select duration
initial_date = '2017-01-01'
finish_date = '2017-12-01'BTC_price_time = BTC_price[initial_date:finish_date]

从数据帧创建特征

接下来,我们将为我们的机器学习算法构建特征。首先,我们将编写一个函数,该函数产生一个大小为 h 的历史价格窗口和下一个未来 f 价格的平均值。

我们将用长度为 10 的收盘价序列来测试我们的函数

BTC_price_time['Close'].head(10)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

GetWindow(BTC_price_time.loc[:,'Close'].head(10), h_window = 5, f_window =2)

我们得到一个包含大小为 5 的滚动窗口的数据帧,如下所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

GetNextMean(BTC_price_time.loc[:,'Close'].head(10), h_window = 5, f_window =2)

GetNextMean 为我们提供了一个数据帧,其中包含从第 6 个价格开始的 2 个连续价格的平均值。比如 896.12 = (893.49+898.75)/2。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

除了价格窗口,我们还为特性添加了时间列。

标志性特征

现在,让我们构建签名特征。如上所述,签名是连续路径的迭代积分形式,但我们只有离散的数据点。有多种方法可以将离散的数据点转换成连续的路径。举个例子,

  • 分段线性插值
  • 矩形线性插值

下面是从一本关于机器学习中签名方法的初级读本中得到的每个转换的插图。对于两个长度为 4 的一维序列,

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然而,还有另一种有趣的变换,即超前-滞后变换,它将一维路径变换为二维路径。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里,我们将在离散数据点上使用这种超前-滞后变换,并将该路径的特征用于我们的特征。

我们用一个序列(1,1),(2,4),(3,2),(4,6)进行测试。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

接下来,是时候计算路径的截断签名了!我们足够幸运,不用写函数来计算迭代积分。显然,有一个包 ESig 将为我们做(肮脏的)工作,尽管它仍处于开发的活跃阶段。

pip install esig
import esig.tosig as ts

下面是 ts.stream2sig(…)的文档。
stream 2 SIG(array(no _ of _ ticks x signal _ dimension),signature_degree)读取一个 2 维 numpy 浮点数组“流空间中的数据”,并返回一个 numpy 向量,其中包含到给定 signature_degree 为止的向量系列的签名。

我们将使用这个函数来计算路径的签名(Time_lead,Price_lead,Price_lag)。

获取功能

现在,我们准备计算正常特征和签名特征。为简单起见,我们将只使用比特币的接近价格。以下代码所做的是获得带有时间列的正常窗口特征,获得预测目标,即未来价格的平均值,并计算签名特征。对于签名特征,我们使用 ESig 包来寻找路径的 2 级截断签名(time_lead,price_lead,price_lag)。

我们可以检查结果特征。

y.head()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

pd.DataFrame(X_window).head()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

pd.DataFrame(X_sig).head()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

火车模型

我们将 X_sig,y 分成模型的训练集和测试集,我们将预测 10 个未来价格。

首先,我们将在具有签名特征的套索线性回归上训练我们的模型。我们使用时间序列分割测试交叉验证和 gridsearchCV 来调整超参数 alpha。

这是错误

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

时间序列预测不可或缺的一部分是将结果可视化。

PlotResult(y_train, y_test, y_train_predict, y_test_predict, test_len, 'Lasso + Signature features')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

该模型可以预测未来将出现一次繁荣,其精确度在 15%左右。注意,这里我们只使用 2 级截断签名特征。从理论上讲,如果我们增加截断的级别,我们希望模型会更准确,因为我们有更多的信息

现在我们将尝试我们的 XGBoost 模型。我们还使用时间序列分割交叉验证和 GridsearchCV 来调整超参数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们观察到训练集的平均绝对误差非常低,这是过度拟合的标志,并且测试集的值与签名方法大致相同。让我们把图表形象化

PlotResult(y_train, y_test, y_train_predict, y_test_predict, test_len, 'XGBoost')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们可以看到,该模型根本不能预测繁荣期,它猜测平均未来价格是稳定的。出现这种情况的一个可能原因是该模型以前没有经历过如此急剧的增长。

与他人进行一段时间的实验

我们将使用 2018 年 1 月至 2018 年 12 月的一段时间来测试该模型是否可以预测崩溃。我们测试了价格相当稳定的持续时间。

#select duration
initial_date = '2018-01-01'
finish_date = '2018-11-01'

以下是签名功能的结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们收到了一个收敛警告,说模型不收敛,结果图形很奇怪。请注意,这里我们只使用截断的签名级别 2,它只有 12 个特征,因此它们可能无法捕获有关路径的重要信息。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们用截断的签名级别 3 进行实验。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

该模型在术语或误差方面表现较差,但是我们可以从图中看到,它具有比 2 级截断签名特征更真实的路径。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

另一方面,这是 XGBoost 算法的结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

该模型做得非常好,做出了误差高达 0.5%的预测。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在,让我们挑战这些模型是否能够预测 2018 年 12 月的崩盘。

我们使用了 3 级截断签名功能,以下是结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

与 XGBoost 模型相比

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

很明显,没有一个模型能提前预测到撞车。在这里,我们可能会达到只使用历史价格的极限。在现实世界中,有许多因素会影响加密货币的价格,如新闻、其他金融产品的吸引力。然而,像这样的技术分析可以让我们快速了解数据。

结论

我们已经学会了如何使用签名特征来建模时间序列,并将其与 XGBoost 算法进行比较,XGBoost 算法是目前最先进的算法。XBGoost 在价格稳定时期表现非常出色,但在繁荣或萧条时,它无法给我们提供太多信息。另一方面,签名方法在价格稳定时期表现良好,但可能会提供一些关于重大变化的信息。尽管如此,作者选择的数据集可能会有偏差,因为我们事先知道什么时候是繁荣期,什么时候是萧条期。总之,这种方法很新,仍然需要证明自己,我鼓励读者尝试一下。

注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值