TowardsDataScience-博客中文翻译-2019-二十四-
TowardsDataScience 博客中文翻译 2019(二十四)
关于 Auto-Deeplab 你需要知道的一切:谷歌关于细分的最新消息
搜索图像分割模型
DeepLab 的所有早期版本(v1、v2、v3 和 v3plus)在发布时都拓展了语义分割问题的最新技术。与此同时,神经结构搜索已被用于击败由人类设计的网络设置的图像识别问题的最先进技术。因此,接下来的步骤是尝试解决密集图像预测问题,如使用神经架构搜索的语义分割。这个故事是对在 CVPR 2019 上发表的论文“ Auto-DeepLab:语义图像分割的分层神经架构搜索”的回顾。
内容:
- 介绍
- 建筑搜索空间
- 获取模型
- 实验结果
- 进一步阅读
介绍
语义分割问题是由一些最早的 CNN 如 AlexNet,VGG,Inception,ResNet 等解决的。然后出现了这些模型的改进版本,如 Wide ResNet、Xception、ResNeXt 等。然而,所有这些模型都是用于手头问题的通用特征提取器。这些模型之后是一系列专门用于分割的模型,例如提出 atrous convolutions 或 PSPNet 概念的 DeepLab 模型系列,这些模型分别在几个数据集的分割挑战中胜出。但是,现在使用的模型大多使用 ImageNet 预训练。然而,这里提出的模型在没有这种帮助的情况下也能产生有竞争力的结果。
为了减少搜索网络所需的计算能力,他们使用差分 NAS 而不是使用进化算法或强化学习的旧技术。这样,我们能够从潜在空间而不是完全随机的搜索中得到结构。
此外,NAS 在过去已经被用于搜索有规律地重复以形成整个网络的 CNN 块。换句话说,它只用于细胞内部水平,而不是确定网络结构。然而,在这里他们建议使用 NAS 来搜索网络以及搜索小区的正常任务。
建筑搜索空间
单元级搜索空间
要搜索一个单元格,首先,我们定义一个单元格。这里,信元是由 B 块组成的完全卷积模块。每个块是两个分支的结构,并且可以由 5 元组 (I₁,I₂,O₁,O₂,C) 定义,其中 I₁,I₂ ∈ Iˡᵢ是层 l 中块 I 的输入的所有可能选择的集合和 O₁,o\是块 c 的层类型的选择,是用于组合两个分支的单独输出以获得该块 h 的输出的方法。细胞的输出张量 Hˡ仅仅是来自块的输出的串联。一个区块的可能张量集合包含前两个单元的输出,即 Hˡ⁻和 Hˡ⁻。此外,来自单元中的块 j 的输出可以被输入到每个块 I,其中 i > j.
此外,每个模块中要考虑的分支类型如下:

深度方向可分离 conv 首先在 MobileNetV2 中引入,在 DeepLab 中引入 atrous conv。
网络级搜索空间
网络级搜索空间是特别需要的,因为这是一个密集图像预测问题,并且通常用于这种问题的网络倾向于从高分辨率图像开始,并且在网络期间在某处获得空间维度,然后再次回到原始维度。这里,作者将总下采样因子限制为 32。同样,空间维度上的移动可以仅通过因子 2 来完成。此外,层的总数,即线程单元的总数被设置为 12。
下图是潜伏空间的示意图。左边是整个网络的潜在空间。它是空间维度因子对层数的网格。当搜索架构时,根据每个可能的最终空间维度因子(s = 4,8,16,32)将用于分割的 ASPP 模块放置在每个可能的位置。
右图是细胞的潜在空间。它包含五个具有所有可能连接的块。这些连接将在下一节中解释。

获取模型
这是我们通过搜索得到模型的地方。这是一个分为三步的过程,如下所示:
细胞结构
首先,我们浏览解释如何搜索架构的系统,该系统也遵循上面定义的搜索空间。简而言之,我们使用下述公式对所有层(待选择的输入、待选择的分支和待选择的空间维度)的每个可能连接赋予权重:
块 Hᵢˡ的隐藏输出:

此外,我们使用以下公式估算每个连接要使用的 Oⱼ₋ᵢ分支:

基本上,连同正常的 CNN 权重,我们在整个潜在搜索空间中添加这些权重(αᵏⱼ₋ᵢ)(从现在起我将称它们为元权重),该潜在搜索空间包含可能的输入和单元内可能的分支之间的所有连接。我们给出一个加权加法,并了解这些元权重的什么组合给我们提供了单元的最佳结构。这种结构最好的部分是,因为上面的等式是可微的,所以元权重可以与正常权重同时训练。既然根据已经决定的潜在空间,我们可以把已经输出的前两个单元格转换成当前单元格。因此,在层 l 给出输出的单元的总体数学公式可以写为:

接下来是网络作为一个整体的结构,当在前面部分描述的潜在空间中时,该结构将被搜索。如果当前层的空间维度因子是 s,则该层的输入只能来自三个空间维度,即 s/2、s 和 s,按照潜在空间。因此,就像我们对单元结构所做的一样,我们定义元权重来获得正确的连接:

这里β是元权重的集合。βs 之间的关系如下:

优化
就像正常权重一样,我们使用交叉熵损失来训练这些“元权重”,以便获得优化的情况,其中α的各种值描述了我们在单元内的网络,而β的各种值描述了整体结构。经过训练,他们想出了以下模型。

他们通过第三步实现了这种架构:
解码
对于细胞结构,我们从所有可能的输入中选取两个最强的连接,使用该分支的最大α值,并对所有块重复这一练习。对于网络架构来说,不能贪婪地计算β的值。我们的目标是得到最终给我们带来最大价值的价值序列。这是动态编程的一个经典案例,使用 维特比算法 可以轻松解决。
解码后我们得到了如上图所示的最终结构。相比之下,Deeplab 的结构如下所示:

实验结果
这个模型最大的一个成果就是不需要任何 Imagenet 的预训练。结果可以总结在下表中。在 CityScapes 数据集上,AutoDeepLab-L 的性能优于 GridNet,而的性能与 DeepLabV3+相当,为 82.1%,而所需的计算能力几乎是后者的一半。

类似地,在 COCO 数据集上,结果与使用 Imagenet 预训练的模型相当。这显示了 NAS 的强大功能以及我们从这一理念中获得的体系结构。

进一步阅读
查看 Auto-DeepLab 的论文以了解更多关于这个想法的信息。
要了解更多关于计算机视觉和深度学习的信息,请关注我的 Medium 和 Github 。
也可以在 LinkedIn 关注我。
关于 TensorFlow 中的自动编码器,您需要了解的一切
在 TensorFlow 中从理论到实现

Photo by Alex wong on Unsplash
自动编码器是人工神经网络,可以从未标记的训练集中学习。这可能被戏称为无监督深度学习。它们既可以用于降维,也可以作为生成模型,这意味着它们可以从输入数据中生成新数据。
在本帖中,将介绍不同类型的自动编码器及其应用,并使用 TensorFlow 实现。
所有代码都可以在 Github 回购中获得。
点燃你的笔记本,让我们开始吧!
关于机器学习、深度学习和人工智能的实践视频教程,请查看我的 YouTube 频道。
Technically, we can generate new “faces” with autoencoders!
自动编码器如何工作
自动编码器将数据作为输入,将其转换为有效的内部表示,并输出看起来像输入的数据。
换句话说,它在输入中寻找模式,以生成新的东西,但非常接近输入数据。
自动编码器总是由两部分组成:
- 一个编码器或识别网络
- 一个解码器或生成网络
当然,编码器将输入转换成更简单的内部表示,解码器负责从内部表示产生输出。

Schema of an autoencoder. Note that the internal representation is also termed “code”. Source
注意,自动编码器在输入和输出层具有相同数量的神经元。为了迫使网络学习数据中最重要的特征,隐藏层必须具有较少的神经元。这样,它就不能简单地将输入复制到输出。由于隐藏层的维数比输出低,自动编码器被称为欠完成。
带自动编码器的 PCA
作为降维的一个例子,如果 PCA 仅使用线性激活函数,并且如果成本函数被设置为均方误差(MSE ),则可以用自动编码器来执行 PCA。
让我们看看如何实现这一点。
首先,我们创建一个虚拟 3D 数据集:

绘制数据集,我们得到:


Generated 3D dataset
厉害!现在,我们准备编码和训练一个自动编码器来执行 PCA:

现在,我们可以像这样绘制结果:

您应该会看到:

Result of PCA with an autoencoder
太好了!如您所见,自动编码器通过保持原始数据集的方差有效地执行了 PCA,但是是在 2D 平面上。
堆叠自动编码器
就像其他神经网络一样,自动编码器可以有多个隐藏层。它们被称为堆叠式自动编码器。更多的隐藏层将允许网络学习更复杂的特征。然而,过多的隐藏层可能会使输入过拟合,并且自动编码器将不能很好地概括。
堆叠式自动编码器的架构是关于编码层(中间隐藏层)对称的,如下图所示。

Schema of a stacked autoencoder
MNIST 的实施情况
让我们使用 MNIST 数据集来训练堆栈式自动编码器。
首先,我们导入 MNIST 数据集:

然后,我们构建堆栈式自动编码器:

我们运行它:

最后,我们可以看到自动编码器是如何重建数字的:

您应该会看到:

Reconstructed digits with a stacked autoencoder. Left: original digits. Right: reconstructed digits.
用可变自动编码器生成数字
2014 年推出的自动编码器的一个重要类别:变型自动编码器。它们在两个方面不同于传统的自动编码器:
- 它们是概率自动编码器,这意味着输出部分是偶然的,即使在训练之后
- 它们是生成式自动编码器;他们可以生成看起来像输入的新数据实例
变分自动编码器的结构与传统自动编码器的结构非常相似。但是,如下图,有一个小小的转折。

Schema of a variational autoencoder
这里,自动编码器产生了一个均值编码(μ)和一个标准差(σ)。然后,从具有相同均值μ和标准差σ的高斯分布中随机采样实际编码。然后,它被正常解码以产生输出。
此外,成本函数还有第二部分,称为潜在损失。这确保了自动编码器的编码看起来像是从简单的高斯分布中采样的。
让我们看看如何构建一个可变的自动编码器来生成新的手写数字。
至于前面的自动编码器,我们从定义架构和构建张量流图开始。您会注意到它与以前的自动编码器非常相似,但是我们添加了几个隐藏层来产生用于输出采样的平均值和标准偏差。

然后,我们可以通过从 MNIST 数据集学习来训练模型生成新的数字:

输出结果时,您应该看到:


Generated digits from a variational autoencoder
正如你所看到的,数字非常接近 MNIST 数据集,我们的变分自动编码器成功地学习了关于输入的最重要的特征。
干得好,坚持到了最后!在这篇文章中,我们了解了自动编码器如何工作,以及它们如何用于降维、无监督学习和作为生成模型。
参考:使用 Scikit-Learn 和 tensor flow-aurélien géRon 进行机器实践学习
关于谷歌新的行星强化学习网络,你需要知道的一切
Google AI 的 PlaNet AI 对强化学习研究意味着什么,迁移学习如何发挥关键作用

Learning to walk before we can run
迁移学习如今在机器学习社区风靡一时。
迁移学习是许多托管 AutoML 服务的基础,这些服务由谷歌、T2、T4、IBM、Azure 和 T7 提供。它现在在最新的 NLP 研究中占据显著地位——出现在谷歌的变形金刚双向编码器表示( BERT )模型和塞巴斯蒂安·鲁德和杰瑞米·霍华德的文本分类通用语言模型微调( ULMFIT )中。
正如 Sebastian 在他的博客文章中所写的,' NLP 的 ImageNet 时刻已经到来':
这些作品上了 头条,证明了预训练的语言模型可以用来在广泛的自然语言处理任务中实现最先进的结果。这种方法预示着一个分水岭时刻:它们可能会像预训练的 ImageNet 模型对计算机视觉一样,对 NLP 产生广泛的影响。
我们也开始看到神经网络的例子,它们可以使用跨领域的迁移学习来处理多项任务。Paras Chopra 有一个关于 PyTorch 网络的优秀教程,它可以基于文本描述进行图像搜索,搜索相似的图像和文字,并为图像编写说明(链接到他的帖子)。
使用单一模型构建图像搜索、图像标题、相似文字和相似图像
towardsdatascience.com](/one-neural-network-many-uses-image-captioning-image-search-similar-image-and-words-in-one-model-1e22080ce73d)
手头的主要问题是: 迁移学习能在强化学习中应用吗?
与其他机器学习方法相比,深度强化学习以数据饥渴而闻名,在其学习过程中易受不稳定性的影响(参见 Deepmind 的[关于带有神经网络的 RL 的论文](http://the correlations present in the sequence of observations, the fact that small updates to Q may significantly change the policy and therefore change the data distribution, and the correlations between the action-values and the target values.)),并且在性能方面落后。我们看到强化学习应用的主要领域和用例是游戏或机器人,也就是说,可以生成大量模拟数据的场景,这是有原因的。
与此同时,许多人认为强化学习仍然是实现人工智能的最可行的方法(AGI)。然而,强化学习不断地遇到在不同环境下概括许多任务的能力——这是智力的一个关键属性。
毕竟学习不是一件容易的事情。当这些环境既有高维度的感觉输入,又没有进步、回报或成功的概念或有极其延迟的概念时,这些强化学习代理必须处理和导出它们的环境的有效表示。最重要的是,他们必须利用这些信息将过去的经验推广到新的情况。
到目前为止,强化学习技术和研究主要集中在对单个任务的掌握上。我很有兴趣看看迁移学习是否可以帮助强化学习研究实现通用性——所以当谷歌人工智能团队今年早些时候发布 深度规划网络(星球)代理 时,我非常兴奋。
在行星后面
对于这个项目,PlaNet agent 的任务是“规划”一系列行动来实现一个目标,如极点平衡,教会虚拟实体(人类或猎豹)行走,或通过击打特定位置来保持盒子旋转。

Overview of the six tasks that the Deep Planning Network (PlaNet) agent had to perform. See the longer video
从最初介绍行星的谷歌人工智能博客帖子来看,这里有六个任务(加上与该任务相关的挑战):
- 横竿平衡:从一个平衡的姿势开始,代理人必须快速识别以保持横竿向上
- Cartpole Swingup: 带固定摄像头,这样手推车就可以移动到看不见的地方。因此,代理必须吸收和记忆多个帧的信息。
- 手指旋转:需要预测两个独立的物体,以及它们之间的相互作用。
- 猎豹奔跑:包括与地面难以精确预测的接触,需要一个可以预测多种可能未来的模型。
- Cup Catch: 只在球被接住时提供稀疏的奖励信号。这需要对未来进行准确的预测,以计划一系列精确的行动。
- 学步车行走:模拟机器人从躺在地上开始,必须先学会站起来再行走。
地球需要实现的这些任务之间有一些共同的目标:
- 代理需要预测各种可能的未来(为了稳健的规划)
- 代理需要根据最近行动的结果/回报来更新计划
- 代理需要在许多时间步骤中保留信息
那么 Google AI 团队是如何实现这些目标的呢?
行星 AI…其他的呢?
《人工智能星球》在三个不同的方面标志着传统强化学习的偏离:
- 用潜在动力学模型学习——PlaNet 从一系列隐藏或潜在状态而不是图像中学习,以预测潜在状态向前移动。
- 基于模型的规划 — PlaNet 在没有政策网络的情况下工作,而是基于持续的规划做出决策。
- 转移学习——谷歌人工智能团队训练了一个星球智能体来解决所有六个不同的任务。
让我们深入了解其中的每一项优势,看看它们如何影响模型性能。
#1 潜在动力学模型
作者在这里的主要决定是使用紧凑的潜在状态还是来自环境的原始感觉输入。
这里有一些权衡。使用紧凑的潜在空间意味着额外的困难,因为现在代理人不仅要学会击败游戏,还要建立对游戏中视觉概念的理解——这种图像的编码和解码需要大量的计算。
使用紧凑潜在状态空间的主要好处是,它允许代理学习更抽象的表示,如对象的位置和速度,也避免了必须生成图像。这意味着实际的计划要快得多,因为代理只需要预测未来的回报,而不是图像或场景。
潜在动态模型现在被更普遍地使用,因为研究人员认为“潜在动态模型与提供的奖励的同时训练将创建对与奖励信号相关的变化因素敏感的潜在嵌入,而对训练期间使用的模拟环境的外部因素不敏感。

Learned Latent Dynamics Model — Instead of using the input images directly, the encoder networks (gray trapezoids) compress the images’ information into hidden states (green circles). These hidden states are then used to predict future images (blue trapezoids) and rewards (blue rectangle).
查看这篇关于使用深度自动编码器进行高效嵌入式强化学习的优秀论文“”,其中提到:
在自主嵌入式系统中,减少现实世界中采取的动作数量和学习策略所需的能量通常是至关重要的。从高维图像表示中训练强化学习代理可能非常昂贵和耗时。自动编码器是深度神经网络,用于将像素化图像等高维数据压缩成小的潜在表示。
#2 基于模型的规划与无模型的规划

Great diagram from Jonathan Hui showing the spectrum of reinforcement learning approaches
基于模型的强化学习试图让代理学习世界的一般行为方式。取代直接将观察映射到行动,这允许代理明确地提前计划,通过“想象”他们的长期结果来更仔细地选择行动。采用基于模型的方法的好处是它的样本效率更高——这意味着它不会从头开始学习每个新任务。
观察无模型强化学习和基于模型强化学习之间差异的一种方法是,看看我们是在优化最大回报还是最小成本(无模型=最大回报,而基于模型=最小成本)。
像使用策略梯度这样的无模型强化学习技术可以成为强力解决方案,其中正确的动作最终被发现并内化为策略。政策梯度必须实际体验到积极的回报,并且经常体验,以便最终缓慢地将政策参数转向重复的高回报举措。
一个有趣的注意事项是任务的类型如何影响你可能选择采取的方法。在 Andrej Kaparthy 的精彩帖子“深度强化学习:来自 Pixel 的 Pongs”中,他描述了政策梯度可以击败人类的游戏/任务:
“在许多游戏中,政策梯度很容易击败人类。特别是,任何需要精确发挥、快速反应和不太多长期规划的频繁奖励信号都是理想的,因为奖励和行动之间的这些短期相关性可以很容易地通过方法“注意到”,并且通过政策精心完善执行。你可以在我们的 Pong 代理中看到这种情况的迹象:它开发了一种策略,在这种策略中,它等待球,然后快速冲刺,在边缘抓住球,以高垂直速度快速发射球。代理重复这一策略,连续得了几分。有许多雅达利游戏中,深度 Q 学习以这种方式破坏了人类的基线表现——例如弹球、突围等。”
#3 迁移学习
在第一场比赛后,星球代理人已经对重力和动力学有了初步的了解,并能够在接下来的比赛中重复使用这些知识。因此,PlaNet 的效率通常是以前从零开始学习的技术的 50 倍。这意味着代理只需要查看一个动画的五帧(字面意思是一个镜头的 1/5 秒)就能够以非常高的精度预测序列将如何继续。就实现而言,这意味着团队不必训练六个独立的模型来实现任务的稳定性能。
来自该论文:“PlaNet 解决了各种基于图像的控制任务,在最终性能方面与高级无模型代理竞争,同时平均数据效率高出 5000%……这些学习到的动态可以独立于任何特定任务,因此有可能很好地转移到环境中的其他任务”
查看 PlaNet 仅用 2000 集就超过 D4PG 的惊人数据效率提升:

From the paper: PlaNet clearly outperforms A3C on all tasks and reaches final performance close to D4PG while, using 5000% less interaction with the environment on average.
以及这些测试性能与收集的剧集数量的关系图(星球用蓝色表示):

Figure 4 from the PlaNet paper comparing PlaNet against model-free algorithms.
这些令人难以置信的令人兴奋的结果意味着数据高效和可推广的强化学习的新时代。留意这个空间!
想了解更多信息?这里有一些关于强化学习的其他好资源:
- TOPBOTS 最重要的 AI 强化学习研究
- 开启深度 RL 教程
- DeepMind 的 David Silver 的 RL 课程(讲座 1–10)
- Skymind.ai 的深度强化学习
- Andrej karpathy 的深度强化学习:来自像素的 Pong】
- [外加一个有趣的转移学习资源😎】迪潘坚(DJ)萨卡的转学指南
👉🏼有问题或反馈吗?下面评论!
👉🏼想要更多牛逼的机器学习内容?F 在 Medium 上关注我们!
关于假设检验你需要知道的一切—第一部分
统计学是关于数据的,但数据本身并不有趣。我们感兴趣的是对数据的解读…

数据科学领域正以前所未有的速度发展。许多公司现在正在寻找能够筛选他们的金矿数据并帮助他们有效地做出快速商业决策的专业人士。这也为许多在职专业人士将职业生涯转向数据科学领域提供了优势。
有了这个人工智能,数据科学周围的许多大学生也想在数据科学领域追求自己的职业生涯。托马斯·达文波特(Thomas H. Davenport)和 D.J .帕蒂尔(D.J. Patil)在《哈佛商业评论》(Harvard Business Review)的一篇文章中正确地指出了这种围绕数据科学的宣传,
“数据科学家:21 世纪最性感的工作”
在今天的分析世界中,建立机器学习模型已经变得相对容易(得益于更强大和灵活的工具和算法),但基本概念仍然非常混乱。其中一个概念是假设检验。
在这篇文章中,我试图用插图来阐明假设检验的基本概念。
什么是假设检验?我们想达到什么目的?为什么我们需要进行假设检验?在我们继续之前,我们必须知道所有这些问题的答案。
统计学就是关于数据的。光有数据是没意思的。我们感兴趣的是对数据的解释。使用假设检验,我们试图用样本数据解释或得出关于人口的结论。一个假设检验评估关于总体的两个互斥的陈述,以确定哪个陈述最受样本数据支持。每当我们想要对数据的分布或者应用机器学习中的一组结果是否不同于另一组结果做出断言时,我们都必须依赖于统计假设检验。
有两种可能的结果:如果结果证实了假设,那么你已经进行了测量。如果结果与假设相反,那么你就有了发现——恩利克·费密
让我们看看在假设检验中我们应该知道的术语
1.参数和统计:
参数是对目标人群的固定特征或测量的总结描述。一个参数表示如果进行人口普查而不是抽样调查将获得的真实值
例如: 均值(μ)、方差(σ)、标准差(σ)、比例(π)
群体:群体是我们想要研究/测试的对象的集合。对象集合可以是城市、学生、工厂等。这取决于手头的研究。
在现实世界中,很难获得完整的人口信息。因此,我们从总体中抽取一个样本,得出与上述相同的统计量。这些测量被称为样本统计。换句话说,
统计数据是对样本特征或测量的总结描述。样本统计用作总体参数的估计。
例如: 样本均值(x̄)、样本方差(s)、样本标准差(s)、样本比例( p)

Picture from CliffsNotes
2.抽样分布:
抽样分布是通过从特定人群中抽取大量样本而获得的统计数据的概率分布。
假设从 20 家医院中随机抽取 5 家医院。可能性可以是,(20,19,18,17,16)或(1,2,4,7,8)或者可以抽取 15,504 个(使用 20C₅组合)大小为 5 的不同样本中的任何一个。
一般来说,抽样分布的平均值将近似等于总体平均值,即( x̄) = μ
要了解更多关于抽样分布的信息,请查看下面的视频:
Video from Khan Academy
3.标准误差(SE):
标准误差(SE)非常类似于标准偏差。两者都是传播的量度。数字越大,数据分布越广。简而言之,这两个术语本质上是相等的,但有一个重要的区别。而标准差使用 统计 (样本数据)标准差使用 参数 (总体数据)
标准差告诉你你的样本统计量(如样本均值)与实际总体均值的偏离程度。样本量越大,误差越小。换句话说,样本量越大,样本均值就越接近实际总体均值。
要了解更多关于标准误差(SE)的信息,请观看下面的视频
现在让我们考虑下面的例子,以便更好地理解其余的概念。
4.(一)。零假设(H₀):
没有预期的差别或效果的陈述。如果零假设未被拒绝,则不会进行任何更改。
“无效”这个词在这个上下文中的意思是,这是一个普遍接受的事实,研究人员要取消。并不代表语句本身就是 null!(也许该术语应称为“可取消的抵押”,因为这样可能会减少混淆)
4.(二)。替代假说(H₁):
预期会有一些不同或效果的陈述。接受另一种假设会导致观点或行动的改变。它与零假设相反。
要了解更多关于无效假设和替代假设的信息,请观看下面的视频
5.(一)。单尾检验:
单尾检验是一种统计假设检验,在这种检验中,分布的临界区域是单侧的,因此它要么大于某个值,要么小于某个值,但不能同时大于和小于某个值。如果被测样本落入单侧临界区,替代假设将被接受,而不是零假设。
单尾检验也称为方向假设或方向检验。
临界区域:临界区域是对应于在某个选择的概率水平上拒绝零假设的值的区域。
5.(二)。双尾检验:
双尾检验是一种方法,在这种方法中,分布的临界区域是双侧的,并且检验样本是大于还是小于某个范围的值。如果被测样本属于任一关键区域,则接受替代假设,而不是零假设。
按照惯例,双尾检验用于确定 5%水平的显著性,这意味着分布的每一边都被截为 2.5%

6.测试统计:
检验统计量测量样本有多接近零假设。它的观测值从一个随机样本到另一个随机样本随机变化。检验统计包含与决定是否拒绝零假设相关的数据信息。
不同的假设检验根据零假设中假设的概率模型使用不同的检验统计量。常见测试及其测试统计包括:

Image from https://support.minitab.com
一般来说,样本数据必须提供足够的证据来否定原假设,并得出结论认为该效应存在于总体中。理想情况下,假设检验在总体中不存在效应时不能拒绝零假设,而在效应存在时拒绝零假设。
到目前为止,我们已经知道,整个假设检验是基于手头的样本进行的。如果样本改变了,我们可能会得出不同的结论。有两种错误与无效假设的错误结论有关。
7.(一)。第一类错误:
Type-I 当样本结果出现错误,导致原假设在事实上为真时被拒绝。第一类错误相当于误报。
第一类误差可以控制。与我们选择的显著性水平相关的α值与第一类误差有直接关系。
7.(二)。第二类错误:
第二类 错误发生在基于样本的结果,当零假设事实上为假时不被拒绝。第二类错误相当于假阴性。

显著性水平(α):
发生第一类错误的概率,用α表示。α是我们有一个类型 I 错误的最大概率。对于 95%的置信水平,α的值是 0.05。这意味着有 5%的概率我们会拒绝一个真正的零假设。
p 值:
p 值 几乎在所有的机器学习模型中,从 t 检验到简单的回归分析到基于树的模型,在所有的统计中都使用。我们都使用 P 值 来确定假设检验中的统计显著性。尽管如此重要, P 值 却是一个容易让人误解的概念。
P 值 评估样本数据在多大程度上支持“魔鬼代言人”的论点,即零假设为真。它衡量你的数据与零假设的符合程度。如果零假设为真,在样本数据中观察到的效果的可能性有多大?
换句话说,假设零假设为真,一个 P 值 是一个通过随机机会单独得到一个结果等于或大于样本结果的概率。
高 P 值:您的数据可能为真空值
低 P 值:您的数据不太可能为真空
例如:假设你在显著性水平(α)为 5%的情况下测试以下假设,你得到的 p 值为 3%,你的样本统计量为x̄=25
H₀: μ = 20
H₁: μ > 20
对 p 值的解释如下:
上面我们看到 α 也就是所谓的犯Type-I错误。当我们说α = 5%时,我们可以 100 次拒绝我们的零假设 5 次,即使它是真的。既然我们的p 值是 3%,这比 α (我们绝对低于犯下type-I错误的阈值)意味着获得尽可能极端的样本统计量(x̄【换句话说,只要我们假设 H₀为真,我们就无法获得样本统计量。因此,我们拒绝 H₀,接受 H₁.假设您得到的 P 值 为 6%,即假设零假设为真,获得尽可能极端的样本统计值的概率更高。所以我们没能拒绝 H₀,与 α 相比,我们不能冒险犯下I 型 错误超过约定的显著性水平。因此,我们不能拒绝零假设,也不能拒绝替代假设。**
既然我们已经了解了假设检验中的基本术语,现在让我们来看看假设检验中涉及的步骤以及一个示例。

例如,一家大型百货公司正在考虑推出网上购物服务。如果超过 40%的互联网用户通过互联网购物,这项新服务将会推出。
第一步:制定假设:
制定假设的适当方式是:
H₀: π ≤ 0.40
H₁: π > 0.40
如果零假设 H₀被拒绝,那么替代假设 H₁将被接受,新的互联网购物服务将被引入。另一方面,如果我们不能拒绝 H₀,那么除非获得额外的证据,否则不应该引入新的服务。这个零假设的检验是一个单尾检验,因为替代假设是定向表达的:使用互联网购物的网民比例大于 0.40。
第二步:选择合适的测试:
为了检验零假设,有必要选择适当的统计技术。对于这个例子,符合标准正态分布的【z】统计量是合适的。
z = (p-π)/σₚ,σₚ=sqrt(π(1-π)/n 所在的地方)
第三步:选择显著性水平,α:
我们了解到 显著性水平 是指 第一类 错误。在我们的示例中,如果我们根据样本数据得出结论,认为偏好新服务计划的客户比例大于 0.40,而实际上该比例小于或等于 0.40,则会出现第一类错误。
如果我们根据样本数据得出的结论是,偏好新服务计划的客户比例小于或等于 0.40,而实际上它大于 0.40,那么就会出现第二类错误。
有必要平衡这两种类型的误差。作为一种折衷,α通常设置为 0.05;有时是 0.01;α的其他值很少。对于我们的示例,我们将考虑 0.05。
第四步:收集数据并计算检验统计量:
在考虑了期望的α和其他定性因素(如收集样本数据的预算限制)后,确定样本量。以我们的例子为例,假设有 30 个用户接受了调查,其中 17 个表示他们使用互联网购物。
因此,样本比例的值为 p=17/30=0.567。
σₚ=sqrt((0.40)(0.60)/30)=0.089.的价值
测试统计量 z 可以计算为
z=(p-π)/σₚ=(0.567–0.40)/0.089=1.88
第五步:确定概率(或临界值):

使用上面的标准正态表,获得 1.88 的 z 值的概率是 0.96995,即 P(z≤1.88)=0.96995 。但是我们想要计算 z 右边的概率(因为我们对获得落在拒绝区域或临界区域的概率值感兴趣),即1–0.96995=0.03005。这个概率与α 直接相当(因为α正在犯 I 类错误,我们计算的概率值也落在临界区域内)
如果您想了解如何查找给定 z 分数的概率值,请观看以下视频:
或者, z 的临界值,将给出临界值 0.05 右侧的面积,在 1.64 (在 1.64 处,概率为 0.94950) 和 1.65 (在 1.65 处,概率为 0.95053) 之间,等于 1.645 (概率为 0.95,即从正态分布的左侧开始,这意味着向右
请注意,在确定检验统计的临界值时,超出临界值的尾部面积为 α或α/2。单尾检验为 α ,双尾检验为 α/2 。我们的例子是一个单尾测试。
如果您想了解如何查找 α、的临界值,请观看以下视频:
第 6 步和第 7 步:比较概率(或临界值)并做出决定:
与测试统计的计算值或观察值相关的概率是 0.03005。这是在π=0.40 时得到一个 P 值 为 0.567 的概率(样本比例= p) 。这低于 0.05 的显著性水平。因此,零假设被拒绝。
或者,测试统计量 z=1.88 的计算值位于拒绝区域,超出 1.645 的值。同样,得出了拒绝零假设的相同结论。
注意,检验零假设的两种方法是等价的,但是在比较的方向上数学上是相反的。如果与检验统计量(TSCAL)的计算值或观察值相关的概率 小于 显著性水平(α),则无效假设被拒绝。但是,如果检验统计量的计算值的绝对值 大于检验统计量的临界值的绝对值(TSCR),则无效假设被拒绝。这种符号偏移的原因是,TSCAL 的绝对值越大,在零假设下获得检验统计量的更极值的概率就越小。
如果 TSCAL 的概率< significance level (α), then reject H₀.
But, if |TSCAL| > |TSCR|,那么拒绝 H₀
第八步:结论:
在我们的例子中,我们的结论是,有证据表明,通过互联网购物的互联网用户比例明显大于 0.40。因此,建议百货公司引进新的网上购物服务。
这个例子指的是比例的一个样本测试。然而,有几种类型的测试取决于对人口和手头问题的了解。
例如,我们有一个 t 检验,Z 检验。卡方检验、曼-惠特尼检验、威尔科克森检验等。
至此,我想结束“关于假设检验你需要知道的一切”的第一部分。我将在第二部分讨论参数和非参数测试,以及在什么场景中使用哪种测试。直到那时快乐学习……
感谢阅读!
请在下面的评论部分分享您的反馈。
引用:
- 市场研究 Naresh K Malhotra 和 Satyabhushan Dash 的应用方向
- https://www . cliffs notes . com/study-guides/statistics/sampling/populations-samples-parameters-and-statistics
- https://www.statisticshowto.datasciencecentral.com
- https://www.khanacademy.org
- https://365datascience.com
- https://blog.minitab.com
关于假设检验你需要知道的一切—第二部分
何时使用哪种统计检验?

Image by Matthias Wewering from Pixabay
在我之前的帖子中,我讨论了我们必须了解的基本术语,这些术语是用插图进行假设检验的。如果你还没有检查过,你可以在这里找到:
统计学是关于数据的,但是数据本身并不有趣。这是对数据的解释,我们是…
towardsdatascience.com](/everything-you-need-to-know-about-hypothesis-testing-part-i-4de9abebbc8a)
我在这第二部分,我将重点关注统计测试。在我们查看了数据的分布,并可能进行了一些描述性统计以找到平均值、中位数或众数之后,是时候对数据进行推断了。在统计学中,我们将“假设检验”归入推断统计学。统计测试允许我们做出推断,因为它们可以显示观察到的模式是由于干预还是偶然。
一般来说,我们通过观察它们的【P 值】, 来识别建模过程中最重要的特征,除非一些关键的业务场景阻止我们考虑其他变量。如果我们分析任何流行的建模技术的输出,无论是线性或逻辑回归还是 XGBoost 或随机森林,我们都会检查 P 值 以及它是否为 < 0.05(在 95%的置信水平下) 以确定模型中的显著性。我们如何获得这些 P 值?在带下划线的建模过程中,我们在测试什么?执行了哪些统计测试?
这些问题将帮助你理解我们在预测变量上测试的假设,最终帮助你做出商业决策。然而,有时,分析专家会对在给定场景中应该使用哪种统计测试感到困惑。选择使用哪种统计检验取决于研究设计、数据分布和变量类型。但是,只要稍微关注一下手头的问题,就很容易决定我们应该使用哪种类型的统计检验来得出结论。
在我们了解所有这些之前,让我们试着理解一些关于统计测试的细微差别。
统计测试旨在确定是否有足够的证据来“拒绝”一个无效假设。如果我们想继续表现得好像我们“相信”零假设是正确的,不拒绝可能是一个好结果。或者这可能是一个令人失望的结果,可能表明我们可能还没有足够的数据来通过拒绝零假设来“证明”一些东西。
当我们进行假设检验时,我们必须问自己我们在检验什么?我们是在测试两个群体之间的联系还是他们之间的差异?我们要测试一组还是两组项目?所有这些问题都关系到选择正确的统计测试。一般来说,我们可以把假设检验大致分为两类。

Classification of Hypothesis Tests
让我们看一个测试两个组之间关联的例子:
在我之前的帖子中,我们讨论了互联网购物服务是否已经推出。对于那些没有机会阅读我上一篇文章的人来说,这里有一个例子:
一家大百货公司正在考虑引进网上购物服务。如果超过 40%的互联网用户通过互联网购物,这项新服务将会推出。在这种情况下,我们使用 Z-test 进行假设检验,无效假设和替代假设分别为;
H₀: π ≤ 0.40
H₁: π > 0.40
现在假设我们对确定互联网使用是否与性别有关感兴趣。
让我们假设那些报告 5 小时或更少使用时间的用户被归类为轻度用户,其余的是重度用户。数据显示在下面的交叉表中。
交叉制表: 它是一种定量分析多个变量之间关系的方法。有时我们称之为“列联表”或“交叉表”交叉制表通常在 分类数据上执行,这些数据可以被分成互斥的组。
让我们来看看下面的轻度和重度互联网用户的交叉列表。

上面的交叉表包括两个变量类别的每种组合的一个单元格。10 名受访者是女性,她们报告说很少使用互联网。该表中的边际总量表明,在对两个变量都有有效回答的 30 名受访者中,15 名报告轻度使用,15 名报告重度使用。从性别来看,15 名受访者为女性,15 名为男性。
为了检验交叉制表中观察到的关联的统计显著性,我们使用了 卡方统计量(χ ) 。它帮助我们确定这两个变量之间是否存在系统的联系。在这种情况下,我们试图测试互联网使用(轻度/重度)与性别之间的关联。
H₀的零假设是变量之间没有关联。
卡方检验是如何计算的: 一般来说,在给定现有行和列总数的情况下,如果变量之间不存在关联,则通过计算预期的单元格频率来进行检验。这些预期的小区频率,表示为 fₑ,然后与实际观察到的频率进行比较,fₒ在交叉表中找到,以计算卡方统计。预期频率和实际频率之间的差异越大,统计值就越大。假设一个交叉制表有 r 行和 c 列以及一个随机抽样的 n 个观察值。则预期频率可计算如下:
fₑ = (nᵣ n꜀)/n,在那里,
nᵣ =该行中的总数,
n꜀ =该列中的总数,
n =总样本量
对于互联网使用数据,从左到右和从上到下,单元的预期频率为:
(15 X 15) / 30 = 7.50
(15 X 15) / 30 = 7.50
(15 X 15) / 30 = 7.50
(15 X 15) / 30 = 7.50
χ 的值计算如下:
χ=∑(fₒ-fₑ)/fₑ
χ=(5–7.5)/7.5+(10–7.5)/7.5+(10–7.5)/7.5+(5–7.5)/7.5
χ=0.833+0.833+0.833
χ = 3.333
为了确定系统关联是否存在,估计获得与交叉表计算值一样大或更大的卡方值的概率(换句话说,计算 p 值)。卡方统计的一个重要特征是与其相关的【df】自由度的数量。
自由度:是指计算中涉及的有 自由度 变化的数值个数。换句话说,的自由度,一般来说,可以定义为观察值的总数减去施加在观察值上的独立约束的数目。
在与交叉制表相关的卡方统计的情况下,自由度的数量等于行数( r) 减一和列数减一的乘积。即 df = (r-1) * (c-1)。只有当检验统计的计算值大于具有适当自由度的卡方分布的临界值时,两个变量之间无关联的零假设(H₀)才会被拒绝,如下图所示。

chi-square distribution with the critical region
卡方分布是一种偏斜分布,其形状仅取决于自由度的数量。随着自由度数量的增加,卡方分布变得更加对称。

在这种情况下,自由度为 1(即(2–1)(2–1))。使用卡方表,我们得到的临界值为 3.84,显著性水平为 5%(您可以从下面的卡方表中看到)*

Chi-Square table at different α values
我们得到卡方计算值为 3.33。因为这小于临界值 3.84,所以无关联的零假设不能被拒绝,表明在 5%的水平上关联没有统计学意义。请注意,这种缺乏显著性主要是由于样本量小(本例中为 30)。相反,如果样本量为 300,交叉表的每个条目乘以 10,可以看出卡方统计值将乘以 10,为 33.33,在 5%的水平上显著。
卡方统计应仅根据数据计数进行估计。当数据为百分比形式时,应首先将其转换为绝对计数或数字。此外,卡方检验的一个基本假设是观察值是独立得出的。作为一般规则,当任何单元中的预期或理论频率小于 5 时,不应进行卡方分析。
像卡方检验一样,可以根据手头的问题使用其他统计检验。让我们看看还有哪些其他可用的统计测试,以及在什么情况下我们可以使用它们。
**
下面的图表总结了在选择正确的测试之前需要回答的问题。

给定研究设计,如何选择正确的统计检验的几个例子:

就此,我想对假设检验的话题做个总结。我希望你觉得这是有用的。
感谢阅读!
请在下面的评论部分分享您的反馈。
引用:
- 市场研究 Naresh K Malhotra 和 Satyabhushan Dash 的应用方向
- https://cyfar.org
关于线性回归你需要知道的一切
线性回归是机器学习领域的第一块敲门砖。如果你是机器学习新手或数学极客,想知道线性回归背后的所有数学知识,那么你和我 9 个月前的情况一样。在这里,我们将看看线性回归的数学,并了解其背后的机制。

Linear Regression (Source: https://datumguy.com/blog/blog/view/5ce138213122e?utm_content=buffer09809&utm_medium=social&utm_source=facebook.com&utm_campaign=buffer)
介绍
线性回归。分解之后,我们得到两个词‘线性’和‘回归’。当我们从数学角度思考时,“线性”一词似乎与直线有关,而“回归”一词意味着一种确定两个或多个变量之间统计关系的技术。
简单地说,线性回归就是找到一条几乎与给定数据相符合的直线的方程,这样它就可以预测未来的值。
假设
这个假设是什么?这只不过是我们正在谈论的直线方程。让我们看看下面的等式。

你觉得这个眼熟吗?这是一条直线的方程式。这是一个假设。让我们用类似的方式重写一下。

我们刚刚分别将 y 替换为 h(x) 和 c ,将 m 替换为θ₀和θ₁。 h(x) 将是我们的预测值。这是机器学习中最常见的写假设的方式。
为了理解这个假设,我们以房价为例。假设您收集了您所在地区不同房屋的大小及其各自的价格。该假设可以表示为

现在你所要做的就是根据你的数据集找到合适的基价和θ₁的价值,这样你就可以在给定房子大小的情况下预测它的价格。
更专业地说,我们必须调整θ₀&θ₁的值,以使我们的线尽可能地适合数据集。现在我们需要一些度量来确定“最佳”线,我们已经有了。这叫做成本函数。让我们调查一下。
成本函数 J(θ)
线性回归的成本函数为

为了让它对我们的大脑来说看起来更漂亮,我们可以把它重写为

这里的 m 表示数据集中的样本总数。在我们的例子中, m 将是我们数据集中房屋的总数。
现在仔细看看我们的成本函数,我们需要所有 m 个例子的预测值,即 h(x) 。让我们再看看我们的预测值或预测价格是什么样子的。

为了计算我们的成本函数,我们需要的是所有 m 个例子的 h(x) ,即 m 个预测价格对应于 m 个房屋。
现在,为了计算 h(x) ,我们需要一个底价和θ₁.的价值请注意,这些是我们将调整以找到最合适的值。我们需要一些东西来开始,所以我们将随机初始化这两个值。
成本函数的解释
如果你仔细观察成本函数

你会发现我们所做的只是在所有的 m 个例子中平均预测值和实际值之间的距离的平方。

看上图,这里 m = 4。蓝色线上的点是预测值,红色点是实际值。绿线是实际值和预测值之间的距离。
这条线路的费用是

所以成本函数计算的只是绿线长度平方的平均值。我们还将它除以 2,以简化我们将看到的一些未来的计算。
线性回归试图通过找到θ₀和θ₁.的合适值来最小化这个成本如何?通过使用梯度下降。
梯度下降
对于机器学习来说,梯度下降是一种非常重要的算法。从线性回归到神经网络,它无处不在。


这是我们更新权重的方法。这个更新规则是在一个循环中执行的&它帮助我们达到成本函数的最小值。 α 是一个恒定的学习速率,我们一会儿会谈到它。
U 理解梯度下降
所以基本上我们是在更新我们的权重,用我们的成本函数对权重的偏导数减去它。

但是这怎么能把我们带到最小的成本呢?让我们想象一下。为了便于理解,我们假设θ₀现在为 0。
所以假设变成了

和成本函数

现在让我们看看成本如何依赖于θ₁.的价值因为这是一个二次方程,所以θ₁对 j(θ)的图形将是一条抛物线,并且看起来像这样,其中θ₁在 x 轴上,j(θ)在y 轴上。**

Source: Machine Learning by Andrew Ng
我们的目标是达到成本函数的最小值,当我们的θ₁等于θₘᵢₙ.时,我们将得到这个最小值**
现在,首先我们将随机初始化我们的θ₁.**

Source: Machine Learning by Andrew Ng
假设θ₁初始化,如图所示。当前θ₁对应的成本等于图上的蓝点。
现在,让我们使用梯度下降更新θ₁。

我们正在减去成本函数 w . r . tθ₁乘以某个常数的导数。

Source: Machine Learning by Andrew Ng
成本函数 w . r . tθ₁的导数给出了曲线在该点的斜率。这在这些情况下是积极。所以我们从θ₁.的当前值中减去正的量这将迫使θ₁向左移动,并慢慢发散到θₘᵢₙ的值,在那里我们的成本函数最小。 α 的作用来了,就是我们的学习率。学习率决定了我们想要在一次迭代中下降多少。此外,这里需要注意的一点是,随着我们向最小值移动,曲线的斜率也变得不那么陡峭,这意味着,随着我们达到最小值,我们将采取越来越小的步骤。

Source: Machine Learning by Andrew Ng
最终,斜率将在曲线的最小值处变为零,然后θ₁将不会更新。**
这样想吧。假设一个人在山谷的顶端,他想到达谷底。因此,当坡度较陡时,他走较大的步子,当坡度不太陡时,他走较小的步子。他根据当前位置决定下一个位置,当他到达他的目标山谷底部时停下来。
类似地,如果θ₁在最小值的左侧被初始化,

Source: Machine Learning by Andrew Ng
这一点的斜率将是负的。在梯度下降中,我们减去斜率,但这里斜率是负的。所以,否定之否定就会变成肯定。因此,我们将继续增加,直到达到成本最低。

Gradient Descent (Source: https://saugatbhattarai.com.np/what-is-gradient-descent-in-machine-learning/)****
上图很好的描绘了梯度下降。注意当我们到达最小值时,步长是如何变得越来越小的。
类似地,θ₀的值也将使用梯度下降进行更新。我没有展示它,因为我们需要同时更新θ₀和θ₁的值,这将导致一个三维图形(一个轴上是成本,θ₀在一个轴上,而θ₁在另一个轴上)变得有点难以想象。
成本函数的导数
我们在梯度下降中使用成本函数的导数。
****
我们来看看微分后得到的结果。

同样,对于θ₁

线性回归可视化

Linear Regression Visualization
在此可视化效果中,您可以看到线是如何拟合到数据集的。注意,最初,这条线很快就覆盖了这段距离。但是随着成本的降低,线路变得更慢。
我的 GitHub 上有上面可视化的代码。
有问题吗?需要帮助吗?联系我!
电子邮件:sushantpatrikarml@gmail.com
github:https://github.com/sushantPatrikar
领英:https://www.linkedin.com/in/sushant-patrikar/
网址:【https://sushantpatrikar.github.io/ T3
关于 MobileNetV3 您需要知道的一切

当 MobileNet V1 在 2017 年到来时,它基本上开始了计算机视觉深度学习研究的一个新领域,即提出可以在嵌入式系统中运行的模型。这导致了几个重要的工作,包括但不限于 ShuffleNet(V1 和 V2),MNasNet,CondenseNet,EffNet 等。介于两者之间的是去年推出的第二版 MobileNet。现在,今年的迭代给了我们 MobileNet 的第三个版本,叫做 MobileNetV3。这篇文章是对今年在韩国首尔 ICCV 上展示的谷歌 MobileNetV3 的回顾。
内容:
- 高效移动积木
- 用于逐块搜索的神经架构搜索
- 网络适配分层搜索
- 网络改进—层移除和 H-swish
- 整体结构
- 实验和结果
与以前的版本相比,第三版中有很多变化。:d .我认为这对于击败已经令人震惊的移动互联网 2 是必要的。如果需要的话,我将尝试简单回顾一下早期版本(主要是 V2)的概念。
高效的移动构建模块
MobileNetV1 引入了深度卷积来减少参数数量。第二个版本在块中增加了一个扩展层,使用三层得到一个扩展-过滤-压缩(见下图[1]) 的系统。这个系统——被称为反向剩余块——进一步帮助提高了性能。

最新版本在取自 V2 的初始构建模块中增加了挤压和激励层[2],这将在以后进行进一步处理(NAS 和 NetAdapt)。与 V2 的比较见下图。

如上图所述,使用了 h-swish 非线性,这将在后面的故事中讨论。挤压和激励模块的添加有助于在创建输出特征图时,对来自输入的不同通道给予不相等的权重,假设输出特征图与普通 CNN 给予的权重相等。挤压和激励通常分别添加到 resnet/inception 模块中。但是,在此模型中,它是与 resnet 层并行应用的。挤压层和激发层如下(上图底部的小箭头):
池- >密- >热卢- >密->h-唰- >鳞退。
光模型的神经结构搜索
用外行人的话来说,神经架构搜索(NAS)[3]是试图让一个模型(通常是一个 RNN,也称为控制器)输出一个模块线程的过程,这些模块可以放在一起形成一个模型,通过在所有可能的组合中进行搜索,给出可能的最佳精确度。基本算法可以用这个图来概括[4]。

这类似于强化学习的标准过程。存在一个奖励函数,根据该函数更新控制器。这样做是为了追求一种状态,在这种状态下,从当前状态得到的回报是最大的。在 NAS 术语中,模型从当前状态移动到奖励准确度增加的状态。
通常,在大多数论文中,NAS 用于获得高效子模块的结构,这些子模块可以重复堆叠在一起以获得整个模型。然而,在这里,它是除了 NetAdapt 算法(稍后讨论)之外使用的,NetAdapt 算法将用于决定每一层的过滤器数量。因此,NAS 将用于优化每个数据块。
此外,因为我们想要一个轻型模型,所以 NAS 也相应地进行了调整。我们致力于一个新的奖励函数:ACC(m)×【lat(m)/tar]^w,】T3,它考虑了模型的准确性和延迟(总推理时间)。ACC 是准确度,LAT 是等待时间,TAR 是目标等待时间,m 是搜索得到的模型。这里 w 是一个常数。作者还观察到,对于较小的模型(我们正在寻找),w 需要是 -0.15 (相对于原始的 w = -0.07 )。
有了所有这些变化,NAS 产生了一种可以使用 NetAdapt 按层进一步优化的网络体系结构。
用于分层搜索的网络适配器
原始的 NetAdapt[5]算法对每个 conv 的过滤器数量起作用,如下所示:

在这里,它试图为每个有问题的 conv 优化过滤器的数量,并选择具有最高精度的模型。K 个模型中具有最高峰值精度的模型是在 K 个 conv 层中的一个上工作得到的。
在 MobileNet 中工作的该算法的一种简化版本如下:
- 从 NAS 输出开始。
- 生成一组提案。与上一步中的模型相比,每个方案的延迟应减少δ。
- 通过使用来自先前网络的权重和任何新过滤器的随机初始化,为新的提议设置权重。
- 微调最终选定的方案,直到达到目标延迟。
最终选择基于一个度量标准。作者选择(Acc 变化/潜伏期变化) 。这是凭直觉完成的,即准确性和延迟两个因素都保留在组合中,并且优先选择最大化准确性-延迟权衡斜率的模型。
网络改进
网络改进有两种方式:
- 图层移除
- swish 非线性
图层移除
这里,我们讨论一些不借助搜索而手动完成的更改。这主要在前几层和最后几层完成。以下是这篇论文所做的调整:
- 在最后一个块中,从 MobileNetV2 的反向剩余单元中提取的 1x1 扩展层被移过池层。这意味着 1x1 图层处理大小为 1x1 的要素地图,而不是 7x7,从而在计算和延迟方面更高效。
- 我们知道扩展层需要大量的计算。但是现在它被移到了一个池层的后面,我们不需要从上一个块的最后一个层进行投影层的压缩。因此,我们可以从先前的瓶颈层(块)中移除投影层和过滤层。这两种变化都显示在这个图中。

3.一个实验性的改变是在初始的 3x3 层中使用 16 个过滤器,而不是 32 个,这是默认的移动模型。
这些变化总共节省了 9 毫秒的推理时间。
非线性
swish 非线性被定义为:

实验证明,它可以提高精度。然而,由于 sigmoid 函数的计算开销很大,并且我们非常关心该模型中的计算开销,因此作者使用所谓的硬 swish 或 h-swish 对其进行了修改:

下图比较了讨论中的所有非线性:

显然,就曲线而言,h-swish 与 swish 没有太大的不同,尽管它的计算开销更小。
整体结构
这就引出了整体结构。本文定义了两个术语:移动网络 3-大型和移动网络 3-小型。两者的结构如下(左边 MobileNetV3-大,右边 MobileNetV3-小):


在前几层和后几层中可以看到上一节所述的变化,特别是在 1x1 最终 conv2d 层之前将池层放置在 7x7 输入上。
实验和结果
作者在计算机视觉的不同问题上做了大量的实验来证明这个模型的实际价值。我们将逐一讨论它们。
因为这篇论文是由谷歌的一群人写的(很多人都是这篇论文的作者,😄),所以显然任何嵌入式设备都必须是 Pixel。他们使用 Pixel 1/2/3,并将其表示为 P-n。还有一点需要注意的是,所有这些结果都是在单核硬件上完成的,而不是这些手机拥有的多核硬件。
分类


左边的表格清楚地显示了从 V2 到 V3 的延迟降低,即使在 Imagenet 上分类的准确度提高了。
目标检测
对于检测实验,作者使用 MobileNetv3 作为 SSDLite 上的主干,以下是结果:

事实证明,在保持类似地图的情况下,MobileNetv3-Large 比 MobileNetV2 快 27% 。
分割
对于语义分割,作者提出了一种新的分割头,它来自 R-ASSP[6],命名为 Lite R-ASSP 或 LR-ASSP。它是基于使用挤压和激励时汇集的想法

作者报告说,LR-ASSP 比与 MobileNetV2 一起提出的前身 R-ASSP 更快。
此外,MobileNetV3 主干网比 V2 的稍快。
结论
谷歌使用神经架构搜索得出最先进的结果是未来深度学习和计算机视觉的伟大成果,因为这可能是使用和进一步改进这种网络搜索算法的巨大动力。这样的改进可能会导致我们完全依赖搜索来决定模型架构的阶段。 MobileNetV3 给出了轻量级模型在主要计算机视觉问题上的 SOTA 结果。
参考
[1]https://machinethink.net/blog/mobilenet-v2/
[2]胡俊杰、沈立群和孙广昌。挤压和激励网络。ArXiv 电子版,2017 年 9 月
[3] Barret Zoph 和 Quoc 诉 Le。强化学习的神经结构搜索。更正,abs/1611.01578,2016
[4]https://towardsdatascience . com/everything-you-neural-architecture-search-8db 1863682 BF
[5]杨天柱、Andrew G. Howard、、肖章、Alec Go、Mark Sandler、Vivienne Sze 和 Hartwig Adam。Netadapt:面向移动应用的平台感知神经网络适配。在 ECCV,2018 年
[6] Mark Sandler,Andrew G. Howard,Menglong Zhu,Andrey Zhmoginov 和陈良杰。Mobilenetv2:反向残差和线性瓶颈。用于分类、检测和分段的移动网络。更正,abs/1801.04381,2018
关于我
对深度学习感兴趣?我尝试研究很酷的深度学习想法,尤其是在计算机视觉领域。访问我的 Github 个人资料。
你需要知道的关于神经网络和反向传播的一切——机器学习简单而有趣
神经网络的基础解释,包括理解背后的数学

我发现很难在一个地方得到关于神经网络的一步一步和详细的解释。在课程或视频中,总会遗漏一些解释。所以我试着在一篇博文中收集所有的信息和解释(一步一步)。我会把这个博客分成 8 个部分,因为我觉得它最相关。
- 模型表示
- 模型表示数学
- 激活功能
- 偏置节点
- 价值函数
- 正向传播计算
- 反向传播算法
- 代码实现
那么让我们开始……
模型表示
人工神经网络 是受构成动物大脑的生物神经网络启发的计算系统。这种系统通过考虑例子来“学习”执行任务,通常没有用任何特定于任务的规则来编程。

Image 1: Neural Network Architecture
神经网络由 3 种类型的层构成:
- 输入层-神经网络的初始数据。
- 隐藏层-输入层和输出层之间的中间层,所有计算都在此完成。
- 输出图层-生成给定输入的结果。
上图中有 3 个黄色圆圈。它们代表输入层,通常记为矢量x。有 4 个蓝色和 4 个绿色圆圈代表隐藏层。这些圆圈代表“激活”节点,通常记为 W 或 θ 。红色圆圈是输出图层或预测值(或多个输出类/类型的值)。
每个节点都与下一层的每个节点相连接,并且每个连接(黑色箭头)都有特定的权重。权重可以被视为该节点对来自下一层节点的影响。因此,如果我们看一下一个节点,它会像这样

Image 2: Node from Neural Network
我们来看最上面的蓝色节点(“图片 1】)。前一层(黄色)的所有节点都与之相连。所有这些连接都代表权重(影响)。当来自黄色层的所有节点值乘以它们的权重并且所有这些被汇总时,它给出了顶部蓝色节点的一些值。蓝色节点具有预定义的“激活”功能(“图像 2”上的单位步进功能),该功能根据汇总值定义该节点是否将被“激活”或其“激活”程度。值为 1 的附加节点称为“偏置”节点。
模型表示数学
为了理解数学方程,我将使用一个更简单的神经网络模型。这个模型将有 4 个输入节点(3 + 1“偏差”)。一个隐藏层,有 4 个节点(3 + 1“偏差”)和一个输出节点。

Image 3: Simple Neural Network
我们将把“偏差”节点分别标记为 x₀和 a₀。因此,输入节点可以放在一个向量 X 中,隐藏层的节点放在向量 A 中。

Image 4: X (input layer) and A (hidden layer) vector
重量(箭头)通常记为 θ 或 W. 在这种情况下,我将它们记为 θ。输入层和隐藏层之间的权重将代表 3x4 矩阵。并且隐藏层和输出层之间的权重将表示为 1x4 矩阵。
如果网络在层 j 中有 a 个单元,在层 j +1 中有 b 个单元,则θⱼ的维数为 b ×(a+1) 。

Image 5: Layer 1 Weights Matrix (θ)
接下来,我们想要的是计算隐藏层的“激活”节点。为此,我们需要将输入向量 X 和权重矩阵 θ 乘以第一层(X***【θ】,然后应用激活函数 g 我们得到的是:

Image 6: Compute activation nodes
并且通过将隐藏层向量与第二层的权重矩阵θ(A***θ)相乘,我们得到假设函数的输出:

Image 7: Compute output node value (hypothesis)
这个例子只有一个隐藏层和 4 个节点。如果我们试图推广具有多个隐藏层和每个层中的多个节点的神经网络,我们将得到下一个公式。

Image 8: Generalized Compute node value function
其中我们有具有 n 个节点的 L 层和具有 m 个节点的层。
激活功能
在神经网络中,激活函数基于加权和来定义给定节点是否应该被“激活”。我们把这个加权和值定义为 z 。在本节中,我将解释为什么“阶跃函数”和“线性函数”不起作用,并讨论最流行的激活函数之一的“ Sigmoid 函数”。还有一些其他的功能,我暂时先放在一边。
阶跃函数
第一个想法是使用所谓的“阶跃函数”(离散输出值),其中我们定义阈值和:
if(z >阈值)——“激活”节点(值 1)
if(z <阈值)——不“激活”节点(值 0)
这看起来不错,但它有缺点,因为节点只能输出值 1 或 0。如果我们想要映射多个输出类(节点),就会遇到问题。问题是有可能激活多个输出类/节点(值为 1)。所以我们不能正确地分类/决定。
线性函数
另一种可能是定义“线性函数”,并获得一系列输出值。

然而,在神经网络中仅使用线性函数会导致输出层是线性函数,因此我们不能映射任何 非线性 数据。对此的证明如下:

然后由函数组合我们得到

这也是一个线性函数。
Sigmoid 函数
它是当今使用最广泛的激活功能之一。它的方程式由下面的公式给出。

Image 9: Sigmoid Equation. source: wikipedia

Image 10: Sigmoid Function. source: wikipedia
它有多种属性,这使得它如此受欢迎:
- 这是非线性函数
- 范围值在(0,1)之间
- 在 x 轴上的(-2,2)之间,函数非常陡峭,这导致函数倾向于将值分类为 1 或 0
由于这个属性,它允许节点取 0 到 1 之间的任何值。最后,在多个输出类的情况下,这将导致每个输出类的【激活】的不同概率。而我们会选择“激活”(概率)值最高的一个。
偏置节点
使用“偏差”节点通常是创建成功学习模型的关键。简而言之, 偏置值允许将激活函数向左或向右 移动,这有助于使更好地适合数据(作为输出的更好的预测函数)。
下面是我画的 3 个 Sigmoid 函数,你可以注意到变量 x 与某个值相乘/相加/相减是如何影响函数的。
- 乘以 x —使函数更加陡峭
- 加减 x —向左/向右移动功能


Image 11: Sigmoid Functions. source: desmos.com
价值函数
让我们从定义成本函数的通用方程开始。该函数表示误差的总和,即预测值和真实(标记)值之间的差异。

Image 12: General Cost functoin. source: coursera.org
由于这是一个分类问题类型 y 只能取离散值{0,1}。它只能在一种类型的类中。例如,如果我们对狗(类别 1)、猫(类别 2)和鸟(类别 3)的图像进行分类。如果输入图像是狗。对于 dog 类,输出类的值为 1,对于其他类,输出类的值为 0。
这意味着我们希望我们的假设满足

Image 13: Hypothesis function range values
这就是为什么我们将假设定义为

Image 14: Hypothesis function
其中 g 在这种情况下将是 Sigmoid 函数,因为该函数的范围值在(0,1)之间。
我们的目标是优化成本函数,所以我们需要找到 min【J(θ)。但是 Sigmoid 函数是一个“非凸”函数(“ Image 15 ”),这意味着存在多个局部极小值。所以不能保证收敛(找到)到全局最小值。我们需要的是“凸”函数,以便梯度下降算法能够找到全局最小值(最小化 J(θ))。为此我们使用 log 函数。

Image 15: Convex vs Non-convex function. source: researchgate.com
这就是为什么我们对神经网络使用以下成本函数

Image 16: Neural Network cost function. source: coursera.org
在标记值 y 等于 1 的情况下,假设为-log(h(x))或-log(1-h(x))否则。**
如果我们看函数图,直觉是非常简单的。先来看一下 y=1 的情况。那么 -log(h(x)) 就会像下图这样。我们只对(0,1) x 轴间隔感兴趣,因为假设只能取该范围内的值(“图像 13”)**

Image 17: Cost function -log(h(x)) . source: desmos.com
从图中我们可以看到,如果y = 1【x】趋近于 1 ( x 轴)成本趋近于0(h(x)-y就会是否则如果 h(x) 趋近于 0 代价函数趋于无穷大(非常大的代价)。****
在 y=0 的另一种情况下,代价函数为 -log(1-h(x))

Image 18: -log(1-h) cost function. source: desmos.com
从图中我们可以看到,如果 h(x) 接近值 0 ,成本将接近 0 ,因为这也是正确的预测。
由于 y 【标注值】始终等于 0 或 1 我们可以把成本函数写成一个方程。

Image 19: Cost function equation. source: coursera.org
如果我们用总和来写成本函数,我们将得到:

Image 20: Cost function in case of one output node. source: coursera.org
而且这是针对神经网络输出层只有一个节点的情况。如果我们将此推广到多个输出节点(多类分类),我们会得到:

Image 21: Generalized Cost function. source: coursera.org
方程的右边部分表示成本函数“正则化”。这种正则化通过降低θ的幅度/值来防止数据“过拟合”。
正向传播计算
这个前向传播的过程,其实就是根据给定的输入,得到神经网络输出值。该算法用于计算成本值。它所做的与第 2 节“模型表示数学”中描述的数学过程相同。最终我们得到假设值“图 7”。

在我们得到了 h(x) 值(假设)之后,我们使用成本函数方程(【图片 21】)来计算给定输入集的成本。

Image 22: Calculate Forward propagation
在这里,我们可以注意到前向传播是如何工作的,以及神经网络如何生成预测。
反向传播算法
我们想要做的是使用(权重)的最优值集合来最小化成本函数【J(θ)。反向传播是我们为了计算 J(θ) 的偏导数而使用的一种方法。**
该偏导数值然后被用于梯度下降算法(“图像 23”)中,用于计算最小化成本函数【J(θ)的神经网络的 θ 值。

Image 23: General form of gradient descent. source: coursera.org
反向传播算法有 5 个步骤:
- 设置(1)= X**;训练示例**
- 执行前向传播并为其他层 (l = 2…L) 计算 a(l)
- 使用 y 计算最后一层的 delta 值 δ(L) = h(x) — y
- 反向计算每个层的【l】值(在“反向传播背后的数学”一节中描述)
- 计算每一层的导数值δ(l)=(a(l))^t∘δ(l+1),代表成本 J(θ) 相对于 θ(l) 的导数
反向传播是关于确定改变权重如何影响神经网络中的总成本。
它所做的是在神经网络中向后传播“错误”。在返回的途中,它会发现每个重量在总“误差”中所占的比重。对整体“误差”贡献更大的权重将具有更大的导数值,这意味着它们将改变更多(当计算梯度下降时)。
现在我们已经知道了反向传播算法在做什么,我们可以更深入地研究背后的概念和数学。
为什么是衍生品?
一个函数(在我们的例子中是 J(θ) )对每个变量(在我们的例子中是权重 θ )的导数告诉我们该函数对那个变量或的敏感度,改变变量如何影响函数值。****
让我们看一个简单的神经网络例子

Image 24: Simple Neural Network
有两个输入节点 x 和 y 。输出函数是计算乘积 x 和 y 。我们现在可以计算两个节点的偏导数

Image 25: Derivatives to respect to y and x of f(x,y) = xy function
对 x 的偏导数是说如果 x 的值增加了某个值ϵ那么它会增加 7ϵ 的函数(乘积 xy )而对 y 的偏导数是说如果
如我们所定义的,反向传播算法计算成本函数相对于每个 θ 权重参数的导数。通过这样做,我们确定成本函数【J(θ)对这些 θ 权重参数中的每一个有多敏感。它还帮助我们确定在计算梯度下降时,我们应该改变每个 θ 权重参数多少。所以最后我们得到了最符合我们数据的模型。
反向传播背后的数学
我们将通过使用下面的神经网络模型作为起点来推导方程。

Image 26: Neural Network
在这个模型中,我们得到了 3 个输出节点( K )和 2 个隐藏层。如前所述,神经网络的成本函数为:

Image 27: Generalized Cost function. source: coursera.org
我们需要的是计算 J(θ) 相对于每个 θ 参数的偏导数。我们将省略总结,因为我们使用的是矢量化实现(矩阵乘法)。此外,我们可以省去正则化(上面等式的右边部分),我们将在最后单独计算它。因为是加法,所以导数可以独立计算。
注意:将使用矢量化实现,因此我们会一次性计算所有训练示例。
我们从定义我们将使用的衍生规则开始。

Image 28: Derivative Rules
现在我们为我们的神经网络模型定义基本方程,其中 l 是层符号,而 L 是最后一层。

Image 29: Initial Neural Network model equations
在我们的例子中 L 的值为 4,因为我们的模型中有 4 层。让我们从计算第三层和第四层之间权重的偏导数开始。

Image 30: Derivative of θ parameters between 3rd and 4th layer
步骤(6) — Sigmoid 导数 为了解释 步骤(6) 我们需要计算 Sigmoid 函数的偏导数。

Image 31: Derivative of Sigmoid function
在我们得到的最后一层的情况下,

Image 32: Output layer equation
所以,

Image 33: Output layer equation
步骤(11) —去掉概括(σ) 也在最后 步骤(11) 需要注意的是,我们需要将δ乘以 a 转置才能去掉概括(训练示例 1…m)。
【δ】——带维数的矩阵
【number _ of _ training _ examples,output _ layer _ size】所以这也意味着我们将摆脱第二次汇总(1…K 为输出节点数)。
a —带维度的矩阵
【隐藏 _ 层 _ 大小,数量 _ 训练 _ 示例】****
现在我们继续对第二层和第三层之间的 θ 参数进行下一次求导。对于这个推导我们可以从 【步骤 9】(【图像 30】)开始。由于 θ(2) 在函数内,我们需要在计算导数时应用“链式法则”(来自“图 28”上的导数规则的步骤(6))。

Image 34: Derivative of θ parameters between 2nd and 3rd layer
现在我们得到了第二层和第三层之间的 θ 参数的导数。我们剩下要做的是计算输入层和第二层之间的 θ 参数的导数。通过这样做,我们将看到相同的过程(方程)将被重复,因此我们可以导出一般的 δ 和导数方程。我们再从 继续第三步 ( 【图片 34】)。

Image 35: Derivative of θ parameters between input and 2nd layer
从上式我们可以推导出 δ 参数以及相对于 θ 参数的导数的方程。

Image 36: Recursive δ equation

Image 37: Derivative of J (cost) with respect to θ in layer l equation
最后我们得到三个矩阵(与 θ 权重矩阵相同)与权重矩阵具有相同的维数,并计算出每个参数的导数。**
添加正则化
如前所述,正则化是防止模型过度拟合数据所必需的。我们已经为我们的成本函数定义了正则化,这是在“图像 21”上定义的等式的右边部分。

Image 38: Regularization equation for Cost function
为了增加梯度的正则化(偏导数),我们需要计算上面正则化的偏导数。

Image 39: Regularization equation for gradient (partial derivative)
这意味着只需将每一层的所有θ值之和与相对于 θ 的偏导数相加。
代码实现
我们现在可以在代码中实现所有方程,我们将在其中计算成本和导数(使用反向传播),以便我们稍后可以在梯度下降算法中使用它们来优化我们模型的 θ 参数。
Image 38: Code implementation of Neural Network Cost function and Backpropagation algorithm
结论
希望这是清晰易懂的。如果您认为某些部分需要更好的解释,请随时添加评论或建议。如有任何问题,请随时联系我。
希望你喜欢它!
有用的链接
用简单的语言解释数学,加上拼图,游戏,测验,工作表和一个论坛。对于 K-12 的孩子,老师和…
www.mathsisfun.com](https://www.mathsisfun.com/calculus/derivatives-introduction.html)**
为神经网络准备 EHR 和表格数据
包含 Python 代码!
这篇文章也可以叫做“我在博士第一年研究大量电子健康记录数据集时学到的一切”在这里,我将概述分类变量和数量变量之间的差异,并解释如何为神经网络模型准备表格数据,包括:
- 分类变量的正确表示(热点向量介绍)
- 连续变量的规范化
- 填充缺失值(插补介绍)
最棒的是,提供了广泛适用的代码来对您的表格数据执行上述所有操作!可以在 GitHub 上下载本教程的代码:rachellea/glassbox medicine/2019–06–01-data processing . py。
分类变量
分类变量是采用不同类别名称的变量。以下是分类变量的一些例子:

分类变量进一步细分为名义变量和顺序变量:
- 名义变量在类别之间没有自然排序。上面的例子(水果、地点和动物)是“名义上的”变量,因为在类别之间没有内在的顺序;
- 序数变量有自然排序。例如,字母等级(A、B、C、D、F)或等级量表(疼痛等级为 1-10)是顺序变量。
医学中的名义分类变量
以下是医疗数据集中的一些名义变量(无自然排序)示例,以及一些示例值:
- 性别:女,男;
- 种族 :美国印第安人或阿拉斯加土著、亚裔、黑人或非裔、西班牙裔或拉丁裔、夏威夷土著或其他太平洋岛民、白人;
- 诊断:糖尿病、高血压、高血脂、肺癌、肺炎、心肌梗死、狼疮、肠易激综合征、中风;
- 手术:阑尾切除术、胆囊切除术、乳房切除术、CABG *;
- 用药 :对乙酰氨基酚、阿丨普丨唑丨仑、阿米替林、氨氯地平、阿莫西林、阿托伐他汀;
- 实验室检查:全血细胞计数(CBC)、凝血酶原时间(PT)、基础代谢板(BMP)、综合代谢板(CMP)、血脂板、肝板、血红蛋白 A1c (HbA1c)。
*旁注:CABG 代表“冠状动脉旁路移植术”,这是一种心脏直视手术。医生把这个缩写念成“白菜”(认真)。

医学中的有序分类变量
以下是医疗数据集中顺序变量(固有排序)的一些示例:
助记符:
- 序数变量是有序的;
- 名义变量只有 NOMS(名字),没有顺序。
数量变量
定量变量具有通常代表测量结果的数值。有两种定量变量:
- 离散的变量有可计数的数值。例如:患者服用的处方数量、患者被诊断患有的疾病数量、患者接受的手术数量;
- 连续变量在特定的取值范围内取任意值。例如:身高、体重、体重指数、肿瘤直径、腰臀比。
实验室测试的附带说明
如果您的变量是实验室测试的名称,那么它就是一个名义(分类)变量,因为它可以采用不同实验室测试的不同名称,例如“全血细胞计数”、“基础代谢组”、“全代谢组”
如果您的变量是实验室测试的结果,它可能是:
- 分类/标称:例如尿液分析中的颜色;
- 定量/离散:例如白细胞数量的计数;
- 定量/连续:例如血糖水平。大多数实验室测试结果都属于这一类,因为它们是某种物质(血液、脑脊液、尿液等)的测量结果。)
表示分类变量:独热向量
在机器学习中,分类变量通常被表示为“独热向量”独热向量是这样一种向量,其中除了一个之外,所有条目都是零,即只有一个元素是“热的”(非零)。以下是一些热点媒介:
独热向量的酷之处在于,它们允许你表示你的分类变量,而不需要假设它们之间有任何特定的关系。
假设您想要表示分类变量“动物”,该变量的值为狗、猫和鱼。
- 如果你说狗= 1,猫= 2,鱼= 3,这意味着狗是鱼的三分之一,猫是狗的两倍,以及其他各种没有意义的数字关系;
- 然而,如果你说狗= [1,0,0],猫= [0,1,0],鱼= [0,0,1],你并没有对这些动物之间的关系做出任何假设,因为这些单热点向量是垂直的:

如果你想要表现 20 种不同的动物,那没问题:只需使用长度为 20 的单键向量。由此产生的 20 个不同的独热向量在 20 维空间中仍然是相互垂直的(你会很高兴地知道,我将而不是试图勾画):
- 狗,狗,狗,狗
- 猫[0,1,0,0,0,0,0,0,0,0,0,0,0,0
- 鱼,鱼,鱼,鱼,鱼,鱼
- 马[0,0,0,1,0,0,0,0,0,0,0,0,0,0,0
- 蜥蜴[0,0,0,0,1,0,0,0,0,0,0,0,0,0,0
- 等等
一般来说,你需要的独热向量的长度等于你的分类变量可以取的不同可能值的数量。如果它可以取 5 个值,那么独热向量的长度应该是 5。如果它可以取 1,298 个值,那么您的独热向量的长度应该是 1,298。
如果我的数据集中有很多分类变量怎么办?
只需为每个分类变量创建一个不同的独热向量。假设你做了一个调查,问了三个人他们最喜欢的动物、地点和水果。最后,您的调查回答数据集包括分类变量“动物”(3 个可能值)、“位置”(4 个可能值)和“水果”(2 个可能值)。因此,您应该:
- 使用长度为 3 的独热向量表示“动物”;
- 将“位置”表示为长度为 4 的单独的独热码向量;
- 将“水果”表示为长度为 2 的另一个独热向量。
可视化,

如果我的分类变量可以同时取多个值,该怎么办?
如果在之前的调查中,你让人们选择多种动物、地点或水果,会怎么样?您可以使用“多热向量”,它与单热向量完全相同,只是多个条目可以等于 1。下面是一个例子(修改了前面的例子;附加条目以黄色突出显示):

像这样可以取多个值的分类变量在医学中很常见。例如,从患者十年的病历中提取的诊断、程序和药物很可能具有不止一个值。许多患者会有几个过去的诊断,几个过去的程序,和几个过去的药物。因此,您将需要一个用于诊断的多热点向量,另一个用于程序的多热点向量,以及另一个用于药物的多热点向量。
下面是提供的代码中的一个片段,它使用熊猫函数 get_dummies() 将每个分类变量转换成一个单热点或多热点向量:
def _one_hotify(self):
"""Modify self.clean_data so that each categorical
column is turned into many columns that together form a
one-hot vector for that variable. E.g. if you have a column
'Gender' with values 'M' and 'F', split it into two binary
columns 'Gender_M' and 'Gender_F'""" print('Onehotifying', str(len(
self.one_hotify_these_categorical)),'categorical variables')
print('\tData shape before onehotifying:',
str(self.clean_data.shape))
#one hotify the categorical variables
self.clean_data = pd.get_dummies(data = self.clean_data,
columns = self.one_hotify_these_categorical,
dummy_na = False)
print('\tData shape after one-hotifying:',
str(self.clean_data.shape))
代表量化变量:规范化的重要性 (即“如何喂养你的神经网络”)
现在我们要换个话题,谈谈表示数量变量。看起来你可以直接把这些变量扔进模型,而不需要任何额外的工作,因为它们已经是数字了。然而,如果您正在构建一个神经网络模型,您不希望输入原始的定量变量,因为它们可能具有非常不同的标度,并且为神经网络提供不同标度的数字会使它变得令人难过(即,神经网络学习任何东西都会更加困难。)
我所说的“不同尺度”是指一些变量可能取小值(例如肿瘤直径= 0.5 厘米),而其他变量可能取大值(例如体重= 350 磅)。)如果只给神经网络输入较小的标准化值,它的训练会更有效。
以下是在训练神经网络之前对定量变量进行归一化的常见步骤:
- 将数据分成训练集、验证集和测试集。
- 计算训练集中定量变量的平均值;
- 计算训练集中定量变量的标准差;
- 使用您刚刚在训练集上计算的平均值和标准偏差,标准化所有数据(训练、验证和测试)中定量变量的每个原始值:

您必须为数据集中的每个定量变量分别执行此操作(例如,分别为“肿瘤直径”和“重量”),因为每个定量变量将具有不同的平均值和不同的标准差。
执行上述步骤的效果是,您所有的量化变量现在都将表示为以 0 为中心的小数字,这将使它们成为您的神经网络的良好食物。
为什么我们只使用训练集来计算均值和标准差?为什么不使用整个数据集?回答:如果我们在计算平均值和标准偏差时包括测试集,我们会将测试集的信息泄露到我们的训练数据中,这是作弊。
下面是提供的代码中的一个片段,它使用 scikit-learn 的标准缩放器对连续变量进行归一化:
def _normalize(self):
"""Provide the features specified in
self.normalize_these_continuous
with approximately zero mean and unit variance, based on the
training dataset only."""
train_data = (
self.clean_data[self.normalize_these_continuous].values
)[0:self.trainidx,:]
scaler = sklearn.preprocessing.StandardScaler().fit(train_data)
print('Normalizing data:\n\tscaler.mean_',str(scaler.mean_),
'\n\tscaler.scale_',str(scaler.scale_))
assert (len(self.normalize_these_continuous)
==scaler.mean_.shape[0]
==scaler.scale_.shape[0](
self.clean_data[self.normalize_these_continuous] =
scaler.transform((
self.clean_data[self.normalize_these_continuous]).values)
插补处理缺失数据
数据值经常丢失。也许调查参与者没有回答所有的问题,或者患者在不同的州接受治疗,他们的诊断、程序和药物没有记录在当地的医疗记录中。
如果我们读入一个带有缺失值的数据文件,这些值将是“NaNs”,或者“不是一个数字”为了训练,我们必须用一个数字来代替它们。填补缺失值被称为“插补”
有不同的插补策略。这里有一个合理的策略:
- 用训练集模式替换分类变量的所有缺失值。因此,如果动物的模式(最常选择的值)是“狗”,我们将替换“你最喜欢的动物是什么?”用“狗”;
- 用训练集中值替换连续变量的所有缺失值。因此,如果中值高度是 5.2 英尺,我们用 5.2 替换所有缺失的“高度”条目。
下面是提供的代码的一个片段,它使用熊猫函数 fillna() 对缺失值进行插补:
def _impute(self):
"""Impute categorical variables using the mode of the
training data and continuous variables using the median
of the training data."""
#impute missing categorical values with the training data mode
print('Imputing categorical variables with mode:\n',
str(self.impute_these_categorical))
training_data = self.clean_data.iloc[0:self.trainidx,:]
imputed_with_modes = (
self.clean_data[self.impute_these_categorical]).fillna((
training_data[self.impute_these_categorical]).mode().iloc[0])
self.clean_data[self.impute_these_categorical] =\
imputed_with_modes
#impute missing continuous values with the training data median
print('Imputing continuous variables with median:\n',
str(self.impute_these_continuous))
imputed_with_medians = (
self.clean_data[self.impute_these_continuous]
).fillna((training_data[self.impute_these_continuous]
).median())
self.clean_data[self.impute_these_continuous] =
imputed_with_medians
摘要
- 仔细的数据准备对于你的神经网络达到良好的性能是至关重要的;
- One-hot vectors 允许您输入分类变量,而无需假设不同类别之间的任何特定数字关系;
- 将你的量化变量归一化为以零为中心的小数字,将有助于你的神经网络更有效地训练;
- 真实数据集往往是不完整的。使用相关变量的中位数或众数来输入缺失值将允许您在这些数据集上构建模型。
关于特色图片

特色图片是一只萨摩耶犬,恰好是我一直以来最喜欢的一种狗。这只狗在“分类变量示例”表中客串了一次。关于萨摩耶的趣闻:
- 萨摩耶犬是西伯利亚的游牧驯鹿牧民饲养的;
- 萨摩耶犬是最古老的犬种之一;
- 脱落的萨摩耶毛皮可以用来编织衣物;
- 由于它们厚厚的皮毛,萨摩耶犬可以在远低于冰点的温度下保持温暖。
原载于 2019 年 6 月 1 日http://glassboxmedicine.com。
关于正则表达式你需要知道的一切

Photo by NESA by Makers on Unsplash
读完这篇文章后,你会对什么是正则表达式,它们能做什么,它们不能做什么有一个坚实的理解。
你将能够判断何时使用它们,更重要的是,何时不使用它们。
让我们从头开始。
什么是正则表达式?
在抽象层次上,正则表达式,简称 regex,是集合的简写表示。一组弦。
假设我们有一个所有有效邮政编码的列表。与其保留那个又长又笨重的列表,不如用一个简短而精确的模式来完整地描述那个集合。每当您想要检查一个字符串是否是一个有效的邮政编码时,您可以将它与模式进行匹配。您将得到一个 true 或 false 结果,表明该字符串是否属于 regex 模式所代表的邮政编码集。
让我们扩展一下邮政编码集。邮政编码列表是有限的,由相当短的字符串组成,在计算上并不特别具有挑战性。
以.csv结尾的那组字符串呢?在查找数据文件时非常有用。这个集合是无限的。你不能事先列个清单。测试成员资格的唯一方法是到字符串的末尾,比较最后四个字符。正则表达式是以一种标准化的方式编码这种模式的一种方式。

Regular expressions match sets of strings. Photo by Kristian Strand on Unsplash
下面是一个正则表达式模式,代表我们的以.csv结尾的字符串集
^.*\.csv$
让我们把这种特殊模式的机制放在一边,看看实际情况:正则表达式引擎可以根据输入字符串测试模式,看它是否匹配。以上图案匹配foo.csv,但不匹配bar.txt或my_csv_file。
在代码中使用正则表达式之前,可以使用在线正则表达式计算器测试它们,并尝试友好的用户界面。
我喜欢regex101.com:你可以选择正则表达式引擎的风格,模式会被很好地分解,所以你可以很好地理解你的模式实际上做了什么。正则表达式模式可能是神秘的。
我建议你在另一个窗口或标签中打开regex101.com,以交互方式体验本文中的例子。我保证,这样您会对正则表达式模式有更好的感觉。

debugging regular expressions
正则表达式是用来做什么的?
正则表达式在任何受益于字符串的完全或部分模式匹配的场景中都很有用。以下是一些常见的使用案例:
- 验证字符串的结构
- 从结构化字符串中提取子字符串
- 搜索/替换/重新排列部分字符串
- 将字符串拆分成标记
所有这些在做数据准备工作时都会定期出现。
正则表达式的构造块
正则表达式模式是由不同的构建块构成的。它可以包含文字、字符类、边界匹配器、量词、组以及或运算符。
让我们深入研究一下一些例子。
文字
正则表达式中最基本的构件是字符,也称为文字。正则表达式模式中的大多数字符没有特殊的含义,它们只是匹配它们自己。考虑以下模式:
I am a harmless regex pattern
这个图案中没有一个字符有特殊含义。因此,模式中的每个字符都与其自身匹配。因此,只有一个字符串匹配这个模式,并且它与模式字符串本身相同。

matching a simple pattern
转义文字字符
有哪些确实有特殊含义的字符?以下列表显示了在正则表达式中具有特殊含义的字符。如果要表示它们自己,就必须用反斜杠对它们进行转义。
characters with special meaning in regular expressions
考虑以下模式:
\+21\.5
该模式仅由文字组成——+有特殊的含义并已被转义,同样的还有.——因此该模式仅匹配一个字符串:+21.5

匹配不可打印字符
有时需要引用一些不可打印的字符,如制表符⇥或换行符↩
最好对它们使用正确的转义序列:
如果您需要匹配换行符,它们通常有两种类型:
\n通常被称为 unix 风格的换行符\r\n通常被称为 windows 风格的换行符
为了抓住这两种可能性,你可以在\r?\n上匹配,这意味着:可选的\r后跟\n

matching a newline
匹配任何 Unicode 字符
有时,您必须使用 Unicode 索引来匹配最能表达的字符。有时候一个字符就是不能被输入——就像 ASCII NUL、ESC、VT等控制字符。
有时,您的编程语言不支持将某些字符放入模式中。在 BMP 之外的字符,如 𝄞 或表情符号通常不被逐字支持。
在许多 regex 引擎中——比如 Java、JavaScript、Python 和 Ruby——您可以使用\uHexIndex转义语法通过 Unicode 索引匹配任何字符。假设我们想要匹配自然数的符号: ℕ - U+2115
匹配这个字符的模式是:\u2115

matching a unicode symbol
其他引擎通常提供等效的转义语法。在围棋中,你可以使用\x{2115}来匹配ℕ
Unicode 支持和转义语法因引擎而异。如果你计划匹配技术符号、音乐符号或表情符号——特别是在 BMP 之外——检查你使用的 regex 引擎的文档,以确保对你的用例有足够的支持。
模式的转义部分
有时模式要求连续字符作为文字进行转义。假设它匹配下面的字符串:+???+
该模式如下所示:
\+\?\?\?\+
将每个字符作为文字进行转义的需要使得阅读和理解变得更加困难。
根据您的正则表达式引擎,可能有一种方式在您的模式中开始和结束文字部分。检查你的文件。在 Java 和 Perl 中,应该逐字解释的字符序列可以用\Q和\E括起来。以下模式等同于上述模式:
\Q+???+\E
如果模式是由部分构成的,对模式的部分进行转义也是有用的,其中一些部分是按字面意思解释的,比如用户提供的搜索词。
如果你的 regex 引擎没有这个特性,那么生态系统通常会提供一个函数来对模式字符串中所有具有特殊含义的字符进行转义,比如 lodash escapeRegExp 。
OR 运算符
管道字符|是选择操作符。它匹配备选方案。假设一个模式应该匹配字符串1和2
下面的模式可以达到这个目的:
1|2
运算符左侧和右侧的模式是允许的替代模式。

以下模式匹配William Turner和Bill Turner
William Turner|Bill Turner
备选方案的第二部分是一致的Turner。将备选方案William和Bill放在前面,并且只提到Turner一次会比较方便。以下模式可以做到这一点:
(William|Bill) Turner
看起来可读性更强。它还引入了一个新概念:组。
组
您可以在圆括号中的部分中分组子模式。它们将包含的表达式组合成一个单元。对模式的各个部分进行分组有多种用途:
- 简化正则表达式符号,使意图更清晰
- 对子表达式应用量词和
- 提取匹配组的子字符串
- 替换匹配组的子字符串
我们来看一个带组的正则表达式:(William|Bill) Turner
组有时被称为“捕获组”,因为在匹配的情况下,每个组的匹配子串被捕获,并且可用于提取。

如何使捕获的组可用取决于您使用的 API。在 JavaScript 中,调用"my string".match(/pattern/)会返回一个匹配的数组。第一项是整个匹配的字符串,后续项是按照在模式中出现的顺序匹配模式组的子字符串。
Accessing sub-strings in captured in groups
示例:国际象棋符号
考虑识别棋盘区域的字符串。棋盘上的区域可以被标识为第一列的 A1-A8,第二列的 B1-B8,等等,直到最后一列的 H1-H8。假设应该验证包含此符号的字符串,并使用捕获组提取组成部分(字母和数字)。下面的正则表达式可以做到这一点。
(A|B|C|D|E|F|G|H)(1|2|3|4|5|6|7|8)
虽然上面的正则表达式是有效的,并完成了工作,但它有些笨拙。这个也可以,而且更简洁一点:
([A-H])([1-8])

这看起来更简洁。但是它引入了一个新概念:字符类。
字符类别
字符类用于定义一组允许的字符。允许的字符集放在方括号中,并且列出了每个允许的字符。角色类[abcdef]相当于(a|b|c|d|e|f)。因为该类包含替代项,所以它只匹配一个字符。
图案[ab][cd]正好匹配 4 串ac、ad、bc和bd。它确实不匹配ab,第一个字符匹配,但第二个字符必须是c或d。
假设一个模式应该匹配一个两位数的代码。与之匹配的模式如下所示:
[0123456789][0123456789]
该模式匹配从00到99范围内的所有 100 个两位字符串。
范围
在一个字符类中列出所有可能的字符通常是乏味且容易出错的。使用破折号运算符:[0-9][0-9]可以将连续字符作为范围包含在字符类中

matching two characters in range 0–9
字符按数字索引排序——在 2019 年,数字索引几乎总是 Unicode 索引。如果您正在处理数字、拉丁字符和基本的标点符号,您可以查看 Unicode 的更小的历史子集: ASCII 。
从 0 到 9 的数字通过码位顺序编码:0的U+0030到9的码位U+0039,所以[0–9]的字符集是一个有效的范围。
拉丁字母的小写字母和大写字母也是连续编码的,所以字母字符的字符类也经常出现。以下字符集匹配任何小写拉丁字符:
[a-z]
您可以在同一个字符类中定义多个范围。以下字符类匹配所有小写和大写拉丁字符:
[A-Za-z]
您可能会有这样的印象,上面的模式可以缩写为:
[A-z]
这是一个有效的字符类,但它不仅匹配 a-z 和 A-Z,还匹配 Z 和 A 之间定义的所有字符,如[、\和^。

the range A-z includes unexpected characters [ and ]
如果你正在气头上咒骂定义 ASCII 并引入这种令人难以置信的不连续性的人的愚蠢,请稍安勿躁。ASCII 是在计算能力比今天珍贵得多的时代定义的。
看
A hex: 0x41 bin: 0100 0001和*a hex: 0x61 bin: 0110 0001*你如何在大写和小写之间转换?你翻转一个位。整个字母表都是如此。ASCII 经过优化,可以简化大小写转换。定义 ASCII 的人考虑得非常周到。一些可取的品质不得不为其他品质而牺牲。不客气
您可能想知道如何将-字符放入字符类。毕竟它是用来定义范围的。如果将-字符放在类中的第一个或最后一个字符:[-+0–9]或[+0–9-],大多数引擎会逐字解释该字符。一些引擎需要使用反斜杠[\-+0–9]进行转义
否定
有时定义一个匹配大多数字符的字符类是很有用的,除了一些定义的例外。如果字符类定义以^开头,列出的字符集将被反转。例如,下面的类允许任何字符,只要它既不是数字也不是下划线。
[^0-9_]

looking for three consecutive non-digit and non-underscore characters
请注意,如果^字符不是类的第一个字符,它将被解释为文字,如在[f^o]中,如果在字符类之外使用,它将是一个边界匹配器。
预定义的字符类
有些字符类使用如此频繁,以至于为它们定义了速记符号。考虑角色类[0–9]。它匹配任何数字字符,并且使用如此频繁,以至于有一个助记符号:\d。
下面的列表显示了具有最常见的速记符号的字符类,您使用的任何 regex 引擎都可能支持这些符号。
大多数引擎都提供了预定义字符类的完整列表,这些字符类与 Unicode 标准、标点符号、特定字母等的某些块或类别相匹配。这些额外的字符类通常特定于手边的引擎,并且不太容易移植。
点字符类
最普遍的预定义字符类是点,它本身就值得拥有一小部分。它匹配任何字符,除了像\r和\n这样的行终止符。
以下模式匹配以小写 x 结尾的任意三个字符串:
..x

the dot matches anything except newline characters
在实践中,点通常用于创建模式中的“任何东西都可以放在这里”部分。它经常与一个量词结合使用和.*用于匹配“任何”或“无关”部分。

matching anything between 1 and 2
请注意,当在字符类中使用时,.字符失去了它的特殊含义。字符类[.,]只匹配两个字符,点和逗号。
根据您使用的正则表达式引擎,您可以设置 dotAll 执行标志,在这种情况下.将匹配任何东西,包括行终止符。
边界匹配器
边界匹配器(也称为“锚点”)不匹配字符本身,而是匹配边界。如果你愿意,它们匹配字符之间的位置。最常见的主播有^和$。它们分别匹配一行的开始和结束。下表显示了最常支持的锚点。
锚定开始和结束
考虑在多行文本中搜索数字的操作。模式[0–9]查找文本中的每个数字,不管它位于哪里。模式^[0–9]查找作为一行第一个字符的每个数字。

matching digits at the beginning of a line
同样的想法也适用于以$结尾的行。

matching digits at the end of a line
\A和\Z 或 \z锚是匹配多行字符串的有用工具。它们锚定到整个输入的开头和结尾。大写的\Z变体可以容忍尾随换行符,并且匹配之前的换行符,有效地丢弃匹配中的任何尾随换行符。
大多数主流 regex 引擎都支持\A 和\Z 锚,JavaScript 是个明显的例外。
假设需求是检查一个文本是否是指定棋位的两行记录。输入字符串如下所示:
Column: F
Row: 7
以下模式与上述结构相匹配:
\AColumn: [A-H]\r?\nRow: [1-8]\Z

Using /A and /Z to anchor to beginning and end of input
全字匹配
\b锚匹配任何字母数字序列的边缘。如果您想进行“全字”匹配,这是很有用的。下面的模式寻找一个独立的大写字母I。
\bI\b

the \b anchor matches on transitions between “words”
模式与Illinois的第一个字母不匹配,因为右边没有单词边界。下一个字母是单词字母——由字符类\w定义为[a-zA-Z0–9_]——而不是非单词字母,这将构成一个边界。
我们把Illinois换成I!linois吧。感叹号不是单词字符,因此构成了边界。

杂项锚
有点深奥的非字界\B是对\b的否定。匹配任何\b不匹配的位置。它匹配空格内字符和字母数字序列之间的每个位置。
一些正则表达式引擎支持\G边界匹配器。这在以编程方式使用正则表达式时很有用,一个模式被重复应用于一个字符串,试图在一个循环中找到所有匹配的模式。它锚定到找到的最后一个匹配的位置。
量词
任何文字或字符组只匹配一个字符。模式[0–9][0–9]正好匹配两位数字。量词有助于指定模式的预期匹配数。它们用花括号表示。以下等同于[0–9][0–9]
[0-9]{2}
基本符号可以扩展到提供上限和下限。说是需要匹配二到六位数。确切的数字各不相同,但必须在 2 到 6 之间。下面的符号做到了这一点:
[0-9]{2,6}

sequences of 2–6 digits are matched
上限是可选的,如果省略,则等于或大于下限的任何出现次数都是可接受的。以下示例匹配两个或更多连续数字。
[0-9]{2,}
对于实践中经常使用的常用量词,有一些预定义的缩写。
那个?数量词
?量词相当于{0, 1},表示:可选单次出现。前面的模式可能不匹配,或者匹配一次。
让我们寻找整数,可选地以加号或减号为前缀:[-+]?\d{1,}

finding integers with optional sign
+量词
量词+相当于{1,},意思是:至少出现一次。
我们可以通过用+替换{1,}来修改上面的整数匹配模式,使其更加符合习惯,我们得到:[-+]?\d+

finding integers with optional sign again
量词*
*量词相当于{0,},意思是:零次或多次出现。你会经常看到它与点号连用为.*,意思是:任何字符都不在乎多频繁。
让我们匹配一个逗号分隔的整数列表。条目之间不允许有空格,并且必须至少有一个整数:\d+(,\d+)*
我们匹配的是一个整数,后跟任意数量的包含一个逗号和一个整数的组。

默认贪婪
假设需求是匹配捕获组中 http URL 的域部分。以下似乎是一个好主意:匹配协议,然后捕获域,然后是可选路径。这个想法大致可以解释为:
[http://(.*)/?](/(.*)/?.*)
如果你使用的引擎使用像 JavaScript 这样的
/regex/符号,你必须避开正斜杠:[http:\/\/(.*)\/?.*](/(.*)/?.*)
它匹配协议,捕获协议之后的域,并允许一个可选的斜杠和其后的一些任意文本,这将是资源路径。

greedy capture matches too much
奇怪的是,给定一些输入字符串,该组捕获到以下内容:
unexpected portion of url captured by group
结果有些令人惊讶,因为该模式被设计为仅捕获域部分,但它似乎捕获了 URL 末尾之前的所有内容。
发生这种情况是因为模式中遇到的每个量词都试图匹配尽可能多的字符串。量词因此被称为贪心。
让我们检查一下:[http://(.*)/?.*](/(.*)/?.*)的匹配行为
捕获组中的贪心*是第一个遇到的量词。它所应用的.字符类匹配任何字符,所以量词扩展到字符串的末尾。因此捕获组捕获了一切。但是等等,你会说,结尾还有/?.*的部分。嗯,是的,它和字符串的剩余部分完全匹配——什么也没有,也就是空字符串。斜杠是可选的,后跟零个或多个字符。空字符串符合。整个模式完全吻合。
贪婪匹配的替代方案
贪婪是量词的默认用法,但不是唯一的用法。每个量词都有一个不情愿的版本,它匹配最少可能数量的字符。量词的贪婪版本通过追加一个被转换成不情愿的版本?交给他们。
下表给出了所有量词的符号。
量化器{n}在贪婪和勉强两种版本中是等价的。对于其他字符,匹配字符的数量可能会有所不同。让我们重新看看上面的例子,改变捕获组以尽可能少地匹配,希望能正确捕获域名。
[http://(.*?)/?.*](/(.*?)/?.*)

capturing empty strings with reluctant quantifiers
使用这种模式,组不会捕获任何东西,更准确地说是空字符串。这是为什么呢?捕获组现在尽可能少地捕获:什么也不捕获。(.*?)什么也没捕捉到,/?什么也没匹配,而.*匹配字符串剩余的全部内容。因此,这种模式并没有像预期的那样工作。
到目前为止,捕获组匹配太少或太多。让我们回到贪婪量词,但不允许在域名中使用斜杠字符,还要求域名至少有一个字符长。
http://([^/]+)/?.*
这种模式贪婪地捕捉协议后面的一个或多个非斜杠字符作为域,如果最后出现任何可选的斜杠,它后面可能会跟有路径中的任意数量的字符。

量化器性能
贪婪量词和勉强量词都意味着一些运行时开销。如果只有几个这样的量词,就没有问题。但是,如果多个嵌套组都被量化为贪婪或勉强,那么确定最长或最短的可能匹配是一个重要的操作,这意味着在输入字符串上来回运行,调整每个量词匹配的长度,以确定表达式作为一个整体是否匹配。
可能出现灾难性回溯的病理情况。如果担心性能或恶意输入,最好选择不情愿的量词,并看看第三种量词:所有格量词。
所有格量词:永不回馈
如果您的引擎支持,所有格量词的行为很像贪婪量词,区别在于它们不支持回溯。他们试图匹配尽可能多的字符,一旦他们这样做了,他们永远不会产生任何匹配的字符来适应模式的任何其他部分的可能匹配。
它们通过在基本贪婪量词后面追加一个+来表示。
它们是“类贪婪”量词的快速执行版本,这使它们成为对性能敏感的操作的良好选择。
让我们在 PHP 引擎中看看它们。首先,我们来看看简单的贪婪匹配。让我们匹配一些数字,后面跟着一个九:([0–9]+)9
针对输入字符串进行匹配:123456789贪婪量词会首先匹配整个输入,然后返回9,这样剩下的模式就有机会匹配了。

greedy match
现在,当我们用所有格量词替换贪婪时,它将匹配整个输入,然后拒绝返回9以避免回溯,这将导致整个模式根本不匹配。

possessive quantifer causing a non-match
什么时候你会想要占有欲行为?当你知道你总是想要尽可能长的比赛。
假设您想要提取文件系统路径的文件名部分。假设/为路径分隔符。那么我们实际上想要的是最后一次出现/之后的字符串的最后一位。
所有格模式在这里工作得很好,因为我们总是希望在获取文件名之前使用所有的文件夹名。使用文件夹名的模式部分不需要归还字符。相应的模式可能如下所示:
\/?(?:[^\/]+\/)++(.*)
注意:这里使用 PHP
/regex/符号,所以正斜杠被转义。
我们希望允许绝对路径,所以我们允许输入以可选的正斜杠开始。然后,我们使用由一系列非斜杠字符后跟一个斜杠组成的文件夹名。为此,我使用了一个非捕获组——因此它被标记为(?:pattern),而不仅仅是(pattern)。最后一个斜杠之后剩下的任何内容都是我们捕获到一个组中进行提取的内容。

example of posessive matching
非捕获组
非捕获组与正常组完全匹配。但是,它们不提供匹配的内容。如果不需要捕获内容,它们可以用来提高匹配性能。非捕获组写为:(?:pattern)
假设我们想验证一个十六进制字符串是有效的。它需要由偶数个十六进制数字组成,每个数字在0–9或a-f之间。以下表达式使用组来完成这项工作:
([0-9a-f][0-9a-f])+
由于该组在模式中的作用是确保数字成对出现,并且实际匹配的数字没有任何相关性,因此该组也可以用更快执行的非捕获组来替换:
(?:[0-9a-f][0-9a-f])+

matching sequences of hex bytes
原子团
还有一个非捕获组的快速执行版本,它不支持回溯。它被称为“独立非捕获群”或“原子群”。
它被写成(?>pattern)
原子组是非捕获组,可用于优化模式匹配速度。通常,它由 regex 引擎支持,这些引擎也支持所有格量词。
它的行为也类似于所有格量词:一旦一个原子组匹配了字符串的一部分,第一个匹配就是永久的。这个群体永远不会试图以另一种方式重新匹配,以适应模式的其他部分。
a(?>bc|b)c匹配abcc但不匹配abc。
原子组的第一场成功比赛在bc进行,并且一直保持下去。正常组将在回溯期间重新匹配,以适应模式末尾的c,从而成功匹配。但是原子组的第一场比赛是永久的,不会改变。
如果您希望尽可能快地匹配,并且不希望发生任何回溯,这是非常有用的。
假设我们匹配路径的文件名部分。我们可以匹配任何字符的原子组,后跟一个斜杠。然后捕获其余部分:
(?>.*\/)(.*)
注意:这里使用 PHP
*/regex/*符号,所以正斜杠被转义。

atomic group matching
一个普通的团队同样可以完成这项工作,但是消除回溯的可能性可以提高性能。如果您将数百万个输入与非平凡的正则表达式模式进行匹配,您将开始注意到差异。
它还通过触发灾难性回溯场景,提高了抵御旨在 DoS 攻击服务的恶意输入的弹性。
反向引用
有时引用字符串中较早匹配的内容很有用。假设一个字符串值只有以相同的字母开头和结尾才有效。单词“alpha”、“radar”、“kick”、“level”和“stars”就是例子。可以在一个组中捕获字符串的一部分,然后在模式 pattern 中引用该组:反向引用。
regex 模式中的反向引用使用\n语法来表示,其中n是捕获组的编号。编号从左到右,从 1 开始。如果组是嵌套的,它们按照遇到左括号的顺序编号。组 0 始终表示整个表达式。
以下模式匹配至少包含 3 个字符且以相同字母开头和结尾的输入:
([a-zA-Z]).+\1
换句话说:小写或大写字母——该字母被捕获到一个组中——后跟任何非空字符串,再跟我们在匹配开始时捕获的字母。

on-letter back references
让我们扩展一下。如果一个输入字符串不止一次地包含任何字母数字序列,那么它就是匹配的。单词边界用于确保匹配整个单词。
\b(\w+)\b.*\b\1\b

搜索并替换为反向引用
正则表达式在搜索和替换操作中很有用。典型的用例是寻找与模式匹配的子字符串,并用其他内容替换它。大多数使用正则表达式的 API 允许您在替换字符串中引用搜索模式中的捕获组。
这些反向引用有效地允许重新排列部分输入字符串。
考虑以下场景:输入字符串包含一个 A-Z 字符前缀,后跟一个可选空格,后跟一个 3–6 位数。像A321、B86562、F 8753和L 287这样的琴弦。
任务是将其转换为另一个字符串,该字符串由数字、破折号和字符前缀组成。
**Input** **Output** A321 321-A
B86562 86562-B
F 8753 8753-F
L 287 287-L
将一个字符串转换为另一个字符串的第一步是在捕获组中捕获字符串的每个部分。搜索模式如下所示:
([A-Z])\s?([0-9]{3,6})
它将前缀捕获到一个组中,允许一个可选的空格字符,然后将数字捕获到第二个组中。替换字符串中的反向引用使用$n语法表示,其中n是捕获组的编号。此操作的替换字符串应该首先引用包含数字的组,然后引用文字破折号,然后引用包含字母前缀的第一个组。这将给出以下替换字符串:
$2-$1
因此A321与搜索模式匹配,将A放入$1并将312放入$2。替换字符串的排列产生了预期的结果:首先是数字,然后是破折号,最后是字母前缀。

请注意,由于$字符在替换字符串中具有特殊的含义,如果要作为字符插入,必须将其转义为$$。
这种支持正则表达式的搜索和替换通常由文本编辑器提供。假设您在编辑器中有一个路径列表,手头的任务是在每个文件的文件名前面加一个下划线。路径/foo/bar/file.txt应该变成/foo/bar/_file.txt
根据我们目前所学,我们可以这样做:

example regex-enabled search and replace in VS Code
看,但不要碰:向前看和向后看
有时断言一个字符串具有某种结构是有用的,而不需要实际匹配它。这有什么用?
让我们编写一个模式,匹配后面跟有以a开头的单词的所有单词
让我们试试\b(\w+)\s+a它锚定到一个单词边界,并匹配单词字符,直到它看到一些空格后跟一个 a。

first attempt at matching words that are followed by words beginning with an a
在上面的例子中,我们匹配了love、swat、fly和to,但是没有捕捉到ant之前的an。这是因为a出发an已经作为to比赛的一部分被消耗掉了。我们已经扫描过那个a,单词an没有匹配的机会。
如果有一种方法可以断言下一个单词的第一个字符的属性,而不实际消耗它,那将是非常好的。
断言存在但不消耗输入的构造称为“前视”和“后视”。
向前看
Lookaheads 用于断言模式在前面匹配。它们被写成(?=pattern)
让我们用它来修正我们的模式:
\b(\w+)(?=\s+a)
我们已经将下一个单词的空格和首字母a放入一个 lookahead 中,所以当扫描一个字符串进行匹配时,它们会被检查但不会被消耗。

look ahead asserts a pattern matches ahead, but does not consume it
负的前瞻断言其模式不匹配前瞻。表示为(?!pattern)
让我们找出后面没有以a开头的单词的所有单词。
\b(\w+)\b(?!\s+a)
我们匹配后面没有空格和一个a的整个单词。

negative look ahead asserts that its pattern does not match ahead
向后看
lookbehind 的作用与 lookahead 相同,但它适用于当前位置的左侧,而不是右侧。许多正则表达式引擎限制了可以在 look back 中使用的模式类型,因为向后应用模式不是它们所优化的。检查你的文件!
回顾被写成(?<=pattern)
它断言在当前位置之前存在某个东西。让我们找出以r或t结尾的单词之后的所有单词。
(?<=[rt]\s)(\w+)
我们断言有一个r或t后跟一个空格,然后我们捕获后面的单词字符序列。

a lookbehind to capture certain words
还有一种消极的观点认为左边的模式不存在。它被写成(?<!pattern)
让我们颠倒一下找到的单词:我们想要匹配不是以r或t结尾的单词之后的所有单词。
(?<![rt]\s)\b(\w+)
我们通过\b(\w+)匹配所有单词,并且通过在前面加上(?<![rt]\s)来确保我们匹配的任何单词前面没有以r或t结尾的单词。

matching with a negative lookbehind
分裂模式
如果您正在使用一个允许您按模式分割字符串的 API,记住前视和后视通常是有用的。
正则表达式拆分通常使用模式作为分隔符,并从部分中删除分隔符。将 lookahead 或 look ahead 部分放在一个定界符中可以使它匹配,而不会删除仅仅被查看过的部分。
假设你有一个由:分隔的字符串,其中有些部分是由字母字符组成的标签,有些是格式为HH:mm的时间戳。
让我们看看输入字符串time_a:9:23:time_b:10:11
如果我们只是在:分裂,我们得到部分: [time_a, 9, 32, time_b, 10, 11]

splitting on delimiter
假设我们想通过分裂来提高,只要:两边都有字母。分隔符现在是[a-z]:|:[a-z]

including adjacent letters in the match treats them as part of the delimiter
我们得到部分: [time_, 9:32, ime_, 10:11]我们丢失了相邻的字符,因为它们是分隔符的一部分。
如果我们细化分隔符,对相邻字符使用 lookahead 和 look ahead,它们的存在将被验证,但它们不会作为分隔符的一部分匹配:(?<[a-z]):|:(?=[a-z])

putting the characters into lookbehind and lookahead does not consume them
最后我们得到我们想要的零件:[time_a, 9:32, time_b, 10:11]
正则表达式修饰符
大多数正则表达式引擎允许设置标志或修饰符来调整模式匹配过程的各个方面。一定要熟悉你选择的引擎处理这种修饰语的方式。
他们经常在不切实际的复杂模式和繁琐的模式之间做出区别。
您可能会发现区分大小写的修饰符、锚定选项、完全匹配和部分匹配模式,以及一个 dotAll 模式,该模式允许.字符类匹配任何内容,包括行终止符。
JavaScript, Python , Java, Ruby, 。网
例如,让我们看看 JavaScript。如果您想要不区分大小写的模式,并且只找到第一个匹配,您可以使用i修饰符,并确保省略g修饰符。

case insensitive match, with only the first match found
正则表达式的限制
阅读完本文后,您可能会觉得一旦掌握了正则表达式,所有可能的字符串解析问题都可以解决了。
嗯,没有。
本文介绍正则表达式作为字符串集合的速记符号。如果您恰好有邮政编码的精确正则表达式,那么您就有一个表示有效邮政编码的所有字符串集合的简写符号。您可以很容易地测试一个输入字符串,以检查它是否是该集合中的一个元素。然而有一个问题。
有许多有意义的字符串集合没有正则表达式!
例如,有效的 JavaScript 程序没有正则表达式。永远不会有正则表达式模式可以检查 JavaScript 源代码的语法是否正确。
这主要是因为 regex 天生无法处理任意深度的嵌套结构。正则表达式本质上是非递归的。XML 和 JSON 是嵌套结构,很多编程语言的源代码也是。回文是另一个例子——单词前后读起来一样,像race car——是嵌套结构的一种非常简单的形式。每个字符打开或关闭一个嵌套层次。

If yor input can arbitrarily nest like JavaScript, you can’t validate it with Regular Expressions alone. Photo by Christopher Robin Ebbinghaus on Unsplash
您可以构造匹配特定深度的嵌套结构的模式,但是您不能编写匹配任意深度嵌套的模式。
嵌套结构经常被证明是不规则的 T4。如果你对计算理论和语言分类感兴趣——也就是说,对字符串集感兴趣——可以浏览一下乔姆斯基的 Hiararchy 、形式语法和形式语言。
知道何时去拿不同的锤子
最后,让我提出一点警告。我有时会看到有人试图将正则表达式不仅用于词法分析(从字符串中识别和提取标记),还用于语义分析,试图解释和验证每个标记的含义。
虽然词法分析是正则表达式的一个非常有效的用例,但是尝试语义验证往往会导致产生另一个问题。
“regex”的复数形式是“后悔”
我举个例子说明一下。
假设一个字符串应该是十进制记法中的 IPv4 地址,用点分隔数字。正则表达式应该验证输入字符串确实是 IPv4 地址。第一次尝试可能是这样的:
([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})
它匹配由点分隔的四组一到三位数。一些读者可能会觉得这种模式有所欠缺。例如,它与111.222.333.444匹配,这不是有效的 IP 地址。
如果你现在迫切想改变模式,让它测试每组数字的编码数字在 0 到 255 之间——可能有前导零——那么你正在制造第二个问题,并后悔。
尝试这样做将从词法分析(识别四组数字)引向语义分析,验证数字组是否转化为可接受的数字。
这产生了一个更加复杂的正则表达式,这里的例子可以在找到。我建议通过使用 regex 模式捕获每组数字来解决这样的问题,然后将捕获的项目转换为整数,并在单独的逻辑步骤中验证它们的范围。

Use regular expressions — like all your tools — wisely. Photo by Todd Quackenbush on Unsplash
当使用正则表达式时,复杂性、可维护性、性能和正确性之间的权衡应该是一个有意识的决定。毕竟,正则表达式模式是计算语法所能达到的“只写”模式。正确读取正则表达式模式都很难,更不用说调试和扩展了。
我的建议是将它们作为一个强大的字符串处理工具,但不要高估它们的可能性,也不要高估人类处理它们的能力。
如果有疑问,考虑去拿盒子里的另一把锤子。
关于在 PyTorch 减肥,你需要知道的一切
一旦我们完成了对模型的训练,我们深度学习实践者会做什么?
我们心寒!!!
哈哈哈 开个玩笑……
我们要么保存学习到的权重,要么保存整个模型,以便我们可以进一步训练模型,或者使用训练好的模型进行推理!
接下来你们可能有兴趣知道的是,我们什么时候只保存学习过的权重,什么时候保存整个模型。
在这篇博客中,我们将试图找到这些问题的答案。
我将非常简单明了地向您解释在 PyTorch 中保存模型架构及其权重的艺术的来龙去脉。
我们还将学习如何访问不同的模块。准确地说,在任何给定的 PyTorch 模型中。
所以可以随意分叉这个 kaggle 内核并使用 代码 😃
我们开始吧!!!
我们从使用 PyTorch 导入编码的 基本必需品 开始。
接下来,我们定义一个基于 CNN 的模型。
让我们初始化并打印模型,看看里面有什么。
打印出模型向你展示它的架构。但是我们要潜得更深,因为我们是深度学习的实践者!
我们需要确保我们理解模型里面到底有什么。
有一种方法可以访问模型的每个可学习参数及其名称。顺便说一下,torch . nn . parameter是一个张量子类,当与torch . nn . module一起使用时,它会自动添加到其参数列表中,并出现在例如 parameters() 或named _ parameters()**迭代器中。另一方面添加一个 torch.nn.Tensor 则没有这样的效果。稍后将详细介绍这一点!
回到打印模型的所有参数。
喔喔喔!这里刚刚发生了什么?
让我们进入 named_parameters() 函数。
model.named_parameters()本身就是一个生成器。它返回名称和参数,它们只不过是参数的名称和参数本身。这里返回的参数是 torch.nn.Parameter 类,是一种张量。由于 param 是张量的一种类型,所以它也具有形状* 和要求 _grad 属性。 param.shape 是张量的简单形状,而param . requires _ grad是一个布尔值,它表明参数是否可学习。由于模型中的所有参数都具有requires _ grad= True**,这意味着所有参数都是可学习的,并且将在训练模型时更新。如果任何特定的参数被设置为假,则该参数的权重不会在训练模型时更新。*
因此, requires_grad 是当您想要训练/冻结您的模型的一组特定层时,您可能想要更改的标志。**
现在,我们将尝试冻结所有,但最后一层的模型。如果我们浏览模型所有参数的所有名称,我们可以看到最后一层的名称是‘fc’,代表‘全连接’。**
因此,让我们冻结所有参数,除了名称为【fc . weight】或【fc . bias】的参数**
我们可以通过为模型的所有参数打印出 requires_grad 来验证所需的更改已经成功完成
我们可以看到,所需的更改已经成功完成!
因此,我们已经了解了如何为模型的任何所需参数更改 requires_grad 标志。我们还了解到,在我们想要学习/冻结模型中某些特定参数/层的权重的情况下,这样做非常方便。**
我们现在将学习两种广为人知的保存模型权重/参数的方法。
- torch.save(model.state_dict(),' weights_path_name.pth')
它只保存模型的权重****** - torch.save(model,' model_path_name.pth')
保存整个模型(架构以及权重)****
state_dict()是什么,在哪里使用?
我们将首先看看如何编写 state_dict 的语法。这很简单。
这只是一个 python 的有序字典。
但是,打印这个,会导致混乱。所以我们不会在这里打印整个模型的 state_dict ,但是我鼓励你们继续在屏幕上打印出来!
我想这是转移话题的好时机。
看,打印帮助(模型)告诉我们,模型是 nn 的一个实例。模块
也可以使用 python 的 isinstance 函数进行验证
model.fc 也是 nn 的实例吗?模块?
显然是的!
但是 fc ,到底是什么,又是从何而来?
我们什么都能看到 nn。模块对象位于模型下
在任何 nn 上应用的 named_children() 。模块对象返回它的所有直接子对象(也是 nn。模块对象)。看看上面这段代码的结果,我们知道‘sequential’,‘layer 1’,‘layer 2’,和‘fc’,都是 model 的子节点,所有这些都是 nn。模块类对象。现在我们都知道【fc】是从哪里来的了。
你知道吗? state_dict() 作用于任何 nn。模块对象并返回它的所有直接子对象(属于类 nn。模块)。
所以我们来试试模型的‘fc’层上的 state_dict() 函数。
记住 model.fc.state_dict() 或者任何 nnModule.state_dict() 都是一个有序字典。所以迭代它给了我们字典的键,可以用来访问参数张量,顺便说一下,它不是一个 nn。模块对象,而是一个简单的火炬。具有形状和的张量需要 _grad 属性。****
所以一定要注意,当我们保存一个 nn 的 state_dict() 时。模块对象例如模型、焊枪。张量物体被保存!
这就是我们保存整个模型的 state_dict 的方法。
这在工作目录中生成了一个 'weights_only.pth' 文件,它在一个有序的字典中保存了火炬。张量模型所有层的对象。
我们现在将尝试加载保存的重量。但是在此之前,我们需要首先定义模型架构。首先定义模型,然后在其中加载权重是有意义的,因为保存的信息只是权重而不是模型架构。****
一旦权重被加载到定义的模型中,让我们检查 model_new 所有层的 requires_grad 属性。
等等!什么?
我们为所有不同层设置的所有 requires_grad 标志发生了什么变化?似乎所有的 requires_grad 标志都被重置为 True 。
其实我们从来没有在第一时间保存参数的 required_grad 标志。记住,一个 state_dict 只是一个 python 字典对象,它将每个层映射到它的参数张量。它不保存参数的 requires_grad 属性。
因此,我们需要再次对所有参数的 requires_grad 属性进行必要的更改,然后才能继续对模型进行更多时期的训练
如何保存整个模型,什么时候做?
是的,我们有第二种保存东西的方法,也可以保存整个模型。对于整个模型,我指的是模型的架构以及它的重量。****
因此,我们将从冻结模型的最后一层(即‘fc’层)的地方继续,并保存整个模型。
这将在工作目录中创建一个‘entire _ model . PTH’文件,它包含模型架构以及保存的权重。****
我们现在将尝试加载保存的模型。这一次,我们不需要定义模型架构,因为关于模型架构的信息已经存储在保存的文件中。
一旦模型被加载,让我们检查 model_new 所有层的属性。
这正是我们想要看到的,不是吗?😄
所以当我们保存整个模型时,我们保存了 nn。模块对象,这样做也保存了其所有参数的 requires_grad 标志。
我强烈建议你们把这个public ka ggle kernel叉出来,玩玩代码,感受一下!
总结
我们在这个博客中学到了很多东西。
- 在 nn 上应用 命名参数() 。模块对象,例如模型或
或模型.图层 2 或模型. fc 返回所有的名称和各自的参数。这些参数是 nn。参数(火炬的子类。张量对象,因此它们具有形状和要求 _grad 属性。
2. 需要 nn 的 _grad 属性。参数对象(可学习参数对象)决定是否训练或冻结特定参数。例如,如果我们想要冻结模型的层 1 ,我们将使用下面的代码。
3.将 命名为 _children() 应用于任何 nn 上。模块对象返回它的所有直接子对象(也是 nn。模块对象)。
4.任何 nn 的一个 state_dict() 。模块对象,例如模型或模型.层 2 或模型. fc 只是一个 python 有序字典对象,它将每个参数映射到其参数张量(火炬。张量对象)。该有序字典的键是参数的名称,可用于访问相应的参数张量。****
5.保存一个 nn。模块对象的 state_dict 仅保存该对象的各种参数的 权重而不保存模型架构。也不涉及权重的 requires_grad 属性。所以在加载 state_dict 之前,必须先定义模型。****
6.整个模型( nn。模块对象)也可以被保存,这将包括模型架构及其权重。既然我们在拯救 nn。模块对象, requires_grad 属性也以这种方式保存。此外,我们不需要在加载保存的文件之前定义模型架构,因为保存的文件中已经保存了模型架构。****
7.保存 state_dict 只能用来保存模型的权重。它不会保存 required_grad 标志,而保存整个模型会保存模型架构、它的权重以及所有参数的 requires_grad 属性。
8.state _ dict 和整个模型都可以被保存以进行推断。
我写这篇博客是因为我通过阅读别人的博客学到了很多东西,我觉得我也应该尽可能多地写下并分享我的学习和知识。所以请在下面的评论区留下你的反馈。此外,我是写博客的新手,所以任何关于如何提高我的写作的建议将不胜感激!😄
我也是一个独立的音乐艺术家,喜欢在空闲时间演奏和录制音乐。也许你可以在 Spotify 上查看我的艺人页面,表示支持:)
Spotify 上的 8 楼和声!
数据可视化散点图的所有信息
想获得灵感?快来加入我的 超级行情快讯 。😎
如果你是一名数据科学家,毫无疑问,你以前处理过散点图。尽管散点图很简单,但它是可视化数据的强大工具。颜色、大小、形状和回归图等几个参数的简单变化带来了大量的选项、灵活性和表现能力。
在这里,您将了解到关于散点图可视化数据的所有知识!我们将浏览所有的参数,看看何时以及如何在代码中使用它们。您可能会发现一些可以添加到您的数据科学工具箱中的惊喜和技巧!
回归绘图
当我们第一次在散点图上绘制数据时,它已经给了我们一个很好的数据概览。在下面最左边的图中,我们已经可以看到大多数数据似乎聚集在一起的组,并且可以快速挑选出异常值。
但是能够看到我们的任务会变得多么复杂也是一件好事;我们可以用回归图来做。在下图中间,我们做了一个线性图。显而易见,线性函数不起作用,因为许多点离直线很远。最右边的特性使用 4 阶多项式,看起来更有前途。所以看起来我们肯定需要至少 4 阶的东西来建模这个数据集。



颜色和形状
颜色和形状可用于显示数据集中的不同类别。颜色和形状对人类视觉系统来说都是非常直观的。当你看一个点群有不同颜色和形状的图时,很明显这些点属于不同的群。这对我们来说很自然。这种自然的直觉总是你在创建清晰和引人注目的数据可视化时想要发挥的。让它显而易见,不言自明。
下图左侧显示了按颜色分组的类别;右图显示了按颜色和形状划分的类别。在这两种情况下,都比我们只有蓝色时更容易看到分组!我们现在知道,以较低的误差分离 setosa 类可能很容易,我们应该将注意力集中在如何将另外两个类彼此分离上。同样清楚的是,一个单一的线性图无法将绿色和橙色点分开;我们需要更高维的东西。
在颜色和形状之间做出选择变成了个人喜好的问题。就我个人而言,我觉得颜色更清晰和直观,但你可以自己选择!


边缘直方图
具有边缘直方图的散点图是那些在顶部和侧面绘制直方图的散点图,代表特征点沿 x 轴和 y 轴的分布。这是一个很小的增加,但对于查看我们的点的精确分布和更准确地识别我们的异常值来说是很棒的。
例如,在下图中我们可以看到,为什么轴在 3.0 附近有一个非常密集的点。有多集中?这在最右边的直方图中最容易看到,它显示 3.0 附近的点至少是任何其他离散范围的三倍。我们还看到,与其他范围相比,几乎没有任何高于 3.75 的点。另一方面,对于 x 轴来说,除了最右边的异常值之外,其他的都比较均匀。

气泡图
通过气泡图,我们可以使用几个变量来编码信息。我们将在这里添加的新参数是大小。在下图中,我们绘制了每个人吃薯条的数量与他们的身高和体重的关系。请注意,散点图只是一个 2D 可视化工具,但是使用不同的属性,我们可以表示三维信息。
这里我们使用的颜色、位置和大小。位置决定了人的身高体重,颜色决定了性别,大小决定了吃薯条的数量!气泡图让我们方便地将所有属性合并到一个图中,这样我们可以在一个简单的 2D 视图中看到高维信息;没什么复杂的。

喜欢学习?
在推特上关注我,我会在这里发布所有最新最棒的人工智能、技术和科学!也请在 LinkedIn上与我联系!
关于雪花参数您需要知道的一切(第 1 部分)
[专业数据技能](http://towardsdatascience.com/tagged/professional data skills)

Photo by Andrea Sonda on Unsplash
雪花是一个非常受欢迎的云数据仓库,以其简单、强大的功能、有竞争力的价格和易于维护而闻名。来到 Snowflake 的 DBA 通常会惊喜地发现,他们只需调整很少的东西就能让它保持运行。
其中之一就是雪花参数。对于传统数据库,DBA 经常花时间微调参数以获得最佳性能。有时,这对于提高单个查询的运行速度是必要的。有几十个雪花参数,但大多数安装都可以运行得很好,而不需要调整任何参数。
然而,知道什么在运行总是好的——不仅仅是为了知道,而是因为有时它可以帮助更快地解决问题。
在这篇由两部分组成的文章中,我将讨论雪花参数及其工作原理。你将学习如何以不同的方式改变和重置它们,这样一个地方的改变不会影响到另一个地方。最后,我们将讨论有时会派上用场的重要参数。
让我们开始吧。
雪花参数的类型和级别
有两种方法可以识别雪花参数:参数的类型及其层次级别。
参数类型基于它所控制的资源类型。有些参数适用于整个雪花帐户,有些适用于用户会话,有些适用于雪花对象。
雪花参数有三种类型:
- 账户
- 会话
- 对象
一个账户类型参数影响整个雪花账户。这些参数是在帐户级别设置的,不能在层次结构的较低级别覆盖。只有 ACCOUNTADMIN 角色成员(对于一个参数,还有 SYSADMIN 角色成员)可以更改它们的值。一旦您设置了帐户参数,它将对所有用户及其会话可见。
接下来,我们有会话类型参数。这些参数主要与用户及其会话相关。它们可以在帐户级别设置,但也可以针对每个用户进行更改。在用户的会话中,它可以再次更改为不同的内容。
这是在层次结构的不同级别改变参数的一个例子。这里,会话类型参数可以在账户级别(层级的根级别)设置默认值。在帐户下,我们还有单独的雪花用户(层次结构的第一层),每个用户可以有多个会话(层次结构的第二层)。创建帐户时(或之后),可以为用户帐户更改在帐户级别设置的参数值。当用户登录时,她可以为她的会话将相同的参数更改为不同的值。换句话说,该参数现在在层次结构的三个级别上具有三个不同的值。
会话类型参数可用于满足不同的用户需求。例如,从美国连接的用户可能希望看到以“mm-dd-yyyy”格式显示的日期,而来自亚洲的用户可能希望看到以“dd/mm/yyyy”格式列出的日期。此参数的帐户级别值可以是默认的“yyyy-mm-dd”。在用户级别设置该值可确保不同的用户以他们希望的方式查看日期。
现在,假设一个来自美国的用户登录到数据仓库,但是想要查看“MMM-dd-yyyy”格式的日期。她只能为自己的会话更改参数。
ACCOUNTADMIN 和 SYSADMIN 角色成员都可以为用户分配或更改参数。如果在用户或会话级别没有对会话类型参数进行更改,则应用帐户级别的值。
最后还有对象类型参数。这些参数适用于雪花对象,如仓库和数据库。仓库没有任何层次结构,因此可以在帐户级别设置特定于仓库的参数,然后针对各个仓库进行更改。
类似地,可以在帐户级别设置特定于数据库的参数,然后针对每个数据库进行设置。与仓库不同,数据库有一个层次结构。在数据库中,模式可以覆盖帐户或数据库级别的参数集,而在模式中,表可以覆盖帐户、数据库或模式级别的参数集。如果在层次结构的较低级别没有进行更改,则在最近的较高级别设置的值将应用于下游。
使用雪花参数
那么如何看出雪花有哪些参数呢?
看你想看什么了。对于帐户或会话类型参数,您可以运行以下命令:
—- shows parameters defined at the account level
SHOW PARAMETERS IN ACCOUNT;—- shows parameters defined at the user level
SHOW PARAMETERS IN USER;-- shows parameters defined at the session level
SHOW PARAMETERS IN SESSION;-- shows parameters defined at the session level
SHOW PARAMETERS
让我们看看输出:

这里:
- 键 是参数名
- 值 是为该参数设置的当前值
- 默认值 是该参数的默认值
- 级别 是应用当前值的层级位置。如果默认值和当前值相同,则该字段为空。
以下是在会话级别更改参数的示例:
ALTER SESSION SET TIMEZONE=’Australia/Sydney’;
如果您现在运行此命令:
SHOW PARAMETERS LIKE ‘%TIMEZONE%’;
输出显示当前值是在会话级别设置的,它不同于默认值:

要查找在帐户级别设置的值,请运行以下命令:
SHOW PARAMETERS LIKE ‘%TIMEZONE%’ IN ACCOUNT;
它显示默认值在帐户级别没有改变。请注意“级别”列在这里是空的:

要将参数重置回原来的值,请运行以下命令:
ALTER SESSION UNSET TIMEZONE;
现在让我们来谈谈对象类型参数。与帐户或会话类型不同,查询对象类型参数需要指定对象类型(数据库、模式、表或仓库)和对象名称。
此代码片段显示了如何列出数据库、模式、表和仓库的对象属性:
-- Shows parameters set at database level
SHOW PARAMETERS IN DATABASE MYTESTDB;-- Shows parameters set at schema level
SHOW PARAMETERS IN SCHEMA MYTESTDB.TEST_SCHEMA;-- Shows parameters set at table level
SHOW PARAMETERS IN TABLE MYTESTDB.TEST_SCHEMA.MY_TEST_TABLE;-- Shows parameters set for a warehouse
SHOW PARAMETERS IN WAREHOUSE MYTESTWH;
假设您想要将 TEST_SCHEMA 的数据保持期更改为 0 天,这实际上关闭了它的时间旅行。运行如下命令:
ALTER SCHEMA MYTESTDB.TEST_SCHEMA SET DATA_RETENTION_TIME_IN_DAYS=0;
要将其改回默认值,请运行如下命令:
ALTER SCHEMA MYTESTDB.TEST_SCHEMA UNSET DATA_RETENTION_TIME_IN_DAYS;
这就是关于查询和设置雪花参数您需要知道的一切。
第 1 部分结束
这是不到十分钟的关于雪花参数的介绍。这里没有什么奇特或复杂的。然而,真正的力量来自于知道需要时可以调整哪些参数,以及调整到什么水平。这就是我们将在第 2 部分讨论的内容。敬请关注。
如果你喜欢它,请鼓掌,在 Twitter、Medium 和 LinkedIn 上关注我。
关于雪花参数您需要知道的一切(第 2 部分)
专业数据技能

Photo by Kai Dahms on Unsplash
在这个由两部分组成的文章系列的第一部分中,您了解了雪花云数据仓库参数是如何工作的。
合乎逻辑的下一个问题是,您应该了解哪些参数?更重要的是,你应该什么时候使用它们?
在这最后一部分,您将了解一些有用的雪花参数。
事不宜迟,这是清单。
中止 _ 分离 _ 查询
该参数告诉雪花,如果客户端连接断开(浏览器窗口关闭、网络连接中断等),它是否应该中止正在进行的查询。这是一个会话类型参数,可以在帐户、用户或会话级别设置。默认值为 FALSE,这意味着即使客户端连接断开,雪花也将继续运行查询。
作为管理员,您可能希望为人类用户将该参数设置为 TRUE,这样他们断开连接的查询就不会浪费宝贵的仓库资源。同样,对于应用程序用户帐户,该值可以设置为 FALSE。这些帐户通常运行大型聚合或冗长的数据加载。将这些帐户的参数设置为 FALSE 将确保关键数据处理任务不受连接中断的影响。
LOCK_TIMEOUT
这是一个会话类型参数,它告诉 Snowflake 在超时和中止查询之前应该等待多少秒来获取资源锁。默认值是 43200 秒或 12 小时,这通常被认为太长了。
作为一个大概的数字,您也许可以将这个值降低到 30 分钟,并保留应用程序帐户的默认值。
数据保留时间天数
这是一个对象类型参数。它可以设置为:
- 帐户级别:该值将应用于雪花帐户中的所有数据库、模式和表
- 对象级:该值适用于单个数据库、模式或表
DATA _ RETENTION _ TIME _ IN _ DAYS告诉雪花应该将历史数据保持可用多长时间,以便用户可以返回到他们数据中的特定时间点。默认值是 1 天,在雪花标准版中只能返回到这一天。对于雪花企业版和更高版本,这可以设置为最多 90 天。将该参数设置为 0 意味着对象的时间旅行已关闭。
如果您使用的是雪花企业版或更高版本,在帐户级别将该参数设置为 90 并忘记它可能很有诱惑力。在这样做之前,请考虑它将如何影响您的数据存储成本。您的帐户是否用于非生产工作并托管大量非生产数据?您的数据处理例程是否创建了大量临时表?在这种情况下,您可能希望关闭非生产数据库或表的数据保留以节省成本。
时区
这是一个会话类型参数,指定雪花帐户的时区。除非有任何在用户或会话级别设置它的实际需要,否则在帐户级别设置该值并保留它。
使用缓存结果
这是另一个会话类型参数,应该在帐户级别设置,不能在用户或会话级别更改。
Snowflake 尽可能使用缓存,它的大部分性能优势来自于能够在再次运行相同的查询时使用缓存的结果——无论是来自云服务层还是来自仓库层。当在缓存中找到匹配的结果集时,Snowflake 返回该结果集。这大大提高了性能,因为没有使用仓库来处理请求。
该参数的默认值为 TRUE,除非有非常特殊的用例,否则应该保持不变。在对查询性能进行故障排除时,您可能希望通过运行以下命令来仔细检查是否在会话级别启用了缓存:
SHOW PARAMETERS LIKE '%USE_CACHED_RESULT%'
语句 _ 超时 _ 秒
这个参数告诉雪花在系统取消之前一个 SQL 语句可以运行多长时间。默认值为 172800 秒(48 小时)
这既是会话参数,也是对象类型参数。作为会话类型,它可以应用于帐户、用户或会话。作为一种对象类型,它可以应用于仓库。如果在两个级别都设置了,则使用最低的值。
您可以在帐户级别保留默认值,但可以根据您的仓库进行更改。例如,如果您不希望您的 ETL 仓库运行数据加载命令超过 8 小时(并且不花钱),那么为仓库设置参数:
ALTER WAREHOUSE <warehouse> SET STATEMENT_TIMEOUT_IN_SECONDS = 28800
处理完成后,您可以重置参数:
ALTER WAREHOUSE <*warehouse*> UNSET STATEMENT_TIMEOUT_IN_SECONDS
语句排队超时秒数
和STATEMENT _ time out _ IN _ SECONDS一样,这个也是会话和对象类型参数。与该参数不同的是,它并不控制已经在运行的 SQL 语句应该允许运行多长时间,而是在系统取消它之前应该允许它在仓库队列中等待多长时间。默认值为 0,这意味着语句在得到服务之前一直保留在队列中。和前面的参数一样,如果在仓库和会话级别都设置了该参数,则使用最小值。
如果数据加载或查询在排队后超时,请检查帐户、用户和仓库级别的参数值。
最大并发级别
这可能是仓库最重要的参数之一。这是一个对象类型参数,可以在整个帐户范围内设置,也可以为单个仓库设置。 MAX_CONCURRENCY_LEVEL 告诉雪花在一个仓库中可以并行运行多少条 SQL 语句。当提交的 SQL 语句的数量达到这个阈值时,任何新的 SQL 语句可能会也可能不会被放入队列中。雪花是怎么决定这个的?以下是方法。
对于配置为自动扩展到最大集群数的多集群仓库,在达到阈值后提交的任何新 SQL 都将导致一个新集群加速运行。然后,新的 SQL 语句由新的集群提供服务。
如果多集群仓库已达到其集群的最大限制,或者如果它是单集群仓库,则新的 SQL 语句将被放入队列中。您可以通过将仓库扩大到更高的容量来避免这种情况。此外,请记住,多集群仓库是雪花企业版和更高版本的一个功能。
假设您的仓库没有扩大,也没有更多的集群可以运转。SQL 语句在队列中等待多长时间?你猜对了——它是由你在语句 _ 排队 _ 超时 _ 秒数参数中指定的时间决定的。
现在,从大型多集群仓库开始,并将 STATEMENT _ QUEUED _ time out _ IN _ SECONDS 参数设置为 0,这样就不会出现阻塞,这可能很有诱惑力。但是您真正应该做的是针对较小的仓库测试您的峰值负载,并查看是否有任何语句始终处于排队状态。如果您使用的是雪花企业版或更高版本,请从较小的多集群仓库开始。从最大集群数的保守值开始,随着测试的进行逐渐增加。对于 Snowflake Standard Edition 帐户,从一个小仓库开始,随着测试的进行逐渐增加它的大小。
此外,将该参数设置为与仓库大小成比例的值。例如,如果您为“小型”仓库将该参数设置为一个很高的值,那么查询很可能需要很长时间才能完成,因为每个查询占用的资源会更少。如果将该参数设置得太低,可能会出现不必要的排队。最佳选择是对每个峰值负载场景进行测试。
日期输出格式
这是一个会话类型参数。它可以在用户或会话的帐户级别设置。顾名思义,这个参数告诉雪花如何显示日期。除非需要更改报告的显示格式,否则请使用默认格式 YYYY-MM-DD。
网络 _ 策略
雪花网络策略允许(或不允许)来自特定 IP 地址或地址范围的流量。这个 IP 白名单(和黑名单)充当了雪花内部事实上的防火墙。网络策略参数告诉雪花哪个网络策略有效。
这是一个帐户类型参数,这意味着它不能被用户或她的会话覆盖。
对雪花的连接进行故障排除时,可以查询此参数。如果客户端连接被拒绝,即使存在网络连接,您也可以检查此参数来查找任何网络策略名称。然后,您可以从策略中找到被阻止的 IP 地址,并查看客户端的地址是否在这些被阻止的 IP 中。
资源 _ 监视器
资源监视器帮助控制雪花的仓库使用量。系统管理员经常创建资源监视器来跟踪雪花仓库使用的信用。如果设置了配额,雪花可以在达到阈值时发送通知,或者立即暂停仓库。可以在帐户级别创建资源监视器,在这种情况下,配额适用于帐户中所有仓库使用的总配额,也可以在仓库级别创建资源监视器,在仓库级别,配额仅适用于单个仓库。如下图所示:

RESOURCE_MONITOR 是一个账户类型参数,只能在账户级别设置。参数值是为帐户定义的资源监视器的名称。
这也强调了这样一个事实,即仅仅为一个帐户创建一个资源监视器是不够的——它的名称应该分配给 RESOURCE_MONITOR 参数。
SAML _ 身份 _ 提供者
这是另一个帐户类型参数。只有在使用第三方身份提供者(如 Active Directory、Okta 或其他)配置单点登录(SSO)时,才需要设置此选项。
参数值应该是用单引号括起来的 JSON 文档。该 JSON 文档指定了身份提供者生成的证书名称、身份提供者的 URL、身份提供者的类型以及雪花登录页面中显示的身份提供者按钮的标签。
在大多数生产设置中,企业通常希望将雪花与他们自己的身份系统集成在一起。因此,设置这个参数需要基础设施工程师和数据库管理员的合作。
单点登录页面
该参数在测试单点登录时很有用。同样,这是一个帐户类型参数,只能在帐户级别设置。这是一个布尔参数,控制当启用联合身份验证时,雪花将如何显示登录页面。
- TRUE 表示预览模式关闭,用户可以在雪花登录页面看到 SAML 身份提供者的 SSO 登录提示。
- FALSE (默认值)表示预览模式开启,用户可以使用特定的 URL 导航到 SSO 登录页面。
URL 的格式在雪花文档中有描述。
最后的话
这就结束了我们的雪花参数系列。我希望这是一个有用的介绍。不过,需要注意的是:不要在生产雪花环境中更改任何参数,除非有强有力的理由,并且该更改已经过测试和批准。对于 DBA:在创建或修改用户帐户或仓库时,考虑为这里描述的一些参数分配标准值。
如果你喜欢这篇文章,请鼓掌欢迎,并在 Medium、Twitter 和 LinkedIn 上关注我。
关于 TensorFlow 2.0 您需要了解的一切
Keras-API、SavedModels、TensorBoard、Keras-Tuner 等等。

2019 年 6 月 26 日,我有幸在圣保罗 papis . io LATAM 大会上展示了一个 TensorFlow (TF) 2.0 工作坊。除了作为工作坊主持人代表大坛的快乐之外,我很高兴谈论 TF 2.0。
研讨会的目的是强调与以前的 1.x 版本的 TF 相比有什么变化。在这篇课文中,你可以跟上我们将要讨论的主要话题。当然,看看的 Colab 笔记本中的实用代码。
TensorFlow 2.0 简介
TensorFlow 是 Google 在 2015 年开源的通用高性能计算库。从一开始,它的主要焦点就是为构建神经网络(NNs)提供高性能的 API。然而,随着时间的推移和机器学习(ML)社区的兴趣,lib 已经发展成为一个完整的 ML 生态系统。

目前,该图书馆正经历着自诞生以来最大的一系列变化。TensorFlow 2.0 目前处于测试阶段,与 TF 1.x 相比,它带来了许多变化,让我们深入了解一下主要的变化。
默认情况下急切执行
首先,急切执行是运行 TF 代码的默认方式。
您可能还记得,为了在 TF 1.x 中构建一个神经网络,我们需要定义这个称为图的抽象数据结构。另外,(您可能已经尝试过),如果我们试图打印一个图形节点,我们将看不到我们期望的值。相反,我们会看到对图形节点的引用。实际上,为了运行图表,我们需要使用一个叫做会话的封装。使用 Session.run() 方法,我们可以将 Python 数据传递给图表,并实际训练我们的模型。

TF 1.x code example.
随着急切的执行,这种情况发生了变化。现在,TensorFlow 代码可以像普通 Python 代码一样运行——急切地。这意味着操作是一次创建和评估的。

Tensorflow 2.0 code example.
因此,TensorFlow 2.0 代码看起来很像 NumPy 代码。事实上,TensorFlow 和 NumPy 对象可以很容易地从一个对象切换到另一个对象。因此,您不需要担心占位符、会话、feed _ dictionalities等。
API 清理
许多像 tf.gans、tf.app、tf.contrib、tf.flags 这样的 API 要么消失了,要么被移动到单独的存储库。
然而,最重要的清理之一与我们如何构建模型有关。你可能还记得,在 TF 1.x 中,我们有不止一两种不同的方法来构建/训练 ML 模型。
Tf.slim、tf.layers、tf.contrib.layers、tf.keras 都是可以用来构建 NNs 的 API。TF 1 . x 中不包括排序 API 的序列。这种缺乏标准化的情况有一个很大的问题——大多数时候,不清楚为每种情况选择哪一种。
尽管这些 API 中有许多都有很好的特性,但它们似乎并没有汇聚成一种通用的开发方式。此外,如果我们用这些 API 中的一个来训练一个模型,那么使用其他 API 来重用那个代码并不直接。
在 TF 2.0 中,tf.keras 是推荐的高级 API。
正如我们将看到的,Keras API 试图解决所有可能的用例。
初学者 API
从 TF 1.x 到 2.0,初学者 API 变化不大。但是现在,Keras 是默认和推荐的高级 API。
总之,Keras 是一组层,描述了如何使用清晰的标准构建神经网络。基本上,当我们使用 pip 安装 TensorFlow 时,我们获得了完整的 Keras API 和一些附加功能。
初学者的 API 叫做 Sequential。它基本上将神经网络定义为一堆层。除了简单之外,它还有一些优点。注意,我们根据数据结构(一堆层)来定义模型。因此,它最小化了由于模型定义而产生错误的可能性。
喀拉斯调谐器
Keras-tuner 是一个用于 Keras 模型超参数调谐的专用库。在撰写本文时,lib 处于的 pre-alpha 状态,但在带有 tf.keras 和 Tensorflow 2.0 beta 的 Colab 上运行良好。
这是一个非常简单的概念。首先,我们需要定义一个模型构建函数,它返回一个编译过的 Keras 模型。该函数将表示调优对象的参数作为输入。使用it,我们可以定义一个候选值范围,从中对超参数值进行采样。
下面我们建立了一个简单的模型,并优化了 3 个超参数。对于隐藏单元,我们对预定义范围内的整数值进行采样。对于辍学率和学习率,我们在一些特定值之间随机选择。
然后,我们创建一个表示随机搜索策略的 tuner 对象。最后,我们可以使用 search() 方法开始优化——它与 fit() 具有相同的签名。
最后,我们可以检查调谐器摘要结果并选择最佳型号。注意,训练日志和模型检查点都保存在目录文件夹 (my_logs) 中。此外,最小化或最大化目标(验证准确性)的选择是自动推断的。
看看他们的 Github 页面了解更多。
高级 API
当你看到这种类型的实现时,它又回到了面向对象编程。这里,您的模型是一个 Python 类,它扩展了 tf.keras.Model 。模型子类化是由 Chainer 启发的想法,与 PyTorch 如何定义模型有很大关系。
使用模型子类化,我们在类构造函数中定义模型层。并且 call() 方法处理向前传递的定义和执行。
子类化有很多优点。更容易执行模型检查。例如,我们可以(使用断点调试)在给定的一行停下来,检查模型的激活或逻辑。
然而,伴随着巨大的灵活性而来的是更多的错误。
模型子类化需要程序员更多的关注和知识。
一般来说,你的代码更容易出错(比如模型连接)。
定义训练循环
在 TF 2.0 中训练模型最简单的方法是使用 fit() 方法。 fit() 支持两种类型的模型,顺序模型和子类模型。如果使用模型子类化,你需要做的唯一调整是覆盖 compute_output_shape ()类方法,否则,你可以通过它离开。除此之外,您应该能够将 fit() 与 tf.data.Dataset 或标准 NumPy nd-arrays 一起用作输入。
然而,如果你想清楚地了解梯度或损失的情况,你可以使用梯度带。如果你在做研究,这尤其有用。
使用梯度带,可以手动定义训练程序的每个步骤。训练神经网络的每个基本步骤,例如:
- 前进传球
- 损失函数评估
- 偶数道次
- 梯度下降步骤
单独指定。
如果你想知道神经网络是如何训练的,这就更直观了。如果您想检查模型权重或梯度向量本身的损失值,您可以将它们打印出来。
梯度胶带具有更大的灵活性。但是就像子类化和顺序化一样,更多的灵活性伴随着额外的成本。与 fit() 方法相比,这里我们需要手动定义一个训练循环。作为一个自然的结果,这使得代码更容易出现错误,也更难调试。我相信,与通常对开发新事物感兴趣的研究人员相比,这是代码工程师(寻找标准化代码)的理想选择。
同样,使用 fit() 我们可以很容易地设置 TensorBoard,如下图所示。
设置张量板
您可以使用 fit() 方法轻松设置 TensorBoard 的实例。它也适用于 Jupyter/Colab 笔记本电脑。
在这种情况下,您添加 TensorBoard 作为对 fit 方法的回调。
只要你使用的是 fit() 方法,它对顺序 API 和子类 API 都有效。
如果选择使用模型子类化,自己编写训练循环(使用评分带),还需要手动定义 TensorBoard。它包括创建摘要文件,使用TF . summary . create _ file _ writer(),并指定您想要可视化的变量。
作为一个值得注意的点,有许多回调你可以使用。一些比较有用的是:
- EarlyStopping:顾名思义,它设置了一个规则,当监控的数量停止改善时,就停止训练。
- ReduceLROnPlateau:当指标停止改善时,降低学习率。
- TerminateOnNaN:遇到 NaN 丢失时终止训练的回调。
- LambdaCallback: Callback 用于动态创建简单的自定义回调。
您可以在 TensorFlow 2.0 回调查看完整列表。
提取您的 EagerCode 的性能
如果您选择使用渐变磁带来训练您的模型,您将会注意到性能的大幅下降。
急切地执行 TF 代码有利于理解,但在性能上失败了。为了避免这个问题,TF 2.0 引入了 tf.function 。
基本上,如果你用 tf.function 修饰一个 python 函数,你就是在要求 TensorFlow 接受你的函数并将其转换成 tf 高性能抽象。
这意味着该函数将被标记为 JIT 编译,以便 TensorFlow 将其作为图形运行。结果,您获得了 TF 1.x (graphs)的性能优势,如节点修剪、内核融合等。
简而言之,TF 2.0 的思想是你可以将你的代码设计成更小的函数。然后,您可以使用 tf.function 注释您想要的内容,以获得额外的性能。最好修饰代表最大计算瓶颈的函数。这些通常是训练循环或模型的向前传递。
注意,当你用 tf.function 来修饰一个函数时,你失去了急切执行的一些好处。换句话说,您将无法在该代码段内设置断点或使用 print() 。
保存和恢复模型
TF 1.x 中另一个严重缺乏标准化的地方是我们如何为生产保存/加载训练好的模型。TF 2.0 也试图通过定义单个 API 来解决这个问题。
TF 2.0 没有很多保存模型的方法,而是标准化了一个叫做 SavedModel 的抽象。
这里就不多说了。如果你创建一个顺序模型或者使用 tf.keras.Model 扩展你的类,你的类继承自 tf.train.Checkpoints 。因此,您可以将模型序列化为 SavedModel 对象。
SavedModels 与 TensorFlow 生态系统相集成。换句话说,您将能够将其部署到许多不同的设备上。其中包括手机、边缘设备和服务器。

转换为 TF-Lite
如果您想将 SavedModel 部署到嵌入式设备,如 Raspberry Pi、Edge TPUs 或您的手机,请使用 TF Lite 转换器。
注意,在 2.0 中,TFLiteConverter 不支持冻结的 GraphDefs(通常在 TF 1.x 中生成)。如果你想转换一个冻结的 GraphDefs 来在 TF 2.0 中运行,你可以使用 tf.compat.v1.TFLiteConverter。
在部署到嵌入式设备之前执行训练后量化是非常常见的。要使用 TFLiteConverter 实现这一点,请将 optimizations 标志设置为“OPTIMIZE_FOR_SIZE”。这将把模型的权重从浮点量化到 8 位精度。它将减少模型大小并改善延迟,而模型准确性几乎没有下降。
请注意,这是一个实验性的标志,它可能会发生变化。
转换到 TensorFlow.js
最后,我们还可以将同一个 SavedModel 对象转换为 TensorFlow.js 格式。然后,我们可以使用 Javascript 加载它,并在浏览器上运行您的模型。
首先需要通过 pip 安装 TensorFlow.js。然后,使用 tensorflowjs_converter 脚本将训练好的模型转换成 Javascript 兼容代码。最后,您可以加载它并在 Javascript 中执行推理。
您也可以在浏览器上使用 Tesnorflow.js 来训练模型。
结论
最后,我想提一下 2.0 的一些其他功能。首先,我们已经看到,向一个顺序的或者子类化的模型中添加更多的层是非常简单的。虽然 TF 覆盖了大多数流行的层,如 Conv2D、TransposeConv2D 等;你总能发现自己处于这样一种情况,你需要一些得不到的东西。如果你正在复制一些论文或做研究,那就更是如此。
好消息是,我们可以开发自己的自定义层。遵循相同的 Keras API,我们可以创建一个类并将其扩展到 tf.keras.Layer 。事实上,我们可以按照非常相似的模式创建定制的激活函数、正则化层或度量。这里有一个关于它的好资源。
还有,我们可以把现有的 TensorFlow 1.x 代码转换成 TF 2.0。为此,TF 团队创建了 tf_upgrade_v2 实用程序。
此脚本不会将 TF 1.x 代码转换为 2.0 惯用代码。它基本上使用 tf.compat.v1 模块来实现名称空间发生变化的函数。此外,如果您的遗留代码使用 tf.contrib ,脚本将无法转换它。您可能需要使用额外的库或者使用新的 TF 2.0 版本中缺少的函数。
感谢阅读。
关于解释相关性你需要知道的一切
并非所有的相关性都是表面上看起来的那样

相关性是评估变量之间关系的最广泛使用的统计方法。然而,相关性必须谨慎使用;否则,它可能导致错误的解释和结论。
相关性可能产生误导的一个例子是当您处理样本数据时。因为样本中的明显相关性不一定存在于样本所来自的总体中,而可能只是由于偶然的巧合(随机抽样误差)。这就是为什么相关性必须伴随着显著性检验来评估其可靠性的原因。
此外,在解释关系时,应该注意不要混淆相关性和因果关系,因为尽管相关性表明两个变量之间存在关系,但它并不自动暗示一个变量导致另一个变量(因果关系)。
这篇文章将定义相关性,相关性的类型,解释如何使用相关系数测量相关性,尤其是如何使用显著性检验评估线性相关性的可靠性。如果熟悉相关,可以跳过介绍。
1 —相关性介绍
相关性是一种统计度量,描述两个变量如何相关,并表明当一个变量的值发生变化时,另一个变量倾向于在特定方向上发生变化。因此,我们可以指出一些现实生活中的相关性,如收入与支出、供给与需求、缺勤与成绩下降等。
每个关联都有一个符号和一种形式,符号可以是积极的、消极的或中性的:
- 正相关:两个变量同向变动(即一个变量随着另一个变量的增加而增加。或者,一个随着另一个减少而减少)。
- 负相关:两个变量反向运动(即一个变量增加,另一个变量减少,反之亦然)
- 中性相关:这两个变量相互之间没有关系。

关于相关性的形式,它可以是线性的、非线性的或单调的:
- 线性相关性:当两个变量以恒定速率变化并满足等式 Y = aX + b 时,相关性是线性的(即,关系必须以直线绘制)。
- 非线性相关性:当两个变量不以恒定速率变化时,相关性是非线性的。在这种情况下,变量之间的关系不是直线,而是曲线(抛物线、双曲线等)。
- 单调相关:在单调关系中,变量倾向于以相同的相对方向运动,但不一定以恒定的速率运动。所以所有的线性相关都是单调的,但反过来就不一定了,因为我们也可以有单调的非线性关系。

2 —相关系数
正如我们在上面的图片中看到的,绘制散点图对于观察变量之间可能存在的相关性非常有用。但是为了用数值量化相关性,必须计算相关系数。
相关系数有几种类型,但最常见的是皮尔逊相关 r 。这是一种参数测试,仅当变量呈正态分布且变量之间的关系呈线性时才推荐使用。否则,应使用非参数 Kendall 和 Spearman 相关检验。
皮尔逊相关系数
皮尔逊相关( r )用于衡量两个变量之间线性关系的强度和方向。数学上,这可以通过将两个变量的协方差除以它们的标准偏差的乘积来实现。

Pearson’s correlation
r 的值在-1 和 1 之间。相关性为-1 表示完全负相关,而相关性为 1 表示完全正相关。相关性为 0 表示两个变量的移动之间没有关系。
下表展示了如何解释相关系数的大小(强度)。

credits : Parvez Ahammad
3 —显著性检验
使用相关系数量化两个变量之间的关系只能说明问题的一半,因为它只测量了样本中的关系强度。如果我们获得不同的样本,我们将获得不同的值,并因此可能得到不同的结论。
所以我们想得出关于群体的结论,而不仅仅是样本。为此,我们必须进行统计显著性测试。显著性检验告诉我们,我们在样本中观察到的情况在总体中是否是真实的,并且可以通过假设检验来进行。
假设检验是统计推断的核心部分。统计推断是根据人口样本对人口进行推断。
在开始假设检验之前,让我们用下面的公式总结一下。
提法
- 假设我们有一个 n 大小的样本数据,有两个变量 x 和 y。
- x 和 y 之间的样本相关系数(r) 是已知的(可以使用上面的公式计算)****
- x 和 y 之间的总体相关系数ρ(希腊字母“rho”)是未知(因为我们只有样本数据)
- 目标:我们想根据 r 推断出ρT5 的值****
逐步进行假设检验
假设检验会让我们推断总体相关系数 ρ 的值是接近 0 还是显著不同于 0。我们根据样本相关系数 r 和样本大小 n 来决定。
- ρ接近 0 :表示总体中 x 和 y 之间没有显著的线性相关性。
- ρ显著不同于 0 : 表示人群中 x 和 y 之间存在显著相关性。
如果测试显示总体相关系数 ρ接近于零,那么我们说没有足够的统计证据表明两个变量之间的相关性是显著的,即相关性是由于样本中的偶然巧合而发生的,并且它不存在于整个总体中。
所以,事不宜迟,让我们看看如何运行测试:
第一步: 假设规范
我们首先指定无效假设和替代假设:
备择假设总是我们试图证明的,在我们的例子中,我们试图证明在总体中 x 和 y 之间存在显著的相关性(即ρ≦0)。**
零假设是我们试图提供证据反对的假设,在我们的例子中,我们试图提供证据反对人口中 x 和 y 之间没有显著的线性相关性的假设(即ρ = 0)
- 零假设 Ho: ρ = 0
- 备选假设 Ha:ρ≦0
第二步:T 检验
T-test 也称为学生 T-test 是一种推断统计,它允许测试适用于总体的假设,或者简单地说,它允许使用样本数据将假设推广到整个总体。在我们的例子中,它将帮助我们发现 x 和 y 之间的样本相关性对于整个人口是否是可重复的。
我们使用以下公式计算 t 检验的值:

使用:
- n 是样本量
- r 是样本相关系数
t 值越大,相关性可重复的可能性越大。但是多大才算“够大”?这是下一步的工作
第三步: P 值
每个 t 值都有一个 p 值。p 值是零假设为真的概率。在我们的例子中,它表示样本数据中 x 和 y 之间的相关性偶然发生的概率。
p 值为 0.05 意味着您的样本中只有 5%的结果是偶然发生的。p 值为 0.01 意味着只有 1%的机会。因此,较低的 p 值是好的,但“足够低”是多低呢?。
在大多数研究中,我们认为统计显著性的阈值是 p 值为 0.05 或更低,它被称为显著性水平α。因此,我们可以将显著性水平设置为 0.05 (α =0.05),然后求出 P 值。
为了找到 p 值,我们需要两件东西,t 检验值(来自步骤 2)和自由度的数量,可以按如下公式计算 df = n-2(n 是样本的大小)。有了这两个值,我们可以通过下式计算 p 值:
- 使用软件
- 通过 t 型表查找
第四步:决定
最后,我们做出决定:
- 如果P-值小于显著性水平(α =0.05),我们拒绝零假设,支持备选项。我们得出结论,相关性是静态显著的。或者简单的说“我们得出结论,在α水平上,总体中 x 和 y 之间存在线性关系”**
- 如果P-值大于显著性水平(α =0.05),我们无法拒绝零假设。我们得出结论,相关性是而不是 静态显著。或者换句话说“我们得出结论,在总体中 x 和 y 之间没有显著的线性相关性”**
3 —相关性与回归

Credits: GraphPad
当研究数值变量之间的关系时,了解相关和回归之间的区别是很重要的。
相关性是一种统计度量,它量化了两个数值变量之间关系的方向和强度。另一方面,回归是一种统计技术,它根据自变量 X 的已知值,通过公式 Y = a + bX 来预测因变量 Y 的值。
参考资料:
- [mintab.com]:线性、非线性和单调关系
- [ 打开课本 ]:检验相关系数的显著性
- 【janda.org】:相关系数的显著性
推荐系统中图形神经网络的发展
介绍推荐系统中图神经网络的三个进展。
注:在整篇文章中,我将偏向于时尚背景下的推荐系统。
随着人工智能热潮在行业中兴起,以及大量公共用户数据可供我们使用,每个公司都希望通过向客户展示/推荐对他们来说似乎很有吸引力的东西来吸引他们,无论是产品还是服务。
从基本的协同过滤和购物篮分析开始,并继续使用矩阵分解的潜在因素模型,如奇异值分解和 PMF,现在已经扩展到更复杂的东西。
让我们分析一个特殊的情况。比方说,我们已经收集了一系列人群的现代流行时尚系列的数据,现在我们必须向他们推荐一套完整的时尚系列(上装、下装、手表和鞋子等)。)或一些单品来完成他们已经存在的时装系列。第一个想法是将时尚项目的一些潜在表示输入到双向 LSTM 中。但是经过进一步的思考,我们意识到 LSTMs 固有的顺序结构成了一个问题,因为不存在固定的项目顺序。套装中不同物品之间的复杂关系,如夹克和鞋子、鞋子和袜子之间的关系等。无法正确学习。
为了克服上述问题,第一个想法是以图形的形式形成某种表示,其中边可以表示被表示为节点的两个项目之间的关系。这就是 GNN(图形神经网络)的用武之地。让我们继续进行这种表示,并根据我们的目的对其进行改进
图形神经网络
GNN 在建模节点之间的依赖关系方面的能力不仅是推荐系统的真正突破,也是社交网络的突破。因此,让我们分析一下 21 世纪第一个十年出现的图形神经网络的基本结构。基本上每个节点都是一个循环单元,灰色的信封表示每个节点的特征。每种边类型都有一个神经网络表示。

在任意时间步,对于一个给定的节点,我们从邻近的循环单元得到消息,就像在一个线性 RNN 网络中一样,并把它们聚集起来。我们使用 Almeida-Pineda 算法继续学习,该算法通过运行传播到收敛,然后基于收敛的解决方案计算梯度来工作。这样我们就可以独立地得到每个节点的嵌入。然后我们把这些放在一起,连接起来,得到图形的表示。
很明显,一个节点对另一个节点的影响随着它们之间的距离呈指数衰减。所以我们可以说,它很难在一张图中长距离传播信息。因此,门控图神经网络(GGNN)来克服这个问题。
门控图形神经网络
顾名思义,主要的变化是我们使用 GRUs(门控递归单元),因此我们让递归在一定数量的时间步长内发生,同时通过时间反向传播,而不是使用经典的 Almeida-Pineda 算法。
节点注释首先被复制到隐藏状态的第一个组件中,其余的用零填充。图的不同节点之间的消息流通过具有取决于边类型和方向的参数的输入和输出边来处理。然后使用隐藏状态和注释,GRU 风格的更新发生。

但是仍然在 GGNN 中,节点通过以固定的方式在边上传递它们的状态信息来与其他节点交互,这导致了它难以对灵活和复杂的节点交互进行建模的限制。因此,节点式图形神经网络应运而生。
节点式图形神经网络
NGNN 的目标是用节点参数对边缘交互进行建模。NGNN 中的每个节点对应一类服装物品。
记住不同类之间的交互,初始化不同类之间的边。从 a 到 b 的边具有与在时尚集合中找到给定 b 的概率成比例的权重。对于每一项,我们都找到了特征,它们被用来更新相应类节点的初始状态。
为了克服 GGNN 的问题,我们维护两个不同的权重矩阵,分别对应于每个节点的输入和输出,不像 GGNN 中所有边都有一个公共的权重矩阵。该输入输出权重用于寻找图中任何边的变换函数。除此之外,传播与 GGNN 相同。
在 T 个传播步骤之后,我们可以获得节点的最终状态,这也是最终的节点嵌入。
在此之上,添加了一个注意机制,以计算出集合中不同项目的兼容性。例如,一双 袜子与一套包含人字拖的时装不兼容。由于一个节点从其他节点接收状态信息,这种注意机制很容易被合并。

A simple graph. The areas of circles and the widths of the links are proportional to the number of fashion items in the corresponding categories and the co-occurrence frequency between categories.
我参考的一些令人惊叹的论文和视频—
机器翻译的发展

1949 年,洛克菲勒基金会的研究员沃伦·韦弗提出了一套基于机器翻译的建议,这些建议是基于信息论和第二次世界大战期间密码破译的成功。
几年后,机器翻译研究在美国许多大学开始认真进行。正如哈钦斯报告所描述的,1954 年 1 月 7 日,乔治敦-IBM 实验开始,IBM 701 计算机有史以来第一次自动将 60 个俄语句子翻译成英语。这是机器翻译系统的首次公开演示,引起了媒体和公众的极大兴趣。
ALPAC 报告指出,机器无法与人工翻译质量竞争,并建议停止对机器翻译的资助。但是几名研究人员继续研究如何使用机器来创建自动化语言翻译。这些研究大多集中在有限的语言对,有限的输入和基于规则的引擎。到 20 世纪 80 年代,大量依赖大型机技术的机器翻译引擎投入使用,如 SYSTRAN、Logos 等。

统计机器翻译
布朗等人。al (1990) 提出在机器翻译中使用统计方法。他们提出了一种翻译过程,其中将源文本划分为一组固定位置,然后使用词汇表选择固定位置集来创建序列,最后重新排列目标固定位置中的单词以形成目标句子。他们成功地开发了自动词汇表创建和目标单词序列排列的统计技术,但未能提供翻译句子的示例。
布朗等人。al (1993) 描述了翻译过程的五个统计模型,并给出了在给定一组双语句子对的情况下估计这些模型参数的算法。这些模型后来被认为是 IBM 校准模型。他们定义了一对双语句子之间的逐字对齐的概念。他们的算法为任何给定的句子对的每一个逐字对齐分配了一个概率。虽然他们的研究仅限于较小的英语和法语翻译,但这对句子中的单词间关系的对齐是一个相当大的改进。

沃格尔等人。al (1996) 描述了一种使用一阶隐马尔可夫模型的统计机器翻译中的单词对齐的新模型,因为它解决了语音识别的时间对齐问题。该模型背后的主要思想是使逐词对齐概率取决于对齐位置而不是绝对位置。基于 HMM 的模型产生与混合对齐模型相当的翻译概率,并且在基于 HMM 的模型中位置对齐更加平滑。
Och et。al (1999) 描述了一种确定用于统计机器翻译的双语词类的方法。他们开发了一种基于最大似然法的优化标准,并进一步描述了一种聚类算法。他们的实验结果表明,双语词类的使用显著改善了统计机器翻译。

基于句法的统计翻译模型是由 Yamada 等人提出的。艾尔(2001) 。他们的模型通过在每个节点应用随机操作,将源语言解析树转换成目标语言字符串。这些操作捕捉到了语言上的差异,如词序和大小写标记。该模型产生的单词排列比 IBM Model 5 产生的单词排列更好。
Koehn 等人提出了一种新的基于短语的翻译模型和解码算法。al(2003) 这使得他们能够评估和比较几种先前提出的基于短语的翻译模型。他们设计了一个统一的框架来比较不同的其他翻译模型。科恩等人提出的模型。al(2003)基于噪声信道模型 Brown 等人。al(1993)和他们使用贝叶斯规则来重新表述将法语中的外国句子翻译成英语的翻译概率。
蒋等人。al(2005) 提出了一个基于短语的机器翻译模型,该模型使用分层短语——包含子短语的短语。他们建议使用由单词和子短语组成的分级短语来解决这个问题。他们的模型基于加权同步上下文无关文法。该模型使用分层短语构建部分翻译,然后在标准的基于短语的模型中连续组合它们。他们没有使用传统的噪声信道方法,而是使用了更通用的对数线性模型。
神经机器翻译
2013 年,Kalchbrenner&blun som(2013)提出了一种新的用于机器翻译的端到端编解码器结构。他们引入了一类称为循环连续翻译模型的概率连续翻译模型,该模型完全基于单词、短语和句子的连续表示,不依赖于对齐或短语翻译单元。
Sutskever et al.(2014) 提出了使用深度神经网络依次进行机器翻译的序列学习。他们的方法使用多层长短期记忆(LSTM)将输入序列映射到固定维度的向量,然后使用另一个深度 LSTM 从向量中解码目标序列。他们的结果表明,具有大深度 LSTM 和有限词汇的神经机器翻译系统可以胜过标准的基于 SMT 的系统。

秋等人。al (2014) 提出了一种新的神经网络模型,采用两个递归神经网络(RNN)作为编码器和解码器。一个 RNN 将符号序列编码成固定长度的向量表示,而另一个将该表示解码成另一个符号序列。他们的结果表明,RNN 编码器-解码器能够捕捉短语的语义和句法结构。
巴赫达瑙等人。al (2014) 提出了一种方法,该方法允许模型自动软搜索源句子中与预测目标单词相关的部分,而不必将这些部分显式地形成为硬段。通过这种方法,他们在英语到法语的翻译任务中获得了与现有的最先进的基于短语的系统相当的翻译性能。
Luong 等人。al (2015) 提出了两种有效的注意机制,一种是始终关注所有源词的全局方法,另一种是每次只关注源词子集的局部方法。他们使用不同注意力架构的集成模型在 WMT 的 15 英德翻译任务中建立了一个新的最先进的结果,25.9 BLEU 点。
Jozefowicz 等人。al (2016) 在不同规模的语料库上对不同的神经网络模型进行了实验,他们的实验表明,RNNs 可以在大量数据上进行训练,并且它们优于包括精心调整的 N-grams 在内的竞争模型。他们的实验表明,大型正则化 LSTM LM(具有投影图层,并使用具有重要性采样的真实 Softmax 的近似值进行训练)的性能比 N 元模型好得多。
在第一届机器翻译会议(WMT'16)的研究结果中,参与 WMT 评估的神经机器翻译系统比基于短语的统计机器翻译系统高出多达 3 BLEU 评分( Bojar 等人。al 2016 。
菲利普·科恩写道,“神经机器翻译(NMT)是一种令人兴奋和充满希望的机器翻译新方法。然而,尽管这项技术很有前途,但我们仍有一段路要走,才能在所有用例中与基于规则的机器翻译(RBMT)和统计机器翻译(SMT)相媲美。一些业内人士最近声称,我们所有人都即将达到接近人类的质量,这可能有点过于简单化了。”。他认为,即使神经机器翻译系统产生了高质量的结果,也很难在工业规模上实现这种系统,因为它需要在处理翻译的基础设施上进行巨额投资。

谷歌的神经机器翻译
吴等(2016) 提出了一个遵循通用序列间学习框架的模型 Sutskever 等(2014) 注意 Bahdanau 等。铝(2014) 。该模型由三部分组成:编码网络、解码网络和注意网络。编码器网络将源句子转换成向量列表,每个输入符号一个向量。当这个向量列表被传递到解码器网络时,它一次产生一个符号,直到遇到特殊的句尾符号(EOS)。编码器和解码器通过注意模块连接,注意模块允许解码器在解码过程中关注源句子的不同区域。

吴等(2016) 架构描述如下。左边是编码器网络,右边是解码器网络,中间是注意力模块。底部的编码器层是双向的:粉色节点从左到右收集信息,而绿色节点从右到左收集信息。编码器的其他层是单向的。剩余连接从编码器和解码器中倒数第三层开始。该模型被划分为多个 GPU 以加速训练。在他们的设置中,有 8 个编码器 LSTM 层(1 个双向层和 7 个单向层)和 8 个解码器层。通过这种设置,一个模型副本被分成 8 个部分,并放置在通常属于一台主机的 8 个不同的 GPU 上。在训练期间,底部双向编码器层首先并行计算。一旦两者都完成,单向编码器层开始计算,每个都在单独的 GPU 上。为了在运行解码器层期间保持尽可能多的并行性,他们仅使用底层解码器层输出来获得循环注意上下文,该上下文被直接发送到所有剩余的解码器层。softmax 层也被分区并放置在多个 GPU 上。根据输出词汇的大小,他们要么让它们在与编码器和解码器网络相同的 GPU 上运行,要么让它们在一组单独的专用 GPU 上运行。

他们的解码器网络实现为 RNN 网络和 softmax 层的合并。解码器 RNN 网络为要预测的下一个符号创建隐藏状态,然后通过 softmax 层生成候选输出符号的概率分布。在他们的实验中,作者发现神经机器翻译系统必须具有用于编码器和解码器网络的深度 rnn,以实现良好的准确性,它们需要捕捉源语言和目标语言中的微小不规则性。他们在研究中实施的注意力模型类似于 Bahdanau 等人。铝(2014) 。

吴等(2016) 承认了这样一个事实,即简单地增加更多的层会使网络更慢且难以训练,可能是由于爆炸和消失梯度问题。他们在堆栈中的 LSTM 层之间引入了剩余连接。剩余连接极大地改善了反向传递中的梯度流,这允许他们用 8 个 LSTM 层来训练他们的编码器和解码器网络。他们将双向连接用于底部编码器层,同时保持其他层单向连接,以在计算过程中实现最大的并行化。
Wu et al (2016) 使用两个公开可用的语料库 14 的英语到法语和英语到德语作为他们的神经机器翻译系统的基准。除了这些公开可用的语料库,他们还使用了谷歌的翻译产品语料库,对于给定的语言对,这个语料库比 WMT 语料库大得多。WMT En- > Fr 包含 36M 个句子对,而 En- > De 包含 5M 个句子对。他们通过与标准 BLEU 评分标准一起进行并排的人类评估来评估他们的模型。并列评分从 0 到 6 不等,0 分表示“完全无意义的翻译”,6 分表示“完美的翻译:译文的意思与原文完全一致,语法正确”。他们使用在 TensorFlow 中实现的系统来训练模型。他们在实验中使用了基于单词、基于字符、基于混合字符和几种不同词汇量的单词模型。表格总结了他们在 WMT En - > Fr 数据集上取得的结果。他们的最佳型号 WPM-32K 获得了 38.95 的 BLEU 评分。WMT En - > De 比 En- > Fr 要困难得多,这是因为训练数据的规模更小,并且德语是一种形态更丰富的语言,需要词汇作为单词模型。他们最好的型号 WPM-32K 取得了 24.61 的 BLEU 分数。

他们进一步使用 RL 训练来微调正常最大似然训练后的句子 BLEU 分数。他们集成了 8 个 RL-refined 模型,并在 WMT En->Fr 数据集上获得了 41.6 BLEU 点的最先进结果。他们在 WMT En->De 数据集上获得了 26.30 BLEU 点的最新结果。这四个翻译是:1)从 statmt 网站下载的最佳基于短语的翻译,2)8ML 训练的模型的集合,3)8ML 训练然后 RL 精炼的模型的集合,以及 4)直接从测试数据获得的参考人类翻译。结果显示在表中。实验结果清楚地表明,尽管 RL 细化可以获得更好的 BLEU 评分,但它几乎没有改善人们对翻译质量的印象。

谷歌的 NMT 是机器翻译的最新水平。
如需 www.ibidemgroup.comT2 的西班牙语翻译或西班牙语翻译,请点击此处。
数据时代传统统计检验的演变

基于研究/学术起源的显著性测试与基于数据科学和分析的更动态应用角色的显著性测试之间的差异
让我们从统计学中显著性检验的简单定义开始。
统计显著性测试表明所观察到的感兴趣变量的差异(不同样本/组之间)是否表明了一些真正的差异(通常在应用了一种处理方法之后),或者这些差异是否仅仅是由于偶然因素/采样误差。
定义显著性检验的方法还有很多。所有的人或多或少都在说同样的话。
注意: 这不是掌握显著性检验的教程。外面有很多这样的人。这是在更多基于研究/学术领域的显著性测试中使用的不同方法的概述,因为它仍然在大学课程中教授(至少在我的经验中),而不是在数据科学和分析的更多基于应用的领域中的演变。希望这篇文章也能表明,不完全熟悉前者并不影响一个人与后者合作的能力。
序言
假设我有一个改变的想法。这种改变可能是一种向高中生教授数学的新方法,我相信这将有助于他们在 AP 考试中取得更好的成绩。这种变化可能会使我的电子商务网站的登录页面看起来略有不同,我相信这会导致访问者在我的网站上花更多的时间。不管是什么想法,我需要一种方法来测试它是否会引发我认为会发生的变化。
继续以电子商务网站为例,我随机挑选访问者并将他们分成两组,A 组和 B 组。我向 A 组(这是我的对照组)的访问者展示旧的登录页面,向 B 组(这是我的治疗组)的访问者展示据称是新的和改进的登录页面。然后我测量每组访问者在我的网站上花费的平均时间,你瞧!B 组访问者在我的网站上停留的平均时间高于 A 组访问者!
现在,我需要做的就是排除这种由于偶然发生的群体间花费在我的网站上的平均时间的差异的可能性。可能我的新页面与这种差异没有任何关系,我只是运气好,不管登陆页面看起来怎么样,我都分配了平均会在我的网站上花更多时间的访问者。
输入显著性测试
显著性检定
在我们讨论进行显著性测试的不同方法之前,重要的是要记住我们感兴趣的变量不是每个访问者在我们网站上花费的时间,甚至不是每组访问者在我们网站上花费的平均时间。这是 A 组和 b 组的访问者在我们网站上停留的平均时间的差异,这是一个叫做我们的测试统计的小东西。

Our Test Statistic
现在我们已经准备好了,来看看我们两组之间的平均时间差异是否是偶然发生的。为此,我们需要进行一个显著性测试,这需要经历以下一般步骤
- 宣布零假设:这只是我们假设自己错了的一种奇特说法。在我们的例子中,这意味着假设我们的登陆页面对访问者在我们网站上停留的时间没有影响。我们的差异只是由于一个幸运的样本,而 A 组和 B 组访问者在我们网站上花费的平均时间之间的真正差异应该是 0。
- 模拟零假设下的数据收集:这里我们需要创建一种假设现实,其中零假设为真。在这个现实中,A 组和 b 组的访客在平均时间上没有区别。我们需要查看我们在这个现实中收集的数据,这就是问题所在—
这是这个假设现实的创造,其中基于研究/学术的方法与你可能在数据科学和分析应用中看到的更注重计算的方法分道扬镳。 - 计算 P 值:最后,我们计算当我们收集数据时,我们最初观察到的一个测试统计数据出现极端情况的概率。我们在假设的现实中这样做,其中零假设为真,以计算 me 偶然看到我们的结果的频率。这是我们的 p 值。
传统方法
t 检验是一种非常常见的方法,用于进行涉及均值差异的显著性检验。t 测试已经存在很长时间了,远在计算机成为主流之前。因此,在缺乏我们习以为常的便捷计算能力的情况下,我们如何模拟零假设下的数据收集呢?很简单,我们使用一个定理,并基于它做一个假设。
输入中心极限定理
特别是,传统方法使用 C 中心极限定理的含义。用最通俗的术语来说,中心极限定理表明
如果我 从一个总体中反复抽取样本并取每个样本的平均值,那么给定足够的样本,所有那些 意味着 将遵循一个近似的 正态分布 而不管总体本身遵循的分布。

Visual Representation of The Central Limit Theorem
统计理论还指出,任何正态分布的线性组合也是正态分布的。使用这些信息,我们可以假设如果(我不会真的去做)我会一遍又一遍地重复进行我的实验,并从两组访问者那里收集我的测试统计数据,那么我所有的测试统计数据将会遵循一个近似正态分布。不需要很大的计算能力,因为我实际上没有一遍又一遍地做实验。我在假设如果我做了,我会看到什么样的分布。现在有了这个假设,我可以继续从我的测试统计量中计算我的标准化** t 统计量,以获得零假设下我的观察值的 t 得分。**
注意: 现在我确信 你们中的一些人可能会奇怪为什么我们不计算 z 统计量来获得 z 得分,因为这是我们标准化正态分布时得到的结果。其原因是,为了获得标准正态分布和 z 值,我们需要总体标准差,但我们也不知道。我们只知道我们收集的 A 组和 B 组两个样本的标准差。因此,在没有总体标准偏差的情况下,为了处理样本标准偏差,我们将使用正态分布的近似值,称为具有不同自由度的 t 分布,因此也就是 t 得分。有趣的事实是,我们的自由度越高(取决于我们的样本大小),我们就越接近标准的正态分布(当然是渐近分布)。
下面是计算 t 统计量的公式。这个小公式是在零假设下得出的,即每个样本的真实总体均值没有差异(在我们的例子中,这意味着每组访问者在我们网站上花费的平均时间是相同的)。也就是说,它们的差值为 0,这正是我们试图得到 t 统计量的假设(我们的假设现实还记得吗!)

T-statistic under the null hypothesis
我们只需插入现有的值,然后弹出我们的 t 统计量。X1 是我的治疗组的样本平均值,X2 是我的对照组的样本平均值,S 是样本标准偏差,n 是样本大小。
一旦我们有了 t 统计量,我们所要做的就是用适当的自由度查看它在 t 分布曲线上的位置,并计算看到如此极端结果的概率,这将是我们的 p 值。
自由度的计算只需使用我们的样本大小,方法如下。

Degrees of Freedom Calculation
让我们假设,对于我们的电子商务网站,我们的 t 统计量约为 2.39,基于我们的样本大小,我们的自由度等于 60。从这里开始,我甚至不需要计算器来计算我的 p 值。我可以使用一个简单的 t 分布查找表。

Look up table for the t-distribution
根据该表,在下面曲线的右尾下的面积,是在零假设下,看到均值差异至少与我们在实验中观察到的差异一样极端的概率,偶然约为 1%。换句话说,我们的 p 值是 0.01

Area under the curve for a one-sided t-test
现在,我们可以使用这个结果来拒绝零假设,并得出结论,我们的新页面确实有助于增加每个访问者在我们网站上花费的时间,或者我们可以得出结论,我们看到我们的原始结果是偶然的。通常在大多数研究/学术领域,你会看到 p 值低于 5%意味着我们可以拒绝零假设,这就是我们的例子。
这里有一个小的统计迷因去它,给你。

计算/当代方法
如果在宣布零假设后,我们有办法在零假设下模拟我们实验的结果很多次(记住,是为了创造我们的假设现实),这样我们就不必依赖于定理、假设和标准正态分布的近似值来告诉我们,如果我们真的重复实验很多次,我们会看到什么。
输入计算机
幸运的是,与过去不同,我们有计算能力在几秒钟内对实验结果进行数十万甚至数百万次的重新采样。手工做起来不太容易甚至不可行的事情,尤其是在计算机出现之前的时代。
这意味着,使用某些有效的重采样技术,我们可以模拟我们的假设现实,而不依赖于任何定理、正态性假设,也不必考虑我们对总体标准差的了解。
回到我们的两个组的例子,A 组(对照组)和 B 组(治疗组),我们可以使用某些简单的重采样技术来模拟零假设下的数据收集。
假设我们有两组数组。A 组是一个数组,其中包含每个被展示旧登录页面的访问者在我们的网站上花费的时间。类似地,B 组是一个数组,显示了每个被展示了新登录页面的访问者在我们网站上花费的时间。假设这两个数组的大小都是 31。我们还可以说,当我们进行实验时,我们发现 B 组的访问者在我们的网站上花费的平均时间比 a 组的访问者多大约 30 秒。为了在零假设下刺激数据收集,我们需要创建两个数组的平均值没有差异的条件。下面介绍两种重采样技术如何实现这一点。
排列重采样
- 将两个数组连接成一个大数组。对于我们来说,这应该是 62,因为我们的两个数组都是 31。
- 打乱整个数组,所以现在每个组的观察值随机分布在整个数组中,而不是从中间分开。
- 从中间任意分割数组,将数组的前 31 个索引中结束的观察值分配给 B 组,其余的分配给 a 组。
- 从新组 b 的平均值中减去这个新组 A 的平均值。
- 这将给我们一个排列测试统计。
这是一个排列重采样的可视化展示—

Assume Observations 1,2,3,4 originally belonged to Group A and observations 5,6,7 originally belonged to Group B
通过混合两种样本,然后将它们混在一起,我们消除了它们分布的差异。我们创造了我们的假设现实,他们来自同一个群体,没有使用任何定理或衍生的标准化统计。
我们重复上述步骤数十万次,并计算数十万个排列测试统计。然后,我们简单地看一下,在我们计算的总排列测试统计数据中,我们计算的排列测试统计数据的比例至少与我们在 30 秒内的原始差异一样高。瞧啊。这是我们的 p 值。不需要近似的正态分布或查找表。
自举重采样
Bootstrap 重采样就是通过替换从分布中进行重采样的过程。这意味着我们可能会对一个值进行多次重采样,对多个值进行多次重采样,对没有值的情况进行多次重采样,甚至可能会有一些值从未出现的样本。一切都很好。这是一个自举重采样的可视化展示

3 different bootstrap resamples from the same sample
在我们开始进行 bootstrap 重采样之前,我们仍然需要为我们的零假设创造条件,以便在。我们可以通过以下步骤做到这一点—
- 考虑具有 B 组(治疗组)观察值的阵列
- 从数组中的每个元素中减去 B 组的平均值
- 将 A 组(对照组)的平均值加到数组中的每个元素上。这是我们的新数组,有一个移动的平均值。
- 从此数组中取出相同大小的引导程序重新采样。
- 计算该引导重采样的平均值与 A 组(对照组)观察值的原始阵列平均值的差值
- 这将给我们一个自举测试统计
在这里,我们简单地将 B 组在我们的网站上花费的平均时间更长的观察结果转移到 a 组,再次创建我们的现实,其中这两个数组具有相同的平均值,以收集数据。然后,我们从这个移位的数组中取出几十万个自举重采样,以计算几十万个自举测试统计,其余的与我们对置换重采样所做的相同。我们简单地计算我们收集的总的 bootstrap 统计数据中 bootstrap 统计数据的比例,该比例至少与我们获得 p 值的 30 秒原始差值一样高。同样,不需要近似的正态分布或查找表。
摘要

结论
有大量的资源可以帮助你掌握显著性测试及其相关概念。这也可能意味着,当你在不同的方法、教程和指南中导航,以决定你想专注于哪一个时,有时很容易感到困惑。希望这篇文章能让你对显著性测试的本质有一个好的认识,以及在两个领域实现其目标的不同方式。在显著性检验中有许多相关的重要概念,如 I 型误差、II 型误差、效应大小、功效..等等,我没有涉及,但你会发现,无论你决定把重点放在资源和应用,现在你知道区别。快乐学习。
如果我遗漏了什么,或者有什么不准确的地方,或者如果你有任何反馈,请在评论中告诉我。我将非常感激。谢谢你。
自然语言处理中文本表示的演变
在自然语言处理的背景下,文本的表达是如何发展的,每种方法的优点是什么。

Photo by Conor Luddy on Unsplash
信息可以用多种方式表示,同时保持相同的含义。我们可以通过多种语言传递信息,我们可以用数学表达式或图画来表达一些东西。我们选择更适合传达我们想要传递的信息的表征。在自然语言处理中,我们必须将文本数据转换成机器可以处理的东西。数字!有许多方法可以实现这种转换。一个简单的方法是给文本中的每个单词一个特定的 id。但是,并不是所有的表示都是相同的,有些表示比其他表示更复杂,携带的信息更多,这将影响 NLP 模型的性能。
凭借当今的计算能力,我们有能力构建能够执行非常复杂的任务和处理大量数据的 ML 模型。我们想给我们的模型提供尽可能多的信息。
一键编码

Source :(Marco Bonzanini, 2017)
最简单的表示形式之一是一键编码。它们将一个单词转换成一个 N 维的向量,向量中充满了 0 和一个 1 的单个(热)位置。
向量是正在使用的字典的大小,每个位置代表一个单词,带有 1 的位置代表单词向量所映射的单词。这个概念很简单,并且在 NLP 的早期阶段使用过。它很便宜,只需要很少的计算能力就可以将文本数据转换成一个热编码数据,并且很容易实现。
但是,它没有携带任何关于数据的额外信息,是一种极其臃肿的表示。这种表示只是一大堆识别单词的 1 和 0,NLP 模型需要从零开始学习每个向量的意思。
一袋单词

单词包是一种简化的表示,它将文本表示为一个多重集(包)。文本被转换成字典大小的向量,每个索引代表一个单词,索引处的值是该单词在文本中出现的次数。表象背后的直觉是,词语本身携带着理解所需要的信息。
但是,并非每个句子都是如此。句子中单词的顺序可能会改变它的意思。单词包不考虑句子的顺序,这是它不如单词嵌入强大的原因之一。它也没有给出每个单词意味着什么的任何信息,模型被给予很少的先验知识。
单词嵌入

单词嵌入是单词到向量的映射。
一个单词被转换成一个 N 维的向量,其中每一维都有一个潜在的含义。单词与这些潜在含义的关系将定义维度的值。
二维的单词嵌入可以如下映射单词:
男人→ [0.85,0.05 ]
狗→ [ 0.9,0.1 ]
苹果→ [ 0.12,0.9 ]
香蕉→ [0.06,0.95 ]
猕猴桃→ [ 0.48,0.56 ]
在这个例子中,我们注意到第一维对于狗和人有一个高值,而第二维对于苹果和香蕉有一个高值。这可能意味着第一维与动物有关,第二维与水果有关。还要注意 kiwi 在两个维度上都有一个中间值。
二维空间太小了,不足以表达单词的意思,除非我们想要一种嵌入的方式来提供不同于动物的水果。嵌入通常有 50、300、600 或 900 个维度。
嵌入的魔力。
嵌入本身是非常令人惊奇的,可以做一些可爱的把戏。
我们可以想象,在嵌入中,“男人”和“女人”这两个词的表征之间的差异是一个解释性别差异的值。“国王”和“王后”也是如此。因此,我们知道:

因此,如果我们有“男人”、“女人”和“男孩”的向量,我们可以预期
如何训练一个单词嵌入?
单词嵌入通常是通过用大语料库在无监督的任务中训练模型来产生的。比如试图预测句子中缺失的单词。
训练嵌入在计算上是昂贵的。对于大多数问题,下载可用的经过训练的嵌入是最好的选择。如果你的语料库过于具体(例如。有很多行话)你可能想训练自己的嵌入。
正如我们在单词 kiwi 的例子中看到的,嵌入不知道如何处理有多重含义的单词。嵌入会将含义平均到单个向量中,在数据集上出现频率较高的含义会获得较高的权重。
单词嵌入也达不到它以前从未见过的单词,如新词、拼写错误和词汇以外的单词。
扩展嵌入
为了补救单词嵌入的一些问题,目前大多数流行的模型通过分成“特征”来标记单词,并使用这些特征而不是单词本身来训练嵌入。
记号赋予器可以将单词“google”分成“goog”和“le ”,嵌入将学习这些特征。它可能会对过去分词中的动词做类似的事情,例如:' watched' → 'watch ',' ed '。现在,假设单词“googled”不在嵌入的训练集中。记号赋予器可以将单词分割成特征:“goog”、“le”、“ed”,所有这些特征嵌入之前都见过,并且每个特征都有适当的特征向量。因此,嵌入即使以前没有见过这样的单词,它仍然可以给它一个很好的表示。
这种直觉可以应用于拼写错误、新词和词外词汇,并且极大地提高了词嵌入的性能。
结论
复杂的单词表示是给 NLP 模型更多先验知识的一种廉价方式,对于数据稀缺且难以收集的任务非常有用。由于这个原因,我们看到了一系列越来越复杂的单词表示法。
单词嵌入非常强大,在 NLP 中已经无处不在。我们探索了单词嵌入和更原始的单词表示背后的一些直觉,我们看到了为什么一些可能比另一些更有利。
人工智能的进化方法:过去、现在和未来
达尔文主义能给 AI 带来革命吗?

Open environments and competition among species are two driving forces of Darwinian evolution that are largely absent in recent works on evolutionary approaches toward AI models. Within a given generation, faster impalas and faster cheetahs are more likely to survive (and reproduce) than their slower counterparts — leading to the evolution of faster and faster impalas and cheetahs over time. Can these and other principles of genetics and natural selection guide us towards major advances in AI?
目录
- 简介
- 遗传和自然选择
- 进化计算
- — 进化策略
- — 采用直接编码的遗传算法
- — 采用间接编码的遗传算法
- — 开放式(这才是真正有趣的地方!)
- — 还缺什么?
- 结论
- 参考文献
介绍
自大约 2012 年[1]以来,人工智能的爆炸式增长几乎完全由反向传播(backprop)训练的神经网络(深度学习)模型驱动。这包括图像分类、自动语音识别、语言翻译、机器人和可以玩单人或多人游戏的自主代理的模型。
然而,正如在生物学中所观察到的,越来越多的模型是使用基于进化方面的方法构建的。这种方法出现在深度学习时代之前,但直到最近才被扩大到可以与反向训练的深度学习模型相竞争的程度。
在这篇博文中,我们讨论了其中的一些进化方法,将它们与生物进化和有机体发展进行了比较和对比,并推测它们如何最终带来比传统深度学习模型具有更大(或更多)能力和能效的人工智能模型。
遗传学和自然选择
简而言之,达尔文的理论认为进化是由被自然选择放大的特征的微小变化驱动的。与具有有害特征的生物相比,具有有益特征的生物更有可能繁殖,从而将这些特征传递给后代。
达尔文不知道特征是如何从父母传递给后代的(这让他的见解更加令人印象深刻),但我们现在知道生物体的基因型及其发育环境决定了其表型(身体和行为特征)。一般来说,新的基因型通过父母 DNA 的随机突变、来自多个父母的基因混合(有性生殖)或两者而出现在后代中。
进化计算
科学家对生物进化的理解产生了受进化启发的计算优化模型。其中最简单的是进化策略。在遗传算法中发现了更大和更多样的建模复杂性。在这两种情况下,目标都是优化一个适应度函数,该函数旨在测量人工有机体在某些特定任务上的表现。另一种方法是放弃适应度函数,转而利用一个或多个物种的多个智能体的丰富、开放的环境,其中智能体只为生存和繁殖而竞争。
进化策略
进化策略是一类优化算法,其中,在每次迭代(世代)中,参数向量(基因型)的群体被扰动(突变),并且它们的适应函数值被评估[2,3]。然后,最高得分的参数向量被重新组合以形成下一代的种群,并且该过程被重复,直到目标被完全优化。在协方差矩阵自适应进化策略(CMA-ES)中,模型参数的分布由协方差矩阵表示。在每一代中,个体代理的模型参数从分布中提取。在确定了哪些代理具有最高的适合度分数之后,基于那些最佳代理的参数值来更新协方差矩阵。想要一个很棒的二维可视化,请看这篇很棒的 Otoro 博客文章。
尽管这种方法很简单,但有时它可以与用强化学习方法训练的相对现代的大规模深度学习模型竞争,如 OpenAI [4]所示,并在这篇帖子中描述。进化策略方法相对于强化学习方法具有一些好的特性,因为进化策略易于实现并跨核心/CPU 扩展,模型训练快速,并且该方法不利用梯度(当使用基于梯度的方法时,对具有离散输出的任务的训练是困难的)。

Above are a few videos of 3D humanoid walkers trained with evolution strategies by OpenAI (videos taken from their blog post). Results have quite a bit of variety, based on which local minimum the optimization ends up converging into. As will be noted later in this post, however, none of movements look very natural in contrast to those of biological animals, some of which begin fluid walking and running within minutes or hours after birth.
直接编码的遗传算法
虽然术语遗传算法可能被不同的研究者和从业者以不同的方式使用,但是我们在这里以非常一般的方式使用它。在每一代中,算法:(1)基于适应度函数从大小为 P (N < P)的群体中选择前 N 个代理,(2)通过从这些顶级代理单独(无性)或成对(有性)繁殖产生新一代代理,以及(3)在繁殖期间,后代基因通过突变、交叉(混合两个伙伴父母的基因)或两者而变化。
进化策略和遗传算法之间的另一个区别是,在进化策略中,群体的基因组由概率分布来表示。典型地,这意味着在给定世代中群体的所有成员将在参数(基因组)空间内的单个聚类中被发现。相比之下,在遗传算法下,对种群没有这样的约束。然而,在实践中,除非环境或额外的算法组件促进种群多样性(在这种情况下,可能出现多个“物种”),否则单个种群集群通常会进化。
在遗传算法的许多应用中,基因型到表现型是直接的,这意味着每个基因直接编码代理模型的一个参数。事实上,基因及其表型表达可能是相同的,例如,代表深度学习模型中的权重或偏差项的数值。如上一节所述,使用进化策略训练的模型使用直接编码。
相比之下,生物学是基于间接编码的。例如,由 DNA 组成的基因并不直接编码大脑神经元之间突触的强度。相反,它们为蛋白质编码,这些蛋白质共同发挥作用,实现大脑(及其突触)的发展,并根据有机体的经验学习突触增强或减弱的规则。我们将在下一节回到人工智能的间接编码的例子。
2017 年,Ken Stanley 和 Jeff Clune——进化神经网络参数的“神经进化”方法的长期倡导者——展示了直接编码的遗传算法在众多 Atari 游戏中表现良好的潜力,包括难以通过强化学习(Q-learning 或策略梯度)解决的游戏[5]。他们在优步人工智能实验室的团队使用了一种简单的遗传算法,通过向父网络的参数添加高斯噪声,将基因突变引入无性繁殖的后代。

In addition to evolving agents to play Atari games, the team from Uber AI Labs evolved agents to complete a relatively simple maze, albeit one with two different “traps.” Agents trained with an evolution strategy (ES) consistently get stuck by Trap 1 and never evolve further. Agents trained with a genetic algorithm (GA) do better, but get stuck in Trap 2. When agents are chosen for reproduction based not only on their fitness score but also their display of novel behaviors (GA-NS), the species ultimately evolves the ability to complete the maze. Agents trained with two different reinforcement learning methods (A2C and DQN) do not learn to complete the maze.
优步团队还额外检验了奖励表现出新奇行为的代理人(允许他们繁殖)的效果。他们证明,尽管这样的代理人通常在传统的适应度函数上得分很低,但随着时间的推移(几代人),这种方法使整个人群受益。为行为新颖性赋值的遗传算法是一种质量多样性算法【6】,这种算法是一个活跃的研究领域。这种观点认为,在整个种群中维持一个多样化的行为库提供了一个新的、更复杂的行为库,这些行为可能会产生有益于后代有机体的新的、更复杂的行为,尽管复杂行为所基于的更简单的行为的价值很小甚至是负面的。【请注意,这在很大程度上是一种启发式方法,因为尚不清楚什么样的自然力会促进“无价值”行为表型的跨代保留。 ]
另外,优步团队使用了一种创造性的有效方法来保留数千个大型代理的基因型(每个代理有数百万个神经网络参数)。也就是说,他们保存了一份记录,记录了用于创建最初一代代理的随机数生成器种子,以及用于创建每组突变的种子。因此,可以从种子向量中重新创建单个代理,并且可以这样存储代理,而不是直接存储代理的模型参数。
间接编码的遗传算法
一般来说,利用间接编码模型的遗传算法没有直接编码模型成功(在现代大规模问题上)。尽管如此,间接编码模型可能被证明是非常强大的,因为它们有可能对复杂的、精密的模型进行紧凑的编码。例如,虽然一个生物体中的一组基因可能是固定的,但基因的蛋白质产物可以以组合的方式跨越时间和空间(在生物体中)相互作用,从而允许几乎无限的可能性。下面我们着重介绍两个间接编码的例子。
超整齐
到目前为止讨论的进化计算方法有一个固定大小的基因组。即固定架构的神经网络。基因定义了这种固定结构的参数,但没有定义该结构的任何方面,因此遗传算法无法增长、收缩或修改该结构。2002 年,Stanley 和 Miikkulainen 引入了扩充拓扑的神经进化(NEAT) [7]。NEAT 定义了基因和神经网络内的连接之间的映射,并且可以适应定义新连接或节点的新基因的进化添加。

NEAT defines rules that map genes to a network architecture in addition to values of network weight and bias terms. Under a genetic algorithm, the network can grow by adding connections and nodes.
然而,NEAT 是一个直接编码模型,每个基因定义两个节点之间的连接权重。虽然一些基因可以呈现“禁用”状态,但这可以被视为编码零权重值。这将我们带到超净。
在 HyperNEAT [8]下,NEAT 训练的网络的输出定义了二级网络的权重。该辅助网络是用于执行所需任务的网络。在最简单的版本中,该次级“任务”网络具有排列在二维空间中的节点,使得每个节点可以通过其(x,y)坐标来识别。第一个网络被称为复合模式生成网络(CPPN),它采用四个输入来定义任务网络中两个节点( i 和 j )的位置:(x i ,y i )和(x j ,y j )。CPPN 的输出是连接这两个节点的权重值。因此,NEAT 可以用来发展一个指导任务网络“开发”的 CPPN。任务网络,而不是 CPPN,由适应度函数来评估。
使用超净方法,相对较小的 CPPN 网络可以定义任意规模和密度的复杂任务网络。作为 CPPNs 可进化性的证明,模型已经进化到产生复杂的二维图像。虽然进化的任务网络的性能落后于最近的模型,但 HyperNEAT 已经被用来训练模型玩 Atari 游戏[9](大约在同一时间,DeepMind 展示了这种通过强化学习训练的模型[10])。

In this HyperNEAT example, the task network (right) is a two-layered network in which neurons connect between the lower and upper layer, but not within layers. The CPPN network (left) defines connection strengths of the task layer for a given pair of task network nodes. The CPPN is a neural network defined by the NEAT genome-to-network mapping, and can be evolved using a genetic algorithm, with a fitness function applied to the task network defined by a given CPPN instantiation.
机体发育
生物进化不直接建立成熟(成年)生物的表型。相反,基因通过发育(例如,产前、婴儿期、青春期)间接建立生物体表型。基因也在成年期对生物体环境的反应中发挥作用(例如,在从低海拔向高海拔移动的生物体中产生更多的红细胞)。虽然 NEAT 进化出一群神经网络,但这些网络实际上并不是从基因组“生长”出来的。相反,它们是直接实例化的,因为纯网络是直接编码的。
研究人员如 Jordan Pollack 和他的前博士后 Sylvain Cussat-Blanc,正在探索包含生物体发育时期的进化计算方法。在 2015 年的一项研究[11]中,他们使用与 NEAT 相关的遗传算法进化出了基因调控网络(grn)的模型。一般来说,grn 是基因(和非基因 DNA、RNA 和蛋白质)控制其他基因表达(翻译成蛋白质)的网络。不同的基因在不同的发育时期和不同的环境条件下表达。因此,进化的不是生物体本身,而是它们发展的方式。作者证明了优于标准遗传算法。然而,计算复杂性很高,并且不太可能使用今天的标准硬件扩展到更具挑战性的现代人工智能任务。

Rather then evolve a genome that directly encoded a neural network (such as NEAT), Pollack and colleagues [11] evolved a gene regulatory network that controlled the development of a neural network, much like biological genomes direct human growth from embryo to adult.
最近,Miller 等人[12]构建了神经网络中神经元(体细胞及其树突)的发育模型。发展模型由计算机程序来表示,这些程序可以使用 遗传编程 来进化。遗传编程明显不同于遗传算法,我们让读者在其他地方探索这个主题。尽管如此,Miller 和他的同事采用了一种进化计算方法来创建开发模型,构建有用的神经网络。结果是网络可以生长新的树突和神经连接,以学习新的任务。
开放性
到目前为止,我们已经讨论了利用适应度函数对个体代理的表现进行明确评分并确定哪个代理将为下一代产生后代的进化方法。显然自然没有明确的适应度函数。(然而,它确实有一种隐含的反向适应度函数——如果生物 X 比生物 Y 产生更多的后代,那么生物 X 可能比生物 Y 具有更高的适应度。)也就是说,在没有外部指导的情况下,自然界的进化产生了非常聪明的物种(人类),以及具有独特而迷人的身体和先天行为特征的物种。
这一观察推动了人工生命和 T2 的研究领域。人工生命是指在真实或人工环境中研究人工有机体,这些环境密切反映了自然环境的某些或许多方面。研究人员用这种方法来研究我们所知的生命,但也研究其他可能的生命。开放式进化研究通常会纳入类似于人工生命研究中的人工生物,并在类似于产生生物进化的条件下观察这些生物的进化——即基于环境内直接行动的繁殖(寻找配偶,获得足够的食物以生存和繁殖,躲避捕食者等)。)而不是基于明确的适合度测量。与深度学习领域相比,开放式进化领域相对较小,但实际上是一个非常古老的领域,查尔斯·奥弗里亚(Charles Ofria)、乔丹·波拉克(Jordan Pollack)、里斯托·米库拉宁(Risto Miikkulainen)和他们的学生(其中几位现在是该领域的领导者)等先驱研究人员已经在战壕中度过了几十年。关于开放的历史和前景的更完整的描述,请看来自雷曼、斯坦利和索罗斯的这篇文章,以及杰夫·克鲁恩的这篇论文。
在开放环境中进化出的人工生物能否导致 AI 模型(智能体)的进步?我们认为答案是肯定的,但这至少取决于两个因素:(1)物种的共同进化和(2)丰富、多样和动态环境中的进化。(关于这个问题的不同观点,请参见丽莎·索罗斯的博士论文。)
针对第一个因素,环境必须容纳具有不同需求和能力的不同物种的多种代理,以便物种的共同进化可能导致物种内的合作——这可能是人类智能进化的先决条件。虽然共同进化已经导致猎豹和黑斑羚越来越快,但它也导致了狼的智能社会行为,正如在群体中协调狩猎所展示的那样。
Due in part to co-evolution, wolves have evolved a social intelligence that allows them to hunt in packs — thereby killing animals much larger than themselves and earning a food reward that benefits the entire pack, not just individual wolves.
事实上,OpenAI 最近的一项研究表明,尽管奖励系统看似贫乏,但经过强化学习训练的代理之间出现了复杂的互动行为。值得注意的是,奖励是根据团队(类似于物种)的表现给予的,而不是个人表现——就像一群狼在完成一次大屠杀后都会得到奖励一样。
Given the simple task of playing hide-and-seek, these agents learn to collaborate to perform complex task that at first blush, seem to have little to do with the primary hide-and-seek objective. Competition between teams is a driving factor in the emergence of these collaborative within-team behaviors. Note that these agents were trained by reinforcement learning rather than evolutionary computation. However, the relevant point is that competition between teams of agents (or species) can promote novel and complex behaviors.
这里应该提到强化学习和进化计算之间的一个重要对比。事实上,强化学习是动物一生中学习的一个模型。当动物的行为得到奖励时(通过食物、住所、交配等)。)更有可能重复这种行为,希望对其有益。然而,许多动物的能力是通过进化获得的,并在出生前的发育过程中或出生后不久就被赋予了。例如,人类生来就有几乎与生俱来的“物体感”(尽管不是“物体恒定性”)——婴儿不需要学习空间接近的“像素”(视网膜上的光子)更有可能是同一物体的一部分。一个与生俱来的极端例子是一些动物出生后获得复杂运动控制的速度(几分钟内)。底线是生物有机体对于许多能力是预先设定好。深度学习模型通常从零开始训练(“白板”),并严格针对特定应用。构建具有更一般的真实世界能力的 AI 智能体可能通过首先进化智能体以具有基本的先天知识(物理、情感、基本欲望等)来实现。)在“出生”。代理随后可以通过强化学习机制(在理想情况下,这种机制已经发展成为代理——例如,元学习)学习执行特定的任务
Baby wildebeests gain agile muscle control and navigation abilities with minutes of birth. Clearly evolution has given them an innate sense of gravity, physics, objectness, and an advanced sensorimotor control system. They do no need to learn these concepts and capabilities through their reinforcement learning system.
如前所述,我们认为进化智能代理的第二个关键因素是一个丰富、多样和动态的环境。这种环境包含跨越时间和空间的生态位条件,某些基因突变可能在其中被证明是有利的,但如果环境是同质的,则在随后的世代中会从物种中被洗掉。反过来,突变的有利表型也可能在不同的小生境环境中被证明是有利的,由于自我驱动的运动或由于其局部环境的变化(例如,真实世界中的气候变化),生物体可能会遇到这种不同的小生境环境。这有点类似于前面讨论的遗传算法中的质量多样性方法。
还缺什么?
除了已经陈述的以外,我们在这里列出了智能体、智能体环境和遗传算法的几个方面,我们推测这些方面可以促进智能体的进化,其能力超过当前的人工智能模型。如果条件支持,列出的一些智能体方面可能会自然进化,但它们也可以被直接强加,以加速向通用人工智能最终目标的进化。
代理人和环境
- 养育和长期发展时期:强迫生殖代理在发展时期照顾无助的后代,可能会促进社会互动、交流(语言)、合作(给定后代的父母之间、父母与子女之间,甚至非亲属父母与子女之间——养育一个孩子需要一个村庄)等。
- 个体识别:智能体应该能够识别同一物种的其他个体智能体(通过“视觉”或其他每个智能体独有的特征,并从智能体的基因组中获得)。如果代理人能够区分彼此,那么他们可以将单个代理人与该代理人的行为联系起来,潜在地允许信任、合作、关怀等的发展。(但也包括不信任、欺骗和勾结)。
- 通信媒介:环境应该允许一些模态,通过这些模态代理可以进化出一种通信方式(一种语言)。这在本质上可以是听觉的、视觉的,甚至是触觉的。这可能是代理进化复杂的社会互动和合作所必需的。
基因和遗传算法
- 用组合基因进行间接编码:使用相互作用的基因来产生更高水平的产物(例如,蛋白质,或对蛋白质产生的控制)可以允许紧凑但高表达的基因组,其可以比每个基因映射到一个且仅一个模型参数或表型性状的基因模型更有效地进化。此外,这种组合方面可以限制由于基因突变或交叉而导致后代完全不能存活(从而浪费模拟/评估时间)的可能性。
- 指导发育的基因:与上述相关,编码生物体发育的基因,而不是最终的、成熟的生物体,可能更紧凑和可进化(如在超净中)。如果发展也是由基因和环境之间的相互作用驱动的,这可能会对基因提供额外的选择压力,从而促进进化。
- 能够在大小上进化的基因组:行为复杂的生物可能比那些行为简单的生物需要更多的基因来定义它们的表现型(或它们的发展)。然而,从简单物种和小基因组开始的进化过程可能比基因组在进化过程开始时就很大的物种更快地进化成行为复杂的大基因组物种。在具有大基因组的简单物种中,单个基因的选择压力可能很弱,因为任何一个基因对生物体表型的影响都很小,从而减缓了进化。
- 再生和死亡代理的结构化选择:在利用适应度函数的算法中,典型的方法是选择表现最好的代理进行再生,并杀死该代中剩余的代理。然而,在这种方法下,为药物提供适合度优势的新突变基因仍可能因物种间的遗传漂变而丢失。最近的工作[15]表明,当另一个因子繁殖时,策略性地选择杀死哪个因子(其规则由结构化的“进化图”表示),可以促进新的有利基因在整个物种中的“扩增”,并降低有利基因丢失的可能性。在富裕、开放的环境中,这种结构可能是环境间接强加的。
结论
近年来,深度学习无疑带来了巨大的人工智能进步,而且很可能会有更多进步。尽管如此,我们相信人工智能的进化计算方法在历史上一直没有得到充分研究,最终将在人工智能能力方面产生类似的飞跃——要么建立在深度学习提供的基础上,要么提供全新的能力。
最后,我们推测进化计算方法可能会产生计算效率高的人工智能。通过在给定的硬件平台上进化代理,并适当地设计基因到指令的映射,可以选择加速任务完成的基因,从而优化该平台上的性能。
参考
- Krizhevsky,a .,Sutskever,I .,和 Hinton,G. E,《用深度卷积神经网络进行图像网络分类》。NIPS,第 1106–1114 页,2012 年。
- 列亨伯格和艾根。进化策略:生物进化的最佳技术体系。1973 年,斯图加特。
- H.-P .施威费尔。进化战略的计算机模型的数值优化,1977
- 进化策略作为强化学习的可扩展替代方案。arXiv 预印本 arXiv:1703.03864 ,2017。
- 费利佩·彼得罗斯基·瑟奇、瓦希斯特·马德哈万、爱德华多·孔蒂、乔尔·雷曼、肯尼斯·斯坦利和杰夫·克伦。深度神经进化:遗传算法是训练深度神经网络进行强化学习的一种有竞争力的替代方法。arXiv 预印本 arXiv:1712.06567 ,2017。
- 贾斯汀·K·普格、丽莎·B·索罗斯和肯尼斯·O·斯坦利。进化计算的新前沿。机器人和人工智能的前沿,2016 年 3:40。
- 通过扩充拓扑进化神经网络。 Evol。计算。10, 99–127 (2002).
- 肯尼思·斯坦利;戴维·安布罗休;杰森·高西(2009 年 1 月 14 日)。“进化大规模神经网络的超立方体编码”。人工生命。15(2):185–212。
- Hausknecht,m .,Lehman,j .,Miikkulainen,r .和 Stone,p.《一般雅达利游戏的神经进化方法》. IEEE Trans。计算机。智能。人工智能游戏 6,355–366(2014)。
- 通过深度强化学习进行人类水平的控制。性质 518,529–533(2015)。
- 通过扩充拓扑结构的基因调控网络进化。 IEEE Trans。Evolut。计算。19, 823–837 (2015).
- Miller,J.F .,Wilson,D.G .,Cussat-Blanc,s:《为解决多重问题建立神经网络的进化发展程序》。在:班扎夫,w。斯佩克特,l。谢尼曼 l。(编辑。遗传程序设计理论与实践第十六章。待定。斯普林格(2019)。
- 杰夫·克伦。AI-GAs:人工智能生成算法,产生一般人工智能的替代范例。arXiv 预印本 arXiv:1905.10985 ,2019。
- 索罗斯,丽莎,“开放式进化的必要条件”(2018)。电子论文和学位论文。5965.https://stars.library.ucf.edu/etd/5965。
- Pavlogiannis A,Tkadlec J,Chatterjee K,Nowak MA。用进化图论构造自然选择的任意强放大器。通讯生物学。2018;1(1):71.
进化深度神经网络

Photo by Johannes Plenio on Unsplash
近年来,我们许多人都看到深度学习在各个领域取得了巨大的成功,其中大部分来自于他们通过从数据中学习“分层特征提取器”来自动化经常繁琐和困难的特征工程阶段的能力[2]。此外,由于架构设计(即创建神经网络的形状和功能的过程)碰巧是一个漫长而困难的过程,主要由人工完成,创新性有限,大多数进展来自旧算法,这些算法在当今的计算资源和数据下表现非常好[13]。另一个问题是,深度神经网络主要通过梯度跟踪算法进行优化(例如, SGD , RMSProp ),这些算法是约束搜索空间的重要资源,但容易陷入局部最优、鞍点和噪声梯度,特别是在强化学习等密集解决方案领域[6]。

Illustration of a function with noisy gradients and several local minima. A gradient following algorithm such as SGD will get easily trapped by the local minima if it is initialized in a low (0–30) or high (65–100) value.
这篇文章回顾了进化算法是如何被提出并被测试为解决上述问题的一个有竞争力的选择。
神经结构搜索
随着深度神经网络(DNN)变得更加成功,对允许更好性能的架构工程的需求一直在上升。随着 DNN 复杂性的增加,人类手动设计它们的能力受到限制,因此神经架构搜索( NAS )方法变得越来越重要。当考虑到萨顿的惨痛教训[15]时,这个问题变得特别有趣:
从 70 年的人工智能研究中可以得出的最大教训是,利用计算的一般方法最终是最有效的,而且是最有效的。
进化算法(EA)已被证明在这件事上是有用的[10]。
人们可能会认为 NAS 是一个三维过程[2]。第一个维度是他们的搜索空间,它定义了算法可能表示的可能架构。自然,更大的搜索空间意味着要测试更多可能的组合。为了使问题可解,一些约束直接在层上实现:
- 选择最大层数。
- 它们只能以链式(顺序)或多分支结构连接。
- 图层类型的构建块是预定义的,但是它们的超参数可以调整。

Chain connected (left) and multi-branch neural network (right) examples. Each node represents a layer and each arrow symbolizes the connection between them. Reprinted from Elsken et al. [2].
接下来是搜索策略,它定义了如何探索搜索空间。一些常见的替代方法是随机搜索、贝叶斯优化、强化学习、基于梯度的优化和神经进化方法。进化 NAS 的第一种方法来自 Miller 等人[7],他们使用遗传方法提出架构和反向传播来优化权重。然后,Stanley 和 Risto [12]提出了增强拓扑的神经进化(NEAT),这是一种用于进化人工神经网络(ANN)的遗传算法(GA),它不仅可以优化解决方案,还可以通过考虑适应性和多样性来使解决方案复杂化。最近,Real 等人[9]发现进化在准确性方面表现得与强化学习一样好,但它开发了更好的中期性能和更小的模型(下面给出了对这种情况的进一步描述)。
即便如此,遗传算法和 DNN 都以要求高资源而闻名,大约需要几千个 GPU 日。因此,为了使 NAS 成为一种可承受的策略,性能评估必须在比实际性能更低的可信度(即,通过使用近似值,确定性更低)上进行。这方面的一些例子是[11],它使用人工神经网络来预测候选网络的性能,逼近帕累托最优前沿,以及[8],通过实施性能估计策略,其中 LSTM 神经网络用于估计另一个候选神经网络的验证分数,仅给定几个时期的训练。一些方法不是进行估计,而是试图保持神经网络的功能,同时改变其结构,从而加快训练。Auto-Keras [5]就是基于这种方法构建的。
NAS 在传统神经网络结构中的应用已经在过去几年中进行了研究,产生了最新的技术成果。举例来说,Rawal 等人[8]提出了一种基于树的 DNN 编码,该编码通过遗传编程进行搜索,并基于标准语言建模(即预测大型语言语料库中的下一个单词)将 LSTM 性能提高了 0.9 个困惑点(即新模型现在更好地估计了目标语言分布)。此外,在图像分类方面,Real 等人[9]发展了 AmoebaNet-A,以实现 83.9%的 top-1 和 96.6%的 top-5 ImageNet 准确性,从而建立了一个新的技术状态。有人提出,通过利用遗传算法群体中固有的多样性来放大当前的集成方法,甚至通过直接奖励群体中的集成而不是直接模型,可以进一步发展这些结果。
进化强化学习
神经进化算法可分为同时进化权重和架构的算法(例如 NAS)和仅试图优化 DNN 权重的算法。进化算法与强化学习的结合通常是一种单一权重的实现。
在一般基于梯度的算法中,如随机梯度下降(SGD)约束探索梯度跟踪,它们的搜索空间变得有些线性,局部最小值成为一个问题[1]。此外,深度强化学习(Deep RL)带来了两个额外的问题:当回报稀少时,很难将行动与回报相关联,过早地收敛于局部最优(即,它们仅在做出一系列决策后发生,也称为时间信用分配)[14],并且它们对超参数选择非常敏感[3]。
在 DRL,遗传算法被提出作为解决这些问题的方法。这样等人[13]用基于种群的无梯度遗传算法改进了 DNN 的权重,并发现它在困难的深度 RL 问题上表现良好,如 Atari 和人形运动。通过将他们的结果与随机搜索(RS)进行比较,他们发现 GA 总是优于 RS,并且 RS 有时优于 RL ,这表明局部最优、鞍点和噪声梯度正在阻碍基于梯度的方法的进展,并且在某些情况下,在原点周围区域的密集采样足以优于基于梯度的方法。他们还发现遗传算法的挂钟速度比 Q 学习快得多。
Such 等人[13]还指出,一个未知的问题是,在早期阶段使用遗传算法采样,然后切换到梯度搜索的混合方法是否会获得更好更快的结果。这正是 Khadka 等人[6]在进化强化学习(ERL) 中提出的,这是一种混合算法,它使用来自 EA 的群体来训练 RL 代理,并将代理重新插入群体中进行适应性评估。他们提出遗传算法是解决之前提到的深层 RL 问题的一个很好的替代方案,但它也很难优化大量的参数。因此,GA 的探索性和时间信用分配能力与来自深度 RL 的梯度相结合,以实现更快的学习。因此,进化 RL 能够解决比深度确定性策略梯度(DDPG)更多的任务,并且比简单 GA 更快。
底线
像[6]和[9]这样的实践研究已经证明了进化深度学习应用是一种推动技术发展的有用方法。然而,在采用的方法中仍然存在许多限制,就像在 ERL 使用预定义的 NAS 构建块和非交叉或非变异。此外,值得注意的是,进化算法被视为黑盒优化方法,因此它们很少提供为什么性能高的理解。
进一步的研究将决定人工智能在深度学习中的未来,但迄今为止,至少在中长期内,它们似乎将成为解决特定学习问题的重要工具。
参考文献
- Aly,Ahmed,David Weikersdorfer,Claire Delaunay (2019),“用多重搜索神经进化优化深度神经网络。”更正,abs/1901.05988。
- 埃尔斯肯,托马斯,简·亨德里克·梅岑和弗兰克·哈特(2018),“神经架构搜索:一项调查。”更正,abs/1808.05377。
- Henderson、Peter、Riashat Islam、Philip Bachman、Joelle Pineau、Doina Precup 和 David Meger (2018 年),“重要的深度强化学习。”在第三十二届 AAAI 人工智能会议上。
- 格雷戈里·霍恩比(2006),“阿尔卑斯山:减少过早收敛问题的年龄分层人口结构。”《第八届遗传和进化计算年会论文集》, 815–822,ACM。
- 金,海峰,宋清泉,胡希贵(2018),“Auto-keras:基于网络态射的高效神经结构搜索”
- Khadka、Shauharda 和 Kagan Tumer (2018 年),“强化学习中进化导向的政策梯度。”在 NeurIPS。
- 米勒、杰弗里·f、彼得·m·托德和沙伊莱什·u·黑格德(1989),“使用遗传算法设计神经网络”在 ICGA。
- Rawal,Aditya 和 Risto Miikkulainen (2018),“从节点到网络:进化的递归神经网络。”更正,abs/1803.04439。
- Real,Esteban,Alok Aggarwal,黄雁萍和 Quoc V Le (2019),“图像分类器架构搜索的正则化进化”arXiv 预印本 arXiv:1802.01548。
- 萨利曼斯、蒂姆、乔纳森·何、陈曦和伊利亚·苏茨基弗(2017),“进化策略作为强化学习的可扩展替代方案。”更正,abs/1703.03864。
- 史密森、肖恩·c、杨光、沃伦·j·格罗斯和布雷特·h·迈耶(2016),“神经网络设计神经网络:多目标超参数优化。”2016 年 IEEE/ACM 计算机辅助设计国际会议(ICCAD),1–8。
- 斯坦利,肯尼斯·o .和里斯托·米库拉宁(2002),“通过扩充拓扑进化神经网络。”进化计算,10,99–127。
- 费利佩·彼得罗斯基、瓦希什特·马德哈万、爱德华多·孔蒂、乔尔·雷曼、肯尼斯·o·斯坦利和杰夫·克鲁恩(2017),“深度神经进化:遗传算法是训练深度神经网络进行强化学习的一种有竞争力的替代方法。”更正,abs/1712.06567。
- 萨顿、理查德·S、安德鲁·G·巴尔托等(1998),《强化学习导论》,第 135 卷。麻省理工学院出版社剑桥。
- 理查德·萨顿(2019)。惨痛的教训。可在:【http://www.incompleteideas.net/IncIdeas/BitterLesson.html 【13/05/19 访问】
- Zoph,Barret,Vijay Vasudevan,黄邦贤·施伦斯和 Quoc V . Le(2018),“学习可扩展图像识别的可转移架构。”IEEE 计算机视觉和模式识别会议论文集,8697–8710。
进化神经网络
进化算法教程
在过去的十年里,深度学习一直主导着机器学习领域,通常会排斥其他技术。作为一名数据科学家,拥有各种工具是很重要的,我觉得一类经常被忽视的技术是进化算法。这么说可能有点自我放纵(我自己是一个长期运行的进化算法的中间产品),但我发现设计的进化技术非常棒,在许多情况下比传统的机器学习技术更实用。在本教程中,我们将使用进化算法来训练神经网络,并使用这种技术来解决回归、分类和策略问题。为此,我们将使用 Python 和 NumPy 库。
算法
进化算法以自然选择为前提,包括五个步骤:
- 创造一个有机体的初始种群。在我们的例子中,这些将是神经网络。
- 根据一些标准评估每种生物。这是生物体的适应度得分。
- 从第二步中挑选最好的生物体,让它们繁殖。后代可以是一个父母的完全相同的复制品(无性繁殖),也可以是两个或更多父母的嵌合体(有性繁殖)。
- 变异后代。
- 取新的变异后代群体,回到第二步。重复进行,直到满足某些条件(例如,通过了固定数量的代,达到了目标适应度,等等)。)
第一步:有机体
在本教程中,我们将使用全连接前馈神经网络作为我们的有机体。

Fig 1: A fully-connected (dense) network with dimensions [1, 12, 12, 12, 1]
在设计我们的有机体时,我们有四个指导原则:
- 我们必须控制生物体的输入和输出维度。从根本上说,我们正试图进化出某种映射ℝᵃ ⟶ ℝᵇ的功能 f ,所以 a 和 b 应该被内置到有机体中。我们通过参数化输入和输出维度来实现这一点。
- 我们必须控制输出激活功能。有机体的输出应该适合手头的问题。我们通过参数化输出激活来实现这一点。
- 我们必须控制生物体的复杂性。理想的生物体应该足够复杂,能够进化出目标功能,仅此而已。我们通过参数化隐藏层的数量及其尺寸来实现这一点。在一个更先进的算法中,这可以通过让生物体进化自己的结构并用适应度函数惩罚复杂性来实现。
- 生物必须兼容有性生殖。幸运的是,上述原则确保了这一点。所有的生物都将有相同的结构,所以“交换遗传物质”在这里意味着后代将从妈妈那里得到一些层重量,从爸爸那里得到一些层重量。
实现如下:
Snippet 1: The partial Organism class and methods for creating and using it
在__init__功能中,我们设置了网络。参数dimensions是图层维度列表,第一个是输入的宽度,最后一个是输出的宽度,其他都是隐藏维度。__init__函数迭代这些 n 维,以使用 Glorot 正常初始化创建 n-1 权重矩阵,这些权重矩阵被存储为layers。如果启用了偏置,还会为每个层存储一个非零偏置向量。该模型对所有内部层使用 ReLU 激活。使用output参数指定输出激活,可以是“ softmax ”、“ sigmoid ”或“ linear ”,在_activation方法中实现。
predict方法对输入矩阵反复应用 ReLU 和矩阵乘法。例如,如果网络由三个隐藏层和 softmax 输出构成,则网络将应用该函数
y=soft max(relu(relu(relu(xw₁)w₂)w₃)w₄)
其中 X 为输入矩阵, Wᵢ 为层 i 的权重矩阵, Y 为输出矩阵。
我们将创造一群这样的生物,它们都有相同的结构,但每一个都有不同的随机重量。
第二步:身体健康
衡量一个有机体的表现如何是进化算法设计的关键,而“好的表现”因任务而异。在回归中,适合度分数可以是负的均方误差。在分类上,可能是分类精度。玩吃豆人,可能是临死前狼吞虎咽的小球数量。因为适应度函数是特定于任务的,所以我们将等到下面的应用部分再来探讨它们。目前,理解我们需要一个函数scoring_function就足够了,它接受一个有机体作为输入并返回一个实数输出,其中越大越好。
第三步:繁殖
繁殖步骤本身有两个步骤:亲本选择和后代创造。每个新的有机体都需要双亲。在无性繁殖中 k 是 1,而在有性繁殖中 k 是 2 或更多。因此,要生成新一代的 n 生物,必须从上一代中选择 n 套 k 生物;决定哪个(些)有机体将成为每个孩子的父母应该基于它们的适应性分数来完成,其中最适合的有机体应该产生最多的后代。有许多方法可以做到这一点,其中包括:
- 从生物的前 10%中统一选择每个亲本。
- 将生物体从最好到最差排序,然后通过从指数分布中取样来选择每个亲本的指数。
- 将 softmax 函数应用于每个生物体的得分,以创建每个生物体的选择概率,然后从该分布中取样。
我在方法一和方法二之间选择了一个折衷方案,其中前 10%的生物体被选择作为一个孩子的第一个亲本,每个亲本十次,第二个亲本使用指数分布随机选择,如上所述。我还强制要求将某一代中表现最好的生物体克隆到下一代中。以下是相关代码:
Snippet 2: The partial Ecosystem class and the method for simulating a generation
如您所见,第 5 行和第 6 行对生物体进行了评分和排序。然后,population_size新的有机体在第 8 行的循环中产生。从第 9 行的前 10%中选择亲本 1(holdout是保证后代的生物数量,这里为population_size //10)。当mating启用时,使用λ= holdout的指数分布选择父 2。当交配被禁用时,父代 1 与其自身交配,子代是克隆体。
一旦选择了 n 对亲本,就可以通过随机组合每对亲本的特征来创造后代。在我们的例子中,这些特征是神经网络层中的权重。下面是Organism类创建后代的方法:
Snippet 3: The partial Organism class and method for mating two organisms together
如您所见,mate方法确认双亲彼此兼容,然后随机选择一个双亲来继承子有机体的每个权重矩阵中的每个列向量。
第四步:突变
每一个子生物体产生后,它都要经历突变(片段 3,第 18 行)。在本教程中,变异步骤被实现为将高斯噪声添加到网络中的每个权重。这里我们不改变网络的激活或架构,尽管更高级的进化算法肯定可以通过在隐藏层中添加或删除节点来做到这一点。代码如下:
Snippet 4: the partial Organism class and mutation method
重复
这几乎不是一个步骤;剩下要做的就是检查是否满足某些条件,如果不满足,就返回到第二步。我选择以固定的代数运行该算法,但是当适应性分数达到期望的阈值时或者在代数没有改进的情况下停止也是很好的选择。以下是有机体和生态系统类的完整代码:
Snippet 5: The Organism and Ecosystem classes in all their splendor
应用
“酷。我为什么要在乎?”—可能是你
回归
让我们将这个过程应用于一个回归问题。我们将进化出一个有机体,在域x∈【0,1】中近似sin(【τx)。显然这是一个微不足道的问题,这就是为什么我们把它作为一个例子。那么我们应该如何设计我们的有机体呢?
- 这是一个从ℝ到ℝ的函数,所以输入和输出维度都是 1。
- 正弦的范围是[-1,1],所以输出激活将是线性的。
- 适应度函数将是有机体输出的负均方误差。
- 我们将使用三个宽度为 16 的隐藏层,因为对于这个简单的任务来说,这可能已经足够复杂了。
代码如下:
Snippet 6: Using an Ecosystem of Organisms to evolve the sine function
结果:

Fig 2: The best organism from each of 200 generations of evolution. Predictions vs. target (left), best fitness per generation (top), and network visualization (bottom).
正如你所看到的,在 200 代之后,一个有机体进化出了一个在域【0,1】内的正弦函数的非常好的近似值。
分类
让我们来看看这种技术如何应对分类问题。这里我们使用虹膜数据集。对于门外汉,(欢迎!)鸢尾数据集是 150 朵鸢尾花的几十年前的萼片和花瓣长度和宽度的集合。每朵花属于三个物种中的一个,任务是根据它的四个测量值按物种对花进行分类。那么这对我们的有机体意味着什么呢?
- 每朵花有四个实值测量,所以我们的输入维数将是 4。
- 有三个不同的类,所以我们的输出维将是 3。
- 因为我们选择了一个类,我们的输出激活将是 softmax。
- 我们将拿出三分之一的培训数据进行测试。这是为了确保有机体不会记住答案。
代码如下:
Snippet 7: Using an Ecosystem of Organisms to evolve the a flower classifier
结果:

Fig 3: The best organism from each of 20 generations.
每个散点图代表一对彼此相对绘制的不同特征。每个点都是一朵花,其中轮廓颜色代表真实的类,填充颜色代表预测的类。每一代中最佳生物体的训练和测试适应性显示在线图中,最佳生物体显示在中右面板中。在仅仅 15 代的时间里,生态系统演化出一个能够正确分类整个测试集的网络!
政策
让我们尝试进化出一种能够玩 OpenAI 的 CartPole“游戏”的生物体,包括在 AI Gym 包中。这是 YouTube 上的一个例子:
Source: Morvan on youtube
来自官方文件:
一根杆子通过一个非驱动关节连接到一辆小车上,小车沿着一条无摩擦的轨道移动。通过对推车施加+1 或-1 的力来控制该系统。钟摆开始直立,目标是防止它翻倒。杆保持直立的每个时间步长提供+1 的奖励。当柱子偏离垂直方向超过 15 度,或者手推车偏离中心超过 2.4 个单位时,该集结束。
在游戏的每个时间步,gamestate 被表示为四个实数的向量,分别对应于手推车的水平位置、手推车的水平速度、杆子的角度和杆子的角速度。然后玩家必须施加一个动作(施加+1 或-1 的力),游戏前进一个时间步长。如果玩家能够在 500 个时间步内避免失败,他们就“赢得”了游戏。
那么这对我们的生态系统和生物意味着什么呢?
- 每个时间步长有四个实值测量,因此我们的输入维将是 4。
- 有两种可能的操作,所以我们的输出维数是 2。
- 因为我们选择了一个动作,所以我们的输出激活将是 softmax。
- 适应度函数是存活的时间步数。为了稳健,我们将运行模拟 5 次,并取存活时间步长的平均数。
代码如下:
Snippet 8: Using an Ecosystem of Organisms to evolve a CartPole player
真的这么简单吗?好吧,这是结果:

Fig 4: The best organism in each generation playing CartPole
没错,生态系统只用了 6 代就进化出了打败游戏的生物体。我自己也有点震惊;你会注意到在第 31 行,我期望它会比这多得多。我本来打算像在其他两个问题中一样显示随时间变化的适应性,但我不会用它来打扰你,因为六个数据点并不是一个有趣的数字。
结论
进化算法直观有效。尽管上面的例子相当简单,但它们证明了进化算法适用于一大类问题。进化算法在解决方案的适合度是可测量的情况下特别有用,但不是以一种容易允许梯度反向传播的方式,如在掷球游戏中。出于这些原因,将进化算法添加到您的机器学习工具箱中是非常值得的。请继续关注我的下一篇文章,在这篇文章中,我将详细探讨适应度函数,以及合理的假设如何会导致令人捧腹的灾难性结果。
5G 时代分析角色的演变

Courtesy: Pixabay
请记住,曾经有一个时代,所有的业务利益相关者都需要接受教育,数据本身并不能带来推动业务增长的洞察力。相反,正是从数据中获得的分析创造了真正的价值!
当时,数据管理和分析被放在组织的不同部门。此外,企业需要一些时间来打破组织界限,将大数据和分析结合起来,以实现大数据的预期结果。再一次,在这个人工智能的时代,我们已经见证了某种形式的地震转移,人工智能正在推动技术的使用,以创造明智的,城市化的和更好的生活。而且,这一切都是从数据开始的!
鉴于自 2G 时代以来,数据和分析总是相互交织并促进敏捷和业务增长,5G 时代,分析将戴上什么新帽子?
当我们进入 5G 时代时,我们可以期待许多公司在大数据和分析方面进行更多投资。 IDC 在一份报告中指出,到 2020 年,大数据和业务分析的全球收入将增长超过2030 亿美元,复合年增长率(CAGR)为 11.7% 随着这种情况的发生,数据分析的应用将变得敏捷而稳健。虽然分析将继续完成其主要任务——从浩瀚的数据宇宙中获得洞察力以获得更好的投资回报,但分析有可能发挥一些高级作用来帮助企业增长。
随着我们转向可穿戴技术,生物特征数据收集可能会变得更加突出和快速,零售商、餐馆、生活方式组织试图了解消费者习惯或预测他们的需求。例如,来自健身跟踪设备的数据,可以整理体重、身高、心率和其他信息,可以导致餐馆或零售商更多的定制广告。
在客户层面,现在可以挖掘非结构化的社交媒体和电子邮件数据——这要归功于预测分析的强大功能。但如果一家公司正在探索非结构化数据的新方式:Instagram 和 YouTube 上的图像、音频和视频,并希望分析照片中的视频帧或姿势,该怎么办?目前,大多数数据分析工具只能解析带有标签关键词的信息,这些标签关键词使视频或照片易于找到,但可能无助于分析上下文、帧或姿势。但在未来,我们可以看到分析能够理解和总结视觉信息,并具有将非结构化和多媒体数据置于上下文中的卓越能力。
谈到物流领域,分析可以通过指导公司使用关于重要资源可用性的见解来更好地利用,从而戴上智能物流合作伙伴的帽子。换句话说,资源分配、运输路线和仓库管理可以轻松优化,从而节省时间和燃料成本。
除了在预测、营销优化、机器维护中发挥关键作用外,分析还可能在预防和检测欺诈活动中发挥重要作用。从电子商务到银行,分析在识别可疑模式和紧急向当局报警方面一直发挥着重要作用。展望未来,我们可能会看到分析通过先进的预测算法和技术,为我们预测交易相关犯罪可能在何时何地以更快的速度发生。
随着创新的步伐日益加快,分析的作用将进一步发展,并对各种运营变得至关重要。话虽如此,组织将需要加强他们的分析实践。然而,增长的灵丹妙药依赖于开放地接受分析实施方式的不断变化。与不断发展的创新保持同步的组织将在未来从数据和分析中获得回报和好处。最后,唯一可以确定的是,5G 时代将是不同的,非常有前途的,分析将引发增长和业务转型的循环。
检查 BERT 的原始嵌入
它们单独存在有什么用处吗?

BERT’s raw word embeddings capture useful and separable information (distinct histogram tails) about a word in terms of other words in BERT’s vocabulary. This information can be harvested from both raw embeddings and their transformed versions after they pass through BERT with a Masked language model (MLM) head. Figure illustrates the top k neighbors for the term cell in BERT’s raw embeddings (28,996 terms — bert-base-cased ) before and after passing through BERT model with a Masked Language Model head. (1) the input sentence. (2) The tokenized version of input sentence — Conan is not present in BERT’s raw vocabulary. It is broken down into two terms “Con” and “##nan” both of which are present in BERT’s vocabulary. (3) BERT’s MLM output finds the closest predictions in BERT’s vocabulary to the transformed vectors. For the word “cell” the top k neighbors (shown on right — this figure shows match — not the exact ordering) contain only terms that capture the semantic notion of incarceration. In contrast, the top k neighbors (shown on left) of the word “cell” before input to BERT captures all the different senses of the word in its top k neighbors — the “incarceration” sense as well as “biological” (protein, tissue) as well as mobile phone sense (phone, mobile). The top k neighbors before and after input fall in the tails of the histogram of distance/prediction score vs counts making those neighbors distinct and separable from the rest of words in the vocabulary
TL;速度三角形定位法(dead reckoning)
BERT 的原始单词嵌入捕捉有用的和可分离的信息(不同的直方图尾部)关于 BERT 词汇表中的其他单词的单词。这些信息可以从原始嵌入和它们的转换版本中获得,在它们通过带有屏蔽语言模型 (MLM) 头的 BERT 之后
当通过让模型从预测每个句子中的几个屏蔽词(大约 15%)**(屏蔽语言建模目标)中学习,在大型语料库上自我监督训练 BERT 模型时,我们得到作为输出的
- 伯特模型(学习权重)和
- 大约 30,000 个向量或嵌入(如果需要,我们可以用自己的词汇训练模型——尽管在这样做之前需要考虑许多因素,例如需要用新的词汇从头开始预训练模型)。在本文中,这些向量被称为原始向量/嵌入,以便在它们通过 BERT 模型时与它们的变换后的对应物区分开来。
这些学习到的原始向量类似于 word2vec 模型的向量输出— 单个向量代表一个单词,而不管其不同的含义或意义。例如,像“细胞”这样的词的所有不同的含义(手机、生物细胞、监狱细胞)被组合成一个向量。
当这些原始向量被输入到训练好的模型中时,它们被用来表示单词。然后,该模型使用句子中相邻单词的上下文来转换单词的表示。
例如,在预测句子中的单词的任务(该预测任务不需要微调,因为它与训练目标相同)中,句子中的所有单词都被模型转换成依赖于上下文的表示。像“细胞”这样的词会摆脱其“移动”和“监狱”的含义,只保留其“生物”的含义,如“生物中有许多细胞器细胞 ”。在类似于“他去监狱* 细胞 用 细胞 手机从生病的囚犯身上采集血液 细胞 样本”的句子中,由单词“细胞”的模型输出的三个独立向量将在它们中分别捕获三种感觉,而不是具有所有感觉的细胞的原始输入向量*
检查 BERT 学习的原始向量(大约 30,000 个向量——其中大约 78%是“细胞”、“蛋白质”形式的完整单词,22 %是“##os”形式的部分单词或子单词。例如,单词“icos”在输入到 BERT 模型期间被表示为两个向量—“IC”和“# # OS”)显示
- 他们捕捉到了不同形式的相似性——语义( 皇冠 、王座、君主、女王、句法( 何 、她、他们)、单词屈折( 进位 、carries、carrying)、拼写( 墨西哥 、墨西哥)跨语言的语音相似性(这种相似性可能部分解释了机器翻译中变压器的性能)。本质上,原始向量的嵌入空间是由上面的例子所说明的不同类型的相似性组成的混合抓取包。
- 原始学习向量,不管它们捕获的相似性度量的类型如何,在它们与其他向量的余弦相似性的直方图(余弦相似性与项数)中具有非常相似的分布形状。对于每个单词,都有一个尾部,那里的计数通常是个位数。在这些尾巴中,有一个以上的上述相似之处占优势。在语言建模目标上微调模型,改变分布形状(平均向右移动),但仍有明显的尾部。
这些原始向量和屏蔽语言模型可以用于各种任务
- 给定一个术语,识别它的不同含义和主要含义(再次使用 BERT 词汇表中的术语获得)。例如,如前所述,术语“细胞”具有多种含义。在特定领域语料库上对模型进行微调后,其中一种意义可能会支配另一种意义(例如,在生物医学语料库上对模型进行微调可能会使单词“细胞”的“生物细胞”意义支配其他两种意义)。**
- 给出两个或更多术语,找出它们之间的任何共同含义(使用 BERT 词汇表中的术语获取的含义)。例如,两种药物将共享共同的描述符,如药物、药物、治疗。
- 特定类型的集群实体(这通常只适用于彼此不同的实体类型)**
- 无监督的“实体识别” —我们可以用 BERT 词汇表中的一组常见名词(如药物、药品、治疗、疗法)来标记专有名词(例如像阿托伐他汀这样的药物)。这些普通名词可以作为专有名词的实体标记代理。可能存在这样的情况,词汇表中的专有名词(参见下面大写术语的词汇表统计)充当实体的代理(例如,人名——Johnson、smith、cohen 可以充当一个人的实体类型的描述符)**
- 关系三元组的无监督收获
伯特词汇统计
上述所有潜在应用的一个共同方面是使用 BERT 的词汇来表示
- 词汇表中的邻居,其中通过原始向量空间中输入项的向量的余弦相似性度量来寻找项的邻居
- 通过屏蔽语言模型对句子中某个位置的单词/子单词的最高预测。句子中的任何输入术语都被标记为 BERT 词汇表中的单词/子单词。MLM 对输入句子中的位置的预测是根据伯特的词汇
使用公共词汇或描述符来表征 MLM 的输入项和输出预测使得上面列出的各种应用成为可能。
预训练 BERT 产生大约 30,000 (28,996)个向量,表示 BERT 词汇表中的单词(这些向量存储在来自拥抱脸* 的 Pytorch Transformers 中的py torch _ model . bin 文件中。用于提取此内容的代码存根粘贴在下面问题的回复中*

BERT (bert-base-cased) vocabulary stats
小写术语占 BERT 词汇的近 45%,大写术语占 27%——基本上 BERT 词汇的 72%用作完整单词的描述符。包括其他语言字符和子词的符号构成了近 28%,并作为描述符来预测子词以及发音相似的声音。使用 MLM 预测句子中的术语的描述符通常是这些不同类别的混合。然而,对于像“细胞”这样的术语,顶部邻居(在原始向量邻域以及 MLM 输出预测中)将主要是其他术语,如上图“细胞、监狱等”而对于像“kan”这样的术语,主要是子词和其他语言发音相似的字符。
假设我们可以使用 BERT 的词汇来完成任务,比如用普通名词作为实体类型(药物、药品、治疗等)来标记专有名词(阿托伐他汀)。—这可以通过提取包含阿托伐他汀的句子并在标记化之前屏蔽整个单词来完成—这必须在标记化之前,因为阿托伐他汀不是 BERT 词汇表的一部分,所以它将被标记为多个子词)出现的几个问题是
- 在向量的原始嵌入空间中描述一个词的描述符与 BERT 词汇表中的其他术语是不同的还是很好地分开的?
- MLM 使用伯特词汇中的描述符来预测一个词在句子中的位置,这些描述符在预测空间中与伯特词汇中的其他术语有区别吗?
原来它们在原始向量空间和 MLM 预测空间中都是不同的。即使邻域(术语捕捉的不同感觉)的性质发生变化,这种明显的分离也通过微调得以保留
伯特的原始向量有不同的邻域
在微调前后,BERT 词汇表中每个术语的邻域及其邻居的聚集直方图显示了一个明显的尾部,其中所有术语表现出不同的相似性(语义、句法、语音等)。)驻留。邻域是通过对 BERT 的原始向量进行余弦相似性来完成的。

Aggregate histogram plot of the neighborhood of each term in BERT’s vocabulary with its neighbors, before and after fine tuning, reveals a distinct tail where all the terms exhibiting different similarities (semantic, syntactic, phonetic, etc.) reside. Neighborhood is done by cosine similarity on BERT’s raw vectors. This plot was done with only terms that are not subwords (##kan etc.). Aggregate histogram plot of subwords also exhibit distinct neighborhoods with a similar shape before and after fine tuning.
下图显示了 BERT 词汇表中单个术语与其他术语的直方图。它们还显示了微调后尾部的项是如何变化的。

Histogram plot of BERT of the cosine similarity of a single term “genes” with vectors of all other terms in BERT’s vocabulary. The neighborhood of the term changes with fine tuning

Histogram plot of BERT of the cosine similarity of a single term “cell” with vectors of all other terms in BERT’s vocabulary. The neighborhood of the term changes with fine tuning. Note the elimination of the different senses for the word “cell” after fine tuning it on a biomedical corpus.
伯特·MLM 对代币的预测也是截然不同的
下面的直方图显示了对输入句子“Connan got to institution cell”(在标记化之后变成“Con # # nan got to institution cell”)中的标记“cell”的预测

Predictions for the token “cell” in the input sentence “Connan went to prison cell” (which becomes “Con ##nan went to prison cell”* after tokenization). We observe a distinct tail like the tails in raw embedding space plots*
我们从尾部选择多少项的阈值(原始嵌入空间和 MLM 头部的预测),由我们的应用需求驱动,特别是我们需要的精度和召回水平。这些分布含义(在单个术语水平或集合水平)有助于我们做出选择(从信号中分离噪声)。
Roberta 是一个具有 50,265 个词汇的类似 BERT 的模型,它在其原始向量空间中为一个词的余弦邻居以及在 MLM 目标的预测分数中展示了明显的尾部,如下所示。

Roberta Cosine neighborhood for the word “cell”. Distinct tail in histogram plot of the term against all the 50,265 terms.

Roberta output with a vocabulary size of 50,265 terms (byte pair encoding) exhibits a distinct tail in its prediction for terms in a sentence. The output above is the histogram distribution of prediction scores for the word “fell” in the sentence “he [mask] down and broke his leg”
很可能其他具有 MLM 目标的变形金刚模型()Distilbert,Camembert)在原始向量空间及其预测分数输出中都表现出明显的尾部,尽管这需要确认。
原始嵌入使用示例的详细信息
如果我们有两个术语(可以是单个单词或短语)并且目标是识别这两个术语之间的共同点,我们可以
- 首先选择每个词在句子中单独出现的句子,并使用 MLM 头找到这些词的预测邻居。这些描述符的交集充当这些术语的孤立含义的签名。
- 选择两个术语都出现的句子,并预测这些术语的邻居。当它们在彼此的上下文中时,这产生两个签名,每个术语一个。
- 上面我们有四个描述符集——单个术语的描述符和两个术语一起使用时的描述符。
- 由于上面收集的所有描述符都是词汇表的一部分,我们可以在原始嵌入空间中以无向图的形式检查这些描述符,其中基于阈值(基于尾部选择的阈值)选择节点之间的连接。检查描述符倾向于产生在两个空间中捕捉相似性的签名。同样,具有高阈值的原始嵌入空间可以用于组合描述符中的拼写变化。这被证明在无监督地获取术语的同义词候选项的任务中是有用的。
最后的想法
距离 word2vec 的原始论文— “向量空间中单词表示的高效估计(2013 年 1 月)”已经过去了将近 7 年。BERT 和它的 transformer 变体已经成为 NLP 任务的主要部分。虽然 word2vec 训练的输出只是向量(我们从训练中没有得到多少模型——只有每个向量的上下文向量副本,通常会被丢弃),在 BERT 的情况下,我们得到的输出是原始的学习向量以及一个模型,该模型可以通过微调模型和向量将这些向量转换为适合特定任务的表示。
虽然两个模型产生的向量将一个单词的多个含义组合成一个向量,并且两个模型都具有与其他单词相比的不同尾部的直方图(与 BERT 的固定单词和子单词词汇表不同,word2vec 情况下语料库中所有单词的向量),但是 BERT 的向量与众不同,原因如下
- 伯特的向量似乎捕捉到了更大范围的相似性——例如,像“kana”这样的子词与其他语言中发音相同的邻居的相似性
- 给定一个由单个字符、子词和单词组成的词汇表,BERT 可以有效地表示句子中的任何单词——消除了词汇表之外的场景(至少对于英语)。
- 不管语料库大小如何,固定词汇表具有显著的实际优势——在计算期间,可以将词汇表的所有向量存储在 GPU 或其他内存受限的环境中。
- 最后,除了被转换成最适合特定 NLP 任务的表示的关键能力之外,与训练的模型结合的 BERT 矢量可以表示句子中单词的特定含义。
Word2vec 模型通过自我监督学习来学习单词的向量表示,这些向量表示捕获了单词之间的相似性。基于转换器的模型,如 BERT,除了学习向量之外,还学习多层转换,这些转换可以应用于这些向量以解决各种 NLP 任务。
为伯特和罗伯塔创建直方图以及提取原始矢量链接的代码在 Github 上
**这篇文章是从 Quorahttps://qr.ae/TcgPF8手动导入的
检查变压器架构
本博客第 1 部分& 2 由 尼提什·阿加瓦尔 在 Exxact Corporation 的合作和赞助下撰写。
第 1 部分:开放 GPT 2 争议
“回收对世界没有好处。这对环境有害,对我们的健康有害,对我们的经济也有害。我没开玩笑。回收对环境没有好处。它对地球具有破坏性,是全球变暖的主要原因。回收对我们的健康没有好处。它会导致肥胖和心脏病、癌症等疾病。回收对我们的经济有害。它增加了产品的成本,进而增加了用该产品制造的所有东西的价格。回收对我们国家没有好处。我们为拥有世界上最先进、最高效的回收系统付出了巨大的代价。回收是对时间、能量、金钱和资源的巨大浪费。”**—open ai 的 GPT 2 模型
是的,这些不是某个试图在社交媒体上推广反回收宣言的反回收怪胎的话。这整件事是用一种语言模型……一种算法……一种人工智能写的,如果我们说得太粗鲁的话。
GPT-2 是一个生成模型,由 OpenAI 创建,在 40GB 的互联网上训练以预测下一个单词。OpenAI 发现这个模型太好了,以至于他们没有发布经过完全训练的模型——有人说这违反了他们让人工智能向所有人开放的创始格言——因为他们“担心该技术的恶意应用”。
我们在谈论哪些恶意应用程序?
开艾说,“我们还可以想象这些模型的应用出于的恶意目的,包括以下几种(或者其他我们还无法预料的应用):
- 产生误导性的新闻文章
- 在网上冒充他人
- 自动制作发布在社交媒体上的辱骂或伪造内容
- 自动制作垃圾邮件/网络钓鱼内容"
“但这种模式真的有那么好吗?”
还是说以上的担忧仅仅是某些偏执狂的观点?
这个模型并没有在算法前沿呈现一些大的飞跃。这只是该团队几个月前发布的 GPT 模型的放大版。
它确实展示了我们当前的语言建模技术在文本生成方面的能力。它是其前身的大规模升级版本。GPT-2 拥有高达 15 亿个参数(比最初的 GPT 多 10 倍),并根据来自 800 万个网站的文本进行训练。
一旦你把它与其他“流行的”生成语言模型相比较,你就能理解这个模型的功绩了。
但是首先说一句题外话——关于语言模型的一个非常简单的解释
语言模型旨在简洁地表示所观察文本的历史,以便预测下一个单词。所以,基本上只是学习预测单词。给模型一个提示,它会预测下一个单词,然后下一个单词,然后再下一个单词,很快它就会形成一个有意义的句子,把足够多的单词组合起来,你就有了一个连贯的段落,然后..几乎所有你想要的。
例如,只需观看这部于 2016 年年中发布的科幻短片,其剧本是由一个生成模型创建的,该模型使用 LSTM 建筑公司在大量科幻电影和电视节目的剧本上训练出来的:
他们让托马斯·米德蒂奇——硅谷的理查德——主演这部电影!!
或者这个哈利波特人工智能生成的同人小说怎么样,它在 2017 年底走红,并且:
正如你所看到的,这两个在质量上比 GPT-2 的例子差得多。Open AI 在他们的博客文章——中挑选并发布了一些更好的语言模型及其含义。
“ unicorn ”样本读起来像一份真正的科学新闻稿。“核材料盗窃”样本读起来像一个真实的新闻故事。“麦莉·赛勒斯入店行窃”样本读起来像是来自名人八卦网站的真实帖子。“ GPT-2 ”样本读起来像一个真正的 OpenAI 新闻稿。《勒苟拉斯和吉姆利》的样本读起来就像一本真正的奇幻小说。“内战家庭作业”读起来就像一份真正的优等生试卷。这个“ JFK 获奖感言”读起来像一个真正的政治家的演讲。“回收”样本读起来像真正的右翼熨平板。
不仅仅是这 8 个精选的例子。Open AI 还为我们提供了数百个原始 GPT-2 样本的转储,这可以让我们更清楚地了解模型的能力。
是的,它们中的每一个“读起来像”一些真实的人类生成的内容。但事实并非如此。
这篇文章认为,如果你略读文本,你会错过明显的荒谬之处。重点是 OpenAI 已经实现了在自动驾驶上通过针对人类的图灵测试的能力。因此,如果你没有真正集中注意力,只是浏览一下,你就不会发现这是由语言模型生成的。对于我上面提到的其他例子来说,这肯定不是真的。甚至“像正常的人类生成的内容一样阅读”也是一个巨大的壮举。
所以,是的。我要说这款真的不错。
不释放模型重量的影响
事实上,Open AI 没有发布这个模型对 AI 社区和媒体来说是一个巨大的冲击。
一些人认为这只是开放人工智能的一部分的宣传噱头,因为没有算法上的壮举。另一群人认为这种的尝试将是徒劳的,因为代码是开源的,愿意在计算资源上花足够多钱的大公司/人们将能够在短短几个月内复制结果。
但是还有另外一群人在为开放人工智能鼓掌,因为他们试图让研究人员意识到他们研究成果的影响。随着人工智能技术变得越来越强大,世界将面临一个重要的挑战,即打击合成内容和错误信息。
sou Smith chint ala 是 PyTorch 的创造者。这是他、杰克·克拉克和杰瑞米·霍华德之间的一根线!
所以知道它是如何工作的,知道驱动它的算法不是很酷吗?
第 2 部分:变压器工作原理的简要描述
变压器架构
这种架构最初是在 2017 年年中谷歌的开创性论文中提出的— 关注是你所需要的全部。
在这么短的时间内,这种架构已经在两篇论文中用于产生最先进的结果——一篇是 GPT/GPT-2,另一篇是伯特。

Table Source: Language Models are Unsupervised Multitask Learners, Radford et al. 2019
最小的一个对应于 GPT 模型;第二小的相当于 BERT 中最大的模型;最大的一个比第一个大一个数量级,对应于 GPT-2 模型
现在让我们来看看架构:

The Transformer architecture as present in the Attention is all you need paper by Google
首先,我们可以看到它有一个序列到序列的编码器-解码器架构。互联网上很多关于变形金刚的文献都是用这种架构来解释变形金刚的。但这不是 Open AI 的 GPT 模型(或 GPT-2 模型,只是其前身的更大版本)中使用的那种。
GPT 是一个只有 12 层解码器的变压器,有 117M 个参数。

Improving Language Understanding by Generative Pre-Training, Radford et al.
来自 Open AI 的 GPT 论文中使用的变压器架构
GPT(以及 GPT-2 的较小发布版本)有 12 层变形金刚,每层有 12 个独立的注意机制,称为“头”;结果是 12 x 12 = 144 种不同的注意力模式。这些注意力模式中的每一个都对应于模型捕捉到的一个语言属性。
正如我们在上面的 transformer 架构中看到的,注意力是 Transformer 的重要组成部分。事实上,这是一种保守的说法。注意力是使变压器工作的原因。那么,我们来简单介绍一下注意力。
注意力模型
RNN 单元将把直到时间戳 t 的输入编码到一个隐藏向量 ht 中,该隐藏向量然后将被传递到下一个时间戳(或者在序列到序列模型的情况下传递到解码器)。有了注意机制,我们不再试图将完整的源句子编码成固定长度的向量。相反,我们允许解码器在输出生成的每一步“关注”源句子的不同部分。重要的是,我们让模型学习根据输入的句子和它到目前为止产生的结果注意什么。
比方说,我们想翻译 1992 年签署的《欧洲经济区协议》。(法语)到英语哪个是“欧洲经济区协议是 1992 年 8 月签订的。”**
下图显示了注意力模型对它生成的每一个翻译单词的关注程度。

Image Source: jalammar.github.io
请注意,除了将“欧洲经济区”翻译为“欧洲经济区”之外,它几乎都是线性的。在这种情况下,它会正确地以相反的顺序出现。
这种能力允许注意力学习长程相关性。
与 RNN 的比较
如前所述,一些从业者认为我们正在见证 RNN/LSTM 的衰落。自 2014 年推出以来,它们一直是所有 NLP 任务的默认首选架构,包括语言建模、机器翻译、文本摘要、图像/视频字幕、语音到文本转换等。
但是 RNN 和它的变体有两个主要缺点:
- 未能记住长程相关性
RNNs 的主要吸引力之一是,他们能够使用他们对电影中先前事件的推理来通知后来的事件。但这也是他们的主要缺点之一。

rnn 需要将来自整个序列的信息编码在一个单独的上下文向量中。来源
解码器应该仅基于来自编码器的最后一个隐藏状态(h3)来生成翻译。这个向量必须编码我们需要知道的关于源句子的一切。它必须完全抓住它的意义。
随着两个单词之间的差距越来越大,RNN 人似乎“忘记”了前面的单词。
长短期记忆单元(LSTMs)和门控循环单元(gru)通过使用由门控制的记忆单元(/s)提供了一种粗略的解决方案,该记忆单元允许它们从更早的过去获取信息。
- 无法利用 GPU 的能力
rnn 不能并行处理输入。它们是带有环路的网络,允许信息持续存在。

Source: http://colah.github.io/posts/2015-08-Understanding-LSTMs/
在上图中,神经网络 A 的一个块查看某个输入 xt 并输出一个值 ht。环路允许信息从网络的一个步骤传递到下一个步骤。这意味着它们一次只能处理一个输入单元。
这就是为什么他们不能利用非常强大的 GPU 的并行计算能力。这种图形处理器允许 CNN 对大量数据进行训练,并增长到绝对巨大的规模。rnn 或
lstm 或其任何变体天生不擅长利用这种手段。
变形金刚擅长这两项任务。
深度学习工作站 来自 Exxact 特色Quadro RTX 8000非常适合训练甚至大型变压器模型。每个Quadro RTX 8000拥有 48 GB GPU 内存,一对可以通过 NVLink 连接,从而提供 96 GB 的总 GPU 内存,以适应大规模的变压器型号。**
预训练语言模型—自然语言处理中的迁移学习
Transformer 架构允许创建在绝对庞大的数据集上训练的 NLP 模型,正如我们在本文中看到的。这样的模型不可能被所有人训练,就像你不会期望在 ImageNet 数据集上从头训练一个 VGG 网一样。因此,预训练语言模型的时代到来了。
通过这种大规模预训练模型学习的权重可以在以后通过针对特定数据集进行微调来重新用于特定任务。这将允许我们通过捕捉语言的底层复杂性并简单地“插入”它以适应我们的特定任务来进行迁移学习。
变形金刚是 NLP 的下一个前沿。在不到几年的时间里,这种新的建筑趋势已经超越了 RNN 建筑的成就。这种令人兴奋的发明步伐可能是早期进入深度学习这样一个新领域的最好部分!
第 3 部分:在 Docker 中从头开始训练变压器网络
本教程的培训将在我们的 Exxact Valence 工作站上使用英伟达 RTX 2080 Ti 完成。此外,我们将使用位于官方 TensorFlow GitHub 上这里的 transformer 模型实现创建一个英语到德语的翻译器。假设您已经满足了 TensorFlow GPU 的所有必要依赖项,我们提供了一个简单的教程指南,用于在 docker 中开始使用 transformers。
步骤 1)启动 TensorFlow GPU Docker 容器
使用 Docker 可以让我们为我们的培训需求构建一个完全包含的环境。我们总是推荐使用 Docker,因为它允许我们的培训环境有最大的灵活性(和宽容)。首先,我们将打开一个终端窗口,输入以下命令来启动我们的 NVIDIA CUDA 驱动的容器。
*nvidia-docker run -it -p 6007:6006 -v /data:/datasets tensorflow/tensorflow:nightly-gpu bash*
注意:上面命令的关键参数的快速描述(如果你不熟悉 Docker)。

步骤 2)安装 git
如果您正在运行一个新的 docker 容器,这可能是必要的。
*apt-get install git*
步骤 3)下载张量流模型
如果您没有模型的最新代码库,这里包含了 transformer,它们往往会非常频繁地更新。
*git clone [https://github.com/tensorflow/models.git](https://github.com/tensorflow/models.git)*
步骤 4)安装要求
作为一个必要的步骤,这将安装用于训练 TensorFlow 模型的 python 包需求。
*pip install --user -r official/requirements.txt*
步骤 5)导出 Pythonpath
将 PYTHONPATH 导出到机器上 models 文件夹所在的文件夹中。下面的命令引用了模型在我们系统中的位置。确保将'/数据集/模型语法替换为存储/下载模型的文件夹的数据路径。
*export PYTHONPATH="$PYTHONPATH:/datasets/datasets/models"*
步骤 6)下载并预处理数据集
data_download.py 命令将下载并预处理训练和评估 WMT 数据集。下载和提取后,训练数据用于生成我们将用作 VOCAB_FILE 变量的内容。实际上,eval 和 training 字符串被标记化,结果被处理并保存为 TFRecords。
注: ( 根据官方要求 ):将下载 1.75GB 的压缩数据。总的来说,原始文件(压缩的、提取的和组合的文件)占用 8.4GB 的磁盘空间。生成的 TFRecord 和词汇表文件为 722MB。运行该脚本大约需要 40 分钟,其中大部分时间用于下载,大约 15 分钟用于预处理。
*python data_download.py --data_dir=/datasets/datasets/transformer*
步骤 7)设置训练变量
'参数集'
这指定了要训练什么模型。【大】或【基】
I 重要提示:【大】 型号无法在大多数消费级 GPU 上工作,如 RTX 2080 Ti、GTX 1080 Ti。如果您需要训练 【大】 型号,我们推荐一个至少有 48 GB 可用 GPU 内存的系统,如配备 Quadro RTX 8000 的 数据科学工作站 ,或 2 个配备 NVLink 的 Qudaro RTX 6000。或者一个 泰坦 RTX 工作站 带 2x 泰坦 RTX(带 NVLink 桥)也应该足够了。对于这个例子,我们使用的是 RTX 2080 Ti,因此我们选择‘基础’。
**PARAM_SET=base**
'数据目录'
此变量应设置为训练数据所在的位置。
**DATA_DIR=$root/datasets/datasets/transformer**
‘型号 _ 目录’
该变量根据在‘参数设置’变量中指定的模型来指定模型位置
**MODEL_DIR=$root/datasets/datasets/transformer/model_$PARAM_SET**
‘VOCAB _ FILE’
该变量表示预处理 vocab 文件的位置。
**VOCAB_FILE=$DATA_DIR/vocab.ende.32768**
‘导出 _ 目录’导出训练好的模型
这将指定以 Tensorflow SavedModel 格式导出模型的时间/位置。这是在步骤 8 的训练中使用标志 export_dir 时完成的。
**EXPORT_DIR=$root/datasets/datasets/transformer/saved_model**
步骤 8)训练变压器网络
下面的命令' python transformer _ main . py '将训练变压器总共 260000 步。查看如何设置标志来引用您在前面步骤中设置的变量。可以少练 26 万步,由你决定。
****注意:这要花很长时间训练,取决于你的 GPU 资源。官方 TensorFlow transformer 模型正在不断开发中,请确保定期查看他们的 github,了解任何优化和技术,以减少训练时间。
**python transformer_main.py --data_dir=$DATA_DIR --model_dir=$MODEL_DIR --vocab_file=$VOCAB_FILE --param_set=$PARAM_SET --bleu_source=test_data/newstest2014.en --bleu_ref=test_data/newstest2014.de --train_steps=260000 --steps_between_evals=1000 --export_dir=$EXPORT_DIR**
步骤 9)在 Tensorboard 中查看结果
正如我们前面提到的,我们可以在 Tensorboard GUI 中检查训练的状态。要实时检查,请在单独的终端(或 TensorFlow 容器)中运行以下命令,并在浏览器中键入 localhost:6007 以查看 Tensorboard。您也可以等到培训完成后再使用当前容器。
**tensorboard --logdir=$MODEL_DIR**
您应该会看到类似下面的一些培训输出。






****
步骤 10)测试训练好的模型(将英语翻译成德语)
现在我们已经训练好了我们的网络,让我们使用 translate.py 来享受我们的劳动成果吧!在下面的命令中,将文本“hello world”替换为需要翻译的文本
**python translate.py --model_dir=$MODEL_DIR --vocab_file=$VOCAB_FILE \ --param_set=$PARAM_SET --text="hello world"**
上述命令的输出:
I 0411 18:05:23.619654 139653733598976 translate . py:150】翻译“hello world”:“hello Welt”
最后的想法
我们已经了解了变压器网络,它们是如何以及为什么如此有效。目前最先进的建筑,这个领域是一个活跃的自然语言处理研究领域。现在,您应该对训练变压器网络有了一个大致的了解,要更深入地了解训练变压器,请访问 TensorFlow github repo 中的官方变压器实现。我们希望你喜欢这个博客系列,现在就去做一些令人敬畏的事情吧!
检查变压器架构
本博客第 1 部分& 2 由 尼提什·阿加瓦尔 在 Exxact Corporation 的合作和赞助下撰写。
第 1 部分:开放 GPT 2 争议
“回收对世界没有好处。这对环境有害,对我们的健康有害,对我们的经济也有害。我没开玩笑。回收对环境没有好处。它对地球具有破坏性,是全球变暖的主要原因。回收对我们的健康没有好处。它会导致肥胖和心脏病、癌症等疾病。回收对我们的经济有害。它增加了产品的成本,进而增加了用该产品制造的所有东西的价格。回收对我们国家没有好处。我们为拥有世界上最先进、最高效的回收系统付出了巨大的代价。回收是对时间、能量、金钱和资源的巨大浪费。”**—open ai 的 GPT 2 模型
是的,这些不是某个试图在社交媒体上推广反回收宣言的反回收怪胎的话。这整件事是用一种语言模型……一种算法……一种人工智能写的,如果我们说得太粗鲁的话。
GPT-2 是一个生成模型,由 OpenAI 创建,在 40GB 的互联网上训练以预测下一个单词。OpenAI 发现这个模型太好了,以至于他们没有发布经过完全训练的模型——有人说这违反了他们让人工智能向所有人开放的创始格言——因为他们“担心该技术的恶意应用”。
我们在谈论哪些恶意应用程序?
开艾说,“我们还可以想象这些模型的应用出于的恶意目的,包括以下几种(或者其他我们还无法预料的应用):
- 产生误导性的新闻文章
- 在网上冒充他人
- 自动制作发布在社交媒体上的辱骂或伪造内容
- 自动制作垃圾邮件/网络钓鱼内容"
“但这种模式真的有那么好吗?”
还是说以上的担忧仅仅是某些偏执狂的观点?
这个模型并没有在算法前沿呈现一些大的飞跃。这只是该团队几个月前发布的 GPT 模型的放大版。
它确实展示了我们当前的语言建模技术在文本生成方面的能力。它是其前身的大规模升级版本。GPT-2 拥有高达 15 亿个参数(比最初的 GPT 多 10 倍),并根据来自 800 万个网站的文本进行训练。
一旦你把它与其他“流行的”生成语言模型相比较,你就能理解这个模型的功绩了。
但是首先说一句题外话——关于语言模型的一个非常简单的解释
语言模型旨在简洁地表示所观察文本的历史,以便预测下一个单词。所以,基本上只是学习预测单词。给模型一个提示,它会预测下一个单词,然后下一个单词,然后再下一个单词,很快它就会形成一个有意义的句子,把足够多的单词组合起来,你就有了一个连贯的段落,然后..几乎所有你想要的。
例如,只需观看这部于 2016 年年中发布的科幻短片,其剧本是由一个生成模型创建的,该模型使用 LSTM 建筑公司在大量科幻电影和电视节目的剧本上训练出来的:
他们让托马斯·米德蒂奇——硅谷的理查德——主演这部电影!!
或者这个哈利波特人工智能生成的同人小说怎么样,它在 2017 年底走红,并且:
正如你所看到的,这两个在质量上比 GPT-2 的例子差得多。Open AI 在他们的博客文章——中挑选并发布了一些更好的语言模型及其含义。
“ unicorn ”样本读起来像一份真正的科学新闻稿。“核材料盗窃”样本读起来像一个真实的新闻故事。“麦莉·赛勒斯入店行窃”样本读起来像是来自名人八卦网站的真实帖子。“ GPT-2 ”样本读起来像一个真正的 OpenAI 新闻稿。《勒苟拉斯和吉姆利》的样本读起来就像一本真正的奇幻小说。“内战家庭作业”读起来就像一份真正的优等生试卷。这个“ JFK 获奖感言”读起来像一个真正的政治家的演讲。“回收”样本读起来像真正的右翼熨平板。
不仅仅是这 8 个精选的例子。Open AI 还为我们提供了数百个原始 GPT-2 样本的转储,这可以让我们更清楚地了解模型的能力。
是的,它们中的每一个“读起来像”一些真实的人类生成的内容。但事实并非如此。
这篇文章认为,如果你略读文本,你会错过明显的荒谬之处。重点是 OpenAI 已经实现了在自动驾驶上通过针对人类的图灵测试的能力。因此,如果你没有真正集中注意力,只是浏览一下,你就不会发现这是由语言模型生成的。对于我上面提到的其他例子来说,这肯定不是真的。甚至“像正常的人类生成的内容一样阅读”也是一个巨大的壮举。
所以,是的。我要说这款真的不错。
不释放模型重量的影响
事实上,Open AI 没有发布这个模型对 AI 社区和媒体来说是一个巨大的冲击。
一些人认为这只是开放人工智能的一部分的宣传噱头,因为没有算法上的壮举。另一群人认为这种的尝试将是徒劳的,因为代码是开源的,愿意在计算资源上花足够多钱的大公司/人们将能够在短短几个月内复制结果。
但是还有另外一群人在为开放人工智能鼓掌,因为他们试图让研究人员意识到他们研究成果的影响。随着人工智能技术变得越来越强大,世界将面临一个重要的挑战,即打击合成内容和错误信息。
sou Smith chint ala 是 PyTorch 的创造者。这是他、杰克·克拉克和杰瑞米·霍华德之间的一根线!
所以知道它是如何工作的,知道驱动它的算法不是很酷吗?
第 2 部分:变压器工作原理的简要描述
变压器架构
这种架构最初是在 2017 年年中谷歌的开创性论文中提出的— 关注是你所需要的全部。
在这么短的时间内,这种架构已经在两篇论文中用于产生最先进的结果——一篇是 GPT/GPT-2,另一篇是伯特。

Table Source: Language Models are Unsupervised Multitask Learners, Radford et al. 2019
最小的一个对应于 GPT 模型;第二小的相当于 BERT 中最大的模型;最大的一个比第一个大一个数量级,对应于 GPT-2 模型
现在让我们来看看架构:

The Transformer architecture as present in the Attention is all you need paper by Google
首先,我们可以看到它有一个序列到序列的编码器-解码器架构。互联网上很多关于变形金刚的文献都是用这种架构来解释变形金刚的。但这不是 Open AI 的 GPT 模型(或 GPT-2 模型,只是其前身的更大版本)中使用的那种。
GPT 是一个只有 12 层解码器的变压器,有 117M 个参数。

Improving Language Understanding by Generative Pre-Training, Radford et al.
来自 Open AI 的 GPT 论文中使用的变压器架构
GPT(以及 GPT-2 的较小发布版本)有 12 层变形金刚,每层有 12 个独立的注意机制,称为“头”;结果是 12 x 12 = 144 种不同的注意力模式。这些注意力模式中的每一个都对应于模型捕捉到的一个语言属性。
正如我们在上面的 transformer 架构中看到的,注意力是 Transformer 的重要组成部分。事实上,这是一种保守的说法。注意力是使变压器工作的原因。那么,我们来简单介绍一下注意力。
注意力模型
RNN 单元将把直到时间戳 t 的输入编码到一个隐藏向量 ht 中,该隐藏向量然后将被传递到下一个时间戳(或者在序列到序列模型的情况下传递到解码器)。有了注意机制,我们不再试图将完整的源句子编码成固定长度的向量。相反,我们允许解码器在输出生成的每一步“关注”源句子的不同部分。重要的是,我们让模型学习根据输入的句子和它到目前为止产生的结果注意什么。
比方说,我们想翻译“1992 年欧洲经济区协议”。(法语)到英语哪个是“欧洲经济区协议是 1992 年 8 月签订的。”**
下图显示了注意力模型对它生成的每一个翻译单词的关注程度。

Image Source: jalammar.github.io
请注意,除了将“欧洲经济区”翻译为“欧洲经济区”之外,它几乎都是线性的。在这种情况下,它会正确地以相反的顺序出现。
这种能力允许注意力学习长程相关性。
与 RNN 的比较
如前所述,一些从业者认为我们正在见证 RNN/LSTM 的衰落。自 2014 年推出以来,它们一直是所有 NLP 任务的默认首选架构,包括语言建模、机器翻译、文本摘要、图像/视频字幕、语音到文本转换等。
但是 RNN 和它的变体有两个主要缺点:
- 未能记住长程相关性
RNNs 的主要吸引力之一是,他们能够使用他们对电影中先前事件的推理来通知后来的事件。但这也是他们的主要缺点之一。
rnn 需要将来自整个序列的信息编码在一个单独的上下文向量中。来源
解码器应该仅基于来自编码器的最后一个隐藏状态(h3)来生成翻译。这个向量必须编码我们需要知道的关于源句子的一切。它必须完全抓住它的意义。
随着两个单词之间的差距越来越大,RNN 人似乎“忘记”了前面的单词。
长短期记忆单元(LSTMs)和门控循环单元(gru)通过使用由门控制的记忆单元(/s)提供了一种粗略的解决方案,该记忆单元允许它们从更早的过去获取信息。
- 无法利用 GPU 的能力
rnn 不能并行处理输入。它们是带有环路的网络,允许信息持续存在。

Source: http://colah.github.io/posts/2015-08-Understanding-LSTMs/
在上图中,神经网络 A 的一个块查看某个输入 xt 并输出一个值 ht。环路允许信息从网络的一个步骤传递到下一个步骤。这意味着它们一次只能处理一个输入单元。
这就是为什么他们不能利用非常强大的 GPU 的并行计算能力。这种图形处理器允许 CNN 对大量数据进行训练,并增长到绝对巨大的规模。rnn 或
lstm 或其任何变体天生不擅长利用这种手段。
变形金刚擅长这两项任务。
深度学习工作站 来自 Exxact 特色Quadro RTX 8000非常适合训练甚至大型变压器模型。每个Quadro RTX 8000拥有 48 GB GPU 内存,一对可以通过 NVLink 连接,从而提供 96 GB 的总 GPU 内存,以适应大规模的变压器型号。**
预训练语言模型—自然语言处理中的迁移学习
Transformer 架构允许创建在绝对庞大的数据集上训练的 NLP 模型,正如我们在本文中看到的。这样的模型不可能被所有人训练,就像你不会期望在 ImageNet 数据集上从头训练一个 VGG 网一样。因此,预训练语言模型的时代到来了。
通过这种大规模预训练模型学习的权重可以在以后通过针对特定数据集进行微调来重新用于特定任务。这将允许我们通过捕捉语言的底层复杂性并简单地“插入”它以适应我们的特定任务来进行迁移学习。
变形金刚是 NLP 的下一个前沿。在不到几年的时间里,这种新的建筑趋势已经超越了 RNN 建筑的成就。这种令人兴奋的发明步伐可能是早期进入深度学习这样一个新领域的最好部分!
第 3 部分:在 Docker 中从头开始训练变压器网络
本教程的培训将在我们的 Exxact Valence 工作站上使用英伟达 RTX 2080 Ti 完成。此外,我们将使用位于官方 TensorFlow GitHub 上这里的 transformer 模型实现创建一个英语到德语的翻译器。假设您已经满足了 TensorFlow GPU 的所有必要依赖项,我们提供了一个简单的教程指南,用于在 docker 中开始使用 transformers。
步骤 1)启动 TensorFlow GPU Docker 容器
使用 Docker 可以让我们为我们的培训需求构建一个完全包含的环境。我们总是推荐使用 Docker,因为它允许我们的培训环境有最大的灵活性(和宽容)。首先,我们将打开一个终端窗口,输入以下命令来启动我们的 NVIDIA CUDA 驱动的容器。
*nvidia-docker run -it -p 6007:6006 -v /data:/datasets tensorflow/tensorflow:nightly-gpu bash*
注意:上面命令的关键参数的快速描述(如果你不熟悉 Docker)。

步骤 2)安装 git
如果您正在运行一个新的 docker 容器,这可能是必要的。
*apt-get install git*
步骤 3)下载张量流模型
如果您没有模型的最新代码库,这里包含了 transformer,它们往往会非常频繁地更新。
*git clone [https://github.com/tensorflow/models.git](https://github.com/tensorflow/models.git)*
步骤 4)安装要求
作为一个必要的步骤,这将安装用于训练 TensorFlow 模型的 python 包需求。
*pip install --user -r official/requirements.txt*
步骤 5)导出 Pythonpath
将 PYTHONPATH 导出到机器上 models 文件夹所在的文件夹中。下面的命令引用了模型在我们系统中的位置。确保将'/数据集/模型语法替换为存储/下载模型的文件夹的数据路径。
*export PYTHONPATH="$PYTHONPATH:/datasets/datasets/models"*
步骤 6)下载并预处理数据集
data_download.py 命令将下载并预处理训练和评估 WMT 数据集。下载和提取后,训练数据用于生成我们将用作 VOCAB_FILE 变量的内容。实际上,eval 和 training 字符串被标记化,结果被处理并保存为 TFRecords。
注: ( 根据官方要求 ):将下载 1.75GB 的压缩数据。总的来说,原始文件(压缩的、提取的和组合的文件)占用 8.4GB 的磁盘空间。生成的 TFRecord 和词汇表文件为 722MB。运行该脚本大约需要 40 分钟,其中大部分时间用于下载,大约 15 分钟用于预处理。
*python data_download.py --data_dir=/datasets/datasets/transformer*
步骤 7)设置训练变量
'参数集'
这指定了要训练什么模型。【大】或【基】
I 重要提示:【大】 型号无法在大多数消费级 GPU 上工作,如 RTX 2080 Ti、GTX 1080 Ti。如果您需要训练 【大】 型号,我们推荐一个至少有 48 GB 可用 GPU 内存的系统,如配备 Quadro RTX 8000 的 数据科学工作站 ,或 2 个配备 NVLink 的 Qudaro RTX 6000。或者一个 泰坦 RTX 工作站 带 2x 泰坦 RTX(带 NVLink 桥)也应该足够了。对于这个例子,我们使用的是 RTX 2080 Ti,因此我们选择‘基础’。
**PARAM_SET=base**
'数据目录'
此变量应设置为训练数据所在的位置。
**DATA_DIR=$root/datasets/datasets/transformer**
‘型号 _ 目录’
该变量根据在‘参数设置’变量中指定的模型来指定模型位置
**MODEL_DIR=$root/datasets/datasets/transformer/model_$PARAM_SET**
‘VOCAB _ FILE’
该变量表示预处理 vocab 文件的位置。
**VOCAB_FILE=$DATA_DIR/vocab.ende.32768**
‘导出 _ 目录’导出训练好的模型
这将指定以 Tensorflow SavedModel 格式导出模型的时间/位置。这是在步骤 8 的训练中使用标志 export_dir 时完成的。
**EXPORT_DIR=$root/datasets/datasets/transformer/saved_model**
步骤 8)训练变压器网络
下面的命令' python transformer _ main . py '将训练变压器总共 260000 步。查看如何设置标志来引用您在前面步骤中设置的变量。可以少练 26 万步,由你决定。
****注意:这要花很长时间训练,取决于你的 GPU 资源。官方 TensorFlow transformer 模型正在不断开发中,请确保定期查看他们的 github,了解任何优化和技术,以减少训练时间。
**python transformer_main.py --data_dir=$DATA_DIR --model_dir=$MODEL_DIR --vocab_file=$VOCAB_FILE --param_set=$PARAM_SET --bleu_source=test_data/newstest2014.en --bleu_ref=test_data/newstest2014.de --train_steps=260000 --steps_between_evals=1000 --export_dir=$EXPORT_DIR**
步骤 9)在 Tensorboard 中查看结果
正如我们前面提到的,我们可以在 Tensorboard GUI 中检查训练的状态。要实时检查,请在单独的终端(或 TensorFlow 容器)中运行以下命令,并在浏览器中键入 localhost:6007 以查看 Tensorboard。您也可以等到培训完成后再使用当前容器。
**tensorboard --logdir=$MODEL_DIR**
您应该会看到类似下面的一些培训输出。






****
步骤 10)测试训练好的模型(将英语翻译成德语)
现在我们已经训练好了我们的网络,让我们使用 translate.py 来享受我们的劳动成果吧!在下面的命令中,将文本“hello world”替换为需要翻译的文本
**python translate.py --model_dir=$MODEL_DIR --vocab_file=$VOCAB_FILE \ --param_set=$PARAM_SET --text="hello world"**
上述命令的输出:
I 0411 18:05:23.619654 139653733598976 translate . py:150】翻译“hello world”:“hello Welt”
最后的想法
我们已经了解了变压器网络,它们是如何以及为什么如此有效。目前最先进的建筑,这个领域是一个活跃的自然语言处理研究领域。现在,您应该对训练变压器网络有了一个大致的了解,要更深入地了解训练变压器,请访问 TensorFlow github repo 中的官方变压器实现。我们希望你喜欢这个博客系列,现在就去做一些令人敬畏的事情吧!
原载于 2019 年 5 月 29 日https://blog.exxactcorp.com。**
在 Tensorflow 2 中检查 LSTM 的权重和偏差
张量流 2 中 LSTM 权重和偏差混淆结构的解释

source: https://dnacentre.co.uk/wp-content/uploads/2018/04/blog-uk-genetic-engineering.png
好,首先,什么是 LSTM?LSTM 是长短期记忆的缩写。它是递归神经网络(RNN)中应用最广泛的一种。基本上, RNN 将时间序列数据作为输入。时间序列中的每一个数据从最早的时间步长开始依次成为 RNN 的输入。某个时步输入的 RNN 输出将与下一个时步的数据一起作为 RNN 的输入。当 RNN 处理完数据的最后一个时间步长时,将输出实际输出。

How the RNN process the input
LSTM 的神经元结构是这样的:

在时间步长的每个过程中,LSTM 有 4 层神经元。这 4 层一起形成一个称为门的处理称为遗忘门- >输入门- >输出门(- >表示序列处理在 LSTM 中发生的顺序)。那就是 LSTM,我不会涉及 LSTM 的细节,因为那会是一篇很长的文章,而且这不是我这次的重点。
长话短说,为了我最近的实验,我需要取回我的 LSTM 的重量和偏差。我用 TensorFlow 2 建立了一个 LSTM。在 TensorFlow 2 中,我们可以使用下面的代码访问 LSTM 权重和偏差的结构。
import tensorflow as tfsimple_lstm_model = tf.keras.models.Sequential()
simple_lstm_model.add(tf.keras.Input((18,7)))
simple_lstm_model.add(tf.keras.layers.LSTM(2))print(simple_lstm_model.layers[0].trainable_weights)
在上面的代码中,我构建了一个接受 18 x 7 形状输入的 LSTM。18 是数据的总时间步长,7 是参数的总数。对于每个时间步长,LSTM 将采用 7 个参数。我声明这个 LSTM 有两个隐藏状态。隐藏状态就像每个时间步长的 LSTM 输出。这意味着我们的 LSTM 最终将输出 2 个实数。这也意味着,LSTM中每层神经元的数量是 2。当您运行这个脚本时,您将得到如下输出。
[<tf.Variable 'lstm/kernel:0' shape=(7, 8) dtype=float32>, <tf.Variable 'lstm/recurrent_kernel:0' shape=(2, 8) dtype=float32>, <tf.Variable 'lstm/bias:0' shape=(8,) dtype=float32>]
好了,这里我们有 3 组参数,它由 lstm/kernel(形状为 7x8)、lstm/recurrent_kernel(形状为 2x8)和 lstm/bias(形状为 8)组成。最后一部分(lstm/bias)很明显,就是偏见。为什么我们有 8 个?记住,在 LSTM 中我们有 4 层神经元,我声明这个 LSTM 有 2 个隐藏状态,或者说每层有 2 个神经元。每个神经元有 1 个偏差,4 层中的每层有 2 个神经元,所以总数是 8。
容易混淆的部分是 lstm/kernel 和 lstm/recurrent_kernel。内核在这里的意思是重量。lstm/kernel 表示我们的输入相对于 lstm 每个神经元的权重。我声明输入有 18 个时间步长和 7 个参数,所以每个参数对每个神经元有 1 个权重,这就是 lstm/kernel 的形状为 7x8 的原因。最后, lstm/recurrent_kernel 表示我们的隐藏状态的权重,也称为 lstm 在前一时间步(t-1)相对于 LSTM 中每个神经元的输出。我声明隐藏状态是 2,LSTM 的总神经元是 8 ,那么隐藏状态对 LSTM 神经元层的权重形状一定是 2×8。
这就是关于 LSTMin TensorFlow 2 的权重和偏差的解释。您还可以使用 summary()函数看到整个神经网络的结构,如下所示。
import tensorflow as tfsimple_lstm_model = tf.keras.models.Sequential()
simple_lstm_model.add(tf.keras.Input((18,7)))
simple_lstm_model.add(tf.keras.layers.LSTM(2))
simple_lstm_model.add(tf.keras.layers.Dense(5))simple_lstm_model.summary()
输出是
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
lstm (LSTM) (None, 2) 80
_________________________________________________________________
dense (Dense) (None, 5) 15
=================================================================
Total params: 95
Trainable params: 95
Non-trainable params: 0
这里我将之前的 LSTM 和一个普通的神经网络层叠加在一起。这个网络的最终输出有 5 个元素。这个堆叠式神经网络的总权重和偏差为 95。
就这些了,下期帖子见。
参考:
https://medium . com/ai-journal/lstm-gru-recurrent-neural-networks-81 Fe 2 BCD f1 f 9,2019 年 12 月 15 日获取
https://colah.github.io/posts/2015-08-Understanding-LSTMs/,2019 年 12 月 15 日进入
数据科学流程中 Docker 的使用案例示例
…或者如何避免“它只在我的电脑上工作,却不在别的地方工作”的问题

Jeff Lofvers 的精彩漫画展示了你在软件开发和数据科学中经常遇到的问题。您正在准备一个数据分析或预测模型,但是当您想要共享它时,它在其他人的机器上无法工作。它失败了,因为库丢失了,库有错误的版本(“依赖地狱”),或者配置不同。耗时的故障排除开始了。
解决方案并不遥远: Docker 以一种轻量级的方式解决了再现性的问题,而且还为您提供了许多其他的优势。
什么是 Docker?
Docker 是一个执行操作系统级虚拟化的免费软件。Docker 习惯于运行被称为容器的软件包。容器相互隔离,并将它们的应用程序、工具、库和配置文件捆绑在一起。所有容器都由一个操作系统内核运行,因此比虚拟机更轻量级。[ 维基百科上的 Docker
Docker 使创建、运行和分发应用程序变得容易。应用程序打包了运行应用程序所需的一切。这个概念保证了容器可以在每个 docker 运行时环境中运行。
码头工人的优点:
再现性
使用 Docker,您可以确保您的软件产品(应用程序、数据分析、预测模型等)。)运行在所有 docker 运行时环境上。你的货件更结实,因为集装箱里装着运行你的人工制品所需的一切。您不仅分发代码,还分发环境。
一致性
Docker 为各种软件产品提供了一个统一一致的运行时环境。它减少了系统管理的时间,让您专注于核心工作。你可能知道 Anaconda 环境;Docker 对于整个软件生态系统来说是类似的东西。
可追溯性
a.)Docker 容器代码的版本控制
Docker 容器是从一个脚本构建的,该脚本是必要的软件依赖关系和环境的可读摘要。这个脚本可以进行版本控制。这个脚本完全可以通过这种方式追踪。
b.)所有人工制品的统一分配环境
Docker 容器可以存储在组织内部的存储库中。你用这种方式保存整个版本历史。
便携性
Docker 容器可以很容易地从一个 docker 环境移植到另一个环境。Docker Swarm (或 Kubernetes )让你自动扩展应用程序。这样可以降低系统管理和操作的成本。
然而,Docker 在数据科学领域有哪些用例?我将专注于数据科学 OSEMN 流程:

数据科学流程中 Docker 的用例
今天的现实是,这个过程由各种各样的工具和编程语言组成。Docker 是管理这些异构技术堆栈的首选平台,因为每个容器都提供了运行它所需要的运行时环境,以运行它所包装的应用程序。这样就减少了技术堆栈的干扰。
1.获取:从相关来源收集数据
数据是数据科学的润滑油。例如,您可以从调查、临床试验、网络搜索、科学实验、企业应用或模拟中检索信息。通常情况下,数据工程师处理数据,但其他利益相关者也参与其中,这导致了数据库系统和编程语言的广泛多样性。
- Web 抓取:Python 应用程序与 Selenium 的 Chrome 驱动程序和 Postgres 数据库之间存在底层依赖关系,通过 Docker Compose 打包成一个多容器应用程序
- 标记图像:使用 vue.js、NodeJS 后端和 MongoDB 的精益 web 应用程序来标记图像
- 调查:小型静态微型网站,由营销团队用纯 HTML 构建,带有集成的 SurveyMonkey 表单
- 企业应用程序:在后台用 AngularJS 和 Java 实现的银行 web 应用程序使用 Oracle 数据库从客户那里产生有价值的银行数据
- 计算机模拟:用 C++编程的模拟将结果存储在亚马逊 S3 的 JSON 中
- 异步数据流:汽车传感器向 Kafka 发送数据,Kafka 在公司内部分发数据
所有这些技术栈都可以在 Docker 容器中独立运行。
2.清理:将数据清理和聚合成机器能够理解的格式
步骤 1 中获得的数据是石油,但现在是原油。你需要清理、处理它,并把它结合成你分析和建模所需的数据。
- 聚合:Java 应用程序从 Kafka 流中获取数据,对底层数据进行聚合,并将其存储到 Oracle 数据库中
- 数据分析师清理并预处理来自企业 web 应用程序的数据,为用 RMarkdown 笔记本回答业务问题做准备,他们希望与管理层分享这些数据
- 机器学习工程师组合来自不同数据源的数据,为 Jupyter 笔记本中的预测模型清理和预处理数据
- 在 Tableau 中,对数据进行组合、清理、聚合、预处理和持久化,以用于高级交互式仪表盘
这些用例中的一些可能已经在数据检索步骤中完成,并且有更多的数据工程技术栈。其他用例与探索和建模阶段重叠,并涉及更典型的数据分析技术。
许多数据分析工作都是在需要发布的笔记本(Jupyter,RMarkdown)上完成的。您可以为组织使用中央 Jupyter 实例。这种方法的问题是,您可能会被固定的配置和库版本所困扰。另一种方法是发布一个或多个带有 Docker 容器的笔记本。这样你就可以更加灵活地使用特定的设置。
3.探索:寻找模式和趋势
在探索阶段,你要做的就是了解数据手中有什么模式和价值。你想让所有感兴趣的人都能看到结果。
- 数据分析师正在创建 Jupyter 或 RMarkdown 笔记本,以回答一个他们需要与所有感兴趣的人分享的问题。
- 数据分析师将公司的客户分成新的细分市场,这些细分市场保存在 MySQL 的客户细分市场数据库中
- 数据分析师为 RShiny、Dash、Tableau 或 Kibana 中感兴趣的利益相关者构建交互式 web 应用程序,用于高级数据探索。这样管理人员可以自己找到模式(危险区域!).
4.模型:构建模型以进行预测和预报
经过清理和预处理的数据用于训练机器或深度学习算法。你以这种方式创建模型,这些模型是观察数据的数学表示。它们可以用来预测、预报和量化不可言喻的事物。
- 用于图像中对象检测的神经网络的完整训练过程被隔离到运行在 Azure、AWS 或 Google Cloud 上的 Docker 容器中
- 由于 Python 的性能问题,Keras 模型被导入到 DeepLearning4J 中,并作为 Java 微服务发布
为了训练神经网络,你需要大量的 GPU 能力。您需要 Nvidia Docker 将训练过程隔离到 Docker 容器中,因为使用 GPU 无法以硬件和平台无关的方式完成。
5.解释:将结果充分利用
数据科学见解得到交流和可视化。模型作为微服务分发。
- 微型网站讲述数据故事
- Python 中的预测机器学习模型作为微服务发布
- 带有聚合数据的 Java REST 微服务向付费 B2B 客户发布
- Python 中的产品推荐服务被集成到该公司的网络应用程序中
- 数据驱动的故事发布在公司的 Tableau 服务器上,供内部和外部使用
- 内容管理团队中的数据故事讲述者在静态 Jekyll 网站上分享来自数据分析师的激动人心的见解
结论
Docker 对于数据科学家来说也是一个强大的工具,可以应用于 OSEMN 流程的所有阶段。你可以以一致、可复制和可追踪的方式运送所有种类的人工制品。工件在其技术栈中可能非常不同,这是数据科学项目中的现实。数据工程师使用 Oracle、MySQL、MongoDB、Redis 或 ElasticSearch 等数据库或 Java、Python 或 C++等编程语言。在分析和建模团队中,人们可能会使用 R、Python、Julia 或 Scala,而数据故事讲述者则用 JavaScript 中的 d3.js 或使用 Tableau 来讲述他们的故事。由于专家很少,最好让他们使用熟悉的技术,而不是将他们推向未知的领域。你会更快得到更好的结果。
Docker 是管理数据科学中异构技术环境的好方法。
参考
how to:Docker 容器中的 Tableau Server Linux
教程:为数据科学运行 Dockerized Jupyter 服务器 Kafka-Docker:使用 Docker 运行 Apache Kafka 的步骤
带有 Chromedriver 和 Geckodriver 的 Docker 图像
由延斯·劳弗于 2019 年 4 月 4 日撰写
随意分享!
原载于 2019 年 4 月 4 日jenslaufer.com。
Excel 与 SQL:概念上的比较
一位经验丰富的 Excel 用户对 SQL 的看法以及为什么它值得学习。

介绍
我已经在数据分析领域工作了大约 3 年。作为一名医疗保健分析师,我已经在这个领域工作了两年多,最近我完成了数据科学专业的 MBA 课程。
在读硕士期间,我对使用 python 的预测建模技术特别感兴趣(现在仍然如此)。然而,从基本的组织/分析/报告的角度来看,我对使用 Excel 最得心应手。一天花 60-80%的时间盯着 Excel 电子表格对我来说并不陌生。Excel GUI 中嵌套的选项卡、功能区、分组和工具是我的乐队的乐器。他们制造声音,但我指挥并将旋律和和声转化为报告、交付物和分析。在咨询项目、个人预算和兼职工作中,Excel 一直是我的首选工具。
我很早就知道 SQL 及其基本概念。然而,直到最近,由于专业原因,我才决定认真学习它。从一个 Excel 用户的角度来看,SQL 有起有落。在本文中,我希望通过与 Excel 的比较来传达 SQL 的本质和用法。
它们是什么?
Excel 是一个程序。SQL 是一种语言。这是一条需要消化的非常重要的信息。只有点击绿色图标并运行程序后,才能使用 Excel。另一方面,SQL 可以用来与数据库程序进行交互和通信。几个最受欢迎的:
- 神谕
- 关系型数据库
- Microsoft SQL Server
我学习 SQL 的方式是通过 Google 的大查询。通过免费分析 Google cloud 上的大型数据库来学习/使用 SQL 是一种有趣的方式。
数据在哪里?
擅长
Excel 是典型的电子表格工具。你把你的数据保存在你电脑上的一个文件里,它通常被组织在标签、列和行里。excel 文件位于您计算机的本地。你直接与它互动。没有中间人。没有管理员。当然,使用 API 从另一个位置获取数据是可能的;然而,数据最终是你的,你想怎么做就怎么做。如果几个人正在协作 Excel 工作簿,这使得跟踪更改变得很困难……确实有可能跟踪更改,但是不太方便。
结构化查询语言
SQL 是一种与数据库交互的语言。它代表结构化查询语言。在这种情况下,您的数据又前进了一步。您用 SQL 编写并向数据库发送查询,数据库接收这些查询,然后给出您的请求或进行更改。数据存储在数据库中,并通过表格进行组织。查询的美妙之处在于它更具协作性和可追溯性。这些查询可以追溯到谁对哪个表做了什么更改。用户还可以保存有用的查询并与其他人共享,以供将来使用或进行协作。
基于“bikeid”在大型查询中过滤“austin_bikeshare”表,然后按“duration_minutes”对选择进行排序的查询示例。
SELECT
duration_minutes
FROM
`bigquery-public-data.austin_bikeshare.bikeshare_trips`
Where
bikeid = "446"
ORDER BY
duration_minutes desc
一旦你知道语法是如何工作的,使用 SQL 操作数据会比使用 Excel 快得多。另一个很棒的方面是它的语法与英语相似,这使得它可以说是最容易学习的计算机语言。
它们的最佳用途是什么?
擅长
- 较小的数据集:少于 100 万行,甚至超过 100,000 行将会降低你的计算机速度。
- 手动输入数据
- 更灵活的结构:任何单元格都可以是任何数据类型,不管它在哪个列中。
- 输出图表和可视化
- 内置的拼写检查和其他有用的功能
- 独立完成一个项目
结构化查询语言
- 更大的数据集:取决于软件和数据库,这可能非常非常大。不会像 Excel 那样变慢。
- 组织/结构:SQL 表对一致的数据类型有更严格的要求,如果用户试图输入错误的类型,就会受到限制。
- 协作工作
- 为在另一个软件中进一步分析准备数据
- 一致的报告或计算:如前所述,您可以保存和共享查询。
- 更安全,因为更改总是可跟踪和可审计的。
结论

当我第一次学习 SQL 中的 JOIN 子句时,我最初的本能反应是将其标记为无关紧要,因为我已经知道如何在 Excel 中使用 Vlookups。后来我保持了一段时间的这种态度,但是随着我继续上课,现实情况开始出现。当我了解到 JOIN 子句是多么简单和有用时,我想起了 Vlookups 在执行大量行时所花费的时间。我记得如果你在运行计算后不粘贴值,他们会使文件成倍地变大。我还记得一次只带来一个值是多么有限…在我学习的整个过程中,当我比较 SQL 和 Excel 时,也经历了类似的教训。
总之,在数据分析方面,这两种工具都有自己的位置。两者都有其独特的用途,了解两者对经常使用数据的人都有好处。然而,根据我的经验和对该主题的研究,SQL 是数据分析师更需要和有用的技能。Excel 非常适合小企业主、顾问和学生。SQL 更适合分析师和数据科学家。
我在 SQL 学习过程中使用的一些有用资源:
SQL For Data Science With Google Big Query
如果您觉得这很有帮助,请订阅。如果你喜欢我的内容,下面是我参与的一些项目:
HiveQL/SQL 脚本完成的自动电子邮件通知
自动将产量提高 2-3 倍

Stock image from RawPixel.com.
如果你觉得这篇文章有任何帮助,请评论或点击左边的掌声按钮给我免费的虚拟鼓励!
动机
这个脚本对于执行 HiveQL 文件(.hql)或者 SQL 文件(.sql)非常有用。例如,这个脚本提供了电子邮件通知以及所涉及的 Hive/SQL 操作所需的时钟时间记录,而不是必须定期检查CREATE TABLE或JOIN何时结束。这对于连夜完成一系列 Hive/SQL 连接以便第二天进行分析特别有用。
剧本
答作为一名实践中的数据科学家,当我只是为了自己的目的而寻找代码进行回收和修改时,我不喜欢过度解释的琐碎片段,所以请找到下面的脚本。如果除了代码注释之外,你还想了解更多关于脚本的解释,请参见最后的附录。对bash的充分解释、它在位级的转换、HiveQL/SQL 和数据库引擎超出了本文的范围。正如所写的那样,下面的脚本仅在复制粘贴时适用于 HiveQL。您必须对它做一些小的修改,以便与您的 SQL 发行版一起工作。例如,如果使用 MySQL,将hive -f改为mysql source。也可以让脚本向多个电子邮件地址发送电子邮件。
#!/bin/bash
## By Andrew Young
## Contact: andrew.wong@team.neustar
## Last modified date: 13 Dec 2019################
## DIRECTIONS ##
################
## Run the following <commands> without the "<" or ">".
## <chmod u+x scriptname> to make the script executable. (where scriptname is the name of your script)
## To run this script, use the following command:
## ./<yourfilename>.sh#################################
## Ask user for Hive file name ##
#################################
echo Hello. Please enter the HiveQL filename with the file extension. For example, 'script.hql'. To cancel, press 'Control+C'. For your convenience, here is a list of files in the present directory\:
ls -l
read -p 'Enter the HiveQL filename: ' HIVE_FILE_NAME
#read HIVE_FILE_NAME
echo You specified: $HIVE_FILE_NAME
echo Executing...######################
## Define variables ##
######################
start="$(date)"
starttime=$(date +%s)#####################
## Run Hive script ##
#####################
hive -f "$HIVE_FILE_NAME"#################################
## Human readable elapsed time ##
#################################
secs_to_human() {
if [[ -z ${1} || ${1} -lt 60 ]] ;then
min=0 ; secs="${1}"
else
time_mins=$(echo "scale=2; ${1}/60" | bc)
min=$(echo ${time_mins} | cut -d'.' -f1)
secs="0.$(echo ${time_mins} | cut -d'.' -f2)"
secs=$(echo ${secs}*60|bc|awk '{print int($1+0.5)}')
fi
timeelapsed="Clock Time Elapsed : ${min} minutes and ${secs} seconds."
}################
## Send email ##
################
end="$(date)"
endtime=$(date +%s)
secs_to_human $(($(date +%s) - ${starttime}))subject="$HIVE_FILE_NAME started @ $start || finished @ $end"
## message="Note that $start and $end use server time. \n $timeelapsed"## working version:
mail -s "$subject" youremail@wherever.com <<< "$(printf "
Server start time: $start \n
Server end time: $end \n
$timeelapsed")"#################
## FUTURE WORK ##
#################
# 1\. Add a diagnostic report. The report will calculate:
# a. number of rows,
# b. number of distinct observations for each column,
# c. an option for a cutoff threshold for observations that ensures the diagnostic report is only produced for tables of a certain size. this can help prevent computationally expensive diagnostics for a large table
#
# 2\. Option to save output to a text file for inclusion in email notification.
#################
脚本解释
在此,我将解释脚本每一部分的代码。
################
## DIRECTIONS ##
################
## Run the following <commands> without the "<" or ">".
## <chmod u+x scriptname> to make the script executable. (where scriptname is the name of your script)
## To run this script, use the following command:
## ./<yourfilename>.sh
chmod是代表“改变模式”的bash命令我用它来改变文件的权限。它确保您(所有者)被允许在您正在使用的节点/机器上执行您自己的文件。
#################################
## Ask user for Hive file name ##
#################################
echo Hello. Please enter the HiveQL filename with the file extension. For example, 'script.hql'. To cancel, press 'Control+C'. For your convenience, here is a list of files in the present directory\:
ls -l
read -p 'Enter the HiveQL filename: ' HIVE_FILE_NAME
#read HIVE_FILE_NAME
echo You specified: $HIVE_FILE_NAME
echo Executing...
在本节中,我使用命令ls -l列出与保存我的脚本的.sh文件相同的目录(即“文件夹”)中的所有文件。read -p用于保存用户输入,即您想要运行的.hql或.sql文件的名称,保存到一个变量中,稍后在脚本中使用。
######################
## Define variables ##
######################
start="$(date)"
starttime=$(date +%s)
这是记录系统时钟时间的地方。我们将两个版本保存到两个不同的变量:start和starttime。
start="$(date)"保存系统时间和日期。
starttime=$(date +%s)保存系统时间和日期,以数字秒为单位,从 1900 开始偏移。第一个版本稍后在电子邮件中使用,以显示 HiveQL/SQL 脚本开始执行的时间戳和日期。第二个用于计算经过的秒数和分钟数。这为在您提供的 HiveQL/SQL 脚本中构建表所花费的时间提供了一个方便的记录。
#################################
## Human readable elapsed time ##
#################################
secs_to_human() {
if [[ -z ${1} || ${1} -lt 60 ]] ;then
min=0 ; secs="${1}"
else
time_mins=$(echo "scale=2; ${1}/60" | bc)
min=$(echo ${time_mins} | cut -d'.' -f1)
secs="0.$(echo ${time_mins} | cut -d'.' -f2)"
secs=$(echo ${secs}*60|bc|awk '{print int($1+0.5)}')
fi
timeelapsed="Clock Time Elapsed : ${min} minutes and ${secs} seconds."
}
这是一个复杂的解码部分。基本上,有很多代码做一些非常简单的事情:找出开始和结束时间之间的差异,都是以秒为单位,然后将经过的时间以秒为单位转换为分和秒。例如,如果工作需要 605 秒,我们将它转换为 10 分 5 秒,并保存到一个名为timeelapsed的变量中,以便在我们发送给自己和/或各种利益相关者的电子邮件中使用。
################
## Send email ##
################
end="$(date)"
endtime=$(date +%s)
secs_to_human $(($(date +%s) - ${starttime}))subject="$HIVE_FILE_NAME started @ $start || finished @ $end"
## message="Note that $start and $end use server time. \n $timeelapsed"## working version:
mail -s "$subject" youremail@wherever.com <<< "$(printf "
Server start time: $start \n
Server end time: $end \n
$timeelapsed")"
在本节中,我再次以两种不同的格式将系统时间记录为两个不同的变量。我实际上只用了其中一个变量。我决定保留未使用的变量,endtime,以备将来对这个脚本的扩展。电子邮件通知中使用变量$end来报告 HiveQL/SQL 文件完成时的系统时间和日期。
我定义了一个变量subject,不出所料,它成为了电子邮件的主题行。我注释掉了message变量,因为我无法使用printf命令在邮件正文中正确地用新行替换\n。我把它留在原处,因为我想让您可以根据自己的目的编辑它。
mail是一个发送邮件的程序。你可能会有它或类似的东西。mail还有其他选项,如mailx、sendmail、smtp-cli、ssmtp、S waks 等多个选项。这些程序中的一些是彼此的子集或衍生物。
未来的工作
本着合作和进一步努力的精神,以下是对未来工作的一些想法:
- 允许用户指定 HiveQL/SQL 文件的目录,在其中查找要运行的目标文件。一个使用案例是,用户可能根据项目/时间将他们的 HiveQL/SQL 代码组织到多个目录中。
- 改进电子邮件通知的格式。
- 通过自动检测是否输入了 HiveQL 或 SQL 脚本,以及如果是后者,是否有指定分布的选项(即 OracleDB、MySQL 等),增加脚本的健壮性。).
- 为用户添加选项,以指定是否应将查询的输出发送到指定的电子邮件。用例:为探索性数据分析(EDA)运行大量 SELECT 语句。例如,计算表中每个字段的不同值的数量,查找分类字段的不同级别,按组查找计数,数字汇总统计,如平均值、中值、标准偏差等。
- 添加选项,让用户在命令行指定一个或多个电子邮件地址。
- 添加一个选项,让用户指定多个
.hql和/或.sql文件按顺序或并行运行。 - 添加并行化选项。用例:你的截止日期很紧,不需要关心资源利用或同事礼仪。我需要我的结果!
- 添加计划代码执行的选项。可能以用户指定的
sleep的形式。用例:您希望在生产代码运行期间以及在工作日集群使用率较高时保持礼貌并避免运行。 - 通过标志使上述一个或多个选项可用。这将是非常酷的,但也有很多工作只是为了添加顶部的粉末。
- 更多。
新手教程
- 打开您喜欢的任何命令行终端界面。例子包括 MacOS 上的终端和 Windows 上的 Cygwin 。MacOS 已经安装了终端。在 Windows 上,你可以在这里 下载 Cygwin 。
- 导航到包含您的
.hql文件的目录。例如,输入cd anyoung/hqlscripts/来改变你当前的工作目录到那个文件夹。这在概念上相当于双击一个文件夹来打开它,只是这里我们使用的是基于文本的命令。 nano <whateverfilename>.sh
nano是一个命令,它打开一个同名的程序,并要求它创建一个名为<whateverfilename>.sh
的新文件。要修改这个文件,使用相同的命令。- 复制我的脚本并粘贴到这个新的
.sh文件中。将我的脚本中的收件人电子邮件地址从youremail@wherever.com更改为您的。 bash <whateverfilename>.sh
Bash 使用扩展名为.sh的文件。这个命令要求程序bash运行扩展名为.sh的“shell”文件。运行时,该脚本将输出与 shell 脚本位于同一目录中的所有文件的列表。这个列表输出是我为了方便而编写的。- 漫威在你的生产力增益!
关于作者
安德鲁·杨是 Neustar 的 R&D 数据科学家经理。例如,Neustar 是一家信息服务公司,从航空、银行、政府、营销、社交媒体和电信等领域的数百家公司获取结构化和非结构化的文本和图片数据。Neustar 将这些数据成分结合起来,然后向企业客户出售具有附加值的成品,用于咨询、网络安全、欺诈检测和营销等目的。在这种情况下,Young 先生是 R&D 一个小型数据科学团队的实践型首席架构师,该团队构建为所有产品和服务提供信息的系统,为 Neustar 带来超过 10 亿美元的年收入。
附录
创建 HiveQL 脚本
运行上述 shell 脚本的先决条件是要有一个 HiveQL 或 SQL 脚本。下面是一个 HiveQL 脚本示例,example.hql:
CREATE TABLE db.tb1 STORED AS ORC AS
SELECT *
FROM db.tb2
WHERE a >= 5;CREATE TABLE db.tb3 STORED AS ORC AS
SELECT *
FROM db.tb4 a
INNER JOIN db.tb5 b
ON a.col2 = b.col5
WHERE dt >= 20191201 AND DOB != 01-01-1900;
注意,在一个 HiveQL/SQL 脚本中可以有一个或多个CREATE TABLE命令。它们将按顺序执行。如果您可以访问一个节点集群,您还可以从查询的并行化中获益。我可能会在另一篇文章中解释。
基于机器学习的运动分类(上)
在这篇分为两部分的文章中,我们将深入探讨一个具体问题:对人们进行各种锻炼的视频进行分类。

第一篇文章将关注一种更为的算法方法,使用k-最近邻对未知视频进行分类,在第二篇文章中,我们将关注一种专门的机器学习 (ML)方法。
我们将要讨论的所有内容的代码都可以在 GitHub 的 这个 资源库中找到。算法方法(第一部分)是用 Swift 编写的,可以作为一个 CocoaPod 获得。ML 方法(第二部分)是用 Python/TensorFlow 编写的,可以作为 GitHub 资源库的一部分找到。
背景
我们想要构建一个系统,它将一个人进行锻炼的视频作为输入,并输出一个描述该视频的类标签。理想情况下,视频可以是任何长度,任何帧速率,任何摄像机角度。类别标签的子集可能如下所示:
back squats — **correct** formback squats — **incorrect** formpush-ups — **correct** formpush-ups — **incorrect** form- 诸如此类…
如何构建这样的系统?最棘手的部分之一是我们需要识别帧之间的关系——也就是说,人在每帧的位置之间的关系。这意味着我们正在处理时域中的数据结构,我们称之为时间序列。

Timeseries in 2 or more dimensions (at least one dimension is always time!)
给定一些从输入视频构建的“未知”时间序列,我们想要根据我们预测的练习给时间序列分配一个标签。

In this example, “A”, “B”, and “C” are potential labels for the unknown timeseries
如何制作时间系列?
我提到过我们将从一个输入视频中构建时间序列,但是我们怎么做呢?让我们假设每个视频都包含一个人进行某种锻炼的镜头。我的策略是:
- 标准化每个视频的长度
- 对于每一帧,使用 14 个关键身体点来确定人的“姿势”
- 创建表示姿势随时间变化的时间序列数据结构
- 过滤掉数据中的噪音
标准化视频长度
处理一个 5 分钟的视频是不现实的,所以为了加强数据的一致性,我们将标准化每个视频的长度。我从每个视频的中间对一个 5 秒的片段进行子采样,假设中间发生的事情是整个视频的“代表”。

对于 5 秒以下的视频,我们使用整个东西。
确定姿势
给定子剪辑的一帧(图像),我们想要确定图像中人的姿态。已经可以估计身体点(称为姿势估计),例如使用项目 OpenPose 。

https://github.com/CMU-Perceptual-Computing-Lab/openpose
我从这里拿了一个预先训练好的卷积神经网络(CNN)并用它来估计每个视频帧的姿势。使用这个 ML 模型,我们为 14 个身体部位中的每一个都获得了一个(x,y)坐标,以及每个身体部位的位置精度的置信水平[0,1]。你可以在 GitHub repo 上看到实现细节。
把它放在一起
现在,从视频构建时间序列的一切都已就绪。为了把它放在一起,我们简单地连接每个视频帧的姿态数据。由此产生的时间序列有 4 个维度:
- 时间:由视频帧索引
- 身体部位:共 14 个身体部位
- x 位置:身体部位的 x 坐标,从[0,1]开始归一化
- y 位置:身体部位的 y 坐标,从[0,1]开始归一化

由于有 14 个身体部位和每个部位的(x,y)坐标,我们可以将时间序列数据结构想象成 28 个随时间变化的波(14 x2 = 28)。
(x,y)坐标通过将每个身体部位位置分别除以帧的宽度或高度来归一化。框架的左下角作为我们坐标系的原点。
平滑噪声数据
在这一点上,我们有一个时间序列,但当我们试图分类和分配一个类标签时,它包含的噪声可能会导致不准确的预测。为了平滑噪声数据,我使用了一种叫做黄土 ( 局部加权散点平滑)的过滤器。

https://ggbaker.selfip.net/data-science/media/loess.gif
总的想法是,对于每个“原始”数据点,我们通过取相邻点的加权平均来得到更好的估计。离我们考虑的点越近的邻居权重越高,因此对平均值的影响也越大。
黄土的好处是(例如,与卡尔曼滤波器相比)只需要考虑一个参数。此参数控制相邻点对加权平均值的影响程度。它越大,邻居的影响就越大,因此产生的曲线就越平滑。
下面是我们的时间序列数据的一个例子,在之前的和在黄土过滤之后的:

Timeseries before and after LOESS filtering
时间序列分析
既然我们有了将输入视频预处理成可用数据的方法,我们需要分析产生的时间序列并对视频进行分类。
分析可以用很多方法来完成,但在这篇文章中,我们将重点关注一种叫做k-最近邻的算法。基本上,我们会将未知时间序列与大量已知时间序列进行比较,找出最接近的匹配(k=1)。比较是使用距离函数来完成的,我们将在后面讨论。

The green item is “unknown,” and we’ll assign it the label of the closest “known” item
一旦我们找到未知视频的最近邻居,我们预测未知视频与已知项目具有相同的类别标签,因为根据我们的距离函数它们是最近的。
距离函数是什么?
在二维空间中寻找两点之间的距离很容易:
dist = sqrt( (x2 — x1)^2 + (y2 — y1)^2 )
但是两波之间的距离呢?还是两个时间序列之间的距离?没那么容易…

更复杂的是,想象以下场景:
我们有一个“已知”标记的时间序列,来自一个人做俯卧撑的视频。他每 2 秒做 1 个俯卧撑,并在视频开始 1 秒做。现在,我们想从其他人做俯卧撑的视频中标记一个“未知”的时间序列。他每 3 秒做 1 个俯卧撑,并在视频的 2 秒后开始做。
即使这些时间序列来自相同的练习(俯卧撑),当我们试图比较“未知”时间序列和“已知”时间序列时,会出现两个问题:不同的频率和不同的相移。

Differing frequency (e.g. push-up rate)

Differing phase shift (e.g. push-up starting time)
比较时间序列
为了帮助解决不同频率和相移的问题,我们将采用一种叫做动态时间扭曲 (DTW)的算法。这是使用动态编程的非线性对齐策略。

https://www.cs.unm.edu/~mueen/DTW.pdf
与许多动态规划算法一样,在 DTW 中,我们填充一个矩阵,其中每个单元的值是相对于相邻单元的函数。
假设我们正在比较长度为M的时间序列s和长度为N的时间序列q。矩阵的每一行对应于s的一个时间点,每一列对应于q的一个时间点。这样矩阵就是MxN。第m ( 0 <= m < M)行和第n ( 0 <= n < N)列的单元成本如下:
cost[m, n] =
distance(s[m], q[n]) +
min(cost[m-1, n], cost[m, n-1], cost[m-1, n-1])
将s[m]想象为未知视频中的人在m时刻的姿势,将q[n]想象为已知视频中的人在n时刻的姿势。它们之间的距离distance(s[m], q[n])是各个身体部位坐标之间的 2D 距离的和。
我还对身体各部分之间的距离进行了加权求和,给与特定锻炼相关的身体部分分配了更多的权重。例如,在分析下蹲时脚是不相关的(因为它们不移动),所以它们的权重较小。但是对于跳来说,脚动的多,重量也大。这项技术稍微提高了算法的准确性。
一旦我们填满了 DTW 成本矩阵,我们计算的最后一个单元实际上是两个时间序列之间的最小“距离”。

Visualization of DTW (image has been modified from this presentation)
可以通过使用一种叫做“扭曲窗口”的东西来提高 DTW 的效率简而言之,这意味着我们不计算整个成本矩阵,而是计算矩阵的一个较小的对角线部分。如果您有兴趣了解更多信息,请查阅论文 快速时间序列分类使用数量缩减 。
结果
现在我们已经建立了一个系统,它将一个未知的视频作为输入,将其转换为时间序列,并使用 DTW 将其与来自一组已标记视频的时间序列进行比较。最匹配的已知时间序列的标签将用于对未知视频进行分类。
为了评估这个系统,我使用了大约 100 个视频和 3 个练习的数据集:负重深蹲、引体向上和俯卧撑。每个视频中的练习要么是正确的要么是不正确的(使用不适当的技术)。从人的正面、侧面和背面记录视频。对于侧面角度,我通过在 y 轴上翻转原始图像生成了第二个视频。 80% 的视频被用作“标记”数据,剩余的 20% 被保留用于测试算法的准确性。**
测试结果表明,该算法非常擅长区分练习之间的*(90–100%准确度),但不太擅长对练习中的变化进行分类(正确与不正确的技术)。这些变化可能很微妙,很难跟踪,在这方面我能达到的最大精度是 ~65% 。*
丰富
k-最近邻算法的一个主要缺点是推理时间——即对未知视频进行分类的时间——随着标记数据集的大小成比例增长,因为我们将未知时间序列与每个标记项目进行比较。
在第二部分中,我们将探索一种使用 ML 模型对视频进行分类的端到端方法,从而使推理时间保持恒定。
资源
- 主 GitHub 库带有视频处理和 DTW
- 打开姿势
- iOS 上的姿态估计
- 局部加权散点图平滑(黄土)
- 动态时间扭曲 (DTW)
- DTW《翘曲的窗户》
基于机器学习的运动分类(下)
在这篇分为两部分的文章中,我们将深入探讨一个具体问题:对人们进行各种锻炼的视频进行分类。

在的上一篇文章中,我们重点关注了一种更为的算法方法,使用k-最近邻对未知视频进行分类。在这篇文章中,我们将关注一种专门的机器学习 (ML)方法。
我们将要讨论的所有内容的代码都可以在这个 GitHub 库的 中找到。算法方法(第一部分)用 Swift 编写,可作为 CocoaPod 获得。ML 方法(第二部分)是用 Python/TensorFlow 编写的,可以作为 GitHub 资源库的一部分找到。
背景
视频分类与图像分类的根本区别在于我们必须考虑时间维度。无论我们使用什么样的 ML 模型,它都需要学习具有时间成分的特征。为此开发了各种架构,现在我们将讨论其中一些。
递归神经网络

Unrolled RNN with many-to-one architecture (source)
rnn 非常适合输入数据序列,比如文本,或者在我们的例子中,是视频帧。RNN 的每一步都是特定时间点输入的函数,也是前一步的“隐藏状态”。以这种方式,RNN 能够学习时间特征。权重和偏差通常在步骤之间共享。
rnn 的缺点是它们经常遭受消失/爆炸梯度问题。另外,反向传播在计算上是昂贵的,因为我们必须通过网络中的所有步骤进行传播。
长短期记忆网络

https://colah.github.io/posts/2015-08-Understanding-LSTMs/
LSTMs 是普通 rnn 的一个更复杂的变体,旨在捕获长期依赖关系。LSTM 的一个“单元”包含 4 个可训练门:
- 遗忘门:一个 sigmoid 函数,确定从先前单元的状态中“遗忘”什么
- 输入门:一个 sigmoid 函数,决定我们将哪些输入值写入单元格
- 双曲正切门:双曲正切函数,将输入门的结果映射为-1 和 1 之间的值
- 输出门:一个 sigmoid 函数,过滤前面门的输出
一般来说,LSTM 架构有助于防止消失梯度,因为它的附加相互作用。
三维卷积神经网络(CNN)
神经网络的 2D 卷积层使用一组“过滤器”(内核),这些过滤器滑过输入数据并将其映射到输出空间。下面,我们可以看到一个过滤器的动画示例:

https://mlnotebook.github.io/img/CNN/convSobel.gif
将 2D 卷积层扩展到时间维度相对简单,我们有一个 3D 输入,其中第三维是时间,而不是 2D 滤波器,我们使用一个 3D 滤波器(想象一个小盒子),它在 3D 输入(一个大盒子)中滑动,执行矩阵乘法。
通过这个简单的 3D 膨胀,我们现在可以(希望)使用 CNN 来学习时间特征。然而,将内核扩展到 3D 意味着我们有更多的参数,因此模型变得更加难以训练。
膨胀的 3D ConvNet (I3D)
让我们回到文章的目标:对人们进行锻炼的视频进行分类。我选择了最后一个架构的变体,3D CNN,基于论文“ Quo Vadis,动作识别?新模型和动力学数据集。
在本文中,作者介绍了一种称为“膨胀 3D conv nets”(I3D)的新架构,该架构将过滤器和池层扩展到 3D 中。I3D 模型基于 Inception v1 和批量规格化,因此非常深入。
迁移学习
我们训练 ML 模型变得善于检测数据中的特定特征,例如边缘、直线、曲线等。如果两个领域相似,则模型用于检测一个领域中的特征的权重和偏差对于检测另一个领域中的特征通常很有效。这叫做迁移学习。

General guidelines for transfer learning
I3D 的创造者依靠迁移学习,使用 Inception v1 模型的权重和偏差,该模型在 ImageNet 上预先训练。当将 2D 模型膨胀到 3D 时,他们只是简单地将每个 2D 层的权重和偏差“叠加”起来,形成第三维度。以这种方式初始化权重和偏差(与从头开始训练相比)提高了测试精度。
最终的 I3D 架构是在 Kinetics 数据集上训练出来的,该数据集是 YouTube 上 400 多个人类动作和每个动作 400 多个视频样本的大规模汇编。鉴于动力学数据集和手头任务(对人们做运动的视频进行分类)之间的相似性,我相信使用公开可用的 I3D 模型进行迁移学习有很大的机会。
数据预处理
先说数据预处理。I3D 模型使用双流架构,其中视频被预处理成两个流: RGB 和光流。我用来创建这些流的代码在这里可用并且基于 I3D GitHub repo 的实现细节。

RBG and optical flow visualizations of a long jump
我使用 Python 的cv2库中的函数calcOpticalFlowFarneback()生成了光流数据。注意,I3D 模型不像在 RNN 或 LSTM 中那样具有显式递归关系,然而光流数据是隐式递归的,因此我们获得了类似的优点。
在测试时,通过添加具有相等权重的逻辑并使用结果来形成类预测,来组合这两个流。
进一步的细节
我剥离了 I3D 模型的最后两层(逻辑层和预测层)并用类似的层替换它们,这样新的逻辑层就有了我的用例的正确数量的output_channels(下面列出了 6 个类)。
bw-squat_correct
bw-squat_not-low
pull-up_chin-below-bar
pull-up_correct
push-up_correct
push-up_upper-body-first
每个流的逻辑值、 RGB 和光流被组合并用于形成类似于原始实现中的预测。我使用了一个由 128 个视频组成的数据集(不幸的是这个数据集很小),这些视频是从不同的摄像机角度录制的,我只对新图层和进行了反向传播,依靠现有图层的权重和偏差将视频映射到相关的特征中。
我用的是批量1,正则化强度0.25 (L 范数),学习率5e-4的tf.train.AdamOptimizer。训练-测试分割为 80% — 20%,在训练数据集中,另外 20%被保留用于验证和超参数调整。TensorBoard 的计算图如下所示:

Modified I3D computational graph from TensorBoard
结果
训练通常需要大约 30 个历元,直到损失达到稳定,在最好的情况下,最后 100 次迭代的平均损失是0.03058。测试精度达到69.23%。
这个项目的结果受到小数据集大小的限制,但随着更多的视频,我相信一个微调版本的 I3D 模型可以实现更高的测试精度。
将端到端的 ML 模型集成到移动客户端提出了一个不同的挑战。例如,在 iOS 领域,模型必须采用 CoreML 可接受的格式。存在诸如 tfcoreml 的工具,用于将 TensorFlow 模型转换为 coreml 模型,但是支持转换的 op 数量有限。
在撰写本文时,tfcoreml 不支持 T2 或任何三维操作,这意味着还不能将 I3D 模型集成到 iOS 应用程序中。
系外行星 I:方法和发现
用数据科学了解系外行星
探索宇宙

Source: L. Calçada, ESO.
7 年前,17 岁的我在高中最后一年选择探索系外行星领域,名为“成熟之旅”。我联系了第一颗系外行星的共同发现者 Didier Queloz ,他曾在日内瓦大学任教,讨论我论文的分析部分,并征求他对可居住性前景以及系外行星重要性的看法。他很大方地抽出时间和我见面接受采访,后来还带我参观了日内瓦天文台和他的实验室。
我的项目工作获得了满分,随后我也被邀请到CERN在一个著名的瑞法学生科学分享活动上公开展示我的见解。
我的演讲很受欢迎,尤其是在理论和研究驱动的领域,如天体物理学,带来了与人类生存相关的焦点。事实上,在别处发现生命的前景,可以帮助我们更好地了解作为人类的自己,受到了观众的赞赏,并植根于我自己的经历中。


Left: CERN ‘Science-Sharing’ event flyer. Right: Group picture of presenters and public at the event in question.
2019 年 10 月,同样是迪迪埃·奎洛兹教授,与米歇尔·马约尔、詹姆斯·皮布尔斯共同被授予 诺贝尔物理学奖 。


Left: observatory tour by Didier Queloz, 2012. (I was too naive to think of taking a selfie). Right: Nobel Prize Winners, 2019.
这篇文章是我当时用他的投入写的报告的一部分,作为对系外行星的介绍。鉴于最近的新闻,我现在可以查看它,因为它非常相关,并在数据科学的背景下,即如何收集、分析和解释数据的背景下,提供了对系外行星发现的见解。我们还可以将这些发现与许多物理定律联系起来,如开普勒第三定律,并观察宇宙中的所有行星如何遵循完全相同的模式。
我已经将内容分成多个部分,如下所示:
外行星学简史
安金德很久以来就一直在推测除了我们自己以外的行星系统。几个世纪前,哲学家们就假设我们的太阳系不是独一无二的;事实上在看似无限的恒星海洋中存在着无数更多的恒星。围绕另一颗恒星运行的行星上存在生命的可能性不仅仅是一个似是而非的理论,而且它还具有优势。事实上,在可观测的宇宙中有几千亿个星系,每个星系包含几千亿颗恒星;认为地球可能是整个宇宙中唯一有能力支持生命的星球,这看起来几乎是荒谬的。
然而,缺乏科学证据来支持这一富有远见的观点意味着在过去的两千年里,这种思想跨越了所有的极端。一方面,有些人——比如伊壁鸠鲁——相信宇宙中除了我们之外还存在其他世界,并且相信它们有能力容纳生命。另一方面,许多人——比如亚里士多德——坚信地球在宇宙中是独一无二的,其他类似的世界不可能存在。基督教和其他信仰也声称上帝之手创造了地球和所有生物。
因此,寻找太阳系外的行星成了一个紧张的科学研究课题。由于缺乏证据,我们不知道它们有多普遍,它们与太阳系的行星有多相似,或者与其他恒星周围的行星系统相比,我们自己的太阳系的构成有多典型。可居住性也是一个重要的问题。如果有其他行星,它们是否也有必要的表面条件来支持某种形式的生命?问题很多,但答案很少。主要的障碍在于无法直接观察这些未知的天体。
哈勃太空望远镜也许宠坏了我们所有人——我们现在开始期望经常看到遥远星系和星云的图像。因此,拍摄一颗太阳系外行星的图像应该不会比拍摄一个遥远星系的图像更困难。然而,问题出现了,因为主星完全超过了它的小而暗淡的行星。在大多数情况下,行星离它们各自的恒星太近,无法直接成像,特别是从地球表面,考虑到我们大气层的干扰效应。
直到 1995 年,日内瓦大学的米歇尔·马约尔和迪迪埃·奎洛兹才首次报告了对太阳系外行星的明确探测。尽管几年前射电天文学家亚历山大·沃尔兹森和戴尔·弗莱尔已经进行了一些其他的探测,但它们不是在一颗普通恒星周围发现的,而是在一颗脉冲星周围发现的——一颗作为超新星爆炸的大质量恒星的超致密残余物。马约尔和奎洛兹于 1995 年 10 月在日内瓦宣布了太阳系外行星 Pegasi b 51 T1,这被认为是第一次明确的太阳系外行星探测。多年来,还有其他几个可以被视为里程碑的发现,如探测到多个行星系统和首次探测到行星大气层。
自 1995 年以来,这一领域取得了惊人的进展。新的发现和重大发展继续以每月一次的速度公布,这在任何科学领域都是前所未有的进步。截至 2019 年 11 月,通过使用几种不同的探测方法,共发现了 4128 颗系外行星。寻找系外行星已经迅速成为一个受人尊敬的科学研究领域和一个能够独立存在的天文学领域。这一领域的进步不仅伴随着数千篇科学论文的发表,还见证了光学天文仪器的改进,这导致了开普勒望远镜的发射和新的探测技术。
检测的方法
在过去的二十年里,几种不同的技术被用来探测系外行星。如前所述,母星发出的光总是会冲掉其行星反射的少量光。因此,科学家必须想出替代和间接的方法来探测系外行星,因为直接观察它们几乎是不可能的。本章概述了已经取得成功的最成熟的方法以及它们背后的逻辑和科学,同时讨论了每种方法的优缺点。
径向速度法
也被称为 RV 方法,是迄今为止最成功的技术。1995 年,米歇尔·马约尔和迪迪埃·奎洛兹用这种方法发现了第一颗公认的系外行星。此后它被用于定位 863 颗太阳系外行星(截至 2019 年 11 月)。
如图 1 所示,多年来,科学家们已经能够探测到各种各样的行星。系外行星的质量是相对于木星质量来表示的,即木星质量。然而,行星的质量测量不确定性高达 sin(i) ,其中 i 是行星围绕其恒星运行的倾角。因此,质量被绘制为 Msin(i) ,而不仅仅是 M 。多年来,这项技术在灵敏度和准确性方面都有所提高,科学家们现在已经发现了许多木星质量低于 0.1 的行星,这一壮举直到 2004 年左右才得以实现。*
这种技术对于探测围绕其母星运行的大质量行星最为有效。值得注意的是,这种方法只提供了行星质量的下限,这是它最大的缺点。一颗行星的真实质量只有当这项技术和凌日法结合起来使用时才能确定,这将在后面描述。
RV 方法基于自然重力系统和轨道,由牛顿万有引力定律定义。
如前所述,行星的引力使其母星在自己的小轨道上摇摆。虽然恒星和行星相互施加的力是相同的,但它们的加速度之间的差异是巨大的,因为恒星和行星的质量不同,至少等于 10^3。由于行星的加速度是基于恒星的质量,而恒星的质量非常高,所以行星的移动量很大。相反,恒星的加速度很小,因为它是基于行星的质量,而行星的质量相对较小。这种微弱的加速度导致恒星在其小轨道上“摇摆”。
这种“摆动”会对恒星的可观测属性造成微小的扰动,比如它在天空中相对于地球的角位置。一个更重要的变化是变化在速度上,恒星以这种速度靠近或远离地球,在那里它被观察到。为了更好地理解 RV 方法,我们首先需要对多普勒效应和普通光谱学有一个基本的了解,因为这两者被结合起来用于探测系外行星。
多普勒效应
让我们以消防车的警笛为例来理解这个概念。让我们想象一辆不动的消防车开着警报器。这个固定声源产生恒定频率λ的声波,声波以恒定的声速c= 340m/s向外传播。由于声波从声源向所有方向传播,如果它们可见,它们将呈现为圆形,所有观察者将听到相同的频率,在这种情况下,这是声源的实际频率。换句话说,观测频率等于发射频率 0。

A stationary and moving fire-truck emitting sound waves at a constant frequency.
但是,如果消防车开始向一个方向移动,由于波长的差异,声波会变得不均匀。在两种情况下,警报器发出的声波的频率相同。然而,由于震源现在正在移动,每个新波的中心在消防车的方向上略有位移(如右图所示)。结果,声波开始在消防车的前部聚集,并在后面扩散。这种现象被称为多普勒效应。由于声波的波长不同,观察到的频率也会受到影响。因此,声源前方的观察者会听到较高频率的汽笛声,而其后方的观察者会听到较低频率的汽笛声。观察到的频率变化是导致警报声音调变化的原因。观察到的频率可以使用以下公式计算:

其中:
- c 是介质中波的速度,在我们的例子中是空气,大约等于 340 [m/s]。
- v_observer 是观测者的速度,用【m/s】表示。如果观察者正朝着光源移动,它将是正的,如果远离光源,它将是负的。
- v_source 是震源的速度,也用[m/s]表示。如果观察者正朝着光源移动,它将是正的,如果远离光源,它将是负的。类似地,如果源远离接收器,它将是正的,如果向接收器移动,它将是负的。
- \ _ 0 是声源发出的频率,单位为[Hz]。
为了观察到这种效应,相对运动必须沿着观察者和波源的连线,也就是朝向或远离观察者。沿着这条直线方向的运动称为径向运动,该运动的速度称为 径向速度 。如果观察者相对于波源既不靠近也不远离,就没有影响。多普勒效应是一种影响任何形式波动的波长和频率的现象,例如声波、水波、光波以及所有电磁波。
现在让我们把我们的类比与天文学联系起来。让我们想象一颗恒星发出光波,而不是消防车发出声波。我们,地球上的人类,是观察者,恒星是光波的来源。如果这颗恒星没有系外行星,它就不会有明显的径向速度,因为它是静止的。然而,如前所述,当一颗行星绕着一颗恒星运行时,后者也在其非常小的轨道上运动,以响应前者的引力。或者更确切地说,它们都绕着它们共同的质量中心运行,而这个质量中心恰好在恒星本身的内,这导致了恒星的轻微摆动。因此,如果我们可以观察到这种“摆动”,那么我们可以得出结论,一颗真正的系外行星可能正在围绕它旋转。这种“摆动”实际上是恒星径向速度的变化。天文学家可以通过将光谱学应用于多普勒效应来探测这些变化。
光谱学
现在让我们想象我们上面提到的恒星有一颗外行星围绕它运行,导致它的径向速度变化,这被我们这些观察者“看到”。就像消防车一样,当恒星看起来朝着我们移动时,它发出的波长会更小,也就是说,被压缩和聚集得更多,因此观察到的频率更高。相反,当它移动远离我们时,波长将会更大,也就是说,更加拉伸和分散,观察到的频率更低。然而,光波的行为与声波略有不同:光波改变的不是其可听的音调,而是其光谱颜色。换句话说,光波的频率、波长和光谱颜色都是相互关联的。

The Electromagnetic Spectrum, with the visible light section highlighted.
对应于可见光谱的波长如下:

Variation in wavelength and frequency by colour

Wavelengths according to colour
当光波的波长很短且频率很高时,光波会发生蓝移,这意味着它们具有蓝色光谱。当光波波长较长且频率较低时,它们会发生红移,这意味着它们获得了红色光谱。

Change of Spectrum Colour due to the direction of the Radial Motion of the Star
由于多普勒效应,我们知道当光波红移时,由于波长增加(因此频率降低),它们会以径向运动的方式远离。同样,当光波蓝移时,我们知道它们正在向我们移动,因为波长变短,频率变高。
因此,当我们观察我们选择的恒星发出的光波的光谱颜色时,我们看到它们不断地从红色变为蓝色。这种周期性的光谱移动之所以发生,是因为恒星在它的小轨道上不断运动,从而周期性地缩短和增加它与我们观察者的距离。

“Wobble” of star causing a Periodic Spectral Colour Change. The motion of the star has been exaggerated to illustrate the point.
总之,通过使用高精度光谱仪器,我们可以有效地探测到主星光谱颜色的周期性光谱变化,这意味着其可见光波长的周期性变化,进而表明一种明显的径向运动,这种运动只能由系外行星的引力引起,因为它迫使恒星围绕两个天体的质量中心运动,从而证实了它的存在。
运输方法
另一种已经在探测系外行星方面取得成果的方法是凌日法,这种方法因基于太空的任务而广为人知,如 CoRoT 和开普勒。这项技术的基本原理很简单:如果一颗行星从它所绕转的恒星前面经过,地球上接收到的光的强度会有小幅下降。

The Observable Drop of Light during a Transit
通过观察由行星凌日引起的恒星光亮度的变化,人们能够探测到系外行星。虽然光度的下降取决于恒星和行星的相对大小,但典型的量估计在 0.01%和 1.7%之间。凌日的持续时间也取决于行星离恒星的距离和恒星的大小。
这种技术有一个明显的缺陷:只有当行星的轨道平面与我们的视线对齐时才适用,这样我们就可以目睹行星挡住了恒星的一些光线。

Varying Orbital Inclinations determine the Observation of a Planetary Transit from Earth
一颗行星以日地距离(1 AU)围绕一颗太阳大小的恒星运行,将有 0.47%的概率产生可观测的凌日。因此,人们会认为这种方法可能是不切实际和无益的。然而,通过在包含数千颗恒星的大面积天空中扫描恒星,原则上可以发现太阳系外的行星,其速度可能超过径向速度法。正是出于这种希望,许多任务已经启动,特别是开普勒任务。2012 年 12 月,用这种方法已经发现了 291 颗行星,开普勒发现的 2000 多颗候选系外行星正在等待确认。今天,使用凌日方法,已确认的行星数量为 2966 颗,候选行星为 2428 颗。
凌日方法的另一个缺点是需要很长时间来确认候选行星的真实性。事实上,由于高错误探测率,单次凌日的观测不足以被完全接受为一颗行星。因此,候选行星可能需要很多年才能被确认为太阳系外行星,因为人们必须等待它绕轨道运行几次。这种方法也更倾向于检测轨道较小的大型行星,这些行星被称为热木星,因为它们过境更频繁,因此更容易被检测到。
另一方面,凌日法的优点之一是光线的下降提供了对行星大小的估计。但到目前为止,最大的优势是我们可以确定系外行星的大气成分,这对确定其可居住性的潜力至关重要。当行星凌日恒星时,星光在到达地球之前会穿过行星的大气层,让我们有机会探测其中是否存在氧等元素。
当穿过恒星的行星有大气层时,恒星发出的光会下降更多,因为除了已经被行星主体阻挡的光波之外,行星中的元素还会吸收一些光波。行星的大气层本质上就像是恒星光波的过滤器,根据大气元素的不同,阻挡一些,释放一些。
大气中存在的元素阻挡了相应的波长,导致光谱中出现黑线,被称为吸收线。

An example of Absorption Lines
每种元素都与一组特定的波长相关联,由于其化学性质,这些波长会被阻挡。因此,当我们在一颗有行星经过的恒星的光谱中发现吸收线时,我们就知道这颗行星有大气层。通过分析吸收线,我们可以通过观察与波长相对应的元素来确定大气的化学成分。如果恒星光谱的吸收线与一种元素的吸收光谱完全一致,那么它就表明它的存在。

Absorption Lines in the Spectrum of a star matching those of Hydrogen, confirming its presence
例如,通过在恒星的光谱中找到与氧相匹配的吸收线,我们可以确定围绕它运行的系外行星是否可能适合居住。
延伸阅读:
- 第二部分 : 数据解释
- 第三部分 : 可居住性和结论
- 原报道:https://eklavyafcb.github.io/exoplanets.html
参考资料:
- 长度卡尔萨达,埃索。https://luiscalcada.com/
- 美国宇航局的想象宇宙,多普勒频移。
- 美国宇航局,可见光波。 (2013)。
- 拉斯坎布雷斯天文台全球望远镜网络,凌日法。 (2013)。
维基百科,https://www.wikipedia.com【2013 年访问】:
- 红移
- 径向速度
- 灯
系外行星 II:数据解释
用数据科学了解系外行星
了解宇宙

Discovered Exoplanets Visualised
这是系外行星系列的第二部分。
现在我们已经看到并理解了历史背景、研究的科学价值以及这些发现的意义,我们将看看太空任务发现并编辑的实际数据,这样我们就可以将它们与实际物理联系起来。通过绘制数据图表,我们可以直观地看到与几个世纪前由著名物理学家如牛顿和开普勒建立的理论或物理定律的相关性。
为了充分理解系外行星领域背后的科学,人们必须查看经常公开的实际研究数据。几个团队已经将所有信息汇编成大型数据库,供公众通过互联网查看,如美国宇航局系外行星档案馆或太阳系外行星百科全书。这些网站中最有用的工具是绘图仪,它允许人们以几种不同的方式直观地探索、理解和分析数据。
在接下来的几页中,我们将分析一组使用来自www.exoplanets.org的数据生成的有趣图表,这是一个由加州行星调查联盟维护的网站,显示了已确认的系外行星(即没有候选行星)的列表,以及它们的特征。
轨道周期的概率分布;

Graph 2: The Number of Exoplanets found for each value of Orbital Period
上图显示了探测到的系外行星的数量与其轨道周期的关系,即它们围绕母星完成一个完整轨道所需的天数。
快速浏览一下,该图中有几个突出的特征。首先,有两个大的峰值,一个在 3 到 4 个轨道周期日之间,窄而长,另一个短而宽,峰值在大约 400 个轨道周期日。另一个值得注意的特征是两个峰值之间的深度下降。
现在,如果我们把我们太阳系行星的轨道周期,八个行星中的五个将符合第二个峰值。然而,我们似乎在第一个峰值的参数范围内找到了同样多的系外行星。此外,似乎还没有发现任何行星的轨道周期超过 5000 天,这仅仅比木星的轨道周期多一点点。即使许多被探测到的行星似乎没有木星的轨道周期,但它们中的大量确实具有木星的质量。
该图显示了两个彩色部分。较小的黄色部分代表类木星,即在质量和轨道周期方面与我们的木星相似的系外行星。较大的红色部分代表热木星,它们在质量上也类似于木星,但它们的轨道周期要小得多,这意味着它们的轨道非常靠近它们的母星,因此接收到大量的光和热,正如它们的名字所示,使它们变得很热。如(第二张)图表所示,这些热木星的轨道比水星的轨道小,水星是我们太阳系中离其主星最近的行星。图中显示了 125 颗热木星,但只有 11 颗木星类似物。这是寻找系外行星的最大惊喜。
研究人员已经发现了许多这种有趣的模式,与预期不符。让热木星的发现对我们来说不同寻常的是,在我们开始发现许多行星之前,普遍的共识是,较小的行星会靠近恒星运行,而大质量的行星可能会留在行星系统的外围。然而,许多新发现的行星绕其恒星运行的距离相对较小,不到太阳到太阳系最内层行星水星距离的六分之一。没有人预料到类似木星的行星会存在于离它们的恒星如此之近的地方。有了这些新数据,我们认为是太阳系的基础知识现在不再是最新的了。我们现在也必须重新评估我们在宇宙中的位置:我们太阳系的类型有多普遍?是独一无二的吗?我们是稀有类型还是典型类型?我们真正了解和理解了多少?
目前,系外行星是通过使用其母星作为工具来探测的。换句话说,我们正在发现新的太阳系外行星系统,并且已经有足够的数据得出以下统计数据:迄今为止发现的至少 50%的系外行星在行星定位方面与我们的太阳系不同。这意味着我们的太阳系充其量只占宇宙中所有行星系统的一半。本质上,当我们观察恒星时,我们看到每两颗恒星中只有一颗有类地行星。这表明像我们这样的系统不是宇宙中的大多数,而是 T4。即使是已经发现的类地行星也比地球大几倍,因此被称为“超级地球”。
提出来解释热木星之谜的理论之一是迁移理论,该理论认为行星随着时间向内迁移,因此我们看到它们处于形成的后期阶段。事实上,这些巨大的行星一定是从 100 倍远的地方开始的,随着时间的推移,它们向内迁移,达到了现在与恒星的距离。
这当然引出了一个问题,即假设他们迁移了,他们是如何迁移的,更重要的是,为什么要迁移?它们最初的轨道不稳定吗?是什么产生了能量给这些巨大的物体以动力?也许真相永远不会为我们所知,但是行星迁移理论确实为我们提供了一些热木星出现的解释。
相对于半长轴的最小质量:
下图很好地说明了热木星:

Graph 3
该图的 X 轴代表半长轴,即恒星到其轨道行星的距离。Y 轴代表系外行星的质量,这是相对于木星的质量来测量的,以使尺度与热木星的问题更相关。
最后,添加一个色标,如图表右侧所示,来表示每个行星的轨道偏心率。轨道偏心率是行星轨道偏离正圆的程度。零度时,行星的轨道是完美的圆形,用蓝色表示。随着偏心率的增加,轨道变得更加抛物线化,如上图 3 中的红色部分所示。

Variations in Orbital Eccentricities
在图 3 中,人们可以清楚地看到两个主要的集中的行星群。如前所述,大多数的质量与木星相同。左上角的星系团由温度更高的行星组成,因为它们离恒星更近。这些是典型的热木星,大多数是用凌日法探测到的。我们还可以看到,几乎所有这些行星都用蓝色表示,这意味着它们的轨道偏心率接近于零,意味着圆形轨道。
然而,另一个行星群在一个更冷的区域,离它的恒星更远。半长轴约为 1 AU。与之前的星团不同,这个星团具有混合的轨道偏心率:它们的范围从 0 到 0.8,这意味着它们倾向于具有更偏心的轨道。这些似乎是典型的气态巨行星,也称为木星类似物,主要是通过径向速度方法检测到的,如下图 4 所示。

Planets detected by Transit Method (Red) and Radial Velocity (Green)
这两个团块之间的偏心率差异是惊人的。左边行星丛中的大多数行星都有完美的圆形轨道,而右边行星丛中的行星则更加多样,更倾向于偏心。正是两个团块之间的半长轴的差异造成了这种差异。左边的行星群有一个较小的半长轴,这意味着它们更靠近它们的恒星,因此被其巨大的引力锁定。一个潮汐锁定的天体绕着它自己的轴旋转的时间和它绕着它的伙伴旋转的时间一样长。这导致一边不断面对伴侣的身体。说明这种现象的一个主要例子是月球,它被潮汐锁定在地球上,因为它总是向我们展示同一个半球。然而,右手边的行星没有被潮汐锁定,因为它们离恒星太远,因此受到的引力较弱。在 1 AU 处,它们是地球的镜像:它们有必要的角动量来持续环绕它们的母星,但没有被它锁定。
图表 3 也提出了一个有趣的问题:来自两个不同星系团的两颗行星会存在于同一个行星系统中吗?换句话说,一个行星系统可能同时包含一颗热木星和一颗木星类似物吗?到目前为止,只发现了一个,被认为是稀有配置。
然而,要正确回答这个问题,我们需要增进我们对热木星形成的了解。回想一下,这些类型的行星大多是用凌日法发现的。当一颗行星从它的恒星前面经过时,我们可以有效地测量它的轨道倾角。当我们查看统计数据时,我们看到大多数热木星的轨道不垂直于恒星的旋转轴,这很奇怪,因为它不像我们太阳系中的任何行星。对于行星以一个倾斜的平面绕其恒星运行,人们认为发生了某种暴力事件或机制。因此,热木星可能是由一些未知的戏剧性和动态现象形成的,这些现象“打破”了这些行星的整个系统。这也意味著,迁移理论无法解释热木星形成的所有原因,因为热木星本身不可能是暴力机制的催化剂。因此,只有一颗行星变成热木星,而同一星系中的另一颗行星保持不变的概率非常低,而且会被认为是奇怪的。大多数被确认的热木星是孤立的,这意味着它们是绕其恒星运行的单一行星。他们确实过着孤独的生活。
但也许这个图表中最引人注目的特征是间隙的存在。事实上,我们似乎没有在右下角和更低的范围内找到任何行星,在 0.01 木星质量之间,这是岩石类地行星应该在的地方,这令人惊讶。如果我们输入我们自己行星的数据,金星和地球会发现自己处于图表的底部,孤独而孤立。我们所有的行星都不会被放在左边的丛中。
此外,两个团块之间还有一个很大的间隙。真实的宇宙是这样的吗?类地行星真的如此罕见,还是我们所看到的实际上是一种选择效应,被我们的探测方法所偏向?**
事实上,我们没有探测到右下角行星的原因不是因为选择效应,而是因为我们处于当前探测能力的阈值。让我们考虑图上的一个小质量,比如 0.03 木星质量。对于这个给定的质量,我们可以看到我们能够在短距离内相对容易地探测到系外行星。然而,当我们增加距离,即半长轴,行星变得更加难以探测。事实上,对于我们选择的质量,在 0.4 天文单位之后,我们似乎根本找不到任何行星。这是因为径向速度方法探测行星所需的振幅信号减弱了。这种减弱是因为所需的信号直接取决于系外行星的轨道周期。
对于任何系外行星,RV 方法的以下方程与其振幅和轨道周期(以及半长轴,因为两者直接相关)相关:
**
- *m_psin(i) 是系外行星的固定最小质量,用木星质量单位表示[ M_Jupiters ]。
- i 是行星轨道相对于天球切线平面的倾角。
- k 是信号的振幅,单位为米/秒[ m/s ]
- p 是系外行星的轨道周期,以年年计量。

The relation between the orbital period p and the amplitude k, in a graphical form
由于系外行星的质量和倾角是固定的,我们可以简化原始方程,看到振幅和轨道周期的乘积等于一个常数。这意味着两个变量之间成反比关系。我们可以看到,随着轨道周期 p 增加,振幅 k 减小。相反,随着轨道周期的减少,振幅增加。径向速度方法不能探测具有高半长轴值(即大轨道周期)的行星,因为信号的振幅变得非常低。因此,参照图 3,我们无法探测到该区域中发出低振幅信号的任何行星。这就是为什么在左上角探测到了很多行星,而在右下角却没有。
为了能够检测到图表右下角区域的行星,我们必须提高测量仪器的灵敏度,以便更准确地检测到信号的幅度。自从检测到 51 Pegasi b 以来,我们已经取得了重大进展,并将继续这样做。图 5 描述了该过程,该图还显示了检测线。检测线对应于信号的幅度 k 。我们看到,我们实际上是从左上角到右下角沿对角线移动。左上方的对角线检测线具有较大的振幅,而下方的检测线具有较小的振幅,最小的振幅约为每秒 1 米。

The lines in this graph have been manually added to better illustrate the point. They are not accurate.
与轨道周期相关的半长轴:

Graph 6
图表 6 清楚地显示了半长轴和系外行星轨道周期之间的惊人关系。与之前的图表不同,我们可以看到行星绕其轨道运行一周所用的时间与距其恒星的距离之间存在紧密的相关性。我们简单地改变了 Y 轴的参数,我们得到了一个完全不同的视图。这一次,如果我们放入我们自己的行星,它们将会完全适合。
这张图表也许是一个特殊的图表,因为它证明了物理学基本定律之一的普遍应用:开普勒行星运动第三定律,早在发现系外行星之前就已经存在。这对寻找系外行星很重要,因为它可以有效地用于计算系外行星与其恒星之间的距离,并确定它是否位于可居住带内。
根据该定律,半长轴 a^3 的立方与轨道周期 p^2 的平方之比是常数,即:

然而,在基于从系外行星获得的数值的图表 6 中,我们注意到这条线代表相同的比率。如果在上图的对数刻度中,我们选择 x 轴上的两点(a1;a2* )和 y 轴上的对应点(P1;p2 ,则:*

如果 a1 = 0.1、 a2 = 1,那么 p1 = 10、 p2 = 320。因此:

这证明了对于线上的任何给定点,即对于任何行星的值,这两个参数的比率是恒定的。这和开普勒第三定律是一致的。开普勒通过观察我们太阳系的行星得出的定律适用于现在正在被发现的太阳系外行星,大约三四百年后。我们可以看到,图 5 和图 6 中直线的斜率是相同的。这证明了重力在行星系统中的作用是一样的。开普勒定律表明,跨越不同系统和不同环境的所有行星都以完全相同的方式服从重力。
我们还可以观察到,除了左下角的数据看起来更分散之外,大多数数据的线都是直的。这个区域中的行星与图 3 中左侧星团中的行星相同。我们可以看到在 1 天的轨道周期之上的行星比之之下要多。这就引出了一个问题,为什么散射只是单侧的。一个可能的解释是,我们目前的科学技术还不够先进,不足以正确测量不到一天的行星轨道。通过检查左下栏中 11 颗行星的数据,我们看到其中 7 颗行星是使用凌日方法探测到的,另外 4 颗是通过径向速度方法探测到的。**

Planets detected by Transit Method (Red) and Radial Velocity (Green)
另一个问题是为什么散射只出现在半长轴小的区域。为什么右上角没有散点反而?原因是行星离它们的恒星很近。在小距离上,行星受到宿主恒星更强的引力,使它们的轨道更圆。如图 8 所示,蓝色表示轨道偏心率低,意味着轨道更圆。

它们实际上变得像月亮对地球一样:它们被潮汐锁定并以圆周运动的方式旋转。随着偏心率的增加,轨道变得更加椭圆。在轨道偏心率低的情况下,更难正确地确定半长轴。因此,蓝色点比其他点有更大的误差。因此,我们可以假设这些行星要么由于它们的低偏心率和与恒星的极度接近而不完全符合开普勒定律,要么它们确实符合该定律,但我们在测量轨道周期时犯了微小的错误。
总之,我们可以看到,在图表上绘制数据不仅有助于直观地表示所有已发现的系外行星,而且有助于对它们进行分类和区分。通过解释图表,我们可以质疑不同现象的原因,如热木星,并试图通过阐述行星迁移等理论来解释它们。另一方面,我们也可以注意到所有的系外行星在遵守相同的引力和运动定律方面是如何相似的,这使我们得出结论,某些物理规则适用于宇宙中的每一种元素。
此外,通过解释这些图表,我们还认识到了目前天文仪器的局限性,并试图对其进行改进,以探测更广泛的系外行星。通过尝试进一步完善技术,我们可以专注于实现在这些图表的未探索区域中找到可居住的类地行星的目标。
延伸阅读:
- 第一部分 : 方法和发现
- 第三部分 : 可居住性和结论
- 原报道:https://eklavyafcb.github.io/exoplanets.html
参考资料:这项研究利用了系外行星轨道数据库
和 www.exoplanets.org的系外行星数据探测器
系外行星 III:可居住性和结论
用数据科学了解系外行星
生活在宇宙中

Source: NASA, ESA, and G. Bacon (STScI)
这是系外行星系列的第三部分。
存在两种可能性:要么我们在宇宙中是孤独的,要么我们不是。两者都同样可怕。
-亚瑟·C·克拉克
可居住
虽然寻找其他行星的部分动机是为了了解它们的形成和增进对我们自己的太阳系的了解,但最终目标是找到地外生命。现在,我们已经看到并分析了由太空任务收集的实际数据,并将它们与实际的物理定律联系起来,我们到了这出戏的最后一幕:可居住性。到目前为止,我们只谈到了对已确认的系外行星的探测和定位,但我们对它们孕育生命的能力了解不多,即它们的可居住性。
对于一颗孕育任何形式生命的行星来说,它必须满足某些特定的参数,才能适合居住。生命只存在于某些条件下,这些条件对于创造生命生长和进化所必需的可持续环境是必不可少的。目前没有理由相信满足这些条件的行星不会大量存在。虽然到目前为止我们还不能找到这样的行星,但这很可能只是时间问题。
人们应该记住,对一颗行星是否适合支持生命的评估在很大程度上是基于地球的特征,因为它是宇宙中我们确定可居住的唯一一颗行星。因此,我们只能寻找我们所知的生命。很可能生命存在于不同的条件下,但我们只能推测它的存在。这最后一章将涵盖生命(正如我们所知)在系外行星上生存所需的主要因素,如距离、质量和大气。
德雷克方程
在我们开始定义生命的不同条件之前,让我们先来看看天文学中的两位著名人物,以及他们对其他地方存在生命的可能性的看法。
卡尔·萨根是美国著名的天文学家,以他对外星生命可能性的研究和思考而闻名。像许多天文学家一样,他认为我们的银河系充满了生命,理论上应该存在大量的地外文明。然而,由于缺乏这种文明的证据,他相信这样一种理论,即一旦它们在技术上足够先进,它们就会自毁。
第一颗太阳系外行星的共同发现者迪迪埃·奎洛兹(Didier Queloz)同意萨根的观点,即宇宙中的其他地方也存在生命,但他强调,生命的出现需要一系列连续的事件,因此“运气”是一个关键因素。因此,这个星系可能不太拥挤。
萨根和奎洛兹都坚信地外生命的存在,这仅仅是因为可能性很小。另一位著名的天体物理学家弗兰克·德雷克提出了一个数学方程,理论上可以估计银河系中可探测到的地外文明的数量。它指出:

Drake’s Equation
其中:
- N 是我们银河系中可以进行通信的文明的数量(通过检测它们的电磁辐射)。
- R* 是我们银河系每年恒星形成的平均速率,用[ 颗/年表示。
- f_p 是那些有行星系统的恒星的分数。
- n_e 是每一个太阳系中可能维持生命的行星数量。
- f_l 是适合生命实际出现的行星的比例。
- f_i 是有智慧生命出现的行星的一部分。
- f_c 是开发出一种技术的文明的一部分,这种技术可以向太空释放它们存在的可探测的迹象。
- L 是此类文明向太空释放可探测信号的时间长度,以年表示。
德雷克的方程不同于之前任何一个与系外行星探测相关的方程,因为它包含了大量的未知变量。由于目前的这些不确定性,没有明确的“正确”或“错误”答案,而只是一个估计。随着我们对我们在宇宙中的位置了解得越来越多,一些未知慢慢变得越来越清晰,最终结果也越来越准确。
科学家们承认德雷克方程中存在非常大的不确定性,并往往倾向于做出非常粗略的估计来取得进展。以我们目前的知识水平,我们知道方程的前三项更接近于 10 而不是 1,并且所有的因子都比 1 小。然而,仍然是最大的未知数。通过做一些假设,我们可以简化这个方程,得到一个可能更有用的德雷克方程:

这将意味着我们可能接触的文明的数量大约等于它们的寿命,这也是德雷克和他的同事在 1961 年得出的结论。这也意味着,除非很大,否则会很小。如果 SETI 成功探测到外星文明发出的信号,这将意味着平均来说信号一定很大,因为我们不可能通过观察银河系中的一小部分恒星来发现信号。由于探测到的外星信号传播的速度是有限的,当它们到达我们这里时,它会告诉我们它们的过去,因为它们离我们有许多光年远。但是因为外星文明必须足够大,我们才能探测到这样的信号,这可以告诉我们我们自己的未来是否漫长。另一个出现的问题是,即使我们真的发现了生命迹象,我们如何与他们交流,用什么与他们交流?
生活的秘诀
当我们从太空看地球时,我们看到几乎 75%的地球被水覆盖,水是所有生物的重要自然资源。植物用水从土壤中的矿物质中获取一些养分。这些矿物质必须溶于水才能被植物吸收。广阔的海洋和其他水体为各种海洋生物提供了庇护所。地球的大气层是由水分子构成的云调节的。当然,为了生存,所有动物都需要定期喝水。地球上的生命是围绕水建立的。
因此,正如我们所知,一颗行星要孕育生命,它必须含有水。与普遍的看法不同,水不是宇宙中的稀有商品。相反,它在宇宙中到处都大量存在。在我们银河系和其他星系的星际云中已经发现了水。人们只要看看水的化学性质就能理解它的平凡。一个水分子由两个氢原子和一个氧原子共价键合而成。

The Atomic Structure of a Water Molecule
氢是整个宇宙中最丰富的元素,在“大爆炸”期间产生。氧是第三丰富的元素,由恒星的核聚变产生。这两者一起形成水。除了天王星和海王星之外,太阳系中的所有行星在其大气层中都有少量的水蒸气,范围从 0.0004%(木星)到 3.4%(水星)。土星的卫星之一,恩克拉多斯,有 91%的水蒸气组成,被认为是太阳系中最有可能居住的地方之一。
然而,对于生命的发展来说,水不是以蒸汽或冰的形式存在,而是以液体的形式存在,这种液体非常罕见,因为它取决于表面温度,而表面温度又取决于大气压力,而大气压力是由行星的表面重力决定的。所有这些要求只能同时在可居住区找到。此外,液体只能存在于表面,这意味着气态行星无法维持水。

Different states of water
本质上,任何行星上孕育生命所需的主要因素似乎都取决于它的质量、大气层以及与母星的距离。这些将在下面详细阐述。
1)距离
一颗行星必须有一个坚固的岩石表面,并且与它的恒星保持完美的距离,以保持其表面的液态水。在太远的地方,行星将会太冷而无法维持其表面的液态水,因为表面温度将会降至冰点以下,导致海洋变成冰。太近的话,地球的温度会超过水的沸点,海洋会变成蒸汽。因此,水能够以液体形式存在的完美区域是这两个极端之间的地带,称为可居住区。

The Habitable Zone (green) of our solar system.
这个地区也被称为“金发姑娘区”,源于著名的故事“T2”、“金发姑娘和三只熊”,在这里,金发姑娘选择不冷不热的汤。同样,对于遵循这一原则的行星来说,它既不应该离它的恒星太近,也不应该太远,而是应该在适当的距离。
每个行星系统的宜居带将从离其恒星不同的距离开始,因为它取决于中心恒星的质量。恒星的质量越大,散发的热量就越多,将可居住区域的内部边缘推得越远,如下图所示。

The Habitable Region (blue) depending on the Star’s Mass. Source: Astrobiology Magazine
因此,当我们寻找系外行星时,我们会在可居住区内寻找,因为这是找到类地行星的最佳选择。目前还不知道在可居住带发现的几颗行星是类地行星还是气态行星。被确认为类地行星的不是位于适居带。此外,仅仅在可居住区找到行星并不能保证存在生命,因为还有其他几个关键因素发挥着重要作用。
2)质量
对于位于可居住区的行星来说,行星的引力必须足够强,才能容纳大气层,大气层可以作为缓冲,有助于保持稳定的表面温度。行星的表面重力可以用下面的公式计算:

其中:
- g 是引力常数= 6.67 * 10^-11 [ N ]
- m 是行星的质量[ kg
- r 是行星的半径[ 米
正如我们所见,重力取决于行星的质量和半径。这很关键。例如,如果地球更小,比方说大约有火星那么大,重力就会弱得多,因为质量和半径都会更小,因此它无法阻止水分子飞入太空,导致大气层非常稀薄。这将降低大气缓冲的有效性,允许极端温度的存在,从而防止水的积累。这就是为什么液态水不能在火星上存在,尽管它位于可居住带的边缘。小质量几乎不允许水在极地冰盖以固态存在。这就是为什么为了评估一颗系外行星的可居住性,了解它的质量是至关重要的。
3)大气
这也许是判断一个星球维持生命能力的最重要的因素。没有大气的压力,液态水无法生存。让我们以月球为例:它没有大气层,甚至没有像火星那样稀薄的大气层。因此,如果我们在月球上洒一些水,它要么会蒸发成蒸汽,要么会冻结固体,形成冰。因此,为了孕育生命,一颗行星必须有大气层,并且足够厚,足以让行星保持恒定的温度,并对水施加压力,使其保持液态。
然而,大气层的厚度并不是可居住性之谜的唯一重要组成部分。它的实际成分也必须正确。让我们以金星为例。金星在物理特征上是最接近地球的行星:同样位于宜居带,表面重力 8.9 [ m/s^2 ],是地球重力的 90%,质量是地球的 82%,体积是地球的 86%,密度几乎相同。一个观察我们太阳系的外星天文学家会认为金星是生命存在的好机会。

Size comparison of Venus and Earth, drawn to scale. Source: NASA, Wikipedia Commons.
然而,正如我们所知,金星不适合生命居住,因为它太热了。它的大气层是太阳系中密度最大的类地行星,其表面压力是地球的 92 倍。它的大气层几乎完全由二氧化碳和其他温室气体组成,并且完全没有任何分子氧。因此,金星的平均表面温度约为 464 摄氏度,是太阳系中最高的,远远高于水的沸点。与地球不同,它也缺乏磁场,这使得太阳风无法将游离氢(水的基本成分)吹到行星际空间。因此金星的表面非常干燥,并被沙漠覆盖。尽管金星在许多方面与地球相似,但它肯定不适合居住。
因此,寻找与地球质量、距离和大气相同的系外行星仅仅是个开始。与金星一样,这些因素不一定足以让生命发展。我们必须仔细观察构成大气的,并确定那些至关重要的元素,如氢、氧,还有氮和碳,是否以正确的的百分比存在。这些为我们所知的生命的基础和发展奠定了 基础 。实际的生命成分清单要大得多,而且可以无止境地详细列出。正确的行星轨道和自转,正确的地球化学和地质机制都可以将行星的状态从宜居变为不宜居。因素是无限的。****
然而,生命出现所需的一系列连续现象依赖于一个无法控制或分类的因素:偶然性。根据我们目前的理解,是偶然使一个小天体与另一个小天体碰撞形成星子,这些星子后来发展成为类地行星。也许正是由于一颗彗星与地球相撞的偶然机会,水被引进了这个星球。事实上,“运气”可能是创造生命本身的另一个必要成分。
而我们不知道的生活呢?如果它需要一种液体而不是水才能出现并繁荣呢?也许是我们是不同的生物,生活在一个不寻常和极端的环境中。或者也许地球只是众多可居住世界中的一种。我们可以无休止地推测,但唯一能确定的方法是走出去探索。****
结论
在这篇论文中,我提出了一个关于系外行星的广泛文献综述的精华,并解释了将它们与基本物理定律联系起来的探测方法。我使用了公开可用的系外行星研究数据,并在一位天文学专家的指导下,使用相关参数的组合生成了一系列图表。我研究了这些图表,并将它们与基本的物理定律联系起来,比如开普勒的行星运动第三定律和牛顿的万有引力定律。以图表为基础,我采访了著名的天体物理学家 Didier Queloz 教授,以进一步了解当前的发现和对热点木星反复出现的发现等问题的科学思考。最后,我确定并解释了影响生命出现的一些因素,包括偶然性等非理性因素。基于这一回顾和分析,我能够解释为什么我们寻找系外行星,以及这一探索实际上有多么有意义。**
自从 1995 年发现第一颗系外行星以来,我们已经走过了漫长的道路。这个领域已经发展成为一个巨大的科学领域,超越了纯粹的物理学,并慢慢深入到天体生物学和化学领域。我们已经看到,系外行星的发现率一直在稳步上升,在我们的银河系中,行星似乎在它们的恒星周围很常见。一些已经在可居住区被探测到,但是不幸的是它们看起来不像是地球上的。事实上,发现的行星系统并不像我们的太阳系,因为它们中的许多都含有热木星和超级地球,这两者在我们的系统中都不存在。这可能是由于我们有限的探测方法的选择效应,或者可能是宇宙的方式。
通过对系外行星的探测,我们已经了解了地球本身的性质以及它自近 40 亿年以来所维持的不同生命形式。我们对我们在浩瀚宇宙中的独特位置有了批判性的认识,并且有实际的科学证据证明,我们似乎处于一张图中的一个孤立的角落,不同于我们所有其他的宇宙邻居。通过寻找和,我们不仅扩展了我们的物理和概念边界,而且理解了在地球上这里所发生的独特性。在这个过程中,一个人更好地将的价值观根植于我们自己的生活中。我们确实是幸运的活着,并且像许多信仰自古以来宣称的那样是特别的。自早期哲学家开始思考以来,没有任何其他科学领域给了我们如此多的实质内容来回答这些问题。这就是我们继续寻找系外行星的原因。
尽管我们还没有发现其他生命,但我们正在积极地向自己提问,并通过开展新的科学项目来寻找答案,这一事实表明我们正在不断地努力扩展我们的知识。亚瑟·C·克拉克曾经说过,我们在宇宙中要么孤独,要么不孤独,这两种可能性都同样可怕。我想说两者都同样令人敬畏。因为即使我们是单独的,我们思考、思考、梦想和问这些问题的事实实际上可能是宇宙中最重要和最有用的元素之一。这表明我们对知识和理解的追求永远不会变得乏味。事实上,我们知道的越多,我们的宇宙似乎就越不可思议,更多的问题似乎就要浮出水面。
正是这些没有答案的问题驱使我们的好奇心去推动当前科学思想和努力的前沿。因此,通过提出更多的问题,也许是自然本身推动人类不断努力寻找答案。如果外星生物真的存在于这个看似空虚的海洋中的某个地方,我衷心希望我们分享对知识的渴望,因为这是将我们聚集在一起的唯一力量。与此同时,我们只能尝试短暂地捕捉大自然的美,因为它在宇宙的尺度上顺其自然。
延伸阅读:
- 第一部分 : 方法和发现
- 第二部分 : 数据解释
- 原报道:https://eklavyafcb.github.io/exoplanets.html
参考资料:
利用功效分析计算实验样本量

如果你用实验来评估一个产品的特性,我希望你这样做,那么得到有统计学意义的结果所需的最小样本量的问题经常被提出来。在本文中,我们解释了如何应用数理统计和功效分析来计算 AB 测试样本量。
在启动实验之前,计算 ROI 和估计获得统计显著性所需的时间是至关重要的。AB 测试不可能永远持续下去。然而,如果我们没有收集足够的数据,我们的实验得到的统计能力很小,这不允许我们确定获胜者并做出正确的决定。
什么是统计能力

先说术语。统计功效是在替代假设 H1 为真的情况下,一个或另一个统计标准能够正确拒绝零假设 H0 的概率。统计测试的能力越高,你犯第二类错误的可能性就越小。
第二类错误与以下因素密切相关
- 样本之间的差异幅度—影响大小
- 观察次数
- 数据的传播
功效分析允许您确定具有特定置信水平的样本量,该置信水平是识别效应大小所必需的。此外,这种分析可以估计在给定样本量下检测差异的概率。
对于“足够”大的样本,即使很小的差异也具有统计学意义,反之亦然,对于小样本,即使很大的差异也难以识别。
最重要的是观察次数:样本量越大,统计功效越高。对于“足够”大的样本,即使很小的差异也具有统计学意义,反之亦然,对于小样本,即使很大的差异也难以识别。通过了解这些模式,我们可以预先确定获得有统计学意义的结果所需的最小样本量。在实践中,通常,等于或大于 80%的检验功效被认为是可接受的(相当于 20%的β风险)。这一水平是α风险和β风险水平之间所谓的“一比四权衡”关系的结果:如果我们接受显著性水平α = 0.05,那么β = 0.05 × 4 = 0.20,标准的功效为 P = 1–0.20 = 0.80。
现在我们来看看效果尺寸。计算所需样本有两种方法
- 使用置信水平、效应大小和功效水平进行计算
- 应用顺序分析,允许在实验过程中计算所需的样本量
让我们研究第一种情况,对两个独立的样本使用 t 检验

让我们假设我们测试了一个旨在提高“商品到愿望清单”转化率的假设。Delta,涵盖了六个月回报率> = 5%的实验成本。这种> = 5%的收益导致了额外的利润,这涵盖了实验中投入的所有资源。除此之外,你要有 90%的把握你会发现差异,如果它们存在的话,还有 95%的把握——你不接受随机波动的差异。
d — delta,siglevel —置信水平,power —功率水平
pwr.t.test(d=.05, sig.level=.05, power=.9, alternative="two.sided") ## Two-sample t test power calculation
##
## n = 8406.896
## d = 0.05
## sig.level = 0.05
## power = 0.9
## alternative = two.sided
##
## NOTE: n is number in *each* group
让我们看看另一个案例,利益相关者希望在几周内得到结果。在这种情况下,我们有一个大约 4000 名访问者的样本量,delta >=5%。我们想知道在上述情况下获得统计显著结果的概率。
添加 n,移除电源
pwr.t.test(d=.05, n=2000, sig.level=.05, alternative="two.sided") ## Two-sample t test power calculation
##
## n = 2000
## d = 0.05
## sig.level = 0.05
## power = 0.3524674
## alternative = two.sided
##
## NOTE: n is number in *each* group
确定差异的概率(如果有的话)是 35%,这不算太低,而错过期望效果的概率是 65%,这太高了。
让我们看看下面的图表。它清楚地表明,效应越大,获得显著结果所需的样本越少。

在计划实验时,计算所需的数据量至关重要,因为任何实验都需要资金和时间成本。因此,为了估计实验的潜在 ROI,提前计划所有未知变量是很重要的。
最初发表于【awsmd.com】。
数据科学时代的实验数学
两个关于我们如何使用猜测和统计工作来做真正的数学的故事
在我们高中的第一堂数学课后,我们的新老师给了我们一页纸,上面有 7 个涉及多项式的问题。虽然我不记得任何具体的问题,但我记得接下来几天课堂上的恐慌程度。全班都很震惊,因为以前我们最多只遇到过二次方程……现在他要我们解决涉及这些神秘生物的问题,这些生物可以达到他们想要的 n,谁知道他们是否有解析解?(伽罗瓦知道。他们大多不会)
他教我们的下一件事是生成函数和递归。他向我们展示了斐波那契数列的一般公式,以及欧拉如何得出他著名的巴塞尔问题的求和。

然后,我取得了我的第一个数学学位。令我惊讶的是,我再也没有遇到过这些东西。回到高中,我确信这就是数学的全部,但现在作为一个更成熟、更有教养的学者,我知道这些是古老的数学和儿童游戏。
想象一下,当我攻读硕士学位,处理与博弈论相关的问题时,我的第二个惊喜是,多项式和递归这些精确的主题以最自然的方式出现了..!
抛开我感人的个人故事,我希望在这篇文章中给出一些实验在数学中的重要地位,以及如何“像数据科学家一样做数学”。当然,将数学视为实验被认为是完全的异端——这是归纳谬误,对吗?但实际上,猜测的艺术在数学中有很多位置,如果你能在以后用一个完整的论证来包装你的猜测,那么你就能得到严格有效的结果。
让我们从一些必备软件开始。有很多符号数学软件——CoQ、sage、maple 等等。在这个世界里,你不能像在软件开发创业世界里那样吹毛求疵——对于软件的任何特定用途,如果它不是完全标准的,很可能只有一种实现——所以无论是在 Maple、Matlab 还是在某人为微波芯片汇编开发的专有框架中,你都必须学会使用它。无论如何,为了阅读这篇文章,我建议你安装 python,Mathematica 和 Matlab。如果您不知道,您仍然可以跟踪简单的代码解释和结果。
10 行 Mathematica 中的一篇欧拉文章
在奥地利林茨的 RISC 研究所,他们为 Mathematica 开发了令人惊叹的 RISCErgosum 包。这个包基本可以证明你能想到的任何身份。让我们看看它如何证明 250 年前的欧拉论文——正如这篇精彩文章摘要中所描述的。
在这篇文章中,欧拉用求中心三项式系数满足的递推公式的方法,导出了中心三项式系数的一般公式。他用了整整一章来讲述他的一次失败的尝试,其中一个基于斐波那契数列的简单递归似乎成立,但通过计算该数列的足够多的项,欧拉最终设法发现这个递归一般不成立,并找到了正确的表达式。我们可以用下面简单的 10 行代码继续他在 Mathematica 方面的努力:
- 首先我们定义欧拉试图确定的级数,作为 myf 的通称。
- 我们还将其拆分为奇数和偶数索引系列(myfodd,myfeven),这样就可以避免使用 Floor[]。这将使 Mathematica 更容易证明我们提取的递归实际上一般成立。
- 我们将它的前 20 个值导出为 fres。
- 然后我们定义欧拉怀疑能够表达原始序列的序列,并将其前 20 个值导出为 GRE。
- Guess 成功地分别为 frec 和 grec 两个系列找到了一个递归。但是它们是不同的。
- 现在,我们将原始级数的符号项输入到递归中,FullSimplify 象征性地为我们验证了它确实在一般情况下成立,产生了应用于项的递归关系,它们的总和等于零。
- 瞧啊。我们完了。
下面是代码和结果:

我只欺骗了一点点——full simplify 并不总是值得信任的,实际上可能会出错。但是考虑到这种循环,无论是通过计算机代数还是手工,都有可能验证它确实普遍成立。“困难的部分”是猜测。
通过简单模拟得到随机过程练习解
让我们来看另一个在更新过程中解决问题的实验方法的例子。想象一下下面这个由无聊少年管理的宠物动物园。
孩子们轮流去宠物动物园。每当一群孩子进来,id 间隔 T1,T2,T3,…分布为 Geo(p),因为青少年有时做他的工作,但有时也懈怠了越来越长的时间。但是因为他知道他要偷懒,他输入了许多孩子 Nk,所以 Nk-s 是独立的,但是给定 Tk+1 = n 的 Nk 的条件分布是 Uni{1,…,n+2}。所以即使他在偷懒,还是会有更多的孩子进去,所以应该没问题。问题是,从长远来看,孩子们在宠物动物园的平均时间是多少?
解析地解决它并不太难——你定义一个匹配的奖励更新过程,通过奖励更新定理和一些总结,你最终会得出公式

p 是几何分布参数。但这需要一些随机过程分析和基本概率方面的知识。即使你对自己的分析能力很有把握,也可以和模拟进行比较。因此,即使不了解太多,您也可以编写以下代码:
- 你做了一百万次实验
- 当你模仿问题的描述时,你会有下一组孩子在某个随机的几何时间间隔内到来,相应地,他们的数量是一致随机的。你把孩子们在网站上花的时间加起来,最后除以访问网站的孩子总数。然后,您将它视为对我们结果的模拟估计。
以下是实现此过程的简单 python 代码:
我们对不同的 p 值运行这个代码,然后我们有一个解的 p 中的函数的估计。但是这怎么能给我们一个公式呢?嗯,即使不做精确的计算,你也可以很确定我们要找的公式是一个有理函数。这是因为它将是涉及均匀分布和几何分布的期望之间的某个比率,这可能是 p 中的低阶多项式。然后我们可以使用任何工具来拟合我们获得的模拟数据的有理函数,我使用了 Matlab 的 cftool
在解释器中键入:
X = 1:100
X = X/100
Y = python_simulation_results
cftool(X,Y)

你可以看到它非常合身。在现实生活中,我没有使用 cftool,而是因为我在分析计算中不断出现算术错误,所以我使用模拟通过猜测一些值来确定确切的表达式。如果我在最初的几次猜测中遇到困难,我会求助于某种有理函数拟合程序。
多少次实验就够了?
现在,也许关于进行实验最重要的问题是什么时候停止。试几次就够了?
对于一些有度数或维数概念的代数实体,我们知道答案。n 次多项式由 n+1 个点决定。因此,对多项式的 n+1 个点进行采样就足以唯一地确定其完整形式。类似的事情适用于 n 阶递归——如果我们知道递归适用于我们的级数,并且我们有 n 个点,其中我们的级数表达式与递归的解一致,那么假设递归表达式没有太坏的事情发生,我们可以归纳并获得真正的一致。
至于更新过程和一般的马尔可夫链,模拟可以产生非常精确的数字,有时比分析计算要少得多,并且保证如下:
我将从那里引用一个很酷的结果:
当你想得到一副均匀分布的牌时,最安全的方法是先随机拿一张牌,然后再从剩下的牌中随机拿一张,以此类推。但是这需要你在第一步从 52 张牌中做出选择,第二步从 51 张中做出选择…你最终需要从可能的 52 张牌中选择一副牌!。
但是,现实生活中也会发生这样的事情,你拿着一副不是随机的牌,你相信经过几次洗牌后,它会和随机的一样好。很明显,如果你只移动一两张牌,不会有什么不同。而且很明显,如果你一直这样做,那么这副牌将会被随机化。什么时候停止比较合适?阅读概述,你会看到,大约 NlogN ~ 400 单卡更换应该做到这一点。这里他们想出了 277 这个数字。当然,如果你做步枪走步,它会花更少的时间,因为在每一次“走步”中,你会有更多的单步发生。
如果这篇文章让你对计算机代数、实验数学或随机模拟产生了一点兴趣,我强烈推荐这些作为进一步的阅读材料:
A=B ,一本关于使用递归关系证明恒等式的艺术和科学的巨著
《A=B》一书的作者多伦·泽尔伯格的实验数学宣言
一本关于随机模拟的伟大而实用的书
数据科学实验
当 AB 测试没有切断它
今天,我要谈谈数据科学中的实验,为什么它如此重要,以及当 AB 测试不合适时,我们可能考虑使用的一些不同的技术。实验旨在确定变量之间的因果关系,这在许多领域都是一个非常重要的概念,对于今天的数据科学家来说尤其重要。假设我们是在产品团队中工作的数据科学家。很有可能,我们的很大一部分职责将是确定新特性是否会对我们关心的指标产生积极影响。也就是说,如果我们引入一个新的特性,使用户更容易向他们的朋友推荐我们的应用,这是否会提高用户增长?这些是产品团队感兴趣的问题类型,实验可以帮助提供答案。然而,因果关系很少是容易识别的,在许多情况下,我们需要稍微深入思考我们的实验设计,这样我们就不会做出不正确的推断。在这种情况下,我们可以使用经常使用的技术取自计量经济学和我将讨论其中一些下面。希望到最后,您将更好地了解这些技术何时应用以及如何有效地使用它们。
AB 测试
大多数读过这篇文章的人可能听说过 AB 测试,因为这是一种极其常见的工业实验方法,用来了解我们对产品所做的更改所产生的影响。这可能很简单,只需更改网页布局或按钮颜色,然后衡量这一更改对点击率等关键指标的影响。在这里,我不会过多地介绍细节,因为我想重点介绍一些替代技术,但是对于那些有兴趣进一步了解 AB 测试的人来说,下面关于 Udacity 的课程提供了一个非常好的概述。一般来说,我们可以采用两种不同的方法来进行 AB 测试。我们可以使用频繁方法和贝叶斯方法,这两种方法各有利弊。
频率论者
我会说 frequentist AB 测试是迄今为止最常见的 AB 测试类型,直接遵循 frequentist 统计学的原则。这里的目标是通过观察我们在 A 组和 B 组中的度量之间的差异是否在某种显著性水平上具有统计学显著性来测量我们治疗的因果效应,通常选择 5%或 1%。更具体地说,我们需要定义一个零假设和替代假设,并确定我们是否能够拒绝零假设。根据我们选择的指标类型,我们可能会使用不同的统计测试,但在实践中通常会使用卡方检验和 t 检验。然而,频率主义方法有一些限制,我认为与贝叶斯方法相比,它更难解释和说明,但可能因为贝叶斯设置中的基础数学更复杂,所以它不常用。frequentist 方法的一个关键点是,我们计算的参数或度量是一个常数。因此,没有与之相关的概率分布。
贝叶斯定理的
贝叶斯方法的关键区别在于,我们的指标是一个随机变量,因此有一个概率分布。这是非常有用的,因为我们现在可以结合我们的估计的不确定性,并作出概率陈述,这对于人们来说往往比频率主义者的解释更直观。使用贝叶斯方法的另一个优点是,与 AB 测试相比,我们可以更快地找到解决方案,因为我们不一定需要为每个变量分配相同数量的数据。这意味着贝叶斯方法可以使用更少的资源更快地收敛到一个解决方案。选择哪种方法显然取决于个人情况,这在很大程度上取决于数据科学家。无论你选择哪种方法,它们都是识别因果关系的强有力的方法。
当 AB 测试不奏效时
然而,在许多情况下,抗体检测并不适合用来鉴定因果关系。例如,为了使 AB 测试有效,我们必须将随机选择到 A 组和 B 组。这并不总是可能的,因为一些干预措施可能因特定原因针对个人,使他们与其他使用者有根本的不同。换句话说,进入每个组的选择是非随机的。稍后,我将讨论并提供我最近遇到的一个具体例子的代码。
AB 测试可能无效的另一个原因是当我们有混淆时。在这种情况下,查看变量之间的相关性可能会产生误导。我们想知道 X 是否导致 Y,但也可能是其他变量 Z 驱动了两者。这使得不可能理清 X 对 Y 的影响,从而很难推断出任何因果关系。这也经常被称为 省略变量偏差 ,会导致我们高估或者低估 X 对 Y 的真实影响。除此之外,从商业角度来看,设计随机实验可能不可行,因为如果我们给一些用户提供新功能,而不给其他用户提供这些功能,可能会花费太多资金,或者被视为不公平。在这种情况下,我们必须依靠准随机实验。
好了,我们已经讨论了我们可能无法应用 AB 测试的一些原因,但是我们能做些什么来代替呢?这就是 计量经济学 的用武之地。与机器学习相比,计量经济学更关注因果关系,因此,经济学家/社会科学家开发了一系列统计技术,旨在了解一个变量对另一个变量的因果影响。下面我将展示一些技术,数据科学家可以也应该从计量经济学中借鉴这些技术,以避免从实验中得出错误的推论,而这些实验会受到上述问题的困扰。
工具变量
假设我们是一家拥有类似 medium 的应用程序的公司,用户可以订阅主题以获取与这些主题相关的内容更新。 现在想象你的产品负责人带着一个假设来找你:订阅更多的话题会让用户更投入,因为他们会获得更多相关和有趣的新内容来阅读 。嗯,这听起来像是一个合理的假设,我们可能认为这很可能是真的,但我们如何用实验来测量呢?
您可能考虑做的第一件事是通过将用户随机分成两组来进行传统的 AB 测试。然而,这将是非常困难的,因为用户已经有不同数量的主题订阅,我们不能真正随机地给用户分配主题订阅。主要的问题是,由于一些不为人知的原因,订阅更多主题的用户可能会比其他用户更投入。这本质上是 内生性 ,因为有一些看不见的因素在推动这些用户的参与度。
幸运的是,经济学有答案。我们可以使用被称为 的工具变量 来帮助我们解决这个内生性问题。如果我们可以找到一个变量(工具)与我们的内生变量(订阅数量)相关,但与我们的因变量(参与度)无关,我们可以用它来清除看不见的因素的影响,并获得订阅数量对参与度的影响的无偏因果估计。但是我们能用什么作为工具呢?这通常是经济学中最大的问题,因为在许多情况下很难找到工具。然而,在我们的案例中,如果我们在一家进行大量 AB 测试的公司,我们可以利用这一点。要获得有效的工具,我们需要两个假设:
- 强第一阶段
- 排除限制
假设过去我们运行了一个 AB 测试,将用户随机分成两组,并在主页上向 B 组显示订阅主题的提示。让我们假设这个 AB 测试也显示了积极的影响,接受治疗的用户最终比控制组订阅了更多的主题。我们可以用这个实验作为工具,来帮助我们识别参与度问题中的因果关系。为什么会这样?嗯,第* 个假设 已经得到满足,因为 AB 测试对订阅数量产生了统计上显著的正面影响。 第二个假设 也得到满足,因为*分配是随机的,因此被处理与敬业度无关,仅通过增加订阅数量来影响敬业度。**
现在,为了实际实现这一点,我们可以使用所谓的两阶段最小二乘法。好消息是这很容易做到,只需要估计两个回归。顾名思义,有两个阶段,在第一阶段,我们将回归处理变量(虚拟变量,识别用户是否在 AB 测试的处理或控制组中)的订阅数量。这将为我们提供治疗组和对照组的预测订阅数。在第二阶段,我们回归第一阶段的预测值。这将为我们提供订阅数量对参与度的因果影响的无偏估计。
概要:
- 对订阅数进行回归处理:得到预测值
- 回归约定的预测值。
您可以使用 statsmodels 库在 Python 中实现这一点,它看起来类似于下面的代码。
***import** **statsmodels.formula.api** **as** **smf****reg1 = smf.ols(formula = "number_of_subscriptions ~ treated", data = data).fit()
pred = reg1.predict()****reg2 = smf.ols(forumla = "engagement ~ pred", data = data)***
回归不连续设计(RDD)
RDD 是另一种可以从经济学中获得的技术,当我们有一个连续的自然分界点时,它特别适合。那些刚好低于临界值的人得不到治疗,而那些刚好高于临界值的人得到了治疗。这个想法是,这两组人非常相似,所以他们之间唯一的系统性差异是他们是否接受过治疗。因为这些组被认为非常相似,这些分配基本上近似于随机选择。特别是,两组间 Y 变量的任何差异都归因于治疗。
使用 RDD 的经典例子有望使这个观点更加清晰,那就是杰出的学术成就获得社会认可(奖状)会有什么影响?与那些没有得到这种社会认可的人相比,它会带来更好的结果吗?我们可以将 RDD 应用到这个例子中的原因是,奖状只颁发给那些在测试中得分超过某个阈值的个人。使用这种方法,我们现在可以在阈值比较两组之间的平均结果,看看是否有统计学上的显著影响。
这可能有助于想象 RDD。下图显示了低于和高于阈值的平均结果。实际上,我们所做的只是测量截止点旁边两条蓝线之间的差异。在经济学中使用 RDD 的例子还有很多,这里的一些例子有望让你了解不同的用例。对于那些想了解这些话题更多背景知识的人,你可以查看以下免费的课程。

Source: Example: RDD cutoff: Threshold at 50 on the x-axis
差异中的差异(差异中的差异)
我将在 Diff 中更详细地介绍 Diff,因为我最近在一个项目中使用了这种技术。这个问题是许多数据科学家在日常工作中可能会遇到的,并且与防止流失有关。对于公司来说,尝试识别可能流失的客户,然后设计干预措施来防止它是非常常见的。现在,识别客户流失是机器学习的一个问题,我不会在这里深入探讨。我们关心的是,我们能否找到一种方法来衡量我们的流失干预措施的有效性。能够凭经验衡量我们决策的有效性是非常重要的,因为我们希望量化我们特征的效果(通常以货币形式),这是为企业做出明智决策的重要部分。其中一种干预措施是给那些有被大量购买风险的人发一封电子邮件,提醒他们注意自己的账户,实际上是试图让他们更多地参与我们的产品。这是我们将在这里研究的问题的基础。
好的,我们想知道这封电子邮件活动是否有效,我们该怎么做呢?嗯,我们需要做的第一件事是想出一些我们想要衡量的指标,我们预计会受到活动的影响。从逻辑上考虑,如果我们阻止用户搅动,那么他们将继续使用我们的产品,并为公司创造收入。这似乎有道理,所以让我们使用平均收入作为我们的衡量标准。您选择的指标在很大程度上取决于问题,如果我们不希望我们的指标以相对直接的方式影响收入,那么它可能不是本实验的最佳选择。总而言之,我们的假设是 将这封邮件发送给有客户流失风险的人会阻止他们流失,从而提高这些客户 的平均收入。如果这个假设是真的,我们可以预计治疗组的平均收入将高于对照组(那些没有收到电子邮件的人)的平均收入。
现在你可能认为这听起来像一个常规的老 AB 测试,但是这种方法有一个主要问题。A 组和 B 组根本不同,因为进入这两个组的选择不是随机的。根据我们的机器学习模型的结果,B 组中的用户更有可能流失,而 A 组中的用户不太可能流失。在这种情况下,我们不会比较苹果,这将导致我们的结果有偏差。专业术语称之为选择偏差。
然而,我们可以用 Diff 中的 Diff 来处理这个问题。本质上,它比较了治疗发生前后对照组和治疗组中度量的差异。这样做允许我们控制组间预先存在的差异,减少选择偏差。在方程形式中,它看起来与下面类似:其中 a 是对照组,b 是治疗组,t 表示干预前的时间段,t+1 是干预后的时间段。

Figure 1: diff in diff estimator
这种方法的好处是它很容易估计,我们可以使用回归框架来完成。这还提供了额外的好处,即能够控制其他特征,如用户的年龄和位置,从而减少遗漏可变偏差的可能性。使用这种方法时需要注意的一点是,要使该技术有效,必须满足某些假设。其中最重要的可能是平行趋势假设。简而言之,它表明如果没有干预,那么治疗组和对照组之间的差异将随着时间的推移而保持不变。这在实践中很难测试,通常最好的方法是直观地观察一段时间内的趋势。
接下来,我将通过一个使用 python 的 Diff 中的 Diff 的快速示例来演示如何在实践中评估这种类型的模型。注意:不幸的是,因为我使用的数据是敏感的,我不能深入数据集,但是* 这里的 是一个类似的数据集,包含客户人口统计信息和交易信息。*
差异案例研究中的差异
继续上面的解释,我们现在将在 Python 中实现 Diff 中的 Diff,向您展示在实践中估计它是多么简单。在下面的代码中,我假设我们有两个主要的数据源,一个是记录每个用户交易的交易表,另一个是包含客户信息(如年龄和位置等)的用户表。我们的目标是估计以下形式的方程:

Figure 2: Diff in Diff regression equation
- y 是我们的平均收入指标
- 如果用户属于治疗组,Treat = 1,否则为 0
- 如果是后处理,时间= 1,如果是预处理,时间= 0
- 𝛿 是上图 1 中的差分估计量(DD)
- x 是我们控制变量的矩阵
根据上面的等式,我们首先需要定义治疗和时间虚拟变量,这将有助于我们将用户分为对照组和治疗组,以及治疗前和治疗后。然后,我们可以通过将这两个特征相乘来定义 DD 相互作用项。最终结果是一个数据帧,包含我们的用户特征(X)、两个虚拟变量和我们最感兴趣的交互项。现在,我们要做的就是在我们的平均收入指标上回归这些变量,看看 𝛿 在我们选择的显著性水平(5%)上是否具有统计显著性。statsmodels 库使得回归的实现非常简单。为简洁起见,我省略了任何数据清理和特征工程,但这是该过程的重要部分,是您应该作为正常工作流程的一部分来做的事情。
***import** **statsmodels.formula.api** **as** **smf****reg1 = smf.ols(formula='revenue ~ treated + time_dummy + DD + X', data = data)
res = reg1.fit()***

Figure 3: Diff in Diff Results
我们可以从图 3 的结果中看到,我们的 DD 估计值在 5%的水平上是显著的和正的,表明我们的治疗产生了积极的影响。更具体地说,这个 p 值意味着,假设零假设(干预没有效果)为真,我们观察到如此大的影响的概率非常小。因此,我们可以拒绝零假设,并得出结论,我们的电子邮件活动已经成功地减少了客户流失,因此,我们为该群体带来了更高的平均收入,因为他们继续使用我们的产品。
好了,伙计们,这个帖子到此为止。希望这突出了在数据科学中进行实验的相关性,以及当我们面临内生性和样本选择偏差等问题时,计量经济学技术如何在确定因果关系方面特别有用。下面是一些有用的链接,可以帮助任何想更深入了解这些概念的人。
参考资料及有用资源:
- https://github . com/Nate matias/research _ in _ python/blob/master/Regression _ discontinuity/Regression % 20 discontinuity % 20 analysis . ipynb
- http://pub docs . world bank . org/en/555311525379751882/TT 6 regressiondiscontinuity ferre . pdf
受控实验的 3 个常见陷阱
实验和因果推断
不合规、外部有效性和伦理考虑

Photo by Michal Matlon on Unsplash
2021 年 2 月 21 日更新
在两篇文章中(为什么要进行更多的实验和双向因果关系),我提出了我们应该进行更多受控实验并做出明智的商业决策的想法。实验擅长于提高内部效度,区分因果关系和相关性,以及产生和检验假设。
有一个心理陷阱经常绊倒数据科学家:他们选择最熟悉的方法,而不是选择最能回答问题的方法。
"如果你只有一把锤子,所有的东西看起来都像钉子."
伯纳德·巴鲁克
为了谨慎起见,我在今天的帖子中详细阐述了实验的陷阱。采用这种方法时,数据科学家应该首先考虑研究问题,然后检查方法的适用性和局限性。也就是检查你要回答什么,检查你有什么信息和约束。
何时不使用
如果这三种情况中的一种或多种发生了,你可能要对实验三思:
1。高度不合规
采用实验的全部意义在于它的高内部效度,这源于一个随机化过程(我的解释)。也就是说,研究参与者被随机分配到治疗组和对照组。
然而,高不符合率或退出率表明设计有问题,并损害了研究的可信度。
这里有一个假设的场景。数据科学和 UX 团队在谷歌合作,试图在搜索算法更新后跟踪用户的行为变化。一位名叫约翰的用户被选中接触新设计,但他在研究中途退出了。例如,用户在一段时间后清空他们的 cookies 后会流失。研究人员争先恐后地寻找与约翰的用户属性相似的替代品。然而,替换不是约翰,并且在实验中间的用户替换对统计假设提出了挑战(例如,缺失数据、依赖性)。
此外,实验组之间的交叉污染会产生有偏见的估计。约翰可能无意中向对照组暴露了治疗状况(例如,更新他的脸书状态并让他的朋友知道该研究)。
2。社会实验的外部效度很低
实验环境并不是真实的世界,一旦用户意识到自己被监视,他们就会改变自己的行为。这两个世界之间存在差距,研究人员应该缩小差距,并确定他们设计的范围和限制。
在社会科学中,有一种现象叫做社会合意性。也就是说,如果可能的话,人们以社会可接受的方式表达自己和行为,并避免对抗。每个人都想成为社区的一部分。
作为一名政治学博士生,这是我最喜欢的现实生活中的例子。在 2016 年的总统选举中,多波民调研究表明希拉里将以较大优势获胜。最终结果出来时,真是一个巨大的惊喜。许多受访者隐藏了他们真实的政治偏好,给出了符合社会需求的回答。
此外,一个地区的实验发现在其他地区并不成立。欧洲用户的认知和行为模式与美国用户不同。任何来自欧洲用户的实验结果在应用于美国的案例时都应该持保留态度。
换句话说,你的研究适用性范围是什么?你的研究有高/低的外部效度吗?当你试图推广到更广泛的案例时,请格外小心,因为实验案例是独特的。
3。道德考量
一些实验给研究参与者带来压力和伤害。例如,研究人员曾经用积极和消极的情绪操纵社交媒体订阅,试图看看人类的情绪如何在虚拟环境中传播。
在这种情况下,研究人员应该告知研究参与者任何潜在的风险和危害。在用户明确同意参与之前,研究不应继续。
权衡的结果是,如果用户知道他们正在参与一项研究,他们可能会以一种意想不到的方式行事。此外,研究参与者和非参与者之间可能存在根本不同的属性。这两种情况都对我们的结果产生了有偏见的估计。
外卖食品
- 不合规
- 我们需要多少个实验组?
- 如何控制交叉污染?
- 我们如何更好地构建潜在的结果框架(例如,提供积极的激励,如亚马逊礼品卡)?
2。外部有效性
- 我们的研究条件看起来是真的还是假的?
- 我们研究的局限性是什么?有更好的选择吗?
- 如何获得真诚的回应?
3。道德考量
- 讲道德!
- 通知用户
- 明确同意参与
进一步阅读:
数据科学中因果关系和相关性之间的地盘之争
towardsdatascience.com](/the-turf-war-between-causality-and-correlation-in-data-science-which-one-is-more-important-9256f609ab92) [## 数据科学家应该有充分的理由进行更多的实验
好的,坏的,丑陋的
towardsdatascience.com](/why-do-we-do-and-how-can-we-benefit-from-experimental-studies-a3bbdab313fe)
喜欢读这本书吗?
还有,看看我其他关于人工智能和机器学习的帖子。
住宅水流分类实验
我从中了解到筛选另一个人的 IOT 数据有点令人毛骨悚然。
去年,我花了大量时间阅读机器学习算法——它们能做什么,以及如何在 Python 中使用它们。一天晚上,我和几个朋友在吃饭时讨论这些问题,其中一个朋友告诉我,他家里的主水管上连接了一个流量计,看看我们能用它做什么可能会很有趣。在查看数据后,我决定看看我们是否可以训练一个分类器来识别水流并对其进行分类。然后你就可以知道有多少水被用来冲厕所、洗碗池、淋浴等等。一天之内。
流量计每秒记录一次流量。一长串随时间变化的值称为“时间序列”,这类问题称为“时间序列分类”。
我使用的是一种叫做监督学习的机器学习,在这种学习中,你提出一种算法,它可以学习一些带标签的例子,然后它对以前从未见过的新数据进行分类。用于实验的训练数据是一小组手写标记的事件,每个事件有 1-4 个示例。我们手动识别了每种类型事件中的一些,很明显房子里的一些东西有不同的波形。早期的一系列训练活动如下所示:

你可以看到事件很容易用肉眼区分。从左到右,这些是马桶冲水、淋浴、浴缸注水、水槽水流和一些电器运行的示例。
隐私问题
当我在筛选我朋友的水流传感器的数据时,我被你能从某人家里的一个传感器推断出的东西震惊了。很简单,你可以看到有人在家。你可以看到房子的主人半夜起床,早上起床,睡觉的时候。人们洗不同的淋浴——观察几天后,你就能知道哪个淋浴属于哪个人。如果一个人离开了一天,也许是去旅行了,你也能看出来。厕所有一个标志,你不仅可以知道哪个冲了水,还可以知道是哪个。由于成年人通常不怎么洗澡,你可以通过对水流分类来推测谁有小孩。这让我想到我想把哪些传感器数据传输到云中,因为如果你有多个不同类型的传感器,我怀疑你可以非常准确地描述谁住在家里。
尝试过的方法
有两种对时间序列数据进行分类的基本方法。第一种是从时间序列中提取特征,如滚动平均值、最小值/最大值等。并将其呈现给学习算法进行分类。这就是使用 RandomForestClassifiers 和 XGBoost 进行学习算法的最初几次程序迭代的工作方式。后来的测试版本使用了一个名为 TSFresh 的特性提取库,从这个系列中提取了几百个特性。在文献中似乎没有关于最佳方法的共识。在尝试这种方法时,我用 TSFresh 特征提取和 XGBoost 得到了最好的结果。
第二种方法是将时间序列数据直接呈现给学习算法。根据文献,公认的最佳方法是使用动态时间弯曲(DTW)的距离度量将时间序列切片呈现给 K-最近邻分类器,其中 K 设置为 1。KNN 非常简单,它只是将测试波形分类为与它最匹配的训练示例相同的类别。衡量匹配程度的标准是距离度量,DTW。
KNN 与 DTW 的表现优于特征提取方法,虽然它更计算密集型。
在尝试了这些方法之后,我偶然发现了一篇很棒的文章“基于软计算技术的水终端使用分解”,它提供了特征提取方法的一种变体。如果您提取每个流量事件,并计算流量、持续时间和平均速率,您会得到一组三个值。如果你把它们用图表表示出来,你可以看到这些事件很好地聚集在一起。下面的 3D 图显示了一个例子:

现在,您将每个流量事件总结为一组数字:平均流量、总流量和持续时间。这些可以输入到各种学习算法中。我得到的最好结果是通过用已识别的示例事件制作标记的训练数据,然后在其上训练 KNN 或 XGBoost 分类器来实现的。它的计算量非常小——它可以在不到一分钟的时间内对一天的数据进行分类,包括生成可视化效果。这是迄今为止最成功的方法。
可视化
Matplotlib 和 Seaborn 用于生成图形,每个流用颜色编码以显示分类。
分类流量的样本图如下所示。



分类性能
厕所、淋浴、水槽和浴缸填充通常被正确分类。很容易将这些事件相加,以了解每个事件在某一天使用了多少水。尽管有一些限制。在复杂的流程中,许多事情同时发生,这是很难验证的。该算法对流量进行分类,但我无法判断它做得有多好,因为我无法判断发生了什么。此外,一些设备流量实际上无法与水槽流量或马桶流量区分开来。作为示例,洗碗机的全流程如下所示。

开始于样本 920 附近的波形很容易识别。然而,即使对人类来说,较大的尖峰看起来像厕所,较小的看起来像水槽。准确分类这些流量的唯一方法是注意它们出现在识别波形附近。将它们作为洗碗机流量包括在训练数据集中的努力导致高的假阳性率,将水槽流量误分类为洗碗机流量。这就是为什么水槽和设备流量被集中在一个分类下。
关于图形颜色的注释
Seaborn 的 Color Brewer 调色板工具文档指出,对于像这样的图,您可以区分类别,并且没有增加/减少值的含义,您需要“定性调色板”。这些都是为了易于区分类别而优化的。示例图使用了这些调色板中的一种,可读性比吸引力更好。
完整的可用调色板列表可在 https://jiffyclub.github.io/palettable/colorbrewer/获得,自定义调色板很容易定义。
树状图和快乐小意外的实验
在我的目标导向图表实验中,数据集中的每一项都由一个小矩形表示。根据用户想要看到的内容,它们会飞来飞去,堆叠成各种形状。因此,我需要针对分类和/或定量维度的不同组合的可视化类型。
例如,假设我们的矩形是电影,用户想看看他们有多少预算。我们有 1 个量化维度来表示,因此我们可以简单地根据预算按比例调整每部电影的大小:

这是一个简单类型的树形图。
现在用户想知道电影的预算是多少,取决于它们的类型。我们增加了一个范畴。矩形飞来飞去形成一个条形图,每个条形代表一个流派的电影总预算。与一个简单的条形图相比,条形图是一个树形图,我们可以看到各个元素,这给了我们额外的洞察力:这种类型的第一名是因为一些大型电影,还是许多普通电影?

用户再一次添加了另一个分类维度:他们想按类型和来源国查看电影的预算。矩形再次飞来飞去,这次为每个流派/国家组合形成一个树状图。它们按流派垂直排列,但现在水平分布在每个国家的一栏中。

已满的“单元格”(第 2 列,第 5 行)是总预算最大的一个,其余部分的大小与此相比。
这是一种热图,我们确实可以使用每个单元格的整体大小,并使用梯度来显示它们各自承载的价值。但在我看来,这让事情更难比较:

最后,让我们添加第三个分类维度。这一次我们可以使用颜色——每个树形图都被分割成子部分,每种颜色一个子部分。部分在树形图中按总值降序排序:

对于二维版本,我们还可以使用条形图和颜色:

关于实现的一些注意事项。
当构建一个树形图时,我们有以下问题:我们需要定位和确定矩形的大小,以便它们填充一个目标区域,同时每个矩形的表面等于它的重量。这是一个挑战,因为解决方案还必须使可视化对人类有用——我们需要看到有多少个项目,它们各自的大小是多少,并能够按需点击它们查看详细信息。
我发现可读性最好的方法是将它们“方形化”,使它们看起来尽可能的方形,同时满足上面的约束。不幸的是,为了进行计算,我们不能独立地逐个放置矩形,我们需要在每次迭代中考虑整个数据集。这使得一个完美的解决方案规模很小,实际上这是一个 NP 难题。所以我们需要寻求妥协。来自埃因霍温大学的这篇论文提出了一种实用、高效的方法,并产生了非常令人满意的结果。它也很容易理解和实现,绝对是我推荐的一本有趣的读物。
这就是我在应用程序中编写的代码。然而,当我在为那个模块搭建脚手架的时候,我有一个占位符 treemap 函数来提前开始测试整个模块。它使用了最简单的方法:只在一个维度上进行插值,即只在一行薄矩形上进行插值:

我并不期望这是一个非常有用的可视化,然而就在那时,一些意想不到的有趣的事情发生了。我使用了一个带有简单 2D 上下文的 HTML 画布。事实证明,如果在有限的区域中有成千上万个这样的矩形,尤其是在这样薄的布局中,浏览器没有足够的像素来显示所有的矩形及其 1 像素宽的白色分隔符。所以它试图平滑事物,1 蓝+ 1 白+ 1 蓝变成了 1 淡蓝色。
它创造了这样的梯度:

这非常有用,因为它回答了我们的问题:条形的大小是由几个大元素(亮色部分)还是许多小元素(亮色部分)决定的。我最终在应用程序中保留了这一点,以防我们有大量的矩形,而“方形”算法开始出现问题。诸如此类的事情使得数据可视化的开发变得非常有趣。
专业知识和推理
理解的统计探索
推理被定义为“基于证据和推理的结论”。我们在生活中做的许多或大多数事情都是基于某种形式的推理。有些,我们有很多经验,比如知道小心地过马路是非常安全的,而有些,我们不知道,比如是否接受某个工作邀请,或者搬到另一个国家。然而,在这两种情况下,我们最终都必须做出一些决定,主要是基于从我们所拥有的(通常是有限的)信息中得出的结论。
案例研究:圭亚那人饮酒
如果你是来决定移居哪个国家的,那么你来错了地方,因为这篇文章的目的不是通过哲学来研究推理,而是从数学这个受限的、可预测的世界来研究推理。让我们说,你试图估计一个随机选择的圭亚那人在周五晚上喝酒的概率。为了这个思想实验的目的,我假设你对圭亚那或其人口的饮酒习惯一无所知。如果你有这方面的知识,请原谅我,想象一个你没有的世界。
在没有任何信息的情况下,我们应该假设概率应该是多少?让我们进一步忽略我们对饮酒或周五可能性的认知。在没有信息的情况下,我们最好的“猜测”概率是 50%。但是如果我们随便问一个圭亚那人,他们正在喝酒,会怎么样呢?如果我们发现另外两个圭亚那人不是呢?我建议探索这个问题的方法是使用贝叶斯定理。这是一种基于新信息更新你对世界的“看法”的有力方式。
编码解决方案
我导入了 math 和 numpy Python 模块来帮助我:
import numpy as np
import math as math
由于我们没有关于这些习惯的信息,我们现在可以假设 0 到 100%之间的每个概率都是同等可能的,因此,我们应该给它们同等的权重:
probs= np.linspace(0,1,101)
weights= np.ones(len(probs))
似是而非
但是当信息开始出现时,我们如何处理它呢?当我们看到第一个人,他正在喝酒,我们知道概率不可能是 0%。这也是一个结果,我们看到 90%的概率是 10%的概率的 9 倍。根据贝叶斯定理,概括这种直觉,每个概率的“似真性得分”等于其先验权重乘以该概率下“现实”发生的可能性。实际概率不可能是 0%,所以给它一个‘似真得分’0。
我们如何看到在某种假设下,某种结果发生的可能性有多大?在我们的简单模型中,我们使用所谓的二项分布。我使用了一个名为“f”的辅助函数来使二项式函数看起来更漂亮:
def f(num):
return math.factorial(num)def binomial_prob(n,x,p):
return (f(n)/ (f(n-x)*f(x) ) * p**(x) * (1-p)**(n-x))
我们结合所有这些来创建我们的贝叶斯概率估计函数。我们用可能性的权重来平均概率。我们设置了概率和先验概率的默认值,以使用户的工作更容易:
def bayes_prob_est(n,x, probs=np.linspace(0,1,101), priors='q')):
if type(probs)==list:
probs=np.array(probs)
if len(probs)!= len(priors): priors= np.ones(len(probs)) if type(priors)== list:
priors== np.array(priors) plausability = priors* binomial_prob(n,x,probs)
return sum(plausability*probs)/sum(plausability)
圭亚那实验的结论
现在我们已经准备好了贝叶斯函数,我们终于可以做一些估计了。下表显示了接受调查的人数、饮酒人数以及随机选择的人饮酒的可能性,使用的是我们的推断方法:

由此产生的有趣模式是,我们对概率的最佳猜测是(x+1)/(n+2),这在逻辑上相当于在我们的样本中添加一个饮酒者和一个不饮酒者。这是一种特殊形式的拉普拉斯平滑
案例分析:扑克
小样
这是否意味着推论就像(x+1)/(n+2)那么简单?这是不是意味着世界上所有的专业知识都可以用(x+1)/(n+2)代替?听到答案是否定的,你不会感到惊讶。这听起来像是常识,但数学并不纯粹通过常识工作,它需要逻辑证据。让我们看一个不同的例子来强调专业知识的价值。
假设我们在一个赌场玩扑克游戏,一桌有 9 个人。一名新玩家来到牌桌前,开始玩他的前 3 手牌。他可能会玩多少手牌?使用我们的贝叶斯函数或上表,我们得到以下结果:
bayes_prob_est(3,3) #0.80
那么我们应该假设他玩了大约 80%的牌吗?完全没有扑克知识,是的,这是一个公平的假设。然而,之前我们定义了一个先验函数,并决定每个概率都是同等可能的。任何一个扑克玩家都会告诉你,80%的牌局是一个令人厌恶的数字。让我们替代性地假设一个扑克高手认为 10%的玩家比较鲁莽,玩了 60%的手牌,80%的玩家比较理智,玩了 20%,10%的玩家比较害怕,玩了 10%。如果我们现在将这些信息放入我们的贝叶斯函数,我们会得到以下结果:
bayes_prob_est(3,3, [.6, .2, .1], [10,80,10]) #0.51
因此,专家可以根据他的专业知识将他的概率从 80%调整到大约 51%。这是一个巨大的意见分歧,这是有道理的,因为复杂的游戏,如扑克,是非常难以理解没有太多的经验。让我们看看,如果我们观察同一个玩家 200 手牌会发生什么,但现在他已经玩了 200 手牌中的 45 手。
大样本
非专家:
bayes_prob_est(200,45) #0.23
专家:
bayes_prob_est(200,45, [.6, .2, .1], [10,80,10]) #0.20
在这种情况下,非专家推断的概率约为 23%,而专家推断的概率约为 20%。两者之间的差距已经明显缩小,几乎相同。随着样本越来越大,这些值越来越接近。
结论:专业知识的价值
我们在上面已经看到,在面对有限的信息时,先前的专业知识可以给你一个非常不同的世界感知,然而,在“足够”的时间后,这收敛到一个天真但有感知的观察者的感知。那么,人们一定想知道,在这个我们可以获得关于各种主题的数千甚至数百万个数据点的时代,在仅仅几百次观察之后,观点似乎趋于一致,为什么还需要专业知识。
在某种程度上,这是对的,面对铺天盖地的数据,先前的观点确实变得不那么重要了。然而,许多重要的问题并不像估计一种简单结果的可能性那样简单。现实生活中有很多输入,例如,在给定 50 种不同的社会经济统计数据的情况下,确定一个社区中不同类型犯罪的可能频率。
最后,即使我们能够从数据中提取概率,我们也必须知道如何使用它们。这些概率最多只能给我们相关性,但要改变世界上的结果(研究数据的目的),我们需要理解原因,而这尤其需要专业知识。因此,虽然数据降低了某些形式的专业知识的价值,但其他形式在这个数据驱动的世界中仍然有价值。
解释任何具有 SHAP 值的模型—使用内核解释器
对 SHAP 值使用 KernelExplainer

自从我发表了文章“用 SHAP 值解释你的模型”,这是建立在一个随机的森林树上,读者们一直在问是否有一个通用的 SHAP 解释器适用于任何 ML 算法——无论是基于树的还是非基于树的算法。这正是内核解释器,一个模型不可知的方法,被设计来做的。在本文中,我将演示如何使用 KernelExplainer 构建 KNN、SVM、Random Forest、GBM 或 H2O 模块的模型。如果你想了解更多关于 SHAP 价值观的背景,我强烈推荐“用 SHAP 价值观解释你的模型”,其中我详细描述了 SHAP 价值观是如何从沙普利价值观中产生的,什么是博弈论中的沙普利价值观,以及 SHAP 价值观是如何在 Python 中工作的。除了 SHAP,你可能还想在“用 LIME 解释你的模型”中查看 LIME,在“用微软的 InterpretML 解释你的模型”中查看微软的 InterpretML。我还在“SHAP 和更优雅的图表”和“SHAP 价值和 H2O 模型”中记录了 SHAP 的最新发展。
想深入了解机器学习算法的读者,可以查看我的帖子我的随机森林、梯度提升、正则化、H2O.ai 讲义。对于深度学习,请查看“以回归友好的方式解释深度学习”。对于 RNN/LSTM/GRU,查看“RNN/LSTM/GRU 股价预测技术指南”。
用 SHAP 价值观诠释你的精致模型
考虑这个问题:“你复杂的机器学习模型容易理解吗?”这意味着您的模型可以通过具有商业意义的输入变量来理解。你的变量将符合用户的期望,他们已经从先前的知识中学习。
Lundberg 等人在其出色的论文“解释模型预测的统一方法”中提出了 SHAP (SHapley 附加解释)值,该值为模型提供了高水平的可解释性。SHAP 价值观提供了两大优势:
- 全局可解释性-SHAP 值可以显示每个预测值对目标变量的贡献大小,无论是正面还是负面。这类似于变量重要性图,但它可以显示每个变量与目标之间的正或负关系(参见下面的汇总图)。
- 局部可解释性——每个观察值都有自己的一套 SHAP 值(见下面的个体力图)。这大大增加了它的透明度。我们可以解释为什么一个案例得到它的预测和预测者的贡献。传统的可变重要性算法只显示整个群体的结果,而不是每个案例的结果。本地可解释性使我们能够精确定位和对比这些因素的影响。
SHAP 值可以由 Python 模块 SHAP 产生。
模型的可解释性并不意味着因果关系
需要指出的是,SHAP 值并不提供因果关系。在“识别因果关系”系列文章中,我展示了识别因果关系的计量经济学技术。这些文章涵盖了以下技术:回归不连续性(参见“通过回归不连续性确定因果关系”)、差异中的差异(DiD)(参见“通过差异中的差异确定因果关系”)、固定效应模型(参见“通过固定效应模型确定因果关系”)以及采用因子设计的随机对照试验(参见“您的变更管理实验设计”)。
内核解释器是做什么的?
KernelExplainer 通过使用您的数据、预测以及预测预测值的任何函数来构建加权线性回归。它根据博弈论的 Shapley 值和局部线性回归的系数计算可变的重要性值。
KernelExplainer 的缺点是运行时间长。如果你的模型是基于树的机器学习模型,你应该使用已经优化的树解释器TreeExplainer()来快速渲染结果。如果你的模型是深度学习模型,使用深度学习讲解器DeepExplainer()。SHAP Python 模块还没有专门针对所有类型算法的优化算法(比如 KNNs)。
在“用 SHAP 值解释你的模型”中,我用函数TreeExplainer()创建了一个随机森林模型。为了让您比较结果,我将使用相同的数据源,但是使用函数KernelExplainer()。
我将为所有算法重复以下四个图:
- 摘要情节:使用
summary_plot() - 依赖情节:
dependence_plot() - 个体力图:
force_plot()对于给定的观察值 - 集体力剧情:
force_plot()。
完整的代码可以在文章末尾找到,或者通过 Github 找到。
[## 通过我的推荐链接加入 Medium-Chris Kuo/data man 博士
阅读 Chris Kuo/data man 博士的每一个故事。你的会员费直接支持郭怡广/戴塔曼博士和其他…
dataman-ai.medium.com](https://dataman-ai.medium.com/membership)
随机森林
首先,让我们加载在“用 SHAP 值解释您的模型”中使用的相同数据。
import pandas as pd
import numpy as np
np.random.seed(0)
import matplotlib.pyplot as plt
df = pd.read_csv('/winequality-red.csv') # Load the data
from sklearn.model_selection import train_test_split
from sklearn import preprocessing
from sklearn.ensemble import RandomForestRegressor
# The target variable is 'quality'.
Y = df['quality']
X = df[['fixed acidity', 'volatile acidity', 'citric acid', 'residual sugar','chlorides', 'free sulfur dioxide', 'total sulfur dioxide', 'density','pH', 'sulphates', 'alcohol']]
# Split the data into train and test data:
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size = 0.2)
让我们构建一个随机森林模型,并打印出变量重要性。SHAP 建立在最大似然算法的基础上。如果你想深入了解机器学习算法,可以查看我的帖子“我关于随机森林、梯度提升、正则化、H2O.ai 的讲义”。
rf = RandomForestRegressor(max_depth=6, random_state=0, n_estimators=10)
rf.fit(X_train, Y_train)
print(rf.feature_importances_)importances = rf.feature_importances_
indices = np.argsort(importances)features = X_train.columns
plt.title('Feature Importances')
plt.barh(range(len(indices)), importances[indices], color='b', align='center')
plt.yticks(range(len(indices)), [features[i] for i in indices])
plt.xlabel('Relative Importance')
plt.show()

Figure (A) Random Forest Variable Importance Plot
你可以从这个Githubpip 安装 SHAP。下面的函数KernelExplainer()通过采用预测方法rf.predict和您想要执行 SHAP 值的数据来执行局部回归。这里我使用测试数据集 X_test,它有 160 个观察值。这一步可能需要一段时间。
import shap
rf_shap_values = shap.KernelExplainer(rf.predict,X_test)
- 概要情节
此图加载了信息。该图与常规变量重要性图(图 A)的最大区别在于,它显示了预测值与目标变量之间的正相关和负相关关系。它看起来有点古怪,因为它是由列车数据中的所有点组成的。让我向您介绍一下:
shap.summary_plot(rf_shap_values, X_test)

- 特征重要性:变量按降序排列。
- 影响:水平位置显示该值的影响是否与更高或更低的预测相关联。
- 原始值:颜色显示该变量对于该观察值是高(红色)还是低(蓝色)。
- 相关性:高水平的“酒精”含量对质量评级有高和正的影响。“高”来自红色,而“积极的”影响显示在 X 轴上。同样,我们会说“挥发性酸度”与目标变量负相关。
您想要保存汇总图。虽然 SHAP 没有内置的保存图的功能,但是您可以使用matplotlib输出图:
2.依赖图
**部分依赖图,简称依赖图,在机器学习结果中很重要( J. H. Friedman 2001 )。它显示了一个或两个变量对预测结果的边际效应。它表明目标和变量之间的关系是线性的、单调的还是更复杂的。我在文章“中提供了更多详细信息:如何计算部分相关图?”
假设我们想得到“酒精”的依赖图。SHAP 模块包括另一个与“酒精”互动最多的变量。下图显示“酒精”与目标变量之间存在近似线性的正趋势,“酒精”与“残糖”频繁交互。
*shap.dependence_plot("alcohol", rf_shap_values, X_test)*

3.个体力图
您可以为每个观察值绘制一个非常优雅的图,称为力图。我任意选择了 X_test 数据的第 10 个观测值。下面是 X_test 的平均值,以及第 10 次观察的值。

Pandas 像 base R 一样使用.iloc()来划分数据帧的行。其他语言开发者可以看我的帖子“你是双语吗?精通 R 和 Python ”中,我比较了 R dply 和 Python Pandas 中最常见的数据争论任务。
*# plot the SHAP values for the 10th observation
shap.force_plot(rf_explainer.expected_value, rf_shap_values[10,:], X_test.iloc[10,:])*

- **输出值是该观测值的预测值(该观测值的预测值为 5.11)。
- **基值:原始论文解释说,基值 E(y_hat)是“如果我们不知道当前输出的任何特征,将会预测的值。”换句话说,它是均值预测,或均值(yhat)。你可能会奇怪为什么是 5.634。这是因为 Y_test 的预测均值为 5.634。你可以通过产生 5.634 的
Y_test.mean()来测试一下。 - **红色/蓝色:将预测值推高(向右)的特征显示为红色,将预测值推低的特征显示为蓝色。
- 酒精:对质量评级有积极影响。这种酒的酒精度是 9.4,低于平均值 10.48。所以它把预测推到左边。
- 二氧化硫总量:与质量等级正相关。高于平均水平的二氧化硫(= 18 > 14.98)将预测推向右边。
- 该图以位于
explainer.expected_value的 x 轴为中心。所有 SHAP 值都与模型的期望值相关,就像线性模型的效果与截距相关一样。
4.集体力量图
每个观察都有它的力图。如果把所有的力图组合起来,旋转 90 度,水平叠加,我们就得到整个数据 X_test 的力图(见 Lundberg 等贡献者的 GitHub 的解释)。
*shap.force_plot(rf_explainer.expected_value, rf_shap_values, X_test)*

合力图上面的 Y 轴是单个力图的 X 轴。在我们的 X_test 中有 160 个数据点,所以 X 轴有 160 个观察值。
GBM
我用 500 棵树(缺省值是 100)构建了 GBM,这对于过度拟合应该是相当健壮的。我使用超参数validation_fraction=0.2指定 20%的训练数据提前停止。如果验证结果在 5 次后没有改善,该超参数和n_iter_no_change=5将帮助模型更早停止。
*from sklearn import ensemble
n_estimators = 500
gbm = ensemble.GradientBoostingClassifier(
n_estimators=n_estimators,
validation_fraction=0.2,
n_iter_no_change=5,
tol=0.01,
random_state=0)
gbm = ensemble.GradientBoostingClassifier(
n_estimators=n_estimators,
random_state=0)
gbm.fit(X_train, Y_train)*
像上面的随机森林部分一样,我使用函数KernelExplainer()来生成 SHAP 值。那我就提供四个情节。
*import shap
gbm_shap_values = shap.KernelExplainer(gbm.predict,X_test)*
- 概要情节
当与随机森林的输出相比较时,GBM 对于前四个变量显示相同的变量排序,但是对于其余变量不同。
*shap.summary_plot(gbm_shap_values, X_test)*

2.依赖图
GBM 的依赖图也显示“酒精”和目标变量之间存在近似线性的正趋势。与随机森林的输出相反,GBM 显示“酒精”与“密度”频繁交互。
*shap.dependence_plot("alcohol", gbm_shap_values, X_test)*

3.个体力图
我继续为 X_test 数据的第 10 次观察制作力图。
*# plot the SHAP values for the 10th observation
shap.force_plot(gbm_explainer.expected_value,gbm_shap_values[10,:], X_test.iloc[10,:])*

该观察的 GBM 预测是 5.00,不同于随机森林的 5.11。推动预测的力量与随机森林的力量相似:酒精、硫酸盐和残余糖分。但是推动预测上升的力量是不同的。
4.集体力量图
*shap.force_plot(gbm_explainer.expected_value, gbm_shap_values, X_test)*

KNN
因为这里的目标是展示 SHAP 价值观,所以我只设置了 KNN 15 个邻居,而不太关心优化 KNN 模型。
*# Train the KNN model
from sklearn import neighbors
n_neighbors = 15
knn = neighbors.KNeighborsClassifier(n_neighbors,weights='distance')
knn.fit(X_train,Y_train)# Produce the SHAP values
knn_explainer = shap.KernelExplainer(knn.predict,X_test)
knn_shap_values = knn_explainer.shap_values(X_test)*
- 概要情节
有趣的是,与随机森林或 GBM 的输出相比,KNN 显示了不同的变量排序。这种背离是意料之中的,因为 KNN 容易出现异常值,这里我们只训练一个 KNN 模型。为了缓解这一问题,建议您使用不同数量的邻居构建几个 KNN 模型,然后获取平均值。我的文章“异常检测与 PyOD ”也分享了这种直觉。
*shap.summary_plot(knn_shap_values, X_test)*

2.依赖图
KNN 的输出显示在“酒精”和目标变量之间存在近似线性的正趋势。与随机森林的输出不同,KNN 显示“酒精”与“总二氧化硫”的交互频繁。
*shap.dependence_plot("alcohol", knn_shap_values, X_test)*

3.个体力图
*# plot the SHAP values for the 10th observation
shap.force_plot(knn_explainer.expected_value,knn_shap_values[10,:], X_test.iloc[10,:])*

该观察的预测值为 5.00,与 GBM 的预测值相似。KNN 确定的驱动力是:“游离二氧化硫”、“酒精”和“残糖”。
4.集体力量图
*shap.force_plot(knn_explainer.expected_value, knn_shap_values, X_test)*

SVM
支持向量机(AVM)找到最佳超平面以将观察结果分成类别。SVM 使用核函数变换到更高维度的空间中进行分离。为什么在更高维的空间中分离会变得更容易?这还得回到 Vapnik-Chervonenkis (VC)理论。它说,映射到更高维度的空间通常会提供更大的分类能力。关于进一步的解释,请参见我的文章“使用 Python 的维度缩减技术”。常见的核函数有径向基函数(RBF)、高斯函数、多项式函数和 Sigmoid 函数。
在这个例子中,我使用带参数gamma的径向基函数(RBF)。当gamma的值很小时,模型受到的约束太大,无法捕捉数据的复杂性或“形状”。有两种选择:gamma='auto'或gamma='scale'(参见 scikit-learn api )。
另一个重要的超参数是decision_function_shape。超参数decision_function_shape告诉 SVM 一个数据点离超平面有多近。靠近边界的数据点意味着低置信度决策。有两个选项:一对一对休息(' ovr ')或一对一(' ovo ')(参见 scikit-learn api )。
*# Build the SVM model
from sklearn import svm
svm = svm.SVC(gamma='scale',decision_function_shape='ovo')
svm.fit(X_train,Y_train)# The SHAP values
svm_explainer = shap.KernelExplainer(svm.predict,X_test)
svm_shap_values = svm_explainer.shap_values(X_test)*
- 概要情节
这里,我们再次从随机森林和 GBM 的输出中看到不同的汇总图。这是意料之中的,因为我们只训练了一个 SVM 模型,而 SVM 也容易出现异常值。
*shap.summary_plot(svm_shap_values, X_test)*

2.依赖图
SVM 的输出在“酒精”和目标变量之间显示出温和的线性正趋势。与随机森林的输出相反,SVM 表明“酒精”经常与“固定酸度”相互作用。
*shap.dependence_plot("alcohol", svm_shap_values, X_test)*

3.个体力图
*# plot the SHAP values for the 10th observation
shap.force_plot(svm_explainer.expected_value,svm_shap_values[10,:], X_test.iloc[10,:])*

此次观测的 SVM 预测值为 6.00,不同于随机森林的 5.11。驱使预测降低的力量类似于随机森林的力量;相比之下,“二氧化硫总量”是推动预测上升的强大力量。
4.集体力量图
*shap.force_plot(svm_explainer.expected_value, svm_shap_values, X_test)*

型号内置开源 H2O
许多数据科学家(包括我自己)喜欢开源的 H2O。它是一个完全分布式的内存平台,支持最广泛使用的算法,如 GBM、RF、GLM、DL 等。它的 AutoML 功能自动运行所有算法及其超参数,生成最佳模型排行榜。其企业版 H2O 无人驾驶 AI 内置 SHAP 功能。
如何将 SHAP 价值观应用于开源的 H2O?我非常感谢 seanPLeary 在如何用 AutoML 产生 SHAP 价值观方面为 H2O 社区做出的贡献。我使用他的类“H2OProbWrapper”来计算 SHAP 值。
*# The code builds a random forest model
import h2o
from h2o.estimators.random_forest import H2ORandomForestEstimator
h2o.init()X_train, X_test = train_test_split(df, test_size = 0.1)
X_train_hex = h2o.H2OFrame(X_train)
X_test_hex = h2o.H2OFrame(X_test)
X_names = ['fixed acidity', 'volatile acidity', 'citric acid', 'residual sugar','chlorides', 'free sulfur dioxide', 'total sulfur dioxide', 'density','pH', 'sulphates', 'alcohol']# Define model
h2o_rf = H2ORandomForestEstimator(ntrees=200, max_depth=20, nfolds=10)# Train model
h2o_rf.train(x=X_names, y='quality', training_frame=X_train_hex)X_test = X_test_hex.drop('quality').as_data_frame()*
让我们仔细看看 SVM 的代码shap.KernelExplainer(svm.predict, X_test)。它采用了类svm的函数predict,以及数据集X_test。因此,当我们应用 H2O 时,我们需要传递(I)预测函数,(ii)一个类,以及(iii)一个数据集。棘手的是,H2O 有自己的数据框架结构。为了将 h2O 的预测函数h2o.preict()传递给shap.KernelExplainer(),Sean pleay将 H2O 的预测函数h2o.preict()包装在一个名为H2OProbWrapper的类中。这个漂亮的包装器允许shap.KernelExplainer()接受类H2OProbWrapper的函数predict和数据集X_test。
*class H2OProbWrapper:
def __init__(self, h2o_model, feature_names):
self.h2o_model = h2o_model
self.feature_names = feature_namesdef predict_binary_prob(self, X):
if isinstance(X, pd.Series):
X = X.values.reshape(1,-1)
self.dataframe= pd.DataFrame(X, columns=self.feature_names)
self.predictions = self.h2o_model.predict(h2o.H2OFrame(self.dataframe)).as_data_frame().values
return self.predictions.astype('float64')[:,-1]*
因此,我们将计算 H2O 随机森林模型的 SHAP 值:
*h2o_wrapper = H2OProbWrapper(h2o_rf,X_names)h2o_rf_explainer = shap.KernelExplainer(h2o_wrapper.predict_binary_prob, X_test)
h2o_rf_shap_values = h2o_rf_explainer.shap_values(X_test)*
- 概要情节
当与随机森林的输出相比较时,H2O 随机森林对于前三个变量显示出相同的变量排序。
*shap.summary_plot(h2o_rf_shap_values, X_test)*

2.依赖图
输出显示“酒精”和目标变量之间存在线性的正趋势。H2O·兰登森林发现“酒精”经常与“柠檬酸”相互作用。
*shap.dependence_plot("alcohol", h2o_rf_shap_values, X_test)*

3.个体力图
此次观测的 H2O 随机森林预测值为 6.07。推动预测向右的力量是“酒精”、“密度”、“残糖”、“总二氧化硫”;左边是“固定酸度”和“硫酸盐”。
*# plot the SHAP values for the 10th observation
shap.force_plot(h2o_rf_explainer.expected_value,h2o_rf_shap_values[10,:], X_test.iloc[10,:])*

4.集体力量图
*shap.force_plot(h2o_rf_explainer.expected_value, h2o_rf_shap_values, X_test)*

R 中的 SHAP 值如何?
这里提到几个 SHAP 值的 R 包很有意思。R package shapper 是 Python 库 SHAP 的一个端口。R 包 xgboost 有内置函数。另一个包是 iml (可解释机器学习)。最后,R 包 DALEX (描述性机器学习解释)也包含各种解释器,帮助理解输入变量和模型输出之间的联系。
SHAP 价值观没有做到的事情
自从我发表了这篇文章和它的姊妹文章“用 SHAP 价值观解释你的模型”之后,读者们分享了他们与客户会面时提出的问题。这些问题不是关于 SHAP 价值观的计算,而是观众思考 SHAP 价值观能做什么。一个主要的评论是“你能为我们确定制定策略的驱动因素吗?”
上面的评论是可信的,表明数据科学家已经提供了有效的内容。然而,这个问题涉及到相关性和因果性。SHAP 值不能识别因果关系,通过实验设计或类似方法可以更好地识别因果关系。有兴趣的读者,请阅读我的另外两篇文章《为你的变革管理设计实验》和《机器学习还是计量经济学?
所有代码
为了方便起见,所有的行都放在下面的代码块中,或者通过这个 Github 。
如果您发现这篇文章很有帮助,您可能想要查看模型可解释性系列:
第一部分:用 SHAP 值解释你的模型
第二部分:图表更优雅的 SHAP
第三部分:部分依赖图是如何计算的?
第六部分:对可解释人工智能的解释
第五部分:解释任何具有 SHAP 值的模型——使用内核解释器
第六部分:H2O 模型的 SHAP 值
第七部分:用石灰解释你的模型
第八部分:用微软的 InterpretML 解释你的模型
* [## 通过我的推荐链接加入 Medium-Chris Kuo/data man 博士
阅读 Chris Kuo/data man 博士的每一个故事。你的会员费直接支持郭怡广/戴塔曼博士和其他…
dataman-ai.medium.com](https://dataman-ai.medium.com/membership)
建议读者购买郭怡广的书籍:

- 可解释的人工智能:https://a.co/d/cNL8Hu4
- 图像分类的迁移学习:https://a.co/d/hLdCkMH
- 现代时间序列异常检测:https://a.co/d/ieIbAxM
- 异常检测手册:https://a.co/d/5sKS8bI*
特征变化解释
在 Scikit-Learn 中使用 PCA

Visualization of PCA results[1]
作为一种多元排序技术,主成分分析(PCA)可以对多元数据集中的因变量进行分析,以探索它们之间的关系。这导致以更少的维度显示数据点的相对位置,同时保留尽可能多的信息[2]。
在本文中,我将使用 Scikit-learn 库对 auto-mpg 数据集(来自 GitHub)应用 PCA。本文分为数据预处理、主成分分析和主成分可视化三个部分。
a)数据预处理
我们首先需要导入数据集预处理所需的库:
import tensorflow as tf
from tensorflow import kerasimport numpy as np
import pandas as pd
import seaborn as sns!pip install -q git+https://github.com/tensorflow/docs
import tensorflow_docs as tfdocs
import tensorflow_docs.plots
import tensorflow_docs.modeling
然后,我们可以导入数据:
datapath = keras.utils.get_file(“auto-mpg.data”, “http://archive.ics.uci.edu/ml/machine-learning-databases/auto-mpg/auto-mpg.data")datapath
并更改列的标题:
columnTitles = [‘MPG’,’Cylinders’,’Displacement’,’Horsepower’,’Weight’, ‘Acceleration’, ‘Model Year’, ‘Origin’]rawData = pd.read_csv(dataPath, names=columnTitles, na_values = “?”, comment=’\t’, sep=” “, skipinitialspace=True)
数据如下所示:
data = rawData.copy()
data.head()

然后,我们需要清理数据:
data.isna().sum()

data = data.dropna()
下一步是定义特征,将它们从响应变量中分离出来,并将其标准化为 PCA 的输入:
from sklearn.preprocessing import StandardScalerdf = pd.DataFrame(data)features = [‘Cylinders’, ‘Displacement’, ‘Horsepower’, ‘Weight’, ‘Acceleration’]X = df.loc[:, features].valuesy = df.loc[:,[‘MPG’]].valuesX = StandardScaler().fit_transform(X)
b)五氯苯甲醚
在 PCA 中,我们首先需要知道需要多少成分来解释至少 90%的特征变化:
from sklearn.decomposition import PCApca = PCA().fit(X)plt.plot(np.cumsum(pca.explained_variance_ratio_))plt.xlabel(‘number of components’)plt.ylabel(‘cumulative explained variance’)

在本案例研究中,选择了两个组件作为组件的最佳数量。然后,我们可以开始进行 PCA:
from sklearn.decomposition import PCApca = PCA(n_components=2)principalComponents = pca.fit_transform(X)
如下所示,总体而言,这两个组件解释了数据集约 95%的特征变化:
pca.explained_variance_ratio_array([0.81437196, 0.13877225])
c)主成分可视化
给定响应变量值(当前数据集中的 MPG ),两个主要成分可以如下所示:
plt.scatter(principalComponents[:, 0], principalComponents[:, 1],c=data.MPG, edgecolor=’none’, alpha=0.5,cmap=plt.cm.get_cmap(‘Spectral’, 10))plt.xlabel(‘Principal component 1’)plt.ylabel(‘Pricipal component 2’)plt.colorbar()

结论
主成分分析(PCA)降低了大数据集的维数,增加了数据的可解释性,同时最小化了信息损失。它通过创建新的不相关成分来实现方差的最大化[3]。
参考文献
[1]https://commons . wikimedia . org/wiki/File:PCA _ vs _ Linear _ auto encoder . png
[2] C. Syms。主成分分析。(2008),生态百科,2940–2949。doi:10.1016/b978–008045405–4.00538–3。
[3] T. I .乔利夫和 j .卡迪马。"主成分分析:回顾与最新发展."(2016),英国皇家学会哲学汇刊 A:数学、物理与工程科学,第 374 卷,第 2065 期,第 2015–2020 页,doi:10.1098/rsta.2015.0202。
用莱姆和 SHAP 解释自然语言处理模型

文本分类解释
上周,我在 QCon New York 做了一个关于 NLP 的“ 动手特征工程”的演讲。作为演示的一小部分,我简单演示了一下LIME&SHAP在文本分类解释方面是如何工作的。
我决定写一篇关于它们的博客,因为它们很有趣,易于使用,视觉上引人注目。
所有在比人脑可以直接可视化的维度更高的维度上运行的机器学习模型都可以被称为黑盒模型,这归结于模型的可解释性。特别是在 NLP 领域,总是出现特征维数非常巨大的情况,解释特征重要性变得更加复杂。
石灰&SHAP帮助我们不仅向最终用户,也向我们自己提供一个关于 NLP 模型如何工作的解释。
利用栈溢出问题标签分类数据集,我们将构建一个多类文本分类模型,然后分别应用&【SHAP】来解释该模型。因为我们之前已经做了很多次文本分类,我们将快速构建 NLP 模型,并关注模型的可解释性。
数据预处理、特征工程和逻辑回归
preprocessing_featureEngineering_logreg.py

我们在这里的目标不是产生最高的结果。我想尽快潜入莱姆 SHAP,这就是接下来发生的事情。
用 LIME 解释文本预测
从现在开始,这是有趣的部分。下面的代码片段大部分是从 LIME 教程中借来的。
explainer.py

我们在测试集中随机选择一个文档,它恰好是一个标记为 sql 的文档,我们的模型预测它也是 sql 。使用该文档,我们为标签 4(即 sql 和标签 8(即 python )生成解释。
*print ('Explanation for class %s' % class_names[4])
print ('\n'.join(map(str, exp.as_list(label=4))))*

*print ('Explanation for class %s' % class_names[8])
print ('\n'.join(map(str, exp.as_list(label=8))))*

很明显这个文档对标签 sql 的解释最高。 我们还注意到,正负符号都是相对于某个特定标签而言的,比如单词“sql”正对类 sql 而负对类 python ,反之亦然。
我们将为该文档的前两个类生成标签。
*exp = explainer.explain_instance(X_test[idx], c.predict_proba, num_features=6, top_labels=2)
print(exp.available_labels())*

它给了我们 sql 和 python。
*exp.show_in_notebook(text=False)*

Figure 1
让我试着解释一下这种形象化:
- 对于该文档,单词“sql”对于类别 sql 具有最高的正面得分。
- 我们的模型预测这个文档应该以 100%的概率被标记为 sql 。
- 如果我们将单词“sql”从文档中删除,我们会期望模型以 100% — 65% = 35%的概率预测标签 sql 。
- 另一方面,word“SQL”对于 class python 是负数,我们的模型已经了解到 word“range”对于 class python 有一个很小的正数分数。
我们可能想要放大并研究对类 sql 的解释,以及文档本身。
*exp.show_in_notebook(text=y_test[idx], labels=(4,))*

Figure 2
用 SHAP 解释文本预测
以下过程都是从本教程中学到的。
tf_model.py
- 在模型被训练后,我们使用前 200 个训练文档作为我们的背景数据集进行集成,并创建一个 SHAP 解释器对象。
- 我们在测试集的子集上得到个体预测的属性值。
- 将索引转换为单词。
- 使用 SHAP 的
summary_plot方法显示影响模型预测的主要特征。
*attrib_data = X_train[:200]
explainer = shap.DeepExplainer(model, attrib_data)
num_explanations = 20
shap_vals = explainer.shap_values(X_test[:num_explanations])words = processor._tokenizer.word_index
word_lookup = list()
for i in words.keys():
word_lookup.append(i)word_lookup = [''] + word_lookup
shap.summary_plot(shap_vals, feature_names=word_lookup, class_names=tag_encoder.classes_)*

Figure 3
- 单词“want”是我们的模型使用的最大信号词,对类 jquery 预测贡献最大。
- 单词“php”是我们的模型使用的第四大信号词,当然对类 php 贡献最大。
- 另一方面,单词“php”可能对另一个类产生负面信号,因为它不太可能出现在 python 文档中。
就机器学习的可解释性而言,莱姆& SHAP 有很多东西需要学习。我只介绍了 NLP 的一小部分。 Jupyter 笔记本可以在 Github 上找到。享受乐趣!
用特征重要性解释你的机器学习
让我们想象一下,你在一家银行找到了一份咨询工作,这家银行要求你找出那些很有可能拖欠下个月账单的人。有了你所学习和实践的机器学习技术,假设你开始分析你的客户给出的数据集,并且使用了一个随机森林算法,它达到了相当高的准确度。您的下一个任务是向客户团队的业务利益相关者展示您是如何实现这些结果的。你会对他们说什么?他们能理解你为了最终模型而调整的算法的所有超参数吗?当你开始谈论随机森林的估计数和基尼系数时,他们会有什么反应?

虽然精通理解算法的内部工作很重要,但更重要的是能够将发现传达给可能没有任何机器学习理论/实践知识的观众。仅仅表明算法预测得好是不够的。您必须将预测归因于对准确性有贡献的输入数据元素。幸运的是, sklearn 的随机森林实现给出了一个名为“特征重要性的输出,这有助于我们解释数据集中特征的预测能力。但是,这种方法有一些缺点,我们将在本文中探讨,还有一种评估特性重要性的替代技术可以克服这些缺点。
数据集
正如我们在简介中看到的,我们将使用来自 UCI 机器学习库的信用卡默认数据集,该数据集托管在 Kaggle 上。该数据集包含从 2005 年 4 月到 2005 年 9 月台湾信用卡客户的违约付款、人口统计因素、信用数据、付款历史和账单等信息,并且包含连续变量和分类变量的良好组合,如下所示:

Columns available in the dataset and their descriptions


default.payment.next.month 是我们的目标变量。值 1 表示客户将在下个月拖欠付款。让我们看看这个变量的分布:
credit.groupby([‘default.payment.next.month’]).size()
>default.payment.next.month
>0 23364
>1 6636
>dtype: int64
这是一个不平衡的数据集,约有 22%的记录的默认值为 1。因为我们的重点是评估特性的重要性,所以在这篇文章中,我不会深入研究数据集及其特性。相反,我会快速建立一个模型,并开始查看分数。在建立模型之前,让我们先对分类变量进行一次性编码。
让我们看看普通随机森林模型在该数据集上的表现:

很明显我们有一个过度拟合的算法。测试集上的准确率低于训练集,但不算太差。因为我们正在处理一个不平衡的数据集,所以精度和召回数量更加重要。训练集和测试集之间在精确度和召回率上有巨大的差异。
让我们来看看该模型背后的主要特性:
Feature importances of the Random Forest model
令人惊讶的是,年龄是影响模型预测的首要因素。我们还应该注意随机森林模型中特征重要性的一个重要方面:
随机森林中的要素重要性是根据提供给模型的定型数据计算的,而不是根据测试数据集的预测。
因此,这些数字并不能表明模型的真实预测能力,尤其是过度拟合的模型!此外,我们看到模型在训练数据集和测试数据集上的性能有很大的不同。因此,我们需要一种替代技术,能够计算测试数据集上的特征重要性,并基于不同的度量标准(如准确度、精确度或召回率)来计算它。
置换特征重要性
置换特征重要性技术用一个非常简单的概念克服了我们在上面看到的缺点:如果只有一个特征的值被随机打乱,模型会如何执行?换句话说,如果我们使一个特征对模型不可用,对性能有什么影响?
关于这项技术的一些想法:
- 如果我们想要评估模型的性能,为什么要打乱数据集中的某个要素,而不是将其完全移除?删除该功能意味着需要重新进行培训。我们想用这个特性来训练模型,但却不用它来测试模型。
- 如果我们让特征全为零呢?在某些情况下,零对模型确实有一些价值。此外,在一个要素中调整值可以确保值保持在数据范围内。
对于我们的场景,让我们将排列重要性定义为由一个特性的排列引起的基线度量的差异。当给定一个已经训练好的分类器时,下面的函数计算排列重要性:
现在,让我们通过置换所有特征,在测试数据集上绘制召回分数的百分比变化:
Percentage change in recall scores
令人惊讶的是,当我们绘制排列重要性时,年龄并没有出现在前 25 个特征中。这是因为随机森林的要素重要性方法倾向于具有高基数的要素。在我们的数据集中,年龄有 55 个唯一值,这使得算法认为它是最重要的特征。
特征重要性构成了机器学习解释和可解释性的关键部分。希望这篇文章能帮助你了解更多。
这篇文章的代码可以在 Github 上找到。
我们讲述的关于自己的故事
…人工智能研究中遇到的问题如何反映了我们自己的认知偏差

Photo by David Matos on Unsplash
大脑是一个复杂的器官,数十亿个神经元通过数万亿个连接形成了一个非常复杂的非线性动力系统。这可以说是宇宙中最复杂的结构(至少是我们所知道的)。它可以解决看似无穷无尽的任务,让我们在不断变化的环境中导航和生存。
这可能是你熟悉的说唱,但同时它的一些后果很容易被忽视。因为我们和我们的个性是大脑行为的产物,我们和我们的个性与它的复杂性联系在一起。
这篇文章深入探讨了构成我们的(大部分)不可言喻的机制与我们不断渴望拥有一个关于我们在做什么和想什么的令人信服和连贯的故事之间的冲突。 理解我们自己的输出 的问题与人工智能研究中的 可解释性 有一些相似之处。
这种冲突的一些副产品在心理学上被称为 认知偏差 ,其中我们发现了两种可爱的效应,称为 认知失调 和 虚构、 ,这使我们对自己内心的理解程度产生了疑问。
潜意识
“你没注意到,但你的大脑注意到了。”
在西格蒙德·弗洛伊德假设潜意识存在的 100 多年后,他认为我们在自己的房子里不是真正的主人的观点在某种程度上已经融入了我们的身份。
考虑到大脑的复杂性,你可能会说,大多数时候,我们不知道自己到底在做什么是很自然的,但只是在二十世纪的过程中,人们才开始接受这样一个事实,即我们内心发生的事情比我们有意识意识到的要多得多。我们生活的大部分时间都处于自动驾驶状态,只有当紧急的事情发生时,我们的意识注意力才会集中到它上面(正如我在我之前的文章中提到的关于注意力)。
大脑每秒钟过滤 数量惊人的信息 ,而有意识的头脑只意识到其中的极小一部分,其中大部分都经过了 重重的预过滤 。几乎所有的过程,无论是运动的、认知的还是情感的, 都是自动化的,并在主动意识控制之外受到调节 。
不仅信息摄取是自动化的,而且决策的做出也与我们每天看到的截然不同:研究表明,如果我们将大脑的情感成分排除在外,仅仅依靠前额叶活动,决策几乎是不可能的(参见安东尼奥·达马西奥的 书 事物的奇怪顺序 中的概述)。
相反,我们的许多决定严重依赖于身体和内脏脑的 模拟能力 ,与特殊类型的非回肠化神经元进行分布式并行处理。根据你的 直觉行动 有着比你可能认为的更精确的科学含义。
正如 丹尼·卡尼曼和 阿莫斯·特沃斯基指出的,由启动或锚定 引起的偏见会对我们在不确定情况下的决策产生强烈影响,我们通常对它们的发生很警觉。
更糟糕的是:有意识地知道我们正在被锚定或启动,仍然不能让我们对它们可能引发的偏见免疫。
机器学习和可解释性
人工智能和计算神经科学的研究人员面临着一个有点类似的问题,总结在术语 可解释性 下。我们如何解释我们的人工智能系统中的新兴智能,并让系统向我们解释它们如何做出决策,同时仍然能够解释它们如何处理信息的细节?
现代机器学习方法不是构建算法来解决某些任务并将它们硬连线到计算机中,而是允许计算机通过处理指定的输入和期望的输出来自行开发算法(有关更详细的概述,请参见 Pedro Domingos 的“主算法 ”)。

Photo by Sai Kiran Anagani on Unsplash
这向我们表明,理解机器在做什么变得越来越困难,而矛盾的是,它们在做各种事情(图像分类、语音识别、下围棋等)方面变得越来越成功。).
有时,它们似乎在没有任何人工干预或试图手动教授它们知识的情况下表现得最好。这促使 Frederick Jelinek(语音识别之父之一)在 IBM 开发语音识别软件时宣称“每当我解雇一名语言学家,语音识别器的性能就会提高”。
大型神经网络中的计算 分布 在整个网络中(在深度神经网络中,也通过几个层,称为隐藏层,具有非线性激活函数),使得 几乎不可能通过构成网络 的层来跟踪计算的细节。
网络所代表的算法中隐含的知识同样 分布在网络 的整个权重结构中,所以你无法看一眼权重就直观地掌握网络擅长的,比如说,对猫或狗的分类。
正如我在我的一些其他文章(例如蚂蚁和神经网络的问题)中所述,请注意,这是一种与图灵机的符号操作非常不同的方法(尽管你当然可以在图灵机上运行神经网络,就像我们在自己的计算机上所做的那样),现代计算机基于图灵机,其符号操作更类似于理性的逐步推理。
因此,当涉及到“理解”复杂分布式系统中的信息处理时,我们可能会面临原则性的限制,或者至少当涉及到构建高效且能够对自己的行为保持满分的智能系统时,我们会面临限制。
叙事的需要
所以毫不奇怪,对于我们大脑中正在进行的一些信息处理,我们人类对于的可解释性有自己的问题。
行为主义者将大脑视为一个黑匣子(类似地专注于输入-输出-关系),但在心理和社会背景下,我们不断需要找到一种叙事来解释我们正在做什么以及为什么要这样做。
但这种叙述,真的有多靠谱?
人类是从动物进化而来的,动物们做得非常好,没有不断地告诉彼此是什么激发了它们的故事。
但后来我们发展出了不祥的能力,可以互相交谈(更重要的是,可以和自己交谈)。社会和性压力(正如我在关于性选择的文章中所详述的那样)可能是引发像语言这样的高级认知能力发展的最前沿。即使在今天,我们的大量脑力都花在了八卦上,花在了跟踪我们周围的人发生的事情上。
从进化的角度来说, 新皮层 ,也就是我们的语言能力所在的地方,是我们神经回路的最新成员(在我的文章为什么智力可能比我们想象的简单中有更多关于新皮层及其架构的内容)。就其绝对质量而言,它构成了我们大脑的大部分,但这并不意味着它一直在负责,一直“知道”发生了什么。
这是大脑功能观的结果:如果大脑的一部分(如语言中心或创建自我模型的大脑区域)想要了解另一部分的活动,指定所述活动的信号需要传播到该大脑区域。
应该清楚的是,对于所有时间的所有大脑活动来说,这既不可行也没有效率,甚至在任何情况下都没有必要。**
因此,这最终只会增加可解释性的问题:试图进行解释的大脑区域有时会简单地从信息流 中 切断,而信息流会给它们必要的洞察力,就像我们将在裂脑症患者的案例中看到的那样。
还有,我们试着解释一下。
能够保持一个持续不断的叙述有它的用处,而且似乎是社会功能成员非常渴望的。但是我们应该意识到,这并不意味着我们对自己或他人的所思所言都是真实的。
实际上完全相反。
我们讲述的关于自己的故事
“如果一个特定的观念已经在人类头脑中存在了许多代,就像我们几乎所有的共同观念一样,需要真诚和持续的努力才能消除它;如果这是我们所拥有的最古老的思想之一,一个伟大的、普遍的、不容置疑的世界思想之一,那么那些寻求改变它的人的劳动是巨大的。”夏洛特·珀金斯·吉尔曼

Even people within stories like compelling stories. Photo by Road Trip with Raj on Unsplash
我们对故事有一种强烈的心理倾向。我们在叙述中感知世界(看看海德尔-西美尔错觉,它让我们相信两个点和一个三角形参与了一场戏剧性的打斗场景)。作为我们过度社交的副产品,我们一直在寻找外部世界的代理和因果关系。随之而来的是对我们自己有一个连贯的叙述的渴望:因为这个或那个原因,我是这样或那样的。
但正如我们所见,对于许多任务来说,大脑和身体中有大量分布式并行计算,这使得理解和描述我们的动机变得很棘手。
因此,我们最终会不断猜测自己行为的原因。
此外,很难实现消除矛盾想法的过程。这意味着我们最终都会带着巨大的矛盾走来走去,这只能通过艰苦的批判性思维来克服,即使是受过良好教育的批判性思考者也无法持续练习这一技能。
老实说,从进化的角度来说,我们的生存并不真的需要一个 完全一致的世界观 ,所以如果他们不太妨碍彼此,我们的大脑就让他们这样。
故事有塑造我们感知的力量,即使我们没有注意到它。大脑(正如我在关于贝叶斯大脑假说的文章中所回避的)不断预测其感知输入的内容,所以你会根据你对世界状态的预期看到和听到不同的东西(这使得认知科学家将现实虚构为 受控幻觉 )。当我们不断试图将世界上复杂和混乱的现象转化为简单的,有时明显自相矛盾的故事时,这些故事最终会戏剧性地改变我们对现实的看法。
认知偏差和认知失调
"他很少怀疑,当事实与他对生活的看法相矛盾时,他闭上眼睛表示反对。"
― 赫尔曼·黑塞,赫尔曼·黑塞的童话
1957 年,利奥·费斯汀格引入了术语 认知失调 来表示当我们经历一些与我们的世界观相矛盾的事情时所感到的不适。但这种不适往往是潜意识的,我们倾向于通过对我们不喜欢的事件提出替代性解释,或简单地抛弃它们来应对它。
我们避免认知失调的冲动让我们停留在世界观的舒适区,让我们下意识地忽略信息或重构我们认知中令人不安的方面。
认知失调通常通过自我辩护来解决,这可能发生在外部和内部。
在她的书 中,错误是犯了,但不是由我犯的卡罗尔·塔弗里斯** 描述了许多案例 认知失调回避战术 产生了严重后果,从法西斯国家公民社会道德的下降,越战期间的美国政府(参见本·伯恩斯和琳恩·诺维克的精彩而令人震惊的纪录片)或伊拉克战争,法律制度在面对迟来的无罪证据时的偏见**
许多决定,特别是道德决定, 是在对其基础 没有任何清晰和理性的理解的情况下做出的(当受试者被巧妙地操纵时,这在实验中变得很明显),但在做出决定后,它们会导致过度的 自我辩护 ,这反过来会引起受试者世界观的调整,以恢复连贯性并最小化认知失调。
一个流行的例子是吸烟者。他或她可能下意识地意识到吸烟的不健康和不合理,但当被问到时,他或她总是以这样或那样的方式为自己辩护(“我只是喜欢这种味道/仪式/社交/在外面/无论哪种方式都不是那么不健康”)。我们中的许多人都有过类似的情况(用吸烟来换取酒精或任何其他不健康的习惯)。我们经常这样做。
分裂的大脑和虚构的艺术
有时,大脑试图在事实 变得 透明到模仿 的程度后,用 来证明自己的行为。
也许没有任何地方像裂脑患者这样清楚,他们连接左右半球的胼胝体已经被切断(在这个短视频,你可以看到 迈克尔·加扎尼加 ,这些实验背后的先驱之一,解释了基本的前提)。
左右半球不能再交流了,所以左右视野是独立处理的。语言中枢位于 左半球 ,意味着它无法进入(记住视觉是交叉连线的,所以左半球处理右视野,反之亦然)。
如果你只在左视野显示某些东西,这些信息在右半球进行处理,这可以表现为身体反应(例如,当你显示裸体人的照片时,紧张的脸红或傻笑,或者用左手指着某个地方),但不能被大脑的语言处理部分直接访问。因此,当被问及他/她为什么咯咯笑或指指点点时,病人会当场做出解释。
当我们在猜测对自己行为的解释却没有一条至关重要的信息时,我们通常不会说 【我不知道】 ,而只是简单地以 编造一些 ,然后回溯性地将这条信息解释为。**
这被称为 虚构 ,每个人几乎一直都在做。虽然在日常生活中,通常无法清楚地表明我们对行为原因的无知程度,但可以肯定地说,我们 永远不会完全理解 是什么决定了我们的决定(根源可以追溯到复杂信息处理系统的可解释性问题),因此我们总是编造东西到 来理顺叙述 。
从中我们能学到什么
探究认知偏见可能有点可怕(维基百科列出了 157 个,是的,我数过了),但正如有人曾经说过的,知识是走向智慧的第一步。后退一步,观察你对自己不断的评论,并将其与你内心生活的复杂性进行对比,这可能会很有趣。
这可以帮助我们更加留意自己的偏见和虚构。我试着记录那些我发现自己公然胡说八道自己的行为,或者明显试图为自己辩护的时刻,但我并不幻想自己摆脱了偏见。它们在我们心中根深蒂固,以至于认为我们可以克服它们可能只是另一种认知偏见。如果连丹尼尔·卡内曼都说他没有取得太大的进步,这可能是不可能的。****
最后,我认为人工智能社区也应该注意这一点。我们的偏见表明,当涉及到我们自己的行为时,我们严重高估了 可解释性 ,所以我们应该意识到机器为自己的行为辩护的能力的潜在局限性。我们强烈希望他们能与我们交流,并公开他们的动机(正如 Lex Fridman 和 David Ferrucci 所言花一些时间在这里讨论),但我们应该注意他们不会变得太像我们人类。
毕竟,我们不希望有整天闲聊的机器人霸主。
缺失数据替换的可解释性
替换缺失的数据会让你的机器学习模型更难解释。以下是如何…

Image by Anemone123 from Pixabay
介绍
输入缺失值是处理真实数据时的一个重要步骤。有几种常见的方法可以解决这个问题。一些流行的方法包括删除有缺失值的实例,为缺失元素创建一个单独的类别,或使用均值插补。它们不一定有效,还有其他算法,如 KNN、MICE、MissForest 或 GANs 可以更准确地估算缺失值。
在我的研究实习项目期间,我注意到在用 KNN、小鼠和 MissForest 估算的数据集上训练的分类器实现了更高的准确性,通常是 3-4%。这是一个相当可观的精度增益,而且几乎没有现存的 Python 库实现这些算法。听起来不错,对吧?

Scheme for computing Classifier accuracy on the dataset with missing values [2]
不幸的是,在获得更高的精确度和得到可解释的结果之间有一个权衡。在这篇文章中,我们将看看缺失数据填补如何影响 ML 模型的可解释性。我文章的一部分将基于这篇研究论文【1】。我们开始吧!
我喜欢数据科学的原因是,它吸引了许多对人工智能和数据科学充满热情的志同道合的人。所以在Linkedin上和你联系会很棒!
不应估算的缺失数据
保存关于缺失的信息对于 ML 模型有时可能是有用的。它还可以使模型更具解释力。
设想一个数据集,其中包含医院患者的信息,这些患者接受了某种疾病的检查。

Hospital patient data with missing values
3 号病人没有被诊断为患病。这就是为什么医生决定不再对症状 _A 和症状 _ b做进一步的实验室测试。这里的遗漏有一个意思:患者没有生病,因此遗漏了其他测量值。如下图所示,患者 3 的输入值是错误的,没有意义。

Hospital patient data with imputed missing values
要保留关于缺失的信息,最好对数据进行一次性编码,并添加新的特性来指示缺失值的出现,如下所示。(为了避免 【哑变量陷阱】 我们可能应该去掉 Symptom_A_No 和 Symptom_B_No,但为了简单起见还是保留在这里)

Retaining information about missingness — rather than trying to replace it
在输入数据集之前,我们必须谨慎思考。这种归罪有意义吗?如果我们这样做,是否会造成重大信息损失?如果是,在这种情况下,将更难解释基于该估算数据训练的 ML 模型的结果。
重要的是要注意,与我们的直觉相反,如果我们将缺失信息作为另一个特征,ML 模型的准确性可能会得到较低的准确性分数。这取决于估计器算法的性质以及它们在训练和测试阶段如何处理数据。这也是我在文章开头提到的在可解释性和准确性之间的权衡。
缺失数据的分布可能不同
数据可能以 3 种不同的方式丢失:MCAR(完全随机丢失)、马尔(随机丢失)和 NMAR(非随机丢失)。详细解释它们超出了本文的范围(如果您想了解更多,可以看看这篇文章)。相反,我将关注 NMAR,它通常对可解释性有最大的负面影响。
NMAR 是一种缺失类型,其中缺失的数据取决于要素本身。例如,想象一下在美国进行的一项关于人民收入的调查:

Annual Income with undisclosed data
一些调查参与者没有透露他们的工资。然而,我们不知何故从一个秘密来源得到了这些数据。没有丢失值的完整(真实)数据集如下所示。

Annual Income with a complete (true) set of data
现在知道他们为什么不提工资了吧!他们只是比大多数人挣得多,他们可能不想和其他人分享这些信息。这正是 NMAR 的现状。数据的缺失与特征本身有关。在这种情况下,收入高于某个门槛的人在调查中没有透露他们的收入信息。
在 NMAR 的案例中,数据的估算可能会出错。问题是插补算法不知道这些缺失值的分布是什么。他们会假设它类似于整个数据集的分布,这显然是错误的!
让我们看看一个简单的均值插补是如何处理这种情况的:

Missing data replaced with the mean
在 NMAR 的例子中,这些插补的可解释性会受到影响,模型的准确性会下降。正如数据科学家所说:“垃圾进,垃圾出”。
摘要
数据插补是机器学习管道中非常重要的一步,因为它会影响数据的质量。数据插补可以通过不同的方式降低机器学习模型的可解释性。有时,应通过创建附加要素来指示值何时缺失,从而保留关于缺失值的信息。NMAR,这种类型的数据缺失,可以使插补更难解释和不正确。还需要记住的是,更复杂的插补算法倾向于以更难解释的方式对数据进行插补,这会影响 ML 模型的可解释性。
参考
[1]https://arxiv.org/pdf/1907.12669.pdf
[2] IT 创新中心
可解释性——下一个前沿
为什么不确定性是人工智能的一个特征,而不是一个缺陷

The billion dollar question
50 多年来,计算机一直是我们生活的一部分。它们最初是只有大公司才使用的巨大装置,它们的最新版本是我们放在口袋里的微型智能手机。
纵观我们与计算机互动的历史,我们主要把它们作为扩展我们能力的一种手段。它们让我们能够更高效地写作,更轻松地编辑照片和视频,即时获取信息。
在这样做的时候,他们遵循了古老的机器范式:以可靠的方式运行的人类结构,其存在的唯一目的是为了让我们的生活更容易完成某项特定任务。从战车,到引擎和汽车,再到计算机,所有这些东西都是为了帮助我们解决特定问题而创造的。
尽管我们人类喜欢抱怨我们的机器无法正确为我们服务的各种方式,从史前战车抛锚到现代计算机显示可怕的蓝屏死亡,但事实是,大多数时候这些机器工作得惊人地好。
考虑一下你的车多久坏一次。如果你特别不幸,那可能是每三个月一次。或者想想现在你需要多长时间重启一次电脑。每周一次?也许每隔一周?这在他们的功能周期中所占的比例非常小。
更重要的是,能工作的机器和不能工作的机器之间有一条清晰的分界线。你的车要么前进,要么不前进,你很清楚是前进还是不前进。你的电脑要么运行,要么不运行——同样,这里没有模糊的界限。
这使得我们与机器的交互变得异常简单。我们需要从他们那里得到某种效用。我们的汽车应该把我们从 A 点送到 B 点,它们要么能做到,要么不能。我们的电脑应该帮助我们写作、编辑照片或网上冲浪,反过来,它们要么胜任这项任务,要么不胜任。作为用户,我们可以立即判断出这是一个还是另一个。
更重要的是,我们从来不会再三考虑是否存在某种中间状态,一种中间状态,在这种状态下,事情可以做,也可以不做。当然,我们的汽车发动机罩下可能会有一些我们没有意识到的问题,但我们的汽车会很高兴地缓慢前行,直到问题变得足够严重,足以抛锚。或者在我们电脑的操作系统中可能有某种未知的病毒,但我们不会意识到这一点,直到事情开始严重失灵。
我们与机器的互动是基于这种基本的二进制操作模式。它们要么“开”要么“关”,要么完全不起作用,要么 100%可靠。
但是在过去的几年里发生了一些变化。我们的机器变得能够以不同的模式运行,一种新的状态,在这种状态下,事情不会“只是”工作或不工作。他们现在已经进入了不确定的领域,这是迄今为止计算机尚未探索的领域,也是迄今为止人类独有的特权。
不确定状态
什么是不确定性?这是一个与世界特定地区有着内在联系的概念。当你想到明天的天气时,会有一定的不确定性。或者,股票市场因其带来的不确定性而臭名昭著。即使被认为是简单的任务也有相关的不确定性:这条信息是真实的吗?那真的是我想买的咖啡机吗?我是真的生病了,还是只是过敏?
直到最近,这些问题只能向我们自己或其他人提出。在大多数情况下,我们不会得到简单的是或否的答案。即使我们这样做了,我们也会(或者应该)要求一些正当的理由。毫无疑问,有时我们可能会与某种更高的权威对话:例如医生、律师或牧师。但即使是他们也不能免于证明他们对感兴趣的主题的观点(也许除了牧师!).
为什么我们拒绝接受一个不合理的观点?这是因为我们知道,每一种观点中都有一种固有的不确定性概念。这也是因为这些问题的答案将为达成进一步的决定提供一个垫脚石。我们希望有一个坚实的基础来构建我们的生活,这就是为什么我们需要对别人告诉我们的有一些信心。
信任
建立信任需要付出巨大的努力,但却极易失去
一个人避免向他人证明自己观点的唯一方法是培养一种难以置信的信任感,让他们的观点不受审查(顺便说一句,牧师就是这样逃脱的!).这将使他们能够避免为他们所有的答案找理由,因为他们在过去已经有了做对事情的良好记录。
信任需要付出巨大的努力来建立,但却极易失去。这是一个众所周知的人性事实,尤其是因为失去对被证明会把我们引入歧途的人的信任是一种非常有用的防御机制,可以抵御那些试图利用其权威地位的人。
可解释性
他们错了,因为任何实体在不确定的情况下做出选择的那一刻,这些选择有能力影响人类的生活,然后这个实体成为我们社会生态系统的一部分,因此,它获得了改变我们世界的能力——无论是好是坏
这和电脑有什么关系?如前所述,他们现在正走向不确定的领域。他们需要表达意见或做出不确定的决定。我们要求亚马逊为我们找到价格合适的产品。我们请求谷歌为我们提供准确的信息,请求脸书提供最新的新闻。我们有算法可以监测我们的健康状况,决定我们再次犯罪的可能性,或者浏览一堆简历来找到合适的候选人。
我们知道没有万无一失的方法来满足这些要求,我们当然也不会要求人类做出 100%正确的决定。然而,如果我们没有办法仔细检查专家的诚意和可靠性,我们永远不会相信人类专家会为我们做所有这些决定。事实上,如果一个对这一切负责的人只是为所欲为,却从未被要求解释他们的行为,我们会认为这是对我们民主的绝对冒犯。如果提供任何一种解释都超出了他们的思维能力,那就更荒谬了。我们绝对不会允许一个人这么做,是吗?我们会吗?
那么,我们为什么允许机器使用它呢?听起来可能很可笑,因为这个想法直到最近才出现在我们的脑海中。还记得我们是如何习惯于把我们的机器想象成总是在“开”和“关”两种状态之间运行的有限生物吗?还记得我们如何从未预料到可能会有某种形式的中间地带,一个薛定谔的盒子,在那里我们的机器将同时开启和关闭,或者,更好的是,它们将进入不确定的领域,我们人类认为这是机器智能的最后一个前沿。
他们确实进入了那个领域。当我们决定使用算法为我们做出这种重要决定的时候,当我们决定使用算法来模拟世界中具有内在不确定性的部分的时候,他们就做到了。
我们认为,在我们遇到这种伦理困境之前,我们需要创造一个具有人类思维能力的机器,一个真正的通用人工智能。这就是为什么我们高兴地让我们的算法承担人类专家的角色,因为我们从未想过这会产生任何问题。
甚至在今天,人们还在谈论机器,认为它们是冷酷的计算实体,不偏不倚,因此在决策方面比人更好。他们永远不会不公平或有偏见,因为他们没有感情或经历偏见。遗憾的是,这种言论也来自当今数据科学前沿的人们。
事实是他们错了。
更不用说隐私、平衡数据集、公平或任何其他目前吸引机器学习社区的流行语了。他们错了,因为任何实体在不确定的情况下做出选择的那一刻,这些选择有能力影响人类的生活,然后这个实体成为我们社会生态系统的一部分,因此,它获得了改变我们世界的能力——无论是好是坏。
在谷歌和其他公司在我们的社会中获得如此突出的地位后,我们发现自己正处于这种状态。我们没有想过这些算法可能在引擎盖下出现故障,这种故障是他们设计的一部分——一个功能,而不是一个错误。直到问题开始出现,我们才注意到。
任何涉及不确定性的决策,世界上任何不确定的部分(我们的世界中没有任何东西是确定的),都不能以模仿我们习惯的机器可靠性的方式进行建模。天气预报准确率可以达到 90%。可能 99%。可能是 99.9999999%。没关系。总会有一个错误,这个错误导致了不确定性的过渡。
你什么时候是对的?你什么时候错了?我什么时候能相信你?这些是每个正常人在向机器提出这些问题时都应该问的问题。如果在接收端有一个人,我们会问这些问题。
但是我们没有。我们已经被与机器互动的漫长历史所愚弄,这些机器明确无误地“开”或“关”,以至于我们放松了警惕。我们被允许被机械“神谕”所统治,这些机器声称会如实回答我们所有的问题。除了他们永远不能做到这一点,不是吗?
接受
如果你的医生说他们在医学院的考试中获得了 95%的分数,但不幸的是,他们不能为他们的专业意见提供额外的理由,你会满意吗?你会相信他们的话吗?
我们怎样才能摆脱这种困境?我们怎样才能让公众知道他们现在面对的机器是不可靠的,永远也不会可靠?我们如何处理这种认识的后果?我们如何回来帮助智能机器在我们的世界中重新获得应有的地位,尽管是以一种更负责任的方式?
我们只有一种方法来处理这种不确定性。作为人类,我们经常需要证明我们的决定和信念是正确的,而正是我们论据的有力度(或不足)决定了其他人对我们观点的重视程度。我们应该让我们的算法保持同样的高标准。
我们目前用来创造智能机器的方式。我们定义一个问题。这个问题可能很简单:你在这张图片中看到的是一只猫还是一只狗?然后我们收集了很多猫狗的图片,我们反复的给我们的算法看,让它回答我们的问题,并且好心的让它知道它什么时候回答对了,什么时候回答错了。然后,我们在一组它从未见过的图片上测试它的新知识。我们测量它得到的正确答案的百分比,并高兴地报告我们的算法的准确性。然后我们把这个算法部署在一个真实世界的系统中,这个系统试图回答不同人提出的同一个问题。
如果我们只是想让我们的智能手机在我们的照片上自动标记我们的狗,这可能是非常无辜的,甚至当它误认为我们邻居的猫时,它可能会很可爱,但如果我们谈论一个更严重的应用程序,事情可能会变得很糟糕。
比方说,在你做完检查后,你走进一个医生的办公室,医生告诉你你得了癌症。你可能会说,“等一下,医生”。“你是如何得出那个结论的?”
如果你的医生说他们在医学院的考试中获得了 95%的分数,但不幸的是,他们不能为他们的专业意见提供额外的理由,你会满意吗?你会相信他们的话吗?
如果一个医生说:你的检查显示了这个和那个,这就是为什么我认为你得了癌症,你不会更开心吗?即使你不明白他们在说什么,难道你不会更信任他们吗?
作为科学家和实践者,这是我们应该坚持的标准。
继续前进
我们可以停止认为自己超越了一个功能社会中每个成员的道德标准
它也不在我们手中。无论我们是否愿意,更广泛的公众将很快开始支持我们的算法达到同样的标准。在一些地区,他们已经开始了。我们可以继续否认这一事实,我们可以继续坚持机器学习算法不需要解释它们自己,它们在某种程度上超越了这一点(就像牧师曾经是!),而且我们应该只是专注于让他们表现得更好。
我们可以,但当公众超越我们时,我们不应该抱怨。当规章制度降临到我们头上时。我们可以抗议他们,我们可以谈论落后的监管者,他们看不到进步的道路。我们可以认为自己精神上高人一等,因为我们是科学家。我们可以看不起我们本该服务的社会。
或者我们可以承认这样一个事实,我们还没有达到我们想要的目标。我们可以承认公众的恐惧。我们可以专注于我们的算法确实可以改善人类生活的情况,远离那些弊大于利的情况。我们可以停止认为自己超越了一个功能社会中每个成员的道德标准。
离开学术界进入现实世界就是这样。
你长大了。
可解释的人工智能(第一部分):解释和机会
本文基于 2019 年 10 月 7 日在柏林机器学习小组上提交的材料。原故事首发于 丹工作室网站 。
随着 ML / AI 领域的成熟和复杂模型在新的(和关键的)行业中的部署,新的挑战出现了。其中最常见的一个是认为这些模型就像黑盒一样,也就是说,很难理解它们是如何工作的以及它们预测背后的推理。与此同时,消除偏差(即发现模型在预测中使用了歧视性特征)的努力也在不断增加。这两者都导致对这些人工智能系统的不信任程度上升。解决这些问题的领域被称为可解释的人工智能,简称 xAI。在这篇博文中,我将带你了解这个领域背后的动机。
警告/夸大其词
在开始之前,我想提出一些警告。虽然机器学习的“黑盒子”不是一个新话题,自从第一个算法被创建以来就一直是一个问题,但新一波的可解释性方法是一个相对较新的发展。由于这是最近的事,该领域的许多方法还没有在不同的环境中彻底测试过,关于该主题的学术工作也很少。这就是为什么在关键生产系统中使用这些方法时要非常小心,并且在盲目应用之前要彻底研究这些方法。
不幸的是,赛也陷入了炒作和流行词风暴,而一般人工智能领域是受害者。这种炒作会掩盖使用这些方法的价值和危险,并使选择最佳方法变得困难。
什么是 xAI?
作为第一步,让我们定义 xAI。尽管这两个术语在这个领域有所不同,但为了简单起见,我们将交替使用可解释性和可解释性这两个词。我找到的最佳定义是这个:
可解释性是人类能够理解决策原因的程度(Miller,2017)。
我们可以把重点放在这个定义中的两个具体的词上——人和决策。这表明该领域最重要的思想是帮助人类理解机器学习系统。
我们为什么需要它
在机器学习出现之前的计算世界中,机器做出的决定是以非常严格的方式执行的。这使得这类程序的结果更容易理解,因为你所要做的就是理解源代码。然而,如今,即使是经验丰富的数据科学家也可能难以解释他们模型的预测原理,这个过程似乎很神奇——给出数据,为预测(决策)添加目标,然后得到结果——中间没有任何东西向你展示决策过程的暗示。下图说明了这个问题:

Image source: Interpretable Machine Learning (C. Molnar)
xAI 领域发展的另一个非常重要的推动因素是关键行业中生产级 ML 系统的日益成熟。虽然在 2009 年左右,大多数部署的机器学习系统都是在技术领先公司(即谷歌、Youtube)的产品中,错误的预测会导致向应用程序用户显示错误的建议,但现在这些算法部署在军事、医疗保健和金融等领域。这些新的人工智能行业的预测结果可能会对许多人的生活产生深远而巨大的影响——因此,我们必须知道这些系统是如何做出决定的。

Image source: DARPA (https://www.darpa.mil/program/explainable-artificial-intelligence). DoD stands for Department of Defense.
与这一主题相关的还有《GDPR》和“解释权”等法律。将机器学习模型部署到生产中的数据科学家可能有法律义务解释它如何做出决定,如果这个决定对人有很大影响的话。
xAi 也有利于应用程序的最终用户。有了这样的系统,他们会更加信任。让我们以一个人工智能驱动的医疗保健应用为例。在这种情况下经常发生的是,技术团队向领域专家(或应用程序用户,在这种情况下)报告模型性能。工程师们报告说,该模型在预测病人是否患有某种疾病方面达到了 95%的准确率。大多数时候,医疗从业者会对这样的结果表示怀疑——说这根本不可能那么准确。如果在这种情况下,我们使用诸如本地可解释的模型不可知解释(LIME)的方法来解释为什么某个患者被分类为没有生病,则应该提高系统中的信任级别。医生应该能够看到,在提供诊断时,模型与他们的逻辑非常相似。这种情况如下图所示,模型显示,即使患者有一些症状,如打喷嚏和头痛,他们也没有生病,因为他们没有表现出疲劳。

Image source: Ribeiro, M. T., Singh, S., & Guestrin, C. (2016). “Why Should I Trust You?”: Explaining the Predictions of Any Classifier. https://doi.org/10.18653/v1/N16-3020
现在,我们介绍了 xAI 的基础知识及其机遇。在接下来的文章中,我们将分享哪些方法和相关的软件工具可用于 xAI。
如果 10 月 29 日你在柏林,我将会和我的同事 Thomas Nguyen 在柏林的 AI in Action 上就这个话题展开讨论。这里有一个报名链接。
可解释的人工智能:人机和谐的下一个前沿

Photo by Andy Kelly on Unsplash
起初,没有机器。人类仅仅依靠体力劳动生存。然后他们发明了工具,从那些工具中进化出了更复杂的工具。最终,由于跨越数千年的创新,这些工具变成了机器。
发明机器的目的是增强我们人类的能力和虚弱的能力,因为从设计上来说,它们超过了我们的身体能力。机械机器在原始能力方面给了我们优势,而计算机器为我们提供了以我们自己根本无法做到的速度生成、组织和处理大量数据的手段。
我们现在正处于计算机中酝酿的另一项人类创新的初级阶段,以便机器能够比我们更好地学习(机器学习或 ML)、推理和解决问题(人工智能或 AI)。如果我们做对了。这些机器将处于下一波人类进步的前沿。但是危险是什么,我们如何避免它们呢?
危险的 AI
人工智能的明显危险是那些可能以这样或那样的方式伤害人类或生命的危险。人工智能/人工智能的概念出现不到 100 年,与智人出现以来的 20 万年相比,这是一个相当小的间隔。因此,很容易怀疑人工智能可能的指数进化,并问自己这样的问题;我们什么时候能造出超越人类认知能力(奇点)的机器,到时候会发生什么?
我邀请你,现在,把奇点问题留给科幻小说。请注意一件事,那就是今天的 ML/AI 已经呈现出有意义的危险,我们有责任尽快减轻这种责任。此外,如果一方面,我们希望在未来“奇点”发生的那一天最大限度地增加积极成果的机会,那么随着人工智能的不断发展,我们应该不断应对风险。另一方面,如果我们想最大化我们的机会去实现那个未来。
今日 AI 的危险
鉴于前面描述的危险,让我们专注于我们认为当今 ML/AI 最紧迫的问题之一,它源于观察到的过度信任基于 AI/ML 的系统的趋势,因为它们现在处于做出明智决策的模糊理想中,因此,它衍生出我们应该瞄准的下一个趋势;那就是深思熟虑地设计基于人工智能的系统,旨在增强我们人类的认知能力,而不是取代它们。
先说,我说的过度信任 AI/ML 是什么意思?今天,如果你面临选择一个队友下棋的决定,你的选择是在这项任务中最好的人类选手或最好的计算机程序之间,你不会因为选择计算机程序而疯狂。在这场游戏中,如果你碰巧因为盲目信任这个程序所做的决定而赢了,难道你不认为信任这样一个程序是最明智的决定吗?当我们盲目地依赖一个可以接收人类无法接收的所有数据的系统时,我们是否在做出最佳决策?
为了回答这些问题,我们还应该问自己,盲目信任特定的人工智能系统会有什么影响?并承认这个问题的答案因情况而异。为了进一步发展这一思想,让我们来检验这样一个假设:越来越依赖机器来做决策已经被证明是对我们人类的一种威胁。
最近一个令人悲伤的例子是在航空领域(波音 737 MAX 问题),人们可以认为飞机越来越多地由自动驾驶系统控制,飞行员只能在起飞和着陆期间执行例行程序。这对飞行员在意外情况下操纵飞机的能力产生了严重的影响。人们还可以说,对机器决策的日益依赖正导致飞行员放弃他们的认知技能和应对困难局面的能力,因为他们盲目信任自动驾驶系统。但是这个问题的答案是我们抛弃自动驾驶系统吗?
也许一个理想的场景是,如果专家(在这种情况下是飞行员)观察到违背他们直觉的东西,他们可以做我们人类自然的事情,这就是质疑。自动驾驶:你在做什么,为什么?如果答案不令人信服,他们(飞行员)应该能够立即控制局面,并且作为拥有巨大认知能力的人类:承担行动的责任。
如果你是那些同意前面的将是一个理想解决方案的人之一,你并不孤单,因为它说明了对一些人所谓的“可解释的人工智能”或 XAI 的需要。因为我们应该能够从任何基于人工智能的系统中询问并获得关于它正在做出的选择的合理解释。好奇是使我们与众不同的人类特征之一,我们应该尽一切努力保持这种人类属性。
可解释的人工智能(XAI)
给你一点背景知识,但不要过多地谈论细节;国防高级研究计划局的人创造了术语“可解释的人工智能”( XAI ),作为一项研究计划,旨在揭示人工智能的一个关键缺点。越复杂的 ML/AI 模型越难以解释。此外,目前形式的人工智能旨在学习特定领域的知识,并从具体的数据示例中学习,仅限于训练他们解决的特定问题,因为它仍然需要人类抽象思维的能力来理解问题的全部背景。
鉴于这些基于人工智能/人工智能的系统的理解范围狭窄,很自然地认为,如果这些算法被用于做出涉及某人生活或社会的关键决策,那么(对我来说很明显,我希望对你也是如此)我们不应该摆脱它们,但我们不应该委托这些系统承担做出这些关键决策的全部责任。
为了进一步阐述这一点,我建议你阅读迈克尔·乔丹(不是篮球运动员,而是来自伯克利的知名工程师),他在他的文章《人工智能——革命尚未发生》中阐述了他的想法。我和他在某些事情上意见一致;我们应该问自己,今天 ML/AI 需要哪些重要的发展,以安全地增强人类解决非常复杂问题的能力。我认为,XAI 肯定是这些重要发展之一。
XAI 重要问题
想想另一个系统给出建议的例子:如果医生使用人工智能系统来帮助她诊断医疗状况,预测的诊断是不够的,逻辑流程是医生还应该能够要求系统解释预测的诊断,在理想的情况下,答案还应该尽可能以医生可解释的术语出现,而不是用机器学习模型及其可调参数中使用的复杂行话来解释。
这向我们所有机器学习学科的人发出了邀请,让我们问自己,我们如何构建可以预测并解释的系统?此外,承认努力的重要性。因为来自 AI/ML 解释的所有学科的领域专家应该能够通过利用他们可用的越来越多的数据和计算能力来推进他们领域的知识。
你们中的一些人可能仍然想知道,最终来说,是否真的需要领域专家?为此,我建议你读一读 Rich Sutton(谷歌 Deepmind 的重要思想家之一)的文章《痛苦的教训》(The bitter lesson),在这篇文章中,他认为领域专业知识无法与机器学习模型的模式识别能力相竞争。我们不必同意或不同意。然而,我的观点是,我们把“竞争”这个词从等式中去掉,而是简单地认为增强了我们人类的认知能力。
因此,第二个邀请是设计这些新工具,使每个人都可以理解问题可以从数据的角度来看,这些工具也应该足够简单,任何人都可以在自己的领域成为【数据科学家】,并通过机器学习的奇妙模式识别能力获得新的见解和发现,这些见解和发现隐藏在乍一看对我们人类来说可能不明显的数据中。如果这样的系统不仅能够发现模式,而且能够向我们解释它们,我们不仅会意识到机器拥有的搜索和学习的探索能力,而且我们还可以塑造下一种形式的人类智能增强 (IA)。
这就是为什么需要建立一个单独的 HCI 类(人机界面),在我看来,这可以归结为解决两个问题:
第一;当使用一个人工智能系统时,不管问题是什么,我们必须能够得到答案的那些基本问题应该是什么?
让我们把这个问题的范围缩小到预测,因为我们相信预测最终会为大多数决策过程提供信息。因此,我们最好能够回答任何人工智能辅助决策的三个基本问题:
- 我能相信这个预测吗?为什么?
- 为什么是这个预测而不是别的呢?
- 我怎样才能使预测更可靠/更好?
第二;我们如何向其他人解释这些问题的答案?
DARPA 有一个独立的团队致力于研究解释心理学。这个团队完全专注于从心理学的角度挖掘解释科学的文学知识库,以建立有助于衡量解释有效性的框架。这是 XAI 向 UX 迈出的一步。
除了 DARPA 之外,在大公司和大学里也有许多研究项目正在为 XAI 开发工具。我认为,开发能够回答 XAI 基本问题的系统遵循两个阶段(软 XAI 和内省人工智能):
软 XAI
想象一下,你正在试图理解为什么一种动物会有这样的行为。但是你不能和这样的动物交流?同样,你试图理解人工智能系统决策背后的基本原理,但该系统目前无法自己回答它为什么要做这些事情。有什么方法可以解决这些问题呢?
深层方法,试图理解系统内部发生的一切。我们可以尝试详细了解系统的不同组成部分,以及它们如何学习,以及这些任务如何影响最终结果。例如,如果我们在谈论人工神经网络,这意味着查看每个感知器的参数,了解是什么使它们“激活”以及这些激活如何传播到我们可以理解的概念中。然而,解释这些结果需要高度的专业化,而且很难一概而论。
与此类似的是,试图通过分析特定刺激下的神经通路和大脑内部来从我们的行为中获得解释,这可以导致关于大脑如何工作的重要发现,并且神经科学和机器学习领域继续从彼此的发现中学习。然而,我们的经验是,可以从更简单的方法中获得可解释结果的替代方案。
黑盒方法,这是通过将系统视为一个我们不知道其内部的黑盒来获得答案,因此只有通过操纵其输入并找出输出中有趣的内容才能理解其行为。这提供了一个很好的框架来获得许多见解,并且在其他领域也很有效,从物理学到心理学。
鉴于这种方法的实用性, MindsDB 将其作为解释的手段,在这条路上,我们有幸站在巨人的肩膀上,因为我们研究并借鉴了其他人的想法(谷歌的 What If 、IBM 的 Seq2Seq-Vis 、香港科技大学的 VisLab 、SHAP 的、 LIME 等等)
内省 AI
一旦我们实现了软 XAI,我们实际上可以教机器如何做到这一点,这将涉及重新设计 AI/ML,以便它可以对自己以及为什么它会这样做做出解释,就像我们学习如何解释我们的行为和思想一样。我们相信下一代人工智能系统将被教会分析自己的行为。
在我看来,内省式人工智能将源自黑盒方法和我们对语言的理解。背后的推理来自于我们人类的观察;我们对我们的大脑知之甚少,但同样可以解释为什么我们会以这样或那样的方式思考。我们已经进化到能够解释我们的行为和我们对周围世界的解释。有人可能会说,可解释性本身是传递知识的基础,它在进化过程中塑造了我们的大脑,使人类成为唯一能够在知识基础上不断构建知识的物种。
展望未来
围绕人工智能及其能力的所有兴奋,任何 XAI 技术都有一个重要的作用,那就是为后代保持人工智能的安全和理智。
我和我在 MindsDB 的同事们,将不断地发布我们对可解释性的贡献。您可以在此处找到公共存储库:
随着我们在未来几年继续为实际成果做出贡献。我们相信,在为现实世界构建任何人工智能驱动的应用程序时,XAI 很可能会成为一项法定要求。
鸣谢:有很多人在撰写本文期间的评论和其中包含的想法给了我很大的帮助,包括李正吉·达博、乔治·霍苏、亚当·卡里根
参考文献
http://www.incompleteideas.net/IncIdeas/BitterLesson.html
https://bdtechtalks . com/2019/01/10/DARPA-xai-explable-artificial-intelligence/
https://bdtechtalks . com/2018/09/25/explaible-interpretable-ai/
https://www . DARPA . mil/program/explaible-artificial-intelligence
https://medium . com/@ BonsaiAI/explaible-ai-3-deep-explaining-approachs-to-xai-1807 e251e 537
https://arxiv.org/pdf/1606.04155
【https://arxiv.org/pdf/1705.04146
http://www.deeplearningpatterns.com/doku.php?id =合理化
可解释的人工智能与解释人工智能——第二部分
统计直觉与符号推理系统

20 世纪初,聪明的马汉斯表现出非凡的回答算术问题的能力。汉斯用蹄子敲击数字或字母来回答问题。这种行为吸引了全世界的注意,他是第一个聪明的动物。然而,经过一些实验后,汉斯似乎有偏见,从他的人类观察者那里读取潜意识线索,并挖掘出适当的答案。
汉斯是如何做出决定的?
聪明的汉斯利用统计偏差来完成他的任务;这种方法在不理解背景符号推理模型的情况下寻找数据集中的关系。
在前一部分,我们介绍了两种思维系统以及它们与可解释性、概括能力和学习速度的关系。这一部分对系统 1 和系统 2 进行了更深入的比较,我将这两个系统分别称为统计直觉系统(“聪明的汉斯”系统)和符号推理系统。
统计直观系统
直觉与自动决策和反思有关。直觉是在没有完全信息的情况下做出决定的能力,它使我们能够在没有对某个领域深刻逻辑理解的情况下做出决定。直觉系统使用历史证据来证明其论点的力量。直觉系统更关心两个历史事件 A(下雨)和 B(打伞)之间的相关性,而不是对它们之间的关系进行推理。因此,为了证明:如果下雨,那么人们带着雨伞,直觉系统使用频繁一起观察两个事件的历史统计证据。而逻辑系统将解决这个问题,并试图用一些常识和逻辑背景来证明它,例如:雨由水组成,水使人潮湿,人们不喜欢淋湿,雨伞挡住了雨。逻辑系统知道带伞并不意味着下雨,所以下雨导致带伞,而不是相反。所以直觉系统是我们大脑中懒惰的部分(聪明的汉斯诡计),不一定是明智的部分,但在大多数时候可能是正确的,特别是如果历史证据是强有力的。
经典的统计机器学习算法使用直觉来做出决策。他们都建立了一个过去经验的数学模型,并利用它来进行自动反思。深度学习通过构建高级特征添加了一些推理,但它仍然使用统计偏差做出最终决策(决策层)。
大多数基于深度学习的统计直观系统具有以下特征:
- 窄(用于特定领域,如数字识别)
- 从历史数据或经验中学习(监督、非监督或强化学习)
- 克服维数灾难:构建低级输入 x 的高级表示
- 依赖于 i.i.d .假设:假设测试分布与训练分布相同
- 由于 i.i.d .的假设,这个系统需要大量的训练数据。训练分布必须尽可能的一般,而这个系统在训练分布之外的推理能力很弱
- 从输入到输出的映射不包含搜索过程,即在许多可能的决策空间中搜索最优决策,或搜索逻辑论证以实现其决策
在本文中,我将使用深度学习(DL)作为直观系统的主要代表,它接受低级输入(语音、图像或文本),降低维度,并将输入映射到高级表示空间,在该空间中,它可以轻松地在不同目标(类、事件)之间建立决策函数,参见图 1。

Figure 1: http://colah.github.io/posts/2014-03-NN-Manifolds-Topology/
目前有很多 DL 可以做什么的例子,比如语音识别、自动驾驶汽车和机器翻译,但我们来讨论一下什么对深度学习具有挑战性。
当涉及到符号计算时,深度网络往往在泛化方面失败。
以标量恒等函数为例,它是最简单的符号计算之一。已经完成了一个实验来训练一个自动编码器,该自动编码器采用一个标量输入(例如,数字 4),在一个潜在空间(分布式表示)中对其进行编码,然后再次预测输入值(数字 4)作为最后一个隐藏层的线性回归。使用不同的自动编码器,它们具有不同的激活功能和范围在-5 和 5 之间的输入。在本实验中,对范围> 5 或< -5 内的输入进行了泛化测试。结果显示,所有的网络都未能一般化(图 2)。

符号运算的另一个例子是使用比较运算符(< > ≤ ≥ =)。在论文 从嘈杂的数据 中学习解释规则,Deepmind 的科学家们实验训练了一个 CNN 模型,该模型比较了两幅 MNIST 图像,并在右侧图像中识别的数字大于左侧图像中的数字时给出真实值(图 3)。

Figure 3: A DNN system that compares two MNIST images and give a true value when the recognized number of the right image is greater than the number of the right image. Learning explanatory rules from noisy data
如果我们训练 CNN 模型来完成这项任务,我们需要创建一个数据集,其中包含每对数字的几个例子;只有这样,它才能概括。例如,在下图中,我们看到一组介于 0 和 9 之间的所有可能的数字对,应用< relation (Figure 4).

Figure 4: Application of the ‘<’ (less-than) relation to every possible pair of digits between 0 and 9
So, if the training data set contains a set of different images for every pair of digits in Figure 4, then the DL system will be able to generalize correctly. However, it will generalize visually rather than symbolically. In other words, whenever this system receives two images, it will map them to their similar training pair (again “Clever Hans” trick), and if that training pair is part of the list in Figure 4, then it will predict 1, or True.
How to test if the system generalizes the symbolic relation?
Suppose the training set of pairs is like that depicted in Figure 5; then, the system will most likely fail to predict the relations 7<9, 2<8, and so forth (Figure 6). It will be able to recognize the 7, 9, 2 and 8 digits because it has seen many images of them (i.e in 8<9). So it generalizes visually but not symbolically.

Figure 5: Application of the “less-than” relationship with some pair of digits between 0 and 9 removed

Figure 6: the difference between Visual and Symbolic generalization, Learning explanatory rules from noisy data
Most symbolic operations, such as simple arithmetic, propositional logic, first-order logic and spatial relations (e.g. object 1 is above, under, before or after object 2) are challenging for the intuitive system, especially when it comes to generalization.
Symbolic Reasoning System
推理可以被定义为历史知识的代数操作,以便回答一个新问题。这种操作可以包括在不同解的代数空间中搜索。
该推理系统具有以下特点:
- 它需要一个知识库(关系、非关系或图形数据库)。参见图 7 中的系谱图。
- 它需要符号事实、规则和关系的集合,如图 8 所示。

Figure 7: A knowledge graph of a family tree, Learning explanatory rules from noisy data

Figure 8: Symbolic clauses about the family tree
3.它需要一个推理引擎,通过使用一组规则和知识库,接受一个问题或查询并生成一个答案。例如,如果我问“谁是芙蕾雅的外叔祖?”,推理机将在图 8 的子句空间中搜索解决方案,并应用演绎规则,如替换。
第一个选择将是最后一个子句(在图中用蓝色表示)。这条规则的第一个谓词是 maternal 祖母(芙蕾雅?).通过检查第三个子句,我们看到“maternal 祖母”有谓词 mother(X,Z),mother(Z,Y)的连词,基本上说的是“如果 Y 是 Z 的母亲,Z 是 X 的母亲,那么 Y 是 X 的外祖母。”
因此,引擎将首先使用第三个子句找到芙蕾雅的外祖母,即夏洛特,然后是夏洛特的母亲,即林赛,最后是林赛的儿子,即弗格斯,他是芙蕾雅的外祖父(图 9)。

Figure 9 : Reasoning about the family tree, Learning explanatory rules from noisy data
正如我们在前面的例子中看到的,符号人工智能涉及一个搜索过程。在这方面,研究人员提出了不同的搜索算法,如目标树搜索(也称为 And-Or 树)和蒙特卡罗树搜索。
让我们再举一个例子,看看我们如何在归纳逻辑编程中使用树搜索,这是一个符号人工智能领域,专注于从数据中学习逻辑子句——这也被认为是机器学习的一部分。假设我们有图 10 中的真值表,我们想要找到正确的逻辑子句来预测给定三个输入 A、B 和 C 的 Y 。

Figure 10: A truth table
第一步是写出所有的迷你表达式,其中 Y 为真,如下所示:

(1)
符号简化系统应该找到的目标表达式是:

(2)
为了解决这个问题,自动符号简化 AI 将需要一组简化(问题简化)规则。然后,它将启动一个搜索树,在树的每个节点,它将选择一个或多个术语,然后它将应用一个最适合的简化规则。

Figure 11: A Search tree for logic simplification
在图 11 中,我们看到了一个例子,说明了如何使用树搜索结合背景知识(简化法则)来查找图 10 中真值表的最简单的布尔表达式。
这个问题的 python 实现如下:
from sympy import * # python symbolic package
from sympy.logic import SOPformimport numpy as np
import time # will use it to estimate the processing timea, b, c = symbols('a b c') # create the four three symbols in Fig 10minterms = [[0, 0, 1], [1, 0, 1],[0, 1, 1], [1, 1, 0], [1, 1, 1]] # the terms/rows in Fig 10, where y = 1tic = time.clock()expr = SOPform([a,b,c], minterms)toc = time.clock()
print('expression :', expr)
print('processing time:', toc-tic)
结果是:
expression : c | (a & b)
processing time: 0.0005342439999989068
正如我们所见,实现它并从训练数据/真值表中找到正确的布尔表达式是非常容易的。直到现在,到目前为止,我们已经看到了两个象征性 AI 可以做什么的例子。但是
符号系统中的挑战是什么?
符号系统的局限性
上面的例子是归纳逻辑编程的一个简单例子,我们用来寻找最优解的技术有以下限制:
- 计算开销大:假设我们有一个包含 15 个变量的真值表。目标表达式和 python 代码如下:

from sympy import * # python symbolic package
from sympy.logic import SOPform
import itertools
import pandas as pd
import numpy as npsm = symbols('x0:10')# create the truth table out of 15 boolean variablesimport itertools
import pandas as pd
n = len(sm)
truth_table = list(itertools.product([0, 1], repeat=n))# create a DataFrame of the truth tabletruth_table_df= pd.DataFrame(truth_table, columns= np.asarray(sm).astype('str'))# write a target logical expression, that the sympy should findy=(truth_table_df['x0'] & ~truth_table_df['x1'] & truth_table_df['x2']) | (truth_table_df['x3'] & ~truth_table_df['x4'] & truth_table_df['x5']) | (truth_table_df['x6'] & truth_table_df['x7'] & ~truth_table_df['x8'] & ~truth_table_df['x9'])# find the miniterms, where y is trueminterms=truth_table_df[y==1].values.tolist()# Run simplification codetic = time.clock() # starting timeexpr = SOPform(sm, minterms) # find the expressiontoc = time.clock() # end timeprint('expression :', expr)
print('processing time:', toc-tic)
结果是:
expression : (x0 & x2 & ~x1) | (x3 & x5 & ~x4) | (x6 & x7 & ~x8 & ~x9)
processing time: 2.3627283299997544
如果我们将这个例子的处理时间与只有三个变量的例子进行比较,我们会发现,根据变量的数量和解决方案的复杂性,处理时间会呈指数增长。
2.对噪声敏感:假设上一步的问题又增加了两个变量。这两个变量被赋予一些随机值,并且目标表达式是相同的:
from sympy import * # python symbolic package
from sympy.logic import SOPform
import itertools
import pandas as pd
import numpy as npsm = symbols(‘x0:12’)# create the truth table out of 15 boolean variablesn = len(sm)
truth_table = list(itertools.product([0, 1], repeat=n))# create a DataFrame of the truth tabletruth_table_df= pd.DataFrame(truth_table, columns= np.asarray(sm).astype(‘str’))# write a target logical expression, that the sympy should findy=(truth_table_df[‘x0’] & ~truth_table_df[‘x1’] & truth_table_df[‘x2’]) | (truth_table_df[‘x3’] & ~truth_table_df[‘x4’] & truth_table_df[‘x5’]) | (truth_table_df[‘x6’] & truth_table_df[‘x7’] & ~truth_table_df[‘x8’] & ~truth_table_df[‘x9’])# find the miniterms, where y is trueminterms=truth_table_df[y==1].values.tolist()# Run simplification codetic = time.clock() # starting timeexpr = SOPform(sm, minterms) # find the expressiontoc = time.clock() # end time
print(‘expression :’, expr)
print(‘processing time:’, toc-tic)
结果是:
expression : (x0 & x2 & ~x1) | (x3 & x5 & ~x4) | (x6 & x7 & ~x8 & ~x9)
processing time: 207.635452686
正如我们所看到的,解决方案是正确的,但是尽管我们只添加了两个变量,处理时间却要长一百倍。
3.对错误标签敏感:假设我们反转一些 Y 值:
from sympy import * # python symbolic package
from sympy.logic import SOPform
import itertools
import pandas as pd
import numpy as npsm = symbols('x0:10')# create the truth table out of 15 boolean variablesimport itertools
import pandas as pd
n = len(sm)
truth_table = list(itertools.product([0, 1], repeat=n))# create a DataFrame of the truth tabletruth_table_df= pd.DataFrame(truth_table, columns= np.asarray(sm).astype('str'))# write a target logical expression, that the sympy should findy=(truth_table_df['x0'] & ~truth_table_df['x1'] & truth_table_df['x2']) | (truth_table_df['x3'] & ~truth_table_df['x4'] & truth_table_df['x5']) | (truth_table_df['x6'] & truth_table_df['x7'] & ~truth_table_df['x8'] & ~truth_table_df['x9'])#reverse 2 random rows (mislabled)mislabels= abs(1-y.sample(n=2))
y.iloc[mislabels.index] = mislabels# find the miniterms, where y is true
minterms=truth_table_df[y==1].values.tolist()# Run simplification codetic = time.clock() # starting timeexpr = SOPform(sm, minterms) # find the expressiontoc = time.clock() # end time
print(‘expression :’, expr)
print(‘processing time:’, toc-tic)
那么结果就是
expression : (x0 & x2 & ~x1) | (x3 & x5 & ~x4) | (x6 & x7 & ~x8 & ~x9) | (x1 & x2 & x4 & x5 & x7 & x8 & ~x0 & ~x3 & ~x6 & ~x9) | (x0 & x2 & x9 & ~x3 & ~x4 & ~x5 & ~x6 & ~x7 & ~x8)
processing time: 2.4316794240000945
正如我们所看到的,只有两个标签错误的行创建了一个不正确的表达式。如果噪音和错误标签结合在一起会怎样?
那么结果就更糟了:
expression : (x3 & x5 & ~x4) | (x0 & x11 & x2 & ~x1) | (x0 & x2 & x5 & ~x1) | (x0 & x2 & x8 & ~x1) | (x0 & x2 & x9 & ~x1) | (x0 & x2 & ~x1 & ~x10) | (x0 & x2 & ~x1 & ~x3) | (x0 & x2 & ~x1 & ~x4) | (x0 & x2 & ~x1 & ~x6) | (x6 & x7 & ~x8 & ~x9) | (x1 & x11 & x3 & x4 & x8 & ~x0 & ~x10 & ~x2 & ~x5 & ~x6 & ~x7 & ~x9)processing time: 181.49175330699995
4。对的敏感的暧昧:
逻辑项 X0 = 1,意味着 X0 等于 1 且仅等于 1。如果我们不确定 X0 = 1 呢?
不确定性在符号系统中具有挑战性
考虑两个 MNIST 图像比较的例子(见上文)。给定使用归纳一阶逻辑编程的小训练示例,我们可以分别容易地学习和概括操作

Figure 12: Logical clause for the < operation
Basically, X is a number and Y is a number; Y is greater than X if there is a number Z, where Z is a successor of Y and X is a successor of Z. But what if the inputs X and Y for this system are images and not numbers, and we want first to recognize the digits of X and Y and then apply the clause in Figure 12?
How can that be done with symbolic AI? Suppose the digit image dimensions are 5 x 5, so we have 25 Boolean inputs. Then, the binary images of the two digits 0,1 are as follows:

and the the expressions for 0 and 1 are:

Other digits from 2 till 9 can be represented in the same way. By using these expressions we can recognize the digit in the image first and then apply the clause in Figure 11. But what if the training set consists of non binary images and the digits are ambiguous as in Figure 13, then the symbolic solution will become much more complex to find and to generalize, while a statistical machine learning approach would do the job much better.

Figure 13: Ambiguous image of digit 0
Summary:
I introduced a brief comparison between statistical and symbolic machine learning, which I referred to as 直观和符号系统。每个系统的优点和缺点都已经介绍过了,并可以在下表中进行总结:

最近,有很多研究来克服直觉和符号系统的局限性。大多数提出的技术结合了两个系统的特征来实现目标。在接下来的部分中,我们将介绍这些旨在弥合符号人工智能和统计人工智能之间鸿沟的技术。
最后,我将以下面的论点来结束这一部分:
为什么 4 比 5 小?你可以用你的符号系统很容易地解释原因(例如,因为 5 = 4+1,或者 5 是 4 的后继者)
现在如果我问你为什么你现在看到下面的数字 4,你能回答吗?不,因为这是我们直觉系统的作用。
敬请期待!
“可解释的人工智能”:谁为我们做决定?

作者:詹法纳,皮卡罗齐,迪塞科
2016 年 3 月,谷歌开发的围棋软件 AlphaGo 击败了韩国冠军 Lee Sedol,取得了历史性的成绩(这是计算机首次击败围棋九段棋手),在人工智能(AI)领域的从业者中引起了很大的兴趣和反响。
学术界和大众媒体已经说了很多来解释这一事件的规模,围棋游戏是出了名的“计算复杂”,对计算机来说,比国际象棋复杂得多,它很难用技术来解决,这些技术在 90 年代末深蓝(IBM)与国际象棋冠军卡斯帕罗夫的历史性胜利中取得了成功。
但对我们来说,这是 AlphaGo 与 Lee Sedol 的第二场比赛中的第 37 步,这是计算机获胜的决定性一步,围棋冠军范辉随后评论道:“这不是人类的举动,我从未见过人类下这样的棋”。没有人能够理解或解释这一制胜之举背后的策略,给它一个合理的解释。
柏林大学机器学习教授克劳斯-罗伯特·穆勒致力于改善乳腺癌诊断的人工智能技术。穆勒教授还开发了一个名为“分层相关性传播”(LRP)的程序,该程序分析并解释了各种人工智能系统做出的决定。作为一项测试,穆勒将 LRP 应用于两个软件程序,这两个程序专门用于识别庞大图像库中的马图像。这两个应用程序都在图像识别方面产生了很高的性能,令人惊讶的结果是,LRP 已经表明,虽然其中一个应用程序专注于一匹马的显著特征,但另一个应用程序识别出了这些马,因为一组公共的版权像素存在于所使用的档案中包含的所有马的图像中,所以纯属偶然。结果是难以区分的,但是如果没有 LRP,我们永远不会知道这两个项目中的一个是通过应用完全没有根据的标准来工作的。
围棋第三十七步棋和马图像识别的例子看起来可能相当琐碎,但允许我们将一个正变得至关重要的话题具体化。最后一代人工智能代理是“黑匣子”,对我们的理解是不透明的,通常不允许我们了解它们如何做出某个决定或某个选择。当它处理识别马匹或玩围棋时,这不是非常重要,但如果人工智能应用于不同的学科(医学、法律或金融领域),就对人的实际影响而言,它就变得必不可少;我们能接受一个癌症的诊断,却没有得到一个最低限度的解释,说明是什么因素导致了这个结论吗?或者在抵押贷款时遭到拒绝,却不知道哪个参数是关键因素?
在进一步发展这个主题之前,让我们后退一步,试着更好地理解像 AI 或机器学习这样的词的含义,这些词在公共语言中强有力地出现,但可能充满歧义和误解。
现代意义上的“人工智能”研究的诞生(不用追溯到希腊神话中的巨人青铜机器人塔罗斯的诞生)可以追溯到 1950 年 a .图灵的基础工作“计算机器和智能”,其中图灵测试被定义为机器与人类相比的智能的条件和衡量标准。
当时,这些研究导致了第一个“专家系统”的诞生,如著名的 ELIZA 软件,它能够与人进行基本的对话。这种方法是符号推理,即将一个知识领域转化为符号,并为机器提供一个推理引擎,该引擎具有处理符号以得出结论的所有规则。
尽管有一些有希望的结果,但最初的热情之后是对专家系统进一步发展的可能性的深刻幻灭,对知识的完整描述的“蛮力”方法和对所有选择树的算法探索被证明是不切实际的,并导致了所谓的“人工智能冬天”时期,冬天的特点是投资削减。转折点发生在 90 年代末和新千年初之间,在这期间,大量数据和巨大计算能力的同时可用性导致了基于机器学习技术的人工智能的现代意义。
基本上,我们不是试图描述知识,教人工智能如何操纵符号来解决问题,而是改变了我们的方法,专注于机器的学习能力,利用对巨大数据库的训练:如果我想教机器如何识别一只猫, 我不会向机器提供猫是什么的抽象描述,但我可能会提供大量代表猫的图像,人工智能系统将被构造为识别另一只不在它被训练的图像数据库中的猫(机器学习)。
所有正在成为我们日常生活一部分的人工智能系统,如手机上的 Siri,作为家庭助手的 Google Home,玩 Jeopardy 或提供医疗建议的 Watson,都是这个新的人工智能系统家族的一部分,它诞生于 2000 年初出现的新一轮机器学习和后续深度学习(基于神经网络的机器学习的进一步发展)的研究
但是,将这些代理视为“智能”系统是正确的吗?普通的叙述和耸人听闻的地方倾向于这样定义他们,但问题并不那么简单。Watson 和 Siri 专门解决特定问题,它们应该在“弱人工智能”范围内得到适当考虑,即在没有适当的进一步编程和没有人类特有的认知功能:意向性和意识的情况下,代理解决特定领域的特定问题,而没有扩展到其他领域的可能性。所有这些系统都被认为是属于“弱人工智能”,因此在“类似于”人类智能这个词的特定含义中,它们并不智能。与“弱人工智能”相反,我们应该考虑“强人工智能”,即试图实现一个智能代理,与人类在相同情况下表现出的行为没有区别。
“强 AI”一词是在塞尔 1960 年的工作和著名的名为“中国房间”的心智实验的背景下诞生的。假设我们创造了一个智能体,它会表现得好像懂中文一样;这意味着代理运行一个程序,该程序允许处理接收到的输入(中文字符),从而提供中文答案,并通过一个假设的图灵测试,该测试与理解中文并回答相同问题的人没有区别。我们会说这个人工智能真的懂中文吗?
关于这个话题的辩论是广泛的,没有穷尽的,但最明显的答案似乎是最受认可的:人工智能操纵符号,表现得好像它理解中文,但没有“真正”的理解,语法与语义不一致,意向性和意识对人工智能来说仍然是非常遥远的目标。
前景开始变得更加清晰:没有人类意义上的智能机器,但弱人工智能的爆发产生了大量人工智能,这些人工智能正在改变人类的习惯,并渗透到金融、医药等关键领域,帮助我们做出决策。
所以,让我们回到最初的问题:我们能理解基于神经网络和深度学习的新人工智能代理的决策背后的基本原理吗?
答案通常是否定的,与基于符号推理的第一代系统不同,当前的机器学习不允许我们理解人工智能体如何执行分配的任务:智能体能够识别猫,但我们不知道它遵循什么特征和模型来做这件事,这不是算法,智能体是一个黑盒,对我们的理解是“不透明的”。
从我们简短的题外话中,我们现在可以更好地理解人工智能系统在最多样化的领域(从医学到金融,从自动驾驶系统到军事防御)的大规模传播中出现的困难和严峻问题。
我们完全知道指导这些代理人设计的原则,但同时我们也意识到不可能“逆向”理解导致系统本身从最不相关的情况到最激烈的军事冲突的决定的原因和理由。
所谓的“可解释的人工智能”(XAI)产生于对人工智能系统提出的建议、解决方案或决定之后的问题给出答案的意识和需求:代理人是基于什么决定以这种方式而不是另一种方式进行的?没有任何答案,就不可能有对 AI 的任何信任。
已经提到的 LRP 系统或由 DARPA(美国国防高级研究计划局)进行的研究活动就是例子,其中的目标是实现人工智能系统的可解释性,而不影响学习阶段的性能。
关于数据处理和安全的新法律法规,如 2018 年 5 月 25 日开始的欧洲 GDPR,进一步放大了“可解释的人工智能”的重要性。GDPR 使不透明人工智能系统的应用变得极其困难,因为 GDPR 要求自动化系统的每个决定都具有可追溯性(第 22 条),重申每个主体都有权获得关于智能系统所做的对其有影响的决定的解释。
不同的国家也在相应地变化。举个例子,我们来想想 2018 年 4 月的文件“ AI 在英国:准备好了,愿意了,有能力了?”英国上议院研究人工智能领域的机遇和开放问题,特别关注讨论的“可解释性”。在这种情况下,如果没有深入的多学科方法和进一步采用人工智能的强大障碍,加速研究以解决可能难以弥合的法律空白可能是合适和有用的。
参考文献:
喷宁,d(2017)。 可解释的人工智能(XAI)【在线】。(网址:https://www.darpa.mil/attachments/XAIProgramUpdate.pdf))(上次访问时间 2018 年 5 月)。
上议院 (2018)。英国的 AI:准备好了,愿意了,有能力了?【在线】。(网址:https://publications . parliament . uk/pa/LD 201719/LD select/ldai/100/100 . pdf))(上次访问时间 2018 年 5 月)。
塞尔,j . r .(1980)。头脑、大脑和程序。行为和脑科学 3(3):417–457
图灵,m . a .(1950)。计算机器和智能,心智,49:433–460
可解释的人工智能(XAI)在 DARPA 的议程上——为什么你应该关注

Explainable Artificial Intelligence — DARPA
当 DARPA 决定资助一项计划时,我们马上就能确定几件事。
- 这是个大问题
- 解决这个问题具有巨大的潜在影响——通常对地球上的每个人都是如此
DARPA 的 XAI 计划是任何对数据科学感兴趣的人都应该关注的计划,不仅因为它的未来影响,还因为它们雄辩地阐述了数据科学中最普遍的挑战之一。可解释性是一个容易被掩盖的问题,尤其是当人工智能处于一个主要的炒作周期中时——但它是人工智能/人工智能实现的致命弱点。https://www . DARPA . mil/program/explaible-artificial-intelligence

DARPA XAI Industry Presentation
这张来自 DARPA 可解释人工智能(XAI)计划的图表是我见过的最好的图表,它有助于透视数据科学家每天面临的困境,当他们被赋予提供准确预测和见解的双重任务时。我们人类认为,为了准确预测一个复杂系统的结果,我们必须了解这个系统的一切。然而,我们不能用同样的过程来告诉我们为什么事情是这样的,就像我们告诉我们最有可能的结果是什么一样。最复杂的模型(如深度学习)可能惊人地准确,但复杂性阻止我们知道为什么机器/算法选择了一个结果而不是另一个。随着时间的推移,DARPA 和其他致力于 XAI 的组织将帮助改变这种情况,但目前,任何自称为人工智能并承诺“最准确的结果和改变游戏规则的见解”的技术都需要健康的怀疑态度。这并不是说 AI/ML 不能成为一个成功的洞察程序的一部分——它绝对可以成为,但是回答为什么的算法/机器将与告诉你下一步做什么(预测)的算法/机器非常不同。
可解释的困境——过去&现在
向非技术利益相关者解释复杂模型的结果一直是应用数据科学中最困难的部分之一。大多数组织的现实是,如果一个模型的结果不能直观地向领导层解释,那么它将永远不会被部署——因此组织将永远不会从中受益。这从一开始就给数据科学家制造了一个难题。一般来说,最准确的模型也是最难解释的,数据科学家长期以来一直面临着决定是使用易于解释的不太准确的技术还是难以或不可能解释的稳健技术的挑战。这个问题随着人工智能/人工智能的发展而变得更加复杂,人工智能/人工智能可以创建非常精确的模型——但几乎不可能解释它们是如何得到答案的。当面临创建准确预测和提供见解的双重任务时,迄今为止最好的选择实际上是通过使用不同技术构建多个模型来重复工作,并希望更粗糙的技术有助于支持稳健模型的结果。当然,这本身就产生了一系列潜在的问题——包括流程效率和相互矛盾的结果。
下一步是什么?
解决问题的第一步是承认你有问题,虽然 DARPA 正在揭示这个突出的问题,但围绕人工智能的繁荣似乎让许多投资者和从业者对可解释性问题视而不见。这是炒作周期的一部分——当炒作转向幻灭时,那些不关注它的人将会哀叹人工智能的失败。但是那些关注世界卫生组织的人会做出更明智的决定,不仅会用当前的人工智能范式做出更明智的决定,还会准备好从 XAI 的进展中受益。这项倡议的结果不仅是真正的人工智能,而且副产品将是实时评估自学算法的新技术。
可解释的人工智能(XAI)研究必须超越实验室的四面墙
XAI 的四个主要利益相关者。
65 岁的埃莉诺想给她唯一的外孙蒂姆买辆车,再过几个月他就 21 岁了。她想送他一辆车,这样他可以相对舒适地去参加工作面试,而不是坐公交车。
埃莉诺去 XYZ 银行申请一万美元的贷款。她在和一个叫柯比的同事通话。Kirby 邀请 Eleanor 填写贷款申请。填完表格后,Eleanor 提交了申请新信用额度的请求。Kirby 将她的详细信息输入软件,然后信息被发送到一个黑盒模型。这个模型发挥了它的魔力,立即把它的决定反馈给 Kirby。他惊愕地看着埃莉诺,顿时,她的心直落地面。她马上就知道了;她的贷款请求没有通过。她问 Kirby 拒绝的原因。不幸的是科比不知道。他告诉她,“数学模型做决定,我们听它的。”
Kirby 被他所目睹的一切伤透了心,他冲向数据科学团队。他请他们给他一些关于黑箱模型如何决策的见解。数据科学团队看着他说,“嗯……这有点难以解释……”。Kirby 进一步催促他们,他们同意分析模型的决定,在这个过程中,他们了解到一些令人震惊的消息——黑箱模型对 65 岁以上的人有偏见!他们回到绘图板,重新构建、重新训练、重新测试和重新部署一个新的没有年龄偏见的黑盒模型。
Kirby 决定重新输入 Eleanor 的贷款申请信息,看看她的贷款请求是否会得到新的和改进的无偏见模型的批准。这个模型产生了同样的结果——被拒绝。
但是这一次,他也得到一个影响模型的关键因素的排序列表。排名列表是数据科学团队解决模型可解释性的一次尝试。列出的前两个因素是—“信用评分(65%)”和“现有信用额度数量(22%)”。百分比数字是因子对模型结果的相对重要性。Kirby 打电话给 Eleanor,告诉她为什么她的申请被拒绝了。Eleanor 对 Kirby 的电话表示感谢,并决定采取积极措施帮助她给 Tim 弄辆车。埃莉诺了解到,她的信用评分是决定她贷款申请被接受还是被拒绝的一个重要因素。她把下个月的财务管理得很好。一个月后,埃莉诺查看了她的新信用评分,发现它奇迹般地上升了 27 分。她前往 XYZ 银行再次尝试。柯比敲击着键盘,敲击着,敲击着,敲击着,他的脸沉了下来。
被拒。
又来了。
科比和埃莉诺都感到震惊。尽管她的信用评分奇迹般地提高了,但对她贷款请求的决定仍然没有改变。埃莉诺苦恼地问科比,“我需要增加多少信用评分才能被录取?”。柯比困惑地说,“我很抱歉,埃莉诺。我不知道……”
上面的故事说明了几点:
- 对于数据科学和业务团队来说,不理解模型的决策过程是不可接受的。
- 提供一份影响因素的排名表是不够的。
- 数据科学家和人工智能研究人员 绝不能 孤立工作。
科学家和商业团队之间必须有强有力的合作。
在这个故事中,XAI 的三个利益相关者被清晰地定义了。让我们来理解为什么这些利益相关方对 XAI 至关重要:
- 数据科学家/人工智能研究人员:他们需要对模型的工作有一个坚实的理解。他们需要以下问题的答案—模型输出有意义吗?这些解释有意义吗?模型是否有偏差?
- 业务团队/非技术用户:银行职员、经理、高管、医生、律师、法官、警察等等都属于这个群体。这些人需要知道如何将模型解释用于商业目的。更重要的是,他们需要相信模型遵守监管准则。最后,如果解释不合理,那么他们可以利用他们领域的专业知识来改进它。
- 消费者:消费者是产品和服务的接受者。让消费者看到全貌是至关重要的。这让他们有能力采取下一个最好的行动。只有在模型解释清晰透明的情况下,他们才会信任企业。消费者的参与确保了以最简单的形式交付解释。解释需要简单明了,即使是祖父母也必须能够在没有帮助的情况下消化这些信息。
到目前为止,我们已经讨论了 XAI 对三个关键利益相关者的重要性。然而,还有一个至关重要的第四利益相关者,他有能力促成必要的合作。第四个重要的利益相关者是决策者。他们在推动 XAI 朝着正确的方向发展方面发挥着关键作用:
- 就 XAI 的构成要素向业务部门提供指导—类似于货币监理署(OCC)为金融机构反洗钱计划中使用的模型编制的风险管理文件范本[ 19 ]。
- 确保对消费者的保护——消费者有权获得模型决策过程背后的清晰和全面的推理。GDPR 是一个很好的例子——特别是它强调来自组织的“易于理解和访问”的隐私声明[20]。

Figure 1: XAI stakeholders and their attributes.
目前 XAI 的大部分研究都是在实验室里进行的。本地可解释的模型不可知解释(LIME) [ 1 ], SHAP(沙普利附加解释) [ 2 ]和模型不可知监督本地解释(MAPLE) [ 3 】是帮助模型可解释性的开源库的例子。我相信这些库是为技术观众服务的。图 2 显示了一个例子。这些模型提供的解释可能是 XAI 之谜的一部分。如果一个真实世界的应用程序位于 XAI 研究的中心,那么我坚信这项研究将更接近于帮助真实世界的场景。这种研究将促进 XAI 主要利益攸关方之间的合作。

Figure 2 (a): Visual created by the SHAP library. It shows the influence of the factors resulting in the model output 24.41. Model is trained to predict the median value ($1,000s) of a home in Boston [14]. (b): Visual created by the LIME library. It shows the influence of the factors resulting in the model output Poisonous with a probability value of 1.0. Model is trained to predict the likelihood of a mushroom to be poisonous or edible [15].

Figure 3: Anchor is another open-source library for model interpretability. It’s developed by the same author of LIME [8]. It generates rule sets to explain the model output. A model was trained to predict if a person will earn more or less than $50,000 [16]. Anchor definitely does a better job in explaining the model output.
2018 年,FICO 共同赞助了可解释的机器学习(xML)挑战赛【4】。这对 XAI 社区来说是一个巨大的挑战。它允许研究实验室在现实世界中应用来测试他们的理论。IBM Research 赢得了比赛【5】。他们明白迎合不同利益相关者的重要性(试试他们的演示吧!).XAI 必须是面向不同受众的工具。

Figure 4: Screenshot of IBM AIX 360 Demo [17]. Model is trained to predict whether to accept or reject a credit application. I selected the Bank Customer to be the entity of interest. The explanation is quite informative. After reading this report, the Bank Customer, in this case, Julia has all the information she needs to get accepted the next time she applied for credit approval.
此外,我很欣赏杜克大学辛西娅·鲁丁实验室的研究人员提交的作品【6,10(t展示他们的演示!).他们获得了 FICO 认可奖,以表彰他们凭借完全透明的全球模型和用户友好的仪表板超越预期,让用户能够探索全球模型及其解释[ 5 ]。我关注辛西娅·鲁丁关于模型可解释性的工作已经有一段时间了。她对模型的可解释性有独特的方法。她的实验室建立了简单而有效且可解释的模型(在准确性上可与黑盒模型相媲美!).她认为你不需要为了准确性而牺牲模型的可解释性。然而,随着世界朝着快速采用深度学习的方向发展,看到她的研究在未来将她带向何处将是一件有趣的事情。我推荐在这里看一看她的作品并观看她在 KDD 2019 的主题演讲。

Figure 5: Decision list generated by an interpretable model [13]. The model is trained to predict the likelihood of survival on the Titanic.
随着深度学习在多个行业的采用,对 XAI 的需求与日俱增。为了让 XAI 的研究朝着正确的方向前进,数据科学家和人工智能研究人员走出实验室,与商业团队(包括法官、律师和医生)和消费者合作,并为政策制定者提供建议至关重要。
参考
- 马尔科·图利奥·里贝罗、萨米尔·辛格和卡洛斯·盖斯特林,“我为什么要相信你?”:解释任何分类器的预测(2016),载于第 22 届 ACM SIGKDD 知识发现和数据挖掘国际会议(KDD '16)。美国纽约州纽约市美国计算机学会,1135–1144。https://doi.org/10.1145/2939672.2939778
- Scott M. Lundberg,Su-In Lee,解释模型预测的统一方法(2017),第 31 届神经信息处理系统会议,美国加州长滩。http://papers . nips . cc/paper/7062-a-unified-approach-to-interpretation-model-predictions . pdf
- Gregory Plumb,Denali Molitor,Ameet Talwalkar,模型不可知论者监督的局部解释(2018),第 32 届神经信息处理系统会议,加拿大蒙特利尔。https://papers . nips . cc/paper/7518-model-agnostic-supervised-local-explaints . pdf
- https://community . Fico . com/s/explaible-machine-learning-challenge
- https://www . Fico . com/en/news room/Fico-announces-winners-of-就职演说-xml-challenge
- http://dukedatasciencefico.cs.duke.edu/
- https://community . Fico . com/s/blog-post/a5q2e 0000001 czy uaa/Fico 1670
- Ribeiro,m .,Singh,s .,& Guestrin,c .,Anchors:高精度模型不可知解释(2018),第 32 届 AAAI 人工智能会议,美国路易斯安那州新奥尔良。https://www . aaai . org/OCS/index . PHP/AAAI/aaai 18/paper/view/16982
- Shrikumar,a .,Greenside,p .,Kundaje,a .,通过传播激活差异学习重要特征(2017),arXiv:1704.02685。
- Rudin,Cynthia 和 Shaposhnik,Yaron,全球一致的基于规则的摘要-机器学习模型的解释:应用于信用风险评估(2019),可在 https://ssrn.com/abstract=3395422或 http://dx.doi.org/10.2139/ssrn.3395422SSRN获得
- Rudin,c .,停止解释高风险决策的黑盒机器学习模型,转而使用可解释的模型 (2019),【在线】可在:【https://www.nature.com/articles/s42256-019-0048-x.epdf? 获得 author _ access _ token = SU _ TpOb-h 5d 3 uy 5 KF-dedtrgn 0 jaj wel 9 jnr 3 zotv 0m 3t 8 udwhdckrosbuooygdb 5 knhqmo _ ji2d 1 _ sddjvr 6 hjgxjxc-7 JT 5 fqzuptqkiakzboti 4 uqjwnzbltd 01 z 8 qwhwksbvwh-z 1 XL 8 bacg % 3D % 3D【2019 年 8 月 31 日访问】。
- 王童和辛西娅·鲁丁以及终曲·多希-维勒兹和刘一民以及埃里卡·克兰弗尔和佩里·麦克尼尔,《用于可解释分类的学习规则集的贝叶斯框架》(2017 年),《机器学习研究杂志》18(2017)1–37。【http://www.jmlr.org/papers/volume18/16-003/16-003.pdf
- 本杰明·勒撒姆;辛西娅·鲁丁;泰勒·麦考密克;Madigan,David,使用规则和贝叶斯分析的可解释分类器:建立更好的中风预测模型(2015),Ann。应用统计。9 (2015)第 3 号,1350–1371。doi:10.1214/15-AOAS848。https://projecteuclid.org/euclid.aoas/1446488742
- https://github . com/slund Berg/shap # tree-ensemble-example-with-tree explainer-xgboostlightgbmcatbootscikit-learn-models
- https://marcotcr . github . io/lime/tutorials/tutorials % 20-% 20 continuous % 20 and % 20 category % 20 features . html
- https://github . com/marcotcr/Anchor/blob/master/notebooks/Anchor % 20 on % 20 tabular % 20 data . ipynb
- http://aix360.mybluemix.net/data
- 李普顿,Z. C .,模型可解释性的神话(2016),arXiv:1606.03490。
- https://www . OCC . treas . gov/news-issues/bulletins/2011/bulletin-2011-12a . pdf
- https://gdpr.eu/privacy-notice/
面向医疗保健的可解释机器学习
理解医疗保健中的机器学习

机器学习在医疗诊断等医疗保健领域有着广泛的应用[1]。癌症研究中经常使用的数据集之一是威斯康星州乳腺癌诊断(WBCD)数据集[2]。与其他领域一样,医疗保健中使用的机器学习模型在很大程度上仍然是黑箱。如[3]中所述,如果医生计划根据诊断预测采取癌症治疗措施,了解机器学习模型预测背后的原因对于确定信任非常重要。这种理解也可以帮助具有领域专业知识的医生发现机器学习模型预测的错误。这可以通过不同的方法实现。其中一种方法叫做“可解释的机器学习”[4]。
在本文中,我使用 WBCD 数据集[2]来演示如何实现可解释的机器学习,以使不可信的预测变得可信。
1.可解释的机器学习
如[4]中所述,本文中可解释的机器学习指的是用于理解预训练模型预测的事后分析和方法。有不同的事后方法,如原因代码生成、模型预测的局部和全局可视化等。[4].在本文中,我使用原因代码生成作为事后方法。特别地,局部可解释模型不可知解释(LIME) [3]用于解释机器学习模型使用哪些特征来做出预测决策。
2.数据集准备
如前所述,本文中使用的数据集是公共 WBCD 数据集[2]。在该数据集中,为每个样本提供了以下 9 个特征,并将用作机器学习模型的输入:
- 团块厚度
- 细胞大小的均匀性
- 细胞形状的均匀性
- 边缘粘连
- 单一上皮细胞大小
- 裸核
- 平淡的染色质
- 正常核仁
- 有丝分裂
2.1 加载数据
假设 WBCD 数据集已经作为 csv 文件乳腺癌-威斯康星. csv 下载到本地计算机上,那么数据集文件可以加载到熊猫数据帧中,如下所示:
feature_names = ["CT","UCSize","UCShape","MA","SECSize","BN","BC","NN","Mitoses"]
columns = ["ID"]
columns.extend(feature_names)
columns.extend(["Diagnosis"])
raw_data = pd.read_csv('breast-cancer-wisconsin.csv', na_values='?', header=None, index_col=['ID'], names = columns)
raw_data = raw_data.reset_index(drop=True)
raw_data.head(10)

2.2 数据预处理
WBCD 数据集有许多共同的问题,因此需要预处理来解决这些问题,然后才能被机器学习模型使用。
- 缺失数据
以下命令用于检查哪些要素缺少数据:
data = raw_data.copy()
data.isnull().sum()

如上表所示,有 16 个裸核缺失数据条目。在本文中,这些缺失的数据条目简单地用 0 替换,因为缺失条目的总数相对较小。
- 小规模数据集
WBCD 数据集[2]只包括 699 个样本,这对机器学习来说太小了。这种小数据量问题可以通过数据扩充来缓解(有关详细信息,请参阅不平衡数据集)。
- 不同尺度的特征值
不同特性的取值范围不同。下面的类尺度是将特征值变换到相同的范围【0,1】内。这个类被设计成可以和其他类一起使用,在以后形成一个管道。
from sklearn.preprocessing import MinMaxScaler
from sklearn.base import BaseEstimator, TransformerMixinminMaxScaler = MinMaxScaler()
minMaxScaler.fit(features[feature_names])class Scale(BaseEstimator, TransformerMixin):
def __init__(self):
pass def fit(self, X, y=None):
return self
def transform(self, X, y=None):
if type(X) == pd.Series or type(X) == pd.DataFrame:
X1 = X.values
X1 = X1.reshape(1, -1)
else:
X1 = X.copy()
X1 = minMaxScaler.transform(X1)
return X1
- 不平衡数据集
以下代码用于检查数据集在标记的诊断值方面是否平衡:
data['Diagnosis'].value_counts()
不同标签的数据样本数量不平衡。有 458 个数据样本被标记为 2(即 B(良性)),但是只有 241 个数据样本被标记为 4(即 M(恶性))。
为了平衡数据集,为简单起见,将标记为 M 的 241 个数据样本的副本添加到原始数据集中。
- 倾斜数据集
以下代码可用于可视化特征值的分布:
data[numerical].hist(bins=20, figsize=(15, 10))

可以看出,大多数特征的值明显向右倾斜。下面的类 Sqrt 通过对特征值求平方根来缓解数据偏斜问题。像 Scale 类一样,这个类被设计成一个管道组件。
class Sqrt(BaseEstimator, TransformerMixin):
def __init__(self):
pass def fit(self, X, y=None):
return self
def transform(self, X, y=None):
if type(X) == pd.Series or type(X) == pd.DataFrame:
X1 = X.copy()
if X1.isnull().values.any():
X1 = X1.fillna(0)
X1 = X1.abs() # avoid negative values
else:
X1 = X.copy()
X1 = np.absolute(X1) # avoid negative values
X1 = np.sqrt(X1)
return X1
2.3 将标签与特征分离
标签(即诊断)与特征分离,因为标签和特征是模型训练和测试所需要的。
labels = data['Diagnosis']
features = data.drop(['Diagnosis'], axis = 1)
2.4 将数据集分为训练数据集和测试数据集
特征和标签被随机分成两部分,75%用于模型训练,25%用于模型测试:
from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(features, labels, test_size=0.25, random_state=42)
3.机器学习模型
具有默认设置的随机森林分类器用于演示目的。模型训练和测试可以如下执行:
from sklearn.ensemble import RandomForestClassifierrfc = RandomForestClassifier(n_estimators=100)
rfc.fit(X_train, y_train)
score = rfc.score(X_test, y_test)
训练后的模型准确率达到 98.23%。
4.解释预测的石灰法
如[3]中所述,在通过机器学习模型进行决策时,确定个体预测的可信度非常重要。例如,当机器学习用于医疗诊断时,如威斯康星州乳腺癌诊断[1],预测不能简单地用于行动,因为后果可能是灾难性的。本节展示了如何使用 LIME [3]为个人预测提供解释,作为确定信任的解决方案。
4.1 创建管道
LIME 中原因代码生成背后的关键点是将模型预测结果与原始的未转换特征值相关联。为此,LIME 方法在解释模型预测结果时,将机器学习管道(包括位于管道开头的数据预处理管道和位于管道末尾的机器学习模型)作为输入。以下管道将用于此目的:
from sklearn.pipeline import make_pipelinescale = Scale()
sqrt = Sqrt()
# rfc is a pre-trained Random Forest modelmachine_learning_pipeline = make_pipeline(scale, sqrt, rfc)
4.2 选择石灰解释器
LIME 方法支持不同类型的机器学习模型解释器,用于不同类型的数据集,如图像、文本、表格数据等。本文选择表格解释器,因为 WBCD 数据集的格式是表格:
from lime.lime_tabular import LimeTabularExplainerclass_names = ['Benign', 'Malignant']
explainer = LimeTabularExplainer(feature_names=feature_names,
class_names=class_names,
training_data=X_train.values)
4.3 解释模型预测
一旦机器学习模型已经被训练,给定原始特征值的任何向量(即,特征向量),下面的解释函数可以用于解释模型预测:
def explain(feature_vector, label=1): # feature_vector - a Pandas Series of features
exp = explainer.explain_instance(feature_vector, machine_learning_pipeline.predict_proba, num_features=9)
fig = plot(exp, label)
exp.show_in_notebook(show_table=True, show_all=False)
LIME explainer 的 show_in_notebook ()方法以笔记本的形式展示了预测和对应的原始特征值之间的关联。
下面的图功能是创建一个条形图来显示石灰模型解释结果:
def plot(exp, label=1):
exp_list = exp.as_list()
fig = plt.figure()
vals = [x[1] for x in exp_list]
names = [x[0] for x in exp_list]
vals.reverse()
names.reverse()
colors = ['green' if x <= 0 else 'red' for x in vals]
pos = np.arange(len(exp_list)) + .5
plt.barh(pos, vals, align='center', color=colors)
plt.yticks(pos, names)
if exp.mode == "classification":
title = 'Local explanation for class {}'.format(exp.class_names[label])
else:
title = 'Local explanation'
plt.title(title)
return fig
例 1:解释恶性肿瘤的预测
以下是 M(恶性)的一个样本(特征向量):
sample_M = raw_data.loc[5, feature_names]
该特征向量的预测结果可以使用 LIME 解释如下:
explain(m_feature_vector, machine_learning_pipeline, label=1)

恶性的预测结果如上图左上角所示。右上角和底部显示哪些特征与恶性的预测正相关,哪些特征与恶性的预测负相关。特别地,橙色/红色的特征表示正相关,而蓝色/绿色的特征表示负相关。
例 2:解释良性预测
以下是 B(良性)特征向量的示例:
sample_B = raw_data.loc[1, feature_names]
该特征向量的预测结果可以由 LIME 解释如下:
explain(sample_B, machine_learning_pipeline, label=0)

良性的预测结果如上图左上角所示。右上角和底部显示哪些特征与恶性的预测正相关,哪些特征与恶性的预测负相关。特别地,橙色/红色的特征表示正相关,而蓝色/绿色的特征表示负相关。
5.结论
在本文中,我使用了 LIME 方法[3]和 WBCD 数据集[2]来演示如何解释机器学习模型在乳腺癌诊断中的预测结果。
正如本文开头所述,如果医生计划根据诊断预测采取癌症治疗措施,那么理解机器学习模型预测背后的原因对于评估信任非常重要。这种理解还可以帮助具有领域专业知识的医生检测机器学习模型预测的错误,以便可以进一步改进正在使用的机器学习模型。
Github [6]中有一个 Jupyter 笔记本,上面有本文中的所有源代码。
参考
[1] 威斯康星州乳腺癌诊断数据集
[2] WBCD 数据集和描述
[3] M. T. Ribeiro,S. Singh,C. Guestrin,“我为什么要相信你?”
解释任何分类器的预测
[4] P. Hall 和 N. Gill,《机器学习可解释性导论》,《从应用角度看公平、问责、透明和可解释的人工智能》,第二版,奥赖利媒体公司,2019 年
[5] M. T. Ribeiro,S. Singh 和 C. Guestrin,局部可解释模型不可知解释(LIME):介绍
[6]黄宇,Jupyter 笔记本在 Github
披露声明:2020 年。本文中表达的观点仅代表作者的观点,不代表阿贡国家实验室的观点。
解释:Tensorflow 中的深度学习—第 0 章
关于深度学习的一切
介绍

我想人们喜欢阅读那些他们最想要而经历最少的东西。伯纳德·洛(西部世界)
你猜怎么着?开始这个系列。该系列说明了深度学习。 ML / DL !嗯。实际上, DL 与 ML 并无不同,但 DL ( 深度学习)是 ML ( 机器学习)的一个子领域,关注的是被称为人工神经网络( ANN )的大脑结构和功能所启发的算法。由于神经元是大脑的基本工作单位,它也是神经网络中的基本计算单位。
神经网络体系结构
我们将在这里直接讨论神经元。

Neuron — the basic unit of the neural network
不讨论神经元的生物学类比,直接来理解人工神经元。顺便说一下,在人类神经系统中可以找到大约 600-1000 亿个神经元,它们与大约 10 个⁴ -10 个⁵突触相连。:)作为人工神经网络的基本构件的神经元接收该特征作为输入,并在进行如下计算后产生输出:

Neural Network Computation: Explained
重要术语
- 输入特征向量(X): 输入数据集的特征有助于得出关于某一行为的结论。它可以是热编码、嵌入等。
- 权重和偏差(W & B) :一般来说权重,w1,w2,…都是实数,表示各自输入对输出的重要性。偏差是添加到输出中的额外阈值。
- Loss (L) : Loss 是一个目标函数,表示预测与原始结果有多接近。它也被称为成本函数。作为训练机制的目标总是最小化这个成本函数的值。换句话说,我们希望找到一组权重和偏差,使成本尽可能小。有几个损失函数作为回归问题中流行的均方误差(MSE ),分类问题中流行的分类或二元交叉熵。
- 优化器:这些用于通过更新权重和偏差来最小化损失函数。随机梯度下降法是一种流行的方法。这里的是对优化者的一个很好的解释。
- 激活函数:激活函数通过计算加权和并进一步加上偏差来决定是否激活一个神经元。但是,我们为什么需要激活功能呢?答案是:如果我们把几个线性变换串联起来,得到的只是一个线性变换。例如,如果来自相邻层两个神经元中的 f(x) = 2x+3 且 g(x) = 5x-1。然后,链接这两个将给出线性函数,即 f(g(x)) = 2(5x-1)+3。所以,如果我们没有层间的非线性,那么即使是很深的一叠层也相当于一个单层。激活功能的目的是将非线性引入神经元的输出。ReLU(校正线性单元)是使用最广泛的激活函数。
- 学习率( η ) :是每次更新时权重和偏差应该变化的速率。

通过调度找到最优 LR 有几种方法:功率、Icycle 和指数调度。其中一种方法是对模型进行数百次迭代训练,将 LR 从非常小的值指数增加到非常大的值,然后查看学习曲线,选择略低于学习曲线开始回升时的学习速率。如左侧的 LR 与损耗曲线所示,1/10 左右是最佳 LR。
前馈神经网络
"本质上,所有的模型都是错误的,但有些是有用的."乔治·博克斯;诺曼·r·德雷珀(1987)。
当一个以上的神经元相互堆叠时,其中单元之间的连接不也不形成循环,则它形成单层密集神经网络。当一个或一个以上的层彼此平行布置时(可以具有不同数量的神经元单元),其中一个层分别是在开始和结束处的输入和输出层,而另一个层是这两个层之间的隐藏层,使得信息(从每个神经元输出)仅在一个方向上移动,从输入节点向前,通过隐藏节点(如果有的话)到达输出节点,这被称为前馈神经网络。如果只有输出层出现在一个人工神经网络中,那么它被称为单层 FFNN,如果它包含隐藏以及输入和输出层,它被称为多层 FFNN。

Multi-layer ANN
人工神经网络中的参数数量
参数的数量意味着在整个神经网络中使用的权重和偏差的总数。因为在每一层,权重矩阵被生成和更新,其维数是 Rm*n,如上所述,并且偏差也随着每个输入而增加。因此,参数的总数将是每一层的权重和偏差的总和。公式结果是:
如果 I 是输入的数量,H = {h1,h2,h3..hn}是隐藏单元的数量,o 是输出的数量。然后,


Source: FFNN with 1 hidden layer
对于左侧的例子,
#model in Keras
model = Sequential()
model.add(Input(3))
model.add(Dense(5))
model.add(Dense(2))
i=3,o=2,H = {5}
因此,参数总数= (35 + 52) + (5+2) = 32
反向传播
反向传播是指在每次向前传递信息后更新网络中的权重和偏差。在进行预测(正向传递)后,它测量误差,并使用链式法则反向遍历每一层以测量来自每个连接(反向传递)的误差贡献,最后,调整连接权重以减少误差。反向传播的目标是计算成本函数 l 相对于网络中任何权重 w 或偏差 b 的偏导数∂L/∂w 和∂L/∂b。由于 FFNN 是一个由大量神经元组成的非常复杂的体系结构,其中线性回归类问题的解决忽略了具有等式 WX + B 的激活函数,因此我们将使用特征的线性函数作为目标函数来理解反向传播。
设估计的函数为【ŷ】,原始函数为 y 其中二次成本函数( L ):

Target function and Loss function
让我们计算一下lw . r . t .ŷ, w1 , w2 , b 的梯度

Partial derivatives
现在,我们将知道如何使用 SGD 作为优化器来更新权重和偏差:

Finding updated weights and bias: SGD
让我们拿一个数据集,试着理解它的一个迭代,然后我们将遍历代码:
**x1** | 2 | 1 | 3 | -1 | -3
**x2** | 3 | 1 | -1 | 1 | -2
**y** |18 | 10 | 8 | 6 | -7
对于初始化,假设 w1= 5,w2=8,b=-2,η = 0.02

Calculation in the first iteration
更新参数后,让我们看看损耗的变化:

Cost function change
随着我们继续深入并在所有迭代中执行计算,我们将能够找到最接近目标函数的最佳拟合。
在张量流 2.0 中
正如我们所知,Tensorflow 是一个强大的数值计算库,特别是谷歌大脑团队开发的大规模机器学习。让我们了解一下它的基本原理。Tensorflow 的 API 围绕张量、展开,从一个操作流向另一个操作,因此得名 Tensorflow。张量基本上是一个多维数组,就像 Numpy 一样。我们可以定义一个常数张量如下:
tf.constant(2)#<tf.Tensor: id=14998, shape=(), dtype=int32, numpy=2>
tf.constant([[1.,2.],[3.,4.]])
# <tf.Tensor: id=14999, shape=(2, 2), dtype=float32, numpy=
array([[1., 2.],
[3., 4.]], dtype=float32)>
我们可以对张量执行几种运算,如平方、求和、转置等。但是,这里 tf.constant 定义的张量是不可变的,我们不能修改它。所以,我们需要 tf。这种情况下的变量:
#<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=2.0>
a=tf.Variable(2.0)# a values changes to 3.0
a.assign(3.0)#add and subtract the tensor by given value
a.assign_add(2.0) # a => 5.0
a.assign_sub(1.0) # a=> 4.0

让我们看看如何使用 Autodiff 自动计算梯度,以解决上面讨论的问题。我们需要创造一个 tf 的环境。GradientTape 会自动记录每一个操作,最后,它可以告诉梯度。
with tf.GradientTape(persistent=True) as tape:
#initializing the loss function with next set of training set
loss = loss_function(y,x1,x2)
# finding the gradient of loss function w.r.t. w1,w2 and b
gradients = tape.gradient(loss, [w1,w2,b])
这里, gradients 给出了偏导数∂L/∂w 和∂L/∂b,我们需要用它们来更新权重和偏差,方法是将它乘以因子 L.R。让我们来看看如何做到这一点:
Visualizing through tf Code how backpropagation works
我们已经定义了 loss_function ,它将训练集作为输入,随后查找损失函数 w.r.t 权重和偏差的梯度。 update_weight 方法在每次迭代后更新新的权重。正如我们所看到的,新的权重和偏差与我们在上面的反向传播部分手动计算的是一样的。我们运行了 7 次迭代,权重和偏差的值越来越接近实际值[w1=2,w2=3,b=5]。
tf .函数
T F2.0 带来了 tf.function decorator,它将 Python 语法的子集转换成可移植的高性能张量流图。如果它是通过方法注释的,Python 控制流语句和签名会将它们转换成适当的张量流操作。例如,if语句如果依赖于一个Tensor,就会被转换成[tf.cond()](https://www.tensorflow.org/api_docs/python/tf/cond)。注释后,该函数将像 python 中的任何其他方法一样,但它将有助于获得急切执行的好处。例如:
[@tf](http://twitter.com/tf).function
def simple_nn_layer(x, y):
return tf.nn.relu(tf.matmul(x, y))x = tf.constant([[-2,-1],[3,4]])
y = tf.constant([[3,4],[1,2]])simple_nn_layer(x, y)<tf.Tensor: id=15133, shape=(2, 2), dtype=int32, numpy=
array([[ 0, 0],
[13, 20]], dtype=int32)>
结合使用 gradientTape 和 tf.function、也可以在调试方面有所帮助。我们可以看到参数是如何变化的,精度在每次迭代中都受到影响。为此,Keras 模型也可以用在 AutoGraph 代码中。
接下来,do visit 解释:tensor flow 中的深度学习——第一章:关于训练人工神经网络和数据预处理。继续关注空间更多更新。
参考资料:
神经网络和深度学习是一本免费的在线书籍。这本书将教你:神经网络,一个美丽的…
neuralnetworksanddeeplearning.com](http://neuralnetworksanddeeplearning.com/) [## 随机梯度下降线性回归分步教程
这是反向传播演示的补充材料,详细说明了它的计算步骤…
towardsdatascience.com](/step-by-step-tutorial-on-linear-regression-with-stochastic-gradient-descent-1d35b088a843)
书籍:奥雷连·杰龙的《机器学习实践》
一个端到端的开源机器学习平台
tensorflow.org](https://tensorflow.org)
解释:Tensorflow 中的深度学习—第 1 章
关于深度学习的一切
训练神经网络和数据预处理
我们在上一章已经谈了很多关于前馈神经网络的内容。现在,我们将讨论一点张量流,然后,在张量流中实现 FFNN。

TF for DL

Tensorflow 2.0 Architecture
Tensorflow 提供高级 API:Keras 和 Estimator,用于创建深度学习模型。然后,tf.data 等 API 进行数据预处理。在最底层,每个 Tensorflow 操作都是使用高效的 C++代码实现的。大多数时候,我们只使用高级 API,但当我们需要更多的灵活性,如直接处理张量时,我们可以使用较低级别的 API,如 tf.nn,tf。GradientTape()等。Tensorflow 提供了广泛的库,如用于可视化的 TensorBoard ,用于下载和重用预训练模型的 Tensorflow Hub 。它还提供了 Tensorflow 服务,在这里我们可以轻松地将我们的模型公开为 REST API 用于生产。关于 TF 上菜的更多细节。
tf.keras (Keras)
我们先说说在 tf.keras 中实现 FFNN。在 Keras 中,我们可以通过三种方式创建模型:
1。顺序 API
它很容易使用,也很常用于创建线性层堆栈。它提供了 输入层 用于取输入, 密集层 用于创建单层神经网络,内置 tf.losses 用于选择一系列损失函数使用,内置TF . optimizer,内置 tf.activation、等。我们可以创建自定义层、损失函数等。我们很快就会看到。让我们以下面的 FFNN 为例进行说明:

Sample FFNN
上述使用顺序 API 的代码:
#Assuming you can import the module needed from tf.keras
#Creating model object
model = Sequential()#Input layer of shape (3,)
model.add(Input(shape=(3,)))
#Adding dense layers
model.add(Dense(units=4))
model.add(Dense(units=4)) #default activation=linear-> x=max(0,x)
model.add(Dense(units=1, activation = 'softmax'))#defining loss and optimizer
model.compile(loss="mean_square_error", optimizer="sgd")#start training
model.fit(X_train, y_train, epochs=10)
[2。函数 API](https://keras.io/models/model/)
有时,我们需要建立一个具有更复杂拓扑结构或多个输入或输出的神经网络,为此,Keras 提供了函数 API。上面的网络代码在函数 API 中可以看到没有太大的区别:
#Again Assuming you can import the module needed from tf.keras
#Input layer of shape (3,)
input = Input(shape=(3,))
#Adding dense layers
x = Dense(units=4) (input)
x = Dense(units=4)(x) #default activation=ReLU
output = Dense(units=1, activation = 'softmax')(x)
#Keras model specifying input and output
model = Keras.model(inputs=[input], outputs=[output])
#Again follows the same compile, fit, evaluate, predict etc.
3。子类化 API /定制模型
除非您需要涉及循环、条件分支和其他动态行为的模型,否则它不会被广泛使用。简单地子类化模型类,在构造函数中创建你需要的层,并使用它们在被覆盖的 call() 方法中执行你想要的计算。子类化 API 中相同网络的代码:
class FFNN(keras.Model):
def __init__(self, activation="softmax", **kwargs):
super().__init__(**kwargs)
self.input = Input(shape=(3,))
self.hidden1 = Dense(units=4)
self.hidden2 = Dense(units=4)
self.output = Dense(units=1, activation = activation) #override call method
def call(self, inputs):
input = self.input(inputs)
x = self.hidden1(input)
x = self.hidden2(x)
output = self.ouput(x)
return output
#create model instance
model = FFNN()
使模型完美的成分!
1。使用回调
它用于获得模型的最佳可能权重或避免过度拟合。tf.keras 中的 fit 方法将回调作为一个参数,它接受各种范围的回调,甚至我们也可以通过编写一个扩展TF . keras . callbacks . callback .model check point的方法来传递自定义回调,在训练期间以固定的间隔保存模型的检查点。它可以如下使用:
checkpoint_cb = **tf.keras.callbacks.ModelCheckpoint**("model.h5", save_best_only=True)#fit the model with callback
model.fit(X_train,y_train,..., callbacks=[checkpoint_cb])
#load the best model after training
tf.keras.models.load_model("model.h5")
另一个回调称为 提前停止 当一个定义的指标在一定数量的时期(耐心)后停止改进时使用,这将可选地回滚到最佳模型。样本如下:
early_stop_cb = **tf.keras.callbacks.EarlyStopping**(patience=5, restore_best_weight=True)
#train the model with these callbacks
model.fit(..., callbacks=[checkpoint_cb, early_stop_cb])
两个检查点一起使用将保存检查点,并在没有更多进展时提前中断训练。
2。使用张量板进行可视化

Tensorboard
Tensorboard 是一个很棒的可视化工具,在这里我们可以看到训练过程中每一次跑步的标量、图表等。它读取名为事件文件的二进制日志文件来投射数据。事件文件可以通过写回调来生成,即tensor board。它就像编写回调一样简单:
tensorboard_cb = **keras.callbacks.TensorBoard(**logdir, ) #provide a logdir where the event files will be stored
#train the model
model.fit(..., callbacks=[tensorboard_cb])
为了可视化它,您需要通过以下命令启动 TensorBoard 服务器:
tensorboard --logdir = logdir
# this will create a server at 6006 port
或者,您可以将您的活动文件上传到 tensorboard.dev 并从谷歌合作实验室在线观看:
!tensorboard dev upload --logdir ./logs
3。使用 批量规格化 和渐变裁剪
在训练期间,始终存在消失/爆炸梯度问题的风险,批量标准化解决了这些问题。这种技术包括在模型中每个隐藏层的激活函数之前或之后添加操作。它只是通过估计输入的平均值和标准偏差来对输入进行零中心化和标准化。在实现中,Keras 在训练期间通过使用层的输入均值和标准偏差的移动平均值来学习每层的每个输入的四个参数。在 ImageNet 分类任务中使用它时,已经观察到了巨大的改进。在 tf.keras 中,我们需要在每个隐藏层的激活函数之前或之后添加一个 BatchNormalization 层。以上面的例子为例:
model.add(Input(shape=(3,)))
#Adding batch normalization layer
model.add(**tf.keras.layers.BatchNormalization**())
model.add(Dense(units=4)) model.add(**tf.keras.layers.BatchNormalization**())
x = Dense(units=4)(x) #default activation=ReLU
渐变裁剪另一种缓解爆炸式渐变问题的流行技术。这种方法主要在 RNN 使用。它有助于将梯度向量的每个分量剪切到所提供的范围之间的值。例如
model.compile(loss="mean_squared_error", optimizer = keras.optimizers.SGD(**clipvalue=1.0**))
上面的代码将在-1 和 1 之间裁剪损失的偏导数。
4.使用正则化来避免过度拟合
我们已经在上面讨论了一些避免过度拟合的技术,让我们看看其他流行的正则化技术。 L1 和 L2 正则化 涉及向成本函数添加一些数量级的权重。下面是我们如何实现:
Dense(units=4, kernel_regularizer=**keras.regularizers.l2**(0.01))
退出是另一种技术,尤其适用于深度神经网络,其中每个神经元都有可能在特定步骤的训练过程中被暂时退出或完全忽略,但在下一步骤中可能是活跃的,这由称为退出率的参数 p 决定。这种脱落在测试过程中是无效的。它可以在致密层之后立即使用。实现如下:
model.add(Dense(units=4))
**tf.keras.layers.Dropout**(rate=0.3)
5.寻找超参数的最佳拟合
由于神经网络有太多的超参数需要调整,因此为网络找到超参数的最佳组合总是一个挑战。我们可以通过尝试尽可能多的组合来手动执行这个选择任务,看看哪一个效果最好。另一种方法是使用 GridSearchCV 或RandomizedSearchCV。由于这些是 sklearn 方法,我们需要通过分别使用keras regressor或keras classifier进行回归和分类任务,将 tf.keras 模型包装在模拟常规 sklearn 回归器的对象中。它采用使用 tf.keras API 描述模型的方法,然后我们可以使用它的 fit() 方法来训练模型。但是,我们的目标是找到 tf.keras 模型的最佳超参数,因此我们提到超参数的名称及其范围,并将其传递给 RandomizedSearchCV 方法,如下所示:
*#tf.keras model
def build_fn():
# the model which we built above using sequential API by making
the no. of hidden units and layers as variable model = Sequential()
..............
return model#KerasRegressor
keras_reg = tf.keras.wrappers.scikit_learn.KerasRegressor(build_fn)
#defining the parameters distribution
param_distrib = {
"n_hidden": [3,4,5],
"n_neurons": [40,50,60,70]
}
search_cv = RandomizedSearchCV(keras_reg, param_distrib, n_iter=4)
search_cv.fit(...)*
根据模型和资源的复杂程度,上述探索任务可能需要几个小时。
tf.keras 中的自定义图层
有时,我们需要创建一个 tf.keras 没有提供默认实现的层。该层可以有两种类型:无状态和有状态。
无状态自定义层与展平层一样,没有要学习的权重。为此,我们使用 tf.keras.layers.Lambda 层如下:
*log_layer = tf.keras.layers.Lambda(lambda x: tf.log(x))*
我已经在这里定义的生产用例中使用了这个自定义 lambda 层来生成特定句子的 ELMo 嵌入。
有状态的自定义层具有要训练的权重,并且可以通过扩展/创建 tf.keras.layers.Layer 类的子类并覆盖 call()方法来实现。例子可以在这里找到。
tf。估计量
tf。Estimator 是另一个高级 API,它在创建深度学习模型的同时提供了灵活性。它与 tf.data API 非常兼容,我们可以在不改变模型的情况下运行分布式多服务器环境。
[tf.estimator](https://www.tensorflow.org/api_docs/python/tf/estimator)为[tf.keras](https://www.tensorflow.org/api_docs/python/tf/keras).提供了一些目前仍在开发中的功能
可以将 tf.keras 模型转换为 tf.Estimator。有几个预先制作的估计器,我们不需要创建计算图或会话,估计器已经处理了它。前馈神经网络的预制估计器为TF . estimator . dnn classifier。**
使用预制评估工具
首先,我们需要根据特征字典对输入数据集进行预处理,该字典将键作为特征名,将值作为张量,将相应的张量列表作为标签。TF . data用于加载并预处理输入数据。然后,一个TF . feature _ column标识一个特征名、其类型和任何输入预处理。实例化模型,将特征列作为参数传递,并调用传递输入特征的 train 方法。下面是创建 FFNN 的代码:
***estimator = tf.estimator.DNNClassifier(feature_columns=[feature1, feature2, feature3], hidden_units=[40, 40, 10]) #instantiate
estimator.train(..) #train***
使用自定义估算器
这是我们根据自己的需求从头开始创建模型的地方,而不是由其他人创建的。这里,应该用相同的 tf.data API 对输入进行预处理,但是我们需要实例化TF . estimator . estimator,其中我们需要传递一个由model_fn指定的模型,该模型返回执行训练、评估或预测所需的操作。该 ops 需要传递给TF . estimator . train _ and _ evaluate以及 tf.estimator.TrainSpec 和 tf.estimator.EvalSpec 。下面是一个示例代码:
**#model_fn method
**def** model_fn(features, labels, mode, params):
.......
**if** mode == tf.estimator.ModeKeys.PREDICT:
**return** tf.estimator.EstimatorSpec(mode,predictions=pred)
**else**:
#define loss, optimizer and another other metric, then
**return** tf.estimator.EstimatorSpec(
mode, loss=loss, train_op=train_op)estimator = tf.estimator.Estimator(model_fn, feature, labels, mode, params) #instantiate estimator
train_spec = tf.estimator.TrainSpec(input_fn=train_inp)
eval_spec = tf.estimator.EvalSpec(input_fn=eval_inp)#finally train and evaluate
tf.estimator.train_and_evaluate(estimator, train_spec, eval_spec)**
数据预处理
As tf.data 对于评估者来说更受欢迎,因为它是分布式模型训练的一个很好的 API,在非常大的训练数据集的情况下,整个数据无法加载到 RAM 中。它可以从 tensor_slices、多个 CSV 文件中读取数据,如 tf.data.dataset,我们可以在其中使用映射、预取、批处理、混洗、填充批处理、重复等执行许多操作。对于相对较小的数据集, 熊猫 、numpy 和sk learn . preprocessing在使用 tf.keras 的同时效果很好。tf.keras 还提供了预处理数据的实用程序,为训练和评估做好准备,就像对图像数据集一样。
这就是前向神经网络的两章内容。请关注下一章 RNN(循环神经网络和注意力)。
参考资料:
书籍:奥雷连·杰龙的《机器学习实践》
一个端到端的开源机器学习平台
tensorflow.org](https://tensorflow.org)**
解释:多语言句子嵌入零镜头传输
对 93 种语言应用单一模型
近年来,语言模型和迁移学习已经成为自然语言处理的基石之一。通过首先建立一个单词甚至字符的模型,然后使用该模型解决其他任务,如情感分析、问题回答等,可以获得惊人的结果。
虽然大多数模型都是为单一语言或几种语言分别构建的,但一篇新的论文——零枪击跨语言迁移及其他的大规模多语言句子嵌入——提出了一种不同的方法。这篇文章使用了一个支持 90 多种语言的单句编码器。它的语言模型是在包含所有这些语言的句子的数据集上训练的。然而,它可以通过仅在单一语言上训练目标模型(例如分类器)来用于给定的任务,这是一种称为零射击的技术。
这种通用语言模型在诸如自然语言推理(对两个句子之间的关系进行分类)的任务中,在大多数语言中取得了很好的结果,这是零镜头模型的最新技术。这种技术训练起来更快,并且有可能用有限的训练资源支持数百种语言。
背景
自然语言处理(NLP)中的大多数预测算法不能直接处理原始文本,因为它是非数字和非结构化的。克服这一点的一种流行方法是通过创建一种语言模型,其中字符、单词或句子被翻译成有意义的向量,即嵌入向量。嵌入可以作为常量输入或通过组合两个模型(语言和预测)并针对任务对它们进行微调来提供给预测模型。
在大多数模型中,每种受支持的语言都需要一个额外的语言模型以及针对每项任务的额外培训。这些模型往往数据饥渴,需要庞大的数据集,有时有数十亿字。一种不同的方法是首先为所有语言一起训练单个语言模型。随后,对于任何给定的任务,在单一语言的数据集上进行训练就足以接收所有语言的良好结果,因为该模型能够概括许多语言,并对它们应用所学的知识。这种被称为零射击的技术的优点是简单(一种模式适用于所有人)和高效,特别是由于训练更快。

Zero-Shot approach vs other models
资料组
为了训练语言模型,作者创建了一个全面的数据集,其中包含句子及其在其他语言中的翻译。该数据集基于多个来源:
- 专业翻译——21 种语言的欧盟数据集(Europarl)、6 种语言的联合国数据集和 42 种语言的古兰经翻译
- 用户生成的翻译——open subtitle 提供 57 种语言的电影字幕,Tatoeba 是一个基于社区的数据集,将英语句子翻译成数百种语言。
最终数据集包括来自 34 个语系(例如日耳曼语和闪米特语)的 93 种语言的 2.23 亿个平行句子和 28 种文字(拉丁语到希伯来语)。
工作原理
该模型包括两个部分——语言模型训练及其在几个自然语言处理任务中的零镜头应用。
语言模型训练
语言模型使用用于机器翻译的标准架构,该架构具有编码器和解码器,编码器为一种语言的句子生成向量表示,解码器试图将句子向量翻译成目标语言。该模式的一个主要特点是对所有语言使用单一网络。
编码器包括两部分:
- 字节对编码(BPE) —一种预处理整个数据集并生成其中最常用字符序列的字典的算法。编码器中的 BPE 模块将句子输入转换成来自预建字典的子词。当使用多种语言时,BPE 显著减少了词汇量,增加了语言之间的共享区域(子词)。有关更多详细信息,请参见附录 A。
- LSTM 层——标准的递归神经网络,具有五层 LSTM 模块(大小为 512),在最后一层通过最大池生成句子嵌入。每个句子也以相反的顺序处理,即双向 LSTM,并且最终的句子嵌入是两个方向的串联。
然后,解码器尝试基于句子嵌入、LSTM 模块(嵌入有 BPE)的先前输出和目标语言 ID 来迭代预测下一个单词。解码器只有一个 LSTM 层(大小为 2048)和一个 softmax 层来预测最可能的字。解码器的唯一目的是训练编码器,而不是事后使用。

Model architecture (source: Artetxe et al.)
为了避免随着学习语言数量的增加而产生的二次成本,该模型仅使用两种目标语言(英语和西班牙语)进行训练,而不是全部对全部。
每项任务培训
经过训练的编码器可以用于解决其他 NLP 任务:
- 自然语言推理(NLI)——决定两个句子,一个前提(p)和一个假设(h)之间的关系是蕴涵、矛盾还是中性的。通过以下面的方式(p,h,p h,| p h |)组合句子,并将其作为输入来训练具有两层的小型神经网络,该模型学习预测关系。
- 主题分类—将短文本(如新闻文章)分类到给定的主题列表中,方法是用编码器嵌入文本并训练单层网络(10 个单元,之后是 softmax 单元)。
- 相似句子识别——更简单的用法是从另一种语言的句子数据集中找到给定句子的翻译。这项任务只需要对所有句子进行编码,并使用余弦相似度或更复杂的度量标准(如论文中所建议的)计算它们之间的距离。
该模型仅在英语句子上训练,然后在所有语言上测试(零射击)。此外,编码器是恒定的,不会针对每个任务进行微调。
结果
该论文给出了在 XNLI 数据集上的模型结果,该数据集包括用于 NLI 任务的 14 种语言的句子。当与同样被训练为零射击的其他模型相比时,该模型实现了最先进的结果。例如,与零镜头 BERT 相比,所提出的模型在大多数语言中都达到了更好的结果。

Comparison of XNLI accuracy between the proposed model and three other Zero-Shot models, BERT among them. All models were trained only on English sentences and tested on up 14 languages. Source: Artetxe et al.
另一方面,当分别为每种语言训练 BERT(通过将训练数据翻译成目标语言)时,其结果优于具有零触发配置的所提出的模型。
此外,该模型还在 MLDoc 数据集(路透社新闻文章)上的分类任务和 BUCC 数据集上的相似文本识别中呈现了最先进的结果。跨多种语言的模型结果显示了其语言模型的一致性以及使用单一多语言模型的低资源语言的优势。
[可选:当编码器在长且正式的句子上被训练时,一些任务(BUCC,MLDoc)往往表现得更好,而其他任务(XNLI,Tatoeba)受益于在更短且更非正式的句子上的训练?]
[可选:消融研究:减少编码器的层数会降低精确度]
计算&实现
该模型在 Pytorch 中实现,编码器和解码器使用 fairseq 。语言模型用 16 个 NVIDIA V100 GPUs 训练了 5 天左右。它将是开源的。
结论
多语言句子嵌入为创建语言模型提供了一种新的技术,它更快、更简单且可扩展。它可以很容易地适应新的语言和新的任务,同时在许多语言中实现强大的结果。它甚至可以处理不属于语言模型的“未知”语言。
然而,当效率和可伸缩性不如准确性重要时,这种模型以及一般的零炮模型似乎不如 BERT 等微调模型。有趣的是,作者计划借用 BERT 架构的概念,例如使用其转换器而不是 BiLSTM 模块来改进他们的模型。另一种不同的方法是针对特定语言对模型进行微调,并比较结果。
要了解最新的深度学习研究,请订阅我在 LyrnAI 上的简讯
附录 A — BPE
字节对编码(BPE)是一种数据压缩技术,它用单个未使用的符号迭代替换给定数据集中最频繁的符号对(最初是字节)。在每次迭代中,该算法找到最频繁(相邻)的符号对,每个符号可以由单个字符或一系列字符构成,并将它们合并以创建新的符号。然后,在下一次迭代之前,所有出现的选定符号对都将被替换为新符号。最终,频繁的字符序列,直到一个完整的单词,被替换为单个符号,直到算法达到定义的迭代次数(本文中为 50k)。在推理过程中,如果一个单词不在 BPE 的预建词典中,它将被分割成子词。
BPE 的示例代码可以在这里找到。
向管理层解释数据科学、人工智能、ML 和深度学习—演示文稿和脚本—第 2 部分,共 3 部分
这一系列的三篇文章旨在作为 Prezi 演讲“数据科学、人工智能、ML、DL 和所有这些东西”的附加脚本。在本系列的第一部分,我们深入探讨了数据科学的概念。这一部分集中在演讲的第二章,旨在给出什么是人工智能以及它与 ML 有何不同的非技术性解释,给出大量例子,并解释什么是人工智能(还不是)。正如你肯定已经注意到的,人工智能现在是几乎每一家出售数据分析和人工智能相关服务的公司的热门词汇,例如宇熙环球😃。
该演示可在此处找到:
什么是 AI?
本章分为五节:
- 三大热门 AI 应用。其中,在大胆给出正式定义之前,我们举例说明了人工智能在当今世界的应用。
- 定义 AI。针对痴迷于形式主义的,本节评述了给“人工智能”下一个令人满意的定义的困难,然后试图给出一个实用的定义。
- AI 子问题目录。凭借通过查看应用程序开发的直觉和定义中引入的概念,我们继续将 AI 分解为几个子领域,根据每个子领域试图解决的问题类型。
- AI 的局限性。在这一小段中,我们指出 AI,至少在我们迄今为止设法开发的狭义形式中,并不是全能的,并且具有严重的局限性。
- AI 不是什么。在最后一部分,我们针对那些看了太多关于机器人接管世界和奴役人类的科幻电影的决策者进行了一些期望管理。
三个流行的人工智能应用
我们不想马上以抽象、学术和枯燥的方式给人工智能下定义,而是想先回顾一下人工智能的三个流行应用。其中一些也可以被认为是简单的机器学习(ML),而不是真正的“智能”。然而,作为人工智能的一个子集,任何人工智能应用也是一个人工智能应用,就像烹饪甜点是更广泛的“烹饪”类别的一个例子一样。这些应用将有助于介绍人工智能定义中的一些基本概念。

应用 1。自动驾驶汽车。
自动驾驶汽车可能是当今人工智能的巅峰。如果你仔细想想,自动驾驶汽车实际上是一个机器人,尽管它可能看起来不像。它通过一组丰富的传感器(相机、雷达、激光雷达、全球定位系统)感知(收集数据)其环境,它还被赋予了致动器,允许它执行动作(转向、加速)以改变其自身在环境中的状况——或以其他方式影响环境。自动驾驶汽车构成了“自主智能体”、总体概念的主要例子,这将是稍后正确定义人工智能的关键。
除了大致对应于输入和输出层的传感器和执行器之外,还有一个中间处理层,它解释来自传感器的原始数据,并将其转化为信息/知识,最终用于解决安全驾驶和从 A 地到 b 地的问题。这一层当然是赋予自动驾驶汽车智慧的,并结合了相当多的关键人工智能技术。仅举三个例子,我们有:
- 计算机视觉:这是一套相对低级的技术,用于将光学或红外摄像机捕获的原始像素转化为车道线、障碍物、行人、鹿、交通标志等的实际检测。这确实是一个纯粹的 ML 问题,目前用深度学习技术和专门的硬件(GPU)解决。
- 搜索和规划:除了其他事情之外,这些被用来寻找从 A 到 B 的最方便的路线,受到障碍、交通、道路封闭、速度限制、天气等的限制……顺便提一下,这是人工智能解决的问题之一,不能通过纯人工智能技术解决,证明人工智能不仅仅是人工智能。
- 不确定情况下的决策:由于传感器测量值不是绝对精确的,并且关于周围环境的可用信息必然是不完整的,任何自主发动机几乎总是被迫在不确定情况下做出决策。这不是计算机系统 pre-AI 的共同特征,甚至不是大多数人会认为计算机可以做的事情。幸运的是,在 20 世纪后半叶,计算贝叶斯统计领域取得了很大的进展,使固有的确定性计算机能够处理不确定性。
应用 2。个性化内容推荐
虽然有时看不见,但推荐系统几乎无处不在,从电子商务网站——想想亚马逊——一直到数字内容分发平台,如网飞和 Spotify,以及社交网络。每当你看到基于你最近的观看/购买历史的信息,我们认为你也会喜欢你可以确定有一个推荐系统在起作用。
这种系统的使用已经渗透到甚至传统的内容提供商,最近转向数字。大多数人没有意识到这一点,但纽约时报网络版的头版对每个读者来说都是不同的。推荐算法以个性化的方式确定每个用户看到的内容。

Because you watched Russian Doll.
推荐系统的目标是从浩瀚的信息或内容项目中筛选出最有可能与特定用户或用户子集(即居住在某个位置或属于特定年龄段的用户)相关的内容项目。这改善了用户体验和平台内容的整体参与度。
从技术上讲,推荐系统可以被看作是以下通用人工智能技术之一的应用:
- 搜索:该系统的任务是根据一些用户特定的约束条件找到最相关的内容,这些约束条件通常来自用户交互的历史记录。
- 预测机器学习:给定过去用户交互的记录(例子),我们调整一个特定于用户的模型,然后允许我们预测用户 X 喜欢(以前看不见的)物品 y 的可能性
应用 3:计算机视觉

Image segmentation is able to identify distinct objects in a scene without necessarily saying what they are.
我们在讨论无人驾驶汽车时,曾简单提到过这种应用。然而,这是一个更广泛的领域,已经开始给制造业和安全行业等带来革命性的变化。人工智能最近人气飙升,很大程度上是因为在这一领域取得了成功。为了丰富您的计算机视觉词汇,我们希望区分管理人员有时会互换使用的几个术语:
- 目标检测:这是指在给定的图像中,围绕特定类别的目标(例如行人)的所有实例进行定位,即绘制边界框。例如,这种方法的变体可以用来在制成品的图像中发现缺陷。
- 物体分类:给定单个孤立物体的图像,识别物体的类别。换句话说,这是一张水果、一个人、一张桌子、另一辆车的照片吗?
- 人脸识别:给定一张人脸图片,告诉我是谁。
- 图像分割:给定一张复杂场景的图片,分离出其中每个单独对象对应的不同组件(像素组),即使你不能告诉我它们是什么。
- 流检测:给定一个视频,在每一帧中识别正在移动的对象,以及移动的速度…
定义人工智能
定义人工智能的尝试充满了文化、概念甚至哲学上的困难,其中我们可以数一数:
- 科幻电影中对人工智能的描述必然有缺陷以及它们在流行文化中产生的相应误解。我们将在稍后关于人工智能不是什么的部分对此进行更多的评论。
- 最近人工智能的复兴带来了这个术语的缺乏精确性,如果不是被营销人员和高管们彻底滥用的话。事实上,这是创建本演示文稿的主要原因之一。在商业环境中,术语“AI”通常用于指代许多过去被称为其他名称的东西至少在它们被开发的更狭窄的学术圈子中是如此。这些例子有:
机器学习:正如我们已经指出的,这只是人工智能的一个严格子集。
商业智能/分析:不是真正的人工智能,尽管它可以指导人类做出更明智的决策。专家系统:这些系统是基于从特定领域的人类专家那里辛苦收集的许多如果-那么规则,并让计算机根据需要应用它们。虽然它们属于人工智能的开端,但自其早期发展以来已经发生了很多事情
一些统计工具:为了营销的利益,甚至经典的统计工具,如线性或逻辑回归,有时也被称为人工智能! - 雪上加霜的是,甚至连人工智能的研究人员都没有对他们的研究领域进行精确的定义,这使得情况变得更加糟糕。如果我们认为他们瞄准的是一个移动的目标,我们就不能责怪他们。许多曾经被认为是人工智能主要例子的产品,如 OCR 系统(从扫描文件中提取数字文本或从信封中提取手写邮政编码)或拼写检查器,现在被许多人认为是“常规软件”,不配拥有“人工智能”的标签。正如一个老笑话所说“人工智能是所有计算机还不能做的很酷的事情”。和所有的笑话一样,这个笑话植根于一种普遍持有的观点,即一旦设计出一种合理有效的算法方法或计算机架构来解决一个问题,该问题就会自动脱离人工智能的领域,进入“经典”软件工程领域。
- 最后但并非最不重要的是,我们应该提到,仅仅是“人工智能”中智能这个词的出现就打开了一个语义和哲学上的难题,困扰着任何令人满意地定义这个短语的尝试。关于意识、思想、头脑和灵魂的“真正本质”的几千年未解决的问题立刻出现了。当然,我们甚至不会试图在这里攻击这些。我只想说,任何一致且被接受的人工智能定义,就像我们将在下一节介绍的那样,都必然会避免触及“生物智能”或“有机智能”实际上意味着什么的危险话题。
不完善的定义
这是人工智能的一个实用定义。由于刚才提到的哲学上的困难,它必然是不完善的。它是可操作的,因为它关注的是智能主体必须表现出的可观察属性,而不是智能意味着什么。
定义:AI 是计算机科学的分支,负责智能代理的设计和构建。
反过来,智能代理是任何(大部分)具有以下特征的代理:
- 自主(即能够在复杂环境中执行任务,无需用户的持续指导)和
- 适应性强(能够通过从经验中学习来提高绩效)
- 能够感知并有效地抽象其环境特征(感知)
- 能够“理智地”行动。在这种情况下,理性行为是指任何旨在最大化定量和客观效用函数或性能测量的行为。
这个定义的两个推论是,智能代理必须包括(并且几乎可以简化为):
- 做出明智决策的程序——这里的“聪明”只是理性的一个更简单的词,在上面已经做了精确的解释。
- 能够模仿人类认知(某些方面)的系统。
人工智能子领域列表
有了前面的定义,不管它有多不完善,我们都可以更好地回顾和理解人工智能的一些子领域。这里有一个简短的目录:
- 搜索和信息检索:这不仅仅指互联网搜索,如谷歌或 Shazam,而是指一系列更广泛的问题,其中我们的智能代理(在本文中称为“搜索引擎”)必须在一个由大量数据项组成的环境中导航,以最大化效用函数,这是每个项与查询相关性的定量测量。
- 规划:这是设计一个计划或一系列行动的问题,这些行动将一个复杂的系统从初始状态 A 引导到期望的状态 B,服从一组约束。这方面的一个重要例子是,在拥挤时段,在繁忙的机场为一组飞机创建公平和最优的着陆时间表。
- 自然语言处理(NLP)和语音识别:这些是任何聊天机器人或对话式数字助理的关键要素。这里的关键能力是“理解”人类输入的话语或书面短语,以检测他们的意图(提出问题、下订单等)。)在这种情况下,一方面,智能代理是机器人,环境是聊天室,另一方面,是用于回答问题或执行人的请求的一组信息服务、数据库或 API。
- 自动推理:这些系统试图进行逻辑思考或从一组前提推导出一个结论。几年前,IBM Watson 因击败之前的人类冠军赢得了 Jeopardy 而出名。可以肯定的是,这个游戏不仅仅是关于推理,还包含了大量的信息检索成分。最近,一个所谓的“法律人工智能”能够发现 NDA 协议中的问题,比一群经验丰富的律师更准确。当然,这个例子也处于自然语言处理和自动推理之间的灰色地带。
- 计算机视觉:我们在这篇文章的第一部分详细讨论了这个子领域,作为三个原型应用的最后一个。
- 任何机器学习(ML)问题:最后但并非最不重要的是,我们应该提到有一大类问题不直接属于上述任何子领域,但可以通过 ML 技术解决。为了能够应用 ML,关键要素是以示例的形式拥有大量数据,通用算法可以从中发现模式,然后做出预测。在本系列的第三篇文章中,我们将会有更多关于 ML 的内容。所以,敬请期待!
AI 的局限性

正如我们在前面一节所暗示的,“聪明”这个词是有问题的,甚至是误导的。能够从皮肤照片中检测黑色素瘤的计算机视觉系统可以被称为智能的,但它不能执行智能人会做的任何其他任务。
这就是为什么我们当中比较迂腐的人会把狭义的和广义的人工智能区分开来。如果一个人工智能系统解决一个问题的能力没有告诉我们解决另一个问题的能力,即使从人类的角度来看,这两个问题密切相关,那么这个人工智能系统就被称为狭义的。关键的观察是狭隘的人工智能系统不能将一般原理从一个问题转移到另一个问题。
到目前为止,我们只能开发狭义的人工智能。人工 通用 i 智能,通常缩写为 AGI ,指的是能够处理任何智力任务并能将知识或技能从一项任务转移到另一项任务的机器。不幸(还是幸运?)AGI 仍处于科幻小说的领域。对于 AGI 是否能在可预见的未来实现,几乎没有共识。尽管在深度学习领域取得了令人印象深刻的进步,这些进步在不久前还被认为是不可能的,(即 AlphaGo ),但这位研究人员认为,AGI 至少还需要 50 年,如果不是更久的话..
总之,人工智能的主要限制是人工智能代理通常只能优化他们的决策和行动来实现一个单一的目标。人的因素仍然在理解这个目标的背景、对不同目标的工作进行优先排序以及有效地交流人工智能模型的结果方面发挥着关键的作用。
什么人工智能不是(还不是…)

Terminator
作为这篇文章的结尾,这里列出了人工智能还没有做到的事情——至少现在还没有:
- 用金属般的声音说话的机器人(并且能够设计对抗人类的机器人)。例如终结者/天网。
- 意识/感觉机器:不管在不久的将来,一些机器在模仿感觉方面会变得多么好,我们都不应该忘记,我们离在数字计算机中复制意识还很远。首先,我们不确定意识需要什么。
- 能够代替任何人做任何工作。尽管越来越多的工作正在被有效地自动化,但仍有大量更具创造性或战略性的工作在中长期内不会被机器取代,甚至可能永远不会。
- 一般智力:能够主动从一个领域中提取知识和技能,并将其转化。参见上一节。
- 能够主动/自由地(显著地)更新自己。尽管适应性是人工智能代理的定义特征之一,但允许它们处理与最初设计的问题有质的不同的问题的重大更新仍然是他们力所不及的。
- 可数名词。奉劝:不要谈“安艾”。人工智能是一门科学学科,就像数学或生物学一样。
结论
在这篇文章中,我们从“商业”的角度,对人工智能领域,它的可能性和局限性做了一个高层次但详细的概述。为了让我们的想法更有条理,我们还尝试了一个精确而实用的人工智能定义,它专注于可观察和客观量化的目标,而不是关于大脑和智能真正含义的难题。
敬请关注本系列的第三篇也是最后一篇文章,在这篇文章中,我们将缩小对机器学习和深度学习领域的关注,通过这些领域,人工智能近年来重新获得了优势。
参考
了解更多关于瑞典的人工智能创新,赫尔辛基大学和 Reaktor 的学生和商业人工智能课程…
www.elementsofai.com](https://www.elementsofai.com/) [## 人工智能| Udacity
向彼得·诺维格和巴斯蒂安·特龙这样的人工智能专家学习基本的人工智能概念,包括…
www.udacity.com](https://www.udacity.com/course/ai-artificial-intelligence-nanodegree--nd898) [## 人工智能与律师:终极对决
在准确发现日常商业合同中的风险方面,人工智能首次超过了顶级律师。
www.lawgeex.com](https://www.lawgeex.com/resources/AIvsLawyer/) [## 20 个顶级律师被法律 AI 打。以下是他们令人惊讶的回应
在一项里程碑式的研究中,20 名在公司法和合同审查方面有数十年经验的美国顶级公司律师…
hackernoon.com](https://hackernoon.com/20-top-lawyers-were-beaten-by-legal-ai-here-are-their-surprising-responses-5dafdf25554d) [## 杰弗里·辛顿和戴密斯·哈萨比斯:AGI 离现实还差得很远
预测音乐品味。检测转移肿瘤。生成脑癌的合成扫描。正在创建虚拟…
venturebeat.com](https://venturebeat.com/2018/12/17/geoffrey-hinton-and-demis-hassabis-agi-is-nowhere-close-to-being-a-reality/)
向管理层解释数据科学、人工智能、ML 和深度学习—演示文稿和脚本—第 1 部分,共 3 部分

Image from the book “Think like a Data Scientist” by Brian Godsey (link in the references below)
介绍
如果你是一名数据科学家、一名机器学习工程师、一名人工智能专家,或者无论你想称呼自己什么,在你职业生涯的某个阶段,你很可能至少遇到过一个经理,他不理解标题中列出的一些概念之间的区别。毕竟,他为什么要这么做?!你可能很难在不使用专业术语的情况下解释这些差异,而且你这样做已经疏远了你已经困惑的经理。
不再害怕!我们羽西环球针对这种情况制定了近乎完美的解决方案。作为 Yuxi Global 的数据分析主管,我的任务是构建 Prezi 演示文稿,以帮助解释“数据科学”、“人工智能”、“机器学习”(ML)和“深度学习”(DL)对中高层管理人员的意义。最终目标是帮助他们指导他们的战略和商业决策,即我们希望为这些领域的客户开发什么样的服务和解决方案。在这样做之后,我们认为与世界分享我们的工作是有价值的,可以节省每个数据科学家使用演示软件的大量时间。
演示链接就在这一段下面。下面,我们还分享了一个以完全线性的方式呈现材料的脚本。当然,你可以选择一些零碎的东西作为演讲的重点,并在它们之间切换。这也是我们选择 Prezi 作为演示解决方案的原因之一。
Presentation by Jhonatan Mora, commissioned by the author.
“分析/数据科学/ AI / ML / DL 和所有这些东西”的演示文稿脚本,第 1 部分,共 3 部分
第 1 部分:什么是数据科学/数据分析?
这一部分由两章组成。第一个重点是试图通过给出不止一个而是三个相关的定义来定义“数据科学”这个有点鬼鬼祟祟的概念。这个想法是,演示者可以选择与他自己的背景和对主题的理解最有共鸣的定义,或者最容易被他的观众吸收的定义。第二章试图解释为什么数据科学现在是一种趋势,而以前不是,这很奇怪,因为根据定义,数据科学的概念是多么自然或基本。
第一章:三个定义
定义 1: 也许理解“数据科学”的最佳方式之一就是将视为一个过程,即使用数据 来理解事物的过程。在我们希望做得更好的“事情”中,我们可以列出:
- 你的顾客
- 您的业务流程
- 顾客如何消费/感知/喜欢你的产品。
这里的关键词是“数据”和“理解”。数据是主要输入,理解是最终目的。因此,数据科学远远超出了商业智能,商业智能往往停留在测量和呈现已经发生的事情,而没有深入研究为什么会发生,或者如何控制或影响未来将发生的事情。另一种简单的说法是让“数据讲述一个故事”。毕竟,所有人类总是试图通过创造叙事来理解他们周围的世界,这些叙事以逻辑连贯的方式(有时甚至是荒诞的方式)将纯粹的事实联系起来,例如神话和传说。
另一种将这一定义转化为文字的方式是,数据科学等同于揭示隐藏在数据背后的洞察力、模式和趋势。有些人喜欢这个定义,因为它很短,并且提到了两个很好的流行语:“趋势”和“见解”。前者的含义对我来说相当清楚。大多数人对什么是趋势都有非常清晰的概念。然而,洞察力是一个更加抽象的概念,含义相当模糊。这个词在西班牙语中没有明显的翻译。从给出的翻译来看,你可能会认为它在某些情况下意味着“理解”,而在其他情况下意味着“知识”……我喜欢这种措辞的原因是,它引入了一个关键概念,即数据本身只是一个开始,在数据的背后隐藏着重要的拼图,人们想要揭开它。
这给我们带来了同一概念的进一步措辞,我特别喜欢:数据科学意味着将数据转化为知识,而可以指导决策。 一个绝妙的形象地说明了数据和知识之间的区别(对一些人来说是意想不到的),这就是“番茄类比”。这是这样的:

Image by the Author
这里的关键见解是,在做决策时,数据本身几乎没有任何价值。数据不过是一些实体的记录事实的集合,有时是巨大的集合,比如你的客户、你的销售交易或你的网络互动。尽管你和你的公司可能会花费大量的金钱、时间和精力来管理这个事实库,但是所说的成本不会自动转化为价值。
在数据之上增加一层价值之后,可以在下一个层次找到信息,在丰富的背景下以系统化或结构化的形式。您的数据中与业务相关的方面只是第一次出现在这里。只有当数据在您的业务环境中具有相关意义时,它才会成为信息。
现在谈谈知识。知识的定义特征是它给你一种竞争优势,或者像古老的格言所说的“知识就是力量”。获得这种优势的方法是做出比竞争对手更好的决策。换句话说,一个人不具备关于某件事的(有价值的)知识,除非所述知识能够为你的决策提供信息,并为你的业务带来更理想的结果。
如果不清楚的话,关于智慧的那一点真的是一个笑话。正如有人曾经说过的那样,通过幽默学到的任何东西都不会被忘记。
定义 2:数据科学就是科学。
这个定义强调了科学已经存在了几个世纪的事实。在那段时间里,应用的配方——也就是科学方法——都是一样的:
- 通过观察一些现象并记录这些观察开始,即产生数据。
- 根据手头的数据,提出假设和问题,并尝试确认和回答它们。严格地说,除非一个假设被表述为另一个假设的否定,否则一个假设永远不会被证实。一个人最大的希望就是拒绝或者拒绝不了它。然而,我建议你永远不要在管理层面前讨论这种微妙之处,因为这很可能导致混乱,让他们错误地认为你是一个廉价的哲学家。
- 给定足够的数据和确认的假设,人们有时可以冒险建立一个模型。模型是一个更加精细的概念/数学工件,它进一步编码或总结了您对所讨论的过程或系统的理解。一个足够强大的模型甚至可以用来产生前瞻性的预测。
- 对于某些研究主题,可以设计实验(例如 A/B 测试)来以可重复的方式真正测试某些条件对您的系统的影响。这确实是建立因果关系的唯一明智的方法。
简而言之,在这个定义下,数据科学只不过是几个世纪前的应用(而且已经被证明!)解决商业问题的科学方法。顺便说一句,这个定义帮助我们看到“数据科学”中的“数据”是多余的,因为从来没有不处理数据的科学!
定义三: 数据科学作为一个总称。
这可能是最不深刻但也是最直接的定义。它将数据科学简化为一些战术组件的直接总和。根据这一定义,数据科学将是一个近期 的总称,它将以下几种工艺组合在一起:
- 人工智能:一些人声称,好的数据科学至少需要雇用少量人工智能。我们不一定同意这种说法。在本系列的第 2 部分中,我们将对此进行更多的讨论。
- 机器学习:这将是第 3 部分的主题
- 统计学确实是任何科学努力的工具,也是将“软”科学转变为“硬”科学的唯一途径。
- ETL,数据清理: ETL 是指提取、转换、加载或数据探索、假设制定、模型构建之前的阶段。这些无疑是数据科学最不迷人但无疑是必要的方面。然而,将这些归入“数据工程”领域已经成为一种时尚。
- 数据可视化:对于第一个定义中提到的数据科学的“讲述故事”方面,以及对于从模型或输入数据的简单初始探索中得出的结果的成功交流,都是必不可少的。
- 算法和基础设施:旨在有效操作和处理数据。这是几乎所有数据科学项目的第二阶段(ETLs 和清理之后)所涉及的“数字处理”。算法和基础设施实际上是一种工具和手段,但不是数据科学工作的目的本身。他们的发展和理论研究确实属于计算机科学系。
- 高效的数据存储和检索架构:与上一个非常相似。这一方面涉及有效获取、存储和检索数据的技术(硬件和软件)。数据科学必然会在这个领域找到支持。
- 业务知识/对应用领域的理解:这是数据科学中经常被忽视的一个方面。我个人经历过许多数据科学项目失败的例子,要么是由于“业务方面”的人想当然地认为数据科学家完全获得了业务动态及其所有隐含的假设和约束,要么是数据科学家自己完全无视这些,只关注数据分析方法。
第二章:为什么如今数据科学是“一个东西”?
考虑到上一章提到的数据科学只不过是将一种旧方法自然应用于商业领域,以使其更好并获得优势,那么显而易见的自然问题是:为什么它没有更早发生?
我们认为,答案可以归结为两个密切相关且相对较新的发展:
- 互联网经济的到来和移动应用的爆炸式增长产生了大量等待转化为价值的数据。因此,有许多公司或所谓的平台,它们的业务包括移动比特。因此,数据是这些公司的主要资产。这同样适用于许多已经过渡到数字世界的传统行业,比如报纸、电视、酒店、食品配送、保险等等

1 exabyte =1.000.000.000 gigabytes, Source: Cisco VNI Global Mobile Data Traffic Forecast (link below)
- 与数据存储和处理相关的成本急剧下降。根据的消息来源和的消息来源,每 GB 硬盘的成本从 1997 年的大约 100 美元下降到 2005 年的 1 美元,然后在 2017 年再次下降到大约 0.03 美元。这只会助长“大数据”和“分布式计算”等趋势。
在更小的程度上,以下因素,我们认为是我们刚才提到的两个因素的结果,促成了数据科学的流行和 ML,AI 和深度学习(ML)的复兴:
- 大量的开源工具。通过公共存储库共享源代码的便利性使开源软件成为数据科学之王,几乎完全取代了传统的昂贵的闭源解决方案,如 SAS 或 IBM SPSS。
- 大量创新的 ML 和 DL 算法的开发能够处理每年增长的数据集以及能够从非表格数据(例如图像或声音文件)中提取价值的需求推动了这一发展。
- 在硬件方面,用于运行深度学习算法所需的繁重计算的 GPU 的可用性。这几乎是游戏流行的一个偶然但幸运的副作用。感谢游戏玩家!
第一部分的结论
在第一部分中,我们从三个不同的角度介绍了数据科学的一般背景。我们还评论了直接促成数据科学应用于以信息为中心的行业的环境变化。
请继续关注第二部分,我们将解释什么是人工智能,以及它如何真的不仅仅是人工智能。
参考
像数据科学家一样思考:在 Amazon.com 一步一步地处理数据科学过程。免费…
www.amazon.com](https://www.amazon.com/Think-Like-Scientist-step-step/dp/1633430278) [## 存储成本的历史-马特·科莫罗夫斯基
存储成本的历史
-马特·科莫罗夫斯基 costwww.mkomo.com 仓储史](http://www.mkomo.com/cost-per-gigabyte) [## 思科视觉网络指数:2017-2022 年全球移动数据流量预测
2019 . 2 . 19 关于思科视觉联网指数 q .思科为什么要开发思科视觉联网指数…
www.cisco.com](https://www.cisco.com/c/en/us/solutions/collateral/service-provider/visual-networking-index-vni/vni-forecast-qa.html)
解释数据科学/人工智能
一位数据科学家对“您是做什么的?”

Photo by Scott Graham on Unsplash
你是做什么的?
对于数据科学家来说,这是一个很难回答的问题,尽管他们经常被问到这个问题,这也是我们写这篇文章的原因。我们将在涵盖人工智能基础知识的同时,尝试解释他们的谋生之道。因此,我们将把这篇文章的重点放在什么是 数据科学家 上,同时也围绕关于 人工智能 的普遍误解。
这是而不是一个关于如何成为一名数据科学家,或者如何开始学习人工智能的教程。这篇文章旨在尽可能简单易懂,你不需要多少数学或编程知识就能理解。
最后,你将有望很好地理解数据科学家是如何谋生的,以及他们如何利用人工智能来解决现实世界的问题。
AI 呢?
嗯,未来似乎会围绕人工智能来塑造自己,作为一个社会,我们需要规范我们对数据能做什么,不能做什么。是的,都是关于数据,我们将在下一节看到。
当然,我们可以花很多时间来谈论人工智能不好的一面,不是说它不重要,而是它在网络上被广泛报道。事实上,你可能会认为人工智能机器人将接管世界。
所以,相反,我们会深入探讨艾的好的一面,通常会被忽略,因为它可能会改变世界。它将帮助我们治愈疾病,发现新的药物,教育更多的人,无论是在富国还是穷国,找到新的娱乐方式,甚至是着陆火箭!
你说的“一切都与数据有关”是什么意思?
好问题!要回答这个问题,我们需要开始谈论严重依赖数据的 机器学习 ,而是 AI 的主要组成部分之一。
要理解到底什么是机器学习,我们先来解释一下什么是算法。通常,我们定义一个算法,就像我们定义一个烹饪食谱一样:一个遵循的步骤列表,它将引导你到一个确定的目标。例如,如果你有心脏问题,你可能会去看医生,做一些检查。当得到你的检查结果时,医生会根据一个算法来决定你是否患有心脏病。这意味着如果你的心率高于某个阈值,你的家族也有心脏问题史,在上面锻炼时有一些问题,那么医生可能会决定你应该进行更多的测试,以验证你的心脏是否有风险,或者你的身体健康。
嗯, 机器学习 算法(或模型)是一种不同类型的算法。这个想法主要是利用菜谱的结果,也就是这道菜,来回溯我们的工作方式,实际上**自动学习整个菜谱。在我们的案例中,我们希望从大量患者数据中自动学习最佳算法。所以,对于一个特定的病人,我们会知道他们的心率、血压、和以及其他一些事情;还能判断他们是否有心脏问题。利用这些信息,我们想训练一台机器学习如何识别心脏问题。我们希望复制人类如何学习,这就是机器学习模型表现良好的原因。算法通常会直接从数据中学习哪些是重要的因素(心率等……),这就是“机器 学习 ”这个术语的由来。有许多算法属于这一类,但是每次的过程都大致相同:**
- 选择要使用的算法
- 训练它使用一些数据,当它答对时奖励它,当它答错时惩罚它
- 通过测量它得到正确/错误答案的频率,在新数据上测试它
如果这一切听起来有点模糊,不要担心,我们已经为您准备了一个例子!
但是他们做什么呢?
数据科学家的工作很难确定,因为它是而不是新的。它围绕着数据、统计、编程和交流。通常,他们会被分配一项特定的任务,例如:“根据这些患者的记录,找到诊断心脏病的最佳方法”。但有时,他们也可以在没有特定指令的情况下获得一些数据,例如:“利用数据来创造价值/赚钱”;是的,就是* 它 。
工作描述非常宽泛,它还包括一些任务,例如:“构建一个能够为我们的客户安排完整行程的对话式人工智能,包括机票或火车票,以及酒店预订”。*
然而,今天我们将专注于一个特定的任务:如果我们必须从一个新病人身上诊断出一种心脏病给定大量关于过去病人的数据,数据科学家将如何着手?
好吧,首先,人们会从尝试获得对数据的感觉开始,因为算法只会和提供的数据一样好。我们的意思是,如果你有一个主要由健康患者组成的数据集,你通常会很难建立一个能够找到患病患者的算法。****
一旦完成,数据足够干净可以利用,工作最好的部分就来了: 建立模型 。数据科学家将训练一个模型来识别一个生病的病人和一个健康的人,这很有趣。我们将在下一节中更深入地讨论这个问题。
最后但同样重要的是,当一个好的模型已经建立起来时,另一个至关重要的部分是向负责人解释结果或预测,作为一名医生或管理人员,通常不是一个精通统计的人。沟通是工作的一个重要部分,因为你必须为你的解决方案辩护,这可能会影响数百万人的生活。**
关于定义的闲聊已经够多了。让我们向你展示数据科学家是做什么的。**
检测心脏病
大学和其他组织可以在网上获得大量的数据集。一个数据集由两个组成,第一个是样本,第二个是特征。这并不像听起来那么复杂,例如在我们的例子中,样本是患者,特征是提供的关于他们每个人的信息。你可以在这里找到由 UCI 提供的数据。所有后续工作都由源代码支持,您可以在这里找到。**
好吧,让我们深入研究一下。在这种特殊情况下,我们看到的是由医生和研究人员收集的大量信息组成的患者数据。我们将大致了解数据科学家是如何做的,这样你就可以理解他们是如何利用数据得出结论和预测事情的。**
所以我们要做的第一件事是理解这些数据是关于什么的。以下是我们现有资料的摘录:
***+-------+------+-------------+--------+----------+---------+
| age | sex | chest_pain | chol | restecg | num_bin |
+-------+------+-------------+--------+----------+---------+
| 63.0 | 1.0 | 1.0 | 233.0 | 150.0 | 0 |
| 67.0 | 1.0 | 4.0 | 286.0 | 108.0 | 1 |
| 67.0 | 1.0 | 4.0 | 229.0 | 129.0 | 1 |
+-------+------+-------------+--------+----------+---------+***
因此,对于每个患者,我们知道很多事情,年龄,性别(男性 1,女性 0),他们经历的胸痛(从 1 到 4), 胆固醇的水平,他们的静息心电图结果,以及其他一些指标:他们总共有 13 人。最后一栏称为“num _ bin”是代表他们是否有心脏问题的一栏,1 表示有,0 表示没有。****
医生通常会询问所有这些信息,并利用这些信息来决定患者是否有风险。数据科学家的工作可能是建立一个能够预测这些心脏问题的数学模型。因此,与医生相反,模型不是知道一些赠品和一般的健康规则,而是试图通过处理数据来学习它们,(嗯,这比那要复杂一点,但这是它的要点)。别忘了我们在这里谈论的是数学,而不是魔法。这个想法实际上很简单,第一步我们希望训练模型能够从数据中识别疾病,然后在新的、从未见过的数据上测试,并评估其性能。**
我们所说的培训是什么意思?
训练是一个特定的过程,它包括提高模型的性能。我们首先向算法随机展示一个病人,而不告诉它病人是否有心脏病,并要求算法预测是否有心脏病。在每次猜测之后,我们通过调整一些参数来计算算法中的误差或好的预测,这些参数将有助于算法在每个例子之后变得越来越好。****
我们所说的测试是什么意思?
正如您所期望的,测试仅仅是测量模型性能的行为。我们一直在用测验或测试来测试人类,这仅仅是一种测试一个人在某个科目上的能力的方式。从设计上来说,这与我们人类的行为非常接近。在我们的具体案例中,我们希望能够看到算法得到正确或错误答案的频率。更重要的是,我们要确保模型不会错过生病的病人,因为很明显,错过生病的病人比向健康的人宣布他们生病更糟糕。
预言
使用前面提到的数据集,我们训练了两个模型,这两个模型都来自不同的算法,每个模型都有自己的优点和缺点。
第一个是 随机森林 ,这是一个高度可解释的模型,这意味着当我们使用它进行预测时,我们将能够理解模型是如何做出决定的。这对医生来说实际上是一个巨大的帮助,因为他们将能够从模型中提取信息,例如哪组特征对做出最佳决策最重要。
随机森林模型是基于决策树的模型,并基于特征做出连续的决策,直到能够得出关于患者是否患病的结论。训练完成后,您可以检索其中一个决策树*,亲自查看模型如何决定对样本进行分类。我们自己训练了这个模型,这是结果树之一:*******

One decision tree from the Random Forest
正如我们所看到的,在每一步,树都根据一些因素做出决定,最后,在下面的树叶上,我们将看到预测。想象一下,对于一个医生来说,在他们的诊断中包含这种模型会有多棒。当我们测试它的时候,随机森林是正确的的概率大约是的 80%,这意味着它在 10 个病人中有 8 个在没有犯错误的情况下发现了病人是健康的还是生病的。但更重要的是我们发现的所有患病患者的百分比,即 61.5% :换句话说,我们 10 次中有 4 次会漏掉一个患病患者。正如我们所看到的,它具有高度的可解释性,但在预测方面却表现不佳,事实上,在所有患病患者中,我们的遗漏率超过了* 38% !*****
好的,让我们来看看第二个模型,它是一个 多层感知器 ,一个最简单的 神经网络。神经网络是基于人脑的数学模型,更具体地说是基于它们的突触。事实上,它们被设计成以与人类相似的方式做决定。与之前的模型相比,这个模型不像那样可解释,但是理论上应该做出更好的预测。事实上,当我们测试它时,该模型的正确率为 86.7%* 比以前高,但真正的变化是它发现的病人,关于他们,它的正确率为 84.6%比以前高得多。我们现在“只”错过了他们中的 15%多一点。***
正如我们所看到的,两个模型之间有一个明显的权衡,一个更准确,但另一个是可解释的,根据应用程序,我们可能希望使用一个而不是另一个。例如,如果我们想帮助医生做出更好的预测,可解释的模型会更好。然而,如果我们希望做出准确的选择,我们会选择另一个。**
成果交流
现在我们有了要展示的结果,我们需要把它们清楚地传达给负责人,不管那个人是医生、经理、科学家还是其他任何角色。因此,数据科学家将需要调整他们的解释,以符合他们听众的技术深度。但有时机器学习对所提供的那种数据不起作用,人们需要解释它为什么不起作用,以及如何修复它。****
这就是为什么通常他们倾向于制造两种不同的解释,一种高层次的,一种低层次的。第一个面向业务相关人员,另一个面向更多的技术受众。****
瞧啊。无论如何,数据科学家的工作相当神秘,所以,很有可能,在角色再次转变之前,这种快速描述可能不会保持准确那么久。人工智能不是黑魔法,也不能解决所有问题,但它可以帮助改变我们的生活。**
本文由 Pierre Fouché、Matthias Leroy、和 Romain Choukroun 共同撰写。再次,你可以在这里 找到分析结果 背后的代码和科学。通过纠正我们在科学或写作方面的错误,帮助我们把这篇文章写得更好!如有疑问,请随时联系我们,我们将很乐意回答: pierre . fouche @ epfl . ch
Matthias . Leroy @ epfl . ch
romain.choukroun@gmail.com
向你的祖母解释数据科学
或者如何向你的家人或任何与技术世界脱节的人解释数据科学。

Photo by Alex Harvey 🤙🏻 on Unsplash
我无法用确切的语言来表达我的沮丧。我做数据科学家已经 3 年了,在这 3 年的大部分时间里,我一直在努力向家人解释我工作的目的和日常活动。首先,我的家人只会说法语,Data Scientist 不会完全翻译成法语。官方的说法是,法国政府提出了一个翻译:“专家在地中海”。剧透警报,对谁都没啥意义。
机器学习的世界是由英语主宰的,向任何一个 60 岁以上的法国人解释英语是一种极其痛苦的经历,这些人从未与计算机或数据世界有过任何联系。此外,我的家人不仅仅是法国人,他们是 T2 南部的法国人,这意味着除了不会说英语之外,他们还有脾气,对他们不理解的事情没有耐心。最终,他们的结论是“她用电脑做了点什么”。公平地说,我有。但是现在,大多数人“用电脑做一些事情”,即使仅限于在该死的电脑上回复电子邮件。
虽然这让我很抓狂,但我也需要理解这对他们来说有多沮丧。老年人已经脱离了科技。它长得如此之快,如此之大,如此之强。它在我们的生活中无处不在,但这并不意味着每一代人都在理解它及其后果。我不能只是沮丧,我也需要一点同情心。尽管我尊重所有的工作,但我厌倦了我的家人相信我能够修理电脑,而数据是没有人能够控制的邪恶事物。

什么是数据?
我相信,作为一名数据科学家,我的部分职责是帮助人们了解如何处理他们的数据,并且每个人都可以用这些邪恶的垃圾来攻击他们。我们在主流媒体上看到的都是脸书如何利用我们的数据进行操纵,或者一个在线约会网站的数据如何泄露并破坏(可能已经非常不幸福的)婚姻。
我想帮助我的家人理解数据不一定是关于他们的,我想让他们知道,是的,可怕的人可以使用数据来影响选举,但大多数数据科学家希望使用数据来提高效率和改进。在某些情况下,分享他们的数据是一个伟大的决定。例如,如果他们的医院要求他们允许在他们的系统内共享数据,我希望他们知道这个决定背后的价值。
找一个他们能与之相关的话题
如果你想让你的家人理解你作为数据科学家的工作,你需要从他们的日常生活中找到一些他们能真正理解的东西。从头开始,从简单开始,从逻辑开始。

Image from giphy.com
以下是你祖母可能会联想到的一些常见事物:
- 食品
- 电视节目
- 天气预测
- 她收到账单的电力公司
杂货是我选择最多的话题。每个人都明白这一点,几乎每个人一生中都买过一次意大利面和番茄酱(除非他们不耐麸质或者没有味蕾)。).
预测你奶奶会在商店买什么
比方说你的曾祖母在家乐福购物(没错,是法国超市)。她每周去那里三次。每个人都知道你的祖母对意大利肉酱面有特殊的配方,她每周至少吃一次。然而,你的祖母并不是唯一的一个,许多人喜欢意大利肉酱面,或者更具体地说,意大利肉酱面。

Photo by Nerfee Mirandilla on Unsplash
当每个人通过收银台时,他们的物品都会被扫描。购物几周后,商店里的数据科学家可以看出意大利面是一种经常和番茄酱一起买的东西。他们还可以看到,我们甚至可以说,在 50%的时间里,在家乐福购买番茄酱意大利面的人通常还会购买另一种商品:碎牛肉。
数据科学家的工作是获得统计数据(让我们保持简单),根据人们的购物习惯模式做出预测并帮助其他人做出决定。营销团队可能会决定给只买意大利面和番茄酱的人一些碎牛肉的个性化折扣,因为这可能会鼓励他们改变习惯,更经常地做一些意大利面,并在商店里多花一点钱。由于数据科学家的发现,他们还可以决定改变物品的位置,让你的祖母更容易购买杂货,方法是将装满碎牛肉的冷藏箱放在离意大利面位置更近的地方。他们的决定可能与利润有关,但也可能与客户或用户满意度有关。
关于机器学习和深度学习,我能跟奶奶说什么?
简而言之,机器学习为系统提供了自主学习和改进的能力,这意味着无需被告知具体要做什么。这个系统从经验中学习,就像人类一样。换句话说,在试图重现结果之前,系统可以通过看到不同结果的不同情况,并一遍又一遍地看到它们来学习。
让我们再举一个天气的例子,因为你奶奶可能会在电视上看天气预报。不看天气预报,人们确实知道如果天气非常潮湿,在接下来的几个小时内很有可能会下雨。人们已经知道了这一点,因为在看到下雨之前,他们已经多次感觉到潮湿。湿度是可以测量的,因此我们可以向系统显示大量关于下雨前湿度水平的数据,以及不下雨时的湿度水平。在看到数据中的许多情况后,系统可以了解到当湿度高时,有 90%的机会在接下来的 2 小时内下雨。在现实中,计算要复杂得多,我真诚地向任何有经验的气象学家道歉,但我们只是试图教奶奶一个简单的机器学习应用。
如果有人对数据和 IT 一无所知,直到现在还在听我的故事,我会让他们摆脱困境,给他们一块饼干作为对他们时间的补偿。我不会尝试进入深度学习,除非他们似乎真的感兴趣,或者开始询问自动驾驶汽车(我不会真的指望奶奶会这样,但我可能错了)。然而,即使神经网络很难详细解释,你也可以简单地提到它们是连接类似大脑连接的系统,这允许它们学习情况和结果之间更复杂的关系。
提统计没问题
数据科学是一个年轻的领域,但统计学不是。对数据科学一无所知的人很可能听说过统计学,即使他们不看电视,他们也会读报纸。不要进入 p 值和 ANOVAs。没有人在教授数据科学,我们只是想让一位老奶奶明白,我们不是航空航天工程师、统治世界的主谋或坏掉的 Windows 98 PC 工作站的服务台。

Your grandma might have never ever used these while the newest generation has never used them either. That’s the strange remarkable evolution of technology. Photo by Vincent Botta on Unsplash
最后,帮助他们理解你离航空航天工程很远的一个方法是解释你基本上是在用计算机做高级统计。你可以提到有些人就像外科医生。他们在计算机内部工作,他们可以修理计算机的物理和内部部分。然而,对你来说,电脑仅仅是你工作的工具。它应该已经开始工作了。****
不要取笑他们或忽视他们的问题
你的头可能会痛,你的工作可能会减少到一瓶番茄酱和一包意大利面。它的性感可能已经离你远去,他们会问你一些你会觉得愚蠢和恼人的问题,但你会坚持下去。当我试图解释我论文的主题,即推荐系统时,我阿姨指责我试图操纵人们(公平地说,这是有争议的),只帮助公司赚更多的钱。我感到有点不安和恼怒。首先,如果它没有以某种方式帮助公司赚钱,大多数工作可能就不会存在。其次,我试图解释通过准确的推荐来改善用户体验的想法。我做得不好,用户体验对那些在智能手机上苦苦寻找图片库的人来说毫无意义。
如果我用简单的方式回答问题,不使用行话,结果往往会更好。
有时,也值得一提的是,对某项技术的行为在几代人之间有不同的发展,他们不完全理解工具或特性背后的必要性也没关系。一代人离不开电视,另一代人离不开智能手机。
技术只是不同地适应不同的世代,反之亦然,世代不同地适应不同类型的技术。
为你的下一次家庭会议干杯!
我决定不强迫我的家人理解我的工作,而是公开回答他们的问题,用适合他们日常生活的简单答案。它可能不是对每个人都有效,也可能不是最终的解决方案,但它会有所帮助。希望你的奶奶会感兴趣,没有人会在下一次家庭会议上让你帮他们修电脑。谁知道呢,如果我们给你奶奶一个机会,她甚至可能会喜欢数据科学的概念,并对技术产生浓厚的兴趣!
作为一名数据科学家,我喜欢写这个话题,但也喜欢写交流问题&讲故事需要围绕这个话题。更多故事关注我上 中 或 推特 。
用反事实解释文档分类
D. Martens 和 F. Provost 的论文“解释数据驱动的文档分类”的摘要。

Photo by Amador Loureiro on Unsplash
注意:可解释性和可解释性在本文中可以互换使用。
需要解释
测试集度量可能无法提供模型优势和劣势的整体视图。对模型预测的解释有助于人类理解为什么会做出预测,并且在某些情况下,能够一致地预测模型的结果。这是有益的,因为:
- 受决策影响的客户可以被告知为什么要采取与他们相关的特定行动。
- 它帮助管理人员理解模型工作良好的用例。
- 数据科学家可以使用这些解释来迭代改进模型。
- 当模型是真实世界的准确表示时,对模型行为的解释可以提高对业务领域的理解。
此外,对如何做出决策的解释有时是法律或监管要求。
什么是“好”的解释?
由于输入和预测之间的关系易于理解,因此具有少量特征的较小决策树和逻辑回归模型被认为是可解释的。
然而,当这些模型涉及数百个特征时,分析特定特征对预测的影响或导致特定决策的主要因素变得势不可挡。
简明扼要并突出最重要因素的解释比提供完整因素列表的解释更容易理解。
不同种类技术的概述
- 模型不可知与模型特定 模型不可知技术独立于模型的内部工作,因此可以用于任何模型,而模型特定技术则绑定于特定类型的模型。模型不可知技术的明显优势在于,可以在不改变可解释性技术的情况下改变所使用的模型。
- 全局与局部 全局解释适用于模型做出的所有预测,并提供了模型如何做出决策的总体概述,而局部解释适用于单个预测或一组类似的预测。
该论文提出了一种模型不可知的技术来解释个人的预测。
反事实
反事实具有对比性。他们解释为什么做出一个决定而不是另一个决定。预测的反事实解释可以定义为:【2】
将预测更改为预定义输出的特征值的最小变化。
本文探讨了从文档中删除某些单词如何改变其预测类别。所提出的方法不同于大多数反事实技术,因为它产生一组单词,而不是代表不同实例的特征向量。
自然语言处理解释的特质
- 高维度: 文档的特征向量表示通常具有数量级大于结构化数据分类问题中存在的特征数量的变量数量。
高维度使得传统的可解释模型和许多全局解释技术失效。为了保持分类树的可读性,它不能包含成千上万的变量(或节点)。
另一方面,计算不同特征对预测的贡献的局部解释技术使得不清楚哪个词的组合实际上导致了给定的分类,并且对于大量的特征来说,通常在计算上非常昂贵。 - 稀疏性:
大多数文档只包含总词汇表中出现的单词的一小部分,因此,文档的基于计数的特征向量是高度稀疏的。
所提出的方法
该文件主要集中于解释为什么一个文件已收到(正确或错误的)“积极的”分类。
在本文的上下文中,一个解释被定义为;
文档中存在的一组单词,删除这些单词会导致预测类发生变化。
单词集是最小。也就是说,删除单词的任何子集都不会改变类别。
完整搜索
这种方法首先检查从文档中删除一个特定的单词是否会改变预测的类。如果类别没有因为一个单词而改变,则接下来考虑 2 个不同单词的组合。如果删除任何两个单词也没有导致类别变化,则考虑三个不同单词的组合,以此类推。
下面这个例子的解释是 E = {'computer'}。

illustrated example
该方法利用了文档表示的稀疏性,因为候选单词组合是文档中的所有单词组合,而不是整个词汇表中的单词组合。然而,这对于大型文档来说仍然是不可行的,因为其复杂性随着文档中唯一单词的数量呈指数增长。

启发式方法
贪婪搜索模型通常计算实例属于特定类别的概率,而不是硬分类,这可以被用作启发,以指导通过贪婪搜索选择接下来要移除的单词组合。
在检查了所有一个单词的解释并计算了预测类别的概率的相应变化后,在后续的单词组合中使用降低概率最大的单词。
更一般; 在搜索的每一步,给定表示部分解释的当前单词组合集,算法接下来将扩展输出分数在类别变化方向上变化最大的部分解释。扩展部分解释需要创建一组新的候选解释,包括与来自文档的一个附加单词的所有组合,该附加单词还没有包括在部分解释中。[1]
搜索空间修剪 当目标是找到多个解释时,在搜索其他解释时,不需要考虑构成解释的单词组 E 。
非线性模型
对于非线性模型,不可能估计特征相互作用对预测分类概率的影响。这导致了以下问题:
- 获得的解释可能不包含解释定义所要求的最小单词子集。也就是说,找到的解释可能会导致预测类的变化,即使在一个或多个单词从其中删除之后。
这在局部搜索后处理阶段中解决,该阶段验证从获得的解释 E 中移除一个或多个单词是否也提供了解释E’,在这种情况下,用较小的解释 E 替换 E 。 - 可能存在比获得的更小的不同单词的解释。
这在第二局部搜索后处理阶段中解决。对于每个解释,两个单词被文档中的另一个单词替换,而不是在解释中。接下来,三个词的解释由两个词的文件,还没有在解释,等等。这产生了大量要检查的潜在组合:用 m 个单词替换对一个文档的解释的一组 k 个单词产生了ᵐ⁻ᵏCₖ组合。为了处理要检查的大量新单词组合,作者进行的实验被限制在 k = 5 个单词,最多 5000 个组合。
个案研究
本文提出了一个关于将网页归类为包含不良内容的问题的实证案例研究,目的是允许广告商选择不在网页上显示他们的广告。
关于新闻故事主题分类的第二个实证演示使用了 20 个新闻组基准数据集。
其他方法的缺点
人们发现,以决策树或最具指示性的词语清单的形式进行的全面解释并没有提供令人满意的解决方案。
使用 C4.5 算法生成的具有 327 个节点的代理决策树模型的保真度仅为 87%。修剪会减小树的大小,但也会降低保真度。
在检查线性模型的单词特征权重的情况下,解释单个决策仅仅需要太多的单个单词;在解释一半的文档之前,需要超过两千个最重要的单词(3%的词汇)。
这与文档术语矩阵的稀疏性相结合,表明各个解释中的单词变化很大,并支持使用实例级解释算法。
下图也证明了这一点,该图描绘了通过考虑根据不同方法加权的前 k 个单词来解释的测试实例分类的百分比。

Source: [1]
下面具有最大面积的线是根据单词在解释中出现的频率排列的单词获得的。
解释的差异

Source: [1]
- PE:解释的测试实例的百分比(%)
- AWS:最小解释的平均字数(数字)
- 答:给出的最小解释的平均数(个)
- ANT:给出的所有解释的平均数(数字)
- ADF:找到第一个解释的平均持续时间(秒)
- ADA:找到所有解释的平均持续时间(秒)
几乎所有的文件都有少于三十几个字的解释,超过一半的文件有少于二十几个字的解释。换句话说,每个解释都非常简洁,
这些图还显示了文档解释大小变化相当平稳,并且似乎有许多不同的文档解释。前一种观察表明,单个证据的强度差异很大:一些案件通过汇总许多薄弱的证据进行分类,另一些案件通过几个强有力的证据进行分类(还有一些案件,大概是通过强证据和弱证据的组合进行分类)。后一种观察表明存在大量冗余。[1]
调试模型
解释对于调试模型很有用,特别是当它们不直观的时候。这种解释被称为过度解释。
假阴性
这种解释可能表明没有证据支持正类;更确切地说,没有与模型相关的证据。在这种情况下,模型词汇表可能需要扩展。
也有可能是负面的证据比正面的证据更重要。这里,解释技术可以被应用于寻找为什么该示例被分类为否定类别的解释,因为它们将突出模型感觉胜过文档中的肯定类别指示词的词。这将提供一个机会来更新模型的权重(通过主动特征标记)或检查包含这些单词的文档的标签。
分类器将 20 个新闻组数据集中的文章分类为“符合”或“不符合”时产生的假阴性的解释示例;
“提供销售分销”
假阳性
该解释可以表明用于将该例子分类为肯定的词实际上并不与肯定类相关联。这种解释为交互式模型开发提供了有用的支持,因为可以结合背景知识来对抗错误分类。
在其他情况下,解释可能会突出一些单词的模糊含义。
分类器将 20 个新闻组数据集中的文章分类为“符合”或“不符合”时产生的误报的解释示例;
《窗口呼叫》
这篇报道实际上属于“rec.autos”新闻组。
在解释提供的单词似乎与积极类合理相关的情况下,可以验证示例的标签。
扩展ˌ扩张
本文介绍的技术也可用于其他高维分类问题,只要单个维度(及其子集)是可解释的。
例如,根据 web 用户访问的网页对他们进行分类。每个用户可以由一个非常大的集合中的一组网页 URL 来表示。然后,用户可以通过这个词汇表上的模型进行分类。
参考
[1] D. Martens 和 F. Provost,解释数据驱动的文档分类,MIS Q .,38(1),(2014)。
[2] C. Molnar,可解释的机器学习。让黑盒模型变得可解释的指南,(2019)。
以随机森林为例解释特征的重要性

Source: https://unsplash.com/photos/BPbIWva9Bgo
了解 Python 中最流行的确定要素重要性的方法
在许多(商业)案例中,不仅有一个准确的,而且有一个可解释的模型是同样重要的。通常,除了想知道我们的模型的房价预测是什么,我们还想知道为什么会这么高/低,以及在确定预测时哪些特征是最重要的。另一个例子可能是预测客户流失——拥有一个成功预测哪些客户容易流失的模型是非常好的,但是确定哪些变量是重要的可以帮助我们及早发现,甚至改进产品/服务!
了解由机器学习模型指示的特征重要性可以在多个方面使您受益,例如:
- 通过更好地理解模型的逻辑,你不仅可以验证它是正确的,还可以通过只关注重要的变量来改进模型
- 以上内容可用于变量选择——您可以删除不太重要的 x 变量,这些变量在更短的训练时间内具有相似或更好的性能
- 在一些商业案例中,为了可解释性而牺牲一些准确性是有意义的。例如,当一家银行拒绝一项贷款申请时,它也必须有一个决策背后的理由,这个理由也可以呈现给客户
这就是为什么在这篇文章中,我想通过一个随机森林模型的例子来探索解释特性重要性的不同方法。它们中的大部分也适用于不同的模型,从线性回归开始,到黑盒(如 XGBoost)结束。
需要注意的一点是,我们的模型越精确,我们就越能相信特征重要性度量和其他解释。我假设我们构建的模型相当准确(因为每个数据科学家都会努力拥有这样的模型),在本文中,我将重点关注重要性度量。
数据
对于这个例子,我将使用波士顿房价数据集(因此是一个回归问题)。但是本文描述的方法同样适用于分类问题,唯一的区别是用于评估的度量标准。
准备数据时唯一不标准的事情是向数据集添加一个随机列。从逻辑上讲,它对因变量(以 1000 美元为单位的自有住房的中值)没有预测能力,因此它不应该是模型中的一个重要特征。让我们看看结果如何。
下面我考察随机特征和目标变量之间的关系。可以观察到,散点图上没有模式,相关性几乎为 0。


这里需要注意的一点是,解释CHAS的相关性没有多大意义,因为它是一个二元变量,应该对它使用不同的方法。
基准模型
我训练了一个简单的随机森林模型来建立一个基准。我设置了一个random_state来确保结果的可比性。我还使用了 bootstrap 并设置了oob_score = True,这样我以后就可以使用 out-of-bag 错误。
简而言之,关于出袋误差的主题,随机森林中的每棵树都在不同的数据集上训练,用原始数据的替换进行采样。这导致每个训练集中大约 2/3 的不同观察。在所有的观察值上计算出袋外误差,但是为了计算每行的误差,模型只考虑在训练期间没有看到该行的树。这类似于在验证集上评估模型。你可以在这里阅读更多。
R^2 Training Score: 0.93
OOB Score: 0.58
R^2 Validation Score: 0.76
嗯,模型中有一些过度拟合,因为它在 OOB 样本和验证集上表现得更差。但是,让我们说它足够好,并前进到特征重要性(根据训练集性能来衡量)。一些方法也可以用于验证/OOB 集,以获得对未知数据的进一步解释能力。
1.总体功能重要性
我所说的总体特征重要性是指在模型层次上得到的特征,即,也就是说在一个给定的模型中,这些特征在解释目标变量时是最重要的。
1.1.默认 Scikit-learn 的功能重要性
让我们从决策树开始,建立一些直觉。在决策树中,每个节点都是如何在单个特征中分割值的条件,以便因变量的相似值在分割后最终出现在同一集合中。该条件基于杂质,在分类问题的情况下是基尼杂质/信息增益(熵),而对于回归树是其方差。因此,当训练一棵树时,我们可以计算每个特征对减少加权杂质的贡献。feature_importances_在 Scikit 中——Learn 是基于这种逻辑,但是在随机森林的情况下,我们讨论的是对树中杂质的减少进行平均。
优点:
- 快速计算
- 易于检索—一个命令
缺点:
- 有偏见的方法,因为它倾向于夸大连续特征或高基数分类变量的重要性

似乎前 3 个最重要的特性是:
- 房间的平均数量
- %较低的人口地位
- 到五个波士顿就业中心的加权距离
然而令人惊讶的是,一列随机值竟然比:
- 每个城镇非零售商业用地的比例
- 放射状公路可达性指数
- 面积超过 25,000 平方英尺的住宅用地比例
- 查尔斯河虚拟变量(= 1,如果区域边界为河流;否则为 0)
直觉上,这个特征对目标变量的重要性应该为零。让我们看看不同的方法是如何评价它的。
1.2.置换特征重要性
这种方法通过观察每个预测器的随机重排(从而保持变量的分布)如何影响模型性能来直接测量特征重要性。
该方法可以用以下步骤来描述:
- 训练基线模型,并通过验证集(或随机森林情况下的 OOB 集)记录分数(准确性/R/任何重要性度量)。这也可以在训练集上完成,代价是牺牲关于泛化的信息。
- 重新排列所选数据集中一个要素的值,将数据集再次传递给模型以获得预测,并计算此修改后的数据集的度量。特征重要性是基准分数和来自修改(置换)数据集的分数之间的差异。
- 重复 2。对于数据集中的所有要素。
优点:
- 适用于任何型号
- 相当有效
- 可靠的技术
- 不需要在每次修改数据集时重新训练模型
缺点:
- 比默认的
feature_importances计算量更大 - 排列重要性高估了相关预测值的重要性——施特罗布尔等 (2008)
至于这个方法的第二个问题,我已经在上面画出了相关矩阵。然而,我将使用我使用的库中的一个函数来可视化 Spearman 的相关性。标准皮尔逊相关的区别在于,它首先将变量转换为等级,然后才对等级进行皮尔逊相关。
斯皮尔曼关联:
- 是非参数的
- 不假设变量之间的线性关系
- 它寻找单调的关系。

我找到了两个具有这种功能的库,并不是说它很难编码。让我们来看一下这两种,因为它们有一些独特的特点。
rfpimp
关于这个库需要注意的一点是,我们必须提供一个度量作为表单metric(model, X, y)的函数。这样,我们可以使用更高级的方法,如使用随机森林的 OOB 分数。该库已经包含该功能(oob_regression_r2_score))。但是为了保持方法的一致性,我将在训练集上计算度量(丢失关于泛化的信息)。

这个图证实了我们在上面看到的,4 个变量没有一个随机变量重要!令人惊讶的是…前四名仍然保持不变。关于rfpimp的一个更好的特性是它包含了处理共线特性问题的功能(这是展示 Spearman 相关矩阵背后的想法)。为了简洁,我不会在这里展示这个案例,但是你可以在这个库的作者写的这篇伟大的文章中读到更多。
eli5
与rfpimp的基本方法和eli5中使用的方法有一些不同。其中一些是:
- 有与使用交叉验证相关的参数
cv和refit。在本例中,我将它们设置为None,因为我并不使用它,但在某些情况下它可能会派上用场。 - 有一个
metric参数,它像在rfpimp中一样接受一个metric(model, X, y)形式的函数。如果未指定该参数,该函数将使用估计器的默认score方法。 n_iter-随机洗牌迭代次数,最终得分为平均值

结果与前面的非常相似,尽管这些结果来自每列的多次重新排列。关于eli5的一个额外的好处是,通过使用 Scikit-learn 的SelectFromModel或RFE,使用置换方法的结果来执行特征选择真的很容易。
1.3.删除列功能重要性
这种方法非常直观,因为我们通过比较具有所有特性的模型和不具有该特性的模型来研究特性的重要性。
我为下面的方法创建了一个函数(基于rfpimp的实现),展示了底层逻辑。
优点:
- 最准确的特征重要性
缺点:
- 由于为数据集的每个变量重新训练模型(删除单个要素列后),潜在的高计算成本

这里变得有趣了。首先,负重要性,在这种情况下,意味着从模型中删除给定的特性实际上提高了性能。这在我们的随机变量中是很好的例子。
或者,代替拟合模型的默认score方法,我们可以使用出袋误差来评估特征重要性。为此,我们需要将上述要点中的score方法替换为model.oob_score_(记住对循环中的基准和模型都要这样做)。
2.观察级别特征重要性
我所说的观察水平特征重要性是指对解释输入到模型中的特定观察有最大影响的特征。例如,在信用评分的情况下,我们可以说这些特征对确定客户的信用评分影响最大。
2.1.树解释器
treeinterpreter的主要思想是,它使用随机森林中的底层树来解释每个特征如何对最终值做出贡献。我们可以观察预测值(定义为每个特征贡献的总和+由基于整个训练集的初始节点给出的平均值)如何沿着决策树内的预测路径变化(在每次分割之后),以及哪些特征导致了分割的信息(预测的变化也是如此)。
预测函数(f(x))的公式可以写为:

其中 c_full 是整个数据集(初始结点)的平均值,K 是要素的总数。
这听起来可能很复杂,但是请看库的作者提供的一个例子:

source: http://blog.datadive.net/interpreting-random-forests/
由于随机森林的预测是这些树的平均值,因此平均值预测的公式如下:

其中 J 是森林中树木的数量。
我从识别具有最低和最高绝对预测误差的行开始,并试图找出造成差异的原因。
Index with smallest error: 31
Index with largest error: 85
使用treeintrerpreter,我获得了 3 个对象:预测、偏差(数据集的平均值)和贡献。
对于误差最小的观察结果,主要贡献者是LSTAT和RM(在以前的案例中,它们被证明是最重要的变量)。在最高误差的情况下,最高贡献来自DIS变量,克服了在第一种情况下起最重要作用的两个变量。
Row 31
Prediction: 21.996 Actual Value: 22.0
Bias (trainset mean) 22.544297029702978
Feature contributions:
LSTAT 3.02
RM -3.01
PTRATIO 0.36
AGE -0.29
DIS -0.21
random 0.18
RAD -0.17
NOX -0.16
TAX -0.11
CRIM -0.07
B -0.05
INDUS -0.02
ZN -0.01
CHAS -0.01
--------------------
Row 85
Prediction: 36.816 Actual Value: 50.0
Bias (trainset mean) 22.544297029702978
Feature contributions:
DIS 7.7
LSTAT 3.33
RM -1.88
CRIM 1.87
TAX 1.32
NOX 1.02
B 0.54
CHAS 0.36
PTRATIO -0.25
RAD 0.17
AGE 0.13
INDUS -0.03
random -0.01
ZN 0.0
---------------------
为了更深入,我们可能还对许多变量的联合贡献感兴趣(如 XOR 和这里的的例子中所解释的)。我将直接看示例,更多信息可以在链接下找到。
最佳和最差预测案例之间的大部分差异来自房间数量(RM)特征,以及到五个波士顿就业中心的加权距离(DIS)。
2.2.石灰
LIME(局部可解释模型不可知解释)是一种以可解释和忠实的方式解释任何分类器/回归器预测的技术。为此,通过用一个可解释的模型(如带有正则化的线性模型或决策树)局部逼近所选模型来获得解释。可解释的模型是在原始观测值(表格数据情况下的 row)的小扰动(添加噪声)上训练的,因此它们仅提供良好的局部近似。
需要注意的一些缺点:
- 只有线性模型用于近似局部行为
- 为了获得正确的解释,需要对数据进行的扰动类型通常是特定于用例的
- 简单的(默认)扰动通常是不够的。在理想情况下,修改将由数据集中观察到的变化驱动
下面你可以看到 LIME 解释的输出。
输出有 3 部分:
1。预测值
2。特征重要性-在回归的情况下,它显示它对预测有负面影响还是正面影响,按绝对影响降序排序。
3。所解释行的这些特性的实际值。
请注意,LIME 在解释中离散化了特征。这是因为在上面的构造函数中设置了discretize_continuous=True。之所以离散化,是因为它给了连续的特征更直观的解释。

LIME 解释同意,对于这两种观测,最重要的特征是RM和LSTAT,这也是之前的方法所指出的。
我收到了一个有趣的问题:我们应该相信哪种观察水平的方法,因为结果可能会有所不同?这是一个没有明确答案的难题,因为这两种方法在概念上是不同的,因此很难直接比较。我建议你参考这个答案,其中有一个类似的问题得到了解决并得到了很好的解释。
结论
在本文中,我展示了几种从机器学习模型(不限于随机森林)中获得特征重要性的方法。我认为理解结果通常与获得好的结果一样重要,因此每个数据科学家都应该尽最大努力理解哪些变量对模型最重要,以及为什么。这不仅有助于获得更好的业务理解,还可以导致模型的进一步改进。
您可以在我的 GitHub 上找到本文使用的代码。一如既往,我们欢迎任何建设性的反馈。你可以在推特或评论中联系我。
喜欢这篇文章吗?成为一个媒介成员,通过无限制的阅读继续学习。如果你使用这个链接成为会员,你将支持我,而不需要额外的费用。提前感谢,再见!
参考
我最近出版了一本关于使用 Python 解决金融领域实际任务的书。如果你有兴趣,我贴了一篇文章介绍这本书的内容。你可以在亚马逊或者 Packt 的网站上买到这本书。
向我的侄子解释排列
用乐高

Unsplash
有一天,当我和我的侄子玩他的乐高玩具时,我想出了一个想法,试图向他解释什么是排列。基本上,一组对象的排列是对它们进行排序的一种方式。例如,对于一组 3 个物体(我们将其命名为 A、B 和 C ),我们有以下 6 种排列:
ABC | BAC | CAB
ACB | BCA | CBA
现在我们知道了什么是排列,让我们以我和我侄子的例子为例。
这个例子
这是我侄子的乐高大众汽车的代表,有 8 个座位来容纳乐高。
如果我们有 8 块乐高积木,有多少种排列方式(例如,在大众汽车内排列乐高积木的不同方式)?

- 乐高玩具有 8 种可能被分配到第一个座位。
- 对于这 8 种可能性中的每一种,都有 7 种可能将另一个乐高分配到驾驶座的右侧(因为我们已经给驾驶座分配了 1 个乐高,所以只剩下 7 个乐高)。因此,前两个座位的乐高玩具有 8 * 7= 56 种选择。
- 对于这 56 种可能性中的每一种,都有 6 种可能性将另一个乐高分配给司机后面的座位。因此,前三个座位的乐高玩具有 8 * 7 * 6 = 336 种选择方式。
- 对于这 336 个座位中的每一个,都有 5 种可能将另一个乐高积木分配到下一个座位(中间的那个)。
因此有 8 * 7 * 6 * 5 = 1680 种可能性 - 如果我们继续这样下去…我们最后只剩下一个可能的乐高玩具,被分配到最后一个座位(右下角的座位)。因此有:
8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 = 40320 种可能性
40320 种排列!如果我和我的侄子尝试了每一种不同的可能性,我们将永远不会成功!
阶乘——有效的方法
上述策略工作良好,但我猜你同意这是相当乏味的。使用阶乘更有效。阶乘表示为N! 并计算如下:
1!= 1 = 1
2!= 1 * 2 = 2
3!= 1 * 2 * 3 = 6
…
N 个物体的排列数因此为 N! 按照我们的例子,我们有 N = 8 (例如 8 个乐高)等于 8!= 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 = 40,320 种排列。
那天,在玩完乐高玩具后,我开车送我的侄子回家,我问他:“你知道在这辆车里给 4 个不同的人分配一个座位有多少种排列吗?”经过一段时间的思考,他得出了正确的答案!成功!他明白了!
PD:你也会知道吗?
如果你想联系,这是我的 LinkedIn 。
解释概率图

它们是什么,如何用 Python 实现它们,以及如何解释结果
1.介绍
在使用线性回归时,您可能已经遇到过一种类型的概率图—Q-Q 图。拟合模型后,我们应该检查的回归假设之一是残差是否遵循正态(高斯)分布。这通常可以通过使用 Q-Q 图来直观地验证,如下图所示。

Example of Q-Q plot
为了充分理解概率图的概念,让我们快速回顾一下概率论/统计学中的一些定义:
- 概率密度函数(PDF)——允许我们计算在属于样本空间的任何区间内找到随机变量的概率的函数。重要的是要记住,连续随机变量取精确值的概率等于 0。

PDF of Gaussian Distribution
- 累积分布函数(CDF)——提供随机变量取值等于或小于给定值 x 的概率的函数。当我们处理连续变量时,CDF 是在负无穷大到 x 范围内 PDF 下的面积。

General formula for CDF, X — random variable, x — point of evaluation
- 分位数——引用维基百科:“将概率分布范围划分为具有相等概率的连续区间的切割点”
下图显示了从标准正态分布以及 PDF 和 CDF 中抽取的随机变量的分布。

在本文中,我将使用另外两个发行版进行比较:
- 平均值为 1、标准差为 2.5 的正态分布— N(1,2.5)
- α= 5 的偏斜正态分布
我使用偏斜正态分布,因为通过调整 alpha 参数(同时将比例和位置保留为默认值)我可以控制分布的偏斜度。随着α的绝对值增加,偏斜度的绝对值也增加。下面我们可以通过观察随机变量的直方图来考察分布的差异。

2.概率图
我们使用概率图来直观地比较来自不同数据集(分布)的数据。可能的情况包括比较:
- 两个经验集
- 一组经验数据和一组理论数据
- 两个理论集
概率图最常见的用途是中间图,当我们将观察到的(经验)数据与来自特定理论分布(如高斯分布)的数据进行比较时。我用这个变体来解释下面的特殊类型的情节,但是,它也可以应用于其他两种情况。
2.1 峰峰值图
简而言之,P-P(概率-概率)图是绘制两种分布(经验的和理论的)的 CDF 的可视化图。

Example of a P-P plot comparing random numbers drawn from N(0, 1) to Standard Normal — perfect match
峰峰值图的一些关键信息:
- 图上的点的解释:假设我们有两个分布( f 和 g )和一个评估点 z (任何值),图上的点指示在 f 和 g (根据 CDF 的定义)中位于或低于 z 的数据百分比。
- 为了比较这些分布,我们检查这些点是否位于一条 45 度线上( x=y )。如果它们出现偏差,分布就会不同。
- P-P 图非常适合于比较高概率密度区域(分布中心),因为在这些区域,经验和理论 CDF 比低概率密度区域变化更快。
- P-P 图需要完全指定的分布,因此如果我们使用高斯作为理论分布,我们应该指定位置和比例参数。
- 改变位置或比例参数不一定能保持峰峰值图的线性。
- P-P 图可以用来直观地评估分布的偏斜度。
- 当分布不重叠时,绘图可能会导致奇怪的模式(例如,沿着图表的轴)。所以 P-P 图在比较位置相近或相等的概率分布时最有用。下面我给出一个 P-P 图,比较从 N(1,2.5) 抽取的随机变量和从 N(5,1) 抽取的随机变量。

Random Variables drawn from N(1, 2.5) vs. N(5, 1)
2.2.Q-Q 图
与 P-P 图类似,Q-Q(分位数-分位数)图允许我们通过绘制它们的分位数来比较分布。
Q-Q 图的一些关键信息:
- 图上的点的解释:图上的一个点对应于来自两种分布的某个分位数(同样在大多数情况下是经验的和理论的)。
- 在 Q-Q 图上,参考线取决于理论分布的位置和比例参数。截距和斜率分别等于位置和比例参数。
- 点中的线性模式表明给定的分布族合理地描述了经验数据分布。
- Q-Q 图在分布的尾部获得了非常好的分辨率,但在中心(概率密度高)分辨率较差
- Q-Q 图不需要指定理论分布的位置和比例参数,因为理论分位数是根据指定族中的标准分布计算的。
- 点模式的线性不受改变位置或比例参数的影响。
- Q-Q 图可用于直观评估两种分布的位置、规模和偏斜度的相似性。
3.Python 中的示例
我使用statsmodels库和[*ProbPlot*](https://www.statsmodels.org/dev/generated/statsmodels.graphics.gofplots.ProbPlot.html)类创建概率图。
数据
首先,我生成了来自三种分布的随机观察值:标准正态、正态和斜正态。您可以在下面的代码片段中看到分布的确切参数。
峰峰值图
当我开始使用statsmodels 创建一些 P-P 图时,我注意到一个问题——当我比较从 N(1,2.5)到标准常态的随机抽取时,该图是完美的拟合,而它不应该是。我试图调查这个问题,并在 StackOverflow 上找到了一个帖子,解释了当前的实现总是试图估计理论分布的位置和比例参数,即使提供了一些值。所以在上面的例子中,我们正在检查我们的经验数据是否来自正态分布,而不是我们指定的那个。
这就是为什么我写了一个函数,用提供的参数直接比较经验数据和理论分布。
让我们首先尝试使用statsmodels和pp_plot来比较从 N(1,2.5)到 N(0,1)的随机抽取。我们看到,在statsmodels 的情况下,这是一个完美的拟合,因为该函数估计了正态分布的位置和比例参数。当检查pp_plot的结果时,我们看到分布明显不同,这也可以在直方图上观察到。

P-P plots of N(1, 2.5) vs. Standard Normal
我们也试着从pp_plot解读一下 P-P 图的形态。为此,我将再次展示图表以及直方图。沿着 x 轴的水平移动是由分布不完全重叠的事实引起的。当该点高于参考线时,意味着理论分布的 CDF 值高于经验分布的 CDF 值。

下一个例子是比较从倾斜法线到标准法线的随机绘制。我们看到statsmodels的图暗示它不是一个完美的匹配,因为它很难找到正态分布的位置和比例参数,这些参数说明了所提供数据的偏斜度。该图还显示,标准正态分布的 CDF 值总是高于所考虑的偏态分布的 CDF 值。

P-P plots of Skew Normal (alpha=5) vs Standard Normal
注意:我们也可以使用statsmodels 获得完美的拟合。为此,我们需要将proplot中的理论分布指定为skewnorm,并传递一个额外的参数distargs=(5,) 来指示α的值。
Q-Q 图
应用和解释
让我们从比较偏斜正态分布和标准正态分布(使用ProbPlot’s默认设置)开始。

Q-Q plots of Skew Normal (alpha=5) vs Standard Normal
可以观察到的第一件事是,点形成曲线而不是直线,这通常是样本数据偏斜的指示。另一种解释图表的方法是看分布的尾部。在这种情况下,与标准正态分布相比,所考虑的偏斜正态分布具有较轻的左尾(质量较小,点位于 Q-Q 图的左侧,线上方)和较重的右尾(质量较大,点位于 Q-Q 图的右侧,线上方)。我们需要记住,偏态分布是移动的(可以在直方图上观察到),所以这些结果符合我们的预期。
我还想快速回顾一下同一个练习的另外两个变化。在第一个示例中,我将理论分布指定为偏斜正态分布,并在distargs中传递alpha=5。这导致了下面的图,在图中我们看到了一个线性(虽然与标准参考线相比有所偏移)的图形。然而,线型基本上是一条 45 度线,表明拟合良好(在这种情况下,标准化参考线不是一个好的选择)。

Q-Q plots of Skew Normal (alpha=5) vs Skew Normal (alpha=5)
第二种方法是比较两个经验样本——一个来自偏斜正态(alpha=5),另一个来自标准正态。我设置fit=False 是为了关闭位置、比例和distargs的自动拟合。
结果似乎符合最初的方法(这是一个好迹象:)。

利用股票收益的例子
我还想展示一个使用 Q-Q 图评估微软股票价格产生的回报是否遵循正态分布的实际例子(更多细节请参考本文中的)。结论是尾部的质量肯定比正常情况下假设的要大(表明更多的负和正回报)。

Returns on MSFT vs Norma Distribution
进一步实施细节
在ProbPlot的qqplot方法中,我们可以指定想要绘制哪种参考线。选项(除了None没有线)有:
- s -标准化线(预期订单统计数据按给定样本的标准偏差缩放,并加上平均值)
- 通过四分位数的 q 线拟合
- r 回归线
- 45 - y=x 线(P-P 图中使用的线)
下面我展示了三种方法的比较,正如我们所见,它们非常相似。

当使用 Q-Q 图时,我们还可以使用statsmodels的另一个特性,它采用不超过概率代替理论分位数(*probplot*方法代替*qqplot*)。
你可以在这里阅读更多关于这种方法的信息。

4.总结
在本文中,我试图以 P-P 和 Q-Q 图为例解释概率图的关键概念。你可以在我的 GitHub 上找到用于生成文章中提到的情节的代码的笔记本。如果你有问题或建议,请在评论中告诉我,或者在 Twitter 上联系我。
喜欢这篇文章吗?成为一个媒介成员,通过无限制的阅读继续学习。如果你使用这个链接成为会员,你将支持我,不需要你额外付费。提前感谢,再见!
您可能还会对以下内容感兴趣:
这在分类变量、序数变量和区间变量之间也是一致的!
towardsdatascience.com](/phik-k-get-familiar-with-the-latest-correlation-coefficient-9ba0032b37e7) [## 预测强度—一种简单但相对未知的评估聚类的方法
了解该标准如何工作,以及如何从头开始用 Python 实现它!
towardsdatascience.com](/prediction-strength-a-simple-yet-relatively-unknown-way-to-evaluate-clustering-2e5eaf56643) [## Python 统计块中的新成员:pingouin
图书馆的快速参观,以及它是如何从老守卫中脱颖而出的
towardsdatascience.com](/the-new-kid-on-the-statistics-in-python-block-pingouin-6b353a1db57c)
参考
- https://www . quora . com/In-laymans-terms-a-P-P-plot-and-a-Q-Q-plot-and-when-we-use-one-or-other
- 【http://v8doc.sas.com/sashtml/qc/chap8/sect9.htm 号
- https://www . stats models . org/stable/generated/stats models . graphics . gofplots . prob plot . QQ plot . html
用非技术性的方式解释技术性的东西——(Py)Spark
什么是 Spark 和 PySpark,我可以用它做什么?

Photo by Markus Spiske on Unsplash
在一次巴斯克维尔分析系统的展示中,我被要求向一个完全不懂技术的人解释 T2 阿帕奇火花。这让我有些困惑,因为我非常习惯于用代码思考和交流,我的头脑只是不停地回到技术术语上,所以我相信我在非常有限的时间里没有做好工作。让我们再试一次,为了那个问我的人,因为我相信尽可能简单地解释事情是一项需要培养的伟大技能。
旁注:sketch nothing
我一直在读 Christina R Wodtke 的《铅笔我》(Pencil Me In)一书,该书谈到了素描笔记,即保持视觉笔记以帮助理解和记忆的过程。我一直是一个视觉型的人,童年时经常涂鸦——这确实帮助我更好地记忆事物,有时也给我带来麻烦。因为我在媒体上写作的整个过程是为了让我更好地理解我认为我知道的东西,也为了学习新的东西,我想我应该再试一次。自从我上次这样做已经有很长时间了,我现在非常习惯于打字而不是写作(翻译:可怕的草图来了!),所以请手下留情。
不可能的作业
我想首先要做的是提供一个任何人,或者几乎任何人都能理解的例子。因此,假设你有一周内到期的作业,你必须做的是阅读一本 7K 页的巨著,并统计作者使用“大数据”一词的次数,最好还能保留包含它的短语(这是一项愚蠢的任务,但请耐心等待:)。

The “impossible” homework
考虑到时间限制,这是一项不可能完成的任务,即使你没日没夜地阅读,你也不可能在一周内完成。但是,你并不孤单,所以你决定和你的同学和朋友谈谈,想出一个解决办法。
似乎合乎逻辑的是,你们将页面分开,每个人至少负责几页。同样有意义的是,你们每个人带回家阅读的页面,都有相关的内容,所以你们将要阅读的内容是有意义的,所以你们试着按章节分开。
看起来也需要一个协调员。假设你接受了那个任务,因为它是你的主意。(理想情况下,你自己会花上一两章,但假设管理和沟通会占用你大部分时间)

Help each other!
另一件要考虑的事情是根据谁有最多的可用时间,谁是快速阅读者或慢速阅读者来划分页面,以便这个过程尽可能高效,对吗?此外,你们中的一些人可能在一周内有其他作业要做,所以这也必须被考虑在内。

Communicate with each other, know the availability and distribute work accordingly
在这一周里,和你的同学聊聊天,看看他们做得怎么样,这是很好的。当然,由于阅读这些章节不会一蹴而就,使用书签来记录你的进度,并跟踪你的任务进度

Bookmark, keep track and redistribute work in case of failure
如果你不得不计算一个以上的术语呢?页面的分割可能应该根据章节的标题和章节包含术语的可能性来完成。如果发生了一些事情,你们中的一个不能完成任务怎么办?相应的页面应该重新分配给你们其余的人,理想情况下取决于你们每个人还剩多少页。
最后,你们将所有人聚集在一起,把你们的计数加起来,得到你们的结果。
因此,总而言之,要完成这项任务,有必要:
- 在同学之间分配章节
- 既然是你的主意,而且你知道事情应该如何发展,你有组织事情吗
- 根据每个学生的能力划分章节——考虑阅读速度和可用性
- 如果有事发生,一个人不能完成他们的部分,重新分配工作
- 记录事情的进展——使用书签,和你的同学交谈来记录他们的进展,等等。
- 结束时聚在一起分享和组合结果
这与 Spark 和 PySpark 有什么关系——更专业一点
家庭作业示例说明了(我的理解是)Apache Spark(以及许多类似的框架和系统,例如水平或垂直数据“分片”)背后的过于简化的基本思想,将数据分成合理的组(在 Spark 的情况下称为“分区”),假设您知道您必须对数据执行什么样的任务,以便您是高效的,并将这些分区分配给理想情况下相等数量的工作人员(或者您的系统可以提供的尽可能多的工作人员)。这些工作者可以在同一台机器上,也可以在不同的机器上,例如,每个工作者在一台机器(节点)上。必须有一个协调者来协调所有这些工作,收集执行任务所需的所有必要信息,并在失败时重新分配负载。在协调员和工人之间也需要有一个(网络)连接,以便沟通和交换数据和信息。或者甚至在失败的情况下或者在计算需要时重新划分数据(例如,我们需要独立地对每一行数据进行计算,但是我们需要通过一个键对这些行进行分组)。还有一个概念是以一种“懒惰”的方式做事,使用缓存来跟踪中间结果,而不必总是从头开始计算一切。
PySpark 是 Apache Spark 的 python 实现,是“大规模数据处理的统一分析引擎”。
请注意,这不是与 Spark 组件的精确和一对一的比较,但在概念上很接近。为了简单起见,我还省略了许多 Spark 内部和结构。如果你想更深入地了解这一点,从官方的 Apache Spark 站点开始,这里有大量的资源。

Comparison with Spark
我前面提到的图片中的比较并不准确。让我们再试一次,让老师也参与进来。教师提供作业和指导(驱动程序),学生被分成工作组,每个工作组负责一部分任务。为了简洁起见——也为了让我的画不那么复杂,让我的生活简单一点,下图展示了一个工作组与 Spark 的对比。我觉得这更接近于 Spark 应用程序运行时的实际情况。

Perhaps a better comparison with Spark
简单地说,用更专业的术语来说,假设您的计算机上有一个巨大的文本文件(好吧,不是大数据文件,而是一个 15GB 的文件),您非常想知道其中有多少个单词,或者像上面的作业一样,术语“大数据”在其中出现了多少次,以及相关的短语,您将面临以下问题:
- 你真的不能用记事本打开这个文件,因为即使你有 32GB 的内存,用来打开和编辑文本文件的应用程序对于 15GB 的文件来说实际上是不可用的。
- 你可以编写一些代码来计算这个文件中的单词或特定的单词或短语,或者通过逐行阅读,或者使用类似“wc”的东西,这取决于你的系统,但它会慢,非常慢。如果你需要做更复杂的事情呢?
因此,我们立即发现没有快速简单的方法来做简单的事情,更不用说用大文件做复杂的事情了。
人们可以想到几种变通办法,比如将大文件分成许多小文件,处理这些小文件,然后将结果相加,利用多重处理技术。这就是 Spark 提供简单解决方案的地方。让我们看一个非常基本的 PySpark 例子,使用 python 库为 pyspark 编程。
Doing the homework — Reading a file with PySpark
看起来很简单,不是吗?只有几行 Python 代码。现在让我们解释一下它的功能:
Doing the homework — Reading a file with PySpark explained
没有明显的把文件分割成“章节”,没有协调,没有跟踪,什么都没有。这是因为 Spark 将在幕后处理所有的复杂性,我们不必担心告诉工作人员和执行者读取文件的一部分或如何分割它,或者如果执行者突然删除它的一部分会发生什么等等。所以,在这里,我们只用了几行代码就完成了我们的功课。
不要误会我的意思,Spark 看起来很简单,但它背后有很多复杂性,对它进行故障排除根本不是一件容易的事情,但是,让我们现在只欣赏好的部分,我们可以稍后再讨论困难。
此外,这里的例子是最简单的例子之一,但是我相信,一旦你理解了这种框架背后的机制和逻辑,就更容易理解你能用它们做什么,更重要的是,不能用它们做什么,如何构建利用这些框架的系统,以及如何善于估计以某种方式做事是否快速有效。同样,为了简单起见,我现在不会深入讨论这个问题。
我希望这有所帮助。任何想法,问题,更正和建议都非常欢迎:)
用数据科学解释 2019 年英国大选结果
使用排列重要性揭开黑盒模型的盖子
9 月 2 日,英国首相鲍里斯·约翰逊站在唐宁街 10 号的台阶上宣布他不想举行大选。任何有一点政治常识的人都知道接下来会发生什么。
12 月 13 日星期五(自然日)早上,英国醒来后发现鲍里斯·约翰逊赢得了自玛格丽特·撒切尔时代以来最大的保守党选举胜利。

Image: The Independent
保守党的胜利既是任何特定的保守党力量的产物,也是拙劣的反对的产物。选民哀叹他们面临的可怕选择——在整个竞选过程中,每一位政党领袖都有的负面支持率,而约翰逊则像躲避瘟疫一样躲避媒体的审查(甚至在竞选的最后一天躲进工业冰箱以躲避电视直播采访)。
尽管保守党耍了花招,反对党工党还是取得了自 20 世纪 30 年代以来最糟糕的结果。他们在他们的护身符“红墙”中输得很惨——这是一系列后工业时代的英国选区(类似于美国的铁锈地带),其中许多人有史以来第一次投票支持保守党。
如此令人震惊的结果能被预测到吗?如果是这样的话,有人对此做过什么吗?即使没有,工党能从如此惨痛的失败中吸取什么教训吗?这些都是政治学家能够很好回答的问题。领导素质、竞选策略和媒体的作用都是值得探讨的定性因素。
然而,这是一个数据科学博客。因此,我们将试图从模糊的个性和政策问题中解脱出来,并着手处理一些冷酷的数字。在我们这样做之前,最好准确理解英国的政治体系是如何运作的,因为这将为我们如何进行分析提供信息。
英国政治速成班
英国的政治权力在下议院(或议会)。它由 650 名议员组成,英国 650 个“选区”各一名。

Results of the 2019 General Election, with each constituency represented by a single hex of equal size.
在大选中,每个选区从候选人中选出一名议员。在那个选区得票最多的候选人当选为议员。拥有最多当选议员的政党赢得选举,并通常组建政府。
这种制度被称为“得票最多者当选”(FPTP)。这可能会导致一个政党的总体普选份额和它在下议院赢得的席位份额之间出现显著差异。
例如,2015 年,保守党仅以 37%的普选票数赢得了超过一半的席位。另一方面,英国独立党(UKIP)仅赢得一个席位(占全部席位的 0.015%),占全国选票的 13%。

The UK parties on a (very) rough 2D political compass. Note — the SNP only contest seats in Scotland, and Plaid Cymru only contest seats in Wales
这是一个明确有助于英国两大政党——自 1922 年以来赢得每一次大选的保守党和工党——的投票系统。
FPTP 出现的另一个现象是“安全席位”——几乎肯定会以某种方式投票的选区。在 2019 年大选之前,自第二次世界大战以来,有 170 个选区投票给了同一个政党(北什罗普郡的选区可能是最安全的席位——自 1834 年以来一直由保守党控制)。
数据科学派上了用场
尽管总有支配性的国家因素影响人们如何投票,但大选本质上是 650 个地方迷你选举。因此,我们应该尽可能多地了解这些独立选区的人口统计数据。
令人高兴的是,通过政府网站可以在选区一级获得很多官方数据,特别是 https://commonslibrary.parliament.uk/local-data/
我们可以将各种 CSV 整合在一起,创建一个跨一系列指标的选区 KPI 大表;从房价、周薪和人口密度,到教育程度、种族,甚至宽带质量。

A full list of KPIs used. The dataset has 110 features in total.
这样做的最终目的是创建一个模型,利用这些人口统计数据来预测哪个政党可能在每个选区获胜。一旦我们开发了一个准确的模型,我们就可以分析它,看看最重要的驱动因素是什么,从而推断出最大的选举因素。
但是,在我们这样做之前,调查一下这些 KPI 的地理分布以及它们所显示的地区差异可能会让我们大开眼界。
例如,我们看到伦敦和东南部选区的工资较高,这对任何英国居民来说都不应感到意外。然而,与英国其他地方相比,这些地方的房价增长如此之快,以至于平均房价高达年薪的 30 倍(其他地方是 5-10 倍)。

你住在哪里也与你可能从事的行业类型密切相关。

蓝领工作(例如,重工业和酒店业)在英格兰中部和北部更为普遍——白领行业(金融服务、IT 和科学)聚集在城市,尤其是伦敦。也许不出所料,白领工人多的选区工资高,失业率低。

Amber markers suggest lower wages, purple suggest higher wages
这种“伦敦对其他地方”的叙述贯穿了大部分数据;伦敦人往往比该国其他地方的人素质更高,种族更多样化,也更国际化。



当我们想到当前英国政治的大恶魔:英国退出欧盟时,这些因素都会发挥作用。这里不是讨论离开欧盟的任何好处(或坏处)的地方,但忽视它对 2019 年大选的影响显然是一个错误。
首先要注意的是英国退出欧盟产生的意见的多样性。尽管全国范围内的胜利差距非常小,只有 52%对 48%,但这一选票在各选区的分布并不均匀。一些地区的脱欧投票率低至 20%,但其他地区高达 75%。

不出所料,这种价差似乎取决于地理位置。我们注意到伦敦以外的强烈脱欧投票——主要是在英格兰中部。

英国退出欧盟的驱动因素复杂多样,然而,有一些个人特征与选区的脱欧投票密切相关——资格水平和行业。

一个选区的休假投票比例与拥有第 4 级+第 1 级资格(学位或同等学历)的人数比例之间的相关系数非常低,为-0.72,而休假投票比例与重工业工作人员比例之间的相关系数非常高,为+0.72。
虽然必须处理要素共线性(该数据集显然存在),但我认为您可以轻松创建一个模型来完美预测选区的脱欧投票。
YouGov 的 MRP 建模
虽然分析欧盟公投是一个我们可以愉快地花时间下降的兔子洞,但上述数据收集的目的是为每个选区如何在大选中投票创建一些预测模型。
因此,这将成为一个分类问题,该模型将决定该选区是给定政党的安全席位,还是两个给定政党之间的边缘席位(如果第一名和第二名之间的差距小于 15 个百分点,我们将该席位定义为“边缘”)。
我们还应该记住,这个练习的一部分是关于在竞选期间是否可以做些什么来改变最终结果。为此,我们将使用 11 月 27 日(投票日前两周多)公布的 YouGov 的 MRP 民调结果,而不是使用 2019 年最终选举结果作为我们的目标。
MRP ( 后分层多水平回归)是一种先进的民意调查方法,而 YouGov 民意调查的样本量非常大,在七天的时间里有超过 10 万人做出了回应。因此,它能够给出每个选区中每个政党的预计投票份额。结果,它略微低估了保守党在席位方面的成功,尽管它对总体投票份额的预测是与主要政党最终结果相差 1-2%。

A Sankey Diagram showing how the seat types were going to change from the 2017 election compared to the 2019 election, based on YouGov’s MRP poll projections
YouGov 的 MRP 民意调查显示了工党的悲惨处境。三分之一以前是保守党/工党边缘的席位现在看起来像他们是安全的保守党,2017 年高达 30%的安全工党席位现在看起来好像他们将成为保守党边缘。
相比之下,保守党将失去很少的安全席位,而且他们在以前处于边缘地位的大多数席位上仍然具有竞争力。
为 2019 年大选建模
现在我们已经有了每个选区的特性和目标值,我们可以进行最后两步了:
- 在给定特征集的情况下,为每个选区建立一个尽可能准确地预测目标的模型。
- 使用排列重要性调查模型,查看哪些要素对模型的准确性影响最大。
作为第一步,我们需要解决数据集的类不平衡问题。该数据集目前有超过 250 个保守党安全席位,但只有四个自由民主党安全席位(和四个其他类型的席位各一个)。

这不是训练模型的合适数据集-我们可能会使模型过度适应大多数类。为了解决这个问题,我们将使用 SMOTE 算法为少数类生成合成数据点。这在 Python 中实现起来相对简单。
*#import the library* **from** imblearn.over_sampling **import** SMOTE*#create a SMOTE object*
smote = SMOTE(k_neighbors=3)*#use the .fit_sample() method to create a new feature and target set that has an equal number of datapoints from each class*
X_smote, y_smote = smote.fit_sample(X, y)
注意,由于 SMOTE 使用“最近邻”算法,我们不能对只有一个数据点的类进行合成。因此,我们将从今后的分析中去掉这些阶层(这些阶层只代表议会中 0.5%的席位,所以这不会过度影响分析)。
鉴于我们的分析将取决于我们训练高度精确模型的能力,我们应该:
- 尝试不同类型的算法
- 为每种算法尝试不同的超参数
最简单的方法是通过一个“网格搜索方法,我们为每个想要测试的超参数指定所有不同的值,然后让代码依次迭代它们,看看哪个组合产生最好的结果。
这很容易在代码中实现,如果我们使用 Scikit Learn,它还带有额外的内置交叉验证,这意味着我们不需要为训练/测试分割而烦恼。
*#Here, we will perform a gridsearch using the XGBoost algorithm**#Bring in the required libraries* **from** sklearn.model_selection **import** GridSearchCV
**import** xgboost **as** xgb*#Create an XGBoost object*
XGB = xgb.XGBClassifier()*#Define a 'grid' of parameters that we want to test
#This is done using a dictionary* param_grid = {
"eta": [0.01, 0.05, 0.2],
"min_child_weight": [0, 1, 5],
"max_depth": [3, 6, 10],
"gamma": [0, 1, 5],
"subsample": [0.6, 0.8, 1],
"colsample_bytree ": [0.6, 0.8, 1]
}*#Define a GridSearchCV object
#This links the model object and the parameter grid* gs_xgb = GridSearchCV(XGB, param_grid, cv=4, n_jobs=-1)*#Fit the data. This will iterate through the grid
#and find the model with the highest accuracy*
gs_xgb.fit(X_smote, y_smote)*#Extract the best model as an XGB object*
model = gs_xgb.best_estimator_
虽然在概念上很简单,但是网格搜索可能计算量很大并且很耗时。如果我们有六个想要调整的超参数,每个都有三个可能的值,那么就有 729 个潜在的模型。如果我们接着做 4 重交叉验证,那么我们实际上是在拟合大约 3000 个不同的模型。
您可以通过将 GridSearchCV 中的“n_jobs”参数设置为-1 来提高性能(这迫使它并行使用所有计算机处理器),但这仍然是那种需要花费数小时来运行的代码。
令人高兴的是,在这种情况下,等待是值得的——我们创建了一个模型,可以 100%准确地预测座位类型。

打开黑匣子
这一切都很好,但我们现在需要研究哪些特性在驱动模型做出决策。也许有一种方法可以解开,比如说,一个简单的决策树或逻辑回归模型。但是 XGBoost 尽管精确,却是出了名的不透明。
机器学习的可解释性是一个变得越来越重要的话题,尤其是当模型变得更加复杂,并且更加公开接受公众监督的时候(例如,你如何证明你的银行的信用评分算法不是种族主义的呢?)
我高度、高度推荐 Kaggle 上的这个免费课程(大约四个小时的材料),它涵盖了你可以解开任何机器学习模型的三种技术。在这篇博客中,我将使用其中最简单的——排列重要性。
排列重要性的概念非常直观:
- 假设我们有一个模型,有一个给定的损失函数(例如,精确度)为 x
- 现在,在特性集中取一个单独的列,并对每个数据点的值进行洗牌
- 使用这个带有混洗列的新数据集重新计算准确度
- 请注意这种混乱对模型的准确性造成了多大的影响。这种准确性的损失就是该特征的“排列重要性”
- 将列返回到其未混合的状态,并移动到下一个特征——混合其值,并计算模型的准确性下降了多少
这个过程打破了每个特征和目标之间的关系,因此精度的下降表明了模型对该特征的依赖程度。
值得注意的是,对于给定的数据点,这些值不会告诉你特性以何种方式影响了模型的决策。为此,可以使用 SHAP 值(见 Kaggle 课程对这些的介绍)。
使用 eli5 包可以在 Python 中计算排列重要性(尽管最近在 Scikit Learn 中添加了一个等价函数)。
*#Import the required libraries* **import** eli5
**from** eli5.sklearn **import** PermutationImportance*#Create a Permutation Importance object
#using our exisitng xbg model
#then fit it to our data*
perm = PermutationImportance(xgb).fit(X, y)*#Call the show_weights method*
eli5.show_weights(perm,
feature_names = X.columns.tolist(),
top=15)

This outputs an ordered table, showing the features and their associated expected loss in accuracy. Note — the function performs many random shuffles of each feature, hence the ranges in the ‘Weight’ column.
最有影响力的特征是选区是否在苏格兰。考虑到苏格兰民族党(Scottish National Party)在 59 个苏格兰席位中的 58 个席位中颇具竞争力,这应该不足为奇。
其次最重要的是投票脱离欧盟的人数比例。让我们看看这是如何根据座椅类型进行分解的。

我们可以看到,离开投票份额是决定席位类型的一个重要因素——不同类别之间存在明显差异。从工党的角度来看,有两个关键问题凸显出来:
- 工党在其中具有竞争力的席位(即工党安全席位,加上其差额)涵盖了非常广泛的数值,从 20%到近 70%。因此,单一的欧盟成员国立场无法同时安抚所有潜在选民。
- 工党/保守党的边缘席位看起来更像安全的保守党席位,而不是拯救工党席位。因此,保守党能够有一个更集中的英国退出欧盟政策,而没有疏远其核心基础或工党边缘的潜在选民的风险。
这两个发现在许多其他具有高排列重要性的 KPI 中表现出来。考虑与房屋所有权相关的两个最重要的特征:


在这两种情况下,潜在的工党席位分布在非常广泛的数值范围内,正如英国退出欧盟的投票一样,保守党/工党的边缘看起来更像是安全的保守党席位,而不是安全的工党席位。
当我们考虑席位的地理类型时,这甚至是真实的——保守党/工党的边缘大多在城镇(而不是城市)。同样,边缘席位的轮廓更好地反映了现有的保守党安全席位。

所有这些都意味着保守党处于更有利的位置来开展一场有针对性的竞选活动,这仍将吸引广泛的选民。然而,工党被迫吸引非常广泛的选民,这在他们的竞选中给人的印象是混乱和过于广泛。
这些人口统计数据不太可能很快改变,如果工党想要赢得选举,就必须收回这些边缘席位。这是否意味着注定失败?
团结各种可能支持工党的选民看起来是一项艰巨的任务,尤其是当保守党能够更有针对性的时候。如果没有其他因素,这将需要非常有才华的领导,有重要证据表明,工党在 2019 年大选中非常缺乏这一点。
有大量的轶事证据表明,他们的领导人杰里米·科尔宾在竞选期间非常不受欢迎。自选举以来,更多的科学调查似乎证实了这一点。

Source: https://twitter.com/OpiniumResearch/status/1205510937995812864
为了赢回权力,工党的下一任领导人将不得不引人注目。那么,对于来说,没有压力,候选人已经在排队等候取代科尔宾先生,而党员们将最终试图从中选出一个胜利者。
感谢你一直读到博客的结尾!我很乐意听到任何关于上述分析的评论,或者这篇文章涉及的任何概念。欢迎在下面留言,或者通过 LinkedIn 联系我。
向非技术观众解释:逻辑回归
逻辑回归的隐喻

Gooses, Geeses
你可能经常会发现一个有趣的技术面试问题,就是“向非技术观众解释一下”这类问题。这些类型的问题旨在考察你能多好地表达复杂的概念,以及你实际上能多好地理解它们。这基本上是一个技术知识和沟通技巧的问题。
"除非能向酒吧女招待解释清楚,否则所谓的科学发现毫无价值."——纳尔逊的卢瑟福勋爵
逻辑回归使用数学来评估某事发生或不发生的可能性。它允许我们回答任何“是或不是”的问题。
参考威利·旺卡和巧克力工厂里受过教育的鸡蛋专家。
“10,000 Tons of Ice Cream”
"鸡蛋鉴定师可以区分好鸡蛋和坏鸡蛋."逻辑回归是决定鸡蛋好坏的数学基础。
Iconic
技术细节
逻辑回归可以是二元的,也可以是多项式的,但是现在让我们把重点放在二元的版本上。该算法在几个主要假设下运行:
- 因变量本质上应该是二分的(是或否)。
- 数据中不应有异常值,这可以通过将连续预测值转换为标准化分数,并去除合理范围之外的值来评估。标绘标准偏差可能有助于确定该范围。
- 预测值之间不应存在高度相关性(多重共线性)。这可以通过预测值之间的相关矩阵来评估。 Tabachnick 和 Fidell (2013) 提出,只要自变量之间的相关系数小于 0.90,就满足假设。
逻辑回归被定义为对典型的二分因变量的回归分析或预测分析。它用于深入了解以下问题:
- 这个人会拖欠他们的贷款吗?
- 应该推荐剖宫产吗?
- 体重、卡路里摄入量、脂肪摄入量和年龄对心脏病发作的概率有影响吗(是与否)?
- 这个癌细胞是恶性的还是良性的?
通过对概率的输出设置阈值,逻辑回归可用于二元分类,但其本身仅揭示给定输入属于某一类别的概率。
评估
已经为二元逻辑回归开发了许多伪 R2 值。应该非常谨慎地解释这些,因为它们有许多计算问题,导致它们被人为地高估或低估。一个更好的方法是提出任何可用的拟合优度测试; Hosmer-Lemeshow 是一种基于卡方检验的常用拟合优度指标。
这是对逻辑回归的一个非常基本的解释,旨在让非技术观众易于理解和使用。饶彤彤有一个很棒的教程,用于参与逻辑回归,并实际使用数据和解释结果。如果你发现自己需要不用统计学来解释逻辑回归,想想受过教育的蛋师。基于一些因素,机器衡量每个鸡蛋好坏的概率。根据它属于任何一类的概率,可以决定它是一个好鸡蛋还是一个坏鸡蛋。使用隐喻和类比是在人们更容易理解的框架内解释概念的好方法。
It’s a metaphor
显式 AUC 最大化
如何在 ROC 下显式优化最大面积

Photo by André Sanano on Unsplash
我刚开始参加“IEEE-CIS 欺诈检测”Kaggle 竞赛,有件事引起了我的注意:

基于 AUC 评估结果的事实对于欺诈检测任务是有意义的,原因如下:
- 数据集通常是不平衡的,这使得很难针对召回或其他简单指标进行优化,除非您使用数据的过采样或欠采样。
- 在现实中,假阴性和假阳性的成本是不同的,实际任务应该包括这些信息并优化实际成本,而不是像召回或 F1 分数这样的数学量。
- 高 AUC 增加了我们能够找到满足这些要求的最佳阈值的机会。
通常,AUC 仅在超参数调整期间优化,而在训练期间,它们使用交叉熵损失。为什么不首先优化 AUC,而不是交叉熵?
这篇论文提出了同样的问题:
论文的引言很好地概括了这个问题:

如果我们使用 AUC 代替交叉熵作为优化函数会怎么样?可以使用 Wilcoxon-Mann-Whitney 统计来计算 AUC 曲线:

如果 x 和 y 是概率,则该度量惩罚任何实际肯定情况的概率小于否定情况的概率的情况。这不是传统的优化函数,因为它缺乏 MSE 或交叉熵成本函数的可加性。正如文件中指出的那样,

上式中的 AUC 不是概率的平滑函数,因为它是使用阶跃函数构建的。我们可以尝试平滑它,以确保函数总是可微的,这样我们就可以使用传统的优化算法。如本文所述,解决这一问题的方法之一是 RankBoost 损失函数:
这里 x 和 y 分别是正类和负类的概率。例如,在逻辑回归模型中,x 和 y 都可以表示为 sigmoid 函数:
这里ξ是一个预测变量。
不得不承认,这些车型并没有什么新意。它们被称为成对比较模型,由瑟斯通于 20 世纪 20 年代首创。更多信息请看这本书。这种分析的基础是布拉德利-特里-卢斯模型,但最广为人知的变化是 Elo 算法。模型本身非常简单,是通过最大化似然函数得出的:

在我们的上下文中,如果 I 来自正类,j 来自负类,则 M_ij 为 1。在所有其他情况下,它是 0。这里的能力值α是对数,而不是概率。这使得模型比 RankBoost 更简单,并且还允许我们将其用作神经网络的最后一层(在这种情况下,值α将只是前一层的激活)。损失函数是:
其中 I 和 j 分别是正例和反例。
我们将使用一个简单的分类问题来演示这种方法。我们将使用 TensorFlow 来利用自动微分。

如你所见,这是一个使用合成数据的二元分类问题。我们将尝试最大化 AUC,而不是尝试对结果进行正确分类。
Epoch 0 Cost = -0.12107406
Epoch 100 Cost = -0.24906836
Epoch 200 Cost = -0.2497198
Epoch 300 Cost = -0.24984348
Epoch 400 Cost = -0.24989356
现在我们画出我们的预测:

讨论
下图基于阈值 0.945。如果我选择常规阈值 0.5,我们将在一个类中得到所有观察值。这是为什么呢?原因是 AUC 对偏差值不敏感。事实上,因为在这个模型中,我们减去成对激活,偏差值抵消。我们可以在成本函数中增加额外的项,使偏差更接近 0.5。或者选择做我们已经做过的事情,手动选择适合我们的阈值。我想提醒你,我们正在优化 AUC,所以如果所有的观察结果都被预测为属于一个类,只要 AUC 具有最优值,我们就不会介意。
结论
人们可能会想,除了使用 AUC 作为评估标准的数据科学竞赛之外,这种方法对任何真正的机器学习项目是否有用。但我认为,作为机器学习的第一步,它在不平衡数据集的情况下可能是有用的。第二步是学习偏差参数,并通过使用基于业务的优化指标对模型进行微调。
AUC 成本函数的一个缺点是,它在观察值之间使用成对比较,因此函数的复杂性随着观察值数量的平方而增长,随着观察值数量的增长,这可能成为性能瓶颈。此外,还必须想出一个好的分批策略,根据一些较小的样本(批次)正确估计 AUC。
所有代码都可以在我的 github 库中找到。也可以在下面找到更多关于 RankBoost 的信息。
我们接下来考虑如何学习对一组对象进行排序,这是一个在各种领域中自然出现的问题。对于…
mitpress.mit.edu](https://mitpress.mit.edu/sites/default/files/titles/content/boosting_foundations_algorithms/chapter011.html)
推荐系统:利用“深度兴趣”挖掘多分类特征
你的深度学习模型如何最大限度地利用长度变化的数组特征?

Photo by Irina Nalbandian on Unsplash
原载于 2019 年 9 月 4 日 Taboola 工程博客 。
在 Taboola,我们的目标是预测用户是否会点击我们展示给他们的广告。我们的模型使用各种各样的特征,然而最重要的特征往往与用户的历史有关。了解如何很好地使用这些特性可以对模型的个性化功能产生巨大的影响,因为它们拥有用户特定的知识。
不同用户之间的用户历史特征差异很大;例如,一个流行的特性是用户类别——用户以前读过的主题。这种列表的一个例子可能是这样的— {“体育”、“商业”、“新闻”}。这些列表中的每个值都是分类的,它们有多个条目,因此我们将其命名为多分类特征。多分类列表可以为每个用户提供任意数量的值——这意味着我们的模型必须处理非常长的列表和完全空的列表(对于新用户)。
向机器学习模型提供未知长度的输入是一个需要明智解决的问题。这篇文章将带你了解如何在你的神经网络中整合这些不同长度的特征,从最基本的方法一直到“深度兴趣”,即当前的艺术状态。

平庸
让我们继续讨论用户类别。我们如何将未知长度的列表转换成我们可以使用的固定长度的特征?最天真,但非常流行的方法是简单地平均。让我们假设每个类别都有一个长度为 d 的独立嵌入——这样列表中的每个值都被映射到一个向量。我们可以使用平均池——平均所有用户的类别,并每次接收一个长度为 d 的向量。更正式地说,如果是全部 N 个字中的第 j 个字的嵌入,那么一个用户的平均池可以写成:

但这远非完美。平均可能工作得很好,但是当列表很长时, 1/N 因子会产生一个很小的最终结果;对不同的指向向量求和可能会导致它们相互抵消,除以 N 会使情况变得更糟(如果你来自物理学/EE 背景,这应该会敲响警钟,因为这很像非相干积分中发生的情况)。这是不好的,因为它伤害了具有更长历史向量的用户,而这些向量是我们拥有最多信息并能给出更好预测的向量。正因为如此,我们(以及来自阿里巴巴研究院的人)去除了 1/N 因素,并对用户历史使用总和池,以确保可预测的客户不会对网络产生可忽略的影响。
举重,天真地
平均会自动为所有元素分配相同的权重。这是我们想要的吗?让我们用这个列表来考虑一个用户:{ '足球','网球','篮球','时尚' }。天真地将它们平均化会强调运动类别,而忽略“时尚”。对一些人来说,这是准确的——那些对运动比对时尚更感兴趣的人;对其他人来说,可能不会。我们可以做些什么来给不同的类别不同的权重,以更好地描述用户?
一个更好的解决方案是使用一些其他信息,例如:用户对每个类别的过去浏览(印象)次数。由于用户阅读一篇文章的次数与他的个人品味相关,我们可以使用这些计数作为权重,进行加权平均合并。例如,这将有助于我们区分以下两种截然不同的用户:
用户 1 = { '足球':2,'网球':2,'篮球':2,'时尚':200}
用户 2 = { '足球':2,'网球':2,'篮球':2,'时尚':2}
你注意到了吗?
我们能堆叠更多的信息吗?比方说,我们不仅有每个用户在每个类别的浏览次数,还有用户上次阅读该类别文章的时间,或者每个用户的该类别点击率(意思是,在该类别出现的所有时间中,用户阅读该类别文章的次数)。在不进行无休止的算法 A/B 测试的情况下,结合这些特性的最佳方式是什么?当然,答案是利用机器学习的力量,并应用一个额外的层,其工作是输出每个值的权重。这有时被称为“注意层”。这一层将所有相关数据作为输入,并学习理想的权重来平均这些值。让我们看一个单一类别值“网球”的注意力子网示例。假设“网球”的嵌入是{5,0.3,5,1,4.2},并且用户被推荐了 10 篇网球文章,但是只点击了一次,则流程可以被图示为:

注意力层计算每个类别嵌入的权重。在上面的例子中,计算的权重是 0.2。假设该用户也对“时尚”感兴趣,并且关注层输出该类别的 0.5,则该用户的历史嵌入的最终计算将是 0.2* emb(网球)+ 0.5* emb(时尚)。这些关注层学习如何利用我们拥有的关于该用户历史的所有信息来计算每个类别的权重。
太好了!但是我们能做得更好吗?
简介:深趣建筑
请记住,我们试图预测某个用户是否会点击某个广告,那么为什么不插入一些关于当前建议广告的信息呢?假设我们有一个用户,他的历史记录是{“网球设备”、“儿童服装”},我们当前的广告是一个网球拍。当然,我们会希望网球装备更重,而忽略这个特殊案例中的儿童部分。我们之前的关注层仅仅是为用户兴趣建模而设计的,并没有考虑用户的个人品味与在汇集阶段向他推荐的广告之间的相互作用。我们希望在池化发生之前将这种用户-广告交互交织在一起,以便计算更具体地针对呈现给用户的当前广告的权重。
为此,我们可以使用 Deep Interest 架构,这是由阿里巴巴研究院的一个小组在 KDD2018 大会上展示的作品。如果我们回到前面的例子,我们现在可以为向用户建议的特定广告添加一个嵌入:

出于浓厚的兴趣,广告特征被用作神经网络的输入两次:一次作为模型本身的输入(贡献关于向用户呈现该广告是否会导致点击的信息),第二次作为用户历史嵌入层的输入(将用户的历史注意力调整到与该特定广告相关的部分)。
我们还可以有不同的方式来为广告特征创建嵌入:一种是对上述两种情况使用相同的嵌入向量,另一种选择是为这两种情况生成两种不同的嵌入。第一个选项在训练时给予嵌入两倍的梯度,并且可能更好地收敛。在后一种情况下,我们可以有两种不同的嵌入方式(比如,对于整个网络,嵌入大小为 12;对于用户历史权重层,嵌入大小为 3)。较短的嵌入可以节省运行时间服务,但是向学习过程添加了更多的参数,并且可能延长训练时间。当然,在这两个选项之间进行选择取决于具体的用例。
摘要
多分类特征对于各种常见问题的预测至关重要,尤其是当试图从过去的交互中预测未来的用户行为(如点击、转化)时。有一些简单的方法可以做到这一点,但是为了更好地预测,我们推荐 Deep Interest 架构,因为它允许根据相关上下文对特征向量进行动态加权。这种体系结构实现起来非常简单,并且为许多推荐系统提供了很好的结果。去试试吧!

印度尼西亚每位总统候选人支持者的推特探索与可视化
按照数据科学流程,通过使用 Plotly 将数据上的发现可视化来进行实践。

介绍
你好!欢迎阅读本文。这一次,我想写一些与我迄今为止所写的不同的东西。我已经发表的文章是关于实现人工智能的,尤其是关于深度学习的。在这篇文章中,我想写一些不同的话题。我觉得如果要开发一个模型,这个话题也很重要。这一步应该在建模之前完成。也就是探索性数据分析(EDA) 。
对不起,我一直在忙着准备我的新工作😫。即使我很忙,我仍然想写媒介和大家分享我的知识😘。每当我有空闲时间,我就一点一点地写这篇文章。

Photo by freestocks.org on Unsplash
在这篇文章中,我不仅想讲述如何编写代码,还想将它实现到一个真实的研究案例中。我使用的数据来自我从图书馆搜集的 twitter。案例是关于“2018印尼各总统候选人支持者分析”。即使文本是印度尼西亚语,我也会努力让你明白文本和单词的意思。
本文中使用的数据是基于我抓取的推文的。可能有一些爬虫跳过了的推文。尽管如此,你可以说人口的数据样本应该是有代表性的。我抓取的数据大约有 70 万条推文。
如果你是来享受阅读统计数据的乐趣的,那就继续吧,不要在意这篇文章中的技术细节。哦,我也不会包括任何关于我们在数据中发现的洞察力的结论。我将只写可视化的分析和解释。你可以在头脑中创造你的结论,如果你想要更多,你为什么不也做 EDA 呢?当然还要写出来😃。
概述
- EDA 为什么?
- 步伐
- 技术
- 第一步:研究问题
- 第二步:收集数据
- 第三步:数据预处理
- 第四步:探索性数据分析
- 结论
- 编后记
- 贮藏室ˌ仓库
EDA 为什么?

摘自 KDNuggets,在创建模型之前进行数据科学的步骤是收集数据、处理数据、清理数据,最后是 EDA。实际上,做 EDA 可以帮助我们更好地提高模型的质量。通过了解数据,我们可以感受到我们的学习算法是如何学习我们的数据的。好吧,如果你觉得你认为有些情况是不可能预测的,我们的学习者也不会。
在数据科学和机器学习的每项任务中,EDA 过程都应该在建模之前完成(没有任何数据要训练的纯强化学习除外)。比如在自然语言处理(NLP)中,做情感分析的时候,也许我们可以把一些做 EDA 时能找到的词去掉,做一个更好的模型。另一个例子,在计算机视觉(CV)中,我们可能会发现模型无法学习,因为我们的模型无法预测一些情况,因为我们的数据有独特的噪声或一些异常,这些噪声或异常在之前的数据清理步骤中没有被清理。
在建模之前做 EDA 还有很多其他好处。也许你可以得到一种直觉,可以让你的模型变得更好。这就是为什么我们应该做这一步。如果你看过我之前关于生成深度学习歌词的文章,我跳过了这一部分。有时在生成歌词时,有一些我不想让它出现的文本(例如“REFF”)。嗯,我没有注意到,如果我先做 EDA 的话,我应该会注意到的。
在做之前,我们需要知道有哪些步骤。开始了。
步伐
首先是,我们必须定义什么是研究的问题?这意味着定义我们想要搜索的内容。这些问题将成为我们下一步行动的指南。这些问题也需要在下一步中回答。
有一些研究问题的例子:
- 有多少包含“x”和“y”标签的推文?
- 哪个国家的推特频率最高?
以问题的形式列出你需要搜索的任何内容。通常,你可以开始锁定 5W 1H(什么,什么时候,哪里,为什么,谁,如何)。在我看来,因为我们可以在以后获得新的见解,我们可以根据我们的发现增加问题的数量,同时专注于我们的主要研究问题。

UCL Repository
第二,我们需要收集数据。确保我们根据已经定义的研究问题搜索数据集。有几种方法可以完成这些步骤。我们可以在数据集存储库中搜索任何结构化数据集,例如 Kaggle 和 UCL 存储库。或者,如果可能的话,我们也可以通过废弃一些社交媒体,如脸书和 Twitter,使用它们的 API 来搜索任何非结构化数据。这取决于你的研究问题。通常,您不会在那里找到您需要的结构化格式的数据。

https://pixabay.com/en/baby-crying-cry-crying-baby-cute-2387661/
第三,预处理,清洗数据,数据扯皮!这将是痛苦和恼人的步骤。做这一步时不要让你的头爆炸。为什么这一步是痛苦的?你需要了解你的数据。找出是否有任何“害虫”需要清理。NLP 中的“害虫”的例子有打字错误、非正式的单词、表情符号、拉长的单词、任何隐藏的炸弹,如果我们移除它们,通常会使我们的可视化和建模更好!
在做任何事情之前,如果数据不是结构化格式,我们需要将其转换为结构化格式,以便更容易地清理数据。让我告诉你,我们经常会多次回到这个步骤,因为我们经常在下一步中发现“害虫”。

Photo by Chris Liverani on Unsplash
最后,我们做 EDA(探索性数据分析)。在这里,我们将回答第一步中定义的一些研究问题。通常我们会在这里做一些可视化来传达我们的结果。当我们可以通过打印结果来查看数据时,为什么还要可视化或绘制数据?记住,分析的结果不会只为你一个人看到。结果会被别人看到。为了 UX(用户体验),我们需要通过可视化来呈现数据,以确保读者在看到结果时感到舒适。我不认为我的文章会被很多人看到,如果我在这里通过裁剪 CLI(命令行界面)中打印结果的截图来呈现结果。在本文中,我们将在 Jupyter 笔记本电脑中进行 EDA,因为它有美丽的 UX,也可以用来展示我们的数据。
技术
我们将使用:
- Python 3.6
- Numpy:一个用于科学计算的 Python 包
- Pandas :用于处理表格数据的 Python 包
- Twint :一个 Python 包,用于抓取 Twitter 中的帖子(tweet)
- Plotly :一个用于交互式可视化数据的 Python 包。这个软件包在可视化数据方面有漂亮的 UX。我们甚至可以操纵绘图的结果(例如:在绘图中隐藏几个标签)
- Jupyter Notebook :很棒的 Python IDE,也可以用来做演示或者教育代码。
第一步:研究问题
好了,在我们制定问题之前,让我告诉你,2019 年,印度尼西亚将举行总统选举。有两个候选人。他们是佐科·维多多(佐科维)——马鲁夫·阿明(第 01 号)和普拉博沃·苏比安托——桑迪亚加·乌诺(桑迪)(第 02 号)。
在这篇文章中,我们将关注的是每个候选人在社交媒体中的支持者是怎样的。在本文中,我们将关注 Twitter 社交媒体。
通过研究和谷歌搜索,我发现了一些佐科维和普拉博沃的支持者用来表达他们支持的标签。为了简单起见,我缩小了他们的标签范围:
- jokowi-Maaruf:# jokowi periode 或#JokowiLagi 或#01IndonesiaMaju 或#2019JokowiLagi 或#2019TetapJokowi 或#TetapJokowi
- 普拉博沃—桑迪:#2019GantiPresiden 或# 2019 普拉博沃桑迪或# 2019 普拉博沃普雷西登
我们将把推文的年份限制在 2018 年。
就这样,我们来创建研究问题。以下是我的研究问题:
- 每个支持者的推文在数据集中出现的频率如何?
- 每个月每个支持者的推文频率如何?
- 通过查看每个月最大频率的推文,该词在每个支持者的推文中当月的频率如何?
- 通过查看每月最大频率的推文,该词在佐科威支持者的推文中当月的频率如何?
- 这个词在普拉博沃支持者的推特上当月的前 30 频率如何?
- 当月佐科威支持者的推文中,Token 伴随‘prabowo’一词出现频率前 30 是怎样的?
- 当月普拉博沃支持者的推文中,Token 伴随‘佐科威’一词出现频率前 30 是怎样的?
- 当月普拉博沃支持者的推文中,Token 伴随'普拉博沃'一词出现频率前 30 是怎样的?
- 佐科威支持者当月推文中 Token 伴随‘佐科威’一词出现频率前 30 是怎样的?
- 普拉博沃和佐科维支持者的推文中 Hashtags 的前 30 频率如何?
- 佐科维和普拉博沃支持者推文中的 length char 均值如何?
- 佐科维和普拉博沃支持者的推文中长度词的均值如何?
我们完了!事实上,我们可以问的问题太多了。为了不使这篇文章变成 1 小时的阅读时间,我们将把我们想问的问题减少到 12 个。
第二步:收集数据
对于这些步骤,我们将使用 Twint 作为我们的库。
对于本文,我们将按如下方式确定数据范围:
- 只有包含上述标签的推文才会被删除
- 我们将采用 2018 年发布的推文
这一步我刮了 706.208 条推文
第三步:数据预处理
好的,因为本文将关注 EDA,所以我们将尽可能缩短这一步。
首先,我们将使用pandas读取 csv
tweet = pd.read_csv(‘tweet.csv’, encoding=’utf-8')
为了简单起见,我们将只形式化 word 并删除停用词
我们将以两种方式形式化,首先是用正则表达式,然后用已知的俚语词替换正式词。后者将需要一本俚语词及其正式词的词典。
我是这样将这个词形式化的:
应该有更好的方法来清理formalize_rule函数,比如使用nltk TweetTokenizer。嗯,我想试试 regex,就这样。
我也实现了在formalize_word上移除停用词。
我们将它应用到数据框架中:
注意,在这一步,实际上我们在做了几次 EDA 之后,还会回到这一步。有时候,我们会发现 EDA 步骤中的“害虫”。
我们完成了,进入最后一步!
第四步:探索性数据分析
因为我们想要回答的所有研究问题都可以在这里找到答案,所以我们将在这一步结束数据科学流程。事不宜迟,让我们回答所有的问题吧!
等等,在这之前。我们应该定义一些将被多次使用的函数。
我们已经定义了将在以后经常使用的数据帧过滤器。我们还创建了一些在数据帧中输出统计数据的函数。统计数据将被绘制成图表。
0.数据中有多少实例?
tweet.shape[0] # 705013
1.每个支持者的推文在数据集中出现的频率如何?
怎么做?
我们取每个支持者推文的属性形状。
freq_hashtag = []
for filter_tweet in array_filter:
freq_hashtag.append(tweet[filter_tweet].shape[0])
我们需要这样做来展示 Jupyter 中的情节:
init_notebook_mode(connected=True)
让我们设定情节
label = ['Jokowi Supporter', 'Prabowo Supporter']
data = [
go.Pie(labels=label,
values=freq_hashtag, textinfo='value')
]
layout = go.Layout(
title='Tweet Frequency of Each Supporters'
)
fig = go.Figure(data=data, layout=layout)
有许多方法可以将这些数据可视化。由于它们每个都是可比较的,我们可以使用饼图来可视化数据。
plotly 需要两个最少的组件。
首先是“数据”。“数据”是我们想要可视化的图表类型的一组数据。我们可以在这里组合多种类型的图表。例如,您可以在可视化中用饼图来可视化条形图。
其次是布局。布局是可视化的容器。在这里我们可以定制标题、图例、轴等等。
然后,我们将容器和图表放入
go.Figure(一个图)中进行组合。这个图形已经可以绘制了。
iplot(fig,'test')
剧情吧!

分析
普拉博沃的支持者推文频率高于佐科维的支持者推文频率
2.每个月每个支持者的 tweets 的前 30 个频率如何?
怎么做?
因为我们要绘制的数据是连续的。我们可以用折线图来绘制。
首先,我们对每个月进行过滤和循环
freq_hashtag = []
for filter_tweet in array_filter_month:
for filter_tweet_prez in array_filter:
freq_hashtag.append(tweet[filter_tweet][filter_tweet_prez].shape[0])
颠倒列表(从 12 月—1 月到 1 月—12 月)
j_freq = freq_hashtag[::2][::-1]
p_freq = freq_hashtag[1::2][::-1]
那就画出来
label = ['Jokowi Supporter', 'Prabowo Supporter']
data = [
go.Scatter(x=month_unique,
y=j_freq, name=label[0]),
go.Scatter(x=month_unique,
y=p_freq, name=label[1])
]
layout = go.Layout(
title='Tweet Frequency of Each Supporters / Month'
)
fig = go.Figure(data=data, layout=layout)
iplot(fig)
剧情吧!

分析
普拉博沃的支持者推特通常比佐科维的支持者推特更频繁。他们的推文在九月达到顶峰。
3.通过查看每月最大频率的推文,该词在每个支持者的推文中当月的前 30 个频率是怎样的?
怎么做?
首先,我们将设置最大频率的推文在 9 月。
i = Sep
然后,我们通过使用上述函数找到最高频词。
stat_word = get_stat_with_func(tweet, lambda x: get_tweet_common_word(x, text_column="tweet3", most_common=30),'month')
我们将只选取 9 月份发布的推文,并对其进行绘图。我们将把它限制在最高频率的前 30 位。
由于数据不是连续的,所以条形图是正确的选择。如果我们不想知道每个单词的频率,单词云也有助于我们可视化词频。
plotting = stat_word.loc[i]
freq = plotting.apply(lambda x: x[1]).values
word = plotting.apply(lambda x: x[0]).values
data = [
go.Bar(x=word,
y=freq),
]
layout = go.Layout(
title='Word Freq in {}'.format(i)
)
fig = go.Figure(data=data, layout=layout)
iplot(fig)
剧情!

分析
“佐科维”在 9 月出现的频率最高。它的频率大约在 35k — 40k 之间。接下来是印尼、Orang(人)、Presiden(总统)、Rakyat(公民)、Dukung(支持)、Allah(神)、Prabowo 等。
4.通过查看每月最大频率的推文,佐科威支持者的推文中当月前 30 个词的频率如何?
怎么做?
这与我们在 RQ(研究问题)3 上的做法类似。不同的是,我们需要过滤佐科维的支持者推文。
tweet_2019_jokowi = tweet[filter_jokowi]
stat_word = get_stat_with_func(tweet_2019_jokowi, lambda x: get_tweet_common_word(x, text_column="tweet3", most_common=30),'month')
i='Sep'
plotting = stat_word.loc[i]
# print(plotting)
freq = plotting.apply(lambda x: x[1]).values
word = plotting.apply(lambda x: x[0]).values
data = [
go.Bar(x=word,
y=freq),
]
layout = go.Layout(
title='Word Freq in {} for Jokowi Hashtag'.format(i)
)
fig = go.Figure(data=data, layout=layout)
iplot(fig)
剧情吧!

分析
“佐科威”这个词在这里也是最高的,与其他词的区别很大。它有积极的词汇,如“伯巴基”(分享)、“图卢斯”(真诚)和“伯杰拉克”(移动)。它也有“安拉”这个词。
5.普拉博沃支持者的推特上当月前 30 个词的出现频率如何
怎么做?
同样,在做 RQ 4 时也是类似的。我们将过滤到普拉博沃支持者的推文。
tweet_2019_prabowo = tweet[filter_prabowo]
stat_word = get_stat_with_func(tweet_2019_prabowo, lambda x: get_tweet_common_word(x, text_column="tweet3", most_common=30),'month')
i = 'Sep'
plotting = stat_word.loc[i]
# print(plotting)
freq = plotting.apply(lambda x: x[1]).values
word = plotting.apply(lambda x: x[0]).values
data = [
go.Bar(x=word,
y=freq),
]
layout = go.Layout(
title='Word Freq in {} for Prabowo Hashtag'.format(i)
)
fig = go.Figure(data=data, layout=layout)
iplot(fig)
剧情吧!

分析
没想到‘佐科威’频率比‘普拉博沃’高。最高的是‘印度尼西亚’。每个词的出现频率相差不太大。我们应该注意的词是' ulama '(穆斯林的学者或神职人员)、' rezim '(政权)、' cebong '(蝌蚪,普拉博沃的支持者对佐科维的支持者的' bad '别名)、' emak '(母亲群体)和' bangsa '(民族)。它也有“安拉”这个词。
6.当月佐科威支持者的推文中,Token 伴随‘prabowo’一词出现频率前 30 是怎样的?
在我们这样做之前,因为我们经常通过多次编写代码来绘图,所以我们应该创建一个可重用的函数。
def plot_freq_word(x,y,title='Title'):
data = [
go.Bar(x=x,
y=y),
]
layout = go.Layout(
title=title,
xaxis=dict(
title='Kata',
titlefont=dict(
family='Latto',
size=8,
color='#7f7f7f'
),
tickangle=45,
tickfont=dict(
size=8,
color='black'
),
)
)
fig = go.Figure(data=data, layout=layout)
iplot(fig)
之后,我们将根据需要过滤数据帧。
tweet_prabowo_in_jokowi = tweet[(filter_jokowi) & (tweet.tweet3.str.contains('prabowo', False))]stat_word = get_stat_with_func(tweet_prabowo_in_jokowi, lambda x: get_tweet_common_word(x, text_column="tweet3", most_common=30),'month')
i='Sep'
plotting = stat_word.loc[i][1:].dropna()
freq = plotting.apply(lambda x: x[1]).values
word = plotting.apply(lambda x: x[0]).values
plot_freq_word(word,freq,"Frequency of Token accompany 'prabowo' Token in Jokowi Supporter's Tweet on {}".format(i))
剧情吧!

分析
佐科维是这里频率最高的。我们会注意到一些有趣的词,它们是“uang”(钱)、“thecebongers”(蝌蚪)、“prestasinya”(成就)、“survei”(调查)和“asing”(外国)
7.那个月普拉博沃支持者的推文中伴随着“佐科威”一词的前 30 位频率是多少
我们将根据需要过滤数据帧。
tweet_jokowi_in_prabowo = tweet[(filter_prabowo) & (tweet.tweet3.str.contains('jokowi', False))]stat_word = get_stat_with_func(tweet_jokowi_in_prabowo, lambda x: get_tweet_common_word(x, text_column="tweet3", most_common=30),'month')
i = 'Sep'
plotting = stat_word.loc[i][1:].dropna()
freq = plotting.apply(lambda x: x[1]).values
word = plotting.apply(lambda x: x[0]).values
plot_freq_word(word,freq,"Frequency of Token accompany 'Jokowi' Token in Prabowo Supporter's Tweet on {}".format(i))
剧情吧!

分析
普拉博沃是这里频率最高的。我们会注意到一些很有意思的词,分别是' gerakan '(运动)、' ulama '、' mahasiswa '(大学生)、' rupiah '(印尼货币)、' rezim '(政权)。
8.当月普拉博沃支持者的推文中,Token 伴随'普拉博沃'一词出现频率前 30 是怎样的?
我们将根据需要过滤数据帧。

分析
“桑迪”在这里出现的频率最高。它与其他词有很大的差距。引起我注意的词是“ulama”、“allah”、“emak”、“gerakan”和“ijtima”(ulama/穆斯林学校的决定)。“佐科维”也是这里第二高的频率。
9.佐科威支持者当月推文中 Token 伴随‘佐科威’一词出现频率前 30 是怎样的?
我们是如何做到的?
我们将根据需要过滤数据帧:
tweet_jokowi_in_jokowi = tweet[(filter_jokowi) & (tweet.tweet3.str.contains('jokowi', False))]stat_word = get_stat_with_func(tweet_jokowi_in_jokowi,
lambda x: get_tweet_common_word(x, text_column="tweet3", most_common=30),'month')
i = 'Sep'
plotting = stat_word.loc[i]
plotting = plotting.dropna()
freq = plotting.apply(lambda x: x[1]).values[1:]
word = plotting.apply(lambda x: x[0]).values[1:]
plot_freq_word(word,freq,"Frequency of Token accompany 'jokowi' Token in Jokowi Supporter's Tweet on {}".format(i))
剧情吧!

分析
“普拉博沃”不在这里最高的 20 个频率中。和上面的不一样。总之,引起我注意词是“blokir”(封锁)、“pembangunan”(建设)、“kepemimpinan”(领导)、“allah”、“hebat”(伟大)和“bergerak”(移动)
10.普拉博沃支持者的推文中话题标签的前 30 频率如何?
怎么做?
由于 hashtag 的列是字符串格式,我们需要使用eval将该类型转换为“list”。之后,我们通过' '连接列表的内容,并调用我们之前的函数。我们将在 9 月份看到不限数据的统计。
hashtag_di_prabowo = tweet[(filter_prabowo)]
hashtag_di_prabowo['hashtags'] = hashtag_di_prabowo['hashtags'].apply(eval)
hashtag_joined = hashtag_di_prabowo['hashtags'].apply(lambda x: ' '.join(x))
hashtag_di_prabowo['hashtag_joined'] = hashtag_joinedstat_word = get_stat_with_func(hashtag_di_prabowo, lambda x: get_tweet_common_word(x, text_column="hashtag_joined", most_common=20),'month')
i = 'all'
plotting = stat_word.loc[i]
plotting = plotting.dropna()
freq = plotting.apply(lambda x: x[1]).values
word = plotting.apply(lambda x: x[0]).values
plot_freq_word(word,freq,"Frequency of Hashtags in Prabowo Supporter's Tweet")
剧情吧!

分析
我关注的标签是‘2019 tetapantipki’(2019 将继续反共)、“mahasiswabergerak”(大学生运动)、“rupiahlongsor jokoweilengser”(Rupiah Fall Jokowi 下台)和“Jokowi 2 periode”(Jokowi 两期)。最后一个标签应该是佐科威支持者的标签。标签大多是关于更换总统和佐科威的负面消息。
11.佐科威支持者的推文中,话题标签的前 30 频率如何?
怎么做?
真的和 RQ 10 差不多。
hashtag_di_jokowi = tweet[(filter_jokowi)]
hashtag_di_jokowi['hashtags'] = hashtag_di_jokowi['hashtags'].apply(eval)
hashtag_joined = hashtag_di_jokowi['hashtags'].apply(lambda x: ' '.join(x))hashtag_di_jokowi['hashtag_joined'] = hashtag_joinedstat_word = get_stat_with_func(hashtag_di_jokowi, lambda x: get_tweet_common_word(x, text_column="hashtag_joined", most_common=20),'month')
i='all'
plotting = stat_word.loc[i]
plotting = plotting.dropna()
freq = plotting.apply(lambda x: x[1]).values[1:]
word = plotting.apply(lambda x: x[0]).values[1:]
plot_freq_word(word,freq,"Frequency of Hashtags in Jokowi Supporter's Tweet")
剧情吧!

分析
我关注的标签有“indonesiamaju”(先进的印度尼西亚)、“jokowimambungunindonesia”(Jokowi 建设印度尼西亚)、“kerjanyata”(看得见的工作)、“diasibukkerja”(他在忙着工作)。大多数标签都是关于让佐科威继续当总统以及关于佐科威的积极的事情。同样,有一个“2019gantipresiden”应该是 Prabowo 支持者的标签。
12.佐科维和普拉博沃支持者推文中的 length char 均值如何?
我们是如何做到的?
我们会用折线图来做。由于这些数据是可比较的,我们将把它们形象化为一张图。我们将制作我们的默认折线图
def show_plotly_linechart(x_data, y_data, color_function=place_default_color,
title="This is title", dash=[], mode=[],
x_axis_dict_lyt=None, name=None,
y_axis_dict_lyt=None, custom_layout=None, x_title=None, y_title=None):
assert len(x_data) == len(y_data)
line_chart = []
for idx, (x, y) in enumerate(zip(x_data,y_data)):
color = color_function(x, idx)
current_dash = 'dash'
current_mode = 'lines+markers'
if len(dash) > 0:
current_dash = dash[idx]
if len(mode) > 0:
current_mode = mode[idx]
if name == None:
name = ["Trace"] * len(x_data)
line_chart.append(go.Scatter(x=x,y=y,
mode = current_mode,name=name[idx]))
layout = custom_layout
if layout is None:
layout = default_define_layout(x_axis_dict_lyt, y_axis_dict_lyt, title, x_title, y_title)
fig = go.Figure(data=line_chart, layout=layout)
iplot(fig)
而且我们还需要一个新的功能:
def get_length_char(df, text_column="tweet3"):
if df.shape[0] > 0:
return df[text_column].apply(len).mean()def get_word_length(df, text_column="tweet3"):
if df.shape[0]>0:
return df[text_column].apply(lambda x : len(x.split())).mean()
我们完成了,让我们绘制它们:
title_label = ["Length Char Jokowi", "Length Char Prabowo"]
counter = 0
x_l = []
y_l = []
for char_len in [jokowi_char_length, prabowo_char_length]:
x = char_len[0].index[:12]
y = char_len[0][:12].values
x_l.append(x[::-1])
y_l.append(y[::-1])
show_plotly_linechart(x_l,y_l,title="Length Char", name=title_label)
我们将制作一个包含两个折线图的列表,并用一张图显示出来。[::-1]表示我们将反转月份。默认从 12 月开始到 1 月。
剧情吧!

分析
佐科威的 char 长度均值呈上升趋势,在 11 月达到峰值。wheras Prabowo char 长度的平均值在 8 月之前趋于上升,在 8 月之后趋于下降
13.佐科维和普拉博沃支持者的推文中长度词的均值如何?
怎么做?
我们最后的 RQ。和上面的一样,但是我们需要新的功能:
jokowi_word_length = get_stat_with_func(tweet[filter_jokowi], get_word_length, label='month')
prabowo_word_length = get_stat_with_func(tweet[filter_prabowo], get_word_length, label='month')
就这些了,让我们画出来:
title_label = ["Jokowi", "Prabowo"]
counter = 0
x_l = []
y_l = []
for word_len in [jokowi_word_length, prabowo_word_length]:
x = word_len[0].index[:12]
y = word_len[0][:12].values
x_l.append(x[::-1])
y_l.append(y[::-1])
show_plotly_linechart(x_l,y_l,title="Word Length", name=title_label)
剧情吧!

分析
不出所料,和 RQ 12 的答案差不多得到了类似的结果。
结论
我们已经回答了我们定义的所有研究问题。答案里有很多有趣的地方。例如,每位总统的支持者的推文中出现频率最高的 30 个词的种类,以及每位支持者如何谈论他们的总统候选人或他们的总统候选人的对手。我不会在这里深究统计数据,因为这会让这篇文章更长。
在我们做 EDA 之后,我们应该注意到有一些东西应该被清理以使数据更好。例如,有一些推文在一条推文中包含了 Jokowi 的支持者和 Prabowo 的支持者的标签。这些推文应该从数据集中删除。我们应该回到清洁步骤,重新做 EDA。
编后记

https://pixabay.com/en/cat-tired-yawn-stretch-814952/
这就是我的文章,主要是关于 EDA 的。其实我答过的 rq 还多。但为了缩短这篇文章,我选择了其中的几个。你一定想知道我们发现的一些结果。为此,您需要更深入地探索数据。如果有很多读者想要,我会分享数据集。
可以为该数据集完成许多任务,如主题建模、情感分析、检测异常(如检测蜂鸣器)和许多有趣的任务。如果有人想让我写,我会考虑写的。
我欢迎任何可以提高我自己和这篇文章的反馈。我正在学习写作。我真的需要一个反馈来变得更好。请确保以适当的方式给出反馈😄。
在我接下来的几篇文章中,我将回到 NLP 或计算机视觉(可能)主题。

https://pixabay.com/en/calligraphy-pen-thanks-thank-you-2658504/
贮藏室ˌ仓库
TBD
来源
在 Springboard,我们的数据学生经常问我们一些问题,比如“数据科学家是做什么的?”。或者“一天做什么……
www.kdnuggets.com](https://www.kdnuggets.com/2016/03/data-science-process.html)
强化学习的探索
应该在勘探和开发上花费多少努力

Photo by Dariusz Sankowski on Unsplash
更新:学习和练习强化学习的最好方式是去 http://rl-lab.com
每个人每天都面临着同样的困境:我应该继续做我正在做的事情,还是应该尝试其他事情。例如,我应该去我喜欢的餐馆还是应该尝试一个新的,我应该保持目前的工作还是应该找到一个新的,等等…
在强化学习中,当你坚持做你正在做的事情时,这种类型的决定被称为 开发 ,当你尝试新事物时,这种类型的决定被称为 探索 。
很自然,这就提出了一个问题:开发多少,勘探多少。
然而,在探索中有一个问题,那就是我们并不真正知道结果会是什么,它可能比目前的情况更好,也可能更糟。
人类在采取行动之前,试图获得尽可能多的信息,例如,在我们尝试一家新餐馆之前,我们会阅读评论或询问已经尝试过的朋友。另一方面,在强化学习中,这是不可能的,但是有一些技术可以帮助找出最佳策略。
后悔的概念
从逻辑上讲,当我们尝试新事物,结果不令人满意时,我们会后悔我们的决定。如果新餐馆很差,我们会后悔去那里,我们认为无论我们付多少钱都是完全的损失。所以我们很遗憾这个金额。
当我们不断为错误的决定买单时,损失的数量和后悔的程度都会增加。因此,将损失金额和后悔程度保持在最低水平应该是个好主意。
我们能做到吗?答案是,是的,这是可能的,至少在 RL 中是这样。
强化学习中的遗憾
首先我们需要定义 RL 中的后悔。为此,我们首先将最佳行动 a*定义为给予最高回报的行动。

Optimal action
因此,我们将 T 次尝试过程中的后悔 L 定义为最佳行动产生的奖励 a*乘以 T 与任意行动的每次奖励从 1 到 T 的总和之差。

可以证明,当 T 趋于无穷大时,后悔趋于 C . log T 的一个下界。

贪婪&ε贪婪
Greedy 和 Epsilon Greedy 探索方法相当容易理解和实现,但是它们遭受重大挫折,即它们具有次优遗憾。事实上,贪婪者和贪婪者的后悔都是随着时间线性增长的。
这很容易直观地理解,因为贪婪者会锁定一个在某个时间点碰巧有好结果的行动,但它实际上并不是最佳行动。所以贪婪者会继续利用这个行为,而忽略其他可能更好的行为。它利用得太多了。
另一方面,贪婪的 Epsilon 探索太多,因为即使当一个行为看起来是最佳的,方法仍然分配固定百分比的时间用于探索,因此错过了机会,增加了总的遗憾。
相反,随着时间的推移,衰减的ε贪婪方法试图减少专用于探索的百分比。如下图所示,这可以产生最佳的遗憾。
然而,挑战在于能够执行正确的衰减过程。

面对不确定性保持乐观
面对不确定性的乐观是一种加强探索和减少总遗憾的方法。
假设我们有三个概率分布不同的老丨虎丨机,我们并不确切知道,但经过几次试验后,我们认为我们有以下分布形状。请记住,这些都是根据经验得出的,并不一定反映事实。

绿色 Q(a3)分布具有相当窄的基数,因为间隔很小[1.8,3.2],红色 Q(a2)具有较大的间隔[0,4],最后蓝色 Q(a1)具有最大的间隔[-1.8,5.2]。所以问题是我们下一步应该采取什么行动。
根据面对不确定性的乐观主义原则,即使不确定性较高,我们也会选择回报较高的行动。查看图表,我们很容易发现 Q(a1)可能比其他人有更高的回报(5.2),所以我们选择了它,即使它有更高的不确定性(它可能是 5.2,因为它可能是-1.8)。
假设采取了行动 a1,分布如下:

我们现在知道蓝色分布的最大值比另外两个小。所以我们对它不太确定,下一个动作将从另一个分布中选择,例如红色的。
这是原则,但如何在现实中实施呢?
这就是 UCB1 的意义所在。
UCB1
在上一段中,我们谈到了采取行动,这可能会带来最大的回报,即使这是不确定的。
然而,问题仍然是如何找到这个最大值?
一种方法是对每个动作的 Q 𝑡 (a)加上一个称为置信上限 U 𝑡 (a)的项,然后选择具有最大 Q 𝑡 (a) + U 𝑡 (a)的动作。

不言而喻,U 𝑡 (a)不是常数,而是应该随时间和经验而变化。
我们的意思是,随着时间的推移,我们频繁地选择行动(a),我们越来越确定 Q(a)是什么,它本身是一个平均值,所以 U 𝑡 (a)应该随着我们对 Q(a)越来越有信心而缩小。
U 𝑡 (a)的公式如下

其中 t 为试验总次数,N 𝑡 (a)为动作(a)被选择的次数。
该公式清楚地表明,随着 t 的增加,分子也以对数方式增加(例如缓慢增加),而当选择动作(a)时,N 𝑡 (a)增加 1,然而 U 𝑡 (a)急剧减少。
这里有一个例子:

我们可以看到,对于 t 从 100 到 1000,N 𝑡 (a)为 1,那么 U 𝑡 (a)从 2 到 2.45 增长非常缓慢,但是当 N 𝑡 (a)增加 1 时,U 𝑡 (a)急剧下降到 1.73。
所以 U 𝑡 (a)是一种调节选择动作(a)的方式,基于过去我们已经多次选择了这个动作。换句话说,它为我们提供了更多回报的确定性。
最终算法规定,对于每次迭代,我们计算所有动作的 Q 𝑡 (a) + U 𝑡 (a),并且我们选择具有最高 Q 𝑡 (a) + U 𝑡 (a)值的动作:

这种探索 vs 利用的方法保证了有一个对数遗憾。
重要提示 : UCB1 没有对分布的类型做任何假设,尽管在上面的图表中它们看起来像高斯分布,但是它们可以是任何分布。
正态分布
假设我们知道报酬分布是高斯分布:
ℛ(r) = 𝒩 (r,μ,σ)

算法变成选择最大化 Q(a)的标准偏差的动作

汤普森取样
也称为后验抽样,这是一种从每个分布中抽取样本,然后从样本中选择具有最大值的动作的方法。
采取行动并收集奖励后,我们更新采取行动的分配,以反映我们得到的结果。
当然,这需要更多的解释。
考虑一个骰子,我们不知道它是否有偏差,实际上我们没有任何关于它的信息。所以我们假设,作为开始,这是一个公平的骰子,得到任何数字的概率都等于 1/6。
所以最初的信念是概率分布是均匀的,等于 1/6。这称为先验分布,它构成了我们对骰子潜在概率分布的一种信念或假设(可能是错误的)。
现在我们开始掷骰子并收集结果,随着每个结果我们更新先验分布,使其反映实验的现实。新的分布现在被称为后验分布。我们不断重复这个过程大量的迭代,其中迭代(I)处的后验分布变成迭代(i+1)处的先验分布,直到我们到达最终后验分布非常接近真实的基础分布的阶段。
例如,如果我们注意到,在大量投掷后,我们有一个数字比其他数字占优势,这意味着分布不可能是均匀的,最有可能的是骰子有偏差。
现在出现的问题是,我们如何更新先验分布来获得后验分布?
要回答这个问题,让我们从定义贝塔分布开始:
贝塔分布是定义在区间[0,1]上的一族连续概率分布,区间由两个正参数α和β参数化,它们决定了分布的形状。

Formula of the Beta distribution, where C is a constant and 𝝰, β are parameters, and x is between 0 and 1
您可以将β分布视为一个分布族,其中每个成员根据参数𝝰,β的值而各不相同。
以下是β分布在𝝰,β值之后的一些形状示例。






Shapes of Beta distribution relative to the values of 𝝰, β parameters
如何采样?
采样包括从分布中随机获取值,但是由于分布可能不均匀,因此采样返回的值很可能来自分布达到峰值的区域。
例如,以上面这组图表中第二行的第三个图表为例。这种分布在大约 0.84 处达到峰值。因此,当从该分布中采样时,它更可能具有大约 0.84 的值,而不是例如具有小于 0.4 的值。
现在假设你有多个行动,每个行动都有未知的回报分布。我们使用汤普森抽样来发现哪种行为是最好的(它使平均回报最大化)。我们首先假设某个分布,如 Beta(1,1),它是每个动作的均匀分布,然后我们对这些分布进行采样,并选择具有最高采样值的动作。
一旦选择的动作被执行并且奖励被收集,选择的动作的分布被更新。
下面举一个多臂土匪(老丨虎丨机)的例子。
例子由三个多臂土匪组成:蓝、红、紫。由于我们对这些匪徒的潜在分布一无所知,我们假设他们是统一的。我们从这些分布中采样,得到如下结果:蓝色= 0.4,红色= 0.5,紫色= 0.7
结果是紫色的采样值最高,所以我们拉紫色机器的手臂。假设我们没有赢,那么我们需要通过将β参数增加 1 来更新我们对紫色分布的信念,使之成为β(1,2),这将给出下面的第一个图。

https://dataorigami.net/blogs/napkin-folding/79031811-multi-armed-bandits
我们再次采样,这一次红色分布得到了最高的采样值,所以我们拉动红色机器的手臂,我们就赢了。我们通过将𝝰增加 1 来更新红色分布,并且我们得到第二个图(第 2 列,第 1 行)。
当我们继续从所有分布中取样时,我们注意到蓝色的分布比其他分布获得更多的胜利,因此更新使它比其他分布更有优势,并且分布开始呈现向高值(> 0.8)的可能性峰值。这意味着我们更多地利用蓝色机器,而不是其他两个。换句话说,我们越来越相信我们已经找到了最佳行动。
结论
本文展示了强化学习中最常用的一些探索技术。从中学到的主要知识是,探索那些优先级低的行为是浪费时间和资源。因此,重要的是使用一种探索的方法来减少遗憾,这样学习阶段会变得更快更有效。
探索命名实体识别,埃莉诺·罗斯福是对的吗?
使用 spaCy 自然语言处理库从新闻文章中获取洞察力

Image credit: unsplash
据说埃莉诺·罗斯福说过:
伟大的头脑讨论想法;普通人讨论事件;心胸狭窄的人讨论人。
虽然这可能是的误解,这种说法似乎引起了许多人的直觉共鸣,但它有多真实呢?经得起推敲吗?
有许多方法可以对此进行调查,一个有趣的方法可能是在一堆报纸中寻找思想、事件和人物,看看它们出现的比例是否与读者的“思想大小”(伟大、普通、渺小)相关。
为了从报纸文章中挖掘信息,我决定使用一种称为命名实体识别(NER)的自然语言处理技术,这种技术用于识别句子中称为“命名实体”的东西。命名实体是诸如产品、国家、公司、数字之类的东西。为此,我将使用自然语言处理库。下面是他们的文档中的一个例子,展示了 NER 标签的外观:

spaCy 识别以下实体:
PERSON: People, including fictional.
NORP: Nationalities or religious or political groups.
FAC: Buildings, airports, highways, bridges, etc.
ORG: Companies, agencies, institutions, etc.
GPE: Countries, cities, states.
LOC: Non-GPE locations, mountain ranges, bodies of water.
PRODUCT: Objects, vehicles, foods, etc. (Not services.)
EVENT: Named hurricanes, battles, wars, sports events, etc.
WORK_OF_ART: Titles of books, songs, etc.
LAW: Named documents made into laws.
LANGUAGE: Any named language.
DATE: Absolute or relative dates or periods.
TIME: Times smaller than a day.
PERCENT: Percentage, including ”%“.
MONEY: Monetary values, including unit.
QUANTITY: Measurements, as of weight or distance.
ORDINAL: “first”, “second”, etc.
CARDINAL: Numerals that do not fall under another type.
可以看出,我们有人物和事件,但非常缺乏想法。为了纠正这一点,我们需要从其他人中选择一个来扮演思想的代理人。为此,我选择了百分比。这样做的原因是百分比通常是一种描述抽象概念的方式,人们在谈论例如作为一个整体的人类时使用它,而不是这个或那个人。从想法上来说,这不是一张完美的地图,但我们必须利用现有的资料。
至于读者的“思维规模”,我会选择科尔曼-廖可读性指数。这是一种量化读者必须达到何种教育水平才能理解文本的方法,使用以下公式计算:
Coleman_Liau = 0.0588*L–0.296*S-15.8L = Average number of letters per 100 characters
S = Average number of sentences per 100 characters
同样,这个类比并不完美,但希望足够好。
看起来我们已经建立了所有的方法,让我们开始处理数据吧!
获取和清理数据
我们将使用免费订阅的《newsapi.org》杂志提供的新闻提要。这意味着我们将获得一个标题,一个描述(文章的摘要)和文章的内容的前 260 个字符。我决定挑选一些主要来自美国和英国的流行英文报纸:
sources = ['abc-news', 'cnn', 'fox-news', 'cbs-news', 'the-new-york-times', 'reuters', 'the-wall-street-journal', 'the-washington-post', 'bloomberg', 'buzzfeed', 'bbc-news', 'daily-mail']
在获得数据(2019 年 6 月的 13,368 篇文章)后,我检查了这些数据,发现有几篇中文和阿拉伯文的文章会给 spaCy 带来问题。我用在 StackOverflow 上找到的一个函数清理了它:
latin_letters= {}def is_latin(uchr):
try:
return latin_letters[uchr]
except KeyError:
try:
return latin_letters.setdefault(
uchr, 'LATIN' in ud.name(uchr))
except:
print(uchr)
raise Exception()def only_roman_chars(unistr):
return all(is_latin(uchr) for uchr in unistr if uchr.isalpha())
清理之后,我们剩下 11458 个帖子,分布在不同的来源:
df.groupby('source').count()['title']abc-news 1563
bbc-news 1076
bloomberg 56
buzzfeed 295
cbs-news 780
cnn 809
daily-mail 1306
fox-news 1366
reuters 916
the-new-york-times 1467
the-wall-street-journal 590
the-washington-post 1234
我决定使用描述作为 NER 标签的基础,因为我们希望根据文章的内容来标记文章,而描述似乎是最适合的。
对于 Coleman-Liau,我们将使用内容,因为这样可以更好地反映文章的整体写作风格。
完成后,我们可以开始提取我们的实体:
ners = ['PERSON','NORP','FAC','ORG','GPE','LOC','PRODUCT','EVENT','WORK_OF_ART','LAW','LANGUAGE','DATE','TIME','PERCENT','MONEY','QUANTITY','ORDINAL','CARDINAL']# The ners we are most interested in
ners_small = ['PERSON', 'EVENT', 'PERCENT']nlp = spacy.load("en_core_web_sm")df['ner'] = df['Description'].apply(lambda desc: dict(Counter([ent.label_ for ent in nlp(desc).ents])))for ner in ners:
df[ner] = df['ner'].apply(lambda n: n[ner] if ner in n else 0)
我们按来源对它们进行分组,并对它们进行标准化:
df_grouped_mean = df.groupby('source').mean()# Normalize
df_grouped = df_grouped_mean[ners].div(
df_grouped_mean[ners].sum(axis=1), axis=0)
df_grouped['coleman_content'] = df_grouped_mean['coleman_content']# Do the same for the smaller ners-set
df_grouped_small = df_grouped_mean[ners_small].div(
df_grouped_mean[ners_small].sum(axis=1), axis=0)
df_grouped_small['coleman_content'] =
df_grouped_mean['coleman_content']
看着结果
fig, axes = plt.subplots(nrows=3, ncols=1)df_grouped[ners].iloc[:4].plot(kind='bar', figsize=(20,14), rot=10, ax=axes[0], legend=False);
df_grouped[ners].iloc[4:8].plot(kind='bar', figsize=(20,14), rot=10, ax=axes[1]);
df_grouped[ners].iloc[8:].plot(kind='bar', figsize=(20,14), rot=10, ax=axes[2], legend=False);

这个条形图可能有点难以解释,所以让我们来看看不同的新闻来源重点领域,或者他们拥有最多的实体:
focus = []for source in df_grouped[ners].values:
focus.append(sorted([(ners[i],x) for i,x in enumerate(source)], key=lambda x: x[1], reverse=True)[:3])
df_grouped['focus'] = [' '.join([y[0] for y in x]) for x in focus]
df_grouped['focus']abc-news ORG GPE DATE
bbc-news GPE PERSON ORG
bloomberg ORG GPE PERSON
buzzfeed ORG PERSON CARDINAL
cbs-news PERSON ORG GPE
cnn PERSON ORG GPE
daily-mail PERSON DATE GPE
fox-news ORG PERSON GPE
reuters DATE GPE ORG
the-new-york-times PERSON GPE ORG
the-wall-street-journal ORG GPE PERSON
the-washington-post GPE ORG PERSON
此外,让我们列出在某个主题中所占比例最大的新闻来源:
largest_in_topic = {}for n in ners:
largest_in_topic[n] = list(df_grouped.sort_values(n,ascending=False).index[:3])largest_in_topic{'PERSON': ['cnn', 'daily-mail', 'the-new-york-times'],
'NORP': ['the-washington-post', 'the-new-york-times', 'fox-news'],
'FAC': ['the-new-york-times', 'abc-news', 'fox-news'],
'ORG': ['buzzfeed', 'the-wall-street-journal', 'bloomberg'],
'GPE': ['abc-news', 'the-washington-post', 'bbc-news'],
'LOC': ['bloomberg', 'abc-news', 'the-washington-post'],
'PRODUCT': ['the-wall-street-journal', 'daily-mail', 'buzzfeed'],
'EVENT': ['bbc-news', 'bloomberg', 'reuters'],
'WORK_OF_ART': ['cbs-news', 'fox-news', 'the-new-york-times'],
'LAW': ['bloomberg', 'the-wall-street-journal', 'cnn'],
'LANGUAGE': ['bbc-news', 'fox-news', 'the-new-york-times'],
'DATE': ['reuters', 'daily-mail', 'cbs-news'],
'TIME': ['bbc-news', 'daily-mail', 'cbs-news'],
'PERCENT': ['bloomberg', 'buzzfeed', 'cbs-news'],
'MONEY': ['bloomberg', 'the-wall-street-journal', 'cbs-news'],
'QUANTITY': ['buzzfeed', 'bbc-news', 'cnn'],
'ORDINAL': ['bbc-news', 'cbs-news', 'reuters'],
'CARDINAL': ['bloomberg', 'cbs-news', 'abc-news']}
这里有一些有趣的事情需要注意:
- 几乎每个人都喜欢谈论国家、公司和人物。
- 正如所料,华尔街日报和彭博喜欢金钱和组织。
- 路透社喜欢精确日期。
如果我们只看较小的 NER 集,我们得到:

好的,看起来不错。是时候计算一下科尔曼-廖指数了。为此,我们需要能够分解成句子,这比我们想象的要困难得多。我将使用来自 StackOverflow 的函数:
import re
alphabets= "([A-Za-z])"
prefixes = "(Mr|St|Mrs|Ms|Dr)[.]"
suffixes = "(Inc|Ltd|Jr|Sr|Co)"
starters = "(Mr|Mrs|Ms|Dr|He\s|She\s|It\s|They\s|Their\s|Our\s|We\s|But\s|However\s|That\s|This\s|Wherever)"
acronyms = "([A-Z][.][A-Z][.](?:[A-Z][.])?)"
websites = "[.](com|net|org|io|gov)"
def split_into_sentences(text):
text = " " + text + " "
text = text.replace("\n"," ")
text = re.sub(prefixes,"\\1<prd>",text)
text = re.sub(websites,"<prd>\\1",text)
if "Ph.D" in text: text = text.replace("Ph.D.","Ph<prd>D<prd>")
text = re.sub("\s" + alphabets + "[.] "," \\1<prd> ",text)
text = re.sub(acronyms+" "+starters,"\\1<stop> \\2",text)
text = re.sub(alphabets + "[.]" + alphabets + "[.]" + alphabets + "[.]","\\1<prd>\\2<prd>\\3<prd>",text)
text = re.sub(alphabets + "[.]" + alphabets + "[.]","\\1<prd>\\2<prd>",text)
text = re.sub(" "+suffixes+"[.] "+starters," \\1<stop> \\2",text)
text = re.sub(" "+suffixes+"[.]"," \\1<prd>",text)
text = re.sub(" " + alphabets + "[.]"," \\1<prd>",text)
if "”" in text: text = text.replace(".”","”.")
if "\"" in text: text = text.replace(".\"","\".")
if "!" in text: text = text.replace("!\"","\"!")
if "?" in text: text = text.replace("?\"","\"?")
text = text.replace(".",".<stop>")
text = text.replace("?","?<stop>")
text = text.replace("!","!<stop>")
text = text.replace("<prd>",".")
sentences = text.split("<stop>")
sentences = sentences[:-1]
sentences = [s.strip() for s in sentences]
return sentences
进行计算:
def calculate_coleman(letter_count, word_count, sentence_count):
return 0.0588 * letter_count*100/word_count - 0.296 *
sentence_count*100/word_count - 15.8df['coleman'] = df['split_content'].apply(lambda x: calculate_coleman(
len(' '.join(x).replace(' ', '').replace('.', '')),
len([y for y in ' '.join(x).replace('’', '').split() if not y.isnumeric()]),
len(x)))df_grouped['coleman'].sort_values(ascending=False)bloomberg 14.606977
reuters 13.641115
bbc-news 13.453002
fox-news 13.167492
abc-news 13.076667
the-washington-post 13.025180
the-wall-street-journal 12.762103
cbs-news 12.753429
daily-mail 12.030524
cnn 11.988568
the-new-york-times 11.682979
buzzfeed 10.184662
这有点令人惊讶;举例来说,我本以为《纽约时报》会更高一点,但从另一方面来看,这可能是对的。如果我有超过 260 个字符的内容,这可能会更准确,但下一层的 newsapi 是 449 美元/月。只是为了确保稍后我会对照外部源再次检查可读性分数。
寻找相关性
让我们根据人员、事件和百分比绘制可读性图:



有趣的是,实际上似乎有一点关联,至少在人和事件上。让我们计算相关分数:
df_grouped_small.corr()

看看 coleman_content 专栏,埃莉诺·罗斯福(Eleanor Roosevelt)的话可能真的有些道理!至少在科尔曼-廖和人之间存在负相关,而在科尔曼-廖和事件之间存在正相关。
由于事件是为“普通”人设计的,我们预计散点图会移动到高事件值的中间,如下所示:

虽然这不是我们真正看到的,但人/事的负/正相关性仍然为引用提供了一些可信度。
当然,这要用一桶盐来吃。除了到目前为止我们所做的所有让步,我们没有足够的样本来达到统计学意义。实际上,我们来看看 p 值(来自 StackOverflow 的函数):
from scipy.stats import pearsonrdef calculate_pvalues(df):
df = df.dropna()._get_numeric_data()
dfcols = pd.DataFrame(columns=df.columns)
pvalues = dfcols.transpose().join(dfcols, how='outer')
for r in df.columns:
for c in df.columns:
pvalues[r][c] = round(pearsonr(df[r], df[c])[1], 4)
return pvaluescalculate_pvalues(df_grouped_small)

正如所料,p 值很低,除了百分比。
由于计算出的 Coleman-Liau 等级似乎有点偏差,我决定用以下可读性等级进行测试,这些等级摘自http://www . adamsherk . com/publishing/news-sites-Google-reading-level/
reading_level = {'abc-news': (41,57,1),'cnn': (27,69,2),
'fox-news': (23,73,2),'cbs-news': (28,70,0),
'the-new-york-times': (7,85,7),'reuters': (6,85,7),
'the-wall-street-journal': (9,88,2),
'the-washington-post': (24,72,2),'bloomberg': (6,81,11)}
他们给出了 3 个值(初级、中级、高级),我用不同的权重(-1,0,1)来计算一个值。
df_grouped_small['external_reading_level'] = df_grouped_small.index.map(
lambda x: reading_level[x][2]-reading_level[x][0] if x in reading_level else 0)
看看这种相关性
df_grouped_small[df_grouped_small['external_reading_level'] != 0][ners_small + ['external_reading_level']].corr()

我们发现相关性和我们之前得到的相似,除了我们实际上和百分比有更高的正相关性。
结论
我们的结果表明,引用的话实际上可能有一定的真实性,但统计意义如此之低,以至于需要进一步的研究。此外,事实证明,无论思想的大小,人们都喜欢谈论别人,非常喜欢。即使是最聪明的新闻(彭博,高得 14.6 分)谈论人的次数也是谈论事件或百分比的 7 倍。
观察柱状图,另一件突出的事情是报纸在内容选择上是多么的相似。因此,尽管人们的利益有所不同,但最终我们的相似之处要多于不同之处。
自杀数据的探索性分析

Foto de Ben Hershey em Unsplash
介绍
年复一年,自杀似乎变得越来越普遍。我自己,才 25 岁,我有一个熟人在大学期间自杀了。这一周,我在 Kaggle 附近闲逛,发现了一组关于自杀的数据。当时我想做一些分析,试图更好地理解这个主题。所以现在,在这篇文章中,我提出这个简短的评论。
如果有人也想“玩”这个数据集,只需通过链接获得 kaggle。
我不会把我用来做可视化的所有代码(它在 GitHub 中)放在这里,并提出数据集可能回答的问题。但在试图理解这些数据之前,我先简单解释一下这些数据里有什么。
数据描述
数据集中的每个数据代表一个年份、一个国家、一个特定的年龄范围和一个性别。例如,在巴西,1985 年,75 岁以上的人中,有 129 人自杀。
数据集有 10 个属性。这些是:
- 国家:记录数据的国家;
- 年份:记录数据的年份;
- 性别:性别(男或女);
- 年龄:自杀年龄范围,年龄分为六类;
- 自杀 _ 否:自杀人数;
- 人口:这一性别、这一年龄范围、这一国家和这一年的人口;
- 自杀人数/ 100k pop:自杀人数与人口/ 100k 之间的原因;
- GDP_for_year:世界卫生组织发布的当年国内生产总值;
- 人均国内生产总值:该国国内生产总值与其人口之间的比率;
- 世代:问题中的自杀世代,可能有 6 个不同的类别。
可能的年龄类别和世代是:
df['age'].unique()array(['15-24 years', '35-54 years', '75+ years', '25-34 years',
'55-74 years', '5-14 years'], dtype=object)
可能的代是:
df['generation'].unique()array(['Generation X', 'Silent', 'G.I. Generation', 'Boomers',
'Millenials', 'Generation Z'], dtype=object)
最初,数据集显示了各国的人类发展指数,但绝大多数数值都是空的。由于我想分析一个国家的发展对自杀人数的影响,所以我在数据中增加了一栏。我去了网站,我取了所有被认为是第一和第二世界的国家的名字,我用这些信息将我们的数据集的数据分为三类。第一、第二和第三世界。
Frist_world = ['United States', 'Germany', 'Japan', 'Turkey', 'United Kingdom', 'France', 'Italy', 'South Korea',
'Spain', 'Canada', 'Australia', 'Netherlands', 'Belgium', 'Greece', 'Portugal',
'Sweden', 'Austria', 'Switzerland', 'Israel', 'Singapore', 'Denmark', 'Finland', 'Norway', 'Ireland',
'New Zeland', 'Slovenia', 'Estonia', 'Cyprus', 'Luxembourg', 'Iceland']Second_world = ['Russian Federation', 'Ukraine', 'Poland', 'Uzbekistan', 'Romania', 'Kazakhstan', 'Azerbaijan', 'Czech Republic',
'Hungary', 'Belarus', 'Tajikistan', 'Serbia', 'Bulgaria', 'Slovakia', 'Croatia', 'Maldova', 'Georgia',
'Bosnia And Herzegovina', 'Albania', 'Armenia', 'Lithuania', 'Latvia', 'Brazil', 'Chile', 'Argentina',
'China', 'India', 'Bolivia', 'Romenia']country_world = []
for i in range(len(df)):
if df['country'][i] in Frist_world:
country_world.append(1)
elif df['country'][i] in Second_world:
country_world.append(2)
else:
country_world.append(3)df['country_world'] = country_world
现在,最后,让我们来探索一下。
探索数据
我会试着提出问题,并通过图表定量回答。这一部分所做的每一个分析都是指整个世界。
这些年来,自杀人数增加了吗?

由于数据一直持续到 2016 年,这张图表表明,当数据被收集时,2016 年才刚刚开始。此外,我们可以看到,从 1988 年到 1990 年,自杀人数大大增加。此外,这一数字在最近几年似乎以预期的方式增长并略有下降,这可能是由于最多样化的自杀预防运动。
谁更倾向于自杀?青少年?成年人?长辈?

嗯,看起来成年人肯定会更多地自杀,但这有什么意义呢?从数据来看,我们没有信息可以回答。但是我想这是一个患抑郁症和类似疾病的常见年龄。
性呢?男人和女人谁自杀更多?

当然,男人。这种模式会在所有年龄段重复吗?

是的,男性自杀率远远高于女性,甚至在 14 岁之前。
有自杀率更高的国家吗?
人口越多的国家自杀率越高,这是一种自然趋势,我使用了根据该国人口标准化的自杀数量字段。这样,每 10 万居民中的自杀人数就被计算出来了。

尽管自杀人数的差异不是很大,但还是有一些国家表现突出,比如俄罗斯和立陶宛。
而这一代人,他们在某些方面也有影响吗?

婴儿潮一代、沉默一代和 X 一代是由 1976 年以前出生的人组成的。这些人处于大多数自杀发生的年龄范围。只需查看处理年龄段的图表。
然而,一个国家的发展呢,它改变了什么吗?

越发达的国家自杀率越高。这可以用各种各样的理论来证明,比如过度工作、宗教问题、精神病发病率等等。
至于人均 GDP,有影响吗?

显然,在贫困地区,自杀率很高。收入增加,自杀一起减少。但是,从一个点(~ 20k)开始,自杀倾向再次增加。显然,数据显示在 60k 范围内有一些缺陷。
数据集属性之间有关联吗?

人口和 GDP 之间的相关性最高,因为一般来说,富裕国家的人口更多。同样,在自杀人数和人口之间,如果人口越多,自杀人数就越多。人均国内生产总值与世界各国之间呈负相关,因为第一世界国家收入较高,而第三世界国家收入较低。
当我们改变国家时,自杀的分布会有变化吗?

我选择了一些国家,它们的指数可能会揭示一些有趣的东西。请注意,我使用的是每 10 万居民的自杀人数。在这种情况下,巴西自杀人数的分布比其他国家更好,异常值较少,与其他国家相比,分布集中在低值。而像俄罗斯这样的国家,它的分布要分散得多,有几个自杀率很高的点。
巴西数据
因为巴西在这些数据中,而且因为我是巴西人,我对巴西的自杀数据特别感兴趣。所以我试着分析一下这个国家的具体费率。
自杀人数如何随时间变化?

显然,和世界上其他地方很不一样。由于巴西是一个发展中国家,看起来更像贫穷国家的自杀率正在上升到更发达国家的水平。
在巴西,成年人的自杀率也比较高吗?

显然,35-54 岁年龄段的世界自杀记录保持者并不在巴西。这一代人是婴儿潮一代。
结论
在这篇文章中,想法是对自杀数量的数据进行定量的探索性分析。总的来说,我们可以看到,这些数据显示了我们在报纸、电视等媒体上看到的东西,在我看来,我得出的大多数结论都是可以预测的;只是想象了更多的青少年自杀,这在数据中看不到。
我尽量不从人口统计学、社会和经济的角度来解释这些图表,保持文章的中立。然而,对于可用的数字可能有几种解释。
其中一个以流行的现成而似是而非的短语形式出现的反映是:
自杀越多,自杀越少
我认为,从上面可以定量地确定这一说法的真实性。
GitHub 上提供了用于生成图表、数据集和其他一些东西的所有代码。
1985-2016 年自杀数据分析。通过创建一个…
github.com](https://github.com/lmeazzini/Suicidal-analysis)
用 Python 进行探索性数据分析:医疗预约数据

“探索性数据分析”是一种态度,一种灵活的状态,一种寻找我们认为不存在的东西以及我们认为存在的东西的意愿。"
介绍
这些文字被认为属于一位杰出的美国数学家——约翰·图基。由于他贡献了几十个关于收集和分析数据的方法的绝妙想法,他在统计学的发展中发挥了关键作用。除此之外,他首先引入了'探索性数据分析 ' (EDA)术语。
让我们来看看这个术语背后隐藏的含义。
什么是 EDA
探索性数据分析 (EDA)是一套方法,包括单变量、双变量和多变量可视化技术、降维、聚类分析。
EDA 的主要目标是获得对数据的全面理解并引起对其最重要特征的注意,以便为应用更高级的分析技术和输入到机器学习算法中做准备。此外,它有助于生成关于数据的假设,检测其异常并揭示其结构。
你永远不应该忽视数据探索——跳过任何数据科学或机器学习项目的这个重要阶段,都可能导致生成不准确的模型或错误的数据分析结果。
在探索过程中,你应该从尽可能多的角度来看你的数据,因为魔鬼总是在细节中。
使用了哪些 EDA 技术
绘图技术对人类思维来说是最自然的,因此,绘图不应该被低估。这些技术通常包括使用盒须图、直方图、滞后图、标准差图、帕累托图、散点图、条形图和饼图、小提琴图、相关矩阵等来描述数据。
动机
本教程的目标是分享我在开始预测分析项目之前探索和可视化数据的经验。我希望能激发你对数据的洞察力,也希望图基鼓励统计学家更多地关注这种方法。
第一步。定义你的目标
在开始一个新的数据可视化项目之前,了解你的长期目标至关重要。
今天我们将使用包含患者预约信息的医疗预约号显示数据集。
每个患者的记录具有以下特征:
- 患者 id——患者的唯一标识符
- 约会 ID —约会的唯一标识符
- 性别
- ScheduledDay —计划进行约会的一天。
- 约会日——约会的真实日期
- 年龄——患者的年龄。
- 邻居——每个患者的邻居
- 奖学金——患者获得奖学金了吗?
- 高血压——患者有高血压吗?
- 糖尿病
- 酗酒
- 障碍
- SMS_received —患者收到短信提醒了吗?
- No_show —患者决定不露面了吗?
我们的目的是了解为什么接受治疗指导的人没有在下一个预约时间出现。换句话说,错过约会的促成因素是什么?
但这是长远目标。在深入挖掘之前,我们应该尝试回答以下问题:
- 错过约会的人和没错过约会的人的比例是多少?
- 谁不经常出现——男人还是女人?
- 不露面最流行的月份/日子/小时是什么?
- 患者年龄分布是怎样的?
这个列表并不完整——你可以在分析过程中想到的其他问题来扩展它。
准备您的工作空间
在本教程中,我们将尝试用 Python 可视化数据。我假设您知道如何使用基本的 Python 库。让我们导入处理数据所需的文件:
我们将使用 Plotly 作为主要图表库。这是一个开源的 Python 包,它扩展了 d3.js 和 stack.gl 的功能,并提供了可以满足任何项目要求的复杂图表。由于是高级的,Plotly 使用起来更方便,因此我更喜欢它而不是 matplotlib。
我非常欣赏的另一件事是它用图表探索数据的交互性。
我们将离线使用它,这样就不会创建一个帐户,并且在尝试构建图表时受到限制。
读取数据
从 Kaggle 下载数据后,下一步是基于 CSV 数据构建熊猫数据框架。这里有一个教程,它会让你对和熊猫一起工作感到舒服。
让我们删除一些不需要的列,以便加快数据处理速度:
分析数据
在清理数据之前,让我们检查一下数据的质量和每一列的数据类型。

Information about the dataframe
在这里,您还可以检查数据帧使用的内存数量。
使用head()方法显示数据帧的前五行:

使用.shape属性检查样本和特征的总数:
我们有 110527 个记录和 12 个特征。
清理和准备数据
清理数据是一门艺术,在开始任何数据科学或机器学习项目之前,都应该首先掌握它。它使数据更容易研究和构建可视化。
在您检查了功能的数据类型之后,您可能已经注意到“日程安排日”和“约会日”功能有一个“对象”数据类型。
为了便于处理日期特征,让我们将“日程安排日”和“约会日”的类型转换为日期时间 64[ns]* 。您需要它来访问有用的方法和属性。*
另一种方法是在读取数据时转换列的类型。
为此,将应被视为日期列的列名列表传递给“read_csv”方法的“parse _ dates”参数。这样,它们将以可读的方式格式化:
此外,将字符串数据类型转换为分类数据类型也是一个好主意,因为这种数据类型可以通过缩小数据框架来帮助您节省一些内存。分类变量的内存使用与分类数量+数据长度成比例。
此外,大多数统计 Python 库将分类列视为分类变量。
有时数据可能不一致。例如,如果预约日期早于预定日期,那么就有问题了,我们需要交换他们的值。
美化列名
您可能已经注意到我们的功能包含键入错误。
我们来重命名拼错的列名:
或者,您可以将“未显示”列重命名为“存在”,将其值重命名为“存在”和“不存在”,以避免任何误解。
现在,我们的数据集既整洁又准确,让我们继续用新的功能扩展数据集。
特征工程
我们可以向数据集中添加一个新功能-“等待时间天数”,以检查患者需要等待预约日期的时间。
另一个新功能可能是“WeekDay”——约会的工作日。有了这个功能,我们可以分析人们不常出现的日子。
同样,添加“月”、“小时”功能:
处理缺失的值
让我们以这种优雅的方式检查每一列中是否有空值:

或者,如果您想检查单个列是否存在空值,您可以这样做:
我们很幸运——我们的数据集中没有空值。
但是,解决缺失值的策略是什么呢?
通过分析现有的技术和方法,我得出结论:处理缺失数据的最流行策略是:
- 让他们保持原样。
- 用
dropna()将其移除。 - 用
fillna()填充 NA/NaN 值。 - 用期望值(平均值)或零替换缺失值。
- 如果缺失值的数量超过某个阈值(例如>值的 50%),则删除列。
探索数据集
一旦你清理了数据,是时候更深入地检查它了。
执行以下步骤:
- 检查所有列中的唯一值

- 看一看数字特征的基本统计数据:

标图数据
- 按性别检查患者分布。
用于可视化比例的最佳图表是饼图、圆环图、树形图、堆积面积图和条形图。让我们使用一个饼图:

- 检查有多少人没有在约会日期出现:

很明显,只有 20.2%的患者没有出现,而 79.8%的患者在预约日出现。
- 测量“年龄”数据的可变性。
一个盒&须状图最好地处理这个任务:

通过这个交互图,可以看到数据的中间四分位数(中位数)是 37 。
这意味着 50%的患者年龄小于 37 岁,另外 50%的患者年龄大于 37 岁。
上四分位数表示 75%的年龄值低于 55 。下四分位数表示 25%的年龄值低于 18 。
从下到上四分位数的年龄值范围被称为四分位数间距。从图中可以得出结论,50%的患者年龄在 18 岁到 55 岁之间。
如果你看一下胡须,你会找到最大值(不包括异常值)也就是 102 。
我们的数据只包含一个异常值——一个年龄为 115 的患者。最低值为 0,这是很有可能的,因为患者可能是小孩。
该图允许获得的另一个洞见是,由于箱形图不对称,数据明显正向偏斜。四分位数 3 —四分位数 2 >四分位数 2 —四分位数 1。
- 检查那些出现和没有出现的人的年龄的四分位数范围。

为此,我们可以使用相同的盒状图,但它是按“存在”列分组的。
- 分析男性和女性的年龄范围:

- 按性别检查出现和不出现的频率

- 人们在哪些工作日最不经常出现:

你可以看到人们通常不会在周二和周三出现。
下一步是什么
稍后可应用于该数据的可能技术:
- 无监督 ML 技术,即 KMeans 聚类或层次聚类(但别忘了缩放特征!).聚类可能有助于了解哪些患者群体具有共同的特征。
- 分析哪些变量对“不露面”一栏有解释力。
把所有的东西放在一起
暂时就这样吧!您已经完成了对数据集的探索,但您可以继续揭示见解。
希望这个简单的项目有助于理解 EDA 的基本概念。我鼓励你尝试用数据和不同类型的可视化来找出获取最大数据的最佳方式。
反馈
反馈的重要性不能被高估。我想掌握我分析数据的技能,所以我很高兴听到你的反馈、想法和建议。
探索性数据分析:
Python 中的插图

Photo by James Harrison on Unsplash
数据科学家的工作流程可以分为六个部分:
- 定义问题
- 收集数据
- 探索数据
- 用数据建模
- 评估模型
- 回答问题
这个工作流程不是一个线性过程。在许多情况下,它涉及到整个过程不同部分之间的多次往返。
我曾经听一位数据科学家说过,数据探索应该是数据分析师或其他底层人员的角色;数据科学家的角色应该是建立和评估模型。真的是这样吗?数据科学家应该擅长调整模型,却不擅长管理和清理数据吗?建立和使用复杂的机器学习模型的能力非常强大。但是必须指出,该过程的某些部分可以(并且已经)自动化。我无法证明流程的哪个部分应该获得最大的权重(想想常见的 0.8 比 0.2 规则)。然而,我将提出一个问题,并提供基本的演练,以解决您在旅途中可能遇到的类似问题。
几年前,我在一家公司工作,该公司维护着 200 多个数据库,并向许多客户提供时间序列数据。我亲眼看到了数据收集和输入的过程,我很快意识到这比我最初想象的要复杂得多。这个过程,即使是由机器或者非常细致的人来完成, 也是容易出错的。因此,这些数据集的消费者(即使在他们经历了质量控制过程之后)拥有的数据可能传达不准确或错误的信息。这可能会给决策者和利益相关者带来破坏性后果。因此,数据科学家必须“审查数据”然后才能为其拟合任何模型。
在这里,我提出了一个基本的探索性数据分析(EDA ),它可以在处理“有趣”的东西之前执行。
导入工具包
我们从导入一些 Python 包开始。这些将作为有效 EDA 的工具箱:
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd %config InlineBackend.figure_format = 'retina'
%matplotlib inline
在这个例子中,我们将使用波士顿住房数据集(之后用它练习并说服自己)。让我们将数据加载到我们的工作区,并查看前五行(记住 Python 索引是从 0 开始的)。
加载并检查数据
df = pd.read_csv(boston_file)df.head()

First five rows of the Boston housing data
接下来,您想要检查数据的结构和格式:
df.isnull().sum() # returns the sum of missing values across columnsdf.shape # returns a matrix of *i* rows and *j* columns.df.dtypes

解决异常情况
我们立即从这次检查中注意到一些事情。首先,第一列似乎是索引的重复。在没有数据字典的情况下,我们可以有把握地假设这是事实。让我们放弃这个专栏:
df.drop(columns = ['Unnamed: 0'])
包含作为方法inplace=True的参数的一部分,以将更改永久应用于数据。
其次,DIS和RAD变量的格式不正确。我们从上面显示的表格中了解到这一点。让我们从解决最明显的问题开始:DIS特性。该列中的值包含一个字符串字符','。这将导致 Python 将数字数据读取为 pandas 对象数据类型。我们可以使用地图功能来处理这个问题:
df['DIS'] = df['DIS'].map(lambda dis_cell: dis_cell.replace(',', '.'))df['DIS'] = df['DIS'].astype(float)
df.dtypes

瞧,问题解决了!
另一方面,RAD变量需要更多一点的探测。目前还不清楚是什么导致这些值以这种方式被读取。
df['RAD'].sort_values(ascending= False).head(8)

好了,我们找到罪犯了。我们可以使用与处理DIS案例相似的流程来处理这个问题。请注意,在我们替换这个字符串字符后,我们现在会有一些丢失的数据。这些可以是丢弃的或估算的。这是数据科学家需要根据其领域知识、寻求解决的问题或直觉做出判断的许多次中的一次。
更改列名
现在,假设您正在一个团队中工作,该团队的成员的任务是向非技术观众或不知道每列代表什么的成员展示数据的发现。您可能希望使列名更具描述性。方法如下:
new_columns_names = {
'CRIM':'rate_of_crime',
'ZN':'residential_zone_pct',
'INDUS':'business_zone_pct',
'CHAS':'borders_river',
'NOX':'oxide_concentration',
'RM':'average_rooms',
'AGE':'owner_occup_pct',
'DIS':'dist_to_work',
'RAD':'access_to_highway',
'TAX':'property_tax',
'PTRATIO':'student_teacher_ratio',
'LSTAT':'pct_underclass',
'MEDV':'home_median_value'
}df.rename(columns = new_columns_names, inplace=True)df.head()

8 out of 13 columns displayed here.
坚持住,我们即将结束这次基本演练!!
现在,我们想更深入一点,看一看对数据更简洁的描述:
df.describe().T #returns a description in transposed matrix

这个简单的方法返回了一个很好的数据摘要。我们现在可以访问每个数字列的有用统计数据,例如平均值、中值(50%)、最小值和最大值(用于观察异常值)、计数(用于发现缺失值)等等。
绘制数据
在数字挣扎的地方,图表更胜一筹。面对现实吧,数字可能很无聊。听一个 只有 用数字讲故事的主持人很难,即使是对于我们这些量化的朋友。
不要用统计学术语说话,给他们看!一个很好的起点是使用直方图查看数据的分布:
df.hist(figsize = (14,14))

最后,根据您寻求解决的问题,您可能希望检查变量之间的相关性。这在执行线性回归时尤其重要。
plt.figure(figsize=(12, 12))
sns.heatmap(df.corr(), annot = True, cmap = 'coolwarm')

我们有一个(皮尔逊)相关矩阵,用直观的热图呈现。还是那句话,不要只用数字!
另外,你可能想要绘制其他类型的图来检查关系,找出异常值,并确定目标变量和预测变量的基本分布。
结束语
如前所述,与数据科学家的其他工作流程一样,EDA 组件也不是线性的。它涉及多次迭代;我的经验告诉我,这是一个循环过程。
这个演示是一个简单的 EDA,可以在大多数数据集上实现;它当然不是详尽无遗的,但是,它是有用的。用数据弄脏你的手!假设没有一个数据集是干净的,直到你梳理过它。如果你的目标是生产高性能的模型,这部分过程是必不可少的。正如乔治·富克斯尔所说,“垃圾进来,垃圾出去”。
探索性数据分析,分类数据—第二部分

“想出新功能很困难,很耗时,需要专业知识。‘应用机器学习’基本上是特征工程。”
—吴恩达教授。
数据科学家花费将近 75%的时间来分析数据和工程特性,这确实是一个困难且耗时的过程。他们需要领域知识和数学计算。
探索性数据分析和特征工程是选择、描绘和转换数据为特征的过程,这些特征可以作为机器学习模型的输入来进行预测。我们应该记住,好的质量特性总是有助于提高整体模型性能。很多时候,即使机器学习任务在不同的场景中可以是相同的,但是在分析每个场景中的数据之后提取的特征将会彼此不同。

上述数据集具有特征“预测 _ 类别”,该特征基于在特征“清洁 _hm”中呈现的人的陈述来检测该人的情绪。" 原始特征"直接从数据集中获得,无需额外的数据操作或工程,而"衍生特征"从特征工程中获得,其中我们从现有数据属性中提取特征。
nycdata = pd.read_csv(“train.csv”)
nycdata.head(5)

Raw features
nycdata.shape(50000, 8)
现在,在完成某些功能工程后,让我们检查:
nycdata.head(5)

nycdata.shape(50000, 12)
因此,我们通过特征工程从原始数据集中又提取了 4 个特征。
在本文中,我将处理数据分析和分类数据的一点特性工程。
让我们考虑一个简单的例子,人们的陈述决定了他们的情绪。现在,如果我认为在这个数据集中所有人都是幸福的,幸福被分为几类——爱、成就、休闲、亲密。例如,某人在工作中获得了提升,他很高兴,这意味着【成就】,而另一个人很高兴,因为他在很长一段时间后与朋友进行了热烈的交谈,这清楚地表明了【感情】,一位母亲很高兴,因为她孩子的生日再次表明了【感情】。我们可以清楚地看到这里没有办法对“幸福属性的这些值进行排序。
但是有一些有序的分类数据,如鞋码、t 恤尺寸或教育水平等。它们遵循特定的顺序。
我更喜欢总是从加载所有必需的依赖项开始。
import numpy as np #linear algebra
import pandas as pd #data processing
import os #operating system dependent modules of python
import matplotlib.pyplot as plt #visualization
import seaborn as sns #visualization
%matplotlib inline
from nltk.corpus import stopwords
from nltk.stem import PorterStemmer
from sklearn.preprocessing import LabelEncoder
import re
from wordcloud import WordCloud, ImageColorGenerator
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
正在加载。csv 文件
at.head(5)

让我们获取数据集的信息。
at.info()Output--<class 'pandas.core.frame.DataFrame'>
RangeIndex: 60321 entries, 0 to 60320
Data columns (total 5 columns):
hmid 60321 non-null int64
reflection_period 60321 non-null object
cleaned_hm 60321 non-null object
num_sentence 60321 non-null int64
predicted_category 60321 non-null object
dtypes: int64(2), object(3)
memory usage: 2.3+ MB
如果一个大数据集有几个特性,我可以通过以下命令获得所有特性的名称:
dataset.columns
数据集的详细信息通过以下方式获得:
at.describe()

我可以得到那些有数字数据的特征的描述。如果我需要所有功能的描述,我会使用:
at.describe(include='all')
这是一种描述性统计,用于总结数据集分布的集中趋势、分散和形状。
编码分类变量:
我需要根据句子预测【幸福】。最初,我为“幸福”的不同标签绘制了一个索引:
from sklearn.preprocessing import LabelEncoder
cols = [‘predicted_category’]
lbl = LabelEncoder()
pred_lbl = lbl.fit_transform(at[cols])mappings = {index: label for index, label in enumerate(lbl.classes_)}
mappings{0: 'achievement',
1: 'affection',
2: 'bonding',
3: 'enjoy_the_moment',
4: 'exercise',
5: 'leisure',
6: 'nature'}
通过函数“标签编码器”,一个对象“LBL”将一个数字映射到“预测 _ 类别”特征的每一个值。
现在,我需要对我们的分类变量应用一个特定的编码方案。原因很简单。如果我直接将pred_lbl属性作为机器学习模型中的一个特征,它会认为它是一个连续的数字特征,认为值 6(Nature’)大于 2(‘Bonding’),但这是没有意义的,因为‘Nature’肯定不会大于或小于’Bonding’,这些实际上是不能直接比较的类别。因此,我需要一个额外的编码方案层,其中需要为每个唯一值创建虚拟特征。
dummy_features = pd.get_dummies(at['predicted_category'])
at=pd.concat([at[['hmid','cleaned_hm']],dummy_features],axis=1)
at.head(9)

由于我们的预测 _ 类别仅取决于人们的陈述,因此我们考虑了“cleaned _ hm”以及“hmid”
清洁和预处理原始文本:
特征“cleaned_hm”包含了我们需要清理的杂乱的原始数据。
stops = set(stopwords.words("english"))
def cleanData(text, lowercase = False, remove_stops = False, stemming = False):
txt = str(text)
#print(txt)
txt = re.sub(r'[^A-Za-z0-9\s]',r'',txt)
#print(txt)
txt = re.sub(r'\n',r' ',txt)
#print(txt)
#convert whole text to lower case & remove stopwords and stemmers
if lowercase:
txt = " ".join([w.lower() for w in txt.split()])
if remove_stops:
txt = " ".join([w for w in txt.split() if w not in stops])
if stemming:
st = PorterStemmer()
txt = " ".join([st.stem(w) for w in txt.split()])
#print(txt)
return txt# clean description
at['cleaned_hm'] = at['cleaned_hm'].map(lambda x: cleanData(x, lowercase=True, remove_stops=True, stemming=True))

与原始数据集不同,我现在有一个非常紧凑的信息,可以将我的数据输入到机器学习中。函数“clean data”删除了不需要的标点符号和单词,并将其转换为完整的小写字母。
现在,除了“cleaned _ hm”,我所有的特征都是数字格式。我必须找到出现频率最高的单词。使用 WordCloud 也可以达到同样的效果。
#use word cloud to understand the word that has the most frequency
text = ' '.join(at['cleaned_hm'].tolist())
text = text.lower()
wordcloud = WordCloud(background_color="white", height=2700, width=3600).generate(text)
plt.figure( figsize=(14,8) )
plt.imshow(wordcloud.recolor(colormap=plt.get_cmap('Set2')), interpolation='bilinear')
plt.axis("off")
矢量化:
为了理解可以在我们的机器学习模型中使用的特征“cleaned _ hm”,我们需要将每个语句转换为数字表示,我们称之为矢量化。
下一次我们将讨论各种矢量化的细节以及如何使用它们。
探索性数据分析初学者指南
包括一个简单的案例研究,以便更好地理解

Image by Author
目录:
- 介绍
- 数据类型
- 单变量分析
- 双变量分析
- 结论
1。简介:
假设你想为你的一次旅行预订一张机票。现在,你不会直接去一个特定的网站,并预订你看到的第一张票。你首先要在多家航空服务提供商的多个网站上搜索机票。然后你将比较票价和他们提供的服务。有免费 WiFi 吗?早餐和午餐是免费的吗?航空公司的总体评分比其他航空公司好吗?
从考虑买票到找到最适合你的票并预订,你将采取的任何措施都被称为“数据分析”。探索性数据分析的正式定义如下:
探索性数据分析(EDA)是指对数据进行初步调查的关键过程,以便在汇总统计和图形表示的帮助下发现模式、发现异常、测试假设和检查假设。
2。数据类型:

Types of Data (Image by author)
- 二分变量:二分变量是在测量时只取两个可能值之一的变量。性别:男性/女性。
- 多项式变量:多项式变量是有多个值可供选择的变量。教育资格:未受教育/本科/研究生/博士等。
- 离散变量:离散变量是可数变量。例如,您的银行存款余额、组织中的员工人数等。
- 连续变量:连续变量是一个有无限个可能值的变量。任何一种测度都是一个连续变量。温度是一个连续的变量。特定区域的温度可以描述为 30℃、30.2℃、30.22℃、30.221 ℃,等等。
所以你一定在想,为什么我们需要知道这些不同类型的数据来进行分析?答案是,统计方法是为处理特定类型的数据而设计的,而不是其他类型的数据。人们用来分析连续数据的许多方法可能不适用于分类数据。如果您不知道数据的类型,您可能会提供错误的数据分析!在统计学中,有大量可能的分析可以完成。了解我们可用的数据类型会限制可能性,并帮助我们选择最适合该数据的分析方法。
现在我们已经了解了不同类型的数据,让我们深入研究单变量分析。在应用任何类型的机器学习算法之前,了解您正在处理的数据类型非常重要。数据有什么样的特征(列)?它是数字数据还是分类数据?要了解数据,分析数据很重要。
3。单因素分析:
单变量分析是分析数据的最简单形式。它是对一组不同特征中的一个特征的分析。它通常给我们一个特定特征的描述。它不处理原因或关系,它只是获取数据,对其进行总结,并以直方图、盒状图和须状图等形式表示出来。我们将在接下来的章节中了解这一点。
3.a 描述性统计:
- 集中趋势:集中趋势是指一个分布的位置。它代表了我们通常对参与者的期望值。我们有三种选择来描述分布的中心趋势。
- 平均值:平均值也称为算术平均值,计算分布中所有值的平均值。平均值容易出现异常值。
- 中位数(Q2): 中位数是分布的第 50 个百分位数。如果分布具有奇数个值,则考虑中间元素;如果分布具有偶数个值,则考虑两个中间元素的平均值。
- 众数:众数是分布中出现频率最高的值。数据分布中可以有一种或多种模式。
尽管集中趋势的度量告诉我们分布的中心,但它并不告诉我们分布中的每个值。参与者可以具有比平均值低得多或比平均值高得多的值。所以我们也应该知道分布的可变性。
- 差异:
使用范围、标准偏差和四分位间距来指定分布的方差。
- 范围:范围就是分布中的最大值和最小值之差。
- 标准差:标准差是一个描述一个组的成员与该组的平均值相差多少的量。
- 四分位间距:四分位间距是第三个四分位(Q3)与第一个四分位之间的差值。
a .第一个四分位数(Q1): 第一个四分位数定义为最小数和数据集中位数之间的中间值。
b .第二个四分位数(Q2): 第二个四分位数不过是数据集的中位数。
c .第三个四分位数(Q3): 第三个四分位数是数据集的中值和最高值之间的中间值。
现在,让我们借助一个示例来理解可用于描述单变量数据的不同图表和图形。使用的数据集是“带评级的视频游戏销售”,可以在这里找到。
首先,让我们导入所需的库。

Screenshot by Author
加载数据:

Screenshot by Author
所有数字数据的五点汇总:
在这里,我们可以看到一些描述性统计数据,如所有数字数据的平均值、标准差、最小值、Q1、Q2、Q3 和最大值。

Five-point summary (Screenshot by Author)
3.b 直方图:
我们可以使用直方图了解更多关于数字数据的信息。数学分数具有单峰和对称分布。直方图是说明分布的集中趋势、可变性和形状的好方法。如果存在多种模式,这也是识别它们的好方法。然而,直方图并不是识别异常值的好方法。

Histogram (Screenshot by Author)
上面的直方图显示了一个特定游戏的发布时间。我们可以看到,最大游戏数量在 2005 年至 2012 年间推出,然后逐渐下降。
3.c 箱线图:
箱线图是说明连续变量的另一种更可靠的方法。箱形图中的垂直线具有特定的含义。方框中的中心线是数据的第 50 个百分位数(中位数)。可变性由通过标记第一个和第三个四分位数形成的方框表示。这个方框代表四分位数范围。胡须从盒子向左右延伸。当没有异常值时,左栏和右栏代表最小值和最大值。当存在任何异常值时,用围栏外的小圆圈或星形表示。
箱线图是说明分布的集中趋势、可变性和偏斜度的有用方法。这也是检测异常值和极值的一个很好的方法。直方图和箱线图都有一定的局限性和限制。因此,在浏览数据时,您应该绘制直方图和箱线图,但只选择其中一个用于报告,以便我们更好地了解数据。如果你有一个有异常值的单峰分布,用一个箱线图,如果你有一个双峰分布,用一个直方图。

Boxplot (Screenshot by Author)
三维分类数据—条形图:
这是一个条形图,显示了客户用来玩游戏的不同平台。我们可以看到,大多数客户使用 PS2 作为他们的控制台,较少的客户使用 GG 或 PCFX 等控制台。
条形图是表中信息的图形表示。条形图的一个关键特征是条形图彼此不接触。这一特征表明这些值是分类的而不是连续的。这是绘制分类数据的合适方法。

Bar Graph (Screenshot by Author)
这是条形图的另一个例子。该图显示了客户演奏的不同流派。最受欢迎的类型是动作片,而最不受欢迎的是益智片。

Bar Graph (Screenshot by Author)
4。双变量分析:
在 EDA 中,我们经常会学到两个变量之间的关系。可以提出一些问题,例如:
- 一个特征与另一个特征的相关程度如何?
- 一个变量的较低值对应于另一个变量的较低值吗?
- 一个变量的较高值对应于另一个变量的较高值吗?
- 这两个特征遵循什么样的关系?
描述两个变量之间的关系比我们已经讨论过的方法更复杂,因为我们必须考虑两个变量中的数据类型。可能有不同的数据组合,例如一个可能是连续的,另一个可能是分类的,或者两个都是连续的,或者两个都是分类的。这些组合导致不同的统计和图形摘要。分析的必要部分是两个变量都必须有某种值。如果任何变量缺少任何值,它们就不能包含在分析中。
现在让我们来看一些可以在双变量分析中做出的图形总结。
4 .关联:
数据关联是了解数据集中多个值或要素之间关系的一种方式。相关性有助于在一个属性的帮助下预测另一个属性(这可用于估算数据集中的缺失值)。
有三种不同类型的相关性:
- 正相关:如果一个特征与另一个特征的值的变化成正比,则相关被认为是正的。
例如:如果特征 A 的值增加,那么特征 B 的值也增加,或者如果特征 A 的值减少,那么特征 B 的值也减少。
2。负相关:如果一个特征与另一个特征的值的变化成反比,则相关被认为是负的。
例如:如果特征 A 的值增加,那么特征 B 的值减少,反之亦然。
3。不相关:这两个属性之间不存在任何关系。
这些相关类型中的每一种都存在于由从-1 到+1 的值表示的谱中,其中轻微或高度正相关特征可以像 0.5 或 0.7。相关性分数为 0.9 或 1 表示非常强且完美的正相关性。如果有很强的负相关,就用-0.9 或-1 的值来表示。接近零的值表示没有相关性。
之所以要了解特征之间的相关性,是因为一个叫做“多重共线性”的概念。如果数据集具有完全正相关或负相关的属性,则模型可能会受到多重共线性的影响。当一个预测变量可以通过其他预测变量以较高的准确度进行线性预测时,就会出现多重共线性。虽然你可能认为这是一件好事,但事实并非如此,因为它会导致误导或扭曲的结果。
处理这个问题的一些方法是删除一个完全相关的特征或者使用降维算法,例如主成分分析(PCA)。
下面的代码显示了我们如何以矩阵的形式可视化特征之间的相关性。

Screenshot by Author

Heatmap (Screenshot by Author)
这里我们可以看到,有一些特征具有轻微的正相关或负相关,但没有完全的正相关或负相关。对角线元素的值将始终为 1,因为它们与相同的特征进行比较。
4.b 散点图:
在散点图中,点分别用点、圆或其他形状表示。使用散点图可以轻松检测异常值和极值。
在下图中,绘制了全球销售和北美销售之间的散点图。我们可以在最右上方发现一个异常值。

Scatter Plot (Screenshot by Author)
4.c 配对图:
除了单独绘制散点图,我们还可以绘制成对图。它会为每个特征和其他特征绘制一个散点图。请注意,默认的 seaborn 库只绘制数字的配对图。对角线上的直方图允许我们看到单个变量的分布,而上下三角形上的散点图显示了两个变量之间的关系(或缺乏关系)。

Screenshot by Author

Pair plot (Screenshot by Author)
5。结论:
这只是探索性数据分析的一个小介绍。我的目的不是向您介绍各种其他类型的图表和图形摘要,而是让您了解应该对不同类型的数据进行什么样的分析。读完这篇文章后,我建议你选择任何数据集,自己完成 EDA。
如果你已经走了这么远,非常感谢。如果你有任何建议让这个博客更好,请在评论中提出。
探索性数据分析:结构化数据的实用指南和模板

Photo by Rawpixel on depositphotos
通常,最难的不是画画,而是在一张白纸上画什么会难倒人。
同样,对于数据科学,人们可能想知道在收到数据集后如何开始。这就是探索性数据分析(EDA)的用武之地。
根据维基百科,EDA“是一种分析数据集以总结其主要特征的方法,通常采用可视化方法”。用我自己的话来说,它是关于了解你的数据,在你开始从数据中提取洞察力之前,对数据有一定程度的熟悉。
由于 EDA 对于所有数据科学项目来说都是至关重要的第一步,懒惰的 me 决定编写一个代码模板,用于在结构化数据集上执行 EDA。这个想法是花更少的时间编码,更多地关注数据本身的分析。向下滚动到代码链接的底部,但是请继续阅读,找到更多关于 EDA 的信息,并理解代码的作用。
EDA 在数据科学过程中处于什么位置
在我们深入研究 EDA 之前,首先了解 EDA 在整个数据科学过程中的位置非常重要。

Image by author, inspired by Farcaster at English Wikipedia
参考维基百科中的流程图,在收集数据后,在清理之前会进行一些处理,然后执行 EDA。请注意,在 EDA 之后,我们可能会回到数据的处理和清理,也就是说,这可能是一个迭代过程。随后,我们可以使用干净的数据集和来自 EDA 的知识来执行建模和报告。
因此,我们可以这样理解 EDA 的目标:
了解数据,从数据中寻找线索,
- 为我们的建模制定假设和假说;和
- 检查数据质量,必要时进行进一步处理和清理。
为了更好地说明 EDA 的概念,我们将使用来自 Kaggle 的 Rossmann 商店销售“train.csv”数据。请记住,问题陈述是为了预测商店销售,因此,我们的 EDA 目标是:
- 检查有助于预测销售的功能;和
- 检查可能影响我们预测模型的异常或异常值。
EDA 概述
我们的代码模板将执行以下步骤:
- 预览数据
- 检查条目总数和列类型
- 检查任何空值
- 检查重复条目
- 数值数据的图分布(单变量和成对联合分布)
- 分类数据的绘图计数分布
- 按每日、每月和每年的频率分析数字数据的时间序列
必要的依赖关系如下:
import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
import missingno
%matplotlib inline
初步数据处理
首先,我们读入数据集,并生成数据的简单预览和统计。
df = pd.read_csv('train.csv')
df.info()
df.head()

输出显示我们有大约 100 万个条目,有 9 列。没有空值,但应该更改一些列的数据类型。正如我们将在后面看到的,正确设置数据类型可以在我们的数据科学过程中帮助我们。简而言之,有三种常见的数据类型(分类、数字和日期时间),我们对每种类型都有不同的 EDA 过程。
在我们的初步处理中,我们以下列方式更改了数据类型:
- 设置标识符将存储为字符串。
- 对于分类的列,也就是说,可能值的数量有限且通常是固定的列,我们将它们的类型设置为“category”。例如性别、血型和国家都是分类数据。
- 对于数值型的列,我们可以将它们的类型设置为“int64”(整数)或“float64”(浮点数)。例如,销售额、温度和人数都是数字数据。
- 将日期设置为“日期时间 64”数据类型。
# set identifier "Store" as string
df['Store'] = df['Store'].astype('str')# set categorical data
df['DayOfWeek'] = df['DayOfWeek'].astype('category')
df['Open'] = df['Open'].astype('category')
df['Promo'] = df['Promo'].astype('category')
df['StateHoliday'] = df['StateHoliday'].astype(str).str.strip().astype('category')
df['SchoolHoliday'] = df['SchoolHoliday'].astype('category')# set datetime data
df['Date'] = pd.to_datetime(df['Date'])
我们的 EDA 开始了
设置完数据类型后,我们就可以开始娱乐了。
要建立这个聚会,我们只需复制、粘贴并运行包含各种函数的代码模板,然后运行函数 eda ,该函数接收熊猫数据帧作为输入。
eda(df)
就是这样!简单:)
现在让我们来看一下输出的显著部分,以了解如何利用我们的 EDA 结果。
缺少值和重复条目
在我们的例子中,没有缺少值的条目。
但是,如果缺少值,代码将生成一个类似于下图的图表。注意 CustomerID 和描述下的空格;这些是缺失的值。因此,一眼就能看出我们价值观缺失的程度。

Missing entries chart
与检查缺失值相关的代码部分如下。
# generate preview of entries with null values
if df.isnull().any(axis=None):
print("\nPreview of data with null values:\nxxxxxxxxxxxxx")
print(df[df.isnull().any(axis=1)].head(3))
missingno.matrix(df)
plt.show()
在我们的例子中,也没有重复的条目,代码将通过输出“没有找到重复的条目”直接指出这一点。
如果出现重复条目,输出将显示重复条目的数量以及这些条目的预览。

Duplicated entries sample output
检查重复条目的代码:
# generate count statistics of duplicate entries
if len(df[df.duplicated()]) > 0:
print("No. of duplicated entries: ", len(df[df.duplicated()]))
print(df[df.duplicated(keep=False)].sort_values(by=list(df.columns)).head())
else:
print("No duplicated entries found")
如果有任何丢失的值或重复的条目,您应该在进一步处理 EDA 的其他部分之前决定所需的清理步骤。
对于重复的条目,检查它们确实是重复的,并通过下面的代码删除它们。
df.drop_duplicates(inplace=True)
分类数据 EDA
我们针对分类数据的主要 EDA 目标是了解唯一值及其对应的计数。
使用 Rossmann 商店销售额,例如列 Promo 指示商店当天是否在进行促销。根据 Promo 的独特值对其进行计数显示,促销活动非常频繁,占据了大约 40% (388,080 / 1,017,209)的店铺天数。这可能表明宣传片是预测销量的一个重要特征。

为分类数据生成 EDA 的函数是分类 eda 。
def categorical_eda(df):
"""Given dataframe, generate EDA of categorical data"""
print("To check: Unique count of non-numeric data")
print(df.select_dtypes(include=['category']).nunique())
top5(df)
# Plot count distribution of categorical data
for col in df.select_dtypes(include='category').columns:
fig = sns.catplot(x=col, kind="count", data=df)
fig.set_xticklabels(rotation=90)
plt.show()
数字数据 EDA
对于数字数据,我们的 EDA 方法如下:
- 绘制每个数字数据的单变量分布图
- 如果分类数据可用,按每个分类值绘制单变量分布图
- 绘制数值数据的两两联合分布
在运行 eda 函数之前,我们通过将销售额除以客户创建了一个新列 ave_sales ,这样我们就可以分析每个客户每天的平均销售额。
我们的数字数据 EDA 的第一个输出显示了一些简单的分布统计,包括平均值、标准差和四分位数。

我们可以从输出中获得的一些要点包括:
- 所有数值数据都没有负值。如果有任何负值,这可能意味着我们必须进一步调查,因为销售额和客户数量不太可能是负数,然后我们可能必须清理数据。
- 数值数据的最大值与 75%相差甚远,表明我们可能有异常值。

箱线图进一步证实了存在销售额超过 40,000 或客户超过 7,000 的异常值。因此,我们可能会进行检查,看看这是一个错误,还是有其他特殊情况导致的异常数字。
我们还按类别值为每个数字数据绘制了小提琴图,以调查促销对销售的影响。

从上面的小提琴图中,我们可以推断,在促销日,从小提琴图的更宽部分可以看出,销售额通常会增加。对于 Promo =0,靠近 0 销售的地块的宽部分可能是由于关闭的商店。在移除打开 =0 的条目后,稍后再次运行 eda 函数,显示 0 附近的宽段不再存在,从而证实了我们的假设。
数字数据 EDA 的最后一个输出是成对联合分布图。
为了获得更深入的信息,我们运行了函数 numeric_eda 并添加了参数 hue='DayOfWeek' 。这使得我们可以根据一周中的每一天来给我们的成对绘图着色。
numeric_eda(df, hue='DayOfWeek')

通过将 DayOfWeek 合并到图中,我们注意到周日的 ave_sales(用粉色表示)相对来说比其他几天更稳定。因此,这是一个可以进一步研究和考虑的预测因素。
时间序列 EDA
最后,我们还绘制了时间序列图来检查趋势和季节性。
为了便于分析,在绘制图表之前,我们的代码会按照每天、每月和每年的频率自动汇总数字数据。这是通过熊猫的重采样方法实现的。

在我们的例子中,年度图表没有用,因为数据只包含 2015 年的部分数据,因此我们在截图中没有显示。
从日图可以看出,2013 年 12 月底有异常值。这也体现在每月的剧情上。
月度图还显示了一些季节性,即二月份销售额较低,这可能是由于短月效应,以及接近年底时销售额较高。如果我们要预测月销售额,我们的预测必须考虑这种季节性影响。
通过上面的例子,我们希望能够展示 EDA 是如何用于为我们的建模制定假设和假说,以及检查数据质量以进行进一步处理和清理的。
如果你错过了代码模板链接,这里再次出现。
最后,请注意,根据您的数据科学问题陈述,您可能希望执行额外的 EDA 步骤。尽管如此,代码模板应该能够涵盖基本的 EDA 并让您快速上手。
如果您也在考虑为文本数据执行 EDA,请查看这篇由 neptune.ai 撰写的关于用于自然语言处理的 EDA 的文章。在这篇文章中,作者举例说明了几乎所有可以用来理解文本数据的主要技术。
感谢阅读,我希望代码和文章是有用的。如果您有任何问题或建议,请随时发表评论。
参考
- https://en . Wikipedia . org/wiki/explorative _ data _ analysis # target text = In % 20 statistics % 2C % 20 explorative % 20 data % 20 analysis,modeling % 20 or % 20 hypothesis % 20 testing % 20 task。
- https://towards data science . com/explorative-data-analysis-EDA-techniques-for-ka ggle-competition-初学者-be4237c3c3a9
- https://medium . com/@ aiden . data miner/the-data-science-method-DSM-explorative-data-analysis-BC 84d 4d 8d 3 f 9
探索性数据分析:哈伯曼癌症生存数据集

什么是探索性数据分析?
E 探索性数据分析(EDA) 是一种分析数据集以总结其主要特征的方法,通常采用可视化方法。EDA 是为了看看数据能告诉我们什么,而不仅仅是正式的建模或假设检验任务。
用多种探索技术探索一个数据集总是一个好主意,特别是当它们可以一起进行比较时。探索性数据分析的目标是获得对数据的信心,从而准备好使用机器学习算法。EDA 的另一个附带好处是细化您对稍后将用于机器学习的特征变量的选择。
为什么是埃达?
在匆忙进入机器学习阶段时,一些数据科学家要么完全跳过探索过程,要么做一个非常敷衍的工作。这是一个具有多种含义的错误,包括生成不准确的模型,生成准确的模型但基于错误的数据,在数据准备中没有创建正确类型的变量,以及由于仅在生成模型后才意识到数据可能有偏差,或有异常值,或有太多缺失值,或发现某些值不一致而导致资源使用效率低下。
在这篇博客中,我们采用了哈伯曼的癌症生存数据集,并使用 python 执行了各种 EDA 技术。你可以很容易地从 Kaggle 下载数据集。
接受乳腺癌手术患者的存活率
www.kaggle.com](https://www.kaggle.com/gilsousa/habermans-survival-data-set)
哈伯曼癌症生存数据集上的 EDA
1.了解数据集
标题:哈伯曼的生存数据
描述:该数据集包含 1958 年至 1970 年间在芝加哥大学比林斯医院进行的一项关于乳腺癌手术患者生存的研究。
属性信息:
患者手术时的年龄(数值)
患者手术年份(年份— 1900,数值)
检测到的阳性腋窝淋巴结数(数值)
存活状态(类别属性):
1 =患者存活 5 年或更长时间
2 =患者在 5 年内死亡
2.导入库并加载文件
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np*#reading the csv file*
haber = pd.read_csv(“haberman_dataset.csv”)
3.理解数据
*#Prints the first 5 entries from the csv file*
haber.head()
输出:

*#prints the number of rows and number of columns*
haber.shape
输出:(306,4)
观察:
- CSV 文件包含 306 行和 4 列。
*#printing the columns*
haber.columns
输出:索引(['年龄','年份','节点','状态'],dtype= '对象')
print(haber.info())
*#brief info about the dataset*
输出:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 306 entries, 0 to 305
Data columns (total 4 columns):
age 306 non-null int64
year 306 non-null int64
nodes 306 non-null int64
status 306 non-null int64
dtypes: int64(4)
memory usage: 9.6 KB
观察结果:
- 该数据集中没有缺失值。
- 所有列都是整数数据类型。
- 状态的数据类型是整数,必须将其转换为分类数据类型
- 在状态列中,值 1 可以映射为“是”,这意味着患者已经存活了 5 年或更长时间。值 2 可以映射为“否”,这意味着患者在 5 年内死亡。
haber[‘status’] = haber[‘status’].map({1:’Yes’, 2:’No’})
haber.head()
*#mapping the values of 1 and 2 to yes and no respectively and #printing the first 5 records from the dataset.*
输出:

haber.describe()
*#describes the dataset*
输出:

观察结果:
- Count:各列中存在的值的总数。
- Mean:各列中所有值的平均值。
- Std:各列中值的标准偏差。
- Min:列中的最小值。
- 25%:给出第 25 个百分点值。
- 50%:给出第 50 个百分位数的值。
- 75%:给出第 75 个百分位数的值。
- Max:列中的最大值。
haber[“status”].value_counts()
*#gives each count of the status type*
输出:
是 225
否 81
名称:状态,数据类型:int64
观察结果:
- value_counts()函数告诉我们每个类有多少个数据点。在这里,它告诉多少病人存活,多少没有存活。
- 在 306 名患者中,225 名患者存活,81 名患者死亡。
- 数据集不平衡。
status_yes = haber[haber[‘status’]==’Yes’]
status_yes.describe()
*#status_yes dataframe stores all the records where status is yes*
输出:

status_no = haber[haber[‘status’]==’No’]
status_no.describe()
*#status_no dataframe stores all the records where status is no*

观察结果:
- 两类患者的平均年龄和接受手术的年份几乎相似,而两类患者的淋巴结平均值相差约 5 个单位。
- 与未存活的患者相比,存活患者的淋巴结更少。
4.单变量分析
单变量分析的主要目的是描述、总结和发现单一特征中的模式。
4.1 概率密度函数(PDF)
概率密度函数(PDF)是变量取值 x 的概率。(直方图的平滑版本)
这里,柱的高度表示相应组下的数据点的百分比
sns.FacetGrid(haber,hue=’status’,height = 5)\
.map(sns.distplot,”age”)\
. add_legend();
plt.show()
输出:

PDF of Age
观察结果:
- 观察到大量重叠,这告诉我们生存机会与人的年龄无关。
- 虽然有重叠,但我们可以隐约看出,年龄在 30-40 岁之间的人更有可能存活,而 40-60 岁的人不太可能存活。而年龄在 60-75 岁之间的人存活和死亡的机会均等。
- 然而,这不是我们的最终结论。我们不能仅仅通过考虑年龄参数来决定病人的生存机会
sns.FacetGrid(haber,hue=’status’,height = 5)\
.map(sns.distplot,”year”)\
. add_legend();
plt.show()
输出:

PDF of Year
观察结果:
- 观察到大量重叠。这张图只显示了多少次手术成功,多少次手术失败。这不能成为决定病人生存机会的参数。
- 然而,可以看出,在 1960 年和 1965 年有更多的不成功的行动。
sns.FacetGrid(haber,hue=’status’,height = 5)\
.map(sns.distplot,”nodes”)\
. add_legend();
plt.show()
输出:

PDF of Nodes
观察结果:
- 无淋巴结或有 1 个淋巴结的患者更有可能存活。如果有 25 个或更多的节点,存活的机会很小。
4.2 累积分布函数
累积分布函数(CDF)是变量取值小于或等于 x 的概率。
counts1, bin_edges1 **=** np.histogram(status_yes['nodes'], bins**=**10, density **=** **True**)
pdf1 **=** counts1**/**(sum(counts1))
print(pdf1);
print(bin_edges1)
cdf1 **=** np.cumsum(pdf1)
plt.plot(bin_edges1[1:], pdf1)
plt.plot(bin_edges1[1:], cdf1, label **=** 'Yes')
plt.xlabel('nodes')print("***********************************************************")
counts2, bin_edges2 **=** np.histogram(status_no['nodes'], bins**=**10, density **=** **True**)
pdf2 **=** counts2**/**(sum(counts2))
print(pdf2);
print(bin_edges2)
cdf2 **=** np.cumsum(pdf2)
plt.plot(bin_edges2[1:], pdf2)
plt.plot(bin_edges2[1:], cdf2, label **=** 'No')
plt.xlabel('nodes')plt.legend()
plt.show()
输出:
[0.835555560.08 0.02222222 0.02666670.0177778 0.00444444
0.00888889 0。0.0.00444444]
【0。4.6 9.2 13.8 18.4 23.27.6 32.2 36.8 41.4 46.]* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
【0.56790123 0.14814815 0.13580247 0.04938272 0.07407407 0 .0.01234568 0。0.0.01234568]
【0。5.2 10.4 15.6 20.8 26.31.2 36.4 41.6 46.8 52.]

CDF of Nodes
观察结果:
- 83.55%的存活患者的淋巴结在 0-4.6 之间
4.3 箱形图和小提琴图
该方框从数据的下四分位数延伸到上四分位数,中间有一条线。触须从框中延伸出来,以显示数据的范围。离群点是那些超过胡须末端的点。
小提琴图是箱线图和概率密度函数(CDF)的组合。
sns.boxplot(x**=**'status',y**=**'age',data**=**haber)
plt.show()sns.boxplot(x='status',y='year',data=haber)
plt.show()sns.boxplot(x='status',y='nodes',data=haber)
plt.show()



Box plots
sns.violinplot(x=”status”,y=”age”,data = haber,height = 10)
plt.show()sns.violinplot(x=”status”,y=”year”,data = haber,height = 10)
plt.show()sns.violinplot(x=”status”,y=”nodes”,data = haber,height = 10)
plt.show()
输出:



Violin Plots
观察结果:
- 超过 1 个淋巴结的患者不太可能存活。节点数量越多,生存机会越小。
- 大部分存活的患者没有淋巴结。然而,有一小部分没有阳性腋窝淋巴结的患者在手术后 5 年内死亡,因此没有阳性腋窝淋巴结并不总是能保证存活。
- 在 1965 年接受手术的人中,存活时间不超过 5 年的相对较多。
- 相对而言,45 至 65 岁年龄组中有更多的人没有活下来。患者年龄本身并不是决定患者存活率的重要参数。
- 年龄和年份参数的箱线图和小提琴图给出了相似的结果,数据点有很大的重叠。与其他特征相比,节点的箱线图和小提琴图中的重叠较少,但是重叠仍然存在,因此很难设置阈值来对两类患者进行分类。
5.双变量分析
5.1 散点图
散点图是一种二维数据可视化,使用点来表示两个不同变量的值,一个沿 x 轴绘制,另一个沿 y 轴绘制。
sns.set_style(“whitegrid”)
sns.FacetGrid(haber, hue = “status” , height = 6)\
.map(plt.scatter,”age”,”year”)\
.add_legend()
plt.show()
输出:

Scatter Plot: age vs nodes
观察:
- 无论年龄大小,淋巴结为 0 的患者更有可能存活。
- 几乎没有病人的淋巴结超过 25 个。
- 年龄超过 50 岁且淋巴结超过 10 个的患者存活的可能性更小。
5.2 配对图
默认情况下,该函数将创建一个轴网格,这样数据中的每个变量将在 y 轴的一行中共享,在 x 轴的一列中共享。对角轴被区别对待,绘制一个图来显示该列中变量的数据的单变量分布。
sns.set_style(“whitegrid”)
sns.pairplot(haber, hue=”status”, height = 5)
plt.show()
输出:

Pair Plot
观察结果:
- 年份和节点之间的关系相对较好。
6.多变量分析
6.1 等高线图
二元函数的等高线或等值线是一条曲线,函数沿着这条曲线有一个常数值。它是三维图形的横截面。
sns.jointplot(x = ‘year’, y = ‘age’, data = haber, kind = “kde”)
plt.show()
输出:

Contour Plot year vs age
观察:
- 从 1960 年到 1964 年,45 岁到 55 岁年龄组的病人做了更多的手术。
结论:
- 患者的年龄和手术年份本身并不是决定其生存的因素。然而,35 岁以下的人有更多的生存机会。
- 生存机会与阳性腋窝淋巴结数成反比。我们也看到没有阳性腋窝淋巴结并不总是能保证存活。
- 基于给定的特征对新患者的生存状态进行分类的目标是一项困难的任务,因为数据是不平衡的。
Python 中的探索性数据分析。
让我们了解如何在 python 中探索数据。

Image Credits: Morioh
介绍
什么是探索性数据分析?
探索性数据分析(EDA)是通过总结数据集的主要特征来理解数据集,通常是直观地绘制出来。这一步非常重要,尤其是当我们为了应用机器学习而对数据进行建模的时候。EDA 中的绘图包括直方图、箱线图、散点图等等。研究这些数据通常要花很多时间。通过 EDA 的过程,我们可以要求在我们的数据集上定义问题陈述或定义,这非常重要。
如何进行探索性数据分析?
这是一个每个人都渴望知道答案的问题。答案是,这取决于您正在处理的数据集。执行 EDA 并没有单一的方法或共同的方法,而在本教程中,您可以了解一些将在 EDA 过程中使用的共同方法和图。
我们今天在探索什么数据?
由于我是一个超级车迷,我从 Kaggle 获得了一组非常漂亮的汽车数据。数据集可以从这里下载。给出一个关于数据集的简短信息,该数据包含 10,000 多行和 10 多列,包含汽车的特征,例如发动机燃料类型、发动机尺寸、马力、变速器类型、公路 MPG、城市 MPG 等等。因此,在本教程中,我们将探索数据,并为建模做好准备。
我们开始吧!!!
1。导入 EDA 所需的库
以下是本教程中用于执行 EDA(探索性数据分析)的库。完整代码可以在我的 GitHub 上找到。
**# Importing required libraries.** import pandas as pd
import numpy as np
import seaborn as sns #visualisation
import matplotlib.pyplot as plt #visualisation
%matplotlib inline
sns.set(color_codes=True)
2。将数据加载到数据框中。
将数据加载到 pandas 数据框中肯定是 EDA 中最重要的步骤之一,因为我们可以看到数据集的值是用逗号分隔的。因此,我们所要做的就是将 CSV 读入数据帧,pandas 数据帧会为我们完成这项工作。
为了获取数据集或将数据集加载到笔记本中,我所做的只是一个微不足道的步骤。在笔记本左侧的 Google Colab 中,你会发现一个“”>”(大于符号)。当你点击它时,你会发现一个有三个选项的标签,你只需要选择文件。然后你可以在上传选项的帮助下轻松上传你的文件。无需安装到 google drive 或使用任何特定的库,只需上传数据集,您的工作就完成了。在这一步要记住的一点是,当运行时被回收时,上传的文件将被删除。这就是我如何把数据集放进笔记本的。
df = pd.read_csv(“data.csv”)
**# To display the top 5 rows** df.head(5)

Displaying the top 5 rows.
**# To display the bottom 5 rows** df.tail(5)

Displaying the last 10 rows.
3。检查数据类型
这里我们检查数据类型,因为有时汽车的 MSRP 或价格会存储为字符串或对象,如果在这种情况下,我们必须将字符串转换为整数数据,然后我们才能通过图形绘制数据。在这里,在这种情况下,数据已经是整数格式,所以没什么好担心的。
**# Checking the data type** df.dtypes

Checking the type of data.
4。删除不相关的列
这一步在每个 EDA 中都是必不可少的,因为有时会有许多列我们从未使用过,在这种情况下删除是唯一的解决方案。在这种情况下,诸如发动机燃料类型、市场类别、车型、受欢迎程度、车门数量、车辆尺寸等列对我来说没有任何意义,所以我只是放弃了这个实例。
**# Dropping irrelevant columns** df = df.drop([‘Engine Fuel Type’, ‘Market Category’, ‘Vehicle Style’, ‘Popularity’, ‘Number of Doors’, ‘Vehicle Size’], axis=1)
df.head(5)

Dropping irrelevant columns.
5。重命名列
在这种情况下,大多数列名读起来非常混乱,所以我只是调整了它们的列名。这是一个很好的方法,它提高了数据集的可读性。
**# Renaming the column names** df = df.rename(columns={“Engine HP”: “HP”, “Engine Cylinders”: “Cylinders”, “Transmission Type”: “Transmission”, “Driven_Wheels”: “Drive Mode”,”highway MPG”: “MPG-H”, “city mpg”: “MPG-C”, “MSRP”: “Price” })
df.head(5)

Renaming the column name.
6。删除重复行
这通常是一件很方便的事情,因为一个巨大的数据集(在本例中包含超过 10,000 行)通常会有一些重复的数据,这可能会令人不安,所以这里我从数据集中删除了所有重复的值。例如,在删除之前,我有 11914 行数据,但在删除重复数据后,有 10925 行数据,这意味着我有 989 行重复数据。
**# Total number of rows and columns** df.shape**(11914, 10)****# Rows containing duplicate data** duplicate_rows_df = df[df.duplicated()]
print(“number of duplicate rows: “, duplicate_rows_df.shape)**number of duplicate rows: (989, 10)**
现在让我们删除重复的数据,因为可以删除它们。
**# Used to count the number of rows before removing the data** df.count() **Make 11914
Model 11914
Year 11914
HP 11845
Cylinders 11884
Transmission 11914
Drive Mode 11914
MPG-H 11914
MPG-C 11914
Price 11914
dtype: int64**
如上所示,共有 11914 行,我们删除了 989 行重复数据。
**# Dropping the duplicates** df = df.drop_duplicates()
df.head(5)

**# Counting the number of rows after removing duplicates.** df.count()Make 10925
Model 10925
Year 10925
HP 10856
Cylinders 10895
Transmission 10925
Drive Mode 10925
MPG-H 10925
MPG-C 10925
Price 10925
dtype: int64
7。删除缺失值或空值。
这与上一步非常相似,但在这里,所有丢失的值都被检测到,并在稍后被删除。现在,这不是一个好的方法,因为许多人只是用该列的平均值来替换缺失的值,但在这种情况下,我只是删除了缺失的值。这是因为与 10,000 个值相比,有将近 100 个值丢失了,这是一个很小的数字,可以忽略不计,所以我只是丢弃了这些值。
**# Finding the null values.** print(df.isnull().sum())**Make 0
Model 0
Year 0
HP 69
Cylinders 30
Transmission 0
Drive Mode 0
MPG-H 0
MPG-C 0
Price 0
dtype: int64**
这就是在上述步骤中,在 10925 行中计算气缸和马力(HP)的原因,分别为 10856 和 10895。
**# Dropping the missing values.** df = df.dropna()
df.count()**Make 10827
Model 10827
Year 10827
HP 10827
Cylinders 10827
Transmission 10827
Drive Mode 10827
MPG-H 10827
MPG-C 10827
Price 10827
dtype: int64**
现在,我们已经删除了所有包含空值或不适用值(气缸和马力(HP))的行。
**# After dropping the values** print(df.isnull().sum()) **Make 0
Model 0
Year 0
HP 0
Cylinders 0
Transmission 0
Drive Mode 0
MPG-H 0
MPG-C 0
Price 0
dtype: int64**
8。检测异常值
离群点是不同于其他点的一个点或一组点。有时它们会很高或很低。检测并移除异常值通常是个好主意。因为离群值是导致模型不太精确的主要原因之一。因此,移除它们是个好主意。我将要执行的异常值检测和去除被称为 IQR 评分技术。通常,使用箱线图可以看到异常值。下面显示的是建议零售价,气缸,马力和发动机大小的方框图。在所有的图中,你可以发现一些点在方框之外,它们不是别的,就是异常值。我在这项任务中执行的寻找和去除异常值的技术得到了来自的数据科学教程的帮助。
sns.boxplot(x=df[‘Price’])

Box plot of Price
sns.boxplot(x=df[‘HP’])

Box Plot of HP
sns.boxplot(x=df['Cylinders'])

Box Plot of Cylinders
Q1 = df.quantile(0.25)
Q3 = df.quantile(0.75)
IQR = Q3 — Q1
print(IQR)**Year 9.0
HP 130.0
Cylinders 2.0
MPG-H 8.0
MPG-C 6.0
Price 21327.5
dtype: float64**
不要担心上面的值,因为知道它们中的每一个并不重要,重要的是知道如何使用这种技术来去除异常值。
df = df[~((df < (Q1–1.5 * IQR)) |(df > (Q3 + 1.5 * IQR))).any(axis=1)]
df.shape**(9191, 10)**
如上所示,大约有 1600 行是异常值。但是你不能完全去除异常值,因为即使你使用了上面的技术,也可能有 1-2 个异常值没有去除,但是这没关系,因为有超过 100 个异常值。有总比没有好。
9。绘制不同特征之间的对比图(散点图),对比频率图(直方图)
直方图
直方图是指变量在一个区间内出现的频率。在这种情况下,主要有 10 个不同类型的汽车制造公司,但了解谁拥有最多的汽车往往是很重要的。做这个直方图是一个简单的解决方案,它让我们知道不同公司生产的汽车总数。
**# Plotting a Histogram** df.Make.value_counts().nlargest(40).plot(kind=’bar’, figsize=(10,5))
plt.title(“Number of cars by make”)
plt.ylabel(‘Number of cars’)
plt.xlabel(‘Make’);

Histogram
热图
热图是一种绘图,当我们需要找到因变量时,它是必要的。找到特征之间关系的最好方法之一是使用热图。在下面的热图中,我们知道价格特征主要取决于发动机尺寸、马力和气缸。
**# Finding the relations between the variables.** plt.figure(figsize=(20,10))
c= df.corr()
sns.heatmap(c,cmap=”BrBG”,annot=True)
c

Heat Maps.
散点图
我们通常使用散点图来寻找两个变量之间的相关性。这里散点图是马力和价格之间的关系,我们可以看到下图。根据下面给出的图表,我们可以很容易地画出一条趋势线。这些特征提供了良好的点分散。
**# Plotting a scatter plot** fig, ax = plt.subplots(figsize=(10,6))
ax.scatter(df[‘HP’], df[‘Price’])
ax.set_xlabel(‘HP’)
ax.set_ylabel(‘Price’)
plt.show()

Scatter Plot
因此,以上是探索性数据分析中涉及的一些步骤,这些是为了执行 EDA 您必须遵循的一些一般步骤。还有更多的,但现在,这是足够多的想法,如何执行一个好的 EDA 给定的任何数据集。敬请关注更多更新。如果你有疑问,那么评论区就是你的了。我会尽我所能回答你的问题。
谢谢你。
面向初学者的 R 中的探索性数据分析(第 1 部分)
从数据导入到清理和可视化的逐步方法

Photo by Lukas Blazek on Unsplash
探索性数据分析 ( EDA )是对数据进行分析和可视化的过程,以更好地理解数据并从中获得洞察力。进行 EDA 时会涉及各种步骤,但以下是数据分析师在进行 EDA 时可以采取的常见步骤:
- 导入数据
- 清理数据
- 处理数据
- 将数据可视化
你希望在这篇文章中找到什么?
本文重点关注数据集的 EDA,这意味着它将涉及上述所有步骤。因此,本文将带您了解所需的所有步骤以及每个步骤中使用的工具。因此,您可能会在本文中找到以下内容:
- 整理数据集的 Tidyverse 包
- 用于可视化的 ggplot2 包
- 相关图相关图包
- 其他一些操作数据的基本函数,如 strsplit()、cbind()、matrix()等等。
对于 EDA 初学者,如果你没有很多时间和不知道从哪里开始,我会推荐你从 Tidyverse 和 ggplot2 开始。你可以用这两个包做几乎所有关于 EDA 的事情。网上有各种资源,像 DataCamp 、 Setscholars ,还有像Data Science Introduction之类的书籍。
在本文中,我将通过对 PISA 分数数据集的分析,带您了解 EDA 的过程。
让我们开始吧,伙计们!!
导入数据
在将数据导入 R 进行分析之前,让我们看看数据是什么样子的:

当将这些数据导入 R 时,我们希望最后一列是“数字”,其余的是“因子”。考虑到这一点,我们来看看以下 3 种情况:
df.raw <- read.csv(file ='Pisa scores 2013 - 2015 Data.csv', fileEncoding="UTF-8-BOM", na.strings = '..')df.raw1 <- read.csv(file ='Pisa scores 2013 - 2015 Data.csv')df.raw2 <- read.csv(file ='Pisa scores 2013 - 2015 Data.csv',na.strings = '..')
这是将数据导入 r 的 3 种方式。通常,一种是用 go 导入 df.raw1,因为这似乎是导入数据最方便的方式。让我们看看导入数据的结构:
df.raw1 <- read.csv(file ='Pisa scores 2013 - 2015 Data.csv')str(df.raw1)

我们可以立即发现两个问题。最后一列是“因子”,而不是我们想要的“数字”。其次,第一列“国家名称”的编码不同于原始数据集。
现在让我们尝试第二种情况
df.raw2 <- read.csv(file ='Pisa scores 2013 - 2015 Data.csv',na.strings = '..')str(df.raw2)

最后一列现在是“数字”。但是,第一列的名称没有正确导入。
最后一个场景呢?
df.raw <- read.csv(file ='Pisa scores 2013 - 2015 Data.csv', fileEncoding="UTF-8-BOM", na.strings = '..')
str(df.raw)

如您所见,第一列现在已正确命名,最后一列是“数字”。
**na.strings = '..'**
这允许 R 用 NA 替换数据集中的那些空白。这将是有用的和方便的,当我们想删除所有的 NA 的时候。
**fileEncoding="UTF-8-BOM"**
用外行人的话来说,这允许 R 正确地读取字符,就像它们出现在原始数据集中一样。
清理和处理数据
install.packages("tidyverse")
library(tidyverse)
我们想做一些事情来清理数据集:
- 确保数据集中的每一行只对应一个国家:使用 tidyverse 包中的 spread()函数
- 确保只保留有用的列和行:使用 drop_na()和数据子集
- 重命名系列代码列以获得有意义的解释:使用 Rename()
df <- df.raw[1:1161, c(1, 4, 7)] #select relevant rows and cols
%>% spread(key=Series.Code, value=X2015..YR2015.)
%>% rename(Maths = LO.PISA.MAT,
Maths.F = LO.PISA.MAT.FE,
Maths.M = LO.PISA.MAT.MA,
Reading = LO.PISA.REA,
Reading.F = LO.PISA.REA.FE,
Reading.M = LO.PISA.REA.MA,
Science = LO.PISA.SCI,
Science.F = LO.PISA.SCI.FE,
Science.M = LO.PISA.SCI.MA
) %>%
drop_na()
现在让我们看看干净的数据是什么样的:
view(df)

可视化数据
- 柱状图
install.packages("ggplot2")
library(ggplot2)#Ranking of Maths Score by Countriesggplot(data=df,aes(x=reorder(Country.Name,Maths),y=Maths)) +
geom_bar(stat ='identity',aes(fill=Maths))+
coord_flip() +
theme_grey() +
scale_fill_gradient(name="Maths Score Level")+
labs(title = 'Ranking of Countries by Maths Score',
y='Score',x='Countries')+
geom_hline(yintercept = mean(df$Maths),size = 1, color = 'blue')

同样,我们也可以通过科学分数和阅读分数来排名,只是相应地改变名称。
2。箱线图
如果我们使用上面的数据集,我们将无法绘制箱线图。这是因为箱线图只需要 2 个变量 x 和 y,但在我们清理过的数据中,有如此多的变量。所以我们需要把它们合并成两个变量。我们将其命名为 df2
df2 = df[,c(1,3,4,6,7,9,10)] %>% # select relevant columns
pivot_longer(c(2,3,4,5,6,7),names_to = 'Score')view(df2)

太好了!现在我们可以做箱线图了
ggplot(data = df2, aes(x=Score,y=value, **color=Score**)) +
geom_boxplot()+
scale_**color**_brewer(palette="Dark2") +
geom_jitter(shape=16, position=position_jitter(0.2))+
labs(title = 'Did males perform better than females?',
y='Scores',x='Test Type')

geom_jitter()允许您在图上绘制数据点。
你可以用上面的代码来得到不同的情节。例如,我可以将“颜色=分数”改为“填充=分数”:
ggplot(data = df2, aes(x=Score,y=value, **fill=Score**)) +
geom_boxplot()+
scale_**fill**_brewer(palette="Green") +
geom_jitter(shape=16, position=position_jitter(0.2))+
labs(title = 'Did males perform better than females?',
y='Scores',x='Test Type')

剧情看起来有点乱。一个更好的视觉化方法是将主题和性别分开,并把它们并排放在一起。
我们如何才能做到这一点?
因为我们想从包含“主题”的列中分离主题和性别。性别’(如数学。f),我们需要使用 strsplit()来为我们做这项工作
S = numeric(408) # create an empty vector
for (i in 1:length(df2$Score)) {
S[i] = strsplit(df2$Score[i],".",fixed = TRUE)
}
现在 S 是 408 个组件的列表,每个组件有 2 个子组件“主题”和“性别”。我们需要将 S 转换成 1 列主题和 1 列性别的数据帧。我们将这个数据帧命名为 df3
df3 = S%>%unlist() %>% matrix(ncol = 2, byrow = TRUE)%>% as.data.frame()view(df3)

我们现在需要将这个 df3 与我们之前创建的 df2 合并,并将结果命名为 df4
df4 = cbind(df2,df3)
colnames(df4) = c('Country','Score','Value','Test','Gender')
df4$Score = NULL # since the 'Score' column is redundant
view(df4)

厉害!现在数据看起来干净整洁。让我们使用 ggplot2 中的 facet_wrap() 函数创建多个图
ggplot(data = df4, aes(x=Test,y=Value, fill=Test)) +
geom_boxplot()+
scale_fill_brewer(palette="Green") +
geom_jitter(shape=16, position=position_jitter(0.2))+
labs(title = 'Did males perform better than females?',
y='Scores',x='Test')+
**facet_wrap(~Gender,nrow = 1)**

这里,我们按照性别对情节进行分类,因此 facet_wrap(~Gender,nrow = 1)
我们也可以通过改变 facet_wrap(~Test,nrow = 1) 来对图进行分类
ggplot(data = df4, aes(x=Gender,y=Value, fill=Gender)) +
geom_boxplot()+
scale_fill_brewer(palette="Green") +
geom_jitter(shape=16, position=position_jitter(0.2))+
labs(title = 'Did males perform better than females?',
y='Scores',x='')+
**facet_wrap(~Test,nrow = 1)**

通过观察这些情节,我们可以对男性和女性的表现有所了解。一般来说,男性在科学和数学方面表现更好,但女性在阅读方面表现更好。然而,如果我们只看了箱线图就下结论,那就太天真了。让我们更深入地研究数据,看看在处理数据集后我们还能获得什么其他见解。
因为我想比较所有参与国家中男性和女性在每一科目中的表现,所以我需要计算男性和女性在每一科目中得分的百分比差异,然后绘制出来以进行可视化。
在 R 中我该如何做呢?使用 mutate()函数
让我们看看我们拥有的原始干净数据集, df
现在,我们将使用 mutate()函数来计算每个国家的男性和女性之间的百分比差异。
df = df %>% mutate(Maths.Diff = ((Maths.M - Maths.F)/Maths.F)*100,
Reading.Diff = ((Reading.M - Reading.F)/Reading.F)*100,
Science.Diff = ((Science.M - Science.F)/Science.F)*100,
Total.Score = Maths + Reading + Science,
Avg.Diff = (Maths.Diff+Reading.Diff+Science.Diff)/3
)view(df)

现在让我们把它画出来,以便更好地可视化数据
##### MATHS SCORE #####
ggplot(data=df, aes(x=reorder(Country.Name, Maths.Diff), y=Maths.Diff)) +
geom_bar(stat = "identity", aes(fill=Maths.Diff)) +
coord_flip() +
theme_light() +
geom_hline(yintercept = mean(df$Maths.Diff), size=1, color="black") +
scale_fill_gradient(name="% Difference Level") +
labs(title="Are Males better at math?", x="", y="% difference from female")

该图表示使用雌性作为参照的分数差异百分比。正差异 表示男性得分较高,负差异表示男性得分较低。黑线代表所有国家的平均差异。
从这里可以得出一些有趣的见解:
- 总体而言,男性在数学方面比女性表现更好,尤其是在大多数发展中国家,男性的分数普遍高于女性
- 有趣的是,在新加坡和香港,女性和男性的表现一样好,在这两个国家的得分差异都在 0 左右。这也许对政策制定者来说是一个很好的见解,因为我们不希望男女在教育方面有巨大的差距。
我们可以对阅读和科学分数做同样的事情。
3。相关图
df = df[,c(1,3,4,6,7,9,10)] #select relevant columns
要创建相关图,只需使用 cor():
res = cor(df[,-1]) # -1 here means we look at all columns except the first columnres

我们可以计算 p 值,看看相关性是否显著
install.packages("Hmisc")
library("Hmisc")res2 <- rcorr(as.matrix(df[,-1))

p 值越小,相关性越显著。
本节关于相关图的目的是向您介绍如何计算 r 中变量之间的相关性。对于这个数据集,很明显所有变量都是相关的
想象
install.packages("corrplot")
library(corrplot)
corrplot(res, type = "upper", order = "hclust",
tl.col = "black", tl.srt = 45)

颜色越浓,尺寸越大,相关性越高。结果和我们之前得到的相似:所有的变量都是相互关联的。
就是这样!希望你们喜欢这篇文章,并从中有所收获。虽然本指南并不详尽,但它或多或少会给你一些如何用 r 做一些基本 EDA 的想法。
如果你有任何问题,请在下面的评论区写下来。谢谢你的阅读。祝您愉快,编程愉快!!!
点击查看本系列的第 2 部分
面向初学者的 R 中的探索性数据分析(第 2 部分)
使用“ggplot2”和“tidyverse”进行 EDA 的更高级方法

ggplot2
在我的上一篇文章, 初学者 R 中的探索性数据分析(第 1 部分)’中,我已经介绍了从数据导入到清理和可视化的基本分步方法。下面是第 1 部分的简要总结:
- 用 fileEncoding 和 na.strings 参数适当导入数据。我展示了它与使用 read.csv()导入 csv 文件的普通方式有何不同。
- 用“tidyverse”包清理数据的一些基本操作
- “ggplot2”包中的箱线图、柱状图、相关图的可视化
这些是执行简单 EDA 的基本步骤。然而,为了让我们的图、图表和图形更丰富,当然也更具视觉吸引力,我们需要更进一步。我这么说是什么意思?让我们去发现它!
你希望在这篇文章中找到什么?
做 EDA 不仅仅是绘制图表。它是关于制作信息图的。在本文中,您可能会发现以下技巧:
- 如何摆弄数据集以获得每种分析的最佳版本?没有放之四海而皆准的数据集。每个分析和可视化有不同的目的,因此有不同的数据结构。
- 更改图中图例的顺序
- 让 R 识别异常值,并在图上标记它们
- 使用' gridExtra '包组合图形
到本文结束时,您将能够生成以下图形:


让我们开始吧,伙计们!!!!
来唤起你的记忆
让我们快速查看一下我们在本系列的第 1 部分中创建的数据集类型。
view(df)

View(df2)

View(df4) ## df3 combines with df2 to get df4

请参考我的上一篇文章中关于如何操作原始数据集以获得这些不同版本的详细解释。
太好了!让我们现在开始新的视觉情节
箱线图
简单箱线图
首先,我们想实现这种箱线图

为了得到这个,我们必须有一个数据框,其中行是国家和 4 列,即国家名称、数学、阅读和科学的百分比差异。现在回头参考我们之前创建的所有数据帧,我们可以看到 df 具有所有这些需求。因此,我们将从 df 中选择相关列,并将其命名为 df5
df5 = df[,c(1,11,12,13)]
boxplot(df5$Maths.Diff, df5$Reading.Diff, df5$Science.Diff,
main = 'Are Males better than Females?',
names = c('Maths','Reading','Science'),
col = 'green'
)
搞定了。按照这段代码,你应该能够得到如上图。
高层箱线图
现在我们想进入下一个阶段。这是我们想要得到的情节

请注意以下差异:
- 副标题
- 坐标轴的名称
- 离群值的布局和颜色。
- 标题
谢天谢地,' ggplot2 '包拥有我们需要的一切。问题只是我们能否在' ggplot2 '包中找到这些参数和函数。但是在我们继续讨论使用什么参数和函数之前,我们需要确定数据集应该是什么样的数据框架/结构。通过查看该图,我们可以看到数据框必须有 1 列 3 个类别(数学、阅读和科学),1 列数字结果表示每个科目的成绩差异百分比,当然还有 1 列国家名称。因此总共有 3 列。
现在我们有了看起来像这样的 df5

我们如何将它转换成上述的数据帧?还记得我在本系列第 1 部分介绍的一个招数吗,神奇的功能是 pivot_longer()。现在,我们开始吧:
df6 = df5 %>% pivot_longer(c(2,3,4))
names(df6) = c('Country','Test Diff','Result')
View(df6)

new = rep(c('Maths', 'Reading', 'Science'),68) #to create a new column indicating 'Maths', 'Reading' and 'Science'df6 = cbind(df6, new)
names(df6) = c('Country','Test Diff','Result', 'Test') #change column names
View(df6)

“Test Diff”列现在是多余的,所以您可以选择删除它,只需使用下面的代码。(这一步不是强制性的)
df6$'Test Diff' = NULL
在这里,我就不删了。
太好了!现在,我们已经为可视化准备好了正确结构的数据集,现在让我们使用 ggplot
- 要获取标题、副标题、题注,请使用 labs(title = ' …',y = ' …',x = ' …',caption = ' …',subtitle = ' …')
- 如果标题或题注很长,使用 ' …。\n …' 将其分成两行。
- 为了指示异常值,在 geom_boxplot()内
geom_boxplot(alpha = 0.7,
outlier.colour='blue', #color of outlier
outlier.shape=19, #shape of outlier
outlier.size=3, #size of outlier
width = 0.6, color = "#1F3552", fill = "#4271AE"
)
将一切结合在一起:
ggplot(data = df6, aes(x=Test,y=Result, fill=Test)) +
geom_boxplot(alpha = 0.7,
outlier.colour='blue',
outlier.shape=19,
outlier.size=3,
width = 0.6, color = "#1F3552", fill = "#4271AE"
)+
theme_grey() +
labs(title = 'Did males perform better than females?',
y='% Difference from FEMALES',x='',
caption = 'Positive % Difference means Males performed \n better than Females and vice versa',
subtitle = 'Based on PISA Score 2015')

这样够好了吗?答案是否:题注、片头和字幕太小,情节的比例和大小都不如我们在这一节开头介绍的情节。
我们可以做得更好。
要调整尺寸等,使用主题()功能
theme(axis.text=element_text(size=20),
plot.title = element_text(size = 20, face = "bold"),
plot.subtitle = element_text(size = 10),
plot.caption = element_text(color = "Red", face = "italic", size = 13)
)
在这里,不要问我如何得到这些数字。这是试错法。你可以尝试任何数字,直到你得到完美的尺寸和位置。
现在让我们把所有的东西结合在一起
ggplot(data = df6, aes(x=Test,y=Result, fill=Test)) +
geom_boxplot(alpha = 0.7,
outlier.colour='blue',
outlier.shape=19,
outlier.size=3,
width = 0.6, color = "#1F3552", fill = "#4271AE"
)+
theme_grey() +
labs(title = 'Did males perform better than females?',
y='% Difference from FEMALES',x='',
caption = 'Positive % Difference means Males performed \n better than Females and vice versa',
subtitle = 'Based on PISA Score 2015') +
theme(axis.text=element_text(size=20),
plot.title = element_text(size = 20, face = "bold"),
plot.subtitle = element_text(size = 10),
plot.caption = element_text(color = "Red", face = "italic", size = 13)
)

现在剧情看起来好多了。你可以停在这里。但是,我想介绍一种方法,重新排列变量的顺序,得到一个递减的趋势。简单使用
scale_x_discrete(limits=c("Maths","Science","Reading"))
因此,结合一切
ggplot(data = df6, aes(x=Test,y=Result, fill=Test)) +
geom_boxplot(alpha = 0.7,
outlier.colour='blue',
outlier.shape=19,
outlier.size=3,
width = 0.6, color = "#1F3552", fill = "#4271AE"
)+
**scale_x_discrete(limits=c("Maths","Science","Reading"))+** theme_grey() +
labs(title = 'Did males perform better than females?',
y='% Difference from FEMALES',x='',
caption = 'Positive % Difference means Males performed \n better than Females and vice versa',
subtitle = 'Based on PISA Score 2015') +
theme(axis.text=element_text(size=20),
plot.title = element_text(size = 20, face = "bold"),
plot.subtitle = element_text(size = 10),
plot.caption = element_text(color = "Red", face = "italic", size = 13)
)

厉害!!现在剧情看起来真的很有知识性。然而,更好的数据分析师会产生更丰富的信息,如下所示:

怎样才能让 R 识别出离群值,并为我们贴上标签?
df6$Test = factor(df6$Test, levels = c("Maths","Science","Reading")) # To change order of legend
让我们来定义离群值。这部分需要一点统计学知识。我会推荐你在这里阅读迈克尔·加拉尼克的文章。他很好地解释了这些概念。
is_outlier <- function(x) {
return(x < quantile(x, 0.25) - 1.5 * IQR(x) | x > quantile(x, 0.75) + 1.5 * IQR(x))
} # define a function to detect outliersstr(df6)

请注意,列“国家”和“测试”是因子。首先让我们把它改成字符。
df6$Country = as.character(df6$Country)
df7 <- df6 %>% group_by(as.character(Test)) %>%
mutate(is_outlier=ifelse(is_outlier(Result), Country, as.numeric(NA)))### What we are doing now is that we are creating a new data frame with the last column 'is_outlier' indicating whether the data point is an outlier or notView(df7)

如您所见,数据框的最后一列显示 Jordan 是一个异常值。现在,在“Country”列,我们希望确保只标记异常值,其余的应该标记为“NA”。这将有助于我们以后编写可视化绘图代码。
df7$Country[which(is.na(df7$is_outlier))] <- as.numeric(NA)
View(df7)

现在,让我们绘制图表。与上面相同的代码。然而,我们需要添加 geom_text () 来标记异常值
ggplot(data = df7, aes(x=Test,y=Result, fill=Test)) +
geom_boxplot(alpha = 0.7,
outlier.colour='red',
outlier.shape=19,
outlier.size=3,
width = 0.6)+
**geom_text(aes(label = Country), na.rm = TRUE, hjust = -0.2)**+
theme_grey() +
labs(title = 'Did males perform better than females?',
y='% Difference from FEMALES',x='',
caption = 'Positive % Difference means Males performed \n better than Females and vice versa',
subtitle = 'Based on PISA Score 2015') +
theme(axis.text=element_text(size=20),
legend.text = element_text(size = 16),
legend.title = element_text(size = 16),
legend.position = 'right', aspect.ratio = 1.4,
plot.title = element_text(size = 20, face = "bold"),
plot.subtitle = element_text(size = 10),
plot.caption = element_text(color = "Red", face = "italic", size = 13)
)

组合多个地块

对于上面组合情节中的每个情节,我们已经在本系列的第一部中讲述了如何创建它。以下是概要:
plot1 = ggplot(data=df, aes(x=reorder(Country.Name, Maths.Diff), y=Maths.Diff)) +
geom_bar(stat = "identity", aes(fill=Maths.Diff)) +
coord_flip() +
theme_light() +
geom_hline(yintercept = mean(df$Maths.Diff), size=1, color="black") +
labs(x="", y="Maths")+
scale_fill_gradient(name="% Difference Level", low = "red", high = "green")+
theme(legend.position = "none") plot2 = ggplot(data=df, aes(x=reorder(Country.Name, Reading.Diff), y=Reading.Diff)) +
geom_bar(stat = "identity", aes(fill=Reading.Diff)) +
coord_flip() +
theme_light() +
geom_hline(yintercept = mean(df$Reading.Diff), size=1, color="black") +
labs(x="", y="Reading")+
scale_fill_gradient(name="% Difference Level", low = "red", high = "green") +
theme(legend.position = "none") plot3 = ggplot(data=df, aes(x=reorder(Country.Name, Science.Diff), y=Science.Diff)) +
geom_bar(stat = "identity", aes(fill=Science.Diff)) +
coord_flip() +
theme_light() +
geom_hline(yintercept = mean(df$Science.Diff), size=1, color="black") +
labs(x="", y="Science")+
scale_fill_gradient(name="% Difference", low = "red", high = "green") +
theme(legend.position = "none")
要将它们结合在一起,请使用“gridExtra”包。
install.packages('gridExtra')
library(gridExtra)grid.arrange(plot1, plot2,plot3, nrow = 1,
top = 'Are Males better than Females?',
bottom = '% Difference from Females'
)#nrow=1 means all the plots are placed in one row
就是这样!同样,我希望你们喜欢这篇文章,并从中有所收获。当然,本指南并不详尽,还有很多其他技术可以用来做 EDA。然而,我相信这个指南或多或少会给你一些如何用 R 从一个简单的情节改进到一个更复杂和更有信息的情节的想法。
如果你有任何问题,请在下面的评论区写下来。再次感谢您的阅读。祝您愉快,编程愉快!!!
探索性数据分析(非视觉)

Exploring Data through Calculations
我被问了很多次“我如何才能做好探索性数据分析(EDA),以便获得功能工程和构建机器学习模型所需的信息?”
在这篇文章和下一篇文章中,我希望这个问题能够得到解答。我不会声称我的过程是最好的,但我希望随着更多的人进入这个领域,他们可以使用我的过程作为更好的 EDA 和建立更好的模型的基础。
做 EDA 有两个主要好处,这些好处将通过模型构建过程获得。这两个好处是:
- 对数据质量有很好的理解。我们需要高质量的数据来建立好的模型。我告诉我的大多数学生和实习生,数据从来都不是干净的。我们只能让它达到我们可以使用的质量水平。
- 快速了解项目。了解监督学习的潜在驱动因素或可能的模式。这些见解可以立竿见影,从其他利益相关者那里获得更多的认同。
我将在两个帖子中讨论 EDA,非可视化(主要通过简单的计算)和可视化。先说非视觉。
汇总统计
我们大多数人都会记得我们的汇总统计,比如均值、中值、众数、极差。如果你需要快速修改,这里有维基百科帖子。汇总统计使我们能够快速查明数据是否存在任何问题。这里举两个例子。
- 对照业务规则/行业法规检查数据。我以前在银行工作过,当涉及到信用卡申请数据时,我们必须检查“年龄”栏,以确保没有年龄低于监管要求的申请。范围(显示最小-最大值)可以帮助我们很快看到这一点。
- 观察和比较中位数和平均数,人们会简单地理解数据是向左还是向右。考虑到这一点,下一个问题是询问数据具有这种分布是否有意义。我经常引用的一个例子是收入。大多数时候收入应该是右偏的(大多数人处于低收入水平,很少人处于高收入水平)。如果要得到正态分布或左偏分布,就需要检查数据质量。
缺失值
我发现很多人一开始都有这样一个普遍的误解,认为丢失数据是“不好的”。这并不完全正确。为了知道它是“坏的”还是“不好的”,人们必须结合上下文。这里有一个例子。
大多数家庭过去都有固定电话(即家庭电话),这意味着如果要收集家庭电话号码,预计应该有一个值。如今,随着智能手机的出现和便利,人们很可能不会有家庭电话号码可给。从这个意义上说,丢失电话号码并不“糟糕”。
当我们探索数据时,我们需要了解丢失了多少数据(即,在观察值的数量中,有多少是丢失值)。这些信息可以让我们预见机器学习模型的任何可能问题,我们可以采用的可能插补方法,甚至可以设置一个指标/虚拟变量来指示缺失值。
相关性
相关性有助于理解当前的哪些特性可以成为目标的驱动力,尤其是。在我看来,这很重要,因为我们正在处理如此多的数据,并且在所有事情上都使用深度学习模型,限制我们输入模型的特征对我们来说很重要。较少的特征允许更快的模型训练(假设深度学习)以及更低的维护成本。
另一个好处是可以预见到多重共线性的问题。对高度相关的特征对有很好的理解,允许我们对这两个特征进行双重检查,以理解它的参数是否有意义,如果没有意义,我们如何纠正它。当然,人们仍然可以使用方差膨胀因子来识别它,但是相关性只是一个额外的‘安全毯’。
聚类分析
一旦完成了相关性分析,就可以选择与目标高度相关的特征,并对其执行聚类分析(简单的 K-Means 即可)。理想情况下,除了目标之外,大约有 7 到 8 个特征。至于集群的数量,这是由个人决定的,看是否能产生一个“易于解释”(即能给大多数集群贴上明确的标签)的集群。
聚类分析在形成聚类时考虑了所有输入特征,人们可以看到这些特征和目标是如何结合在一起的。这有助于提供额外的“安全毯”,以确保我们构建了“正确的”模型。
结论
这些是我在执行探索性数据分析时通常采取的非可视化步骤。一个非常重要的注意事项是,当进行探索性数据分析时,文档非常重要,因为这些学习将在下游过程中有用,即模型训练过程。
同样,这些并不是决定性的步骤,您可能还想添加其他步骤来补充您的模型构建过程,如果您有其他步骤,请与我分享。
在我的下一篇文章中,我将讨论更多关于如何使用视觉来探索数据。
我希望这篇文章对你有用。我希望所有读者有一个有趣的数据科学学习之旅,并访问我的其他博客文章和 LinkedIn 个人资料。
Python 中 FIFA 19 数据集的探索性数据分析
FIFA 19 数据分析

在本帖中,我们将对 FIFA 19 数据集进行简单的探索性数据分析。数据集可以在 Kaggle 上找到。FIFA 是国际足球协会联合会,FIFA 19 是 FIFA 系列足球电子游戏的一部分。这是有史以来最畅销的视频游戏之一,迄今为止已经在 T2 卖出了 2 . 6 亿份拷贝。
对于这个分析,我们将使用 python pandas 库、numpy、seaborn 和 matplotlib。数据集包含 89 列,但我们将分析限制在以下 10 列:
- 姓名 —玩家姓名
- 年龄 —玩家的年龄
- 国籍 —球员的国籍
- 价值 —当前市场价值
- 工资 —球员的工资
- 首选脚 —玩家首选脚
- 身高 —球员的身高
- 体重 —玩家的体重
- 位置 —球场上的位置
- 总体 —玩家的总体评分
我们开始吧!
首先,让我们导入 pandas 库,将 csv 文件读入 pandas 数据帧,并打印前 16 列的前 5 行:
import pandas as pddf = pd.read_csv("data.csv")print(df.head())

我们可以过滤数据帧,使其只包含我们需要的十列:
df = df[['Name**',** 'Age', 'Nationality', Value', 'Wage', 'Preferred Foot', 'Height', 'Weight', Position', 'Overall']]
print(df.head())

我们可以做的第一件事是在 height 列上生成一些统计数据。这些值是以字符串的形式给出的,所以我们希望将它们转换成可以在计算中使用的数字。这里我们将高度字符串转换成厘米值。为此,我们将字符串的第一个元素(例如“5'7”)乘以 12.0(英寸),然后添加字符串的第三个元素“7”(英寸),并将最终结果乘以 2.54(厘米):
Height_cm = []for i in list(df['Height'].values):
try:
Height_cm.append((float(str(i)[0])*12.0 + float(str(i)[2:]))*2.54)
except(ValueError):
Height_cm.append(np.nan)
df['Height_cm'] = Height_cm
首先,我们初始化一个名为“Height_cm”的列表,并迭代 dataframe 中的高度字符串值。我们在 try except 子句之间插入转换语句,因为存在字符串包含非数值的情况,特别是缺少高度值的情况。每当我们到达一个缺失值时,我们就追加一个 np.nan (numpy '非数字')值。最后,我们将新列定义为我们刚刚填充的列表。
接下来,让我们删除数据帧中缺少的值,并打印前五行:
df.dropna(inplace = True)
print(df['Height_cm'].head())

我们可以查看以厘米为单位的身高平均值和标准差:
print("Mean: ", df['Height_cm'].mean())
print("Standard Deviation: ", df['Height_cm'].std())

我们还可以生成高度直方图:
import seaborn as sns
sns.set()
df['Height_cm'].hist(bins = 10)

我们还可以将其封装在一个函数中,并将其用于任何数字列:
import seaborn as sns
import matplotlib.pyplot as plt
def get_statistics(numeric_column_name):
print("Mean {}: ".format(numeric_column_name), df[numeric_column_name].mean())
print("Standard Deviation in {}: ".format(numeric_column_name), df[numeric_column_name].std())
sns.set()
plt.title("{} Histogram".format(numeric_column_name))
df[numeric_column_name].hist(bins = 10)
get_statistics('Height_cm')
它生成与上面相同的输出。

我们还可以将重量列转换为千克,以便与公制保持一致。我们通过取“重量”列中每个字符串值的前三个元素,将它们转换为浮点值,然后除以千克和磅之间的转换因子(2.20462)来实现这一点:
df['Weight_kg'] = df['Weight'].str[:3].astype(float)/2.20462
print(df.head())
我们可以用‘Weight _ kg’调用 generate_statistics 函数:
get_statistics('Weight_kg')

我们还可以使用 collections 模块中的“Counter”方法来查看每个球员的国籍频率:
from collections import Counter
print(Counter(df['Nationality'].values))

我们可以限制计数器只输出五种最常见的国籍:
print(Counter(df['Nationality'].values).most_common(5))

如你所见,英格兰是最常见的国籍,有 1657 项记录,其次是德国,有 1195 项,西班牙有 1071 项。我们可以在条形图中显示此输出:
bar_plot = dict(Counter(df['Nationality'].values).most_common(5))
plt.bar(*zip(*bar_plot.items()))
plt.show()

同样,我们可以定义一个函数来绘制任何分类列的最常见值:
def plot_most_common(category):
bar_plot = dict(Counter(df[category].values).most_common(5))
plt.bar(*zip(*bar_plot.items()))
plt.show()
如果我们用‘Position’调用函数,我们得到:
plot_most_common('Position')

接下来,让我们将价值(球员的市场价值)和工资转换成可以在计算中使用的数值。首先,让我们截断“值”列中的字符串值,以便删除“欧元”和“M”。然后,我们可以将每个字符串转换为一个浮点并乘以 1e6:
value_list = []
for i in list(df['Value'].values):
try:
value_list.append(float(i)*1e6)
except(ValueError):
value_list.append(np.nan)
df['Value_numeric'] = value_list
我们可以对“工资”做同样的处理,但这里我们乘以 1e3:
wage_list = []
for i in list(df['Wage'].values):
try:
wage_list.append(float(i)*1e3)
except(ValueError):
wage_list.append(np.nan)
df['Wage_numeric'] = wage_list
我们还想将“年龄”列中的字符串值转换成整数:
df['Age'] = df['Age'].astype(int)
在这里,我们可以从数字列中生成一个热图,它将向我们显示每个变量与其他变量的相关性有多强。让我们过滤数据帧,使其仅包含数值,并从结果数据帧中生成热图:
numerical_columns = df[['Height_cm', 'Weight_kg', 'Value_numeric', 'Age', 'Wage_numeric']]sns.heatmap(numerical_columns.corr(), annot=True)
plt.show()

我们还可以使用盒状图来显示基于最小值、最大值、中值、第一个四分位数和第三个四分位数的数值分布。如果你对它们不熟悉,可以看看文章了解盒子情节。

例如,英国、德国和西班牙的市场价值分布:
df = df[df['Nationality'].isin(['England', 'Germany', 'Spain'])]
sns.boxplot(x= df['Nationality'], y = df['Value_numeric'])
plt.show()

年龄分布:
sns.boxplot(x= df['Nationality'], y = df['Age'])
plt.show()

重量分布:
sns.boxplot(x= df['Nationality'], y = df['Weight_kg'])
plt.show()

和高度:
sns.boxplot(x= df['Nationality'], y = df['Height_cm'])
plt.show()

我就讲到这里,但是您可以随意使用数据并自己编码。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!
探索性数据分析——第一部分
在本文中,我们将了解如何用熊猫探索数字数据。

Source : “Panda” by thedailyenglishshow is licensed under CC BY 2.0
什么是数据分析中使用的数据集?
数据分析中使用的数据集是某些数字或字符串或两者的组合,它们可能有也可能没有任何特定的顺序,我们需要从中预测未来可能发生的结果。
现在,当我们有了原始数据集,我们必须从中做出预测,几个问题将出现,以采取这样的决定。例如,如果我想在 5 年内投资获得最佳回报,我会首先研究公共和私营企业的几种投资方案并进行比较,联系企业的客户服务部门以消除我的疑虑,阅读其他客户的评论以更深入地了解他们,彻底检查他们的条款和条件以及更多此类调查。对于数据科学家来说,这些调查方法不过是“探索性数据分析”,同时处理这些原始数据并从中推断预测。
在开始探索性数据分析过程之前,需要了解以下重要问题:
- 我在给定的数据集中寻找的问题是什么
- 我的数据集包含哪种类型的数据
- 为了预测我的目标变量,需要在数据集中添加或删除哪些特征
- 是否存在任何缺失值,如果是,如何处理
- 如果有异常值,我们如何消除它们
在本文中,我们将只在一个数字数据集上探索 EDA 的过程。
- 让读取给定的数据集(使用
read_csv)),并考虑到要训练的给定数据集在,使用head方法查看前 5 行。csv 格式。
import pandas as pd
import numpy as np
df = pd.read_csv("train.csv")
df.head(5)
注意:如果原始数据由分隔符“;”分隔那么我们的命令将是:
df = pd.readcsv(“train.csv”, sep = “;”)

这里我们需要预测“票价金额”
我们使用了一个数据集,该数据集将根据在纽约市内行驶的距离来预测出租车的费用。head()和tail()函数返回数据集的第一个和最后一个观察值。
df.shape()可以获取数据集中的行数和列数。df.describe()为我们提供每个变量数据集的平均值、标准偏差和其他特征。

- 此处,我们的目标变量“票价 _ 金额”和其他变量(如“乘客 _ 数量”和“接送 _ 纬度”)的 75%和最大值之间存在显著的差异。这些值清楚地暗示了我们的数据集包含了异常值。
- 我们在这里也可以注意到,均值远高于变量“fare_amount”的中值。
df.dtypes给出了df数据帧中每个变量的数据类型。

df.info()可以帮助我们查看是否有丢失的值

- 在我们的数据集中,可变列“fare_amount”和“passenger_count”包含缺失值。
我们的目标变量“票价金额”本质上是数字。
missing_value = pd.DataFrame(df.isnull().sum())

我们需要弥补我们缺失的价值观。但是在执行相同的操作之前,我们需要移除异常值。
为什么我们要在缺失值插补之前移除异常值?
因为缺失值插补有不同的方法;其中之一是用特定列的平均值、中值或众数替换该列的缺失值。现在,如果在执行插补过程时数据集包含这些异常值,那么丢失的值将被错误地替换。因此,我们需要去除异常值。
异常值去除
我们将继续为每个变量构建箱线图,以了解每个变量的异常值。
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
sns.boxplot(df['passenger_count'])

这里我们可以清楚地看到,有些数据点表明“乘客计数”超过 5000,我们将删除这些数据点。事实上,没有一辆出租车能够搭载超过 8 名乘客,因此,我们将删除那些值大于 8 的数据点,并对<1.
df=df.drop(((df[df['passenger_count']>8])).index,axis=0
df=df.drop(((df[df['passenger_count']<1])).index,axis=0)
df
Once the rows with outliers are deleted, we can once again check our boxplot.

We also checked if any latitude or longitude is out of the range. If so, we have dropped it along with the outliers present in every column.
进行排序:
- 在这里,我们可以根据特定变量对数据框进行升序或降序排序。
df.sort_values(by='passenger_count', ascending =True).head(5)
df

- 现在,如果我们需要对多列进行排序:
df.sort_values(by=['passenger_count','fare_amount'], ascending =[True,True] ).head(5)

上面我们可以看到,我们的代码几乎相同,但输出是不同的。通过这种方式,我们可以获得所需的数据框架,以便对其进行更深入的分析。
- 现在,如果我需要知道当我的 passenger_count 为 1 或 2 时所有其他变量的平均值,我可以得到相同的结果:
df[df['passenger_count'] == 1].mean()

缺失值分析
- 现在,我们需要检查所有变量中缺失值的数量。
missing_value = pd.DataFrame(df.isnull().sum())
missing_value

我一直认为重要的是估算缺失的值,而不是删除它们。在这里,我对每一列使用了“最频繁出现的数据”的方法来替换各自缺失的值。
imp = SimpleImputer(missing_values=np.nan, strategy=’most_frequent’)
train_data=pd.DataFrame(imp.fit_transform(df), columns=df.columns)
print(f’Row count after imputing missing values — {train_data.shape[0]}’)

通过图表检查变量之间的相关性
检查任何变量之间是否高度相关是非常重要的。如果是这样,那么我们不应该考虑这些变量,而是在它们之间只选择一个变量,用于预测因变量所需的数据框。
df.corr(method=’pearson’).style.format(“{:.2}”).background_gradient(cmap=plt.get_cmap(‘coolwarm’), axis=1)

- 我们使用了 corr()函数和所有变量的图形表示来观察它们是否与数据集中的任何其他变量高度相关。
在清理和删除某些数据点之后,我们获得了所需的数据框,可以在此基础上进行更深入的分析。
- 这里,我们通过列联表比较两个变量:
pd.crosstab(df['passenger_count'], df['fare_amount'], normalize = True)

让我们来看看用纬度和经度衡量的特定地区的平均乘车人数:
df.pivot_table(['pickup_latitude', 'dropoff_latitude', 'pickup_longitude','dropoff_longitude'], ['passenger_count'], aggfunc='mean')

现在我们的数据集可以进行机器学习了!
类似地,您可以添加几个其他高级功能来从数据中推断出更好的洞察力。这只是分析任何数值数据集的一个基本方法。在下一篇文章中,我们将讨论如何在分类数据集上执行 EDA。
启动资金、投资和收购

Source: Pixabay
探索性数据分析
以下是我最近决定做的一个有趣的小数据分析项目,主要是作为练习 SQL 和做一点探索性数据分析(EDA)的一种方式。在我的互联网旅行中,我遇到了 模式分析 ,并看到他们有一个非常好的界面来编写 SQL 查询,以及可供选择的数据集(该界面被称为 模式工作室 ,我非常确定数据保存在 PostgreSQL 数据库中)。另一个很棒的特性是你可以将 SQL 分析与 Python 笔记本集成在一起。我是这个的忠实粉丝,因为我正在努力寻找其他在线资源,在那里我可以很容易地访问一些免费的 SQL 数据库。
写这篇文章时,我有三个主要目标:
- 练习我的 SQL 技能并实现一个有趣的迷你项目
- 概述一个数据分析项目的典型工作流程,着重于初始数据探索。(至少对我来说是典型的工作流程)。
- 为那些试图学习 SQL 或 Python 的人提供一个教程,并展示你可以从一点点 EDA 和一些相关问题中产生一些真正强大而有趣的见解。
我真的很喜欢分析这个数据集,并且发现我探索得越多,我提出的问题就越多,但是为了保持这篇文章的相对简洁和正确,我将提出我想探索并获得一些见解的 3 主要 主题/问题(下) 。我鼓励任何跟随我的人提出他们自己的问题,因为有比我在这里讨论的更多的问题。
数据集和初始问题
我们今天要看的数据集是 Crunchbase 数据集。它包含了自 20 世纪初以来超过 40,000 家初创企业的融资、收购和投资信息。我将使用数据集的教程版本,据我所知,它们基本上是相同的,除了教程版本比原始版本稍短,并且一些列已被清理,这对我们来说是个好消息,因为我们不必花时间清理数据(然而,通常,这是任何分析中至关重要的一步,我建议熟悉清理不同类型的数据)。该数据库由三个表组成:
我想探究的数据的主要方面是融资、投资和收购的趋势。更明确地说,我将提出 3 个一般性问题来尝试和回答。这样做将有助于我们集中分析,并使我们的最终目标更加清晰。
- 按行业和国家划分的资助有哪些主要特点?
- 收购倾向于同行业内还是跨行业?即是否有纵向或横向整合的证据?
- 有没有投资泡沫的迹象?
好了,我们已经提出了几个要探讨的问题,实际上我们可以在这里做一些分析。最初,我将查询数据库来回答这些问题,当然也是为了实际获取数据。我还将使用 Python 做一些进一步的分析和可视化。Mode 通过将我们的查询结果转换成 Python 对象,并允许我们从一个 notebook 实例访问它们,使得两者之间的切换非常无缝。为了获得数据的概述,我建议查看每个表的上面的链接。
探索性数据分析
提供资金
我将直接切入正题,看看我们能否回答第一个问题。嗯,我们可以把它分解一下,因为这个问题有几个部分。让我们先来看看平均资助金额、总资助金额和行业资助的公司数量,并将结果限定为前 10 名。
SELECT category_code,
COUNT(*) AS number_of_companies,
AVG(funding_total_usd) AS avg_funding,
SUM(funding_total_usd) AS total_funding
FROM tutorial.crunchbase_companies
WHERE funding_total_usd IS NOT NULL AND category_code IS NOT NULL
GROUP BY 1
ORDER BY 4 DESC
LIMIT 10;
这里的结果非常有趣,但也许并不出乎意料,因为获得最多资金的行业似乎都与技术相关,如生物技术/软件/电子商务等。在以下三个图表中出现的行业之间也有非常密切的相关性(这些图表都是使用 mode studio btw 制作的)。我在这篇文章的结尾提供了一个完整报告的链接,其中包含了那些想看的人的交互式图表。最高的平均资助额似乎出现在清洁技术领域,这与推动生产对环境负面影响较小的技术相一致。从表面上看,鉴于许多国家都有严格的碳排放目标,这是一个非常受欢迎的进展。

Figure 1: Average Funding By Industry

Figure 2: Total Funding By Industry
如果我们仔细研究一下,会得到什么样的见解?嗯,如果我们长期观察融资情况,我们会得出一个不同的结论。从图 3 中我们可以看出,从 2002 年到 2006 年,资金总额大幅增加,达到 80 亿美元左右的峰值。然而,2006 年后,该部门的资金大幅减少。这似乎是投资繁荣和萧条的标志,或者换句话说,是泡沫。在做了一点研究后,似乎有许多因素可能促成了这一繁荣,包括这一时期的税收减免和清洁技术贷款担保。还有一些因素可能导致清洁技术在随后几年的资金下降,如燃料价格下跌,当然还有始于 2007/2008 年的金融危机。这减少了投资清洁技术和燃料来源的资金激励,也可能导致投资者在当前经济环境下的不确定性。
好吧,这是分析的一个好的开始,似乎在回答问题 1 和问题 3 方面都有所进展。让我们看看我们还能从这些数据中收集到什么有趣的见解。
SELECT category_code,
DATE_PART('year', first_funding_at::DATE) AS year,
SUM(total_funding_amt) AS sum_funding_amt
FROM tutorial.crunchbase_companies
WHERE category_code = 'cleantech' AND first_funding_at IS NOT NULL
GROUP BY 1,2
ORDER BY 2 ASC;

Figure 3: Total Funding in cleantech Sector
既然我们已经了解了一个特定的行业,不如我们来更全面地了解一下,看看这些年来所有行业中获得累计最高融资水平的公司,看看我们是否认识其中的任何一家。所以我敢肯定,你们大多数人都知道这些公司,比如脸书、Groupon、Twitter、威瑞森等等(图 4)。我们也可以看看排名前 10 的公司是在什么样的时间段得到资助的。他们是一次获得一次性付款,还是长期获得资助?我们可以通过简单地从最后资助的 t 变量中减去第一资助的 t 变量来得到天数差。我们还可以计算每个人获得的融资轮数,并以此计算每轮融资的平均水平。****

Figure 4: Top 10 Companies by Total Funding
SELECT name,
funding_total_usd,
TO_DATE(first_funding_at, 'DD/MM/YY') AS first_month,
TO_DATE(last_funding_at, 'DD/MM/YY') AS last_month,
(TO_DATE(last_funding_at, 'DD/MM/YY') - TO_DATE(first_funding_at, 'DD/MM/YY')) AS days_difference,
funding_rounds,
funding_total_usd/funding_rounds AS funding_per_roundFROM tutorial.crunchbase_companies
WHERE funding_total_usd is NOT NULL
ORDER BY 2 DESC
LIMIT 10;
我们可以在下面的表 1 中看到这个查询的结果。这张表告诉了我们什么?看起来有 3 家公司,Sigmacare,Carestream 和 Terra-Gen Power 进行了首轮融资。前 10 名中的其余公司似乎已经获得了多轮融资,平均每轮融资 5。这些公司也在几年内获得了资助。除了只进行了一轮融资的 3 家公司之外,平均每轮融资约为 5.67 亿美元,这是一笔惊人的资金。相比之下,其他超过一轮融资的初创公司平均只有不到 800 万美元。
with t1 as (SELECT funding_total_usd/funding_rounds AS funding_per_round
FROM tutorial.crunchbase_companies
WHERE funding_rounds > 1)
SELECT AVG(funding_per_round) FROM t1;

Table 1
我们还可以绘制资金的分布图,这将为我们提供资金数量的直观概览。出于绘图的目的,我已经删除了一些非常大的投资,包括数字,以便我们可以更好地可视化其余的数据(下面的 Python 代码)。平均值约为 1600 万美元,而中值为 500 万美元,这表明该样本中仍有显著的异常值。
fund_dist = fund_dist[fund_dist['funding_total_usd'] < 2.050000e+08]
plt.figure(figsize=(16,6))sns.distplot(fund_dist['funding_total_usd'], bins = 30)

Figure X: Distribution of Funding Amount
好了,现在我们对融资数据有了一个相当好的概述,让我们看看一家公司收到的融资额和他们是否还存在之间是否有关系?用 Python 来看看吧。首先,我们来探讨一下公司的现状。下面的代码获取每个类别中公司的原始计数和百分比。绝大多数公司仍在运营(82%),但也有 8%的公司在此期间已经关闭。查看表 3,我们可以看到最高平均融资水平来自 IPO(股票市场的首次公开发行),这很有趣,因为它是状态列中最不常见的类别。
datasets[3]['status'].value_counts()
datasets[3]['status'].value_counts(normalize = True)datasets[3].groupby('status')['funding_total_usd'].agg(['mean', 'sum'])

Table 2: Status Categories

Table 3: Average and Total Funding by Status.
鉴于平均融资额最高的是 IPO,让我们快速浏览一下融资额最高的 10 家 IPO。这里又出现了一些熟悉的面孔,如威瑞森、脸书和特斯拉,它们都从 IPO 中获得了大量资金。我还计算了数据集中所有 IPO 产生的资金占总资金的比例,非常惊讶地发现前 2 名产生了总资金的 16%。当时显然有很多投资者对这些公司感兴趣。
datasets[3][datasets[3]['status'] == 'ipo'][['name', 'category_code', 'funding_total_usd']].sort_values(by = 'funding_total_usd', ascending=False)[:10]

Table 5: Top 10 IPO’s
那么,对于仍在运营的公司和现在关闭的公司之间的区别,我们能说些什么呢?从上面的信息中,我们可以说,现在关闭的公司平均获得的资金更少,总的资金也更少。那么这仅仅是资金问题吗?大概不会。这些公司不再运营可能还有很多其他原因。我试图找出运营公司和非运营公司的特征之间的一些差异,比如它们获得的融资轮数以及它们运营的国家,但我真的没有发现任何明显的差异。不幸的是,我们似乎无法找到这个问题的确切答案。这实际上是非常重要的一点,
利用现有的数据,并不总能找到你想要的答案。这是我们进行探索性数据分析的原因之一,因为它让我们能够找出我们有望找到答案的问题。
对数据进行初步探索性分析是分析项目中非常重要的一步,因为它可以帮助制定现实的目标,也可以帮助分析师设定和管理对项目结果的预期。
在资金表中,我想看的最后一件事是整个美国资金的分布,因为我怀疑其中很大一部分在美国,特别是在加利福尼亚州。这是 Python 擅长的地方。我在以前的帖子中曾使用过,这是另一个使用它的绝佳机会。下面是 Python 代码,用于从 mode 创建的对象中获取我们需要的数据,然后绘制一个漂亮的交互式 Chloropleth(我必须附加一个 PNG,因为 Plotly 的自由层有视图限制)。
*import matplotlib.pyplot as plt
%matplotlib inline
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
import plotly as py
import plotly.graph_objs as go
init_notebook_mode(connected=True) #do not miss this line
from plotly import tools comp_df = datasets[3] # object created by mode
temp_plot = comp_df[['funding_total_usd', 'country_code', 'state_code']].dropna()
grouped_data = temp_plot.groupby('state_code').sum().reset_index() data = [ dict(
type='choropleth',
locations = grouped_data['state_code'],
autocolorscale = True,
z = grouped_data['funding_total_usd'],
locationmode = 'USA-states',
marker = dict(
line = dict (
color = 'rgb(255,255,255)',
width = 2
)
),
colorbar = dict(
title = 'Millions USD'
)
) ]
layout = dict(
title = 'Total Funding for startups across the US',
geo = dict(
scope='usa',
projection=dict( type='albers usa' ),
showlakes = True,
lakecolor = 'rgb(255, 255, 255)'),
)
fig = go.Figure(data = data, layout = layout)
py.offline.iplot(fig)*

Figure 5: Funding across the US
看起来我的怀疑是正确的,最强烈的红色是在加利福尼亚州,表明最高水平的资金出现在那里,主要是因为硅谷的高科技公司密度高。在美国的其他地区,如纽约、马萨诸塞州和马里兰州,也有大量的资助。考虑到这些州有众多的大学和科技公司,这也不足为奇。既然我们已经看了美国,为什么我们不快速看一下资金的全球分布呢?(为了简洁起见,我将省略 python 代码,但它与上面的代码非常相似。)

Figure 6: Funding across the world
同样,大部分资金位于美国,然而,中国、印度和英国也有大量资金,尽管从上面的图表中可能有点难以看出(这在我在底部链接的互动报告中更明显)。
获得
我们已经花了相当多的时间来分析公司表,但是其他表呢?这些年来的收购情况如何?本节的主要目的是了解正在进行的收购的类型,即正在进行的收购是跨行业还是在同一行业内进行。这可以帮助我们了解横向和纵向整合的水平(这些是竞争经济学中的重要概念)。我们可以从一些最大的收购开始,看看它们是在同一个行业还是不同的行业。这可以让我们对每个行业的集中度有一点了解。
我们可以做的第一件事是观察一段时间内收购数量的总体趋势,并检查数据集中最大的收购。这在 PostgreSQL 中相对简单。第一个查询非常简单,只返回按价格排序的前 10 项收购。第二个查询使用窗口函数返回每年的收购数量以及累计数量。
*SELECT company_name,
company_category_code,
acquirer_name,
acquirer_category_code,
acquired_year,
price_amount
FROM tutorial.crunchbase_acquisitions
WHERE price_amount IS NOT NULL
ORDER BY price_amount DESC
LIMIT 10;------------------------------------------------------------------SELECT acquired_year,
AVG(price_amount),
COUNT(*),
SUM(COUNT(*)) OVER (ORDER BY acquired_year) AS total_count
FROM tutorial.crunchbase_acquisitions
WHERE price_amount IS NOT NULL AND acquired_year > 1995
GROUP BY 1
ORDER BY 1;*
从总价排名前十的收购来看,似乎大多数收购是跨行业的,而不是同一行业内的。这表明,没有太多的横向整合,因为收购和被收购的公司往往处于不同的行业,至少对于最大的收购来说是这样。有趣的是,似乎有一些公关公司正在被其他公司收购(表 2)。这可能与品牌或公司试图改善自己的形象有关吗?我们还可以看到,几乎所有这些收购都是在过去 10 年中完成的,几乎所有的公司都被技术相关行业的公司收购了。这些观察结果与我们目前所看到的非常一致。

Table 6: Top 10 Acquisitions by Price ($)
下图对应于上面的第二个查询,并突出显示了从 2000 年到 2014 年(数据集中的最后一年)收购的激增。综上所述,这些行业显然存在大量的金融活动。总的来说,随着时间的推移,收购数量的增长相当不稳定,但从 2010 年起(除了 2013 年),收购数量似乎呈下降趋势。有趣的是,尽管数字有所下降,但在同一时期,平均成本方面的收购规模一直在上升。换句话说,近年来出现了大规模收购的趋势。这是否意味着某些公司或行业垄断力量的增强?

Figure 7: Acquisitions over time — number and amount paid
投资
在这一部分,我想简要地看一下投资表。首先,我绘制了每笔投资筹集金额的分布图,让我们更好地了解数据的分布情况。图 9 显示了整个时间段内投资价值的直方图。从图中我们可以看到,大多数投资似乎在 1,200 万美元左右。也有一些异常值。让我们来看看哪些公司获得了巨额投资,以及这是哪一轮融资。结果显示,几乎所有最大的投资都是在 IPO 之后。这大概意味着投资是购买股票。
*SELECT funding_round_type, raised_amount_usd
FROM tutorial.crunchbase_investments
WHERE funding_round_type IS NOT NULL AND raised_amount_usd IS NOT NULL
ORDER BY 2 DESC;------------------------------------------SELECT funding_round_type, COUNT(*)
FROM tutorial.crunchbase_investments
WHERE funding_round_type IS NOT NULL AND raised_amount_usd IS NOT NULL
GROUP BY 1
ORDER BY 2 DESC;-----------------------------------------SELECT company_name, company_category_code, investor_name, investor_category_code,
funding_round_type, raised_amount_usd, funded_at
FROM tutorial.crunchbase_investments
WHERE raised_amount_usd IS NOT NULL
ORDER BY 6 DESC LIMIT 15;*

Figure 8
样本的其余部分呢?他们的资金来源是股权、债务还是天使投资者?按融资轮类型划分的投资总数如图 10 所示。首轮融资似乎是公司获得的最常见的融资类型,其次是风险资本和天使投资。顾名思义,A 轮融资是初创企业可以获得的首批融资之一。之后通常是 B 轮和 C 轮。事实上,首轮融资可能比后续融资更频繁,因为许多初创企业实际上并不成功,因此无法进入下一轮融资。请参见此处了解融资轮类型的更深入的解释。

Figure 9
*with t1 AS
(SELECT company_name, investor_name, funded_year ,investor_category_code,
company_category_code,
SUM(raised_amount_usd) AS total_raised,
rank() OVER(PARTITION BY investor_category_code
ORDER BY SUM(raised_amount_usd) DESC) AS rank
FROM tutorial.crunchbase_investments
WHERE raised_amount_usd IS NOT NULL
AND investor_category_code IS NOT NULL
GROUP BY 1,
2,
3,
4,
5
ORDER BY 5,
3 DESC)
SELECT *
FROM t1
WHERE rank < 2
ORDER BY 6 DESC
LIMIT 15;*
上面的查询显示了每个行业的最高投资以及哪个行业正在接受投资。出于展示数据的目的,我们仅选择了前 15 项投资。前 15 名主要是移动行业。大量资金涌入移动行业,这就引出了一个问题:这些资金是流向一家公司还是多家公司?为什么人们对这个行业如此感兴趣?经过进一步调查,我们发现 2008 年在 Clearwire 上有大量投资,这基本上就是我们在表 1 中看到的。为什么对 Clearwire 这么感兴趣?2008 年有许多公司投资 Clearwire,包括 Sprint Nextel、Google、Intel 和 Comcast 等,这些公司似乎被用来推出 4G 无线技术。

Figure 10
主要要点
- 似乎没有证据表明的横向整合,尤其是那些最大的收购。因此,没有明显的证据表明缺乏竞争。这当然不是最终的结论,因为一些行业可能已经集中了。这表明,至少它没有因为收购而变得更加集中。**
- 似乎确实有更大规模收购的总趋势,这可能预示着公司垄断力量的增强。
- 我们确实发现了一些投资泡沫的证据,特别是在清洁技术领域。有其他泡沫的证据吗?我会让你们自己去发现。****
- 大部分资金都流入了美国,尤其是流入了加州,鉴于近年来硅谷科技公司的激增,这确实是我们所期待的。
- 最高水平的资助主要集中在与技术相关的行业,如清洁技术、生物技术、移动等。
- 毫无疑问,产生最多资金的融资类型是 IPO 。
感谢大家的阅读,希望你们都觉得这很有趣,学到了一些东西,在下一个帖子里再见。
探索性数据分析……一个在数据科学项目中被忽视的话题

探索性数据分析
作为探索性数据分析的一部分,我们将讨论以下主题:
- 什么是探索性数据分析?
- 我们为什么要做 EDA?
- EDA 有哪些步骤?
- EDA 用的工具有哪些?
- 如果我们不做 EDA 会怎么样?
什么是探索性数据分析?
探索性数据分析(EDA) 是由“John Tukey”于 20 世纪 70 年代开发的数据分析过程的第一步。在统计学中,探索性数据分析是一种分析数据集以总结其主要特征的方法,通常采用可视化方法。从名字本身就可以知道,这是我们需要探索数据集的一个步骤。
****例如,你打算去一趟“ X 的地方。做决定前要做的事情:
- 你将在谷歌、Instagram、脸书和其他社交网站上探索该位置的所有地方、瀑布、徒步旅行、海滩和餐馆。
- 计算它是否在你的预算之内。
- 检查覆盖所有地方的时间。
- 旅行方式的类型。
同样,当你试图建立一个机器学习模型时,你需要非常确定你的数据是否有意义。探索性数据分析的主要目的是获得对数据的信心,从而准备好使用机器学习算法。

我们为什么要做 EDA?
探索性的数据分析是你跳到机器学习或数据建模之前至关重要的一步。通过这样做,您可以了解所选的特征是否足以建模,是否所有的特征都是必需的,是否有任何相关性,基于这些相关性我们可以返回到数据预处理步骤或继续建模。
一旦 EDA 完成并得出见解,其特征就可以用于监督和非监督机器学习建模。
在每个机器学习工作流程中,最后一步是向利益相关者报告或提供见解,作为一名数据科学家,你可以解释每一点代码,但你需要记住受众。完成 EDA 后,您将获得许多图表、热图、频率分布、图表、相关矩阵以及假设,通过这些图表,任何个人都可以了解您的数据是关于什么的,以及您从探索您的数据集中获得了什么见解。
我们有句谚语“一图胜千言”。
我想为 data scientist 修改为"一个图值一千行"
在我们的旅行示例中,我们对选定的地方进行了所有的探索,在此基础上,我们将获得计划旅行的信心,甚至与我们的朋友分享我们对该地方的见解,以便他们也能加入。
EDA 有哪些步骤?
进行探索性数据分析有许多步骤。我想就以下几个步骤进行讨论
- 数据描述
- 处理缺失数据
- 处理异常值
- 通过情节理解关系和新的见解
a)数据描述:
我们需要了解不同种类的数据和数据的其他统计数据,然后才能继续其他步骤。一个好的方法是从 python 中的 describe() 函数开始。在 Pandas 中,我们可以对数据框应用函数 describe,这有助于生成描述性统计数据,这些统计数据总结了数据集分布的集中趋势、分散性和形状,不包括" NaN "值。
对于数字数据,结果的索引将包括计数、平均值、标准差、最小值、最大值以及下限、50%和上限。默认情况下,下百分位是 25,上百分位是 75。50%与中位数相同。

对于对象数据(如字符串或时间戳),结果的索引将包括计数、唯一、顶部和频率。顶部是最常见的值。Freq 是最常见的值频率。时间戳还包括第一项和最后一项。

b)处理缺失数据:
现实世界中的数据很少是干净的和同质的。由于多种原因,数据可能在数据提取或收集过程中丢失。缺少的值需要小心处理,因为它们会降低我们任何性能指标的质量。它还会导致错误的预测或分类,并且还会对所使用的任何给定模型造成高偏差。有几种处理缺失值的方法。然而,应该做什么的选择在很大程度上取决于我们的数据和缺失值的性质。以下是一些技巧:
- 删除空值或缺失值
- 填充缺失值
- 用 ML 算法预测缺失值
(i) 删除空值或缺失值:
这是处理缺失值的最快和最容易的步骤。不过一般不建议。这种方法降低了我们模型的质量,因为它减少了样本量,因为它通过删除任何变量缺失的所有其他观察值来工作。
****Python 代码:
dataset.dropna()
****(二)填补缺失值:
这是处理缺失值的最常见方法。在此过程中,缺失值将被测试统计数据(如缺失值所属的特定特征的平均值、中值或众数)替换。
Python 代码:
dataset[‘Column_name’]=dataset[‘Column_name’].fillna(mean_value).
(三)用 ML 算法预测缺失值:
这是迄今为止处理缺失数据的最好和最有效的方法之一。根据缺失数据的类别,可以使用回归或分类模型来预测缺失数据。
c)处理异常值:
离群值是指与人群分离或不同的东西。异常值可能是数据收集过程中出现错误的结果,也可能只是数据中出现偏差的迹象。检测和处理异常值的一些方法:
- 箱形图
- 散点图
- z 分数
- IQR(四分位数间距)
(一)方框图:

箱线图是一种通过四分位数以图形方式描绘数字数据组的方法。该方框从数据的 Q1 值延伸到第三季度的四分位值,中间有一条线(Q2)。触须从框的边缘延伸出来,以显示数据的范围。离群点是那些超过胡须末端的点。箱线图显示了位置和分布的稳健度量,并提供了关于对称性和异常值的信息。
****(二)散点图:

散点图是一种数学图表,使用笛卡尔坐标来显示一组数据的两个变量的值。数据显示为点的集合,每个点的一个变量的值决定水平轴上的位置,另一个变量的值决定垂直轴上的位置。远离总体的点可以称为异常值。
(三)Z 值:
Z 得分是标准偏差的有符号数,通过它,观察值或数据点的值高于正在观察或测量的平均值。在计算 Z 值时,我们会重新调整数据的比例并使其居中,同时寻找离零太远的数据点。这些离零太远的数据点将被视为异常值。在大多数情况下,使用阈值 3 或-3,即如果 Z 分值分别大于或小于 3 或-3,则该数据点将被识别为异常值。
Python 代码:
z = np.abs(stats.zscore(dataset))
一旦我们得到 z 分数,我们就可以在此基础上拟合我们的数据集。
Python 代码:
dataset = dataset[(z < 3).all(axis=1)]
(四)IQR:
四分位数间距(IQR)是统计离差的一种度量,等于第 75 个和第 25 个百分位数之间的差值,或者上四分位数和下四分位数之间的差值。
IQR = Q3 Q1。
****Python 代码:
Q1 = dataset.quantile(0.25)Q3 = dataset.quantile(0.75)IQR = Q3 — Q1
一旦我们得到了 IQR 分数,下面的代码将给出一个包含真值和假值的输出。值为假的数据点表示值有效,值为真表示存在异常值。
Python 代码:
print(boston_df_o1 < (Q1–1.5 * IQR)) |(boston_df_o1 > (Q3 + 1.5 * IQR))
d)通过情节理解关系和新见解:
通过可视化数据集,我们可以获得数据中的许多关系。让我们来看一些技巧,以便了解其中的洞见。
- 柱状图
- 热图
(一)直方图:

直方图是快速评估概率分布的一个很好的工具,几乎任何观众都能很容易理解。Python 为构建和绘制直方图提供了一些不同的选项。
(二)热图:

热图程序显示了定量变量在 2 个分类因素的所有组合中的分布。如果这两个因素中有一个代表时间,那么这个变量的演变就可以很容易地用图来观察。渐变色标用于表示定量变量的值。两个随机变量之间的相关性是一个从-1 到 0 到+1 的数字,分别表示强的反比关系、无关系和强的正关系。
EDA 用的工具有哪些?
有很多开源工具可以自动执行预测建模的步骤,如数据清理、数据可视化。其中一些也很受欢迎,如 Excel,Tableau,Qlikview,Weka 和许多除了编程之外的其他软件。
在编程上,我们可以用 Python,R,SAS 来完成 EDA。Python 中的一些重要包是:
- 熊猫
- Numpy
- Matplotlib
- 海生的
- 散景

如果我们不做 EDA 会怎么样?
许多数据科学家将急于进入机器学习阶段,有些人要么完全跳过探索过程,要么只做很少的工作。这是一个具有多种含义的错误,包括生成不准确的模型,生成准确的模型但基于错误的数据,在数据准备中没有创建正确类型的变量,以及由于仅在生成模型后才意识到数据可能有偏差,或有异常值,或有太多缺失值,或发现某些值不一致而导致资源使用效率低下。
在我们的旅行示例中,在没有对该地点进行任何预先探索的情况下,您将在旅行中面临许多问题,如方向、成本、旅行,这些都可以通过 EDA 来减少,这同样适用于机器学习问题。
谢谢
Python 中的探索性数据分析教程
了解数据的最佳方式是花时间去探索它。
简介
每个数据科学家必须掌握的最重要的技能之一是正确探索数据的能力。为了确保收集的数据和执行的分析的完整性,彻底的探索性数据分析(EDA)是必不可少的。本教程中使用的示例是对历史 SAT 和 ACT 数据的探索性分析,以比较不同州的 SAT 和 ACT 考试的参与情况和表现。在本教程结束时,我们将获得关于美国标准化考试潜在问题的数据驱动的洞察力。本教程的重点是演示探索性的数据分析过程,并为希望练习使用数据的 Python 程序员提供一个示例。为了进行这项分析,我在 Jupyter 笔记本上检查并处理了包含 2017 年和 2018 年 SAT 和 ACT 数据的可用 CSV 数据文件。通过构造良好的可视化和描述性统计来探索数据是熟悉您正在处理的数据并根据您的观察制定假设的一种很好的方式。
探索性数据分析(EDA)目标
1)快速描述数据集;行数/列数、缺失数据、数据类型、预览。
2)清理损坏的数据;处理丢失的数据、无效的数据类型、不正确的值。
3)可视化数据分布;条形图、直方图、箱线图。
4)计算和可视化变量之间的相关性(关系);热图。
数据驱动方法的优势
众所周知,标准化测试程序多年来一直是一个有争议的话题。通过我自己的初步研究,我很快发现了 SAT 和 ACT 考试的一些明显问题。例如,有些州只要求 SAT,只要求 ACT,两种考试都要求,或者要求每个学生参加他们选择的一种标准化考试。由各州设定的标准化考试预期之间的这种可变性应被视为各州之间考试记录(如参与率和平均成绩)偏差的重要来源。研究可能很重要,但采用数据驱动的方法来支持基于定性研究的主张(假设)是至关重要的。采用数据驱动的方法可以验证以前提出的主张/假设,并基于对数据的彻底检查和处理开发新的见解。
入门
请随意下载我的代码和/或数据,跟随教程,链接到我的 GitHub:https://github.com/cbratkovics/sat_act_analysis
使用 Python 探索数据的第一步是确保导入正确的库。
对于这个介绍,我们需要的库是 NumPy、Pandas、Matplotlib 和 Seaborn。导入库时,可以为其指定一个别名,以减少使用每个库的属性所需的键入量。下面的代码显示了必要的导入语句:

使用 Pandas 库,您可以将数据文件加载到一个容器对象中,称为数据框。顾名思义,这种类型的容器是一个框架,它保存使用 Pandas 方法 pd.read_csv()读入的数据,该方法专用于 csv 文件。每个 CSV 文件到 Pandas 数据框对象的转换如下所示:

探索数据&清理损坏的数据
在执行探索性分析时,了解您正在处理的数据至关重要。幸运的是,数据框对象具有许多有用的属性,使这变得很容易。比较多个数据集中的数据时,标准做法是使用属性检查每个数据框中的行数和列数。形状,像这样:

Note that number of rows is on the left and number of columns is on the right; (rows, columns).
我们关于数据的第一个问题是 ACT 2017 和 ACT 2018 数据框架之间的维度不一致。让我们使用更好地查看数据。head() 方法,该方法显示 Pandas 数据框对象中每一列的前五行,前五个索引值。我将以 2018 年法案为例:

在预览了其他数据框的前五行之后,我们可以推断出在如何将状态输入到数据集中可能存在问题。由于美国有 51 个州,因此 ACT 2017 和 ACT 2018“州”列中很可能存在不正确和/或重复的值。然而,在处理数据时,我们无法确定这种推断。我们需要检查有问题的数据来找出确切的问题。首先,让我们使用检查 2018 ACT 数据中“State”列的值。value_counts()方法,该方法以降序显示数据框中每个特定值出现的次数:

请注意,值“缅因州”在 2018 年 ACT 数据中出现了两次。下一步是确定值是重复的还是数据输入不正确。我们将使用一种称为屏蔽的技术来实现这一点,它允许我们检查数据框中满足指定标准的行。例如,让我们使用屏蔽来查看 2018 ACT 数据中“州”值为“缅因州”的所有行:

现在,损坏的值已被确认为重复条目。因此,我们可以使用简单地删除该值。drop() 方法,并重置数据帧索引,使用。reset_index() 方法,解决问题:

注意:act_18.index[52]指定要删除的索引,inplace=True 保存对原始数据框对象的更改,而不将其重新分配给原始数据框对象(act_18)。
现在我们已经解决了 ACT 数据帧之间行数不一致的问题,但是 SAT 和 ACT 数据帧之间的行数不一致的问题仍然存在(ACT 为 52 行,SAT 为 51 行)。为了比较各州之间的 SAT 和 ACT 数据,我们需要确保每个州在每个数据框中得到同等的表示。这是您发挥创造力的机会,您可以想出一种方法来检索数据框之间的“State”列值,比较这些值,并显示结果。我的解决方案显示在下面的函数中:

函数 compare_values() 从两个不同的数据框中提取一列,临时存储这些值,并显示只出现在其中一个数据集中的任何值。让我们看看在比较 2017 年和 2018 年的 SAT/ACT“State”列值时它是如何工作的:

好吧!现在,我们知道需要移除两个 ACT 数据框中“州”列中的“国家”值。这可以通过使用我们用来定位和移除 ACT 2018 数据帧中重复的“Maine”值的相同代码来实现:

然而,在 SAT 2018 和 ACT 2018 数据中,关于值“华盛顿特区”和“哥伦比亚特区”还有另一个错误。我们需要确定一个一致的值来表示四个数据框中的华盛顿特区/哥伦比亚特区。这两个选项之间的选择并不重要,但选择数据框中出现率最高的名称是一个好习惯。由于 SAT 2017 和 ACT 2017“州”数据之间的唯一区别是“国家”值,我们可以假设“华盛顿特区”和“哥伦比亚特区”在两个数据框的“州”列中是一致的。让我们使用屏蔽技术来检查值“华盛顿特区”和“哥伦比亚特区”中的哪一个在 ACT 2017“州”列中:

现在,我们正式拥有足够的证据来证明在 ACT 2018 数据框中用“哥伦比亚特区”替换“华盛顿特区”值的合理性。使用熊猫数据帧。replace() 方法,我们可以做到这一点。然后,我们可以使用 compare_values 函数确认我们的更改是成功的:

成功!现在,每个数据框中各状态的值是一致的。现在,我们可以解决 ACT 数据集之间列数不一致的问题。让我们使用比较每个数据帧中的列名。列属性:

Note that adding the “\n” expression prints a new line after the output of print() is displayed.
由于此分析的目标是比较 SAT 和 ACT 数据,我们越能相似地表示每个数据集的值,我们的分析就越有帮助。因此,我将在每个数据框中只保留“州”、“参与”、“总计”(仅限 SAT)和“综合”(仅限 ACT)。请注意,如果你的分析目标不同,例如比较 2017 年和 2018 年的 SAT 成绩,保持每个成绩类别(如数学)的数据是必不可少的。与手头的任务保持一致,我们可以使用删除多余的列。法降(),如是:

现在数据框都有相同的尺寸!不幸的是,仍有许多工作要做。让我们看看是否有数据丢失,并查看所有数据框的数据类型:

Check for missing data using .isnull().sum()

Check data types with .dtypes
好消息是数据中不存在不存在的值。坏消息是数据类型中的错误,特别是每个数据框中的“参与”列是对象类型,这意味着它被视为字符串。这是有问题的,因为在探索数据时,许多有用的可视化需要数值类型变量才能起作用,例如相关热图、箱线图和直方图。在两个 ACT 数据帧的“复合”列中可以看到同样的问题。我们来看看 SAT 2018 和 ACT 2018 数据的前五行:

First 5 rows of SAT 2018 data.

First 5 rows of ACT 2018 data.
你可以看到“复合”和“参与”应该是浮动类型。良好的做法是保持您想要比较的数字数据的类型一致,因此在不损害数据完整性的情况下将“Total”转换为 float 类型也是可以接受的(integer = 1166,float = 1166.0)。这种类型转换的第一步是从每个“Participation”列中删除“%”字符,这样就可以将它们转换成浮点数。下一步是将所有数据转换成浮点数,除了每个数据帧中的“State”列。这可能是乏味的,给我们另一个很好的机会来创建一个函数来节省时间!我的解决方案显示在下面的函数中:

Note: https://stackabuse.com/lambda-functions-in-python/ is a great resource to learn more about using lambda functions in Python 3.
是时候让这些功能发挥作用了。首先让我们使用 fix_participation() 函数:

现在我们可以使用 convert_to_float() 函数转换所有列的数据类型:

但是等等!运行 convert_to_float() 函数应该会抛出一个错误。根据您使用的 IDE,错误消息可能非常有用。在 Jupyter Notebook 中,该错误清楚地将您导向 ACT 2017 数据框中的“复合”列。若要更仔细地查看这些值,请使用。 value_counts() 方法:

看起来我们的罪魁祸首是数据中的一个“x”字符,很可能是在将数据输入原始文件时输入错误的结果。要将其移除,请使用。strip() 方法在内。应用()方法,像这样:

太好了!现在尝试再次运行这段代码,所有数据都将是正确的类型:

开始可视化数据之前的最后一步是将数据合并到单个数据框中。为此,我们需要重命名每个数据框中的列,以描述它们各自代表的内容。例如,SAT 2018 中“参与”栏的一个好名字应该是“sat_participation_17”。当数据被合并时,这个名称更具描述性。另一个注意事项是下划线符号,用于消除访问值时繁琐的空格错误,小写约定用于加快键入速度。数据的命名约定由开发人员决定,但是许多人认为这是一个好的实践。您可以像这样重命名列:

为了合并没有错误的数据,我们需要对齐“state”列的索引,以便在数据帧之间保持一致。我们通过按每个数据框中的“状态”列排序,然后从零开始按顺序重置索引值来实现这一点:

最后,我们可以合并数据。我没有一次合并所有四个数据帧,而是一年一次合并两个,并确认每次合并都没有出现错误。下面是每次合并的代码:

2017 SAT & ACT merged data frame.

2018 SAT & ACT merged data frames.

Final merge of data frames.
清理完数据后,最好保存它,这样就不必再次清理数据。使用 Pandas 的 pd.to_csv()方法:

Setting index = False saves the data without its index values.
是时候可视化数据了!现在,我们可以使用 Matplotlib 和 Seaborn 来仔细查看我们干净的组合数据框架。当检查直方图和箱线图时,我将着重于可视化参与率的分布。检查热图时,将考虑所有数据之间的关系。
可视化数据分布— Seaborn 直方图

直方图表示数据集中指定范围内数字数据值出现的频率(例如,数据中有多少值落在 40%-50%的范围内)。从直方图中,我们可以注意到,在 2017 年和 2018 年,有更多的州的 ACT 参与率为 90%-100%。相反,2017 年和 2018 年 SAT 的参与率为 0%-10%的州更多。我们可以推断,90%-100% ACT 参与率的州的较高频率可能是由一些要求采取 ACT 的法规引起的。
可视化数据分布— Matplotlib 盒图

箱线图表示数据的分布,包括最小值、最大值和四分位间距(IQR)。四分位数范围由第一个分位数、中间值和第三个分位数组成。根据上面的方框图,我们可以看到,从 2017 年到 2018 年,SAT 参与率整体上升。另一个我们可以注意到的是 2017 年到 2018 年 ACT 参与率的一致性。这就提出了一个问题,为什么 SAT 的参与率总体上是上升的,尽管 ACT 的参与率没有显著变化。
计算并可视化相关性——Seaborn 热图

中更强的关系由热点图中更接近负值或正值的值表示。较弱的关系由更接近于零的值表示。正相关变量,即在零和正一之间相关的值,表示一个变量随着另一个变量的增加而增加。负相关变量,在负 1 和零之间具有相关性的值,表示一个变量随着另一个变量的增加而减少。需要进一步考察的关联性强的变量包括 2017 年 SAT 参与情况和 2018 年 SAT 参与情况,2017 年 ACT 综合成绩到 2017 年 ACT 参与情况,2018 年 ACT 参与情况和 2018 年 SAT 参与情况。还有更多的关系需要进一步研究,但这些都是引导研究为什么这些关系存在的良好起点。
结论
全面的探索性数据分析可确保您的数据干净、可用、一致且直观。请记住,没有干净的数据这种东西,因此在开始处理数据之前探索数据是一种很好的方式,可以在数据分析过程开始之前为其增加完整性和价值。通过对数据的深入研究来指导外部研究,你将能够有效且高效地获得可证明的见解。
探索性数据分析——用数据阐明故事
在本文中,我们将探讨如何挖掘数据中隐藏的模式。
我发现 Kaggle 上的 房价竞赛是磨练你的分析技能并开始像数据科学家一样思考的好地方。对于一些背景,请务必阅读艾姆斯住房数据文档。这 80 个解释变量似乎是典型的影响房价的因素。然而,有些变量对销售价格的影响比其他变量更大,而有些变量对销售价格没有任何影响。**

我们将从研究整体数据开始,使用描述和信息方法。正如您将看到的,数据集有 80 列。要获得一些关于变量的上下文,请参考数据描述文件。目标变量是销售价格,其右偏如下:

为了使数据正常化,我们需要取销售价格的对数。此外,Kaggle 问题度量表明了观察价格和预测价格之间的 RMSE。在记录日志时,我们注意到下图:

谈到变量,我们看到有数字和分类的特点。记下不同的特征是个好主意。
#Numeric Features
numeric_features = train.select_dtypes(include=[np.number])
numeric_features.dtypes#Categorical Features
categoricals = train.select_dtypes(exclude=[np.number])
print(categoricals.dtypes)
categoricals.describe()

There are 43 categorical variables and the rest are numeric
我们将很快开始研究变量,但在此之前,我们应该看看训练数据集中的空值。
sns.heatmap(train.isnull(), cbar=False)

PoolQC and Alley have maximum missing values
请注意,PoolQC 数据可能会丢失,因为大多数房屋中可能没有游泳池。通过观察 PoolArea 列中的数据,可以再次检查这一事实。几乎所有列的值都为零。因此,我们可以有把握地假设,这两列对于预测销售价格可能不是很重要。
但是,如果您查看变量 alley,丢失的数据表示没有 Alley 访问。我们将很快看到小巷如何影响销售价格。
下图给出了所有变量之间的汇总关系:
corr = numeric_features.corr()
plt.subplots(figsize=(20, 9))
sns.heatmap(corr, square=True)

注意我们关于 PoolArea 的假设是如何被证明是正确的。与销售价格的相关性实际上几乎为零!
MSSubclass 实际上是一个分类变量,但是因为分类是数字,所以它被错误地标记为数字。如果有人不仔细阅读数据描述文本,就很容易忽略这一事实!
此外,一些变量似乎显示多重共线性,即,相互关联(用白色方块表示)。
**TotRoomsAbvGrd & GrLivArea**- Generally a big house will have a bigger living room and more number of rooms, hence data seems consistent**GarageArea & GarageCars**- This sounds logical, more garage area will translate to more car capacity, and vice versa**1stFloorSF & TotalBsmtSF**- Ideally basement will be the same size as 1st floor, and the reverse is also true in most cases.**GarageYrBlt & YearBuilt**- Building a garage will depend on the house being built, but not vice versa! Hence this warrants some investigation!
在绘制 year build 与 GarageYrBlt 的散点图时,请注意,在某些情况下,year build 大于 GarageYrBlt!这显然是数据输入错误。

我们将在特征工程中处理时间变量。
转到其他变量,我实际上绘制了每一个变量,以检查分布情况以及它们如何影响销售价格。建议检查哪些是影响销售价格的最重要的变量。最重要的变量是(忽略销售价格):
print(corr[‘SalePrice’].sort_values(ascending=False)[:5],’\n’)SalePrice 1.000000
OverallQual 0.790982
GrLivArea 0.708624
GarageCars 0.640409
GarageArea 0.623431
在绘制 GrLivArea 对销售价格的对数时,我发现:

总的来说,它显示出增加的趋势,但是明显存在一些异常值,在继续进行数据训练之前必须去除这些异常值。
如果不好好研究数据,就不可能找到异常值,因此,尽管很乏味,我还是建议在为机器学习准备数据之前探索每一个变量。
我们已经停在可变的巷子里做进一步的调查。让我们看看它是否影响销售价格。在绘制小巷与销售价格的箱线图时,我们发现:

看起来,铺设的小巷肯定比碎石路要价更高。因此,没有小巷通道的房子可能会比碎石房价格更低。这绝对是一个重要的专栏,您会希望保留它。
同样,在探索分类变量时,您会发现许多变量的数据受一个类别支配。例如,在用计数图检查组合数据(训练+测试)中外部类型的优势时,我发现:

根据数据描述,大多数房屋都有“TA”,这意味着典型条件。现在绘制一个 ExterCond 与销售价格的箱线图,我们得到下图:

从该图可以清楚地看出,“TA”、“Gd”和“Ex”房屋最终具有相似的销售价格,这意味着它们并没有真正影响我们的目标变量。这听起来合乎逻辑。我们听说过影响销售价格的外部材料的现状吗?
但是我们确实经历了位置对房价的影响,这一点在下图中得到证实:

总之,在接近 EDA 时,一个人需要的基本行为品质是好奇心。发现空值、异常值或不相关的特征只是这种质量的结果。本文旨在开始思考过程,这将使你成为一名成功的数据科学家。
请继续关注我关于数据争论/特征工程以及最终机器学习的下一篇博客。
使用 Pandas 进行探索性数据分析

Image by Author
在本文中,我们将重点关注'巴西亚马逊森林火灾数据集',并使用
*Pandas*库执行一些基本分析,使用*Matplotlib*和*Seaborn*库可视化数据。
andas 是 Python 中最强大的工具,它允许我们对数据集做任何事情,例如分析数据、组织、清理、排序、过滤、聚合、计算等等!,这使得数据分析非常容易。

Pandas — Python’s most powerful library for Data Analysis…[Image by Author]
在这篇文章中,我们将回顾“亚马逊火灾数据集”(从 Kaggle.com 下载),并探索 pandas 的功能,通过做一些练习,然后使用 python 的可视化库可视化数据,这些功能将帮助我们进行探索性数据分析(EDA)。
首先,我们来深入挖掘一下我们的 Kaggle 数据集 - 巴西森林火灾 (amazon.csv),你可以在这里下载。
对于那些不了解 Kaggle.com 的人,让我给你们一些建议..
Kaggle 是一个最受数据科学家和机器学习者欢迎的在线社区,他们可以参加分析比赛,建立预测模型,并且是用户寻找有趣数据集的好地方。我们可以找到各种数据,包括图像数据集、CSV、时间序列数据集等。,可免费下载。
这个数据集是关于什么的?
该数据集包含 10 年的数据,其中包含了 1998 年至 2017 年期间亚马逊雨林(巴西各州)发生的起森林火灾的总数。
亚马逊地区幅员辽阔,横跨八个快速发展的国家:巴西、玻利维亚、秘鲁、厄瓜多尔、哥伦比亚、委内瑞拉、圭亚那、苏里南和法属圭亚那。亚马逊森林的大部分包含在巴西境内,其中 60%是雨林。

Amazon rainforest wildfires[Image by Author]
现在,让我们开始我们的熊猫练习来探索这个数据集并得出一些见解。
让我们遵循以下步骤:
- 首先,我们将导入所有需要的 python 库。
- 从 kaggle 下载数据集,保存到我们的桌面,并使用 python 将其提取到 Jupyter 笔记本。
- 分析几个问题,将数据可视化。
在导入我们的库之前,让我们使用 pip install 命令将它们安装到我们的 python Jupyter 笔记本或任何其他我们进行编码的 python 接口中。
Pandas : pip install pandas
Numpy : pip install numpy
Matplotlib : pip install matplotlib
Seaborn : pip install seaborn
让我们使用 pandas 读取 csv 文件,并将其保存到数据帧中

现在,让我们快速检查数据集的前 10 行

数据集描述:
- 第 1 栏-【年份】:森林火灾发生的年
- 第 2 列-“州”:巴西州
- 第 3 栏-【月份】:森林火灾发生的月份
- 第 4 栏-"数字":报告的森林火灾数量
- 第 5 栏-“日期”:报告森林火灾的日期
方法为我们提供了数据集的快速概览,如行和列的总数、数据类型和空值的数量(如果有的话)

从上面的输出可以清楚地看到,我们总共有 6454 行(包括标题),5 列,没有空字段(这对于我们的分析来说是一个好兆头🙂)
让我们使用describe() 方法来看看关于我们的数据集(数值)的统计摘要

数据清理:
清理数据是第一步,也是最重要的一步,因为它可以确保数据质量,为可视化做好准备。经过全面检查后,我们从上面的数据集中看到,浮点型的“数字”列(报告的森林火灾数量)具有小数点值,例如 18.566、14.59、11.068……,这意味着该值没有四舍五入,对于报告的森林火灾数量没有任何意义。因此,让我们使用 round 函数清理这些数据,并将数据存储回我们的主数据帧。
首先让我们对样本数据应用round()函数…
之前:

之后:

现在我们将使用 numpy 对整个数据集应用round()方法

‘number’ column values are now corrected
练习 1 : 检查“年”列的最小值和最大值

练习 2 : 找出“英亩州”的火灾总数,并基于每个“年度”可视化数据
在开始这个练习之前,我想深入了解 Pandas 中一个叫做'布尔索引'的重要概念,它将在处理基于数据实际值的数据子集时非常有帮助。
布尔索引:
顾名思义,当我们希望根据某些条件从数据帧中提取数据子集时,就会使用布尔索引。我们还可以有多个条件,这些条件可以分组放在括号中,并应用于数据帧。
让我们看看下面的例子,看看熊猫布尔索引是如何工作的。在我们的示例中,我们将使用雇员及其工资的数据框架:
import pandas as pd
df = pd.DataFrame({'EmployeeName': ['John','Sam','Sara','Nick','Bob','Julie'],
'Salary':[5000,8000,7000,10000,3000,5000]})

我们来查一下哪个员工的工资是 5000 。首先,我们将执行矢量化布尔运算,生成一个布尔序列:
salary_bool = df['Salary'] == 5000

现在,我们可以使用这个序列来索引整个数据帧,留下只对应于薪水为 5000 的雇员的行
salary_5000 = df[salary_bool]
*# that means it returns only those rows which are 'True'*

我希望现在你对布尔索引的工作原理有所了解..你可以在这里 找到更多关于布尔索引教程 的信息..
现在,让我们开始我们的实际练习,即找出“英亩”州的森林火灾总数:

从上面的输出可以清楚地看到,“Acre”州报告的火灾总数为 18463 。是的,这个第一次太难理解了:)。所以让我来破解这段代码,一步一步解释。
步骤 1 : 让我们使用布尔索引来仅获取‘Acre’状态子集,并将其分配给名为‘Amazon _ Acre’的变量
amazon_acre = amazon['state'] == 'Acre'
“amazon_acre”将根据我们的条件为我们生成一个序列,显示每行的真和假。
第 2 步:让我们使用这个系列来索引整个数据集,并将其分配给名为“amazon_acre_data”的变量
amazon_acre_data = amazon[amazon_acre] # total 239 entries

First five rows of amazon_acre_data
第 3 步:接下来,我们只显示上面数据集中的“数字”列
amazon_acre_number = amazon_acre_data['number'] #这将只显示‘数字’列值。
第四步:现在我们可以使用sum()函数对amazon_acre_number 变量求火灾总数。

给你。!!当我们第一次试验数据时,打破代码总是一个最佳实践。但是,最终为了获得更好的编程技能,我们应该致力于减少代码行。
现在让我们使用groupby()方法在“年”列上得到每年的火灾总数。

在这里的输出中,我们看到“year”被标记为索引,“number”被标记为列。为了使数据可视化更加简单,我们可以使用reset_index()方法将索引作为列来处理。

上述数据集的可视化:

Importing libraries
Matplotlib是 python 的数据可视化库,可以让我们将数据可视化,对于简单的情节非常容易上手。Matplotlib 由几个图组成,如线形图、条形图、散点图、直方图等。,推荐你去探索官方 Matplotlib 网页 了解更多信息。
Seaborn 是 python 最流行的统计可视化库,构建在 Matplotlib 之上。查看 seaborn 官方 网页 了解所有不同类型的 seaborn 地块。
让我们使用matplotlib和seaborn(barplot)来可视化“英亩火灾年份”数据集

More number of fires are reported in 2002[Image by Author]
注意: plt.figure()创建一个 figure 对象,我们这里用来自定义图表的大小。
练习 3 : 找出所有州的火灾总数
为此,让我们使用“州”栏上的groupby(),找出火灾总数。


Image by Author
从上图可以明显看出,大多数森林火灾发生在马托格罗索州,其次是帕莱巴州和圣保罗州。
练习 4 : 找出 2017 年的火灾总数,并根据每个“月”可视化数据

Image by Author
练习 5 : 找出火灾发生的平均次数

练习 6 : 找出“十二月”月份发生火灾的州名

这就是这篇文章的全部内容…你现在应该对 pandas、matplotlib 和 seaborn 有了很好的了解,并且知道如何使用它们进行数据准备和数据可视化。
嗯,谢谢你看我的第一篇文章:)。我希望这篇文章对你有用,如果你有任何问题,请随时在下面的评论区发表评论,并给我一些建议和意见🙂
探索性数据分析(可视化)

Visuals, graphs and more visuals!
继我之前关于进行探索性数据分析时要做的计算的帖子之后,在这篇博文中,我将讨论如何使用 visual 来更好地探索我们的数据。
这里重申一下,做好 EDA 的两个主要好处是:
- 对数据质量有很好的理解。我们需要高质量的数据来建立好的模型。我告诉我的大多数学生和实习生,数据从来都不是干净的。我们只能让它达到我们可以使用的质量水平。
- 快速了解项目。了解监督学习的潜在驱动因素或可能的模式。这些见解可以立竿见影,从其他利益相关者那里获得更多的认同。
假设:在这个讨论中,我假设读者对变量有一些背景知识(理解什么是分类变量或连续变量)和基本的汇总统计,如均值、中值、众数和统计分布。
在数据的可视化探索中,我们关注两件事:
1 —一个单变量的值分布。
2—两个变量之间的关系。
1 —单个变量的值分布
分类变量
为了探究分类变量,我们可以绘制一个频率条形图。

Created from Tableau Public (Superstore.xls)
因此,当我们探索单个分类变量时,我们会寻找以下内容:
a.最受欢迎和最不受欢迎的类别是什么?
b.有没有不希望出现的值?
c.某些类别出现的频率是否低于/高于预期?
d.有没有不应该存在的分类值?
这些问题旨在检查数据质量,以及数据是否能够“可信”地反映现实。
连续变量

Source: Wikipedia
直方图是我用来理解连续变量分布的直观工具。在试图创建直方图之前,需要首先对连续变量进行分箱(即创建箱)。例如,年龄是连续的,我们可以将其分为 0–5、5–10、10–15……一旦我们将其分类,我们就可以绘制该分类中潜在价值的频率。
宁滨实际上是一门艺术和科学,如果你不仔细设置垃圾桶的宽度,你可能会错过重要的信息。例如,当仓宽度较小时,分布可能显示为双峰(2 个或更多个模式),但是当仓宽度较大时,它变成单峰。因此,仔细选择你的箱子宽度,最好从较小的箱子宽度开始。
从视觉上看,我们正在寻找偏斜度和峰度。偏斜度非常重要,尤其是当您打算将其用作回归模型的要素或目标时,因为假设要素和目标呈正态分布,以获得系数/参数的蓝色(最佳线性无偏估计)。绘制直方图可以更好地规划以后的数据清理。
2 —两个变量之间的关系
绝对与绝对
为了理解两个分类变量之间的关系,即哪些独特的组具有最大的大小,我们可以使用热图,其中每个分类变量作为行和列,每个组的频率由矩形或正方形的大小表示。下面的例子:

Created from Tableau Public (Superstore.xls)
您询问的关于热图的问题类似于您询问的关于频率条形图的问题(如上所述)。这是为了了解不同分类值的相互作用,以及所呈现的数字是否有意义,如果没有意义,其原因是什么,以及原因是否合理。
通常,通过提出正确的问题并将其与预期相匹配,可以获得更多的非数据发现,如营销活动何时进行,以及谁是上个月的目标市场等。你可以从中发现很多关于你的业务。
连续 vs 连续

Source: Wikipedia
散点图是观察两个连续变量之间关系的很好的可视化工具。你要寻找的是数据点在平面/图形中的位置。例如,你问的问题是:
a.数据点在二维平面上是如何分布的?它们是否形成一种模式/线条?
b.这两个连续变量之间有什么样的关系?积极还是消极?线性还是非线性(二次或三次)?
c.它们有集群/组吗?它们是截然不同、相距甚远还是非常接近?这些集群有什么特点?
毫无疑问,我们可以使用相关性来找出两个连续变量是正相关还是负相关,但如果不看散点图,它永远不会揭示关系的全部细节。
散点图的另一个优点是它允许我们人类消化大量的数据。假设用于创建上述散点图的数据又增加了 5000 个观察值,因此我们在上述散点图中添加了另外 5000 个数据点。我们中的大多数人仍然能够辨别两个连续变量之间是否存在关系,以及这两个变量之间的关系。
连续与分类

Source: Wikipedia
为了查看连续变量和分类变量之间的关系,我们有盒图来帮助我们。可以提出的问题有:
a.哪个类别的均值/中值最高?
b.哪一类是正态分布,哪一类不是?
c.哪一类的范围和分布更广?
d.哪个类别有异常值?
e.每个类别的分布(左偏或右偏)?
通过大量的实践,盒状图变得更容易阅读和解释,因此对于那些刚开始的人来说,这是一个需要克服的小障碍。阅读和解释更具挑战性的箱线图是那些具有许多独特分类值的箱线图。这是箱线图变宽的地方,并且很难在两个分类值/组之间进行比较。建议使用过滤器使箱线图“更小”,以便于比较。
结论
写这两篇关于探索性数据分析(EDA)、非可视化和可视化的帖子的目的,是为了帮助任何希望在 EDA 方面做得更好的人,以便他们可以建立对他们的组织有用的健壮的机器学习模型。
我希望这篇文章对你有用。也欢迎反馈,因为我希望改进我自己的 EDA 过程。
祝所有读者有一个有趣的数据科学/人工智能学习之旅。请访问我的其他博客文章和 LinkedIn 个人资料。谢谢大家!
补充说明:我已经建立了自己的网站,作为我 2020 年新年计划的一部分,最新消息请访问这里。感谢支持!
熊猫的探索性数据分析

Pandas provides high-performance, easy-to-use data structures and data analysis tools for the Python
作为一名数据科学家,我每天都使用 pandas,我总是对它的众多功能感到惊讶。探索性数据分析是一种分析数据集以总结其主要特征的方法,通常采用可视化方法。许多复杂的可视化可以用熊猫来实现,通常不需要导入其他库。要运行示例,请下载本 Jupyter 笔记本。
探索性数据分析是一种分析数据集以总结其主要特征的方法,通常采用可视化方法
这里有几个你可能会感兴趣的链接:
- [Labeling and Data Engineering for Conversational AI and Analytics](https://www.humanfirst.ai/)- [Data Science for Business Leaders](https://imp.i115008.net/c/2402645/880006/11298) [Course]- [Intro to Machine Learning with PyTorch](https://imp.i115008.net/c/2402645/788201/11298) [Course]- [Become a Growth Product Manager](https://imp.i115008.net/c/2402645/803127/11298) [Course]- [Deep Learning (Adaptive Computation and ML series)](https://amzn.to/3ncTG7D) [Ebook]- [Free skill tests for Data Scientists & Machine Learning Engineers](https://aigents.co/skills)
上面的一些链接是附属链接,如果你通过它们购买,我会赚取佣金。请记住,我链接课程是因为它们的质量,而不是因为我从你的购买中获得的佣金。
要升级您的熊猫游戏,请参见:
从提示和技巧,如何不指南到与大数据分析相关的提示,熊猫文章的精选列表。
medium.com](https://medium.com/@romanorac/pandas-data-analysis-series-b8cec5b38b22)
设置
让我们创建一个有 5 列 1000 行的熊猫数据帧:
- a1 和 a2 具有从正态(高斯)分布中抽取的随机样本,
- a3 具有从一组(0,1,2,3,4)中随机分布的整数,
- y1 具有在从 0 到 1 的对数标度上均匀间隔的数字,
- y2 从一组(0,1)中随机分配整数。
mu1, sigma1 **=** 0, 0.1
mu2, sigma2 **=** 0.2, 0.2
n **=** 1000df **=** pd**.**DataFrame(
{
"a1": pd**.**np**.**random**.**normal(mu1, sigma1, n),
"a2": pd**.**np**.**random**.**normal(mu2, sigma2, n),
"a3": pd**.**np**.**random**.**randint(0, 5, n),
"y1": pd**.**np**.**logspace(0, 1, num**=**n),
"y2": pd**.**np**.**random**.**randint(0, 2, n),
}
)
有机器学习背景的读者会认可其中 a1、a2、a3 代表属性,y1、y2 代表目标变量的记法。简而言之,机器学习算法试图在属性中找到模式,并使用它们来预测看不见的目标变量——但这不是这篇博客文章的主要焦点。我们在数据帧中有两个目标变量(y1 和 y2 )(一个二进制变量和一个连续变量)的原因是为了使示例更容易理解。
我们重置索引,将索引列添加到数据帧中,以枚举行。
df**.**reset_index(inplace**=**True)

1.打印自定义
当我第一次开始使用熊猫时,绘图功能似乎很笨拙。我在这一点上大错特错,因为 pandas 公开了完整的 matplotlib 功能。
1.1 定制输出轴
Pandas plot 函数返回 matplotlib.axes.Axes 或它们的 numpy . n array,这样我们可以额外定制我们的绘图。在下面的示例中,我们向熊猫线图添加了一条水平红线和一条垂直红线。如果我们需要:
- 将平均线添加到直方图中,
- 在图上标出重要的一点等。
ax **=** df**.**y1**.**plot()
ax**.**axhline(6, color**=**"red", linestyle**=**"--")
ax**.**axvline(775, color**=**"red", linestyle**=**"--")

1.2 自定义输入轴
Pandas plot 函数也接受输入的轴参数。这使我们能够定制我们喜欢的情节。在下面的例子中,我们用不同类型的图创建了一个 2×2 的网格。
fig, ax **=** mpl**.**pyplot**.**subplots(2, 2, figsize**=**(14,7))
df**.**plot(x**=**"index", y**=**"y1", ax**=**ax[0, 0])
df**.**plot**.**scatter(x**=**"index", y**=**"y2", ax**=**ax[0, 1])
df**.**plot**.**scatter(x**=**"index", y**=**"a3", ax**=**ax[1, 0])
df**.**plot(x**=**"index", y**=**"a1", ax**=**ax[1, 1])

2.直方图
直方图是数字数据分布的精确表示。它是对连续变量概率分布的估计,由卡尔·皮尔逊【1】首先提出。
2.1 堆叠直方图
Pandas 使我们能够通过一次函数调用,在一个直方图上比较多个变量的分布。
df[["a1", "a2"]]**.**plot(bins**=**30, kind**=**"hist")

为了创建两个独立的图,我们设置了subplots=True。
df[["a1", "a2"]]**.**plot(bins**=**30, kind**=**"hist", subplots**=**True)

2.2 概率密度函数
概率密度函数(PDF)是一个函数,其在可能值集合中任何给定样本的值可以被解释为随机变量的值等于该样本【2】的相对可能性。换句话说,在随机变量的任何特定抽取中,两个不同样本的 PDF 值可用于推断随机变量与一个样本相比更有可能等于另一个样本。
请注意,在 pandas 中,有一个density=1参数,我们可以将其传递给hist函数,但使用它,我们不会得到 PDF,因为 y 轴不在从 0 到 1 的范围内,正如下面的图中所示。其原因在 numpy 文档中有解释:“注意,直方图值的总和将不等于 1,除非选择了宽度一致的条块;它不是一个概率质量函数。”。
df**.**a1**.**hist(bins**=**30, density**=**1)

为了计算一个变量的 PDF,我们使用一个hist函数的weights参数。我们可以在下图中观察到,y 轴的最大值小于 1。
weights **=** pd**.**np**.**ones_like(df**.**a1**.**values) **/** len(df**.**a1**.**values)
df**.**a1**.**hist(bins**=**30, weights**=**weights)

2.3 累积分布函数
累积直方图是一种映射,它计算直到指定条柱为止的所有条柱中的累积观察次数。
让我们为 a1 列制作一个累积直方图。我们可以在下图中观察到,大约有 500 个数据点的 x 小于或等于 0.0。
df**.**a1**.**hist(bins**=**30, cumulative**=**True)

归一化的累积直方图就是统计学中我们所说的累积分布函数(CDF)。CDF 是变量取值小于或等于 x 的概率。在下面的示例中,x <= 0.0 的概率为 0.5,x <= 0.2 的概率约为 0.98。请注意,densitiy=1参数对累积直方图起着预期的作用。
df**.**a1**.**hist(bins**=**30, cumulative**=**True, density**=**1)

3.单独组的图
Pandas 使我们能够可视化由指定列的值分隔的数据。按某些列分隔数据并观察分布中的差异是探索性数据分析中的常见步骤。让我们用 y2 列来分隔 a1 和 a2 列的分布,并绘制直方图。
df[['a1', 'a2']]**.**hist(by**=**df**.**y2)

由于数据是随机生成的,因此分离的分布之间没有太大差异。
我们可以对线图做同样的处理。
df[['a1', 'a2']]**.**plot(by**=**df**.**y2, subplots**=**True)

4.虚拟变量
一些机器学习算法不能处理多元属性,比如我们例子中的 a3 列。a3 列有 5 个不同的值(0、1、2、3、4 和 5)。要将一个多变量属性转换为多个二进制属性,我们可以对列进行二进制化,这样我们可以得到 5 个值为 0 和 1 的属性。
让我们看看下面的例子。a3 列的前三行的值为 2。所以 a3_2 属性的前三行标记为 1,其他所有属性都为 0。a3 中第四行的值为 3,因此 a3_3 为 1,其他所有行为 0,以此类推。
df**.**a3**.**head()

df_a4_dummy **=** pd**.**get_dummies(df**.**a3, prefix**=**'a3_')
df_a4_dummy.head()

get_dummies功能还使我们能够删除第一列,这样我们就不会存储多余的信息。当 a3_1,a3_2,a3_3,a3_4 都是 0 时,我们可以假设 a3_0 应该是 1,我们不需要存储它。
pd**.**get_dummies(df**.**a3, prefix**=**'a3_', drop_first**=**True)**.**head()

现在我们已经二进制化了 a3 列,让我们将它从 DataFrame 中移除,并向它添加二进制化的属性。
df **=** df**.**drop('a3', axis**=**1)df **=** pd**.**concat([df, df_a4_dummy], axis**=**1)

5.安装线路
有时我们想用一条直线来比较某个分布。确定月销售增长是否高于线性增长。当我们观察到我们的数据是线性的,我们可以预测未来的值。
Pandas(在 numpy 的帮助下)使我们能够对数据进行线性拟合。这是机器学习中的线性回归算法,尽量使直线与数据点的垂直距离尽可能小。这被称为“拟合数据线”
下图显示了 y1 柱。让我们画一条与 y1 列的数据点非常匹配的直线。
df**.**plot**.**scatter(x**=**'index', y**=**'y1', s**=**1)

下面的代码计算线性方程的最小二乘解。我们感兴趣的函数的输出是最小二乘解。
df['ones'] **=** pd**.**np**.**ones(len(df))
m, c **=** pd**.**np**.**linalg**.**lstsq(df[['index', 'ones']], df['y1'], rcond**=**None)[0]
一条线的方程是y = m * x + c。让我们用这个等式来计算最接近y1线的y线的值。
df['y'] **=** df['index']**.**apply(**lambda** x: x ***** m **+** c)df[['y', 'y1']]**.**plot()

在你走之前
在推特上关注我,在那里我定期发关于数据科学和机器学习的推特。

B2B 营销中的 Python 探索性数据分析
使用数据可视化深入研究 B2B 营销

这个项目的重点是使用 Python 对 B2B 营销进行探索性数据分析(EDA)。我们将使用 Olist 的数据作为例子,Olist 是一个连接巴西中小企业和顶级市场的电子商务平台。除了提供方法和代码,我还想讨论 B2B 营销的基础,以及这些来自 EDA 的见解如何帮助 Olist 做出更好的营销决策。 我的 GitHub 上提供了所有的 Python 代码。
介绍
Olist 是一个连接中小型企业和巴西市场的平台(Extra、Shoptime、Walmart、Submarino、。并帮助商家在这些市场销售。与一些国家不同,巴西快速增长的电子商务领域是由一些大型市场主导的,而不是由少数几个市场主导的(如美国的亚马逊和易趣)。因此,商家有动力在多个市场经营以最大化他们的收入。人力资源的限制是主要的棘手问题,商家希望使用 Olist 来管理其在不同市场的销售渠道,并简化库存管理和订单执行流程。

Olist’s business model
通过这种 B2B2C 模式,Olist 的营销团队有两个主要目标:
- 从卖家方面来说,他们想增加使用 Olist 平台的商家数量。
- 从买方来看,他们希望最大限度地提高这些市场上商家的电子商务销售额。
这个分析的范围更多地集中在 Olist 的卖方(B2B)方面。有了给定的数据集,我将进行探索性数据分析(EDA) ,这可以为 Olist 的 B2B 营销团队带来一些有用的见解。
B2B 的营销和销售流程:

B2B Marketing Funnel
数据特征
数据集是从 Kaggle 获得的。你可以在这里下载。
- 第一个数据集有 4 个变量,8000 个数据点。这些变量包括 MQL 标识(市场营销合格销售线索)、首次联系日期、获取销售线索的登录页面以及销售线索来源(将销售线索带到登录页面的渠道)。

- 第二个数据集包含 842 个观察值和 14 个变量。每个观察都是 Olist 的一个成功交易,它由商家的 mql_id、seller_id(在 Olist 平台中使用)、sdr_id 和 sr_id(负责该交易的销售开发代表和销售代表)、won_date、业务部门、lead_type、lead _ behaviour _ profile、business_type、declared_monthly_revenue 组成。其中,5 个变量的空值过多,无法为分析带来价值。


- 第三个数据集:通过 Kaggle,Olist 也捐赠了他们关于需求方的数据集。我们将利用这一点向 Olist 营销人员通报销售人员的表现,从而帮助他们改进 B2B 营销流程。
探索性数据分析
MQL 数量:MQL 数据提供时间为 2017 年 7 月至 2018 年 6 月,而韩元 MQL 数据提供时间为 2018 年 1 月至 2018 年 12 月。2017 年,Olist 营销团队产生的 MQLs 约为 400 MQLs/月。2018 年,他们将这一数字提升至每月 1000–1400 条线索。关于韩元 MQL,其峰值出现在 2018 年 5 月,有 200 个韩元机会。
#Figure 1
num_mql = mql.set_index(pd.to_datetime(mql[‘first_contact_date’]))
num_mql = num_mql.groupby(pd.Grouper(freq = “M”)).count().drop(axis =1, columns = [‘first_contact_date’,“landing_page_id”, “origin”])num_won = close.set_index(pd.to_datetime(close[“won_date”]))num_won = num_won.groupby(pd.Grouper(freq = “M”)).count().drop(axis = 1, columns = [“seller_id”, “sdr_id”, “sr_id”,“business_segment”, “lead_type”, “lead_behaviour_profile”, “has_company”, “has_gtin”, “average_stock”, “business_type”,“declared_product_catalog_size”,
“declared_monthly_revenue”, “won_date”])plt.figure(figsize = (8,6))
plt.plot(num_mql.index, num_mql, "-", label = "number of MQL")
plt.plot(num_won.index, num_won, "-", label = "number of won MQL")
plt.legend()
plt.title("Number of MQL", size = 15)
plt.savefig("NumMQL.png")

FIGURE 1
渠道:MQLs 大部分来自 organic_search 渠道,其次是直接流量和社交。Other、other _ publicities、referral 和 display 是给 Olist 带来最少 MQLs 的来源。有机搜索 MQL 在 2018–02 年显著增加,之后有所下降。这可能是大型活动/公关活动的结果。
#Figure 2
mql_origin = mql.groupby(‘origin’).agg({‘mql_id’:”count”});print(mql_origin)origin = list(mql_origin.index)plt.figure(figsize = (10,8))
fancy_plot = plt.subplot()
for i in origin:
channel = mql[mql[‘origin’] == i]
channel = channel.set_index(pd.to_datetime(channel[‘first_contact_date’]))
channel_agg = channel.groupby(pd.Grouper(freq = “M”)).count().drop(axis = 1, columns =[“first_contact_date”,
“landing_page_id”, “origin”])
fancy_plot.plot(channel_agg.index, channel_agg, “-o”, label = i)
fancy_plot.legend()
plt.title(‘Number of MQL by channels overtime’, size = 15)
plt.savefig(“channel-mql.png”)

FIGURE 2
这些通道的转换率各不相同。Organic_search、付费 _search 和直接流量是享有最高转化率的来源(分别为 12.5%、11.5%和 11%)。邮件、其他 _ 公众号和社交的转化率最低(分别为 3%、5%、5.5%)。这意味着 SEO 和 Google Adwords 是 Olist 最有效的营销渠道。这一结果似乎与说明 B2B 公司最有效营销渠道的几项调查有关。
[## 以下是对最有效的 B2B 营销渠道的行业分析[2017 年更新数据]
2015 年,我们发布了首份管道营销状况报告,并分享了我们对管道营销人员如何…
www.bizible.com](https://www.bizible.com/blog/b2b-industry-analysis-best-marketing-channels)
#Figure 3
origin_lost = data.groupby([‘origin’, ‘lost’]).count().drop(axis = 1, columns =[‘first_contact_date’,’landing_page_id’,
“seller_id”, “sdr_id”, “sr_id”, “won_date”,
“business_segment”, “lead_type”, “lead_behaviour_profile”,
“has_company”, “has_gtin”, “average_stock”, “business_type”,
“declared_product_catalog_size”, “declared_monthly_revenue”])percentage = []
for i in origin:
pct = origin_lost.loc[i].loc[False][0]/(origin_lost.loc[i].loc[True][0]+origin_lost.loc[i].loc[False][0])
percentage.append(pct)plt.figure(figsize = (6,4))
plt.bar(origin, percentage)
plt.xticks(rotation = 90)
plt.ylabel(‘won rate’)
plt.savefig(“won-rate.png”)

FIGURE 3: Won rate by channels
登录页面
Olist 使用了 495 个登录页面来捕获 mql。尽管销售团队负责将 MQL 转化为成功机会,但营销团队可以通过在登录页面上提供相关信息和优势,从漏斗顶部影响这种可能性。从上面的图 4 中可以看出,有 2 个登录页面拥有非常高的 mql 数量(大约 800 个 mql)以及非常高的赢得率(大约 20%),这意味着从这些登录页面获取的 mql 中有 20%成为了 Olist 的卖家。
#Figure 4
mql_lp = mql.groupby(‘landing_page_id’).agg({‘mql_id’:”count”})
mql_lp = mql_lp[mql_lp[‘mql_id’] > 30]data_lp = pd.merge(data, mql_lp, how = “inner”, left_on = “landing_page_id”, right_index = True)
lp_lost = data_lp.groupby([‘landing_page_id’, ‘lost’]).agg({‘mql_id_x’:”count”})landing_page = list(mql_lp.index)
percentage_lp = []
landing_page_2 = []
Num_mql = []
for i in landing_page:
if mql_lp.loc[i][0] == lp_lost.loc[i].loc[True][0]:
lp_lost.drop([i])
else:
pct = lp_lost.loc[i].loc[False][0]/(lp_lost.loc[i].loc[True][0]+lp_lost.loc[i].loc[False][0])
percentage_lp.append(pct)
landing_page_2.append(i)
Num_mql.append(mql_lp.loc[i][0])fig = plt.figure(figsize = (10,4))
ax = fig.add_subplot(111)
ax2 = ax.twinx()
ax.bar(landing_page_2, percentage_lp)
ax2.plot(landing_page_2, Num_mql, color = “red”)
ax.set_ylabel(‘won rate’)
ax2.set_ylabel(‘number of MQL’)
for tick in ax.get_xticklabels():
tick.set_rotation(90)
plt.savefig(“landing-page.png”)

FIGURE 4: Number of MQLs and won opportunity by landing pages
从这些登录页面中学习可以帮助 Olist 将成功复制到其他登录页面。
定位-业务领域
目标定位在 B2B 营销中非常重要。有些细分市场会对 Olist 非常感兴趣,反之亦然。下图显示了通过使用销售周期(销售过程有多长)作为指示:
#Figure 5
data2 = pd.merge(mql, close, how = “right”, on = “mql_id”)
data2[‘first_contact_date’] = pd.to_datetime(data2[‘first_contact_date’])
data2[‘won_date’] = pd.to_datetime(data2[‘won_date’])
data2[‘sales cycle’] = data2[‘won_date’] — data2[‘first_contact_date’]
data2[‘sales cycle’] = data2[‘sales cycle’].dt.dayssegment_time = data2.groupby([‘business_segment’]).agg({“mql_id”:”count”, “sales cycle”:”mean”})
fig = plt.figure(figsize = (10,4))
ax = fig.add_subplot(111)
ax2 = ax.twinx()
ax.bar(segment_time.index, segment_time[‘sales cycle’])
ax2.plot(segment_time.index, segment_time[‘mql_id’], color = “red”)
ax.set_ylabel(‘Sales cycle’)
ax2.set_ylabel(‘number of MQL’)
for tick in ax.get_xticklabels():
tick.set_rotation(90)

FIGURE 5
家居装饰、健康美容、家用设施、房屋和花园建筑工具、汽车配件和电子产品等业务领域是卖家的主要业务,销售周期通常为 50 天左右。一些细分市场的销售周期比其他市场更长,如香水和手表。然而,由于这两个部分只有少量的 mql(7 & 10 个),所以 Olist 可能应该等待更多的 mql 来获得更精确的观察。

FIGURE 6: Number of MQLs and sales length by lead type
关于 Lead_type 变量,Online_medium 是 Olist MQLs 中最流行的类型。这些业务类型的销售周期没有显著差异。
#Figure 7fig = plt.figure(figsize = (10,4))
ax = fig.add_subplot(111)
ax2 = ax.twinx()
ax.bar(lead_time.index, lead_time[‘sales cycle’])
ax2.plot(lead_time.index, lead_time[‘mql_id’], color = “red”)
ax.set_ylabel(‘Sales cycle’)
ax2.set_ylabel(‘number of MQL’)
for tick in ax.get_xticklabels():
tick.set_rotation(90)
Olist 还可以根据销售周期来评估销售代表的表现。从图 7 中可以看出,销售代表拥有的销售线索越多,销售周期就越短。这可以解释为有经验的销售代表(更多 mql)会比新的销售代表表现得更好(销售时间更短)

FIGURE 7: Number of MQLs and sales length by Sales Reps
领导行为
下表是每个行为特征的描述,基于心理学家威廉·莫尔顿·马斯顿的 DiSC 理论开发的行为评估工具 DiSC。

#Figure 8segment = pd.DataFrame(index = ['cat','eagle', 'wolf', 'shark'])
**for** i **in** segment_time.index:
lead_profile = close[close['business_segment'] == i]
segment = lead_profile.groupby('lead_behaviour_profile').agg({'mql_id':"count"}).rename(columns = {'mql_id':i}).merge(segment,
how = "right", left_index = **True**, right_index = **True**)
segment = segment.fillna(0)
plt.figure(figsize = (14,4))
snb.heatmap(segment, annot = **True**)
plt.title("Heatmap of Lead Behaviour Profile and Business Segment", size = 15)

FIGURE 8
48.3%的领导行为特征是坚定,这意味着此人强调合作、真诚和可靠性。了解销售线索的特征可以帮助 Olist 团队创建相关的人物角色,使他们更容易为目标受众设计内容、信息和故事。
业务类型
#Figure 9segment2 = pd.DataFrame(index = ['reseller', 'manufacturer', 'other'])
**for** i **in** segment_time.index:
lead_profile = close[close['business_segment'] == i]
segment2 = lead_profile.groupby('business_type').agg({'mql_id':"count"}).rename(columns = {'mql_id':i}).merge(segment2, how = "right", left_index = **True**, right_index = **True**)
segment2 = segment2.fillna(0)
plt.figure(figsize = (14,4))
snb.heatmap(segment2, annot = **True**)

FIGURE 9
有两种商业类型:经销商和制造商。经销商占 mql 总数的 69.7%。因此,经销商在业务领域中出现得最多也就不足为奇了。然而,在家居装饰行业,56%是制造商。
成交业绩
第一批订单的时间
#Figure 10seller = pd.merge(order_item, orders[['order_id','order_approved_at']], how = "left", left_on = "order_id",right_on = "order_id")
seller['order_approved_at'] = pd.to_datetime(seller['order_approved_at'])
seller_first_order = seller.groupby('seller_id').agg({"order_approved_at":"min"})
diff = pd.merge(close, seller_first_order, how = "inner", left_on = "seller_id", right_index = **True**)
diff['first_order_time'] = diff['order_approved_at'] - pd.to_datetime(diff['won_date'])
diff['first_order_time'] = diff["first_order_time"].dt.days
*#Histogram*
plt.figure()
plt.hist(diff["first_order_time"], bins = 15, rwidth = 0.9)
plt.title("Histogram of time for first order",size = 15)
plt.xlabel("Days")
plt.show()

FIGURE 10
自同意加入 Olist 平台之日起,大多数卖家必须等待不到 50 天才能收到来自 Olist 的第一个订单(图 10)。
健康美容、家居装饰、家用设施、音频视频电子产品等主要业务领域通常要等 50-60 天才收到第一份订单。我们也看到一些其他细分市场,如食品饮料、手工制品和时尚配饰,在第一次订购前有明显较长的时间。
#Figure 11first_order_segment = diff.groupby("business_segment").agg({"first_order_time":"mean", "mql_id":"count"})
fig = plt.figure(figsize = (10,4))
ax = fig.add_subplot(111)
ax2 = ax.twinx()
ax.bar(first_order_segment.index, first_order_segment['first_order_time'])
ax2.plot(first_order_segment.index, first_order_segment['mql_id'], color = "red")
ax.set_ylabel('Days')
ax2.set_ylabel('number of MQL')
**for** tick **in** ax.get_xticklabels():
tick.set_rotation(90)
plt.title("First order time by segments", size = 15)

FIGURE 11
每个细分市场的销售额:
#Figure 12product = pd.merge(product[["product_id", "product_category_name"]], category, how = "left", left_on = "product_category_name",
right_on = "product_category_name")
product_by_value = pd.merge(seller, product, how = "left", left_on = "product_id", right_on = "product_id")
category_sales = product_by_value.groupby("product_category_name_english").agg({"price":"sum"})
category_sales = category_sales.sort_values(by = ["price"], ascending = **False**)
top10 = category_sales.iloc[:10]
top10_category = top10.indexplt.figure(figsize = (10,6)) fancy_plot_2 = plt.subplot() **for** i **in** top10_category: order_category = product_by_value[product_by_value['product_category_name_english'] == i] order_category = order_category.set_index(pd.to_datetime(order_category['order_approved_at'])) order_category_agg = order_category.groupby(pd.Grouper(freq = "M")).agg({"price":"sum"}) fancy_plot_2.plot(order_category_agg.index, order_category_agg,'-x', label = i) fancy_plot_2.legend() plt.title("Sales by segment overtime", size =15)

FIGURE 12
图 12 是 Olist 销售额最高的前 10 个产品类别。由于健康美容、电脑配件、家具开发、家庭用品、汽车和园艺工具也是 MQLs 的主要业务领域,这些领域的销售价值也很高。唯一让我惊讶的是手表。虽然手表市场只有少量卖家,但与其他市场相比,手表的收入确实很高。
结论&建议
我们从不同的角度来看 Olist 卖方市场营销:渠道、消息(登录页面)、目标(业务细分、销售线索行为、业务类型、..)、销售流程(销售周期、销售代表)、达成交易的绩效,以表明平台的使用情况。每个角度都可以增加团队优化营销活动的价值。
以下是一些详细建议:
- 继续致力于 SEO/活动,以增加有机流量
- 从成功的登录页面中学习,为 A/B 测试创建假设。目标是复制其他登录页面中的成功
- 运动休闲和手表细分市场可以得到更大的发展,因为 Olist 可以从中获得高收入
- 引线是稳定型的。Olist 可以围绕这些类型的人建立客户角色,并针对这些人设计信息/内容。
- 调查为什么它在家居装饰领域吸引了很多制造商。能否在其他细分领域复制?
关于作者: 我是加州大学戴维斯分校的 MBA 学生。我对营销分析、建模、机器学习和数据科学充满热情。如果您有任何意见、反馈或问题,请随时通过 mapnguyen@ucdavis.edu 联系我,或通过LinkedIn联系我。快乐造型!
使用 Tableau 进行探索性数据分析

在机器学习中,探索性数据分析或 EDA 通常是我们向新数据集介绍自己的第一件事。它的作用是对数据进行一般性观察、总结、探索一些基本趋势或揭示变量之间的隐藏关系。Qlik 或 Tableau 等数据可视化工具有助于更好地浏览新数据,并以流行的方式呈现 EDA 结果。在接下来的几分钟阅读时间里,我将使用 Tableau Prep Builder 和 Tableau 桌面软件讲述一个特定的分类案例。
我们将在这里使用的数据集对这个城镇来说并不陌生,您可能以前就遇到过。该数据由一家葡萄牙银行在 2008 年至 2013 年间收集,包含电话营销活动的结果,包括客户对该银行提供定期存款合同的回应。我们的目标将是在数据集中找到那些能够更好地对活动做出肯定反应的客户群。数据集在加州大学欧文分校的机器学习库中可用。所以让我们开始吧!
首先,让我们使用 Tableau Prep Builder 连接到数据集,然后单击“添加步骤”以了解有关其功能的更多信息,软件将自动为我们生成数据集中所有变量的摘要:

Figure 1. Quick Summary of the Features by Tableau Prep Builder
这也是我们使用 Tableau Prep Builder 向数据中引入一些更改时的要点,例如,重命名或删除列、更改数据类型、删除明显的异常值等。
现在,让我们使用 Tableau Desktop 来研究这些数据,以获得一些有趣的数字。首先,让我们看看二元目标变量“y”与客户对银行提供存款合同的反应。

例如,随着欺诈性信用卡交易或在线活动的结果等分类案例的出现,往往会出现类别失衡的问题。图 2 显示了变量“y”的两个类在我们的数据集中也没有被平等地表示。确切地说,有 36,548 条记录属于“否”类,4,640 条记录属于“是”类。
这种不平衡表明,后来——如果我们要用这些数据建立一个机器学习模型——我们必须在训练模型之前对数据进行过采样或欠采样。

图 3 显示了数据集中任何给定年龄的“是”和“否”回答数之间的比率,与记录总数无关。有了这个图表,我们可以评估不同年龄的人对这个活动的反应。从图中我们可以得出这样的结论:是/否比率在年轻人中更好,但它也显示了一个稳定的负面趋势。大约在 30 岁左右达到一个虚拟的平台期,最低的数字一直持续到大约 57 岁左右,几乎没有变化。然后,回答“是”的比例进入快速积极变化的阶段,这可能与通常的退休年龄有关。数据集中没有足够的数据来充分代表 85 岁以上的人——因此图表的这一部分是不规则的。(要与此图互动,请点击单词 Chewbacca )
要创建这样一个数字,您应该从相关变量的菜单中应用表计算功能(在本例中为 CNT(y) ),选择“合计百分比”作为计算类型,并指定“y”作为计算百分比的维度,如下所示:

现在,这就是前面的图表显示的实数:

在图 4 的年龄范围内,对活动做出肯定回答的人数在 23 岁到 40 岁之间上升,但没有否定回答的人数上升得那么快。我们在之前的图表中看到,这种“是”的增加完全被人口统计中“否”的激增所抵消。

在图 5 中,我们将最后两张图连接在一起。该图强调了这样一个观点,即具有最低“是/否”比率的区域也代表了数据集中最大的记录份额-这必然对活动的结果产生了双重打击。虽然在一个非常大的年龄组中,反对得到了很大一部分人的支持,但在样本中人数不足的组中,赞成成功了。(如果你想更详细地探究这张图,你应该先摸摸这只姜黄色的小狗>🐕)

我们从图 4 中得出的结论在这个表(图 6)中也得到了支持。如您所见,职业列表中有两个类别在对活动的响应方面非常突出,即“学生”和“退休人员”。这些阶层与图 4 中的两个高峰有关:年轻人和 60 岁或以上的人。我们认为,后者可能与这个年龄段的人开始大量退休有关。我们从这张表中获得的洞察力证实了一定存在某种程度的因果关系。
具有平均线的盒须图(图 7)再次强调了这两组客户在“是”类中的比例过高。但我们现在不会对这一点进行更彻底的调查。

虽然探索性数据分析绝不是找到此类业务问题的全面答案的充分方法,但底线是我们所做的分析已经证明数据集展示了一些我们应该注意的有趣趋势。请阅读我的帖子'使用 Python 进行直接营销的机器学习分类,了解如何使用预测性机器学习模型以更彻底的方式解决这种分类情况。
感谢您的关注!!
使用方便的工具探索图像放大
了解图像转换工作原理的简单方法由 Albumentations 和 Streamlit 提供支持

The interface of the service. Original photo by Binyamin Mellish from Pexels
图像增强是一个重要的概念,已经成为计算机视觉的行业标准。它使 ML 模型更加精确和健壮,提高了泛化能力,并有助于用最少的数据创建高精度的模型。
有现成的工具可以将不同的转换应用到您的培训渠道中。我的选择是相册库
但是为了有效地使用它,你应该理解它是如何工作的。在本文中,我将告诉您如何选择正确的转换集,并为您提供一个简单的工具来可视化和探索不同的增强技术。
如果你熟悉“增强”的概念,并且已经在使用白蛋白,你可以现在就点击这个链接;你可以在交互界面上玩不同的转换,并实时看到结果(就像上面的 gif),或者你甚至可以获取源代码并在本地运行它。
否则,我建议你继续阅读,然后检查它。

Original photo by Jose Mueses from Pexels
什么是增强?
简单地说,增强是一种从现有样本中生成额外训练样本的技术。
让我们假设你正在训练一个 CV 模型,用“猫”和“狗”对图像进行分类。但是由于某种原因,你只有一些训练图像。

Dog image (Photo by Svetozar Milashevich from Pexels)
但是尽可能多地向你的模型展示训练图像总是好的。获得新样品而不制作新照片的最简单方法是稍微改变现有图像:
- 翻转
- 辐状的
- 规模和作物
- 添加一些噪点或模糊
- 更改亮度和对比度
- 或者稍微改变一下颜色通道
结果,你会得到许多新的图像,这些图像仍然是狗的图像,并且会告诉模型一个重要的信息:“狗的旋转图像仍然是狗的图像。”











Light transformations made using Albumentations library
最后,你可以应用一些更强的变换,这在某些情况下也是有用的(只要我们能在这些图像上认出狗):












Stronger transformations made using Albumentations library
如何将这种增强技术应用到实践中?
如今,你不需要通过你的双手来完成所有这些转变;有一些现成的实现库。而我最喜欢的是albumenations。
Albumenatations 是一个广泛使用的图像增强库,由计算机视觉专家、Kaggle Masters 和 Grandmasters 创建。您可以找到几十种不同的变换,它们都是以计算效率非常高的方式实现的。
您现在就可以开始使用它(如果您还没有使用的话),按照展示笔记本中的示例进行操作。
哪些转换是最好的?
有一些标准的转换集,在大多数任务中工作得很好(翻转、旋转、调整大小),但没有灵丹妙药,每个特定的工作都有其最佳组合。
让我们看看最近的 Kaggle 比赛,看看获胜者使用了哪些增强功能。
注意:下面我列出了第一名解决方案的总结,他们中的许多人使用了白蛋白,但不是全部。为了一致性,我使用了 Albumentations 名称来描述转换,如果它适用的话。
任务:查找钢板上不同类型的缺陷

Source: https://www.kaggle.com/c/severstal-steel-defect-detection/data
获胜者使用的增强 :
- 随机作物
- 水平翻转
- 垂直滑动
- 随机亮度对比
- 定制缺陷封锁

Source: https://www.kaggle.com/c/recursion-cellular-image-classification/overview
任务:在特殊的 6 通道图像上从真实的生物信号中分离出实验噪声
胜利者使用的扩充 :
- 随机调整裁剪大小
- 水平翻转
- 垂直滑动
- RandomRotate90
- 将每个图像通道归一化为 N(0,1)
- 对于每个通道:通道=通道* a + b,其中 a ~ N(1,0.1),b ~ N(0,0.1)
任务:在视网膜图像上发现糖尿病视网膜病变

Source: https://www.kaggle.com/ratthachat/aptos-eye-preprocessing-in-diabetic-retinopathy
- 随机对比
- 翻转
- 随机标度
- 随机亮度
- hue 饱和值
- 随机旋转
- 虚化
- 弹性变形
****任务:在胸片中识别气胸疾病

Source: https://www.kaggle.com/c/siim-acr-pneumothorax-segmentation/data
胜者使用的增强 :
- 水平翻转
- 随机对比
- 随机伽玛
- 随机亮度
- 弹性变形
- 网格历史
- 光学失真
- ShiftScaleRotate

Source: https://www.kaggle.com/c/imaterialist-fashion-2019-FGVC6/overview
****任务:服装分割和属性分类
- 水平翻转
- 随机亮度对比
- JPEG 压缩
加成!非图像竞赛
计算机视觉模型可以应用于其他领域,增强也是如此。例如,在音频处理中,大多数 SOTA 算法将原始音频转换成 Mel 频谱图,并将其作为普通图像进行处理。
任务:识别声音并应用不同性质的标签

Source https://github.com/lRomul/argus-freesound
- 随机作物
- RandomResizedCrop
- 光谱增强(光谱图的~剪切)
正如您在大多数示例中所看到的,使用了相似的基本转换集,但是更复杂的转换是针对每个特定任务的。此外,不仅变换而且它们的参数也很重要,看看 parrot 的这些图像。
****



********
Original photo by Skitterphoto from Pexels****
所有的(除了原来的)都是相同尺度(0.25)但是插值方法不同的降尺度变换的结果——那个乍一看似乎不是很重要的参数。但结果却大相径庭。
那么,如何选择变换和调整它们的参数呢?
有时候,选择变换背后的逻辑是很清楚的:当你处理来自显微镜的图像时,你可以很容易地将其旋转 360 度,当你处理人们的照片时,在大多数情况下,旋转应该更加温和。有时意想不到的事情可能会像 Freesound 比赛中的 RandomResizedCrop 一样,因为它与声谱图的物理意义相矛盾。从常识的角度来看,有些案例是可疑的,也不明显。例如我们是否应该将水平翻转应用于 x 射线图像,并使用上面有器官异常侧面的结果照片?
对于每个特定的任务,所有这些问题都应该独立地回答。即使您处理来自同一域的不同数据集,也可能最终得到不同的最佳变换集。
有一些尝试自动化这一过程。看看这篇关于自动增强的论文。但现在主要是科学练习,而不是生产技术。艰苦的工作应该手工完成。
选择增强策略的最佳方式是通过反复试验——将您引向交叉验证的最佳度量值或测试集的一组转换及其参数是最佳的。
但是有一些经验法则告诉我们如何做得更快。常见的增强搜索方法包括 3-4 个步骤:
- [可选]在没有增强的情况下训练您的模型,以获得可靠的基线。这对于调试很有用,但有时第 2 步也可以用作基线。
- 尝试一些光线变换(移动,旋转,翻转,裁剪,亮度,对比度等。)遵循常识。如果您得到的结果与数据集中的原始图像非常相似,您最有可能接受它。
- 尝试添加一些特定于数据集的扩充。例如,如果您知道在制作阶段,您将使用低质量的图像—尝试某种模糊、压缩或噪声是值得的。如果您处理街道照片,并且有许多不同天气条件的照片,请尝试随机雾、显示或下雨。但是不要依赖视觉评估;比较您的模型在使用这些增强前后的指标。如果他们在简历上变得更好——保持这种转变,否则就放弃。
- 尝试一些强转换。将它们视为您想要优化的一些超参数。剪切、曝光或通道拉伸等变换会产生非常不寻常的非自然图像,但有时,它可以帮助您训练更好的模型。现在,你应该完全依靠你的 CV 指标——测试一些组合,找到最好的一个。同时,你也可以尝试第二步和第三步中更激进的参数。
最后,您将得出最佳的转换组合。
最终的选择总是基于度量标准,但是您的经验、直觉和常识可以帮助您更快地找到解决方案。
但是我如何能直观地了解不同的转换是如何工作的呢?
有些变换直观上很清楚,例如,裁剪“裁剪输入的中心部分”而且它只有两个参数“高度”和“宽度”的作物。
但是像 RandomRain 这样的复杂函数就不那么直观了,可能有多达 10 个不同的参数。很难想象在头脑中改变它们的结果。
这就是为什么我创建了这个服务来试验不同的转换,在线版本可以在这里找到

Screenshot of the service
我使用了优秀的 Steamlit 框架来创建一个方便的界面。

Params of the MultiplicativeNoise transform
您可以选择任何想要的变换,并使用可视化控制元素调整参数,以查看生成的变换图像。
为了方便起见,您还可以看到使用所选参数调用所选转换的代码——将其复制粘贴到 Python 脚本中并使用它。您还将看到来自这个转换的源代码的原始 docstring,在这里您可以找到关于这个转换的解释和细节。

The code to call the transformation and the docstring
摆弄参数并了解它们如何在不同的图像上工作是获得快速增强调音所需直觉的最佳方式。
我可以在这项服务中使用我的图像吗?
是的,如果您在本地运行该服务,您可以做到这一点。
****git clone https://github.com/IliaLarchenko/albumentations-demo
cd albumentations-demo
pip install -r requirements.txt
streamlit run src/app.py -- --image_folder PATH_TO_YOUR_IMAGE_FOLDER****
这项服务的源代码可以在 GitHub(https://github.com/IliaLarchenko/albumentations-demo)上找到,你可以克隆它,做任何你想做的事情。
当您想要探索所有可用的转换或只是快速检查它们如何工作时,在线版本是有用的,而本地版本更灵活,可以根据您的需要进行定制。
我希望这个工具和这篇文章对你有用!不要犹豫问我任何事情或提出任何改进。祝你好运!
探索 16000 篇神经科学前沿文章

Photo by jesse orrico on Unsplash
最近我一直在做语音应用。对我来说真正突出的一点是对话界面是多么自然。如果技术足够进步,它将允许我们更轻松地完成任务,因为我们可以简单地说我们想做什么。然而,无论一个设备呈现信息的效率有多高,你消化信息的能力总是会受到你阅读、听或看的速度的限制。
这就是高级脑机接口(BCIs)如此伟大的原因。它们将允许人们比以往任何时候都更有效地学习、保留知识和交流。埃隆·马斯克一直在谈论他的神秘初创公司 Neuralink 如何开发高带宽脑机接口来连接人类和计算机。Neuralink 背后的想法是,如果大脑可以被实时解释和操纵,你就可以“扩展”大脑。这可以增加一个新的能力、理解和沟通的层次。人们将能够直接向另一个人传递想法,而不需要用书面/口头语言交流。然而,脑机接口已经研究了一段时间,许多应用集中在帮助瘫痪的人。
Neuralink 背后最近的炒作是这一分析背后的灵感。我想探索脑机接口研究的一些趋势。因此,在设定目标后,我准备花一天时间与熊猫和 Matplotlib 战斗,看看我是否能从我的数据集中收集到任何有趣的信息。
准备数据集
前沿媒体是同行评审的开放存取科学期刊的学术出版商。他们有许多科学、技术和医学期刊。在我的分析中,我使用了神经科学前沿期刊系列的文章,其中包含了一些在影响力和质量方面的世界顶级神经科学期刊。其中一些期刊包括《神经科学前沿》、《神经信息学前沿》和《细胞神经科学前沿》。
我的第一步是收集数据。在这种情况下,我编写了一个 Python 脚本来收集所有的神经科学文章。web scraper 保存了文章的文本和元数据。为了收集所有文章的 URL,我使用了一点 regex 来解析 sitemap.xml 文件中神经科学系列的 URL。一旦我的 web scraper 运行完毕,我的数据集就包含了 15803 篇以 JSON 格式存储的文章。这些文章带有丰富的元数据,包括出版国家、作者、引用日期和关键词。
对于 Pandas 来说,将 JSON 数据集转换成 CSV 是没有问题的。如果 JSON 对象被展平(只有一级键),您可以简单地使用普通的 dataframe 构造函数。然而,仔细观察就会发现,在缺少值的字段中有空的 dict 对象。这里有一个巧妙的技巧,你可以用 NaN 替换这些空字典:
df = df.mask(df.applymap(str).eq(‘{}’))
现在一切看起来都很好,我们调用 df.to_csv(),将数据集上传到 Kaggle,做一些探索性的数据分析。
查看内核:https://www . ka ggle . com/markoarezina/frontiers-in-neuroscience-article-EDA
你可以在 Kaggle 上找到数据集:https://www . ka ggle . com/markoarezina/frontiers-in-neuroscience-articles
了解数据
在深入研究 BCI 的具体研究之前,我想先了解一下数据集中的文章类型。除了期刊文本,数据集还包含了大量有趣的元数据。这包括有用的字段,如“引文 _ 期刊 _ 标题”,它指定了文章的具体神经科学期刊。例如,细胞神经科学前沿。由于元数据还包含引用国家,我认为国家和神经科学期刊的热图可能是获得数据集概览的好方法。

从热图中你可以看到该系列中一些最大的期刊是《细胞神经科学前沿》、《神经科学前沿》和《人类神经科学前沿》。
接下来,我想探索文章中的一些共同主题。为此,我找到了引文摘要中最常见的单字、双字和三元字。下面的情节展示了一些常见的主题。

单字谜没有透露太多,不出所料,最常见的词是“大脑”。最常见的三元模型与成像有关,这对研究大脑至关重要。磁共振成像使用强磁场和无线电波来生成体内器官的图像。功能磁共振是指通过检测与血流相关的变化来测量大脑活动的方法。
我也认为随着时间的推移,分析二元模型的流行程度可能是个好主意。这揭示了一些关键概念,如磁共振,这是多年来的顶级双字母组合。这也表明了这些年来研究的焦点是如何转移的。

随着时间的推移,绘制三元模型提及的百分比增长,显示了特定关键字的峰值,因为在特定年份有大量研究论文涌入。

BCI 特定研究
为了开始分析某些特定于 BCIs 的主题,我查询了抽象地提到大脑计算机/机器接口短语的文章。这给了我们 332 篇文章。
对二元模型和三元模型进行类似的分析,揭示了 BCI 特定文章中的一些共同主题。

以下是一些最常见的 BCI 专用术语及其解释:
运动想象:是 BCI 的标准概念之一,用户可以通过想象运动动作来产生诱发活动。用户在学会如何产生期望的大脑活动并发出预期的命令之前,可能需要几次训练。这种 BCI 的典型训练协议包括用户执行运动想象任务,随后在计算机屏幕上移动物体。
“支持向量机”/“分类准确率”:这些短语出现在对运动想象脑电信号进行分类的上下文中。支持向量机可用于对运动想象脑电图信号进行分类,以确定用户正试图采取何种行动。
随着时间的推移绘制二元图揭示了多年来焦点的转移。

一些有趣的模式包括 p300 波及其在拼写 BCI 中的应用。在 2017 年和 2018 年,对脑电图和对这些信号进行分类的关注也有所增加。
未来可以尝试一些有趣的事情,包括比较该系列不同期刊的研究主题。探索包括机构、关键词和参考文献在内的更多数据也很有趣。我对神经科学了解不多,我发现这种分析是一种很好的方式,可以让我对神经科学的一些研究领域有一个总体的了解,重点是 BCI。我很想听听你在哪些方面做得更好,或者是否有我可以纠正的地方。
我在 Vecgraph 开发谷歌助手和亚马逊 Alexa 技能。目前,我们正在寻求与一些品牌合作,开发他们的语音集成。由于我们希望在案例研究上进行合作,我们为您的语音应用程序的设计和开发提供折扣率。这个机会是先到先得的。让我知道你想创造什么!marko.arezina@vecgraph.com
探索具有简单熊猫和绘图可视化功能的数据集
Pandas 和 Plotly 进行初始数据分析——以网球为例

Image Courtesy of Kevin Mueller via Unsplash
介绍
Python Pandas 库与 Pandas graphing 库 plotly 相结合,可以帮助进行初始数据集探索。通过使用这两个库的简单函数和方法,可以快速获得快速但信息丰富的数据集摘要。
过去 20 年中最好的网球运动员
本教程将使用我从 ATP 巡回赛网站上搜集的数据集。具体来说,该数据集包含过去 20 年前世界排名第一的各种统计参数的信息。这篇文章的 CSV 文件的链接可以在我的 Github 页面这里找到。
数据集介绍
首先,在读入数据集时对其进行检查是一种很好的做法。数据集作为 CSV 文件保存在我的本地目录中,我使用 pd.read_csv 方法读取该文件并将其保存到名为 World 的数据帧中。数据集看起来不错,但是在右边有一个额外的不必要的列,我可以删除它。示出了 26 行中的 12 行。

12 of 26 Former World Number 1’s are shown
当处理一个新的数据集时,运行一些简单的 pandas 函数并检查各种属性总是最佳实践。如图所示,我删除了不必要的列,确保指定列 axis 1,并将关键字参数 inplace 设置为 True。为了检查这个函数是否按预期工作,我简要地看了一下列和形状属性。
尽管对于这个特殊的例子,数据集相对较小,但我鼓励检查空值,并使用 sum 方法给出关于任何缺失数据的信息。最后,我检查 dtypes 属性,因为我想在后续步骤中对列值执行数值运算。

Using convenient attributes such as .column/shape/dtypes/ and checking for missing data will serve you well when you familiarize yourself with any data-set.
谁是最好的前世界第一?
数据集有一些有用的信息,可以用来决定谁可能是最好的前世界第一。一个简单的方法来确定谁可能是最好的前世界排名第一,可能是确定谁有最高的胜率。
World DataFrame 有一个名为 Careers _ Wins _ Losses 的列,其中包含有关职业比赛输赢的信息。为了得到这些数据,把这一栏分成两个独立的栏可能是有用的,在它们各自的栏中有赢和输。

Pandas 提供了使用一行程序执行强大操作的能力。在这里,我创建了两个名为“Career_Wins”和“Career _ losses”的新列,并在连字符(-)分隔符上将该列从原始世界数据帧 Careers _ Wins _ Losses 中分离出来,使用 expand=True 参数,并将这些列指定为数字浮点数据类型列。
下面,我包含了世界数据框架中列的子集,以展示这是如何工作的。

现在可以创建一个包含所有职业比赛的新列,并且可以通过创建一个名为 win percentage 的新列来确定胜率,用职业胜率除以所有比赛次数,然后乘以 100 得到一个百分比数字。
接下来,我查看了下面所示的三列中的前 10 行,按成功百分比排序。数据显示拉斐尔·纳达尔拥有最高的胜率,这是否意味着他是最好中的最好?可能吧。最好是保持谨慎,并考虑不同时代对手的素质等限制因素。
通过使用简单的 Pandas 函数和方法,我们可以开始进行尝试性的总结。

Top 10 Current/Former World Number 1’s sorted by Win Percentage
对多列排序
按多列排序也可能有助于进一步区分。例如,我已经进行了排序(使用 DataFrame 系列方法,sort_values),首先是世界排名第一的年数,然后是获胜百分比。这可能是决定谁是最好的前世界第一的另一种方法。

Sorting by Years at No 1, places Pete Sampras in top position despite having a lower win percentage
每个玩家之间的百分比差异
为了从数据集中收集更多的信息,可以获得每个玩家之间的获胜百分比差异。在这里,我创建了一个名为 Tennis_Win_Perc 的新数据帧,它按照获胜百分比排序。然后我简单的使用。pct_change()方法,乘以 100,并从这个数据帧的三列中查看头部。
现在很容易按顺序看到每个玩家的胜率变化!

Incremental percentage difference (%) between each player (Top 10 rows shown)
易于阅读的过滤
当在筛选过程中使用多个条件时,筛选条件语句会变得很长,难以阅读。避免这种情况发生的一个有用的技术是将每个过滤条件分配给它自己的标准,并在过滤数据帧时将它们组合在一起。为了避免输出所有的列,我使用 loc 访问器只选择符合这个标准的网球运动员。
functools 模块中的 reduce 函数与 lambda 表达式的工作方式类似,它采用前两个条件的过滤乘积,并将它们与第三个条件相结合,以生成可应用于 DataFrame 的单个过滤条件。

将数据可视化
使用 Pandas 图形库 plotly 可视化数据对于探索性分析非常有用。通过一行代码(虽然我把这一行分成了 4 行,因为它是换行的),可以清楚地看出哪些球员在第一名的位置上呆了最多的周数。虽然这个输出当然可以使用一些增强,但对于初始数据探索来说并不坏!在 plot 方法()之前添加一个过滤条件来过滤世界数据帧,允许某些数据,在这种情况下,玩家从最终的视觉输出中被修剪掉。
有用的提示! 在使用 Jupyter 笔记本中的绘图方法绘图时
当在 barh 的括号内时,如果您按下 shift+tab 四次,将出现 barh 栏类型的文档字符串,为您提供可应用于视觉增强的特定定制的信息!

The output has been trimmed to only include players who have 50 or more weeks at no.1.
信息散点图
探索性散点图可用于研究两个连续变量之间的关系。在这里,我简单地创建了网球运动员、他们的收入和他们的胜率的列表。然后我创建一个 for 循环,遍历这三个列表并绘制它们,创建一个信息散点图。
注意:收益列是为这个散点图创建的,如代码片段所示。
现在显而易见的是,像比约·伯格这样的球员和诺瓦克·德约科维奇、费德勒、纳达尔有着相似的胜率,但是他们挣的钱要少得多。
现代社会的钱多了吗?需要更多的信息来找出答案。

摘要
Pandas 及其相关的绘图库 Plotly,可以帮助提供任何初始数据集的介绍,以表格和可视化格式给出有用的摘要。
探索 Tableau 中的分析
Tableau 的分析能力非常全面。使用分析中的一些功能,用户可以从他们的数据中得出有趣的推论。根据所需的输出,用户可以选择应用各种模型来总结他们的结果。
Tableau 在版本 9 中引入了分析选项卡。它位于数据选项卡旁边。

分析功能根据功能分为三组。让我们探讨一些分析数据时常用的选项。
箱线图:箱线图通常用于检查数据的分布情况。用户可以通过箱线图了解数据的分布情况。在 Tableau 中,要使用方框图,第一步是使用任何标准图表绘制数据。使用盒状图进行分析时,不应聚集数据。这可以通过不选择分析菜单中的集合测量选项来实现。这样,数据中的每个值都将包含在绘图中。绘图后,您可以选择位于分析选项卡中的框绘图选项。瞧,你的有胡须的方框图准备好了。您可以轻松识别异常值、中值、第 25 和第 75 百分位值。

可以根据特定要求编辑和格式化箱线图。

趋势线,预测:趋势线表示数据序列的趋势。趋势可以是积极的,也可以是消极的。它也被称为最佳拟合线。线性趋势线用于线性数据集。曲线也用于表示数据随时间变化的一般模式。趋势线在根据当前数据预测未来值时非常有用。
在 Tableau 中,通过单击按钮可以很容易地将趋势线添加到绘图中。

T 趋势线主要用于时间序列数据,即以连续时间间隔获取的一系列数据点。在上图中,您可以看到如何在 Tableau 中为一个数据集添加趋势线,该数据集包括澳大利亚四个地区的平均销售额(礼貌用语:Udemy )。这个数据是从 2010 年到 2015 年的。要在 Tableau 中添加趋势线,首先绘制数据点。

接下来,点击位于分析菜单中的趋势线选项。所有图的趋势线立即出现。您可以通过点击编辑趋势线选项选择要添加的趋势线类型,并进行其他修改。您可以添加置信区间,以显示相对于趋势线的 95%置信上限和置信下限。但是,这不适用于指数模型。

每条趋势线都有自己的描述。您可以点击描述趋势线选项查看所用模型的详细描述。


在分析和比较多个实体的数据时,这些信息非常有用。R 平方值和 P 值有助于推断数据模式,例如,R 平方值表示数据与线性模型的拟合程度。
预测是分析时间序列数据的下一步。一旦添加了趋势线,根据历史数据和趋势预测未来数据就变得容易了。在 Tableau 中,您只需点击位于趋势线链接下方的预测选项即可查看预测。

预测在当前图中显示为阴影区域。将鼠标悬停在预测图上,可以查看其描述。

与趋势线类似,您可以编辑预测选项,并根据您的需求进行定制。默认情况下,预测遵循包括季节性在内的源数据趋势。你可以预测几个月到几年的数据。

您可以通过查看“描述预测”窗口中显示的详细信息来了解预测描述。

与趋势线和预测功能一起,分析和可视化时间序列数据,如销售数据、人口增长、气候变化等。可能很容易。
聚类:聚类是一种将数据分成不同组的技术,这样每个组中的数据点都有一些相似性。它用于不涉及训练或学习的无监督学习。
在 Tableau 中,要实现一个集群,首先必须绘制数据。一旦绘图准备就绪,您只需点击分析选项卡中的聚类选项。

Y 我们的数据瞬间被漂亮地分成不同的聚类。如上图所示,Tableau 将数据点分成了三个不同的簇,并分别进行了颜色编码。您可以将鼠标悬停在数据点上,以了解 Tableau 将数据分组到不同集群所使用的逻辑。对数据所做的任何更改都会改变群集分组。
在 Tableau 中,聚类分析不适用于混合数据以及无法聚合维度的情况。此外,应该有可以分组到集群中的有效变量。可以修改聚类变量和聚类数量。
通过在数据窗格中将分类保存为组,可以将分类添加为维度。完成后,可以编辑组中的单个集群。该组的一个有用特性是,它可以在其他工作表中重用,就像使用任何维一样。该组和创建的原始集群相互独立。

趋势线也可以添加到聚类中。这有助于轻松识别每个集群中的异常值。此外,基于趋势线预测每个聚类的结果更有效。

这些是 Tableau 的一些关键分析功能。您可以更深入地研究它们,以了解它的完整应用。使用分析生成的输出,您可以在 Tableau 中创建引人注目的演示文稿,方法是将表单拖到仪表板中或创建令人印象深刻的故事。
你可以在 https://public.tableau.com/profile/rajeshwari.rai#!/查看这里给出的剧情
用 Tableau 探索澳大利亚网球公开赛数据——第三部分
使用 Tableau 了解 2000 年至 2018 年男子巡回赛的澳大利亚网球公开赛数据。Tableau 就像 visual SQL。

本周悉尼热浪袭人,气温高达 30 多度。冬天什么时候到来?
我已经错过了我的帖子,我继续给未来的自己写信,继续#29dayproject。为期 29 天的项目是一个热情的项目,应用分析和一些数据科学和工具的分析思维。在上一篇文章中,我们使用 R 进行了探索性数据分析(EDA ),评估了缺失值并生成了一些描述性统计数据。
为什么我需要画面?
Tableau 是一个商业智能工具,在全球范围内用于帮助行业理解他们的数据。您不需要在 Tableau 中编写任何代码,但它将帮助您使用单个或多个数据源讲述故事,您可以根据数据关系将这些数据源联合、混合或连接在一起,以创建工作表和仪表板或故事板。
通俗地说 Tableau 就是 visual SQL。
我如何访问 Tableau?
Tableau 桌面对在大学注册的学生和学者是免费的
你可能是一名学生或在学术界工作,你知道 Tableau 桌面是免费的,只要你在大学注册?我知道你知道。你只需要谷歌一下 Tableau 软件|学术项目


有一些内务管理项目需要向 Tableau 团队注册,您必须表明自己是一名学者或学生,并使用您的学生证或学术成绩单来验证您的身份。审查过程完成后,您将获得一个产品密钥。
Tableau 入门
我今天的目标是在进行任何预测建模之前,可视化 Tableau 中的数据,以理解这些数据。取预处理后的数据' aus_open.csv '文件,通过选择'文本文件'上传到 Tableau Desktop 2018 v3。

我之前已经准备了一些东西,创建了一个工作簿,保存为“Tennis_viz”。twbx '文件,而不是*。twb 文件。我在安联保险公司使用 Tableau Desktop,你只能通过将工作簿保存为 *来分享见解。twbx 文件,你的股东将需要安装 Tableau 阅读器,这是免费查看你的可视化。

数据源
一旦您的数据上传到 Tableau,您将必须检查您的数据,以确保 Tableau 已经正确地估计了您的数据属性,如日期、数字(度量)、分类变量(维度)或字符串(文本)。
一旦您对数据类型感到满意,将鼠标悬停在连接上,并将您的连接保存为提取而不是实时连接,因为读取实时数据的内存可能会降低您的计算机数据处理时间。我推荐 extract 版本,特别是当你在笔记本电脑上工作的时候。

创建您的第一个工作表
当您在 Tableau 中访问第一个工作表时,请像对 Excel 电子表格一样重命名工作表,并且不要忘记保存文件。

我检查了数据上传,确保 Tableau 正确地将变量分配为度量或维度。我感兴趣的是策划多年来第一盘的失败者。在列中,我拖动“年份”,在行中用总和聚集“L1”。
第一盘的进展
第一盘的进展 setI 希望通过比较第一盘的赢家和输家来进一步探索数据。从 tennis-data.co.uk提供的数据和注释我们可以看到缺少 2000 年到 2003 年的数据,这在之前的 R 中显示过。

他们在第四盘的表现如何?

他们在第五盘是如何追踪的?

根据 Tableau,看起来澳大利亚网球公开赛男子决赛要么是拉斐尔·纳达尔,要么是罗杰·费德勒。然而,在我们的下一篇文章中,我们将着眼于建立一个预测模型,以检查我们的建模和特征工程的准确性。
Tableau 工作簿在 Github 上分享。
快乐编码,享受网球!🎾
贝叶斯 A/B 测试——模拟实践探索
如今,A/B 测试是几乎所有数字产品公司发布功能的核心组成部分——这是有充分理由的。我们已经用科学的洞察力取代了猜测和直觉,了解什么能引起用户的共鸣,什么不能。但是我们从实验中获得的洞察力不是免费的。每次我们做实验,都是在冒险。我们要么冒着将次优版本投入生产的风险,要么冒着维护可能不如我们想要发布的新特性的体验的风险。此外,实验可能需要很长时间,尤其是在那些没有产生谷歌规模数据的初创企业。对于一些公司来说,实验的速度会成为在产品路线图上发布新功能的瓶颈。
许多公司的数据科学家都在寻找传统 A/B 测试方法的快速替代方案。因此,贝叶斯 A/B 测试成为了主流。虽然其他人已经写了贝叶斯 A/B 测试方法背后的理论和基本原理(见这里的和这里的),但很少有资源提供关于如何实施这些方法以及预期影响有多大的实用建议。例如,我对以下问题感兴趣:
- 贝叶斯方法能在多大程度上缩短实验时间?
- 实验速度和精度之间的权衡?
- 我们如何选择一个优先分布?我们选择的先验分布有多重要?
在本文中,我们将探讨这些问题,并为您提供将贝叶斯 A/B 测试实用地应用到您自己的项目中的工具。
审查方法
在开始分析之前,让我们简要回顾一下这种方法是如何工作的。正如我在介绍中提到的,其他人已经详细介绍了这一点,我从他们的文章中借用了一些。
任何实验的设计都有三个组成部分:构建变量,随机分组,分析结果。Frequentist 和 Bayesian A/B 测试方法的区别仅在于分析步骤。
频繁主义方法
我们大多数人都熟悉统计学入门课程中的频率主义方法。该方法如下进行:
- 声明一些假设。通常,零假设是新的变体并不比现有的更好。另一种选择是相反的。
- 使用统计功效计算提前确定样本大小,除非您使用顺序测试方法。
- 通过随机实验收集数据。
- 计算观察到结果的概率,至少与零假设(p 值)下的数据一样极端。如果 p 值<为 5%,则拒绝零假设并将新变体部署到生产中。
贝叶斯方法
虽然 frequentist 方法将每个变量的总体参数视为一个(未知)常数,但 Bayesian 方法将每个参数建模为一个具有某种概率分布的随机变量。虽然这种区别是微妙的,但它使我们能够计算我们在频繁主义世界观中无法计算的量。最重要的是,我们可以直接计算感兴趣参数的概率分布(以及期望值)。
为了对每个变量的概率分布进行建模,我们依靠贝叶斯规则将实验结果与我们所拥有的关于感兴趣的度量的任何先验信息相结合。我们可以通过在之前使用共轭来简化计算。当我们处理样本比例时(如本文后面的例子),一个自然的选择是 Beta 分布。
贝叶斯决策
我们定义损失为停止测试并选择一个变量,如下所示。

这里, α 和 β 代表实验每一侧的感兴趣的度量,而 x 代表选择的变量。用英语来说,这个函数的意思是,如果我们选择变量 A,如果我们做了错误的决定,我们所经历的损失要么是 β 大于 α 的量,要么是如果我们做了正确的决定,我们什么也没有。
因为贝叶斯法则允许我们直接计算每个指标的概率分布,我们可以计算出选择 A 或 B 的预期损失,给出我们收集的数据如下:

该指标考虑了我们通过 p.d.f. f(α,β) 选择最差方案的概率和通过 L(α,β,x) 选择潜在错误决策的幅度。
然后,我们可以设置某个损失阈值、 ε、,并在预期损失低于该阈值时停止测试。这个数字代表我们对错误的容忍度。正如我们将很快看到的,它在控制实验的速度和准确性之间的权衡中起着重要的作用。
检查和调整方法
介绍完毕后,让我们探索一下贝叶斯 A/B 测试是如何根据经验进行的。为了做到这一点,我们将使用蒙特卡罗模拟来探索该方法在几个假设场景中的行为。我在本文末尾链接了我的代码,因此您可以应用相同的方法来研究这些问题,并针对其他感兴趣的场景调整参数。
模拟
假设我们正在测试我们网站上的一个新的登陆页面。我们目前登陆页面的转化率是 0.20%。一个频率专家的功率计算会告诉我们,如果我们预期由于一个新的变体,这个指标会有 25%的改进,我们需要 22 万次观察才能有 80%的概率检测到这个差异(在 5%的显著性水平上)。哇哦。对于许多公司来说,这些数据需要几周或几个月的时间来收集。

让我们用一些模拟来看看贝叶斯方法会做什么。现在,我们将假设我们没有太多关于感兴趣的度量的历史数据,所以我们将选择统一的先验 Beta(1,1),它只假设两个先验观察值(一个转换,一个非转换)。此外,我们必须设置一个损失阈值。我们将使用 0.004%,这将代表我们的基本利率 0.20%的 2%的相对损失。我们的第一个模拟“实验”如下图所示。


在这个实验中,变体 B 的转换率很快就超过了变体 A。在每个时间步,我们通过数值积分计算选择变量 A 或变量 B 的预期损失。通过对每个变量的第一万次观察,变量 B 的预期损失低于阈值(由黑色虚线表示)。这将是对传统方法建议的每个变体 110k 的巨大改进,但这只是一个模拟。



在 500 次模拟中,我们几乎 90%的时候都正确选择了变量 B。此外,75%的实验在 50k 的观测值内结束。这不到传统方法所需样本量的四分之一!速度的提高并没有什么神奇之处——我们只是调整了决策标准。贝叶斯方法不仅考虑出错的概率,还考虑潜在错误的预期程度。贝叶斯 A/B 测试更能容忍低成本的错误,而 frequentist 方法(A)不考虑大小,( B)将误报视为,特别是高成本。请注意,我们仍然没有纳入任何先前的信息——速度的提高完全是因为我们增加了对小错误的容忍度。
速度和准确性
自然,下一个问题是:我们应该对错误有多大的容忍度?与任何 A/B 测试方法一样,我们面临着准确性和速度之间的权衡。在贝叶斯 A/B 测试中,损失阈值是控制这种权衡的节流阀。

We can use the loss threshold to trade accuracy for speed, and vice-versa
虽然没有解析公式告诉我们这种关系是什么样子,但模拟可以帮助我们建立直觉。以下是在不同效应大小(范围从 10%到 50%)下的几个模拟结果。这些图表显示了当我们改变损失阈值时,精确度和实验持续时间是如何变化的。


不出所料,随着我们对损失容忍度的提高,准确性往往会下降。当真正的效果尺寸更小时,我们往往会失去更多的准确性,这并不奇怪。在损失阈值非常高的情况下,我们倾向于很早就停止我们的实验,更有可能的是,次优的变体将完全凭运气首先达到损失阈值。你可以在右边的图表中看到这种效果:不管效果大小,当损失阈值足够高时,实验总是立即停止。
虽然选择的损失阈值将取决于业务环境,但在这种情况下,正确的选择可能在 0.002%到 0.007%的范围内。在这个范围之外,我们可以做便宜的交易:要么以很小的准确性成本减少我们的实验时间(当损失阈值为<0.002%), or improve our accuracy with little cost to experiment duration (when loss threshold is > 0.007%时)。
优先选择
贝叶斯分析中最有争议的问题之一是先验选择。这是许多贝叶斯统计新手认为感觉“主观”的部分,因为对于如何形成先验信念没有严格的科学指导方针。但是我们应该对我们在分析中的发现感到欣慰:在一开始,我们选择了弱β(1,1)先验分布,并且我们仍然能够在实验速度和可容忍的准确性方面获得不错的收益。
在大多数情况下,我们有一些预先的信息可以利用:我们在 A/B 测试中试图移动的度量标准通常是公司的 KPI。我个人发现用柱状图(通常是过去几个月的每周观察窗口)来可视化这些指标很有用。然后,我们可以在这个数据之前“目测”一下,或者更好的是,使用像fitdistplus这样的包来参数化地拟合一个分布。我通常采用比历史数据稍弱的先验分布。
选择一个好的先验将帮助你提高速度和准确性,而不是用一个去换另一个——也就是说,它是一个前沿移动器。但是正如我们已经看到的,即使没有强有力的背景,你也可以得到好的结果。所以如果你缺乏历史数据,不要放弃贝叶斯 A/B 测试。这个方法仍然可以帮助你更好地平衡速度和风险。
结论
我希望这篇文章有助于建立你对贝叶斯 A/B 检验的理解,以及你对如何选择损失阈值和先验的直觉。正如数据科学中的典型情况一样,上下文至关重要。用准确性换取速度的意愿将因公司而异,作为形成先验的历史数据的可用性也是如此。但是本文中使用的框架和工具应该足够通用,能够帮助您针对自己的用例调整贝叶斯 A/B 测试。
我发现蒙特卡罗模拟在试图理解许多不熟悉的量的行为时很有帮助,如预期损失,但我很想听听其他人对他们发现有价值的其他工具的看法——请在评论中分享!
参考文献:
- 我的代码:https://github . com/Blake ar/Bayesian _ ab _ testing/blob/master/Bayesian _ a _ b _ sims。Rmd
- 克里斯·斯图基奥的 VWO 白皮书
- 迈克尔弗拉斯科的合成
使用 Python 进行探索性数据分析:牛肉干数据集

Kilishi (Spicy Beef Jerky)
为什么是牛肉干?
在我进入编码领域之前,我尝试过联盟营销。我决定回顾牛肉干,并试图把它卖给志同道合的消费者。我喜欢牛肉干,也喜欢收集数据,所以我觉得把我的兴趣结合起来,为我吃过的牛肉干创建一个数据集会很有趣。我从制造商的网站或肉干包装上收集数据。本文涵盖了使用 python 库 Pandas 、Matplotlib 和 WordCloud 进行基本的数据清理和探索。
你可以在这里下载 kaggle 的数据。
你可以从我的 github 下载这个笔记本。
导入、检查、清理
导入依赖项和数据:
import numpy as np
import pandas as pdimport matplotlib.pyplot as plt
import seaborn as snsimport re
from wordcloud import WordCloud, STOPWORDSjerky_df = pd.read_csv(r"C:\Users\Admin\Downloads\jerky.csv")
jerky_df.head(3)

创建一个热图来发现具有空值的列:
热图是可视化数据的一种流行方式,因为它们使用从暖到冷的色谱将单个数据值转换为矩阵中的颜色。下面是一个热图,将非空值显示为黑色,空值显示为白色:
plt.figure(figsize=(8,6))
sns.heatmap(jerky_df.isnull(),cbar=True);

检查“品牌”和“口味”列的唯一值
print(jerky_df['brand'].unique())
print(len(jerky_df['brand'].unique()))
print(jerky_df['flavor'].unique())
print(len(jerky_df['flavor'].unique()))

注意数据有点乱。例如,由于大小写不同,品牌“Jack Links”出现了两次。同样,一些味道也可以被清除。特别是因为我们将制作一个单词云,将所有单词都设置为小写是有意义的。
创建新列来存储修改后的数据:
jerky_df['norm_brand'] = [brand.lower() for brand in jerky_df['brand']]
jerky_df['norm_flav'] = [flavor.lower() for flavor in jerky_df['flavor']]
jerky_df['norm_desc'] = [manufactureDescription.lower() for manufactureDescription in jerky_df['manufactureDescription']]print(jerky_df['norm_brand'].unique())
print(len(jerky_df['norm_brand'].unique()))
print(jerky_df['norm_flav'].unique())
print(len(jerky_df['norm_flav'].unique()))

将值设置为小写会将品牌减少到 10 个,口味减少到 23 个。
计算一些统计数据
print("Sodium Per Serving Mean: " + str(jerky_df['sodium'].mean()))
print("Calories Per Serving Mean: " + str(jerky_df['calories'].mean()))
print("Protein Per Serving Mean: " + str(jerky_df['protein'].mean()))

探索营养信息
我们可以使用 pandas、matplotlib 和 seaborn 来创建可视化,让我们探索口味、品牌和营养信息之间的关系。
某些品牌每份比其他品牌含有更多的钠或卡路里吗?
想象钠、卡路里和蛋白质
jerky_df[["sodium", "calories", "protein"]].plot.bar(label = 'Nutrition',figsize=(12,8),subplots = True, title = 'Nutrition Information Per Serving')
plt.show()

看起来钠含量有很大差异,但卡路里和蛋白质含量相当稳定。
根据品牌和味道来想象钠
#Create new data frame
brand_flav = jerky_df[['norm_brand', 'norm_flav', 'sodium', 'calories', 'protein']]#Group the data
brand_flavg = brand_flav.groupby(['norm_brand']).mean().sort_values(by = 'sodium', ascending=False)
brand_flavg.head()

#Group the data by brand and flavor
brand_flavg = brand_flav.groupby(['norm_brand', 'norm_flav']).mean().sort_values(by = 'sodium', ascending=False)
brand_flavg.head()

#plot the heatmap
plt.figure(figsize=(8,6))
sns.heatmap(brand_flavg[['sodium']],cbar=True, cmap='viridis')

根据品牌和口味直观显示卡路里
brand_calg = brand_flav.groupby(['norm_brand', 'norm_flav']).mean().sort_values(by = 'calories', ascending=False)plt.figure(figsize=(8,6))
sns.heatmap(brand_calg[['calories']],cbar=True, cmap='viridis')

用词云分析描述
词云是可视化文本数据的一种有用方式,因为它们使理解词频变得更容易。在葡萄酒描述中出现频率更高的词在云中会显得更大。这是一种提取和可视化关键词的方法。
清除描述并检查最高频率
clean_desc = []
for w in range(len(jerky_df.norm_desc)):
#Remove punctuation
desc = re.sub('[^a-zA-Z]', ' ', jerky_df['norm_desc'][w])
#remove tags
desc = re.sub("</?.*?>"," <> ",desc)
# remove special characters and digits
desc = re.sub("(\\d|\\W)+"," ",desc)
clean_desc.append(desc)
jerky_df['clean_desc'] = clean_descword_frequency = pd.Series(' '.join(jerky_df['clean_desc']).split()).value_counts()[:20]
word_frequency

拆分文本并删除停用词
停用字词是最常见的字词列表,如“the”和“of”将它们从描述中移除可以突出更相关的常用词。此外,在本文中创建单词云之前,我没有对单词使用词干化或词汇化技术。如果对更高级的自然语言分析感兴趣,可以看看 t 我的这篇文章。
#load stopwords
stop_words = set(STOPWORDS)#add additional stopwords to the set
add_stopwords = ["beef", "jerky", "flavor"]
stop_words = stop_words.union(add_stopwords)#create list of split words
split = []#iterate through using for loop
for w in range(len(jerky_df['clean_desc'])):split_text = jerky_df['clean_desc'][w].split()
split_text = [word for word in split_text if not word in stop_words]
split_text = " ".join(split_text)
split.append(split_text)
生成字云
Generate the wordclould
wordcloud = WordCloud(width = 800, height = 800, background_color = 'black',
stopwords = stop_words,
max_words = 1000,
min_font_size = 20
).generate(str(split))
#print(wordcloud)
fig = plt.figure(figsize = (8,8), facecolor = None)
plt.imshow(wordcloud)
plt.axis('off')
plt.show()
#fig.savefig("wordcloud.png")

最后的想法
使用正确的包,在 Python 中探索和可视化数据是很容易的!Pandas 和 matplotlib 使可视化数据变得容易,WordCloud 简化了识别自然语言中的关键字。使用这些工具,我们能够对牛肉干的营养和风味进行基本的数据分析。
谢谢大家!
- 如果你喜欢这个, 跟我上 Medium 了解更多
- 通过订阅 获得完全访问权限并帮助支持我的内容
- 我们连线上LinkedIn
- 用 Python 分析数据?查看我的 网站
探索过去五年的畅销书
每周,《纽约时报》( NYT)都会公布小说和非小说类的十大畅销小说。作为一个狂热的读者,我想确定这些列表是否会为未来的阅读提供建议(即它们是否会更强烈地迎合特定的子流派),并最终回答过去一年多来对我来说最困扰的问题之一:是只有我还是最近的畅销书中有很大一部分包含“女孩”这个词?!
接下来是我用报纸自己的 API 自行策划的 NYT 畅销书数据集的快速探索。这项工作部分受到了其他人的工作的启发,特别是迈克尔·陶伯格(https://medium . com/@迈克尔·陶伯格/how-to-name-a-best seller-6f 7313 fbb 9 e,)https://towards data science . com/book-titles-are-getting-longer-1c 341 FBD 4829)。我选择考察两个时间段:去年和过去五年,以便挖掘任何潜在的趋势。
正如你对每周出版率的预期,每周出现在列表上的书名没有太大变化。因此,作为第一步,我删除了所有重复的内容。下面的词云显示了前五年剩余语料库中每个词的流行程度。果然,我们马上看到“女孩”这个词在图表中占主导地位。

Best selling title words over the last five years.
仅在去年,这一趋势并没有消失。取而代之的是出现频率更高、主题更黑暗的词汇,比如“谋杀”、“战争”、“迷失”、“魔鬼”,甚至“黑暗”本身。

Best selling title words over the last year.
在这个续集和前传的时代,我们可能还会期待最近看到更长的标题,因为系列附加了修改描述(想想《哈利波特与……》)。事实上,这是勉强正确的,因为五年期间的平均标题长度为 2.74 个单词,而去年增加到 2.79 个单词(逐年分析在这里将被证明是最有用的)。


Distribution of title lengths over the last five years (left) and one year (right).
图书描述的聚类
除了书名之外,API 还提供了对小说适度详尽的描述。有了这些数据,我们应该可以初步猜测这本书的类型。然而,由于最畅销的书籍是那些吸引最广泛的人,我们可能不会期望在这项工作中取得突出的成果。
标题本身的信息内容可能不够密集,无法做出任何准确的判断。因此,我们将使用描述的原始文本。实际上,无论何时处理原始文本,都必须执行标记化、删除常用(停用)单词以及将每个单词简化为最基本形式(词干化/词汇化)的标准预处理步骤。在这里,我们在将标记提交给 TfidfVectorizer 之前这样做,TfidfVectorizer 根据每个标记在所学词汇中的出现频率将其转换为数字特征。通过这种方式,我们已经建立了自己的“书籍相关”语料库,而没有使用任何先前创建的嵌入。
有许多广泛使用和可用的聚类技术。对于这些无监督学习方法中的任何一种,最困难的决定是使用多少个聚类作为起始参数。在我们的例子中,我们可以想象的类型数量肯定是有限的,至少在第一次剪辑时是如此。再说一次,NYT 畅销书排行榜不太可能在可能的子流派的嵌套树中走得太深。(无监督学习的大部分乐趣是看算法能得出什么)。
在最常见的聚类类型 k-means 中,有一些聪明的方法来证明这种选择,比如“肘方法”。该方法试图选择“k ”,使得由下一个最高选择所解释的方差的边际增益第一次降低。换句话说,它选择的转折点,或“肘”在方差图解释对集群数量。使用我们的数据集,多达 50 个集群,我们获得了下图:

Attempt to select the ideal number of clusters using the elbow method.
我们已经可以看到,K-means 很难对聚类进行排序,因为在图中没有可识别的肘部。由于这个原因和其他原因,更常见的是使用剪影方法,该方法使用距离度量(通常为欧几里得距离)来评估聚类的点之间的间隔。接近 1 的轮廓系数意味着良好的分离。然而,同样在这里,我们获得了随着聚类数几乎线性增加的轮廓分数,这表明没有实现清楚的分离。
在我们五年的数据集中,我们有大约 1400 个独特的标题。剩下的最明显的选择是假设在集群之间平均分配,并选择 sqrt(1400)=37 作为第一个猜测。
这样做后,我们可以通过使用 TSNEVisualizer 来证实我们对分离不良的聚类的怀疑,TSNEVisualizer 在二维空间中呈现矢量化的语料库,由预定的聚类着色。

TSNE Visualization of our novel descriptions.
虽然乍一看这看起来很乱,但似乎确实有一些更密集的口袋可能真正捕捉到相似之处。
与 K-means 聚类相比,谱聚类是一种图聚类技术,它使用相似性矩阵来识别聚类,而不仅仅是距离度量。实际上,谱聚类通常更好地分离重叠的数据点;它不太关心它们在空间中的位置,而更关心它们在内容上的相似性。这些声音与我们息息相关;从现在开始,我们将使用谱聚类。
这样做,我们得到了一个在集群中很常见的分布,其中最大的集群使那些比它小的集群相形见绌。
Cluster_number Count
0 261
33 88
13 87
36 65
18 64
17 64
2 63
10 59
1 58
19 49
30 48
32 47
24 42
.
.
.
我们如何最好地可视化文本聚类以了解它们包含的内容?最好的方法之一是使用华盛顿大学的白蚁 d3 软件包,它可以按主题绘制常用词的流行度或显著性。这个项目的工作主要是用 Python 来完成的,所以我们现在将把自己限制在这种语言上。也许我们可以对每个主题中的单词进行排序,并给出一个或两个单词的中间值?通常,这仍然会导致单词缺乏意义,尤其是当集群的规模很小时。
nltk 包有一个很好的方法,叫做 freqDist,它确定单词在字符串中的频率分布。对于上面显示的最常见的聚类 0,如果我们只对那些长于 5 个字符并且出现超过 3 次的单词进行采样,我们将得到如下列表:
Cluster 0:
['america', 'american', 'ancient', 'artist', 'becomes', 'between', 'british', 'criminal', 'dangerous', 'during', 'encounters', 'father', 'follows', 'forensic', 'former', 'friendship', 'herself', 'investigation', 'investigator', 'involving', 'island', 'missing', 'mysterious', 'nantucket', 'parents', 'people', 'private', 'pursues', 'search', 'sequel', 'series', 'summer', 'together', 'treasure', 'vampire', 'wedding']
这里当然有很多词,但它们确实非常多样,缺乏一致性。与具有 63 个数据点的更紧密的集群 2 相比,我们开始看到一种模式出现:
Cluster 2:
['detective', 'detectives', 'disappearance', 'husband', 'investigate', 'investigates', 'lieutenant', 'murder', 'partner', 'president', 'series']
事实上,如果我们访问第 2 类的前 5 个元素的完整描述,我们会得到:
Sally Grissom investigates the disappearance of President Harrison Tucker’s wife.
D.D. Warren and Flora Dane investigate whether a pregnant woman shot and killed her husband.
Detective Dave Robicheaux and his new partner Bailey Ribbons investigate the death of a young woman by crucifixion.
Nick Fourcade and Annie Broussard, a husband-and-wife detective team, investigate a boy’s murder and the disappearance of his babysitter.
A television producer investigates the murder of a physician and whether it was his wife who killed him.
所有明显的调查秘密!
最后,我们还可以仅使用上面找到的最大聚类的描述作为我们的新语料库来进一步对其进行子聚类。现在我们有了 sqrt(261)=16 个更小的集群。对于其中最大的一个,我们现在有以下常用词和一些描述的样本:
['american', 'encounters', 'finds', 'found', 'widow']
A Star Wars saga. Grand Admiral Thrawn must choose between his sense of duty to the Chiss Ascendancy and loyalty to the Empire.
A photographer embarks on a road trip to reconnect with three men she might have married.
Maxim Trevelyan inherits several estates and beds his cleaner Alessia Demachi, an Albanian piano prodigy who has been trafficked into England.
Hans-Peter Schneider pauses his ghastly deeds to seek a dead man’s gold hidden under a Miami mansion, but its caretaker’s surprising skills prove daunting.
Investigations by Leaphorn, Chee and Manuelito overlap in the desert Southwest.
我们仍然有单词“american”和“encounters ”,但是比我们最初的集群 0 少了很多。然而,这些描述本身仍然缺乏一致性。
结论
我们研究了《纽约时报》畅销书数据库,揭示了近年来更黑暗主题的趋势。似乎也有迹象表明书名的长度正在增加。然后,我们看了看使用 K-means 和谱聚类基于书籍的描述对书籍进行聚类,并就可视化结果的方法提出了一些想法。虽然出现了一些共同的主题,但似乎没有足够的信息来对流派做出结论性的陈述。
敬请关注后续文章,我们将使用迁移学习来预测 Kindle 书评的极性(积极或消极)!
请在https://github.com/scjones5/nyt-bestsellers.git找到代码。
使用 Python 探索布伦特原油价格数据

在本帖中,我们将对布伦特油价数据集进行一些简单的探索性分析。我们首先导入 pandas 库并将数据读入 pandas 数据框:
import pandas as pddf = pd.read_csv("BrentOilPRices.csv")
我们还可以显示前五行:
print(df.head())

First five rows of Brent oil price data
接下来,我们可以将“Date”列转换为 datetime 对象,并查看前五行:
df['Date'] = pd.to_datetime(df['Date'])
print(df.head())

First five rows of Brent oil price data with datetime object timestamps
我们还可以查看最后五行数据:
print(df.head())

Last five rows of Brent oil price data
我们可以从数据中看到,价格是从 1987 年到 2019 年。我们还可以看到有 8,216 行数据。接下来,我们可以使用“seaborn”数据可视化软件包绘制价格与时间的关系图:
import seaborn as sns
sns.set()
plt.title('Brent Oil Prices')
sns.lineplot(df['Date'], df['Price'])

prices vs. time
我们还可以看看价格的分布:

Histogram of Brent Oil Prices
在下一篇文章中,我们将建立一个简单的回归模型来预测未来的布伦特原油价格。这篇文章的代码可以在 GitHub 上找到。感谢阅读。祝好运,机器学习快乐!
使用 Foursquare 和 Zomato API 探索印度昌迪加尔的场馆
数据科学顶点项目

Sukhna Lake, Chandigarh
作为 IBM 在 Coursera.org 的应用数据科学顶点课程的一部分,我参与了一个顶点项目,在这个项目中,我使用 Foursquare API 和 Zomato API 来获取印度昌迪加尔各个场馆的位置、评级和价格信息。在本文中,我将讨论我将来自两个 API 的数据结合起来并从中提取有意义的信息的方法。
该库将包括 Coursera 上应用数据科学顶点课程顶点项目的代码。…
github.com](https://github.com/kb22/Coursera_Capstone/blob/master/Exploring venues in Chandigarh.ipynb)
请注意,这些地图可能不会直接出现在 Github 的笔记本视图中,因此您可以通过克隆 repo 并检查
maps文件夹来检查它们。
介绍
在本文中,我们将根据评级和平均价格来探索印度昌迪加尔的场馆。每当一个人游览一个城市时,他们就开始寻找逗留期间可以参观的场所。他们主要根据所有场馆的场馆评级和平均价格来寻找场所,以便这些场所符合他们的预算。因此,我们在这里的目的是确定人们可以参观的地方。
在这里,我们将根据从 Foursquare 和 Zomato APIs 收集的数据以及从 Data Science 应用程序检索的信息来确定适合不同个人的地方。
数据讨论
数据是从两个 API 收集的,Foursquare API 和 Zomato API。第一步是在昌迪加尔中心点半径 4 公里的范围内搜寻场地。在使用 Foursquare API 提取了 120 多个位置之后,使用 Zomato API 将纬度和经度值用于获取场地的详细信息。

Venues retrieved from Foursquare API

Venues retrieved from Zomato API
我们看到一些场地重叠,而另一些场地则相距甚远。因此,通过仔细分析,我们决定从两个数据集中删除所有纬度和经度值相差超过0.0004的相应地点。完成后,我们发现仍有一些场馆没有对齐,可分类如下:
- 有些场馆内有 Zomato API(Elante Mall 的必胜客)提供的特定餐厅/咖啡馆。
- 两个位置如此接近,以至于它们实际上具有相同的纬度和经度值(披萨厨房和 Zara)。
- 一些场馆已被新场馆取代(Underdoggs 现已被 Brew Estate 取代)。
虽然可以保留属于第 1 类和第 3 类的场馆,但我们应该放弃第 2 类场馆。这给我们留下了 49 个场馆的数据集。
方法学
作为第一步,我们从两个 API(four square 和 Zomato)中检索数据。我们从昌迪加尔市中心提取场地信息,最远距离为 4 公里。然后,纬度和经度值用于从 Zomato 获取场馆评级和价格。
基于两个源的名称、纬度和经度值,来自这两个源的数据被仔细地组合在一起。最终数据集将包括每个场馆的评级和价格值。
接下来,我们分析根据每个场馆的收视率和价格创建的数据。我们识别顶级类别类型。我们确定了许多场馆所在的地方,以便任何游客都可以去一个地方,享受在众多场馆选项中进行选择的机会。我们还探索了高评分和低评分的区域,同时还绘制了高价位和低价位场馆的地图。最后,我们根据每个场馆的可用信息对场馆进行聚类。这将使我们能够清楚地确定哪些场馆可以推荐,以及具有哪些特点。
最后,我们将根据游客的评分要求和费用来讨论和总结哪些场馆需要开发。
分析
在分析阶段,我研究了昌迪加尔地图上的场馆类别、场馆评级分布和价格区间。
种类
当我们从 Foursquare API 中提取类别时,识别城市中最受欢迎的场馆类型真的会很有帮助。我们绘制了同样的柱状图。

看来昌迪加尔的大多数场所不是咖啡馆就是印度餐馆。如果游客试图探索其中任何一个,他们是幸运的。
评级
接下来我们就来看看场馆的收视率。作为一名游客,你想知道哪些地方有评级较高的场馆。我们可以绘制一个条形图,显示所有场馆的评分和每个评分的计数,以查看所有场馆的平均评分。

我们看到评级范围从1.0到5.0。剧情揭示最大场馆评分接近 4 。游客也可能有兴趣知道高评级场馆实际位于何处。

Venues with different ratings
橙色或红色的场馆等级低于 3 级,而标有绿色或深绿色的场馆等级为 3 级及以上。我们可以看到,很多高收视率场馆都位于第 35 扇区、第 17 扇区附近。 Elante Mall 拥有个分级在全系列的场馆。另外,从第 11 区到第 7 区和第 26 区的场馆带有高评级场馆。
价格
接下来,我们使用散点图探索所有场馆的人均价格,以及具有人均平均价格的场馆数量。

从上图我们可以看到,大量场馆的均价在 200 卢比到 400 卢比之间。我们还可以根据场馆的价格范围来划分场馆,看看哪些区域有什么价格的场馆。

Venues with different prices
从地块中,我们观察到35 区和 17 区附近的场馆主要是价格较低的。靠近7 区和 26 区的场馆价格很高。Elante Mall 似乎有高价和低价的混合场地。
使聚集
我们现在将根据价格范围、位置等因素对所有这些场馆进行分类,以确定相似的场馆以及它们之间的关系。我们将把场地分成两个独立的组。

从地图上,我们可以看到两个集群:
- 第一集群(绿色)遍布整个城市,包括大部分场馆。这些场馆的平均价格区间为 1.71,评级差约为 3.57 。
- 第二集群(红色)分布非常稀疏,场地非常有限。这些场馆的平均价格区间为 3.21,评级差约为 4.03 。
结果和讨论
在从 Foursquare 和 zoma to T21 API 中收集数据后,我们得到了 120 个不同场馆的列表。然而,并不是两个 API 中的所有场地都是相同的。因此,我们必须检查它们的纬度和经度值以及它们的名称,以便将它们组合起来,并删除所有异常值。这导致场地总数为 49 个。
我们发现,在所有的场地中,大多数是咖啡馆和印度餐馆。喜欢咖啡馆/印度餐馆的游客肯定会从昌迪加尔之旅中受益。
虽然评分范围从 1 到 5,大多数场馆的评分接近 4 。这意味着大多数餐馆提供的食物质量好,受到城市居民的喜爱,因此表明其评价高。当我们在地图上标出这些场馆时,我们发现在 17 区、35 区和伊兰特购物中心周围有一簇簇场馆。这些集群也有非常高的评级(超过 3) 。
当我们看一下每个场馆的价格时,我们发现许多场馆的价格在每人 200 到 400 卢比之间。然而,的价格变化非常大,整个系列从 100 卢比开始,一直涨到 1200 卢比。根据价格范围在地图上标出场馆,我们发现位于17 区和 35 区附近的场馆价格相对低于 7 区和 26 区的场馆。Elante Mall 中存在低价和高价的组合。
最后,通过聚类,我们发现许多场馆价格相对较低,但平均评分为 3.57 。另一方面,少数场馆价格较高,平均评分为 4.03 。
- 如果你想找价格便宜、评级相对较高的地方,你应该去 35 区看看。
- 如果你在寻找最好的地方,有最高的评级,但也可能有很高的价格标签,你应该参观第 7 区和第 26 区。
- 如果你想探索这座城市,但没有具体的标准来决定你想去的地方,你应该试试 Elante Mall。
公司可以使用这些信息来构建在线网站/移动应用程序,根据搜索标准(名称、评级和价格)为用户提供城市中各种场馆的最新信息。
结论
这个项目的目的是探索参观昌迪加尔的人可以探索的地方。已经使用 Foursquare 和 Zomato API 确定了比赛场地,并在地图上进行了标注。地图显示一个人可以参观的三大区域:第 35 区,第 7 区&第 26 区和伊兰特购物中心。根据游客的场地评级和价格偏好,他/她可以在三个地方中进行选择。
用 R 探索电影中的彩色故事

一次丰富多彩、数据驱动的电影色彩世界之旅
你最喜欢的电影的主色调是什么?电影制作人对色彩的运用是如何随着时间而变化的?光看一部电影的调色板就能猜出谁是导演吗?
在电影制作中,色彩是向观众传达信息最有力的手段之一。掌握色彩的确至关重要,许多最伟大的导演和摄影师都有丰富的视觉艺术背景。
颜色可以在我们不知不觉中影响我们的心理和情感。不同的颜色可以用来创造场景中的和谐或紧张,加强导演试图传达给观众的想法,引起对关键视觉主题的注意,展示角色的旅程,等等。
根据情节、主题、目标观众甚至只是导演的喜好,电影可以是激进的色彩,深入探索整个色轮,也可以是单色的,温和的,遵循完全不同的审美。
从下一章开始,我们将使用数据驱动的方法和构建适当的数据-viz 工具来探索彩色故事的这些和许多其他观点。
在我们丰富多彩的旅程中,我们将探索一些从著名电影中挑选出来的有趣例子,试图猜测导演选择背后的原因,并通过 R 脚本了解能够做些什么。

A glimpse of Wes Anderson’s color aesthetic in The Life Aquatic with Steve Zissou. [©Touchstone Pictures]
注:技术部分已标注⑇。如果您想了解文章的主要内容,而不想参与令人讨厌的编码部分,请随意跳过它们!
一.一切从哪里开始:数据
什么是视频?
V 视频只是连续图像的集合(即帧),当以合适的速度再现时,这些图像给人以运动的感觉。每个视频可以正式表示为一个 4 阶张量。
图像在数字上被定义为三阶张量,其中每一层都是代表不同颜色通道的二维数字阵列。因此,图像的颜色由这些通道的组合来定义。
根据编码的不同,张量的每个单位(即像素)可以是实数(HSL,HSB/HSV,归一化 RGB),也可以是整数(RGB)。为了更好地解释颜色模型,看看这个。现在让我们坚持使用 RGB 编码,这是最直观的一种。
RGB 是加色模型,其中帧由三个颜色通道 : 红色(R)绿色(G)蓝色 (B)叠加表示。通道的每个单元是 0-255 强度范围内的整数(即 8 位)。

Visual representation of second, third and fourth order tensors in imaging.
用 Matlab ⑇实现视频导入和帧预处理
我们要处理的数据是张量。在 R 中检索视频源的张量分量有点棘手;因此,在最初阶段,我们将使用VideoReader对象在 Matlab 中工作。
上面的脚本逐帧检查视频源。每一帧都是一个高 ×宽×3 张量。因为我们最感兴趣的是探索整个剪辑的颜色趋势,而不是关注此时单个帧的调色板,所以我们需要提取的唯一信息是每个帧的平均颜色(即 RGB 三色组)。
运行这个预处理管道需要一些时间。电影通常以 24 fps(即每秒帧数)显示,这意味着我们每秒钟的视频要处理二十多张图像。假设输入分辨率为 720p,为了获得单个帧的平均颜色,我们必须计算 1280 ⋅720 =921600 像素≃ 1 Mp 的平均值三次(每个通道一次)。所以得到一秒 视频需要处理的字节量是 0.92 Mpixel ⋅24 frames⋅ 8 bit⋅ 3 声道≃ 66 Mb !这基本上就是视频源这么重的原因了,对了。

Converting Uma Thurman from frames to RGB spreadsheets. Frames from Pulp Fiction, by Quentin Tarantino. [©Miramax]
一旦处理流水线已经运行,我们最终得到一个三列(即 RGB 平均值)和 N 行的逗号分隔值文件,输入视频源的每一帧一个。现在我们准备好出发了!
二。弄脏双手:框架线
框架线
S 由于我们的输入基本上只是一个时间序列的颜色,人们可能绘制的第一件事就是颜色时间线。从现在开始,我们将要创建的所有彩色条形码将被称为 框架线 。基于电影框架的美丽艺术作品可以在这里找到(非常感谢查理·克拉克的灵感!)和这里的。
这是我们在本章结束时能够构建的示例:

Frameline representation of 2001: A Space Odyssey, by Stanley Kubrick.
每一行代表一组连续帧的平均颜色,从时间 0(左)开始到电影结束(右)。最后一个瓦片是整部电影的平均色调。图块的厚度取决于我们想要平均的时间窗口。如果时间窗口太宽,有意义的颜色信息会在平均过程中丢失;如果我们选择一个非常短的时间窗口,过度拟合会使框架线很难解释。如果我们将宫崎骏的幽灵公主和娜乌西卡的框架线并列,我们可以清楚地看到当采样窗口太宽时,最有趣的颜色变化是如何被洗掉的。

Princess Mononoke and Nausicaa of The Valley of The Wind framelines. In both the movies, blue scenes start to fade out when the sampling window exceeds 100 seconds. As the time window become wider, the main color of the movie kills all the other tones, starting from the less represented ones.
在⑇实施框架线
现在让我们看看如何在 R 中实现所有这些。我们已经有了一个。csv* 文件,每帧的平均 RGB 值,所以数据导入已经基本完成。*
现在我们有了一个合适的输入数据框,我们将使用ggplot2包来绘制我们的第一个彩色框架线。 Ggplot 大概是 R 上最强大最流行的数据 viz 包 。绘制复杂的框架线需要掌握一点 ggplot,这不符合第一篇文章的目的。无论如何,这里有一个简化但功能齐全的脚本来绘制您的第一个框架线:
颜色平均值通常看起来非常暗/不饱和。这是非常生理的,因为场景经常在灰色和暗色调的中性色调下播放,而今天的电影往往有点无色。我们可以帮助我们的大脑和眼球使用鲜艳的颜色。这可以很容易地从 RGB 颜色模型切换到色调-饱和度-亮度 模型 (HSL)并打开最后两个组件。我们稍后会花一些关于 HSL 的单词。现在,我们只能说plotwidgets包中的modCol函数使得生动性增强实现非常直接。
框架检查:星球大战传奇
现在,让我们通过**检查星球大战宇宙**的颜色来让事情变得更有趣。通过对前面的脚本稍加修改,我们可以轻松地构建一个如下所示的可视化地图:

The Star Wars Saga framelines, starting from first trilogy (1st-3rd row) to Episode VIII (last row).
除了是一件我会自豪地挂在我床头的艺术品之外,这本画框集还揭示了乔治·卢卡斯在他史诗般的太空歌剧中使用色彩的大量信息。例如,让我们把注意力集中在使用更非典型调色板的那一集:《帝国反击战》(第二排)。

The Empire Strikes Back frameline with some manually extracted key frames. [©Lucasfilm LTD]
在这一集《天行者的奥德赛》中,我们的英雄穿越银河系,在三个不同的地方着陆:霍斯、达格巴和云城。在这里,乔治·卢卡斯巧妙地将不同的主色与每个地点联系在一起:耶鲁蓝代表冰冷的霍斯,深绿色代表沼泽,淡紫色代表云城。不同的颜色有助于展示故事的空间过渡、但它们也设定了每个部分的基调、调整饱和度和亮度:卢克在达戈巴沼泽的自省时刻没有周围部分那么饱和,每次原力的黑暗面上升,暗色调就占主导地位。在整个故事中,这些图案可以被观察到几次,给它一些颜色一致性。

The most vivid and intense point of the entire saga. Can you spot it on the framelines map? [©Lucasfilm LTD]
在每一部三部曲中也可以观察到颜色的一致性:在第一部三部曲中主要的色调是冷的,在前传三部曲中切换到更加温暖的色调,在著名的穆斯塔法决斗中高潮达到了一个强烈的火红色。让我们试着想象一下这些趋势。
摘要图块:色调、亮度和饱和度
在前面几节中,我们提到 RGB 不是唯一的颜色模型,也不是我们最感兴趣的颜色模型。只是简单直观而已。要检查有趣的颜色趋势,从 RGB 模式切换到 HSL 模式可能是个好主意。色调(H)明度 (L)和饱和度 (S) 实际上是我们谈论色彩故事时最重要的一些颜色属性。

Bicone representation of the HSL color space. [from Wikipedia]
HSL 颜色空间可以被视为一个双锥,其中每个点(即颜色)都在一个圆柱坐标系中表示,其中 S∈**【0,1】,L∈【0,1】和 H∈【0,360】。虽然我们都知道饱和度和亮度的含义,但色调的定义可能有点模糊。国际照明委员会(CIE)将色调定义为一种刺激与被描述为红色、绿色、蓝色和黄色的刺激相似或不同的程度。我们基本上可以称之为色影。****
这三个通道/属性中的每一个都可以被隔离,将其他的设置为固定值:例如,我们可以通过将亮度通道设置为 0.5(半强度)并将色调通道设置为 0(即纯红色)来检查每一集的平均饱和度值。亮度和饱和度通道可能会被重新缩放,以显示电影之间的差异。这种检查可以以摘要区块的形式可视化,其中每个方块代表一个不同的情节。**

Summary tiles for saturation (left), brightness (middle) and hue (right) channels of the Star Wars saga. From top to bottom: Sequel Trilogy, Prequel Trilogy, Original Trilogy.
上面显示的摘要图块证实了我们上面所说的关于色调的内容。此外,我们可以清楚地看到,与第一部和第二部相比,前传三部曲显得不那么黑暗和高度饱和。相反,续集三部曲的前两集是整个传奇中最黑暗、最不饱和的章节,第七集:原力觉醒获得了两个类别的第一名。将所有的帧线合并在一起,平滑产生的时间序列,可以更好地检查 HSL 通道随时间的趋势。**

Saturation (left), brightness (middle) and hue (right) channels trend over time in the Star Wars saga.
在这一点上,开始猜测下一集将会如何可能会很有趣。考虑到每个三部曲的第一章和第三章都没有第二章那么饱和,我们可以预期第九集的饱和度会更低。关于色调,色块矩阵是非常对称的,因此很难说电影的温度会是多少;考虑到整个故事的基调,我们可以推测一个不那么温暖的红色基调。
下注吧,12 月底见,看谁是赢家!**
三。找点乐子:电影和导演比较
彩色指纹:韦斯·安德森和宫崎骏
既然我们知道如何收集电影色彩中的暗示,让我们来看看一些最具代表性的导演的作品和他们的电影。许多电影制作人已经形成了一种独特的美学风格,通过在他们的作品中使用调色板很容易辨认出来。在最近的电影导演中,最引人注目的是韦斯·安德森和他的传奇故事。

Fantastic Mr Fox, by Wes Anderson. [©20th Century Fox, palettes from here]
安德森非常喜欢柔和的色调,他将这些颜色运用到了几乎所有的场景元素中。这让他完全垄断了自己电影的意义和潜台词。

Color fingerprints of three contemporary directors: Wes Anderson, Hayao Miyazaki and Christopher Nolan.
有许多有意识和无意识的偏见导致导演在他/她的职业生涯中选择类似的调色板。例如,自然和生态是宫崎骏思想的里程碑,这清楚地反映在他在绝大多数杰作中使用的调色板上。
颜色象征:矩阵
与导演的情况类似,电影和电视节目也可能会使用特定的调色板;一些电影对特定颜色的运用如此之多,以至于他们最终将自己与这些颜色联系在一起。例如,让我们想想绿色的。你联想到的第一部格林的电影是什么?还有为什么是矩阵?**

Framelines of The Matrix trilogy, by The Wachowskis.
《黑客帝国》可能是电影摄影中最明显和最著名的色彩关联案例之一,因为虚拟世界中发生的每个场景都是绿色的,灵感来自老式显示器的磷绿色。色彩象征在沃卓斯基的作品中强烈而明显;事实上,绿色并不是我们看到的唯一主色:当场景从矩阵转移到现实世界时,绿色完全被深蓝色调色板所取代。****

Chord diagrams of color hues transitions in The Matrix trilogy. The dominance of green fades away in the third episode, where the plot is almost entirely set in the real (blue) world.
这一选择背后的原因当然不是随机的:在色彩心理学中,黄色的绿色与恶心和疾病联系在一起,而蓝色的色调应该让观众感觉更舒服。从这个意义上说,通过将尼奥的正常存在设定为一种病态的、幽闭恐惧症的绿色,我们可以欣赏现实世界以其蓝色色调提供的新鲜感。相反,亮度对比是用来提醒观众,与《黑客帝国》的虚假和受控环境相比,现实是多么富有戏剧性。**

The Matrix vs Reality. Color palettes extracted automatically using k-means. [© Warner Bros]
滑过色谱:哈利波特传奇
说到绿色:你有没有注意到最新的哈利波特电影有多绿色?嗯,事情并不完全是这样开始的。

Framelines of The Harry Potter saga. Can you spot the Dolores Humbridge’s office scene?
实际上,《哈利·波特》很好地总结了我们之前说过的关于颜色的所有东西。不同色彩的巧妙运用清楚地定义了人物和地点:例如,想想霍格沃茨的四所房子、咒语和教师办公室。在传奇故事中,的导演们探索了整个色彩光谱、,从明亮、温暖的红棕色慢慢褪色为黑暗、无菌和冷绿色,在传奇故事的中间穿过一些蓝色。从这个意义上来说,看看*颜色如何随着角色一起演变,随着事件的发展变得越来越冷、越来越暗是很有趣的。*******

Harry’s character color evolution from The Philosopher’s Stone to The Deathly Hallows. [© Warner Bros]
JK 罗琳以一本儿童书开始了这一切,孩子们在魔法世界里奔跑尖叫。为了捕捉这种氛围,之前以执导《独自回家》而闻名的克里斯·哥伦布决定使用温暖明亮的调色板。至于书,故事很快成长成熟,随着哈利长大成人变得越来越复杂和悲剧。这清楚地反映在后续导演的色彩选择上,正如《传奇》中亮度成分的单调下降趋势所指出的那样。**

Brightness trend over the entrie Harry Potter saga. The set slowly become darker and darker, with the only exeption of the Harry and Dumbledore Talk at King’s Cross scene.
结论
这里是我们半音阶探索的第一部分结束的地方。我们看到在电影、中有许多使用色彩的方法,并且可以开发许多不同的技术来探索这些方法。为了收集这个项目中使用的所有函数,并使它们在 R 环境中易于访问,我构建了一个名为 c hromaR 的 R 包。 跳转到 第二部分 如果你想了解更多!**
*** [## 用 R 探索电影中的彩色故事:ChromaR 包
关于如何生成电影框架线和许多其他彩色数据的实用见解
medium.com](https://medium.com/@detsutut/the-chromar-package-892b716ee2c9) [## Tommaso Buonocore -作者-走向数据科学| LinkedIn
查看世界上最大的职业社区 LinkedIn 上 Tommaso Buonocore 的个人资料。托马索列出了 5 项工作…
www.linkedin.com](https://www.linkedin.com/in/tbuonocore/)***
使用 ICAs 从 fMRI 数据中识别静息状态网络
实践教程:从数据收集到特征提取

本教程通过分析 fMRI 数据的基本实践教程,提供了对神经影像研究合理实践的深入了解。我讨论(1)提出一个合适的研究问题,(2)数据收集,(3)质量控制,和预处理(4)特征提取。
下一个 post- 使用具有 rs-fMRI 数据的 LSTMs 从健康对照中分类 ADHD集中于数据分析。

A neuroimaging study pipeline (Lindquist, 2008). This tutorial (#1) focuses on the steps highlighted in purple.
本教程的代码可以在 这里 找到。做好准备,请下载 freesurfer 、 docker 、以及 python 。
我选择检查精神分裂症(SZ)患者的静息状态网络,并将其与这些健康人进行比较。
我很好奇精神分裂症是否表现出功能上的差异,主要是这种差异是否能在静息状态的网络中找到。
我认为这是一个有趣的问题(也是 fMRI 分析教程的一个很好的案例研究),因为它通过探索已知与异常神经回路相关的疾病,提供了对功能连接性分析的见解(Yu 等人,2012)。
数据收集
不,这部分与 MRI 机器的操作无关,而是集中于提供现有扫描供公众使用的各种在线资源。其中 openfMRI 、 Oasis 、 openNeuro 、 1000 功能连接体项目。
大多数数据集呈现原始的、去标识的数据,而有些数据集包含一些预处理脚本。有用的数据集将按照某种标准进行组织;常见的是脑成像数据结构 (BIDS)格式。在 BIDS 格式的数据集中,您可以看到按层次结构组织的文件:首先是主题 id,然后是扫描类型,然后(如果适用)是与每种扫描相关的不同任务或运行。文件本身最有可能是 NIFTI 文件(神经成像信息学技术倡议)或压缩的 NIFTI 文件(。nii 或. nii.gz)。
我使用来自 openneuro 的这个数据集。它包括对 290 名被诊断患有各种生理精神疾病(精神分裂症、双相情感障碍、多动症、抑郁症、创伤后应激障碍等)的个人以及健康对照组的扫描。除了各种条件之外,该数据集还包括捕捉不同任务的几种类型的扫描。为了探索上面提出的研究问题,我选择关注 SZ 患者的静息状态 fMRI 扫描。
fMRI 数据由 3T 西门子 Trio 扫描仪获得。扫描参数如下-层厚=4 mm,34 层,TR=2 s,TE=30 ms,翻转角= 90°,矩阵 64×64°,FOV=192 mm,斜切面取向。在静息状态扫描期间,参与者被要求保持放松并保持睁开眼睛;在扫描过程中,他们没有受到任何刺激,也没有被要求做出反应(Poldrack,2016A)。
从数据集描述中,我们可以看到 T1w(解剖学)扫描已经被使用free surfer MRI _ defage篡改(通过面部特征移除匿名化)。根据定义,损坏的数据之前经过了一些预处理。理想情况下,处理原始数据可以确保更加统一的预处理,但是如果不是这样,那么了解已经采取了哪些步骤是非常重要的。
因为这篇文章关注的是数据准备,所以我使用数据的一个子集来演示这个教程。一名 SZ (sub-50006)和一名对照(sub-10228)受试者。数据目录(根据投标组织)应如下所示:

BIDS formatted data
目录,这包括数据集描述、主题人口统计信息表和任务描述文件。
让我们看看我们的数据。
NIFTI 图像包含一个头,它可以很好地为您提供关于图像的大量元数据。当我们需要校正图像的噪声和其他失真时,这些信息将变得很方便。(更多详情此处)

我们还可以通过元数据找到扫描的切片数量(Z 轴的尺寸)和 TR。TR: 2.0,切片数:34。(万岁,这些数字似乎与作者报告的数字相符)。
此外,我们可以使用 freesurfer 轻松地将它们可视化。通过检查图像,我们可以识别扫描中的明显问题(奇怪的方向、伪像、对比度差,甚至图像缺失)。有一些工具允许自动执行这样的质量控制(我们将很快讨论它们)。

质量控制和预处理
在运行预处理管道之前,让我们看看手头数据的质量。质量控制(QC)有助于检测存在严重问题的图像,如伪影或严重失真。
用于分析大规模网络的数据的质量控制特别关注时间一致性。Power 等人(2011 年)详细介绍了几个图像质量指标(IQM ),重点是识别非伪相关性。我使用一个名为 mriQC 的软件,因为它根据同行评审的出版物(其中包括 power 等人,2011;Krüger 等人,2011 年)。下表描述了与确保时间一致性和避免虚假关联相关的 IQMs。包含坏的伪像或非常低的 SNR 的图像将被排除,而其余的进入预处理管道。在预处理期间将使用 DVARS 和 FD 来形成时间掩模(即,突出显示要移除的特定切片)。
IQMs
SNR (信噪比)
- 这是主要的空间度量。使用结构数据提取信号功率与噪声功率的比值。SNR 对于估计统计功率很重要。
- 它计算噪声均方根的信号幅度。较高的值表明重复测量的信号更稳定,因此测量的可靠性更高。
tSNR (时间信噪比)
- 报告时间序列的时间进程 SNR 的中值。
- 它计算平均 BOLD 信号(跨时间)与其对应的时间标准差图之间的比率。
- 当稍后使用数据来比较信号变化时,tSNR 很重要(低 tSNR 可能会使数据产生偏差)
DVARS (方差的导数)
- 衡量大脑图像的强度与之前的时间点相比变化的程度。因此,它是一个时间度量。
- 它通过体素上的导数 RMS 方差来索引 BOLD 的变化率。具有异常高值的切片被标记为排除。
FD (框架式位移)
- 测量头部在连续帧之间的位置变化量。
- 它计算重新校准参数的导数的绝对值之和。具有异常高值的切片被标记为排除。
该命令为您的数据目录中的所有参与者运行 QC-这是一个漫长而繁重的计算。请确保分配足够的资源(或逐个磨合)。
在查看指标之前,我先看一下结构化的可视化报告。从报告中获得的关键信息是污损过程(此处可见粗体噪声可视化上的黄色标记)。

Defaced structural data
功能报告报告一段时间内的 DVARS、FD 和异常值测量值。这些图表表明,sub-10228 提供了比 sub-50006 更清晰的扫描。

sub-10228 noise measurements. DVARS max:89 mean:24.4 FD- max:2.3 mean:0.2

sub-50006 noise measurements.DVARS max: 131.9 mean: 42.2 FD- max:2.7 mean:0.58
组功能报告揭示了 tSNR 和 SNR 的高值。

在检查数据并确保我们对其质量满意之后,让我们执行预处理。
我使用 fMRIPrep ,因为它试图提供一个标准化的预处理管道,并解决 fMRI 数据的健壮和可重复预处理的挑战。fMRIPrep 是一个独立于分析的工具,它为 fMRI 数据提供了一个灵活、最小且健壮的管道。此外,它是易于使用的开源软件,对其局限性和发展保持透明的讨论。
请注意我使用的标志- '- -fs-license-file '向 fMRIPrep 指示您的 freesurfer 许可证文件在哪里,- -fs-no-reconall '跳过 freesurfer 重建步骤(它有些错误,在这里不是必需的),而'- -output-spaces '定义了从其重新采样数据的解剖空间(T1w 指的是图像本身,fsaverage5 指的是 free surfer 模板,而 template 指的是 MNI 地图)。
类似地,这个命令为数据目录中的所有参与者运行 fMRIPrep。要注意。fMRIPrep 很重。更多信息点击这里。

fMRIPrep computing time under different conditions
fMRIPrep 在其管道中使用结构和功能映像。它输出头部运动校正、切片定时校正后的图像,并与同一受试者的结构空间对齐,符合蒙特利尔神经研究所(MNI)的空间。MNI 是一个标准化的空间,允许将不同的大脑标准化为一个单一的、可比较的图。
简而言之,fMRIPrep 管道。更多信息请访问文档。
- 分析 T1w 图像以检测脑屏蔽和脑组织分割

- T1w 参考扫描用于空间标准化。图像将被映射到它们的原生空间以及 MNI(以及您通过标记'- 输出空间')指定的任何其他空间)

- 第一个功能性重新对准通过使用 FSL 的 MC flight算法来建立运动校正,以头部运动为目标。

- 使用 AFNI 的 3dTShift 功能进行切片时间校正,以便将所有切片在时间上重新对齐到每个 TR 的中间。
- 磁化率失真校正(SDC)集中于修正由扫描仪内部磁场不均匀性引起的空间失真。
- 超过 0.5 mm FD 或 1.5 标准 DVARS 阈值的帧被标注为运动异常值。
这些步骤的顺序支持更稳健的校正(Power 等人,2012 年)。
比较原始数据和预处理数据的 DVARS、FD 和异常值测量,我们看到预处理减少了数据中的噪声。

sub-50006

sub-10228
特征提取:静息状态分析方法
一旦数据被清理、去噪和预处理,我们就可以(最终)识别连通性特征。请记住,静息状态网络在空间独立的区域中表现出相关的时间模式(Jandric 等人,2018)。检查这种相关性模式的两种常见方法是基于种子的相关性分析(SCA)和独立分量分析(ICA)。SCA (Biswal 等人,1995 年)是一种基于模型的方法;因此,它需要先验地将大脑划分为感兴趣的区域(ROI)(Lee 等人,2013)。SCA 特别有用,因为它实施起来很容易,解释起来也很简单(Soares et al .,2016)。基本上,它使用先验选择的种子区域的时间序列来识别全脑功能连接图(基于指定的 ROI)。另一方面,ICA 是一种无模型的方法,并将来自整个大脑的数据分解为已识别信号的时间过程和空间图。这些信号,即独立分量,是展现最大空间独立性但随时间共同变化的区域的集合(Cole 等人,2012;史密斯等人,2013 年)。

Commonly used analysis methods in functional MRI studies (Soares et al., 2016)
Nilearn 是一个 python 库,支持这些(以及许多其他)神经影像分析方法。
首先,我们需要上传预处理过的图像:
这些工具是我们需要的,以便得到一个地区地图集,并产生一个相关矩阵。如上所述,在 SCA 中,我们使用先验图谱,而在 ICA 中,我们基于数据集创建一个图谱。
第一个函数创建一个掩码。我喜欢尼尔对面具的定义。他们让我们“把掩蔽物体想象成瑞士军刀,用于将 3D 空间中的原始神经成像数据塑造成与手头的研究问题相关的观察单位”。屏蔽器将只过滤我们感兴趣的数据部分。掩蔽者使用图谱来转换 fMRI 扫描。
事实上就是这样。变换的 fMRI 扫描反映了区域到时间步长的 2D 矩阵(即[10,160]将反映跨越 160 个时间步长的十个区域的值)。
但是为了有一个好的、简单的、可视化的效果——我们计算提取区域的相关矩阵并绘制它(第二个和第三个函数)。
SCA 分析
我包括两种类型的地图集。第一个是哈佛-牛津概率图谱(Makris et al .,2006;弗雷泽等人,2005 年;Desikan 等人,2006 年;Goldstein et al .,2007),第二个是 Smith 的 ICA 功能图(Smith et al .,2009)。
哈佛-牛津图谱基于 MNI 定义的区域,因此展示了众所周知的大脑区域的先验分割。另一方面,史密斯的图谱反映了独立分析静息态 fMRIs 及其显示的激活大脑动力学产生的区域。因此,它介于 SCA 和 ICA 之间。它确实提供了一个独立于当前数据的掩码,但是它的起源是在一个相似数据集的 ICA 中。


我们使用这两个地图集来创建基于提取区域的面具。计算它们相应的相关矩阵并绘图。


ICA 分析
在 ICA 中,我们不是导入地图集,而是使用数据集本身来计算它们。

一旦生成了区域,这个过程就像我们在 SCA 中所做的一样。我们创建一个掩码并计算相关性。

在本教程的下一部分— 我们如何在统计分析中使用这些数据。SZ 受试者和对照组之间的静息状态网络有差异吗?
作为一个小玩笑,这个图显示了一个 SZ 患者的相关矩阵。你能发现任何明显的不同吗?

*This figure reflects the correlation between regions identified via the control ICA (so the plots could be comparable)
参考文献
Biswal、f . z . yet kin、v . m . Haughton 和 j . s . Hyde(1995 年)。使用回波平面磁共振成像研究静息人脑运动皮层的功能连接。马格纳。原因。医学。34, 537–541.doi:10.1002/MRM。19360.863863863616
科尔,D. M .,史密斯,S. M .,,贝克曼,C. F. (2010)。静息态 FMRI 数据分析和解释的进展和缺陷。系统神经科学前沿,4,8。
德斯坎 RS,塞贡内 F,菲施尔 B,奎因 BT,迪克森 BC,布莱克尔 D,巴克纳 RL,戴尔 AM,马奎尔 RP,海曼 BT,阿尔伯特 MS,基利安尼 RJ。一种自动标记系统,用于将 MRI 扫描上的人类大脑皮层细分为基于脑回的感兴趣区域。神经影像。2006 年 7 月 1 日;31(3):968–80.
埃斯特万 O,比尔曼 D,沙尔 M,科耶霍 OO,波尔德拉克 RA,戈尔戈莱夫斯基 KJ;MRIQC:推进来自未知部位的 MRI 图像质量的自动预测:PLOS 一中 12(9):e 0184661;doi:10.1371/journal . pone . 0184661。
弗雷泽 JA,邱 S,布雷兹 JL,马克里斯 N,兰格 N,肯尼迪 DN,赫伯特 MR,本特 EK,科内鲁 VK,迪特里奇 ME,霍奇 SM,劳奇 SL,格兰特 PE,科恩 BM,塞德曼 LJ,Caviness VS,比德曼 j。精神病学硕士。2005 年 7 月;162(7):1256–65
Jandric,d .,Lipp,I .,& Mumford,J. (2018)。OHBM 按需操作:静息状态功能磁共振成像分析。检索于 2019 年 10 月 26 日,来自https://www . ohbmbrainmappingblog . com/blog/ohbm-on demand-how-to-resting-state-fmri-analysis
Krüger 等人,氧合敏感磁共振成像中的生理噪声,Magn。原因。医学。46(4):631–637, 2001.doi:10.1002/mrm.1240
Lang,E. W .,Tomé,A. M .,Keck,I. R .,Górriz-Sáez,J. M .,& Puntonet,C. G. (2012 年)。大脑连通性分析:一个简短的调查。计算智能和神经科学,2012,8。
Lee,M. H .,Smyser,C. D .和 Shimony,J. S. (2013 年)。静息态功能磁共振成像:方法和临床应用综述。AJNR Am。神经放射学杂志。34, 1866–1872.doi: 10.3174/ajnr。A3263
林德奎斯特,硕士(2008)。功能磁共振成像数据的统计分析。统计科学,23(4),439–464 页。
N. K. (2008 年)。我们能做什么,不能做什么。自然,453(7197),869。
里昂大学(2017 年)。死鲑鱼和巫毒教的相关性:我们应该怀疑功能磁共振成像吗?。大脑,140(8),e53-e53。
大脑成像中的前瞻性运动校正:综述。Magn Reson Med 201369: 621–636.
马克里斯 N,戈尔茨坦 JM,肯尼迪 D,霍奇 SM,Caviness VS,法拉尼 SV,Tsuang 山,塞德曼 LJ。精神分裂症患者左侧和全部前岛叶体积减少。精神分裂症患者,2006 年 4 月;83(2–3):155–71
缪泽,K. T .,杰斯特,D. V .(编辑。).(2011).精神分裂症临床手册。吉尔福德出版社
Poldrack,R. A .,Congdon,e .,Triplett,w .,Gorgolewski,K. J .,Karlsgodt,K. H .,Mumford,J. A .,… & Bilder,R. M. (2016A)。神经和认知功能的全现象检查。科学数据,3160110。
Poldrack,R. A .,Baker,C. I .,Durnez,j .,Gorgolewski,K. J .,Matthews,P. M .,Munafo,m .,… & Yarkoni,T. (2016B)。扫描地平线:神经影像研究的未来挑战。bioRxiv,059188。
Power,J. D .,Cohen,A. L .,Nelson,S. M .,Wig,G. S .,Barnes,K. A .,Church,J. A .,… & Petersen,S. E. (2011 年)。人脑的功能网络组织。神经元,72(4),665–678。
Power JD,Plitt M,Kundu P,Bandettini PA,Martin A (2017)时间插值改变 fMRI 扫描中的运动:伪影检测的幅度和结果。PLOS 一号 12(9): e0182939。doi:10.1371/journal . pone . 0182939
Raichle,M. E .,MacLeod,A. M .,Snyder,A. Z .,Powers,W. J .,Gusnard,D. A .,& Shulman,G. L. (2001 年)。大脑功能的默认模式。美国国家科学院学报,98(2),676–682。
Smith SM,Fox PT,Miller KL,Glahn DC,Fox PM,Mackay CE,
Filippini N,Watkins KE,Toro R,Laird AR 和 Beckmann,参见 2009。
激活和休息时大脑功能结构的对应。美国国家科学院院刊(PNAS),106(31):13040–13045。
史密斯、S. M .、维道尔、d .、贝克曼、C. F .、格拉瑟、M. F .、简金森、m .、米勒、K. L .、… &巴奇、D. M. (2013)。静息态功能磁共振成像的功能连接组学。认知科学趋势,17(12),666–682。
Soares,J. M .、magal hes,r .、Moreira,P. S .、Sousa,a .、Ganz,e .、Sampaio,a .、… & Sousa,N. (2016 年)。功能磁共振成像指南。神经科学前沿,10,515。
Yu,q .、A . Allen,e .、Sui,j .、R . Arbabshirani,m .、Pearlson,g .、D . Calhoun,V. (2012 年)。精神分裂症患者静息态功能磁共振成像下的脑连接网络。药物化学当前主题,12(21),2415–2425。
探索数据中的循环。

Photo Credit : https://www.pexels.com/photo/two-yellow-labrador-retriever-puppies-1108099/
简短的概述
我们充满了循环。
周期是生活的一部分,是自然的一部分,也许是你可能会遇到的一些数据,我们所说的周期是指事件在时间和空间中以一定的周期性重复发生。
如果你生活在地球上,你每天都会经历白天/夜晚的循环,大约一天的三分之一时间会变得黑暗和寒冷,然后剩下的时间会变得明亮和温暖,这一系列的事件会在我们称为一天的时间段内重复发生。
季节是另一种类型的循环,连续几天寒冷,然后变暖,这在更长的时间内重复,生与死是另一个循环的例子,但这里的时间尺度如此之大,以至于我们通常忘记或没有注意到我们是一个更大循环的一部分。
为什么要学习周期?
通过研究周期,我们可以发现它们,并调整我们的行为以利用或避免所述周期的某个阶段,例如,如果我们知道从现在起 6 个月后温度将会变冷,食物将会匮乏,我们就可以相应地做好准备。
如前所述,周期无处不在,我们生物被硬编码到它们的某些方面(日子和季节),并创造我们自己的周期(睡眠/醒来,生育周期,工作/玩耍,等等,等等。),然而知道如何识别和描述它们的效用扩展到了其他领域…
考虑一下金融市场中的周期问题以及何时投资,这里的周期受已知和未知因素的影响,但如果你想成为一名成功的投资者,你需要知道你在周期中的位置,或者如一位著名投资者所说:
**"Being too far ahead of your time is indistinguishable from being wrong."**- Howard Marks ( Oaktree capital )
一个循环的细节。
首先,让我们看看最简单的周期:

And some relevant data points: +---+----+---+---+----+----+----+----+----+----+
| **X** | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | 32 |
+---+----+---+---+----+----+----+----+----+----+
| **Y** | -4 | 0 | 4 | 0 | -4 | 0 | 4 | 0 | -4 |
+---+----+---+---+----+----+----+----+----+----+Note that the values **-4** and **4**repeat themselves over the non-repeating axis **0…32**, what we have here are 2 cycles that start and end at **(0,-4)** with a length of 16.
这是另一个遍布自然界的周期(科学与工程,通常被称为 正弦波 :

Sine waves deserve their own separate discussion, for now just note that they provide us with additional ways to talk about cycles and describe their parts.
但更多的时候,你会遇到像这样的原始周期:

The axes are left out on purpose so you can hopefully note that there are 2 large full cycles and an incomplete 3rd one, you can identify the first 2 by their peaks and troughs, the 3rd one is longer in length and hasn't peaked yet...After noticing these features, we can then reveal the mystery data as the Dow Jones Industrial Stock Average (DJIA) from May 1997 to May 2019 (~ 22 Years), these cycles represent the financial ups and downs of millions of people on planet earth during those years.
检测周期
在代表您的数据的图表上直观地检测周期是一种非常有效的方式来弄清楚这个周期业务,不幸的是它缺乏一些改进,我们可以询问关于我们的周期的具体指标,然后我们将被留在图表上做手势...这个周期大概 hmmm 2 拇指宽!
幸运的是,聪明人一直在以结构化和数学的方式处理周期,所以我们可以利用这一点。
I'll explore a common and popular algorithm for cycle detection (Floyd's Tortoise and Hare) but there are a few more if you want to explore them at your own pace, here's a good place to start:[https://en.wikipedia.org/wiki/Cycle_detection](https://en.wikipedia.org/wiki/Cycle_detection)

弗洛伊德的龟兔赛跑

我们从一个数字序列开始(这里的循环很明显),把乌龟和兔子放在同一个起点上。

就像寓言中一样,兔子跑得快,乌龟跑得慢,兔子以两个2的空间增量移动,而乌龟每次只移动一个1。

以这种速度,如果有一个循环,乌龟和兔子将在相同的值0相遇,从而揭示循环0,4,8,4,0,简单而优雅,但是…
**Notes:(1)** This is a very naive explanation of the algorithm (for the sake of clarity), in reality we need to deal with nodes and pointers and also implement the algorithm in your language of choice, a good starting point is python, you will need to learn and implement [**linked lists**](https://medium.com/@kojinoshiba/data-structures-in-python-series-1-linked-lists-d9f848537b4d)**,** after thatyou can add complexity, here's a few implementations: [**Rossetta Code: cycle Detection**](https://rosettacode.org/wiki/Cycle_detection#Python)**.****Notes:(2)** It might not be obvious, but you can now get cycle metrics, once you have a cycle, you can get the min/max (trough/peak ...0,8) and calculate amplitude, things like frequency and period are also possible once you incorporate pointers (the X axis, which in this example we are omitting but assume the data is continuous like a time series).**Notes:(3)** This problem/algorithm has multiple practical applications, a favorite of coding interviews, it also helps detect infinite loops and cryptographic collisions amongst other uses.

Photo Credit: https://www.pexels.com/photo/animal-canine-close-up-dog-546229/
高级循环学
周期的世界是广阔的,取决于你的具体需求和项目,创建你自己的研究路径或分析可能是方便的,这并不是说有更先进的方法来看待数据中的周期和相应的技术和工具,这里有一些你可能想考虑的兔子洞…
希尔伯特-黄&小波 变换:另外两种分解信号的方法,每种都有不同于傅立叶分析的方法,根据数据的类型和可用性可能会更好。
预测:
预测是一个沉重的课题(c*heck the notes below)*,一旦你发现你的数据有周期性成分并完成量化,你还需要弄清楚它是否以及何时会重复,它会跟随一个趋势吗?上,下,横着?是什么在推动这个循环,是什么让你如此确定它会永远重复下去?
这些问题不仅需要一些关于周期的知识和在未来重现周期的数学和算法,更重要的是,还需要你预测的主题的知识,以获得关于未来行为和驱动行为的潜在原因的见解。
例如,当生物体死亡时,生物学中的一个循环迟早会突然停止;周期性的季节性趋势(想想假日销售)可能会被新技术破坏,或者像我们将看到的外部因素也可能影响周期,这里的背景是王道,假设你遇到了以下未标记的数据/图表…

没有上下文,我们可以合理地观察到存在周期,并且我们可以很轻松地预测下一个周期,这里是实际发生的情况以及缺少的上下文…

通过恢复上下文、实际数据和之前的观察,我们现在可以认识到当前周期没有以正常或预期的方式运行,然后我们可以寻找可能的原因并弄清楚。
**Notes:** A few sources related to forecasting (especially time series) and cycles:**-** [**Forecasting: Principles and Practice**](https://otexts.com/fpp2/)An excellent introduction.- [**Prophet**](https://github.com/facebook/prophet)(Facebooks forecasting library), check the [**white paper**](https://peerj.com/preprints/3190.pdf) for a related discussion on forecasting, also a pretty cutting edge tool.**-** [**Time Series in Python- Part 2\. Dealing with seasonal data**](/time-series-in-python-part-2-dealing-with-seasonal-data-397a65b74051)**:** An excellent series on forecasting and extracting cyclical elements.
作为周期的介绍和概述,我希望这是一个起点;如果你有任何意见或想建议增加或减少,让我知道。
最好的,
基诺。

关于作者:
【出生于 Eugenio Noyola Leon(基诺)我是一名设计师,软件开发人员&艺术家目前居住在墨西哥城,你可以在 www.k3no.comT5找到我
探索纽约的环境修复场所
使用 Matplotlib 和 Seaborn 进行数据探索

Photo by Luca Bravo on Unsplash
在本文中,我将探索位于纽约的各种环境修复站点,并尝试将数据集中包含的信息可视化。该数据由纽约州托管,可在 Kaggle 上获得。您可以在下面浏览该笔记本:
使用来自 NYS 环境补救地点的数据
www.kaggle.com](https://www.kaggle.com/bhanotkaran22/exploring-environmental-remediation-sites-in-ny)
资料组
- 数据集中有 70,324 个站点。
- 每个站点信息有 42 个不同的数据列。每份记录都包括了关于场地、项目、废物处理等信息。每个记录还包括大量信息,如地址、邮政编码等。
- 一些列具有空值,例如
Address 2和Waste Name。 - 每一列中的条目都是类型
integer、floats和objects。
数据探索
程序类型
数据集中总共有 5 种不同的程序类型:
- HW——州超级基金计划
- BCP——棕色地带清理计划
- VCP——自愿清洁计划
- ERP——环境恢复计划
- RCRA——危险废物管理计划

最常见的项目类型是州超级基金项目。此外,最不常见的类型是危险废物管理计划,在所有数据中几乎可以忽略不计。
站点类别
每个站点的类别/状态使用字母数字代码进行识别,如下所述:
- 02 —危险废物的处置对环境或健康构成了重大威胁
- 03 —污染目前不会对环境或健康构成重大威胁
- 04 —该站点已正确关闭,但需要继续进行站点管理
- 05 —不需要进一步的操作
- A —活动
- C —已完成
- p——初步信息表明某一场地可能受到污染的场地
- PR——现在或曾经受 RCRA 要求约束的场所
- N —没有进一步的操作
虽然每个类的描述都很清楚,但是有些看起来是多余的,比如同时使用05和N来表示不需要做更多的事情。不过,还是来看看剧情吧,看看有没有透露什么信息。

数据分布本身是非常独特的。有一点很明显,那就是许多场地项目已经完工。
项目完成日期
虽然所有网站都提供了建议的完成日期,但我更感兴趣的是已经关闭的网站,以及数据中是否有任何趋势。

正如我们从上面的线图中看到的,从 1985 年到 2005 年,很少有网站关闭,然而,在那之后,数量显著增加。【2015 年关闭的最大站点。
由于 1985 年至 2005 年期间,随着人口的激增,废物产量增加,因此关闭的场所数量减少,关闭的场所也减少了。
污染物
与其探究废物的名称,不如知道哪个场地有什么污染物。这可以允许将类似的解决方案应用于具有相同污染物的场所。T2 有超过 237 种不同的污染物需要处理。

Sites with the given contaminant

Sites with the given contaminant
铅是所有场所中最常见的污染物,多达 2500 多个场所含有铅。最不常见的污染物是酸洗液、矿物/白酒和碳酸钙。
控制类型
控制类型分为顶层的制度控制和工程控制,进一步包括契约限制、决定文件、环境通知、环境地役权和其他控制。

契约限制是最常见的控制类型,约占总数据集的 45%。
结论
这些数据揭示了许多关于修复场地的信息,使我们能够处理组合在一起的类似场地。
希望你喜欢我的作品。请随时分享你的想法,建议和想法。
探索探索性数据分析
后退一步理解数据集的简单指南

Stock photo by https://pixabay.com/
探索性数据分析(EDA)的全部意义在于,在对数据集做任何事情之前,先退后一步看看数据集。EDA 与数据项目的任何部分一样重要,因为真实的数据集非常混乱,很多事情都可能出错。如果你对你的数据不够了解,你怎么知道去哪里寻找那些错误或混乱的来源呢?
花些时间了解您将要使用的数据集。每当我处理新数据集时,我都会例行地问自己/检查以下几点:
1.数据导入是否正确?
我过去常常为找到导入数据的正确方法而苦苦挣扎。在 R 的基本库中可以找到read.csv()函数,因此它是我用来导入数据集的第一个函数。
# the two assignment statements below render the same output> df <- read.csv("mydataset.csv")
> df <- read.csv("mydataset.csv", header = TRUE)
read.csv()的默认标题选项设置为 TRUE ,这意味着该函数将数据集中的第一行观察值分配给列名。
假设mydataset.csv只包含没有定义列名的观察值。如果header = FALSE是函数中指定的而不是,则导入的数据框的列名将获得数据集中第一个观察值的值。检查这一点的最好方法是简单地查看导入数据的前几行。在这种情况下,使用colnames()也会有所帮助。
# returns the first few rows of df
> head(df)# returns a vector of characters that correspond to the column names
> colnames(df)
避免这种情况的一种方法是使用可以在 r 中的data.table库中找到的fread()。在这种情况下,header 选项被设置为 auto ,因此该函数会自动检查第一行观察值是否可以是列名,并相应地分配 TRUE 或 FALSE 值。我建议不管怎样,先看看前几行,但这比read.csv()更快、更方便
注 : read.csv()返回一个数据帧,fread()返回一个数据表。
2.是否存在缺失值和异常值?
成功导入数据文件后,我总是检查数据集中是否有任何丢失的值。我发现检验这一点的最好方法是按列对来自is.na()的所有真值求和,如下所示:
> colSums(is.na(df))
处理缺失值的方法有很多。丢失值的处理本身是一个单独的主题,但是我在这里试图强调的是对这些值的意识。一旦我知道数据集中有丢失的值,我就可以采取适当的措施来处理这些值。
也值得问问自己“为什么这些价值观缺失了?”。了解数据集中某些值缺失的原因有助于您更好地理解数据。请记住,这个练习的全部目的是帮助您获得数据集的完整度量,以便您知道您正在处理的是什么。
一些数据集也可能有非常不寻常的值。用一个例子来讨论这个更容易,所以让我们看看来自faraway包的pima数据集。数据集的描述可以在这里找到。
查看数据集每列的一些基本汇总统计信息是确保数据集中的值有意义的良好起点。看看下面的pima数据集的概要。

Summary of the dataset run in R.
具体看一下glucose、diastolic、triceps、insulin和bmi的最小值。这些变量取值为 0 有意义吗?不会。一个人不可能没有血压或没有体重指数。这些值为 0 的唯一可能的解释是,这些条目是没有收集数据的实例(即,它们是缺失值)。将这些值设置为 NA 值,以便可以用数据集中的任何其他缺失值来处理它们。下面是一个如何替换变量bmi的 0 值的例子:
# pima loaded as a dataframe
> pima$bmi[pima$bmi==0] <- NA

Updated summary of the bmi variable in R.
注意bmi摘要的变化。这样这些值更有意义。
现在来看看test。这个变量被认为是糖尿病迹象的二元指标。为什么会有均值?这清楚地表明,R 将 1 和 0 识别为定量变量,而不是分类变量。运行class()查看这些值在 R:
> class(pima$test)
[1] "integer"
要让 R 将该列作为分类变量来处理,可以使用factor():
> pima$test <- factor(pima$test)
> class(pima$test)
[1] "factor"
检测这些实例非常重要,因为这些异常值可能会严重影响预测模型以及从中得出的任何结论。
3.形象化
以各种方式可视化您的数据可以帮助您看到您在探索的早期阶段可能错过的东西。以下是我的一些直观形象:
直方图
继续前面关于pima数据集的例子,下面是我使用ggplot2和tidyr库绘制的直方图。这种可视化方法有助于我查看数据集中每个变量的频率/点数:
> pima %>%
+ gather() %>%
+ ggplot(aes(value)) +
+ facet_wrap(~ key, scales = "free") +
+ geom_histogram(stat="count")

Nine bar graphs by count for nine variables in the dataset.
通过可视化您的数据,您可以看到变量triceps和insulin明显有大量的缺失值。这表明,在这种情况下,必须小心处理丢失的数据。理解为什么如此多的值丢失可能是一个需要注意的重要特性。
注意:如果您之前没有纠正异常的 0 值,您将会看到类似的可视化效果。
关于使用ggplot2和tidyr进行可视化的代码详情,请看这个网站。
散点图矩阵
散点图矩阵可以帮助您了解数据集中任意两个变量之间是否存在某种关系。使用iris数据集来看看这个成对散点图的对称矩阵。
> pairs(iris)

Pairwise plots for the iris dataset
你可以看到,只要看看上面的图,在Petal.Length和Petal.Width之间有一些线性关系。您甚至还没有进入建模阶段,就已经对您想要关注的变量有了深入的了解!
相关矩阵图
这个相关矩阵图为理解两个数值型变量如何相互变化提供了直观的帮助。换句话说,它实际上只是一个相关矩阵的可视化表示。
函数cor()用于评估相关矩阵,库corrplot中的函数corrplot()用于基于相关矩阵创建热图。看看下面使用相同iris数据集的例子。
# use only numeric type variables
> correlations <- cor(iris[,1:4])# correlation plot
> corrplot(correlations)

Correlation matrix plot
从刻度可以看出,大的正相关值更蓝,大的负相关值更红。因此,从这个图中,看起来Petal.Length和Petal.Width是强相关的,并且看起来Petal.Length和Sepal.Length之间也有很高的相关性。注意对角线是完全正相关的,因为它代表了变量与自身的相关性。
虽然这些结论类似于之前用散点图得出的结论,但这种方法只是提供了一个更具体的理由来相信两个属性是相关的。
经历这个理解数据的过程是至关重要的,不仅仅是因为我提到的原因。它最终也可能帮助你在选择型号时做出明智的决定。我在本文中概述的方法和过程是我在获得新数据集时最常用的一些方法和过程。您可以使用数据集探索和试验更多的可视化方式。不要退缩。你只是想看看你的数据并理解它。
我希望这篇文章有助于提供一些关于什么是探索性数据分析以及为什么经历这个过程很重要的见解。
探索国际足联
“足球的重要之处在于,它不仅仅是足球。”~特里·普拉切特爵士。
足球或英式足球,不仅仅是一项游戏,它是许多人的一种情感。人们追随他们最喜爱的俱乐部不亚于他们的宗教!伟大的球员受到全世界的称赞。但是并不是所有人都知道这些球员的工资是多少?,是什么促成了它们的市场价值?让我们一起来试着回答这些和类似的问题。因此,没有进一步的原因,让我们开始吧!
国际足球协会联合会(国际足联)自称是足球协会、足球联合会、沙滩足球和电子足球的国际理事机构。使用国际足联的 2019 年球员数据集,我们将尝试回答一些有趣的问题。
Kaggle 笔记本同样可以在这里找到。而这里的是 Github 的链接,供你参考(复制下文)。要完全跟上,我们建议你分叉 Kaggle 笔记本/Github 回购。我们还提供了文档的链接,以进一步了解所用函数的技术细节。
看&感受数据
在进行所有花哨的分析之前,了解数据的外观和感觉是非常重要的。该数据集的概述可在此处找到。在导入必要的库并使用' df.head()'之后,我们得到了下面的输出(对不起,它不能滚动,它只是一个视图)

进一步检查数据集中所有可用的属性(字段)

从上面可以清楚地看到,根据我们的需要,我们当然需要删除某些列(字段),并且可能进一步清理数据。但是我们现在将把它放在一边,继续定义我们需要使用这个数据集来回答的问题。
你可以明确地看到,这个数据集可以提出几个问题,这取决于需求、感知和你需要完成的目标。以下是我们想出的问题-
球员的市值和工资有关系吗?
在查看数据后,我们决定进行一些数据清理和格式化。准备工作完成后,我们绘制了市场价值与工资的关系图(如下)。

可以清楚地看到,通常随着市场价值的增加工资也会增加,但我们也有更高的工资和接近零的市场价值!裁决- 市场价值确实在一定程度上影响球员的工资。
球员们最喜欢哪只脚,这对他们的定位有什么影响?
我们发现在我们的数据集中,不到 25%的球员是左撇子(如下图所示)。

为了检查运动员的偏好脚是否对运动员的位置有任何影响,我们采用了按运动员的位置分组的偏好脚的比例。

从上面可以看出,除了少数例外,左脚和右脚的比例是相同的。也就是说,无论你是左撇子还是右撇子,职位的分布都没什么关系,一个职位对另一个职位的需求大致相同。
进一步探究,根据脚的前 5 个位置(查看下面),我们发现 CB(中后卫)是第三个最受欢迎的位置,st(前锋)在这两个位置中都排在前 5 位。虽然有一些惊人的不同,像守门员大多是右脚!威尔第-是的,脚确实有影响,但只是很少,不是很实质性。

此外前锋、门将和中后卫是球员数量排名前三的位置(参考下面的截图)!

我们能根据一个球员的属性(比如准确性、射门能力、反应、运球等)预测他的价值吗?
诸如“首选脚”、“位置”、“传中”、“射门”、“头球精准”、“短传”、“截击”、“运球”、“弧线球”、“控球精准”、“长传”、“控球”、“加速”、“冲刺速度”、“敏捷度”等特征被选择。
使用一键编码对位置和首选脚列进行编码,并在格式化数据后,删除 nan(nan 是数据不存在的空值);我们分割数据,并尝试使用 RandomForestRegressor (集成学习器)和 GridSearch 进行预测(这就像在超参数调整的最佳参数列表中逐个搜索)。我们获得了“0.42”的 R 平方分数(模型评估)。
注-该模型可以进一步改进,使用不同的算法和/或特征工程。
同样使用相互信息回归器,我们发现以下是决定一名球员价值的 5 个最重要的特征-反应、控球、沉着、运球和短传。裁决- 并不是所有的特征都同样有用,同样一个人可以在给定足够的数据和玩家属性的情况下预测市场价值。
此外,我们还可以从数据中提出相当直接的问题(假设我们有适量的数据)。下面是我们尝试的两个这样的问题,后面是结论。
工资中位数最高的俱乐部(前 11 名)?

解约条款最大的球员(前 11)?

结论
给定 FIFA 19 球员数据集,可以问几个问题。上面我们提出了 5 个问题,我们试图回答,你可能对同一个问题不感兴趣,或者可能喜欢从不同的角度探索数据集。我们在这篇博文中的探索只是冰山一角,通过先进的机器学习技术加上正确的问题集,可以实现和理解很多东西!您可以随意使用笔记本这里或这里并摆弄数据集。
希望您喜欢阅读这篇博文,上面的 EDA 向您概述了如何处理某个数据集以及可以使用的一些技术。
探索与熊猫的足球夏季转会活动
欧洲前 25 大支出足球队的转会交易

Image Courtesy of Sandro Schuh via Unsplash
探索夏季转会的有用熊猫特征
夏季转会窗口为欧洲足球队提供了招募关键球员的机会,以加强他们各自的阵容,迎接即将到来的赛季。边缘和破坏性的球员也可以被抛弃,被租借到不同的俱乐部去积累经验。
为了深入了解欧洲最大的 25 家俱乐部的转会交易,我搜集并整理了每支球队的关键信息。这些信息包括每个团队的支出和收入。此外,我还想知道与球员年龄相关的招募策略。抓取的数据如下所示。
本教程将演示如何使用简单、直观的 Pandas 功能和特性来研究数据。另请注意,截至 2019 年 8 月 13 日,此信息可能会更改和更正。
西班牙的西甲联赛、意大利的意甲联赛、德国的德甲联赛和法国的法甲联赛都在 9 月 2 日的不同时间有转会截止日期。

1.将对象数据类型转换为浮点数据类型
在开始任何数据分析之前,检查每一列都是数值数据类型是很重要的。df.dtypes 属性表明,“Income”列是一个 Object (string)数据类型。Pandas 将我的 Excel 文件中的“Income”列解析为 object 数据类型,因为某些球队的条目(连字符)是非数字的,例如上面显示的索引为 8 的阿斯顿维拉。

要转换这个对象列,有必要使用 to_numeric 函数,并告诉 Pandas 通过使用 errors = ' compete '将任何无效输入转换为 NaN 值。如果知道 NaN 值实际上表示 0,可以使用。将 0 作为参数传递的 fillna(0)方法。
现在,当使用 df.dtypes 检查数据类型时,income 列是一个 float 数据类型,现在可以用于以后基于数字的操作。在数据框中,在指数 8 处,阿斯顿维拉的收入现在可以被视为 0,与之前显示的连字符相对。

2.新列和列重新排序
球员支出和球员销售所得之间的净差额很容易计算,但它让我们对欧洲 25 家最大支出者的财务转移交易有了有趣的了解。
新列“Net_Difference”是通过从支出列中减去收入列创建的。为了便于阅读,最好让 Net_Difference 列靠近它所引用的两个列。

数据帧的列被转换成列表,并且数据帧 df 根据索引列被重新分配。这里,前三列保持不变,但最后一列(用 python index -1 表示)跟在后面,最后一列包含特定于年龄的数据。通过打印数据帧的头部,信息可以更直观地对齐以便解释。

3.过滤从描述方法输出的数据
描述方法给出了数据集的数字数据摘要。但是,如果我们想要截断这个输出,只需使用。loc 函数,并根据需要过滤行和列。
在下面显示的输出中,我希望只看到具体关于年龄的数据快照,并且我只对该快照中的 min 到 max 行感兴趣。

4.将连续数据转换为分类数据
收入列可以用来创建一个新的收入类别数据列。在这里,可以使用 pd.cut 函数将收入列中的连续数据分成-1–40、40–80 和 80–350 范围内的区间。我给这些箱子贴上了标签:低、中、高。
这代表了每个俱乐部收到的收入是低、中、高。现在,快速扫一眼牌桌就能发现哪些球队为他们各自的球员获得了高收入。

5.设计数据框架的样式
对数据帧进行样式化可以增加视觉冲击力并有助于数据解释。在 githib gist 中显示的示例代码中,我展示了各种样式化 DataFrame 的方法。例如,要为列添加背景渐变,可以使用。background_gradient 属性,这个渐变将创建一个指示收入趋势的信息性配色方案。蓝色越深,收入越高。
此外,我为每个列值添加了一个横条,以指示该团队在净差额列中是盈利还是亏损。标题也可以添加到数据帧中,以告知观众具体信息的内容。

6.招聘策略并引用 query()字符串中的变量
下面 github gist 的代码片段的第一行显示了对列进行重新排序的另一种方法。
我还确定了到达年龄和离开年龄的平均值。
了解哪些球队正在招募年龄低于所有 25 支球队平均年龄的球员将是很有见地的。
为此,我创建了一个名为 arrival_mean 的变量,为了在查询字符串中引用它,我简单地在它前面加上了一个元字符' @ '。
看起来像皇家马德里、曼联甚至罗马这样的球队正在齐心协力签下年轻球员。这是他们今夏转会政策的信息,所有这些似乎都是为了签下优秀的年轻球员,让他们有更好的表现。


Daniel James (left) and Aaron Wan-Bissaka (right) are two 21-year old Man Utd Summer signings
除此之外,数据显示排名前 25 的球队正在招募的球员平均比他们释放的球员年轻大约 2 岁!
摘要
本教程展示了熊猫在数据分析和解释方面的一个用例。样式化和创建分类列可以简化数据解释,而在查询字符串中引用变量可以为任何调查的数据集增加有价值的洞察力。
探索 R 中的高图表
使用《我如何遇见你的母亲》中的数据可视化趋势和模式
这篇文章最初是作为探索性的探索开始的,目的是为了理解 r 语言中的可视化数据。随后是一系列的实验、测试和探索。在此期间,我还重新观看了我最喜欢的节目《我是如何遇见你母亲的》,这次是看一些重复出现的模式&它留下的数据集。在这两种相似性之间建立联系的需要促使我记录并分享这种学习,这本身仍然是这篇文章的灵感来源。
一般的 R viz 空间目前是相当令人兴奋的,g gplot2 主宰了与 Hadley Wickham 的商标学校的游戏,使复杂的操作非常轻盈。它能够快速可视化趋势,并定制您想要的任何东西,这使得它成为一个可靠的工具。 Plotly 另一方面,让你建立非常美丽的 D3 情节,特别是网站,仪表板。它允许您灵活地悬停键盘或鼠标并查看数据标签,并允许您自定义缩放以查看特定细节,使其成为 R shiny apps & markdown 文档的典范。
2009 年进入数据 viz 空间的是 D3JS 模块“Highcharts ”,其目前的客户吹嘘脸书、微软和 Stack Overflow。
Highcharts 的故事也许是一个时代的故事。它的制造商 Torstein hnsi 位于一个被峡湾、山脉和溪流环绕的挪威小镇,他正在寻找一个适中的制图工具,以更新他的主页,其中包括他家在当地山区 Vikjafjellet 的积雪深度测量结果。由于对不断遇到的插件感到厌烦,他采取了启动 Highcharts 的飞跃。自 2009 年以来,它一直是该公司 Highsoft 最畅销的产品&它作为一种主要的图表工具而闻名于世。
Joshua Kunst 在 R 中的 Highcharter 包是原始 Highcharts Java Script 库的包装函数。本文利用一档以图表和 viz- 《我是如何遇见你的母亲》著称的节目的相关数据,探索了它的一些视觉功能。

HIMYM features makes use of many aesthetic charts
软件包中有两个主要功能,即 hcharts()和 highcharts(),类似于 Ggplot2 的 qplot()和 Ggplot()。前者是单键快捷方式,而后者利用 html 小工具和动画。由于本文绘制了一些非常简单的图表,hcharts()函数足以满足大多数图表的需求。我在最终的图表中使用了更复杂的 highcharts()函数来组合极坐标图和折线图。
让我们跳进来吧!-
分组柱形图
很好的老式柱形图可能是显示分类数据的最佳图表选择,理由很充分。它以一种易于阅读的方式有效地比较和对比数据。
下面我画出了 HIMYM 一伙在这个系列中喝的酒的数量。
该语法很容易导航,使用 hcharts()快捷方式,第一个命令本身就足以完成创建原始柱形图的任务,而随后的命令行增加了美观和信息的层次。这里-标题,副标题,学分&一个自定义主题。
这里要注意的另一个方面是广泛使用了马格里特的(它的共同开发者 Stefan Bache 在短片中坚持说它应该用复杂的法国口音发音)% > %,即“管道”,使得语法对 tidyverse 用户友好。
Number_of_drinks %>%
hchart(type = 'column', hcaes(x = `HIMYM Character`, y = `Number of Drinks`, group = Type)) %>%
hc_title(text = "How much did the gang really drink?",
style = list(fontWeight = "bold", fontSize = "30px"),
align = "center") %>%
hc_subtitle(text =
"'All I want was to have a regular beer at my regular bar with my regular friends in my regular city.'-Ted Mosby",
style = list(fontWeight = "bold"),
align = "center") %>%
hc_credits(enabled = TRUE,
text = "Data Source: HIMYM;[https://imgur.com/user/haaaaaaaveyoumetted](https://imgur.com/user/haaaaaaaveyoumetted)",
style = list(fontSize = "10px")) %>%
hc_add_theme(hc_theme_ffx())

Number of drinks by types of drinks & show characters.
饼状图&彩色面积图
幸运的是,highcharter 包的作者可能是该节目的粉丝,并在包中包含了一些基于该节目的数据集。对于这两个图表,我使用了那些数据集——马歇尔最喜欢的条形图和馅饼。在节目中,Marshall 以饼状图和条形图的形式向大家展示了他对自己喜欢的棒饼的偏好。在这里,他的偏好以饼状图的形式显现出来&彩色区域图。使用的语法与创建的第一个图表非常相似。我已经根据十六进制代码给这些图表添加了定制的颜色。尽管可以将自定义主题编码到图表中,但软件包本身有一个巨大的迷人主题库。在整篇文章中,我使用了“ffx”主题,灵感来自 Mozilla Firefox 浏览器。
#pie chartfavorite_bars %>% hchart(type = ‘pie’, hcaes(bars, percent)) %>% hc_title(text = “Marshall’s Favorite bars”,
align = “center”,
style = list(fontWeight = “bold”, fontSize = “30px”)) %>%
hc_tooltip(enabled = T) %>% hc_subtitle(text = “In Percentage of Awesomness!”,
align = “center”,
style = list(fontWeight = “bold”)) %>% hc_add_theme(hc_theme_ffx()) %>% hc_credits(enabled = T,text = “Data source:HIMYM”)#colored area graph
favorite_pies %>% mutate( segmentColor = c("#000004", "#3B0F70", "#8C2981", "#DE4968", "#FE9F6D"))%>% hchart(type = 'coloredarea', hcaes(x = pies, y = percent))%>%
hc_title(text = "Marshall's favorite pies",
style = list(fontWeight = "bold", fontSize = "30px"),
align = "center") %>% hc_subtitle(text = "In Percentage Of Tastiness!",
style = list(fontWeight = "bold"),
align = "center") %>% hc_add_theme(hc_theme_ffx())

Marshall’s favorite bars & pies- in a pie chart & colored area graph respectively
气泡图
倒数第二个图表是一个气泡图,直观地显示了收视率最高的剧集。与散点图不同,气泡图允许绘制 3 D 数据——气泡的大小增加了数据的维度。这里-X 轴代表剧集的名称,Y 轴代表剧集的评分,而气泡代表 IMDB 上的投票数。这有助于我们推断,尽管《三天法则》被评为十大剧集之一,但它的票数很少,因此必须谨慎解读。像这样的标注和注释也可以添加到图表中来指出某些事实——HC _ annotation()函数也允许这样做。
HighestRated %>% hchart(type = “bubble”, hcaes(x = ‘Episode’, y = Rating, size = Votes, color =
Votes), maxSize = “20%”) %>% hc_title(text = “Top Rated Episodes of HIMYM”,
style =list(fontWeight = “bold”, fontSize = “30px”),
align = “center”) %>% hc_subtitle(text = “What was your favorite episode?”,
align = “center”,
style =list(fontWeight = “bold”)) %>% hc_credits(enabled = T, text = “Size by Number of Votes,
Colored by Rating.
| Data Source- IMDB”) %>% hc_add_theme(hc_theme_ffx())

Top Rated episodes of the series, by Ratings & Votes on IMDB
极线图
最后,极线图被用来衡量人们对备受争议的 HIMYM 大结局的反应。
这个数据集有一个有趣的旋转。《HIMYM》的大结局播出后遭到了一些严重的嘲笑(这里读,这里读,这里读&这里读)。事实上,即使是为这篇文章做研究,也激起了我在 5 年多前看完大结局后第一次感受到的愤怒。但是这些数据,就像人们有时知道的那样,告诉我们一个惊人的变化的故事。
社交分析平台 Canvs 研究的大多数人对结局感到乐观。Canvs 算法利用人们对 twitter 反应的情感分析来计算人们对娱乐形式的感受。
下面的图表以极坐标图的形式显示了这一数据集,将最常分享的“观点”用粉红色着色,即高于反应平均阈值的反应,而其余的用黄色突出显示。
highchart() %>% hc_chart(polar = TRUE) %>% hc_title(text = “HIMYM Finale Reactions”,
style = list(fontWeight = “bold”, fontSize = “30px”),
align = “center”) %>% hc_subtitle(text = “‘And that kids is the story of how I met your mother’”,
style = list(fontWeight = “bold”),
align = “center”) %>% hc_xAxis(categories = fans_react$Fans,
style = list(fontWeight = “bold”)) %>% hc_credits(enabled = TRUE,
text = “Data Source:Based on a study done by Canvs as reported by The Atlantic”) %>% hc_add_theme(hc_theme_ffx()) %>% hc_legend(enabled = FALSE) %>% hc_series(
list(
name = “Bars”,
data = fans_react$Contribution,
colorByPoint = TRUE,
type = “column”,
colors = ifelse(fans_react$Contribution < mean(fans_react$Contribution),”#ffeda0",”#c51b8a”)
),
list(
name = “line”,
data = fans_react$Contribution,
pointPlacement = “on”,
type = “line”))

HIMYM Finale reactions on twitter bucketed and visualized
关键要点-
- R 中的 Highcharter 包具有可导航的特性、可抓取的语法和高级 D3JS 视觉效果,是对 R viz 空间的一个很好的补充,目前由 graphics Ggolot2 包的语法所主导。
- 它可以使用相似的语法和参数创建各种各样的图表,如气泡图、柱形图、树状图、时序图等。
- 它不仅支持 R 对象,还使用了广受欢迎的%>% '管道'操作符,让 tidyverse 用户对它非常熟悉。这种简单的语法加上令人惊叹的视觉效果使它成为 R 闪亮应用程序和 R markdown 文档的首选工具。
代码和所有使用的数据集可以在 github 这里找到。
感谢阅读!你可以在这里联系我。
探索神经网络的工作方式并将其可视化
部署一个可以识别 Excel 手写数字的神经网络,以便所有的计算和交互都可以可视化和检查
在本文中,我们将使用一个 Excel 文件,可以通过点击此处找到。尽管您应该能够在没有该文件的情况下继续学习,但我还是强烈建议您下载它,以便更深入地探索。

Preview of the Excel file | Mikkel Duif (2019)
你有没有想过神经网络背后的数学是如何工作的?数学通常以向量和矩阵的形式出现,尽管这使学习变得更加简单,但有时很难理解你只是在数百、数千或数百万个数字上做同样的计算。我破坏了一个有 30 个神经元的单层神经网络,这样你就可以从头到尾看到所有的相互作用。你也可以看到它如何实时适应输入的变化,输入你自己的数字,看看它预测了什么。
注意:这是一个预先训练好的神经网络,所以我们现在不讨论实际训练它的所有数学问题(这要复杂得多),而只是看看如何使用训练好的神经网络的结果。此外,神经网络一直保持简单,在 1 层中有 30 个神经元,然而,对于更大的网络,它不会有很大的不同,可能只是更难跟上。我不记得这个网络的准确率,但我想象大约 90%(这对这个数据集来说不是很好)。我也没有加载实际的数字,但是你可以估计一下你自己会猜测的数字(有些数字甚至对人类来说也很难估计)。最后,本文也假设对神经网络有一些基本的了解,但是,大多数人应该能够理解。
理解数据
在我们深入研究计算之前,让我们先了解我们将使用的数据,以及神经网络的架构。
我们将使用的数据集是 MNIST 手写数字数据集,它基本上只是由人类书写的数字,然后扫描并转换为 28x28 像素的图像。我们使用的数据是基于每个像素的亮度,所以如果一个区域非常暗,它的值接近 1,没有任何墨水的区域的值接近 0。
在这里,您可以看到一个数字是什么样子,以及它对应的四舍五入到一位小数的值:

Visualizing the data | Mikkel Duif (2019)
因为我们总共有 28x28 个像素,所以总共有 784 个输入像素,这基本上就是我们的数据点。对于我们的神经网络,我们不会在矩阵中处理这些数据,而是展平图像(即,将其转换为向量),我在上面记录了四个不同输入(像素)的数量,以便您可以跟随。左上角基本上是我们向量中的第一个数,右下角是我们向量中的最后一个数。
理解模型的架构
现在我们知道了我们的数据是什么样的,让我们看看神经网络是如何对这些手写数字进行分类的。一个神经网络基本上由一个输入层(即我们的像素),一个隐藏层(这只是这个模型的一个)和一个输出层(这是模型从 0 到 9 分类的数字)组成。此外,它由权重和偏差组成,我将在图片下面简要解释。

Visualisation of Neural Network | Mikkel Duif (2019)
权重:由于每幅图像总共有 784 个像素,我们的模型中也将有 784 个输入神经元。由于 784 个神经元太多,无法在这里显示,我跳过了大部分神经元,只显示了中间的一些不只是零的输入神经元(尝试在 GIF 中找到它们)。在隐藏层,我选择了 30 个隐藏的神经元(为了简单起见,上面的图片中跳过了 20 个)。最后,我们的输出层有 10 个神经元,对应从 0 到 9 的数字。所有的神经元通过从第一个输入神经元到隐藏层中的每个神经元的权重连接。即,i nput 神经元 1 通过权重连接到隐藏层中 30 个神经元中的每一个——Input 神经元 2、等也是如此。,一直到 i nput 神经元 784 。做一些简单的数学计算,这给了我们从输入层到隐藏层总共 30 x 784 = 23,520 个权重。这些权重中的每一个都分配有一个值,它们共同决定隐藏层中的每个值。重量可以在 A1:AB870 区域的参数选项卡的 excel 文件中找到。
从隐藏层到输出层也是如此。然而,这一次我们在隐藏层中只有 30 个神经元,每个神经元只连接到 10 个输出神经元,这一次我们只有 30 x 10 = 300 个权重。少得多,但仍然太多,无法显示每一个重量。如果你还不明白这一切是如何相互联系的,不要担心,在下一节中,我将解释这一切是如何组合在一起的——但首先,我们只需要理解偏差。重量可以在 A871:A1180 区域的参数选项卡的 excel 文件中找到。
术语:从第 1 层中的神经元 1 到第 2 层中的神经元 1 的权重可以写在第一个权重的正上方,这对应于 Excel 文件的参数选项卡上的单元格 A2 的值。从最后一个输入神经元到隐藏层中最后一个神经元的权重,即权重左下方的 w(2–1,784)可以在 AB870 单元格中找到。单元格 A872 中的重量 w(3–1,1)和单元格 A1180 中的重量 w(30–10,30)。每个权重的位置并不重要,只是让您知道如何在 Excel 表格中导航。
偏差:除了权重之外,神经网络也有偏差,这是添加到每个隐藏层和外部层的值中的东西。这些偏差在上图中没有显示,但是可以在 A1181:A1222 区域的参数选项卡的 excel 文件中找到。
你可能会想,这些权重和偏差的值是从哪里来的呢?请记住,这是一个经过训练的神经网络,这意味着我们不会经历如何获得这些权重,而只是如何使用它们。如果你很想知道如何训练一个神经网络,我建议你研究一下迈克尔·尼尔森的资源,他使用了相同的数据集——他给了我很多学习人工智能的灵感。
理解计算
现在我们已经有了权重和偏好,让我们试着弄清楚如何计算我们需要什么。它实际上并不复杂,我们只需要计算 40 个不同的数字(30 个用于隐藏层,10 个用于输出层)。然而,输出层依赖于隐藏层中的计算(如果我们有更多的隐藏层,每一层将总是依赖于它前面的层)。为了保持数学符号简单,让我们将隐藏神经元的值写成这样:

Activation function for first neuron in hidden layer
注意:上标 2 并不意味着我们正在平方这个值,它仅仅意味着从第一层(下标 1)到第二层(上标 2)。
对于那些熟悉乙状结肠功能的人来说,基本上就是这样了。然而,在神经网络中,它通常被称为激活函数。让我们快速澄清一下上面等式中的字母是什么意思。
- e (简单地说就是欧拉数,一个大约等于 2.71828 的常数)
- I (输入神经元,即 784 个像素中每个像素的值——每个隐藏神经元的值相同)
- W (从每个输入像素到隐藏层的第一个神经元的权重——也是 784 个值,但是每个隐藏神经元的新值,即总共 23,520 个不同的值)
- B (属于隐藏层的第一个神经元的偏置项——对于第一个隐藏神经元,这对应于值为 0.43 的单元格 A1182)
请注意,我们取输入神经元和权重之间的点积。记住,我们有 784 个输入神经元和 784 个相应的权重(对于隐藏层中的每个神经元,权重是变化的)。输入神经元 1 的值和从输入神经元 1 到隐藏层中的神经元的权重相乘——我们对它们中的每一个都这样做,并取乘积的和,再加上偏置项。这个的负值作为欧拉数的幂,我们加 1。然后我们最后用 1 除以这些数字的和。如果我们必须提供一个包含所有数字的示例,那么这个示例会很长,但是请检查包含该数字最终值的单元格 AD2,在 Excel 中可以写成:
= 1/(1+EXP(-(sum product(number;weight _ 1 _ 1)+INDEX(bias _ 1;1)))),其中“数字”是该数字的像素值的数组,而“权重 _1_1”表示从输入层到隐藏层中的第一个神经元的权重。我给数组命名是为了让公式更有意义——如果你想研究数组,去“公式”->“在 Excel 中定义名称”,看看数组代表什么。
第一个隐藏神经元的值在图像中显示为 1.00,但这只是由于四舍五入。真的是 0.99676789。那么这到底意味着什么呢?没有任何简单的方法来解释这一点——好的一面是它确实有效。
回到等式,我们基本上只需要对隐藏层中的每个神经元(总共 30 个)应用这个,这样我们就有了隐藏层的值。对于最终的输出层来说,这样做实际上没有太大的不同,唯一的区别只是我们不再使用 784 像素作为输入——我们使用隐藏层中每个神经元的值,即我们刚刚计算的值。隐藏层中的每一个神经元都有自己的权重(A871:A1180)分配给它们(就像图中一样),输出层中的每一个神经元都有自己的偏置 (A1212:A1222) 。您可以在单元格 AE1:AE11 中找到输出图层的最终计算结果。
画你自己的数字
试着去 Excel 文件的‘Draw’选项卡画出自己的数字,看看神经网络是如何对自己的数字进行分类的。希望它应该做得更好一点,但仍然很有挑战性,试着画一个 7。

Preview of the Excel file | Mikkel Duif (2019)
我希望这篇短文和 Excel 文件对你更好地理解神经网络有所帮助。请随意留下您的评论或问题。也许将来我会写一篇关于如何训练一个神经网络并得出权重和偏差的新文章。
使用 Keras 和 TensorFlow 探索数据扩充
在下一个深度学习项目中使用数据增强的指南!

Photo by Jon Tyson on Unsplash
数据扩充是一种用于通过使用裁剪、填充、翻转等技术来增加数据量的策略。
数据扩充使得模型对于微小的变化更加健壮,因此防止模型过度拟合。
将增加的数据存储在内存中既不实际也没有效率,这就是 Keras 的ImageDataGenerator类(也包含在 TensorFlow 的高级 api 中:tensorflow.keras)发挥作用的地方。ImageDataGenerator通过实时数据增强生成批张量图像数据。最棒的是。只是一行代码!
生成器生成的输出图像将具有与输入图像相同的输出尺寸。
下面是一个辅助脚本,我们将使用它来直观地展示使用ImageDataGenerator类所能实现的一切。

1.旋转

通过指定rotation_range,生成的数据被随机旋转+rotation_range到-rotation_range范围内的一个角度(以度为单位)。
2.宽度移动

width_shift_range是一个介于0.0和1.0之间的浮点数,它指定了图像随机向左或向右移动的总宽度分数的上限。
3.高度移动

除了图像是垂直移动而不是水平移动之外,与宽度移动完全一样。
4.聪明

brightness_range指定随机选择亮度偏移值的范围。0.0的亮度对应绝对无亮度,1.0对应最大亮度。
5.剪切强度

剪切变换会倾斜图像的形状。这不同于旋转,因为在剪切变换中,我们固定一个轴,并以某个角度(称为剪切角)拉伸图像。这在图像中产生了一种“拉伸”,这在旋转中是看不到的。shear_range以度为单位指定倾斜的角度。
6.一款云视频会议软件

通过zoom_range参数获得随机缩放。小于1.0的缩放会放大图像,而大于1.0的缩放会缩小图像。
7.频道转换

信道偏移通过从channel_shift_range指定的范围中选择一个随机值来随机偏移信道值。
8.水平翻转

生成器将生成图像,图像将随机水平翻转。
9.垂直翻转

除了水平翻转,我们还可以应用垂直翻转。
但是那些我们没有任何价值的点呢?

我们有几个选项,从中我们可以选择我们希望如何填充这些区域。
1.最近的
这是默认选项,选择最接近的像素值,并对所有空值重复使用。(例如 aaaaaaaa | abcd | dddddddd)

2.显示
该模式创建一个“反射”,并以已知值的相反顺序填充空值。(例如 abcddcba|abcd|dcbaabcd)

3.包装
除了反射效果,我们还可以通过将已知点的值复制到未知点来创建“包裹”效果,同时保持顺序不变。(例如 abcdabcd|abcd|abcdabcd)

4.常数
如果我们想用一个常数值填充位于输入边界之外的所有点,这种模式可以帮助我们实现这一点。常量值由cval参数指定。

但还有更多!
您可以直接从该课程中获得一些额外的好处。一些例子包括将数据归零(featurewise_center 、 samplewise_center)和归一化(*featurewise_std_normalization* 、 *samplewise_std_normalization*)。这些变量可以通过将它们的布尔值传递给ImageDataGenerator类来设置。我们还可以通过指定rescale参数来重新调整这些值,它会乘以所有的值。
此外,还有一个参数preprocessing_function,使用它您可以指定自己的自定义函数来执行图像处理。多酷啊!
如果你喜欢这篇文章,你可能也会喜欢 VGGNet vs ResNet:消失渐变问题的清晰答案!
参考
[1] Keras 文档
[2] 张量流文档
[3] 剪切变换
用交互式可视化探索印度超级联赛

可视化数据的艺术和实践在弥合人机差距以有意义的方式传递分析洞察力方面变得越来越重要。
——艾德·邓比尔
介绍
I 印度超级联赛(IPL) ,印度职业二十强(T20)板球联赛成立于 2008 年。该联盟以循环小组和淘汰制为基础,在印度主要城市都有球队。
这是在machinehack.com举办的 IPL 数据可视化挑战赛(2008–2018)的探索。我用 Tableau 做了可视化。
关于数据
该数据集包含 2008 年至 2018 年的以下信息。
- 匹配日期—匹配的日期和年份
- Match_number —每个赛季的比赛号码
- Macth_venue —体育场名称和位置
- 匹配时间—晚上或白天/晚上
- Toss_winner —赢得投掷的团队名称
- 决定是击球还是投球
- 第一队——先击球的队
- 团队 1 得分—团队 1 得分
- 第二队——第二个击球的队
- 团队 2 得分—团队 2 得分
- Winning_team —赢得比赛的团队
- winning _ margin——每个队赢了多少分?
在这篇文章中,我们试图通过可视化来理解 IPL 球队,比赛和获胜模式。我已经用这个数据集做了初步的分析,但是还有很多工作要做。
以下是分析所遵循的步骤:
Python 中的数据读取、数据预处理和数据清理。完整的源代码在 这里有 ,万一你想看的话。
我制作了大量可视化的工作表,探索 Tableau 中数据的各个方面。Medium 没有给我们嵌入 HTML 或 javascript 代码的选项,因此你在这个博客中看到的是一个截图。然而,我所有的可视化和仪表板都可以在这里看到
交互式可视化和分析
谁是最有胜算的 IPL 队伍?
从这个圆形的条形图中,我们可以看到孟买印度人队和钦奈超级国王队是 IPL 历史上最成功的球队,其次是加尔各答夜骑队。从 2008 年到 2018 年,孟买印度人赢得了 97 场比赛,钦奈超级国王队赢得了 90 场比赛,加尔各答骑士队赢得了 86 场比赛。

IPL 赛季 Top Toss 赢家?
从这个包装好的泡泡中,可以看出孟买的印度人赢得了 IPL 中最高的投掷数,其次是加尔各答的夜间骑手和德里的夜魔侠。

在印度各地举行的多场比赛?
下面的地图显示了印度各地的比赛。最多的比赛在孟买、加尔各答、班加罗尔和德里举行。此外,2009 和 2014 赛季发生在南非和阿联酋,同样没有显示在下面的地图。

IPL 冠军?
钦奈超级国王队和孟买印度队三次赢得 IPL 冠军。加尔各答骑士骑手两次获得冠军。数据集中有 12 支球队。12 支队伍中,只有 6 支队伍获得了冠军。皇家挑战者、德里夜魔侠、XI 旁遮普国王、浦那勇士、古吉拉特雄狮和高知塔斯克从未获得过冠军。

每个体育场打了多少场比赛?
根据下面的棒棒糖图,M Chinnaswamy 体育场举办了最多的比赛(76 场),其次是伊甸园花园、Feroz 体育场和 Wankhede 体育场。

每个城市的平均分是多少?
下面的蝴蝶图显示,班加卢鲁的得分最高,其次是达兰萨拉和拉杰科特。这显然显示出对这些城市的偏爱。

平均团队 1_ 分是多少?
根据甜甜圈图表,钦奈超级国王和孟买印度人在第一次击球时获得了高分。

IPL 总决赛——击球第一的团队成绩是多少?
Sunrisers Hyderabad 在 IPL 决赛中得分最高,其次是 Chennai Super Kings 和孟买印度人。孟买印度人在两个赛季的 IPL 决赛中得分最低,其次是德干充电器。

每个赛季进行多少场比赛?
棒棒糖图显示了 2012 和 2013 赛季的最高比赛次数,随后是 2011 赛季。

球队每个赛季的最低和最高分是多少?
以下两张图表显示了一支球队在 IPL 历史上的最低和最高得分。德里夜魔侠在 2008 年和 2011 年两个赛季中得分最低(56 分)。加尔各答夜骑士在 2008 年举办了 67 场,皇家挑战者在 2011 年举办了 56 场。

皇家挑战者队在 2013 年和 2016 年获得了 IPL 历史上最高的 263 分和 248 分。

最成功的 IPL 团队?
钦奈超级国王队是 IPL 历史上最成功的球队。尽管停赛两年,但他们三次获得冠军,五次获得亚军,两次获得季后赛资格。

上述可视化是在 Tableau 中创建的,只是一个初步的。然而,还可以做得更多。你可以在这里找到所有的可视化
探索用于机器学习的 JetBrains 数据仓库
Datalore 是一款来自 JetBrains 的数据探索工具!

Photo by Luke Chesser on Unsplash
JetBrains Datalore 可能是你的下一个 Google Colab 或 Jupyter 的替代品😌。目前,处于测试阶段的 Datalore 是 JetBrains 提供的一个数据分析 web 应用程序。今天,我们将讨论 Datalore 的一些特性,并探索它的功能。
1.设置 Datalore.io
转到 Datalore.io 并完成注册过程。接下来,您将看到一个主页,我们可以在上面保存我们的工作簿(笔记本😕 ).

Datalore’s Home page
通过上面的三个按钮,我们可以为我们的项目创建、导入工作簿。
2.工作簿环境
我们将创建一个简单的工作簿来测试数据知识。我们将写下一段张量流代码✌️来检查工作。

Datalore workbook
我们可以为我们的工作簿选择不同的内核。这就是 Datalore 与 Jupyter 不同的地方。我们可以有一个 Datalore 内核,它能够实时执行我们的代码😳。

The IPython Kernel works like Jupyter. The Datalore kernel has something different for us.
您可能会发现我们在 Datalore 内核特性方面的问题。对于我们的讨论,我们将使用 IPython 内核。如上图所示,我们有多个基于 RAM 大小的实例。

Managing libraries
我们可以管理 Datalore 中所有可用的各种包。要安装一个新的软件包,我们可以按照我们为 Jupyter 笔记本所做的正常程序。喜欢!pip install pillow。

File Uploader
对于任何机器学习项目,我们的下一个要求是将文件上传到工作簿的能力。这可以通过选择 【工具】- >文件上传选项 来完成。上传您的所有文件,我们可以在工作簿中访问它们。
3.发布我们的工作簿
这是 Datalore 的一个很好的特性。转到 文件- >发布 。Datalore 为您的工作簿创建了一个整洁的演示文稿,您可以与他人共享😎。我们可以在 view.datalore.io 上查看我们发布的工作簿。如果您使用过 Kaggle 内核,那么您可能会注意到一些相似之处。

Published Workbook
你可以包括图表,可视化,然后发布笔记本。开发人员可以轻松地将自己与工作簿和数据可视化连接起来。

A Published workbook with a plot
等等,还有…
希望你喜欢 Datalore!
Datalore’s Live kernel execution.
Datalore 是我们数据科学项目的一个很好的工具。如果你能花💰在他们提供的各种实例(GPU)上,你可以充分利用它。感谢阅读,机器学习快乐!
探索学习率以提高 Keras 中的模型性能
学习率是一个超参数,它控制每次更新模型权重时响应估计误差而改变模型的程度。选择学习率是具有挑战性的,因为非常小的值可能会导致长时间的训练过程而停滞不前,而非常大的值可能会导致过快地学习一组次优权重或不稳定的训练过程。
迁移学习
我们使用迁移学习将经过训练的机器学习模型应用于不同但相关的任务。这在深度学习中工作得很好,深度学习使用由层组成的神经网络。特别是在计算机视觉中,这些网络中的早期层倾向于学习识别更一般的特征。例如,它们检测边缘、梯度等。
这是一种经过验证的方法,可以在计算机视觉任务中产生更好的结果。大多数预先训练好的架构(Resnet、VGG、inception 等。)是在 ImageNet 上训练的,根据您的数据与 ImageNet 上的图像的相似性,这些权重将需要或多或少地进行大的改变。
在 fast.ai 课程中,杰瑞米·霍华德探索了迁移学习的不同学习速率策略,以提高速度和准确性方面的模型性能。
1.差异学习
差分学习背后的直觉来自于这样一个事实,即在微调预训练模型时,更接近输入的层更有可能已经学习了更多的一般特征。因此,我们不想改变他们太多。然而,随着我们向模型的更深处移动,我们会想要更大程度地修改权重,以便适应手边的任务/数据。
短语“不同的学习速率”意味着在网络的不同部分使用不同的学习速率,在初始层中学习速率较低,在后面的层中逐渐增加学习速率。

Sample CNN with Differential Learning Rate
在 Keras 中实施差异学习率
为了在 Keras 中实现差分学习,我们需要修改优化器源代码。
Adam Optimizer source code in Keras
我们修改了上面的源代码,加入了以下内容—
- init 函数被修改为包括:
- 分割层: split_1 和 split_2 分别是第一次和第二次分割的层的名称
- 修改参数 lr 以接受学习率列表——接受 3 个学习率的列表(因为架构分为 3 个不同的部分)
- 在更新每一层的学习速率时,初始代码遍历所有层,并为其分配一个学习速率。我们对此进行了修改,以包含不同层的不同学习速率
Updated Optimizer Code with Differential Learning Rate
2.重启随机梯度下降(SGDR)
随着每一批随机梯度下降(SGD),理想情况下,网络应该越来越接近损耗的全局最小值。因此,随着训练的进行,降低学习率是有意义的,使得算法不会超调,并且尽可能接近最小值。利用余弦退火,我们可以按照余弦函数降低学习速率。

Decreasing learning rate across an epoch containing 200 iterations
SGDR 是学习率退火的一个最新变体,由 Loshchilov 和 Hutter [5]在他们的论文“Sgdr:带重启的随机梯度下降”中引入。在这项技术中,我们不时地突然提高学习率。下面是一个用余弦退火重置三个均匀间隔的学习率的例子。

Increasing the learning rate to its max value after every 100 iterations
突然增加学习率背后的基本原理是,这样做时,梯度下降不会卡在任何局部最小值处,并且可以在朝向全局最小值的途中跳出它。
每次学习率下降到它的最低点(上图中每 100 次迭代),我们称之为一个周期。作者还建议用某个常数因子使下一个周期比前一个周期长。

Each cycle taking twice as many epochs to complete as the prior cycle
在 Keras 中实施 SGDR
使用 Keras 回调,我们可以更新学习率以遵循特定的函数。我们可以参考 这个已经实施循环学习的回购 。
请查看 github 库 了解差分学习和 SGDR 的完整代码。它还包含一个测试文件,用于在一个样本数据集上使用这些技术。



浙公网安备 33010602011771号