TowardsDataScience-博客中文翻译-2021-二十-
TowardsDataScience 博客中文翻译 2021(二十)
原文:TowardsDataScience Blog
协议:CC BY-NC-SA 4.0
使用变压器实现语音识别的突破
原文:https://towardsdatascience.com/breakthroughs-in-speech-recognition-achieved-with-the-use-of-transformers-6aa7c5f8cb02?source=collection_archive---------2-----------------------
思想和理论
让我们来谈谈由于变形金刚而在语音识别方面出现的关键突破!
作者图片
亲爱的读者。让我们谈论一些不能不激发你的想象力的事情——让我们谈论由于变形金刚而在语音识别方面出现的关键突破。
本文概述了在语音识别中使用基于 Transformer 的体系结构时使用的主要技巧。每一个特别激动人心的想法都用粗体突出显示。在这个过程中,将会有许多链接允许您更详细地解析所描述的技术的细节。在本文的最后,您会发现基于 Transformer 的语音识别模型的基准。
略谈语音识别
开发人员使用语音识别为各种产品创建用户体验。智能语音人工智能助手、呼叫中心代理增强和对话式语音人工智能只是最常见的几种用途。像 Gartner 这样的分析师预计,语音到文本(STT)的使用在未来十年只会增加。
语音识别(语音到文本,STT)的任务看似简单——将语音信号转换成文本数据。
解决这个问题的方法有很多,新的突破性技术也在不断涌现。迄今为止,最成功的方法可以分为混合和端到端解决方案。
在STT的混合方法中,识别系统由几个组件组成,通常是声学机器学习模型、发音 ML 模型和语言 ML 模型。单独组件的训练是独立执行的,并且为推断构建解码图,在解码图中执行对最佳转录的搜索。
端到端方法是一个系统,其所有部分一起训练。在推理中,这样的系统通常会立即返回文本。端到端方法根据学习标准和架构类型进行分类。
有趣的是,基于变压器的解决方案不仅在混合系统和端到端系统中都有应用,而且比许多其他现代解决方案都要好!
一点关于变形金刚
Transformer 架构出现在 2017 年的后续论文【1】中,解决机器翻译的问题。有很棒的论文详细解释了这种架构是如何工作的——看看这两篇( 1 )。 2 。
作者图片
后来,NLP 有了很大的发展,变压器架构得到了发展,需要解决的任务范围增加了,基于变压器的解决方案的结果越来越少。
在接管 NLP 之后,transformers 已经被引入其他机器学习领域:语音识别、语音合成和计算机视觉等等。
现在让我们进入正题。
语音转换器
语音识别中第一次提到变压器可以追溯到 2018 年,当时一群中国科学家发表了一篇研究论文【2】。
作者图片
架构的变化很小——卷积神经网络(CNN)层是在将特征提交给转换器的输入之前添加的。这使得减少输入和输出序列的尺寸差异成为可能(因为音频中的帧数明显高于文本中的标记数),这对训练有有益的影响。
尽管结果并不令人眼花缭乱,但这项工作证实了变形金刚确实可以成功地用于语音识别!
首次改进
2019 年,语音转换器在不同方向有几项关键改进:
- 这篇论文的作者提出了一种将 CTC 损耗集成到语音转换器中的方法。CTC 丢失已经在语音识别中使用了很长时间,并且具有几个优点。
首先,由于允许使用空白字符进行对齐,它允许我们考虑特定音频帧与特定转录字符的对应关系。
其次,这是 Speech-Transformer 的第二个改进,它简化了将语言模型整合到学习过程中的过程。
- 拒绝正弦位置编码(PE) 。与长序列相关的问题在语音识别中更为严重。拒绝以不同的方式发生——在一些论文中,从绝对位置编码过渡到相对 PE(如在论文 [4】之后的中所见),在其他论文中——通过用池层替换 PE(如在论文 [5】之后的中所见),在第三篇论文中——用可训练卷积层替换位置编码(如在论文 [6]之后的中所见)。后来的工作证实了其他技术对抗 sidusion PE 的优越性。
- 变压器首次适应流识别。这两篇论文的作者[ 5 ]和[ 7 ]分两个阶段完成了这项工作——首先,他们调整了编码器,使其能够以块为单位接收输入信息并保留全局上下文,然后使用单调分块注意力 (MoChA)技术进行在线解码。
- 仅使用变压器的编码器模块。对于某些系统(例如,混合方法或基于传感器的解决方案),要求我们的声学模型完全像编码器一样工作。这项技术使得在混合系统【8】和传感器识别系统【9】中使用变压器成为可能。
在 2019 年 10 月,在一篇研究论文(【10】)中,对基于 ESPNet 框架的变压器与其他方法进行了广泛的比较,这证实了基于变压器的模型的识别质量。在 15 项任务中的 13 项中,基于 transformer 的体系结构比循环系统要好。
使用变形金刚的混合语音识别
在 2019 年末-2020 年初,变形金刚在混合语音识别方面取得了 SOTA 成果(如[ 8 ]所示)。
如前所述,混合方法的一个组成部分是声学模型,它现在使用神经网络。本文中的声学模型由几层变换器编码器组成。一个这样的层的示意图如图 3 所示。
作者图片
在这项工作中最有趣的事情,我想强调的是,作者再次证明了可训练 卷积(即,类 VGG)嵌入相比正弦 PE 的优势。他们还使用迭代损失来提高训练深度变形金刚时的收敛性。深度变形金刚这个话题还会进一步讨论。
变压器传感器
更准确地说,两款 Transformer Transducer——一款来自脸书【9】,一款来自谷歌【11】出现在 2019 年底和 2020 年上半年。形式上,在脸书的工作中,它被称为变压器-传感器(由连字符分隔)。但是这两项工作的本质是相同的— 将变压器集成到 RNN 传感器架构中。
作者图片
集成并不针对整个变压器,而仅针对编码器,作为 RNN-T 框架中的音频编码器。在这篇论文【11】中,预测器网络也是基于变压器的,但是层数更少——在推理过程中经常需要调用该组件,不需要更复杂的架构。
与 CTC 损失不同,RNN-T 损失允许您不仅考虑基于输入序列的概率,还考虑基于预测标签的概率。此外,transformer 传感器架构的一个优点是,这种方法更容易适应流识别,因为只使用了 Transformer 的编码器部分。
2020 年夏天,另一篇论文【12】发表,命名为 conv-变压器换能器,其中音频编码器由三个块组成,每个块包含卷积层,然后是变压器层。今年秋天,在[ 13 ](这是[ 11 ]的延续)中,作者提出了可变上下文层技术,该技术允许训练一个能够使用未来上下文的可变大小的模型,在推理阶段提供折衷的延迟/质量。
本地&全球背景
基于变压器的架构的优势之一是其高效率,同时考虑到了全球背景。在音频信号中,本地连接比全球连接起着更大的作用。2020 年夏天,发表了几部作品,引起人们对这些方面的关注,并再次将基于变压器的模型引入差距:
- [ 14 的作者提出通过在多头注意力(MHA)模块后添加卷积模块来改变变压器模块的架构。卷积更擅长考虑局部信息,而变压器模型擅长提取全局信息。作者将最终模型命名为 Conformer 。同样,受马卡龙网的启发,作者使用了半步前馈网络**。**
- 论文 15 介绍了弱注意抑制技术;建议使用稀疏注意力,动态地将小于某个阈值的权重置零,以便我们使模型在整个上下文中分散较少的注意力,并且更多地关注有意义的帧。
可流式传输的变形金刚
如上所述,换能器方法允许系统用于流式语音识别,即,当音频实时进入系统时,处理立即发生,并且系统一准备好就返回响应。流识别是语音对话人工智能任务的先决条件。
然而,对于要进行流式传输的系统,transformer 模型本身必须能够顺序处理音频。在最初的转换器中,注意力机制查看整个输入序列。
语音识别中有以下流数据处理技术,用于基于转换器的解决方案:
- 有时间限制的自我关注被使用,例如在下面的论文【11】。每个变压器层都有一个有限的前瞻性上下文。这种方法的缺点是,随着层数量的增加,随着展望未来的一般环境的增加,延迟也会增加。
- 分块处理 —思路见 5 、 16 、 17 。想法是将片段/块/组块作为输入提供给转换器。这种方法的缺点是上下文仅限于片段。为了不丢失全局上下文,可以将其作为单独嵌入进行传输,如[ 5 ]所示,或者使用具有循环连接的架构,其中来自先前片段的嵌入被传输到当前片段,如[ 16 ]所示,或者使用来自存储在存储体中的所有先前处理的片段的信息。这种方法被称为增强记忆,在 17 中提出。
电磁变压器
在接下来的研究论文【18】中,提出了一种适用于流识别的模型,包括混合设置和传感器系统。
Emformer 继续发展[ 17 ]中的观点。像它的前身一样,Emformer 使用增强内存。执行计算优化、计算缓存,不从当前层使用内存库,而是从先前的转换器层使用,并且添加了 GPU 并行化。
因此,有可能实现系统训练的显著加速和推理时间的减少。此外,由于更少的无用计算,该模型收敛得更好。
无监督语音表示学习
变形金刚成功应用的另一个领域是基于未标记数据构建高级音频表示,在此基础上,即使简单的模型也会产生良好的结果。
在这里我要特别说明一批作品——mock injay【19】Speech-XLNet【20】Audio ALBERT【21】TERA【22】wav2 vec 2.0【23】。
构建这种视图的一个想法是破坏频谱图(通过沿时间轴屏蔽它,如在 Mockingjay 和 Audio ALBERT 中,或者沿时间轴和频率轴屏蔽它,如在 TERA 中,或者打乱一些帧,如在 Speech-XLNet 中),并训练模型来恢复它。那么这种模型的潜在表示可以被用作高级表示。这里的转换器充当一个模型,或者更确切地说,它的编码器加上之前和之后的附加模块。
作者图片
生成的视图可用于下游任务。此外,模型的权重可以被冻结或留给下游任务进行微调。
另一个想法是在 wav2vec 2.0 中实现的。是VQ-wav2 vec【24】的延续。
首先,使用卷积神经网络层从音频信号构建潜在表示。潜在表示被馈送到变换器的输入,并且也用于构造离散表示。变压器入口处的一些帧被屏蔽。transformer 模型被训练成通过对比损失来预测类似离散的授权。与 vq-wav2vec 不同,离散和潜在表征的学习现在一起发生(端到端)。
作者图片
在[ 25 ]中,作者将 wav2vec 预训练的思想与 Conformer 架构结合使用。作者使用 LibriLight 数据进行预训练,并在撰写本文时获得了 LibriSpeech 语料库上的 SOTA。
大规模设置
大多数科学出版物都考虑在小型的大约 1000 小时的案例上训练的模型的结果,例如 LibriSpeech。
然而,像[ 26 ]和[ 27 ]这样的研究表明,基于变压器的模型即使在大量数据上也显示出优势。
结论
本文研究了在语音识别中使用基于转换器的模型时遇到的技术。
当然,这里并没有体现语音识别领域所有与变形金刚相关的论文(STT 与变形金刚相关的作品数量呈指数级增长!),但我努力为你收集了最有趣的想法。
最后—基于 LibriSpeech 变压器的模型案例的 WER 图:
作者图片
作者图片
参考文献
- A.瓦斯瓦尼等人,2017,“注意力是你所需要的一切”,https://arxiv.org/abs/1706.03762
- 长度董等,2018“语音转换器:无递归序列到序列的语音识别模型”,,
- 南 Karita 等人,2019,“利用连接主义时间分类和语言模型集成改进基于 Transformer 的端到端语音识别”,https://pdfs . semantic scholar . org/FFE 1/416 BCF de 82 f 567 DD 280975 bebccfeb 4892298 . pdf
- 页(page 的缩写)周看了看周虎。,2019,“利用并行调度采样和相对位置嵌入提高语音识别的变换器泛化能力”,https://arxiv.org/abs/1911.00203
- E.Tsunoo 等人,2019,“带上下文块处理的变压器 ASR”,https://arxiv.org/abs/1910.07204
- A.Mohamed 等人,2019,“用于自动语音识别的卷积上下文的变压器”,https://arxiv.org/abs/1904.11660
- E.Tsunoo 等,2019,“走向在线端到端的变压器自动语音识别”,https://arxiv.org/abs/1910.11871
- Y.王等,2019,“基于变换器的混合语音识别声学建模”,
- C.叶等,2019,“变压器-换能器:带自我注意的端到端语音识别”,https://arxiv.org/abs/1910.12977
- 南 Karita 等人,2019,“Transformer vs RNN 在语音应用中的对比研究”,【https://arxiv.org/abs/1909.06317
- 张等,2020,“变压器换能器:一种具有变压器编码器和 T 损失的流式语音识别模型”,【https://arxiv.org/abs/2002.02562】
- W.黄等,2020,《变压器换能器:低延迟、低帧率、可流式传输的端到端语音识别》,、
- A.Tripathi 等人,2020,“Transformer Transducer:一种统一流式和非流式语音识别的模型”,https://arxiv.org/abs/2010.03192
- A.Gulati 等人,2020,“Conformer:用于语音识别的卷积增强变换器”,https://arxiv.org/abs/2005.08100
- Y.史等,2020,“基于变压器的弱注意抑制语音识别”,
- Z.田等,2020,“用于端到端语音识别的同步变压器”,,
- C.吴等,2020,“基于流式传输器的具有增强记忆的自注意声学模型”,,
- Y.史等,2020,“Emformer:基于高效记忆变换器的低延迟流式语音识别声学模型”,
- A.T.Liu 等人,2019,“Mockingjay:深度双向变换编码器的无监督语音表示学习”,https://arxiv.org/abs/1910.12638
- X.宋等,2020,“Speech-XLNet:自注意网络的无监督声学模型预训练”,
- 页(page 的缩写)迟等,2020,“音频阿尔伯特:一个用于音频表征的自我监督学习的 Lite BERT”,,
- A.T.Liu 等,2020,《:语音的变换编码器表示的自监督学习》,【https://arxiv.org/abs/2007.06028】
- A.巴耶夫斯基等人,2020,“wav2vec 2.0:语音表征的自我监督学习框架”,【https://arxiv.org/abs/2006.11477】T4
- A.巴耶夫斯基等人,2020“VQ-wav2 vec:离散语音表示的自我监督学习”,https://arxiv.org/abs/1910.05453
- Y.张等,2020,“拓展半监督学习在自动语音识别中的应用”,
- 长度陆等,2020,“面向大规模语音识别的变形金刚探索”,
- Y.王等,2020,“变压器在行动:基于变压器的声学模型在大规模语音识别应用中的比较研究”,
浓缩咖啡的冲泡比
原文:https://towardsdatascience.com/brew-ratio-for-espresso-174441e1315b?source=collection_archive---------20-----------------------
咖啡数据科学
探索投入产出比
浓咖啡的酿造比例有很大的变化范围,在味道的口感和拍摄的强度上有巨大的图像。许多人坚持 2:1(输出对输入)拍摄,最近,3:1 甚至 5:1 比例的长时间慢速拍摄的想法已经普及。我个人比较喜欢 1:1 到 1.4 之间的拍摄比例。
所有图片由作者提供
对于这个简短的测试,我想展示拍摄比例的差异,并讨论对口味的影响。我认为这个变量比其他浓缩咖啡变量更个人化,因为它对口感有影响。我会具体看比率 1.5,1.3,1.1。
鸣谢:很多人将 brew 比率写成输入输出,但我更喜欢另一种方式,因为我更喜欢在比率冒号的左边写一个较大的比率数字。
照片中的镜头
为了拍摄这些照片,我使用了韩国研磨机、Kim Express 机器、VST 篮子、Pyxis 秤和自制分配器。每一次注射都是间断的,预注射时间比正常时间长(至少 30 秒),我在注射过程中使用了压力脉冲。三个镜头只是冲泡比例不同。
我考虑制作一份意大利香肠,这样我就可以品尝到完全相同的味道,但与使用三份独立的、每份之间间隔很长时间的香肠相比,它对最初的味道、口感和回味有很大的影响,可能会被混淆。在这方面,我没有吃任何东西或喝任何东西之前,这些镜头,他们都被拉了几个小时。
在拍摄过程中的几个不同时间,每列都是不同的酿造比:
1.5 : 1 …………… 1.3 : 1 ……………… 1.1 : 1
所有三个镜头有相似的提取,这是一个很好的健全检查。他们在同一时间间隔看起来也很相似。
绩效指标
我使用两个指标来评估技术之间的差异:最终得分和咖啡萃取。
最终得分 是记分卡 7 个指标(尖锐、浓郁、糖浆、甜味、酸味、苦味和回味)的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难确定。
用折射仪测量总溶解固体量(TDS),这个数字结合咖啡的输出重量和输入重量用于确定提取到杯中的咖啡的百分比,称为提取率(EY)** 。**
表演
短距离射击味道更好。这对我来说并不奇怪,因为在 1:1 的拍摄之后,已经没有什么可提取的了。随着 TDS 的增加,口感真的改善了。太短的镜头可能会变得太酸,但我没有发现这个问题,特别是这个烤。
****
镜头比率
对于 1.5:1 的注射,预输注时间要长几秒钟,但总的来说,时间非常相似。
TCF 是时候盖上过滤器了
有时候我们被某个参数束缚住了,以至于很难去实验。测试比例的最佳方法是制作一份意大利香肠(使用多个杯子),这样你就可以品尝提取物的不同部分,并将它们混合在一起。
我的目的不是告诉每个人拉一个特定的投篮比例(在这种情况下,一个较低的投篮比例),而是,我的目的是鼓励实验。
如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以关注我中和订阅。
我的进一步阅读:
浓缩咖啡系列文章
工作和学校故事集
个人故事和关注点
乐高故事启动页面
摄影飞溅页
使用图像处理测量咖啡研磨颗粒分布
改善浓缩咖啡
断奏生活方式概述
测量咖啡研磨分布
咖啡萃取
咖啡烘焙
咖啡豆
浓缩咖啡用纸质过滤器
浓缩咖啡篮及相关主题
意式咖啡观点
透明 Portafilter 实验
杠杆机维修
咖啡评论和想法
咖啡实验
布里奇顿:网飞最热门的电视连续剧分析
原文:https://towardsdatascience.com/bridgerton-an-analysis-of-netflixs-most-streamed-tv-series-c4c9e2926397?source=collection_archive---------14-----------------------
使用 Python 和 Tableau 中的 NLP 技术对 Bridgerton 电视连续剧上的 300,000 多条推文进行分析
在 Unsplash 上由 Thibault Penin 拍摄的照片
《布里奇顿》系列电视剧在圣诞节上映后,占据了全球大多数电视频道。几乎所有的电影爱好者都在谈论这件事,因为炒作,我被*【胁迫】在 网飞 看了这部连续剧。最近, CNN 报道称,《布里奇顿》是“ 有史以来最大的网飞剧集” ,因为它已经在超过 8200 万个家庭中播放。然而,最吸引我注意的是推特上的官方标签,这帮助为这部剧制造了更多的轰动。正如你在下图中看到的,它们都有一个特殊的标志。如果你问我,我会说这是伟大的营销策略!*
推特上布里奇顿官方标签的截图(图片由杰西卡·乌戈格伦提供)
基础
为了这个项目,我决定在我上一个情感分析项目的基础上,根据 Twitter 用户对电视连续剧《布里吉顿》的评论做一个评论。用于该项目的推文创建于 2020 年 12 月 27 日至 2021 年 1 月 28 日。除了,分析只涵盖了用 英文 写的推文。我可以肯定地说,如果你在那段时间里在你的推文中使用了任何 布里奇顿 标签或者提到了“ 【布里奇顿】 ”,那么你的推文就是这个分析的一部分。
以下是我想了解的关于这部电视剧的一些事情:
- 最受欢迎的布里奇顿标签
- 最受关注的人物布里顿
- 普通观众对布里奇顿的看法
- 关于布里奇顿的推特常用词
- 哪个国家关于布里奇顿的推特最多
我还在组合中加入了一个 Tableau 仪表板,让您可以按国家、日期和时间来浏览我的分析结果。
项目策略
项目步骤如下所示。在我上一个项目中详细讨论了一些关键概念。因此,在本文中,我将展示一些简短的 Python 脚本,用于实现我的分析的一些结果。
布里奇顿电视剧分析项目流程图(图片由杰西卡·乌戈格伦使用 Canva 开发)
使用的 Python 库包括 Pandas(用于数据清理/操纵)、Tweepy(用于推文挖掘)、NLTK(用于文本分析的自然语言工具包)、TextBlob(用于情感分析)、Matplotlib & WordCloud(用于数据探索)、Emot(用于表情符号识别)、Plotly(用于数据可视化)等内置库,如我的 Jupyter 笔记本所示。
推特挖掘
有一个月,我使用他们的 API 和 Python 库, Tweepy 从 Twitter 上搜集了一些推文。要使用 Twitter 的 API,你只需要在创建 Twitter 开发者账户后获得一些证书。你也可以查看我上一篇文章中关于如何使用 Twitter 的 API 的简要说明。对于搜索查询,我使用了单词“Bridgerton”和所有官方的 Bridgerton 标签。我甚至添加了错误的拼写,例如,为拼错电影名称的用户添加了“Brigerton”。请参见下面的代码片段。
用于 Bridgerton Tweet 挖掘的 Python 脚本(代码由 Jessica Uwoghiren 编写)
数据清理和处理
我一直说,一个数据科学或分析项目,大约 80%都是围绕这一步展开的。想象一下处理 300,000 多行数据,您不可能检查每一行的正确性或完整性。在任何数据项目中,缺失值总是一个大问题。在这个例子中,Location 列有许多缺失值,因为只有少数 Twitter 用户在他们的简历中有正确的位置。我还需要确保没有使用“Tweet ID”的重复 Tweet,这是我的数据集的主键。请参见下面的熊猫数据框。
显示推特数据集的熊猫数据框(截图来自 Jupyter 笔记本作者杰西卡·乌戈格伦
使用正则表达式从推文中提取标签和角色名
我非常喜欢分析的这一部分。我想看看哪个官方的 推特“布里吉顿”标签 和 角色名字 最受欢迎。我必须找到一种方法,从每条推文中提取这些信息,并将它们返回到我的数据框中的新列。我是怎么做到的?答案是正则表达式。REGEX 代表“正则表达式”,它用于指定想要匹配的字符串模式。它在这里证明是有效的。对于角色的名字,我使用了 REGEX 来纠正名字拼写错误的地方,如下面的代码片段所示。
Python 脚本从 Bridgerton Tweets 中提取标签和角色名(代码由 Jessica Uwoghiren 编写)
查看我的 Jupyter 笔记本这里看最后的数据框。基于上面的分析,最受欢迎的标签如下所示。
布里奇顿推特标签的频率。(图片由 Steve Uwoghiren 使用 Adobe Photoshop 开发)
布里奇顿推文中的词频
对于这部分分析,我使用了 WordCloud 库,根据推文中使用的单词频率生成单词云图像。使用 Matplotlib 库中的 Pyplot 模块显示下图。单词云以更大的文本尺寸显示具有更高频率的单词*。*
关于 Bridgerton 电视剧的推文中最常用的词(图片由 Jessica Uwoghiren 使用 WordCloud 和 Python 的 Matplotlib 库生成)
位置地理编码
为了确定哪个国家在推特上发布的关于布里吉顿电视剧的信息最多,我使用了位置地理编码,这是一种返回给定城市、地点、州或国家的精确坐标的奇特方式。我这样做是因为大多数 Twitter 用户只在他们的简历中使用他们的“州”或“城市”,而我需要检索他们的国家名称。像我的上一个项目一样,我使用了开发者的 API 来返回每个 tweet 位置的 国家代码和国家名称 。
情感分析
最后,我想看看对 Bridgerton 系列的整体看法。为了实现这一点,我使用了一种被称为自然语言处理(NLP)的机器学习技术。另一种说法是处理人类文本或单词。NLP 有几个方面,这里最重要的是“情感分析”。一个简单的例子,请查看我上一篇关于这个主题的文章。
对于这个分析,我使用了 TextBlob 中的情感分析器模块。Python 上的库。该算法通过给每个句子一个极性分数来分析句子的情感。基于极性得分,人们可以定义推文的情感类别。对于这个项目,我将一条负面推文定义为极性得分为 < 0,而 ≥ 0 为正面。情感类别的分布如下所示。您可以在 Tableau dashboard 这里 探索按国家划分的情绪类别分布。
根据 2020 年 12 月 27 日至 2021 年 1 月 27 日的推文(由 Jessica Uwoghiren 使用 Python 的 Plotly 库生成的情节),观众对布里吉顿电视剧的总体看法
交互式 Tableau 仪表板
为了帮助读者更深入地探索我的分析,我利用 Tableau 创建了一个用户友好的交互式仪表板。这允许你通过国家、推文创建日期、时间等等来探索结果。请注意,虽然可以在任何设备上查看仪表板,但最好使用平板电脑或计算机查看。
布里奇顿推特分析仪表板剪辑(仪表板由杰西卡·乌戈格伦使用画面创建)
最终想法
感谢您花时间阅读这篇文章。你可以去我的个人资料浏览更多文章。一如既往,我喜欢分享我的见解。以下是一些例子:
- 布里奇顿的营销策略: 这个特殊的布里奇顿标签引起了超越网飞订户的轰动。这让人们在推特上谈论这部电视剧。
- 假日季: 根据cnn.com的报道,这部电影在圣诞节期间上映也帮助提升了这部电视剧的收视率,在上映的第一个月就有超过 8200 万家庭观看了这部电视剧
- 发微博最多的国家: 与尼日利亚和印度等其他国家相比,美国、英国和加拿大的推特用户发了更多关于这部电视剧的微博。我想到了几个原因,如互联网普及率较低,网飞用户较少等。
- 推出电影或产品?你可能要考虑研究一下布里奇顿的推特策略。吸引你的观众,让人们为你销售你的产品!
评论
文章中使用的所有参考文献都有超链接。关于在 Jupyter Notebook、GitHub、Tableau Dashboard 和我的社交媒体页面上编写的完整 Python 代码,请使用以下链接:
- Tableau 仪表盘
- Jupyter 笔记本
- GitHub 资源库
- 个人网站
- 领英
- 推特
- 数据技术空间社区
弥合人工智能的概念验证与生产差距
原文:https://towardsdatascience.com/bridging-ais-proof-of-concept-to-production-gap-insights-from-andrew-ng-f2ac119ee737?source=collection_archive---------16-----------------------
关于在现实世界中部署机器学习项目的挑战和解决方案的三个关键要点(来自吴恩达)
亚历克斯·拉德里奇在 Unsplash 上的照片
我们经常听说人工智能( AI )和机器学习( ML )领域令人兴奋的突破和新的最先进的研究。
尽管有这些进步,残酷的现实是这些概念验证(PoC)项目中的大多数没有部署在现实世界中。为什么会这样?
这个问题被称为 PoC 到生产的差距,ML 项目在走向实际部署的过程中遇到了重大的瓶颈和挑战。
在这篇文章中,我们发现了吴恩达分享的三个关键经验教训,关于团队如何弥合这一差距以从 ML 项目中交付更大的实际价值。
关于演讲者
吴恩达|图片来自维基共享资源
Andrew NG是 deeplearning.ai 的创始人,Coursera 的联合创始人。
他目前是斯坦福大学的兼职教授。他是百度公司的首席科学家和谷歌大脑项目的创始人。
目前也是 Landing AI 的创始人兼 CEO。
(1)小数据问题
行业中对 ML 应用的讨论主要集中在消费互联网用例上,如社交媒体(如脸书)、娱乐(如 YouTube)和电子商务(如亚马逊)。
这种现象并不奇怪,因为这些公司可以从数百万用户那里获得大量数据。
然而,在消费互联网之外,还有许多其他应用和行业只能访问小数据**。**
这种小数据在人工智能项目的部署中是一个巨大的挑战,因为数据分布不均匀的问题被大大放大了。虽然我们可以构建平均精度良好的 ML 模型,但这些模型在数据中较少出现的罕见事件上可能仍然表现不佳。
一个例子是胸部 X 射线诊断 ML 算法的开发,该算法对积液等常见疾病的预测很好,但对疝气等罕见疾病的预测很差。
虽然整体模型可能具有出色的性能指标,但部署一个遗漏明显疝病例的系统在医学上是不可接受的。
幸运的是,在研究更好的算法来处理小数据方面取得了进展。以下是一些例子:
- 合成数据生成(如 GANs)
- 一次性/一次性学习(如 GPT-3)
- 自我监督学习
- 迁移学习
- 异常检测
国立癌症研究所在 Unsplash 上拍摄的照片
即使您只有少量数据,在企业中开发 ML 解决方案之前等待更多数据(例如,首先构建新的 it 基础设施)几乎总是一个糟糕的想法。
更谨慎的做法是,从您拥有的任何数据开始,然后反向工作以确定您需要收集哪些额外的数据。只有从一个系统开始,您才能进一步了解如何构建或增强 It 基础架构。
(2)通用性和稳健性
事实证明,许多在已发表的论文中运行良好的模型在生产环境中往往不起作用**。**
这个问题源自于构建不良的概括和不健壮的模型,它被证明是部署 ML 概念证明的又一个挑战。
回到早期的 X 射线诊断的例子,一个团队可以基于从现代机器获得的高质量 X 射线图像构建一个高性能算法,这些现代机器由像斯坦福医院这样的知名机构的训练有素的技术人员操作。
如果我们要在一家更老的医院运行这种模型,那里的 x 光机更老,技术人员训练更差,成像协议也不同,我们预计模型的性能会降低**。**
这种表现与人类放射科医师形成对比,后者可能在两家医院中对扫描进行类似的良好诊断。
这一挑战适用于所有行业,不仅仅是医疗保健行业。它突出了深入理解训练数据分布和具有领域知识以了解数据和过程的细微差别的重要性。
鉴于这一挑战没有明确的解决方案,研究人员和工程师必须共同努力开发系统化的工具和流程以确保算法可推广到用于训练以外的数据。
在 Unsplash 上拍摄的 ThisisEngineering RAEng
(3)变革管理
许多团队没有意识到人工智能解决方案会扰乱许多利益相关者的工作。如果没有正确的认同和接受,企业用户将会犹豫是否使用你辛辛苦苦构建的 ML 模型。
下图说明了在管理技术带来的变化时的五个关键考虑因素**:**
变更管理的注意事项|作者图片
在提供保证和解释模型的预测方面,团队可以利用可解释的人工智能的工具(特定于每个利益相关者的需求),以及第三方审计服务来审查 ML 系统的代码和设置。
一旦利益相关者理解了最大似然算法是如何得到他们的预测的,并且确信这是公平合理的,那么模型就更有可能被部署和使用。
当然,ML 解决方案本身是完全无用的。任何项目的第一步(可能也是最重要的一步)是范围界定,技术和业务团队一起在“人工智能能做什么”和“什么对业务有价值”的交叉点上确定用例。
结论
据麦肯锡称,到 2030 年,人工智能可以为世界经济带来 13 万亿美元的增长。更重要的是,这种价值大部分存在于消费互联网行业之外的行业,这证明了还有大量未开发的价值。
为了在所有行业实现人工智能的全部潜力,有必要将人工智能转变为一个系统工程学科,在这里项目被有效地部署以交付重要的价值。
请随意查看下面的完整研讨会:
在你走之前
欢迎您加入我的数据科学学习之旅!关注我的媒体页面和 GitHub 以了解更多精彩的数据科学内容。同时,享受将您的项目投入实际部署的乐趣!
** **
弥合人工智能和软件工程之间的鸿沟
原文:https://towardsdatascience.com/bridging-the-gap-between-ai-and-software-engineering-386395e7ff1f?source=collection_archive---------24-----------------------
如何在您的数据科学家和软件工程师之间创造协同效应
AI @ DayTwo 旨在改善我们业务的各个方面。从血糖反应水平预测到个性化算法和微生物组分析,我们的人工智能应用涵盖许多领域和方面。为了最大化我们研究的影响,我们不会将研究集中在一个方向。相反,我们有大量的研究渠道,有多个人工智能问题,我们希望与业务团队、工程团队和公司外部的其他研究小组合作解决。这允许数据科学家和每个领域的业务或工程团队之间的紧密合作。此外,对于我们进行的任何研究,我们都会召集一个学习论坛,提供一个分享知识的地方,并提出我们在路上可能遇到的障碍。这些论坛也有助于确定和激励未来的研究方向。
作者图片
在实践中,大规模应用机器学习需要大量的基础设施和系统工程投资。今天,我们的主要挑战之一是缩小开发和培训 ML 模型的数据科学家与负责将这些模型引入我们的生产系统并使其可用的 ML 软件工程师之间的差距。我们一直在寻找新的方法来创建数据科学家和软件工程师之间的共享语言,并共同将我们的人工智能解决方案扩展到我们的主要产品中。
人工智能解决方案
在第二天,一旦一个主题已经被充分研究和建模,我们的数据科学团队就继续进入机器学习模型本身需要集成到我们的生产流程中的阶段。拥有一个机器学习模型或算法,可以解决我们的一个问题,这听起来很令人兴奋,并让我们对我们所取得的成就感到满意,毕竟,获得高准确率是每个数据科学家的梦想。但严峻的事实是,要将该解决方案部署到生产环境中,我们仍有许多工作要做,这些工作如果做得不恰当,可能会危及整个目标。此外,通常,这种工作需要数据科学团队中没有的知识,并且还必须有具有更广泛的系统工程概述能力的人参与。这就是为什么这两个团队之间的顺利合作如此重要,这甚至导致了新的行业职位名称命名为 ML 软件工程师。
照片由莱昂在 Unsplash 上拍摄
第二天的路
在第二天,我们非常依赖 AWS 服务,我们利用它们来满足我们的特定需求,我们从不害怕尝试新的服务,尤其是当它有可能对我们有用的时候。此外,我们还与 AWS 解决方案架构师密切合作,因为我们知道他们对自己的服务能力有着更深入的了解,当需要就某个解决方案集思广益时,他们是我们的咨询对象。
为了支持数据科学家和 ML 工程师之间顺畅、快速的协作,我们确保所有团队都熟悉相关的 AWS 服务,并能够编写适当的代码。例如,我们的一个推荐引擎涉及在用户流的某个点上对多个分类模型进行推理。为了支持这一点,我们使用 SageMaker MMS 端点基础设施,并确保我们将工作分开,以便我们的数据科学家在推理 docker 容器模块中编写代码,该模块调用实际的机器学习模型,而 ML 软件工程师编写端点包装器并将其集成到产品流中。此外,由于我们在多个开发环境中工作,我们开发了从代码无缝部署服务的能力,没有任何瓶颈,因此,我们确保所有团队成员都具备这方面的知识(使用 AWS CDK)。
在某些情况下,需要更复杂的算法(不仅仅是触发某种模型的推断)。在这些情况下,需要将额外的算法编程到流程中,我们要么由数据科学家将其编码到推理 docker 容器中,要么由 ML 软件工程师直接编码到产品流程代码中。在这种情况下,每种情况都要分别审查和决定。
作者图片
投资于教授我们的数据科学家技术,如 *Docker、Jenkins、REST APIs、Git、VS-Code remote work、CDK、Setuptools、Bash、*等,让他们能够自我驱动和独立,并推动他们成为全栈数据科学家。同样,向我们的软件工程师教授机器学习的基础知识,并让他们接触算法和人工智能管道,从长远来看,当团队之间真正的协作和协同作用出现时,会有回报。
收场白
将人工智能解决方案集成到产品中可能具有挑战性并且非常耗时。人们可能会认为大部分工作是在训练 ML 模型,而现实表明在软件工程方面也需要大量的时间。可能有助于缩小这些差距的主要要点是 (1) 确保您的数据科学和工程团队相互沟通。 (2) 确保你的数据科学团队会说软件工程的语言(反之亦然)——投资将你的一些软件工程师变成 ML SE,将你的一些数据科学家变成全栈数据科学家。 (3) 在你的产品中集成一个新的 AI 解决方案时,不要低估工程工作。 (4) 在团队之间的协作中投入资源,并经常回顾以供下次改进。
如果你想了解更多关于我们正在开发的最新最棒的产品,请随时联系我。
亚龙
带回亲自参加的数据科学训练营
原文:https://towardsdatascience.com/bring-back-the-in-person-data-science-bootcamp-67cc9dbb6675?source=collection_archive---------22-----------------------
照片由 CX 洞察在 Unsplash 上拍摄
意见
这太有趣了
现在我们终于可以在疫情隧道的另一边看到光明,我对 METIS 和镀锌有一个请求。
请带回来亲自参加数据科学训练营。
我知道去偏远地区是你去年唯一的选择。但当你们都永远远离我时,我感到震惊和难过。
我是梅蒂斯大学的毕业生——我喜欢这种经历。我的一些最好的朋友是我的训练营同学,我从这次经历中获益良多。我会去一个完全偏远的训练营吗?没门,我不会为日复一日的缩放课程付 17000 美元。
我肯定不止我一个人有变焦疲劳。经过一年多的 Zoom 会议和 Zoom pair 编码,上周我第一次在办公室见到了我的团队。太棒了!我们有一个正常的会议,我们用白板,我们在外面吃午餐。如果我想问问题,我就转身问。面对面的感觉总是比变焦好,但经过 15 个月的强制变焦,面对面的感觉甚至比正常情况下更好。
训练营
全日制训练营是一大进步。你需要辞掉工作,拿出一大笔钱,至少花几个月时间在训练营结束后找工作,因为很多雇主会对你的训练营教育持怀疑态度。最重要的是,数据科学家的供需状况不像几年前那么好了——通常,当一个工作很热门(且薪酬很高)时,供应(数据科学家)的增长速度比需求快得多。
这是一个很大的风险,但对许多人来说,这也是转向数据职业的唯一途径(离开工作岗位两年去获得硕士学位实在是太长了)。训练营有责任让他们的学生全力以赴,提供尽可能多的价值。其中一部分就是给他们一个空间,让他们可以一起学习,一起编程,一起玩耍,一起交流。
我从训练营经历中得到的最大收获是我的同伴。它们让学习变得更有趣,让我的项目更有趣,让找工作的压力更小,并成为我的社交网络和职业网络的一部分。你可以试着让它超过 Zoom,但你就是无法复制社交体验。在我看来,一场酣畅淋漓的乒乓球赛胜过我们之间的十几场比赛,而且这还远远不够。
所以梅蒂斯、激励和其他训练营,不要把疫情作为增加利润的借口。你的学生对你做出了很大的承诺,所以你应该尽你所能给他们最好的体验。
通过找到“几个重要原因”,将可解释的人工智能带到下一个层次
原文:https://towardsdatascience.com/bring-explainable-ai-to-the-next-level-by-finding-the-few-vital-causes-4838d46857de?source=collection_archive---------24-----------------------
一个有效的可解释人工智能应该旨在发现“重要的少数”原因,而不是“琐碎的许多”事件。下面是如何用 Python 实现的。
[作者图]
可解释 AI (缩写为 XAI )是解释机器学习模型所做选择的能力。在现实世界中,XAI 通常是机器学习应用程序成功的关键。
例如,以预测客户流失这样的经典任务为例。当然,模型精度是根本。但是,一旦你知道哪些客户更有可能离开公司,关键问题是:“我们如何让他们改变主意”?为了帮助回答这个问题,我们需要知道为什么模型认为他们有风险。换句话说,我们需要确定客户流失的原因(老实说,我认为“症状”这个词比“原因”更合适,但在这里我会互换使用它们)。
最重要的概念是任何个体(或一群个体)都有自己的原因。这些原因可能(经常)不同于其他人的。在这篇文章中——给定一个机器学习模型——我们将看到如何为每个个体(或群体)找到(并可视化)最重要的原因。正如约瑟夫·巨然所说,我们将关注“至关重要的少数”而不是“微不足道的许多”症状。
虽然这篇文章是基于一个特定的用例(客户流失),但下面的内容可以应用于任何机器学习任务。所有的分析都将基于 Kaggle 上的 Orange Telecom 数据集。你可以在 Github 中找到包含所有代码的 Python 笔记本。
不令人满意的结果
当谈到可解释的人工智能时,你可以肯定有人会说出这样的情节:
图一。Python 中 SHAP 库的 Force plot。[作者图]
这被称为“力图”,很容易通过 Python 的 SHAP 库获得。总的来说,我认为这个情节是次优的。
数据可视化的第一条戒律:人类的注意力非常有限。
「原力情节」有什么问题?它包含的信息太多了!事实上,
- 它显示 SHAP 值和观察值。有效的 XAI 应该只基于后者,因为 SHAP 值对人类来说是不可理解的;
- 它显示了所有的特征。有效的 XAI 应该能够只选择少数与单个(或一组)客户相关的特性;
- 它既显示了对客户流失概率产生积极影响的特征(红色),也显示了产生消极影响的特征(蓝色)。有效的 XAI 应该只关注客户流失的原因,因为我们对客户流失感兴趣。包括降低流失概率的因素令人困惑;
- 它显示观察值,但不提供上下文。有效的 XAI 应该基于上下文。例如,图中显示该客户拨打了 2 个国际电话,但是并没有解释为什么这是相关的。换句话说:2 个国际电话太多了吗?还是太少?
找到“至关重要的少数”
在 XAI,我们离不开 SHAP 价值观(在本文中,我们将把 SHAP 视为魔法,但如果你想知道它是如何在引擎盖下运作的,我已经写了一篇文章详细解释了这一点: SHAP 解释了)。
例如,假设我们有一个适合某些数据的模型:
**model_fitted = model.fit(X, y)**
。
SHAP 有两个输入:拟合模型和预测矩阵。
**shap_values = get_shap(model_fitted, X)**
。
最需要理解的是,SHAP 的输出是一个与 **X**
形状相同的矩阵。换句话说:
现在,我们来看看 ID 为 950 的客户的输入数据。**X.loc[950, :]**
:
图二。原始功能(客户 id: 950)。[作者图]
相应的 SHAP 值存储在这里,**shap_values.loc[950, :]**
:
图 3。SHAP 值(客户 id: 950)。[作者图]
当 SHAP 值为正数(粉红色)时,意味着相应的功能提高了该客户流失的可能性。SHAP 为负时相反(蓝色)。例如,“国际计划”有助于提高该客户的流失率,而“总夜间分钟数”会降低流失率。
“力图”(见图 1。)显示所有这些数字(19 个原始特征和 19 个 SHAP 值),每个彩色条的长度与 SHAP 值的大小成比例。
但是,如前所述,我们只想关注最重要的症状,即“重要的少数”。第一步是看看 SHAP 值是如何产生的:
图 4。SHAP 值(客户 id: 950)。[作者图]
这些特征已经通过增加 SHAP 进行了分类,因此主要症状在右边。我们可以只保留从右边开始的 4 或 5 个特征,而不是显示所有 19 个特征,从而获得更有效的可视化效果。事实上,有了“国际计划”、“国际通话总量”、“全天费用”以及更多,我们已经考虑了最大部分的风险因素。
好吧,但也许,在这种情况下,我们只是运气好。也许,对于其他顾客来说,有很多原因,而不仅仅是几个。因此,让我们为所有有风险的客户复制上面的情节。
图 5。每个客户的 SHAP 值按升序排序。[作者图]
(注意,这一次,我们不能在 x 轴上标注特性名称,因为每个客户的排序顺序可能不同)。
我们在一个客户身上看到的似乎适用于所有客户:几乎所有的风险都是由少数几个功能造成的。
实际上,这是一种“普遍”行为:它不仅发生在这个数据集或这个应用程序中。一个结果的绝大部分是由极少数原因造成的这一观点在自然界几乎随处可见,被称为 帕累托原理 。
这个概念非常强大,因为不管你有多少特性,它都是有效的。
但是“少”是多少呢?
让我们回到我们的客户。我们已经决定只保留具有最高正 SHAP 值的要素。但是,确切地说,他们有多少人?我们希望找到一个可以大规模应用的规则,而不需要我们为每一个客户做出决定。
当然,没有固定的规则。但是这里有一个在实践中很有效的方法。首先,我们需要按升序对 SHAP 值进行排序。下一步是计算累积和。让我们看看结果:
图 6。SHAP 值,累积和(客户 id: 950)。[作者图]
仔细想想,最终位于 y 轴正侧的特征(在粉色背景上)实际上是“触发”客户从无风险(SHAP 总和≤ 0)到有风险(SHAP 总和> 0)的特征。我们希望专注于这些功能,而忽略其他功能。
这可以用几行 Python 代码来完成:
**shap_sorted = shap_values.loc[950, :].sort_values()
main_causes = shap_sorted[shap_sorted.cumsum() > 0].index**
既然我们已经找到了“关键的几个原因”,最重要的部分是理解为什么它们会导致流失风险增加。
“治标,治本。”— 迈克尔·克莱顿
如果我们对所有有风险的客户重复上述过程,我们将得到如下表格:
图 7。主要症状选择表。[作者图]
表中的每个元素都是一个布尔值,表示该功能是否是该客户的相关症状。
一旦我们获得了这张表,我们就可以彻底摆脱 SHAP 价值观了!
重点是: SHAP 价值观非常有用,但没有实际(或商业)意义。在确定主要原因时,我们不能没有它们。但是,一旦我们这样做了,就没有理由把它们带在身边。
从 XAI 的角度来看,最重要的部分还没有到来。的确,仅仅指出相关症状是不够的。真正与众不同的是能够解释为什么这些功能会让客户面临风险。
一种有效的方法是通过基于主要原因的平行图将客户与样本的其余部分进行比较。
图 8。主要原因的平行图(客户 id: 950)。[作者图]
红线代表客户。蓝线是参考人群(即样本)的中值,而蓝带的上下边界分别是人群的第 25 和第 75 百分位。
任何说商业语言的人都能理解这个情节。
事实上,它并不涉及诸如 SHAP 价值观之类的复杂概念。此外,它一目了然地显示了“正常”人口是如何构成的,以及该客户相对于样本中的其他客户有多极端。
在这种情况下,我们立即注意到这个家伙持有“国际计划”,而至少 75%的客户没有。尽管如此,他拨打的国际电话(总国际电话数= 2)还是少于大多数客户(事实上,至少 25%的客户至少拨打了 3 次国际电话)。此外,这个人比大多数人支付更多的费用(总日费、总夜费),也打更多的电话(总日分钟数)。
在这一点上,很容易理解为什么这个客户有流失的风险:这个人实际上是在为他没有使用的东西(一个国际计划)付费,并且他比客户群中的其他人付费更多。从图 1 中不可能注意到这一点。
从单一客户到群体
我们已经为客户 n. 950 建立了一个地块。但在大多数实际情况下,不可能一一列举。想象一下,有成百上千的高风险客户。在这种情况下,更有效的方法是建立症状相似的客户群并将它们放在一起。
让我们看几个例子:
图 9。主要原因的平行图(一组客户)。[作者图]
图 10。主要原因的平行图(一组客户)。[作者图]
在这种情况下,我们比较了两种分布:
- 红色表示有相同症状的一群顾客。实线代表中间值,而范围在第 25 和第 75 百分位之间;
- 蓝色代表样本的其余部分。
这些图表使我们的方法具有可扩展性。事实上,一旦获得了同类集群,就很容易用更适合任何给定组的“处理方法”来处理每个集群。
你可以在这个 Github 笔记本里找到帖子的所有代码。
感谢您的阅读!我希望这篇文章对你有用。
我感谢反馈和建设性的批评。如果你想谈论这篇文章或其他相关话题,你可以发短信到我的 Linkedin 联系人。
将机器学习引入数据
原文:https://towardsdatascience.com/bring-machine-learning-to-the-data-c85a4b2f34b6?source=collection_archive---------38-----------------------
Google BigQuery 展示了一个新的范例
图片来自穆罕默德·哈桑在 Pixabay
从数据仓库或数据湖中提取数据的传统方法——然后对其进行清理、转换并构建模型——正慢慢被一种更新的方法所取代
将计算带到数据或
将机器学习/算法引入数据
特别是因为像谷歌、亚马逊和微软这样的大提供商将数据库和数据仓库等服务与机器学习服务相链接,所以不再需要将数据集成到其他平台或系统中。在像 Google 的 BigQuery 这样的服务中,传统的数据库系统甚至用 ML 工具进行了内部扩展[2]。
新范式的优势
新方法的优势包括简化的基础架构。如果我们看一下下面的简化架构,就可以清楚地看到,如果服务已经可以在云环境中相互通信,或者集成在一个服务中,那么就不需要第三方系统的进一步接口。这大大缩短了这些环境的设置和维护时间。
经典分析流程架构—作者图片
另一个重要因素是数据科学流程可以显著简化。每个数据科学家和工程师都知道这一过程有多耗时,因此将您需要的一切都放在云环境甚至服务中的方法大大简化了这一过程。
集成的数据湖和分析平台
第三点是可编程性的简化——比如分析师只用 SQL 就能轻松完成机器学习任务。下面我想用 Google BigQuery 中的一个简单例子来说明这一点。如果您想更深入地了解数据平台现代化这一主题,您可能会对这篇文章感兴趣。
BigQuery ML 示例
为了展示解决方案如何简化数据分析过程,我将使用 BigQuery 及其 ML 功能。这里,我使用了公共数据集,其中包含了爱荷华州所有批发购买的酒。
在这个例子中,我只是想做一些聚类。这个例子非常简单,但是很好地展示了可能性和您必须采取的步骤。
步骤 1 —创建模型
CREATE OR REPLACE MODEL DATA.iowa_bottle_clusters OPTIONS (model_type=’kmeans’, num_clusters=3, distance_type = ‘euclidean’) ASSELECT item_description, AVG(state_bottle_cost) AS state_bottle_cost,FROM `bigquery-public-data.iowa_liquor_sales.sales`WHERE EXTRACT(YEAR FROM date) = 2018GROUP BY item_description;
上面,您可以看到我使用了 k-Means 算法,并将聚类数的参数设置为 3。我的想法是,如我所说,高度简化的例子只是使用变量state _ bottle _ payed(酒精饮料部门为每瓶订购的酒支付的金额)将其分为三个价格类别。
第二步——评估模型
创建模型后,BigQuery 会自动为您提供一些指标。这些允许对聚类算法进行评估。对于戴维斯-波尔丁指数,目标将是最低的可能值【3】。
指标—按作者分类的图像
另一个很棒的特性是我们得到的损失图表。
随着
SELECT * FROM ML.TRAINING_INFO(MODEL Data.iowa_bottle_clusters);
和
SELECT davies_bouldin_index FROM ML.EVALUATE(MODEL Data.iowa_bottle_clusters);
如果需要,您可以稍后查询结果。
第三步——预测
Via ML。预测我们将看到某个特定品牌属于哪个集群。
SELECT
centroid_id,
item_description,
state_bottle_cost
FROM
ML.PREDICT(MODEL Data.iowa_bottle_clusters,(SELECT
item_description,
AVG(state_bottle_cost) AS state_bottle_cost
FROM
bigquery-public-data.iowa_liquor_sales.sales
WHERE
date <= '2018-02-02'
AND date >='2018-01-01'
GROUP BY
item_description) )
ORDER BY
centroid_id;
步骤 4 —检查结果
现在让我们检查结果是否有意义(当然这是一个非常简单的例子),但是让我们看看。以下是三个集群的示例:
第一组中只有一个项目似乎是高级产品:
1 —雷米·马丁路易十三干邑— 1599.19
在第二组中,我们有更多的瓶子,这似乎被认为是中产阶级,例如:
2 —达尔莫尔雪茄麦芽苏格兰威士忌— 93.33
2 —卡瓦兰雪利酒橡木单一麦芽— 73.33
2 —吉姆梁酒厂的杰作— 104.91
还有一组你可能会和可乐或其他混合物一起喝的产品:
3—斯米尔诺夫葡萄— 8.25
3 —斯米尔诺夫酸青苹果— 8.25
3 —伯内特水果潘趣酒— 4.48
所以最终的结果并没有那么糟糕——但当然可以优化。这里您需要的只是 BigQuery 和一些基本的 SQL。
结论
在这篇短文中,我想提供一些关于将机器学习或算法转移到数据的范式的理论基础知识。此外,相对于传统方法的优势是显而易见的。尤其是在设置和维护方面,以及在节省时间方面的实际数据分析过程。最后,我展示了现在只使用 SQL 和 Google 的 BigQuery 开发一个机器学习模型是多么容易。要了解更多信息,请点击下面的链接。
资料来源和进一步阅读
1唐斯,B. N .,奥菲姆,D. M .,黑尔,w .,Xi,l .,多纳霍,L. A .,&卡拉,D. (2014)。将计算引入数据的实际例子。生物分子技术杂志:JBT , 25 (增刊),S5。
【2】Google,什么是 BigQuery ML? (2020)
[3]戴维斯博士,波尔丁博士(1979 年)。“一个集群分离措施”。IEEE 模式分析与机器智能汇刊。PAMI-1 (2),第 224 至 227 节。
在几秒钟内将你童年的图画变成现实 Meta 创造性人工智能的演示
原文:https://towardsdatascience.com/bring-your-childhood-drawings-to-life-within-seconds-a-demo-of-metas-creative-ai-1e8695d9f3b6?source=collection_archive---------4-----------------------
创造性人工智能正在兴起。在几秒钟内,Meta Demo Lab 的这款全新工具将静态绘图转换为生动的卡通版本。
从图画中创造一个动画角色从未如此简单。[作者 GIF,使用 Meta 演示实验室创建]
随着假期的临近,是时候用 AI 来点轻松的娱乐了。作为一个孩子,你可能会幻想你的画变成现实——移动、跳舞、奔跑……感谢 Meta AI 研究,这不再需要保持幻想!
在元演示实验室,只需几秒钟就能把一幅画变成一个成熟的动画角色。诉讼程序极其简单;这简直是儿戏。我们去看看吧!
画点什么
嗯……不需要言语。画一幅人体解剖图就可以了。理想情况下,它在白色背景上,没有阴影或其他物体。
我的静态图。我希望我能说它源于我的童年,但遗憾的是我今天才画的。
创建一个遮罩
上传后,程序会自动创建一个遮罩,覆盖你所画角色的体表。这个演示很好地将人物从背景中分离出来。如果它没有完全捕捉到所有内容,标记和橡皮擦允许手动纠正遮罩。
为你的角色创建一个面具[截图来自元演示实验室
重新调整分数
创建遮罩后,是时候设置关节(脚踝,手腕,膝盖,臀部,肩膀,肘部,手腕,耳朵,眼睛,头部中心)以确保逼真的动画。
在这种情况下,除了眼睛和(明显的)耳朵,一切都非常准确。同样,一个简单的拖放就可以修复它。你可以故意弄乱关节,看看会发生什么,但我们在这里适当地做一下。
设置角色关节【截图来自元演示实验室
还有…跳舞!
整个过程几乎在几秒钟内完成。之后就是挑选自己喜欢的动画,渲染,就大功告成了!
[作者 GIF,使用 Meta 演示实验室创建]
该动画可以作为一个简单的 MP4 下载——本文中转换为 GIF 格式降低了质量。
或者……盒子!
[作者 GIF,使用 Meta 演示实验室创建]
或者…跳过!
[作者 GIF,使用 Meta 演示实验室创建]
嗯,你明白了。目前有 32 部动画可供选择。
人工智能在哪里?
好吧,酷,但是人工智能在哪里?如果他们不从你的上传中学习,Meta 就不是 Meta 了。在开始上传时,他们会请求将您(孩子)的绘画存储在一个公共数据库中,该数据库随后将用于进一步培训和开发该工具。与任何机器学习算法一样,手头的高质量数据越多,我们未来可以预期的结果就越好。
尽管从表面上看这是一个噱头,但就此放弃创造性人工智能将是一个错误。人工智能正在以越来越快的速度产生新的内容。事实上,Gartner 将生殖人工智能确定为 2022 年的顶级技术趋势之一:
进入市场的最可见、最强大的人工智能技术之一是生成式人工智能——从数据中学习内容或对象的机器学习方法,并使用它来生成全新的、完全原创的、真实的人工智能。— Gartner
Gartner 预测,正在创建的所有数据的百分比将从 2021 年的不到 1%飙升至 2025 年的 10%。原因显而易见。把我们自己限制在内容创作上,在创作音乐、动画、艺术和——对我们来说很不幸——写作方面有大量的机会。
我们还没有到人类创造力过时的地步。现在,只需快速参观一下 Meta Demo Lab,就能在假期中神奇地将您孩子的杰作带回来!
[作者 GIF,使用元演示实验室创建]
https://www.gartner.com/en/newsroom/press-releases/2021-10-18-gartner-identifies-the-top-strategic-technology-trends-for-2022 https://developer.ibm.com/blogs/what-is-generative-ai-and-how-much-power-does-it-have/
使用亚马逊 SageMaker 自带容器
原文:https://towardsdatascience.com/bring-your-own-container-with-amazon-sagemaker-37211d8412f4?source=collection_archive---------5-----------------------
SageMaker 中最灵活的实时推理选项
图片来自斯蒂芬·菲利普斯拍摄的 Unsplash
过去我曾谈论过如何在亚马逊 SageMaker 上训练一个定制的 TensorFlow 模型。这很容易,因为 SageMaker 为流行的框架管理容器,比如 TensorFlow、PyTorch、HuggingFace 等等。这允许开发人员使用这些提供的容器,并专注于以一种称为脚本模式的方法提供用于训练和/或推断的脚本。
现在,假设 SageMaker 现有的深度学习容器不支持您正在使用的框架。这是一个真正的可能性,因为有许多现有的 ML 框架将在未来的每一周推出。SageMaker 提供了一个名为自带容器 (BYOC)的功能,作为开发者,你可以完全控制这个容器。在本文中,我们将通过一个示例,将一个预训练的空间 NER 模型引入 SageMaker,并通过部署过程创建一个用于推理的实时端点。如果您想直接跳到代码,请查看这个库的源代码和其他与推理相关的 SageMaker 示例。
**注意:**对于刚接触 AWS 的人来说,如果你想继续学习,请确保在下面的 链接 中注册账户。部署过程中会产生成本,尤其是如果您让端点保持运行。本文还将假设您对 SageMaker 和 AWS 有一定的了解。
目录
- 容器设置
- 构建 Docker 映像并将其推送到 ECR
- 创建模型
- 创建端点配置
- 创建端点
- 推理
- 结论和附加资源
1.容器设置
在我们开始之前,请确保创建一个笔记本实例并在 SageMaker 上运行。一旦您打开了 SageMaker JupyterLab 设置,您的目录应该如下所示。创建一个笔记本(Python3 内核),然后创建一个包含 docker 文件和推理/服务文件设置的目录。
总体结构(作者截图)
服务/预测代码的 docker 文件和目录(作者截图)
您的 Docker 文件将指向您的 NER 目录,其中包含您的代码来编排 SageMaker 上的模型服务以及 Docker 将安装的内容。在这个 NER 目录中,有四个文件有助于这个设置。
NER 目录(作者截图)
- nginx.conf :配置设置 nginx 前端。你可以直接复制这个文件,因为对于大多数 BYOC 例子来说它是。
- serve :这个程序在后台启动一个 gunicorn 服务器,它是在容器启动托管时启动的,你也可以把这个文件保持原样。注意,通常情况下,如果你是负责培训和主持的 BYOC 人,你也会有一个“培训”文件。关于这个例子,请查看这个代码。
- predictor.py :这个程序实现了一个 Flask web 服务器,在 /ping 和 /invocations 中有两条路径是至关重要的。Ping 接收 GET 请求,如果您的容器是健康的,则返回 200。调用是您可以对正在使用的模型使用推理逻辑的地方,它将从您的模型返回预测。
- wsgi.py :是你的 predictor.py 文件的包装器,不需要修改,除非你用另一个文件名命名 predictor.py。
我们要查看的文件是 predictor.py,因为配置的其余部分不需要修改或编辑。
负载空间模型
在这里,我们可以加载我们的空间模型进行推理。接下来,正如我们所讨论的,我们正在处理两个 URL。我们可以使用 ping 路径对我们的容器执行健康检查。
健康检查
现在我们可以专注于调用路径中的推理逻辑。
空间推理
这里我们期待一个 JSON 输入,所以我们将在给端点提供信息时在客户端进行配置。我们的容器现在已经设置好了,我们现在需要创建一个 Dockerfile ,它指向并执行这些文件并且安装我们的模型依赖。
空间安装的 docker 文件
在这里,我们安装 Spacy 并将我们的代码指向 SageMaker /opt/program 目录,该目录是 SageMaker 在为模型提供服务时创建的。
现在,我们可以进入笔记本,专注于将此图像推送到 ECR,SageMaker 可以在那里检索并使用此图像进行推理。
2.构建 Docker 映像并将其推送到 ECR
SageMaker Classic 笔记本带有对 Docker 的支持,因此我们也可以在实例上的终端中进行本地测试。在进入创建端点的步骤之前,我们需要构建 Docker 映像并将其推送到 ECR,SageMaker 在 ECR 中存储和检索所有用于训练和推理的映像。以下 shell 命令可以在笔记本中运行,无需任何重大更改。
将 Docker 图像推送到 ECR
在这里,我们使 serve 文件可执行,用我们的算法名命名我们的 ECR 存储库,并基于我们的容器结构和 Docker 文件构建 Docker 映像。这需要一点时间,但是你应该能够在最后看到一个成功的映像,以及一个用你的映像创建的 ECR 存储库。
图片被推送到 ECR(作者截图)
3.创建模型
现在,我们可以专注于使用 SageMaker 构建实时端点。对于实时端点创建,传统上要遵循三个步骤:模型创建、端点配置创建和端点创建。我们可以通过使用 SageMaker Boto3 客户端来编排这些步骤。
客户端设置
注意这里有两个客户端: sm_client 用于模型、端点配置和端点创建。运行时客户端用于推断和调用端点。
现在的第一步是模型创建,这里我们需要指向我们推送的 ECR 图像,以便 SageMaker 可以创建我们的模型。我们通过提供我们的算法名称和 account_id 作为容器位置的变量来实现这一点,您也可以从 ECR 中手动抓取图像 URI,尽管不建议这样做。
模型创建
在这里,我们还指定了我们正在使用的实例类型,因此请确保查看 SageMaker 实例以了解什么适合您的用例及价格。您应该看到单元返回您创建的模型,我们将在端点配置创建的下一步中使用它。
模型已创建(作者截图)
4.创建端点配置
我们现在可以使用我们的模型名,并简单地将其作为我们的端点配置的输入,这将为我们正在创建的端点类型提供必要的细节。
端点配置
端点配置创建(作者截图)
5.创建端点
现在,我们可以使用端点配置来创建端点,我们将用它来进行另一个简单的 Boto3 调用。
端点创建
这应该需要几分钟的时间来执行,但是如果您看到一个成功的消息,我们现在可以看到一些示例推理了。
端点已创建(作者截图)
6.推理
现在我们可以调用端点了。我们需要记住,我们在 predictor.py 文件中输入了一个样本输入 json,因此我们在调用之前正确地配置和序列化了输入。
示例调用
现在我们可以看到一些来自我们端点的 NER 结果样本。
作者截图
如果您不想让您的端点启动并运行,请确保运行下面的 Boto3 调用来删除您的端点,以免产生成本。
删除端点
7.结论和附加资源
https://github.com/RamVegiraju/SageMaker-Deployment/tree/master/RealTime/BYOC/PreTrained-Examples/SpacyNER
要访问示例的完整代码,请查看上方的链接,还有大量其他 SageMaker 推理示例和资源。BYOC 一开始可能会令人生畏,但是它提供了难以置信的灵活性来配置和调整 SageMaker 以与您的框架一起工作。在一天结束时,通过改变当前设置中的几个文件,您可以使用您正在使用的任何模型和框架进行大规模的推理。
要了解使用什么 SageMaker 推理选项,请查看这篇文章。要了解如何使用现有的 SageMaker 图像,请查看这篇文章。
如果你喜欢这篇文章,请在LinkedIn上与我联系,并订阅我的媒体 简讯 。如果你是新手,使用我的 会员推荐 报名。
让你的电报聊天机器人更上一层楼
原文:https://towardsdatascience.com/bring-your-丨t丨e丨l丨e丨g丨r丨a丨m丨s丨-chatbot-to-the-next-level-c771ec7d31e4?source=collection_archive---------3-----------------------
发现可以改变现状的高级功能
丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 是一个流行的开发聊天机器人的平台:优秀的文档,活跃的社区,各种各样的库和大量的例子。
如果你是刚入门的话,这里有很多教程,尤其是关于 T2 媒体的。并且 Stackoverflow 也是一个很好的回答问题和理解问题的资源(你的作者经常被发现在那里试图帮助其他开发者🤓).
相反,本文关注于与使用 Python 电报机器人实现电报机器人相关的更高级的方面:
- Pull vs Webhook
- 获取聊天 ID
- 显示“正在输入…”并建议答案
- 深层链接
- 发送媒体和文件
Christian Wiediger 在 Unsplash 上拍摄的照片
本地工作的轮询模式
电报机器人可以通过拉或推机制工作(参见更多网页挂钩)。“拉”机制是 bot(您的代码)定期检查服务器上新的可用消息的地方。
每个人都同意这不是一个理想的方法(不必要的资源浪费,消息在 24 小时后被丢弃),但是在本地开发时它是方便的。(不需要 ngrok 之类的隧道软件)。
**def** main():
updater = Updater('my丨t丨e丨l丨e丨g丨r丨a丨m丨s丨Token')
dp = updater.dispatcher *# define command handler* dp.add_handler(CommandHandler(**"**help**"**, help_command_handler))
*# define message handler* dp.add_handler(MessageHandler(Filters.text, main_handler)) updater.**start_polling**()
生产上的网络挂钩
一旦 bot 为部署做好准备,就该启用 Webhook 了:这样做 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 会将更新推送到注册的 webhook 端点,只有当有新的消息传入时,您的服务才会变得繁忙。
updater.start_webhook(listen=**"0.0.0.0"**,
port=3978,
url_path='my丨t丨e丨l丨e丨g丨r丨a丨m丨s丨Token')
updater.bot.setWebhook('https://example.com/svc/my丨t丨e丨l丨e丨g丨r丨a丨m丨s丨Token')
注意 : webhook 与无服务器架构或“按需”节点配合良好。我已经在 Heroku 自由层上部署了 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 webhooks,它会在 30 分钟不活动后进入睡眠状态,但如果推送新消息,Heroky Dyno 会启动,消息会在几秒钟内消耗掉。
注 2 :根据 bot 部署的位置,需要配置端口号。例如,在 Heroku 上,端口通常由 port 环境变量定义,不应该硬编码。
如何注册 webhook
你可以调用一个setWebhook
URL:使用你的私有令牌并传递 webhook 的 URL(必须是 HTTPS)。
[https://api.丨t丨e丨l丨e丨g丨r丨a丨m丨s丨.org/bot{](https://api.丨t丨e丨l丨e丨g丨r丨a丨m丨s丨.org/bot(mytoken)/setWebhook?url=https://mywebpagetorespondtobot/mymethod)my丨t丨e丨l丨e丨g丨r丨a丨m丨s丨Token}/setWebhook?url=https://example.com/svc
在拉和推模式之间切换
我发现使用环境变量以编程方式在轮询和 webhook 之间切换非常方便:默认设置是polling
在本地工作,但是,当部署在实时系统上时,它可以被覆盖(到webhook
)。
# read MODE env variable, fall back to 'polling' when undefined
mode = os.environ.get(**"MODE"**, **"polling")****if** DefaultConfig.MODE == **'webhook'**:
# enable webhook
updater.start_webhook(listen=**"0.0.0.0"**,
port=3978,
url_path='my丨t丨e丨l丨e丨g丨r丨a丨m丨s丨Token')
updater.bot.setWebhook('https://example.com/svc/my丨t丨e丨l丨e丨g丨r丨a丨m丨s丨Token')**else**:
# enable polling
updater.start_polling()
获取聊天 Id
回复收到的信息非常简单。
update.message.reply_text("Hi there!")
然而,有时我们希望能够在用户没有询问任何事情的情况下发起消息(例如,几天后的通知,以重新吸引我们的用户)。
检索(并保存)在用户发送的消息的 JSON 有效负载中找到的chat_id
(是的,您至少需要一条消息)
{'update_id': 527095032,
'message': {
'message_id': 412,
'date': 1615991013,
'chat': {
'id': 931365322,
'type': 'private',
'username': 'gcatanese',
....
当解析有效负载 Python 时,不要忘记不同的消息有稍微不同的 JSON。
**def** get_chat_id(update, context):
chat_id = -1
**if** update.message **is not None**:
# text message
chat_id = update.message.chat.id
**elif** update.callback_query **is not None**:
# callback message
chat_id = update.callback_query.message.chat.id
**elif** update.poll **is not None**:
# answer in Poll
chat_id = context.bot_data[update.poll.id]
**return** chat_id
建议的行动
引导对话,为用户提供预定义的选项以供选择。这可以通过使用InlineKeyboardMarkup
来实现,这是一个出现在信息旁边的键盘(像一个问题)。
作者图片
下面是创建选项的 Python 片段:
options = []
options.append(InlineKeyboardButton(text='Text', callback_data='1'))
options.append(InlineKeyboardButton(text='File', callback_data='2'))
options.append(InlineKeyboardButton(text='GoogleDoc', callback_data='3'))
options.append(InlineKeyboardButton(text='Gallery', callback_data='4'))reply_markup = InlineKeyboardMarkup([options])context.bot.send_message(chat_id=get_chat_id(update, context), text='What would you like to receive?', reply_markup=reply_markup)
重要的是要理解响应将由一个CallbackQueryHandler
来处理,并且传入的 JSON 有效负载不同于纯文本消息。
# input from text message
text = update.message.text
# selection from callback
choice = update.callback_query.data
注意:一旦做出选择,选项就会从聊天中消失。
注 2 :使用常数值定义callback_data
,该常数值将用于决定要做什么。与按钮上的text
不同,该值不应改变,因为它对用户不可见。
choice = update.callback_query.data**if** choice == **'1'**:
# Choice 1: Text
update.callback_query.message.edit_text('You have chosen Text')
显示“正在键入…”
显示输入指示器是聊天机器人的一个常见功能:用户被告知消息即将到达,即使有一点延迟。
context.bot.send_chat_action(chat_id=get_chat_id(update, context), action=丨t丨e丨l丨e丨g丨r丨a丨m丨s丨.ChatAction.TYPING, timeout=1)
time.sleep(1)
注:在显示打字指示器时,我通常会引入一个短暂的延迟,以营造一种真实对话的感觉。
带有附加参数的深度链接
深度链接是一种允许打开与给定机器人对话的机制。这有助于在网站、电子邮件或社交媒体上分享机器人的链接。
定义深层链接时,可以添加一个附加参数:
[https://t.me/username_bot?start=signup](https://t.me/username_bot?start=signup)
该链接打开电报应用程序,提示与机器人进行对话。附加参数被传递给处理/start
命令的CommandHandler
。
**def** start_command_handler(update, context):
param_value = context.args[0]
update.message.reply_text(**'**Value is ' + param_value)
发送文件
聊天机器人可以通过不同的方式发送文件(如 pdf、Office)。
使用send_document
和文件的完整 URL:
url='https://github.com/gc/丨t丨e丨l丨e丨g丨r丨a丨m丨s丨BotDemo/raw/main/test.pdf'
context.bot.send_document(chat_id=get_chat_id(update, context), document=url)
注意:这种方法需要一个直接指向文件的 URL。
另一种方法是首先在本地下载文件,然后用同样的方法发送它send_document
。
# fetch from Google Drive
url = 'https://drive.google.com/file/d/0BZ3dWQ2ZXVOdE1V/view'
r = requests.get(url, allow_redirects=True)
# save local copy
open(**'file.ppt', 'wb'**).write(r.content)# send file to user
context.bot.send_document(chat_id=get_chat_id(update, context), document=open(**'file.ppt'**, **'rb'**), filename="Presentation.pptx")
注意:当 URL 不直接指向一个文件时,这种方法通常是必要的,但它是一个按需输出内容的端点。
创建媒体集
一个很酷的功能是发送一组媒体,如照片,视频和音频。
作者图片
list = []# define list of files
list.append(InputMediaPhoto(media='https://../mintie.jpg', caption='Mint'))
list.append(InputMediaPhoto(media='https://../pinkie.png', caption='Pink'))
list.append(InputMediaPhoto(media='https://../orangie.png', caption='Orange'))
context.bot.send_media_group(chat_id=get_chat_id(update, context), media=list)
注意:机器人最多可以同时发送 10 个媒体文件。
注 2 :每条消息在电报速率限制内计数(每秒 30 条消息),因此您最多可以发送 3 条消息,每条消息包含 10 个媒体(总共 30 个),但在这种情况下,您不能在同一事务中添加任何其他内容(甚至不能是一条简单的文本消息)。
结论
我希望这篇文章有助于理解一些更高级的场景,并发现可以让您的 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 聊天机器人变得更特别的功能。我的建议是总是首先考虑用户在寻找什么(他们为什么要聊天?)然后以一种让他们的谈话没有摩擦、愉快的方式来设计:取得良好的平衡决定了你的聊天机器人的成功。
查看一下 Github repo ,在那里你可以获得上面显示的代码片段。
如有问题和建议,请在 Twitter上找到我。
聊天愉快!
将人工智能引入下一代保险解决方案
原文:https://towardsdatascience.com/bringing-ai-to-next-generation-insurance-solutions-1a75d8e81a33?source=collection_archive---------36-----------------------
财产保险应用中的卷积神经网络
建筑足迹——旧金山(图片由作者提供)
从无人驾驶汽车到加密货币,科技正在颠覆我们生活的方方面面——包括我们工作、饮食和交流的方式。同样,企业正在整合技术和数字化业务流程,以推动增长并为客户创造价值。虽然技术改变了许多行业,但财产和意外伤害(P & C)行业采用技术的速度相对较慢。事实上,P & C 行业的成本结构并没有改善。在过去十年中,每份保单的管理成本增加了 30%以上。
为了解决不断增加的费用和损失率,像河马保险和柠檬水这样的保险技术正在利用人工智能和自动化的力量来重新定义客户与他们的保险公司互动的方式。通过放弃传统的保险代理并创建在线分销渠道,这些保险技术公司能够最大限度地减少整个价值链中的客户接触点,从保险报价到绑定,一直到理赔。虽然大多数保险技术都专注于通过为最终用户提供快速无缝的在线体验来扰乱住宅房地产市场,但商业和工业保险市场的扰乱时机已经成熟。
**下一个 insurtech 颠覆者将是一家能够规划商业和工业资产、构建分析以更好地进行风险选择和索赔管理,并扩展流程以覆盖中小型企业(SME)的公司。**为了简化在线分销渠道,在核保、定价和理赔之间建立分析驱动的反馈回路至关重要。在这种情况下,航空影像和照片可用于构建定制分析解决方案,以便为(再)保险公司提供更好的风险选择和管理。考虑从航空图像中构建数据精炼厂和数据管道,这有助于在飓风或地震袭击后进行核保和事后分析。
虽然有许多方法可以从空间影像中构建数据驱动的工作流,但在本文中,让我们探索一种从航空和街景数据中提取洞察力的强大方法。在本文中,让我们探索 Con voluntive Neural Networks(CNN)如何帮助构建简单而强大的地理空间数据预测模型。来自这些预测模型的可操作见解有助于提高承保和理赔管理的风险选择决策树的质量。
卷积神经网络:
卷积神经网络(CNN)是用于图像分析和分类问题的最常见的神经网络类型。与标准神经网络类似,卷积神经网络也有一个输入和一个输出层,以及多个隐藏层。对于细胞神经网络,隐含层包括一对运算— 【卷积】 和 汇集 。CNN 架构的示意图如下所示,带有两对卷积和汇集操作。我们从输入图像开始,它通常是一个 3D 矩阵。然后,通过将 3D 阵列穿过一系列卷积层来转换图像。卷积和池层的最佳堆叠数量取决于图像中存在的更精细的模式。在每个卷积操作结束时,我们创建一个输入图层的特征地图。在达到预定数量的卷积层之后,我们将卷积后的 3D 输出展平为 1D 向量,然后将其馈送到标准的多层感知器神经网络模型。
卷积神经网络示意图(图片由作者提供)
卷积: 卷积层的作用是从图像中提取特征。图像通常由边缘、形状和对象等图案组成。由于这些模式是固定的,我们可以使用较小维度的滤波器/核来提取这些大规模图像特征。作为卷积层的一部分,我们预定义了选定数量的过滤器及其尺寸。过滤器可以被认为是一个小矩阵(例如 2×2 ),其值用随机数初始化。然后,我们通过在输入图像的每个 2x2 像素块上滑动 2x2 滤波器的中心来卷积滤波器和图像,然后将滤波器中的每个值乘以图像中的像素值,最后将这些乘积求和。卷积层的结果输出表示输入图像的特征图,其中提取了不同的模式。下图显示了 2D 图像阵列(4x4)、过滤器(2x2)和尺寸为 4x4 的输出要素图。
卷积(输入图像 X 滤波器=特征图)
汇集: 卷积后就是汇集操作。汇集卷积特征图的目的是— (1)压缩信息&减少数据的维度,(2)改善计算时间,以及(3)控制过拟合。有两种常见的池功能:a)最大池和 b)平均池。“最大池”函数返回过滤器覆盖的卷积数组的最大值,“平均池”返回过滤器覆盖的卷积数组的平均值。下图显示了池大小为 2x2、步幅为 2 的最大池示例。在这里,我们将尺寸从 4x4 减少到 2x2。汇集的值表示原始图像中最活跃的像素(例如,边缘、图案)。
Max Pooling[Pool Size = 2 x2&Stride = 2](图片由作者提供)
现在我们已经介绍了卷积神经网络的基本构建模块,让我们看看如何使用 TensorFlow Keras API 轻松实现卷积层。下面的代码片段显示了卷积层的一般实现。对于这个实现,我们选择默认的过滤器数量为 64,内核/过滤器大小为 3x3。我们还使用了最大池,池大小为 3x3,跨度设置为 1 个像素。整流线性 (ReLU)是本实施方案的激活功能选择。
卷积层—卷积和池化操作的 Keras 实现
我们可以很容易地堆叠这些卷积层,以创建一个所需深度的 CNN 模型,如下面的代码片段所示。例如,我们首先用输入图像实例化一个 Keras 张量,然后将一个层的输出作为输入依次传递到下一个卷积层。最后,我们将 3D 特征图展平成 1D 特征向量,然后将它们馈送到标准前馈网络,该网络具有表示我们试图解决的分类问题中的标签数量的多个端节点。
整合—卷积神经网络
应用:
我们已经看到在 Keras 中实现一个基本的 CNN 是多么容易。现在,让我们将 CNN 模型应用于三个不同的数据集,并评估其从空间图像中推断信息/模式的有效性。前两个数据集涉及从航空影像中识别土地利用类别,这有助于对感兴趣的属性/基础设施进行圈定和地理编码,以及为数据管道构建暴露数据集。最后一个数据集着眼于评估建筑物损坏,这有助于自动化理赔工作流。
数据集:
1。UC-Merced 土地利用数据集: 该数据集拥有近 2100 张航空影像,涵盖 21 个不同的土地利用类别。下面显示了 16 个不同图像的样本,以及指定的标签。数据集可以从这个链接下载。虽然每个图像的数据都有一个指定的标签,但是我们可以通过视觉观察发现,可以为一些图像分配多个标签。例如,第一图像可以被标记为“棒球场”、“树”和“建筑物”。
UC-Merced 土地利用图片样本(图片由作者提供)
2。UC-Merced 土地利用数据集(多标签): 为了使 UC-Merced 土地利用目录更能代表地面参考数据,https://big earth . eu/的研究人员用一个或多个(最多七个)标签手动重新标记了每幅图像。在重新标记的数据集中有 17 个不同的类,下面显示了一个带有指定标签的图像示例。多标签的 UC-Merced 土地利用数据库可以从这个链接下载。
UC-Merced 土地利用图像样本【多标签】(图片由作者提供)
3。作为 phi-net 挑战的一部分,加州大学伯克利分校的太平洋地震工程研究(PEER)中心已经收集了一个大型结构图像数据集。该数据集有助于开发和评估基于视觉的自动化算法,用于结构健康监测和损伤评估。phi-net challenge 中有八个检测任务,在这项研究中,我们将使用任务 1 场景级数据,解决图像中的缩放问题。共有 24,309 幅图像,它们分为三类——a)像素,b)对象和 c)结构。可以从这个网页请求数据集。
任务 1:场景级图像(图片由作者提供)
结果:
对于所有这三个应用程序,基本的 CNN 模型架构与前面所示的相同,只是对读/写操作进行了微小的修改,以反映所使用的输入-输出数据。完整的模型实现可以在我的 GitHub 页面上找到。
单个类别: 在这个数据集中的 2100 幅图像中,我们使用了 2000 幅图像用于训练和验证目的,剩余的 100 幅图像用于测试模型。下图显示了测试数据集中的图像样本,包括实际标签(左)和预测标签(右)。该模型在识别图像中的模式和预测适当的标签方面做得相当好。还存在实际标签和预测标签之间存在微小不匹配的情况。例如,第 3 行第 1 列的图像被归类为“密集住宅”,但 CNN 模型预测它是一般的“建筑”类别。
实际【左】和预测【右】(图片由作者提供)
为了总结 CNN 模型在这个分类问题上的性能,我们基于测试数据的实际和预测标签生成了混淆矩阵。我们可以看到该模型具有良好的泛化能力,混淆矩阵看起来是合理的。
混淆矩阵(图片由作者提供)
多标签: 同一个代码实现可以进一步扩展进行多标签分类。与前面的分析类似,我们使用 2000 张图像来训练和验证模型,剩余的 100 张图像用于测试目的。
测试数据集中的图像样本—实际标签(图片由作者提供)
上图展示了来自测试数据集的图像样本以及实际标签。现在,对于相同的图像,让我们比较和对比 CNN 模型生成的标签。我们可以清楚地看到,预测的标签更能描述图像,突出了 CNN 模型在图像中选取多个模式的有效性。
测试数据集中的图像样本—预测标签(图片由作者提供)
建筑物损坏: 现在,让我们过渡到评估同一 CNN 模型在评估视觉损坏估计中的缩放问题时的鲁棒性。如前所述,这里的目标是对场景级图像进行分类,并将它们归类为像素、对象或结构。该模型能够达到 82%的预测准确度分数。
混淆矩阵——建筑物损坏评估任务 1 的模型性能(图片由作者提供)
结束语:
世界上大多数风险都没有保险。经济损失与保险损失之差称为 【保障缺口】 。保险投保率不高的原因有很多,但普遍的成本结构是最令人望而却步的原因。如果我们能够利用最新的技术和计算进步来降低保险成本结构,我们将能够在缩小保障差距方面取得重大进展。
在本文中,我们谈到了构建一个简单的卷积神经网络模型的主题,该模型可以帮助从空间数据中获得可操作的见解。当这些自动化模型集成到再保险(保险公司)数据工作流程中时,可以帮助优化组合比率并降低保险成本结构。地理配准完成后,这些模型可自动进行调整,以满足以下要求:
1。为感兴趣的区域开发建筑物和基础设施的位置级暴露足迹
2。创建网格级别的暴露集和风险图,可以进一步扩展以开发新的参数保险产品
3。改进核保和定价的风险选择决策树
4。微调索赔管理流程
感谢阅读这篇文章!感谢所有反馈。如有任何问题,请随时联系我。
如果你喜欢这篇文章,这里还有一些你可能喜欢的文章:
*https://medium.com/@kap923/hurricane-path-prediction-using-deep-learning-2f9fbb390f18
参考文献:
- 杨和纽萨姆(2010)。土地利用分类的视觉词汇和空间扩展,ACM 地理信息系统进展空间国际会议,2010 年。
- 乔杜里,德米尔。路易斯安那州布鲁佐内(2018 年)。使用半监督图论方法的多标签遥感图像检索,IEEE 地球科学与遥感汇刊,第 56 卷,第 1 期
- 高,y .和莫萨拉姆,K. M. (2019 年)。PEER Hub ImageNet(φ-Net):结构图像的大规模多属性基准数据集,同行报告 №2019/07,加州大学伯克利分校太平洋地震工程研究中心。
- 高,杨,&莫萨拉姆,K. M. (2018)。基于图像的结构损伤识别的深度迁移学习。计算机辅助土木和基础设施工程,33(9),748–768。*
通过 ARM 模板将所有基础设施作为一个代码
原文:https://towardsdatascience.com/bringing-all-of-the-infrastructures-as-a-code-through-arm-templates-ba9987ccac1f?source=collection_archive---------39-----------------------
使用 ARM 模板通过 ARM 模板将虚拟机和存储帐户置于安全的私有虚拟网络中
奥马尔·弗洛雷斯在 Unsplash 上拍摄的照片
动机:
假设我们已经有了一个基础设施。有时我们可能需要再次复制相同的基础架构。手动操作肯定会在迁移阶段给我们带来错误。因此,我们将利用来自 Azure 的名为 Azure ARM Templates 的服务,以幂等的方式部署我们的基础设施。
建筑:
苏拉布什雷斯塔。通过 ARM 模板 1 将所有基础设施作为一个代码。2021.JPEG 文件。
先决条件:
- Azure Blob 存储
- Azure 虚拟机
- Azure VNet
Azure 虚拟网络:
Azure 虚拟网络是 Azure 在云中的网络。这个虚拟网络可以细分成不同的子网。在本练习中,我们将创建一个带有一个子网的虚拟网络,该子网是私有的,不能访问互联网。点击虚拟网络,填写详细信息,点击查看+创建。****
苏拉布什雷斯塔。通过 ARM 模板 2 将所有基础设施作为一个代码。2021.JPEG 文件。
您的虚拟网络将成功部署。
苏拉布什雷斯塔。通过 ARM 模板 3 将所有基础设施作为一个代码。2021.JPEG 文件。
Azure 虚拟机:
现在,我们在 VNet 中创建一个 Azure 虚拟机。点击 Azure 虚拟机,填写基本细节,选择刚刚创建的 VNet ,点击审核+创建。
苏拉布什雷斯塔。通过 ARM 模板 4 将所有基础架构作为一个代码。2021.JPEG 文件。
部署应成功完成
苏拉布什雷斯塔。通过 ARM 模板 5 将所有基础设施作为一个代码。2021.JPEG 文件。
Azure Blob 存储:
让我们创建 Azure Blob 存储。点击存储账户,+创建,填写基本信息,点击审核+创建。
苏拉布什雷斯塔。通过 ARM 模板 6 将所有基础设施作为一个代码。2021.JPEG 文件。
您的部署将被创建。
苏拉布什雷斯塔。通过 ARM 模板 7 将所有基础设施作为一个代码。2021.JPEG 文件。
ARM 模板:
ARM 模板是以 JSON 形式编写基础设施以获得最大可用性的幂等方法。创建虚拟机、虚拟网络和子网是一个非常漫长的过程,我们在创建过程中可能会出现错误,因此,ARM 模板是首选。我已经创建了 ARM 模板,并且在我的 GitHub 上。但是不要担心,我会教你如何编写 ARM 模板,更重要的是生成它们,因为从头开始编写非常困难。
假设我已经创建了一些基础设施,我想为它创建一个 ARM 模板。进入资源组,选择资源,和导出模板。
苏拉布什雷斯塔。通过 ARM 模板 8 将所有基础设施作为一个代码。2021.JPEG 文件。
然后点击下载按钮。
苏拉布什雷斯塔。通过 ARM 模板 9 将所有基础设施作为一个代码。2021.JPEG 文件。
您将获得 template.json 和 parameter.json。template . JSON 包含您想要使用其详细信息创建的基础结构,parameter . JSON 包含您想要为资源指定的唯一名称。在这篇文章中,我将添加我的默认值。您可以通过 parameter.json 添加唯一的名称,并输入下面给出的命令。
在您使用 CLI 执行命令后,它可能无法运行,因为您必须对 JSON 文件进行一些整理,比如删除订阅 id 以实现动态可用性,还需要删除不必要的键值对。对于这篇文章,你不必担心,因为我提供的 JSON 已经发挥到了极致。打开代码后,这里是您需要线性输入的命令。
az create group --name prem-vm --location eastusaz deployment group create --resource-group prem-rg --template-file template.json
演示:
正如在体系结构中承诺的那样,让我们检查一下虚拟机和存储帐户。
苏拉布什雷斯塔。通过 ARM 模板 10 将所有基础架构作为一个代码。2021.JPEG 文件。
苏拉布什雷斯塔。通过 ARM 模板 11 将所有基础设施作为一个代码。2021.JPEG 文件。
我们的两个资源都在我们创建的虚拟网络中。
结论:
我们展示了如何利用 Azure ARM 模板轻松创建复杂的基础设施。这只是最低限度,因为我们可以向 ARM 模板添加越来越多的内容。还有其他工具,如 Terraform 和 Pulumi,我们可以利用它们以声明和命令的方式编写 IaC 代码。可能性是无限的,选择是无限的,你想做什么取决于你自己。如果你遇到任何问题或难以遵循这些步骤,请在下面评论这篇文章或在 tsulabh4@gmail.com 给我发消息。你也可以在 Linkedin 和 GitHub 上和我联系。
资源:
1 Azure 虚拟网络:https://docs . Microsoft . com/en-us/Azure/Virtual-Network/Virtual-networks-overview
[2] ARM 模板:https://docs . Microsoft . com/en-us/azure/azure-resource-manager/templates/overview
将数据科学引入能源领域
原文:https://towardsdatascience.com/bringing-data-science-to-energy-cbebfc704c57?source=collection_archive---------27-----------------------
为什么可再生能源项目工程师应该学习数据科学
作者照片
可再生能源项目工程师有很多责任。他们必须准确预测未来 30 多年的天气,设计一个电厂以最大限度地降低建设和运营成本,并管理涵盖地面以上 500 英尺空间到地面以下 30 英尺土壤特性的研究。工作量的多样性带来了准确性的压力;这些研究中的小错误可能代价高昂。一座 100 兆瓦发电设施 1%的能源预测误差会造成超过 200 万美元的终生收入损失。
由于所需任务的范围,理想的工程师必须是全面的,具有强大的工程背景。通常,他们拥有机械、土木或环境工程学位。虽然这些课程非常适合培养管理项目工程研究所需的技能,但通常不会教授熟练的数据科学技能,如如何编程、高级统计和机器学习。结果是可再生能源工程师的劳动力在没有适当培训(或时间)的情况下有效地处理大量数据。这给清洁能源革命带来了一个问题。
但是这真的是个问题吗?能源评估软件已经存在,Excel 模板可用于定制其输出。机器学习听起来不必要的复杂,只是一个时髦词,它将要求我们雇用软件工程师来减缓没有附加值的项目开发。有些人不应该需要计算机科学学位来从事工程工作。
当然,软件确实存在,Excel 模板确实有效,项目工程师不需要成为软件工程师,但现有的软件会咬人,Excel 模板会咬人,编写机器学习代码所需的技能水平略高于用 byte 这个词制造双关语所需的水平。提升项目工程师的数据分析技能的成本是微不足道的(免费的开源工具、免费的培训材料、很少的学习时间),并且它为开发公司整体带来了巨大的利润(更少的错误、更高的生产率和更好的项目洞察力)。这里有一个例子。
项目工程师的一项常见任务是,在给定不同布局约束的情况下,估计项目在其整个生命周期内将产生的能量。这种分析对于项目的经济性是至关重要的,因此受到高度的审查,但是一个项目在完成开发时可能会运行上百种不同的评估。这些评估通常是匆忙地成批执行的,一次运行十次迭代,每批之间间隔几个月。以下是传统流程:
1.必须对现场天气数据进行汇编、清理和分析。
2.必须汇编和分析卫星气象数据集。
3.必须跨现场数据和卫星数据绘制模型,并预测新的天气数据集。
4.这些天气数据必须输入到能源评估软件中,并设置特定的输入,以代表项目布局的单次迭代。
5.能源评估软件的输出必须输入到 Excel 模板中,由该模板进一步处理结果。
6.将创建一个报告来汇总 Excel 模型的结果。
7.对于项目的每个布局迭代,必须重复步骤 4-6。
通常,此流程的第 1-3 步包括从各种网站下载 CSV,并将它们全部插入一系列 Excel 模板,将数据从一个模板复制并粘贴到下一个模板。有时,除了 Excel 之外,还会使用特定应用软件。“清理”过程是通过手动梳理成千上万的数据点来删除您不喜欢的数据点(或者因为您没有时间而什么都不做),并且分析结果是高度主观的。如果你让两个工程师重复这个过程(或者同一个工程师试着做两次),你会得到两个不同的答案。用于预测天气数据的模型通常非常简单,但这并不全是坏事,因为这个过程有太多的不确定性,无法保证任何更复杂的事情。总的来说,这个过程可能需要一天的时间来完成,并需要另一名工程师的详细审查。
步骤 4-7,如果设置得好,非常单调,不需要任何批判性思维。这相当于让某人重复点击屏幕上的相同点,一次也不出错。手动错误可能而且经常发生,尤其是在时间紧迫的情况下(每次都是这样)。
再次说明,这个过程是可行的。优秀的工程师足够勤奋,能够发现大的错误,并且能够将所有的小错误一笔勾销。是的,时间下沉是巨大的,但是工程师只是被期望在办公室呆到很晚来完成它。最重要的是,任何人都可以被训练成这样。
与此同时,可再生能源项目的利润率继续下降。市场竞争越来越激烈,如果一个项目想要有机会,能源预测的不确定性必然会加剧。最重要的是,工程师的工作量呈指数增长,他们花在疯狂点击屏幕上的任何时间都可以更好地用于工程。
幸运的是,上面概述的整个过程可以在工程师喝杯咖啡的时间内完成。他们只需要指定想要运行的布局场景,然后点击 play。当他们回来时,他们可以把他们含咖啡因的能量用于批判性地分析结果,这是他们以前负担不起的。他们可以相信分析没有人为错误,不确定性更少,并且团队中的任何人都可以完全重现。
这个黑魔法按钮是什么?这是一种无需正式培训、无需任何费用即可打造的东西。任何工程师都可以编写一个简单的程序来自动化整个过程,从获取数据,到使用高级统计模型进行分析,然后创建交互式视觉效果和有吸引力的报告。该工程师甚至可以完美地定制程序,以匹配他们公司的工作流程,这是第三方软件永远做不到的。我知道,因为我自己也做过。
对建筑工程师数据科学技能的好处远不止这个例子。全自动、可重复的工作流节省了无数时间和错误,复杂的模型(如机器学习)可以利用当前未充分利用的数据来释放业务洞察力。可再生能源项目工程师有更好的方法来分析他们的数据,开发公司也有更好的方法来利用他们工程师的时间。
这些技能非常容易学习,任何项目工程师都可以在不需要计算机科学学位的情况下掌握它们。强调这种训练对任何工程团队都有好处。知道了这一点,一个更难回答的问题是“为什么工程师不应该学习数据科学?”
将联合学习引入企业
原文:https://towardsdatascience.com/bringing-federated-learning-to-the-enterprise-50284a88f842?source=collection_archive---------45-----------------------
如果公司可以通过跨不同的云和多个数据平台训练数据来建立更准确的 ML 模型,会怎么样?
来源: Freepik
A 面对市场的不确定性和波动性,企业扩展和提高其机器学习(ML)模型性能的能力已经成为一项至关重要的工作。问题是,对于许多企业来说,运行它们的 ML 模型的体系结构不是盟友,而是性能和可用性的敌人。
随着云原生架构的发展,跨不同云平台集成的概念在最近几年肯定有所增长。对于数据、分析和人工智能企业社区来说,情况更是如此,因为企业正在努力充分利用现有的技术投资,以便在当前市场不确定性的情况下优化运营。不幸的是,这种集成通常需要投资软件,以促进本地、混合、边缘和多云部署的使用,从而最有效、最经济地移动和处理数据。
将这种松散耦合的体系结构串联在一起确实可以降低成本,并产生一种敏捷和灵活的感觉。但是想象一下在这种环境中高速大规模地移动 ML 模型数据。当然,这是可以做到的,但通常是异步的。对于异常检测等用例,模型的实时准确性取决于对实时数据的实时访问。以在高度管制的市场中运营的组织为例。对于金融机构来说,即使是高度统一的内部数据架构也可能阻碍进步,因为金融法规可能会限制数据本身的移动性。
但是,如果公司可以通过跨多个云或跨多个数据主权区域/网络训练数据来更快速地提高其 ML 模型的准确性,而又不损害数据隐私或安全性,会怎么样呢?
进入联合学习
第一次讨论是在谷歌 2016 年发表的一篇论文中,联合学习允许数据科学家构建一系列本地数据模型,这些模型从一个共享模型中协作学习,同时将所有训练数据保留在本地。谷歌在 2017 年继续将这一想法付诸实践,为所有 Android 移动设备配备了一个键盘(Gboard)工具,可以不断改善预输入预测,使用来自所有参与设备的数据,而不必实际上将数据从每个设备移动到云。这一理念给谷歌(和 Android 用户)带来了许多重要的好处:
- 针对个性化(每台设备)预输入推荐的更准确、更强大的预测模型
- 利用一般数据保护法规(欧盟 GDPR)中提到的数据最小化原则,改进数据隐私
- 提高性能,降低延迟和功耗,从而改善成本模型
不幸的是,即使取得了早期的成功,联合学习还没有进入主流企业解决方案。但这种情况正在慢慢改变,因为供应商正在寻找将这种独特的架构产品化的方法。2019 年,谷歌推出了开源框架 TensorFlow Federated (TFF),谷歌希望这将鼓励更广泛的行业进行实验。将来,该公司可能会寻求构建一个更具可操作性的,甚至是产品化的应用程序。
跳进拳击场
但是谷歌不是唯一一个调查联合学习的供应商。鉴于 IBM 作为早期创新者的传奇历史,在许多潜在影响但有些不可预测的想法上,如区块链和量子计算,该公司自己调查联合学习的概念也就不足为奇了。
在该公司最近更新的 Cloud Pak for Data(现在是 3.5 版本)的一系列新功能中,IBM 在一个联邦学习的技术预览版中加入了 Python 算法包。基本想法是让公司有能力训练和完善人工智能模型,而不必集中支持这些模型的数据。但是 IBM 并不打算让它的客户将它的联邦学习的实现用于像预输入预测这样的孤立用例。相反,该公司希望企业将联合学习视为一个机会,通过更好的模型训练来推动更好的人工智能成果,而不受数据孤岛的阻碍,并责成集体参与,而不必担心上文提到的隐私、合规、安全或性能问题。
IBM 的方法有三个重要且相互关联的结果。首先,它允许数据科学家和 AI 开发人员利用大量数据,而不必在源和模型之间维护稳定、高性能的数据管道。其次,它使数据科学家能够利用源数据,而不必担心创建和维护数据隐私和安全。第三,企业可以节省维护模型训练性能的成本和风险,避免重新构建或移动数据的需要。
这是否意味着 IBM 客户可以简单地将现有项目移植到联合学习环境中?当然不是。鉴于联合学习本身的许多复杂性,公司应该仔细评估调整现有项目以利用这一新功能的价值。例如,客户必须仔细规划他们希望如何共享数据、调整超参数、构建隐私模型等。以便最有效地利用联合学习。此外,因为联合学习本身是一种非常不成熟的技术,所以有许多未回答的问题必须由所有社区参与者来解决,例如如何克服数据异构性、客户端模型偏差、推理攻击预防等挑战。
最佳策略将包括客户和技术合作伙伴之间的一些联合试验,这些合作伙伴希望为特定的业务成果构建定制的实施。为此,IBM 已经有了一个良好的开端,因为已经有 50 家系统集成商和技术合作伙伴在开发特定于行业的内容,作为 Cloud Pak for Data 的一部分出售。即使是横向数据库、数据管理和数据科学合作伙伴,如 Anaconda、MongoDB 和 NetApp,也可能会找到直接支持垂直化实施的新市场途径。
不管联合学习的市场路线如何,市场领导者谷歌和 IBM 的这些早期努力对企业人工智能从业者来说是个好兆头。虽然联邦学习不太可能以一键点击、可部署的服务选项出现,但它现在作为一个框架(来自谷歌)和一套库(来自 IBM)可用的事实证明,对于努力解决艰难的架构人工智能挑战的公司来说,隧道尽头有一盏灯。
注: 本帖 摘自一篇最初出现在 Omdia VisionAIres 社区 内的帖子。
将更多的人类带入人工智能的生命周期
原文:https://towardsdatascience.com/bringing-more-humans-into-the-ai-lifecycle-ac5bed139314?source=collection_archive---------29-----------------------
介绍 Rubrix,一个人在回路的工具,用于跟踪、探索和迭代人工智能项目的数据
Ehimetalor Akhere Unuabona 在 Unsplash 拍摄的照片
启动人工智能项目变得比以往任何时候都容易。像拥抱脸枢纽或带代码的论文这样的倡议让开发者可以即时获得最新的研究成果。迁移学习和 AutoML 方法的兴起意味着你不需要花几个月的时间来为你的项目训练一个模型。然而,以我的经验来看,这只是故事的(一小)部分。
几乎每个处理“应用”人工智能项目的人都会同意,像数据收集和管理,或者模型服务和监控这样的事情要重要得多,而且很难做好。虽然这些事情也变得越来越容易,但管理数据和模型的任务仍然感觉像是将工具和流程拼凑在一起。当我们谈论工具和过程时,我们最终谈论的是人,我们,使用工具并试图遵循过程的人。
“我们毕竟是人。
皮肉全部揭开后”《毕竟是人》,蠢朋克,2005 年。
关于所谓的 ML/data science 项目生命周期已经写了很多,但是关于在这样的“生命周期”中工具、数据、模型和人之间的相互关系却写得不多。让我们来看看一个“简化的”生命周期:
一个“简化的”人工智能项目生命周期
上图显示了流程中涉及的一系列活动和角色:
- **数据收集和标记:**此活动中涉及的典型角色是数据工程师、数据科学家、业务和主题专家,甚至是数据饥渴项目的群众工作者。
- **模型开发和实验:**这里的核心角色是数据科学家。
- **模型测试:**典型角色有 ML 工程师和数据科学家。
- **模型部署:**这里的角色是 ML 和 DevOps 工程师。
- **监控和可观察性:**主要角色还是 ML 和 DevOps 工程师。
到目前为止,我们有流程和角色。但我们缺少两个关键因素:“生命”和“周期”。数据和模型不是静态的,它们是“活的”东西,训练/测试/服务模型也不是一次性的活动,它们形成循环。
“这是现代生活,但在电视上看起来更好
哇。这是现代生活”《现代生活》,德沃,1981 年
进入 ML 模型的生产使用,事情会变得复杂。实践中出现了几个关键问题,例如:
数据科学家可以轻松地回到业务和主题专家那里收集更多数据吗?
我们是否可以轻松地与专家分享“实时”预测,以收集更多训练示例?
我们能否在不将生产数据持续转移到数据收集和标记阶段的情况下测量生产精度?
我们能否直接从最终用户那里无缝收集反馈?
所有上述问题都有一个潜在的主题:为基于人工智能的解决方案管理数据的角色、工具和过程之间的摩擦。
在 Recognai,自从四年前我们开始与客户合作企业 NLP 项目以来,我们就遭受了这些摩擦。我们开发了内部和开源工具来帮助我们更好地支持我们的客户。但是有一些东西我们一直在构建、重建和重新思考:一个连接模型、数据和参与项目的人的工具,这样他们都可以在过程的任何一步为改进数据做出贡献。
在围绕这个想法进行了多次迭代之后,我们终于高兴地分享了 Rubrix ,一个免费开源的https://github.com/recognai/rubrix/,人工智能项目的人在回路工具。
红框是:
- 一个 Python 库使数据科学家、数据工程师和 ML 工程师能够在数据、模型和用户之间建立桥梁,用于数据收集、模型开发、测试、 部署和监控。
- 一个网络应用**,用于在整个项目工作流程中探索、管理和标记数据。**
- 一个开放 API** ,用于存储、检索和搜索人类注释和模型预测。**
Rubrix 和相关的生命周期活动(作者图片)
Rubrix 可以安装pip
:
pip install rubrix
唯一的非 Python 依赖项是 Elasticsearch。您可以使用 Docker 和docker-compose
来启动它,或者使用现有的 Elasticsearch 实例。
要获得更详细的设置指南,请查看 Rubrix 的指南,但是如果你渴望尝试它并且熟悉 Docker:
下载docker-compose.yml
并启动 Rubrix 服务器和 Elasticsearch:
mkdir rubrix && cd rubrix
wget -O docker-compose.yml [https://git.io/rb-docker](https://git.io/rb-docker) && docker-compose up
现在,在进入更多的细节之前,让我们先来看看 Rubrix 是如何工作的!
以下代码从 Hugging Face hub、 AG 新闻数据集(一个众所周知的文本分类基准)加载一个零镜头文本分类器,并使用 Rubrix 存储预测和人工标注的标签:
AGNews 数据集上的 Rubrix 日志零炮预测
就是这样!您和您团队的其他成员现在可以探索这个分类器如何在一个看不见的数据集上工作:
带有 AGNews 数据集和零炮预测的 Rubrix 探索模式(图片由作者提供)
根据带标签的数据集探索模型预测,这只是您可以使用 Rubrix 做的许多事情中的一件,因为在“现实生活”中,有时您没有开始的标签,或者您没有模型,或者您只想在开始训练您的第一个模型时查看您的数据。模型开发是 Rubrix 最初的设计用途之一。
Andrej Karpathy 的这条推文总结了尽早查看数据的全部要点。
关于管理数据对人工智能的重要性,另一个伟大的灵感来自文森特·d·沃默达姆,他是 Rasa 的研究倡导者,也是令人惊叹的 calmcode.io 和 human-learn 等库的创造者:
以零触发分类器结束我们的第一个例子,让我们看看 Rubrix 的另一个有趣的用例:模型监控和可观察性。如果你对模特监测感兴趣,我强烈推荐你这篇来自本·洛里卡和帕科·内森的 文章 。正如我上面提到的,Rubrix 与 Elasticsearch 堆栈紧密集成。由于 Kibana 的易用性和 Rubrix 的数据模型,在 Rubrix 数据集的基础上构建自定义仪表板轻而易举。这是我们在 Jupyter 笔记本中记录零炮预测时实时仪表盘的样子:
自定义监控仪表板,带有红色字体和基巴纳字体(图片由作者提供
回到我们为什么构建 Rubrix,让我们介绍一下 Rubrix 指导原则:
1.没有人应该被迫改变他们的工作流程来为项目做贡献。
对于数据科学家来说,这个原则意味着 Rubrix 不会要求他们离开他们喜欢的工具,如 Jupyter Lab 或 Colab,来扩展任何类或围绕任何新的抽象包装他们的模型。
**对于数据和 ML 工程师来说,这意味着 Rubrix 为读写(大量)数据提供了简单而有效的方法。我们设计了易于在自动化脚本中使用的 Rubrix。
**对于业务和主题专家来说,这意味着一个干净且易于使用的用户界面,在这里他们可以感觉到控制,并且可以透明地检查数据和模型预测。
我们为提高透明度和信任度而感到兴奋的另一个用例是与 Kibana 仪表板配套的 Rubrix 中的模型可解释性**。**
这里有一个 Rubrix 数据集的例子,它包括使用集成梯度方法提取的情感分类器的令牌级属性,使用变压器解释和 captum.ai 库。
Rubrix 提供了一个不可知的数据模型,所以你可以使用其他库和技术,比如 Lime。
探索带有模型解释的情感分类器预测
基巴纳对积极情绪标签的平均表征归因分数的自定义可视化(图片由作者提供)
下面是记录预测和令牌属性的代码:
2.API 应该对每个人都足够简单,同时支持复杂的工作流。
****数据模型符合这个简短的描述:
数据集是记录的集合,其形状由任务(例如文本分类)定义。
****快照是用于再现性和自动化管道的数据集的存储版本。
一个记录由它的输入定义,并且可选地包含注释、预测、和元数据。****
注释通常是由人类代理为给定的任务和输入定义的基本事实。
预测通常来自来自机器代理(例如文本分类器的输出)。
在这个小图表中:
Rubrix 数据模型(图片作者)
让我们看看如何为 NER(命名实体识别)创建和记录一个记录**,这是一个广为人知的 NLP 任务:**
上面的代码使用 rb.log 方法记录了一个带有歌曲和乐队标签的 NER 示例,如果数据集不存在,它也会创建一个数据集。数据集是增量的,您可以使用 rb.log 来批量记录大型数据集(正如我们在监控示例中看到的)。这是该记录在 web 应用程序中的外观:
红色字体中的 NER 探险景观(图片由作者提供)
Rubrix 只需要调用两个主要的方法**:**
- rb.log(records,name) 将记录存储到一个 Rubrix 数据集中。
- rb.load(name) 将记录从 Rubrix 数据集中读入 Pandas 数据帧。
为了理解这两种方法支持的工作流类型,让我们看一个加载 Rubrix 数据集以微调预训练模型的示例。我们将遵循指南"微调预训练模型"从拥抱脸。
工作流程如下:
1 -我们已经使用 rb.log 创建了一个具有零命中率预测的 Rubrix 数据集,并且我们已经花了一些时间使用 Rubrix web-app 注释模式来手动标记一些示例。这和之前的例子是一样的,但是在这个例子中我们没有任何先验标签。
具有零触发预测的数据集中的红框注释模式(图片由作者提供)
2——在花了一些时间进行注释之后,我们准备好使用 rb.load 并准备好我们的数据集来微调模型。通常,我们会将其分为训练、测试和验证,但是让我们尽可能简单地描述这个例子:
3 -从这一点开始,只是按照指南中的描述对训练器 API 进行常规微调。请注意,我们使用的是无壳蒸馏器而不是有壳蒸馏器
如果您对此感兴趣,您可以:
- 阅读更多关于 Rubrix 的数据模型和 Python API 参考的信息。
- 查看我们的深入教程,了解如何将 Rubrix 与🤗转换器和数据集。
3.拥抱与其他工具、库和框架的集成。
我们生活在一个激动人心的时代,每个月都有新的库和工具发布。人们对用于不同事情的许多工具感到舒适,例如数据注释,或者模型实验跟踪,我们想要拥抱这种多样性。
Rubrix 不是一个全有或全无的工具或平台,我们的目标是让用户能够构建新颖的工作流,并将 Rubrix 与他们选择的工具相结合。这就是为什么,除了 Python 库和 web 应用程序,我们还为开发人员设计了一个开放的 REST API。
此外,为了激发你的想象力和创造力,请查看 Rubrix 的文档:
- 将 Rubrix 整合到 Streamlit 应用的指南,
- 一个使用 Rubrix 和通气管弱监控的教程
- 食谱提供了将 Rubrix 用于主要 NLP 库的代码片段,如我们喜爱的斯坦福大学的 spaCy、Flair 或 Stanza。
- 用 scikit-learn 和 ModAL 进行主动学习的基础教程。
4.提供一个最小的特性集,让社区来指导接下来的工作。
你可能已经注意到,我一直在谈论人工智能项目,但我们只看到了自然语言处理的例子。原因很简单:自然语言处理和知识图用例一直是 Rubrix 在 Recognai 开发的原始驱动力。然而,Rubrix 的数据模型和架构旨在轻松添加新的用例和应用程序。Rubrix 涵盖了广泛的 NLP 和知识图应用,只支持两个任务,文本分类和标记分类。
对于知识图用例,可以使用令人惊叹的 kglab 和 PyTorch 几何库和 Rubrix 随意查看节点分类教程。
我们设想的直接用例是 t ext2text ,它将涵盖许多其他 NLP 应用,如文本摘要或机器翻译;计算机视觉任务如图像分类;以及语音识别任务如 speech2text 。但在此之前,我们想听听你的声音。
这就是为什么我们很高兴宣布 Rubrix,这样你就可以成为一个开放友好的社区的一部分,并推动接下来的发展。
如果你想加入 Rubrix 社区或谈论你的即时和预想的应用,请在 Rubrix 的 Github 的论坛上给我们留言。
“我打这个号码
是为了约会
我不知道该做什么
我需要约会”发电厂乐团的《计算机之恋》,1981 年
感谢
感谢 Paco Nathan、Amélie Viallet、David Carreto、Ignacio 塔拉贝拉和 Francisco Aranda 为改进本文提供的巨大帮助和建议。
脚注
- 如果你不熟悉人在回路的概念,我强烈推荐你斯坦福大学以人为中心的人工智能研究所的这篇文章。
数字广播
原文:https://towardsdatascience.com/broadcasting-in-numpy-58856f926d73?source=collection_archive---------28-----------------------
理解 NumPy、PyTorch 和 TensorFlow 的关键概念之一
图片来源:作者
广播是一种匹配不同形状的数组的维数的操作,以便能够对这些数组执行进一步的操作(例如每元素算术)。
一个非常强大的功能,但是文档有些不足。通常,当数组大小不匹配时,人们会从错误消息中了解到这一点。
最简单的广播示例是 n 维数组乘以标量,这显然意味着每个元素的元素乘以标量值:
广播类似于众所周知的“类型提升”:在大多数语言中,当添加一个整数和一个浮点时,整数首先被自动转换为浮点类型。
在 2D(例如用向量除一个矩阵)中,广播有点棘手,因为运算的结果取决于操作数的特定形状:
所有这些形状变化(灰色数字)都是动态发生的,不占用额外的内存(也称为视图)。
在 3D 及以上版本中,广播甚至更不直观,使用它需要了解广播规则的一般形式。它们在不同的来源中以略微不同的方式表述,确切的措辞也随着时间而改变。我发现来自 Python 数据科学手册 的三步法则是最全面的:
规则 1:如果两个数组在维数上不同,维数较少的那个数组的形状在它的前(左)侧用 1 填充*。*
规则 2:如果两个数组的形状在任何维度上都不匹配,则在该维度中形状等于 1 的数组将被拉伸以匹配另一个形状。
规则 3:如果在任何维度中,尺寸不一致并且都不等于 1,则产生错误。
拉伸意味着相应的层被复制:
将彩色图像转换为灰度图像是 3D 广播的一个很好的例子。根据 sRGB 颜色空间的公式,可以通过图像颜色通道的线性组合获得亮度:
使用广播,这可以简单地写成
其中im
是具有标准索引顺序的图像,例如 if im.shape == (1080, 1920, 3)
then gray.shape == (1080, 1920)
其中 1080 是图像的高度,1920 是其宽度,3 是色彩平面(RGB)的数量。完整示例:
图片来源:openastronomy.org
有一个专门的函数np.[broadcast](https://numpy.org/doc/stable/user/basics.broadcasting.html)
返回一个生成器对象
虽然广播很少被明确地完成(因为循环将在 python 中执行,这比在 C 中慢)。通常它发生在“幕后”。
但是广播并不局限于算术运算。更多用法示例见我的文章“ Numpy Illustrated ⁴”
广播最初是在 1995-1999 年左右在 NumPy 的前身 Numeric⁵图书馆引入的,被 PyTorch 、 TensorFlow 、 Keras 等采用。甚至 Matlab 在 2016b 中加了感谢“这些年来要求这种行为”的用户。
参考文献
- 杰克·范德普拉斯。Python 数据科学手册,数组计算:广播
- 维基百科。灰度
- NumPy 文档。广播
- 列夫·马克西莫夫(2020)。 Numpy 图解:Numpy 视觉指南
- 大卫·阿谢尔;保罗·迪布瓦;康拉德·欣森;吉姆·胡古宁;特拉维斯·奥列芬特(1999)。《数值 Python》
布朗洛奖章预测者
原文:https://towardsdatascience.com/brownlow-medal-predictor-36586d535226?source=collection_archive---------28-----------------------
使用数据驱动方法预测美国橄榄球联盟布朗洛奖章投票数
Ruck 竞赛。图片由教皇, CC BY-SA 4.0 ,通过维基共享
布朗洛奖章(Brownlow Medal)被授予由裁判决定的 AFL 在主客场赛季中“最佳和最公平”的球员。每场比赛结束后,三名现场裁判分别给比赛中第一、第二和第三名的选手 3、2 和 1 票。在颁奖之夜,每场比赛的投票都被记录下来,根据资格,获得最高票数的选手将被授予奖牌。
由于集体裁判意见中“最佳和最公平”定义的主观性,预测布朗洛奖牌获得者具有挑战性,这可能会受到公众舆论的影响。此外,一些球员更有可能在视野之内——中场球员在历史上赢得了绝大部分的选票。
此分析的目的是了解有助于布朗洛投票的玩家行为的关键可量化预测因素,并建立一个合理的预测模型,为整个赛季的下注策略奠定基础。
基线模型概述
基线模型的目标是勾勒出一个框架,从这个框架中可以改进模型的未来迭代。
性能测量我们将基线模型的性能评估测量定义为实际投票与预测投票的均方根误差(RMSE );这种方法根据与实际观测的距离非线性地惩罚预测。
数据数据集包括来自菲茨罗伊数据包的 2012-2021 赛季约 85,000 行球员比赛统计数据。2021 赛季的数据已经被预留出来作为预测的测试数据集。
预处理数据经历如下所述的一些转换。
- 玩家投票是基于每场比赛分配的——这需要对每场比赛的玩家统计数据进行标准化——因此可以根据天气、场地等因素的预期变化进行调整。这一过程也自然地为缩短了游戏时间的 2020 赛季进行了调整。
- 我们最初还以 4:1 的比例平衡职业,以确保训练数据不会过度偏向没有获得投票的玩家。
学习算法底层学习算法是一个基于树的分类框架(xgboost ),它在玩家匹配的基础上为投票计数生成概率和预期类别。该模型仅使用数字变量,并经过交叉验证。
每场比赛只能分配三张选票,这使得这成为一个分类问题,我们需要用概率来理解预测,并能够辨别 2 票对 3 票游戏之间的质量差异。
该模型是堆叠的,它依次计算 0-3 票的条件概率,而不是一个多类分类问题。为简单起见,我们将各个模型标记为概率 B1、概率 B2、概率 B3,以分别表示获得至少 1、2 和 3 票的概率。
这允许我们使用迁移学习——先前迭代的结果成为后续模型的输入。
模型结果:可变重要性
可变重要性允许我们识别和解决可能降低模型预测质量的问题。有 50 多个可能的预测变量。
为了建立一个不会过度处理问题的稳健模型,我们希望在最终模型增加复杂性之前,先减少预测因子的数量。
prob_B1 模型的可变重要性(图片由作者提供)
上面的图表让我们第一次很好地了解了在 prob_B1 模型中,当玩家至少获得一票时,哪些变量的贡献最大。最初的想法-
- 前 4 个变量是其他统计数据的线性组合,特别是梦之队积分和排名积分是常用的衡量球员表现的综合统计数据。
- 处置比全部财产稍微重要一些;对投篮得分的贡献。
- “有效”变量与原始总数非常相似,但是在变量重要性方面排名较低,这意味着裁判员在场上没有完全量化处理的质量。
因此,在模型的下一次迭代中,我们将从数据集中删除线性组合以及高度相关的变量。
最后一个条件模型(prob_B3)的变量重要性图表显示,先前模型的条件概率在对最终预测的贡献方面排名很高。
概率 B3 模型的可变重要性(图片由作者提供)
整体精度
输出是一系列条件概率,其中整个数据集的分类精度在 2–5%的数量级。2020 年第一场比赛(RI v CA)的选定球员的原始条件概率如下。
2020 年第一轮选定球员的条件概率结果(里士满对卡尔顿)
- 初始模型结果是匹配不可知的,因此它们不认为给定匹配内的概率之和对于概率 B1、概率 B2、概率 B3 模型中的每一个应该分别等于 1、2、3;因此,我们需要在匹配的基础上使结果正常化。
- 此外,我们还想对结果进行归一化处理,使单个玩家级别上的概率总和等于 1。
归一化过程的结果如下所示(注意,由于四舍五入,一些总概率不完全是 1)。
2020 年第一轮(里士满对卡尔顿)选定球员的标准化概率
在纯概率基础上目测结果,我们看到该模型正确地建议了 Dion Prestia (3 票)的结果,但与 Dustin Martin、Jack Martin 和 Patrick Cripps 的 1 票和 2 票类别混淆了。
根据标准化的概率,我们将它们转换成预测的投票数。考虑了两种方法,一种是原始值,另一种是原始值的排序。在这两种情况下,我们确保每场比赛分配的总票数必须始终加起来正好是 6。
概率到投票的转换(加权和类别)
同样,Jack Martin 没有获得任何投票,而 Dustin Martin 在我们的模型中获得了 1 票(实际上是 2 票),我们保留这个离群值的示例,作为在基线模型的后续迭代中进行改进的机会。
ESPN 的一篇文章描述了另一种分配投票的方法,该文章提出,3、2.5、1.5 或 0.5 的投票分配方法会导致更低的误差幅度。我们将在未来的研究中调查这种配置。
赛季末的准确性
我们承认可能存在总体不准确,但这项工作的目标是在(1)季末水平和(2)逐轮汇总水平达到合理的准确性。
每种预测方法的准确性通过实际投票与按季节预测的投票以及整个训练集的均方根绝对误差(RMSE)来衡量。
不同季节的模型精确度
虽然分级分类法似乎比原始值法更好,但平均法更胜一筹。下图显示了 2020 赛季前 15 名竞争者的最终预测结果。
2020 赛季实际投票和预测投票(图片由作者提供)
在上面的图表中,有几件事很突出—
- 目测显示,pred-votes 方法通常会低估投票数,而 pred-class 方法则更加平衡。总的来说,平均模型在获得正确的最终预测顺序方面做得很好。
- 2020 年,拉奇·尼尔、扎克·梅里特和泰勒·亚当斯是一个典型的异类。
逐轮汇总的精确度
下面的图表让我们可以更详细地分析每一轮比赛,并随着赛季的进行,对预期的误差有一些信心。对前 8 名竞争者的结果进行了更详细的分析。
2020 赛季绩效指标(图片由作者提供)
从表面上看,随着赛季的发展,基线模型通常可以在样本中产生合理的预测,误差在 1-2 票以内。
出样模型精度
2021 年的数据是样本外的,因此预计预测不如 2020 年准确,因为 2020 年在训练集中。在训练集中,最后一轮的 RMSE 是 0.9,而在样本外的 2021 数据中,RMSE 是 3.3。
2021 赛季实际和预测投票(图片由作者提供)
- 2021 年值得注意的异常值是马库斯·邦滕佩里、达西·帕里什和萨姆·沃尔什,他们的结果都被模型低估了。
- 托克·米勒是一个因为赛季中的停赛而没有资格获得布朗洛的球员的例子——如果他在随后的比赛中被裁判无意地否决,那么调查他将会很有趣。
2021 赛季前 8 名布朗洛奖牌获得者的道路(作者图片)
对此可能的解释是我们最初的模型中没有考虑到的因素-
- “可见性”因素,可见性可以通过身体特征来定义——纹身、发色、身高——这使得球员更容易被注意到或记住(被裁判)。
- 影响因子,一些球员对比赛结果的影响可能比原始统计数据(如处置)实际显示的影响更大。
- “浮华”的因素,一些球员在包的外面走得更快,或者在包的里面更有统治力。
- 媒体对裁判判罚的影响;有些球员比其他人更“受人喜爱”。
现在,评估模型质量的框架已经到位,我们现在可以在迄今所学的基础上进一步改进预测模型。
反思和后续步骤
我们可以通过将基线模型输出与 2021 年样本数据中的几个公共模型进行比较,对我们的结果质量进行基准测试——仍然需要砍伐,但肯定不是最不准确的!
专家同行的 2021 赛季基准模型-球员投票和最终排名
练习的下一阶段基于布朗洛预测器的结果构建成一种形式,该形式可用作逐轮投注策略的基础,从中我们可以监控 2022 赛季的实况结果。然后,我们将回到我们的关键学习,以提高预测模型的准确性。
参考文献
- 维基百科—布朗洛奖章(链接)
- ESPN 的布朗洛奖章获得者,每一票都投给 2021 ( 链接)
- AFL.com.au:布朗洛的内幕:每个俱乐部的最爱,一票奇迹,前三名(链接)
- AFL.com.au:禁赛:34 名球员没有资格参加布朗洛(链接)
- Foxsports.com.au:布朗洛奖牌预览:统计数据证明谁将赢得近年来最接近的比赛和价值选择(链接)
- 先驱太阳报:冠军数据布朗洛追踪者:前 20 名选手揭晓(链接)
- Betfair.com.au:2021 年布朗洛奖牌预测(链接)
- 菲茨罗伊简介(链接)
基于浏览器的数据库客户端
原文:https://towardsdatascience.com/browser-based-database-clients-5ff927c4cb5d?source=collection_archive---------19-----------------------
照片由 Fotis Fotopoulos 在 Unsplash 上拍摄
数据工程
远离基于桌面的数据库客户端
背景
从十多年前的大学时代,当我的数据库实验室讲师给了我一张 Oracle 11g 数据库的 CD,让我安装在系统上,到今天,当我可以用一个简单的 CLI 命令启动一个数据库实例,我们已经取得了很大的进步。随着数据库从内部迁移到云,数据库客户端也从桌面或 Mac 应用程序迁移到浏览器。这种转变不明显地与使用 Docker 等易于使用的虚拟化工具向平台独立性的转变完全一致。
随着数据工作成为后衰退十年科技繁荣的核心,数据库和数据仓库工具也经历了巨大的创新,导致了工程师现在日常使用的工具。这直接导致了 SaaS 上市的全面繁荣。虽然有点晚,但这种影响也影响到了数据库客户机,导致了基于浏览器的 SQL 客户机的上升趋势。本文将讨论一些流行的基于浏览器的数据库客户机,以及为什么它们在未来几年会越来越流行。
云服务集成客户端
基于云的数据库和数据仓库服务,比如 Amazon RDS、Azure Synapse、Google BigQuery、Snowflake 等等,提供了一个基于浏览器的客户端,可以用来与数据库进行交互。除了 Snowflake 之外,大多数集成的 SQL 客户端功能不够丰富,也不够成熟。例如,语法突出显示、命名实施、数据管理工具等。,受限于这些集成客户端。
由于这些集成客户机的有限特性所带来的不便,工程师们经常转向使用成熟的数据库客户机应用程序作为他们的 IDE。
**T5 桌面客户端 **
毫无疑问,DataGrip、MySQL Workbench、dBeaver、Oracle SQL Developer 等应用程序提供的功能比基于浏览器的客户端提供的功能更重要,但大多数高级功能(如逆向工程、备份和恢复等。)对数据库开发人员和数据仓库工程师更有用,而不是对数据分析师、ML 工程师、数据科学家和其他业务用户。
基于浏览器的客户端
为了使工程师和业务用户的生活更加轻松,使用一个更全面、功能更丰富、基于浏览器的工具来实现一致的开发体验以及更好的 SQL 查询共享和协作功能更有意义。基于浏览器的数据库客户端经常会创新并演变成成熟的 BI 工具。许多基于浏览器的数据库客户端如 JackDB 是专有的 SaaS 工具,而其他如 Superset 是 OSS 项目,每个人都可以免费使用。
探索和可视化工具或数据库客户端的选择取决于目的。业务用户需要从数据库和仓库中获取数据,以探索和总结数据;他们还经常需要想象和讲述一个故事。根据需求,有几种不同类别的基于浏览器的数据库客户机。现在让我们简单看一下这些类别。
笔记本风格的数据库客户端
分析师和企业用户喜欢笔记本电脑。受 Jupyter 和 Zeppelin 的 Spark、Python 和 R 代码笔记本的启发,SQL 的神奇语法也在几年前随着 CloudySQL 和 iPython-sql 引入。像 Count.co这样的产品已经开发了一个完全成熟的笔记本电脑,专门为 SQL 开发,并将其提升到一个新的水平。几个月前我试用了这款笔记本。界面看起来是这样的:
图片作者。请不要被触发,因为我没有使用大写的 SQL 关键字。谢谢大家!
正如您所看到的,它非常类似于 Jupyter 笔记本,只是它在视觉上更具吸引力,并且像普通的数据库客户端一样支持数据库连接。它还支持分叉和版本控制,如上所示。
像 Count.co 一样,市场上也有其他笔记本。选择通常取决于您使用的技术。例如,Databricks 的 SQL 笔记本集成了 charing 库。类似地,您可以在 Azure Data Studio 中使用 SQL 内核。让我留给你一个不太受欢迎的 SQL 笔记本,由 HVF 实验室制造。
图片作者。摘自这个开源项目 (MIT 许可)。
https://datasciencenotebook.org/
像 Count、Databricks 和 Franchise 这样的笔记本可以有一些集成的图表和可视化库。但是,它们对于构建报告和仪表板并不理想。这就是我们进入一个完全独立的领域。在您继续之前,请查看上面的链接。这是对当今市场上从 Jupyter 到 Deepnote 的所有数据科学笔记本的一个很好的总结。
具有 BI 功能的数据库客户端
大多数人不会把我将要谈到的三个工具看作数据库客户机。 Redash 、元数据库和超集。相反,他们将这些工具称为 BI 工具。虽然这些工具很少用于企业级 BI 报告和仪表板,但我认为将它们视为全面的 BI 工具是公平的,因为它们确实拥有 BI 工具中需要的所有东西。只是随着大量的钱流入到像 Tableau 或 Looker 这样的东西中,OSS 社区的进步并没有那么快。
https://stackshare.io/stackups/metabase-vs-redash-vs-superset
在过去的五年中,我广泛地使用了这三个工具,主要用于数据探索、查询编写和报告调度(读取 CSV 转储调度)。我目前正在为一个项目使用超集,我喜欢它。访问这个链接,你会对这些工具的可视化能力有一个很好的了解。
其他数据库客户端
其他一些数据库客户机既不属于笔记本类,也不属于 BI 工具类,这意味着它们更适合 SQL 开发,而不是数据探索和可视化。 SQLPad 、 PopSQL 、 JackDB 都是比较流行的。有时,当您的唯一目标是编写 SQL 查询并以表格格式、线形图或条形图查看结果时,您不需要一整套不必要的功能。
我需要单独提一下修图。这是另一个怪物。它不仅仅是一个数据库客户端,不仅仅是一个笔记本。这个要复杂得多,是为开发人员设计的,而不是数据科学家和分析师。不过,开发人员可以使用 Retool 来满足数据科学家和分析师的需求。
虽然 VSCode 是一个桌面应用程序,但我需要为它提供支持数据库客户端扩展的强大支持,不管它们可能多么基础。VSCode 很棒,因为您无论如何都会将它用于其他目的。如果它带有数据库客户端扩展。太好了。
结论
基于浏览器的数据库客户端、笔记本电脑和 BI 工具是未来的趋势。留意像 Superset 这样令人惊奇的 OSS 项目。您可能会在下一个数据作业中使用一个或多个这样的工具。
我很快会写我最常读的作品之一的续集,其中我将涵盖数据工程师、数据科学家和数据分析师的基本堆栈。如果你觉得我的文章有用,请订阅并查看我的文章🌲Linktree。你也可以考虑用我的推荐链接购买一个中级会员来支持我。干杯!
https://kovidrathee.medium.com/membership
BSTS 和因果影响:通过网页浏览量分析戴尔 XPS 笔记本电脑的受欢迎程度
原文:https://towardsdatascience.com/bsts-and-causalimpact-analysing-dell-xps-laptop-popularity-by-web-page-views-30015c2456f?source=collection_archive---------26-----------------------
新冠肺炎消费者对 Dell XPS 笔记本电脑的兴趣如何?
来源:图片由Clker-Free-Vector-Images/29580 Images来自 Pixabay
免责声明:本文是在“原样”的基础上编写的,没有担保。它旨在提供数据科学概念的概述,不应被解释为专业建议。本文中的发现和解释仅是作者的,不支持或隶属于本文中提到的任何第三方。这篇文章不是为了推销任何特定的公司或产品。
背景
2020 年 2 月, Forrester 预测,由于新冠肺炎,对包括计算机和通信设备在内的硬件的需求将非常疲软,因为在经济活动疲软期间,消费者往往会推迟对硬件的资本投资,而软件和云服务将继续蓬勃发展。
其中一个原因是,与软件和云服务相比,硬件通常需要更多的前期投资。因此,经济活动疲软的时期会诱使消费者和企业推迟购买硬件,直到经济状况再次好转。
确定消费者对特定产品范围的兴趣的一种方法是通过分析网页浏览量,例如,某个特定的硬件或软件产品在规定的时间内有多少网页浏览量?
业务场景
戴尔 XPS 是一个面向高端市场的高品质笔记本电脑品牌。笔记本电脑在数据科学家中也很受欢迎(我自己就用一台)。
**现在,让我们考虑一下这个场景。**假设戴尔希望确定消费者对 XPS 笔记本电脑的兴趣是否因疫情的经济影响而降低。
在这种情况下,我们如何衡量消费者的兴趣?除了查看销售数字,一种可能是查看搜索术语**“Dell XPS”**的网页浏览量。
事实上,这甚至可能是更可取的,因为人们应该考虑到消费者推迟支出但仍在考虑最终购买该品牌笔记本电脑的可能性,这将反映在页面浏览量保持在与以前类似的水平上。
虽然很容易简单地观察 2020 年 3 月前后网页浏览量的变化,但这并不一定能说明全部情况。
例如,如果没有发生疫情,我们无法确切知道页面浏览量会是什么样子。
在这方面,以下分析将利用以下方法:
- 使用 BSTS (贝叶斯结构时间序列建模)包从 R 到样本从后验分布
- 使用因果影响来尝试计算如果新冠肺炎事件没有发生,网页浏览水平会是什么样
网页浏览量数据来自 pageviews.toolforge.org,它允许对整个维基媒体基金会的特定搜索词的网页浏览量进行分析。
具体来说,从 2015 年 7 月到 2021 年 3 月,检查了搜索词“戴尔 XPS”的页面浏览量。当使用 CausalImpact 软件包建模时,还会在同一时间段内分析搜索词“VMware Workstation”的页面浏览量,并将其用作控制序列— VMware Workstation 是一种虚拟机管理程序,允许在一台 Windows 或 Linux PC 上设置多个操作系统。
假设软件产品受疫情经济衰退的影响较小,如果经济因素没有显著变化,消费者对戴尔 XPS 和 VMware Workstation 的兴趣比较可能会更好地概括消费者对戴尔 XPS 产品的兴趣水平。
BSTS
以下是指定时间段内“戴尔 XPS”页面浏览量的图示:
来源:RStudio 输出
我们可以看到,在第 1700 天之后——这大约是新冠肺炎疫情在 2020 年 3 月开始站稳脚跟的时候——我们可以看到页面浏览量呈下降趋势。然而,还不清楚这是最近事件的直接结果,还是随机波动的结果。
使用 BSTS 的目的是基于来自后验分布的 MCMC(马尔可夫链蒙特卡罗)采样来量化潜在页面浏览量水平的范围。与其直截了当地预测页面浏览量接下来会如何,我们可以根据后验分布观察到的潜在范围是什么?
页面视图数据以 CSV 格式加载到 R 中。为了让 BSTS 正确解释数据,数据帧随后被转换为 xts 格式:
mydata<-read.csv("dellxps.csv")library("xts")
mydata$my_dates <- as.Date(mydata$Date)
mydata <- xts(mydata$Dell.XPS, mydata$my_dates)
现在,BSTS 模型被具体化了。在这种情况下,考虑到网页浏览数据固有的易失性,在这种情况下,只有localineartrend将被建模。
执行 1000 次迭代,并绘制模型组件。
library(bsts)
ss <- AddLocalLinearTrend(list(), mydata)model <- bsts(mydata, state.specification = ss, niter = 1000)plot(model)
plot(model, "components")
这是趋势和生成的分布,后者显示了在特定时间点可能观察到的潜在结果的范围:
趋势
来源:RStudio 输出
分配
来源:RStudio 输出
现在,让我们进行一些预测。对未来 15 个时间段进行预测,目的是生成一系列在此时间段内可以观察到的潜在页面浏览量。
pred <- predict(model, horizon = 15, burn = 100)
pred
plot(pred)
来源:RStudio 输出
从上面可以明显看出,BSTS 预测了在选定时期内网页浏览量的一系列结果。提供了平均值、中间值和区间预测。在这个范围的最极端,BSTS 模型预测页面浏览量可能低至 144 或高达 690。
> pred$mean
[1] 418.5689 420.4969 419.4255 418.6695 415.5628
[6] 413.9601 413.5601 414.8989 415.8069 416.0139
[11] 415.7935 413.9589 408.6109 410.5100 411.8946$median
[1] 417.8570 417.9747 419.1763 418.3281 417.6503
[6] 414.5861 418.8882 415.3306 417.3510 413.3739
[11] 417.3411 407.7334 411.0777 411.6520 411.1981$interval
[,1] [,2] [,3] [,4] [,5]
2.5% 288.8354 285.9850 275.0117 254.0120 248.9270
97.5% 542.8098 565.5993 567.6804 591.9176 580.5002
[,6] [,7] [,8] [,9] [,10]
2.5% 221.8867 208.5441 210.8201 198.3210 195.1280
97.5% 596.5839 608.9127 613.7725 615.1689 640.2005
[,11] [,12] [,13] [,14] [,15]
2.5% 182.5640 174.2203 141.7563 143.3177 144.2848
97.5% 648.4422 650.0539 642.7709 694.1793 690.8501
在整个时间序列中观察到的每天 471 次页面浏览的总体平均值,预测平均值明显低于平均值。然而,由于页面浏览量中存在大量“峰值”,平均值出现了明显的偏差。如果没有这些异常值,平均水平可能更接近于 BSTS 计算的水平。
因果影响
如前所述,时间序列分析的一个缺点是,在没有干预的情况下,不可能分析时间序列的变动。
换句话说,假设新冠肺炎的经济衰退导致硬件更换周期延长,那么如果新冠肺炎事件没有发生,消费者对戴尔 XPS 系列的兴趣会有多大是不可能的。
我们最接近这样做的方法是通过分析时间序列和没有受到干预影响的控制序列。同样,假设软件的更换周期不会受到最近事件的影响,VMware Workstation 的网页浏览量用作控制系列。
为了消除异常,两个系列都用对数格式表示。
因果影响用于分析前期和后期,如下所示:
pre.period <- c(1, 1705)
post.period <- c(1706, 2101)impact <- CausalImpact(data, pre.period, post.period)
plot(impact)summary(impact)
summary(impact, "report")impact$summary
以下是后验推断结果:
> summary(impact)
Posterior inference {CausalImpact}Average
Actual 6.3
Prediction (s.d.) 6.1 (0.45)
95% CI [5.2, 6.9]
Absolute effect (s.d.) 0.19 (0.45)
95% CI [-0.63, 1.1]
Relative effect (s.d.) 3.1% (7.4%)
95% CI [-10%, 17%]
Cumulative
Actual 2495.5
Prediction (s.d.) 2421.4 (178.46)
95% CI [2078.2, 2745.2]
Absolute effect (s.d.) 74.13 (178.46)
95% CI [-249.67, 417.3]
Relative effect (s.d.) 3.1% (7.4%)
95% CI [-10%, 17%]Posterior tail-area probability p: 0.34393
Posterior prob. of a causal effect: 66%For more details, type: summary(impact, "report")
在这种情况下,与预测的 6.1 相比,戴尔 XPS 的实际网页浏览量在 6.3 时实际高于预期(均以对数格式表示)。因果效应的后验概率为 66%。
让我们阅读由 CausalImpact 生成的扩展摘要。
> summary(impact, "report")
Analysis report {CausalImpact}During the post-intervention period, the response variable had an average value of approx. 6.30\. In the absence of an intervention, we would have expected an average response of 6.11\. The 95% interval of this counterfactual prediction is [5.25, 6.93]. Subtracting this prediction from the observed response yields an estimate of the causal effect the intervention had on the response variable. This effect is 0.19 with a 95% interval of [-0.63, 1.05]. For a discussion of the significance of this effect, see below.Summing up the individual data points during the post-intervention period (which can only sometimes be meaningfully interpreted), the response variable had an overall value of 2.50K. Had the intervention not taken place, we would have expected a sum of 2.42K. The 95% interval of this prediction is [2.08K, 2.75K].The above results are given in terms of absolute numbers. In relative terms, the response variable showed an increase of +3%. The 95% interval of this percentage is [-10%, +17%].This means that, although the intervention appears to have caused a positive effect, this effect is not statistically significant when considering the entire post-intervention period as a whole. Individual days or shorter stretches within the intervention period may of course still have had a significant effect, as indicated whenever the lower limit of the impact time series (lower plot) was above zero. The apparent effect could be the result of random fluctuations that are unrelated to the intervention. This is often the case when the intervention period is very long and includes much of the time when the effect has already worn off. It can also be the case when the intervention period is too short to distinguish the signal from the noise. Finally, failing to find a significant effect can happen when there are not enough control variables or when these variables do not correlate well with the response variable during the learning period.The probability of obtaining this effect by chance is p = 0.344\. This means the effect may be spurious and would generally not be considered statistically significant.
最终,分析得出的平均值高于预测值,但不具有统计学意义,即可能是偶然获得的。
这也可能意味着干预期比预期的要短——即新冠肺炎对硬件市场的任何可能的经济影响都是短暂的。
最终,BSTS 和 CausalImpact 的分析未能证明过去一年对戴尔 XPS 的兴趣受到了负面影响。
限制
当然,以上分析带有局限性。首先,它只是在考虑硬件市场无数产品中的一种。对其他硬件产品的兴趣可能相对下降,但对戴尔 XPS 的兴趣仍然很强。
此外,我们无法确定消费者对某个特定软件产品(在本例中为 VMware Workstation)的兴趣是否代表了整个软件市场。如果使用 CausalImpact 来比较戴尔 XPS 与另一款软件产品的页面浏览量,结果可能会有所不同。
此外,只考虑了一个干预点。2020 年 3 月—新冠肺炎被宣布为全球疫情。可能有其他重要的干预点没有被考虑,但可能仍然是重要的,例如,那些与新产品的发布、市场的新进入者等相一致的干预点。
最后,只有一个来源的网页浏览量被用作基准。有很多方法可以衡量消费者对产品的潜在兴趣,这里没有讨论。
结论
这是贝叶斯方法如何用于分析时间序列中的干预的一个例子。具体来说,您看到了如何使用 BSTS 和因果影响:
- 分析网页浏览
- 后验分布样本
- 生成后验预测
- 使用干预分析预测时间序列
在进行分析时,我们也看到了一些与贝叶斯时间序列建模相关的局限性,以及如何谨慎解释结果。
非常感谢您的宝贵时间,非常感谢您的任何问题或反馈。你也可以在 michael-grogan.com的找到更多我的数据科学内容。
参考
- bsts 功能—r 文档
- 因果影响函数—记录
- 数据黑客:R 如何将数据帧转换为 xts &动物园时间序列
- Toolforge —浏览量分析(戴尔 XPS)
- Toolforge —浏览量分析(VMware 工作站)
气泡图
原文:https://towardsdatascience.com/bubble-charts-70ef7485c51e?source=collection_archive---------27-----------------------
plotly Express vs . plotly . graph _ objects
安德鲁·伍尔夫在 Unsplash 上的照片
数据可视化
数据可视化讲故事是人类最原始的交流形式。有可追溯到公元前 44000 年的洞穴绘画,远早于公元前 3000 年的文字交流。
根据进化论,我们是视觉物种:我们进化的方式使得大量的精神资源被用于视觉感知和知识获取。比起文字,我们更注重视觉元素。
我们的大脑是一个带宽非常宽的并行图像处理器。一些数据证实了上面的说法:传输到我们大脑的信息 90%是视觉的;视觉信息传递到大脑的速度比同样的信息以文本形式传递要快 6 万倍;65%的学生是视觉学习者。
数据可视化是一种交流工具。这是讲述我们数据中的故事并将其传达给适当受众的最有力方式。但在一个充满屏幕和视觉元素的世界里,我们必须防止观众出现视觉疲劳的症状。
所以我们的图表和数字应该:视觉上有趣;展示一个清晰的故事;有可以利用的信息;有一个信息丰富的标题,清晰标注的轴,适当的图例,最好是没有不必要元素的二维图表。
当信息的本质是显示三个或更多数字变量之间的**联系或相关性时,**一个好的图表应该帮助我们找到模式,确定相关性的存在或不存在,识别异常值,并显示集群和缺口的存在。气泡图非常适合这种用途。
气泡图
气泡图用于确定至少三个数值变量 是否相关或共享某种模式。在笛卡尔坐标系中,为一对数值变量( A,B )的每次观察绘制一个气泡或圆盘,圆盘根据变量 A 的值水平放置,根据变量 B 垂直放置。第三个数值变量(C)通过气泡的区域表示。你甚至可以在不同的泡泡中使用不同的颜色加入第四个变量( D :数字或分类)。
通过这些数据点产生的形状以及气泡或圆盘相对大小的差异,讲述了三个或四个变量之间的关系,而不是它们的确切值。
在特殊情况下,它们可以用来显示一段时间内的趋势或比较分类变量。它们被认为是散点图的自然延伸,其中的点被气泡或圆盘所取代。
带有 Plotly Express 的气泡图
Plotly Express (PE)是 Plotly.py 的高级包装器,与 Plotly 生态系统的其余部分完全兼容,简单、强大,有点类似 Seaborn。它是免费的,可以用于商业应用和产品。该库包括绘制趋势线和地图的函数,以及执行刻面和动画的函数。有了 PE,你可以在线制作交互式图形,也可以离线保存。
我们使用了从 Kaggle 1下载的数据集。它属于 80 种谷类产品的营养数据。这些数据是由康奈尔大学的学生于 20 世纪 90 年代早期在当地的威格曼斯超市收集的。我们想知道《消费者报告》的评级和一些特定的营养数据(糖、钠、维生素)之间是否有关联。
首先,我们导入 Plotly Express 为 *px,*熊猫库为 pd ,并将我们的 csv 文件转换成数据帧:
import pandas as pd
import plotly.express as pxdf = pd.read_csv(path + 'cereals.csv', index_col = False,
header = 0, sep = ';', engine='python')
下面的屏幕截图显示了数据集的前十条记录:
实际的数据探索表明,我们只需使用*df.dropna(inplace = True)*
消除一些具有 N/A 值的行,数据集就可以绘制图形了。
对于本文中的气泡图,Plotly Express 函数为 *px.scatter*
,对应的参数为:*data_frame*
; x=
代表一个数值变量的数据帧中的列名;*y=*
表示另一个数值变量的数据帧中的列名;*size=*
通过气泡的区域表示第三个数值变量的数据帧中的列名。
df.dropna(inplace = True)fig0 = px.scatter(df, x = 'sugars', y = 'rating',size = 'vitamins')fig0.write_image(path + "figbubble0.png")fig0.show()
图 0:气泡图。作者用 Plotly Express 制作的图表。
毫无疑问,这不是一个有用的讲故事的合适图表。
我们认为 0 糖和 93 等级的泡沫是异常值。我们没有删除该点,而是在范围[0–80]内建立了 y 轴。此外,我们使用*px.scatter*.
中的 *color*
参数合并了第四个数值变量
我们用 *update.layout*
更新了图表:设置标题、字体大小、 模板、以及带有宽度和高度的图形尺寸。然后我们更新了 x 轴和 y 轴(文本、字体、tickfont)。我们将图表保存为静态的 png 文件,最后,我们绘制了图表。
fig1 = px.scatter(df, x = 'sugars', y = 'rating',
size = 'vitamins', color = 'sodium')fig1.update_layout(
title = "Cereals Consumer Reports Ratings ",
"title_font_size = 40,
template = 'seaborn',
width = 1600, height = 1400)fig1.update_xaxes(
title_text = 'Sugar',
title_font=dict(size=30, family='Verdana',
color='purple'),
tickfont=dict(family='Calibri', color='black',
size=25))fig1.update_yaxes(
title_text = "Rating", range = (0,80),
title_font=dict(size=30, family='Verdana',
color='orange'),
tickfont=dict(family='Calibri', color='black',
size=25)fig1.write_image(path + "figbubble1.png")
fig1.show()
图 1:一个合适的气泡图。作者用 Plotly Express 制作的图表。
图 1 清楚地显示了消费者评价和谷物含糖量之间的负相关关系。右侧的彩色垂直刻度表示钠的量(color = ‘sodium’
)。由于图表上的彩色气泡分布均匀,我们可以得出结论,钠的含量不会显著影响消费者的鉴赏能力。最后,气泡的大小与谷物中维生素的数量有关。该图显示了评级和维生素之间的零关系。
气泡图与 Plotly.graph_objects
*plotly.graph_objects*
模块包含了 Python 类的层次结构。*Figure*
是初级类。*Figure*
具有数据属性和布局属性。数据属性有 40 多个对象,每个对象引用一个特定类型的图表( trace )及其相应的参数。布局属性指定图形的整体属性(轴、标题、形状、图例等。).
使用 plotly.graph_objects 的概念是使用 .*add_trace(go.Scatter())*
创建图形,然后添加.update_layout(), .update_xaxes, .update_yaxes
等方法来操作图形。最后,我们用.write_image()
导出图形,并用.show().
渲染
注意,我们键入了带有颜色、色彩空间、不透明度、大小和其他大小参数的mode = ‘markers’
和字典。特别是,*sizeref*
属性允许缩放气泡的大小,而*colorscale*
允许显示特定的调色板。图例的文本由*name*
属性表示。
import plotly.graph_objects as go
fig2 = go.Figure()sizeref = 2.*max(df['sodium'])/(150**2)fig2.add_trace(go.Scatter(
x = df['sugars'], y = df['rating'],
mode = 'markers',
name = 'Size = vitamins * Color = sodium',
marker = dict(color = df['sodium'],
colorscale = 'portland',
opacity = 0.8,size = df['vitamins'],
sizemode = 'area', sizeref= sizeref,
sizemin= 4, showscale = True
)))fig2.update_layout(title = "Cereals Consumer Reports Ratings ",
title_font_size = 40, template = 'seaborn',
width = 1600, height = 1400)fig2.update_layout(legend=dict(
yanchor="top", y=0.99,
xanchor="left",x=0.01),
legend_font_size= 20,
showlegend = True)fig2.update_xaxes(title_text = 'Sugar',
title_font=dict(size=30, family='Verdana',
color='purple'),
tickfont=dict(family='Calibri', color='black',
size=25))fig2.update_yaxes(title_text = "Rating", range = (0,80),
title_font=dict(size=30, family='Verdana',
color='orange'),
tickfont=dict(family='Calibri', color='black',
size=25))fig2.write_image(path + "figbubble2.png")
fig2.show()
图 2:带有 Plotly.graph_objects 的气泡图。作者使用与上图相同的数据集制作的图表。
总结一下:
当我们想要显示三个或四个变量之间的关系而不是它们的确切值时,气泡图是合适的。Plotly Express 和 Plotly.graph_objects 允许您使用少量且一致的代码行创建高质量的静态图像。
但是您必须注意以下警告:
- 请记住,气泡的面积与其半径不成正比,而是与其平方成正比;
- 与散点图不同,气泡图不会随着数据点数量的增加而改善;
- 它们不应用于表示零或负值,因为没有负或零区域;
- 要用气泡图显示一段时间内的趋势,你必须把时间变量放在横轴上。
如果你对这篇文章感兴趣,请阅读我以前的(https://medium.com/@dar.wtz):
带 Plotly Express、跟踪和布局的面积图
带有 Plotly Express、主题和模板的直方图
参考文献
[2]:https://www . ka ggle . com/Crawford/80-麦片/discussion/154053
用 Vespa 从 python 构建一个基本的文本搜索应用程序
原文:https://towardsdatascience.com/build-a-basic-text-search-application-from-python-with-vespa-b0a4f77dcbb4?source=collection_archive---------21-----------------------
pyvespa 简化 API 简介。用几行代码从 python 构建 Vespa 应用程序。
这篇文章将向您介绍简化的pyvespa
API,允许我们用 python 的几行代码从头开始构建一个基本的文本搜索应用程序。后续的帖子将通过在这里描述的基础应用之上逐步构建来增加复杂性。
莎拉·多维勒在 Unsplash 上拍摄的照片
pyvespa
在 python 中公开了 Vespa API 的子集。该库的主要目标是允许更快的原型开发,并促进 Vespa 应用程序的机器学习实验。我曾经写过我们如何使用它来连接正在运行的 Vespa 应用并与之交互和评估 python 的 Vespa 排名函数。这一次,我们重点关注从零开始构建和部署应用程序。
安装
这里介绍的 pyvespa 简化 API 发布于版本0.2.0
pip3 install pyvespa>=0.2.0
定义应用程序
例如,我们将构建一个应用程序来搜索 CORD19 样本数据。
创建应用程序包
第一步是创建一个 Vespa 应用包:
from vespa.package import ApplicationPackage
app_package = ApplicationPackage(name="cord19")
向架构中添加字段
然后我们可以将字段添加到在app_package
中默认创建的应用程序的模式中。
from vespa.package import Field
app_package.schema.add_fields(
Field(
name = "cord_uid",
type = "string",
indexing = ["attribute", "summary"]
),
Field(
name = "title",
type = "string",
indexing = ["index", "summary"],
index = "enable-bm25"
),
Field(
name = "abstract",
type = "string",
indexing = ["index", "summary"],
index = "enable-bm25"
)
)
cord_uid
将存储 cord19 文档 id,而title
和abstract
不言自明。- 在这种情况下,所有字段都是类型
string
。 - 将
"index"
列入indexing
列表意味着 Vespa 将为title
和abstract
创建一个可搜索的索引。你可以在 Vespa 文档中了解更多关于indexing
可用选项的信息。 - 设置
index = "enable-bm25"
使 Vespa 预先计算数量,以便快速计算 bm25 分数。我们将使用 BM25 对检索到的文档进行排序。
查询时搜索多个字段
字段集将字段组合在一起进行搜索。例如,下面定义的default
字段集将title
和abstract
组合在一起。
from vespa.package import FieldSet
app_package.schema.add_field_set(
FieldSet(name = "default", fields = ["title", "abstract"])
)
定义如何对匹配的文档进行排序
我们可以通过定义一个 RankProfile 来指定如何对匹配的文档进行排序。在这种情况下,我们定义了bm25
等级配置文件,它结合了在title
和abstract
字段上计算的 BM25 分数。
from vespa.package import RankProfile
app_package.schema.add_rank_profile(
RankProfile(
name = "bm25",
first_phase = "bm25(title) + bm25(abstract)"
)
)
部署应用程序
我们现在已经定义了一个包含相关字段的基本文本搜索应用程序,一个将字段分组在一起的字段集,以及一个对匹配文档进行排名的排名配置文件。是时候部署我们的应用程序了。我们可以通过创建 VespaDocker 的实例,使用 Docker 在本地部署我们的app_package
,而无需离开笔记本,如下所示:
from vespa.package import VespaDocker
vespa_docker = VespaDocker(
disk_folder="/Users/username/cord19_app",
port=8080
)
app = vespa_docker.deploy(
application_package = app_package,
)Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for application status.
Finished deployment.
app
现在拥有一个 Vespa 实例,我们将使用它与我们的应用程序进行交互。恭喜,您现在已经有了一个可以运行的 Vespa 应用程序。
要知道pyvespa
提供了一个方便的 API 来定义来自 python 的 Vespa 应用包,这一点很重要。vespa_docker.deploy
将 Vespa 配置文件导出到上面定义的disk_folder
。浏览这些文件是开始学习 Vespa 语法的一个很好的方法。
输入一些数据
部署 Vespa 应用程序后,我们的第一个动作通常是向它提供一些数据。为了更容易理解,我们准备了一个包含 100 行的DataFrame
,以及模式定义所需的cord_uid
、title
和abstract
列。
from pandas import read_csv
parsed_feed = read_csv(
"https://thigm85.github.io/data/cord19/parsed_feed_100.csv"
)parsed_feed
然后我们可以遍历上面的DataFrame
并通过使用 app.feed_data_point 方法来填充每一行:
- 默认情况下,模式名被设置为等于应用程序名,在本例中为
cord19
。 - 当向 Vespa 提供数据时,我们必须为每个数据点提供一个唯一的 id。这里我们用
cord_uid
。
for idx, row in parsed_feed.iterrows():
fields = {
"cord_uid": str(row["cord_uid"]),
"title": str(row["title"]),
"abstract": str(row["abstract"])
}
response = app.feed_data_point(
schema = "cord19",
data_id = str(row["cord_uid"]),
fields = fields,
)
如果需要,您还可以检查对每个请求的响应。
response.json(){'pathId': '/document/v1/cord19/cord19/docid/qbldmef1',
'id': 'id:cord19:cord19::qbldmef1'}
查询您的应用程序
有了数据,我们可以开始查询我们的文本搜索应用程序。我们可以通过向 app.query 方法的主体参数发送所需的参数,直接使用 Vespa 查询语言。
query = {
'yql': 'select * from sources * where userQuery();',
'query': 'What is the role of endothelin-1',
'ranking': 'bm25',
'type': 'any',
'presentation.timing': True,
'hits': 3
}res = app.query(body=query)
res.hits[0]{'id': 'id:cord19:cord19::2b73a28n',
'relevance': 20.79338929607865,
'source': 'cord19_content',
'fields': {'sddocname': 'cord19',
'documentid': 'id:cord19:cord19::2b73a28n',
'cord_uid': '2b73a28n',
'title': 'Role of endothelin-1 in lung disease',
'abstract': 'Endothelin-1 (ET-1) is a 21 amino acid peptide with diverse biological activity that has been implicated in numerous diseases. ET-1 is a potent mitogen regulator of smooth muscle tone, and inflammatory mediator that may play a key role in diseases of the airways, pulmonary circulation, and inflammatory lung diseases, both acute and chronic. This review will focus on the biology of ET-1 and its role in lung disease.'}}
我们还可以通过使用 QueryModel 抽象来定义相同的查询,它允许我们指定我们希望如何匹配和排列我们的文档。在这种情况下,我们定义我们想要:
- 使用
OR
操作符匹配我们的文档,该操作符匹配与查询至少共享一个术语的所有文档。 - 使用我们的应用程序包中定义的
bm25
等级配置文件对匹配的文档进行分级。
from vespa.query import QueryModel, RankProfile as Ranking, OR
res = app.query(
query="What is the role of endothelin-1",
query_model=QueryModel(
match_phase = OR(),
rank_profile = Ranking(name="bm25")
)
)
res.hits[0]{'id': 'id:cord19:cord19::2b73a28n',
'relevance': 20.79338929607865,
'source': 'cord19_content',
'fields': {'sddocname': 'cord19',
'documentid': 'id:cord19:cord19::2b73a28n',
'cord_uid': '2b73a28n',
'title': 'Role of endothelin-1 in lung disease',
'abstract': 'Endothelin-1 (ET-1) is a 21 amino acid peptide with diverse biological activity that has been implicated in numerous diseases. ET-1 is a potent mitogen regulator of smooth muscle tone, and inflammatory mediator that may play a key role in diseases of the airways, pulmonary circulation, and inflammatory lung diseases, both acute and chronic. This review will focus on the biology of ET-1 and its role in lung disease.'}}
使用 Vespa 查询语言作为我们的第一个示例,可以为您提供 Vespa 所能提供的全部功能和灵活性。相比之下,QueryModel 抽象侧重于特定的用例,对于 ML 实验可能更有用,但这是以后的主题。
用 Facebook Messenger 在 60 分钟内创建一个聊天机器人
原文:https://towardsdatascience.com/build-a-chatbot-with-facebook-messenger-in-under-60-minutes-f4c8b8046a91?source=collection_archive---------12-----------------------
使用 Rasa 部署一个人工智能助手——从构思到脸书——只需一小时。
沃洛德梅尔·赫里先科在 Unsplash 上的照片
Rasa 是一个开源的对话式 AI 框架,使用机器学习来构建聊天机器人和 AI 助手。今天,我将向您展示如何使用 Rasa 构建您自己的简单聊天机器人,并将其作为机器人部署到脸书信使——所有这一切都在一个小时内完成。你所需要的只是一些简单的 Python 编程和一个有效的互联网连接。
完整代码可以在这里找到:GitHub Repo
代码是用 Python 3.7 开发和测试的。Rasa 目前只支持 Python 到 3.8(更新见此处)。
我们今天构建的机器人将非常简单,不会深入到任何高级 NLP 应用程序中。然而,该框架确实为更复杂的应用程序提供了充分的支持。
我推荐 DeepLearning 提供的这个 Coursera 课程。人工智能学习更多自然语言处理。
https://click.linksynergy.com/link?id=J2RDo*Rlzkk&offerid=759505.16188218824&type=2&murl=https%3A%2F%2Fwww.coursera.org%2Flearn%2Fsequence-models-in-nlp
我们开始吧!
克隆我的回购的完整代码。
属国
确保安装了所有依赖项。我们的简单机器人只需要两个库:
rasa==2.2.0
spacy==2.2.4
如果您克隆了我的库,您可以运行pip install -r requirements.txt
从根目录安装这两个库。
spacy 语言模型需要在单独的步骤中安装。
python3 -m spacy download en_core_web_md
python3 -m spacy link en_core_web_md en
知识库演练
在我向您展示如何培训和部署我们的助手之前,让我们来看一下每个组件,了解它们是如何组合在一起的。
这些文件中的大部分可以通过运行rasa init
来生成,这将创建一个包含示例训练数据、动作和配置文件的新项目。
我们将从配置文件开始。
配置文件
endpoints.yml
这是助手的所有端点所在的位置。为了支持自定义动作(基本上是您可以编写的用于调用其他 API、查询数据库或访问您构建的其他服务的自定义代码),我们需要创建动作服务器。为此,将action_endpoint
包含在该文件中。
这里还可以定义其他端点,例如,使用 Kafka 发送事件,或者将对话存储在 Redis 中,而不是存储在内存中。
这是我们的端点文件的样子。
action_endpoint:
url: "http://localhost:5055/webhook"
config.yml
配置文件定义了模型将如何被训练——这是你可以真正发挥创造力的地方。第一行用于指定聊天机器人语言。在这里,它将是英语。
language: "en"
下一个组件配置 NLU 管道。我们正在使用 Rasa 推荐的“合理的”启动管道之一。
pipeline:
- name: SpacyNLP
- name: SpacyTokenizer
- name: SpacyFeaturizer
...
接下来是policies
。这些是 Rasa 回应用户信息时将遵循的政策。
policies:
- name: MemoizationPolicy
- name: RulePolicy
core_fallback_threshold: 0.3
core_fallback_action_name: action_default_fallback
...
MemoizationPolicy 会记住训练故事中的最后 X 个事件。可以通过将max_history
添加到策略配置中来指定 x。
RulePolicy 利用我们为机器人编写的硬规则(我们将在后面讨论)来形成响应。尽管 RulePolicy 是第二个指定的,但它将优先于其他策略。这是因为默认情况下,RulePolicy 具有最高优先级,这些优先级也可以配置。通过我们的策略配置,机器人将首先检查适用的规则,如果没有,则转向训练故事。
我们的策略还配置了默认的回退机制。当动作置信度低于我们的core_fallback_threshold
0.3 时,它将发送一个预定义的响应,称为utter_default
,并恢复到触发回退之前的状态。当用户说一些完全没有意义的事情时,这非常有用。
credentials.yml
如果你的代码托管在 GitHub 之类的地方,在发布这个文件之前你应该三思。该文件是身份验证所必需的。我们将利用它来连接到我们的 Facebook Messenger 机器人。我暂时隐藏了这些秘密,但是我们也将介绍如何从脸书生成它们。
**注意:**这个文件不包含在我的 GitHub repo 中。您需要创建这个文件,并用稍后生成的令牌填充它。
facebook: verify: "[this is your custom verification token]" secret: "[this is generated from facebook]" page-access-token: "[this is generated from facebook]"
domain.yml
来自官方 RASA 文档:
域定义了您的助手在其中工作的领域。它指定了你的机器人应该知道的意图、实体、插槽、响应、形式和动作。它还定义了对话会话的配置。
domain.yml 文件分为意图、实体、槽、响应、动作和会话配置。
- 这个机器人被训练成能识别你定义的意图,并根据检测到的意图做出不同的行为
- 如果您在管道中指定了实体提取器,它将提取您在该文件中定义的所有实体;实体可用于进一步调节对话流
- 插槽是机器人将信息存储到内存中的键值对;在对话过程中,可以随时设置、重置和检索插槽
- 响应是预定义的响应模板,供机器人发送消息;我们的默认回退将总是在到达那个状态时发送与
utter_default
相关的消息 - 操作包括已经定义的任何自定义操作
在会话配置中,我们可以定义会话到期时间,以及是否应该将时隙转移到新会话。
培训用数据
我们将训练数据分成三个文件夹:nlu、规则和故事。在 nlu 文件夹中,我们定义了我们的意图和实体。在 rules 文件夹中,我们定义了通过 RulePolicy 执行的规则。stories 文件夹包含模拟对话,用作如何管理对话的附加培训数据。
nlu.yml
在我们的 NLU 设置中,我们定义了一些非常基本的意图。以下是我们的“问候”意图示例,它使用了以下培训数据:
nlu:
- intent: greet
examples: |
- hey
- hello
- hiya
...
官方文档更加详细地介绍了如何改进 NLU 组件,例如通过包含实体、同义词和查找表。
rules.yml
规则定义了机器人应该始终遵循的小型对话模式。RulePolicy 利用这些规则管理对话流。
这里,我们定义了一个简单的规则“总是问候用户”。当机器人遇到“问候”意图时(它根据上面提供的数据学习识别问候意图),它将继续执行自定义操作action_greet
。
- rule: always greet the user
steps:
- intent: greet
- action: action_greet
stories.yml
故事是“真实”对话的例子,用于进一步训练机器人的对话管理模型。它们被写成用户和机器人之间的对话。
我们将包括一个非常简单的故事。
version: "2.0"stories: - story: generic happy pathsteps: - intent: greet - action: action_greet - intent: select_price - action: action_select_upper_price - intent: select_purpose - action: action_select_purpose - intent: select_brand - action: action_select_brand
自定义操作
自定义操作对于更复杂的机器人来说非常有用——它们可以用来调用其他内部 NLP 服务或公共 API 来改善对话体验。
自定义动作存储在actions/actions.py
这里有一个我们的自定义动作action_greet
的例子,它问候用户。
每个自定义操作都遵循非常标准的格式。有一个name
方法返回定制动作的名称——这个名称必须与 domain.yml 中提供的名称相匹配
run
方法需要接受一个分派器、跟踪器和域。
- 调度程序用于生成响应(这里它发出两条消息)
- 追踪器指的是会话追踪器,并且可以被利用来获取槽值、当前和过去的状态
返回值是在操作结束时执行的事件列表。下面是一些我们可以包括在内的常用事件:
- 插槽集-用于设置插槽值
- 后续操作—触发后续操作
- 重新启动—结束当前对话
培训和启动机器人
一旦你有了以上所有的文件,你就可以训练机器人了。在根目录下运行rasa train
开始这个过程。根据您拥有的数据量和管道的复杂程度,这可能需要一段时间。
如果您看到此消息,这意味着模型已成功训练并保存。
您需要运行两个命令来启动 bot——一个用于操作服务器,一个用于 bot 本身。我在这里把它合并成一行。
**注意:**这将在本地启动机器人。稍后,我们需要用脸书生成的令牌填充我们的凭证文件,以将其部署到 Messenger。
rasa run -m models --enable-api --cors "*" --debug & rasa run actions
这是我的终端在该命令运行完毕后的样子。每次服务器参与对话时,都会有额外的日志。
当上述程序运行时,操作服务器将占用端口 5055,而机器人将占用端口 5005。
您可以通过 pinghttp://localhost:5005来测试服务器是否正在运行。
与机器人互动
有几种方法可以开始与机器人互动。
REST API
您可以通过 REST API 与 bot 进行交互。当 RASA 服务器运行时,以用户身份发送此请求以发送消息:
curl --request POST \
--url [http://localhost:5005](http://localhost:5005)/webhooks/rest/webhook \
--header 'content-type: application/json' \
--data '{"sender": "sender_id", "message": "hi"}'
发件人字段是会话的唯一 ID。当您在同一个发件人字段下按顺序发送邮件时,服务器会识别出这些邮件都是一个会话的一部分。消息字段是您要发送的文本。
RASA shell
你可以通过命令行运行rasa shell
与机器人开始对话。
Facebook Messenger 设置
我倾向于通过 ngrok 来部署 Rasa 服务器,这将把您的本地端口暴露给公共互联网。或者,你可以使用 Heroku 之类的服务,但 Rasa 映像的大小使得应用程序很难在大多数空闲层上运行。
ngrok 设置
- 创建一个 ngrok 账户
- 按照以下说明在您的电脑上设置 ngrok:https://ngrok.com/download
- 通过在单独的终端中运行
./ngrok http 5005
,在端口 5005 上启动 HTTP 隧道
确保你保持终端运行——任何时候终端停止运行,你的隧道将停止,你的机器人将在 Messenger 上没有响应。
记下生成的 url。安全的网址(与 https)将需要提供给脸书。
在脸书上创建应用程序
脸书机器人需要链接到脸书网页。你需要一个脸书账户来创建一个页面。
一旦你的页面创建好了,去https://developers.facebook.com/apps。点击绿色的“创建应用程序”按钮创建一个新的应用程序。
选择第一个选项,并按照说明创建您的应用程序。
点击下方的“设置”按钮,将“Messenger”添加到您的应用程序中。
在脸书上设置应用程序
一旦创建了应用程序,它会引导你进入 Messenger 下的“设置”页面。如果您没有被自动带到那里,请导航到您的应用仪表板,然后进入“信使”>“设置”:
首先,将你的脸书页面链接到应用程序。
在链接页面旁边,添加订阅以允许邮件。
一旦你的页面被链接,点击页面旁边的“生成令牌”。跟踪这个令牌,因为它需要包含在您的 Rasa 项目中。我们将这个令牌称为“页面访问令牌”。
接下来,导航到仪表板上的设置>基本,找到您的应用程序密码。
然后,向下滚动到“webhooks”添加一个新的回调 URL。
在填写回调细节之前,在 Rasa 项目中创建 credentials.yml。该文件应该如下所示:
以下是填充字段的方法:
- **验证:**创建您选择的安全验证令牌
- **秘密:**这是从基本设置中获取的应用程序秘密
- **页面访问令牌:**使用您之前为页面生成的页面访问令牌
通过运行以下命令再次启动 Rasa 服务器。这与前面的命令略有不同,因为我们现在利用了凭据标志。
rasa run -m models --enable-api --cors "*" --debug --credentials credentials.yml & rasa run actions
获取作为 credentials.yml 的一部分创建的 verify 标记,并在 Webhooks 部分的回调 URL 旁边输入它。
- 回调 URL 为https:///web hooks/Facebook/web hook
**注意:**在你的 ngrok 隧道停止的任何时候,你都必须重启它,并在脸书上更新你的回拨 URL
验证您的应用程序已启动并正在运行
导航到您的页面并尝试向机器人发送消息。
太棒了,都准备好了!目前状态下的机器人实际上不会提供有意义的笔记本电脑推荐——也许有一天会的:)
感谢您的阅读!
通过 Medium 关注我的最新动态。😃
作为一个业余爱好项目,我还在 www.dscrashcourse.com建立了一套全面的免费数据科学课程和练习题。
再次感谢您的阅读!📕
为实际用例建立分类模型
原文:https://towardsdatascience.com/build-a-classification-model-for-a-practical-use-case-670a1bb8dd11?source=collection_archive---------21-----------------------
具有核心技巧和松弛变量支持向量机深度挖掘
在 Unsplash 上由 Ameer Basheer 拍摄的照片
数据科学家你好!我希望你们都过得很好。上次我们讨论了如何用核心概念从零开始构建一个回归模型到一个实际用例。今天,我计划向您提供对分类模型的高级理解,并通过实践经验深入了解实际场景。
在本文中,您将了解到:
- 支持向量机
- 拉格朗日乘数
- 松弛变量
- 内核技巧
- 超参数调谐
- 类别不平衡处理
- 准确度测量
用例: 银行营销数据集:与一家葡萄牙银行机构的直接营销活动(电话)相关。目标是预测客户是否会认购定期存款。
我在这里使用的数据集来自 UCI 机器学习库,它可以公开用于研究。
数据集来源:https://archive.ics.uci.edu/ml/datasets/bank+marketing#
1.问题定义
在我们着手做任何事情之前,我们需要了解问题和影响决策的事实。所以根据给定的用例,这是一个分类问题。我们需要预测特定的客户是否愿意将他/她的钱存入银行。
作为数据科学家,我们的总体目标应该是,通过识别影响营销活动成功的主要因素并预测营销活动对特定客户是否会成功,来提高营销活动的效率。
因此,作为第一步,我们需要找出我们在数据集中有什么(+它的复杂性)以及可以直接或间接影响我们预测的特定事实。然后我们需要像往常一样做预处理。
我假设你已经熟悉了我之前的文章中的预处理步骤。我已经更深入地解释过了。因此,您将能够轻松地对该数据集进行预处理,直至添加 PCA。
此外,您可以参考我在资源部分下的 python 笔记本,一步一步地了解这个过程。
预处理完成后,我们需要拟合一个模型。所以根据给定的用例,这是一个分类问题。有如此多的分类技术可用。一些非常受欢迎的是:
- k-最近邻(KNN)-通过具有最小距离的多数表决原则确定数据点的类别。
- 朴素贝叶斯——基于贝叶斯定理的概率算法。
- 决策树—遵循一组决策规则(if-then-else 条件)来可视化数据并根据条件对其进行分类。
但是你不能盲目地将任何模型应用于给定的数据集。在应用模型之前,您需要了解问题环境、数据集复杂性、每个模型的特点和缺点,以及许多额外的东西。如果您用一些领域级别的理解(+您的经验)正确地分析它,您将能够为您的数据集找到一个更好的适合模型。
在这里,我选择了 SVM 模式。我将用一些数学概念在更深的层次上解释 SVM。如果你赶时间,跳过下面的解释,直接跳到实际的实现(第 6 节)。
2.支持向量机解释
支持向量机是机器学习中最流行的分类技术之一,它直接受到一个叫做统计学习理论的数学概念的启发。
它是一种监督学习技术,主要应用于线性可分的数据集(特征)。同样,目标(y)应该是明确的。当 y 是连续的,我们可以使用支持向量回归。
线性可分的意思是,我们应该能够找到一条线性直线或者一个线性超平面,能够把数据点完全分成两类。
关键思想是找到尽可能广泛地将一个类与另一个类分开的最优超平面。
注意——我们只能讨论两类的线性可分性。但是如何处理多类分类呢?等到最后!
如果数据集不是线性可分的,您应该使用非线性转换或松弛变量使它们可分(至少在某种程度上)。我将在几分钟后解释什么是松弛变量。
SVM 的主要直觉是识别边界向量。那么什么是边界呢?我用图表来解释一下。
对 SVM 的主要直觉(图片由作者提供)
在线性可分离的数据集中,我们可以找到分隔两个类的边界。(这里我取正和负)这些位于边界线上的向量称为支持向量。
SVM 总能找到线性可分模式的最佳超平面。这个边界被称为决策边界。(在神经网络中,这个判定边界是任意选择的。但是在 SVM,它是以一种最佳的方式被挑选出来的。)
在 SVM,我们讨论如何绘制这些线条,使它们具有最宽的宽度,将阳性样本与阴性样本分开。
通过最大化宽度来绘制决策边界(图片由作者提供)
所以这 3 条线可以用下面的等式来表示。
- wx+b = 0——用于决策边界
- Wx+b=-1 —适用于 1 级边界
- Wx+b=+1 —用于 2 级边界
阳性样本位于 Wx+b≥ +1 侧,阴性样本位于 Wx+b≤ -1 侧。
如果我们为正样本引入变量 y=+1,为负样本引入变量 y=-1,那么我们可以得到该条件的一般形式。
条件的一般形式(作者提供的图片)
如果满足这个条件,所有正负数据点都将在边界线后面。(完美区分两个类别)
当我们确定 w 和 b 时,我们应该考虑最大宽度。让我们找出宽度。
寻找宽度(作者图片)
我们想最大化宽度。为了最大化宽度,我们需要最小化|W|或 1/2|W|(这不会改变优化函数,但在计算梯度时只会导致更整洁的解决方案)
所以最终我们需要在y(Wx+b)-1=0
的约束下最小化 1/2|W|
如果根据给定的条件,我们需要最小化某个东西,我们拥有的唯一定理是拉格朗日定理。所以还是来应用一下吧。
拉格朗日定理的应用(图片由作者提供)
在解完方程并将数值代入前面的方程 A 后,我们可以找到最佳宽度。
最佳宽度(图片由作者提供)
最佳权重向量和偏差可以这样导出。
最佳权重向量和偏差(图片由作者提供)
现在我们知道了最佳权重向量和偏差。我们可以用它来预测给定的数据点。
给定数据点的预测(图片由作者提供)
所以到现在为止,我们一直在讨论线性可分数据。如果我们找不到数据之间的线性分离,我们要么将它们转换成线性可分离状态,要么我们需要使用松弛变量技术对这个非线性可分离数据应用 SVM 模型。
3.松弛变量的使用
实际上,大多数数据集不会是线性可分的。结果,将没有办法满足我们先前导出的约束。缓解这个问题的一个方法是通过引入松弛变量来放松一些约束。
因此,我们在这里做的是,计算与决策裕度不同的数据点之间的距离,并定义一个罚函数。该罚函数控制对误分类的支持。(由于违反了某些约束,这将导致多少数量被错误地分类。)
我们对落在边界之外的数据点施加惩罚。惩罚参数的实际作用是,它温和地惩罚位于决策边界错误一侧的点。这个损失(ξ)被称为松弛变量。
引入惩罚(图片由作者提供)
ξ = 0 表示数据点在正确的边界上或边界内。
对于决策边界上的数据点,ξ = 1。
落在错误一侧的数据点ξ ≥ 1。(j 和 k 被错误分类)
现在我们必须最小化:
最小化新目标(图片由作者提供)
参数 C 是惩罚强度,它指定了我们有多在乎错误。它也被称为正则化参数,我们用它来调整我们的模型。
如果 C 很小,SVM 就变得很松散,可能会牺牲一些点来获得一个简单的解。这将导致未命中分类的增加。如果 C 非常大,SVM 会变得非常严格(强),并试图获得超平面右侧的所有数据点。这将导致模型过拟合。所以在选择 C 的值时,你应该更加关注。
惩罚力量 C vs 分类行为(图片由作者提供)
4.用于多类分类的 SVM
二元对多类分类(图片由作者提供)
SVM 通常用于二元分类。它本身不支持多类分类。因此相同的二元分类原理被用于多类分类。可以看到有两种方法。
- 一对一方法— 将多类问题分解为多个二元分类案例。
- 一对多方法 — 细分设置为每个类一个二元分类器。连续地,某一类与所有其他类相区别。
让我们举一个简单的例子来进一步说明。这里,目标是四个可能的类中的一个:{红色、绿色、蓝色、黄色}。
在一对一方法中,我们创建了一组二元分类器,每个分类器代表一个对:
- OvO 二元分类器 1:红色对绿色
- OvO 二元分类器 2:红色对蓝色
- OvO 二元分类器 3:红色 vs 黄色
- OvO 二元分类器 4:绿色对蓝色
- OvO 二元分类器 5:绿色对黄色
- OvO 二元分类器 6:蓝色 vs 黄色
一对一多类分类所需的分类器数量可以用下面的公式(n 为类的数量)来检索:n*(n-1)/2
在一对一分类器中,仅涉及创建四个二元分类器:
- OvR 二元分类器 1:红色对{绿色、蓝色、黄色}
- OvR 二元分类器 2:绿色 vs {红色、蓝色、黄色}
- OvR 二元分类器 3:蓝色 vs {红色、绿色、黄色}
- OvR 二元分类器 4:黄色 vs {红色、绿色、蓝色}
因此所需的分类器等于类别的数量。这两者都可以通过使用 scikit-learn 库轻松实现。
from sklearn.svm import SVC
from sklearn.multiclass import OneVsOneClassifier
from sklearn.multiclass import OneVsRestClassifier# define model one-vs-one
clf1 = OneVsOneClassifier(SVC());# define model one-vs-rest
clf2 = OneVsRestClassifier(SVC());
最好的是什么?最好的方法是根据问题的具体情况而定。所以要明智地使用它。尽管如此,我还是会给出一些赞成和反对的意见。
一对一
- pro 不容易在数据集中造成不平衡。
- con 仅对每对类将主数据集分割成一个二元分类。
一比一休息
- pro 需要更少的分类器,使其成为更快的选项。
- con——由于大量的类实例,处理大型数据集具有挑战性。
5.内核技巧
内核是适用于所有 SVM 氏症的窍门。这是一种优化技术,使 SVM 更快,并导致高度的普遍性。这是一个非常简单但更强大的概念。
核函数的思想是使操作能够在输入空间中执行,而不是在潜在的高维特征空间中执行。因此,内积不需要在特征空间中计算。
迷茫?让我用图表来解释一下。
从输入空间到特征空间的数据转换(图片由作者提供)
我们使用函数(φ)将非线性可分数据转换到高维空间,在该空间中我们可以找到线性可分的决策状态。
对于线性可分数据,我们已经推导出宽度为 W =σαy x
,但是现在使用变换函数,它变成 W =σαyφ(x ),最终我们的 Q 最优宽度函数将是:
新的最佳宽度函数(图片由作者提供)
这里的问题是我们需要分别计算事物的数量。
- φ(xi)
- φ(xj)
- 两者的点积[φ(xi).φ(xj)]
为了降低计算复杂度,我们可以引入另一个函数为:
k(xi,xj) =φ(xi)*φ(xj)
该函数接受原始低维空间中的输入,并返回高维空间中已转换向量的点积。(直接进行转换,而不是显式地将转换应用于x i 和 xj 并获得点积)
这就是所谓的内核技巧。因此,该函数通过大幅降低计算复杂度,在 SVM 及其性能中起着关键作用。
对于大型数据集(如-10k、1M……),您不需要对所有数据点逐一进行转换并获得点积,但您可以简单地将此核函数应用于所选数据点,以获得相同的结果,这将有助于降低复杂性。
重要提示—核函数应该是对称的。
最常用的内核类型列表如下所示。
内核类型(图片由作者提供)
最流行的核函数类型是 **RBF。**因为它具有沿整个 x 轴的局部和有限响应。然而,需要记住的一个关键点是,当我们将数据映射到一个更高维度时,我们很有可能会过度拟合模型。因此,选择正确的核函数(+选择正确的参数)和正则化非常重要。
6.将 SVM 应用于预处理数据集
好吧!我希望我已经涵盖了 SVM 中的大部分核心概念。让我们回到我们的问题。现在我们需要将 SVM 模型应用到我们的数据集。编写代码比理解概念要容易得多。但是如果你盲目地应用它,那只是一种浪费。在实现任何模型之前,您需要更好地理解基本概念。我打算写更多关于不同模型的文章,并将它们应用于实际用例。希望它也有助于提高你的知识。
拿够了。来做实现吧。
我假设您已经在我上一篇文章的帮助下完成了 PCA 之前的所有预处理。
预处理数据集到 PCA(图片由作者提供)
scikit-learn 库提供了支持向量分类器来实现 SVM 模型。
from sklearn import svm
svc = svm.SVC(kernel='rbf', C=1.2, gamma=0.5)
你可以像往常一样得到预测。
predictions = svc.predict(X_test_pca)
y_hat = pd.DataFrame(predictions, columns=["predicted"])
7.准确性测量和评估
在回归分析中,我们有像均方误差、R 值这样的精度指标..等等。但是在分类问题中,分数在某些情况下可能是误导的(例如不平衡的分类问题)
我们用总预测中的正确预测来衡量准确性。可能会有这样的情况,一些类完全没有被识别(忽略),但由于其他类的影响,给出了超过 90%的准确率。它们在少数类中占主导地位,并使准确性成为衡量模型性能的不可靠指标。
因此,建议使用以下一些技术,因为它们为所有类别提供了良好的度量,并且是分类任务中最常用的指标。
- 混淆矩阵
- 精确召回和 F1 得分
- AUC - ROC 曲线
混淆矩阵
混淆矩阵提供了一个更有洞察力的图像,显示了哪些类被正确和错误地预测,最重要的是,显示了正在犯的错误的类型。它克服了单独使用分类精度的局限性。
困惑矩阵(图片由作者提供)
以下是需要记住的重要术语。(真更好,因为模型正确预测了它们)如果这两个类是正和负:
- 真正值(TP): 实际值是正值,它们被预测为正值
- 真负值(TN): 实际值是负值,它们被预测为负值
- 误报(FP): 实际值为负值,预测值为正值。(也称为 I 型错误)
- 假阴性(FN): 实际值为正,预测值为负。(也称为第二类错误)
解读困惑矩阵(图片由作者提供)
让我们看看实现。
混淆矩阵实现(图片由作者提供)
如您所见,一个类(0)得到了非常好的预测,而另一个却没有。这是因为阶级不平衡。将在几分钟后看到如何克服这一点。
F1 分数
F1 分数是精确度和召回率的调和平均值。(传达了精准和召回之间的平衡。)我们先来看看什么是精准和召回。
- 精确度—从预测的阳性中,有多少是实际阳性
- 回忆—从实际阳性中,有多少被正确分类
方程式(图片由作者提供)
F1 分数通常比准确性更有用,尤其是如果你的班级分布不均匀。如果假阳性和假阴性具有相似的成本,则准确性最好。如果误报和漏报的代价相差很大,最好同时看精度和召回率。这就是为什么我们使用 F1 的分数。
from sklearn.metrics import f1_scoref1_score(y_test,y_hat)
F1 的分数为 1 时被认为是完美的,而当分数为 0 时,这个模型就是一个彻底的失败。Scikit-learn 的分类报告精确地提供了所有的分数。
from sklearn.metrics import classification_reportprint(classification_report(y_test,y_hat))
分类报告(图片由作者提供)
对于 AUC-ROC 曲线,我将单独写一篇文章,因为它需要更深入地解释。(+带有成本函数)但是如果你好奇,你可以参考我的 Colab 笔记本,因为我把所有代码都放在里面了。
8.处理阶级不平衡
你可能会注意到有一个类在预测中占主导地位。那是因为阶级不平衡。我们将类不平衡定义为分类数据集类的比例不均衡。
目标中的类不平衡(图片由作者提供)
如果我们检查数据集,我们可以发现这两个类之间的巨大差异。这在大多数实际情况下都会发生,如垃圾邮件检测、欺诈分析等。为了避免这种情况,我们可以使用不同的技术。我将简单解释两种不同的方法。如果你想进一步了解它,请告诉我,我也会就此写一篇单独的文章。
请记住,我们需要将这些技术应用于预处理过的数据集,因为它们也被视为模型。另一件事是,我们只对训练数据进行采样。
过采样
通过这样做,它将按照多数类比例对少数类比例进行重新采样。
SMOTE 是一种非常著名的过采样技术。(合成少数过采样技术。)它通过利用k-最近邻算法来创建合成数据。这就是为什么我们需要在数据预处理之后使用它。
SMOTE 最初从少数类中选取随机数据开始,然后设置数据的 k 个最近邻。然后在随机数据和随机选择的 k-最近邻之间产生合成数据。
SMOTE 有不同的变体/形式,例如边界 SMOTE、SVM SMOTE(使用 SVM 算法)、自适应合成采样(ADASYN)…等等。让我们应用默认形式的 SMOTE。
from imblearn.over_sampling import SMOTEsm = SMOTE(random_state=101)
X_train2, y_train2 = sm.fit_resample(X_train_pca, y_train)
应用 SMOTE 后(图片由作者提供)
应用 SMOTE 后的分类报告(图片由作者提供)
它为少数民族班级带来了一点进步,但是我对结果有点担心,因为我期望得到更高的结果。没关系!总有改进的余地。如果你有时间,尝试一些不同的方法,如 SVM SMOTE,并把结果放在评论部分。
欠采样
通过这样做,它将减少多数阶级的比例,直到人数与少数阶级相似。
最流行的欠采样技术之一是侥幸成功。它也是基于 k-NN 算法。它所做的是当属于不同类别的两个点在分布中彼此非常接近时,该算法消除较大类别的数据点,从而试图平衡分布。
这项技术有三个版本。
- 接近失误 1 — 通过计算较大分布和三个最接近的较小分布之间的平均最小距离来平衡数据。
- 接近失误 2 — 通过计算较大分布和三个最远的较小分布之间的平均最小距离来选择示例。
- 接近未命中 3 — 考虑较小的类实例,并存储 m 个邻居。然后取该分布与较大分布之间的距离,并消除最大距离。
您可以尝试一些不同的方法/排序,并找出最适合您的数据集和模型的方法。这里我使用了版本 3 和两个最近的邻居。
# Undersample imbalanced dataset with NearMiss-3
from imblearn.under_sampling import NearMissundersample = NearMiss(version=3, n_neighbors_ver3=2)
# transform the datasetX_train_undermiss, y_train_undermiss = undersample.fit_resample(X_train_pca, y_train)
应用未遂事故后(图片由作者提供)
应用未遂事件后的分类报告(图片由作者提供)
虽然精确度下降了,但它为两个类别提供了相当好的分类。
另一种良好的欠采样技术是 Tomek 链接(T-Links ),它是压缩最近邻或简称 CNN 的一种改进。(不要与卷积神经网络混淆)它寻找样本集合的子集,这不会导致模型性能的损失。这种方法比 k-最近邻算法更有效,因为它减少了内存需求。
from imblearn.under_sampling import TomekLinks
undersample = TomekLinks()
X_train_under, y_train_under = undersample.fit_resample(X_train_pca, y_train)
9.超参数调谐
为了找到超参数的最佳配置,我们可以使用 GridSerch 。这是一种调整技术,用于确定给定模型的最佳值。如你所知,在我们的 SVM 模型中,我们使用了两个超参数 C 和γ。但是没有办法预先知道这些超参数的最佳值是什么。
所以,我们需要尝试所有可能的值,才能知道最优值。手动完成这项工作需要大量的时间和精力,因此我们使用网格搜索来自动完成这项工作,它会为我们找到最佳参数。
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC# defining parameter range
param_grid = {'C': [0.1, 1, 10, 100, 1000],
'gamma': [1, 0.1, 0.01, 0.001, 0.0001],
'kernel': ['rbf']}#grid search
grid = GridSearchCV(SVC(),param_grid,n_jobs=-1,verbose=3,refit = True)# fitting the model for grid search
grid.fit(X_train_pca, y_train.values.ravel())
n_jobs 参数允许 GridSearch 在幕后使用 Python 的多处理模块。设置 n_jobs = -1 会导致使用机器上所有可用的内核,这将提高网格搜索性能。
注意—在联合实验室中,我们只有 2 个内核。所以还需要一些时间。在我的情况下,它会持续 1 个半小时。
这里将测试不同的参数组合,并最终找到最佳参数。
不同网格的性能+时间分析(图片由作者提供)
# print best parameter after tuning
print(grid.best_params_)
# print how our model looks after hyper-parameter tuning
print(grid.best_estimator_)
微调 T-连锁 SVM 后的结果如下所示。它在所有实例中提供了最好的准确性,但是在识别第二(1)类时仍然有一些缺点。
T 型链接的网格搜索优化 SVM(图片由作者提供)
最后,我将向您展示这种情况下两种最佳技术的准确性比较。
最终对比(图片由作者提供)
10.资源
- 完整的合作实验室 Python 笔记本
https://colab.research.google.com/drive/1EcVY0jQsO6uKzTMlCPK1wt-T6eEYNDzA?usp=sharing
- 前一篇文章
[## 从零开始建立一个机器学习模型到实际使用案例
towardsdatascience.com](/build-a-machine-learning-model-to-a-practical-use-case-from-scratch-3a8dc65ab6f1)
结论
我们在这里讨论了支持向量机背后的原理的深层解释。我们学习了松弛变量和内核技巧,它们帮助我们高效地解决非线性问题。此外,我们还探索了如何使用这个 SVM 模型处理多类分类。
我们通过理解如何从零开始实现 SVM 和正确评估模型的准确性度量来掩盖实际场景。不仅如此,我们还通过修复类不平衡和使用网格搜索微调我们的模型来增加我们模型的准确性。我们已经看到了许多视觉表现,这有助于我们更好地理解所有的核心概念。
所以我希望你对 SVM 模式及其实施有一个清晰的了解。我会在另一篇有趣的文章中再见到你。在那之前,注意安全!快乐学习!❤️
使用 Rasa 构建强大的对话助手
原文:https://towardsdatascience.com/build-a-conversational-assistant-with-rasa-b410a809572d?source=collection_archive---------11-----------------------
用你的私人助理回复重复的信息
作者图片
动机
你曾经希望有一个私人助理来回答重复的信息吗?你可能会犹豫这样做,因为你不知道从哪里开始。
事实证明,创建一个对话助手并不困难。在本文中,我将向您展示如何使用 Rasa 为自己创建一个。
什么是 Rasa?
Rasa 是一个开源的机器学习框架,用于自动化对话。使用 Rasa,您可以创建一个健壮的模型,并使用几个命令行来部署它。
要安装 Rasa,请键入:
pip install rasa
现在,您可以通过键入以下命令来创建一个新项目:
rasa init
您可以训练一个初始模型,并在命令行上与您训练有素的助手聊天,如下所示。
作者图片
看到问题Do you want to speak to the trained assistant on the command line?
,输入Y
。你现在可以像下面这样和你的助手交谈。
作者图片
你与训练有素的助手的最初对话可能不太好。但是不用担心。你可以训练你的助手,让他明白你以后想要什么。
按 Ctrl + C 停止对话并完成项目目录的创建。项目的结构如下所示:
作者图片
现在你有了一个项目,让我们来学习如何提高你的助手。
基本概念
目的
首先,训练有素的助理如何理解你的消息?
作者图片
如果你打开data/nlu.yml
文件,你会看到如下内容:
因此,当我们键入Good morning
、hi
或hello there
时,该模型将检测这些句子的意图为greet
。而当我们键入bye
时,模型会检测到它的意图是goodbye
。
到目前为止一切顺利。但是你的助手如何知道如何响应检测到的意图,比如greet
?
故事
我们可以通过创建故事来指定我们的助手将如何响应每个意图。故事由用户和机器人之间的对话组成。
要查看故事,请打开data/stories.yml
文件。
intent
参数指定用户的意图,而action
参数指定机器人的响应。我们可以创造不同的故事来应对不同的场景。
让我们试着根据上面列出的sad path 1
故事与我们的助理聊天。
作者图片
酷!我们的助手对这个故事的反应类似。我们来分解一下为什么我们的助手会像上面这样回答我们:
Hi
:意图greet
Hey! How are you?
:动作utter_greet
I am sad
:意图mood_unhappy
Here is something to cheer you up
:动作utter_cheer_up
Did that help you?
:动作utter_did_that_help
Yes, it helps. Thank you!
:意图affirm
Great, carry on!
:动作utter_happy
厉害!但是对于utter_greet
这样的动作,我们怎么能指定具体答案?
领域
您可以通过更改domain.yml
中的text
来指定每个响应的答案。
请注意,这些文本与我们在之前的对话中看到的答案相似。
厉害!现在你知道一些基本概念了。让我们训练你的助手乐于助人。
创建列车数据
使用 Rasa 创建列车数据有多种方式。您可以使用交互模式、YAML 文件或 Rasa X 进行训练
相互作用的
如果你不知道从哪里开始,我建议你通过和你的助手聊天来创建新的训练数据。
要开始交互式会话,请键入:
rasa interactive
作者 GIF
正如你在上面看到的,在和你的助手交谈时,你可以标记你的问题的意图,并根据你的意图选择正确的回答!请注意,每个响应都应该以单词utter_
开头。
还可以在运行rasa interactive
的同时,在http://localhost:5006/visualization . html可视化交互对话。
作者 GIF
要停止交互式会话,请键入 Control + C。
现在你应该会在nlu.yml
文件中看到新的意图,在stories.yml
中看到新的故事,在domain.yml
文件中看到新的回应
YAML 文件
您也可以将数据直接添加到 YAML 文件中,或者更改任何您不喜欢的信息。您可以按照上面的格式添加新的故事、意图和回应。
不要害怕犯错误。要确保不同文件中的数据一致,请键入:
rasa data validate
如果有任何不一致,您应该会看到如下警告消息:
UserWarning: Issue found in 'data/stories.yml':
Found intent 'answer_question_about_health' in stories which is not part of the domain.
火车
添加更多训练数据后,您可以通过运行以下命令开始训练您的数据:
rasa train
和你的助手谈谈
现在,让我们通过运行来测试我们刚刚训练的模型:
rasa shell
作者图片
酷!现在问题"How are you?"
的答案更相关了。
想象你的故事
您还可以通过运行以下命令来可视化创建的故事:
rasa visualize
并且一个graph.html
文件将在您的当前目录中生成。在浏览器上查看该文件时,您应该会看到类似下面的内容。
作者图片
在浏览器上训练并与你的助手交谈
如果你喜欢在浏览器上训练和与你的助手交谈,使用 Rasa X。在这里找到安装 Rasa X 的说明。
安装 Rasa 后,您可以通过运行以下命令开始使用它:
rasa x
您应该能够在浏览器上与您的助手聊天,如下所示:
作者图片
您还可以通过单击对话右下角的铅笔图标,在与模型对话的同时训练模型。
作者图片
在与你的助手交谈时,你可以创造如下新的意图和行动:
作者图片
作者图片
对新的培训数据及其标签感到满意后,单击屏幕右下角的“保存故事”。
作者图片
您的新训练数据应该添加到您的 YAML 文件中,如下所示!
共享您的助手
您也可以通过点击左上角的共享按钮,然后点击生成链接,与其他测试人员共享您的助手。
作者图片
应该会为您生成一个链接!如果你在本地模式下使用 Rasa X,你可以使用 ngrok 让你的机器人对其他机器上的用户可用。
安装 ngrok 后,打开一个新的终端并键入:
ngrok http 5002
将生成如下所示的链接:
作者图片
现在,将此链接发送给你的同事,让他们在你的应用仍在运行时尝试一下。他们现在应该可以和你的助手互动了!
部署您的助手
如果您想要部署您的助手并使其对您的客户端可用,请遵循本说明。
结论
恭喜你!您刚刚了解了使用 Rasa 创建和部署聊天机器人是多么容易。我希望这篇文章能激励你创建自己的助手来帮助回答客户的问题。
这篇文章的源代码可以在这里找到。
本文只涉及了这个不可思议的库所能做的事情的表面。我建议你看看 Rasa 的文档或者他们的 Youtube 视频。
我喜欢写一些基本的数据科学概念,并尝试不同的算法和数据科学工具。你可以在 LinkedIn 和 Twitter 上和我联系。
如果你想查看我写的所有文章的代码,请点击这里。在 Medium 上关注我,了解我的最新数据科学文章,例如:
用 Python 在 7 分钟内构建一个 Dash 应用程序
原文:https://towardsdatascience.com/build-a-dash-app-with-python-in-7-minutes-72b6cca7d268?source=collection_archive---------4-----------------------
使用 Python 从头开始创建一个漂亮的可视化应用程序
卢克·切瑟在 Unsplash 上的照片
当我几个月前开始我的顶点项目时,我想为我的机器学习模型创建一个交互式仪表板。
我希望这个仪表板是 web 应用程序的形式,并在新数据进入系统时显示实时更新。
在探索了许多可视化工具之后,我决定使用 Dash。
Dash 是一个开源库,允许您用 Python 创建交互式 web 应用程序。
如果您经常使用 Python 来构建数据可视化,Dash 是您的理想工具。您可以围绕您的数据分析创建一个 GUI,并允许用户使用您的仪表板应用程序。
Dash 最棒的地方在于它允许你纯粹用 Python 来构建这些东西。您可以创建 web 组件,而无需编写任何 HTML 或 Javascript 代码。
在本教程中,我将展示如何用 Dash 创建一个简单的数据可视化应用程序。
最终产品将如下所示:
作者图片
步骤 1:先决条件
在我们开始构建应用程序之前,您需要具备:
- Python IDE:我使用 Visual Studio 代码进行分析,但是任何 Python IDE 都可以使用(除了 Jupyter 笔记本)。
- 库:安装 Dash、Pycountry、Plotly 和 Pandas
- 数据:我使用 Zomato Kaggle 数据集来构建 web 应用程序。我对数据集做了一些修改,使其适合这个分析,你可以在这里找到预处理版本。
步骤 2:构建仪表板
首先,让我们导入构建应用程序所需的所有库:
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
import plotly.graph_objs as go
import plotly.express as px
import numpy as np
import pandas as pd
如果上面几行代码执行成功,干得好!所有的装置都工作正常。
就在导入的下面,添加这行代码以在 Dash 应用程序中包含 CSS 样式表:
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
然后,让我们初始化 Dash:
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
server = app.server
现在,我们可以用下面几行代码将数据帧读入 Pandas:
df = pd.read_csv('restaurants_zomato.csv',encoding="ISO-8859-1")
数据帧的头看起来像这样:
作者图片
该数据框由餐厅数据组成,即每家餐厅的名称、位置、评级和受欢迎程度。
我们将在 Dash 应用程序中可视化这些数据。
我们将创建三个图表显示在我们的 Dash 应用程序上——一个地图,一个条形图,以及一个饼图。
先说地图。
我们将按国家显示数据集中的餐馆数量。最终产品将如下所示:
作者图片
为此,我们将使用数据集中的' country_iso' '列。我们需要计算每个国家的餐馆数量,并创建一个新的“ count ”列,这可以用下面几行代码来完成:
# country iso with counts
col_label = "country_code"
col_values = "count"
v = df[col_label].value_counts()
new = pd.DataFrame({
col_label: v.index,
col_values: v.values
})
太好了!现在,我们可以创建包含*【国家/地区 _ iso】和计数*列的地图:
hexcode = 0
borders = [hexcode for x in range(len(new))],
map = dcc.Graph(
id='8',
figure = {
'data': [{
'locations':new['country_code'],
'z':new['count'],
'colorscale': 'Earth',
'reversescale':True,
'hover-name':new['final_country'],
'type': 'choropleth'
}],
'layout':{'title':dict(
text = 'Restaurant Frequency by Location',
font = dict(size=20,
color = 'white')),
"paper_bgcolor":"#111111",
"plot_bgcolor":"#111111",
"height": 800,
"geo":dict(bgcolor= 'rgba(0,0,0,0)') }
})
上面几行代码将创建地图,并根据列出的餐馆数量给每个区域着色。
现在,我们可以开始创建条形图了。
如果您查看上面显示的地图,印度在数据框中拥有最多的餐厅。数据框中列出的 8,155 家餐厅位于印度。
让我们用下面几行代码来看看印度最受欢迎的餐馆:
df2 = pd.DataFrame(df.groupby(by='Restaurant Name')['Votes'].mean())
df2 = df2.reset_index()
df2 = df2.sort_values(['Votes'],ascending=False)
df3 = df2.head(10)
bar1 = dcc.Graph(id='bar1',
figure={
'data': [go.Bar(x=df3['Restaurant Name'],
y=df3['Votes'])],
'layout': {'title':dict(
text = 'Top Restaurants in India',
font = dict(size=20,
color = 'white')),
"paper_bgcolor":"#111111",
"plot_bgcolor":"#111111",
'height':600,
"line":dict(
color="white",
width=4,
dash="dash",
),
'xaxis' : dict(tickfont=dict(
color='white'),showgrid=False,title='',color='white'),
'yaxis' : dict(tickfont=dict(
color='white'),showgrid=False,title='Number of Votes',color='white')
}})
上面的代码将呈现一个如下所示的条形图:
(注意,在完成所有组件的创建和显示之前,您还不能运行代码)
作者图片
让我们创建最终的图表。
我们将查看数据集中的总体评分分布:
col_label = "Rating text"
col_values = "Count"
v = df[col_label].value_counts()
new2 = pd.DataFrame({
col_label: v.index,
col_values: v.values
})
pie3 = dcc.Graph(
id = "pie3",
figure = {
"data": [
{
"labels":new2['Rating text'],
"values":new2['Count'],
"hoverinfo":"label+percent",
"hole": .7,
"type": "pie",
'marker': {'colors': [
'#0052cc',
'#3385ff',
'#99c2ff'
]
},
"showlegend": True
}],
"layout": {
"title" : dict(text ="Rating Distribution",
font =dict(
size=20,
color = 'white')),
"paper_bgcolor":"#111111",
"showlegend":True,
'height':600,
'marker': {'colors': [
'#0052cc',
'#3385ff',
'#99c2ff'
]
},
"annotations": [
{
"font": {
"size": 20
},
"showarrow": False,
"text": "",
"x": 0.2,
"y": 0.2
}
],
"showlegend": True,
"legend":dict(fontColor="white",tickfont={'color':'white' }),
"legenditem": {
"textfont": {
'color':'white'
}
}
} }
)
由上述代码创建的饼图将如下所示:
作者图片
现在我们已经创建了所有三个图表,让我们在网页上显示它们并运行 Dash 应用程序。
我们首先需要想出我们的 web 应用程序的页面布局和结构。
Dash 组件遵循网格结构(类似于 CSS 网格布局)。Dash 有三个核心组件——行、列和容器。
您可以以任何方式排列这些组件,以适合页面上的元素。
因为我们只有三张图表,所以我想出了这个简单的布局:
作者图片
对于这些图表,我们将只使用两行,第二行将有两列来容纳条形图和饼图。
下面是在 Dash 中创建这样的布局的一些代码:
graphRow1 = dbc.Row([dbc.Col(map,md=12)])
graphRow2 = dbc.Row([dbc.Col(bar1, md=6), dbc.Col(pie3, md=6)])
我们现在需要做的就是定义我们的应用程序布局并运行服务器:
app.layout = html.Div([navbar,html.Br(),graphRow1,html.Br(),graphRow2], style={'backgroundColor':'black'})
if __name__ == '__main__':
app.run_server(debug=True,port=8056)
默认情况下,Dash 在端口 8050 上运行。如果正在使用,您可以手动指定要运行它的端口。
我们已经完成了仪表板应用程序的编码。
只需运行 Python 应用程序并导航至仪表盘位置,您将看到您的可视化效果:
作者图片
下面是这个 Dash 项目的完整代码:
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
import chart_studio.plotly as py
import plotly.graph_objs as go
import plotly.express as px
external_stylesheets =['https://codepen.io/chriddyp/pen/bWLwgP.css', dbc.themes.BOOTSTRAP, 'style.css']
import numpy as np
import pandas as pd
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
server = app.server
df = pd.read_csv('restaurants_zomato.csv',encoding="ISO-8859-1")
navbar = dbc.Nav()
# country iso with counts
col_label = "country_code"
col_values = "count"
v = df[col_label].value_counts()
new = pd.DataFrame({
col_label: v.index,
col_values: v.values
})
hexcode = 0
borders = [hexcode for x in range(len(new))],
map = dcc.Graph(
id='8',
figure = {
'data': [{
'locations':new['country_code'],
'z':new['count'],
'colorscale': 'Earth',
'reversescale':True,
'hover-name':new['country_code'],
'type': 'choropleth'
}],
'layout':{'title':dict(
text = 'Restaurant Frequency by Location',
font = dict(size=20,
color = 'white')),
"paper_bgcolor":"#111111",
"plot_bgcolor":"#111111",
"height": 800,
"geo":dict(bgcolor= 'rgba(0,0,0,0)') } })
# groupby country code/city and count rating
df2 = pd.DataFrame(df.groupby(by='Restaurant Name')['Votes'].mean())
df2 = df2.reset_index()
df2 = df2.sort_values(['Votes'],ascending=False)
df3 = df2.head(10)
bar1 = dcc.Graph(id='bar1',
figure={
'data': [go.Bar(x=df3['Restaurant Name'],
y=df3['Votes'])],
'layout': {'title':dict(
text = 'Top Restaurants in India',
font = dict(size=20,
color = 'white')),
"paper_bgcolor":"#111111",
"plot_bgcolor":"#111111",
'height':600,
"line":dict(
color="white",
width=4,
dash="dash",
),
'xaxis' : dict(tickfont=dict(
color='white'),showgrid=False,title='',color='white'),
'yaxis' : dict(tickfont=dict(
color='white'),showgrid=False,title='Number of Votes',color='white')
}})
# pie chart - rating
col_label = "Rating text"
col_values = "Count"
v = df[col_label].value_counts()
new2 = pd.DataFrame({
col_label: v.index,
col_values: v.values
})
pie3 = dcc.Graph(
id = "pie3",
figure = {
"data": [
{
"labels":new2['Rating text'],
"values":new2['Count'],
"hoverinfo":"label+percent",
"hole": .7,
"type": "pie",
'marker': {'colors': [
'#0052cc',
'#3385ff',
'#99c2ff'
]
},
"showlegend": True
}],
"layout": {
"title" : dict(text ="Rating Distribution",
font =dict(
size=20,
color = 'white')),
"paper_bgcolor":"#111111",
"showlegend":True,
'height':600,
'marker': {'colors': [
'#0052cc',
'#3385ff',
'#99c2ff'
]
},
"annotations": [
{
"font": {
"size": 20
},
"showarrow": False,
"text": "",
"x": 0.2,
"y": 0.2
}
],
"showlegend": True,
"legend":dict(fontColor="white",tickfont={'color':'white' }),
"legenditem": {
"textfont": {
'color':'white'
}
}
} }
)
graphRow1 = dbc.Row([dbc.Col(map,md=12)])
graphRow2 = dbc.Row([dbc.Col(bar1, md=6), dbc.Col(pie3, md=6)])
app.layout = html.Div([navbar,html.Br(),graphRow1,html.Br(),graphRow2], style={'backgroundColor':'black'})
if __name__ == '__main__':
app.run_server(debug=True,port=8056)
您可以摆弄代码,尝试改变图表的颜色和布局。您甚至可以尝试使用上面的数据集创建新行和添加更多图表。
Dash 有比我在本教程中提到的更多的功能。您可以创建过滤器、卡片,并添加实时更新数据。如果你喜欢这篇教程,我会写另一篇介绍 Dash 更多特性和功能的文章。
感谢您的阅读,祝您有美好的一天:)
本文原载此处。
构建群组分析的数据应用程序
原文:https://towardsdatascience.com/build-a-data-app-for-cohort-analysis-5d4e3161a988?source=collection_archive---------19-----------------------
进行群组分析的分步指南,关注技术而不是代码
作者图片
群组分析是一个强大的工具,它使公司能够更好地了解客户的需求和习惯。我们可以通过将具有相似属性(例如,注册日期、首次购买日期、潜在客户来源等)的用户或客户分组来收集有价值的见解。)然后观察关键绩效指标(KPI 例如,参与度、产生的收入、留存)。
下面是一个消费者应用留存的群组分析热图示例。该应用程序的用户被分组到注册月的队列中,他们的保留率是按周观察的。
作者图片
每一个水平行代表一个不同的用户群体,每一个方块代表该群体在注册后一周内的留存率。例如,我们可以看到,在注册 4 周后,该应用对 2018 年 2 月注册的用户有 49%的保留率,而对 2018 年 7 月注册的用户来说,同样的 4 周保留率只有 20%。
研究这种模式有助于发现与业务相关的系统问题,或者反过来,有助于验证随着时间的推移所做的更改。
虽然有许多文章谈到用 python 或 R 或 FORTRAN 执行群组分析,但没有一篇文章关注实际技术。
注意:在这里,虽然所有的分析都发生在 【交集】 (一个让你构建 数据应用 来自动化重复数据任务的平台),你可以用你喜欢的工具或语言来重复这些步骤。
数据描述
所用数据*:*https://archive.ics.uci.edu/ml/datasets/Online+Retail+II
该零售数据集包含一家英国在线零售店在 2009 年 12 月 1 日至 2012 年 12 月 9 日之间的所有交易。该公司主要销售独特的、适合各种场合的礼品。
数据集中的每一行都是客户订购的单独行项目。具有相同发票号(第一列)的行项目是同一订单的一部分。InvoiceDate 是购买的日期/时间,Customer ID 是每个客户的唯一标识符。
数据快照:
作者图片
我们主要感兴趣的是跟踪按月分组的客户保持率,换句话说,对于每个客户分组(按首次购买的月份分组),在首次购买后的每个月中重复下单的百分比是多少?
数据准备
缺少客户 id
数据集包含一些缺少客户 ID 的行。如果我们有办法知道它们代表什么,我们会估算值,但不幸的是,在不了解更多业务的情况下,我们所能做的就是删除这些行。
作者图片
负量
一些订单的数量为负;这样的订单最有可能是退货。返回并不是真正的约定,所以我们也删除了这些行。有人可能会说,我们还应该删除这些最终退货所附带的原始订单。然而:
- 我们不知道如何识别这些订单
- 即使我们这样做了,导致退货的订单仍然是客户的约定,因此对我们的目的有意义
为了减轻这种情况,我们筛选数量> 0 的行的数据。
作者图片
汇总成订单
如上所述,每张发票可以有多行,因为每一行对应一个单独的项目。但是,对于合约,我们感兴趣的是分析订单,而不是订单中的单个项目。我们汇总这些项目来管理不同订单的列表。
作者图片
断代分析
计算每个用户所属的群组
在这一部分中,我们确定了每位客户下第一笔订单的月份(即他们的群体)。
首先,我们按发票日期的升序排序,并计算第一个订单的日期:
作者图片
接下来,我们从该日期中提取月份名称和年份,并连接这些列以形成“群组名称”列。
作者图片
最后,我们将得到的数据集连接到上面的“Orders”数据集,以向其中添加“cohort name”列。
作者图片
生成群组分析表
接下来,对于每个订单,我们计算下订单的周期(订单月份—同期月份)。
作者图片
生成的输出如下所示(注意末尾的 period 列):
作者图片
最后,我们透视我们的表以生成群组分析报告,其中每行是一个单独的群组,每列显示随后几个月的保留情况。
作者图片
在对列和行进行快速排序后,我们得到了群组分析表
作者图片
这向我们展示了每个月每个群体中的回头客数量。但是,为了将这些值转换成百分比,我们将每一列除以第一列,然后乘以 100。
生成热图
最后,我们将表格转换成热图,以快速识别模式。右边的图例告诉我们,盒子越接近红色,保留值越高(越热),反之亦然,保留值越低的盒子越接近蓝色。
大约一半的方块是蓝色的,因为我们还没有这些群体的数据。
作者图片
有趣的见解
马上,我们注意到 2010 年 12 月的队列包含了第 11 个月的高回报(大概对应于第二年的假期)。我们在每个队列中都看到类似的峰值,但是没有一个像第一个队列那么高。这批人有什么特别之处吗?也许,这群人本质上由假日购物者组成,他们更倾向于在每个假日季节回来!
如果你想让用户/顾客再次光顾你的生意,你必须定期研究他们的群体和习惯。
为你的下一个时间序列数据科学项目在云上构建一个数据收集应用
原文:https://towardsdatascience.com/build-a-data-collection-app-on-the-cloud-for-your-next-time-series-data-science-project-71e6d6291a70?source=collection_archive---------38-----------------------
使用 Python 和 PostgreSQL 在 Heroku 上构建和部署数据收集应用程序的分步指南
注:本帖代码可在 这里 找到
计划的数据收集应用程序工作流(图片由作者提供)
尽管近年来观察到数据激增,但我们经常发现自己被项目数据的缺乏所阻碍。在典型的一天网页浏览中,我们会遇到无数的信息(数据),这些信息可能会产生伟大的数据科学想法,如当前天气、交通、灾难预警、股票价格、投票计数、covid 计数、浏览量计数、社交媒体评论等等。我们知道数据得到维护并可供公众使用,但很少有方便的汇编。在本文中,我们将一步一步地介绍使用 Python 中的 RDMS ( 关系数据库管理系统)开发和部署数据收集应用程序。意识到根据收集的数据不同,各个脚本可能会有很大的不同,我们采用的方法是遍历一个简单的示例,同时为每个步骤提供充分的推理:
开发步骤
这个演示应用程序将由一个收集公共可用数据快照的脚本和一个定期调用收集脚本的调度程序组成。应用程序可以选择性地部署在云上,这提供了可靠性和可用性(以及其他好处)。我们选择了 Heroku 进行部署,这是一个平台即服务( PaaS ),使开发者能够完全在云端构建、运行和操作应用。
定义目标和目的
有许多不同的方式来获取数据:API 请求、web 抓取以及介于两者之间的任何方式。项目的第一步是确定可靠的数据源。我们的灵感来自于开放数据,这是一个想法,即一些数据应该免费提供给每个人,让他们随心所欲地使用。它的目标类似于其他“开放(源代码)”运动,如开源软件。有趣的是,美国联邦和地方层面的公共部门在数据透明方面取得了巨大进步。我们使用来自 511.orghttps://511.org/open-data/traffic的数据进行演示。它们为当前交通事件提供了一个方便的 API(参见文档)。 API 密钥需要注册,请求受发行方的费率限制。一旦接收到,响应就会以 JSON 格式出现,我们可以用它来提取有用的数据。我们感兴趣的是捕捉仅具有以下属性的单个交通事件。通过开发一个自动化脚本,我们希望收集所有交通事件的汇编。
one_record={'**id**': '511.org/721616'
'**headline**': 'Caltrans Bridge work...',
'**event_type**': 'CONSTRUCTION',
'**severity**': 'Unknown',
'**lat**': -122.241176,
'**lon**': 38.483586}
创建 GitHub 存储库并设置虚拟环境
Git 是一个免费开源的分布式版本控制系统。它跟踪对项目所在的存储库中的文件所做的所有更改。GitHub 是一个 Git 存储库托管平台,允许开发者为开源和私有项目构建软件。包括 Heroku 在内的许多平台都支持与 GitHub 的集成,从而简化了代码部署。
更多关于 Git 和基本用法的信息可以在 这里 找到。我们将在 GitHub 上为这个项目创建一个远程存储库,并使用$ **git clone "**[**https://github.com/[github_name]/[repo_name].git**](https://github.com/[github_user_name]/[repo_name].git)**”**
将其克隆到我们的本地机器上。使用$ **cd [repo_name]**
更改目录,以确保命令是针对作为根的新存储库执行的。
接下来,我们将为项目创建一个虚拟环境**。虚拟环境的主要目的是为项目创建隔离的环境。这意味着每个项目都可以有自己的依赖项,不管其他项目有什么依赖项。同样,在开发具有特定需求的应用程序时,虚拟环境也很重要。**
虚拟环境
用$ **conda create --name env_name python=3.6**
创建一个新环境,用$ **conda activate env_name**
激活。注意,我们用**python=3.6**
指定了新环境,以包括 pip (在 3.4 中添加了Python的包安装程序)和 f 字符串(在 3.6 中添加了格式化字符串文字**)。在此项目目录/存储库中安装应用程序和运行命令时,应该激活此环境。由于这是一个新环境,所有的依赖项都需要通过$ **pip install**
安装,然后才能导入。使用$ **conda deactivate**
停用虚拟环境。**
我们还需要为应用程序设置环境变量**。环境变量被认为是 操作系统 的一部分,存在于任何特定脚本之外。我们可以使用环境变量来隐藏敏感的凭证,比如 511 API 密钥。它们可以在我们部署时在主机上设置,但也需要在本地可用以进行开发。这些变量应该被限制在项目的范围内,所以我们真正需要的是“临时的”环境变量。幸运的是,我们可以使用python-dotenv从.env
文件中读入键值对,并在运行时将它们设置为环境变量。这允许我们开发我们的脚本,就像环境变量已经设置好了一样。应该将.env
文件添加到.gitignore
中,这样它就不会包含在本地或远程的 git 提交中。**
$ **echo "FIVEONEONE_TOKEN=[api_key]" > .env** $ **echo ".env" >> .gitignore**
环境变量比脚本更安全
开发数据收集脚本和数据库
在这一步中,我们将创建一个脚本来从数据源获取一次数据。在本演示中,我们使用分配的 api_key 向指定的端点发出请求。
fetch.py
我们实现了对请求成功与否的条件检查。一旦收到,响应包含 JSON 格式的数据。具体来说,我们对 JSON 的events
键中的活动交通事件的列表感兴趣。在安装必要的依赖项后,我们可以用$ **python fetch.py**
测试这个脚本:
$ **pip install requests**
$ **pip install python-dotenv**
接下来我们想把数据保存在数据库中,但是我们必须先做一点数据库工程。在这一步中,我们要充分考虑数据的大小以及如何使用数据。一般有两种类型的数据库: SQL 和 NoSQL 。相比之下,SQL 数据库需要更多的工作来建立,但当数据有一个定义的模式时是合适的。因为它与我们的数据相关——假设我们已经确定了想要收集的属性子集,那么使用 SQL 数据库是有意义的。我们将得到一个“事件”表,其中每个行代表一个事件,每个列代表一个感兴趣的属性。
SQL 数据库上的示例事件表
换句话说,从我们收到的 JSON 中的交通事件列表开始,我们将遍历每个元素并解析出我们感兴趣的属性。我们可以使用 SQLAlchemy 库在 Python 中使用 SQL。SQLAlchemy 是一个 Python SQL toolkit 和对象关系映射器,可以实现 SQL 的全部功能。****
在将记录存储到数据库之前,我们必须定义表模式。使用 声明性 将该模式映射到一个 Python 类,因此每个记录将被表示为其实例。
models.py
我们在一个单独的脚本models.py
中布置数据库表的模式,稍后我们可以调用这个脚本来创建表和记录。请注意,SQLAlchemy ORM 要求每个表都有一个主键。
将fetch.py
脚本修改为fetch_insert.py
到 1) 连接到数据库, 2) 基于models.py
创建表, 3) 遍历响应中的每个元素/解析出感兴趣的属性,并且 4) 创建要插入到数据库中的映射 Python 类的实例。
获取 _ 插入. py
我们使models.py
成为依赖**(如from models import *
)来加载模式以创建表和记录。**
使用 SQLAlchemy 从在数据库 url 建立连接开始。当没有DATABASE_URL
环境变量存在时,我们编写脚本来连接到单个文件 SQLite 数据库。我们将 SQLite 用于开发和备份目的,因为它是独立的、功能齐全的。像 Postgres 这样的 DB 服务器通常是首选,因为它支持可用性和可靠性**。一旦我们将生产数据库 url 作为一个环境变量添加,它将优先建立数据库连接。我们应该将数据库 url 视为环境变量,因为它包括用户名、密码、主机名和数据库名。**
[sqlalchemy.create_engine()](https://docs.sqlalchemy.org/en/14/core/engines.html#sqlalchemy.create_engine)
和Base.metadata.create_all()
的典型用法是每个特定的数据库 URL 使用一次,在单个应用程序进程的生命周期内全局保存。单个[Engine](https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.Engine)
代表流程管理许多单独的 DBAPI 连接,并且旨在以并发方式被调用。如果表已经存在,SQLAlchemy 不会尝试重新创建它们。
一旦请求返回了响应,我们就遍历事件列表来收集表记录的数据。在 SQLAlchemy 中,记录作为映射到 SQL 表的 Python 类的实例被添加和操作。**
操作符允许我们获取一个键值对字典,并将其解包为Events()
构造函数的关键字参数。
一旦记录被添加和提交,我们使用session.close()
将资源交还给引擎的连接池。这不应该与engine.dispose()
混淆,后者关闭连接池的所有连接。
至此,我们已经构建了一个脚本来收集数据并将记录存储到 SQL 数据库中。我们可以使用$ **python fetch_insert.py**
(在安装完依赖项之后)测试应用程序,这将创建一个新的 SQLite 文件作为数据库,如果它还不存在的话。
$ **pip install sqlalchemy**
$ **pip install psycopg2**
添加调度程序
我们可以安排数据获取过程按时间间隔运行,从而使我们能够持续收集数据。APS Scheduler(高级 Python 调度器)是一个 Python 库,它让用户调度 Python 代码稍后执行,要么只执行一次,要么定期执行。它易于使用,并与其他有用的框架集成。****
调度程序
很方便,Heroku 在他们的 自定义时钟进程 的实现中使用了 APScheduler。在他们的文档中,他们解释说主要有四个组件来促进作业的调度。在主程序中,用户选择一个调度器和一个作业存储器。调度器负责根据触发器将作业添加到作业库中,而执行器处理作业的运行。
clock.py
使用 APScheduler 调度作业很容易——我们在clock.py
中展示的基本实现从定义一个调度器和作业存储(默认为BlockingScheduler()
和MemoryJobStore()
)开始,它们充当运行应用程序的主要过程。接下来,使用包含调度逻辑的特定触发器添加作业。我们通过用scheduled_job()
和调用数据收集脚本的interval
触发器来装饰 函数来做到这一点。从技术上讲,该过程应该被描述为在计算的延迟之后重新执行。为了管理与数据库的连接,我们在主程序中创建引擎连接,并将其传递给收集脚本。我们必须再次将fetch.py
脚本重构为fetch_job.py
来适应这个实现。
fetch _ 作业. py
数据收集脚本被封装在函数fetch_data
中,因此可以很容易地调用它,并接受数据库连接作为参数。对于每个计划的“获取”作业,在关闭之前,会与数据库建立一个会话,直到所有插入操作完成。在安装新的依赖项后,我们可以用$ **python clock.py**
测试这个应用程序。
**$ **pip install apscheduler****
设置 Heroku 应用程序并添加配置文件
此时,数据收集应用程序以固定的时间间隔“自动”执行,但仅在应用程序处于本地活动状态时执行。我们可以将应用程序部署到 Heroku 来消除这种依赖性。
本次演示避免使用 Heroku 命令行界面 ( CLI )以保持部署简单。首先,在 Heroku 上创建一个新的应用程序。登录( #1 )后,转到“创建新应用”( #3 )并给应用一个唯一的名称以完成创建。Heroku 提供了与 GitHub 的便捷集成,以无缝加载代码进行部署。一旦通过验证( #5 ),开发人员就可以通过名称( #7 )进行搜索,并将应用程序的源代码连接到相应的存储库( #8 )。
设置 Heroku 应用程序
在部署之前,我们必须更新 GitHub 上的源代码,但我们必须首先配置几个设置: Postgres 数据库、配置变量、 requirements.txt 和 Procfile 。
Heroku 应用程序的 Postgres 数据库附件
Heroku 免费提供了一个 Postgres 插件(有限制)——一个单独的数据库比用于开发的 SQLite 本地数据库更好,因为它支持应用程序之外的访问。
在 Heroku 上,进入应用程序主页的资源部分( #1 )。在附加组件下,搜索“Heroku Postgres”(# 2&# 3)。接下来选择适当的计划(Hobby Dev-Free 计划提供多达 10k 行的数据)并进行配置。
Heroku-Postgres 附加软件
Heroku 构型
我们必须将 API 键和数据库 URL 设置为环境变量,以防止它们被暴露。从仪表板页面,导航至设置( #1 )并点击“显示配置变量”( #2 )。数据库的连接字符串自动添加到DATABASE_URL
( #3 )下。这可以用来连接到数据库(在这个项目之外)。我们必须手动添加 api_key ( #4 )作为环境变量( #5 )。
设置配置变量
要将应用程序部署到 Heroku,还需要两个文件:1) requirements.txt
和 2) [Procfile](https://devcenter.heroku.com/articles/procfile)
。这将有助于 Heroku 配置托管应用程序的服务器。我们必须在存储库中手动创建这些文件,它们必须位于根目录下,这样 Heroku 才能在部署过程中找到它们。
- requirements . txt—列出运行应用程序所需的所有依赖项和包。要创建 requirements.txt 文件,运行项目目录中的
$ **pip freeze > requirements.txt**
命令。这将把活动环境中安装的所有库的列表写入 requirements.txt 文件。这有助于 Heroku 为应用程序安装相同的依赖项。 - Procfile —告诉 Heroku 如何运行应用程序,并声明启动应用程序应该执行什么命令。要创建 Procfile 文件,运行项目目录中的
$ **echo "clock: python clock.py" > Procfile**
。请注意,Procfile 是一个没有文件扩展名的简单文本文件。
Procfile 在单独的行上声明应用程序进程类型,每一个都具有格式<process type>: <command>
,其中process type
是原型,从该原型实例化一个 dyno 。Dynos 是提供计算机、内存、操作系统和临时文件系统的容器,旨在根据用户指定的命令执行代码。
鉴于演示应用程序的简单性,一个时钟 dyno 就足够了。注意,对于我们的用例,在 Procfile 中,clock
或worker
流程类型声明都可以。选择使用clock
进程类型是为了表明clock.py
是一个调度应用程序,它是一个单独的进程,不应该扩展到多个进程,以防止任务重复。
另外,在我们的实现中,Dyno 负责调度和执行作业。根据数据收集脚本的复杂性和作业的频率,可能需要使用单独的 worker dynos(不在本项目范围内)。
对于简单的工作,一个时钟 Dyno 就足够了
正确的 Postgres 数据库 URL(3 月编辑)
由于 SQLAlchemy 在 2021 年 3 月弃用了postgres
方言,我们不得不手动更新 Heroku 的 DATABASE_URL 环境变量。不幸的是,它不能在 Heroku 操作系统级别更新,因为它是由附加组件生成的。相反,我们可以给clock.py
添加一个简单的String.replace()
语句来适应这种变化。
**SQLALCHEMY_DATABASE_URI=SQLALCHEMY_DATABASE_URI.replace('postgres://', 'postgresql://')**
部署到 Heroku
一旦创建了两个配置文件( Procfile 和 requirements.txt ),将所有工作文件保存在存储库中,然后将它们添加/提交/推送至远程存储库。
**$ **git add .**
$ **git commit -m 'ready to deploy'** $ **git push****
一旦代码被推送到 GitHub,我们就可以在 Heroku 部署它。在部署页面( #1 )中,选择要部署的分支(# 2)(# 3)。Heroku 将开始构建应用程序。
部署
我们要做的最后一件事是在 Heroku 对 dyno 进行缩放。回到资源页面( #1 ),现在应用程序已经部署完毕,已经识别出了clock
dyno。它需要扩大规模并保持扩大规模,以便保持运行并确定调度作业的合适时间( #2 、 #3 和 #4 )。
将时钟动态缩放至 1
摘要
在本文中,我们逐步介绍了数据收集应用程序的创建。我们还使用 Heroku 将它部署到云中。我希望这对你有帮助。我的希望是激励更多的人分享他们的想法(和数据),这些想法和数据是他们努力为其他人合作策划的。
接下来,我们将创建一个监控工具,并为我们的应用程序构建一个时序机器学习模型。如果你喜欢这篇文章,我邀请你跟我来,这样你就可以得到这个项目继续的通知。
如何用 PySpark & Faker 创建 JSON 数据流
原文:https://towardsdatascience.com/build-a-data-streaming-job-in-5-mins-with-pyspark-faker-a4f3d2420384?source=collection_archive---------11-----------------------
在本教程中,您将学习如何生成 JSON 格式的实时数据流,将文件存储在 AWS S3 桶中,以及使用 Python (Spark)动态聚合数据。
Evgeny Tchebotarev 在像素上拍摄的照片
建议的点播课程
我的一些读者联系我,要求提供点播课程,以了解更多关于Apache Spark的信息。这是我推荐的 3 个很好的资源:
- 用阿帕奇 Kafka 进行数据流&阿帕奇 Spark nano degree(uda city)
- 数据工程纳米学位(Udacity)
问题:生成流数据集
如果您熟悉 PySpark 及其结构化流 API,您就会知道将流作业表示为标准批处理作业是多么容易,不同之处在于数据流可以被视为一个不断追加的表。
尽管以简单明了的方式编写了一个流处理模型,但是寻找流数据源可能是一项具有挑战性的任务,尤其是在部署应用程序之前测试应用程序,或者在学习 PySpark 时设置第一个流作业。
为了让你的工作生活更轻松,学习过程更快,在本教程中,我将向你展示如何使用 Python 的faker
和random
包产生一个模拟数据流,以 JSON 格式序列化。
此外,您将学习如何将数据流保存在 S3 桶中(免费),然后使用 PySpark 动态读取和聚合数据流。所有这些步骤只需要 5 分钟。
先决条件和安装
为了快速完成这一过程,在您进一步阅读之前,我建议您:
- 在 AWS 上创建一个免费账户以及一个 IAM 用户。记得把
ACCESS KEY ID
和SECRET ACCESS KEY
都留着以后用。设置您的 IAM 用户,使其拥有一个AmazonS3FullAccess
。 - 安装
boto3
包并创建一个配置文件,以编程方式使用上面生成的两个密钥。 - 访问 Databricks 的社区版,然后配置一个标准集群并将其连接到您将运行 PySpark 代码的笔记本上。即使您以前没有使用该平台的经验,这项任务也应该相当直观。
- 安装剩余的软件包,其中有
faker
、random
、uuid
和json
。
如果是第一次在S3
创建 IAM 用户,以及config
文件,建议先看一下本教程的第一段。
一旦你完成了这些安装(大约需要 30-45 分钟),你就可以开始生成一个模拟数据流了!
创建您的数据生产者
第一步是使用以下命令创建一个带有boto3
(在本例中为data-stream-dump
)的S3
桶:
然后,我创建一个名为Transaction
的data class
( 如果数据类和装饰器对你来说是一个新概念,请看 本教程 ),它由 3 个字段组成:
username
是一个字符串,将通过调用faker.user_name
随机生成;currency
是一个字符串,在属于currencies
列表的字符串中取一个随机值。我将货币限制为 3 种,以使稍后在 PySpark 中执行的聚合更加明显,但是您也可以使用faker.currency
生成随机货币。amount
也是一个字符串,被定义为介于100
和200,000
之间的随机整数。
我现在可以使用Transaction
来定义一个serialize(self)
方法(是的,您可以将方法定义为数据类的一部分),它有效地用于将这 3 个字段格式化为一个字典:
现在每次我打电话:
print(Transaction().serialize())
我得到一个假的银行交易,由一个假的username
在一个假的currency
和一个假的amount
中创建:
{‘username’: ‘jjohnson’, ‘currency’: ‘GBP’, ‘amount’: 102884}
使用数据类和 faker 包很酷的一点是,您可以不断增加或改变字段的数量和类型,以满足您的特定需求。
使用数据类和 faker 包很酷的一点是,您可以不断增加或改变字段的数量和类型,以满足您的特定需求。
我终于准备好定义一个Producer()
函数,并将其传递给一个运行 100 次的循环:
每次调用Producer()
函数时,它都会以json
格式将单个事务写入一个文件(上传到 S3 ),该文件的名称采用标准根transaction_
加上一个uuid
代码,以使其唯一。
在这种情况下,循环将生成 100 个文件,每个文件之间的间隔为 3 秒,以模拟真实的数据流,其中流应用程序监听外部微服务。
完整的代码,直到这一点是可用的在这里。我将很快编译它,但在此之前,我需要先创建一个流作业。
在数据砖的 FS 中安装你的 S3 桶
我的流作业将写在 DataBrick CE 笔记本中,如下所示:
如果您希望您的流作业监听 S3 存储桶中发生的事情,您需要将您的亚马逊 S3 存储桶作为文件系统“挂载”。
挂载是指你可以使用 Databricks 的平台“ ”与亚马逊 S3 桶进行交互,对文件和文件夹 进行读写操作。
有一些关于如何在 Databricks 中挂载文件系统的文档,但是它们让您相信只有获得高级许可才有可能。原来,在这篇伟大的文章 中,Sneha Mehrin 找到了一个非常简单的方法来解决这个问题。
你需要做的一切,就是在你的笔记本上运行下面的代码(记住使用你在本教程开始时保存的 2 个键):
如果您没有得到任何错误,这意味着您的 S3 文件系统已经正确挂载,但是,因为您的 bucket 仍然是空的,所以您不会通过运行以下命令看到任何文件:
%fs ls /mnt/s3Data/ # --> where /s3Data is the folder name
相反,如果您很好奇并且已经运行了Producer()
函数(希望少于 100 次迭代:D ),您将会看到这种类型的文件结构:
一旦生成器运行,您将看到装载的 bucket 的文件结构。
最后,用 PySpark 写一些代码就都设置好了!
创建 Spark 会话并定义模式
首先,我定义了一个SparkSession
( 在 Databricks CE 中不是必需的,但是很好的实践),然后我手动声明了在使用readStream
读取文件时必须提供的数据流模式(JSONschema
):
请注意,Producer()
函数已经将字典转换为 JSON 文件,因此在 PySpark 中,金额类型现在被读取为LongType()
整数。
消耗数据流并在内存中输出
下面我要做的是读取挂载文件夹中以transactions
根目录开始的所有文件,然后将它们保存到ds
DataFrame:
如果ds.isStreaming
为True
,则表示流处理处于活动状态。
然后,我希望通过currency
计算总数amount
,因此我只从ds
中选择这两个字段,并执行简单的聚合(将其保存到trxs
最终,我只需要开始将trxs
写成一个流,并保存在memory
(对于本教程的范围来说已经足够了)。因为我正在执行聚合,所以我必须使用complete
作为outputMode
。注意,写入存储器的流被命名为transactions_stream_output:
现在,我要做的第一个操作是运行 PySpark 代码,开始读写一个流。这是因为它可能需要 30 秒,所以在此期间你可以跳到别的东西上。
我要执行的第二个操作是运行第一个生成数据的 Python 脚本。当您这样做时,您会看到屏幕上出现编号的迭代:
您将看到每 3 秒钟出现一次迭代(PyCharm)
此外,如果您检查您的 S3 用户界面,您会看到文件被写入桶:
用事务文件填充的 S3 时段。
现在回到数据砖笔记本。希望您应该看到流处于活动状态,并且随着新文件写入 S3 并被流作业读取,图形会不断变化:
Databricks 的数据流仪表板。
PySpark 的一个很酷的特性是,您可以使用 SQL 轻松查询由流作业创建的内存表。如您所见,每次在 S3 写入新文件并由流式作业处理时,表中保存的聚合都会更新:
查询 1:在执行了 10 次迭代之后。
查询 2:在执行了 20 次迭代之后。total_amount 持续增长!
结论
恭喜你!如果您已经做到了这一点,那么您已经成功地在 PySpark 中构建了一个工作数据流作业,该作业从一个 S3 桶中读取 JSON 文件(,每个文件包含一个模拟银行事务,并将它们写入内存表中。
既然您已经知道如何构建一个动态数据类(使用field()
和defaulty_factory
参数),那么您可以扩展这个概念并创建自己的流数据集。极限只是你的创意!
如果你觉得这个教程有用,请留下一些掌声,或者如果你想阅读更多类似主题的教程,请跟我来:D
使用 Arduino、Python 和 Streamlit 构建一个 DIY 迷你雷达
原文:https://towardsdatascience.com/build-a-diy-mini-radar-using-arduino-python-and-streamlit-c333006681d7?source=collection_archive---------28-----------------------
如何建立一个廉价的迷你雷达系统与现场仪表板
迷你雷达仪表板。作者视觉。
介绍
对于我们这些从事机器人行业的人来说,特别是像相扑和机器人足球机器人这样的竞争型机器人,我们知道检测物体以避免碰撞是不可能被夸大的。虽然你经常会用大量的红外传感器来探测周围的物体,但事实上,你可以用更少的资源建造自己的迷你雷达来达到同样的效果。在这里,我将向您展示如何使用红外测距传感器与伺服电机耦合来创建一个 DIY 迷你雷达,以及如何通过令人眼花缭乱的仪表盘实时显示结果。
1.阿尔杜伊诺
首先,我们将使用 Arduino Uno 板从锐距离测量传感器读取距离值。随后,我们将使用双面胶带将传感器安装到伺服电机的臂上,并如下所示连接电线。
Arduino,红外测距传感器和伺服电机—图片由作者提供。
一旦您连接了传感器和伺服系统,请继续将以下程序上传到 Arduino。
请注意,根据您使用的传感器和电源电压,您可能需要重新校准传感器。电流传感器可以读取 20-150 厘米之间的值,如有必要,通过读取已知距离的传感器测量值,并使用该测量值推导出一个新的公式,实验性地重新校准电机。
要验证 Arduino 和传感器是否按预期工作,请打开串行监视器(“工具”>“串行监视器”),确保记录值并通过串行端口发送,如下所示。
Arduino 串行监视器—图片由作者提供。
2.计算机编程语言
既然 Arduino、传感器和伺服系统正在工作并将值发送到串行端口,我们需要获取 Python 中的读数来生成我们的雷达仪表板。要通过串行 USB 连接将 Python 脚本与 Arduino 接口,我们需要下载并安装 Pyserial。继续启动 Anaconda 或您选择的任何其他 Python IDE,并键入以下命令:
pip install pyserial
为了生成一个图形用户界面,我们可以可视化我们的仪表板并与之交互,我们将使用 Streamlit 。这个高度通用的 web 框架允许您快速开发应用程序并将其部署到 web 服务器上,或者在您的浏览器上本地运行它们。为了显示传感器读数的雷达图,我们将使用 Plotly 。这是 JavaScript 的高度交互式数据可视化框架的 Python 绑定,允许您在指尖渲染令人眼花缭乱的视觉效果。
继续将以下源代码保存在本地目录中:
上述代码将启动到 Arduino 的连接,然后将从串行端口连续读取雷达位置和传感器值,直到被提示停止。它还会不断渲染和更新雷达图。
要运行上述脚本,请在 Anaconda 提示符下键入以下命令:
cd C:/Users/.../local_directory
streamlit run python_radar.py
结果
这就是你要的,一个自己动手做的迷你雷达!
如果您想了解更多关于数据可视化和 Python 的知识,请随时查看以下(附属链接)课程:
使用 Streamlit 开发 Web 应用程序:
https://www.amazon.com/Web-Application-Development-Streamlit-Applications/dp/1484281101?&linkCode=ll1&tag=mkhorasani09-20&linkId=a0cb2bc17df598006fd9029c58792a6b&language=en_US&ref_=as_li_ss_tl
使用 Python 实现数据可视化:
https://www.coursera.org/learn/python-for-data-visualization?irclickid=xgMQ4KWb%3AxyIWO7Uo7Vva0OcUkGQgW2aEwvr1c0&irgwc=1&utm_medium=partners&utm_source=impact&utm_campaign=3308031&utm_content=b2c
面向所有人的 Python 专业化:
https://www.coursera.org/specializations/python?irclickid=xgMQ4KWb%3AxyIWO7Uo7Vva0OcUkGQgW16Ewvr1c0&irgwc=1&utm_medium=partners&utm_source=impact&utm_campaign=3308031&utm_content=b2c
物联网专业化编程简介:
https://www.coursera.org/specializations/iot?irclickid=xgMQ4KWb%3AxyIWO7Uo7Vva0OcUkGQgQzrEwvr1c0&irgwc=1&utm_medium=partners&utm_source=impact&utm_campaign=3308031&utm_content=b2c
GitHub 资源库:
https://github.com/mkhorasani/arduino_python_radar
新到中?您可以在此订阅并解锁无限文章。
建立假新闻检测器
原文:https://towardsdatascience.com/build-a-fake-news-detector-2092ef1e8cf2?source=collection_archive---------46-----------------------
是时候粉碎错误信息了
作者图片
如果冠状病毒教会了我一件事,那就是没有人能幸免于这种危险的病毒。它在世界的某些地方成倍增长,让我们担心和害怕我们所爱的人和我们自己的身体健康。但是你有没有花一点时间停下来想想错误的信息会如何影响你?你根据这些数据做出的决定?事实上,虚假新闻传播或“病毒式传播”的可能性高达 70%1。想象一下,有些决策是基于这种虚假的病毒式新闻做出的。令人欣慰的是,人工智能在对抗错误信息方面取得了一些重大进展。
在本文中,我们将使用 python 构建我们自己的假新闻检测器。我们将利用一些测试数据和代码,使用被动积极分类器(PAC)用我们的数据训练模型,该分类器将确定一段文本是真还是假。PAC 背后的主要概念是,它占用的内存较少,并且使用每个训练样本来重新评估训练算法的权重。预测正确,保持不变,预测错误,调整算法。它是一种流行的机器学习算法,特别是在做假新闻检测等工作时。其背后的数学并不简单,所以我们将把它留给另一篇文章。在本文中,让我们构建一个实际的应用程序。准备好了吗?我们开始吧!
To see a video demonstration of this exercise check out the youtube video with code walkthrough at [https://youtu.be/z_mNVoBcMjM](https://youtu.be/z_mNVoBcMjM)
为了开发这个应用程序,我们将利用两个流行的 python 包,一个是 pandas ,另一个是 sklearn 。完整的代码和数据可以在我的 g ithub 链接找到。所以让我们从导入我们的需求开始
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import PassiveAggressiveClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, confusion_matrix
from sklearn.model_selection import cross_val_score
一旦我们导入了需求,下一步就是导入数据集。我们从 kaggle 得到的数据和直接链接可以在上面链接的 github 链接上找到。
df=pd.read_csv('fake-news/train.csv')
conversion_dict = {0: 'Real', 1: 'Fake'}
df['label'] = df['label'].replace(conversion_dict)
df.label.value_counts()Fake 10413
Real 10387
Name: label, dtype: int64
一旦我们将数据导入 pandas 数据框架,我们将根据样本数据重新标记数据的真假。结果表明,我们有一个相当均匀和平衡的数据集,不需要在真实和虚假评论之间进行任何采样。所以我们不必担心不平衡的数据集。咻!少了一件需要担心的事情!
然后,我们获取数据集,创建一个训练测试分割,并保留一定百分比进行测试,在本例中为数据集的 25%。测试数据将由作为 X 变量的实际文本和作为 Y 值的标签组成。为了确保我们只使用关键字,我们还从算法中删除了所有停用词。
x_train,x_test,y_train,y_test=train_test_split(df['text'], df['label'], test_size=0.25, random_state=7, shuffle=True)
tfidf_vectorizer=TfidfVectorizer(stop_words='english', max_df=0.75)vec_train=tfidf_vectorizer.fit_transform(x_train.values.astype('U'))
vec_test=tfidf_vectorizer.transform(x_test.values.astype('U'))pac=PassiveAggressiveClassifier(max_iter=50)
pac.fit(vec_train,y_train)PassiveAggressiveClassifier(C=1.0, average=False, class_weight=None,
early_stopping=False, fit_intercept=True,
loss='hinge', max_iter=50, n_iter_no_change=5,
n_jobs=None, random_state=None, shuffle=True,
tol=0.001, validation_fraction=0.1, verbose=0,
warm_start=False)
然后,我们用数据训练模型,运行 50 次迭代,并使其符合 PAC。太好了,现在我们有一个训练有素的分类器。接下来让我们测试我们的训练模型的准确性。我们运行 y 测试和 y_pred 准确度分数,看到我们得到了一个不错的分数。96.29%.太好了!
y_pred=pac.predict(vec_test)
score=accuracy_score(y_test,y_pred)
print(f'PAC Accuracy: {round(score*100,2)}%')PAC Accuracy: 96.29%
为了进一步确保我们的模型预测正确的行为,我们查看混淆矩阵,以帮助我们更好地了解我们在结果集中看到多少真阴性和假阳性。
confusion_matrix(y_test,y_pred, labels=['Real','Fake'])array([[2488, 98],
[ 95, 2519]])
基于上面的混淆矩阵,结果看起来相当不错。在大多数情况下,它准确地预测了正确的结果。好吧,但是我们也不要就此打住。让我们针对这些结果运行黄金标准测试,这是一个 K 倍精度测试。
X=tfidf_vectorizer.transform(df['text'].values.astype('U'))
scores = cross_val_score(pac, X, df['label'].values, cv=5)
print(f'K Fold Accuracy: {round(scores.mean()*100,2)}%')K Fold Accuracy: 96.27%
这导致了 96.27%的 k 倍测试分数。好的,我对这个结果很满意。好了,现在让我们向这个模型展示一些它从未见过的数据,看看它在预测正确标签方面表现如何。
df_true=pd.read_csv('True.csv')
df_true['label']='Real'
df_true_rep=[df_true['text'][i].replace('WASHINGTON (Reuters) - ','').replace('LONDON (Reuters) - ','').replace('(Reuters) - ','') for i in range(len(df_true['text']))]
df_true['text']=df_true_rep
df_fake=pd.read_csv('Fake.csv')
df_fake['label']='Fake'
df_final=pd.concat([df_true,df_fake])
df_final=df_final.drop(['subject','date'], axis=1)
df_fake
在上面的代码块中我们引入了两个新的数据集,df_true 表明我们都是真实的新文档,df_fake 表明我们都是虚假的文章。我想把这些文章放入我们训练好的分类器,看看它对 df_true 数据集预测为真的次数,以及对 df_fake 数据集预测为假的次数的百分比。
为此,让我们构建一个快速函数,该函数将返回模型的一个不可见数据集的标签
def findlabel(newtext):
vec_newtest=tfidf_vectorizer.transform([newtext])
y_pred1=pac.predict(vec_newtest)
return y_pred1[0]findlabel((df_true['text'][0]))'Real'
在这个函数中,我们传递一些数据集,它将根据我们的 PAC 训练算法计算数据集是真是假。然后,我们运行 df_true 数据帧中的第一个文本文档,希望它能预测 real,在本例中就是这样。我想看到的是它准确预测正确数据集的时间百分比。
sum([1 if findlabel((df_true['text'][i]))=='Real' else 0 for i in range(len(df_true['text']))])/df_true['text'].size0.7151328383994023sum([1 if findlabel((df_fake['text'][i]))=='Fake' else 0 for i in range(len(df_fake['text']))])/df_fake['text'].size0.6975001064690601
好了,我们已经循环了 df_true 数据集中的数据,并注意到它在 71.5%的时间里准确地预测了“真实”。当我们查看 df_fake 数据集时,它准确预测 69.75%为“假”
对我来说,这实际上是一个非常有趣的项目,我也非常喜欢做这个项目。虽然训练结果看起来很惊人,但实际测试数据与看不见的数据相比并没有那么高,但是嘿,如果我能阻止来自互联网的错误信息大约 7/10 次,我认为这是一个胜利。
希望您喜欢这个代码演练。请务必登录 levers.ai 查看我们,了解更多关于我们服务的信息。
来源:https://www . Reuters . com/article/us-USA-cyber-twitter/false-news-70%更有可能在 Twitter 上传播-study-iduscn1 gk2 QQ
使用 Spotify API 构建一个 Flask-Heroku 情绪跟踪器 Web 应用程序
原文:https://towardsdatascience.com/build-a-flask-heroku-mood-tracker-web-app-using-the-spotify-api-14b3b5c92ac9?source=collection_archive---------15-----------------------
实践教程
A-Z 项目根据我每天听的歌曲生成情绪得分,并相应地给我的在线情绪跟踪器着色
埃斯特扬森斯在 Unsplash 上拍摄的照片
下面先睹为快的 最终结果 !
子弹日记是我的主要爱好之一。浏览上百个 Instagram bujo 账号,每个月我最期待的一件事就是 bujo 艺术家的情绪追踪器模板。这些色彩缤纷的情绪拼贴画奠定了我这个项目的基础。当我在设计下个月的情绪跟踪器时,我的脑海中闪过一个想法,如果有一个系统可以自动检测我们的情绪,并帮助我们每天填充单元格,那将是非常棒的。
照片由拍摄那是她的事在 Unsplash
好的,数据呢?
音乐一直是我日常生活的重要组成部分。我的音乐和我的情绪之间的关系通常是线性的:当我开心的时候,我会听欢快的歌曲;当我悲伤的时候,我会听民谣;当我压力过大的时候,我会听治愈的节奏。因此,我决定使用我在 Spotify 上听的歌曲,特别是它们通过 API 提供的属性,如声音、舞蹈性等,作为歌曲快乐水平的指标,以及随后我的整体情绪。
头脑风暴出了一个总体的项目想法后,我开始起草一份管道组件的清单,确定任务应该完成的顺序以及我应该如何处理每一项任务。下图记录了我的思考过程和每个阶段的发展计划/进度:
帮助我跟踪项目进度的工作流程——按作者分类的图片
赫罗库
Heroku 是一个云平台,为 Webapp 的基本托管提供免费选项,因此它适用于小规模的个人项目。我们只需要一个账户!
注册后,导航到你的个人仪表盘,点击“新建”创建一个新的应用程序(我的应用程序叫做心情日志)。转到您的应用程序,在“部署”下,选择 Heroku Git 作为您的“部署方法”,并按照下面列出的步骤将您的项目(目前为空)克隆到您的本地工作环境。我们将在此文件夹中添加文件,然后推送更改。就这样,让我们开始这个项目吧!
决定模型
首先,我需要一个模型来根据我的音乐列表产生上述情绪得分。确定合适的模型需要后退一步,关注最终的结果。我相信好的模型来自于专注于你的最终目标;一个更复杂的模型不一定能为一个人的问题提供最好的解决方案。
如上所述,我的快乐程度是由一首歌听起来有多快乐来定义的。因此,我需要一种算法,给有快乐氛围的歌曲分配较高的分数,否则分配较低的分数。K-Means 是一种经常用于歌曲分析的无监督方法,它根据歌曲的相似性对歌曲进行分组,但这对我的任务没有帮助,因为我已经记住了两个类别。用于歌词分析的深度学习模型也是一种选择,但歌曲中的句子通常很短,重复且有隐藏的含义。另外,歌词不是我听歌的主要因素,节奏才是。
通过不同选项的循环,我得出结论,我可以用二元逻辑回归模型获得想要的结果。如果我使用两个非常不同的列表来拟合模型,一个是乐观快乐的歌曲,另一个是民谣式的忧郁旋律,那么我可以产生一个概率预测,任何给定的歌曲离快乐歌曲有多近。这个概率可以作为我的*情绪得分。*取一天中所有歌曲的所有情绪得分的中间值,我将准备好最终得分!
训练逻辑回归模型
从训练数据来看…
由este 扬森斯在 Unsplash 上拍摄
特别感谢 Sejal Dua 的详细指南使用 Spotify API 抓取歌曲,使这项任务变得前所未有的简单!Sejal 的程序接受 Spotify 的播放列表 id 列表,并返回所有歌曲属性的数据帧,准备用于训练模型。我将 Spotify 制作的快乐合辑(情绪助推器、快乐节拍等)和悲伤合辑(悲伤时刻、生活糟透了等)输入到这个功能中,这些合辑包含了这个类别中非常有代表性的歌曲。全套大约有 1000 首歌曲。
我用交叉验证训练了这个模型,它的准确率达到了 0.89!我还在包含悲伤和快乐歌曲的个人播放列表上使用了 predict_proba ,分配给歌曲的概率估计模型很好地反映了每首歌曲的快乐水平。然后,该模型被处理以用于我们的应用程序。
import picklepickle.dump(lr, open("deploy_model.sav", 'wb'))
…预测
为了进行预测,我需要收集一天中我听的所有歌曲。在 Spotify API 提供的所有功能中,current _ user _ recent _ played是最接近我们的目标结果的功能。然而,它仅限于在一次调用中返回最近的 50 首歌曲。因此,我不得不编写一个小程序来收集过去 24 小时内的所有歌曲(在我的手写笔记上也可以找到如何工作的说明)。
每当我调用这个函数的时候,在所有曲目旁边,它还会返回一个 光标 ,告诉我我听的第 50 首歌的时间戳(以毫秒为单位)。例如,如果我在过去 24 小时内听了 120 首歌曲,那么第 50 首最近的歌曲是,比如说,5 小时前。这个想法是一次获取一批 50 首歌曲,提取这个光标,将起点设置到这个光标,然后重新开始获取接下来的 50 首歌曲。一旦我得到的批次的光标超过 24 小时标记,该过程就停止了。在这一点上,我必须调用一个 get_right_limit() 函数,该函数确定从最后一个光标开始我听了多少首没有超过 24 小时的歌曲。代码片段如下:
get limit 函数如下:
一旦我得到了所有的歌曲,剩下的就是提取这些歌曲的特征,就像我在上一节中所做的那样。之后,我用 pickle.load() 加载 pickle 模型,并使用 predict_proba 生成分数,我将把它作为一个名为“prediction”的列添加到我们的数据帧中:
mixed = get_features_for_playlist2(mixed, curr_time, curr_time - 86400000) # 86400000 is 1 day in millislr = pickle.load(open('models/deploy_model.sav', 'rb'))vnpred = lr.predict_proba(mixed.drop(['name', 'artist','track_URI'], axis=1))[:,1]mixed.insert(3, 'prediction', vnpred)# take the median score
day_median = float(median(mixed['prediction']))
存储结果
我还需要一种存储方式,当上面的程序运行时,它会得到更新,Flask 应用程序可以很容易地从中检索和使用结果。这里我使用了一个 SQL 表。每天存储和更新结果的代码是:
将我的结果存储在 schema.sql 中
值得注意的是,我必须创建一个 31 行的表,因为 Flask 应用程序将检索所有 31 个值来查找图形的颜色。表中的所有值都被初始化为 0。每当我们转向一个新的月份,该表将被重置:所有旧的值将被清除并替换为 0。
去弗拉斯克和赫罗库!
在 Unsplash 上由埃斯特·扬森斯拍摄的照片
烧瓶环境
如果你以前没有用过 Flask,这里的是一个快速而有用的安装和入门指南!我们的 flask 应用程序的所有必要文件的列表可以在上面的我的计划器中找到。
此外,为了将您的应用程序推送到 Heroku,我建议使用 pipenv——一种创建虚拟环境的工具——因为它很好地锁定了您的应用程序的所有必要的依赖库(并且比使用 requirements.txt 文件给我带来的麻烦更少!).为了使用它,使用 pip install pipenv ,然后键入 pipenv shell 来激活环境。在这种环境下,请执行*pipenv install[list of package _ name]*来安装您的程序所需的软件包。最后, pipenv lock 完成安装后,将所有这些需求锁定到您的应用程序。在将应用程序推送到 Heroku 之前,如果你安装了任何额外的包,你需要再次键入这个命令,否则部署会给你错误,说没有这样的模块。
SQL 烧瓶(app.py)
现在我已经将现成的结果存储在 schema.sql 中,我继续将它加载到我的 Flask 应用程序中。在 app.py 中,为了方便地从表中提取信息,我使用了一个名为 Flask-SQLAlchemy 的包。首先,我必须用下面的语法创建引擎和声明模型:
main.htmlJavaScript
“模板”文件夹中的 main.html 文件被我们的 Flask 应用程序用来创建网站的界面。但是为了绘制图形和定制颜色,我们需要 Javascript 和 CSS。烧瓶要求我们把。js 和。css 文件放在另一个名为 static 的文件夹中。我使用 Javascript 的 Canvas API 和 R ainbowVis 包来制作图纸。这一阶段需要大量的试验和错误,然后才能得到最终产品,但这也是最有趣的部分。 RainbowVis 包提供了一个工具来生成一个十六进制数字数组,表示从蓝色(=悲伤)到绿色(=中性)到黄色(=快乐)的 1000 种颜色的渐变。这个想法是将情绪分数四舍五入到小数点后 3 位,乘以 1000,并得到该指数处的十六进制颜色。
因此,我必须将分数从 app.py 传递到 html 文件,再传递到 javascript 文件。经过一轮谷歌搜索,我想到了解决方案:
- 为了将分数从 app.py 传递给 main.html,我使用 Flask-SQLAlchemy 函数来查询分数,或者“结果”列,并通过 render_template()将其作为数组传递给 html。我把这个函数放在默认路径下,因为我希望当我们访问首页时,这些图形能够正确地呈现。
[@app](http://twitter.com/app).route('/', methods=['GET'])
def main():
table = Mood.query.with_entities(Mood.results).all()
table = [r for r, in table]
# table is currently storing the mood scores
return render_template('main.html', results = table)
分数现在存储在 html 中一个名为 results 的数组中。为了获得数组中的信息,我们必须使用双花括号。我们可以使用***console . log({ })***来确认数组成功传入。
为了将分数从 main.html 传递到 canvas.js ,我将 canvas.js 中的代码包装在一个名为 draw() 的函数中,该函数接受一个参数:值数组。在 HTML 内部,我调用 draw()并将情绪得分表传入。代码如下。注意,Flask 的 HTML 文件在语法上与普通的 HTML 文件略有不同,包括 src 和 href。
现在在 canvas.js 中,您可以使用普通的数组索引来访问结果中的值!
至此,我们已经完成了应用程序中不同组件之间的链接设置!如果你输入 flask run 我们可以看到我们的应用程序在本地主机上运行。现在剩下的,就是把它推到 Heroku 身上,让其他人也能看到!
烧瓶 Heroku
按照 Deploy 下的后续步骤,添加、提交和推送我们的文件到 Heroku(记住在执行这个步骤之前要 pipenv lock)。您的终端应该显示如下内容:
如果你访问这个网址,当你运行 *flask 时,它会显示出你在本地电脑上的 Flask 应用程序上看到的准确状态。*瞧!
计划每天运行:
最后一步是使程序自动化,以便它在每天结束时运行并相应地更新图表。为此,我编写了一个 crontab 脚本,它在每晚 11:59 运行 clock.py,用当天的新分数更新 SQL 表,然后将整个项目重新推送到 Heroku。
注意,为了让 crontab 在 macOS 上正常工作,您必须授权它使用您的本地文件夹。进入系统偏好设置->安全和隐私->全磁盘访问。单击下面的锁图标可以进行更改。单击“+”号,然后转到路径“/usr/sbin/cron”。选中 cron 的复选框,再次点击锁以锁定更改。我们都准备好了。
键入 crontab -e 开始编写 crontab 脚本:
59 23 * * * cd /Users/irenechang/Desktop/PORTFOLIO/Fall2021/mood-journaling && /opt/anaconda3/bin/python /Users/irenechang/Desktop/PORTFOLIO/Fall2021/mood-journaling/clock.py && /usr/local/bin/git add /Users/irenechang/Desktop/PORTFOLIO/Fall2021/mood-journaling/. && /usr/local/bin/git commit -m "commits" && /usr/local/bin/git push heroku HEAD:master
搞定了。我们的程序每天都会更新!
最终结果—作者提供的图片
结论:
这是一个有趣的从想法到部署的 ML 项目,我开始这个项目的目的是获得使用 Heroku 和 Flask 的实践经验,并让自己熟悉数据科学模型的 A-Z 管道。希望你会像我一样喜欢这篇在线子弹日志揭示的对你日常情绪的洞察。此外,我希望这能为您的个人项目提供有益的指导,尤其是在部署模型和找出多个不同元素之间的联系时。
非常感谢您的阅读!我的代码可以在这个 repo 中找到!如果您有任何进一步的想法或反馈,请随时通过我的 LinkedIn 联系我,我很乐意与您联系!
参考资料:
- https://python-adv-we b-apps . readthedocs . io/en/latest/flask _ DB2 . html
用 Streamlit 构建纪娜神经搜索
原文:https://towardsdatascience.com/build-a-jina-neural-search-with-streamlit-a2b5c323cd45?source=collection_archive---------24-----------------------
借助深度学习的力量,使用纪娜搜索文本或图像
通过流线
你有没有想过,“该死的云。为什么不能有更简单的方法在上面建立一个神经搜索?”
如果你有,这篇文章是给你的。我将介绍如何使用纪娜的新 Streamlit 组件来搜索文本或图像,以构建一个神经搜索前端。
想直接跳进去吗?查看我们的文本搜索应用或图片搜索应用,这里是组件的回购。
为什么要用纪娜来建立一个神经搜索?
纪娜是一个开源的深度学习搜索框架,用于在云上构建跨/多模态搜索系统(例如,文本、图像、视频、音频)。本质上,它让你用任何类型的数据为任何类型的数据构建一个搜索引擎。
所以你可以建立自己的文本到文本的搜索引擎,比如谷歌,文本到图像的搜索引擎,视频到视频的搜索引擎等等。脸书、谷歌和 Spotify 等公司通过最先进的人工智能模型(如 FAISS、DistilBERT 和 Annoy)来构建这些搜索。
为什么将 Streamlit 与纪娜一起使用?
在我加入纪娜之前,我就已经是 Streamlit 的忠实粉丝了。我在一个项目中使用它来创建可怕的《星际迷航》脚本,后来变成了《变形金刚文本生成的前端。所以我非常高兴能使用这个很酷的框架为我们的用户构建一些东西。
构建 Streamlit 组件有助于数据科学家、机器学习爱好者和 Streamlit 社区中的所有其他开发人员构建由神经搜索驱动的酷东西。它提供了灵活性,并且由于是用 Python 编写的,数据科学家可以更容易地跟上速度。
开箱即用,streamlit-jina 组件有文本到文本和图像到图像的搜索,但纪娜提供了丰富的搜索体验为任何类型的数据与任何类型的数据,所以有更多的添加到组件!
它是如何工作的?
每个纪娜项目包括两个流程:
**索引:**用于使用神经网络模型从数据集中分解和提取丰富的含义
**查询:**接受用户输入并查找匹配结果
我们的 Streamlit 组件是终端用户的前端,所以它不用担心索引部分。
- 管理员旋转出一个纪娜码头工人的图像:
docker run -p 45678:45678 jinahub/app.example.wikipedia-sentences-30k:0.2.9-1.0.1
- 用户在 Streamlit 组件中输入一个查询(当前为文本输入或图片上传)并点击“搜索”
- 输入查询被封装在 JSON 中,并发送给纪娜的查询 API
- 查询流完成它的工作,并以 JSON 格式返回结果(以及大量元数据)
- 该组件解析出有用的信息(例如文本或图像匹配)并将它们显示给用户
示例代码
让我们来看看我们的文本搜索示例,因为这样更容易看到那里发生了什么:
可以看到,上面的代码:
- 进口
streamlit
和streamlit_jina
- 设置搜索的 REST 端点
- 设置页面标题
- 显示一些说明性文本
- 显示定义了
endpoint
的纪娜文本搜索小部件
对于纪娜的 Streamlit 小部件,你也可以传入其他参数来定义你想要返回的结果数量或者你是否想要隐藏某些小部件。
在幕后
我们模块的源代码只有一个文件。现在让我们来看看文本搜索示例的高级功能:
设置配置变量
渲染组件
简而言之,jina.text_search()
法:
- 创建一个 Streamlit 容器来保存所有内容,如果没有指定,则使用默认设置
- 如果小部件没有设置为隐藏,则向用户显示它们
- [用户类型查询]
- [用户点击按钮]
- 向纪娜 API 发送查询并返回结果
- 显示组件中的结果
我们方法的参数是:
jina.text_search()
调用其他几种方法,这些方法都可以在__init__.py
中找到。对于图像搜索,还有一些附加功能:
- 将查询图像编码为 base64,并在传递给纪娜 API 之前将其包装在 JSON 中
- 纪娜的 API 返回 base64 格式的匹配。
image.render.html()
方法将它们包装在<IMG>
标签中,这样它们就能很好地显示
在您的项目中使用它
在你的终端:
创建一个包含虚拟环境的新文件夹并激活它。这将防止系统库和单个项目库之间的冲突:
mkdir my_project
virtualenv env
source env/bin/activate
安装细流和细流-纪娜包:
pip install streamlit streamlit-jina
索引您在纪娜的数据并启动查询流程。或者,使用预先索引的 Docker 图像:
docker run -p 45678:45678 jinahub/app.example.wikipedia-sentences-30k:0.2.9-1.0.1
创建您的app.py
:
运行 Streamlit:
streamlit run app.py
这就是你自己的文本搜索!
对于图像搜索,只需将上面的文本代码替换为我们的图像示例代码,并运行一个纪娜图像(就像我们的口袋妖怪示例)。
下一步做什么
感谢您阅读本文,并期待听到您对该组件的看法!如果你想了解更多关于纪娜和 Streamlit 的信息,这里有一些有用的资源:
纪娜
- 流线型纪娜组件
- 纪娜 101 :纪娜的基本部件
- 纪娜 102 :纪娜组件如何协同工作
- 我的第一个纪娜应用程序:为维基百科句子建立一个简单的文本搜索应用程序
- 我们的示例 repo:文本、图像、音频、视频和多模态搜索后端的示例,更不用说查询语言、增量索引、QA 搜索等等
细流
- 精简文档
- 组件图库
- 应用程序库
- 社区论坛
非常感谢你!
主要感谢 Randy Zwitch,TC Ricks 和 Amanda Kelly,感谢他们的帮助,让组件上线。感谢我在纪娜的所有同事,是他们构建了后端让这一切成为可能!
原载于 2021 年 4 月 15 日https://blog . streamlit . io。
不到一个小时就能构建一个机器学习应用
原文:https://towardsdatascience.com/build-a-machine-learning-app-in-less-than-an-hour-300d97f0b620?source=collection_archive---------11-----------------------
迈克尔·泽兹奇在 Unsplash 上的照片
无需编写一行代码
简介:
机器学习在过去的几年里取得了很多成功,并且发展得非常快。然而,它也依赖于机器学习专家来开发机器学习模型,如进行预处理、特征工程、构建模型、超参数调整等。在本文中,我们将看到如何开发一个卷积神经网络模型,而无需编写一行代码。此外,使用 Streamlit 框架创建一个机器学习应用程序,只需最少的代码。我们也可以在 Heroku 免费部署应用程序。这篇文章的目的是吸引很多对机器学习感兴趣但没有编码经验的人来尝试机器学习。
内容:
- 什么是自动 ML
- 开发一个图像分类模型,无需编写一行代码
- 使用 Stremlit 开发机器学习应用程序
- 如何在 Heroku 部署 app
什么是自动 ML?
根据谷歌文档
AutoML 使机器学习专业知识有限的开发人员能够针对他们的业务需求训练高质量的模型。在几分钟内构建您自己的定制机器学习模型。
有很多来自 GCP、AWS 和 Azure 的自动 ML 工具。
例如,以 GCP 为例,我们有以下 AutoML 工具
- 汽车视觉
- 汽车视频智能
- AutoML 自然语言
- 汽车翻译
- AutoML 表格
此外,他们有
- 大查询 AutoML
- 预建型号可用
如果有兴趣了解更多关于 AutoML 的信息,请参考谷歌文档https://cloud.google.com/automl/docs.
AWS AutoML:
- 自动驾驶
AWS 表示,其目标之一是将机器学习(ML)放在每个开发者的手中。通过使用亚马逊 SageMaker 和 AWS Lambda 部署的开源 AutoML 库 AutoGluon ,它可以更进一步,将 ML 交给任何想要基于数据进行预测的人——无需事先编程或数据科学专业知识。
请查看更多细节
https://auto.gluon.ai/stable/index.html
Azure AutoML:
根据 Azure 文档,什么是 Auto ML?
自动化机器学习,也称为自动化 ML 或 AutoML,是将机器学习模型开发的耗时、迭代任务自动化的过程。它允许数据科学家、分析师和开发人员构建具有高规模、高效率和高生产率的 ML 模型,同时保持模型质量。传统的机器学习模型开发是资源密集型的,需要大量的领域知识和时间来产生和比较几十个模型。借助自动化机器学习,您可以轻松高效地加快生产就绪型 ML 模型的速度。
查看他们的文档以获得更多关于 AutoML 的信息
https://docs . Microsoft . com/en-us/azure/machine-learning/concept-automated-ml
因此,几乎所有的主要参与者都在将他们的研究转向 AutoML,以吸引非程序员进入机器学习学科。
开发图像分类模型,无需编写任何代码:
- teachablemachine.withgoogle.com
- Kaggle X 射线数据集
让我们选择https://teachablemachine.withgoogle.com/来创建我们的神经网络模型。Teachable Machine 是一个基于网络的工具,它使创建机器学习模型变得快速、简单,并且每个人都可以访问。这是谷歌的一个自动化工具。
我选择了 Kaggle 的 x 光数据集。
https://www . ka ggle . com/paultimothymooney/胸部 x 光-肺炎
***关于数据集:*胸部 X 线图像(前-后)选自广州市妇女儿童医疗中心的 1-5 岁儿科患者的回顾性队列。所有的胸部 x 光成像都是作为患者常规临床护理的一部分进行的。对于胸部 x 射线图像的分析,最初通过去除所有低质量或不可读的扫描对所有胸部射线照片进行质量控制筛选。图像的诊断然后由两名专家医生进行评级,然后被批准用于训练人工智能系统。为了解决任何评分错误,评估集也由第三方专家检查。
X 光图像分类 App :最终结果 App 如下。用上述数据集训练模型。当你上传一张 x 光照片到应用程序,然后它会对 x 光照片进行分类,看它是正常的还是有肺炎症状。
作者提供的图片-创建的应用程序的 Gif 文件
创建模型和 app 的步骤:
- 从 Kaggle 下载数据集。链接是https://www . ka ggle . com/paultimothymooney/chest-Xray-pneumonia
数据集的大小为 1.15 GB ,包含大约 5856 张图像。
2.转到 teachablemachine,网址是
https://teachablemachine.withgoogle.com/train/image
3.不需要对数据进行任何预处理。将所有正常图像上传到 Class1。将所有肺炎图像上传到 2 班。我只考虑了训练图像文件夹。请参考下面的截图。
作者提供的图片—在可示教机器中上传文件时拍摄的屏幕截图
3.上传完所有图片后,选择火车模型。我只是在高级设置中将批量大小从 16 改为 128。我保持了相同的默认 50 个纪元和默认学习速率。
图片由作者提供——在可教机器培训期间拍摄的截图
4.模型训练完成后,导出模型。此外,您可以测试模型。尝试从验证文件夹或测试文件夹上传图像。我只上传了训练文件夹图片,训练了模型。
图片由作者提供—截图是在可教机器训练后拍摄的
5.导出模型-选择张量流并选择 Keras。然后点击下载我的模型。
图片由作者提供—导出可示教机器时拍摄的截图
现在,模型已经创建并下载完毕。您还可以将您的模型导出为 TensorFlow.js 模型,并将其免费托管在可教学的机器上,这样您就可以在任何网站或应用程序中调用它。也可以转换成 TensorFlow 和 TensorFlow Lite 下载本地使用。
让我们更进一步,使用 Stremlit 创建一个应用程序并测试模型。
使用 Stremlit 开发机器学习应用程序:
通过最少的代码,您可以使用 Streamlit 创建一个应用程序。检验
https://streamlit.io/
- 安装 Streamlit。
- teachbalemachine 中提供了测试 Keras 模型的代码片段,它是
作者图片
3.现在,您使用 Streamlit 文件上传并添加一些标题
作者图片
4.要执行应用程序,请调用文件—参考下面的代码。文件名为 xray.py
作者图片
5.完整的代码如下
作者图片
5.使用正常类别的 x 光图像和肺炎类别的 x 光图像测试应用程序。
肺炎图片:
根据您显示的消息类别,在这种情况下,将显示以下消息"这张 x 光片看起来像患了肺炎。它有异常的平静。需要放射学家/医生的进一步调查”。
作者图片
正常图像:
在正常的 x 光下,显示信息“万岁!!这张 x 光片看起来很正常。这张 x 光片描绘了清晰的肺部,图像中没有任何异常浑浊区域”。
作者图片
最后一步是在 Heroku 部署 app。如果你对托管你的应用感兴趣,那就继续学习吧。
如何在 Heroku 部署 app
按照步骤在 Heroku 中部署应用程序。Heroku 里面有很多关于如何部署一个 app 的文章。请查看下面的文章,其中有在 Heroku 部署应用程序的步骤
https://towards data science . com/from-streamlit-to-heroku-62a 655 b 7319
此外,请查看 youtube 视频,了解整个部署过程
视频来源于 Data Professor Youtube 频道
部署所需的文件
- Python 脚本(上面的 Python 文件带有逻辑)
- Procfile
- setup.sh
- requirements . txt
结论:
我们刚刚看到创建一个卷积神经网络来进行图像分类是多么容易,而无需编写一行代码。此外,我们还看到了使用 Streamlit 创建应用程序是多么容易。我们只是使用了 Streamlid 文件上传器命令和 Google 提供的 Keras 代码片段。同样,创建这个应用程序只需要很少几行代码。要在 Heroku 中部署应用程序,我们需要 4 个文件,然后按照文档中提供的步骤操作。同样,AutoML 的目标是吸引非程序员进入机器学习领域。请尝试使用 Kaggle 的数据集或您自己的数据集。希望你喜欢这篇文章。
请随时在 LinkedIn 与我联系
参考资料:
1【https://cloud.google.com/automl/docs
【2】https://blog.google/technology/ai/teachable-machine/
【3】https://streamlit.io/
【4】https://www . cell . com/cell/full text/s 0092-8674(18)30154-5
【5】https://AWS . Amazon . com/blogs/machine-learning/code-free-machine-learning-automl-with
从零开始建立一个机器学习模型到实际使用案例
原文:https://towardsdatascience.com/build-a-machine-learning-model-to-a-practical-use-case-from-scratch-3a8dc65ab6f1?source=collection_archive---------4-----------------------
实践教程
从预处理、特征工程、PCA 到模型创建、预测和核心概念的准确性测试
亚历山大·奈特在 Unsplash 上拍照
机器学习是一个巨大的领域。它是一项强大的技术,使我们能够比以前更快地开发软件解决方案,并且是目前解决各种问题的最先进的解决方案。我们可以把它应用到几乎每个领域。在本文中,我们将深入研究如何将开发机器学习模型的过程转化为实际用例。
在文章中,我们将讨论:
- 问题定义和数据收集
- 数据预处理
- 数据转换
- 特征编码
- 缩放和标准化
- 特征工程
- 主成分分析降维
- 回归
- 准确性测量和评估技术
假设:-我相信你有 python 编程以及与机器学习相关的基本库的先验知识。
用例:-湿度和温度之间有关系吗?湿度和表观温度之间呢?给定湿度,你能预测表观温度吗?
1.问题定义
首先,我们必须了解问题、问题所在的环境,并收集与场景相关的领域知识。
该问题主要要求在给定湿度的情况下预测表观温度。这个表观温度是多少?
表观温度是人类感知的温度当量,由空气温度、相对湿度和风速的综合影响引起。-维基百科
这揭示了一个重要因素。不仅是湿度,气温和风速也在影响表观温度。因此,对于一个给定的场景,我们需要找出哪些直接和间接(隐藏)的事实会影响我们的问题。
银行业就是一个很好的例子。假设您需要确定一个客户是否有资格获得贷款。(执行者或非执行者)你不能只通过查看以前的银行交易来预测它。你需要分析,他工作的领域是什么,如果他是一个合作客户,其他给他带来利润的行业是什么(虽然他在一个领域失败了,但他可能会在另一个领域崛起),他是否有任何政治支持,例如一个广泛的领域(间接的),你可能需要覆盖以提供一个良好的预测。记住这一点,让我们来解决我们的问题。
那么我们需要一个数据集来解决这个问题。 Kaggle 网站为任何人提供了大量的数据资源,我们可以很容易地从那里找到一个数据集。最重要的是,在 Kaggle 上,你可以在各种问题情境中向他人学习。我将使用 Kaggle —天气历史数据集来分析这个问题。
https://www.kaggle.com/budincsevity/szeged-weather?select=weatherHistory.csv
注意:所有的编码都是在 Google Colab python 笔记本中完成的,您可以在参考资料部分找到它。
2.数据集的结构
作为一名数据科学家,你需要对你的数据集和数据的复杂性有一个清晰的认识。让我们首先将数据可视化,以便获得一些见解。
下面的代码片段将把天气数据 CSV 文件加载到 pandas 数据框中,并显示前 5 行。
weatherDataframe = pd.read_csv(‘weatherHistory.csv’);
weatherDataframe.head();
数据集结构
您可以通过weatherDataframe.info()
方法进一步分析数据集,然后您将看到 12 列中有 96453 个条目。
我们可以将目标列标识为表观温度,将其余列标识为特征。
3.预处理数据集
预处理是机器学习中最重要的部分。我们模型的成功高度依赖于输入机器学习模型的数据质量。真实世界的数据通常是脏的。它包含重复缺失值异常值、不相关的特征、非标准化数据..等等。因此,我们需要以适当的方式清理数据集。让我们一步一步来看,我们将如何实现它。
首先,我们需要在数据集中找到任何唯一的字段。如果发现了,我们应该丢弃它们,因为它们在识别模式时没有用。如果数据集包含的列只有很少的唯一值,这将为数据清理提供良好的基础。此外,如果列有太多的唯一值,比如 ID 号、电子邮件(对于每个数据点都是唯一的),我们应该删除它们。
# summarize the number of unique values in each column
print(weatherDataframe.nunique())
标识包含单个值的列
正如您在结果中看到的, Loud cover 列只有一个值(0)。所以我们可以完全放弃那个专栏。此外,我们还需要分析行中有哪些唯一的值。为了进行分析,我们可以计算每个变量的唯一值的数量占数据集中总行数的百分比。这是为此定制的函数。
每列中唯一值的摘要
格式化日期给总数据帧 100%唯一比率。所以我们可以放弃那个专栏。此外,通过查看数据集,我们可以得出结论,每日摘要和摘要列有很大的相似性。所以我们可以移除其中一个。所以我会保留摘要。
3.1.删除重复项
接下来,可能会有重复的行。所以我们需要识别包含重复数据的行并删除它们。
有一件重要的事情要记住。当我们删除行时,这将导致索引不同。例如,如果从数据框中删除第 18 行,现在索引将是..16,17,19,20..像这样。这最终会在实际行数和最后一个索引之间产生差异。为了避免这种情况,我们需要重置索引。然后它会更正顺序。
3.2.处理缺失值
数据集中可能有许多缺失值。对于缺失值,我们主要可以做两件事,要么丢弃,要么进行插补来替换它们。插补是用平均值或中间值代替缺失值。但这种插补的问题是,它会导致数据集出现偏差。因此,建议谨慎操作插补。
如果缺失值的情况非常少,最好的选择是删除它们。(如果案例的数量少于样本的 5%,您可以更安全地删除它们)
# Check for any missing values
weatherDataframe.isnull().values.any()
# This gives - True#Getting the summary of what are missing value columns
weatherDataframe.isnull().sum()
识别缺失值
如您所见,Precip 类型列中有 517 个缺失值。因此,让我们检查一下总体概率,看看是否可以删除这些列。
weatherDataframe['Precip Type'].isna().sum()/(len(weatherDataframe))*100
这将返回 0.536 的结果,与整个数据集相比,这是一个非常低的百分比。所以我们可以放弃他们。它将确保没有偏差或差异被添加或删除,并最终导致一个稳健和准确的模型。
# make copy to avoid changing original data
new_weatherDf = weatherDataframe.copy()# removing missing values
new_weatherDf=new_weatherDf.dropna(axis=0)# Resetting Indexes
new_weatherDf=new_weatherDf.reset_index(drop=True)
3.3.移除异常值
离群值是明显远离主流的数据点(或者可以是少量数据点)。
但是,如果您看到许多点远离主流,它们不会被视为异常值,它们可能是某种聚类模式或与异常相关的东西。在这种情况下,我们需要分别对待。
异常值识别
有许多方法可以发现异常值。
- 箱线图——扫视上下四分位数之外的可变性
- 散点图-使用两个数据列的笛卡尔坐标
- z 得分-使用数学函数
我将使用方框图方法来直观地检测它们。
所有数字数据列的箱线图
您可以看到数据集中存在一些异常值。所以要逐个检查,分别对待。最好的选择是移除它们。考虑到数据分布,您可以应用平均值和中值。但存在使数据集产生偏差的高风险。所以如果你想这么做,就要非常精确地处理它。
我将在一篇专栏文章中演示如何去除异常值。你可以在我的 python 笔记本里看到剩下的东西。正如您在图中看到的,压力列中有一个异常值。这是一个压强,在正常情况下不会变成零。这可能是由于数据输入错误或收集的设备有问题。所以我们应该移除它们。
移除异常值-之前和之后
4.列车测试分离程序
在进行转换之前,我们需要记住一件事。那就是数据泄露。为了评估我们的模型,我们需要保留一个测试数据集。但是,如果我们对数据集中的所有数据执行以下转换步骤,然后将其拆分出来(作为训练集和测试集),我们就犯了数据泄漏的罪。
不要忘记测试数据点代表真实世界的数据。所以模型不应该看到这些数据。如果是这样,后果将是过度拟合您的训练数据,并对您的模型在看不见的数据上的表现做出过于乐观的评估。
为了避免这种情况,我们现在应该将数据集分成训练集和测试集,并执行转换步骤。这将确保前方没有窥视。否则,来自测试集的信息将“泄露”到您的训练数据中。
首先,我们需要定义我们的特征和目标(我们要预测什么。)用例告诉我们预测表观温度。所以这将是我们的目标。其余的栏目我们可以作为特写。
features_df= new_weatherDf.drop('Apparent Temperature (C)', 1)
target = pd.DataFrame(new_weatherDf['Apparent Temperature (C)'], columns=["Apparent Temperature (C)"])
现在,我们可以将它们分成 80% — 20%比例的培训和测试。random_state
确保您生成的分割是可重复的。它总是以相同的随机顺序分裂,并且每次运行都不会改变。
from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(features_df, target, test_size = 0.2, random_state = 101)
此外,请记住重置索引,因为这可能会导致后面部分的混乱。
X_train=X_train.reset_index(drop=True)
X_test=X_test.reset_index(drop=True)
y_train=y_train.reset_index(drop=True)
y_test=y_test.reset_index(drop=True)
好吧。我们都为转变做好了准备!
5.数据转换
您之前清理的数据可能没有正确的格式或正确的比例,并且对于模型来说很难理解。因此,我们需要进行数据转换。
5.1.处理偏斜度
偏斜度是偏离正态分布的一组数据的不对称性。它也可以定义为对称钟形曲线的变形。如果曲线向左移动(尾部在右边),它是右斜的,如果曲线向右移动(尾部在左边),它是左斜的。为了使它成为对称的形状,我们应该进行适当的变换。这将导致增加我们模型的准确性。
处理偏斜度
如上图所示,我们需要对右偏的数据应用对数变换,对左偏的数据应用指数变换,以使数据集对称。
但是我们如何检测偏斜度呢?为此,我们有 Q-Q 图(分位数-分位数图)和直方图。让我们用我们的数据集来分析。
import scipy.stats as stats# Temperature (C). - Training
stats.probplot(X_train["Temperature (C)"], dist="norm", plot=plt);plt.show();
X_train["Temperature (C)"].hist();
Q-Q 图和温度直方图
正如你在 Q-Q 图中看到的,大部分数据位于红线内。此外,直方图没有显示任何偏斜,它是对称的。所以我们不需要变换这个列。
湿度的 Q-Q 图和直方图
如果你分析湿度柱,你会注意到一个左偏的分布。所以我们需要应用指数变换使其对称。
# create columns variables to hold the columns that need transformation
columns = ['Humidity']# create the function transformer object with exponential transformation
exp_transformer = FunctionTransformer(lambda x:x**3, validate=True)# apply the transformation
data_new = exp_transformer.transform(X_train[columns])
df_new = pd.DataFrame(data_new, columns=columns)# replace new values with previous data frame
X_train.Humidity=df_new['Humidity']
转换后湿度的 Q-Q 图和直方图
现在你会看到一个漂亮的对称分布。同样,我们可以对所有必要的列进行转换。我将向大家展示另一个重要的转变。所有的转换在我的 python 笔记本里都有解释。参考它以获得更多的澄清。
风速的 Q-Q 图和直方图
如果你分析风速柱,你会看到一个右偏分布。为了使它对称,我们需要应用对数变换。但是这里有一个特例,列中有 0 值数据点可以看到。如果我们应用对数变换,0 值数据点将被替换为减去无穷大。为了避免这种情况,我们可以应用 log(x+1)变换。
# create columns variables to hold the columns that need transformation
columns = ['Wind Speed (km/h)']# create the function transformer object with logarithm transformation
logarithm_transformer = FunctionTransformer(np.log1p, validate=True)# apply the transformation
data_new = logarithm_transformer.transform(X_train[columns])
df_new = pd.DataFrame(data_new, columns=columns)# replace new values with previous data frame
X_train['Wind Speed (km/h)']=df_new['Wind Speed (km/h)']
Q-Q 图和变换后的风速直方图
5.2.特征编码技术
我们的数据集中有分类数据(文本)和数值数据。但是大多数模型只接受数字数据。因此,我们需要将这些分类数据或文本数据列转换成数字。为此,我们可以使用两个编码器。
- 标签编码器
- 一个热编码器(OHE)
注意—一些算法可以直接处理分类数据,如决策树。但是它们中的大多数不能直接对标签数据进行操作。
标签编码器使用 0 到 n-1 之间的值对类进行编码,其中 n 是不同类(标签)的数量。如果一个类被复制,它将分配与之前相同的值。
让我们举一个简单的例子来澄清事情。有一个关于不同国家的专栏。如果我们应用一个标签编码器,它将提供下面的输出。
例如,将标签编码器应用于国家/地区列
它将分配一个从 0 到 n 类的唯一值。正如你在这里看到的,标签编码使用字母排序。因此,巴西被编码为 0,I n dia 被编码为 1,I t aly 被编码为 2。如果相同的类出现在不同的行中,它将分配与前面分配的值相同的值。
但是标签编码的问题是,它会导致查找编码值之间的关系。举例来说,如果国家标记为 1、2、3、4..类别,模型可以创建一种模式,如标签 2 国家比标签 1 国家更强大,标签 3 国家比标签 1 和标签 2 更强大。但实际上,这两个国家之间没有任何关系。
因此,通过标签编码,它会使模型误以为某列中的数据具有某种顺序或层次结构。为了克服这个问题,我们使用一种热编码。
一种热编码采用包含分类数据的列,然后将该列拆分为多个列。这些类被二进制文件(1 和 0)替换,这取决于哪一列有特定的类。
看下面的例子。首先,它将为每个类创建单独的列,然后它将为所显示的类分配一个二进制值 1,为其他类按行分配 0。第一排代表斯里兰卡。因此,值 1 仅适用于斯里兰卡列,第一行中的其余列将获得值 0。
例如,对国家/地区列应用一个热编码
这不会在类之间产生一个模式,因为结果是二进制的而不是顺序的,所有的东西都在一个正交的向量空间中。但是它会导致大量的列,并最终导致维数灾难。但是如果我们应用像 PCA 这样的降维技术,它将解决这个问题。此外,建议使用 OHE 标签编码器。
在我们的数据集中,现在我们有两个分类列,Precip Type 和 Summary。所以我们可以对两列都进行编码。
我们正在处理一个训练和测试集。所以我们需要记住一件重要的事情。在训练模型时,您将使用训练数据集。对于经过训练的模型,我们需要输入与训练中使用的数据规模相同的数据。那么我们如何得到之前的比例呢?有趣的部分来了。为了解决这个问题,大多数图书馆有两种方法。也就是fit()
和transform()
您需要首先对您的训练数据集应用fit()
方法,以便只计算规模并将其作为对象保存在内部。然后,您可以调用transform()
方法将转换应用于训练和测试数据集。这将确保数据在相同的规模上进行转换。
我对摘要列应用了一次性编码。对于 precip 类型列,我们可以应用分类编码(类似于标签编码),因为只有两个类。
X_train['Precip Type']=X_train['Precip Type'].astype('category')
X_train['Precip Type']=X_train['Precip Type'].cat.codes
我们最终的训练数据框架将如下所示。
特征编码训练数据帧
5.3.标准化的特征
我们用标准化使数据居中(使其具有零均值和单位标准差)。这样做的实际效果是,数据将减去平均值,然后将结果除以标准差。(x' =(x-μ)/σ)
正如我们之前所做的,我们需要对训练和测试数据应用标准化。我希望您已经记住了我在特性编码部分提到的重要事实。
您必须使用完全相同的两个参数 μ 和 σ (值),这两个参数用于对训练集进行居中。
所以在 sklearn 的 StandardScaler 中提供了两种方法来实现这一点。因此,每个 sklearn 的变换的fit()
只是计算参数(例如,本例中的 μ 和 σ )并将它们保存为内部对象的状态。之后,您可以调用它的transform()
方法将转换应用于任何特定的数据集。
另一个非常重要的事情是,我们没有对先前编码的分类变量做任何标准化。所以在应用标准化之前,先把它们放在一边。
to_standardize_train = X_train[['Temperature (C)', 'Humidity','Wind Speed (km/h)','Visibility (km)','Pressure (millibars)']].copy()
注意:我故意留下了风向柱,因为它显示了数据点的巨大变化。(0-360 度)我将在标准化后的下一步对该列进行离散化。
在我们进行标准化之前,我们可以检查一下直方图的外观,以便理解 x 标度。
标准化之前
如你所见,它们处于不同的 x 刻度。现在让我们做标准化。
# create the scaler object
scaler = StandardScaler()# Same as previous - we only fit the training data to scaler
scaler.fit(to_standardize_train)train_scaled = scaler.transform(to_standardize_train)
test_scaled = scaler.transform(to_standardize_test)standardized_df_train = pd.DataFrame(train_scaled, columns = to_standardize_train.columns)
standardized_df_test = pd.DataFrame(test_scaled, columns = to_standardize_test.columns)
标准化后
现在你可以看到所有的 x 轴都变成了一个标准的缩放器。您也可以对目标变量应用标准化。
5.4.特征离散化(宁滨)
通过数据离散化,我们可以将连续值转换为离散形式。这一过程可用于将数据集的大范围缩小到小范围,从而消除观察值之间的关系。
举个例子,如果我们拿年龄来说,它可能会有 1 到 100 年的变化。这是一个大范围的数据,数据点之间的差距也会很大。为了减少这种情况,我们可以将该列离散化为有意义的类别或组,如下所示:12 岁以下的
【小孩】 在 12-18 岁之间的 【青少年】 在 18-55 岁之间的 【成人】 在 55 岁以上的
因此,离散化有助于模型更容易理解数据。有各种方法来进行离散化。(决策树,等宽,等频..等等)这里我使用的是 K 均值离散化。
在数据集中,我们有一个特征叫做测风。如果你还记得的话,因为这个原因,我之前一直把这个专栏放在一边。它提供 0-360 度的风向覆盖范围。范围很大。我们可以将其离散为八个代表实际风向的箱。(北部,东北部..等等)
n_bins
参数控制将要创建的容器的数量。我们可以使用直方图来查看输出。
离散化前后
这样就完成了所有的预处理和转换步骤。现在我们需要使用特征工程来进一步改进它。
6.执行特征工程
事实上,我们已经在转换中完成了一些功能工程流程。但是最重要的部分来了。这里,我们必须手动决定特征之间的关系,以及如何选择最佳特征集来训练模型。我们需要找到最重要的特征,因为不相关或部分相关的特征会对我们的模型性能产生负面影响。
如果我们举一个像银行业这样的实际例子,将有数百万个特征需要分析,并且数据点也将是巨大的。想象一下数据会有多复杂,数据处理会有多困难。随着数据维度的增加,这将导致数据分析任务变得更加困难。这种现象被称为维数灾难。
此外,它还会导致另一个问题,即它可能会导致机器学习模型过度拟合,使模型过于复杂。这个模型将不能很好地概括看不见的数据。更高的维度导致高计算/训练时间以及可视化的困难。所以降维是很有必要的。
在降维之前,我们应该记住两件事。
1。原始数据应该能够近似重建。
2。应该保留数据点之间的距离。
降维
6.1.识别重要特征
我们可以使用关联矩阵和热图来轻松识别重要特征。它显示了这些特征之间或与目标变量之间的关系。
相关性可以成正比,也可以成反比。当它成反比时,它会显示一个(-)符号。让我们绘制热图,以确定哪些特征与我们的目标变量最相关,哪些特征具有高相关性。
*correlation_mat = features_df.iloc[:,:6].corr()
plt.figure(figsize=(10,8))
sns.heatmap(correlation_mat, annot = True, cmap="RdYlGn")
plt.title("Correlation matrix for features")
plt.show()*
特征的相关矩阵(截断)
***正如你在热图中看到的,在:
温度和湿度
温度和能见度
湿度和能见度之间有很高的相关性
任何两个特征(独立变量)如果高度相关,则被认为是冗余的。通常情况下,建议移除此类特征,因为这将稳定模型。但我们不能断定这些功能不够有价值。它应该在训练模型之后决定。此外,删除变量是非常主观的,应该始终牢记领域。
与目标的相关矩阵(截断)
看最后一栏。表观温度与湿度高度相关,其次是能见度和气压。所以我们可以说它们是最重要的特征。我们应该保留这些变量,因为这将使模型表现良好。
这里我们有一些矛盾。从图 1 中,我们确定了一些高度相关的特征,它们需要被删除。图 2 暗示了相同的特征集与目标变量高度相关,我们应该保留它们。因此,在得出结论之前,我们需要对该模型进行多次实验。但是不用担心!我们可以应用一种更好的方法叫做主成分分析来降低维数。
6.2.使用 PCA(主成分分析)的维数减少
PCA 是一种强大的降维算法,它基于特征之间的相关性来识别数据集中的模式。通过查看 PCA 对象解释的 variance_ratio,我们可以决定在不影响实际数据的情况下可以减少多少个要素(组件)。
简要 PCA
主成分分析实际上是将数据投影到特征向量空间的维度中。然后,它将确定保存实际信息的最重要的维度。其他维度将被删除。所以这里重要的部分是,它并没有删除整个特征列,而是从其中提取大部分信息并投射到其他维度。最后,它将作为一组全新的维度(列)出现。
如果你有兴趣详细了解 PCA,我推荐 Matt Brems 写的一篇非常好的文章,发表在towardsdatascience.com
***
我们将在以后的文章中更深入地研究这种技术。因此,让我们将主成分分析应用于我们的数据集。
from sklearn.decomposition import PCA
pca = PCA()
pca.fit(X_train)
首先,我们必须确定可以减少的维度数量。为此,我们分析之前拟合的 PCA 对象中的explained_variance_ratio_
。
pca.explained_variance_ratio_
pca.explained_variance_ratio_
这里我们有一个由每个维度解释的方差的排序数组(向量)。我们必须保留高方差维度,删除其余维度。如果高方差维数(n_components)之和超过 95%,这将是一个好数字。
通过分析向量,我们可以确定前 7 个维度保留了数据集中 95%以上的信息。因此,我们可以将 33 维减少到 7 维,而只损失 5%的信息。
现在,我们可以通过添加需要保留的组件(尺寸)的数量来再次应用 PCA。
pca = PCA(n_components=7)
pca.fit(X_train)X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)
一切就绪!让我们进行建模,了解它在我们的数据集上的表现,同时牢记这些核心概念。
快速提醒-您可以比较带或不带 PCA 的模型,并检查精度值。如果 PCA 中的精度低于原来的精度,可以尝试逐个增加 n_components。
7.建模
在应用任何模型之前,您需要正确理解领域、领域的复杂性以及给定的数据集是否代表您的问题的实际复杂性。此外,如果问题与业务领域相关,您需要在某种程度上理解业务流程、原则和理论。
建模时,根据您的问题,有许多模型可供使用。我使用多元线性回归模型,因为我们需要在给定多个解释变量(特征)的情况下预测一个响应变量(目标)。这个模型基本上是用一个线性方程来拟合观察到的数据。这条线应该给原始点一个最小的偏差。
形式上,模型为多元线性回归,给定 n 个观测值:
多元线性回归模型
让我们将模型应用到数据集。
from sklearn import linear_modellm = linear_model.LinearRegression()
model2 = lm.fit(X_train_pca,y_train)
8.预言;预测;预告
对于预测,我们已经准备了一个测试数据集。如果您想要预测整个新数据,您需要应用所有预处理和转换步骤(转换应该根据之前拟合的值进行)以及 PCA,以便获得正确的预测。
predictions = lm2.predict(X_test_pca)
y_hat_pca = pd.DataFrame(predictions, columns=["Predicted Temparature"])
实际与预测
你可以看到,我们的模型对看不见的数据预测得很好。此外,这可以在图中可视化。
import matplotlib.pyplot as plt
plt.figure(figsize=(20, 10))# Limiting the data set to 100 rows for more clearance
plt.plot(y_hat_pca[:100], label = "Pred")
plt.plot(y_test[:100], label = "Actual")plt.title('Comparison of Prediction vs Actual - With PCA')
plt.legend()
plt.show()
预测值与实际值的比较
9.精度测量和评估技术
正如我们前面讨论的,线性回归试图拟合一条使原始点偏差最小的直线。所以实际和预测之间有误差。通过测量这个误差(损失),我们可以检查我们的模型的准确性。
我们用损失函数来衡量这一点。当损失最小时,我们可以判定该模型具有非常好的精度。有几种损失函数可用:
- MSE —均方误差
- 平均绝对误差
- RMSE —均方根误差
当记录模型的效率作为输出时,建议使用 MSE 上的 RMSE,因为 MSE 广泛用于消除训练阶段的误差。(对模型优化更好。)不建议用 MAE 来测试精度,因为它不能让我们知道误差的方向。
除此之外,还有各种评估技术,如 F1 分数、曲线下面积、混淆矩阵等来衡量模型的准确性。你可以多搜索一下这些东西来提高自己的知识。我也打算就此单独写一篇文章。
好吧。让我们为我们的模型检查 MSE 和 RMSE。
我们使用 R 平方值来评估线性模型的整体拟合度。介于 0 和 1 之间。值越高,性能越好。因为这意味着模型可以解释更多的方差。
#Percentage of explained variance of the predictions
score_pca=lm2.score(X_test_pca,y_test)
score_pca
#This has given - 0.9902083367554705
这些实际上是很好的价值观。但在得出结论之前,我们也来分析一下权重因素。
#W parameters of the model
print(lm2.coef_)
模型的 w 参数
权重也可用于评估模型。如果权重给出了更高的值,这表明您的模型过度拟合。如果是这样,你需要重新审视你的预处理和转换步骤,分析你是否做错了什么。
此外,另一个可能导致过度拟合的因素是模型的复杂性。如果对简单数据集应用多项式或高阶回归,可能会过度拟合。所以你可以试着简化模型。此外,你可以进一步研究如何做体重规律化。在我们的场景中,权重因子要小得多,而且不会过多。
您可以进一步进行 K-fold 交叉验证,以获得总体准确性得分。我已经在笔记本上做了。你也可以参考其他测试。
最终交叉验证分数
所以现在我们可以得出结论,我们的模型已经达到了 99%以上的准确率。
10.资源
- 完整的合作实验室笔记本。(带有预加载的数据集)
https://colab.research.google.com/drive/10sHxKg512G4v9d79Z3EI3ixZ_E1gs5Iq?usp=sharing
- Kaggle 天气历史数据集
https://www.kaggle.com/budincsevity/szeged-weather?select=weatherHistory.csv
结论
通过这篇文章,我们已经讨论了很多重要的概念。我希望现在您已经清楚了如何通过理解核心概念来从头开始训练和测试一个模型。
数据科学是一个非常广泛的领域,不可能什么都知道!但是有大量的文章可以探索这个神奇的世界。所以,学好基本概念,在提高知识的同时,用它们来解决实际问题。
我要特别感谢 Subha Fernando 博士(莫拉图瓦大学高级讲师)激励我写这篇文章。
非常感谢你坚持到最后!希望这篇文章能帮助你了解 ML。如果你有什么需要澄清或提及的,请留言。
快乐学习!❤️***
用 Python 构建机器学习 web 应用程序
原文:https://towardsdatascience.com/build-a-machine-learning-web-app-in-python-683480acbd37?source=collection_archive---------6-----------------------
在 7 分钟内编写并部署您的第一个机器学习 web 应用程序
詹姆斯·亚雷马在 Unsplash 上的照片
介绍
在过去的几年中,对数据相关工作的需求大幅增长。
大多数有抱负的数据科学家要么参加数据科学课程,获得硕士学位,要么参加训练营,开始他们的行业之旅。
这些地方教授的技能主要围绕机器学习。
当我第一次开始自学数据科学时,我在 Udemy 和 Coursera 上学习了多门在线课程。我学习了机器学习技能,并建立了一个主要围绕建模和算法的基础。
然而,在实践中,大多数建立机器学习模型的公司都需要部署它们。这些模型需要投入生产,以便最终用户可以访问它们。
这个旅程不会随着建立机器学习模型而结束。模型创建只是开始。对数据科学家来说,部署这些模型并对其进行扩展以便最终用户可以访问是一项非常重要的技能。
一些公司甚至为此雇佣 MLOps 工程师。这些人专门从事模型部署,他们的工作围绕着将机器学习模型投入生产。
然而,作为一名数据科学家,至少对模型部署有一个基本的了解仍然很重要。并不是所有的公司都有专门研究 MLOps 的团队,所以需要很多数据科学家来打理端到端的流程。
在本文中,我将带您了解机器学习模型的构建和部署。本教程将涵盖三个部分:
- 构建机器学习模型
- 用这个模型创建一个 web 应用程序
- 在谷歌云平台上部署这个模型
我们将构建一个简单的情感分析应用程序。这个应用程序将获得一个句子作为用户输入,并返回一个预测,这个句子是积极的,消极的,还是中性的。
这是最终产品的外观:
作者图片
第一步:设置
您可以使用任何 Python IDE 来构建和部署这个应用程序。我建议用 Atom,Visual Studio 代码,或者 Eclipse。您将无法使用 Jupyter 笔记本来构建 web 应用程序。Jupyter 笔记本主要用于数据分析,用 Jupyter 运行 web 服务器是不可行的。
一旦设置了编程 IDE,就需要安装以下库:Pandas、Nltk 和 Flask。
步骤 2:构建应用程序
为整个情感分析项目创建一个文件夹。在您的主文件夹下,您需要有以下文件:
作者图片
让我们一个一个地检查这些文件:
首先,创建名为 main.py 的文件。这是包含所有机器学习代码的文件。
完成后,将下面几行代码复制并粘贴到您的 main.py 文件中:
import pandas as pd
import nltk
from flask import request
from flask import jsonify
from flask import Flask, render_templateapp = Flask(__name__) @app.route('/')
def my_form():
return render_template('index.html')@app.route('/', methods=['POST'])
def my_form_post():
text = request.form['text']
nltk.download('vader_lexicon')
from nltk.sentiment.vader import SentimentIntensityAnalyzer
sid = SentimentIntensityAnalyzer()
score = ((sid.polarity_scores(str(text)))['compound']) if(score>0):
label = 'This sentence is positive'
elif(score == 0):
label = 'This sentence is neutral'
else:
label = 'This sentence is negative' return(render_template('index.html', variable=label))if __name__ == "__main__":
app.run(port='8088',threaded=False)
我选择在端口 8088 上运行这个应用程序,但是任何空端口都可以。
在运行应用程序之前,在你的父目录下创建一个名为模板的文件夹。然后,在这个文件夹中创建一个名为 index.html: 的文件
作者图片
在index.html文件中,键入以下代码行:
<!DOCTYPE html>
<html>
<head>
<body> <link rel='stylesheet' href='bootstrap.min.css'></style>
<link rel='stylesheet' href='font-awesome.min.css'></style> <div class="container">
<div class = "centered">
<header class="text-center text-white">
<title> sentiment analysis app </title> <h1 class = 'header'>
Sentiment Analysis App
</h1> <p class = 'desc'>
Type a sentence, click on the submit button and wait for your prediction.
</p> <form method="POST" onSubmit = 'return validate();' class='form'>
<input name="text">
<input type="submit" onclick = 'this.form.submit();'>
</form>
<br>
<br> <p id='demo'>{{ variable }} </p>
</div>
</div>
</head>
</body> <style> .container {
position: relative;
text-align: center;
color: white;
} .header {
color: black
} p { color: #111; font-family: 'Helvetica Neue', sans-serif; font-size: 14px; line-height: 24px; margin: 0 0 24px; text-justify: inter-word; } h1 { color: #111; font-family: 'Helvetica Neue', sans-serif; font-size: 36px; font-weight: bold; letter-spacing: -1px; line-height: 1; text-align: center; } #demo {
color: #111; font-family: 'Helvetica Neue', sans-serif; font-size: 22px; line-height: 24px; margin: 0 0 24px; text-justify: inter-word;
} input[type=submit] {
background-color: #f06237; /* Green */
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 0.95em;
} input[type=submit]:hover {
background-color: #b0540e;
} </style>
</html>
上面几行代码将创建我们的应用程序的前端:输入文本框、描述和提交按钮。
点击提交按钮后,Flask 应用程序的输出将显示在屏幕上。
在这种情况下,输出将是正的、负的或中性的,这取决于用户的输入。
太好了!
现在,我们已经拥有了在本地运行 Flask 应用程序所需的一切。
在 Python 上运行应用程序,然后转到应用程序所在的位置。以我为例,它将是 127.0.0.1:8088。
您应该会看到应用程序显示在屏幕上:
作者图片
你可以摆弄你的应用程序,输入随机的句子作为输入,以检查算法是否做出准确的预测。
步骤 3:应用程序部署
现在,是时候部署应用程序了。我们会在谷歌云平台上做这件事。
如果你不熟悉 GCP,下面是你需要做的开始:
- 按照这个教程创建一个 GCP 账户。
- 您将看到一个激活您的 GCP 帐户的选项。点击“激活”您将被要求输入您的信用卡信息。但是,您不会被起诉。一旦您创建了一个 GCP 帐户,您将获得 300 美元信用的免费试用,并且您使用的服务将不会被收费,除非您超过了这个限额。
现在,按照以下步骤在 GCP 上部署您的应用程序:
- 首先,转到页面顶部,点击下拉菜单。你会看到一个像这样的屏幕,列出了你过去所有的项目。如果你刚到 GCP,这里是空的:
作者图片
点击新建项目。
2.将项目的名称更改为您喜欢的任何名称,然后单击 Create。
作者图片
3.转到主页->仪表板,检查您创建的项目是否列出:
作者图片
4.现在,您需要安装 Google Cloud SDK。这将允许您通过本地命令行在 Google Cloud 上部署您的机器学习模型。只需点击此链接并安装可执行文件,然后继续点击“下一步”直到安装完成。
5.在您的父文件夹中创建一个名为 app.yaml 的文件,并键入以下内容:
runtime: python37
6.现在,在父文件夹中创建一个名为 requirements.txt 的文件,并在其中键入以下内容:
pandas==1.3.2
nltk==3.6.2
Flask==2.0.1
7.一旦完成,检查以确保您的父目录中有以下文件: main.py 、 app.yaml 和 requirements.txt 。在模板文件夹中,你应该有一个index.html文件。
8.打开本地命令提示符,导航到 ML 应用程序所在的目录。然后,在命令提示符下键入 gcloud init :
作者图片
9.为“创建新配置”选择数字选项对我来说,是 2。
作者图片
10.然后,选择您想要使用的电子邮件地址。然后,选择您想要使用的项目。这将是您之前创建的项目。
作者图片
11.之后,您将被要求为您的计算引擎虚拟机选择一个区域。任何地区都可以,只要选择一个。
作者图片
12.现在,您可以输入命令在 Google Cloud 上部署您的应用程序。为此,请键入:
gcloud app deploy app.yaml --project *your_project_name*
例如:
作者图片
现在,等待部署完成。这需要几分钟时间。
13.部署完成后,在终端中键入' gcloud app browse' 。您将被自动导航到您在 Google Cloud 上的应用位置。这个是我的。
如果一切正常,您应该会看到您的应用程序部署在自定义的 URL 上,如下所示:
作者图片
如果你坚持到了最后,恭喜你!您已经成功地将您的第一个应用程序部署到 Google Cloud。
如果你对 GCP 要求输入信用卡信息进行免费试用感到不快,那么你可以尝试一个不同的平台。我将在未来创建更多教程,涵盖 AWS 和 Heroku 等平台上的模型部署。
本教程到此为止!
我希望你喜欢这篇文章,并能从中学到一些新的东西。
祝您的数据科学之旅好运,感谢您的阅读。
在云上建立一个基于 MFCC 的音乐推荐引擎
原文:https://towardsdatascience.com/build-a-mfcc-based-music-recommendation-engine-on-cloud-3bf3cfbd594b?source=collection_archive---------26-----------------------
作者 GIF
实践教程
在 Microsoft Azure 中创建非结构化数据驱动的创新应用程序的简单指南。
在过去的十年里,移动技术和蜂窝网络的发展以无人能预测的方式前所未有地重塑了世界。我们生活在一个信息爆炸的时代,并且利用由越来越便宜的蜂窝数据驱动的花哨的移动应用。自从配备音乐流媒体应用程序(如 Spotify 和 Pandora)的智能手机问世以来,随身听和 iPods 已经不再放在我们的口袋里。如果你正在使用或曾经使用过其中的一个,你可能会知道音乐推荐列表,也就是流媒体播放音轨时的“猜你喜欢”功能。音乐推荐是一个大话题,现有的文章阐述和探索了背后运行的算法——流派的聚类分析、歌词的 NLP 建模、基于用户和基于内容的协作过滤等等。那么,有没有一种内在的方式可以基于音频信号本身来进行推荐呢?答案是肯定的,本文将介绍一些基本的声学知识,并探索基于轻量级音频特征的音乐推荐系统的可行性。
1.声音音高
根据定义,声音是一种由振动产生的能量,振动通过空气等传输介质以一定的频率和振幅传播正弦波。一段音乐本质上是一系列不同频率和振幅的声波。“音高”一词广泛用于感知乐器的音频特性。虽然不完全等同,但频率被视为“音高”的代理。当人们说“高音乐器”时,它特指那些总是以更高频率产生声波的管弦乐队乐器,例如小号、短笛或小提琴。很明显,声音频率和人们的情绪之间有很强的相关性,有趣的事实之一是,有时人们声称调到 A432 的钢琴比调到 A440 的钢琴优越,因为所谓的 432 赫兹的“治疗频率”。
图片由 Alexyo 提供。维基共享资源网https://commons . wikimedia . org/wiki/File:Estensione _ Strumenti _ musicale . jpg
2.振幅
声波的振幅决定了声音的响度,当声音产生时,振动产生的空气压缩会产生压力变化,这种压力变化可以被耳朵感知。感知到的压力变化(以 dB 为单位)也受到到声源的距离的影响。一般来说,每增加一倍距离,点声源的声压级衰减 6dB,线声源衰减 3dB。
3.数字录音
谈到数字音频,有一个关键概念是我们无法回避的——采样率。在数字录音中,样本是沿着声波以一定的间隔采集的,采集样本的频率就是我们所说的采样率。如果你喜欢音乐,你可能知道“44.1 千赫/16 位”标签印在你的 CD 封面背面。44.1kHz 是消费类 CD 的标准采样速率,有些可以达到 48kHz。为什么是这个数字?这是因为 20kHz 通常被认为是人耳能够感知的上限,根据奈奎斯特–香农采样定理,采样率必须是 处的至少是原始音频信号最大频率的两倍,以避免意外失真或混叠。采样率越高越好吗?音质方面是的,经常看到高保真发烧友对“劣质”44.1kHz/16 位嗤之以鼻,并追求以 96kHz/24 位甚至 192kHz/24 位录制的优质音轨,这些音轨来自模拟介质,如任何基于线性 PCM 的无损音频格式(如 WAV、FLAC 或 APE)中的乙烯。
作者的情节
好了,是时候进行一些音频分析了,让我来绘制一下我最喜欢的挪威歌手凯瑞·布莱妮丝演唱的配乐《柏林恋人》的音频样本。通常情况下,我们希望大多数声道都有两个声道,而且在大多数情况下,它们是相似的。振幅被标准化为从 0 到 1 的范围。
import matplotlib.pyplot as plt
from scipy.io import wavfile
import numpy as npfile = r"(01) [Kari Bremnes] A Lover in Berlin.wav"
sample_rate,data = wavfile.read(file)
length = data.shape[0]/sample_rate
fig,axes = plt.subplots(1,2,figsize=(20,7))
time = np.linspace(.0,length,data.shape[0])
for i,j,k in zip(range(axes.size),["Left Channel","Right Channel"],["b","y"]):
axes[i].plot(time, data[:, i]/data[:, i].max(),color=k)
axes[i].set_xlabel("Time [s]")
axes[i].set_ylabel("Amplitude")
axes[i].set_title(j)
plt.show()
作者的情节
4.频域信号
由于声波是时域信号,需要对频域响应进行快速傅立叶变换。
from scipy.fftpack import fft# Take the left channel
a = data.T[0]
# Normalised fast fourier transformation
c = fft(a)/len(a)
freqs = np.arange(0, (len(a)), 1.0) * (sample_rate*1.0/len(a))
plt.figure(figsize=(20,7))
y=c[:int(len(c))]
# Normalised the amplitude plt.plot(freqs/1000,abs(y)/max(abs(y)),'r')
plt.xlabel("Frequency (kHz)")
plt.ylabel("Amplitude")
plt.show()
作者的情节
等等…为什么这个 FFT 图是镜像的?由于离散傅立叶变换的性质,在技术上它被称为共轭对称。DFT 公式写为:
Xn 这里是幅度输入,在这种情况下是实数, k 表示当前频率,而输出 Xk 是封装了幅度和相位信息的复数。根据欧拉公式,基本方程可以写成:
Xk 在某个 n 处具有正或负的频率项。**Xk的幅度实质上就是我们想要绘制的振幅,可以从其实部和虚部导出:
如你所见,正频率和负频率下的 Xk 具有相同的幅度,因此在幅度方面响应相同,换句话说,正频率下的 Xk 与负频率下的 Xk 共轭。也就是说,我们只需要用整个情节的前半部分来讲述故事,但考虑到大多数特征分布在低频带上,为了便于展示,我选择了前 1/20:
作者的情节
正如所料,该原声带的声学特征在以下意义上得到了很好的呈现:丰富的尖峰信号遍布 200~600 Hz ,这符合典型的女性音域。已经说过,FFT 响应在这里很有意义,但我们不能在建模时单独使用它,因为 FFT 不处理时间特性。音乐,在某种程度上,就像是按照一定顺序承载信息的语言。如果您熟悉 NLP,您可能知道像双向 LSTM 和 BERT 这样的算法通常比 TF-IDF 性能更好,因为输入顺序起着关键作用。类似地,我们想在这里捕捉这个特性。频谱图似乎是一个很好的方法,因为它显示了频率和振幅如何随时间变化。
plt.figure(figsize=(25,8))
plt.title('Spectrogram - A Lover In Berlin',fontsize=18)
spec, freqs, t, im = plt.specgram(data[:,0],Fs=sample_rate,NFFT=512)
plt.xlabel('Time [s]',fontsize=18)
plt.ylabel('Frequency',fontsize=18)
plt.show()
作者的情节
5.梅尔频率倒谱系数
如果我们选择在频谱上建模,就会出现一个新的问题——将原始频率作为输入似乎不现实,因为它太细了。有没有什么技巧可以根据我们现有的东西生成一个低基数的特性? MFCC **(梅尔-倒谱系数)**就是要走的路之一!MFCC 广泛用于语音分析。虽然已有文章涉及这个主题,但我仍然想简单介绍一下倒谱的概念。cepsturm 是“规格”相反的频谱,从技术上讲,它是通过对原始 FFT 信号的对数进行傅里叶逆变换而得到的。它描述了不同光谱带的变化率。所得的倒谱是“倒频”域中的信号。
作者的情节
梅尔频率倒谱是通过将初始 FFT 响应传递给一组称为梅尔滤波器组的带通滤波器而获得的。在取对数之前,这些滤波器的工作方式与人耳相同。假设人耳天生是一个低通滤波器,这就是为什么我们大多数人无法感知 20kHz 以上的高频声音。Mel-frequency 通过以下公式将原始频率输入映射到 Mel-scale:
简而言之, Mel-scale 针对人类听觉系统进行了优化。得到的 MFC 有 13 个系数:
from python_speech_features import mfcc
from matplotlib import cmplt.figure(figsize=(25,8))
mfcc_feat = mfcc(a,sample_rate)
mfcc_data= mfcc_feat.T
plt.imshow(mfcc_data, cmap=plt.cm.jet, aspect='auto',origin='lower')
plt.title('MFC - A Lover In Berlin',fontsize=18)
plt.xlabel('Time [s]',fontsize=18)
plt.ylabel('MFCC',fontsize=18)
plt.show()
作者的情节
6.动态时间扭曲
鉴于我们的最终目标是开发一个音乐推荐引擎,可以根据歌曲之间这些系数的相似性进行推荐。嗯…相似度是怎么计算的?由于音轨长度可能因人而异,这是不太可能进行比较,是吗?动态时间缠绕(DTW)就是为了解决这个问题而设计的。根据定义, **DTW 是一种时间序列对齐算法,其目的是通过反复扭曲时间轴来对齐两个特征向量序列,直到最佳匹配。**这意味着我们可以使用它来计算任何两个输入向量之间的相似性或距离,而不用担心输入长度。
作者的情节
我创建了一个迷你音乐库,包含 151 首 MP3 格式的 190kbps 的音轨,涵盖了广泛的流派,如流行、爵士、民谣、金属、摇滚、R&B 等。让我们来看看我的音乐库中所有 13 个系数的分布情况。
from python_speech_features import mfcc
import seaborn as sns
import librosa
import ostracks = os.listdir(r"soundtracks")
L=[]
for i in tracks:
data,sample_rate = librosa.load(r"soundtracks"+"\\"+i,sr=44100)
# Cut off the first and the last 500 samples
a = data.T[500:-500]
a = a/a.max()
plt.figure(figsize=(20,7))
mfcc_feat = mfcc(a,sample_rate)
mfcc_data= mfcc_feat.T
L.append(mfcc_data)
L2 = np.array([i.mean(axis=1) for i in L])
fig,axes = plt.subplots(5,3,figsize=(30,10))
for i in range(L2.shape[1]):
sns.distplot(L2.T[i],ax=axes.ravel()[i])
axes.ravel()[i].set_title("Coe "+str(i))
plt.tight_layout()
作者的情节
看起来所有 13 个系数正态分布在我的音乐库中,因此我将对所有 13 个 coe 向量上计算的 DTW 距离求和,作为任何两个音轨的整体相似性的代理。让我们看看这个算法是否有效:
from fastdtw import fastdtw
import numpy as npc=[]
for i in range(len(L)):
group = []
for n in range(13):
dis,path=fastdtw(L[2][n],L[i][n])
group.append(dis)
total_dis = np.sum(group)
c.append([total_dis,i])
c.sort(key=lambda x:x[0])
fig,axes = plt.subplots(1,2,figsize=(25,8))
tracks = os.listdir("soundtracks")
for i,j in enumerate([tracks[2],tracks[c[1][1]]]):
title = "MFC-"+j.replace(".mp3","")
data,sample_rate = librosa.load(r"soundtracks"+"\\"+j,sr=44100)
a = data.T[500:-500]
a = a/a.max()
mfcc_feat = mfcc(a,sample_rate)
mfcc_data= mfcc_feat.T
axes[i].set_title(title,fontsize=18)
axes[i].set_xlabel('Time [s]',fontsize=18)
axes[i].set_ylabel('MFCC',fontsize=18)
axes[i].imshow(mfcc_data, cmap=plt.cm.jet, aspect='auto',origin='lower')
plt.tight_layout()
作者的情节
Ok…The result indicates that the closest soundtrack to “A Lover In Berlin” is “Samba De Verao” performed by Ono Lisa (小野リサ). Folk pop vs. Bossa nova, both are stylish female vocal music. Not too bad!
图片由 J esterWr,Danniel Shen 在维基共享资源https://commons . wikimedia . org/wiki/File:Lisa _ Ono _ 2005 _(已裁剪)。jpghttps://commons . wikimedia . org/wiki/File:Kari-brem nes 2012 . jpg
7.云解决方案开发
现在让我们在 Microsoft Azure 上开发一个完整的解决方案来托管这项服务。这个解决方案采用了一个迷你的λ架构。速度层是提取并加载上传的配乐的元数据,我们要针对这些元数据向 Azure CosmosDB 提出建议。批处理层执行推荐逻辑,并将结果推荐列表加载到 SQL 数据库。所有服务组件都是用 Python 和 Spark 开发的。
作者的架构图
7.1 主要工作流程
- 开发了一个 flask 应用程序,并将其部署到 Azure App Service,作为初始音频文件上传和后续推荐音乐流的主 UI。
- 构建 Azure SQL 数据库来存储音乐库元数据,例如标题、艺术家、专辑、流派、发行年份、音轨路径和作品路径。
- 在同一个 Azure 存储帐户中创建了 5 个 blob 容器。
- 容器 A 捕获 blob 中的初始上传,并触发 Azure 函数通过第三方音乐识别 API 服务收集元数据,并将 json 中的结果加载到 CosmosDB,以供另一个 Azure 函数查询,该函数充当 web 应用程序使用的 API 端点。
- 初始上传在 blob 中被复制到容器 B,因为它在容器 a 中着陆。该复制被视为由 Azure 事件网格捕获的 blob 更改事件,该事件随后触发放置在 Azure 数据工厂管道中的 Azure Databricks 笔记本。该笔记本将执行推荐逻辑,并将结果推荐列表加载到 Azure SQL 数据库中的另一个表中,以加入到包含 web 应用程序查询的所有元数据的视图中。
- 容器 C 用于存储包含音乐库的梅尔频率倒谱的拼花文件。在步骤 5 中,parquet 文件被注册为一个 Hive 表,供 Azure Databricks 引用。
- 构建容器 D 和 E 是为了存储音乐库音轨和艺术作品,以便通过 web 应用程序进行流式传输和显示。
- 包括 CosmosDB 连接字符串、SQL 数据库连接字符串、Blob 存储连接字符串和第三方音乐识别 API 令牌在内的所有服务凭据都存储在 Azure Key Vault 中并受其保护。
7.2 主数据准备
将配乐和艺术品装入指定的容器。
作者图片
在 SQL 数据库中创建一个新表来存储音乐库元数据。
作者图片
从音频文件中提取元数据,并将它们加载到数据帧中。音轨路径和插图路径由共享访问签名( SAS )通过 blob 客户端 API 生成。
from mutagen.easyid3 import EasyID3
import pandas as pd
import os
from azure.storage.blob import generate_container_sas
from datetime import datetime,timedeltasongs = os.listdir("soundtracks")
l=[]
for song in songs:
audio = EasyID3("soundtracks"+"\\"+song)
meta=[]
for e in ["title","album","artist","genre","date"]:
try:
if e=="date":
attr = audio[e][0][:4]
elif e=="title":
attr = song.replace(".mp3","")
else:
attr = audio[e][0]
meta.append(attr)
except:
meta.append(None)
l.append(meta)df = pd.DataFrame(l,columns=["TITLE","ALBUM","ARTIST","GENRE","RELEASE_YEAR"])
key=my_key
sas_sound=generate_container_sas('xwstorage', 'soundtracks',key,expiry=datetime.utcnow()+timedelta(days=30),permission='r')
sas_art=generate_container_sas('xwstorage', 'artworks',key,expiry=datetime.utcnow()+timedelta(days=30),permission='r')
df["SOUNDTRACK_PATH"] = "[https://xwstorage.blob.core.windows.net/soundtracks/](https://xwstorage.blob.core.windows.net/soundtracks/)"+df["TITLE"]+".mp3"+"?"+sas_sound
df["ARTWORK_PATH"] = "[https://xwstorage.blob.core.windows.net/artworks/](https://xwstorage.blob.core.windows.net/artworks/)"+df["TITLE"]+".jpeg"+"?"+sas_art
作者图片
将生成的数据框加载到我们之前创建的 SQL 表中。
import sqlalchemy
import pyodbc
from sqlalchemy.engine import URLcnxn = my_odbc_connection_string
connection_url = URL.create("mssql+pyodbc", query={"odbc_connect": cnxn})
engine = sqlalchemy.create_engine(connection_url)
df.to_sql("SOUNDTRACKS", engine,if_exists="append",index=False)
作者图片
将音乐库 Mel 频率倒谱转储到拼花文件中,然后将拼花文件上传到指定的容器中。
import pandas as pd
from python_speech_features import mfcc
import matplotlib.pyplot as plt
import librosa
import ostracks = os.listdir(r"soundtracks")
L=[]
for i in tracks:
print(i)
data,sample_rate = librosa.load(r"soundtracks"+"\\"+i,sr=44100)
a = data.T[500:-500]
a = a/a.max()
plt.figure(figsize=(20,7))
mfcc_feat = mfcc(a,sample_rate)
mfcc_data= mfcc_feat.T
L.append(mfcc_data)
columns = ["COE_"+str(i) for i in range(1,14)]
L2 = [pd.DataFrame(i.T,columns=columns) for i in L]
titles = [i.replace(".mp3","") for i in tracks]
for i,j in zip(L2,titles):
i["Title"]=j
df=pd.concat(L2)
df.reset_index(drop=True).reset_index().to_parquet("soundtracks.parquet")
作者图片
7.3 加密
如前所述,所有服务凭据都存储在 Azure Key Vault 中,并由 Azure Key Vault 保护。
作者图片
7.4 速度层
创建一个 CosmosDB 实例来存储上传的音频文件的元数据。
创建一个 blob 触发器类型的 Azure 函数作为起点。该功能是从输入 blob 中剪切出 200KB 的样本,并将其发送到第三方音乐识别服务 API 以收集元数据。
让该函数将输出路径绑定到 CosmosDB 和另一个 blob 容器,这样原始输入 blob 将被复制到批处理层处理所需的位置,同时 json 中的结果元数据将被加载到 CosmosDB 中。
作者图片
作者图片
用 GET 方法创建一个 http-trigger 类型的 Azure 函数,只查询 CosmosDB 中的最新记录。这个函数作为一个 API 端点被 web 应用程序使用。
作者图片
一旦我们部署了两个 Azure 函数,我们可以简单地将一个 MP3 文件放到目标 blob 容器中,以快速测试 API 端点是否在浏览器中工作。
作者图片
7.5 批次层
为 Azure Databricks 创建一个群集实例。将倒谱拼花文件加载到 spark 数据框中,并将其注册为 Hive 表。假设倒谱表有将近 400 万行,而只有 14 列(13 个 MFCC +标题),在这种情况下,像 parquet 这样的列存储格式 比像 CSV 这样的行存储格式更加优化。
需要创建一个秘密范围来与 Azure Key Vault 交互。
作者图片
创建一个新的笔记本,重写基于 DTW 的 MFCC 相似性计算逻辑,从 Python 列表迭代触发数据框操作,并通过 JDBC 连接器将结果加载到 Azure SQL 数据库。
鉴于相似性计算只需要大型表聚合,并且不涉及任何机器学习算法,多节点计算环境在这里绝对具有优势,这是我选择 Azure Databricks 而不是 Azure ML 服务进行此操作的根本原因。
作者图片
如果操作成功,建议列表将被加载到 SQL 表中,以连接到视图中。
将笔记本放在 Azure 数据工厂管道中,并使其可被目标容器中发生的 blob 更改事件触发。在这种方式下,笔记本将在初始上传从速度层容器复制到批处理层容器后立即被激活。
作者图片
7.6 网络应用
开发并部署 flask 应用到 Azure 应用服务。该应用程序是用来渲染 2 个 html 页面。第一个用于音乐文件上传,第二个用于推荐音乐流。
作者图片
7.7 Web 应用程序测试
最后…演示环节。上传了玛丽莲·曼森表演的无信息配乐“午餐盒”。这首歌和前 5 首相似的歌曲被准确地识别出来,其中一首是由同一位歌手演唱的!
参考文献
- https://link . springer . com/content/pdf/bbm % 3a 978-3-319-49220-9% 2 f1 . pdf
- https://en.wikipedia.org/wiki/Dynamic_time_warping
- https://en.wikipedia.org/wiki/Cepstrum
在 5 分钟内构建一个电影推荐引擎后端 API(第 2 部分)
原文:https://towardsdatascience.com/build-a-movie-recommendation-engine-backend-api-in-5-minutes-part-2-851b840bc26d?source=collection_archive---------18-----------------------
为一个令人印象深刻的数据科学组合项目创建一个简单的后端 Flask API
劳伦·曼克在 Unsplash 上的照片
让自己成为一名数据科学家是一项挑战,因为每个人都上过机器学习课程,熟悉分类和回归等概念。要想真正脱颖而出,你需要展示一个真实世界的产品,让招聘人员能够很快抓住它。
在这篇文章中,我们将创建一个 Flask API,它根据其他人的评分向用户推荐电影。我们将使用开源的 MovieLens 数据集,并实现项目到项目的协作过滤方法。
本系列第 1-4 部分的目标是为您提供如何构建电影推荐引擎的分步指南,然后您可以将它放在您的 GitHub & Resume 上,以增加您获得梦想中的数据科学工作的机会。
在上一个教程中,
- 通过简单的例子解释用户对用户与项目对项目的协同过滤(第一部分)
我们讨论了什么是项目对项目的协同过滤,在以后的文章中,我们将讨论:
- 如何在 AWS &上部署 Flask API(我们将在本文中构建)
- 如何使用 Vue.js 创建前端?
您将通过本系列构建的最终产品可以在以下设备上试用:
- mynextmovie.ca
看起来会像这样
最终产品:电影推荐引擎
我们开始吧!
第一步是从以下位置下载数据:
[https://grouplens.org/datasets/movielens/](https://grouplens.org/datasets/movielens/)
我使用了来自 MovieLens 的以下数据集:“教育&发展”。
用户评分数据来源:MovieLens
下载并解压缩“ml-latest-small”文件夹后,让我们将相关文件加载到 Jupyter 笔记本中:
import pandas as pddf_movies = pd.read_csv('~/Downloads/ml-latest-small/movies.csv')
df_ratings = pd.read_csv('~/Downloads/ml-latest-small/ratings.csv')
df_merged = pd.merge(df_movies, df_ratings, on='movieId', how='inner')df_merged.head()
接下来,让我们创建一个 dataframe,该 data frame 将单个用户评级映射为行,将每个电影映射为列,并删除少于 8 个评级的电影。
df = df_merged.pivot_table(index='userId', columns='title', values='rating')# Keep only movies that had at least 8 ratings
df = df.dropna(thresh=8, axis=1)
df.fillna(0, inplace=True)
df.head()
现在我们可以使用皮尔逊相关来计算电影之间的相似性。皮尔逊方法将每个电影(即列)视为包含用户评级值的向量,并确定一部电影与其他电影的接近/相似程度。从下面的相似度矩阵可以看出,每部电影都与自己非常相似,要么与其他电影高度相关(~ +1 ),要么高度不相似(~ -1 )。
df_similarity = df.corr(method='pearson')#Store the data for later to be used in building the API
df_similarity.to_csv('movie_similarity.csv')df_similarity.head()
如果你像我一样喜欢电影“Heat (1995)”,让我们看看通过访问相应的电影列并从最高到最低排序相似性得分以获得前 50 名电影推荐,我们会得到什么推荐:
movieLiked = 'Heat (1995)'
similarityScores = df_similarity[movieLiked]
similarityScores.sort_values(ascending=False)[1:50]
看起来电影《摇滚》和《赌场》是我们的两大推荐。
是时候创建 Flask API 了,它可以被部署并用于实时推荐电影。
如果你熟悉 Flask,请跳过下面的“Flask入门”部分,直接进入“电影推荐引擎 Flask API 部分。
烧瓶使用入门
如果您没有 Flask,您可以使用 pip 安装它:
pip install Flask
让我们简单地从创建一个 python 文件开始: flask_ex.py ,代码如下:
在您的终端中,您可以运行这个文件,它实际上将运行一个 Flask 服务器:
python flask_ex.py
应该会看到以下显示内容:
在一个单独的终端中,您可以使用 curl 命令向您的默认" / " flask API 资源发送 HTTP 请求来测试它:
curl [http://0.0.0.0:80](http://0.0.0.0:80)
应该输出:
我们可以通过以下命令访问 /find_friend 资源,找出 Joey 最好的朋友是谁:
curl -X POST [http://0.0.0.0:80/find_friend](http://0.0.0.0:80/find_friend) -H 'Content-Type: application/json' -d '{"person":"Joey"}'
应该输出
电影推荐引擎 Flask API
现在让我们创建我们的 Flask API-application . py文件,它将提供电影推荐:
注意:确保你的 application.py 文件在你从 jupyter 笔记本输出 movie_similarity.csv 文件的同一个目录下。
如您所见,我们创建了一个名为 /recms 的资源,当向发出“POST”请求时,该资源将访问 make_rec() 函数,并获取用户最喜欢的电影的“movie_title ”,将其存储在“movie”变量中,并查找类似的电影作为推荐。
然后, api_recommendations 列表从 Flask API 发送到前端,并且包含电影推荐列表,然后可以向用户显示该列表。
让我们用电影《热度(1995)》再来测试一下。
首先,要运行 API,在终端中执行以下命令
python application.py
然后在单独的终端中执行以下命令:
curl -X POST http://0.0.0.0:80/recms -H 'Content-Type: application/json' -d '{"movie_title":"Heat (1995)"}'
如果一切正常,您应该会看到以下输出:
API 输出一个包含电影推荐的列表,然后可以被前端使用。
就这样,我们成功构建了我们的电影推荐引擎 Flask API!
遗言
在下一篇文章中,我们将介绍如何将这个 API dockerize 并将其部署在 AWS 上,供其他人使用。
参考文献
- 电影镜头
- https://medium . com/code-heroku/how-to-turn-your-machine-learning-scripts-into-projects-you-can-demo-CBC 5611 ca 442
- https://flask.palletsprojects.com/en/2.0.x/api/
使用 Vue.js 构建电影推荐引擎前端(第 4 部分)
原文:https://towardsdatascience.com/build-a-movie-recommendation-engine-frontend-using-vue-js-part-4-ac85280da670?source=collection_archive---------19-----------------------
本分步指南面向希望使用 Vue.js 为电影推荐引擎应用程序构建简单前端的数据科学家和 web 开发人员。
我们在这里构建的最终产品可以在 mynextmovie.ca 上试用
这是我们 4 部分系列的最后一部分!在前 3 篇文章中,我们介绍了协作过滤的理论,如何构建 Flask API,以及如何在 AWS ECS 上部署 API。以下是之前的帖子:
- 通过简单的例子解释用户对用户与项目对项目的协同过滤(第一部分)
- 如何构建电影推荐引擎后端 Flask API(第二部分)
- 如何在 AWS ECS 上部署 Flask API(第 3 部分)。
在这篇文章中,我们将构建一个简单的 Vue.js 前端,旨在尽可能简化电影推荐。因此,我们将只要求用户输入他们最喜欢的电影,并推荐与之相似的电影。
这个项目的关键功能是自动搜索功能,用于从 MovieLens 数据集中查找电影标题,并利用开源的废弃电影海报到通过后端 API 显示推荐的电影。
如果您熟悉 Vue.js,请跳过' 建议,如果您是前端开发 新手,请直接进入' 使用 Vue.js 构建前端'部分。
如果你是前端开发新手的建议
如果你是 Vue.js 的新手(和我一样),我建议你先浏览一下精彩的 Khan Academy 资源,这些资源侧重于 HTML/CSS、JavaScript、DOM 和 jQuery,以便熟悉核心的前端概念。
Vue.js 是最新的 JavaScript 框架之一,它使我们能够在 10 到 100 行代码中构建交互式特性。在本文中,我们将使用 Vue 2。您需要了解的最重要的 Vue 基本概念是:
i) Vue 项目结构
如果您运行一个简单的命令
vue create vue_proj_ex
它将创建一个完整的项目,可以使用
npm run serve
创建的模板项目需要关注的关键方面如下:
主应用程序设置在 App.vue 中,我们在其中加载 组件 如 HelloWorld.vue 以及任何 json 数据子目录。在 main.js 中,我们加载必要的库,如 Bootstrap,以帮助我们利用现有的前端风格功能。
要做任何有用的事情,我们必须在 HellowWorld.vue 这样的组件中声明变量和函数,如下所示:
ii)声明数据方法(即变量)
data() {
return{
varX: '',
varY: [] }}
iii)声明函数
methods: {
fcnName(){ <Some Code>
}}
iv)单向和双向数据绑定
例如,无论你在哪里看到
v-bind:or shortly :
就是一个单向绑定的例子。这意味着存储在您的数据方法中的变量值将被发送到主应用程序组件。
双向绑定
是通过
v-model
这还使得在应用程序组件(如表单)中输入的变量值能够在数据方法变量中传输和存储。
一旦你对 JavaScript 和 DOM 概念如事件(即发生在 HTML 元素上的事情 ) ,你可以通过利用像这样的优秀教程 one 继续使用 Vue 构建简单的项目。这将使你更容易理解我们将在下一部分做什么。
让我们开始吧!
使用 Vue.js 构建前端
步伐
- 克隆并设置 后端 API (我们已经构建好了)来推荐电影
- 克隆前端存储库
- 测试前端
- 了解应用程序的主要组件
先决条件设置
1。后端 API
为了让前端工作,你需要在你的计算机上本地运行 Flask 后端 API,就像我们在第 2 部分中所做的那样,克隆这个项目。
克隆后端烧瓶 API
a) 克隆回购:
git clone [https://github.com/kuzmicni/movie-rec-engine-backend](https://github.com/kuzmicni/movie-rec-engine-backend)
b) 从的 google drive &下载 movie_similarity.csv 文件,粘贴到克隆回购的根目录下。
您的代码结构应该如下所示:
c) 创建虚拟环境&安装必要的库
conda create --name py37_tut python=3.7
conda activate py37_tut
pip install Flask Flask-Cors pandas
运行应用程序
python application.py
e) 在一个单独的终端中运行测试 API
curl -X POST [http://0.0.0.0:80/recms](http://0.0.0.0:80/recms) -H 'Content-Type: application/json' -d '{"movie_title":"Heat (1995)"}'
应该从 API 获得以下输出:
现在,您可以让这个 API 在后台运行。
接下来,我们将下载已经构建好的整个前端项目,并浏览每个部分。
2。克隆前端回购
克隆 Vue.js 前端回购&确保你已经安装了必要的库
git clone [https://github.com/kuzmicni/movie-rec-engine-frontend](https://github.com/kuzmicni/movie-rec-engine-frontend)cd movie-rec-engine-frontend**#In terminal check that you have node & vue installed** npm --version
vue --version**#In case you don't have node, download it from:** [https://nodejs.org/en/](https://nodejs.org/en/)**#In case you don't have vue, run:**
npm install -g [@vue/cli](http://twitter.com/vue/cli)
现在让我们为这个项目安装必要的库:
jquery,axios,bootstrap & bootstrap-vue
在终端中运行以下命令:
npm install jquery axios bootstrap bootstrap-vue**Check that npm & vue/cli are installed properly**
npm -v
vue --version **Then run the app**
npm run serve
如果一切安装正确,您应该看到:
3。测试前端
然后,您可以在浏览器中打开本地链接并进行测试。如果你输入“Heat (1995)”你应该会得到以下推荐(因为我们的 API 是在http://0 . 0 . 0 . 0:80/recms上后台运行的):
4。了解 app 的主要组件
从下面的片段中可以看出,我们的 Vue 应用程序主要由 SearchAutocomplete 组件组成,用户可以在其中输入他们最喜欢的电影标题。
更具体地说,我们有一个输入框,通过使用 v-model 的双向绑定,将输入的电影标题存储在 "movieTitle" 变量中。当用户在电影中输入时,它将触发 onChange 方法。
您可以看到 onChange 将依次触发 filterResults 方法,该方法将在包含 MovieLens 数据集中所有电影标题的项目属性中搜索相应的电影标题。
一旦用户选择了他们最喜欢的电影标题,我们需要通过“生成推荐”按钮将其发送到我们的 API:
这将触发提交方法,将输入的电影标题发送到后端 API
因此,我们可以解析提供的 API 响应,并将在 rec_movie 中找到的建议存储在一个数组中:
一旦填充了推荐数组,就会触发 > 1 条件,通过下面的代码显示与推荐电影相关的海报:
现在你知道了!这些是这个应用程序的关键成分。请随意使用它,并根据您的喜好进行修改。
遗言
下一步将是对应用程序进行 dockerize,并将其部署在 AWS(或您选择的任何其他云提供商)上,以便其他人可以像使用 mynextmovie.ca 一样使用它。
为了创建 mynextmovie.ca ,我利用了微服务架构,其中后端 API 与前端分开部署。将前端连接到您自己的域名将需要 Route 53 和负载平衡器等服务。也许我们可以在以后的文章中详细讨论这个问题。
参考文献
- https://www.middlewareinventory.com/blog/docker-vuejs/
- https://medium . com/code-heroku/part-2-how-to-turn-your-machine-learning-scripts-into-projects-you-can-demo-467 B3 acff 041
用 50 行代码在 R 中构建一个多类分类神经网络
原文:https://towardsdatascience.com/build-a-multi-class-classification-neural-network-in-r-in-fifty-lines-of-code-88ba161297d3?source=collection_archive---------19-----------------------
人工神经网络
R 语言允许我们快速建立神经网络模型的原型。在这里,我将向您展示如何构建一个神经网络来预测虹膜数据集。
R 语言允许机器学习和神经网络模型的快速原型化。学会使用 Python 创建神经网络后,我发现使用 R 构建神经网络原型既快速又简单。尽管由于 Python 作为编程语言所提供的灵活性和对算法的高级控制,我仍然倾向于使用 Python,但我认为自己在简单快速的项目中使用 R。
在本教程中,我将使用流行的虹膜数据集,通过一个简单的神经网络来预测花卉的种类。我将使用neuralnet
包来创建一个神经网络,使用tidyverse
包来创建一些方便的工具。
我们开始吧
首先,导入tidyverse
和neuralnet
包。
library(tidyverse)
library(neuralnet)
现在,让我们来看看虹膜数据集。默认情况下,这个 iris 数据集在 R 中可用。因此,我们可以通过调用iris
来直接使用它。
print(iris)
当您将数据集打印到控制台时,您将能够看到数据集有四个要素列和一个标注列,并且有 150 行数据。该数据集只包含三种花卉的数据。
虹膜数据集
由于标签列由分类变量组成,我们需要将标签列转换成一个因子。您可以通过使用as_factor
方法来完成此操作。
iris <- iris %>% mutate(Species=as_factor(Species) )
这里,%>%
操作符是由tidyverse
包提供的管道操作符。我们可以使用mutate
方法将“物种”列转换为因子列。
数据预处理
现在,让我们可视化数据集,看看我们是否需要做任何预处理。我将绘制一个箱线图,以查看数据集是否需要缩放,以及是否有任何异常值。为此,让我创建一个绘制箱线图的函数。
draw_boxplot <- function(){
iris %>%
pivot_longer(1:4, names_to="attributes") %>%
ggplot(aes(attributes, value, fill=attributes)) +
geom_boxplot()
}
该方法将特性列转换为行,这样我们将得到一个包含特性列名称及其各自值的列。然后,我们将 name 列作为 x 轴传递,将 value 列作为 y 轴传递给pivot_longerggplot
函数。最后,我们使用geom_boxplot
方法绘制箱线图。然后,调用draw_boxplot
方法绘制一个箱线图。
预处理前绘制的箱线图
我们可以观察到柱子有不同的鳞片和萼片。“宽度”列有异常值。首先,让我们剔除离群值。我将使用squish
方法来删除离群值。这里,请注意,我不会删除无关的数据。相反,我将只把外围的数据行设置为最大值或最小值。
iris <- iris %>%
mutate(across(Sepal.Width, ~squish(.x,
quantile(.x, c(0.05,0.95)))))
这将把我的数据压缩在第 95 个百分点和第 5 个百分点之间。
现在,让我们也使用scale
方法缩放列。R 中的 scale 方法使用 Z 分数归一化来归一化数据。
iris <- iris %>% mutate(across(1:4, scale))
让我们再次可视化数据集,看看是否有任何改进。
预处理后绘制的箱线图
我们可以看到这些列具有相似的比例,并且没有异常值。太好了!
分割数据集
现在我们已经完成了预处理任务,让我们将数据集分成训练数据和测试数据。我们将使用 70%的数据作为训练数据,其余的作为测试数据。
在分割数据集时,我们需要确保随机分配行。所以,让我们首先生成一个随机整数向量。整数的总数应该等于数据集中总行数的 70%。
training_data_rows <- floor(0.70 * nrow(iris)) set.seed(123) training_indices <- sample(c(1:nrow(iris)), training_data_rows)
我们将通过获得总行数的 70%来获得所需的整数个数。因为我们有 150 行,这个值将是 105。因此,我们的训练数据集将由 105 行组成。然后,我们生成一个由 1 到 150 之间的 105 个随机整数组成的向量。
现在,让我们使用training_indices
来分割我们的数据集。
training_data <- iris[training_indices,]
test_data <- iris[-training_indices,]
培养
你现在还在等什么?让我们根据训练数据训练一个神经网络。
为了创建一个神经网络,我将使用neuralnet
包。我将使用默认设置,并将使用两个隐藏层,每个层上有两个神经元。默认情况下,neuralnet
使用逻辑函数作为激活函数。要查看其他默认值是什么,查看它的文档。
nn=neuralnet(Species~Sepal.Length+Sepal.Width+Petal.Length+Petal.Width,
data=training_data,
hidden=c(2,2),
linear.output = FALSE)
这里,第一个参数是指定 y 轴和 x 轴的公式。执行代码开始训练我们的模型。
完成后,我将调用plot(nn)
来绘制网络的架构。
我的神经网络架构
你得到的权重值显然与我的不同,因为权重是随机初始化的。现在,让我们测试我们的神经网络模型。
测试
我将创建一个 predict 函数来获取我们的模型在测试数据和训练数据上的性能。
predict <- function(data){
prediction <-data.frame(neuralnet::compute(nn,
data.frame(data[,-5]))$net.result) labels <- c("setosa", "versicolor", "virginca") prediction_label <- data.frame(max.col(prediction)) %>%
mutate(prediction=labels[max.col.prediction.]) %>%
select(2) %>%
unlist() table(data$Species, prediction_label)
}
我们将数据集作为参数传递,然后使用该方法生成混淆矩阵。要预测物种,可以使用neuralnet
包提供的compute
方法。因为计算方法给出了每个输出神经元的概率,所以我们使用max.col
函数来得到最高的概率。沉淀的物种将是具有最高概率值的物种。
接下来,让我们检查训练数据的性能。
predict(training_data)
训练混淆矩阵
如你所见,准确率是 100%。但是坚持住!这只是训练数据。真正的考验在测试数据上。我们称之为测试数据是有原因的!
predict(test_data)
测试混淆矩阵
一点也不差。这个模型只错了一行。这给了我们 97.7%的准确率。现在,您可以试验超参数,如层数和每层上的神经元数量,看看是否可以获得更好的精度值。
你可以从我的 GitHub repo 获得本教程中使用的完整代码。
原载于 2021 年 6 月 11 日https://www.thearmchaircritic.org/tech-journal/build-a-multi-class-classification-neural-network-in-r-in-fifty-lines-of-code。
使用 Streamlit 构建多层地图
原文:https://towardsdatascience.com/build-a-multi-layer-map-using-streamlit-2b4d44eb28f3?source=collection_archive---------3-----------------------
使用 Plotly 和 Geopandas 增强 Streamlit
作者图片
“一张地图对你说,‘仔细阅读我,紧紧跟随我,不要怀疑我。’它说,“我是你手中的地球。”。没有我,你是孤独的,迷失的。"
― 柏瑞尔·马卡姆,夜色中的西方
说到可视化数据,每个人都喜欢好的地图。我想这是因为地图让我们觉得我们是正在讲述的故事的一部分。它为我们提供了一个可以分享数据的空间,并带来了更丰富、更有力的信息。
令人欣慰的是,随着开源库扩展了 ArcMap 和 QGIS 等传统地理空间软件的应用范围,使用地图变得更加民主化。
此外,Streamlit 和 Dash 等网络应用程序库允许通过网络浏览器轻松显示地图。
然而。。。
虽然这些库非常有用,但是像图层选择这样的操作并不直接;尤其是如果你习惯了传统的地理空间软件。
本教程概述了向 Streamlit 项目添加可选点和面图层的简单过程。以我的经验来看,给用户增加和减少图层的能力会给他们的体验增加很多。
我们的地图将是一个简单的美国地图,主要城市表示为点,500 个美国城市的地图边界表示为多边形。
在我们开始之前,建立一些在本教程中遇到的词汇是有帮助的:
词汇
如果你来自 Plotly/Dash 的世界,这可以翻译成“痕迹”。图层是空间数据集,它们一个接一个地“分层”,从而使地图变得更加复杂
**矢量数据:**点、线或多边形。也称为“非栅格”数据
**点:**具有单一 x,y 坐标的空间特征
**线:**连接至少两个 x,y 坐标的空间特征
**多边形:**由至少三个相连的闭合顶点组成的空间特征
**CRS(坐标参考系统):**一组属性,告诉软件在空间中放置数据的位置,以及使用哪个数学模型将地球展平为 2D 表面。没有 CRS,空间数据就不是空间数据
导入库
import streamlit as st
import json
import geopandas as gpd
import pyproj
import plotly.graph_objs as go
简要说明:如果您正在使用 python 的 Anaconda 安装,我建议您创建一个新环境来导入 GeoPandas。这是一个非常有用的空间库,它有大量特定于版本的依赖项。我建议首先对其进行全新安装,然后将其余的包安装到该环境中。
密码
我们的第一步是读入数据。对于这个项目,我已经上传了点和多边形数据到项目 github 页面,你可以在这里本地下载:https://github.com/wagneaj/mapLayers。
让我们从多边形数据开始:
# reading in the polygon shapefile
polygon = gpd.read_file(r"\Downloads\CityBoundaries.shp")
在这里,我们使用 GeoPandas 来读取我们的第一位数据。这将把我们的数据保存为一个地理数据框架对象,您可以像调用熊猫数据框架对象一样调用和操作它。的’。“shp”文件类型表示 shapefile,它实际上是一组帮助定义数据的空间和表格信息的文件。现在,如果我们愿意,我们可以在 Jupyter 笔记本中查看表格数据:
GeoPandas 数据帧
现在,让我们创建一个新对象,并使用它将特定的坐标参考系统(CRS)应用于我们的数据:
# project GeoPandas dataframe
map_df = polygon
map_df.to_crs(pyproj.CRS.from_epsg(4326), inplace=True)
epsg 4326 '是欧洲石油勘探组织(epsg)的一个编码 CRS。它映射到 WGS 84 CRS。
接下来,我们将对我们的点数据做同样的事情。
# reading in the points shapefile
points = gpd.read_file(r"\Downloads\USA_Major_Cities.shp")# project GeoPandas dataframe
points.to_crs(pyproj.CRS.from_epsg(4326), inplace=True)# define lat, long for points
Lat = points['Lat']
Long = points['Long']
一个关键的区别是额外的步骤,即指定数据集中的哪些列对应于点的纬度和经度。在这种情况下,列分别命名为“Lat”和“Long”。
一旦我们将所有数据读入正确的 CRS,我们需要将多边形数据集转换成 GeoJSON 文件。当我们调用 Plotly 图形对象库时,这个 GeoJSON 将被用作一个参数。
如果您不熟悉,GeoJSON 是一种开放的标准文件格式,专门用于表示空间数据。它基于 JSON 格式,是我们将如何与 Plotly 交流多边形数据的空间参考。
# set GeoJSON file path
path = r"C:\Users\project\geojson.json"# write GeoJSON to file
map_df.to_file(path, driver = "GeoJSON")
with open(path) as geofile:
j_file = json.load(geofile)# index geojson
i=1
for feature in j_file["features"]:
feature ['id'] = str(i).zfill(2)
i += 1
这里,我们设置了导出 GeoJSON 的路径;我们已经将文件回调到我们的分析中;然后我们给文件的每个记录编了索引。
在我们创建并索引 GeoJSON 之后,在我们把所有东西放在一起之前还有一个步骤,那就是生成一个 mapbox 令牌。
Mapbox 提供了在线地图,可以使用 mapbox 令牌通过 API 访问这些地图。我已经生成了自己的令牌,但这是一个相当无痛的过程,可以在这里找到说明:【https://docs.mapbox.com/help/glossary/access-token
随着地图框令牌的生成,我们现在可以开始把我们的地图层放在一起。
# mapbox token
mapboxt = 'MapBox Token'
# define layers and plot map
choro = go.Choroplethmapbox(z=map_df['STFIPS'], locations =
map_df.index, colorscale = 'Viridis', geojson = j_file,
text = map_df['NAME'], marker_line_width=0.1) scatt = go.Scattermapbox(lat=Lat, lon=Long,mode='markers+text',
below='False', marker=dict( size=12, color ='rgb(56, 44,
100)'))layout = go.Layout(title_text ='USA Cities', title_x =0.5,
width=950, height=700,mapbox = dict(center= dict(lat=37,
lon=-95),accesstoken= mapboxt, zoom=4,style="stamen-
terrain"))
在这里,我们已经定义了我们的 choropleth 地图层,我们的散点图地图层,我们的布局都使用 Plotly 图形对象。图形对象是类似字典的结构,可以用来方便地存储和调用不同的图形。
最后,我们为图层选择创建了一个 Streamlit multiselect 小部件;我们给我们的图形对象分配图形;我们调用 Streamlit 来显示最终的地图。
# streamlit multiselect widget
layer1 = st.multiselect('Layer Selection', [choro, scatt],
format_func=lambda x: 'Polygon' if x==choro else 'Points')# assign Graph Objects figure
fig = go.Figure(data=layer1, layout=layout)# display streamlit map
st.plotly_chart(fig)
就是这样!现在,您已经有了向多层 web 地图添加和减去图层的结构。成品截图如下。
初始图层选择
多边形图层选择
多边形和点图层选择
进一步探索
- 对 Streamlit 的精彩介绍:
- 如果你更喜欢 Dash for web apps:
https://plotly.com/python/maps/
- 是什么让空间数据变得特殊 l:
https://escholarship.org/uc/item/3ph5k0d4
使用 Vespa 从 python 构建新闻推荐应用程序
原文:https://towardsdatascience.com/build-a-news-recommendation-app-from-python-with-vespa-6aa37450eb32?source=collection_archive---------50-----------------------
第 3 部分—通过亲子关系有效利用点击率
这部分系列引入了一个新的排名信号:类别点击率(CTR)。这个想法是,我们可以为没有点击历史的用户推荐受欢迎的内容。我们不是仅仅根据文章进行推荐,而是根据类别进行推荐。然而,这些全局 CTR 值经常会不断变化,因此我们需要一种有效的方法来为所有文档更新这个值。我们将通过在 Vespa 中引入文档之间的父子关系来做到这一点。我们也会在排名中直接使用稀疏张量。这篇文章复制了这篇更详细的 Vespa 教程。
由 Unsplash 上的absolute vision拍摄的照片
我们假设您已经阅读了新闻推荐教程的第 2 部分。因此,您应该有一个保存新闻应用程序定义的app_package
变量和一个名为news
的 Docker 容器来运行应用程序,该应用程序从 MIND 数据集的演示版本获取数据。
设置全球类别 CTR 文档
如果我们在news
文档中添加一个category_ctr
字段,那么每当这项运动的 CTR 统计数据发生变化时,我们就必须更新这项运动的所有文档。如果我们假设类别 CTR 会经常改变,这被证明是低效的。
针对这些情况,Vespa 引入了亲子关系。父文档是全局文档,会自动分发到所有内容节点。其他文档可以引用这些父项并“导入”值以用于排名。好处是全局类别 CTR 值只需要写入一个地方:全局文档。
我们通过创建一个新的category_ctr
模式并设置global_document=True
来表示我们希望 Vespa 在所有内容节点上保留这些文档的副本,从而实现了这一点。在父子关系中使用文档时,需要将文档设置为全局文档。注意,我们使用一个具有单一稀疏维度的张量来保存ctrs
数据。
稀疏张量将字符串作为维度地址,而不是数字索引。更具体地说,这种张量的一个例子是(使用张量文字形式):
{
{category: entertainment}: 0.2 },
{category: news}: 0.3 },
{category: sports}: 0.5 },
{category: travel}: 0.4 },
{category: finance}: 0.1 },
...
}
这个张量包含所有类别的 CTR 分数。在更新这个张量的时候,我们可以更新单个的细胞,不需要更新整个张量。这个操作叫做张量修改,当你有大的张量时会很有帮助。
在子文档中导入父值
我们需要设置两个东西来使用category_ctr
张量对news
文档进行排序。我们需要引用父文档(本例中为category_ctr
),并从引用的父文档中导入ctrs
。
字段category_ctr_ref
是category_ctr
单据类型的类型引用字段。当输入这个字段时,Vespa 需要完全合格的文档 id。例如,如果我们的全局 CTR 文档有 id id:category_ctr:category_ctr::global
,那就是我们需要提供给category_ctr_ref
字段的值。一个文档可以引用许多父文档。
导入的字段定义了我们应该从category_ctr_ref
字段中引用的文档中导入ctrs
字段。我们将其命名为global_category_ctrs
,我们可以在排序时将其引用为attribute(global_category_ctrs)
。
排序中的张量表达式
每个news
文档都有一个类型为string
的category
字段,指示该文档属于哪个类别。我们希望使用这些信息来选择存储在global_category_ctrs
中的正确 CTR 分数。不幸的是,张量表达式只对张量起作用,所以我们需要添加一个名为category_tensor
的tensor
类型的新字段,以在张量表达式中使用的方式保存类别信息:
使用上面定义的category_tensor
字段,我们可以使用张量表达式sum(attribute(category_tensor) * attribute(global_category_ctrs))
来选择与被排序的文档类别相关的特定 CTR。我们在下面的等级配置文件中将该表达式实现为Function
:
在新的 rank-profile 中,我们添加了第一阶段排名表达式,该表达式将最近邻得分与类别 CTR 得分相乘,分别用函数nearest_neighbor
和category_ctr
实现。作为第一次尝试,我们将最近邻与类别 CTR 分数相乘,这可能不是组合这两个值的最佳方式。
部署
我们可以重用在本教程第一部分中创建的同一个名为news
的容器。
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for application status.
Waiting for application status.
Finished deployment.
饲料
接下来,我们将下载全局类别 CTR 数据,该数据已经以具有类别维度的稀疏张量所期望的格式进行了解析。
{'ctrs': {'cells': [{'address': {'category': 'entertainment'},
'value': 0.029266420380943244},
{'address': {'category': 'autos'}, 'value': 0.028475809103747123},
{'address': {'category': 'tv'}, 'value': 0.05374837981352176},
{'address': {'category': 'health'}, 'value': 0.03531784305129329},
{'address': {'category': 'sports'}, 'value': 0.05611187986670051},
{'address': {'category': 'music'}, 'value': 0.05471192953054426},
{'address': {'category': 'news'}, 'value': 0.04420778372641991},
{'address': {'category': 'foodanddrink'}, 'value': 0.029256852366228187},
{'address': {'category': 'travel'}, 'value': 0.025144552013730358},
{'address': {'category': 'finance'}, 'value': 0.03231013195899643},
{'address': {'category': 'lifestyle'}, 'value': 0.04423279317474416},
{'address': {'category': 'video'}, 'value': 0.04006693315980292},
{'address': {'category': 'movies'}, 'value': 0.03335647459420146},
{'address': {'category': 'weather'}, 'value': 0.04532171803495617},
{'address': {'category': 'northamerica'}, 'value': 0.0},
{'address': {'category': 'kids'}, 'value': 0.043478260869565216}]}}
我们可以将该数据点输入到category_ctr
中定义的文档中。我们将为该文档分配global
id。可以通过使用 Vespa id id:category_ctr:category_ctr::global
来参考本文档。
我们需要对news
文档执行部分更新,以包含关于引用字段category_ctr_ref
和新category_tensor
的信息,该字段将具有与每个文档相关联的特定类别的值1.0
。
{'id': 'N3112',
'fields': {'category_ctr_ref': 'id:category_ctr:category_ctr::global',
'category_tensor': {'cells': [{'address': {'category': 'lifestyle'},
'value': 1.0}]}}}
测试新的等级档案
我们将重新定义本教程第二部分中定义的query_user_embedding
函数,并使用它进行一个涉及用户U33527
和recommendation_with_global_category_ctr
等级档案的查询。
下面第一个命中的是一篇体育文章。这里还列出了全球 CTR 文档,体育类的 CTR 得分为0.0561
。因此,category_ctr 函数的结果是预期的0.0561
。nearest _ neighborhood 分数是0.149
,得到的相关性分数是0.00836
。所以,这和预期的一样有效。
{'id': 'id:news:news::N5316',
'relevance': 0.008369192847921151,
'source': 'news_content',
'fields': {'sddocname': 'news',
'documentid': 'id:news:news::N5316',
'news_id': 'N5316',
'category': 'sports',
'subcategory': 'football_nfl',
'title': "Matthew Stafford's status vs. Bears uncertain, Sam Martin will play",
'abstract': "Stafford's start streak could be in jeopardy, according to Ian Rapoport.",
'url': "https://www.msn.com/en-us/sports/football_nfl/matthew-stafford's-status-vs.-bears-uncertain,-sam-martin-will-play/ar-BBWwcVN?ocid=chopendata",
'date': 20191112,
'clicks': 0,
'impressions': 1,
'summaryfeatures': {'attribute(category_tensor)': {'type': 'tensor<float>(category{})',
'cells': [{'address': {'category': 'sports'}, 'value': 1.0}]},
'attribute(global_category_ctrs)': {'type': 'tensor<float>(category{})',
'cells': [{'address': {'category': 'entertainment'},
'value': 0.029266420751810074},
{'address': {'category': 'autos'}, 'value': 0.0284758098423481},
{'address': {'category': 'tv'}, 'value': 0.05374838039278984},
{'address': {'category': 'health'}, 'value': 0.03531784191727638},
{'address': {'category': 'sports'}, 'value': 0.05611187964677811},
{'address': {'category': 'music'}, 'value': 0.05471193045377731},
{'address': {'category': 'news'}, 'value': 0.04420778527855873},
{'address': {'category': 'foodanddrink'}, 'value': 0.029256852343678474},
{'address': {'category': 'travel'}, 'value': 0.025144552811980247},
{'address': {'category': 'finance'}, 'value': 0.032310131937265396},
{'address': {'category': 'lifestyle'}, 'value': 0.044232793152332306},
{'address': {'category': 'video'}, 'value': 0.040066931396722794},
{'address': {'category': 'movies'}, 'value': 0.033356472849845886},
{'address': {'category': 'weather'}, 'value': 0.045321717858314514},
{'address': {'category': 'northamerica'}, 'value': 0.0},
{'address': {'category': 'kids'}, 'value': 0.043478261679410934}]},
'rankingExpression(category_ctr)': 0.05611187964677811,
'rankingExpression(nearest_neighbor)': 0.14915188666574342,
'vespa.summaryFeatures.cached': 0.0}}}
结论
本教程介绍了父子关系,并通过我们在排名中使用的全局 CTR 特性进行了演示。我们还引入了使用(稀疏)张量表达式的排序。
使用 Vespa 从 python 构建新闻推荐应用程序
原文:https://towardsdatascience.com/build-a-news-recommendation-app-from-python-with-vespa-7c5b3ce079be?source=collection_archive---------26-----------------------
第 1 部分—新闻搜索功能
我们将在 Vespa 中构建一个新闻推荐应用程序,而不会离开 python 环境。在本系列的第一部分中,我们希望开发一个具有基本搜索功能的应用程序。未来的帖子将增加基于嵌入和其他 ML 模型的推荐功能。
照片由菲利普·米舍夫斯基在 Unsplash 上拍摄
这个系列是 Vespa 的新闻搜索推荐教程的简化版。我们还将使用微软新闻数据集(MIND) 的演示版本,这样任何人都可以在他们的笔记本电脑上跟随。
资料组
最初的 Vespa 新闻搜索教程提供了一个脚本来下载、解析和转换 MIND 数据集为 Vespa 格式。为了方便您,我们提供了本教程所需的最终解析数据供下载:
{'abstract': "Shop the notebooks, jackets, and more that the royals can't live without.",
'title': 'The Brands Queen Elizabeth, Prince Charles, and Prince Philip Swear By',
'subcategory': 'lifestyleroyals',
'news_id': 'N3112',
'category': 'lifestyle',
'url': 'https://www.msn.com/en-us/lifestyle/lifestyleroyals/the-brands-queen-elizabeth,-prince-charles,-and-prince-philip-swear-by/ss-AAGH0ET?ocid=chopendata',
'date': 20191103,
'clicks': 0,
'impressions': 0}
这里使用的最终解析数据是一个列表,其中每个元素都是一个字典,包含一篇新闻文章的相关字段,比如title
和category
。我们也有文章收到的impressions
和clicks
的数量信息。mind 数据集的演示版包含了 28.603 篇新闻文章。
28603
安装 pyvespa
创建搜索应用程序
创建应用程序包。app_package
将保存与您的应用规范相关的所有相关数据。
向架构中添加字段。下面是对下面使用的非显而易见的参数的简短描述:
- 索引参数:为字段配置索引管道,它定义了 Vespa 在索引期间如何处理输入。
- “索引”:为此字段创建搜索索引。
- “summary”:让该字段成为结果集中文档摘要的一部分。
- “属性”:将该字段作为属性存储在内存中——用于排序、查询和分组。
- 索引参数:配置Vespa 应该如何创建搜索索引。
- “enable-bm25”:设置一个兼容 bm25 排名的索引进行文本搜索。
- 属性参数:配置Vespa 应该如何对待一个属性字段。
- “快速搜索”:为属性字段建立索引。默认情况下,不会为属性生成索引,搜索这些属性默认为线性扫描。
向架构中添加字段集。字段集允许我们轻松地搜索多个字段。在这种情况下,搜索default
字段集等同于搜索title
和abstract
。
我们有足够的资源来部署应用程序的第一个版本。在本教程的后面,我们将把一篇文章的受欢迎程度包括在相关性分数中,用于对匹配我们查询的新闻进行排名。
在 Docker 上部署应用程序
如果您的机器上安装了 Docker,您可以在本地 Docker 容器中部署app_package
:
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for application status.
Waiting for application status.
Finished deployment.
vespa_docker
将解析app_package
并将所有必要的 Vespa 配置文件写入disk_folder
。然后它将创建 docker 容器,并使用 Vespa 配置文件来部署 Vespa 应用程序。然后,我们可以使用app
实例与部署的应用程序进行交互,比如用于提要和查询。如果你想知道更多幕后发生的事情,我们建议你浏览Docker 入门教程。
向应用程序提供数据
我们可以使用feed_data_point
方法。我们需要具体说明:
data_id
:识别数据点的唯一 idfields
:字典中的键与我们的应用程序包模式中定义的字段名相匹配。schema
:我们要向其馈送数据的模式的名称。当我们创建应用程序包时,我们默认创建了一个与应用程序名同名的模式,在我们的例子中是news
。
查询应用程序
我们可以使用 Vespa 查询 API 到app.query
来释放 Vespa 所能提供的全部查询灵活性。
使用关键字搜索索引字段
从文档中选择default
(标题或摘要)包含关键字“音乐”的所有字段。
{'id': 'index:news_content/0/5f1b30d14d4a15050dae9f7f',
'relevance': 0.25641557752127125,
'source': 'news_content'}
选择title
和abstract
,其中title
包含‘音乐’,default
包含‘节日’。
{'id': 'index:news_content/0/988f76793a855e48b16dc5d3',
'relevance': 0.19587240022210403,
'source': 'news_content',
'fields': {'title': "At Least 3 Injured In Stampede At Travis Scott's Astroworld Music Festival",
'abstract': "A stampede Saturday outside rapper Travis Scott's Astroworld musical festival in Houston, left three people injured. Minutes before the gates were scheduled to open at noon, fans began climbing over metal barricades and surged toward the entrance, according to local news reports."}}
按文档类型搜索
选择文档类型等于news
的所有文档的标题。我们的应用程序只有一种文档类型,所以下面的查询检索我们所有的文档。
{'id': 'index:news_content/0/698f73a87a936f1c773f2161',
'relevance': 0.0,
'source': 'news_content',
'fields': {'title': 'The Brands Queen Elizabeth, Prince Charles, and Prince Philip Swear By'}}
搜索属性字段,如日期
因为date
没有用attribute=["fast-search"]
指定,所以没有为它建立索引。因此,搜索它相当于对字段的值进行线性扫描。
{'id': 'index:news_content/0/debbdfe653c6d11f71cc2353',
'relevance': 0.0017429193899782135,
'source': 'news_content',
'fields': {'title': 'These Cranberry Sauce Recipes Are Perfect for Thanksgiving Dinner',
'date': 20191110}}
由于default
字段集是由索引字段组成的,Vespa 将首先过滤所有在title
或abstract
中包含关键字“天气”的文档,然后在date
字段中扫描“20191110”。
{'id': 'index:news_content/0/bb88325ae94d888c46538d0b',
'relevance': 0.27025156546141466,
'source': 'news_content',
'fields': {'title': 'Weather forecast in St. Louis',
'abstract': "What's the weather today? What's the weather for the week? Here's your forecast.",
'date': 20191110}}
我们还可以执行范围搜索:
{'id': 'index:news_content/0/c41a873213fdcffbb74987c0',
'relevance': 0.0017429193899782135,
'source': 'news_content',
'fields': {'date': 20191109}}
整理
默认情况下,Vespa 会按相关性分数降序对点击进行排序。相关性分数是由 nativeRank 给出的,除非另有说明,我们将在本文后面做些说明。
[{'id': 'index:news_content/0/5f1b30d14d4a15050dae9f7f',
'relevance': 0.25641557752127125,
'source': 'news_content',
'fields': {'title': 'Music is hot in Nashville this week',
'date': 20191101}},
{'id': 'index:news_content/0/6a031d5eff95264c54daf56d',
'relevance': 0.23351089409559303,
'source': 'news_content',
'fields': {'title': 'Apple Music Replay highlights your favorite tunes of the year',
'date': 20191105}}]
然而,我们可以使用关键字order
通过给定的字段显式排序。
[{'id': 'index:news_content/0/d0d7e1c080f0faf5989046d8',
'relevance': 0.0,
'source': 'news_content',
'fields': {'title': "Elton John's second farewell tour stop in Cleveland shows why he's still standing after all these years",
'date': 20191031}},
{'id': 'index:news_content/0/abf7f6f46ff2a96862075155',
'relevance': 0.0,
'source': 'news_content',
'fields': {'title': 'The best hair metal bands', 'date': 20191101}}]
order
默认按升序排序,我们可以用desc
关键字覆盖:
[{'id': 'index:news_content/0/934a8d976ff8694772009362',
'relevance': 0.0,
'source': 'news_content',
'fields': {'title': 'Korg Minilogue XD update adds key triggers for synth sequences',
'date': 20191113}},
{'id': 'index:news_content/0/4feca287fdfa1d027f61e7bf',
'relevance': 0.0,
'source': 'news_content',
'fields': {'title': 'Tom Draper, Black Music Industry Pioneer, Dies at 79',
'date': 20191113}}]
分组
我们可以使用 Vespa 的分组功能来计算文档数量最多的三个新闻类别:
- 有 9115 篇文章的新闻
- 体育 6765 篇
- 金融 1886 篇
{'id': 'group:root:0',
'relevance': 1.0,
'continuation': {'this': ''},
'children': [{'id': 'grouplist:category',
'relevance': 1.0,
'label': 'category',
'continuation': {'next': 'BGAAABEBGBC'},
'children': [{'id': 'group:string:news',
'relevance': 1.0,
'value': 'news',
'fields': {'count()': 9115}},
{'id': 'group:string:sports',
'relevance': 0.6666666666666666,
'value': 'sports',
'fields': {'count()': 6765}},
{'id': 'group:string:finance',
'relevance': 0.3333333333333333,
'value': 'finance',
'fields': {'count()': 1886}}]}]}
使用新闻流行度信号进行排名
默认情况下,Vespa 使用 nativeRank 来计算相关性分数。我们将创建一个新的等级简档,它在我们的相关性分数计算中包括一个流行度信号。
我们新的等级档案将被命名为popularity
。以下是对上述内容的细分:
- inherits="default "
这会将 Vespa 配置为创建一个名为 popularity 的新等级配置文件,它继承了所有默认的等级配置文件属性;只有显式定义或覆盖的属性才会与默认等级配置文件的属性不同。
- 功能流行度
这就建立了一个可以从其他表达式中调用的函数。该函数计算点击数除以印象数,以表示受欢迎程度。然而,这并不是最好的计算方法,因为即使不确定性很高,一篇印象数少的文章也可以在这个值上得分很高。但这是一个开始:)
- 第一期的
Vespa 中的相关性计算分为两个阶段。第一阶段中完成的计算是对匹配查询的每个文档执行的。相比之下,第二阶段的计算仅在由第一阶段中完成的计算所确定的前 n 个文档上完成。我们现在只使用第一阶段。
- 表达式:nativeRank + 10 *人气
该表达式用于对文档进行排序。在这里,默认的排名表达式—默认字段集的 nativeRank 被包含进来以使查询相关,而第二个术语调用 popularity 函数。这两个术语的加权和是每个文档的最终相关性。注意,这里的权重 10 是通过观察设定的。更好的方法是使用机器学习来学习这些值,我们将在未来的帖子中回到这个话题。
重新部署应用程序
因为我们已经更改了应用程序包,所以我们需要重新部署我们的应用程序:
Waiting for configuration server.
Waiting for application status.
Waiting for application status.
Finished deployment.
使用新的流行度信号进行查询
当重新部署完成时,我们可以通过使用ranking
参数来对匹配的文档进行排序。
{'id': 'id:news:news::N5870',
'relevance': 5.156596018746151,
'source': 'news_content',
'fields': {'sddocname': 'news',
'documentid': 'id:news:news::N5870',
'news_id': 'N5870',
'category': 'music',
'subcategory': 'musicnews',
'title': 'Country music group Alabama reschedules their Indy show until next October 2020',
'abstract': 'INDIANAPOLIS, Ind. Fans of the highly acclaimed country music group Alabama, scheduled to play Bankers Life Fieldhouse Saturday night, will have to wait until next year to see the group. The group famous for such notable songs like "If You\'re Gonna Play in Texas", "Love In The First Degree", and "She and I", made the announcement that their 50th Anniversary Tour is being rescheduled till ...',
'url': 'https://www.msn.com/en-us/music/musicnews/country-music-group-alabama-reschedules-their-indy-show-until-next-october-2020/ar-BBWB0d7?ocid=chopendata',
'date': 20191108,
'clicks': 1,
'impressions': 2}}
结论和未来工作
这篇文章提供了使用 Vespa 从 python 构建新闻搜索应用程序的一步一步的方法。我们还展示了如何部署、馈送和查询应用程序,重点介绍了排序和分组等查询功能。未来的帖子将添加用户信息,以展示我们如何将这个搜索应用程序变成由 ML 模型支持的推荐应用程序。
使用 Vespa 从 Python 构建新闻推荐应用程序
原文:https://towardsdatascience.com/build-a-news-recommendation-app-from-python-with-vespa-f59c0a08c9a3?source=collection_archive---------30-----------------------
第 2 部分—从新闻搜索到嵌入的新闻推荐
在这一部分中,我们将开始使用本教程中创建的嵌入,将我们的应用程序从新闻搜索转换为新闻推荐。嵌入向量将代表每个用户和新闻文章。我们将提供用于下载的嵌入,以便更容易理解这篇文章。当用户来时,我们检索他的嵌入,并通过近似最近邻(ANN)搜索使用它来检索最近的新闻文章。我们还表明,Vespa 可以联合应用一般过滤和人工神经网络搜索,而不像市场上的竞争对手。
马特·波波维奇在 Unsplash 上拍摄的照片
我们假设你已经阅读了新闻搜索教程。因此,您应该有一个保存新闻搜索应用程序定义的app_package
变量和一个名为news
的 Docker 容器来运行一个搜索应用程序,该应用程序从 MIND 数据集的演示版本中获取新闻文章。
添加用户模式
我们需要添加另一种文档类型来表示用户。我们设置模式来搜索一个user_id
,并检索用户的嵌入向量。
我们通过指定fast-search
属性为属性字段user_id
构建一个索引。请记住,属性字段保存在内存中,默认情况下不进行索引。
嵌入场是张量场。Vespa 中的张量是灵活的多维数据结构,作为一等公民,可用于查询、文档字段和排名中的常数。张量可以是稠密的,也可以是稀疏的,或者两者兼有,并且可以包含任意数量的维度。更多信息请参见张量用户指南。这里我们定义了一个单维的稠密张量(d0
-维 0),代表一个向量。51 是本文中使用的嵌入大小。
我们现在有一个用于news
的模式和一个用于user
的模式。
['news', 'user']
索引新闻嵌入
类似于用户模式,我们将使用密集张量来表示新闻嵌入。但与用户嵌入字段不同,我们将通过在indexing
参数中包含index
来索引新闻嵌入,并指定我们希望使用 HNSW(分层可导航小世界)算法来构建索引。使用的距离度量是欧几里德。阅读这篇博文了解更多关于 Vespa 实现 ANN 搜索的历程。
使用嵌入的推荐
在这里,我们添加了一个使用紧密度排名特性的排名表达式,它计算欧几里德距离并使用它来对新闻文章进行排名。这个等级配置文件依赖于使用最近邻搜索操作符,我们将在搜索时回到下面。但是现在,这需要查询中的一个张量作为初始搜索点。
查询配置文件类型
上面的推荐等级配置文件要求我们随查询一起发送一个张量。为了让 Vespa 绑定正确的类型,它需要知道这个查询参数的预期类型。
当查询参数 ranking . features . query(user _ embedding)被传递时,该查询配置文件类型指示 Vespa 预期一个维数为d0[51]
的浮点张量。我们将在下面看到它是如何与最近邻搜索操作符一起工作的。
重新部署应用程序
我们做了所有必要的改变,将我们的新闻搜索应用变成了新闻推荐应用。我们现在可以将app_package
重新部署到名为news
的运行容器中。
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Finished deployment.
["Uploading application '/app/application' using http://localhost:19071/application/v2/tenant/default/session",
"Session 7 for tenant 'default' created.",
'Preparing session 7 using http://localhost:19071/application/v2/tenant/default/session/7/prepared',
"WARNING: Host named 'news' may not receive any config since it is not a canonical hostname. Disregard this warning when testing in a Docker container.",
"Session 7 for tenant 'default' prepared.",
'Activating session 7 using http://localhost:19071/application/v2/tenant/default/session/7/active',
"Session 7 for tenant 'default' activated.",
'Checksum: 62d964000c4ff4a5280b342cd8d95c80',
'Timestamp: 1616671116728',
'Generation: 7',
'']
喂养和部分更新:新闻和用户嵌入
为了让本教程易于理解,我们提供了已解析的嵌入供下载。要自己构建它们,请遵循本教程。
我们刚刚创建了user
模式,所以我们需要第一次输入用户数据。
对于新闻文档,我们只需要更新添加到news
模式中的embedding
字段。
获取用户嵌入
接下来,我们创建一个query_user_embedding
函数,通过user_id
检索用户embedding
。当然,您可以使用 Vespa 搜索器更有效地做到这一点,如这里描述的,但是在这一点上保持 python 中的所有内容会使学习更容易。
该函数将查询 Vespa,检索嵌入内容,并将其解析为一个浮点列表。下面是用户U63195
嵌入的前五个元素。
[0.0,
-0.1694680005311966,
-0.0703359991312027,
-0.03539799898862839,
0.14579899609088898]
获取推荐
人工神经网络搜索
下面的yql
指示 Vespa 从最接近用户嵌入的十个新闻文档中选择title
和category
。
我们还指定,我们希望通过我们之前定义的recommendation
rank-profile 对这些文档进行排序,并通过我们在app_package
中定义的查询配置文件类型ranking.features.query(user_embedding)
向用户发送嵌入。
这是十个回复中的前两个。
[{'id': 'index:news_content/0/aca03f4ba2274dd95b58db9a',
'relevance': 0.1460561756063909,
'source': 'news_content',
'fields': {'category': 'music',
'title': 'Broadway Star Laurel Griggs Suffered Asthma Attack Before She Died at Age 13'}},
{'id': 'index:news_content/0/bd02238644c604f3a2d53364',
'relevance': 0.14591827245062294,
'source': 'news_content',
'fields': {'category': 'tv',
'title': "Rip Taylor's Cause of Death Revealed, Memorial Service Scheduled for Later This Month"}}]
将人工神经网络搜索与查询过滤器相结合
Vespa ANN 搜索完全集成到 Vespa 查询树中。这种集成意味着我们可以包含查询过滤器,人工神经网络搜索将只应用于满足过滤器的文档。无需进行涉及过滤器的预处理或后处理。
以下yql
搜索以sports
为类别的新闻文档。
这是十个回复中的前两个。注意category
字段。
[{'id': 'index:news_content/0/375ea340c21b3138fae1a05c',
'relevance': 0.14417346200569972,
'source': 'news_content',
'fields': {'category': 'sports',
'title': 'Charles Rogers, former Michigan State football, Detroit Lions star, dead at 38'}},
{'id': 'index:news_content/0/2b892989020ddf7796dae435',
'relevance': 0.14404365847394848,
'source': 'news_content',
'fields': {'category': 'sports',
'title': "'Monday Night Football' commentator under fire after belittling criticism of 49ers kicker for missed field goal"}}]
结论和未来工作
我们通过在 Vespa 中存储用户资料,将我们的新闻搜索应用程序转变为新闻推荐应用程序。在这种情况下,用户简档被选择为由基于关于用户浏览历史的数据训练的 ML 模型生成的嵌入。然后,我们使用这些用户资料,根据近似最近邻搜索推荐新闻文章。未来的工作将集中在评估新闻推荐应用程序获得的结果是否符合用于生成嵌入的 ML 模型的预期。
使用机器学习构建抄袭检查器
原文:https://towardsdatascience.com/build-a-plagiarism-checker-using-machine-learning-6538110ce162?source=collection_archive---------9-----------------------
Python、Flask、NLP、相似性搜索等等
克里斯多夫·伯恩斯在 Unsplash 上拍摄的照片
网络上、课堂上抄袭现象猖獗。有这么多的内容,有时很难知道什么时候被剽窃了。撰写博客文章的作者可能想要检查是否有人窃取了他们的作品并将其发布到其他地方。老师们可能想对照其他学术文章检查学生的论文是否抄袭。新闻媒体可能想要检查内容农场是否窃取了他们的新闻文章并声称内容是自己的。
那么,我们如何防范抄袭呢?如果我们能让软件为我们做这些繁重的工作,那不是很好吗?使用机器学习,我们可以构建自己的剽窃检查器,在庞大的数据库中搜索被盗内容。在本文中,我们将做到这一点。
我们将构建一个 Python Flask 应用程序,它使用松果——一个相似性搜索服务——来查找可能抄袭的内容。
演示应用概述
让我们来看看我们今天要构建的演示应用程序。下面,你可以看到一个应用程序运行的简短动画。
UI 提供了一个简单的 textarea 输入,用户可以在其中粘贴文章中的文本。当用户点击提交按钮时,该输入用于查询文章数据库。然后向用户显示结果及其匹配分数。为了帮助减少噪音,该应用程序还包括一个滑块输入,用户可以在其中指定一个相似性阈值,以便只显示非常强的匹配。
演示应用——剽窃检查器
正如你所看到的,当原始内容被用作搜索输入时,可能抄袭的文章的匹配分数相对较低。然而,如果我们从数据库中的一篇文章中复制并粘贴文本,抄袭文章的结果会有 99.99%的匹配!
那么,我们是怎么做到的呢?
在构建应用程序时,我们从 Kaggle 的新闻文章数据集开始。该数据集包含来自 15 个主要出版物的 143,000 篇新闻文章,但我们只使用了前 20,000 篇。(这个数据库的完整数据集包含超过 200 万篇文章!)
接下来,我们通过重命名几列并删除一些不必要的列来清理数据集。然后,我们通过嵌入模型运行文章,以创建向量嵌入——这是机器学习算法的元数据,用于确定各种输入之间的相似性。我们使用平均单词嵌入模型。最后,我们将这些矢量嵌入插入到由松果管理的矢量数据库中。
将矢量嵌入添加到数据库并建立索引后,我们就可以开始寻找相似的内容了。当用户提交他们的文章文本作为输入时,会向一个 API 端点发出请求,该端点使用 Pinecone 的 SDK 来查询矢量嵌入的索引。端点返回 10 篇可能抄袭的类似文章,并在应用程序的 UI 中显示出来。就是这样!很简单,对吧?
如果你想自己尝试一下,你可以在 GitHub 上找到这个应用的代码。README
包含如何在您自己的机器上本地运行应用程序的说明。
演示应用程序代码演练
我们已经了解了应用程序的内部工作原理,但是我们实际上是如何构建它的呢?如前所述,这是一个利用松果 SDK 的 Python Flask 应用程序。HTML 使用模板文件,前端的其余部分使用静态 CSS 和 JS 资产构建。为了简单起见,所有的后端代码都在app.py
文件中,我们在下面完整地复制了它:
让我们检查一下app.py
文件的重要部分,以便理解它。
在第 1–14 行,我们导入了应用程序的依赖项。我们的应用依赖于以下内容:
dotenv
用于从.env
文件中读取环境变量flask
用于网络应用程序设置json
用于使用 JSONos
也用于获取环境变量pandas
用于处理数据集pinecone
使用松果 SDKre
用于处理正则表达式(RegEx)requests
请求 API 下载我们的数据集statistics
获取一些方便的统计方法sentence_transformers
对于我们的嵌入模型swifter
用于处理熊猫数据框
在第 16 行,我们提供了一些样板代码来告诉 Flask 我们的应用程序的名称。
在第 18–20 行,我们定义了一些将在应用程序中使用的常量。其中包括松果索引的名称、数据集的文件名以及从 CSV 文件中读取的行数。
在第 22–25 行,我们的initialize_pinecone
方法从.env
文件中获取我们的 API 密匙,并用它来初始化松果。
在第 27–29 行,我们的delete_existing_pinecone_index
方法在松果实例中搜索与我们正在使用的名称相同的索引(“剽窃检查器”)。如果找到一个现有的索引,我们就删除它。
在第 31–35 行,我们的create_pinecone_index
方法使用我们选择的名称(“剽窃检查器”)、“余弦”邻近度度量和一个碎片创建了一个新的索引。
在第 37–40 行,我们的create_model
方法使用sentence_transformers
库来处理平均单词嵌入模型。稍后我们将使用这个模型对矢量嵌入进行编码。
在第 62–68 行,我们的process_file
方法读取 CSV 文件,然后对其调用prepare_data
和upload_items
方法。接下来描述这两种方法。
在第 42–56 行,我们的prepare_data
方法通过重命名第一个“id”列并删除“date”列来调整数据集。然后,它将文章标题和文章内容组合成一个字段。我们将在创建矢量嵌入时使用这个组合字段。
在第 58–60 行,我们的upload_items
方法通过使用我们的模型对文章进行编码,为每篇文章创建一个矢量嵌入。然后,我们将矢量嵌入插入到松果索引中。
在第 70–74 行,我们的map_titles
和map_publications
方法创建了一些标题和出版物名称的字典,以便以后更容易通过它们的 id 找到文章。
到目前为止,当后端应用程序启动时,我们描述的每个方法都在第 95–101 行被调用。这项工作为我们基于用户输入实际查询松果索引的最后一步做准备。
在第 103–113 行,我们为我们的应用程序定义了两条路径:一条到主页,一条到 API 端点。主页提供了index.html
模板文件以及 JS 和 CSS 资产,API 端点提供了查询松果索引的搜索功能。
最后,在第 76–93 行,我们的query_pinecone
方法获取用户的文章内容输入,将其转换为矢量嵌入,然后查询松果索引来查找相似的文章。当点击/api/search
端点时调用该方法,这发生在用户提交新的搜索查询的任何时候。
对于视觉学习者来说,这里有一个图表概述了该应用程序的工作原理:
应用架构和用户体验
示例场景
那么,把这些放在一起,用户体验是什么样的呢?让我们来看三个场景:原创内容、抄袭内容的精确副本和“补丁编写”的内容。
当提交原创内容时,应用程序会回复一些可能相关的文章,但匹配度很低。这是一个好迹象,因为内容没有抄袭,所以我们会期待低匹配分数。
当提交抄袭内容的精确副本时,应用程序会对一篇文章给出近乎完美的匹配分数。那是因为内容一模一样。不错的发现,抄袭检查!
现在,对于第三个场景,我们应该定义“补丁编写的”内容的含义。补丁写作是剽窃的一种形式,在这种形式中,有人复制并粘贴窃取的内容,然后试图通过更改一些文字来掩盖他们剽窃作品的事实。如果原始文章中的一句话是,“他为找到他丢失的狗而欣喜若狂”,有人可能会将内容改为“他很高兴找回他丢失的狗。”这与转述有些不同,因为在整篇抄袭的文章中,内容的主要句子结构通常保持不变。
有趣的是:我们的剽窃检查器在识别“补丁编写”内容方面也做得很好!如果您复制并粘贴数据库中的一篇文章,然后在这里或那里更改一些单词,甚至可能删除几个句子或段落,匹配分数仍然会以近乎完美的匹配返回!当我用一篇匹配率为 99.99%的复制粘贴的文章尝试这样做时,在我修改之后,“编写的补丁”内容仍然返回 99.88%的匹配率!
不算太寒酸!我们的剽窃检查器看起来运行良好。
结论和下一步措施
我们现在已经创建了一个简单的 Python 应用程序来解决现实世界中的问题。模仿可能是奉承的最高形式,但没有人喜欢自己的作品被偷。在一个不断增长的内容世界中,像这样的剽窃检查器对作者和老师都非常有用。
这个演示应用程序确实有一些限制,因为它毕竟只是一个演示。加载到我们索引中的文章数据库仅包含来自 15 个主要新闻出版物的 20,000 篇文章。然而,有数百万甚至数十亿的文章和博客文章。像这样的剽窃检查器只有在检查你的输入和所有你的作品可能被剽窃的地方时才有用。如果我们的索引中有更多的文章,如果我们不断地添加到它,这个应用程序会更好。
无论如何,在这一点上,我们已经展示了一个坚实的概念证明。松果作为一个管理相似性搜索服务,在机器学习方面为我们做了大量工作。有了它,我们能够相当容易地构建一个利用自然语言处理和语义搜索的有用应用程序,现在我们可以安心地知道我们的工作没有被剽窃。
利用 K-最近邻算法构建板球运动员推荐系统
原文:https://towardsdatascience.com/build-a-player-recommendation-system-for-cricket-using-k-nearest-neighbor-algorithm-3742d2bfc657?source=collection_archive---------13-----------------------
使用 k-最近邻算法构建简单推荐系统的初学者指南。
照片由迈克尔·韦尔在 Unsplash 拍摄
在本文中,我们将构建一个简单的板球运动员推荐系统,该系统将根据过去为该队打球的运动员的统计数据,为该队推荐击球手名单。
我们将只为击球手构建推荐系统,通过计算他们各自的指标,该系统可以扩展到投球手和其他类型的球员。
k 近邻概述
简而言之,k-nearest neighbors (kNN)算法根据任何距离度量找出距离数据点最近的 k 个邻居。在计算数据点相似性的方式上,它与 k-means 非常相似。我们将使用 kNN 算法来推荐最接近当前团队成员的玩家。
数据采集
用于该系统的数据集是从 Kaggle 上的印度超级联赛 CSV 数据集下载的。它由 6 个 CSV 文件组成,总结了截至 IPL 第 9 赛季的 577 场 IPL 比赛的逐球信息。
理解数据
我们将使用 Pandas 来读取以下 CSV 文件。
- Ball_by_Ball.csv — 这个文件有比赛中每一个球的数据。我们可以提取前锋和非前锋球员的身份,得分等等。我们将使用这个文件来计算推荐系统的击球手统计数据。
- Match.csv — 该文件存储关于比赛的信息,如场地、球队、结果、裁判的详细信息等。我们将需要这个文件来提取一个
Match_Id
和Season_Id
之间的关联。 - Player.csv — 该文件包含所有球员的数据,即他们的姓名、国家、出生日期等。这些字段将用于使用 k-最近邻算法构建我们的推荐系统。
- Player_Match.csv — 该文件将
Player_Id
与他们参加过的比赛相关联。我们会用这个文件来了解当前队伍中球员的特点。
数据清理
我们将创建另一个名为player_data
的数据帧来存储击球手统计数据和来自现有player
数据帧的其他相关特征。由于player
数据帧有两列Is_Umpire
和unnamed:7
,这对我们的用例来说无关紧要,我们将删除它们并将其他列复制到player_data
。
player_data = player.drop(["Is_Umpire", "Unnamed: 7"], axis = 1)
特征抽出
从 Match_Id 导出赛季
我们将得出每个赛季球员的表现统计。match
数据帧具有字段Match_Id
和Season_Id
,可用于从Match_Id
中导出季节编号。
NUMBER_OF_SEASONS = 9
season_info = pd.DataFrame(columns = ['Season', 'Match_Id_start', 'Match_Id_end'])for season in range(1, NUMBER_OF_SEASONS + 1):
match_info = match.loc[match['Season_Id'] == season]['Match_Id']
season_info = season_info.append({
'Season' : season,
'Match_Id_start' : match_info.min(),
'Match_Id_end' : match_info.max()
}, ignore_index=True)
上面的代码片段会找到每个季节的Match_Id
的范围。
每个赛季的 Match_Id 范围
基于以上结果,我们将创建一个函数,该函数将基于比赛的 id 返回正确的赛季号。
def get_season_from_match_id(match_id):
season = season_info.loc[
(season_info['Match_Id_start'] <= match_id) &
(season_info['Match_Id_end'] >= match_id)] ['Season']
# Return the integer value of the season else return -1 if
season is not found
return season.item() if not season.empty else -1
每个赛季击球成绩的计算
根据ball_by_ball
数据,我们将计算每个赛季所有球员的以下特征:
- 得分得分
- 玩的局数
- 玩家没有出局的局数
- 面对球
- 四的数量
- 六的数量
计算得分、面对的球数、4 分和 6 分的数量非常简单。在ball_by_ball
数据框中,我们可以简单地检查Striker_Id
和Batsman_Scored
列中的值,并相应地增加这些特征。
难点在于计算每个赛季打的局数和球员没有出局的局数。为此,我们不仅需要查看数据帧中的当前行,还需要查看前一行。在下列情况下,玩家的局数应该增加:
Match_Id
前一个球与当前球不同。这意味着当前行属于新的比赛,因此新的一局将开始。我们将增加射手和非射手的局数。Match_Id
与前一个和当前焊球相同,但Innings_Id
发生变化。这意味着这是同一场比赛的第二局。我们将增加射手和非射手的局数。- 前一个球和当前球中的
Match_Id
和Innings_Id
相同,但当前的Striker_Id
不等于前一个Striker_Id
或Non_Striker_Id
。这意味着有新的玩家来击球了,所以我们将只为 id 等于Striker_Id
的玩家增加局数。类似的逻辑也适用于电流Non_Striker_Id.
我们还将跟踪Player_dismissed
列,找出玩家是否在特定的一局中没有出局。
击球统计的计算
最后一步是计算击球统计数据,如击球命中率(BSR) 、击球率(BA) 和每局边界得分(BRPI) 。首先每个赛季计算 BSR、BA 和 BRPI,然后根据球员参加的赛季数计算这些值的平均值。在计算平均指标时,只考虑击球手实际打过的那些赛季。这消除了对过去所有赛季都参加过比赛的球员的偏见。
每个赛季平均击球率的计算
每季击球命中率的计算
每个赛季每局边界得分的计算
一旦我们计算了这些统计数据,我们还可以得出球员的年龄,以及他们是国内还是国际球员。这些属性很重要,因为假设目前超过 40 岁的球员不会参加下个赛季的比赛。此外,由于在 IPL 球队中选择国际球员的限制,国内球员的属性将很重要。
K-最近邻的实现
对于 k-最近邻的实现,我们将使用 scikit learn 并构建一个 numpy 数组,其中只有那些特征有助于团队选择,即 BA、BSR、BRPI、年龄和国籍。
x 是代表这些特征的 numpy 数组。
from sklearn.neighbors import NearestNeighborsnbrs = NearestNeighbors(n_neighbors=3, algorithm='ball_tree').fit(X)
distances, indices = nbrs.kneighbors(X)
indices
将给出 x 中每一行的最近邻的索引
前几个玩家和他们最近的邻居的可视化。节点号是玩家的 id
对于在当前赛季中在特定球队中比赛的所有球员,kNN 将返回与现有球员相似的 3 个最近邻居。
在建议的 3 个玩家中,第一个玩家将与现有玩家相同,因为玩家与自己的距离为 0。
所有推荐的玩家都被添加到有序集合中,并按照最高 BSR 到最低排序。我们可以编程返回前 n 个击球手,其中 n 可以根据需要更改。
最终输出推荐 15 名球员按击球命中率排序。
这是击球手推荐系统的一个非常简单的实现。你可以在这里查看代码的 GitHub 库。感谢您的阅读!:)
编写生产就绪 API -第 1 部分:实现 ORM
原文:https://towardsdatascience.com/build-a-real-life-professional-api-with-an-orm-part-1-8fce4d480d59?source=collection_archive---------22-----------------------
为我们的网站创建一个高效、安全和快速的 API,而不需要编写一行 SQL
我们的 API 会比这些可爱的生物更快(图片由切瓦农摄影在像素上拍摄)
想象一下去一家餐馆。你坐下来,看菜单,选择一些菜。然后你走向厨房,告诉厨师你想吃什么,等他吃完后再把你的饭菜端上桌。这家奇怪的餐馆里发生了什么事?
没有 API 的应用程序就像没有服务员的餐馆。在餐馆里,你不需要和厨房沟通,也不需要等着点菜来享用美食。同样的,一个网站不需要知道如何与你的数据库通信。像一个服务员一样,我们的 API 从我们的网站收到一个命令:“我想要一些带有元数据的用户统计数据”。API 随后检查订单(是否允许您拥有该数据?),说服我们的数据库(厨师)为他烹制一些美味的信息,等待数据库完成,最后将数据返回到网站。
这篇文章是关于什么的?
我们将使用 ORM 为我们正在构建的名为 BeerSnob 的现实世界应用程序创建一个全功能、快速和安全的 API 一个专门为喝优质啤酒的人建立的网站。它允许用户分享关于他们在特定场所喝的啤酒的评论;在提供价格和口味信息的同时,对场地和啤酒进行评级。在本文结束时,您将拥有一个带有 ORM 的工作 API,并有一个迁移模型来完成它!首先我们进入为什么我们会创建一个 API 或者 ORM,然后我们开始编码。
0.目标和准备
我们的目标是为 BeerSnob 创建一个 API,它将从网站接收用户创建的数据包。基于所需的动作,它然后从数据库中检索数据或将数据包插入到数据库中。数据包可能包含多个表的信息,API 的工作是确保正确的信息出现在正确的表中。
为什么要构建 API?
如果你点击脸书网站或应用程序中的“我的朋友”,你会向 API 发送信息请求。这个软件翻译你的请求,检查你是否被允许提出请求,收集所有的数据并用你的数据包回应。这很好,有几个原因:
- 保持我们的代码整洁
- 保护对我们数据库的访问(网站与我们的数据库分离,例如:我们的网站不需要有数据库凭证)
- 检查用户对数据的访问(我只能更改我的个人资料,不能更改其他人的)
为什么要使用 ORM?
ORM 代表对象关系映射,它是一种允许你使用对象从数据库中查询和操作数据的技术。您不必再编写查询,您可以使用对象来检索数据。伪代码示例:song_list = SongTable.query(artist="Snoop dogg")
。优点:
- 没必要写 SQL
- 很多事情都是自动完成的
- 阻止 SQL 注入
我们来编码吧!
1.设置
在 API 能够处理数据库数据之前,我们需要一个实际使用的数据库。在 这篇文章 中,我们使用迁移来创建所有的表、关联、关联和索引。无论您是否使用迁移,本文还包含一个非常漂亮的 BeerSnob 数据库结构图。
我们将在 本文 中构建的迁移模型上构建 API。如果你想编码,那么 git 从这里的https://github.com/mike-huls/beersnobv2****克隆代码。首先让我们构建一个 ORM,然后实现我们的 API。
2.为我们的 ORM 创建模型
ORM 是我们可以在 API 中使用的对象和数据库中的数据之间的转换。为了将数据库数据转换成对象,它使用“模型”。在我们的 BeerSnob 示例中,我们希望按照foundbeers = BeerTable.Get(ID=2)
的思路做一些事情。在这个例子中,BeerTable 是一个模型,它能够连接到数据库中的 Beers 表,并对其执行操作,如检索数据和插入新记录。
像这个好孩子一样,我们的 ORM 将在我们的努力中帮助我们
让我们创建我们的第一个模型;国家。这个模型处理我们国家表中的数据。在“models”目录下创建一个名为 countries.js 的新文件,内容如下:
这个简单的文件允许我们创建一个模型。创建一个模型并理解它是如何工作的并不难。重要的事情定义如下。
- 在 tableModel(第 5 行)中,我们添加了 modelName。我决定保持表名的复数形式(countries 表包含许多国家的记录)和模型名的单数形式(一个模型只描述一个国家)。
- 模型与另一个模型相关联(第 11 行)。我们告诉我们的 ORM,如果我们删除一个国家,一个城市应该被删除。我们还在国家表(CountryId)上定义了外键。
- 在 Init 中,我们定义了一些关于列的信息。ORM 需要知道数据库中列的数据类型和名称。
- 时间戳:false(第 24 行)。如果设置为 true,ORM 会添加额外的列来跟踪创建和修改的时间戳(我们手动处理这些,但是 ORM 也可以为您完成)。
当定义模型之间的关联时,有几个选项。到目前为止,我已经在这个项目中使用了一些,但是我们将在下一部分中更深入地研究它们。我还为其他表格创建了模型。查看存储库以获取更多信息。
3.原料药制备
在我们开始创建 API 之前,我们需要安装一些依赖项并准备一些东西。
3.1 安装包。
转到您的根文件夹并:
npm install --save express body-parser
npm install --save-dev nodemon
这将安装我们的 API 需要的包。Express 是一个 web 服务器,body-parser 允许我们解析通过该 web 服务器发送的请求体。然后我们安装一个开发依赖;这些仅用于构建我们的应用程序,并且通常仅用于开发。每次我们更改代码时,Nodemon 都会重新加载我们的 web 服务器。我的 f5 键对此非常感谢。
3.2 配置您的应用程序以使用 Nodemon
打开根文件夹中的 package.json 文件。调整“脚本”部分以反映以下内容:
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js"
},
这将允许我们在生产环境中调用npm run start
或npm run dev
用 nodemon 运行我们的应用程序,允许重启。
3.3 创建文件夹
在根目录下创建两个文件夹:“routes”和“service”。
4.构建 API
是时候让这些模型发挥作用了!有了 API,我们将能够接收请求并使用模型从数据库中检索数据。我们首先设计我们的服务器,它将捕获所有的请求,并将它们传递给一个路由。然后,路由将检查请求并与数据库通信。
该去拿东西了!(图片由 Pexels 上的约瑟夫·费尔拍摄)
4.1 为我们的应用程序创建服务器
使用下面的脚本,我们将有一个服务器启动并运行。
事情是这样的:
- 我们导入了一些包和日志服务。这个服务帮助我们调试,我们在第 13 行这样做。
- 在第 9 行,我们创建了一个可以传递请求的应用程序。
- 第 24 行;我们告诉 app 我们要用 bodyParser 通过这种方式,我们可以接收例如 json 数据。
- 第 29 行:我们设置 API 的规则。
- 第 41 行到第 46 行:我们捕获一些 URL 路径,并将它们传递给我们的 routes。
- 第 59 行:为我们的应用程序创建一个服务器,并告诉它监听本地主机上的端口 5000
4.2 创建路线和处理请求
现在我们的服务器已经启动并运行了,是时候将请求传递给我们在第 41 行到第 46 行定义的路由了。下面我将展示一个处理路由的例子。我已经以完全相同的方式实现了其他路线;你可以在找到我们的知识库。
在上面的代码中,您可以看到 ORM 在处理路由时是如何工作的。让我们走完第一条路线(11 号线至 39 号线)。
- 第 11 行:我们定义路线。
/search
在我们的例子中是指localhost:5000/api/beers/search
- 第 14 行:我们从 url 获取数据。req.query 检索 url 参数(T2 中的粗体部分)。我们将参数 q 的值存储在一个变量中,这个变量也称为 q(用于查询)。在 url
localhost:5000/api/beers/search?q=ale
中,键 q 的值是‘ale’。 - 第 20 行:如果 q 太短,什么也不做
- 第 23 行到第 30 行:返回所有包含 q 的啤酒(不区分大小写)
- 第 33 行 res.retun 是我们的 API 返回的内容。它将返回一个只有一个键的对象:“beers”和我们在数据库中找到的所有啤酒的数组。我们返回状态代码 200(成功)。
- 第 36 行:如果 try-block 中有任何错误,我们通过返回一个错误让客户端知道(我们使用 errorService 来完成这个任务)。
如您所见,我们不必自己编写一行 SQL 我们可以调用模型来翻译我们的请求并与我们的数据库通信。这不仅很方便,还能防止 SQL 注入。
5.测试我们的路线
让我们测试我们的啤酒路线!在啤酒行业,有三条不同的道路:
- 这条路线使用我们的 ORM 来查询 Beers 表。你可以通过一个搜索词(q)像
localhost:5000/api/beers/search?q=heine
。然后它会寻找类似 q 的啤酒。 - 一个 GET for /
这个路由使用可选的查询参数 Id,如果提供了 Id,就尝试查找记录。否则它返回所有啤酒。尝试localhost:5000/api/beers
或localhost:5000/api/beers?id=1
- 一个用于/
的 POST 此路由接受一个它将在第 72 行(req.body)上捕获的主体。试着将下面的 json 发布到localhost:5000/api/beers
,你会看到数据库中出现一条新记录。
{
"Name": "Bud Light",
"Type": "Beer flavored water"
}
这是一篇相当长的文章:这只可爱的小狗是我们应得的(图片由 Hannah Grace 在 Unsplash 上提供)
结论
这个 API 为我们的应用程序提供了一些不错的基本功能!使用我们的 ORM,我们现在能够使用我们的 API 来搜索、获取和创建国家、城市、地点、啤酒、用户和报告。在下一部分中,我们将进一步充实我们的 API:
- 我们将添加更深入的关联(返回用户 X 提交的所有啤酒或返回访问过场所 X 并报告了啤酒 Y 的所有用户)。
- 实现更多的功能,例如:用户想要更新他们的密码
- 我们会增加安全措施。我只能编辑自己的密码,不能编辑别人的。
这是一篇很长的文章;我希望你到这里为止,我的解释够清楚了。如果不是,请让我知道我可以在哪里提高自己。关注我敬请关注!
—迈克
使用电报机器人创建一个货物跟踪工具
原文:https://towardsdatascience.com/build-a-real-time-shipment-tracking-tool-using-a-丨t丨e丨l丨e丨g丨r丨a丨m丨s丨-bot-beb6ab29fca3?source=collection_archive---------12-----------------------
设计一个电报机器人,它将与卡车司机互动,以跟踪您的货物,并提供您的运输性能的实时可见性
K8 在 Unsplash 上拍照
零售商和快速消费品公司正面临着越来越大的压力,以改善他们的供应链,增加他们的灵活性和降低成本。
使用配送中心(DC) 是一个有效的解决方案,因为它们允许在一个地方储存来自靠近最终客户的不同供应商的各种产品。
然而,它应该与有效的发货跟踪相结合,以便为商店提供准确的 eta,确保交付流程的透明度并衡量绩效。
💌新文章直接免费放入您的收件箱:时事通讯
一、TMS &跟踪工具的局限性
例子
你是一家中型零售商,在运输行业不成熟的市场上经营。
您希望实施由外部提供商提议的运输管理系统(TMS) ,以获得对您的货件的全面可见性和实时跟踪。
你能面对什么样的障碍?
- **系统接口:**您有多个不同系统的运营商
- **运营商成熟度:**他们用手工流程(Excel)管理他们的车队
- **当地具体情况:承运人不经营自己的车队(分包)
- **谈判能力有限:**因为与其他客户相比,您的业务量较低,承运商拒绝调整他们的流程,也不使用您的系统来记录状态
如果您正面临这些障碍,本文中介绍的解决方案可能会满足您的需求。
二。我们需要什么?
一个简单、便宜且易于实施的解决方案,用于跟踪您的货件
- 不需要为您的运营商进行额外的 IT 开发
- 轻松整合到当前的运输流程中
- 减少物流团队的管理工作量
- 不会影响驾驶员的工作效率
- 不需要额外设备
- 提供可见性、实时跟踪和透明度
电报机器人:您提升物流绩效的最佳盟友
三世。什么是电报机器人?
电报
丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 是一款安全、便捷的跨平台消息应用,这意味着它可以在您的所有设备上运行。丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 在全球拥有超过 5 亿用户,它有一个对所有人免费的开放 API 和协议。有了这个 API,我们可以构建自己的工具,包括机器人。
什么是机器人?
机器人是第三方应用程序,可以通过向用户发送消息、命令和内嵌请求来与用户进行交互。使用 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨,您可以通过向电报机器人 API 发送 HTTPS 请求来设计和控制电报机器人。
您的机器人可以发送/接收消息、照片、视频和 GPS 位置,足以构建我们的货件跟踪工具。
如何与电报机器人互动?
添加他并开始对话:)
四。创建你的追踪助手机器人
标准运营模式(SOP)
对于我们的 bot 的第一个版本,让我们用一个简单版本的 SOP 来记录交付时间。
确认在目的地卸货
- 商店团队已将您的货物从卡车上卸下
- 司机与你的电报机器人分享 货物编号、 GPS 位置 n 和货物的图片 以确认交货
- 电报机器人通过电子邮件发送一个 交货通知 给 你的物流团队 上面列出的信息
编辑:你可以在下面的链接中找到这篇文章的 Youtube 版本和动画。
动词 (verb 的缩写)演示:发货交付确认
方案
您的货物已在您的商店卸载。司机想在前往下一个目的地之前发送交货确认。
第一步:司机打开电报,开始与机器人讨论
驱动程序启动进程|机器人询问 GPS 位置—(图片由作者提供)
第二步:司机分享自己的 GPS 位置
司机分享其 GPS 位置| BOT 要求送货编号—(图片由作者提供)
第三步:司机分享一个送货号码
司机分享其发货编号| BOT 索要发货图片—(图片由作者提供)
第四步:司机分享货物的图片
司机分享发货照片| BOT 停止流程并发送电子邮件(图片由作者提供)
第五步:您的物流团队收到发货确认
BOT 通过邮件向运输团队发送交货确认(图片由作者提供)
http://samirsaci.com
七。设计你的电报机器人
你可以在我的 GitHub 资源库中找到完整的代码:链接
我的投资组合与其他项目:萨米尔萨奇
1。用另一个机器人创建你的机器人:)
@ BotFather 是一个电报机器人,它将帮助你创建自己的机器人
- 在电报上搜索@ BotFather,并发送给他 '/start'
- 回答 '/newbot' 消息,并按照说明设置一个名称和一个用户名
- 您的 bot 现在已经准备好了,创建了一个 API 令牌— 请保留这个令牌的副本!
用@ BotFather(图片由作者提供)通过三个步骤创建您的电报
2。安装 Python 包
包来管理你的电报机器人
pip install python-丨t丨e丨l丨e丨g丨r丨a丨m丨s丨-bot
3。导入库并启用日志记录
导入库并初始化你的电报机器人
TOKEN :创建你的 bot
APP _ NAME:你的 Heroku 应用的地址(见以下步骤)
4。带有对话处理程序的主函数
为了简化驱动程序的过程,您的 BOT 将使用 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 API 的 ConversationHandler 函数按顺序询问信息
由 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 API 的 ConversationHandler 函数处理的装运信息收集过程(图片由作者提供)
对话处理程序为具有取消功能的驱动程序创建一系列指令
照片示例 功能
- photo_file :提取用户写的消息中最后上传的照片
- 链接 1 :电报 API 创建的链接,我们可以从中提取照片文件 id
- link 2:丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 API 创建的保存这张照片的网页
- 邮件功能:用 HTML 发送一封带有 delivery_number、gps_location 和内嵌照片的邮件
照片功能示例
关于 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 API 的更多细节,我强烈建议查看文章末尾的参考链接列表。
5.邮件功能
在收集了递送号码、GPS 位置和装运图片后,您的机器人将使用 smtplib python 包和 Gmail 帐户通过电子邮件向您的运输团队发送通知。
可以在脚本 mail.py 中找到 mail 函数。
6.在云上托管您的机器人
Heroku 是一个基于云的服务,在这里你可以托管你的网络应用;托管的免费公式提供了足够的资源来运行你的应用程序。
Procfile
requirements.txt
在 Heroku 上设置您的应用程序需要上面列出的两个文件。
在这篇由浩辉 ( 链接)撰写的好媒体文章中,你可以找到如何在 Heroku 上部署你的电报机器人的详细说明。
后续步骤
关注我的 medium,了解更多与供应链数据科学相关的见解。
这是一个非常简单的版本,展示了电报机器人的潜力。
我们可以通过增加
- 实时 GPS 位置跟踪
- 将记录存储在数据库/或/ google 工作表中
- 增加扫描功能(条码/二维码),避免司机手动输入发货编号
- 在延迟交付的情况下获取商店评论和司机评论的功能?
- 运输敏感货物时的封条管理
你对可以添加的功能有什么想法吗?
请掉个评论,让我们努力打造更好的版本!
关于我
让我们在 Linkedin 上连线,我是一名供应链工程师,正在使用数据分析来改善物流运营并降低成本。
如果你对数据分析和供应链感兴趣,可以看看我的网站
https://samirsaci.com
参考
为了简洁易读,本文跳过了许多细节。你可以在下面列出的优秀文章中找到详细的说明。
【1】—https://www.freecodecamp.org/news/learn-to-build-your-first-bot-in-丨t丨e丨l丨e丨g丨r丨a丨m丨s丨-with-python-4c99526765e4/Dzaky Widya、 用 Python 、freecodecamp.org学会在电报中构建你的第一个 bot
【2】—浩辉 、 如何免费部署一个使用 Heroku 的电报 Bot、中型
【3】—吴伟峰 、 如何用 Python 创建电报 Bot、中型
[4] — 电报 API 文档
用 Node,Express 和 MongoDB 构建一个 REST API
原文:https://towardsdatascience.com/build-a-rest-api-with-node-express-and-mongodb-937ff95f23a5?source=collection_archive---------1-----------------------
让我们使用 Node、Express 和 MongoDB 构建一个遵循 CRUD 原则的 REST API,并使用 Postman 测试它。
由 Unsplash 上 Greg Rakozy 拍摄的照片
API 现在是很常见的东西。它们在网站上随处可见。API 充当存储所有数据的数据库和用户与之交互以访问数据的前端之间的连接。
API 是指**应用编程接口,**是一套明确定义的前端和数据库之间的通信方法。
REST 代表代表性状态转移,是一种架构风格,用于在网络上的计算机系统之间提供标准,使系统之间更容易相互通信。
REST APIs 大多使用 JSON 作为传输数据的首选,因为它们易于理解和阅读。
在本教程中,我们将使用 Node、Express 和 MongoDB 来创建一个 REST API,它将支持四个操作— GET、POST、PUT 和 DELETE。
所以,我们先来讨论这四个操作,并试着理解它们在 API 开发的上下文中意味着什么。
- GET — GET 表示读取数据。该操作的功能是从数据库中检索数据并呈现给用户。
- POST — POST,顾名思义,用于向数据库发布/添加新数据。它允许用户向数据库添加新数据。
- 上传 —上传意味着更新数据库中已经存在的数据。
- 删除 —用于从数据库中删除任何现有数据。
因此,我们的 REST API 将执行所有这四个操作。我们将使用 Express package 来简化我们的工作。我们将使用 MongoDB 作为 NoSQL 数据库来存储我们所有的数据。MongoDB 以 JSON 格式存储数据。
所以,我们会一步一步来。首先,我们将构建 API 端点,然后我们将连接到数据库来执行实际操作。我们将使用 Postman 软件进行 API 测试。
设置项目
首先,我们需要在我们的系统上下载 Node。然后我们可以开始创建我们的项目。
因此,首先,我们需要在系统中创建一个文件夹,我们希望在其中构建我们的项目。我将文件夹的名称保留为 rest-API 。
然后我们需要移动到我们刚刚创建的 rest-API 文件夹中。现在开始一个新项目,我们将在文件夹中运行以下命令:-
npm init
它会询问有关项目的各种问题,如名称,描述和其他事情。我们希望除了名称和描述之外的所有内容都保持默认模式,我们可以在方便的时候添加名称和描述。
完成后,我们会在文件夹中看到一个 package.json 文件。它包含了我们刚刚给出的创建这个文件的所有数据。你可以看到入口点是 index.js 文件。
在创建了 package.json 文件之后,我们需要在我们的机器上下载 Express。要安装 Express,我们可以:-
npm install express --save
这将在我们的系统中下载并保存 express,并且将 express 作为一个依赖项添加到我们的 package.json 文件中。
我们还想下载一个名为 nodemon 的开发依赖项,这将允许我们更快地开发。这将有助于我们避免每次更改时重启服务器,并且会自动刷新,这将节省我们很多时间。
因此,要安装 *nodemon,*我们应该:
npm install --save-dev nodemon
注意,我们已经使用了 save-dev 来安装并将其添加到 package.json 文件中作为开发依赖项,因为我们使用它来加速我们的开发过程。
现在,我们需要将 MongoDB 下载到我们的系统中,然后创建集群并将其连接到您的本地计算机。
接下来,我们必须从我们的 express 应用程序下载mongose来与 MongoDB 数据库交互。
要安装猫鼬,请执行以下操作:
npm install mongoose --save
现在,我们准备开始构建我们的 REST API。在开始之前,我想展示一下我的 package.json 文件,这样你就可以验证一切进展顺利。
所以,让我们开始构建我们的 REST API。首先,我们需要创建一个名为 index.js 的文件;正如我们可以看到的,它是我们应用程序的入口点。
索引文件
我们将从 index.js 文件开始。我们将首先要求 express 进入我们的系统。
const express = require('express');
然后,我们将通过编写以下代码行来设置我们的 express 应用程序
const app = express();
因此,我们将设置一个 GET 函数来使用浏览器测试它。当我们向 localhost:4000/API 发出 GET 请求时,我们传递一条消息作为响应。
app.get('/api', (req, res) => res.send('Its working!'));
然后,我们将设置我们的应用程序开始监听请求。我们将使用 4000 作为端口号。我们在那里使用了 OR 操作符,这样如果有任何通过环境变量定义的端口号,它就可以使用它;不然就用 4000。您可以根据自己的选择选择端口号。我们将 console.log 一条消息来检查它是否正常工作。
app.listen(process.env.port || 4000, function(){
console.log('now listening for requests');
});
因此,当我们现在使用以下命令启动服务器时:
nodemon index
当我们转到 *localhost:4000/api,*时,我们会看到消息“*正在工作!”。*同样,在控制台中,我们会收到为控制台设置的消息。
现在,我们已经正确设置了 express 服务器,并且成功发送了第一个 GET 请求。
现在,我们希望将所有四个操作放在一个名为 api.js 的单独文件中,该文件位于 routes 文件夹下,因为我们希望避免将所有操作都放入 index.js 文件中。
因此,我们将删除这个 index.js 文件中的 app.get 部分。我们想在我们的文件中添加猫鼬作为需求。
const mongoose = require('mongoose');
接下来,在我们的 express 应用程序的设置下面,我们希望连接到 MongoDB。我们将使用以下代码来实现这一点:
mongoose.connect('mongodb://localhost/ourdata');
mongoose.Promise = global.Promise;
这里, ourdata 是我们将在本教程稍后在 MongoDb 中创建的模型的名称。
由于猫鼬.诺言现在贬值,我们也将猫鼬的诺言更新为全局诺言。
接下来,我们将在文件中添加一些中间件。我们将首先添加对静态文件的支持。虽然我们不会在本教程中提供静态文件,但拥有它是很好的,因为我们以后无论如何都需要添加一个前端来使用 API。
app.use(express.static('public'));
然后,我们将添加 Express 解析器来解析从数据库发送或接收的数据。
app.use(express.json());
然后,我们设置应用程序来使用新的 api.js 文件,我们将创建该文件来保存所有四个操作。
app.use('/api',require('./routes/api'));
我们在开头添加了 '/api' ,以避免将其添加到所有四个操作中。
最后,我们添加了一个中间件来处理操作过程中出现的错误。
app.use(function(err,req,res,next){
res.status(422).send({error: err.message});
});
以下是 index.js 文件的最终代码
四个 CRUD 操作的布局
接下来,我们创建一个名为 router 的文件夹,并在该文件夹中创建一个名为 api.js 的新文件。这将包含我们想要用正在构建的 REST API 完成的所有四个 CRUD 操作。
我们首先在文件中要求 express。然后我们将使用快速路由器创建一个路由器。
const express = require('express');
const router = express.Router();
所以,让我们开始一个接一个地构建这四个操作。我们不会将任何东西保存到数据库中,因为我们还没有创建数据库,但是我们会更简单地测试它们。
因此,我们将从 GET 操作符开始。我们将以这种方式编写 GET 请求的代码:-
router.get('/students',function(req,res){
res.send({type: 'GET'});
};
这里,我们给出了一个端点和一个函数,该函数给出一个响应,该响应告诉我们发送的请求的类型。
接下来是 POST 请求。这将是一个类似的方式,虽然我们想返回的数据,我们收到的请求。
router.post('/students', function(req, res){
res.send({
type: 'POST',
name: req.body.name,
roll: req.body.roll
});
});
接下来是 PUT 和 DELETE 请求。现在,我们将返回两个操作的请求类型。它接受带有 id 的端点,这表示当我们保存数据到 MongoDB 时 MongoDB 提供的惟一 id。
router.put('/students/:id', function(req, res){
res.send({type: 'PUT'});
});
router.delete('/students/:id', function(req, res){
res.send({type: 'DELETE'});
});
接下来,我们将导出在 index.js 文件中使用的模块。
module.exports = router;
为了测试这些操作,我们将使用一个叫做 Postman 的软件。这很神奇,有助于快速测试 API。
下载 Postman 桌面代理或安装其 Chrome 扩展,开始使用 Postman。邮递员的新工作区如下所示
Postman API 测试
在这里,我们可以选择发送请求的操作类型和目标 URL。对于 POST 请求,我们需要在发送请求的同时发送一些 JSON 数据,这可以通过在 Body 部分添加 JSON 来实现。
您需要选择原始数据类型,然后选择 JSON 作为格式,如下所示:-
邮递员邮件请求
因此,我们可以很容易地通过 Postman 测试所有这些操作。当我们更新数据时,我们还需要在 PUT 请求时提供数据。我们只传递需要更新的数据。
构建数据库模式和模型
接下来,我们将创建一个名为 models 的文件夹,然后在该文件夹中创建一个 student.js 文件。
我们需要在那个文件夹中放入mongose,并构建一个模式,然后基于该模式构建一个模型。模式告诉模型如何构造数据。
我们正在建立一个模型,其中包含学生的数据——姓名、他们的点名号码以及他们是否在场。
- 名称 —这是字符串数据类型,在模式中不是必填字段。
- Roll —这也是字符串数据类型,是必填字段。它不能为空。
- 呈现 —这是一个布尔型字段,默认为真。
然后,在我们创建的学生模式的帮助下,我们创建了名为学生的模型。然后,我们导出模型以在 API 文件中使用它。
那么,让我们来看看 student.js 文件:-
最终确定 api.js 文件
现在,我们将通过从我们创建的数据库模型中保存和检索数据,使所有四个 API 端点都可用。
因此,我们需要在 API 文件中包含该数据库模型。
const Student = require('../models/student');
然后,我们从 GET 请求开始。我们会获取数据库中的所有学生,并作为响应发送给他们。您可以为学生添加任何类型的过滤,但是我们将 find 函数保留为空,以便从数据库中访问每个学生。然后我们使用*。catch(next)* 函数帮助捕捉任何错误,并将其传递给下一个中间件——在我们的例子中是错误处理中间件。
router.get('/students',function(req,res,next){
Student.find({}).then(function(students){
res.send(students);
}).catch(next);
});
接下来,我们要处理 POST 请求。我们在数据库中创建一个新学生,然后返回创建的学生作为响应。
router.post('/students',function(req,res,next){
Student.create(req.body).then(function(student){
res.send(student);
}).catch(next);
});
接下来,我们有 PUT 请求。我们将使用 findOneAndUpdate 函数,使用我们在 URL 端点中传递的 id 在数据库中查找相应的条目。然后,我们在 Id 的帮助下找到同一个学生,并返回更新后的学生作为响应。
router.put('/students/:id',function(req,res,next){
Student.findOneAndUpdate({_id: req.params.id},req.body).then(function(student){
Student.findOne({_id: req.params.id}).then(function(student){
res.send(student);
});
});
});
最后,我们有删除请求。我们使用函数 findOneAndDelete 通过提供的 id 在数据库中找到相应的学生,并从数据库中删除该学生。它还返回被删除的学生作为响应。
router.delete('/students/:id',function(req,res,next){
Student.findOneAndDelete({_id: req.params.id}).then(function(student){
res.send(student);
});
});
我们可以使用 Postman 软件非常容易地测试所有这些。在测试中,一切都应该很好,我们已经做得很好,很干净。
下面是 api.js 文件的最终代码:-
最后,我们创建了 REST API,它执行所有四个 CRUD 操作。因此,如你所见,在 Node、Express 和 MongoDB 的帮助下,构建 REST API 非常容易。
希望你觉得这个教程很有趣,并且学到了一些新东西。
这里还有一些值得一读的教程:
https://javascript.plainenglish.io/build-a-blog-app-with-react-intro-and-set-up-part-1-ddf5c674d25b https://shubhamstudent5.medium.com/build-an-e-commerce-website-with-mern-stack-part-1-setting-up-the-project-eecd710e2696 https://medium.com/javascript-in-plain-english/build-a-simple-todo-app-using-react-a492adc9c8a4
用 SQL 构建搜索引擎
原文:https://towardsdatascience.com/build-a-search-engine-with-sql-cc8baf06ddb2?source=collection_archive---------15-----------------------
使用全文搜索
在 Unsplash 上 Marten Newhall 拍摄的照片
如果您使用 SQL 来执行文本搜索,您可能会使用类似于的命令。但是 like 命令的限制是它寻找精确的匹配。幸运的是,SQL 提供了一个特性——SQL 全文索引——可以对任何包含原始文本的列进行模糊文本搜索。这是上帝为 NLP 项目派来的。
我是 python 提供的 NLP 库——scikit learn 和 spaCy 的忠实粉丝。
但是在进入文本处理的深水区之前,最好先尝试一下 SQL 的全文索引。
在本文中,我们将了解如何使用 MS SQL 的文本搜索功能来执行弹性搜索。是的,完全成熟的弹性搜索。
资料组
我们将使用亚马逊点评数据集,网址为:
让我们专注于一个产品类别
作者捕获的屏幕截图
把下载的 json 导入 python,看一下数据。
作者捕获的屏幕截图
将数据推入 SQL
作者捕获的屏幕截图
设置全文搜索功能
先做点家务。
在 SQL 中,检查 SQL Server 中是否安装了全文功能
如果尚未安装,请使用以下链接进行安装。
https://www.sqlshack.com/hands-full-text-search-sql-server/
检查它是否已启用。
在 AmazonReviews 表上创建全文目录。
可以把这里想象成索引将要被填充的地方..
人口…这是什么意思..?
我们很快就会知道…
现在,看看 AmazonReviews 表的主键。
嗯(表示踌躇等)..
该表将 ID 作为主键。
在索引中,它被命名为 PK_AmazonRe_3212…
为了方便以后访问,我们将其重命名。
表的主键
看上去好多了。
现在,我们一直在等待的部分…
填充,即填充全文索引。这使我们能够对评论文本执行超快速搜索。
让我们来看看全文的内容。
《金融时报》索引的内容
这就是我们所说的填充索引。
Its 有 121995 个条目。它记录了哪个术语在哪个列中出现了多少次。
就像我们在 scikit learn 中创建的计数矢量器中的词汇表一样。
最后,让对 reviewText 列执行搜索操作。
你瞧…!
精确匹配排名更高
28000 行匹配结果。
让我们进一步探索…
比赛的低端
排名较高的行包含与搜索词“低电量”完全匹配的内容。而相反,排名较低的行包含部分匹配,如仅单词“低”或仅单词“电池”。
此外,请注意,当我们滚动浏览结果时,评论的长度会增加。
排名是如何运作的?
在这一点上,理解行是如何排列的是很有趣的。
它的排名基于 OKAPI BM 公式。
完整的公式是:
公式来自:https://docs . Microsoft . com/en-us/SQL/relational-databases/search/limit-search-results-with-rank?view=sql-server-ver15
但实际上归结为以下因素:
查询中的字数
数据库中匹配查询词的行数
以 DB 为单位的行的平均长度
词的频率(DB)
查询中的词频
这解释了为什么具有 12330 个字符的匹配行具有最低的等级分数,而具有 141 个字符的匹配行具有最高的等级分数。
并且使用 SQL 中的全文搜索可以快速、轻松地执行弹性搜索。这种执行模糊搜索并对结果进行排序的能力构成了任何搜索引擎的核心。这个特性最好的部分是索引可以被设置为在基本数据更新时自动更新。
除了使用它的搜索功能之外,我个人在许多 NLP 项目的开始使用了全文索引。例如,浏览索引和术语计数让我对特定领域的停用词有所了解。滚动索引并查看拼写错误的单词或错别字,给了我需要执行的文本清理步骤的线索。
谢谢你能走到这一步。我会写更多这样的帖子。让我知道你对这篇文章的看法,以及你希望通过在 LinkedIn 上给我发消息来了解的其他话题。以后的帖子,请关注我的媒体。
用 Amazon Lambda 和 API Gateway 构建一个无服务器 API
原文:https://towardsdatascience.com/build-a-serverless-api-with-amazon-lambda-and-api-gateway-dfd688510436?source=collection_archive---------8-----------------------
如何以最简单的方式托管可伸缩的无服务器 API
照片由 Unsplash 的 Saish Menon 拍摄。
目录
- 介绍
- 使用 GingerIt 创建一个拼写和语法纠正器
- 将 Python 服务部署到 Lambda
- 将 API 网关与 Lambda 相关联
- 使用 API 密钥保护和抑制 API
- 结论
- 参考
介绍
在我以前的文章“使用亚马逊 S3 和 Route 53 构建一个无服务器网站”中,我演示了如何构建一个由静态(客户端)内容组成的无服务器网站。这种方法允许轻松地将网站从 10 个扩展到 1000 个,同时保持低成本。
为了将无服务器扩展到动态(服务器端)内容,Amazon Web Services (AWS)提供了更多的服务,如 AWS Lambda。与 API Gateway 一起,我们可以创建 RESTful APIs,实现实时双向通信应用程序。
在这篇文章中,我们将介绍如何使用 AWS Lambda 创建和部署拼写和语法纠正应用程序,并通过 API Gateway 响应标准 HTTP 请求。
使用 GingerIt 创建一个拼写和语法纠正器
GingerIt 是一个人工智能驱动的开源 Python 包,它可以根据完整句子的上下文来帮助纠正文本中的拼写和语法错误。
要使用它,让我们首先创建一个虚拟环境,并在其中安装 GingerIt。
为了测试它,在终端中运行下面的代码片段。
这将显示原始文本,然后是由 GingerIt 修改的文本。
Original text: 'This is a corrects snetence'
Corrected text: 'This is a correct sentence'
将 python 服务部署到 Lambda
“AWS Lambda 是一种无服务器计算服务,让您无需配置或管理服务器就能运行代码(…)。Lambda 自动精确地分配计算执行能力,并基于传入的请求或事件运行您的代码(…)。你可以用自己喜欢的语言(Node.js、Python、Go、Java 等)编写 Lambda 函数,同时使用无服务器和容器工具,比如 AWS SAM 或 Docker CLI。”
Amazon 的上述声明总结了 Lambda 的目的:提供一个简单的服务,使用任何主要语言的定制代码对请求做出反应,并且不需要管理运行时。为了进一步促进 API 的开发和部署,Lambda 还支持 Docker。
为了部署 GingerIt 拼写和语法纠正服务,我们将利用 Lambda 的 Docker 支持。为此,我们首先需要将 Python 服务打包到 Docker 容器中。
让我们从创建 lambda 处理程序开始,每次执行 Lambda 函数时都会调用这个处理程序。这个处理程序将接收一个 json,其中包含我们想要修改的文本,用 GingerIt 处理它,并返回修改后的文本。将下面的代码片段另存为 app.py 。
现在我们只需将 app.py 文件包装在一个 Dockerfile 中,如下所示。请注意,您应该使用 AWS 支持的图像。这将确保正确设置执行 Lambda 所需的所有包。
要测试 lambda 函数,首先要构建并运行 docker 容器。
然后在终端或笔记本中运行下面的代码片段。
如果所有步骤都成功,您应该会看到以下输出。
{‘body’: ‘{“corrected_text”: “This is the correct sentence”}’, ‘headers’: {‘Content-Type’: ‘application/json’}, ‘isBase64Encoded’: False, ‘statusCode’: 200}
此时,我们知道本地 Lambda 工作正常。下一步是远程运行它(无服务器)。为此,我们需要:
- 将 docker 映像推送到 Amazon 弹性容器注册中心(ECR)
- 创建一个新的 Lambda 函数,并将其与 ECR 图像相关联
- 为 Lambda 函数设置 IAM 访问权限
幸运的是,通过使用*无服务器框架,整个过程(以及后面介绍的额外步骤)可以被简化。*要安装它,只需按照官方无服务器网站 ⁴.
安装完 serverless 后,创建一个名为 serverless.yml 的新文件,并在其中添加以下内容。
这个文件定义了 Lambda 中的关键参数。
**service**: Name of the service we are creating. This name will be user across all required resources.**provider:
name**: Name of cloud provider to use (AWS)
**stage**: Stage to use (dev, prod)
**region**: Region to where to deploy the lambda function
**runtime**: Runtime that will be used to run the docker container. the python version should match the docker one.
**ecr**:
**imager**:
**gingerit**: Target name for the docker image
**path**: Defines where the docker file is**functions:
gingerit**: Defines the parameters for the lambda function named ‘gingerit’
**timeout:**If request takes longer than the defined value, return time out
**memory_size**: Total docker RAM in Megabytes
**image:
name**: Name of the docker image to use. Must match provider.ecr.image
要部署我们的服务,我们现在只需在终端中调用无服务器部署。应该会出现以下输出(将映像部署到 ECR 和 Lambda 函数可能需要几分钟时间)。
Serverless: Stack update finished...
Service Information
service: language-corrector
stage: dev
region: eu-west-1
stack: language-corrector-dev
resources: 6
api keys:
None
endpoints:
None
functions:
gingerit: language-corrector-dev-gingerit
这个输出显示了我们的 lambda 函数的全名**(language-corrector-dev-gingerit)以及我们定义的一些变量。要测试该函数,请在终端或笔记本单元格中运行以下代码片段。**
应该可以看到以下输出:
**{'body': '{"corrected_text": "This is the correct sentence"}',
'headers': {'Content-Type': 'application/json'},
'isBase64Encoded': False,
'statusCode': 200}**
万岁!您刚刚创建了一个拼写和语法纠正工具,并将其部署为无服务器。
将 API 网关与 Lambda 相关联
“API Gateway 处理与接受和处理多达数十万个并发 API 调用相关的所有任务,包括流量管理、CORS 支持、授权和访问控制、节流、监控和 API 版本管理。(…) API Gateway 支持容器化和无服务器工作负载,以及 web 应用程序。”⁵
总之,API Gateway 充当了客户端浏览器和 Lambda 函数之间的中间人,接受并处理 HTTP 请求和响应。此外,它还可以用来设置每秒允许的调用次数的限制,或者给定函数或 api 键的每月上限。
要使用它,我们只需在无服务器的函数中添加一个 events 对象。我们新的无服务器看起来像这样:
事件对象定义了设置 API 网关所需的字段。
****http:** Defines the event as an HTTP method
**path:** Endpoint path name
**method:** HTTP method used to access this endpoint
**cors:** If true allows Cross-Origin Resource Sharing
**async:** Endpoint can be accessed async
**private:** Endpoint requires an API key to be accessed**
如果我们现在重新运行无服务器部署,则会出现一个新字段(端点)。这个字段指示 API 网关的地址,我们需要它通过 HTTP 请求调用 Lambda 函数。
**endpoints:
POST - [https://olx5ac31og.execute-api.eu-west-1.amazonaws.com/dev/language_corrector](https://olx5ac31og.execute-api.eu-west-1.amazonaws.com/dev/language_corrector)**
这表示我们需要通过标准 HTTP 请求调用 Lambda 函数的 API 网关地址。要测试新端点,请运行下面的代码片段。
如果成功实现了 API 网关,应该会出现正确的文本:
**{'corrected_text': 'This is the correct sentence'}**
使用 API 密钥保护和抑制 API
到目前为止,我们有一个部署在 Lambda 中的工作 API,它可以通过标准的 HTTP 方法接受请求。
然而,任何知道 URL 的人都可以访问这个函数,并且对每秒的请求数没有限制。这是很危险的,因为如果有太多的请求,它会很快增加你每月的花费。
为了减轻这种情况,我们可以在 API Gateway 中设置 API 密钥。要使用它,我们只需在无服务器中向我们的提供者添加一个 apiGateway 对象,并将我们的 events 对象中的私有标志设置为 true。我们新的无服务器看起来像这样:
apiGateway 对象为我们的 API 定义了使用计划。在这个例子中,我们设置了两个 API 键。一个有一些限制的免费 API 密匙,和一个允许每秒更多请求和更高上限的付费 API 密匙。
**apiGateway:
apiKeys:
- free: name of the usage plan
- name of the api key
usagePlan:
- free:
quota:
limit: Maximum number of requests in a time period
offset: The day that a time period starts
period: The time period in which the limit applies
throttle:
burstLimit: Rate limit over a short amount of time
rateLimit: API request steady-state rate limit**
如果我们现在重新运行无服务器部署,则会出现一个新字段( api 密钥)。该字段指示我们的新 API 密钥的名称和值。
**api keys:
medium-language-corrector-free: FREE_KEY
medium-language-corrector-paid: PAID_KEY**
要测试新端点,请运行下面的代码片段。
如果成功实现了 API 网关,应该会出现正确的文本:
**{'corrected_text': 'This is the correct sentence'}**
完成脚本
如需完整的脚本,请点击以下链接进入我的 GitHub 页面:
****https://github.com/andreRibeiro1989/medium/tree/main/spell_grammar_correction
结论
使用无服务器计算允许您在不管理 web 服务器的情况下扩展应用程序,同时保持低成本。
虽然对于静态内容,最简单和最实惠的选择是亚马逊简单存储服务(S3),但这种方法不允许我们使用动态服务器端代码。
为了将无服务器扩展到更复杂的应用程序,在本教程中,我们探索了如何使用 Amazon Lambda 和 API Gateway 来部署无服务器拼写和语法纠正工具。
这个简单的例子将为您提供构建更复杂的应用程序所需的所有工具,比如无服务器聊天机器人或图像处理服务。****
加入我的邮件列表,我一发布就有新内容!
如果你喜欢阅读这样的故事,并想支持我成为一名作家,可以考虑报名成为一名媒体成员。每月 5 美元,让你可以无限制地访问 Python、机器学习和数据科学文章。如果你使用我的链接注册,我会赚一小笔佣金,不需要你额外付费。
****https://andrefsr.medium.com/membership
参考
1 A .里贝罗。"用亚马逊 S3 和 Route 53 搭建一个无服务器网站"
https://towardsdatascience . com/Build-a-server less-website-using-Amazon-S3-and-Route-53-c 741 FAE 6 ef 8d
[2] T .克莱因施密特。"欢迎使用 Gingerit 的文档!(2015)
https://gingerit.readthedocs.io/en/latest/
[3]亚马逊团队。AWS Lambda
https://aws.amazon.com/lambda/
[4]无服务器团队。无服务器框架—文档
https://www.serverless.com/framework/docs/getting-started
[5]亚马逊团队。亚马逊 API 网关
https://aws.amazon.com/api-gateway/****
在 GCP 建立一个无服务器的交付指挥中心
原文:https://towardsdatascience.com/build-a-serverless-parcel-delivery-command-center-on-gcp-7c2df99b3db1?source=collection_archive---------39-----------------------
结合地图,或工具,发送网格和云功能来征用一个送货车队
本文展示了如何:
1.在 GCP 建立一个云存储,当文件上传时触发云功能;
2.用谷歌地图和谷歌 OR-Tools 设置一个计算最优路线策略的云功能;
3.通过 SendGrid 向承运人发送说明电子邮件;
4.为持续部署设置云构建。
令人惊讶的是,仅仅通过几项服务就可以在云上构建许多现代商业解决方案。开发人员可以将云组件结合起来,构建一个从数据接收到通过电子邮件发送结果的管道,只需点击几下鼠标。价格很灵活。硬件配置最少,尤其是使用无服务器选项时。因此,小型企业现在可以负担起大量的计算能力。计算能力的民主化使许多传统企业迅速现代化。其中之一一定是送货服务。
图一。Joshua Fernandez 在 Unsplash 上的照片
我在 Medium 上看到了两篇文章:一篇是由 Sebastian Telsemeyer 写的,关于用 Cloud Run 和 Pub/Sub 在 GCP 建立一个时间序列预测管道;
第二个是由 Samir Saci 提出的,他使用 Goolge OR-Tools 来优化最后一英里的交付(然而解决方案是由 Goolge 在 2020 年首先提出的):
塞巴斯蒂安的文章鼓舞人心。在他的管道中,一个 Pub/Sub 监控一个特定的 GCP 桶。上传 TSV 文件时,它会激活云运行计算,在第二个存储桶中生成结果。他的整个基础设施是无服务器的,并且是用 Terraform 编码的。在我看来,他的管道甚至可以更简单:一个Finalise/Create
事件触发的云函数,可以代替“Pub/Sub + Cloud Run”组合。更简单的版本需要更少的设置。因为云函数基本上是一个 Lambda 函数,所以它摆脱了整个 Docker 部分和 Gunicorn + Flask 依赖关系。
Samir 的文章展示了一个复杂的有容量限制的车辆路线 问题 (CVRP)如何通过 Google OR-Tools 解决。让我们假设有 30 个包裹需要由两个承运人从德国布伦瑞克的一个物流中心分发到九个不同的地方。每个承运人最多可以承运 15 个包裹。然后,Google OR-Tools 会尝试以最低的成本规划路线,同时平衡每个承运人的负载和距离。示例输出如下所示:
Hello Driver A, your delivery route is:
bring 2 Parcels to Institute of System Security, Muehlenpfordtstrasse 23, 38106 Braunschweig ->
bring 2 Parcels to Am Schuetzenpl. 1, 38114 Braunschweig ->
bring 3 Parcels to Humboldtstrasse 1, 38106 Braunschweig ->
bring 2 Parcels to Johanniterstrasse 5, 38104 Braunschweig ->
bring 6 Parcels to Willy-Brandt-Platz 1, 38102 Braunschweig ->
OR 工具将十个位置的距离矩阵作为输入之一。在谷歌的原始帖子和萨米尔的文章中,距离矩阵是虚构位置的硬编码虚拟物,路线指示只是以文本形式打印出来。在真实的配送指挥中心,我们需要根据真实地址计算距离矩阵(见我之前的文章此处)并通知承运人他们的路线。
图二。GCP 交付精简版架构。由onlinewebfonts.com承运图标,由 CC 3.0 授权。图片作者。
带着这些想法,站在 Sebastian 和 Samir 的肩膀上,我接受了挑战,并在 GCP 实施了一个简单的解决方案。云存储中的上传事件可以触发云函数通过 Google Maps API 构建距离矩阵。或工具然后计算路线。最后,它通过 SendGrid 将路线指示发送给运营商(图 2。).作为奖励,我设置了云构建来持续部署应用程序。这个项目的代码存放在我的 Github 库中。
https://github.com/dgg32/gcp-delivery-lite
1.准备输入 Json 数据
输入的 Json 数据包含两部分。第一部分包含所有位置的地址和包裹数量。第一个位置总是承运人装载包裹的物流中心。第二部分是承运人的信息,包括他们的姓名、能力和电子邮件地址。下面是我的 input.json 的缩略版。
2.设置发送网格
我们希望通过云功能向运营商发送说明电子邮件。Goolge 建议我们使用可信的第三方提供商,比如 SendGrid。SendGrid 中的免费计划允许每天 100 封邮件永远免费,这对我们的项目来说足够了。
图 3。发送网格 API 设置。图片作者。
图 4。通过整合测试。图片作者。
首先,用免费计划在 SendGrid 中注册一个账户。然后创建一个发送者身份。这是电子邮件中的“发件人”地址。之后,SendGrid 会向您发送一封电子邮件。在发送电子邮件之前,您需要验证您的单一发件人是否遵循其说明。
然后导航到用户仪表盘,点击打开Email API
和Integration Guide
。选择Web API
和Python
。然后创建一个 API 键(图 3。)并遵循测试说明,直到您通过集成测试(图 4。).将单个发件人的电子邮件和 API 密钥保存在安全的地方,以备后用。
3.建立 GCP
在你的 GCP 控制台上创建一个名为delivery-lite
的项目。启用Distance Matrix API
并为其创建一个限制性 API 密钥。这个过程涉及到许多点击,你可以在这里阅读我以前的文章获得指导。
然后转到Cloud Function
并创建一个函数command-center
,选择Cloud Storage
作为触发类型,选择Finalize/Create
作为事件。单击“浏览”并创建一个存储桶。点击SAVE
。
图 5。云功能配置。图片作者。
展开RUNTIME
设置,添加四个环境变量:
KEY
是你的距离矩阵 API 键。SENDGRID_API_KEY
是您的 SendGrid API 密钥。SENDER
是您的单一发件人电子邮件地址。PROJECT
是项目名称,在本例中是delivery-lite
。
然后可以点击NEXT
按钮进入Code
页面。启用Cloud Build API
,并按照警告横幅中的说明创建凭证。完成后,返回到Code
页面。选择Python 3.9
作为运行时,输入main
作为进入点。
在内嵌编辑器中创建一个名为function.py
的文件。将我的存储库中的内容复制并粘贴到相应的文件中(图。6).或者你可以压缩并上传我的三个文件。按下DEPLOY
按钮,等待功能就绪。
图 6。定义云函数。图片作者。
function.py
包含三个辅助功能。前两个用于通过 Maps API 计算地点列表的距离矩阵。第三个通过 SendGrid 发送电子邮件。
main.py
利用了function.py
。在第 12 行收到距离矩阵后,脚本将它与运营商信息打包在一起,最后在第 29 行调用 OR-Tools。如果找到了至少一个解决方案,脚本将制定路线指令,并通过第 46 行的 SendGrid 分别发送给每个承运人。在此,我感谢 Samir 和 Google 团队提供的 OR-Tools 代码示例。
4.测试管道
设置好一切之后,我们现在可以测试管道了。下面是input_test.json
文件。修改carrier
列表中的信息,特别是在email
字段中输入有效的电子邮件地址,以便接收输出指令。打开云存储页面的一个新选项卡,找到指定的存储桶。将input_test.json
文件上传到 bucket 中(图 7。).这应该会触发我们的云功能运行。
图 7。将输入数据上传到指定的桶中。图片作者。
如果一切顺利,您可以在云功能页面的LOGS
中看到新的日志条目。它们是脚本的标准输出(图 8。).
图 8。成功执行管道的日志。图片作者。
你可以查看你的运营商的电子邮件。一封包含路由说明的新电子邮件应该很快就会到达(图 9。).
图 9。带有路线说明的电子邮件。图片作者。
5.为持续部署设置云构建
使用云构建建立一个连续部署(CD)管道是非常容易的,这样新的修改就可以被自动和立即地部署。首先,建立一个 Github 存储库,并用这三个文件初始化它。或者你可以直接转到我的知识库。你还需要先启用[Cloud Resource Manager](https://medium.com/ci-t/how-to-set-up-a-deployment-pipeline-on-gcp-with-cloud-build-and-cloud-functions-88ef485728f9)
API。
图 10。云构建触发器设置。图片作者。
接下来,导航到Cloud Build
页面。创建一个名为CICD-delivery
的触发器。选择你的 Github 库和Source
的^master$
分支(你需要按照 GCP 的指示连接你的 Github 库)。选择Cloud Build configuration file (YAML or JSON)
,点击CREATE
。最后,在 Settings 选项卡中,启用Cloud Functions Developer
角色。
然后,确保文件cloudbuild.yaml
位于您的存储库的顶层,并且包含以下内容:
该文件指示 Cloud Build 使用正确的区域、存储桶触发器和运行时来部署应用程序。从现在开始,每当你向存储库推送新的变更时,GCP 将自动构建管道并将其部署为云功能。
结论
成功!现在,我们有了一个简单的管道,作为递送业务的神经中枢。手动调度已经成为过去。每当您将新订单或新承运商的新 Json 文件上传到桶中时,云功能将自动计算最佳路线,并通知登记的承运商他们的指令。并且只有在运行时才会产生成本。此外,CD 管道确保您的更改可以自动部署。
承认,这个设计是我的指挥中心理念的一个基本实现。您可以在其中构建更多组件,使其更加强大。例如,一旦用完可用层配额,距离矩阵的成本可能会失控。如果我们能够将成对距离存储在数据库中,那就太好了。此外,我们可以将运营商放入一个池中,以便更好地管理他们的个人数据。
即使有了所有这些扩展,管道仍然只是一个大型现实世界优化问题的简单抽象。OR 工具假设所有的订单都是已知的,并且在路线开始之前所有的承运人都已经在物流中心等待。在现实世界中,订单源源不断,承运人无处不在。但我认为,这些违规行为只会对结果产生轻微影响,管道仍然可以保持畅通。此外,距离有时并不是成本计算的最佳替代。幸运的是,距离矩阵 API 也返回两个地方之间的行驶时间,值得进行一些测试,看看哪个度量更好。
此外,我可以想象我们可以从这条管道中创造出非常不同的东西。因为谷歌或-Tools 可以计算其他类型问题的解决方案,我们可以将管道转化为汽车共享指挥中心、公交路线设计师、班次规划服务甚至饮食计算器。
因此,现在是时候让你在这条管道上进一步构建一些东西,并向我展示你的想法。
https://dgg32.medium.com/membership
使用亚马逊 S3 和 Route 53 建立一个无服务器网站
原文:https://towardsdatascience.com/build-a-serverless-website-using-amazon-s3-and-route-53-c741fae6ef8d?source=collection_archive---------11-----------------------
如何在 15 分钟内托管一个可扩展的网站
图片来自 Unsplash 上的迭戈·希门尼斯。
目录
- 介绍
- 在亚马逊 S3 主持一个网站
- 将自定义域与 Amazon Route 53 相关联
- 在线主持个人作品集
- 结论
- 参考
介绍
你有没有想过建立自己的网站?也许是为了展示你的工作、你的业务,或者只是一种在线展示的方式?
对于大多数应用程序来说,网站可以只用客户端代码运行,并且只由 HTML、CSS 和 JavaScript 组成。这类网站通常被定义为静态网站。由于没有运行或维护服务器端代码,使用传统的 web 服务器毫无意义。
Amazon Web Services (AWS)为托管静态或动态网站提供了多种选择。对于静态内容,最简单和最实惠的选择是亚马逊简单存储服务(S3)。
在这篇文章中,我们将介绍如何创建一个 S3 桶,并为虚拟主机设置它,将 S3 端点指向一个自定义域,并创建一个简单的投资组合网站。
在亚马逊 S3 主持一个网站
‘亚马逊简单存储服务(亚马逊 S3)是互联网存储。它旨在使网络规模的计算更容易。亚马逊 S3 有一个简单的网络服务界面,你可以用它在任何时间从网络上的任何地方存储和检索任何数量的数据。’
亚马逊的上述声明总结了 S3 的目的:提供一个简单的接口,以高度可扩展和可靠的方式存储和检索数据。不仅如此,将数据存储在亚马逊 S3 是一个可行且负担得起的解决方案。
这些关键优势加上不需要网络服务器,使得亚马逊 S3 成为静态虚拟主机的理想服务。让我们潜入亚马逊 S3,托管我们的第一个网站。
为虚拟主机创建和配置 S3
第一步是创建一个 S3 桶来存储我们的网站文件。为此,请导航至 S3 界面,然后单击“创建时段”。
S3 接口。图片由作者提供。
在“常规配置”部分,将“存储桶名称”定义为“投资组合”。#DOMAIN_NAME# '。这将是你的投资组合的主页链接。将#DOMAIN_NAME#替换为您拥有的域名。如果您没有域和/或不想创建域(查看下一节如何注册域),这可以是 rfc3986 中允许的任何字符序列。
在下一部分中,取消选中“阻止所有公共访问”。这将允许用户检索存储在 S3 存储桶中的静态页面。
选中警告框“关闭阻止所有公共访问可能会导致此存储桶和其中的对象成为公共的”,然后单击“创建存储桶”。
在 S3 创建一个新的存储桶。图片由作者提供。
单击您刚刚创建的存储桶名称,然后转到“属性”。向下滚动并点击“静态虚拟主机”部分的“编辑”按钮。
在此窗口中:
- 在“静态网站托管”中选择“启用”
- 在“托管类型”部分保留默认的“托管静态网站”
- 在“索引文档”中键入“index.html”
- 单击保存更改
改变 S3 桶到静态网站托管。图片由作者提供。
转到“权限”部分,向下滚动并单击“存储桶策略”部分中的“编辑”按钮。在文本框中,键入以下策略,然后单击“保存更改”。
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "AllowPublicRead",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::portfolio.#DOMAIN_NAME#/*"
}
]
}
您的存储桶策略应该是这样的。
添加 S3 策略以允许公共读取访问 S3 存储桶。图片由作者提供。
上传数据并测试网站端点
仍然在您创建的 S3 存储区中,移动到“对象”部分,上传一个名为“index.html”的新文件,其内容如下:
<html>
Hello World!
</html>
您可以用任何文本编辑器创建这个文件。请确保将其命名为“index.html”。您的 S3 桶现在应该看起来像这样。
为静态虚拟主机配置的 S3 桶包括一个样本 index.html。图片由作者提供。
我们可以通过打开以下链接来测试网站是否工作:
http://portfolio。# DOMAIN # . S3-website-eu-west-1 . Amazon AWS . com
测试新创建的静态虚拟主机。“Hello World”消息表明“index.html”文件已成功检索。图片由作者提供。
好吧!我们刚刚创建了一个工作网站。我们缺少的是这个端点和一个自定义域之间的链接。
如果您有自己的域,或者现在想使用 Route 53 创建一个域,请转到下一部分,将我们新创建的端点链接到该域。否则,转到“在线托管个人投资组合”部分,创建您的第一个投资组合网站。
将自定义域与 Amazon Route 53 相关联
Amazon Route 53 是一个高度可用和可扩展的云域名系统(DNS)service⁴.Amazon Route 53 可用于将自定义域路由到任何 AWS 服务(如 S3 端点)。推荐使用该服务,因为它可以轻松地与许多 AWS 服务(如 S3、CloudFront 或 EC2)集成。
亚马逊路线 53 主页。图片由作者提供。
虽然您可以通过多个提供商注册一个域,但 Amazon Route 53 也提供了一种注册自定义域的简单方法。使用 53 号公路简化了从注册域名到托管网站的整个过程。
向 Route 53 注册自定义域
要注册域名,请导航至 Route 53 主页,然后点击“开始”。点击“注册一个域”,键入您想要注册的域,如果可用,将其添加到购物车。最后,添加如下所示的详细信息,并完成注册过程。
亚马逊 53 路的域名注册页面。图片由作者提供。
当您使用 Route 53 注册一个域时,AWS 会自动为该域创建一个“托管区域”,并在域注册年费之外对托管区域收取少量月费。
如果您决定不使用 Route 53,您可以在注册域名的 12 小时内删除托管区域,并且不会为此向您收费。在本教程中,我们将假设您将使用 Route 53 来处理端点和您的域之间的路由。
自定义域注册后的 Route 53 接口示例。图片由作者提供。
将自定义域与 S3 端点相关联
要链接之前创建的 S3 端点,请点击 Route 53 主页中的“托管区域”,然后点击您的域,最后点击“创建记录”。
在这个新窗口中,在“记录名称”中键入“投资组合”,并按如下方式匹配其余字段。确保自动识别的 S3 存储桶与我们刚刚创建的存储桶相匹配。最后,点击“创建记录”。
创建 Route 53 记录以将 S3 web 宿主端点链接到自定义域。图片由作者提供。
现在让我们来测试我们的定制域的投资组合。#域# '
测试到 S3 web 宿主端点的自定义域链接。“Hello World”消息表明“index.html”文件已成功检索。图片由作者提供。
很好。我们设法创建了一个功能齐全的网站托管在 S3,并链接到我们的自定义域。现在,你只需要将你的内容添加到 S3,它将在你的网站上随时可用。
在线主持个人作品集
为了完整起见,让我们下载一个引导文件夹模板,并将其添加到我们的网站。
要做到这一点,去 https://startbootstrap.com/theme 的下载他们免费的自由职业者模板(或者任何你喜欢的模板)。
Start Bootstrap 免费提供的作品集模板快照。
在本地提取 zip 文件的内容,并将文件拖放到您创建的 S3 存储桶中。
S3 上传界面。图片由作者提供。
最后刷新你的网站,你的新作品集应该会出现。
在新创建的 web 服务中运行的项目组合模板。图片由作者提供。
结论
托管一个静态网站从来没有这么容易。
亚马逊 S3 提供了一个简单的界面,以灵活、可扩展、快速和廉价的方式存储和检索大量数据。
同时,Route 53 简化了定制域的创建和路由,并且非常容易与 S3 和其他 AWS 服务集成。
似乎这还不够,AWS 为前 12 个 months⁵.使用 S3 的新用户提供了一个免费层因此,如果你的网站低于 5GB,你只需支付域名注册和托管区。
参考
1亚马逊团队。"什么是亚马逊 S3?
https://docs . AWS . Amazon . com/Amazon S3/latest/user guide/welcome . html
[2] T. Berners-Lee 等.统一资源标识符(URI):通用语法(2005)
https://www.ietf.org/rfc/rfc3986.txt
[3]亚马逊团队。"设置网站访问权限"
https://docs . AWS . Amazon . com/Amazon S3/latest/user guide/websiteaccesspermissionsreqd . html
[4]亚马逊团队。亚马逊路线 53
https://aws.amazon.com/route53/
[5]亚马逊团队。" AWS 自由层【https://aws.amazon.com/free/?all-free-tier】"
构建一个简单的 Web 应用程序来分类 50 美元和 100 美元的钞票
原文:https://towardsdatascience.com/build-a-simple-web-app-to-classify-us-50-dollar-100-dollar-bills-d4ef8298ae6?source=collection_archive---------34-----------------------
使用 Jupyter 笔记本从模型到生产
“作者提供的图像”
你有一张 50 美元或 100 美元的钞票,关于这张钞票的一些事情引起了关注,你想检查这张钞票是不是假钞,如果你有一个应用程序,可以上传钞票的照片并立即得到结果,这不是很方便吗?如果你能为自己造一个呢?你可能会说,既然市场上已经有很多其他选择,为什么还会有人开发这样一款应用。好了,这就把我们带到了人工智能和深度学习的话题上。这篇文章不是关于一个应用程序或想法是否是原创的,而是关于如何使用 fastai 深度学习库和 voila 创建有用的模型并将其部署在网络上。在这篇文章中,我将分享我是如何建立我自己的美国钞票分类器的,通过遵循说明,你也许可以建立一个甚至更好的分类器,或者赋予你独特的想法以生命。话虽如此,我将要提供的代码和指令可能适用于类似的问题,然而,相同的代码和技术并不适合所有的解决方案。
深度学习模型
在这个 50 美元和 100 美元分类模型的背景下,该模型将分类或预测图像是 50 美元还是 100 美元的钞票,就像我们人类可以用我们的视觉区分或识别物体一样。例如,一个孩子看到一只鸟向窗外望去,可以立即认出羽毛、喙以及与标签“鸟”相关的特征。孩子以前见过鸟,两个重要的方面来自孩子对鸟的识别或辨认机制:1)鸟的特征,如羽毛、喙、翅膀、形状、颜色等。以及 2)与那些特征相关联的标签“鸟”。类似地,该模型以带有标签的图像形式提供数据——“50 美元”或“100 美元”,然后学习这些图像的特征,例如边缘、颜色、梯度等。一旦模型已经从数据中学习,当呈现学习数据中不包括的图像时,它仍然可以识别对象!假设我们为模型提供每种类型的 100 张图片,总共 200 张带有标签的图片。然后我们可以要求模型(以编码的形式提供参数)取每种类型的 80 幅图像(标签)来学习特征(每种类型的 80 幅图像,总共 160 幅图像被称为训练数据),并留出模型没有看到的其余图像(未看到的图像组被称为验证集)。验证集用于检查模型已经学习了多少。如何检验模型是否准确?有一些方法可以用来验证模型的口径。我们将继续研究这些方法。使用标签区分图像的过程称为分类。深度学习是基于人脑功能的人工智能的一个子集。我们的大脑中有数十亿个神经元,它们相互发送信号和信息,让我们能够理解周围的环境。深度学习模型利用数据来检测物体、语音、语言,并在没有人类监督的情况下做出决策。
图 1:神经网络的演示(“作者图片”)
对于我们的模型,我们将使用 CNN 或卷积神经网络。简而言之,神经网络由分层包装在一起的人工神经元组成。每一层都由许多神经元组成,这些神经元将图像分解成非常小的部分并寻找模式,这些神经元中的每一个都与下一层中的所有神经元相连,以便它们可以传递它们获得的信息。一层一层地,神经元将所有的碎片放在一起,创建一个有意义的图像(见上面的图 1)。CNN 应用于图像分类问题,好消息是你不必创建任何算法,计算机会为你做所有的计算!
我试图提供这些概念的 10,000 英尺水平的视图,要真正掌握对这些概念的全面理解,我建议您探索大量可用的在线资源和书籍。我可以推荐访问: Fast.ai 这是目前最好的深度学习免费课程之一。虽然该课程是针对那些已经有一些编码经验的人,但它也是新手获得全面理解的一个很好的课程。
功能和限制
我们将要创建的这个模型将是一个很好的练习,可以帮助我们理解这项技术的一些功能和局限性。如前所述,我们将应用 CNN 模型来对 50 美元和 100 美元钞票进行分类,这将需要具有标签的图像形式的数据。模型的效力在很大程度上取决于我们提供的数据。一张钞票有许多复杂的细节,如全息图和只有在紫外光下才可见的特征。这意味着您要么必须拍摄将这些要素纳入视野的照片,要么找到包含这些类型图像的数据集。我没有使用过这样的图片,我将提供我如何创建模型并在网上部署它的说明。但是你已经可以猜到有很多机会让你调整和改进模型,也可以估计一些与这项技术相关的挑战和限制。过多或过少的数据是另一个约束,称为过度拟合,会导致模型效率低下。那么,当您为模型提供与用于训练模型的图像完全不同的图像时,会发生什么呢?该模型在预测方面表现不佳,例如,当使用彩色图像训练模型时,输入黑白图像进行分类可能会突出缺陷。这个模型只能识别它所看到的,或者与相似的图像和物体进行类比。但是,我的模型用我提供的数据取得了显著的效果。理论上的东西说够了,现在让我们开始吧!
设置环境
我提供的指导正是我创建和部署这个模型的方式。还有其他方法可以达到同样的效果。由于这是一个使用深度学习库的深度学习模型,你需要在你的计算机上安装一个 NVIDIA GPU(图形处理单元),但是,我使用并建议使用 GPU 服务器。
- 第一步:创建一个免费的 Paperspace Gradient 账户,按照的指示操作。创建帐户后,为您的项目创建一个 jupyter 笔记本文件夹和一个笔记本文档/IPYNB 文件。
- 第二步:创建一个免费的微软 Azure 账户。一旦帐户被创建,你将得到一个 API 密钥,保存在某个地方以备后用(非常重要!).
下载图片
从上面第 2 步的 Microsoft Azure 帐户中复制 Bing 图像搜索 API 密钥,并将其粘贴到显示将您的 API 密钥粘贴到此处的区域:
注意:您将使用 Bing 图像搜索 API 键来搜索带标签的图像,并将它们下载到您的笔记本上。下载的图像将成为您的数据集。
套餐
使用以下代码导入包:
粘贴您的 API 密钥:
使用以下功能在 Bing 中搜索图像:
使用下面的代码下载 50 美元和 100 美元的图像:
使用以下代码检查您的文件夹,确保其中包含图像文件:
您的输出应该是这样的。
有时,从互联网下载的文件可能会损坏,要检查此类文件,请使用以下代码:
要删除任何失败或损坏的图像,请使用以下代码:
数据加载器&数据块我们下载的图像存储在文件夹中,如您在前面的步骤中所见。为了使这些数据对模型可用,需要创建一个 DataLoaders 对象。DataLoaders 是一个 fastai 类。要将下载的数据转换成 DataLoaders 对象,我们至少需要告诉 fastai 四件事:
我们正在处理哪些类型的数据?如何获取物品清单?这些物品怎么贴标签?如何创建验证集?
为了定制数据加载器,我们将使用称为数据块 API 的东西,下面是使用数据块定制数据加载器的代码(检查代码中的注释,了解每个参数)。
使用以下代码,使用账单数据块指向图像目录:
数据加载器一次成批处理几个项目,并将其提供给 GPU。数据加载器具有培训和验证数据加载器,使用下面的代码查看一些项目:
数据扩充
使用 fastai 函数可以应用多种技术来处理图像,如挤压、填充等。但是这些技术可能会导致关键特征的丢失。例如,如果我们挤压或填充一张 100 美元钞票的图片,可能会导致关键特征的丢失,或者使钞票看起来与实际钞票不同,这反过来会降低模型的准确性。我将只提供我用来创建我的模型的技术。数据扩充是指创建我们输入数据的随机变化,这样它们看起来不同,但实际上并不改变数据的含义。常见的图像数据增强技术的例子有旋转、翻转、透视扭曲、亮度变化和对比度变化。对于自然照片图像,如我们在这里使用的,aug_transforms 函数提供了一套标准的增强功能,效果非常好。因为我们的图像现在都是相同的大小,我们可以使用 GPU 将这些放大应用于整批图像,这将节省大量时间。这里有一个我上面刚刚描述的例子,我们使用 RandomResizeCrop。要传入的最重要的参数是 min_scale,它决定了每次至少要选择多少图像。使用下面的代码查看示例:
我们使用 unique=True 让相同的图像在不同版本的 RandomResizedCrop 转换中重复。这是一个更一般的技术的具体例子,称为数据扩充。对于我们的问题,我们没有太多的数据(每种熊最多 150 张照片),所以为了训练我们的模型,我们将使用图像大小为 224 px 的 RandomResizedCrop,这对于图像分类来说是相当标准的,默认的 aug_transforms:
型号
现在我们已经准备好了数据,我们可以训练和测试我们的模型。我们需要创建一个学习器,它将使用函数 cnn_learner,该函数需要一个数据集,在我们的情况下,它是 dls ,一个架构,我们将使用一个预训练的 18 层神经网络,称为 resnet18 ,以及一个度量,它将是 error_rate,给我们错误分类的百分比。使用下面的代码创建学习者:
现在,您应该会看到如下统计数据:
世
时期是模型通过训练数据的迭代次数。如前所述, error_rate 是我们模型准确性的关键指标(准确性= 1-error_rate)。在最后一次迭代中,error_rate 是 0.096154,这意味着精度是 1–0.096154 = 0.903846 或 90.3% ,这已经很不错了!损失是训练集上的误差。loss 和 error_rate 之间是有区别的,loss 的整个目的是定义一个“性能度量”,训练系统可以使用它来自动更新权重。权重和梯度下降是神经网络的一些重要方面,我可能会在另一篇博客文章中介绍。
注意:您的历元结果可能会有所不同
我们将使用另一种方法来检查模型所犯的错误,我们将使用一个混淆矩阵。使用以下代码运行混淆矩阵:
现在,您应该会看到这样一个矩阵:
“作者提供的图像”
行代表我们数据中的 100 美元和 50 美元,列代表预测。对角线单元给出正确的预测,非对角线单元给出误差。所有 50 美元的预测都是正确的,100 美元的预测有 5 个错误。
使用下面的代码查看模型做出错误预测的图像:
现在,您应该会看到类似这样的内容:
哎呀!一张 100 美元的钞票上有唐纳德·特朗普!难怪模型会出错!
接下来,您可以使用下面的代码选择删除不正确预测的图像:
现在,您应该会看到类似这样的内容:
一旦您决定进行更改、保留或删除图像,请运行以下代码:
将您的模型转化为应用
一旦你成功地完成了上面的所有步骤,你的模型就可以变成任何人都可以访问和使用的实际应用程序了。要将模型转换成应用程序,首先需要将模型导出为**。pkl** 文件。使用下面的代码创建您的。pkl 文件,该文件应该出现在您的项目文件夹中。
现在您已经有了一个训练好的模型和一个. pkl 文件,我们只需要创建一个推理来获得预测。使用下面的代码创建一个推理:
使用下面的代码,通过一个名为 ipywidgets 的 GUI 组件创建一个上传按钮:
执行完代码后,您应该会看到一个上传按钮,如下所示:
上传按钮
您可以使用此上传按钮从您的设备上传图像文件以进行预测。如果你有一张 50 美元或 100 美元的钞票,拍一张照片并从你的电脑上传来测试模型,或者你也可以从互联网上下载随机的 50/100 美元的图片进行测试。只有 50 或 100 美元的图像会产生有意义的结果。使用以下代码显示您上传的图像。
我上传了一张 100 美元的图片,你上传的图片应该是这样的:
要使用标签获得图像的预测,请使用以下代码:
输出应该是这样的:
模型预测我上传的图片是 100 美元,准确率 94.78%!万岁!这个模型起作用了,现在它变成了一个应用程序!下一步是安装 voila ,voila 是一个 python 库,它通过隐藏代码单元,只显示小部件按钮和输出,将 jupyter 笔记本转换为 web 应用程序。使用以下代码安装 voila:
将笔记本转换成网络应用
成功完成上述步骤后,打开一个新的 jupyter 笔记本文档,只使用下面的代码。代码只包含创建应用程序所必需的内容,即小部件、事件处理程序、调用。pkl 文件,一个 vbox,将小部件和输出放在一起。我使用 markdown 文本来描述我的应用程序,使用以下代码来创建您的应用程序:
部署
完成上述所有步骤后,您就可以与全世界分享您的应用程序了!也可以免费做。这个应用程序将只在我的指示桌面上工作,而不是在智能手机上。按照以下步骤进行部署:
- 创建一个 GitHub 库。
- 将笔记本(包含应用程序的笔记本)添加到您的 Git 存储库中。
- 添加。pkl 文件并创建一个需求文件。
- 导航到活页夹将所有东西放在一起。
- 将文件下拉列表改为选择 URL。
- 在“要打开的 URL”字段中,输入
/voila/render/name.ipynb
(用笔记本的名称替换name
)。 - 单击右下角的点击板按钮复制 URL 并粘贴到安全的地方。
- 单击启动。
注意:binder 构建和启动需要一段时间
我希望你喜欢我的帖子,并祝贺你建立了一个深度学习模型并部署它!!
我想引用史蒂夫·乔布斯的一句话来结束这篇文章——“保持饥饿”。呆呆
参考资料:
fast.ai
免费在云上构建一个简单的零停机 NLP web 应用程序
原文:https://towardsdatascience.com/build-a-simple-zero-downtime-nlp-web-application-on-cloud-for-free-50d9e4f3f9c4?source=collection_archive---------50-----------------------
为了检测输入消息的情感和得分
腾雅特在 Unsplash 上拍摄的照片
背景
让我们先快速看一下我的原型做了什么:
图片由作者制作,gif(内)由 QooBee 制作,图标(内)由 Pixel perfect 制作
本文将关注我们如何将这个基于情感分析的 NLP web 应用程序部署到云中。如何为这个项目构建 NLP 模型的深入主题将在以后的文章中讨论。该模型是使用以下数据源和模型构建的。
来源数据:来自 twitter api 的 1,600,000 条标签推文
型号:后勤补给
文本矢量器:哈希矢量器
介绍
先决条件
- 一个免费的 Heroku 账号https://www.heroku.com/free—强烈推荐获得验证以免费获得1000 小时/月,这允许您的单个应用程序零停机,因为只有大约 740 小时/月。
- 一个免费的 cron-job 帐户https://cron-job.org/en/——设置一个定期唤醒 web 应用程序的作业。
- Python 和 web 框架的基础知识(GET/POST)。
脚本架构
脚本架构
脚本文件的功能
Heroku 相关文件的功能
部署
1.从我的 Github 资源库链接的 medium-article 分支下载资源库:https://Github . com/cmy 113/sensation-analysis-project/tree/medium-article
2.登录https://dashboard.heroku.com/apps并创建一个新应用。输入您唯一的应用程序名称,并选择离您最近的地区。
从 Heroku 创建新应用
从 Heroku 创建新应用
3.使用以下链接在本地下载并安装 Heroku CLI:https://devcenter.heroku.com/articles/heroku-cli
4.导航至应用程序的部署部分,并遵循使用 Heroku Git 部署中的说明
Heroku 从 Heroku 部署
登录 heroku,导航到您在步骤 1 中从 Github 下载的项目目录,初始化 git,定义远程分支,添加所有文件,提交并最终推送到 Heroku
从 Heroku 使用 Heroku CLI
如何使用 Heroku CLI 进行部署
5.web 应用程序现在已经启动并运行,让我们导航到该网站,看看它是否按预期工作。
图片由 Heroku 和作者制作,gif(内)由 QooBee 制作,图标(内)由 Pixel perfect 制作
8.[可选]还记得我们提到过我们想要一个零停机应用吗?为了实现这一点,我们需要定期唤醒 web 应用程序,因为 Heroku 会在应用程序 30 分钟不活动后让其进入睡眠状态。当然,这将消耗你 24*31 = 744 小时的免费 dyno 小时。如果您想使用免费的 dyno 小时构建不同的 web 应用程序,请跳过这一步。
登录到https://cron-job.org/en/。单击 CREATE CRONJOB 并输入以下内容:
从 cron-job.org创建克朗乔布
然后,我们可以看到,根据历史记录,GET 请求被成功执行
cron-job.org 的克朗乔布历史
9.搞定了。耶!我们设法以零成本构建零停机 NLP web 应用程序并将其部署到云中!
你能进一步修改什么
因此,在快速了解了如何部署示例 NLP web 应用程序之后,下一个问题是:**如何从中获得更多的好处?**你可以使用这个库作为你现有 NLP 项目的启动,或者你可以在它的基础上修改额外的 5 东西:
- 将 Heroku 应用与 GitHub 集成,可以在 GitHub 上forkmyrepository并与 Heroku 同步。注意,我在本文的演示中使用了中型文章分支,我可能会对我的主分支做一些不定期的更新。
在 Heroku 中,您可以启用自动化部署,从而允许您在每次推送至 Github 存储库时重新创建 web 应用程序!我觉得这很神奇!:)
来自 Heroku 的 Github 和 Heroku 之间的集成
2.你需要在你的本地环境中安装一个虚拟环境来本地修改/测试我现有的代码。您可以按照下面概述的示例步骤来创建所需的虚拟环境。
# Assume you have installed python 3 in your local environment
# I am using python 3.8.5 for this project but the project should work for any version of 3.8
# Can refer to this tutorial here as well on how to create virtual env [https://www.youtube.com/watch?v=N5vscPTWKOk](https://www.youtube.com/watch?v=N5vscPTWKOk) # Identify where your python3 path is
# e.g. /usr/local/bin/python
which python# Install virtualenv package
pip install virtualenv# Navigate to home directory
# Create an Environments directory that stores all your virtual environment
# Navigate to Environments directory for the next step
cd
mkdir Environments
cd Environments # Create an empty virtualenv named sentiment-analysis-project
virtualenv -p /usr/local/bin/python sentiment-analysis-project# Activate the virtual environment
source sentiment-analysis-project/bin/activate # Navigate to downloaded project repository from Github
# Install project dependency from requirements.txt in the virtual environment
cd Downloads/sentiment-analysis-project-medium-article
pip install -r requirements.txt# You might need to download wordnet from nltk if you have not done it before. Open python terminal and run below command:
# python
# import nltk
# nltk.download('wordnet')
# Please follow this if you have trouble installing the nltk dataset
[https://stackoverflow.com/questions/38916452/nltk-download-ssl-certificate-verify-failed](https://stackoverflow.com/questions/38916452/nltk-download-ssl-certificate-verify-failed)# Finally trigger the application
python wsgi.py# Yay! Time to test/modify the code based on your liking and requirement
您应该能够通过访问http://127 . 0 . 0 . 1:5000/在本地访问 web 应用程序
3.根据您希望如何预处理您的输入文本来编辑 model.py ,因为该项目主要关注 Twitter 风格的数据。您也可以更改我最初使用的矢量器 TfidfVectorizer ,但是我在将它部署到 Heroku 时遇到了问题,因为大量的词汇导致了 Heroku 自由层版本的内存过载。使用哈希矢量器将会克服这个限制。
4.将静态文件夹中的logisticregression . pickle文件替换为您自己的模型文件,并在本地/Heroku web 应用程序中测试其相应的输出。请注意,并非所有模型都像逻辑回归一样提供概率得分。我的模型基于 160 万 Twitter 数据集,目前的精度大约是 0.81 (还有很大的提升空间!).
5.通过编辑 css/html 文件,集成 Bootstrap 以及根据您的喜好更改图像/gif/图标,改善网络可视化。我保持了简单的设计,这样任何人都可以很容易地理解代码,并进一步轻松地修改可视化。
结论
我真诚地希望这篇文章能够帮助那些已经在情感分析的基础上构建了自己的自然语言处理(NLP)模型,但是不知道如何可视化地部署它的人(我在学习 NLP 的时候就忽略了这一点)或者那些渴望了解如何免费部署一个基本的、长期运行的 web 应用程序的人**!我还会让我的应用程序在https://cmy-sentiment-analysis.herokuapp.com运行,这样任何人都可以随时访问它!我尽最大努力保持我的代码库相对干净和简单**,并添加了大量评论,因此任何对 Python/web 框架了解有限的人都应该能够很快学会!如果你觉得这篇文章有用,或者对我有任何改进的建议,请在下面评论。干杯!
使用语义搜索构建更智能的聊天机器人
原文:https://towardsdatascience.com/build-a-smarter-chatbot-with-semantic-search-323c9a77a31d?source=collection_archive---------19-----------------------
来源: VectorStock
使用语义搜索引擎,你可以不费吹灰之力扩大聊天机器人的覆盖范围。
不太久以前,聊天机器人和助手并不好用。像亚马逊 Alexa 这样的公司是由拥有大量 R&D 预算和专业 ML 和 NLP 团队的公司开发的。
但由于 2017 年推出变压器后 NLP 系统性能的飞跃,加上许多这些模型的开源性质,前景正在迅速改变。像 Rasa 这样的公司使得组织可以轻松地构建复杂的代理,这些代理不仅比早期的代理工作得更好,而且只需要很少的时间和金钱来开发,并且不需要专家来设计。
然而,尽管最近取得了一些进步,但仍有很大的改进空间。在本文中,我们将展示如何通过将客户助手聊天机器人附加到语义搜索后端来扩展它,以处理更广泛的查询。
亚特兰蒂斯迪拜的基本聊天机器人
当迪拜的亚特兰蒂斯酒店于 2008 年开业时,它的水下套房迅速获得了全世界的关注。今天,他们的网站为潜在访问者列出了一百多个常见问题。出于我们的目的,我们将使用 Rasa 构建一个聊天机器人来处理关于这些主题的查询。
你可能想知道 Rasa 聊天机器人提供了什么优势,而不是简单地访问网站的 FAQ 页面。第一个主要优点是,它对查询给出了直接的回答,而不是要求客户浏览一大串问题。
其次,与 Ctrl-F 搜索相比,Rasa 可以更智能地找到内容。凭借 NLP 模型的支持,它可以优雅地处理拼写错误和释义错误。例如,如果我问“允许我的狗吗”,Rasa 给我下面的结果,而 Ctrl-F 搜索“狗”将不会返回任何结果,因为常见问题是你允许在迪拜亚特兰蒂斯养宠物吗?
我们的机器人的源代码可以在github.com/amin3141/zir-rasabot获得,最终版本部署在我们的演示页面。下面的文件提供了使用 Rasa 创作语法的核心知识库实现。
- nlu.yml ,包含常见问题及其变体。
- domain.yml ,包含意图的响应和声明。
- rules.yml ,将 nlu.yml 中定义的意图映射到 domain.yml 中定义的响应。
顾客评论:一个未开发的信息源
随着互联网和在线电子商务的兴起,客户评论是在线景观的普遍元素。评论包含各种各样的信息,但因为它们是以自由形式的文本编写的,并且是用客户自己的话来表达的,所以要访问其中的知识并不容易。
亚特兰蒂斯酒店有数千条评论,其中 326 条包含在 OpinRank 评论数据集中。在其他地方我们展示了语义搜索平台,如 Vectara Neural Search ,如何让组织利用存储为非结构化文本的信息——大规模释放这些数据集中的价值。
Rasa 包含一个称为后备处理器的便利特性,我们将使用它来扩展我们的语义搜索机器人。当机器人没有足够的信心直接处理请求时,它会将请求交给后备处理程序来处理。在这种情况下,我们将针对客户评论语料库运行用户查询,如果结果得分足够高,将显示最多两个匹配项。回退处理程序的源代码可以在 main/actions/actions.py 中找到。第41–79行显示了如何准备语义搜索请求、提交请求以及处理结果。
我们如何确定机器人不够自信?为了本文的目的,我们作弊了:我们直接根据评估数据计算了我们的选择指标 F1 得分,并选择了一个最大化它的阈值。虽然这并不妨碍我们从评估结果中得出结论,但我们必须记住,基线聊天机器人被赋予了不切实际的优势。
我们还使用阈值 0.3 来确定语义搜索回退结果是否足以显示。至关重要的是,这个阈值是从一个不相关的数据集获得的。因此,我们希望我们的指标能够准确反映现实世界的表现。
比较机器人
复杂系统的性能必须进行概率分析,NLP 驱动的聊天机器人也不例外。缺乏严格的评估将会使你很难确信当你扩展你的系统时你正在取得进步。本节的其余部分描述了我们评估聊天机器人的方法。
首先,我们构建了一个包含 63 个问题的评估集。在预订房间之前,我们询问了五位以前住过酒店的人,他们可能有兴趣了解迪拜亚特兰蒂斯酒店的哪些问题。提示中有几个要点需要注意:首先,它介绍了迪拜酒店的位置,以考虑到地理上相关的问题,如*它离海滩有多远?*其次,它还设定了一个目标,这个目标首先符合构建这样一个机器人的现实商业动机,也就是说,帮助潜在客户决定这是否是他们愿意呆的地方。
为了表征机器人的性能,我们从标准的四类答案分类开始,这对于以前使用过 ML 系统的人来说是熟悉的:
- 正确答案:聊天机器人正确回答了这个问题。在我们的评估中,单个评估员做出了决定,尽管如果您的预算允许,使用多个评估员更可靠。
- 误报:聊天机器人回答问题不正确。
- 假阴性:聊天机器人拒绝回答一个合法的问题。当系统回复很抱歉,我没有这方面的任何信息时,这种情况就会出现。
- 真否定:描述聊天机器人避免回答不合理问题的情况,例如,马里纳拉海沟有多深?然而,真正的否定在我们的数据集中并不存在,因为所有的问题都是切题的。
使用这些类,我们将计算精度,这是正确回答的已回答问题的比例,以及真实肯定率,也称为召回率,这是可以正确回答的有效问题的百分比。以下公式表达了这一点:
精确度和真阳性率公式。
为了用一个数字来描述系统的性能,我们将转向 F 值。下面等式中的系数β表示真实阳性率被认为比精度重要β倍。应选择β,以准确反映与假阳性和假阴性结果相关的相对成本。
F 分数的公式
总结和分析
来自默认聊天机器人和启用了回退的聊天机器人的回答被评估并分类如下:
- 默认值:(TP=7,FP=7,TN=0,FN=49)
- 回退:(TP=29,FP=24,TN=0,FN=10)
下图显示了他们在上述指标上的相对表现。
最大的改进是聊天机器人的真实阳性率。在现实问题的评估集上,聊天机器人的正确回答率从 13%上升到了 74%。这也使 F1 得分从 20%提高到 63%。最重要的是,这种改进是通过语义搜索访问现有评论轻松实现的。
精度呢?令人惊讶的是,它似乎也有所改善,从 50%上升到 55%。然而,90%的置信区间清楚地表明,这种差异完全在误差范围内,无法得出任何结论。需要产生更多真阳性和假阳性的更大的问题集。如果没有这个时间间隔,就很难得出这个结论。一个很好的经验法则是,对没有置信区间的统计数据要非常怀疑。
我们已经走到路的尽头了吗?我们能像一位前美国总统曾经做过的那样,宣布“任务完成了吗!”在我们的例子中,就像在他的例子中一样,答案是,没那么快!在本文的最后一部分,我们将讨论在聊天机器人中添加语义搜索时应该考虑的其他一些事情。
总结挑战
顾客评论可能会提到与官方政策不一致的事实。例如,如果顾客询问结账时间,信息性评论可能会说的结账时间是上午 10 点,但我下午 1 点就离开了,这不是问题。因此,机器人需要弄清楚什么时候它在权威地回答,什么时候它在第二手资料中寻找答案。一种方法是以这样的陈述开始搜索结果,比如下面是其他客户不得不说的:
如果顾客问亚特兰蒂斯酒店的房间是否干净呢?管理层会希望机器人成为志愿者吗地毯发臭,墙上有蟑螂在跑!很难想象,即使评论是准确的。定期检查回退处理程序产生的响应是确保这些情况不会发生的一种方法。另一个是从语料库中过滤出负面评论。
注释者之间的协议
当我们评估我们的聊天机器人时,我们将每一个回答分为真或假、肯定或否定。这个任务被称为注释,在我们的例子中,它是由团队中的一个软件工程师执行的。几乎可以肯定的是,如果你让另一个人来注释这些回答,结果将是相似的,但不完全相同。
出于这个原因,包含多个注释者并跟踪它们之间的一致程度是一个好的实践。注释者的分歧也应该反映在我们度量的置信区间中,但是这是另一篇文章的主题。
资源和引用
- 启用了回退功能的 Hotel Atlantis 聊天机器人。
- 所有 63 个问题的评估结果
- 关键词搜索的高成本包括一个教程,展示如何将客户评论上传到 Vectara Neural Search。
- Rasa 利用最新的语言理解技术构建对话系统。
- 甘乃山,K. A .和翟春祥,“基于观点的实体排名”,信息检索,2011 年。
阿明·艾哈迈德是 Vectara 的联合创始人。聊天机器人是由 Basit Anwer 开发的。
使用 Gretel.ai 和 Apache Airflow 构建合成数据管道
原文:https://towardsdatascience.com/build-a-synthetic-data-pipeline-using-gretel-ai-and-apache-airflow-a99f1773112f?source=collection_archive---------25-----------------------
现实世界中的数据科学
在这篇博文中,我们使用 Gretel 的合成数据 API和Apache air flow构建了一个从 PostgreSQL 数据库生成合成数据的 ETL 管道
照片由seli̇m·阿尔达·埃尔伊尔马兹在 Unsplash 上拍摄
嗨,伙计们,我叫德鲁,我是一名软件工程师,在 Gretel.ai 。我最近一直在思考将 Gretel API 集成到现有工具中的模式,这样就很容易建立数据管道,安全和客户隐私是第一位的特性,而不仅仅是事后的想法或检查框。
数据工程师中流行的一个数据工程工具是 Apache Airflow。这也正好与 Gretel 的工作很好。在这篇博文中,我们将向您展示如何使用 Airflow、Gretel 和 PostgreSQL 构建一个合成数据管道。让我们跳进来吧!
什么是气流?
Airflow 是一个常用于构建数据管道的工作流自动化工具。它使数据工程师或数据科学家能够使用 Python 和其他熟悉的构造以编程方式定义和部署这些管道。气流的核心是 DAG 或有向无环图的概念。气流 DAG 提供了用于定义管道组件、它们的依赖性和执行顺序的模型和一组 API。
您可能会发现气流管道将数据从产品数据库复制到数据仓库。其他管道可能会执行查询,将规范化的数据连接到适合分析或建模的单个数据集。另一个管道可能发布汇总关键业务指标的每日报告。这些用例有一个共同的主题:协调跨系统的数据移动。这是气流闪耀的地方。
利用 Airflow 及其丰富的集成生态系统,数据工程师和科学家可以将任意数量的不同工具或服务整合到一个易于维护和操作的统一管道中。了解了这些集成功能后,我们现在将开始讨论如何将 Gretel 集成到气流管道中,以改善常见的数据操作工作流。
格雷特尔是怎样融入的?
在 Gretel,我们的使命是让数据更容易、更安全地使用。在与客户交谈时,我们经常听到的一个痛点是让数据科学家访问敏感数据所需的时间和精力。使用 Gretel Synthetics ,我们可以通过生成数据集的合成副本来降低使用敏感数据的风险。通过将 Gretel 与 Airflow 集成,可以创建自助管道,使数据科学家可以轻松快速地获得他们需要的数据,而不需要数据工程师来处理每个新的数据请求。
为了演示这些功能,我们将构建一个 ETL 管道,从数据库中提取用户活动特征,生成数据集的合成版本,并将数据集保存到 S3。随着合成数据集保存在 S3,它可以被数据科学家用于下游建模或分析,而不损害客户隐私。
首先,让我们来鸟瞰一下管道。该图中的每个节点代表一个管道步骤,或气流术语中的“任务”。
气流上的格雷特合成材料管道示例。(图片由作者提供)
我们可以将管道分成 3 个阶段,类似于 ETL 管道:
- 提取—
extract_features
任务将查询数据库,并将数据转换为一组数据科学家可以用来构建模型的特征。 - 合成—
generate_synthetic_features
将提取的特征作为输入,训练一个合成模型,然后使用 Gretel APIs 和云服务生成一组合成的特征。 - 加载——
upload_synthetic_features
将综合特征集保存到 S3,在那里它可以被摄取到任何下游模型或分析中。
在接下来的几节中,我们将更详细地探讨这三个步骤。如果你想了解每个代码示例,你可以去grete lai/Gretel-air flow-pipelines下载这篇博文中用到的所有代码。repo 还包含启动 Airflow 实例和端到端运行管道的说明。
此外,在我们剖析每个组件之前,查看完整的气流管道可能会有所帮助。以下部分中的代码片段摘自链接用户预订管道。
提取特征
第一个任务extract_features
负责从源数据库中提取原始数据,并将其转换成一组特征。这是一个常见的特征工程问题,你可能会在任何机器学习或分析管道中发现。
在我们的示例管道中,我们将提供一个 PostgreSQL 数据库,并加载来自 Airbnb Kaggle 竞赛的预订数据。
这个数据集包含两个表,Users
和Sessions
。Sessions
包含一个外键引用user_id
。利用这种关系,我们将创建一组包含由用户聚合的各种预订指标的特性。下图显示了用于构建要素的 SQL 查询。
然后从我们的气流管道执行 SQL 查询,并使用以下任务定义将其写入中间 S3 位置
任务的输入sql_file
决定了在数据库上运行什么样的查询。该查询将被读入任务,然后对数据库执行。然后,查询结果将被写入 S3,远程文件密钥将作为任务的输出返回。
下面的屏幕截图显示了上面提取查询的示例结果集。我们将在下一节描述如何创建该数据集的合成版本。
查询结果预览。(图片由作者提供)
使用 Gretel APIs 合成特征
为了生成每个特征的合成版本,我们必须首先训练一个合成模型,然后运行该模型来生成合成记录。Gretel 有一组 Python SDKs,可以很容易地集成到 Airflow 任务中。
除了 Python 客户端 SDK,我们还创建了一个 Gretel Airflow Hook 来管理 Gretel API 连接和秘密。设置好 Gretel 气流连接后,连接到 Gretel API 就像
有关如何配置气流连接的更多信息,请参考我们的 Github 知识库自述文件。
上例中的project
变量可以用作使用 Gretel 的 API 训练和运行合成模型的主要入口点。更多细节可以查看我们的 Python API 文档,https://Python . docs . Gretel . ai/en/stable/projects/projects . html。
回到预订管道,我们现在来回顾一下generate_synthetic_features
任务。此步骤负责使用前一任务中提取的特征来训练合成模型。
查看方法签名,您会看到它需要一个路径,data_source
。该值指向上一步中提取的 S3 要素。在后面的部分中,我们将介绍所有这些输入和输出是如何连接在一起的。
当使用project.create_model_obj
创建模型时,model_config
参数代表用于生成模型的合成模型配置。在这个管道中,我们使用我们的默认模型配置,但是许多其他的配置选项也是可用的。
模型配置好之后,我们调用model.submit_cloud()
。这将使用 Gretel Cloud 提交用于训练和记录生成的模型。调用poll(model)
将阻塞任务,直到模型完成训练。
现在模型已经训练好了,我们将使用get_artifact_link
返回一个链接来下载生成的合成特征。
合成集特征的数据预览。(图片由作者提供)
这个工件链接将被用作最终upload_synthetic_features
步骤的输入。
加载合成要素
原始特征已经被提取,并且已经创建了合成版本。现在是上传合成特性的时候了,这样下游消费者就可以访问它们了。在本例中,我们将使用 S3 桶作为数据集的最终目的地。
这项任务非常简单。data_set
输入值包含一个签名的 HTTP 链接,用于从 Gretel 的 API 下载合成数据集。该任务将把该文件读入 Airflow worker,然后使用已经配置好的 S3 钩子把合成特征文件上传到 S3 桶,下游消费者或模型可以访问它。
协调管道
在过去的三个部分中,我们已经浏览了提取、合成和加载数据集所需的所有代码。最后一步是将这些任务捆绑到一个单独的气流管道中。
如果你还记得这篇文章的开头,我们简要地提到了 DAG 的概念。使用 Airflow 的 TaskFlow API,我们可以将这三个 Python 方法组合成一个 DAG,该 DAG 定义了输入、输出以及每个步骤的运行顺序。
如果您遵循这些方法调用的路径,您最终会得到一个看起来像我们的原始特性管道的图。
气流上的格莱特合成纤维管道。(图片由作者提供)
如果你想运行这个管道,并看到它的运行,那就去 Github 仓库的看看吧。在那里,您可以找到关于如何启动一个 Airflow 实例并端到端运行管道的说明。
包装东西
如果您已经做到了这一步,那么您已经看到了如何将 Gretel 集成到基于气流的数据管道中。通过结合 Gretel 的开发人员友好的 API 和 Airflow 强大的钩子和操作符系统,很容易构建 ETL 管道,使数据更容易访问,使用起来更安全。
我们还讨论了一个常见的特性工程用例,其中敏感数据可能不容易访问。通过生成数据集的合成版本,我们降低了暴露任何敏感数据的风险,但仍然保留了数据集的效用,同时使需要它的人可以快速获得它。
从更抽象的角度来考虑特性管道,我们现在有了一个可以重新用于任何数量的新 SQL 查询的模式。通过部署新版本的管道,并替换初始 SQL 查询,我们可以用保护客户隐私的合成数据集来处理任何潜在的敏感查询。唯一需要更改的代码行是 sql 文件的路径。不需要复杂的数据工程。
感谢阅读
如果您有任何问题或意见,请发送电子邮件至 hi@gretel.ai 或加入我们的 Slack 。我们希望了解您如何使用 Airflow,以及我们如何才能最好地与您现有的数据管道集成。
用 Python 构建文本推荐系统
原文:https://towardsdatascience.com/build-a-text-recommendation-system-with-python-e8b95d9f251c?source=collection_archive---------4-----------------------
使用 NLP 语义相似度来提供最准确的推荐
丹尼斯·詹斯
自然语言处理是机器学习中最令人兴奋的领域之一。它使我们的计算机能够理解非常密集的语料库,分析它们,并为我们提供我们正在寻找的信息。
在本文中,我们将创建一个推荐系统,其行为类似于一个垂直搜索引擎*【3】。它允许在非常有限的与一个主题高度相关的文档中搜索文档。为了充分利用 NLP 的能力,我们将把搜索方法与语义相似性结合起来。*
本文包括不同 NLP 模型的数据集、理论、代码和结果。
为什么要用机器学习?
- 机器学习和深度学习擅长提供捕捉单词和文档语义的文本数据的表示,允许机器说出哪些单词和文档语义相似。深度学习的使用能够为其最终用户提供更多相关结果,提高用户满意度和产品功效。在本文中,我们将致力于一个为您的数据量身定制的解决方案,并且稍后可以将您的数据与用户查询进行比较,以提供排名良好的结果。
- 对于大多数常见的编程语言,如 Python,许多开源库提供了工具,可以在您自己的数据上创建和训练非常简单复杂的机器学习模型。在本文中,我们将看到在您自己的机器上构建和训练模型有多快。
用例
想象一下,你想看一部电影,但你已经看完了遗愿清单上的所有电影。今天你想看一部电影,里面一个美丽的女人卷入了一场犯罪。我们将建立的推荐系统会将您理想的电影描述与电影描述数据库进行匹配,并推荐符合您描述的前三部电影。
这非常简单,要构建这个管道,您需要:
- 包含要推荐的文本项集合的数据集。
- 一种句子清洁算法
- 匹配算法。
我们来编码吧!
您可以在 jupyter 笔记本中访问本文的所有代码。
j .凯利·布里托
准备数据
作为查找表的数据集
对于这个玩具实验,我们使用电影数据集https://www.kaggle.com/rounakbanik/the-movies-dataset。
它包含 2017 年 7 月之前发布的 44,512 部电影的元数据。幸运的是,我们不会全部观看,因为我们会选择符合我们确切愿望的一个。
在我们的实验中,我们将只使用表“movies_metadata.csv ”,它包含的属性有:预算、流派、网页链接、 原标题、描述概述 、上映日期、口语、IMDb 平均投票、…。
我们的推荐系统将使用电影描述概述句子,并应用机器学习模型将每个句子表示为数字特征向量。在将 ML 模型应用于每个句子之后,我们可以连接这些特征向量来创建代表整个数据集的嵌入矩阵。这个矩阵非常重要,它将是我们对系统进行的每个查询的查找表。
作者图片
假设我们有 100 个电影描述句子,我们的嵌入向量大小是 300,那么我们的嵌入矩阵大小将是(100×300)。当用户输入一个句子时,我们使用相同的模型将其查询句子嵌入到 300 维向量中,并计算 100 行中的每一行与嵌入的查询向量之间的余弦距离。
加载数据集
下载。csv 文件,并将其作为数据框加载到 python 脚本或笔记本中。
干净的句子
我们会做基本的预处理。我们希望给模型一个统一的文本,所以我们在将句子嵌入向量之前对它们进行清理。这将有助于模型关注内容而不是格式来找到数据中的相关模式。
让我们回顾一下下面的清洁方法。
- 删除非字母数字字符/标点符号,
- 删除太长和太短的句子,
- 删除停用词,
- lemmatize,
- 标记化
我们使用正则表达式模式匹配从电影描述中删除所有非字母数字字符。
我们创建自己的记号赋予器。记号赋予器将一个字符串转换成一个字符串列表,其中每个元素是一个单词。
*word_tokenizer(‘the beautiful tree has lost its leaves’)
>>> [‘the’, ‘beautiful’, ‘tree’, ‘has’, ‘lost’, ‘its’, ‘leaves’]*
我们使用一个词条解释器将一个单词转换成通用形式:
*from nltk.stem import WordNetLemmatizer
stemmer = WordNetLemmatizer()
[stemmer.lemmatize(w) for w in word_tokenize(sentence)]
>>> ['the', 'beautiful', 'tree', 'ha', 'lost', 'his', 'leaf']*
我们通过使用最小单词和最大单词进行过滤,从数据集中删除太短和太长的句子。我们去掉了对提取给定句子的特殊性没有帮助的常用词(停用词)。
清洁的结果
我们将“句子”列转换为两列:
- clean_sentence 这里的句子主要是字母数字文本。
- tok_lem_sentence 其中数据被词汇化和标记化。
加载、训练、预测
现在,我们的数据集已准备好进行处理,我们可以比较提供不同折衷方案的不同模型:
- 基准/基本 TF-IDF
- ***Word2Vec,*一个简单的前馈网络
- 非常灵活和强大的 NLP 库
- 变形金刚,最先进的深度学习模型。
我在下面介绍一个函数,在给定向量之间的余弦距离的情况下,我将使用该函数对最佳推荐进行排序。
你可以注意到在 l.11 中,我们在距离矩阵上使用了平均值。距离矩阵的形状是(查询句子中的字数,我们的词汇表中的句子数)。我们计算从查询的每个单词到数据库的每个句子的距离,并取整个查询的平均值。然后我们可以选择与查询距离最小的三个句子。
基准模型,TF-IDF
什么是 TF-IDF?
文本语料库通常包含经常出现的单词,并且不包含任何有用的歧视性信息。Tf-idf 旨在降低这些频繁出现的单词在特征向量中的权重。它可以被定义为术语频率(一个词在给定文档中的频率)和逆文档频率(该词在所有文档中的出现次数)的乘积1。术语频率/文档频率测量术语在给定文档中的相关性。在我们的例子中,一个文档就是一个句子。
应用 TF-IDF
一旦我们在 Tf-idf 模型上拟合我们的数据,我们可以为每个电影描述生成嵌入的 22,180 维向量。这些特征存储在特征矩阵 tfidf_mat 中,其中每一行都是嵌入到特征向量中的电影描述记录。
当我们从用户输入中获得一个查询时,我们将把它嵌入到相同的向量空间中,并且我们将逐个比较查询句子特征 embed_query 和嵌入矩阵 tfidf_mat 的句子向量。
从距离矩阵中找到最佳索引的函数取每个嵌入句子的余弦距离的平均值,并对结果进行排序。暂时不要注意掩蔽参数,我们将把它用于另一个模型。
这个模型使用起来非常简单,只需要几行代码就可以完成,训练也非常快。
关于疑问句:'一个有美女的犯罪故事',
前 3 名结果
-一个美丽的吸血鬼把一个犯罪头目变成了夜行动物。无辜的血
-一个吸血鬼引诱年轻漂亮的女人到他在欧洲的城堡。吸血鬼安魂曲
-一个年轻女子在被有组织犯罪控制的墨西哥坚持梦想成为选美皇后的故事。巴拉小姐。
你的数据模型,Word2Vec
Word2Vec 是一个强大而高效的算法,可以捕捉你语料库中单词的语义。Word2vec 在训练期间采用包含许多文档/句子的语料库,并输出一系列向量,文本中的每个单词一个向量。单词向量包含该单词的语义,这意味着在向量空间中接近的两个单词具有相似的含义。国王和王后就像蛋糕和咖啡一样亲密。例如,Word2Vec 可以很容易地用于查找同义词。在训练期间,神经网络根据从训练数据集中推断的出现概率对每个词向量进行加权。这个概率是如何计算的取决于你选择的架构(连续单词包或跳格)。最后,word2vec 模型实际上是一个非常简单的 2 层神经网络,但我们不会关心输出,我们将提取信息编码的隐藏状态[3]。word2vec 的优势在于它采用高维稀疏单词表示(如 tf-idf 或 hot encoded vectors ),并将其映射为密集表示,希望在更小的维度中。
应用 word2vec
我们使用 gensim 库在我们的语料库数据上训练一个 word2vec 模型。我们首先需要提供词汇表(我们要向量化的单词列表),然后在几个时期内训练模型。默认情况下,模型训练 CBOW。
Word2Vec 的主要缺点是它不能为最初不在词汇表使用训练中的单词生成向量。这就是为什么我们需要提供一个 utils 函数 is_word_in_model 来从查询语句中删除在训练集中看不到的单词。
我们使用他们的库函数 n_similarity 来有效地计算查询语句和数据集语句之间的距离。
前 3 名结果
- A tragic love story set in contemporary Shanghai. The film stars Zhou Xun in a dual role as two different women and Jia Hongsheng as a man obsessed with finding a woman from his past. 苏州河
-一个发光的球体用一系列黑暗幻想、色情和恐怖的故事恐吓一个年轻的女孩。重金属。
-弗里茨·兰的心理惊悚片讲述了一个女人嫁给了一个有致命嗜好的陌生人,通过他们的爱,他试图摆脱他的强迫症行为。门外的秘密
很好的妥协模式,斯帕西
spaCy 是一个 python 开源库,包含许多针对各种语言的预先计算的模型(参见 64+语言列表这里)。因为我们需要加载与每个单词相关的向量,所以我们使用一个经过训练的管道来访问特征向量,即 en_core_web_lg 。他们将其 NN 称为 Tok2Vec,我们可以使用包含 685k 个关键字的预训练权重作为在网页语料库上训练的 685k 个维度 300 的唯一向量。SpaCy 有自己的深度学习库和模型。你可以在这里阅读更多关于他们默认的 CNN+散列嵌入模型。他们的管道包括记号化器、词汇化器和单词级矢量化,所以我们只需要提供字符串形式的句子。
我们使用掩码 l.12,以防该单词在预训练的语料库中没有单词。
前 3 名结果:
就算预计 spaCy 比 TF-IDF 更厉害,对于这句话,给出的结果也和 TF-IDF 一样。
最强大的变形金刚
如果我们想要一个鲁棒且准确的方法,我们可以使用深度学习。幸运的是,许多图书馆已经发布了他们自己的预训练权重,我们不需要花几个月的时间在整个互联网上训练一个非常深入的模型。
我们将使用伯特建筑。成本高于以前的模型,但对环境的理解也更加敏锐。
变形金刚库
' SentenceTransformers '团队开发了他们自己的高级管道,以方便在 Python 中使用变压器。你可以点击查看他们的车型和推荐列表。我个人选择了满足 高质量的快速模型-MiniLM-L6-v2。
前 3 名结果
-一个年轻女子在被有组织犯罪控制的墨西哥坚持梦想成为选美皇后的故事。巴拉小姐。
-在一名年轻女子在她的邻居中被可怕地谋杀后,一名生活在纽约市的自决女子-好像是在测试她自身安全的极限-将自己推进了一场不可思议的冒险性关系。很快,她变得越来越警惕与她接触的每个男人的动机,以及她自己的动机。在切口处。
-一个奋斗中的美国艺术家和一个美丽的中国香港妓女之间的爱情故事。苏丝黄的世界
与以前的模型相比,我们可以看到结果的改进。
用 HuggingFace 编写自己的 BERT 管道
SentenceTransformer 在后端使用 HuggingFace 架构。HuggingFace 作为 NLP 技术的开源提供商领导着这项研究。他们免费公开模型、数据集和代码库。任何人都可以训练他们的模型并将结果推送到他们的数据库中。
我们将使用标记化器(AutoTokenizer)和模型(AutoModel)来检索句子-transformer/ 释义-MiniLM-L6-v2 。
我们可以选择在 CPU 或 GPU 上训练,我们使用 fit_transform 使用一批数据来生成我们的嵌入矩阵,以避免内存过载。再次在转换方法中,我们使用 mean_pooling 函数来推断每个单词的向量,并对每个句子进行平均。这种汇集比以前更复杂,因为 BERT 中的注意机制使用掩码,我们在平均之前将它们应用于结果。
代码比我们使用 SentenceTransformer 时稍长,但我们也有更多的灵活性。我们需要设计自己的推断方法也更加透明
训练和预测(CPU 或 GPU)
训练需要时间,所以如果你有 GPU,用它来加快你的训练。对于这个数据集,在我的 16Gb 8 CPUs 本地计算机上,对 20,000 个句子行的训练在 CPU 上花费了12 分钟,而当我使用具有相同训练配置的本地 GPU (GeForce MX150)时,训练仅花费了6 分钟*。***
示例查询:
查询:‘一只狗在和他的朋友玩’
伯特模型:“一个男人拯救了一只德国牧羊犬,两人如何成为好朋友的故事。”[我的狗郁金香]
查询:“一部欧洲英雄电影”
伯特模型:“在一个反乌托邦的欧洲,一名警察调查一名连环杀人案嫌犯,使用了他现在已经名誉扫地的前导师写的有争议的方法。”[Forbrydelsens 元素]
(我们可以断定它不存在于数据库中)
查询:《一个女服务员的故事》
伯特模特:“一名女服务员不顾一切地想要实现她当餐馆老板的梦想,踏上了将青蛙王子变回人类的旅程,但是在她吻了他之后,她不得不面对同样的问题。”[公主和青蛙]
结论
一旦我们加载并矢量化了初始数据集,我们就可以使用一个新句子作为查询,并从数据集中检索与该查询句子匹配的前 3 个最接近的项目。
为此,我们使用了简单的 TF-IDF 模型,该模型使用单词和句子中的频率来创建向量。我们使用了 Word2Vec 模型,一个简单的神经网络。我们使用了 spaCy ,它可以处理和计算许多不同语言的向量,具有最先进的性能。
最后,我们使用 transformer 模型来利用最新的深度学习方法进行矢量化。深度学习技术可以实现最好的(主观上)检索结果,但它们较慢。选择最适合你权衡的方法!
资源
1 Python 机器学习,Sebastian Raschka,Packt Edition(https://www . packtpub . com/product/Python-Machine-Learning-third-Edition/9781789955750)
[2]http://mccormickml . com/2016/04/19/word 2 vec-Tutorial-The-skip-gram-model/,http://mccormickml . com/assets/word 2 vec/Alex _ Minnaar _ word 2 vec _ Tutorial _ Part _ II _ The _ Continuous _ Bag-of-Words _ model . pdf
[3] 用于搜索的深度学习,托马索·特奥菲利,曼宁出版。
从零开始在 JAX 建造一个变压器
原文:https://towardsdatascience.com/build-a-transformer-in-jax-from-scratch-how-to-write-and-train-your-own-models-9aa02b5b28fd?source=collection_archive---------16-----------------------
如何编写和训练自己的模型
作者图片
在本教程中,我们将探讨如何开发一个神经网络(神经网络)与 JAX。还有什么比变压器更好的型号可以选择。随着 JAX 越来越受欢迎,越来越多的开发团队开始尝试使用它,并将其整合到他们的项目中。尽管它缺乏 Tensorflow 或 Pytorch 的成熟度,但它为构建和训练深度学习模型提供了一些很好的功能。
如果你还没有对 JAX 的基础知识有一个坚实的理解,看看我以前的文章。你也可以在我们的 Github 库中找到完整的代码。
俳句和 Flax 似乎是 Google/Deepmind 内部最多的框架,拥有最活跃的 Github 社区。对于本文,我将从第一个开始,看看以后是否还需要另一个。
所以你准备好用 JAX 和俳句做一个变形金刚了吗?对了,我假设你对变形金刚有扎实的了解。如果你还没有,请指点我们关于注意和变形金刚的文章。
让我们从自我关注块开始。
自我关注障碍
首先,我们需要引进 JAX 和俳句
*import* jax
*import* jax.numpy *as* jnp
*import* haiku *as* hk
import numpy *as* np
幸运的是,俳句有一个内置的MultiHeadAttention
模块,可以扩展来构建一个屏蔽的自我关注模块。我们的块接受查询、键、值以及掩码,并将输出作为 JAX 数组返回。可以看到代码非常熟悉标准 Pytorch 或者 Tensorflow 代码。我们所要做的就是构建因果掩码,使用np.trill()
使第 k 个以上数组的所有元素无效,乘以我们的掩码,并将所有内容传递给hk.MultiHeadAttention
模块
这个片段允许我介绍俳句的第一个关键原则。所有模块都应该是hk.Module
的子类。这意味着他们应该实现__init__
和__call__
,以及其他方法。在某种意义上,这与 Pytorch 模块的架构相同,我们实现了一个__init__
和一个forward
。
为了清楚起见,让我们构建一个简单的 2 层多层感知器作为hk.Module
,它将方便地用在下面的变压器中。
线性层
一个简单的两层 MLP 看起来像这样。你可以再次注意到它看起来多么熟悉。
这里需要注意一些事情:
- 俳句为我们提供了一组
hk.initializers
下的权重初始化器,在这里我们可以找到最常见的方法。 - 它还内置了许多流行的层和模块,如
hk.Linear
。如需完整列表,请查看官方文档。 - 没有提供激活函数,因为 JAX 已经有一个名为
jax.nn
的子包,在那里我们可以找到激活函数,比如relu
或者softmax
。
标准化层
层规范化是 transformer 架构的另一个组成部分,我们也可以在 Haiku 的公共模块中找到它。
变形金刚
现在说说好东西。下面你可以找到一个非常简单的转换器,它利用了我们预先定义的模块。在__init__
中,我们定义了基本变量,如层数、注意力头和辍学率。在__call__
中,我们使用一个for
循环组成一个块列表。
如您所见,每个模块包括:
- 标准化层
- 自我关注障碍
- 两个脱落层
- 两个标准化层
- 两个跳跃连接(
h = h + h_attn
和h = h + h_dense
) - 两层致密块体
最后,我们还添加了一个最终的规范化层。
我想现在你已经意识到用 JAX 建立一个神经网络非常简单。
嵌入层
最后,让我们也包括嵌入层。很高兴知道俳句还提供了一个嵌入层,它将从我们输入的句子中创建标记。令牌然后被添加到位置嵌入,产生最终输入。
hk.get_parameter(param_name, ...)
用于访问模块的可训练参数。但是你可能会问,为什么不像我们在 Pytorch 中那样使用对象属性呢?这就是俳句的第二个关键原则发挥作用的地方。我们使用这个 API,这样我们就可以使用 hk.transform
将代码转换成一个纯函数。这不是很容易理解,但我会尽可能地把它说清楚。
为什么是纯函数?
JAX 的力量体现在它的函数转换中:用 T2 向量化函数的能力,用 T3 自动并行化,用 T4 实时编译。这里需要注意的是,为了转换一个函数,它需要是纯的。
纯函数是具有以下特性的函数:
- 对于相同的参数,函数返回值是相同的(没有局部静态变量、非局部变量、可变引用参数或输入流的变化)
- 函数应用程序没有副作用(没有局部静态变量、非局部变量、可变引用参数或输入/输出流的变异)。
来源: Scala 纯函数 by O'Reily
这实际上意味着一个纯函数将总是:
- 如果用相同的输入调用,返回相同的结果
- 所有的输入数据都通过函数参数传递,所有的结果都通过函数结果输出
Haiku 提供了一个名为hk.transform
的函数转换,它将具有面向对象的、功能上“不纯”的模块的函数转换成可以与 JAX 一起使用的纯函数。为了在实践中看到这一点,让我们继续训练我们的 Transformer 模型。
向前传球
典型的向前传球包括:
- 获取输入并计算输入嵌入
- 运行通过变压器的块
- 返回输出
上述步骤可以很容易地用 JAX 组成如下:
虽然代码很简单,但它的结构可能看起来有点奇怪。实际的正向传递通过forward_fn
功能执行。然而,我们用返回forward_fn
的build_forward_fn
函数包装它。什么鬼东西?
接下来,我们需要使用hk.transform
将forward_fn
函数转换成一个纯函数,这样我们就可以利用自动微分、并行化等功能。
这将通过以下方式实现:
这就是为什么我们不是简单地定义一个函数,而是包装并返回函数本身,或者更准确地说是一个可调用的。然后,这个可调用函数可以被传递到hk.transform
中,成为一个纯函数。如果这是清楚的,让我们继续我们的损失函数。
损失函数
损失函数是我们熟知的交叉熵函数,不同之处在于我们还考虑了掩模。JAX 再次提供了one_hot
和log_softmax
功能。
如果你还和我在一起,喝一口咖啡,因为从现在开始事情会变得严重。是时候建立我们的训练循环了。
训练循环
因为 Jax 和 Haiku 都没有内置的优化功能,我们将使用另一个框架,名为 Optax 。如开头所述,Optax 是渐变处理的 goto 包。
首先,您需要了解一些关于 Optax 的事情:
Optax 的关键改造是GradientTransformation
。转换由两个函数定义,即__init__
和__update__
。__init__
初始化状态,__update__
根据状态和参数的当前值转换梯度
state = init(params)
grads, state = update(grads, state, params=None)
为了减少我们的main
函数,我们将把渐变更新提取到它自己的类中。
首先,GradientUpdater
接受模型、损失函数和优化器。
- 该模型将是由
hk.transform
转换的纯forward_fn
函数
forward_fn = build_forward_fn(vocab_size, d_model, num_heads, num_layers, dropout_rate)forward_fn = hk.transform(forward_fn)
2.损失函数将是具有固定forward_fn
和“vocab_size”的部分的结果
loss_fn = functools.partial(lm_loss_fn, forward_fn.apply, vocab_size)
3.优化器是一组按顺序运行的优化转换(可以使用optax.chain
组合操作)
optimizer = optax.chain(
optax.clip_by_global_norm(grad_clip_value),
optax.adam(learning_rate, b1=0.9, b2=0.99)
)
梯度更新器将被初始化如下:
updater = GradientUpdater(forward_fn.init, loss_fn, optimizer)
看起来会像这样:
在__init__
中,我们用self._opt.init(params)
初始化优化器,并声明优化的状态。状态将是具有以下内容的字典:
- 当前步骤
- 优化程序状态
- 可训练参数
- (一个随机生成的密钥传入
jax.random.split
)
update
功能将更新优化器的状态以及可训练参数。最终,它将返回新的状态。
updates, opt_state = self._opt.update(g, state['opt_state'])params = optax.apply_updates(params, updates)
这里还有两件事需要注意:
jax.value_and_grad()
是一个特殊函数,它返回一个带梯度的可微函数。__init__
和__update__
都用functools.partial(jax.jit, static_argnums=0
标注,这将触发即时编译器,并在运行时将它们编译成 XLA。注意,如果我们没有将forward_fn
转换成一个纯函数,这是不可能的。
最后,我们准备构建整个训练循环,它结合了迄今为止提到的所有思想和代码。
注意我们是如何合并GradientUpdate
的。这只是两行代码:
state = updater.init(rng, data)
state, metrics = updater.update(state, data)
仅此而已。我希望你们现在对 JAX 及其能力有了更清楚的了解。
感谢
所展示的代码在很大程度上受到了俳句框架的官方例子的启发。已经对其进行了修改,以适应本文的需要。有关完整的示例列表,请查看官方知识库。
结论
在本文中,我们看到了如何使用俳句在 JAX 开发和训练一个普通的变压器。尽管代码并不难理解,但它仍然缺乏 Pytorch 或 Tensorflow 的可读性。我强烈建议尝试一下,发现 JAX 的优点和缺点,看看它是否适合你的下一个项目。根据我的经验,JAX 非常适合需要高性能的研究应用,但对于现实项目来说还不够成熟。在我们的不和谐频道让我们知道你的想法。别忘了访问我们的博客艾夏获取类似文章。
原载于 2021 年 3 月 19 日【https://theaisummer.com】。
使用 Python 构建您自己的自定义数据集
原文:https://towardsdatascience.com/build-a-your-own-custom-dataset-using-python-9296540a0178?source=collection_archive---------8-----------------------
我是如何从零开始构建数千行数据点的
肖恩·托马斯在 Unsplash 上拍摄的照片
D ata 是数据科学和机器学习的基础。为了分析、可视化、得出结论和建立 ML 模型,需要成千上万的数据点。在某些情况下,数据是现成的,可以免费下载。其他时候,数据无处可寻。
在数据不容易获得但需要的情况下,您将不得不求助于自己构建数据。您可以使用许多方法从 webscraping 到 API 获取这些数据。但是有时,您最终需要创建假的或“虚假的”数据。当您知道将要使用的确切功能和包含的数据类型,但是您没有数据本身时,虚拟数据会很有用。
在这里,我将向您展示我是如何创建 100,000 行虚拟数据的。这个数据也不完全是随机的。如果是的话,建造它会容易得多。有时,当从头开始创建虚拟数据时,您需要在数据中开发可能反映真实世界行为的趋势或模式。你以后会明白我的意思。
在这里注册一个中级会员,可以无限制地访问和支持像我这样的内容!在你的支持下,我赚了一小部分会费。谢谢!
构建数据集的需求
假设你正在从头开始构建一个应用程序,需要建立一个庞大的用户群来进行测试。为您提供了一个要素及其各自数据类型的列表。
这个用户群也需要在一定程度上准确地反映真实世界的用户和趋势,所以它不能完全随机。例如,您不希望一个用户拥有大学学历,但也只有 10 岁。或者,您可能不希望某个特定数据点的代表性过高,例如男性多于女性。这些都是创建数据集时需要注意的事项。
由于真实世界的数据很少是真正随机的,所以像这样的数据集将是对您将来要处理的其他数据集的一个很好的模拟。它还可以作为你希望训练的任何机器学习模型的试验场。
现在让我们开始吧,请随意跟进,我将向您展示我是如何构建这个数据集的…
构建数据集
要进行编码,首先要导入以下库:
import pandas as pd
import uuid
import random
from faker import Faker
import datetime
大小
数据集大小将为 100,000 个数据点(您可以做得更多,但可能需要更长时间来处理)。我将这个数量分配给一个常量变量,我在整个过程中都使用这个变量:
num_users = 100000
特征
我挑选了我认为在常规用户数据集中最常见的 10 个特征。这些功能和各自的数据类型是:
- ID —标识每个用户的唯一字符串。
- 性别 —三种选择的字符串数据类型。
- 订阅者 —他们订阅状态的二元真/假选择。
- Name —用户的名和姓的字符串数据类型。
- Email—用户电子邮件地址的字符串数据类型。
- 上次登录 —上次登录时间的字符串数据类型。
- 出生日期 —年-月-日的字符串格式。
- 教育 —字符串数据类型的当前教育水平。
- Bio —随机词的短字符串描述。
- 评分——对某事物从 1 到 5 的整数型评分。
我输入上面的内容作为初始化熊猫数据框架的特征列表:
# A list of 10 features
features = [
"id",
"gender",
"subscriber",
"name",
"email",
"last_login",
"dob",
"education",
"bio",
"rating"
]# Creating a DF for these features
df = pd.DataFrame(columns=features)
创建不平衡的数据
上面的一些属性通常应该包含不平衡的数据。通过一些快速的研究,可以有把握地假设,有些选择不会被同等地代表。对于更真实的数据集,需要反映这些趋势。
本能冲动
对于 ID 属性,我使用uuid
库生成了 10 万次随机字符串。然后,我将它赋给数据帧中的 ID 属性。
df['id'] = [uuid.uuid4().hex for i in range(num_users)]
UUID 是一个很好的库,可以为每个用户生成唯一的 ID,因为它复制 ID 的几率非常低。在生成独特的识别字符集时,这是一个很好的选择。但是,如果您希望确保没有重复的 id,那么您可以使用以下命令对数据帧进行简单的检查:
print(df['id'].nunique()==num_users)
如果数据集中的所有 id 都是唯一的,这将返回 True 。
性别
照片由 Dainis Graveris 在 Unsplash 上拍摄
该属性是不应该使用同样随机的选择的实例之一。因为,可以有把握地假设,每一种选择发生的可能性并不相等。
对于性别,我提供了三个选项:男性、女性和 na。然而,如果我使用 Python 的random
库,那么每个选择可能会平等地显示在数据集中。事实上,男性和女性的选择要比北美多得多。所以我决定在数据中展示这种不平衡:
genders = ["male", "female", "na"]df['gender'] = random.choices(
genders,
weights=(47,47,6),
k=num_users
)
通过使用random
库,我向choices()
函数提供了性别选项列表、每个选项的权重,以及由“ k 表示的要做出多少个选择。然后将它分配给 dataframe 的“ gender ”属性。我之前描述的不平衡,在权重部分表示为大约 6%的时间出现“na”选择。
订户
对于这个属性,选项可以在真和假之间随机选择。因为可以合理地预期大约一半的用户将是订户。
choice = [True, False]df['subscriber'] = random.choices(
choice,
k=num_users
)
就像之前的“性别”一样,我使用了random.choices()
,但是没有权重,因为这个属性可以在两个选项之间随机拆分。
名字
在这里,我使用 Faker 库为所有这些用户创建了数千个名字。Faker 库在这种情况下很棒,因为它有一个男性和女性名字的选项。为了处理性别化的名字,我创建了一个函数来根据给定的性别分配名字。
# Instantiating faker
faker = Faker()def name_gen(gender):
"""
Quickly generates a name based on gender
"""
if gender=='male':
return faker.name_male()
elif gender=='female':
return faker.name_female()
return faker.name()# Generating names for each user
df['name'] = [name_gen(i) for i in df['gender']]
我使用我的简单函数根据之前的“性别”属性数据快速生成一个姓名列表,并将其分配给 dataframe。
电子邮件
照片由 Daria Nepriakhina 在 Unsplash 拍摄
电子邮件被证明是更棘手的属性之一。我想创建与生成的名称相关的电子邮件地址。然而,可能会有重复的机会,因为人们可以共享相同的名称,但不是相同的电子邮件。
首先,我创建了一个新函数,它可以将名字格式化成带有默认域名的电子邮件地址。它还可以通过在格式化名称的末尾添加一个随机数来处理重复的地址:
现在,为了恰当地利用这个函数的目的,我创建了一个循环,当遍历“ Name 属性时,这个循环将在必要时重新运行这个函数。该循环将继续运行该函数,直到创建一个唯一的电子邮件名称。
emails = []for name in df['name']:
# Generating the email
email = emailGen(name)
# Looping until a unique email is generated
while email in emails:
# Creating an email with a random number
email = emailGen(name, duplicateFound=True)
# Attaching the new email to the list
emails.append(email)
df['email'] = emails
在所有电子邮件生成之后,我将它们分配给 dataframe 的“ Email ”属性。您还可以使用与 IDs 相同的方法进行可选的检查,以查看每封电子邮件是否是唯一的。
上次登录
这个属性现在需要特定的格式,通过使用datetime
库,这变得更加容易。在这里,我希望用户有过去一个月左右的登录历史。我使用了另一个自定义函数来帮助:
该函数主要生成两个给定时间之间的时间戳列表。它生成了一个随机时间戳列表来分配给数据帧。
出生日期
这个属性很简单,因为它类似于“上次登录”。我所做的只是通过删除小时、分钟和秒来改变时间格式。我再次使用datetime
来帮助为每个用户随机选择一个日期,但是这次时间范围从 1980 年到 2006 年,以获得一个很好的年龄随机分布。下面的代码与前面的代码基本相同,但格式和日期范围不同:
教育
马特·拉格兰在 Unsplash 上拍摄的照片
“教育”属性依赖于“出生日期”。在这些情况下,教育水平是基于使用者的年龄,而不是他们达到的最高教育水平。这是随机选择教育水平不能反映真实世界趋势的另一个属性。
我创建了另一个简单的函数,它根据今天的日期检查用户的年龄,并返回他们当前的教育水平。
生成教育水平列表后,我将它分配到数据框架中。
个人简历
对于这个属性,我想根据用户的订阅状态来改变简历的长度。如果用户是订阅者,那么我会假设他们的 bios 比非订阅者的要长。
为了适应这种情况,我构建了一个函数来检查他们的订阅状态,并从 Faker 返回一个长度不等的随机句子。
在上面的函数中,我根据订阅状态随机选择了假句子的长度。如果他们是订阅者,那么他们的简历会比平时长,反之亦然。
评级
乔治·帕甘三世在 Unsplash 上的照片
为了完善这个数据集,我想包含一个数字数据类型。我选择“ rating ”为整数类型。1 到 5 的评级代表任何东西,它只是为了任何自由裁量的目的而存在。
对于评分本身,我选择将 1 到 5 的分布向极端倾斜,以反映用户似乎对他们的评分更加绝对的倾向。
# The different ratings available
ratings = [1,2,3,4,5]# Weighted ratings with a skew towards the ends
df['rating'] = random.choices(
ratings,
weights=(30,10,10,10,30),
k=num_users
)
我再次使用了random.choices()
函数,但是权重偏向 1 和 5。
保存数据集
既然数据已经完成,如果您正在编写代码,那么在决定保存它之前,可以随意查看数据帧。如果一切正常,那么用这个简单的命令将数据帧保存为一个.csv
文件:
df.to_csv('dataset.csv')
这将数据集作为一个相当大的 CSV 文件保存在本地目录中。如果您想检查保存的数据集,请使用以下命令查看它:
pd.read_csv('dataset.csv', index_col=0)
一切都应该看起来不错,现在,如果你愿意,你可以执行一些基本的数据可视化。如果您想了解更多关于数据可视化的知识,请查看我的以下文章:
[## 为什么我使用 Plotly 进行数据可视化
towardsdatascience.com](/how-to-use-plotly-for-data-visualization-f3d62bbcfd92)
结束语
我希望您能从我构建这个数据集的经历中学到一些新东西。如果有的话,构建它提供了一点创建 Python 函数和算法的实践。此外,我相信构建自己的数据集可以让你对数据集有更好的理解。它也许能让你准备好处理任何你需要的大量数据。
如果您愿意,您可以通过向数据分布添加更多的限制或依赖性,甚至向数据帧添加更多的属性来改进它。请随意探索这些数据或对其进行扩展!
不是中等会员?点击这里支持 Medium 和我!
Github 上的代码
https://github.com/marcosan93/Medium-Misc-Tutorials/blob/main/Build-a-Dataset.ipynb
用 FastAPI & SQLAlchemy 构建异步 python 服务
原文:https://towardsdatascience.com/build-an-async-python-service-with-fastapi-sqlalchemy-196d8792fa08?source=collection_archive---------0-----------------------
使用 FastAPI 和新的 SQLAlchemy AsyncIO 支持构建一个完全异步的 python 服务,包括异步数据库查询
约翰·卡梅隆在 Unsplash 上拍照
背景
在开始之前
在这篇博文中,我们将构建一个小的 CRUD python 应用程序(我将使用 Python 3.9,但它应该可以在 3.7+上工作)。这篇文章将关注 FastAPI 和 async SQLAlchemy 的实现和使用,而不是 AsyncIO 在 Python 中的理论和一般用法。此外,这个职位假设你有以下主题的知识:
1。Python 语言与生态系统(venvs,IDE)
2。SQL 和 SQLALchemy
3。HTTP web 服务概念
这篇文章中的所有代码都可以在这个公共知识库中找到:https://github.com/azimovMichael/my-async-app
异步编程和 python AsyncIO
异步编程是一种编程模式,它使代码能够独立于主应用程序线程运行。异步编程被用在许多用例中,比如事件驱动的系统、高度可伸缩的应用等等。
异步编程并不是一个新概念。它已经存在了一段时间,尤其是在 JavaScript 生态系统中。Python 3.4 引入了 asyncio 包,实现了 Python 对 Async/Await 设计的支持。有很多关于它的例子和教程,但我最喜欢的是:python 异步编程简介,多任务不是我的强项,所以我怎么能责怪 Python 呢?(由我的同事 Danielle shaul )和Concurrent Burgers-Understand async/await(由 FastAPI 的创建者 Sebastián Ramírez )
初始设置
准备环境
首先,你需要用一个新的虚拟环境创建一个新项目。在新的 venv 里面,安装我们的第一个包——FastAPI和uvicon。
pip install fastapi uvicorn[standard]
FastAPI 是一个相当新的 python(微)web 框架,内置了对异步端点的支持。
Uvicorn 是我们选择的 ASGI 服务器。ASGI 是 python WSGI 的异步姐妹。
现在我们已经准备好了一些代码。
第一个异步端点
要配置 FastAPI 服务,创建一个名为app.py
的 python 模块,代码如下:
这段代码没做什么。它使用 uvicorn ASGI 服务器在端口 1111 上启动了一个 FastAPI 应用程序,没有任何自定义端点。FastAPI 自带对 OpenAPI Docs 的开箱即用支持,因此你可以运行该应用程序,并在浏览器中转至:http://127 . 0 . 0 . 1:1111/Docs。如果一切顺利,您应该会看到类似如下的网页:
自动生成的 API 文档的初始视图
现在我们准备创建我们的第一个异步端点。
在您的app.py
文件中,添加一个名为hello_world
的异步函数,并将其挂载到基本 GET 路径:
重新运行服务,您应该会看到两个新东西:在 API 文档中,您应该会看到我们的新端点,您也可以使用“试用”按钮调用它:
我们新终端的文档
你也可以去http://127 . 0 . 0 . 1:1111/,在我们的浏览器中看到“hello_world”响应文本。
我们有了第一个异步端点!🎆
书店 CRUD 应用程序
所以,这篇文章的目的是建立一个小的 CRUD 应用程序。出于演示的目的,我们将构建一个简单的书店应用程序,能够创建、更新和获取书籍。
SQLAlchemy 和 AsyncIO
为了使用 DB 来存储书籍,我使用 Python 的 SQLalchemy 库和支持 asyncio(aiosqlite)的 sqlite 方言
安装必要的软件包:
pip install SQLAlchemy==1.4.3 aiosqlite
SQLAlchemy 1.4.X 是一个非常新的版本,有很多升级和新特性(这是迈向备受期待的 2.0 版本的第一步),在这里详细介绍。在这篇文章中,我将主要关注新的异步支持。
SQLAlchemy****Asyncio 在 1.4 版本早期应该算是 alpha 级别(!).
一旦我们安装了 SQLAlchemy,我们需要配置我们的数据库连接。创建一个名为db
的新 python 包,并在其中创建一个名为config.py
: 的新模块
我们的数据库服务器是 SQLLite(一个本地test.db
文件)的本地实例,我们将使用支持异步查询的aiosqlite
方言与它对话。我们正在使用新的create_async_engine
函数创建 db 引擎。创建的会话标记有两个唯一的标志:expire_on_commit=*False*
确保我们的数据库实体和字段在会话提交后仍然可用,而class_=AsyncSession
是新的异步会话。我们还将使用好的、旧的declarative_base
来配置我们即将创建的 DB 模型。
如果你想使用不同的数据库(MySql、PostgreSQL 等),你需要安装一个支持 AsyncIO 的兼容驱动程序,并更新
DATABASE_URL
参数。
数据库模型
我们正在构建一个书店应用程序,所以我们的主数据库表应该是一本书,这一点也不奇怪。在db
包中创建一个名为models
的新包,并在其中创建一个名为book.py
的新模块。
我们的图书实体也会有一些字段——名称、作者、发行年份:
为了创建一个新的实体,我们将使用一个 DAL(数据访问层)类,它将负责这个 DB 模型的所有 sql 函数。在其中创建一个dals
包和一个book_dal.py
模块:
我们有 3 个函数:一个create_book
函数接收我们的实体字段,并将一条新记录保存到数据库。一个get_all_books
函数返回数据库中的所有书籍,一个update_book
函数接收 book_id 和书籍字段的可选新值并更新它们。在update_book
函数中,我们添加了一个名为synchronize_session
的执行选项,它告诉会话使用fetch
方法“刷新”更新的实体,以确保我们在内存中的实体将与我们更新的新值保持一致。
现在我们需要一些将使用这些 DAL 函数的新端点,所以让我们将它们添加到我们的app.py
:
每个端点异步创建一个 DB 会话,一个带有会话的 BookDAL 实例,并调用相关函数(如果您的“干净代码”本能现在正在尖叫,那完全没问题,我们将在几个段落中解决它们)。
注意 PUT 方法:通过使用带有默认值的
Optional
类型,我们使查询参数成为可选的。
但是,为了让所有这些好东西实际工作,我们需要创建我们的书籍 表格。为此,我们将利用 FastAPI 的事件特性,并在应用启动时创建必要的表(显然,这不是我们想要在生产应用中做的事情):
现在,您可以运行应用程序,并查看 API 文档页面。它应该是这样的:
API 文档是交互式的,因此您可以直接从该页面调用我们的新端点。创建一本书:
您可以使用任何想要的输入参数。执行该命令后,您应该会在我们的 books 表中看到一条新记录。现在,让我们使用 get 端点来获取它:
正如你所看到的,我们的应用程序用我们的新书作出了回应,这本书被赋予了 id 1。我们现在可以使用更新图书上传功能来更新该图书:
然后再次获取它,并验证该书的名称实际上已经更改:
祝贺你,你已经创建了你的第一个完全异步的 python 服务!🎉
重构
现在我们有了一个可以工作的异步应用程序,我想使用一些 FastAPI 特性来使代码更简洁。
API 路由器
目前,我们的app.py
文件包含了我们所有的端点。在现实世界的应用程序中,我们可以有更多的端点,这个文件可以变得非常大。为了避免这种情况,我们可以使用 FastAPI 的 API 路由器特性。创建一个routers
包并在其中创建一个book_router.py
文件:
book_router.py
文件将包含与我们的 book 实体相关的所有 http 路由。现在我们需要更新我们的app.py
文件来包含这个新的路由器:
您可以使用交互式 API 文档来验证我们的端点是否正常工作。
属国
你注意到我们在端点实现中使用的所有样板代码了吗?数据库会话初始化?如果我们不必为我们的每一个端点实现它,那该有多好,对吗?幸运的是,FastAPI 再次帮助了我们!
我们可以使用 FastAPIs 依赖注入功能使book_dal
成为端点的依赖。这样我们只实现一次 BookDAL 的创建逻辑,然后就可以在每个端点使用了。创建一个dependencies.py
文件并添加一个get_book_dal
函数:
现在,我们需要使用 FastAPIs 依赖特性使这个函数成为端点的依赖项:
FastAPIs 依赖注入特性,非常强大而且易于使用。在我们的用例中,我们用它来为我们的端点注入 DAL 类,但是我们可以注入许多其他的东西——安全组件、商业智能组件等等。
验证我们的端点仍然工作,这就结束了!
结论
Python asyncio 相对较新,有很多复杂性和其他有趣的用例我们没有涉及,我鼓励你们每个人探索这个令人兴奋的新世界。
FastAPI 是一个新的现代 web 框架,强调速度、易用性,当然还有对 AsyncIO 的内置支持。
在本文中,我们构建了一个完全异步的 python 应用程序——从使用 FastAPI 的异步 http 端点到使用 SQLAlchemy 1.4 的异步 DB 查询。一个非常重要的话题是测试异步端点和代码,这个话题我们在这篇文章中没有涉及,我期待在我的下一篇文章中讨论这个话题。
为你的机器学习模型建立一个令人敬畏的用户界面
原文:https://towardsdatascience.com/build-an-awesome-ui-for-your-machine-learning-models-7fab52ecdd86?source=collection_archive---------8-----------------------
我如何为我的 PDF-to-audiobook 转换器构建一个出色的用户界面
PDF 到有声读物
最终界面托管在 Gradio hub!
https://gradio.app/hub/aliabd/text_speech
简介
数据科学家、数据分析师和机器学习工程师面临的一个重大挑战是向非技术人员展示和演示他们的模型。这通常需要额外的技能,包括前端开发、后端开发,有时甚至是开发运维。即使你在这些领域很熟练,完成这项工作也需要大量的时间。一些库可以为您处理这项工作,让您将更多的精力放在模型开发任务上。 Gradio 就是一个很好的例子;这是一个 Python 库,可以为每个机器学习模型生成易于使用的 UI。
本教程将探索这个库,并向您展示如何使用它来构建 PDF-to-Audiobook 演示。所以,让我们开始吧!
格拉迪欧是什么?
Gradio 是一个开源 Python 库,它允许你为机器学习模型构建一个用户界面,并在几行代码中进行部署。如果你之前在 python 中用过 Dash 或者 Streamlit,也差不多;然而,它直接与笔记本集成,不需要单独的 python 脚本。
如何运作?
用起来很简单;为了渲染一个界面,我们需要五个组件:前三个我们可以根据你的模型的用例自由定制,最后两个绑定到渲染和部署:
- 一个输入组件:定义输入的类型(文件、文本框、图片上传等)。)
- 一个输出组件:定义输出的类型(文件、文本框、标签、音频等)。)
- 可调用函数:应用于输入并呈现在输出中的主要推理函数。该功能可以是任何东西,从简单的打印到预先训练的模型— 查看组件列表。
- 接口类:是一个 python 类,它将可调用函数与呈现接口中的输入进行映射。
- launch() 函数负责在 gradio 服务器上运行应用程序。
查看更多详细文档和 Gradio 入门页面
在幕后,Gradio 使用 Flask 框架构建接口组件并在本地运行,然后在它们的域上进行端口转发,这样您就有了一个已部署的链接(24 小时有效)。
如果你想要一个永久的链接,你可以设置一个 Gradio 高级账户,Gradio 将在他们的服务器上的 docker 镜像中托管你的整个应用程序。
Gradio 工作流程
调用launch()
会生成一个公共的、可共享的链接,只要您的服务器打开,您就可以自由地共享它——因为它共享工作区会话依赖项。在使用 colab 笔记本的情况下,总是会自动创建一个可共享的链接。一般是这样的: XXXXX.gradio.app 。尽管该链接与 gradio 域相关联,但它只是本地服务器的代理,并不从托管界面收集或存储数据。
但是,要注意这些可共享的链接是公开的,这意味着任何人都可以访问你的界面。因此,不要通过输入函数暴露任何敏感数据,也不要允许对您的机器进行任何危险的修改。我们可以通过设置用户名和密码在 launch 函数中配置 auth 参数来解决这个问题。
如果您设置 share=False(默认),则仅创建一个本地链接,您可以通过端口转发与特定用户共享该链接。
在接下来的几个步骤中,我们将使用 Gradio 为 PDF-to-audiobook 转换器构建一个用户界面,以便更加熟悉这个库。
步骤 1:将文本转换为语音的逻辑(后端)
在下面的代码中,我利用 pdfminer 将 pdf 文件转换成纯文本。接下来,我使用谷歌文本语音转换将文本转换成音频格式。
函数 pdf_to_text()将是我们将传递给接口的可调用函数。
第二步:定义输入输出组件
根据功能和用例,您可以传递多个输入。但是,您需要将多个输入作为一个列表(数组)结构来传递。在我们的例子中,我们将只传递一个输入组件和一个输出组件。
输入将是一个文件;输出将是一个音频文件。我们可以通过指示组件名来决定输入或输出的类型,如下所示:
import gradio as griface = gr.Interface(
fn = pdf_to_text,
inputs = 'file',
outputs = 'audio'
)
第三步:启动应用
启动应用程序将初始化 flask 应用程序,并触发本地主机服务器显示该应用程序。launch()函数有许多参数,允许您共享接口、在 colab 上调试它、内联显示它或在浏览器中打开它。所以,当他们走到一起时:
当您运行上面的代码片段时,您将得到类似如下的内容:
在 Gradio 本地服务器上运行的接口
假设您正在使用 colab 笔记本。在这种情况下,您可以直接使用该界面,或者在页面顶部导航与 gradio 应用程序相关联的外部 URL。然后拖动任何 pdf 文件,点击提交,等待编译。
上传 pdf 文件并将其转换为音频
现在,我们有了输入文本的音频版本。厉害!
我们还可以使用实时 URL 来临时公开共享应用程序——正如我们前面讨论的那样,这样人们就可以尝试它,而不必担心安装依赖项和拥有在本地服务器上运行应用程序的基本技能。你需要做的就是在 launch(share = true) 函数中把 share 标志变成 True。然而,该链接将可用于 24 小时导航;如果你想让它永久托管在 Gradio 主机上,你可以考虑创建一个 Gradio 高级账户。
此外,我们可以在接口函数中为同步响应将标志“live”设置为 true。你也可以添加一个标题,描述,甚至写一篇文章或报告来描述这个界面。这些参数可以接受 markdown 或 HTML 中的文本,这不是很棒吗?您可以在这里查看所有可用的界面选项。
下面是将前面的功能添加到界面功能后的最终应用:
如下图所示,我们添加的段落在< p > 标签下创建了一个新 div,并带有一个名为 article 的类。
确认它接受 HTML 降价
部署
为了维护该界面的永久链接,您可能需要订阅 Gradio,每月 7 美元。使用与您的 GitHub 回购相同的账户进行认购至关重要。您需要做的就是选择项目存储库、分支名称、可执行文件名称以及您希望接收通知的电子邮件。
他们允许每个人在二月份使用二月份促销代码部署一个免费链接
部署梯度屏幕
一旦你点击启动按钮,它将建立界面-这可能需要几分钟,取决于应用程序的大小。
启动屏幕
最后,我们有一个永久的界面 URL,你可以在这里试用一下。
最终接口托管在 Gradio hub
它在移动设备上看起来也很整洁,反应灵敏👌
在 iPhone x 尺寸上模拟的界面
如果您导航回您的帐户,您可以选择在 Gradio Hub 发布与社区的界面。
用户帐户仪表板
此外,您可以从 Logs 链接访问部署错误。
部署后记录输出
成交记录
我希望这篇短文让您对使用 gradio 库有了全面的了解。一旦您的工作是活的,您可以有更多的反馈,最终使您能够增强模型。这是一个迭代的过程,反馈是其中必不可少的一部分。使用 gradio 可以使这一步更加舒适和灵活,使您能够专注于改进模型。如有疑问,请在下方评论区评论;我很乐意帮忙。感谢阅读!
参考
- 与本教程相关的 GitHub 库
- Gradio 文档
- Gradio GitHub 回购
- 在野外轻松共享和测试 ML 模型
用 Shiny 和 Flexdashboard 构建交互式机器学习模型
原文:https://towardsdatascience.com/build-an-interactive-machine-learning-model-with-shiny-and-flexdashboard-6d76f59a37f9?source=collection_archive---------25-----------------------
构建房价预测交互式仪表盘的分步指南
作者图片
在这篇文章中,我们将介绍用 r 构建交互式机器学习仪表板的步骤。如果你不熟悉 flexdashboard 和 Shiny,请参见我以前的文章这里的以获得如何使用 flexdashboard 和 Shiny 构建基本交互式仪表板的分步教程。
要开始使用,请确保您已经安装了***shiny***
、 ***flexdashboard***
、 ***dplyr***
、 ***plotly***
、 和***DT***
。
仪表板概述
我们将使用美国住房数据,通过线性回归来预测房价。用户将能够控制独立变量和监测结果的变化。
仪表板将有四种不同的输出。(1) 线性回归汇总显示了模型的 R2 统计量和 F 统计量,以及参数的 p 值和标准偏差。(2) 实际与预测散点图揭示了模型预测与实际结果的匹配程度。真实值和期望值之间的差异见(3) 残差直方图;直方图的形状显示残差是否呈正态分布,以及线性回归模型是否适合该结果。用户也可以从预测表中导入数据。当更多的独立变量添加到模型中时,R 的平方增加,残差减少,所有点都更接近回归线。
让我们开始吧
步骤一。创建仪表板布局
使用**文件>新文件> R 减价>创建空文档,从 R Studio 初始化空减价。**接下来,让我们复制模板,保存它,并编织文档。
作者图片
这将创建一个带有侧栏、两列和两行的仪表板。
作者图片
第二步。收集和准备数据
我们将使用的美国住房数据。数据分为 7 列,包括 5000 次观察。变量包括房价、家庭地址和市场人口统计数据,包括人口、平均收入、平均房龄以及房间和卧室的平均数量。
让我们在仪表板的代码块下加载和准备数据。
第三步。创建用户输入
我们将在侧边栏中创建一个小部件,允许用户为线性模型选择一个或多个自变量。
SelectInput 小部件提供了一个基本的下拉菜单。指定了三个参数:(1) Name :对用户不可见,我们用它来访问小部件的值,(2) label :显示在下拉菜单上方,以及(3) choices: 用户选择的值列表。
仪表板在呈现时应如下所示:
作者图片
第四步。创建反应式表达式
为了限制在不同的代码块中重复运行同一个函数,我们使用了一个反应表达式。我们第一次运行反应表达式时,它会保存输出。下次我们运行反应表达式时,它会返回保存的值,而不进行任何计算。
反应表达式模型 1** 使用输入变量,运行线性回归模型,并保存输出。可以通过调用表达式的名称后跟括号来访问输出,例如 model1() 。可以从反应函数或渲染函数内部调用反应表达式。在下一节中,我们将使用渲染函数(renderPrint、renderPlotly 和 renderDataTable)来访问 model1 的值。**
第五步。用户输出
5.1 添加线性回归输出
使用一个简单的 renderPrint 函数来呈现和打印一个线性模型概要输出。我们在 render 函数中使用 model1() 反应表达式来访问我们在步骤 4 中创建的值。
5.2 添加数据表
用 DT DataTable 包构建交互式表格。这个包的主要功能是 datatable()。它创建了一个 HTML 小部件,用数据表显示 R 数据对象。让我们显示实际价格、预测价格和剩余价格三列。残差是实际值和预测值之间的差值。
5.3 添加 Plotly 散点图:预测价格与实际价格。
让我们使用renderPlotly函数创建一个散点图,显示预测房价与实际房价。X 轴代表实际值,Y 轴代表预测值。
5.4 添加残差的 Plotly 直方图
现在画出我们的线性回归模型的残差直方图。围绕零均匀分布的对称钟形直方图表明正态假设可能是正确的。
这是没有 CSS 的仪表板的样子。让我们设计仪表板的样式,调整线性回归汇总的字体和颜色以及表格格式。
作者图片
第六步。使用 CSS 的样式
有几种方法可以将 CSS 添加到 flexdashboard 中。因为我们只是做了一些小的调整,所以我们将 CSS 作为一个单独的代码块来添加。随着 CSS 文件变得越来越大,它会使代码更难阅读和调试,在这种情况下,最好将 CSS 作为一个外部文件。
您可以简单地在浏览器中打开仪表板,并检查它的 CSS 选择器。选择器是用来选择我们想要样式化的元素的模式。如果你不熟悉 CSS 选择器和基本的 CSS 属性,我将在参考部分为你提供一些额外的链接。
CSS 选择器
*.dt-center*
选择器从仪表板中选择桌子。*#section-section .shiny-bound-output*
选择器选择线性汇总模型的输出。
CSS 属性
- 属性设置元素的背景颜色。
*color*
属性定义了文本的颜色。- 属性指定了一个元素的字体。
*font-size*
属性设置字体大小。
第 6 步—最终仪表板。作者图片
结论:
***Shiny 是一个强大的工具,用于将 R 的数据处理、可视化和机器学习功能集成到一个交互式 web 应用程序中。在构建高度个性化的基于 web 的解决方案时,Shiny 添加 CSS 代码的能力提供了一个很大的优势。Flexdashboard 提供了一个简单的框架,并且是用大家熟悉的 R markdown 编写的。Shiny 和 Flexdashboard 共同提供了一个优雅的解决方案。查看 闪亮画廊 中的一些精彩例子,获取更多灵感。
完成的仪表盘可以在下面的 页面 中找到。我希望你在制作仪表板的时候玩得开心。我欢迎并感谢您的建议和反馈!***
谢谢大家!
参考
- Plotly R 图形库| R | Plotly
- 使用闪亮的 Flexdashboard 和 Plotly 创建一个交互式仪表板| Nata Berishvili |迈向数据科学
- flex dashboard:R(rstudio.com)的简易交互式仪表盘
- 【闪亮的 rstudio.com】T4
- DT:数据表库(rstudio.github.io)的一个 R 接口
- CSS 选择器— CSS:级联样式表| MDN(mozilla.org)
- CSS 选择器(w3schools.com)
- 引导样本:引导的免费主题
构建一个接口来解析任何类型文档中的文本
原文:https://towardsdatascience.com/build-an-interface-to-parse-text-from-any-type-of-document-in-1-line-of-code-33f9dcf8003e?source=collection_archive---------21-----------------------
在 Unsplash 上由 Clayton Cardinalli 拍照
使用面向对象的设计模式从 txt 、 docx 、 pdf 、html、 pptx 等文件中提取文本
这篇文章是关于将面向对象的设计原则应用到一个常见的数据科学任务中,从文档中提取文本。我们将构建一个可维护和可定制的接口来从多种文件类型中提取文本。我所说的接口是指一个对象,即一个类的实例,它可以在一行中从文档中提取文本,而不管文件类型如何。如果您正在构建文本挖掘应用程序,并且希望从各种文件类型中提取文本数据,那么您将需要这个功能。
有一种好的方法和一种不太好的方法来编写代码来执行这项任务。你不应该这样做:
一个很难维护的从不同文件格式中解析文本的代码示例。
该函数有多种用途:确定文件类型,选择使用 if-elif-else 结构执行哪个逻辑路径,最后执行该路径。从软件工程的角度来看,这是有问题的,因为它违反了单一责任原则1。
假设您想要添加新的逻辑路径或者改变现有的路径以提供更多的功能,或者因为一个包更新迫使您更改代码;为了做到这一点,你必须修改负责解析所有文件类型的代码。这增加了 bug 完全破坏应用程序的可能性,而不是部分破坏。此外,你可能很快就会得到一个包含数十条 elif 语句的巨大函数:你添加的越多,你就越有可能引入一个 bug,而且没有人(包括你自己)会喜欢试图理解在使用、修改或修复代码时发生了什么。我们需要把它分解成几个部分。
我们将通过使用工厂方法模式来重构这段代码,这是一种在 90 年代流行的面向对象的设计模式,用于生成一个类的新实例。在我们的例子中,我们想要生成的对象将是一个字符串,但是最初,我们并不确切地知道如何去做,因为这取决于我们想要读取的文件类型。
工厂模式方法定义了一个接受任何文件类型的接口,然后将对象生成的实现委托给一个子类或函数。为了澄清这个概念,让我们来谈谈下面的例子中发生了什么。
使用工厂方法模式重构
定义一个通用接口来解析 txt 和 docx 文件。
类 DocParser 有一个方法 *parse。*当用户用文件路径调用 parse 时,会发生一系列事件:
- 路径传递给第 6 行中的函数 get_format ,返回值存储在变量解析器中。
- get_format 从路径中提取文件扩展名,并在其返回语句中将其传递给另一个函数 get_parser,。
- 在 get_parser 内部,使用一个 if-elif-else 结构,根据文件扩展名执行三个逻辑路径之一。如果提供了有效的文件扩展名,则返回两个函数之一, parse_txt 或 parse_docx 。
- 此时,第 6 行中定义的变量 parser 现在存储的是 parse_txt 或 parse_docx。第 7 行,将文件路径传递给存储在解析器中的函数,并将结果字符串对象返回给用户。
这就是为什么我们将 DocParser 的实例称为接口的原因,因为它唯一的职责是充当用户和生成用户所请求的对象的逻辑之间的接口。接收到文件类型后,接口将确定文件类型、选择解析函数和实际生成对象的责任传递给其他函数。这就是我们所说的接口推迟了类的实现的意思。
函数 parse_txt 和 parse_docx 被称为该类的具体实现,它们是为给定文件类型生成字符串对象的部分。
现在,最初的功能已经被分解为多个部分,每个部分都有一个单一的职责。为什么这样更好?
我们现在可以添加和更改我们接口的功能,而不必触及代码的其他部分,我们只需定义一个新的具体实现作为一个函数,并添加另一个 elif 语句到 *get_parser。*这更容易维护,尤其是当您想要解析的文件类型数量增加时,这意味着如果一部分停止工作,其余的代码将不受影响。下面是如何修改上面的例子来提供解析 pdf 、 *html、*和 pptx 文件的功能。
解析 pdf、html 和 pptx 文件的额外功能可以很容易地添加到界面中。
我们做的第一件事是向 get_parser 添加更多的 elif 语句,然而,由于我们在每个逻辑路径中只有一个 return 语句,函数仍然可读。然后我们定义了三个新函数 parse_pdf、 parse_html 和 parse_pptx ,而原来的解析函数保持不变。很容易理解如何继续这种模式来解析任何类型的文件。
使用公共界面
通过将上述代码保存在一个文件中, parse_file.py,我们可以用一个简单的 import 语句将接口导入到我们的应用程序中。我们需要做的就是实例化一个 DocParser 对象,我们可以使用 parse 方法在一行中读取我们定义的所有文件类型的文本,如下面的第 17 行所示。
如何使用 DocParser 的实例来解析每个不同文件类型的文本。
在这个例子中,我们在一个循环中调用 parse 方法,路径指向 *txt、docx、pdf、html、*和 pptx 文件,并将结果打印到终端。你可以在项目 GitHub repo 访问测试文件,我在这里从下载了 html 文本文件。输出如下面的动画所示。
每个测试文件中包含的文本被顺序打印到终端上(我添加了一个 2 秒钟的 sleep 命令,以使动画更容易观看)。作者的动画。
如您所见, DocParser 的单个实例可以解析我们传递给它的所有五种文件类型。 pdf 和 html 文件包含一些空白,所以如果你愿意,你可以去编辑 parse_pdf 和 parse_html 来移除这个,安全地知道你的其他解析功能将保持不变。
结论
我们已经介绍了如何使用工厂方法设计模式来构建可维护的接口,该接口可以解析许多不同类型的文档,使我们能够在文本挖掘项目中利用尽可能多的数据源。一旦构建了接口,我们就可以用它在一行代码中提取文本,保持应用程序文件的整洁。
请注意,这种模式是通用的,可以在任何用于生成对象的逻辑依赖于某些参数的情况下使用,这些参数通常由应用程序的用户决定。在其他地方,我发现这对于为 API 提供额外的功能非常有用,这样它就可以接受各种请求负载。稍加考虑,您可能会找到在自己的应用程序中使用这种设计模式的方法,保持它们的整洁、可维护性和通用性。
1 单一责任原则
[2] 设计模式:可复用面向对象软件的要素
我们连线: Linkedin
建立一个无与伦比的棋盘游戏人工智能
原文:https://towardsdatascience.com/build-an-unbeatable-board-game-ai-68719308a17?source=collection_archive---------18-----------------------
一个详细的指南,以编码一个复杂的算法,掌握回合制战略游戏
阿瑟·奥西皮扬在 Unsplash 上的照片
介绍
如果你想尝试人工智能,甚至是一点博弈论,那么建造一台赢棋的机器是一个很好的项目。
我实现了这个 AI 来玩 Connect Four,但它适用于许多不同的游戏。不过,我还是推荐像 Connect Four 这样的游戏,因为游戏机制很简单。
以国际象棋为例:Minimax 可以下棋,但你有几个不同的棋子,可以走不同的棋,有捕捉,阉割,检查和将死等。而使用 Connect Four,您所能做的就是将一片放入一列中。这意味着每一步棋都非常简单,可以用一个整数来表示(棋子所在列的索引),棋盘只是一个 2D 数组。
像井字游戏这样的游戏也是一个不错的选择,但是即使在那里,你也必须考虑列和行。
现在让我们来谈谈这个人工智能将如何实际工作:极大极小算法。
Minimax 如何工作
在博弈论中,极大极小是一种递归算法,它最大化自己的机会,同时最小化对手的机会。因此,这个名字不言自明。
假设对手先动。一旦移动完成,Minimax 会查看游戏棋盘的状态,然后考虑它可能做出的每一步棋。对于每一个结果游戏状态,它会考虑对手可能采取的每一个可能的行动,等等…
这将一直进行,直到找到一个终端游戏状态(游戏获胜或棋盘已满),或者直到达到某个深度。深度是有上限的,否则所有可能的游戏状态的树会快速增长,计算起来会变得非常慢。
最小最大算法考虑了所有可能的棋盘状态(所有图片由作者提供)
现在,在每个级别,这些棋盘状态中的每一个都将根据一组参数(由您定义)分配一个分数,以确定该状态对于最大化玩家或最小化玩家(无论轮到谁)在机会方面有多“好”或“坏”。例如,当前玩家的获胜棋盘将被分配极高的分数,而对手的获胜棋盘将被分配极低的分数。还必须分配中间分数,因为除了最简单的游戏,大多数棋都不是赢棋。
然后,算法选择最终导致 AI 得分最高而对手得分最低的棋盘状态。这就是它将要采取的行动。
选择最高和最低分数的极大极小算法
履行
设置
为了能够编写极大极小算法,你需要一些变量和函数,它们的实现取决于你的棋盘游戏:
npc => In my case, just a character that represents the AI's piece
opponent => Another character to represent the opponent's pieceisTerminalNode() => To determine if a board is terminal (boolean)
isWinningMove() => To determine if a move wins the game (boolean)
getValidMoves() => To get all possible valid moves (array)
score() => To calculate a board state's score (integer)
tempBoard() => To make a copy of the game board (2D array)
makeMove() => Make a hypothetical move on the board (void)
因为我的游戏是 Connect Four,所以我的 isTerminalNode() 方法调用一系列帮助器方法来完成以下任务:
- 检查一行中是否有四个(对角、垂直或水平)。
- 检查棋盘是否已满,不能再移动了。
您需要 getValidMoves() ,因为一列可能会变满,因此 Minimax 不应该试图在该列中移动。
并且 score() 方法调用更多的帮助器方法,这些方法最终为当前棋盘分配一个分数。这是我如何分配分数的(这是你可以支付的——调整损失函数):
Current player gets 4 in a row => 100
Current player gets 3 in a row with an empty adjacent space => 5
Current player gets 2 in a row with 2 empty adjacent spaces => 2
Opponent has 3 in a row with an empty adjacent space => -500
这将确保你的人工智能把它的棋子一个接一个地摆放,同时阻止对手连续获得 4 个。
照片由真诚媒体在 Unsplash 上拍摄
该算法
我用 Java 编写了我的代码,但是我打算在这里把它翻译成一种 Java/Python 风格的伪代码,以保持这篇文章的语言不可知。
- 在第一部分中,检索所有可以进行的有效移动,并检查棋盘是否处于终止状态。
- 我们每次都会减少深度,所以当深度为 0 或者棋盘是终点时,检查游戏是 NPC(非玩家角色)赢了还是对手赢了。
- 如果是,分别返回一个很高或很低的分数。如果没有,返回该板的分数。
minimax(board, depth, maximisingPlayer)
int[] validCols = *getValidMoves*(board)
boolean isTerminalNode = *isTerminalNode*(board)
if (depth == 0 || isTerminalNode)
if (isTerminalNode)
if (*isWinningMove*(board, *npc*))
return null, 1000000000
else if (*isWinningMove*(board, *opponent*))
return null, -2000000000
else
return null, 0
else
return null, *score*(board, *npc)*
注意这个函数返回两件事:分数和移动。
- 创建两个变量:移动(有效移动列表中的随机移动)和值(分数)
- 现在检查当前回合是针对我们的 AI(我们想要最大化的玩家)还是对手(我们想要最小化的玩家)。这作为一个参数传递到函数中—检查上面代码块中的签名。
- 如果轮到最大化玩家,将值设置为非常低的值,比如负无穷大。
- 接下来,遍历有效走法的数组,对每个走法进行走法(在棋盘的副本上,以便不改变原始棋盘的状态——我定义了一个函数来浅层复制我的棋盘),递归调用 *minimax(),*传入新的游戏棋盘,深度减 1 并为 false(因为现在我们要为最小化玩家走法)。调用末尾的1表示我们希望返回第二个东西,即分数。
- 如果 minimax() 返回的分数大于负无穷大,则给 value 赋值并移动。
int move = validCols[(Math.*random*() * validCols.length)]
double value if (maximisingPlayer)
value = *NEGATIVE_INFINITY*;
for (int validCol : validCols)
char[][] tempBoard = *tempBoard*(board)
*makeMove*(validCol, tempBoard, *npc*, *ROWS*)
int newScore = *minimax*(tempBoard, depth - 1, false)[1]
if (newScore > value)
value = newScore
move = validCol
最后,在为最小化玩家调用函数的情况下,进行完全相反的操作。
else
value = *POSITIVE_INFINITY*
for (int validCol : validCols)
char[][] tempBoard = *tempBoard*(board)
*makeMove*(validCol, tempBoard, *opponent*, *ROWS*)
int newScore = *minimax*(tempBoard, depth - 1, true)[1]
if (newScore < value)
value = newScore
move = validCol return move, value
返回的移动是你最终想要的。就这么简单。
照片由马库斯·温克勒在 Unsplash 上拍摄
最佳化
你的人工智能对可能的棋盘看得越深,它就越复杂。然而,正如我前面提到的,这需要很高的计算成本。
当然,你可以通过一种叫做 alpha-beta 剪枝的方法来优化 Minimax 算法,我将在另一篇文章中讨论这一点,当它出来的时候在这里链接。
结论
你会注意到,有了这些简单的规则,人工智能开始表现出优秀玩家推荐的行为。例如,当我的 AI 第一个移动的时候,它总是把它的棋子放在中间。我从来没有明确地编程让它这么做,这只是让人工智能的可能性最大化的一步。
我已经把游戏发给了我的一个朋友,他认为自己是一个相当强大的 Connect Four 玩家,他是那个称人工智能为“不可战胜”的人。
这应该给你实现你自己的棋盘游戏-粉碎人工智能所需要的东西。如果你真的做了一些很棒的东西,请留下回复。
同时,祝您编码愉快!
资源
凯斯加利连接四个极小极大艾 https://www.youtube.com/watch?v=MMLtza3CZFM
辉煌 极大极小算法https://brilliant.org/wiki/minimax/
FreeCodeCampMinimax 算法https://www . FreeCodeCamp . org/news/playing-strategy-games-with-Minimax-4 ECB 83 b 39 B4 b/
用 Diffbot 构建和分析知识图
原文:https://towardsdatascience.com/build-and-analyze-knowledge-graphs-with-diffbot-2af83065ade0?source=collection_archive---------15-----------------------
如何用知识图谱回答疑难问题
动机
当你想进一步了解一个人的时候,你通常会怎么做?你可能会决定使用维基百科等网站来了解一个人。
作者图片
但是,文本可能会很长,您可能需要一段时间才能获得所需的信息。
既然我们更擅长吸收图像形式的信息而不是文本,那么如果你在搜索史蒂夫·乔布斯时能得到如下的图表岂不是很好?
作者图片
这时 Diffbot 就派上用场了。在本文中,您将学习如何使用 Diffbot 构建和分析知识图。
什么是知识图?
知识图表示实体的集合,这些实体是对象、事件、抽象概念,并说明它们之间的关系。谷歌使用知识图表来增强其搜索引擎的结果。
作者图片
用 Diffbot 访问知识图
Diffbot 是世界上最大的知识图,允许你访问网络上万亿个相关事实。
从 Diffbot 开始,注册 14 天的免费试用。这次免费试用将允许您搜索 Diffbot 的知识图谱。
登录后,单击搜索选项搜索 Diffbot 知识图。
作者图片
分析苹果的员工
你有没有想过:
- 苹果的员工去了哪所学校,
- 他们的专业是什么,
- 苹果公司最受欢迎的角色是什么?
我们可以使用 Diffbot 的搜索来回答这些问题。首先通过以下方式搜索苹果公司的 Diffbot ID:
- 选择“组织”
- 按“包含”apple 的“名称”过滤
- 点击“搜索”
作者图片
您将看到 61,820 个与苹果相关的结果。由于我们只对苹果公司感兴趣,请点击“苹果公司”
作者图片
您将被引导至显示 Apple Inc .具体信息的网站。复制该网站 URL 中的 ID。在下面的 URL 中找到的 ID 是“EHb0_0NEcMwyY8b083taTTw”。
作者图片
要搜索 Apple Inc .的所有员工,请单击查询选项卡,然后传递:
type:Person employments.employer.id:”EHb0_0NEcMwyY8b083taTTw”
…到搜索框。
作者图片
点击“搜索”后,Diffbot 将返回超过 200k 的结果。
获取知识图
单击右上角的图表图标,查看结果的知识图表。
作者图片
而且你应该会看到如下的知识图!这张图表显示了苹果公司和其他实体之间的关系。与这些实体的关系可以是“城市”、“雇主”、“市区”、“机构”等
作者图片
请注意,此图仅显示了前 25 个结果。要获得接下来 25 个最重要结果的知识图表,请单击图表顶部的“更多”按钮。
为了更好地查看某个节点,可以将其移动到另一个位置。
作者 GIF
要查看每个实体的信息,请单击该实体。您应该会看到如下信息:
作者 GIF
获取 JSON
作者图片
要获得 JSON 格式的结果,单击右上角的 JSON 选项卡。
寻找苹果员工的顶级技能
苹果的员工有哪些技能?我们可以通过查看 JSON 文件中的技能部分找到答案。
作者图片
一个员工可以拥有多种技能,不同的员工拥有不同的技能。有没有一种方法可以总结这些技巧?这可以通过在前面的查询中添加facet:skills.name
来轻松实现:
type:Person employments.employer.id:"EHb0_0NEcMwyY8b083taTTw" facet:skills.name
facet
将显示关于指定字段的值的汇总数据skills.name
告诉 Diffbot 访问 JSON 文件中skills
字段内的name
字段。
苹果员工的 50 大技能:
作者图片
作者图片
获取专业
苹果公司的员工在大学时都是学什么专业的?我们可以通过在查询中添加facet:educations.major.name
来找出答案:
type:Person employments.employer.id:"EHb0_0NEcMwyY8b083taTTw" facet:educations.major.name
苹果员工最喜欢的 25 个专业是:
作者图片
从上图中,我们可以看到热门专业与计算机科学、和工商管理相关。这一结果并不令人惊讶,因为苹果是一家专门从事消费电子产品、计算机软件和在线服务的技术公司。
得到学校
苹果的员工上过哪些顶尖的学校?这可以通过在查询中添加facet:educations.institution.name
来找到:
type:Person employments.employer.id:"EHb0_0NEcMwyY8b083taTTw" facet:educations.institution.name
作者图片
苹果员工去过的前 5 所学校是:
- 斯坦福大学
- 加州大学伯克利分校
- SJSU
- 哈佛大学
- 凤凰城大学
我们可以看到很多这样的大学都是全国顶尖的大学,而且都位于加州。这并不意味着你需要去这些顶尖大学才能被苹果录取。这确实意味着,如果你去这些大学,你可能有更高的机会被苹果公司录取。
分析人工智能公司
你有没有想过:
- 人工智能公司的收入是多少,
- 这些公司位于哪些国家,
- 这些公司有多少员工?
让我们用 Diffbot 来回答这些问题。从选择“组织”开始,然后按行业过滤搜索。单击下拉框并向下滚动,直到您看到“人工智能公司”选项。
作者图片
作者图片
搜索结果中显示的前 25 家公司的知识图表:
作者图片
热门描述符
这些人工智能公司排名前 50 的描述符是什么?让我们通过将facet: descriptors
添加到前面的查询中来找出答案:
type:Organization industries:"Artificial Intelligence Companies" facet: descriptors
作者图片
作者图片
收入
这些公司的收入如何?
type:Organization industries:"Artificial Intelligence Companies" facet: revenue.value
作者图片
作者图片
这些公司中的大多数收入在10 万到 100 万美元之间。
要获取收入在特定范围内的公司,可以将以下内容添加到查询中:
type:Organization industries:"Artificial Intelligence Companies" revenue.value>=100000 revenue.value<500000
作者图片
与人工智能相关的公司数量最多的国家
另一件有趣的事情是,哪些国家拥有最多的人工智能公司。
type:Organization industries:"Artificial Intelligence Companies" facet: location.country.name
前 25 个国家的位置:
作者图片
人工智能公司数量最多的前 5 个国家的名称:
作者图片
雇员人数
这些公司的平均员工人数是多少?
type:Organization industries:"Artificial Intelligence Companies" facet: nbEmployees
作者图片
大多数公司的员工人数从 5 到 100 不等。员工超过 10 万人的公司只有 4 家。它们是什么?
让我们通过点击图表下方表格中的数字来找出答案:
作者图片
作者图片
全球只有 4 家公司员工超过10 万人,而且都是日本公司!这可能是因为许多日本工人忠于他们的公司。
这些结果很酷。但是,如果您想从 Diffbot 中导出数据以进行进一步分析,该怎么办呢?这可以使用 Python 或命令行来完成。
从 Diffbot 下载数据
使用 Python 下载
要使用知识图 API,请向以下端点发出 HTTP GET 请求:
https://kg.diffbot.com/kg/dql_endpoint?token=...&type=query&query=...
我们还可以创建一个返回端点的函数。该函数采用:
- Diffbot 的 API 令牌
- 我们想要下载的 JSON 文件的 URL
您可以在控制面板的右上角找到该令牌。
作者图片
单击右上角的 JSON 选项卡可以找到 JSON 文件的 URL。
作者图片
使用您被定向到的页面的 URL 作为函数get_diffbot_json
的第二个参数。
您将获得一个可下载的 URL:
[https://kg.diffbot.com/kg/dql_endpoint?token=your-token&type=query&query=type%3APerson+id%3A%22EyauXV2QZOW2fEP8Cb_Hoxg%22&from=0&size=25&output_format=](https://kg.diffbot.com/kg/dql_endpoint?token=c2887c50296c48408adef6ca12ce831c&type=query&query=type%3APerson+id%3A%22EyauXV2QZOW2fEP8Cb_Hoxg%22&from=0&size=25&output_format=)
要下载由get_diffbot_json
返回的 URL 中的数据,使用请求库:
并且 JSON 文件将保存在您的本地机器中!
使用命令行下载
您也可以使用wget
在您的终端上下载 JSON 文件:
wget [https://kg.diffbot.com/kg/dql_endpoint?token=your-tokenc&type=query&query=type%3APerson+id%3A%22EyauXV2QZOW2fEP8Cb_Hoxg%22&from=0&size=25&output_format=](https://kg.diffbot.com/kg/dql_endpoint?token=c2887c50296c48408adef6ca12ce831c&type=query&query=type%3APerson+id%3A%22EyauXV2QZOW2fEP8Cb_Hoxg%22&from=0&size=25&output_format=)
结论
恭喜你!您刚刚学习了如何使用 Diffbot 构建知识图和总结基本事实。希望这篇文章能给你动力去探索你感兴趣的其他话题。
我喜欢写一些基本的数据科学概念,并尝试不同的算法和数据科学工具。你可以在 LinkedIn 和 T2 Twitter 上与我联系。
星这个回购如果你想检查我写的所有文章的代码。在 Medium 上关注我,了解我的最新数据科学文章,例如:
[## 如何用 Excalidraw 勾画您的数据科学想法
towardsdatascience.com](/how-to-sketch-your-data-science-ideas-with-excalidraw-a993d049f55c)
为你的机器学习模型构建并运行一个 Docker 容器
原文:https://towardsdatascience.com/build-and-run-a-docker-container-for-your-machine-learning-model-60209c2d7a7f?source=collection_archive---------0-----------------------
使用简单的机器学习模型快速简单地构建 Docker 容器
Annamária Borsos 摄影
本文的想法是用一个简单的机器学习模型快速简单地构建一个 Docker 容器并运行它。在阅读本文之前,请务必阅读为什么使用 Docker 进行机器学习和Docker 的快速安装和首次使用。
为了开始为机器学习模型构建 Docker 容器,让我们考虑三个文件: Dockerfile、train.py、inference.py.
你可以在 GitHub 上找到所有文件。
train.py 是一个 python 脚本,它接收并规范化 csv 文件(train.csv)中的 EEG 数据,并训练两个模型对数据进行分类(使用 scikit-learn)。该脚本保存了两个模型:线性判别分析(clf_lda)和神经网络多层感知器(clf_NN)。
将调用 inference.py 通过加载之前创建的两个模型进行批量推理。该应用程序将对来自 csv 文件(test.csv)的新 EEG 数据进行标准化,对数据集进行推理,并打印分类准确性和预测。
让我们创建一个简单的 Dockerfile ,使用 jupyter/scipy-notebook 图像作为我们的基本图像。我们需要安装 joblib 来允许我们的训练模型的序列化和反序列化。我们将 train.csv、test.csv、train.py 和 inference.py 文件复制到映像中。然后,我们运行 train.py ,它将拟合和序列化机器学习模型,作为我们映像构建过程的一部分,这提供了几个优势,例如在过程开始时进行调试的能力,使用 Docker 映像 ID 进行跟踪或使用不同的版本。
为了构建映像,我们在终端中运行以下命令:
docker build -t docker-ml-model -f Dockerfile .
输出如下所示:
是时候对新数据执行推断了(test.csv):
docker run docker-ml-model python3 inference.py
输出如下所示:
我们可以做一些事情来改善我们的集装箱化体验。例如,我们可以使用 docker 文件中的 WORKDIR 绑定容器中的主机目录:
在推论. py 中,我们可以决定保存一个输出. csv 文件,其中包含 X_test 数据:
当您构建并运行它时,您应该能够在 /mydata 中看到 output.csv 文件:
我们还可以在 Dockerfile 文件中添加 VOLUME 指令,生成一个将创建新挂载点的映像:
使用我们指定的名称, VOLUME 指令创建一个挂载点,该挂载点被标记为保存从本地主机或其他容器外部挂载的卷,我们在这些容器中找到我们想要处理的数据。
对于未来的开发,可能有必要从一开始就设置环境变量,只需在构建时设置一次,以便持久化训练好的模型,并可能向特定位置添加额外的数据或元数据。设置环境变量的好处是避免在代码中到处都是必要路径的硬代码,并且在一个商定的目录结构上更好地与他人共享您的工作。
让我们再举一个例子,用一个新的 docker 文件:
我们需要给 train.py 添加环境变量:
和推论. py :
下一步是什么?
我们的目标是通过简单的机器学习模型,产生快速简单的步骤来构建 Docker 容器。构建就像做一个docker build-t my-docker-image 一样简单。。
从这一步开始,我们可以开始部署我们的模型,这将更加简单,并消除发布和扩展您的机器学习模型的恐惧。下一步是用一个 CI/CD 工具(持续集成/持续交付)产生一个工作流,比如 Jenkins。得益于这种方法,可以在任何地方构建和服务 docker 容器,并公开 REST API,以便外部利益相关者可以使用它。如果您正在训练一个需要高计算需求的深度学习模型,您可以将容器移动到高性能计算服务器或您选择的任何平台,如内部、私有或公共云。这个想法是,您可以扩展您的模型,但也可以创建弹性部署,因为您可以跨区域/可用性区域扩展容器。
我希望您能看到容器提供的极大的简单性和灵活性。通过容器化你的机器/深度学习应用,你可以让它对世界可见。下一步是在云中部署它并公开它。在某些时候,您需要借助 Red Hat open shift(Kubernetes 发行版)等技术来协调、监控和扩展您的容器,以便为数百万用户提供服务。
来源
https://docs.docker.com/engine/reference/builder/
https://mlinproduction.com/docker-for-ml-part-3/
https://theaisummer.com/docker/
通过修剪构建更好的决策树
原文:https://towardsdatascience.com/build-better-decision-trees-with-pruning-8f467e73b107?source=collection_archive---------3-----------------------
通过限制最大深度和修剪减少决策树的过度拟合和复杂性
作者:爱德华·克鲁格、希德尔·邦戈尔和道格拉斯·富兰克林。
照片由 Ales Krivec 在 Unsplash 上拍摄
在另一篇文章 中,我们讨论了决策树或 CART 算法的基本概念,以及在回归或分类问题中使用决策树的优势和局限性。
点击这里阅读更多内容:
[## 了解决策树是如何生长的
towardsdatascience.com](/learn-how-decision-trees-are-grown-22bc3d22fb51)
有关决策树的视频介绍,请查看本 8 分钟课程:
**在本文中,**我们将重点关注:
- 决策树中的过度拟合
- 限制最大深度如何防止决策树过拟合
- 成本复杂性修剪如何能够防止过度适应决策树
- 在 Python 中实现一棵全树、一棵有限最大深度树和一棵修剪树
- 修剪的优点和限制
下面使用的 代码 在本 GitHub 资源库 中可用。
过度拟合和决策树
决策树容易过度拟合。如果我们允许决策树增长到其最大深度,它将总是过度适应训练数据。
当决策树被训练为完全适合训练数据集中的所有样本时,该决策树是过度适合的。您可以调整一些参数,如 min_samples_leaf ,以最小化默认过拟合。这种类型的调整被称为**预修剪,**但是超出了本文的范围。
你让你的树长得越深,决策规则的序列就变得越复杂。给一棵树指定一个最大深度可以简化它并防止过度拟合。
让我们来看看一个没有使用 Python 修剪的完整决策树:
这些 ipynb 单元包含导入、数据文件的路径以及构建和交叉验证树模型所需的变量。
现在让我们用 scikit-learn 来种出我们的第一棵树。
在这里,我们创建了full_tree
,一个 scikit-learns DecisionTreeClassifier
的实例。然后,我们将模型与训练数据进行拟合。
接下来,我们使用 matplotlib 来确定可视化的大小,使用 scikit-learn 的plot_tree
来绘制我们的树。
注意这棵树的大小。这个二元分类器中有多少规则?
如果你数的是“18”,你答对了。下面是这棵树遇到测试数据时的分类报告。
注意精确度,91。在我们构建下两棵树时,请记住这一点。
默认情况下,树会一直生长,直到每个叶节点中的所有点都来自同一个类。换句话说,直到每片叶子都纯。
怎样才能产生一个规则更少结果更好的树?
如何用最优最大深度简化决策树
现在让我们建立一棵树,并限制其最大深度。
在上面的第一个单元格中,我们找到了整个树的深度,并将其保存为max_depth
。我们这样做是为了从 1 → max_depth
建立一个网格搜索。
这种网格搜索建立深度范围为 1 → 7 的树,并比较每棵树的训练精度,以找到产生最高训练精度的深度。
最精确的树的深度为 4,如下图所示。
这棵树有 10 条规则。这意味着它是一个比完整树更简单的模型。
它在测试数据上的表现如何?
看那个!规则更少,准确率更高。当我们限制我们的最大深度时,我们确实建造了一个更好的模型。
然而,有时设置一个最大深度可能会过于苛刻,导致拟合不足。
我们如何以更精确的方式调整我们的树模型?
什么是修剪?
修剪是一种用于减少过度拟合的技术。修剪还通过删除最弱的规则来简化决策树。修剪通常分为:
- 预修剪(提前停止)在树完成对训练集的分类之前停止树,
- 后期修剪允许树对训练集进行完美的分类,然后对树进行修剪。
在本文中,我们将重点关注后期修剪。
修剪从一棵未修剪的树开始,获取一系列子树(修剪过的树),并通过交叉验证选择最佳的一棵。
修剪应确保以下几点:
- 子树是最优的,这意味着它在交叉验证的训练集上具有最高的准确性。(采油树可以针对对工程师最重要的任何参数进行优化,但并不总是精确的)
- 对最优子树的搜索在计算上应该是易处理的。
在 scikit-learns DecisionTreeClassifier
中,ccp_alpha
是成本复杂度参数。
本质上,修剪递归地找到具有“最弱链接”的节点最弱的链路由有效α来表征,其中具有最小有效α的节点首先被修剪。
数学上,树 T 的成本复杂性度量由下式给出:
- R(T) —叶节点的总训练误差
- |T| —叶节点数
- α —复杂度参数(整数)
随着 alpha 的增加,更多的树被修剪,这增加了树叶的总杂质。
如果只是试图减少训练误差 R(T) ,会导致树相对更大(叶节点更多),造成过拟合。
成本复杂性修剪生成一系列树,其中子树 Tₜ 的成本复杂性度量为:
参数 α 通过控制叶节点的数量来降低树的复杂度,最终减少过拟合。
最终选择哪个子树取决于α。如果α= 0*,那么将选择最大的树,因为复杂度惩罚项实质上被丢弃了。当α接近无穷大时,将选择大小为 1 的树,即单个根节点。*
为了了解什么样的ccp_alpha
值将有助于减小树的大小,scikit-learn 提供了一个函数cost_complexity_pruning_path
,它返回修剪过程中每一步的有效 alphas 和相应的总叶子杂质。
让我们构建最终的树模型,看看它的表现如何。
上面的每个ccp_alpha
代表一个最优子树。我们再次构建网格搜索来比较不同的树。这里,网格搜索比较每个最优子树的训练精度。
我们看到最准确的子树是由ccp_alpha
,0.0059340658…
现在让我们画出这棵修剪过的树。
这个模型只包含 5 条规则!
与以前的决策树图相比,修剪后的模型不太复杂,更容易解释,也更容易理解。
使用最大深度限制树的一半规则,我们已经达到了相同的精度。我们又一次改进了我们的模型!这一次,我们在保持性能的同时降低了复杂性。
修剪决策树的优势
- 修剪降低了最终树的复杂性,从而减少了过度拟合。
- 可解释性——修剪过的树更短,更简单,也更容易解释。
修剪的局限性
类似于套索正则化,没有真正的劣势。然而,修剪带来了很高的计算成本。
资源
- scikit-学习文档为cost 复杂性修剪 。
- PennState STAT 508 |应用数据挖掘和统计学习https://online.stat.psu.edu/stat508/lesson/11/11.8/11.8.2
进一步阅读
要继续学习相关概念,请查看这篇由 Aliaksandr Kazlou 撰写的关于随机森林和过度适配的文章。
用 LASSO 构建更好的回归模型
原文:https://towardsdatascience.com/build-better-regression-models-with-lasso-271ce0f22bd?source=collection_archive---------10-----------------------
学习如何在 SciKit 中实现 LASSO 学习提高线性回归的可解释性和性能
由爱德华·克鲁格和艾琳·欧菲琳
照片由普里西拉·杜·普里兹在 Unsplash 拍摄
在本文中,我们将介绍使用 LASSO 回归需要了解的基础知识:
- 我们将简要介绍拉索背后的理论。
- 我们将讨论为什么正确使用套索需要具有相似比例的特征。
- 我们将讲述如何用标准化特征解释线性回归和套索回归中的系数。
- 我们将介绍数据集,并给出一些见解为什么 LASSO 帮助。
- 我们将在 SciKit-Learn 中展示如何实现线性回归、套索回归和岭回归。
浏览理论的表面
在上一篇文章中,我们讨论了 LASSO 如何以及为什么提高广义线性模型的可解释性和准确性。我们将在这里重述基础知识,但是如果你有兴趣深入研究这个理论,可以看看下面的文章。
https://edkruegerdata.com/lasso-increases-the-interpretability-and-accuracy-of-linear-models-c1b340561c10
我们可以使用套索通过选择特征来改善模型中的过度拟合。它与线性回归,逻辑回归和其他几个模型。本质上,如果模型有系数,可以使用 LASSO。与其他特征选择技术不同,LASSO 中的特征选择是内生的。即,它出现在模型的算法内部。LASSO 不是查看要素的每个组合或实施逐步子集选择,而是在算法中选择要素,自动生成子集选择。
LASSO 的工作原理是对损失函数应用 L1 罚函数。由于 L1 罚函数所隐含的约束区域的形状,LASSO 可能选择系数的备用估计。即,一些系数可能被设置为 0,并且实际上,这些特征被移除。惩罚系数越大,趋势越明显。
具有较少的特征通常会减少模型中的过度拟合,这可能会提高模型的可解释性。提高模型的复杂性通常会减少测试误差。
数据集
我们将使用 SciKit-Learn 的糖尿病数据集演示 LASSO。你可以在这里找到数据集【1】。该数据集非常适合演示 LASSO,因为它的所有要素都是数值型的。当分类变量存在时,可以使用 LASSO,但当缩放时,它们可能很难解释。
数据集中的目标是对糖尿病进展的数值评估。这些特征包括年龄、性别、体重指数(身体质量指数)、血压和标记为“s1”到“s6”的六个血清测量值。
使用与StandardScaler
使用的过程相同的过程对特征进行缩放。但是,整个数据集已被用于计算每个要素的平均值和标准差,因此从技术上讲,存在一些可能无害的数据泄漏。我们将使用管道中的StandardScaler
来重新调整数据集,该管道将仅使用训练集来重新调整数据,以计算平均值和标准差。这将使我们的演示适用于尚未缩放的数据。
我们来看看特征之间的相关性。我们在下面包括相关矩阵和相关的绝对值。通过查看绝对值,可以更容易地看出相关性的强度。
相关矩阵(来源:作者)
相关矩阵的逐元素绝对值(来源:作者)
查看特性之间的相关性,我们可以看到特性之间存在一些共线性。特别地,s3 和 s4 高度负相关,s2 和 s4 高度相关。所有的血清测量值都有显著的相关性。LASSO 更有可能移除相关要素集中的要素,因此如果 LASSO 移除要素 s2、s3 和 s4 中的一个或两个,也不会令人惊讶。另一方面,LASSO 基于交叉验证的度量选择正则化强度,即惩罚强度。因此,如果一个特征背后有一些额外的解释力,即使它与另一个特征密切相关,也可能不会被删除。
缩放对套索很重要
在我们进入代码之前,我们需要更深入地理解缩放。如果我们想在 SciKit-Learn 中正确地应用 LASSO,我们需要首先缩放我们的数据。与线性回归不同,LASSO 中的要素缩放至关重要。这是因为 LASSO 的罚函数包含了特征系数的绝对值之和。
为了更好地理解这一点,让我们来理解缩放是如何影响线性回归的。
线性回归的拟合不受线性变换的影响
虽然这并不能完全构成一个证明,但让我们看看为什么“*特征的线性变换不会影响线性回归做出的预测”*的说法是正确的。我们会看看一元线性回归,但是
给定一个特征“x”,对于任何数字“a”和“b”,该特征的线性变换可以写成如下形式。
x 的线性变换(来源:作者)
回想一下,特征“x”的单变量线性回归的形式可以写成如下形式。优化选择系数,使平方和最小。
x 的线性回归形式(来源:作者)
对于转换后的特征,可以写成如下形式。再次选择系数以最小化平方和。
变换特征的线性回归形式(来源:作者)
在定义中代入转换后的特征,我们得到以下结果。
重写的变换特征的线性形式(来源:作者)
让我们看看分组术语。对于这两项,总项可以取任何值,并且我们已经从未变换的问题中知道了最佳系数。因此,实际上,转换后的形式等同于未转换的形式。
这是系数的变化
在其他条件不变的情况下,如果我们将一个特征除以 1000,那么系数会发生什么变化?举个更具体的例子,如果我们以“米”为特征,1 米对目标的作用是 1,那么 1 公里对目标的作用是什么?
看看上面的数学,或者咨询一下你的直觉。转换的效果是将系数乘以 100。
记住 LASSO 根据系数的大小增加了一个惩罚,现在看到缩放可以影响系数,我们可以看到不同的缩放会如何导致 LASSO 中最佳系数的不同选择。
标准化是一种线性转换
在 SciKit-Learn 中作为StandardScaler
提供的标准化是一种线性转换。如果你想确定的话,看看 SciKit-Learn 文档中定义的这里的缩放程序,并把它改写成线性变换的形式。MinMaxScalar
也采用线性变换。
用比例特征解释线性回归
StandardScaler
通过将每个观测值转换为一个新的尺度来单独转换每个特征,该尺度表示观测值相对于平均值的标准偏差。
让我们来看看代码
我们将跳过如何加载数据集并将其分成训练集和测试集。如果您想更深入地了解这一部分,可以在这里查看与本文相关的资源库。
线性回归
为了预先用缩放步骤拟合线性回归,我们可以使用 SciKit-Learn Pipeline
。SciKit-Learn 提供了一个简单的接口来创建一个带有make_pipline
的Pipeline
,我们将在下面使用。
制作和训练线性回归管道(来源:作者)
因为以模型结尾的Pipeline
——从技术上讲是Estimator
的子类——行为就像模型一样。由于这条管道在一个模型实例LinearRegression
中结束,我们可以用.fit()
方法训练它。
计算 MSE(来源:作者)
为了验证Pipline
实例,我们可以使用它的 predict 方法来获得估计值并计算均方误差(MSE)。这里我们的 MSE 是 2900 左右。
为了得到系数,我们必须从流水线的最后一步提取它们。幸运的是,Pipeline
中的步骤可以像数组元素一样被索引。我们使用-1
索引糖来检索线性回归。
提取和显示线性回归系数(来源:作者)
为了解释这些系数,请记住,每个特征都经过缩放,因此一个单位的变化代表标准差的一个单位的变化。因此,对于每个特征,我们可以将每个系数解释为目标变化对平均值的一个标准差的影响。例如,以身体质量指数为例,身体质量指数值与平均值的一个标准差会使一个人的糖尿病进展增加 25.6 倍。
套索回归
sci kit-了解回归问题中 LASSO 的一些不同实现。最常见的两个Lasso
和LassoCV
。你可以在这里找到文档页面这里和这里。两者的区别在于Lasso
希望您设置惩罚,而LassoCV
使用交叉验证的 MSE (CV-MSE)执行网格搜索,以找到正则化强度的最佳选择。实际上,除非您以前处理过相同或非常相似的数据集,否则您永远不会知道罚超参数的理想值。因此,在实践中,您几乎总是会使用LassoCV
——这里我们也是这样做的。
与使用管道时的情况一样,用于训练和验证的代码几乎是相同的——这是使用管道的优势之一。除了从LassoCV
的实例中提取系数,我们还可以根据 CV-MSE 提取最优的正则化 str。让我们看看结果。
Lasso 回归的代码和结果(来源:作者)
请注意,MSE 略有下降,这意味着我们得到了一个更准确的模型。通过查看系数,我们可以看到线性回归和套索之间的变化。LASSO 将年龄 s2 和 s4 设置为 0,有效地将它们从模型中排除。
里脊回归
值得一提的是,有一种在计算上和理论上与 LASSO 非常相似的技术叫做岭回归。它将稍微不同的约束区域应用于损失函数,并且不是选择特征,而是收缩所有的系数。此外,SciKit-Learn 中的代码几乎是相同的,因此不涵盖它将是一个遗憾。那么,让我们来看看。
岭回归的代码和结果(来源:作者)
对于这个数据集,岭回归没有做得很好,但我们可以看到,一般来说,系数较小。
如果你想了解更多关于岭回归的知识,可以看看下面这篇由 Qshick 撰写的文章!
比较系数
最后,让我们将三种不同技术的系数可视化!我们可以看到,岭回归发现几乎所有系数都更小,更接近于 0,其中 LASSO 将一些系数设置为 0。对于这个数据集,更稀疏的系数也导致具有更低 MSE 的更精确的模型。拥有更少的特征,它也更容易被理解。
系数图(来源:作者)
我们希望你喜欢这篇文章!要了解更多关于数据科学、机器学习和开发的内容,请查看 Edward 的 YouTube 频道,并订阅我下面的邮件列表,成为第一个听到新文章的人!
https://edkruegerdata.com/subscribe [## 每当爱德华·克鲁格发表文章时,就收到一封电子邮件。
edkruegerdata.com](https://edkruegerdata.com/subscribe)
参考
[1]sci kit-learn:Python 中的机器学习,Pedregosa 等人,JMLR 12,第 2825–2830 页,2011 年。
构建更好的时间序列模型:ByteHub 简介
原文:https://towardsdatascience.com/build-better-time-series-models-introducing-bytehub-98b548b98977?source=collection_archive---------35-----------------------
了解如何使用要素存储来简化您的数据科学工作流
数据管道对机器学习至关重要。西格蒙德在 Unsplash 上拍照。
本文介绍 ByteHub:一个开源的特性库,,旨在帮助数据科学家建立更好的时间序列数据模型,准备用于预测和异常检测等任务。虽然我们经常关注用于这些任务的机器学习技术和算法,但数据管道经常被忽视,尽管它对于开发高质量的模型以及能够将其作为更大项目的一部分进行部署和维护来说至关重要。
我们将探索在构建时间序列模型时改进数据科学工作流的三种方式,并通过示例演示如何使用 ByteHub。
获取数据
模型的好坏取决于它们接受训练的输入数据。对于任何使用时间序列模型的数据科学家来说,一项重要的任务是确定要使用的数据源。结果可能是戏剧性的:例如,在处理零售、能源、运输和其他部门的各种建模问题时,包含单个天气变量的结果通常会大大提高准确性。
添加天气数据会使伦敦自行车租赁数据的时间序列模型产生很大的性能差异1。
不幸的是,向模型中添加新的数据源通常不是一件容易的事情。数据集经常被锁在不同的数据库中或复杂的 API 后面,这使得很难快速迭代不同的数据输入并找到最好的。
ByteHub 通过两种方式解决了这个问题。首先,通过提供一种简单的方法来存储时间序列数据,以便可以轻松地访问、过滤、重新采样并输入模型。例如,以下代码片段演示了如何加载多个时间序列要素并将其重新采样到每小时分辨率,以便在模型训练中使用,而无需任何额外准备。
快速加载和重新采样时间序列特征。
其次,这些数据集存储有描述和额外的元数据,并且可以从简单的 Python 接口中进行搜索。数据科学家可以更轻松地搜索和重用现有数据,在更短的时间内开发出更好的模型,而不是在每个新项目上重新发明轮子。
在 Python 中快速搜索数据集和要素。
准备数据
找到正确的数据后,下一步是在将数据输入模型之前准备和转换数据。被称为特征工程,它允许我们使用我们自己的领域专业知识来提高模型性能。
ByteHub 引入了一个叫做特征转换的概念:可以应用于原始时间序列数据的 Python 代码片段。这些可以链接在一起,允许您构建非常复杂的功能工程管道,然后发布这些管道,以便在不同的项目和模型之间重用。
例如,在这个天气预报示例中,我们需要将风速和风向转换为 x 和 y 风速,因为否则我们使用的模型将很难正确解释风的角度。下面的 Python 函数包含了实现这一点所需的数学知识,而 decorators 将这些转换添加到特性库中,以便可以重用它们。
使用 Python 函数将原始时序数据转换为模型要素。
保持整洁!
在过去,所有这些数据管道很容易产生难以理解和维护的代码鸟巢。通过使用特征库,可以将数据准备从模型训练代码中分离出来。这不仅使模型更容易理解,也使更容易部署:数据加载和准备可以用一行代码完成。例如,ByteHub 中的典型模型训练脚本如下所示,其中包含加载数据、构建和训练模型的简单而清晰的步骤。
一旦所有的数据准备都转移到特征存储中,模型训练代码就会变得更加简单和易于理解。
最后的想法
我希望这篇文章能激发你在下一个时间序列建模项目中尝试 ByteHub。如果你想试一试,完整的文档和安装说明在 GitHub 上。
https://github.com/bytehub-ai/bytehub
所有的教程和示例都可以从 Google Colab 笔记本上运行。
如果您有任何想法、意见或问题,请在下方留言或直接联系我们。
1伦敦交通局:桑坦德循环雇佣计划的雇佣总人数,按日、月、年统计。
使用 Argparse 在 Python 中构建命令行界面
原文:https://towardsdatascience.com/build-command-line-interfaces-in-python-using-argparse-6031daa28252?source=collection_archive---------24-----------------------
在 Python 中使用命令行授权!
Argparse 是一个内置的 Python 库,有助于在 Python 代码上构建命令行界面。Argparse 意味着解析参数。当我第一次听 Argparse 时,我感到害怕,但一旦我开始探索和学习,它就成为我的脚本中不可或缺的一部分。它为您的 Python 代码提供了额外的灵活性。您可以发送您修改的参数、参数选择等。通过命令行和 Argparse 会照顾它。下图解释了我对 Argparse 的理解:
作者创造的形象
为了实时解释这一点,让我们从一个基本的例子开始。让我们假设我们有下面的脚本 argparsetest.py. 该脚本可以根据用户输入执行两个变量的加法或减法。
在这里,我们只定义了两种可能性“add”或“sub”。如果用户两者都没有提供,它将作为无效操作返回(以黄色突出显示),如下面的屏幕截图所示:
用户可以通过提及下面的语法来传递参数:
关于库的更多详细信息:
**💡位置参数:**您需要在每次执行脚本时指定这些参数。如果没有提到默认值,则不能跳过它们,因为默认值是必须提供的。例如,在我们之前提到的示例中,如果我们只是要求用户从命令行提供 b 的值,则需要对脚本进行如下微调:
显示位置参数的脚本
命令行中的命令如下所示:
带有位置参数的命令
如果我们不指定“b”输入,我们会得到类似下面这样的错误:
不带位置参数的命令
如果有多个位置参数,它需要按照脚本的特定顺序出现。试试看,看看效果如何!
**💡可选参数:**与 positional 相反,这些参数可以是可选的,不指定也可以。将默认值添加到位置参数会转换为可选参数,如以下脚本所示:
显示可选参数的脚本
如前所述,如果我们不指定参数,它将采用默认值并执行脚本,没有任何错误
不带参数的命令
**💡获得帮助:**如果你想知道脚本中需要/使用的参数,你可以通过添加“- h”获得帮助。下面的截图显示了如何做到这一点:
**💡设置值的数量:**如果您想为一个变量提供多个值作为输入,您也可以这样做。传递的值以列表的形式读取。例如,添加' c '作为参数,并将 nargs 定义为 3,,这意味着需要 3 个输入值。
带 nargs 的脚本
我们通过命令行将这些值传递给 c ,如下所示:
**💡设置输入参数的类型:**你可以明确地指出需要什么类型的输入。例如,我们只需添加' int '作为 b 的必需变量,如果用户未能提供所需输入类型的输入,脚本将抛出一个错误。该脚本将更改如下所示的内容:
如果我提供字符串而不是整数到 b 它将抛出如下错误:
总之,argparse
library 是通过命令行界面提供用户友好方法的完美方式!这些只是开始使用 argparse 的基础。如果你有任何其他的诀窍/技巧,请随时评论。感谢您的宝贵时间!
在 Twitter 或 LinkedIn 上关注我。你也可以通过 pratikkgandhi@gmail.com 联系我
如何构建和部署 React + Flask 应用程序
原文:https://towardsdatascience.com/build-deploy-a-react-flask-app-47a89a5d17d9?source=collection_archive---------0-----------------------
简单易懂的教程
简明指南
Zan 在 Unsplash 上的照片
当我试图弄清楚如何构建和部署我的 React + Flask 应用程序时,我设法在网上找到了各种教程。我所做的是,我首先谷歌并找出如何构建 React+Flask 应用程序,然后我试图搜索如何部署它。
可惜我好不容易找到的大部分教程都太复杂了(个人观点)。如果你谷歌“如何建立一个 React Flask App”,这里是我的前三个结果:链接、链接、链接。
它们可能是很棒的教程,但是如果你现在不想为 Nginx、各种配置和额外的包**(你只是想从 Flask 返回一些东西进行反应,然后开始在线查看它的部署),你可能想试试这个教程。**
它分为三个部分——后端(Flask)、前端(React ),最后是在 Heroku 上的部署。这是 GitHub 回购协议——https://github.com/Reine0017/reactFlaskTutorial。
我们开始吧!ʕ•́ᴥ•̀ʔっ
第 1 部分—后端(烧瓶)
根据您自己的需求,您可能需要预先安装必要的 python 包。我使用 pip 安装了我需要的所有包,而没有使用虚拟环境(尽管这是强烈推荐的)。要创建一个名为 venv 的新 python 虚拟环境(您可以将其命名为其他名称,只需将下面命令中的最后一个 venv 替换为您自己的 venv 名称),请运行:****
python -m venv venv
要激活 venv:
source venv/bin/activate
我们将首先从后端烧瓶设置开始。有许多方法可以构建您的项目,但是要稍后在 Heroku 上部署,Procfile 必须在根目录中公开(稍后将详细介绍 Procfile)。在根目录中,创建一个名为 app.py 的文件。
暂时忽略其他文件
这是我们运行 flask run 时运行的东西。我将我的命名为 app.py,但是你可以选择将它命名为除 flask.py 之外的任何名称,因为这将与 flask 本身相冲突。
在第 6 行,我们创建了 Flask 类的一个实例。参考官方的 Flask 文档,你会注意到在我的例子中还有两个参数(static_url_path 和 static_folder)。static_url_path 可用于为 web 上的静态文件指定不同的路径,它默认为 static_folder 文件夹的名称。static_folder 指向 react 项目的构建目录(因为我将子目录命名为 frontend,所以在我的例子中是 frontend/build——相应地更改它)。
第 10–12 行:@app.route decorator 告诉 Flask 哪个 URL 应该触发我们的 serve(path)函数。最后,send_from_directory 允许我们从“前端/构建”目录发送“index.html”文件。
第 3、7 行:这是为了消除我们在向不同的域发出 API 请求时经常遇到的恼人的 CORS 错误。在当前阶段(部署之前),React 在端口 3000 上运行,Flask 在端口 5000 上运行。因此,当 React 向 Flask 后端发出请求时,会弹出这个 CORS 错误。关于 CORS 错误的更多信息,请查看这个或这个链接。
第 4、8、14 行:为了可读性,我将 HelloApiHandler.py 放在了一个名为 api 的子目录中。
在我的 HelloApiHandler.py 中只有两个简单的 GET 和 POST 函数来处理对这个 API 端点的 GET 和 POST 请求:
要检查一切是否正常,请键入
$ flask run
在您的终端中,然后转到 localhost:5000/flask/hello(上面 app.py 中的参考行 14 ),您应该会看到:
事情正在解决:')
第 2 部分—前端(反应)
接下来,我们将在项目目录中为前端(React)创建一个文件夹。我把我的叫做“前端”。
cd 放入前端文件夹并运行
npx create-react-app .
这将创建一个新的 React 项目。
在您的 app.js 文件中,进行以下更改来测试我们对 flask 后端的 GET 请求。
如果一切正常,您应该会看到:
原谅偏心裁剪,只是想表明它在 localhost:3000 上
好极了,所以它在本地工作!让我们试着把它部署在 Heroku 上。
第 3 部分 Heroku 上的部署
对于 Heroku,设置一个帐户,然后创建一个新的应用程序。在您的设置选项卡中,您可以向下滚动并看到如下内容:
https://react-flask-tutorial.herokuapp.com是你的用户访问你的应用的网址
https://react-flask-tutorial.herokuapp.com/flask/hello是我们将从 React 前端发出请求的后端端点。因此,在 App.js(前端)中,将 axios . get(' http://localhost:5000/flask/hello ')更改为 axios . get(' https://react-flask-tutorial . heroku app . com/flask/hello ')。
我们必须做的另一个小编辑是在我们的后端(App.py)注释掉与 CORS 相关的内容。
接下来,在前端目录中,运行 npm run build:
这将创建我们的构建文件夹:
在根目录中,创建一个 Procfile,并在其中写入:
web: gunicorn app:app
记得记下空格!!
接下来,要生成 requirements.txt,将 cd 放入这个项目的根目录并运行:
pip freeze >> requirements.txt
我个人不得不在 requirements.txt 中注释掉 TBB 行,以使部署工作。不太清楚为什么。
因为我已经有了一个现有的 heroku 应用程序(我在 heroku 的网站上创建了一个新的应用程序),所以我只运行了:
接下来,就像你将如何提交给 GitHub 一样,做通常的事情:
git add .
git commit -m "first deployment"
git push heroku master
注意最后一行是 heroku 而不是 origin。
然后等待并希望它能起作用:')
是的,它有效!!
好了,这就是本教程,让我知道你是否有任何问题或面临任何问题:)
快乐的通货膨胀!_( ͡❛ ͜ʖ ͡❛)_/
我真的不喜欢无耻的插头,但如果你已经在考虑每月 5 美元获得中等会员资格,如果你能使用我的推荐链接来注册,我会非常感激-【https://reine-ran.medium.com/membership:】
即使您不知道如何编码,也要构建 ETL 数据管道
原文:https://towardsdatascience.com/build-etl-data-pipelines-even-when-you-dont-know-how-to-code-a6f09f60364d?source=collection_archive---------42-----------------------
当您想要的只是通过简单的步骤将分散在各处的良好数据集中到一个位置,以便快速洞察业务时,不要让编码和基础设施的复杂性阻碍您。
作者图片
了解如何整合各种来源的数据并执行简单的转换来解决数据质量问题是从大数据中获取洞察力的第一步。在这篇博文中,我们将探讨如何在谷歌云平台(GCP)上通过云数据融合构建和部署简单的 ETL 数据管道,而无需编码。
你将了解:
- 为什么我们需要云数据融合?
- 如何用云数据融合构建和部署 ETL 管道?
为什么我们需要云数据融合?
问题:你从大数据中获得深刻见解的第一个障碍
尽管复杂的数据分析和机器学习技术越来越受欢迎,但有些事情从未改变。获得伟大洞察力的第一个障碍通常是数据集成,包括将分散在各处的相关数据收集到一个单一的统一位置,并执行许多预处理步骤以使其清晰可用。
我们的数据集成需求可能非常简单,比如删除空值、将各种数据集连接在一起、删除不相关的列或者将所有数据放入数据仓库以供快速查询。然而,作为一个技术知识有限的业务用户,这样简单的需求可能会引发不适,因为您经常不得不考虑两个同样不方便的选项。
- 你需要学习如何自己编写代码
- 你必须等待一段时间,直到数据工程团队有足够的带宽来帮助你建立一个定制的数据管道(让我委婉地提醒你,在现实中,不是每个公司都有足够的预算来聘请数据工程师,更不用说资助数据工程团队了。)
怎么样,棕色的母牛?
解决方案:云数据融合如何提供帮助
由开源项目 CDAP 提供支持,云数据融合是一个完全托管的云原生企业数据集成服务,用于快速构建和管理数据管道。
—来自谷歌云
有了谷歌云平台上可用的云数据融合,你不必知道代码如何让简单的事情发生。简而言之,这就是你可以通过云数据融合做的事情。
- 构建数据管道,从多个来源收集数据,并将其放入一个位置进行查询和提取见解
- 转换数据以解决任何数据质量问题,或将数据转换成可用的格式
- 自动管理部署数据管道的所有方面,例如配置基础架构、集群管理和作业提交
这和你有什么关系?用外行人的话来说,这就是为什么它很重要。
无需编写任何代码,您不必成为每一个数据源的专家,就可以将所有数据整合在一起,获得快速的洞察力。在编码上花费更少的时间(并确保它一直工作)意味着有更多的时间来了解您的数据,回答更多关于业务绩效和如何做出更好决策的紧迫问题。有什么不喜欢的?
此外,**由于数据管道的部署是自动化和完全管理的,你不必担心 IT 基础设施。这意味着更快地获得您想要的结果,而不必担心后端的管理工作。**毕竟,为什么业务用户要费心去理解基础设施意味着什么,或者如何配置实例或管理集群呢?
如何才能使用云数据融合?
说得够多了,让我们看看如何构建和部署一个简单的 ETL 管道,结合两个不同的数据源。
初始设置
先决条件
这是你开始之前需要的。
- 创建谷歌云项目和启用计费
- 通过导航菜单> IAM & Admin > IAM 检查与您的帐户相关的角色和权限。您需要管理员权限来启用云数据融合 API
创建云融合实例
- 在 GCP 控制台主页面上,在搜索框中键入“云数据融合”。
2.选择云数据融合 API 。
作者图片
3.看到下面的屏幕后,选择启用。
作者图片
4.刷新页面并选择导航菜单。向下滚动到大数据,选择数据融合。
作者图片
5.点击创建一个实例。
作者图片
6.按照屏幕上的说明输入实例的名称。选择基本作为版本类型,并将所有其他字段保留为默认值。点击创建。但是如果你看到创建按钮是灰色的(就像下面的截图),确保先点击授予权限。
作者图片
7.单击创建后,实例创建过程可能需要大约 15–20 分钟。一旦创建完成,你会收到一个通知铃按钮在哪里。
作者图片
8.创建实例后,让我们授予与新数据融合实例相关联的服务帐户对项目的权限。要继续,请单击实例名称(不是视图实例)并将服务帐户复制到剪贴板。
作者图片
9.进入导航菜单> IAM & Admin > IAM ,点击添加。
作者图片
10.将复制的服务帐户添加为新成员。点击选择角色,在过滤框中输入 云数据融合 。在所有过滤选项中,选择云数据融合 API 服务代理角色。然后点击保存。
作者图片
11.在继续下一步操作之前,请确保与新创建的数据融合实例相关联的服务帐户作为您的项目的授予权限之一可见(类似于下图)。
作者图片
创建 ETL 数据管道
计划
为了比较和对比 COVID19 在不同国家传播的严重性,我们通常可以查看病例和死亡的总数。然而,如实地描述病例和死亡人数是行不通的,因为每个国家的人口规模都有很大的不同。
考虑到不同的人口规模,一个更常见的方法是比较每 100,000 人口中的病例和死亡总数。
每 10 万人口总发病数=总发病数/人口 10 万*
不幸的是,病例数和死亡数的信息不包括人口数据。因此,我们将构建一个 ETL 管道来使用云数据融合将一个 CSV 文件(包含病例和死亡总数)与一个 BigQuery 表(包含每个国家的人口)结合起来。
这篇博文使用的数据集摘自新冠肺炎公共数据集,该数据集可在谷歌云平台或 this GitHub 上获得。在我们使用流水线之前,下面是我们的计划。
作者图片
加载 CSV 数据
- 从导航菜单中,进入数据融合并点击查看实例。
作者图片
2.按照屏幕上的提示,您应该能够看到如下所示的云数据融合 UI。由于我个人想从一些数据探索入手,点击牧马人。如果您想探索其他选项,请随意尝试 UI。
作者图片
3.让我们将 CSV 数据集加载到管道中,方法是选择左侧的云存储默认值,并单击包含每个国家一段时间内的病例数和死亡数的存储桶的名称。
作者图片
4.选择表名。
作者图片
5.一旦从 CSV 加载了数据,您可能会注意到所有属性都组合在同一个 body 列下。所以我们必须将 CSV 数据解析成适当的列。点击位于 body 栏左侧的向下箭头,选择解析> CSV 。
作者图片
6.选择适当的分隔符并勾选框,选择第一行作为标题。然后点击应用。
作者图片
7.随着不同的属性被拆分到各自的列中,我们现在可以开始研究我们的数据集了。看看下面的截图。您能猜出为什么有些列(如 country_name)全是绿色,而 subregion2 _ code 显示一点绿色,而大部分是红色吗?
**提示:**红色代表每列空值的比例。简单地说,如果条形的大部分是红色的,您可以很容易地注意到,由于缺少许多值,数据属性对于分析可能不是很有用。
作者图片
8.以更直观的方式探索数据的另一个有用功能是 Insights 。例如,在这里我可以很容易地观察到这个数据集包含从 0 到 3 的不同级别的聚合。这是我必须小心处理的事情,因为我只对国家一级的数字感兴趣,而不是次区域一级的数字。
提示:**不要急于下结论,因为这些见解是从数据集中的 1000 个样本中产生的。**这可能有助于初步理解,但并不代表整个数据集中的所有可用信息。
作者图片
转换 CSV 数据
在详细检查了 CSV 数据之后,下面是一些常见的数据转换步骤,我们可以通过这些步骤将原始数据清理和整形为可用的格式。
按特定值过滤行
如上所述,数据集包括每个国家的新冠肺炎病例和死亡人数(这是我们想要的),以及每个次区域的数字(这是我们不想要的)。
要仅保留国家级别的数字,单击 aggregation_level 列旁边的向下箭头,并过滤以保留 aggregation_level = 0 的行
作者图片
删除冗余列
在右侧的菜单中,勾选方框以选择您想要保留的列。然后点击任一选定列旁边的向下箭头,并点击保持选定列。
作者图片
删除冗余列后,点击#旁边的向下箭头,并选择清除所有以返回正常数据视图,进行后续转换步骤。
作者图片
将字符串转换为数值数据类型
对于每个数字列(如 new_confirmed、new _ deceased、cumulative_confirmed、cumulative _ deceased),点击向下箭头,选择更改数据类型,选择整数或小数。
作者图片
解析字符串到日期
要将字符串转换为适当的日期类型,对于每个日期列,单击向下的箭头,选择解析>简单日期。
作者图片
选择合适的日期格式,点击应用。
作者图片
更改列名
要将原来的列名更改为更直观的名称(例如从 cumulative_confirmed 更改为 total_case),双击列标题,输入新名称并按回车键。
作者图片
对 CSV 数据的最终格式满意后,点击创建管道,然后选择批处理管道。
作者图片
但是请记住,我们还需要我们的人口数据,这些数据目前位于 Google BigQuery 表中。所以让我们把它带进来。
加载包含人口数据的 BigQuery 表
- 从左边的菜单中,导航到源并选择您试图集成的数据源。这里我选择了大查询。
作者图片
2.一旦 BigQuery source 的新节点出现,将鼠标悬停在 BigQuery 节点上并单击属性。
作者图片
3.选择浏览。
作者图片
4.导航到您想要集成的 Google BigQuery 表
作者图片
5.要验证 BigQuery 表是否包含您正在寻找的正确信息,请单击获取模式。BigQuery 表的所有列都将出现在向导的右侧,供您查看。
作者图片
从模式中可以看出,我们不需要 BigQuery 表的每一列。所以让我们剔除我们不需要的。但是首先,我们需要退出 BigQuery 属性。
6.单击右上角的 X 按钮,退出 BigQuery 属性并返回数据管道。
作者图片
转换 BigQuery 数据
- 为了消除多余的列,我们将需要使用牧马人。在左侧菜单中,导航至变形并选择牧马人。
作者图片
2.要将两个节点连接在一起,请拖动 BigQuery 节点右边缘的连接箭头,放在新的 Wrangler 节点上。将鼠标悬停在新的牧马人节点上,点击属性。
作者图片
3.为了避免与我们用来转换 CSV 数据的前一个 Wrangler 节点相混淆,让我们通过指定一个新标签给这个节点一个新名称。点击辩论配置清理和整形数据的步骤。
作者图片
4.导航并选择包含我们需要清理的人口数据的 BigQuery 表。
作者图片
5.对于这个人口数据集,我们只需要“key”和“population”列。因此,类似于我们如何消除 CSV 文件的冗余列,在右边的菜单中,勾选框以选择您想要保留的列。然后点击任一选定列旁边的向下箭头,并点击保留选定列。
作者图片
6.点击应用返回到属性视图。然后单击右上角的 X 按钮,退出 BigQuery 属性并返回到数据管道。
作者图片
将两个数据源连接在一起
是时候将新冠肺炎数据和人口数据结合在一起了。这一次,我们将需要使用 Joiner 节点,它位于分析部分之下。
- 从左侧菜单中,导航至分析并选择连接器。
作者图片
2.一旦新的 Joiner 节点出现在屏幕上,通过拖放连接箭头将两个牧马人节点连接到 Joiner 节点。然后将鼠标悬停在 Joiner 节点上,单击属性来配置这两个表应该如何连接在一起。
作者图片
3.指定连接类型和连接条件。这里我们做了一个内部连接来匹配人口数据集中的“key”列和新冠肺炎数据集中的“location_key”。单击获取模式以验证输出列是否是您正在寻找的。
作者图片
4.对输出满意后,单击右上角的 X 按钮,退出连接器属性并返回数据管道。
在 Google BigQuery 中存储最终数据集
由于我们已经成功地将新冠肺炎数据和人口数据缝合在一起,ETL 管道的最后一步是将所有数据加载到一个存储位置(即一个接收器),以便您可以随时回去分析数据。
在这里,我选择将最终数据集存储在 Google BigQuery 中,因为我可以轻松地使用 SQL 查询它来计算每 100,000 个国家的病例和死亡人数,或者将其与任何数据可视化工具(如 Tableau、Google Data Studio 等)相连接。
- 从左侧菜单中,导航至接收器并选择大查询。
作者图片
2.将 Joiner 节点连接到新创建的 BigQuery 节点。将鼠标悬停在 BigQuery 节点上,点击属性来配置数据存储。
作者图片
3.指定您想要存储组合数据集的引用名称、项目 ID、数据集和表。
作者图片
4.为确保所有内容都被正确指定,点击验证。当您看到未发现错误时,单击右上角的 X 按钮退出 BigQuery 属性并返回数据管道。
作者图片
查看 ETL 数据管道
最后,我们已经完成了第一个 ETL 数据管道的构建,将新冠肺炎数据和人口数据结合起来计算每 100,000 人口中的病例数和死亡数。这是我们简单的 ETL 数据管道目前的样子。大家一起击鼓吧!
作者图片
在直接进入部署之前,我强烈建议花 15-20 分钟从头到尾回顾一下 ETL 管道,并给管道命名。
提示:不要忘记给每个节点取一个有意义的名字。你最不希望的是 3 个月后,你发现自己盯着 5 个不同的牧马人节点,挠头试图理解 Wranger3 和 Wranger5 之间的区别。让我们善待自己,善待任何可能继承这个 ETL 管道的人,好吗?
部署 ETL 管道
好吧!是时候看看我们的 ETL 管道在运行了。你准备好了吗?
- 在页面右上角,点击部署。
作者图片
2.看到以下屏幕后,点击运行立即启动数据整合过程。或者,您可以点击计划来设置该 ETL 数据管道的每日或每周执行,或者监控状态。请注意,需要一段时间才能完成,状态将变为成功。
作者图片
在 BigQuery 中计算每 100,000 人口的病例和死亡总数
一旦 ETL 管道运行完成,下面是您可以在 BigQuery 中看到的组合数据集。
作者图片
由于新冠肺炎数据和人口数据现在很好地结合在一起,编写一个 SQL 查询来计算一段时间内每 100,000 人口的病例和死亡总数再简单不过了。
SELECT
EXTRACT(DATE FROM date) AS record_date,
country_name,
new_case/ population*100000 AS new_case_per_100k_pop,
new_death/ population*100000 AS new_death_per_100k_pop,
total_case/ population*100000 AS total_case_per_100k_pop,
total_death/ population*100000 AS total_death_per_100k_pop
FROM `covid19-305322.epidemiology.covid19_with_population_data`;
作者图片
包扎
面对现实吧!在编码和管理基础设施上花费更少的时间意味着有更多的时间来了解您的数据,回答更多关于业务绩效和如何做出更好决策的紧迫问题。云数据融合只是市场上许多其他数据集成解决方案中的一种,这些解决方案可以帮助业务用户将分散在各处的良好数据集中到一个位置,而不必担心编码或管理基础架构的复杂性。现在是时候为业务用户提供工具和功能,将大数据快速转化为业务洞察力,同时保持简单的事情简单。
感谢您的时间,如果您觉得这篇文章有用,请在 LinkedIn 和 T2 Twitter 上关注我,了解关于数据、商业和这两者之间的任何令人兴奋的故事。下一集再见!
原载于 2021 年 2 月 22 日 http://thedigitalskye.comhttp://thedigitalskye.com/2021/02/23/build-etl-data-pipelines-even-when-you-dont-know-how-to-code/。
在 Python 类中构建“工厂”和“工具”
原文:https://towardsdatascience.com/build-factory-and-utility-in-your-python-classes-ea39e267ca0a?source=collection_archive---------9-----------------------
图片由 arturo meza olivares 从 Pixabay 拍摄
三个内置的 Python 类装饰器
如果您曾经使用过其他面向对象的编程语言,如 Java 或 C++,您可能对“静态方法”、“类方法”、“getter”和“setter”等概念很熟悉。事实上,Python 也有所有这些概念。
在本文中,我将介绍 Python 类的三个内置装饰器。他们会帮助我们
- 创建类范围的实用工具方法
- 为我们的类创建工厂设计模式
- 保护类中的重要属性
现在我们应该开始了。
1.静态法
图片来自 Pixabay
让我们跳过所有概念性的干货,直接从例子开始。假设我们需要定义一个名为“Employee”的类。我们应该保留员工的姓名,以及这个人是什么时候加入我们公司的。此外,我们希望通过显示该员工为我们工作的年数来检查资历。
最初,我们可以这样写。
这里我们仅有的逻辑是calc_year()
方法。它获取当前年份并减去该员工加入的年份。这应该是大于或等于零的整数。如果为零,则输出“不到一年”,而不是确切的年数。
declaration:这个逻辑很不理想,只是作为一个例子。不要误会:)
它会把工作做好的。
e1 = Employee('Chris', 2020)
e1.seniority()
然而,这是一个小问题。您注意到了吗,calc_year()
方法实际上并不需要类的实例才能工作。这也意味着“自我”作为一个论点是不必要的,因为它不需要这样的依赖。
因此,我们可以将函数从类中取出,如下所示。
这个也很好用。
好的。如果calc_year()
方法甚至可以被重用用于其他目的,那就更好了。然而,如果我们不需要它做其他用途呢?还有,在类之外有这样的函数是很难看的,如果它只服务于这个类的话。
因此,该方法被认为是该类的“实用方法”。换句话说,它应该被定义为一个静态方法。
如上面的代码所示,在 Python 中定义一个静态方法非常容易。当我们向方法添加装饰符@staticmethod
时,我们不再需要添加self
参数,因为静态方法不需要现有的实例起作用。
使用静态方法,我们可以在一个类中定义我们的实用方法,并保持代码整洁。
2.分类方法
图片来自 Pixabay 的 falco
那么,Python 中的类方法是什么?同样,比起解释概念,我更喜欢用例子来演示。
你用过 Python 中的datetime
模块吗?通常,我们可以使用datetime.datetime()
来创建一个datetime
对象。然而,还有更多不同的方法可以创建这样一个带有不同参数的对象。
- 日期时间.今天()
- datetime.now()
- datetime.utcnow()
- datetime.fromtimestamp()
- datetime.utcfromtimestamp()
- datetime.strptime()
- …
为什么它们可以接受不同的参数,但像__init__()
构造函数那样返回一个 datetime 对象?那是因为它们是类方法。类方法可以将当前类的引用作为参数,这样它就可以调用__init__()
构造函数。
让我们用一个例子来证明这一点。假设我们想用一个字符串来创建一个雇员对象。该字符串必须是固定的模式,因此我们可以使用 regex 提取雇员的姓名和加入年份。然后,我们使用构造函数创建一个 employee 对象并返回它。
代码如下。
如上面的代码所示,我们已经将装饰器@classmethod
添加到方法from_string()
中,并将变量cls
传递给该方法。所以,我们可以使用变量cls
来创建一个当前类的对象。
该方法提取雇员的姓名和加入年份,然后利用构造函数__init__()
创建对象。
让我们试一试。
e1 = Employee.from_string('I am Chris and I joined in 2020.')
e1.seniority()
这种方法就像一个“工厂”,可以使用不同的“组件”来生产相同的产品。这也是为什么称之为“工厂法”的原因。工厂方法是使用类方法装饰器的非常典型的用例。
3.类别属性
来自像素库的像素的图像
Python 类的最后一个重要装饰是属性。
Python 是一种动态语言,它给予开发者最大的灵活性去做他们想做的事情。然而,有时,一些限制是必要的。
例如,更改员工的加入年份是没有意义的,因为那应该是固定的。这条需求与大多数其他编程语言中的“私有属性”概念相匹配。如何在 Python 类中保护一个属性?装潢师会帮忙的。
让我们简化前面的例子,因为这些静态/类方法在这种情况下无关紧要。在下面的代码中,我们使用@property
装饰器将year_joined
定义为 Python 中的一个属性。
class Employee:
def __init__(self, name, year_joined):
self.name = name
self._year_joined = year_joined @property
def year_joined(self):
return self._year_joined
现在,如果我们创建一个对象并试图设置属性,它不允许我们这样做。
e1 = Employee('Chris', 2020)
e1.year_joined = 2021
这是因为@property
装饰器保护属性不被修改。
你可能也知道我在变量前面加了下划线,所以它变成了_year_joined
。这里没有什么神奇的,但是按照 Python 的惯例,为了可读性,我们应该为任何私有属性加上下划线。如果你想知道更多,请查看我以前的一篇文章,如下所示。
那么,现在如果我们想实现 setter 和 getter 呢?使用@property
装饰器,我们可以很容易地将它们定义如下。
class Employee:
def __init__(self, name):
self.name = name @property
def year_joined(self):
print('getting year_joined...')
return self._year_joined @year_joined.setter
def year_joined(self, value):
print('setting year_joined...')
self._year_joined = value @year_joined.deleter
def year_joined(self):
print('deleting year_joined...')
del self._year_joined
如图所示,我们只是继续使用装饰器
- Getter:带有
@property
装饰的方法将成为 getter - 设定者:
@<attr_name>.setter
- 删除者:
@<attr_name>.deleter
删除器在 Python 中是非常独特的。这是因为 Python 允许我们在运行时从对象中移除属性。因此,删除器将使我们能够对一个受保护的属性这样做。
当然,在 getter 和 setter 中,当属性被获取或设置时,我们可以做其他事情。我刚刚添加了一个打印的消息来通知这一点。
删除程序将删除该属性。因此,在我们删除属性后,它将不再存在于对象中。
摘要
图片来自 Pixabay 的 RayMark
在本文中,我介绍了 Python 面向对象编程中使用的三个重要的装饰器:类。我们通常将静态方法用于类中的实用程序,将类方法用于工厂设计模式,将属性用于我们希望防止被随机修改的任何属性。
https://medium.com/@qiuyujx/membership
如果你觉得我的文章有帮助,请考虑加入灵媒会员来支持我和成千上万的其他作家!(点击上面的链接)
使用 Flask 和 D3.js 构建交互式图表
原文:https://towardsdatascience.com/build-interactive-charts-using-flask-and-d3-js-70f715a76f93?source=collection_archive---------16-----------------------
为电子商务销售分析设计交互式 D3.js 可视化,并支持业务决策
劳拉·乔伊特在 Unsplash 上拍摄的照片
可视化的力量
失意的天才
您是一位自豪的数据科学家,展示了您使用优化代码、花哨的库、高级线性代数和复杂的统计概念设计的新解决方案。
和[…]
与前一天新实习生展示的简单 PowerBI 仪表板相比,您的解决方案没有得到管理层的兴趣、认可或热情。
你遇到过这种挫折吗?
你需要发展你的视觉化技能
简单花哨的可视化比非常复杂的模型更有影响力,尤其是对非技术观众而言。
本文将给你一个在没有 javascript (或者很轻)的先验知识的情况下,使用 D3.js 设计花式可视化的菜谱。
先决条件
- HTML 的基础知识
- Python 中级知识,包括烧瓶框架
- 找到一个你想要设计的可视化的例子
💌新文章直接免费放入你的收件箱:时事通讯
从 D3.js 的例子中获得灵感
示例:悲惨世界人物矩阵图
你正在浏览http://bl.ocks.org*/,*一个很棒的网站来获取 D3.js 的教程,你看着迈克·博斯托克的这个矩阵图找到了灵感。
《悲惨世界》同现,迈克·博斯托克&让·丹尼尔·费科特,链接
《悲惨世界》是法国著名历史小说,作者维克多·雨果,出版于 1862 年。
这个矩阵显示了字符的共现
- 1 个彩色单元格=同一章中出现的两个字符
- 深色单元格:出现频率高的字符
- 浅色单元格:出现频率低的字符
将这种可视化应用到您的业务案例中
您有一个订单行级别的奢侈品化妆品在线销售的数据集。
你想要建立一个矩阵来显示品牌的共现
- 1 个彩色单元格=两个品牌出现在同一个客户订单中
- 深色单元格:与许多其他品牌一起出现的品牌
- 光细胞:与其他品牌很少出现的品牌
你可以在我的 Github 资源库中找到共享的源代码:萨米尔萨奇
我与其他项目的作品集:萨米尔萨奇
http://samirsaci.com
使用 Flask 构建您的解决方案
在用 Flask 渲染的模板上复制这个例子
让我们先通过渲染一个例子发现 b.locks (链接) 下面的结构
app.py
/templates
index.html
/static
/data
miserables.json
/js
/Libs
matrix.js
/css
- /templates:index.html 仪表板页面的 HTML 源代码(链接)
- /js/libs:用于呈现 D3.js 的 javascript 库
- /js/matrix.js:用于使用 miserables.json 呈现您的仪表板的脚本
- /static/Miserables . json:matrix . js 用来渲染 (L 墨迹 ) 的 JSON 文件
- /CSS:用于呈现页面的 CSS 文件
全部代码上传在我的 Github 资源库( 链接 )使用过
- 将 Github 资源库复制到您的本地文件夹中
- 下载 requirements.txt 中列出的库
- 启动 app.py
您的示例使用 Flask (链接)——(图片由作者提供)
现在,您已经使用 Flask 和 D3.js 构建了第一个可视化解决方案。
接下来的步骤是
- 用你的数据集替换Miserables . JSON
- 改编 matrix.js 以显示品牌共现
- 改编 HTML 页面代码以
**http://samirsaci.com **
将原始数据集处理成最终的 JSON
从 miserables.json 开始
第一步是分析 miserables.json
**1\. Nodes: Characters distributed in different groups**"nodes": {"name" : Character Name,
"group" : Group Number}2\. Links: Listing pairs of characters"nodes": {"source" : Character Name 1,
"target" : Character Name 2,
"value" : Number of Co-occurence}
获取 brands.json
我们想要什么?
**1\. Nodes: Brands are distributed in groups depending on the number of different brands that are ordered with it**"nodes": {"name" : Brand Name,
"group" : Group Number}2\. Links: Listing pairs of brands that with number of orders they appear together"nodes": {"source" : Brand Name 1,
"target" : Character_name2,
"value" : Number of Orders they appear together}
构建节点
第一个函数 order_brand 将为 create_nodes 函数准备所需的数据帧和列表,该函数将构建您的节点字典。
评论
- n_groups :将要拆分的品牌组数
- ****第 35 行:降序
{第 1 组:与许多其他品牌一起订购的品牌,
第 n 组:与少数其他品牌一起出现的品牌}
建立链接
导出 JSON 中的所有内容
决赛成绩
评论
- json_to :该函数将返回 json,通过向页面'/get-json '发送 get 请求来检索该 JSON
你的 JSON 已经可以被 matrix.js 使用了(经过一些调整)。
**http://samirsaci.com **
调整 Matrix.js 以适应您的品牌
添加工具提示以显示悬停时选择的品牌对
品牌对与订单数量一起显示在左上角—(图片由作者提供)
我在 mouseover 函数中添加了这几行来显示所选择的品牌对。
下载 JSON 文件
该函数将向 flask 页面'/get-json '发送一个 GET 请求,该页面将使用 create_json 函数返回 json_to 。
最后一击
改编 HTML 代码以添加标题
最终渲染
- /CSS: bootstrap 和 styles.css 来改进页面的呈现
您的奢侈品牌在线销售矩阵的最终效果图—(图片由作者提供)
结论
关注我的 medium,了解更多与供应链数据科学相关的见解。
你可以在我的作品集里找到这个矩阵图的静态版本:矩阵图
这是一个简单的 4 步过程
- 找到一个你想用于你的商业案例的好的可视化
- 下载 HTML 代码、javascript、CSS、JSON 文件和所有构建页面所需的文件
- 用烧瓶在本地渲染该页面
- 分析 JSON 格式并构建函数来适应你的输入数据
- 调整 javascript 以适应您的数据框格式
- 自定义 HTML 页面以添加有关数据集的信息
关于我
让我们连接上 Linkedin 和 Twitter ,我是一名供应链工程师,正在使用数据分析来改善物流运营和降低成本。
如果你对数据分析和供应链感兴趣,可以看看我的网站
**https://samirsaci.com
参考
*【1】—*迈克·博斯托克&让-丹尼尔·费科特,《悲惨世界》共现,链接
【2】—萨米尔萨奇 ,初始示例为烧瓶渲染, Github
【3】—小萨奇 ,最终解决, Github
【4】—小萨奇 ,我的作品集中一个最终渲染的例子, 最终渲染**
轻松构建多个机器学习模型
原文:https://towardsdatascience.com/build-multiple-machine-learning-models-easily-54046f022483?source=collection_archive---------28-----------------------
使用 lazy predict 仅用 2 行代码创建多个机器学习模型
由 Unsplash 上的 Pietro Jeng 拍摄
创建机器学习模型并找出最佳模型是一项令人厌倦的任务,因为这将花费大量的时间和精力。Lazy predict 有助于在短短两行代码中构建多个机器学习模型。
它不仅创建多个模型,而且有助于了解哪些模型适用于给定的数据。以便我们可以使用该模型并执行超参数调整以使其更加精确。它易于使用并且是开源的。它创建了大部分用于回归和分类的机器学习模型。
在本文中,我们将学习如何使用 lazy predict 并使用它创建多个机器学习模型。
让我们开始吧…
安装所需的库
我们将从使用 pip 安装来安装 lazy predict 开始。下面给出的命令将使用 pip 安装 lazy predict。
pip install lazypredict
导入所需的库
在本文中,我们将讨论分类和回归问题。在这一步中,我们将加载所需的库。我们将使用著名的糖尿病数据集进行分类,使用波士顿数据集进行回归分析。
from lazypredict.Supervised import LazyClassifier
from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
from lazypredict.Supervised import LazyRegressor
from sklearn import datasets
from sklearn.utils import shuffle
import numpy as np
创建机器学习模型
这是最后一步,我们将对数据进行预处理,并创建多个机器学习模型。
1.分类
data = load_breast_cancer()
X = data.data
y= data.targetX_train, X_test, y_train, y_test = train_test_split(X, y,test_size=.5,random_state =123)clf = LazyClassifier(verbose=0,ignore_warnings=True, custom_metric=None)
models,predictions = clf.fit(X_train, X_test, y_train, y_test)print(models)
模特表演(来源:作者)
在这里,我们可以清楚地分析不同的分类模型以及它们的性能,这仅仅是由两行代码创建的。
2.回归
boston = datasets.load_boston()
X, y = shuffle(boston.data, boston.target, random_state=13)
X = X.astype(np.float32)offset = int(X.shape[0] * 0.9)X_train, y_train = X[:offset], y[:offset]
X_test, y_test = X[offset:], y[offset:]reg = LazyRegressor(verbose=0, ignore_warnings=False, custom_metric=None)
models, predictions = reg.fit(X_train, X_test, y_train, y_test)print(models)
模特表演(来源:作者)
在这里,我们可以分析不同的模型及其对回归数据集的性能。
这就是我们如何使用 Lazy Predict 轻松、毫不费力地创建多个机器学习模型。
继续尝试不同的数据集,并让我知道您在回复部分的评论。
本文是与皮尤什·英加尔合作完成的。
在你走之前
感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github简介针对不同的数据科学项目和包教程。还有,随意探索 我的简介 ,阅读我写过的与数据科学相关的不同文章。
使用 HuggingFace 数据集构建 NLP 管道
原文:https://towardsdatascience.com/build-nlp-pipelines-with-huggingface-datasets-d597ff5f68ad?source=collection_archive---------13-----------------------
NLP 实践者的宝库和无与伦比的管道工具
作者图片
H F Datasets 是 NLP 从业者的必备工具——托管超过 1.4K *(主要是)*高质量的以语言为中心的数据集和易于使用的函数宝库,用于构建高效的预处理管道。
本文将研究可用的大规模数据集存储库,并探索该库出色的数据处理能力。
数据集
我们将从探索数据集开始。正如我们所说的——有大量的数据集可用,其中许多是由社区上传的。我经常使用的两个数据集是 OSCAR 和 SQuAD 数据集。
SQuAD 是一个用于训练问答变压器模型的出色数据集,通常无与伦比。HF 数据集实际上允许我们从跨越几种语言的几个不同的队数据集中进行选择:
当微调问答的 transformer 模型时,我们只需要这些数据集中的一个。
另一个数据集 OSCAR 可能是现有的最令人印象深刻的语言数据集之一。它由超过 166 种不同的语言数据集组成,包含从网络上搜集的非结构化文本。
其中一些数据集很小,如 11KB 的 Nahuatl 语言,但其他数据集很大,如 106GB 的日语或 1.2TB 的英语。这使得 OSCAR 成为预训练 transformer 模型的理想选择。
访问和查看数据集
在查看哪些数据集可用时,我们可以采用两种方法。使用在线数据集查看器应用或直接使用 Python。
在线数据集查看器相当简单,因此我建议您点击了解它是如何工作的。在这里,我们将重点放在 Python 方面。
我们希望从导入和查看所有可用的数据集开始。有很多,所以如果你在寻找一个特定的数据集——比如squad
——提前知道会很有帮助。
为了加载数据集,我们使用了datasets.load_dataset
函数。默认情况下,这会将整个数据集下载到文件中,这对于小队来说是可以的。但如果我们考虑到 1.2TB 大小的英语奥斯卡,这可能是一个糟糕的想法…😅
因此,我们可以不使用默认行为,而是通过设置streaming=True
,在需要时迭代下载数据集的大块内容。
我们可以看到,squad
数据集包含两个子集,train
和validation
。如果愿意,我们可以指定只使用其中的一个:
尽管我们将坚持使用整个数据集。要查看数据集的大小、描述和特性,我们可以分别访问dataset_size
、description
和features
属性。
如果使用streaming=False
,可以使用像dataset['train'][0]
这样的语法来访问数据集中的特定记录——但是因为我们有streaming=True
,所以我们必须遍历数据集。
这意味着,如果我们想查看记录以了解内容的类型(除了由dataset['train'].features
显示的内容之外),我们可以写:
这样,我们对可用的数据集有了一个很好的概念,并理解了它们的目的和内容。在下一节中,我们将继续讨论datasets
提供的处理方法。
数据集预处理
而datasets
值得使用,因为它可以方便地访问如此多的高质量数据集。它还附带了许多令人惊叹的预处理功能。当使用streaming=True
时,这些变得更加有用,因为我们可以迭代地转换我们的数据,而不需要下载所有东西。
修改特征
我们将从修改队伍数据中的answers
特征开始。在 Q & A 中,我们通常需要一个答案起始位置和结束位置。小队已经包含了answer_start
,但是我们必须使用这个和答案text
长度来创建我们自己在answers
特征中的answer_end
值。
修改现有特征(和创建新特征)最常用的方法是map
功能。
请注意,当
streaming=True
时,我们必须将中的每个特征都包含在map
中,否则它们会在映射后消失。当*streaming=False*
时情况并非如此,我们将在后面看到。
当我们定义这个转换时,它不会立即执行。相反,它是作为调用数据集时要执行的*‘指令’*添加的。这意味着我们仍然没有在内存中存储任何数据集。
该指令用于在需要时仅转换数据集样本*——也称为惰性加载(一个通用术语,不特定于 HF 甚至 ML) 。如果我们再次遍历几个样本,我们会看到转换得到了应用。*
我们还可以看到,如果我们故意在map
函数中创建一个错误,这是延迟加载的,因为在我们遍历数据集之前,错误不会出现。
我们将在后面介绍filter
w 方法,它只能在streaming=False
时使用——所以我们将在没有流的情况下重新加载我们的数据,并在本文的剩余部分使用它。**
使用
streaming=False
,我们可以使用列表索引直接访问数据集中的记录。
我们不再需要在map
函数中包含每一个特性。当streaming=False
时,我们只包括我们正在修改(或创建)的特征。
定量
我们几乎总是会执行的另一个操作是将文本标记化为标记 id。对于 SQuAD,这要求我们将question
和context
字符串传递给一个记号赋予器,记号赋予器将输出三个张量(对于 Bert)——input_ids
、token_type_ids
和attention_mask
。
一般来说,这个过程在批量执行时要快得多。幸运的是,map
方法允许我们使用batched=True
批量转换,甚至指定batch_size
。
重命名功能
有时我们可能需要重命名特性,通常是为了将特性名称与模型所期望的输入名称对齐。
在这种情况下,我们只是迂腐。我想将主题功能从title
重命名为topic
。
过滤
这是一个非常漂亮的特性。我们可以根据样本是否满足某种条件来过滤掉数据集中的样本。
我们已经返回了数据集的前几个样本,都是关于University_of_Notre_Dame
的主题——假设我们不想在我们的数据集中包含University_of_Notre_Dame
样本。
我们需要做的就是把它们拿出来:
这样,我们只保留了中topic
不等于和University_of_Notre_Dame
的样本。另外需要注意的是,我们不能用* *filter*
当 *streaming=True*
。*
删除功能
我们已经完成了处理,并且我们决定——实际上——我们不需要大多数特性。事实上,对于问答推理,我们只需要input_ids
、token_type_ids
、attention_mask
。
因此,对于我们的最终转换,让我们继续前进,并删除所有这三个功能。
我们到了。我们已经学会了如何找到并下载(或流式传输)一些在线可用的最佳数据集。然后,我们探索了 HF 的datasets
中打包的一些最重要的数据处理功能。
我希望你喜欢它!如果你有任何问题,请通过推特或者在下面的评论中告诉我。如果你想要更多这样的内容,我也会在 YouTube 上发布。
感谢阅读!
🤖《变形金刚》课程 NLP 的 70%折扣
*所有图片均由作者提供,除非另有说明
使用 Python 和 Flask-RESTful 为机器学习模型构建 REST API
原文:https://towardsdatascience.com/build-rest-api-for-machine-learning-models-using-python-and-flask-restful-7b2cd8d87aa0?source=collection_archive---------1-----------------------
数据科学家可以遵循的最小工作示例
Marcin Jozwiak 在 Unsplash 上拍摄的照片
1。简介
2。环境设置
∘ 2.1 使用 conda
∘ 2.2 使用 pip
∘ 2.3 为它创建一个 conda 环境
3 .培养一个最小 ML 模型
4。构建 REST API
∘ 4.1 理解代码
∘ 4.2 旋起 REST API
5 .测试 API
结论
关于我
参考文献
注:本帖提到的所有代码和结果都可以从我的 GitHub 页面访问。
1。简介
作为数据科学家,我们不仅需要构建模型,还需要部署它们,并使它们在完整的系统中有用。在许多情况下,我们需要与其他开发人员合作,将模型保存在单独的位置并使用 API 将模型提供给其他应用程序几乎总是一个好主意。
应用程序编程接口(API)是一种 web 服务,它允许访问其他应用程序可以通过标准 HTTP 协议访问的特定数据和方法,而表述性状态转移(REST)是 web 服务最流行的 API 架构风格之一。另一方面,Python 是数据科学家最喜欢的语言,有两种流行的 web 框架:Django 和 Flask。与 Django 相比,Flask 以轻量级和快速开发著称。它也有许多扩展来为 vanilla Flask 应用程序添加特定的功能,Flask-RESTful 是一个完美的选择,可以让构建一个功能完整的 REST API 变得非常容易。
在这里,我将带你通过一个例子和你需要遵循的所有代码,来了解如何使用 Flask-RESTful 构建一个最小可行的 REST API。这篇文章有三个主要部分:
- 制作一个 ML 模型:一个使用玩具数据集的简单模型
- **构建一个 REST API:**post 的主要部分。为刚做好的 ML 模型服务
- 测试 API :通过调用 API 使用模型进行预测
2.环境设置
因为这是一个最小的例子,所以不需要很多包。可以用conda
也可以用pip
。对于下面的 2.1 到 2.3,选择任何一种你感兴趣的方法。完成这些之后,你可以直接跳到第三部分。
2.1 使用 conda
如果您安装了 conda,您可以运行:
conda install -c conda-forge numpy scikit-learn flask-restful requests
2.2 使用画中画
如果没有安装 conda,pip
也可以通过运行:
pip install numpy scikit-learn flask-restful requests
2.3 为 it 创造康达环境
有时,为不同的项目保留不同的环境是有益的,因此如果您想创建另一个虚拟环境,可以运行以下命令:
conda create --name flask_api -c conda-forge numpy scikit-learn flask-restful requests
它将创建另一个名为flask_api
的环境,安装了这些软件包,您可以通过运行以下命令切换到新环境:
conda activate flask_api
你也可以使用pip
创建虚拟环境,但是我将跳过这一步,因为你可以很容易地在网上找到教程。
3.训练最小 ML 模型
东西摆好之后,我们先来搭建一个玩具 ML 模型。要获得更完整的代码和结果,请参考 Jupyter 笔记本,但以下是该部分的最低可行代码,也可以从这里下载。我们把它命名为train_model.py
,你可以使用python train_model.py
来运行
如果你熟悉机器学习,并且有过一些使用scikit-learn
的实践经验,那么代码应该对你有意义。
基本上,我们首先加载一个玩具数据集iris
,如下所示:
有 150 条记录。它们中的每一种都有 4 个特征,并被标记为 3 类中的一类(刚毛藻、杂色藻和海滨藻)。
在此示例中,我们直接训练模型并跳过微调部分,然后使用模型对测试集进行预测:
[0 2 0 1 2 2 2 0 2 0 1 0 0 0 1 2 2 1 0 1 0 1 2 1 0 2 2 1 0 0 0 1 2 0 2 0 1 1]
其中数字代表 3 类中的每一类。通过与真实标签比较,我们发现准确率为 97%,混淆矩阵如下所示:
图 1:测试集上模型预测的混淆矩阵(直接来自模型对象)
我们的表现已经足够好了(可能现实生活中太好了)。然后,我们通过在 pickle 文件中序列化来保存训练好的模型。
4.构建 REST API
4.1 理解代码
现在,一个简单的模型已经准备好了,让我们构建一个 REST API。同样,下面是代码,我会一步一步地解释它。也可以从我的 GitHub 下载。我们把这个命名为api.py
app = Flask(__name__)
api = Api(app)
首先,我们导入模块,上面的两行应该几乎总是存在于代码的顶部,以初始化 flask app 和 API。
*# Create parser for the payload data* parser = reqparse.RequestParser()
parser.add_argument(**'data'**)
上面的代码块创建了一个请求解析器来解析将随请求一起发送的参数。在我们的例子中,由于我们服务于 ML 模型,我们通常以 JSON 序列化格式发送数据,并将键命名为data
,因此我们要求解析器查找请求中包含的数据。
*# Define how the api will respond to the post requests* class IrisClassifier(Resource):
def post(self):
args = parser.parse_args()
X = np.array(json.loads(args[**'data'**]))
prediction = model.predict(X)
return jsonify(prediction.tolist())
api.add_resource(IrisClassifier, **'/iris'**)
然后我们通过继承从flask-restful
导入的Resource
类来创建一个名为IrisClassifier
的类,它已经定义了处理不同类型请求的各种方法,包括get
post
put
delete
等等。我们的目标是重写post
方法,告诉它如何使用模型对给定数据进行预测。因为我们的 API 的目的是服务于 ML 模型,我们只需要post
方法,不用担心其他的。
在post
方法中,我们首先调用刚刚定义的解析器来获取参数。数据(最初是 np.array)在 JSON 中被序列化为字符串格式,所以我们使用json.loads
将其反序列化为一个列表,然后返回到一个 NumPy 数组。预测部分和scikit-learn
模型一直做的一样。在最后一步,我们需要将预测的标签(np.array)放回列表,并调用从flask
导入的jsonify
函数再次序列化它,以便它们以正确的格式返回给应用程序。
在定义了类之后,我们将我们的IrisClassifier
(本质上是一个修改过的resource
类)连同访问它的相对路径一起添加到我们的 API 中,在我们的例子中是/iris
。如果我们只是在本地运行 flask,那么 ML 模型的整个 URL 将类似于[http://127.0.0.1:5000/iris](http://127.0.0.1:5000/iris)
。
if __name__ == **'__main__'**:
*# Load model* with open(**'model.pickle'**, **'rb'**) as f:
model = pickle.load(f)
app.run(debug=True)
在api.py
代码的最后一部分,我们加载从上一节保存的模型,以便应用程序知道如果需要任何预测,从哪里获取模型。然后,我们在调试模式下运行 flask 应用程序,如果发生任何错误,它只允许在浏览器中直接执行任意代码。
4.2 启动 REST API
如果您有保存为api.py
的代码,您可以使用:
python api.py
将会出现如下信息:
* Serving Flask app "api" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: on
* Running on [http://127.0.0.1:5000/](http://127.0.0.1:5000/) (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 117-609-315
那你就可以走了!
5.测试 API
如果您遵循了前面的章节,那么您应该已经在本地机器上运行了 REST API。现在是测试的时候了,看看是否有效。同样,下面是您需要复制、粘贴和运行的所有代码(最少)。更多完整的代码和结果,请参见 Jupyter 笔记本,或者下面的代码,您可以在这里访问。
然后我会一步一步地解释代码。我们把它命名为test_api.py
,你可以通过调用python test_api.py
来运行它
*# Load data* iris = load_iris()
*# Split into train and test sets using the same random state* X_train, X_test, y_train, y_test = \
train_test_split(iris[**'data'**], iris[**'target'**], random_state=12)
导入相关模块后,首先要做的是获取一个数据子集(仅特性)来测试 API 返回的预测。为了便于比较,我们可以使用我们在第 3 节中拆分的相同测试集。我们可以加载 iris 数据集,并使用相同的随机状态(12)来获得数据的确切子集X_test
。
*# Serialize the data into json and send the request to the model* payload = {**'data'**: json.dumps(X_test.tolist())}
y_predict = requests.post(**'http://127.0.0.1:5000/iris'**, data=payload).json()
然后,我们创建一个payload
变量,将X_test
的列表序列化为 JSON 格式,key 为data
,就像我们在api.py
中定义的那样,这样我们的 API 就知道在哪里可以找到输入数据。然后,我们将有效负载发送到我们定义的端点,并获得预测结果。
*# Make array from the list* y_predict = np.array(y_predict)
print(y_predict)
最后一步是可选的,但是我们可以将数据返回到 NumPy 数组并打印出预测,这与我们之前在第 3 节中创建模型时得到的结果完全相同。混淆矩阵也完全相同:
[0 2 0 1 2 2 2 0 2 0 1 0 0 0 1 2 2 1 0 1 0 1 2 1 0 2 2 1 0 0 0 1 2 0 2 0 1 1]
图 1:测试集上模型预测的混淆矩阵(来自 REST API)
在 REST API 端,在使用了post
方法之后,我们可以看到显示响应为 200 的消息,这意味着请求已经被成功处理:
127.0.0.1 - - [01/Nov/2021 17:01:42] "POST /iris HTTP/1.1" 200 -
因此,我们已经测试了刚刚构建的 REST API,并获得了与原始模型对象返回的结果完全相同的结果。我们的 API 管用!
结论
我们刚刚介绍了使用 Python 和 Flask-RESTFul 构建一个全功能 REST API 所需的基本知识和步骤。如果我们只看 API 构建部分(第 4 节),它确实非常简单——不到 30 行代码,其中大多数只是标准语句。修改代码也非常容易:您所需要做的就是替换您想要使用的模型,指定post
方法如何工作,并给出访问 API 的正确路径。
为了进一步利用我们刚刚构建的 REST API 来为其他应用程序提供我们的机器学习模型,我们可以将它部署在服务器上,或者使用任何流行的云 web 托管服务:AWS、Google Cloud、Heroku 等。通过适当的配置,任何获得许可的人都可以从世界上的任何地方访问我们的模型。
感谢您的阅读!如果你喜欢这篇文章,请关注我的频道和/或 成为我今天的推荐会员 (非常感谢🙏).我会继续写下去,分享我关于数据科学的想法和项目。如果你有任何问题,请随时联系我。
https://zhouxu-ds.medium.com/membership
关于我
我是赛诺菲的数据科学家。我拥抱技术,每天都在学习新技能。欢迎您通过媒体博客、 LinkedIn 或 GitHub 联系我。我的观点是我自己的,而不是我雇主的观点。
请看我的其他文章:
- 利用空气质量传感器数据进行时间序列模式识别
- 理解分类问题中的 Sigmoid、Logistic、Softmax 函数和交叉熵损失(对数损失)
- 使用 Elasticsearch (AWS OpenSearch)进行实时类型预测搜索
- 利润最大化的贷款违约预测
- 使用 Berka 数据集进行贷款违约预测
参考
1如何将 Python 请求模块与 REST API 一起使用:https://www . nylas . com/blog/Use-Python-Requests-Module-REST-API/
[2] Python REST API 教程—构建 Flask REST API:https://www.youtube.com/watch?v=GMppyAPbLYk&t = 3769s&ab _ channel = TechWithTim
用 Python 构建健壮的 Google BigQuery 管道:第一部分
原文:https://towardsdatascience.com/build-robust-google-bigquery-pipelines-with-python-part-i-1ac8ca11391a?source=collection_archive---------8-----------------------
谷歌云平台
Apache Beam 与 Google BigQuery API
弗兰基·查马基在 Unsplash 上拍摄的照片
这是关于在 Python 中与 BigQuery 交互以构建数据管道的三篇文章系列的第 1 部分。
- 第一部分. Apache Beam 与 Google BigQuery API
- 第二部分。Python 中的 BigQuery 结构
- 第三部分。BigQuery 和 Google Sheet:隐藏的复杂性
摘要
在 Spotify,我们有许多软件工程师和数据工程师团队,他们使用 Scala 或 Java 来帮助将大量数据带入我们的谷歌云平台(GCP)生态系统,供用户和研究人员使用。然而,大部分数据还不能立即使用。为了正确地进行分析,需要进行清洁和整形步骤。对于我们来说,重要的是拥有一个强大的管道,可以处理日常的数据清理需求,同时应用业务逻辑和机器学习方法。Python 有一个独特的优势,即既敏捷又强大。这就是为什么我在过去的一年里投入了大量的时间和精力来提出一个优化的解决方案,用 Python 构建 BigQuery 数据管道。感谢开源社区,那里有很多资源提供了很好的提示和指导。然而,经过几轮反复试验,我还是花了一些时间找到了正确的信息。因此,我希望这篇文章能让你的生活变得更简单,如果你也想在 Python 中使用 BigQuery 的话。
在这篇文章中,我将简要介绍 BigQuery,并讨论可以与 BigQuery 交互的两个最常用的 Python APIs。
目录
- BigQuery 概述
- Apache Beam BigQuery Python I/O:实现、利弊
- Python 中的 Google BigQuery API:实现、优缺点
BigQuery 概述
BigQuery 是一个完全托管的、无服务器的数据仓库,能够对数 Pb 的数据进行可扩展的分析。它是一个平台即服务,支持使用 ANSI SQL 进行查询。它还内置了机器学习功能。BigQuery 于 2010 年 5 月发布,并于 2011 年 11 月正式发布。(维基百科)
在 GCP,两个最常见的存储数据的地方是 BigQuery 和 GCP 桶。GCP 桶更像一个存储场所,而 BigQuery 允许用户在 UI 上立即进行分析。有许多方法可以与 BigQuery 交互。最简单和最明显的方法是通过 BigQuery 的交互式 UI 控制台。BigQuery 控制台允许用户使用标准 SQL 或遗留 SQL 来查询表。在云控制台和客户端库中,标准 SQL 是默认的。在bq
命令行工具和 REST API 中,遗留 SQL 是默认的。您可以在查询设置中或者通过在 API 调用中传递参数来轻松地在两者之间切换。
谷歌最近发布了一个新的视图,增加了一些功能,比如允许多个标签供编辑使用,这是一个受用户欢迎的变化。但是,有几个 bug 需要修复。首先,对于每日分区,只能查看最新的模式——早期分区的模式和预览功能不起作用。再比如 delete table 函数只允许用户删除最近的分区,看起来会像是用户删除了数据集中的所有东西!幸运的是,事实并非如此;刷新将显示只有最新的分区被删除。
BigQuery 控制台当前视图
BigQuery 控制台旧视图
Apache Beam BigQuery Python I/O
我最初是通过其 Google BigQuery I/O 连接器使用 Apache Beam 解决方案开始旅程的。当我了解到 Spotify 数据工程师在 Scala 中使用 Apache Beam 进行大部分管道工作时,我认为它也适用于我的管道。事实证明并非如此,但我并不后悔,因为一路上我学到了很多关于 Apache Beam 的知识。
Beam SDKs 包含内置函数,可以从 Google BigQuery 表中读取数据和向其中写入数据。要安装,请在您的终端中运行pip install apache-beam[gcp]
。
导入包
import apache_beam as beam
import json
from apache_beam.io.gcp.bigquery_tools import parse_table_schema_from_json
从 BigQuery 读取
要从 BigQuery 读取数据,您可以选择。Apache Beam 不是我最喜欢的从 BigQuery 读取数据的方法。我更喜欢使用 Google BigQuery API 客户端,因为它可以下载数据并将其转换为 Pandas 数据框架。但作为参考,您可以直接从表中读取:
*# project-id:dataset_id.table_id*
table_spec **=** 'YOUR_PROJECT:YOUR_DATASET.YOUR_TABLE_ID'my_column = (
p
| ‘ReadTable’ >> beam.io.ReadFromBigQuery(table=table_spec)
# Each row is a dictionary where the keys are the BigQuery columns
| beam.Map(lambda elem: elem[‘my_column’]))
或者传递一个 SQL 查询:
my_column = (
p
| ‘QueryTableStdSQL’ >> beam.io.ReadFromBigQuery(
query=’SELECT my_column FROM ‘\
‘`YOUR_PROJECT.YOUR_DATASET.YOUR_TABLE_ID`’,
use_standard_sql=True)
# Each row is a dictionary where the keys are the BigQuery columns
| beam.Map(lambda elem: elem[‘my_column’]))
数据格式编排
现在您已经检索了数据,您可以用 Python 对它们做各种有趣的事情。你可以操作数据,应用 ML 模型等。但是在将这个表上传到 BQ 之前,这里有一些最终处理的指针。
- 时间戳 格式时间戳列如下:
my_table[‘my_timestamp’] = my_table[‘my_timestamp’].apply(lambda x: x.strftime(‘%Y-%m-%d %H:%M:%S’)))
- 数据类型 将 Float 、 Integer 、 Timestamp 或 Date 数据类型转换为 String 首先在 Beam 中传递,然后在 schema 文件中指定数据类型。请注意时间戳/日期数据类型不接受空字符串。
my_table = my_table.applymap(str)
- 数据结构这使得 beam 能够分离列表,如果是一个巨大的数据集,就将数据传回。
my_table = my_table.to_dict("records")
- 空值
None (Null)类型不能作为除了 ApacheBeam 中的字符串之外的任何内容传递。当作为字符串类型传递时,您将在 BigQuery 中看到一个实际的‘None’字符串,这是 Python 中的 NULL 值。尽管令人困惑,但将其转换为空字符串将解决问题,并在 BigQuery 中获得实际的空值。
一旦为数据类型准备好数据框,并根据需要将其转换为字典列表,就可以将对象上传到 BigQuery 了。
上传到 BigQuery
为了将数据上传到 BigQuery,我们需要首先定义模式。下面是一个用 JSON 生成模式文件的模板。
def make_sink_schema():
mapping = {
"string": ["STRING", "This is my string."],
"timestamp": ["TIMESTAMP", "This is my timestamp."],
"numeric": ["FLOAT", "This is my float."],
} mapping_list = [{"mode": "NULLABLE", "name": k, "type": mapping[k][0], "description": mapping[k][1]} for k in mapping.keys()]
return json.JSONEncoder(sort_keys=True).encode({"fields": mapping_list})
你也可以在 Avro 中生成模式文件。但是这里我们以 JSON 为例。一旦准备好模式,就可以使用下面的模板将表上传到 BigQuery。
def run_beam(my_table, table_name, dataset_name, project_name, my_schema):
argv = [
'--project={0}'.format('YOUR_PROJECT'),
'--job_name=YOUR_JOB_NAME',
'--staging_location=gs://{0}/staging/'.format('YOUR_BUCKET'),
'--temp_location=gs://{0}/temp/'.format('YOUR_BUCKET'),
'--region=YOUR_REGION',
'--service_account = YOUR_SERVICE_ACCOUNT'
'--runner=DataflowRunner'
]
p = beam.Pipeline(argv=argv)
# write table to BigQuery
(p
| 'Create Data' >> beam.Create(my_table)
| 'Write to BigQuery' >> beam.io.Write(
beam.io.WriteToBigQuery(
# The table name is a required argument for the BigQuery sink.
# In this case we use the value passed in from the command line.
table=table_name, dataset=dataset_name, project=project_name,
# JSON schema created from make_sink_schema function
schema=parse_table_schema_from_json(my_schema),
# Creates the table in BigQuery if it does not yet exist.
create_disposition=beam.io.BigQueryDisposition.CREATE_IF_NEEDED,
# Deletes all data in the BigQuery table before writing.
write_disposition=beam.io.BigQueryDisposition.WRITE_TRUNCATE))
)
return pp = run_beam(my_table, table_name, dataset_name, project_name, my_schema)p.run().wait_until_finish()
赞成的意见
在处理大量数据时,ApacheBeam 的优势是显而易见的。因为它在行级别处理数据,所以数据集可以分成多个部分,以便不同的工作人员可以并行处理它们。
骗局
对我来说,Apache Beam 的最大问题是它在数据类型和空值方面的不灵活性。有太多的细微差别,没有太多的变通办法。
Python 中的 Google BigQuery API
当我在应对 Apache Beam 的缺点时,我决定尝试一下 Google BigQuery API ,我很高兴我这么做了!如果你不想运行一个有大量数据的大任务,Google BigQuery API 是一个很好的选择。要安装,请在您的终端中运行pip install — upgrade google-cloud-bigquery
。
导入包
from google.cloud import bigquery
import pandas as pd
从 BigQuery 读取
要从 BigQuery 读取数据,您可以决定是使用自己的凭据还是使用服务帐户凭据来读取。如果您想使用自己的凭证,第一步是通过在您的终端中运行gcloud auth login command
来授权您的 Google 帐户。然后,您可以继续使用您最喜欢的 Python 编辑器:
# Construct a BigQuery client object.
client = bigquery.Client(project=YOUR_PROJECT)query = """
SELECT name, SUM(number) as total_people
FROM `bigquery-public-data.usa_names.usa_1910_2013`
WHERE state = 'TX'
GROUP BY name, state
ORDER BY total_people DESC
LIMIT 20
"""
query_job = client.query(query).result().to_dataframe() # Make an API request and convert the result to a Pandas dataframe.
如果您选择使用服务帐户凭证,首先将其保存为本地 JSON 文件,然后按如下方式构造客户端对象:
client = bigquery.Client.from_service_account_json(
json_credentials_path=PATH_TO_YOUR_JSON,
project=YOUR_PROJECT)
数据格式编排
Google BigQuery API 在数据类型上也有一些怪癖,但我喜欢的是它更好地处理 NULL 值,并且允许所有数据类型中的 NULL 值。以下是一些额外的提示:
- 时间戳
格式时间戳列如下:
my_table[‘my_timestamp’] = my_table[‘my_timestamp’].apply(lambda x: x.strftime(‘%Y-%m-%dT%H:%M:%S’)))
- 日期
格式日期列如下:
my_table['my_date'] = pd.to_datetime(my_table['my_date'], format='%Y-%m-%d', errors='coerce').dt.date
- String
空字符串在 BigQuery 上将作为空字符串返回。所以用np.nan
来代替他们。
my_table = my_table.replace(r'^\s*$', np.nan, regex=True)
上传到 BigQuery
您可以选择在将数据上传到 BigQuery 时自动检测模式,也可以使用下面的函数定义您自己的模式。请注意,列的顺序无关紧要。BigQuery 客户端将按名称查找列。
def make_schema():
schema = [
bigquery.SchemaField(name="string", field_type="STRING", description="This is my string."),
bigquery.SchemaField(name="numeric", field_type="FLOAT", description="This is my float."),
]
return schema
一旦准备好模式,就可以使用下面的模板将表上传到 BigQuery。
def run_bigquery(my_table, table_id, project_name, my_schema, table_description = None):
*"""
Upload a dataframe to BigQuery
"""* client = bigquery.Client(project=project_name)
job_config = bigquery.LoadJobConfig(schema=my_schema, destination_table_description=table_description,
write_disposition='WRITE_TRUNCATE')
job = client.load_table_from_dataframe(
my_table, table_id, job_config=job_config)
return jobjob = run_bigquery(YOUR_TABLE, table_id, project_name, make_schema(), table_description)
job.result()
赞成的意见
Google BigQuery API 比 Apache Beam 更容易实现。它在数据类型方面也更加灵活,并且可以更好地处理 Python 中的空值。
骗局
如果数据量很大,这不是一个合适的解决方案。在这种情况下,考虑 Apache Beam。
所以给你!我希望这篇文章能给你一些关于在 Python 中使用 BigQuery 的想法。本系列的下一篇文章将讨论 BigQuery 中的一个特定结构——Struct,以及 Python 环境中由于当前限制而产生的变通方法。回头见!:)
用 Python 构建健壮的 Google BigQuery 管道:第二部分
原文:https://towardsdatascience.com/build-robust-google-bigquery-pipelines-with-python-part-ii-2883423a1c8a?source=collection_archive---------26-----------------------
谷歌云平台
Python 中的 BigQuery STRUCT
由 Joseph Barrientos 在 Unsplash 上拍摄的照片
这是关于在 Python 中与 BigQuery 交互以构建数据管道的三篇文章系列的第二部分。
- 第一部分:Apache Beam 与 Google BigQuery API
- 第二部分。Python 中的 BigQuery
STRUCT
- 第三部分。BigQuery 和 Google Sheet:隐藏的复杂性
什么是 STRUCT?
STRUCT
是有序字段的容器,每个字段都有一个类型(必需的)和字段名称(可选的)。—谷歌云
在 BigQuery 中,一个STRUCT
就像一个数据帧,因此它可以包含多个具有不同列名和数据类型的子列。相比之下,一个ARRAY
就像 Python 中的一个LIST
,你可以在一个ARRAY
中嵌套一个STRUCT
,也可以在一个STRUCT
中嵌套一个ARRAY
。
STRUCT
使用尖括号(<
和>
)声明类型。STRUCT
的元素类型为所需的,可以任意复杂。字段名可选,允许重复字段名。当缺少字段名时,该字段被认为是匿名的。
使用STRUCT
的好处是在连接表时减少了重复的麻烦。然而,它确实增加了访问的难度——特别是对于那些不太懂技术的用户。
要阅读更多关于构建STRUCT
的内容,Google Cloud 有一个非常好的关于这个主题的文档。
查询结构
DOT
注释将允许您查询包含在STRUCT
中的项目。UNNEST
是在需要展平嵌套结构时使用的函数,例如 BigQuery 中的STRUCT
或ARRAY
。
SELECT
user.user_id, -- ARRAY
user.gender, -- STRING
user.is_active, -- BOOLEAN
FROM
`my-project.my_dataset.user_info`,
UNNEST(user) user
值得一提的几个怪癖:
- 当字段是嵌套在
STRUCT
中的ARRAY
时,NOT NULL
功能不起作用(即WHERE user.user_id IS NOT NULL
)。NULL
仍将返回值行。在WHERE
子句中使用LENGTH(user.user_id) > 0
——这将达到目的! - 有时
UNNEST
函数会导致重复行。这是因为UNNEST
正在对表中的所有字段执行CROSS JOIN
。为了避免这种情况,可以考虑在STRUCT
中创建一个ARRAY
,或者仅对子查询中需要的字段使用UNNEST
。
用 Python 下载STRUCT
当一个STRUCT
在 Python 中没有任何UNNEST
被下载时,它将在DataFrame
中被呈现为DICTIONARY
的一个LIST
。
将结构下载到数据帧中
用 Python 将结构上传到 BigQuery
由于Pyarrow
中的序列化限制,BigQuery I/O 不支持将STRUCT
结构上传到 Pandas DataFrame
中的 BQ。据我所知,在Pyarrow 2.0
发布后,这仍然是一个正在进行的问题(见这个线程)。但我建议定期检查这个问题,因为这个问题是由谷歌云工程师提出的,看起来他们正在解决这个问题。
解决方法是将表转换成基于行的数据结构,比如JSON
或 Python DICTIONARY
。我可以使用JSON
上传带有STRUCT
的表格。如果您想将一个数据类型为STRUCT
的表上传到 BigQuery,这里有一个例子,希望对您有所帮助。
导入包
from google.cloud import bigquery
import pandas as pd
数据结构
为了上传一个STRUCT
到 BigQuery,该列的数据结构需要是DICTIONARY
的LIST
。想象一下,你正在建造一个DICTIONARY
的LIST
来转换成一个DataFrame
。
data = pd.DataFrame([
{‘item’: ‘album’,
‘user’: [{‘user_id’: [‘50’, ‘25’], ‘gender’: ‘M’, ‘is_active’: True},]
}, {‘item’: ‘jacket’,
‘user’: [{‘user_id’:[‘20’, ‘30’, ‘35’], ‘gender’: ‘F’, ‘is_active’: False}]
},])# convert DataFrame to the list of dict format
data_json = data.to_dict('records')
一旦您准备好了DataFrame
,这里有一个STRUCT
的模式示例:
schema = [
bigquery.SchemaField(name="item", field_type="STRING", description="an item user purchased"),
bigquery.SchemaField(
"user",
"STRUCT",
fields=[
bigquery.SchemaField("user_id", "STRING", mode="REPEATED", description="User's internal user_id; users can have e multiple ids"),
bigquery.SchemaField("gender", "STRING", mode="NULLABLE", description="User's gender"),
bigquery.SchemaField("is_active", "BOOLEAN", mode="NULLABLE", description="User's active status. True if user logged in in the past 7 days, else False"),
],
mode="REPEATED",),
]
在 BigQuery 控制台上,你会看到 a STRUCT
有类型 ' RECORD
',而 aARRAY
有模式 ' REPEATED
'。
如果STRUCT
中有类型为ARRAY
的字段,则将STRUCT
的模式标记为REPEATED
。如果没有,您可以将模式保留为“NULLABLE
”。
BQ 控制台上的结构模式
现在我们已经准备好了模式,我们可以通过使用来自client
对象的load_table_from_json
函数来上传表。
client = bigquery.Client(project=your_project_name)
job_config = bigquery.LoadJobConfig(
schema=your_schema,
destination_table_description=your_table_description,
write_disposition='WRITE_TRUNCATE'
)job = client.load_table_from_json(
data_json, table_id, job_config=job_config
)job.result()
这是表上传到 BigQuery 后的样子。
具有嵌套数组的结构示例
希望这个关于使用 BigQuery STRUCT
的简单例子对您有所帮助。如果您有任何问题,请随时评论或联系我:)
参考:
- 在表模式中指定嵌套和重复的列
- 数据类型—
[STRUCT](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#struct_type)
用 Python 构建健壮的 Google BigQuery 管道:第三部分
原文:https://towardsdatascience.com/build-robust-google-bigquery-pipelines-with-python-part-iii-e19c6da566f3?source=collection_archive---------31-----------------------
谷歌云平台
BigQuery 和 Google Sheet 隐藏的复杂性
由 Ashkan Forouzani 在 Unsplash 拍摄
这是关于在 Python 中与 BigQuery 交互以构建数据管道的三篇文章系列的第三部分。
- 第一部分:Apache Beam 与 Google BigQuery API
- 第二部分。Python 中的 big query
[STRUCT](/build-robust-google-bigquery-pipelines-with-python-part-ii-2883423a1c8a)
- 第三部分。BigQuery 和 Google Sheet 隐藏的复杂性
在 Spotify,Google Sheet 是一款非常受欢迎的办公工具。BigQuery 的优势之一是它能够与存储在 Google Sheet 中的数据进行交互。您可以使用新的 BigQuery 数据连接器 Connected Sheets 访问、分析、可视化和共享电子表格中的数十亿行数据。当数据科学家或工程师与不太懂技术的用户合作时,这非常方便。然而,当涉及到 Google Sheet 时,BigQuery 中有一些意想不到的行为,起初它们可能看起来并不直观。本文旨在深入探讨 BigQuery 中 Google Sheet 的不同用例,并帮助避免由于这些意外行为而造成的混淆,尤其是在 Python 管道环境中。
I .从 Google Sheet 到 BigQuery 创建表格
在这种情况下,“创建表”一词会产生误导,更准确的说法应该是“创建表连接”BigQuery 正在建立一个活动连接,而不是将数据集实际导入 BigQuery。但是 BigQuery console 使用这个术语,所以我们现在坚持使用它。
以下是从 Google Sheet 创建表格需要做的工作概述:
- 为
Create table from
选择“驱动” - 将 URI 工作表复制并粘贴到下一个框中
- 为
File format
选择谷歌表单 - 记下表的元数据,如项目、数据集和表名。为表定义模式—我建议手动输入模式,因为自动检测并不总是正确的
- 定义
Header rows to skip
,如果没有标题,则为 0,如果有 n 个标题行要跳过,则为 n
从 Google 工作表创建表格
一旦创建了表,您将能够在 BigQuery 中查询它。然而,一个常见的错误是认为数据现在作为一个单独的副本存储在 BigQuery 中。事实并非如此。BigQuery 在这里所做的仅仅是创建一个到 Google Sheet 的活动连接,其含义如下:
- 如果在 Google Sheet 上放置任何过滤器,BigQuery 将无法显示整个数据集;Google Sheet 中的过滤器实际上会立即反映出来,并影响数据在 BigQuery 中的外观。因此,如果您想访问 BigQuery 中的所有数据,请始终对单个视图使用过滤器。
- 如果有任何模式更改,如列名更改、列类型更改,则不能在 BigQuery 中编辑现有模式。删除当前的 BigQuery 表并重做
Create table
过程。
二。用 Python 阅读 BigQuery Google Sheet 数据
如果您尝试使用服务帐户来运行作业,请确保您将服务帐户添加为 Google Sheet 的编辑器。
将 Google 工作表设置为 BigQuery 表的最重要步骤是在 Python BigQuery API 中修改 BigQuery 客户机的范围。
import pandas as pd
from google.cloud import bigqueryscopes = (
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.file',
'https://www.googleapis.com/auth/spreadsheets',
)
bigquery.Client.SCOPE += scopesclient = bigquery.Client()
然后,这里有一行代码将您的查询结果转换成 pandas dataframe
。
gs = client.query("""SELECT * FROM `YOUR_PROJECT.YOUR_DATASET.{table}`""".format(table=table_name)).result().to_dataframe()
三。用 Python 写 Google Sheet
有几个包可以让你用 Python 写 Google Sheet。我将以pygsheets
为例。如果您不打算在管道中运行作业,这个包非常简单。但是,如果您计划在管道中使用包,则需要一个变通方法;出于安全原因,我们不能在我们的云服务器中存储任何服务帐户密钥文件,因此常规功能将不起作用。让我们看看这两个场景中的一些例子。
假设您计划为此作业使用服务帐户密钥。这里是服务帐户的快速介绍。
服务帐户是与电子邮件相关联的帐户。该帐户使用一对公钥/私钥进行身份验证,这比其他选项更安全——只要私钥保持私有。— Pysheets
要创建服务帐户,请按照下列步骤操作:
- 转到“凭据”选项卡并选择“创建凭据>服务帐户密钥”。
- 接下来选择服务帐户为“App Engine default ”,密钥类型为 JSON,然后单击创建:
3.接下来点击下载按钮下载client_secret[…].json
文件;请务必记住您将它保存为本地json
文件的位置:
现在我们已经准备好了服务帐户密钥文件,让我们导入所需的包:
import requests
import json
import pygsheets
import styx_secrets
from google.oauth2 import service_account
from google.cloud import bigquery
import pandas as pd
import numpy as np
授权过程很简单:
gc = pygsheets.authorize(client_secret='path/to/client_secret[...].json')
然而,如果您有一个管道作业,这个过程会稍微复杂一些,因为我们需要使用一个字典作为我们的解决方法。
首先,我们需要加密我们的服务帐户密钥。在 Spotify,我们有一个名为styx-secrets
的包用于加密。请注意,为了让pygsheets
识别这个密钥,需要对utf-8
进行解码。
import styx_secretskey1 = styx_secrets.decrypt("FIRST_HALF_OF_ENCRYPTED_KEY_STRING").decode("utf-8")
key2 = styx_secrets.decrypt("SECOND_HALF_OF_ENCRYPTED_KEY_STRING").decode("utf-8")
我不得不把密匙分解成两串,因为原来的密匙串太长了,styx-secrets
不接受。
然后我们可以在一个dictionary
中准备密钥文件,这基本上是json
密钥文件的一个copy
和paste
,除了用你的加密字符串交换真实的密钥(注意解密后还需要做一些格式上的改变):
sc_key = {
"type": "service_account",
"project_id": "YOUR_PROJECT",
"private_key_id": "YOUR_PRIVATE_KEY_ID",
"private_key": ("-----BEGIN PRIVATE KEY-----" + key1 + key2 + "-----END PRIVATE KEY-----\n").replace("\\n", "\n"),
"client_email": "YOUR_SERVICE ACCOUNT_EMAIL",
"client_id": "SERVICE_ACCOUNT_CLIENT_ID",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/xxxxxxxx"
}credentials = service_account.Credentials.from_service_account_info(
sc_key,
scopes=[
'https://www.googleapis.com/auth/spreadsheets',
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.file', ])gc = pygsheets.authorize(custom_credentials=credentials)
现在我们完成了授权,我们可以玩一玩了!要写入 Google 工作表,这里有一个例子。
假设您有一个跟踪管道事件的 Google Sheet,这样您的团队就可以轻松地分析数据:
# open the google spreadsheet
sh = gc.open('Data Incident Tracker')
# select the first sheet
wks = sh[0]# import previous events
track_prev = client.query("""SELECT * FROM `YOUR_PROJECT.YOUR_DATASET.{table}`""".format(table=table_name)).result().to_dataframe()
# current event
track_now = [{
'incident_date': date_param,
'num_of_tables': len(missing_list),
'table_list': ', '.join(missing_list),
'alert': True,
'root_cause': root_cause}, ]
# create new data frame with all incidents
tracker_df = pd.concat([track_prev, pd.DataFrame(track_now)])
# update the first sheet with tracker_df
wks.set_dataframe(tracker_df.replace(np.nan, '', regex=True), 'A1')
最后,请注意,如果您的表中有任何None
值,它们实际上将作为“NaN”字符串上传到 Google Sheet 中。为了避免这种情况,使用replace(np.nan, ‘’, regex=True)
将它们替换为空字符串,单元格将作为实际的Null
上传到 Google 工作表中。
这是 Python 系列中 Google BigQuery 的最后一篇文章。我希望它们对你有用。如果您有任何问题,请随时联系我们或发表评论。干杯!
使用 Vespa 从 python 构建句子/段落级问答应用程序
原文:https://towardsdatascience.com/build-sentence-paragraph-level-qa-application-from-python-with-vespa-9ec61fb43d2?source=collection_archive---------29-----------------------
使用稀疏和密集排序功能检索段落和句子级别的信息
我们将通过必要的步骤来创建一个问答(QA)应用程序,它可以基于语义和/或基于术语的搜索的组合来检索句子或段落级别的答案。我们首先讨论使用的数据集和为语义搜索生成的问题和句子嵌入。然后,我们将介绍创建和部署 Vespa 应用程序以提供答案的必要步骤。我们将所有需要的数据提供给应用程序,并展示如何结合语义和基于术语的搜索来查询句子和段落级别的答案。
布雷特·乔丹在 Unsplash 上拍摄的照片
本教程基于 Vespa 团队的早期工作来复制 Ahmad 等人的论文 ReQA:端到端答案检索模型的评估的结果。使用斯坦福问答数据集(SQuAD)1.1 版数据集。
关于数据
我们将使用斯坦福问答数据集(SQuAD)1.1 版数据集。数据包含段落(这里表示为上下文),每个段落都有问题,这些问题在相关的段落中有答案。我们已经解析了数据集,并组织了将在本教程中使用的数据,以使其更容易理解。
段落
每个context
数据点包含一个唯一标识段落的context_id
、一个保存段落字符串的text
字段和一个保存问题 id 列表的questions
字段,这些问题 id 可以从段落文本中得到回答。如果我们想在应用程序中索引多个数据集,我们还包括一个dataset
字段来标识数据源。
{'text': 'Architecturally, the school has a Catholic character. Atop the Main Building\'s gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend "Venite Ad Me Omnes". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858\. At the end of the main drive (and in a direct line that connects through 3 statues and the Gold Dome), is a simple, modern stone statue of Mary.',
'dataset': 'squad',
'questions': [0, 1, 2, 3, 4],
'context_id': 0}
问题
根据上面的数据点,可以用context_id = 0
来回答带id = [0, 1, 2, 3, 4]
的问题。我们可以加载包含问题的文件,并显示前五个问题。
段落句子
为了构建更精确的应用程序,我们可以将段落分解成句子。比如下面第一句话来自带context_id = 0
的段落,可以用question_id = 4
回答问题。
{'text': "Atop the Main Building's gold dome is a golden statue of the Virgin Mary.",
'dataset': 'squad',
'questions': [4],
'context_id': 0}
嵌入
我们希望结合语义(密集)和基于术语(稀疏)的信号来回答发送给我们的应用程序的问题。我们已经为问题和句子生成了嵌入以实现语义搜索,每个嵌入的大小等于 512。
[-0.005731593817472458,
0.007575507741421461,
-0.06413306295871735,
-0.007967847399413586,
-0.06464996933937073]
这里是脚本,包含我们用来生成句子和问题嵌入的代码。我们当时使用了 Google 的通用句子编码器,但是可以随意用您喜欢的模型生成的嵌入来替换它。
创建和部署应用程序
我们现在可以基于上述数据构建一个句子级的问答应用。
保存上下文信息的模式
context
模式将有一个包含数据部分描述的四个相关字段的文档。我们为text
字段创建一个索引,并使用enable-bm25
来预先计算加速使用 BM25 进行排名所需的数据。summary
索引指示所有字段都将包含在所请求的上下文文档中。attribute
索引将字段存储在内存中,作为排序、查询和分组的属性。
默认字段集意味着默认情况下查询标记将与text
字段匹配。我们定义了两个等级配置文件(bm25
和nativeRank
)来说明我们可以定义和试验尽可能多的等级配置文件。您可以使用可用的等级表达式和功能创建不同的等级。
保存句子信息的模式
sentence
模式的文档将继承context
文档中定义的字段,以避免相同字段类型的不必要的重复。此外,我们添加了定义用来保存大小为 512 的浮点数的一维张量的sentence_embedding
字段。我们将把字段作为属性存储在内存中,并使用HNSW
(分层可导航小世界)算法构建一个 ANN index
。阅读这篇博文以了解更多关于 Vespa 实现 ANN 搜索的历程,以及文档以了解更多关于 HNSW 参数的信息。
对于sentence
模式,我们定义了三个等级配置文件。semantic-similarity
使用 Vespa closeness
排名功能,该功能被定义为1/(1 + distance)
,因此嵌入问题嵌入更近的句子将比相距较远的句子排名更高。bm25
是基于术语的等级配置文件的示例,而bm25-semantic-similarity
结合了基于术语和基于语义的信号,作为混合方法的示例。
构建应用程序包
我们现在可以通过创建一个应用程序包来定义我们的qa
应用程序,这个应用程序包包含了我们上面定义的context_schema
和sentence_schema
。此外,我们需要通知 Vespa,我们计划发送一个名为query_embedding
的查询排名特性,其类型与我们用来定义sentence_embedding
字段的类型相同。
部署应用程序
我们可以在 Docker 容器中部署app_package
(或者部署到 Vespa Cloud ):
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for application status.
Waiting for application status.
Finished deployment.
输入数据
部署完成后,我们可以使用Vespa
实例app
与应用程序进行交互。我们可以从输入上下文和句子数据开始。
句子级检索
下面的查询通过ranking.features.query(query_embedding)
参数发送第一个问题嵌入(questions.loc[0, "embedding"]
),并使用nearestNeighbor
搜索操作符检索嵌入空间中最近的 100 个句子,使用HNSW
设置中配置的欧几里德距离。返回的句子将按照在sentence
模式中定义的semantic-similarity
等级配置文件进行排序。
{'id': 'id:sentence:sentence::2',
'relevance': 0.5540203635649571,
'source': 'qa_content',
'fields': {'sddocname': 'sentence',
'documentid': 'id:sentence:sentence::2',
'questions': [0],
'dataset': 'squad',
'context_id': 0,
'text': 'It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858.'}}
句子级混合检索
除了发送查询嵌入之外,我们可以通过query
参数发送问题字符串(questions.loc[0, "question"]
),并使用or
操作符检索满足语义操作符nearestNeighbor
或基于术语的操作符userQuery
的文档。选择type
等于any
意味着基于术语的操作符将检索至少匹配一个查询标记的所有文档。检索到的文档将按照混合等级-配置文件bm25-semantic-similarity
进行分级。
{'id': 'id:sentence:sentence::2',
'relevance': 44.46252359752296,
'source': 'qa_content',
'fields': {'sddocname': 'sentence',
'documentid': 'id:sentence:sentence::2',
'questions': [0],
'dataset': 'squad',
'context_id': 0,
'text': 'It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858.'}}
段落级检索
对于段落级检索,我们使用 Vespa 的分组特性来检索段落而不是句子。在下面的示例查询中,我们按context_id
分组,并使用段落的最大句子分数来表示段落级别分数。我们将返回的段落数限制为 3,每段最多包含两句话。我们返回每个句子的所有概要特征。所有这些配置都可以更改,以适应不同的使用情况。
{'id': 'group:long:0',
'relevance': 1.0,
'value': '0',
'children': [{'id': 'hitlist:sentences',
'relevance': 1.0,
'label': 'sentences',
'continuation': {'next': 'BKAAAAABGBEBC'},
'children': [{'id': 'id:sentence:sentence::2',
'relevance': 0.5540203635649571,
'source': 'qa_content',
'fields': {'sddocname': 'sentence',
'documentid': 'id:sentence:sentence::2',
'questions': [0],
'dataset': 'squad',
'context_id': 0,
'text': 'It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858.'}},
{'id': 'id:sentence:sentence::0',
'relevance': 0.4668025534074384,
'source': 'qa_content',
'fields': {'sddocname': 'sentence',
'documentid': 'id:sentence:sentence::0',
'questions': [4],
'dataset': 'squad',
'context_id': 0,
'text': "Atop the Main Building's gold dome is a golden statue of the Virgin Mary."}}]}]}
{'id': 'group:long:28',
'relevance': 0.6666666666666666,
'value': '28',
'children': [{'id': 'hitlist:sentences',
'relevance': 1.0,
'label': 'sentences',
'continuation': {'next': 'BKAAABCABGBEBC'},
'children': [{'id': 'id:sentence:sentence::188',
'relevance': 0.5209270028414069,
'source': 'qa_content',
'fields': {'sddocname': 'sentence',
'documentid': 'id:sentence:sentence::188',
'questions': [142],
'dataset': 'squad',
'context_id': 28,
'text': 'The Grotto of Our Lady of Lourdes, which was built in 1896, is a replica of the original in Lourdes, France.'}},
{'id': 'id:sentence:sentence::184',
'relevance': 0.4590959251360276,
'source': 'qa_content',
'fields': {'sddocname': 'sentence',
'documentid': 'id:sentence:sentence::184',
'questions': [140],
'dataset': 'squad',
'context_id': 28,
'text': 'It is built in French Revival style and it is decorated by stained glass windows imported directly from France.'}}]}]}
结论和未来工作
这项工作使用谷歌的通用句子编码器来生成嵌入。将评估指标与最新的脸书密集段落检索方法生成的嵌入进行比较会很好。这篇 Vespa 博文使用 DPR 在一个可扩展的生产就绪型应用程序中重现了基于检索的问答系统的最新基线。
建立正确的机器学习团队,而不是最好的
原文:https://towardsdatascience.com/build-the-right-machine-learning-team-not-the-best-2a1f2f889d73?source=collection_archive---------45-----------------------
了解在建立一个通过机器学习提供高级分析能力的团队时的陷阱
商业问题解决高级分析。图由照片混合而成。
由机器学习(ML)驱动的高级分析正在风靡一时。大大小小的公司都在提出预测、推荐、分类等等。并创建团队,在不同的问题领域解决这些概念。
需要回答的一个关键问题是如何建立这样一个团队。通常,团队的目标是开发和/或管理软件系统和围绕系统的过程。在他们的核心,他们管理数据、代码、模型和洞察力。我已经看到团队一有机会就跳起来解决高度专业化的问题。因此,他们需要多名数据科学家、机器学习工程师、数据分析师等。,尽快加入这个团队。这是解决未知问题和建立团队的正确方法吗?
我们生活在一个没有两个相同挑战的环境中。对于在同一个国家经营的两家食品连锁店来说,试图为他们的产品找到合适的折扣价格可能不是同样的挑战。一个食品杂货渠道可能会吸引富裕的顾客,而另一个渠道可能更适合寻找便宜货的人。对于同一家杂货店,长期货架产品的优化订购经验可能不容易转化为季节性产品。可能很容易想到技能,如零售、数据分析、算法、数据和建模管道等方面的经验。,就足够了。事实上,拥有这样的专业人士是一个优势,但还不够。交付价值超越了做技术工作的技能。弄清楚如何在正确的时间以正确的方式将这些经历联系起来是很重要的。
就我个人而言,我觉得我正处于学习如何做的初级阶段。然而,我已经学到了一些东西,我想与社区分享。在本文中,我将解释团队在交付高级分析时所经历的阶段。每个阶段都有独特的需求,团队需要解决这些需求来交付期望的结果。正确处理需求是建立正确团队的核心。
机器学习团队的阶段
图 1:ML 产品团队的阶段。作者图。
图 1 展示了 ML 产品团队的五个主要阶段。我们在下面描述了这些阶段和技能要求。
- 探索:在这个阶段,团队需要隔离要解决的关键问题。与此同时,团队需要找出可以提供更多关于近似问题场景的洞察力的数据,这将激发解决方案的设计。在这个阶段,重要的是扫描和保持广度,而不是深入。此外,每天在团队中交流发现和后续想法以及定期与涉众交流也很重要,但不要太频繁。这一阶段的结果是,团队已经对已识别的问题提出了一些数据驱动的公式。这个阶段需要的技能包括问题领域的知识、与问题领域相关的数据知识、数据分析和可视化、需求分析、设计思维、沟通等。请注意,这些技能中有一些是在创业环境中应用的企业家技能,可能来自产品所有者或项目经理以及数据或业务分析师。
- 测试:在这个阶段,团队应该专注于实现公式化问题的解决方案,允许他们测试一些关键的假设。显然,测试开发应该与解决方案开发并行,这样就可以立即识别错误。一旦解决方案在测试环境中运行,它就可以在目标市场的有限范围内进行测试。随着时间的推移,范围可以分阶段扩大。一个阶段中成功的测试应该加强下一个测试阶段的解决方案的改进。一个阶段中测试的失败应该鼓励对问题的形成进行更深入的研究,并对解决方案和测试场景进行可能的调整。此阶段的结果是团队已经确定了应该用于常规价值交付的解决方案。除了探索阶段的技能,一个团队至少需要几个有经验的数据科学家和一个数据工程师才能正常工作。这个团队还需要一些假设检验和实验方面的知识和经验。在这个阶段,重要的是技术解决者要紧密合作并保持广阔的视野。
- 工业化:在这一阶段,团队应该集中精力改进主要解决方案,以达到适当的效率和自动化水平。目标是获得足够的技术深度,以确保定期向中小型目标区域投放。在这个阶段,解决方案可能会遇到在运行过程中出现的边缘情况。因此,解决方案的假设和设计应该到处都有。因此,解决方案的技术复杂性不应妨碍对解决方案进行实验的能力。除了前两个阶段的技能,团队还需要用软件和机器学习工程师来补充数据工程师。团队中每个数据科学家或分析师至少要有两名工程师,这一点很重要。团队也可以有一些没有经验的成员。团队认真对待运营责任是很重要的,即,为即将到来的运行做好充分准备,并愿意放下手头的任何事情以使运行畅通无阻。此外,重要的是将任务委派给个人贡献者,强烈鼓励偶尔的联合工作。为了确保有人需要站出来成为一名技术领导者,他将促进架构和算法设计和实现以及团队文化的讨论。在这个阶段,技术角色需要保持宽泛,然后深入挖掘。
- 扩展:在这个阶段,所有的一切都是为了将系统的能力增强到一个更大的范围,以支持业务的大部分份额。解决方案设计的一部分可能需要重新构思,以便与秤配合使用。此外,在自动化、效率和透明度方面,解决方案的技术复杂性需要非常高。同样重要的是,开发、测试和生产环境应该相似,以便于转移解决方案。一旦一个团队在这个阶段成熟了,开发活动相对于运营支持应该会减少很多。除了早期阶段需要的技能,团队需要增加所有角色的人数。此外,团队应该专注于获得大数据、云、数学建模、软件开发等领域的一些专家。,至少是兼职。
理想情况下,团队会线性地经历这些阶段。然而,我们并不是生活在一个理想的世界中,因此,这样的叙述并不真正合适。业务设置将会发生变化,这将会导致解决方案不断地发生变化。实际上,随着一个团队的成熟,它在不同的阶段会有不同的工作流。
组建合适团队的十项实践
一直招到有特定资质的人是很难的。团队和组织争夺同一个人才库,从而蚕食市场。此外,团队成熟度越低,他们在招聘方面就越差。最后,招聘预算总是落后于候选人的期望。当团队被招募时,开始考虑 ML 系统交付类似于交付一部几十年的肥皂剧。你需要很多人做更多的工作。你需要晋升的人。你经常需要新面孔。你需要多个人来承担大量的责任并协调这个过程。除了技能和经验,获得正确的心态是必须的。
虽然分享什么是应该的方式是很诱人的,但让我分享一些让我和我的团队进入正确心态的技巧。
- 早点招几个忍者通才:刚招的几个需要自己做所有的事情。这几个人必须有能力与整个堆栈一起工作。这几个人将成为团队的核心,因此需要高度协作。
- **招聘喜欢指导和/或良好文化的专家:**雇佣躲在角落里做自己的事的专家是不好的。这个人应该激励和帮助他人在他们的技能领域做得更好。重要的是,这些人推动重大的有影响力的事业,例如,减少技术债务、增加透明度、进行实验等。
- 碰碰运气:招聘要求通常与潜在雇员不完全匹配。在这种情况下,只要有足够的态度和愿望来弥补差距,就要抓住机会。例如,如果这个职位是 Python 软件开发人员,但是候选人有 Java 经验并且愿意学习其他语言,那就去争取吧。
- 目标多样化:避免让你的团队充满超级资深的志同道合者。机器学习是关于优化的,这通常发生在考虑全局或大范围的时候。在这种情况下,如果解决方案不够健壮,那么它再复杂也没用。重要的是,除了大众需求之外,它还有能力覆盖利基市场。当一个团队保持同质的时间太长时,它可能会很难转向,而一个多样化的团队可能会因为其思维的多样性而朝着正确的方向前进。试着把招聘看成一个拼图,需要不同颜色的积木来代表经验水平、教育程度、性别、种族等等。
- **鼓励敏捷:**实现敏捷需要自由思考、学习和反应的时间。交付时,团队必须为提升技能和惊喜留出空间。计划不超过团队能力的百分之七十,鼓励团队花更多的时间结对编程、学习和讨论。鼓励低年级学生从事更有雄心的工作,鼓励高年级学生领导,鼓励人们超越自己的典型职责。最终,这将使个人对自己的工作拥有更多的自主权,从而获得更快反应的心态和能力。
- **减少部落知识:**总是不停地问我们能不能在容错的同时做我们做的事情。否则,无论工作有多复杂,都要减少对个人的高度依赖。一旦团队找到了稳定的解决方案,轮换以增加知识,将责任交给一个团队而不是个人,使文档和演示成为强制性的。
- **追求一个良好的生态系统:**避免仅仅运行一个交付成果的团队。走充分的弯路,比如参加团队内外的黑客马拉松,加入论坛,支持实习生,跑边项目,拯救其他团队。我们不可能一直通过花钱来摆脱危机。为此,我们需要社会化,让社区解决社区的问题。从生态系统的角度考虑挑战,而不是你的团队。如果你有意识或无意识地受益于另一个团队,你应该有意识地回报。
- **为分享建立一个安全的空间:**分享和奖励成就对我们来说很常见。这样的事情激励我们做得更好。然而,这还不够好。通过积极的反馈来奖励和鼓励好习惯也很重要。例如,如果有人写了很好的文档或者用大量的测试覆盖了代码,在代码评审期间公开表扬这个人。此外,团队应该强调从错误中学习,并真正尝试找到根本原因,而不是责怪个人。例如,如果有人因为缺乏知识而犯了错误,这是团队的失败,因为他们没有考虑到团队成员的教育。犯错误是常见的,不应该受到惩罚。重要的是团队在发现错误后会做什么。分享根本原因并建议补救过程不仅对团队有益,对其他团队也有益。
- **努力成为学习型组织:**鼓励主动学习和分享。为人们从事各种学习活动提供足够的空间、预算和手段,如上课、探索新技术和方法、组建学习小组、组建学习委员会、鼓励认证和学位。能力成长具有滚雪球效应,这种效应来自于友好的环境和临界质量。尽管没有立竿见影的效果,但有必要从早期阶段就朝着这个方向努力。
- **创造一个轻松的氛围:**最重要的是,采取行善,善良,减少不良行为。创造一个稳定的地方,在那里大部分时间都不会有压力。诱发事件,使之容易做到这一点。在我工作的瑞典文化中,鼓励人们每天喝咖啡、喝茶、吃面包、吃香蕉,一天几次随意闲聊。我强烈推荐给大家。
备注
我已经试着以某种能力处理每一项实践,并观察到了改进。我不是这方面的研究者,也没有数据来支持我的观点。如果你有更有力的证据支持或反对我的论点,请分享。我会感激这些知识。如果你有其他建议,也请分享。
用 PyCaret 构建,用 FastAPI 部署
原文:https://towardsdatascience.com/build-with-pycaret-deploy-with-fastapi-333c710dc786?source=collection_archive---------6-----------------------
这是一个循序渐进、初学者友好的教程,介绍如何使用 PyCaret 构建端到端的机器学习管道,并将其作为 API 进行部署。
py caret——Python 中的开源、低代码机器学习库
👉介绍
这是一个循序渐进、初学者友好的教程,介绍如何使用 PyCaret 构建端到端的机器学习管道,并使用 FastAPI 将其作为 web API 部署到生产中。
本教程的学习目标
- 使用 PyCaret 构建端到端的机器学习管道
- 什么是部署?我们为什么要部署机器学习模型
- 使用 FastAPI 开发一个 API 来生成对未知数据的预测
- 使用 Python 向 API 发送以编程方式生成预测的请求。
本教程将在较高层次上涵盖整个机器学习生命周期,分为以下几个部分:
PyCaret —机器学习高级工作流
💻在本教程中,我们将使用哪些工具?
👉PyCaret
PyCaret 是一个开源的低代码机器学习库和端到端的模型管理工具,内置于 Python 中,用于自动化机器学习工作流。它因其易用性、简单性以及快速有效地构建和部署端到端 ML 原型的能力而广受欢迎。
PyCaret 是一个替代的低代码库,可以用几行代码代替数百行代码。这使得实验周期成倍地快速和有效。
py caret简单 好用。PyCaret 中执行的所有操作都顺序存储在一个管道中,该管道对于**部署是完全自动化的。**无论是输入缺失值、一键编码、转换分类数据、特征工程,甚至是超参数调整,PyCaret 都能实现自动化。
要了解更多关于 PyCaret 的信息,请查看他们的 GitHub。
👉FastAPI
FastAPI 是一个现代、快速(高性能)的 web 框架,用于基于标准 Python 类型提示用 Python 3.6+构建 API。主要特点是:
- 快:非常高的性能,与 NodeJS 和 Go 不相上下(感谢 Starlette 和 Pydantic)。最快的 Python 框架之一。
- 快速编码:将开发特性的速度提高 200%到 300%左右。
- 易:设计为易于使用和学习。减少阅读文件的时间。
要了解 FastAPI 的更多信息,请查看他们的 GitHub 。
PyCaret 和 FastAPI 的工作流
👉正在安装 PyCaret
安装 PyCaret 非常容易,只需要几分钟。我们强烈建议使用虚拟环境来避免与其他库的潜在冲突。
PyCaret 的默认安装是 pycaret 的精简版本,只安装这里列出的硬依赖项。
**# install slim version (default)** pip install pycaret**# install the full version**
pip install pycaret[full]
当您安装 pycaret 的完整版本时,这里列出的所有可选依赖项也会被安装。
👉安装 FastAPI
您可以从 pip 安装 FastAPI。
pip install fastapi
👉商业问题
对于本教程,我将使用一个非常受欢迎的案例研究,由达顿商学院发表在哈佛商学院。这个案子是关于两个未来将要结婚的人的故事。名叫格雷格的家伙想买一枚戒指向一个名叫莎拉的女孩求婚。问题是找到莎拉会喜欢的戒指,但在他的密友建议后,格雷格决定买一颗钻石,这样莎拉就可以决定她的选择。然后,格雷格收集了 6000 颗钻石的价格和切割、颜色、形状等属性数据。
👉数据
在本教程中,我将使用一个数据集,该数据集来自达顿商学院的一个非常受欢迎的案例研究,发表在哈佛商业上。本教程的目标是根据钻石的重量、切割、颜色等属性来预测钻石的价格。您可以从 PyCaret 的存储库下载数据集。
**# load the dataset from pycaret** from pycaret.datasets import get_data
data = get_data('diamond')
数据中的样本行
👉探索性数据分析
让我们做一些快速可视化来评估独立特征(重量、切割、颜色、净度等)之间的关系。)与目标变量即Price
**# plot scatter carat_weight and Price**
import plotly.express as px
fig = px.scatter(x=data['Carat Weight'], y=data['Price'],
facet_col = data['Cut'], opacity = 0.25, template = 'plotly_dark', trendline='ols',
trendline_color_override = 'red', title = 'SARAH GETS A DIAMOND - A CASE STUDY')
fig.show()
莎拉得到了一份钻石案例研究
让我们检查目标变量的分布。
**# plot histogram**
fig = px.histogram(data, x=["Price"], template = 'plotly_dark', title = 'Histogram of Price')
fig.show()
请注意,Price
的分布是右偏的,我们可以快速查看对数变换是否可以使Price
接近正态,从而给假设正态的算法一个机会。
import numpy as np**# create a copy of data**
data_copy = data.copy()**# create a new feature Log_Price**
data_copy['Log_Price'] = np.log(data['Price'])**# plot histogram**
fig = px.histogram(data_copy, x=["Log_Price"], title = 'Histgram of Log Price', template = 'plotly_dark')
fig.show()
这证实了我们的假设。这种转换将帮助我们摆脱偏态,使目标变量接近正态。基于此,我们将在训练我们的模型之前转换Price
变量。
👉数据准备
对于 PyCaret 中的所有模块来说,setup
是在 PyCaret 中执行的任何机器学习实验中的第一个也是唯一一个强制步骤。该功能负责训练模型之前所需的所有数据准备。除了执行一些基本的默认处理任务,PyCaret 还提供了一系列预处理功能。要了解 PyCaret 中所有预处理功能的更多信息,您可以查看这个链接。
**# init setup**
from pycaret.regression import *
s = setup(data, target = 'Price', transform_target = True)
pycaret.regression 模块中的设置函数
每当在 PyCaret 中初始化setup
函数时,它都会分析数据集并推断所有输入要素的数据类型。在这种情况下,你可以看到除了Carat Weight
所有其他特征都被推断为分类,这是正确的。您可以按 enter 键继续。
注意,我在setup
中使用了transform_target = True
。PyCaret 将使用 box-cox 变换在后台转换Price
变量。它以类似于日志转换*(技术上不同)*的方式影响数据的分布。如果你想了解更多关于 box-cox 变换的知识,你可以参考这个链接。
设置的输出—为显示而截断
👉模型训练和选择
现在数据准备工作已经完成,让我们使用compare_models
功能开始训练过程。此函数训练模型库中可用的所有算法,并使用交叉验证评估多个性能指标。
**# compare all models**
best = compare_models()
compare_models 的输出
基于平均绝对误差的最佳模型是CatBoost Regressor
。使用 10 倍交叉验证的 MAE 为 543 美元,而钻石的平均价值为 11,600 美元。这还不到 5%。对于我们到目前为止所付出的努力来说还不错。
**# check the residuals of trained model**
plot_model(best, plot = 'residuals_interactive')
最佳模型的残差和 QQ 图
**# check feature importance**
plot_model(best, plot = 'feature')
最佳模型的特征重要性
完成并保存管道
现在让我们最终确定最佳模型,即在包括测试集在内的整个数据集上训练最佳模型,然后将管道保存为 pickle 文件。
**# finalize the model**
final_best = finalize_model(best)**# save model to disk** save_model(final_best, 'diamond-pipeline')
👉部署
首先,我们来了解一下为什么要部署机器学习模型?
机器学习模型的部署是使模型在生产中可用的过程,其中 web 应用程序、企业软件和 API 可以通过提供新的数据点和生成预测来使用经过训练的模型。通常建立机器学习模型,以便它们可以用于预测结果(二进制值,即用于分类的 1 或 0,用于回归的连续值,用于聚类的标签等)。生成预测有两种主要方式(I)批量预测;以及(ii)实时预测。本教程将展示如何将您的机器学习模型部署为 API 以进行实时预测。
既然我们已经理解了为什么部署是必要的,并且我们已经具备了创建 API 所需的一切,即作为 pickle 文件的训练模型管道。使用 FastAPI 创建 API 非常简单。
https://gist . github . com/moe zali 1/4bd 5312d 27884d 7 b 07 f 66 bef CDC 28 CCF
代码的前几行是简单的导入。第 8 行正在通过调用FastAPI()
初始化一个 app。第 11 行从您的磁盘加载训练好的模型diamond-pipeline
(您的脚本必须与文件在同一个文件夹中)。第 15–20 行定义了一个名为predict
的函数,它接受输入,并在内部使用 PyCaret 的predict_model
函数来生成预测,并将值作为字典返回(第 20 行)。
然后,您可以通过在命令提示符下运行以下命令来运行该脚本。在执行此命令之前,您必须与 python 脚本和模型 pickle 文件位于同一目录下。
uvicorn main:app --reload
这将在本地主机上初始化一个 API 服务。在您的浏览器上键入http://localhost:8000/docs,它应该显示如下内容:
http://本地主机:8000/docs
点击绿色的**POST**
按钮,会打开一个这样的表单:
http://localhost:8000/docs
点击右上角的**“试用”**,在表格中填写一些值,然后点击“执行”。如果您做了所有正确的事情,您将看到以下响应:
来自 FastAPI 的响应
请注意,在响应主体下,我们有一个预测值 5396(这是基于我在表单中输入的值)。这意味着,考虑到您输入的所有属性,这颗钻石的预测价格为 5396 美元。
这太好了,这表明我们的 API 正在工作。现在我们可以使用 Python 或任何其他语言中的requests
库来连接 API 并生成预测。我为此创建了如下所示的脚本:
https://gist . github . com/moe zali 1/545 be 5743 b 61 aa 5477228 b 8727 e 40 b 59
让我们来看看这个函数的运行情况:
为进行 API 调用而创建的 get_prediction 函数
请注意,预测值是 5396,这是因为我在这里使用了与上表中相同的值。(1.1,“理想”,“H”,“SII”,“VG”,“EX”,“GIA”)
我希望你会喜欢 PyCaret 和 FastAPI 的易用性和简单性。在不到 25 行代码和几分钟的实验中,我使用 PyCaret 训练和评估了多个模型,并使用 API 部署了 ML 管道。
即将推出!
下周我将写一篇教程来推进部署到下一个级别,我将在下一篇教程中介绍像容器化和码头工人这样的概念。请关注我的媒体、 LinkedIn 、 Twitter 获取更多更新。
使用 Python 中的这个轻量级工作流自动化库,您可以实现的目标是无限的。如果你觉得这很有用,请不要忘记给我们 GitHub 库上的⭐️。
要了解更多关于 PyCaret 的信息,请关注我们的 LinkedIn 和 Youtube。
加入我们的休闲频道。此处邀请链接。
您可能还对以下内容感兴趣:
使用 PyCaret 2.0
在 Power BI 中构建您自己的 AutoML 使用 Docker
在 Azure 上部署机器学习管道在 Google Kubernetes 引擎上部署机器学习管道
在 AWS Fargate 上部署机器学习管道
构建和部署您的第一个机器学习 web 应用
使用 AWS Fargate 无服务器
构建和部署机器
重要链接
文档
博客
GitHub
stack overflow
安装 PyCaret 笔记本教程 投稿于 PyCaret
想了解某个特定模块?
单击下面的链接查看文档和工作示例。
分类 回归 聚类
异常检测
自然语言处理 关联规则挖掘
使用 Streamlit 构建您的第一个 Python 数据质量检查 Web 应用程序
原文:https://towardsdatascience.com/build-your-first-data-quality-checking-web-app-in-python-using-streamlit-5f2ab6d1126a?source=collection_archive---------28-----------------------
最终产品快照。点击查看 app 。
质量从来不是偶然;它总是高度的意图、真诚的努力、明智的指导和熟练的执行的结果;它代表了多种选择中的明智选择。
M 保持数据集的质量不是一项简单的任务。众所周知,数据质量的下降通常会引入偏差,导致误导性结果,最终对业务产生不利影响。根据 Gartner research 的调查,数据质量差给组织带来的平均经济影响为每年 970 万美元。类似地,来自 IBM 的数据表明,仅在美国,由于数据质量低下,企业每年损失 3.1 万亿美元。数据质量低不仅仅是一个货币问题;这也有可能损害公司的声誉。
数据质量是一个普遍的问题。Forrester的研究表明,在进入决策流程之前,分析师三分之一的时间中有近 40%用于筛选和确认分析数据。
数据质量是业务运营、规划和发展的关键。然而,数据质量是由不同的因素定义的,有些是主观的,有些是客观的。因此,积累数据质量的所有参数是一个十亿美元的问题。
在这篇博客中,我们将学习创建一个 Streamlit python 应用程序,根据以下指标检查数据的基本质量:
1.缺失值/ NaN
2。完成率
3。重复率
4。正规性检验
这里是这个 tutoria l 的完整代码,如果你想跟随你的教程,这里是 演示 。
导入库
import os
import streamlit as st
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
from PIL import Image
导入库后,我们将自定义文本和表格的宽度。此外,我们将隐藏默认的页脚文本。
def main():
def _max_width_():
max_width_str = f"max-width: 1000px;"
st.markdown(
f"""
<style>
.reportview-container .main .block-container{{
{max_width_str}
}}
</style>
""",
unsafe_allow_html=True,
)# Hide the Streamlit header and footer
def hide_header_footer():
hide_streamlit_style = """
<style>
footer {visibility: hidden;}
</style>
"""
st.markdown(hide_streamlit_style, unsafe_allow_html=True)# increases the width of the text and tables/figures
_max_width_()# hide the footer
hide_header_footer()
现在,我们将创建一个选项来选择准备好的数据集或允许用户上传他们自己的文件。
st.markdown("# Data Quality Checker ✅")
st.markdown("Check the basic quality of any dataset")
st.markdown("---")st.subheader(" [Read full tutorial at Medium.]([https://medium.com/@maladeep.upadhaya](https://medium.com/@maladeep.upadhaya)) | [Complete code at GitHub]([https://github.com/maladeep](https://github.com/maladeep))")
st.markdown("---")
def file_select(folder='./datasets'):
filelist=os.listdir(folder)
selectedfile=st.selectbox('select a default dataset',filelist)
return os.path.join(folder,selectedfile)if st.checkbox('Select dataset from local machine'):
data=st.file_uploader('Upload Dataset in .CSV',type=['CSV'])
if data is not None:
df=pd.read_csv(data)
else:
filename=file_select()
st.info('You selected {}'.format(filename))
if filename is not None:
df=pd.read_csv(filename)
st.markdown("---")
直到这段代码,我们有了以下结果。现在我们将开始实现探索数据质量的必要部分。
图片作者。点击查看应用。
数据集和形状的快照
#show data
if st.checkbox('Show Dataset'):
num=st.number_input('No. of Rows',5,10)
head=st.radio('View from top (head) or bottom (tail)',('Head','Tail'))if head=='Head':
st.dataframe(df.head(num))
else:
st.dataframe(df.tail(num))
st.markdown("---")
if st.checkbox('Rows & Columns size'):
st.markdown("Number of rows and columns helps us to determine how large the dataset is.")
st.text('(Rows,Columns)')
st.write(df.shape)st.markdown("---")
图片作者。点击查看 app 。
检查缺少的值
缺失值称为空值或 NaN 值。在大多数情况下,缺失数据会导致偏差,从而导致模糊的结果。
#check for null values
if st.checkbox('Missing Values'):
st.markdown("Missing values are known as null or NaN values. Missing data tends to **introduce bias that leads to misleading results.**")st.write("Number of rows:", len(df))
dfnull = df.isnull().sum()/len(df)*100
totalmiss = dfnull.sum().round(2)
st.write("Percentage of total missing values:",totalmiss)
st.write(dfnull)
if totalmiss <= 30:
st.success("Looks good! as we have less then 30 percent of missing values.")
else:
st.success("Poor data quality due to greater than 30 percent of missing value.")st.markdown(" > Theoretically, 25 to 30 percent is the maximum missing values are allowed, there’s no hard and fast rule to decide this threshold. It can vary from problem to problem.")
st.markdown("[Learn more about handling missing values]([https://medium.datadriveninvestor.com/easy-way-of-finding-and-visualizing-missing-data-in-python-bf5e3f622dc5](https://medium.datadriveninvestor.com/easy-way-of-finding-and-visualizing-missing-data-in-python-bf5e3f622dc5))")
理论上,25%到 30%是允许的最大缺失值,没有硬性规定来决定这个阈值。它可能因问题而异。
图片作者。点击查看 app 。
完整率
完整性定义为数据集中非缺失值与记录总数的比率。实际上,大于 0.85 的完全率是可接受的。
#check for completeness ratio
if st.checkbox('Completeness Ratio'):
st.markdown(" Completeness is defined as the ratio of non-missing values to total records in dataset.")
# st.write("Total data length:", len(df))
nonmissing = (df.notnull().sum().round(2))
completeness= round(sum(nonmissing)/len(df),2)
st.write("Completeness ratio:",completeness)
st.write(nonmissing)if completeness >= 0.80:
st.success("Looks good! as we have completeness ratio greater than 0.85.")
else:
st.success("Poor data quality due to low completeness ratio( less than 0.85).")
图片作者。点击查看 app 。
复制率
重复率定义为数据集中的重复记录数除以记录总数。没有硬性规定来决定门槛。它可能因问题而异。
#check dupication rate
if st.checkbox('Duplication Rate'):
st.markdown(" Duplication rate is defined as the ratio of number of duplicates to total records in dataset.")
duplicated = df.duplicated().sum()
dupratio= round(duplicated/len(df),2)
st.write("Duplication rate:",dupratio)
st.markdown(" > There’s no hard and fast rule to decide the threshold. It can vary from problem to problem.")
图片作者。点击查看 app 。
正规性检验
正态性检验用于确定数据集是否由正态分布很好地建模。对于正态性检验,我们可以使用偏斜度技术,这是一种量化分布被向左或向右推的程度,是分布不对称性的一种度量。
#check for normality test
if st.checkbox('Normality'):images=Image.open('images/n.png')
st.image(images,width=600, caption="Image from ALVARO.")st.markdown("Normality tests are used to determine if a dataset is well-modeled by a normal distribution. For normality test we can use skewness technique which is a quantification of how much a distribution is pushed left or right, a measure of asymmetry in the distribution.")
aa= pd.DataFrame(df).skew()
normalityskew= round(aa.mean(),4)
st.write("How far is my dataset from Normal Distribution:", normalityskew)if normalityskew == 0 :
st.success("Your dataset is in Normal Distribution i.e mean, mode and median are all equal ")
elif normalityskew > 0:
st.success("Positively Skew so Mean > Median > Mode")elif normalityskew < 0:
st.success("Negatively Skew so Mode > Median > Mean")
图片作者。点击查看应用。
这就完成了我们用 Streamlit 构建的基于 python 的数据质量检查 web 应用程序。这只是理解数据集质量的一个小方法。维护和验证数据的质量是关键所在,应该承担很大的责任。
引用亨利·福特的话作为结束语:
质量意味着在没人看的时候做对。
点击此处,了解关于从 DataCamp 免费创建 python 应用程序的更多信息。(附属链接)
GitHub 提供完整代码:
https://github.com/maladeep/data-quality-checker
想进一步讨论这个吗?请在 Linkedin 上发表评论或与我联系。
推荐读物
https://www.datapine.com/blog/data-quality-management-and-metrics/
构建您的首个数据科学应用
原文:https://towardsdatascience.com/build-your-first-data-science-application-9f1b816a5d67?source=collection_archive---------8-----------------------
七个 Python 库,打造您的第一个数据科学 MVP 应用
凯利·西克玛在 Unsplash 上的照片
要制作我的第一个数据科学应用程序,我需要学习什么?web 部署呢?web 应用需要学习 Flask 或者 Django 吗?做深度学习应用需要学习 TensorFlow 吗?我应该如何制作我的用户界面?我也需要学习 HTML、CSS 和 JS 吗?
当我开始学习数据科学的旅程时,这些是我脑海中一直存在的问题。我学习数据科学的目的不仅仅是开发模型或清理数据。我想开发人们可以使用的应用程序。我在寻找一种快速制作 MVP(最小可行产品)的方法来测试我的想法。
如果你是一名数据科学家,并且想开发你的第一个数据科学应用程序,在本文中,我将向你展示 7 个 Python 库,你需要学习它们来开发你的第一个应用程序。我相信你已经知道其中一些,但我在这里提到它们是为了那些不熟悉它们的人。
照片由 Med Badr Chemmaoui 在 Unsplash 拍摄
熊猫
数据科学和机器学习应用都是关于数据的。大多数数据集是不干净的,它们需要为你的项目进行某种清理和操作。Pandas 是一个库,可以让你加载、清理和操作你的数据。您可以使用 SQL 之类的替代方法进行数据操作和数据库管理,但是 Pandas 对于您这样一个想成为开发人员(或者至少是 MVP 开发人员)的数据科学家来说要容易得多,也更适用。
点击了解更多关于熊猫的信息。
Numpy
在许多数据科学项目中,包括计算机视觉,数组是最重要的数据类型。Numpy 是一个强大的 Python 库,允许您使用数组、操作数组,并高效地对数组应用算法。学习 Numpy 对于使用我稍后提到的其他一些库是必要的。
点击安装并了解更多关于 Numpy 的信息。
SciKitLearn
这个库是许多类型的机器学习模型和预处理工具的工具包。如果你正在做一个机器学习项目,有一点点可能你不需要 SciKitLearn。
安装并了解更多关于 SciKit 的信息-点击了解。
喀拉斯或皮托尔奇
神经网络,尤其是深度神经网络模型,是数据科学和机器学习中非常流行的模型。许多计算机视觉和自然语言处理方法都依赖于这些方法。几个 Python 库提供了对神经网络工具的访问。TensorFlow 是最著名的一个,但我相信初学者很难从 TensorFlow 入手。而是建议你学习 Keras,它是 Tensorflow 的一个接口(API)。Keras 使您作为一个人可以轻松测试不同的神经网络架构,甚至构建自己的架构。另一个最近越来越流行的选择是 PyTorch。
安装并了解更多关于 Keras 和 PyTorch 的信息。
要求
如今,许多数据科学应用程序都在使用 API(应用程序编程接口)。简而言之,通过 API,您可以请求服务器应用程序允许您访问数据库或为您执行特定的任务。例如,Google Map API 可以从您那里获得两个位置,并返回它们之间的旅行时间。没有 API,你必须重新发明轮子。Requests 是一个与 API 对话的库。如今,不使用 API 很难成为一名数据科学家。
点击安装并了解更多请求。
Plotly
绘制不同类型的图表是数据科学项目的重要组成部分。虽然 Python 中最流行的绘图库是 matplotlib,但我发现 Plotly 更专业、更易用、更灵活。Plotly 中的绘图类型和绘图工具非常多。Plotly 的另一个优点是它的设计。与具有科学外观的 matplotlib 图形相比,它看起来更加用户友好。
点击安装并了解更多关于 Plotly 的信息。
ipywidgets
谈到用户界面,你必须在传统外观的用户界面和基于网络的用户界面之间做出选择。您可以使用像 PyQT 或 TkInter 这样的库来构建传统外观的用户界面。但是我的建议是制作可以在浏览器上运行的 web 外观的应用程序(如果可能的话)。要实现这一点,您需要使用一个在浏览器中为您提供一组小部件的库。ipywidgets 为 Jupyter Notebook 提供了丰富的小部件。
点击安装 ipywidgets 并了解更多信息。
Jupyter 笔记本和瞧
创建第一个数据科学应用程序需要学习的最后一些工具是最简单的。第一,ipywidgets 在 Jupyter 笔记本中工作,你需要使用 Jupyter 来制作你的应用。我相信你们中的许多人已经在使用 Jupyter 笔记本进行建模和探索性分析。现在,把 Jupyter 笔记本想象成前端开发的工具。还有,你需要使用 Voila,一个你可以启动的第三方工具,它隐藏了 Jupyter Notebook 的所有代码部分。当您通过 Voila 启动 Jupyter 笔记本应用程序时,它就像一个 web 应用程序。您甚至可以在 AWS EC2 机器上运行 Voila 和 Jupyter 笔记本,并从互联网访问您的简单应用程序。
点击安装并了解更多关于的信息。
摘要
使用我在本文中提到的 7 个库,您可以构建人们使用的数据科学应用程序。通过成为使用这些工具的大师,您可以在几个小时内构建 MVP,并与真实用户一起测试您的想法。后来,如果您决定扩展您的应用程序,除了 HTML、CSS 和 JS 代码之外,您还可以使用更专业的工具,如 Flask 和 Django。
关注我在媒体和推特上的最新报道。
使用 Streamlit 构建您的第一个 Python 数据可视化 Web 应用程序
原文:https://towardsdatascience.com/build-your-first-data-visualization-web-app-in-python-using-streamlit-37e4c83a85db?source=collection_archive---------8-----------------------
在不到 20 分钟的时间内,使用 Streamlit 视觉表达功能进行自我探索式可视化
最终产品快照。图片作者。Allison Horst 的作品。
作为数据科学弟子,我以前更多的工作是在 jupyter 笔记本上,进行 EDA ,设计开发模型,只在笔记本上展示结果。有时,我试图连接 Flask 模型,并为观众提供一个工作视图,但连接和开发一个具有前端的模型似乎既耗时又繁琐。然后我开始探索 alternative 并来到 Streamlit,这是一种分享机器学习/数据科学模型、分析和可视化的好方法,完全不用担心前端。
" Streamlit 是 ML 和数据科学工具的下一步."—来自 Vega-Lite 的张秀坤·莫提兹
社区喜欢它。图片来自 Streamlit 网站。
Streamlit 是一个发展迅速的开源 Python 库,可以轻松地为数据科学及其子领域制作漂亮的定制 web 应用。它也是一个优秀的工具,允许我们创建高度交互式的仪表板。Streamlit 最大的优点是,它不需要任何 web 开发知识。如果你懂 Python,你就可以开始了!
我喜欢 streamlit,因为它为非技术团队带来了一些高级模型和视觉效果。它可以让你从 jupyter 笔记本变成一个时尚的网络应用,值得以最小的努力提供给观众。
在这里,我们将学习通过使用 Streamlit visual expression 的强大功能来构建自我探索的可视化,我假设您对使用 jupyter notebook 有很好的理解。
这是本教程的完整代码如果你想继续学习本教程,这是最终产品。
最终产品。作者 Gif。
要求
- Python 3.7 版本或更高版本
- Streamlit 0.60 版本或更高版本
- 熊猫图书馆
- 数字图书馆
- Seaborn 图书馆
- Matplotlib 库
- Python 脚本的升华文本编辑器
我们开始吧
让我们首先通过 Mac 的终端或 windows 的命令提示符将 Streamlit 安装到我们的系统中。这里我使用终端。
$ pip install streamlit
一旦完成,让我们运行 Streamlit。
$ streamlit hello
运行上述命令后,localhost 服务器将在您的浏览器中打开,自动显示包含少量演示内容的 Streamlit 主页。
本地服务器上细流的主页。图片作者。
对于这个演示,我使用的是帕尔默企鹅数据。数据由克里斯汀·戈尔曼博士和LTER 南极洲帕尔默站收集并提供。在这里,我们将数据保存为“Penguin data.csv”
https://github.com/allisonhorst/palmerpenguins
目标
在帕尔默企鹅上创建自我探索可视化,用户可以
1。探索 daw 数据
2。参见统计描述
3。创建自己的图形(计数图、箱线图和显示图,根据用户的选择)
一旦我们下载了数据,让我们在任何文本编辑器中打开一个新文件(这里我使用的是 sublime 文本编辑器,并将其命名为 app.py
正在导入核心包,请注意我们正在使用*‘ST’*作为 Streamlit 命令。
import streamlit as st
from PIL import Image
导入数据可视化和数据操作包
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use("Agg")
import seaborn as snsimport pandas as pd
import numpy as np
正在连接数据。
DATA_URL = ("Penguin data.csv")
到目前为止,我们的代码是这样的
图片作者。
现在,让我们使用减价来给出一些标题和一些信息(你一定会觉得哇,是的,减价是被接受的,_ )。此外,让我们添加一个图像。
请记住,您可以使用 st.markdown( ) 而不是 streamlit.markdown( ) ,因为我们将 streamlit 导入为' st' 。
st.markdown("# Self Exploratory Visualization on palmerpenguins")
st.markdown(“Explore the dataset to know more about palmerpenguins”)img=Image.open('images/palmerpenguins.png')
st.image(img,width=100)st.markdown(“**Penguins** are some of the most recognizable and beloved birds in the world and even have their own holiday: **World Penguin Day is celebrated every year on April 25**. Penguins are also amazing birds because of their physical adaptations to survive in unusual climates and to live mostly at sea. Penguins propel themselves through water by flapping their flippers. Bills tend to be long and thin in species that are primarily fish eaters, and shorter and stouter in those that mainly eat krill.”)st.markdown(“The data presented are of 3 different species of penguins - **Adelie, Chinstrap, and Gentoo,** collected from 3 islands in the **Palmer Archipelago, Antarctica.**”)
要在终端或命令提示符下运行应用程序:
$ streamlit run app.py
一旦你运行应用程序,这是结果。
图片作者。
现在,为了使过程更具交互性,让我们使用 st.button 添加一个按钮,一旦用户点击它,我们将使用 st.balloons( ) 显示一个带有一些气球效果的图像
if st.button("Meet the Palmer Penguins"):
img=Image.open('images/lter_penguins.png')
st.image(img,width=700, caption="We are Penguin 🐧")st.markdown(
"The data was collected and made available by **[Dr. Kristen Gorman]([https://www.uaf.edu/cfos/people/faculty/detail/kristen-gorman.php)**](https://www.uaf.edu/cfos/people/faculty/detail/kristen-gorman.php)**) and **[Palmer Station, Antarctica, LTER]([https://pal.lternet.edu/)**](https://pal.lternet.edu/)**).")
images=Image.open('images/meet.png')
st.image(images,width=600)
#Ballons
st.balloons()
在这里,您不需要重新运行应用程序,因为 Streamlit 会自动更新。您将看到一个带有文本的按钮:遇见帕尔默企鹅
图片作者。
一旦你点击按钮,我们就会看到这些可爱的企鹅和飞行气球的图片。
图片作者。Allison Horst 的作品。
现在,让我们使用 st.info( ) 突出显示数据中的内容,并再次添加一些图片。
st.info(“ The dataset contains the different aspect between the species like Body Mass (g), Flipper Length (mm), Culmen Length (mm), Culmen Depth (mm) etc.”)
img=Image.open(‘images/beak.jpg’)
st.image(img,width=700)
它呈现出
图片作者。由艾莉森·霍斯特创作的艺术品。
现在,允许用户探索数据的时刻到来了。我们将使用 st.sidebar 创建一个侧面板,并使用 st.sidebar.markdown( ) 在其上添加一些 markdown,我们将添加一些按钮来根据他们的需要浏览数据。我们还需要用 nrows 选项加载数据,解析它,并在数据完成时向用户显示信息。
st.sidebar.markdown("## Side Panel")
st.sidebar.markdown(“Use this panel to explore the dataset and create own viz.”)df = pd.read_csv(DATA_URL, nrows = nrows)
lowercase = lambda x:str(x).lower()
df.rename(lowercase, axis='columns',inplace=True)
return dfst.header(“Now, Explore Yourself the Palmer Penguins”)
# Create a text element and let the reader know the data is loading.
data_load_state = st.text('Loading palmerpenguins dataset...')
# Load 10,000 rows of data into the dataframe.
df = load_data(100000)
# Notify the reader that the data was successfully loaded.
data_load_state.text('Loading palmerpenguins dataset...Completed!')images=Image.open('images/meet.png')
st.image(images,width=600)
在我们的侧边栏上工作,我们为用户的自我探索添加选项和信息。
我们在此添加:
- 标题带 st.title( )
- 副标题为 st.subheading( )
- 带 st.checkbox()的复选框
- 用 st.write() 在屏幕上写入输出
# Showing the original raw data
if st.checkbox("Show Raw Data", False):
st.subheader('Raw data')
st.write(df)st.title('Quick Explore')
st.sidebar.subheader(' Quick Explore')
st.markdown("Tick the box on the side panel to explore the dataset.")
if st.sidebar.checkbox('Basic info'):
if st.sidebar.checkbox('Dataset Quick Look'):
st.subheader('Dataset Quick Look:')
st.write(df.head())
if st.sidebar.checkbox("Show Columns"):
st.subheader('Show Columns List')
all_columns = df.columns.to_list()
st.write(all_columns)
if st.sidebar.checkbox('Statistical Description'):
st.subheader('Statistical Data Descripition')
st.write(df.describe())
if st.sidebar.checkbox('Missing Values?'):
st.subheader('Missing values')
st.write(df.isnull().sum())
它呈现出
图片作者。
如您所见,我们使用了 Streamlit 语法,并在其中加入了 Python 数据操作和可视化代码。
**例如:**为了看一下 jupyter 笔记本中的数据集,我们这样做:
df.head()
在 Streamlit 中,我们还允许用户选中复选框,使用 if 语句查看原始数据:
if st.sidebar.checkbox('Dataset Quick Look'):
st.subheader('Dataset Quick Look:')
st.write(df.head())
现在,我们将深入创建图形。概念与上面的例子相同,即我们将使用 Streamlit 中的 seaborn 库来显示图形,由 if 语句控制。我们正在创建计数图,直方图或散点图和箱线图。
st.title('Create Own Visualization')
st.markdown("Tick the box on the side panel to create your own Visualization.")
st.sidebar.subheader('Create Own Visualization')
if st.sidebar.checkbox('Graphics'):
if st.sidebar.checkbox('Count Plot'):
st.subheader('Count Plot')
st.info("If error, please adjust column name on side panel.")
column_count_plot = st.sidebar.selectbox("Choose a column to plot count. Try Selecting Sex ",df.columns)
hue_opt = st.sidebar.selectbox("Optional categorical variables (countplot hue). Try Selecting Species ",df.columns.insert(0,None))
fig = sns.countplot(x=column_count_plot,data=df,hue=hue_opt)
st.pyplot()
if st.sidebar.checkbox('Histogram | Distplot'):
st.subheader('Histogram | Distplot')
st.info("If error, please adjust column name on side panel.")
# if st.checkbox('Dist plot'):
column_dist_plot = st.sidebar.selectbox("Optional categorical variables (countplot hue). Try Selecting Body Mass",df.columns)
fig = sns.distplot(df[column_dist_plot])
st.pyplot()
if st.sidebar.checkbox('Boxplot'):
st.subheader('Boxplot')
st.info("If error, please adjust column name on side panel.")
column_box_plot_X = st.sidebar.selectbox("X (Choose a column). Try Selecting island:",df.columns.insert(0,None))
column_box_plot_Y = st.sidebar.selectbox("Y (Choose a column - only numerical). Try Selecting Body Mass",df.columns)
hue_box_opt = st.sidebar.selectbox("Optional categorical variables (boxplot hue)",df.columns.insert(0,None))
# if st.checkbox('Plot Boxplot'):
fig = sns.boxplot(x=column_box_plot_X, y=column_box_plot_Y,data=df,palette="Set3")
st.pyplot()
它呈现出
图片作者。
现在,稍微润色一下,添加数据源信息,艺术品确认。
st.sidebar.markdown("[Data Source]([https://data.world/makeovermonday/2020w28](https://data.world/makeovermonday/2020w28))")
st.sidebar.info(" [Source Article]([https://github.com/allisonhorst/palmerpenguins](https://github.com/allisonhorst/palmerpenguins)) | [Twitter Tags]([https://twitter.com/allison_horst/status/1270046399418138625](https://twitter.com/allison_horst/status/1270046399418138625))")
st.sidebar.info("Artwork by [Allison Horst]([https://twitter.com/allison_horst](https://twitter.com/allison_horst)) ")
st.sidebar.info("Self Exploratory Visualization on palmerpenguins - Brought To you By [Mala Deep]([https://github.com/maladeep](https://github.com/maladeep)) ")
st.sidebar.text("Built with ❤️ Streamlit")
它呈现出
图片作者。
这结束了我们的过程。这是本教程的完整代码,这是你刚刚和我一起开发的最终产品。
在短短 20 分钟内,你已经开发了一个自我探索的可视化应用程序。在这里,我们已经讨论了交互式小部件、数据框、标题、图像、降价、绘图渲染。现在,您可以尝试不同的数据集来创建交互式数据可视化应用程序,我将更高兴地看到您在 Streamlit 上的进展。
Streamlit 社区论坛 每周综述 精选
点击此处,了解更多关于从 DataCamp 免费创建此类应用的信息。(附属链接)**
如果你对这篇文章有任何疑问,或者想在你的下一个 Streamlit 项目上合作,请在LinkedIn上 ping 我。
推荐读物
- 细流超越烧瓶
- Streamlit 教程
- 知道这 5 个 HCI 的原则会让你的数据可视化看起来很惊艳
- 鲜为人知的数据可视化方法
- Streamlit + Heroku = Magic?
建立您的第一个图形神经网络模型来预测 20 分钟内的交通速度
原文:https://towardsdatascience.com/build-your-first-graph-neural-network-model-to-predict-traffic-speed-in-20-minutes-b593f8f838e5?source=collection_archive---------7-----------------------
实践教程
循序渐进的编码实践
图形神经网络(GNN)是深度学习的一个活跃前沿,有很多应用,例如交通速度/时间预测和推荐系统。在这篇博客中,我们将建立第一个 GNN 模型来预测旅行速度。我们将使用来自 dgl 库的示例代码运行时空 GNN 模型。
图片由 Caleb Oquendo 从 Pexels
时空 GNN 模型
我们将训练一个在 IJCAI'18 发表的论文中提出的 GNN 模型:
时空图卷积网络:流量预测的深度学习框架 。
本文的总体思想是使用历史速度数据来预测未来时间步长的速度。
图来源:参考文献1
参见图 1。每个节点代表一个记录交通速度的传感器站。连接两个节点的边意味着这两个传感器站连接在道路上。代表一个地区交通速度的地理图随时间而变化。我们的任务是使用历史数据,例如从 v_{t-M+1} 到 v_ ,来预测未来时间步的速度,例如 v_{t+H} 。这里的 M 是指之前的 M 交通观测值( v_{t-M+1},…,v_ ),而 H 是指下一个 H 时间步,例如,在接下来的 30 分钟内。
图来源:参考文献1
该模型由一组圣 Conv 块和一个输出层组成。每个圣 Conv 区块由两个时间门控 conv 图层和位于两者之间的空间图形 conv 图层组成。输出图层由 conv、诺姆、conv 和一个完整的 conv 图层组成。
准备洛杉矶 METR 数据集
我们先准备数据集,接下来我会解释。
mkdir <your working directory>
cd <your working directory>
# clone dgl source code
git clone [git@github.com](mailto:git@github.com):dmlc/dgl.git
# clone DCRNN_PyTorch repo, because we need the data folder from it
git clone [git@github.com](mailto:git@github.com):chnsh/DCRNN_PyTorch.git
# copy the data folder from DCRNN_PyTorch repo to dgl repo
cp -r DCRNN_PyTorch/data dgl/examples/pytorch/stgcn_wave/
# go to the stgcn_wave folder
cd dgl/examples/pytorch/stgcn_wave/
然后从这个 Google drive 下载 metr-la.h5 文件,放在 data 的文件夹里。最后,您的目录结构应该是这样的:
.
├── data
│ ├── metr-la.h5
│ └── sensor_graph
│ ├── distances_la_2012.csv
│ ├── graph_sensor_ids.txt
├── load_data.py
├── main.py
├── model.py
├── README.md
├── sensors2graph.py
└── utils.py
请注意,在数据文件夹中,我们只需要 metr-la.h5、graph_sensor_ids.txt 和 distances_la_2012.csv 文件。数据文件夹中的其他文件无关紧要。
METR-拉交通数据集广泛用于交通速度预测。它包含从洛杉矶县高速公路的环形检测器收集的交通信息。选择了 207 个传感器,数据集包含从 2012 年 3 月 1 日到 2012 年 6 月 30 日收集的 4 个月的数据。
文件 graph_sensor_ids.txt 包含传感器的 id。文件 distances_la_2012.csv 包含传感器之间的距离。这两个文件用于创建一个邻接矩阵,然后使用 dgl 库创建一个图。
METR-洛杉矶数据集的传感器分布(图来源:参考文献[2])
文件 metr-la.h5 包含一个形状为[34272,207]的数组,其中 34272 是时间步长的总数,207 是传感器的数量。该数组仅包含速度数据,这意味着 GNN 模型使用历史速度来预测未来速度。不涉及其他特征(道路类型、天气、节假日)。用传感器每 5 分钟记录一次速度。207 个传感器分布在区域内的道路上。分布见上图。每 5 分钟收集一次速度。所以一天应该有 24*(60/5)=288 条记录。因此,一天的数据只是一个形状数组[288,207],其中 288 是总时间步长,207 是传感器的数量。由于数据是在 4 个月内收集的,在可选的数据清理之后,总共有 34272 个时间步长。下面是前 5 行。标题是传感器的 id,内容的值是速度。
文件 metr-la.h5 的标题和前 5 行
为了使数据适应机器学习,我们需要准备特征 X 和目标 Y 。对于每个样本(时间步长 t ),特征 X 是其从 t-144 到 t-1 (12 小时)的过去 144 个时间步长的速度历史。假设我们有 N 个样本,那么 X 的形状就是 N,144,207 。目标 Y 是未来时间步的速度,比如说 t+4 ,那么 Y 的形状就是 N,1,207 。现在我们有了( X,Y )对,我们可以把它们馈送给 ML。
培训、验证和测试
现在我们已经准备好训练、验证和测试了。
首先,创建一个虚拟环境并安装软件包。你需要访问这个链接来选择你合适的 dgl 包。
conda create -n stgcn_wave python=3.6
conda activate stgcn_wave
pip install dgl-cu102 -f [https://data.dgl.ai/wheels/repo.html](https://data.dgl.ai/wheels/repo.html)
pip install torch
pip install pandas
pip install sklearn
pip install tables
然后我们可以通过以下方式运行 main.py
# maybe you need to adapt your batch size to suit your GPU memory
python main.py --batch_size 10
main.py 一次性完成训练、验证和测试。它使用 pytorch 作为 ML 框架。总的来说,使用 NVIDIA GeForce GTX 1080 显卡需要将近一天的时间。
作为评估行驶速度预测模型的常用方法,脚本中使用了平均绝对误差(MAE)、平均绝对百分比误差(MAPE)和均方根误差(RMSE)。下面是我日志的结尾:
我的日志截图
MAE (6.68)接近于 dgl 库的自述文件中声称的版本(~5.76)。如果我能够使用默认的批处理大小(50)运行,我可能会得到更接近的结果。
参考文献:
1冰雨,郝腾银,朱占兴,时空图卷积网络:一个用于流量预测的深度学习框架,2018,IJCAI。
[2],Rose Yu,Cyrus Shahabi,,扩散卷积递归神经网络:数据驱动的交通预测,2018,ICLR。
用卷积神经网络(CNN)构建您的第一个图像分类器
原文:https://towardsdatascience.com/build-your-first-image-classifier-with-convolution-neural-network-cnn-b4e9034ec5cb?source=collection_archive---------12-----------------------
CNN tensor flow 初学者指南
图片由皮克斯拜的 Gerd Altmann 提供
卷积神经网络(CNN)是一种深度神经网络,主要用于图像分类和计算机视觉应用。本文将通过使用 Python 中的 TensorFlow 包实现 CNN,引导您创建自己的图像分类模型。
一个简单的神经网络有一个输入层、一个隐藏层和一个输出层。深度神经网络可以有两个或多个隐藏层。卷积神经网络具有卷积层,其后是完全连接的神经网络。层的类型及其功能将在后续章节中解释。
简单的神经网络或完全连接的层
简单的神经网络(图片由作者提供)
上图中突出显示的部分显示了一个神经元。神经元是神经网络的基本元素。神经元接受输入,对其应用权重来预测输出。隐藏层中的每个节点都是前一层(在本例中为输入层)输出的函数。用于获得隐藏层输出的函数被称为激活函数。最后,输出 y 通过将权重应用于隐藏层的每个节点并通过应用适当的激活函数将它们组合而获得。
CNN 的架构
基本 CNN 的架构(图片由作者提供)
卷积层从图像(输入)中提取特征。一个小的过滤器或内核扫描整个图像并提取特征,例如,一条垂直线或一条水平线,并创建一个特征图。卷积层之后的层是池层。汇集图层实质上是对卷积图层提取的要素地图进行缩减采样。由卷积图层提取的要素地图包含要素的准确位置。这可能会导致过度拟合。池图层在整个要素地图中运行过滤器。它只从该筛选器中获取特定信息,根据所选的池化方法,可以是筛选器下的平均值,也可以是最大值。这减小了要素地图的空间大小,并将要素的精确空间信息转换为粗略信息。这有助于防止过度拟合。根据输入数据集的复杂程度,任何卷积和池化图层都可以堆叠在一起。最终的池层随后被展平并转换为一维数组,然后被提供给预测输出的完全连接的层。这是卷积神经网络架构的总结。在接下来的步骤中,我们将使用该算法实现它来构建我们的第一个图像分类器。
履行
我们将使用 Keras 的 MNIST 数据库来训练该模型,以对手写数字进行分类。MNIST 数据库由大小为 28x28 的手写数字的黑白图像组成。让我们从导入和可视化数据集开始。此外,我们还通过将整个数据集除以 255 来标准化数据。这是因为数据集中的值范围是从 0 到 255。进行归一化是为了使整个数据集达到共同的比例。
下面是存储在数据库中的图像示例。
存储在 MNIST 数据集中的手写数字图像(作者提供的图像)
现在我们已经完成了数据集的导入和规范化,让我们继续构建模型。下面是我们将要建立的模型的示意图。
我们的模型将包含三组卷积和池层以及两个完全连接的层。上一节解释了每种类型层的功能。上面的示意图可以用 python 实现,如下所示。
“过滤器”参数定义卷积层的深度:叠加在一起形成一个卷积层的特征地图的数量。我们使用的内核大小为 3x3,除了最后一层,所有层的激活函数都被设置为 relu,简称为整流线性 **激活函数。**我对最后一个密集层使用的是 softmax 激活,基本上给出了每一类的概率分布,根据其概率可以预测出正确的类。点击 链接 可以了解更多关于激活函数的信息请注意,只有第一层需要“input_shape”参数。这必须是输入的大小。在这种情况下,input_shape 参数是(28,28,1),这是输入图像的大小。密集层中的“单位”参数是节点的数量。最后一层中单元的数量必须基本上等于输出类的数量。在我们的例子中,输出类的数量是 10 (0 到 9)。
我们已经定义了一个函数来构建模型。下一步将是优化模型,调整权重以最小化损失。我们将定义一个函数来编译带有优化器和损失函数的模型,以获得最佳权重。你可以从这里 了解更多关于优化器的知识
好了,我们已经定义了一个函数来建立模型并编译模型。我们唯一剩下的就是用我们的数据集来训练模型。在下一步中,我们将定义一个函数来训练模型。在下面的代码片段中,“epochs”是算法遍历整个数据集的次数。“x”和“y”是训练数据集和相应的标签。
让我们通过使用合适的参数调用每个相应的函数来总结所有三个部分(构建、编译和训练)。在将数据集输入模型之前,我们必须执行一些小的数据预处理。MNIST 的输入数据是 28x28 的形状。然而,灰度图像是 28×28×1 的形状。因此,我们必须将训练和测试数据调整为 28x28x1。此外,存储在 train_y 和 val_y 变量中的数字的标签是数字的。这些数字必须被视为绝对的,因为我们有 10 个不同的类别(0 到 9)。因此,我们将把标签编码成二进制;例如,0 将编码为[0,0,0,0,0,0,0,0,0],1 将编码为[1,0,0,0,0,0,0,0],2 将编码为[0,1,0,0,0,0,0,0,0]等等。
唷…在没有强大 GPU 的情况下,花了一段时间来训练模型(我没有使用 google collab 这样的云服务)。在上面的代码片段中,“model.save”命令将训练好的模型保存在根文件夹中,稍后可以加载该模型来预测输入,而无需再次重新训练整个模型。所以,我们的模型被建立和训练。让我们来看看它的性能。
该模型经过训练,上面的图显示它表现得相当好。任务完成了吗?还没有。在我们知道如何使用模型来解决问题之前,模型是没有用的。在下一节中,我简要介绍了如何使用之前训练过的模型对手写数字进行分类。为了实际测试该模型,我在一张纸上草草写了一个数字,使用 OpenCV 处理图像,使其与我们用来训练模型的图像一致,并将其传递给模型。可以看到原始图像和处理后的图像。我承认我本可以在图像处理方面做得更好😬。但目的是测试模型,我相当有信心 CNN 将能够对处理后的图像进行分类(相信我,神经网络相当强大)。
输入图像的处理和图像类别的预测
瞧啊。现在你知道用卷积神经网络建立一个图像分类器。您可以随意选择层数和相关参数、时期数等。,并决定什么是最好的。类似的方法可以应用于更复杂类型的图像。一旦你习惯了对手写数字进行分类,你就可以将这种方法应用到来自“https://keras.io/api/datasets/fashion_mnist/”的 MNIST 时装数据集中。
我希望这篇文章对你有用。从https://www.linkedin.com/in/vipul-kumar-03241b102/通过 LinkedIn 与我联系,分享和讨论更多与数据科学相关的技能。
使用 Streamlit 构建您的首个交互式数据科学 Web 应用
原文:https://towardsdatascience.com/build-your-first-interactive-data-science-web-app-with-streamlit-d4892cbe4792?source=collection_archive---------11-----------------------
突出一些最常见的特征
照片由石页康让在 Unsplash 拍摄
Web 应用程序是展示您的数据科学工作的最便捷的方式之一。对于许多没有任何 web 开发经验的数据科学家来说,构建 web 应用程序可能会令人望而生畏。然而,有了 streamlit 框架,web 应用程序对数据科学家来说不再困难——如果你了解 Python,你可以用 streamlit 构建交互式 web 应用程序——这个令人敬畏的框架为我们在幕后制作和布局 web 元素做了艰苦的工作。我们将只关注数据部分。
要安装 streamlit 框架,请使用 pip 工具。
pip install streamlit
一旦安装完毕,你就可以检查它的版本。
streamlit --version
如果您已经正确安装了 streamlit,您可以通过运行以下命令来运行演示应用程序。在应用程序中,您将有机会看到使用 streamlit 框架可以实现的各种可能性。
streamlit hello
在演示应用程序中,你会发现 streamlit 框架支持这么多很酷的功能,而这些功能是数据科学家通常需要的。在这篇文章中,我想提供一个简短的教程来开始使用这个令人敬畏的 web 框架。我敢打赌,如果你了解 Python,你只需要几个小时就能对这个工具有一个合理的理解。
如果你想跟随这个教程,你可以在 GitHub 页面这里找到这个脚本。出于本教程的目的,我们将使用 Titanic 数据集来展示一些常见的 streamlit 技术,重点是交互式小部件。
在适用的地方,我还会集成一些可选的小部件,这样您就可以在这个过程中了解更多。
项目设置
每个 streamlit web 应用的核心都是一个 Python 脚本。在文件的顶部,我们导入必要的依赖项。在这种情况下,我们将使用多个模块,如下所示。
import pandas as pd
import time
import streamlit as st
import plotly.express as px
在数据集方面,我们将使用泰坦尼克号数据集,我们将从互联网上下载。
加载数据
一个值得注意的特性是装饰器st.cache
的使用,这将提高 web 响应能力,因为缓存了之前获取的数据。在这种情况下,titanic 数据集将只被获取一次,并且随着网页的刷新,它将不会被再次获取。与此相关,应该注意的是,一旦代码中有任何更改,脚本将再次运行,因此利用缓存功能对于改善用户体验至关重要。
要查看数据,我们可以简单地运行st.dataframe(titanic_data)
,您将看到如下所示的内容。
数据概述
1.组织元素(如标题)
在 streamlit 中,有几种方法可以给你的网页添加标题。要给页面添加标题,可以运行:st.title(“My First Streamlit App”)
。
要在两个不同的级别添加额外的标题,您可以使用st.header()
和st.subheader()
。
或者,你可以利用减价功能,你可以添加像st.markdown(“#Just like a header”)
和st.markdown(“#Just like a subheader”)
这样的标题。
除了标题之外,streamlit 中一个重要的组织元素是侧边栏,您可以在其中添加配置元素来修改主页上显示的元素。要添加侧边栏,只需在脚本中添加st.sidebar
。值得注意的是,您可能会在侧边栏中添加更多的元素。因此,与其使用st.sidebar
来引用侧边栏,不如创建一个对侧边栏的引用,类似于sidebar = st.sidebar
。
2.多选择小工具
为了收集用户的反馈,我们有几个选项来创建多选择小部件。第一个小部件是单选按钮。
单选按钮代码
您将看到如下所示的内容。请注意,所选选项将是所显示选项的实际值,而不是所选的数字索引。在这种情况下,它将是文本。
用单选按钮选择选项
第二个小部件是**selectbox**
,它提供了一个下拉列表,您可以从中进行选择。代码会是这样的。
selected_sex = st.selectbox("Select Sex", titanic_data['sex'].unique())
st.write(f"Selected Option: {selected_sex!r}")
交互将如下所示。
用选择框选择选项
当您要求用户输入多选时,您应该使用**multiselect**
小部件,如下所示。
selected_decks = st.multiselect("Select Decks", titanic_data['deck'].unique())
st.write("Selected Decks:", selected_decks)
对于这个小部件,您将看到类似下面的内容。
多选小工具
3.与数字相关的部件
当您需要收集数字作为输入时,我们可以使用**number_input**
小部件。和往常一样,您可以命名小部件并为其设置一个值。
数字输入码
在代码中,我还在 streamlit 中包含了一个“通知”特性。当你想显示一条错误消息时,你使用st.error()
,而要显示一条成功消息,你使用st.success()
。另一个包含的特性是使用列(st.beta_columns),这在您拥有彼此密切相关的并行小部件时非常有用。在这种情况下,将收集最小和最大年龄的两个小部件组合在一起是合理的。
使用上面的代码,我们将看到一个如下所示的小部件。
数字输入
除了这个小部件之外,streamlit 还提供了一个 slider 小部件,允许用户在不键入任何内容的情况下指定数字输入。这是代码。
滑块
使用slider
小部件,您可以指定小部件的名称。同时,设置最小值和最大值。除了 slider 小部件,上面的代码还包含了另一个叫做 expander 的特性(st.beta_expander
)。当您想要隐藏一些可选的小部件时,这个特性非常有用。您可以指定是否希望扩展器默认扩展。
下图向您展示了这样一个交互式滑块小部件。
滑块和扩展器
4.文本相关的小部件
为了收集文本数据,我们可以使用**text_input**
和**text_area**
小部件。主要区别在于,text_input
小部件适合收集简短的文本字符串,而如果您想要收集大量的文本数据,则首选text_area
小部件。
文本输入部件
上面的代码向您展示了如何显示这些小部件。我还包括了两个额外的特性。一个是代码显示小部件(st.echo
),除了小部件之外,它还将显示包含在with
语句中的代码。另一个特色是一个复活节彩蛋,就是发射一堆气球(st.balloons
)。这样的功能见下图。
文本输入部件
5.一些其他功能的亮点
进度条代码如下所示。
进度条—代码
这是进度条在应用程序中的样子。
应用程序中的进度条
MarkdownStreamlit 支持 Markdown 条目,为我们创造了很多可能性。要使用这个特性,您只需使用st.markdown
。要了解更多关于 markdown 语法的信息,你可以去 GitHub 。
下面是一些常用的例子。
降价示例
Plots 这里有一个列表,摘自其官方文档。
write(mpl_fig): Displays a Matplotlib figure.
write(altair): Displays an Altair chart.
write(graphviz): Displays a Graphviz graph.
write(plotly_fig): Displays a Plotly figure.
write(bokeh_fig): Displays a Bokeh figure.
下图是用 Plotly 制作的一个图形。
Plotly 制作的直方图
结论
在本文中,我们回顾了一些有用的特性,您应该将它们包含在您的交互式 web 应用程序中。正如您所看到的,streamlit 提供了各种功能,允许您收集数字、文本、多项选择选项,并显示代码、降价和数字。有了 streamlit,您几乎不用担心 web 元素。你只需要专注于构建网络应用的内容。
用 Python 在 7 分钟内构建您的第一个机器学习模型
原文:https://towardsdatascience.com/build-your-first-machine-learning-model-with-python-in-7-minutes-30b9e1a3eafa?source=collection_archive---------10-----------------------
使用熊猫、NumPy 和 Scikit-学习
马塞尔·埃伯勒在 Unsplash 上的照片
当我刚开始学习数据科学时,机器学习听起来像是一门极其困难的学科。我正在阅读一些有着奇特名字的算法,比如支持向量机、梯度推进决策树、逻辑回归等等。
我很快就意识到,所有这些算法本质上都是在捕捉变量之间的关系或数据中的底层结构。
有些关系非常清楚。例如,我们都知道,在其他条件相同的情况下,汽车的价格会随着车龄的增长而下降(经典款除外)。然而,有些关系并不那么直观,不容易被我们注意到。
想简单点,先学基本面。
在本文中,我们将创建一个简单的机器学习算法来预测客户流失。我也会解释一些你需要额外注意的基本要点。因此,我们不仅要练习,还要学习一些理论。
我们将使用 Python 库。更具体地说,Pandas 和 NumPy 用于数据争论,Scikit-learn 用于预处理和机器学习任务。
数据集可以在 Kaggle 上以无版权的知识共享许可获得。让我们从读取数据集开始。
import numpy as np
import pandas as pddf = pd.read_csv("/content/Churn_Modelling.csv")print(df.shape)
(10000, 14)df.columns
Index(['RowNumber', 'CustomerId', 'Surname', 'CreditScore', 'Geography', 'Gender', 'Age', 'Tenure', 'Balance', 'NumOfProducts', 'HasCrCard','IsActiveMember', 'EstimatedSalary', 'Exited'],
dtype='object')
数据集包含 10000 行和 14 列。我们应该使用其他 13 列来预测客户流失(即退出= 1)。退出的列称为目标变量或独立变量。其他列称为特征或因变量。
行号、姓氏和客户 id 是多余的特性,所以我们可以删除它们。客户的 id 或他们的姓氏对客户流失没有影响。
df.drop(["RowNumber","CustomerId","Surname"], axis=1, inplace=True)df.head()
df(作者图片)
编码分类变量
典型的数据集包含分类变量和数值变量。很大一部分机器学习算法只接受数字变量。因此,对分类变量进行编码是一项常见的预处理任务。
我们的数据集包含两个分类变量,即地理和性别。让我们检查这些列中的不同值。
df.Geography.unique()
array(['France', 'Spain', 'Germany'], dtype=object)df.Gender.unique()
array(['Female', 'Male'], dtype=object)
将这些值转换成数字的一种方法是给每个值分配一个整数。例如,法国是 0,西班牙是 1,德国是 2。这个过程称为标签编码。
这种方法的问题在于,算法可能会将这些数字视为一种层级关系。德国被认为比法国有更高的优先权。
为了克服这个问题,我们可以使用一种叫做一键编码的方法。每个不同的值都表示为一个二进制列。如果“地理”列中的值是“法国”,则只有“法国”列的值为 1。其他的变成零。
熊猫的 get_dummies 函数可以用来完成这个任务。
geography = pd.get_dummies(df.Geography)gender = pd.get_dummies(df.Gender)df = pd.concat([df, geography, gender], axis=1)df[["Geography","Gender","France","Germany","Spain","Female","Male"]].head()
一键编码(图片由作者提供)
探索性数据分析
在设计和实现模型之前,探索性数据分析是至关重要的一步。目标是全面了解手头的数据。
我们将通过一些控制来完成这一步。随着经验的积累,您将花费越来越多的时间来探索数据。
探索性数据分析的典型任务是检查数值变量的分布。您还可以用这种方法检测异常值(即极值)。
直方图对于检查变量的分布非常有用。您可以使用 Seaborn 或 Matplotlib 等数据可视化库。我更喜欢用熊猫,因为制作基本情节很简单。
让我们从平衡栏开始。
df.Balance.plot(kind="hist", figsize=(10,6))
余额列的直方图(作者提供的图片)
好像很多顾客都是零余额。将该列转换为二进制可能更好,0 表示无余额,1 表示正余额。
我们可以使用 NumPy 的 where 函数来完成这项任务,如下所示:
df.Balance = np.where(df.Balance==0, 0, 1)df.Balance.value_counts()
1 6383
0 3617
Name: Balance, dtype: int64
三分之一的客户余额为 0。
我们也来画年龄栏的直方图。
df.Age.plot(kind="hist", figsize=(10,6))
年龄列的直方图(按作者分类的图像)
它接近正态分布。高于 80 的值可能会被视为异常值,但我们现在不会关注检测异常值。
随意探索其他数字变量的分布,如任期、产品数量和估计工资。
缩放数值变量
您可能注意到,数值变量的取值范围非常不同。年龄值小于 100,而估计工资超过 1 万。
如果我们按原样使用这些特性,模型可能会赋予具有较高值的列更多的重要性。因此,最好将它们缩放到相同的范围。
一种常见的方法是最小-最大缩放。最高值和最低值分别缩放为 1 和 0。介于两者之间的部分会相应地缩放。
还有更高级的扩展选项。例如,对于具有极值的列,mix-max 缩放不是最佳选择。然而,我们现在将坚持简单的情况。这里的重点是强调特征缩放的重要性。
在引入另一个非常重要的主题后,我们将执行特征缩放。
列车测试分离
机器学习模型通过训练来学习。我们向模型输入数据,它学习变量之间的关系或数据中的结构。
一个模型训练好之后,就要进行测试。但是,用模型训练的数据来测试模型是不可接受的。这类似于作弊。一个模型可能只是记住数据中的一切,并给你 100%的准确性。
因此,在训练模型之前,通常的做法是留出一部分数据用于测试。应该使用测试数据来评估模型性能。
这里重要的是,一个模型不应该有任何关于测试数据的信息。因此,我们在上一步中讨论的特征缩放应该在分割训练集和测试集之后进行。
我们可以手动或使用 Scikit-learn 的 train_test_split 函数来完成此操作。
from sklearn.model_selection import train_test_splitX = df.drop(["Exited","Geography","Gender"], axis=1)y = df["Exited"]X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
X 包含特性,y 包含目标变量。默认情况下,整个数据的 25%被留出用于测试。您可以使用 test_size 或 train_size 参数来更改此比率。
X_train.shape
(7500, 13)X_test.shape
(2500, 13)
我们现在可以进行特征缩放。Scikit-learn 的 MinMaxScaler 函数可用于此任务。我们将创建一个 Scaler 对象,并用 X_train 训练它。
然后,我们将使用经过训练的缩放器来变换(或缩放)X_train 和 X_test。因此,模型不会得到任何关于测试集的提示或信息。
from sklearn.preprocessing import MinMaxScalerscaler = MinMaxScaler()scaler.fit(X_train)X_train_transformed = scaler.transform(X_train)X_test_transformed = scaler.transform(X_test)
模特培训
这部分其实包括两个步骤。第一个是选择算法。有几种机器学习算法。它们都有一些优点和缺点。
我们无法在一篇文章中涵盖所有算法。所以我们会选一个继续。逻辑回归算法是二元分类任务的常用算法。
Scikit-learn 的这一过程如下:
- 创建一个逻辑回归对象,这是我们的模型
- 用训练集训练模型
- 基于特定的度量在训练集和测试集上评估其性能
以下代码将执行所有这些步骤:
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score# Create a model and train it
model = LogisticRegression()
model.fit(X_train, y_train)# Make predictions
y_train_pred = model.predict(X_train)
y_test_pred = model.predict(X_test)# Evaluate model performance
print(accuracy_score(y_train, y_train_pred))
0.78print(accuracy_score(y_test, y_test_pred))
0.80
我们的模型在训练集和测试集上分别达到了 78%和 80%的准确率。肯定是可以改进的。
提高模型性能的一些方法有:
- 收集更多数据
- 尝试不同的算法
- 超参数调谐
在本文中,我们将不讨论模型改进。我认为最有效的方法是收集更多的数据。其他两种方法的潜在改进是有限的。
结论
我们已经介绍了创建机器学习模型的基本工作流程。在真实案例中,每一步都更加详细和深入研究。我们只是触及了表面。
一旦你熟悉了基本的工作流程,你就可以专注于改进每一步了。
建立一个像样的机器学习模型是一个迭代的过程。性能评估后,您可能需要多次修改模型或特征。
你如何评价一个分类模型也是非常关键的。在许多情况下,我们不能只使用一个简单的准确性指标。我之前写过一篇关于如何最好地评估分类模型的文章。
感谢您的阅读。如果您有任何反馈,请告诉我。
零配置构建您的第一个机器学习模型——探索 Google Colab
原文:https://towardsdatascience.com/build-your-first-machine-learning-model-with-zero-configuration-exploring-google-colab-5cc7263cfe28?source=collection_archive---------9-----------------------
开始你的机器学习之旅就是这么简单。
雷锐在 Unsplash 上拍照
机器学习(ML)是一种趋势,每个公司都希望利用 ML 来帮助他们改善产品或服务。因此,我们一直在观察对 ML 工程师不断增长的需求,这种需求已经吸引了许多人的注意。然而,对于许多人来说,ML 可能听起来令人生畏,尤其是对于那些几乎没有编码或数据相关工作经验的人。
一个可能的原因是设置计算机需要大量的努力,允许他们开发任何 ML 模型。在本文中,我想介绍 Google Colab,这是一个用于学习和构建 ML 模型的免费工具(尽管有付费升级选项)。更重要的是,你会发现,它对你来说是零配置——现在就可以使用——唯一的要求是你有一个谷歌账户。如果你还没有,请注册,这样你就可以跟随教程。
我假设你不太了解 ML,但是非常热衷于学习 ML。你懂多少 Python 其实并不重要。我会尽可能用外行人的语言解释主要步骤。
事不宜迟,让我们开始吧。如果你想看源代码,你可以使用链接访问笔记本。
第一步。在 Colab 中创建笔记本
在 Colab 中,您使用笔记本(。ipynb),就像你处理文档(。docx)在微软 Word 中。所以,使用 Colab 的第一步是创建一个新的笔记本,方法是转到:https://colab.research.google.com/。
Colab 中的新笔记本(图片由作者提供)
点击“新建笔记本”按钮后,您会看到 Colab 创建了一个新的笔记本,默认名称为Untitled1.ipynb
。为了现在的教程,姑且称之为first_ml_model.ipynb
。
从现在开始,我们将在这个笔记本上工作。
第二步。导入依赖关系
当我们构建模型时,我们需要经验丰富的 ML 开发人员开发的代码库。本质上,这些库通过提供用于处理数据和构建模型的预定义功能来充当工具集。在本教程中,我们将主要使用以下库。
- scikit-learn :一个 ML 库,由各种数据处理函数和 ML 算法(例如回归、分类和聚类)组成。这个库也称为 sklearn,我们将使用 sklearn 作为参考。
- pandas :一个数据科学库,主要用于在构建 ML 模型之前预处理类似电子表格的数据。
在 Google Colab 的笔记本中,每个工作单元被称为一个细胞,我们使用一系列细胞来完成我们的 ML 工作。在每个细胞中,我们通常做一个特定的任务。要添加单元格,只需点击顶部的+ Code
,如下所示。您可以点击+ Text
添加自己的代码注释。
添加代码单元格(图片由作者提供)
使用创建的代码,通过运行下面的单元,您可以导入本教程所需的库。
导入依赖项(按作者排序的图像)
顺便提一下,如果您试图为 ML 配置一台计算机,您需要在配置 Python 的基础上安装所有这些依赖项。
第三步。工作数据集
在当前教程中,我们将使用红酒质量数据集。你可以在kaggle.com找到关于这个数据集的更多信息,这是一个流行的数据科学和 ML 网站,以一系列比赛为特色。您还可以在领先的 ML 数据存储库 UCI 上找到数据集的信息。
wine 数据集经常被用作展示 ML 模型的例子,因此,在 sklearn 中可以方便地获得它。请注意,sklearn 中的数据集已被修改,以更好地作为 ML 训练和学习的玩具数据集。数据如下所示。
葡萄酒数据框架(图片由作者提供)
上面的截图向您展示了数据的特征。在 ML 中,我们使用特征来研究哪些因素对于正确的预测可能是重要的。正如你所看到的,有 12 种特性可供选择,它们对红酒的质量有潜在的重要性,比如酒精和苹果酸。
一个特定的 ML 与分类有关。每个数据记录都有一个显示其类别的标签,所有记录的类别都被称为数据集的“目标”。在红酒数据集中,标签有三类,我们可以检查标签,如下所示:
红酒数据集—目标(图片由作者提供)
请注意,在典型的管道中,我们通常需要花费大量时间来准备数据集。一些常见的准备工作包括异常值识别和移除/重新编码、缺失数据处理、一键重新编码(某些模型需要)、降维、特征选择、缩放等。因为数据集在 sklearn 中已经被清理为玩具数据集,所以我们不需要担心这些准备工作。
第四步。训练模型
下一步是训练 ML 模型。你可能想知道训练一个 ML 模型有什么意义。嗯,对于不同的用例,有不同的用途。但总的来说,训练一个 ML 模型的目的或多或少是为了对他们从未见过的东西做出预测。这个模型是关于如何做出好的预测。创建模型的方法称为训练,即使用现有数据来确定进行预测的适当方法。
有许多不同的方法来建立一个模型,如 K-最近邻、SVC、随机森林和梯度推进,仅举几例。为了让本教程向您展示如何使用 Google Colab 构建 ML 模型,我们只使用 sklearn 中现成的模型——随机森林分类器。
需要注意的一点是,因为我们只有一个数据集。为了测试模型的性能,我们将数据集分成两部分,一部分用于训练,另一部分用于测试。我们可以简单地使用train_test_split
方法,如下所示。训练数据集有 142 条记录,而测试数据集有 36 条记录,比例大约为 4:1(请注意,test_size=0.2
表示原始数据集的 20%(如果需要,可以取整)用于测试)。
分割数据集(按作者分类的图像)
sklearn 的好处是,它通过预先配置许多分类器来为我们做大量繁重的工作,这样我们只需几行代码就可以使用它们。在下面的截图中,我们首先创建一个随机森林分类器。本质上,它为我们建立了一个框架,我们可以将数据放入其中来构建模型。
创建随机森林分类器
使用 classifier.fit,我们正在训练该模型以生成该模型的参数,以便该模型可用于未来预测。
第五步。做出预测
通过 sklearn 的训练模型,我们可以在我们之前创建的测试数据集上测试模型的性能。如下所示,我们实现了 97.2%的预测准确率。请注意,在玩具数据集中达到这样的高水平并不罕见,但在实际项目中被认为是非常高的。
预测准确度(图片由作者提供)
如果您想更仔细地查看我们模型的预测,您可以运行下面的代码,这样我们就有了一个更完整的预测模型性能报告。
分类报告(图片由作者提供)
您可能会注意到,有几个术语您可能不熟悉,比如精度和召回。您可能会发现关于这些术语和分类模型的相关讨论。
结论
在本文中,我使用 Google Colab 作为代码编辑器,向您展示如何构建 ML 模型来对玩具数据集进行预测。它甚至可能没有触及所有重要的 ML 概念的表面。然而,它确实向您展示了 Google Colab 是一个易于使用的工具,只需要最低限度的配置就可以开始您的 ML 学习之旅。
当您熟悉 Google Colab、Python 和 ML 相关的术语和概念时。您可以探索其他 Python IDEs,如 PyCharm,以获得更高级的 ML 工作和更好的编码体验。
感谢阅读这篇文章。通过注册我的简讯保持联系。还不是中等会员?通过使用我的会员链接支持我的写作(对你没有额外的费用,但是你的一部分会费作为奖励由 Medium 重新分配给我)。
用 Python 构建你的第一个基于情绪的音乐推荐系统
原文:https://towardsdatascience.com/build-your-first-mood-based-music-recommendation-system-in-python-26a427308d96?source=collection_archive---------4-----------------------
实践教程
使用 Spotify API 从头开始基于音频的推荐
照片由阿莱娜·达梅尔拍摄
为什么要建立基于情绪的推荐系统?
虽然音乐流派在建立和展示社会身份方面发挥着巨大的作用,但在音乐偏好领域,歌曲的情感表达以及更重要的是,它对听众的情感印象往往被低估。
流派是不够的
仅仅几十年前,按流派和/或艺术家选择音乐是唯一的选择。想听现场音乐?好吧,选择一个艺术家或者一个典型的基于流派的节日。想买音乐?好吧,看看我们按流派分类的 CD 架,挑一张你喜欢的艺术家的专辑。随着数字音乐平台上定制或预先策划的播放列表和个人推荐的出现,这种情况发生了巨大变化。
因此,如果你的目标是建立一个音乐推荐系统,你将需要找到一种超越流派标签的思维方式,并且——更困难的是——找到量化的方法来将你的想法实现为一个真正有用的推荐工具。推荐方法有两个主要分支:
协同过滤:
在这里,我们对用户行为进行建模,以预测在特定情况下特定用户在统计上可能喜欢什么。这包括“其他人也买了 X”以及考虑到整体受欢迎程度。最后,一个随机的用户很可能比活结更喜欢德雷克。尤其是如果我们已经知道他喜欢其他说唱艺人。
基于内容的过滤
另一种方法是从音乐对象本身检索数据。这可以是元数据,如发行日期、指定的流派或歌曲发行时使用的标签。另一方面,我们也可以从音频本身检索出或多或少的抽象音乐特征。这包括明显的方面,如音调或速度,但也包括高度抽象的数学特征,如 MFCCs,在某种程度上,它是对音乐音色的测量(GER:“Klangfarbe”,EN:“声音的颜色”)。
在这篇文章中,我将向你展示一种无需任何机器学习就能构建有效推荐系统的简单方法。嗯……至少你那边没有。
从哪里获取音频数据?
使用现有算法或机器学习模型从 MIR ( 音乐信息检索)研究中提取音频数据,对于该领域的初学者来说是一件困难的事情。幸运的是,一些聪明人构建了 API 来与我们分享他们的数据,这样我们就可以用它来构建创新技术。
图 1: 节选 Spotify Web API 关于可用音频功能的文档。
Spotify Web API 是一个很好的起点。它可以免费使用,正如你在图 1 中看到的,它提供了多种情绪特征,这些特征是从它们内部的机器学习模型中提取出来的。但是,我们究竟如何用“可跳舞性”、“效价”、“能量”和“节奏”(后者很难被视为情绪特征)来模拟情绪的复杂性呢?实际上,我们只需要其中的两个。
心理学:效价唤醒平面
图 2: 价唤醒平面和其上几种情绪/心境的位置(改编自 Russel,1980)
情绪的因素结构(即情绪存在多少个独立维度)的一个占主导地位的心理学模型是**价-唤醒平面(图 2)。**这是一个二维模型,将每一种现有的情绪或心情还原为其唤醒成分(这种感觉是高能还是低能?)及其化合价成分(感觉好还是不好?).尽管这种模式并非没有问题(例如,恐惧和愤怒在这里会被放在一起),但它被广泛采用,因为它在复杂性和预测能力之间取得了巨大的平衡。
这里令人惊讶的是,我们可以很好地采用价-唤醒平面模型,使用 Spotify API 的“价”和“能量”功能。在本文的其余部分,我将介绍如何从 API 抓取数据,以及如何用它实现一个简单有效的推荐系统。
如何使用 Spotify API 创建数据集
授权(烦人的部分)
让我们从最无趣的部分开始:要访问 Spotify API,你需要按照本指南注册一个应用程序。或者,看看这篇中型文章,其中很好地说明了这个过程。我知道你只是想开始,但不幸的是,你必须先通过认证。一旦您有了自己的客户 ID 和客户机密 ID,我将为您提供创建推荐数据集所需的所有代码。这听起来像交易吗?
代码准备
为了建立一个推荐系统,我们需要一个曲目数据库,从中我们可以挑选出最适合给定曲目的曲目。为此,您只需要 Python 包 tekore ( < pip 在您的终端中安装 tekore >)、您的 Spotify 客户端 ID 和 Secret ID,以及我将向您提供的代码。
首先,请在项目目录中创建一个名为“authorization.py”的新 python 脚本,并用以下代码填充它:
import tekore as tkdef authorize():
CLIENT_ID = “ENTER YOUR CLIENT ID HERE”
CLIENT_SECRET = “ENTER YOUR CLIENT SECRET HERE”
app_token = tk.request_client_token(CLIENT_ID, CLIENT_SECRET)
return tk.Spotify(app_token)
只需输入您的客户 ID 和客户密码 ID,代码中会这么说。这个脚本只做一件事:它授权您访问 Spotify API,并返回一个允许您访问 API 的对象。该脚本充当我们的主程序的助手脚本。然而,主要的是,它确保你的客户 ID 和秘密 ID 对主程序的读者/用户是隐藏的。只有这样我才能和你分享我的全部代码。
获取 Spotify 数据集
当然,有很多方法可以收集数据集。我们将使用一种方法,从超过 120 个流派中抽取 100 首曲目,从而产生一个包含各种风格音乐的约 12000 首曲目的曲目数据库。
如果你还没有安装软件包熊猫和 tqdm 的话,你需要通过< pip install【软件包名称】>来安装它们。从那里,只需复制并运行下面的代码和/或按照我的代码快速概述。
如果您只想复制代码,请跳过这一步
算法是这样工作的:我们使用助手脚本来授权我们的 API 访问。然后,我们使用<sp.recommendation_genre_seeds>获取 Spotify 的所有 120 个流派标签,并将每个流派的推荐数量设置为 100(这是可能的最大数量)。下一步,我们建立一个字典,它可以保存我们想要抓取的所有数据。接下来,我们循环播放每个流派,然后播放该流派的每首曲目。对于这些音轨,我们抓取元数据和音频信息,并将它们存储在我们之前创建的<data_dict>中。然后,我们将字典转换成 pandas 数据帧,删除重复的 id,最后将数据帧导出到我们的工作目录。</data_dict></sp.recommendation_genre_seeds>
**惊艳!**你知道你的工作目录中有一个名为“valence _ 唤醒 _ 数据集. csv”的数据集。接下来,我们将使用这个数据集来构建我们的推荐系统。
如何使用效价和唤醒度进行推荐
基本思想:向量距离
图 3: 应用于一些知名歌曲的价唤醒平面上的距离(仅估计位置)
如果你看一下图 3 ,我们的相似性度量就很容易理解。在那里,我估计了几首著名歌曲在效价唤醒平面上的位置。在这个平面上,每个向量(一条轨迹,其坐标为“价”和“唤醒”),在这个例子中是托托的“罗莎娜”,可以通过一条线与其他轨迹相连。从视觉上看,很明显,迈克尔·杰克逊的“颤栗”的情感轮廓更类似于“罗珊娜”,而不是平面上更远的所有其他曲目。
数学上,连接每条轨道的线也是向量,我们可以测量它们的长度。2D 向量(a,b)的长度或“范数”被定义为 sqrt(a +b ) 。假设一个轨道有 0.5 个“价”和 1 个“能”,因此坐标是(0.5,1)。那么,它的长度,也就是它到坐标系原点(点(0,0))的距离,等于 sqrt((0.5) + 1 ,大约是 1.12。因此,我们所需要的是找到连接一个给定轨迹和所有其他轨迹的所有向量(箭头),应用公式并取具有最低范数/长度的箭头。
从点 p1 到点 p2 的这个“箭头向量”由 *p2-p1 给出。*因此,轨迹 T1 和轨迹 t2 之间基于情绪的“距离”等于 norm(t2-t1)。换句话说,从 t2 中减去 t1,然后使用上面的公式计算得到的向量的范数。在 Python 代码中,这很容易实现:
def distance(p1, p2):
distance_x = p2[0]-p1[0]
distance_y = p2[1]-p1[1]
distance_vec = [distance_x, distance_y]
norm = (distance_vec[0]**2 + distance_vec[1]**2)**(1/2)
return norm
在我的代码中,我使用 numpy.linalg.norm(p2-p1),它做同样的事情。
一些统计问题
在我们进入推荐系统的实际实现之前,我想向您指出我们的系统将要面临的两个统计问题。如果你真的不在乎,就跳过这一部分,或者以后再来。
图 4: “化合价”和“能量”特征的分布。
正如您在图 4 中看到的,这两个特性的分布完全不同。虽然“化合价”似乎遵循某种近似非常平坦的正态分布,但“能量”却严重左倾。这对于我们的模型来说有一个主要的缺点:在不涉及太多统计细节的情况下,这意味着:“化合价”0.2 的“跳跃”并不总是与“能量”0.2 的跳跃是一回事。然而,我们的模型假设向量(0.5,0.5)与(0.7,0.5)一样接近。如果你想解决这个冲突,应用一个 z 变换 会有所帮助。出于本文的目的,我们将忽略这个问题。
图 5: “化合价”与“能量”的相关性与线性回归线。
另一个问题如图 5 所示。在心理学理论中,效价和唤醒被认为是情绪的两个统计上独立的维度。然而,如果我们将数据集中的所有 12,000 首曲目绘制成“能量-价”平面,我们会看到随着“价”的增加,“能量”也会增加。事实上,发现回归斜率为 0.250,这表明两个特征之间存在不可忽略的相关性。不幸的是,这个问题没有解决方案,因为这个错误(至少对我们来说)是内置在 Spotify API 中的。
最终推荐算法
从这一点开始,构建最终的推荐算法就很简单了。我将指导您完成本部分的最后几个步骤。你也可以跟着一起看这个笔记本。
首先,我们导入一些模块:
import pandas as pd
import random
import authorization # this is the script we created earlier
import numpy as np
from numpy.linalg import norm
接下来,我们读入大约 12000 个磁道的数据帧:
df = pd.read_csv("valence_arousal_dataset.csv")
现在,我们将“价”和“能量”列组合起来,形成每个音轨的单个向量“情绪 _vec ”:
df["mood_vec"] = df[["valence", "energy"]].values.tolist()
我们实施推荐算法之前的最后一步是授权您的 Spotify API 访问,就像我们之前做的那样:
sp = authorization.authorize()
最后,是时候实现我们的基于向量距离的推荐算法了。该算法采取的步骤是:
- 从 Spotify API 抓取输入音轨的“价”和“能量”值
- 计算输入轨迹和参考数据集中所有其他轨迹之间的距离。
- 从最低到最高距离对参考轨迹进行排序。
- 返回 n 条最近的轨迹。
代码是:
测试推荐算法
剩下要做的就是测试我们的算法是否产生有意义的结果!每个 Spotify 曲目作为一个 ID,您可以像这样简单地从 web 浏览器中提取:
这就给你带来了 https://open.spotify.com/track/3JOVTQ5h8HGFnDdp4VT3MP?的[si=96f7844315434b0a](https://open.spotify.com/track/3JOVTQ5h8HGFnDdp4VT3MP?si=96f7844315434b0a) "其中" 3JOVTQ5h8HGFnDdp4VT3MP "为曲目 ID。
加里·朱尔斯的《疯狂的世界》
那么我们把加里·朱尔斯的《疯狂的世界》("化合价" = 0.30,"能量" = 0.06)扔到我们的推荐者里怎么样?
Spotify 嵌入加里·朱尔斯的《疯狂世界》。
mad_world = "3JOVTQ5h8HGFnDdp4VT3MP"
recommend(track_id = mad_world, ref_df = df, sp = sp, n_recs = 5)
“化合价”= 0.31,“能量”= 0.05 的最佳推荐是亨瑞·贝拉方特的《荣耀经理》。
Spotify 嵌入亨瑞·贝拉方特的《光荣的马槽》。
还不错!虽然“荣耀经理”来自完全不同的流派,但我们的算法已经匹配了这些歌曲,因为它们都具有相似的“价”和“能量”水平。
托托的《罗珊娜》
让我们再举一个例子!托托的《罗珊娜》“化合价”为 0.739,“能量”为 0.513。
Toto 的《罗珊娜》的 Spotify 嵌入。
最受欢迎的推荐是由 Duelo 创作的“Sentimientos De Chartón ”,其“化合价”为 0.740,“能量”为 0.504。
Spotify 嵌入 Duelo 的“Sentimientos De Chartón”。
再一次,音乐类型非常不同,更像是“拉丁”而不是“流行摇滚”。然而,《Sentimientos De Cartón》捕捉到了这种“浪漫渴望”的感觉,同时仍传达出一种运动感和最佳状态,就像《罗珊娜》一样。
结论和最终想法
**恭喜你!**如果你一直关注这篇文章,那么你要么已经建立了你的第一个基于情绪的推荐系统,要么至少已经了解了一点如何编写这样一个系统。然而,仍有一些事情值得简要地思考或讨论。
我们取得了什么成就?
我们一起建立了音乐推荐系统的基础,该系统使用“价-唤醒平面”的适应以及向量距离测量来匹配传达相似类型情感/情绪的曲目。这种方法从根本上不同于协作过滤方法(“其他用户也购买了[…]”),因为它试图提取歌曲的内在品质,而不依赖于用户数据。这对于你们(像我一样)没有运营大型音乐平台,拥有数十亿相关用户数据点的人来说,尤其有帮助。另一个好处是,这种方法的实现是快速和免费的,从收集数据到实现实际的推荐算法。最后,跨流派类别推荐音乐是任何现实世界推荐系统的期望品质,因为这支持用户参与新类型的音乐并发展他们的个人音乐品味。
我该如何改进这个推荐系统?
正如在统计一节中提到的,**对“价”和“能量”特征进行“z 变换”**将使您的距离测量更准确,从而使您的推荐更准确。
Spotify API 提供了更多功能,如“可跳舞性”、“声音”和“速度”。试着想出合理的方法来**扩展“价-唤醒平面”**或者从零开始开发你自己的变量集。
将基于情绪的方法与协作过滤方法结合起来也是一种有趣的探索。怎么样,在我们使用“价”和“能量”计算出前 10 个推荐之后,我们**按照“流行度”**对推荐重新排序(这也是 Spotify API 中的一个功能)。
你可以让用户决定一组所有推荐都必须是的类型,或者一组不应该出现在推荐中的类型。
最后,你可以通过探索 Spotify API 的可能性和分析越来越多的歌曲来扩展你的参考数据集。较大的数据库更有可能为每个输入轨迹准备一个近乎完美的匹配。
非常感谢你阅读这篇文章!如果您有任何问题或意见,或者有任何不正常的地方,请告诉我。我目前正在探索创造性的方法,使用自建的机器学习模型来扩展这里显示的推荐系统。如果你想看的话,请继续关注!
用 Python 构建你的语言过滤器
原文:https://towardsdatascience.com/build-your-language-filter-with-python-d6502f9c224b?source=collection_archive---------14-----------------------
这是一个关于如何用 python 构建语言过滤器的指南,用于审查污言秽语和其他不合适的内容
玛利亚·克里萨诺娃在 Unsplash 上的照片
语言过滤器是一个你可以去除不必要的脏话的过滤器。某种过滤对于维护网站或所提供服务的真实性是必要的。
这种必要的审查对于各种自然语言处理项目也是有帮助的。为了儿童使用的安全,你可以使用语言过滤,在聊天机器人中使用来阻止亵渎的词语,以及审查被认为对工作不安全的污言秽语。
**注意:**在这篇文章中,我将删除任何被认为冒犯公众的词语。但是,当您在您的设备上尝试这种方法时,建议使用完整的单词来测试它们,并检查它是否如您所愿完美地工作。
在这篇文章中,我们将讨论两个这样的简单方法,我们可以利用有效的语言过滤。一种方法是使用预构建的 python 库模块,它可以有效地执行这项任务,另一种方法是构建自己的定制语言过滤。
有关如何使用深度学习从头开始构建聊天机器人的更多信息,请查看下面的文章。我们今天看到的脏话过滤器对这类应用也很有用,你可以选择过滤掉可能被你的聊天机器人认为是不适当的回复的文本。
照片由 Unsplash 上的 Clément H 拍摄
在本文的这一部分中,我们将探索几种方法来实现过滤掉特定语言中任何不合适的俚语的过程。我们将讨论完成以下任务的两个过程。在第一种方法中,我们将利用亵渎过滤器库来完成项目。在第二种方法中,我们将构建自己的自定义代码来执行这样的操作。
1.脏话过滤方法:
其中一种方法是使用 python 中的脏话过滤器库模块。这是一个通用的检测和过滤脏话的库。包括对英语和俄语的支持。它有助于检测两种语言范围内的脏话,并可以相应地审查它们。
该模块的安装过程非常简单,可以使用以下 pip 命令成功完成:
pip install profanity-filter
但是,在执行您安装的以下库模块时,您可能会遇到一些小问题。在运行本节后面提供的代码时,您可能会遇到的错误之一如下。
**ProfanityFilterError**: Couldn't load Spacy model for any of languages: 'en'
以下错误表明您的 Spacy 模型中没有可用的英语。Spacy 是处理自然语言处理相关数据的最佳工具之一。它建立在高端研究的基础上,旨在支持复杂的任务。如果您还没有安装这个库,我强烈建议您用下面的命令安装它。
pip install spacy
现在你已经安装了 spacy 库,你可以同时在这个模块中安装英语,这样脏话过滤库就可以利用它来过滤不合适的内容。下面提供的以下命令应该可以成功地在您的设备上为 Spacy 型号安装英语。
python -m spacy download en
让我们看一些关于如何有效利用这个库的代码。一旦我们浏览了代码,我们将理解这个库的一些特性,然后在本文的下一节中继续开发我们自己的过滤系统。
代码:
使用脏话过滤器库的代码块非常简单。我们可以导入下面的库和空间模块。我们可以访问需要执行审查操作的特定语言,并将返回值存储在所需的变量中。这个变量现在可以用来有效地过滤掉任何不必要的俚语。下面的代码片段及其输出显示了一个完美的用例示例。
from profanity_filter import ProfanityFilter
import spacyspacy.load('en')pf = ProfanityFilter(languages = ['en'])
pf.censor("That's bullshit!")
输出:
"That's ********!"
亵渎过滤器支持该库中包含的多种语言。目前,两个最突出的语言支持是英语和俄语。本节的特点来自官方来源之后的。让我们看看脏话过滤模块能够实现的一些惊人的功能。
特点:
- 全文或单个单词审查。
- 多语言支持,包括在混合语言编写的文本亵渎过滤。
- 深度分析。该库不仅使用 Levenshtein 自动机检测精确的亵渎单词匹配,还检测衍生和扭曲的亵渎单词,忽略字典单词,包含亵渎单词作为一部分。
- 将库用作管道一部分的空间组件。
- 决策说明(属性
original_profane_word
)。 - 部分文字审查。
- 扩展性支持。可以通过提供词典来增加新的语言。
- RESTful web 服务。
该模块的唯一限制是它是上下文无关的。该图书馆无法检测使用由体面的话组成的亵渎性短语。反之亦然,图书馆不能检测一个亵渎的词的适当用法。这意味着过滤器不能理解一个单词的真实语义。因此,有可能在数据库没有意识到的讽刺语句或俚语中出现失误。
2.如何在不使用该库的情况下构建自己的过滤器系统:
在本节中,我们将了解如何在这个自定义代码块中为特定语言(如英语)构建我们自己的自定义语言过滤器。这种执行的代码很简单,我们可以构建自己的函数来执行这种任务。
第一步是为你的特定项目列出你希望保留审查的所有单词。下面是一个例子代码块的一些话,我们可能希望被审查。用户也可以随意添加和探索任何其他类型的单词。
Banned_List = ["idiot", "stupid", "donkey"]
下一步,我们将定义一个包含三个禁用单词中的两个的随机句子。下面是我们将在变量中声明的句子。
sentence = "You are not only stupid , but also an idiot ."
最后,我们将定义我们的审查自定义函数,该函数将执行审查特定句子中不适当语言的操作。在这个函数中,我们将把想要的句子作为一个参数,并相应地计算下面的内容。我们将用空格将句子分开,这样我们就有了需要的单词。然后,我们将继续检查以下单词是否是禁用列表的一部分。如果是,那么我们将用星号代替这个词。如果没有,我们将继续按照最初的解释打印句子。下面是解释这个函数的代码片段。
def censor(sentence = ""):
new_sentence = ""
for word in sentence.split():
# print(word)
if word in Banned_List:
new_sentence += '* '
else:
new_sentence += word + ' '
return new_sentence
最后,让我们调用函数并查看下面句子的相应输出。
censor(sentence)
输出:
'You are not only * , but also an * . '
还有一些额外的改进,观众可以选择进行,例如为每个单词加入正确数量的星号空格,并确保阅读单词时标点符号不会干扰。这两项任务都很容易完成,我建议有兴趣的人试一试!
结论:
照片由乔·凯恩在 Unsplash 拍摄
在本文中,我们讨论了两种简单的方法,通过这两种方法,我们可以针对任何特定的任务有效地使用语言过滤方法。然而,这些过滤系统的一个主要问题是缺乏对所用语言的语义理解。因此,它无法找出什么合适的短语或特定的巧妙方法来绕过它的方法。
尽管如此,他们在从网站设计到使用深度学习方法创建的聊天机器人的广泛应用中,出色地完成了与大多数常见做法的对抗。您可以找到更好的方法来使用这些函数产生更有效的结果。
如果你想在我的文章发表后第一时间得到通知,请点击下面的链接订阅邮件推荐。如果你希望支持其他作者和我,请订阅下面的链接。
https://bharath-k1297.medium.com/membership
看看我的其他一些文章,你可能会喜欢读!
</6-reasons-why-your-ai-and-data-science-projects-fail-2a1ecb77743b>
谢谢你们坚持到最后。我希望你们喜欢阅读这篇文章。我希望你们都有美好的一天!
用 Keras 以三种方式建立你的神经网络
原文:https://towardsdatascience.com/build-your-neural-networks-with-keras-in-three-ways-553cea182c6b?source=collection_archive---------13-----------------------
如何、为什么以及何时使用每种方法
如何使用 Keras API[图片由作者提供]
我仍然清晰而痛苦地记得我第一次面对神经网络及其实现的情景。好像我的困惑还不够大,试图让我的思想围绕着神经网络的内部工作方式,如何使用 Keras API 的不同方式使混乱更加彻底。所以我坐下来,拼命寻找这个问题的最终答案:实现神经网络的最佳方式是什么?
在接下来的几节中,我们将解开这些乱七八糟的东西。避免不同语法带来的不必要的麻烦,因此我们可以专注于更重要的问题,如使用哪种架构或如何提高模型的性能。
Keras 或者更具体地说是模型 API 可以分为三个部分,因此可以通过多种方式创建模型。接下来,我们将学习如何以及何时利用 API 的哪一部分。
我们将使用良好的 MNIST 数据集,以三种不同的方式构建相同的全连接神经网络。
顺序模型
使用Sequential Model
非常简单。我们既可以通过向构造函数传递一个层列表来构建模型,也可以通过多次调用add()
方法来逐步构建模型。
顺序模型的作用类似于一个线性或普通 层的堆叠,其中每一层恰好有一个输入张量和一个输出张量。这使得我们一方面很容易使用和调试,而另一方面,我们失去了很多灵活性。
层叠[图片由作者提供]
因此,当我们的模型或我们的一个层具有多个输入或输出时,顺序模型是不合适的,我们需要进行层共享,或者我们想要使用非线性拓扑,例如剩余或跳过连接。
我们现在可以编译、训练并获得我们模型的摘要。
>> Total params: 119,306
>> Trainable params: 118,794
>> Non-trainable params: 512
功能 API
functional API
为我们提供了一种建立模型的方法,比顺序模型更加灵活。它使我们能够创建非线性拓扑、共享层,甚至多个输入或输出。作为功能 API 的基础,主要思想是构建一个层图。
我们可以通过用输入维度(28x28 像素)定义一个输入节点来构建一个图层图。
接下来,我们定义更多的节点来重新创建之前的模型。然后,通过将前一个节点作为输入传递给下一个节点来连接这些节点。这些连接为我们提供了构建非线性拓扑所需的灵活性,例如通过连接非相邻节点和创建跳过连接。
我们还可以编译、训练并获得我们的模型的摘要,它与序列模型具有相同的结构。
>> Total params: 119,306
>> Trainable params: 118,794
>> Non-trainable params: 512
模型子类化
用子类化创建模型为我们提供了最大的灵活性。然而,这种灵活性的代价是复杂性和冗长性的增加。
Layer Class
是 Keras 中的核心抽象之一。一个层保存状态(层的权重)和从输入到输出的转换(来自调用的前向传递)。当模型的复杂性增加时,创建定制层特别有用,它为我们提供了在模型架构中创建可重用“块”的方法。
在我们的模型中,我们可以使用一个定制层来创建一个在我们的架构中多次出现的基本构建块。下面的类继承自 layer 类,初始化两层:Dense 和 BatchNormalization。然后,这两层都在正向传递中被简单地调用。
接下来,我们利用上面的自定义层创建我们的模型。我们的类继承自Keras Model Class
,因此得名子类化。我们基于hidden_layer = [128,128]
初始化我们的自定义图层,以及另外两个图层:展平和我们的最终输出图层。然后,在模型的正向传递中,所有的层都被简单地调用。
然后,我们可以再次编译、训练并获得模型的摘要,这应该与之前相同。
>> Total params: 119,306
>> Trainable params: 118,794
>> Non-trainable params: 512
结论
在 Keras 中有三种创建模型的方法。根据我们要解决的问题和我们需要构建的模型,一种方法可能比另一种更适合,但一般来说没有绝对最好或正确的方法。
简单、线性和直观的模型可以而且可能应该用顺序 API 或函数 API 来构建。然而,更复杂、非线性和高度定制的模型将从子类化中受益匪浅。
总之,一个人应该知道并尝试以上所有的方法,扩大他们的工具箱,以便有效地解决问题。
感谢您的阅读!确保保持联系&在 Medium 、 Kaggle 上关注我,或者在 LinkedIn 上说声“嗨”
喜欢这篇文章吗?成为 中等会员 继续无限学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。
https://medium.com/@marvinlanhenke/membership
构建您自己的 arcpy 助手包
原文:https://towardsdatascience.com/build-your-own-arcpy-helper-package-6842e2f6d339?source=collection_archive---------32-----------------------
告别剪切粘贴 Python
沃洛季米尔·赫里先科在 Unsplash 上的照片
Esri 的 arcpy package for Python 是最全面的地理信息管理、分析和可视化工具包。
这种详尽的功能集是以代码的简洁性为代价的。看似简单的操作实现起来可能会很复杂,Esri 的 ArcGIS 软件可能会增加学习曲线。
Pythonic 的格言应该有一个……显而易见的方法去做并不一定适用。
由于技术需求和个人偏好的混合,每个组织都将以自己的方式组装和配置脚本。结果可能是大量重复的代码,以及复制和粘贴的强烈诱惑。更糟糕的是,在一个部门内,同样的行为可能以不同的方式实施。
轮子:不要重新发明它。乔恩·卡塔赫纳在 Unsplash 上的照片
软件工程的一个关键原则是不要重复你自己(干)。 Python 的模块框架是为帮助我们实现这一目标而量身定制的。然而,从地理学家-GIS 分析师(像我一样)的角度来看,当您第一次面对一项复杂的任务时,将 arcpy 与模块开发结合起来可能会感觉像以毒攻毒。这当然是一个我推迟了几年的问题!
事实上,抽象掉重复的逻辑有很多好处。它确保了一致性,有助于维护,并增加了脚本的可读性。您可以进行渐进的改进,并立即看到它们在所有项目中的应用!短期的痛苦伴随着明确的长期收益。
下面是你需要知道的开始。我假设您已经安装了 ArcGIS Pro,并且可以从命令行运行 python 和 pip。你可以在这里找到下面所有代码的模板。
结构
我认为 90%以上的 arcpy 项目都是由单独的脚本组成的。
当我们刚刚找到一种方法来做我们一直试图做的事情时,我们不倾向于用额外的复杂性把它弄乱。
没有必要每次想要自动化某件事情时都创建一个成熟的 Python 项目。然而,当我们包装所有最重要的代码时,我们应该尝试遵循最佳实践。
假设我们有以下 c:\files\parent_folder 文件夹结构
parent_folder module_name tests
我用一个很基本的例子。假设我们想要调用 arcpy。每次我们调用 AddMessage()时都以一种特殊的方式。我们将调用我们的包 archelpy,并创建一个 messages.py 模块。
archelpy archelpy __init__.py
messages.py tests
这个基本的 messages.py 示例在脚本工具界面中将时间戳应用于 arcpy 消息。这有助于确定漫长流程中哪个部分最耗时。
消息. py
您可以决定创建相应的模块来管理属性域、索引、切片缓存或任何数量的其他技术问题,
archelpy archelpy __init__.py
caching.py
domains.py
indexes.py
messages.py tests
测试
单元测试是另一个经常被归为“太难”的话题。
对于许多工作流来说,编写测试可能是多余的。另一方面,它们可能非常有益。
据说可测试代码是高质量的代码。测试鼓励深思熟虑的设计,不鼓励过于复杂或混乱的代码。测试还以其他开发人员能够理解的方式记录了工具的目的和预期行为。随着项目的发展,他们通过验证行为和确保质量来提供安心。
Python 内置的 unittest 框架允许我们检查我们的逻辑是否以我们期望的方式调用了 arcpy(或其他第三方模块)。
archelpy
__init__.py archelpy __init__.py
messages.py tests __init__.py
test_messages.py
测试消息. py
注意测试 _。命名约定很重要。*
从父目录中运行下面的命令将通过在整个项目中搜索测试文件来执行我们的测试套件,
cd c:\files\archelpypython -m unittest discover -v
在这种情况下,我们应该看到这样的结果,
testAddMessageParameters (tests.test_messages.HelpyMessagesTestCase)Uses assert_called_with() to make sure that our code passes ... ok----------------------------------------------------------------------Ran 1 test in 0.003sOK
在实践中,您将创建更多的测试,并将它们组织到不同的文件和目录中。这时,unittest 中的 discover 特性变得特别有用。
打造
我们已经准备好分发包裹了。如果你想大方一点,你可以开源它并把它添加到 PyPi 中。对于专有工作,您更愿意将安装资源保存在安全的地方。
cd c:\<path>\archelpy
ArcGIS Pro 的 Python 安装附带了 setuptools 和 wheels,它们会创建一个名为 wheel 文件的 pip 兼容安装程序。whl)。
我们在名为 setup.py 的文件的顶层目录中定义我们的包属性,
archelpysetup.py
setup.py 模板
运行以下命令,
python setup.py bdist_wheel
这将在项目中生成许多工件,包括一个. whl 文件,您可以用它来安装您的模块!
archelpy dist archelpy-0.1.0-py3-none-any.whl
安装
使用 pip 来安装使用新创建的 wheel 文件的模块,
pip install c:\files\archelpy\archelpy-0.1.0-py3-none-any.whl
您应该会看到以下结果,
Processing c:\files\archelpy\archelpy-0.1.0-py3-none-any.whl
Installing collected packages: archelpy
Successfully installed archelpy-0.1.0
使用!
像这样在脚本工具中导入 archelpy,
from archelpy import messagesmessages.time_message("Hello!", arcpy)
你已经准备好了!当您对软件包进行改进时,使用以下命令重新构建 wheel 文件并更新安装,
pip install <wheel file> --upgrade
快乐脚本!
由 uomo libero 在 Unsplash 上拍摄的照片
感谢
参见起亚 Eisinga 的这篇文章,对包装进行了更深入的讨论。
参见来自帕特里克·肯尼迪的这篇文章,以及来自 Ian Firkin 的这篇文章,分别了解关于测试 Python 和 arcpy 的更多细节。
构建您自己的自动差异化程序
原文:https://towardsdatascience.com/build-your-own-automatic-differentiation-program-6ecd585eec2a?source=collection_archive---------3-----------------------
实践教程
对于那些完全不知道如何使用图形计算导数的人,或者只想知道张量流在基本层面上是如何工作的人,这是你的指南。
照片由在 Unsplash 上拍摄
深度学习如今如此流行,如此广泛,人们很容易问这样一个问题,“为什么人们花了这么长时间才弄明白这个问题?”原因有很多,进入深度学习的历史真的不是这篇文章的重点(参考文献1的介绍做得很好),但使这场革命滚动的关键进步之一是自动微分(AutoDiff) 。
如果您想直接了解技术细节,请跳到“构建自动挖掘”一节,如果您只想了解代码,请跳到“用 Python 实现自动挖掘”一节
关于本文所用代码的配套 Jupyter 笔记本,请参见以下链接:https://github.com/Jmkernes/Automatic-Differentiation
你问自动微分有什么了不起的?假设你正在研究一个函数,你很想知道它的导数。如果这是一个相对简单的函数,你大概可以很快给出答案。如果 *f(x)=x,*那么我们可以很快得出 df/dx=3x 。如果它更复杂,而你不仅仅知道答案呢?好吧,你没有太多的选择。
选项 1:如果你想要数值答案,你可以回到基础,直接计算有限差分,使用公式如下
以及他们更复杂、更精确的表亲。但这并不令人满意。也许我们想要象征性的答案,用 x和 y之类的东西来表示,在这种情况下,一个数字答案是不够的。或者,也许我们的微分变量 x 实际上是一个大的多维张量,为那个东西的每个条目逐个计算数值差将是非常低效和耗时的。
选项二:求导求导。这应该是元的。求导是什么意思?我们之前是怎么知道 df/dx=3x 的答案的?事实证明,只有两种方法可以算出导数。如果这是一个全新的函数,你只需要通过上面显示的极限表达式来得到答案。然而在现实中,大多数函数都不是新的,它们实际上只是其他函数的组合。在这种情况下,我们可以通过链式法则算出新的衍生品:
但是,比如,什么是功能?
我从事的第一个物理项目涉及到一些特殊函数的使用,叫做广义超几何函数。如果你不知道那些是什么,不要担心,这才是重点。像每一个特殊函数一样,它们很难处理,并且包含足够多的身份和特殊情况,足以填满一本哈利波特魔法书。所以,心灰意冷的我去找我的导师,直接问他,“嘿,这到底是什么东西?”
他的回答非常简单——“这只是我们知道的一些功能。”这似乎是一个无用的答案,但它实际上很有深度。然后他问我“你知道余弦是什么,对吗?”对此我尖刻地回应道:“是的,当然,我知道余弦是什么。”他毫不犹豫地回击道,“但是你怎么知道余弦是什么?知道什么是超几何函数和知道什么是余弦有什么不同?最后,你知道余弦是什么,因为你能说出一些恒等式,你能画出一个漂亮的图。就是这样。”
此时,我被难住了。我正面临一场数学生存危机,并重新评估我所学的一切。“我知道余弦是什么,因为我知道它的导数是 -sin(x) !”,我想。“而且,我知道正弦是什么!因为它的导数是 cosi… ",哦不,一个无限循环。
从我的生存危机中恢复过来后,我开始意识到世界上有两种类型的功能:我们熟悉的东西,如 x 或 *x+5,*和我们不熟悉的东西,但可以由熟悉的东西组成——如 (x+5) 。自动微分以后一个概念为中心。我们可以把它的使命描述为:
给定一组初等函数,比如 e^x 、 cos(x) 、或 x 、,然后使用微积分规则,就有可能确定由这些初等函数的组成的的任何函数的导数。
因为我们可以用各种方式表示函数,比如幂级数、傅立叶级数等等。这是一个非常有力的声明。这一切都是通过链式法则起作用的。自学的奇妙之处在于,它在数学上相当于零计划地环游世界。您可以随心所欲地不断组合和堆叠函数,越来越深入,始终确保 AutoDiff 能够跟踪面包屑并为您计算导数。
在这篇文章的其余部分,我们将假设我们想要求导的每一个函数都可以分解成初等函数(如果你想要第二类修正贝塞尔函数的导数,你将不得不去别处寻找
建立我们的自动挖掘系统
在这篇文章结束时,你将能够生成如下图:
来源:现作者。一个非常简单的计算图
但是你喜欢多复杂就有多复杂。我们来分解一下这个图的意思。假设我们被赋予了这个函数
我们想计算 f 对其变量 x,y,和 z 的偏导数。我们可以将这个函数分解成一组非常基本的函数,即函数 add(x,y)=x+y 接受两个数并将它们相加,函数 **multiply(x,y)=xy* 接受两个数并将它们相乘。基本的,对吧?在这种新形式中,我们有
这是一个更罗嗦的表述,但是…这并没有错。
资料来源:knowyourmeme.com。我们冗长陈述的理由。
这种形式很有用,因为我们立即知道了的导数加上和乘以。此外,我们将它重写为两个初等函数的组合,因此我们可以应用链式法则。我们获得
利用基础微积分,我们得到 1*y=y,这显然是正确答案。虽然你可能没有注意到,但是每当你计算导数的时候,你都会隐式地执行上面的操作。现在,让我们让计算机来做这件事。
计算图
为了说明这个过程,我们需要做两件事:1)告诉计算机什么是基本构件 2)告诉它如何把这些构件放在一起计算导数。
让我们先集中讨论第一部分。有四种基本类型的块,我们用图论的语言称之为节点 T21。这些包括
- 变量 —我们想要知道其梯度的可变对象(张量)。
- 常量 —不可变对象(张量),其值一旦指定就不会改变。
- 占位符 —这些基本上是空的容器,一旦我们决定了未来变量或常数的值应该是什么,它们就指定了未来变量或常数的位置。
- 操作符——这些是概念上最难描绘的,但也是最重要的。
前三个应该相对简单。需要一段时间来适应的计算图有一点令人困惑,那就是图中的节点实际上是操作符,而不是变量、常数或占位符。直觉上,我们喜欢认为函数是由它们的值组成的。我们写 f(x,y,z) 的时候用的是 x,y,z. 没有写 f( 加,乘) 。然而,这正是我们的计算机要寻找的。通常,操作符节点接受输入并返回输出。我们假设节点只发出一个输出;虽然张量包含许多项,但它可以被认为是一个单一的输出
来源:现作者。操作符节点的特写。
我们现在可以理解本节开头的图表了。我们只使用了数字,但是这些数字也可以被认为是标量张量。因此,图表显示了张量是如何在计算中流动的。明白了吗?张量…流…张量流。现在让我们考虑相反的方向,计算梯度。
为了计算输出 f(x,y,z) 的实际值,我们沿着箭头的方向向前运行图形,从变量 *x,y,z,*开始,流经操作符。现在让我们用图形来思考这个方程。我们将添加一个额外的、琐碎的计算
这将帮助我们初始化反向传播程序。检查我们的方程对 f 的偏导数,需要注意的一点是*导数也是一个函数!*这意味着链式法则导数也是函数的组合。记住,函数的组合=图形。这是规矩。真正好的是,我们的图形结构是相同的,但反向运行。你可以看到下面的结构:
来源:现作者。红线表示梯度的流动。
红色箭头表示从最终输出到开始的导数流是一个反向计算图。它可以用完全相同的方式计算,其中我们使用平凡的恒等式 df/df=1,为第一个节点提供 1 的导数。我们的目标现在应该很明确了:
- 指定图表中的所有变量、占位符和常量
- 使用运算符将它们组合在一起,形成最终的标量输出
- 计算一个前向传递,它输入值并流经运算符以获得输出。将每个节点的输出值存储在该节点中。
- 计算一个反向传递来计算梯度,从最后一个节点(输出)的梯度 1 开始。
实现这一点是本文剩余部分的目标。
在 Python 中实现自动搜索
我们想预先警告读者这涉及到全局变量。全局变量是禁忌,但是我们使用它们的原因有望随着我们的深入而变得清晰。图是我们的全局对象(好吧,不是一个全局变量,实际上是一个全局对象,很抱歉我说谎了),我们将向其中添加节点。据我所知,没有一种简单的方法可以明确地确定对象的范围,我相信 TensorFlow,至少在 V1,也使用了全局图形变量。如果有人有避免全局变量的解决方案,请在评论中发表!
好了,先不说警告,我们开始吧。我们首先需要定义默认的图形类。这将是一个基本的结构,只跟踪当前的节点和它们的类型。
一些事情:所有在 init 方法之后的事情你都可以忘掉。它不影响代码,只是试图使创建本地化的图形变得稍微容易一些。您也可以删除它,并确保运行Graph()
来初始化全局默认图,运行del _g
来在定义一组节点之前和之后删除它。此外,我们并不真的需要 numpy,它是为了帮助我们以后做矩阵乘法。
太好了,我们有工作图了。现在让我们来定义我们之前讨论的四个类。它们或多或少都是一样的,每个都包含一些独特的功能
Operator 类需要一个输入属性,Constant 类需要保护它的值,其余的类似。我们使用了一些默认的名字,比如 Var1,Var2,…这是描述性的最低水平。name 字段对于以后从图中检索节点很重要,因为我们没有任何其他方法来标识它们
此外,跟踪占位符的名称也很重要,否则我们真的无法在计算图中找到它们。
我们放入了一些其他东西,比如 repr 函数,以类似“Operator: name:mul/2,value:3.875”的格式自动将节点显示为字符串。这应该能帮助我们马上知道我们正在处理的是哪个节点。
现在,为了让我们的图做点什么,我们需要给它一些真正的操作符。这些正是我们一直在谈论的基本操作。像加减乘除之类的东西。我们将定义其中的一些,为了使事情更容易编码,我们将重载所有这些操作符(注意:我想不出更好的方法来做到这一点,既不重复大量的代码,也不需要以奇怪的方式向基本节点类添加方法。接受更好的建议)。一个棘手的运算符是 neg。记住 x - > -x 实际上是一个乘法运算符,所以图形需要知道这一点。
现在,我们所有的基础设施都已就绪。我们只需定义变量、常量或占位符,并执行常规计算,就可以轻松构建图表。操作员将负责向图中添加节点和其他一切。我们可以创建一个图g
并通过下面的语法添加一些操作
with Graph() as g:
x = Variable(1.3)
y = Variable(0.9)
z = x*y+5g.variables # Will output {Variable: name:Var/0, value:1.3, Variable: name:Var/1, value:0.9}g.operators # Will output {Operator: name:add/0, Operator: name:mul/0}g.constants # Will output {Constant: name:Const/0, value:5}
如您所见,该图正确地创建了一个常数,并且还记录了两个操作,x*y 乘法以及常数 5 的加法。如果我们再次运行with Graph() as g
,它应该会删除当前的默认图形,并开始重新构建。酷,一切正常。现在,我们必须使用一点算法知识来计算我们的向前和向后传球。
目前,我们的默认图表只跟踪当前节点。它没有结构。最终,我们想要向前运行我们的图形,这意味着我们给它输入所有的变量、常量和占位符,然后这些通过操作符流到我们的输出。我们这样做的顺序是一个经典的算法问题。我们需要执行一个拓扑排序(CLRS 的书【3】总是好的,或者只是使用维基百科)。我们的图是一个有向无环图,意味着每个节点都有一个起点和终点。没有循环。拓扑排序保证了如果我们按顺序运行每个节点,我们将永远不会缺少计算节点的信息。就像点了课前提;您将时间表调整为在 Calc III 之前学习 Calc I。
经过拓扑排序,我们的图真正成为了一个图。它终于有了一些坚实的结构!即使这个结构只是有序节点的数组。为了完成我们的程序,我们执行通行证。向前传球真的很简单;只需按顺序计算每个节点的值,并将其值存储在该节点中,以便将来的节点可以在需要时访问它。
向后传球稍微难一点,但也不算太难。用值 1 初始化根节点(回想一下使用 df/df=1 的讨论)。然后,只通过它的操作符遍历图形。换句话说,计算当前操作符的所有输入的梯度,然后递归地对那些也是操作符的输入做同样的事情。代码如下:
就是这样!我们已经完成了程序的主要部分。剩下的就是摆弄它,并对它进行一点分析。这里有一个例子,说明如何计算一个简单函数的梯度
它取决于两个变量和一个常数。我们可以很容易地手工计算它的导数,并检查我们的代码是否正确。首先向前传球:
val1, val2, val3 = 0.9, 0.4, 1.3with Graph() as g: x = Variable(val1, name='x')
y = Variable(val2, name='y')
c = Constant(val3, name='c')
z = (x*y+c)*c + x order = topological_sort(z)
res = forward_pass(order)
grads = backward_pass(order) print("Node ordering:")
for node in order:
print(node) print('-'*10)
print(f"Forward pass expected: {(val1*val2+val3)*val3+val1}")
print(f"Forward pass computed: {res}")
---------------------------------------------------""" Output:
Node ordering:
Variable: name:x, value:0.9
Variable: name:y, value:0.4
Operator: name:mul/6
Constant: name:c, value:1.3
Operator: name:add/6
Operator: name:mul/7
Operator: name:add/7
----------
Forward pass expected: 3.0580000000000003
Forward pass computed: 3.0580000000000003
"""
对于向后传球:
dzdx_node = [a for a in order if a.name=='x'][0]
dzdy_node = [a for a in order if a.name=='y'][0]
dzdc_node = [a for a in order if a.name=='c'][0]print(f"dz/dx expected = {val3*val2+1}")
print(f"dz/dx computed = {dzdx_node.gradient}")print(f"dz/dy expected = {val1*val3}")
print(f"dz/dy computed = {dzdy_node.gradient}")print(f"dz/dc expected = {val1*val2+2*val3}")
print(f"dz/dc computed = {dzdc_node.gradient}")---------------------------------------------------""" Output:
dz/dx expected = 1.52
dz/dx computed = 1.52
dz/dy expected = 1.1700000000000002
dz/dy computed = 1.1700000000000002
dz/dc expected = 2.96
dz/dc computed = 2.96
"""
测绘
好吧,所以我答应你在这结束之前你会拍出漂亮的照片。这是我信守的承诺。我们将使用 python 库 Graphviz 。你可能不得不pip install graphviz
这就是为什么我把这个留到最后。要构建图,我们只需为图中的每个节点创建一个节点,然后使用运算符绘制边。操作符决定了图的流向,所以就像我们做 backward_pass 时一样,我们只需要操作符的边。通过使用下面的代码
我们可以制作如下漂亮的图片
它代表了我们之前运行的测试代码的图表。
结论
如果你已经做到了这一步,感谢你的阅读!总而言之,我们已经展示了自动微分是建立在两个理念之上的
- 我们通常对计算导数感兴趣的所有函数都可以表示为初等函数的组合
- 这些初等函数很简单,或者至少有已知的导数,我们可以用它们来提供我们的自动探索程序
从那里,我们可以创建一个图形,拓扑排序,然后运行一个向前向后传递来获得梯度。我希望这是有用的,也是对像 TensorFlow 这样的自动挖掘系统如何工作的很好的介绍。有时候,如果你只是稍微努力思考一些你已经非常了解的东西,你可能会发现一些有趣的东西!
参考
1 Goodfellow,Ian 等深度学习。第一卷。№2.剑桥:麻省理工学院出版社,2016 年。
[2]https://en.wikipedia.org/wiki/Five-point_stencil
[3]科尔曼、托马斯·h 等著算法导论。麻省理工学院出版社,2009 年。
使用 Python 和深度学习构建自己的不和谐调节机器人
原文:https://towardsdatascience.com/build-your-own-discord-moderation-bot-using-python-and-deep-learning-4386fc43e45e?source=collection_archive---------22-----------------------
建立一个自主机器人,删除所有有毒信息。
在 Unsplash 上由 Clément Falize 拍摄的照片
介绍
鉴于互联网用户生成的文本规模,内容审核可能很困难。简化这一过程的一个解决方案是使用机器学习来自动化它。一个 ML 模型训练了版主不想看到的例子,如有毒内容、侮辱或种族主义评论,然后可以用来自动过滤掉这些消息。
在这个项目中,我们将使用 Jigsaw 毒性评论数据集训练这样的模型:https://www . ka ggle . com/c/Jigsaw-Toxic-Comment-class ification-challenge/Data
然后,我们将使这个模型可以从一个 Discord bot 中调用,该 bot 将删除该模型标记为有毒的所有消息。
数据
Jigsaw 毒性数据包括 159,000 个样本,每个样本都可以贴上多个类别的标签,如“有毒”、“侮辱”…
数据集格式-按作者分类的图像
为简单起见,我们使用所有这些类别来创建一个二进制目标,如下所示:
data["label"] = (
data[
["toxic", "severe_toxic", "obscene", "threat", "insult", "identity_hate"]
].sum(axis=1, skipna=True)
> 0.5
).astype(int)
机器学习步骤
机器学习步骤-作者图片
标记器
我用 huggingface 的库训练了我自己的 BPE 分词器,你可以用我的 Github 库中的脚本做同样的事情:
python bleach_bot/ml/train_tokenizer.py --files YOUR_TEXT_FILES
这个记号赋予器将句子分解成小记号,然后将每个记号映射成整数:
标记器—按作者分类的图像
分类者
我们使用变压器网络作为分类器:
变压器网络—图片由作者提供
通过使用 torch.nn.TransformerEncoderlayer 和 torch . nn . transformer encoder 类,实现变得很容易。
class TextBinaryClassifier(pl.LightningModule):
def __init__(
self,
vocab_size,
channels=256,
dropout=0.4,
lr=1e-4,
):
super().__init__()
self.lr = lr
self.dropout = dropout
self.vocab_size = vocab_size
self.embeddings = torch.nn.Embedding(self.vocab_size, embedding_dim=channels)
self.pos_embedding = torch.nn.Embedding(1024, embedding_dim=channels)
encoder_layer = nn.TransformerEncoderLayer(
d_model=channels, nhead=4, dropout=self.dropout, dim_feedforward=1024
)
self.encoder = torch.nn.TransformerEncoder(encoder_layer, num_layers=8)
self.linear = Linear(channels, 1)
self.do = nn.Dropout(p=self.dropout)
self.loss = torch.nn.BCEWithLogitsLoss()
def forward(self, x):
batch_size, sequence_len = x.size(0), x.size(1)
embedded = self.embeddings(x)
pos_x = (
torch.arange(0, sequence_len, device=x.device)
.unsqueeze(0)
.repeat(batch_size, 1)
)
pos_x = self.pos_embedding(pos_x)
embedded += pos_x
embedded = self.do(embedded)
embedded = embedded.permute(1, 0, 2)
transformed = self.encoder(embedded)
transformed = transformed.permute(1, 0, 2)
out = self.linear(transformed[:, 0])
return out
预言者
火炬至 onnx
出于实际原因,我们将模型从 torch 转换。ckpt 格式到. onnx.
我们还使用 onnxruntime 库在我们的预测中使用这个模型。
为此,我们运行:
torch.onnx.export(
model, # model being run
ids, # model input (or a tuple for multiple inputs)
filepath, # where to save the model (can be a file or file-like object)
export_params=True, # store the trained parameter weights inside the model file
opset_version=10, # the ONNX version to export the model to
do_constant_folding=True, # whether to execute constant folding for optimization
input_names=["input"], # the model's input names
output_names=["output"], # the model's output names
dynamic_axes={
"input": {0: "batch_size", 1: "sequence_len"}, # variable length axes
"output": {0: "batch_size"},
},
)
执行此过程可以将模型的大小减少 66%,并将 CPU 上的预测速度提高 68%(从 2.63 毫秒到 0.85 毫秒,以生成一个小句的预测)。
预测服务器
我们使用一个带有 RabbitMQ 和 pika 的排队系统来处理来自机器人的预测查询。
预测架构—作者图片
这种架构允许将机器人逻辑与机器学习/NLP 逻辑隔离开来,并且如果需要的话,可以更容易地横向扩展到多个预测器。
您可以使用我的存储库中的 docker-compose 文件来运行整个架构:
首先,按照本教程获取您的 bot 令牌:
[https://www.freecodecamp.org/news/create-a-discord-bot-with-python/](https://www.freecodecamp.org/news/create-a-discord-bot-with-python/)
然后,下载模型和标记器:
wget https://github.com/CVxTz/bleach_bot/releases/download/v1/toxicity_model.onnx -P ./data/wget https://github.com/CVxTz/bleach_bot/releases/download/v1/tokenizer.json -P ./data/
最后,运行 docker-compose
docker-compose up --build
机器人演示
该机器人删除分类模型给出的分数大于 0.8 的所有邮件。
接下来是演示。我使用 docker-compose 在我的机器上运行这个机器人。我们可以看到,机器人删除了所有令人讨厌的负面消息,保留了常规消息。不要眨眼,因为它真的很快😉
结论
这个项目详细介绍了使用深度学习构建一个仲裁机器人所需的第一步。该机器人经过训练,可以检测有毒或侮辱性信息,并自动删除它们。下一步将是进一步改进机器人的机器学习部分,以减少误报的数量,并致力于其部署。
来源
[1] [https://www.freecodecamp.org/news/create-a-discord-bot-with-python/](https://www.freecodecamp.org/news/create-a-discord-bot-with-python/)
密码
https://github.com/CVxTz/bleach_bot
用 Python 构建自己的语法
原文:https://towardsdatascience.com/build-your-own-grammarly-in-python-6fb4297c189c?source=collection_archive---------8-----------------------
Python 中的拼写和语法纠正工具
图片由洛伦佐·卡法罗来自皮克斯拜
良好的语法和正确拼写的单词有助于你清楚地写作和交流,并得到你想要的东西。无论你是在写一篇文章、短文还是电子邮件,用清晰正确的语言表达你的想法会给你的读者留下好印象。在打电子邮件、短文、文章等的时候,人们经常会犯很多语法和拼写错误。
Grammarly 是一家总部位于美国的技术公司,提供基于人工智能和自然语言处理的数字写作评估工具。它提供了许多免费和付费的工具,包括语法检查、拼写检查、写作辅助等。在本文中,我们将使用一个开源包**gingerit**
来实现一个可以纠正文本中拼写和语法错误的模型。
GingerIt:
来自 Pixabay 的像素的图像
GingerIt 是一个开源的 Python 包,它是 gingersoftware.com API 的包装器。Ginger 是人工智能支持的写作辅助工具,可以根据完整句子的上下文来纠正文本中的拼写和语法错误。
使用此软件包,您可以:
- 消除语法错误
- 纠正拼写错误
- 纠正标点错误
- 提高你的写作水平
这个包并不完全是 Grammarly 的克隆,但可以被看作是它的基础版本,因为它提供了一些通用的特性。目前,gingerit 只支持英语。
拼写检查和语法检查算法是如何工作的?
拼写检查器运行各种算法来纠正错别字。该算法如下:
- 首先,它扫描文本以标记出单个或一对单词。
- 它涉及字典中单词列表的标记/单词。
- 如果这些单词与任何单词都不匹配,那么它会运行编辑距离算法来建议最接近的单词或单词列表。
与拼写检查算法类似,语法检查算法也从文本中提取一个句子,并对照句子检查每个单词,根据句子中的位置查看诸如词性之类的信息。同样依赖于几个规则,该算法检测时态一致、数字、词序等方面的错误。
安装:
可以使用以下命令从 PyPl 安装 Gingerit:
**pip install gingerit**
用法:
- 在安装和导入 gingerit 包之后,它可以用来纠正给定输入文本的语法和拼写错误。
- 将文本传递给 gingerit 包中的 parse()函数,它返回一个输出字典,关键字为:“更正”、“文本”、“结果”。
**Value of the corresponding keys:****Corrections:** List of mistakes in dictionary format as starting index, mistaken text, corrected text, the definition of the corrected text.
**Text:** Original Text
**Result:** Corrected text free from grammatical and spelling mistakes
(作者代码)
从上面的代码片段可以看出,使用 gingerit 包纠正了一个不正确的语句。
(图片由作者提供),输入输出文本
结论:
在本文中,我们使用开源 Python 包实现了一个基本版本的语法和拼写检查器。gingerit 软件包的结果没有达到标准,因为它可以纠正拼写错误和轻微的语法错误。Gingerit 是一个围绕gingersoftware.comAPI 的包装器,这是一个付费版本,在纠正语法错误方面可能会有很好的效果。
language_tool 是另一个开源包,工作方式与 gingerit 包非常相似。
感谢您的阅读
建立你自己的关于人工智能道德和安全的模块化音频课程
原文:https://towardsdatascience.com/build-your-own-modular-audio-course-on-ai-ethics-and-safety-5035a66eef55?source=collection_archive---------41-----------------------
人工智能研究前沿问题和利害关系的精选“倾听清单”
菲利普·伯恩特在 Unsplash 上的照片
人工智能和机器学习的最新进展有助于创造新的工具和产品,并推动科学知识向前发展。它们也带来了我们尚未完全理解的风险和复杂性——这些风险和复杂性从超本地化(例如,公司在人工智能驱动的招聘流程中延续偏见)到存在性(如我们所知,一般人工智能正在消灭生活😱).
很难跟上该领域的发展,更不用说理解新研究的深层含义了。但我们是来帮忙的:由 Jeremie Harris 主持的 TDS 播客第二季,聚焦于这些围绕人工智能、安全和伦理的新兴问题。我们鼓励你探索整个赛季(现在有超过 24 集,还在增加!),下面我们汇集了一个八集的节略课程,涵盖了这次对话中一些最基本的要素。
你可以按顺序进行选择,也可以根据自己的需要进行混搭。无论你是在沙滩上、做饭时还是在办公桌前听,我们希望这些讨论能激励你不断学习和思考这个及时而紧迫的话题。
布莱恩·克里斯蒂安谈校准问题
全面介绍了围绕构建安全人工智能(与我们的价值观一致的人工智能)的重大问题,以及如何找到非常清楚和正确地量化我们希望我们的人工智能做什么的方法。
海伦·托勒谈人工智能的战略和安全含义
随着人工智能技术的不断发展和变得更加强大,我们将不得不更加担心安全和保障。但竞争压力有可能鼓励公司和国家专注于能力研究,而不是负责任的人工智能开发。
大卫·罗德曼谈经济史和通往奇点的道路
现在是我们探索变革性人工智能如何、甚至何时可能从根本上改变当代经济的时候了。
爱德华·哈里斯谈机器学习中出现的问题以及如何让人工智能变得“好”
一个数据科学家可以设计出一种算法,在部署后的几分钟内,它将立即影响数百万甚至数十亿人的生活。尚不清楚我们是否已经变得足够聪明来运用这种力量。
Margot Gerritsen 谈人工智能是否必须是可理解的才是道德的
非故意的坏人工智能可能会导致各种偏见,使算法对一些人来说比其他人表现得更好,或者更普遍地说,使系统对我们实际上长期不想要的东西进行优化。
罗布·迈尔斯上为什么我们要关心 AI 的安全
在部署先进的人工智能系统之前,我们是应该努力确保它们绝对安全,还是可以在它们出现时修复它们?随着系统变得越来越强大——随着它们的部署伴随着人类不可避免且不可逆转地失去对世界的控制——似乎有可能在前期需要更多的谨慎。
西尔维亚·米兰诺谈推荐系统的伦理挑战
推荐系统是非常有价值的技术,但它们也有一些严重的道德失败模式——其中许多是因为公司倾向于建立反映用户反馈的推荐器,而没有考虑这些系统对社会和人类文明的更广泛影响。
安迪·琼斯谈人工智能安全和扩展假说
正如 GPT-3 所显示的,当人工智能系统变得更大时,它们不仅在特定的任务上表现得更好,而且在全新的、更一般的任务上也表现得更好。
有关 TDS 播客的最新剧集,请访问此页面。
使用 BERT4Rec 构建您自己的电影推荐系统
原文:https://towardsdatascience.com/build-your-own-movie-recommender-system-using-bert4rec-92e4e34938c5?source=collection_archive---------9-----------------------
PyTorch 中基于变压器的推荐系统的分步实现
在 Unsplash 上由 Myke Simon 拍摄的照片
推荐算法是我们每天使用的许多服务的核心部分,从 YouTube 上的视频推荐到亚马逊上的购物项目,不要忘记网飞。
在这篇文章中,我们将实现一个简单而强大的推荐系统,名为 BERT4Rec:来自 Transformer 的双向
编码器表示的顺序推荐。
我们将在约 60,000 部电影的数据库上,将该模型应用于电影推荐。
任务
我们的目标是向用户推荐他们过去看过的电影。该推荐直接从数据中学习,并且针对每个用户进行个性化。
作者图片
数据
我们将使用 MovieLens-25m 数据集(https://grouplens.org/datasets/movielens/25m/)。这是一个记录 162541 个用户和 62423 部电影之间互动的数据集。
我们可以为每个用户构建他们互动的电影的时间排序序列。我们将使用这些序列来训练我们的推荐系统。
模型
BERT4Rec 很像 NLP 的常规 BERT。这是一个变形金刚网络,它被训练来从用户的历史中预测“屏蔽”的电影。
第一步是以按时间排序的电影列表的形式构建用户的历史记录。
作者图片
其中一些电影被一个符号[面具]所取代。
作者图片
然后对 BERT4Rec 模型的任务进行训练,以尝试预测[MASK]项的正确值。通过这样做,模型将学习每部电影的有用表示,以及电影之间存在的重要模式。
作者图片
然后为了进行推断,我们可以在用户序列的末尾添加一个[MASK]来预测他们将来最有可能想要的电影。
作者图片
BERT4Rec 是一种常规的转换器架构,类似于 NLP 中使用的架构:
变压器层
序列中的每个电影都被映射到一个嵌入向量。
src_items = self.item_embeddings(src_items)
然后,自我关注是允许这种架构对输入序列的元素之间的长期依赖性进行建模的原因。
顺序通过位置嵌入来建模,其中我们在每个时间步学习一个“位置向量”。
batch_size, in_sequence_len = src_items.size(0), src_items.size(1)
pos_encoder = (
torch.arange(0, in_sequence_len, device=src_items.device)
.unsqueeze(0)
.repeat(batch_size, 1)
)
pos_encoder = self.input_pos_embedding(pos_encoder)
src_items += pos_encoder
最后,在每个时间步,模型从 62423 部电影中输出每个可能选项的预测分数。我们使用这些分数来优化分类交叉熵损失。
培训日志
模型使用示例
现在,我们将使用经过训练的模型,根据三种情况提出建议:
场景 1:冒险/幻想
用户历史-->
- 《哈利·波特与魔法石》(又名《哈利·波特与魔法石》)(2001 年)
- 哈利·波特与密室(2002)
- 哈利·波特与阿兹卡班的囚徒(2004)
- 哈利·波特与火焰杯(2005)
车型推荐->
['**Ice Age (2002)**',
"**Pirates of the Caribbean: Dead Man's Chest (2006)**",
'**Avatar (2009)**',
'Star Wars: Episode III - Revenge of the Sith (2005)',
'Shrek 2 (2004)',
'Ratatouille (2007)',
'Bruce Almighty (2003)',
'I, Robot (2004)',
'Last Samurai, The (2003)',
'Up (2009)',
'Matrix Revolutions, The (2003)',
'Men in Black II (a.k.a. MIIB) (a.k.a. MIB 2) (2002)',
'Iron Man (2008)',
'**Spirited Away (Sen to Chihiro no kamikakushi) (2001)**',
'300 (2007)',
'Big Fish (2003)',
"Bridget Jones's Diary (2001)",
'My Big Fat Greek Wedding (2002)',
'Pianist, The (2002)',
'Interstellar (2014)',
'Shaun of the Dead (2004)',
'Moulin Rouge (2001)',
'Juno (2007)',
'WALL·E (2008)',
'Casino Royale (2006)',
'School of Rock (2003)',
'40-Year-Old Virgin, The (2005)',
'**Harry Potter and the Order of the Phoenix (2007)**',
'Bourne Supremacy, The (2004)',
'Miss Congeniality (2000)']
我们可以看到,该模型在冒险/幻想流派中提出了一些有趣的建议。请注意,该模型无法访问电影的类型。
场景 2:动作/冒险
用户历史-->
- 黑豹(2017 年)
- 复仇者联盟(2012)
- 复仇者联盟 3:无限战争—第一部分(2018 年)
- 洛根(2017)
- 蜘蛛侠(2002)
- 蜘蛛侠 3 (2007)
- 《蜘蛛侠:远离家乡》(2019)
车型推荐->
['**Avengers: Infinity War - Part II (2019)**',
'**Deadpool 2 (2018)**',
'**Thor: Ragnarok (2017)**',
'**Spider-Man: Into the Spider-Verse (2018)**',
'**Captain Marvel (2018)**',
'Incredibles 2 (2018)',
'**Untitled Spider-Man Reboot (2017)**',
'Ant-Man and the Wasp (2018)',
'Guardians of the Galaxy 2 (2017)',
'Iron Man 2 (2010)',
'Thor (2011)',
'Guardians of the Galaxy (2014)',
'Captain America: The First Avenger (2011)',
'X-Men Origins: Wolverine (2009)',
"Ocean's 8 (2018)",
'Wonder Woman (2017)',
'Iron Man 3 (2013)',
'Pirates of the Caribbean: The Curse of the Black Pearl (2003)',
'Amazing Spider-Man, The (2012)',
'Aquaman (2018)',
'Dark Knight, The (2008)',
'Mission: Impossible - Fallout (2018)',
'Avengers: Age of Ultron (2015)',
'Jurassic World: Fallen Kingdom (2018)',
'Iron Man (2008)',
'Coco (2017)',
'Lord of the Rings: The Two Towers, The (2002)',
'Rogue One: A Star Wars Story (2016)',
'X-Men: The Last Stand (2006)',
'Venom (2018)']
这些建议完全正确!大部分来自漫威宇宙,就像用户的历史一样。
场景 3:喜剧
用户历史-->
- 疯狂动物城(2016)
- 玩具总动员 3 (2010)
- 玩具总动员 4 (2019)
- 海底总动员(2003)
- 《料理鼠王》(2007)
- 乐高电影(2014)
- 捉鬼敢死队(又名捉鬼敢死队)(1984)
- 艾斯·文图拉:当自然召唤(1995)
车型推荐->
['**Home Alone (1990)**',
"**Bug's Life, A (1998)**",
'**Toy Story 2 (1999)**',
'Nightmare Before Christmas, The (1993)',
'Babe (1995)',
'**Inside Out (2015)**',
'**Mask, The (1994)**',
'**Toy Story (1995)**',
'Back to the Future (1985)',
'Back to the Future Part II (1989)',
'Simpsons Movie, The (2007)',
'Forrest Gump (1994)',
'Austin Powers: International Man of Mystery (1997)',
'Monty Python and the Holy Grail (1975)',
'Cars (2006)',
'Kung Fu Panda (2008)',
'Groundhog Day (1993)',
'American Pie (1999)',
'Men in Black (a.k.a. MIB) (1997)',
'Dumb & Dumber (Dumb and Dumber) (1994)',
'Back to the Future Part III (1990)',
'Big Hero 6 (2014)',
'Mrs. Doubtfire (1993)',
'Clueless (1995)',
'Bruce Almighty (2003)',
'Corpse Bride (2005)',
'Deadpool (2016)',
'Up (2009)',
"Ferris Bueller's Day Off (1986)"]
在这种情况下,该模型能够推荐一些很棒的电影,如《玩具总动员 1》或《独自回家》,这些电影符合用户历史的主题。
结论
在这个项目中,我们构建了一个强大的电影推荐系统,名为 BERT4Rec。这是一个基于 transformer 层的模型,使用与 BERT 非常相似的方案进行训练,其中我们屏蔽了用户电影历史序列的一些元素,然后尝试预测这些项目的真实值。
你看看下面代码中的实现细节-->
代号:https://github.com/CVxTz/recommender_transformer/
构建您自己的 Salesforce 数据加载器
原文:https://towardsdatascience.com/build-your-own-salesforce-dataloader-c39f291cfb32?source=collection_archive---------22-----------------------
使您的用户能够使用 Salesforce Dataloader 的强大功能,但具有可定制的用户体验
莫兰在 Unsplash 上的照片
作为全球领先的客户关系管理(CRM)平台,Salesforce 是一款能够存储大量数据的出色工具。因此,管理这些数据是平台管理员的日常工作。其中一种方法是通过 数据加载器 *,*一个能够提取、插入、更新和删除 Salesforce 记录的客户端应用程序。
当我在 2018 年夏季实习期间第一次开始与 Salesforce 合作并使用 Dataloader 时,我记得我很害怕不小心做错事情。一打开它,所有我能接触到的物品就出现在我面前,即使我一开始并不知道它们的存在或对它们感兴趣。虽然可以限制哪些用户可以使用该工具,但我感兴趣的是能够在其中定制用户体验,并创建一个更可控和优化的环境。这样,我可以选择只向销售团队显示业务机会、销售线索和客户,或者向开发团队显示自定义元数据类型和自定义设置,而不是显示组织内的所有对象。选项是无限的,在本文中,我将介绍一个尝试完整模拟 Salesforce 数据加载器的应用程序,它可以作为构建更多定制体验的垫脚石。它的一些限制是,它在一个作业中最多只能插入、更新和删除 10k 条记录,输入 Excel/Csv 文件中的列名必须与您尝试写入的字段的“API 名称”完全匹配,并且登录需要从您在 Salesforce 中的个人设置中获得的安全令牌。该解决方案使用 simple_salesforce 和 salesforce_bulk Python 包来处理数据,并使用 Tkinter 来构建用户界面。
应用程序
我只在文章正文中包含了部分代码。要检查整个事情,导航到https://github.com/soravassi/FauxSFDCDataloader
登录窗口
当用户第一次打开应用程序时,他们会发现一个简单的 Tkinter 窗口,必须在其中插入用户名、密码和安全令牌。按下“登录”后,将调用 Login()函数并构建主菜单。
炙单
认证后,将出现操作选项。
query 按钮调用查询操作特有的顶层 Tkinter 窗口,因为它的用户体验与其他操作稍有不同。插入、更新和删除按钮都调用同一个窗口模板,通过函数“open_secondary(operation)”上的关键字参数指定动作
动作窗口
该应用程序有两个主要的操作窗口模板:一个用于查询,另一个用于写操作(插入、更新、删除):
查询窗口
查询页面利用两个 Tkinter 列表框来帮助用户构建他们的 SOQL 查询。第一个列表框是 SOQL 查询的结果,它包含 Salesforce 中所有对象的名称,而第二个列表框是 SOQL 查询的结果,它包含第一个列表框中所选对象内的所有字段名称。在这里,用户可以按“创建查询”,这将根据他们的列表框选择编译查询,或者直接在文本框中编写查询,然后单击“提取”以生成包含所需数据的 Excel 文件。
用于编译“open_query()”函数中的对象名的代码段,该函数打开查询顶层窗口
分别按下“显示字段”、“创建查询”和“提取”时运行的功能
更新/插入/删除窗口:
此窗口的行为类似于查询窗口,因为在打开它时,列表框将显示您可以在其中执行所需操作的对象。主要区别在于,对于写操作,应用程序利用 salesforce_bulk 包而不是 simple_salesforce,并且用户必须输入从中选择字段的 CSV/Excel 文件,而不是在第二个列表框中选择受影响的字段。
提示用户选择输入文件,并将其保存在数据帧上
“动作(操作)”功能的一部分,启动批量数据作业并编译结果。
将这一切结合在一起
使用 Tkinter 构建这样一个应用程序的好处在于,您可以快速推出它的不同版本。例如,您可以使应用程序的某些方面(如他们可以访问的对象列表)以用户的配置文件为条件。
其他选项可能只显示查询按钮,或者隐藏删除按钮。根据我自己的个人经验,我创建了该应用程序的多个版本,帮助产品所有者提取选项列表值及其依赖关系,并帮助质量保证用户更改他们自己的配置文件,以便从业务用户的角度测试新功能,而无需授予他们“管理用户”权限或“登录身份”功能。正如我说过的,天空是无限的,具体的应用将因 Salesforce 的实施而异。希望这有助于帮助用户以更加定制化和定制化的体验处理数据。
威廉·冈克尔在 Unsplash 上拍摄的照片
感谢您的阅读!这是我尝试分享一些代码和我试图解决的一个问题的解决方案的第一篇文章。我很感激你所有的建设性反馈,从文章的结构到代码本身。
更多项目,我邀请您参观andrecarmo.com
构建更好的数据文化:采访 ThoughtSpot 首席数据战略官辛迪·豪森
原文:https://towardsdatascience.com/building-a-better-data-culture-an-interview-with-thoughtspots-chief-data-strategy-officer-cindi-214d88c873d8?source=collection_archive---------31-----------------------
数据停机访谈
与辛迪·豪森就如何实现大规模数据民主化展开对话。
我们与领先的搜索和人工智能驱动的分析平台thought spot的首席数据战略官 辛迪·豪森 进行了广泛的交谈,讨论了她的日常工作、组织在数据民主化道路上面临的共同挑战以及数据科学的多样性。
在过去的几十年里,数据分析领域经历了从孤岛式实体到跨职能机构的转变。现在,在 2021 年,在这个数据十年中,又一次巨变的时机已经成熟,这次是以数据民主化和可访问性的形式。
ThoughtSpot 为这一走向可操作和精确分析的新运动铺平了道路,首席数据战略官 Cindi Howson 负责该公司的客户支持计划。
刚刚获得雪花对 ThoughtSpot 的 2000 万美元投资,辛迪一直很忙。从帮助组织更智能地利用他们的数据到代表 STEM 中的女性进行宣传,Cindi 是数据分析领域最杰出的声音之一。而且理由很充分。
在加入 ThoughtSpot 之前,Cindi 曾在 Gartner 担任副总裁,并担任分析和商业智能魔力象限的主要作者。她还创建了 BI 记分卡,这是评估商业智能解决方案的第一个行业框架。现在,在 ThoughtSpot,她正围绕在整个企业中构建(和扩展)数据战略的意义展开对话。
我们与 Cindi 进行了交谈,以了解她在数据分析方面的更多信息,ThoughtSpot 的首要目标是什么,以及行业如何使 STEM 更具包容性:
在您的职业生涯中,您评估了各种 BI 和分析解决方案,以帮助您的客户更好地了解这种情况。有没有让你惊讶的行业趋势?
对我来说最大的惊喜之一是,我们仍然不擅长如何评估新技术,这听起来很疯狂。
如果你想想 iPhone 刚出来的时候,人们会说,“等等。我的键盘呢?”他们把它和黑莓进行了比较。甚至当 iPad 出来的时候,你会说,“等等,那个 u 盘在哪里?”我们一直想把东西放回旧的评估框架中。作为一个技术行业,我们必须意识到旧框架的局限性,以及它们移动的速度有多慢。
我们关心的一件事是让每个人都能轻松地进行分析——采用消费级易用性的概念,如 Spotify 或 iTunes,并将这种易用性应用于数据和分析。如果以前没有人考虑过这个问题,它甚至可能不会出现在你的评估列表中。令我惊讶的是,作为一个行业,我们仍然没有想出如何做得更好。
作为首席数据战略官,您能更详细地介绍一下您现在的角色吗?听起来人们经常错误地认为你可能负责在内部塑造自己公司的数据文化,但事实并非如此。
所以实际上,我的角色有三个方面。一个是与我们的顶级客户合作,指导他们克服障碍。许多障碍不是技术,而是文化。是人们改变管理和数据流畅性,所以我帮助他们驾驭这些东西。它还可能会考虑什么样的工具适合合适的用户,以及管理他们的 BI 工具组合的用例。
但是,当我与我们的客户一起工作时,他们也会给我反馈,告诉我我们需要将我们的产品带到哪里,以继续保持市场上的最佳和领先优势。因此,我与我们的产品团队合作,要么解决差距,要么规划下一波颠覆和创新。
然后第三部分实际上是这样的事情,巴尔——成为一个思想领袖,并与像你这样的人会面。因此,去年,我的目标之一是推出数据首席播客,我可以与团队一起完成这项工作,并参与整个行业的活动。
我见过这种数据囤积的现象,组织每天吸收、转换和处理如此多的数据,但实际上这些信息中只有很小一部分得到了利用。您认为数据组织如何才能消除噪音并从分析中获得更多价值?
我不知道我们囤积了这么多,因为技术落后了。获取数据的能力超过了我们获得洞察力的能力。
这就是我认为云改变了游戏的地方。从历史上看,由于计算和桌面分析产品有限,因此出于性能原因,许多分析必须进行汇总和简化。在云中运行分析,您不再需要这样做。我认为这是为什么我们会陷入捕捉多于实际分析的陷阱的部分原因。
传统公司的数据团队如何开始迁移到云并推动数字化转型的旅程?如果有的话,你见过哪些效果最好的?
首先,我们不能称他们为传统公司,因为他们没有死。但也许我们会称他们为落后者,我想这是《哈佛商业评论》的术语。
我认为疫情向我们展示了你过去认为不可能的事情,比如将客户数据放在云中,甚至共享医疗保健或其他私人数据——实际上,这是非常可能的。当您的业务成果一致时,很有可能更快地完成工作。如果你走老派路线,你可能会让恐惧和对改变的抗拒拖慢你的脚步,阻碍你前进。这就是这些组织将成为传统组织的时候。
我想到了 Clayton Christensen,以及他关于颠覆性创新和创造性破坏的观点:仅仅因为你今天运作良好并不意味着你明天就会成为领导者。我听过 Instacart 的一位领导说过一句话,我很喜欢,他说“你的下一个竞争对手可能是两个在大学宿舍里的女人,她们想出了最酷的创业公司。”云和开源技术降低了众多领域的准入门槛
这无疑是数据民主化趋势的一部分,这一运动旨在让每个人都可以访问数据。在你看来,真正的数据民主化是什么样子的?
我脑海中经常浮现出老派电话接线员或总机接线员的形象。这就是所发生的事情,因为 BI 工具最初很难使用,并且需要专业培训。这种模式无法扩展,也无助于业务发展。
了解该领域的人,知道他们想问的问题,应该能够获得真知灼见。有太多的窃窃私语偏离了方向。我的客户会谈到仪表板积压。供给和需求是不平衡的,因为对新数据、更及时的见解和更复杂的问题的需求超过了能够回答这些问题的分析师的供给。
您之前提到过,与业务成果挂钩有助于迁移或推动转型。负责这些重要计划的数据领导者如何将他们与业务成果联系起来?
作为 ThoughtSpot 的首席数据战略官,辛迪·豪森(Cindi Howson)通过更易于访问的人工智能驱动的分析,帮助客户运营他们的数据。
我经常告诉 CDO 和分析主管,从他们最大的痛点或最高价值的机会开始。你不想从你的超级乱七八糟的数据开始,因为人们会失去兴趣和信心。
说客户忠诚度是你生意中的头等大事。我们通过 NPS 分数来衡量这一点,但还有其他指标,如响应服务请求的时间或与客户忠诚度相关的准时交付。
通过了解这些数字并确定 NPS 得分或响应时间最低的服务代表,您可以深入了解这些数据点背后的原因。他们 NPS 分数最低是因为训练吗?也许是因为他们的耳机电话并没有那么好?我们可以修好那些东西。因此,数据大众化实际上是执行这些业务成果的一个推动者。
我认为很多人是从下往上开始的,因为变化不是从上往下的。那些数据专业人员或技术专业人员可能是知道可能性艺术的人。因此,他们可能会做一个概念或技术的证明,说,好吧,我们有这些数据,我们认为这是一个没有人关注的价值。让我快速向你展示可能的艺术。
对我来说,技术创新和数字化转型的区别在于,在你证明了这个概念之后,你必须找到一个拥护者来说,“是的,这将有助于提高我们的业务绩效。”
我经常看到的另一个挑战是,无论你的数据分析解决方案有多好,如果你不信任你的数据,就很难获得有意义的见解。您见过客户如何处理数据质量和数据可靠性?
信任是一个大问题。这确实与数据素养,或者我们喜欢说的数据流畅性有很大关系。
我确实认为,数据技能将继续成为全体员工的必备技能。我们已经看到小学和初中越来越多地教授这种课程。甚至 SAT 现在实际上也包括了解决某人数据素养的问题。但是现在,大多数员工都不懂得数据。不幸的是,有了 COVID,你真的可以看到人们不明白数据从何而来,意味着什么。
当人们明白数据来自哪里,当他们明白即使是高质量的数据也不会完全干净时,您就建立了信任。我喜欢我们的一位数据分析领导者谈论“数据在方向上准确吗——准确到足以做出决策吗?”
现在有些事情必须做到完美。举例来说,你必须确定你的血型。但是,如果我着眼于活动分析和客户体验趋势,我们可以利用足够准确的数据做出决策。
几年前,你写了一篇名为 的伟大文章,我们可以把男人送上月球,但我们不能把女人留在科技领域 。我喜欢这个标题,它是关于技术多样性的商业案例,以及是什么阻止了我们实现更公平的劳动力。对于许多数据驱动的公司来说,增加 STEM 中表示的多样性是一个巨大的优先事项,但显然,许多公司都做不到。事实上,根据 BCG 统计,如今的数据科学家中只有 15%是女性。在你看来,为了创造一个更具包容性的行业,我们需要做哪些完全不同的事情?
我想说,嗯,自从我一年前写了那个博客,事情已经变得更好了。但不幸的是,在疫情,情况变得更糟了。部分原因与虚拟学校教育有关,女性在家工作时必须在家教学,然后可能还要照顾生病的父母或兄弟姐妹。这很难。
如果有一线希望,我会说,2020 年发生在乔治·弗洛伊德和布里奥纳·泰勒身上的种族不公正提高了对话的水平。人们现在说,我们不能一直谈论这个。我们确实需要将它与行动结合起来。因此,我很高兴地看到,组织实际上正在更多地衡量这些事情,并主动制定计划来解决这个问题。例如,星巴克现在将高管薪酬与实现各种多元化目标的高管挂钩。纳斯达克提议将多元化指标作为在纳斯达克上市的一项要求。
现在我确实有一种担心——希望它是错误的或者没有根据的——但是担心这会适得其反,因为没有人愿意被雇佣去打勾。他们希望被雇用,因为他们是这项工作的最佳人选。他们只是不想让这些无意识的偏见或系统性的偏见妨碍他们打针。
让我们以一些有趣的问题来结束。2020 年你最喜欢的书是什么?
在小说方面,我喜欢星星的给予者,它基于一个关于肯塔基州的驮马图书馆员的真实故事。然后从商业和分析方面来说,我真的很喜欢约翰·汤姆逊的建立分析团队和艾琳·迈耶的文化地图。
播客或时事通讯呢?你今年学到了什么最喜欢的东西吗?
我确实听过雪花的数据云的兴起。如果允许我说,我喜欢那些如此乐意分享他们对数据主管的灵感的客人。所以我实际上是在录音后听的。当然,我会听布伦·布朗的歌。
至于时事通讯,我刚刚订阅了《原子习惯》的作者詹姆斯·克利尔的一篇,它真的很不错。
有兴趣在ThoughtSpot了解更多关于辛迪的作品?关注她上 推特 或者LinkedIn***!***
阅读更多来自蒙特卡洛数据停机采访系列的内容:
- 将可靠的数据和人工智能带到云端:A Q&A with Data bricks ' Matei Zaharia
- 关于数据治理:SAP 企业数据战略和转型主管 Maria Villar
- 用数据对抗流失:卡尔·戈尔德访谈
构建生物医学知识图谱
原文:https://towardsdatascience.com/building-a-biomedical-knowledge-graph-2930c7e05760?source=collection_archive---------21-----------------------
使用公开可用的数据集对复杂的生物医学数据进行分析推理
听取 Vaticle 社区讲座的汇报—主讲人是罗氏系统生物学科学家 Konrad myliwiec。这个演讲是四月份在轨道 2021 上虚拟发表的。
像许多 TypeDB 社区成员一样,Konrad 来自不同的工程背景。自从为 GSK 开发企业知识图以来,知识图一直是他工作范围的一部分。他加入 TypeDB 社区已经大约 3 年了。虽然他的大部分职业生涯都在生物医药行业度过,但他也花时间研究商业智能应用程序,开发移动应用程序,目前是罗氏制药公司 RGITSC(罗氏全球 IT 解决方案中心)的数据科学工程师。
去年,康拉德开始注意到网上的一种趋势,无论是 LinkedIn 上的文章还是他的生物医学网络;知识图表到处都是。鉴于世界正处于与新冠肺炎·疫情的斗争中,他想知道知识图谱是否能帮助他的生物同龄人的努力。
在开发 BioGrakn Covid 的过程中,他试图将这两个主题结合在一起,以提供一种更容易理解和有用的方法来支持疫情期间的研究和生物医学斗争。在这个演讲中,他描述了他和一组 TypeDB 社区成员如何处理一些技术开发领域。
外卖:
- biog rakn Covid——它是什么,项目的目标是什么
- 公开可用的数据源和本体——什么数据被加载到 BioGrakn Covid 中
- 知识提取—处理非结构化数据
- 分析推理——如何在知识图上进行一些分析
建筑 BioGrakn Covid
BioGrakn Covid 是由 Konrad、Vaticle 的 Tomás Sabat 和 GSK 的 Kim Wager 共同发起的开源项目。这是一个以新冠肺炎为中心的数据库。
用图表表示生物医学数据
一旦我们认识到生物医学数据的自然表示倾向于类似图形,将生物医学数据建模为图形就成了显而易见的选择。图形数据库传统上将数据表示为二进制节点和边。想想标签属性图,其中两个节点通过有向边连接。康拉德和他的同事很快意识到,用超图来表示生物医学数据变得更简单,最终也更自然,就像在 TypeDB 中发现的那样。
图表与超图模型—经许可使用的幻灯片
超图通过放宽边的定义来概括图的一般概念。图中的边只是一对顶点。相反,超图中的超边是一组顶点。这种顶点集可以进一步结构化,遵循超图的不同可能定义中涉及的一些附加限制。
在 TypeDB 中,模型使用矩形来表示实体(节点),菱形表示关系或超关系(一个关系中有 n 个角色)。
TypeDB 图表示例—经许可使用的幻灯片
使用的数据源
目前,在 BioGrakn Covid 中有相当多的公开数据集。简而言之,以下是数据库中包含的一些数据集和映射:
BioGrakn Covidslides 中使用的数据集经许可使用
- https://www.uniprot.org/—实体(转录本、基因、蛋白质),关系(翻译、转录、基因-蛋白质编码)
- 人类蛋白质图谱 —实体(组织)、关系(表达)
- https://reactome.org/—实体(通路),关系(通路——参与)****
- DGldb —实体(药物),关系(药物-基因-相互作用)
- https://www.disgenet.org/—实体(疾病),关系(基因-疾病关联)
- 冠状病毒 —实体(病毒)、关系(生物体-病毒宿主、基因-病毒关联、蛋白质-病毒关联)
- ClinicalTrials.gov—实体(临床-试验,组织),关系(临床-试验-协作,临床-试验-药物-关联)
保持数据质量 我们很多人都知道,从上述来源获取数据并将其加载到数据库中并不简单。首先需要考虑数据质量。正如 Konrad 在他的演讲中指出的,保持数据质量是这项工作的一个重要方面。
你不希望有任何数据差异,你不希望有几个节点代表相同的实体,因为这将影响和偏见你的分析在未来。
他们解决数据质量问题的方法是使用像 UMLS(统一医疗语言系统)这样的数据源。UMLS 提供了一些有助于维护数据质量的结构和上下文。在演讲中,康拉德关注了 UMLS 的两个子集。第一个,UMLS 的“Metathesaurus ”,包含了各种类型不同层次的生物医学实体,如蛋白质、基因、疾病、药物以及它们之间的关系。
作为可用的例子,我们有两种蛋白质:protein-1
和protein-2
,它们通过interact-with
边缘连接。
将 UMLS 映射到 TypeDB 架构—经许可使用的幻灯片
第二个子集是语义网络数据。这集中在分类法上。每个概念都在一个分类法中给出,例如,我们有一个概念compound
,而protein
是compound
的一个子类型。这个子集的好处将在以后变得更加明显。
使用 UML 作为初始或基线本体给了我们信心,我们可以在没有数据质量问题的情况下前进——显然,这不是解决数据质量挑战的唯一方法。尽管如此,UML 在生物医学领域仍然是有效的。
定义 TypeDB 架构
TypeDB 中的 Schema 为我们的数据提供了结构和模型,并且知道所有被接收到数据库中的数据都将遵守这个模式,这是安全的。
在 Konrad 的案例中,他们正在创建一个具有实体的生物医学模式:protein
、transcript
、gene
、pathway
、virus
、tissue
、drug
、disease
;以及它们之间的关系。应该注意的是,这些决策中的大部分都可以从您使用的数据源中推导出来。
以下是该模式的摘录:
**define
gene sub fully-formed-anatomical-structure,
owns gene-symbol,
owns gene-name,
plays gene-disease-association:associated-gene;
disease sub pathological-function,
owns disease-name,
owns disease-id,
owns disease-type,
plays gene-disease-association:associated-disease;
protein sub chemical,
owns uniprot-id,
owns uniprot-entry-name,
owns uniprot-symbol,
owns uniprot-name,
owns ensembl-protein-stable-id,
owns function-description,
plays protein-disease-association:associated-protein;
protein-disease-association sub relation,
relates associated-protein,
relates associated-disease;
gene-disease-association sub relation,
owns disgenet-score,
relates associated-gene,
relates associated-disease;**
现在我们有了模式,可以开始加载数据了。
摄取结构化数据
在讲座中,Konrad 演示了如何从 UniProt 加载数据,其中也包含来自 Ensembl 的数据。首先要做的是识别相关的列,然后根据我们的模式,识别要用数据填充的相关实体。从这里开始,为每个概念添加属性就相当简单了。
将 UniProt 映射到 TypeDB 模式—经许可使用的幻灯片
加载数据很简单——使用 Python、Java 或 Node.js 中的客户端 API。Konrad 为 UniProt 数据构建了这个迁移器——可通过 BioGrakn Covid repo 获得。
那些积极使用这些类型的公开可用数据集的人知道,它们不会像我们希望的那样频繁更新。其中一些是每年更新的,所以我们需要用相关的当前数据来补充这些数据源。这里的问题是,这些数据通常来自论文、文章和非结构化文本。要使用这些数据,需要一个子域模型。这使我们能够更有表现力地处理文本,并最终将其与我们的生物医学模型联系起来。这两种型号如下所示:
在 TypeDB 模式中一起使用两个域模型—经许可使用的幻灯片
知识抽取
随着模式集和发布的确定,需要解决一些挑战。Konrad 强调了其中的两个:从文本中提取生物医学实体,并在一个中心知识图中链接不同的本体。
从文本中提取生物医学实体
在应对这一挑战时,Konrad 提醒我们不要重新发明轮子,而是要利用现有的命名实体识别语料库。在这个项目中,康拉德公司使用了 NER 科德公司和 SemMed 公司。
命名实体识别是在文本中识别命名实体的自然语言处理算法。
软线 NER
绳索 NER 是预先计算的命名实体识别输出的数据源。CORD NER 的优点是 NLP 工作的输出,来自文本的实体,被映射到 UML 中的概念。这有助于在知识图中提供一致性和数据质量。有了概念及其类型,我们现在可以映射到 TypeQL 中的模式。
经许可使用的幻灯片
SemMed
SemMed 包含从 PubMed 中可用的出版物派生的实体,这些实体存储在语义三元组中。CORD NER 的问题是它不包含命名实体之间的任何链接,而 SemMed 确实提供了这些链接。这些语义三元组由主语、谓语和宾语组成。所有这些都与 UMLS 元霸王龙相对应,这再次帮助我们在知识图谱中保持一致的命名惯例。
下面你可以看到一个例子,说明 Konrad 如何处理 SemMed 中的数据。这是两个表的简单连接,我们看到主语、谓语和宾语:NDUFS8
是基因组,NDUFS7
也是基因或基因组,interacts-with
是它们之间的谓语或关系。SemMed 自然地从文本中导出这些联系,并且当涉及到将这些实体映射到定义的模型时,这为我们提供了所需的大部分内容。事实上,Konrad 注意到大约有 18 种不同的谓词可以映射到模式中的关系。
经许可使用的幻灯片
经许可使用的幻灯片
使用 SciSpacy 进行文本处理
很多时候,我们需要自己从论文中的非结构化文本中提取结构化数据。对于 Konrad 来说,这里的挑战是处理临床试验数据,这些数据通常以 XML 数据的形式出现。
问题在于有时输出并不直接。它可以提供一种以上的药物、化合物或化学品以及其他信息。为了对这些数据进行 NER,康拉德推荐使用科学软件。SciSpacy 是一个 Python 库,构建于 Spacy 之上,它使用一个在公开出版物上训练过的 transformer 模型来执行 NER。用它来对照上面的例子,它可以识别两个命名实体,更好的是,它提供了 UMLS 的映射。
生物数据中的 ID 解析
另一种可能出现的情况是当本体中的 ID 不存在于您正在处理的数据中时。为了解决这个问题,我们可以使用实体的规范名称,并使用类似于 RxNorm 的 API 来获取一个 RxNorm ID,然后可以用它来查找丢失的 ID。
经许可使用的幻灯片
转换图表
一旦加载了数据,我们如何开始遍历图表以生成一些见解和/或新信息?在下面的截图中,Konrad 浏览了一个查询的可视化结果。
TypeDB studio 查询可视化—经许可使用的幻灯片
更高层次的问题是:
找出在与 SARs 病毒的关系中起 *host*
作用的、受另一个基因刺激的任何基因;以及与刺激基因相互作用的药物;最后,提到基因之间关系的出版物。
在 TypeQL 中,该查询如下所示:
**match
$gene isa gene;
$virus isa virus, has name "SARs";
$r(host: $gene, virus: $virus) isa gene-virus-host;
$gene2 isa gene;
$r2(stimulating: $gene2, stimulated: $gene) isa gene-gene-interaction;
$r3(mentioned: $r2, publication: $pub) isa a mentioning;
get $gene, $gene2, $pub;
$drug isa drug;
$r4 (interacted: $gene2, interacting: $drug) isa gene-drug-interaction;**
这个问题在 TypeDB 中变得非常容易查询,并且代表了在限制探索空间的同时遍历图是多么简单。
其他查询可以帮助我们从临床试验数据中了解更多信息。我们能够识别临床试验的潜在目标、赞助组织的标识符,并将这些信息与我们对药物、药物-基因关系和药物-疾病关系的了解联系起来。
其他查询示例可在 Github 上的 BioGrakn Covid repo 中找到。
图的分析推理
因为 BioGrakn Covid 是一个开源数据库,任何人都可以自己使用它;如果不提及获取价值的其他方式,那将是我们的失职。
众所周知,给定网络中的社区——尤其是生物医学网络中的社区——倾向于聚集在一起,在特定网络或整个系统中创建共享功能的社区。给定网络中节点的这个函数可以从它们的 n 跳 egonet 或邻居中导出。例如,在蛋白质-蛋白质相互作用网络中,蛋白质倾向于与共享类似功能(如代谢过程或免疫信息)的其他节点聚集在一起。
PPI 网络—经许可使用的幻灯片
我们可能有一个关系的假设,但我们需要确认这个关系是否应该存在于数据库中。我们可以使用图形神经网络来实现
为了创建或识别这些类型的集群,我们可以执行一些任务:节点分类、链路预测和图形分类。Konrad 选择将本次演讲的重点放在链接预测上,因为他觉得这是继续探索 BioGrakn Covid 的最令人兴奋的途径。
链接预测
在 BioGrakn Covid 中,我们已经实例化了现有的关系,但是,Konrad 想要识别隐含的、未发现的关系。这是由于生物医学知识图表是出了名的不完整。找到自动完成它们的方法是非常令人兴奋的。这样做之后,可以直接从图表中得出新的见解。
经许可使用的幻灯片
他使用的方法是假设关系存在,并使用图形神经网络(ML 中的一个新的热门话题)来确认这一点。
接近
使用图邻接矩阵的特征向量加上图的结构特征作为特征,Konrad 能够训练平面图卷积神经网络。要预测的新关系是现有节点之间的假设的“疾病-基因”和“疾病-药物”关系,并且通过从所有可能和不可能的关系类型中进行负采样来获得负样本。
在机器学习中,术语负采样描述了从不存在的数据中抽取随机样本作为负样本的行为。在不完整的图中,负样本可能确实是正的,但根据经验,Konrad 发现这种方法效果很好。
结果
Konrad 使用模型上的最终 Softmax 层来生成关系存在的概率。
他发现,随着阈值的变化,精确度和回忆的行为如下图所示。他对 85%的回忆值感兴趣,这在两条曲线上都标有一个红点。令人高兴的是,我们可以看到,在这个性能点附近,我们看到了精确度和召回率的平衡。
经许可使用的幻灯片
从另一个角度来看结果,我们可以看到固定召回率为 85%时的混淆矩阵。在这一点上,他给出了 91.16%的精确度。我们还可以注意到矩阵是相当平衡的。我们看到有 50,160 个假阴性,略多于 31,007 个假阳性。作为比较,我们看到 303,393 个真阴性和 264,240 个真阳性。
经许可使用的幻灯片
基因关系预测
Konrad 对所做的基因关系预测进行了特别分析,他对是否所有这些预测都能被正确分类表示怀疑。为了进一步研究,Konrad 对靶向另一个节点(化合物或另一个基因)的基因的前 5 个关系预测进行了抽查。他发现这些预测的关系中有 3 个已经在文献中的一篇或多篇论文中进行了研究。
药物关系预测
对网络预测的前 5 种药物-疾病相互作用进行抽样检查,他在文献中发现其中 2 种已经确定存在。
经许可使用的幻灯片
经许可使用的幻灯片
康拉德自然对他使用这些方法所取得的成就感到非常兴奋,并对如何扩大该方法的范围和准确性有很多想法,正如他在演讲视频中概述的那样。
6 月 30 日,我们将举办一场关于加速药物发现和在 TypeDB 中建立生物医学数据模型的网络研讨会。你可以通过变焦加入。
你能提供什么帮助
这是一个正在进行的项目,我们需要你的帮助!如果您想做出贡献,您可以帮助我们,包括:
- 迁移更多数据源(如临床试验、药物库、Excelra)
- 通过添加相关规则来扩展模式
- 创建网站
- 撰写教程和文章,供研究人员入门
如果您希望取得联系,请通过#biograkn 频道联系我们的 Discord ( 链接此处)。
特别感谢康拉德的辛勤工作、热情、灵感和透彻的解释。
你可以在 Vaticle YouTube 频道点击找到完整的演示文稿。
为我的定制笔记本服务器构建单元数据格式
原文:https://towardsdatascience.com/building-a-cell-data-format-for-my-custom-notebook-server-aaa963c858?source=collection_archive---------47-----------------------
Jockey.jl
在 Jockey.jl 中为我的单元格构建新的数据格式
(图片由像素栏上的像素向量生成)
介绍
我最近参与的一个相当酷的项目,让我非常兴奋的是新的 Jockey 笔记本编辑器。该编辑器可用于处理整个技术堆栈范围内的笔记本电脑,并计划提供各种功能,远远超出标准单元环境。有几个组件需要为后端构建,今天我将为我们的单元编辑器制作后端。这也将与我之前编程的骑师会议和配置设置相关联,因此如果您想阅读我编程所有这些内容的文章,您可以在此处进行:
另外,这里有一个 Github 上 Jockey 的链接。Github 可能会让您对这个项目的构建方向、包组成和目标有更好的了解。
https://github.com/ChifiSource/Jockey.jl
今天,我们正在为后端会话制作一个关键组件,它将成为一种基础数据格式,我们将把它加载到文件中,并在将来使用它。还会有一篇后续文章介绍我如何为这些数据创建保存/加载算法。
参考点
为了确保这种格式正是我想要的,我将参考 Pluto.jl 文件。这是因为我认为将它作为第一种读/写文件格式是最有意义的。将来,我可能会编写一个算法,通过。IPYNB 文件,但现在是常规的。Pluto 笔记本自带的 jl Julia 格式可能是最佳选择。记住这一点,在下一篇文章中,我将创建一个阅读器来将这些类型的文件解析到我的新结构中。本文将只讨论如何创建结构。
所以让我们快速创建一个新环境,放一个冥王星笔记本进去。
([@v1](http://twitter.com/v1).6) pkg> activate PLTO
Activating new environment at `~/dev/nbs/PLTO/Project.toml`(PLTO) pkg> add Pluto
Updating registry at `~/.julia/registries/General`
我将我的环境命名为 PLTO,我们真正需要添加的是 Pluto.jl。我们的目标只是获得一个. jl 文件,其中包含一些可以读取的特性。我对 Pluto 如何处理保存 Julia 文件有一些痛苦的怀疑,让我们看看它可能是下面的哪一个(或者可能是别的什么东西)。
- 文档字符串?
- 评论?
- 真正的朱利安类型?
让我们开始一个快速的笔记本会话,看看!
julia> using Plutojulia>julia> Pluto.run()
当我写这篇文章并启动这台笔记本服务器时,有一件事我肯定会注意到——服务器慢得令人难以置信。这不是执行,这只是在不同的端点之间导航,尝试得到一个示例笔记本,我注意到页面加载需要多长时间。对我来说,我讨厌等待加载东西——这就是为什么我编写加载时间更短的东西,我可以肯定地告诉你,jl 会比这更快。我跑题了,因为谢天谢地,我现在把它做成笔记本了!
(图片由作者提供)
另一个注意是,我认为管理文件的 Pluto.jl 很奇怪。很奇怪,我不喜欢。最终,我觉得在某些方面,很多焦点从来没有传递到这样的事情上,我想要一个 GUI 或终端中的目录浏览器,而不是一个放 URI 的文本框。现在应该注意的是,这个方法没有障碍,默认情况下目录实际上是 Julia 的目录(服务器的目录),我仍然认为可以有一个更好的方法,比如 IJulia/Jupyter 如何处理它——这只是一个例子。
现在,我可以关闭这个会话及其合作服务器,我们可以继续了解这样做的全部目的,也就是更好地了解 Pluto 文件以及代码和 markdown。
(图片由作者提供)
哦,我的天啊—
看来正确的答案是答案 3:这些细胞使用朱莉娅类型的一切。我认为这可能会面临一些问题。首先也是最重要的一点,很明显,UUID 在评论中被用于某种阅读算法。解析器使用注释来跟踪 UUID,以及那些单元格内的内容。对于我的实际格式,我想改变这种方法的很多东西。另一件我觉得奇怪的事情是,输出细胞也有 UUID 和各自的朱莉娅代码。
当然,我有能力简单地匹配这种格式,但我认为这最终弊大于利。我的计划更像是将数据保存到文本中,然后加载数据的典型路线——不需要 UUID,只需要代码。问题是我想让我的单元格以这种数据格式可读——尽管这不是我最喜欢的。或者,我也可以创建自己的程序来使用它,但是考虑到这两种类型的笔记本都使用。jl 扩展名,我们可能希望寻找某种标识符来区分这两个文件。
回到骑师
对这种格式做了一些研究后,我们准备对 Jockey.jl 包本身做一些工作。我要做的第一件事是为新文件中的单元添加一个新的代码文件,我将把这个文件称为“Cells.jl”。鉴于这个组件是 Jockey 会话的一部分,我们将把它包含在相应的目录中。之后,我将创建另一个名为“Formats.jl”的新文件
(PLTO) pkg> activate Jockey
Activating environment at `~/dev/Jockey/Project.toml`shell> cd Jockey
/home/emmac/dev/Jockeyshell> cd src
/home/emmac/dev/Jockey/srcshell> ls
Jockey.jl ServerControllershell> touch Formats.jlshell> touch ServerController/Cells.jl
目前,我们不打算使用 Formats.jl,这将在未来的文章和提交中迭代。在这段代码中,我们要做的是编写新的单元结构,这实际上会有点复杂。因为我们要保存并加载到 Pluto.jl 格式中,所以我们要跟踪 UUID 的。也就是说,在我们创建这个小的附加物之前,让我们添加依赖关系:
(Jockey) pkg> add UUIDs
Resolving package versions...
Updating `~/dev/Jockey/Project.toml`
[cf7118a7] + UUIDs
No Changes to `~/dev/Jockey/Manifest.toml`
在新的 Cells.jl 文件中,我要做的第一件事是为模块的这一部分定义类型层次的顶层。让我们继续这样做:
abstract type Cell end
现在我们将为这个类型添加两个子类型,分别是输入和输出单元格。
abstract type Cell end
mutable struct InputCellendmutable struct OutputCellend
我们可能需要在这些单元格中添加一些数据。我要添加第一个东西是 UUID。添加了这些基本 ID 后,我将把注意力转向输入单元格。我想给这个单元格添加一些不同的东西,最好一次只关注一个构造函数。
mutable struct InputCell
ID::
end
我必须承认,我相信类型将是 UUID,但我们可能会测试它或在添加它之前在文档中查找它。我最终决定,至少对于这个迭代,我应该有以下内容:
abstract type AbstractCell end
mutable struct InputCell <: AbstractCell
ID::UUID
Text::String
env::Dict
hidden::bool
end
注意这只是针对输入,不是针对输出。输出非常简单,只包含一个 ID 和一些输出:
mutable struct OutputCell <: AbstractCell
ID::UUID
output::String
end
最终,无论选择什么,输出都是 HTML。我认为这是给定的,所以输出单元格在这个例子中并没有太大的关系。最后,我将创建顶层单元格。还需要注意的是,我将抽象类型 Cell 更改为抽象 Cell。然后将这些细胞装入更大的细胞类型中,这将非常方便地容纳它们。
using UUIDs, TOMLabstract type AbstractCell end
mutable struct InputCell <: AbstractCell
ID::UUID
Text::String
env::Dict
endmutable struct OutputCell <: AbstractCell
ID::UUID
output::String
endmutable struct Cell <: AbstractCell
input::Cell
output::Cell
hidden::bool
end
所以有一些功能需要添加到这个单元中… Jockey.jl 意味着有一些非常好的环境跟踪,我也将在这里添加一些这样的空实现。以下是我得出的这些类型的最终版本:
using UUIDs, TOMLabstract type AbstractCell end
mutable struct InputCell <: AbstractCell
ID::UUID
Text::String
env::Dict
endmutable struct OutputCell <: AbstractCell
ID::UUID
output::String
endmutable struct Cell <: AbstractCell
input::Cell
output::Cell
hidden::bool
lang::Symbol
env::UUID
end
结论
还有一件事我们必须要做,那就是将这一点纳入到一揽子计划的其余部分。一些简单的代码,但是这些新的类型将成为我们 Jockey.jl 会议如何处理代码的基础。我们需要修改的代码与我们上次使用的代码相同。我们正在寻找的文件被称为 Session.jl。这将是在这个类型之上的另一个类型,它将控制单元格。我们只是将单元格添加到那个会话对象中,作为一个字典,这样我们就可以按正确的顺序排列单元格。
include("Cells.jl")
mutable struct Identifier
id::Int64
auth::Int64
username::Int64
status::Int64
end
mutable struct JSession
ID::Identifier
KeyBindings::Dict
Extensions::Dict
username::String
Cells::Dict
end
非常感谢您的阅读!我希望这个项目对我的文章来说是有趣的,也许这给了我一个坚实的视角来看这个东西是如何开发的,以及我在这样的开发过程中所看到的。我真的很感谢你的阅读,并希望在这个项目的下一部分看到你!
用 Rasa 构建聊天机器人
原文:https://towardsdatascience.com/building-a-chatbot-with-rasa-3f03ecc5b324?source=collection_archive---------1-----------------------
入门指南
作者图片
聊天机器人是模拟人类对话的程序。这些机器人可以是简单的基于规则的聊天机器人,用户只能点击按钮或机器人提供的建议回复,也可以是成熟的机器人,可以处理上下文、聊天和其他复杂的事情,这些在人类对话中非常常见。
从数量上来说,对话式人工智能有 5 个层次,从简单的基于规则的系统到真正自适应的聊天机器人,它们可以处理复杂的场景,比如当用户甚至不确定他们想要什么时,可以根据他们想要的详细程度来回复用户。
**Table of Contents**
- Rasa
- Intents, Entities, Slots and Responses
- Setting up Rasa
- Creating training data
- Building our bot -- training and testing
罗砂
Rasa 是一个开源框架,用于构建基于文本和语音的聊天机器人。它在对话式人工智能的第 3 层工作,机器人可以理解上下文。第三级对话代理可以处理诸如用户改变主意、处理上下文甚至意外查询之类的事情。
如果你想建立一个聊天机器人,Rasa 不是唯一可用的工具,但它是最好的工具之一。还有其他几个,像 DialogFlow,虽然我们不会在这篇文章中讨论它们。
意图、实体、位置和响应
这些是任何聊天机器人对话的主要组成部分。我们将通过一个示例对话来更好地理解这些术语。假设我们正在构建一个收集用户联系信息的机器人。
意图
用户所暗示的被称为intent
。例如,如果用户说出以下内容之一来开始聊天:
- 早上好!
- 嗨!
- 嘿!
- 你好。
用户本质上是在说问候。因此,我们可以将这些组合成一个称为greet
的单一意图。现在,每当机器人收到类似于greet
中其他短语的用户消息,机器人就会将其归类为属于greet
意图。
意图示例—作者提供的图片
**user**: Hi. (bot classifies this message as "greet")
实体
实体是可以从用户消息中提取的数据片段。
继续我们的例子,在用户问候机器人之后,机器人询问他们的联系信息。大概是这样的:
**user**: Hi. (bot classifies this message as "greet")
**bot**: Hello! Could you please provide your contact information?
然后,用户将输入他们的详细信息,如他们的姓名和电子邮件 id。
**user**: Sure. It's John Doe. My email is johndoe@email.com.
上面的消息包含两条信息——姓名和电子邮件。这些可以被提取为实体。你的机器人将根据你训练数据的质量提取它们。
假设您已经为姓名和电子邮件定义了两个实体。这是机器人将提取的内容。
**name**: John Doe
**email**: johndoe@email.com
这里的一个重要问题是:机器人如何知道要提取什么?用户可以潜在地输入信息的任意组合。所有这些都是有效的用户输入:
- 我叫约翰·多伊。电子邮件:johndoe@gmail.com
- 姓名:无名氏电子邮件:johndoe@gmail.com
- 是啊,当然。我是无名氏。我的电子邮件是 johndoe@gmail.com。
- 约翰·多伊,johndoe@gmail.com
人类可以很容易地提取姓名和电子邮件 id。但是聊天机器人是怎么做到的呢?
这个问题的答案在于我们的训练数据有多好,我们稍后会谈到这一点。
时间
插槽是机器人的记忆。任何需要在整个对话中保持的信息,比如用户的名字或者他们的目的地(如果你正在构建一个机票预订机器人),都应该存储为 slots。
由于我们已经有了两个实体(姓名和电子邮件),我们可以创建具有相同名称的槽,因此当提取姓名或电子邮件 id 时,它们会自动存储在各自的槽中。这是因为默认情况下有两个属性是True
。
auto_fill
store_entities_as_slots
我们将如何设置这些位置,我们将在稍后讨论。
反应
响应是机器人对用户说的话。自然,对于一个机器人来说,要给出一个适当的响应,它必须弄清楚用户想要说什么。
在我们的例子中,当用户向机器人打招呼时,它理解消息本身,并通过问好和询问他们的联系方式做出适当的响应。
继续我们的示例对话,在机器人提供他们的信息后,假设我们对机器人进行编程,让它在用户提供他们的详细信息后说“谢谢”。
**user:** Hi. (bot classifies this message as "greet")
**bot**: Hello! Could you please provide your contact information?
**user**: Sure. It's John. My email is john@email.com.
**bot**: Thanks John for the info!
一些先决条件
- 使用
pip install rasa==2.6.2
安装 Rasa 开源
你可以安装最新的版本,但是这篇文章是基于 v2.6.2 的,所以任何 v2.x 都应该可以很好地适应这里介绍的内容。
2.运行rasa init
来设置演示项目。
创建培训数据
回到我们的问题,如何创建能够以多种形式提取有用信息的机器人。
这对我们来说很容易,因为我们得到了自然语言的语义,但聊天机器人做不到这一点。机器人不知道“电子邮件”是什么。它也不知道约翰可能是一个名字,电子邮件包含“@”符号。
我们的目标是提供各种数据,以便机器人能够理解单词之间的一些关联,比如单词“email”后面的内容可能是电子邮件 id,或者形式为<some_text>@<some_text>.com
的单词可能是电子邮件。
当然,不可能涵盖所有场景,但我们可以教会聊天机器人最常见的场景,确保我们添加了通用的单词和短语,这些单词和短语可能代表了机器人可能看到的很大一部分信息。
正如你可能猜到的,这更多的是一个迭代过程,我们评估我们的机器人在现实世界中的性能,并使用它来提高其性能。
密码
我们会一个文件一个文件的来,这样更容易理解。出于本文的目的,我们将讨论三个文件:
nlu.yml
domain.yml
stories.yml
NLU 培训数据
为了supply_contact_info
的意图,我们来处理下面的案例。
- 我叫约翰·多伊。电子邮件:johndoe@gmail.com
- 姓名:无名氏电子邮件:johndoe@gmail.com
- 是啊,当然。我是无名氏。我的电子邮件是 johndoe@gmail.com。
- 约翰·多伊,johndoe@gmail.com
- 当然可以。是无名氏。我的电子邮件是 johndoe@email.com。
这个训练数据被称为 NLU 数据,它包含了我们期望从用户那里得到的短语和对话(intents
)。请注意,这不包括机器人的响应或我们的对话流程。这将存在于我们项目的一个单独的部分。
YAML 文件用于此目的。
添加意图— nlu.yml
接下来,我们将为这个意图命名。姑且称之为supply_contact_info
。
用这个替换nlu.yml
的内容。改变名称和电子邮件 id 本身是一个好主意,这样机器人可以更好地概括。
version: "2.0"
nlu:- intent: supply_contact_info
examples: |
- My name is John. email's john@gmail.com
- name: David email: david@email.com
- Yeah sure. I’m Barbara. My email is barbara@email.com.
- Susan, susan@email.com
- Sure. It's Fred. My email is fred@email.com.
version
键是指 rasa 支持的训练数据格式。所有2.x
版本的 Rasa 都支持2.0
。
标记实体 nlu.yml
上面的 NLU 数据会让机器人知道用户可以说什么。但是我们仍然没有标记任何entities
,这是一个快速提醒,是机器人应该收集的关键信息。
首先,让我们定义一些实体。让我们创造性地将表示客户名称的实体称为name
。类似地,对于电子邮件,我们将使用一个名为email
的实体。
标记实体的语法是[entity_value](entity_name)
。所以对于这条线:
My name is John. email's john@email.com
我们把它写成:
My name is [John](name). email's [john@email.com](email)
标记实体-按作者分类的图像
这样,我们最终得到了用于supply_contact_info
目的的最终 NLU 数据。
version: "2.0"
nlu:- intent: supply_contact_info
examples: |
- My name is [John](name). email's [john@email.com](email)
- name: [David](name) email: [david@email.com](email)
- Yeah sure. I'm [Barbara](name). My email is [barbara@email.com](email)
- [Susan](name), [susan@email.com](email)
- Sure. It's [Fred](name). My email is [fred@email.com](email).
我们还有另一个意图,叫做greet
意图,当用户开始对话并说“嗨”或“你好”之类的话时。最后, **nlu.yml**
应该是这个样子。
nlu:- intent: greet
examples: |
- hi
- hello- intent: supply_contact_info
examples: |
- My name is [John](name). email's [john@email.com](email)
- name: [David](name) email: [david@email.com](email)
- Yeah sure. I'm [Barbara](name). My email is [barbara@email.com](email)
- [Susan](name), [susan@email.com](email)
- Sure. It's [Fred](name). My email is [fred@email.com](email).
添加插槽— domain.yml
现在我们有了意图和实体,我们可以添加我们的插槽。
头到文件domain.yml
。用这个替换slots
键的内容。
slots:
name:
type: text
email:
type: text
因为姓名和电子邮件都是字符串,所以我们将类型设置为text
。
添加响应 domain.yml
就像我们想要抽象出用户想说什么一样,我们也有反应来代表机器人会说什么。
简单的响应是基于文本的,尽管 Rasa 允许您添加更复杂的功能,如按钮、备选响应、特定于频道的响应,甚至自定义操作,我们将在后面介绍。
在我们的例子中,在用户问候机器人(intent: greet
)之后,机器人向用户询问他们的联系信息。这可以表示为机器人响应或发声。按照惯例,我们在每个机器人发声前添加一个“绝对”前缀——就像这样:
utter_ask_for_contact_info
用我们的响应替换domain.yml
中responses
键的内容。
responses:utter_ask_for_contact_info:
- text: Hello! Could you please provide your contact information?
类似地,我们可以在用户提供他们的信息后添加响应。姑且称之为:utter_acknowledge_provided_info
(粗体,如下)。
responses:utter_ask_for_contact_info:
- text: Hello! Could you please provide your contact information?**utter_acknowledge_provided_info****:
- text: Thanks for provided your info!**
我们可以通过在确认信息中提到用户的名字来让用户体验稍微好一点,比如“谢谢 John 提供的信息!”
为此,我们将修改上面的utter_acknowledge_provided_info
,为name
插槽添加一个占位符,如下所示:
utter_acknowledge_provided_info:
- text: Thanks {name} for provided your info!
对话示例—作者提供的图片
故事
故事让我们的机器人知道对话应该如何进行。回到我们的例子,机器人向用户询问他们的联系方式,对话是这样的:
**user:** Hi. (bot classifies this message as "greet")
**bot**: Hello! Could you please provide your contact information?
**user**: Sure. It's John. My email is john@email.com.
**bot**: Thanks John for the info!
这可以分解为如下的意图和回应:
intent: greet
action: utter_ask_for_contact_info
intent: supply_contact_info
action: utter_acknowledge_provided_info
添加故事— stories.yml
让我们把这个变成 rasa 能理解的语法。用这里将要讨论的内容替换文件stories.yml
的内容。让我们称这个故事为“用户提供客户信息”。
故事名称不会影响机器人的工作方式。
version: "2.0"stories:
- story: user supplies customer info
steps:
- intent: greet
- action: utter_ask_for_contact_info
- intent: supply_contact_info
- action: utter_acknowledge_provided_info
但是还有一件事。
我们还必须指出用户意图可能提供的实体,这样机器人就更容易知道如何响应。
在意图下,只需列出可能出现在该意图中的实体。
version: "2.0"stories:
- story: user supplies customer info
steps:
- intent: greet
- action: utter_ask_for_contact_info
**- intent: supply_contact_info
entities:
- name
- email** - action: utter_acknowledge_provided_info
建造我们的机器人
现在我们已经准备好了数据和故事,我们必须遵循一些步骤来让我们的机器人运行起来。
代码设置
我们对演示机器人中的文件做了一些修改。让我们回顾一下。
**nlu.yml**
—保存我们模型的 NLU 训练数据
在这个文件中,我们为我们的两个目的保留标记数据:
supply_contact_info
greet
**stories.yml**
—让机器人知道对话应该如何进行
我们的单story
就设在这里。
**domain.yml**
—所有意图、响应和实体的完整信息
这个文件比其他两个文件稍微复杂一点。如果你看看演示机器人(post running rasa init
)提供的domain.yml
文件,你会注意到intents
、actions
、responses
、entities
等键。
我们已经在我们的domain.yml
中添加了slots
和responses
。我们现在需要做的就是提到我们的intents
和entities
。最后,该文件将如下所示:
version: '2.0'intents:
- greet
- supply_contact_infoentities:
- name
- emailslots:
name:
type: text
email:
type: textresponses:
utter_ask_for_contact_info:
- text: Hello! Could you please provide your contact information?
utter_acknowledge_provided_info:
- text: Thanks {name}, for the info!
训练机器人
验证数据
在训练机器人之前,一个好的做法是检查故事和规则中的任何不一致,尽管在这么简单的项目中,这不太可能发生。
$ rasa data validate
截断的输出如下所示。没有发现冲突,所以我们可以很好地训练我们的模型。
The configuration for policies and pipeline was chosen automatically. It was written into the config file at 'config.yml'.
2021-09-12 18:36:07 INFO rasa.validator - Validating intents...
2021-09-12 18:36:07 INFO rasa.validator - Validating uniqueness of intents and stories...
...
2021-09-12 18:36:08 INFO rasa.validator - No story structure conflicts found.
注意:您可能会收到以下警告:
UserWarning: model_confidence 设置为“softmax”。建议尝试使用“model_confidence=linear_norm”来更容易地调整回退阈值。
这只是一个建议,可以忽略。
培训
为了训练机器人,我们只需使用rasa train
命令。为了更好地组织,我们将为模型提供一个名称,但这不是必需的。
$ rasa train --fixed-model-name contact_bot
这个的输出要大得多,所以我不会在这里展示。
注意:您可能会收到以下警告:
用户警告:在您的管道中找到基于规则的策略,但没有基于规则的培训数据。请将基于规则的案例添加到您的培训数据中,或者从您的 pipeline 中删除基于规则的策略(
RulePolicy
)。我们不会在这篇文章中讨论规则,但它们本质上就是它们听起来的样子。它们需要一个称为 RulePolicy 的东西,默认情况下,它会添加到您的 bot 管道中。暂时可以忽略。这将在以后的帖子中讨论。
和我们的机器人聊天
与我们的新机器人聊天很简单。打开一个新的终端窗口并启动一个 rasa shell。
$ rasa shell
这将让你在终端上与你的机器人聊天。但是如果你想清理 UI 和更多的信息,比如识别了什么意图,提取了什么实体,你可以使用 Rasa X.
关于 Rasa X 有一点很简单:它可以让你测试你的机器人,修复机器人的错误响应,更重要的是,你可以和其他人分享你的机器人,以更好地了解它在现实世界中的表现。
要使用它,请在本地模式下安装它。
$ pip3 install rasa-x --extra-index-url https://pypi.rasa.com/simple
然后,运行它。
$ rasa x
前往左边菜单中的“与你的机器人交谈”,开始与你的机器人交谈。
下面,你可以看到我们的机器人表现如何。
在 Rasa X 中与我们的机器人对话——图片由作者提供
注意
在上面的对话中,除了对话,你会注意到一些灰色的信息。在每条用户消息下面,您可以看到用户消息的意图和可信度,以及提取了哪些实体。
在每条 bot 消息的上方,您可以看到 bot 以什么样的信心决定采取什么样的行动,以及设置了什么样的槽。
action_listen
是一个内置动作,意味着聊天机器人需要用户输入。
示例代码和资源
本文中使用的所有代码都可以在以下位置获得:
https://github.com/Polaris000/BlogCode/tree/main/RasaChatbot
链接
- 拉莎
- 5 级对话人工智能
最后
Rasa 是对话式人工智能的一个伟大工具。它的灵活性和定制深度使它成为一个很好的工具选择。在这篇文章中,我们制作的机器人非常简单。
有很多东西我无法在一篇文章中描述,比如动作、表单、规则、正则表达式、同义词、交互式学习、配置文件、管道等等。但是这篇文章中的内容应该足以让你开始。
我们将在以后的文章中介绍其余的内容。我会在这里添加所有未来帖子的链接。希望有帮助!
该系列的下一部分
第二部分:槽和实体一样吗?
第三部分:处理聊天机器人故障
第四部分:聊天机器人如何理解?
更新
20.3.2022
向该系列的其余部分添加链接
构建一个从经验中学习的国际象棋人工智能
原文:https://towardsdatascience.com/building-a-chess-ai-that-learns-from-experience-5cff953b6784?source=collection_archive---------15-----------------------
不需要数据!
拉胡尔·帕博卢在 Unsplash 上拍摄的照片
在像国际象棋这样的规则定义的环境中应用机器学习技术已经成为掌握像国际象棋或围棋这样的策略游戏的稳定手段。这些技术通常涉及使用某种数据来训练模型,以做出最佳举措。
作为一个挑战,我想尝试创建一个完全不需要任何数据的引擎。尽管这会减慢模型的训练过程,但它会解决基于数据的模型所面临的一个关键问题。
模型的好坏取决于它的数据。在这种情况下,根据数据训练的象棋模型只能和数据源一样好。通过从方程中移除数据,算法的理论上限将被移除,这将给予模型(理论上)无限的潜力。
概念:
我打算怎么做?这可以通过结合我以前用过的两种技术来实现。该模型将由两部分组成:一个支配性的遗传算法和一个用于遗传算法中每个主体的蒙特卡罗搜索树。
遗传算法:
照片由国立癌症研究所在 Unsplash 上拍摄
遗传算法将由一定数量的代理组成。代理人将相互竞争,获胜者将获得一定数量的分数。
前 20%的玩家将被保留,而其余玩家的数据将被删除。前 20%的玩家之间的权重会发生交叉,从而产生一组新的玩家。这应该有希望产生越来越好的球员。
将遗传算法用于该项目的原因有两个:遗传算法可以在没有数据的情况下进行优化,并且还具有非常灵活的适应度函数。该适应度函数可以被改变以微调模型的结果,并且它还可以涉及抽象的非数值运算。
蒙特卡罗搜索树:
在 Unsplash 上由理查德·装载机拍摄的照片
蒙特卡洛搜索树用于进行每一步棋:引擎从给定的位置随机进行一系列的移动。最终位置然后由神经网络评估,其返回单个值。这个过程重复一定次数。汇总每次迭代的所有评估将导致位置分析。从初始位置开始的每一次合法移动都要重复这个过程。
然后将进行具有最高评估分数的移动。理论上,随着评估模型的改进,这些举措将是最优的。
当使用蒙特卡罗树时,需要在灵活性和速度之间进行权衡。理论上,可以使用单个深度神经网络直接评估电路板。然而,这个模型将更加难以优化,因为它需要自己“学习”许多概念,这对于遗传算法来说尤其缓慢。
蒙特卡洛搜索树是一种具有内置深度概念的神经网络,允许训练更快。
实施:
我提供的代码只是片段,肯定会出错。该项目的完整代码可以在我的 Github 上的链接中找到。
1.健身功能:
这是用于评估每个代理的适应度的适应度函数。
最初,我想让每个代理扮演每个其他代理,但发现这将花费太长时间。一些快速的计算让我得出结论,用那个设置,我需要 400 多个小时才能得到像样的结果。
原始算法的一个关键变化是在评估函数中。Model(input)比 model.predict(input)快 106 倍,每代节省 9 个多小时。
通过让每个代理只玩一个其他代理,它将减少每一代(p+1)/2 倍(p 是玩家的数量)所用的时间。
为了简单起见,我只是将代理的当前适应度乘以某个值来改变他们的适应度。如果我决定做一个 Elo 系统,这将会很有趣,并且可能会产生更好的结果。然而,我决定反对它,因为实现它会降低算法的速度。
2.评估网络
评估网络是每个代理背后的大脑。左边的代码展示了两种模型架构:
complex_eval 定义了一个复数卷积模型,常用于 Pix2Pix GAN 的编码部分。然而,这种复杂性使其难以部署,因为进行预测需要太多时间。
simple_eval 是一个基本的概念验证模型,它需要大约 0.004 秒来进行预测。低数量的权重也将导致更快的收敛。
模型的输入形状是(8,8,12),因为棋盘是 8 乘 8,并且有 12 个可能的棋子(每边 6 个)
3.遗传算法
遗传算法的大脑是适应度函数,心脏是交叉和变异函数。
交叉函数很容易理解,但实现起来有点困难。
从人口的前 20%中随机选择两个父母代理。这两个父代理的基因被合并以形成子代理。以下是对的逐步解释
- 它们的权重是扁平的,因此值可以改变。
- 找到一个随机的交点。这个点是父母一方的遗传信息结束的地方,也是父母一方的遗传信息开始的地方。
- 父母的基因结合在一起,然后一个新的子代理拥有这个操作产生的权重。
这有望让好父母的优良品质传递给他们的后代。
变异过程非常相似:随机代理的权重变平,其中一个权重变为随机值。实施遗传算法的突变,以便最终形成不是在第一种群中随机产生的有利性状。
结论:
这个项目非常有趣:没有算法理论限制的成本是由成功训练算法所花费的时间来支付的。
我的想法的实现并不完美,只是我未来工作的一个框架。
以下是可以改善/改变它的一些事情:
1.更改健身功能:
即使蒙特卡罗搜索树是最快的移动,最现实的搜索算法是找到哪一步移动结束时对手的平均评价最低。
2.改变评估模式:
尽管这看起来很容易,但它必须足够快,以允许执行时间存在于可能性的范围内
3.使用并行:
对于足够强大的 CPU,并行性(同时运行脚本)可以大大加快处理速度。如果这个问题得到解决,项目的限制将被移除,从而允许更好的结果。
我的链接:
如果你想看更多我的内容,点击这个 链接 。
构建象棋引擎:第 2 部分
原文:https://towardsdatascience.com/building-a-chess-engine-part2-db4784e843d5?source=collection_archive---------17-----------------------
结合 AlphaGo 和变形金刚学习象棋
大家好,这将是我构建象棋引擎系列教程的第二部分。这一课将着重于建立一个我们可以玩的人工智能代理。这一课比第一部分更专业,所以请耐心听我说。我试图提供方程式和图表来帮助使事情变得简单一点。
既然我们已经完成了构建我们的国际象棋游戏,我们可以开始设计一个玩它的人工智能了。国际象棋人工智能已经成功很多年了,从深蓝到 stockfish 。然而,有一个新的程序已经成为使用深度学习的最先进的技术。 AlphaZero 是一个由 DeepMind 开发的强化学习代理,它已经在众多游戏(象棋、松木、围棋)中取得了超人级别的结果。
由于这一成功,我们将建立在 AlphaZero 的基础上,并使用其强大的思想来指导具有深度学习模型的蒙特卡罗树搜索 (MCTS)算法。我们将使用一个转换器,而不是像他们论文中使用的那样使用卷积神经网络 (CNN)。变形金刚最近在自然语言处理(NLP)和计算机视觉(CV)等许多领域取得了巨大成功。因此,我们可以尝试在这里使用一个。
蒙特卡洛树搜索(MCTS)
在所有的游戏中,都有一系列的动作。在博弈论中,在博弈树中表示这些动作是很常见的。
游戏树示例|作者图片
在简单的游戏中,游戏树很小,可以被暴力搜索。对于小博弈树,我们可以使用贪婪算法,比如" MiniMax "搜索算法。大多数游戏都不简单,尽管这导致暴力方法在现代计算极限下被认为是不可行的。正因为如此,像 MCTS 这样的其他搜索算法被证明是更有益的。
MCTS 首先检查当前状态是否是叶节点(游戏结束)。如果当前状态是叶节点,搜索算法返回游戏结果。
游戏结果|作者图片
- sw =白色胜利(0 或 1)
- st =平局(0 或 1)
- sb =黑色胜利(0 或 1)
如果动作不是叶节点,并且这是第一次看到它,则使用神经网络(NN)来确定当前状态的值(v)和所有可能动作的概率(p)。当前状态节点奖励值是新预测的值。使用预测的概率分布来更新所有可能的有效动作的概率。我们返回要更新的先前节点的值(v)和概率(p)。
节点反向传播示例|作者图片
如果我们以前见过当前状态,我们递归地搜索具有最高 UCB 的动作。
UCB 是一个试图平衡开发和探索的强大公式。等式的前半部分利用了人工智能的游戏知识。后半部分通过将超参数(c)乘以概率(p)来增强探索。
置信上限(UCB) |作者图片
- v =结束游戏值
- c =探索超参数[0–1]
- p =行动概率
- N =父节点访问
- n =行动节点访问
当搜索游戏树时,如果当前深度等于最大允许深度,则返回当前深度处的值(v)和概率(p ),以更新之前的节点。
MCTS 流程图|作者图片
模型架构
了解了 MCTS 之后,让我们来谈谈我们的模型。我们的模型将获得游戏状态作为输入,并返回预期的游戏结果以及动作概率分布。
模型公式|作者图片
- vs =基于当前状态的游戏结果的概率分布
- psa =当前状态下所有行为的概率分布
我们模型的主要组件是变压器。变压器最近被谈论了很多,并越来越多地出现在最先进的系统中。通过使用注意力机制(多头比例点积注意力),变形金刚非常有效。
注意力是一个强大的等式,允许模型学习哪些事情是重要的,值得更多的关注。它通过获取一个查询和一个关键字的比例点积来确定两者的相似性。点积通过找出输入之间的角度来确定相似性。然后 Softmax 在 0-1 之间缩放结果。对结果和值进行点积,以确定两者的相似性。第二个点积有另一个有用的特性,有助于输出保持其初始形状。
缩放的点积注意力|作者图片
- Q = Q(E) =查询(向量/矩阵)
- K = K(E) = key(向量/矩阵)
- V = V(E) =值(向量/矩阵)
- E =嵌入
多头注意力将输入分成多个头,并行处理不同的组块。人们认为多头注意力通过创建不同的子空间来获得其优势。然后将每个头的结果连接在一起,并传递到一个线性层,该层将输入映射回其原始维度。
多头缩放点积关注|图片来自https://arxiv.org/abs/1706.03762
普通变压器具有简单的编码器和解码器架构。
变压器架构(编码器-解码器)|图片来自 https://arxiv.org/abs/1706.03762
然而,我们不打算使用这种架构,而是打算使用一个仅支持解码器的转换器。一个只有解码器的变压器看起来就像“注意是你需要的全部”论文中的变压器架构图中的编码器。当您比较上面的编码器模块和解码器模块时,您会发现只有一个区别,即编码器中缺少编码器-解码器关注层。在一个只有解码器的转换器中不需要这个编码器-解码器关注层,因为没有编码器,这意味着我们可以利用编码器块来创建一个只有解码器的模型。
纯解码器变压器架构|图片来自https://arxiv.org/abs/1706.03762
在变压器模块之后,我们模型的其余部分相当简单。我们添加一个线性层来映射我们的转换器层的输出到我们需要的维度(1D)。
线性图层|作者提供的图像
- x =输入(向量/矩阵)
- A =层权重(矢量/矩阵)
- b =层偏差(矢量/矩阵)
该模型然后分叉成两个平行的线性层(v,p)。这些线性图层用于将每个输出映射到所需的大小。其中一层将是游戏结果的大小(v),而另一层是动作状态的大小(p)。在线性层之后,softmax 独立应用于两个输出,以将其结果转换为概率分布。
Softmax |作者图片
- x =输入(向量/矩阵)
输入编码
既然我们知道了我们正在使用的模型架构,我们可能应该讨论一下输入数据。该模型将接收游戏的状态作为输入,但不能直接处理它。对于要处理的游戏状态,需要对其进行编码。为此,我们将通过标记化的方法使用嵌入。这些嵌入是代表每一部分的唯一向量。嵌入允许我们的模型获得每个游戏片段之间的相关性的强表示。
符号化嵌入|作者图像
转换器模型并行处理输入序列,导致它们丢弃位置信息。幸运的是,我们可以在输入中添加一个位置编码来帮助恢复这些附加信息。位置编码允许模型根据其在输入序列中的位置从每个嵌入中提取额外的信息。这些额外的信息代表了每个棋子和它在游戏棋盘上的位置之间的关系。
嵌入示例|作者图片
位置编码公式|作者图片
输出编码
有了对输入的这种理解,我们来谈谈输出。该模型将有两个输出值。一个代表可能结果的概率分布(奖励),另一个代表行动的概率分布(政策)。
在我们的国际象棋游戏中,可能的结果是白棋赢,平手和黑棋赢。由于这些结果是在名义规模上,我们知道这是一个分类问题。独热编码在分类问题中很流行,因为每一位可以代表不同的结果。为了确定游戏最可能结果的指数,我们可以取输出的 argmax。由此,我们现在知道了游戏最有可能的结果和预测的可信度。
预测的游戏结果|作者图片
- sw =白色胜利(0 或 1)
- st =平局(0 或 1)
- sb =黑色胜利(0 或 1)
在国际象棋中,棋子不断移动。这种移动使得我们很难将有效的动作映射回当前状态。为了缓解这个问题,我们将把动作想象成哪个方块移动到哪个方块。这里我们有效地简化了解码过程,因为棋盘上的方块在整个游戏中保持不变。我们可以用一个扁平的 64x64 矩阵来表示。展平矩阵是必要的,因为这又是一个分类问题,因为我们的行动是名义上的。正因为如此,我们将希望使用一键编码来表示我们的动作空间。为了确定最可能采取的动作的索引,我们过滤掉无效的动作,并取输出的 argmax。由此,我们现在知道了最有可能的有效动作和该预测的置信度。
游戏动作编码|作者图片
动作概率分布|作者图片
- a=行动概率(0–1)
培训模式
与 AlphaZero 类似,我们的模型完全通过自我游戏来学习。在我们的版本中,我们通过让两个模型(活动的,新的)在循环赛系列中相互竞争,为自我游戏添加了一个进化的方面。在我们的循环赛系列赛中,新型号在每场比赛后都要训练。如果新模型是循环赛的获胜者,它将成为活动模型。这样,我们可以将自我游戏导致的潜在收益递减最小化。
该模型根据每场比赛的结果进行训练,以使预测的比赛结果和预测的行动(奖励和政策网络)的损失最小化。为此,该模型使用两个输出的二元交叉熵(BCE)。BCE 是损失函数,因为它能很好地处理多变量分类问题。
损失函数公式|作者图片
- p =行动概率分布
- pi =所采取行动的一次性编码
- v =游戏结果概率分布
- z =游戏结果的一次性编码
谢谢
就这样,我们成功地创造了一个国际象棋人工智能。这个 AI 会在没有任何知识的情况下开始学习国际象棋的游戏。它玩的训练游戏越多,表现就越好。我希望您喜欢阅读本系列的第 2 部分。你可以在我的 GitHub 上查看完整版本的代码。你也可以看到这个系列的第一部分在这里和我的新机器人结合穆泽罗和感知者 IO 在这里。
感谢阅读。如果你喜欢这样,可以考虑订阅我的账户,以便在我最近发帖时得到通知。
参考
- https://en . Wikipedia . org/wiki/Deep _ Blue _(chess _ computer)
- https://en . Wikipedia . org/wiki/stock fish _(chess)
- https://deep mind . com/blog/article/alpha zero-shedding-new-light-grand-games-chess-shogi-and-go
- https://deepmind.com/
- https://en.wikipedia.org/wiki/Monte_Carlo_tree_search
- https://en.wikipedia.org/wiki/Convolutional_neural_network
- https://en.wikipedia.org/wiki/Minimax
- https://jalammar.github.io/illustrated-transformer/
- https://kazemnejad . com/blog/transformer _ architecture _ positional _ encoding/
- https://en.wikipedia.org/wiki/One-hot
- https://arxiv.org/abs/1706.03762
通过写作构建引人注目的数据科学产品组合
原文:https://towardsdatascience.com/building-a-compelling-data-science-portfolio-with-writing-daceec1cd0fe?source=collection_archive---------18-----------------------
数据科学写作不仅可以在你的旅程中,也可以在你的职业生涯中产生变革性的影响。
照片由 Aaron Burden 在 Unsplash
我参加了由Weights&bias组织的快速阅读会议,讨论数据科学写作的好处。我写这篇文章是为了总结我在那里讨论的内容。这篇文章最初发表在他们的论坛上,但是我在这里分享了一个编辑过的版本。它主要讨论了为什么写作在数据科学中很重要,以及如何将其作为一种工具来利用您的投资组合。
学习任何概念的最佳方式,尤其是在数据科学中,是通过写下它。它有助于你详细理解这个主题,反过来,你的工作也可以帮助别人。但这说起来容易做起来难。即使许多人想写作,他们也需要几个月甚至几年的时间来克服最初的自我怀疑。雷切尔·托马斯的博客文章《为什么你(是的,你)应该写博客》非常恰当地触及了这个问题。事实上,它涵盖了你开始写作时应该记住的所有要点。我的职业生涯是从写作开始的,在这篇文章中,我将分享你如何运用你的写作技巧来创作一个引人注目的作品集。
写作为什么有用?
写作,尤其是在数据科学领域,是一项重要的技能。它给你声音和能见度。依我看,写作的好处可以总结如下:
写作的好处|作者图片
- 记忆:写作帮助你记住一个新概念。
- 研究:写作有助于培养研究思维。
- 声誉:写作有助于在社区中建立声誉。人们引用你的文章,在他们的谈话中提到你,等等。
- 收入:写作本身也可以是一种自给自足的职业。随着创作者经济的蓬勃发展,写作可以带来潜在的工作机会。
如何开始你的写作之旅
当你决定写一篇文章时,你就成功了一半。然而,第二部分是决定写什么,在哪里写,主题,长度等等。最好是自己创造自己的写作道路。从最舒服的概念开始;这会给你必要的信心开始。逐渐多样化你的写作组合。开始接触新事物,并尝试写下它们。写作是一个反复的过程。写得越多,学得越多,写得越好。
你可以写的东西
- 如何使用数据科学库
- 研究论文摘要
- 课程点评
- 采访社区里的人
- 阐明概念
- 总结技术视频/网络研讨会
- 将您的 Kaggle 笔记本转换为博客文章等
这些只是一小部分,但可以作为一个很好的起点。
展示你的作品
无论你是为一个人还是为一千个人写一篇文章,付出的努力是一样的。因此,一定要在其他平台上分享它们,比如 Linkedin、Twitter 和其他你所在的社区团体。请不要要求他们喜欢或分享本身。这是因为在分享你的作品和发送垃圾邮件之间只有一线之隔。如果人们喜欢它,觉得它有趣,相信我,他们会想自己分享它。
展示你作品的另一种方式是在聚会、演示和会议中使用它们。内容创建很有挑战性,但是一旦完成,就可以以多种方式重用。
创建公共投资组合
你可以在开放的博客平台上写作或者创建自己的网站。这完全取决于你。但是确保从一开始就建立一个好的投资组合。Github 页面、Kaggle 配置文件、堆栈溢出等。,可以支持你的简历。
为社区做贡献
社区是数据科学的支柱。加入当地的 Meetup 社区。在会议上发言——从地方到地区,甚至国家。你甚至可以指导这个领域的新手。在论坛回答和帮助别人。尝试为开源库的文档做贡献。
这些都很好,但是有人会读我的文章吗?
这是我遇到的最常见的问题。不仅在数据科学领域,而且在几乎所有领域,甚至在开始之前就自我怀疑是相当普遍的。人们的一些常见疑虑是:
已经有很多关于这个话题的文章了。我的文章会有什么不同?
假设你想写一个图书馆。你快速搜索了一下,发现还有十多篇关于这个话题的好文章。所以你会放弃这个想法吗?不,绝对不是。尝试通过使用有趣的数据集和关注库中鲜为人知的方面来对您的文章进行不同的处理。例如,我写了一篇关于Lux——一个 Python 库 的文章,在那里我展示了 Simpson 使用这个库的效果。库的创建者喜欢它,并把它作为文档的一部分。
来自 Lux 的 Github 知识库的片段| 来源
这是另一个例子。我最近写了一篇文章可解读还是准确?为什么不两者都要?,在那里我解释了可解释的助推机器的概念——模型被设计成具有与助推树相当的准确性,同时具有高度的可理解性和可解释性。 EBM 是微软的开源库。我收到了团队写这篇文章的个人信息。
作者图片
这些只是几个例子,突出了写作不仅可以给你的简历带来巨大的价值,而且可以在社区内建立人际网络。
入门资源
既然你已经决定冒险一试,这里有一些开源工具可以帮助你开始。
- blog site:fast pages—一个易于使用的博客平台,支持 Jupyter 笔记本、Word 文档和 Markdown。另一个选项可以是中。
- Images : Unsplash 、 Pixabay 和 Pexels 是一些提供免费图片和照片的网站,你可以下载并用于任何项目。
- 插图: unDraw 为可定制的开源插图。
- 自定义图像 : Canva 用于设计和发布几乎任何内容。
- 校对 : Grammarly 的免费增值版,用于拼写检查和捕捉最基本的语法错误。小型 SEO 工具则提供除了检查语法之外的免费抄袭检查。
反馈是必不可少的,但不要气馁。
领导力专家肯·布兰查德恰如其分地创造了这个短语:“反馈是冠军的早餐。”。获得批评性的反馈是提高的必要条件,这同样适用于写作。然而,给予反馈是重要的,但是谴责某人的工作(尤其是公开地)是完全错误的。可悲的是,很多时候,你会遇到这样的情况。有些人在你的文章上留下非常令人反感的评论,没有给出任何理由。
苏珊娜在推特上的绝妙建议
然而,我给你的建议是不要让消极情绪战胜你的激情。我和上面苏珊娜的推文产生共鸣。创造任何东西都是困难的,需要大量的耐心、毅力和坚持。
结论
在我看来,最重要的是找到你感兴趣的话题,这个话题产生了你想要回答的问题。我们倾向于拖延很多事情,比如写作。我们相信我们的第一个博客一定是最好的。就像我上面提到的,写作是一个迭代的过程,我们写的每一篇文章都会让我们成为更好的作家。所以,走出去,弄脏你的手,享受写作的乐趣。
构建机密数据网
原文:https://towardsdatascience.com/building-a-confidential-data-mesh-1a4a103471dc?source=collection_archive---------30-----------------------
数据网格架构和差分隐私技术如何帮助您以安全的方式实现对机密数据的访问民主化
里卡多·戈麦斯·安吉尔在 Unsplash 上的照片
最常见的数据工程架构是数据湖和数据仓库。两者都是集中式系统:来自每个数据产生实体的数据被集中到一个位置,由一个数据工程师团队负责。它带来了许多挑战和限制:
- 数据工程师没有特定的领域知识。产生数据的系统可能变化很快,由一个单独的团队负责集成到一个集中的系统中会增加复杂性和延迟。数据湖/仓库不太灵活。
- 很难添加大量数据源,因为集中式工程团队很难扩展。
- 将数据移动到一个中央存储库在法律上可能具有挑战性,尤其是跨业务线或地理边界。
- 当数据被复制到中央存储库时,数据泄露的风险就更大了
为什么数据网格现在如此受关注?
数据网格架构是 Zhamak Dehghani ( @zhamakd )(在这篇论文)在 2019 年 5 月提出的。这是数据架构设计中的一个重大转变,克服了集中式方法的局限性,并提供了可伸缩性和敏捷性。
Zhamak Dehghani 介绍她关于数据网格的论文(来源:Twitter)
数据网格的核心原则是:
— 分布式、面向领域的数据:与许多实体(比如营销、运营、R&D……)推送数据的集中式存储库相反,数据网格意味着数据是按领域组织的。这意味着数据工程师拥有领域知识,因此可以更加高效和敏捷
— 数据即产品:数据消费者的用户体验必须是域名所有者的主要关注点。任何人(当然是经过授权的)都应该能够自主地消费数据,而不需要领域数据团队的帮助。数据应该是高质量的、可发现的、自我描述的,并且通常易于消费
— 自助式数据平台:为了支持领域数据团队,组织必须提供自助式数据基础架构,为数据团队提供工具,如大数据存储、联合身份管理或数据访问日志记录
— 分散化&联合治理:全球(在组织级别)标准应该通过联合机制定义,并有领域代表。这些标准是在平台中通过计算实现的。
围绕数据网格有一个活跃的社区,你可以在这里加入。
文化和组织的变化:当数据成为产品
现在,每个数据生产实体都应该通过一个定义明确、记录完善的标准来提供其数据。数据工程师现在就来自这个领域,所以更容易扩展:领域的数量不会影响集中的数据团队,变得无关紧要。
领域数据团队现在必须考虑他们的资产,他们的产品,以及数据的消费者,他们的客户。必须衡量和跟踪客户满意度,以推动数据团队的工作。
软件和数据工程架构和哲学的可喜融合
数据网格的引入与软件工程中从单片到微服务的转变有一些相似之处。它强调了域所有者和互操作性的重要性,旨在在高度复杂的环境中进行扩展。
机密数据网格简介
在大多数组织中,许多数据集是高度敏感的,并受到限制(出于监管或商业原因)。例如,可能无法将个人数据移出法律实体或国家/地区。这些数据集不能添加到网格中,原始域之外的分析师也不能利用它们。
这是一个重大的错失机会。传统的补救策略依赖于数据屏蔽,但它需要定制的数据争论,无法解决大规模的合规性挑战,并可能对数据效用产生重大影响(更多关于数据屏蔽缺点的信息此处)。为了充分利用数据网格的力量,我们需要大规模解决机密数据访问。
输入隐私保护技术,尤其是差分隐私。
差分隐私是定义数据分析中隐私风险的数学框架。它提供了在处理数据时保护私有信息的机制和算法。它是由 Cynthia Dwork 在 2006 年推出的,并在商业应用中慢慢部署(还有很多工作要做)。它主要被谷歌、苹果或微软用于内部需求,抓住机会利用数据,同时保护隐私。这里有一个很好的资源,不用太多数学就可以学习 DP。为了更系统地回顾它,这是参考书:差分隐私的算法基础(德沃克,罗斯)。
差分隐私可以被认为是匿名计算结果的定义。它被认为是匿名的,因为它不会透露任何特定个人的重要信息。它适用于任何类型的计算,但机器学习或 SQL 分析是显而易见的候选。对一行数据应用差分隐私没有太大意义,因为结果不应该取决于数据行本身!但幸运的是,没有人在一行数据上做 ML 或 BI。在数据网格体系结构中,整个数据集位于一个位置,因此可以对所有行执行每个分析,这是差异隐私的完美匹配。
有了差分隐私,我们现在可以设计一个真正可扩展的机密数据网格。当一些域具有不能在整个组织内共享的敏感或管控数据时,这是传统数据网格的扩展。每个域都实施与其监管约束相关的隐私政策。
在机密数据网格中,不能从节点中提取敏感数据,但是仍然可以在其上执行计算。因为它实现了与经典数据网格相同的互操作性需求,所以数据源可以被同样地编目。需要提取数据样本甚至流式传输数据的应用程序总是可以访问模拟源属性的合成数据,这些数据是通过差分私有深度学习算法生成的。可以使用 SQL 查询的不同私有实现来查询节点级数据库。机器学习可以在原始数据上进行训练,仍然具有差分隐私保证。
最后,从数据从业者的角度来看,机密数据网格的行为与原始数据网格完全一样。主要区别在于所有权原则还扩展到了遵从标准和隐私政策的实现。
一个机密数据网混合了敏感域和开放域。敏感域必须只公开不同私有 API(由 Sarus technologies 绘制)
构建您自己的机密数据网(CDM)
清洁发展机制的组成部分是:
- 在 SQL 查询或 ML 作业中实现不同隐私的远程执行框架
- 跟踪数据集上所有影响隐私的查询的会计师
- 差分专用合成数据发生器
- 实现互操作性标准的 API(包括目录、数据导出、SQL 驱动程序……)
- 还有把所有东西粘在一起的胶水。
没有一种开源解决方案可以一键部署 CDM,但幸运的是,一些基本的构建模块是可用的。大多数开源项目仍处于试验阶段,但它们是一个很好的开始资源。最有趣的是:
- OpenDP :这是哈佛和微软的共同努力,为差分私有计算提供了主要的工具箱。主要贡献是一组 DP 原语( smartnoise-core )和一个运行 SQL 查询的 SDK(smart noise-SDK)
- Google Differential Privacy:与 OpenDP 类似,Google DP 提供了 DP 原语,可以在 Apache Beam、Differential-private SQL 引擎和隐私会计师之上运行
- TensorFlow/privacy :允许训练具有差分隐私的 TensorFlow 模型。请注意,这段代码已经打包在 OpenMined 中。
- PyTorch Opacus :来自脸书的一个库,用来训练 PyTorch 模型的不同隐私
通过将这些库安装在机密域上,用户可以在不同的隐私保证下对机密数据进行查询。
这是一个良好的开端,但我们仍远未找到可行的解决方案,因为缺少许多关键部分:
- API:数据网格非常强大,因为所有与外部用户的通信都是通过标准化的 API 进行的。CDM 提供与其他节点的互操作性也是如此。
- 加强隐私合规性:开源库是为科学家设计的,他们可以访问原始数据,并希望发布私人成果。用户有责任使用差分隐私的安全参数化。在 CDM 中,这应该是强制的,这样用户就不能执行任何暴露隐私的查询。
- 优化隐私消费 : DP 伴随着隐私预算的概念。但是如果孤立地考虑每个查询,这个预算会很快用完。为了获得最佳的准确性,人们希望利用所有的公共信息来建立有用的先验知识,以及之前已经发布的任何信息。实现记忆化是执行连续查询或学习作业的重要部分。
- 合成数据:数据从业者会希望看到一些原始数据的样本。因为揭示原始数据不是一个选项,所以合成数据是必须的。它必须用差分隐私来生成,以保持隐私保证。
- 使用策略和会计的隐私治理:如何控制多个请求的隐私泄露?(提示:这不是微不足道的,因为差异隐私的关键指标ε不是可加的:如果你花了ε= 1,那么ε= 2,你没有花ε= 3:()。管理员如何为不同的用户设置不同的策略?
如果没有单一的开源库可以将 CDM 带入生活,一些初创公司和大型组织正在慢慢地将所有的碎片汇集在一起,使 CDM 成为大规模利用敏感数据的最有效方式。
在 Sarus,我们让以数据为中心的组织在以完全合规的方式处理敏感数据时更加高效和敏捷。如果您想了解更多关于机密数据网格、Sarus 如何提供帮助、获取演示并亲自尝试,请联系 hello@sarus.tech.
如果你对用最先进的技术解决隐私问题感兴趣,我们正在招聘,所以快来加入我们吧!
构建卷积神经网络模型以理解场景
原文:https://towardsdatascience.com/building-a-convolutional-neural-network-model-to-understand-scenes-1673abd9884d?source=collection_archive---------18-----------------------
R 中的数据科学
一个完整的循序渐进的数据扩充和转移学习教程
照片由索拉萨克、迈克尔·克拉恩、肖恩·皮尔斯、纪尧姆·布里亚德、希法兹·沙蒙和岩田良治在 Unsplash
**Table of Contents**· [Library](#dcd8)
· [Dataset](#44f0)
· [Exploratory Data Analysis](#7f82)
· [Data Preprocessing](#e848)
· [Modeling](#8635)
∘ [Simple CNN](#a08c)
∘ [Deeper CNN](#161c)
∘ [Deeper CNN with Pretrained Weights](#0f40)
· [Conclusion](#fb48)
自从我开始在介质上写作,我就非常依赖 Unsplash 。这是一个美丽的地方,创造高品质的图像。但是你知道 Unsplash 用机器学习来帮助标记照片吗?
对于上传到 Unsplash […]的每张图片,我们都会通过一系列机器学习算法来理解照片的内容,从而消除了投稿人手动标记照片的需要。— Unsplash 博客
给照片贴标签是一项非常重要的任务,可以由机器快速完成。因此,我们将建立一个模型,可以从图像中提取信息,并给出正确的标签,以根据主题位置对图像数据库进行分类。我们将使用卷积神经网络(CNN)进行预测,以对图像是关于“建筑物”、“森林”、“冰川”、“山”、“海”还是“街道”进行分类。所以,这是一个图像分类问题。
图书馆
除了我们通常在 R 中使用的循环库,我们还将利用 keras 。Keras 是一个高级神经网络 API,开发的目的是实现快速实验。
library(keras) # deep learning
library(tidyverse) # data wrangling
library(imager) # image manipulation
library(caret) # model evaluation
library(grid) # display images in a grid
library(gridExtra) # display images in a gridRS <- 42 # random state constant
注意,我们创建了一个名为RS
的变量,它只是一个数字,用于未来随机过程的再现性。
资料组
数据由带有 6 个不同标签的图像组成:“建筑物”、“森林”、“冰川”、“山”、“海”和“街道”。不像上一篇文章中的图像像素数据已经被转换成一个.csv
文件的列,这次我们使用数据生成器直接读取图像。
https://medium.com/data-folks-indonesia/hand-gesture-recognition-8c0e2927a8bb [## 手势识别
medium.com](https://medium.com/data-folks-indonesia/hand-gesture-recognition-8c0e2927a8bb)
为此,我们需要知道图像文件夹结构,如下所示。
seg_train
└── seg_train
├── buildings
├── forest
├── glacier
├── mountain
├── sea
└── streetseg_test
└── seg_test
├── buildings
├── forest
├── glacier
├── mountain
├── sea
└── street
在每个buildings
、forest
、glacier
、mountain
、sea
和street
子文件夹中,保存有相应的图像。顾名思义,我们将使用seg_train
进行模型训练,使用seg_test
进行模型验证。
探索性数据分析
首先,我们需要定位每个类别的父文件夹地址。
folder_list <- list.files("seg_train/seg_train/")
folder_path <- paste0("seg_train/seg_train/", folder_list, "/")
folder_path#> [1] "seg_train/seg_train/buildings/" "seg_train/seg_train/forest/" "seg_train/seg_train/glacier/" "seg_train/seg_train/mountain/"
#> [5] "seg_train/seg_train/sea/" "seg_train/seg_train/street/"
然后,列出来自每个父文件夹地址的所有seg_train
图像地址。
file_name <-
map(folder_path, function(x) paste0(x, list.files(x))) %>%
unlist()
下面我们可以看到总共有 14034 张seg_train
图片。
cat("Number of train images:", length(file_name))#> Number of train images: 14034
作为理智检查,让我们看几张seg_train
图片。
set.seed(RS)
sample_image <- sample(file_name, 18)
img <- map(sample_image, load.image)
grobs <- lapply(img, rasterGrob)
grid.arrange(grobs=grobs, ncol=6)
拿第一张图片来说。
img <- load.image(file_name[1])
img#> Image. Width: 150 pix Height: 150 pix Depth: 1 Colour channels: 3
下面可以看到,这张图的尺寸是 150 × 150 × 1 × 3。这意味着这个特定的图像具有 150 像素的宽度、150 像素的高度、1 像素的深度和 3 个颜色通道(用于红色、绿色和蓝色,也称为 RGB)。
dim(img)#> [1] 150 150 1 3
现在,我们将构建一个函数来获取图像的宽度和高度,并将该函数应用于所有图像。
get_dim <- function(x){
img <- load.image(x)
df_img <- data.frame(
width = width(img),
height = height(img),
filename = x
)
return(df_img)
}
file_dim <- map_df(file_name, get_dim)
head(file_dim)#> width height filename
#> 1 150 150 seg_train/seg_train/buildings/0.jpg
#> 2 150 150 seg_train/seg_train/buildings/10006.jpg
#> 3 150 150 seg_train/seg_train/buildings/1001.jpg
#> 4 150 150 seg_train/seg_train/buildings/10014.jpg
#> 5 150 150 seg_train/seg_train/buildings/10018.jpg
#> 6 150 150 seg_train/seg_train/buildings/10029.jpg
我们得到了图像的宽度和高度的如下分布。
hist(file_dim$width, breaks = 20)
hist(file_dim$height, breaks = 20)
summary(file_dim)#> width height filename
#> Min. :150 Min. : 76.0 Length:14034
#> 1st Qu.:150 1st Qu.:150.0 Class :character
#> Median :150 Median :150.0 Mode :character
#> Mean :150 Mean :149.9
#> 3rd Qu.:150 3rd Qu.:150.0
#> Max. :150 Max. :150.0
正如我们所见,数据集包含不同维度的图像。所有的宽度都是 150 像素。但是,最大和最小高度分别为 150 和 76 像素。在适合模型之前,所有这些图像必须在相同的维度上。这一点至关重要,因为:
- 每个图像像素值所适合的模型的输入层具有固定数量的神经元,
- 如果图像尺寸太高,训练模型可能会花费太长时间
- 如果图像尺寸太低,就会丢失太多信息。
数据预处理
神经网络模型可能出现的一个问题是,它们倾向于记忆seg_train
数据集中的图像,以至于当新的seg_test
数据集进来时,它们无法识别它。数据扩充是解决这一问题的众多技术之一。给定一幅图像,数据增强将对其进行轻微转换,以创建一些新图像。然后将这些新图像放入模型中。这样,模型知道原始图像的许多版本,并且希望理解图像的意思,而不是记住它。我们将只使用一些简单的转换,例如:
- 随机水平翻转图像
- 随机旋转 10 度
- 随机放大 0.1 倍
- 随机水平移动总宽度的 0.1 分之一
- 随机水平移动总高度的 0.1 分之一
我们不使用垂直翻转,因为在我们的情况下,他们可以改变图像的意义。这种数据扩充可以使用image_data_generator()
功能完成。将生成器保存到名为train_data_gen
的对象中。注意train_data_gen
仅在训练时应用,我们在预测时不使用它。
在train_data_gen
中,我们还进行了归一化处理,以减少光照差异的影响。此外,CNN 模型在[0..1]数据比[0..255].为此,只需将每个像素值除以 255。
train_data_gen <- image_data_generator(
rescale = 1/255, # scaling pixel value
horizontal_flip = T, # flip image horizontally
vertical_flip = F, # flip image vertically
rotation_range = 10, # rotate image from 0 to 45 degrees
zoom_range = 0.1, # zoom in or zoom out range
width_shift_range = 0.1, # shift horizontally to the width
height_shift_range = 0.1, # shift horizontally to the height
)
我们将使用 150 × 150 像素作为输入图像的形状,因为 150 像素是所有图像中最常见的宽度和高度(再次查看 EDA),并将大小存储为target_size
。此外,我们将分批训练模型,每批 32 个观测值,存储为batch_size
。
target_size <- c(150, 150)
batch_size <- 32
现在,构建生成器以从各自的目录中流动训练和验证数据集。填写参数target_size
和batch_size
。由于我们有彩色的 rgb 图像,将color_mode
设置为“RGB”。最后,使用train_data_gen
作为generator
来应用之前创建的数据扩充。
# for training dataset
train_image_array_gen <- flow_images_from_directory(
directory = "seg_train/seg_train/", # folder of the data
target_size = target_size, # target of the image dimension
color_mode = "rgb", # use RGB color
batch_size = batch_size , # number of images in each batch
seed = RS, # set random seed
generator = train_data_gen # apply data augmentation
)
# for validation dataset
val_image_array_gen <- flow_images_from_directory(
directory = "seg_test/seg_test/",
target_size = target_size,
color_mode = "rgb",
batch_size = batch_size ,
seed = RS,
generator = train_data_gen
)
接下来,我们将看到目标变量中标签的比例,以检查类不平衡。如果有的话,分类器倾向于做出有偏差的学习模型,与多数类相比,该模型对少数类具有较差的预测准确性。我们可以通过对训练数据集进行上采样或下采样来以最简单的方式解决这个问题。
output_n <- n_distinct(train_image_array_gen$classes)
table("Frequency" = factor(train_image_array_gen$classes)) %>%
prop.table()#> Frequency
#> 0 1 2 3 4 5
#> 0.1561208 0.1618213 0.1712983 0.1789939 0.1620351 0.1697307
幸运的是,从上面可以看出,所有的职业都相对平衡!我们不需要进一步的治疗。
建模
首先,让我们保存我们使用的训练和验证图像的数量。除了训练数据之外,我们还需要不同的数据来进行验证,因为我们不希望我们的模型只擅长预测它已经看到的图像,而且还可以推广到未看到的图像。这种对看不见的图像的需求正是我们也必须在验证数据集上看到模型性能的原因。
因此,我们可以在下面观察到,我们有 14034 个图像用于训练(如前所述),3000 个图像用于验证模型。
train_samples <- train_image_array_gen$n
valid_samples <- val_image_array_gen$n
train_samples#> [1] 14034valid_samples#> [1] 3000
我们将从最简单的开始逐步构建三个模型。
简单 CNN
该模型只有 4 个隐藏层,包括最大池化和展平,以及 1 个输出层,详情如下:
- 卷积层:滤波器 16,核大小 3 × 3,相同填充,relu 激活函数
- 最大池层:池大小 2 × 2
- 展平图层
- 密集层:16 节点,relu 激活功能
- 密集层(输出):6 节点,softmax 激活功能
请注意,我们使用扁平化层作为从网络的卷积部分到密集部分的桥梁。基本上,展平层所做的就是——顾名思义——将最后一个卷积层的维度展平为单个密集层。例如,假设我们有一个大小为(8,8,32)的卷积层。这里,32 是过滤器的数量。展平层将把这个张量整形为大小为 2048 矢量。
在输出层,我们使用 softmax 激活函数,因为这是一个多类分类问题。最后,我们需要指定 CNN 输入层所需的图像大小。如前所述,我们将使用存储在target_size
中的 150 × 150 像素的图像尺寸和 3 个 RGB 通道。
现在,我们准备好了。
# Set Initial Random Weight
tensorflow::tf$random$set_seed(RS)
model <- keras_model_sequential(name = "simple_model") %>%
# Convolution Layer
layer_conv_2d(filters = 16,
kernel_size = c(3,3),
padding = "same",
activation = "relu",
input_shape = c(target_size, 3)
) %>%
# Max Pooling Layer
layer_max_pooling_2d(pool_size = c(2,2)) %>%
# Flattening Layer
layer_flatten() %>%
# Dense Layer
layer_dense(units = 16,
activation = "relu") %>%
# Output Layer
layer_dense(units = output_n,
activation = "softmax",
name = "Output")
summary(model)#> Model: "simple_model"
#> _________________________________________________________________
#> Layer (type) Output Shape Param #
#> =================================================================
#> conv2d (Conv2D) (None, 150, 150, 16) 448
#> _________________________________________________________________
#> max_pooling2d (MaxPooling2D) (None, 75, 75, 16) 0
#> _________________________________________________________________
#> flatten (Flatten) (None, 90000) 0
#> _________________________________________________________________
#> dense (Dense) (None, 16) 1440016
#> _________________________________________________________________
#> Output (Dense) (None, 6) 102
#> =================================================================
#> Total params: 1,440,566
#> Trainable params: 1,440,566
#> Non-trainable params: 0
#> _________________________________________________________________
建立后,我们编译和训练模型。我们对损失函数使用分类交叉熵,因为这又是一个多类分类问题。我们使用默认学习率为 0.001 的 adam 优化器,因为 adam 是最有效的优化器之一。我们还使用准确性作为简单性的衡量标准。更重要的是,因为我们不喜欢一个类高于其他类,并且每个类都是平衡的,所以与精确度、灵敏度或特异性相比,准确性更受青睐。我们将训练 10 个时期的模型。
model %>%
compile(
loss = "categorical_crossentropy",
optimizer = optimizer_adam(lr = 0.001),
metrics = "accuracy"
)
# fit data into model
history <- model %>%
fit_generator(
# training data
train_image_array_gen,
# training epochs
steps_per_epoch = as.integer(train_samples / batch_size),
epochs = 10,
# validation data
validation_data = val_image_array_gen,
validation_steps = as.integer(valid_samples / batch_size)
)plot(history)
从第十个时期的最终训练和验证精度,我们可以看到它们具有相似的值并且相对较高,这意味着没有发生过拟合。接下来,我们将对验证数据集上的所有图像执行预测(而不是像在训练中那样对每批图像执行预测)。首先,让我们将每个图像的路径和它对应的类列表。
val_data <- data.frame(file_name = paste0("seg_test/seg_test/", val_image_array_gen$filenames)) %>%
mutate(class = str_extract(file_name, "buildings|forest|glacier|mountain|sea|street"))
head(val_data)#> file_name class
#> 1 seg_test/seg_test/buildings\\20057.jpg buildings
#> 2 seg_test/seg_test/buildings\\20060.jpg buildings
#> 3 seg_test/seg_test/buildings\\20061.jpg buildings
#> 4 seg_test/seg_test/buildings\\20064.jpg buildings
#> 5 seg_test/seg_test/buildings\\20073.jpg buildings
#> 6 seg_test/seg_test/buildings\\20074.jpg buildings
然后,我们将每个图像转换成一个数组。不要忘记将像素值归一化,即除以 255。
image_prep <- function(x, target_size) {
arrays <- lapply(x, function(path) {
img <- image_load(
path,
target_size = target_size,
grayscale = F
)
x <- image_to_array(img)
x <- array_reshape(x, c(1, dim(x)))
x <- x/255
})
do.call(abind::abind, c(arrays, list(along = 1)))
}
test_x <- image_prep(val_data$file_name, target_size)
dim(test_x)#> [1] 3000 150 150 3
接下来,预测。
pred_test <- predict_classes(model, test_x)
head(pred_test)#> [1] 4 0 0 0 4 3
现在,将每个预测解码到相应的类别中。
decode <- function(x){
case_when(
x == 0 ~ "buildings",
x == 1 ~ "forest",
x == 2 ~ "glacier",
x == 3 ~ "mountain",
x == 4 ~ "sea",
x == 5 ~ "street",
)
}
pred_test <- sapply(pred_test, decode)
head(pred_test)#> [1] "sea" "buildings" "buildings" "buildings" "sea" "mountain"
最后,分析混淆矩阵。
cm_simple <- confusionMatrix(as.factor(pred_test), as.factor(val_data$class))
acc_simple <- cm_simple$overall['Accuracy']
cm_simple#> Confusion Matrix and Statistics
#>
#> Reference
#> Prediction buildings forest glacier mountain sea street
#> buildings 348 24 14 20 35 106
#> forest 8 418 3 4 4 19
#> glacier 7 5 357 53 38 5
#> mountain 19 6 98 381 61 5
#> sea 13 1 75 65 363 6
#> street 42 20 6 2 9 360
#>
#> Overall Statistics
#>
#> Accuracy : 0.7423
#> 95% CI : (0.7263, 0.7579)
#> No Information Rate : 0.1843
#> P-Value [Acc > NIR] : < 0.00000000000000022
#>
#> Kappa : 0.6909
#>
#> Mcnemar's Test P-Value : 0.0000000001327
#>
#> Statistics by Class:
#>
#> Class: buildings Class: forest Class: glacier Class: mountain Class: sea Class: street
#> Sensitivity 0.7963 0.8819 0.6456 0.7257 0.7118 0.7186
#> Specificity 0.9224 0.9850 0.9559 0.9236 0.9357 0.9684
#> Pos Pred Value 0.6362 0.9167 0.7677 0.6684 0.6941 0.8200
#> Neg Pred Value 0.9637 0.9780 0.9227 0.9407 0.9407 0.9449
#> Prevalence 0.1457 0.1580 0.1843 0.1750 0.1700 0.1670
#> Detection Rate 0.1160 0.1393 0.1190 0.1270 0.1210 0.1200
#> Detection Prevalence 0.1823 0.1520 0.1550 0.1900 0.1743 0.1463
#> Balanced Accuracy 0.8593 0.9334 0.8007 0.8247 0.8238 0.8435
从混淆矩阵中可以看出,该模型很难区分每个类别。我们在验证数据集上获得了 74%的准确率。有 106 个街道图像被预测为建筑物,这超过了所有街道图像的 20%。这是有意义的,因为在许多街道图像中,建筑物也存在。
我们可以通过各种方式来提高模型的性能。但是现在,让我们通过简单地改变架构来改进它。
深度 CNN
现在我们用更多的卷积层制作一个更深的 CNN。这是它的架构:
- 块 1: 2 个卷积层和 1 个最大汇集层
- 块 2: 1 个卷积层和 1 个最大池层
- 块 3: 1 个卷积层和 1 个最大池层
- 块 4: 1 个卷积层和 1 个最大池层
- 展平图层
- 一个致密层
- 输出层
tensorflow::tf$random$set_seed(RS)
model_big <- keras_model_sequential(name = "model_big") %>%
# First convolutional layer
layer_conv_2d(filters = 32,
kernel_size = c(5,5), # 5 x 5 filters
padding = "same",
activation = "relu",
input_shape = c(target_size, 3)
) %>%
# Second convolutional layer
layer_conv_2d(filters = 32,
kernel_size = c(3,3), # 3 x 3 filters
padding = "same",
activation = "relu"
) %>%
# Max pooling layer
layer_max_pooling_2d(pool_size = c(2,2)) %>%
# Third convolutional layer
layer_conv_2d(filters = 64,
kernel_size = c(3,3),
padding = "same",
activation = "relu"
) %>%
# Max pooling layer
layer_max_pooling_2d(pool_size = c(2,2)) %>%
# Fourth convolutional layer
layer_conv_2d(filters = 128,
kernel_size = c(3,3),
padding = "same",
activation = "relu"
) %>%
# Max pooling layer
layer_max_pooling_2d(pool_size = c(2,2)) %>%
# Fifth convolutional layer
layer_conv_2d(filters = 256,
kernel_size = c(3,3),
padding = "same",
activation = "relu"
) %>%
# Max pooling layer
layer_max_pooling_2d(pool_size = c(2,2)) %>%
# Flattening layer
layer_flatten() %>%
# Dense layer
layer_dense(units = 64,
activation = "relu") %>%
# Output layer
layer_dense(name = "Output",
units = output_n,
activation = "softmax")
summary(model_big)#> Model: "model_big"
#> _________________________________________________________________
#> Layer (type) Output Shape Param #
#> =================================================================
#> conv2d_5 (Conv2D) (None, 150, 150, 32) 2432
#> _________________________________________________________________
#> conv2d_4 (Conv2D) (None, 150, 150, 32) 9248
#> _________________________________________________________________
#> max_pooling2d_4 (MaxPooling2D) (None, 75, 75, 32) 0
#> _________________________________________________________________
#> conv2d_3 (Conv2D) (None, 75, 75, 64) 18496
#> _________________________________________________________________
#> max_pooling2d_3 (MaxPooling2D) (None, 37, 37, 64) 0
#> _________________________________________________________________
#> conv2d_2 (Conv2D) (None, 37, 37, 128) 73856
#> _________________________________________________________________
#> max_pooling2d_2 (MaxPooling2D) (None, 18, 18, 128) 0
#> _________________________________________________________________
#> conv2d_1 (Conv2D) (None, 18, 18, 256) 295168
#> _________________________________________________________________
#> max_pooling2d_1 (MaxPooling2D) (None, 9, 9, 256) 0
#> _________________________________________________________________
#> flatten_1 (Flatten) (None, 20736) 0
#> _________________________________________________________________
#> dense_1 (Dense) (None, 64) 1327168
#> _________________________________________________________________
#> Output (Dense) (None, 6) 390
#> =================================================================
#> Total params: 1,726,758
#> Trainable params: 1,726,758
#> Non-trainable params: 0
#> _________________________________________________________________
剩下的和之前做的一样。
model_big %>%
compile(
loss = "categorical_crossentropy",
optimizer = optimizer_adam(lr = 0.001),
metrics = "accuracy"
)
history <- model_big %>%
fit_generator(
train_image_array_gen,
steps_per_epoch = as.integer(train_samples / batch_size),
epochs = 10,
validation_data = val_image_array_gen,
validation_steps = as.integer(valid_samples / batch_size)
)plot(history)
pred_test <- predict_classes(model_big, test_x)
pred_test <- sapply(pred_test, decode)
cm_big <- confusionMatrix(as.factor(pred_test), as.factor(val_data$class))
acc_big <- cm_big$overall['Accuracy']
cm_big#> Confusion Matrix and Statistics
#>
#> Reference
#> Prediction buildings forest glacier mountain sea street
#> buildings 390 3 24 24 11 34
#> forest 3 465 11 7 8 11
#> glacier 2 0 367 35 9 1
#> mountain 0 2 82 415 17 1
#> sea 3 1 57 42 461 6
#> street 39 3 12 2 4 448
#>
#> Overall Statistics
#>
#> Accuracy : 0.8487
#> 95% CI : (0.8353, 0.8613)
#> No Information Rate : 0.1843
#> P-Value [Acc > NIR] : < 0.00000000000000022
#>
#> Kappa : 0.8185
#>
#> Mcnemar's Test P-Value : < 0.00000000000000022
#>
#> Statistics by Class:
#>
#> Class: buildings Class: forest Class: glacier Class: mountain Class: sea Class: street
#> Sensitivity 0.8924 0.9810 0.6637 0.7905 0.9039 0.8942
#> Specificity 0.9625 0.9842 0.9808 0.9588 0.9562 0.9760
#> Pos Pred Value 0.8025 0.9208 0.8865 0.8027 0.8088 0.8819
#> Neg Pred Value 0.9813 0.9964 0.9281 0.9557 0.9798 0.9787
#> Prevalence 0.1457 0.1580 0.1843 0.1750 0.1700 0.1670
#> Detection Rate 0.1300 0.1550 0.1223 0.1383 0.1537 0.1493
#> Detection Prevalence 0.1620 0.1683 0.1380 0.1723 0.1900 0.1693
#> Balanced Accuracy 0.9275 0.9826 0.8222 0.8746 0.9301 0.9351
这个结果总体上比之前的model
要好,因为model_big
更复杂,因此能够捕捉更多的特征。我们在验证数据集上获得了 85%的准确率。虽然对街道图像的预测已经变得更好,但对冰川图像的预测仍然存在。
预训练权重的深度 CNN
实际上,研究人员已经为图像分类问题开发了许多模型,从 VGG 模型家族到谷歌开发的最新艺术级 EfficientNet。出于学习目的,在本节中,我们将使用 VGG16 模型,因为它是所有模型中最简单的模型之一,仅由卷积层、最大池层和密集层组成,如我们之前介绍的那样。这个过程叫做迁移学习,将预先训练好的模型的知识进行迁移,来解决我们的问题。
最初的 VGG16 模型是在 1000 个类上训练的。为了使它适合我们的问题,我们将排除模型的顶部(密集)层,并插入我们版本的预测层,该预测层由一个全局平均池层(作为扁平化层的替代)、一个具有 64 个节点的密集层和一个具有 6 个节点的输出层(用于 6 个类)组成。
我们来看看整体架构。
# load original model without top layers
input_tensor <- layer_input(shape = c(target_size, 3))
base_model <- application_vgg16(input_tensor = input_tensor,
weights = 'imagenet',
include_top = FALSE)
# add our custom layers
predictions <- base_model$output %>%
layer_global_average_pooling_2d() %>%
layer_dense(units = 64, activation = 'relu') %>%
layer_dense(units = output_n, activation = 'softmax')
# this is the model we will train
vgg16 <- keras_model(inputs = base_model$input, outputs = predictions)
summary(vgg16)#> Model: "model"
#> _________________________________________________________________
#> Layer (type) Output Shape Param #
#> =================================================================
#> input_1 (InputLayer) [(None, 150, 150, 3)] 0
#> _________________________________________________________________
#> block1_conv1 (Conv2D) (None, 150, 150, 64) 1792
#> _________________________________________________________________
#> block1_conv2 (Conv2D) (None, 150, 150, 64) 36928
#> _________________________________________________________________
#> block1_pool (MaxPooling2D) (None, 75, 75, 64) 0
#> _________________________________________________________________
#> block2_conv1 (Conv2D) (None, 75, 75, 128) 73856
#> _________________________________________________________________
#> block2_conv2 (Conv2D) (None, 75, 75, 128) 147584
#> _________________________________________________________________
#> block2_pool (MaxPooling2D) (None, 37, 37, 128) 0
#> _________________________________________________________________
#> block3_conv1 (Conv2D) (None, 37, 37, 256) 295168
#> _________________________________________________________________
#> block3_conv2 (Conv2D) (None, 37, 37, 256) 590080
#> _________________________________________________________________
#> block3_conv3 (Conv2D) (None, 37, 37, 256) 590080
#> _________________________________________________________________
#> block3_pool (MaxPooling2D) (None, 18, 18, 256) 0
#> _________________________________________________________________
#> block4_conv1 (Conv2D) (None, 18, 18, 512) 1180160
#> _________________________________________________________________
#> block4_conv2 (Conv2D) (None, 18, 18, 512) 2359808
#> _________________________________________________________________
#> block4_conv3 (Conv2D) (None, 18, 18, 512) 2359808
#> _________________________________________________________________
#> block4_pool (MaxPooling2D) (None, 9, 9, 512) 0
#> _________________________________________________________________
#> block5_conv1 (Conv2D) (None, 9, 9, 512) 2359808
#> _________________________________________________________________
#> block5_conv2 (Conv2D) (None, 9, 9, 512) 2359808
#> _________________________________________________________________
#> block5_conv3 (Conv2D) (None, 9, 9, 512) 2359808
#> _________________________________________________________________
#> block5_pool (MaxPooling2D) (None, 4, 4, 512) 0
#> _________________________________________________________________
#> global_average_pooling2d (GlobalAveragePooling2D) (None, 512) 0
#> _________________________________________________________________
#> dense_3 (Dense) (None, 64) 32832
#> _________________________________________________________________
#> dense_2 (Dense) (None, 6) 390
#> =================================================================
#> Total params: 14,747,910
#> Trainable params: 14,747,910
#> Non-trainable params: 0
#> _________________________________________________________________
哇,这么多层次啊!我们可以直接使用vgg16
进行训练和预测,但同样,出于学习的目的,让我们自己从头开始制作 VGG16 模型。
model_bigger <- keras_model_sequential(name = "model_bigger") %>%
# Block 1
layer_conv_2d(filters = 64,
kernel_size = c(3, 3),
activation='relu',
padding='same',
input_shape = c(94, 94, 3),
name='block1_conv1') %>%
layer_conv_2d(filters = 64,
kernel_size = c(3, 3),
activation='relu',
padding='same',
name='block1_conv2') %>%
layer_max_pooling_2d(pool_size = c(2, 2),
strides=c(2, 2),
name='block1_pool') %>%
# Block 2
layer_conv_2d(filters = 128,
kernel_size = c(3, 3),
activation='relu',
padding='same',
name='block2_conv1') %>%
layer_conv_2d(filters = 128,
kernel_size = c(3, 3),
activation='relu',
padding='same',
name='block2_conv2') %>%
layer_max_pooling_2d(pool_size = c(2, 2),
strides=c(2, 2),
name='block2_pool') %>%
# Block 3
layer_conv_2d(filters = 256,
kernel_size = c(3, 3),
activation='relu',
padding='same',
name='block3_conv1') %>%
layer_conv_2d(filters = 256,
kernel_size = c(3, 3),
activation='relu',
padding='same',
name='block3_conv2') %>%
layer_conv_2d(filters = 256,
kernel_size = c(3, 3),
activation='relu',
padding='same',
name='block3_conv3') %>%
layer_max_pooling_2d(pool_size = c(2, 2),
strides=c(2, 2),
name='block3_pool') %>%
# Block 4
layer_conv_2d(filters = 512,
kernel_size = c(3, 3),
activation='relu',
padding='same',
name='block4_conv1') %>%
layer_conv_2d(filters = 512,
kernel_size = c(3, 3),
activation='relu',
padding='same',
name='block4_conv2') %>%
layer_conv_2d(filters = 512,
kernel_size = c(3, 3),
activation='relu',
padding='same',
name='block4_conv3') %>%
layer_max_pooling_2d(pool_size = c(2, 2),
strides=c(2, 2),
name='block4_pool') %>%
# Block 5
layer_conv_2d(filters = 512,
kernel_size = c(3, 3),
activation='relu',
padding='same',
name='block5_conv1') %>%
layer_conv_2d(filters = 512,
kernel_size = c(3, 3),
activation='relu',
padding='same',
name='block5_conv2') %>%
layer_conv_2d(filters = 512,
kernel_size = c(3, 3),
activation='relu',
padding='same',
name='block5_conv3') %>%
layer_max_pooling_2d(pool_size = c(2, 2),
strides=c(2, 2),
name='block5_pool') %>%
# Dense
layer_global_average_pooling_2d() %>%
layer_dense(units = 64, activation = 'relu') %>%
layer_dense(units = output_n, activation = 'softmax')
model_bigger#> Model
#> Model: "model_bigger"
#> _________________________________________________________________
#> Layer (type) Output Shape Param #
#> =================================================================
#> block1_conv1 (Conv2D) (None, 94, 94, 64) 1792
#> _________________________________________________________________
#> block1_conv2 (Conv2D) (None, 94, 94, 64) 36928
#> _________________________________________________________________
#> block1_pool (MaxPooling2D) (None, 47, 47, 64) 0
#> _________________________________________________________________
#> block2_conv1 (Conv2D) (None, 47, 47, 128) 73856
#> _________________________________________________________________
#> block2_conv2 (Conv2D) (None, 47, 47, 128) 147584
#> _________________________________________________________________
#> block2_pool (MaxPooling2D) (None, 23, 23, 128) 0
#> _________________________________________________________________
#> block3_conv1 (Conv2D) (None, 23, 23, 256) 295168
#> _________________________________________________________________
#> block3_conv2 (Conv2D) (None, 23, 23, 256) 590080
#> _________________________________________________________________
#> block3_conv3 (Conv2D) (None, 23, 23, 256) 590080
#> _________________________________________________________________
#> block3_pool (MaxPooling2D) (None, 11, 11, 256) 0
#> _________________________________________________________________
#> block4_conv1 (Conv2D) (None, 11, 11, 512) 1180160
#> _________________________________________________________________
#> block4_conv2 (Conv2D) (None, 11, 11, 512) 2359808
#> _________________________________________________________________
#> block4_conv3 (Conv2D) (None, 11, 11, 512) 2359808
#> _________________________________________________________________
#> block4_pool (MaxPooling2D) (None, 5, 5, 512) 0
#> _________________________________________________________________
#> block5_conv1 (Conv2D) (None, 5, 5, 512) 2359808
#> _________________________________________________________________
#> block5_conv2 (Conv2D) (None, 5, 5, 512) 2359808
#> _________________________________________________________________
#> block5_conv3 (Conv2D) (None, 5, 5, 512) 2359808
#> _________________________________________________________________
#> block5_pool (MaxPooling2D) (None, 2, 2, 512) 0
#> _________________________________________________________________
#> global_average_pooling2d_1 (GlobalAveragePooling2D) (None, 512) 0
#> _________________________________________________________________
#> dense_5 (Dense) (None, 64) 32832
#> _________________________________________________________________
#> dense_4 (Dense) (None, 6) 390
#> =================================================================
#> Total params: 14,747,910
#> Trainable params: 14,747,910
#> Non-trainable params: 0
#> _________________________________________________________________
注意model_bigger
与vgg16
每层的参数数量完全相同。迁移学习的优势在于,我们不必从随机权重开始训练模型,而是从原始模型的预训练权重开始。这些预先训练的权重已经针对图像分类问题进行了优化,我们只需要对它们进行微调以符合我们的目的。因此有了这个比喻:
我们正站在巨人的肩膀上。
话虽如此,我们还是把vgg16
的权重全部赋给model_bigger
吧。
set_weights(model_bigger, get_weights(vgg16))
这里是我们的model_bigger
层的总结:
layers <- model_bigger$layers
for (i in 1:length(layers))
cat(i, layers[[i]]$name, "\n")#> 1 block1_conv1
#> 2 block1_conv2
#> 3 block1_pool
#> 4 block2_conv1
#> 5 block2_conv2
#> 6 block2_pool
#> 7 block3_conv1
#> 8 block3_conv2
#> 9 block3_conv3
#> 10 block3_pool
#> 11 block4_conv1
#> 12 block4_conv2
#> 13 block4_conv3
#> 14 block4_pool
#> 15 block5_conv1
#> 16 block5_conv2
#> 17 block5_conv3
#> 18 block5_pool
#> 19 global_average_pooling2d_1
#> 20 dense_5
#> 21 dense_4
请注意,第 19-21 层仍然具有随机权重,因为它们是由我们创建的,而不是来自原始模型。因此,我们需要先冻结所有层,然后只训练这些层。
freeze_weights(model_bigger, from = 1, to = 18)
为了训练这些预测层,我们将简单地使用先前的设置。
# compile the model (should be done *after* setting base layers to non-trainable)
model_bigger %>% compile(loss = "categorical_crossentropy",
optimizer = optimizer_adam(lr = 0.001),
metrics = "accuracy")
history <- model_bigger %>%
fit_generator(
train_image_array_gen,
steps_per_epoch = as.integer(train_samples / batch_size),
epochs = 10,
validation_data = val_image_array_gen,
validation_steps = as.integer(valid_samples / batch_size)
)
现在,微调模型。要做到这一点,我们应该对优化器应用一个低的学习率,这样就不会打乱预先训练好的权重。我们将使用 0.00001 的学习率。此外,为了节省时间,我们只训练 4 个时期的模型。
在微调之前,不要忘记解冻要训练的层。在我们的例子中,我们将解冻所有层。
unfreeze_weights(model_bigger)
# compile again with low learning rate
model_bigger %>% compile(loss = "categorical_crossentropy",
optimizer = optimizer_adam(lr = 0.00001),
metrics = "accuracy")
history <- model_bigger %>%
fit_generator(
train_image_array_gen,
steps_per_epoch = as.integer(train_samples / batch_size),
epochs = 4,
validation_data = val_image_array_gen,
validation_steps = as.integer(valid_samples / batch_size)
)plot(history)
pred_test <- predict_classes(model_bigger, test_x)
pred_test <- sapply(pred_test, decode)
cm_bigger <- confusionMatrix(as.factor(pred_test), as.factor(val_data$class))
acc_bigger <- cm_bigger$overall['Accuracy']
cm_bigger#> Confusion Matrix and Statistics
#>
#> Reference
#> Prediction buildings forest glacier mountain sea street
#> buildings 396 0 2 1 2 13
#> forest 1 469 2 2 4 0
#> glacier 1 2 479 61 5 0
#> mountain 0 0 50 452 4 0
#> sea 1 1 16 7 492 2
#> street 38 2 4 2 3 486
#>
#> Overall Statistics
#>
#> Accuracy : 0.9247
#> 95% CI : (0.9146, 0.9339)
#> No Information Rate : 0.1843
#> P-Value [Acc > NIR] : < 0.0000000000000002
#>
#> Kappa : 0.9095
#>
#> Mcnemar's Test P-Value : 0.00281
#>
#> Statistics by Class:
#>
#> Class: buildings Class: forest Class: glacier Class: mountain Class: sea Class: street
#> Sensitivity 0.9062 0.9895 0.8662 0.8610 0.9647 0.9701
#> Specificity 0.9930 0.9964 0.9718 0.9782 0.9892 0.9804
#> Pos Pred Value 0.9565 0.9812 0.8741 0.8933 0.9480 0.9084
#> Neg Pred Value 0.9841 0.9980 0.9698 0.9707 0.9927 0.9939
#> Prevalence 0.1457 0.1580 0.1843 0.1750 0.1700 0.1670
#> Detection Rate 0.1320 0.1563 0.1597 0.1507 0.1640 0.1620
#> Detection Prevalence 0.1380 0.1593 0.1827 0.1687 0.1730 0.1783
#> Balanced Accuracy 0.9496 0.9929 0.9190 0.9196 0.9769 0.9752
我们已经找到了赢家。model_bigger
在验证数据集上有 92%的准确率!尽管如此,还是有一些错误的分类,因为没有模型是完美的。以下是预测的摘要:
- 有些建筑被误预测为街道,反之亦然。再次,这是由于一些建筑物的图像也包含街道,这使模型混淆。
- 森林预测几乎是完美的。
- 许多冰川被预测为山脉和海洋,也有许多山脉被预测为冰川。这可能来自冰川、山脉和海洋图像的相同蓝色。
- 海上的好预测。
结论
rbind(
"Simple CNN" = acc_simple,
"Deeper CNN" = acc_big,
"Fine-tuned VGG16" = acc_bigger
)#> Accuracy
#> Simple CNN 0.7423333
#> Deeper CNN 0.8486667
#> Fine-tuned VGG16 0.9246667
我们已经成功地用 6 个类别进行了图像分类:“建筑物”、“森林”、“冰川”、“山”、“海”和“街道”。由于图像是非结构化数据,这个问题可以通过使用神经网络的机器学习来解决,神经网络在没有人工干预的情况下自动进行特征提取。为了获得更好的性能,我们使用卷积神经网络来实现这一点,并继续使用密集层进行预测。最后,我们使用 VGG16 模型和 IMAGENET 权重初始化,达到 92%的准确率。
使用图像分类,拥有大型可视化数据库网站的公司可以轻松地组织和分类他们的数据库,因为它允许对大量图像进行自动分类。这有助于他们将视觉内容货币化,而无需投入大量时间进行手动分类和标记。
🔥你好!如果你喜欢这个故事,想支持我这个作家,可以考虑 成为会员 。每月只需 5 美元,你就可以无限制地阅读媒体上的所有报道。如果你注册使用我的链接,我会赚一小笔佣金。
🔖想了解更多关于经典机器学习模型如何工作以及如何优化其参数的信息?或者 MLOps 大型项目的例子?有史以来最优秀的文章呢?继续阅读:
艾伯斯·乌兹拉
从零开始的机器学习
View list8 stories
艾伯斯乌兹拉
高级优化方法
View list7 stories
艾伯斯乌兹拉
MLOps 大型项目
View list6 stories
艾伯斯乌兹拉
我最好的故事
View list24 stories
艾伯斯·乌兹拉
R 中的数据科学
View list7 stories