使用 Tensorflow 对象检测控制第一人称射击游戏
在这篇文章中,我将解释我如何使用 tensorflow 的对象检测模型来玩经典的 FPS 游戏《反恐精英》。
Playing Counter Strike with my webcam recording and a Tensorflow Object Detection model.
不久前,我偶然发现了这个非常有趣的项目,在这个项目中,文章作者使用一个网络摄像头来玩名为真人快打的经典格斗游戏。他利用卷积神经网络和递归神经网络的组合来从他的网络摄像头记录中识别踢和打的动作。然后,他将模型的预测转化为游戏中要采取的适当行动。玩游戏的方式真的很酷!
Playing Mortal Kombat with webcam and deep learning. Original article can be found here.
以此为灵感,我创建了一个类似的控制器界面,可以使用 Tensorflow 对象检测模型的预测来玩第一人称射击游戏。
这个项目的代码可以在我的 Github 页面上找到,下面也有链接。
[## ChintanTrivedi/DeepGamingAI _ FPS
一款使用网络摄像头和深度学习来玩游戏的 FPS 游戏控制器——ChintanTrivedi/DeepGamingAI _ FPS
github.com](https://github.com/ChintanTrivedi/DeepGamingAI_FPS)
该控制器设计用于处理游戏中的以下动作:-
1。瞄准枪
首先,为了在游戏中环视四周,我在一个网球上使用了对象检测。根据屏幕上检测到的球的位置,我们可以设置鼠标的位置,这反过来控制我们的玩家在游戏中的目标。
2。移动播放器
接下来,为了指示玩家在游戏中向前移动,我正在使用我的食指的检测。当手指指向上方时,玩家向前移动,再次放下手指会停止玩家的移动。
3。射击枪
这里支持的第三个动作是开枪。因为在瞄准和移动的时候两只手都用光了,所以我用张嘴的姿势来控制枪的射击。
目标检测模型
这里用于物体检测的模型教程是 MobileNet 结合单镜头多盒检测器 (SSD)进行图像定位。它被训练成各种各样的图像,比如网球、竖起的手指和张着嘴的牙齿。它设法以合理的速度运行,使得实时使用轻量级模型来控制我们的游戏成为可能。
模型性能
就模型的性能而言,玩游戏时手指和牙齿的检测似乎相当可靠。主要的问题是要把枪准确地瞄准我们想要的地方,因为模型运行的帧率比游戏低得多,因此鼠标的移动是跳动的,不是很平滑。此外,对朝向图像边缘的球的检测很差,使其不可靠。这个问题可以通过调整模型来解决,以可靠地检测离摄像头稍远的物体,这样我们就有足够的空间来移动网球,从而更好地控制我们的目标。
这款机型的游戏内性能结果可以在我的 YouTube 频道上找到,下面嵌入了视频。
结论
我觉得只用网络摄像头而没有额外硬件来控制游戏的整体体验仍然是一个非常诱人的概念。由于深度学习模型的进步,这已经变得非常可能。这种控制机制的实际实现需要完善,以便取代玩这些游戏的更常规的方式。我可以看到这个想法的完美实现是玩 FPS 游戏的一种有趣的方式。
感谢您的阅读!如果你喜欢这篇文章,请在媒体、 GitHub 上关注我,或者订阅我的 YouTube 频道。
使用张量流对象检测进行逐像素分类
用数据做酷事!
过去,我使用 Tensorflow 对象检测 API 来实现对象检测,输出是图像中不同感兴趣对象周围的边界框。更多请看我的文章。Tensorflow 最近增加了新功能,现在我们可以扩展 API 来逐个像素地确定感兴趣对象的位置。请参见下面的示例:
Tensorflow Object Detection Mask RCNN
代码在我的 Github 上。
实例分割
实例分割是对象检测的扩展,其中二进制掩码(即对象与背景)与每个边界框相关联。这允许关于框内对象范围的更细粒度的信息。
那么我们什么时候需要这种额外的粒度呢?我想到的一些例子有:
I)自动驾驶汽车——可能需要知道另一辆汽车在路上的确切位置,或者过马路的人的位置
ii)机器人系统——如果机器人知道两个部件的确切位置,那么它们将会表现得更好
有几种实现实例分割的算法,但是 Tensorflow 对象检测 API 使用的算法是 Mask RCNN。
屏蔽 RCNN
让我们从简单介绍一下 Mask RCNN 开始。
Mask RCNN Architecture
快速 RCNN 是一种用于目标检测的非常好的算法。更快的 R-CNN 由两个阶段组成。第一阶段,称为区域提议网络(RPN),提议候选对象包围盒。第二阶段本质上是快速 R-CNN,使用 RoIPool 从每个候选框中提取特征,并执行分类和包围盒回归。这两个阶段所使用的特征可以被共享以用于更快的推断。
屏蔽 R-CNN 在概念上很简单:更快的 R-CNN 对每个候选对象有两个输出,一个类标签和一个边界框偏移量;为此,我们添加了第三个分支,输出对象遮罩—这是一个二进制遮罩,指示对象在边界框中的像素位置。但是额外的遮罩输出不同于类和框输出,需要提取对象的更精细的空间布局。为此,RCNN 使用下面描述的完全卷积网络 k (FCN)。
Fully Convolutional Network Architecture
FCN 是一种流行的语义分割算法。该模型使用各种卷积块和最大池层,首先将图像解压缩到其原始大小的 1/32。然后,它在这个粒度级别上进行分类预测。最后,它使用采样和反卷积层来调整图像的大小到原始尺寸。
简而言之,我们可以说 Mask RCNN 将两种网络——更快的 RCNN 和 FCN——结合在一个大型架构中。模型的损失函数是进行分类、生成包围盒和生成掩模的总损失。
掩模 RCNN 有几个额外的改进,使它比 FCN 更准确。你可以在他们的论文中读到更多关于他们的信息。
实施
图像测试
为了在图像上测试这个模型,你可以利用 tensorflow 网站上分享的代码。我测试了他们最轻量级的型号——mask _ rcnn _ inception _ v2 _ coco。下载模型升级到 tensorflow 1.5 就行了(这个很重要!).请参见下面的示例结果:
Mask RCNN on Kites Image
视频测试
对我来说,更有趣的练习是在 you tube 的样本视频上运行模型。我用 keepvid 从 you tube 下载了几个视频。我喜欢处理视频文件的图书馆电影。
主要步骤是:
- 使用 VideoFileClip 函数从视频中提取每一帧
- fl_image 函数是一个很棒的函数,它可以获取一个图像并用修改后的图像替换它。我用这个对从视频中提取的每张图像进行物体检测
- 最后将所有修改后的剪辑图像组合成一个新的视频
你可以在我的 Github 上找到完整的代码。
接下来的步骤
关于进一步探索这个 API 的几个额外想法:
- 尝试更精确但开销大的模型,看看它们能带来多大的不同
- 使用 API 在自定义数据集上训练掩码 RCNN。这是我接下来要做的事情。
给我一个❤️,如果你喜欢这个职位:)希望你拉代码,并尝试自己。
我有自己的深度学习咨询公司,喜欢研究有趣的问题。我已经帮助许多初创公司部署了基于人工智能的创新解决方案。请到 http://deeplearninganalytics.org/的来看看我们。
你也可以在https://medium.com/@priya.dwivedi看到我的其他作品
如果你有一个我们可以合作的项目,请通过我的网站或 info@deeplearninganalytics.org 联系我
参考文献:
使用 tf。在 TensorFlow 中打印()
我听说你想印一些张量。
我知道你每次都以正确的方式使用调试器,并且永远不会使用 print 语句来调试你的代码。对吗?
因为如果您这样做了,您可能会发现 TensorFlow 的Print
语句与典型的 print 语句不太一样。
今天我将展示 TensorFlow 的打印语句是如何工作的,以及如何最大限度地利用它们,希望能帮你解决一些困惑。
TensorFlow 打印
在编写 TensorFlow 代码时,有几种方法可以将内容打印出来。当然,还有经典的 Python 内置的print
(或者函数print()
,如果我们是 Python 3 的话)。然后还有 TensorFlow 的打印功能,tf.Print
(注意大写的P
)。
当使用 TensorFlow 时,重要的是要记住一切最终都是图形计算。这意味着如果您使用 Python 的print
打印 TensorFlow 操作,它将简单地显示该操作的描述,因为还没有任何值通过它传递。如果已知的话,它通常还会显示该节点中预期的维度。
Hmm, where are the values? At least we have the shape and type 😃
如果你想打印执行时流经图形特定部分的值,那么我们需要使用tf.Print
。
构建您的打印节点
我们通常认为打印是我们在事情发生后添加的东西,让它运行,然后回到我们正常的运营流程。在 TensorFlow 中,只有图中需要执行来计算输出的节点才会被执行。因此,如果您的图形中有一个“悬空”打印节点,它将不会被执行。
那我们该怎么办?我们需要将打印调用拼接到图形本身中,就像这样:
这在代码中的体现方式是将 Print 调用作为其第一个参数传递给作为其“输入”的节点,然后将返回值tf.Print
赋给一个变量,该变量将作为图中后面节点的输入,从而将 Print 语句串行链接到操作流中。(实际使用这个返回的节点是至关重要的,因为如果不使用,它就会悬空。)
虽然 Print 语句不做任何计算,只是向前传递张量,但它确实打印了所需的节点,这是一个副作用。
另一个有点不同于我们在 print 语句中看到的行为是,我们引入到图中的 Print 节点仅仅是设置 Print 语句何时发生,即何时到达计算图中的节点。但是,对打印的内容没有太多限制。
也就是说,它只是在图中标记您希望打印语句出现的位置,但是您可以打印图中它可以访问的任何节点。这是调用tf.Print
的第二个参数:要打印的节点数组。通常我们只使用同一个节点作为第一个参数,也就是输入,但是如果我们愿意,我们可以在输出中包含更多的节点。
还有第三个论点,一个信息。这允许您在打印节点之前预先考虑一些字符串,因此您可以很容易地在日志中找到给定的 print 语句。
付诸实践
简单地说,tf.Print
就是这样。但是你可以在哪里利用 tf 呢?在代码中打印?
经常发现自己在用 tf。在我的输入函数中打印,以调试传递到我的训练循环中的确切内容。这里仅仅使用 Python print
是不够的,因为它只会在构造输入函数图时打印一次。
相反,我们将介绍 tf。打印对输入函数数据管道的调用。请注意,我们只是打印了作为输入传入的相同值,但是您当然也可以打印其他节点。
一些更多的建议
请注意,打印输出显示在我的 Jupyter 笔记本控制台的 stderr 中,而不是作为笔记本本身的输出。搜索打印输出时,请记住这一点!
另一个警告:如果你使用 tf。在你的输入函数中,一定要限制你传入的数据量,否则你可能会滚动一个很长的控制台窗口:)
TensorFlow 的打印语句在许多方面都不是典型的打印语句,但当您需要查看图形中流动的张量时,它可以发挥很大的作用。
感谢阅读本集云 AI 冒险。如果你喜欢这个系列,请为这篇文章鼓掌让我知道。如果你想要更多的机器学习动作,一定要关注 Medium 上的 me 或者订阅 YouTube 频道来观看未来的剧集。更多剧集即将推出!
现在,看看 TensorFlow 的打印语句如何帮助您更清楚地了解您的机器学习是如何运行的!
使用神经网络背后的度量来预测软件进化
阿西莫夫研究所发表了这篇文章,向我们展示了下图所示的不同种类的网络。神经网络现在很热门,但以这种方式表示知识的想法来自二十世纪,当时逻辑学家有一个想法,即使用图通过构建顶点和边来形式化两个集合的映射[1],以便对形式知识进行建模。最早的形式被称为存在图,由哲学家查尔斯·桑德斯·皮尔士 发明,作为符号逻辑的线性符号的替代:皮尔士对有机化学中的分子图印象深刻,认为逻辑的图形符号可以简化推理规则。皮尔斯的洞察力卓有成效,许多类型的图表今天被用来建模知识。随着人工智能的发展,语义图不仅被用来显示概念,如认知图[2],[3],而且被用来"以抽象的形式捕获人类知识,以便于计算机程序对其进行处理"[4]。经验图表结合了知识和数据,定性和定量项目。
source: Asimov Institute
使用图度量预测软件演化
在这篇文章 [5]中,他们使用图来理解软件演化,并构建促进其开发和维护的预测器。为了实现这个目标,他们创建了基于图形的模型,这些模型捕获了 11 个开源软件系统的几个图形度量。研究结果表明,这些模型可以检测结构变化,可以预测错误的严重性,减少维护工作,并改善未来的版本。这篇论文很重要,因为它是第一篇使用动态图来跟踪软件发展的论文。
他们接受源代码仓库和缺陷跟踪系统中的图模型的输入。然后,他们构建图形:他们定义图形度量(表 1)并评估每个软件的属性,接下来他们绘制图形,显示这些属性在软件的每个新版本中的演变(表 2)。最后,他们证明他们的假设,并发展预测。
Table 1. Graph Metrics. One example when it level of the metric is high, another when the level is low
图形构造可以从两个来源获取数据:基于代码的图形或开发者协作图形。第一个来源与软件每个版本中使用的功能和模块有关。当它只接受函数时,它是一个"调用图,当它接受函数及其模块时,它是一个调用"模块协作图。大部分实验工作都是通过“调用图”方法论来完成的。第二个来源是基于随着软件的发展,开发人员如何交流。如果开发者之间的联系仅依赖于解决 bug 问题,则称之为“基于 bug 的开发者协作”,但如果它还依赖于除 Bug 修复之外的事件,则称之为“基于提交的开发者协作”。实验结果显示在表 2 中,对于每个应用程序,它显示了度量如何随时间演变,以及这些变化如何影响软件工程方面。
Table 2. Adapted from Bhattacharya’s paper: Graph-Based Analysis and Prediction for Software Evolution
总的来说,这个结果表明软件的进化遵循共同的规律。图度量揭示了软件发展中的重要事件,例如关键时刻,或者代码重构。他们的方法使用节点等级来识别错误的严重性。他们发现在节点等级和 bug 严重性之间有很高的相关性(0.6–0.86),这意味着节点等级可以预测 bug 严重性,并可以识别关键功能和模块。然而,节点度并不能很好地预测 bug 的严重性。此外,当模块的模块化比率增加时,相关的维护工作也会减少。这意味着更好内聚性(模块内调用)和更低的耦合性(模块间调用)将改进软件结构。此外,基于 Bug 的开发人员协作图显示,编辑距离的增加会增加缺陷数量。这意味着合作者之间更密切的关系将提高开发人员的生产力和软件质量。
这项工作开发了一种使用图分析来揭示软件过程的关键属性的方法。这些属性在图形度量中暴露出来,揭示了软件结构和演化中的差异和相似之处。它们还捕获重要的度量来预测软件生命周期中的事件:节点等级可用于预测 bug 严重性,模块比率用于预测维护工作,编辑距离用于预测软件质量。
这项研究可以应用于其他复杂的系统和过程,例如供应链管理。可以在参与者和活动之间构建图表,然后可以研究图表的演变,以检测参与者做出挑战性决策的点(具有高节点排名的节点),并帮助他们做出更好的选择。此外,通过寻求增加供应链管理图的模块化比率,可以提高供应链的生产率,通过减少编辑距离也可以提高质量。
[1] R. Diestel,图论(数学研究生教材)。美国纽约:施普林格出版社,2000 年。
[2] J. F. Sowa,“从概念图生成语言”, Comput。数学。附申请,第 9 卷,第 1 期,第 29-43 页,1983 年。
[3] W. H. Warren,D. B. Rothman,B. H. Schnapp,J. D. Ericson,《虚拟空间中的虫洞:从认知地图到认知图》,认知,第 166 卷,第 152–163 页,2017 年。
[4] R. J. Brachman,“概念中有什么:语义网络的结构基础”。j .曼。马赫。种马。,第 9 卷,第 2 期,第 127-152 页,1977 年。
[5] P. Bhattacharya,“基于图的软件演化分析和预测”,第 1–2 页。2012
用不确定性来解释你的模型
这是一个与 约尔·泽尔德斯 的联名帖。最初发布于 taboola engineering 博客 。
随着深度神经网络(DNN)变得更加强大,它们的复杂性也在增加。这种复杂性带来了新的挑战,包括模型的可解释性。
可解释性对于构建更健壮、更能抵抗恶意攻击的模型至关重要。此外,为一个新的、没有被很好研究的领域设计一个模型是具有挑战性的,能够解释模型正在做什么可以在这个过程中帮助我们。
模型解释的重要性促使研究人员在过去几年里开发了各种各样的方法,去年在 NIPS 会议上,一个完整的研讨会专门讨论了这个主题。这些方法包括:
- LIME :通过局部线性近似解释模型预测的方法
- 激活最大化:一种理解哪些输入模式产生最大模型响应的方法
- 特征可视化
- 将 DNN 层嵌入到低维解释空间
- 运用认知心理学的方法
- 不确定性评估方法——这篇文章的重点
在我们深入探讨如何使用不确定性来调试和解释您的模型之前,让我们了解一下为什么不确定性很重要。
你为什么要关心不确定性?
一个突出的例子是高风险应用。假设您正在构建一个模型,帮助医生决定患者的首选治疗方案。在这种情况下,我们不仅要关心模型的准确性,还要关心模型对其预测的确定程度。如果不确定性太高,医生应该考虑到这一点。
自动驾驶汽车是另一个有趣的例子。当模型不确定路上是否有行人时,我们可以使用该信息来减慢汽车速度或触发警报,以便司机可以控制局面。
不确定性也可以帮助我们找出数据之外的例子。如果模型没有使用与手边的样本相似的例子进行训练,那么如果它能够说“对不起,我不知道”可能会更好。这本来可以避免谷歌照片将非裔美国人错误归类为大猩猩的尴尬错误。像这样的错误有时会因为训练不够多样化而发生。
不确定性的最后一种用法,也是这篇文章的目的,是作为从业者调试模型的工具。我们一会儿会深入探讨这个问题,但首先,让我们来谈谈不同类型的不确定性。
不确定性类型
有不同类型的不确定性和建模,每一种都有不同的用途。
模型不确定性,又名认知不确定性:假设你有一个单一的数据点,你想知道哪个线性模型最好地解释你的数据。没有好的方法来选择图片中的不同线条—我们需要更多的数据!
左边:数据不足导致高度不确定性。右边:给定更多数据,不确定性降低
认知不确定性解释了模型参数的不确定性。我们不确定哪个模型权重能最好地描述数据,但是给定更多的数据,我们的不确定性会降低。这种类型的不确定性在高风险应用中以及在处理少量稀疏数据时非常重要。
举个例子,假设你想建立一个模型,得到一个动物的图片,并预测这个动物是否会吃你。假设您在狮子和长颈鹿的不同图片上训练模型,现在它看到了一个僵尸。由于该模型不是在僵尸图片上训练的,因此不确定性会很高。这种不确定性是模型的结果,如果有足够多的僵尸图片,这种不确定性就会减少。
数据不确定性,或随机不确定性,捕捉观察中固有的噪声。有时候世界本身是随机的。在这种情况下,获得更多的数据对我们没有帮助,因为噪音是数据中固有的。
为了理解这一点,让我们回到我们的食肉动物模型。我们的模型可以识别出一幅图像包含一只狮子,因此你很可能会被吃掉。但是如果狮子现在不饿呢?这一次的不确定性来自于数据。另一个例子是两条看起来一样的蛇,但其中一条有毒,另一条则没有。
任意不确定性分为两种类型:
- 同方差不确定性:所有输入的不确定性是相同的。
- 异方差不确定性:取决于手头具体输入的不确定性。例如,对于预测图像中深度的模型,无特征的墙预计比具有强消失线的图像具有更高的不确定性。
测量不确定度:不确定度的另一个来源是测量本身。当测量有噪声时,不确定性增加。在动物的例子中,如果一些照片是用质量差的相机拍摄的,模型的可信度会受到损害;或者,如果我们正在逃离一只可怕的河马,结果我们只能处理模糊的图像。
嘈杂的标签:通过监督学习,我们使用标签来训练模型。如果标签有噪声,不确定性就会增加。
每种不确定性都有不同的建模方法。这些将在本系列的后续文章中讨论。现在,让我们假设我们有一个黑盒模型,它暴露了关于其预测的不确定性。我们如何使用它来调试模型?
让我们考虑一下 Taboola 中的一个模型,它用于预测用户点击内容推荐的可能性。
使用不确定性来调试您的模型
该模型具有许多由嵌入向量表示的分类特征。该模型在学习稀有值的广义嵌入时可能会有困难。解决这一问题的常见方法是使用特殊的词汇外(OOV)嵌入。
想想一篇文章的广告词。所有罕见的广告客户共享相同的 OOV 嵌入,因此,从模型的角度来看,他们本质上是一个广告客户。这个 OOV 广告商有许多不同的项目,每一个都有不同的点击率。如果我们只用广告客户作为点击率的预测指标,我们会得到 OOV 的高度不确定性。
为了验证 OOV 模型输出的高度不确定性,我们采用了一个验证集,并将所有的广告客户嵌入转换到 OOV。接下来,我们考察了转换前后的不确定性。不出所料,由于切换,不确定性增加了。该模型能够学习给定一个信息丰富的广告客户,它应该减少不确定性。
我们可以对不同的特征重复这一过程,并寻找用 OOV 嵌入替换时导致低不确定性的特征。要么是这些特征没有提供信息,要么是我们将它们输入模型的方式不理想。
我们甚至可以达到更精细的粒度:一些广告客户在不同项目的点击率之间有很高的可变性,而另一些项目的点击率大致相同。我们预计第一类广告客户的模型具有更高的不确定性。因此,一个有用的分析是着眼于广告客户的不确定性和点击率可变性之间的相关性。如果相关性不是正的,这意味着该模型未能了解与每个广告客户相关联的不确定性。这个工具允许我们了解在训练过程中或者在模型的架构中是否出了问题,这表明我们应该进一步调试它。
我们可以执行类似的分析,并查看与特定项目相关的不确定性是否随着我们展示它的次数增加而降低(例如,向更多用户/在更多地方展示它)。同样,我们希望模型变得更加确定,如果不确定,我们会调试!
另一个很酷的例子是标题特性:带有罕见单词的独特标题应该招致高度的模型不确定性。这是模型没有从所有可能标题的区域中看到大量示例的结果。我们可以在验证集中寻找一组罕见的相似标题,并估计模型在这些标题上的不确定性。然后,我们将使用其中一个标题重新训练模型,并查看整个小组的不确定性是否已经降低。事实上,我们可以看到这正是所发生的:
等等……通过向模型展示一些标题,它能够变得更好,并且对一堆新标题更加确定。也许我们可以利用这一点来鼓励对新物品的探索?嗯,是的,我们可以!在本系列的后续文章中会有更多的介绍。
最后的想法
不确定性在许多领域都很重要。识别哪种不确定性类型是重要的取决于具体的应用。一旦你知道如何建模,你就可以用各种方式使用它们。在这篇文章中,我们讨论了如何使用它们来调试你的模型。在下一篇文章中,我们将讨论从模型中获得不确定性估计的不同方法。
使用无监督学习优化儿童 t 恤尺寸
这篇文章的所有代码和数据都可以在 Github 上找到。本分析使用了 Python 3、Numpy 1.12.0、Pandas 0.19.2、Scikit-Learn 0.18.1、matplotlib 1.4.3 和 Seaborn 0.7.1。
U 在处理低维数据时,监督学习,特别是 K-Means 并不难理解。然而,随着变量数量的增加,可能很难理解你在看什么,更不用说试图弄清楚它是否有用了。
使用儿童身体测量的大型数据集,这项探索的目的是使用无监督学习来提出三种不同的 t 恤尺寸,适合大多数儿童的小号、中号或大号。
本次研究中使用的数据集包含儿童的人体测量数据,以及一些与人口统计相关的属性。有 122 个变量的 3900 个观察值。
数据清理
第一步是检查数据,发现许多对象包含空值。因此,任何包含超过 2000 个空值(在本例中为零)的变量都将被删除。
import pandas as pddf = pd.read_csv('data.csv', index_col=0)
remove_cols = []
*for* i *in* df.columns:
*if* 3900 - df.loc[:,i].astype(bool).sum() > 2000:
remove_cols.append(i)
df = df.drop(remove_cols, axis = 'columns')
使用该标准去除了 76 个变量。
如上所述,数据集包含人体测量和人口统计数据。在这种情况下,人口统计数据被认为是没有用的,因为目的是设计 t 恤,所以 22 个人口统计变量也被删除了。
demographic_attributes = ['AGE IN YEARS', 'LOCATION',
'BIRTH DATE', 'MEASUREMENT DATE', 'MEASUREMENT SET TP',
'MEASURER NUMBER', 'COMPUTER NUMBER', 'RACE', 'GRADE LEVEL',
'HANDEDNESS', 'NUMBER OF BROTHERS', 'NUMBER OF SISTERS', 'TWIN','BIRTH ORDER', 'MOTHERS OCCUPATION', 'FATHERS OCCUPATION',
'MOTHERS EDUCATION', 'FATHERS EDUCATION', 'YEARS IN COMMUNITY','ANTHROPOMETER NO', 'CALIPER NO', 'GIRTH NO']
df = df.drop(demographic_attributes, axis = 'columns')
探索性数据分析
2 对聚类有很大影响的重要变量是年龄(以月为单位)和性别(1 或 2)。尚不清楚 1 号或 2 号是雄性还是雌性,但这不是分析的必要信息。对年龄范围的研究表明,年龄范围为 0 至 240 个月(20 岁),中位数约为 128 个月(10 岁零 8 个月)。
print(df.loc[:,'AGE IN MONTHS'].describe())
显然,为所有年龄设计一个单一的 t 恤尺寸是不合适的,因此使用直立坐姿高度作为尺寸的代表,绘制了一个图表,以查看这一测量值如何随着儿童年龄的变化而变化(0 岁、1 岁、19 岁和 20 岁的儿童被删除,因为没有足够的准确性观察)。
shoulder_data = df[['ERECT SITTING HEIGHT', 'AGE IN MONTHS']]
shoulder_data['YEAR'] = shoulder_data['AGE IN MONTHS'].apply(*lambda* x: x//12)x = list(shoulder_data.groupby('YEAR').mean().index[1:-2])y = list(shoulder_data.groupby('YEAR').mean()['ERECT SITTING HEIGHT'][1:-2])
这显示了一个大致线性的增长率,在两个年龄阶段,身高有了显著的增长。6-7 岁和 12-13 岁是这两个年龄跳跃点,增长率明显增加。因此,有三个需要确定衬衫尺码的年龄区间;0 到 6,7 到 12,13 到 20。小、中、大之间也有重叠的空间,也就是说,7-12 岁的大衬衫可能与 13-20 岁的小衬衫尺寸相似。
同样有趣的是性别和体型之间的关系。第一性和第二性的每个年龄的平均坐高图表明,在 15 岁左右之前,男性和女性之间没有太大的差异,这时男性会稍微长高一些。有了这些信息,估计 1 号性别是男的,2 号性别是女的。
shoulder_data = df[['ERECT SITTING HEIGHT', 'AGE IN MONTHS', 'SEX']]
shoulder_data['YEAR'] = shoulder_data['AGE IN MONTHS'].apply(*lambda* x: x//12)y_1 = shoulder_data[shoulder_data['SEX'] == 1].groupby('YEAR').mean()['ERECT ' \
'SITTING HEIGHT'][1:-2]y_2 = shoulder_data[shoulder_data['SEX'] == 2].groupby('YEAR').mean()['ERECT ' \
'SITTING HEIGHT'][:-1]x = list(shoulder_data.groupby('YEAR').mean().index[1:-2])
区分男性和女性的另一个有用的变量是胸围。下图显示了每个年龄的平均测量值。
这再次表明,主要的分歧发生在 15 岁左右。因此,我认为有 12T 的球衣尺寸需要改进:
- 0-6 岁小号、中号和大号男女通用
- 年龄 7-12 岁小号、中号和大号男女通用
- 年龄 13-20 岁小、中、大男性和女性
出于这个练习的目的,我将把重点放在 7-12 岁。
这里需要注意的是,这两张图有些矛盾。在我看来,女性的胸围应该考虑到乳房的大小,这样的差异表明性别 1 是女性,而身高数据表明性别 1 是男性。我找不到这个数据的模式,所以无法解决这个问题。不管结果是什么,只要记住,无论何时我指定了男性 vs 女性,他们都可以互换。
无监督学习
第一步是将数据分成子集,删除值为 0 的行(本例中为 1584 行中的 59 行),然后转换为 numpy 矩阵进行聚类:
import numpy as npt_shirt_columns = ['CHEST CIRCUMFERENCE', 'WAIST CIRCUMFERENCE',
'SHOULDER-ELBOW LENGTH', 'ERECT SITTING HEIGHT',
'SHOULDER BREADTH']
young = df[df['AGE IN MONTHS'] < 84].loc[:,t_shirt_columns]middle = df[(df['AGE IN MONTHS'] < 156) & (df['AGE IN MONTHS'] >= 83)].loc[:,t_shirt_columns]old_1 = df[(df.SEX == 2) & (df['AGE IN MONTHS'] >= 156)].loc[:,t_shirt_columns]old_2 = df[(df.SEX == 2) & (df['AGE IN MONTHS'] >= 156)].loc[:,t_shirt_columns]
drop_list = []
*for* i *in* range(len(middle.index)):
*if* 0 *in* middle.ix[i,:].values:
drop_list.append(i)
middle = middle.drop(middle.index[drop_list])
data = middle.as_matrix()
下一步是决定数据中有多少个聚类。我们想要三个,但我们也希望它们包含足够的观察,值得为它们创建一个特定的 t 恤尺寸。找出数据中聚类数的一种方法是使用惯性图,并寻找“弯头”。
import matplotlib.pyplot as pltinertias = []
ks = range(1,11)
*for* k *in* ks:
inertias.append(KMeans(n_clusters=k).fit(data).inertia_)
plt.plot(ks, inertias, '-o')
plt.xticks(ks)
plt.show()
由此看来,似乎有 2 或 3 个集群。我们还可以通过查看树状图来了解聚类顺序:
*from* scipy.cluster.hierarchy *import* linkage, dendrogrammergers = linkage(data, method='complete')
dendrogram(mergers, leaf_rotation=90, leaf_font_size=6)
plt.show()
这看起来不错,有两个容易识别的集群,绿色和红色。第三个不太容易看到,但我们可以解决这个问题。这是有希望的。
为了找出聚类,是时候执行 K-Means 聚类了。我们的目标是找到代表大部分观测值的三个聚类。从n_clusters=2
开始,我运行下面的代码,直到我有了三个大的不同的集群。这适用于 3 个集群。
*from* sklearn.cluster *import* KMeanskmeans = KMeans(n_clusters=3).fit(data)
samples = kmeans.predict(data)
names = middle.index
ns = pd.DataFrame({'names': names, 'cluster': samples})
clusters = ns.set_index(names).iloc[:,0]
print(clusters.value_counts())
打印每个集群中的实例数量显示:
这太棒了。我们已经将所有观察结果分成了三个不同的组!现在,看看聚类中心,我们可以看到它们之间的差异:
print(kmeans.cluster_centers_)
这太棒了。我们可以看到,在所有类别中,分类 0 包含最小的值,分类 1 包含最大的值,分类 2 包含中间的值。这意味着这些质心值代表了三种不同体型的中间值,应该在为 7 至 12 岁的孩子制作 t 恤时使用。
扩展ˌ扩张
现在,制造不同尺寸的 t 恤很烦人,所以制造商希望在尽可能多的体型上使用相同的模板。因此,我之前假设不同年龄组之间可能有小/大的重叠。让我们来验证一下这个理论。
对最年轻的年龄段做同样的处理,我们得到下面的树状图:
这不像上一个那样清晰,因为我们在左边有一个高度相似的聚类,但只包含少量的值。这不是很好,但也不重要。当我们使用 KMeans 进行集群时,我们将会看到它们的归属。同样,从n_clusters=2
开始并逐渐增加该值,我们可以看到,在 4 个聚类中,大部分(95.5%)数据被聚类到 3 个良好的聚类中。
查看聚类中心(忽略聚类 2,因为它包含的观察值太少):
同样,我们看到有 3 种不同的大小:小型(群集 0)、中型(群集 3)和大型(群集 1)。不幸的是,这个年龄段的大码和中年组的小码似乎没有太多相似之处。
对于较大的年龄组,可以执行类似的过程,并且男性和女性的小型集群的大小如下所示:
Small Sizing for Males
Small Sizing for Females
正如所料,男性和女性的小尺寸在一些变量上有很大不同,最明显的是肩宽。因此,最初的假设,即不同性别在 13-20 岁年龄组需要不同的尺寸,似乎是正确的。
值得注意的另一点是,13-20 岁年龄组男性的小尺寸与 6-12 岁年龄组的大尺寸不太接近,因为腰围有很大差异。这可能也在意料之中
结论
该分析显示了即使是简单的聚类分析也能从大型脏数据集中产生的结果。一如既往,处理错误和不相关的数据是至关重要的,垃圾输入=垃圾输出。通过一些简单的试错聚类,我们已经确定了跨 3 个年龄组的 t 恤设计的关键尺寸,并排除了多个年龄组使用同一尺寸的可能性!对于 145 行代码来说还不错!
同样,所有用于分析的代码和数据都可以在https://github.com/Padam-0/cluster_t-shirt_sizing获得
如果你喜欢这篇文章,请点击❤按钮让你的关注者知道,或者让我知道你的想法。
使用无监督学习计划去巴黎的假期:地理位置聚类
The Eiffel Tower in the City of Love but there are so many great sights in Paris — how can I help her organise her trip?
当我的朋友告诉我她计划去巴黎旅行 10 天时,我想我可以帮上忙。
她:“我和我的朋友正在考虑去巴黎度假。”我:“哦,听起来很有趣。也许我也可以加入。”
她:“对!我们计划报名参加一个法语课程,然后去购物!我们已经列出了所有我们想去的购物中心,还有…“
我:“啊,听起来很棒…那么你需要我什么时候开车送你去机场?”
因为我自己也去过巴黎几次,我想我可以在其他方面有所帮助,比如为旅游景点列表做贡献。在列出所有的景点之后,我创建了一个谷歌地图,每个位置都有一个图钉。
The initial Google Map with pins for sights to visit — but in what order should these sights be visited?
很明显,要想参观完巴黎所有的景点,需要做一些日程安排工作——但是她怎么能决定先看什么,按什么顺序看呢?这在我看来就像是一个 聚类 的问题,而 无监督学习 方法可以帮助解决它。
像 K-Means 或 DBScan 这样的算法可能会成功。但首先,必须准备好数据,以便于此类算法按预期执行。
地理位置收集和数据准备
首先,我必须以 2D 格式收集谷歌地图的地理位置(可以存储在一个 numpy 数组中)。将这些图钉翻译成[经度,纬度]将是完美的。
由于这是一次性的,我寻找一种快速的方法从谷歌地图中提取这些信息。这个 StackOverflow 查询给了我所需要的一切。
基本上,你需要去 google.com/maps/d/kml?mid={map_id}的下载一个。kmz 文件。然后,手动更改的扩展名。kmz 文件转换为。zip 文件。提取文件,并在您选择的文本编辑器中打开doc . KML(sublime text是我个人的首选)。*
然后,你可能会决定手动 CTRL+F 来搜索字段,或者决定而不是这么懒,使用 BeautifulSoup (如下图)!
从 XML 文件中提取坐标后,我将坐标存储在一个数据帧中。地标总数为 26(存储在 XML 文件中的<地标> < / 地标> )。
Dataframe populated with info from the XML file (first 7 rows only shown)
从存储坐标和地标/景点名称的数据帧中,我生成了一个散点图。
Google Map Pins Scatter Plot
k 均值聚类
一般来说,无监督学习方法对于没有标签的数据集是有用的,并且当我们不一定知道结果时,我们会尝试预测。这些算法通常采取以下两种形式之一:(1)聚类算法,或(2)降维算法。
在这一节中,我们将重点关注k——意为,这是一种聚类算法。使用 k 均值,提供预定数量的聚类作为输入,并且算法在未标记的数据集中生成聚类。
k -means 生成一组 k 聚类质心和一个输入数组 X 的标签,该标签将 X 中的每个点分配给一个唯一的聚类。该算法将分类质心确定为属于该分类的所有点的算术平均值,并定义分类,使得数据集中的每个点与其自己的分类中心比与其他分类中心更接近。
source: https://bit.ly/1z29ZIV
它可以使用 sklearn 在 Python 中实现,如下所示:
从下面的散点图中可以看出,我生成了 10 个聚类——每个假期一个。但巴黎市中心的景点彼此靠得很近,很难区分这两个集群。由此产生的预测也被分类并存储在数据帧中。
k-means was used to generate 10 clusters (one for each day), the black dots represent cluster centers
使用由 k 生成的 10 个集群,我生成了一个数据帧,为每个集群分配一周中的某一天。这将构成一个时间表的例子。
k-means results as Vacation Days of the Week (first 3 days only shown)
现在,在这个阶段,我可以简单地交出排序后的数据帧,按层重新组织谷歌地图图钉(即每层代表一天),就这样——旅程完成了。
但是有些事情仍然困扰着我,那就是 k -means 正在根据点与点之间的欧几里得距离(即地图上两个大头针之间的直线距离)生成聚类。
但是我们知道,地球不是平的(对吗?)所以我想知道这种近似是否会影响正在生成的星团,特别是因为我们有相当多的地标远离巴黎市中心的高密度区域。
因为地球不是平的:输入 HDBSCAN
因此,我们需要一种能够处理地理距离的聚类方法,即地球表面两点之间最短曲线的长度。
基于 DBScan 算法的密度函数 HDBSCAN 可能对此有用。
HDBSCAN 和 DBSCAN 算法都是基于密度的空间聚类方法,它们根据距离度量和最小点数将彼此靠近的点组合在一起。它还将低密度区域中的点标记为异常值。
幸运的是,HDBSCAN 支持哈弗线距离(即经度/纬度距离),这将正确计算地理位置之间的距离。关于 HDBSCAN 的更多信息,请查看这篇博客文章。
HDBSCAN 不包含在您的典型 Python 发行版中,因此您必须 pip 或 conda 安装它。我这样做了,然后运行了下面的代码。
最后得到了下面的散点图和数据图。我们看到孤立点聚集在聚类’-1 ‘中,这意味着它们被识别为’噪声’。
HDBSCAN generated 9 clusters and 3 data points as ‘noise’
HDBSCAN results as Vacation Days of the Week (first 3 days only shown)
不出所料,我们最终有几个点被标记为噪声。由于 HDBSCAN 聚类的最小点数是 2,像凡尔赛宫这样的孤立位置被归类为噪声。万森斯的圣小教堂和罗丹博物馆遭遇了相似的命运。
然而,有趣的是 HDBSCAN 识别出的集群数量为 9,比设定的假期天数少一天。我猜对于我们选择的景点/数据点的数量,10 天听起来没问题。
最终,来自 k 均值的结果是我们用来制定时间表的结果,因为 k 均值生成的聚类与 HDBSCAN 生成的聚类相似,并且包含了所有数据点。
这里介绍的聚类方法当然可以改进。一个可能的改进是为数据点增加一个权重特性。例如,权重可以表示完全参观一个特定场所所需的时间量(例如,勒卢浮宫很容易花一整天来欣赏),因此这将影响具有高权重点的聚类中的数据点的总数,这将在未来的项目中进行调查。
这个迷你项目的 Jupyter 笔记本可以在这里找到。
使用 Word2Vec 更好地嵌入分类特征
回到 2012 年,当神经网络重新受到欢迎时,人们对训练模型而不必担心特征工程的可能性感到兴奋。事实上,大多数最早的突破是在计算机视觉领域,其中原始像素被用作网络的输入。
很快,事实证明,如果你想使用文本数据、点击流数据或几乎任何具有分类特征的数据,在某些时候你必须问自己——我如何将我的分类特征表示为我的网络可以使用的向量?
最常用的方法是嵌入图层,即向网络中添加一个额外的图层,为分类要素的每个值分配一个矢量。在训练期间,网络学习不同层的权重,包括那些嵌入。
在这篇文章中,我将展示这种方法何时会失败的例子,介绍 category2vec,这是一种使用第二个网络学习嵌入的替代方法,并将介绍在您的主网络中使用这些嵌入的不同方法。
那么,嵌入图层有什么问题呢?
嵌入层经过训练以适应特定的任务,即训练网络的任务。有时候这正是你想要的。但是在其他情况下,您可能希望您的嵌入捕获一些关于问题领域的直觉,从而降低过度拟合的风险。你可以把它看作是在你的模型中增加了先验知识,这有助于它进行归纳。
此外,如果您在相似的数据上有不同的任务,您可以使用来自一个任务的嵌入来改进您在另一个任务上的结果。这是深度学习工具箱中的主要技巧之一。这被称为迁移学习,预训练或多任务学习,取决于上下文。潜在的假设是,解释数据的许多未观察到的随机变量是跨任务共享的。因为嵌入试图隔离这些变量,所以它们可以被重用。
最重要的是,将嵌入作为网络的一部分来学习会增加模型的复杂性,因为这会给模型增加许多权重,这意味着您需要更多的标记数据来学习。
所以不是说嵌入层不好,而是我们可以做得更好。让我们看一个例子。
示例:点击预测
Taboola 的研究小组开发了算法,根据用户当前阅读的内容向他们推荐内容。我们可以把它想成一个点击预测问题:给定你的阅读历史,你点击每篇文章的概率是多少?
为了解决这个问题,我们训练深度学习模型。自然地,我们从学习嵌入作为我们网络的一部分开始。
但是我们得到的很多嵌入没有意义。
您如何知道您的嵌入是否有意义?
最简单的方法是获取几个项目的嵌入,并查看它们的邻居。他们在你的领域里相似吗?这可能会让人精疲力尽,而且不会让你看到全局。因此,另外你可以使用 PCA 或者 t-SNE 来减少你的向量的维数,并根据特定的特征给它们上色。
一个物品的广告主是一个强特征,我们希望相似的广告主有相似的嵌入。但这就是我们为不同广告客户嵌入的样子,用广告客户的语言来着色:
哎哟。事情显然不对劲。我的意思是,除非我们假设我们的用户是多语言天才,他们阅读一篇西班牙语文章,然后毫不费力地阅读另一篇日语文章,否则我们可能会希望我们嵌入空间中的类似广告商拥有相同语言的内容。
这使得我们的模型更难解释。人们很不安。有些人甚至失眠了。
我们能做得更好吗?
Word2Vec
如果你听说过嵌入式,你可能听说过 word2vec 。这种方法将单词表示为高维向量,因此语义相似的单词将具有相似的向量。它有两种风格:连续单词包(CBOW)和跳过单词。CBOW 训练网络根据上下文预测单词,而 Skip-Gram 则相反,根据特定的目标单词预测上下文。
我们可以用同样的想法来提高我们的广告植入吗?是的我们…嗯,你明白了。
从 Word2Vec 到 Category2Vec
想法很简单:我们根据用户的点击历史来训练 word2vec。每个“句子”现在是用户点击的一组广告商,我们试图根据用户喜欢的其他广告商(“上下文”)来预测特定的广告商(“单词”)。唯一的区别是,与句子不同,顺序不一定重要。我们可以忽略这个事实,或者用每个历史的排列来增强数据集。您可以将这种方法应用于任何种类的高模态分类特征,例如,国家、城市、用户 id 等…查看更多详情此处和此处。
如此简单,却又如此有效。还记得我们之前看到的混乱的嵌入可视化吗?这是它现在的样子:
好多了!所有语言相同的广告客户都聚集在一起。
现在我们有了更好的嵌入,我们能用它们做什么呢?
使用来自不同模型的嵌入
首先,请注意,category2vec 只是一般实践的一个示例:将任务 A 中学习到的嵌入用于任务 b。我们可以用不同的架构、不同的任务,在某些情况下,甚至是不同的数据集来替换它。这是这种方法的最大优势之一。
在我们的模型中有三种不同的方式来使用新的嵌入:
- 使用新嵌入作为新网络的特征。例如,我们可以对用户点击的所有广告商的嵌入进行平均,以表示用户历史,并使用它来学习用户的口味。这篇文章的重点是神经网络,但实际上你可以用任何 ML 算法来做。
- 用我们刚刚学过的嵌入初始化网络中嵌入层的权重。这就像告诉网络—这是我从其他任务中了解到的,现在为当前任务进行调整。
- 多任务学习 —取两个网络,参数共享一起训练。你可以强迫它们共享嵌入(硬共享,或者当它们的权重相差太大时,通过“惩罚”网络来允许它们具有稍微不同的权重(软共享)。这通常是通过调整重量之间的距离来实现的。你可能会认为这是将知识从一个任务传递到另一个任务,但也是一种正则化技术:word2vec 网络充当另一个网络的正则化器,并迫使它学习具有我们感兴趣的特征的嵌入。
好吧,让我们回顾一下。
有时候,我们可以简单地通过采用一些现有的方法,但把它应用到新的东西上,从而获得很好的结果。我们使用 word2vec 为广告商创建嵌入,我们的结果比使用嵌入层获得的结果更有意义。正如我们在 Taboola 中所说——有意义的嵌入=有意义的生活。
你有没有以不寻常的方式使用 word2vec?有一些关于分类特征的专业建议吗?看了一篇有趣的相关论文?我很想在评论中了解一下:)
使用 Word2vec 进行音乐推荐
我们如何使用神经网络将数十亿条数据流转化为更好的推荐。
Each point represents a song. The closer the points, the more similar the songs are.
流媒体服务改变了我们体验内容的方式。虽然推荐系统以前专注于向您提供您可能想要购买以供以后消费的内容,但现代流媒体平台不得不转而专注于推荐您可以并且想要立即享受的内容。由于任何内容都可以立即访问,流媒体模型使得个性化电台或推荐播放列表形式的新发现方法成为可能,其中现在的重点是生成可以很好搭配的相似歌曲序列。
现在每月有超过 7 亿首歌曲在流媒体上播放, Anghami 是中东和北非地区领先的音乐流媒体平台。这也意味着,所有这些数据流产生的数据量被证明是一个非常宝贵的训练集,我们可以用它来教机器学习模型更好地理解用户的口味,并改进我们的音乐推荐。
在这篇文章中,我将介绍一种神经网络方法,我们使用它从我们拥有的大量流媒体数据中提取歌曲嵌入,以及我们如何使用该模型来生成相关的推荐。
推荐系统
推荐系统分为两大类:
- 基于内容的系统是基于我们想要推荐的商品特征的推荐系统。当谈到音乐时,这包括例如歌曲的类型或每分钟多少拍。
- 基于协同过滤的系统是依靠历史使用数据来推荐其他类似用户先前已经交互过的项目的系统。这些系统不理会内容本身的特征,并且将它们的推荐基于这样的原则,即拥有许多共同歌曲或艺术家的人通常会喜欢相同风格的音乐。
有了足够的数据,协同过滤系统在推荐相关项目上证明是有效的。协同过滤背后的基本思想是,如果用户 1 喜欢艺术家 A & B,而用户 2 喜欢艺术家 A B&C,那么很可能用户 1 也会对艺术家 c 感兴趣
观察所有用户的全球歌曲偏好,并应用经典的协作过滤方法,例如对用户项目评级矩阵进行矩阵分解,这为我们提供了关于歌曲组如何相关的有价值的信息。所以如果一群用户有一大套他们喜欢的共同的歌曲,我们可以推断那些是对音乐有非常相似品味的用户,他们听的歌曲彼此相似。
这些跨多个用户的全球共现因此给了我们关于歌曲如何相关的有价值的信息;然而,他们没有捕捉到的一件事是,歌曲如何能够在时间上局部地同时出现。所以他们可能会告诉我们,宋立科 A 的用户也可能会宋立科 B,但他们会在同一个播放列表或收音机里听吗?因此,我们不仅可以看到用户一生中播放的歌曲,还可以看到他们在什么环境下播放这些歌曲。或者换句话说,在同一个会话中,他们还会在之前或之后播放哪些歌曲?
所以我们感兴趣的是一个模型,它不仅能捕捉到相似的人对什么歌曲普遍感兴趣,还能捕捉到在非常相似的背景下 T2 经常一起听什么歌曲。这就是 Word2vec 的用武之地。
那么……什么是 Word2vec?
Word2vec 是一类神经网络模型,最初用于学习对自然语言处理任务非常有用的单词嵌入。近年来,该技术还被应用于更一般的机器学习问题,包括产品推荐。神经网络接收大量文本,对其进行分析,并为词汇表中的每个单词生成一个代表该单词的数字向量。这些数字向量正是我们所追求的,因为正如我们将会看到的,它们编码了与单词出现的上下文相关的单词含义的重要信息。
定义了两个主要模型:连续词袋模型和跳跃式模型。在接下来的讨论中,我们将把自己限制在 Skip-gram 模型,因为这是我们使用的模型。
Word2vec Skip-gram 模型是一个具有单一隐藏层的浅层神经网络,它将一个单词作为输入,并试图预测其周围单词的上下文作为输出。让我们以下面这句话为例:
在上面的句子中,单词“back-lanches”是我们当前的输入单词,单词“little”、“dark”、“behind”和“the”是我们在给定输入单词的情况下想要预测的输出单词。我们的神经网络看起来像这样:
W1 和 W2 表示权重矩阵,用于控制我们应用于输入以获得输出的连续变换的权重。训练神经网络包括学习那些权重矩阵的值,这些值为我们提供最接近所提供的训练数据的输出。
给定一个输入单词,我们通过网络进行第一次前向传播,以获得输出单词是我们根据训练数据所期望的单词的概率。因为我们确切地知道在输出端我们期望什么样的单词,所以我们可以测量预测中的误差,并且使用反向传播通过网络传播该误差,并且通过随机梯度下降调整权重。通过这一步,我们稍微修改了 W1 和 W2 的值,因此它们可以更准确地预测给定示例输入单词时我们想要的输出单词。完成这一步后,我们将上下文窗口移到下一个单词,并再次重复上述步骤。
我们对训练集中的所有句子重复上述过程。当我们完成时,权重矩阵的值会收敛到产生最准确预测的值。
**有趣的部分来了:**如果两个不同的单词在相似的上下文中大量出现,我们预计,给定这两个单词中的任何一个作为输入,神经网络将输出非常相似的预测作为输出。我们之前提到过,权重矩阵的值控制输出端的预测,因此如果两个单词出现在相似的上下文中,我们希望这两个单词的权重矩阵值在很大程度上是相似的。
特别地,权重矩阵 W1 是一个具有与我们的词汇表中的单词一样多的行的矩阵,每行保存与特定单词相关联的权重。所以,既然相似的词需要输出相似的预测,那么它们在矩阵 W1 中的行应该是相似的。与这个矩阵中的每个单词相关联的权重是我们将要用来表示该单词的“嵌入”。
但是这和音乐推荐有什么关系呢?好吧,我们可以把用户的收听队列想象成一个句子,句子中的每个单词就是用户听过的一首歌。因此,在这些句子上训练 Word2vec 模型本质上意味着,对于用户过去听过的每首歌曲,我们使用他们之前和之后听过的歌曲来教导我们的模型,这些歌曲在某种程度上属于相同的上下文。这里有一个用歌曲代替单词的神经网络的想法:
这是与上面讨论的文本分析相同的方法,除了我们现在为每首歌曲有一个唯一的标识符,而不是文本单词。
在训练阶段结束时,我们得到的是一个模型,其中每首歌曲都由高维空间中的权重向量表示。关于这些向量有趣的是,相似的歌曲将比不相关的歌曲具有更接近的权重。
宋矢用例
使用 Word2vec,我们已经将寻找出现在相似上下文中的歌曲的问题转化为捕捉这些局部共现的数学数字。我们可以将权重视为高维空间中的坐标,每首歌曲由该空间中的一个点来表示。这个空间由几十个维度定义,作为人类我们不容易想象,但我们可以使用维度缩减技术,如 t-SNE 将高维向量缩减为 2 维,并将其绘制在图表上:
上图中的每个点代表一首歌,点与点之间的距离越近,歌曲越相似。
这些向量可以以多种方式使用,例如,作为其他机器学习算法的输入特征,但是它们也可以单独用于查找相似的歌曲。
正如我们之前提到的,两首特定的歌曲在相似的上下文中出现的次数越多,它们的坐标就越接近。因此,给定一首特定的种子歌曲,我们可以通过取该种子歌曲和所有其他歌曲的向量之间的余弦相似性来找到 k 首其他相似的歌曲,同时保留具有最高余弦的前 k 首歌曲(其对应于最低的角度,因此最相似)。例如,黎巴嫩经典歌手 Fayrouz 的 Shayef El Baher Shou Kbir 和同一歌手的 Bhebbak Ma Baaref Laych 之间的余弦相似度为 0.98,而现代黎巴嫩流行艺术家 Elissa 的 Shayef El Baher Shou Kbir 和 Saharna Ya Leil 之间的相似度仅为-0.09。这是有道理的,因为听 Fayrouz 等经典歌曲的人不太可能在排队时将它们与 Elissa 的流行音乐交替播放。
我们可以使用歌曲向量的另一种有趣的方式是将用户的收听习惯映射到这个空间,并基于此生成推荐。既然我们现在在处理向量,我们可以用基本的算术将向量相加。让我们以听了三首歌的用户为例:基顿·汉森的《早晨的*、伦敦文法学院的《浪费我的青春的和女儿的青春的*。我们能做的是得到对应于这三首歌中每一首的向量,然后将它们平均在一起,找到一个与这三首歌等距的点。我们所做的基本上是将用户已经听过的歌曲列表转换成坐标向量,该坐标向量在我们的歌曲所在的相同向量空间中表示用户。现在我们有了一个定义用户的向量,我们可以使用以前使用的相同技术来查找与用户相近的相似歌曲。以下动画有助于形象化地展示生成这些建议所涉及的不同步骤:**
我们发现诸如《头和心在山谷中》、狐狸乐队的、米克诺斯的和本·霍华德的小事情*等歌曲都与我们的输入歌曲具有相同的独立民谣风格。请记住,我们所做的这一切不是基于对音频声学的研究,而是通过简单地查看其他人在这些特定歌曲周围听过的歌曲。*
结论
Word2vec 允许我们用一个坐标向量精确地模拟每首歌曲,这个坐标向量捕捉了这首歌曲播放的上下文。这使得我们可以轻松地识别相似的歌曲,并使用向量算术来找到定义每个用户的向量。
Word2vec vectors 目前与其他音乐推荐功能模型一起用于生产,主要用于基于用户收听习惯的音乐发现。所以,下次你通过推荐发现一首好歌时,想想在你之前有成千上万的人演奏过这首歌,他们接下来还会演奏哪首你最喜欢的歌曲。
想成为这样有趣故事的一部分吗? 我们在招聘 !
使用 XGBoost 预测献血量,而无需使用 Dataiku 编写任何代码
我决定用一个类似 Kaggle 的比赛的数据集来测试Data taiku 的数据科学工作室技术,这个比赛是由一个叫做驱动数据的组织举办的。驱动数据主办数据科学竞赛,以解决具有社会影响的问题。
Dataiku 为清理数据、训练模型和部署模型提供了编码环境和点击式界面。
我想比较在 Jupyter 笔记本中手动编写每一步代码与使用 Dataiku 的点击界面,并尝试回答以下问题:
- 使用点击式界面会显著提高我的工作效率吗
- 我会得到更好的结果吗?
- 我会被介绍到通常不属于我的标准剧目的新算法吗?
我从一个竞赛中挑选了一个超级简单的数据集来预测谁会献血,然后开始在大台库工作。在这篇博文中,我将概述我是如何使用 Dataiku 的,学到了什么,我的最终结果和我的结论。
清理数据
在大台库清理数据其实挺容易的,甚至“好玩”!而不是煞费苦心的把字符串编码成类别,整数等。在熊猫身上,大太酷是自动完成的。我喜欢这个功能。
加载数据集:
注意—不要在此界面中更改列名。如果有必要,可以稍后在脚本中完成。否则,当您加载您的测试数据时,您将不得不再次手动更改名称,否则模型将无法工作。
快速统计和直方图:
你可以很容易地点击任何功能,以获得快速统计和直方图。虽然这很酷,但不利的一面是,当信息太容易获取时,你可能会花更少的时间来真正消化它。我还发现直方图格式比使用旧的 matplotlib 更难阅读。 (Matplotlib 是 Python 的开源数据可视化工具。)
基础数据准备:
Dataiku 正确地猜到我的字符串应该被转换成整数。以下是下拉菜单中的其他快捷选项。同样,如果您打算使用具有相同原始模式的附加数据集,请不要在这里进行更改。
你也可以做其他漂亮的事情,比如过滤、排序、着色。这对于了解数据非常有用。
数据探索
是时候做一些散点图和条形图了!只是拖放。您可以存储图表、下载图表并将其发布到仪表板。这很方便,但是当然你需要花时间去学习这个软件的功能,并且熟练地使用它。
不利的一面是,如果你已经掌握了 matplotlib,对你的图表没有相同程度的控制是令人沮丧的。此外, Seaborn (另一个 python 可视化库)有一个叫做 pairplot 的漂亮函数,让你使用一行代码生成一个散点图矩阵,其中包含你的所有特征。据我所知,这里你必须一次创建一个散点图。
我对数据探索功能的另一个批评是,我无法像在 Jupyter Notebook 中那样系统地展示我的分析和评论。Jupyter 笔记本让你创建一个按时间顺序排列的记叙文来记录你的整个思考过程。
然后,我发现了 Dataiku 的“仪表板”功能。这种“排序”让你建立一个叙述,通过保存你的图表作为一个仪表板的瓷砖,并添加到每个瓷砖的洞察力。然而,你不能同时查看你的‘洞察力’和你的图表,我觉得这有点烦人。我也更喜欢年表,而不是瓷砖的排列,但也许我可以及时适应这个新系统。
现在,Dataiku 的一个非常好的功能是,如果你对点击太不耐烦,你可以随时跳到 Jupyter 笔记本上做你的事情。
建模时间!
现在是时候去“实验室”做一些功能工程和建模了。你可以做一个“视觉分析”,即点击,使用空白笔记本,或使用预定义的笔记本。
这里有几个截图,让你知道有什么可用的。Dataiku 还有额外的“插件”,你可以用它来获得更多预定义的选项,比如处理 Twitter 数据。
Keep it simple — do you want to predict or cluster?
Do some topic modeling, PCA, time-series forecasting, etc. in a prebuilt note book. Or just get a blank notebook up and running.
我将向您展示我是如何使用可视化分析选项对数据建模的。
创建数据预处理脚本
首先,我创建了一个脚本来处理我的数据。这里,我删除了一个列,因为它与另一个列完全相关,并且我创建了一个每月捐款的新特性。
当你点击“添加新步骤”时,你会得到大量的选项。坦率地说,这些选项给了我新的想法,让我知道我可以用这些数据做些什么,这是我以前可能没有想到的。此外,这个接口减少了大量的时间,否则你可能要花在弄清楚如何编写代码来实现你伟大的特性工程思想
我认为,如果人工智能可以查看我的数据,并根据文献给我具体的建议,以实现更好的特征工程,那将是绝对美妙的。
一旦您完成了数据预处理,请确保将脚本部署到您的“流”中,以便它可以在您的测试数据中重用,等等。
运行一些模型
使用 Dataiku(我认为是所有的数据科学平台),你可以同时训练多个模型,并方便地为你总结所有的统计数据。
这里有一些截图,让你知道什么是可能的。对建模功能可以做的每一件事做一个深入的教程太多了。如果您想了解更多,Dataiku 有一个免费层,可以让您了解该产品。
玩你的功能和运行许多模型是非常容易的。优化参数的网格搜索在后台自动完成,但您也可以自己调整参数。
这里的另一个便利是不必自己下载和安装某些算法的包。例如,我在让 XGBoost 工作时遇到了很多麻烦,所以不用在这里处理安装问题就很好了。
一个方便的并排比较分数!我运行的模型比这多得多,但这个截屏只显示了其中的几个。
查看每个型号的功能重要性和其他详细信息。
不看看自己的困惑矩阵,就不能称自己是数据科学家。
我希望我可以在彼此之上绘制多条 ROC 曲线,这样我就可以同时看到所有的模型。
这个自动特征生成“功能”也非常棒。
还有很多,但这些是我的亮点。同样,太容易获得所有这些信息的缺点是,你可能会跳过一些步骤,花更少的时间来真正消化正在发生的事情。有了这个界面,就很难创建一个叙述来记录你的思维过程。下一次我想我会打开一个记事本来整理我的思绪。
部署您的模型并对测试数据进行评分
《大台库》中有两个概念理解起来很重要,我还没有涉及到:“菜谱”和“流量”。下图中的黄色小扫帚代表了数据清理的方法(我们之前部署的脚本/步骤)。绿色图标代表模型、预测和评分。
正如你在这里看到的,我把我的训练数据,做一些数据清理,训练一个模型,然后用在测试数据上。然后,我获取测试数据,运行数据准备程序,然后进行评分。我还在测试数据的最后做了一个额外的数据准备步骤,为 DrivenData 竞赛提交做准备。
这无疑(现在仍然有点)令人困惑。但是,我认为一旦你掌握了窍门,这一切真的很有意义。
所有这一切的美妙之处在于,您可以在您的流程中使用点击和编码方法!所以,你可以两全其美。我觉得这很酷。
Flow
Recipes
附加功能
Dataiku 还具有更多功能,可用于构建 web 应用程序、自动化任务、监控、创建实时预测 API 等。
比赛结果
我向比赛提交了我的测试数据,得到了以下结果。
这是一位领导者的 github repo (截至 2017 年 1 月),他使用各种算法记录了他的模型结果。作为直接比较,你可以看到他的 XGBoost 模型的笔记本。他的原木损耗分数是 0.4851,而我使用大台库的原木损耗分数是 0.4607(越低越好)。
如果你想看到更多的比较,这是与各种竞赛领导者提交的代码链接的回购。我想我可以通过尝试这些回复中的功能工程思想来大大提高我的分数。
结论
让我们重温一下我最初的问题。
- 大台库让我更有生产力了吗?是啊!我认为使用 Dataiku 进行分析所花的时间比编写代码要少得多,即使有学习 Dataiku 的加速时间。
- 大台库让我得到了比其他方式更好的结果吗?不是 100%确定,但我认为是这样,因为所有的自动优化工具在后台做的。
- 我接触到新算法了吗?不完全是。我没有展示完整的列表,但是他们所有的预烤的都已经在我的 repetoire 里了。相比之下,我看到了一个数据机器人(一个竞争的数据科学平台)演示,其中有相当多我以前从未听说过的算法。
总体而言,我对数据科学“平台”有什么看法?
我认为,一旦你掌握了技术并有了一个好的工作流程,使用数据科学平台会是一个很大的优势。它允许您:
- 多思考,少编码。
- 更快获得结果。
- 让非编码人员掌握领域专业知识
我很想听听其他人对数据科学平台的体验。我希望你喜欢这篇文章,如果你有任何问题,请随时联系我。
利用 Yelp 数据预测餐馆倒闭
米恰伊尔·阿里菲拉克斯是一名有抱负的数据科学家,也是普林斯顿大学的化学工程博士生,他在普林斯顿大学模拟复杂材料的机械和电子特性。他是 2017 年秋季的 洞察数据科学研究员 。在 Insight,他在三周内建立了一个模型,预测餐馆在四年内关闭。
作为 Insight Data Science 的研究员,我有机会花三周时间构建餐馆成功模型:一个评估餐馆在未来四年内可能成功还是失败的模型。这个项目最具挑战性的部分是建立正确的数据集,其中包含有关过去某个时间点存在的餐馆的当前信息,并设计预测功能。
过去利用 Yelp 数据预测餐馆成功的努力都没有成功。另一方面, Yelp 评论文本在短时间尺度上对餐厅关闭具有很强的预测性。在我的工作中,我使用 Yelp 评论的元数据设计了更大时间范围(四年)内的预测功能,以及基于周围餐馆相对表现的功能。这个问题的更多细节、使用的程序和获得的结果在下面给出。
1.定义问题
美国餐饮业确实很大,2016 年创造的收入约为7990 亿美元,分布在 100 多万家企业之间,这些企业雇佣了约 10%的美国劳动力。鉴于小企业的数量和这个行业的总规模,我决定创建一个模型,可以帮助餐馆贷款人(如银行)和投资者根据某个餐馆在未来几年内倒闭的可能性来决定他们是否应该贷款/投资该餐馆。
餐厅关闭是一个非常明确的成功衡量标准,尽管可以设计更复杂的成功衡量标准。餐馆关闭度量标准的选择允许我将这个问题作为一个分类问题,这使得获得标记数据变得更加容易。很难找到关于每家餐厅业绩的更详细信息,因为大多数餐厅都是私营公司。
2.构建数据集
据我所知,不存在可用于解决上述餐馆关闭问题的标记数据集。首先,要构建这样的数据集,我必须找到过去某个时候存在的餐馆列表,然后将该信息与餐馆的当前信息进行匹配。
我的起始数据集是 2013 年发布的 Yelp 数据集。该数据集包含亚利桑那州凤凰城地区的商业信息。使用该数据集的训练数据,我决定只研究餐馆,并且只研究在获得该数据集时仍在营业的餐馆。
这个数据集和 Yelp 发布的所有其他用于学术用途的数据集不包含真实的企业识别码或电话号码。如果有这些代码,从 Yelp API 获取当前数据将变得很容易。为了克服缺少业务 id 的问题,我使用 Yelp 搜索 API 从旧列表中搜索每个餐馆,使用它们的名称和地址,但是结果令人失望。
使用这种方法,只有三分之二的餐馆与当前信息相匹配。其余的搜索给出的结果与真正的餐馆不相符。不过,这种搜索方法的基本问题不是数据点的数量,而是返回结果的方式存在偏差。
通过 Yelp 搜索正确返回的餐馆要么是仍在营业的餐馆,要么是最近关闭的餐馆。这产生了一个包含几乎所有成功餐馆的数据集(因为即使是关闭的餐馆也是自原始数据集发布以来设法保持营业约四年的餐馆)。至于其余的餐厅,在我获得每家餐厅的具体信息之前,我无法确定它们是否已经关门。
2a)获得正确的当前餐馆信息的解决方案
尽管 Yelp 不会通过 Yelp 搜索 API 返回关闭很长时间的餐馆的结果,但它会在数据库中保留这些信息。我的解决方案是使用 Google Search API 来搜索 yelp.com 域,并提取尚未匹配的餐馆的业务 id。这些业务 id 用于通过 Yelp 业务 API 直接从 Yelp 获取当前数据。这使我能够获得大多数剩余餐馆的信息,并建立一个有意义的模型。
2b)连接新旧数据集
我确认新旧数据集中的餐馆是否相同的方法是,检查新旧餐馆名称的前四个字符是否包含在新旧餐馆名称中,以及地址的前四个字符是否相同。对于只符合上述两个标准之一的餐厅,我手动检查以确定原因,并创建了一个自 2013 年以来在 Yelp 数据库中发生变化的餐厅名称字典(例如,肯德基改为 K.F.C .)。
最终的数据集总共包含 3,327 家餐馆,其中约 23%自 2013 年以来已经关闭。下图概述了创建该数据集的过程。
Graph of process of creating the discussed dataset. The percentages indicate the percentage of data points carried from the previous step.
3.特征工程
Yelp 提供的原始特征(例如 Yelp 星级)的预测能力非常差。如下图所示,Yelp 星级分布对于开放和关闭的餐馆来说看起来非常相似。
Yelp star distribution for restaurants that remained open in the 4-year period (black) and for restaurants that closed (red). On the left, the percentages per category are shown, where the similarity of the two categories becomes apparent. On the right, the absolute numbers are presented, which give a better picture of the class imbalance.
生成有意义的特征是建立这个模型的关键,为此我使用 yelp 评论和位置元数据生成了特征。其中一些功能如下:
- 这家餐厅是连锁餐厅的一部分吗?如果餐馆名称在列表中出现不止一次,那么它被认为是连锁店的一部分。这包括全国或地方连锁店。由于连锁店的定义方式,在特定列表中仅由一家餐厅代表的一些连锁店不算为连锁店。
- 当地的餐厅密度是多少?根据餐馆坐标,我为列表中的每个餐馆创建了一个半径 1 英里内的餐馆列表。
- 点评数、星级、价格(即一般用餐费用)相对于周边餐厅是多少?识别每个餐馆 1 英里半径内的周围餐馆(类似于餐馆密度计算),并且通过从每个单独的餐馆中减去该组餐馆的平均值并除以该组餐馆的值的标准偏差来计算每个餐馆的评论计数、星级和价格的相对值。
- 每个餐厅的年龄是多少?这个值大约是 yelp 第一次评论的日期。这意味着加入 yelp 较晚或没有经常收到评论的餐厅看起来比其实际价值相对年轻。此外,餐厅的年龄受到 Yelp 成立日期(即 2004 年)的限制。
4.机器学习模型和优化
使用分层采样将数据集分为 80%的训练集和 20%的测试集。这个数据集的基本问题是,即使引入了附加的特性,它也没有很好地分离,其中一些特性已经在上面描述过了。
一家餐厅成功或失败的原因有很多,但不包括在我们的特征空间中(例如,其他邻近的餐厅、周围的场地、更新的税收系统、健康检查结果等)。).在这种情况下,复杂的决策边界没有好处。通过使用准确度、精确度、召回率和 F1 分数作为评估指标,在我们的数据上测试不同机器学习模型的性能,这一点得到了证实。
由于我从使用更复杂的模型中获得的这种改进的缺乏,我选择使用线性逻辑回归模型,它简单并且具有良好的可解释性。基于餐馆贷款的用例,我选择优化我的模型参数,使用交叉验证的网格搜索来提高开放餐馆的精确度。优化的参数是正则化强度(使用 L2 正则化)和截距比例因子。我的参数选择结果如下所示。
On the left, there is a list of evaluation metrics for the model performance. On the right, the confusion matrix is presented, which gives a different perspective on model performance.
如上图所示,开放餐馆的准确率为 91%。这意味着,在被模型识别为开放的餐馆中,91%的餐馆实际上仍然开放。剩下的 9%是误报。基于这种模型做出贷款决定的银行,其 4 年违约率可能为 9%,而不加选择地向列表中的所有餐馆提供贷款的银行,其 4 年违约率约为 23%(相当于我们数据集中的餐馆倒闭率)。
看上面的混淆矩阵可以看出,在餐厅关门的情况下,模型的预测能力很差。在被预测将会关闭的餐馆中,只有 36%的餐馆在 4 年内最终关闭。这是在我们的特征空间中实现的两个类之间的不良分离的结果。封闭式餐厅的精确度可以进一步提高,但开放式餐厅的精确度总是需要权衡。基于我们的用例(即餐馆贷款),我选择将注意力集中在提高开放餐馆的精确度上。为了提供更多贷款,应该根据银行愿意接受的风险进一步调整模型。
5.特征重要性和模型解释
该模型产生的特性重要性如下所示。促使餐馆继续营业的要素显示为黑色,而促使餐馆关闭的要素显示为红色。
A list of features ranked on decreasing importance. Features that contribute towards the restaurants remaining open are shown in black, while features that contribute towards restaurant closure are shown in red.
根据我们的模型,最重要的特征是餐厅是否是连锁餐厅的一部分。连锁餐馆更有可能继续营业。这并不奇怪,因为连锁餐厅的利润率通常高于个体餐厅。
相对评论数(即相对于周围 1 英里半径内餐馆的评论数)是促使餐馆保持营业的第二个最重要的特征。很难将这一指标严格定义为成功的标志或原因。大量的评论表明餐馆的流量更高,但这也是在 Yelp 搜索结果中出现更高的原因,这本身就可以带来更多的流量。
高餐厅密度与较高的关闭率相关。这可能是由于竞争加剧。与相似的餐厅密度(即半径 1 英里内属于同一食品类别的餐厅密度)相比,观察这一特征很有意思。高餐馆密度对餐馆成功是负面的,而高相似餐馆密度是正面的。举例来说,在一个有很多餐馆的地区拥有一家中国餐馆通常对这家中国餐馆是不利的,但是如果这家中国餐馆在一个有很多其他中国餐馆的地区(例如唐人街),那么这就降低了失败的风险。从消费者的角度来看,这种观察的一个可能的假设是,像唐人街这样的地区的餐馆缺乏差异化减少了个体餐馆之间的竞争(对于一般商品来说这通常是不正确的,但是当尝试一家新餐馆时,从消费者的角度来看通常缺乏信息)。另一个可能的假设是,消费者的胃口不容易改变,因此唐人街受欢迎的餐馆可能会在他们太忙而无法满足需求的时候吸引周围餐馆的流量:去受欢迎的中国餐馆寻求中餐的人会更喜欢去附近的类似餐馆,如果他们的第一选择太忙而无法为他们服务的话。这一主题有待进一步研究,通过关注一些类似餐馆密度高的特定区域的数据,可以获得更深入的理解。
Yelp 上宣称的餐厅更有可能继续营业。所谓的 Yelp 业务是指所有者努力在 Yelp 上运营,并声明该业务是他们自己的。从这个意义上说,与餐馆成功的正相关是意料之中的。
每周相对评论数量的增加似乎对餐馆的成功有负面影响。这是一个反直觉的结果,并且可能是由两个原因引起的:1)每周的相对评论是通过相对评论的数量除以餐馆的餐馆年龄(自最老评论起的时间)来计算的;餐厅年龄与餐厅成功正相关,用这个数字除一个指标会产生负相关,这可能比评论数效应更重要,2)每周相对评论数与模型已经考虑的相对评论数相关。逻辑回归模型不擅长处理相关特征。
6.建议的改进
这一模型的结果非常有希望,它们表明相对于随机模型,贷款目的有了显著的改善。在我看来,进一步改进的关键是添加更多的功能,可能通过利用不同的数据源。
- 餐馆倒闭的一个可能原因是健康检查评级。将健康检查评级作为一个特性添加到我们的模型中可以提高它的精确度。
- 餐馆关闭的另一个原因是高昂的租金。增加每个地区的租金定价可能有助于解释更多餐馆倒闭的原因。
- 城市特定区域人口统计数据的变化会增加或减少某些餐馆的客流量。
- 新的周边场馆是另一个原因,它可以带动餐馆的客流量,并带来目前这种模式无法预测的成功。
- 餐馆的成功目前被定义为餐馆保持营业。一个更准确的成功定义将更适合贷款的目的,将与餐馆收入相关。即使大多数餐馆的收入不是公开信息,也可以构建相关指标。例如,将餐馆每周收到的评论数量乘以餐馆的价格(即,一般餐饮成本)可以作为有用的度量。
摘要
- 该模型是为餐馆贷款目的而构建的,可以识别在 4 年内仍在营业的餐馆,准确率为 91%。
- 该数据集是通过 Yelp 和谷歌搜索 API 提取 2013 年在亚利桑那州凤凰城存在的餐馆的最新信息建立的。
- 该模型的一些非常有预测性的功能是使用 Yelp 评论和位置元数据构建的。这有助于构建相对指标,如相对于周围餐厅的餐厅密度和数量。
- 使用的机器学习模型是简单的逻辑回归模型,该模型使用交叉验证的网格搜索针对开放式餐馆的精确度进行了优化。
- 我们得到的一个教训是,决定一家餐馆是否继续营业的最重要因素是它是否是连锁店的一部分。属于连锁店的餐馆关门的频率较低。
- 另一个经验是,在有许多其他餐馆的地区建造餐馆通常是负面的,除非这些餐馆提供类似的食物(例如在唐人街建造一家中国餐馆)。
- 该模型可以通过进一步的数据集进行改进,如健康检查数据(目前在亚利桑那州菲尼克斯不公开),以及关于周围场馆的信息。
这个项目的代码可以在这个 github 库中找到。
利用流行病模型提高脸书的广告点击率
本文是与安迪·麦克斯威尼合写的
社交媒体的年度广告预算在过去几年中出现了大幅增长,预计到 2019 年仅在美国就将达到173.4 亿美元。脸书、Twitter 和 Snapchat 等社交媒体公司所展示的直接瞄准巨大市场的能力,为营销机构提供了一种全新、更强大的接触客户的方式。
为了让广告商满意,社交媒体公司通过其网络有效分发广告的方法需要有效地锁定最有可能对广告做出回应的用户。作为他们服务的费用,脸书收取“每次观看”和“每次点击”的费用,所以广告商必须权衡他们的成本和暴露的用户数量。
很明显,脸书计算的是每个用户回复广告的可能性,并且只锁定可能性高的用户。这对营销人员来说是有效的,因为他们的“每次观看”成本是固定的,“每次点击”成本理论上可以被销售额抵消。不清楚的是,如果脸书利用友谊信息,更具体地说,假设:
如果用户点击广告,他们的连接也会点击广告的概率会增加。
基于这种假设,是否可以探索用户网络,以病毒式方式“传播”广告,以获得类似(或更高)的点击量,同时向更少的人显示广告?
为了探索这个想法,我们采用了一个小的子图,即由 4039 个节点和 88234 条边组成的脸书“社交圈”数据集。为了便于理解,你最好把这个网络想象成喜欢脸书网页的用户。大约有 4000 人,他们都是至少一个喜欢这个页面的人的朋友。他们中的一些人非常受欢迎,一个人有 1045 个朋友也喜欢这个页面,而其中的 75 个人只认识一个喜欢这个页面的人。总体而言,学位分布如下:
Lots of nodes have low degree, a few have a high degree. Turns out that’s pretty normal for Facebook
现在,根据一些特征(他们喜欢页面帖子的频率,查看页面的频率,他们喜欢的相似页面等),脸书对每个人真正喜欢这个主题的程度有了一个不错的想法。
我们的第二个假设是,用户与页面交互的概率分布与页面用户的程度分布非常相似。一些人真的很可能会与之互动,而很多人则相当矛盾。这就是为什么你会看到有几千个赞的页面,但只有几百个赞。
这是一个指数分布,如果我们将“与页面互动的概率”替换为“点击与页面主题相关的广告的概率”,我们就有了一个粗略的衡量用户点击广告的潜在概率的方法。我们无法准确衡量这一点,因为我们没有脸书的数据,但我们有一个起点。
Per user likelihood of clicking on an ad that relates to the group. Most users have a small chance, and a few have a decent chance.
为了提出一个“基础案例”来比较我们的流行病模型,我们选择了阻力最小的方法。将广告展示给小组中的每个成员,使用独立的伯努利试验,看看有多少人根据他们的潜在概率做出了回应。
我们进行了 1,000 次测试,在 4039 次浏览中,平均点击次数为 88.54 次,即每次浏览的点击率为 0.0198。每次点击量(CPV)和总点击量是对广告客户很重要的两个指标。
知道了我们必须打破的数字,我们设计了一种方法,利用用户如何连接的信息来更慢地传播广告,但希望有更好的结果
首先,每个用户的潜在概率是使用均值为 0.03 的指数分布来确定的,与基本情况一样。根据用户共享的连接数量,用户之间的每个连接都被赋予 0 到 1 之间的“强度”。如果两个用户都有 12 个朋友,但其中 8 个是他们共有的,他们的优势是 66%。
由此,在沙地上画了一条线。共享超过 50%好友的用户连接被认为是“强”连接,而那些少于 50%的用户连接被认为是“弱”连接。这很容易想象,只要想想和一个亲密的友谊团体的关系,在那里每个人都认识每个人,和一个你认识的同事或亲戚,但不是你朋友的朋友。
考虑到这一点,还有 3 个因素有待确定。
- 假设用户的一个连接先前点击了广告,那么对用户点击广告的概率的实际影响是什么?
- 广告的“传染性”如何,或者它如何在用户之间传播?
- 广告应该如何开始,或者需要多少个“耐心零”?
所有这些因素都必须设置在两个界限之间。太低的话,广告会很快消失,也许会产生很高的点击率,但总点击率很低。对广告商不利。太高,假设不切实际,也不适用。
第一个因素被设定在 10%的最大增幅,与友谊的强度成线性比例。也就是说,如果用户点击了广告,他们的所有连接都会看到他们点击广告的潜在概率增加了一个数量。如果这两个人之间的友谊强度是 60%,那么数量将是 6%。如果人与人之间的力量是 25%,那么这个量就是 2.5%。每次迭代后都会重新计算,如果越来越多的朋友点击广告,用户可以看到多倍的概率增加。
接下来,广告的病毒式传播取决于“广告服务”的构成。也就是说,当用户点击一个广告时,在下一次迭代中,他们的多少个连接以及哪些连接将被显示广告?广告服务的组成范围从 10 个强连接和 0 个弱连接到 16 个强连接和 24 个弱连接。总共测试了 28 篇作文,让 10 人、20 人、30 人或 40 人看一些强朋友和弱朋友的组合。
改变这些数字的目的很简单。虽然强连接在他们的朋友点击广告后出现概率最高,但只向强连接显示可能会使广告停留在小社区或网络的子图中,并限制其传播。另一方面,仅向弱连接显示广告有广告消失的风险,因为调整的概率较低。我们想测试这种平衡行为是如何影响结果的。
最后一个因素,即“种子”组,或“患者零”的数量在 10 到 40 之间变化。由于假设这些人是第一个点击广告的人,他们被选为具有总体最高原创概率的人。这个假设有点牵强,特别是对于 40 人的 seed 组,稍后会有更多的介绍。
在设置了所有因素的情况下,模拟被设置为针对每个广告组合、每个种子组大小在 20 个随机图上运行(因为概率的原始分布是随机的,所以我们复制了模拟以获得更一般化的结果)。当 4000 个用户看过广告,或者在一次迭代中没有新的点击时,每个模拟都结束了。
在第一次模拟中,我们采用了“最佳”每次点击观看比率(针对所有种子组大小),并将结果与广告服务构成和生成的总额外点击量(TACG,或总点击量减去种子组大小)进行了对比。结果如下所示:
我们首先看到的是我们最初的恐惧被证实了。小型广告组合产生了较高的点击率(红点),但整体点击率较低(黑线)。为了避免这种情况,我们根据视图总数过滤了这些点。蓝点达到了 4000 的观看阈值,红点没有(平均而言)。
剔除这些数据后,结果令人振奋。表现最好的广告服务比率是 20 强/ 20 弱,仅播种 12 个初始最高概率用户。
这在 4025 次浏览中平均产生了 122.45 次额外的广告点击,CPV 比率为 0.0304,比基本情况下增加了 53%!
有趣的是,不同的广告组合之间似乎没有太大的区别。尽管那些拥有大量强关系的人在概率上有优势,但弱关系的强度似乎使这种优势达到了平衡!
这非常有趣,因为我们证明了只要减慢广告在网络中的移动速度,每次点击量就会显著增加。
然而,如上所述,我们并不喜欢我们的一些假设。潜在的概率分布和种子用户的选择基本上是随机的,我们想知道是否有更好的方法来模拟这一点。
然后,我们试图对社交媒体“影响者”的真实趋势进行建模。在过去的几年里,社交媒体上“有影响力的人”的崛起经历了巨大的增长。影响者可以被定义为在社交媒体上拥有大量追随者的人,并由公司支付报酬,向他们的网络推广产品。
基于用户的等级(连接的数量),我们可以用它来代表他们在网络中的影响力。然后,我们让用户点击广告的潜在概率等于他们的朋友数量除以网络中任何人的最大朋友数量(1045)。这产生了一个非常接近指数的概率分布!稍微调整一下(将所有概率乘以 0.7),我们得到了一个非常接近我们最初假设的分布。
现在最大的不同是潜在概率不再是随机的!这意味着我们对模拟结果有了更多的信心。
像最初的模拟一样,种子用户仍然是组中概率最高的用户,但现在这些用户是组中实际的影响者。不要认为这些人“最有可能”点击广告,他们实际上可能是那些付费推广广告的用户。对于广告如何被引入生态系统,这是一个更加有机和现实的假设。
我们做的第二个改变是,在用户的连接点击广告后,用户的概率是如何调整的。之前是连接强度乘以 10%。现在是连接强度乘以 5%,加上 15%乘以影响力。这代表了一个事实,即用户更有可能受到网络中某个名人的影响,而不是“某个人”。
5 + 15 系数纯粹是假设,但模型的妙处在于实际数字有些无关紧要。如果它们是 0%和 0%,我们将回到基本情况。如果模型显示出任何非零系数的改进,这就证明了病毒式广告方法是有效的!
话虽如此,我们还是来看看结果吧。模拟以与原始情况类似的方式运行,除了没有 20 个随机图形(因为图形现在是确定性的)。
该图显示了与原始情况大致相同的结果,但是每次查看的点击量和总的额外点击量更高!事实上,最好的情况是使用 36 个强的和 4 个弱的广告组合,用 24 个影响者播种,产生 0.0341 的 CPV。这又产生了 137 次点击。
24 个影响者有点多,他们不便宜这些影响者,所以我们看看是否有稍微差一点的结果,使用较少的影响者。而且有:
16 强 24 弱的广告组合产生了 0.0335 的 CPV 比率和 135 次额外点击,仅使用了 14 个影响者!比基本情况好 70%!
因此,我们已经看到我们的广告服务病毒式营销模式在小图表上产生了惊人的结果,我们想看看它与更大的模式相比会如何。使用 Albert-Barabási 优先模型,我们生成了更大的图形,这些图形非常接近原始脸书图中的度数分布:
The tails of each distribution are a little different, but they’re close enough for what we’re trying to do
我们生成了具有 4,039 个(直接比较)、10,000 个和 20,000 个节点的图,在每种情况下,为每个新节点附加 20 条额外的边(原始脸书图中的平均度数约为 21)。
令人放心的是,这些网络产生了非常相似的结果,并让人们相信该模型可以扩展到脸书或 Twitter 开发的更大的真实世界图表。
从这一建模实践中得出的最终结论是,无论实际调整值是多少,用户通过朋友点击广告而看到的点击广告的概率的任何增加,病毒式营销模型都将产生 CPV 和 TACG 的增加,从而增加社交网络和广告商的收入。
所有的代码和稍微多一点的技术报告都可以在 https://github.com/Padam-0/facebook_viral_advertising 获得
如果你喜欢这篇文章,请点击❤按钮让你的追随者知道,或者让我知道你的想法。
再次衷心感谢安迪·麦克斯威尼对这篇文章的贡献。
为企业利用人工智能云解决方案
Cloud computing
钻研人工智能解决方案来简化业务流程似乎是一项艰巨的任务。幸运的是,有越来越多的资源和基于云的服务可以用来外包或促进商业人工智能的努力。
人工智能解决方案可以集成到业务流程中,以提高生产能力并降低劳动密集型成本负担。
基于云的通用机器学习
几家著名的互联网技术公司提供通用的机器学习和人工智能解决方案,作为端到端数据驱动流程的平台。这些解决方案结合了各种组件来传递数据、安全地托管数据,并提供一系列算法来为决策和相关流程提供及时的分析。
通用解决方案旨在满足不同的需求,能够选择集成的机器学习模块,以便从数据中实现所需的预测输出。人工智能模块可以按顺序连接,一个模块的输出可以作为下一个模块的输入。实时数据处理可以受益于虚拟内核资源上的快速并行处理,因此预测输出可以在终端应用中以非常低的延迟使用。
考虑到可用资源的可扩展性,通用机器学习云解决方案可以适用于简单到多维的人工智能应用。这些解决方案的示例包括:
- 亚马逊 AWS 机器学习 —在人工智能解决方案和内容交付方面拥有多种服务产品。
- 谷歌云人工智能——高度模块化的平台,通过有针对性的集成人工智能解决方案来瞄准特定的用户案例。
- 微软 Azure AI —支持开源 AI 解决方案,重点关注云和本地托管的应用程序组件之间的集成。
- IBM Watson —包括一个专门的业务分析解决方案,可以从多种文档格式中进行人工智能模式识别。
特定任务的人工智能云解决方案
人工智能的云解决方案也适用于特定领域的问题解决和流程自动化。特定于任务的解决方案相对于通用解决方案的优势在于可以简化实施,并提高定制方法的相关性。
利用符合特定业务流特征的云人工智能系统也可以补充更广泛的通用解决方案的使用。在这些场景中,数据从一个解决方案的输出传递到另一个解决方案的输入,直到自动化决策过程获得所需的结果。人工智能特定任务解决方案的示例包括:
- Diffbot AI:X —通过智能分析关系,从 web 内容中提取数据和结构化元数据。
- 猴子学习 —自然语言处理(NLP)和从文档中挖掘文本,具有流程工作流自动化智能。
- 向量空间 —预测金融市场和加密货币趋势的 NLP 机器学习算法。
- 现场智能 —处理多种格式的业务文档,提取信息进行分析和智能处理。
- Tisane Labs —从多语言文本内容中提取见解和情感分析的经济实惠的 NLP 平台。
- Chatler AI —具有学习和推荐智能的客户支持功能的实时聊天引擎。
- Semanti—IPTC 媒体标准下具有主题标识提取和分类的 Web 内容提取 API。
- Edge Verve —致力于特定领域业务应用的人工智能模块,涵盖供应链管理、金融和营销流程。
- Wipro Holmes —结合技术和咨询,定制解决方案,实现业务流程自动化并重新定义运营。
- Rainbird —整理企业知识和专业技能,结合人工智能解决方案,实现更快、更高效的商业决策。
- Ayasdi —业务和流程驱动数据流的模式发现和预测引擎。
- Receptiviti —沟通和语言分析,用于开发实时响应流程的心理和情绪特征。
开源人工智能工具
开源解决方案存在于云或本地开发平台上,可以以更低的成本为商业人工智能工作提供更多的控制。由于许多云解决方案也支持开源模块,在这些模块上进行内部开发可以是测试潜在实现的良好起点。
开源人工智能解决方案的进一步优势包括灵活性和保留定制解决方案知识产权的能力。开源人工智能工具的例子包括:
- WIT AI —一个社区驱动的自然语言处理算法 API,将文本转换成可操作的流程。
- R 编程 —为 R 编程环境开发 AI 解决方案的机器学习包库。
- Acumos AI —一个面向数据科学家和开发人员的人工智能引擎,可以访问用于构建可部署解决方案的机器学习模块市场。
- Caffe 2 —由脸书开发的支持跨平台部署的模块化轻量级深度学习框架。
- 张量流 —谷歌开发的面向数字和科学数据流的机器学习框架。
将人工智能集成到业务流程中
利用人工智能云解决方案需要商业环境中的一些先决条件。需要对要考虑的业务流程进行实施人工智能解决方案的成本效益分析。被认为从人工智能中获益最多的过程将会对它们周围的过程产生影响;因此,对执行情况的流动和整体分析也将是建设性的。
人工智能的实施可能会扰乱员工的士气,特别是当成本降低是通过资本替代劳动力实现的时候。这需要进行管理,以便让那些参与实现的人参与进来,并让那些被替换的人参与到令人满意的过渡场景中。
技术开发需要与现有的过程基础设施、编程语言和输入/输出要求无缝集成。设计可以从定义存在什么输入和期望的输出开始。然后,可以围绕这些定义选择和调整适合的解决方案,以确保最终结果符合所需的值增益。
利用 quosures 在 R Shiny 中创建超灵活的过滤控件
我构建了很多闪亮的应用程序,其中一个常见的用途是允许动态过滤底层数据,这样你就可以根据感兴趣的特定子集来调整图表或表格。
通常,我们将过滤选项硬编码到某种形式的侧边栏菜单中,并为感兴趣的字段定义输入选项列表。例如,如果我们正在过滤mtcars
数据集,我们可能会在 UI 端提供这样的输入选项列表:
shiny::selectInput('cyl', "Select no of cylinders", choices = mtcars$cyl %>% unique() %>% sort())
然后我们可以在服务器端使用input$cyl
过滤mtcars
,例如:
df <- shiny::reactive({
mtcars %>% dplyr::filter(cyl == input$cyl)
})
我一直致力于创建一个更通用的结构,它允许完全灵活的动态过滤系统(类似于 MSExcel 电子表格中的过滤),允许用户选择他们希望过滤的任何字段,以及他们感兴趣的任何字段值。我还想对它进行设置,以便它可以通用地应用于任何数据集,只需要用户指定数据集和允许过滤的列名子集。
闪亮输入的参照透明度
为了做到这一点,我们必须避开非标准的评估问题。在上面的mtcars
示例中,cyl
与input$cyl
的处理方式不同。cyl
在mtcars
的上下文中是引用透明的,但是input$cyl
作为输入变量被传递,其值被引用。例如,如果我们选择input$cyl = 6
,这将被解释为我们在 dplyr 中所期望的:
df <- mtcars %>% dplyr::filter(cyl == '6')
这很好,但是如果我们想选择这个列作为闪亮的输入呢?例如,您可能希望您的用户能够选择 20 或 30 个不同的列进行筛选。也许我们可以为要过滤的选定列创建一个input$col
,为选定的值创建一个input$val
,如下所示:
df <- shiny::reactive({
mtcars %>% dplyr::filter(input$col == input$val)
})
嗯,不,我们不能,因为input$col
是作为引用值传递的,并且不是引用透明的。
这就是 quosures 真正有用的地方,它可以让你抽象出你的过滤能力(以及你的分组、选择和所有其他我们喜欢的关于dplyr
的可爱的事情)。
考虑设置以下简单函数,允许您选择要筛选的列和值:
filter1_by <- function(df, fcol1, fv1) {
filter_var1 <- dplyr::quo(fcol1) df %>% filter_at(vars(!!filter_var1), all_vars(. == fv1))}
这个简单的小函数允许我们使用filter_at()
将列选择(fcol1
)与值选择(fval1
)分开处理。fcol1
现在被捕获为带引号的表达式及其环境,使其在引用上透明,然后我们简单地使用!!
(bangbang)操作符去掉引号,这样dplyr
就可以接受不带引号但在引用上透明的列名。
不用说,这可以扩展到从任意数量的列中选择任意数量的输入进行过滤。例如,允许三个过滤器的函数如下所示:
filter3_by <- function(df, fcol1, fv1, fcol2, fv2, fcol3, fv3) {
filter_var1 <- dplyr::quo(fcol1)
filter_var2 <- dplyr::quo(fcol2)
filter_var3 <- dplyr::quo(fcol3)df %>%
filter_at(vars(!!filter_var1), all_vars(. == fv1)) %>%
filter_at(vars(!!filter_var2), all_vars(. == fv2)) %>%
filter_at(vars(!!filter_var3), all_vars(. == fv3))
)
让我们构建一个完整的示例
让我们继续使用mtcars
构建一个完整的例子。假设我们希望用户能够从mtcars
中的任何可用列中选择三列进行过滤。
我们首先从mtcars
的列名创建一个向量,我们将使用它作为我们的初始输入选择:
fields <- colnames(mtcars)
让我们设置三个函数来基于一列、两列或三列进行筛选:
# filter on 1 columnsfilter1_by <- function(df, fcol1, fv1) {
filter_var1 <- dplyr::quo(fcol1)df %>%
filter_at(vars(!!filter_var1), all_vars(. == fv1))
)# filter on 2 columnsfilter2_by <- function(df, fcol1, fv1, fcol2, fv2) {
filter_var1 <- dplyr::quo(fcol1)
filter_var2 <- dplyr::quo(fcol2)df %>%
filter_at(vars(!!filter_var1), all_vars(. == fv1)) %>%
filter_at(vars(!!filter_var2), all_vars(. == fv2))
)# filter on 3 columnsfilter3_by <- function(df, fcol1, fv1, fcol2, fv2, fcol3, fv3) {
filter_var1 <- dplyr::quo(fcol1)
filter_var2 <- dplyr::quo(fcol2)
filter_var3 <- dplyr::quo(fcol3)df %>%
filter_at(vars(!!filter_var1), all_vars(. == fv1)) %>%
filter_at(vars(!!filter_var2), all_vars(. == fv2)) %>%
filter_at(vars(!!filter_var3), all_vars(. == fv3))
)
现在,让我们构建一个闪亮的输入结构,允许我们至少过滤一列,但最多三列,使用复选框允许用户决定他们是否需要额外的过滤器:
shiny::mainPanel(
# select first filter column from fields vector
shiny::selectInput("filter1", "Select filter column 1:",
choices = fields),
# reference a uiOutput that will offer values for first column
shiny::uiOutput("filter1choice"),
# offer a checkbox to allow user to select a second filter
shiny::checkboxInput("filter2req", "Add second filter?"),
# set further conditional panels to appear in the same fashion
shiny::conditionalPanel(condition = 'input.filter2req',
shiny::uiOutput("filter2eval"),
shiny::uiOutput("filter2choice"),
shiny::checkboxInput("filter3req",
"Add third filter?")),
shiny::conditionalPanel(condition = 'input.filter3req &
input.filter2req',
shiny::uiOutput("filter3eval"),
shiny::uiOutput("filter3choice"))
)
现在我们需要构建uiOutputs
,它根据所选的过滤器列进行填充,并对已经选择的内容进行响应:
# vector of picklist values for the first selected filter
choicevec1 <- reactive({
mtcars %>% dplyr::select(input$filter1) %>% unique() %>% dplyr::arrange_(input$filter1)
})# renders the picklist for the first selected filter
output$filter1choice <- renderUI(
selectizeInput("filter1val", "Select filter 1 condition:", choices = choicevec1(), multiple = TRUE)
)# second column chosen from all remaining fields
output$filter2eval <- renderUI({
selectInput("filter2", "Select filter criteria 2:", choices = sort(fields[fields != input$filter1]))
})# vector of picklist values for the second selected filter
choicevec2 <- reactive({
filter1_by(mtcars, input$filter1, input$filter1val) %>%
dplyr::select(input$filter2) %>%
unique() %>%
dplyr::arrange_(input$filter2)
})# renders picklist for filter 2
output$filter2choice <- renderUI(
selectizeInput("filter2val", "Select filter 2 condition:", choices = choicevec2(), multiple = TRUE)
)# third column selected from remaining fields
output$filter3eval <- renderUI({
selectInput("filter3", "Select filter criteria 3:", choices = sort(fields[!fields %in% c(input$filter1, input$filter2)]))
})# vector of picklist values for third selected column
choicevec3 <- reactive({
filter2_by(mtcars, input$filter1, input$filter1val,
input$filter2, input$filter2val) %>%
dplyr::select(input$filter3) %>%
unique() %>%
dplyr::arrange_(input$filter3)
})# render picklist for filter 3
output$filter3choice <- renderUI(
selectizeInput("filter3val", "Select filter 3 condition:", choices = choicevec3(), multiple = TRUE)
)
所以这就是我们在 UI 端需要做的全部。
在服务器端,我们现在只需要根据选择的输入定义我们需要的过滤器:
filtered_mtcars <- reactive({ # case when all three filters are used
if (input$filter3req & input$filter2req) {
filter3_by(mtcars, input$filter1, input$filter1val,
input$filter2, input$filter2val,
input$filter3, input$filter3val)
} else if (input$filter2req) {
# case when two filters are used
filter2_by(mtcars, input$filter1, input$filter1val,
input$filter2, input$filter2val)
} else {
# case when only one filter is used
filter1_by(mtcars, input$filter1, input$filter1val)
}})
现在你可以显示你的反应数据框filtered_mtcars()
或者在上面进行操作。
在实践和进一步发展中使用这种方法
这些功能可以很容易地移植到你正在设计的任何需要这种灵活过滤的应用程序中。通过简单地编写进一步的函数filter4_by
、filter5_by
等,您可以轻松地扩展到更多的过滤器选择。您还可以通过使用selectizeInput()
并将==
替换为filter_at()
中的%in%
来轻松调整选项列表中的多值选择。
见这里一个非常简单的演示应用程序,我构建了显示奥运会奖牌统计,允许多达三个过滤器。Github 的代码是这里是。
你能帮助改善这一点吗?理想情况下,我们只需要一个如下所示的过滤函数,而不是编写所有这些独立的函数filter1_by
、filter2_by
等:
filter_by <- function (df, ...) {
filter_conditions <- quos(...)
df %>% dplyr::filter(!!!filter_conditions)
}
其中输入是条件列表。这些输入将需要某种调整来应对非标准的评估,但我还没有想出它们应该如何措辞。
如果你破解了就告诉我。
最初我是一名纯粹的数学家,后来我成为了一名心理计量学家和数据科学家。我热衷于将所有这些学科的严谨性应用到复杂的人的问题上。我也是一个编码极客和日本 RPG 的超级粉丝。在LinkedIn或Twitter上找我。
数据科学家和人工智能产品 UX 设计指南
当查找 UX 人工智能产品的设计策略时,我几乎没有找到相关的资料。在我发现的少数几个中,大部分要么过于专业,要么完全专注于 web UIs 的视觉设计。我遇到的关于这个主题的最好的文章是 Vladimir Shapiro 的“ UX 的《人工智能:作为设计挑战的信任》”和 Dávid Pásztor 的“人工智能 UX:设计好的人工智能产品的 7 个原则”。意识到 UX 设计师和数据科学家之间存在着合理的知识差距,我决定尝试从数据科学家的角度来解决这些需求。因此,我的假设是读者对数据科学有一些基本的了解。对于几乎没有数据科学背景的 UX 设计师来说,我避免使用复杂的数学和编程(尽管我鼓励阅读迈克尔·加拉尼克的《如何建立数据科学组合》和我的《数据科学面试指南》。
人工智能正在接管我们日常生活的几乎每个方面。这将改变我们的行为方式以及我们对这些产品的期望。作为设计师,我们的目标是创造有用、易于理解的产品,为这个阴暗的新世界带来清晰。最重要的是,我们想用人工智能的力量让人们的生活变得更轻松、更快乐。
确定关键目标
甚至在我们试图设计我们的产品之前,我们需要理解我们的产品试图解决的整体商业模式。一些常见的问题是:
- 该模型试图解决什么业务问题?是分类问题还是回归问题?
- 谁是最终用户?他们是技术性的还是非技术性的?他们期望从该产品中获得什么价值?
- 数据是什么?数据是静态的还是动态的?模型是基于状态的还是无状态的?正在收集的数据的粒度和质量如何?我们如何最好地表达这些信息?对数据使用是否有监管限制,如 PCI 、 HIPAA 或 GDPR ?
- 这种模式的更大含义是什么?市场有多大?这个市场的其他参与者是谁?他们是在称赞你的产品还是直接竞争对手?转换成本是多少?需要考虑哪些关键的监管、文化、社会经济和技术趋势?
更好地了解最终产品将使我们能够更有效地满足需求。我推荐一些关于这个主题的书,如伯纳德·马尔的《智能公司:基于证据的管理成功的五个步骤》和亚历山大·奥斯特瓦尔德的《商业模式的产生:远见者、游戏改变者和挑战者手册》。
构建可解释的模型
虽然大多数人的目标是一个精确的模型,但是经常忘记理解模型为什么会这样做。模型的优缺点是什么?为什么它为给定的输入要素提供预测?虽然这个问题看起来微不足道,但许多行业都需要提供这个答案,作为其产品价值主张的一部分。
Model interpretation on Credit Karma, Netflix and Amazon
下面是一些真实生活中的用例,其中模型解释是最终用户所要求的:
- 为什么你的信用评分没有现在高?
- 为什么亚马逊推荐我购买某些产品?
- 为什么自动驾驶汽车即使识别了行人也要撞车?
大多数机器学习模型,如决策树和逻辑回归,本质上都是可以解释的。我们可以分析权重系数,可视化树或计算熵来预测最终预测的主要贡献(详情此处)。虽然在过去,大多数商业问题依赖于简单的可解释的模型,但像神经网络这样的“黑箱”模型已经开始变得非常流行。这是因为神经网络以较低的成本为具有复杂决策边界的问题(例如图像和语音识别)提供了高得多的准确性。然而,与大多数传统模型相比,神经网络很难解释。对于有非技术人员的团队来说尤其如此,因为分析神经网络是一项重要的任务。
有些神经网络模型比其他模型更容易解释,例如下面的图像识别模型。
Visualizing Convolutional Neural Networks of an Image Classification Model (Source: Simonyan et al. 2013)
其他时候,我们可以根据预测和输入来推断工程特征。例如,模型可能不具有道路上存在冰的特征。然而,如果道路上的水的存在和道路的表面温度被模型拾取作为输入,我们可以直观地说,冰的存在可以通过特征工程由隐藏层导出。特斯拉的自动驾驶仪导致了致命事故,这只是为什么我们在自动驾驶汽车领域需要可解释的人工智能的一个例子。
Example of how Neural Networks create higher-order features in their hidden layers on self-driving vehicles
有关可解释模型的更多信息,请查看 Lars Hulstaer 的“解释机器学习模型”。
模型解释并不总是需要数学。定性地观察输入及其相应的输出通常可以提供有价值的见解。下面是一个智能安全摄像头误将一名窃贼识别为正在自拍的人,仅仅因为他像拿自拍杆一样拿着吧台。
Source: Mark West — Building a Smart Security Camera with Raspberry Pi Zero, Node.js and The Cloud
处理边缘案例
AI 可以生成内容,并采取以前没有人想到的行动。对于这种不可预测的情况,我们必须花更多的时间来测试产品,并找到怪异、有趣、甚至令人不安的不愉快的边缘情况。一个例子是对聊天机器人ٍbelow.的曲解
Chatbot fails due to unexpected user commands
广泛的实地测试有助于最大限度地减少这些错误。在生产模型上收集清晰的日志有助于在出现意外问题时进行调试。有关测试和 DevOps 相关主题的更多信息,请阅读我的“ DevOps for Data Scientists:驯服独角兽”。
从最终用户的角度来看,清楚地传达产品的功能可以帮助他们理解这些意外情况。例如,在许多情况下,模型必须在精确度和召回率之间进行权衡。
- 优化召回意味着机器学习产品将使用它找到的所有正确答案,即使它显示一些错误的答案。假设我们构建了一个可以识别猫图片的 AI。如果我们优化召回,算法将列出所有的猫,但狗也会出现在结果中。
- 为精确而优化意味着机器学习算法将只使用明显正确的答案,但它会错过一些边缘阳性的情况(看起来有点像狗的猫?).它只会显示猫,但会漏掉一些猫。它不会找到所有的正确答案,只会找到明确的案例。
当我们在人工智能 UX 上工作时,我们帮助开发者决定优化什么。提供关于人类反应和人类优先事项的有意义的见解可以证明是人工智能项目中设计师最重要的工作。
管理期望
虽然相信一个给定的模型可以解决世界上的任何场景是很有诱惑力的,但了解局限性并向最终用户坦诚这些局限性是很重要的。在她的演讲“我们不了解的信任”中,英国哲学家奥诺拉·奥尼尔指出了信任的三个组成部分:能力、诚实和可靠性。坦诚向客户表明,我们有足够的能力、诚实和可靠来维持成功业务所需的长期关系。否则,当产品不能交付时,满足过高的期望和失去信任就更加困难了。
金融产品就是很好的例子。根据政府规定,您的信用评分可能只考虑价值超过 2000 美元的资产。因此,在计算您的分数时,任何低于 2000 美元的资产都不会被模型考虑在内。网络安全产品也是如此。如果该模型每天或每周收集数据,就不能指望它监控 DDoS 攻击。
At 1.3 seconds before impact, Uber’s car decided emergency braking was necessary — but didn’t have the ability to do that on its own. The yellow bands show distance in meters, and the purple indicates the car’s path. (Source: National Transport Safety Board)
最近的优步自动驾驶车祸更是如此:
报告称,在撞击前大约一秒钟,“自动驾驶系统确定需要紧急制动来减轻碰撞。”然而,优步不允许其系统自行进行紧急制动。优步依靠其人类操作员来观察道路并在出现问题时进行控制,而不是冒着“车辆行为不稳定”的风险,如急刹车或转弯以避开塑料袋。
一个自然的反应是自行车上的摄像头没有拍摄到。然而,摄像头确实识别出了行人,但系统选择不停车。这是因为该模型不是为完全取代驾驶员而设计的。
提供反馈机会
好的 UX 设计的目标是交付最终用户满意的产品。为了确保你的用户得到他们想要的,给他们机会对人工智能内容给出反馈。这可以包括电影的评级系统或让银行知道他们的信用卡交易不是欺诈性的。下面是 Google Now 的一个例子。
Google Now asking for feedback on the Recommendation System’ s predictions
请记住,用户反馈也可以作为模型的训练数据。如果我们向机器学习算法提供更多数据,人工智能产品的用户体验会越来越好。
最终外卖
归根结底,人工智能的设计是为了解决一个问题,让生活变得更简单。在开发一个成功的产品时,必须始终以人为中心的设计为核心。没有解决客户需求是主要行业破产并被更好的服务提供商取代的原因。理解客户的需求是前进的关键。
如果你有想法或评论,欢迎订阅我的博客,在推特上关注我。
疫苗和数据科学是未来吗?
Made in Tableau
这个博客有双重目的。首先是给出我的项目是什么,它的目的的一个总体想法。二是更深入的讨论我的 EDA(探索性数据分析)的技术方面。所有的 EDA 都是使用 Anaconda 和 Tableau 完成的。
《英国医学杂志》已经并将继续认为疫苗是人类历史上最伟大的医学进步之一。有了疫苗,我们已经从人群中根除了天花甚至麻疹(短期内)。然而,随着越来越多的被误导的演员、政治家和家长参与进来,他们主张取消儿童疫苗接种,声称疫苗会导致自闭症;近年来,罗马尼亚的麻疹病例激增,爆发了约 3400 起病例,17 人死亡。后者已被一项系统综述无数次否定。2012 年发表在 Cochrane Collaboration 上的一项研究(5 项随机对照试验、1 项对照试验、27 项队列研究、17 项病例对照研究、5 项时间序列试验、1 项病例交叉试验、2 项生态学研究和 6 项自身对照病例系列研究)显示,没有证据表明 MMR 疫苗和自闭症之间存在关系。
As HealthCare Triage(由 Carroll 博士主持的关注健康领域的 Youtube 频道)讨论了各种研究疫苗和自闭症之间关系的研究,以及这些研究如何在让父母给孩子接种疫苗方面不起作用。
作为一名具有生物化学背景的数据科学家和一名在医学领域有着深厚投资的人。我开始研究是否有任何我可以公开使用的数据集来观察第一世界国家可预防疾病的趋势。经过搜索,我找到了一张地图,上面汇集了世界各地可预防疾病的爆发,甚至是对医疗服务提供者的袭击。这张地图是由外交关系委员会编制的。
外交关系委员会的全球健康项目自 2008 年以来一直在跟踪新闻报道,以产生一个…
www.cfr.org](https://www.cfr.org/interactives/GH_Vaccine_Map/#introduction)
在查看了数据和数据清理(主要涉及重命名数据帧中的行和列)之后。我决定忽略的数据是暴力,因为它不符合我接种疫苗和预防疾病的最初目标,并且影响了我的死亡率。我将公告作为变量之一,以观察它是否对任何疾病有任何影响。公告显示,在这两个地区与所有疾病呈负相关。我将北美和欧洲划分为两个独立的数据框架,因为它们有不同的人口和地理类型。这将影响数据相关性和统计。以及了解两个地区之间的差异。
Outbreaks in North America and European Nations using Tableau
总结:
欧洲的平均死亡人数为 226,456 例,占 20.29%,北美的平均死亡人数为 93,810 例,占 14.70%。当我们深入研究影响规模等变量时,我们发现地区是影响事件发生数量的一个重要因素。
了解每个区域的影响范围对于每个区域的行为非常重要。这种流行病更糟糕,因为它涉及到疾病病例数量的增加。其次是聚集性,是疾病病例的集合,但在时间和地点上是紧密分组的。继发性感染是指小于群集或大小相同但感染不局限于一个地方的病例。欧洲比北美有更多的流行病,这与地理和国家边界如何影响疾病的传播有关。
群体免疫是我们接种疫苗的主要原因之一,因为它们可以保护那些由于免疫系统受损而无法接种疫苗的人,或者他们太年轻而无法接种疫苗的人,例如新生儿。R0(R 0)> 1 的疾病成为疫情或流行病的可能性更高。麻疹的 R0(R 零)= 18,因此,如果一个人患有这种疾病,它会将麻疹传播给平均 18 个人。因此,MMR 疫苗(麻疹、腮腺炎、风疹)需要达到 92-95%的群体免疫。旨在实现这种群体免疫的疫苗接种计划至关重要。
变量的相关性
Europe Correlation Heatmap
North America Correlation Heatmap
在两张热图中都可以看到一些有趣的相关性。
- 麻疹与其他疾病呈负相关,甚至与风疹和腮腺炎也呈负相关,而这两种疾病都是用同一种疫苗治疗的
- 这两个地区的公告与病例和死亡呈负相关
- 麻疹与北美的继发性麻疹和欧洲的流行性麻疹相关性最强
- 在北美,百日咳与流行病有较高的相关性,在欧洲,百日咳与死亡有相关性
最后,这个项目有很多有趣的变量相关性。这需要进一步调查。
未完待续…
我在这个项目中的下一个目标是拟合一个模型,并尝试回答以下问题:
- 我们能改进疫苗接种计划吗?
- 我们能预测小热点吗?
- 我们应该针对特定的城市进行疫苗接种吗?
如果你想知道这个项目是如何完成的,以及我接下来还有哪些医疗保健项目,你可以关注我这里的哈维尔·冈萨雷斯-Compte 或者查看我的 Github !随便打个招呼吧!
- 征服无法治愈的疾病。BMJ 2007;334 补充 1: s19。可用:www.bmj.com/cgi/data/334/suppl_1/DC2/1
- 随着麻疹在欧洲激增,官员们准备迎接艰难的一年。可用:http://www . NPR . org/sections/goatsandsoda/2017/04/07/522867040/as-麻疹-浪涌-在欧洲-官员-支撑-为一个粗糙的年
- 德米切利 V,里韦蒂 A,德巴利尼 MG,迪皮特兰托尼 c .https://www.ncbi.nlm.nih.gov/pubmed/22336803
vaex:Python 和快速可视化的核心数据框架
1,008,842,985 taxi dropoff location visualized in 1 second with vaex.
数据越来越大
有些数据集太大,不适合你的台式电脑的主存,更不用说你的笔记本电脑了。尽管如此,我们还是希望在大数据时代使用大型数据集。然而,我们真的不想为了一个小实验而学习设置 Hadoop 或 Spark 基础设施。
我们的梦想
如果您可以立即加载 1tb 的数据文件,只读取您需要的部分,并使用聪明的内核程序员花了几十年时间优化的策略,这不是很好吗?在提出疯狂请求的同时,我们为什么不请求一个感觉有点像熊猫的 API,我们都在使用它。哦,对了,请不要在我的 2013 MacBook Air 上占用太多内存。因为现在是 2018 年,我们都在 Jupyter 笔记本上工作,所以也让它工作,好吗?请确保我所有打开的笔记本也共享该数据集的内存。
如果能瞬间加载 1 TB 的数据文件岂不是很棒。
让我们的梦想成为可能
所有这些都可以通过内存映射来实现,这是一种告诉操作系统您希望一块内存与磁盘上的内容同步的技术。它在技术上非常类似于交换磁盘。如果一块内存没有被修改,或者有一段时间没有被使用,内核将丢弃它,以便 RAM 可以被重用。此外,打开相同文件的所有进程共享相同的物理内存。
内存映射非常出色,你可以立即对一个 1 TB 的文件进行内存映射,内核会智能地决定读取或丢弃什么。现在假设您想过滤掉一些包含不相关数据的行。在 pandas 中,使用我们的 1 TB 数据帧,我们可以执行df_filtered = df[df.x > 0]
,这将复制所有数据,再占用 0.8 TB……实际上,您会看到一个内存错误。
遇见 vaex
Vaex 是一个 Python 库,使得处理如此大的数据集变得轻而易举。除了内存映射之外,除非明确请求,否则它永远不会接触或复制数据。这使得处理硬盘大小的数据集成为可能。此外,它可以进行惰性计算,使用虚拟列,进行有效的数据清理,计算快速的 N 维统计数据,创建交互式可视化等等。
我猜又是一种新的文件格式?不,我们使用好的 ol’ hdf5 格式,任何有自尊的语言都支持这种格式。Vaex 并不真正关心文件格式,只要你能内存映射数据,你就会长寿,繁荣🖖.
阿帕奇箭头
hdf5 不够新颖性感吗?好的,我们支持 Apache Arrow ,它也允许内存映射和与其他语言的互操作性。
所以…没有熊猫🐼?
原作者韦斯·麦金尼(Wes McKinney)在他颇有见地的博客文章中概述了熊猫的一些问题:“ 阿帕奇箭头和“我讨厌熊猫的 10 件事”。这些问题中的许多将在下一版本的熊猫(pandas2?),构建在 Apache Arrow 和其他库之上。Vaex 从头开始,同时保持 API 相似,并准备好今天使用。
Vaex 很懒
Vaex 不仅仅是熊猫的替代品。尽管在执行像np.sqrt(ds.x**2 + ds.y**2)
这样的表达式时,它有一个类似 pandas 的 API 用于列访问,但是不会发生任何计算。而是创建一个 vaex 表达式对象,当打印出来时,它显示一些预览值。
Calling numpy functions with vaex expression leads to a new expression, which delays a computation and saves RAM.
使用表达式系统,vaex 仅在需要时执行计算。此外,数据不需要在本地:表达式可以通过网络发送,统计数据可以远程计算,这是vaex-server
包提供的。
虚拟列
我们还可以向数据帧添加表达式,这将产生虚拟列。虚拟列的行为类似于常规列,但不占用内存。Vaex 不区分真实列和虚拟列,它们被平等对待。
Adding a new virtual column to a DataFrame takes no extra memory.
如果一个表达式在运行时计算起来非常昂贵,该怎么办?通过使用python或 Numba ,我们可以使用手动实时(JIT)编译来优化计算。
Using Numba or Pythran we can JIT our expression to squeeze out a better performance: > 2x faster in this example.
甚至远程数据帧也支持 JIT 表达式(JIT 发生在服务器上)。
内存充足吗?只是物化这个列。你可以选择以 RAM 为代价挤出额外的性能。
Materializing a column converts a virtual column into an in-memory array. Great for performance (~8x faster), but you need some extra RAM.
数据清理
对数据帧的过滤,例如ds_filtered = ds[ds.x >0]
,仅仅导致对现有数据的引用加上一个布尔掩码,该掩码跟踪哪些行被选择,哪些行没有被选择。几乎没有内存使用,也没有内存复制。
df_filtered has a ‘view’ on the original data. Even when you filter a 1TB file, just a fraction of the file is read.
几乎没有内存使用,也没有内存复制。
除了过滤数据帧,选择还可以定义数据的子集。通过选择,您可以在单次通过数据时计算多个子集的统计数据。这对于不适合内存(核外)的数据帧非常有用。
Passing two selections results in two means in a single pass over the data.
缺失的价值观可能是一种真正的痛苦,并不总是很容易决定如何对待它们。使用 vaex,您可以轻松地填充或删除缺少值的行。但是事情是这样的:dropna 和 fillna 方法都是通过过滤和表达式实现的。这意味着,例如,无论数据集的大小如何,您都可以在没有额外内存开销的情况下尝试多个填充值。
You can try several fill values at virtually no extra memory cost.
分类统计
Vaex 在统计方面真的很强。因为我们正在处理大数据,所以我们需要一种替代 groupby 的方法,一种计算速度更快的方法。相反,您可以在一个常规的 N 维网格上计算统计数据,这非常快。例如,即使数据集包含 10 亿行(是的,每秒 10 亿行),也要花大约一秒钟来计算常规箱中一列的平均值!)。
Every statistic method accepts a binby argument to compute statistics on regular Nd array.
是的,每秒 10 亿行!
形象化
制作有意义的图表和可视化是理解数据的最佳方式。但是,当你的数据框架包含 10 亿行时,制作标准散点图不仅需要很长时间,而且会产生无意义和难以辨认的视觉效果。如果您关注聚合属性(如计数、总和、平均值、中值、标准差等),您可以更好地了解数据的结构。)的一个或多个特征/列。当在箱中计算时,这些统计数据给出了数据如何分布的更好的想法。Vaex 擅长此类计算,结果很容易可视化。
让我们看看这些想法的一些实际例子。我们可以使用直方图来可视化单个列的内容。
这可以扩展到二维,产生一个热图。我们可以计算平均值,取总和的对数,或者任何自定义的统计数据,而不是像典型的热图那样简单地计算落入每个箱的样本数。
我们甚至可以使用 ipyvolume 制作三维体积渲染。
由于在 N 维网格上计算统计数据的底层机制如此之快,我们可以在运行中完成它们,并拥有交互式可视化
(基于 bqplot )。
Interactively exploring 150 million taxi trips using vaex+bqplot
更多?
是的,vaex 包括一个厨房水槽,但它是一个模块化厨房水槽。Vaex 实际上是一个元包,它将安装 vaex 家族中的所有 Python 包。以下是软件包列表:
vaex-core
: DataFrame 和核心算法,将 numpy 数组作为输入列。vaex-hdf5
:向 vaex 数据帧提供内存映射的 numpy 数组。vaex-arrow
:类似,但是用的是阿帕奇箭。vaex-viz
:基于 matplotlib 的可视化。vaex-jupyter
:基于 Jupyter widgets/ipywidgets、 bqplot 、 ipyvolume 和 ipyleaflet 的交互可视化。vaex-astro
:天文学相关的转换和 FITS 文件支持。vaex-server
:提供远程访问数据帧的服务器。vaex-distributed
:(概念验证)将多个服务器/集群组合成一个数据框架,用于分布式计算。vaex-ui
:基于 Qt 的交互式独立 app/GUI。
想要更多吗?
我们一直在努力让 vaex 变得更好。但这还不是全部。我们也在非常努力地开发vaex-ml
,这是一个为 vaex 增加机器学习能力的包。一些非常酷的东西即将推出,敬请关注!与此同时,请查看这个现场演示,了解 vaex 的实际操作和vaex-ml
的预览。
通过我们在 PyParis 2018 上的现场演示,了解有关 vaex 和 vaex-ml 的更多信息
您也可以使用 mybinder 在 Jupyter 笔记本上在线试用这篇文章的片段:
Click the button to launch a Jupyter notebook to try out the code snippets from the article
结论
你准备好接受大表格数据了吗?我们是!零内存复制策略、内存映射、类似 pandas 的 API 以及 N 维网格上极快的统计计算速度,使 vaex 成为探索和分析海量数据集的首选 Python 库。所有这一切都来自您舒适的笔记本电脑或个人电脑。Vaex 是开源的(MIT),在 GitHub 上,查看它的主页,文档文档,或者在 gitter 上提问。尝试一下,让我们知道你的想法。
Maarten Breddels 是一名企业家和自由职业开发人员/顾问/数据科学家,主要从事 Jupyter 生态系统中的 Python、C++和 Javascript 工作。 的创始人 vaex.io 。他的专业领域从快速数值计算、API 设计到 3d 可视化。他拥有 ICT 学士学位,天文学硕士和博士学位,喜欢编码和解决问题。
股票图片来自https://pixabay.com/
可变自动编码器
当我们遇到没有标签的数据会怎样?大多数深度学习技术需要干净标签的数据,但这有多现实?其核心是,这种技术本质上是说,如果你有一组输入和它们各自的目标标签,你可以尝试和学习一个特定标签对于一个特定目标的概率。当然,所以美化图像映射?在这篇文章中,我将探索变分自动编码器,以更深入地探索未标记数据的世界。该模型将在对没有标签的图像集合进行训练之后生成独特的图像。
自动编码器顺序地将输入数据解构造成隐藏的表示,并使用这些表示来顺序地重建与其原始数据相似的输出。从本质上讲,数据压缩是特定于数据的,这意味着它只能压缩与其接受训练的数据相似的数据。众所周知,自动编码器也是有损耗的,因此解压缩后的输出与原始输入相比会有所下降。那么,如果它们导致质量下降,为什么它们有用呢?好问题是,它们对数据去噪非常有用,我们训练自动编码器从其自身的损坏版本中重建输入,以便它可以消除类似的损坏数据。
在这篇文章中,我通过他的 youtube 频道使用我的主要男人,Siraj 的支持,并潜入变分自动编码器(VAE)。
让我们从贝叶斯推断说起。阅读这篇文章的每个人可能都知道深度学习及其在逼近复杂函数时的有用性,然而,贝叶斯推理提供了一个推理不确定性的独特框架。在其中,所有的不确定性都用概率来表示。如果你想一想,这是有意义的,在任何给定的时间都存在支持或反对我们已经知道的东西的证据,这些证据可以用来创造一个新的概率。进一步延伸,当我们学习新的东西时,我们必须考虑到我们已经知道的东西,并加入新的证据来创造新的概率。贝叶斯理论基本上从数学上描述了这个想法。
VAE 是这些思想的产物。从贝叶斯的角度来看,我们可以将 VAE 的输入、隐藏表示和重构输出视为有向图形模型中的概率随机变量。假设它包含某些数据的特定概率模型 x 和潜在/隐藏变量 z。我们可以将模型的联合概率写出如下:
Joint Probability of a Model
给定一个由模型产生的角色,我们不知道潜在变量的什么设置产生了这个角色,我们的模型本质上是随机的!
现在,让我们打开深度学习镜头,VAE 由 3 个主要部分组成:
- 编码器
- 解码器
- 损失函数
给定一些输入 x,假设我们有一个 28 乘 28 的手写数字图像,它有 784 个维度,其中每个像素是一维的。现在,这将编码成一个潜在的/隐藏的表示空间,这将比 784 少得多。我们现在可以对高斯概率密度进行采样,以获得表示的噪声值。
酷毙了。让我们用代码来写吧!(我已经在这篇文章的末尾链接了完整的代码)
首先,我们导入库并找到我们的超参数。
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
from keras.layers import Input, Dense, Lambda
from keras.models import Model
from keras import backend as K
from keras import objectives
from keras.datasets import mnist# Hyperparameters
batch_size = 100
original_dim = 784
latent_dim = 2
intermediate_dim = 256
nb_epoch = 10
epsilon_std = 1.0
接下来,我们初始化我们的编码器网络。这个网络的工作是将输入映射到我们隐藏的分布参数。我们获取输入,并通过 ReLU(压缩维度的经典非线性)的密集全连接层发送。接下来,我们将输入数据转换成隐藏空间中的两个参数。我们使用密集、完全连接的层来预定义大小——z 均值和 z 对数西格玛。
#encoder
x = Input(batch_shape = (batch_size, original_dim))
h = Dense(intermediate_dim, activation = ‘relu’)(x)
z_mean = Dense(latent_dim)(h)
z_log_var = Dense(latent_dim)(h)print(z_mean)
print(z_log_var)
解码器将“z”作为其输入,并将参数输出到数据的概率分布。让我们假设每个像素是 1 或 0(黑或白),现在我们可以使用伯努利分布,因为它将成功定义为一个二进制值来表示单个像素。因此,解码器将获得一个数字的潜在/隐藏表示作为其输入,并且它输出 784 个伯努利参数,每个像素一个,因此本质上是 0 和 1 之间的 784 个值。
我们将使用 z_mean 和 z_log_var,通过定义采样函数,从隐藏/潜在正态分布中随机采样新的相似点。下面代码块中的ε是一个随机正规张量。
def sampling(args):
z_mean, z_log_var = args
epsilon = K.random_normal(shape=(batch_size, latent_dim), mean=0.)
return z_mean + K.exp(z_log_var / 2) * epsilon
# note that “output_shape” isn’t necessary with the TensorFlow backend
z = Lambda(sampling, output_shape=(latent_dim,))([z_mean, z_log_var])#latent hidden state
print(z)
一旦我们得到 z,我们可以把它输入到我们的解码器,解码器会把这些潜在空间点映射回原始输入数据。因此,为了构建一个解码器,我们首先用两个完全连接的层和它们各自的激活函数来初始化它。因为数据是从一个小的维度提取到一个更大的维度,所以在重建过程中会丢失一些数据。
#decoder
# we instantiate these layers separately so as to reuse them later
decoder_h = Dense(intermediate_dim, activation=’relu’)
decoder_mean = Dense(original_dim, activation=’sigmoid’)
h_decoded = decoder_h(z)
x_decoded_mean = decoder_mean(h_decoded)print(x_decoded_mean)
酷,但是一些多少钱?所以我们将建立损失函数来精确测量。下面的第一项测量重建损失。如果解码器输出在重建数据方面表现不佳,此时将考虑损失方面的成本。下一个术语是正则化,这意味着它尽可能保持每个数字的表示形式多样化。举个例子,如果两个不同的人写出数字 3,结果可能看起来非常不同,因为,当然,不同的人写的不同。这可不好,正则来救援!我们惩罚不良行为(像这里的例子),并确保类似的表现是紧密联系在一起的。我们的总损失函数被定义为我们的重建项和 KL 散度正则化项之和。
#loss
def vae_loss(x, x_decoded_mean):
xent_loss = original_dim * objectives.binary_crossentropy(x, x_decoded_mean)
kl_loss = — 0.5 * K.sum(1 + z_log_var — K.square(z_mean) — K.exp(z_log_var), axis=-1)
return xent_loss + kl_lossvae = Model(x, x_decoded_mean)
vae.compile(optimizer=’rmsprop’, loss=vae_loss)
现在是训练部分,我们通常使用梯度下降来训练该模型,以优化编码器和解码器参数的损失。但是我们如何对随机变量的参数求导呢?
事实证明,我们已经将随机性融入了我们的模型本身。现在,梯度下降通常期望对于一组固定的参数,给定的输入总是返回相同的输出。在我们的例子中,随机性的唯一来源是输入。那么我们如何解决这个问题呢?我们参数化!我们将对样本进行参数化,以使随机性与参数无关。
我们将定义一个确定性地依赖于参数的函数,因此我们可以通过引入一个随机变量将随机性注入到模型中。编码器将生成均值向量和标准差向量,而不是生成实值向量。我们对包含 z 的函数求关于其分布参数的导数。我们已经将模型的优化器定义为 rmsprop,将损失函数定义为 vae_loss。
我们通过导入 MNIST 数据集并根据给定的历元数和批量大小将它们输入到我们的模型中来开始下面的训练。
# train the VAE on MNIST digits
(x_train, y_train), (x_test, y_test) = mnist.load_data()x_train = x_train.astype(‘float32’) / 255.
x_test = x_test.astype(‘float32’) / 255.
x_train = x_train.reshape((len(x_train), np.prod(x_train.shape[1:])))
x_test = x_test.reshape((len(x_test), np.prod(x_test.shape[1:])))vae.fit(x_train, x_train,
shuffle=True,
nb_epoch=nb_epoch,
batch_size=batch_size,
validation_data=(x_test, x_test),verbose=1)
下面我们在一个 2D 平面上画出了邻近区域。每个彩色的簇代表一个数字表示,紧密的簇实质上是结构相似的数字。
# build a model to project inputs on the latent space
encoder = Model(x, z_mean)# display a 2D plot of the digit classes in the latent space
x_test_encoded = encoder.predict(x_test, batch_size=batch_size)
plt.figure(figsize=(6, 6))
plt.scatter(x_test_encoded[:, 0], x_test_encoded[:, 1], c=y_test)
plt.colorbar()
plt.show()
Digit Representation
表示这一点的另一种方式是通过扫描潜在平面、以规则的间隔对潜在点进行采样并为这些点中的每一个生成相应的数字,如下所示:
# build a digit generator that can sample from the learned distribution
decoder_input = Input(shape=(latent_dim,))
_h_decoded = decoder_h(decoder_input)
_x_decoded_mean = decoder_mean(_h_decoded)
generator = Model(decoder_input, _x_decoded_mean)# display a 2D manifold of the digits
n = 15 # figure with 15x15 digits
digit_size = 28
figure = np.zeros((digit_size * n, digit_size * n))
# linearly spaced coordinates on the unit square were transformed through the inverse CDF (ppf) of the Gaussian
# to produce values of the latent variables z, since the prior of the latent space is Gaussian
grid_x = norm.ppf(np.linspace(0.05, 0.95, n))
grid_y = norm.ppf(np.linspace(0.05, 0.95, n))for i, yi in enumerate(grid_x):
for j, xi in enumerate(grid_y):
z_sample = np.array([[xi, yi]])
x_decoded = generator.predict(z_sample)
digit = x_decoded[0].reshape(digit_size, digit_size)
figure[i * digit_size: (i + 1) * digit_size,
j * digit_size: (j + 1) * digit_size] = digitplt.figure(figsize=(10, 10))
plt.imshow(figure, cmap=’Greys_r’)
plt.show()
Generated Digits
这在一定程度上让你大吃一惊!
因此,在这个练习的本质上,有三个要点:
- 变分编码器允许我们通过执行无监督学习来生成数据
- VAEs =贝叶斯推理+深度学习
- 重新参数化允许我们通过网络反向传播,通过使随机性独立于允许我们导出梯度的参数。
在机器学习的宇宙中,这是一个非常迷人的世界,我希望我能够通过这篇文章给你带来一些价值!
解释了各种自动编码器
想知道变分自动编码器(VAE)模型是如何工作的吗?你想知道 VAE 是如何能够生成与它所训练的数据集相似的新样本的吗?
读完这篇文章后,你将对 VAE 的内部运作有一个理论上的理解,并且能够自己实现它。
在未来的一篇文章中,我将为你提供一个在手写数字图像数据集上训练的 VAE 的工作代码,我们将有一些生成新数字的乐趣!
生成模型
VAE 是一个生成模型,它估计训练数据的概率密度函数(PDF)。如果这样的模型是在看起来自然的图像上训练的,它应该给狮子的图像分配高概率值。另一方面,随机乱码的图像应该被赋予低概率值。
VAE 模型还可以从学习过的 PDF 中抽取样本,这是最酷的部分,因为它能够生成看起来与原始数据集相似的新样本!
我将使用 MNIST 手写数字数据集来解释 VAE。模型的输入是 2828 维空间(ℝ[28∙28]).)中的图像如果输入看起来像一个数字,模型应该估计一个高概率值。
对图像建模的挑战
像素之间的相互作用带来了巨大的挑战。如果像素是彼此独立的,我们将需要独立地学习每个像素的 PDF,这很容易。采样本来也是轻而易举的——我们只是独立地对每个像素进行采样。
在数字图像中,像素之间有明显的相关性。如果你看一个图像的左半部分,看到一个 4 的开始,你会非常惊讶地看到右半部分是一个 0 的结束。但是为什么呢?…
潜在空间
你知道一个数字的每个图像应该包含一个单独的数字。ℝ[28∙28 的输入]并不明确包含该信息。但是它一定存在于某个地方…某个地方的就是潜在空间。
The latent space. Photo by Samuel Zeller on Unsplash
你可以把潜在空间想象成ℝ[k 】,其中每个矢量都包含绘制一幅图像所需的 k 条基本信息。假设第一维包含由数字表示的数字。第二维可以是宽度。第三——角度。诸如此类。
我们可以把生成图像的过程想象成一个两步过程。首先,这个人有意识或无意识地决定他要画的数字的所有属性。接下来,这些决定转化为笔触。
VAE 试图对这一过程进行建模:给定一幅图像 x ,我们想要找到至少一个能够描述它的潜在向量——一个包含生成 x 的指令的向量。使用全概率的定律公式化它,我们得到
让我们给这个等式注入一些直觉:
- 积分意味着我们应该在整个潜在空间中寻找候选者。
- 对于每一个候选 z ,我们问自己:是否可以使用 z 的指令生成 x ? P(x|z) 够大吗?例如,如果 z 对数字为 7 的信息进行编码,则 8 的图像是不可能的。然而,1 的图像可能是可能的,因为 1 和 7 看起来相似。
- 我们找到一个好的 z ?很好!但是等一下…这有可能吗? P(z) 够大吗?让我们考虑一个颠倒的 7 的给定图像。描述相似外观 7 的潜在向量将是完美匹配,其中角度维度被设置为 180 度。然而,那个 z 不太可能,因为通常数字不会以 180 度角绘制。
VAE 的训练目标是最大化 P(x) 。我们将使用多元高斯𝓝 *(f(z),𝜎I)*对 P(x|z) 建模。
f(z) 将使用神经网络建模。 𝜎 是一个将单位矩阵 I 相乘的超参数。
你应该记住 f 是我们在使用训练好的模型生成新图像时要用到的。强加高斯分布仅用于训练目的。如果我们使用 Dirac delta 函数(即 x = f(z) 确定性),我们将无法使用梯度下降来训练模型!
潜在空间的奇迹
潜在空间方法有两个大问题:
- 每个维度包含哪些信息?一些维度可能与抽象的信息有关,例如风格。即使解释所有维度很容易,我们也不想给数据集分配标签。这种方法无法扩展到新的数据集。
- 潜在空间可能是纠缠的,即维度可能是相关的。例如,一个手指画得非常快,可能会导致有角度的和更细的笔触。指定这些依赖关系很难。
深度学习拯救世界
事实证明,每个分布都可以通过对标准多元高斯函数应用足够复杂的函数来生成。
因此,我们将选择 P(z) 作为标准多元高斯。由神经网络建模的 f 因此可以分为两个阶段:
- 第一层将高斯映射到潜在空间的真实分布。我们无法解释维度,但这并不重要。
- 然后,后面的层将从潜在空间映射到 P(x|z) 。
那么我们该如何训练这只野兽呢?
P(x) 的公式很难处理,所以我们将使用蒙特卡罗方法来近似它:
- 样本{ zᵢ } (i = 1…n)来自先前的 P(z) 。
- 近似使用p(x)≈(1/n)∙∑p(x|zᵢ)。
太好了!因此,我们只需对一些 z 进行采样,然后让反向传播派对开始!
不幸的是,由于 x 具有高维数,因此需要许多样本来获得合理的近似。我的意思是,如果你对 z 进行采样,你最终得到一个看起来和 x 有关的图像的可能性有多大?顺便说一下,这解释了为什么 P(x|z) 必须为任何可能的图像分配正概率值,否则模型将无法学习:采样的 z 将产生几乎肯定不同于 x 的图像,如果概率为 0,梯度将不会传播。
那么,我们如何解决这个烂摊子呢?
我们走捷径吧!
Photo by Stefan Steinbauer on Unsplash
大多数被取样的 z 对 P(x)没有任何贡献——它们太差了。如果我们能提前知道从哪里取样就好了…
我们可以引入 Q(z|x) 。 Q 将被训练为向可能已经生成 x 的 z 给出高概率值。现在,我们可以使用来自 Q 的更少样本来计算蒙特卡罗估计。
不幸的是,新的问题出现了!而不是最大化
我们将最大化以下内容
这两者之间有什么关系?
变分推理
变分推理是一个自成一帖的话题,这里就不细说了。我要说的是,这两者确实通过这个等式联系在一起:
KL 是kull back–lei bler 散度,它直观地衡量两个分布有多相似。
一会儿你会看到我们如何最大化等式的右边。这样,左侧也将被最大化:
- P(x) 将被最大化。
- 从 P(z|x) 到 Q(z|x) 有多远——我们不知道的真实后验——将被最小化。
等式右边背后的直觉是我们有一个张力:
- 一方面,我们希望最大化从 z ~ Q 解码 x 的效果。
- 另一方面,我们希望Q(z | x)(编码器)类似于先前的 P(z) (多元高斯)。人们可以把这个术语看作是正则化。
给定正确的分布选择,最小化 KL 散度是容易的。我们将把 Q(z|x) 建模为神经网络,其输出是多元高斯的参数:
- 一个平均值 μ_Q
- 对角协方差矩阵σ_ Q
KL 散度然后变得解析可解,这对我们(和梯度)是很好的。
解码器部分有点棘手。天真的是,我们会用蒙特卡罗来解决这个棘手的问题。但是从 Q 对 z 进行采样不会允许梯度通过 Q 传播,因为采样不是可微分的操作。这是有问题的,因为输出σ_ Q和 μ_Q 的层的权重不会被更新。
重新参数化的技巧
我们可以用无参数随机变量的确定性参数化变换来代替 Q :
- 来自标准(无参数)高斯的样本。
- 将样本乘以σ_ Q的平方根。
- 将 μ_Q 加到结果上。
结果将具有等于 Q 的分布。现在采样操作将从标准高斯。因此,梯度将能够通过σ_ Q和 μ_Q 传播,因为现在这些是确定性路径。
结果呢?该模型将能够学习如何调整 Q 的参数:它将集中于能够产生 x 的好的 z 。
将这些点连接起来
VAE 模式可能很难理解。我们在这里讨论了很多材料,可能会让人不知所措。
因此,让我总结一下实施 VAE 需要掌握的所有步骤。
左侧是模型定义:
- 输入图像通过编码器网络。
- 编码器输出分布参数 Q(z|x) 。
- 从 Q(z|x) 中采样潜在向量 z 。如果编码器学会做好它的工作,大多数机会是 z 将包含描述 x 的信息。
- 解码器将 z 解码成图像。
右边是损失:
- 重构误差:输出应该类似于输入。
- Q(z|x) 应该类似于先验(多元标准高斯)。
为了生成新的图像,可以直接从先验分布中采样一个潜在向量,并将其解码成图像。
在下一篇文章中,我会给你提供一个 VAE 的工作代码。此外,我将向您展示如何使用一个巧妙的技巧来调节潜在向量,以便您可以决定要为哪个数字生成图像。敬请期待:)
笔记
这篇文章是基于我的直觉和以下来源:
这个帖子最初是我在www.anotherdatum.com发的。
变型自动编码器详细解释
在本系列的前一篇文章中,我介绍了变分自动编码器(VAE)框架,并解释了其背后的理论。
在这篇文章中,我将更详细地解释 VAE,或者换句话说,我将提供一些代码:)
读完这篇文章后,你会理解实现 VAE 所需的技术细节。
作为奖励,我将向您展示如何通过对一些潜在向量的维度施加特殊作用,该模型可以根据手指类型生成图像。
该模型将在MNIST——手写数字数据集上进行训练。输入是ℝ[28∙28].的图像
接下来,我们将定义将要使用的超参数。
随意使用不同的值来感受模型是如何被影响的。笔记本可以在这里找到。
模型
该模型由三个子网络组成:
- 给定 x (图像),将其编码成潜在空间上的分布——在前一篇文章中称为Q(z|x)。
- 给定 z 在潜空间(一个图像的代码表示),解码成它所表示的图像——在上一篇文章中称为 f ( z )。
- 给定 x ,通过将其映射到大小为 10 的层来对其数字进行分类,其中第 I 个值包含第 I 个数字的概率。
前两个子网络是普通的 VAE 框架。
第三个用作辅助任务,它将执行一些潜在维度来编码图像中的数字。让我解释一下动机:在上一篇文章中,我解释过我们不在乎潜在空间的每个维度包含什么信息。该模型可以学习编码它认为对其任务有价值的任何信息。因为我们熟悉数据集,所以我们知道数字类型应该很重要。我们希望通过向模型提供这些信息来帮助它。此外,我们将使用这些信息生成以手指类型为条件的图像,我将在后面解释。
给定数字类型,我们将使用一种热编码对其进行编码,即大小为 10 的向量。这 10 个数字将被连接成潜在向量,因此当将该向量解码成图像时,该模型将利用数字信息。
有两种方法为模型提供一个热编码向量:
- 将其作为输入添加到模型中。
- 将它添加为标签,这样模型将必须自己预测它:我们将添加另一个预测大小为 10 的向量的子网络,其中损失是与预期的一个热向量的交叉熵。
我们将采用第二种选择。为什么?在测试时,我们可以以两种方式使用这个模型:
- 提供图像作为输入,并推断潜在向量。
- 提供潜在向量作为输入,并生成图像。
因为我们也想支持第一个选项,所以我们不能为模型提供数字作为输入,因为我们在测试时不会知道它。因此,模型必须学会预测它。
既然我们已经了解了组成模型的所有子网,我们就可以对它们进行编码了。编码器和解码器背后的数学细节可以在之前的文章中找到。
培养
我们将使用 SGD 训练模型来优化两种损失——VAE 损失和分类损失。
在每个时期结束时,我们将对潜在向量进行采样,并将它们解码成图像,这样我们就可以直观地看到模型的生成能力如何随着时期的推移而提高。取样方法如下:
- 根据我们想要生成图像的数字,确定性地设置用于数字分类的维度。例如,如果我们想要生成数字 2 的图像,这些尺寸将被设置为[0010000000]。
- 根据先验——多元高斯随机抽取其他维度的样本。我们将把这些采样值用于我们在给定时期生成的所有不同数字。通过这种方式,我们可以对其他维度的编码有一种感觉,例如笔画风格。
步骤 1 背后的直觉是,在收敛之后,模型应该能够使用这些维度对输入图像中的数字进行分类。另一方面,这些维度也用于解码步骤以生成图像。这意味着解码器子网络了解到当这些维度具有对应于数字 2 的值时,它应该生成该数字的图像。因此,如果我们手动设置这些维度来包含数字 2 的信息,我们将得到该数字的生成图像。
让我们验证一下这两种损失看起来都不错,也就是说——在减少:
此外,让我们绘制生成的图像,看看模型是否真的能够生成数字图像:
最后的想法
很高兴看到使用一个简单的前馈网络(没有花哨的卷积),我们能够在仅仅 20 个时期后生成好看的图像。该模型很快学会了使用特殊的数字维度——在第 9 纪元,我们已经看到了我们试图生成的数字序列。
每个纪元对其他维度使用不同的随机值,因此我们可以看到不同纪元之间的风格如何不同,而每个纪元内部的风格是相似的——至少对于某些纪元而言是如此。例如,与时段 20 相比,在时段 18,所有的数字都更粗。
我邀请你打开这个笔记本和 VAE 一起玩耍。例如,超参数值对生成的图像有很大影响。玩得开心:)
变分推理:伊辛模型
在二值图像去噪的应用中
本文主要研究 Ising 模型的变分推理在二值图像去噪中的应用。
Noisy gray-scale image (left) and denoised binary image (right)
例如,在上图中,左边是一幅有噪声的灰度图像,右边是一幅去噪的二值图像。
伊辛模型是马尔可夫随机场(MRF)的一个例子,它起源于统计物理学。伊辛模型假设我们有一个节点网格,其中每个节点可以处于两种状态之一。在二进制图像的情况下,您可以将每个节点看作是一个黑色或白色的像素。每个节点的状态通过相互作用势依赖于相邻节点。在图像的情况下,这转化为平滑度约束,即像素喜欢与相邻像素具有相同的颜色。
在图像去噪问题中,我们假设我们有一个潜在真实图像的噪声像素观察的 2-D 网格,并且我们想要恢复真实图像。因此,我们可以将图像建模为网格:
Variational approximation (left) and the Ising model [1] (right)
上图显示了 Ising 模型1,其中阴影节点是{-1,+1}中二元潜在变量(无阴影节点)x _ i \的噪声观测值 y_i。左边的方程代表我们的变分近似,我们将在下面得到。
我们可以将联合分布写为:
其中,对于一组边 E 中的每对节点 x_s 和 x_t,相互作用势由ψ_ ST 表示,并且观察值 y_i 是具有等于σ平方的均值 x_i 和方差的高斯型。这里,w_st 是耦合强度,并且被假设为常数,并且等于 J>0,指示对于作为邻居的相同状态的偏好(即,当 x_s 和 x_t 都是+1 或-1 时,potential \Psi(x_s,x_t) = \exp{x_s J x_t}较高)。
变分推断背后的基本思想是选择接近原始分布 p(x)的近似分布 q(x ),其中距离通过 KL 散度来测量:
这将推理转化为优化问题,目标是最小化 KL 散度或最大化证据下限(ELBO)。我们可以导出 ELBO 如下:
在伊辛模型的应用中,我们有:
在平均场变分推断中,我们假设一个全因子近似 q(x):
可以证明[2]q(x _ I;最小化 KL 发散的μI 由下式给出:
其中 E_{-q_i}表示除 j=i 之外的所有 q_j 的期望值,为了计算 q_i(x_i),我们只关心涉及 x_i 的项,也就是说,我们可以将它们分离如下:
其中 N(i)表示节点 I 的邻居,\mu_j 是二进制随机变量的平均值:
为了计算这个平均值,我们需要知道 q_j(x_j=+1)和 q_j(x_j=-1)的值。设 m_i = \sum_{j\in N(i)} w_ij mu_j 为邻居的平均值设 l_{i}^{+} = n(x _ I =+1;σ)和 l_{i}^{-} = n(x _ I =-1;sigma),那么我们可以如下计算平均值:
换句话说,我们在迭代 k 时参数\mu_i 的平均场变分更新计算如下:
我们增加了一个学习率参数λ。既然我们得到了我们的变分更新,我们可以用 python 实现二值图像去噪。
ELBO objective (left) and average entropy (right)
上图显示了实验结果。注意左边的 ELBO 图是单调增加的,在大约 10 次平均场迭代后变平。右图显示了平均熵的减少:
由于随机初始化,我们期望平均熵在开始时很高。然而,随着迭代次数的增加,平均场更新收敛于与观测值及其邻居一致的 x_i 的二进制值,导致平均熵减小。
密码
实现基于平均场变分推理的二值图像去噪的所有代码可以在下面的 ipython 笔记本中找到。
参考
[1] E. Sudderth,“CS242:概率图形模型”,【http://cs.brown.edu/courses/cs242/lectures/
[2] K. Murphy,“机器学习:概率视角”,麻省理工学院出版社,2012 年
电报信息主题的变化
Photo by Ketut Subiyanto: https://www.pexels.com/photo/serious-woman-using-smartphone-4353614/
介绍
你有没有想过你的网上足迹对你的行为有什么影响?我最近读了塞思·斯蒂芬斯的书,他在书中描述了基于搜索引擎和社交搜索查询等在线来源的数据对人类行为的见解。我发现这很有趣,因为有了互联网,数据科学家可以访问大量人的各种公共使用数据。随着我对的深入阅读,我开始把我生活中的每一件事想象成一张图表,把对话想象成我头脑中的原始数据,也许我可以利用它们。**
在我的脑海中,每个人都在撒谎,我很有兴趣看看在我自己使用的网站和应用程序中,我可以访问哪些类型的数据。因此,许多主要的社交网站和应用程序都有可以访问使用数据的 API。作为一名数据科学家,我发现一旦我学会了如何利用 API,这项技能就为各种探索打开了许多大门。通过使用 API,我获得了所有这些可能性,我受到启发,去做与 Stephens 在他的书中所做的类似的项目,但更多地与我自己的生活和兴趣相关。
大约在这个时候,在美国呆了一年后,我回到了哈萨克斯坦的家。即使我搬回了世界的另一端,我仍然想和我的一位名叫约书亚的美国密友保持联系。最后,我们每天通过即时通讯应用 Telegram 聊上几个小时。我们互相了解生活的最新情况,谈论政治、人际关系、旅行和许多其他事情。发了这么长时间短信,我突然意识到我们正在创建一个我个人非常熟悉的大数据集,我可能会出于兴趣对其进行分析。
该项目
第一步是访问 Telegram 的 API 。Telegram 的 API 允许访问我自己的使用数据。我还从一个朋友那里请求了聊天 id,以便访问双方的聊天数据。我用 Python 做了所有的工作,并用 Jupyter Notebook 作为这个项目的内核。在开始加载所有数据之前,我下载了所有需要的包。您可以在本文末尾的 GitHub 库中找到我的完整代码和一步一步的说明。
我的项目包括 4 个月的聊天数据。数据分两批下载。我总共处理了 17904 条信息。这些消息包括字符串、媒体内容、gif、贴纸和表情符号。
Final data saved in two batches
我首先删除了不是文本的信息,比如媒体和贴纸。这从数据集中筛选出了 2202 条信息,留下了我们之间发送的多达 15702 条短信。然后我用两个用户名来划分数据。我很惊讶我们每个人发的短信数量有这么大的差异。
Number of messages by usernames
然后,我努力排除停用词,如:语法冠词、连词和其他与我们谈话内容无关的语言的外围用法。
图表 1 —每天的消息数
第一个图表包括每天的邮件数量。令人惊讶的是,一天之内竟然有 350 条信息,大概是我醒着的时候每 3 分钟就有一条信息发出或收到。过去,当我们中的一个人在旅行或生病时,邮件数量为零。我还观察到,在我们开始打电话后的一月份,这一数字有所上升,这显然与我们更多地互相发短信的时间相吻合。一月中旬,当我回到美国,我们开始面对面交谈时,这个峰值再次下降。总的来说,图表的变化非常大,当我们处于相反的时区时,会观察到更高的计数。
Graph 1
图 2 —基于一天中时间的消息数量
下一张图显示了基于时间的平均消息交换数量。这张图没有图 1 变化大。图表上的时间是哈萨克时区(GMT+6),当时我正在为一家美国公司远程工作,我的日程安排发生了重大变化。很明显,在凌晨 3 点到 5 点和下午 3 点到 7 点之间会有一个消息高峰。此外,平均数字从来不会接近零,这意味着在这四个月中,我们没有一天不发信息。
Graph 2
图书馆上的文字
sci-kit-learn 的一个最大的优点是,该软件包使用户能够使用网格搜索策略来找到特征提取组件和分类器的良好配置。在我的例子中,我使用 scikit-learn 将我的库中的单词划分为使用阈值较高和较低的单词。它还确定了不适用于阈值、与我们的对话主题无关或没有重要意义的单词(即“真的”)。我运行了四次这个测试,每次代码都会生成一组不同的相关单词,我称之为“主题”在本文中,我选择显示第三组结果,在所有四个测试中,它的单词分组对我来说最有意义。
主题
以下十个主题由具有较高阈值的单个单词组成。我称之为“话题”的那几组单词,是在我们的对话中频繁使用的、彼此紧密相关的单词。
图 3——每日话题变化动态
此图显示了每周的邮件数量(Y 轴)、时间轴(X 轴),并按主题进行了颜色编码,每个主题都以不同的颜色显示。每个主题中的单词都在图例中明确标识。通过观察图表,人们可以看到我们的对话如何随着时间的推移在不同的高频词组之间移动,这显示了在这四个月中哪些话题与我们相关。
总结
这个简单的图表和数据分析让我对我和我朋友的信息历史有了更全面的了解,并成为我们之间有趣的讨论点。在一个充斥着小聊天框中的短信的生活中,很容易忘记所有关系的历史和发展,因为这些大量的数据隐藏在过去,并且在线性滚动界面中。通过做这个练习,我们可以带着更大的熟悉感和意识回顾我们的课文。
请随意查看我在 GitHub 库中的全部代码。
*最长——聊天——分析——这是我的第一个个人项目。我很好奇,分析了我和我朋友在…*github.com的聊天记录
协同过滤的各种实现
利用协同过滤构建推荐系统的不同方法比较
我们看到推荐系统在我们周围到处都在使用。这些系统正在个性化我们的网络体验,告诉我们买什么**(亚马逊)【网飞】****【脸书】【Spotify】等等。这些推荐系统利用我们的购物/观看/收听模式,并根据我们的行为模式预测我们未来可能喜欢的东西。推荐系统最基本的模型是协同过滤模型**,它基于这样一种假设,即人们喜欢与他们喜欢的其他事物相似的事物,以及被具有相似品味的其他人喜欢的事物。**
Figure 1: Example of collaborative filtering. Reference: here
****建立有针对性的推荐模型很容易,那么为什么不为自己的客户建立一个呢?我写这篇文章是为了让你更容易理解。本帖大部分内容灵感来源于 fast.ai 深度学习 part 1 v2 课程。
这里是笔记本的链接,它实现了下面讨论的技术。
介绍
在这篇文章中,我讨论并比较了不同的协同过滤算法来预测电影的用户评分。为了进行比较,我使用了 MovieLens 数据,它有来自 671 个独立用户对 9066 部独立电影的 100004 个评分。读者可以将这篇文章视为一站式资源,了解如何在 python 上进行协同过滤,并在自己的数据集上测试不同的技术。 (我也根据我的分析提供了我自己关于使用哪种技术的建议)。
在进一步阅读之前,我希望您对协同过滤及其在推荐系统中的应用有基本的了解。如果没有,我强烈推荐你浏览下面的博客,这些博客是 USF 大学的一个学生写的:Shikhar Gupta
职位布局
- **协同过滤技术的类型
基于记忆的
基于模型的 矩阵分解
聚类
***** 深度学习 - Python 实现
惊喜包
fast . ai 库 - 比较和结论
协同过滤技术的类型
关于协同过滤(CF)已经做了很多研究,最流行的方法是基于低维因子模型**(基于模型的矩阵分解。这些我会详细讨论)。CF 技术大致分为两种类型:**
Figure 2: Types of collaborative filtering approaches. Reference: Wikipedia
假设我们想向我们的产品用户推荐一件新商品(例如,向网飞的订户推荐一部电影,或者向亚马逊的在线买家推荐一件衣服)。为此,我们可以使用下面讨论的许多技术中的一种。
1。基于记忆的方法:
Agnes Johannsdottir 在她的博客中引用
基于记忆的协同过滤 方法可以分为两个主要部分: 用户-项目过滤和项目-项目过滤。一个 用户项目过滤 取一个特定的用户,基于评分的相似性找到与该用户相似的用户,并推荐那些相似用户喜欢的项目。相比之下, 物品-物品过滤 会取一个物品,找到喜欢过那个物品的用户,再找到那些用户或者类似用户也喜欢过的其他物品。它接受项目并输出其他项目作为推荐。
物品-物品协同过滤:“喜欢这个物品的用户也喜欢……”
用户-物品协同过滤:“和你相似的用户也喜欢……”
基于记忆的方法与基于模型的技术(等等,将在下一段讨论)*的关键区别在于,我们没有使用梯度下降(或任何其他优化算法)来学习任何参数。最近的用户或项目仅通过使用余弦相似度或皮尔逊相关系数*来计算,它们仅基于算术运算。
**编辑:如上一段所述,不使用参数化机器学习方法的技术被归类为基于记忆的技术。因此,像 KNN 这样的非参数 ML 方法也应该属于基于记忆的方法。当我最初写这篇博客的时候,我用的是基于模型的方法,这是不对的。
引用于这篇博客
一个常见的距离度量是 余弦相似度 。如果将评级矩阵中给定用户(项目)的行(列)视为一个向量,则可以从几何角度考虑该指标。对于基于用户的协同过滤,两个用户的相似性被度量为两个用户的向量 之间的角度的 余弦。对于用户 u 和 u’,余弦相似度为:
我们可以通过取来自所有其他用户(u)的电影 1 评级的加权和来预测用户 u 对电影 1 的评级,其中加权是每个用户和用户 u 之间的相似性数
我们还应该通过 u’(其他用户的)评级总数来标准化评级。
****关于基于记忆的方法的最后一句话:由于不涉及训练或优化,这是一种易于使用的方法。但是当我们有稀疏的数据时,它的性能会下降,这阻碍了这种方法对于大多数现实世界问题的可伸缩性。
如果您有兴趣尝试这种方法,下面是展示 python 一步一步实现这种方法的精彩文章的链接。
(我没有在这里讨论实现,因为我个人会使用可扩展的基于模型的方法)
****链接 1:用 Python 实现自己的推荐系统链接 2:推荐系统简介:协同过滤
2。基于模型的方法
在这种方法中,使用机器学习算法来开发 CF 模型,以预测用户对未评级项目的评级。根据我的理解,这种方法中的算法可以进一步细分为 3 个子类型。
Figure 3. Types of model based collaborative filtering approaches
编辑:组名称基于上图的“基于聚类的算法有误。它没有生成集群。我们只是在 KNN 找到 k 个最接近的训练例子。“非参数方法”是更好的术语。****
上述算法的简要说明:
- 矩阵分解(MF): 这种模型背后的思想是,用户的态度或偏好可以由少量的隐藏因素来决定。我们可以称这些因素为嵌入。****
矩阵分解可以转化为一个带有损失函数和约束的优化问题。 现在,约束是基于我们模型的属性来选择的。例如,对于非负矩阵分解,我们希望结果矩阵中有非负元素。
Figure 4. Visualization of matrix factorization
嵌入:
直观上,我们可以把嵌入理解为物品和用户的低维隐藏因素。例如,假设我们有 5 维(即上图中的 D 或 n _ factors = 5*)项目和用户的嵌入(随机选择# 5)。那么对于 user-X & movie-A,我们可以说这 5 个数字可能**代表关于电影的 5 个不同特征,比如****【I】movie-A 有多科幻【ii)电影【iii】有多新同样,用户嵌入矩阵中的 5 个数字可能表示,(I)user-X 有多喜欢科幻电影(ii)*user-X 有多喜欢最近的电影……等等。在上图中,user-X 和 movie-A 矩阵的点积数值越大,意味着 movie-A 是 user-X 的好推荐。
(我并不是说这些数字实际上代表了这样的信息。我们实际上不知道这些因素意味着什么。这只是建立一种直觉)
***在 USF 大学的另一位同学 Kerem Turgutlu 的这篇博文中,可以了解更多关于嵌入的知识。
*链接:结构化深度学习
矩阵分解可以通过各种方法完成,并且有一些研究论文。在下一节中,将介绍正交分解(SVD)或概率分解(PMF)或非负分解(NMF)的 python 实现。
- 非参数方法(KNN): 这个想法和基于记忆的推荐系统是一样的。在基于内存的算法中,我们使用用户和/或项目之间的相似性,并将它们用作权重来预测用户和项目的评分。不同之处在于,这种方法中的相似性是基于无监督学习模型计算的,而不是基于皮尔逊相关或余弦相似性。在这种方法中,我们还将相似用户的数量限制为 k ,这使得系统更具可扩展性。**
- ****神经网络/深度学习:有大量关于使用矩阵分解或相似矩阵的协同过滤的研究材料。但是缺乏在线材料来学习如何使用深度学习模型进行协同过滤。这是我在 fast.ai 深度学习 part 1 v2 中学到的东西。
下面是解释当我们使用神经网络解决这个问题时会发生什么的可视化。
Figure 5. Matrix factorization and embeddings for neural net
我们可以把这看作是矩阵分解方法的扩展。对于 SVD 或 PCA,我们将原始稀疏矩阵分解成 2 个低秩正交矩阵的乘积。对于神经网络实现,我们不需要它们是正交的,我们希望我们的模型学习嵌入矩阵本身的值。对于特定的电影-用户组合,从嵌入矩阵中查找用户潜在特征和电影潜在特征*。这些是进一步线性和非线性图层的输入值。我们可以将此输入传递给多个 relu、线性或 sigmoid 层并通过任何优化算法(Adam、SGD 等)学习相应的权重。).***
___________________________________________________________________
Python 实现
Github 回购链接: 此处
让我们看看上面讨论的算法的 python 实现。我研究了 2 个不同的 python 包,它们提供了各种算法供选择。****
(一) 惊喜套餐 :
这个软件包是专门开发来使基于协同过滤的推荐变得容易的。它有各种 CF 算法的默认实现。
第一步: 下载 MovieLens 数据并在熊猫 dfhttp://files . group lens . org/datasets/movie lens/ml-latest-small . zip中读取
第二步: 安装惊喜包通过
pip install scikit-surprise.
加载数据到*Dataset class*
Code chunk 1. Surprise dataloader
第三步: 现在在数据准备后实现任何 MF 算法都是运行 1 行代码那么简单。下面是奇异值分解(SVD)和非负矩阵分解(NMF)的代码和输出。该代码也可用于 KNN,只需更改以下代码中的
*algo = KNNBasic()*
。(请查看维基百科上SVD和NMF)**
Code chunk 2. SVD and NMF using Surprise
验证奇异值分解和 NMF 的 RMSE 分数
Figure 6. RMSE scores of SVD and NMF using Surprise
最佳 RMSE = 0.8967 (SVD),对应的均方误差为 0.804
(b) fast.ai 库 :
fast.ai 是一个庞大的 python 库,它使具有基本编码技能的人可以轻松进行机器学习和深度学习。
浅薄的学问
下面是为 CF 实现概率矩阵分解的 5 行代码。该实现利用了这样一个事实,即 2 个分解的矩阵只是嵌入矩阵,可以通过在神经网络中添加嵌入层来建模(我们可以称之为浅层学习*)。***
Code chunk 3. Collaborative filtering using fast.ai (based on concept of PMF)
培训结果:
Figure 7. Left: Training MSE, Right: Validation MSE. Rows: Epochs
从 PMF 的 fast.ai 实现获得的最佳验证 MSE 是 0.801,这接近于我们从 SVD 获得的结果。
深度学习
我们可以向我们的神经网络添加更多的线性和非线性层,使其成为深度神经网络模型。
使用 fast.ai 制作用于协同过滤的深度神经网络的步骤
第一步: 加载数据到 PyTorch 数据加载器。fast.ai 库建立在 PyTorch 之上。如果你想为特定格式的数据定制数据集类,在这里 学习 。
我用了 fast.ai 的ColumnarModelData.from_data_frame
函数加载数据集。您还可以定义自己的数据加载器函数。 X 具有关于用户 Id、电影 Id 和时间戳的数据,而 Y 仅具有关于收视率(目标变量)的数据。****
Code chunk 4. Data-loader (fast.ai function)
步骤 2: 定义自定义神经网络类(语法特定于 PyTorch,但相同的逻辑也可用于 Keras)。
*我们必须创建两个函数。init(),**该类的构造函数为和 *forward(),该函数向前传递。
Code chunk 5. Neural net on PyTorch
关于层的更多信息,这些层已经在正向通道中使用:**
dropout
该层将删除具有给定概率参数的激活。激活有 p1,p2 概率变为 0。这样做是为了减少过度拟合。embedding
该层为对应于唯一用户和唯一电影的嵌入创建查找表。该层中的值通过反向传播来更新。linear
加偏的线性矩阵乘法。relu
使用非线性图层。sigmoid
用于限制来自训练数据的预测评级 b/w 最小值和最大值。
第三步: 模型拟合和预测。
Code chunk 6. Training deep neural net (fast.ai functions)
结果:
Figure 8. Left: Training MSE, Right: Validation MSE. Rows: Epochs
最佳验证 MSE = 0.7906。这是上面讨论的所有模型中最好的。
比较和结论
下面是从 MovieLens 100k 数据的不同方法获得的 MSE 图。
Figure 9. Comparison of MSE scores using different CF methods
神经网络(DL)和奇异值分解给出了最好的结果。与其他 MF 算法不同,神经网络实现也将在不经常使用的不平衡数据上表现良好。
为你的产品/服务建立客户目标推荐系统是很有用的。最简单和研究充分的方法是协同过滤。我写这篇文章的目的是,读者可以在一个地方找到所有有用的资料,以及实现,而不是浏览技术研究论文和花费几个小时来学习协同过滤。
参考资料和其他有用资源:
- 我的 GitHub 回购链接与 python 实现
- 推荐系统
- 协同过滤使用 Fast.ai
- 惊喜:用于推荐系统的 Python scikit
- 协同过滤和嵌入—第一部分和第二部分 【https://medium.com/@shik1470/63b00b9739ce】T21
https://medium.com/@shik1470/919da17ecefb - Python 中的协同过滤和矩阵分解教程
- 研究论文 http://www . science direct . com/science/article/pii/s 1877050915007462
https://www.cs.toronto.edu/~amnih/papers/pmf.pdf