TowardsDataScience-博客中文翻译-2021-六十二-

TowardsDataScience 博客中文翻译 2021(六十二)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

磁铁:使用深度神经网络的现代艺术生成器

原文:https://towardsdatascience.com/magnet-modern-art-generator-using-deep-neural-networks-57537457bb7?source=collection_archive---------8-----------------------

实践教程

我如何使用 CLIP、SWAGAN 和自定义遗传算法从文本描述中创建现代绘画

磁体输出样本,图片作者

我最新的利用人工智能进行创造性努力的项目叫做磁铁。我构建了一个定制的遗传算法(GA ),通过几代人的文本描述,使用生成性对抗网络(GAN)来驱动现代绘画的创作。MAGnet 使用 OpenAI 的 CLIP 模型[1]和 Nvidia 的 StyleGAN2 ADA [2]的变体 SWAGAN [3],后者使用小波来创建图像。

这个项目的所有源代码都可以在这里找到。这里有一个谷歌实验室,你可以用它来创作你自己的画。

先前的工作

一个名为 CLIP-GLaSS 的类似系统于 2021 年早些时候发布。在他们的论文“通过剪辑引导的生成潜在空间搜索从字幕生成图像,反之亦然”4中,Federico Galatolo 等人建立了一个图像生成系统,该系统使用 StyleGAN2、CLIP 和一个称为 NSGA-II 的 GA[5]。作者在他们的 Google Colab 这里提供了这个系统。

以下是经过 50 代之后,来自查询“有白色尖塔的教堂”的 CLIP-GLaSS 的顶级结果。

由 CLIP-GLaSS 使用提示“有白色尖塔的教堂”生成的图像,由作者提供

该系统似乎工作得相当好,但图像有点小,为 256 x 256 像素。许多源图像似乎来自库存视频网站 Shutterstock。请注意 GAN 是如何在每个图像中重新创建 Shutterstock 水印的。

磁铁概述

以下是 MAGnet 中使用的组件的简要概述。我将在本文的后面详细介绍每个组件。请注意,使用 WikiArt 中的图像收集、过滤和训练 GAN 的步骤类似于我的 GANscapes 项目,该项目生成印象派风景画。

下图显示了 MAGnet 的主要系统组件。

磁铁组件,作者提供的图表

我从 WikiArt.org[6]那里收集了一些现代绘画的图像,并对这些图像进行处理,从中提取出一幅或多幅方形图像。然后,我使用剪辑模型来过滤图像,以保留 1 万张与“现代绘画”最匹配的图像

我用这些图像来训练 SWAGAN,它有一个生成器和鉴别器网络。生成器从形式和风格的随机“潜在”向量开始创建新图像,并试图欺骗鉴别器,使其认为输出的图像是真实的。在将真实图像和生成的图像输入鉴别器之前,会使用自适应鉴别器增强(ADA)模块对其进行轻微修改,从而在图片中创建视觉多样性。

我再次使用 CLIP 作为我的 GA 的一部分,来引导 SWAGAN 在指定数量的代上创建一个与用户提供的文本描述最匹配的图像。作为最后一步,我对最终图像进行了后期处理,进行了温和的对比度调整,并以全尺寸显示了结果。

查看文章末尾附录中的图片集,了解更多来自 MAGnet 的结果。

磁体系统详情

这一节将更详细地讨论我用来构建 MAGnet 的过程和系统。

收集图像

我开始用自定义的 python 脚本从 WikiArt.org 搜集现代绘画。该脚本按字母顺序遍历网站上的每个艺术家。它检查艺术家是否被标记为“现代”艺术运动的一部分,以及他们是否生于 1800 年之后,死于 1950 年之前。然后,脚本遍历所有艺术家的画作,寻找公共领域中可用的作品。然后,脚本使用艺术家和绘画名称作为文件名下载每个符合条件的图像,即 Henri-Matisse _ still-life-with-fruit-1896 . jpg。系统找到了大约 4,000 幅符合这些标准的绘画。请注意,我使用 Python 中的 ThreadPoolExecutor 通过 8 个并行线程来收集图像,以加快处理速度。

这是一个符合标准的图片样本。

来自 Wikart.org 的现代绘画样本,由维尔莫斯·阿巴和文森佐·阿巴蒂拍摄

注意“现代”这个词相当宽泛,所以剧本既收集了抽象绘画也收集了具象绘画。

拉动正方形图像进行训练

gan 可以有效地处理像素大小为 2 的幂的正方形图像,例如 256 x 256、512 x 512、1024 x 1024 等。对于磁铁,我决定使用大小为 512 x 512 的图像。因为源绘画有各种纵横比,所以我选择从每个图像中提取三个剪切部分。

例如,亨利·马蒂斯的画《水果静物》就有一个横向方向。这是三个剪影,分别展示了这幅画的左、中和右部分。

亨利·马蒂斯用三种方式修剪水果的静物,图片来源于 Wikiart.org

第二个例子是毕加索的丑角。肖像被裁剪为顶部、中间和底部。

巴勃罗·毕卡索的《丑角剪成三样》,图片来源于 Wikiart.org

剪短的丑角似乎是最好的,因为脸是完整的。然而,在训练 GAN 时使用所有三种剪裁是可以的,因为我稍后将使用 CLIP 来过滤和指导“好”绘画的生成。

处理训练图像的源代码在这里的实验室

使用 CLIP 对训练图像进行过滤

裁剪完图像后,我最终拥有了 12,000 多幅作品。这足以训练一个甘,但并不是所有的画都是好的。仅仅因为一个画家在 WikiArt 上被标记为“现代”,并不意味着他们所有的作品都是现代绘画的好例子。我使用 CLIP 来过滤图像,就像我在 GANscapes 项目中筛选数据集一样。

OpenAI 为 CLIP 设计了两个模型,一个图像和文本编码器,来执行语义搜索。他们在带有相应短语的图像数据集上训练这两个模型。模型的目标是使编码图像与编码短语相匹配。

一旦经过训练,图像编码器系统将图像转换为嵌入,即捕获图像一般特征的 512 个浮点数的列表。文本编码器将文本短语转换为相似的嵌入,该嵌入可以与图像嵌入进行比较以进行语义搜索。

对于 MAGnet,我将短语“现代绘画”中的嵌入内容与绘画中的嵌入内容进行比较,以找到与该短语最匹配的前 10,000 幅图像。源代码在这里的 Colab 里。

这里有一些不符合现代绘画的例子。前两个大概得分比较低,因为没有太多对比。第三张看起来更像一张素描,而不是一幅油画。

Wikiart.org 来源:克里斯托夫·伍德的《海港中的船》,阿尔弗雷德·威廉·芬奇的《静物》,洛克威尔·肯特的《给凯瑟琳·布拉什的插图》

斯瓦甘

对于这个项目,我使用的是 StyleGAN2 的一个变种,叫做 SWAGAN。它是由特拉维夫大学的 Rinon Gal 等人发明的。这个新模型在他们的 SWAGAN 中有描述:一个基于风格的小波驱动的生成模型[3]。以下是对他们方法的描述。

…我们提出了一种新颖的通用样式和基于小波的 GAN (SWAGAN ),它在频域中实现渐进生成。SWAGAN 在其生成器和鉴频器架构中融入了小波,在每一步都加强了频率感知的潜在表示。这种方法提高了生成图像的视觉质量,并显著提高了计算性能。-里农·加尔等人。

小波是一种类似波浪的振荡,其振幅从零开始,增加,然后减小回到零。小波的研究是基于匈牙利数学家阿尔夫雷德·哈尔的工作。该论文的作者表明,通过采用 GAN 架构直接在基于小波的空间中工作,他们在高频范围内实现了更高的视觉质量和更真实的内容[3]。

下面是论文中 StyleGAN2 和 SWAGAN 的输出比较。

style gan 2 和 SWAGAN 的比较,摘自 Rinon Gal 等人的 SWAGAN 论文

作者指出,插值的 StyleGAN2 图像在高频区域(如头发)周围显示出相当大的模糊,而 SWAGAN 图像则没有。

训练营地

我用这个 Google colab 训练了这个系统两周。下面是运行培训的命令。

**python /content/stylegan2-pytorch/train.py --data_dir /content/drive/MyDrive/modern_results/ --augment --arch swagan 
--size 512 /content/drive/MyDrive/modern_art_processed_512/**

注意,架构设置为 SWAGAN(另一个选择是 StyleGAN2)。你可以在这里看到一些未经过滤的结果。

SWAGAN 接受现代绘画训练的样本结果,图片由作者提供

你可以看到抽象和具象图像的有趣结合。这些代表性的图像似乎从印象派到立体派都有。而且有很好的调色板组合。

甘实施注意事项

我正在使用的 SWAGAN 版本是由独立开发者 Seonghyeon Kim 编写的,在 GitHub 上被称为 rosinality 。他实现了 StyleGAN2 和 SWAGAN 在这里

rosinality 的大部分源代码都是在 MIT 开源许可下发布的,这是非常宽松的。但是,他的代码包括两个操作,fixed_act()和 upfirdn2d(),写成低级 CUDA 函数。这些功能由 Nvidia 编写,并在他们的非商业开源许可下发布。Nvidia 许可证声明源代码可以非商业使用,这意味着它只能用于研究或评估目的。

在 GitHub 上搜索后,我找到了 fixed_act()和 upfirdn2d()函数的副本,它们是由或 Patashnik 等人在 MIT 开源许可下为他们的 StyleCLIP 项目重新实现和发布的[7]。它们的函数与 rosinality 的 SWAGAN 实现配合得很好。你可以在我的 GitHub 项目这里找到合并后的代码。我在许可的 CC-BY-SA-4.0 许可下发布源代码。是的,你可以将我的源代码用于商业目的💲💲💲。但是如果你用的话,请告诉我一声。📣

遗传算法

在计算机科学中,遗传算法(GA)是一种受自然选择过程启发的元启发式算法,它依赖于生物启发的操作符,如突变、交叉和选择。遗传算法通常用于生成高质量优化和搜索问题的解决方案[8]。你可以在 Vijini Mallawaarachchi 关于介质的文章中读到更多关于气体的内容。

我创建了一个定制的 GA,它使用 CLIP 来引导 SWAGAN 生成与用户给出的文本描述相匹配的图像。以下是该算法的概述。

为每一代生成初始种群
:
选择-选择前 4 个匹配图像
交叉-将每个图像与其他图像交叉
变异-给潜在向量添加一点噪声

这是遗传算法的 Pythonish 伪代码:

**# get the features from the text query using CLIP** text_query = 'an abstract painting with orange triangles'
query_features = clip.encode_text(text_query)**# get an initial population of images, i.e. 200** latents = random(num_initial_samples)**# run the genetic algorithm for some number of steps, i.e. 5 times** for g in range(num_generations): **# generate the images**  images = swagan.generate_images(latents) **# get the image features using CLIP and rank them to get the top 4**  image_features = clip.encode_image(images)
  ranked_indices = get_top_N_(query_features, image_features, 4) **# start with a blank slate**  new_latents = empty_set **# copy the best four latents (A, B, C, D)**  for i in range(4):
    offspring = latents[ranked_indices[i]]
    new_latents.append(offspring) **# loop through all 16 combinations**  for j in range(4):
    for i in range(4): **# combine i with j**      offspring = (1-recombination_amount) * new_latents[i] +  
         recombination_amount * new_latents[j] **# add a little mutation**      offspring += random() * mutation_amount

      **# add it to the batch**
      new_latents.append(offspring) **# use the new latents**  latents = new_latents

好,让我们用一个真实的例子来看看这是如何工作的。

参数是这样设置的:
text_query = '一幅带有橙色三角形的抽象画'
num _ initial _ samples = 200
recombination _ amount = 0.333
mutation _ amount = 0.25
num _ generations = 5

生成 200 张图片后,这里是匹配查询的前四张图片。

与“一幅带有橙色三角形的抽象画”相匹配的前 4 张图片作者提供的图片

这些图像明确显示了许多橙色,并且可以看到一些三角形。这是第一代产品。字母“x”表示交叉,符号‘表示突变。

来自磁铁的第一代图片,图片作者

原来的四个图像在最上面,有突变的组合在下面。该系统将查看所有 20 个图像(原始的 4 个加上 16 个组合),并使用 CLIP 来确定下一代的前 4 个。

我运行了五代遗传算法。如果你好奇,你可以在这里看到所有的中间结果。下面是最终结果。

作者提供的“带有橙色三角形的抽象画”的磁铁结果

还不错!您可以看到,最终结果主要基于最初的前两张图像,但系统在运行遗传算法的过程中设法找到了一些额外的橙色三角形。

接下来,我将分享我开发的一项技术,该技术可以在使用天然气和天然气水合物时改善结果。

GANs 的交叉技术

在遗传算法的文献[8]中,用于交叉操作的技术描述如下:
1。从 0 到向量长度
2 之间选择一个随机的“交叉点”。将值从第一个父节点复制到交叉点
3。从交叉点开始,复制第二个父节点的值

例如,如果向量中有 10 个数字,重组量为 40%,如果 A 向量设置为全 1,B 向量设置为全 0,则后代看起来会是这样。交叉点用粗线表示。

传统交叉方法,图片由作者提供

您可以看到,A 中的前六个值被复制到 AxB 后代中,接下来的四个值被复制到 b 中。BxA 后代具有来自父代的反向贡献。

下面是传统交叉方法的 Python 代码:

**offspring = empty(vector_length)
crossover_point = int(vector_length * recombination_amount)
offspring_axb[crossover_point:] = a[crossover_point:] 
offspring_bxa[:crossover_point] = b[:crossover_point]**

尽管这种方法大致是基于它在生物学中的工作方式,但我发现它并不是处理 GANs 的最佳技术。例如,下面是两个最佳图像的混合,这两个图像符合使用传统交叉技术的“带有红色方块的抽象画”的描述。

传统交叉方法,图片由作者提供

第一个图像是父图像 A,最后一个图像是父图像 B,中间的三个图像是使用传统的交叉方法在两个父图像之间逐渐混合的。请注意,父母之间会有一些奇怪的变化。

对于磁铁,我在混合的两个父向量之间使用线性插值。这是向量之间的简单加权平均。下面是使用线性交叉方法得到的相同父图像的样子。

线性交叉方法,图片作者

这似乎是一种更好的交叉方法,因为所有的后代似乎都是带有红色方块的抽象画的变体,而传统的交叉方法似乎遍历了一些不是抽象画的图像。

回到 A 向量被设置为全 1 且 B 向量被设置为全 0 的示例,线性交叉方法通过重组量及其倒数来混合后代中的每个数字。

传统交叉方法,图片由作者提供

可以看到,AxB 后代中的每个值分别是 A 和 B 父代的 60/40 混合,BxA 后代是 40/60 混合。

这是线性交叉方法的代码。

**offspring = (1-recombination_amount) * a + recombination_amount * b**

对最终图像进行后处理

类似于我的 GANscapes 项目中的图像后处理,我提高了最终图像的对比度,就像 Photoshop 中的自动色阶功能一样。这是对比度调整前后的示例图像。

对比调整前后,图片作者

您可以看到对比度调整是如何“放大”颜色的。Python 中调整图像对比度的源代码是这里是

结果

以下是用各种文本查询运行 MAGnet 的一些结果。请务必查看附录,了解更多结果。

磁铁渲染的“一幅画着圆圈的抽象画”,作者的图片

磁铁效果图“一幅风景画”,作者图片

磁铁渲染的“一幅立体派油画”,作者图片

讨论和未来工作

磁铁系统工作得相当好。它似乎在生成抽象画方面比具象画做得更好。它收敛于一个解决方案相当快,在五代之内。

虽然 MAGnet 的效果相当不错,但是如果你玩它,你可能会偶尔看到相同的视觉主题。这可能是由于训练期间使用的源图像数量有限(大约 4,000 个初始图像,通过裁剪增加到 12,000 个以上,并过滤到 10,000 个)。用更多的图像进行训练可能会减少重复视觉主题的频率。

另一个可以改进的地方是图像中的纹理。在平坦区域似乎有一些“计算机化”的人工制品。这可能是因为重新实施了 CUDA 业务。

我注意到 rosinality 目前正在 GitHub 上开发一个新的开源项目,名为 alias-free-gan-pytorch 。听起来很有希望!

源代码

这个项目的所有源代码都可以在 GitHub 上获得。源代码在 CC BY-SA 许可下发布。

归属共享相似

感谢

我要感谢詹尼弗·林和奥利弗·斯特瑞普对本文的帮助。

参考

[1] A .拉德福德,J. W .金,c .哈勒西,a .拉梅什,g .高,s .阿加瓦尔,g .萨斯特里,a .阿斯克尔,p .米什金,j .克拉克等人,从自然语言监督中学习可转移视觉模型 (2021)

[2] T. Karras,M. Aittala,J. Hellsten,S. Laine,J. Lehtinen,T. Aila,“用有限的数据训练生成性对抗网络”,【https://arxiv.org/pdf/2006.06676.pdf】T4(2020)

[3] R. Gal、D. Cohen、A. Bermano 和 D. Cohen-Or,“SWAGAN:一种基于风格的小波驱动的生成模型”,https://arxiv.org/pdf/2102.06108.pdf(2021)

4 F.A .加拉托洛、M.G.C.A .西米诺和 G .瓦格利尼,“通过剪辑引导的生成潜在空间搜索从字幕生成图像,反之亦然”,https://arxiv.org/pdf/2102.01645.pdf,(2021)

[5] K. Deb,k .,A. Pratap,S. Agarwal 和 T. Meyarivan,“一种快速的精英多目标遗传算法:Nsga-ii。”,《IEEE 进化计算汇刊》,(2002)

[6]维基百科,https://www.wikiart.org(2008 年至 2021 年)

[7] O. Patashnik,Z.Wu,E. Shechtman,D.Cohen-Or,Dani Lischinski《风格剪辑:文本驱动的风格意象操纵》,(2021)

[8] M.Mitchell,遗传算法简介。麻省剑桥:麻省理工学院出版社。(1996)

附录—磁铁图片集

这是一个由 MAGnet 创建的图像样本。你可以点击每张图片查看大图。

磁体的样本结果,图片由作者提供

这里是我的一位评论者 Oliver Strimpel 建议的更多文本查询的例子。

磁铁渲染的“工业荒地”,图片作者

磁铁渲染的“起伏的农田”,图片作者

磁铁渲染的“传统欧洲景观”,作者图片

磁铁渲染的《惊涛骇浪》,作者图片

磁铁效果图《宁静的海边之画》,作者图片

磁铁渲染的“点彩风格的湖”,作者图片

为了无限制地访问 Medium 上的所有文章,成为了的会员,每月 5 美元。非会员每月只能看三个锁定的故事。

美国职业足球大联盟分析的现状

原文:https://towardsdatascience.com/major-league-soccer-analytics-9fc76891c440?source=collection_archive---------31-----------------------

作者图片

目标:

在此分析中,目标是检查美国职业足球大联盟(MLS)的当前分析状态。俱乐部如何构建他们的分析部门,什么样的职位需要数据相关的任务。大部分美国职业棒球大联盟的特许经营权遵循的文化是在俱乐部的业务方面成为数据驱动的决策者。然而,越来越多的俱乐部在体育方面的决策中使用数据。这份报告的重点是从足球运营的角度。凭借在 MLS 超过四年的分析经验,我想分析联盟内的分析现状。我试图回答的问题如下:

  • 每个团队目前的人员配备情况如何?具体来说,我们只关注与数据相关的职位。
  • 东部联盟和西部联盟在人员配备上有区别吗?
  • 足球运营中不同部门的数据是如何流动的?

作者图片

方法:

数据收集:第一步是收集数据以进行分析。我自己从每个俱乐部的网站和通过我在 MLS 分析社区的联系人收集数据。注意:迈阿密 FC 过去没有发布任何关于他们分析人员的信息。我不得不使用 LinkedIn 和其他平台自己做一些研究。

变量:下面是数据集中所有变量的列表。我还解释了所有的变量,以及一个人要成为那个特定角色的成功候选人需要什么样的技能。

球队:分析包括所有参加过 2020 MLS 赛季的球队。

  • 亚特兰大联队
  • 芝加哥大火
  • 科罗拉多急流
  • 哥伦布船员
  • 华盛顿联合航空公司
  • 辛辛那提足球俱乐部
  • 达拉斯足球俱乐部
  • 休斯顿迪纳摩
  • 洛杉矶足球俱乐部
  • 洛杉矶银河
  • 迈阿密 CF
  • 明尼苏达联合队
  • 蒙特利尔影响
  • 南卡罗来纳州纳什维尔
  • 新英格兰革命
  • 纽约市足球俱乐部
  • 纽约红牛队
  • 奥兰多市 SC
  • 费城联盟
  • 波特兰木材公司
  • 真正的盐湖
  • 圣何塞地震
  • 西雅图海湾者
  • 堪萨斯城体育
  • 多伦多足球俱乐部
  • 温哥华白浪

体育表演科学负责人:需要有很强的分析能力。评估受伤运动员的状况时,绩效科学家需要观察受伤情况,并正确分析和解释数据,以确定其程度。

运动科学家/表现专员:需要有很强的分析能力,收集和提取数据。体育科学家负责监控运动员的表现,跟踪身体数据,以评估疲劳程度,防止受伤。除了技术和分析技能,他们还需要领导和发展健身训练计划。

足球分析/数据科学总监:需要收集和处理数据进行分析。足球分析总监负责将分析和数据科学整合到俱乐部的每个足球方面,包括对手分析、国内和国际球员招募以及表现预测。通常管理绩效分析师和数据分析师。

绩效分析师:需要有很强的分析能力。性能分析师负责赛前和赛后分析。性能分析师还负责现场比赛日编码和编辑比赛和训练镜头以供分析。创建各方面性能的报告。向工作人员和运动员解释成绩数据。此外,负责保持统计和视频数据库的更新。

数据分析师:需要成为从数据库和其他技术中收集和提取数据的技术专家。职责包括设计和维护数据库,从各种来源挖掘数据,使用统计工具解释数据集,并为员工、球员和行政领导准备报告。

视频/数据分析师:参见上文对性能分析师和数据分析师的描述。预算较低的俱乐部雇佣一个人负责视频和数据分析。

总经理/总经理助理:随着技术的发展和职业体育特许经营使用更多的数据,总经理需要具备良好的分析技能。他们不处理原始数据,但需要理解和解释在数据帮助下开发的解决方案。数据分析师或绩效分析师被提升为总经理助理甚至总经理的趋势越来越明显。

球探总监/技术总监/助理蔻驰:对教练、球探和技术总监的需求也增加了。他们需要更加适应 Wyscout、Instat、Opta 等技术和平台。越来越多的趋势是助理教练进行视频分析,而不是全职的视频分析师。

赛区:球队分为东部(E)赛区和西部(W)赛区。

结果:

截至 2021 年 1 月 14 日,亚特兰大联队和温哥华白浪队在日常任务中在一定程度上使用数据的员工最多。

作者图片

Atlanta United 有一名头衔为“运动性能科学总监”的员工、三名性能分析师和一名足球分析总监。Whitecaps 还有一名头衔为“运动性能科学总监”的员工、两名性能分析师和两名数据科学家。平均而言,每个俱乐部的足球运营部门都有三名全职员工处理数据。

作者图片

当我们按会议(东部和西部)查看员工总数时,我们可以看到两个会议非常接近。东部联盟有 40 名工作人员,西部联盟共有 37 名。一个让我印象深刻的数字是,东部联盟团队中拥有“绩效分析师”头衔的员工几乎是其他团队的两倍。东部联盟球队有 20 名性能分析师,西部联盟球队总共有 11 名。

作者图片

一般来说,关于足球运营中不同部门之间的数据流动,MLS 内的团队之间有一个标准的组织结构。至少有一名在足球操作方面技术熟练的雇员处理原始数据。此人可以是数据科学家、数据分析师或足球分析总监。这很难想象,但你会不时发现没有内部分析部门的俱乐部。然而,他们找到了不同的方法来运行他们的分析。例如,圣何塞地震与当地大学合作,支持他们的分析,或者俱乐部聘请第三方提供商进行分析,就像芝加哥火灾过去所做的那样。

作者图片

当我们看上面的数据流程图时,我们看到三种不同类型的数据。在足球比赛中,数据分为物理数据、事件数据和跟踪数据。为了更好地理解数据如何在不同部门流动,我们首先需要理解每个部门的含义。

身体数据:可以想象,身体数据为我们提供了球员身体表现的信息。比如速度、走过的距离、心率等。

事件数据:这种类型的数据描述了球上发生的事情。事件数据可以是射门、传球、传中、铲球等。

追踪数据:在这里,我们描述所有球员在球上和球下的位置坐标。

如今,事件数据随处可见。大联盟的大多数球队都和 Opta,Instat,Wyscout 合作。另一方面,物理信息通过可穿戴设备变得可用,例如安装在体育场内的弹射器或摄像头。MLS 在 2020 年初与 Second Spectrum 合作,后者使用机器学习和人工智能来收集跟踪、身体和事件数据。结果,光学跟踪系统不得不安装在每个大联盟体育场。点击此处查看第二光谱能提供什么。

如数据流程图所示,数据流经足球运营部门的三个不同部门。一个是体育科学部,两个技术部,三个招聘部。

流经体育科学部的数据主要是身体数据。目的是管理运动员在训练和比赛中的负荷,最终目的是提高成绩和防止受伤。技术和招聘部门在其分析中包括所有三种不同类型的数据。教练将事件数据和关于对手分析、比赛评估或运动员发展的跟踪数据结合起来。除此之外,技术人员还通过他们的现场比赛分析来使用数据。体育数据主要用于根据运动科学团队的建议制定训练计划。招聘部门在日常工作中也包括所有三种数据类型。事件数据主要用于识别玩家的开始阶段。例如,如果一个俱乐部正在寻找一名前锋,一名特定前锋的进球记录是人们首先要看的统计数据。举例来说,如果一个前锋在过去的两个赛季里没有进球,你会认为他不能胜任他的工作。一旦确定了一个玩家,就可以更详细地使用所有三种数据类型。回到我们的前锋例子,身体数据可以方便地看到前锋平均走了多远。如果前锋努力无球跑动,这可能会帮助球探回答这个问题。当涉及到球员比较时,跟踪数据也变得很方便。你可以和其他前锋比较坐标,看看他们的动作是否相似。最终,每个部门的最终目标都是让俱乐部获得相对于其他团队的竞争优势。

结论:

基于我们在数据和研究中的发现,我们可以得出以下结论:

  • 平均而言,MLS 中的俱乐部在足球运营部门有三名员工以某种身份处理数据。
  • 这两个会议中与数据相关的员工数量几乎相等(东部 40 人,西部 37 人)。
  • 东部联盟的性能分析师几乎是西部联盟的两倍。(东部 20 人,西部 11 人)。亚特兰大联队和纽约市足球俱乐部在一线队级别的每个俱乐部的绩效分析师总数方面领先。两者一共三个。
  • 即使大多数 MLS 俱乐部在如何将数据和分析纳入运营程序方面有相似的结构,一些球队仍然以不同的方式做事。例如,如上所述,圣何塞地震队是联盟中唯一一个在分析方面完全依赖当地大学合作的团队。身在硅谷很有帮助,因为周围当地大学里精通技术的学生数量和人才储备都很高。尽管许多大联盟俱乐部与当地大学有合作关系,但地震俱乐部是唯一没有内部分析部门的俱乐部。
  • 即使大多数俱乐部都有全职的表现分析师,但也有一些俱乐部的助理教练完全负责视频分析。再次,一个例子是圣何塞和他们现任主教练马迪亚斯·阿尔梅达或国际米兰,他们的视频分析师上赛季是他们教练组的一部分。
  • 有一种趋势是,以前的绩效分析师或其他数据相关职位晋升为助理总经理或总经理。仅举几个例子,蒙特利尔影响,LAFC,科罗拉多急流,都有来自分析背景的总经理或助理总经理。

我希望这篇分析很有见地,能让你更好地理解 MLS 内部的分析现状。如果你对这个话题有任何问题或者有任何反馈,请随时联系我。如果你能在任何社交媒体平台上分享它,我将不胜感激。谢谢你,下次再见 time️!✌️

https://www.navidma.com/

用 Python 和 Kafka 制作一个模拟的“实时”数据流

原文:https://towardsdatascience.com/make-a-mock-real-time-stream-of-data-with-python-and-kafka-7e5e23123582?source=collection_archive---------5-----------------------

这是一个 Dockerized 教程,提供了将带有时间戳的. csv 文件转换成 Kafka 流所需的一切

阿布拉卡-卡夫卡!(作者画的漫画很差。)

随着越来越多的数据科学工作转向实时管道,数据科学家需要学习编写流分析。虽然有一些伟大的、用户友好的流数据管道工具存在(我最喜欢的显然是 Apache Kafka。)如果没有一个友好的开发环境来实际生成可以测试您的分析的数据流,就很难开发流分析的代码。

实时数据流的简单方法

本文将介绍如何部署一个简单的基于 Python 的 Kafka producer,它从带有时间戳的. csv 文件中读取数据,将数据转换成实时(或者说,实际上是“实时”)Kafka 流,并允许您编写自己的消费者,以便对数据流应用函数/转换/机器学习模型/任何您想要的东西。

佐料

所有资料均可在我的 GitHub 时间系列-卡夫卡-demo repo 中获得。接下来,将 repo 克隆到您的本地环境中。您可以在系统上仅运行 Docker 和 Docker Compose 来运行该示例。

回购有几个不同的组成部分:

方向

将 repo 和 cd 克隆到目录中。

git clone https://github.com/mtpatter/time-series-kafka-demo.git
cd time-series-kafka-demo

启动卡夫卡经纪人和动物园管理员

合成文件从 Confluent 的 Docker Hub 存储库中提取 Kafka 和 Zookeeper 版本 6.2.0 的 Docker 映像。(必须固定您的版本!)

docker compose up

这使得 Kafka 和 Zookeeper 在同一个 Docker 网络上开始相互对话。Kafka 代理可以在端口 9092 上本地访问,因为合成文件将本地端口绑定到内部镜像端口。

构建 Docker 映像(可选地,为生产者和消费者)

如果您不想在 requirements.txt 文件中安装 Python 模块,您可以为生产者和消费者脚本使用 Docker 映像。

从主根目录:

docker build -t "kafkacsv" .

这个命令现在应该可以工作了:

docker run -it --rm kafkacsv python bin/sendStream.py -h

启动消费者

我们将首先启动一个消费者来模拟“实时”打印来自流“my-stream”的所有消息。我们在生产者之前启动消费者的原因是,生产者将在每个有时间戳的数据点之间及时再现所有的“暂停”。如果在生产者之后启动消费者,消费者将立即处理队列中已经存在的所有消息。但是如果你喜欢,就去做吧。_(ツ)_/

python bin/processStream.py my-stream

或使用 Docker:

docker run -it --rm \
      -v $PWD:/home \
      --network=host \
      kafkacsv python bin/processStream.py my-stream

消费者主要功能的相关代码如下。请注意,我捕获了未知主题错误消息,并让使用者创建新主题。还要注意,在这个例子中,键盘中断将帮助您关闭消费者。

产生数据流的时间序列

如果您检查数据文件,它有两列:时间戳和(随机产生的)数据值。

timestamp,value
2021-01-01 00:00:00,51
2021-01-01 00:00:04,60
2021-01-01 00:00:06,82
2021-01-01 00:00:07,86
2021-01-01 00:00:11,99
2021-01-01 00:00:12,23
2021-01-01 00:00:21,63
2021-01-01 00:00:23,20
2021-01-01 00:00:24,32

现在(在另一个终端 shell 窗口中),我们将把时间序列从 data/data.csv 发送到主题“my-stream”默认情况下,第二条消息将在第一条消息 4 秒后发送,第三条消息将在 2 秒后发送,依此类推。就像我们回到了过去!(提示休易·路易斯和新闻。)

python bin/sendStream.py data/data.csv my-stream

或使用 Docker:

docker run -it --rm \
      -v $PWD:/home \
      --network=host \
      kafkacsv python bin/sendStream.py data/data.csv my-stream

你也可以加快速度,因为为什么不呢?下面是将速度提高 10 倍的命令:

python bin/sendStream.py data/data.csv my-stream --speed 10

下面是 main 函数的相关代码,展示了时间序列数据到 json 的转换。我们这样做是因为它将保留类型,在这种情况下,数据值中的浮点将保持浮点状态。

如果您观察消费者的输出,它看起来会像这样:

python bin/processStream.py my-stream
2021-08-27 15:54:44 {'2021-01-01 00:00:00': 51.0}
2021-08-27 15:54:48 {'2021-01-01 00:00:04': 60.0}
2021-08-27 15:54:50 {'2021-01-01 00:00:06': 82.0}
2021-08-27 15:54:51 {'2021-01-01 00:00:07': 86.0}
2021-08-27 15:54:55 {'2021-01-01 00:00:11': 99.0}
2021-08-27 15:54:56 {'2021-01-01 00:00:12': 23.0}
2021-08-27 15:55:05 {'2021-01-01 00:00:21': 63.0}
2021-08-27 15:55:07 {'2021-01-01 00:00:23': 20.0}
2021-08-27 15:55:08 {'2021-01-01 00:00:24': 32.0}

看看吧!这个输出是 msg_process()函数的结果,它只打印当前时间和带有时间戳和数值的 json 数据。请注意,接收到的消息保留了这些暂停。msg_process()函数如下所示:

实际的数据输入(带有时间戳的键和值的值的 json,可能应该以不同的方式命名)可以在每个 Kafka 消息中通过调用。值()。

我在这里提供的消费者显然非常简单,因为它所做的只是打印到屏幕上,但是您可以很容易地将 msg_process()函数替换为您想要应用于每个数据点的函数。我推荐使用 json(或者 Apache Avro,如果你想了解模式等等。)因为,就像我说的,它将保留类型。

关闭并清理

用 Return 和 Ctrl+C 停止消费者/生产者。

关闭 Kafka 经纪人系统:

docker compose down

就是这样!希望这就是开始用 Python 编写自己的流数据分析所需的全部内容。

用 Sklearn 管道做一个坚如磐石的 ML 模型!

原文:https://towardsdatascience.com/make-a-rock-solid-ml-model-using-sklearn-pipeline-926f2ccf4706?source=collection_archive---------15-----------------------

为什么、如何以及何时使用 Sklearn 的管道!

照片由西格蒙德Unsplash 拍摄

如果你正在建立一个预测模型,并在没有任何预处理步骤(如清理数据、输入缺失值)的情况下达到预期的精度,那么你恰好是世界上最幸运的人!但是,除非您执行大量的转换和预处理,否则今天的大多数数据都不会说话。涉及到几个步骤,从预处理、转换到建模。当将这些模型投入生产时,我们必须构建一个可以无中断运行的健壮流程,这一点很重要。这就是 Sklearn Pipeline 和其他支持组件发挥作用的地方。

为什么要用 Sklearn 管道?

我会旋转 Jupiter 笔记本,开始探索我的数据,创新新功能,执行预处理,如清理、缩放等。在输入模型之前。然而,我知道在 Jupyter 或类似的 ide 中这样做可能会变得一团糟。在 Jupyter 笔记本中创建一个自动化路径比按 Shift+Enter 更有意义。使用 Sklearn Pipeline 是一种方便的方法,可以通过预处理步骤来执行这些步骤,并确保代码的可再现性。

如果企业每天都依赖机器学习模型来做出决策,生产模型的不稳定和不一致的结果会对企业产生重大影响。

我不是“Jupyter haters 粉丝俱乐部”的成员;我自己构建了 Jupyter Notebook 中的所有内容,然后将其转换为集成 Sklearn 管道的 Python 脚本!

一般 Sklearn 管道工作流程:

如果我们看一个端到端机器学习管道的一般化图表,它看起来会像下面这样:

一旦提供了数据,

  • 我们做插补——用平均值、中间值等填充缺失值。
  • 接下来是一些特性工程,比如为缺失值创建一个标志,为所提供的分类特性创建 groupby 均值,等等。可以做到。
  • 可以使用缩放/归一化来帮助算法更快地收敛,并且可以使用 PCA 来去除一些噪声。
  • 最后,对数据进行估计。你可以使用管道来生成对未知数据的预测。

Sklearn 的管道 集成了上面提到的所有组件,并编排了交付模型的流程。如果我们想一想,不同的乐高积木如何有助于实现你的最终产品,不同的积木在管道中和谐地组合在一起,使其发挥作用!让我们一起来简单了解一下几种常用的变压器:

  • Pipeline: 它是一系列步骤的集合,包括帮助机器学习工作流程自动化的最终估计器。上图是管道的一个例子。
  • 特征联合:数据流不是线性的,需要多个东西一起预处理。它并行执行所有函数,并将最终结果粘贴在一起。当您想要对一列应用不同的转换时,请使用它。

作者创造的形象

  • Column Transformer: 帮助组合应用于不同列的不同类型的转换,并将它们连接起来。

作者创造的形象

  • make_column_selector: 这个 Lego 块有助于根据数据类型选择多个列。Regex 也可以用于选择列。

作者创造的形象

  • 简单估算器:该转换器可用于用平均值、中值、最频繁值或常数来填充缺失值。
  • BaseEstimator,TransformerMixin: 您可以使用这些基类来创建您的转换器。TransformerMixin 主要用于实现一个转换方法。
  • FunctionalTransformer: 这有助于将用户定义的函数转换成易于使用并与管道集成的函数。

简短示例:

让我们在乳腺癌数据集上做一个小的实现,看看使用管道时会有什么不同。

正常 ML 代码:

实施管道:

正如我们从上面的代码中看到的,有几件事很突出:

  • 清洁和质量代码
  • 易于复制
  • 裁员实践中的失业

一些优势:

可读性和再现性

  • 可读性是机器学习领域经常被忽视的一个方面。比起关注代码的质量,我们更重视取得成果。代码必须是任何用户/同事在他们的实践中容易想到的,并与你分享。
  • 此外,重要的是,编写的代码在以相同的步骤反复运行时能够产生相同的结果。当在代码中进行小的调整以获得更好的 ML 模型而不干扰所有组件时,这非常有帮助。

标准化的工作流程—减少数据泄露的机会

  • 当使用管道拟合数据时,工作流程变得非常规范,发生数据泄露的机会也更少。数据泄漏是 ML 从业者在将模型投入生产时面临的最大障碍之一。

出错时易于调试

  • 您的管道可能会抛出错误或导致失败。在这种情况下,如果你的代码是干净有效的,那么找出问题的根源就变得更加容易了!

可重用性

  • 您可以根据新项目的要求,稍加调整,将已经建成的管道移植到一个项目中。这提高了我的效率,帮助我专注于整个 ML 管道的不同部分。

更多应用

  • 我们可以结合管道使用网格搜索
  • 使用像 Dask 这样的库将它们并行化。
  • 您可以使用多个估算器运行一个循环,并对每个估算器使用管道

最后但同样重要的是,Sklearn Pipeline 应该真正集成,并成为工作流的重要组成部分。我已经构建了几个项目,并广泛使用了它们。它们的扩展或应用是无限的,如果使用,它们可以成为一个很好的工具!感谢您的宝贵时间!

TwitterLinkedIn 上关注我。你也可以通过 pratikkgandhi@gmail.com 联系我

在 R 中制作漂亮的 3D 情节——对讲故事的增强

原文:https://towardsdatascience.com/make-beautiful-3d-plots-in-r-an-enhancement-on-the-story-telling-613ddd11e98?source=collection_archive---------1-----------------------

示例和数据解释

3D 可视化通常比平面可视化更好用。两张图片来自 Unsplash

为什么要数据可视化?当我们处理统计数据时,无论我们正在处理什么数据,使用什么模型,数据可视化总是工作中不可避免的一部分。有时我们可能只是机械地制作图表,低估了可视化的重要性。事实上,数据的可视化不仅使数据更容易消化,而且比文本形式和描述性统计数据告诉我们更多。安斯科姆的四重奏就证明了这一点。

为什么是 3D?有时一个 2D 图(或多个图)可以包含我们需要的足够信息,但是 3D 图通常更直观,因为 3D 空间是我们居住的地方。这就像我们通常在地理教科书中看到的地图或地图集的 2D 投影,但地球仪总是更容易使用——更有趣,更直观。此外,在统计学中,我们经常会遇到更高维度的空间(大于 3 维),3D 可视化可以帮助我们在更高维度的空间中进行概括。

本文将介绍一些有用的 3D 绘图类型,即 3D 表面图3D 线条图3D 散点图,它们将使用库plotlyrgl来实现。此外,我们将看一下图表的解释——我们应该知道图表的含义,因为我们不仅仅是在制作精美的图片。

3D 表面图

图 1.1 使用来自plotly.com的代码制作的图像

使用plotly库中的plot_ly函数制作的 3D 表面图非常适合可视化地理数据。使用文档中的代码片段,我们可以从内置的数据集volcano中绘制出一个非常真实的火山。这个数据很容易解释。数据集包含奥克兰 Maunga Whau 火山的地形信息,以 61×87 矩阵的形式显示。矩阵中的每个元素都是火山在 10 乘 10 的网格中的高度。所以,剧情的结果就是火山的形状。不仅是地理数据(高度),我们还可以用它来表示密度,例如概率密度。首先,我们生成一个概率分布矩阵。

# simulate joint probability distribution (normal)
num.rows <- 60
num.cols <- 60simulate <- function(n.row, n.col) {
  # initiate the matrix
  prob.n <- matrix(0, nrow=num.rows, ncol=num.cols)

  x.seq <- seq(1, n.row)
  y.seq <- seq(1, n.col)

  xx <- dnorm(x.seq, mean=n.row/2, sd=12)

  for (i in 1:n.row) {

    y <- dnorm(i, mean=n.row/2, sd=12)
    prob.n[i,] <- y * xx
  }
  prob.n;
}res <- simulate(num.rows, num.cols)

在这个例子中,我们模拟了两个正态分布的独立变量的联合概率。我们可以使用下面的代码来绘制图形,它将输出图 1.2 (a)

# 3D plot of joint probability distribution without projection
fig.n <- plot_ly(z = ~res)
fig.n <- fig.n %>% add_surface()
fig.n

或者我们可以在 x-z 和 y-z 平面上添加投影,这是通过属性contour设置的。

# add projection
fig.nc <- plot_ly(z = ~res,
     contours = list(
       z = list(
         show=TRUE,
         usecolormap=TRUE,
         highlightcolor="#ff0000",
         project=list(z=TRUE)
       ),
       y = list(
         show=TRUE,
         usecolormap=TRUE, 
         highlightcolor="#ff0000",
         project=list(y=TRUE)
       ),

       x = list(
         show=TRUE,
         usecolormap=TRUE,
         highlightcolor="#ff0000",
         project=list(x=TRUE)
       )
     )
  )
fig.nc <- fig.nc %>% add_surface()
fig.nc

highlightcolor参数决定当光标悬停在图形上时,图形轮廓的高亮颜色。在这种情况下,它被设置为红色。图表告诉我们什么?X 和 Y 轴表示随机变量 X 和 Y,它们具有正态分布。z 轴显示 X 和 Y 的联合概率——X 和 Y 取特定值的概率(P(X=x,Y=y)),这决定了图 2.2 中“山丘”的高度。在我们的例子中,由于 X 和 Y 是独立的,根据独立性的定义,P(X=x,Y=y) = P(X=x)P(Y=y)。如果 X 和 Y 具有不同的标准偏差,则其中一个投影会较宽,另一个会较窄,山丘的横截面将是椭圆形,而不是圆形。

但是我们需要小心 x-z 和 y-z 平面上投影的含义。看起来它们是 X 和 Y 的边际概率,但事实上,它们不是。投影只告诉我们 P(X=x 和 Y=y)相对于 X 和 Y 的相应值。但是,X 或 Y 的边际概率应该是行或列的总和(想想边际概率表)。

图 1.2 (a)联合分布(b)轮廓(c)悬停在图像上的联合分布将导致高亮颜色显示。图片由作者提供。

此外,我们可以使用一个颜色代码向量,通过colors属性来定义定制颜色。在图 1.3 中,颜色模板由coolers生成。

color.vec2 <- rev(c("#F2DC5D", "#F2A359", "#DB9065", "#A4031F", "#240B36"))
# color.vec2 <- rev(c("#F7AEF8", "#B388EB", "#8093F1", "#72DDF7", "#F4F4ED"))
fig.n2 <- plot_ly(z = ~res, colors=color.vec2)
fig.n2 <- fig.n2 %>% add_surface()
fig.n2

图 1.3 自定义颜色。图片由作者提供。

3d 线图和瀑布图

当我们想要很好地显示多条线时,3D 线图会非常有用。它使我们能够在一个图形中展示多种趋势,省去了设计更多图形的麻烦,也增加了美感(这是一点个人看法)。我们以美国的电力消耗数据为例,3d 折线图有助于在同一个图表中展示不同年份和月份的电力使用趋势。

# plot of the electricity usage in the US
data.us <- usmelec
dmn <- list(month.abb, unique(floor(time(data.us))))
# convert to data frame by month, to make data retrieval easier
res.us <- as.data.frame(t(matrix(data.us, 12, dimnames = dmn)))# set the values of the 3d vectors
n <- nrow(res.us)
x.us <- rep(month.abb, times=n)
y.us <- rep(rownames(res.us), each=12)z.us <- as.numeric(data.us)
# we need to append two values to the vector
# converted from the time series and we let them
# equal to the last value in the time series so the
# shape of the graph will not be influenced
n.z <- length(z.us)
z.us[n.z+1] = z.us[n.z]
z.us[n.z+2] = z.us[n.z]data.us <- data.frame(x.us, y.us, z.us)
colnames(data.us) <- data.frame("x", "y", "z")fig.us <- plot_ly(data.us, x = ~y, y = ~x, z = ~z, 
                 type = 'scatter3d', mode = 'lines', color=~y.us)
# to turn off the warning caused by the RColorBrewer
suppressWarnings(print(fig.us))

在本例中,数据存储为时间序列,这需要花费一些精力来设置 x、y 和 z 轴的值。幸运的是,这可以简单地使用rep函数来完成。

图 2.1 美国用电量的 3D 线图。图片作者/

从 y-z 平面我们可以看到,从 1973 年到 2010 年,人们普遍使用越来越多的电力,从 x-z 平面我们可以看到全年的用电量是如何分布的(这实际上就是所谓的季节性,一些时间序列所具备的一个非常重要的属性)。

瀑布图(它不同于 3D 线图,因为在 3D 线图中不必有多条线——可以简单地有一条线穿过 3D 空间)是一个 3D 图,其中同时显示多条曲线。通常,它用于显示光谱,例如,显示离散傅立叶变换的结果。在 R 中,这可以通过使用lines3d来实现。下面的代码生成了一个 10 元素数组经过复数傅里叶变换后的频率分量图。

# For displaying the result
options(rgl.printRglwidget = TRUE)x.f <- c(5, 4.2, 9, 3, 5.5, 8.2, 4.8, 6.4, 11, 10.2, 8.9, 10.9)
res.f <- fft(x.f)nx <- length(x.f)
ny <- 70xx <- seq(0, nx, by = 1)
yy <- seq(0, 1, length = ny)aspect3d(4, 2.5, 1)
axes3d()cols <- c("#CBE896", "#AAC0AA", "#FCDFA6", "#A18276", "#F4B886", "#DD99BB", "#7F5A83", "#A1D2CE", "#78CAD2"
          , "#62A8AC", "#5497A7", "#50858B")
for (i in 1:nx) {
  c <- x.f[i]
  a <- Im(res.f[i])[1]
  b <- Re(res.f[i])[1]
  lines3d(yy, xx[i], c*(sin(a*xx) + cos(b*xx)), col=cols[i], lwd=2)
}

上述代码的输出如图 2.2 所示。为了运行代码,库rgl是必要的。与之前的示例(图 2.1)不同,这些线是在一个循环中一条一条添加的,而不是立即在 3D 空间中设置点的位置。

图 3.2 频率成分。图片由作者提供。

我们也可以使用瀑布图来显示密度。这可以通过函数slicedens来实现,该函数可以从 GitHub 库 BivariateSlicer 中获得。我们可以使用source函数立即导入整个源文件,但是其中的一些例子可能无法正常运行。所以,还是直接运行函数比较好。slicedens使我们能够在数据中制作切片,并在一个 3D 绘图中呈现它们。

我们使用艾姆斯住宅数据集作为例子,它可以从 Kaggle 获得。

housing <- read.csv2(file='data/AmesHousing.csv', header=TRUE, sep=',')
housing
summary(housing$Gr.Liv.Area)
ground <- housing$Gr.Liv.Area
price <- housing$SalePriceplot(ground, price, cex=.2, col="deepskyblue3", xlab="Above grade living area", ylab="Price")fcol <- c(.3, .8, .8,.12)
lcol <- c(0.1, 0.5, 0.4,.1)
slicedens(ground,price,
          fcol=fcol, bcol='white', lcol=lcol,
          gboost=0.015)

数据用散点图表示,如图 2.4 所示

图 2.4 房价散点图。图片由作者提供。

想象一下,把散乱的数据切割成几个水平的块,其中一些包含的点多一些,一些少一些。将切片排列成单个图后,结果如图 2.5 所示。

图 2.5 中的图看起来很漂亮,但这可能不是呈现散点数据的最佳方式。当然,我们可以从该图中看到密度分布,但与图 2.4 相比,图 2.5 似乎不那么清晰——我们无法确定哪个区域和价格范围最常见。在这种情况下,如图 2.4 所示的 2D 散点图可能更好。但是因为好看的视觉效果和slicedens有趣的想法,这篇文章里也介绍了这个 3D 剧情。

图 2.5 房价瀑布图。图片由作者提供。

3d 散点图

散点图是表示离散观察值的好方法。我们以埃德加·安德森的鸢尾数据为例,给出了三种鸢尾的萼片和花瓣的长度和宽度。这通常也用于演示 PCA(主成分分析)。我们将使用下面的代码来绘制花的特征和组件向量的散点图。代码是这个的修改版。如果你不太了解 PCA,也不用担心,它背后的数学需要一些时间来解释,但这个想法很简单——这是一种有助于以最小的信息损失减少数据集维数的技术。

# iris data
summary(iris)
iris$Species <- factor(iris$Species,
                       levels = c("versicolor","virginica","setosa"))
pca <- princomp(iris[,1:4], cor=TRUE, scores=TRUE)# Scores
scores <- pca$scores
x <- scores[,1]
y <- scores[,2]
z <- scores[,3]# Loadings
loads <- pca$loadingsscale.loads <- 3p <- plot_ly() %>%
  # the scatter plot of the data points 
  add_trace(x=x, y=y, z=z,
            type="scatter3d", mode="markers",
            marker = list(color=y, 
                          colorscale = c("#FFE1A1", "#683531"), 
                          opacity = 0.7, size=2))ns <- rownames(loads)
# add the vectors of the components
for (k in 1:nrow(loads)) {
  x <- c(0, loads[k,1])*scale.loads
  y <- c(0, loads[k,2])*scale.loads
  z <- c(0, loads[k,3])*scale.loads
  p <- p %>% add_trace(x=x, y=y, z=z,
                       type="scatter3d", mode="lines",
                       line = list(width=8),
                       opacity = 1, name=ns[k]) 
}
# display the graph
print(p)

3D 散点图可以很好地帮助我们了解数据的分布以及“组件”所扮演的角色。

图 3.1 虹膜数据集的 3D 图以及组件的方向。图片由作者提供。

在图 3.1 中,数据没有聚类(按物种着色),颜色只是沿着 y 轴变化。为了绘制聚类数据,我们可以很容易地使用函数plot_ly来完成。

p <- plot_ly(iris, x=~Sepal.Length, y=~Sepal.Width, 
             z=~Petal.Length, color=~Species) %>%
  add_markers(size=1) 
print(p)

图 3.2 聚类虹膜数据。图片由作者提供。

其他有用的 3D 绘图

在这一节中,我们介绍一些其他的有代码的图。

(1)奇特的 3D 直方图来自:http://www . sth da . com/English/wiki/impressive-package-for-3D-and-4d-graph-r-software-and-data-visualization,这是一个显示离散数据频率的好工具,例如关于经度和纬度的地震事件数量(图 3.3)。在图 3.3 中,柱表示每个经度和纬度范围内的地震事件计数(x-y 平面上的小方块)。在网格下面的 x-y 平面上,投影是给定范围内地震事件深度的散点图。

图 3.3 斐济附近地震的位置,使用的是奇特的 3D 直方图。(图片来自 STHDA )图 3.4 gapminderDataFiveYear 数据集的气泡图。(图片来自plotly)

(2)3D 泡泡图出自:https://plotly.com/r/3d-scatter-plots/。它可用于在单个 3D 绘图中显示多个变量的关系。图 3.4 中给出的示例显示了人口、预期寿命、GDP 和国家(每个标记的标签,悬停时可见)以及国家大小(标记的大小)之间的关系。

图 3.4 螺旋面的 3D 图。来自 R 视图的图像

(3) 发展几何直觉的 3D 曲面图来自:https://rviews . r studio . com/2020/12/14/plotting-surfaces-with-r/。本文中的例子对于可视化拓扑形状非常实用。

资源:

[1] Matejka,j .,& Fitzmaurice,G. (2017 年 5 月)。相同的统计,不同的图形:通过模拟退火产生不同外观和相同统计的数据集。载于2017 年中国计算机学会计算系统中人的因素会议论文集(第 1290-1294 页)。

[2] R 数据集:火山,2021 年 8 月 31 日获取

使用 Plotly 和 Mapbox 制作漂亮的空间可视化效果

原文:https://towardsdatascience.com/make-beautiful-spatial-visualizations-with-plotly-and-mapbox-fd5a638d6b3c?source=collection_archive---------11-----------------------

使用 Python 探索基于切片的 Web 地图的优势

谢栋豪在 Unsplash 上的照片

我最近给写了一篇关于可视化 NOAA 天气数据的文章。我们用 Plotly 处理了数据并制作了一些基本的交互式地图。在本文中,我想使用相同的数据,但重点是我们可用的选项,以改善我们的 Plotly 和 Mapbox 的网络地图。Web 地图有多种用途,拥有一个有助于强调数据点或为数据点提供上下文的高质量底图可以极大地提高可视化的质量。

Mapbox 是一家初创公司,为 Foursquare 和天气频道等网站提供地图,同时开发一些最强大的开源工具来创建网络地图。多年来,Mapbox JavaScript 库一直是最好的网络地图工具,现在我们可以使用 Plotly 利用 Python 中的 Mapbox。

Plotly 中的地图类型

轮廓与平铺地图

Plotly 有两种主要类型的地图,Geo 地图和 Mapbox 地图。地理地图是基于轮廓的,地图框地图是基于切片的。两者的主要区别在于,基于轮廓的地图可以一次绘制所有内容,而基于切片的地图具有以不同缩放级别呈现的信息层次。

如果我有一个以全球比例开始的地图,并且我希望用户能够放大以查看精细的粒度级别,那么基于切片的地图可能比轮廓地图更适合我的需要。由于基于切片的地图不必立即加载所有信息,因此它们的内存消耗较少,但是缩放时必须处理粒度变化会增加切片地图的处理能力开销。这意味着基于切片的地图非常适合提供大量信息而不会使地图变得杂乱,但它们需要更多的数据和处理能力。

这是作为轮廓图和基于图块的地图渲染的同一张地图。试着放大,看看你是否能发现两者之间的一些显著差异。

由作者使用 Plotly 创建

由作者使用 Plotly 和 Mapbox 创建

乍一看,除了使用不同的投影之外,这些地图可能看起来非常相似。但是当你开始放大的时候,你开始看到基于地图的好处。国家边界变得可见,因为它们变得相关,对数据点不那么突出;当您放大到越来越精细的比例时,甚至城市、道路和河流也会加载到底图中。

能够接触到这种细节真的可以让可视化感觉更专业,并且在多尺度下工作时,不同的粒度是有帮助的。如果我们想使用 Plotly 的散点地理函数显示国家边界,我们需要以各种比例绘制它们,如下所示:

由作者使用 Plotly 创建

在这种规模下,这个地块比两个没有国界的地块要繁忙得多。我们仍然缺少平铺地图提供的细节,如国家名称和城市。这些类型的要素可以在轮廓地图上进行配置,但对于可能很快变得混乱的轮廓地图来说,它们并不十分实用。

尽管有这些缺点,轮廓图仍然占有一席之地。当创建较小区域的地图时,我们通常不需要以多种比例渲染数据,这意味着没有理由增加基于图块的地图的数据和处理开销。此外,当制作用于演示的地图时,定制基于轮廓的地图以从远处最大化快速可读性可能是有利的。更不用说会议室并不总是有最好的 wifi,我已经看到我的网络地图加载速度非常慢,让说话的人感到沮丧。

地图框和 Plotly 平铺地图基础

Mapbox GL JS 是一个 JavaScript 库,用于交互式切片地图的 web 制图。当我们调用 Python 中的一个 Plotly Mapbox 函数时,Plotly 指的是 Mapbox JavaScript 库。由于 Mapbox GL JS 库的某些版本是开源的,因此使用这些函数和开源底图不需要 Mapbox API 密钥。然而,作为一家公司,Mapbox 拥有非常高质量的矢量切片底图,需要使用 Mapbox API 密钥。Mapbox 有一个很好的免费层,允许每月多达 50,000 次地图加载,这对大多数用户来说已经足够了。

栅格切片与矢量切片

大多数 web 地图传统上使用栅格切片来构建地图,但是 Mapbox 也允许我们利用矢量切片。如果您熟悉 GIS 数据,则栅格是值(影像)的格网,而矢量数据是几何数据,通常是点、线和面。

栅格切片是一组图像,它们彼此相邻排列以形成完整的地图。放大时,可以加载不同级别的栅格切片,以不同的比例显示新要素。矢量切片的工作方式与此非常相似,但是切片包含适合您正在查看的缩放和位置的预生成矢量数据。

矢量图块有很多优点。它们不需要像栅格切片一样大小完全相同,而是由客户端的计算机渲染,这可以使它们对于主机来说重量轻得多。矢量数据通常也比使用 map snappier 制作的栅格数据小得多,因为您对快速互联网连接的依赖更少。如果需要的话,矢量数据甚至可以渲染栅格,这使得它非常灵活。

平铺底图

使用 Plotly,我们可以访问光栅和矢量平铺基础地图。我们访问的栅格切片底图是开源的,就像 Open Street Map 的底图一样。Mapbox 提供对矢量切片底图的访问,但它们需要 Mapbox API 令牌才能访问。下面我将浏览一些可用的底图,并向你展示实际的区别。

来自公共服务器的栅格切片底图

我们可以访问的所有栅格切片底图都是开源的,不需要 API 令牌就可以使用。以下是一些可用的示例:

打开街道地图

尽管我们使用的是开放街道地图中的底图,但我们仍然调用了“散点图框()”函数。这是因为 Plotly 利用开源的 Mapbox JavaScript 库来绘制切片地图,而不管它们是栅格切片还是矢量切片。

使用开放街道地图中的栅格切片绘制地图(由作者创建)

USGS 影像栅格切片

美国地质调查局有大量的在线图像,包括一些很棒的底图!像这样使用栅格切片图像图层的最简单方法是渲染一个空白的白色画布,然后手动渲染数据或“轨迹”下面的底图。

使用 USGS 中的光栅切片绘制地图(由作者创建)

使用 Plotly 可以如此轻松地创建和共享各种地图,这真是太酷了!像这样的图像可以为气候数据提供真正有用的背景,尽管你可能会注意到我的色标可以使用一些调整来适应这张底图中的深色。由于基于切片的 web 地图是一种流行的标准,因此有许多可轻松访问的底图。

注意:如果你运行的网络连接速度较慢,这些地图可能需要更长时间才能加载。栅格切片可能非常大,这意味着需要将大量数据传输到浏览器中。

USGS 水文栅格切片

如果我们使用此链接作为我们的来源,我们也可以从 USGS 获得水文底图:

source = ["[https://basemap.nationalmap.gov/arcgis/rest/services/USGSHydroCached/MapServer/tile/{z}/{y}/{x](https://basemap.nationalmap.gov/arcgis/rest/services/USGSHydroCached/MapServer/tile/{z}/{y}/{x)}"]

由作者使用 Plotly 创建

你会注意到美国地质勘探局的一些数据产品,北美的数据要完整得多,所以在世界的某些地方可能没有有用的水文信息。总的来说,从美国地质勘探局、美国国家海洋和大气管理局等机构获得的免费和有用的数据令人印象深刻。

USGS 地貌晕渲底图

这里是一个阴影地形底图,作为美国地质勘探局免费提供的最后一个例子。请记住,网上还有其他栅格地图数据集,我将在最后的参考资料部分链接这些数据集。

"source": [          "[https://basemap.nationalmap.gov/arcgis/rest/services/USGSShadedReliefOnly/MapServer/tile/{z}/{y}/{x](https://basemap.nationalmap.gov/arcgis/rest/services/USGSShadedReliefOnly/MapServer/tile/{z}/{y}/{x)}"]

由作者使用 Plotly 和 Mapbox 创建

来自 Mapbox 服务器的矢量切片底图

矢量切片底图是从 Mapbox 的服务器上获取的,这意味着我们需要一个 Mapbox 帐户和 API 令牌来使用它们。如果您的计算机相当现代,您可能会注意到这些矢量平铺地图在响应速度和细节方面有了相当大的改进。由于矢量数据是由您的计算机渲染的,因此从服务器传输到您的计算机的数据较少,这通常意味着更快的加载时间。

地图框深色样式

使用 Mapbox 底图进行绘图的语法与开源替代方法非常相似。我们简单地传递一个带有 API 键和其他参数的“mapbox”字典,而不是指定层。“样式”决定了您的地图使用哪个地图框底图。

由作者使用 Plotly 和 Mapbox 创建

街道风格

如果你正在寻找街道和城市的更多细节,那么“街道”风格将非常适合你的用例。它从以前的地图中去掉了许多户外娱乐的细节,换来了街道、小路和公园的极端细节。这张底图可以让我们放大看到甚至非常小的街道的名称。这张底图甚至包括了我的家乡科罗拉多州博尔德市所有的校园建筑名称和步行路径。

由作者使用 Plotly 和 Mapbox 创建

户外风格

Mapbox 甚至有类似“户外”风格的底图,其中有重要的地标和徒步旅行、骑自行车和其他户外活动的细节。您甚至可以放大到像科罗拉多州布雷肯里奇这样的地区,当您足够接近时,可以看到呈现的滑雪道:

Mapbox 户外风格截图(作者创作)

包扎

我们可以看到,Plotly 和 Mapbox 为我们提供了范围广泛的底图,以满足许多不同用户的需求。即使从 USGS 等第三方加载栅格切片也相当简单。能够使用 Python 中如此强大的 web 制图工具真是太棒了,因为能够在不使用 JavaScript 的情况下制作高质量的地图可以减少工作流程中的许多摩擦。

资源

让沟通成为你的超能力

原文:https://towardsdatascience.com/make-communication-your-superpower-improving-the-1-skill-for-data-professionals-670c2e250d7c?source=collection_archive---------27-----------------------

提高数据专业人员的首要技能

最重要的是,作为一名数据科学家,你如何沟通将是你成功的决定性因素。听听为什么,你能做些什么来把交流变成一种力量。

轻松吸引观众,你要说什么以及如何说很重要(图片由万三叶Unsplash 上拍摄)

有抱负的数据科学家问了我很多关于如何改进以及他们应该关注什么的问题。比如:

  • 接下来该学什么框架?
  • 我应该使用什么型号?
  • 接下来该学茱莉亚还是火花?

虽然对大多数人来说,这些都是值得考虑的事情(在正确的环境下),但它们不是你应该关注的地方。成为那种比同龄人更了解朱莉娅的罕见的数据科学家只会在某些情况下有所帮助——这是可能用来区分两个强有力候选人的技能之一。你首先要确保你已经为成为一名强有力的候选人打下了基础。

在我看来,没有什么比沟通更重要。在这篇文章中,我将概述为什么以及如何去改善它们。

沟通的重要性

这是显而易见的,对吗?对于任何职业和生活来说,能够有效地沟通都是一项至关重要的技能,但我想强调它在商业环境中的重要性。

我曾经和几个超级天才一起工作过,他们很难达到你期望的效果,因为他们被他们的交流所阻碍。更糟糕的是,许多有才华的人认为他们超越了这一点,工作应该为自己说话——它不会。

简单化

你的工作是把你的想法翻译成最清晰、最容易理解的形式,而不损害信息的内容。在许多情况下,你将是你所讨论的领域的专家——你将因为你的技术专长而被雇用,并被要求将这种专长翻译给非技术利益相关者,或者你将在一个技术团队中,并将你的项目成果传达给更广泛的团队。无论哪种方式,都与背景有关。这让我想起了许多由伊丽莎白·牛顿在斯坦福大学做的著名实验——研究参与者被要求给其他人弹奏一首曲子,并猜测它被正确猜到的可能性,那些弹奏曲子的人大大高估了它被猜到的容易程度。这被称为“知识的诅咒”,并得到了很好的研究。

从本质上讲,任何人在向他人解释某件事情时,都很难对自己已经知道的东西打折扣。数据专家在这方面尤其糟糕。我们经常假设一定程度的理解(甚至是兴趣!)根本就不存在,并且在完全错误的层面上进行沟通。

尽管我有技术背景,但我告诉我的所有团队写他们的演示、演示和文档时,就好像他们在和一个白痴交流。假设我什么都不知道,你需要以这样一种方式沟通,我得到你的要点。算法或数学可能真的让你感兴趣,但对许多非技术利益相关者来说,却不是。更糟糕的是,许多企业的高层领导可能会认为这是智力势利或浪费时间。

你如何提高这方面的能力?练习。为非技术人员或在你的领域缺乏经验的人安排午餐和学习。问问你不从事科技工作的家人或朋友,你是否可以就此对他们进行测试。正确地做到这一点将会给你带来奇迹,并节省你在不需要的时候陷入技术细节的时间。

学术论文交流

当你记录你的工作和与团队合作时,这是一项需要时间的技能。尽量保持简洁,避免使用复杂的词语或语言。

在我的整个职业生涯中,我都有写日记的习惯。我在读博士的时候就知道,我需要尽可能清楚地写东西,并记录参考文献,就像我的生活依赖于此一样。我们在一个广阔的领域工作,有许多深入的技术领域,很容易忘记你六个月前知道的事情。养成做好笔记的习惯会提高你的写作水平。

不要害怕审查和编辑过程。我写论文时经历了很多痛苦,因此我的写作变得更好了。让别人客观地评论你的作品是金。如果你发现自己写的东西很难读懂,那就开个博客吧,网上有很多人都很乐意帮忙。事实上,如果你在读完这篇文章后开了一个博客,并希望有人评论它,伸出手来,我会告诉你我的想法。

最后,我建议使用 Grammarly 这样的工具,它会让你不再怀疑你的语法,有助于保持一致性。

语言通信

我认为我所认识的大多数数据专业人士在口头交流方面比书面交流更加困难。有很多提高口语的技巧和窍门。在指导这类事情时,我告诉人们的前三条是:

  • 许多技术人员倾向于做的一件事就是说得太快,尤其是当他们兴奋的时候。尽量避免这种情况。试着主动放慢速度,想想政治家或演员在排练演讲或独白时的语速。
  • 更多停顿,更长时间——这似乎违反直觉,但会给你的演讲增加更长的停顿。留下空白真的很有力量,可以加强你所说的内容。它散发着自信。这也给了其他人一个明确的信号,如果需要,他们可以插入问题或其他观点,而不必超过你或等太久。这也给了你一个很好的机会来回顾你从房间里得到的肢体语言暗示,并相应地调整你的信息。
  • 直奔主题——我经常听到非常好的观点因为演讲者跑题或掉进兔子洞而被破坏或错过。你可能见过有人迷路,忘记他们在说什么。在工作环境中,这可能会损害你的声誉,并可能导致每次你开始说话时,人们就不再说话。尽量简明扼要,不跑题,只有在被要求或绝对必要的情况下才详细阐述你的观点。

关于这方面的更多帮助,有一些很棒的 Ted 演讲:

视觉呈现

这可能比列表中提到的任何事情都更伤害我的灵魂。请花一些时间来学习有效地使用视觉效果。求你了。

我经常看到人们用错误的图表类型绘制出色的工作成果,有糟糕的轴,不清楚,丑陋,斜视的视觉效果。无论你是为期刊写作、做演示、写博客,还是仅仅在你的 Jupyter 笔记本上记录你的结果——你的图表是大多数人都会被吸引的东西。让他们真正击中要害。

我坚信,如果我不能立即(在一秒钟内)理解图表中发生的事情,这可能是一个糟糕的视觉效果。如果有人必须向我介绍或解释一个图表,很有可能它会被简化或以更好的形式呈现。

有很多资源可以利用。有时,一个混杂的包但是 r/databasebeautiful 是一个观察其他人在做什么的好地方:

https://www.reddit.com/r/dataisbeautiful/

我建议你熟悉一下《金融时报》的视觉词汇——这是一个值得努力的伟大标准。也有一些类似 Tableau 和 Power BI 的实现。

有时,复杂的数字是必要的,在这种情况下,尽最大努力应用爱德华·塔夫特的量化信息的奇妙视觉显示中的一些要点:

https://www.amazon.co.uk/Visual-Display-Quantitative-Information/dp/0961392142?crid=ISCRTVDDNDYT&dchild=1&keywords=tufte+data&qid=1613689357&sprefix=tufte+%2Caps%2C182&sr=8-3&linkCode=ll1&tag=adzsroka-21&linkId=774f076e002659b4ebca2946226b4059&language=en_GB&ref_=as_li_ss_tl

后续步骤

不管怎样,有针对性的练习将是你开始看到全面显著进步所需要的一切。有些事情对你来说可能是自然而然的,而有些则不会。不要害怕接触导师、同事甚至更广泛的社区——没有什么比开博客或参加当地聚会更能磨练你的技能了。你可能会喜欢它。

希望这对您有所帮助。如果你认为我可能遗漏了任何提示,请告诉我——我也一直在学习!

进一步阅读

作为一名数据科学家,如果您正在寻找其他方面的建议,以下一些文章可能会让您感兴趣:

https://medium.com/better-programming/7-non-data-science-books-that-will-make-you-a-better-data-scientist-1e2844d75fa1

做出正确的决定

原文:https://towardsdatascience.com/make-good-decisions-aed89eca68c8?source=collection_archive---------13-----------------------

实践教程

我女儿在上中学,最近买了她的第一部新手机。她用自己从一个利润丰厚的暑期社区工作(遛狗、看猫、浇花、看孩子)中辛苦赚来的钱。拿起电话的那天,她要做一个决定。她应该购买保险以防意外损坏,还是通过购买手机壳来降低损坏的可能性,还是什么都不做,听天由命?

阿里·阿卜杜勒·拉赫曼Unsplash 上拍摄的照片

她应该如何做出决定?不是恐惧地,也不是愉快地,而是理性地。

理性决定

有 3 种可能的 决策 :

  1. 买保险(没有手机壳)。假设一年的保险费为 100 美元,如果她需要维修/更换,她必须支付 50 美元的免赔额。

2.买个手机壳(不买保险)。假设对她有吸引力的最简单的案例花费 40 美元。

3.没有任何保险或手机壳的风险。

每个决策有两种可能的 结果 :

  1. 这款手机在一年内没有任何重大损坏。
  2. 电话在一年内坏了,需要修理/更换。有了保险,这将花费她免赔额。如果没有保险,她大概要花 200 美元才能拿回一部能用的手机。手机壳会降低手机摔坏的风险。

列举的决策和结果可以被可视化为逻辑树。从根到叶子的每一条路径都代表了几种可能性中的一种。

决策树(图片由作者提供)

她有足够的信息做出理性的决定吗?不完全是。一个关键的缺失部分是每种可能性的 概率 :

  1. 一年内手机坏掉的概率,无案例。
  2. 一年内手机坏掉的概率,有案例。

如果这是一场掷骰子、纸牌或掷硬币的游戏,她会客观准确地知道概率。但是现实生活很乱。潜在概率中存在不确定性。这是否注定了一个理性的决定?号码

她先从一些 概率的合理主观估计 开始。鉴于她自称笨手笨脚,她认为她有很大的可能会摔坏手机,比如说 50%。而一个手机套可以减少一半(25%)。然后,她计算出每个决策的 期望值 :

expected value = V + *v_1 x p_1 + v_2 x p_2 + ... + v_n x p_n*where V is the value of the decision, and *v_i, p_i* are the expected value and probability respectively of the *ith* possible outcome.So,
╔═══════════════════════════╦══════════════════════════════════════╗
║       Decision            ║            Expected value            ║
╠═══════════════════════════╬══════════════════════════════════════╣
║ Insurance: yes, Case: no  ║ -100 +  -50 x 0.50 + 0 x 0.50 = -125 ║
║ Insurance: no,  Case: yes ║  -40 + -200 x 0.25 + 0 x 0.75 =  -90 ║
║ Insurance: no,  Case: no  ║    0 + -200 x 0.50 + 0 x 0.50 = -100 ║
╚═══════════════════════════╩══════════════════════════════════════╝

具有期望值和概率的决策树(图片由作者提供)

期望值是什么意思?从一个决策反复出现的场景来考虑这个问题。所以,一次又一次,她买了一部手机,带着它生活了一年,并看到了她的决定的结果。然后,在一些重复中,手机会坏掉(例如,当她决定不买一个盒子时,大约一半的重复),而在其他重复中,手机不会坏掉。她在所有重复中的平均收益/损失就是决策的期望值。因此,她做出了理性的决定,通过拒绝保险和购买保护箱(因为-90 > -125 和-90 > -100)来最小化她的预期成本(或者,等价地, 最大化预期价值 )。

你反对在现实生活中她没有机会重复上演这个场景。你说得对。但是她确实演了很多很多不同的场景,而且统计数据显示了所有这些场景。所以,如果她坚持做出最大化她期望价值的决定,她会比非理性地做出决定做得更好。参见运气与此有什么关系了解重复事件与大量不同事件的更详细讨论。

还有别的事困扰着你。你怀疑她的决定是基于对概率的错误估计,而不同的估计会导致不同的理性决定。再说一次,你是对的。处理潜在概率不确定性的方法是找到最优决策发生变化的阈值,然后决定你最有可能在阈值的哪一边。有了保费、免赔额、case、维修的具体数值,结果发现,只要手机坏了没有 case 的概率是< 40%,她还是不买保险和 case 的好。如果可能性高于 40%,那么一个案例最有意义。购买保险从来都不是最好的选择。

作为手机损坏概率函数的每个决策的期望值(图片由作者提供)

女儿靠在一旁小心翼翼,估计自己摔坏手机的几率大于 40%,决定给手机买个保护套。到目前为止,她对自己的决定很满意。

好的决定可能会有坏的结果

如果我女儿在拒绝保险后没几天就摔坏了手机怎么办?然后,她不是简单地支付 150 美元的保险费和免赔额,而是为这个箱子和替换手机支付 240 美元。她一定会后悔自己的决定,不是吗?不要!或者至少她不应该。一个好的决定可能会有一个坏的结果(由于运气不好)。相反,一个糟糕的决定会有一个好的结果(因为运气好)。尽管有这样做的强烈倾向,但永远不要根据结果的质量来评估决策的质量。如果你持续做出好的决定,你会在更多的时候有更好的结果(相比之下,如果你持续做出坏的决定或者持续做出好的决定)。

决策质量与结果质量(图片由作者提供)

为特殊的赌注破例

期望值最大化的决策规则适用于大多数情况。但是,当赌注异常高时,情况就不同了。有时你不得不放弃预期的收益,因为很难实现它。而且,有时你必须承受预期的损失来保护自己免受灾难。

有时放弃预期的收益

假设你有机会以有利的赔率玩彩票。你有百万分之一的机会赢得十亿美元。玩的费用是 100 美元。你想玩几次都可以。

迪伦·诺尔特在 Unsplash 上的照片

游戏的预期价值是 900 美元:

*expected value = -$100 + $1,000,000,000 x 1/1,000,000 = $900*

彩票决策树(图片由作者提供)

所以你应该玩,对吗?如果你输了,你应该继续玩,直到你赢了,对不对?不,除非你愿意先损失数亿美元。赢的几率,从而实现预期的收益,是如此之低,以至于大多数时候你会输。平均来说,你必须玩一百万次才能赢,花费你 1 亿美元。当然,你会在获胜后弥补,但你有那么多的资本和时间来投资吗?

因此,为了修正我们的决策启发法,决定最大化期望值的路径,除非最有可能的情况是亏损。在这种情况下,如果可能的话,最好选择另一个损失可能性不大的决定。不玩彩票

有时会招致预期的损失

我和我的家人住在一个地震多发地区,那里在未来几十年内会发生一场大地震。我们一直在努力决定是否为我们的房子购买地震保险。假设保险费是每年 1000 美元,在要求保险覆盖我们家的全部损失的情况下,免赔额是 100000 美元。如果没有保险,假设更换/维修费用为 1,000,000 美元。

何塞·安东尼奥·加列戈·巴斯克斯在 Unsplash 上拍摄的照片

如果下一年发生灾难性地震的可能性很低(低于千分之一),那么如果我们不买保险,我们的预期成本是最低的。

地震保险决策树(图片由作者提供)

所以我们应该拒绝为我们的房子投保地震完全损失险,对吗?不,除非我们愿意变得无家可归,虽然可能性很小,但却不容忽视。最坏的情况是灾难性的,足以保证相对较小的成本来防范它。

再次调整我们的决策启发式,决定最大化期望值的路径,除非最有可能的情况是亏损,或者最糟糕的情况是灾难性的。在灾难性的最坏情况下,如果可能的话,更倾向于另一个更容易接受最坏情况的决定。不要拿重要的事情冒险。

使用工具

有了关于如何做出理性决策的启发,你应该如何真正去做,而不是每次面对决策时都陷入计算中?当然,使用适当的工具。如果你是一个电子表格忍者或程序员,你可能会对分析你面临的每个决策的期望值、可能情况、最坏情况和概率阈值感到舒服。对于你们其余的人,我很高兴分享我一直在使用的东西的粗略原型:https://vishesh-khemani.github.io/decisions/decision.html。下面的截图会让你知道它是干什么的。

决策树输入规范的屏幕截图(图片由作者提供)

渲染决策树的屏幕截图(图片由作者提供)

可以调整以找到阈值的自动生成参数的屏幕截图(图片由作者提供)

每个决策的“烛台”值(最小值、预期值、第 90 个百分位数、最大值)的屏幕截图,可快速查看相关指标(图片由作者提供)

摘要

  1. 理性地做决定,通常选择最大化你的预期价值的选项。
  2. 如果每个场景的概率有太多的不确定性,确定最佳决策发生变化的阈值概率,并判断阈值的哪一侧最有可能发生变化。
  3. 如果你坚持做出好的决定,你会有许多应得的好结果和一些不幸的坏结果。永远不要仅仅根据结果的质量来判断一个决定的质量。
  4. 不要玩彩票:如果最有可能的结果是失败,拒绝期望值最大的决定(除非没有更好的选择)。
  5. 不要拿最重要的东西冒险:如果最糟糕的结果是灾难性的,拒绝期望值最大的决定(除非没有更好的选择)。
  6. 使用工具来帮助评估决策。其中一个工具就是我在 https://vishesh-khemani.github.io/decisions/decision.html 的粗略原型。

参考

  1. 分析思维的格言 —丹·莱维

使可测量:关于算法的主观性,伽利略没有说什么

原文:https://towardsdatascience.com/make-measurable-what-galileo-didnt-say-about-the-subjectivity-of-algorithms-8d1d324253da?source=collection_archive---------16-----------------------

公平和偏见

关于如何衡量世界的选择意味着,并非所有的数据和算法都像它们看起来那样客观。

Diana PolekhinaUnsplash 上拍摄

伽利略的格言“测量能测量的,让不能测量的变得可测量”在今天的几乎每一个算法系统中都有回响。但在这些回声中回荡的是这样一个现实,即“制造”某种可测量的东西从来都不是纯粹客观的:它是主观选择的结果。承认这一点是防止算法造成伤害的关键。

将关于一件事物的“数据”视为它的真实表示似乎很直观。例如,我的身高是 5 英尺 9 英寸,伦敦是英国的首都——这两个数据点反映了现实。但是著名的统计学家 David Spiegelhalter 提醒我们,数据“几乎总是不完美的衡量我们感兴趣的东西”他指出,要数清地球上所有的树,我们必须首先定义什么算一棵树。有多种方法可以做到这一点,但并不是每个人都同意哪种方法是正确的。这是一个很好的提醒:有些人会说我更像 5 英尺 8 英寸半,这取决于你如何拿卷尺,爱丁堡、威尔士和贝尔法斯特呢?它们也都是英国的首都。

换句话说,使事物可测量的过程就是选择如何测量它们的过程。一个现象的哪些方面应该算?如何对这些方面进行分类和量化?将使用哪些指标?这些指标捕捉和反映了或没有捕捉和反映什么质量?这些选择通常会推动一个缩减的过程:将复杂的定性现象压缩成简单的数字数据:这个过程被称为数据化。

数据不是世界的完美反映,这一事实在数据科学中是众所周知的(所有的模型都是错误的,但有些是有用的。)然而,数据是许多算法的基础,这些算法越来越多地渗透并支持我们的数字社会。算法采用数据化的还原产物——关于如何使某些东西可测量的主观选择的产物——并通过固定的过程将它们硬编码成理应客观的输出。未能说明数据化的这种还原性质是许多算法伤害和失败的根本原因。

我们可以从两个例子中看出这一点:数字接触追踪和所谓的情感识别。

识别接触和追踪情绪

第一,数字接触追踪。在应对新冠肺炎疫情疫情时,公共卫生专家很快认识到,追踪接触者是应对病毒传播的关键。然而,手动接触追踪是费力的,需要相当多的时间和人力资源。政府和公共卫生机构想要一种可扩展以应对 Covid 挑战的接触者追踪模型。为了实现这一目标,许多国家寻求数字解决方案。

一系列联系追踪应用很快出现,主要基于蓝牙技术和由 Android 和 iOS 开发者支持的。每个应用程序的具体工作方式各不相同,但通常用户会下载他们国家的应用程序并处理日常事务。该应用程序记录了所有与它密切接触的其他手机的日志,通过蓝牙信号记录它们的接近程度。如果手机接触到另一个后来新冠肺炎病毒检测呈阳性的人,该应用程序会发送通知,警告用户进行自我隔离并接受检测。

理论上,这是一个很好的解决方案。不幸的是,数字联系追踪应用程序被证明不如手动联系追踪有效。这有许多可能的原因,从蓝牙传感器的精度到计算暴露的方式。但另一个主要原因是,这些应用根本没有真正进行联系人追踪。手动追踪接触者是一项高度复杂的任务,需要训练有素的专业人员通过面谈和其他方式详细绘制感染者的社会联系图。然而,蓝牙联系追踪不能做到这一点。取而代之的是,它只是记录“联系事件”(两部手机在一段设定的时间内彼此靠近,并开着蓝牙)。

换句话说,数字联系追踪应用是一种选择的产物,它将复杂的联系追踪任务简化为一个不完美的量化指标:手机之间的距离。这与对一个人的社会接触的丰富了解相去甚远,详细了解他们有什么互动以及他们之间传播病毒的可能性有多大。所有数字接触追踪应用程序可以测量的是蓝牙信号,而不是病毒传播。依赖这种主观定义的替代物作为接触的客观衡量标准,有可能导致公共卫生响应方面的差距,并转移人工接触者追踪工作的时间和金钱。

忽视数据化主观性风险的另一个例子是所谓的情感识别技术。在这里,危险远远超出了简单的无效,如蓝牙接触追踪,而是开始触及更深层次的社会不公和更广泛的技术科学伦理问题。

情绪识别系统是人工智能驱动的工具,声称它可以通过分析一个人的面部图像来识别他的情绪。微笑?你有 95%的机会开心。扮鬼脸?85%的几率你会觉得恶心。

问题是,这些系统大多是基于可疑的科学,表明人类情感有有限的、普遍的和特定的类别。此外,他们假设你脸上的表情是你内心情绪状态的直接反映,任何曾经笑过哭过的人都知道那不是真的。

当然,这些系统的支持者会争辩说,笑-哭是一种情绪的表达,这些系统只是需要一个能够识别它的类别。但这没有抓住重点。我们在任何时候的情绪状态都反映了我们的基因、我们的教养、我们的文化、我们目前所处的情况、房间里其他人的情绪、我们当时有多饿等等:情绪同时具有深刻的社会性、文化性和心理性。根据一些预先确定的、简单的类别,将所有这些都压缩到一个单一的、定量的概率计算中,这依赖于关于如何解释和分类所有这些定性因素的许多简化的和主观的选择。结果是,这里可测量的不是人类的情感,而是人脸可能形成的特定形状,一个粗糙的、可能有偏见的分类被置于顶部。

像情绪识别这样的算法工具对一些人来说很有吸引力,因为它们声称可以将难以置信的复杂现象变得简单。对其他人来说,吸引力在于这些算法可以提供比人类单独更深入或更真实的世界分析。但事实是,他们通常都不这样做。情感识别算法并不真正“识别”情感,它们只是检测表情并给它们贴上过于简单的标签。这就像把一个粘土十二面体强行穿过一个方孔,并且一直假装它是一个正方形。

在这两种情况下,接触追踪和情感识别,问题不一定是定量的分析方法。任何称职的统计学家或数据科学家都会指出,当对如何使某些东西可测量做出武断或简化的选择时,可能会出现缺陷。

问题是,这些算法系统采用这些简化的指标,并将其固定在一个没有细微差别、异常值或独特背景的技术流程中。他们采用现象,用基于一套主观的、有价值的和潜在偏见的观点的规则来解释它们,但吐出看起来客观的、没有主观性的陈述,因此被认为是真实的:追踪接触;情感确定。

选择如何使可测量的

回到伽利略,现代数据化和算法也使他的陈述成为简化论的受害者:它们侵蚀了“制造”一词的复杂性。正是在“制造”可测量的事物的过程中,价值、选择、偏见、缺陷、错误、疏忽等等悄悄进入数据集。在这种“使”可测量的过程中,事物被转化为量化的度量,这些度量只反映了那些选择所关注的现象的一部分。一旦这些数据集被纳入算法系统,这些选择就会被硬连线到技术成果中。凯西·奥尼尔的一句现代格言很好地描述了这一过程:“算法是嵌入代码中的观点。”

在我们的现代数字社会中,我们不会停止依赖算法。我们也不应该。当它们被精心设计时,它们会非常有效。但是数据科学和算法设计总是需要数据化的元素:使事物可测量总是需要主观选择。

关键是要更加适应这些选择,认识到这些选择是在何时、如何做出的,以及由谁做出这些选择,并承认算法的输入和输出永远不会不受主观性的影响,不管科技公司的营销可能宣称什么。承认算法的这种主观本质是设计它们对人类和社会产生更多积极和更少有害影响的关键。

让代码发挥最大价值

原文:https://towardsdatascience.com/make-most-value-of-your-code-8db8073fc43b?source=collection_archive---------20-----------------------

包装,把它们都包装起来,做自己的巨人

钥匙——作者根据钥匙

一个最聪明的人曾经说过:“如果我看得更远,那是因为我站在巨人的肩膀上”。作为一名数据科学家、数据工程师、机器学习专家、数据分析师或任何每天与数据、python 和朋友打交道的人,我们都知道自己是幸运的。我们站在 StackOverflow 的肩膀上,意思是一个巨大的社区。

做自己的巨人呢?利用你自己的见解,你的研究,以及你从成千上万的 StackOverflow 中提取的信息。我们都想做一些新奇的东西,研究最新的创新、技术和模型,但老实说,我们也经常做同样的模型、图表等。

那么,为什么不利用我们的代码,我们在这么多不同的笔记本中复制粘贴并稍微修改了这么多次?我们可以把它打包,把它们打包,所有这些我们多年来自豪地编写的函数和类打包。

📦构建您的私有包

利用你的工作的一个极好的方法是构建你的私人包。私人的,因为目的是不公开发表在 PyPi.org 或任何其他服务器上。

包装有许多优点:

  • 模块化:为了使代码最模块化,你需要大量的函数、类等
  • 轻松访问您的代码和更干净的 NB/脚本
  • 更多自动化
  • 可再现性(“隐藏状态”与可再现性相反,结果可能取决于您运行单元格的顺序,您定义的函数可能由范围外的变量提供)
  • 易于共享/协作
  • 您可以将模块设置为使用%load_ext autoreload、%autoreload 1 和%aimport module_name 自动重新加载
  • 测试(单元、集成)
  • 版本控制(众所周知,NB 很难版本控制)

🤔什么是包,它的基本组件是什么?

首先,它说明了构成 python 包的基本组件。我将使用一个基本模板给出结构并解释它们各自的作用。

一个基本的私有 python 包的结构,可以在 GitHub 上找到

  • pkgtemp:一个基本 python 包的模板,带有子包和模块
  • pkgtemp/sub_pkg1/modA.py中:类和继承的例子,用于说明
  • pkgtemp/sub_pkg2/modC.py中:用特殊方法比较对象的类的例子,用于说明
  • pkgtemp/sub_pkg2/modD.py中:使用特殊方法使对象实例可调用的类的例子
  • pkgtemp/__version__.py中:关于版本、作者等的所有细节。
  • pkgtemp/__init__.py中:默认为空,可以用来绑定上层包的子包和模块(更容易导入)
  • setup.py构建包的主文件
  • requirements.txt安装pkgtemp时被安装的依赖项
  • envs中,yaml 文件用于创建 conda python 环境,见下图
  • README.md登陆解释文件(包是做什么的,如何安装等等。)

可选文件和文件夹:

  • tests中:单元测试——这是可选的
  • docs中:包文档(通常带有 sphinx)
  • data中:您希望与您的包一起分发的数据,您应该提到在 setup.py 中
  • documentation附加文档中,(不随代码一起分发)
  • notebooks中,作为文档的替代,突出显示您的代码
  • scripts中,作为文档的替代,突出显示您的代码
  • egg-info中,包构建过程的所有输出——不要关心这个,它们将通过运行 setup.py 生成

模块

模块是一个*。包含 Python 代码的 py 文件。为了模块化,将代码分解成模块。python 模块只是一个包含代码的文件。模块化代码更容易使用。编码时(人类)记忆中保存的东西更少,滚动更少,当你必须找到一个特定的东西时知道确切的位置,把大问题分解成小问题,等等。

包裹

包是包含其他文件夹(子包)或模块(的集合)的文件夹。py 文件),以及特定的文件。如果满足某些要求,可以安装它。

假设您开发了一个包含几个模块的应用程序。随着模块数量的增长,如果将它们放在一个位置,就很难跟踪所有的模块。如果它们具有相似的名称或功能,尤其如此。您可能希望有一种方法来对它们进行分组和组织。包允许使用点符号对模块名称空间进行分层结构。模块有助于避免全局变量名之间的冲突,同样,包也有助于避免模块名之间的冲突。

包可以包含任意深度的嵌套子包。Python 中的每个包都是一个目录,其中必须包含一个名为__init__.py的特殊文件。这个文件可以是空的,它表明它包含的目录是一个 Python 包,因此可以像导入模块一样导入它

应用程序接口

API:Application Programming Interface(应用编程接口)的缩写,指的是通过抽象底层实现和只暴露开发者需要的对象或动作来简化编程的函数和类的集合。API 是多用途的,并不打算产生一个单一的输出(不是特别的),而是一个可以在不同的项目和任务中重用的工具。

例如,lightGBM 是用 C++编写的,但提供了几个 API:python、R 等。

💡你必须做什么来写你的私人包裹?

💻写一些代码

为了扩大您的工具堆栈,您可以收集并重构您发现对几个(至少两个)项目有用的代码,因为如果它对一个以上的项目有用,它很可能对未来的项目也有用(例如,在您需要执行回归的任何时候,不要从头重写您的 sklearn 管道)

最好是在收集和重构你的代码时,尽量让它不那么具体,更模块化。很可能您为特定的项目编写了代码,带有一些硬编码的名称、参数和变量值。尝试移除任何硬编码的部分,取而代之的是将它们作为函数/类的参数。

另外,尽量将函数和类整理到包含模块(*)的子包(子文件夹)中。py 文件)。例如

包、子包和模块的基本结构,如模板所示

用于收集您喜欢的绘图函数、模型比较类、lightGBM 包装器等。

📃记录您的代码

最好的方法是在重构代码的同时,也记录你的代码。使用您最喜欢的约定(NumPy、Pandas、Google 等)编写适当的文档字符串。).这将有助于你记住目的是什么,并使与同事的合作更加顺利。

🗃️创建了一个专用的 python 环境

创建专用的 python 环境。这将隔离您的项目;您不会破坏您的基础,如果您需要通过 conda 而不是 pip 安装一些包,这将允许您这样做(例如,conda-forge 的一些预建包)

  • conda create -n proj-env python dependency1 dependency2
  • conda activate proj-env
  • 当你安装了所有的 conda 依赖项,并且在转移到 pip 之前:conda env export > proj-env.yml如果你计划跨平台共享(Win-linux 或其他),你可以使用“no-builds”标志
  • 继续安装您的 pip 依赖项,并在requirements.txt中收集所需的包或使用pip list --format=freeze > requirements.txt

🖊️编辑 _ 版本 __。巴拉圭

编辑__version__.py以满足你的需求(作者、标题、版本号等)。)

  • title = 'pkgtemp '
  • _ _ description _ _ = ' python-pkg-temp-包模板项目生成器'
  • version = '0.0.1 '
  • __ 作者 __ = '威尔·史密斯'
  • _ _ author _ email _ _ = ' will . Smith @ Google . mars '
  • __ 许可证 __ = '麻省理工学院'
  • _ _ URL _ _ = ' https://github/will Smith/bad boys 4 '

🖊️编辑 setup.py

原则上,你可以让它保持原样。您可以编辑 EXTRAS_REQUIRE 和/或 classifiers=…以适应您的包。其他输入可在 version 中编辑。py 文件。

⛭安装你的软件包并使用它

非常简单,两步:

  • conda activate [ENV_NAME]
  • cd C:/[USER_NAME]/[pkg_name]的意思,setup.py 在哪里
  • pip install .如果您还在编辑您的包,请不要忘记时间段或pip install -e .

完成了!您可以导入您的包,并在不同的项目中重用您的函数和类。你可以在本笔记本中找到一个例子。

结论

打包是利用您的艰苦工作并构建一个令人惊叹的函数库和类库的一种极好的方式。这样你就可以重复使用你的代码,与你的同事分享,建立一个文件夹如果你是自由职业者,你可以对它进行版本控制和部署更新。

我们看到了如何构建一个不在公开渠道上发布的包来实现这一点。利用 GitHub,你也可以让它像pip install git+https://github.com/[GH_USER]/[REPO_NAME].git一样容易安装

我用它来包装我经常使用的库。比如,包装 lightGBM、CatBoost 和 Optuna,使它们具有一致的语法。而且还标准化了我的制图风格、基本 EDA 和我必须执行的所有重复任务。此外,我可以在工作中使用我在个人项目中所做的,反之亦然。我也可以很快地和其他人分享我找到的一些解决方法。

最后,当您对自己的软件包感到满意,并且认为社区可以从您的工作中受益时,您可以考虑以开源方式发布您的软件包。不知何故,偿还社区的债务💸

让熊猫跑得飞快

原文:https://towardsdatascience.com/make-pandas-run-blazingly-fast-3dbcd621f75b?source=collection_archive---------29-----------------------

你不需要再等了

Unsplash 上的 CHUTTERSNAP 拍照

我们都喜欢并使用熊猫。当我们作为数据探索者深入探索数据奥秘时,它是我们的日常伴侣。通常,我们处理大量的数据,如果我们的apply函数能够快速运行,我们会很高兴。

好了,不要再等了,我向你介绍。

我们将看到我们如何从这里开始:

资料来源:https://github.com/nalepae/pandarallel

对此:

来源:https://github.com/nalepae/pandarallel

泛平行函数

来源:https://github.com/nalepae/pandarallel

上面我们看到了可供我们使用的功能。

如何安装?

这个库在 pip 上是可用的,所以,只需要这样做:

pip install pandarallel

怎么用?

我们首先需要导入库。

from pandarallel import pandarallel

在这之后,我们需要调用.initialize()pandarallel发挥它的魔力。

pandarallel.initialize()

你会从 Pandarallel 收到一些关于你的设置的信息。

INFO: Pandarallel will run on 2 workers. 
INFO: Pandarallel will use Memory file system to transfer data between the main process and workers.

由于我使用的是 Google Colab,它不提供很多 CPU,所以我们只有 2 个工作人员。当你在你的机器上运行这个的时候,工人的数量将会更多,速度也会加快。所以,我们在这里看到的是加速的下限 T21。

现在,让我们看看魔法。

我们将首先创建一个大型数据框来测试 Pandarallel 的能力。

df = pd.DataFrame(dict(a=np.random.randint(1, 8, df_size), b=np.random.rand(df_size)))

我们创建了一个有五百万行的数据帧。

让我们创建一个应用于此数据框的函数。

**def** func(x):
    **return** math.sin(x.a**2) + math.sin(x.b**2)

使用 Pandas 的 apply() 函数:

%%time
res = df.apply(func, axis=1)

我们得到输出:

CPU times: user 2min 12s, sys: 1.64 s, total: 2min 14s 
Wall time: 2min 14s

上面我们得到的是未并行化的代码,需要 2 分 14 秒。

让我们看看由 Pandarallel 库并行化的代码

使用 Pandarallel 的 parallel_apply() 函数:

%%time 
res_parallel = df.parallel_apply(func, axis=1)

我们得到输出:

CPU times: user 780 ms, sys: 271 ms, total: 1.05 s 
Wall time: 2min 2s

所用的时间是 2 分 2 秒,比上面未并行化的代码所用的时间少,即 2 分 14 秒。节省了时间(12 秒),即使我们只使用 2 个工作线程(1 个工作线程= CPU 中的 1 个实际内核)。

如果你不满意,这里有一个库的作者做的基准测试。

来源:https://github.com/nalepae/pandarallel

在 4 个内核(即 4 个工作线程)上,我们看到时间减少得更多。

结论

只需在函数调用中做一个简单的改变,我们就能让我们的熊猫代码获得巨大的加速。这绝对是一件好事,因为数据处理需要花费大量时间,让我们远离数据分析。

阿布舍克·维尔马

  • 如果你喜欢这个,请关注我的Medium了解更多
  • 我们来连线一下LinkedIn
  • 看我在 Kaggle 上的作品。

使用 CFFI Python 绑定提高 Python 速度

原文:https://towardsdatascience.com/make-python-faster-with-cffi-python-bindings-eb5402bc35dd?source=collection_archive---------17-----------------------

从 Python 中的任何 C 库中调用函数。准备好起飞了吗?

图片来自 Pixabay维基图片

Python 是最用户友好的编程语言之一。它易于学习,免费使用,并且您可以随意扩展它的功能。

此外,Python 可以说是数据科学和机器学习领域最常用的编程语言。优秀的数字库,如 NumPy 和 SciPy,以及卓越的深度学习框架,如 PyTorch 和 TensorFlow,为每个喜欢玩数据和人工神经网络的程序员创建了一个庞大的工具库。

另一方面,Python 是一种解释型语言,它可以设置代码执行速度的上限。在 AI 和大数据的世界里,这不是一件好事。所以,我们确实有矛盾。Python 如何成为该领域使用最多的编程语言?我们能做些什么让它更快?

好吧,我们可以用另一种语言(例如,C 或 C++)编写我们要求高的函数,并利用特定的绑定从 Python 调用这些函数。这就是这些巨大的数字库或深度学习框架所做的事情。因此,如果你是一名数据科学家或机器学习工程师,想要调用 CUDA 函数,这个故事适合你。

学习率是为那些对 AI 和 MLOps 的世界感到好奇的人准备的时事通讯。你会在每周五收到我关于最新人工智能新闻和文章的更新和想法。在这里订阅!

CFFI

在上一篇文章中,我们用标准 Python 库的一部分库ctypes做了同样的事情。我们看到了什么是编组,以及 Python 在内存管理方面与 C 有何不同。最后,我们通过一个简单的例子看到了ctypes如何帮助我们调用 C 函数。

在这个故事中,让我们和 CFFI 一起更上一层楼。

CFFI 对 ctypes

ctypes可能是 Python 标准库的一部分,但是所有这些类型声明都容易出错,并且它不能扩展到大型项目/

此外,ctypes允许您将共享库直接加载到 Python 程序中。另一方面,使用CFFI,您可以构建一个新的 Python 模块,并像导入任何其他 Python 库一样导入它。

装置

CFFI不是标准库的一部分。因此,要使用它,我们需要先安装它。我们可以使用 Python 包管理器pip轻松做到这一点:

$ python3 -m pip install cffi

请注意,建议使用 Python 虚拟环境来遵循本教程,以避免全局安装 Python 包。这可能会破坏系统工具或其他项目。

简单的例子

在这个例子中,我们将从的m库中调用一个函数。我们将使用这个函数来得到一个数的平方根。

第一步是创建一个 python 文件,该文件将构建一个具有我们需要的功能的 Python 模块;提供所有好东西的图书馆。

为此,复制并粘贴以下代码:

在这个例子中,您从的m库中用sqrt函数创建了一个绑定。首先,在set_source方法中,传递想要构建的 Python 模块的名称(例如_libmath)。

您还包括来自的m库的math头文件,因为我们使用的是来自C标准库的库,所以我们不需要在library_dirs中提供库的位置。

最后,您可以像运行任何其他 Python 脚本一样运行该脚本:

$ python3 build_cffi.py

这将产生.o和一个.c文件。让我们看看如何使用这个调用的输出。

从 Python 调用 C

现在您已经准备好从C调用sqrt函数。这就像运行下面的代码一样简单:

首先,从您创建的库(即_libmath)导入 lib 模块。在内部,您可以找到对sqrt函数的绑定。最后,您可以用任何浮点数调用这个函数。

您也可以创建到其他函数的绑定。例如,要创建与m库的sincos函数的绑定,只需在cdef中声明它们:

ffibuilder.cdef("""
    double sqrt(double x);
    double sin(double x);
""")

结论

Python 是最用户友好的编程语言之一,也可以说是数据科学和机器学习领域中使用最多的编程语言。

另一方面,Python 是一种解释型语言,它可以设置代码执行速度的上限。但并不是所有的希望都破灭了;我们可以用另一种语言(例如,C 或 C++)编写要求苛刻的函数,并利用特定的绑定从 Python 调用这些函数。

在上一篇文章中,我们讨论了ctypes以及如何使用它从 Python 中调用C库。在这篇文章中,我们使用了一种更加自动化的方法,并看到了如何使用CFFI来实现这一点。

接下来:我们将看到如何利用 Cython 来加速我们的 Python 代码!

关于作者

我的名字是迪米特里斯·波罗普洛斯,我是一名为阿里克托工作的机器学习工程师。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲央行、经合组织和宜家等主要客户设计和实施过人工智能和软件解决方案。

如果你有兴趣阅读更多关于机器学习、深度学习、数据科学和数据操作的帖子,请关注我的 MediumLinkedIn 或 Twitter 上的 @james2pl

所表达的观点仅代表我个人,并不代表我的雇主的观点或意见。

让 Python 和 C 一样快

原文:https://towardsdatascience.com/make-python-run-as-fast-as-c-9fdccdb501d4?source=collection_archive---------10-----------------------

理解大数据

用 Numba 实现更快的 Python 代码

照片由夏洛特·科内比尔Unsplash 上拍摄

速度问题

虽然 Python 被广泛接受,主要是因为其精简的语法,可以作为一种很好的原型语言,但它也有一个缺点,在“编程语言战争”式的辩论中经常提到:速度。与其他编程语言相比,Python 对于标准基准算法的运行时间要慢得多。

我自己创造的

从计算机语言基准测试游戏上的二叉树基准测试来看,Python 的 48.03 秒比不上 C++的 0.94 秒或 C 的 1.54 秒。由于是一种解释型和动态类型语言,Python 允许极快的原型速度,但无法与 C++、C、Fortran 以及其他几种编译语言的运行时间竞争。

快速原型制作+快速运行时间= Numba

Numba 通过一个针对 Python 的实时(JIT)编译器,结合了快速原型和快速运行时的优点。真正的意思是你的代码只能在运行时编译,而不能在运行前编译。这样做,Numba 使您能够将 Python 代码的速度提高“一到两个数量级”。[2]然而,使用 Numba 的实际速度增益在很大程度上取决于每个特定的用例,因为该项目侧重于科学计算应用。

安装 Numba

Numba 最大的优势之一是易于使用。与加速 Python 的其他方法所需的或多或少复杂的安装过程相反,Numba 可以使用pipconda完全安装。

这两种方法都非常简单,应该可以在大多数数据科学环境中开箱即用。使用 Anaconda,conda install numba将安装所有需要的东西。pip install numba也是如此。

何时使用 Numba

一旦安装,Numba 可以帮助 Python 代码运行得更快。然而,有三个主要的标准作为指导方针来确定 Numba 对于特定任务的适合程度,以及它加速 Python 的潜力。

  1. 如上所述,Numba 专注于加速科学应用。因此,代码包含的数学运算越多,Numba 就能提供越多的帮助。
  2. 与第一个标准相关,Numba 与 NumPy 配合得特别好。有可能,专注于数学运算的 Python 代码将包含大量的 NumPy。然而,需要注意的是 Numba 并不支持所有的 NumPy 函数,有些函数可能需要在原始 Python 和受支持的 NumPy 函数中实现才能使用。
  3. 循环越多越好。通常,当代码包含几个非常长的循环时,Numba 可以节省大量时间。

打开涡轮增压器

使用 Numba 的另一个原因是它与其他 Python 代码集成的方式。使用 Numba 的唯一要求是为需要加速的函数添加一个装饰器。

来自 Numba 文档的代码

在上面的例子中,decorator @jit(nopython=True)向 Numba 发出信号,让它以 nopython 模式运行,而不是 Numba 的替代对象模式。默认情况下,nopython 参数设置为 false,即使它生成的代码要快得多,这是因为它限制了所支持的 NumPy 函数的数量。除了@jit(nopython=True),你也可以使用简写@njit

由于 for 循环和对数学计算的关注,monte_carlo_pi函数的代码至少满足了 Numba 的三个有前途的用例中的两个,添加@njit装饰器应该会提供一个不错的性能提升。

我自己创造的

虽然该函数的纯 pythonic 版本在向其传递大约 1 亿个样本时开始大幅减慢,但等效的 Numba 版本保持了更高的性能水平,两个选项之间的相对差距只会随着计算负载的增加而扩大。

更多装饰

**懒编译是指让 Numba 决定如何优化代码。一般来说,这种方法实现起来很快,并且最大限度地减少了可能出现的错误。装饰器向 Numba 发出懒惰编译的信号。

我自己创造的

此外,惰性编译还将允许您保留更高程度的灵活性。本质上,它可以给 Python 函数一个不错的速度提升,同时仍然允许高原型速度。

**急切编译允许对函数的签名进行更多的控制,这可以提高代码的可读性(以及潜在的性能)。同时,指定签名也会降低代码的灵活性,并可能导致容易被忽略的错误。签名被添加到要优化的函数之上的装饰器中。例如,@jit(int64(int64))描述了一个将整数作为输入并返回整数的函数。Numba 还允许通过以下语法在签名中指定数组:@jit(int64(int64[:]))。前面提到的签名将指定一个整数数组作为函数的输入,一个整数作为函数的输出。

我自己创造的

正如在急切编译的介绍中所暗示的,快速原型化会导致未被发现的错误。函数f()的签名需要一个整数数组,并将返回一个整数。当传递数组[1,2,3,4]时,正确的结果应该是10 + 2.5 = 12.5。然而,由于函数的签名,上面的函数调用将返回12而不抛出异常。例如,产生预期结果的签名应该是@jit(float64(int64[:])。因此,当使用 Numba 进行急切编译时,正确地制定每个函数的签名是非常必要的。

然而,Numba 的 jit 装饰器的最强大的变体是@jit(nopython=True)或等价的@njit。通过激活 nopython 模式,正在讨论的函数将不会使用 python 的 C API,并产生更快的代码。与@jit相反,强制 Numba 使用 nopython 模式将防止退回到较慢的对象模式,但也需要更多时间密集的开发准备,同时也不太宽容。在对象模式下运行将允许使用其他标准的数据科学包,如 Pandas,而 nopython 模式则不能。

摘要

虽然 Numba 的能力比本文中描述的方法更深入,但是很好地掌握和理解如何使用@jit decorator 是从看似永无止境的循环向更好地执行科学代码迈出的一大步。

当谈到快速原型和实验时,Numba 通过其快速的安装过程和易用性完美地集成了 Python。不需要安装全新的编译器或者用不同的语言混合 Python 代码,使用 Numba 可以让 Python 编码人员立即投入工作,像没有 Numba 一样专注于他们的代码。

我自己创造的

然而,Numba 并不是一个适合所有人的方法。每个潜在的用例都应该单独检查,因为通过使用 nopython 模式节省更多的时间是以不能使用像 Pandas 这样的标准数据科学包为代价的。因此,根据一般经验,大多数应用程序可能从让 Numba 通过@jit装饰器完成所有优化工作中受益匪浅。另一方面,需要尽可能少的运行时间的高级用例需要更多的时间投入,以使它们与 Numba 兼容,这是因为该项目具有丰富的生态系统和广泛的功能。

来源:

[1]“二叉树。”计算机语言基准游戏。2021 年 8 月 2 日接入。https://benchmarks game-team . pages . debian . net/benchmarks game/performance/binary trees . html

[2]“农巴。”Numba 文档—Numba 0 . 53 . 1-py 3.7-Linux-x86 _ 64 . egg 文档。2021 年 8 月 2 日接入。https://numba.readthedocs.io/en/stable/index.html.

在一行 Python 代码中实现现有 Matplotlib 绘图的交互

原文:https://towardsdatascience.com/make-your-existing-matplotlib-plots-interactive-in-a-single-line-of-python-code-8a6d1673ba2d?source=collection_archive---------24-----------------------

使用 matplotlib 库的交互式小部件,而不是内联绘图

图片由 Michal Jarmoluk 来自 Pixabay

探索性数据分析是数据科学模型开发流程中的一个重要元素。EDA 帮助数据科学家更好地理解数据变量和它们之间的关系,并揭示超越正式建模或假设检验的任务。Matplotlib 是一个流行的 Python 绘图库,它提供了一个面向对象的 API 来将绘图嵌入到应用程序中。

有很多开源库可以生成交互式的情节,包括 Bokeh,Altair,Plotly。在本文中,您可以通过添加几行 Python 代码,了解如何在 Jupyter 笔记本或 Jupyter Lab IDE 中使现有的 matplotlib 内联绘图具有交互性。这可以通过使用两个开源库ipywidgetsipympl来实现。

入门指南

首先安装**ipywidgets** (也称为 jupyter-widgets)库,该库将在内部用于创建小部件。该软件包为 Jupyter 笔记本和 IPython 内核提供了交互式 HTML 小部件。

**ipymlp** 是另一个将 IPython 笔记本转换成易于编辑的 YAML 文件的 Python 包。使用**ipymlp**的好处是你可以完全兼容 IPython 笔记本,并且能够在任何文本编辑器中编辑文件。

安装:

这两个包都可以从 PyPl 安装,使用:

**pip install ipywidgets --user
pip install ipympl --user**

安装必要的软件包后,使用以下方式启用widgetsipympl 扩展:

**jupyter nbextension enable --py --sys-prefix widgetsnbextension
jupyter nbextension install --py --symlink --sys-prefix ipympl**

现在,由于您希望所有的 matplotlib 图都作为小部件,您可以使用%matplotlib magic 命令更改外观。

  • 使用%matplotlib inline magic command,绘图命令的输出在 Jupyter notebook 之类的前端内联显示,就在产生它的代码单元的正下方。
  • 使用%matplotlib widget将您的所有绘图作为一个小部件

用法:

使用**%matplotlib widget** 更改后端后,使用 matplolib 包生成的图出现在一个小部件框内。figure canvas元素是一个适当的 Jupyter 交互式小部件,可以以交互式小部件布局格式定位。现在不是静态的内嵌 matplotlib 图,而是具有一些给定功能的交互式图。将出现小组件框:

(图片由作者提供)

使用上面的交互式绘图,您可以更改绘图的大小,平移和缩放绘图。人们也可以选择缩放和呈现给定的 x 和 y 坐标矩形的绘图。

下面的 GIF 描述了一个人如何在时间序列图中盘旋并从中获得洞察力。

(作者 GIF)

结论:

Matplotlib 小部件是一个方便的工具,它的主要优点是不需要在 Python 代码中做任何这样的修改。还有各种其他的 Python 包,包括 Plotly、Altair、Boker,它们可以生成交互式图形,但是需要首先适应新库的 API 功能。

阅读下面提到的的文章作者 Pier Paolo Ippolito 可以更好地了解其他绘图库,包括 Plotly、Bokeh 等。

参考资料:

[1] Ipympl GitHub 库:https://github.com/matplotlib/ipympl

感谢您的阅读

在 Python 中进行库存模拟

原文:https://towardsdatascience.com/make-your-inventory-simulation-in-python-9cb950da8cf3?source=collection_archive---------3-----------------------

在本文中,您将在 Python 中创建一个定期补货策略的模拟。不到 30 行。

本文摘自我的著作 库存优化:模型与模拟 。你可以在这里 阅读我的其他文章 ,在这里 订阅我的博客 。我也活跃在LinkedIn上。

西奥多·加勒(1571-1633)大约在 1600 年(后来着色)雕刻的“新发现”的卷首。来源

在使用 Python 编写库存模拟代码之前,让我们花点时间来定义我们将要模拟的库存策略:一个定期补货的库存策略。

库存政策:定期补货

遵循定期补货政策的产品会根据固定的时间表和最高水平定期订购。

定期补充。来源:我的库存培训

在任何评估期的开始,我们需要订购足够的产品,以使我们的净库存达到水平 S 。从上图中可以看出,订单数量取决于我们下单时的库存数量,因此是可变的。另一方面,订单是按照固定的时间表生成的:两个连续订单之间经过的时间总是相同的。

这种定期补货策略实际上是供应链中最常见的,因为它经常被 MRP/DRP 的广泛使用强加到供应链上。这些工具遵循预定义的时间表—通常是每天或每周—这导致了定期审查策略的隐含使用。

固定评审期政策通常被称为(R,S),其中 R 是固定评审期, S 是 up-to-level。

优势

定期补充允许企业将他们的订单分组给他们的每个供应商。这有助于客户和供应商简化他们的操作,因为他们可以提前计划订单和工作量。

限制

  • 🛡️ 风险。这种定期策略比连续策略(您可以在任何时间点下订单)风险更大,因为它会产生盲点:您不能在两个审核期之间下订单。如果你每周五向供应商下订单,但在周一晚上缺货,你将不得不再等四天才能下新订单。同时,你可能会因为缺货而损失销售额。这比固定再订购点政策风险更大,在固定再订购点政策下,你会在周一晚上直接下新订单。
  • ️📦可变订货量 y .另一个问题是,每份订单的订货量会有所不同。这可能会破坏平稳的操作流程。例如,如果您有一个货盘化的产品,您可能不想移除整个货盘周围的包装来运输一个单元。

连续保单呢?

在持续策略中,我们根据固定的阈值订购产品。一旦净库存达到阈值(或低于阈值),我们就向供应商要求预定数量的单位(或启动生产批次)。这个阈值称为再订购点或 ROP。

连续保单假设客户可以随时向其供应商订购。实际上,情况可能并非如此。例如,供应商可能一个月只接受一次订单(或者一个月只发一次货——这是一样的)。在这种情况下,认为您会遵循固定的再订购点政策是不合理的,因为供应商实际上是在遵循自己的日历。因此,在实践中,真正的连续策略是例外的(一些完全自动化的生产流程或内部流程可能遵循这些假设)。

定期审查与持续政策。来源:我的库存培训:【https://supchains.com/live-training/

在开始你的第一个库存模拟之前,你可能想阅读我以前的文章,库存优化,它为优化策略奠定了基础。

模拟设置

需求和供应链

让我们从定义变量 time — 开始,它将设置我们模拟的持续时间。然后,我们可以填充遵循正态分布的需求数组。

import numpy as np
time = 200
d_mu = 100
d_std = 25
d = np.maximum(np.random.normal(d_mu, d_std, time).round(0).astype(int),0)

在这个模拟中,我们假设我们的需求是正态分布且严格为正。通过改变你设置它的方式,你可以随意改变这个假设。

然后,我们可以定义策略的其余输入,并计算各种参数。

from scipy.stats import norm
L, R, alpha = 4, 1, 0.95 
z = norm.ppf(alpha) 
x_std = np.sqrt(L+R)*d_std

请注意,我们将 x_std 计算为超过风险范围的需求偏差,风险范围是我在书中虚构的。

接收订单需要等待的最长时间。在此期间,您的库存有被耗尽的风险。

*https://nicolas-vandeput.medium.com/inventory-optimization-5-ways-to-set-service-level-and-safety-stock-targets-cc3a9a5f44b

您可以在下图中看到我们的策略(和模拟)在第一个时间步中的表现。在时间步长 0 结束时做出的订单将在时间步长 5 期间可用。

模拟和库存策略的工作原理。来源:库存优化:模型和模拟

库存水平

让我们使用常用的安全库存公式来设置不同的库存水平。

  • 📦周期股 Cs在一个补货周期内满足预期需求(或预测)所需的库存。
  • 🛡️ 安全库存不锈钢保护供应链免受需求变化(或预测错误)和供应缺乏可靠性影响的库存。
  • 🚚在途库存不同地点之间的在途库存。通常,这些是从供应商处订购的货物,但还没有在我们的仓库中提供给我们的客户购买。
Ss = np.round(x_std*z).astype(int) 
Cs = 1/2 * d_mu * R 
Is = d_mu * L 
S = Ss + 2*Cs + Is

https://nicolas-vandeput.medium.com/the-4-biggest-mistakes-when-using-the-safety-stock-formula-1f3cc93bcb1

由于我们的传入订单可以在运输途中停留多个周期(在我们的示例中,有 4 个周期),我们将把 transit 定义为一个二维数组。

hand = np.zeros(time, dtype=int) 
transit = np.zeros((time,L+1), dtype=int)

正如您在下表中看到的,新订单将从第二维结束时开始( transit[time,-1] ),然后通过第二维久而久之(每周期一层),直到到达最后一个槽( transit[time,0] )。最后一个时段意味着此在途库存将在本期期末收到(换句话说,从下一期开始可用)。

来源:库存优化:模型和模拟

服务水平

我们还必须创建两个对象来跟踪策略的服务级别:

  • stock-out_period 将包含一个 Boolean 值,用于标记某一期间是否缺货。
  • stock-out_cycle 将为每个订单周期(即审核周期)包含一个布尔值,用于标记我们在上一个周期的任何时候是否缺货。
stock−out_period = np.full(time, False, dtype=bool)
stock−out_cycle = []

模拟初始化

我们现在必须为第一个时间步长初始化这些数组。初始现有库存和净库存是 S 减去第一个期间的需求。第二个期间的在途库存初始化为第一个期间的需求。

hand[0] = S − d[0]
transit[1,−1] = d[0]

如何模拟库存策略

我们现在可以开始模拟了。以下是在每个时间步 t 执行的主要步骤:

  1. 检查我们在期初是否收到订单( transit[ t-1,0] > 0 )。如果是这样,我们需要通过检查上一期间是否有缺货来计算周期服务水平。
  2. 通过减去需求 d[t] 并加上接收库存运输[t-1,0] 来更新现有库存
  3. stockout_period[t] 中指出我们是否缺货。
  4. 更新净库存头寸 net[t]
    记住是总在途库存 transit[t]。sum() 加上现有库存手【t】
  5. 通过将先前时间步长的值偏移 1 来更新在途数组: transit[t,:-1] = transit[t-1,1:] 。这代表了订单在供应链中移动的事实。
  6. 如果我们处于评审期( t%R==0 ),我们根据当前净库存头寸net【t】和合格水平 S 进行订购。然后,订单被存储在在途数组 transit[t,L] 的末端。
for t in range(1,time): 
  if transit[t−1,0]>0: 
    stockout_cycle.append(stockout_period[t−1]) 
  hand[t] = hand[t−1] − d[t] + transit[t−1,0] 
  stockout_period[t] = hand[t] < 0
  transit[t,:−1] = transit[t−1,1:]
  if 0==t%R: 
    net = hand[t] + transit[t].sum() 
    transit[t,L] = S − net

你可以在这里下载我的书的摘录(共 100 页):https://supchains.com/books/

报告

最后,我们可以创建一个数据框架 df 来保存我们的模拟结果,并将它们绘制在类似下图的图表上。

df = pd.DataFrame(data= {'Demand':d, 'On−hand':hand, 'In−transit':list(transit)}) 
df = df.iloc[R+L:,:] #Remove initialization periods 
print(df)
df['On−hand'].plot(title='Inventory Policy (%d,%d)' %(R,S), ylim=(0,S), legend=True)

我们还可以打印周期和期间服务水平。

print('Alpha:',alpha∗100)
SL_alpha = 1−sum(stockout_cycle)/len(stockout_cycle)
print('Cycle Service Level:', round(SL_alpha∗100,1))
SL_period = 1−sum(stockout_period)/time
print('Period Service Level:', round(SL_period∗100,1))

下一步是什么?

模拟对于优化不符合通常假设(常态、固定交付周期、无销售损失等)的策略是有说服力的。).上面的代码只是模拟驱动库存优化的第一步。

如果你想玩这个新工具,

  • 查看不同的安全库存水平和提前期可以带来多大的库存变化和服务水平。
  • 尝试不同的需求概率函数(如泊松或伽玛),看看它们与正常假设有何不同。您也可以使用自定义发行版。*

攻击神经网络

原文:https://towardsdatascience.com/make-your-neural-net-confuse-dogs-with-pelicans-af7ad6ec95a5?source=collection_archive---------24-----------------------

使用 PGD 攻击为神经网络制造视错觉。

图标由平面图标photo3idea-studio 组合而成,作者(【marcelmoos.com】T4

我们来看看下面两张图:

图片来自安娜·杜德科娃的Unsplash

左图是一只德国牧羊犬,右图是一只美丽的鹈鹕……至少根据最先进的神经网络来看是这样的。我们将探索如何从左边的图片为右边的神经网络创建视错觉。您甚至可以创建我们的狗图像的版本,顶级图像分类器可以将它与您喜欢的任何东西相混淆,从花椰菜到敞篷车。如果你更喜欢代码而不是文字,这里有一个交互式 Jupyter 笔记本。通过它,你可以关注和调整这个故事的一切:colab . research . Google . com/drive/1 fl 0 px 0g 4 ppdlycmrerp-PS blf 4 ftzug?usp =共享

答几年前,我在学习神经网络时做的第一件事就是训练一个简单的图像分类器。神经网络可以很好地分辨图像中的内容。然而,有一件事我当时没有问过自己:“这些网络到底在学什么?”

让我用一个例子来解释我的意思:我们人类是如何识别狗是狗的?我认为我们应该寻找一些与众不同的特征,比如尖耳朵、鼻子、尾巴、四条腿以及类似的东西。然而,对于神经网络来说,其他东西可能是必不可少的。他们在寻找什么,比如一只狗,这可能是一个相当神秘的事情。这种现象在我称之为神经网络的视错觉中变得非常明显。令人着迷的是,它们是 而不是 对人类的幻觉。

下图包含一只漂亮的德国牧羊犬。神经网络不仅正确地将它归类为狗,甚至将其归类为正确的品种。而且它对自己的决定有 93 %以上的把握,所以这里一切都好。

现在问题来了。我们来看看下面这张图:

该图像几乎是前一个图像的完美副本。剧透:不是!你必须非常仔细地观察才能看出不同。背景不是绿色的,画面似乎有点嘈杂。但对人类来说几乎是察觉不到的。我想我们都同意,每一个接受第一张图片显示的是一只德国牧羊犬的人都会对这张图片说同样的话。所以我们的神经网络也应该仍然声明它看到一只德国牧羊犬有大约 93 %的把握,对吗?错了。我们的神经网络现在 100%确定它看到了一只鹈鹕:

好吧,这里发生了什么?我们使用的分类器是一个 50 层的 残差神经网络 (resnet)。它在 ImageNet 数据集上进行了预训练,这是一个包含 1000 个不同对象类的庞大图像集合。接下来,我们使用了一张我们的 resnet 正确分类的德国牧羊犬的图片。

为了给我们的 resnet 创建视错觉,我们取原始图像并稍微改变原始图像的像素。我们只改变正确的像素,resnet 对我们可爱的狗最敏感的像素。

下图显示了我们需要改变多少像素来欺骗我们的分类器。因为像素变化非常小,我把它们放大了 10 倍,所以我们可以看得更清楚:

因此,我们改变了原始图像稍微偏蓝和偏红。还有,一些像素点变亮了一点。在我们看来,这些变化几乎不存在。但是对我们的 resnet 来说…哦,天哪…它改变了一切。现在看到鹈鹕就彻底服气了。最棒的是,它不一定是鹈鹕。这一招基本上适用于任何职业。我们可以欺骗神经网络,让它认为我们的狗是花椰菜、打印机或其他任何东西。此外,每一个像样的图像分类器都容易受到这些视错觉或者——它们在文献中如何被称为——对抗性图像的影响。

现在的问题是,我们如何找到这些混淆我们的分类器的像素变化?我们如何自动创造这些视错觉?

自动愚弄神经网络

我们对狗的形象所做的改变非常微小,但也非常具体。手动寻找这些扰动是不可行的。幸运的是,有各种不同的技术,也称为攻击,可以自动创建这些视错觉。其中一种攻击叫做投影梯度下降(PGD)** 。为了理解 PGD,我们首先需要快速提醒自己神经网络是如何使用梯度下降进行学习的。**

梯度下降

神经网络包含权重。改变权重会影响神经网络的输出。为了训练一个神经网络,我们需要量化它的答案与正确答案的偏差程度。这是通过损失函数来完成的。一旦定义了损失函数,我们就可以计算损失函数相对于网络权重的梯度。直观地说,(负)梯度告诉我们如何改变网络的权重,以使损耗尽可能快地减少,这意味着它的答案尽可能快地变得更正确。

基于梯度下降的学习图解。(图片由作者提供)

对训练集中的所有图像反复进行这种操作会得到一个训练好的网络。在高层次上,这概括了基于梯度体面的学习。

PGD 攻击

恭喜,如果你理解梯度下降,你就已经理解了 PGD 攻击。对于 PGD 攻击,我们采用网络并定义一个新的损失函数。对于我们的德国牧羊犬形象,我们希望它被归类为鹈鹕(或任何你喜欢的)。现在,类似于基于梯度下降的训练,我们计算梯度。

然而,我们不是根据网络的权重(那些是固定的)来计算梯度,而是根据图像的像素来计算梯度。直观上,这种梯度告诉我们如何改变图像的像素,以便网络尽快认为这是一只鹈鹕。

PGD 攻击的插图(没有最终投影)。(图片由作者提供)

差不多就这样了。我们应用这些变化并继续,直到神经网络实际上将我们的图像分类为一只鹈鹕。

你可能会问,PGD 的 P 、投影*在哪里发挥作用。PGD 攻击允许我们为每个像素定义一个变化极限。每个像素的所有颜色通道都采用 0 到 255 之间的值。对于 PGD 攻击,我们可以指定任何像素都不应该改变超过 10 个点。每当一个像素受到超过 10 个点的干扰时,该像素被投影到其允许的一组值。*

Python 包

幸运的是,我们不需要了解所有的细节并从头开始重新实施 PGD 袭击。有一个令人惊叹的 python 包叫做fool box(【github.com/bethgelab/foolbox】T2),它支持 PGD 攻击(以及更多)并兼容 TensorFlow 和 PyTorch。使用 Foolbox,从德国牧羊犬图片生成我们的鹈鹕敌对图像既简单又快捷:**

*criterion = TargetedMisclassification(pelican_label)
attack = PGD()
adv_input = attack.run(net, german_shepherd, criterion, epsilon=10)*

如果你想自己生成对抗性的图像并运行和调整代码,我强烈建议查看 Jupyter 笔记本:colab . research . Google . com/drive/1 fl 0 px 0g 4 ppdlycmrerp-PS blf 4 ftzug?usp =分享

结论

从一张我们的分类器正确标记为德国牧羊犬的照片中,我们创建了一张敌对的图像——神经网络的一种视错觉——显示了同一只狗,但被我们的网络误分类为鹈鹕。创造这些视错觉可能是一项有趣的练习。然而,在现实生活中,敌对的图像可能会产生严重的后果。试想一下,一辆自动驾驶汽车将停车标志误标为限速标志。有一些技术可以抵御敌对的图像,但那是另外一个故事了。

觉得这个故事有趣?你可以在这里成为一个中等会员来支持我的写作:medium.com/@mmsbrggr/membership。你将获得所有媒体的访问权,你的部分会员费将直接支持我的写作。

欢迎在 LinkedIn上向我提出私人问题和评论。如果你喜欢这篇文章,让我告诉你我的时事通讯:marcelmoos.com/newsletter

以下是另外三个你可能感兴趣的故事:

*** ***

用记忆让你的神经网络更聪明:神经图灵机

原文:https://towardsdatascience.com/make-your-neural-network-smarter-with-memory-neural-turing-machines-e5601b3123b6?source=collection_archive---------27-----------------------

将神经网络与记忆系统结合起来,可以像人类一样学习通用算法。请继续阅读,了解更多信息。

Lyman Hansel Gerona 在 Unsplash 上拍摄的照片

计算机很神奇,因为它们执行任意算法的速度比人快几个数量级。神经网络很神奇,因为它们可以学习特定的东西(开车、下棋等。)远胜人类。然而,还没有一个神经网络将这两者结合起来——在任意算法上的卓越性能。直到 2014 年,一篇关于“神经图灵机”的论文发表。本文作者将标准神经网络与类似计算机的记忆系统相结合,发现这种新型网络能够学习一些简单的算法,例如复制粘贴。我认为这是一个惊人的成就,所以让我们仔细看看它是如何工作的。

首先,我们先明确一下“学习简单算法”是什么意思。复制粘贴算法就是这样一种算法。基本上,给定一系列任意大小的输入向量,我们希望输出与输入相同。现在你可能会问——这不就是身份函数吗?当然,即使是最简单的神经网络也能学会!这是真的——神经网络可以学习给定输入大小的的身份函数。神经网络无法学习适用于任何输入大小的任意身份函数。您可以自己尝试:训练一个神经网络来学习长度为 10 的向量的恒等函数,然后测试长度为 20 的向量的准确性。性能会很差。总而言之——我们的目标是用单个神经网络学习算法的一般形式,而不仅仅是算法的一个具体情况。

计算机擅长算法的一般形式。例如,当您在文本编辑器中进行复制(Ctrl-C)和粘贴(Ctrl-V)时,所选文本有多长并不重要。计算机将完美地执行任意长度的复制-粘贴。计算机如此擅长这类算法的部分原因是因为它们的记忆系统。基本上,这个记忆系统让计算机存储输入,对这些输入进行处理,并在以后需要时检索它们。相比之下,神经网络拥有的唯一“存储”是网络权重的值。砝码的容量远小于计算机上千兆字节的内存。这就是为什么我们要给神经网络添加一个记忆系统——提供许多算法成功执行所需的存储空间。

那么研究人员是如何实现记忆系统的呢?这个想法很简单。“内存”是一个 N x M 维的大型二维矩阵,N 行中的每一行代表一个内存单元。n 和 M 是网络运行前设置的超参数。下一步是定义如何读写这个内存。这更棘手。根据所学的算法,我们可能只需要读取矩阵中的一行,或者矩阵中的所有行。也有可能一些行比其他行更重要。为了适应所有这些情况,我们引入了长度为 n 的权重向量 w_read 。从存储器的“读取”则是所有矩阵行的加权和:σ(w _ read _ I)*(row _ I)。(在本文的其余部分,向量将被加粗,标量将是常规字体)

写入存储器更复杂。首先,我们需要决定如何处理内存中的现有行。因此,我们需要另一个参数 e 。这个参数是一个长度为 M(与行相同)的向量,具有 0 到 1 之间的各个分量。 erow_i 之间的元素乘积决定了 row_i 剩余多少。例如,如果 e 的所有组件都是 0,这意味着我们不想保留任何 row_i 。如果 e 拥有所有 1 个组件,这意味着我们想要保留所有的 row_i 。而如果 e 在中间某处,我们更想保留 row_i 的某些组件。注意 e 对于所有行都是相同的。

一旦我们决定保留什么,我们接下来必须添加任何新的信息。因此,我们有另一个参数 a 添加到每一行。最后,我们有一个权重向量 w_write ,它决定了对数组中每一行的写操作的大小(或“重要性”)。因此每行的总更新量为row _ I _ new=erow _ I _ old+w _ write _ Ia

我们现在已经描述了如何从内存矩阵中读取和向内存矩阵中写入单独的行。我们这样做是根据一些参数: w_read,w_write,e,a 。自然的问题是——这些参数从何而来?回想一下,总体目标是将神经网络与记忆系统结合起来。因此,我们将这些参数作为我们系统的神经网络部分的输出。更准确地说,我们将建立一个神经网络,它有两个输出区域:读头和写头。网络的读头区负责输出读取所需的参数: w_read 。同样,网络的写头区会输出写参数: w_write,e,a 。最后,读取头的输出作为整个系统的输出返回。****

图片作者。

这种架构的一个主要优点是整个事情都是可微分的。请注意,所有读/写操作对于每个组件来说都是线性的,因此是可区分的。这使得网络在概念上易于训练:只需找到每个分量相对于输出的梯度,然后进行梯度下降。

丰富

在这一点上,我们有一个原型网络,其中包含了一个记忆系统。然而,仍然有可以改进的地方。这些改进大多围绕着 w_readw_write 向量,如果您还记得的话,它们决定了每个内存行在读或写中的相对重要性。正因为如此, w 向量通常被称为寻址向量,参考了计算机中内存寻址的思想。就像现在的网络一样,寻址向量由读写头直接输出。

我们可以对寻址向量的产生方式进行各种修改。首先,不是让读写头输出 w ,而是让它们输出一个键向量 k 。那么我们可以做几件事:

  • 算法中一个常见的用例是根据 k 获取内存中的特定行。实现这一点的直观方法是对所有行使用余弦相似性,并基于这些余弦相似性对 w 的分量进行加权。我们称之为内容聚焦
  • 如果我们不想要一个基于内容的特定行( k ),而是想要一个特定的常量行呢?例如,我们可能正在学习一个在第 5 行存储重要内容的算法。我们如何总是访问第 5 行?这被称为位置聚焦。首先,我们可以让读写头输出一个门加权值** g。门加权值是一个介于 0 和 1 之间的标量,它决定了保留多少先前地址 w_(t-1) 与保留多少当前地址 w_(t) 。换句话说,更新方程是w (t) new =g*** w _(t-1)+(1—g)w _(t)。在我们强调的用例中(在每个时间步访问第 5 行),神经网络最终会找到一个聚焦于第 5 行的 w ,然后将 g 设置为 1,以在未来的时间步中保持该 w*
  • 另一个常见的用例是循环,我们希望内存地址在每个时间步长增加一个常数。我们可以通过使读写头输出一个代表地址的每个部分增加多少的移位加权来实现这一点。例如,如果 s=2,那么 w 的所有分量都移动 2。因此,如果先前的 w = [0.1,0.7,0.2,0](集中在第 2 行),随着移位的应用 w = [0.2,0,0.1,0.7](集中在第 4 行)。

寻址机制的这些改进为神经网络提供了更多的工具来访问它在内存中想要的行。相应地,我们应该看到准确性的提高。整个网络的更新示意图如下所示:

图片作者。

这是一个简单的版本,论文作者称之为“神经图灵机”(NTM)。在论文中,我们描述的各种组件更加复杂,但思想是相同的。如前所述,尽管 ntm 比常规神经网络要复杂得多,但它们很容易训练,因为所有组件都是可微分的。因此,训练上述 NTM 的方式是将网络/存储器初始化为一些值,决定成本函数,并简单地运行梯度下降。

有用吗?

是的。实验表明,ntm 比常规神经网络更好地学习一些算法。让我们考虑一下我们在开始介绍的复制粘贴问题:取一个输入向量序列,输出相同的序列。论文作者在这项任务中训练了两个不同版本的 NTM,以及一个 LSTM。下表显示了结果:

图片作者。

各行代表每种网络类型的误差(单位为每序列位数)。这些列表示(以千计)到达该点需要多少训练序列。例如,第一列意味着通过 50000 个训练序列,NTM/LSTM 具有接近每个序列 0 比特的误差,NTM/前馈网络具有 0.2 的误差,而 LSTM 具有 8.2 的误差。

正如你所看到的,这两个 NTM 变种学习复制粘贴问题比常规神经网络(LSTM)快得多。一旦学习完成,它们也具有较低的误差(注意,LSTM 的渐近成本约为每个序列 0.5 比特,但是两个 ntm 的渐近成本接近于 0)。研究人员还检查了两个经过训练的 NTM 网络中网络和记忆之间的交互模式,并意识到该模式可以用下面的伪代码来概括:

****初始化矩阵,写/读磁头到开始位置

****而(输入不是分隔符):

  • 将输入写入写入磁头位置
  • 将写磁头增加 1

****而(真实):

  • 从读取头位置读取输出
  • 将读取头增加 1

这太神奇了。虽然并不完美,但这段伪代码显示了 NTM 学会了像人类一样复制粘贴。这是我第一次看到神经网络以如此可理解、直观的方式学习东西。通常神经网络有一个“黑箱”问题——它们学习东西,但我们无法理解它们。这里不是这样的。****

另一件重要的事情是,研究人员采用了在大小为 20 的序列上训练的 NTM,并应用 NTM 来复制粘贴更长的序列。至关重要的是,尽管 NTM 犯了一些错误,但它总体上仍然工作正常。相比之下,常规的神经网络(在 LSTM 的论文中)不能推广到长度超过 20 的序列。前面我们提到过,我们想学习算法的一般形式,而不是特定的版本——看起来 NTM 成功地实现了这个目标。

研究人员还对 ntm 进行了其他任务的训练,如联想回忆和数据分类。我们不会在这里进入细节,但一般来说,NTMs 优于常规神经网络,并能够学习任务的通用算法。更多详情,请阅读原文论文

ntm 是神经网络架构中一个真正令人兴奋的发展。他们能够学习一般形式的算法,这是以前的网络无法做到的。正因为如此,我认为 ntm 是通往真正智能的关键一步。我很高兴看到这种基于记忆的想法的进一步发展。如果您有任何问题/意见,请告诉我,感谢您的阅读!

让你的神经网络更小:修剪

原文:https://towardsdatascience.com/make-your-neural-networks-smaller-pruning-da1fcdb6f206?source=collection_archive---------31-----------------------

剪枝是使神经网络更经济的重要工具。请继续阅读,了解它是如何工作的。

Unsplash 上的 C D-X 拍摄的照片

神经网络的一个问题是它们的大小。你在在线教程中看到的神经网络足够小,可以在你的计算机上有效运行,但工业中的许多神经网络都很庞大,难以操作。它们通常需要几天来训练,运行它们会消耗大量的计算能力。这就提出了一个问题:在保持测试集准确性的同时,有没有可能减小神经网络的规模?事实证明,是的。有一种叫做“修剪”的技术可以做到这一点。还有一个被称为“彩票假说(LTH)”的想法,它让我们深入了解为什么修剪会有效。在本文中,我们将首先查看剪枝算法,然后讨论 LTH。

修剪是一种简单、直观的算法。有许多变体,但基本思想适用于任何神经网络。想法是这样的。在一个大型的、经过训练的神经网络中,会有一些具有较大幅度的权重和一些具有较小幅度的权重。自然,具有大幅度的权重对网络输出的贡献更大。因此,为了减小网络的大小,我们去除(修剪)小幅度的权重。要修剪的小幅度权重的确切数量由用户设置——大约 10%是合理的。问题是,一旦发生这种情况,网络就不再被正确训练。因此,在修剪小幅度的权重之后,我们需要再次训练网络。我们可以根据我们想要使网络有多小来任意次数地进行这个循环(修剪->训练)。

样本剪枝算法的两次迭代。红线代表修剪后的权重。图片作者。

修剪的一个好处是它确实有效。有大量的经验证据支持它。更具体地说,修剪已经被证实可以在降低网络规模(内存)的同时保持准确性。有什么不好的地方吗?是—完成清理过程可能需要很长时间。prune- >训练循环的每一次迭代都要花费大量时间,尤其是在网络很大的情况下。我们可以通过增加每次迭代期间修剪的权重的数量(例如,从 10%到 20%)来减少循环的数量,但是这样循环的每次迭代需要更长的时间。总而言之,修剪是有效的,但是需要一段时间才能完成。

还有一个问题是,最终修剪后的子网可能会有一个奇怪的体系结构,权重会出现在看似随机的地方。因为现代代码/硬件仅针对少数神经网络架构进行了优化,所以有可能修剪后的网络虽然更小,但实际上可能需要更多的时间来运行。这些权衡是否值得取决于具体的用例。

现在我们转到一个更有趣的问题:为什么修剪会起作用?如前所述,我们知道修剪适用于许多流行的神经网络架构。这导致了一个假设,即许多神经网络被过度参数化。换句话说,存在一个更小但仍然有效的网络(通过剪枝找到)的事实意味着在原始网络中有太多的参数。

另一个问题是为什么剪枝算法选择最终的权重。回答这个问题的一个有趣尝试是彩票假说。这篇论文中的研究人员声称,通过修剪选择的最终子网是因为该子网的初始初始化而被选择的。

他们通过以两种不同的方式执行 prune->train 循环得出了这个结论。第一种方法,在每次训练循环之前,他们随机初始化所有剩余的(未修剪的)权重。第二种方法是,在每次训练循环之前,他们对所有剩余的权重使用初始初始化。他们发现,使用原始初始化显著提高了剪枝算法的最终精度和训练速度。因此,研究人员假设最初的初始化是剪枝算法选择什么子网背后的驱动因素。然而,不清楚为什么会这样。起初,研究人员认为剪枝算法喜欢在训练期间不变的权重(即剪枝算法更喜欢接近最终值的原始权重初始化)。然后他们测试了这个理论,实际上发现正好相反。修剪算法选择在训练期间变化最大的权重。为什么会这样,这意味着什么,这仍然是一个悬而未决的问题。

总之,有实验证据表明,修剪产生的子网络与权重的初始初始化有关。建筑怎么样?所选子网的架构可能很特别,这似乎是很自然的。已经有一些研究表明深度网络比浅层网络更有效地表示某些假设类别(多项式对指数)。对于修剪后的子网来说,可能存在类似的情况。但是,我没有找到任何实证或理论论文来支持这个理论。

总体来说,有两个关键点。首先,修剪起作用(需要一些时间权衡)。第二,修剪肯定与原始网络的初始化有关,也可能与体系结构有关。感谢阅读,并请留下任何问题/评论!

使用 Azure 认知服务制作您自己的有声读物

原文:https://towardsdatascience.com/make-your-own-audiobook-using-azure-cognitive-service-fbc0cbc7a224?source=collection_archive---------28-----------------------

我们过去购买有声读物的日子已经一去不复返了,现在是时候使用 Python 和 Azure 认知服务了

一张由亚伦·伯登Unsplash 上拍摄的图片

L ets 说你已经有了一本书的 PDF 版本,这本书是你从某些来源(可能是免费的)获得的,你没有时间一行一行地阅读它。也可能发生的情况是,你不想花钱买它的音频版本,或者可能它的音频版本不可用。那么这篇文章就送给你了。在本文中,您将看到如何使用简单的 python 脚本和 Azure Cognitive service 的文本到语音功能制作自己的有声读物。但是首先让我告诉你一些关于有声读物的事情。

什么是有声读物?

有声读物(或有声读物)是大声朗读的一本书或其他作品的录音。完整文本的阅读被描述为“未删节的”,而较短版本的阅读则是删节的。”— [维基百科](https://en.wikipedia.org/wiki/Audiobook#:~:text=An audiobook (or a talking,shorter version are an abridgement.)。

市场上有许多服务可以为你提供有声读物。一些受欢迎的有有声手写有声读物等等。但是所有这些都要收取订阅费。

所以,让我们开始建立自己的有声读物。为此,请确保您具备以下先决条件。

先决条件:

  1. 确保你已经在你的电脑上安装了 Python 3.5 或更高版本。万一你没有,那么你可以从官网安装。在我的电脑上,我安装了 Python 3.6,所有这些演示都将基于它。不要担心,如果你使用的是最新的 Python 3.9,不会有任何不同。
  2. 接下来,我们需要一些能帮助我们处理 PDF 的东西。因为 Python 有一个很棒的库,可以充当 PDF 工具包,名为 PyPDF2 。你也可以看看它的完整文档。
  3. 我们还需要一个 Azure 账户来使用 Azure 认知服务。但是等等,我们在寻找制作免费有声读物的方法,对吗?是啊!别担心,我会告诉你免费的东西。

安装— 1:

首先,我们将安装 PyPDF2。对于,请打开终端或命令提示符,并键入:

pip install PyPDF2

现在,如果你第一次使用 Python(或者 pip ),你很可能会得到一个错误,比如“PIP 不被识别为内部或外部命令……”。这基本上意味着你没有为 pip 设置路径。下面我会给出一篇文章的链接,详细解释如何解决这个问题。

https://medium.com/swlh/solved-windows-pip-command-not-found-or-pip-is-not-recognized-as-an-internal-or-external-command-dd34f8b2938f

虽然我们需要一些其他的库,但是让我们先看看如何使用 pdf。

阅读 PDF 文件:

我们的 PyPDF2 库可以对一个 PDF 文件进行各种各样的操作。其中我们会用到它的阅读能力。为此,我们首先需要创建一个 python 文件(一个带有。py 作为扩展名)并导入库。

import PyPDF2

然后我们将创建一个名为 book 的对象,我们将用它在阅读模式下打开我们的 pdf。

book = open(**"yourPdfName.pdf"**,**"rb"**)

这里需要注意的重要一点是 pdf 的位置。上面的代码假设所需的 pdf 与 python 文件位于同一文件夹中。如果它在不同的文件夹中,那么你有两个选择。1:将文件(pdf 或 python)移动到与其他文件相同的文件夹中。2:给出 pdf 文件的确切位置。假设我的 pdf 在桌面中,那么我会写“C:\ \ Users \ \ sag Nik \ \ Desktop \ \ yourpdfname . pdf”。这将解决问题。

现在可能会有一个问题,什么是“rb”写到最后。“rb”基本上是文件处理中使用的一种存取方式。要了解 Python 中其他访问模式或文件处理的更多信息,请参考 Python 文件处理。

https://stackabuse.com/file-handling-in-python/

到目前为止,我们只是打开了我们的 PDF 文件。现在我们需要指定一个读者,他可以阅读我们的 pdf 并从 pdf 文件中逐页提取文本。为此,我们将使用下面几行代码。

reader = PyPDF2.PdfFileReader(book)

**for** num **in** range(0,reader.numPages):
    text = reader.getPage(num).extractText()
    # print(text)

这里对象读者利用 PyPDF2 库来阅读我们的书。之后,它遍历书的每一页,并通过使用基于页码的 for 循环从中提取文本。如果你想知道它会显示什么样的文本,你可以去掉“#”,看看它会显示什么。甚至你可以将它与你的 pdf 中的文本进行匹配。

现在我们得到了我们的文本,我们唯一剩下的事情就是把它转换成语音并听它。为此,我们将使用 Azure 认知服务。要了解更多关于认知服务的信息,您可以访问下面的链接。

https://azure.microsoft.com/en-in/services/cognitive-services/#overview https://docs.microsoft.com/en-us/azure/cognitive-services/what-are-cognitive-services

文本到音频:

为了使用 Azure 认知服务,你需要一个 Azure 账户。但是我们需要免费得到它,对吗?为此,请访问 Azure 注册页面并选择开始免费来创建您的新 Azure 帐户。你也可以观看这个 YouTube 视频来获得设置免费账户的帮助。

如果你是一名学生(像我一样),那么你有三种不同的选择来获得 Azure 帐户并免费使用。

  • 为学生使用 Azure。但是这需要你使用你的大学电子邮件 id (an )登录。edu 邮箱)。如果你的学校没有提供这样的课程,那么你有下面两个选择。

https://azure.microsoft.com/en-in/free/students/

  • 使用 GitHub 学生开发者包。这个包还有大量其他高级设施。这给了你 100 美元的 Azure 信用。

https://education.github.com/pack

  • 成为微软学生学习大使。该计划每月为您提供 150 美元的 Azure 信用点数和许多其他好处,包括 MTC 代金券和免费域名。我个人非常热爱这个社区。

https://studentambassadors.microsoft.com/

在我们获得 Azure 账户后,是时候创建一些 Azure 资源了。但是为什么呢?为此,我们需要了解 Azure 认知服务的定义。

认知服务让每个开发人员都可以接触到人工智能,而不需要机器学习专业知识。只需一个 API 调用,即可将看、听、说、搜索、理解和加速决策的能力嵌入到您的应用中。使所有技能水平的开发人员能够轻松地将人工智能功能添加到他们的应用程序中。

现在我们可以清楚地看到,为了嵌入认知服务的工具,我们需要进行 API 调用。要进行 API 调用,我们需要一些键和端点。这将由我们的 Azure 资源提供。

获取我们的语音 API 密钥:

第一次登录 Azure 门户网站。它看起来会像下面这样。

使用我的帐户登录时 Azure portal 的屏幕截图

然后我们将前往创建一个资源并点击它。寻找左上角的大加号(+),你会在那里找到选项。

创造言语资源的过程。我的账户截图。

在这里你可以找到 Azure 提供的所有可用服务的列表。现在在搜索栏中搜索语音,如上图所示,并点击回车。然后,您可以看到如下所示的页面。

来自我的帐户的屏幕截图

现在点击创建来创建你的 Azure 语音资源。它现在会问你一个名字。给你的资源起一个有意义的名字。这个名字可以帮助你以后找到你的资源。对我来说,我选择“learnoverflow”作为它的名字,因为我们从这篇文章中的学习应该是溢出的。

订阅区域选择一个订阅或创建一个您想要使用的新订阅。这基本上决定了 Azure 费用将如何向您收取。但是不要担心,这次你不会收到任何账单。我将在接下来的几个步骤中解释如何操作。

它还要求一个位置。这意味着你想在哪个领域使用资源。Azure 是一个全球平台,它为你提供了大量可以创建资源的位置。但是,为了从您的资源中获得最佳性能,请选择离您最近的位置。

创建语音资源时来自我的 Azure 帐户的图像

接下来是重要的部分,这是定价层。对于语音资源,您将获得两种类型选项:1 .自由 F0 ,2。标准 S0。两者各有不同的优势和好处。如果您使用免费的低容量语音服务层,即使在免费试用或服务点数过期后,您也可以保留此免费套餐。显然我们这次将使用免费的 F0 作为我们的资源。这是免费使用这一资源的关键。如果你对所有的定价等级都感兴趣,你可以看看语音服务定价

资源组部分,为该语音订阅创建一个新的资源组,或者将该订阅分配给一个现有的资源组。资源组是一个容器,通过在一个地方保存相关资源,帮助您组织各种 Azure 订阅。

现在,您已经填写了所有详细信息,只需单击“Create”并等待几秒钟进行资源分配。

您会看到这样的通知,说明您的部署正在进行中。图片来自部署资源后我自己的帐户。

在这里,您可以看到您的资源得到了部署。来自我自己的 Azure 帐户的图片

现在,单击“转到资源”访问您的资源。

您的资源页面。创建资源后,来自我自己帐户的图像

在上图中,您可以看到资源的所有详细信息。但是我们正在寻找 API 密钥,对吧。在总览页面(每次打开资源时你都会进入的主页面)上,我们没有那么多工作要做。

现在看左边的面板(上图),我用红色标记了一些东西,这是键和端点。我们所有的 API 密钥和其他必需的信息都在这个选项卡中。点击后,你会发现类似下图的东西。

来自我自己的 Azure 帐户的图片

在这里,您可以看到有两个 API 键。任何一个密钥都足以访问你的认知服务 API。我们需要 Python 代码中的一个键和位置。你可以把它们记在记事本上以备将来参考,也可以根据需要直接进入本页查找。

使用我们的 API 密钥:

现在打开您的 Python 代码编辑器,开始实现您刚刚获得的 API。但是在此之前,我们需要准备本地机器来处理这样的 API 调用。为此,我们需要安装一些 Python 包。

安装— 2:

我们需要认知服务语音 SDK Python 包。为此,我们将再次使用 pip 命令。

pip install azure-cognitiveservices-speech

这个包裹对我们会很有帮助。

实现 API 密钥:

我们将从导入刚刚安装的语音库开始。将此内容添加到我们之前编写的上一条 import 语句之后的第二行。

import azure.cognitiveservices.speech as sdk

之后,我们将把 API 键和区域分配给 Python 代码中的一个变量。这是我们订阅信息的基本设置。在我们之前写的 for 循环开始之前保留这些语句。

key = "YourSubscriptionKey"
region = "YourServiceRegion"

用创建 Azure 资源后获得的密钥和区域替换 YourSubscriptionKeyYourServiceRegion 。之后,我们将使用下面的代码创建一个带有订阅密钥和服务区域的语音配置实例。

config = sdk.SpeechConfig(subscription=key, region=region)

我们将继续使用默认的扬声器作为音频输出来创建我们的语音合成器。这将作为人工产生的人类声音。

synthesizer = sdk.SpeechSynthesizer(speech_config=config)

现在,我们将进入我们之前创建的 for 循环来阅读我们的书的每一页。我们的方法是将我们阅读的每一页的文本制作成音频。但是如果你愿意,你也可以修改代码来获得整本书的文本,然后通过下面的代码传递它。

result = synthesizer.speak_text_async(text).get()

还记得我们之前创建的变量文本吗?现在是将收到的文本合成语音的时候了。一旦您的 Python 解释器执行了上面的行,那么您就可以期望您的扬声器播放写在特定页面上的文本。

一旦你听到一个声音从你的电脑扬声器或从你的耳机连接到你的电脑,你肯定你终于做了自己的有声读物。万岁!!!

完整实施:

如果你希望看到这个程序的运行,那么在最后我会链接一个 YouTube 视频,你可以通过视频格式浏览整篇文章。但在此之前,让我讨论一些重要的事情。

运行此程序时可能出现的问题:

如果你是第一次使用这个 Azure 语音库,你可能会遇到一些问题。它可能会提示“azure 不被识别为内部或外部命令”,即使你已经用上面写的命令安装了正确的库。为了避免这些,请确保在实际安装 Speech SDK 之前更新您的 pip。让我们假设你已经安装了语音 SDK,现在你得到这些错误,然后如何解决?

在这种情况下,您首先需要卸载您的语音 SDK。

pip uninstall azure-cognitiveservices-speech

然后使用下面的命令升级 pip。总是建议在安装任何库之前确保您的 pip 已更新。

python -m pip install --upgrade pip

然后使用之前使用的相同命令安装 Azure speech SDK。

这将解决你的问题。无论如何,你仍然面临同样的问题,那么你可能需要使用下面的命令安装 azure。

pip install azure

但是不要担心,升级您的 pip 肯定会解决您的问题。

你可以对此做很多改进。要一遍又一遍地听某本书,你不需要再次运行这个程序。实际上,您可以将生成的音频保存为您想要的音频格式。你也可以创造自己的声音。以及更多其他的东西。但是请记住,并不是所有的特性都属于自由层 API。如果你感兴趣的话,你一定可以查看使用这种文本到语音转换功能的完整文档

查看有声读物的运行情况:

最后,当你成功地制作了有声读物,是时候听它了。但是这篇文章是书面文件,它不可能在这里显示最终输出。因此,下面是一个视频实现的整个过程中,它的建设,如本文所示。跳到 23:00 仅查看其实施情况。希望这能帮助你。

结论:

在本文中,我们介绍了基本有声读物的实现,它可以使用几行 python 代码和 Azure 认知服务阅读整本书。有声读物的最终音频结果并不是最好的,因为文本在馈送到扬声器引擎之前需要一些预处理。

感谢您的阅读!

我是微软学生大使 Sagnik Chattopadhyaya。你可以访问我的网站来了解我。

推特: @sagnik_20 。YouTube: 学习溢出

希望你能从这个故事中学到一些东西。❤

快乐学习!🐱‍💻

使用 Surprise 制作您自己的书籍和电影推荐系统

原文:https://towardsdatascience.com/make-your-own-book-and-movie-recommender-system-using-surprise-42cc1c840a19?source=collection_archive---------23-----------------------

Juraj Gabriel 在 Unsplash 上拍摄的照片

我花了几年的博士时间来构建推荐系统,并从头开始对它们进行基准测试,只有当我完成它时,我才听说了 sikit 图书馆的惊喜。

GIF by GIFY

这是我以前就想知道的一个惊喜。这将节省我的时间和精力来实现许多推荐系统基线。

所以我想在这里分享关于这个库的信息,并给出一些关于如何使用它的代码,因为它可能会帮助其中一个读者。让我们开始吧!

什么是惊喜?

Surprise(代表简单 Python 推荐系统引擎)是一个 Python 库,用于构建和分析处理显式评级数据的推荐系统。它提供了各种现成的预测算法,如基线算法,邻域法,基于矩阵分解(奇异值分解,PMF,SVD++,NMF),以及许多其他算法。此外,各种相似性措施(余弦,MSD,皮尔逊…)是内置的。来源:http://surpriselib.com/

我将在两个不同的数据集上使用 Surprise:

  1. 建立一个电影推荐系统。
  2. 建立图书推荐系统。

在这两种情况下,我将使用协作过滤技术和基于内容的技术来过滤项目,不用担心我会解释它们之间的区别。

使用 Surprise 构建电影推荐系统

安装惊喜

pip install surprise

读取数据集

我在这里使用的是 MovieLens 数据集。它包含 2500 万用户评级。数据在。/data/raw 文件夹。我们可以直接加载。csv 文件,具有内置的惊喜功能,但为了以后的灵活性目的,通过 Pandas 数据框加载它会更方便。

出于复杂性考虑,我只使用了这个数据集的一个子集,但是你可以全部使用。然后,我将评级上传到一个惊喜数据集对象,该对象按顺序包含以下字段:

  1. 使用者辩证码
  2. 电影 Id
  3. 相应的评级(通常在 1-5 的范围内)

训练和交叉验证协同过滤模型

协同过滤方法依赖于用户的偏好以及系统中其他用户的偏好。这个想法是,如果两个用户是志同道合的(在过去就项目的一些偏好达成一致),与一个用户相关的项目被推荐给另一个用户,反之亦然。他们仅从用户项目评级矩阵中获得推荐。来源:[我的博士论文报告](https://boa.unimib.it › phd_unimib_799490)

Surprise 实现了一些协作算法,如奇异值分解、NMF 等。

0it [00:00, ?it/s]RMSE: 0.9265
RMSE: 1.0959
Computing the msd similarity matrix...
Done computing similarity matrix.1it [00:12, 12.72s/it]RMSE: 0.9919
RMSE: 0.9299
RMSE: 1.1025
Computing the msd similarity matrix...
Done computing similarity matrix.2it [00:26, 13.54s/it]RMSE: 0.9915
RMSE: 0.9270
RMSE: 1.0996
Computing the msd similarity matrix...
Done computing similarity matrix.3it [00:42, 14.14s/it]RMSE: 0.9905

训练基于内容的过滤模型

基于内容的过滤方法分析与用户相关的项目的一组特征,并基于这些特征学习用户简档。过滤过程基本上包括将用户简档的特征与项目内容(即项目简档)的特征进行匹配。来源:[我的博士论文报告](https://boa.unimib.it › phd_unimib_799490)

因此,这里我将直接依赖于项目属性,即电影标题。首先,我必须用属性向量描述一个用户概要文件。然后,我将使用这些向量来生成基于相似性度量的推荐。

大多数基于内容的过滤方法是基于启发式模型,该模型在向量空间模型中将用户和项目表示为 TF-IDF(或 BM25)的向量。

我在这段代码中使用了 TF-IDF,它考虑了在一个文档中频繁出现的术语(TF =term-frequency),但在语料库的其余部分很少出现的术语(IDF = inverse-document-frequency)。

由于项目和用户简档被表示为 TF-IDF 的向量,所以项目以与用户相似度递减的顺序被推荐
(用户简档以项目的相同形式表示)。最常见的度量是余弦相似性,我将在下面使用它来计算两个配置文件之间的相似性。

假设用户想要电影《山达基和信仰的监狱(2015)》中最‘相似’的 10 部电影。

Recommending 10 products similar to Going Clear: Scientology and the Prison of Belief (2015)...
-------
	Recommended: Soulless 2 (2015) (score:0.09111541613391295)
	Recommended: Víkend (2015) (score:0.09111541613391295)
	Recommended: No Longer Heroine (2015) (score:0.06179864475000222)
	Recommended: In the Shadow of Women (2015) (score:0.06179864475000222)
	Recommended: Marco Polo: One Hundred Eyes (2015) (score:0.05026525144746273)
	Recommended: Ugly American, The (1963) (score:0.0)
	Recommended: Snitch Cartel, The (El cartel de los sapos) (2011) (score:0.0)
	Recommended: Drone (2014) (score:0.0)
	Recommended: Kenny Rogers as The Gambler (1980) (score:0.0)
	Recommended: Le Rossignol (2005) (score:0.0)

构建图书推荐系统

这将是一个类似于上面的代码,但应用于不同的数据集。

我使用了 Kaggle 上可用的 goodbooks-10k 数据集。它包含评级和图书 csv 文件。第一个包含超过 53,000 个用户对 10,000 本书的评级数据。第二个文件包含 10,000 本书的元数据(标题、作者、ISBN 等。).

我通过 Github 分享了书籍和电影推荐系统。

结论

就是这样!您可以将此推荐系统代码模板应用于任何您想要的数据。在接下来的几天里,我还将分享关于上下文推荐系统以及如何实现它。

所以,敬请期待!

GIFGify

通过缓存让您的 Python 代码运行得更快

原文:https://towardsdatascience.com/make-your-python-code-run-faster-with-caching-87bee85e9002?source=collection_archive---------6-----------------------

使用“functools”中的“cache”和“lru_cache”

照片由克莱德·杜克派克斯拍摄

提高 Python 代码的速度非常重要。它不仅能节省时间,还能减轻机器的负荷。提高程序性能的一种方法是缓存。

在这篇文章中,我将讨论什么是缓存,什么时候使用缓存,以及如何在 Python 中使用缓存。

查看我以前的一篇文章,关于使用爱因斯坦符号编写更好更快的 Python。

何时使用缓存

您可以通过实现缓存策略来加快 Python 代码(或任何代码)的速度。这个想法是存储一个函数的结果,这样在将来的调用中你就不必重新计算或再次检索结果。这在使用重复参数多次调用资源密集型或时间密集型函数时非常有用。

  • 你不应该缓存一个依赖于外部变量的函数。(例如time()random())。
  • 你不应该缓存有副作用的函数。

从服务器检索数据时,缓存也很有用。我们可以在本地存储(缓存)数据,而不是每次需要数据时都请求服务器。但是,如果我们的缓存空间有限,或者缓存的数据会随时间而变化,我们可能需要一个缓存策略。

缓存也可以在服务器本身上实现。我们可以缓存内容并从缓存中提供给用户,而不是每次用户加载页面时都查询数据库。然后,每隔一段时间更新我们的缓存。

缓存策略

高速缓存可能出现的一个问题是高速缓存太大。虽然您可以创建无限的缓存,但最好不要这样做。为了克服这一点,我们可以在缓存时使用许多策略。这些策略描述了何时从缓存中清除值。

先进先出(FIFO)

FIFO 缓存流程图。图片作者。

第一个添加到缓存中的值是第一个被逐出的值,依此类推。当较新的条目最有可能在我们的程序中被重用时,最好使用这种策略。

后进先出法

后进先出缓存流程图。图片作者。

就像先进先出但相反。最后一个加到缓存中的值是第一个被逐出的值。当旧条目最有可能在我们的程序中重用时,最好使用这种策略。

最近最少使用(LRU)

LRU 缓存流程图。图片作者。

这可能是最著名的策略。名字说明了一切。它会清除最近最少使用的值。但这意味着什么呢?

当您调用缓存函数时,结果被添加到缓存中(这就是缓存的工作方式)。但是当您使用已经缓存的值调用缓存函数时,它会返回缓存的值并将其放在缓存的顶部。
当缓存满时,最底部的值被删除。

在这种策略中,最近使用的条目最有可能被重用。

基于时间的缓存

这更适合缓存函数随时间变化的情况。添加到缓存中的每个条目都有一个过期时间,过期后就会被清除。到期时间通常被称为生存时间(TTL)。

Python 中的缓存

简单缓存实现

让我们考虑一个我们想要缓存的函数func。一个简单的方法是将我们的函数包装在另一个函数中:cached_func并使用一个全局字典来保存值。每当叫cached_func的时候,我们就查字典。如果对于传递的参数存在一个值,我们返回它,否则我们从func中获取该值,并将它添加到字典中并返回它。

为了简化函数的缓存,我们可以创建一个通用的缓存包装器。

要使用我们的包装器,我们有两个选择。

  • 使用简单的函数调用。

  • 使用装修工。

使用 functools 中的装饰器

Python 在functools : cachelru_cache中配备了缓存装饰器。cache是无界缓存,而lru_cache是 LRU 缓存。

使用这些装饰器很简单。

lru_cache接受两个可选参数:

  • maxsize=128 : 缓存的最大大小。
  • typed = False:函数参数是否被类型化。比如66.0是不是一回事。

如果您正在使用方法和类,您可以像使用cachelru_cache一样使用functools中的cached_property

除了我们讨论的以外,还有更多关于缓存的内容。从服务器和 cdn 到 CPU 和 GPU,缓存无处不在。

当处理纯函数时,缓存应该是显而易见的。在 Python 中需要两行代码。然而,还有其他重要的方法可以让你的代码更高效。

使用 pytest fixtures 提高 python 测试的效率

原文:https://towardsdatascience.com/make-your-python-tests-efficient-with-pytest-fixtures-3d7a1892265f?source=collection_archive---------7-----------------------

了解 pytest 夹具的基础知识

PC:蓝钻画廊 ( CC BY-SA 3.0 )

如果你是一个测试新手,或者如果你被分配去修复一些测试失败,或者如果你最近实现的一个很棒的新特性崩溃了💥任何现有的测试用例,你都不得不走进软件测试的厄运☠️。

尤其是在使用 pytest 的情况下,您可以看到(👀)许多奇怪的包装器/装饰器位于测试文件中的函数之上。这些包装器中最常见的是@pytest.fixture()。什么是❓测试夹具

维基说,

一个测试夹具是一个用来持续测试一些项目、设备或软件的环境。在测试电子、软件和物理设备时,可以找到测试夹具。

让我们微调一下我们的问题,什么是计算中的测试夹具???

软件测试夹具通过初始化来建立软件测试过程的系统,从而满足系统可能具有的任何前提条件。

在继续之前,让我先弄清楚我们将在这篇文章中看到什么

  1. pytest 中的 fixture 是什么?
  2. 使用固定物有什么好处?
  3. pytest 夹具的范围有哪些?

奖金🎁,

4.理解夹具范围的示例工作代码。

pytest 中的 fixture 是什么?

为了理解测试夹具,首先,我们必须理解测试实际上是什么。为了简单起见,让我带你看一个简单的例子。

让我们假设你是一个厨艺大师👨🏻‍🍳你在为一个严肃的美食评论家做饭🚨,你要确保你已经把盐加到了点子上。所以这里唯一要检验的因素就是“盐后味”。为了做这个测试,我们需要四个步骤,

  • 安排/设置:这包括我们在测试阶段之前需要做的所有步骤,在我们的例子中是加盐之前的所有步骤(清洗蔬菜和肉类,切割和切碎它们,准备平底锅,以及加盐之前的所有烹饪步骤)。
  • 动作:这是触发我们想要测试的行为/状态的单一状态改变动作。在我们的例子中,“加盐”是单一动作。
  • 断言:这是我们检查特定行为的结果状态是否与我们预期的相同或不同的阶段,如果与预期的相同,则我们的测试通过,否则失败,在我们的情况下,断言是,加盐后食品测试是否“良好”。
  • 清理:一旦我们做了烹饪和测试味道,我们就需要清理厨房来烹饪另一顿饭,对吗???这正是在这个阶段中所发生的,为这个特定测试创建/设置的测试对象需要被清理,以确保它们不会影响其他测试。

现在回到夹具,是的,我们在安排阶段和数据中所做的任何步骤都被称为夹具。这些是需要测试某个动作的东西。

在 pytest 中,fixture 是我们定义的服务于这些目的的函数,我们可以将这些 fixture 传递给我们的测试函数(测试用例),这样它们就可以运行并设置您执行测试所需的状态。

@pytest.fixture
def db_conn(creds):
    # steps to connect to db def test_add_user(db_conn):
    user = User(....)
    desired_response = "......." response = db_conn.add_user(user)
    assert response == desired_response

当 pytest 试图运行测试test_add_user 时,fixture db_conn将被执行,以建立将用户添加到数据库所需的数据库连接。

我们可以看到更多确凿的例子👨🏻‍💻在结束之前,让我再回答几个问题。

使用固定物有什么好处?

当然,这可能是你看到上面的例子后想到的问题,让我列出那些是什么,

  • 夹具是可重用的,夹具是以模块化的方式实现的,因此每个夹具名称都会触发一个夹具功能。
  • 夹具可以使用其他夹具。
  • 测试或夹具可以一次请求多个夹具。
  • 夹具可以自动使用,有时所有的测试用例都需要夹具,在这种情况下,我们可以使用“自动使用”夹具。@pytest.fixture(autouse=True)举个例子。
  • 夹具管理从简单的单元测试扩展到复杂的功能测试。我们甚至可以根据配置和组件选项来参数化夹具和测试。
  • 无论使用多少夹具,拆卸逻辑都很容易管理。
  • 可以为每个 Fixture 设置 Fixture scopes,这将极大地帮助在运行昂贵的测试用例时节省大量时间和计算资源。

在这里,我想讨论更多关于**Fixture Scope** 的问题,让我们跳到下一个问题。

pytest 夹具的范围有哪些?

一些测试可能需要网络活动,如登录到远程服务器或数据库,或者如果您正在为机器学习模型编写测试,您可能必须训练可能由几个测试用例使用的模型,在这种情况下,每次用户请求时运行这些 fixture 函数可能会非常耗时且计算量很大。

在这种情况下,我们可以定义固定物的范围,例如:@pytest.fixture(scope='...')。作用域仅仅是通过运行 fixture 函数来删除返回的对象。有 5 个不同的范围。

  • 功能:当范围设置为功能时,在请求测试功能终止后,对象将立即被拆除。当另一个测试函数调用该 fixture 时,它将重新运行并创建一个新对象。默认情况下,fixtures 将有一个函数范围。
  • module: 当一个函数第一次调用 fixture 时,它将创建对象并保存它以供同一个模块中的测试函数使用。因此,如果同一个模块中的任何测试函数调用 fixture,将返回缓存的对象。该模块中的所有测试完成后,该对象将被拆除。
  • 类:fixture 将被每个类执行一次,它将被同一个测试类的所有测试函数重用。它将在该类的所有测试函数完成后被拆除。
  • package: fixture 将在第一次请求时被执行并被缓存,直到该类中的所有测试函数都被执行,之后将被拆除。
  • session: 这是 pytest fixture 中的广泛范围,每当我们调用pytest时,它就被称为会话。因此,具有会话范围的 fixtures 将在第一次请求时被执行和缓存,它们将被重用,直到所有测试完成。

奖金

哎呀,很多理论📚,让我们深入一些 pytest fixtures 及其范围的例子。

test_dir/conftest.py

conftest.py是 pytest 的一个特殊文件,您可以在其中添加所有的测试夹具。这些夹具对于同一个测试目录中的所有模块都是可见的。

注意:如果您有多个测试包,您可以为每个包添加一个conftest.py。这些文件有目录范围。

这里我们声明了三个具有三种不同作用域的 fixtures。

  • empty_account: 对于会话范围,每个会话只应执行一次。
  • account_20: 对于模块范围,应该每个模块执行一次。
  • account_50: 有函数作用域,每次请求时都要执行。

将下面的测试模块和conftest.py一起添加到你的测试目录中。

测试目录/测试装置 1.py

测试目录/测试装置 2.py

您可以从以下网址获得完整的代码:

https://github.com/Mathanraj-Sharma/python_boilerplate/tree/main/tests/test_fixtures

这些是一些简单的测试用例,用来看看当我们调用具有不同作用域的 fixtures 时会发生什么。运行以下命令来运行测试

python -m pytest --color=yes -s -v --show-capture=no tests/test_dir

PC:作者

如果仔细观察,您会得到类似于下面的输出

  • 对空账户夹具整个会话只执行了一次。
  • 对于每个模块,account_20 fixture 已经执行了两次。
  • account_50 fixture 因为是函数作用域,所以已经按要求执行了多次。

希望这是理解会话、模块和函数范围的好例子。我把类和包的范围留给你的作业,试着为这两个范围实现一个好的例子。

总之,pytest fixtures 是为测试功能安排/设置测试环境所需的功能。测试人员可以定义他们需要的任意多的夹具,并且从不同的测试功能中请求它们任意多的次数。此外,fixture scope 有助于在昂贵的测试中节省时间和资源。

希望这篇文章能给你一个关于测试夹具的好主意。快乐测试🤗!!!

让你的科学与芝诺多公平

原文:https://towardsdatascience.com/make-your-science-fair-with-zenodo-b209fc74400c?source=collection_archive---------26-----------------------

如何使用 Zenodo REST API 用 Python 上传数据

达斯汀·休姆斯在 Unsplash 拍摄的照片

发布的数据应该公平:可查找、可访问、可互操作和可重用。数据仓库,比如 Zenodo,有助于确保研究项目的公平性。

Zenodo 是一个免费平台,允许任何人上传和存储数据,使其可以搜索并提供数字对象标识符(DOI)。通过网页上的拖放功能,从本地计算机上传小文件很容易。但是如果文件很大并且在远程计算机上,那么你需要使用 Zenodo REST API

这篇文章描述了如何通过 Python 使用 API 与你的 Zenodo 帐户交互,这样你就可以以编程的方式创建项目和上传数据。

目录

RESTful API 基础

应用程序编程接口(API)是两台计算机相互通信的一种方式。它的工作原理就像一个网络浏览器,但是你写代码从服务器请求数据,而不是点击按钮。大多数 API 都是 RESTful 的,这意味着它们遵循一组称为表述性状态转移的规则。深入探究 REST APIs 超出了本教程的范围。然而,理解什么是 API 以及它如何在基础层面上工作是很重要的。

RESTful API 将数据组织成一串唯一的链接,类似于网页统一资源定位器(URL),只是它们被称为统一资源标识符(URIs)。例如,基本的 Zenodo API 是 https://api.zenodo.org/api和 https://zenodo.org/api/deposit/depositions 的的一个 URIs。

如果你点击这些链接,你实际做的是发送一个请求到一个服务器,在你的屏幕上显示的是响应。基本的 Zenodo API 链接将显示所有的 URIs,而/deposit/depositions链接可能会显示这样的错误消息

{"message":"The server could not verify that you are authorized to access the URL requested. You either supplied the wrong credentials (e.g. a bad password), or your browser doesn't understand how to supply the credentials required.","status":401}

写着“status”:401的部分是一个状态码,表示我们未经授权,需要提供一个访问令牌。

RESTful APIs 的一个很好的简单解释可以在这个视频的前两分钟中找到。

芝诺多 API

假设我们有一个 Zenondo 帐户,我们想从本地计算机与之交互。我所说的交互是指创建项目、上传数据、更新元数据以及删除文件或整个项目。我们可以用 API 向 Zenodo 发出四个基本请求:GETPOSTPUTDELETE

  • 获取是读取数据
  • POST 是创建项目并将数据移动到芝诺多
  • 是改变与项目相关的元数据
  • 删除将删除数据或项目

这些是我们将用来与 Zenodo 交互的 HTTP REST API 方法。一般来说,这是如何工作的,我们(客户机)将向 Zenodo(服务器)发出请求,作为回报,我们将得到响应。该响应可以是返回给我们的数据和/或表明我们的请求成功或失败的响应状态码。上的响应代码:

  • 2** =一切顺利
  • 4** =客户端错误(你做错了什么)
  • 5** =服务器错误(服务器出现问题)

这一切现在听起来可能有点抽象,但当我们应用它时,它将是有意义的。

总而言之,API 是一种代码,它让我们通过发送请求 ( GETPOSTPUTDELETE)和作为回报的响应,在互联网上与服务器(在本例中是 Zenodo)进行通信。

更深入的解释,请看佩里·艾辛的帖子。

https://medium.com/@perrysetgo/what-exactly-is-an-api-69f36968a41f

在我们开始之前…

您需要创建一个帐户和一个访问令牌。使用 API 时,这个令牌是您帐户的密钥。我们向它提供我们的请求,告诉 Zenodo 我们有适当的权限来访问这个帐户。

  1. 你首先需要用芝诺多创建一个账户
  2. 之后,您将需要创建一个访问令牌来使用 API 。该令牌将是一个长的字母数字字符串,并且只显示一次。
    将此令牌保密
  3. 复制令牌并将其作为环境变量保存在您的环境文件中(例如~/.bash_profile ):
    export ZENODO_TOKEN=YOUR_ACCES_TOKEN_GOES_HERE
  4. 确保您可以从终端访问令牌:
    echo $ZENODO_TOKEN如果一切正常,这将在您的提示中显示您的令牌值。
  5. 安装 python 请求包:
    conda install -c conda-forge requests 你也可以通过 pip 安装
  6. 确保可以导入包:import requests

如果您正在使用 JupyterLab,python-dotenv包是在笔记本中使用环境变量的一个好方法。该软件包有助于从环境文件中读取键值对,并确保您的令牌在与同事共享笔记本时保持私有。

现在一切都准备好了,您创建了一个帐户,存储了您的访问令牌,并安装了必要的包。

现在我们准备开始使用 Zenodo API 了!

获取关于 API 的信息

让我们从向 Zenodo 基础 API 发出一个GET请求开始。

我们在访问令牌中附加了一些头信息,现在应该返回内容了。对于这种类型的请求,这不是必需的。我们得到的是一个包含两条重要信息的响应对象,即状态代码和响应数据:

  • print(r.status_code):显示状态码
    2** =一切成功
    4** =客户端错误(您做错了)
    5** =服务器错误(服务器出错)
  • print(json.dumps(r.json(), indend=2)):以可读的方式显示响应 JSON 输出。输出如下所示

我们得到的响应是与 API 相关的所有 URIs。URI 的存款是我们唯一会用的。

  • 存款:用于上传和发布到 Zenodo
    (这与 web 界面中可用的功能相同)。

其他 URIs 主要用于搜索芝诺多。

发布创建项目的请求

您可以使用 web 界面或通过 API 以编程方式创建项目。为了完整起见,我将展示这两种方式。如果你正在填充大量的可选元数据,web 界面会更容易使用,并且 API 可以快速创建你想要上传的项目。

使用网络界面

进入你的账户,点击顶部的“上传”,然后点击右边绿色的“新上传”按钮,创建一个新项目

新建一个项目:点击顶部的“上传”,然后点击右边的“新建上传”。(图片由作者提供)

最起码,要在旁边标有红色*的字段中进行填写。完成后,点击顶部的“保存”。顶部的 URL 会改变,并给你的项目一个唯一的 ID。这里有一个例子:

https://zenodo.org/deposit/4781404

/deposit表示这是一个私人项目。

这是一个公共项目 URL

https://zenodo.org/record/4760205

/record表示这是一个公共项目。

使用 API

为了用 API 创建一个项目,我们将发出一个POST请求。

这将创建一个没有标题或信息的空项目。

r是响应对象,包含两条有用的信息

  • r.status_code:表示作业是否成功
    (记住 2**处的响应表示成功)
  • r.json():哪个是服务器以 JSON 格式返回给我们的数据

响应代码201表示“已创建”

注意响应输出中的links中的idbucket。这些以后会有用的。

存储 id 和存储桶

从这个响应中,我们想要保存两条信息idlinks中的bucket

  • id是与项目相关的唯一编号
  • bucket是你上传数据文件的地方

下面是保存从输出中提取这些内容的代码。

这个在网页上看起来怎么样?

当你登录到 Zenodo 并导航到上传时,你会看到这个。

一个没有标题的项目,当你看里面的时候,你会看到没有字段被填写,也没有上传。这是意料之中的,因为我们创建了一个空白项目。在 API 中,我们没有将空数据附加到我们的POST请求中。

提交更改元数据的请求

现在让我们更改一些与我们的项目相关的信息。为此,我们将发出一个PUT请求。

这些更改将立即生效,并将在网页上显示。

上传数据的上传请求

就像填写元数据一样,上传数据有两种方式:通过 web 界面和通过 API。同样,我将展示两者。

从 web 上传

如果您的数据集很小,并且位于本地计算机上,那么通过网页上的拖放功能上传文件可能是最好的方法。导航到您的项目,然后单击“选择文件”。

拖放对于笔记本电脑上的小数据集是很好的(图片由作者提供)

使用 API 上传

如果数据集很大或者位于远程计算机上,则需要使用 API。为此,我们向bucket_link发起一个PUT请求。

如果我忘记保存存款 id 和存储桶链接怎么办

这种情况时有发生,尤其是当我不断重写r的时候。如果您忘记了“id ”,找到它的最简单方法是访问项目网页并查看 URL。

一旦知道了 id,就将它保存到一个名为deposition_id的变量中。

您也可以发出GET存款请求来抓取idbucket

r = requests.get(f"{baseurl}/deposit/depositions", 
                 headers=headers)

删除文件和项目

在这一节中,我将向您展示如何使用 API 删除文件和项目。

从你的项目中删除东西太容易了。发出DELETE请求时要小心,如果要执行此操作,没有弹出窗口需要仔细检查。

删除文件

要删除一个文件,我们需要获得惟一的file_id,然后发出一个DELETE请求。

注意使用filter()首先找到正确的文件名,然后获取文件的id。如果项目中有多个文件,这是必要的。

在这种情况下,响应状态代码是204,表示“无内容”,这通常是对DELETE 请求的响应。

如果您遵循此示例,您将会看到该文件在网页上不再可见。

删除项目

要删除一个项目,向沉积发出一个DELETE请求id

一旦你这样做了,你的项目就…

最后的想法

Zenondo API 让您能够从命令行与您的帐户进行交互。你能在网页上做的任何事情都可以用 API 来做。然而,仅仅因为你可以用 API 做这些事情,并不意味着你应该这样做,或者它很容易和直观。例如,我个人觉得用 web 界面创建项目和添加元数据更容易。

API 的主要优势是能够将远程数据上传到您的帐户。

我对 Zenodo 唯一的不满是它不允许你上传目录树,这是 GitHub 上的一个未解决的问题。解决方法是上传目录结构的压缩版本。从整体来看,这只是一个小小的不便。然而,如果你上传时绝对需要这种结构,我建议看看开放科学框架

发布您的项目

完成上传数据和填写所有元数据后,您可以将项目公开以确保其可访问性。我建议从网页上做这件事。单击蓝色的“发布”按钮,让任何人都可以访问您的项目。可及性是公平原则之一,公平的科学更好。

教程笔记本

额外资源

https://fairplus.github.io/the-fair-cookbook/content/recipes/findability/zenodo-deposition.html#programmatic-deposition-to-zenodo-via-the-rest-api

特别感谢 Rachana Maniyar 博士 编辑本帖的草稿版本

感谢阅读和支持媒体作者

https://lukegloege.medium.com/membership

Makie:高水平,美丽的情节

原文:https://towardsdatascience.com/makie-high-level-beautiful-plots-3ae670de2fa1?source=collection_archive---------16-----------------------

熟悉 Makie.jl,这是一个用于 Julia 编程语言的高级绘图和统计图形库。

作者图片

介绍

在 Julia 的生态系统中,已经出现了许多可视化数据的奇妙解决方案。尽管如此,许多用户经常最终使用 Plots.jl。虽然 Plots.jl 肯定是一个很酷的包,但重要的是要记住,该包必须提供的是来自其他编程语言的不同软件的三个独立端口。这些端口是 Plot.ly、Matplotlib.pyplot 和 GR。默认情况下,Plots.jl 使用 GR 可视化库,这是一个很好的库,但在许多方面非常缺乏特色。此外,像这样使用端口真的会减少预编译时间,而且使用 PyCall 这样的包会影响 Julia 的性能。有趣的是,如果你感兴趣,我确实有一个关于 Plots.jl 的 GR 后端的完整教程:

还有一些其他纯粹的朱利安解决方案已经出现。在我看来,最大的例子是牛虻包。牛虻包的交互性比不上 Plot.ly,但对大多数情况来说已经足够了。最重要的是,牛虻可视化很容易操作,而且看起来很好!我还写了一篇关于使用该包的教程和概述,如果您感兴趣,可以在这里查看:

在 Julia 中还有另一个很棒的可视化库,名为 Vegalite.jl。我见过许多其他科学家,他们发誓说这是 Julia 中最好的一个,但我仍然偏爱牛虻. jl。这是因为我发现牛虻更容易使用。Vegalite 有一个奇怪的方法,它涉及到在你的绘图中为各种不同的设置使用大量的数组,而不是参数。也就是说,我要说的是,与列表中的其他选项相比,Vegalite 确实有一些严肃的统计可视化。实际上,我比较了另一篇文章中提到的所有三个选项,如果您愿意,可以在这里查看:

所有这些文章都有更多的信息可以链接,这真是太棒了。

Julia 语言及其绘图功能的另一个新增功能是 Plot.ly 打包了该语言的官方端口。我必须承认,我还没有机会尝试这一点,但我很高兴尝试一下,我甚至可能会写一篇关于它的文章,并将其与 Python 实现进行比较!

有了生态系统中的所有这些图形库,我真的很想接触所有这些库,以便公开比较所有可用的选项,并找出我想要使用的那个。很高兴知道他们中的许多人,因为我认为他们都有自己的功能。在 Julian 图形库之旅中,我的下一站是 Makie.jl. Makie.jl 有点独特,因为有多个使用不同图形库的库实现。例如,我决定使用 OpenGL,所以我将通过 Pkg 添加 MakieGL.jl。还有一个 webgl 版本和一个 Cairo 版本,分别是 WGLMakie.jl 和 CairoMakie.jl。让我们继续添加软件包并开始吧!

笔记本

julia > ]
pkg > add GLMakie

基本绘图

由于我从未实际使用过 Makie.jl 包,所以我决定稍微熟悉一些基本情节。Makie.jl 遵循图形库的典型高级约定,所以幸运的是这里不会有任何 Vegalite-esc 曲线球。

using GLMakie

像 Plots.jl 一样,我注意到 Makie 也需要很长时间来预编译。这可能是因为我决定使用 OpenGL,但我怀疑事实是否如此。我说真的真的花了很长时间。这不太重要,但肯定是您在应用程序中使用该包时需要记住的事情。我绘制的第一个例子直接来自 Makie 文档:

points = [Point2f0(cos(t), sin(t)) **for** t **in** LinRange(0, 2pi, 20)] colors = 1:20 
figure, axis, scatterobject = scatter(points, color = colors, markersize = 15) 
figure

作者图片

看起来像是 OpenGL 驱动程序加载失败!好消息是我碰巧知道一个事实,Cairo 在我的电脑上可以很好地运行我的 Julia 安装,所以我们将切换到 CairoMakie,而必须再次预编译它

julia > ]
pkg > add CairoMakie
using CairoMakiepoints = [Point2f0(cos(t), sin(t)) for t in LinRange(0, 2pi, 20)]
colors = 1:20
figure, axis, scatterobject = scatter(points, color = colors, markersize = 15)
figure

作者图片

耶!

实际上,我很喜欢这个库的功能,虽然它是极简的可视化,类似于没有交互性的 GR,这是我在大多数情况下所需要的。类型是可变的,所以我们现在可以改变这个结构内部的数据来产生不同的结果。更牛逼的是,我们可以在这个数字上加数字!这实际上让我想起了很多很久以前制作的图形库。这真的很酷,因为它是元编程和面向对象的,但该项目已经停止。实际上,我在《走向数据科学》上写过相关文章,所以如果你碰巧对那个项目感兴趣,里面有很多非常非常有趣的 Julia,你可以在这里查看:

该系列有许多不同的部分,所以如果您真的对这个包及其背后的代码感兴趣,这可能是一个不错的读物。无论如何,从我的开发历史来看,很明显我是图形模块化的狂热爱好者,Makie.jl 正是提供了这一点!这很快成为我最喜欢的图形库。我们可以添加基本上任何新的数字到我们的数字,通过使用!版本散点!方法。

circlefunc = ts -> 1.5 .* Point2f0.(cos.(ts), sin.(ts))
scatter!(circlefunc, LinRange(0, 2pi, 30), color = :red)
figure

作者图片

布局

Makie.jl 也有一个相当健壮的布局实现。它们比 GR 更容易理解和制作,看看吧!我们可以制作一个完全空的图形,并在其上添加我们可视化的所有模块部分!

fig = Figure(resolution = (700, 500), backgroundcolor = RGBf0(0.98, 0.98, 0.98))
ax1 = fig[1, 1] = Axis(fig, title = "Pre Treatment")
data1 = randn(50, 2) * [1 2.5; 2.5 1] .+ [10 10]line1 = lines!(ax1, 5..15, x -> x, color = :red, linewidth = 2)
scat1 = scatter!(ax1, data1,
    color = (:red, 0.3), markersize = 15px, marker = '■')
fig.layout
ax2, line2 = lines(fig[1, 2], 7..17, x -> -x + 26,
    color = :blue, linewidth = 4,
    axis = (title = "Post Treatment",))fig

作者图片

动画片

Makie.jl 除了之前牛逼且实现良好的特性外,还有对动画的支持!我真的很兴奋,我已经知道我会一直使用这个图书馆了!我已经很高兴我尝试了这一点,动画只是一个蛋糕上的糖衣,它已经非常湿润,可以在你的嘴里融化。为了创建一个动画情节,我们还需要添加“AbstractPlots”包。

julia > ]
pkg > add AbstractPlots

我将继续尝试它。为了实际创建动画,我们将使用 record()方法。这实际上会将其输出到一个视频文件。这有点奇怪,因为我当然更喜欢 GIF 之类的东西——但不管怎样,它会起作用的。

**using** GLMakie 
**using** AbstractPlotting.Colors
figure, ax, lineplot = lines(0..10, sin; linewidth=10)
n_frames = 30 
framerate = 30 
hue_iterator = LinRange(0, 360, n_frames)  
record(figure, "color_animation.mp4", hue_iterator; framerate = framerate)
 **do** hue     lineplot.color = HSV(hue, 1, 0.75) **end**

作者图片

也可能行不通。

结论

我相信随着时间和努力,一定会有办法加载适当的驱动程序,并实际上让我的系统与 Makie.jl 的全部功能一起工作。不管动画斗争,我非常兴奋地开始使用这个图形库!它的模块化性质和原始能力正是我在这样的东西寻找。我真的很高兴我试用了它,我现在实际上对这个包感到非常兴奋。我强烈推荐它。我认为这个包最糟糕的部分可能是包的分段性,你需要用 Pkg 添加很多包。当然,这没什么大不了的,我认为这个图形库的能力绝对值得。感谢您的阅读!我当然推荐试试这个库!

制作更好的填充地图

原文:https://towardsdatascience.com/making-a-better-filled-map-8818f333bcf1?source=collection_archive---------36-----------------------

改善您的地理数据交流

在我看来,在地图上可视化地理数据是向受众传达数据的最有效方式之一。与包含相同数据的简单表格或条形图相比,我们对州、地区和领地的了解有助于我们更快、更好地发现趋势。

然而,并不是所有的地图都是平等的。有一些简单的方法可以改善我们可视化地理数据的方式,使我们的信息更流行,更好地向我们的受众传达信息。

作为一个例子,看看下面两张地图。左边的来自美国消费者新闻与商业频道可视化各州家庭收入中值,右边的来自 CDC 可视化 COVID 数据。你怎么想呢?

左图:各州收入中位数的美国消费者新闻与商业频道视觉图。右图:美国疾病控制中心各州 COVID 感染地图。

这里有几个想法引起了我的注意:

  • 如果您在左侧地图上选择 5 个州,并找到相应的家庭收入桶,您需要多长时间?10 个州?一个 5000 美元的分色是否有意义(例如,与一个 10000 美元的桶相比,类别数量增加一倍是否对信息有影响)?
  • 在右边,找到正确的蓝色阴影然后将其映射到底部的桶需要多长时间?你能不能立即确定哪些州的 COVID 病例最高和最低?

当我们不得不付出额外的努力来理解信息时,地图并不能更好地传达信息。我们可以使用更好的颜色、文本的策略性使用和变换来改善上面的视觉效果。

下面,我们将在上述地图的基础上介绍改进连续和分类地理变量可视化方式的策略,并引入新的示例。

连续变量

让我们来看看中等收入的地图。我喜欢使用 Tableau,但认为他们的默认设置甚至可以产生一个足够的地图是一种误导。只需将数据放入 Tableau 地图中,就会生成以下内容:

来自 2017 美国 ACS 的 HH 收入中值的默认表格图

重叠的地理区域,即使是灰色的,也会让人分心。如果你仔细观察,颜色表明新泽西州、马萨诸塞州、康涅狄格州和新罕布什尔州是中等收入最高的州,但我不能肯定地说。

在表示精确的连续变量很重要的情况下,首先考虑变量是否有方向,以及这是否会影响颜色选择以改善感知——一种结果是否比另一种更好(绿色与红色)?与变量的关联是否有助于读者更好地理解变量(例如,蓝色代表平均值。各州降雨量)?

对于中等收入,我们可以选择绿色,因为绿色通常与金钱联系在一起,通常绿色与“更好”的结果(更高的中等收入)联系在一起。从风格上来说,当可视化美国各州时,我也发现底层地图没有什么价值,所以我通常会删除它。

做出这两个改变(颜色改为绿色和去除背景)是一个开始,但并没有真正达到预期的效果。我仍然没有更好地快速识别哪些州具有最高和最低的值。

美国 HH 收入中值地图,绿色,无背景地图

有三种后续技术来改善视觉效果:

  • 扩大色阶:在你的色阶上扩大两种颜色之间的差异,以提供更大范围的颜色选择。
  • 变换变量:通过取平方根、自然对数或提高值的幂(即平方或立方)来增加(或减少)变量之间的差异,以达到着色的目的。
  • 标记选择值:通过只标记前 x%的值、后 x%的值或两者来吸引人们对某些州/地区的注意。

你对下面的有什么看法?

它并不完美,但更容易看出哪些州是深绿色的(东北部),哪些州是浅色的(东南部)。要实现这一点,您可以将色标更改为更亮的连续绿色,将不透明度从默认的 80%增加到 100%,并通过将其提升到 4 次方来转换变量,这将放大状态之间的差异。

为了更进一步,我们可以选择标记一些状态,以便查看者可以快速识别更暗和更亮的值意味着什么。看下面,我们仍然可以使用视觉颜色线索来知道哪个更高或更低,并且还可以看到“更低”意味着 $70K。

用戏剧化的色标、变换和数据标记进行连续制图。

上面的并不完美,但这是对标准画面视觉效果的改进。在尺度上没有显著差异的连续变量很难绘制,但是可以使用上面的简单视觉技巧改进基线。

等级映射

有时知道单个最高值并不重要,重要的是那些更高或更低的值。当显示层次是一个选项,而不是精确的连续值时,我喜欢使用我所谓的层次映射来平衡颜色、文本和注意力。分层映射是一种既能实现连续变量的特异性,又能实现分块的直观简单性的方法。

让我们来看看另一种看待 COVID 数据的方式(与上面的视觉略有不同,但数据和用例相似)。下面是一张 30 天 COVID 增长率的地图,按实施了等级映射的州划分。

各州的 30 天 COVID 病例增长率。分层映射的一个例子。

在地图中有一些视觉提示需要考虑(另一个例子在这一部分的下面)。首先,我根据从最高到最低的度量将状态分成三个桶(Tableau 中使用WINDOW_PERCENTILE的简单IF > ELSEIF语句)。

其次,因为越高越糟糕,我选择了红色作为主要颜色,这种颜色通常与糟糕的结果联系在一起。我选择了深红色>浅红色>灰色三色组合,而不是我有时难以理解的纯红色。对我来说,这将注意力集中在黑暗的状态,并使主题更容易拉出。它还明确区分了类别。

最后,我选择只包含中值或高值的文本(同样,在文本标记卡上有一个带有WINDOW_PERCENTILEIF > ELSEIF声明)。低值有多低真的重要吗?也许吧,但在这种情况下,我不认为它保证了地图上的空间。在 Tableau 中,如果值对查看者很重要,也可以很容易地将它放在悬停文本中。

每 100,000 名居民的积极 COVID 住院率;分层映射的另一个例子。

我最喜欢这些地图的一点是,通过观察哪些地方有颜色,哪些地方没有颜色,可以相当直观地发现图案。试着快速解读大图主题的每张地图,看看你是否有同样的感觉。

分类变量

没有层次关系的分类变量更容易映射,但我们仍然有办法确保我们的数据能够被用户轻松快速地解释。对于分类变量,一些改进映射的技巧是:

  • 使用互补色,读者可以很容易地识别出不同之处(尽可能避免连续的颜色)。
  • 如果可能,将类别限制在 5 个或更少。如果有 5 个以上的变量,最好考虑替代视觉效果或更广泛的卷式分类。
  • 尝试在地图中标注,而不是让读者经常查阅图例。

考虑下面的地图,它测量(截至 2013 年)一个州是连续 3 次或更多次投票支持共和党,连续 3 次或更多次投票支持民主党,还是“独立”(任何一方的连续投票都少于 3 次)。

注意使用互补的、不同的颜色,以便在类别之间提供视觉线索(我喜欢使用这个网站来帮助我挑选颜色,当我不受公司品牌颜色的限制时)。此外,的原始图像有 7 个类别,我将其合并为 3 个(我将 3–5、6–10 和 11+更改为 3+)。最后,请注意在一组相似颜色的状态附近标记类别的方式,这是一种替代通常远离视觉效果的图例的方式。

分类映射的例子

绘制地图是一种非常有效的信息交流方式,通过一些简便的技巧,我们可以制作更好的可视化效果,改善我们的受众对数据的理解,并带来更有影响力的演示和数据故事。

有反馈吗?有兴趣联系吗?随时联系我LinkedIn

制作完美的 ML env。在 Ubuntu 20.04 上使用 Tensorflow 2 和 CUDA 10.1,双启动 2021

原文:https://towardsdatascience.com/making-a-flawless-ml-env-with-tensorflow-2-and-cuda-10-1-on-ubuntu-20-04-with-dual-boot-2021-3731c92692fb?source=collection_archive---------16-----------------------

在 Ubuntu 20.04 上使用 Tensorflow 2 和 Nvidia CUDA 支持的简单、快速和可靠的 Python3 环境,满足您的所有 ML 需求!

正如我所希望的那样简单,在搜索了互联网上的各种文章之后…事实证明并非如此。尤其是如果你的电脑是 Windows 10 双启动的话。

所以经过几夜的挣扎,看到红色的错误,听到安装失败的哔哔声…我成功了!这是我成功之路的总结!

  • 步骤 1:“双重启动”安装和 BIOS 调整。
  • 第二步:检查 Python3 和 GCC。
  • 第三步:整理!(可选—如果是全新安装,则跳过)
  • 第四步:安装!(最期待的)

来源:下载自谷歌图片

第一步:【双引导】安装和 BIOS 调整。

相信我,这是确保操作系统和 BIOS 设置正常的关键一步,这样你就不必一次又一次地经历卸载和重新安装的麻烦。

‘双开机’安装:

对于 Ubuntu 20.04 双引导安装,我按照这个视频稍加改动。我预装了 Windows 10。我的电脑和视频中的有不同的硬件设置,所以我根据自己的需要为安装配置了磁盘分区。在那段视频的 9 分钟时,我在安装时勾选了“为图形和 Wi-Fi 硬件以及其他媒体格式安装第三方软件”复选框(可选)。一旦完成,你应该会看到 GRUB 引导加载器,带有 Ubuntu 和 Windows 引导管理器选项,如视频中所示的

BIOS 调整:

在您的“双重引导”安装之后,在 BIOS 设置中,确保“安全引导”选项必须是“启用的”(上面的视频要求禁用它),“快速引导”选项必须仍然是“禁用的”,并且您应该仍然看到 GRUB 引导加载程序和可用的选项。一旦完成,我们就可以进入下一步了!(注:不同的 BIOS 有不同的引导选项,如果您找不到选项,请参考您的版本的手册。)

第二步:检查 Python3 和 GCC。

Ubuntu 20.04 预装了 Python3 和 GCC。要验证这一点,您可以运行以下命令。

sudo apt update
sudo apt -y upgrade
python3 -V
gcc --version

此外,验证pip是否已安装并使用该命令正常工作(如果您这样设置,它可能是pip3,但不是我)。

pip --version

我的版本是:

  • Python 3.8.5
  • gcc(Ubuntu 9 . 3 . 0–17 Ubuntu 1 ~ 20.04)
  • pip 21.1.2

第三步:整理!(可选—如果是全新安装,则跳过)

即使你已经完成了前两个步骤,我仍然建议你完成上面的步骤来修复你在之前的尝试中可能错过的任何东西。

卸载/移除/恢复您迄今为止对系统所做的所有 CUDA 相关更改!以下命令应该可以帮您做到这一点:

sudo rm /etc/apt/sources.list.d/cuda*
sudo apt remove --autoremove nvidia-*
sudo apt-get purge nvidia*
sudo apt-get autoclean
sudo apt-get autoremove
sudo rm -rf /usr/lib/cuda*
sudo rm -rf /usr/local/cuda*

.profile.bashrc文件中删除 CUDA 路径(通常附加在iffi之间的末尾)并保存。

sudo gedit ~/.profile
sudo source ~/.profile
sudo gedit ~/.bashrc
sudo source ~/.bashrc

一旦移除,echo $PATH | grep cudaecho $LD_LIBRARY_PATH | grep cuda应该不会有‘cuda’在里面!

现在我们将整理 python 包。如果您设置了任何 python 虚拟环境(在这里阅读,您应该切换到它们。但是对于我的设置,我运行了这个命令:

pip uninstall tb-nightly tensorboardX tensorboard tensorflow tensorflow-gpu

这可能会抛出一些错误,这取决于您是否安装了该软件包,所以不必担心!

第四步:安装!(最期待的)

在我们开始之前,确保到目前为止的步骤都已经完成。如果按照正确的顺序进行,安装并不可怕!所以让我们开始吧…

安装 CUDA 10.1 和 cuDNN 7:

这些都是稳定的版本,命令都经过了反复测试,所以只要一个一个地运行它们,就能看到神奇的事情发生了!(查看了解更多信息。)

sudo add-apt-repository ppa:graphics-driverssudo apt-key adv --fetch-keys [http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub](http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub)sudo bash -c 'echo "deb http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64 /" > /etc/apt/sources.list.d/cuda.list'sudo bash -c 'echo "deb http://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64 /" > /etc/apt/sources.list.d/cuda_learn.list'sudo apt install cuda-10-1

执行完最后一个命令后,安装会暂停,并在此显示以下屏幕:

在安装过程中,屏幕上弹出“配置安全引导”屏幕。来源:作者图片

按下向下箭头键并阅读全文。按 tab 键,然后按 enter 键进入。屏幕上有很好的书面说明,它们会带你完成步骤。您将被要求设置一个密码(8 到 16 个字符),该密码将在重新启动时再次被要求验证它是真实的用户。不要忘记密码!如果有的话,记下它(我把我的mycuda1234)。如果您仍然对“登记 MOK”屏幕感到不舒服,请参考本文中的

完成后,系统启动,运行命令:

sudo apt install libcudnn7

这应该会在您的系统上安装 CUDA 和 cuDNN。最后一部分是运行sudo gedit ~/.profile并追加下面的块并保存。

# set PATH for cuda 10.1 installation
if [ -d "/usr/local/cuda-10.1/bin/" ]; then
    export PATH=/usr/local/cuda-10.1/bin${PATH:+:${PATH}}
    export LD_LIBRARY_PATH=/usr/local/cuda-10.1/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
    export LD_LIBRARY_PATH=/usr/local/cuda-10.2/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
fi

重新启动计算机,并尝试以下命令:

/sbin/ldconfig -N -v $(sed 's/:/ /' <<< $LD_LIBRARY_PATH) 2>/dev/null | grep libcudnncat /proc/driver/nvidia/versionnvidia-settings -q NvidiaDriverVersionnvidia-sminvcc --version

这些现在应该运行没有任何错误!如果是,恭喜你!您已经成功地在您的机器上设置了 CUDA 10.1。

用 Python 3 安装 tensor flow 2.0:

如果您正在使用 python 虚拟环境,请切换到适合您需求的环境。要用 Python 3 设置 Tensorflow 2.0,首先,我们运行一个命令来获取依赖关系:

sudo apt install python3-testresources

这将在 Tensorflow 安装时防止此错误:

ERROR: launchpadlib 1.10.13 requires testresources, which is not installed.

现在运行以下命令完成(这确保您拥有 Tensorflow 版及其所有依赖项):

pip install tensorflow
pip install --upgrade tensorflow==2.2
pip install --force-reinstall tensorflow==2.2

通过运行pip freeze | grep tensorflow检查安装,它在我的系统上给出以下输出:

tensorflow==2.2.0
tensorflow-estimator==2.2.0

作为最后一步运行命令:

python3 -c "import tensorflow as tf;print(tf.reduce_sum(tf.random.normal([1000, 1000])))"

这可能会打印几行,但是倒数第二行应该包含Created TensorFlow device,最后一行应该返回一个类似的张量:tf.Tensor(368.0642, shape=(), dtype=float32)

我希望这篇文章很容易理解,并让您的完美 ML 环境准备就绪!

对我提到的使这个设置工作的资源的一个巨大的呼喊!

https://medium.com/@exesse/cuda-10-1-installation-on-ubuntu-18-04-lts-d04f89287130 https://documentation.commvault.com/commvault/v11/article?p=118661.htm https://itsfoss.com/ppa-guide/

让情感模型变得可以解释

原文:https://towardsdatascience.com/making-a-sentiment-model-explainable-5413437d9db2?source=collection_archive---------19-----------------------

模型可解释性

理解人工智能的内部运作有很多目的,每一个都进一步扩大了它的范围和有效性。

我们一生中花了大量的时间去挖掘他人的动机。(“她为什么说那个?”).我们在这个世界上经常被别人的言行所困惑,通过假设和归因来解决我们之间的理解差距(“我确定这是因为我昨天迟到了。”)或者通过询问,既间接("她的问题到底是什么?")并且直接(“除非你告诉我为什么你那样说,否则我不会离开。”).换句话说,我们想象为什么或者问为什么。

随着人工智能变得越来越普遍,我们开始想知道它的动机是很自然的。是的,这部分是因为我们害怕会奴役我们所有人的超级智能可能会从人工智能中进化出来,并希望看到它的到来。但至关重要的是,这也是因为这种新智能的机制对我们来说是如此陌生。我们有兴趣了解它是如何工作的。如果它做出的决定对我们的生活有重大影响,我们很自然会想知道它是如何做出这些决定的。

我们想知道,就像我们经常对人类做的那样:

  • 决策正确吗:人工智能出错的频率有多高?决策是否基于所有相关信息?
  • 这些决定公平吗:人工智能表现出对人类如此普遍的有害的社会偏见吗?
  • 决策可靠吗:AI 每次遇到类似的输入都会做出一致的决策吗?
  • 这些决定合理吗 : 这些决定能向我们解释吗?
  • 决策是确定的 : 特定决策的 AI 有多有把握?

理解是建立信任的先决条件。使用算法技术来理解人工智能的决策被称为人工智能可解释性。在 Dialpad,我们使用可解释性技术来帮助我们的客户理解他们通过产品功能进行交互的深度学习模型的输出。我们还使用这些技术来改进我们的深度学习模型。

拨号键盘的可解释性

让我们以目前在产品中运行的情感分析模型为例,可解释性在其中扮演着重要的角色。情绪分析功能挑选出通话记录中表现出积极或消极情绪的部分。

每当一个说话者说了一些表示他们对某事非常高兴或满意的话,积极情绪就会被识别和强调。

一个例子:“我们喜欢这个演示,它提供了很多信息。”

每当说话者说了一些表示他们对某事非常沮丧或恼火的话,消极情绪就会被识别和强调。

一个例子:“这不起作用,我真的很沮丧。”

关于我们的情感分析功能的旧版本,一个常见的用户抱怨是,他们不明白为什么某些句子被标记为积极或消极的情感。

在句子很长或者表达的情感不太明显的情况下尤其如此。此外,一些情感判断是主观的价值判断。例如,情感分析模型对脏话应该有多敏感?

有些人不赞成在商务交流中使用任何脏话,认为它们是“负面的”,而另一些人则根据上下文评估它们的适当性,或者根本不介意它们。在这种情况下,情感分析的“正确性”取决于用户的视角。

有时尽管模型是完全错误的。例如,当今的情感分析模型在讽刺方面表现很差,通常标记为积极的情感,因为使用了“积极”的词,这显然是(无论如何对人类来说是显而易见的)轻蔑的表示。

许多这些灰色区域存在于情感检测的任务中。为了在情感分析功能中建立信任,我们需要使作为其基础的深度学习模型变得可解释。

如何审问人工智能

当我们戳

当我们敦促深度学习模型解释自身时,我们希望揭示模型功能的哪些错综复杂之处?我们可能想知道:

  • ****输入数据的哪些元素对做出的决策最重要。例如,在一个帮助自动驾驶汽车感知的深度学习模型中,我们可能想知道相机图像的哪些部分最常帮助模型区分类似的物体,如路灯杆和交通灯杆。
  • ****一个模型需要学习哪些中间任务才能达到它的既定目标。例如,为了学习如何概括一段文本,模型需要学习词类吗?我们可能还想知道模型的哪些部分专门执行这些中间任务。
  • ****为什么模型失败,什么时候失败。当语音助手无法理解对他们说的话时,那个特定的输入或者那个输入和模型之间的交互会导致这个失败。
  • ****是否存在某些模型表现不佳的可识别输入组?这条询问线对于确定你的模型是否已经学会了基于性别、种族和其他受保护类别的有害偏见至关重要。

当他们回应时

深度学习的解释有两大类:

****全局可解释性/结构分析:这包括研究模型的内部结构,检测哪些输入模式被捕获,以及这些模式如何被转换以产生输出。这类似于进行大脑核磁共振成像或脑电图检查,可以让你窥视大脑,看看它是如何连接的,研究各个组成部分及其对不同刺激的反应,记录结构和操作故障等等。

****局部可解释性/行为分析:这包括通过观察单个特定实例的行为来推断模型如何工作。这类似于心理学实验,要求参与者在干预前后执行指定的任务,以研究所述干预的效果。

提问的艺术

有几种技术可以用来查询深度学习模型的工作情况。虽然这些技术的机制超出了本文的范围,但我将尝试总结主要的调查:

****用局部扰动解释:在这条研究路线中,我们非常细微地改变单个输入的不同部分或方面,以观察这如何影响输出。如果输入的一个部分或一个方面——一组可识别的像素,一个特定的单词——在输出中产生明显的变化,人们可以得出结论,输入的这些部分对输出最重要。

例如,在自动语音识别模型中,一个将口头语音转录为文本的模型,从头到尾一个接一个地丢弃音频的小部分,并查看这种干预如何改变转录的文本,将告诉您特定音频文件的哪些部分对其转录最重要。

这一类技术会给你局部的解释。这类技术包括渐变遮挡激活最大化

****用代理人解释:通过这类技术,我们建立更简单的、基于树的或线性的机器学习模型,来解释更复杂的深度学习模型的个体预测。线性模型让我们非常清楚地知道哪些输入要素对预测很重要,因为它们本质上是为不同的输入要素分配权重。权重越高,特征越重要。

这一类技术会给你局部的解释。这一类的技术包括石灰SHAPSmoothGrad

****基于传播的方法(利用结构):在这里,我们深入研究模型结构,并研究单个神经元的贡献,以了解哪些神经元和层对输出影响最大。使用一种名为层相关性传播 (LRP)的技术,发现流行图像数据集上训练的分类模型只学会了如何识别一匹马,因为大约五分之一的马图像中存在源标签。移除标签也移除了将图片分类为马的能力。此外,在汽车图像上插入标签会将分类从汽车更改为马。

资料来源:https://www.nature.com/articles/s41467-019-08987-4.pdf(抄送 4.0)

可解释的模型可以帮助模型建立者发现这种错误的相关性并加以纠正。

这一类技术会给你全面的解释。这类技术包括 LRP解卷积导向反向传播

****元解释:我们使用技术来发现相关的或基础的任务,这些任务是模型为了完成工作必须首先学习的。为此,我们插入模型的中间层,即位于输入和输出之间的层,并要求它们执行各种感兴趣的任务。例如,一项研究的作者发现 BERT 的中间层编码了丰富的语言信息层次,例如学习句子中的名词是复数还是单数,动词的时态是过去、现在还是将来,动词的类型和句子的主语是否匹配。他们得出结论,这些技能的学习似乎是执行高级自然语言任务(如文本分类和生成连贯文本)的先决条件。

这一类技术会给你全面的解释。这类技术包括喷雾探测

使情绪模型可解释:指南

步骤#1:决定解释的种类

如上文部分所述,解释本质上可以是全局的(基于结构)或局部的(基于预测)。我们想帮助用户理解个人情绪预测,所以我们选择使用局部可解释技术,专门解释个人预测。

步骤#2:决定解释的形式

接下来,我们必须决定解释应该采取什么形式。它应该是视觉的,文本的,表格的,图形的?什么形式的解释既容易理解,又可能回答用户对输出的问题。我们决定向用户展示哪些单词对迫使模型将一个句子标记为积极或消极情绪最有影响。我们决定在产品中突出这些词。用户研究表明这种形式的解释是最有帮助的。

在某种意义上,这种解释的汇总为用户提供了一个观察情绪模型世界观的窗口——该模型发现哪些类型的负面情绪特别值得注意,它对隐喻等比喻性语言的理解程度如何,什么习惯性地混淆了它。

图片由 Dialpad 提供

步骤#3:在可解释技术之间进行选择

你选择的技术将取决于你建立的深度学习模型的类型。有些技术是模型不可知的,也就是说,它们适用于每一种模型,而有些技术是特定于模型的。我们尝试了各种技术,对输出结果进行了多次人工评估,并在局部扰动技术家族中选择了一种技术,它给了我们最直观、最丰富的解释。

在这个过程中,我们必须做出几个设计选择——例如,我们选择的技术返回对预测最重要的单词和短语的加权列表。我们必须做出选择——我们是应该向用户显示所有重要的单词,也许用渐变的颜色来表示哪些单词更重要和更不重要,还是只显示单词的子集。最后,我们定义了一个阈值,决定只突出显示最重要的单词。我们还编制了一个格式规则列表,用于清理和完善解释——例如,如果短语中的大部分单词被认为是重要的,则突出显示整个短语。

您用于个人预测的任何技术都必须集成到模型推理代码中,并在模型做出预测后执行,因为您实际上是在解释那个预测。有许多打开 你可以适应解释你的模型。

步骤#4:优化技术

我们必须优化所选择的技术,因为情感功能必须足够快速和灵活,以便在实时环境中操作,并且对于做出预测所花费的时间,我们现在添加了一个解释预测的额外任务。你可以通过删除无关的操作,使用更有效的库和函数来完成中间任务,甚至改变技术来更快地返回结果。

我们最重要的学习?

关键是要让你的听众站在最前面,以听众可能喜欢的解释的形式和类型为基础做出决定。为满足管理标准而给出的解释可能与为日常用户的教育而给出的解释有很大不同。

我们的用户发现,这一功能升级有助于他们更好地理解和信任情感分析功能,其在产品中的使用和可见性也有所增加。

可解释性也帮助我们建立了一个更好的模型。通过各种解释技巧,特别是本地解释的集合,我们能够识别地址:

  • 误报的原因,模型不应触发的次数。
  • 可能导致不利结果的数据偏差。

结论

理解人工智能的内部工作有很多目的,每一个目的都促进了人工智能的范围和有效性。我们必须理解建立更好和更公平的模式,建立信任,并建立一个包容和致力于人类繁荣的数字未来。

在 10 分钟内制作一个简单快速的聊天机器人

原文:https://towardsdatascience.com/making-a-simple-and-fast-chatbot-in-10-minutes-2d84a4ba35e?source=collection_archive---------38-----------------------

图像来源

在现实世界中,聊天机器人的响应时间非常重要。无论是旅游业、银行还是医生,如果你想真正帮助你的客户,响应时间应该更短,类似于与客户服务代表交谈时的响应时间。

除了时间,理解聊天机器人的主要动机也很重要,每个行业都不能使用类似的聊天机器人,因为他们有不同的目的,并有不同的语料库来回复。

虽然变形金刚很容易得到合适的回复,但回复可能需要时间。另一方面,就时间而言,可以应用各种其他方法,甚至可以找到一些基于规则的系统来获得适合所提问题的适当答复。

你可能已经联系了多少次旅行社,要求退还你去年在封锁期间预订的机票,我敢肯定,得到一个恰当的答复是远远不现实的。

现在让我们制作一个简单的聊天机器人并安装这些包:

pip install nltk 
pip install newspaper3k

包装报纸 3k 有如下几个优点:

  1. 多线程文章下载框架
  2. 新闻网址可以识别
  3. 可以从 HTML 中提取文本
  4. 从 HTML 中提取顶部图像
  5. 所有的图像提取都可以从 HTML 中完成
  6. 可以从文本中提取关键词
  7. 可以从文本中提取摘要
  8. 可以从文本中提取作者
  9. Google 趋势术语提取
  10. 用 10 多种语言工作(英语、德语、阿拉伯语、中文……)

按如下方式导入库:

#import libraries
from newspaper import Article
import random
import nltk
import string
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics.pairwise import cosine_similarity

我已经在我以前的博客中谈到了 CountVectorizer。

余弦相似性或余弦核将相似性计算为 X 和 Y 的归一化点积:

sk learn . metrics . pairwise . cosine _ similarity(X,Y=None,dense_output=True)

参数

X{ n array,稀疏矩阵}形状(n_samples_X,n_features) 输入数据。Y{ n array,shape 的稀疏矩阵}(n _ samples _ Y,n_features),默认=无 输入数据。

如果没有,输出将是 x 中所有样本之间的成对相似性。 dense_output bool,default=True 即使在输入稀疏时是否返回密集输出。如果为 False,则如果两个输入数组都是稀疏的,则输出是稀疏的。

回报

核矩阵:n 个形状数组(n_samples_X,n_samples_Y)

import numpy as np
import warnings
warnings.filterwarnings('ignore')

在我的博客中已经解释了标记化。这里我们从一个医疗保健网站获取数据

article=Article("https://www.mayoclinic.org/diseases-conditions/chronic-kidney-disease/symptoms-causes/syc-20354521")
article.download()
article.parse()
article.nlp()
corpus=article.text
print(corpus)

#tokenization
text=corpus
sentence_list=nltk.sent_tokenize(text) #A list of sentences

#Print the list of sentences
print(sentence_list)

一旦你准备好了语料库,你可能不得不考虑用户或客户可能会问或说的问题,这些问题与我们拥有的内容没有任何关系。

它可以是问候信息、感谢信息或类似再见的信息。团队需要对这样的信息和他们的反应进行头脑风暴。

我试着在这里介绍一些。

问候机器人响应

#Random response to greeting
def greeting_response(text):
 text=text.lower()

 #Bots greeting
 bot_greetings=["howdy","hi","hola","hey","hello"]

  #User Greetings
 user_greetings=["wassup","howdy","hi","hola","hey","hello"]
 for word in text.split():
 if word in user_greetings:
 return random.choice(bot_greetings)
#Random response to greeting
def gratitude_response(text):
 text=text.lower()

感恩机器人回应:

#Bots gratitude
 bot_gratitude=["Glad to help","You are most welcome", "Pleasure to be of help"]

 #User Gratitude
 user_gratitude=["Thankyou so much","grateful","Thankyou","thankyou","thank you"]

 for word in text.split():
 if word in user_gratitude:
 return random.choice(bot_gratitude)

排序列表

# Default title text
def index_sort(list_var):
 length=len(list_var)
 list_index=list(range(0,length))
 x=list_var
 for i in range(length):
 for j in range(length):
 if x[list_index[i]]>x[list_index[j]]:
 #swap
 temp=list_index[i]
 list_index[i]=list_index[j]
 list_index[j]=temp

 return list_index

聊天机器人响应功能,使用预定义文本的余弦相似度来响应。

#Creat Bots Response
def bot_response(user_input):
 user_input=user_input.lower()
 sentence_list.append(user_input)
 bot_response=""
 cm=CountVectorizer().fit_transform(sentence_list)
 similarity_scores=cosine_similarity(cm[-1],cm)
 similarity_scores_list=similarity_scores.flatten()
 index=index_sort(similarity_scores_list)
 index=index[1:]
 response_flag=0
 j=0
 for i in range(len(index)):
 if similarity_scores_list[index[i]]>0.0:
  bot_response=bot_response+' '+sentence_list[index[i]]
 response_flag=1
 j=j+1
 if j>2:
 break

 if response_flag==0:
 bot_response=bot_response+" "+"I apologize, I dont understand"

 sentence_list.remove(user_input) 

 return bot_response

对于从聊天退出列表中退出,单词被写成“退出”、“再见”、“回头见”、“退出”。

作为对这些话的回应,聊天机器人将退出。

启动聊天机器人,尽情享受吧!

#Start Chat
print("Doc Bot: I am DOc bot and I will answer your queries about chronic kidney disease, if you want to exit type, bye")

exit_list=['exit','bye','see you later','quit']

while(True):
 user_input=input()
 if user_input.lower() in exit_list:
 print("Doc Bot: Bye Bye See you later")
 break
 elif greeting_response(user_input)!= None:
 print("Doc Bot: "+ greeting_response(user_input))
 elif gratitude_response(user_input)!= None:
 print("Doc Bot: "+ gratitude_response(user_input)) 
 else:
 print("Doc Bot: "+ bot_response(user_input))

请参见以下聊天机器人的回复:

作者图片

重要的是要注意到“谢谢”并不在我们的机器人感恩功能中,因此有了这个消息。随着时间的推移,您可以扩充这样的词汇表,或者利用正则表达式对其进行微调。

结论:

这是一个小例子,让你开始制作快速简单的聊天机器人。你需要为不同的行业微调聊天机器人,这些行业的语料来自实时数据或云上的一些存储。

我们需要记住,实时数据有其自身的挑战,聊天必须从最新的数据中得到回应。一个例子是在旅行社订票。

感谢阅读!

原载于 2021 年 1 月 6 日 https://www.numpyninja.comhttps://www.numpyninja.com/post/making-a-simple-and-fast-chatbot-in-10-minutes

通过辩论让 AI 变得安全

原文:https://towardsdatascience.com/making-ai-safe-through-debate-935fe8a0ec5?source=collection_archive---------19-----------------------

播客

伊桑·佩雷斯解释了人工智能辩论如何让我们安全地获得超级智能

要选择章节,请访问 Youtube 视频这里

编者按:这一集是我们关于数据科学和机器学习新兴问题的播客系列的一部分,由 Jeremie Harris 主持。除了主持播客,Jeremie 还帮助运营一家名为sharpes minds的数据科学导师初创公司。可以听下面的播客:

苹果 | 谷歌 | SPOTIFY | 其他

大多数人工智能研究人员相信,有一天我们将创造出超级智能系统——在各种各样的任务中远远超过人类的机器。

如果这种情况最终发生,将会带来一些潜在的严重问题。具体来说:如果一个系统是超智能的,我们如何保持对它的控制?这是人工智能对齐问题的核心——将高级人工智能系统与人类价值观对齐的问题。

对齐问题的完整解决方案必须包括至少两件事。首先,我们必须确切地知道我们希望超级智能系统做什么,并确保当我们要求它们做时,它们不会误解我们(“外部对齐”问题)。但是第二,我们必须确保这些系统是真正地在尝试优化我们要求他们做的事情,并且他们没有试图欺骗我们(“内部对齐”问题)。

创造内部一致的超级智能系统可能看起来是不同的问题——许多人认为它们是不同的。但在过去的几年里,人工智能研究人员一直在探索一种新的策略家族,一些人希望这种策略能够让我们同时实现超级智能和内在一致性。今天的嘉宾 Ethan Perez 正在使用这些方法构建语言模型,他希望这些语言模型能够成为未来超级智能系统的重要组成部分。Ethan 曾在谷歌、脸书和 MILA 从事前沿研究,现在正全职致力于开发具有泛化能力的学习系统,有朝一日这种能力可能会超过人类。

以下是我在对话中最喜欢的一些观点:

  • 研究创造超级智能人工智能系统的方法的挑战之一是,超级智能的含义相当不清楚。比 90%的人类都聪明的系统是超级智能吗?99%呢?如果一个系统只和人类中值一样聪明,但却能以百万倍的速度思考,因为它工作在计算机时钟时间上,那会怎样?或者,如果人类水平的智能可以简单地被复制大量次,允许并行探索许多不同的可能性,会怎么样?这些问题没有普遍接受的答案。
  • 有可能监督学习技术无法让我们一路到达超级智能系统。这是因为他们依赖于人类产生的数据,只能学习像那些人类一样表现(有一些额外的优势,我不会进入)。从一个角度来看,监督学习系统可以说是“模拟器”而不是“原始思考者”,但伊森认为,通过教它们简单的逻辑,或许有可能将它们的能力扩展到超智能领域。
  • 这种逻辑就是分解:伊桑的工作包括训练语言模型来分解抽象和复杂的问题(比如,“苹果应该是非法的吗?”)转化为他们所依赖的更简单、更易处理的子问题(比如,“苹果有多有害?”,以及“一件事要有多有害,我们才能宣布它为非法?”).然后在子问题上重复这种分解方法,这个过程可以根据需要重复多次,以确保我们得到的最终子问题是简单的。如果这些最后的问题足够简单,像 GPT-3 这样的人类训练语言模型可以用来直接回答它们。这种技术属于统称为迭代蒸馏和扩增(IDA)的策略家族。
  • 这种方法的一个好处是它是人类可以理解的。至少在原则上,人类可以调查每个分支子问题,并确信人工智能使用的逻辑是合理的,并且人工智能没有试图欺骗他们(这是当前在人工智能比对文献中深入探索的一个严重问题)。但在实践中,Ethan 的系统生成的问题和子问题树太大,人类无法详细解析。因此,Ethan 正在探索一些方法,可以让人类更有效地发现给定的人工智能系统是否提供了真诚的答案。其中一种方法是辩论:通过让两个人工智能系统在一个精心控制的环境中相互辩论,逻辑错误或欺骗可能会浮出水面,并被人类法官抓住。我们讨论了这种方法可能有效的一些原因,以及可能无效的一些原因。

你可以在推特上关注伊森,或者在推特上关注我

播客中引用的链接:

章节:

  • 0:00 介绍
  • 1:37 伊森的背景
  • 7:26 与 IDA 的问题
  • 12:09 哥德尔不完全定理
  • 15:01 当今 IDA 的角色
  • 26:45 国际开发协会和 GPT-3 的能力
  • 29:54 系统和辩论流程
  • 41:21 让 AGI 发挥作用
  • 49:33 我们控制这些系统的能力
  • 51:41 总结

请查看下面的文字记录:

杰里米·哈里斯(00:00):
大家好。我是杰里米。欢迎回到迈向数据科学播客。今天的这一集是关于人工智能中最大的未决问题之一,句号。这就是我们是否能够使用当前的人工智能系统达到超人智能水平的问题。

Jeremie Harris (00:18):
许多人怀疑我们是否能够使用传统的机器学习来实现超人的智能,原因之一是传统的机器学习算法通常是根据人类创造的数据进行训练的。因此,逻辑是,你怎么能通过在人类水平的数据上训练它来达到超人的智能呢?

Jeremie Harris (00:38):
现在,有很多策略可以解决这个问题,试图从人类水平的数据中获得超人的智能,其中一种叫做迭代蒸馏和放大,简称 IDA。虽然 IDA 本身有多种形状和大小,但迄今为止,IDA 最常见的卓有成效的应用之一是问答系统。现在,这通常包括将复杂的问题分解成简单的问题,从理论上讲,这些问题可能非常复杂,人类无法理解,人类实际上可以解析,处于人类水平的人工智能系统实际上可以回答和处理。

Jeremie Harris (01:12):
我今天的嘉宾 Ethan Perez 是 IDA 风格问答系统的专家。我们将会讨论这些系统,他对这些系统如何产生 AGI 的想法,以及他对人工智能安全更普遍的思考。所以,有很多要了解的。我希望你和我一样喜欢这次谈话,没有任何进一步的麻烦,让我们开始吧。

杰瑞米·哈里斯(01:32):
你好,伊桑。非常感谢你参加我的播客。

伊桑·佩雷斯(01:34):
嘿。很好聊天。

杰瑞米·哈里斯(01:37):
你能来我真的很高兴。实际上,这是一次我一直很兴奋能和某人进行的谈话,而你绝对是最好的人选。我真的很好奇你对一种特定的比对 AI 安全,AI 比对策略的看法,这是一种可能会在辩论或 IDA 中出现的策略。我们一会儿会讲到这是什么。但首先我想了解你一点,探索你的背景,你是如何来到这个空间的。那么,你是如何发现人工智能安全和人工智能对齐的,是什么让你全职研究它?

Ethan Perez (02:12):
我对人工智能的长期影响普遍感到兴奋。我,在早期,有一些数学背景,我在想,哦,有了这种背景我能做些什么有影响力的事情。对机器学习有了更多的了解。然后我读了尼克·博斯特罗姆的书《超智能》,我觉得这本书大概是有这些兴趣的人的常见读物。我认为这让我开始思考人工智能的长期影响,哦,我真的应该思考当我们的技术在能力上接近人类水平,甚至超过人类水平时会发生什么。

伊桑·佩雷斯(02:51):
这可能是我生命终结时发生的事情,甚至不是在我的有生之年。但我认为,这真的是人工智能将产生许多影响的地方,也是我们能够使用人工智能来实际提升我们人类知识的地方,这是我真正关心的事情。

Jeremie Harris (03:06):
顺便提一下,我想问一点关于超智能的事情。是什么超级智慧改变了你对事物的看法?读了这本书,你的观点是如何转变的?

Ethan Perez (03:17):
我认为这本书非常注重长期考虑。我不认为我有足够的专业知识或时间去衡量尼克当时对存在风险和其他事情的非常具体的论点。但我认为它确实提出了一些论点,即人工智能和非常强大的人工智能系统是可能的。

Ethan Perez (03:41):
我记得的一个关键论点是,假设我们有一个系统可以在某些任务上达到人类水平的能力。也许一些可以想象的方法就是模仿人类的大脑。这可能在计算上非常昂贵,但至少在原则上,这似乎是可能的,因为我们是这种智能系统的一个例子。我们只需要复制它。

Ethan Perez (04:09):
然后,如果你做某种复制程序,也许如果你认为神经科学[听不清 00:04:13]是不可能的,我们可以在很大规模上对人类文本或数据进行监督学习或无监督学习,并获得类似的效果。但这似乎有点道理,然后他提出了这一点,哦,你可以在很大程度上加速或并行化该软件,然后得到某种超人的东西,在某种意义上,它可以比人类更快地做事情,但在人类水平的能力质量上。

伊森·佩雷兹(04:40):
我认为这让我很兴奋,哦,我的阅读速度和我能学到的东西太多了。如果我能有 1000 份我的拷贝,去阅读互联网上的不同部分,那将是非常令人兴奋的。我正在寻找一种新的饮食或寻找一个新的哲学问题,然后向我报告他们收集的所有信息。我认为这是一个似是而非的论点,对我来说似乎很现实,哦,这似乎很合理,我们可能会得到比我们在集成方面做得更多的系统。

耶雷米·哈里斯(05:18):
是啊。从某种意义上来说,这几乎就像是在玩智力是一个定义非常模糊的东西的游戏,在这里你甚至可以通过几乎完全复制人类的神经硬件而变得超级聪明。在一个不同的媒介中进行,在那里计算会更快,因为它是[听不清 00:05:37]细胞或其他东西的基质。你马上就有了某种东西,它实际上是超人的,尽管算法只是人类的。这是一种有趣的…是的,硬件软件方面。

杰瑞米·哈里斯(05:49):
这是否给了你提示?就像,你准备好了超级智慧,你就像,“我知道我想把这作为我一生的工作。”

伊森·佩雷斯(05:53):
这促使我接受了我的第一份主要研究实习,并且-

Jeremie Harris (05:58):
在 MILA,对吗?

伊森·佩雷兹(05:59):
是的。在 MILA。没错。艾伦·库维尔是一位伟大的导师。我在那里有其他非常好的同行,并最终有了一篇成功的论文。然后,我真的很享受整个过程。我对我们如何利用机器学习来帮助人类提升我们的集体知识感到非常兴奋。我只是读了很多书,总是很兴奋地想了解这个世界。有时候,我觉得非常瓶颈,或者我觉得我们真的需要在回答一些关于世界的问题的能力上有所改变。尤其是,我在哲学方面思考这个问题,看起来,哦,这些真的是很难的问题,看起来我们需要很多很多年才能回答一些问题。我想,我们真的需要思考新的方法来解决真正具有挑战性的问题。

Ethan Perez (06:50):
然后,我想在第一次研究实习后,我开始更广泛地思考,哦,还有哪些方法可以让我们超越人类的能力。是的,我的意思是,没有太多的方法可以做到这一点,这似乎是合理的,这就是我遇到迭代蒸馏和放大的地方,以及在不同范式的背景下进行的辩论,以超越人类的能力,而不仅仅是模仿人类的能力,监督和非监督方法都可以做到。

Jeremie Harris (07:26):
这实际上给我们带来了另一个有趣的方面,也就是从一开始,你就在接近 IDA,迭代蒸馏和放大,这是我从对话开始就一直在取笑的东西。你谈到这是从人工智能系统获得超人能力的一种方式。我很乐意讨论这一点,因为通常当我听到 IDA 谈论时,我会花更多的时间与 AI 安全社区的人交谈,所以他们专注于 IDA,将其作为实现可以被询问的安全 AI 系统的一种方式。我也想谈谈这个,但我真的很好奇,是什么阻止我们在没有 IDA 的情况下获得超人的性能。我认为那可能是一个有趣的起点。

伊森·佩雷斯(08:06):
是的。是的,我的意思是,我认为基线,思考它的起点是,嗯,我们训练系统回答问题的默认方式是监督学习。这是训练系统回答问题的所有最先进和标准的方法,MLP 只是使用监督学习,我们收集问题答案的大型数据集,然后我们学习从问题到答案的映射。这是一个很好的范例,只要我们能够收集问题的答案,这对于人们在谷歌上搜索的许多问题和非常实际的问题都是可能的,比如,这个人是什么时候出生的?但是,当我们无法收集问题的答案时,这种范式基本上就崩溃了。

Ethan Perez (08:53):
然后,基本上,然后我们只是没有任何训练数据来训练我们的监督学习算法。这基本上是迭代蒸馏和放大试图解决的问题是,假设你有一个系统可以进行人类水平的问题回答,因为你已经在我们有人们收集的问题答案的数据上训练了它。所以你有了这个黑盒子,投标问答系统。现在的问题是,我们如何使用这个系统来回答一些超出其分布的问题,因为它没有被一个问题的答案所标记?

伊桑·佩雷兹(09:30):
比方说,就像哲学中的问题,我认为这是一个很好的例子,因为我们没有这类问题的答案。因此,它们可能不在分布范围内,可能需要不同的推理过程才能得到答案。但是我们有一个非常好的问答系统,可以回答很多其他相关的问题。

Ethan Perez (09:49):
我们可以考虑的解决这个问题的方法是,将我们没有实际答案的问题分解成子问题,我们可以用现有的问答系统来回答这些子问题。所以我们可以把它分解成,我不知道,如果这样的问题,人们有自由意志吗?我们首先会有一个问题,自由意志是什么意思?然后我们可以围绕自由意志的神经科学提出一些问题,等等,等等。然后,对于这些问题中的每一个,我们可以用我们的问答系统来回答它们,或者如果因为它们具有挑战性而需要进一步细分,我们可以进一步细分它们,然后回答这些子问题。

Ethan Perez (10:34):
我们希望通过不断地将这些问题分解为子问题,我们最终会找到一个有监督的问答系统需要训练的问题;其中这些子问题是我们可靠地期望我们的训练模型准确回答的那种问题。那么,现在我们已经回答了这个大问题的一系列不同部分,给定这些子问题的答案,我们预测最终答案应该容易得多。

Jeremie Harris (11:04):
所以,简单地说,为了确保我理解它,你有一些复杂或非常困难的问题,这个问题名义上需要超人的智慧来回答。你拥有一种,也许是人类的,甚至是你训练出来的亚人类水平的智力。你可以训练它,因为你有一大堆真实人类给出的问题和答案,所以你可以用这两样东西来训练这种大致人类水平的智能。然后我们希望可以把这个非常复杂的问题分解成子问题,最终可以用这个略低于人类或大致相当于人类水平的智能来回答。这就是计划吗?

伊桑·佩雷兹(11:46):
是的。没错。

Jeremie Harris (11:50):
这太酷了,因为对我来说,如果这是真的,如果我们真的可以做到这一点,那么原则上没有问题,如果我错了,请纠正我,但是没有问题不能被分解成最终人类可以理解的子问题。

Ethan Perez (12:09):
我想你可能会进入,如果你做非常一般的陈述,你可能会进入围绕哥德尔不完全性定理的问题,我们知道有些真实的陈述我们无法证明答案。但是也许有一个适度的版本,我的意思是,一些用来证明哥德尔不完全性定理的例子有点奇怪,人们并不真正关心它们。但是你可能会说,对于大多数我们真正关心的问题,可能有一些合理的方法把它们分成子问题,足够多的子问题。在某些情况下,我们可能会回答非常多的子问题,是的。

哈利斯(12:56):
对不起。你能详细解释一下与此相关的哥德尔不完全性定理吗?我想可能有些听众不熟悉哥德尔的不完全性定理。

伊桑·佩雷斯(13:02):
哦,是的。

杰里米·哈里斯(13:03):
这是一个有趣的方面。

伊桑·佩雷斯(13:05):
是啊。我是说,我肯定不是这方面的专家。

杰里米·哈里斯(13:08):
当然,是的。

Ethan Perez (13:08):
但据我所知,这种说法的简单陈述是存在真实陈述,我们知道这些陈述是真实的,但无法证明这些陈述是真实的。这些通常是自我参照的陈述,就像-

耶雷米·哈里斯(13:27):
就像一个能容纳自己的筛子,或者类似的东西,是吗?

伊桑·佩雷兹(13:30):
是的,或者这种说法是错误的。他们有一种自我指涉的特质。这最初让我很难过。我想,哦,我们不能证明每一个真实的陈述。这真的令人失望,但我认为这将是一个很大的进步。我的意思是,这些很奇怪,因为它们是自我指涉的,而且有很多…有一个存在的证明,我们不能证明对每一个真实的陈述进行推理,但我认为…对我来说,这有点不清楚,在实践中实际上在多大程度上成立。

Jeremie Harris (14:04):
我想这本身就是一个有趣的问题,就像谈论 IDA 的局限性或任何策略的局限性一样,我的意思是,从安全的角度来看,我们希望使用 IDA 这样的东西来制造一种超级智能,可以探索任意复杂的想法。如果这些想法最终涉及的逻辑领域最终不是人类可以理解的,也就是说,我们实际上不能把它们分解成甚至人类可以理解的术语,那么这就像是妖怪从瓶子里出来了。从本质上讲,我们没有希望在预测这个系统的行为时重新控制这个思维过程。

伊桑·佩雷兹(14:44):
是的。我猜你可能想要一个可以说“嘿,我不能回答这个问题”的系统。

耶雷米·哈里斯(14:51):
对。

伊桑·佩雷斯(14:53):
就像“给定我的计算资源,找不到证据”之类的话。

Jeremie Harris (15:01):
我们通过引用人类水平系统或几乎人类水平系统来谈论 IDA,然后我们谈论它如何导致超级智能。我想我的一个问题是,艾达今天怎么样?游戏的状态是怎样的,你可以用 IDA 系统做些什么,否则你可能做不了什么?

伊桑·佩雷斯(15:21):
哦,是的。我认为这是一个很好的问题。我认为这种系统现在很有用,因为从根本上来说,它们,我的意思是,这就像迭代放大中的放大,你正在放大一个现有系统的能力,你已经训练它能够做更多的事情。

伊桑·佩雷斯(15:43):
例如,在我的一些工作中,我采用了标准的问答系统,它可以回答关于维基百科中某个段落的问题。他们非常擅长回答关于维基百科上单个段落的问题,但他们很难回答问题,或者不清楚如何将他们应用于答案在多个不同维基百科文章或不同段落中的问题。

伊桑·佩雷斯(16:08):
例如,乔治·华盛顿和亚伯拉罕·林肯谁出生得早?这些信息仅出现在维基百科的两篇文章中。我在工作中所做的是训练一个模型,首先为原始问题生成子问题,所以你会得到一些子问题,大意是,乔治·华盛顿什么时候出生?亚伯拉罕·林肯什么时候出生?然后,您可以使用预先训练的模型单独回答每个问题,然后将子问题的两个答案与子问题一起传递给另一个问答系统。然后它应该能够预测答案,基本上,我想是关于子问题的两个答案的争论。

Ethan Perez (16:55):
它使整个过程变得更加容易,然后我们表明它改善了当前流行的问答基准的结果。

Jeremie Harris (17:06):
你如何训练它识别子问题?我在努力思考这个问题……是不是只有一个带标签的训练集?你用的是这个吗?

伊桑·佩雷斯(17:13):
是的。我认为这是最简单的事情,但它们是一种奇怪的监督方式。得到这些问题和子问题对并不常见。是的,另一个简单的策略,如果你没有那么多的监督,我有一篇论文可以做到这一点,就是基本上利用这些大型语言模型,这些模型可以根据一些例子进行调整,从而进行推广。

Ethan Perez (17:41):
是的,所以我们基本上一直在使用 GPT-3,加上一些其他技巧,来生成子问题。您以一个问题和子问题对或几个子问题为条件,然后提示一个新问题。它可以很好地生成子问题。还有,在我的另一篇论文中,我们基本上只是想看看我们是否能在没有监督的情况下完全生成子问题。在那里,我们使用了一些来自未预见的机器翻译的疯狂方法来做到这一点。不过,如果你感兴趣的话,我可以更详细地介绍一下。但是有一种…这是你可以使用的不同方法的一个高层次。

耶雷米·哈里斯(18:22):
是的。不,我觉得非常有趣的是,你在看,有效地,用,我不知道术语是“一点点逻辑”还是一种你正在烘焙的逻辑结构来扩充 GPT-3。这让我想到了另一个问题,尤其是作为一个在这个领域工作的人,他有很多 Q & A 类型的问题。当 GPT3 问世时,你对它的印象如何?你对 lit 的出色表现有多惊讶?

伊森·佩雷斯(18:50):
我印象深刻。我想我印象最深的地方可能是使用模型来生成论点或建议,或者其他形式的长文本生成。这真的很好,尤其是大多数人问的那种问题,因为这方面可能有最多的训练数据。所以任何与政治或政治争论或经济,经济争论,护教学和宗教辩论有关的东西。它实际上只是做了一个合理的工作,我不知道,引用圣经经文或其他非常疯狂的事情;因为互联网上可能有很多关于这类事情的讨论。所以它比我见过的做这些事情的任何模型都要好。

伊桑·佩雷斯(19:46):
是的,我认为有些地方可能会失败,或者如果你想要非常精确的东西,如果正确的输出数量是一个,并且没有任何其他正确的输出,如果你想要一个问题的答案,你需要一个问题的准确答案,这仍然是…我的意思是,这不是真正使用监督。我认为这基本上是监督有帮助的地方,就是得到你想要的那种事情。

耶雷米·哈里斯(20:20):
你认为它背后有一个合理的世界模型吗?在多大程度上…因为我认为人们一直在争论的一个领域是,GPT-3 基本上是一种美化的记忆工具吗,就像你说的,“哦,我以前见过这个。我以前见过有人对圣经中的一节有这样的争论。我知道引用什么。诗句…”它实际上是在更高的抽象层次上连接点。你认为它落在光谱的哪个位置?

伊桑·佩雷斯(20:47):
嗯,这是个好问题。肯定是在做一些概括。我和一个朋友最近在玩它,他有点怀疑,我就想,“哦,那么是什么让你相信它在做某种推广呢?”他说,“嗯,它可能在网上看过很多食谱。也可能看到过关于独角兽的文章,但可能从未见过这两者在一起。”因为我不知道,这似乎不太可能。所以他只是[听不清 00:21:14]用一个…比如,“给我一个如何做独角兽眼汤的配方。”然后我们开始谈论我们如何需要红宝石,我们需要熔炼铁矿石,把它放进汤里,在上面撒上一些金粉作为装饰。

耶雷米·哈里斯(21:35):
哇。

伊桑·佩雷斯(21:35):
写得非常详细。是的,我不知道。这看起来像是一条鱼在寻找证据,证明它正在进行某种推广。我认为在某种程度上,似乎很难抓住那些没有真正做好工作的案例。

Jeremie Harris (21:53):
在此基础上,你是否预计随着 GPT3 的扩展,我的意思是,显然谷歌刚刚推出了他们的一万亿参数模型,我们可以预计在不久的将来会有更多的扩展。你认为扩大规模可能会使 GPT-3 达到你一直在探索的 IDA 战略,至少是最近探索的 IDA 战略被它所包含的程度吗;它本身就足够好,不需要这种增强,或者这种增强可以用来针对该模型的下一层失败?换句话说,这是 GP-3 加 IDA 的扩展,能让我们任意地走多远吗,我想这是我想问的。

伊桑·佩雷斯(22:35):
是的。我认为 IDA 的好处在于,它可以利用你所拥有的任何能力,得到一个可以做更多事情的模型。我认为……我不担心更大的语言模型包含了 IDA 的需求,因为无论你有什么大的语言模型,你总是可以通过编写这个深度问题分解过程来让它回答更多种类的问题。到目前为止,我们的模型越好,似乎就越容易从问题分解中获益;因为,是的,如果你有一个更好的语言模型,你就可以产生更好的子问题。

Ethan Perez (23:22):
来自 GPT-3 的问题分解比来自我们以前的序列到序列方法的问题分解做得更好。即使是在预训练的基础上,也比不使用序列的方法做得更好。这只是一个明显的梯度,从子问题中获得的好处有所提高。是的,所以我认为我们会看到这种问题分解带来的越来越大的影响。

Jeremie Harris (23:48):
这很有意思,因为我猜想在某个时候,随着这些语言模型变得越来越复杂,它们就像一个越来越复杂的世界模型一样,这个世界模型将包括问题分解的值,因此……基本上,我们可以说,GPT-N 可以同时优化问题分解和回答问题。换句话说,如果这一切都发生在同一个优化引擎的引擎盖下,你会从这种互动中受益?

伊桑·佩雷兹(24:21):
是的。我认为这似乎是正确的。只要你有你需要做的分解量的训练数据。我不知道,GPT-3 可能会在一些问题上接受训练,可能需要几个或两到四个子问题。所以它可能只是在做这个内部分解过程,并预测答案。谁知道呢?你甚至可以从内部权重中解码出子问题。

伊桑·佩雷斯(24:53):
但我认为棘手的是,你如何归纳出比人们通常在互联网上回答的问题更需要分解的问题。我认为这就是这个结构化过程有帮助的地方,因为你可以任意地将问题分解成子问题。

Jeremie Harris (25:13):
我喜欢它是因为它在玩这个……我有一个物理的心理模型,或者你可以把它称为物理、逻辑和机器学习作为一个连续体的两端。在物理学中,我们走进世界,进行一系列实验,试图找出似乎一直适用的潜在规则,比如不管发生什么,这些规则总是正确的。任何参照系中的光速都是一样的。重力也是如此等等。

杰瑞米·哈里斯(25:48):
逻辑法则有点类似于……好像你在这里假设了一条逻辑法则。问题分解定律你可以连贯地把复杂的命题分解成简单的命题,永远都是这样。这几乎就像你在试错,机器学习,让我在大象周围摸索,但实际上从来没有…就像,机器学习模型实际上不会提出规则。他们提出了预测模型,这些模型有一点点不同,也没有那么基础。

Jeremie Harris (26:18):
感觉就像你把两者结合在一起。你会说,好吧,你真的,真的很擅长建立这个世界的模型。这是一个非常灵活的模型,但是当它遇到没有被训练过的东西时,它就会失败。因此,我们认为,这个原则的补充,将是真实的,独立于上下文,给予它更大的影响。这是一个公平的框架或描述吗[听不清 00:26:41]?

伊桑·佩雷兹(26:41):
是的。不,我想差不多就是这样。是的,你做到了。

杰瑞米·哈里斯(26:45):
你认为有什么是艾达加 GPT-3,或者 GPT-N,我应该说,做不到的吗?IDA 能让我们越过超级智能 AGI 终点线吗,或者有其他东西,比如自我游戏或强化学习,必须与这些系统相结合吗?

伊桑·佩雷斯(27:06):
是的。我认为这是一个好问题,至少如果你想回答问题,而不是说,在世界上采取行动。然后,我认为一个语言模型加上问题分解会让你走得很远。我的一些不确定性是围绕…我发现的一个问题是,如果您错误地回答了一个子问题,那么这可能会作为一个错误传播到最终答案中。如果你回答“乔治·华盛顿是什么时候出生的”,就说是 1900 年。然后,你会错误地回答“他比亚伯拉罕·林肯早出生吗”这个问题。

Ethan Perez (27:56):
我认为我们需要深入思考如何进行问题分解,如何使用子问题的答案。我们可能只需要对任何不同的问题做许多不同的问题分解。我们也可能想直接问这个问题。也许维基百科上有一些文字说,“乔治·华盛顿出生在亚伯拉罕·林肯之前。”所以我们可能只想直接问这个问题。也许出生日期无法得知,所以我们想看看他们的死亡时间,也许如果他们死亡时间的差异足够大,那么我们可以得到一些估计。这将让我们对他们的出生日期做一些贝叶斯更新。

Ethan Perez (28:40):
我们可能希望将这些不同的问题分解结果集合在一起。另外,我认为其他重要的事情,是看回答子问题的模型在预测答案时的置信度。我发现的一件事是,当模型对自己的答案不太有信心时,整个过程很可能会以一个不正确的答案结束,我认为这是有道理的。

耶雷米·哈里斯(29:09):
有道理,是的。

伊桑·佩雷斯(29:11):
这是一种我们应该仔细调整的事情。它出现在我们建立的系统中,但这是我们应该小心的事情,哦,也许我们应该实际训练更好校准的模型,看看我们应该如何利用它们的信心来影响我们对整体预测的信心。这个系统有很多不同的部分,我认为确实需要仔细研究,以使整个过程正常进行。

耶雷米·哈里斯(29:38):
是的。毫无疑问,这是一个很高的赌注,尤其是就我认为的那些早期的问题而言,对吗?系统越早出错,整个树越早受到危害。那是…

伊桑·佩雷斯(29:53):
是的。

杰里米·哈里斯(29:54):
好的。这实际上把我们带到了,因为你提到了组装。你有一大堆不同的问题分解。问题分解一得出一个结论。问题分解二导致不同的结论等等。最后,你平均一下,或者你让他们都投票,然后你用这个来集合他们的预测,你会得到一些更可靠的结果。另一个角度呢,让这些系统,也许,经历某种辩论过程。我知道这是你一直在做的另一件事。

伊桑·佩雷斯(30:24):
是的。

哈里斯(30:25):
你能谈谈辩论及其在这方面的重要性吗?

伊桑·佩雷斯(30:28):
是的。我认为高层次的想法是相似的,那就是当我们有一个更困难或更复杂或不知何故不分布的问题时,我们需要以某种方式递归地分解它,以便达到这样一个点,即我们实际上可以从一个经过监督学习训练的模型中做出评估。

Ethan Perez (30:48):
辩论的方式是不同的,我将从强化学习的角度出发,讨论如何解决这个问题。假设你想问一个模式,我该不该吃 keto?给我一个答案,并解释一下为什么我会认为你给了我一个好的答案。如果你对那些解释没有那种监督,你可能想做的一件事就是让你的语言模型生成一个解释。然后,你就查一下解释,然后你看,哦,这个好像有道理吧?如果它看起来合理,那么 RL 类型的方法将奖励给出良好解释和答案的语言模型,如果它看起来不正确,则给予负面奖励。

伊桑·佩雷兹(31:39):
如果你认为答案很容易核实但很难找到,我认为这种事情很有意义。数学证明可能是一个例子,其中有一个非常复杂的推理过程,以生成整个证明。但是一旦我们有了证据,那么检查答案就容易多了,然后每个人都可以积极地奖励提出证据的模型。这种强化学习类型的方法似乎会让我们超越人类的能力,因为我们实际上并没有产生答案。我们让模型做一些昂贵的计算来得出答案,然后我们检查它们。

伊桑·佩雷斯(32:16):
问题在于它不安全,或者可能与我们的价值观不一致,因为我们基本上只是在优化一个模型,以生成令人信服的答案,或者看起来正确的答案。但是

耶雷米·哈里斯(32:27):
我们认为有说服力的事情。

伊桑·佩雷斯(32:30):
是的。是啊,没错。我认为这就是辩论的动机所在,我们有一个模型来回答一个问题。然后我们可以让同一个模型带给我们对这个问题的答案的思考,我们可能会错过,这是反对这个答案的非常有说服力的案例。所以也许它提供了另一个答案,所以现在我们既有了最初的答案,也有了相反的答案。对于一个好的模型来说,这些可能是这个问题的两个最佳答案。我们可能会想,好吧,现在我们知道的更多了,也许是一些我们可能没有的缺失信息。

伊桑·佩雷斯(33:17):
辩论,以类似的方式,是重复的放大。你可以重复整个过程,然后你可以说,好的,给定我这个答案和反驳的答案,我可以对那个回答产生一个反驳的论点,一个反驳的论点,等等,等等,直到基本上,我们有足够的信息让一个人以相当高的信心预测正确的答案是什么。然后我们可以用它来…既然我们对这些数据有可靠的人类判断,那么我们可以训练可靠的模型来做出同样的预测,只是使用监督学习。

Jeremie Harris (33:59):
这里的希望是让两个人工智能系统相互辩论,在这个过程中,它们最终以人类可理解的方式揭示彼此论点的优缺点。

伊桑·佩雷兹(34:09):
是的。

耶雷米·哈里斯(34:10):
这样我们就可以走了,哦,这个人工智能是恶意的,它试图愚弄我来帮助它实现统治世界的计划,而这个人工智能正在做正确的事情。当我看到这场辩论结束时,它的答案实际上是有道理的。这真的有用吗?我想我会想象的一件事,或者我在这里会想象的一个问题是,当这两个争论的系统大大超过人类的推理能力时,你最终会处于一种脱节的情况,就像你说的,听起来对人类有说服力的东西和实际逻辑会支配的东西之间。这种逻辑变得非常复杂,看起来欺骗一个人会变得非常非常容易,而传达真实的论点会变得非常困难。

伊桑·佩雷兹(35:04):
是的。我认为这是这种方法的主要不确定性。你可能会认为,随着运行这种辩论的模型变得更好,那么论点和反论点都会变得更好,以一种有益的方式,因为你更有可能抓住论点中的某些领域,但是是的。看起来确实有…我的意思是,有一些有趣的实验,比如 OpenAI 进行的人体实验,他们让了解物理的聪明人参与辩论过程,并试图以一种方式…非物理的,不太物理的人尝试判断辩论。对我来说,评估这些争论真的非常非常困难。

伊桑·佩雷斯(35:54):
所以我认为,这是另一件需要调整的事情,以便找出我们如何能够最容易地评判辩论,这样我们仍然可以有信心对整个过程做出可靠的评判。

杰瑞米·哈里斯(36:11):
对,因为我不知道,对我来说,这看起来很天真,这就像是一个维度的诅咒,问题领域变得越复杂,他们的推理就越复杂,高维度就越高,这些人工智能就有更多的自由。看起来这些自由度,就像是你需要楔入欺骗的空间。随着问题复杂性的增加,空间似乎也在增长。

Jeremie Harris (36:46):
但是,是的,希望有一些潜在的原则,所以我们可以实际上揭示[听不清 00:36:50]规模多一点。

Ethan Perez (36:52):
你可能需要将这些方法结合起来。我不知道。训练一些 IDA 类型的系统,然后因为它完成了这种分解,然后它能回答什么样的问题,也能判断什么样的辩论,这超出了人类的能力。然后,你可能想用这个系统作为这个辩论过程的裁判。它可能比直接使用人类注释者作为评判者做得更好。

伊桑·佩雷斯(37:22):
对于辩论,我认为动机之一是这可能是一个很好的训练信号,如果你可以训练一个模型来准确判断辩论的结果。然后,你可以把它作为某种自我游戏的奖励信号,甚至是 AlphaZero 类型的系统,其中模型优化奖励,并更好地产生这些论点。然后随着他们变得更好,你也可能认为他们可能是整个系统更好的法官。这些拼图有不同的组合,我们可以试着把它们拼在一起,但这是一个悬而未决的问题,关于怎样做才能得到可靠的判断。

Jeremie Harris (38:04):
我也很好奇的一件事,这不仅影响了研究人员选择的工作策略,也影响了他们对安全的态度以及他们认为必须要研究的校准和人工智能安全技术。这些技术问题和关于人工智能时间线的想法之间有着紧密的联系。当你认为一个 AGI 人类水平的一般智能,或者我们可以用那些术语来指的东西,将会出现;你有,我不知道,你对此有什么看法?如果是,这是否告知了您的立场,即是否要在能力、一致性或其他方面开展工作?

伊桑·佩雷斯(38:41):
是的。对此我做了一个预测。有一根很好的线。我可能要晚些时候发给你,但这个研究小组 AUT 有一个非常好的帖子,他们收集了许多不同人的人工智能时间轴。我认为从这点来看…

杰里米·哈里斯(38:53):
我会发布一个链接。我确实看到了你的非法情节,所以每个人都可以查看播客附带的博客帖子,你将能够看到伊森的非法帖子,因为我认为它有点耐人寻味。

伊森·佩雷斯(39:02):
好的。很好,是的。我认为这在很大程度上取决于你对 AGI 的定义。我想我在考虑,它既需要良好的语言建模能力或语言能力,良好的视觉能力,又能够在世界上采取行动。我认为,在我的预测中,我把它分解成两种情况。有一种情况是,我们通过组合我们目前拥有的现有组件并利用我们拥有的计算对它们进行扩展来获得一般智能。然后,我的分布还有另一个组成部分,那就是在另一个场景不成立的情况下,只是在下一个世纪或几个世纪之前,嗯,不确定它什么时候会发生。所以我会有一些时间线上的衰减分布。

伊桑·佩雷斯(39:57):
在第二种情况下,我们何时能获得总体情报似乎还不确定,因为这很可能是一些非常困难的突破……我们已经在这个问题上努力了很长时间,所以可能需要很长时间才能获得我们需要的必要突破。但在另一种情况下,似乎很有可能在短期内,如果我们得到更大的 GPT 式模型,如果我们有足够的计算能力来获得良好的性能;那么我认为我们得到相当好的语言模型似乎是合理的。然后我们只需要将它们与视觉组件结合起来,我认为这是 CLIP 和 DALL-E 以及其他一些模型的发展方向。然后,我们只需要给他们一些在世界上采取行动的能力,或者能够像我们希望的那样训练他们。

耶雷米·哈里斯(40:56):
某个身体。

伊桑·佩雷斯(40:58):
是的。也许…我不知道我是否被束缚在身体上,但是至少模型应该能够,例如,经营一家公司,选择优化一些目标的行动。除了获得和理解视觉和语言,这似乎还需要更多的工作。

Jeremie Harris (41:21):
我认为你提出这个问题的方式是每个人都在他们的脑海中含蓄地提出了这个问题,但是从来没有人像你这样明确地提出来,或者就我在评论中看到的那样。核心问题是,嘿,我们基本上解决了所有需要解决的概念性问题了吗?基本上,我们是否已经拥有了所有这些成分,强化学习,深度学习,我们只是将它们混合在一起,并添加少量的香料,然后我们就有了 AGI?或者有一些基本的东西,是否是一些奇怪的量子效应,或者一些我们必须弄清楚的东西,使 AGI 实际工作?

Jeremie Harris (41:53):
如果我没记错的话,您实际上说过,您认为目前我们有四分之一的机会拥有实现起飞所需的一切。对吗?

伊桑·佩雷斯(42:03):
是的。我想那是对的。我的意思是,这很大程度上取决于你对 AGI 的定义。我认为语言模型本身非常强大,可能已经足够好了-

杰里米·哈里斯(42:17):
[听不清 00:42:17]

伊桑·佩雷兹(42:17):
…对世界有巨大的影响。我在那篇文章中说的是四分之一,但我认为可能大多数人在这个问题上比我低。有些人会更高。

哈里斯(42:29):
哦,有意思。所以你认为大多数人会认为可能有一些缺失的概念成分?

伊桑·佩雷兹(42:37):
是的。我认为这可能是一种被 OpenAI 的一些扩展工作所削弱的观点,但一般来说,大多数研究人员似乎都是这样的,“哦,我们确实需要一些新的想法来处理事情。”

Jeremie Harris (42:55):
当我看着你的图表时,给我留下深刻印象的一件事是,你已经做到了,基本上,我们在未来 10 年左右的某个时候达到 AGI 峰值的可能性,基本上是你的大幅提升,这与我们可能已经拥有一切,我们需要的只是规模。所以在接下来的 10 年内,我们将能够扩大我们的规模。

杰里米·哈里斯(43:13):
然后,当然,你有他的高度不确定性的大时期,你喜欢,“我不知道。如果在这段时间内没有实现,扩展也不起作用,那么谁知道我们什么时候会有大想法呢?”这引起了关注吗?你担心未来 10 年我们可能会袭击 AGI 吗?你认为我们从安全的角度,从结盟的角度,从哲学的角度准备好了吗?

伊桑·佩雷斯(43:38):
是啊。这个问题问得好。我认为,在某种程度上,如果没有[听不清 00:43:47]模型,似乎很难研究这些安全方法。

哈里斯(43:48):
能力?

伊桑·佩雷斯(43:48):
是的。在我们…几年前,很难对一个问题提出一个好的子问题。是的,所以我的一部分感觉是,哦,随着我们越来越接近非常强大的语言模型,这些方法将变得越来越有用。是的,但是看起来,我不知道,也许我们需要很长一段时间来接近拥有强大的语言模型,并且有很多时间来开发我们的方法。然后,哦,然后我们会为此做好准备,我们会有所有这些超越人类能力的方法,以一种适当的方式推广。

伊桑·佩雷斯(44:32):
是的,也许更多的是轨迹的形状…

哈里斯(44:35):
有意思。

伊桑·佩雷斯(44:36):
这对我很重要。

杰里米·哈里斯(44:40):
这是否意味着我们会知道?因为现在我认为我们正在扩展世界上最大的机器学习模型。我认为每年都有 10 倍的增长。对我来说,这似乎表明,当我们找出解决方案时,我们很可能不会在人类智力水平之下哼唱,而是突破那个门槛,然后创造出比我们能处理的更大的东西。这是一个看似合理的担忧,还是你认为其他事情可以消除这种担忧?

伊桑·佩雷斯(45:13):
嗯,我认为它的计算能力非常有限。在这种情况下,我们从我们当前的方法集中得到的方法通常是智能的,看起来未来的方向是,我们需要大量的扩展。在这种情况下,在你得到的模型的质量和你使用它的计算量之间会有一些权衡。我认为这确实限制了……是的,我想就智力而言,它确实可以快速增长。

伊森·佩雷兹(45:49):
是的,看起来……我的意思是,我们确实需要更高数量级的计算能力来达到接近人类水平的智能。在这一点上,这就像是,你在用一大笔预算,谷歌研发预算的很大一部分来训练模型。这是一个问题,嗯,还有多少钱可以花在这些上面?这似乎是一个需要一段时间的过程,至少需要一些时间,甚至可能需要某种政府项目来筹集比谷歌研发预算更多的资金来扩展模型。但似乎很难就这么过去了。

Ethan Perez (46:28):
我们也有这些非常可预测的幂律曲线,随着计算的增加,语言建模的损失将如何下降?也就是说……就我们从更多计算的训练中获得的语言建模的改善程度而言,我们获得的收益正在放缓。我认为这些因素都向我暗示,事情会有所放缓。

Jeremie Harris (46:52):
嗯,我想如果他们这样做了,这将表明像 IDA prolyl 这样的策略将变得更加有价值,因为我们需要这里或那里的一些额外推动。IDA 是否有必要跨越 AGI 门槛,或者是否有其他可信的技术……IDA 本身是否是一种可信的方式,换句话说,让我们从基于人类水平数据训练的系统中获得超人水平的性能?

伊桑·佩雷斯(47:25):
是的。好的,所以我脑海中的描述是这样的,一个非常好的语言模型将捕捉到人类智力和能力的全部分布。它知道人类智力的最高端是什么样的。例如,我提出 GPT-3 就好像是斯坦福大学两个教员之间的对话。然后对话是非常独特的,这是他们引用不同的名人和非常高质量,格式良好的英语之类的东西。

Jeremie Harris (48:01):
非常复杂的对话。

伊森·佩雷兹(48:02):
对,没错。那里,我想,那里很清楚。我的意思是,那似乎…我的意思是,就质量而言,它高于人类智力的平均值。所以我认为这似乎是一个合理的地方…我的意思是,也许你可能已经认为是超人了,这取决于你的想法-

耶雷米·哈里斯(48:22):
对。没错。它选择了人类人口的前百分之一。那是超人的东西吗?我是说,也许,是的。是啊。

伊桑·佩雷兹(48:32):
是的。我是说,那已经很有用了。然后我想,也许如果你使用某种基于强化的方法,就像我描述的那样,你可以超越它。但我认为你会开始看到我描述的一些失败,模型产生的答案令人信服,但不一定正确。在那里,我认为你会陷入危险,嗯,人们可能会使用这些答案,因为它们可能是正确的,但它们也是经过优化的,只是为了说服你-

杰里米·哈里斯(49:04):
【听不清 00:49:04】。

伊桑·佩雷斯(49:04):
因此,你可能会根据错误的信息做出重要的决定。我认为,当我们试图超越人类能力的水平时,我们可能会想要…我们可能基本上需要使用蒸馏和放大或辩论的方法,以一种我们有信心会奏效的方式让我们超越人类能力的这一体系。

Jeremie Harris (49:33):
你对……总体上持乐观态度吗?因为我们已经讨论了 IDA 作为一种增强这些系统的潜力,以获得超人水平的性能。看起来我们确实有策略,至少在原则上,看起来他们有很好的机会让我们拥有超级智慧。不管这些策略中的哪一个有效,还是其他什么有效,我们似乎很有可能最终会实现目标。你对我们控制这些系统的能力持乐观态度吗?也许明智地使用它们是另外一个问题。而是我们控制它们的能力,以确保我们不会把我们宁愿放回瓶子里的精灵从瓶子里放出来。

伊桑·佩雷斯(50:12):
是的。我认为问答系统的好处之一就是我们可以决定如何处理这些信息。这并不是说我们让系统自己自主行动,我认为这是很多困难的来源。我的意思是,正确回答这个问题仍然有困难,但我认为如果我们真的能解决这个问题,我认为更简单的问题,只是让模型概括过去人类的能力,只是在预测的领域,回答问题;然后,我认为我们可以使用这些方法中的一些来帮助我们在更普遍的情况下,我们希望我们的系统只是以一种不受人类监督的方式自动采取行动。

Ethan Perez (51:03):
例如,我认为建立这种联系的一种方式是使用这个经过 IDA 或辩论训练的问答系统,为运行制造业的系统提供奖励,如亚马逊制造或在科技公司做出 CEO 级别的决策等。我认为,如果我们有某种超人的问答系统,可能会更容易获得对这些采取长期行动的系统的准确评估。

耶雷米·哈里斯(51:41):
有意思。好吧,我们希望问答系统将会成为解决方案的重要组成部分。非常感谢你的时间和想法,伊森。你有没有一个个人网站,你想让人们实际上-

伊桑·佩雷斯(51:53):
是的。

杰里米·哈里斯(51:53):
……看看他们是否有兴趣关注你的工作?

伊桑·佩雷斯(51:55):
是的。只是 ethanperez.net。

哈利斯(51:57):
太棒了。点网。太棒了。我喜欢。非常,是什么?我不想说是潮人,但它有很好的美感,是的。太好了。

伊森·佩雷斯(52:07):
很好。这是唯一可用的。[听不清 00:52:09]

杰里米·哈里斯(52:09):
不错。很好。我想,欢迎来到 2021 年。伊森,非常感谢。我真的很感激。

伊桑·佩雷斯(52:16):
是的。谢谢你邀请我。

使用脚本制作交互式 Web 应用程序 PyWebIO 方式

原文:https://towardsdatascience.com/making-an-interactive-web-app-using-a-script-the-pywebio-way-315ed65c3ae3?source=collection_archive---------16-----------------------

在制作数据科学 web 应用程序时,Streamlit 不是您的唯一选择

高桥幸一Unsplash 上拍摄的照片

网络应用是展示你作品的最有效的方式,因为它们是独立于平台和高度互动的。如果 Python 是您选择的语言,您可以选择,包括 Django 和 Flask,这是 Python 中两个领先的 web 开发框架。然而,对于你来说,学习它们并不容易,因为你要制作功能性的 web 应用程序。

之前,我已经写了几篇关于使用 Streamlit 的文章( 1234 ),Streamlit 是一个在数据科学家中很流行的趋势 web 框架。随着几个主要投资者的支持,Streamlit 预计将继续增长,如果您有兴趣了解如何使用 Streamlit 轻松制作交互式应用程序,我们鼓励感兴趣的读者探索这个框架。

在这里,我想描述一种制作交互式 web 应用程序的替代工具。GitHub 上几乎有超过 1.8k 的星星,这个趋势 Python 库 PyWebIO 允许用户仅使用 Python 脚本创建 web 应用程序,而无需任何 HTML、CSS 或 JavaScript 知识,类似于 Streamlit。然而,这是不同的—我将把讨论留到本文的结尾。在此之前,我们先来看看 PyWebIO 是如何工作的。

事不宜迟,让我们开始吧。

装置

在虚拟环境中(是的,为您的项目建立一个虚拟环境是一个好的实践),您可以通过运行以下命令使用pip来安装该包:

pip install -U pywebio

请注意pywebio需要 Python 3.5.2+。

第一次互动——让我们收集意见

顾名思义,这个 Python 库专门处理输入和输出。让我们先用一些数据输入来尝试一下。

输入示例(图片由作者提供)

如您所见,PyWebIO 为您提供了常用的 web 小部件来收集输入。该示例包括文本输入、用于连续数值选择的滑块、复选框、用于选择的下拉框以及基于单选按钮的多项选择。除了这些显示的小部件,您还有其他选项,比如文件上传和多行文本输入。

对于这些小部件,您可以添加标签、验证、占位符和许多其他微调配置。

为了便于您复制上述操作,您可以找到下面的代码。

输入示例的代码

产量怎么样?

在上一节中,为了向您展示代码和输入小部件,您已经看到我使用了put_code函数作为输出小部件。如您所见,它创建了一个灰色小框,用不同的字体显示代码。除了显示代码,最常见的是使用put_text函数显示文本,你可以使用put_table函数显示表格。

pout.put_text("This is an awesome library.")pout.put_table([
    ("Col 1 Title", "Col 2 Title"),
    ("Row 1, Col 1", "Row 1, Col 2"),
    ("Row 2, Col 1", "Row 2, Col2")
])

您将看到一行文本和一个结构良好的表格,如下所示。

输出表(图片由作者提供)

就像 Streamlit 一样,PyWebIO 也支持 markdown,这为使用 markdown 语言显示信息创造了很多机会。下面的代码和截图向您展示了一些常见的降价用法。

pout.put_markdown("# This is the Title")
pout.put_markdown("## This is the Subtitle")
pout.put_markdown("_Bold Text_")
pout.put_markdown("__Italic Text__")
pout.put_markdown("*__Bold & Italic__*")
pout.put_markdown("[google.com](google.com)")

降价示例(图片由作者提供)

除了文本,您还可以使用put_image功能轻松显示图像。

pout.put_image(open("airplane.jpg", "rb").read())

显示图片(图片来源:维基百科,授权:公共领域)

虽然我向您展示的是来自本地的图片,但是您也可以使用显示在线图片的 URL。

如果你想有一些需要特别注意的东西,你可以使用toast功能把它作为一个通知框。此通知将在指定的延迟后消失。

pout.toast("Please Pay Attention!", duration=10)

吐司示例(图片由作者提供)

另一个重要的输出/输入部件是按钮——许多 web 应用程序没有按钮就无法运行。PyWebIO 当然支持按钮。让我们现在试一试。

def show_text():
    pout.toast("Button is clicked!", duration=10)

pout.put_button("I'm Ready!", onclick=show_text)

按钮示例(作者图片)

您也可以探索其他输出小部件。例如,您可以显示下载文件的链接或显示供选择的弹出菜单。

Streamlit 与 PyWebIO

如果你用过 Streamlit,你可能会想知道 Streamlit 和 PyWebIO 有什么区别。以下是我思考这个问题时想到的四个要点。如你所见,它们不是同一类东西。

  • 整体生态系统。Streamlit 得到了更大的发展,因此,它有更成熟的小部件和更好的内置 web 应用程序的外观调整。它还提供云托管服务,让您可以轻松部署应用程序。许多数据科学家和机器学习工程师已经采用了 Streamlit。相比之下,PyWebIO 相对较新,它正在等待看它如何被该领域接受。换句话说,PyWebIO 的生态系统仍在成长。
  • 剧本执行/设计原则。 Streamlit 完全执行脚本。每当脚本中有变化时,将再次评估脚本。因此,对于某些用例来说,这可能是一个难题。相比之下,PyWebIO 线性地评估脚本。当脚本需要输入时,它不能让您继续,直到输入被提供。
  • 预期使用案例。对我来说,你可以使用 Streamlit 来开发更精致、结构更复杂、服务大众的 web 应用。相比之下,PyWebIO 擅长解决较小的任务。因为它的“线性”设计,如果你开发一个内部使用的逐步 web 应用程序,它是有用的。
  • 开发者友好。我发现它在开发阶段变得更加友好,因为它的“热加载”功能——当你更新你的脚本时,你的 web 应用程序会重新加载以反映变化。然而,从设计上来说,PyWebIO 本质上是 web 应用程序中 Python 控制台的图形表示,因此您只能使用会话和脚本中的位置。因此,您可能会发现很难立即修改您的脚本以查看更改。(编辑:根据 PyWebIO 开发人员的回应,您可以通过启动服务器进行“热加载”开发。可以在这里找到说明:https://pywebio . readthedocs . io/en/latest/guide . html # overview)

结论

在本文中,我们回顾了新的 PyWebIO 库最常见的特性,您可以使用这些特性通过 Python 脚本创建 web 应用程序。我预计 PyWebIO 将继续增长。

然而,由于它的设计原则(例如,线性执行)和更有限的用例,我怀疑它能否吸引许多数据科学家和机器学习工程师。尽管如此,您肯定可以找到该工具的一些相关用例。

感谢阅读这篇文章。通过注册我的简讯保持联系。还不是中等会员?使用我的会员链接通过支持我的写作(对你没有额外的费用,但是你的一部分会费作为奖励被 Medium 重新分配给我)。

让分析更容易:破译数据标题

原文:https://towardsdatascience.com/making-analytics-easier-deciphering-data-titles-fe8d40b451de?source=collection_archive---------25-----------------------

3 个重要的数据标题,它们的作用,以及如何与它们交互

卢卡斯·布拉塞克在 Unsplash 上的照片

作为一个不经常与分析团队互动的人,看到不同的数据标题可能会感到困惑。数据科学家和数据分析师有什么区别?数据工程师是做什么的?每个职位的人都有什么样的才能和技能?

无论您是与数据团队互动,为他们招聘,还是只是好奇这些数据角色做什么,这都是适合您的地方!我们将比较和对比数据工程师、数据科学家和数据分析师的工作,以及您对他们的期望。

对视频感兴趣?看看下面的短视频,类似的内容!

作者提供的视频

为了理解这些角色的作用,让我们先回顾一下分析过程。为了让分析产生最大影响,我们必须:

  • 在可访问的系统中拥有可用的数据
  • 将原始数据转化为分析和见解
  • 以创新的方式使用数据来推动收入增长机会、改善客户体验和/或改进我们的产品

我们将讨论的三个标题中的每一个都有助于该过程中的这些关键步骤之一。数据工程师通过从后端系统提取数据并将其暴露给分析团队,使数据可访问。数据分析师使用数据提供关于过去行为和趋势的见解。数据科学家使用数据来预测未来的行为、趋势和商业机会。****

数据分析师和数据科学家之间的最大区别是,数据分析师通常是向后看,报告已经发生的事情,而数据科学家是向前看对未来事件做出预测。数据工程师通过为这两个角色提供及时、相关和准确的数据,使他们能够更好地完成工作。

数据工程师

照片由克里斯蒂娜@ wocintechchat.comUnsplash 上拍摄

数据工程师通常有很强的技术背景,应该能够将数据从大的、非结构化的格式转换成干净的、可工作的格式,供数据团队使用。它们通过从不透明的系统中解锁数据并将其公开到数据库中以供使用,使其他数据专业人员能够完成他们的工作。

例如,如果您经营一家零售企业,您可能会将数据存储在事务系统中。数据工程师将数据从销售点(POS)系统转移到数据分析师可以引用的表中。分析师很少能直接在 POS 系统中“查询”(搜索)数据,需要从该系统到可访问数据库的转换。

优秀的数据工程师通过以下方式为数据团队的成功做出贡献:(1)有效地向其他团队公开数据;(2)了解如何优化数据格式以节省公司资金。存储数据需要成本,了解组织公司数据的最有效方式可以大规模节省成本。

除非你直接管理一个团队,否则你可能不会经常与数据工程师交流。但是,也许您有一个以前没有回答的新业务问题,您想知道该数据点是否存在于系统中的某个地方,可以提取出来进行分析。这个团队可能是回答这个问题的良好起点。

数据分析师

米利安·耶西耶在 Unsplash 上拍摄的照片

数据分析师是分析小组的骨干,帮助向业务部门提供见解。他们将数据工程团队公开的数据从原始数据转化为洞察力。例如,对于前面提到的 POS 数据,数据工程团队通常会交付一个原始的交易文件。然后,分析师寻找模式或趋势,或者使用数据来回答业务问题。

数据分析师有两个主要关注领域:(1)将数据转化为洞察力,以及(2)向业务部门报告。因此,他们通常能够胜任一种或多种数据分析工具,如 Excel、Python 和/或 R,以及 PowerPoint、Tableau 或 PowerBI 等通信工具。

您应该向数据分析师询问有关业务进展的问题—销售趋势如何?是否有某些产品组表现突出?什么是关键指标的同比比较?如何解释[指标]的[减少/增加]?

您的问题可以是有针对性的—报告单个数据点—也可以是开放式/探索性的,具体取决于具体情况。最终,数据分析师负责使用数据回答业务问题,并将其报告给业务部门。

数据科学家

照片由西格蒙德Unsplash 拍摄

被《哈佛商业评论》称为“21 世纪最性感的工作”的数据科学家职位已经成为声称从事机器学习和人工智能的公司的统称。有时候,数据科学家确实有更多的数据分析师职责,但我们将讨论数据科学家应该在公司做什么。

与向后看的数据分析师不同,数据科学家是向前看的。他们希望了解我们如何使用数据来进行预测,或者在未来推动对企业更有利的行为。数据科学家花时间了解建模和机器学习可以在哪些方面给组织带来影响,然后采取措施去做。

建模的一个常见挫折是获取可用和可靠的数据;数据科学家的大部分时间都花在寻找、清理和准备数据以输入到模型中。构建(基线)模型的实际过程已经自动化,并且随着时间的推移变得更加容易。

当与数据科学家一起工作时,你应该依靠他们来识别机器学习可以为你的组织增加价值的领域。

例如,你能从被搅动的顾客身上学到什么来预测下一个可能离开的顾客吗?你能建立一个推荐系统,在结账时向当前顾客追加销售吗?你能创建客户群并对他们进行个性化营销吗?

职位因公司而异,但总的来说,这些职位对数据团队来说是一致且重要的贡献者。每个都为组织提供了独特的价值:

  • 数据工程师从系统中提取原始数据,并将它们转换成表格或文件进行分析
  • 数据分析师从原始数据中获取洞察力,通常查看过去的趋势来回答业务问题
  • 数据科学家使用原始数据开发模型和/或预测,以推动未来的行为或见解

您对数据团队有什么样的体验?我错过了什么,你会补充吗?

有兴趣讨论更多关于数据素养的内容吗?随时 在 LinkedIn 上和我联系

让分析更容易:什么是机器学习?

原文:https://towardsdatascience.com/making-analytics-easier-what-is-machine-learning-551b81722f56?source=collection_archive---------29-----------------------

在(大约)5 分钟或更短时间内对复杂分析主题进行可解释的解释。

作者图片

有多少次你听说数据科学项目由于业务团队和数据团队之间缺乏沟通而失败?如果这种情况发生在你的公司,你见过多少次公司采取下一步措施来提升员工的技能?对于那些采取措施的人来说,这是一个为期一天的研讨会,有望引起共鸣(永远)吗?专注于解释分析内容的冗长课程?

许多公司想要更多的分析人才——不仅仅是数据科学家,还包括具有分析思维的产品负责人或能够解释分析并采取行动的营销经理。然而,他们并不总是(1)提供有意义的分析培训机会和(2)为非技术员工量身定制内容。

分析民主化的下一波浪潮不是更好的数据科学家,而是更多了解分析的非分析人员

根据我的经验,目前的分析培训内容主要侧重于培训数据分析师或数据科学家,而不是培训能够从工作中受益(但不仅仅是使用)分析的人。所以,我决定尝试一些新的东西,一个叫做让分析更容易的系列。数据科学&分析既艰难又令人生畏。本系列将分析主题,并将其翻译成可解释的解释,供不倾向于数字,但希望(或需要)了解分析的人使用。

因此,无论您是分析人才的招聘人员、查看仪表板的销售经理,还是试图了解分析如何影响您的业务的高管,这都适合您!

更喜欢视频?看看这个内容相似的 YouTube 视频。

作者提供的视频

什么是机器学习?

机器学习这个词可能会让人联想到机器人或科幻小说。虽然这可能需要一个数学博士来理解后端,但有一个简单的联系可以让这个话题不再神秘。当你听到机器学习,就想想模式识别。机器学习算法有效地获取输入(数据),找到模式,并生成输出(预测)。

作者图片

让我们举个例子——夏天的一个星期五下午,你去湖边小屋过一个放松的周末。你会注意到与冬天的星期二相比,交通特别拥挤。你可以合理地将一天中的时间(下午)、一周中的日期(星期五)和季节(夏天)与路上的汽车数量联系起来。

照片由 Iwona Castiello d'AntonioUnsplash 上拍摄

如果有人说他们将“使用机器学习来预测交通”,他们本质上说的是他们将采用已知的输入(一天中的时间、一周中的日期和季节)来预测输出(路上的汽车数量)。该模型将从过去的数据中发现存在的关系或模式(例如,夏天路上有更多的汽车;星期三路上的车更少)并使用该信息对未来进行预测。

照片由托比亚斯Unsplash 拍摄

在另一个例子中,假设去年夏天你是一家冰淇淋店的经理。每天你记录总销售额。夏天快结束了,你想知道你能卖出多少产品,这样你就不会(1)在年底有太多的库存积压,( 2)因为库存不足而失去潜在的销售机会。

在销售额特别高或特别低的日子里,你回头寻找模式。你会注意到周末的销售额往往高于平日,而且天气越热,销售额越高。你还会注意到,在下雨的日子里,你的销售额会下降——这是机器学习在起作用。您正在寻找与销售相关的模式,并利用它来预测未来的销售预期。

机器学习模型将采用这些输入(温度、星期几、降雨量)来预测总销售额。它会寻找模式——就像你观察到的那样——并将其量化为输出。

机器学习是强大的,因为它可以大规模地找到这些模式,并抓住我们可能错过的趋势。我们可以识别某一天的流量或某一家店铺的趋势,但无法识别数百天或数千家店铺的趋势。此外,我们偏向于自己的假设和信念,而模型在寻找模式时更客观。

人们会(有意或无意地)让机器学习听起来像一个巨大、棘手、复杂的话题。这并不意味着你不能知道它什么时候可以被应用,或者在高层次上他们正在做什么。

如果你认为输入中存在可以告知输出的模式,机器学习可能会对你的角色有用——想想像什么时候会有流量或哪些因素会导致冰淇淋销售这样的例子。在新客户或流失客户中是否有一种模式需要研究?产品使用趋势的预测?也购买了产品的客户的追加销售机会?

机器学习并不陌生——它已经无处不在。你生活中常见的应用可能是网飞根据你过去看过的节目推荐一个节目(识别你观看偏好中的模式)或者 Instagram 在搜索标签上整理他们认为你会喜欢的内容(识别你互动的内容类型中的模式)。

机器学习可能看起来令人生畏,但你已经在生活中定期与它的应用进行交互,并可能已经在日常生活中创建了类似的“心理模型”(看起来好像要下雨了)→ 识别以前暴雨的模式,并将其与你当前看到的联系起来)。

机器学习很难,但理解它是什么并不是必须的。敬请关注未来的主题,或者随时留下您希望看到解释的分析概念的反馈。

对联系或了解更多感兴趣? 在 LinkedIn 上给我发个便条

用 IoT 和 ML 制作更好的奶酪

原文:https://towardsdatascience.com/making-better-cheese-with-iot-and-ml-5e9cccc63c3f?source=collection_archive---------19-----------------------

利用低成本物联网和机器学习解决方案优化奶酪制作流程。

一家小型奶酪厂希望改进其生产流程,专注于产品质量。关键的焦点是改善冷藏室的温度监控,以保持产品新鲜并延长保质期。

以前的质量控制系统需要一个人每四个小时去一次冷藏室,手动从数字显示器上读取温度。这对于正常工作时间的监控很有效,但是对于晚上和周末就不行了。当然,假设四小时内没有任何差错。由于工厂位于农村地区,电力中断经常发生,因此安装了备用发电机。然而,发生了发电机无法启动的情况,这导致了周末的一些产品损失。

第一阶段侧重于改进监控,这将简要讨论,第二阶段侧重于实现机器学习,这将在本文中详细讨论。

阶段 1:改进监测

该项目的第一步是实施物联网(IoT)解决方案,以提供对冷藏室制冷系统的实时监控。虽然有一些商业物联网解决方案可用,但考虑到传感器、基础设施和云托管费用,成本往往会迅速增加,尤其是对小型工厂而言。

更具成本效益的解决方案是定制的物联网设备,利用 ESP32 微控制器和一些现成的传感器。一个简单的基于 web 的应用程序被创建并托管在本地 PC 上。

该系统测量冷藏室内部的温度、制冷机组的功耗和外部环境温度。现在,实时温度每 30 到 60 秒自动捕获一次,而不是手动进行现场测量,这提供了更一致的监控和对系统运行的更多洞察。

如果温度超过上限或下限达 30 分钟,就会发出警报,但是,似乎每隔几个小时就会发出警报,无需人工干预即可恢复正常。

正常高低限物联网监控系统趋势。作者图片。

阶段 2:使用数据获得更好的洞察力

物联网解决方案的实施提供了改进的监控和大量的实时数据,这是以前所没有的。该项目的下一阶段是实施更高级的分析,即使用生成的数据,以更好地了解过程和系统操作。

三个关键业务需求

1.怎样才能更好的实现制冷温度监控?我们需要了解常规的有害警报以及在控制范围内会发生什么。

2.制冷系统目前的能源性能如何?首先,我们能否利用现有数据建立一个良好的能源模型,我们能否确定潜在的能源节约?

3.需要做些什么来实施已确定的变更,这样做是否具有成本效益?

计划评估方法

  • 数据准备:建立数据摄取管道,包括数据质量处理。这也将允许在未来添加额外的数据。
  • 探索性数据分析(EDA) :探索数据,识别特征,识别潜在的新特性。
  • 开发和测试 ML 模型:根据业务需求,开发合适的模型并测试性能。
  • 总结成果:讨论项目这一部分的发现和后续步骤。

数据和 python 笔记本可以在 GitHub :-)上获得

数据准备

传感器描述和数据

各种传感器的描述位于sensors _ sensor _ 202107282041 . CSV中。它包括:

  • sensor_id 与日常数据文件相匹配;
  • sensor _ typesensor _ uom(计量单位);
  • sensor_uclsensor_lcl 是用于报警的控制上限和下限;和
  • sensor_uuclsensor_llcl 是用于报警的控制上限和下限。

添加了 sensor_short_name 的数据框细节,便于参考。图片作者。

感兴趣的传感器是冷藏室温度、冷藏室功耗和外部环境温度。有两个冷藏室:一个用于在制品(WIP ),一个用于配送(DP)。

物联网系统在 2021 年 3 月底实施,提供了大约五个月的高频数据。每日数据文件以压缩的 CSV 文件形式接收,由系统创建用于备份目的。该文件包含三列:

  • 时间戳 :获取传感器读数的日期和时间
  • :传感器描述文件中的原始传感器读数,单位为测量单位;和
  • sensor_id_id :与传感器描述文件匹配的传感器的整数 id。

查看原始数据的统计数据,我们可以看到当前读数(32 和 36)有大约 5000 个额外的数据点,这表明一些数据点缺失。还可以看出,温度读数(29、30 和 31)的最小值为-127,这是可疑的,并且还会影响平均值和标准偏差,这取决于该值有多少数据点。

原始数据的基本统计(第一遍)。作者图片。

数据处理

开发了一个数据管道来读取单个压缩的 CSV 数据文件,将其合并到一个数据帧中,并执行一些清理。根据实时监控系统,以下标准用于过滤质量差的数据:

  • 值-99 被分配给任何质量差或不可用的传感器值;
  • 值-127 表示一些温度传感器的数据质量差;和
  • 值-327 和 327 表示质量差的数据处于设备范围的极限。

在此应用中,温度通常略高于零摄氏度,因此-99 或-127 的值不在正常范围内。没有等于-99 的数据点,也没有处于极限的数据点,但是有 155 个数据点等于-127。移除这些之后,统计数据看起来更符合流程。

在移除质量差的数据之后,温度标准偏差和最小外观的统计数据与过程一致。作者图片。

温度数据在五分钟的时间段内被平均,以减少来自原始测量的噪声,因为系统是缓慢动作的,至少对于温度是如此。正常开关周期数据的变化略有减少,但除霜尖峰仍然突出。

对于能量分析,电流测量值(功率测量值)被转换为能量测量值,因为电流变化很快,可以在噪声电流趋势中观察到。我们还对能耗感兴趣,而不是瞬时值。在三相系统中,现场电压为 400 伏。假设平均功率因数为 0.85。该分析的温度数据是一个小时内的平均值。

这些步骤在data-ETL . ipynb中有所概述。

探索性数据分析

外部温度呈正态分布,有道理。WIP 温度看起来像预期的那样具有特定的设定点,然而,DP 温度似乎具有两个不同的设定点。在能量上,我们可以看到设备关闭的时间段(峰值在第一个框中)。

每个传感器的数据分布。图片作者。

在分析时间序列趋势(温度和能量)时,似乎有一些能量峰值与工作日的每日温度相匹配,但在周末没有太大变化。包含星期几可能是一个很好的特性。周六和周日的能源消耗不同于一周中的其他日子,因为周末的工作最少。在这一周中,不断有人进出冷藏室,并添加新产品。

WIP 冷藏室每周一天的能耗与外部温度。周末观察到的明显差异。作者图片。

观察调度冷藏室的设定点差异,我们可以将冷藏室温度分为 3.5°C,以比较高设定点(4°C)和低设定点(2°C)的能耗差异。平均差额为 3 538 千瓦时/年,约为 18%。这意味着如果它在较高的设定点运行,可能会节省 18%,假设它不会影响产品质量。然而,随着时间的推移,我们需要考虑可能产生重大影响的相关变量。

比较低(2°C)和高(4°C)设定点之间能耗分布的箱线图。作者图片。

这些步骤在EDA . ipynb中有所概述。

使用异常检测进行冷房温度监控

更一致的监控中的一个见解是每 6 小时发生的显著的自动除霜循环。这是大多数有害警报的原因。这不是常识,也很少引起对之前人工读数的关注,除非读数是在这段时间内获得的。实时监控使这一点变得可见,但有害警报无助于新系统的采用。

六小时制冷循环,显示了一个清晰的模式和除霜循环接近尾声。图片作者。

解决恼人警报的一个解决方案是使用自动编码器、卷积神经网络。有一个使用 Keras 库进行时间序列异常检测的很好的例子,它使用了来自 pavithrasv 的自动编码器,该编码器被用于本分析。它基本上接受输入数据并对其进行编码(压缩),减少特征,然后开始解码特征以重建原始数据,同时将误差降至最低。因此,确保输入数据的高质量和正常对于手头的流程非常重要。

我们有六小时一个周期的温度趋势,在正常情况下是可以预测的。在检查了时间序列趋势后,确定了一个好的时间段作为自动编码器的训练数据(在 2021–05–07 16:30 和 2021–05–11 4:20 之间)。这种方法的困难在于处理未标记的数据和直观地找到好的周期。研究了一个典型的循环,以确定创建训练序列所需的时间步长。典型的时间步长约为 74,即 6 小时 15 分钟。

指标

在定义 Keras 模型时,选择均方误差(MSE)作为损失函数,以惩罚较大误差的益处,这对于该应用至关重要。对于其他参数,使用默认值。

模型评估和选择

经过训练后,我们看到该模型与训练和验证数据集都非常吻合。通过绘制 MSE,在训练损失最大值为 0.13 时计算重建阈值。当参数调整过多时会遇到一些困难,导致模型中的大量损失。

派遣冷房温度的培训与验证损失。图片作者。

确定重建误差阈值的训练损失函数的分布。图片作者。

从模型中检查和重建单个序列,并计算误差以验证模型的拟合。使用训练序列之一,我们观察到良好的拟合和最小的误差。使用一些检测到的异常序列,可以清楚地看到大误差区域。

无异常的重建趋势示例(测试数据)。图片作者。

带有异常的重构趋势示例。图片作者。

结果

将此应用于所有可用的数据,有一些我们期望捕捉的明显异常,但也有一些其他可能或可能不重要的异常。重要的是,一些设定值的变化也被确定为异常,这可能意味着过程没有正常运行。使用提供的示例,这是一个很好的第一步。

突出异常的长期趋势。有些异常是意料之中的,比如更高的峰值,而有些则在正常的控制范围内,但可能会有影响产品质量或设备寿命的重大变化。作者图片。

调整损失函数阈值会影响模型检测异常的灵敏度。如果阈值太高,我们可能会错过设定点温度偏移两度的时间段,这可能意味着使用额外的能量或减少产品的保质期。

这是一个复杂的方法,用一些基础知识和世界类库就可以实现。它可以减少我们的应用程序的有害警报,并且应该与其他方法结合使用,以实现更健壮的实现。

这些步骤在 异常-检测-dp.ipynb 中有所概述。 对 WIP 冷室做了类似的分析( 异常-检测-wip.ipynb )。

估计制冷系统的能量性能

到目前为止,人们关注的焦点一直是冷藏室的温度监测。为了建立一个衡量能源绩效的模型,需要衡量相关的变量。物联网系统测量外部环境温度以及制冷设备消耗的电流。从能源的角度来看,冷室温是一个设定点,而不是一个相关变量。然而,这将影响能耗,因为在不同时期,调度冷室似乎有两个不同的设定点。

从质量的角度来看,要求将房间保持在 4℃左右,因此任何更冷的温度都意味着在这种特定的气候下需要更多的能量来降温。因此,我们的能量模型可以估计两个设定点之间的能量差,并估计潜在的能量节省。

定义模型

使用将能耗与环境温度和设定点温度相关联的回归分析,开发了一个简单的能量模型。使用每日数据是因为数据在较小的时间间隔内可能会有噪声,尤其是具有有限特征的数据。与 EDA 阶段相同的温度分割用于数据集,即 3.5°C。对于该模型,使用每日数据,将 4°C 设定点用作基线,将 2°C 设定点用作我们的报告期。基准期和报告期的可用数据点分别为 53 个和 61 个,因此非常平衡。

EDA 还显示了能量消耗和外部温度之间的相关性。我们用基线期的散点图证实了这一点,并且在右上角观察到四个明显的异常值,以及与 lowess 线的轻微非线性。异常值已从分析中剔除。

调度冷藏室能耗与外部温度的关系,添加等高线图,并用红色表示一条 lowess 线。作者图片。

指标

均方根误差(RMSE)优于平均绝对误差(MAE ),因为它对大误差不利。与预测能量的小偏差并不重要,但一个大值会影响累积能量性能。另一个指标是调整后的 R 平方,因为我们有一个以上的功能,它提供了一个比 R 平方更鲁棒的指标,R 平方通过添加功能来提高。该指标的实际应用是解释能耗的可变性,并在我们可能遗漏某些功能时给出提示。

模型评估和选择

特征(外部温度和设定点温度)已标准化,25%的数据集用于测试。作为基本参考,拟合了 OLS 回归模型,剔除了异常值,只有轻微的非线性。该模型在测试集上产生了 3.83 的 RMSE 和 0.5356调整 R 平方,这解释了约 53%的可变性。这可能表明一些缺失的相关变量或过程控制问题。

为了看看是否可以用更健壮的算法来改进模型,我选择使用增强回归树,即 XGBoost,因为它对特征的非正态性不敏感,更容易解释和准确。我包括 3 个交叉验证,因为它是一个小数据集,使用每日数据和网格搜索进行超参数调整。为了找到最佳参数,选择了相当宽的范围,但在选择时要小心,以确保模型不复杂且可能过度拟合,例如 max_depth 不应太深。为了减少过度拟合的可能性,我还指定了 colsample_bytree子采样参数,以便它在每一步使用稍微不同的数据。

该模型得出的 RMSE 为 3.49调整后的 R 平方为 0.6147 ,比 OLS 回归模型高出约 8%。最佳参数是在最大深度为 5,采样参数都为 0.3,这意味着没有过度拟合的可接受模型。看看测试数据的回归图,残差看起来是随机分布的,只有一个点在 Q-Q 图中突出。

使用 XGBoost 模型的测试数据的回归图。用 Python 模拟 R 图——数据之旅&音乐(emredjan.xyz)图片作者。

结果

现在,我们可以在报告期数据上使用优化的 XGBoost 模型来预测在较高设定值下消耗的能源。预测能量消耗和实际能量消耗之差的累积和将给出在此期间消耗的额外能量。在此期间,额外的能源消耗为 419 千瓦时,对其进行调整以代表年度数字,预计额外的能源消耗为 2 507 千瓦时/年,即高出约 11%。

显示使用 2°C 设定点的额外能耗的累积能源性能。平线期是使用基线数据最多的时期,即设定点为 4℃。作者提供的图像。

因此,基于更保守的能源模型,该工厂可能在一年内节省 2 507 千瓦时(约 11%)。这大约是在 EDA 阶段完成的平均盒图分析的 70%。这是一个很好的节约,特别是在电力中断时使用柴油发电机,这会增加企业成本和碳排放。

需要注意的几个关键问题是,有些数据是不可用的,如关于生产量的数据,以及门打开和关闭的次数(潜在的附加功能)。另一个原因是能源消耗受环境温度的影响,我们只查看了几个月的数据,因此不能代表所有季节。

这些步骤在energy-model . ipynb中有所概述。

业务成果和考虑因素

一个关键的发现是突出的自动除霜循环。了解了这一点后,维护经理想知道为什么另一家工厂的一个拥有相同系统的冷藏室没有任何除霜循环。事实证明,这个系统没有正常运行,这也解释了为什么它需要更频繁的维护和消耗更多的能源。这种情况已经得到纠正,降低了他们组织中另一家工厂的成本。

根据能源分析,我们确定 2°C 和 4°C 的设定点之间存在能耗差异。降低约 11%的能耗可以在更大范围内产生巨大影响,尤其是考虑到更多自持能源系统,如太阳能和电池。它可能对这种系统的资本成本以及电池容量有影响。

相比之下,冷藏室的工作温度较低可能会有好处。可能会消耗稍微多一点的能量,但这可能会延长产品的保质期。考虑到产品中的固有能量,这可能意味着减少食物浪费和节约能源。

结论

该项目专注于利用新的实时数据从低成本、定制的物联网解决方案中提取价值。使用简单的机器学习技术进行异常检测,可以让人员专注于实际的警报,并避免讨厌的警报。通过持续测量能源性能,可以实现能源和成本节约。

简单机器学习模型的应用意味着,可以开发一种低成本、非计算密集型的分析解决方案,该解决方案易于理解、实施和维护,同时提供 80%的商业价值。

改进的机会

项目这一阶段的下一步是构建机器学习管道并将其集成到主要的物联网解决方案中,并提供一个接口来重新训练和部署测试模型。

后者不仅对模型维护很重要,而且因为可用数据有限,使用更大、更有代表性的数据集会有好处。

对于异常检测,自动编码器应与控制限值以及统计过程控制原则相结合,以提供更强大的报警功能。

对于能源模型,还应该收集额外的数据,以添加更多的功能和增加每日数据点。这种分析的困难在于我们可用的每日数据点有限,这可能意味着该模型在操作中不能很好地概括。

笔记本和资料可在GitHub😃上获得

参考

使用机器学习使 dashcam 视频符合 GDPR 标准

原文:https://towardsdatascience.com/making-dashcam-videos-gdpr-compliant-f9832883fe94?source=collection_archive---------11-----------------------

我的旅程从建立一个最小可行的产品一直到从零开始训练一个检测器,不需要标记一个图像

示例性 dashcam 镜头

自从我的车有了 dashcam,数据保护法就成了我的一个话题——在许多国家,分享我自己车上的原始视频是非法的,因为它们包括可识别的特征,即车牌和人脸。

对专注于交通分析和驾驶教育的德国 Youtube 频道的快速研究显示,许多人在分享视频前手动编辑这些视频,其他人使用付费服务,根本不审查可识别数据,或者只私下分享视频。这足以引起我的兴趣:在不投入太多时间和金钱的情况下,审查可识别信息的任务能自动化到什么程度?它完全符合我最近关于机器学习的研究,我正在寻找一个小项目,以获得一些不同方法的实际经验。这篇文章并没有过多关注技术细节,关于机器学习主题的优秀博客已经存在。相反,我想谈谈我是如何完成这个看似简单的任务的,我的动机是什么,以及遇到了哪些障碍。

结构很简单,我从一个最小可行的原型开始,添加一些改进来克服 MVP 的缺点,然后为了主要组件的完整重建而废弃它。

首先,我要考虑多个重要的方面。目标是一个简单的应用程序,它将 dashcam 视频作为输入,并输出一个新的视频,其中人脸和车牌是模糊的。可用性也很重要,因为这样的工具可以让很多人受益——他们中的很多人不喜欢使用命令行界面或者自己编译任何东西。直觉上,这可以分解为

  1. 将视频分割成帧
  2. 检测每个框架上的板和面
  3. 模糊这些区域
  4. 将处理后的帧编码成结果视频。

Python 和 opencv 使第 1、3 和 4 步变得非常简单——唯一缺少的部分是检测可识别信息的可靠算法。选项是有限的:

  • 自己应用机器学习技术
  • 使用传统的图像处理技术
  • 利用现有的机器学习项目

第一个选择是最有趣的,尤其是因为我可以运用我新学到的技能。然而,缺乏一个带标签的数据集(甚至是一个数据集),无法获得巨大的计算能力,以及导致 GPU 价格飙升的长期芯片短缺,让这个想法很快停止,并迫使我评估其他选择。使用纯传统的图像处理技术失败了,因为需要检测的对象种类繁多,以及错过检测的严厉惩罚(最终迫使我的程序的用户手动编辑视频)。

考虑到这一点,我研究了当前车牌检测(LPD)的情况,不要与车牌识别(LPR)混淆,后者也试图读取实际的车牌字符。很快,我找到了 understand-ai 的 Anonymizer ,这是一个开源 repo,可以自动审查图像中的可识别信息。太好了!
将匿名器集成到一个简单的 Python GUI 中(大喊到 Qt !)是一个相当简单的任务,并导致了我的工具 DashcamClearner 的工作原型,我在 Github 上发布了它。这感觉非常令人满意,最终的视频显示了良好的准确性,并提供了一个工作原型;这很快就让我保持了很高的动力。

MVP 的 Qt-GUI

经过进一步检查,开始出现一些裂缝:

  • 在一些画面中,明显没有检测到车牌
  • 由于依赖 Python 3.6 和几个严重过时的库,运输/安装非常麻烦
  • 性能。在 GTX 1060 上大约每秒 1.2 帧,一个 1 分钟的剪辑可能需要将近半个小时来处理!更糟糕的是,最终的工具应该能够在广泛的硬件上运行,可能没有 Nvidia GPUs(或 Tensorflow 1.x with CUDA 所必需的令人难以置信的复杂设置),进一步降低了已经缺乏的性能。

尽管被托管在 Github 上开源,Anonymizer 的内部工作本质上是一个黑盒——其网络的权重在第一次运行时被下载,确切的结构是未知的。这给我带来了一个问题:我根本无法提高性能,而且提高准确性也只能在匿名器的范围之外。

起初,我试图在不放弃主要思想的情况下,利用匿名器来扩展程序的可能性。为此,我引入了几个后处理选项:

  • 使用 opencv 来模糊感兴趣的区域,而不是 Anonymizer 的默认算法来提高性能
  • 模糊帧中的感兴趣区域,在大多数静态视频中,如果漏检只出现在几帧中,这将隐藏漏检
  • 扩展模糊区域以改善仅部分检测到车牌或人脸的情况

这些小的添加已经使结果看起来更好了,代价是必须处理更多的参数。但是主要的问题,缓慢的性能,仍然存在,过时的依赖仍然是一个噩梦,缺乏对工具核心部分的控制困扰着我。

也就是说,我不得不重新评估我早期的选择——在这个项目中断了很长时间之后。我又用传统的图像处理算法碰了碰运气,但无济于事。无论我如何结合阈值、梯度、轮廓检测和一般过滤,可靠的检测似乎大大超过可用的工具。作为下一个尝试,我使用了级联分类器。但类似的问题困扰着这种方法,太多的漏检和低于标准的性能。

我仍然没有数据集,我不愿意标记从互联网上搜集的成百上千的图像,我也没有足够的计算能力从头开始训练任何合理规模的网络。早期 MVP 的主体与使用 Anonymizer 完全无关,切换到另一种检测算法就像重载实现检测的函数一样简单,detect _ identificate _ information(image)。

以下来自 Github 的片段显示了该工具主体的当前状态,以及它在视频中循环、检测可识别信息、模糊信息和写回视频的不同阶段。

def run(self):
    *"""
    Write a GDRP compliant copy of the input video
    """* # gather inputs from self.parameters
    print("Worker started")
    input_path = self.parameters["input_path"]
    output_path = self.parameters["output_path"]
    threshold = self.parameters["threshold"]

    # customize detector
    self.detector.conf = threshold

    # open video file
    cap = cv2.VideoCapture(input_path)

    # get the height and width of each frame
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    length = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    fps = cap.get(cv2.CAP_PROP_FPS)

    # save the video to a file
    fourcc = cv2.VideoWriter_fourcc(*'H264')
    writer = cv2.VideoWriter(
        output_path,
        fourcc,
        fps,
        (width, height)
    )

    # update GUI's progress bar on its maximum frames
    self.setMaximum.emit(length)

    if cap.isOpened() == False:
        print('error file not found')
        return

    # loop through video
    current_frame = 0
    while cap.isOpened():
        ret, frame = cap.read()

        if ret == True:
            new_detections =  self.detect_identifiable_information(
                frame
            )
            frame = self.apply_blur(frame, new_detections)
            writer.write(frame)

        else:
            break

        current_frame += 1
        self.updateProgress.emit(current_frame)

    self.detections = []
    cap.release()
    writer.release()

在我寻求克服 MVP 状态的问题时,我通读了几篇文章,无意中发现了最初的 YOLO 论文,一个具有非常令人印象深刻的性能的单发探测器。经过多次迭代,维护人员的变更和关于名称的争议, YOLOv5 为我提供了一个非常容易使用的检测器,它具有针对许多类的预训练权重,我决定用它进行一些实验。从 COCO 基准测试中检测物体的性能看起来非常惊人,所以我决定训练 YOLOv5 只检测车牌和人脸。唯一的问题是缺少我迫切需要的标记数据。这就引出了本文的主要工作——与其尝试在网上查找数据集或花几天甚至几周的时间进行标注,为什么不自动创建我自己的数据集呢?

为了得出有标签的数据,我所要做的就是开车。想出一个方法来标记我自己的数据。但是有了早期的匿名器原型,标记可以工作,尽管速度很慢。

YOLO 是一个杰出的探测器,我所要关注的是拥有大量可靠的数据。结果现在是 DashcamCleaner 的 repo 的一部分,这是一个小脚本,允许您以正确的格式为 YOLO 创建带标签的数据。它的工作原理如下:

  • 遍历所有给定的输入视频文件和图像
  • 将输入分成训练集和验证集
  • 抓取每个视频的每第 n 帧(抓取所有帧会导致许多帧看起来几乎相同,所以这个选项非常重要——尤其是如果你像我一样有许多原始素材。我选了 n=20)
  • 将抓取的帧和图像保存到各自的输出文件夹中
  • 运行 Anomyzer 来检测人脸和车牌
  • 将所有标签导出到一个熊猫数据框架中
  • 以 YOLO 的格式保存标签,对熊猫的礼貌和它对数据帧的简单管理

这个脚本的用法很简单:

>> python generate_training_data.pyusage: generate_training_data.py [-h] input output labelformat skipframes trainsplitpositional arguments:
  input        input folder containing video and jpg files
  output       output folder for labeled training images
  labelformat  label format - yolo, voc or torch
  skipframes   for each analyzed image, skip n frames in videos
  trainsplit   training split of all data

选择 YOLO 时,输出的结构如下图所示。训练数据被分成两个顶级文件夹,即图像和标签,每个文件夹又被分成训练集和验证集。

生成的文件夹结构

总之:一旦这个公认缓慢的过程结束,近 400 分钟的记录产生了超过 35k 的 YOLO 正确格式的标记图片,具有非常好但不完美的准确性。太好了!

培训 YOLOv5 非常简单——官方报告非常好地描述了这个过程。由于对性能的关注,也由于减少到只有两类(脸,车牌),选择了更小的 yolov5s 配置。在个人电脑上进行培训对我来说很重要,因为从 GDPR 的角度来看,将我的数据集上传到像 colab 这样的网站上是有问题的。为了验证训练数据实际上被正确标记(即检查 Anonymizer 和我对 YOLO 标记符号的转换是否工作良好),在开始训练之前,我使用 Yolo Mark PWA 测试了一些随机样本。

之后,进行了只有 500 幅图像和 5 个时期的短验证训练,以确保训练有效。即使在非常有限的数据上进行如此短暂的训练,YOLO 也已经能够很好地进行归纳,并在非常不同的图像中检测出车牌和人脸!我的训练数据文件夹位于驱动器 F:的根目录下,训练命令如下所示:

python train.py --img 1920 --batch 2 --weights yolov5s.pt --workers 2 --epochs 30 --data F:/training_data/dataset.yaml

这里有一些事情需要解释:乍一看,这些参数似乎非常不理想,导致训练非常缓慢。这是有原因的:对我的标签的分析表明,我的许多目标,尤其是车牌,非常非常小(仪表板摄像头使用令人难以置信的广角镜头!),因此以全分辨率进行训练可以确保最高的精度。小批量和工人数量是由于我的 GTX 1060 老化,无法可靠地将更多数据存储到其 VRAM 中。Google Colab 可以解决这个问题(根据我的测试,一个 Pro 帐户给你一个 16G VRAM 和 4 核 Haswell Xeon CPU 的 P100),但由于 GDPR 的原因(以及 Colab 的 ToS 不鼓励像这样的非交互式、计算昂贵的任务),我必须依赖自己的硬件。

当然,这些数据并不完美。Anonymizer 遗漏了一些检测(虽然可以很容易地用手修复),但更重要的是,所有数据都来自单个摄像头。但是,使用本文中描述的工具,只需增加数据集生成的输入,从而引入更多样化的训练数据,就可以很容易地解决这个问题。数据集生成脚本将图像和视频作为输入,并将它们分成训练集和验证集,因此组合不同的来源也不成问题。

集成到我现有的工具中也相当简单,因为 YOLOv5 可以与 Pytorch Hub 一起使用。给定定制训练模型的权重路径,在代码中初始化检测器是一行代码:

model = torch.hub.load('ultralytics/yolov5', 'custom', weights_path)

剩下的就是通过将检测到的坐标输入到我的 Box 类中来稍微修改模型输出结果的方式。这允许该工具保持后处理的改进,如帧存储或 ROI 放大。结果令人印象深刻:速度比 Anonymizer 提高了 10 倍,同时检测更加可靠!应用于更一般的图像,结果显示了训练集的不平衡:人脸检测不像车牌检测那样健壮。这就是生成我自己的训练数据的能力派上用场的地方:喂养任何(无标签!)数据集中的人脸插入到generate _ training _ data . py中应该会产生更可靠的人脸检测。

就我个人而言,我对我的这个小项目的结果非常满意。创建一个易于使用的开源应用程序来审查视频中的可识别数据的目标已经完全实现,在这个过程中,我学到了许多关于不同神经网络架构的知识。主要成就是从一个工作良好但速度缓慢的黑盒检测器和没有标记的训练数据过渡到一个没有任何手动标记工作的更快的解决方案。

本文使用的所有相关代码,特别是从无标签的 dashcam 视频生成训练数据的脚本和最终的 GUI 项目,都可以在 Github 上获得。我还没有完成,但是当我已经达到了项目工作的点时,我想直接分享这个里程碑。未来的工作包括

  • 一旦“真正的”训练完成,就更新权重
  • 将工具打包为独立的可执行文件
  • 用更平衡、更高质量的数据重新训练 YOLOv5

如果您有任何问题、更正或改进的想法,请随时评论或联系我!或者下载代码或者为您自己的项目克隆代码这里

利用数据科学制定决策

原文:https://towardsdatascience.com/making-decisions-with-data-science-36fae52ccfab?source=collection_archive---------21-----------------------

一个简单的例子,说明如何使用为化学物理学开发的算法来优化商业决策。

通过将现实世界中的商业决策转化为最小化的功能,我们可以将数据科学应用到它将产生最大影响的地方。只是要小心当地的最小值!来自 Pixabay 的 Susanne stck Li 的图片。

随着数据科学中几乎每天都有新算法和技术出现,人们很容易忽略企业投资分析的最初原因。

任何业务的潜在驱动因素都很简单;基本上,这些目标是:

  1. 降低成本
  2. 增加收入
  3. 降低风险

然而,令人惊讶的是,数据科学项目常常远离这些业务驱动因素。通常情况下,工作的重点是哪里有数据可用,或者哪里有测试最新工具和算法的空间,而不是可以为组织提供最大价值的领域。

在本文中,我们将通过一个成功的例子来回顾基础知识,说明我们如何将数据科学应用于现实世界的业务决策,从而为底线带来切实的影响。

我们将“窃取”最初为预测原子分子结构而开发的盆地跳跃优化算法,并通过改进采购决策来降低成本。

优化供应链

在我们的示例中,您为 Initech 工作,这是一家专门在全球分销小部件的公司。

它从三个首选供应商那里采购这些部件。每个供应商按照相同的规格生产,并提供两种价格:

  1. 每个部件的单一单价,以及
  2. 如果是批量购买,可以享受折扣价;这节省了制造和物流成本。

批次大小和可用折扣因供应商而异,如下所示:

三家供应商的价格结构摘要。作者图片

例如,如果 Initech 从供应商 1 ( widgets to you Inc. )订购了 250 件 Widgets,这将由两批(200 件)以 10%的折扣率组成,其余 50 件以单一单价订购。

Initech 每天需要这些供应商提供各种不同的订单规模。这位首席执行官确信,这些订单的下单方式可以改进,最近他花了一大笔钱聘请顾问,这些顾问制作了一个大型幻灯片,详细介绍了他们在这个问题上与她意见一致的情况。不幸的是,无论是首席执行官还是顾问都没有能够提供一个更好的解决方案。

因此,请你来看看你能否解决以下问题:

对于给定的最小订单规模,我们如何通过向三家供应商订购来找到最低的可能成本?

当前流程

为了了解 Initech 目前是如何订购小部件的,您与采购经理进行了交谈。他们解释说,当收到订单时,他们将采用最适合每个供应商订单的“批量”价格。他们向您展示了一个今天最低订购量为 500 件的示例:

  1. 他们购买符合订单数量的最佳价值批次(这是供应商 2 对 260 件的 35%折扣)。
  2. 他们一次又一次地重复这个过程。
  3. 一旦剩余数量低于所有批量,他们将向提供最佳单价的供应商(供应商 3)订购。

对于 500 的订单,这导致:

  • 来自供应商 2 的一批(260 件),
  • 供应商 1 的两个批次(200 件),
  • 供应商 3 的 40 个单位,单位成本。

这是一辆总造价 4149。你向经理解释说,你将尝试使用优化技术来改进这一点,并且你认为流域跳跃算法可以提供一种有效的方法来降低每份订单的成本……他们嘲笑你。

“这种购买流程已经通过几代小部件采购经理传承下来,没有办法再改进了!”

建模问题

为了优化 Initech 的供应链决策,我们首先需要能够对问题进行建模。这在 Python 中非常简单,在下面的代码中,我们提供了每个供应商的详细信息,并创建了一个函数,在给定每个供应商的订单值的情况下计算总成本:

使用 Python 创建业务问题的基本模型

我们创建的函数为我们提供了我们想要最小化的东西,因为它与订单的总成本相关。下一步将应用盆地跳跃优化算法,但首先让我们了解更多关于算法如何工作。

跳盆?

流域跳跃算法是 1997 年开发的,用于化学物理领域[1]。它在问题空间中“跳跃”,探索不同的“盆地”,然后找到这些盆地的最小点。

如果这没有很大的意义,下面的图表可能有助于想象这在实践中是如何工作的。

流域跳跃算法如何跨越局部最小值点(a 和 b)以找到包含全局最小值(点 c)的流域的图示。作者图片

大量的问题可以有‘局部极小值’。这些解决方案与周围环境相比看起来是最佳的,但并不代表整个问题空间的最佳解决方案。

上图中的 a 点和 b 点代表局部最小值,c 点是可能的最佳解(全局最小值)。

盆地跳跃算法能够通过在问题空间中“跳跃”来避开这种局部最小值。在它到达的每一个区域,它会局部搜索最优(最小)点。

这一特性使它成为一种适用于大量问题的健壮的通用优化算法。

实现盆地跳跃

为了将盆地跳跃应用到我们的问题中,我们可以利用 Python 中的 SciPy 库。这需要输入一些参数,如下所述:

  • 待优化的功能。这需要有一个单一的数字输出,我们正试图最小化(这是我们上面创建的“func”函数)。
  • 对该函数输入值的第一次“猜测”。这在某些情况下可能很重要,但是在这个例子中,这似乎没有什么不同。因此,我们只是为每个供应商输入了一些任意的数量:每个供应商 200 个订单[200,200,200]。
  • niter’代表算法的迭代次数,更多的迭代可能会找到更好的结果,代价是需要更多的时间来完成。
  • 步长设置算法中每个“跳”的最大值。设置这个值需要一点反复试验,因为它将取决于手头的问题。在本例中,值为 500 就可以了。

然后我们有最小化器关键字参数,这些用于将值传递给最小化器函数,盆地跳跃算法位于该函数之上。这些描述如下:

  • 方法:标识要实现的具体算法。在我们的例子中,这是 SLSQP ,因为它允许我们输入问题的界限和约束(见下文)。
  • 界限:这些界限定义了算法中每个项目的上限和下限(在我们的例子中,是每个供应商)。因此,我们利用这一点来确保订单高于零。
  • 约束:这些类似于界限,但允许我们在整个问题中设置阈值。因此,我们利用这一点来确保所有供应商的订单都不会低于最低订单金额。

将所有这些放在一起,我们得到以下结果:

这将返回以下内容:

这里进行了很多工作,但两个最重要的输出是lowest _ optimization _ result,它详细说明了我们提供给算法的函数的最低输出(在这种情况下,它是最小订单数所能找到的最低成本)和输出 x ,它详细说明了获得最佳结果所需的输入。

舍入后,我们因此得到:

  • 供应商 1 没有订单
  • 供应商 2 的 520 份订单(两批)
  • 没有供应商 3 的订单

有些不对劲

您对这个结果感到非常兴奋,并回到采购经理那里向他们介绍这个结果。

但是,他们并不以为然:“你的‘超级智能’算法已经超序了!我们只需要 500 个小部件,但它想让我们订购 520 个。”

他们是对的。你后悔在和他们交谈之前没有看到这一点。然后,您意识到算法的任务是寻找满足最小数量的最低成本订单。

你检查成本;采购经理的流程将导致订单金额为 4,149,,但是使用流域跳跃算法的总成本为 3,723 ,订单成本减少了 10%

采购经理很惊讶:“啊,我一直被困在当地的最低价格!我从未考虑过订购更多的产品可能会降低整体成本,而且我们还可以利用额外的 20 个部件!”

你回去告诉首席执行官,通过几行代码,你已经将 Initech 的销售成本降低了 10%。她欣喜若狂,问你还可以利用数据科学改善哪些业务领域。“所有的,”你回答。

摘要

在本文中,我们看到了实施数据科学技术如何对公司的底线产生巨大而切实的影响。

工作示例提供了一个输出,作为企业可以采取行动的决策。我们基本上已经能够创建一个优化问题,将商业决策直接映射到结果。

最后,通过能够在问题空间“跳跃”,我们的算法已经能够提出一个真正新颖的解决方案,一个很容易被人类决策者忽略的解决方案。

进一步阅读

参考

[1]David J. Wales 和 Jonathan P. K.Doye,通过盆地跳跃的全局优化和包含多达 110 个原子的 Lennard-Jones 团簇的最低能量结构(1997)https://pubs.acs.org/doi/10.1021/jp970984n

让 FastRP 图嵌入为您服务

原文:https://towardsdatascience.com/making-fastrp-graph-embeddings-work-for-you-f7344a535dc3?source=collection_archive---------4-----------------------

实践教程

如何针对您的具体问题调整 FastRP 的超参数

布莱恩·阿萨尔Unsplash 上拍摄的照片

介绍

图无处不在!单个数据点可以通过多种方式连接到其他数据点。通过使用这些连接的数据,通常以图形结构表示,我们可以制作机器学习模型,这些模型有可能比仅从柱状数据中创建模型更准确。但是为了将图形数据整合到机器学习模型中,我们必须首先找到一种将其矢量化的方法。

我已经写过关于如何开始使用图嵌入并展示了一种可视化它们的方法。我的朋友 Tomaz Bratanic 和我写了一些关于两种最常见的图形嵌入技术的内部工作原理的博客文章(这两种技术都可以在 GDS 的 Neo4j 图形数据科学图书馆找到): FastRPnode2vec 。Tomaz 也写了一些关于使用 FastRP 进行节点分类和链接预测的文章。

然而,就像在 ML 模型中可能使用的任何向量嵌入一样,为了从模型中获得最佳结果,必须对所有讨厌的超参数进行调整。在这篇文章中,我将通过一个例子演示如何使用 Optuna 针对给定的节点分类问题调整 FastRP 超参数。

使用这些嵌入,我们将比较基于单词嵌入的多类分类的传统 ML 方法和基于图嵌入的方法。

因此,在这篇文章中,我们将做以下事情:

  • 构建图:将 CORA 数据集(通过 Apache 2.0 许可提供)导入 Neo4j 沙盒实例
  • 设置问题:为传统方法和基于图形的方法创建 ML 模型
  • 优化 FastRP 超参数:探索使用 Optuna 我们可以将基于图形的模型做得多好
  • 讨论和最终想法

最后,我希望你能看到,不仅严格地从图嵌入中创建一个 ML 模型是可能的,而且有时你实际上能得到比传统 ML 模型更好的结果,甚至使用比传统方法维数更少的向量!

本帖附带的 Google Colab 笔记本可以在这里https://dev.neo4j.com/classic_vs_graph_ml找到。

构建图表

为了让自己开始运行,您需要创建一个免费的 Neo4j 沙盒数据库。在这个练习中,你需要选择一个空白的沙盒。

*https://neo4j.com/sandbox/

您应该会看到如下所示的屏幕:

创建空白沙盒(作者图片)

您应该特别注意 Bolt URL 和密码,因为它们是从 Python 连接到数据库所必需的。(这个沙盒在这篇博文发表的时候就已经被销毁了,所以在这篇博文中它只是用于演示的目的。)

我们将使用 CORA 数据集,这是一个经典的图表数据集,用于查看关于机器学习主题的同行评审科学文章之间的共同引用。出于几个原因,这对于本例是一个有用的数据集。首先,数据集已经被标记。根据给定论文所属的机器学习子分支,它被分为 7 个不同的类别(稍后将详细介绍这些类别)。其次,维护人员已经创建了这些论文摘要的一系列词向量,我们将使用这些词向量来比较我们基于图的 ML 方法和基于自然语言处理(NLP)的传统 ML 模型。这些嵌入是基于 1433 个唯一单词的字典一次性编码的。最后,图形本身很简单。这是一个单部分图,意味着只有一种类型的节点(论文)和一个时间关系(引用)。许多图算法在处理单部图时效果最佳,尽管我们今天不会利用这些算法。如果不是这样,我们需要将我们的图重构为一个单部分图,这将是未来博客文章的主题。

将数据上传到图表中

为了便于导入,我已经将 CORA 数据集上传到 GitHub 的 CSV 文件中。如果你想知道更多关于如何将数据导入 Neo4j 的信息,你可以看看这篇博文。该数据集的图形模型如下所示。

CORA 图形模型(图片由作者提供)

我们要做的第一件事是,在导入数据之前,基于节点的 id,在数据库中为节点创建一些惟一性约束。这样做的好处是既能确保没有重复,又能为节点创建索引,从而加快数据搜索的速度。为此,我们通过浏览器进入沙箱。(见这篇博文,关于中途下来,如果你想学习如何访问浏览器。)从浏览器中,我们将输入以下 Cypher 命令:

接下来,从浏览器中,我们将加载 CORA 节点列表。在这个文件中,我们有每篇论文的节点 id(一个整数)、每篇论文被分配到的类(在数据集中称为subject),以及由 CORA 维护者提供的词向量(在数据集中称为features,它是一个独热编码整数的列表)。

最后,我们将引入每篇论文的关系(又名边缘)。这个文件是节点 id 的 CSV 文件。每行都有一个source和一个target节点。这样,我们知道这两者中的每一个都将通过一种我称之为CITES的关系联系在一起。

所以现在我们有一个完全填充的图表来处理。我们应该看到有 2708 个论文节点,它们之间有 5429 个引用关系。该图应该如下所示:

CORA 图的一部分(图片由作者提供)

(注意,这是图形的一小部分,由 Cypher 命令MATCH (n) RETURN n LIMIT 300返回,它防止屏幕变得过于混乱,浏览器陷入停滞。)

太棒了。现在我们有了一个图,我们可以继续做一些 ML 了!

设置问题

现在我们有了这个图,我们需要创建一个 GDS 内存图,我们将使用它来计算 FastRP 嵌入。这些图形投影非常有用,因为它们将所需的节点和关系放入有效存储在存储器中的存储空间中,并且仅包含用于运行后续计算的必要信息。为此,我们将在浏览器中运行以下程序:

如前所述,我们幸运地使用了 CORA,因为图已经是单部分的了。所以我们可以使用单个节点投影Paper,和单个关系类型CITES。请注意,我们声明此图是无向的。这是因为我们假设被引用的文章可能与引用它的文章属于同一类,反之亦然。有关如何创建内存中图形的更多信息,请查看 GDS 文档或查看我的快速视频这里

酷毙了。这给了我们从数据库中创建 ML 模型所需的一切!

如前所述,我们将使用 Google Colab 笔记本来运行我们的模型,可以在这里找到。我们将使用的许多包已经预装在 Colab 中。然而,我们仍然需要安装官方的 Neo4j Python 驱动程序以及 Optuna(当我们到达那里时)。关于如何使用该驱动程序的更多信息,请参考这段视频这篇博客文章。我们看到我们需要连接到我们的沙箱实例。这些信息可以从如上所示的沙箱 UI 中获得。

基于词嵌入的 ML 模型

让我们从嵌入这个词开始。应该预先注意,我没有创建这些嵌入,也没有机会对它们进行调优。因此,我们将不得不利用我们现有的资源,把它当作一个基准模型。

在笔记本中,有一些函数可以从 Neo4j 中获取数据,并将列转换为与scikit-learn兼容的数据类型。我在这里就不赘述了。

一旦我们有了这些数据,笔记本就使用来自scikit-learn的支持向量分类器(SVC)说明了一个多类分类模型。在这个例子中,我们使用 SVC 的默认超参数,并使用 5 重验证。这篇博文的目的不是调整这个模型,而是强调基于使用哪种嵌入的分类准确性的差异。因此,这个模型将在本文中保持一致。模型的主体是:

当运行时,发现平均精度为 0.724(当然,基于 ML 建模的随机性质有变化),并且获得以下混淆矩阵:

单词嵌入模型的混淆矩阵(作者图片)

用数字表示的类如下,它们的样本(节点)总数在括号中:

  • 神经网络:0.0 (818 个节点)
  • 规则 _ 学习:1.0 (180 个节点)
  • 强化 _ 学习:2.0 (217 个节点)
  • 概率方法:3.0 (426 个节点)
  • 理论:4.0 (351 个节点)
  • 遗传算法:5.0 (418 个节点)
  • 基于案例:6.0 (298 个节点)

很明显,我们有一个不平衡的阶级问题,但这就是生活。考虑到这一事实以及我们无法访问原始词汇,0.726 的准确度真的不算太差。

基于 FastRP 图嵌入的 ML 模型

我们将从使用上面创建的内存中的图来创建 FastRP 图嵌入开始。在与这个模型相关联的笔记本中,我们为每个节点创建了一个 256 维的图形嵌入。然后,我们像以前一样运行非常基本的 SVC 模型,并获得以下混淆矩阵:

基本 FastRP 嵌入的混淆矩阵(图片由作者提供)

我们还获得了 0.845 的平均精度!与单词嵌入模型相比,这是一个相当大的改进!这有一些很好的理由。第一,NLP 是出了名的吵。NLP 模型的质量在很大程度上取决于你输入的内容,这是基于垃圾输入-垃圾输出的原则。然而,如果不能访问词汇表,就不可能研究如何改进这些单词嵌入。然而,这些个体节点之间的连接一点也不嘈杂。事实上,让我们通过 t-SNE 降维来进一步探索这些嵌入。如果我们将这些 256 维的向量降低到 2 维,我们得到如下:

FastRP 嵌入的 t-SNE 可视化(图片由作者提供)

在一个理想的世界中,我们会看到每一个类都在它们自己的、非常可区分和可分离的集群中。虽然我们没有在所有情况下都看到这一点,但我们看到的情况多少是可以解释的。0.0 类对应于神经网络,这是一个相当广泛的类别。事实上,很可能其他课程会在这里引用一两篇论文,使它们比其他论文联系得更紧密。相比之下,遗传算法(紫色类 5.0)是一个非常狭窄和具体的主题。因此,它们与该学科之外的许多其他论文没有联系也就不足为奇了。这可能会导致它们更加集中。检查图中的其他集群可以让我们得出类似的结论。

优化 FastRP 超参数

我们现在已经看到了 FastRP 图嵌入的工作原理。然而,这些结果是在指定嵌入的维数时仅使用算法的默认设置而获得的。一般来说,在现实世界中这样做很少是个好主意。像 ML 中使用的任何其他嵌入一样,图嵌入应该通过优化它们的超参数来调整。这就是 Optuna 的用武之地。

有许多不同的 Python 包用于调优嵌入,Optuna 是最容易使用的包之一。一般的想法是,您指定一些要优化的变量,给它们一个要评估的值范围,然后指定要优化的目标度量(在本例中是准确性)。然后,Optuna 在该超参数空间中进行复杂的搜索,进行给定次数的迭代,直到找到度量的最佳值,这是通过使用这些最佳超参数获得的。

在我们的例子中,我们将使用完全相同的 SVC 模型,但是允许 Optuna 改变 FastRP 超参数,直到我们得到最佳值。这一点在这本笔记本中有所体现。

我们首先为 Optuna 将要进行的试验指定超参数:

这些params值将由 Optuna 通过复杂的搜索方法进行数学选择。它们将被输入到 ML 算法中,该算法根据params的试验值计算精度,试验值在每次运行时会发生变化:

一旦这些东西准备就绪,我们就可以开始研究了:

这里我们提供了一些初始的,任意选择的参数。然后,我们告诉 Optuna 以“最大化”的目标度量(准确性)创建研究。然后,我们让 Optuna 对这项研究进行 100 次试验,几分钟后我们就可以获得优化的超参数。在这种情况下,我们可以看到我们的精度提高到了 0.868!虽然仍然涉及到一些随机变量,但是如果您多次运行此研究,您将会看到精确度和优化的超参数值变化不大。

然而,有趣的是,在这个解决方案中,哪些超参数是最重要的:

超参数重要性(图片由作者提供)

很明显,嵌入维数支配着解决方案。Optuna 在这次运行中确定的最佳维数是 506。虽然这在我们的范围的较大一端,有趣的是注意到这比 1433 维的单词向量少多少。其次,我们可以看到,转移矩阵中的第四个权重比第三个权重更重要(见这篇博文),这证实了原始算法的作者所报告的

讨论和最终想法

在这篇博文中,我展示了一个针对给定问题的 FastRP 超参数的简单优化。重要的是要注意,这个过程绝对应该用你的问题的具体图表来完成。我在选择这张图时也非常特别,因为它让我们有机会评估传统的 ML 模型和图形模型。我不会说这是每个图,甚至每个问题的正确方法。例如,如果您的图不是非常密集连接的,那么 FastRP 计算中涉及的矩阵可能会太稀疏而无法获得有意义的结果。

我在帖子中没有展示的一件事是除了非常基本的 FastRP 算法之外的任何东西。还有许多其他的图形嵌入算法,Neo4j 和其他地方都有,可以使用。事实上,FastRP 有一个更复杂的兄弟,叫做fastr extended,它也可以将节点属性引入到这个嵌入中!但这将是未来博客文章的主题。看看像 node2vec 这样的流行算法如何响应这种方法也是值得的。最后,我使用了最基本的分类器:SVC。如果您选择另一个分类器,看看会发生什么是值得的。当然,您可以使用 TensorFlow 或 PyTorch 中的嵌入功能!我的朋友克里斯托夫·奈斯图形神经网络写了一个很好的演示。

说了这么多,我希望你能够看到使用图表解决有趣的 ML 问题有巨大的好处!

有关更多信息…

我制作了一系列迷你视频(我的目标是 5 分钟或更少),向数据科学家传授如何使用 Neo4j 进行数据科学研究的基础知识:“面向数据科学家的小型 Neo4j”我试着每周给 Neo4j 新用户添加一个非常具体的主题视频。

一些其他参考

其中许多链接在上面的不同地方,但这里有一个适当的列表。

特别感谢 Jacob Sznajdman 和Tomaz Bratanic对这篇博文的内容和评论提供帮助的人!另外,特别感谢Alessandro Negro对本帖的宝贵见解和编码支持!*

与机器学习交朋友

原文:https://towardsdatascience.com/making-friends-with-machine-learning-5e28d5205a29?source=collection_archive---------8-----------------------

谷歌传奇的应用人工智能课程为初学者和专家设计

与机器学习交朋友是一门仅供内部使用的谷歌课程,专门为启发初学者和娱乐专家而创建。*这是谷歌有史以来最受欢迎的教育产品之一。好奇里面有什么吗?今天,你可以!

你可以在 YouTube 上找到完整的课程:

完整的课程可以在 YouTube 这里免费获得:bit.ly/funaicourse

该课程旨在为每个人(无论你的角色如何)提供有效参与机器学习所需的工具,以解决商业问题,并在一个日益以人工智能为燃料的世界中成为一个好公民。

MFML 对各种各样的人来说都是完美的;它侧重于概念理解(而不是数学和编程细节),并通过形成机器学习成功方法基础的思想来指导您。它有适合每个人的东西!

整个 6.5 小时的课程分为 4 个部分:

三种方式来享用整个课程

1)每隔几个月通过这份简讯获取完整的章节。第 1-4 部分的拖车。

2)在 YouTube 上订阅并欣赏短视频,因为他们每隔几天就会加入 MFML 播放列表

3)跳过视频,直接进入 MFML 播放列表每集描述中链接的博客文章。

课程介绍

与机器学习交朋友 是一门仅供内部使用的谷歌课程,专为启发初学者和娱乐专家而创建。*今天,每个人都可以使用它!

该课程旨在为您提供有效参与机器学习所需的工具,以解决商业问题,并在一个日益以人工智能为燃料的世界中成为一个好公民。MFML 对所有人类来说都是完美的;它侧重于概念理解(而不是数学和编程细节),并通过形成机器学习成功方法基础的思想来指导您。它有适合每个人的东西!

完成本课程后,您将:

  • 获得对核心机器学习概念的直观而正确的理解。
  • 了解几种流行的机器学习方法的味道。
  • 避免机器学习中的常见错误。
  • 了解机器学习如何帮助你的努力。
  • 深入了解领导机器学习项目从概念到启动及以后的各个步骤。
  • 提高你与 ML 专家和非专家沟通的能力。

寻找动手 ML/AI 教程?

以下是我最喜欢的 10 分钟演练:

*课程适合你吗?看看人们对此有什么看法

她演讲的质量简直让我震惊。这是一个 6 小时(!)绝技;在每一分钟里,凯西都清晰、风趣、充满活力、平易近人、见解深刻、知识丰富。麻省理工学院计算机科学教授哈尔·艾伯森

这门课程是针对普通大众的,我怎么强调都不为过 —人力资源专家

“神奇的课,再加上很爆笑!” —软件工程师

“我现在对自己对 ML 的理解更有信心了……我喜欢它。” —通信经理

“在这方面,比我在大学里学的任何课程都有用。” —可靠性工程师

“我喜欢她组织课程的方式,了解课程内容,并在一整天的课程中游刃有余。因此,我在这一课中学到了两件事。1)机器学习,2)演示技巧。” —主管

很棒的东西:我会推荐它 — ML 研究科学家

“…总是很有趣,吸引我的注意力。” —工程高级主管

“…结构良好,清晰,适合像我这样的人,充满有用的视觉效果和故事,有助于我理解和记忆。我学到了很多。” —高级销售主管

“MFML 的课程是非凡的。它为理解最佳实践奠定了基础,并增强了我尝试应用 ML 的信心。” —产品技术经理

“这一次我觉得我已经理解了 90%以上的内容。平时我一直很失落,觉得自己极其愚蠢,想哭。” —项目经理

“比其他课程高级得多,但也更普遍、更完整。提供了一个很好的主题概述…填补了我的许多“漏洞”。它真的揭开了很多事情的神秘面纱。” —软件工程师

“虽然我在过去(大约 8 年前)学习和使用过 ML,但我已经厌倦了,所以我对最近的趋势不太感兴趣……经过这次更新,我觉得我可以重建这种关系,并再次与 ML 成为朋友。” —产品经理

“由于凯西深厚的专业知识、机智和幽默,原本深奥的材料变得通俗易懂,令人愉快。” —用户体验设计师

如果你喜欢它,那么你应该分享它…

外面有很多垃圾,所以万一你认为这个课程比大多数选择都好,请通过与你的社区分享来帮助它脱颖而出:bit.ly/mfml_part1

超越机器学习

如果你对超越 ML 的数据科学主题感兴趣,请查看我的迷你课程:

还在找课程链接?

他们又来了:

用 Python 熊猫和牛郎星制作交互式线条图

原文:https://towardsdatascience.com/making-interactive-line-plots-with-python-pandas-and-altair-7ee1d109e3dd?source=collection_archive---------21-----------------------

将增强你的 EDA 过程的图

Neven KrcmarekUnsplash 上拍摄的照片

线图是数据分析的重要部分。它让我们了解了一个量在连续测量中是如何变化的。在处理时间序列的情况下,线图的重要性变得至关重要。

趋势、季节性和相关性是可以在精心生成的线图上观察到的一些特征。在本文中,我们将使用两个 Python 库创建交互式线图:Pandas 和 Altair。

Pandas 提供数据,Altair 制作美丽且信息丰富的线图。虽然 Pandas 也能够绘制数据,但它不是一个显式的数据可视化库。此外,我们将使情节互动,这是熊猫无法做到的。

让我们从生成数据开始。折线图的一个典型用例是分析股票价格。获取股价数据最简单的方法之一就是pandas-datareader库。我们首先需要将它与 Pandas 一起导入(已经安装在 Google Colab 中)。

import pandas as pd
from pandas_datareader import data

我们将得到 3 种不同股票在 1 年内的价格。需要指定开始日期、结束日期和来源。

start = '2020-1-1'
end = '2020-12-31'
source = 'yahoo'

还有一个必需的信息是股票的名称。

apple = data.DataReader("AAPL", start=start ,end=end, data_source=source).reset_index()[["Date", "Close"]]ibm = data.DataReader("IBM", start=start ,end=end, data_source=source).reset_index()[["Date", "Close"]]microsoft = data.DataReader("MSFT", start=start ,end=end, data_source=source).reset_index()[["Date", "Close"]]

(图片由作者提供)

我们现在有苹果、IBM 和微软在 2020 年的股价。最好将它们放在一个数据框中。在合并之前,我们需要添加一个列来指示特定价格属于哪只股票。

下面的代码块添加相关的列,然后使用concat函数组合数据帧。

apple["Stock"] = "apple"
ibm["Stock"] = "ibm"
microsoft["Stock"] = "msft"stocks["Month"] = stocks.Date.dt.monthstocks = pd.concat([apple, ibm, microsoft])

(图片由作者提供)

我们还添加了可能对分析有用的月份信息。我们现在可以开始创建情节。

阿尔泰尔

Altair 是 Python 的统计可视化库。它的语法清晰易懂,我们将在示例中看到。用 Altair 创建交互式可视化也非常简单。

我将简要说明牵牛星的结构,然后重点介绍如何创建交互式线条图。如果你是牛郎星的新手,这里有一个牛郎星的 4 部分系列教程:

这是一个简单的线图,不具备任何交互性。

alt.Chart(stocks).mark_line().encode(
   x="Date",
   y="Close",
   color="Stock"
).properties(
   height=300, width=500
)

(图片由作者提供)

基本结构从顶级图表对象开始。数据可以是 Pandas 数据框的形式,也可以是指向 json 或 csv 文件的 URL 字符串。然后指定可视化的类型(例如,mark_circlemark_line等等)。

encode函数告诉 Altair 在给定的数据帧中绘制什么。因此,我们在encode函数中写的任何东西都必须链接到数据。color参数区分不同的股票名称。与 Seaborn 的hue参数相同。最后,我们使用properties函数指定绘图的某些属性。

为情节增加交互性的一种方法是通过选择。Altair 中的一个选择捕获了用户的交互。

selection = alt.selection_multi(fields=["Stock"], bind="legend")alt.Chart(stocks).mark_line().encode(
   x="Date",
   y="Close",
   color="Stock",
   opacity=alt.condition(selection, alt.value(1), alt.value(0.1))
).properties(
   height=300, width=500
).add_selection(
   selection
)

上面的选择对象基于包含股票名称的股票列。它必然与传说有关。我们将其传递给opacity参数,这样线条的不透明度会根据所选股票名称而变化。

我们还需要使用add_selection函数将选择添加到绘图中。下面两幅图像演示了选择是如何工作的。我们只需要点击图例中的股票名称。然后,相应地更新绘图。

(图片由作者提供)

(图片由作者提供)

Altair 提供了其他选项来捕捉用户交互。例如,我们可以创建一个交互式的线图,将鼠标悬停在图上就可以更新。

下面的代码创建了一个 selection 对象,它执行我们刚刚描述的选择。

hover = alt.selection(
   type="single", on="mouseover", fields=["Stock"], nearest=True
)

我们将使用选择对象来捕捉图上最近的点,然后突出显示该点所属的线。

下面的代码中有 3 个组件。第一个创建线形图。第二个是绘制在线图上的散点图,用于识别最近点。我们调整不透明度,使散点图不可见。

第三个负责突出显示第二个图中包含捕获点的线。

# line plot
lineplot = alt.Chart(stocks).mark_line().encode(
   x="Date:T",
   y="Close:Q",
   color="Stock:N",
)# nearest point
point = lineplot.mark_circle().encode(
   opacity=alt.value(0)
).add_selection(hover)# highlight
singleline = lineplot.mark_line().encode(
   size=alt.condition(~hover, alt.value(0.5), alt.value(3))
)

现在可以通过合并第二个和第三个图来生成交互式线图。

point + singleline

(图片由作者提供)

(图片由作者提供)

第一个图像显示了原始或原始的情节。第二张图显示了我悬停在图上时的更新版本。

结论

Altair 在向可视化添加交互式组件方面非常灵活。一旦你对交互性的元素有了全面的理解,你就可以丰富你的可视化。

感谢您的阅读。如果您有任何反馈,请告诉我。

用 Python Altair 制作交互式可视化

原文:https://towardsdatascience.com/making-interactive-visualizations-with-python-altair-7880ab5cf894?source=collection_archive---------11-----------------------

综合实践指南

米卡·鲍梅斯特在 Unsplash 上的照片

数据可视化是数据科学的基础。如果用于探索性数据分析,数据可视化在揭示数据集内的底层结构或发现变量之间的关系方面非常有效。

数据可视化的另一个常见用例是交付结果或发现。它们比简单的数字承载了更多的信息。因此,我们经常在讲故事中使用数据可视化,这是数据科学管道的一个关键部分。

我们可以通过增加交互性来增强数据可视化的能力。Python 的 Altair 库在创建交互式可视化方面效率很高。

在本文中,我们将介绍 Altair 中交互性的基本组件。我们还将举例说明如何将这些组件付诸实施。让我们从导入库开始。

import numpy as np
import pandas as pd
import altair as alt

我们还需要一个数据集的例子。我们将使用 Kaggle 上的墨尔本房屋数据集中的一个小样本。

df = pd.read_csv("/content/melb_data.csv", usecols = ['Price','Landsize','Distance','Type', 'Regionname'])df = df[(df.Price < 3_000_000) & (df.Landsize < 1200)].sample(n=1000).reset_index(drop=True)df.head()

(图片由作者提供)

我只看过原始数据集的一小部分。read_csv 函数的 usecols 参数允许只读取 csv 文件的给定列。我还过滤了价格和土地面积方面的异常值。最后,使用 sample 函数选择 1000 个观察值(即行)的随机样本。

在数据转换和创建交互式图形方面,Altair 是一个强大的库。交互性有三个组成部分。

  • 选择:捕获来自用户的交互。换句话说,它选择了可视化的一部分。
  • 条件:根据选择更改或自定义元素。为了看到一个动作,我们需要将一个选择附加到一个条件上。
  • Bind:它是选择的一个属性,在选择和输入之间创建一个双向绑定。

当我们通过例子时,这些概念将变得更加清楚。

让我们首先创建一个静态散点图,然后我们将添加交互式功能。

alt.Chart(df).mark_circle(size=50).encode(
   x='Price',
   y='Distance',
   color='Type'
).properties(
   height=350, width=500
)

(图片由作者提供)

在开始交互情节之前,最好先简要介绍一下 Altair 语法的基本结构。我们首先将数据传递给一个顶级图表对象。数据可以是 Pandas 数据帧或指向 json 或 csv 文件的 URL 字符串的形式。

然后,我们描述可视化的类型(例如,标记圆、标记线等)。encode 函数指定在给定的数据帧中绘制什么。因此,我们在编码函数中写的任何东西都必须链接到数据帧。最后,我们使用 properties 函数指定绘图的某些属性。

就点而言,情节的某些部分似乎过于重叠。如果我们还可以查看属于特定类型的数据点,效果会更好。

我们可以分两步实现这一目标。第一步是添加一个带有 type 列的选择,并将其绑定到图例。

selection = alt.selection_multi(fields=['Type'], bind='legend')

仅仅添加一个选择是不够的。我们应该在选择的基础上更新剧情。例如,我们可以通过使用带有不透明度参数的 condition 属性,根据所选类别调整数据点的不透明度。

alt.Chart(df).mark_circle(size=50).encode(
   x='Price',
   y='Distance',
   color='Type',
   opacity=alt.condition(selection, alt.value(1), alt.value(0.1))
).properties(
   height=350, width=500
).add_selection(
   selection
)

(作者 GIF)

对于第二个示例,我们将创建距离和地块大小列的散点图以及价格列的直方图。直方图将根据散点图上的选定区域进行更新。

因为我们想在图上选择一个区域,所以我们需要在散点图上添加一个选择区间。

selection = alt.selection_interval()

此选择将作为选择属性添加到散点图中。对于直方图,我们将使用选择作为转换过滤器。

chart1 = alt.Chart(df).mark_circle(size=50).encode(
  x='Landsize',
  y='Distance',
  color='Type'
).properties(
  height=350, width=500
).add_selection(
  selection
)chart2 = alt.Chart(df).mark_bar().encode(
  alt.X('Price:Q', bin=True), alt.Y('count()')
).transform_filter(
  selection
)

chart1 和 chart2 变量分别包含散点图和直方图。我们现在可以组合并显示它们。Altair 在组合多个剧情或支线剧情方面相当灵活。我们甚至可以使用逻辑运算符。

chart1 | chart2

(图片由作者提供)

正如我们所看到的,直方图是根据散点图上所选的数据点进行更新的。因此,我们能够看到所选子集的价格分布。

为了更好地理解选择和条件的概念,让我们交换散点图和直方图上的角色。我们将选择添加到直方图,并使用它作为散点图的转换过滤器。

selection = alt.selection_interval()chart1 = alt.Chart(df).mark_circle(size=50).encode(
   x='Landsize',
   y='Distance',
   color='Type'
).properties(
   height=350, width=500
).transform_filter(
   selection
)chart2 = alt.Chart(df).mark_bar().encode(
   alt.X('Price:Q', bin=True), alt.Y('count()')
).add_selection(
   selection
)chart1 | chart2

(图片由作者提供)

你可以成为 媒介会员 解锁我的全部写作权限,外加其余媒介。如果你已经是了,别忘了订阅https://sonery.medium.com/subscribe如果你想在我发表新文章时收到电子邮件。

结论

天空才是极限!我们可以创造许多不同的互动情节。Altair 在向可视化添加交互式组件方面也非常灵活。

一旦你对交互性的元素有了全面的理解,你就可以丰富你的可视化。这些元素是选择、条件和绑定。

如同任何其他科目一样,熟能生巧。起初,语法可能看起来有点混乱。然而,一旦你理解了我们提到的元素之间的逻辑和联系,创建交互式的情节将变得相当容易。

感谢您的阅读。如果您有任何反馈,请告诉我。

用雨云图让它下雨

原文:https://towardsdatascience.com/making-it-rain-with-raincloud-plots-496c39a2756f?source=collection_archive---------6-----------------------

用 python 实现 ptitprince 库以创建健壮的数据可视化

什么是雨云图

雨云图是一种直观、可靠和透明的数据可视化形式。它本质上是一个 violin + boxplot + jittered dataset 组合,通过中位数和置信区间很好地提供了原始数据、概率分布和统计推断的概览。这可以为用户提供个人观察和一般模式的信息。

要了解更多关于雨云地块的细节和背景,请阅读原文:

https://wellcomeopenresearch.org/articles/4-63/v2

下雨了

要开始创建 raincloud 地块,必须首先导入必要的库。这个例子是从 ptitprince 库构建的,这个库是由 David Pogialli 创建的。它是 raincloud plots 的 python 实现,基于 Micah Allen 的原始 R + ggplot 代码。

import pandas as pd
import seaborn as sns
import os
import matplotlib.pyplot as plt
#sns.set(style="darkgrid")
#sns.set(style="whitegrid")
#sns.set_style("white")
sns.set(style="whitegrid",font_scale=2)
import matplotlib.collections as cltimport ptitprince as pt

加载数据

对于这个笔记本,我们使用了 ptitprince 存储库提供的样本数据。这里有一个 google drive 链接用于下载个人使用的数据。

df = pd.read_csv ("simdat.csv", sep= ",")
df.head()

数据帧的头部

探索数据

在绘制雨云图之前,我们用一个简单的条形图来观察每个测量值的分布。

sns.barplot(x = "group", y = "score", data = df, capsize= .1)
plt.title("Figure P1\n Bar Plot")if savefigs:
    plt.savefig('../figs/tutorial_python/figureP01.png', bbox_inches='tight')

简单的条形图

绘制云彩

“云”是直方图的平滑版本,它将让我们了解数据集的分布情况。

# plotting the clouds
f, ax = plt.subplots(figsize=(7, 5))
dy="group"; dx="score"; ort="h"; pal = sns.color_palette(n_colors=1)ax=pt.half_violinplot( x = dx, y = dy, data = df, palette = pal, bw = .2, cut = 0.,
                      scale = "area", width = .6, inner = None, orient = ort)plt.title("Figure P2\n Basic Rainclouds")
if savefigs:
    plt.savefig('../figs/tutorial_python/figureP02.png', bbox_inches='tight')

看看我们的云

加雨

为了查看特定的数据点并识别潜在的异常值或其他模式,我们添加了“rain”。

无抖动

# adding the rainf, ax = plt.subplots(figsize=(7, 5))ax=pt.half_violinplot( x = dx, y = dy, data = df, palette = pal, bw = .2, cut = 0.,scale = "area", width = .6, inner = None, orient = ort)ax=sns.stripplot( x = dx, y = dy, data = df, palette = pal, edgecolor = "white",size = 3, jitter = 0, zorder = 0, orient = ort)plt.title("Figure P3\n Raincloud Without Jitter")if savefigs:plt.savefig('../figs/tutorial_python/figureP03.png', bbox_inches='tight')

数据点的简单一维表示

带抖动

# adding jitter to the rainf, ax = plt.subplots(figsize=(7, 5))ax=pt.half_violinplot( x = dx, y = dy, data = df, palette = pal, bw = .2, cut = 0.,scale = "area", width = .6, inner = None, orient = ort)ax=sns.stripplot( x = dx, y = dy, data = df, palette = pal, edgecolor = "white",size = 3, jitter = 1, zorder = 0, orient = ort)plt.title("Figure P4\n Raincloud with Jittered Data")if savefigs:plt.savefig('../figs/tutorial_python/figureP04.png', bbox_inches='tight')

添加抖动点

添加箱线图

为了更好地理解数据的中位数、四分位数和异常值,我们添加了一个空的箱线图。

#adding the boxplot with quartilesf, ax = plt.subplots(figsize=(7, 5))ax=pt.half_violinplot( x = dx, y = dy, data = df, palette = pal, bw = .2, cut = 0.,scale = "area", width = .6, inner = None, orient = ort)ax=sns.stripplot( x = dx, y = dy, data = df, palette = pal, edgecolor = "white",size = 3, jitter = 1, zorder = 0, orient = ort)ax=sns.boxplot( x = dx, y = dy, data = df, color = "black", width = .15, zorder = 10,\showcaps = True, boxprops = {'facecolor':'none', "zorder":10},\showfliers=True, whiskerprops = {'linewidth':2, "zorder":10},\saturation = 1, orient = ort)plt.title("Figure P5\n Raincloud with Boxplot")if savefigs:plt.savefig('../figs/tutorial_python/figureP05.png', bbox_inches='tight')

添加箱线图,覆盖抖动的数据点

添加颜色

我们可以设置调色板来表征这两个组。

#adding colorpal = "Set2"f, ax = plt.subplots(figsize=(7, 5))ax=pt.half_violinplot( x = dx, y = dy, data = df, palette = pal, bw = .2, cut = 0.,scale = "area", width = .6, inner = None, orient = ort)ax=sns.stripplot( x = dx, y = dy, data = df, palette = pal, edgecolor = "white",size = 3, jitter = 1, zorder = 0, orient = ort)ax=sns.boxplot( x = dx, y = dy, data = df, color = "black", width = .15, zorder = 10,\showcaps = True, boxprops = {'facecolor':'none', "zorder":10},\showfliers=True, whiskerprops = {'linewidth':2, "zorder":10},\saturation = 1, orient = ort)plt.title("Figure P6\n Tweaking the Colour of Your Raincloud")if savefigs:plt.savefig('../figs/tutorial_python/figureP06.png', bbox_inches='tight')

添加颜色

结论

本文概述了如何使用 python 和 ptitprince 库来创建雨云图。要更深入地使用 ptitprince 库,请查看 github 存储库:

https://github.com/pog87/PtitPrince

或者查看我的存储库和 google colab 实现的链接:

https://github.com/chags1313/raincloud_colab https://colab.research.google.com/drive/10UObYNGsepQgaCswi6l1cOy0CxQdr3Ki?usp=sharing

感谢您的阅读!

使用 kubectl 插件简化 Kubernetes 操作

原文:https://towardsdatascience.com/making-kubernetes-operations-easy-with-kubectl-plugins-206493c1f41f?source=collection_archive---------23-----------------------

使用这些kubectl插件来提高你的生产力,使所有的 Kubernetes 任务和操作更容易,更快,更有效

Gabriel Crismariu 在 Unsplash 上拍摄的照片

kubectl是一个功能强大的工具,允许您执行几乎所有与 Kubernetes 相关的任务。不管你是需要列出 pod,调试节点,管理 RBAC 还是其他什么,kubectl都可以做到。然而,这些常见任务中的一些可能相当笨重,或者可能包括许多可能需要相当长时间来执行的步骤。在其他情况下,kubectl的输出可能不完全可读,或者可能包含大量噪声,这可能非常烦人,尤其是当你试图调试某些东西时,在这种情况下时间是至关重要的。所以,当我们可以避免的时候,为什么要浪费时间在重复的,普通的,耗时的任务上呢?问如何?好吧,让我给你介绍一下kubectl插件!

什么插件?

kubectl附带有限的核心功能,不包括 Kubernetes 管理员或用户可能需要执行的所有任务。因此,为了解决这个限制,我们可以用插件来扩展kubectl,插件的功能相当于kubectl本身的子命令。所有这些插件都是独立的可执行文件,可以用任何语言编写,但是考虑到我们正在谈论 Kubernetes 工具和生态系统,它们中的大多数显然是用 Go 编写的。

现在你可能会想— “我在哪里可以找到所有这些插件?为什么不直接使用不带 *kubectl* 的独立二进制文件呢?” -这两个问题的答案是krew -一个针对kubectl插件和 Kubernetes SIG 的包管理器,旨在解决kubectl的包管理问题。

作为一个软件包管理员,有助于发现、安装和更新我们所有的插件,但是要使用它,我们首先需要安装它,因为...krew本身也是插件。您可以在此处导航至安装指南/脚本,使用您喜欢的方法安装。

现在我们有了krew,让我们找到并安装一些插件吧!

上面的代码展示了几种搜索和获取特定插件信息的方法。除了使用kubectl krew搜索,你还可以使用krew网站的插件索引。除了kubectl krew显示的信息之外,这也给了你源代码库的链接和每个插件的 GitHub 星级数。因此,当您找到您需要的东西时,您只需运行kubectl krew install并开始使用它:

请注意上面输出中的警告——尽管这些插件被列在官方插件索引中,但这并不保证它们使用起来是安全的,也不保证它们实际上做了它们声称正在做的事情。你应该把所有这些看作是从互联网上下载的任何随机的,未经验证的脚本。

尽管krew包含了很多插件,但这并不意味着它是所有可用插件的详尽列表。所以,万一你找不到解决你的任务/问题的插件,你也可以去别的地方看看。一个这样的地方是[awesome-kubectl-plugins](https://github.com/ishantanu/awesome-kubectl-plugins) 仓库,那里有几个额外的插件,或者你也可以试着谷歌一下。

考虑到这些不是krew的一部分,要安装它们,我们需要采用手动方式,如下所示:

如前所述,这些插件只是脚本或二进制文件,因此你可以手动下载并使用它们。如果您想让kubectl将它们识别为插件,您还需要以格式kubectl-plugin-name给它们命名,并将它们放在 path 中的某个位置。在上面的例子中,我们安装了dig插件,方法是下载它的源代码,编译二进制文件,并把它移动到路径中的krew目录。要检查kubectl是否找到了新安装的插件,你可以运行kubectl plugin list

必须有

索引中有相当多的插件(在撰写本文时有 149 个),在krew索引之外还有更多,所以为了节省您浏览所有插件的时间,我列出了我认为特别有用的插件。因此,让我们从最容易被忽视的领域开始,按类别对其进行细分,即安全性:

  • [rakkess](https://github.com/corneliusweig/rakkess)krew中的access-matrix是一个插件,用于显示和查看对 kubernetes 资源的访问。这在设计 RBAC 角色时非常有用——例如,您可以运行kubectl access-matrix --as other-user --namespace some-ns来验证用户或服务帐户在指定的名称空间中具有所需的访问权限。
  • [kubesec](https://github.com/controlplaneio/kubectl-kubesec) -在krew中称为kubesec-scan,是一个用https://kubesec.io/扫描仪扫描资源的插件。当您针对清单运行这个插件时,它会告诉您建议的更改,以提高工作负载的安全性。要查看扫描器使用的所有规则,请访问上述网站。
  • [rbac-lookup](https://github.com/FairwindsOps/rbac-lookup) -类似于我们提到的第一个插件,这个插件也有助于你集群中的 RBAC。这可用于执行角色的反向查找,为您提供用户、服务帐户或组已分配的角色列表。例如,要查找绑定到名为my-sa的服务帐户的角色,可以使用下面的- kubectl rbac-lookup my-sa --kind serviceaccount --output wide

当调试一些关键问题时,真的没有时间浪费,有一些调试插件可以帮助加快这个过程:

  • [ksniff](https://github.com/eldadru/ksniff) -即sniff是一个调试和捕获网络数据的工具。它可以连接到一个 pod,并使用tcpdump将网络数据转发到您本地的 Wireshark 。这个工具在使用 Wireshark 的命令行版本tshark时也能很好地工作。
  • [dig](https://github.com/sysdiglabs/kubectl-dig) —这个由 SysDig 构建的插件提供了非常好的终端接口,用于探索各种节点级数据——例如——端口、跟踪、运行窗格、页面错误等。要观看正确的演示,请在dig资源库中查看视频,点击这里。然而这个插件不在krew中,可能还需要在你的集群节点上做一些额外的设置(见这个问题)。

还有一些有用的插件可以帮助集群及其资源的日常管理:

  • [neat](https://github.com/itaysk/kubectl-neat) -可能是所有插件中我最喜欢的是neat,它从 Kubernetes 资源的 YAML 输出中移除了所有生成的冗余字段。如果你厌倦了滚动浏览所有的managedFields和其他垃圾,那么一定要试试这个。
  • [kube-capacity](https://github.com/robscott/kube-capacity) -在krew中称为resource-capacity,试图更好地了解集群资源的使用和利用率。它本质上是一种类固醇。它可以显示每个命名空间或单元的资源利用率和消耗,允许节点或单元标签过滤,以及输出排序。
  • [kube-pug](https://github.com/rikatz/kubepug) -是一个在krew中被称为deprecations的插件。每个集群迟早都需要升级,在某个时候,您会遇到 API 被弃用和/或被移除的情况。发现什么被否决可能是一个漫长且容易出错的过程,这个插件试图简化这个过程。您需要做的就是运行kubectl deprecations --k8s-version=v1.XX.X,您将获得集群中所有 API 对象实例的列表,这些实例将在指定版本中被弃用或删除。

最后也是最大的一类是电动工具——用普通的kubectl可以完成很多复杂、繁琐或需要多个重复步骤的任务,所以让我们用这些插件简化一些:

  • [tree](https://github.com/ahmetb/kubectl-tree) -在 Kubernetes 中创建单个对象可以触发更多依赖资源的创建,无论是仅仅部署创建复制集还是一个操作员实例创建 20 个不同的对象。这种层次结构可能很难导航,而kubectl tree可以通过创建依赖资源的类似文件系统的树形可视化来帮助导航。
  • [kubelogin](https://github.com/int128/kubelogin) -如果你正在使用 Google、Keycloak 或 Dex 等 OIDC 提供商对 Kubernetes 集群进行身份验证,那么这个插件也就是krew中的oidc-login可以帮助你避免一次又一次地手动登录集群。当您设置此插件时,每当您在没有有效认证令牌的情况下尝试运行任何kubectl命令时,oidc-login将自动打开您的提供商的登录页面,并在成功认证后获取令牌并让您登录到集群。要查看工作流视频,请点击此处查看存储库
  • [kubectx](https://github.com/ahmetb/kubectx) -在krew中被称为ctx,可能是所有插件中最受欢迎的。它允许您轻松地在kubectl上下文和集群名称空间之间切换,而不必处理kubectl config
  • [ketall](https://github.com/corneliusweig/ketall) -我们都知道kubectl get all并没有真正给你所有的资源。要真正列出所有资源,您可以使用ketall,在krew中也称为get-all。这个插件可以将所有的资源转储到你的终端中,并根据时间、排除、标签选择器或范围(集群或名称空间)进行过滤。

结束语

这只是一个我觉得有用的东西的列表,所以对我有用的可能对你不一定有用,同时,可能有很多我省略了的插件,但是它们对你可能非常有用。所以,去查看一下krew索引或者[awesome-kubectl-plugins](https://github.com/ishantanu/awesome-kubectl-plugins) 了解更多。如果你碰巧发现了一些很酷的东西,请分享出来,这样其他人也可以从中受益。

也就是说,并不是每个用例都有一个插件,所以如果你找不到插件来解决你的问题,也许你可以构建一个来填补这个空白(更多信息请见文档)。😉

除了kubectl插件,还有其他工具可以提高你的生产力,简化 Kubernetes 的操作。最突出的一个是,所以如果插件不够,你想抓住一个更大的锤子,那么这可能是一个正确的工具给你。

本文原帖martinheinz . dev

用柠檬做柠檬水:仔细观察一个产品的特征,了解它的有效性

原文:https://towardsdatascience.com/making-lemonade-from-lemons-taking-a-closer-look-at-a-products-features-to-understand-its-6227b4eca168?source=collection_archive---------36-----------------------

照片由南茜薇Unsplash 上拍摄

评估基于游戏的数学程序的成功

背景: ST Math 是一个基于游戏的数字数学项目,面向学前班到八年级的学生。开发者和教育工作者投入了 4 年时间和 300 万美元来评估一学年中每周 50 分钟的参与会如何影响玩家的数学技能。一个学术研究小组查看了玩家的标准化考试成绩,比较了治疗组和对照组在测试前和测试后的数学水平——结果发现差距很大。你可以在这里阅读更多相关信息

没有统计学意义的结果是不好看的。但对于一家试图向学校出售其软件的公司来说,这种结果可能是一记丧钟。

此外,这种结果是不明确的,就像一个黑盒或一个沉默的狮身人面像。显然,我们没有得到“正确的”但是我们是否部分正确呢?走上正轨?如果有的话,什么需要优化?大修?一个人留下?一个普遍的“空”不提供任何线索。我们需要打开黑匣子的锁,欺骗斯芬克斯——梳理出更多的数据,以便我们能够理解为什么我们没有找到预期的结果,并决定如何前进。

挑战:发现玩家的 ST 数学经历中发生了什么。

幸运的是,我们有额外的信息!

Sebastian Herrmann 在 Unsplash 上拍摄的照片

当创意遇到数据…

其他研究人员寻找对整体标准化数学成绩的影响(没有发现)。总分是学生所有数学评估的平均值,或者说是“报告组”每个报告组都有自己的分数,报告组的类型和数量因年级而异。这些报告群集描述了特定的数学技能,如数字感觉、代数与函数、测量与几何、统计、数据分析与概率。

找到了!时刻

如果我们更深入地研究总体得分并分析每个报告组,会怎么样?也许 ST Math 的影响局限于一个或几个集群,这些重要的结果被其他集群的分数“淹没”…

可能是玩家在测量和几何技能上提高了很多,但在其他报告集群上没有任何提高。当您对所有这些进行平均时,您可能仍然会得到一个总体为空的结果。就像在一个大水桶里加入几滴水一样,你可能不会察觉到桶里水的总量有任何差异。

我们比较了每个报告集群的治疗组和对照组的前后得分,我们是对的!之后,治疗组玩家的数字感觉分数明显高于之前。

粘土银行Unsplash 拍摄的照片

现在怎么办?

我们的下一个任务是找出原因。为什么玩家的数字感分数会暴涨?为什么学生的分数在其他报告集群中没有增加?

数字感是一种建构——一组允许个人与数字打交道的技能。这个结构中的技能包括(但不限于):理解概念,比如多理解多理解少理解多理解;理解表示数量的符号;按顺序排列数字;等等。数字感通常被描述为数学学习的基础

如果我们观察 ST 数学程序中的每一个游戏,确定它们引入了哪些技能,以及它们如何支撑玩家的掌握,会怎么样?也许我们可以理解 ST Math 是如何支持数字感的。那么我们可以建议开发人员复制有效的方法。这将减少未来游戏开发中花费在旋转轮子上的时间。

我们评估的旧 ST 数学版本的屏幕截图

奥运会的定性编码

四个研究员(还有很多咖啡!)按技能编码 ST Math 的 1000+级课程。例如,当一个游戏使用数字作为对象时,我们选中了“数字感”框,因为这支持玩家理解符号代表数量。当一个游戏提供了数字线时,我们选中了“数字感”框,因为它支持玩家按顺序排列数字的能力。或者,当一个游戏包含作为对象的数字表示时,我们选中“数字感”框(如上图所示)。

最后,我们发现程序中的每个游戏,包括旨在支持其他报告集群的游戏,都培养了数字感觉技能。这就是 ST Math 如何支持数感——通过将它整合到程序的每个方面。

还有结果!

通过深入挖掘我们客户的数据和产品,我们能够发现可行的见解,并重新构建最初令人沮丧的零功效叙事。

事实上,我们的项目是如此成功,以至于教育科学研究所在他们资助复制研究的声明中提到了我们。这个第三方的建议给 ST Math 带来了很大的可见度,更重要的是,它赋予了之前的评估结果所否认的东西:合法性。

观察游戏中的特定设计元素可以告诉你很多关于你的产品是如何工作的,以及你的产品可能会有什么预期效果。将这些多种方法结合起来可以节省你大量的时间和头痛

前进!

卡特琳娜·申克博士。 Katalyst Methods的创始人和负责人,也是ed tech Recharge的联合创始人,在那里她与教育媒体公司合作设计和评估游戏、软件和评估。她还与关注学习的组织合作,如脸书、互联学习实验室和联合国儿童基金会,开展研究项目,帮助他们改善教育政策和实践。了解更多请点击【katalystmethods.com】https://www.katalystmethods.com/

让最终用户轻松使用 MLOps

原文:https://towardsdatascience.com/making-mlops-easy-for-end-users-a3c22491e5e0?source=collection_archive---------20-----------------------

使用开源工具简化 MLOps 的教程

由 pch.vector & pikisuperstar 创建的人物向量—www.freepik.com

当人们说“MLOps”时,很难弄清楚 T2 指的是什么。即使对于一个技术人员来说,弄清楚如何正确地 MLOps,可能更加困难。那么,对于一个对 web 技术、Kubernetes、监控、云基础设施等一无所知的公民数据科学家来说,做 MLOps 会有多难呢??在这里,我将继续探索如何为此目的建立一个开源的 MLOps 框架:具体来说,我将概述并展示 Databricks、mlflow 和 BentoML 的组合如何为最终用户提供一个引人注目、可扩展且易于使用的 MLOps 工作流。

我之前已经讨论过 MLOps 框架必须包含电池并支持广泛的功能列表;模型生命周期管理和治理、监控、A/B 测试、可解释性、漂移/异常值检测,等等。但是,作为最终用户:

我只想定义一个给定的 python 接口,按下一个大的绿色按钮,并获得一个 REST 端点 URL,在那里我可以与我部署的模型进行交互。

在这一系列博客文章的第一部分中,我探讨了 Databricks 如何与 Seldon-core 相结合来检查我所看到的部署和运行 MLOps 的大部分需求;然而,Seldon-core 的开源产品对最终用户来说相当麻烦,而且不符合简单性的愿景;写一个 python 类,按下按钮,得到 REST 端点。这篇文章是我上一篇文章的延伸,所以我推荐看看:

我们在看什么工具

Databricks 涵盖了 ML 模型生命周期管理的从实验、跟踪、版本化、注册和治理的所有内容,同时是按需付费的,没有前期成本,对普通数据科学家来说入门的障碍最小。在这篇文章中,我们将关注 BentoML 将帮助我们部署任何注册到 mlflow 模型注册表中的 REST 端点的下一步——我们将不得不做一些黑客工作来让这些工具很好地配合使用😏。再次检查第一部分,了解数据块中 MLOps 的详细信息。

步骤 1:最终用户看到的内容

从第一篇博文开始,我们可以说我们已经训练了:

  • MNIST 分类的标准 Keras 模式
  • 一种检测输入数据中特征漂移的算法
  • 一种检测输入数据中异常值的算法
  • 解释我们预测的综合梯度算法。

大多数数据科学家至少会熟悉以上几点中的一点。让我们将所有这些模型保存到本地磁盘的artifacts/mnist-keras文件夹中:

我们希望将所有这些模型放入一个简单的 python 类中,并将其注册到 mlflow 模型注册表中。本质上我们希望这个类做所有的事情;返回预测、返回解释、定义要监控的指标等。因此,我们告诉最终用户将模型放入如下界面:

这里有几点需要注意:

  • 该类继承自mlflow.pyfunc.PythonModel,因此可以登录到 mlflow 模型注册中心,在那里我们可以控制治理,拥有多个版本,将版本转换到不同的阶段,等等。
  • predictexplainreward方法用 BentoML 端点定义修饰,以表明这些是我们希望公开的 API 端点。当然,可以添加额外的端点。注意 mlflow 不知道这些 BentoML 装饰器是做什么的。
  • 方法prepare_input定义了如何处理输入数据;这是必要的,因为 BentoML 支持微批处理;也就是说,如果一百万个单独的请求同时到来,那么为了提高效率,它会创建批处理来同时通过模型。
  • 每次调用predict时,该方法都会自动计算并记录这些样本的漂移和异常值结果到 Prometheus metrics 中——当然,如果我们可以异步计算并记录这些结果,那将是理想的,但是在大多数用例中,这些计算并不昂贵,并且我们通过将它们保留在predict方法中,赢得了很多简单性。

既然我们已经定义了模型,我们希望将它记录到 mlflow 模型注册表中,与保存所有模型的本地目录(artifacts/mnist-keras)和描述 python 环境&包的字典放在一起。mlflow UI 可以帮助完成部分工作,但我们也可以完全用代码来完成:

就这样,现在我们已经将与 MNIST 模型相关的所有内容(预测器、解释器、漂移和异常值检测器)放入一个 mlflow 模型中,并将该模型注册到我们的注册表中,并将其过渡到“生产”阶段。

但是还没有部署任何东西。因此,在下一节中,我们将看看是否可以使用 BentoML 在 mlflow 的“生产”阶段自动部署所有内容的一些代码原型。

第二步:幕后

在幕后,我们希望运行一个服务,该服务不断检查新模型是否已经进入模型注册中心的“生产”阶段,并确保所有这些模型都被实际部署。为了执行部署,我们将使用 BentoML,它允许我们包装 mlflow 模型对象,并将它们封装到 docker 映像中。因此,本节中的所有内容应该是完全通用的,并且发生在后端,没有任何用户交互。

步骤 2.1:用 BentoML 包装 mlflow

首先,我们必须为 BentoML 定义一个“工件”,在本例中,这个工件就是我们的 mlflow 模型。假设我们已经从 mlflow 模型注册中心下载了一个模型,我们可以创建一个工件,让 BentoML 将本地目录的内容复制到 BentoML 容器中(save),并指示 BentoML 如何加载模型(load):

用于加载 mlflow 模型工件的 BentoML 工件。作者代码。

现在我们有了一个工件,接下来,我们需要定义一个 BentoML“服务”,它将我们在 mlflow 模型上公开的所有端点也在 BentoML 上公开。为此,我们侵入_config_artifacts方法,该方法在 BentoML 服务的每个实例化时被调用,然后在 BentoML 服务上动态添加来自 mlflow 模型的任何 API 方法。

用于将 mlflow 端点公开为 BentoML 端点的 BentoML 服务。作者代码。

本课程的注意事项:

  • 它有一个装饰器,详细说明了它如何依赖于一个MlflowArtifact
  • 它也依靠一个environment.yml来描述康达环境
  • 它调用_config_inference_apis将 mlflow 方法添加到 API 中

这样,我们现在可以创建一个简单的函数,该函数获取模型注册中心中的任何 mlflow 模型,下载它,并将其打包到 BentoML 服务中,即类似于以下内容的东西:

从模型注册表下载 mlflow 模型

这将在本地保存一个MlflowBentoService:latest BentoML 服务。然后,我们可以运行以下命令,将 BentoML 服务放入 docker 映像中:

将 BentoML 服务放入 docker 映像的 Bash 命令。作者代码。

我们现在有了一个bentoml-mlflow-mnist-keras docker 映像,它包含了我们的模型,并准备好进行部署。我们可以通过在本地运行 docker 映像来测试它是否工作正常:

用于本地测试 BentoML docker 映像的 Bash 命令。

转到localhost:5000,我们现在应该会看到一个 swagger API,它暴露了我们所有的端点,准备好接受请求。目前为止一切正常。

步骤 2.2:自动部署

下一步是将注册中心中注册的任何 mlflow 模型自动部署到一些云基础设施中。BentoML 允许您部署在许多不同的基础设施上,但是我们将假设我们已经建立了一个 Kubernetes 集群;参见第一篇博文中的例子。

本质上,我们需要一个服务来保持 mlflow 模型注册与部署到 Kubernetes 的同步。我们可以把它想象成:

  • 每隔 X 分钟运行一次 API 请求以在 mlflow 注册表中列出模型并部署它们的服务。
  • 使用 Databricks 模型注册中心(目前为私有预览版)中的 CI/CD webhooks,在注册模型后立即部署模型。

一旦在注册表中找到一个新模型,就需要进行以下操作:

  • 下载 mlflow 模型,并将其打包成一个 BentoML docker 映像,类似于上一节所示。
  • 将 docker 映像推送到存储库(例如,DockerHub、ACR 等)。)
  • 创建一个 Kubernetes 部署yaml并应用

这种实现的细节取决于我们将部署到的特定基础设施。尽管如此,我们仍然可以快速编写一个过于简化的 python 函数示例,该函数获取 Kubernetes 部署的模板,填写模型细节,然后应用部署。

用于读取 Kubernetes 模板文件的过于简化的 python 方法&应用它。作者代码。

用于部署 BentoML 映像的过于简化的 Kubernetes 模板。作者代码

适当的实现还可以添加一个特定的入口路由,这样模型就可以在给定的自定义域路由(例如www.myexample.com/model-name/)上提供 Swagger UI API

结果

BentoML 文档展示了我们如何将 Prometheus 安装到我们的集群中,并为我们所有部署的模型自动抓取metrics/端点。基于此,如果我们还在集群上安装了 Grafana,我们可以让我们的自动部署创建如下所示的控制面板:

Grafana dashboard,最终用户可以对其进行定制,以包含我们记录的任何指标。作者截图

最后的想法

在这篇文章中,我们使用 mlflow 和 BentoML 拼凑了一个简单的 python 类。该类提供了实现定制模型的充分灵活性,定制模型具有要监控的漂移和异常值的定制度量,以及用于解释或奖励模型预测的定制端点。这个类的美妙之处在于,不管模型细节如何,我们都可以将它注册到 mlflow 模型注册表中,然后创建一个服务,自动将其部署到生产中。

概述的解决方案很容易扩展到包括附加功能。例如,我们可以在 mlflow 模型上创建额外的“配置”选项,这些选项将确定使用哪个基础 docker 映像进行部署、在哪个基础架构上进行部署(在多个集群的情况下)、向数据块发送重新训练请求(例如,当漂移或回报降低到阈值以下时),或者甚至如何部署 A/B 测试。

这个设置中必须实现的一个重要组件是从 mlflow 到 Kubernetes 集群的权限同步。也就是说,只有对 mlflow 注册表中的模型具有读取权限的用户(可以通过 UI 来控制)才应该具有调用最终端点的权限。

像这样的框架是引人注目的。它允许数据科学家专注于模型开发,然后通过监控、治理等快速将模型投入生产。,在此过程中无需咨询数据/云工程师。

让人工智能模型更强大更高效

原文:https://towardsdatascience.com/making-models-more-robust-more-efficiently-e8737178452c?source=collection_archive---------16-----------------------

行业笔记

将机器学习模型部署到现实世界容易发现领域覆盖问题。一种使模型稳健的方法是生成看不见的数据,而模型需要处理这些数据。基于属性的测试可以解决这个问题!

基于属性的测试旨在维护给定操作域的某个属性,允许我们估计模型的健壮性。图片作者。

上一篇关于测试机器学习模型的文章中,我们研究了软件测试和如何在 MLOps 领域中使用这些策略之间的相似之处。我们表明,基于静态数据集的评估模型性能的方法不足以全面检查高维空间中模型的准确性。更深入了解模型稳健性的一种方法是通过基于属性的测试等方法,这些方法根据某些规范合成输入数据,以打破模型!

但是测试如何能使你的模型在训练时更加健壮和有效呢?

首先,让我们从谈论预期的操作域开始。换句话说,我们期望我们的输入来自哪个数据域——我们期望观察到什么类型的变化、约束、极值?例如,在计算机视觉领域,我们可以开始描述一天中的时间、气象条件,甚至关于观测本身的属性——物体的大小和类型,它们如何变化以及什么需要保持固定。

这允许我们定义变化轴,或数据的不同可变性。对于一个很少数字输入的小问题,很容易找到一个导致模型性能差的变换输入。但是,如果输入是一个图像,我们该如何做呢?假设我们想将白天的图像转换成夜晚的样子。

的上一篇博文中,我们谈到了将数据样本从数据域转换到运营域,沿着时间轴执行更改,然后再转换回数据域。在下图中,我们可以看到一只鹿的图像,它的整个身体被捕捉到,头和鹿角朝向我们。我们可以列举描述图像的其他属性,例如它是在黎明时拍摄的,它包含了背景中的各种灌木和树木,等等。

我们可以将一天中的时间属性从黎明改为傍晚。作者配图。

如果我们想确保我们的汽车,在州内高速公路系统中行驶,能够识别鹿,并且不管一天中的时间或假设的背景如何,它都能这样做。这意味着我们现在可以改变这些属性,并评估模型的整体稳健性。在工业应用中,收集的数据将最大化以尽可能覆盖模型的操作域。然而,在最好的情况下,观察跨越整个操作领域的数据是不切实际的,在最坏的情况下也是不可能的,这导致部署的机器学习算法从未在该领域的一些领域中被评估。数据的过度收集不仅会导致管理问题、增加注释成本,还会导致算法迭代变慢。如果我们不能明确地列举数据域,那么推断我们期望 ML 模型在其中工作的操作域就容易得多。

在这种情况下,我们将对象的背景从树木改为公路。作者的图表和 Sebastian Palomino 的照片。

在每个培训阶段结束时,ML 模型需要在部署到相应的操作域之前进行测试。然而,在 Efemarai,我们认为鲁棒性评估不需要在 MLOps 周期结束时进行,而是可以作为培训管道的一部分进行整合。

测试平台

Efemarai 是一个测试和强健 ML 模型的平台。它的工作原理是在问题的操作域中找到导致模型性能不佳的边缘案例。它使开发人员能够轻松地将他们现有的 ML 资产(模型、数据、代码)与规范和测试相集成,以发现这些健壮性问题。

因此,您可以获得一个健壮性覆盖图,使开发人员能够沿着多个轴(与行业标准准确性、f1 分数、混淆矩阵等一起)监控进度,以获得对部署模型的信心,并为非技术利益相关方(如业务领导、经理、用户和监管机构)提供见解。

例如,UI/UX 设计师可以利用这些见解引导用户走上一条人工智能模型运行良好的道路,并将遇到问题的几率降至最低。

此外,产生的具有边缘情况的新的合成数据集对 ML 模型的性能具有直接影响。它有多种用途,在本文的其余部分,我们将说明如何将这些边缘案例样本添加到训练数据集中,不仅对准确性和 f1 分数,而且对模型的整体稳健性产生直接和可测量的影响。与穷举搜索相比,它加快了迭代和训练时间,从而最小化了所需的资源。

ML 模型鲁棒性挑战

汽车行业和资产管理中的一个常见问题是识别交通标志。对于那些在现实世界中可以观察到的任何扰动,从一天中的时间、准确的前景、观察角度到天气条件或规模,都必须极其准确和稳健。

让我们使用德国交通标志识别基准数据集,并尝试在最少的时间内训练最鲁棒的模型。因此,我们将对领域覆盖健壮性和训练速度进行基准测试。

我们将使用相同的 ImageNet 预训练模型测试以下条件:

  • a:没有任何额外扰动和变换的有效网络模型;
  • b:用自动增强训练的高效网络模型;
  • c:用所有可能的扰动和变换训练的有效网络模型;
  • d:使用 Efemarai 平台生成的附加数据,在没有额外扰动和转换的情况下训练的 EfficientNet 模型。

ML 鲁棒性结果

让我们首先强调现代神经网络作为通用特征近似器的巨大能力,因为在所有情况下,模型都达到了 97%以上的准确度。这也显示了一些问题,比如一项新技术可能会改善百分之零点几的结果,但很难评估现实生活中可能会导致什么样的改善。这正是领域覆盖图可以提供帮助的地方。

但首先,让我们从达到的准确度和训练时间开始:

  • 模型 A: 98.6%,2 分 0 秒,20 个周期
  • B 型:97.4%,2 分 22 秒,20 个周期
  • 模型 C: 97.0%,20 个周期 8 分 20 秒
  • 模型 D: 99.3%,20 个周期 3 分 34 秒
  • D 型*: 98.6%, 15 个周期2 分 40 秒

不同车型的训练力度。图片作者。

从上述结果中,我们可以看到所有模型都表现良好,并且添加不同的扰动在某些情况下可以显著增加训练时间(2 分钟对 8 分钟以上)。使用 Efemarai 平台数据的 D 型在 3 分 30 秒内达到最高精度。如果我们尝试匹配第二好的模型的准确性,它将花费少于 25%的时期,并且将几乎匹配最快的训练模型的墙时间。相比之下,它比使用所有增强功能快近 3 倍。这突出表明,针对模型表现不佳区域的智能转换对整体性能的影响要比统一采样的盲增强高得多。

现在让我们看看健壮性覆盖图。

域覆盖图。图片作者。

上面的径向图显示了每个模型在特定扰动下的稳健性水平。目标是最大程度地鲁棒并完全填充相应的切片。我们有颜色分组扰动,基于它们的类别,如几何的,颜色的,或本质上基于噪声的。

首先,我们要强调的是,经过零转换训练的原始模型 A 非常容易受到在数据集中看不到的扰动的影响!业绩下降 30%以上。考虑操作领域是将模型从开发过渡到部署的一个非常重要的步骤,尤其是影响业务度量的情况。

在几何和一些基于噪声的扰动方面,使用 Efemarai 平台训练的模型 D 的鲁棒性有了显著提高,并显示出整体最佳的鲁棒性。它将性能最低的案例从大约 50%提高到 80%以上,这是一个显著的改进!

值得注意的是,即使训练时间比模型 c 少 3 倍,ML 模型 D 的稳健性的额外数据也能带来多大的改善。

平台的使用和生成的看不见的数据导致模型性能的直接改进、在与用户操作期间观察到的更少的极限情况,以及对需要收集什么类型的数据的理解。在下一篇博文中,我们将展示这个平台的另一种用途。

结论

在模型开发过程中考虑模型的健壮性,与在部署前最后一步评估模型相比,在迭代速度和达到的性能方面有巨大的回报。我们已经表明,使用基于属性的测试平台进行机器学习,如 Efemarai,可以产生更好的模型,更深入地了解性能,并在部署这些模型时更有信心。

关于作者

我是 Efemarai 的首席技术官兼联合创始人,这是一家早期初创公司,为测试和调试 ML 模型和数据搭建了一个平台。通过我们的平台,机器学习团队可以跟踪回归,监控改进,并满怀信心地交付他们的 ML 解决方案。

在硅谷和欧盟投资者的支持下,我们正在为人工智能世界带来质量保证,并释放出新的 ML 应用程序的寒武纪大爆发!

如果你想联系我们,请发邮件至 team@efemarai.com

制作电影

原文:https://towardsdatascience.com/making-movies-a68fc0f0852e?source=collection_archive---------82-----------------------

使用探索性数据分析,提供商业建议,帮助新电影工作室的高管实现利润最大化

克里斯特·卢哈尔斯在 Unsplash 上的照片

在这篇博文中,我将向非技术受众描述我完成的项目。对于代码,我鼓励你看看我的 GitHub 库

问题陈述

一家新电影工作室的高管们正在寻求可行的见解,以最大限度地提高投资回报,并确保制作出成功的电影。

商业价值

“复仇者联盟 4:终局之战 12 亿美元的首映周末是电影史上最大的”——Vox,2019 年 4 月。

“票房猫-tastrophe:猫预计损失 7000 万美元”——《卫报》,2019 年 12 月。

从这两个对比鲜明的标题中,我们看到进入电影业对我们的利益相关者来说是一个高风险/高回报的冒险。有潜力,但需要确保“正确”的电影。通过数据分析,我们将寻求提供建议,以最大化成功的机会。

数据

本项目使用的主要数据来自两个来源。

来自 IMDB 的数据包括 146,144 个条目,以起始年份、运行时间和流派作为关键特征。

来自数字的数据包括 5,782 个条目,以发行日期、生产预算、国内总收入和全球总收入为主要特征。

我们还删除了维基百科中与网飞原创电影相关的数据。

方法学

第一阶段集中于数据准备,包括:
-导入库
-读取并清理提供的数据
-处理缺失值
-连接数据集
-抓取额外的数据并清理它

第二阶段集中于可视化和洞察,包括:
-在适用的情况下实施特征工程
-创建可视化
-得出结论
-提供建议

挑战

第一个挑战是决定什么是成功的电影。我看了两个指标利润(全球总收入减去预算)和利润率(利润超过收入)。我发现最赚钱的电影是你所期待的动作/冒险大片。然而,利润率最高的电影大多是小成本的恐怖片。我们注意到,电影业因使用不透明的会计方法而臭名昭著,使用这样的指标我们不太可能获得准确的财务状况。我们没有考虑其他形式的收入,包括商品和 DVD 销售,也没有考虑其他成本,包括延期支付人才。由于不明确,我们将全球总收入作为衡量成功的标准。

第二个挑战是结合来自两个不同来源的数据。IMDB 的数据有相关的细节,如运行时间,类型和发行日期,而来自-numbers 的数据有全球总收入和预算数字。然而,在两个源之间没有唯一的电影标识符,因此唯一的选择是使用电影名称,即字符串来合并数据帧。这并不理想,因为字符串对间距、标点符号很敏感。此外,在电影同名的情况下,存在错误匹配的风险。如果有更多的时间,我们会探索其他的方法。

调查结果和建议

《T2》的制作预算和全球票房之间没有明显的关联,2010 年后票房收入最高的 100 部电影的预算从 3500 万美元到 4 . 1 亿美元不等。

作者图片

如前所述,公开可用的财务信息有限,需要进一步分析以帮助确定最佳预算。

根据我们的数据,一部电影的平均 T4 时长为 100 分钟。然而,当具体查看票房前 100 名的电影时,运行时间更长,为 120 分钟。我们建议将目标定为 2 小时的电影,因为这对电影观众来说似乎是合适的时间长度。

作者图片

我们接下来研究了流派。每部电影被指定了三种类型。在 2010 年后票房前 100 的电影中,我们看到超过 80 部被描述为冒险电影,60 部被认为是动作片。因此,以动作/冒险电影为目标是明智的。然而,我们发现这类电影的制作成本平均要高出 4500 万美元。其他值得考虑的类型是科幻、喜剧或动画。

作者图片

最后,我们看看电影是什么时候上映的。与票房收入最高的电影相关的上映月份是 5 月/6 月,夏季大片季的开始,以及 11 月/12 月,与假期相一致,并为新年的奖项进行了优化。电影工作室应该致力于在这两个时期中的一个时期发行他们的电影。

作者图片

作为最后一个考虑,虽然我们的利益相关者没有明确要求,但随着网飞等平台的崛起,调查电影的在线发行可能是值得的。我们简要检查了网飞的原创电影,发现喜剧/剧情片非常突出(相对于动作/冒险片)。这是有道理的,因为动作/冒险电影更适合受益于大屏幕和更身临其境的体验的票房。我们还发现,网飞原创电影的平均时长为 99 分钟。

未来的工作

作为后续步骤,我们将积极开展以下工作:

  • 进一步的财务分析(例如,如何分配预算)
  • 顶级创意人才调查(导演、制片人、演员)
  • 评论的情感分析(洞察消费者偏好和趋势)
  • 剧本来源分析(如小说改编)

我希望你觉得这个项目审查有趣。如果你想了解更多,请访问我的 GitHub 知识库,里面有 Jupyter 笔记本和一个非技术演示。

用人工智能技术实现我孩子的飞行梦想

原文:https://towardsdatascience.com/making-my-toddlers-dream-of-flying-come-true-with-ai-tech-82881eac01b8?source=collection_archive---------40-----------------------

实践教程

使用姿势估计模型、使用亚马逊 SageMaker JumpStart 构建的对象检测模型、手势识别系统和在 NVIDIA Jetson AGX Xavier 上运行的 OpenGL 编写的 3D 游戏引擎,我构建了 Griffin,这是一个让我的蹒跚学步的孩子在幻想的 3D 世界中用身体像鹰一样飞翔的游戏。

我和我老婆有一个超级好动的 2.5 岁男孩,叫德协。他喜欢动物,他最喜欢的动物之一是老鹰——他经常在房子周围巡游,假装像老鹰一样飞翔。

最近,我还收到了 NVIDIA 的 NVIDIA Jetson AGX Xavier,因为我的 Qrio 项目赢得了本月的 Jetson 项目,这是一个为 Dexie 说话和播放 YouTubeKids 视频的机器人。它包括强大的硬件和强大的 GPU,这使它成为这个计算密集型项目 Griffin 的完美硬件平台。

德西假装像鹰一样飞翔。

概念

基于 Dexie 对鹰和飞行的兴趣,以及我在新冠肺炎为期两周的圣诞假期中不能去任何地方,我认为如果我能建立一个能给他鹰飞行体验的系统或游戏会很酷。此外,为了增强沉浸感,我希望他能够用自己的身体控制鹰的身体——站在树枝上,用自己的手臂拍打翅膀为飞行做准备,跳跃起飞,在飞行中途左右摆动手臂以控制方向。

我决定把这个系统叫做狮鹫,它是一种神话生物,有着狮子的身体和鹰的头。

格里芬,由publicdomainvestors

研究

为了实现上述目标,Griffin 需要具备以下模块:

  • 3D 游戏引擎——使用 OpenGL 编写的飞行模拟器,将有丘陵、山脉、蓝天和狮鹫的 3D 幻想世界带入生活。
  • 身体姿势估计 —使用 OpenPose 姿势估计模型和 SSD 对象检测模型,不断检测玩家的身体姿势作为系统的输入,以控制 Griffin。
  • 动作映射和手势识别——将身体姿势转化为有意义的动作和手势,如抬起左/右翼、左右滚动身体、起跳等。
  • 通信系统——使用套接字将手势输入发送到 3D 游戏引擎。我将在后面讨论为什么我们需要它。

以下是运行系统所需的硬件列表:

  • NVIDIA Jetson AGX Xavier——一款基于 GPU 的小型嵌入式设备,将运行上述所有模块。这是这项工作的完美设备,因为它可以通过简单的 HDMI 端口支持视频和音频输出,并且它有一个以太网端口,便于互联网接入。你甚至可以插入鼠标和键盘,在设备上进行开发和调试,因为它有一个功能齐全的 Ubuntu 18.04 操作系统。
  • 电视(带有 HDMI 输入和内置扬声器)——作为游戏引擎的显示器。
  • 摄像头 —索尼 IMX327。这是一个非常棒的微型全高清超低光相机。老实说,我本来可以选择一款更低端的相机,因为我只需要 224x224 的图像分辨率。然而,既然我已经为另一个项目准备了这台相机,为什么不使用它呢?
  • Blu-Tack——将所有东西粘在一起,确保所有东西都在原位。😃

Jetson AGX Xavier,IMX327 相机和 Blu Tack。

履行

现在是我动手开始建设的时候了。

构建 3D 游戏引擎

为了更好地模拟飞行体验,Griffin 系统将以第三人称视角渲染 3D 世界。想象一下,一台摄像机紧跟在格里芬身后,准确地观察着他正在观察的地方。为什么不用像飞行模拟器风格的单人视图?因为看到一只鹰的翅膀和他的手臂同步移动,将有助于德协快速学习如何控制游戏,并享受更身临其境的体验。

构建自己的 3D 游戏引擎不是一件容易的事情,可能需要几周时间。如今,大多数开发者只是简单地使用一个专有的游戏引擎,如 Unity 或 Unreal。然而,我运气不好,因为我找不到任何运行在 Ubuntu OS/ARM 芯片组上的游戏引擎。一个替代方法是找到一个完全在 OpenGL 上运行的开源飞行模拟器。这将保证它可以在 AGX 上工作,因为它支持 OpenGL ES(OpenGL 的轻量级版本)并且是硬件加速的,如果你不想游戏引擎运行得像乌龟一样慢,这是必须的。

幸运的是,我遇到了一个符合上述标准的 C++ 开源飞行模拟器。我进行了以下修改:

  • 我把基于按键的飞行控制系统换成了基于目标的系统。这样,我可以不断地为格里芬的身体设定一个目标翻滚角度,让它慢慢翻滚。这个滚动目标稍后将由手势识别模块通过映射 Dexie 手臂的方向来自动设置。
  • 我增强了静态 3D 模型管理,以支持分层结构。最初的飞机模型作为一个刚体移动,没有移动的身体部分。然而,格里芬有两个翅膀,需要能够独立于身体移动。为此,我将两个翅膀作为独立的 3D 模型添加到身体上。我仍然可以独立旋转每个翅膀,但我也可以移动格里芬的身体,从而间接移动两个翅膀。一个正确的方法是建立一个骨骼动画系统,并将身体的各个部分组织成一个树状结构。然而,因为我只有三个身体部分要处理(身体和两个翅膀),所以把它们分割开就行了。为了编辑老鹰和树的 3D 模型,我使用了 Blender,这是一个免费且易于使用的 3D 创作工具。

在 Blender 中编辑 eagle 3D 模型。

  • 我为 Griffin 添加了一个树模型和一个游戏状态,可以在不重启应用程序的情况下重启游戏。格里芬有两种状态:站立,也就是格里芬站在树枝上飞行的状态。
  • 我使用 libSFML 添加了声音回放:一只尖叫的鹰和格里芬一起飞就开始播放的循环风声。

建立身体姿势评估

该模块的工作是不断地从摄像机输入中检测身体姿态。具体来说,我们需要知道左/右肘、左/右肩、脖子和鼻子的位置,以便能够驱动格里芬的翅膀和身体,并触发特定的手势。 OpenPose 是一个流行的开源库,收集了估计身体姿势、手部姿势甚至面部特征的 AI 模型。我使用的模型是以 resnet18 为骨干特征提取器的人体姿态 COCO 模型。这个模型可以实时检测 18 个关节,包括上面我们需要的 6 个关节。

身体 COCO 联合图。

一个大问题是 OpenPose 是建立在 PyTorch 框架之上的,它在 NVIDIA AGX Xavier 中以 4FPS 的速度运行非常慢,因为它不会利用高度优化的 TensorRT 框架。幸运的是,有一个很棒的工具叫做 torch2trt,它可以自动将 PyTorch 模型移植到 TensorRT!安装 OpenPose,将 PyTorch 转换成 TensorRT,下载预先训练好的 resnet18 主干模型的步骤在这里有完整的讲解。

为了从摄像机获取视频,我使用了另一个名为 Jetcam 的强大库。在 4 行代码内,您就可以让整个系统运行起来。

from jetcam.csi_camera import CSICameracamera = CSICamera(width=224, height=224, capture_width=224, capture_height=224, capture_fps=30)
image = camera.read()

动作中的身体姿态估计。

正如你在上面看到的,我让姿态估计模块以 100FPS 的速度运行!我确信这还可以进一步优化。

经过几次测试后,我发现有时模型会错误地将随机对象识别为关节(假阳性),如下图所示。这足以在格里芬的运动控制中制造麻烦。

检测到假阳性身体关节

用亚马逊 SageMaker JumpStart 建立物体检测模型

解决这个问题的一个方法是添加一个辅助人工智能模型,一个物体检测,给我一个检测到人类存在的边界框。然后,我可以排除这些框之外的所有检测到的身体关节。作为一个额外的收获,边界框还帮助我从背景中的其他可见玩家中识别出主要玩家。被认为是主要玩家的离摄像机最近的人会使他/她的脚(边界框的底部)最靠近屏幕的底部。请注意,这个假设只有在他们的脚可见时才有效。

在我过去的项目中,我手动训练了一个 SSDMobileNetV2 对象检测模型。这次我使用了一个亚马逊 SageMaker JumpStart ,这是 AWS 几周前发布的一个工具,让你只需点击一个按钮,就可以从 TensorFlowHub 和 PyTorchHub 部署一个人工智能模型。有 150 多种型号可供选择,其中一种是经过全面预培训的 SSDMobileNetV2:)

从 Amazon SageMaker Studio 启动 JumpStart

亚马逊 JumpStart 是亚马逊 SageMaker Studio 中的一个功能,这是一个集成的人工智能开发环境,让你可以轻松地构建、训练、调试、部署和监控你的人工智能模型。在我选择了 SSDMobileNetV2 之后,只需点击一个按钮,我就可以部署这个模型了。接下来,我打开提供的 Jupyter 笔记本,它带有推理代码,让我通过调用已经为您自动构建的模型端点来立即测试模型。

如果您将这个模型作为 REST API 部署在云中,那么您的工作基本上已经完成,无需编写任何代码。然而,由于我将在 edge 上部署这个模型,我将在 S3 bucket 中创建的预训练模型文件复制到我的 Jetson AGX Xavier,并使用 tf.saved_model.load 函数加载它们,为推理调用做好准备。看,更好的方法可能是使用亚马逊 SageMaker Neo 编译模型,然后使用 AWS 物联网 Greengrass 直接部署到 Jetson AGX Xavier。然而,由于一些张量的命名惯例,在撰写本文时,Amazon SageMaker Neo 无法从 JumpStart 编译 SSD 对象检测模型,否则这将是一个完整的端到端过程。

以上整个过程只花了我 5 分钟。相比之下,在我的上一个项目中,我花了两天时间标记所有数据,设置训练代码,并等待训练完成。

现在有了对象检测,我在盒子排除逻辑之外添加了身体关节,我看到假阳性大大减少了。耶!

在人体边界框之外的拒绝的身体点。

今天你可以用人工智能做的事情是相当惊人的。回想 20 年前,当我还是一名游戏和电影 SFX 开发人员时,要做这样的事情,你需要花费数十万美元的动作捕捉硬件,这需要在你的身体和脸上到处都有摄像头和红外线灯以及反光球。看,公平地说,他们更准确;然而,用不了多久,我们就可以用人工智能和 50 美元的网络摄像头达到同样的结果。

动作捕捉系统设置,由维基百科

建立动作映射和手势识别

这个模块对于将姿态估计模块检测到的 6 个关节的运动转换成对游戏系统更有意义的输入是至关重要的。这包括三个从检测到的关节到 Griffin 运动的直接运动映射和两个触发动作的手势识别。

  • 飞行时身体翻滚——控制狮鹫飞行的前进方向。身体滚动是根据水平轴和从右到左肘部向量之间的角度计算的(顶部照片)。当飞行时,两翼使用这个滚转角同步移动。选择肘部而不是手腕是为了最大化可见度,因为手腕经常移动到相机的视野之外或者被其他身体部位挡住。
  • 站立时旋转翅膀——这纯粹是一个装饰性的动作,除了让游戏更有趣和给人更多站立时独立控制每只翅膀的印象之外,没有其他目的。它是根据水平轴和每个机翼的肩到肘向量(下图)之间的角度分别计算出来的。最终的横滚角度增加了 15 度,以夸大机翼的运动,因为在一段时间内将双臂高高举起是相当累人的。

身体滚动和机翼旋转运动映射。

  • 蹲伏是另一个修饰动作,给人一种在飞机起飞前控制格里芬蹲伏姿势的印象。它是根据脖子到鼻子的向量和肩膀向量的长度之比计算出来的。你蹲得越远,你的脖子和鼻子之间的距离越小,而你的左肩和右肩之间的距离保持不变,这就产生了一个更小的比值。你可能想知道为什么我不直接使用颈部垂直坐标作为下蹲偏移。直接使用原始坐标从来都不是一个好主意,因为颈部垂直运动的幅度取决于人和相机之间的距离。我们不希望当人越来越靠近和远离摄像机时错误地触发蹲伏动画。蹲伏动画只是通过向下移动格里芬来实现。理想情况下,我可以让双腿弯曲;然而,这需要做更多的工作,却没有什么附加值。我需要将腿作为身体的一部分分离出来,并像制作翅膀一样分别制作它们的动画。

蹲伏运动贴图。

  • 起跳手势——当左肩和右肩之间的中心点在不到一秒的时间内上下移动大于阈值时被识别。阈值被选择为肩部之间的长度。顾名思义,当这个手势被触发时,格里芬会从树枝上跳下来开始飞行。
  • 游戏重置手势 —当左肩和右肩的水平位置颠倒时被识别。例如,演员背对着摄像机。当这个手势被触发时,游戏将重置,格里芬将重新站在树上,准备下一次飞行。

取下并重置手势识别。

通信系统

现在,随着三个主要组件的完成,我们只需要把所有的东西粘在一起。我们需要将从姿态估计中检测到的身体关节发送到手势识别模块。这是一项简单的任务,因为它们都是用 Python 编写的同一个应用程序的一部分。然而,没有简单的方法将映射的动作和手势发送到 3D 游戏引擎,因为它在 C++中是作为单独的应用程序构建的。你可能想知道为什么我不直接用 Python 来构建游戏引擎。原因是因为没有可靠的方法使用 Python 访问 OpenGL。此外,即使有可能,我也不想花费数周时间将 C++移植到 Python 代码中。

我需要找到一种方法,以最小的开销在两个应用程序之间高效地传递这些信息。我想强调最小开销的要求,因为这是一个游戏引擎的关键因素。在输入控制器和相关动作发生之间的小至 100 毫秒的延迟将很容易消除沉浸感。考虑到这一点,两个独立应用程序之间的最佳通信媒介是通过套接字。它是 TCP 协议(通俗地说就是互联网的主干技术)使用的一种底层通信机制。由于这两个应用程序驻留在同一台计算机中,延迟将在 5 毫秒之内。

在 C++中,我们简单地使用 sys/socket 库,而在 Python 中,我们可以使用 socket 框架。手势识别和姿势估计模块,从现在开始我将调用 Python 应用程序,作为发送 5 条信息的客户端:roll_target、lwing_target、rwing_target、body_height(蹲伏偏移)和 game_state。3D 游戏引擎,从现在开始我将称之为 C++应用程序,作为一个服务器监听并不断接收上述信息。

为了将这 5 条信息/变量正确地从 Python 映射到 C++,在我们发送它们之前,它们被放置在一个类似 Python C 的结构中。

class Payload(Structure):
 _fields_ = [(“roll_target”, c_int32),
             (“lwing_target”, c_int32),
             ("rwing_target", c_int32),
             ("body_height", c_int32),
             ("game_state", c_int32)]

在 C++应用程序中,它们作为本机 C 结构被接收。

typedef struct payload_t 
{    
    int32_t roll_target;    
    int32_t lwing_target;
    int32_t rwing_target;
    int32_t body_height;
    int32_t game_state;
} payload;

正如您在下面的架构图中所看到的,通信层由位于 Python 应用程序中的客户端模块和位于 C++应用程序中的服务器模块组成。

格里芬架构图。

校准和测试

一切准备就绪后,我在办公室安装了 Griffin 系统来进行校准和测试。该系统的表现比我预期的好得多,在进行所有实时 3D 渲染和姿态估计时,整体帧率为 60FPS。NVIDIA Jetson AGX Xavier 果然名不虚传。你可以在下面的视频中看到校准和测试过程。视频可能看起来有点断断续续,因为我以 15FPS 的速度拍摄 Ubuntu 桌面,以最小化对 Griffin 的性能影响。

格里芬系统校准和测试。

表演时间

最后,是时候进行一次真正的测试了,让德西与格里芬一起进行他的第一次飞行。我在起居室里安装了系统,他正不耐烦地等着开始行动。

德西和格里芬的经历。

只用了一次演示如何控制格里芬,跳跃起飞和左右移动我的手臂来控制翅膀,德谢就熟悉了这个系统。他收集到格里芬的翅膀运动与我的手臂运动直接同步,这要归功于第三人称视角模式!从那以后,一切变得非常自然,他开始独自享受他的飞行经历。这证明了没有比自己的身体更好的游戏操控了。还记得史蒂夫·乔布斯在发布第一代 iPhone 时嘲笑手写笔胜过手指的评论吗?

很有趣的是,有一次,当德西快要撞到一座山的时候,他把手臂举得很高,试图来个急转弯。然而,由于我设置的最大滚动角度限制,格里芬不会让他变得更急,最终撞到了山上。:)下面的视频会给你展示这一切。

德西与格里芬的第一次飞行。

他玩了足足半个小时,直到他累得发狂,疯狂地挥舞着双臂。好的方面是,那天晚上他睡得非常好,这对我们来说是一场胜利。耶!更多网飞时间:)

摘要

我确实从建造格里芬中学到了很多,同时也获得了乐趣。以下是我学到的一些东西:

  • Torch2trt 是一个很棒的工具,可以自动将 PyTorch 模型转换为 TensorRT,以优化您在 Jetson AGX Xavier 中运行的 AI 模型。许多前沿的人工智能模型都是在 PyTorch 中构建的,将它们手动移植到 TensorFlow 是一件痛苦的事情。
  • NVIDIA Jetson AGX Xavier 真是个畜生!很多人说过,你可以运行一个计算机视觉模型,同时处理 30 个直播的 1080p 视频流。现在,我对此毫不怀疑。
  • Amazon SageMaker JumpStart 通过使部署它们变得超级容易,为您提供了大量受欢迎的人工智能模型。
  • 构建 3D 游戏引擎让我回到了过去作为游戏和电影 SFX 开发人员的生活,并让我重温了 OpenGL、C++和三角学方面生疏的技能。
  • 我可以用 Unity 引擎和 Kinect 传感器在 Xbox 上构建 Griffin。然而,这有什么乐趣呢?有时候从头开始建设才是乐趣所在。
  • 做老鹰是一件相当累人的工作,尤其是举起手臂一段时间。然而,一只真正的鹰可能会从空气阻力中获得很多帮助,以在飞行过程中保持翅膀张开。

就这样了,伙计们。我希望你喜欢这个故事。

完整的源代码可以在这里找到。

用 Python 和 Pyvis 制作交互式网络图。

原文:https://towardsdatascience.com/making-network-graphs-interactive-with-python-and-pyvis-b754c22c270?source=collection_archive---------6-----------------------

绘制精美图表的简单方法。

图片作者。

有一段时间,我和 Streamlit 社区的其他人 [1]一直在寻找一种工具来呈现交互式图形,但直到现在,只有少数人能够实现这一点。这可能是因为需要 javascript 的专业水平,这是许多 Streamlit 用户可能想要避免的,因为这是项目的承诺,从 python 部署漂亮的 web 应用程序,不需要 javascript!!(当然,掌握 javascript 是制作令人敬畏的 streamlit 应用程序的一大优势)。

最近,经过几周的努力,我发现 Pyvis 正在寻找其他基于 javascript 的库的替代品,这些库用于使图形具有交互性。我非常喜欢 pyvis,并想在这篇文章中分享一些我学到的技巧。但是如果你想自己看,可以查看文档页面[2]:

https://pyvis.readthedocs.io/en/latest/index.html#

这篇文章的其余部分如下:首先,我将展示一个超级简单的例子来做一个小的 3 节点网络。其次,我展示了如何固定节点的位置,以及如何保持分子图形的形状。第三个案例是用 Networkx 构建一个网络。最后,我展示了一个使用 Pyvis 的 Streamlit 应用程序。

1.简单的图形例子。

我将从一个简单的例子开始,创建一个网络对象并添加 3 个节点(方法 add_node ),用两条边分别标记为 1、2 和 3(方法add _ edge)[1–2]和[2–3]。为了部署图表(例如在 Jupyter 或 Colab 环境中), pyvis 使用 show 方法将 python 代码“翻译”成 html+javascript。调用 g.show('example.html') 将可以用 display 渲染的 html 文件写入磁盘:

这是结果,

图片作者。Pyvis 的简单示例🚀。

这很容易,不是吗?这个基本配方将在下文中使用。我做了一个小函数 show_graph() 来一步完成显示,如下面的代码片段所示。您可以在底部的 github repo 中的 Colab 笔记本中找到这些代码和所有代码🙌。

2.图形形式的分子。

下一个案例是我认为可以实现的,将 pyvis 与化学信息学库 RDKit 结合起来🤓 [3].我假设这不是普遍感兴趣的,所以我将避免构建分子的过程,相反,我将只呈现原子的最终节点和连接信息。这里显示的是咖啡因分子☕️.

图片作者。咖啡因分子

因为我想保持它的形状,首先我需要原子的坐标,还需要一些非常具体的物理选项。让我用一种简单的方式来解释这是如何完成的:因为有 14 个原子,所以我在每个原子编号上运行了一个循环,用 add_node 方法分配节点。对于每个节点,我给出了原子符号,以及来自三个独立列表的笛卡尔坐标(这是我从 RDKit 预处理中获得的),这三个列表分别命名为idxsys :

for atomo in range(14): 
    g3.add_node(atomo,label=ids[atomo],
    x=int(100*xs[atomo]),y=int(100*ys[atomo]),
    physics=True,size=30)

( xsys 被任意乘以 100,只是为了使图形更易于管理)

完整的片段由❤️主持:),在这里你还可以看到物理选项:

这就是我认为可以接受的结果:

图片作者。用 Pyvis 将 2D 表示转换成交互式图形😎。

这可以主要用于吸引眼球的演示或设计面向化学的网页。但是也可以设想其他用途。

3.现在,一些空手道动作。

如果你熟悉Networkx【4】的话,你应该知道它很受欢迎,因为这个库很好用,文档也很好,但是据我所知,它缺少这个让图形交互的功能。幸运的是,Pyvis 漂亮地接受了来自 Networkx 的 graph 对象。Networkx 已经预建了 Zachary 的空手道俱乐部图[5],其中有 34 个俱乐部成员,0 和 33 个主席和老师有冲突,他们根据成员之间的影响将俱乐部分成两组。下面显示了 pyvis 中这个图形所需的代码片段。首先,我们从 Networkx 得到了图 G 。然后我们构建 pyvis 对象 g4、和方法 from_nx is 用于将图形导入 pyvis…就这么简单:

在这里,我必须强调第 8 行中的 show_buttons 方法,该方法用于部署物理选项,允许用户交互地改变节点相互交互的方式,就好像它们由弹簧连接并具有其他物理交互一样。这使得图形的动态看起来更“自然”,在视觉上是一种享受。

图片作者。Pyvis 中使用 Networkx 生成的扎卡里空手道俱乐部数据集的图表🤛。

当然,还有其他方法可以使图形具有交互性,比如使用高级库,但是一般来说,它们更复杂。pyvis 提供的简单性值得赞赏。

4.在 streamlit 上部署。

最后,我展示了这些动态图表在 Streamlit web 应用程序中的外观。我不打算讨论如何做这个应用程序,我把它作为读者的家庭作业。

提示:你可以在下面看到 github 回购😏

图片作者。Pyvis 在 Streamlit 中运行🔥。

现在该怎么办..

  • 如果你愿意,你可以在这里玩网络应用:

https://share . streamlit . io/napoles-uach/streamlit _ network/main/app . py

  • 如果你喜欢,请启动 github 回购🌟

https://github.com/napoles-uach/streamlit_network

  • 这里展示的代码片段是 Colab 笔记本的一部分,您可以在这里找到:

https://github . com/napoles-uach/streamlit _ network/blob/main/pyvis _ sample . ipynb

感谢阅读!!

帮助我通过使用下面的链接成为媒体成员来继续创建这样的内容。只需 5 美元/月,你就可以在媒体上看到所有的故事,还可以用 2.27 美元支持我,谢谢!

https://medium.com/@jnapoles/membership

https://jnapoles.medium.com/membership

引用的链接:

https://discuss.streamlit.io/ https://pyvis.readthedocs.io/en/latest/index.html# https://www.rdkit.org/ https://en.wikipedia.org/wiki/Zachary's_karate_club

让神经网络通过更长时间的“思考”来解决更棘手的问题!

原文:https://towardsdatascience.com/making-neural-networks-solve-tougher-problems-by-thinking-for-longer-32ecb599bcd?source=collection_archive---------29-----------------------

这是我根据对论文的理解写的一篇博文——“你能学会一个算法吗?从简单到困难的循环网络问题的归纳,来自 Schwarzchild 等人(2021) [ 链接

TL;在这里,作者在更简单的迷宫/谜题形式上训练一个递归神经网络(RNN),并在测试时,在“更难”的问题上评估它们。与通常的训练/测试集评估不同,在这里,RNN 可以“思考更长时间”进行测试。更具体地说,它将比在训练阶段有更多的循环块。作者注意到,与具有类似深度的简单前馈神经网络相比,通过思考更长时间,RNNs 能够以有原则的方式解决更复杂的问题。也就是通过使用更多的循环层。这里,相似深度指的是训练时 RNN 和前馈神经网络的有效深度。

长处 —论文开始了一个重要的方向——“如何让神经网络处理看不见的测试情况?使用比训练时更多的计算有助于在测试时表现得更好吗?NNs 能从它的记忆(或内部表征)中归纳/推断吗?在这里,作者让 RNN 推断它对类似的,但“更难”的问题的理解。最初的实验看起来很有希望,并可能成为我们理解什么实际上使更深(或更宽)的模型表现更好的方法。

告诫 — 除了少数简单明了的案例,很难对问题的难度进行精选和排序。因此,在较简单的问题上进行训练并理解对较难问题的影响将是一个挑战。这在其他研究领域也是一个众所周知的问题,比如课程学习(Bengio et al .,2008)。

未来方向 —作者注意到,由于更好的感受野,利用扩张的卷积得到了更好的结果。一个增加的方法是使用注意层、变压器等来观察更大感受野的效果。因此,回答了一个更大的问题,什么是重要的——思考更长时间还是对整体空间有“感觉”,或者两者都有。此外,这里通过使用相同的权重(权重共享)天真地增加了循环迭代。观察随机扰动一小部分权重的效果会很有趣。最后,尽管 rnn 考虑的时间更长,但他们应该考虑的“时间”仍然是预定义的——使额外的循环步骤的数量由数据驱动可能是一个有趣的实验。

简介

人类表现出解决复杂问题的能力,这是基于他们对简单玩具问题的学习。例如,解决了一个 3x3 难题的人,可以使用类似的逻辑,花更多的时间来解决一个 5x5 难题,尽管以前从未见过它。更具体地说,人类可以通过“更努力/更长时间地思考”,从更小的问题中得出解决更大问题的模式。

在 Schwarzchild 等人(2021)的文章中,作者从人类身上看到的这些现象中获得了灵感,以了解是否可以在神经网络(NNs)中观察到类似的模式。也就是说,我们能否让神经网络基于对简单问题的学习来解决未知和更复杂的问题。这里,对 3 种主要类型的数据进行分析——前缀和计算、迷宫和象棋。

出于多种原因,在测试推断中思考更长时间可能是一个有趣且重要的问题,但不限于—

  1. 计算预算的限制——模型可以在测试时进化,而不是训练非常深的网络。
  2. 这在问题不断发展的领域(与训练相比,输入的复杂性和输入的大小都在增加),以及对测试分布的访问是有限的,可能是特别有趣的。
  3. 理解神经网络从其记忆中进行推断的能力,并为推广带来新的视角。

已经有大量的文献从迁移学习 的角度研究类似的方面(Hinton 等人,2006;刘冰等人,2007 年;本吉奥等,2012)神经网络中的泛化 (张等,2016;阿罗拉等人,2019;马内尔等人,2020 年;Garg 等人,2021)元学习 (Schmidhuber,1987;本吉奥等人,1992 年;Thrun & Pratt,1998;Andrychowicz 等人,2016;拉维&拉罗歇尔,2017;Finn 等人,2017)神经架构搜索 (Zoph 等人,2016) 等等。虽然,本文中使用的任务类型(Schwarzchild 等人,2021)与上述作品不同—

  1. 在这里,重点是让神经网络像人类一样“思考更久”,以解决更复杂的问题——也就是说,在这里,模型被提供更多的计算(或更长的执行时间),直到它对答案有信心。在传统的迁移学习框架中,模型根据开放世界知识进行预训练,然后根据相关的下游任务进行微调——目的是让模型从大量可用数据中学习有用的表示,并使用它来提高下游任务的性能。
  2. 在元学习设置中,重点是 学习一个可以学习的算法。而在目前的工作中,作者着眼于学习一种算法来解决一个特定的问题,例如,一个国际象棋配置或拼图游戏。
  3. 典型的概括与记忆工作侧重于理解神经网络从数据中学到了什么,以及它们基于相同分布、不同分布等的“概括误差”(训练/验证误差)概括得有多好。在这项工作中,重点是了解模型是否可以从较小的问题中学习模式,并在额外计算的帮助下将它们用于较大的问题,从而进行归纳。

数据集

如前所述,作者分析了 3 类问题的假设——

  1. 前缀求和问题 [ 链接 ]—这里输入的是 32 位长度的二进制字符串(测试时使用 40 到 44 位的字符串)。重点是计算二进制字符串模 2 的前缀和。也就是说,输出将是计算输入模 2 的累积和的等长字符串。

模 2 前缀和的一个例子。[ 来源

2.迷宫 —训练时输入为 9x9 迷宫,测试时输入为 13x13 迷宫。预期输出是二进制掩码输出,它突出显示输入迷宫中绿色和红色点之间的最短路径。

左侧面板是迷宫的示例,绿点代表起点,红点代表终点(目的地)。白色像素是代理可以采取的步骤,黑色像素是代理无法通过的障碍物。右图显示了这些点之间的最短路径(这是网络的预期输出)。[ 来源

  1. Chess — 输入数据是一个 8x8x12 数组,输入棋盘中所有棋子的位置。这些配置来自在线平台 Lichess。与之前的数据集不同,其中输入大小在训练和测试时间中变化,这里我们有不同的“难度评级”:模型在难度较低的样本上训练(基于评级),在难度较高的样本上测试。

左图是输入的国际象棋布局,右图是可以引导玩家走向胜利的(单个)最佳走法。来源

模型架构和培训

基于循环块的展开测量有效深度的样本。[ 来源

所用的前馈网络基于 ResNet 架构,但有一些变化——除了初始层和最后一个递归层之后,宽度没有变化,没有批处理,完全卷积——以确保递归模型尽可能接近前馈实现。用于循环网络的模型架构类似于经典的 ResNet 模型。也就是说,两个模型之间的主要区别在于,权重在循环块中共享,但在前馈网络中不是这样。

结果

该图将最佳前馈模型与等效深度的递归模型进行了比较。[ 来源

前缀总和 —从上图中我们可以看出,随着迭代次数的增加(循环块的展开),性能会提高。

结果基于在 32 位字符串上训练后在 40 位字符串上的测试。[ 来源

迷宫求解— 模型在经历更多迭代的同时改进并学习其路径,如下图所示。递归模型表现出比传统前馈模型更好的性能

在这里,模型解决迷宫的顺序思考能力可以被可视化。此外,根据模型在其输出中的置信度对像素进行着色。[ 来源

8×8 拼图训练后在 13×13 格子上的表现。递归模型始终比深度相当的前馈模型表现更好。

这里将递归模型与最佳前馈模型进行比较。通过思考更长的时间,循环模型能够表现得更好。

国际象棋— 观察到的国际象棋趋势也类似。在考虑这个难题的最佳解决方案时,为了简洁起见,忽略了一些边缘情况。

我们可以注意到一个相似的趋势,模型依次分析所有可能的移动,并且随着迭代的进行越来越自信。

与表现最好的深度为 20 的前馈网络相比,在测试时思考得更深入有助于递归模型更好地解决更难的象棋难题。

讨论

作者提出了一个关于循环层如何帮助的重要问题。这里仍有许多未解的问题

  1. 递归模型如何模拟分层滤波器,即,尽管权重共享,但是与每层中具有特定滤波器的前馈网络相比,递归模型如何能够提取相似的模式以学习特定模式?这个问题在作者的另一篇论文中得到了部分回答——复发和深度的不可思议的相似性[ 链接 ](很快会有更多关于这篇论文的内容!).
  2. 怎样才能让模型明白什么时候停止思考?人类在找到一个谜题的最优解后,不会突然走向一个随机的方向,最后得出一个错误的答案(至少,我们大部分不会:)
  3. 理解思考时间更长、视野更大的影响。该论文表明,对于较大的感受野使用扩张的卷积是有帮助的。这是否意味着有一个方向,我们不仅可以看到模型思考了多长时间,还可以看到所有模型(在空间上)可以思考/感觉什么?

如果你已经读到这里,非常感谢,希望你能读到一些新的有趣的东西!请查看原始论文以获得更深入的分析和结果!请随时让我知道你的想法。我是这方面文献的初学者,如有理解上的错误,欢迎随时指出!乐学!

Twitter | LinkedIn

PS——所有的数字都来自原始论文,如果没有,我也提到了来源。这些信息图表的所有荣誉归原作者所有。谢谢!

用 Face API 和一些创意为朋友制作新年礼物

原文:https://towardsdatascience.com/making-new-year-presents-for-friends-with-face-api-and-some-creativity-57c169e73c99?source=collection_archive---------10-----------------------

几年前,我想出了制作认知画像的主意,这是一个人的混合图像,由许多自动对齐的照片组成。因为就在圣诞节和新年之前,我通过在日历海报上打印朋友和亲戚的认知画像,为他们制作了个性化的礼物。今年圣诞节,我想和你分享做同样事情的秘诀。

我的女儿薇琪带着自己的新年认知日历

TL;DR: 产生认知画像的代码可以在认知画像 GitHub 库中获得。如果你想出一些新的创造性的方法来有计划地排列照片,并向原始回购请求贡献你的想法,我会很高兴!

创建认知肖像的方式是根据他们的眼睛排列几幅肖像,从而在有些混合或模糊的背景上创建看起来像组合混合脸的东西。虽然你当然可以在 PhotoShop 中手动完成,但这会很耗时,而且你快速实验的能力会受到严重限制。

使用 微软认知服务 ,也就是 Face API ,可以通过编程创建同样的效果。它能做的事情之一是从面部提取关键点,即所谓的面部标志。

如果你想了解更多关于 Face API 和它能做的很酷的事情,我推荐你参加 微软学习课程

准备照片

你应该做的第一件事是收集你朋友的照片——理想情况下,每个人你应该有 10-30 张照片。分辨率没有多大关系,因为最终的肖像是相当混合的,相对低分辨率的图像也很好。我将假设你有你的朋友的脸是图片上最大的一张的图片——如果不是这样的话,你可能想要裁剪图像。

提取面部标志

让我们从学习如何从图片中提取面部标志开始。 微软人脸 API 提供了一个简单的 REST API,可以从人脸图像中提取很多有用的信息,包括眼睛的坐标。

通过 REST 直接调用 Face API 相当容易,但使用现有的 SDK 更好,它作为 Azure SDK 库 的一部分可供 Python 使用。你可以 访问微软文档 获取更多关于 Face API 的详细信息,以及在 Python 之外的语言中使用它。

我们使用以下命令安装 SDK(以及我们将需要的 OpenCV 库):

pip install azure-cognitiveservices-vision-face opencv-python

要使用 Face API,你需要访问微软 Azure 云。如果你没有,你可以随时获得一个https://azure.microsoft.com/free/?WT.mc_id=academic-35500-dmitryso,或者Azure for Students/GitHub Student Developer Pack以防你是学生。

一旦有了订阅,创建 Face API 端点。选择离您最近的地区和免费层。它将允许您免费拨打多达 30000 个电话,每分钟 20 个电话的限制(这对我们的任务来说足够了)。

这样做之后,您就可以获得资源键和端点,这是以编程方式访问 API 所必需的。将它们放入我们的代码中:

key **=** '--INSERT YOUR KEY HERE--'
endpoint **=** 'https://westus2.api.cognitive.microsoft.com'

Face API 的大多数调用都是通过 FaceClient 对象完成的:

**from** azure.cognitiveservices.vision.face **import** FaceClient
**from** msrest.authentication **import** CognitiveServicesCredentialscli **=** FaceClient(endpoint,CognitiveServicesCredentials(key))

面部检测的主要功能称为face.detect_with_urlface.detect_with_stream。根据您指定的参数,它可以从面部提取许多有用的信息——在我们的例子中,我们需要面部标志:

im_url**= \** 'https://2016.dotnext-piter.ru/assets/images/people/soshnikov.jpg'
res **=** cli.face.detect_with_url(im_url,return_face_landmarks**=**True)
**print**(res[0].facial_landmarks.as_dict())

在这段代码中,res是一个数组,它的每个元素对应于图片中的一张脸。最大的脸将首先出现,因此使用res[0]将给出该脸的信息。我们还可以使用as_dict()将其转换为 Python 字典,以便于操作:

{
  "eyebrow_right_inner": {
    "y": 106.3,
    "x": 157.2
  },
  "pupil_right": {
    "y": 118.9,
    "x": 170.9
  },
  "eye_right_outer": {
    "y": 118.5,
    "x": 181.5
  },
  "pupil_left": {
    "y": 126.7,
    "x": 112.6
  }, 
...

处理图像

假设您将想要为其创建认知画像的人的所有照片放在images目录中,我们可以遍历所有照片并提取所有照片的面部标志:

**import** glob
filenames **=** []
images **=** []
imagepoints **=** []
**for** fn **in** glob.glob("images/*"):
  **print**("Processing {}".format(fn))
  **with** open(fn,'rb') **as** f:
    res **=** cli.face.detect_with_stream(f,return_face_landmarks**=**True)
    **if** len(res)**>**0:
      filenames.append(fn)
      images.append(cv2.cvtColor(cv2.imread(fn),cv2.COLOR_BGR2RGB))
      imagepoints.append(res[0].face_landmarks.as_dict())

处理完所有图像后,我们可以显示它们,以及获得的面部标志:

**def** decorate(i):
   img = images[i].copy()
   **for** k,v **in** imagepoints[i].items():
      cv2.circle(img,(int(v['x']),int(v['y'])),7,(255,255,0),5)
   **return** imgdisplay_images([decorate(i) **for** i in range(5)])

作者图片

在这段代码中,函数display_images用于绘制一系列图像,这里我将省略这段代码,你可以在资源库中找到它

仿射变换

现在我们有了这些点,我们需要对齐图像,这样眼睛就可以移动到所有图像的完全相同的位置。要做到这一点,我们需要缩放图像,旋转它,可能还需要做一些倾斜。在数学上,图像的这种变换叫做 仿射变换 。众所周知,仿射变换由三个点的变换唯一定义。

在我们的例子中,我们知道眼睛的位置,并且我们知道我们想要将它们移动到位置(130,120)和(170,120),如果我们的目标图像尺寸是 300x300,这听起来是一个不错的位置。然而,除了眼睛之外,我们还需要一点来完整地定义转换。

虽然我们可以选择任何一个点,但选择嘴中间是很方便的——因为它在某种程度上与眼睛相对,并且三角形的眼睛——嘴中间覆盖了脸的相当大的区域。我们没有中嘴的面部标志,但是我们可以在mouth_leftmouth_right之间取一个平均值。

使用矩阵在 2D 空间中定义仿射变换。OpenCV 包含一个函数getAffineTransform,它可以计算这样一个矩阵,给定变换前后的 3 个点的坐标,如我们上面所描述的。然后,我们使用warpAffine对原始图像应用变换——它还剪切掉图像的剩余部分,以便它适合指定大小的矩形。

target_triangle **=** 
   np.float32([[130.0,120.0],[170.0,120.0],[150.0,160.0]])
size **=** 300**def** **affine_transform**(img,attrs):
    mc_x **=** (attrs['mouth_left']['x']**+**attrs['mouth_right']['x'])**/**2.0
    mc_y **=** (attrs['mouth_left']['y']**+**attrs['mouth_right']['y'])**/**2.0
    tr **=** cv2.getAffineTransform(np.float32(
        [(attrs['pupil_left']['x'],attrs['pupil_left']['y']),
         (attrs['pupil_right']['x'],attrs['pupil_right']['y']),
         (mc_x,mc_y)]), target_triangle)                                
    **return** cv2.warpAffine(img,tr,(size,size))

一旦我们定义了这个函数,我们就可以变换我们所有的图像:

aligned **=** [affine_transform(i,a) **for** i,a **in** zip(images,imagepoints)]
display_images(aligned[:5])

作者图片

然后…瞧!

为了得到最终的结果,我们基本上需要将图像融合在一起。要做到这一点,让我们回忆一下 Python 中的图像是用 numpy 数组表示的,并且可以很容易地用np.average对它们进行平均——我们只需要指定正确的轴:

imgs**=**np.array(aligned,dtype**=**np.float32)**/**255.
plt.imshow(np.average(imgs,axis**=**0))

这里的一个技巧是,我们需要将图像数据从整数矩阵转换为浮点(在 0..1)为了获得正确的平均。一旦我们做到了——这就是结果:

作者图片

要混合多少个图像

一个很好的问题是混合在一起的图像的正确数量是多少。从下面的例子可以看出,不同数量的图像会产生不同的结果。虽然很少有图像留下一些周围的细节可见,这可能会添加一些有趣的背景,有更多的图像产生非常混合的背景。

作者图片

尝试找到正确的平衡。此外,从随机选择和不同数量的照片中生成许多认知画像是完全有意义的,以便能够选择最佳结果。

下一步是什么?

将一个人的照片混合在一起仅仅是个开始!你可以尝试混合不同人的照片,或者混合一个人的不同年龄。此外,由于您可以通过编程控制图像在生成的画布上的放置方式,因此您可以创建一些有趣的艺术效果,如下所示:

《长大了》,2020。认知画像作者德米特里·索什尼科夫

这张照片是从我的家庭照片档案中自动创建的,通过使用 Face API 来检测我女儿的面部,然后过滤掉那些包含面部直视视图的照片,并根据年龄分成几个类别,以显示她的成长过程。

要了解如何识别人脸和处理家庭照片档案,请随意查看我的另一篇博客文章。

你可以在我的网站和 GitHub 知识库中找到更多认知画像的例子。如果你想出了一个新主意,利用面部标志提取将照片排列在一起——请随时通过提出拉取请求来为该存储库做出贡献。

我会等着看你们能把这个想法带到哪里去!

使 Numba 可访问,以便用 Python 进行更快的处理

原文:https://towardsdatascience.com/making-numba-accessible-for-faster-processing-with-python-77a4377576c?source=collection_archive---------28-----------------------

克服 Numba 的局限性,并以明智的方式使用它

克里斯里德在 Unsplash 上的照片

Numba 是一个针对 Python 的实时编译器,可以通过计算密集型的计算和函数(如 NumPy 数组上的循环)来加速代码。

Numba 编译的算法可以使 Python 代码的运行时间加快一百万倍,从而可以达到 c 的速度。此外,随着操作数量的增加,计算时间通常比 Cython 快得多,cyt hon 是另一种用于更快处理的编译器。这里有一篇参考文章,展示了 Python、Cython 和 Numba 处理之间的精确比较。使用 Numba 也非常容易,只需将 Numba decorators (@njit)应用于 Python 函数。

Numba 的局限性及其克服方法

但是,Numba 有一定的局限性。虽然它在 NumPy 数组上工作得最好,但它可能无法被 pandas 对象或 list 参数列表、一些 NumPy 函数(如 numpy.concatenate 或 numpy.diff)访问,或者更重要的是,无法被一些流行的 python 库(如 Scipy)访问。在这种情况下,使用 Numba 和 Cython/Python 函数以智能的方式重构代码可以大大提高处理速度。

在本文中,我将向您展示一个使用 Numba 和 Cython/Python 进行重构的示例,该示例旨在借助 Scipy 函数从任何 1D 信号中生成峰值屏蔽。在这里,我使用质谱数据作为示例数据集,它显示了肽的强度与质量/电荷的关系。如果您想对这些数据有更深入的了解,参考文章(张等,2009)可能会对您有所帮助。使用 Cython/Python 函数通过 Scipy 库进行峰值检测,然后使用 Numba 进行其余计算,结果证明这是一种高度优化且省时的方法。

一些 Scipy 函数有一些 Numba 替代函数,比如 scipy.integrate.quad 的 numbaducpack 和 scipy.optimize.root 的 NumbaMinpack。对于这些,建议在 Cython 和 Numba 之间分割总的处理,因为,

两者都被证明可以显著提高 Python 代码的速度

Scipy 代码可以用 Cython 编译

随着运算次数的增加,Numba 的速度比 Cython 快。

下面是 Jupyter notebook 中编写的一段简单代码的示例,它通过使用 Scipy.signal 的 find_peaks 和 peak_prominences 函数来检测信号(_data_slice)的峰值。在 Cythonized 单元格中,手动添加每个变量的类型,最后将信号全长的强度值(int_array)的 numpy 版本、峰值点(作为 peaks_array)、检测到的峰值的左右基点(分别作为 left_bases_array 和 right_bases_array)传递给 Numba 函数

Cython 函数

%load_ext Cython%%cython 
from scipy.signal import find_peaks, peak_prominences
cimport numpy as cnp
cnp.import_array()
import numpy as npcpdef **peak_finder_cy**(cnp.ndarray _data_slice, _scan_no, int int_index = 0): cdef cnp.ndarray _int
    cdef cnp.ndarray _peaks
    cdef cnp.ndarray _prominences
    cdef cnp.ndarray peak_mask
    cdef int wlen
    cdef cnp.ndarray int_array
    cdef cnp.ndarray left_bases_array
    cdef cnp.ndarray right_bases_array
    cdef cnp.ndarray peaks_list_array _int = _ms1_data_slice[_data_slice[:, 4] == _scan_no, int_index]
    _peaks, _ = find_peaks(_int)
    prominences, left_bases, right_bases = peak_prominences(_int,   _peaks, wlen=20)         

    int_array = np.array(_int)
    peaks_array = np.array(_peaks)    
    left_bases_array = np.array(left_bases)
    right_bases_array = np.array(right_bases) return int_array, peaks_array, left_bases_array,        right_bases_array

数字函数

import numba as nb[@nb](http://twitter.com/nb).njit()
def **peak_mask_finder_cy**(_int_list, _peaks_list, _left_bases_list, _right_bases_list):   
    peak_id = 1
    peak_mask = np.zeros(_int_list)
    j = 0
    for j in nb.prange(_peaks_list):                
        if j > 0 and _left_bases_list[j] < _right_bases_list[j-1] and _int_list[_peaks_list[j]] > _int_list[_peaks_list[j-1]]:
            _left_bases_list[j] = _right_bases_list[j-1]             

        peak_mask[_left_bases_list[j] + 1 : _right_bases_list[j]] = peak_id
        peak_id += 1
    return peak_mask

调用各自的函数

%%timeit
int_list, peaks_list, left_bases_list, right_bases_list = **peak_finder_cy**(signal_data, scan_no)peak_mask_final = **peak_mask_finder_cy**(int_list, peaks_list, left_bases_list, right_bases_list)

使用 Cython 和 Numba 的处理时间

每圈 39.2 s 120 ns(平均标准偏差。戴夫。7 次运行,每次 10000 个循环)

仅使用 cy thon

每循环 101 s 178 ns(平均标准偏差。戴夫。7 次运行,每次 10000 个循环)

因此,即使对于一小块数据,与仅基于 Cython 的代码相比,使用带有 Cython 和 Numba 的重构代码在处理时间上的改进也是显著的。随着从更大体积的数据集中检测到的峰的数量的增加,两者之间的处理时间差异可能会更加突出和显著。

这里要提到的是,为了开发处理流水线,Cython 代码必须在. pyx 文件中,并且需要一个单独的 setup.py 脚本,由 Cython 将其编译成. c 文件。C 文件由 C 编译器编译成. so 文件。这里使用的命令是:python setup . py build _ ext—in place。然后,可以在任何 python 脚本中以通常的方式导入 Cython 模块。

有人可能会说直接使用 Python 代码,而不是使用第一个函数(peak_finder_cy)的 Cythonized 版本。对于像 Scipy 这样调用编译 C 的库来说,它已经是一个高性能的库了,这是一个合理的论点。然而,当有大量扫描/数据段需要循环查找峰值时,Cython 可以被证明是非常有效的。这里的这篇文章可以帮助你了解更多的细节和例子。作为参考,使用 Python 和 Numba 对上面这段代码的处理时间是每循环 40.7 s 91.6 ns(平均标准时间。戴夫。7 次运行,每次 10000 个循环)。

结论

总之,重构是最可行的选择,使 Numba 可用于不兼容的 Python 库和函数的计算,同时确保代码的最佳运行时间。

参考

  1. https://www . pick up brain . com/python/speed-up-python-up-to-100 万次-cython-vs-numba/
  2. 张,j,冈萨雷斯,e,赫斯提洛,t,哈斯金斯,w,黄,y(2009)。液相色谱-质谱联用中的峰值检测算法综述。当代基因组学10 (6),388。
  3. http://Stephan hoyer . com/2015/04/09/numba-vs-cy thon-how-to-choose/

从读者的角度来看, Joseph Bloom 感谢他对本文非常有用的反馈。

让熊猫快速工作

原文:https://towardsdatascience.com/making-pandas-work-fast-35104cafa6b4?source=collection_archive---------33-----------------------

用摩丁让熊猫手术更快

照片由萨夫Unsplash 上拍摄

在我们的数据科学之旅中,我们一定都遇到过熊猫。它是最常用的 python 库之一,有助于执行各种操作,如解析数据、创建数据可视化、执行统计操作等。

但是,如果我们处理大型数据集,Pandas 可能会有点慢,它需要时间来加载数据并对其执行操作。那么,对于大型数据集,我们如何让它更快呢?我们可以使用开源 python 库 Modin 来加速熊猫库。

在这篇文章中,我们将探讨如何使用摩丁,并将其与熊猫进行比较。

让我们开始吧…

安装所需的库

我们将从使用 pip 安装一个 Modin 开始。下面给出的命令可以做到这一点。

!pip install modin[dask]

导入所需的库

在这一步,我们将导入所需的库,Pandas 和 Modin,因为我们将比较它们加载数据集所用的时间。

import modin.pandas as mpd
import pandas as pd

比较熊猫和摩丁

在这一步中,我们将使用 Pandas 和 Modin 加载数据集,以比较两者所用的时间。为此,您可以使用任何数据集。我用了著名的糖尿病数据集。

%%time
df1 = pd.read_csv("/content/Diabetes.csv")

熊猫(来源:作者)

%%time
df2 = mpd.read_csv("/content/Diabetes.csv")

摩丁(来源:作者)

您可以看到,Modin 在加载数据集时花费的时间更少,同样,它在执行所有其他操作时也会节省时间。

继续尝试不同的数据集,并使用 Modin 执行 pandas 操作,节省时间。如果您发现任何困难,请在回复部分告诉我。

本文是与皮尤什·英加尔合作完成的。

在你走之前

感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。

用 Python 制作出版物质量的图形(第一部分):图形和轴

原文:https://towardsdatascience.com/making-publication-quality-figures-in-python-part-i-fig-and-axes-d86c3903ad9b?source=collection_archive---------7-----------------------

python-可视化-教程

如何自己完全理解和控制所有的绘图参数

迈克尔·泽兹奇Unsplash 上拍摄的照片

在这整个系列中,我将与你分享我通常是如何用 Python 制作出版质量的数字的。我想真正传达如何完全控制 python 情节中的每个元素的想法。本教程结束时,你将能够完全理解用 Python 制作图形的哲学。

因为这将是一个巨大的话题,我决定把它分成几个部分。在本教程的第一部分中,我将把重点放在第一步——理解你将要绘制的画布( Fig object )和每个图形的边界( Ax object )。在接下来的教程中,我将带你了解如何制作你所熟悉的各种图形(如散点图、箱线图、热图等)。

  1. 教程 I: Fig 和 Ax 对象
  2. 教程二:线图、图例、颜色
  3. 教程三:箱线图、条形图、散点图、直方图、热图、色彩图
  4. 教程四:小提琴剧情,树状图
  5. 教程 Seaborn 的图(聚类热图、pair 图、dist 图等)

所有代码和附加信息可在:https://github.com/frankligy/python_visualization_tutorial获得

我们开始吧!

顺便提一下,有几个 python 绘图包,像 matplotlib、seaborn、plotly 等。我想展示 matplotlib 中的所有技术,因为它是最底层的库,学习 matplotlib 可以让你完全理解所有的细节。我们将在本教程的最后谈到 seaborn,在那里您可以看到这个高级库的好处。然而,学习任何东西都没有捷径,如果你想制作出版物质量的数字并完全控制我们正在制作的数字,matplotlib 是我所能建议的最佳选择。

了解 matplotlib 全局参数

首先,让我们加载必要的包,不要害怕,我经常感到不知所措看到人们加载十个不同的包,我不知道他们是什么。你基本上加载 matplotlib 包,我们要用的武器。然后是 maplotlib 包中的一个子包 pyplot ,这只是为了方便。最后,我们需要使用另一个子包 ticker 中的一些有用的函数,这些函数将用于我们定制轴的刻度。所以你看,你真的只是用 matplotlib,没什么复杂的!

# load package
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator,FormatStrFormatter,MaxNLocator 

在我们开始绘图之前,我想介绍一下 matplotlib 的一些全局设置,它有很多你的图形元素的默认设置,比如字体类型,字体大小,刻度等等。因此,了解这一点是非常重要的,同样,本文的目的是向您展示如何充分理解每个细节。

您可以按如下方式访问全局参数:

a = list(mpl.rcParams.keys) # just a dictionary
len(a)
# 305

如您所见,共有 305 个全局参数,让我们来看一看:

...
axes.grid
axes.grid.axis
axes.grid.which
axes.labelcolor
axes.labelpad
axes.labelsize
axes.labelweight
axes.linewidth
axes.prop_cycle
axes.spines.bottom
axes.spines.left
axes.spines.right
...

完整列表可在我的 github 页面获得:https://github . com/frank ligy/python _ visualization _ tutorial/blob/main/RC params . txt

如果有一些参数您希望所有后续图形都遵循,您可以通过简单地更改这个庞大的 python 字典的值来随时调整任何参数。

我发现更改如下设置很有用,原因是当我们制作出版物质量的图形时,我们有时会使用 Adobe Illustrator 进行最终格式化,默认字体类型在 Adobe Illustrator 中无法识别,所以我将它们更改为 42 号。另外,在学术上,我们更喜欢使用“Arial”字体,所以我也改了。

mpl.rcParams['pdf.fonttype'] = 42
mpl.rcParams['ps.fonttype'] = 42
mpl.rcParams['font.family'] = 'Arial'

您的画布(Fig 对象)

现在让我们创建一个画布:

fig = plt.figure(figsize=(10,6))

默认的 figsize 是(6.4,4.8)英寸,记住 6.4 英寸是宽度,4.8 英寸是高度。它也可以通过以下方式访问:

mpl.rcParams['figure.figsize']
# [6.4, 4.8]

让我们看看不同 figsize 的效果,我使用 Pycharm 作为我的 python 编程 IDE,它会立即弹出一个画布窗口,这样你就可以清楚地看到不同之处:

(左侧尺寸)默认的体形尺寸,(右侧)增大的体形尺寸

好了,这就是你要画数字的画布。让我们开始在画布上画一个图形,每个单独的图形将是一个 ax 对象,我们可以通过指定图形的(左,下,宽,高)来创建一个 Ax,当你看到结果时就很清楚了,

fig = plt.figure(figsize=(10,6))ax = plt.axes((0.1,0.1,0.5,0.8))

该图形由其锚点、左下角(0.1,0.1)和大小参数(0.5,0.8)定位

让我们看看这个元组的值,(0.1,0.1)意味着这个图形的左下角位于整个画布的这个坐标(0.1,0.1),整个画布将在范围(0,1)内。然后(0.5,0.8)确定宽度将为 0.5,高度将为 0.8。搞定了。

操纵 Ax 对象

首先,我想摆脱这个人物的脊椎,我找到 ax.spines 对象,并设置它们不可见。

fig = plt.figure(figsize=(10,6))
ax = plt.axes((0.1,0.1,0.5,0.8))ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['top'].set_visible(False)

去掉四根刺

你看,它们都不见了,现在你可以清楚地看到,一个图形是由四个刺、记号和标签组成的。这是我想在这里传达的信息。

接下来,我们要使用 x 轴刻度和刻度标签,我使用 tick_params 函数将所有参数设置为我想要的值。

fig = plt.figure(figsize=(10,6))
ax = plt.axes((0.1,0.1,0.5,0.8))
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['top'].set_visible(False)ax.tick_params(axis='x',which='major',direction='out',length=10,width=5,color='red',pad=15,labelsize=15,labelcolor='green',
               labelrotation=15)

玩 x 轴刻度和刻度标签

这里发生了什么?首先,我增加了每个 x 记号的长度和宽度,然后我将 x 记号的颜色改为红色。我增加了 x 记号与它们对应的标签之间的间距,然后我改变了标签的大小和颜色,最后我将标签逆时针旋转了 15 度。我没有动 Y 轴,所以你可以清楚地看到我调整了什么。同样,我希望你能完全控制 python 图形中的每个元素。

除了改变格式,你还可以改变刻度和刻度标签本身,我们使用 set_xticks()函数和 set_xticklabels 函数来实现,见下图效果:

fig = plt.figure(figsize=(10,6))
ax = plt.axes((0.1,0.1,0.5,0.8))
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.tick_params(axis='x',which='major',direction='out',length=10,width=5,color='red',pad=15,labelsize=15,labelcolor='green',
               labelrotation=15)ax.set_xticks([0.2,1])
ax.set_xticklabels(['pos1','pos2'])

更改 x 刻度和 x 刻度标签的内容

接下来,让我们简要介绍一个稍微高级一点的话题,我们上面尝试的都是大分笔成交点,如果你想在每个大分笔成交点间隔之间添加小分笔成交点呢?我们将使用 set_minor_locator()函数,以及开始时从 ticker 子包中导入的 locator()对象。基本上,Locator()确定记号的位置,Formatter()确定记号的格式。这里我们用 Y 轴来证明。

fig = plt.figure(figsize=(10,6))
ax = plt.axes((0.1,0.1,0.5,0.8))
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.tick_params(axis='x',which='major',direction='out',length=10,width=5,color='red',pad=15,labelsize=15,labelcolor='green',
               labelrotation=15)
ax.set_xticks([0.2,1])
ax.set_xticklabels(['pos1','pos2']) ax.yaxis.set_major_locator(MultipleLocator(0.5))
ax.yaxis.set_minor_locator(MultipleLocator(0.1))

MultipleLocator 能够在某个基数的倍数的位置创建分笔成交点,在上面的例子中,每 0.1 个单位间隔将有一个次要分笔成交点,每 0.5 个单位间隔将有一个主要分笔成交点。

在 Y 轴上添加次要刻度

您也可以使用 tick_params()函数调整次要刻度参数,只需将“which”参数指定为“minor”。

还有一堆额外的 Locator()和 Formatter()类,我想向您推荐一个解释得很好的博客:https://jakevdp . github . io/python datasciencehandb/04.10-customizing-ticks . html

最后,我想告诉你另一件操作 Ax 对象的事情,那就是添加网格线,有时这会使我们的图形看起来更好。

fig = plt.figure(figsize=(10,6))
ax = plt.axes((0.1,0.1,0.5,0.8))
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.tick_params(axis='x',which='major',direction='out',length=10,width=5,color='red',pad=15,labelsize=15,labelcolor='green',
               labelrotation=15)
ax.set_xticks([0.2,1])
ax.set_xticklabels(['pos1','pos2'])
ax.yaxis.set_major_locator(MultipleLocator(0.5))
ax.yaxis.set_minor_locator(MultipleLocator(0.1))
a=ax.yaxis.get_major_locator()
b=ax.yaxis.get_major_formatter()

ax.grid(True,which='major',axis='both',alpha=0.3)

我们使用 grid()函数,并指定我们想要基于两个轴上的主要刻度的网格线(True ),不透明度将为 0.3。

添加网格线

检查 Ax 对象

这里我要介绍一类非常重要和有用的方法,我们创建的图形(或 Ax 对象)基本上是一个 python 对象,我们可以通过定义访问它的所有属性。有时,我们需要这些信息来完全控制我们的图形生成过程。

你可以使用 get 方法来实现,你基本上可以得到我们刚刚玩过的每一个元素。例如,我想获得 x 轴刻度和刻度标签。

fig = plt.figure(figsize=(10,6))
ax = plt.axes((0.1,0.1,0.5,0.8))
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.tick_params(axis='x',which='major',direction='out',length=10,width=5,color='red',pad=15,labelsize=15,labelcolor='green',
               labelrotation=15)
ax.set_xticks([0.2,1])
ax.set_xticklabels(['pos1','pos2'])
ax.yaxis.set_major_locator(MultipleLocator(0.5))
ax.yaxis.set_minor_locator(MultipleLocator(0.1))
a=ax.yaxis.get_major_locator()
b=ax.yaxis.get_major_formatter()
ax.grid(True,which='major',axis='both',alpha=0.3)

c = ax.get_xticks()
d = ax.get_xticklabels()

我们使用了 get_xticks()和 get_xticklabels()函数,并将返回的对象存储在两个变量 c 和 d 中。

print(c)
# [0.2 1\. ]
print(d)
# [Text(0.2, 0, 'pos1'), Text(1.0, 0, 'pos2')]

有道理,对吧?我希望到目前为止,你对 python Fig 和 Ax 对象感觉更舒服。实际上,我并没有告诉你如何做出漂亮的图形,但是我给了你一个工具包,你可以用它来做出你想要的任何图形。

一张画布上的多个图形

我们经常会遇到这样的情况,我们想在一块画布上制作多个图形。一种方法是像上面那样,通过指定 Ax1 对象的位置元组来手动创建 Ax1 对象,然后一次又一次地对 Ax2 对象做同样的事情。有时候这样做是个好办法。但是,如果你想在一个 9 x 7 的网格中生成 63 个图形,我们该如何实现呢?

我们可以使用 plt.subplots()函数,

fig,axes = plt.subplots(nrows=4,ncols=4,figsize=(10,6))

在这里,我建立了一个 4 x 4 的网格,并指定 figsize。我们来看看效果:

一张画布上的多个图形

你看到这画布有什么问题了吗?每个图之间有很多重叠,你可以通过增加图的尺寸或者减小标签的字体来解决这个问题,但是我提供了一个更好的方法。

fig,axes = plt.subplots(nrows=4,ncols=4,figsize=(10,6),gridspec_kw={'wspace':0.5,'hspace':0.5})

我基本上告诉 python 在两个图形之间留一些空间,wspace 是水平间隙,hspace 是垂直间隙。我们来看看效果:

多个图形被很好地分开

好了,我现在就知道这些。我希望现在你能更好地使用 python 来设计和创建你自己的图形。如果将来我发现有趣的技巧和窍门来分享,我可能会给这个故事添加新的内容。另外,请继续关注我的后续教程,我们将深入研究如何制作每一种图形。不要犹豫问我问题。所有的代码都在这里:https://github.com/frankligy/python_visualization_tutorial

如果你喜欢这些教程,请在 medium 上关注我,非常感谢你的支持。在我的 TwitterLinkedIn 上联系我,也可以问我你想学习如何简洁地画哪种图形,我会回复你!

继续阅读

教程二:线图、图例和颜色

教程三:箱线图、条形图、散点图、直方图、热图、色彩图

教程四:小提琴剧情,树状图

教程 V:Seaborn 的图(聚类热图、对图、距离图等)

用 python 制作出版物质量的图形(第二部分):线图、图例、颜色

原文:https://towardsdatascience.com/making-publication-quality-figures-in-python-part-ii-line-plot-legends-colors-4430a5891706?source=collection_archive---------12-----------------------

python-可视化-教程

学习如何绘制线图,理解图例和颜色

照片由Cookie PomUnsplash 上拍摄

这是我的 python 可视化教程的第二篇文章:制作出版物质量的图形。以下是我到目前为止已经发表并将很快发表的文章列表:

  1. 教程一:Fig 和 Ax 对象
  2. 教程 II:线形图、图例、颜色
  3. 教程三:箱线图、条形图、散点图、直方图、热图、色彩图
  4. 教程四:小提琴剧情,树状图
  5. 教程 Seaborn 的图(聚类热图、pair 图、dist 图等)

如果您还没有查看教程 I,我建议您在阅读本文之前先查看一下。然而,如果你已经很好地理解了什么是图形和轴对象,可以跳过第一部分。

在本文中,我将以线图为例向您展示:

  1. 关于线图你需要知道的每一个元素。
  2. 涵盖了 matplotlib 颜色的一部分知识。(将在后面的教程中继续讨论)
  3. 了解图例是什么以及如何控制它们。

同样,所有的代码都可以在我的 GitHub 页面上找到:https://github.com/frankligy/python_visualization_tutorial

事不宜迟,我们开始吧!

我会把所有的内容串成一个简单的线条图。首先,我们将加载 matplotlib 包,并稍微更改一下全局设置,以确保字体类型和字体系列是我们想要的,如果这是我想了解的更多信息,请查看第一篇教程

此外,我将为绘制线图做一点准备,只需创建一些随机数据x,y1,y2 来绘制图形。

绘制线条图

与其他图相比,折线图可以说是最简单的图,它将帮助我们展示数据的动态趋势,并帮助读者比较几个类别之间的内在差异。上面,我创建了一个数组x和两个响应数组y1y2。现在让我们首先通过使用ax.plot()基本函数绘制y1与变量x的关系。

fig = plt.figure(figsize=(10,6))
ax = fig.add_axes([0.1,0.1,0.5,0.8])ax.plot(x,y1) 

你会有一个非常基本的线图:

基本线图

然后让我们再次开始玩一些参数,我会向你解释每个参数的意思,以及如何理解它们。但首先,让我们看看效果:

fig = plt.figure(figsize=(10,6))
ax = fig.add_axes([0.1,0.1,0.5,0.8])ax.plot(x,y1,   # data
marker='o',     # each marker will be rendered as a circle
markersize=8,   # marker size
markerfacecolor='red',   # marker facecolor
markeredgecolor='black',  # marker edgecolor
markeredgewidth=2,       # marker edge width
linestyle='--',            # line style will be dash line
linewidth=3)          # line width 

修改的线图

现在我们来思考一下,线状图是由什么构成的?它是一系列标记和一条线,对吗?因此,当我们调整线形图的外观时,我们将首先调整标记的外观,包括标记样式、标记大小、标记表面颜色、标记边缘颜色、标记边缘宽度。然后让我们移动到线条,我们可以调整线条样式和线条宽度。为了帮助您理解这一过程,我们提出了这样一个问题:为什么我们最初在默认设置下绘制的基本图看起来像这样?

要回答这个问题,我们需要再次检查rcParams 全局设置。

mpl.rcParams['lines.marker']  #None
mpl.rcParams['lines.markersize']  #6.0
mpl.rcParams['lines.linewidth']   # 1.5

我们会看到,默认情况下,不会有任何标记样式,所以你没有看到任何标记,但一条蓝线。默认情况下,标记大小为 6.0,现在我们将其放大到 8.0。默认的线宽是 1.5,现在是 3.0。

我希望现在我们会对线条图更加熟悉,并且知道如何控制它,因为我们已经了解了它的所有构成。会有一个快捷参数叫做fmt代表格式化字符串,fmt='ro-'相当于marker='o',markerfacecolor='red',linestype='-'。但是,我再次建议通过明确地指定它们来完全理解每个参数所代表的内容。

完事了吗?当然不是,但这是我接下来材料的第一步。

颜色和“zorder”

接下来,让我们在刚刚画出的第一条线的上面画第二条线。

fig = plt.figure(figsize=(10,6))
ax = fig.add_axes([0.1,0.1,0.5,0.8])
ax.plot(x,y1,marker='o',markersize=8,markerfacecolor='red',markeredgecolor='black',markeredgewidth=2,linestyle='--',linewidth=3)ax.plot(x,y2,marker='o')

用橙色绘制另一个线图

让我问你两个问题:

  1. 现在橙色线在蓝色线的上面,这是由我们画这两条线的顺序决定的。但是,如果我希望我的蓝线向我们移动,即使它不是我们画的最后一条线,该怎么办呢?

2.我们没有指定第二个图的颜色,为什么渲染成橙色?

让我们首先解决问题 1。为了实现这一点,我们需要使用zorder参数。它决定了哪条线(艺术家对象)将被首先画出,zorder越高,这条线将被画得越晚,因此它将更靠近我们。现在让我们把蓝线的zorder增加到 3。

fig = plt.figure(figsize=(10,6))
ax = fig.add_axes([0.1,0.1,0.5,0.8])
ax.plot(x,y1,marker='o',markersize=8,markerfacecolor='red',markeredgecolor='black',markeredgewidth=2,linestyle='--',linewidth=3,zorder=3)ax.plot(x,y2,marker='o')

(左)前面的图,(右)我们将蓝线的“zorder”增加到 3

对于第二个问题,我们将稍微涉及一下 python 的颜色。基本上,matplotlib 根据全局设置rcParams['axes.prop_cycle']确定第二行的颜色为橙色,列表如下:

cycler('color', ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf'])

如您所见,有十种颜色,如果您连续绘制 10 条线,每条线将被分配到该颜色列表中基于颜色的索引。

默认情况下,第一行会采用第一个十六进制颜色“#1f77b4”,为蓝色,第二行自然会采用第二个“#ff7f0e”,为橙色。现在有意义了,对吧?但是让我给你展示更多关于颜色系统的东西。

我不打算向你解释整个色彩理论,例如,互补色图式等等。因为我不是这方面的专家,我也不想假装是。但这里有一些我做数字时遵循的提示,经验法则是,

在分类变量中,您需要选择对比明显的颜色,例如蓝色和橙色。

在连续变量中,比如热图,你最好选择连续色图(cmap)来反映它们的关联性。

因此,在线图中,我们希望反映不同线条之间的差异,我建议您在大多数情况下坚持使用 python 默认的颜色系统,因为它们使用的颜色确实有非常强烈的对比效果,就像我上面显示的蓝色和橙色。您可以通过使用十六进制符号来表示每种颜色,并且您可以使用如下方式将每个十六进制符号转换为(红色、绿色、蓝色)元组:

mpl.colors.to_rgb('#1f77b4')
#(0.12156862745098039, 0.4666666666666667, 0.7058823529411765)

在 Maplotlib 中,它也有一些表示颜色的快捷方式,有 8 个内置的单字母颜色(b-blue,g-green,r-red,c-cyan,m-magenta,y-yellow,k-black,w-white)和一个 tableau 调色板,与我们刚刚打印出来的设置rcParams['axes.prop_cycle']相同。此外,还有一堆颜色可以通过特定的名称访问,如“橙色”,完整列表显示在此https://matplotlib . org/3 . 1 . 0/gallery/color/named _ colors . html

请查看它们,更好地了解 maplotlib 中的颜色系统。总之,无论何时你想告诉 maplotlib 用某种颜色画任何东西,你都可以选择:

  1. 十六进制符号(我建议保存一份你读过的论文中你发现它们的颜色令人印象深刻的颜色列表,或者你可以通过打印出rcParams['axes.prop_cycle']来使用 python 默认的 tableau 调色板)
  2. 单字母快捷键,仅适用于 8 种内置类型
  3. 可以通过字符串对象访问的其他颜色,如“橙色”。

对于连续和离散的色彩图,当我们绘制散点图或热图时,我会涉及到它,因为我相信当你实际使用它并看到它的效果时,它会更有意义。但现在,我希望你能更好地理解如何选择颜色,并理解不同的颜色表示,当涉及到分类/定性变量时。

传说

我们仍将使用这个线图示例来说明如何向 python 图添加图例。最简单的方法是在蓝线和橙线中添加一个标签参数。然后我们调用函数ax.legend(),它会自动检测这两行和对应的标签信息。

fig = plt.figure(figsize=(10,6))
ax = fig.add_axes([0.1,0.1,0.5,0.8])ax.plot(x,y1,marker='o',markersize=8,markerfacecolor='red',markeredgecolor='black',markeredgewidth=2,
linestyle='--',linewidth=3,zorder=2,label='blue line')
ax.plot(x,y2,marker='o',label='orange line')ax.legend()

自动添加图例

然而,这种方法并不能帮助我们理解它实际上是如何工作的。因此,我将向您展示如何明确地向图形添加图例。

ax.legend()该函数接受两个参数,handleslabelshanles将是一个存储 matplotlib Artist对象的列表。我们刚刚画的蓝线将是一个Artist对象,橙色线也是。labels将是一个列表,存储与您要分配给handles列表中每个Artist对象的标签相对应的字符串对象。我们首先需要从我们刚刚画的图中提取出Artist对象。

p1 = ax.plot(x,y1,marker='o',markersize=8,markerfacecolor='red',markeredgecolor='black',markeredgewidth=2,
        linestyle='--',linewidth=3,zorder=3)p2 = ax.plot(x,y2,marker='o')

我使用两个变量p1p2来存储 ax.plot()函数返回的数据。让我们检查这两个变量:

print(p1)
#[<matplotlib.lines.Line2D object at 0x1822957f0>]
type(p1)
# <class 'list'>
type(p1[0])
# <class 'matplotlib.lines.Line2D'>

你看,p1 将是一个只有一个元素的列表,我们通过 p1[0]访问这个元素,p1[0]将是一个 Line2D 对象,这是一个Artist对象,我们可以传递给 ax.legend()函数。p2[0]也是如此。

现在让我们明确地添加图例:

fig = plt.figure(figsize=(10,6))
ax = fig.add_axes([0.1,0.1,0.5,0.8])
p1 = ax.plot(x,y1,marker='o',markersize=8,markerfacecolor='red',markeredgecolor='black',markeredgewidth=2,
        linestyle='--',linewidth=3,zorder=3)
p2 = ax.plot(x,y2,marker='o')ax.legend(handles=[p1[0],p2[0]],labels=['blue line','orange line'])

显式添加图例

我将总是使用后一种方法,因为这是 ax.legend()函数实际工作的方式。同样,快捷方式是方便的,但是理解这些机制可以帮助您实现简单快捷方式无法实现的目标。

现在我想挑战一下自己,向你展示一下传奇实际上是 python 情节中的一个独立元素。这一次,我们将不会从刚刚绘制的线图中提取Artist对象。相反,我将从头开始创建handles

单独图例添加

在这里,我实际上没有绘制线条,只是使用 ax.plot()函数得到两个句柄,h1h2,它们将用于添加图例。现在你知道了,事实上传奇是你可以随意改变的东西。

最后,我将与你分享另一个完全控制图例的技巧,那就是调整它的位置和外观。

ax.legend(handles=[p1[0],p2[0]],
labels=['blue line','orange line'],
loc='upper left',
bbox_to_anchor=(1,1))

我添加了两个额外的参数,这意味着,使用图例的左上角作为一个锚点,并将这个锚点放置到 ax 坐标(1,1),记住这里整个 ax 对象将在范围(0,1)内。现在让我们看看效果,然后一切都有意义了:

调整图例框的位置

如果你想去掉图例框的框架并给图例添加一个标题,我们可以这样做:

ax.legend(handles=[p1[0],p2[0]],
labels=['blue line','orange line'],
loc='upper left',
bbox_to_anchor=(1,1),
title='legend',
frameon=False)

只需添加两个参数,titleframeon。搞定了。

修改图例框的外观

好了,这就把我们带到了本教程的结尾,我希望它能以某种方式帮助你。我的目标是真正帮助你理解 maplotlib 绘制过程的底层细节。明白了这一点,你就可以使用这些技巧来设计你自己的形象,有时审美偏好因人而异,但我打算与你分享一些技术机制,通过这些机制,你可以使用你最喜欢的审美风格来构建自己的情节。

如果你喜欢这些教程,请在 medium 上关注我,我将教你如何在 matplotlib 中制作小提琴图和树状图,非常感谢你的支持。在我的 TwitterLinkedIn 上联系我,也请问我关于你想学习如何以简洁的方式绘制哪种图形的问题,我会回复!

所有代码都可以在https://github.com/frankligy/python_visualization_tutorial获得

继续阅读

教程三:箱线图、条形图、散点图、直方图、热图、色彩图

教程四:小提琴剧情,树状图

教程 Seaborn 的图(聚类热图、pair 图、dist 图等)

用 Python 制作出版物质量的图形(第三部分):箱线图、条形图、散点图、直方图、热图、彩色图

原文:https://towardsdatascience.com/making-publication-quality-figures-in-python-part-iii-box-plot-bar-plot-scatter-plot-407fa457449?source=collection_archive---------25-----------------------

实践教程

带您了解如何理解这些广泛使用的图形类型背后的机制

米利安·耶西耶Unsplash 上拍摄的照片

这是我的第三篇教程,这里列出了我以前所有的帖子和我即将发布的帖子:

  1. 教程一:Fig 和 Ax 对象
  2. 教程二:线图、图例、颜色
  3. 教程 III:箱线图、条形图、散点图、直方图、热图、色彩图
  4. 教程四:小提琴剧情,树状图
  5. 教程 Seaborn 的图(聚类热图、pair 图、dist 图等)

我为什么做这个教程?你有什么理由需要把宝贵的时间花在阅读这篇文章上?我想分享一下学习 matplotlib 的最重要的事情,就是理解每种类型图形的构建模块,以及如何完全控制它们。有了这款 undersood,你可以轻松构建出你喜欢的任何图形,无论它有多复杂。我会用非常虚拟的例子来夸大情节中的每个元素,以便让你感受到每个元素在哪里,它们是如何布局的。

我制作本教程的第二个动机是我想向你展示如何阅读 matplotlib 文档。仅仅通过阅读我的教程或任何一个单独的教程是不可能学会 matplotlib 的,(不要相信任何题为“5 分钟学会 XXX”的文章),但我想与你分享当你有问题时你应该去哪里查找资源。如何快速找到你正在寻找的解决方案?

如果这符合你的需求,那么这就是适合你的文章。

所有的代码都可以在 https://github.com/frankligy/python_visualization_tutorial 买到

箱线图

当您制作箱线图时,您基本上输入一维数组的序列,每个数组的分布将由一个方框表示,该方框显示数据的中值、25%分位数、75%分位数以及上限(q3 + 1.5*IQR)和下限(Q1–1.5 * IQR)。

# load packages
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np# prepare some data
np.random.seed(42)
data1 = np.random.randn(100)
data2 = np.random.randn(100)
data3 = np.random.randn(100) fig,ax = plt.subplots()
bp = ax.boxplot(x=[data1,data2,data3],  # sequence of arrays
positions=[1,5,7],   # where to put these arrays
patch_artist=True).  # allow filling the box with colors

基本箱形图

一个盒子由一个盒体(中间的矩形)、须(垂直线)、帽(水平帽)、中线(橙色线)、传单(离群标记)组成。如何控制所有人?

ax.boxplot()函数将返回一个 python 字典,该字典如下所示:

{'whiskers': [<matplotlib.lines.Line2D object at 0x16b113748>, <matplotlib.lines.Line2D object at 0x16b1136a0>, <matplotlib.lines.Line2D object at 0x16b22b978>, <matplotlib.lines.Line2D object at 0x16b22b2b0>, <matplotlib.lines.Line2D object at 0x16145f390>, <matplotlib.lines.Line2D object at 0x16145f7f0>], 'caps': [<matplotlib.lines.Line2D object at 0x16b1bee10>, <matplotlib.lines.Line2D object at 0x16b1c7358>, <matplotlib.lines.Line2D object at 0x1961afd30>, <matplotlib.lines.Line2D object at 0x1961afb00>, <matplotlib.lines.Line2D object at 0x16b4672b0>, <matplotlib.lines.Line2D object at 0x153ea0eb8>],

'boxes': [<matplotlib.patches.PathPatch object at 0x1614793c8>, <matplotlib.patches.PathPatch object at 0x16b3acc18>, <matplotlib.patches.PathPatch object at 0x16b399b00>], 'medians': [<matplotlib.lines.Line2D object at 0x1546fb5f8>, <matplotlib.lines.Line2D object at 0x1960db9b0>, <matplotlib.lines.Line2D object at 0x153ea0518>], 'fliers': [<matplotlib.lines.Line2D object at 0x16b1e3ba8>, <matplotlib.lines.Line2D object at 0x1960f9fd0>, <matplotlib.lines.Line2D object at 0x161476898>], 
'means': []}

它准确地存储了您想要修改的所有Artist元素。这里是关键的部分,例如,boxes键下有三个PathPatch物体,它们对应上面图中的三个箱体。每个箱体将是一个PathPatch对象。(如果你没有指定patch_artist = True,它们将是Line2D对象)。这是我想说明的一点——学习和理解 matplotlib 的正确方法是理解每个元素是什么对象。图中显示的每个美学元素都有一个指向它的底层 python 对象。每个底层 python 对象都拥有自己的方法和属性,这是我们需要掌握的知识,以便能够随意修改情节。

不知道PathPatch对象是什么,也不知道Line2D。所以我通过谷歌搜索找到了这些文件:

https://matplotlib . org/3 . 1 . 1/API/_ as _ gen/matplotlib . patches . path patch . html

他们告诉我这个对象有一个有效的属性叫做facecolor,所以我点击这个属性,并找到如何将它设置为不同颜色的方法。

https://matplotlib . org/3 . 1 . 1/API/_ as _ gen/matplotlib . patches . patch . html # matplotlib . patches . patch . set _ face color

现在我知道我只需要使用set_facecolor功能来调整我所有箱体的正面颜色。然后,基本上对盒状图中的所有元素做同样的事情,如下所示:

for flier in bp['fliers']:    # outliers
    flier.set_markersize(9)
    flier.set_marker('v')
for box in bp['boxes']:     # box bodys
    box.set_facecolor('green')
    box.set_edgecolor('black')
    box.set_linewidth(2)
for whisker in bp['whiskers']:   # whisker line
    whisker.set_linewidth(5)
for cap in bp['caps']:     # cap line
    cap.set_color('red')
    cap.set_linewidth(10)
for median in bp['medians']:   # median line
    median.set_linewidth(15)

改良箱线图

我故意把这个图形做成虚拟的,以突出每个独立的元素。这是方块图的组成部分,现在明白了,难道你不能做出任何你想要的方块图吗,你可以!

并且一定要定期查看文档,这是掌握 matplotlib 的必经之路。

柱状图

同样的哲学也适用于我将在这里讲述的所有其他情节。对于柱状图,你基本上告诉他们我想画一个带有某个height的柱状图,我会把柱状图放在某个position上。除此之外,他们只是一些审美调整。

fig,ax = plt.subplots()
ax.bar(x=[1,4,9],   # positions to put the bar to
height=(data1.max(),data2.max(),data3.max()),  # height of each bar
width=0.5,   # width of the bar
edgecolor='black',   # edgecolor of the bar
color=['green','red','orange'],    # fill color of the bar
yerr=np.array([[0.1,0.1,0.1],[0.15,0.15,0.15]]), # 
ecolor='red',
capsize=5)

条形图

同样,条形图的构建块就是这么简单,然后请确保查看条形图的文档:

https://matplotlib . org/3 . 3 . 3/API/_ as _ gen/matplotlib . axes . axes . bar . html

柱状图

直方图是显示单个数组分布的图,它将显示数组中有多少元素落入每个面元中。所以你只要给他们一个数组,它就会给你画一个直方图,就是这样。

fig,ax = plt.subplots()
ax.hist(x=[data1,data2],bins=20,edgecolor='black')

柱状图

分享一点经验,我一直发现 ax.hist()函数的默认bin数没那么好看,把bin设置成一个大的数字可能会产生更好的视觉效果。然后添加一个黑边也可以帮助它。

提醒一下,请参考他们的官方文档了解更多信息:

https://matplotlib . org/3 . 3 . 3/API/_ as _ gen/matplotlib . axes . axes . hist . html

散点图

散点图被广泛使用,它显示点在 2D 平面甚至三维平面中的分布。这里我们只关注 2D 的情节。想法是,对于一系列的点,你准备四个与存储所有点的数组长度相同的向量:

x数组中所有点的 x 坐标

y数组中所有点的 y 坐标

s数组中所有点的大小

c数组中所有点的颜色

然后就可以开始出图了。

fig,ax = plt.subplots()
ax.scatter(x=[1,2,3],y=[1,2,3],s=[100,200,300],c=['r','g','b'])

简单但完整的散点图

现在,我需要介绍一下色图的知识,请允许我暂时离题。到目前为止,我们只处理离散的颜色,像这里,我们有红色,蓝色和绿色。有时,我们希望颜色在相邻颜色非常相似的意义上是连续的,我们希望利用颜色的这种相似性来传递一些重要的信息,即这两点之间的相似性。

我们需要连续的颜色,也就是彩色地图。Matplotlib 有很多彩色地图,请在这里查看:

https://matplotlib . org/3 . 1 . 0/tutorials/colors/colormaps . html

你真正需要做的是简单地选择一个颜色图,默认的颜色图叫做viridis,但是你可以指定它为例如autumn

让我们看看它在另一个散点图示例中是如何工作:

fig,ax = plt.subplots()
ax.scatter(x=np.arange(10),
y=np.arange(10)+5,
s=np.arange(10)*10,
c=np.random.rand(10),  # make sure c is numeric value
cmap='spring')

使用彩色地图的散点图

确保这里的c需要是一系列数值,所以函数将映射这些浮点值,例如[0.1,0.2,0.3…]来绘制一系列的颜色图,这样你就给每个点分配了相应的颜色。

检查散点图文档,不要忘记!

https://matplotlib . org/3 . 3 . 3/API/_ as _ gen/matplotlib . axes . axes . scatter . html

彩色地图

在这一节中,我们将更深入地研究颜色图。有两种经常遇到的情况:

  1. 我想使用一个连续的颜色图来给我的连续变量分配颜色,例如,热图,散点图等。
  2. 我想提取一定数量的颜色来表示我的离散变量,例如,我有 18 类对象,我需要给它们分配颜色,使它们的差异可以很容易被人眼分辨出来。

第一种情况相对简单,大多数时候你需要做的只是指定一个“cmap”字符串,比如“viridis”或“autumn”。第二种情况可能有点复杂。

如果您想要的颜色数量少于 10 种,您可以使用rcParams[axes.prop_cycle]中默认的 10 种颜色:

cycler('color', ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf'])

或者你可以从任何定性的彩色地图中提取:

如果要<12 colors:

import matplotlib.pyplot as plt
from matplotlib.colors import to_hex,to_rgb,to_rgbaa = [to_hex(i) for i in plt.get_cmap('Set3').colors[:12]

This is what we get:

['#8dd3c7',
 '#ffffb3',
 '#bebada',
 '#fb8072',
 '#80b1d3',
 '#fdb462',
 '#b3de69',
 '#fccde5',
 '#d9d9d9',
 '#bc80bd',
 '#ccebc5',
 '#ffed6f']

If you want < 20 colors, just change “Set3” to “tab20”, “tab20b” or “tab20c” where 20 colors are available to choose.

Heatmap

What is a heatmap? Heatmap is basically mapping a 2D numeric matrix to a color map (we just covered). So the input is a 2D numeric array, that’s it.

fig,ax = plt.subplots()
ax.imshow(np.random.randn(5,5),cmap='Set1')

Basic heatmap

Most often, I need to add a grid line and text onto the basic heatmap, I already taught how to add a grid line in 教程一:Fig 和 Ax 对象

fig,ax = plt.subplots()
ax.imshow(np.random.randn(5,5),cmap='Set1')
ax.set_xticks(np.linspace(0.5,3.5,4))
ax.set_yticks(np.linspace(0.5,3.5,4))
ax.tick_params(axis='both',length=0,labelsize=0)
ax.grid(b=True,which='major',axis='both',color='black')

带网格线的热图

最后,在 matplotlib 中,你可以通过ax.text()灵活地在图形上添加文字,你只需要指定你想写下的位置/坐标,然后告诉它你想写什么,简单吧?

fig,ax = plt.subplots()
ax.imshow(np.random.randn(5,5),cmap='Set1')
ax.set_xticks(np.linspace(0.5,3.5,4))
ax.set_yticks(np.linspace(0.5,3.5,4))
ax.tick_params(axis='both',length=0,labelsize=0)
ax.grid(b=True,which='major',axis='both',color='black')
ax.text(-0.2,3,'hey')

向热图添加文本

结论

正如我所说,一个教程涵盖 matplotlib 的所有方面是不现实的,我还在学习。但我想“授人以鱼”,而不是“给你一条鱼”。此外,我一直认为我们应该从最简单的案例中学习一切,这就是为什么我试图用非常愚蠢的例子来涵盖基本概念。但是您应该能够使用这里介绍的技巧来绘制自己的图形。

如果你喜欢这些教程,请在 medium 上关注我,我将教你如何在 matplotlib 中制作小提琴图和树状图,非常感谢你的支持。在我的 TwitterLinkedIn 上联系我,也请问我关于你想学习如何以简洁的方式画出哪种图形的问题,我会回复的!

所有代码均可从以下网址获得:

https://github.com/frankligy/python_visualization_tutorial

继续阅读

教程四:小提琴剧情和树状图

教程五:瑟伯恩

用 Python 制作出版物质量的图形(第四部分):小提琴图和树状图

原文:https://towardsdatascience.com/making-publication-quality-figures-in-python-part-iv-violin-plot-and-dendrogram-ed0bb8b23ddd?source=collection_archive---------22-----------------------

python-可视化-教程

从头开始绘制小提琴情节和树状图,一步一步的指南

米利安·耶西耶Unsplash 上拍摄的照片

这是我的 python 可视化系列的第四篇教程,

  1. 教程一:Fig 和 Ax 对象
  2. 教程二:线图、图例、颜色
  3. 教程三:箱线图、条形图、散点图、直方图、热图、色彩图
  4. 教程四:小提琴情节,树状图
  5. 教程 Seaborn 的图(聚类热图、pair 图、dist 图等)

这次让我们做一个简短的介绍,这篇文章只是从教程三停止的地方继续。我想为 Violin 情节和 dendrogram 写一篇单独的文章的原因是,与前面介绍的情节类型相比,它们有点复杂。所以深呼吸一下,让我们深入这两个情节。

小提琴情节

Violin 图基本上采用与 box 图完全相同的输入,即一系列 1D 数组。唯一的区别是,violin 图可以显示 1D 阵列的附加信息层,即密度或分布。这条信息被涂抹在盒状图中(盒体必须是矩形的),但在小提琴图中(这个名字是如何产生的),密度信息能够被揭示出来,因为我们现在有了一个弯曲的“盒子”,或小提琴。

上一篇教程准备相同,

# load packages
import matplotlib as mpl
import matplotlib.pyplot as plt

# set global parameters
mpl.rcParams['pdf.fonttype'] = 42
mpl.rcParams['ps.fonttype'] = 42
mpl.rcParams['font.family'] = 'Arial'# prepare some data for drawing figures
import numpy as np

np.random.seed(42)
data1 = np.random.randn(100)
data2 = np.random.randn(100)
data3 = np.random.randn(100)

为了方便起见,我添加了两行代码:

dataset = [data1,data2,data3]. # the sequence of arrays
positions = [1,5,7].  # where to put those violin, the x-coordinates

现在让我们开始画小提琴的情节:

fig,ax = plt.subplots()
vp = ax.violinplot(dataset=dataset,positions=[1,5,7])

小提琴基本情节

它看起来很好,它有我们正在寻找的理想密度信息。出于探索的目的,这样做绝对没问题。但是我可能需要把它弄得漂亮一点:

  1. 审美调整:脸型颜色、线条颜色等
  2. 添加分位数,胡须到小提琴情节

对于第(1)点,这是我在教程三中所涉及的,找出每个图形元素的基础 python 对象,并通过阅读文档来查找函数以更改它们各自的美学设置。这很重要!查看方框图部分了解更多详情。

fig,ax = plt.subplots()
vp = ax.violinplot(dataset=dataset,positions=[1,5,7])

for body in vp['bodies']:
    body.set_facecolor('red')
    body.set_edgecolor('black')
    body.set_alpha(1)
vp['cmaxes'].set_color('black')
vp['cmins'].set_color('black')
vp['cbars'].set_color('black')

我们来看看效果:

修改美学元素

对于第(2)点,这是事情变得有点复杂的地方,但是不要担心,让我们一起检查一下。基本上,我们需要两个数组,一个存储分位数信息,姑且称之为tmp数组,因为它是临时数组。另一个叫做whisker数组,它是用来存储上下界的,或者叫触须。

tmp : [(q1,中值,q3),(q1,中值,q3),(q1,中值,q3)]

whisker : [(上须,下须),(上须,下须),(上须,下须)]

你看,每个元组对应一个小提琴盒。现在我们需要计算这些东西,对吗?

tmp很简单,np.percentile()函数为我们做了所有的事情,我们只是使用一个列表理解来迭代得到最终的tmp数组。

tmp = [np.percentile(data,[25,50,75]) for data in dataset]

那么对于晶须,我们来定义一个函数,逻辑很简单因为我们要计算上晶须和下晶须,需要先计算iqr,那么上晶须正好是 1.5 * IQR + q3,下晶须正好是 q1-1.5 * IQR。

def get_whisker(tmp,dataset):
    whisker = []
    for quantile,data in zip(tmp,dataset):
        data = np.array(data)
        q1 = quantile[0]
        median = quantile[1]
        q3 = quantile[2]
        iqr = q3 - q1
        upper = q3 + 1.5 * iqr
        upper = np.clip(upper,q3,data.max())
        lower = q1 - 1.5 * iqr
        lower = np.clip(lower,data.min(),q1)
        whisker.append((upper,lower))
    return whisker

记住,在这里,如果超过数据(1D 数组)的最大值,我们使用np.clip()函数来修剪upper whisker,否则它会被误导,因为如果这里没有数据点,就不应该有上须,对吗?

现在我们也有了whisker数组。

whisker = get_whisker(tmp,dataset)

然后我们将这些元素添加到小提琴的情节中:

fig,ax = plt.subplots()
vp = ax.violinplot(dataset=dataset,positions=[1,5,7])

for body in vp['bodies']:
    body.set_facecolor('red')
    body.set_edgecolor('black')
    body.set_alpha(1)
vp['cmaxes'].set_color('black')
vp['cmins'].set_color('black')
vp['cbars'].set_color('black')ax.scatter(positions,
[quantile[1] for quantile in tmp],
marker='o',color='white',s=30,zorder=3)

我们使用散点图为每把小提琴的主体放置三个中点,请查看以前帖子中的散点图部分zorder 部分

向小提琴图添加中间点

然后,我们添加 25%分位数和 75%分位数范围:

ax.vlines(positions,
[quantile[0] for quantile in tmp],
[quantile[2] for quantile in tmp],
color='black',linestyle='-',lw=5)

添加 25 和 75 分位数范围

最后,我们需要添加晶须绑定:

ax.vlines(positions,
[bound[0] for bound in whisker],
[bound[1] for bound in whisker],
color='black',linestyle='-',lw=2)

添加晶须绑定

由于我们的剪辑功能和黑线背景,这一步与上一步相比没有任何差异,为了展示它的效果,我夸大了一点,但这只是为了展示效果,你不需要那样做,只要坚持上面的一个。

ax.vlines(positions,
[bound[0] for bound in whisker],
[bound[1] for bound in whisker],
color='black',linestyle='-',lw=4)

我把线宽改成了 4,让我们看看:

夸大胡须边界范围(如果超过最小值或最大值,我们将进行剪裁)

总结一下,这里有两个技巧,我们使用zorder总是保持中间点在最前面。然后我们使用不同的linewidth来强调25%-75%分位数范围。

所有代码可从https://github.com/frankligy/python_visualization_tutorial获得

系统树图

说实话,你所在的地区可能不会遇到这种情况。但是作为一名生物信息学学生,我处理了很多聚类问题,在我的项目和日常编码中经常会遇到树状图。

我们什么时候使用树状图?

以著名的iris数据集为例,假设我们有 6 朵花,每一朵都有不同的特征,包括但不限于sepal lengthsepal widthpetal length等。它可以更正式地用一个m x n矩阵来表示,其中m代表 m 个观察值,n 代表每个观察值的 n 个特征。

让我们为此准备虚拟数据:

sample1 = np.random.randn(100)
sample2 = np.random.randn(100)
sample3 = np.random.randn(100)
sample4 = np.random.randn(100)
sample5 = np.random.randn(100)
sample6 = np.random.randn(100)

mat = np.row_stack([sample1,sample2,sample3,sample4,sample5,sample6])

matm x n矩阵。

我们感兴趣的是找出这 6 种花之间成对的相似性,哪两朵彼此更近,哪两朵最远。我们需要做层次聚类并将花分组在一起,最终,我们会得到这样的东西:

系统树图

你可以看到,这是一个树状图,它告诉你花(2)和花(3)非常相似,基本关系在上面的图中清楚地显示出来。接下来,我将向你们展示如何一步一步地得到这个树状图。

首先,我们需要做层次聚类,点击链接了解更多信息。但简单地说,在每一步中,我们将最相似的两个分组形成一个新的元样本或聚类,然后这个元样本在下一轮中也将被视为单个样本,我们仍然打算在第二轮中找到最相似的两个组。这是一种“自下而上”的方法来聚集不同的观察结果。

from scipy.spatial.distance import pdist,squareform
dense_distance = pdist(mat,'euclidean')
square_distance = squareform(dense_distance)

我们使用 scipy 中的pdist()函数来计算成对距离,它将返回一个dense_distance列表,乍一看很难理解列表中的每一项代表什么,所以我们首先将它转换成一个square_distance矩阵来建立一些直觉。

平方距离矩阵

现在我们来对比一下dense_distance列表:

print(dense_distance)
[13.76499829 14.86214799 14.67696826 14.49691937 13.35096827 15.18247523
 14.51538309 13.39787901 13.77284523 14.35555456 14.82429126 14.66308396
 13.73263062 13.82613097 13.45116341]

所以,dense_distance基本上是按照这个顺序存储两两距离的:[(0,1),(0,2),(0,3),(0,4),(0,5),(1,2),(1,3),(1,4),(1,5),(2,3),(2,4),(2,5),(3,4),(3,5),(4,5),(4,5)],这里(0,1)是指0th观测和1st观测之间的两两两距离,回忆,python 是基于 0 的索引。如果看square_distance矩阵的上三角,正好是从左向右读。

现在我们有了dense_distance列表,我们可以进行分层聚类:

from scipy.cluster.hierarchy import linkagelinkage_matrix = linkage(dense_distance,method='ward',metric='euclidean')

要了解更多关于methodmetric参数的信息,你可以查阅文档或者一些不错的博客。但是我们将得到的是另一个叫做linkage_matrix的矩阵。让我们试着去理解:

连锁矩阵

请跟随我下面的叙述,这样你就能明白它的意思了,

0th迭代中(第一行),0th观察(第一列)和5th观察(第二列)基于我们定义的methodmetric最为相似。它们之间的距离是13.35097(第三列),所以我们把它们组合在一起,形成一个新的聚类/观察6th(或者 7 号观察,python 是基于 0 的索引),因为我们已经有 6 个观察了。在新形成的集群6th (or no.7 observation)中有 2 个观察/节点(第四列)。

然后在1st iteration(第二排),同样的过程再次进行。

明白了这一点,我们只需要知道,这个linkage_matrix是绘制dendrogram的输入,那么让我们来绘制它。

from scipy.cluster.hierarchy import linkage,dendrogram
linkage_matrix = linkage(dense_distance,method='ward',metric='euclidean')fig,ax = plt.subplots()
dendrogram(linkage_matrix,ax=ax)

现在我们得到了树状图

我个人发现制作树状图的文档不是很清楚,所以我打算用简单的英语更详细地描述这个过程,以传达一个更好的直觉。

就这些,希望能有点帮助。

如果你喜欢这些教程,请在 medium 上关注我,非常感谢你的支持。在我的 TwitterLinkedIn 上联系我,也请问我关于你想学习哪种图形以及如何简洁地画出它们的问题,我会回复的!

所有代码都可在https://github.com/frankligy/python_visualization_tutorial获得

继续阅读

教程 Seaborn 的图(聚类热图、pair 图、dist 图等)

制作 Python 包第 3 部分:设计您的类

原文:https://towardsdatascience.com/making-python-packages-part-3-designing-your-classes-82b3a5786e30?source=collection_archive---------17-----------------------

为成功建立您的图书馆

你好!欢迎阅读制作 Python 包系列的第 3 部分!

高塔姆·克里希南在 Unsplash 上拍摄的照片

前两部分探索了如何打包你的代码,以及在 PyPI 上发布供公众使用

在这一部分,我们将讨论如何设置你的源代码:让你的包做一些有趣的事情的类和函数。

让我们直接开始吧。

类别和功能

如果您是一名数据科学家,您可能会花大量时间在笔记本上编写代码,或者编写一个 Python 脚本。

我们中的许多人倾向于在没有太多封装的情况下构建代码原型,只是一行一行地写我们想对我们的熊猫数据帧做的任何统计分析。

有时候你可能会写函数:也许是因为你需要给 pd 一个函数。DataFrame.apply(),或者将数据帧上的一系列类似 sql 的操作封装到一个函数中,或者将所有清理步骤封装到一个列表中。我们编写代码的风格几乎更符合函数式编程,在函数式编程中,像 Pandas DataFrame 或 list 这样的数据结构是通过一系列操作来传递的。

类似地,当我们第一次运行一些统计数据,或者用一个数据集创建一个初始的 ML 模型时,我们也倾向于不在那里写类。

但是我们当然使用类——毕竟,Python 中的一切都是对象:从字符串和整数,到列表和数据帧,到 ML 模型类和 NLP 管道。

我们很容易使用这些类对象——我们机械地记住我们可以运行。groupby()转换我们的熊猫系列。tolist(),。update()一个集合,获取。来自计数器的 most_common()。拟合()一个 ML 模型并得到它的。参数

但是,即使我们经常使用这种语法,我们也可能会忽略这样一个事实,即这些确实是某些人编写的类的方法和属性。

当我们编写自己的包时,我们需要生成相同类型的直观方法和属性。

为什么上课?

学习正确方式的最好方法是看错误方式

写 Python,Pandas,scikit-learn 和 spaCy 的那些才华横溢的人在设计他们的包的时候,为什么不直接用函数呢?

至少对于 scikit-learn 来说,我们可以想象得到一个函数,它获取你的数据并输出预测和参数。

也许类似于:

from scikit-learn import run_logistic_regressionpredictions, parameters = run_logistic_regression(data)

这有什么不好?他们为什么使用类?

接下来会发生什么?一旦这个模型被训练,我们需要一个新的函数来做进一步的预测。我们需要将这些参数传递给它。

predictions = make_logistic_predictions(data, parameters)

这有点尴尬,因为我们必须保存和传递参数。

令人尴尬的是,这两个函数没有正式的关系,尽管它们是为了拟合和使用同一个模型。

如果您运行 dir()或查看源代码,您必须在 scikit-learn 的其他模型的 1000 个其他函数列表中找到这两个相关的函数。

但这可能会变得更糟。

当它是一个决策树或神经网络的集合体——具有复杂架构的东西——时会发生什么?

predictions, parameters = run_random_forest(data)
predictions = make_random_forest_predictions(data, parameters)

如果这些参数描述了我们所有不同形状的决策树上的规则,它们会采用什么结构?在列表列表中指定树的形状有点困难。

无论如何,我不会反复强调这一点。你可以看到问题。

那么,为什么要上课呢?

因为, 一个类是状态和行为的容器。

当我们希望允许用户获取一些数据,用这些数据做一些事情并保存结果时,类是实现这一点的自然方式。

一个类可以存储信息,给我们的用户一套很好的操作,他们可以对这些信息进行操作,并为他们保存结果。

我的意思是,这真的只是面向对象编程的基本论点。但是当你写一个库的时候不要忘记它。

使用类是有意义的!

界面驱动开发

所以我们知道我们应该使用类,我们也使用过其他库的类,但是如何为你的库开发正确的类结构呢?

您编写类名、这些类中的方法和属性名,并且还没有填充逻辑。

那是你的界面。接口是一个类的蓝图。它是 API,特别是您的用户将使用的类、方法和属性。

同样的建议也适用于开发函数:首先编写输入和输出,使用函数的。只有在这之后,您才应该实现逻辑。

让我们看一个例子。

在 spaCy 中,开发人员希望对文本字符串提供 NLP(自然语言处理)。因此,他们创建了一个类,该类接受文本字符串,并生成一个对象(一个“doc”)来提供对该文本字符串的各种 NLP 分析。

从根本上说,他们的库获取输入数据通过使用一些算法和数据库对数据进行操作来创建新的信息,而使新的信息易于访问

总的来说,他们希望直观地访问新信息。

doc = nlp(my_text)
token = doc[4] #an object derived from the word at index 4
token.pos_ #outputs the part of speech of that word at index 4
  1. 他们想给你每个词的 NLP 分析。
  2. 他们希望访问一个单词(令牌)看起来像是访问一个列表元素(如果它像内置 Python 对象或熟悉的库一样工作,会更直观)
  3. 他们希望对单词(token)的 NLP 分析是简单的属性,如 word.pos_

结论

当你开发你的库时,关注你的终端用户的体验。

你想让 他们的 代码变成什么样子。 在你的自述文件中写出用例 的例子。什么会使他们的代码更直观?让他们的生活变得轻松。

概述一个提供这种体验的库:类、方法、属性。在你得到用户 体验之前,不要写逻辑。

如果你优先考虑用户,那么用户会喜欢你的图书馆!

感谢阅读!

请关注我的 Medium,了解数据科学家的更多见解!

这是本系列的第 1 部分和第 2 部分:

https://medium.com/@skylar.kerzner/publish-your-first-python-package-to-pypi-8d08d6399c2f https://medium.com/@skylar.kerzner/packages-part-2-how-to-publish-test-your-package-on-pypi-with-poetry-9fc7295df1a5

让 scikit-learn 更好地与熊猫一起工作

原文:https://towardsdatascience.com/making-scikit-learn-work-better-with-pandas-13d197e60dc9?source=collection_archive---------20-----------------------

招数

在功能转换后,再也不会丢失列名

何苦呢?

除了提供常见的机器学习算法,scikit-learn 还允许用户构建可重复使用的 管道 ,将数据处理和模型构建步骤集成到一个对象中。

iMattSmartUnsplash 上拍摄的照片。

pipeline 对象中的每一步都由一个 Transformer 实例组成,该实例公开了易于使用的fit / transform API。转换器可以对用于输入缺失值、特征工程、模型推理等的逻辑进行编码。

不幸的是, scikit-learn 直接处理 numpy 数组或 scipy 稀疏数组,而不是在数据科学工作中广泛使用的 [pandas.DataFrame](https://scikit-learn.org/stable/faq.html#why-does-scikit-learn-not-directly-work-with-for-example-pandas-dataframe)。附属于数据帧的元数据,例如列名,对于调试模型解释的目的来说非常有帮助。

我们应该如何解决上面讨论的问题?虽然 StackOverflow 像往常一样有用,但从长远来看,我更愿意使用组织良好的代码,而不是每次都要谷歌的代码片段。因此,我写了自己的代码,可以在 GitHub (笔记本这里)上找到,并在本文中展示。

[sklearn.compose.ColumnTransformer](https://scikit-learn.org/stable/modules/generated/sklearn.compose.ColumnTransformer.html)呢?

公平地说,scikit-learn 使用数据帧中的元数据有一种方式:ColumnTransformer可以通过字符串名称识别数据帧列,并将您需要的转换器指向每一列。这是 Allison Honold 在 TDS 上的一个例子。

不幸的是,ColumnTransformer产生了 numpy 数组或 scipy 稀疏矩阵。这篇文章将扩展ColumnTransformer,这样它也会产生pandas.DataFrame

用例 1:多元插补

我们可以通过子类化sklearn.base.BaseEstimatorsklearn.base.TransformerMixin来创建自己的变压器。自定义功能应该在fit(X, y)transform(X)方法中实现。

下面是一个运行中的自定义转换器。[ImputeNumericalByGroup](https://github.com/openerror/PandasTransform/blob/main/src/ImputeByGroup.py)类计算由pandas.DataFrame.groupby标识的每个组的中间值,并使用每个组的所述中间值估算新数据帧中的缺失值。

在 Titanic 数据集中证明年龄的异质性,并使用每组中位数进行估算。图片作者。

当你从领域知识中知道你的数据包含不同的组时,按组插补是合理的。下面例子中使用的泰坦尼克号幸存者数据就是一个恰当的例子:众所周知,在这艘命运多舛的豪华邮轮上,三等舱乘客往往比一等舱乘客年轻。

是— 多变量特征插补在技术上已经在 scikit-learn 中可用。但是截至 2021 年 4 月 7 日,它仍然是该库的“实验”部分,其 API 可能会发生变化。如果您喜欢类似于SimpleImputer的行为,并且需要处理数据帧,我的代码提供了一个可行的替代方案。

转换异构数据

如上所述,scikit-learn 可以通过sklearn.compose.ColumnTransformer对 DataFrame 列应用不同的转换。在这里,我提供了一个关于ColumnTransformer的包装器,这样它接收并产生一个具有正确列名的数据帧— —即使列数已经改变,例如,由于一次热编码。

我的 PandasColumnTransformer 在 scikit-learn 管道中工作,并允许我快速可视化基于大量数据训练的逻辑回归模型的系数。注意,它只用了一行代码(pd。序列等)来将每个系数归因于一个特征。图片作者。

当然,你总是可以恢复列名并且手动将它们附加到ColumnTransformer生成的数组上。但是,当像我这样的代码作为可重用的管道的一部分为你记账时,为什么还要麻烦呢?

摘要

  1. scikit-learn对于 Python 中的机器学习来说是很棒的,但是它故意提供了与熊猫有限的互操作性,熊猫是当今数据科学家的面包和黄油。
  2. 本文展示了两个自定义 scikit-learn 转换器可以在两个库之间架起桥梁的例子。数据帧中的元数据可以方便调试和模型解释。
  3. 我的 GitHub 资源库中提供了所有代码和一个示例笔记本。

理解模型和算法

原文:https://towardsdatascience.com/making-sense-of-models-and-algorithms-9f753a924092?source=collection_archive---------28-----------------------

数据科学家越来越意识到,当我们简单地将数据放入模型(无论多么强大)并在没有真正理解是什么产生的情况下使用结果时,我们面临的风险。为了限制代价高昂(甚至有害)的错误和偏见,我们需要避免众所周知的黑箱。幸运的是,TDS 作者非常擅长理解复杂的概念。这里是一些我们最近最喜欢的解释模型和算法的具体细节的帖子。

  • 了解梯度推进决策树如何工作 。在过去的几周里, Carolina Bento 耐心地带领我们走过了基于树的算法的复杂道路。在她的系列文章的最后一部分中,Carolina 探索了梯度增强决策树,将它们与其他一些流行的算法进行了比较,并展示了它们控制模型偏差的能力。
  • 更好地理解图形嵌入算法背后的数学原理 。快速随机投影(FastRP)算法——名副其实——非常快速,知道如何部署它会非常方便。CJ Sullivan 的帖子是关于其基本功能和核心数学概念的精彩入门。

照片由 Aaron BurdenUnsplash 上拍摄

  • 发现多智能体强化学习(MARL)算法背后的历史 。当我们读到机器学习的最新前沿发展时,有时很容易忘记让我们走到今天的漫长而曲折的道路。Omri Kaduri 的五部分系列从最开始就公正地讲述了 RL 的历史——第一部分集中在 A*算法(可以追溯到 1968 年)及其后续的改进迭代。
  • 采取正确的步骤给你的模型一个更好的记忆Robert kübler 博士求助于贝叶斯分层建模和 PyMC3 来解决处理未规划模型时常见的过拟合问题。结果是一个更有效的过程,防止罗伯特所谓的“模型的健忘症。”
  • 探索一个有趣而迷人的人工智能游戏项目 。如果你曾经想更好地掌握强化学习如何训练人工智能(最终)击败它们的人类创造者,请加入 Ben Williams 的行列,他将着手构建一个战锤 40k-playing 代理。在这篇文章中,Ben 搭建了舞台,奠定了基础;在以后的文章中,您将会看到这个项目的雏形。
  • 认识一位利用计量经济学技能促进社会公正的数据科学家 。如果我们不考虑它们对人类和社区的影响,最强大的算法也只能带我们走这么远,甚至会造成伤害。这是 Haaya Naushan 在最近与 TDS 的本胡伯尔曼 T21 的谈话中强有力地提出的一个观点,她还谈到了保持好奇心和开放思想的重要性,以及将一个人的数据科学之旅转变为自我发现的过程的好处。

我们喜欢从我们发布的帖子中学习新的东西,我们更喜欢与你分享它们。感谢你找到的所有支持我们工作的方式,分享我们的工作,并与我们互动。

直到下一个变量,
TDS 编辑

我们策划主题的最新内容:

入门

实践教程

深潜

思想和理论

用 Geopy 和 leav 制作酷地图

原文:https://towardsdatascience.com/making-simple-maps-with-folium-and-geopy-4b9e8ab98c00?source=collection_archive---------15-----------------------

使用 Nominatim 地理编码器将城市名称转换为点位置,并使用 leav 进行可视化

谢栋豪在 Unsplash 上的照片

这是一个由两部分组成的关于可视化城市和与他人分享您的成果的系列。对于那些“给我看看代码”的家伙来说,这是链接。以下是要涵盖的主题的顺序:

简介
重现代码
场景
代码
用 Geopandas
用树叶
用树叶做更多事情
回答提问

简介

以这篇文章为例,简单介绍一下地理编码以及分别用 geopy 和 leav 绘图。除了 geopy 之外,还有许多其他方法可以进行地理编码。有许多可用的 API,其中一些执行普通的地理编码,而另一些则帮助您从 IP 地址获取位置信息。在这里查看。对于这篇文章,我是从阅读这篇中获得灵感的。我知道有一个全 python 的方法来解决这个问题,所以我们来了。

复制代码需要什么

一台电脑(显然?🤷🏾‍♀️),你选择的 IDE,安装的 geopyshapelygeopandasmatplotlib叶子随机模块。您可以使用虚拟环境,这样这些新的包就不会与您已经安装在基础环境中的包发生冲突。选择权在你。

方案

AYK 快递公司在非洲各国首都有 11 个分支机构,每个分支机构雇用 10 至 30 人,这些分支机构都有网址。我们必须为快递公司生成一些数据,并将其可视化。公司应该在哪些国家开设新的分支机构?让我们看看如何在可视化的同时回答这个问题。

代码

GIF via giphy

用于该任务的模块被导入。创建了一个由该公司有分支机构的 11 个城市组成的列表。对于 get_coordinates 函数,它将城市名称列表作为参数。名称是使用的地理编码器,存储在地理定位器变量中。然后对列表中的每个城市进行迭代,地理编码器将它们转换成坐标值。在每次迭代结束时,坐标被保存到字典中,字典在开始时被初始化为值和城市名、关键字。 get_coordinates 函数在 city_list 上被调用并保存到 city_coords_dict。

用 Geopandas 绘图

由于我们将主要在 geopandas 中工作,它有一个绘图功能,我们可以使用它来可视化我们的城市,然后再在 follow 中绘图。使用它的一个原因是因为它对矢量数据非常有用,另一个原因是因为我们正在处理 3D 世界中的点(城市),而不仅仅是 2D 平面中的点,所以我们需要这个属性。好吧,我们开始吧!

我们为所有城市点创建了一个 shapely 点列表,并存储在一个 cities_geom 中。 d ,dict 是用城市作为关键字创建的,城市名称、值和几何关键字的形状点都存储为值。 cities_gdf 是通过将 dict、 dcrs 传递给 geopandas 的 GeoDataFrame (带有几何列的 pandas 数据帧)方法创建的,然后进行绘制。但这并不意味着什么,不是吗?它只是一些标在 2D 坐标轴上的蓝点。现在,如果将这些点标绘在非洲地图上,可视化效果将会得到改善,您可以看到这些点之间的相互关系,还可以看到没有点的国家(如果您愿意,也可以是代表)。

Geopandas 有许多可供您探索的数据集。我们将使用的是 naturalearth_lowres ,它使我们能够访问世界地图,但我们的城市都是非洲的,因此我们将提取地理数据框中所有大陆值等于非洲的行,并将其存储为 africa_gdf。然后我们再次使用绘图函数,并传递参数颜色边缘颜色,来定制我们的绘图。 plt.rcParams 允许您控制绘图的大小。为了标记非洲国家(用多边形表示),我们为每个国家找到了一定会在它们各自的多边形中找到的点(使用 代表点()。x代表点()。y )然后把标签放在那里,用标注。这里我们要做的最后一件事是断言 cities_gdf 的 crs 等于 africa_gdf 的 CRS,因为如果不是这样,我们的点数就不会落在正确的位置。

用叶子绘图

我们先用 Let 做一个简单的地图。

cities_gdf 的几何列被转换为 json( 但它自动成为 GeoJson,因为它有一个地理空间组件)。叶子。Map() 创建地图对象,该对象具有其他用于绘图的功能,如 add_child 。geojson 被传递给它,然后您就有了输出。

用叶子做更多事情

还记得我说过我们必须为分支机构生成数据吗?是啊,是时候了。我们需要这样做,这样我们就可以添加 popups 来使地图更具交互性。

除了已经存在的栏之外,还创建了新的栏(名称坐标员工数量网站】)

add_markers_to_the_map 采用一个树叶地图对象、地理数据框、颜色和图标参数。变量被创建。它存储点的坐标、名称、员工人数和网站地址。这些将用于弹出窗口。一次迭代完成后,对于存储在 points 变量中的每个点,创建 popup_text、popupmarker v 变量,并将添加到 the_map 中。

  • popup: 创建一个 popup 对象并存储 popup_text。
  • marker :定制弹出窗口,并在某个特定位置显示。前缀“fa”代表字体牛逼,里面有很多图标。

然后我们用我们选择的参数和 TA-DA 调用函数!继续使用以下命令保存您的地图:

the_map.save(‘the_map.html’)

将地图保存为 html 文件意味着它可以在网页上使用。我们将在本系列的第二部分讨论这个问题。

对提问的回答

公司应该在哪些国家开设新的分支机构?

对于这个问题,你可以考虑两个城市,计算它们之间的距离,并创建一个匀称的 LineString 。然后,你可以使用 LineString质心属性来知道那个中心点是什么。它会落在一个国家,那里有你的答案。很简单,是吧?

结论

这是一个总结!欢迎在评论中留下你的想法。快乐学习和编码。感谢阅读!😃👋

接下来:

制作异常数据库

原文:https://towardsdatascience.com/making-the-anomaly-database-d81471f9ddaf?source=collection_archive---------27-----------------------

这是与 Docker、Postgres 数据库和异常数据集相关的两篇文章的第二部分。阅读 第一部分 ,它将教你如何使用 Docker 建立一个新的 postgres 数据库。

这篇文章描述了如何填充在第 1 部分中构建的异常数据库。

动机

继续端到端可再现工作流的主题,我还希望能够以编程方式重新创建我的原始数据库。

在这项活动结束时,我能够快速加载和管理大约 6G 的数据供我个人使用。

大量数据,可使用 VSCode 快速浏览。来源:作者。

填充数据库的全部代码都在我的 GitHub repo 中。

谁应该读这个?

如果你习惯使用download.file()、系统命令、arff文件格式和{DBI},你在这里不会学到很多东西。如果你对我的方法感兴趣,请继续阅读。

步伐

这里只有三个文件:

  1. 初始设置([00-execute.R](https://github.com/rsangole/anomaly_db/blob/master/00-execute.R))
  2. 从网上下载数据([01-download-data.R](https://github.com/rsangole/anomaly_db/blob/master/01-download-data.R))
  3. 将数据加载到 PostgreSQL 中的anomaly数据库([02-load-data-to-postgres.R](https://github.com/rsangole/anomaly_db/blob/master/02-load-data-to-postgres.R))

初始设置

列表有助于跟踪数据来源,并帮助我关闭任何下载以节省空间/时间(例如,Monash 是一个大约 2G 的下载)。

一些简单的内务处理,以确保目录设置正确。此外,如果文件夹是 git 控制的,存放数据集large_data的目录需要在.gitignore中。我检查这个。

下载数据

现在,对于上面列表中的数据集,只需使用download.file()下载所选数据集的数据,并将它们移动/解压缩到large_data文件夹。我还在检查文件夹是否已经存在,我想覆盖它。

这里有一个 UCR 数据集的例子。其余数据集的代码非常相似。

加载数据

现在,它就像:

  1. 使用DBI::dbConnect连接到 PostgreSQL 数据库
  2. large_data/读取数据集
  3. 简单清理(janitor::clean_names,所有时间戳列被称为time等)
  4. 使用DBI::dbWriteTable将数据加载到 postgres 中

下面是一个示例代码:

对于 monash 数据集,你确实需要使用 [*foreign::read.arff()*](https://stat.ethz.ch/R-manual/R-devel/library/foreign/html/read.arff.html)

技巧

大文件下载将在 1 分钟的默认超时窗口内超时。在调用download.file()之前处理这个。

数据字典也可以直接存储在数据库中。我将UCR_Archive2018/*文件夹中每个README.md的内容存储在一个名为ucr_00_meta的数据字典表中。这允许我在下游开发中编程调用字典。

UCR 数据集的数据字典。来源:作者。

闪亮可以有效用于快速探索。这是一个我为自己建造的东西的例子。仪表板直接从 PostgreSQL 提取数据。UCR 元数据也从呈现在每个页面顶部的数据库中提取,从而可以快速浏览数据集。随着我添加更多数据集,我不断扩展这个仪表板。

闪亮的仪表板快速可视化数据。来源:作者。

制造“自动化科学家”:使用结构化高斯过程共同导航假说和实验空间

原文:https://towardsdatascience.com/making-the-automated-scientist-co-navigating-the-hypothesis-and-experimental-space-using-9c9e14de74c8?source=collection_archive---------42-----------------------

思想和理论

马克西姆·兹亚迪诺夫&谢尔盖·加里宁

美国田纳西州橡树岭橡树岭国家实验室纳米材料科学和计算科学与工程中心

实验科学研究是人类已知的最迷人的活动之一(至少,在作者高度主观的观点中)。我们俩都是因为相对简单的后院实验而开始了我们的科学生涯。对于第二个十几岁的作者,这是应用放热化学反应,又名自制烟花。在这里,按照教科书上的食谱制作出非凡而多彩的灯光效果是相对简单的。我们怀疑这个过程能比 J. R. R .托尔金在《魔戒》开篇描述比尔博的告别会时描述的更好,所以我们就说到这里。然而,更有趣的是理解烟花背后的氧化还原化学方程式,并利用这一知识来调整成分分数,以增强火花的产生或持续时间,或添加碱金属盐来调整光发射。换句话说,理解烟花背后的魔力,并试图利用这种理解让烟花变得更有趣。

作为第二个例子,在他的博士学位中,第一作者使用超高真空扫描隧道显微镜和密度泛函理论的结合来探索石墨烯中边缘和空位的化学修饰如何影响其电子性质[1,2]。同样,对美丽的原子尺度图像的观察只是理解石墨烯功能性的复杂物理机制的第一步。阐明它们使我们能够解决干预性和反事实的问题,即假设问题。例如,如果我们用元素周期表中某个特定原子的邻居来代替它,会发生什么?我们能找到产生所需功能的替代品吗?这些问题和许多其他问题让科学变得如此有趣。

这些是构成科学家大部分工作的科学探索连续循环的例子。我们计划实验以增强对理论机制的理解,从而改进和发展理论模型。在许多情况下,实验会产生新的结果,而这些结果在现有的框架内是无法解释的。这反过来激发了解释观察结果的新理论的发展(或质疑和检查实验方法)。从理论的角度来看,理论可以建立在一组假设或已知的法律和关系,从高度抽象的现代代数理论的建设,以新材料和化合物的计算探索。同样,在实验实现的背景下,新的和非平凡的理论预测通常是令人感兴趣的。

图一。(左)放热分解的神秘橙色粉末,在此过程中变成绿色。(右)通过扫描隧道显微镜观察到的含有缺陷的石墨烯的原子分辨率图像。作者图。

输入机器学习(ML)。机器学习有多种概述和观点,描绘了该领域的总体愿景和基础[3,4]。然而,目前绝大多数 ML 方法都是基于纯粹的相关模型——在经典的监督学习中优化特征和目标之间的相关关系的发现,或者在(变分的)自动编码器中解开数据表示。更重要的是,这些方法中的许多通常基于静态数据集,如 MNIST、CIFAR 或大型医学和生物成像数据集。请注意,从静态数据集到动态数据集(动态地包含新数据)的转换是非常重要的——并且经常会受到超出分布效应的影响。经典 ML 的这些局限性是众所周知的,在过去的几年里,关于如何解决这些问题提出了多种观点[5],包括作者的观点[6]。

部分地为了回应这些限制,在过去的几年里,ML 和物理学团体已经积极地探索 ML 和物理学的结合。例如,科学的中心前提之一是深信正确的物理定律将有优雅的数学表示。也许这个概念最好的代表是 Winer 关于“数学在自然科学中不合理的有效性”的著名的文章。相应地,将机器学习与简化的符号表示相结合开辟了一种将机器学习与物理学相结合的方法,克兰默、何、巴塔格利亚、布伦顿和库兹的最新作品就是早期的例子。

经典机器学习方法的第二个限制是它们依赖于完善的静态数据集。从某种意义上说,一旦数据完全可用,ML 部分就开始了。因此,经过训练的网络可以应用于新数据,但前提是新数据由相同的过程生成,即来自相同的分布。对于许多最大似然问题,这是通过拥有覆盖所有可能潜力的广泛训练数据集来实现的。然而,这通常是困难或不可能的,这刺激了主动学习方法的发展,其中 ML 算法与数据生成过程动态交互。这可以从简单地选择候选人进行人工标记,到玩雅达利游戏,再到运行定制的科学工具或自动汽车。

主动学习框架的经典例子是贝叶斯优化(BO)和强化学习(RL)。然而,这些框架中的大多数算法仍然是数据驱动的,依赖于动作、状态和奖励之间的相关性。相应地,这些算法通常需要相对大量的数据(到目前为止,RL 比 BO 更多)来建立政策和结果之间的相关关系。请注意,应用于实验或理论的贝叶斯优化和强化学习方法的许多最新进展都是基于纯粹的相关方法[7–9,10,11]。最近,一些小组开始探索结合物理模型和主动学习的方法,或者是在参数模型的经典贝叶斯推理[12]的背景下,或者是更灵活的结构化高斯过程。然而,在大多数情况下,物理模型是相对刚性的。

这个简短的概述解决了一个自然的问题,即物理发现和主动学习是否可以整合到一个单一的框架。在这种假设驱动的主动学习中,或简称为假设学习,算法查询假设空间和实验空间,具有选择和提炼理论以及驱动实验协议的双重目标。在这里,我们假设这是可能的,并介绍了一个 hypoAL 算法,允许实现这一点。

当我们有一系列可能的模型作为替代假设时,我们考虑最简单的发现形式。我们假设只有一个模型是正确的。每个模型都有几个参数。我们假设可以定义参数值的先验,这些参数值代表了我们对感兴趣系统的一些了解。这里的想法是,一个正确的系统行为模型会导致系统整体贝叶斯不确定性的快速降低。然而,在每个模型上运行完整的贝叶斯推理(BI)并选择具有最低不确定性的模型在计算上是昂贵的并且非常耗时的(随着新测量的增加,成本和时间迅速上升)。因此,我们的算法只有一个短暂的“预热”阶段,我们对每个模型进行 BI,选择一个在所有未测量点上具有最低总不确定性或中值不确定性的模型,并根据预定义的奖励函数奖励该模型。在这之后,我们利用标准的ϵ-贪婪策略在每一步只对一个模型进行采样。将根据样本模型的贝叶斯后验计算的总/中值不确定性与前一步骤中记录的总/中值不确定性进行比较。如果不确定性降低,样本模型会得到正奖励,否则会受到惩罚(负奖励)。然后,下一个测量点被导出为xₙₑₓₜ=arg max(u),其中 U 是由采样模型产生的不确定性“图”。整个 hypoAL 算法总结如下。

HypoAL 算法协同导航实验和假设空间

让我们用一个具体的例子来说明 hypoAL 算法,这个例子与物理学中的相变有关,相变表现为一个可测量系统属性(例如热容)的不连续性。相应的(合成)数据如图 2 所示,其中 x 轴是可调参数(温度、浓度等)。)和 y 轴是通过实验测量的系统属性。

图二。描述具有不连续“相变”的 1D 系统的合成数据。作者提供的数字。

请注意,图 2 中的完整数据(“噪声观察”)永远不会被算法看到。相反,我们从少量(本例中为 3 个)“种子”测量开始,以初始化 hypoAL 算法。该算法包含系统行为的三种可能模型:

模型 1 在转变点之前具有幂律行为,在转变点之后具有线性行为,

模型 2 在转变点之前和之后具有线性行为,

模型 3 在转变点前后具有幂律行为。

我们可以将它们用作独立的概率模型,或者将它们包装到结构化的高斯过程中。我们选择了后者,因为它提供了更多的灵活性,并且可以更好地处理没有一个模型是正确的情况(参见我们之前的帖子)。

在所有这三个模型中,我们在转变点的可能位置上放置一个统一的先验(意味着我们不假设对它可能发生的确切位置有任何了解),并在其余参数上放置正态先验。

下面以动画的形式展示了 hypoAL 学习。它显示了由在每个步骤采样的模型执行的重建、相关的不确定性、获取函数(这里相当于中值不确定性)以及每个模型的运行样本平均回报。

图三。hypoAL 应用于具有不连续“相变”的 1D 系统。作者提供的数字。

在该过程中考虑重构函数和获取函数的行为是有益的。我们选择的假设函数在连续区域中的功能行为不同,跳跃的位置和大小也不同。按照惯例,采集函数(此处对应于未测量点上的 s GP 不确定性)定义了算法对参数空间不同区域的“感兴趣程度”,采集函数的 argmax 定义了进行下一次测量的点。很明显,模型的选择和获取函数的行为是紧密耦合的,该函数寻找不连续的位置。此外,请注意,包含不连续点的位置最初被错误地发现,但随着新观测值的累积,算法已收敛于地面真实值。

主动学习期间贝叶斯不确定性的演变如图 4 所示。该算法倾向于第三种模型,其中系统在转变点之前和之后的行为由幂律函数描述(并且,因为我们使用了具有已知基本事实的合成数据,所以我们知道这是正确的模型)。

图 4。主动学习期间中值不确定性的演化(Uₘ在 hypoAL 算法中)。每个模型的最终样本平均奖励显示在图图例中。作者提供的数字。

图 5 还显示了使用 hypoAL 发现的点对三个模型的整个参数空间进行贝叶斯拟合的结果。获得最高奖励的模型显然是最合适的。因此,我们能够仅使用少量测量来学习由不连续函数产生的正确数据分布,并且还识别描述系统行为的正确模型。

图五。利用海波发现的点,贝叶斯符合三种不同的模型。每个模型的最终样本平均奖励也显示在支线剧情标题中。作者提供的数字。

通过对种子点的不同初始化以及其他不连续函数进行运行,该算法的可重复性和鲁棒性得到了的证实

到目前为止,我们主要关注我们的算法发现系统行为的正确模型的能力,但它也在整体执行时间和重建精度方面比使用单一概率模型的主动学习策略提供了实际优势(如之前的文章所述,使用标准 GP 的主动学习不太适合不连续的函数,因此这里根本不考虑)。我们注意到,理想的情况是将 s GP 与系统行为的已知/正确模型(本例中为模型 3)一起使用。然而,在实践中,这几乎是不可能的。在图 6 中,我们比较了主动学习与部分正确的独立概率模型(AL-Model 1 和 AL-Model 2)和 hypoAL 之间的重建误差和执行时间。hypo al明显优于这两种型号。它的执行时间也与使用正确模型(AL-Model 3)的主动学习相当,有趣的是,它始终能产生略好的重建。

图 6。对于相同的贝叶斯推理设置,使用独立概率模型(AL-模型 1、AL-模型 2、AL-模型 3)和 hypoAL 的主动学习的效率。请注意,模型 3 是完全正确的模型,模型 2 和模型 1 是部分正确的模型。y 轴对应于平均绝对误差。作者提供的数字。

总之,通过这里开发的 h ypoAL 算法实现的假设学习方法提供了与科学家工作的多个相似之处。该算法顺序查询黑盒数据生成过程,有效地执行实验。基于测量结果和感兴趣系统的一些部分知识,如编码在可能的模型列表和它们参数的先验分布中,算法探索哪个模型更好地解释了观察结果,并试图根据它解释数据的程度奖励正确的模型——就像科学家会做的那样。同样,就像以人为基础的研究一样,先验知识很重要。如果先验是正确且狭窄的(即,我们对系统了解很多),它将极大地加速算法的收敛,如果先验是广泛的(我们知道的不多,但有开放的头脑),它将收敛到正确的模型,如果先验是狭窄且不正确的(我们有错误的先入为主的观念),则可能导致非常缓慢的进展。

虽然当前的示例非常简单,并且依赖于模型和地面实况的分析函数,但是扩展到更复杂的模型、更高维度的空间等是相当简单的。在这种情况下,将变得开放的问题包括,我们如何对待高维行为,以及在何种程度上低维嵌入可以与简单的函数形式相结合。类似地,对于大维理论空间,我们需要通过图形或 NLP 编码有效地枚举理论的途径,避免在功能空间中禁止性的枚举搜索。这也与探索政策的选择有关,标准的ϵ——贪婪只在低维空间中是足够的(在低维空间中没有那么多做错事的方法)。但这恰恰是这个方向令人兴奋的地方!

继最初的在《未知的已知》上发布之后,我们的一位读者分享了伊本·亚明(https://onejourney.net/ibn-yamin-quotes/)的另一部波斯诗歌杰作,他说

谁不知道呢

不知道自己不知道,

是个傻瓜——避开他。

不知者不晓,

并且知道自己不知道,

是个孩子——教他。

谁知道呢,

不知道自己知道,

他睡着了,叫醒他。

谁知道呢,

并且知道他知道,

明智——跟随他。

我们希望贝叶斯方法联合导航假设和自动化实验空间可以成为未来几年的发展方向之一。最后,在科学界,我们感谢我们的研究赞助商。这项工作在橡树岭国家实验室纳米材料科学中心(CNMS)进行并得到支持,该中心是美国能源部科学用户设施办公室。您可以使用此链接进行虚拟漫游,如果您想了解更多信息,请告诉我们。

更多细节/结果,请查看我们在 arxiv 上的预印本和 GitHub 上相应的代码

参考文献

1.齐亚特迪诺夫,m;藤井,s;KusakabeKiguchit .莫里;Enoki,《单一石墨层中单空位-氢复合物的直接成像》。物理复习 B 2014、 89 (15)、155405。

2.齐亚特迪诺夫,m;林,h;藤井,s;KusakabeKiguchit .伊诺克;在石墨烯扶手椅边缘化学诱导拓扑零模式。理化。化学。Phys. 2017, 19 (7),5145–5154。

3.纽约州勒村;纽约州本吉奥;深度学习。性质 2015, 521 (7553),436–444。

4.神经网络中的深度学习:概述。神经网络。 2015, 61 ,85–117。

5.schlkopf,b;洛卡泰洛,女;鲍尔;柯;北卡罗来纳州卡尔施布伦纳;Goyal,a。迈向因果表征学习。IEEE 会议录 2021, 109 (5),612–634。

6.瓦苏德万;齐亚特迪诺夫,m;弗尔切克湖;现成的深度学习是不够的,需要节俭、贝叶斯和因果关系。npj 计算机公司。脱线。 2021、 7 (1)、6。

7.瓦苏德万;凯利,K. P。欣克尔,j。Funakubo,h;杰西;加里宁公司;扫描探针显微术和光谱学的自主实验:选择在哪里探索铁电体的极化动力学。 ACS Nano 2021, 15 (7),11253–11262。

8.加里宁公司;瓦莱蒂,m;瓦苏德万;Ziatdinov,m,《通过基于高斯过程的探索发现功能和结构的晶格哈密顿量的探索——利用》。 J. Appl. Phys 2020, 128 (16),164304。

9.克鲁尔,a。美国好施集团;罗泽尔特区;席夫林,a。人工智能驱动的扫描探针显微镜。通信物理 2020, 3 (1),54。

10.白银,d;黄;马迪森,首席法官;Guez,A 西弗尔湖;范登德里斯切;Schrittwieser,j;安东诺格鲁岛;Panneershelvam,v。Lanctot,m;迪耶曼公司;格雷韦博士;Nham,j;北卡罗来纳州卡尔施布伦纳;苏茨基弗岛;Lillicrap 利奇,硕士;Kavukcuoglut .格雷佩尔;Hassabis 博士,利用深度神经网络和树搜索掌握围棋游戏。性质 2016, 529 (7587),484-+

11.Mnih,v;Kavukcuoglu 白银,d;鲁苏公司;Veness,j;贝勒马尔;格雷夫斯,a。里德米勒,m;菲吉兰,又名:奥斯特洛夫斯基;彼得森;贝蒂角;萨迪克;安东诺格鲁岛;h .金;库马兰博士;威斯特拉博士;莱格公司;通过深度强化学习进行人类水平的控制。性质 2015, 518 (7540),529–533。

12.麦克丹尼尔。佛朗泽克,m。萨维齐;多塞特,硕士;罗德里格斯,E. Ek .默兹;Opsahl-Ong,j;萨马罗夫;竹内岛;通过基于物理学的贝叶斯主动学习实现中子衍射的即时自主控制。 arXiv 预印本 arXiv:2108.089182021。

控制中的不当学习

原文:https://towardsdatascience.com/making-the-case-for-improper-learning-in-control-bb5c5e1692b0?source=collection_archive---------19-----------------------

一个众所周知的 ML 技术正在改变强化学习和控制理论

罗伯特·尼克森在 Unsplash 上的照片

历史上,控制系统是这样建立的:首先使用熟知的模型,如线性二次调节器(LQR)或列表马尔可夫决策过程(MDP),来近似受控系统(或“设备”),然后为这个假定的模型设计(近)最优控制器。这种方法非常有效,从保持飞机漂浮到防止化工厂爆炸,经典控制理论支持的众多应用领域证明了这一点。事实上,这些领域的研究已经产生了一个现成的设计原则和经验法则的仓库,可以毫不费力地生成一个显示可容忍性能的控制器菜单。

这种经典方法提供的另一个优势是产生的控制策略的可解释性——它们直观上令人满意并且有意义。这就是为什么简单的线性反馈控制器和阈值策略在如此长的时间里仍然是控制理论的支柱,尽管在性能上还有很大的改进空间。相比之下,你将很难向外行人解释,例如,你最喜欢的深度神经网络的 500,000 个权重实际上“意味着什么”,尽管它“有效”。

然而,由于现代控制应用的复杂性或对更快的部署和更好的性能的不断增长的需求,这种方法可能会大大低于预期。例如,缺乏理解的系统——以及由此产生的错误指定的模型——可能会导致实际中控制器的过拟合和欠匹配。或者用这些方法接近最优所需的数据量可能会对性能和部署速度产生不利影响。因此,像自动驾驶车辆和机器人团队这样复杂的系统的出现,现在要求我们对控制的基本问题进行范式转变。

Brian McGowan 在 Unsplash 上拍摄的照片

像自动驾驶车辆和机器人团队这样复杂的系统的出现,现在要求我们在看待控制的基本问题的方式上进行范式转变。

在这种新的情况下,一种新兴的通用强化学习(RL)方法似乎是采用给定的、预先设计的“基本”(或“原子”)控制器集合的组合,这(a)允许灵活地组合给定的控制器,以获得比原子策略更丰富的策略(我们将互换地使用术语“策略”和“控制器”),同时(b)可以保留给定控制器类的基本结构,并赋予所得到的混合策略高度的可解释性。这里,我们使用术语策略的通常含义,即,为工厂的每个状态输出一个动作的映射。

什么是不当学习?在机器学习的说法中,给定一类控制器(或假设或分类器,视情况而定),从可用的算法中严格挑选的算法被称为合适的学习器,从(潜在地)给定类之外输出的算法被称为不合适的学习器【2】。一个简单的例子是使用有限的一组 N 线性预测器,即 N 权重向量的分类问题。在这种情况下,(训练后)总是从给定的 N 个预测器中选出最佳预测器的学习算法将被称为合适的学习器。或者,该算法可以从这个集合的凸包中输出最好的,然后将被称为不适当的学习器。多年来,虽然不当学习(IL)在统计和在线学习社区中受到了一些关注,但它在很大程度上仍未得到控制。因此,这篇文章的目的之一是让研究者和实践者注意到这项技术是一个有前途的和及时的研究方向。

统计学习。不当学习已经侵入了统计学习领域,其结果非常明显地令人鼓舞。一个明显的例子是增强的技术,在【5】的分类上下文中进行了彻底的探索。著名的 AdaBoost 算法现在已经适用于从分类到算法交易的机器学习的每一个可以想象的应用领域,甚至为其发明者赢得了 2003 年的 G o del 奖。最近,例如,在[3]的监督学习的背景下,调查了模型错误设定的问题,这也表明,即使在使用不正确的参数模型时,不正确的学习者的后悔表现也有显著改善(正确的学习者表现更差)。类似地,最近在4中调查了使用 T10 逻辑回归 T11 的有限时间后悔问题,其中,后悔表现再次通过利用不当学习得到显著改善。请注意,在这两种情况下,学习者只需扩展其搜索,以包括可用的原子预测器的凸组合。

控制中学习不当。不当学习开始受到控制群体的关注,并且已经可以观察到两种不同的方法。第一种[6]遵循上述范例,使用(非自适应)控制策略的基本类或原子类以及自适应元学习器,该自适应元学习器组合这些策略的输出,以产生性能严格优于基本类的不适当控制器。事实上,[6]也展示了稳定控制器从一组不稳定的原子控制器中出现的例子。重要的是,不合适的控制器仅通过基础控制器与受控系统交互,即它在每一轮中选择一个基础控制器,该控制器进而对系统实施其控制动作。从自适应算法中产生的控制策略不需要与每个系统状态的任何基本策略精确匹配,因此显然是不合适的。

另一方面,第二种方法[1]实质上是将增压的概念扩展到控制。这包括维护一组“弱学习”算法的实例(例如在线梯度下降)。弱学习者被认为是自适应的,并向非自适应助推器提供控制建议。反过来,助推器将这些建议组合成一个控制动作,在受控系统上实施。与之前相同的逻辑表明了为什么强化者可以被认为是一个不合适的学习者。但是请注意,这里的架构本质上与[6]中的架构相反——控制器是非自适应的,直接与系统交互。

向前移动。虽然这些初步尝试看起来很有希望,但仍有很大的改进空间。例如,上面描述的两种架构是仅有的两种可能吗?对于给定的应用程序,有没有一种原则性的方法来选择基类?在理论方面,关于后悔界限和收敛速度的问题比比皆是。如何将这一理论扩展到包含多个学习代理的情况?因此,许多非常基本的理论和实践问题仍然是开放的,并为研究人员提供了激动人心的机会,以推动这一新兴控制领域的发展。

关键词:不当学习,强化学习,Boosting,MetaRL,AdaBoost。

参考文献

[1]纳曼·阿加瓦尔、纳塔利·布鲁希姆、埃拉德·哈赞和周露。助力控制动力系统。机器学习国际会议,第 96–103 页。PMLR,2020 年。

[2]维基百科贡献者。分布学习理论 —维基百科,免费百科. https://en . Wikipedia . org/w/index . PHP?title =分配 _ 学习 _ 理论,2020。

[3]约翰·杜奇、安妮·马斯登和格雷戈里·瓦兰特。关于预测问题中的错误设定和通过不当学习的鲁棒性。arXiv 预印本 arXiv:2101.05234,2021。

4Dylan J . Foster、Satyen Kale、Haipeng Luo、Mehryar Mohri 和 Karthik Sridharan。逻辑回归:不当的重要性。学习理论会议,第 167-208 页。PMLR,2018。

[5]罗伯特·沙皮雷和约夫·弗罗因德。助推:基础与算法。麻省理工学院出版社。, 2013.

[6]穆罕默迪·扎基、阿维·莫汉、阿迪蒂亚·戈帕兰和阏氏·曼诺尔。基于梯度的策略优化学习不当。arXiv 预印本 arXiv:2102.08201,2021。

用 Milvus 制作:小米手机浏览器内的人工智能新闻推荐

原文:https://towardsdatascience.com/making-with-milvus-ai-powered-news-recommendation-inside-xiaomis-mobile-browser-18e41d112c5f?source=collection_archive---------32-----------------------

了解小米如何利用人工智能和 Milvus 构建智能新闻推荐系统,能够为其移动网络浏览器用户找到最相关的内容

普里西拉·杜·普里兹在 Unsplash 上的照片

从社交媒体反馈到 Spotify 上的播放列表推荐,人工智能已经在我们每天看到和互动的内容中发挥了重要作用。为了使他们的移动网络浏览器与众不同,跨国电子制造商小米建立了一个人工智能新闻推荐引擎。专门为相似性搜索和人工智能构建的开源向量数据库 Milvus 被用作该应用的核心数据管理平台。这篇文章解释了小米如何构建其人工智能新闻推荐引擎,以及如何使用 Milvus 和其他人工智能算法。

使用人工智能来建议个性化内容并消除新闻噪音

仅《纽约时报》一家每天就发布超过 230 篇内容,如此庞大的文章量让个人无法全面了解所有新闻。为了帮助筛选大量内容,并推荐最相关或最有趣的作品,我们越来越多地转向人工智能。尽管推荐还远非完美,但机器学习对于从我们日益复杂和互联的世界中涌出的源源不断的新信息越来越有必要。

小米制造并投资智能手机、移动应用、笔记本电脑、家用电器和许多其他产品。为了使该公司每个季度销售的 4000 多万部智能手机中预装的移动浏览器与众不同,小米在其中内置了一个新闻推荐系统。当用户启动小米的手机浏览器时,人工智能用于根据用户搜索历史、兴趣等推荐类似内容。Milvus 是一个开源的向量相似性搜索数据库,用于加速相关文章的检索。

AI 驱动的内容推荐是如何工作的?

其核心是,新闻推荐(或任何其他类型的内容推荐系统)涉及将输入数据与大规模数据库进行比较,以找到相似的信息。成功的内容推荐包括平衡相关性和及时性,并有效地整合大量新数据—通常是实时整合。

为了适应海量数据集,推荐系统通常分为两个阶段:

  1. 检索:在检索过程中,根据用户兴趣和行为,从更广泛的库中缩小内容范围。在小米的移动浏览器中,从包含数百万篇新闻文章的海量数据集中选择了数千条内容。
  2. 排序:接下来,将检索时选择的内容按照一定的指标进行排序,然后推送给用户。当用户使用推荐内容时,系统会实时调整以提供更相关的建议。

新闻内容推荐需要基于用户行为和最近发布的内容实时进行。此外,推荐内容必须尽可能符合用户兴趣和搜索意图。

Milvus + BERT =智能内容建议

Milvus 是一个开源的向量相似性搜索数据库,可以与深度学习模型集成,以支持跨自然语言处理、身份验证等应用。Milvus 对大型矢量数据集进行索引,使搜索更加高效,并支持各种流行的 AI 框架,以简化开发机器学习应用程序的过程。这些特性使该平台成为存储和查询矢量数据的理想选择,矢量数据是许多机器学习应用程序的关键组件。

小米选择 Milvus 来管理其智能新闻推荐系统的矢量数据,因为它快速、可靠,并且需要最少的配置和维护。然而,Milvus 必须与人工智能算法配对,才能构建可部署的应用程序。小米选择了 BERT(双向编码器表示转换器的缩写)作为其推荐引擎中的语言表示模型。BERT 可以用作通用 NLU(自然语言理解)模型,它可以驱动许多不同的 NLP(自然语言处理)任务。其主要特点包括:

  • BERT 的 transformer 用作算法的主要框架,能够捕捉句子内部和句子之间的显式和隐式关系。
  • 多任务学习目标、掩蔽语言建模(MLM)和下一句预测(NSP)。
  • BERT 在处理大量数据时表现更好,并且可以通过充当转换矩阵来增强其他自然语言处理技术,如 Word2Vec。

米尔乌斯和伯特一起工作。图片作者。

BERT 的网络架构采用多层变压器结构,摒弃了传统的 RNN 和 CNN 神经网络。它的工作原理是通过其注意力机制将任意位置的两个单词之间的距离转换为一个,并解决了 NLP 中持续了一段时间的依赖问题。

BERT 中一个变压器的网络架构。图片作者。

伯特的网络结构。“Trm”代表上述变压器网络架构。图片作者。

BERT 提供了一个简单的和一个复杂的模型。对应的超参数如下:BERT 基:L = 12,H = 768,A = 12,总参数 110MBERT LARGE: L = 24,H = 1024,A = 16,参数总数为 340M。

上述超参数中,L 表示网络的层数(即变压器块的个数),A 表示多头注意中的自我注意数,滤波器大小为 4H。

小米的内容推荐系统

小米基于浏览器的新闻推荐系统依赖于三个关键组件:向量化、ID 映射和近似最近邻(ANN)服务。

矢量化是将文章标题转换成一般句子向量的过程。小米的推荐系统采用的是基于 Bert 的 SimBert 模型。SimBert 是 12 层模型,隐藏大小为 768。Simbert 使用训练模型 Chinese L-12_H-768_A-12 进行连续训练(训练任务为“公制学习+UniLM”),已经使用 Adam 优化器在单个泰坦 RTX 上训练了 117 万步(学习速率 2e-6,批量大小 128)。简单来说,这是一个优化的 BERT 模型。

人工神经网络算法将矢量化的文章标题与存储在 Milvus 中的整个新闻库进行比较,然后为用户返回相似的内容。ID 映射用于获取相关信息,如相应文章的页面浏览量和点击量。

内容推荐是如何工作的。图片作者。

存储在 Milvus 中的数据为小米的新闻推荐引擎提供动力,这些数据不断更新,包括额外的文章和活动信息。当系统包含新数据时,旧数据必须被清除。在该系统中,在第一个 T-1 天进行完全数据更新,在随后的 T 天进行增量更新。

在定义的时间间隔,旧数据被删除,T-1 天的处理数据被插入到集合中。在这里,新生成的数据被实时合并。一旦插入新数据,就会在 Milvus 中进行相似性搜索。检索到的文章再次按照点击率和其他因素进行排序,并将排名靠前的内容显示给用户。在这样一个数据频繁更新并且必须实时提供结果的场景中,Milvus 快速整合和搜索新数据的能力使得在小米的移动浏览器中大幅加速新闻内容推荐成为可能。

Milvus 使向量相似性搜索变得更好

对数据进行矢量化,然后计算向量之间的相似度,是最常用的检索技术。基于人工神经网络的向量相似性搜索引擎的出现极大地提高了向量相似性计算的效率。与类似的解决方案相比,Milvus 提供了优化的数据存储、丰富的 SDK 和分布式版本,大大减少了构建检索层的工作量。此外,Milvus 活跃的开源社区是一个强大的资源,可以帮助回答问题和解决出现的问题。

如果您想了解更多关于向量相似性搜索和 Milvus 的信息,请查看以下资源:

让你的数据科学简历脱颖而出

原文:https://towardsdatascience.com/making-your-data-science-resume-stand-out-119d2eb37d8c?source=collection_archive---------16-----------------------

保持简历简洁具体的小贴士

Unsplash 上由罗恩·迪亚拍摄的照片

想象一下,作为一名数据科学家职位的招聘经理或招聘人员。这些职位往往会有大量的申请——数据科学很热门,竞争也很激烈,尤其是在初级水平上。你可能每周,甚至每天都有上百份简历。

对这一大堆简历的决定必须迅速做出,因为没有太多的时间可以花在每一份简历上。你希望能够迅速决定这份简历是否可以被安全地拒绝,或者是否值得面试。

简历被安全拒绝的信号是什么?通常缺乏特定的所需技能

是什么让一份简历脱颖而出?许多不同的事情都可以,但候选人最容易控制的是有相关经验

这导致在制作简历时要遵循两条主要规则:

  1. 简洁。为了确保没有任何重要的信息被埋没或丢失,争取一份更短的简历。只提重要的东西。让找到所需技能和相关经验变得容易。
  2. 特异性。你对自己具体从事的工作描述得越清晰,简历审查员就会越清楚地看到与工作的联系,即使你自己在申请时看不到这种联系。

这两个特征在整个简历中都很重要,但我认为在技能部分简洁尤为重要,在描述经历和项目时清晰尤为重要。

技能部分的简洁

Branko StancevicUnsplash 上拍摄的照片

通常,技术简历会有一个技能部分,数据科学简历也不例外。你想确保列出了重要的技能,但又不想列出太多。这就是简洁最重要的地方。

在实验室里使用了某种晦涩难懂的蛋白质测序技术。除非你申请的生物信息学公司使用这种或类似的技术,否则不要考虑它。

增加额外的技能不仅意味着你很难找到重要的东西,还会让你看起来对重要的技能不够专业。列出与该职位直接相关的内容,不要太多。

这感觉很糟糕——列出更少的技能可能会让人觉得你在低估自己。但是保持你的简历简洁是很重要的,并不是你拥有的所有技能都是相关的。

通常,您可能希望列出两种技能:

  1. 标准数据科学技能。这可能取决于你从事的数据科学类型或行业,但通常这可能包括 Python (Pandas、sklearn、numpy)、统计学(A/B 测试、实验设计)、机器学习和 SQL 等。
  2. 与角色直接相关的技能。他们提到 AWS 了吗?如果有 AWS 经验,列举出来。如果你有使用其他云平台的经验,把它列为你最相关的技能。如果他们认为没有重要到可以列为一项要求,问问自己是否重要到可以列为一项技能。

项目/经验的清晰性

照片由乔·什切潘斯卡Unsplash 拍摄

人们在描述过去的工作时犯的最大错误之一是过于抽象。

相反,尽量让具体化

将经验具体化可以让你更容易发现与招聘经理需要完成的项目的相似之处。这种相似性可能源于所使用的工具、项目的主题或数据的类型。你不知道那些相似点可能在哪里,所以最好尽你所能,尽可能的具体明确。

这里我就拿自己的建议,举个例子,把事情具体化。

不好:“分析客户支出”

我在简历上看到过这种或者类似的模糊表述。问题是,这可能意味着构建复杂的统计模型和生成解释客户行为的高质量可视化,也可能意味着查看别人构建的仪表板中的一些图表。

有两种简单的方法来增加特异性:

  1. 明确项目的投入和产出是什么
  2. 提及项目中使用的工具

项目的投入和产出

给出一个项目的投入和产出,有助于读者理解项目的形态。尝试回答以下问题:使用了什么类型的数据?结果如何?

将这些细节添加到上面的语句中,我们可能会得到如下语句:

好一点的是:“分析客户交易数据,了解不同产品的销售情况”

这给出了输入(客户交易数据)和输出(大概是关于不同产品销售的某种报告/可视化)的概念。

我们正在努力,但是仍然不清楚在输入和输出之间发生了什么。如果不变得太罗嗦,很难给出一幅完美的图片来描述这些“洞见”是什么。但是为了帮助充实这些细节,我们可以谈谈所使用的工具。

项目中使用的工具

增加细节的最简单方法可能是谈论你使用的具体工具。如果我熟悉这些工具,它会生动地描述所做的事情。

具体来说:“分析客户交易数据,了解不同产品的销售情况。使用的工具:Pandas、Scipy、matplotlib "

这额外的五个单词增加了大量的额外信息。

因为我知道 pandas、scipy 和 matplotlib 都是做什么的,所以您只需添加几个词,就为我描绘了一幅非常生动的项目图。Pandas 告诉我可能有一些数据争论,scipy 告诉我可能有一些统计测试,matplotlib 告诉我有一些可视化。这也告诉我你使用了 Python,并且在探索数据和解决实际问题时足够得心应手。

即使你觉得你使用的工具并不“令人印象深刻”,我也宁愿知道一个项目是在 Excel 中完成的,而不是被困在猜测实际完成了什么。列出一个“不起眼”的技能,或者一个我不熟悉的技能,只会让我忽略项目的这一部分,就像我没有使用工具一样。

当简洁和具体发生冲突时

正如上面的例子所显示的,简洁和具体之间存在一些矛盾。为了增加具体性,它通常意味着添加额外的单词。

像生活中的所有事情一样,需要一点平衡。但是不要害怕砍掉那些不令人印象深刻或不相关的项目。

关于写简历,我得到的一些最好的建议是,简历上的内容的平均质量,而不是质量的总和,这很重要。拿出你最强的一面——不要用不必要的东西冲淡你所有的好工作。**

请记住:保持简短,保持具体。

相关文章

** [## 为什么大多数数据科学组合项目没有得到招聘经理的认可

towardsdatascience.com](/why-your-data-science-portfolio-project-sucks-208ee830ad1b) **

首次提交 Kaggle

原文:https://towardsdatascience.com/making-your-first-kaggle-submission-36fa07739272?source=collection_archive---------5-----------------------

这是一本简单易懂的指南,指导你如何开始比赛,如何成功地建模和制作你的第一份作品。

照片由戴恩·托普金Unsplash 拍摄

在数据科学的世界里,使用 Kaggle 几乎是必须的。你用它来为你的项目获取数据集,查看和学习那些希望看到你成功建立良好的机器学习模型的人慷慨分享的各种笔记本,发现如何处理复杂的机器学习问题的新见解,这样的例子不胜枚举。

在现实世界中尝试你的技能的最好方法之一是通过网站上举办的比赛。泰坦尼克号竞赛是最有益的、对初学者友好的入门方式,可以让他们很好地了解会发生什么,以及如何以最好的方式解决问题。

在本文中,我将带领您制作您的第一个机器学习模型,并成功进入您自己的船,在这些竞赛的海洋中航行。

我们走吧!

理解数据

首先——打开比赛页面。你需要时不时地引用它。

对于这一特定任务,我们的问题陈述和最终目标在竞赛页面上有明确定义:

我们需要开发一种 ML 算法来预测泰坦尼克号上乘客的生存结果。

测量结果为 0(未存活)和 1(存活)。这就是我们手头有一个二元分类问题的确凿证据。

好吧,打开你的 jupyter 笔记本,让我们看看数据是什么样的!

df = pd.read_csv(‘data/train.csv’)
df.head()

将数据训练成数据帧

乍一看——有分类和连续特征的混合。让我们来看看列的数据类型:

df.info()

关于列车数据的信息

我不会详细说明这些特征实际上代表了泰坦尼克号乘客的什么——我假设你现在已经在 Kaggle 网站上读过了(如果你还没有的话,你应该已经读过了)。

数据清理

这是我们整个 ML 工作流程的主干,是决定一个模型成败的步骤。我们将处理:

  1. 准确(性)
  2. 一致性
  3. 一致性,以及
  4. 完全

的数据,如这篇精彩文章所述。如果您想获得关于数据清理技术的最深入的知识,请稍后阅读。

同样,也要研究测试数据。我称之为df_test

现在,继续制作一个训练和测试数据的组合列表,开始我们的清理工作。

data = pd.concat(objs = [df, df_test], axis = 0).reset_index(drop = True)

我们的目标变量将是**Survived**列——让我们把它放在一边。

target = ['Survived']

首先,我们检查训练数据列中的空值。

df.isnull().sum()

列中空值的总和

我们马上可以观察到,三列对于建模来说似乎是不必要的。还有,机舱柱表现得相当稀疏。我们可以保留它,并从中获得某种价值,但现在,让我们保持简单。

data = data.drop(['PassengerId', 'Ticket', 'Cabin'], axis = 1)

现在我们转到具有空值的其他列。

我们用中间值代替年龄票价,而用众数代替上船(将是 S )。

data.Age.fillna(data.Age.median(), inplace = True)
data.Fare.fillna(data.Fare.median(), inplace = True)
data.Embarked.fillna(data.Embarked.mode()[0], inplace = True)

这样,我们的数据中就没有空值了。干得好!

特征工程

现在,让我们为数据创建一些新的特性。

我们创建一个名为' familySize 的列,它将是我们的父母+兄弟姐妹+子女的总和。

data['FamilySize'] = data.SibSp + data.Parch

此外,我们想要一个名为“ isAlone 的新列,基本意思是泰坦尼克号的乘客是否独自在船上旅行。

data['IsAlone'] = 1 #if alone
data['IsAlone'].loc[data['FamilySize'] > 1] = 0 #if not alone

最后,我们再补充一点,那就是——乘客的头衔作为单独的一栏。

让我们先创建一个新列。

data['Title'] = data['Name'].str.split(", ", expand=True)[1].str.split(".", expand=True)[0]

现在,让我们看看有多少独特的标题被创建。

data[Title].value_counts()

乘客的所有头衔

那是相当多的!我们不想要那么多头衔。

因此,让我们继续将少于 10 名乘客的所有标题累积到一个单独的“ Other ”类别中。

title_names = (data.Title.value_counts() < 10) 
data[‘Title’] = data[‘Title’].apply(lambda x: ‘Other’ if title_names.loc[x] == True else x) 
# data.drop(‘Name’, axis = 1, inplace= True) # uncomment this later

现在我们来看看修改后的列。

这看起来好多了。

好了,让我们最终将两个连续的列——年龄和费用——转换成四分位数。点击了解关于此功能的更多信息。

data['AgeBin'] = pd.qcut(data['Age'].astype(int), 5)
data['FareBin'] = pd.qcut(data['Fare'], 4)

这使得这两列是绝对的,这正是我们想要的。现在,让我们再来看看我们的数据。

data.head()

工程数据

标签编码我们的数据

我们所有的分类列现在可以编码成 0,1,2…等等。通过 sklearn 提供的便利功能进行标记。

from sklearn.preprocessing import LabelEncoderlabel = LabelEncoder()
data['Sex'] = label.fit_transform(data['Sex'])
data['Embarked'] = label.fit_transform(data['Embarked'])
data['Title'] = label.fit_transform(data['Title'])
data['Age'] = label.fit_transform(data['AgeBin'])
data['Fare'] = label.fit_transform(data['FareBin'])

好吧!现在只剩下两步了。首先,我们删除不必要的列。

data.drop(['FareBin', 'AgeBin'], axis = 1, inplace = True)

最后,我们一个 - - 用熊猫的 get_dummies 函数编码我们的非标签列。

columns_train = [col for col in data.columns.tolist() if col not in target]
data = pd.get_dummies(data, columns = columns_train)

现在让我们再看一下我们的数据,好吗?

一位热编码数据

厉害!现在我们可以开始建模了!

制作 SVM 模型

将我们数据分成训练集和验证集。

train_len = len(df)
train = data[:train_len]# to submit 
test = data[train_len:]
test.drop(labels=["Survived"],axis = 1,inplace=True)

现在,我们的训练数据将具有以下形状:

train.shapeOutput:
(891, 49)

现在,我们从训练数据中删除标签列。

train["Survived"] = train["Survived"].astype(int)

最后,我们将标签为的列与其他列分开。

columns_train = [col for col in data.columns.tolist() if col not in target]
label = train['Survived']
train = train[columns_train]train.shape Output:
(891, 48)

通过 sklearn 的分割功能,我们使用80–20 分割将我们的训练数据分割成训练集和验证集。

X_train, X_test, y_train, y_test = model_selection.train_test_split(train, label, test_size = 0.20, random_state = 13)

让我们再看一下数据形状。

X_train.shape, y_train.shape, X_test.shape, y_test.shapeOutput:
((712, 48), (712,), (179, 48), (179,))

完美!我们准备训练我们的 svm 模型。

训练模型

我们导入我们的支持向量机模型:

from sklearn import svm

接下来,我们从它构建一个简单的分类器,并将其应用于我们的训练数据和标签:

clf = svm.SVC(kernel='linear') # Linear Kernelclf.fit(X_train, y_train)

很好!我们非常接近做出最终的提交预测。到目前为止做得很好!

现在,让我们在验证装置上验证我们的模型。

y_pred = clf.predict(X_test)print("Accuracy: ", metrics.accuracy_score(y_test, y_pred)) Output:
Accuracy:  0.8379888268156425

对于简单的线性 svm 模型来说,这看起来相当不错。

为提交做预测

我们终于来了,这是我们生成第一份提交预测的时刻,也是我们将上传到竞赛网站的文件的时刻。

让我们使用经过训练的分类器模型来预测测试(提交)数据集。

test_Survived = pd.Series(clf.predict(test), name="Survived")

最后,我们制作一个

ID_column = df_test["PassengerId"]
results = pd.concat([ID_column, test_Survived], axis=1)

我们检查最终预测输出数据帧的形状:

results.shapeOutput:
(418, 2)

厉害!这正是我们所需要的。

最后一步是从该数据帧创建一个 csv 文件:

results.to_csv("svm_linear.csv",index = False)

我们完了。

提交材料

进入竞赛网站,寻找下面的页面上传您的 csv 文件。

提交您的申请!

本文中的所有代码都可以在我的 repo 中找到。尽管如此,如果您已经完成了,那么您已经有了一个可以提交的 code base+文件。

README文件也有助于其他事情,比如构建虚拟环境和其他一些事情,所以如果你想的话,一定要检查一下。

https://github.com/yashprakash13/data-another-day#ml-mini-projects-because-crash-courses-are-the-best

单独学习数据科学可能会很难。跟我来让我们一起乐一乐。😁

Twitter 上与我联系。

另外,看看我的另一篇文章,你可能会感兴趣:

https://pub.towardsai.net/how-to-build-an-end-to-end-deep-learning-portfolio-project-caa459bf3029

男人对于电脑程序员就像女人对于家庭主妇一样?

原文:https://towardsdatascience.com/man-is-to-computer-programmer-as-woman-is-to-homemaker-e57b07cbde96?source=collection_archive---------20-----------------------

本文是《男人对于电脑程序员就像女人对于家庭主妇?去偏置词嵌入”

照片由 Unsplash 上的 Dainis Graveris 拍摄

简介

本文是“男人对于电脑程序员就像女人对于家庭主妇”一文的摘要[1]。本文讨论了机器学习中由于使用有偏见的训练数据而导致的性别偏见,并提出了一种解决模型去偏见的方法。本文概述了该白皮书,并讨论了该白皮书的 python 实现中的主要发现。

概述

该论文的作者使用单词嵌入模型来证明训练数据中的性别偏见。单词嵌入模型在谷歌新闻文章上进行训练,所有单词的向量表示存储在“ w2v_gnews_small.txt 文件中。w2v_gnews_small 包含来自 Google 新闻文章的单词,这些单词用 300 维向量表示。

例如,二维向量将是:

作者图片

因此,如果单词被表示为向量,我们可以使用余弦相似度来发现这些向量有多接近,从而理解单词之间的语义相似度。

本文讨论了使用单词的向量表示来寻找类比。例如,我们要找类比,“人是为了什么?作为女人吗?”。在线性代数中,我们会找出向量男女之间的差异,并找出有差异的向量对与男女向量的差异一样接近。

最接近这种差异的向量组合将是男人对 x 的最佳类比,就像女人对 y 的最佳类比一样。下图用图形解释了这一点:

作者图片

人类最好的类比是?就像女人一样。男人之于国王,犹如女人之于王后。使用简单的向量算法,单词嵌入对于捕获语料库中的各种关系是强大的。

然而,作者发现了单词嵌入模型放大的训练数据中隐含的性别歧视。例如,模型返回的性别歧视类比有:

男人对于电脑程序员就像女人对于家庭主妇一样。

父亲对于医生就像母亲对于护士一样。

因此,在谷歌新闻文章中存在隐含的性别偏见,这是单词嵌入模型识别并可能夸大的。本文讨论了如何评估训练数据中的性别偏见,并提出了消除或最小化性别偏见的方法。我们将在接下来的章节中讨论这些。

偏差评估

性别专用词是指与其性别相称且没有偏见的词。比如父亲这个词是男性性别,母亲是女性性别。因此,父亲和母亲是一对性别专用词。

为了量化偏见,作者将一个词向量与一对性别特定的词进行了比较。考虑单词矢量“护士”和父亲-母亲的性别特定的成对单词。护士这个词应该是中性的。我们将它非正式地形象化如下:

作者图片

使用余弦相似度计算向量奶妈和奶爸之间的距离。我们注意到奶妈之间的距离比奶爸之间的距离要小。因此,嵌入意味着护士更女性化,更接近母亲的向量。这是不正确的,因为护士可以是男性也可以是女性。

本文讨论了两种类型的性别偏见:

  1. 直接偏差:

在这种类型的性别偏见中,中性词被投射到性别轴上,理想情况下应该是中性的。如果偏向男性或女性,那么就存在性别偏见。论文中直接性别偏见的一些例子如下:

图片来自纸张[1]

2。间接偏置:

在这种性别偏见中,中性词被投射在极端-她极端-他职业轴上。

例如,垒球被认为是极限职业,足球被认为是极限职业。理想情况下,中性词应该在垒球-足球轴的中间。如果他们偏向轴线的任何一边,那么就有间接的性别偏见。论文中间接性别偏见的一些例子如下:

图片来自纸张[1]

我们已经讨论过嵌入产生性别偏见的输出。但是为了正式量化这些偏差,进行了群体实验。总部位于美国的亚马逊机械土耳其人被用来征求对单词或类比的性别偏见评级。

去偏置程序

消除性别偏见模型的程序解释如下:

1.我们首先从语料库中找到一小组特定性别的词,如他、她、男人、女人。这些充当种子词。完整列表可在附录 C[1]中找到。

2.使用这些种子词,创建线性 SVM 分类器来获得所有性别特定的词。

3.使用所有性别特定的单词,我们对语料库进行补充,以找到性别中性的单词,如程序员、家庭主妇、园丁。我们最终分离出性别专用词和性别中性词,如下图所示:

在该图中,y 轴表示该单词是特定于性别的还是中性的。

4.接下来,我们选择种子对单词作为 x 轴。我们选择 she-he 单词对,其他单词被投射到这个性别轴上。这个步骤被称为识别性别子空间,即识别捕获偏差的嵌入的方向。

于是,女演员更偏向她,少年时代更偏向何。我们注意到像天才这样的中性词更倾向于“他”而不是“她”。这是数据上的性别偏见。

我们可以用两种方法来消除中性词的偏见。我们可以执行硬去偏置(中和和均衡)或软去偏置(软化)。

硬债务是一种极端措施,在这种措施中,性别中性术语的性别痕迹将不复存在。软 debias 根据指定的超参数以中性术语保留性别。接下来我们将讨论硬德拜斯技术。

5.在 neutralize 中,我们将所有性别中性术语投影到 y 轴上,从而消除了性别偏见。视觉表现是,

图片来自纸张[1]

6.在 equalize 中,我们使中性词与每个等式集合中的所有词等距,如{祖母、祖父}、{guy、gal}。这意味着单词保姆将在祖母-祖父轴上等距,在男人-女人轴上等距。

该论文指出,模型的去偏化减少了刻板的类比(比如男人=程序员,女人=家庭主妇),并保持了嵌入的可用性。

Python 实现

使用来自以下 GitHub repo 的代码成功地重复了该实验:https://github.com/simsong/debiaswe[2]

GitHub repo 的文件描述如下:

作者图片

教程 _example1.ipynb 的代码讨论:

  1. 步骤 1 中,我们正在加载在谷歌新闻语料库上训练的单词嵌入。

来自代码[2]的图像

2.在步骤 2 中,我们通过舍和的方向来定义性别方向。

来自代码[2]的图像

3.在步骤 3 中,我们为她和性别方向找到最佳类比对。

来自代码[2]的图像

来自步骤 3 输出的 she-he 对的一些语义正确且无偏见的类比是:
1。女汉子
2。女儿-儿子 3。女商人-商人
4。女孩-男孩。女演员

来自步骤 3 输出的 she-he 对的一些有偏差的类比是:
1。钢琴大师 2。紧张自大的人。愉快地——出色地。助理教授经济学教授。注册 _ 护士-医生

4.在步骤 4 中,我们分析与职业相关的性别偏见。

来自代码[2]的图像

职业词汇列表来自人群实验,这些词汇是从亚马逊机械土耳其人那里征集来的。

每个字后的双浮点数定义如下:

来自代码[2]的图像

例如:

作者图片

根据定义,球员是弱男性职业,但刻板印象中,它比男性职业得分高。

5.最后,我们把嵌入这个词去掉。我们使用 debiaswe.debias 函数对我们选择的词集进行去偏置。

来自代码[2]的图像

结论

本文讨论了去偏差技术和量化数据偏差的指标。总之,词嵌入可以用来捕捉性别关联和性别偏见。一旦我们确定了偏见,我们就可以消除它们,以减轻性别偏见的扩大。我强烈推荐阅读原始论文,它写得非常好。

参考资料:

[1]t . Bolukbasi,k . Chang,j . Zou,Saligrama,v .,& Kalai,A. (2016 年 7 月 21 日)。男人对于电脑程序员就像女人对于家庭主妇一样?去偏置词嵌入。检索于 2020 年 10 月 28 日,发自 https://arxiv.org/abs/1607.06520

[2]辛姆森·加芬克尔男人对于电脑程序员就像女人对于家庭主妇一样?来自 https://github.com/simsong/debiaswe的去偏置词嵌入(2019)。

[3] Bolukbasi,t .,Chang,k .,Zou,j .,Saligrama,v .,& Kalai,A. (2016 年 7 月 21 日),男人对于电脑程序员就像女人对于家庭主妇?https://github.com/tolga-b/debiaswe

4t . Bolukbasi,k . Chang,j . Zou,Saligrama,v .,& Kalai,A. (2016 年 7 月 21 日)。男人对于电脑程序员就像女人对于家庭主妇一样?去偏置词嵌入。https://drive . Google . com/file/d/1 ixidmreh 4 qvynx 68 qvkqcc 9-_ yyksoxR/view

[5]t . Bolukbasi,k . Chang,j . Zou,Saligrama,v .,& Kalai,A. (2016 年 7 月 21 日)。男人对于电脑程序员就像女人对于家庭主妇一样?去偏置词嵌入。https://pdfs . semantic scholar . org/cc F6/a 69 a 7 f 33 BCF 052 a 7 def 176d 3 b 9 de 495 beb 7 . pdf

使用 FiftyOne 和 Labelbox 管理注释错误

原文:https://towardsdatascience.com/managing-annotation-mistakes-with-fiftyone-and-labelbox-fc6e87b51102?source=collection_archive---------20-----------------------

使用 51 查找图像数据集中的注释错误,并在 Labelbox 中修复它们

约翰尼·麦克朗在 Unsplash 上的照片

随着计算机视觉数据集增长到包含数百万张图像,注释错误无疑会悄然而至。虽然训练数据中的注释错误如果大量存在,可能对模型的性能有害,黄金标准测试集没有任何错误是至关重要的。

在学术界,ImageNet 和 MS-COCO 等著名数据集充当基准,允许研究人员比较相隔多年创建的计算机视觉方法。但是即使是流行的公共数据集也不是没有错误的。

COCO 数据集上的模型性能在 5 年内缓慢提高(图片来自 paperswithcode.com,CC-BY-SA)

随着时间的推移,这些数据集的性能仍在提高。当您需要决定使用哪种特定的模型来完成任务时,问题就来了。在公共数据集上比较整体性能是不够的。尤其是在生产环境中,当表现不佳会带来金钱甚至道德后果时,你需要确定你的模型的表现

高质量的黄金标准数据集即使不比高质量的模型更有价值,也同样有价值。能够准确地选择最佳模型并保持对其生产数据性能的信心,特别是在困难边缘情况下的性能,将节省时间和金钱,否则将不得不花费在取下模型并修改它上。

在这篇博客文章中,我看了两个机器学习工具,它们可以快速轻松地找到并修复可视化数据集中的注释错误。我正在使用开源的 ML 开发工具 第五十一 来计算标签的错误。然后,FiftyOne 直接与标注工具 Labelbox 集成,让我们可以轻松地重新标注有问题的样本。

设置

五十一标签盒API 都可以通过pip安装:

pip install fiftyone
pip install labelbox

使用 Labelbox 首先需要您创建一个免费帐户。这使您可以访问 Labelbox 注释应用程序,并让您上传原始数据。

FiftyOne 是一个开源工具,所以不需要帐户,只需要安装 pip。

为了使用 Labelbox Python SDK,您需要生成并验证您的 API 密钥:

export LABELBOX_API_KEY="<your-api-key>"

:你需要一个付费账号在 Labelbox 中进行模型辅助标注。这是将现有标签上传到 Labelbox 的唯一方法。

将数据载入 51

在这篇博客中,我使用 COCO-2017 对象检测数据集作为例子。该数据集在51 数据集 Zoo 中,因此可以在一行代码中加载到 51 中:

加载到第五十一个应用程序中的 COCO 数据集样本(图片由作者提供)

当然,在实践中,您会希望使用自己的数据,所以让我们来讨论一些数据存储在哪里以及如何加载数据的场景。

案例 1:数据集在 Labelbox 中

如果您有一个正在 Labelbox 中注释的数据集,并且只想使用 fiftone 来浏览该数据集并找到注释错误,那么 fiftone 中提供的 Labelbox 集成使这变得快速而简单。

首先,您需要从 Labelbox 中导出您的数据。这就像登录 Labelbox 应用程序一样简单,选择一个项目,转到 Exports 选项卡,然后生成标签的 JSON 导出。

接下来,您可以使用 FiftyOne 中提供的 Labelbox 实用程序来导入数据集。您只需要指定导出的 JSON 的路径以及用于从 Labelbox 下载原始数据的目录。

案例 2:数据集遵循通用格式

FiftyOne 支持加载十多种常见的计算机视觉数据集格式,包括 COCOTFRecordsYOLOmore 。如果您的数据集遵循这些格式之一,那么您可以用一行代码将其加载到 FiftyOne 中:

案例 3:数据集以自定义格式存储

不管你使用什么格式,你总是可以把你的数据和标签放到 51 个中。你需要做的就是用 Python 解析你的标签,将你的标签添加到51 个样本,然后将样本添加到51 个数据集。例如,如果您有检测,以下代码将构建一个数据集:

用 51 查找注释错误

FiftyOne 还包括 FiftyOne Brain 包,其中包含各种方法,可以帮助您分析数据集,以找到独特的坚硬的样本,以及在分类和对象检测数据集中找到潜在的注释错误

生成模型预测

51 大脑中的[mistakenness](https://voxel51.com/docs/fiftyone/user_guide/brain.html#label-mistakes)方法使用模型预测,根据模型的置信度对可能的注释错误进行排序。因此,让我们向数据集添加一些模型预测。

我们可以使用 FiftyOne Model Zoo 从各种预训练的模型中自动加载和生成检测,并将检测添加到我们的数据集中,只需两行代码。

在这个例子中,我使用的是在 COCO-2017 上预训练的 EfficientDet-D6。

:如果您正在使用自定义数据集,那么您可能需要使用自己的训练模型来生成预测,并手动将它们添加到您的 51 数据集。无论您使用的是 分类 检测 ,还是 更多 ,这个过程都很简单。对于分类,您还可以为每个预测添加逻辑来计算误差。

计算错误

一旦我们将基础事实和预测标签添加到 51,我们只需要运行一个命令来计算错误

这将在标签上填充以下属性:

  • mistakenness — [0,1]地面实况标签上的值,指示地面实况对象的标签不正确的可能性
  • mistakenness_loc — [0,1]基本事实检测值,表示基本事实的边界框不准确的可能性
  • possible_spurious —基于地面真实检测的布尔型,指示潜在对象可能不存在
  • possible_missing —预测检测上的布尔值,表示注释过程中可能会遗漏某个对象

浏览数据集

既然已经为数据集中的所有样本计算了错误率,我们可以使用51 应用来可视化我们的数据集,并寻找我们需要修复的特定样本和注释。

第五十一个应用程序中的错误计算结果(图片由作者提供)

此外,我们可以通过在数据集中创建视图来搜索、排序和查询错误计算的结果。例如,我们可以按最多possible_spurious次检测的样本进行排序:

带有虚假对象的顶级样本(图片由作者提供)

或者,我们可以过滤所有检测,只查看mistakenness大于 0.6 的检测:

椅子和沙发类的错误注释示例(图片由作者提供)

浏览一下上一个查询中的一些样本,我们可以看到一个常见的错误模式是误认为couchchair类。这两个类似乎经常包含注释错误的事实会人为地降低模型在这些类上的性能。让我们从这些样本中选择一些,并将其加载到 Labelbox 中进行重新计数。

修复 Labelbox 中的批注

FiftyOne 使查找有注释错误的样本变得快速而容易。由于 FiftyOne 和 Labelbox 之间的集成,我们现在可以将我们想要重新标注的数据加载到 Labelbox 中。在 Labelbox 应用中,只需创建一个新的数据集并选择您想要上传的文件。

您还可以使用 FiftyOne 中的 Labelbox 实用程序将媒体文件添加到您之前在 Labelbox 应用程序中创建的数据集中:

注意:如果您标记的项目已经存在于 Labelbox 中,那么您只需要收集您想要修复的样本的 id。

使用标签框编辑器

使用 Labelbox 的主要好处之一是能够访问用于标记图像的强大编辑器。他们的在线工具非常容易使用,非常适合我们希望尽快修复这些错误注释的工作流。

一旦 Labelbox 应用程序的数据集中有了原始数据,我们现在就可以创建一个新项目,并附加我们想要重新标注的数据。

为 Labelbox 中的项目选择数据集(按作者排序的图像)

然后我们需要为我们想要注释的类配置编辑器。在本例中,我们只想重新标记我们选择的样本中的chairscouches,所以我们添加了这些对象类。

在 Labelbox 中配置编辑器(按作者排列的图像)

一旦建立了项目,您就可以开始根据所定义的类来标记样本。

重新标注错误的治疗床标签(作者图片)

现在这些样本已经被重新标注,我们可以更新 Labelbox 数据集中的标签,或者再次下载标注,并在 Labelbox 外部手动更新我们的数据集。

(可选)模型辅助标注

Labelbox 还为 Pro/Enterprise Labelbox 用户提供付费的模型辅助贴标功能。这样,您可以将注释直接加载到 Labelbox 中并编辑它们。这使得更新错误的注释或使用模型预测作为未来注释的起点变得更加容易。

第五十一个中的标签盒实用程序提供了多种功能来帮助实现这一点。您可以将数据集以 Labelbox 格式导出到磁盘,然后将其上载到现有的 Labelbox 项目。

摘要

带有正确标签的干净数据是黄金标准测试集的关键。注释错误会导致不可靠的模型性能,这在生产环境中可能是昂贵的,甚至是危险的。利用 FiftyOne 和 Labelbox 之间的紧密集成来快速查找和修复注释错误可能是生成成功模型的关键。

关于体素 51

高质量、有针对性的数据对于训练优秀的计算机视觉模型至关重要。在 Voxel51 ,我们拥有超过 25 年的 CV/ML 经验,非常关心如何让社区将他们的 AI 解决方案带入生活。这就是为什么我们开发了 FiftyOne ,一个帮助工程师和科学家更快更好地完成 ML 的开源工具。

想了解更多?在 fiftyone.ai 查看我们的网站。

作为数据工程师管理数据—第 3 部分:关键原则和经验教训

原文:https://towardsdatascience.com/managing-data-as-a-data-engineer-part-3-key-principles-lessons-learnt-920d9ebead1d?source=collection_archive---------39-----------------------

在前两篇文章中,我们已经了解了用户如何查看数据以及数据如何随时间变化。在作为数据工程师管理数据系列的第 3 部分中,我将分享作为数据工程师管理数据时的一些关键原则和经验教训。

不要盲目

为了管理不断变化的数据范围,首先要做的事情之一就是不要在黑暗中工作。由于各种原因,数据会随着时间发生变化,这些变化可能会以不同的方式破坏系统。能够监控系统中的数据流并确保它们按预期工作是很重要的。

为了不盲目,首先,我们定义一组度量数据系统的指标。可以测量的一些示例度量是仓库健康度量,例如 CPU 负载、内存负载、到仓库的连接数、查询队列时间的持续时间和存储容量。此外,其他指标,如数据的“新鲜度”、列中 NULL 值的数量和重复行的数量,都是数据系统是否健康的非常有用的指标。

使用我们确定的指标,我们可以设置基线来确定我们定义的“健康”是什么。然后,可以通过建立警报系统,在意外发生时自动通知利益相关方,来实施监控。这允许立即关注并迅速采取补救措施。

将警报反馈给正确的利益相关者也很重要,这样沟通就可以尽可能地顺畅。例如,当产品的数据管道中断时,同一产品的产品经理、数据科学家和数据工程师会一起收到警报。利益相关者列表和警报应该不时地被审查,以便警报总是到达正确的人,而不是被忽略。

有了一个强大的监控系统以及一个有效的利益相关方反馈机制,我们将能够看到数据可用性和可靠性的提高。数据工程师将能够更准确地指导他们的工作,因为排除故障所需的时间更少。这也有助于数据工程师进行容量规划,因为我们可以更好地预测工作负载的变化。

应用 80/20 法则

随着公司的发展,数据也呈指数级增长,我们很快发现我们没有足够的资源在所有数据管道上投入同等的精力。80/20 法则可以方便地指导我们的工作,更有效地优化数据系统。

帕累托原则指出,你 20%的活动将会产生 80%的结果。在数据的世界里,我们发现这个原则是成立的。我们观察到的一些例子有:

  • 20%的表占用了数据仓库中 80%的存储空间
  • 20%的表用于支持 80%的关键业务仪表盘
  • 数据仓库中 80%的瓶颈通常是由 20%的查询/工作负载造成的

这个原则对于识别仓库中的瓶颈特别有用,比如释放存储空间和提高查询性能。在进行任何类型的优化工作之前,我们应该始终尝试评估影响的大小。它通常不是最大也不是最复杂的工作,而是最准确的工作,它将对整个系统产生最大的影响。除了瓶颈之外,任何其他地方的优化都是浪费时间。

保持简单

作为数据仓库的守护者,组织仓库中的数据以及设计数据权限和用户角色是我们的部分职责。

在日常工作中,随着业务需求的变化或用户加入和离开公司,我们会处理大量的数据创建、数据迁移和数据访问请求。随着公司及其数据的发展,如果数据没有得到很好的组织,即使是授予数据访问权限这样简单的任务也会变得不必要的复杂。这是因为业务用户可能会改变角色,在不同的项目之间切换,并且随着公司产品的成熟,数据用例可能会随着时间而改变。

对于简单的任务,如数据创建和授权数据访问,标准化可以走很长的路。我们不需要十种不同的方式来创建数据资产和授予访问权限。我们只需要一种易于理解的方法,并且可以被管理数据仓库的整个团队所遵循。围绕数据创建的标准化流程有助于减少数据工程师执行任务所需的步骤。它还减少了数据工程师在创建新的数据资产和访问时的认知工作量。

标准化之后,我们可以围绕数据创建和数据访问创建一个流程,然后创建工具来自动化它们。这有助于减少人为错误,并支持审计跟踪。

请记住,数据是沉重的

一旦用户开始消费数据,就很难做出改变。随着越来越多的用户使用数据,以及越来越多的应用程序或仪表板使用数据,将会有更多的依赖性。当我们对数据进行更改时,无论是简单地更改列名还是更改数据类型,都有破坏所有数据相关性的风险。这就是为什么数据迁移总是如此缓慢和痛苦。

在消费者使用数据模型之前,最好从一开始就设计和创建数据模型。如果在将数据推送到生产环境后需要进行更改,请在对数据建立更多依赖关系之前尽快进行。对于长期存在的数据资产,最好避免引入对数据的更改,除非不这样做的风险很高并且是绝对必要的。

通常情况下,数据迁移是不可避免的。产品发展如此之快,以至于不可避免地会出现新的需求,甚至需要新的工具来支持这种变化。在这种情况下,当对数据进行更改或旧的数据集被废弃时,与利益相关者的持续沟通非常重要。为您的迁移做好计划,并让您的利益相关者尽可能平稳地完成过渡。

建立一个可持续的知识库

人们发现,数据用户实际上花费了超过 50%的时间来发现和理解数据,以确保他们使用的是正确的数据。在创建数据时对其进行记录大有裨益,因为这有助于未来的用户信任和使用这些数据。

这里的关键词是“可持续”。虽然为数据创建文档很重要,但保持文档的活力和更新也同样重要。通常情况下,数据用户使用 Google Sheets 或个人笔记创建自己的数据字典,以便在处理数据时理解数据。然而,这些形式的文档很难与公司的其他部门共享,并且很难维护。

有一些流行的开源工具可以用来创建数据字典。像 dbt 这样的工具允许用户使用。yml 文件,并允许用户生成一个 web 静态页面,以便在一个漂亮的网站界面中查看数据字典。Dbt 存储库也可以存储在 git 中进行版本控制,并允许多个数据用户在创建数据模型时轻松协作。

近年来,越来越多的开源项目提供元数据引擎和数据发现解决方案,如阿蒙森数据中心。这些工具旨在帮助数据用户记录数据字典和其他元数据。用户还可以使用该工具轻松发现新的和现有的数据集,并在一个地方找到所有相关信息,从而提高他们使用数据的效率。

期待改变

尤其是在成长中的初创公司,数据预计会呈指数级增长,我们必须预见到变化。记住这个问题总是好的,如果 X 在未来发生变化,wh at?

对于数据系统中重要的移动部分,我们应该使用版本控制工具来集中和跟踪变化。Terraform 等工具有助于将基础设施配置存储为代码,并允许我们将它们存储在 git 存储库中,以便我们可以跟踪对基础设施资源所做的任何更改。dbt 存储库是用于管理数据变更的工具的另一个例子。它帮助我们集中转换后的数据资产,跟踪变更并创建 dbt 数据测试,以确保数据按预期运行。

为了管理由产品变化引起的变化,最好根据业务领域或产品在公司中的结构来组织数据。随着时间的推移,业务用户和角色很容易发生变化,而随着产品的发展,生成的数据总是可以与业务领域联系起来。随着公司和应用的发展,数据的组织方式也需要密切关注。

沟通是关键

最后但同样重要的是,尽管这是老生常谈,但沟通是关键。归根结底,只有终端用户和应用程序正确使用数据,数据才能成为有用的信息。将数据视为与公司中的业务用户以及使用您公司产品的最终用户进行交流的一种方式。

业务需求总是在变化的,这些变化会反映在生成的数据中。上下文很重要,仅从生成的数据来看,它的含义通常并不明显。这就是为什么文档对于交流上下文至关重要。

这些是可用工具的一些示例,这些工具可以帮助组织数据、自动化流程,以及有效地向利益相关者传达变更。

  • 版本控制:git
  • 组织数据模型:dbt,holistics
  • 数据文档:Amundsen、dbt、DataHub
  • 警报系统:Slack、寻呼机工作、电子邮件、社交网络
  • 监控:NewRelic,DataDog,CloudWatch,任何 BI 工具
  • CI/CD: Codefresh、GitLab、Jenkins

沟通是关键无论您是生成应用程序数据的软件工程师、处理数据的数据工程师,还是使用数据的最终用户。对于不同的对应方来说,能够正确理解、使用和反馈数据以创造最佳结果是非常重要的。这将使公司能够制造一流的产品,并为关键决策提供准确的商业见解。我们所有人,而不仅仅是数据工程师,都有责任确保数据管道顺畅运行。

结论

好了,这是作为数据工程师管理数据的 3 部分系列的最后一部分。如果你错过了前面的文章,这里有这三篇文章的链接:

我希望在您踏上数据之旅时,它们会对您有所帮助。感谢阅读!

使用 Python 管理栅格数据中的空值

原文:https://towardsdatascience.com/managing-null-values-in-raster-data-with-python-511339b1b31b?source=collection_archive---------36-----------------------

入门

使用地图代数将简单算法应用于图像

空值总是数据科学家的心头之火,正确地管理它们可能是应用程序崩溃和应用程序腾飞的区别。

这对于 GIS 影像或任何栅格化数据尤为重要。我们不能忽略空值或用零填充它们(删除不是一个选项!)因为它会在生成的图像中产生难看的洞(见下面的例子)。

左侧的数字高程模型(DEM)显示了包含空值的栅格数据集;右图显示了对空值应用空间滤波平滑后的效果。(图片| 布比杰尼斯)

我们必须应用一种叫做空间过滤的技术,用反映我们发现它们的背景或环境的信息来填充空白。

为了使“之后”的图像(上图)看起来一致或平滑,我们知道“之前”图像顶部的空像素应该用与图像底部的空像素完全不同的值填充。那么,如何才能使用 Python 恰当而系统地计算出这些新值呢?

在我的 Github 页面上查看该项目的完整代码(链接)。

数据工程任务

我的同事 Daniel Bonhaure 和我构建了一个非常标准的 GIS 分析 web 应用程序,允许用户上传矢量数据集(即 shapefiles),可视化它们并对存储的数据进行分析。然而,在将数据存储到数据库中之前,我们的数据工程管道必须正确地处理空值。

如果我写的是关于 R 编程语言的文章,这篇文章会短得多,因为 R 提供了一个简单的函数, focal() ,它完成了所有的工作。然而,使用 Python,这是一个更难解决的问题。我们需要召唤 NumPy,SciPy 和 Matplotlib 的力量。

这很复杂…从好的方面来说

空间过滤或焦点分析是一种地图代数技术,在这种技术中,我们使用相邻像素的值来改变目标像素的值,在我们的情况下,目标像素为空值。如果你曾经使用过图像滤镜来增强你的 Instagram 照片,这是完全相同的技术。

空间过滤器如何用周围值的平均值替换空值的示例。(图片| bubjanes )

她有许多名称——窗口、内核、过滤器足迹、地图——但本质上它是一个二维数组(最常见的是 3 x 3 或 5 x 5),它在图像中逐个像素地移动,其中数据集中的每个像素在中心有一个转折,即我们的 3 x 3 数组中的第五个或位置x[4】。这个过程叫做卷积。

过滤器覆盖区或“窗口”以这种卷积模式逐个像素地穿过整个栅格。️(image| 布比杰斯&玛琳

我们在函数中使用的过滤器仅在目标位置发现空值时触发,即 x4 。当找到时,它用周围像素的平均值填充该值。

Code| dbonaure

SciPy 多维图像处理子模块为卷积和滤波提供了几个选项;我们在我们的系统中使用了【generic _ filter()(见下文)。

边缘案例

如果你检查一下笔记本你会发现我们的过滤窗口效果很好,但是我们忽略了一个非常重要的细节:边缘。也就是说,当我们的过滤窗口的目标值在我们的光栅矩阵的边界上时,我们该怎么办?

这由 SciPy generic_filter() 函数中的模式参数处理,该函数提供了五个选项:

用于将窗口扩展到卷积计算边缘之外的选项(image| bubjanes)

  • 常量 —通过用我们传递给 cval 参数的任何内容填充窗口来扩展窗口的值;在我们的例子中 cval=np。南
  • 反射 —以相反的顺序重复外部边缘附近的值(对于 3 x 3 窗口,这将只包括栅格边缘的像素;一个 5 x 5 将包括两个额外的反射值)。
  • 最近的-仅取最靠近边缘的值(对于 3 x 3 窗口,这相当于反射 )
  • 镜像 —在内部矩阵的反射模式中,将窗口的值扩展到光栅边缘之外,但跳过边缘值(在 3×3 矩阵中,这意味着添加的行或列不是边缘,而是边缘的第二行)。
  • wrap —通过从矩阵的另一边获取值来扩展窗口的值(就像在超级马里奥中,当你跳出屏幕的一边,出现在另一边)

高级过滤算法

既然我们已经使用空间滤波成功地平滑了我们的空值,为什么不更进一步呢?使用相同的管道,我们可以通过将它添加到我们的 generic_filter() 函数来应用任何我们想要的空间算法。

在本例中,由于我们使用的是数字高程模型或 DEM,因此计算地块中每个点的坡度可能是合理的。我们可以使用邻域算法来实现这一点(如下)。

用 Python 实现邻域算法。(图片| bubjanes )

我们正在查看的数据集是农田(非常平坦),因此斜率图并不十分令人兴奋,…但你已经明白了。

结论

此处提供的清理栅格数据的解决方案(空间过滤)是影像处理科学特有的,需要地图代数和卷积的专业知识。

尽管空间滤波是一种较为复杂的平滑空值的方法,但我们可以重新利用这种技术对我们的数据进行更复杂的科学计算,例如计算数字高程模型在每个点的斜率。

🔥🔥🔥🔥

延伸阅读:

像专家一样管理 Python 环境

原文:https://towardsdatascience.com/managing-python-environments-like-a-pro-4d8ad1d5b80?source=collection_archive---------7-----------------------

还在用 virtualenv?试试这个新工具。

Unsplash 上的 CHUTTERSNAP 拍摄

Python 虚拟环境帮助我们轻松地管理依赖性。最常见的环境创建工具是 virtualenvconda ,后者用于多种语言的环境管理,而前者是专门为 python 开发的。

为什么不使用全局 python 包,那么我们就不需要陷入这种环境混乱,对吗?是的,这将节省我们管理环境的时间,但代价是,为项目做好准备的痛苦将呈指数增长。我通过艰难的方式了解到这个事实,对所有事情都使用全局包,而不是对每个项目都有一个专用的环境。

在这篇博客中,我将写关于 virtualenvwrapper 的内容,这是一个 python 库,用于管理和定制 python 中的环境,它运行在优秀的旧 virtualenv 之上。随着我们的进展,我们将看到 VEW CLI 命令如何类似于 Linux 命令,如 mkdir、rmdir 和 cp。

注意:在本文中,我将把 virtualenvwrapper 称为 VEW

开始前

值得注意的是,pyenv 与 virtualenv 或 VEW 没有关系。pyenv 用于在多个 python 版本之间切换,并且不管理已安装的包。另外,pip 是 python 中的一个包管理器,pip 也不能帮助我们管理环境,因为它不是用来做这个的。有关更多信息,请阅读此 stackoverflow 线程。

https://stackoverflow.com/questions/38217545/what-is-the-difference-between-pyenv-virtualenv-anaconda

装置

安装过程与任何其他库相同。

pip install virtualenvwrapper

在 Linux 系统中,安装之后,我们需要编辑。bashrc 文件,这将允许用户在任何终端和位置访问 VEW。

export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3export WORKON_HOME=~/my_env_folderexport VIRTUALENVWRAPPER_VIRTUALENV=/home/my_user/.local/bin/virtualenvsource ~/.local/bin/virtualenvwrapper.sh
  1. 在第一行中,我们设置了 VIRTUALENVWRAPPER_PYTHON 变量,该变量指向 VEW 必须引用的 PYTHON 二进制安装
  2. 接下来,WORKON_HOME 是 VEW 将存储所有环境和实用程序脚本的文件夹
  3. VIRTUALENVWRAPPER_VIRTUALENV 是原始 VIRTUALENV 二进制文件的路径

创建新的虚拟环境

如前所述,这里的命令类似于 Linux 命令。要创建一个新环境,请执行下面一行。

mkvirtualenv my-env

该环境将存储在 WORKON_HOME 变量中指定的路径中。除 virtualenv 选项外,还支持三个选项,它们是:

  1. -一个 my_path :环境的文件夹,表示每当环境被激活时,无论用户当前在什么路径,都会被重定向到 my_path 。这并不意味着环境将创建在 my_path 中。
  2. -i package1 package2 … :创建环境后,尝试安装提到的包。
  3. -r requirements.txt :创建一个环境,从 requirements.txt 文件安装。

删除虚拟环境

rmvirtualenv my_env

删除环境文件夹。请记住在删除环境之前将其停用。

显示环境的详细信息

showvirtualenv my-env

列出所有虚拟环境

lsvirtualenv

列出通过该工具创建的所有虚拟环境。使用-b 选项仅列出环境并忽略细节。

激活环境

virtualenv 使用以下命令激活环境。

source my-env/bin/activate

source是一个常用的 Linux 命令,主要用于改变当前 shell 的环境变量。点击阅读更多信息。VEW 抽象了这个源命令,并提供了一个易于记忆的替代命令workon

workon my-env

在引擎盖下,VEW 执行source命令。

停用环境

停用 VEW 的环境与 virtualenv 相同。在活动环境 shell 中,执行以下命令。

deactivate

卸载环境中的第三方软件包

wipeenv

该命令将在活动环境中运行。当这被执行时,VEW 将识别所有第三方库并卸载它们。

结论

虽然 virtualenv 可以很好地管理我们所有的环境,但 virtualenvwrapper 是一个推荐的附加组件。它与 Linux 命令的相似性使得操作更容易记忆。关注更多这样的文章。感谢阅读到最后:)

利用 GCP 云资源仓库管理人工智能平台上的脚本

原文:https://towardsdatascience.com/managing-scripts-on-ai-platform-with-gcp-cloud-source-repository-b27f5f0db70c?source=collection_archive---------21-----------------------

分享通过 GCP 云资源仓库管理和共享脚本的步骤的教程

Thiago Barletta 拍摄于 Unsplash

介绍

之前我曾经在组件 Google Cloud AI 平台下有多个 Jupyter 笔记本。当我想将脚本从 Notebook-1 复制到 Notebook-2 时,我将启动 Notebook-1 的实例,并从那里下载脚本以上传到 Notebook-2。这种方法效率很低,并且随着实例的启动会产生更多的成本。然后我的队友建议与 Google 云资源仓库合作——这是一个绝妙的主意!

那么什么是 Google 云源码库呢?

Google Cloud Source Repositories 是一个很好的平台,可以在团队成员之间管理和共享代码,或者在项目结束时与客户共享您的脚本。云资源存储库可以是团队共享脚本、管理和跟踪变更的单一位置。用户可以轻松地将他们的脚本的更新版本从笔记本推送到云资源存储库。

Google Cloud Source Repository 可以连接到许多其他 GCP 组件,如 App Engine、Cloud Build 等。然而,本文将分享创建存储库所需的步骤,并将脚本从您的 AI 平台 Jupternotebook 推送到云资源存储库,并从云资源存储库克隆到 AI 平台 Jupternotebook。

让我们开始我们的教程!(本教程假设已经设置了一个 GCP 项目)

创建云资源存储库:

首先从您的 GCP 控制台下拉菜单导航到云源存储库。

步骤 1:开放云源代码库

选择“添加存储库”选项,然后选择“创建新存储库”

步骤 2:创建新的存储库

提供一个“存储库名称”并指定您希望云资源存储库成为的“项目”。

步骤 3:指定“存储库名称”和“项目”

一旦成功创建了您的存储库,将会有一个指南分享您如何将代码添加到存储库中。有三种方法:

  • SSH 认证
  • 谷歌云 SDK
  • 手动生成的凭据

让我们遵循“Google Cloud SDK”方法,它为我们提供了将脚本推送到存储库所需的命令。

步骤 4:选择并遵循方法——Google Cloud SDK

将存储库克隆到 Jupyternotebook

现在让我们打开 Jupyternotebook,看看如何将新创建的存储库克隆到 Jupyternotebook 中。要运行笔记本中提供的代码,我们需要启动“终端”。

第五步:在 Jupternotebook 中启动“终端”

这将启动一个新的“终端标签”。现在,我们可以通过运行提供的命令集,在这个“终端选项卡”中开始克隆我们新创建的云资源存储库

首先运行第一个命令来设置身份验证凭据:

gcloud init 

步骤 6:提供身份验证凭据

接下来,克隆您新创建的云资源存储库

gcloud source repos clone Our-Scripts-Folder --project=sue-gcp-learning-env

步骤 7:克隆存储库

当我们克隆一个空的存储库时,在警告消息显示上注明。让我们切换到这个新的克隆存储库,并向其中添加文件。

cd Our-Scripts-Folder

步骤 8:切换到新的克隆存储库

将一些文件上传到新的克隆存储库文件夹中。在这个例子中,我上传了 2 个文件到文件夹“我们的脚本文件夹”

步骤 9:将文件/脚本上传到新文件夹

推送至云资源存储库

上传完成后,我们需要添加并提交它们,然后将它们推回主云资源存储库。

此外,您需要通过运行以下命令在提交之前设置您的详细信息:

git config — global user.email “you@example.com”
git config — global user.name “Your Name”

步骤 10:更新用户详细信息

现在,您可以添加、提交和推送您的代码到云源代码库。

git add . 
git commit -m "type your commit message here"
git push -u origin master

步骤 11:添加、提交和推送

成功推送文件后,检查它们是否上传到了云资源存储库中。

步骤 12:执行检查

恭喜你!文件已成功上传到云源资料档案库。

现在,让我们反过来工作。假设我们正在与新同事分享这组脚本。我们的新同事需要将云资源存储库中的脚本克隆到他/她的 Jupyternotebook 中。让我们看看如何做到这一点!

从云资源库中克隆和提取

在云资源仓库中,有一个“克隆”选项,向我们展示了如何克隆仓库并提取代码。选择“+克隆”选项,然后选择“如何设置?”。

步骤 13:选择“+克隆”选项

与之前类似,有 3 种克隆方法。让我们选择选项——Google Cloud SDK,它为我们的新同事克隆存储库提供了所需的命令。

通过在终端中运行克隆命令来克隆存储库

gcloud source repos clone Our-Scripts-Folder --project=sue-gcp-learning-env

步骤 14:克隆存储库

这就是所需的所有步骤,并且已经用文件夹中的文件和脚本克隆了存储库。

如果云源存储库中有新的变化。需要执行以下命令来获取文件/脚本的最新版本。

切换到新的克隆存储库位置,然后提取更新的文件/脚本。

cd Our-Scripts-Foldergit pull origin master

这些是你在 jupter notebook with Cloud Source Repository 上管理代码所需的步骤。

结论:

使用 Google 云源码库管理团队成员在不同 AI 平台笔记本上的脚本效率更高,并且可以跟踪更改。文件和移交给另一个成员的过程也将更加顺利。

感谢你阅读这篇文章,我希望这能帮助那些从 GCP 云资源仓库起步的人。

参考和链接:

[1]https://cloud.google.com/source-repositories/docs/

[2]https://blog . peterschen . de/use-cloud-source-repositories-in-jupyter-notebooks/

DoorDash 如何通过机器学习管理供需平衡

原文:https://towardsdatascience.com/managing-supply-and-demand-balance-through-machine-learning-70d4f0808617?source=collection_archive---------25-----------------------

预测和数学优化如何用于最后一英里物流行业。

照片由 Kenjo 提供

在 DoorDash,我们希望我们的服务成为日常便利,提供及时的送货和一致的价格。实现这些目标需要在配送员(我们对配送司机的称呼)的供应和订单需求之间取得良好的平衡。

在高需求时期,我们一般会增加工资(T3),这是一种激励措施,以确保有足够的司机供消费者尽快接受订单。我们不会将增加的费用转嫁给消费者,因为无论何时,消费者都将支付相同的费用。

考虑到向员工提供高峰需求薪酬的复杂性,我们建立了一个新的动员系统,在任何预期的供需失衡之前分配激励措施。在构建该系统时,我们重点关注以下几个方面:

  • 明确定义我们的供需衡量指标和项目目标
  • 生成高保真的供需预测
  • 建立约束条件下激励分配的新优化过程
  • 管理不确定性
  • 提高系统的可靠性和可维护性

我们如何量化供需不平衡?

在概述供求不平衡的问题时,采用所有受影响方的背景是有益的:

  • 对于消费者来说,在高峰需求期间缺少司机更有可能导致订单延迟、更长的交付时间,或者无法请求交付而不得不选择提货。
  • 对于短跑运动员来说,订单的缺乏会导致收入下降,为了达到个人目标,轮班时间更长、频率更高。
  • 对于商家来说,供应不足会导致交货延迟,这通常会导致冷食和再订购率下降。

在这种背景下,很明显,理想的场景是拥有一个在交付层面而不是市场层面平衡供需的系统,但是在选择市场测量指标时,这是不现实的。交付层面的平衡意味着每个订单都有一个在最佳时间可用的搅拌器。

相比之下,市场水平的平衡意味着市场中有相对相等数量的搅拌器和订单,但在交货水平上不一定有每个组的最优条件。在实践中,由配料器和消费者偏好以及环境中的其他变化条件(如交通和天气)驱动的供应和需求的差异水平使得很难在交付水平上平衡供应和需求。因此,我们专注于市场级别的指标来定义每个市场的状态,即使交付级别的指标会提供更理想的结果。

对于我们的主要供应和需求测量指标,我们查看了交付所需的小时数,同时保持交付持续时间低和 Dasher 繁忙程度高。通过关注小时,我们可以考虑由交通状况、配料率和食物准备时间驱动的区域变化。

为了理解这一指标在实践中是如何工作的,我们来看一个例子。让我们假设纽约市的晚餐时间是星期天,我们估计需要 1000 个驾驶小时来满足预期的需求。我们还可能估计,除非我们提供额外的激励,否则只有 800 小时可能是有机提供的。如果没有动员行动,我们将会少供应 200 小时。

我们通常在 Dash 注册 Dash 和时间单位时计算这一指标,时间单位可以从每小时持续时间到像午餐和晚餐这样的白天单位。非常重要的一点是,不要选择会导致人为需求和供应平滑的汇总层。例如,一天之内,我们可能在早餐时供应过多,而在晚餐时供应不足。一整天的优化将导致平滑任何不平衡,并产生不正确的动员行动。

一旦我们决定了健康指标和我们采取行动的单位,我们就通过调整供应来平衡供应和需求。我们的团队通常通过提供激励来调整市场的供应方,以便在需求增加时提高搅拌机的使用率。我们将在下一节中描述预测和优化在其中的作用。

我们如何在局部水平上预测供给和需求?

现在,我们有了衡量供应和需求水平的指标、采取行动的区域/时间单位以及管理供应的行动,我们可以确定预测需求的详细信息以及如何预测每个市场的供应和需求状况。

定义预测需求

鉴于我们生成的预测旨在用于自动化系统,我们用于预测的算法和我们将依赖的后续图书馆生态系统从长远来看都会对维护自动化产生巨大影响。我们主要将预测问题转化为回归问题,并通过微软开发的开源 LightGBM 框架使用梯度推进。这一选择背后有几个原因。

支持多元预测

许多单变量预测方法在生成数以千计的低粒度区域预测时并不适用。我们的经验有力地支持了这样一个论点,即一些最好的模型是通过快速原型制作过程创建的,因此我们寻找从假设模型改进到获得最终结果可以快速完成的方法。LightGBM 可用于在一次训练运行中训练和生成数千个区域预测,使我们能够非常快速地迭代模型开发。

支持外推法

随着 DoorDash 在国内和国际的扩张,我们需要我们的预测系统能够对我们目前不提供服务的地方的供需增长情况产生一些预期。例如,如果我们在一个新城市启动,即使没有历史数据,我们仍然可以对供需轨迹做出合理的预测。深度学习和传统的基于机器学习(ML)的方法在这种情况下特别有效,因为有助于外推的潜在信息可以通过嵌入向量或通过良好的特征工程来学习。关于人口规模、一般交通状况、可用商家数量、气候和地理的信息都可以用来进行推断。

支持反事实

预测用于设定对将要发生的事情的预期,但也不可避免地用于指导决策过程。例如,我们的利益相关者会问我们,如果我们改变供应预测模型中的激励水平,情况会如何变化,这样我们就可以了解如何在供应和成本之间进行权衡。这些反事实不仅有助于预测我们认为会发生什么,也有助于估计我们将要采取的行动的影响。在 LightGBM 中,可以通过在推理时改变进入模型的输入来生成近似的反事实。

依赖性小

我们希望预测系统具有最小的依赖性,这意味着我们不会过度依赖大量的第三方库。这一需求立即消除了许多自动预测方法,在这些方法中,安装一个库通常意味着安装 100 多个额外的库,或者提供统一工具包并具有大量可传递依赖项的方法。臃肿的内存占用会带来兼容性问题、升级挑战和大量安全漏洞。LightGBM 具有非常小的依赖性,并且执行升级相对容易。

繁荣的社区

最后,我们希望依靠一个拥有繁荣社区和强大核心维护团队的生态系统。维护一个开源库很有挑战性。一个库可以由一个研究生或者一个公司里的一到三个核心开发人员创建。尽管如此,人们还是会找到新的兴趣,新的工作,换工作,寻找新的职业,或者放弃职业。几年或几个月后,跟踪与库相关的问题和错误通常不是优先考虑的事情。这种最终缺乏支持的情况迫使用户创建内部分支,以便为他们的用例采用预测工具,或者参与完整的重新建模工作。出于这些原因,在选择工具时,我们会考虑发布周期、星级数和社区参与度等指标,以确保未来有良好的社区维护。

用 ML 预测

在纯回归问题的背景下进行预测可能会有其挑战,其中之一与理解数据生成过程以及输入和输出之间的因果关系有关。例如,下面的图 1 显示了我们的激励措施与办公时间增长的关系。

图 1:该数据表明,激励和动员之间存在非线性关系,较高的激励导致办公时间增加,而非常高的激励导致工作时间大幅减少。这种违反直觉的关系通常可能是遗漏变量偏差或同时因果偏差的标志。

如果我们盲目地依赖模型,通过数据中发现的相关性来学习因果关系,我们将会创建一个系统,该系统会错误地认为提供非常高的激励水平会导致路上更少的司机。高增长激励会导致流动性下降的因果解释是荒谬的。

更有可能的是,这个模型只是缺少了一个混淆变量。例如,在与恶劣天气或假日相关的时期,达什尔人想呆在家里或与家人在一起。在这些时候,我们更有可能看到可用性的下降,从而触发我们的供需系统提供更高的激励来保持市场平衡。

缺乏天气或假期知识的模型可能会了解到,当因果关系只是缺少一个协变量链接时,高激励会导致更少的休息时间。这个例子说明了为什么找出一种方法变得很重要,这种方法有时通过领域知识来约束在数据中发现的关系,或者依赖实验结果来调整由模型识别的一些相关关系,而不是盲目地将算法应用于可用数据。

第二个挑战与预测中发现的一个普遍真理有关,即预测的单位需要与做出决策的背景相匹配。进行更精细的预测可能很诱人,但这通常不是一个好主意。这可以很容易地通过模拟来演示。

考虑以下三个子区域,通过从平均值为 100、标准偏差为 25 的正态分布中抽取样本来描述日需求量,如下图 2 所示,得出变异系数为 25%。当我们合计这些地区时,我们简单地合计预期平均值,得到预期总需求为 300。尽管如此,组合标准差不等于标准差之和,而是等于方差之和

,得出综合预测的变异系数为 14.4%。通过简单地聚集随机变量,我们能够相对于平均值减少超过 40%的方差。

图 2:上图显示了三个次区域的需求。底部面板简单地表示总需求。通过执行随机变量的聚集,底部面板中的相对方差减少了 40%。

选择优化器

使用最大似然算法的一个好处是,在给定输入数据的情况下,它们提供了对将要发生的事情的更准确的预期。尽管如此,最大似然算法通常只是一个更大系统中的一个构件,它消耗预测并试图产生一组最优动作。基于混合整数规划 (MIP)或强化学习 (RL)的解决方案在构建专注于特定业务约束下回报最大化的系统方面非常出色。

我们决定采用 MIP 方法,因为它易于形式化、实施和向利益相关者解释,并且我们在该领域拥有大量的专业知识。优化器有一个自定义的目标函数,通过几个约束条件最小化供应不足。目标本身是非常灵活的,可以根据业务需求指定为有利于盈利或增长。在优化器中,我们通常对一些全局约束进行编码:

  • 不要在一个特定的地区-时间单位内分配一个以上的激励。
  • 永远不要超过我们的财务和运营合作伙伴设定的最大允许预算。

根据不同的要求,我们还可能有不同的地区或国家约束,例如不同的预算、定制罚款、哪些单位不应包括在优化中的排除标准,或者由输入可变性引导的激励约束。

处理不确定性

当资源有限时,输入的不确定性对优化器如何分配激励起着重要作用。为了证明这一点,下面的图 3 显示了两个城市中假设的供需不平衡的分布情况。

图 3:在城市 A,我们相信我们将会供应不足,并且对我们的预测也很有信心。在城市 B,我们的平均预测是,我们将略有过剩,但我们在我们的估计不太确定,并有一定的可能性经历大量供应不足。

如果优化器对不确定性一无所知,它最终会遇到两个问题。首先,它缺乏对供需平衡可能从极度供应不足转变为极度供应过剩的理解。如果优化器被设置为在一些预设的阈值下进行优化,它将错过为城市 B 进行优化的机会,因为分布的平均值大于零。

第二个问题是,它最终会在我们预测不确定的地方过度分配资源。我们的预测往往是在那些没有多少搅拌器和订单的小区域的长尾区域最嘈杂。因为这些地区的数量很大,并且它们表现出很高的方差,如果我们不明确说明这种不确定性,我们更有可能产生估计,偶然会有很高的供应不足,从而过度分配激励给相对于具有低方差的地方表现出高方差的地方。

为了解决差异问题,我们使用重采样过程从预测中生成小时差距的预期估计值。通过执行重新采样,我们实际上是在供应不足发生的可能性的背景下测量供应不足的影响。例如,在上面的图 3 中,城市 B 只有 34%的机会供应不足。然而,如果发生这种情况,我们可以更准确地估计供应不足的巨大变化的影响。这些方法中的任何一种都会导致激励分配中的更优决策,而不是简单地使用来自上游预测输入的平均估计。

可靠性和可维护性的改进

DoorDash 在去年有了巨大的增长。DoorDash 超过 70%的人是在 2020-21 年期间加入的。这通常带来了一波新的工程、产品、平台和基础设施相关项目,有助于持续增长、扩展和可伸缩性。例如,我们有几十个内部项目,这些项目与打破我们的垄断和采用更加面向微服务的架构有关。我们有数百个与产品改进或新的垂直发布相关的大大小小的项目。这些项目中的许多都伴随着我们的数据模型以及数据生成和收集过程的变化。不幸的是,当数据如何产生和暴露的生态系统不断变化时,ML 模型可能非常不可靠,因此我们需要做出一些改变来增强我们系统的可靠性。

解耦数据依赖链

我们可以使用许多不同的数据源,并对数百个特征进行编码,以构建一个具有高性能的模型。虽然这种选择非常有吸引力,并且确实有助于创建一个性能优于简单数据管道的模型,但在实践中,它会创建一个缺乏可靠性的系统,并为特性漂移产生很大的表面积,其中输入的分布会随时间而变化。因此,在建立我们的预测模型时,我们首先追求简单和可靠。这一战略还帮助我们更快地创建了一个端到端的移动系统。

图 4:具有复杂数据管道的模型通常可以在部署的最初几周显示出它们的优势,但随着时间的推移会迅速恶化。简单的数据管道通常更健壮,并减少维护和改造负担。

为了管理复杂性和数据暴露方式的转变,我们做了两件事。首先,我们将数据管道从彼此分离到独立的业务领域。现在,当有人致力于改善用于预测的输入信号时,他们不需要被单一的查询和数据管道淹没。相反,开发人员在一个隔离的管道上工作,只需要确保聚合在一个适当的实体上完成。

我们做的第二件事是移除中间数据依赖性。我们认识到,如果我们的输入信号来自 ETL 作业,并且在它们的有向无环图(Dag)中有非常长的依赖链,我们将增加失败的表面积。因此,我们希望依赖由我们的商业智能团队彻底审查过的主表,或者生产数据源的副本,其中的数据生成没有隐藏在复杂的 ETL 后面。

图 5:在这个例子中,任务 E 是带有数据转换的 ML 任务。如果 ML 模型的源数据来自 ETL 系统中的长依赖链(从 A 到 D),那么如果任何上游依赖失败,就有经历特性漂移和数据失败的高风险。

专注于实验

测试我们的系统是否可维护的最好方法之一是简单地检查迭代速度,以此我们可以在不产生错误或引入回归的情况下推动新的变化和启动实验。在 DoorDash,我们执行许多实验来确定某个功能是否按预期工作。这通常意味着我们更加重视通过扩展和交付新功能的速度来衡量软件质量。不出所料,如果实验很难启动,新功能很难测试,我们的目标就失败了。

类似地,如果一个系统在很长一段时间内(例如,六个月或更长时间)保持不变,这也是一个错误的迹象,因为这意味着我们创建了一个僵化的系统,不需要改进、构思和实验。持续的实验是一种强制采用更好实践的功能,例如依赖于自动化的 CI/CD 系统,建立库依赖管理,将代码分离到业务领域,以及添加测试、警报和文档。

结果

实施这一动员系统让我们能够更准确地将激励分配给从供需平衡改善中受益最大的地区时间单位。该系统为我们的客户带来了更好的体验,因为我们的指标显示交付时间、取消和极端延误的减少。对于 Dashers,我们能够确保将激励措施分配到最需要的地方。对于商家,我们降低了整体订单取消量。此外,由于预测准确性的提高,我们还能够更可靠地达到预算预期,并在支出决策中观察到更少的可变性。由于可靠性的提高,我们能够快速提高激励动员系统的实验速度。

结论

处理在约束条件下优化系统的问题从在适当的聚集级别上评估行动的影响的度量标准中受益匪浅。如果每天都进行预测,但优化措施是隔天进行的,那么决策可能不是最佳的。

其次,我们一般建议将预测组件与决策组件分离。如果输入具有稳定的统计属性,并且预测是无偏估计,则大多数优化系统会工作得更好。例如,在预测中开始使用非对称损失函数,以与我们是否更关心低估或高估产出保持一致,这可能很有诱惑力。虽然这种方法对于 ML 模型的输出直接用于驱动决策的各种问题来说是完美的,但是对于 ML 预测仅仅是更广泛的优化引擎的另一个输入的问题,最好生成无偏的预测。相反,最好让优化引擎来处理权衡。

如果你热衷于构建能够积极影响数百万商人、老板和顾客生活的 ML 应用程序,考虑加入我们的团队

承认

非常感谢 Jared Bauman 和 Dan Madwed 为新系统的架构出谋划策,感谢 Gary Ren 指导我们解决供需工程组件的复杂性,感谢 Henry Liao 简化实验,感谢 Matthew Ferro 和 Eugene Braude 推动自动化程度的提高。

欲获取本帖原文,请查看 DoorDash 工程博客

管理创新的风险

原文:https://towardsdatascience.com/managing-the-risk-of-innovation-8f964dc64b14?source=collection_archive---------17-----------------------

意见

从 iBuyer 的失败中我们能学到什么

将集体智慧应用于技术决策(图片由作者提供)

Zillow 在 AI 上下了大赌注,输了。Zillow 几周前报告的人工智能损失揭示了信任基于数据预测的自主黑盒算法的危险。数千人失去了工作,经济损失超过 5 亿美元。损失之后出现了无数的文章。这不是另一篇试图分析问题所在的文章。相反,它讨论了降低风险的新途径,并回答了导致成功结果的三个问题:

1.管理部署人工智能技术决策的最有效流程是什么?

2.我们如何在部署新技术的过程中降低风险?

3.我们如何在部署的人工智能应用程序中建立信任?

第一代人工智能研究和开发集中在人类身上,手工制作模拟人类如何应用知识解决问题的程序,从而产生了基于知识的专家系统。第二代人工智能专注于数据,希望模拟人脑如何处理信息。第二代人工智能的基本信念是,适当构建的人工神经元将引领我们走向人工智能,相当于关于智能的“万物理论”。

人工智能机器的概念鼓励最好的想象场景和最坏的人类傲慢。我们是多么迅速地掩盖了如此大规模工程的潜在隐患。这也发生在 20 世纪 80 年代。建立世界上最广泛的知识库,包含人类知识和“鲍勃是你的叔叔。”目前,这转化为一种信念,即构建示例性的深度学习架构将导致一般化的人工智能。

在这些错位的希望中,蕴含着科学知识的核心,承诺给未来带来极大的好处。理解人类大脑如何工作是一项巨大的创举,可能比万物理论更难。发展弦理论和超对称性的倡议始于 50 年前,第一次关于 AI 的会议是在 60 多年前。我们应该根据任务的大小来调节对人工智能进展的期望。人工智能在扩展信息技术的能力和用途方面取得了长足的进步。因此,我们应该满怀信心地继续前进,我们将在前进的道路上看到经济和社会效益。

DARPA 对人工智能的概述对公众开放。它包括一个简单的被忽视的陈述,“第二代人工智能在统计上是正确的,但在个体上是错误的。”这就是问题所在。你能相信什么?齐洛太相信了。

对于一个基于从数据中学习的模式的人工智能来说,信任它为你做决定是有风险的。如果它在统计学上是正确的,但个体有风险,你怎么知道什么时候该相信它?

由于过于信任统计人工智能,我们忽视了人类智能的力量和神秘。计算机科学家朱迪亚·珀尔说得很好,“你比你的数据更聪明。”我相信珀尔的话包含了一种成功可能性非常高的方法的精髓。本文的剩余部分将专注于该解决方案——讨论一种集人类智能和人工智能技术之大成的集体智能技术。

问题 1:管理部署人工智能技术的决策的最有效流程是什么?

1961 年,技术历史学家埃尔廷·e·莫里森在麻省理工学院做了一次关于计算机潜力的演讲。在书中,他提到了一种担忧——“计算机可能会显著增加我们社会中封闭决策的趋势。”他继续表达了对“给不真实披上数学现实外衣”的趋势的额外关注。虽然已经 60 岁了,但这两个观察都照亮了我们走向成功的道路。

将人类的集体智慧融入任何决策过程都将带来新的发现,因为人类的思维能够直觉地看到超出我们在逻辑、编程和数学中所能描述的东西。不幸的是,我们未能理解自动化的局限性和人类思维未开发的潜力和力量。

在过去的十年里,对集体智慧的广泛研究表明,我们集体更聪明。认知多样化个体的适当集合远比任何单个专家更准确。多样性预测定理抓住了集体智慧的本质:

集体误差=平均个体误差—预测差异

简而言之,分集预测定理指出:

  1. 多样性胜于能力
  2. 集体智慧胜过个人专长
  3. 总的来说,我们更有可能发现新的前进道路

该定理的明显问题是:“我如何创建和管理预测多样性?”这就是集体智慧的艺术:为手头的问题召集合适的问题解决者。这个定理的实际价值在泰特洛克、佩奇和马龙的书中得到了论证和广泛讨论。六年前,我们实施了一种人工智能方法,将集体人类智能集成到一个系统中。

CrowdSmart 系统最初应用于一个严重依赖人类判断的复杂问题:预测一家早期创业公司筹集第一笔 100 万美元种子资金并继续进行投资的可能性。在四年多的时间里,我们测量、跟踪并投资了那些筹集到第一个一百万美元种子资金的公司。每个公司组成的集体小组各不相同,但评审小组的重点始终是平衡投资、行业、技术和最终用户体验(如果有)。小组进行评分,并集体讨论他们得分的驱动因素。这一过程是由早期投资研究中得出的启发式模型指导的。总体而言,集体预测那些将获得后续融资(生存的必要条件)的公司的准确率超过 80%。结果显示多样性得分和准确性之间有直接的相关性。群体的评分模式越多样化,结果就越准确。关于这个话题的更多内容可以在另一篇文章中找到: 运用集体推理进行投资结果揭示了另一个意想不到的结果——这一过程大大减少了性别偏见。42%投资的公司由女性领导。其结果与现有的风险投资实践形成鲜明对比。此外,得分最高的公司以大约 1000 万美元的投资前估值筹集了第一个 100 万美元,目前正在筹集 3.5 亿美元。

总之,使用该技术进行投资的经验非常清楚: 将人类集体智慧与人工智能结合和集成的技术在减少偏差的同时,在预测准确性方面表现出了显著的提高。 这些结果导致了集体推理平台的创建:

CrowdSmart 的集体推理系统从群体审议中学习知识模型。在这种情况下,人工智能是一个“智能促进者”,它使用模板驱动的过程来引导群体做出决策、计划或预测。结果是一个动态的知识模型,保留了从小组讨论中提取的所有知识。知识模型是决策或计划过程的“迷你专家系统”,用于“假设”战略分析。有关 CrowdSmart 的集体推理系统的更多信息,请参见 用集体推理转变协作决策。

集体推理过程和认知多样化的团队减少了偏见。在集体推理过程中,个体在掩盖其身份的环境中表达他们的思想和感受。他们通过优先考虑哪些表达符合他们的观点来表达他们与他人的想法和感受的一致。

回到本文的副标题:集体推理是如何帮助 Zillow 决定部署其房屋买卖程序 iBuyer 的?很可能,一个包括房地产行业经验的认知多元化的团队会在信任算法方面引入更广阔的视角。

Zillow 可能会咨询专家,但他们不太可能参与系统部署的详细推理过程。报告中记录的专家访谈的标准做法不尽人意。很有可能产生偏见和误解。主动协作提供主动学习;在采访和报道过程中完全漏掉的东西。

集体推理过程拓宽了逻辑和数学创建者与实践领域专家之间的互动。撒下更大的网可以降低风险,为信任打下更坚实的基础。

问题 2:我们如何降低部署新技术的风险?

埃尔廷·莫里森指出了一个导致实践的担忧:

“在我们的社会中,计算机可能会明显增加封闭决策的倾向。”

自动化和遗忘太容易了,当伤害已经造成的时候才醒悟过来已经太晚了。Zillow 只是一个发现自动化过程失败的例子。断层很深。在大多数情况下,我们将决策视为时间点而非过程。

集体推理用连续的决策过程取代了决策作为时间点的概念。集体推理系统允许在数据从初始决策中出现时进行修改。

如果 Zillow 团队有一个包括与决策相关的原因和假设的模型会怎么样?当早期的结果从 iBuyer 推出时,是否有可能对策略进行修改或提供指导?让一个由具有房地产交易经验的人组成的认知多元化团队来审查算法所做的决策,这样做有意义吗?

决策过程允许在假设和证据出现时重新审视它们。决策过程最适合于复杂的、适应性强的环境,在这种环境中,由于问题本身的复杂性,结果的预测变得很困难。

问题 3:我们如何在部署的 AI 应用中建立信任?

黑盒模型可能是危险的。黑箱模型可以给不真实披上数学现实的外衣。如果要信任人工智能应用程序,就需要详细解释系统如何做出预测。

可解释性是在第一代人工智能中开发的几乎每个人工智能应用程序的核心特征,因为它是基于符号逻辑结构的。在第一代人工智能中,复杂逻辑和表示的可解释性是一种催化剂,能够解决以前逃避自动化的问题。可解释性创造了系统和用户之间的信任。

可解释性是集体推理系统的核心。例如,运行一个集体推理过程来为 iBuyer 程序提供资金将会产生一个分数。该分数代表决策小组对项目成功(或失败)的集体预测。此外,集体推理系统提供了支持得分的集体推理的详细解释。

未来之路:持续的、创造性的、协作性的学习

我们设想集体推理使决策过程成为可能,在这个过程中,创造性指导的机会总是存在的。在这个挑战迅速变化的时代,这是应对我们面临的挑战的适当框架。

我们生活在一个错综复杂的时代。我们面临的问题非常复杂,它们给预测结果带来了挑战。集体智慧提供了一个框架,通过结合人类和人工智能的精华,创造性地合作应对这些挑战。

我们太依赖于研究、计划、执行的阶段控制过程了。这些 20 世纪的工具——访谈、焦点小组和调查——已经导致文档和电子表格模型变得过时。这一过时的流程不再适应我们日常生活中所面临的时间框架。此外,它没有解决人和机器之间相互联系、纠缠和复杂的交互。

当我们考虑技术对我们日常生活的深度时,我们必须超越逻辑,拥抱整个人类体验。语言是表达人类对未来的决定、计划或信念的由衷反应的源泉。我们不仅仅是逻辑和信息。当我们的面孔和友谊生活在由计算模型驱动的设备中,为我们的情感镀金时,我们再也不能将信息技术划分为后台事件。

莫里森很久以前就发现了失败决策的根本原因。在他的书的两个章节中,人、机器和现代,他追溯了与军事重大创新相关的决策过程。这两个案例都有强有力的证据证明为什么创新会产生更好的结果,然而尽管有强有力的证据,这些创新却遇到了关于为什么它们不会起作用的强有力的争论。原因很微妙。如果一项创新导致个人的感知价值和身份受到威胁,他们会本能地寻求生存。杰伊·范·巴维尔和多米尼克·帕克最近在《T2:我们的力量》一书中谈到了这种身份的力量。

在合作过程中很难挖掘身份和生存问题。然而,理解一个决定背后的推理,在一个身份被掩盖的环境中挖掘观点、感觉和原因,是朝着正确方向迈出的重要一步。在一个特定的决定或预测的背景下,自由地发表我们的意见,打开了发现潜在直觉和感觉的大门。找到发现身份问题的安全方法对于创造创新文化至关重要。

在计算能力出现之初,埃尔廷·莫里森说:

"..情感在人的生活中有一种存在,一种身份,一套需求和要求,一种独立于自身的塑造性影响。人是存在的,不仅因为他思考,而且因为他感觉,正是这两种令人印象深刻的能量之间的相互作用,建立了今天人们所说的人类状况。……不重视受过教育的心灵的社会——或者不管情感的所在地是什么——将会灭亡。”一

我们如何看待我们在一个组织或社会中的个人身份,在我们如何做决定和如何看待未来方面起着巨大的作用。从来没有比这更真实的了:部落主义影响了我们处理信息的方式。企业界也不能幸免于部落潜流的负面影响。

集体推理包含自由形式的语言表达,旨在挖掘人类头脑中存在的复杂性。此外,它鼓励以建设性的摩擦分享想法,从而能够分享从合作中产生的新想法。集体推理提供了一条前进的道路。

我们赢在哪里

Zillow 的人工智能经历不应该动摇人工智能作为一门科学或创新源泉的信任基础。相反,它应该提高我们在决定如何部署和管理技术时的谨慎程度。我们必须适应。在 1950 年对加州理工学院的一次演讲中,埃尔廷指出:

“适应性..指的是一种韧性,它能使我们完全轻松地接受挑战性环境的最佳承诺,而不会失去我们的连续性意识或基本的完整性。

..建造不只是工作的机器,而是在人类自然反应和同情的范围内继续工作的机器。"

马丁·里维斯(Martin Reeves)的新书《想象机器》(The Imagination Machine)重申了人工智能开发人类认知的前景。

“因为人工智能是一种认知技术,除非我们重新思考商业的认知方面,否则我们不会受益——除非我们建立公司,培养和利用人类最有价值的思维能力,与智能算法合作。”

集体推理建立在这样一个概念上,即我们真正相信和感受的东西是可以用语言表达的。如果我们了解决策过程参与者的认知多样化群体在决策或项目的预期结果方面的能量一致性,我们就赢了。我们还必须不断挖掘集体想象力,以预见下一件大事。

  1. 埃尔廷·e·莫里森,《人、机器和现代》,50 周年纪念版,麻省理工学院出版社 2016 年
  2. 斯科特·佩奇,《差异》,第八章,《多样性和预测》,普林斯顿大学出版社,2007 年
  3. 结果是值得注意的,因为没有试图策划评估团队来平衡多样性。准确性和减少偏差直接归因于集体推理技术。

使用 UMAP 和 GMM 的嵌入空间中的流形聚类

原文:https://towardsdatascience.com/manifold-clustering-in-the-embedding-space-using-umap-and-gmm-dbab26a9efba?source=collection_archive---------25-----------------------

如何降低嵌入向量的维数并保持分组到簇中的流形结构。

马頔·瓦伦蒂娜在 Unsplash 上的照片

在上一篇文章使用 PyTorch 和 ResNeXt-WSL 从图片中提取丰富的嵌入特征中,我们已经看到了如何将图片表示到多维数字嵌入空间中。我们还看到了嵌入空间表示彼此接近的相似图片的有效性。在本教程中,我们将看到一些适用于发现和识别数据集中流形的聚类技术。
此外,提出的聚类技术也受到“文档嵌入平均化”的启发,这将在下一篇文章中描述。

通过均匀流形逼近和投影(UMAP)进行维数约简

降维不仅用于数据可视化,而且由于“维数灾难”,它也是聚类算法的一个基本步骤。换句话说,如果维度的数量增加,那么大部分的点将开始在至少几个维度上看起来相似和不同。结果是没有清晰的结构可循,导致数据点的随机分组。

无监督降维技术分为两类:线性投影和流形学习。

使用线性投影(例如 PCA、SVD)的流形学习的主要区别在于,它可以处理数据中的非线性关系,并且它对于聚类相似数据点的组保持它们的相对邻近性非常有效。对于我们的目的和给定的数据性质(由深度卷积神经网络产生的嵌入空间),我们不认为任何线性投影技术是合适的。

在多元学习家族中,有两个主要的竞争者:t-SNE 和 UMAP。

可可检测 2017 图片的 t-SNE 3d 投影由超级分类着色

UMAP 3d 投影可可检测 2017 图片由超级分类着色

t-SNE vs UMAP COCO detection 2017 的 3d 投影图片由 supercategory 着色

一致流形逼近和投影(UMAP)是一种通用的流形学习和降维算法。
T-分布式随机邻居嵌入(t-SNE)是一种算法,它生成低维图,试图保持相似的实例靠近,不相似的实例分开。

它们听起来很相似,事实上从很多方面来看都是如此。尽管如此,让我们总结一下出于集群目的而更喜欢 UMAP 而不是 SNE 霸王龙的几个原因:

SNE 与 UMAP 的比较

要更全面地比较 t-SNE 和 UMAP,请参考下面的文章:UMAP 到底是如何工作的

由于上面讨论的原因,我们可以得出结论,t-SNE 是一个伟大的可视化工具,但 UMAP 是一个更适合的技术,用于流形结构的聚类目的。

高斯混合模型聚类(GMM)

GMM 是一种概率模型,它假设所有的数据点都是由有限个参数未知的高斯分布混合生成的。可以看作是更流行的 k-means 模型的推广。与 k-means 相比,使用 GMM 的优势在于它可以基于参数协方差矩阵表示不同大小和形状的聚类。
在 k-means 中,簇在所有维度上都是球形的,并且具有相同的直径。当考虑流形特征空间时,这是一个很大的限制,如用 UMAP 变换深度卷积神经网络嵌入空间的情况。

使用 iris 数据集
( 来源)上的两个模型的不同聚类输出

另一个区别是对聚类输出的解释。k-means 将空间划分为 voronoi 单元,并将每个点硬分配给最近质心的聚类。另一方面,GMM 给了我们一个可解释的输出,它模拟了每个数据点属于每个聚类的概率。后者是用于处理存在重叠聚类或离群值的模糊情况的期望概率。

GMM 参数

和 k-means 一样,GMM 也要求指定聚类数 k。

此外,为了使 GMM 能够在特征空间中模拟任意椭圆形状,协方差矩阵应该是“完整的”。“全”GMM 模型的问题在于,自由度随着特征空间的维度成二次方地增加,存在过度拟合数据的风险。有几个 GMM 的约束版本会对协方差矩阵施加某些属性。,即:球形、对角线形和并列形。

使用不同协方差类型获得的聚类形状
(来源: scikit-learn )

  • 球形是圆形轮廓的“对角线”情况(更高维度的球形,由此得名)。
  • 对角线表示轮廓轴沿坐标轴定向,但除此之外,组件之间的偏心率可能不同。
  • 表示部件可以独立采用任何位置和形状。
  • 并列表示形状相同,但形状可以是任何形状。

现在我们只剩下两个主要参数需要调整:上面列出的 4 个选项中的聚类数 k 和协方差类型。

使用 BIC 和轮廓分数的模型选择

很可能,由于 GMM 是一个概率模型,我们可以计算贝叶斯信息标准(BIC ),这是一个统计计算为模型的负对数似然性和一个惩罚项,这是数据样本的数量和模型的自由参数的数量的函数。BIC 值越小,模型越可取。尽管如此,搜索最小 BIC 分数可能会建议选择一个在分数微小下降之前有很多聚类的模型。这就是为什么优选的方法是识别对应于二阶导数最小值的曲线的拐点。
只有当不同聚类输出表示相同特征空间中的相同点时,它们之间的 BIC 分数才是可比较的。也就是说,我们不能比较通过 PCA 减少的数据点和通过 UMAP 减少的数据点。

另一种技术是剪影评分,这是一种通过比较一个点与其聚类的相似程度(内聚力)与其他聚类的相似程度(分离度)来衡量聚类一致性的经验方法。轮廓的范围从 1 到+1,其中高值表示对象与其自己的簇匹配良好,而与相邻簇匹配较差。如果大多数对象都有一个高值,那么集群配置是合适的,否则集群配置可能有太多或太少的集群。

如果我们将 BIC 曲线和剪影曲线绘制为 4 种不同协方差类型的聚类数 k 的函数,我们将获得下图:

使用 BIC 和剪影分数的 GMM 模型选择。图片作者。

这些点分别对应于 BIC 和剪影曲线的肘部和最大值。

我们可以得出结论,理想的集群数量应该在 30 到 50 之间。
就协方差类型而言,束缚类型使 BIC 最小化,而没有强有力的证据表明轮廓曲线中的结果恶化。
较低的 BIC 分数可以通过低模型复杂性和点的高可能性之间的良好权衡来解释。此外,给定特征空间的性质,考虑不规则但相似形状的流形是有意义的。

用 40 个聚类训练的 GMM 模型的约束协方差矩阵。图片作者。

为我们选择的配置将是并列协方差类型和 40 个集群。

可视化集群

为了可视化聚类,我们将重新使用在中计算的 3D 投影,使用 PyTorch 和 ResNeXt-WSL 从图片中提取丰富的嵌入特征,但我们将基于分配的聚类而不是图片的 COCO 超级类别来着色点。

第一行:按可可类别(左侧)或 GMM 聚类(右侧)着色的 PCA 3D 投影。第二行:UMAP 三维投影,由可可类(左边)或 GMM 集群(右边)着色。

与可可分类学的比较

通过监督学习预测 COCO 注释

为了测量嵌入空间的预测能力,让我们尝试预测 COCO 注释。我们可以在多标签任务上用默认参数训练一个随机森林分类器。由于每张图片可以没有、一个或多个类别注释,任务包括预测给定标签是否出现在图片中。

我用 4000 张图片进行训练,用 1000 张图片对每张图片中最常见的标签进行分层测试。多标签准确度(sci kit-learn中定义的标签匹配的精确子集)将是 16.7%,考虑到任务的高基数,这并不坏。如果我们对所有标签预测进行微平均,我们可以执行二元评估:

多标签随机森林分类器的混淆矩阵

我们已经在所有可能的图片注释上实现了 89%的准确率和 31%的召回率,不算太差也不算太好。我们应该考虑到,我们只在非常小的图片样本上进行训练,并且少数标签出现的次数非常少。尽管如此,本教程的目的不是预测 COCO 类别,而是展示嵌入特性在识别正确流形中的有效性。

聚类相似性和一致性

因为我们已经将 COCO 图片分组为 40 个无监督的聚类,所以让我们将我们的分组与 COCO 分类法中提供的类别进行比较。我们可以使用调整后的 Rand 指数,它是两个聚类输出之间相似性的度量。分数越高,两个分组之间的一致性越高。

我们获得了以下结果:

  • adjusted rand(GMM _ 聚类,可可 _ 超级分类)= 0.09955
  • AdjustedRand(GMM 聚类,可可分类)= 0.08844

正如我们已经从 3D 投影中观察到的,我们可以得出结论,由数据中的流形定义的发现的主题性与 COCO 分类法不匹配。

群集中的图片

那么每个集群代表什么主题呢?
让我们打印几组样本中最接近质心的图片。

聚类 0:马

第三组:餐饮

第 10 组:海洋和水上运动

第 18 组:熊

第 22 组:塔楼

结论

在本教程中,我们学习了如何在图片的潜在嵌入空间中对图片进行聚类。我们首先用 UMAP 分离流形,并把它们投影到一个低维空间。然后我们用 GMM 发现了 UMAP 空间的高密度区域。BIC 肘和剪影技术被用来寻找理想的集群数量以及协方差矩阵的约束。通过 AdjustedRand 测试,我们证明了数据本质上被组织到与 COCO 分类法不匹配的主要主题中。例如,我们发现了马、熊、塔、水上运动、人们用餐等的集群。

所提出的方法可以用于聚类任何呈现高维流形的数据集,而不仅仅是图片。它通常适用于由神经网络模型产生的嵌入。

如果不使用预先训练好的网络,而是训练自己的网络,您可能希望考虑较小的维数(低于 50 ),以便在聚类之前不需要任何维数缩减。其他适用于任何形状且不受高斯混合假设约束的聚类算法是基于密度的分层模型,如 HDBSCAN

请继续关注下一篇文章,讨论如何利用嵌入特性和流形集群来平均和表示相同潜在空间中的数据点(文档)集合。

你可以在 https://github.com/gm-spacagna/docem 找到代码和笔记本。

如果你想了解更多关于数据聚类算法的调优技术,你可以阅读这些文章:数据聚类?不要担心算法数据聚类的分布式遗传进化调优:第 1 部分

原载于 2021 年 1 月 2 日 https://datasciencevademecum.comhttps://datasciencevademecum.com/2021/01/02/manifold-clustering-in-the-embedding-space-using-umap-and-gmm/

操作 PDF 文件,使用 PyPDF2 和正则表达式提取信息(第 2 部分)

原文:https://towardsdatascience.com/manipulate-pdf-files-extract-information-with-pypdf2-and-regular-expression-39ff697db0ca?source=collection_archive---------3-----------------------

使用 PyPDF2 和正则表达式简化 PDF 操作任务

照片由 Benoit GauzereUnsplash 拍摄

介绍

毫无疑问,现代科技使我们的生活变得容易了。甚至我们也无法想象没有现代技术的日子。自然语言处理是近来使用最多的技术之一。基本上,自然语言处理在我们的日常交流中起着重要的作用。如果我们开始了解对技术的见解,并能运用我们自己的技术,这将是我们的一大乐事。

最开始,我们要了解一下玩文本文件的各种技巧。如果你不熟悉,我推荐你看我之前的文章。

然后,我们需要了解如何从 pdf 或其他格式的文本文件中提取文本信息。但是在本文中,我们将讨论如何使用PyPDF2库来浏览 pdf 文档。从文本文件中提取信息的另一个最重要的工具是正则表达式。使用正则表达式,我们可以很容易地获得我们想要的信息,如电话号码、地址、电子邮件等等。特别地,正则表达式是一些符号和字母的组合,用于从成千上万的文本数据中获取我们想要的信息。

【注意——为了您的方便,我在结论的最后链接了文章的完整源代码。】

路标

本文旨在用 python 覆盖 NLP 的先决条件。以下主题将在下一篇文章中涉及。

第一部

  • PyPDF2概述
  • 阅读 PDF 文件
  • 向 PDF 添加文本
  • 从 PDF 中抓取所有文本

第二部分

  • Python re库概述
  • 搜索基本模式
  • 复杂模式概述
  • 使用量词的模式搜索
  • re库分组
  • or 运算符
  • 通配符
  • 以字符开始和结束
  • 将字符分散成字符串
  • 从字符串中删除标点符号
  • 用于分组的括号
  • 多个选项的括号
  • 实践问题

让我们开始吧

第一部分

接下来的部分是关于 python 的PyPDF2库,用于处理 PDF 文件。

  1. 概述 **PyPDF2**

你经常需要处理 PDF 文件。Python 中有许多用于处理 PDF 的库,每一个都有其优缺点,最常见的是 PyPDF2。您可以安装它(注意区分大小写,您需要确保您的大写匹配):

pip install PyPDF2

请记住,不是所有的 PDF 文件都可以用这个库读取。太模糊、有特殊编码、加密的 PDF,或者可能只是用不适合 PyPDF2 的特定程序创建的 pdf,将无法被读取。如果你发现自己处于这种情况,尝试使用上面链接的库,但是记住,这些也可能不起作用。这是因为 PDF 有许多不同的参数,而且设置可能非常不标准,因此文本可以显示为图像,而不是 utf-8 编码。这方面要考虑的参数很多。

就 PyPDF2 而言,它只能从 PDF 文档中读取文本,而不能从 PDF 中抓取图像或其他媒体文件。

2。阅读 PDF 文件

首先需要导入PyPDF2库如下

# note the capitalization
import PyPDF2

现在,我们打开一个 pdf,然后为它创建一个 reader 对象。注意我们是如何使用二进制阅读方法的,‘rb’,而不仅仅是‘r’

# Notice we read it as a binary with 'rb'
f = open('US_Declaration.pdf','rb')

阅读更多为什么用 [‘rb’](https://www.quora.com/What-does-opening-a-file-rb-in-Python-mean) 代替 [‘r’](https://www.quora.com/What-does-opening-a-file-rb-in-Python-mean)

这里,文件‘US_Declaration.pdf’位于与jupyter notebook文件位置相同的目录中。

你可以从这里下载 [*US_Declaration.pdf*](https://drive.google.com/file/d/115DPlPclA69A2VvIAfrRPoSRWA26SDvd/view?usp=sharing) 文件。

是时候读这一页的课文了。下面这段代码将帮助我们阅读 pdf 格式的页面。

#pdfFileReader() reads the text  form the pdf
pdf_reader = PyPDF2.PdfFileReader(f) #the following lines of code will output the number of pages of the pdf
pdf_reader.numPages#getPage()reads the text of a specific page. Here the parameter 0 indicates the first page of the pdf
page_one = pdf_reader.getPage(0)
page_one_text = page_one.extractText()
#Finally the extractText() extracts the the texts in a text format of page 1\. 

如果您运行上面的代码并想看看page_one_text变量包含什么,您会发现下面的输出。

作者照片

3。向 pdf 添加文本

我们不能使用 Python 编写 PDF,因为 Python 的单个字符串类型与 PDF 可能具有的各种字体、位置和其他参数之间存在差异。

我们能做的就是复制页面,把页面追加到最后。

我们将提供一个向新的 pdf 文件添加文本的例子。很简单。

f = open('US_Declaration.pdf','rb')
pdf_reader = PyPDF2.PdfFileReader(f)first_page = pdf_reader.getPage(0)#pdfFileWriter() enables to create a page
pdf_writer = PyPDF2.PdfFileWriter()#addPage() adds the content of first_page to a new page
pdf_writer.addPage(first_page)#The open() function with "wb" mode creates a document named "Some_New_Doc.pdf" to the directory
pdf_output = open("Some_New_Doc.pdf","wb")#finally we will get a pdf file with the contents of the first page of the previous pdf by write() function
pdf_writer.write(pdf_output)

搞定! 现在我们已经复制了一页,并添加到另一个新文档中!

4。从 pdf 文件中抓取所有文本

从上面的代码中,我们知道使用PyPDF2,我们一次只能阅读特定页面的文本。但是我们如何一次获得 pdf 的所有文本呢?有什么解决办法吗?耶!显然,一个简单的循环就可以解决这个问题。让我们看看实际情况。

f = open('US_Declaration.pdf','rb')# List of every page's text.
# The index will correspond to the page number.
pdf_text = [0]  # zero is a placehoder to make page 1 = index 1pdf_reader = PyPDF2.PdfFileReader(f)for p in range(pdf_reader.numPages):

    page = pdf_reader.getPage(p)

    pdf_text.append(page.extractText())

代码的和平将有助于把所有的文本保存到一个列表对象中。现在,我们可以像print(pdf_text[1])一样将索引插入列表,轻松打印出页面内容。它将打印第 2 页的文本。

【注意——使用 *f.close()* 命令关闭文档总是一个好习惯。】

第二部分

  1. 正则表达式概述

正则表达式(有时简称为 regex)允许用户使用他们能想到的几乎任何类型的规则来搜索字符串。例如,在字符串中查找所有大写字母,或者在文档中查找电话号码。

正则表达式因其看似奇怪的语法而臭名昭著。这种奇怪的语法是他们灵活性的副产品。正则表达式必须能够过滤掉你能想象到的任何字符串模式,这就是为什么它们具有复杂的字符串模式格式。

正则表达式使用 Python 内置的 re 库来处理。更多信息参见文档

让我们从解释如何在字符串中搜索基本模式开始!

2。搜索基本模式

假设我们有以下字符串:

text = "The agent's phone number is 408-555-1234\. Call soon!"

我们将首先尝试找出字符串“phone”是否在文本字符串中。现在,我们可以通过以下方式快速做到这一点:

'phone' in text

它将返回在语句中找到的True

但是让我们来展示正则表达式的格式,因为稍后我们将搜索没有如此简单解决方案的模式。看一个使用 python 正则表达式库re的简单例子。

首先,

import re

现在,

pattern = 'phone'
re.search(pattern,text)

输出

<_sre.SRE_Match object; span=(12, 17), match='phone'>

表示phone与变量text的字符串匹配,并且存在该字符串的1217索引。另一个例子可以如下。

pattern = "NOT IN TEXT"
re.search(pattern,text)

它不会返回任何内容,因为没有找到匹配。现在我们已经看到 re.search()将获取模式,扫描文本,然后返回一个匹配对象。如果没有找到模式,则返回 None。

让我们仔细看看这个匹配对象。跨度match.span()有开始和结束索引。如果我们运行代码match.start(),它将输出12。另一方面,match.end()输出匹配字符串的结束索引,即17

但是如果这种模式出现不止一次呢?

text = "my phone is a new phone"
match = re.search("phone",text)

它将返回输出<re.Match object; span=(3, 8), match=’phone’>。请注意,虽然字符串phone有 2 个匹配,但只找到第一个匹配。

如果我们想要所有匹配的列表,我们可以使用.findall()方法:

matches = re.findall("phone",text)

输出

['phone', 'phone']

如果您想要匹配的实际文本,您可以使用.group() 方法。

match.group()

输出

'phone'

3。复杂模式概述

到目前为止,我们已经学习了如何搜索一个基本字符串。更复杂的例子呢?比如试图在一大串文本中找到一个电话号码?或者电子邮件地址?

如果我们知道确切的电话或电子邮件,我们可以使用搜索方法,但如果我们不知道呢?我们可能知道一般的格式,我们可以使用它和正则表达式在文档中搜索匹配特定模式的字符串。

这是语法开始看起来奇怪的地方,但是要慢慢来;通常只需要查找模式代码。

我们开始吧!

4。模式中字符的标识符

数字或单个字符串等字符有不同的代码来表示。您可以使用这些来构建模式字符串。注意这些是如何大量使用反斜线\ 的。因此,在为正则表达式定义模式字符串时,我们使用以下格式:

r'mypattern'

将 r 放在字符串前面可以让 python 理解模式字符串中的 \ 不是转义斜杠。

下面是所有可能标识符的列表:

你可以边工作边看表格,因为记住这些符号是不可能的。

请看下面的代码

text = "My telephone number is 408-555-1234"
phone = re.search(r'\d\d\d-\d\d\d-\d\d\d\d',text)
phone.group() #there are three groups separated with (-) symbol

输出

'408-555-1234'

注意\d的重复。这有点麻烦,尤其是当我们在寻找很长的数字串时。量词让这个任务变得简单了。

5。使用量词的模式搜索

让我们探索可能的量词。

现在,我们知道了特殊的字符标识,我们可以使用它们和量词来定义我们期望的数量。我们不需要重复使用标识符。

让我们使用这些量词重写我们的模式:

text = "My telephone number is 408-555-1234"
phone = re.search(r'\d{3}-\d{3}-\d{4}',text)
phone.group()

代码的输出和前面的一样。但现在它似乎很容易,可以很容易地用于复杂和大的模式。

6。组有 **re**

如果我们想做两个任务,查找电话号码,但也能够快速提取他们的区号(前三位数字)的上述例子。我们可以将组用于任何涉及到将正则表达式组合在一起的常规任务(以便我们稍后可以分解它们)。

以电话号码为例,我们可以使用括号分隔正则表达式组:

# The entire result
results.group()

输出

'408-555-1234'

然后

# Can also call by group position.
# remember groups were separated by parentheses ()
# Something to note is that group ordering starts at 1\. Passing in 0 returns everything
results.group(1)

这段代码返回第一组(电话号码的 3 位数)。

7。 **or**

使用钻杆操作器进行定位。例如

re.search(r"man|woman","This man was here.")

输出

<_sre.SRE_Match object; span=(5, 8), match='man'>

又..

re.search(r"man|woman","This woman was here.")

输出

<_sre.SRE_Match object; span=(5, 10), match='woman'>

8。通配符

使用“wildcard”作为一个位置,它将匹配放置在那里的任何字符。可以用简单的句号为此。例如:

re.findall(r".at","The cat in the hat sat here.")

输出

['cat', 'hat', 'sat']

假设,我们想匹配前 3 个字母。

re.findall(r"...at","The bat went splat")

它生成类似[‘e bat’, ‘splat’]的输出。请注意,我们只匹配了前 3 个字母,这是因为我们需要为每个通配符字母添加一个 **.** 。或者使用上面描述的量词来设置自己的规则。

如果我们想要以“at”结尾的单词,应该怎么做?

# One or more non-whitespace that ends with 'at'
re.findall(r'\S+at',"The bat went splat")

上面的代码已经完成了工作并返回输出[‘bat’, ‘splat’]

9。开始和结束字符

我们可以用来查找以字符开头的, $ 来查找以字符结尾的:

# Ends with a number
re.findall(r'\d$','This ends with a number 2')# Starts with a number
re.findall(r'^\d','1 is the loneliest number.')

上面的代码返回[‘2’][‘1’]作为字符串的结束和开始字符。

注意,这是针对整个字符串,不是针对单个单词!

10。分散字符串中的字符

为了排除字符,我们可以将^符号与一组方括号[] .一起使用,方括号内的任何内容都被排除在外。例如:

phrase = "there are 3 numbers 34 inside 5 this sentence."
re.findall(r'[^\d]',phrase)

输出

['t',
 'h',
 'e',
 'r',
 'e'
....]

11。去除标点符号

test_phrase = 'This is a string! But it has punctuation. How can we remove it?'
re.findall('[^!.? ]+',test_phrase)

它将只返回单词。

['This',
 'is',
 'a',
 'string',
 'But',
 'it',
 'has',
 'punctuation',
 'How',
 'can',
 'we',
 'remove',
 'it']

我们可以把这个词按如下顺序连接起来。

clean = ' '.join(re.findall('[^!.? ]+',test_phrase))
clean

它将返回不带标点符号的字符串。

'This is a string But it has punctuation How can we remove it'

12。用于分组的括号

如上所示,我们可以使用括号将选项组合在一起,例如,如果我们想要查找带连字符的单词:

text = 'Only find the hypen-words in this sentence. But you do not know how long-ish they are'
re.findall(r'[\w]+-[\w]+',text)

输出

['hypen-words', 'long-ish']

13。多个选项的括号

如果我们有多个匹配选项,我们可以使用括号列出这些选项。例如:

*# Find words that start with cat and end with one of these options: 'fish','nap', or 'claw'*text **=** 'Hello, would you like some catfish?'re.search(r'cat(fish|nap|claw)',text)

输出

<_sre.SRE_Match object; span=(27, 34), match='catfish'>

14。练习题

这是额外的任务。我已经上传了一个 jupyter 笔记本文件到github。你可以从这里下载文件,并根据指示填写单元格。有六项任务。试着做你自己的。我认为这很容易,也很有趣。如有任何问题或困惑,请在下面评论。

MUnsplash 上拍照

结论

我认为我们学到了很多。虽然主题和语法很简单,但对于自然语言处理(NLP)和其他数据科学任务来说,它们非常重要。我已经开始将这些文章作为一系列 NLP。从下一篇文章中,我们将学习 NLP 的核心基础知识。和我保持联系。

第一部分完整的 Jupyter 笔记本如下

**https://github.com/Zubair063/ML_articles/blob/fe3aabe41a68f1b0a305e63dd38cb91b5445d9bd/PDF manupulation an regular expression/Working-with-PDF-Text.ipynb

找到下面给出的完整正则表达式源代码

https://github.com/Zubair063/ML_articles/blob/fe3aabe41a68f1b0a305e63dd38cb91b5445d9bd/PDF manupulation an regular expression/Regular-Expressions.ipynb

祖贝尔·侯赛因

  • 如果你喜欢这篇文章,请关注我的 中型 了解更多。
  • LinkedIn上连接我进行协作。**

用 OpenCV 和 Dlib 操作面部特征

原文:https://towardsdatascience.com/manipulating-facial-features-with-opencv-and-dlib-14029f136a3d?source=collection_archive---------21-----------------------

如何使用 OpenCV 和 Dlib 在图片上使用虚拟口红的快速教程。

这位女士用的是虚拟口红!照片由科托姆布罗,https://www.pexels.com/@cottonbro

这是一个关于如何使用 OpenCV 和 Dlib 在图像上应用虚拟口红的快速教程。同样的原则也可以延伸到其他面部特征,比如某人的眼睛、鼻子、下巴……要有创意。

为了达到上图所示的效果,我们需要执行以下步骤:

  1. 检测面部标志
  2. 使用包含嘴部标志的凸多边形创建一个遮罩
  3. 用形态学操作增强蒙版,模糊蒙版以获得更好的混合效果
  4. 隔离嘴唇和脸
  5. 对嘴唇应用颜色变换
  6. 将嘴唇和脸合在一起

首先要做的是检测人脸的面部标志。库 Dlib 提供了一种方便的方法来实现它;但是,请记住,拍摄对象的脸需要面向摄像机。如果头部的姿态不对,检测结果不会很好。

面部标志

在这个例子中,我们只对嘴唇的点感兴趣。下图是 Dlib 返回的面部标志点的索引。如你所见,我们感兴趣的是点 48 到 60(嘴唇的外部“轮廓”)。

来自 iBUG 300-W 数据集的 68 个面部标志坐标(来源:【https://www.pyimagesearch.com/】T2

利用这些点,我们可以建立一个面具,让我们在不影响面部整体外观的情况下处理嘴唇的颜色。但是坚持住。在我们开始处理这些颜色之前,我们需要改进蒙版。在这个例子中,具有 4×4 矩形核的形态学闭合操作就足够了。请注意下图,该步骤填充了由 cv2.fillConvexPoly 函数生成的原始多边形右上角的一个间隙。

右:使用 lips 界标创建的凸多边形/左:闭合操作后的多边形

为了得到自然的效果,我们还需要模糊蒙版。模糊蒙版将产生更好的混合。我们通过应用 cv2 来做到这一点。高斯布鲁到面具。最后,我们倒置面具(我们将需要两个,一个为嘴唇,一个为脸)。

右:模糊遮罩/左:模糊反向遮罩

我们将应用这些遮罩,将它们从 0–255(uint 8)转换到 0–1(浮点)范围,然后乘以图像。下面右边的图像是原始图像乘以反转遮罩。左边的图像是原始图像的颜色变换乘以蒙版的结果。颜色转换由 cv2.applyColorMap(im,cv2。COLORMAP_INFERNO)。

右:原始图像和反模糊蒙版的按位与/左:颜色变换图像和模糊蒙版的按位与

现在,剩下要做的就是把这两幅图像加在一起。

右:原始图像/左:结果图像

我希望你喜欢这个简短的教程。如果你有更好的方法或者你有什么建议,请在评论中告诉我。(对了,我老婆说从来不允许我选择她的口红颜色。不知道她是什么意思。)

这是代码。尽情享受吧!

import cv2
import dlib
import faceBlendCommon as face
import numpy as np# Load Image
im = cv2.imread("cv2/girl-no-makeup.jpg")# Detect face landmarks
PREDICTOR_PATH = r"C:\Users\felipe.cunha\Documents\venv\cv2\week1-pyton\data\models\shape_predictor_68_face_landmarks.dat"faceDetector = dlib.get_frontal_face_detector()
landmarkDetector = dlib.shape_predictor(PREDICTOR_PATH)
landmarks = face.getLandmarks(faceDetector, landmarkDetector, im)# Create a mask for the lips
lipsPoints = landmarks[48:60]
mask = np.zeros((im.shape[0], im.shape[1], 3), dtype=np.float32)
cv2.fillConvexPoly(mask, np.int32(lipsPoints), (1.0, 1.0, 1.0))
mask = 255*np.uint8(mask)# Apply close operation to improve mask
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (40,40))
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, 1)# Blur the mask to obtain natural result
mask = cv2.GaussianBlur(mask,(15,15),cv2.BORDER_DEFAULT)# Calculate inverse mask
inverseMask = cv2.bitwise_not(mask)# Convert masks to float to perform blending
mask = mask.astype(float)/255
inverseMask = inverseMask.astype(float)/255# Apply color mapping for the lips
lips = cv2.applyColorMap(im, cv2.COLORMAP_INFERNO)# Convert lips and face to 0-1 range
lips = lips.astype(float)/255
ladyFace = im.astype(float)/255# Multiply lips and face by the masks
justLips = cv2.multiply(mask, lips)
justFace = cv2.multiply(inverseMask, ladyFace)# Add face and lips
result = justFace + justLips# Show result
cv2.imshow("", result)
cv2.waitKey(0)

处理熊猫数据框中的值

原文:https://towardsdatascience.com/manipulating-values-in-pandas-dataframes-a84fe35a190?source=collection_archive---------24-----------------------

知道何时使用 map()、apply()和 applymap()

安妮·斯普拉特在 Unsplash 上的照片

数据分析中的一个常见任务是处理数据帧中的值。对于那些熟悉熊猫的人来说,你知道通常你有三个函数可以使用——map()apply()applymap() 。然而,通常不清楚什么时候应该使用哪一个,有时每个函数的工作原理都很混乱。

这篇文章试图让你明白每个函数是如何工作的,以及什么时候你应该使用什么。

各种功能的快速总结

首先,让我们快速浏览一下每个功能的定义:

  • map() —对序列应用函数
  • apply() —将函数应用于序列或数据帧(沿两个轴中的一个)
  • applymap() —对数据帧元素应用函数

记住它们如何工作的最好方法是使用下表来总结它们:

如您所见, map() 函数仅适用于系列, applymap() 函数仅适用于数据帧,而 apply() 函数可用于系列或数据帧。

与其解释每个函数的用法,不如让我们通过陈述你试图解决的问题来解决这个问题。

修改单列值

如果您想修改数据帧中的一列值,使用 map() 函数很容易做到。考虑以下 AAPL 数据集(https://finance.yahoo.com/quote/AAPL/history/):

import pandas as pd
df = pd.read_csv('AAPL.csv')
df

假设您想要重新格式化日期,使其现在以下列格式显示:

Dec 24, 2018 (Mon)

一种简单的方法是将日期列作为一个序列,然后对其使用 map() 函数。以下代码片段将日期值转换为我们想要的格式:

from datetime import datetimedef format_date(x):
    return datetime.strptime(x, '%Y-%m-%d').strftime(
        '%b %d, %Y (%a)')df = pd.read_csv('AAPL.csv')df['Date'] = **df['Date'].map(format_date)**
df

format_date() 函数中,参数 x 是字符串类型(日期列的每个值)。例如“2018–12–24”)。为了转换成我们想要的日期格式,我首先使用 strptime() 将给定的字符串转换成一个 datetime 对象,然后使用 strftime() 函数将 datetime 对象转换成想要的字符串格式。然后使用 map() 函数(这是一个序列)的结果来更新日期列。

更新后的数据帧现在如下所示:

您也可以使用 apply() 函数达到同样的目的,因为它也适用于序列。以下代码片段显示了如何使用 apply() 函数实现上述步骤:

df = pd.read_csv('AAPL.csv')
df['Date'] = **df['Date'].apply(format_date)** 
df

修改数据帧中的多列值

假设现在除了更改日期格式之外,您还需要将 Close 列中的值向下舍入到两位小数。在这种情况下,使用 apply() 函数会很有用,因为它适用于数据帧。

以下代码片段显示了如何修改日期列中值的日期格式,以及如何对结束列执行舍入:

from datetime import datetimedef format_date2(x): 
    x['Date'] = datetime.strptime(
        x['Date'], '%Y-%m-%d').strftime('%b %d, %Y (%a)')
    x['Close'] = round(x['Close'],2)
    return xdf = pd.read_csv('AAPL.csv')
df = **df.apply(format_date2, axis=1)**   
df

这一次,您在数据帧上使用 apply() 函数。在 format_date2() 函数中,参数 x 现在将是一个序列(包含每一行,因为我们指定了 axis=1 )。

在该函数中,我们首先修改日期值,然后对收盘值进行舍入。结果将如下所示:

在数据帧上使用 apply() 功能时,可以指定参数(0 或 1)。但是,当您在系列上使用 apply() 功能时,不支持参数。

当您在设置为 1 的数据帧上使用 apply() 函数时,您可以将其视为遍历数据帧中的每一行,然后将所有 作为一个序列,如下图所示。

另一方面,如果将指定为 0,它现在将遍历数据帧中的每一列,然后将所有 作为一个序列,如下图所示:

组合数据帧中的列

这里是另一个数据集,我将使用它来说明在数据帧上使用 apply() 函数。这次我将使用来自 http://www.weather.gov.sg/climate-historical-daily/的降雨数据集。

df = pd.read_csv('DAILYDATA_S24_202107.csv')
df

数据帧看起来像这样:

该数据集包含新加坡 2021 年 7 月 31 天每天的降雨量(以及温度和风速等其他要素)。

假设我想将三个独立的列— 合并成一个列— 。这是使用 apply() 函数的好时机:

import datetimedf['Date'] = **df[['Year','Month','Day']].apply(
    lambda x: datetime.date(** # x is a series **int(x['Year']),
        int(x['Month']),
        int(x['Day'])), 
    axis=1)**
df

您首先提取想要作为数据帧的三列(),然后对其使用 apply() 函数。当您指定 axis=1 时,dataframe 的每一行(包含三列— )将作为一个序列( x )传递给 lambda 函数。现在,您可以使用序列中的值来创建一个 datetime.date 对象。现在在数据帧中创建了一个新列( Date ),用于存储新创建的 datetime.date 对象(数据帧中的最后一列):

列或行值的聚合

有时需要聚合数据帧中特定列的值。例如,使用降雨量数据集,您可能想要计算该月的平均日降雨量。在这种情况下,您可以使用 apply() 功能,将参数设置为 0:

df[['Daily Rainfall Total (mm)']].apply(lambda x: x.mean(),
    axis=0)

当您为 apply() 函数指定 axis=0 (或者省略它,因为这是默认值)时,dataframe 中的每一列都将作为一个序列传递给 lambda 函数:

假设您想获得整个月的平均降雨量和平均温度。您可以首先提取降雨量和温度这两列,然后使用 apply() 函数:

df = pd.read_csv('DAILYDATA_S24_202107.csv')**df[['Daily Rainfall Total (mm)','Mean Temperature (°C)']].apply(
    lambda x: x.mean()**,
    axis=0)

结果将是一系列:

Daily Rainfall Total (mm)     6.316129
Mean Temperature (°C)        28.619355
dtype: float64

如果你想计算降雨量的平均值和温度的中值呢?在这种情况下,您可以使用序列的名称属性来标识每一列。以下示例向您展示了如何操作:

def aggregate_columns(x):
    if **x.name** =='Daily Rainfall Total (mm)':
        return x.mean()
    if **x.name**=='Mean Temperature (°C)':
        return x.median()

**df[['Daily Rainfall Total (mm)','Mean Temperature (°C)']].apply(
    aggregate_columns,
    axis=0)**

结果将如下所示:

Daily Rainfall Total (mm)     6.316129
Mean Temperature (°C)        **29.200000**
dtype: float64

变换数据帧中的元素

到目前为止,我们的讨论一直集中在对数据帧执行按行或按列的操作上。然而,有些时候你并不真正关心你的值被计算的顺序,只要它们被计算。我们之前使用的 AAPL 数据集就是一个很好的例子。假设您需要将打开关闭调整关闭列中的所有数字四舍五入到两位小数:

我们是按行还是按列处理它们有关系吗?没有。只要能四舍五入到小数点后两位,我们就很高兴了。这是一个使用 applymap() 函数的完美例子。 applymap() 函数将遍历数据帧中的每个元素,并执行指定的功能。以下代码片段显示了这是如何实现的:

df = pd.read_csv('AAPL.csv')
**df[['Open','High','Low','Close','Adj Close']] = \
    df[['Open','High','Low','Close','Adj Close']].applymap(
        lambda x: round(x,2))** 
df

所选数据帧中的每个元素都将作为参数传递给 lambda 函数。

指定列中的值现在四舍五入到两位小数:

结论

我希望这篇文章已经让您清楚地决定了什么时候应该使用 map()apply()applymap() 函数。总而言之:

  • 如果你想修改数据帧中的一列,使用 map()
  • 如果你想一次修改数据帧中的几列,使用 apply()
  • 如果想对数据帧中的列或行执行聚合函数,使用 apply()
  • 如果您想修改数据帧中的值,而不用担心是按行还是按列执行,请使用 applymap()

为持续学习而操纵信息空间

原文:https://towardsdatascience.com/manipulation-of-information-space-for-continual-learning-2a758b728cee?source=collection_archive---------41-----------------------

VeriMedi 项目动机文章—持续学习、深度度量学习、调整信息理论

让我们从一些问题开始:

假设我有两个概念,比如巧克力曲奇和布朗尼。如果我说巧克力曲奇的值是 0,布朗尼的值是 1,这是不是一个错误的说法?

给出不同的值有助于我区分巧克力曲奇和核仁巧克力饼。如果我用相同的价值来代表两者,当我品尝它们的时候,我能认出它们的不同吗?如果我不能区分它们,那它们还会是信息吗?

这个帖子是关于信息的表示和信息操作的实现。本文中产生和呈现的想法和方法是为我在工作中参与的一个创新项目——药丸识别项目而设计的:链接到预印本
所以,让我们从信息开始。信息是当存在两个或两个以上不同事实时出现的现象。当信息所代表的事实能够被感知它的人获得和区分时,信息就能够被识别和获得。所以,要创造信息,就应该有不同的事实,而且它们需要被感知它的人感知为两个或两个以上不同的事实。这是森林故事里的经典树。如果一棵树在森林里倒下了,这是信息吗?既然没人观察,没人知道,没人听见,那就不是。

帕特·惠伦Unsplash 上的照片

信息是可以测量的,而且是通过信息的熵来测量的。根据 Shannon 的说法,信息的熵不是由感知者感知的数据量,而是由感知者感知的不同数据量。那么,什么是信息熵呢?信息熵是定义信息的概念的分布。想象一个向量,一个箭头,从你的电脑到厨房的水槽。这个向量代表一个概念。如果这是该空间中唯一的向量,则该信息不存在。当从你的电脑到门有第二个矢量,那么信息就存在了。因为我们可以说,电脑和水槽之间的矢量,和电脑和门之间的矢量是不一样的。信息不是矢量之间的差。信息是当这两个向量之间存在差异时出现的现象。

我们如何测量两个向量之间的差异?我们可以测量它们之间的欧几里德距离。此外,向量的方向可以不同,这意味着两个向量之间的余弦相似性可以帮助我们测量它们之间的差异。如果我们想用一个向量来表示一个概念呢?我们如何做到这一点?我们可以为这个概念指定任何向量。在主流分类模型中,表示概念的向量是二元向量。例如:概念 1 是 0001,而概念 2 是 0010,概念 3 是 0100,概念 4 是 1000。但问题是“我们能用非二进制的向量来表示概念吗?”。是的,我们可以。基于代理的深度度量学习模型正是这样做的。他们为每个类定义代理多维向量,然后尝试使输入数据适合这些代理。深度度量学习中使用了两种基于代理的损失函数:代理 NCA 损失(链接)和代理锚点损失(链接)。不幸的是,这两个损失函数都与代理的初始化无关。因此,当代理的向量大小不够大时(相对于向量所代表的代理的数量),这些代理有可能彼此接近。此外,我们知道,当代表代理的向量足够明显时,信息就出现了。所以,我们定义的代理向量应该尽可能地远离彼此,这样我们才能更好地表示信息。我们需要能够操纵这个代表性的信息空间。为了做到这一点,我开发了一种优化方法,它将一组向量(代理)作为输入,并通过使用梯度下降来分解它们,以便它们的方向将是不同的。

要使这种方法奏效,需要遵循几个步骤:

  • 定义正态分布的代理
    定义一个线性层来分配代理。
  • 将所有代理注册为参数,以便更新它们。
  • 计算每个二进制代理组合中代理之间的余弦相似度。
  • 计算余弦相似度和零向量之间的损失。
  • 反向传播丢失,以便更新代理。

很简单,对吧?

代码如下:

首先,让我们定义 l2_norm 和计算向量的二进制组合之间的余弦相似性的相似性函数:

import itertoolsdef l2_norm(self, x):
    input_size = x.size()
    buffer = torch.pow(x, 2)
    normp = torch.sum(buffer, 1).add_(1e-12)
    norm = torch.sqrt(normp)
    _output = torch.div(x, norm.view(-1, 1).expand_as(x))
    output = _output.view(input_size)
    return outputdef sim_func(base_proxies):
    layers = l2_norm(base_proxies)
    combinations = list(itertools.combinations(np.arange(0,len(layers)), 2))
    sim_mat = torch.nn.functional.linear(layers, layers)
    similarity_vector = torch.zeros(len(combinations))
    for cnt,comb in enumerate(combinations):
        similarity_vector[cnt] = sim_mat[comb[0],comb[1]]
    return similarity_vector

现在,让我们定义稍后将处理分解操作的代理和类。我将把 sim_func 和 l2_norm 放在这个类中。

class ProxyOperations(torch.nn.Module):def __init__(self, base_proxies = None):
        super(ProxyOperations, self).__init__()
 if base_proxies == None:
            base_proxies = torch.randn(4, 2)
            torch.nn.init.kaiming_normal_(base_proxies, mode='fan_out')
        self.base_proxies = torch.nn.Parameter(base_proxies) def l2_norm(self, x):
        input_size = x.size()
        buffer = torch.pow(x, 2)
        normp = torch.sum(buffer, 1).add_(1e-12)
        norm = torch.sqrt(normp)
        _output = torch.div(x, norm.view(-1, 1).expand_as(x))
        output = _output.view(input_size)
        return output def sim_func(self):
        layers = l2_norm(self.base_proxies)
        combinations = list(itertools.combinations(np.arange(0,len(layers)), 2))
        sim_mat = torch.nn.functional.linear(layers, layers)
        similarity_vector = torch.zeros(len(combinations))
        for cnt,comb in enumerate(combinations):
            similarity_vector[cnt] = sim_mat[comb[0],comb[1]]
        return similarity_vector

现在,让我们在某个地方定义类,然后开始分解过程。

POP = ProxyOperations()
optimizer = torch.optim.Adam(POP.parameters(), lr=0.1)
lossfunc = torch.nn.MSELoss()
POP.train()cnt = 0
max_iter = 100
desired_sim_score = 0.1
loss_max = 1.while loss_max>desired_sim_score:
    optimizer.zero_grad()
    distance_vector = POP.sim_func()
    loss_mse = lossfunc(distance_vector, torch.zeros(distance_vector.shape)) loss_max = torch.max(torch.abs(distance_vector-torch.zeros(distance_vector.shape)))
    loss_mse.backward()
    optimizer.step()
    cnt += 1
    if cnt+1>max_iter:
        break

好的,我们的分解过程将最多运行 100 次迭代。我仅为本文创建了这段代码。不幸的是,我不能分享原始代码,因为知识产权和版权的东西。如果你出于非商业原因想要实施这个系统,你可以通过阅读论文来实现:)如果你是一家需要这个系统(持续学习模式)的公司,你需要通过我在论文中写的电子邮件再次联系我。

让我们继续这个话题:

使用这种方法,我们定义的代理在它们的方向上彼此远离。在代理被定义和优化之后,我们可以用新的代理来训练我们的网络。

现在该说说第二种方法了:代理添加。

因为我们可以优化代理并操纵信息空间,所以我们也可以向信息空间添加新的向量,以便我们可以向模型引入新的类,使其能够预测。想象一个分类模型,当需要一组新的类时,您不必从头开始重新创建和重新训练。不错吧。

所以现在,让我们想象一下我们如何做到这一点。我们是否可以创建一组数量更大的新代理,然后优化它们?这可能行得通,但不太合适。如果我们从头开始定义新的代理,那么模型将会很混乱,因为它已经学会了将你的输入图像映射到现有的代理(与以前的不同)。因为当你定义一个新的更大的代理集合时,你失去了之前的代理,在那里你的模型已经用来学习你之前输入的图像。

我们是否可以在现有的代理中添加新的代理,然后优化所有要分解的代理?这个想法比第一个好,但还不够好。因为我们添加的新代理将是随机的,当其他代理与这些新代理一起被分解时,它们将受到极大的影响。这意味着模型所学的将毫无意义,因为我们的初始代理已经再次发生了很大变化。此外,新的代理可能会比模型在当前状态下产生的代理更加不同。这又会增加训练的复杂性。

另一个想法是:如果我们生成属于新类别的图像的嵌入向量(使用初始代理预先训练的模型),然后将这些嵌入向量用于新代理,会怎么样?这是可行的,让我们继续这个想法。因此,在生成嵌入向量之后,我们可以计算每个新类的平均向量,然后将这些平均向量作为新的代理添加到先前的代理集中。通过这样做,我们的旧代理不受影响,新代理是模型已经生成的向量。因此,我们不会增加这些新代理的训练复杂性。这听起来不错。但是,如果新生成的代理接近现有的代理呢?这里还有一个问题,我们来解决一下。我们需要优化这些新代理,使它们彼此远离,也远离旧代理。因为我们的新代理的起点将接近模型的当前状态,所以我们的训练复杂性将尽可能小。这说起来容易,但是在项目过程中很难实现。

实现这一想法有几个步骤:

  • 生成属于新类别的图像的嵌入向量。
  • 计算每个类别的平均向量,并将这些平均向量定义为候选代理。
  • 将候选代理附加到旧代理,并仅将新代理注册为要更新的参数。
  • 按照前面分解新代理的方法运行优化。

耶,我们成功了!但是等等,还有提升的空间。

在我们适当地扩大我们的代理空间之后,我们仍然可以通过优化这个新的、更大的代理集来尽可能地相互分解,从而增强我们的代理空间。所以,我们基本上可以再次运行第一次优化。现在,我们准备好了,☺

详细信息请阅读论文预印本(链接在上面)。

我们在本文中还应用了一项创新。如果你读过我以前的一篇文章(conv·托奇求解文章),你就会知道,利用线性代数的精确解,只需一步就可以训练出一个卷积层。有趣的巧合是,澳大利亚的研究人员发表了一篇做类似事情的论文(链接到论文)。基本上,他们用梯度下降法训练 CNN 只需几次迭代。然后,他们采用倒数第二层,并为其计算最佳权重,以最佳方式将输入映射到输出。我强烈建议你读读那篇论文,它太棒了!

所以,回到正题。我们所做的是,在我们的识别解决方案中,我们实施了经过精确解决方案训练的全连接层。我们不是一开始训练一个经典的 CNN,而是训练一个深度的度量学习模型来生成嵌入。我们认为,我们可以使用精确的解决方案来训练完全连接的层,以将生成的嵌入向量映射到输出向量,输出向量是表示类的二进制向量。你知道吗,这招很管用。

请查看论文中的实验部分,查看我们所做的不同实验的结果。

现在,我们有了一个可以像人类一样不断学习的模型。在用新的类训练后,它甚至可以对以前学习的类给出更好的预测。这是有意义的,因为它有能力更好地解释知识。

请查看论文中的进一步研究部分(链接在上面)。这个新系统还有很多工作要做。

我的下一篇文章将是关于我在进一步研究部分提到的方法。

为大家干杯,我希望你们喜欢这篇文章和报纸。

链接到纸质预印本

马诺娃

原文:https://towardsdatascience.com/manova-97e675a96158?source=collection_archive---------1-----------------------

用 R 和 Python 编写的示例深入研究 MANOVA

马诺娃。照片由 Unsplash 上的 Nick Fewings 拍摄。

方差分析

ANOVA 是方差分析的简称,也叫 AOV ,是一种主要用于假设检验的统计方法。方差分析最常见的用例是当你做一个实验,其中你的结果变量是数字,而你的解释变量是一个有三个或更多类别的分类变量。

ANOVA 用于统计假设检验。如果您还不熟悉假设检验,我强烈建议您先阅读这篇文章。

使用 ANOVA 的示例研究

一个例子是对一种新的农作物生长产品的试验,在这个试验中,你要衡量两种新的处理方法和一个对照组的表现。您在三个组(处理 1、处理 2 和对照)中测量数字结果(例如收获的千克数)。

为了统计的有效性,你需要多次应用每种处理。想象一下,你在 15 个支线剧情中切割了你的农田,你做了 5 次治疗 1,5 次治疗 2,5 个支线剧情都没有(对照)。

然后计算每次处理的平均收获公斤数,你会发现平均值存在差异。但是,您需要定义差异是否大到足以说明结果 显著不同 并且差异不仅仅是由于一些随机变化。

这就是方差分析的用途。当然,许多领域的许多研究都遵循完全相同的设置(三个或更多独立组和一个连续结果变量)。

你可以查看这篇文章,了解更多关于方差分析和高级选项的详细内容。

马诺娃

MANOVA 是 ANOVA 模型的多变量版本。这里的多变量表示有多个因变量而不是只有一个的事实。

MANOVA 分析的目标仍然是检测相对于其他组是否有治疗效果。然而,这种影响现在是通过多个连续变量而不是一个变量来衡量的。

一个方差分析与多个方差分析

你可以对每个因变量进行单独的方差分析,得到的结果与方差分析方法没有太大的不同。

然而,非常可能的是,MANOVA 发现了显著的治疗效果,而这种效果在对每个单独的因变量进行单独的 ANOVA 时不会被发现。

马诺娃:多元统计的一部分

现在,不要把 MANOVA 看作 ANOVA 的多变量替代,我们也可以把 MANOVA 描述为多变量统计领域的一个工具。

家族多元统计中的其他方法有结构方程建模多维标度主坐标分析典型相关分析,或因子分析。这些方法的一个中心点是,它们都被用来理解许多变量,并试图将这些变量总结成一个或几个教训。

这与假设检验(常用于实验研究)非常不同,假设检验是一个专注于为非常精确的假设找到绝对答案(基于显著性的真理)的领域。

对于马诺娃来说,两者都是正确的,但重要的是要注意,具有一个因变量的“常规”假设检验领域通常具有与多元统计领域相对不同的应用。在选择方法时,考虑你的学习目标是很重要的。

MANOVA 的使用案例示例

让我们开始研究一个马诺娃的例子。在这种情况下,让我们做一项研究,其目标是证明不同的植物生长产物导致显著不同的植物生长。

因此,我们将有三种治疗方法:

  • 处理 1(对照,无产品)
  • 处理 2(产品 1)
  • 处理 3(产品 2)

我们将使用三种测量方法来定义植物生长:

  • 植物的高度
  • 植物的宽度
  • 植物的重量

与多元统计中可能遇到的情况相比,拥有三个结果变量相对较少。然而,它将非常适合跟随这个 MANOVA 的例子。

R 中的 MANOVA

让我们从 r 中的 MANOVA 分析开始。

获取 R 中的 MANOVA 数据

我把数据上传到了 S3 桶里。您可以在 R 中使用以下代码来获取数据:

数据如下所示:

MANOVA 数据。作者图片。

数据的单变量描述

为了快速了解治疗对三个因变量的影响,您可以使用以下代码创建方框图:

创建 MANOVA 植物生长数据的方框图。

您将获得以下图:

MANOVA 植物生长数据的方框图。作者提供的图像。

您在该图中可以看到,接受处理 1 的植物具有最低的高度、宽度和重量。接受治疗 3 的植物是所有植物中最高的。在某些地方有一些重叠,但我们可以合理地预期,处理 3 是植物生长的最佳整体产品。

数据的多元描述

在进行多元分析时,查看因变量之间的关系也很重要。

让我们从用下面的代码查看因变量之间的相关性开始

计算因变量之间的相关性

您将获得以下结果:

因变量之间的相关性

这三个变量之间都有很强的相关性。身高与体重的关系最为密切。

包括多元分析中的治疗

通过绘制散点图,您可以看到所表示的各个数据点。如果您将治疗方法作为一个形状添加到其中,您可以在一个绘图中看到相关性和治疗方法。

您可以使用以下代码来完成此操作:

创建 MANOVA 散点图

您将获得以下图:

MANOVA 散点图

在 R 中安装 MANOVA

现在,与其看图,我们想有一个客观的答案,以找出治疗是否是显著改善植物生长。

在 R 中安装 MANOVA

您将获得以下结果:

MANOVA 导致 R

了解 R 中 MANOVA 的输出

如果你不熟悉假设检验,我建议你先读这篇文章。

假设检验输出中首先要看的通常是检验统计量和 p 值。

MANOVA 中的检验统计量是皮莱轨迹:一个介于 0 和 1 之间的值。像往常一样,p 值需要解释为重要性结论。p 值低于 0.05 表明治疗对结果有显著影响。

在目前的情况下,我们可以得出结论,处理对植物生长有显著影响。

Python 中的 MANOVA

现在让我们看看如何使用相同的步骤在 Python 中进行相同的分析。

用 Python 获取 MANOVA 数据

您可以在 Python 中导入相同的数据集,如下所示:

在 Python 中导入 MANOVA 数据

它将如下所示:

Python 中的 MANOVA 数据

在 Python 中安装 MANOVA

您可以使用 statsmodels 在 Python 中安装 MANOVA。您可以使用以下代码来实现这一点:

在 Python 中安装 MANOVA

您将获得以下输出:

Python 中的 MANOVA 输出

理解 Python 中 MANOVA 的输出

现在在 Python 中,输出显示了使用不同测试统计数据的分析。第二个是 Pillai 的轨迹,也是我们在 R 输出中看到的轨迹。众所周知,皮莱的迹线相对保守:它不太容易给出有意义的结果(差异必须更大才能获得有意义的输出)。

威尔克斯的λ是另一个常用的检验统计量。Hotelling-Lawley trace 和 Roy 的最大根也是备选方案。在统计学文献中,对于哪种检验统计量更好,没有绝对的一致意见。

p 值显示在右栏中,并且都小于 0.05,这证实了处理对植物生长有影响。

马诺娃的假设

和所有的统计模型一样,有一些假设需要考虑。在 MANOVA 中,假设是:

  • 独立同分布随机变量
  • 每组内的因变量遵循多元正态分布
  • 各组之间的相等总体协方差矩阵(ANOVA 中方差齐性的多变量替代)。如果满足这个假设,通常建议使用皮莱的迹线,否则应该默认使用维尔克的λ。

如果你想依靠你的马诺瓦结论,你需要确保这些假设得到满足。

结论

在本文中,您了解了什么是 ANOVA,何时应该使用它,以及如何在 R 和 Python 中通过一个关于作物生长的用例来应用它。我希望这篇文章对你有用!感谢您的阅读,请不要犹豫,继续关注更多的统计、数学和数据科学内容。

使用 Python 进行制造数据分析:实践示例

原文:https://towardsdatascience.com/manufacturing-data-analytics-with-python-a-hands-on-example-6de8817a24dc?source=collection_archive---------3-----------------------

行业笔记

我们展示了如何使用 Python 工具处理机器/测试人员漂移和基准测试的典型制造数据分析问题。

图片来源:作者创作

数据分析解决制造问题

在进入数据科学(DS)和机器学习(ML)职业生涯之前,我在硅谷的科技行业担任了十多年的半导体技术专家和设计师。我是拥有大量制造足迹的组织的一员——前端晶圆厂、后端组装厂等。

我们在推出高性能产品和开发新型技术节点方面取得了巨大成功。我们也有相当多的制造问题。我一直坚持认为使用 DS 和 ML 的现代工具可以更好地分析和解决这些问题。

当然,这不是我。许多聪明人也在谈论它。

https://www.kdnuggets.com/2019/03/top-8-data-science-use-cases-manufacturing.html

很自然,在我进入数据科学领域后,我经常被要求举例说明如何使用任何人都可以使用的快速编程工具和技术来解决常见的制造分析问题。在这篇简短的文章中,我试图展示一个具体的例子——机器和测试人员的漂移问题。

机器/测试仪漂移问题

现代制造工厂使用非常复杂的机器和设备进行生产、包装、测试等。虽然设计的目的是为了高质量和稳定性,但没有一台机器能够避免漂移和变化。随着时间的推移,子组件的行为开始与它们在安装阶段的行为略有不同,并且整体特性会发生漂移。

图片来源:作者创作

由于许多原因,检测这种漂移是重要的,

  • 确定哪台机器(在一组机器中)可能需要维修和保养
  • 通过软件或硬件干预来校正/重置漂移
  • 将产品质量与机器漂移相关联
  • 调查可能由机器漂移和偏差增加引起的产量问题或可靠性故障

图片来源:作者创作

个体漂移检测

检测单个设备的漂移和变化是一个常见的制造问题。这可以使用各种方法来处理,特别是如果某种测试/传感器数据也是可用的。一些方法是,

  • 寻找并计算过程中的异常情况—如果其密度超过阈值,则机器可能需要维修/维护
  • 监控与机器相关的数据的统计分布(不一定是正态/高斯分布),并检测其变化
  • 每天/每周执行某种简单的统计测试(例如,将平均值与金标准机器进行比较),并检测是否有显著变化

虽然设计的目的是为了高质量和稳定性,但没有一台机器能够避免漂移和变化。

哪些机器掉线最多?

通常,最谨慎的任务是(在一组相同的机器中)找出与黄金标准相比偏差最大的机器。理想情况下,我们希望通过分配某种数值分数来对它们进行排序。

这在现实生活中经常发生。为什么?因为以前的经验和数据分析可能已经表明,小的漂移不会影响产品质量或产量,只有漂移最大的机器才应该停下来进行干预和维护。

业务经理和制造副总裁会告诉你,干预是要花钱的,只有在不可避免的时候才应该这么做。他们期望,你的数据分析将引导他们解决最紧迫的问题,而不仅仅是扔给他们一般的统计分析和图表。

这不是一个微不足道的数据问题

围绕工业 4.0数字化转型智能制造的所有宣传,你会惊讶地发现,在这种转型变革的道路上,最大的障碍仍然是基本的数据收集和摄取。

机器移动,操作执行,产品生成。但是,大多数情况下,它们并没有被数字化记录。如果它们没有被正确地记录下来(及时),相关的数据就会丢失到宇宙中,导致不断增加的熵。它们对任何后续的数据驱动的分析管道都没有用。

通常,最谨慎的任务是(在一组相同的机器中)找出与黄金标准相比最偏离的机器。

这是一个全新的讨论,我们将把它放到另一篇未来的文章中。让我们假设我们可以在一组机器运行时捕获与它们相关的传感器/过程数据。此外,这些数据是结构良好和干净的。即便如此,漂移检测的解决方案也不简单。

比方说,

  • 我们收集每台机器 200 个样品的测量值
  • 有 10 个过程测量值(或传感器)——ABC 等。
  • 共有 10 台机器— M 1、 M 2、 M 3 等。
  • 当然,有一台黄金机器,我们希望用它来对所有这 10 台机器进行基准测试并检测漂移

因此,我们有一个包含 20,000 个数据点的漂亮表格(加上黄金机器数据)。但是每种测量在本质上是不同的,并且彼此不相关。机器' M 1 '中传感器' A 的测量值与机器' M 2 '或机器' M 3 '中传感器' A 的测量值相互关联。下图说明了这个想法。

图片来源:作者创作

机器移动,操作执行,产品生成。但是,大多数情况下,它们并没有被数字化记录。如果它们没有被正确地记录下来(及时),相关的数据就会丢失到宇宙中,导致熵不断增加。

也不是一个微不足道的认知负荷

分析仪表板在制造业中非常受欢迎,尤其是在工厂经理中。在许多情况下,它们有自己的用途,描绘生产过程健康状况的整体图景。

然而,在这种特殊情况下,如果您试图可视化每个传感器测量并找出相关程度,您将遇到迷宫般的图,并且没有任何有用的东西。

图片来源:作者用 Pixabay 免费图片创建

在这种情况下,暴力可视化会适得其反。

想象一下,当 10 多台机器进入你的工厂时会发生什么?或者再增加 10 个传感器。

此时,你开始意识到更多的数据实际上没有帮助。这不是一个简单的 ML 问题,你有一个“机器漂移”的标签数据集。在这里,您必须仔细构建统计测试和度量,以检测漂移并基于该度量对机器进行排序。

同样,像任何其他数据驱动的问题解决案例一样,您有多种选择。

  • 您可以从每个传感器数据栏中提取描述性统计数据并将与其他机器中的进行成对比较
  • 您可以从黄金机器中为每台机器计算某种类型的全局“距离分数”(这里有一个距离度量列表,您可以使用 Scipy 包进行评估)
  • 您可以计算个体数据分布之间复杂的距离度量(例如 Mahalanobis 距离)并基于它们进行排名

为了证明本文的命名是一个实践教程,让我向您展示一个非常简单的方法来提取成对相关分数(即,将黄金机器的传感器“A”数据与传感器“A”数据 M 1、 M 2、 M 3 等匹配,然后将黄金机器的传感器“B”数据与传感器“B”数据 M 1、 M 2、

简单的演示

样板代码可以在我的 Github repo 这里找到

有一个黄金数据帧machine_golden和代表 10 台机器的 10 个以上数据帧的字典,称为machines。每个数据帧有 200 行(样本)和 10 列(传感器测量)。

我们用代表从各种机器收集的数据集的合成数据来构建这些数据帧。基本上,我们将可变高斯噪声添加到黄金数据集,并为各种机器生成数据集。由于噪声的可变性质(高斯均值和方差因机器而异),一些机器会比其他机器偏离黄金数据更多。

下面是实现这一点的示例代码,

*machines = {'machine'+str(i):[] for i in range(1,11)}for i in range(1,11):
    loc = np.random.uniform(0,2)
    scale = np.random.uniform(0,2)
    df1 = machine_golden + pd.DataFrame(np.random.normal(loc=loc,scale=scale,size=(200,10)))
    machines['machine'+str(i)] = df1*

现在,开始相关性分析。

我们可以通过对每一列数据进行切片并使用 Numpy 的关联例程来计算关联分数,从而编写手动代码。然而,对熊猫来说,有一种更好、更干净的方法。这是一种叫做[**DataFrame.corrwith**](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.corrwith.html)的方法,它只用一行代码就可以计算两个数据帧的列之间的皮尔逊相关分数。**

这是我的高效数据分析技巧。寻找简洁明了的替代代码。通常,它们非常适合您的问题,并且它们产生了干净且易于调试的代码库。这就引出了 生产性数据科学

*https://medium.com/productive-data-science/why-and-how-should-you-learn-productive-data-science-53377b473f37

一行代码也打印出了相互关系,

for machine in machines:
    print(f"Correlation of {machine} with the golden tester:", round(**machine_golden.corrwith(machines[machine],axis=1).sum()**,2))

这里我们做的是列相关(axis=1),然后对该行的分数求和(.sum())(我们也可以取平均值,但是因为样本数是相同的,所以这无关紧要)。

图片来源:作者创作

结果是这样的,

Correlation of machine1 with the golden tester: 130.67
Correlation of machine2 with the golden tester: 91.78
Correlation of machine3 with the golden tester: 116.57
Correlation of machine4 with the golden tester: 178.85
Correlation of machine5 with the golden tester: 147.76
Correlation of machine6 with the golden tester: 150.91
Correlation of machine7 with the golden tester: 199.94
Correlation of machine8 with the golden tester: 192.48
Correlation of machine9 with the golden tester: 199.73
Correlation of machine10 with the golden tester: 97.73

显然,机器 2 与黄金机器的相关性最小,而机器 7、8 和 9 的相关性最大。

视觉证明?如果我们在黄金机器和机器 2/机器 7 之间绘制一些传感器数据。

图片来源:作者创作

图片来源:作者创作

但是我们已经从之前的相关性分析中知道了这一点,并且可以挑选出像machine2machine10这样相关性分数低于 100(只是一个任意的阈值)的机器进行干预。

图片来源:作者创作

最好的部分是,漂移机器的提取随着采样频率、传感器数量或机器数量平滑缩放。观看每一个情节并决定干预什么,没有任何认知负荷。

下周,漂移模式可能会改变,另一台机器可能会开始比其他机器漂移更多。尽管如此,我们还是会用同样的分析方法抓住它。此外,我们可以调整这种方法来使用均值相关,这样它就可以处理不同机器的样本数量不同的情况(这是生产中相当常见的场景)。

图片来源:作者创作

摘要

在本文中,我们展示了如何使用非常简单的 Python 分析工具来处理机器/测试人员漂移和基准测试的典型制造数据分析问题。

这个想法只是为了展示各种可能性,以便在制造业或工业 4.0 计划中工作的工程师能够超越盒子进行思考,并在其分析工作中采用数据科学工具和技术。*

喜欢这篇文章吗?成为 中等会员 继续 无限制学习 。如果您使用下面的链接, ,我将收取您的一部分会员费,而不会对您产生额外费用

*https://medium.com/@tirthajyoti/membership *

很多超参数?使用杜松子酒

原文:https://towardsdatascience.com/many-hyperparameters-use-gin-fdf6741d282?source=collection_archive---------27-----------------------

如何处理所有的参数

Jez Timms 在 Unsplash 上拍摄的照片

动机

处理特定于用户的设置的常见方法包括解析命令行参数或使用存储定义的单独 python 文件。对于小型项目,这些技术易于集成和维护。

然而,一旦您必须处理过多的可配置(超级)参数,您将很快失去对情况的跟踪。

作为起点,考虑这个简单的代码片段:

如果您只使用几个参数,比如 5 到 10 个,那么您可以通过命令行操作它们,就像这样:

或者,您也可以将这些值存储在一个单独的 python 文件中,并给它们取一个有意义的名称,如下一个代码片段所示。这些值存储在 definitions.py 中(未显示,但内容应该很清楚)。然后,这些文件被导入并按如下方式处理:

现在,随着您不断添加越来越多的参数,您要么扩大命令行解析器,要么必须从单独的文件导入所有内容。这种设置意味着您必须跟踪您已经定义/导入的内容以及没有定义/导入的内容。因此,情况可能会迅速失控:

即使所有的值都被导入,我们仍然必须将它们传递给被调用的函数,这导致我们重复编写相同的代码。如果我们要使用参数解析器,这将是一个类似的方向。而且我们会有很长很混乱的命令行调用。

杜松子酒

输入杜松子酒:

Gin 帮助您维护所有超参数的概览。它通过从配置文件(类似于假设的 definition.py 文件)中读取它们来实现这一点。但是,与必须全部导入并手动处理它们不同,您可以使用 @gin.configurable 来注释函数,如下所示:

注意,当调用 method1 时,我们不必设置任何参数,即使它们都被声明为强制的(即,我们必须传递它们)。这是由于 Gin,它解析配置文件并用存储的值加载参数。尽管如此,如果您想在调用该方法时手动设置一个参数,您可以这样做,它会覆盖 Gin 对该特定参数的设置。

让我们看看上面提到的配置文件是什么样子的:

正如您所注意到的,参数被写成带注释的方法 >的<名称。< 参数名称 >。按照这个惯例,你可以很容易地将它们与各自的位置联系起来。这也适用于类,在这种情况下,您要覆盖 init 方法。此外,您可以将所有设置捆绑到一个配置文件中。Gin 可以通过参数命名约定检测适当的方法,使得每个带注释的方法或类都有一个文件过时。

Gin 的魔力随着要跟踪的超参数的数量而展现。您还可以将它与命令行解析器结合起来,解析最重要的参数——比如时期、批量大小、学习速率——并从配置文件中加载更详细的设置。

您还可以维护两个配置文件以便于处理:一个包含所有带注释的方法和类的所有默认参数,另一个包含您的自定义设置。这样,你永远不会忘记你的初始值,并且可以很容易地在默认设置和实验设置之间切换。

结论

Gin 是一个易于使用的框架。它降低了代码的复杂性,同时增加了灵活性。您所要做的就是将所需的参数设置外包给一个配置文件,用 @gin.configurable 注释方法和类,然后在运行时加载配置。

负责任地使用杜松子酒。

用 GeoPy 和 leav 绘制黑人拥有的企业

原文:https://towardsdatascience.com/mapping-black-owned-businesses-with-geopy-and-folium-4416adc4c7cb?source=collection_archive---------51-----------------------

探索大波士顿地区黑人企业的公共交互式地图

图片作者。第一个图标来自于维基共享资源,一个免费使用的图片库。

介绍

新冠肺炎疫情对全美的小企业造成了严重的损失,黑人拥有的企业继续受到最严重的打击。在过去的一年里,许多人目睹了持续的经济和种族正义危机的升级与公共卫生危机的加剧。支持当地和黑人拥有的企业的呼吁很难开始完成结束这些同时发生的危机所需要的一切;然而,这样的呼吁可能是朝着缩小种族财富差距和修复地方经济的正确方向迈出的一小步。

本文中讨论的地图旨在为有兴趣探索大波士顿地区黑人企业的人以及希望为其他地区创建类似地图的人提供资源。该地图使用了来自波士顿地区黑人拥有的商店、餐馆和服务的众包电子表格的数据。应该注意的是,并不是电子表格中的每个条目都被确认为黑人所有的企业,所以地图可能包括已确认和未确认的条目。

清理数据

上述电子表格文档中的数据被读入三个独立的熊猫数据框:“餐馆”、“商店”和“服务”。数据框的列在必要时被重命名,以便每个数据框包含“名称”、“地址”和“网站”列。最终的服务数据框架还包含一个“类别”列,允许在映射阶段按服务类别进行简单的子集划分。

删除了重复的名称,这样就可以为每个企业在地图上添加一个标记。许多多服务业务在服务数据帧中有重复出现。仅保留每个企业的第一次出现,这意味着地图的一个局限性是其标记可能无法捕捉某些企业提供的各种服务。

对于餐馆和服务数据框,地址数据最初分布在多个列中。使用**Series.str.cat()** 方法将每个地址的组成部分连接成一列,如下例所示:

获取地理坐标

一旦为每个数据帧准备好完整的地址列,就可以使用 GeoPy 获得地理坐标。GeoPy 客户端允许开发人员检索给定地址的坐标,反之亦然。下面的函数通过遍历整个列并将纬度和经度附加到“lat”和“lon”列表来获得整个地址列的坐标。客户端为无法获得坐标数据的某些地址返回了非类型对象。考虑到这些情况,函数中的 if/else 语句使得只获得一个**geopy.location.location**对象的坐标数据;对于非类型对象,“NA”将附加到列表中。

向地图添加标记

上面的函数在**add_markers()**中被用作辅助函数,它在 leav 中向地图添加标记。**folium.map()** 中的位置参数取一组地理坐标,标记地图默认的中心位置。 tiles 参数影响地图背景的样式,zoom_start 参数指的是地图的初始缩放级别,其中较高的数字会创建更接近的缩放。

**add_markers()** 函数将带有“地址”列、标记颜色和标记图标的数据框作为参数。它检索带有**get_lat_lon()**的地址的坐标数据,并过滤掉缺少坐标数据的行。要添加到地图中的点及其相应的业务信息存储在一个 zip 对象列表中。每个对象(在 for 循环中别名为“p ”)都包含以下数据:

  • p[0]和 p[1]:分别是纬度和经度
  • p[2]:企业名称
  • p[3]:营业地址
  • p4:商务网站

如果电子表格中没有记录网站,则每个企业的 zip 对象中的最后一个元素网站可能包含空数据。在这些情况下,函数中的 if/else 语句仅将企业名称和地址添加到标记的弹出文本中;如果网站可用,它也会包含在弹出文本中。

在此函数中,**icon**参数对所有标记采用相同的尺寸。标记的颜色和图标将根据传递给**add_markers()**函数的内容而变化。地图中使用的图标是通过字体 Awesome 访问的,字体 Awesome 的**prefix**关键字参数是**icon**参数中的‘fa’。下表显示了已经添加到地图中的不同类型的标记及其对应的业务类别:

按作者分类的表格。图标 via 字体牛逼免费(免费开源)。

**add_markers()**函数用于餐馆和商店数据框,以及按类别分解的服务数据框的子集。在下面的例子中,对应于建筑服务的行进入了“建筑师”数据框。然后在数据框上调用该函数,标记被赋予一个学员蓝色的“建筑物”图标:

探索地图

以下是地图当前外观和导航方式的预览:

作者 GIF。

互动地图托管在这里。通过放大您选择的邻域并单击商业标记查看其弹出信息,您可以随意探索它。

结论

这篇文章回顾了我创建波士顿地区黑人企业交互式地图的过程。要查看该项目的完整代码,请访问其 GitHub 库

你也应该关注支持黑人企业,它的贡献者计划在互动地图上展示美国各地的黑人企业。在当前的网站上有一个选项,黑人企业主可以提交他们的企业信息,以便在地图推出后将其包含在地图中。

支持黑人拥有的企业不仅仅是创建易于发现的清单和地图。像这样的资源只有当它们真正被用来寻找黑人拥有的企业来用你的美元支持时才有真正的价值——无论是在这个特别困难的经济时期还是以后。

用华夫饼网格绘制便利店地图

原文:https://towardsdatascience.com/mapping-convenience-stores-with-waffle-grids-d0196901418a?source=collection_archive---------39-----------------------

什么是华夫格网格图,并与堆积条形图进行比较

(图片由作者提供)

TL;速度三角形定位法(dead reckoning)

什么是华夫饼图表?什么是地图上的华夫饼图表?什么时候应该使用这种类型的地图?本文使用香港便利店的数据集,对华夫格图和华夫格网格图进行了简单的介绍。第一部分解释了什么是华夫格图,而第二部分从数据可视化和制图的角度比较了使用华夫格网格图和堆叠条形图的利弊。

第一部分—华夫格网地图

这是一张华夫饼干网格图,显示了两个主要便利店(cv)的数量和比例,分别是 7-ElevenCircle K 。这是一张地图上的华夫饼图表。

:我的上一篇文章简单介绍了这两大 CVS 链条。或者查一下维基百科关于香港 7-ElevenCircle K 的运营描述。

便利店华夫饼(图片由作者提供)

但是,首先,什么是华夫饼图表?

但是什么是华夫饼图表呢?

简而言之,华夫饼图是饼图的平方版本。它把各种范畴的成分显示为一个整体的一部分。每个华夫饼干切片包括许多正方形。所有的方块一起形成一个网格,显示总量。

华夫饼干图表可以很容易地解释为每一个正方形网格的一些东西。网格显示了构成一个整体的各种组的数量。

华夫格图显示朝着目标或完成百分比的进展。有一个由小单元格组成的网格,其中的彩色单元格代表数据。

一个图表可以由一个类别或几个类别组成。多个华夫饼图表可以放在一起显示不同图表之间的比较。

出自【datavizproject.com】T21

方形饼图(也称为华夫格图)可用于传达分类数量的整体部分。为了模拟饼图的百分比视图,应该使用 10x10 的网格,每个正方形代表总数的 1%。华夫格图的现代用法不一定遵循这一规则,可以用任何矩形的网格来创建。

摘自R 华夫饼包的自述

华夫饼干图的用法示例见此处https://qz.com/576057/why-infectious-bacteria-are-winning/此处 。另外,著名的 xkcd 辐射剂量图 也是华夫图!

辐射剂量图(来源: xkcd

华夫格图给读者留下深刻印象的一个原因是因为它的重复的性质——一个接一个地重复绘制相同颜色的网格。这样,对读者的视觉冲击是巨大的,人们会恢复每个网格的意思(或者说,他们会被洗脑)。网格的迭代使人们记住了数据编码,反过来也更容易阅读。

但是什么是华夫饼网格地图呢?

很明显,华夫饼网格地图(或华夫饼地图,我在这里互换使用这两个术语)实际上是将华夫饼放在地图上。

当用于对每个观察值进行分组的变量与空间相关时(例如,按县、按区、按任何边界等)。),你可以把每片华夫饼干放在地图上各自的位置,代表华夫饼干所指的区域。恭喜你,你立即将基本的华夫饼图表升级为华夫饼网格图!

Kenneth Field 的精彩文章展示了华夫饼干网格地图的使用。他创建的地图将每个国家的 COVID 数据的华夫格图放置在该国边界内的某处(或附近)。

第二部分——地图上的图表:是否应该使用?

华夫饼图与堆积条形图

你可能见过上面有图表的地图。华夫格地图应用了同样的原理——在每个空间变量上放一张图表。在大多数情况下,空间变量意味着国家或地区。在地图上放置图表从来都不是一种新的制图技术。历史地图集非常重视这种类型的数据可视化技术。

因此,华夫饼地图属于专题地图谱系树中的地图上的图表类别。这是否意味着我们可以用其他类型的图表替换每个地区的华夫饼图表?答案是——为什么不呢?

最后,这个华夫饼干网格图使用相同的数据集来创建堆积条形图。从本质上来说,堆叠的条形和华夫饼干网格源自每个地区的 7-Eleven 和 Circle-K 商店的数量。

图表背后的数据集(图片由作者提供)

作为一个快速的草图,我可以用我在上一篇文章中制作的条形图中相应的条形替换华夫饼网格。还有哒哒,我们成功回收了旧的材料,做了新的专题地图。

上一篇文章中的堆积条形图(图片由作者提供)

将华夫饼网格替换为堆叠条形图(图片由作者提供)

相同的数据,不同的图表(图片由作者提供)

我应该使用哪种方法?

多种观想方法带来的是一个棘手的问题:

那么,我应该选择哪种观想方法呢?

和每一种数据可视化一样,没有选择哪种方法是最好的通用规则。不过,列出利弊有助于决策。下表比较了堆积条形图和华夫饼网格图的优势和劣势。

比较两种数据可视化方法的汇总表(图片由作者提供)

堆积条形图

👍🏻优点:易于按变量排列分析的地区/县/单位

对于堆积条形图的数组,您可以根据可视化数据的目标对条形进行排序。在大多数情况下,条形按一个变量的值排序。在我创建的堆积条形图中,我按照 7-11 家商店占该地区所有 cv 的比例对它们进行了排序,以强调“,在那里你可以找到一家连锁便利店比另一家”的说法。这样,就可以直接看到哪个区的 7-11 比例最大/最小。

👍🏻优点:允许地区之间的直接比较

制作堆积条形图意味着每个条形图的总和为 100%。使用百分比意味着每个地区(即分析单位)都有相同的“基数”,并允许不同群体之间进行直接比较。无论每个地区的商店总数是多少,都可以直接比较 7-11 家商店在该地区所有便利店中所占的百分比。

比如说,如果我们比较一下深水区(很多 cv)和离岛(很少 cv)的店铺分布。绝对数字无助于说明趋势(深水埗(152 家店)的简历比离岛(35 家店)多 4 倍左右)!).然而,使用百分比,我们可以忽略商店的绝对数量,允许直接比较。

👎🏻缺点:不能区分每个地区的总数

百分比意味着原始总数被删除。有时,每一组的原始总数也说明了一个重要的信息。在这种情况下,便利店的总数可以显示出每个地区商店密度的差异。

如果总数对读者来说是一个重要的点,有必要添加一些脚注。一种方法是创建一个额外的列,指示每个地区的商店总数。

华夫格地图

👍🏻优点:地区小计之间的简单比较

华夫饼大小的差异会给读者带来强烈的视觉冲击。一个大的华夫饼干网格让读者立即知道该区有大量的商店。这种视觉元素比在汇总表中抛出一个总数要强大得多。

👍🏻优点:显示数据背后的空间分布

当然,cv 的空间分布不是随机分布的——商店通常位于人口密集的区域。使用地图可以显示市中心、新城镇和乡村之间商店密度的差异。

👍🏻优点:可以检索原始数据

原始数据并没有完全在华夫格图中显示出来——人们可以通过计算网格来计算 7-11 和 Circle-K 的数量(如果他们感到无聊的话)。

👍🏻优点:不寻常的观想方法

说实话,有时我们会对条形图感到厌倦。尽管显示图表比抛出包含大量数字的表格要好,但是条形图是不够的。

Waffles 有助于在数据可视化中创造一个“惊喜因素”。这有助于读者从之前阅读过的成千上万的条形图中恢复过来。地图让读者赏心悦目。这些地图给故事增添了一点新鲜感。即使空间元素不是讲述故事的必要元素,但在后面添加县和地点会增加几分乐趣。

👎🏻缺点:准备时间较长

制作一张能有效传达信息的地图需要时间。如果设计不当,背后的信息会被多余的 图表垃圾 所阻碍。地图应该添加什么级别的空间细节才能有效地融合数据的非空间和空间部分,然后讲述故事?

将华夫图放在合适的位置是一项不简单的任务。不要忘记添加这些注释所需的时间。还是那句话,准备一张有效的地图需要时间。

👎🏻缺点:地图总是需要的吗?

竟然还要做地图?

数据中的地理元素重要吗?背后的地图有助于更清楚地传达信息吗?地图可能是一把双刃剑——如果趋势与空间相关,它可能会告诉你更多数据背后的故事。如果趋势不是空间相关的,它也可能掩盖事实,阻碍你发现趋势(通过做出错误的感知)。****

三思而后行,在映射之前多考虑两次。

裂缝

这篇文章比较了华夫饼图和堆积条形图。从数据可视化和制图学的角度来看,你可以注意到每种数据可视化方法在哪些方面做得更好,在哪些方面做得不好。一般来说,选择数据可视化方法不是一个非黑即白的决定。没有万灵药,也没有一张图表可以显示数据背后的所有故事。同时,很难量化哪种方法绝对优于另一种方法。

不要忘记,我们是带着目的来制作图表和地图。Waffle grid maps 是一个很好的工具,可以创建很好的地图,但是应该有合理的理由使用它。****

进一步阅读

https://datavizproject.com/data-type/percentage-grid/
项目数据

测绘冠状病毒华夫饼
https://www . ESRI . com/ArcGIS-blog/products/ArcGIS-pro/Mapping/Mapping-冠状病毒-华夫饼/

如果我们使用图形方法的语法将地图视为几何图层(经度和纬度分别为 x 和 y 美学)之一,我们可以有四种图表类型(堆叠条形图、华夫饼图表、地图上的堆叠条形图、地图上的华夫饼网格)。但这可能会让整个故事变得过于复杂。这里,我只比较两种类型的“图表”,以使事情更简单。

我将写一篇幕后故事来记下我在创建这张地图时的想法和实验。敬请期待!

用 Plotly 和 TigerGraph 绘制新冠肺炎案例

原文:https://towardsdatascience.com/mapping-covid-19-cases-with-plotly-and-tigergraph-f529f32c1a40?source=collection_archive---------30-----------------------

使用 Plotly Express、Plotly Dash 和 TigerGraph 创建交互式地图以可视化韩国新冠肺炎案例

概观

导言和目标

TigerGraph 的最新入门工具包之一是新冠肺炎分析工具包,它提供了韩国新冠肺炎数据的 33,000 多个顶点和 49,000 条边。我们不仅可以使用这个初学者工具包运行高级分析,还可以创建很酷的可视化效果。本博客将带您了解如何使用 Plotly Express 的地图功能和 TigerGraph 的新冠肺炎初学者工具包来创建展示南韩新冠肺炎病例的交互式地图。这将被放入仪表板使用 Plotly 破折号。

使用的工具

tiger graph Cloud:tiger graph Cloud 是我们创建解决方案和托管图形数据库的地方。这也将包含我们将使用的所有数据。

Plotly Express:Plotly Express 是 Plotly 下的一个高级库,可以轻松创建漂亮的可视化效果。有了它,我们将创建我们的地图视觉效果。

Plotly Dash : Plotly Dash 是 Plotly 的仪表板库,我们将使用它来展示我们创建的地图,并允许用户切换地图的不同设置。

第一部分:设置您的 TigerGraph 初学者工具包

首先,你需要设置你的 TigerGraph 初学者工具包。为此,请转到https://tgcloud.io/,登录或创建一个帐户(如果您还没有)。

登录或注册

登录后,导航至“我的解决方案”,然后按蓝色的“创建解决方案”按钮。

点击“我的解决方案”,然后点击蓝色的“创建解决方案”按钮。

注意:要创建免费解决方案,TigerGraph 不需要您的信用卡。

在第一个屏幕上,点击“新冠肺炎分析”这将创建一个带有新冠肺炎图、模式、加载作业和查询的解决方案。按下一步。

点击“新冠肺炎分析”,然后按“下一步”

不要更改第二页上的任何内容。所有这些将会创建一个免费的解决方案。按下一步。

不要做任何更改,按“下一步”

在第三页上,根据您的解决方案和目的修改详细信息。一旦你更新了这些部分(记住你的子域和密码!),按“下一步。”

注意:请记住您的子域和密码。子域必须是唯一的(两个人不能同时拥有同一个子域)。

根据您的目的修改信息,然后按“下一步”

最后,验证所有细节是否正确,然后点击“提交”解决方案需要几分钟的时间来调配。

确认一切正常,然后点击“提交”

完美!等到您的解决方案的状态为“就绪”,然后我们将准备我们的数据。

等待状态显示“就绪”,然后开始!

第二部分:在 GraphStudio 上准备您的 TigerGraph 解决方案

第一步:打开 Graph Studio

在“Actions”下,按下四个框(带有“Applications”的悬停标签),并从下拉列表中选择“GraphStudio”

按下“应用程序”(四个框)并选择“GraphStudio”

你将被重定向到 TigerGraph 的 GraphStudio,这是一个用 TigerGraph 可视化创建图形数据库的平台。

TigerGraph 的 GraphStudio

点击“全局视图”,然后选择“我的图表”以查看新冠肺炎图表。

点击“全局视图”,然后选择“我的图表”

按“设计模式”查看图表的模式(将其视为数据映射)。如果将鼠标悬停在顶点或边上,可以查看其属性。

新冠肺炎图的模式

让我们现在准备我们的图表!

第二步:加载数据

接下来单击“加载数据”选项卡。你会注意到“总顶点”和“总边”都是零。让我们通过向上插入我们的数据(由文件图标表示)来改变这一点。

转到“加载数据”选项卡。

单击所有文件图标(shift 单击),然后按下播放按钮(开始/恢复加载)。

选择所有文件,然后按播放。

接下来会提示您确认。在这里按“继续”。

确认上传数据。

状态将变为“正在运行”

CSV 加载运行

几秒钟后,您会看到状态为“已完成”

数据加载完成

按顶部的标签(你可能需要刷新),然后你会注意到你的顶点和边向上插入。

所有的顶点和边都向上插入。

干得好!下一步将是安装查询。

步骤三:安装查询

我们现在将安装所有的查询。为此,导航到最后一个选项卡“编写查询”

导航到“编写查询”选项卡。

在“GSQL 查询”的左侧,按下带有向上箭头的矩形(带有“安装所有查询”的悬停数据)。

安装所有查询

你将再次被要求确认。按安装,然后等待安装完成。

确认安装查询

注意:安装可能需要几分钟时间。

一旦你完成了,恭喜你!您的图表现在已经完全设置好了!现在让我们转到 Google Colab 笔记本上来获取数据并将其可视化。

第三部分:准备你的图表

第一步:安装并导入 pyTigerGraph,并连接到您的 TigerGraph 解决方案

首先使用 pip 安装 pyTigerGraph。在 Colab 中,这个前面会有一个感叹号。

!pip install pyTigerGraph

安装后,您可以导入它。

import pyTigerGraph as tg

最后,连接到您刚刚创建的解决方案。为此,传递您在第一部分中创建解决方案时设置的子域名和密码。然后,我们将通过运行 getToken 并传递 createSecret 函数的值来生成 API 令牌。使用这个令牌,我们将能够运行查询。

conn = tg.TigerGraphConnection(host="https://SUBDOMAIN.i.tgcloud.io/", password="PASSWORD", graphname="MyGraph")conn.apiToken = conn.getToken(conn.createSecret())

注意:确保子域是您的子域,密码是您在第一部分的第三页上设置的密码。

第二步:编写查询

接下来,我们需要编写额外的查询来从图表中提取我们想要的值。我们将编写的第一个查询将提取带有详细信息的感染位置。我们将获取每个地点的纬度和经度以及感染病例

print(conn.gsql('''USE GRAPH MyGraph
DROP QUERY grabInfectionLocationDetailsCREATE QUERY grabInfectionLocationDetails() FOR GRAPH MyGraph SYNTAX v2 {TYPEDEF TUPLE <FLOAT lat, FLOAT lon, STRING infcase, STRING province, UINT num_confirmed_cases, UINT population, FLOAT area> INFO;
HeapAccum<INFO> (10000, num_confirmed_cases DESC, population DESC) @@information;Seed = {City.*};Res = SELECT tgt FROM Seed:c - (CASE_IN_CITY:e)- InfectionCase:i -(CASE_IN_PROVINCE:e2)-Province:tgt
      ACCUM @@information+=INFO(e.latitude, e.longitude, i.infection_case, tgt.province, i.confirmed, tgt.population, tgt.area);PRINT @@information;}INSTALL QUERY grabInfectionLocationDetails'''))

太好了!让我们把它分解一下。我们首先创建一个 TYPEDEF 元组,其中包含我们想要累积的所有内容(纬度、经度、感染病例、省份、确诊病例数、人口和面积)。然后,我们创建一个 HeapAccum,限制为 10000 个值,按照确诊病例数降序排列这些值,然后第二次检查是总体。要了解更多关于 HeapAccums 的信息,请查看这个博客。接下来,我们获取种子中所有的城市顶点。最后,我们将我们的值累积到 HeapAccum,从城市顶点开始,经过 CASE_IN_CITY 边,到 InfectionCase 结束,然后经过 CASE_IN_PROVINCE 边,最后到省顶点结束。最后,打印 HeapAccum。

现在我们有了我们需要的查询,让我们进入 Plotly Express 部分。

第四部分:用 Plotly Express 可视化你的图形

第一步:导入库

我们的数据已经准备好,我们有查询来获取我们想要的数据。现在是时候观想它了!让我们先安装并导入所有的 Plotly Express 和 Plotly Dash 库。

!pip install -q jupyter-dashimport pandas as pdimport plotly.express as pxfrom jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

首先,我们引入熊猫来轻松创建数据框架。然后,我们导入 Plotly Express,这是一个高级库,可以轻松地创建可视化。最后,我们将导入 dash 库,包括在笔记本中创建和运行仪表板的 JupyterDash、在仪表板中创建图表的 Dash 核心组件、向仪表板添加 HTML 元素的 Dash HTML 组件,以及使仪表板具有交互性的最终输入和输出。

第二步:用确诊病例创建街道地图

现在,让我们用 Plotly Express 创建我们的第一张地图!让我们首先运行我们的查询,并将其转换为 DataFrame,这是一种易于 Plotly Express 读取的格式。

res = conn.runInstalledQuery("grabInfectionLocationDetails")[0]["@@information"]df = pd.DataFrame(res)

接下来,我们将使用 Plotly Express 的 scatter_mapbox 函数。我们将传递点的纬度和经度。大小是病例的数量,颜色是人群。最后,悬停名称将是感染案例,悬停数据将是区域。

fig = px.scatter_mapbox(df, lat="lat", lon="lon", size="num_confirmed_cases", hover_name="infcase", color="population", hover_data=["area"])

然后我们需要更新地图布局。我们将使用开放的街道地图,并确保地图在所有方向都没有空白。

fig.update_layout(mapbox_style="open-street-map")fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})

最后,我们可以显示我们的地图。

fig.show()

结果地图

厉害!您可以将鼠标悬停在某个值上以获取关于它的更多详细信息,并进行放大和缩小。

您可以将鼠标悬停在某个值上,以获得关于它的更多详细信息!

第二步:创建确诊病例的地理地图

让我们用不同的地图类型映射相同的数据:地理地图。这张地图和另一张地图的唯一区别是使用的布局。在这里,我们正在获取美国地质调查局的影像地理地图数据。

fig = px.scatter_mapbox(df, lat="lat", lon="lon", size="num_confirmed_cases", hover_name="infcase", color="population", hover_data=["area"])fig.update_layout(
   mapbox_style="white-bg",
   mapbox_layers=[
      {
         "below": 'traces',
         "sourcetype": "raster",
         "sourceattribution": "United States Geological Survey",
         "source": ["https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer/tile/{z}/{y}/{x}"] }
   ]
)fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})fig.show()

地理地图

瞧啊。您现在已经创建了一个地理地图!

第三步:创建条形图

接下来,我们将创建一个条形图。使用 Plotly Express,这与编写一行代码并显示每个感染病例的病例数一样简单。它将根据人口进行颜色编码。

bar = px.bar(df, x="infcase", y="num_confirmed_cases", color="population", barmode='overlay')bar.show()

条形图

第三步:创建 3D 散点图

太好了!让我们用 Plotly Express 创建最后一个可视化:一个 3D 散点图,显示确诊病例数、面积和人口。

bar = px.scatter_3d(df, "num_confirmed_cases", "population", "area")bar.show()

三维散点图

太棒了。现在,我们所有的可视化都已经创建好了,让我们把它们放在一个仪表板上。

第五部分:创建仪表板

步骤 1:创建仪表板的布局

让我们首先创建仪表板的布局。首先,我们将初始化应用程序。

app = JupyterDash(__name__)

接下来,我们将使用 HTML 标题和组件、下拉菜单和图表来创建仪表板的布局。

app.layout = html.Div([ html.H1("COVID-19 Dashboard Demo"), dcc.Dropdown(
      id = "map_type",
      options=[
         {"label": "Street Map", "value": "light"},
         {"label": "Geometric Map", "value": "dark"}
      ],
      value="light",
      clearable=False
   ), dcc.Graph(id="map_graph"), html.Br(), dcc.Dropdown(
      id = "graph_options",
      options=[
         {"label": "County vs. Number of Confirmed Cases", "value": "county_cases"},
         {"label": "Number of Confirmed Cases vs. Population vs. Area", "value": "3d_graph"}
      ],
      value="county_cases",
      clearable=False
   ), dcc.Graph(id="bar_graph"),])

在这里,我们从一个标题开始,大文本说新冠肺炎仪表板演示。接下来,我们有一个下拉菜单,有两个选项:街道地图和几何地图。接下来是 dcc。图表将是地图本身,一个 HTML 换行符,另一个条形图选项的下拉菜单,最后是条形图。

我们的下一步将是通过回调使仪表板具有交互性。

第二步:回调 I:更新地图图形

首先,让我们基于下拉菜单更新地图。我们将获取下拉列表的值(“亮”或“暗”)作为输入,然后创建并返回各自的地图(街道或地质)。唯一的区别是,我们将向地图添加一个 custom_data 参数,以便更容易地从地图中提取我们想要的数据。返回值将是地图的图形属性。

@app.callback(
   Output('map_graph', 'figure'),
   Input('map_type', 'value'),
)def update_graph(typ):if typ == "light":
      fig = px.scatter_mapbox(df, lat="lat", lon="lon", size="num_confirmed_cases", hover_name="infcase", color="population", hover_data=["area"], custom_data=["num_confirmed_cases", "population", "area"])
      fig.update_layout(mapbox_style="open-street-map")
      fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})else:
      fig = px.scatter_mapbox(df, lat="lat", lon="lon", size="num_confirmed_cases", hover_name="infcase", color="population", hover_data=["area"], custom_data=["num_confirmed_cases", "population", "area"])
      fig.update_layout(
         mapbox_style="white-bg",
         mapbox_layers=[{
            "below": 'traces',
            "sourcetype": "raster",
            "sourceattribution": "United States Geological Survey",
            "source": ["https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer/tile/{z}/{y}/{x}"]
      }])
      fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0}) return fig

步骤三:回访二:更新图表

对于第二次也是最后一次回调,我们将更新图表。这将接受两个输入:从地图中选择的值和图表类型的下拉列表。这将是一系列的 if 语句。我们将从地图上获取选定的数据。如果存在,我们会将该数据格式化为数据帧,然后根据从下拉列表中选择的值绘制图表。如果我们没有选择任何数据,我们将显示所有数据。

@app.callback(
   Output('bar_graph', 'figure'),
   Input('map_graph', 'selectedData'),
   Input('graph_options', 'value'),
)def update_graph(data, graph_type): if data:
      if graph_type == "county_cases":
         df = pd.DataFrame({"num_confirmed_cases": [i["customdata"][0] for i in data["points"]], "place": [i["hovertext"] for i in data["points"]], "population": [i["customdata"][1] for i in data["points"]]})
         bar = px.bar(df, x="place", y="num_confirmed_cases", color="population", barmode='overlay')
         return bar elif graph_type == "3d_graph":
         df = pd.DataFrame({"num_confirmed_cases": [i["customdata"][0] for i in data["points"]], "population": [i["customdata"][1] for i in data["points"]], "area": [i["customdata"][2] for i in data["points"]]})
         bar = px.scatter_3d(df, "num_confirmed_cases", "population", "area")
         return bar else:
      res = conn.runInstalledQuery("grabInfectionLocationDetails")[0]["@@information"]
      df = pd.DataFrame(res)
      if graph_type == "county_cases":
         bar = px.bar(df, x="infcase", y="num_confirmed_cases", color="population", barmode='overlay')
         return bar elif graph_type == "3d_graph":
         bar = px.scatter_3d(df, "num_confirmed_cases", "population", "area")
         return bar

第四步:启动并探索应用程序

最后,通过一行代码,我们将启动这个应用程序。

app.run_server(mode='external')

当您运行这个命令时,您将得到一个带有链接的输出。点击它。

点击此链接

然后,哒哒,你会找到仪表板。

仪表盘

使用下拉菜单在地图和图形之间切换。对于地图,使用选择器工具之一(套索选择或框选)仅查看选定区域的数据。

查看运行中的仪表板:

仪表盘在工作!

第六部分:祝贺+资源

恭喜你。您已经创建了一个显示 TigerGraph 新冠肺炎数据的仪表板!好样的。

请在此处记下:

https://colab.research.google.com/drive/1zKsgHHOi6RI4dCAjMKfxS0EO0CUAB6ST?usp=sharing

如果您在此过程中遇到任何错误,请在 TigerGraph Discord 或社区论坛中发布。

https://discord.gg/gRHWBZNpxW https://community.tigergraph.com/

最后,在接下来的日子里期待更多 Plotly + TigerGraph 内容!如果您想创建自己的 Plotly 和 TigerGraph 演示,请将它们放在一起并通过 TigerGraph 社区贡献计划提交,以获得您的条纹。

https://www.tigergraph.com/community-contribution/

非常感谢你阅读这篇博客,下次再见!

利用机器学习绘制入侵物种地图——第 1 部分

原文:https://towardsdatascience.com/mapping-of-invasive-species-using-machine-learning-part-1-800848f72ff6?source=collection_archive---------18-----------------------

变更数据

使用卫星图像进行环境传感和建模

图 1.1:美国得克萨斯州休斯顿,由 Sentinel-1 使用合成孔径雷达拍摄(包含修改的哥白尼 Sentinel 数据(2019),由欧空局处理, CC BY-SA 3.0 IGO )。

这是一篇由 3 部分组成的文献综述,介绍了机器学习如何被用来绘制像桉树这样的入侵物种。此外,还研究了如何估计混交林中的树木种群。
第一部分是对主题的介绍,包括动机以及所需背景知识的简要概述。然后,在第二部分,可以找到不同方法的比较。第三部分是最后一部分,包括结果、结论和展望。

目录

  1. 简介
    一、外来入侵植物物种
    二。卫星任务
    三。合成孔径雷达
    iv。多光谱仪器
    v. 算法
  2. 方法混交林中的树木种群
  3. 结果
    一、入侵物种图谱
    二。混交林中的树木种群
  4. 展望&结论一、结论
    二。观点

介绍

入侵植物物种

入侵植物物种不是生态系统中的本地物种,会伤害当地的动植物。这包括对动物和人类的环境、经济甚至健康威胁。总的来说,入侵植物物种造成财政支出,特别是在农业部门[1]。这些急剧变化的环境的原因可以通过观察人类与这些生态系统的相互作用来找到。开发自然的影响和国际商品交换的增加导致了负面的副作用。入侵是由此产生的过程之一,科学家很难预测。因此,建立一个入侵植物物种发生模式的数据库对于进一步的研究以及空间动态的适当分析是必不可少的。

在观察中有大量不同的植物种类。尤其是种植在伊比利亚半岛以支持当地经济的桉树种群,正在失控。管理种植园外的树木会影响本地植物,甚至取代它们。桉树最初从澳大利亚进口到欧洲,因为它们的生长速度很快,可以提供廉价的建筑木材。但是目前,科学家们估计每年都有巨大的经济影响,这是由入侵物种造成的。总体而言,对环境和自然的潜在威胁仍然研究不足。因此,通过监测这些物种,可以为进一步的研究奠定基础[2]。

与欧洲一样,在亚洲和南美洲,桉树也是管理人工林中最常见的树种之一。林场的数量正在迅速增长,如果管理不当,它们会对环境产生负面影响。在一些研究人员的科学共识中,桉树对环境的影响主要是由于其糟糕的人工林管理。植物本身的生物学特性起着相当小的作用。因此,以大比例和足够的空间分辨率创建快速轮伐期桉树人工林的地图非常重要[3]。正如4所指出的,可持续森林管理至关重要,并提供了生物多样性的指标,例如森林认证计划所依赖的指标。因此,有必要通过遥感来确定不同的树种及其发生模式。参考数据通常是在树种数量有限的成熟森林中获取的,即使树叶在近红外光谱中提供高反射率,也要额外考虑其他波段。由于实地调查不适合大规模收集详细的树种信息,因此使用了适用于大面积应用的遥感工具。在最好的情况下,高空间和高光谱分辨率图像数据由卫星提供。此外,根据所采用的方法,提高时间分辨率也有好处[5]。

卫星任务

现代卫星是大规模地球观测的重要工具。欧洲航天局(ESA)最近免费提供了他们的哨兵卫星拍摄的图像。有两个哨兵任务,每个都有两颗卫星,它们的设备不同。

哨兵-1 包括卫星哨兵-1A 和哨兵-1B。两者都携带双极化合成孔径雷达(SAR)。由于合成孔径雷达和所应用的配置,哨兵-1 号卫星适合于植被测绘。此外,这些卫星提供空间分辨率为 5 米至 20 米的图像

Sentinel-1 SAR:从太空看地球,拉普兰(包含经修改的哥白尼 Sentinel 数据(2019 年),由欧空局处理, CC BY-SA 3.0 IGO )

哨兵-2 任务包括哨兵-2A 和哨兵-2B 卫星。这两个携带多光谱仪器(MSI)的波长从 442 纳米到 2202 纳米。因此,来自全球的 MSI 图像具有足够的时间分辨率,并且是免费的。Sentinel-2 提供 10 米至 20 米的空间分辨率。与 Sentinel-2 任务相同,WorldView-2 也携带 MSI,并根据所用波段提供 0.5 米至 2.0 米的空间分辨率。虽然 WorldView-2 早在 2009 年就已经发射,但 Sentinel-2 是一个更年轻的任务,于 2017 年发射。除了欧空局提供的哨兵任务之外,美国航天局还为地球观测目的提供卫星数据。Landsat 8 配备了一台实用的陆地成像仪(OLI ),而 Aqua 和 Terra 卫星携带了中分辨率成像光谱辐射计。

一旦有了合适的卫星图像,谷歌地球引擎和专题开发平台就可以用来管理和分析大量的数据。

合成孔径雷达

合成孔径雷达(SAR)是一种常用的遥感工具,主要用在飞机或卫星上,用于绘制地球表面的二维图。为此,使用了电磁波。与光学传感器相比,它更少受到恶劣天气条件的影响,例如下雨或下雪。空间分辨率甚至可以低于一米。图 1.1 显示了休斯顿的摘录。这是一张由哨兵 1 号任务提供的图像,由合成孔径雷达拍摄。

多光谱仪器

多光谱仪器(MSI)收集多行图像数据。由于卫星向前移动,行数可以自动增加。三面镜子收集地球反射的光,而 12 个探测器用于观察更大的区域。

图 1.2:Sentinel-2 使用多光谱仪器拍摄的乌克兰基辅(包含修改的哥白尼 Sentinel 数据(2019),由欧空局处理, CC BY-SA 3.0 IGO )。

Sentinel-2 任务中使用的 MSI 提供了几个波段(从 442 纳米到 2202 纳米),允许探索不同的光谱特征。空间分辨率取决于所使用的波段,从 10 米到 60 米不等。图 1.2 显示了基辅的摘录。该图像由哨兵-2 任务提供,由 MSI 拍摄。

算法:简介

随机森林(RF)是决策树的集合。每个节点再拆分成两个节点,直到到达最后一个节点,再拆分就没有意义了。随机森林对噪声具有鲁棒性,并且不像神经网络那样需要大量参考数据。不过,过度拟合是一个更复杂的问题可以很快达到的问题。图 1.3 显示了一个有 8 个叶子的决策树的例子。

图 1.3:随机森林分类器的决策树的示例性结构(图片由作者提供)。

前馈神经网络(FNN)是一种受监督的机器学习方法,其中节点不形成循环,而是将信息从一层转发到下一层。FNN 是最简单的人工神经网络。通常,整个数据集被分成三个不同的部分。研究人员正在寻找,在开始时需要训练集和验证集来调整神经网络及其参数,而测试集则用于生成结果。与 RF 相比,FNN 需要更多的参考数据用于训练目的,并且通过增加更多的深度(即更深的隐藏层)来考虑更复杂的特征细节。那么,过度拟合的神经网络更有可能。图 1.4 显示了一个有两个隐藏层的 FNN 的例子。数据在图中从左向右流动。

图 1.4:由三个输入参数、一个隐藏层和两个输出组成的前馈神经网络的示例性结构(图片由作者提供)。

支持向量机(SVM)是一种有监督的机器学习方法。在给 SVM 提供一个参考数据集后,它能很快分辨出新的输入数据并标记出来,属于训练好的类别之一。内核技巧允许 SVM 有效地执行非线性分类。图 1.5 显示了一个 SVM 的例子,它使用一条直线边界将十字和圆分成两类。

图 1.5:通过最大化最近数据点和决策边界之间的间隔来划分两个类别的支持向量机的示例性结构(图片由作者提供)。

继续第二部分第三部分

文献学

[1] Teja Kattenborn、Javier Lopatin、Michael F orster、Andreas Christian Braun 和 Fabian Ewald Fassnacht。基于 Sentinel-1 和 Sentinel-2 组合数据,无人机数据作为实地采样的替代方案,用于绘制木本入侵物种地图。环境遥感,227:61–73,2019。

[2]安德烈亚斯·福斯特迈尔、安基特·谢卡尔和陈佳。使用 Sentinel 2 图像和人工神经网络绘制 Natura 2000 地区的桉树地图。遥感,12(14),2020。

[3]邓新平、郭、孙、。利用多卫星影像和云计算平台大规模识别短轮伐期桉树人工林。遥感,12(13),2020。

4马格努斯·佩尔森、伊娃·林德伯格和希瑟·里斯。多时相 sentinel-2 数据的树种分类。遥感,10(11),2018。

5 Markus Immitzer、Clement Atzberger 和 Tatjana Koukal。利用甚高空间分辨率 8 波段 worldview-2 卫星数据进行随机森林树种分类。遥感,4(9):2661–2693,2012。

[6]作者截图:伊比利亚半岛树木种植园地图。【在线;访问于 2021 年 3 月 15 日],网址:https://www.globalforestwatch.org/map/.

[7]作者使用福斯特迈尔等人在[2]中提供的图像创作的作品。伊比利亚半岛西部的桉树分布。

[8]作者截图:显示低生物多样性区域的欧洲地图。【在线;访问于 2021 年 3 月 15 日],网址:https://www.globalforestwatch.org/map/.

[9]作者截图:Housten Texas,SAR,2019。【在线;2021 年 3 月 10 日访问】,网址:https://www . esa . int/Applications/Observing _ the _ Earth/Copernicus/Sentinel-1

[10]作者截图:乌克兰基辅,MSI,2020。【在线;2021 年 3 月 10 日访问】,网址:https://www . esa . int/Applications/Observing _ the _ Earth/Copernicus/Sentinel-2

利用机器学习绘制入侵物种地图——第二部分

原文:https://towardsdatascience.com/mapping-of-invasive-species-using-machine-learning-part-2-faf331ecfada?source=collection_archive---------25-----------------------

使用卫星图像进行环境传感和建模

图 1.2:Sentinel-2 使用多光谱仪器拍摄的乌克兰基辅(包含修改的哥白尼 Sentinel 数据(2019),由欧空局处理, CC BY-SA 3.0 IGO )。

目录

  1. 引种
    一、外来入侵植物种类
    二。卫星任务
    iii。合成孔径雷达
    iv。多光谱仪器
    五、算法
  2. 方法
    一、外来入侵物种图谱
    二。混交林中的乔木种群
  3. 结果
    一、入侵物种图谱
    二。混交林中的树木种群
  4. 展望&结论一、结论
    二。观点

方法

入侵物种地图

用于分类和培训目的的数据收集

为了监测入侵物种,科学家们选择了一种使用不同图像数据集的分类方法。为了评估绘图程序,有必要收集参考数据。因此,实地调查提供了一种收集某种实地真相的通用方法。但是它们带来了巨大的缺点。由于大量的非自动化工作和必要的劳动力,现场活动非常昂贵。此外,GNSS 位置测量精度可能变化并导致不准确的结果。此外,很难将数据集、卫星数据和实地活动数据联系起来。不同的视角(俯视图和地面视图)之间的关系并不简单,现场数据通常只提供离散的点观测,而卫星数据则覆盖整个区域[1]。另一个值得注意的方面是,如果不对大面积区域进行监测,在早期阶段发现小块入侵物种是不可能的。因此,需要找到不同的方法,不仅支持实地活动,而且减少实地活动。卫星图像似乎是最合适的方法。此外,欧空局的哨兵任务免费提供图像[2]。

出于训练目的,福斯特迈尔和他的团队使用高分辨率卫星图像结合实地调查来获得桉树发生的参考数据。尽管试验区提供了不同类型的桉树物种,但所有物种仅使用一个类别,即蓝桉。因此,可以应用二元分类方法。通过使用 Sentinel-2 卫星的 MSIs 的 13 个波段和从 442.7 nm 到 2202.4 nm 的中心波长,收集了四个不同时期的图像数据。每个波段的空间分辨率各不相同,从 10 米到 60 米不等[2]。

为了解决收集参考数据的问题,Kattenborn 建议使用无人机(UAV)作为替代来源。这可以极大地提高空间分辨率,同时具有成本效益。此外,无人机是一种多功能的数据收集工具,因为可以配备 RGB 相机或其他更复杂的传感器[1]。

使用无人机收集参考数据有四个优点:

  • 可以提高收集参考数据的速度。
  • 由于不再存在无法到达的地形,因此可以生成更具代表性的数据集。
  • UAV 数据提供了与卫星相同的视角,因此数据是可直接链接的。
  • 数据收集本身可以以更有效的方式实现,包括自动描绘目标物种。

对于每一种入侵物种,研究小组用八轴飞行器进行了四次飞行。两次飞行记录了一个训练集,另外两次收集了独立验证的数据。该团队决定在智利进行第一次测试,测试区域由当地人推荐。octocopter 本身配备了两个传感器:一个 1840 万像素的 RGB 相机和一个超光谱成像帧相机。然后,飞行在地面以上 150 米处进行,以获得 3 厘米的 RGB 图像空间分辨率[1]。

另一方面,邓周围的小组通过收集 Landsat-8 提供的数据和 MODIS 数据以及 Sentinel-2 提供的 MSI 数据,研究了广西桉树人工林的变化。广西是中国最大的木材产地,具有相似的异质性植被类型。为了克服这一障碍,使用了三个步骤来创建分类程序:

  • 创建增强型植被指数(EVI)时间序列
  • 阔叶树和针叶树的分类
  • 去除椒盐噪声的改进

为了训练分类器,使用了谷歌地球提供的高分辨率图像,同时考虑了不同的植物[3]。

Sentinel-2 MSI:从太空看地球,基辅(乌克兰)(包含修改后的哥白尼 Sentinel 数据(2019),由欧空局处理, CC BY-SA 3.0 IGO )。

车型描述

Kattenborn 等人建议使用无人驾驶飞行器(UAV)来收集参考数据。对于每个无人机测绘区域,5000 个随机样本点按 80 比 20 的比例分成训练和验证数据,进行 5 次交叉验证和 100 次重复。为了实现半自动映射,使用了最大熵(MaxEnt)分类器。它允许只对一个成员感兴趣就预测植物入侵的覆盖范围。因此,其他类如本地物种或地面是不需要的。对于数据处理,收集了每个入侵物种的多时相 Sentinel-1 和 Sentinel-2 图像。然后,用无人机数据创建的分类图训练基于哨兵的模型。为了生成可比较的基于无人机的地图,随机森林回归被用于达到与基于哨兵的地图相似的分辨率[1]。

为了在卫星图像上对桉树种群进行分类,福斯特迈尔建议使用前馈神经网络(FNN)。模糊神经网络在遥感应用中很常见,因为与支持向量机、最近邻分类器或随机森林算法相比,它们提供了更高的分类精度。在这个实验中,团队使用了四个完全连接的隐藏层,层的大小逐渐减小。因此,网络的输入为 32 像素乘 32 像素,结果面积为 102,400 平方米(320 米乘 320 米)。选择这个大小是为了有足够的背景信息,同时避免过度拟合并保持较低的处理工作量。该模型是用 Python 中的 Keras 库实现的,并提供一个介于 0 和 1 之间的浮点值作为输出。输出数字表示每个像素上出现桉树的概率。通过在灰色调的浮现图上应用阈值,二进制黑白图显示估计的桉树和非桉树类。为了评估这种方法的性能,使用了预先收集的参考数据集[2]。

如一节所述,围绕邓的中国团队遵循三步走战略,以充分利用他们的数据集。然而,预先对 Landsat-8 OLI 图像进行预处理是必要的,使用 Landsat-8 地表反射代码和 CFmask 来过滤云、雪、水等。然后,应用清晰的检测。由于广西人工林中的大部分桉树用于木材生产,它们遵循一定的生长周期。在年轻的时候,它们生长相对缓慢,而一旦长出更强壮的根,它们每年的增长率为 150 万至 300 万。最后,树木被收割,种植园变成了光秃秃的土地。这一周期信息用于计算增强植被指数(EVI)。当查看几年的图像收集时,该团队能够区分桉树种植园与自然森林、果园和农田。

第二步的目的是建立一个阔叶树和针叶树的分类,在观察到的栽培树木区域,有三种不同的树种:松树、杉树、桉树。松树和冷杉是针叶植物,而桉树是唯一的阔叶树。因此,使用 Sentinel-2 图像进行二元分类是合适的。分类过程中最重要的属性是红边光谱带中的反射率值。然后,应用支持向量机(SVM)。在遥感领域,支持向量机是一种常见的选择,因为它们不依赖于大量的训练样本,并且具有良好的泛化能力。为了消除图像上的噪声和干扰,使用 Sentinal-2 图像生成中值复合图像。

第三步也是最后一步对于基于超像素的优化非常有用。基于像素的检测不会产生非常平滑的地图,但可能包含椒盐噪声。因此,原因是即使相邻像素可能属于同一类,像素也是独立处理的。由于图像分割是包含上下文信息的常用工具,作者使用了一种名为简单非迭代聚类(SNIC)的超像素分割算法[3]。表 2.1 比较了两种绘制入侵物种的尝试之间最重要的差异。

表 2.1:forsmaier 和 Deng 绘制入侵物种图方法的比较(表格由作者提供)。

混交林中的树木种群

数据收集

两种方法都使用多光谱图像数据进行常见树种分类。Persson 等人使用 Sentinel-2 图像,并侧重于多时相的尝试。为此,Sentinel-2 任务的 MSI 提供的 4 幅图像被用于随机森林分类器。这些图像拍摄于 2017 年春季(4 月 7 日和 5 月 27 日)、夏季(7 月 9 日)和秋季(10 月 19 日),覆盖了瑞典的研究区域。结果表明,红边波段 2、3 和 NIR(近红外)波段 8a 以及 SWIR 波段非常重要,而春季和秋季的图像对于分类不同的树种最为有用。此外,作者还注意到图像上的云干扰很少,数据集由同一年的不同物候期组成。野外数据是在 2016 年至 2017 年期间收集的,数据处理包括两个步骤:首先计算树木的断面积,然后在第二步中,计算每个地块中每个树种的出现率4

Immitzer 等人使用的研究地点位于奥地利东部,占地约 3000 公顷。奥地利的一片温带森林是本次实验中所关注的 10 个树种的家园。参考数据是使用林分地图创建的,以发现研究地点内的同类区域。此外,测试集是一个独立的数据集,不包括参考数据[5]。卫星图像由 WorldView-2 卫星使用 8 个波段提供。

型号描述

两个团队都提出了类似的方法,并使用随机森林分类器,因为它易于参数化,对于这种应用是准确的,并且对噪声是鲁棒的。Persson 等人通过将所有波段的光谱信息与实地数据合并来创建参考数据。不同图像数据的组合用于为随机森林算法获取各种参考数据集。

然后,使用 10 倍交叉验证方法来获得 RF 分类准确度4。Immitzer 等人区分了基于对象和基于像素的 RF 分类。除了改变观察到的树种数量,还测试了输入特征数量的变化(使用全部 8 个波段或仅使用 4 个标准波段)[5]。

继续第 1 部分第 3 部分

文献学

[1] Teja Kattenborn、Javier Lopatin、Michael F orster、Andreas Christian Braun 和 Fabian Ewald Fassnacht。基于 Sentinel-1 和 Sentinel-2 组合数据,无人机数据作为实地采样的替代方案,用于绘制木本入侵物种地图。环境遥感,227:61–73,2019。

[2]安德烈亚斯·福斯特迈尔、安基特·谢卡尔和陈佳。使用 Sentinel 2 图像和人工神经网络绘制 Natura 2000 地区的桉树地图。遥感,12(14),2020。

[3]邓新平、郭、孙、。利用多卫星影像和云计算平台大规模识别短轮伐期桉树人工林。遥感,12(13),2020。

4马格努斯·佩尔森、伊娃·林德伯格和希瑟·里斯。多时相 sentinel-2 数据的树种分类。遥感,10(11),2018。

5 Markus Immitzer、Clement Atzberger 和 Tatjana Koukal。利用甚高空间分辨率 8 波段 worldview-2 卫星数据对随机森林进行树种分类。遥感,4(9):2661–2693,2012。

[6]作者截图:伊比利亚半岛树木种植园地图。【在线;访问于 2021 年 3 月 15 日],网址:【https://www.globalforestwatch.org/map/.

[7]作者使用福斯特迈尔等人在[2]中提供的图像创作的作品。伊比利亚半岛西部的桉树分布。

[8]作者截图:显示低生物多样性区域的欧洲地图。【在线;访问于 2021 年 3 月 15 日],网址:【https://www.globalforestwatch.org/map/.

[9]作者截图:Housten Texas,SAR,2019。【在线;2021 年 3 月 10 日访问】,网址:https://www . esa . int/Applications/Observing _ the _ Earth/Copernicus/Sentinel-1

[10]作者截图:乌克兰基辅,MSI,2020。【在线;2021 年 3 月 10 日访问】,网址:https://www . esa . int/Applications/Observing _ the _ Earth/Copernicus/Sentinel-2

利用机器学习绘制入侵物种地图——第三部分

原文:https://towardsdatascience.com/mapping-of-invasive-species-using-machine-learning-part-3-8c9270f95258?source=collection_archive---------27-----------------------

使用卫星图像进行环境传感和建模

图 1.3:陆地卫星拍摄的中国澳门。地球地球图片网拍摄的照片。

目录

  1. 引种
    一、外来入侵植物种类
    二。卫星任务
    iii。合成孔径雷达
    iv。多光谱仪器
    五、算法
  2. 方法
    一、入侵物种制图
    二。混交林中的树木种群
  3. 结果
    一、外来入侵物种图谱
    二。混交林中的乔木种群
  4. 展望&结论
    一、结论
    二。展望

结果

入侵物种地图

在 Kattenborn 使用无人机进行的实验中,高光谱数据为四种测试的入侵物种中的三种提供了最高的准确性。相反,第四种方法在使用高光谱数据和 RGB 数据时得到了类似的结果。一般来说,通过组合不同的预测器,准确性得到了提高。最佳组合是高光谱、纹理和 3D 结构,这提供了最高的准确性。当比较卫星数据时,Sentinel-2 及其多光谱图像比 Sentinel-1 及其合成孔径雷达数据提供了更多植被覆盖率的价值[1]。

在所有三篇论文中,卫星图像被用于数据收集,而 Kattenborn 进一步改进了训练过程,并决定不仅仅依赖实地调查或手工标记的卫星数据,而是使用无人机创建地面实况。当我们查看 Forstmaier 实现的分类结果时,结果是 92.5%的预测准确率。然而,值得注意的是,在所观察的区域中,灵敏度和特异性高度不同。此外,创建的二进制地图不能很好地代表较小的桉树片,因为在选择阈值时必须找到一个折衷方案[2]。邓和他的团队取得了稍好的结果,总体分类准确率为 93.59%。即使两个不同的来源被用来建立一个地面真相,作者担心,目前的方法是低估了桉树人工林造成的数据缺乏。作为参考数据,考虑了 2017 年的一次实地调查和高分辨率的谷歌地球数据。除了分类地图之外,由于收集的数据,该团队还能够创建一个日历,显示桉树每年的种植分区[3]。

图 2.1:伊比利亚半岛地图,显示了植树造林的情况。该地图是使用 Landsat、SPOT 或 RapidEye 卫星影像的监督分类和手动多边形描绘创建的。图像日期各不相同,但可以集中在 2015 年左右。分辨率也因国家而异[6]。

当查看伊比利亚半岛的树木种植地图时,可以发现与桉树的出现有很强的相关性。Globalforestwatch 免费提供森林图像数据,在选择感兴趣的区域时可以应用不同的数据层。因此,可以创建一个显示伊比利亚半岛上人工管理的树木分布的地图。

图 2.1 证明了伊比利亚半岛上大多数管理的树木种植园位于西部,用于生产木质纤维和木材。通过比较图 2.1 和图 2.2,我们可以看到这个结果与 Forstmaier 等人在[2]中显示的结果重叠,绘制了伊比利亚半岛西部的桉树分布图。

图 2.2:地图显示了 2010 年至 2018 年间伊比利亚半岛西部的桉树出现率占最大森林覆盖率(FC)的百分比[7]。

混交林中的树木种群

当我们比较树种分类方法的结果时,可以发现明显的差异。虽然 Persson 等人设法获得了 88.2%的总体分类准确率,但 Immitzer 和他的团队实现了 82.4%的总体准确率。两个团队都使用了整个可用的数据集来获得最佳结果,也使用了所有可用的光谱带。当以较少影像和较少使用的光谱波段的形式使用较少的输入数据时,他们都取得了良好的性能,但得出了相同的结论,即每增加一个波段都会改善结果,即使只是轻微的改善。Persson 等人指出,5 月拍摄的图像在仅依赖单一图像时提供了最佳结果(总体准确率为 80.5%)。最重要的波段是 3 个红边和 NIR 波段。使用这种波段提供的影像上的树种已经是高度可分的4。另一方面,Immitzer 等人在区分阔叶树和针叶树时取得了非常好的结果,没有一个错误分类。此外,使用 4 个标准波段而不是全部 8 个波段会导致精度稍差。虽然这项研究的结果高度依赖于观察到的树种,但不同的其他研究强调了这一说法,并指出树种的数量和树种本身起着主要作用。此外,作者建议使用基于对象的分类方法,因为基于像素的方法提供了明显较低的准确性。最重要的波段是绿色、近红外和蓝色。

此外,建议使用视觉照片判读来创建适当的图像数据集进行验证,因为实地调查(即从地面进行测量)可以提供自上而下视角之外的另一种结果。10 棵树的总体分类精度约为 82%(基于对象),生产者的精度介于 33%(欧洲犀木)和 94%(欧洲山毛榉)之间。基于对象的方法比基于像素的方法提供了更好的结果,并且当使用全光谱分辨率而不是子集时,分类精度增加[5]。

总之,这两种遥感工具(Sentinel-2 和 WorldView-2)由于其空间和光谱特性,非常适合提供有关混交林树种分类任务的图像。

图 2.3 显示了南欧的生物多样性热点。国际保护组织的生物多样性热点用红色标出,通常位于南欧。该数据集收集于 2011 年,仅涵盖陆地上的濒危区域。国际保护组织的生物多样性热点必须满足以下标准:

  • 至少有 1500 种维管植物(超过世界总数的 0.5%)是特有的。
  • 至少 70%的原始自然植被已经消失。

另一方面,分辨率为 30m 30m 的绿色标记树木覆盖的区域。这些内容是在 2000 年和 2010 年使用 Landsat-7 和 MSI 拍摄的。

图 2.3:中欧和南欧生物多样性热点地图。红色区域标志着由于特有现象和人类威胁导致的低生物多样性区域,而绿色区域标志着树木覆盖密度[8]。

展望和结论

结论

总而言之,每篇论文都强调了监控入侵物种的重要性。用无人机收集图像的方法不仅提供了一种更快、成本更低的获取卫星分类参考数据的方法,而且质量更高。这导致更精确的卫星分类图。组合不同的信息图层(如光谱、纹理和结构)可提高地图精度。然而,制图质量也取决于植物种类及其特性(例如,植物出现在较小的斑块中)[1]。

检测像桉树这样的入侵物种并对其进行监控对于保持一个地区的高生物多样性至关重要。通过这样做,灵敏度和特异性很大程度上取决于所选择的参数。尽管 FNN 是一种相当简单的方法,但神经网络能够很好地解决不同的土地覆盖分类任务。分类精度很高,但仍然不是没有误差。因此,将 FNN 应用于 Sentinel-2 提供的多光谱图像被证明是监测入侵物种的合适方法。此外,该研究指出,葡萄牙的 9 个 Natura 2000 地区(保护区)受到桉树的严重影响[2]。

不利的一面是,卫星数据通常依赖于天气。频繁的云层会导致数据的缺乏,因为卫星只是偶尔绕地球的某些部分运行一次,所以很难补偿这种损失。哨兵-2 任务降低了这种风险,因为重复率更高。此外,合成孔径雷达(SAR)是减少对天气依赖的另一种方法,因为这种技术受使用不同波长的云的影响较小[3]。

短轮伐期人工林是世界不同地区的一种日益增长的现象。一些科学家提请注意生态系统可能面临的危险,但有必要对这些种植园进行大规模观察,以进一步了解影响。

当我们比较一下用卫星绘制桉树地图时,邓和福斯特迈尔能够绘制出非常精确的地图。尽管两个团队没有使用相同的测试集,但 Forstmaier 等人设法获得了与 Deng 几乎相同的结果,同时使用了更少输入数据的简单得多的方法。

通过观察混交林中树木种群的分类,两个团队都使用了多光谱卫星图像。Persson 等人使用所有波段和 4 幅图像中的每一幅图像获得了 88.2%的总体准确率。最重要的照片是在五月拍摄的。当不考虑其他 3 个因素时,它提供了 80.5%的总体分类准确率。然后,将其他月份相加,准确度依次提高。仅使用全部 40 个波长中的 13 个会略微降低结果(86.3%的总准确度),最重要的波段是红边、窄 NIR 波段和大多数 SWIR 波段4。Immitzer 周围的团队在用 8 个光谱带对 10 种不同的树种进行分类时,总体准确率达到了 82%[5]。

与其他树种相比,一些树种的分类精度明显较低,作者建议提高时间分辨率以改善分类。

然而,当比较两种树种分类的尝试时,需要考虑重要的差异,这最终导致准确性的偏差。两个团队都检查了不同的树种和不同数量的树种,这极大地影响了整体结果。但是他们也使用不同的卫星任务。WorldView-2 任务不仅比 Sentinel-2 老 6 年,而且相机系统也各不相同。

观点

尽管方法不同,但他们有着相同的目标:改善地图绘制,特别是入侵物种的地图绘制,了解它们对环境的影响,并最终保护人类、动物和其他本地植物。虽然一些国家,尤其是岛屿,很久以前就已经禁止进口外来物种,但其他国家却试图开发某些外来植物。现在,他们不得不处理一些对当地环境的严重威胁,但总体程度仍不清楚。

提出了不同的方法来改进观察程序。收集参考数据的半自动方式是朝着正确方向迈出的第一步。当然,无人机不能覆盖像卫星图像那样大的区域。但是训练和验证数据对于改进分类任务的结果是必不可少的。

另一方面,目前的限制可以在卫星图像本身中找到。如果向研究人员提供分辨率更高的数据,甚至可以在减少工作量的同时获得更好的结果。更多的卫星将提高时间分辨率,而更好的仪器将提高空间分辨率。未来,欧空局将通过将更多的卫星送入轨道来扩展地球观测任务,这些卫星将携带不同的工具,有望改善对植被的监测。

为了进一步改进福斯特迈尔等人提出的 FNN 方法,可以扩展输入数据层。除了仅仅使用 Sentinel-2 和 MSI 收集的图像数据,还可以将其他任务和不同的遥感工具提供的数据结合起来。

当涉及到绘制植被甚至入侵植物物种时,依赖大的时间分辨率甚至扩展似乎是有问题的。尽管这适用于大规模轮伐期种植园,但自然发生模式会定期发生变化。因此,前一年的数据可能与实际数据有很大差异。此外,在收集具有较高时间分辨率的数据集时,会有明显的延迟。新引进的遥感工具提供的数据不能立即使用,但科学家们需要等到几个月或几年以后。

激光雷达可以是一个不同的数据图层,以进一步改善树木分类,尤其是在参考数据采集方面。随着制造商开始使用 MEMS 技术,同时价格大幅下降,激光雷达测量设备变得越来越可靠。无人机收集的激光雷达数据不仅可以提供树冠数据,还可以揭示下面的植被。

继续第一部分第二部分

文献学

[1] Teja Kattenborn、Javier Lopatin、Michael F orster、Andreas Christian Braun 和 Fabian Ewald Fassnacht。基于 Sentinel-1 和 Sentinel-2 组合数据,无人机数据作为实地采样的替代方案,用于绘制木本入侵物种地图。环境遥感,227:61–73,2019。

[2]安德烈亚斯·福斯特迈尔、安基特·谢卡尔和陈佳。使用 Sentinel 2 图像和人工神经网络绘制 Natura 2000 地区的桉树地图。遥感,12(14),2020。

[3]邓新平、郭、孙、。利用多卫星影像和云计算平台大规模识别短轮伐期桉树人工林。遥感,12(13),2020。

4马格努斯·佩尔森、伊娃·林德伯格和希瑟·里斯。利用多时相 sentinel-2 数据进行树种分类。遥感,10(11),2018。

5 Markus Immitzer、Clement Atzberger 和 Tatjana Koukal。利用甚高空间分辨率 8 波段 worldview-2 卫星数据对随机森林进行树种分类。遥感,4(9):2661–2693,2012。

[6]作者截图:伊比利亚半岛树木种植园地图。【在线;访问于 2021 年 3 月 15 日],网址:【https://www.globalforestwatch.org/map/.

[7]作者使用福斯特迈尔等人在[2]中提供的图像创作的作品。伊比利亚半岛西部的桉树分布。

[8]作者截图:显示低生物多样性区域的欧洲地图。【在线;访问于 2021 年 3 月 15 日],网址:https://www.globalforestwatch.org/map/.

[9]作者截图:Housten Texas,SAR,2019。【在线;2021 年 3 月 10 日访问】,网址:https://www . esa . int/Applications/Observing _ the _ Earth/Copernicus/Sentinel-1

[10]作者截图:乌克兰基辅,MSI,2020。【在线;2021 年 3 月 10 日访问】,网址:https://www . esa . int/Applications/Observing _ the _ Earth/Copernicus/Sentinel-2

使用 ArcGIS 绘制数据科学家的年平均工资

原文:https://towardsdatascience.com/mapping-the-annual-mean-wage-of-data-scientists-with-arcgis-8c0fa6aa8b24?source=collection_archive---------28-----------------------

图片由 Freepik 上的用户 11628272 提供

哪个统计区域的年平均工资最高?

使用分析工具为地图增值。

本文将探索 ArcGIS,根据我们从美国劳工统计局收集的数据绘制地图。为了澄清,我们将在这里看到的年平均工资数据包含了“数据科学家和数学科学”职业。

数据从州一级进入统计领域。这些地区被美国联邦政府划分为大都市统计区(MSA)和小城市统计区(μSA)。它们可能与县甚至州重叠。

同样,MSA 也是一个类似城市的区域。它通常有很高的人口密度和经济中心。另一方面,μSA 通常不像大城市那样具有政治和经济上的重要性,但它们在大格局中仍然是重要的。由于我们的数据集的性质,我们可能会将重点放在 MSA 数字的分析上。

需要指出的另一件重要事情是,我们的数据集只有关于美国市场的数据。数据报告截至 2019 年 5 月。

现在我们已经完成了内务处理,让我们来看看我们将在这里涵盖的内容,以及我们希望您获得的预期结果和见解。

1 —我们能制作的最基本的 ArcGIS 地图。

2-演示“热点分析”(这是 ArcGIS 中可用的聚类分析之一)。

3 —从国家级别向下钻取到州级别。另外,结合热点分析和缓冲区分析。

4-了解各州和统计领域的数据科学家的当前或预期薪资。

但是,卢西亚诺,为什么选择 ArcGIS?

在某种程度上,我们确实可以使用其他解决方案,比如 Tableau 或 Power BI。但是,我喜欢 ArcGIS 的一点是,它是为处理多个图层而设计的。是的,您可以合并和组合大量不同的数据,并以有意义的方式排列它们。ArcGIS 中的控件基本上是无穷无尽的,这也是我选择它作为这个特定项目的原因。我是说 ArcGIS 是我们现有的最好的制图工具吗?是,也不是。这完全取决于项目的范围和你必须考虑的其他因素。最好的工具是你成功地用来表达你的观点的工具。

我们应该从一个问题开始这个项目吗?

绝对的!我们可能会提出以下问题之一,但不限于此:

  • 哪些州的平均工资最高和最低?
  • 哪个统计区域的年平均工资最高和最低?

我知道这些问题很简单。但是,如果你目前正在寻找一份数据科学家的工作,这篇文章将为你提供一些数据,以更好地协商你的工资。这不是很有用吗?接下来,我们开始绘制地图来回答这些问题,所以请系好安全带。

映射还是不映射

决定何时使用地图并不总是简单明了的。首先考虑你的观众是一个好习惯。然而,一个常见的问题是,关于信息的呈现,他们经常不知道自己想要什么,或者需要。这有时会令人沮丧,但你会去测试,看看什么对你有效——对他们有效。

对于本文,我们将跳过这个对话,并提出地图。我们相信它们是可视化数据的一种强有力的方式,尽管并不总是被推荐。您将看到如下三个不同的图:

1-基本 ArcGIS 地图。为了澄清并确保我们都在同一页上,这里的“基本”实际上是指显示计数或任何类型数据的地图。在我们的例子中,我们将看到一个显示各州年平均工资的地图。它没有任何花哨的分析工具。

2-在第二张地图中,我们将使用名为“热点分析”的 ArcGIS 工具。这是一种聚类分析。通过这种方法,我们可以看到年平均工资的热点和冷点在哪里。然而,我们不看州一级,而是看大都市的统计区域。这将为我们提供比查看州级别更详细的信息。

3 —最后但同样重要的是,我们将重点分析一个特定的状态。我们将继续在 MSA 级别利用热点分析。然而,我们将展示缓冲区分析如何帮助我们构建一些区域。

如果您有任何问题或意见,请随时联系我。

基本地图

下面我们看到了我们在这里绘制的最基本的地图。我们还在其顶部添加了“前 5 名”部分,以便于理解,并提供一些“正确的”见解。

图片 1(来自作者)。美国各州年平均工资地图。

我们上面看到的这张地图通常是我们做的第一张。这个想法是为了获得关于数据的高层次直觉。这里的问题是,你可能认为仅仅搬到,比方说,加州就可能付给你更高的工资。因为整个州都处于“红色”——意味着高年平均工资——你可能会被诱惑搬到加州的任何地方。因此,在下一张图中,我们试图获得更详细的信息。

热点分析地图

有了这张地图,我们可以更好地了解全国工资最高和最低的。虽然我们没有很多数据点(观察值),但这种类型的分析使我们能够专注于极端情况:低和高。现在你确切地知道去哪里或不去哪里。

图片 2(来自作者)。美国大都市统计区年平均工资图。

热点和缓冲区分析图

现在,我们没有从东海岸到西海岸,而是选择了加利福尼亚来深化我们的分析。这里可以保持我们在以前的地图中使用的相同参数,但现在,我们在旧金山大桥周围添加了一个缓冲区。这有助于我们以英里为单位看到数据科学家在哪里赚了更多的钱——通过 MSA。

显然,我们都知道这是湾区。这不应该是一个惊喜,对不对!?但这里的重点是使用数据来证实我们的假设,并找到一种不容置疑的方式来展示我们的结果。我们希望这个练习能帮助你打开思维,激发你创造新的和令人敬畏的东西。

图片 3(来自作者)。加利福尼亚州大都市统计区年平均工资地图。

概括起来

在本文中,您了解了使用 ArcGIS 绘制数据的不同方法。现在,您已经知道 ArcGIS 有一个分析工具可以帮助您增强分析并推动决策制定。

此外,您还获得了有关数据科学专业的英特尔信息。希望你今天至少学到了一件新东西。

我们可以做的使这个项目更好的其他事情是合并不同的数据集,并添加与这些静态地图相反的交互式地图。这些都是很酷的特性,但是请记住,如果您已经学到了一些东西,我们就此打住。干杯!

描绘得梅因农贸市场的游客

原文:https://towardsdatascience.com/mapping-visitors-to-the-des-moines-farmers-market-4419c32a1459?source=collection_archive---------45-----------------------

秋季大学生的回归推动了人口结构的变化吗?

Unsplash 上由 Toa Heftiba 拍摄的照片

本文是一个两部分系列文章的第二部分,该系列文章关注的是如何利用来自手机 pings 的客流量数据来分析游客人口统计数据。 第一部分:利用客流量数据对得梅因农贸市场进行人口统计分析 提供了指导本文的重要背景。请在任何社交媒体分享中标记 SafeGraph。

人口统计分析推动零售商、大学、游乐园等的决策。理解你的消费者的重要性不能被夸大。

在上一篇文章中,我们发现得梅因农贸市场——爱荷华州得梅因市中心从 5 月到 10 月的大型每周活动——每年秋天游客的年龄和收入都会下降。我们假设观察到的人口变化是由大学生返校驱动的。虽然不是一个统计上严格的测试,但数据可视化通常具有现实世界的价值,映射也不例外。我们将通过绘制农贸市场游客的住宅区来检验我们的假设。

数据

第一部分已经介绍了设置,所以我们将简单介绍一下分析中使用的数据。我们使用 SafeGraph 的邻域模式。从文档中:

SafeGraph 的邻域模式数据集包含按人口普查区块组(CBG)聚合的客流量数据。了解 CBG 在一周中的哪一天最忙,CBG 在一天中的什么时间最忙,在早餐、午餐和晚餐期间停止的设备从哪里出发,以及工作日和周末的人口统计数据如何比较。

虽然我们在第一部分中查看了 2018 年和 2019 年,但本文的范围仅限于 2019 年。此外,我们只分析来自得梅因所在的波尔克县的游客。在继续之前,有一个重要术语:

普查区块组(CBG): 同一普查区域内的一组区块。CBGs 通常包含 600 到 3000 人,是美国人口普查局使用的地理单位。

我们的可视化处于 CBG 水平,这是美国人口普查局发布人口统计数据的水平。

绘图

首先,我们来看一张 2019 年 7 月的地图。

2019 年 7 月:波尔克县 CBG 家居得梅因农贸市场的游客量。

得梅因农贸市场由黑色记号笔和深灰色 CBG 显示。德雷克大学和大观大学用蓝色标记表示。

现在,一张 2019 年 10 月的地图。

2019 年 10 月:波尔克县 CBG 家居得梅因农贸市场的游客量。

很难看出两者之间有什么大的区别。让我们结合各自的数据来看看从 7 月到 10 月游客的相对变化。为了做到这一点,我们为每个 CBG 取(10 月访问者的数量)/(7 月访问者的数量)。例如,如果给定的 CBG 在 7 月有 100 个访问者,在 10 月有 125 个访问者,相对变化是 125/100 = 1.25,相当于 125%。换句话说,CBG 10 月份的游客比 7 月份多了 25%。

在这张地图中,如果 CBGs 在 10 月份的访客比 7 月份多,我们将把它涂成蓝色。否则,它们将被涂成红色。白色表示每个月的访客数量接近相同。因此,如果我们的假设是正确的,我们预计会在两所大学周围看到一些蓝色(我们假设大多数学生住在校园内/附近)。

很难看到,所以让我们放大感兴趣的区域…

这是一张比前两张更有用的地图。看起来我们可能会有所发现!德雷克大学所在的 CBG 10 月份的游客数量是 7 月份的 12 倍。你也可以看到 CBG 的平均年龄是 19 岁,平均收入是 35192 美元。

此外,地图的大部分是红色,但每个大学周围都有一簇蓝色的 cbg。有趣的是,在缩小的地图上还有另一个无法解释的蓝色星团…在谷歌搜索后,我发现这个蓝色星团是 Faith Baptist 圣经学院的所在地,这进一步证实了我们的发现。

结论

重要的是要记住,相关性不是因果关系,我们的分析有许多潜在的混淆因素。例如,得梅因市中心地区是该市的夜生活热点之一;也许我们观察到的人口变化与市中心酒吧的关系比与农贸市场的关系更大。(注意:我们可以通过使用 SafeGraph 的兴趣点步行交通数据、 SafeGraph 模式 来纠正这一点,但这超出了本笔记本的范围)。再者,SafeGraph 的数据只是整个人群的样本;我们使用原始计数,但最佳实践是将数据标准化,以努力纠正偏差。

然而,我们的发现看起来确实像是某种东西。它们有直观的意义,它们甚至可能有现实世界的意义,一个容易被遗忘的统计意义的表亲。应用到现实世界中,我们的发现具有实际的、可操作的洞察力,这并不像我们在数据科学中希望的那样普遍。例如,Greater Des Moines Partnership(DSM 农贸市场的生产者)可以利用这种类型的分析来优化农贸市场以适应人口变化。像学生折扣、校园班车、社交机会、庭院游戏和免费食物/饮料票这样的事情可以在每个周六早上最大限度地提高出席率。

提问?

我邀请你在 SafeGraph 社区#safegraphdata 频道问他们,这是一个面向数据爱好者的免费 Slack 社区。获得支持、共享您的工作或与 GIS 社区中的其他人联系。通过 SafeGraph 社区,学者们可以免费访问美国、英国和加拿大 700 多万家企业的数据。

规划您的企业数据环境

原文:https://towardsdatascience.com/mapping-your-enterprise-data-landscape-a796374a2afe?source=collection_archive---------31-----------------------

非结构化数据

你知道,有时我太习惯于所有这些数据了,这似乎并不令人兴奋。直到你做了一件让你想起为什么要做的事情。

今天,我要向一家大型机构的高管介绍我们的工作。这是他们第一次听说我们如何掌控他们的整个数据环境。结构化 非结构化数据。这不是一个容易讲的故事。所以你只要从头开始。

马库斯·斯皮斯克在 Unsplash 拍摄的照片

一些关于隐私的法律法规要求组织必须知道他们存储个人数据的地方。这不是一个简单的问题。要回答这个问题,您必须协调物理基础设施和业务。许多商务人士更喜欢电子邮件中的附件,而不是共享驱动器的链接。他们不想谈论数据库和文件服务器。

将信息映射到物理数据存储区时,有许多因素需要考虑。从头开始,第一个问题是:你的企业数据源是什么?

  • 系统和应用程序(ERP、CRM、财务、人力资源等)。)
  • 数据库(SQL、Oracle 等。)
  • 电子邮件服务器(即 Exchange)
  • 共享驱动器(网络文件夹、本地驱动器、Sharepoint、OneDrive、团队等。)

列举的例子暴露了这一点,后者是最重的。视行业而定,电子邮件服务器实际上可能包含更多信息。了解这些数据源包含的所有信息,如何开始呢?有人知道关于物理数据库位置的好故事吗?

扬·安东宁·科拉尔在 Unsplash 上拍摄的照片

在这个层面上——尽管很模糊——我们在说什么还是很清楚的。企业将了解他们是将信息存储在特定的应用程序中、共享驱动器上还是他们的邮箱中。为了在企业层面上实现这一点,我们必须开始讨论服务器、服务器名称和 IP 地址。对于大量观众来说,这可能很快变得过于专业。

在做这个练习时,也许要评估你的数据有多少是由第三方托管的,为什么。

然而,对理解的追求并没有就此结束。要真正理解数据,需要更深层次的细节。系统和应用程序链接到数据库。数据库被分成数据表。数据表转换成数据属性(列)。文件服务器被分成文件共享。文件共享到文件夹中。文件夹包含数据对象(例如文档或电子表格)。企业数据存在于这些属性和对象中。

最酷的事情是,如果您映射企业数据源中的实际信息,那么您可以将您的发现一直提升到最高级别。您将确切知道哪些应用程序需要额外的安全措施,并相应地保护它们。去年发生了如此多的网络攻击。

但我想以积极的方式结束。这次演习不仅仅关注法律和安全。通过映射您的企业数据源,您不仅可以确定存储个人信息的位置,还可以围绕知识管理的主题来管理内容。嘿,企业告诉我,我们对人工智能了解多少?或用于产品信息管理的产品编号。几乎自我更新的产品信息。很酷的东西。

您如何管理您的企业信息?

马拉松训练:数据透视

原文:https://towardsdatascience.com/marathon-training-a-data-perspective-ba2fc00c912b?source=collection_archive---------22-----------------------

(上图)英国约克。卢克·波特在 Unsplash 上拍摄的照片

来自 Strava 的数据分析(通过其 API)

我的第一次马拉松

2018 年末,38 岁的我意识到,我在 20 多岁和 30 多岁时进行的中等水平的体育锻炼已经成为遥远的记忆。生活完全占据了我的业余时间,当我反复思考并不遥远的向 40 多岁的转变时,我知道机不可失,时不再来。

我对任何形式的运动都不感兴趣,并且非常讨厌学校的体育课。当我在 25 岁左右开始定期锻炼时,我认为 3 英里跑已经足够了,10 公里跑是值得筹集赞助费的活动。

现在的问题是:我能找到什么样的挑战来激发足够的兴奋和注意力?什么能把我从久坐不动的麻木状态中唤醒?当一个同事提到他们最近完成了约克郡的马拉松比赛,并且他们度过了一段美好的时光时,答案出现在我面前。

我立即进入。毕竟,还有将近一年的时间,这肯定是足够的时间来恢复身材。在通知我妻子后,我最初的动力感被第一反应“你要死了”所阻碍,但我还是坚持了下来。

为了提高我的生存几率,我加入了当地的一个跑步俱乐部,令我震惊的是,这个俱乐部对待 10 公里跑就像我对待休闲散步一样。但这种心态的转变正是我所需要的,几个月后,这样的距离已经成为了家常便饭。值得庆幸的是,我住在一个小村庄里,周围的路线都很宜人(见下图),所以在夏季的几个月里,训练通常都很愉快。

(上图)一次训练中的场景(图片由作者提供)

我花了 3 个月的时间准备马拉松,尽我所能训练。我画出路线,试图遵循一个基本的计划,尝试营养,穿破我的鞋子。我的配速完全是随意的,而且经常是快,因为在我的天真观点中,更快等于更健康!

在重要的一天,我设法绕过了全程,但它花了我比我希望的更长的时间(4 小时 35 分钟),我不得不在最后的 4 或 5 英里慢下来步行 3 次。几个星期后,我决心做得更好,再次参赛。

由于新冠肺炎,2020 年的比赛变成了 2021 年的比赛,在这个大日子的 3 个月前,我的训练又开始了。这一次,我决定阅读耐力跑的科学知识,这让我想到了心率训练的概念。

心率区

我读到的基本要点是,有 5 个不同的心率区,不同区域的锻炼适合不同类型的训练。这些是,

  • 1 区:非常轻。最大值的 50–60%。心率
  • 二区:光。最大值的 60–70%。心率
  • 第三区:中度。最大值的 70–80%。心率
  • 4 区:硬。最大值的 80–90%。心率
  • 第 5 区:最大值。最大值的 90–100%。心率

你需要做的就是确定你的最大心率来计算出这些区域(或者像 Strava 这样的应用程序会帮你计算出来)。解决这个问题的近似公式是,

最高。心率= 220 —年龄

这使我的最高心率达到了 182。我将它插入到 Strava 中,并检查了我最近几次跑步的区域百分比。我完成的最后一次跑步是 10 公里,Strava 告诉我,我将在 5 区花费超过 90%的时间。这是不可能的(5 区是你最快的冲刺。想想被一群疯狗追着跑!).我还准备了一些批评上述公式的文章,所以我寻找一种替代技术。

相反,我所做的是找到一个跑步的地方,我在一个陡峭的山上冲刺,寻找我的峰值心率,结果是 200。然后我把它插入 Strava,我所有的区域突然变得有意义了(我的快速 10 公里现在大部分是第 4 区)。据我所知,这不是最科学的方法(特别是使用腕部心率监测器,而不是胸部心率监测器),但这是我能做到的最好的方法,看起来差不多没问题。

对于马拉松训练,我找到的文章建议主要在 2 区训练,在这里和那里有少量的 4 区。对我来说,2 区是每分钟 120-140 次。我记得我第一次在 2 区跑步。我不得不走得很慢,感觉就像在走路一样。结果,我的跑步训练似乎要花很长时间,因为我试着一周跑 4 次,而两年前是一周 3 次(不够),所以我很快就没时间了。

过了一段时间,我决定唯一能让我适应训练的方法就是跑得快一点(但还是比两年前慢)。那就只好这样了!

然后大日子又来了。问题是,由于我希望有更好的训练方法,我能更快地适应吗?我会不停地四处走动吗?还是我现在已经大了 2 岁的事实会让我退缩?我们来看数据!…

培训分析

(上图)训练路线图(图片由作者提供)

首先,简单看一下马拉松前 3 个月的距离,

  • 2019 年总训练距离:493 公里(306 英里)
  • 2021 年总训练距离:559 公里(347 英里)

好的,那么在 2021 年再往前一点。出于兴趣,左边的图片显示了我在 2021 年训练期间的主要路线。

现在让我们更仔细地看看一些数据,从两个不同年份的每月运行次数开始,

(上图)作者图片

注意,马拉松是在每年的十月中旬举行的。这里我们可以看到,2019 年,7 月到 8 月有一个大的跳跃,然后我实际上在 9 月份跑得更少了。相比之下,2021 年显示出在 10 月之前的 3 个月中逐渐增加。

心率呢?下图显示了我的心率在训练期间的重叠直方图,其中显示了平均心率(虚线),

(上图)作者图片

按照计划,我的平均心率在 2021 年降低了。我每年运行超过 30 次(这是有效的 t 检验的近似经验法则最小值,由于中心极限定理),所以我对上述数据运行一次(特别是单尾测试,寻找 2019 年大于 2021 年),

Welch Two Sample t-testdata:  marathon_all_training$average_heartrate[marathon_all_training$Year == "2019"] and marathon_all_training$average_heartrate[marathon_all_training$Year == "2021"]
t = 6.0937, df = 68.361, **p-value = 2.868e-08**
alternative hypothesis: true difference in means is greater than 0
95 percent confidence interval:
 7.420702      Inf
sample estimates:
mean of x mean of y 
 167.2844  157.0682

微不足道的 p 值!换句话说,如果零假设(均值之间没有差异)是真的,那么极不可能看到这样的数据。

这是分解心率数据的另一种方法,

(上图)作者图片

有趣的是,2019 年的中值心率(盒须图中较粗的水平线)在整个训练期间没有真正的模式,在 2021 年,随着我开始休息,心率稳步上升,然后在 10 月份下降。这也可以从平均速度分解中看出,

(上图)作者图片

这表明我的训练受到了更多的控制,并且我遵循了一个正确的计划!

上面我展示了我 2021 年的总距离比 2019 年多。我想知道这在长跑(我定义为超过 16.1 公里(10 英里)的任何东西)方面意味着什么。在下面的图中,彩色条表示长距离,灰色条表示小于该距离的距离。

(上图)作者图片

2019 年 13 个,2021 年 11 个,所以实际上第一次会更多。然而,你可以在 2021 年看到更好的终点减量(即马拉松前的休息),4 次更短的跑步,而 2019 年只有 2 次。

重要的日子

我两次马拉松的完成时间是,

  • 2019 完成时间: 4 小时 35 分钟
  • 2021 完成时间: 3 小时 58 分钟

我真的很高兴我用了不到 4 个小时的时间(我没想到会这样!).事后看来,看着上面的数据,我相信多一点距离,随着时间的推移控制和稳定地增加训练距离,再加上训练期间较慢的配速(因此平均心率较低)都是造成差异的原因。

这是我在约克郡马拉松比赛中的一张照片,

又一个情节。这是我每场马拉松比赛当天的心率。你可以看到 2019 年的 3 个点,我在那里短暂地放慢了脚步。我完全筋疲力尽了,尽管我的心率(和步速)比 2021 年还低。与此形成鲜明对比的是,在 2021 年,你可以看到更高的心率(因为我更舒适地推动自己),接近尾声时没有下降。

(上图)作者图片

如果这篇文章启发了任何人考虑马拉松,我可以强烈推荐约克郡的马拉松。它相对平坦,组织良好,人群很大,你可以跑过北欧第二大哥特式大教堂(约克大教堂)。请参见此处的了解参赛详情和更多信息。

(上图)约克大教堂。由理查德·格伦丹宁Unsplash 上拍摄的照片

附录—关键包和链接

互联网最不需要的就是更多的代码向你展示如何用 R 语言创建一个情节,所以我在这篇博文中省略了细节。但是,请参见下面的一些说明和软件包的关键链接。我在这个分析中使用的主要工具是 rStrava。请随时给我发信息了解更多细节。

三月版:温暖而模糊的数据科学

原文:https://towardsdatascience.com/march-edition-warm-and-fuzzy-data-science-9d3cfaa1905e?source=collection_archive---------40-----------------------

月刊

数据科学不需要像数学看起来那样冷漠和遥远

照片由波格丹一世·格里西克派克斯拍摄

随着您对数据科学的了解和实践,避免抽象变得越来越难——通常是以特定编程语言编码的算法的形式,或者是一个想法的数学特征。我想在这里强调的是,数据科学及其组成学科(统计学、机器学习等。)的起源与我们感知和思考世界的方式密切相关。我想邀请您将您遇到的每一个数据科学原则或重要想法与您的生活联系起来:给定的学习算法与您自己的学习方式之间有哪些相似之处?无论是有监督的还是无监督的,甚至是强化学习,这些范式及其底层技术都不需要像我们可能描述的那样抽象。

做到这一点的方法之一是寻找机会,以一种与广大受众非常相关的方式谈论数据科学概念。在我作为一名数据教育工作者的经历中,我经常发现思考简单场景的需要和愿望,这些场景完美地描述了数据科学中一个潜在的令人生畏的想法。

例如:我经常在网球(或任何其他 1-1 运动)的背景下描述泛化的概念。比方说,一个人选择在一所学院训练网球比赛,只和同一个教练一起训练,几年都没有和其他人一起比赛过。过了一段时间,这个人开始不断地击败他们的教练,并决定加冕自己为世界上最好的网球运动员。这个标题有多现实?我们敢说这个人代表了过度拟合数据问题吗?毕竟,在和他们的教练玩了这么多之后,他们一定会记住他们的模式并加以利用。如果我们让这个人和另一个学院的球员比赛会怎么样?我们的选手击败对手的可能性有多大?

即使你自己不练习一项运动,我相信你一定能权衡与不同对手比赛的好处。你可以训练重复性的动作和技术,但是在压力面前制定策略、做出反应和执行的能力最好是通过在测试你的能力时不断面对不同的对手来激发。这就是我所说的学习中的良好概括。

勇往直前,挑战自己,用简单而又有意义的正确方式解释抽象概念。试着向朋友或同事解释,评估他们的兴趣和同意程度。自己拿这个反馈,努力成为更好的数据科学传播者。毕竟,清晰而吸引人的沟通是现代数据科学家最容易被忽视的技能之一!

你能想到其他更容易沟通的概念吗?探索 vs 剥削?偏差-方差权衡?概率上的独立?正规化?合奏?梯度下降?在下面分享你的想法吧!

你可能感兴趣的来源:
-https://arxiv.org/pdf/1702.07800.pdf
-https://www . frontiersin . org/articles/10.3389/fevo . 2020.00082/full
-https://link.springer.com/article/10.1007/BF02478259
-https://archive.org/details/in.ernet.dli.2015.226341

Sergio e . betan court《走向数据科学》的编辑助理

去吧,改变我的想法

代理作为人工智能公平辩论中缺失的成分。

由文森特·万霍克——4 分钟阅读

用 5 个步骤训练你的思维进行递归思考

如何轻松解决递归问题

萨拉·a·梅特沃利(Sara a . Metwalli)——6 分钟阅读

向任何人解释版本控制的简单故事

让我们一起盖房子吧…用 git。

由朱莉娅·迪鲁索 — 6 分钟阅读

AlphaZero 和人工智能之美

自我学习人工智能如何重新定义我们的创造力概念

由曼努埃尔·布伦纳 — 11 分钟读完

如何在面试中解释每个机器学习模型

从回归到支持向量机再到 XGBoost 的模型综述

特伦斯·申 — 6 分钟阅读

聪明是什么感觉?

探索人类意识的深处

由 Aki Ranin — 25 分钟阅读

意识,自由意志&人工智能

为自由意志辩护,它是如何与意识紧密相连的,以及为什么它对人工智能至关重要

由米格尔·平托——12 分钟阅读

PyTorch + SHAP =可解释的卷积神经网络

学习如何用 PyTorch 和 SHAP 解释卷积神经网络的预测

达里奥·拉德契奇 — 4 分钟阅读

水晶般清晰的强化学习

强化学习的综合简明概念

By 白加延塔罗伊 — 31 分钟阅读

新播客

我们也感谢最近加入我们的所有伟大的新作家立花雄一郎利恩·特兰斯蒂芬妮·a .济托·雷洛娃尼科洛·卢切西拉克什米·阿贾伊法鲁克·坎卡亚维奥莱塔·梅泽克列娃胡安·安德烈斯·马拉 卡梅隆·特罗特陈·卡尼劳拉·戈里埃里普拉蒂克·卡马斯约翰·比卡詹妮弗·布兰德奥斯卡·达利亚斯·普拉斯西亚纪尧姆·波特弗兰基·坎西诺施特莱彻·劳亚历山大·彼得罗夫努里亚·科雷亚·马尼亚斯托梅尔·罗嫩瓦西里·丑石艾蒂安·迪洛克布鲁斯·阮塔尔·巴拉姆斯文·哈里斯蒂姆·卢博士【特 我们邀请你看看他们的简介,看看他们的工作。

使用凸优化框架的利润最大化

原文:https://towardsdatascience.com/margin-maximization-using-a-convex-optimization-framework-69824c4c1084?source=collection_archive---------40-----------------------

不需要计算能力的封闭方法

老实说,我是优化的忠实粉丝,每当我看到强大的优化器支持的新深度学习算法的出现,我的信念就变得更加坚定。但在这篇博客中,我不会触及任何随机优化过程,而是将重点放在简单而优雅的凸优化解决方案,可以在任何利润最大化问题中利用。这种方法的一个优点是其封闭形式的性质,不需要任何计算能力来解决甚至是大规模的问题。无论规模如何,您只需要一个计算器就可以在一分钟内实现这个解决方案。此外,该方法是领域不可知的,可以应用于大范围的优化问题。记住这一点,让我们开始吧。

问题陈述

假设我们想向客户发送关于个性化报价的信息。现在,我们可以根据我们的预算向每个人发送 n 次随机消息。但是,我们也希望收到基于我们发送的消息的最大响应。为了简单起见,我们不会在业务问题的复杂性上花费太多时间,而是开始简单地描述问题。

让我们假设我们有 k 个特征,这些特征通过这样的交流影响了客户产生的收入。如果我们开发一个乘法模型来捕捉响应曲线,它将如下所示:

这里 comm 是捕获历史发送的通信数量的特征, b(comm) 表示该特征的系数。

现在保证金可以定义为:

这里 c 是指每次通信的固定成本。

现在,如果我们试图计算发送给客户的最佳通信数量,以最大化利润,我们可以简单地进行一阶导数,得到以下结果:

现在,我们将得出最佳通信数量,如下所示:

这里的 comm*是发送给客户的最佳通信总数,以实现利润最大化。问题的第一部分到此结束。现在,我们必须计算要向单个客户发送多少信息。因此,如果我们总共有 N 个客户,并且每个客户都由 i 索引,那么在这种情况下最大化利润将如下所示:

我们需要解决上面的优化问题。现在如果我们能证明目标函数是凸的,这将使我们的工作更容易。可以证明,如果,

目标函数将是凸的。让我们努力实现上述问题的封闭形式的解决方案。

对于带有等式约束的凸函数,我们可以应用拉格朗日乘子来求解最优化问题。让我们写出拉格朗日函数:

为了解决这个问题,我们将采取如下方法。

如果我们求解上述方程,我们将得到以下结果:

闭合形态看起来有多美。事实上,它与一些直觉产生了共鸣。本质上是其他驱动因素对有个客户的的收入的贡献与所有客户相比的比例。事实上,您可以使用上面的公式在简单的 excel 中计算最佳通信计数(当然,您需要在优化之前首先估计响应曲线的参数)。

如果你看看到目前为止的公式,这里唯一重要的部分是确保我们的响应函数的凸性。公式的其余部分与业务问题的领域或上下文无关。现在不考虑任何领域,如果我们可以将利润最大化问题转化为上述形式的凸优化,我们将能够在任何用例中利用它的力量。

在我的下一篇文章中,我们将推广这种方法,并设计一种算法来解决大量的优化问题。

大麻消费:一个数据故事

原文:https://towardsdatascience.com/marijuana-consumption-a-data-story-6ea73317027f?source=collection_archive---------30-----------------------

丹佛市的药房活动:总体趋势和季节性分析

糖蜂Unsplash 上拍摄的照片

注: 这是关于丹佛酒类商店和药房指标的系列文章中的第二篇。第一篇文章涵盖了丹佛酒类数据的总体、月度和季度分析,并得出结论,丹佛的酒类商店在夏季和春季更受欢迎。

人类总是深入研究醉酒作为现代生活负担下的一种娱乐方式。自从酒精被发现以来,它就被当作一种休息和放松的工具,人类已经将饮酒作为一种社会联系的形式。在历史上,将大麻用于娱乐经常被看不起,但这种趋势现在正朝着对这种物质更积极的观点转变。2012 年,这两种主要的娱乐物质在丹佛市开始发挥作用,因为这一年大麻在科罗拉多州合法化。随着两种大型娱乐性药物在该市的出现以及自大麻合法化以来一百多家药房的兴起,分析丹佛市这些药物的消费趋势似乎是合乎逻辑的。这篇文章是一系列文章中的第二篇,旨在分析丹佛的酒和大麻流行情况,并且只涉及丹佛药房,对于丹佛酒类商店数据的趋势分析,请查看本系列的第一篇文章。

在我们的分析中,我们将使用 Safegraph 模式数据以及来自丹佛市的数据。SafeGraph 是一家数据提供商,为数百家企业和类别提供 POI 数据。它向学术界免费提供数据。在这个特定的项目中,来自模式数据集的关于访问和流行度指标的数据将证明对我们的分析非常有帮助。模式数据的模式可以在这里找到:模式信息

与烈酒数据一样,第一步是加载和可视化 SafeGraph 模式和丹佛药房数据

丹佛的药房数据是这样的:

让我们分析许可证类型的价值计数,看看在美国哪些地点可以合法销售大麻:

print(dispo_df[‘License Type’].value_counts())plt.bar(dispo_df[‘License Type’].unique(), dispo_df[‘License Type’].value_counts())

出于本文的目的,我们将只查看零售大麻商店类型的许可证。下一个片段将作为地址列的格式和扩展,以便在连接两个数据集时更好地满足我们的需求:

dispo_df = dispo_df.where(dispo_df[‘License Type’] == ‘Retail Marijuana Store’).dropna()dispo_df[‘index’] = range(1, len(dispo_df) + 1)dispo_df[‘Facility Street Number’] = dispo_df[‘Facility Street Number’].astype(int)dispo_df[‘Address’] = dispo_df[[‘Facility Street Number’, ‘Facility Street Name’,’Facility Street Type’]].apply(lambda x: ‘ ‘.join(x.dropna().astype(str)),axis=1)dispo_df.head(5)

以下是安全图模式数据的外观:

因此,现在我们有两个独立的数据集,一个来自官方城市丹佛,包含位置坐标和酒类许可证类型等信息,另一个来自 SafeGraph,包含关于访问和受欢迎程度的信息。问题是,我们如何连接这两个数据集。答案可以在 Placekey 生成的概念中找到。

Placekey 通过为所有感兴趣的点生成唯一的标识符并将生成的值用作连接列,解决了地址匹配概念带来的许多问题。创建地点键的过程非常简单,在这里可以找到这个过程的详细步骤。

patterns_18_m_path = ‘/content/drive/MyDrive/UpWork/safeGraph/Data Projects/Project1/Patterns Data M/year sep/patterns_2018_m.csv’patterns18_m_df = pd.read_csv(patterns_18_m_path)#{‘city’, ‘iso_country_code’, ‘query_id’, ‘location_name’, ‘longitude’, ‘postal_code’, ‘region’, ‘latitude’, ‘street_address’}def get_df_for_api(df, column_map = {“index”: “query_id”, “Entity Name” : “location_name”,”Address” : “street_address”,“Facility City”: “city”, “region”: “region”, “Facility Zip Code”: “postal_code”}): df_for_api = df.rename(columns=column_map) cols = list(column_map.values()) df_for_api = df_for_api[cols] df_for_api[‘iso_country_code’] = ‘US’ return(df_for_api)dispo_df[‘index’] = dispo_df[‘index’].astype(str)dispo_df[‘region’] = ‘CO’df_for_api = get_df_for_api(dispo_df)df_for_api[‘postal_code’] = df_for_api[‘postal_code’].astype(int).astype(str)df_for_api

data_jsoned = json.loads(df_for_api.to_json(orient=”records”))print(“number of records: “, len(data_jsoned))print(“example record:”)data_jsoned[0]

responses = pk_api.lookup_placekeys(data_jsoned, verbose=True)df_placekeys = pd.read_json(json.dumps(responses), dtype={‘query_id’:str})df_placekeys.head()

这个代码片段获取这些生成的 Placekeys 并将它们连接到丹佛药房数据:

def merge_and_format(loc_df, placekeys_df):   
    lr_placekey = pd.merge(loc_df, placekeys_df, left_on=”index”,
    right_on=”query_id”, how=’left’)    lr_placekey =
    lr_placekey.drop(‘error’, axis=1)
    lr_placekey[‘address_placekey’] = df_placekeys.placekey.str[:3]+
    df_placekeys.placekey.str[-12:]    
    lr_placekey = lr_placekey[[‘placekey’,‘address_placekey’]
    +list(loc_df.columns)]   
    return(lr_placekey)
loc_placekey=merge_and_format(liquor_df,df_placekeys)def merge_with_patterns(patterns_df, loc_res_placekey):
    patterns_df[‘address_placekey’] patterns_df.placekey.str[:3]+patterns_df.placekey.str[-12:]
    df = loc_res_placekey.merge(patterns_df.drop(‘placekey’,  axis=1), how=’inner’,on=’address_placekey’)
    df = df.reset_index().drop(‘index’,axis=1)
    return(df)df = merge_with_patterns(patterns18_df, loc_placekey)cols = list(df.columns)cols.pop(cols.index(‘address_placekey’))df = df[[‘address_placekey’] + cols]print(df.shape)liquor_GS_df = df

现在我们已经有了格式化的数据,我们可以开始分析它了。

丹佛药房:植物 2 的成功

当查看药房数据的总体平均受欢迎程度和访问量时,我们看到以下趋势:

在这两种情况下,2018 年最受欢迎的药房记录对应于 Canosa Properties and Investments LLC,但如果你并排查看这些指标的箱线图,你会发现一个有趣的变化。

访问者指标没有将该记录的值显示为异常值,这与我们在之前的白酒分析中看到的数据有着奇怪的区别。在酒类分析过程中,如果一个记录是访问者指标的异常值,它也是流行指标的异常值。这是一个有趣的变化,我们可以继续寻找这个潜在的趋势,现在,让我们看看这个特定药房成功背后的原因。

当在谷歌上对商标名 BOTANICO 2 进行快速搜索时,我们看到评级非常好,在 Weedmaps 上为 3.9,在 Leafly 上为 4.7。这可能是一个证据,说明这家药房做得这么好的原因是它提供了这么好的服务和高质量的产品。

这个特定药房的评级与同一邮政编码的其他药房的评级相比如何?

我们可以看到,在这个邮政编码有两个药房,只有 Botanico 有连续良好的受欢迎程度评分,另一个药房的评级不是很好,其他药房的低质量可以归因于 Botanico 2 的成功。

这种特定药房受欢迎的背后是否还有其他原因,比如它周围的当地商店?让我们检查一下与这些记录相关的本地品牌:

由此我们可以看出,没有品牌与药房的知名度相关联。这种相关性可能归因于大量与药房相关的食品品牌和杂货店,但这不会得到数据的很好支持,因为与酒店和五金店等位置的相关性高于与食品和杂货店的相关性。

让我们分析药房数据的每月数据,看看这是否有助于找到 BOTANICO 2 受欢迎的原因

丹佛药房数据的月度分析:寒冷的月份与药房更受欢迎相关吗

与之前的月度趋势分析一样,这里的代码块将比较 2018 年每个月的受欢迎程度和访问指标。在本节中,该代码将不包括在内,因为它重复了每月的白酒分析。要自己研究代码和处理数据,请不要犹豫,去看看笔记本

一月:

二月:

三月:

四月:

五月:

6 月:

七月:

八月:

九月:

十月:

十一月:

十二月:

月度分析显示了一个有趣的模式。似乎随着天气越来越冷,2018 年丹佛的药房的受欢迎程度和访问指标都在增加。这当然与酒精消费量的见解形成了鲜明的对比——随着天气变暖,这些指标也会增加。这也与我个人的预期有点矛盾,四月份是这些药房受欢迎的月份。似乎就像节假日酒类销售增长对数据整体结果的最小影响一样,4 月 20 日的大麻销售对该月整体消费的影响非常小,因此 4 月份在该列表中的排名不是很高。现在让我们用季节分析来证实我们关于药房受欢迎程度的理论。

药房数据:季节性分析

这个代码片段将以前每月分析的数据汇编到一个表中,并添加了季节性信息:

Season_Df = pd.DataFrame(data = {‘Monthly_avg_visits’: [2.645161,1.571429,2.258065,2.5,1.741935,1.633333,1.419355,1.354839,2.166667,2.612903,2.466667,2.516129],’Monthly_avg_pop’: [13.958333,6.125,8.291667,8.291667,6.541667,7.125,5.5,4.958333,7.125,8.541667,7.458333,9.333333],‘Season’: [‘Winter’,’Winter’,’Spring’,’Spring’,’Spring’,’Summer’,’Summer’,’Summer’,’Fall’,’Fall’,’Fall’,’Winter’]})Season_Df.head()

这些数据提供了以下图表:

从这些图中,我们首先可以看到访问者和受欢迎程度指标之间的相关性是线性的,这一发现也与线性数据相同。仔细观察,我们可以发现冬季和秋季比其他月份更受欢迎。这与之前的酒类数据形成鲜明对比,之前的数据显示,在较温暖的月份,酒类商店的人气有所上升。让我们将同样的分析应用于整个数据集,而不仅仅是月平均值,看看趋势是否成立

从这些趋势我们可以看出,当使用完整的数据时,受欢迎程度和访问之间的相关性仍然存在。此外,我们可以再次看到,显示最受欢迎的季节是冬季和秋季,从而支持我们的假设。

结论:

就来访者而言,按季节划分,诊所接待来访者最多的月份是 1 月、10 月、11 月、12 月和 3 月。这令人惊讶,因为随着 4 月 20 日的到来,大麻消费成为一个受欢迎的日子,4 月份成为最受欢迎的月份更有意义。但就像酒类数据一样,一个月中某一天产品受欢迎并不能抵消整个月的平均总访问量。目前的趋势是,随着天气变冷,诊所就诊人数增加。

至于受欢迎程度,药房最受欢迎的月份是一月、十二月、十月、三月、四月和十一月。这似乎很有趣,因为它与就诊的季节性趋势相关——较冷的月份往往显示药房受欢迎的程度增加。目前的一个趋势是,4 月份的受欢迎程度大幅上升。这很有趣,因为访问和流行趋势之间的变化。这可能是因为 BOTANICO 2 药房通过在线销售实现了大部分销售。这可能是受欢迎程度增加但访问量没有增加背后的原因。

提问?

我邀请你在 SafeGraph 社区#safegraphdata 频道问他们,这是一个面向数据爱好者的免费 Slack 社区。获得支持、共享您的工作或与 GIS 社区中的其他人联系。通过 SafeGraph 社区,学者们可以免费访问美国、英国和加拿大 700 多万家企业的数据。

使用 Plotly Express 的 Marimekko 图表

原文:https://towardsdatascience.com/marimekko-charts-with-plotly-express-you-can-also-lie-with-charts-4ee98a30ed66?source=collection_archive---------31-----------------------

你也可以用图表撒谎

由 Unsplash 放大的图像

数据可视化

假设你参加了一个商业计划竞赛。你需要展示一个令人信服的商业案例,因为投资者会根据你的讲述做出决定。

你必须包括视觉上有趣的图形和图像。但是在这里我们可能会犯双重错误 : 1)观众会看到我们的数字并立即理解我们展示的想法;2)即使在专业环境中,观众也可以接收到一系列重要的复杂可视化,并以我们选择的方式掌握趋势、模式、相关性、比例、分布。

记住:数据可视化是一种交流工具。所以,我们必须经常问自己:我表达清楚了吗?我是否使用了一种不容置疑的数字?如果我们使用可变宽度条形图,这些问题尤其重要。

可变宽度条形图

有不同类型的可变宽度条形图,但有两种是最流行的:1)条形图;2) Marimekko 图(Marimekko 是芬兰的纺织品牌,有大而多样的形状图案,也有简单明亮的颜色和风格)。

它们在以下方面有所不同:一个条形图 (BMc)类似于一个“标准”条形图,但是它的条形宽度是可变的; Marimekko 图 (Mc)类似于 1 00%堆积条形图 t,但其条形宽度可变,它是一个条形宽度可变的标准化柱形图。

两个图表都用于显示数据集中每个类别的两个数值变量;目标是在类别之间进行比较,而不是在数字变量之间进行比较。它们广泛用于仪表板或营销、销售和业务演示中。

纵轴有一个数字刻度(在 Marimekko 图上为 100%),代表一个定量变量。横轴可以是数字,也可以是类别。如果是数字,每个矩形的宽度与第二个定量变量的值成比例,有不同的颜色,并有一个图例来标识它。如果是分类的,每个条形的宽度也表示第二个定量变量的值。

与标准条形图不同的是,在条形之间没有留出空间(注意不要将麦可图与直方图混淆)。)在 BMc 和 Mc 两者中,水平轴的整个宽度被占据

Mekko 条形图是传统条形图的替代产品,可让您减少商业演示中图表的数量。为了实现这一点,图表通过条形的高度对一个数字变量进行编码,通过条形的宽度对另一个数量变量进行编码。

Marimekko 图表簇状条形图(分组条形图)的替代物,允许减少其在商业展示中的数量:它们显示与主要类别内的子组或子类别相关的数字信息。

不要混淆 Mcs 和 spineplots 。根据其最严格的定义, spineplot 是一个一维的水平堆积条形图,用于显示列联表中两个交叉分类的分类变量的频率、比例或百分比。这种混乱是因为一些 spineplots 可视化工具允许垂直方向,他们称之为马赛克图。这个术语也被错误地归因于 Marimekko 图表,但应该保留给那些允许通过可变宽度矩形检查两个或更多分类变量之间关系的图表。

带有 Plotly Express 的 Marimekko 图表

总部位于加拿大蒙特利尔的计算公司 Plotly 开发了 plotly.py,这是一个用于 Python 的交互式开源可视化工具。2019 年,该公司发布了 Plotly 4.0,其中包括 Plotly Express ,这是一个与 Plotly 生态系统的其余部分完全兼容的高级包装器。

Plotly 提供了一组名为的图形对象的类,可以用来构造图形。 plotly.graph_objects 模块包含了 Python 类的层次结构。是初级类。有一个数据属性和一个布局属性。数据属性有 40 多个对象,每个对象引用一个特定类型的图表( trace) 及其相应的参数。布局属性指定图形的整体属性(轴、标题、形状、图例等。).

我们使用了从 Kaggle 下载的数据集。该数据集包含从 VzCharts 收集的与视频游戏销售和游戏评级数据相关的记录。我们特别选取了三个 csv 文件:1)索尼[1]关于 Playstation 4 平台上视频游戏销售的 1031 条记录;2) 422 条关于微软 Xbox One 主机【2】上视频游戏销售的记录;3) 11563 条关于来自不同发行商【3】的视频游戏 销售的记录。我们想知道不同平台的销售额在全球几个地区的分布情况。

首先,我们导入 Plotly Express 为 px,模块 plotly.graph_objectsgo ,库 Numpy & Pandas 分别为 nppd

import plotly.graph_objects as goimport plotly.express as pximport numpy  as npimport pandas as pd

然后,我们使用 read_csv 函数将逗号分隔值( csv )文件读入它们对应的数据帧。

df1 = pd.read_csv(path + 'XboxOne_GameSales2.csv', 
                  index_col =False, header = 0, 
                  sep = ';',   engine='python')df2 = pd.read_csv(path + 'PS4_GamesSales2.csv', 
                  index_col = False, header = 0,
                  sep = ';', engine='python')df3 = pd.read_csv(path + 'Video_Games_Sales.csv', 
                  index_col = False, header = 0,
                  sep = ';', engine='python')

下面的截图显示了名为 df1 的数据集的前十条记录(对应 XboxOne):

名为 df2 的数据集具有与 df1 相同的列数和名称,但是df3(Video _ Games _ Sales)具有非常不同的布局:

对于我们的计算,我们只需要存储四个感兴趣地区(北美、欧洲、日本和世界其他地区)销售额的列。在 df1df2 中,我们简单地选择相应的四列,但是 df3 r 需要预处理来均衡数据。预处理任务只包括选择 Nintendo sales 并重命名四个选定的列:

df1 = df1[['North America', 'Europe', 'Japan', 'Rest of World']]df2 = df2[['North America', 'Europe', 'Japan', 'Rest of World']]df3 = df3.drop(df3[(df3.Publisher != 'Nintendo')].index)df3 = df3[['NA_Sales', 'EU_Sales', 'JP_Sales', 'Other_Sales']]df3 = df3.rename(columns={'NA_Sales': 'North America', 
                          'EU_Sales': 'Europe',
                          'JP_Sales': 'Japan',
                          'Other_Sales' :'Rest of World'})

然后,我们将函数 sum() 应用于三个数据帧。记住函数 sum() 返回所请求的轴的值的总和。

同样,df3 需要预处理,因为在应用函数 sum() 之前,我们必须使用 pd.to_numeric,errors = ' compete '将存储为 object 的列数据转换为数字。选项错误= '强制'将非数值转换为 NaN

最后,我们将这三个文件连接起来,并在一个名为 df4 的新数据帧中计算各自的百分比。

sum_1 = df1.sum(axis = 0, skipna = True)sum_2 = df2.sum(axis = 0, skipna = True)df3 = df3.apply(pd.to_numeric, errors='coerce')sum_3 = df3.sum(axis = 0, skipna = True)list_df = [sum_1, sum_2, sum_3]df4 = pd.concat(list_df , axis = 1).reset_index()df4.columns = ['region', 'xbox', 'ps4', 'nint']df4['perc_xbox'] = (df4['xbox'] / ( df4['xbox'] + df4['ps4'] + 
                    df4['nint'])) * 100df4['perc_ps4']  = (df4['ps4']  / ( df4['xbox'] + df4['ps4'] + 
                    df4['nint'])) * 100df4['perc_nint'] = (df4['nint'] / ( df4['xbox'] + df4['ps4'] + 
                    df4['nint'])) * 100

为了绘制一个可变宽度条形图,我们使用一个名为 data 的字典进行堆栈排序,使用另一个名为 colors 的字典进行条形颜色排序,并使用一个系列(width和一个变量( width_x )来指定水平轴上条形的宽度:

data = {"Nintendo": df4['perc_nint'],
        "Xbox"    : df4['perc_xbox'],
        "PS4"     : df4['perc_ps4']
        }colors= {"Nintendo": 'blue',
         "Xbox"    : 'green',
         "PS4"     : 'darkred'
        }widths  = sum_3
x_width = sum_3.sum()

plotly.graph_objects 的概念思路是使用。 add_trace(去。(bar())创建图然后添加等方法。更新 _ 布局(),。update_xaxes,。更新 _yaxes 来操作图形。最后,我们用导出图形。write_image()渲染。显示()。

注意 add_trace(go。Bar()) 根据我们在名为 data 的字典中决定的顺序,位于 for 循环内部。

我们用 update.layout 更新了图表:设置标题文本、标题字体和图例字体,并设置图形尺寸(宽度和高度)。 barmode = 'stack' 确定条堆叠在另一条的顶部

然后我们更新了 x 轴和 y 轴(文本、字体、tickfont)。将 y 轴范围设置在 0 到 100%之间,将 x 轴范围设置在 0 到 x_width 之间。

fig = go.Figure()
for key in data:
fig.add_trace(go.Bar(name = key,
                     y = data[key],
                     x = np.cumsum(widths) - widths,
                     width = widths, offset = 0,
                     marker = {'color' : colors[key]},
                     customdata = data[key],
                     texttemplate = "%{y:.2f}",
                     textposition = "inside",
                     textangle = 0,textfont_color = "white",
                     textfont_size = 30))fig.update_layout(title_text ="Sales of Consoles per Region",
                  barmode = "stack",
                  title_font_size  = 40,legend_font_size = 30,
                  width = 1400, height = 1400)fig.update_xaxes(title_text=
                 'Width of each bar=Sales of Nintendo in MM',
                 range = [0, x_width],  
                 title_font_size = 30,                   
                 tickvals = np.cumsum(widths)-widths/2,
                 ticktext =["%s<br>%d"% l, w)for l,w 
                            in zip(labels, widths)],
                 tickfont = dict(family='Calibri', 
                                color='black', size=25))fig.update_yaxes(title_text = 'Percentage (%)',
                 range = [0,100],
                 title_font=dict(size=35,
                                 family='Verdana', color='darkred'))fig.write_image(path + "figmarimekko1.png")fig.show()

图 1:作者用 Plotly Express 制作的 Marimekko 图。

图 1 在一张图表中描述了任天堂视频游戏在不同地区的累计销售额,以及不同游戏机对应的百分比。可以看到 Marimekko 图的特征要素:一个矩形区域被分成宽度不同的小矩形;垂直堆叠的矩形;占据图表整个宽度的水平轴;带有百分比刻度的垂直轴;特定品牌(任天堂)的总销售额在较低的基线上;不同的条形宽度允许计算每个地区对总销售额的相对贡献。

但是堆叠顺序的选择完全是任意的。那么,如果我们改变顺序会发生什么呢?我们只需要对代码做一些简单的修改:

data = {"Xbox"    : df4['perc_xbox'],
        "PS4"     : df4['perc_ps4'],
        "Nintendo": df4['perc_nint']
        }
widths  = sum_1
x_width = sum_1.sum()

图 2:作者用 Plotly Express 制作的 Marimekko 图。

在图 2 中,不同宽度的矩形是由感兴趣地区的不同 XboxOne 销售情况给出的。虽然不同游戏机之间的销售百分比保持不变,但观众会收到非常不同的信息,尤其是在日本。

如果横轴按 PS4 控制台销售进行细分,情况也是如此:

data = {"PS4"     : df4['perc_ps4'],
        "Nintendo": df4['perc_nint'],
        "Xbox"    : df4['perc_xbox']
        }
widths  = sum_2
x_width = sum_2.sum()

图 3:作者用 Plotly Express 制作的 Marimekko 图。

这是 Marimekko 图表的主要缺点:它们不仅难以阅读和解释,因为它们是基于观众通过比较区域来解码数字信息的能力,而且它们还会误导观众得出错误的结论

正如 Alberto Cairo 明智地指出的那样4: “正如我们可以用统计数据撒谎一样,我们也可以用图表撒谎”

如果你对这篇文章感兴趣,请阅读我以前的(https://medium.com/@dar.wtz):

带有 Plotly Express、趋势线和分面的散点图

带有 Plotly Express、主题和模板的直方图

参考文献

【1】:https://www.kaggle.com/sidtwr/videogames-sales-dataset?select=PS4_GamesSales.csv

[2]:https://www.kaggle.com/sidtwr/videogames-sales-dataset?select = Xbox one _ gamesales . CSV

[3]:https://www.kaggle.com/sidtwr/videogames-sales-dataset?select = Video _ Games _ Sales _ as _ at _ 22 _ Dec _ 2016 . CSV

使用 Python 的 Matplotlib 制作 Marimekko 图表

原文:https://towardsdatascience.com/marimekko-charts-with-pythons-matplotlib-6b9784ae73a1?source=collection_archive---------12-----------------------

可视化分组和分段比例的好方法

Marimekko 图表—图片由作者提供

通常被称为马赛克图,脊柱图,或只是 Mekko。在其他应用程序中,该图表通常用作市场地图,以可视化按客户类型、地区和许多其他变量划分的行业。

本质上,它们只是一个堆叠的条形图,其中的条形宽度用于显示另一个变量,通常是整个组占总数的比例。

Marimekko 图表—图片由作者提供

比例对于发现模式和比较不同规模的群体非常有用。本文将探讨如何用 Matplotlib 中的 Marimekko 图表来改进我们可视化它们的方式。

为什么要使用 Marimekko 图表

我们将通过一个 Marimekko 图表的快速示例来说明它们的可用性,最后,我们将看到如何更系统地绘制它们。

首先,我们将导入我们将使用的库。

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

在我们公司,部门 A 的 30 人和部门 B 的 20 人希望继续远程工作。

y = np.array([.3, .4, .7, .8]) * np.array([100., 50., 100., 300.])
x_label = ['a','b','c', 'd']
plt.bar(x_label, y)
plt.show()

条形图—作者提供的图片

光是这些信息是没有帮助的,而且可能会产生误导,因为我们不知道每个部门有多少人在工作。分析比例会更有见地。

y = [.3, .4, .7, .8]
x_label = ['a','b','c', 'd']plt.bar(x_label, y) # bottom bar
plt.bar(x_label, np.ones(len(y))-y, bottom=y) # top barplt.ylim(0,1)
plt.yticks([0, 0.25, 0.5, 0.75, 1], ['0%', '25%', '50%', '75%', '100%'])plt.show()

百分比堆积条形图—图片由作者提供

但是,假设我们也想把所有部门想象成一个整体。上面的图表可能也会误导我们。我们可以说这是一个整体“分裂”的意见;一半部门在 50%以上,另一半在 50%以下,这是不对的。

为了从整体上了解各个部门,我们需要多种可视化或不同的方法,如树状图和 Marimekko 图表

fig, ax = plt.subplots(1)
y = [.3, .4, .7, .8]
x = [100, 50, 100, 300]
x_label = ['a','b','c', 'd']
width = [i/sum(x) for i in x]# calculate x coordinates based on the width of the previous bars
# same as: [0, width[0], width[0] + width[1], width[0] + width[1] + width[2]]
adjusted_x, temp = [0], 0
for i in width[:-1]:
    temp += i
    adjusted_x.append(temp)# Marimekko chart
plt.bar(adjusted_x, y, width=width, align='edge', edgecolor='black')
plt.bar(adjusted_x, np.ones(len(y))-y, bottom=y, width=width, align='edge', edgecolor='black')# x and y ticks (%)
ax.set_yticks([0, 0.25, 0.5, 0.75, 1])
ax.set_yticklabels(['0%', '25%', '50%', '75%', '100%'])
ax.set_xticks([0, 0.25, 0.5, 0.75, 1])
ax.set_xticklabels(['0%', '25%', '50%', '75%', '100%'])plt.ylim(0,1)
plt.xlim(0,1)# twin y-axis to draw x-ticks at the top
axy = ax.twiny()
axy.set_xticks([(width[i]/2)+ v for i, v in enumerate(adjusted_x)])
axy.set_xticklabels(x_label, fontsize=14)plt.show()

Mekko 图表—图片由作者提供

这种可视化帮助我们毫不费力地将部门内的比例以及每个部门占总数的比例可视化。

我们可以清楚地看到,我们公司的绝大多数人都希望继续远程工作,但我们仍然注意到,较小的部门似乎不太热衷于这一想法。

数据集

现在,为了更系统地使用 Marimekko 图表,让我们尝试使用 Pandas 数据框。这样,我们可以更容易地在列、行和数据集之间切换。

我将使用的数据集来自世界银行公开数据。我想将一些指标的比例形象化,如农村人口用电识字率。但我也想说明这些国家占总人口的比例。

人口数据框-图片由作者提供

世界银行数据集可能包含一些区域、次区域、社会经济群体等行,但我们希望将国家与其他国家进行比较。我们需要一些国家的列表来清理我们的数据框架,例如所有国家拉丁美洲&加勒比海欧盟等等。

我们还需要考虑,我们不会给每个国家贴标签;那就太杂乱了,所以我们还需要选择一些国家来突出显示。

由于这些内容广泛,我将在这里 留下这部分代码 的链接。

现在,让我们创建一些字典,以便更容易地与所有这些列表和值进行交互。

var_dict = {'Rural Population':
             {'file':'API_SP.RUR.TOTL.ZS_DS2_en_csv_v2_2166125.csv',
              'label':'Rural Pop. (%)',
              'legend':['Rural Population', 'Urban Population'],
              'min_year':1960,
              'max_year':2019}, 

            'Access to Electricity':
             {'file':'API_EG.ELC.ACCS.ZS_DS2_en_csv_v2_2164123.csv',
              'label':'Access to Electricity (%)',
              'legend':['Access to Electricity', 
                        'No Access to Electricity'],
              'min_year':1990,
              'max_year':2018},

            'Literacy':
             {'file':'API_SE.ADT.LITR.ZS_DS2_en_csv_v2_2163525.csv',
              'label':'Literacy Rate (age +15)',
              'legend':['Literate Pop.', 'Illiterate Pop.'],
              'min_year':1970,
              'max_year':2018},

            'Unemployment':
             {'file':'API_SL.UEM.TOTL.ZS_DS2_en_csv_v2_2163385.csv',
              'label':'Unemployment (ILO Estimate)',
              'legend':['Unemployed', 'Employed'],
              'min_year':1991,
              'max_year':2019}}countries_dict = {"All":all_countries,
                  "European Union": eu, 
                  "Latin America & Caribbean": la_c,
                  "East Asia and Pacific": eap,
                  "Europe and Central Asia": eca,
                  "Middle East and North Africa": mena,
                  "North America": na,
                  "South Asia" : sa,
                  "Sub-Saharan Africa": ssa,
                  "Custom":False}highlights_dict = {"All":highlight_all,
                  "European Union": highlight_eu, 
                  "Latin America & Caribbean": highlight_la_c,
                  "East Asia and Pacific": [],
                  "Europe and Central Asia":[],
                  "Middle East and North Africa":[],
                  "North America":[],
                  "South Asia" : [],
                  "Sub-Saharan Africa":[],
                  "Custom":[]}

我们已经做好了一切准备,可以更有效地与数据集进行交互。现在让我们设置变量并开始清理。

year = 2018
countries_select = "All"
indicator = 'Rural Population'
countries = countries_dict[countries_select]
highlight = highlights_dict[countries_select]

无论我们绘制什么指标,人口数据框架都是一样的。尽管如此,指标数据框架将取决于我们从以前的代码中选择,在这种情况下,农村人口。

pop_file = 'API_SP.POP.TOTL_DS2_en_csv_v2_2163507.csv'df = pd.read_csv('../data/'+pop_file)
var_df = pd.read_csv('../data/'+var_dict[indicator]['file'])df = df.merge(var_df, 
              left_on='Country Name', 
              right_on='Country Name', 
              suffixes=['_pop', '_var_df'])

合并的数据框-作者提供的图片

合并后的数据框将为人口和变量指标的每一年提供一列。

清洁

我们将删除不在列表中的国家,删除没有值的行,并按指标值对行进行排序。

# remove non-countries
df = df[df['Country Name'].isin(countries)]# remove rows with empty values for the indicator or population
df = df[(df['{}_var_df'.format(year)].notna() & df['{}_pop'.format(year)].notna())]# sort rows by the indicator values 
df.sort_values('{}_var_df'.format(year), inplace=True)

经过清理和排序的数据框-图片由作者提供

准备数据

接下来,我们需要定义 Y,这是每个国家的指标值。

条形的宽度就是人口数量。X 是宽度的累积和。

# get y
y = df['{}_var_df'.format(year)]/100# get the width of the bars (population / 1mi)
width = df['{}_pop'.format(year)].values / 1000000# calculate the x position of each country
# x is the cummulative sum of all previous widths
x = [0]
temp = 0
for i in width[:-1]:
    temp += i
    x.append(temp)

我们将定义的最后一个变量与 x 记号和国家标签相关。我们将使用高亮列表来绘制记号,获取国家的 X 和一半宽度来定位标签。

# create lists with the x ticks positions and labels
# based on a list of countries we want to highlight
xticks_pos = []
xticks_labels = [] 
for i, v in enumerate(df['Country Name']):
    if v in highlight:
        xticks_pos.append(width[i]/2 + x[i])
        xticks_labels.append(v)

厉害了,我们有 XY宽度x 刻度位置标签

绘制 Marimekko 图表

我们完成了函数的第一部分。现在我们可以开始绘制条形图,并使用变量来绘制 Marimekko 图。

默认情况下,Matplotlib 在 x 位置的中心对齐条形,我们需要它们在边缘。我们还需要给每个条形添加一个轮廓,这样我们就可以区分它们。

fig, ax = plt.subplots(1, figsize=(24,12))# plot proportions
plt.bar(x, y, 
        width=width, 
        align='edge', 
        edgecolor='w', 
        linewidth=0.5, 
        color='#559A65')# plot ones - proportions at the top
plt.bar(x, np.ones(len(y))-y, bottom=y, 
        width=width, 
        align='edge', 
        edgecolor='w', 
        linewidth = 0.5, 
        color='#477C91')

Marimekko 图表—图片由作者提供

接下来,我们需要修改 x 和 y 的限制来删除空白,并用一些适当的值替换 x 和 y 记号。

要在 x 轴上绘制百分比和标签,我们需要写第一个,设置一个双 y 轴,然后写另一个。

fig, ax = plt.subplots(1, figsize=(24,12))plt.bar(x, y, 
        width=width, 
        align='edge', 
        edgecolor='w', 
        linewidth=0.5, 
        color='#559A65')plt.bar(x, np.ones(len(y))-y, bottom=y, 
        width=width, 
        align='edge', 
        edgecolor='w', 
        linewidth = 0.5, 
        color='#477C91')# xy limits
plt.xlim(0, x[-1]+width[-1])
plt.ylim(0,1)# xy ticks
plt.xticks(xticks_pos, xticks_labels, fontsize=14)
plt.yticks(np.arange(0,1.1,0.25), 
          ['{:.0f}%'.format(i*100) for i in np.arange(0,1.1,0.25)],
          fontsize=14)# twin y-axis to draw x-ticks at the top
axy = ax.twiny()# max value on the x axis
max_x = (x[-1] + width[-1])# get the values for 0%, 25%, 50%, 75%, and 100%
x_ticks_percent = np.arange(0, max_x+1, max_x/4)# set ticks and labels
axy.set_xticks(x_ticks_percent)
axy.set_xticklabels(['{:.0f}%'.format(i*100) for i in x_ticks_percent/max_x],fontsize=14)plt.show()

Marimekko 图表—图片由作者提供

就是这样。我们需要添加一个图例,标题,一些注释,并在一个函数中获得所有这些代码,以方便地切换指标和国家。

def marimekko(countries_select, indicator, 
              year, countries, highlight): ##################
    ###### DATA ######
    ##################
    pop_file = 'API_SP.POP.TOTL_DS2_en_csv_v2_2163507.csv'
    df = pd.read_csv('../data/'+pop_file)
    var_df = pd.read_csv('../data/'+var_dict[indicator]['file'])
    df = df.merge(var_df, 
                  left_on='Country Name', 
                  right_on='Country Name', 
                  suffixes=['_pop', '_var_df'])

    # remove non-countries
    df = df[df['Country Name'].isin(countries)] # remove rows with empty values for the indicator or population
    df = df[(df['{}_var_df'.format(year)].notna() & df['{}_pop'.format(year)].notna())] # sort rows by the indicator values 
    df.sort_values('{}_var_df'.format(year), inplace=True) # get y
    y = df['{}_var_df'.format(year)]/100 # get the width of the bars (population / 1mi)
    width = df['{}_pop'.format(year)].values / 1000000 # calculate the x position of each country
    # x is the cummulative sum of all previous widths
    x = [0]
    temp = 0
    for i in width[:-1]:
        temp += i
        x.append(temp) # create lists with the x ticks positions and labels
    # based on a list of countries we want to highlight
    xticks_pos = []
    xticks_labels = [] 
    for i, v in enumerate(df['Country Name']):
        if v in highlight:
            xticks_pos.append(width[i]/2 + x[i])
            xticks_labels.append(v)

    ##########################
    ########## PLOT ##########
    ##########################
    # define figure and axis
    fig, ax = plt.subplots(1, figsize=(24,12)) # bars
    plt.bar(x, y, align='edge', 
            width=width, edgecolor='w', 
            linewidth = 0.5, color='#559A65')
    plt.bar(x, np.ones(len(y))-y, bottom=y, 
            align='edge', width=width, edgecolor='w', 
            linewidth = 0.5, color='#477C91')

    # Add notes (Total population and Year)
    total_pop = df['{}_pop'.format(year)].sum()
    if total_pop > 1000000000:
        total_pop = '{:.2f} bi'.format(total_pop/1000000000)
    elif total_pop > 1000000:
        total_pop = '{:.2f} mi'.format(total_pop/1000000)
    else:
        total_pop = '{:.2f}'.format(total_pop) notes = 'Total population: {} | Year: {}'.format(total_pop,
                                                     year)
    plt.text(x[-1], 1.07, notes, ha='right', fontsize=20) # title and legend
    plt.legend(var_dict[indicator]['legend'], 
               ncol=2, loc='upper left', fontsize=20,
               frameon=False, bbox_to_anchor=(0,1.11))
    plt.title('{} by Country\n\n'.format(var_dict[indicator]['label']), 
              loc='left', fontsize=24)

    # xy limits
    plt.xlim(0, x[-1]+width[-1])
    plt.ylim(0,1) # xy ticks
    plt.xticks(xticks_pos, xticks_labels, fontsize=14)
    plt.yticks(np.arange(0,1.1,0.25), 
              ['{:.0f}%'.format(i*100) for i in np.arange(0,1.1,0.25)],
              fontsize=14)
    # twin y-axis to draw x-ticks at the top
    axy = ax.twiny()
    # max value on the x axis
    max_x = (x[-1] + width[-1])
    # get the values for 0%, 25%, 50%, 75%, and 100%
    x_ticks_percent = np.arange(0, max_x+1, max_x/4)
    # set ticks and labels
    axy.set_xticks(x_ticks_percent)
    axy.set_xticklabels(['{:.0f}%'.format(i*100) for i in x_ticks_percent/max_x], 
                        fontsize=14) plt.savefig('chart.png')

太棒了,让我们试试我们的新功能。

year = 2018
countries_select = "All"
indicator = 'Rural Population'
countries = countries_dict[countries_select]
highlight = highlights_dict[countries_select]marimekko(countries_select, indicator, year, countries, highlight)

Marimekko 图表—图片由作者提供

year = 2000
countries_select = "European Union"
indicator = 'Unemployment'
countries = countries_dict[countries_select]
highlight = ['Belgium', 'Czech Republic', 'France', 'Germany', 
             'Italy', 'Poland', 'Portugal', 'Spain', 'Sweden']marimekko(countries_select, indicator, year, countries, highlight)

Marimekko 图表—图片由作者提供

太好了!我们有一个很好的可视化工具,可以让我们检查国家的比例和整体的比例。所有这些都在一个函数中,因此我们可以轻松地在不同的指标和国家组之间切换。

现在就看你的了。您可以改进设计,增加交互性,或者在笔记本或脚本中使用它。

用 Python 生成并用 Pixlr 编辑的元素—图片由作者提供

Streamlit 打造的数据探索 app 图片由作者提供

上述例子的代码可以在这里找到。

更多 Python DataViz 教程

感谢阅读我的文章。希望对你有帮助!

降价:从描述性到规定性

原文:https://towardsdatascience.com/markdowns-from-descriptive-to-prescriptive-ec729c4cce82?source=collection_archive---------10-----------------------

商业科学

3 种分析方法来回收价值和防止浪费

降价和浪费。照片由约翰·卡梅隆Unsplash 拍摄

描述性的、预测性的和规范性的:这三种方法你可以用分析来解决任何商业问题。例如降价。

降价幅度很大:如何处理过剩的库存?

我最近的文章中的一些统计数据:仅在美国就有超过 2 万亿的库存——20,400 亿美元——每销售 1 美元就有 1.43 美元的库存。那么,当这 43%的过剩库存达到报废时,该如何处理呢?

当一个产品用尽了销售的可能性,降低它的价格是一个合理的方法,试图清理剩余库存:残值,防止浪费。

降价有 3 种主要方法,展示了三种主要的分析策略:描述性、预测性和规范性。在进入细节之前,先了解一下背景。

背景:产品金字塔

像任何以产品为中心的分析问题一样,降价需要浏览复杂的产品层级,并在每个层级使用适当的方法。

产品金字塔的一个例子可能如下所示,以名为 Event Network 的公司为例,该公司是北美体验式零售的领先运营商:遍布美国和加拿大的标志性文化景点和生活方式场所的商店,例如博物馆、动物园、水族馆。

产品金字塔。图片来源: Evo 定价 (CC 带归属)

产品金字塔的不同层次需要不同的预测方法。

例如,在最底层的是特定产品,或称库存单位(简而言之,SKU):一件印有黄色三藩市图案的 S 码绿色 t 恤。我知道,这是一个奇怪的调色板,也许去另一个 SKU?蓝色印花的中号灰色连帽衫。好了,你明白了。

在这种粒度级别,销售相对较少,因此有必要进行详细的预测。沿着产品金字塔向上,汇总销售更频繁,因此可以应用汇总预测方法。

最后,所有的方法必须匹配,这样各部分的总和与总数相符,例如预测总和必须与预测总和相匹配。

请参见以下视觉摘要以供参考:

降价临近。图片来源: Evo 定价 (CC 带归属)

降价的三种方法

在浏览产品金字塔的复杂性时,您可以使用三种方法来设置最佳降价,使用不同数量和类型的数据:

  • 描述性:仅使用历史数据
  • 预测:使用价格弹性数据
  • 规定性:使用尽可能多的数据。

每种方法都需要不同数量的数据、业务流程,当然还有分析策略。

降价过程取决于方法。图片来源: Evo 定价 (CC 带归属)

描述性方法的构建和维护相对简单,它只需要很少的数据。毫不奇怪,这种方法只允许自上而下的推荐,因此效率相对较低,下面我会进一步说明。

另一方面,规范的方法相对更难构建和维护,并且需要更大的数据集。然而,这种方法允许做出完全自下而上的建议,并且可以提供显著的财务收益。

描述性方法介于两者之间,我将在后面介绍。

所以让我先从基线方法开始:描述性的!

方法 1:描述性降价

第一种也是最直接的方法是选择降价的产品,它依赖于一个简单的经验法则:

库存比销售额多的折扣产品。

直觉是用覆盖率,或 天的库存 ,作为问题大小的代理。计算步骤:

  1. 某产品的历史销量:比如一个月 100 件
  2. 现有库存:比如 1000 件
  3. 覆盖率比率,例如,在本例中为 10 个月:1,000/100 →如果销售继续保持历史平均水平,则需要 10 个月才能将当前库存销售一空
  4. 每件产品花费的降价预算=额外%折扣 X 库存单位成本 X 现有库存件数。阅读下面的例子。
  5. SKU 排名:从最高覆盖率往下。

在这一点上,挑选前 N 个产品,直到所有可用的降价预算都花完!

一种产品降价预算的简单示例:

  • 打八折;现在要打五折,所以额外打三折
  • 10 美元的单位库存成本
  • 1 万件现有库存

→花费的 30k 美元降价预算= 30% x 10k 美元。

明白这是怎么回事了吗?

按降序排列 SKU,您可以轻松挑选:根据降价百分比和可用预算,您可以轻松确定降价的 SKU(覆盖率最高的那些)。

描述性降价。图片来源: Evo 定价 (CC 带归属)

优势:

  • 简单的笔和纸的方法,可以做 100%在一个电子表格,如微软 Excel
  • 让首席财务官的生活变得轻松,因为对花费的预算有 100%的把握,事实上这是他们一开始的决定!
  • 植根于任何人都容易理解的关于库存和销售的简单客观事实。

缺点:

  • 完全无视结果:无法保证影响、销售加速或投资回报,因为产品可能对价格不敏感
  • 不清楚如何验证预算水平的选择,因为没有迹象表明对多少产品(或多大程度)进行折扣是合适的
  • 最终,推动决策的原型是经理驱动的,而不是客户驱动的(拉动)。

简而言之,100%推送决策,Excel 友好。描述性降价没有错,但也没那么好。让他们成为我们的基准模型。

第一个,几乎是显而易见的,尚未回答的问题是:产品对价格有多敏感?当我把它们标下来的时候,我能期待什么样的加速度?

输入预测降价中使用的价格弹性概念。

方法 2:预测性降价

价格的变化,比如降价,会对销售产生什么样的预期影响?

常规答案是使用价格弹性:相关的 Wikipedia 文章对此解释得相对较好,因此我不会在此重复所有内容。

卡罗教授和加林在 2010 年写了一篇优秀的免费可得的科学论文,详细介绍了快时尚零售商 Zara 使用回归技术进行弹性降价的方法。

价格弹性高的折扣产品。

什么是价格弹性?长话短说,从价格的某个%的变化中,我能期望销售额有什么%的变化?例如,如果我的“价格弹性”是-2,那么-10%的价格变化(负号:这是折扣/降价)预计将产生+20%的销售量增长(-10% X -2 = +20%)。诸如此类。

为了计算这个系数,一种传统的方法是在适当的粒度级别上对历史价格运行历史销售量的回归。例如:按类别按商店按周。

弹性计算示例。图片来源: Evo 定价 (CC 带归属)

基于弹性,你现在可以通过应用任何降价百分比或价格变化来计算预期回报。

好处?例如,如果价格降低 10%,弹性系数为-2,你的销售量就会增加 20%。因此,如果我们以每件 10 美元的价格销售 100 件产品,收入为 1,000 美元,那么现在你将以每件 9 美元的价格销售 120 件产品(+20%)(-10%)。因此,您的新收入将为 1,080 美元,正收益+8%。

遍历弹性为-2 的所有可能组合的数学:

预测降价,弹性= -2 的例子。图片来源: Evo 定价 (CC 带归属)

这张图表简单地展示了如何根据预期影响选择最佳降价

  • 如果你想要最大的收益,那么-35%的降价是最佳选择
  • 如果你想要最大的利润,那么-15%的降价是最理想的
  • 如果你想两者兼得,那么降价 15%到 35%是最佳选择,这取决于收入和利润目标的相对重要性。

这种方法的问题是,虽然系数的 t 值相当好(价格确实影响销售),但模型的 R 平方并不太好。

当销售量很高时,所得到的价格弹性收敛到 0:量价关系的一维回归非常嘈杂。

弹性计算。图片来源: Evo 定价 (CC 带归属)

因此,与描述性模型相比,这种方法既有一些优点,也有一些明显的缺点。

优点:

  • 相对简单的方法,至少它的简单版本可以在像 Microsoft Excel 这样的电子表格中部分完成
  • 根据历史价格弹性,就降价投资的预算水平和预期影响提供指导
  • 植根于需求的价格敏感性数据,这增加了以客户为中心的流程的数量。

缺点:

  • 预测能力差:这些方法的 R 平方相对较差,因此该模型不完全符合目的
  • 预测仅在中间聚集级别可行,如商店/类别,因为项目级别的弹性通常无法确定
  • 有限的输入信号,因为价格不是影响销售的唯一因素,并且产品价格具有相互关联的影响,例如由于同类相食。

简而言之,50–50%的推动决策,对 Excel 有些友好。比描述性降价好得多,但在指导决策的能力方面仍然有限。

此时,下一个需要回答的问题是:如何考虑更复杂的输入信号?如何建立一个具有更大影响潜力的系统?

输入机器学习和说明性降价。

方法 3:指令性降价

由于价格不是影响销售的唯一因素,基于价格弹性的传统预测模型无法通过准确性测试。

向问题扔更多的数据怎么样?规定方法需要使用更先进的技术,如机器学习和自动化优化

在合适的时间给合适的产品打折。

当添加数据集时,回归和时间序列等传统方法在最初的几个数据集上表现出初步的性能提升,但当添加更多数据集时,它们会遇到共线性和噪声等问题,使它们越来越不适合使用。

R 的平方来自降价中的数据使用。图片来源: Evo 定价 (CC 带归属)

具体来说,在多达 7 个变量的情况下,回归模型的表现优于机器学习。

当数据的数量和种类增加时,机器学习胜过回归,实现更大的粒度和准确性。

附加输入数据集的增量贡献。图片来源: Evo 定价 (CC 带归属)

在降价方面,使用机器学习方法时的%预测误差,以及因此更大的数据集,明显更低。

规定降价的误差。图片来源: Evo 定价 (CC 带归属)

与总是简单的描述性方法的基线模型相比,这反过来释放了显著的财务收益。

规定降价的影响。图片来源: Evo 定价 (CC 带归属)

因此,与其他两种方法相比,这种方法提供了最多的优点,但也有一些缺点。

优点:

  • 更好的性能:更大的经济效益、准确性、输入信号的广度
  • 自学系统降低运营风险,在市场偏离预期时自动调整未来建议
  • SKU/商店级别的推荐粒度,有机会根据需要集成自定义规则和人工输入。

缺点:

  • 相对复杂的设置:需要更多的数据和专业知识来使用更先进的技术
  • 需要非常大的数据资产,以便能够自学和快速响应市场情况
  • 最终,一个先进的模型,在跨其他过程的更广泛的能力的背景下有意义,而不仅仅是降价。

简而言之,一个 0%的推,纯拉的决定;一点都不 Excel 友好。比描述性和说明性降价都好得多,即使只适用于注重分析的组织。

通过数据以客户为中心

通过数据以客户为中心。图片来源: Evo 定价 (CC 带归属)

归根结底,任何数据都是关于客户的。无论是直接的,如客户年龄、性别等数据,还是间接的,如天气、竞争等数据。

数据将客户注入到日常管理决策中。

使用的数据越多,管理决策就越以客户为中心。规范方法利用机器学习,以尽可能最好的方式使用最多的数据。

总结:三种方法

现在,您已经看到了使用数据的三种不同方法:描述性的、预测性的、规范性的。

分析方法的演变。图片来源: Evo 定价和【neuraldesigner.com】T4(CC 带归属)

发展您的分析方法需要勤奋和良好的以客户为中心,但最终可能价值数百万美元的日常影响。

快乐大减价!

PS 更多商业科学来自我的写作:

</94-perfect-the-surprising-solution-to-the-200-billion-inventory-problem-b6ba0bc1417a>

Monthly Business Science in your inbox, new software, and University-level learning:[**Free access**](https://evouser.com/register)Questions? Please reach out on [Linkedin](https://www.linkedin.com/in/fabrizio-fantini/)

使用 PySpark 的购物篮分析

原文:https://towardsdatascience.com/market-basket-analysis-using-pysparks-fpgrowth-55c37ebd95c0?source=collection_archive---------5-----------------------

用 PySpark 的 FPGrowth 进行数据挖掘

由克莱姆·奥诺杰胡在 T2 拍摄

动机:

你想学习如何分析顾客购物篮中经常一起购买的商品吗?如果你愿意和 PySpark 的 FPGrowth 一起工作,就别再找了。

解决方案:

首先,让我们看看我们的数据框架(数据存储在我的 github 库)。如果你想使用谷歌的 Colab,你首先需要安装你的谷歌硬盘:

# To be able to use your data stored in your Google Drive you first need to mount your Google Drive so you can load and save files to it.from google.colab import drive
drive.mount('/content/gdrive')#You'll need to put in a token which Google will generate for you as soon as you click on the link.

输入令牌后,您的 Google Drive 就安装好了。

现在,我们将数据加载到我们的数据框架中,并查看:

import pandas as pd
import numpy as np
data = pd.read_excel(‘/content/gdrive/MyDrive/DDDDFolder/DDDD.xlsx’) 
data.head()

这就是我们的数据帧最初的样子。

因此,我们得到的是每个销售日的销售额、客户(例如,客户代码 0 是一个特定的客户)、销售项目(类似于客户,销售项目 0 是一个特定的销售项目)和销售交易 ID。

我们将分析与每个销售交易 id 的销售项目相关的市场篮。其他列对我们的数据挖掘不感兴趣。

要在 Colab 中安装 PySpark,我们必须使用我们的超级用户权限:

%%capture!sudo apt-get update --fix-missing!apt-get install openjdk-8-jdk-headless -qq > /dev/null!wget -q https://archive.apache.org/dist/spark/spark-3.0.0/spark-3.0.0-bin-hadoop3.2.tgz#!wget -q https://downloads.apache.org/spark/spark-3.0.0/spark-3.0.0-bin-hadoop3.2.tgz!mv spark-3.0.0-bin-hadoop3.2.tgz sparkkk!tar xf sparkkk!pip install -q findspark

之后,我们可以开始我们的 Spark 会话:

import osos.environ["JAVA_HOME"] = "/usr/lib/jvm/java-8-openjdk-amd64"os.environ["SPARK_HOME"] = "/content/spark-3.0.0-bin-hadoop3.2"import findsparkfindspark.init()from pyspark.sql import SparkSessionspark = SparkSession.builder.master("local[*]").getOrCreate()spark = SparkSession \.builder \.appName('fpgrowth') \.getOrCreate()spark

当一切正常运行时,您会看到这条消息。

与熊猫不同,在 Spark 中创建数据帧,我们必须使用 Spark 的 CreateDataFrame:

from pyspark.sql import functions as F
from pyspark.ml.fpm import FPGrowth
import pandas
sparkdata = spark.createDataFrame(data)

对于我们的购物篮数据挖掘,我们必须将销售交易 ID 转换为行,因此每一行代表一个销售交易 ID,包括购买的销售项目。首先,我们确保每个销售事务 ID 对于其销售项目是唯一的(这就是为什么要删除重复项)。然后,我们按销售交易 ID 分组,并使用聚合函数的 collect_list 接收每个销售交易 ID(行)的所有销售项目:

basketdata = sparkdata.dropDuplicates(['SalesTransactionID', 'SalesItem']).sort('SalesTransactionID')basketdata = basketdata.groupBy("SalesTransactionID").agg(F.collect_list("SalesItem")).sort('SalesTransactionID')

结果现在看起来像这样,并且已经准备好供 FPGrowth 的算法使用:

现在,我们将计算市场篮子指标,如支持、提升和信心。请注意,MinSupport 等参数设置是非常具体的数据:

#Frequent Pattern Growth – FP Growth is a method of mining frequent itemsets using support, lift, and confidence.fpGrowth = FPGrowth(itemsCol="collect_list(SalesItem)", minSupport=0.006, minConfidence=0.006)model = fpGrowth.fit(basketdata)# Display frequent itemsets.model.freqItemsets.show()items = model.freqItemsets# Display generated association rules.model.associationRules.show()rules = model.associationRules# transform examines the input items against all the association rules and summarize the consequents as predictionmodel.transform(basketdata).show()transformed = model.transform(basketdata)

结果看起来就是这样。

这已经是我们的 FPGrowth 结果了。如果您想将其导出为 Excel 文件,您可以这样做:

# Convert the Spark DataFrame back to a Pandas DataFrame using Arrowresult_pdf = items.select("*").toPandas()
result_pdf.head()

result_pdf.to_excel('result_pdfItemsFreq.xlsx')

规则也类似:

rules_pdf = rules.select("*").toPandas()
rules_pdf.head()

rules_pdf.to_excel('rules_pdfAnteConseConfLift.xlsx')
transformed_pdf = transformed.select("*").toPandas()
transformed_pdf.head()

transformed_pdf.to_excel('transformed_pdfSalesTransactionIDCollectListPred.xlsx')

恭喜你,你已经成功地使用 FPGrowth 进行了数据挖掘技术!也许你已经发现了上一个截图中的列预测?这个“预测”为推荐系统搭建了一个非常好的桥梁。如果你有兴趣,请阅读我的相关文章。

非常感谢您的阅读!希望这篇文章对你有帮助。请随时在 LinkedInTwitter工作室与我联系。

https://jesko-rehberg.medium.com/membership

最初发表在我的网站 DAR-Analytics 。我的 Github 存储库中也有 Jupyter 笔记本和数据文件:https://Github . com/DAR-DatenanalyseRehberg/DDDD _ Data-Driven-deadlines-Development/blob/main/Market _ Basket _ DDDD . ipynb

由深度学习驱动的市场情报

原文:https://towardsdatascience.com/market-intelligence-powered-by-deep-learning-bb63dae49481?source=collection_archive---------72-----------------------

【tensorflow 能增加自由职业者赢得项目的几率吗?

克里斯托弗·高尔Unsplash 上拍摄的照片

根据最近的一份报告,美国有 5900 万自由职业者。自由职业者是全球性的,竞争非常激烈;人才供给高于工作需求。您可以在此财务业绩报告中了解更多关于不断变化的全球市场和 covid 影响的信息。

自由职业者面临多重挑战,其中两个挑战是:

  • 研究对他们技能/服务的需求
  • 寻找和赢得项目的难度

Freelancer.com 有一个优秀的 API,可以用来提取项目细节。它是一个丰富的数据集,有着令人尊敬的历史(超过 5 年);它既包含竞赛,也包含项目,虽然我只会涉及后者。

上述报告包含大量有用的信息(自由职业者简介、每个项目的平均出价、市场总量趋势等)。).在这篇文章中,我将尝试回答以下问题:一个项目被授予的概率能被准确地确定吗?

鉴于广泛的模式,我一直关注 2 个主要组件:

  • 项目详情
  • 用户详细信息

诚然,深度学习被视为解决当前许多问题的灵丹妙药,但围绕它有很多宣传。还有一种倾向(我也有这种倾向)是关注工具。在这篇文章中,我将重点关注深度学习可以增加的价值;具体来说,深度学习能否准确地帮助一个自由职业者只专注于那些将被授予的项目?最终,这不仅会节省自由职业者的时间,还会节省金钱,因为出价不是免费的;浪费在未中标项目上的投标将不予退还。

此时,您可能会问自己:在发布的所有项目中,有多少项目获得了奖励(我称之为项目奖励率)。根据我的计算(并在本分析的背景下考虑这一点),项目奖励率约为 30%。这看起来很有希望,但这个市场竞争非常激烈,因为每个项目平均有 45 个投标。因此,专注于将被授予的 30%的项目将节省时间和精力。当然,深度学习模型将为你提供一种可能性,这仍然是一种强大的洞察力。

所以我建立了一个 tensorflow 模型来预测一个项目是否会获奖。我只提取了 16 个工作/技能的项目和用户细节;一些例子:

  • 机器学习
  • 数据挖掘
  • 数据科学
  • 深度学习

以下是关于如何开发模型的一些高级步骤:

  • 提取和拆分数据
  • 使用 tensorflow keras 预处理归一化输入。例如,下面是货币的代码片段。在这种情况下,ds_train 是训练数据集
def get_category_encoding_layer(name, dataset, dtype, max_tokens=200): index = preprocessing.StringLookup(max_tokens=max_tokens) feature_ds = dataset.map(lambda x, y: x[name]) index.adapt(feature_ds) encoder = preprocessing.CategoryEncoding(output_mode=”binary”, max_tokens=max_tokens) feature_ds = feature_ds.map(index) encoder.adapt(feature_ds) return lambda feature: encoder(index(feature))currency_norm = get_category_encoding_layer(“currency”, ds_train, ‘string’, max_tokens=25)
  • 在模型中包括预处理。连接所有层和输入。我只有两个深层次的单位基于超参数调谐与keras-调谐器
currency_input = tf.keras.Input(shape=(None,), name=”currency”, dtype=’string’)currency_layer = currency_norm(currency_input)all_layers = tf.keras.layers.concatenate([ currency_layer, # rest of layers …])dense_layer_1 = tf.keras.layers.Dense(units=hp.Int(‘dense_layer_1’, min_value=2014, max_value=8048, step=64), name=”dense_layer_1", activation=’elu’)(all_layers )dense_layer_2 = tf.keras.layers.Dense(units=hp.Int(‘dense_layer_2’, min_value=1024, max_value=1024, step=32), name=”dense_layer_2", activation=’elu’)(dense_layer_1)award_pred = tf.keras.layers.Dense(1, name=”award”)(dense_layer_2)
  • 培训和测试
  • 将预测(概率)整合到图表中
app.layout = html.Div([dash_table.DataTable(columns=[{"name": i, "id": i} for i in df.columns],style_header={ 'backgroundColor': 'white','fontWeight': 'bold'},data=df.to_dict('records'),fixed_rows={'headers': True},filter_action="native",sort_action="native",sort_mode="multi",style_table={'height': '900px'},style_cell_conditional=[{'if': {'column_id': 'currency'}, 'width': '40px'},# rest of columns
]),html.Div(id='datatable-interactivity-container')])

除了上面详述的货币列,我还有以下变量作为输入(请注意,我包括数字、分类和文本):

  • 工作/技能类别(例如工程和科学)
  • 项目名称
  • 项目描述
  • 项目类型(每小时或固定)
  • 预算(最低和最高)
  • 平均出价
  • 投标计数
  • 雇主国家
  • 雇主历史/整体声誉
  • 雇主评论
  • 付款已验证
  • 存款已存入

以上是一小部分,自由职业者 API 提供了更多的细节。

训练数据集并不庞大(只有关闭状态的项目)。大约是 90K 记录。

我们通过为 1 个时期训练模型来回答这个问题:75%的准确度。

下面你有几个活跃的项目例子以及预测的概率。

如何提高模型 75%的准确率?几个领域:

  1. 添加所有项目(有 14M 个项目;我只用了 90K 左右)
  2. 添加更多变量(尤其是获奖者的详细信息)
  3. 调整模型架构

总而言之,这种模式的附加值可能是:

  • 自由职业者可以节省时间和金钱,因为他们可以专注于那些很有可能中标的项目
  • 启用平台公司(如自由职业者、upwork 等。)到:
  1. 确定并支持那些拥有高预算项目且中标概率较低的雇主

2.在高级会员计划中包含这些类型的见解

让我知道你的想法。

营销分析可视化— WordCloud

原文:https://towardsdatascience.com/marketing-analytics-visualization-wordcloud-c32bec445cae?source=collection_archive---------30-----------------------

PYTHON。数据可视化。分析。营销。

通过 Python 生成 WordCloud 可视化

作者图片

WordCloud 显示文本中使用最频繁的单词,其中文本的大小与其在文本中的使用频率成比例;字体越大,该单词在文档中出现的次数就越多。

因此,对于探索性的数据分析,WordCloud 可能会提供一些有趣的见解来跟进或调查

在这个练习中,让我们试试 Tripadvisor_Hotel_Review 数据集。这个可以从 Kaggle 下载或访问。

预赛

如果你还没有安装 WordCloud 软件包,你可以打开你的终端,输入:

pip install wordcloud

以下是我们的准备工作:

#Preliminaries
from wordcloud import WordCloud, STOPWORDS#For Data Manipulation
import pandas as pd#For cleaning the texts
import re#For the Mask
from PIL import Image
import numpy as np
import urllib
import requests#For Visualization
import matplotlib.pyplot as plt
%matplotlib inline

输入数据

df = pd.read_csv('data/tripadvisor_hotel_reviews.csv')
print(f'The row and column sizes, respectively of the table are {df.shape}')
df.head()

请注意,在本练习中,我们将只使用 review 列。

数据预处理

为了处理我们能产生的最好的词云,下面是我们在预处理阶段需要做的步骤:

  • 将所有文本组合成一个字符串
  • 将所有文本转为小写(不同大小写字母的计数不同)
  • 删除停用词

预处理—合并文本并转换为小写

这可以用一段简单的代码来完成:

text = df['Review'].str.cat(sep=', ').lower()

预处理—停用词

WordCloud 提供了一个不错的停用词列表,我们已经可以使用了。这包括经常使用的词,如“the”、“a”、“or”等,这些词可能会使我们的词云变得混乱

有一些方法可以发现比预期出现频率更高的潜在单词,我们可以随时将它们添加到我们的词云排除的停用词列表中。

虽然人们可以拆分文本并进行数值计算,但我选择先简单地生成 WordCloud,并简单地删除那些我们不想成为图像一部分的内容。

因为我已经看到了输出,所以我只想删除一个词:“n,t”。

# Adding to the list of stopwords
stopwords = list(set(STOPWORDS)) + ["n't"]

形象化

WordCloud 包的使用非常简单,参数也很简单。

wordcloud = WordCloud(width = 800, height = 800,
                background_color ='white',
                stopwords = stopwords,
                min_font_size = 10).generate(text)#After generating the WordCloud object, enter this to a plotting function# plot the WordCloud image                       
plt.figure(figsize = (8, 8), facecolor = None)
plt.imshow(wordcloud)
plt.axis("off")
plt.tight_layout(pad = 0)

plt.show()

作者图片

这就是我们的基本词云。

可视化—屏蔽

对于那些想通过添加一些遮罩来改善这一点的人,我们可以通过选择 PNG 图像来实现。我对酒店图标不太满意,所以让我们选择一架飞机,因为它也是一个与酒店和旅游业相关的图标。

在选择蒙版时,选择带有白色背景的 png 或 jpeg 图像。计算机将彩色背景视为独立的对象,因此它可能无法捕捉到我们想要的形状。

我们可以得到一个免费使用的面具或图标。现在,在遮罩功能中,图像的白色部分的值应该是“255”,而不是 0。值 255 与白色相关联是更常见的(而黑色是 1),但为了以防万一,人们应该查看“遮罩”对象以防万一。阵列中的数字代表像素的强度。

mask = np.array(Image.open(requests.get('[https://www.freeiconspng.com/uploads/airplane-icon-image-gallery-1.png'](https://www.freeiconspng.com/uploads/airplane-icon-image-gallery-1.png'), stream=True).raw))

让我们选择一架飞机作为我们的图标,因为酒店住宿通常与旅行联系在一起。

目测遮罩对象:

图片由作者提供;像素值数组

因为我们的蒙版似乎用 255 作为白色值,我想我们可以用这个。

关于遮罩的注意:不是所有的东西都工作良好,你需要检查遮罩是否产生了我们想要使用的容器的预期形状。这个问题对于 3D 比 2D 更普遍。

可视化-将 2D 和 3D 遮罩从 0 转换为 255 的功能

如果您选择的掩码是 2D,并且您想将 0 值转换为 255,您可以使用以下函数:

def transform_format(val):
    if val == 0:#000080
        return 255
    else:
        return val# Transform your mask into a new one that will work with the function:
transformed_mask = np.ndarray((mask.shape[0],mask.shape[1]), np.int32)for i in range(len(mask)):
    transformed_mask[i] = list(map(transform_format, mask[i])

对于 3D 遮罩:

# Transform your mask into a new one that will work with the function:
transformed_mask = np.ndarray((mask.shape[0],mask.shape[1]), np.int32)for i in range(len(mask)):
    for y in range(len(mask[i])):
        transformed_mask[i][y] = list(map(transform_format, mask[i][y]))

带遮罩的 WORDCLOUD

处理完掩码后,我们现在可以将它用作 WordCloud 函数的参数输入:

wordcloud = WordCloud(background_color ='white',
                mask=mask,   
                stopwords = stopwords,
                min_font_size = 10,
                width=mask.shape[1],
                height=mask.shape[0],
                contour_width=1, 
                contour_color='#000080').generate(text)plt.figure(figsize = (8, 8), facecolor = None)
plt.imshow(wordcloud)
plt.axis("off")
plt.tight_layout(pad = 0)

plt.show()

作者图片

理想情况下,我们选择的面具与我们视觉化的主题有关。另一个我们可以尝试的是星级面具,因为酒店是以星级的形式来评定的:

作者图片

单词云的颜色功能

单词云的一个有趣的输入是颜色函数。color function 参数接受一个函数,然后根据每个单词的特征输出一种特定的或不同的颜色(方案)。

去这个网站挑选你想要的颜色组合:https://hslpicker.com/

少数专业人士更喜欢使用单调的颜色,而不是绘图软件的默认配色方案。因此,我们可以编写一个函数来完成这个任务:

def one_color_func(word=None, font_size=None, position=None, orientation=None, font_path=None, random_state=None):
    h = 204 #0-360
    s = 100 #0-100
    l = random_state.randint(30, 70) #0-100 As we want to randomize it per color, let's randomize this

    return f"hsl({h},{s}%, {l}%)"

使用此函数作为输入:

wordcloud = WordCloud(background_color ='white',
                mask=mask,   
                stopwords = stopwords,
                min_font_size = 10,
                width=mask.shape[1],
                height=mask.shape[0],
                color_func=color_func,
                contour_width=1, 
                contour_color='#000080').generate(text)plt.figure(figsize = (8, 8), facecolor = None)
    plt.imshow(wordcloud)
    plt.axis("off")
    plt.tight_layout(pad = 0)plt.show()

作者图片

用我们所知道的再玩一点,让我们尝试一个红色函数和一个心形的家用面具:

def red_color_func(word=None, font_size=None, position=None, orientation=None, font_path=None, random_state=None):
    h = 0 #0-360
    s = 100 #0-100
    l = random_state.randint(30, 70) #0-100 As we want to randomize it per color, let's randomize this

    return f"hsl({h},{s}%, {l}%)"

作者图片

结束语

WordCloud 是一个优秀的数据探索工具,用于查看文本对象中最常用的单词。因此,它们是营销分析和情感分析的绝佳工具。

作为一个 EDA 工具,人们应该尝试探索可能从生成的可视化中产生的问题和见解。

最后,有许多方法可以定制,并使观众的视觉效果更加强大。数据科学家应该始终努力使用可视化工具,同时兼顾细心和创造力。

让我知道你的想法!

参考

https://www . data camp . com/community/tutorials/word cloud-python

https://towards data science . com/create-word-cloud-into-any-shape-you-want-using-python-d0b 88834 BC 32

营销自动化:客户流失预测

原文:https://towardsdatascience.com/marketing-automation-customer-churn-prediction-6001cf91d8ae?source=collection_archive---------18-----------------------

防止客户流失的最好方法是预测他们是否会离开你。这些分析和预测技术可能有助于防止或尽量减少客户流失。

内森·杜姆劳Unsplash 上拍摄的照片

客户流失是企业需要追踪的最重要的数据点之一。客户流失分析有助于您识别客户旅程中人们流失的关键阶段,让您能够精确定位特定策略,以改善他们与您的品牌的互动,并提高品牌忠诚度。

什么是客户流失?

客户流失率是客户离开你公司的比率。这可能是由多种原因造成的,例如转向竞争对手,由于糟糕的客户服务而取消订阅,由于接触点太少而停止与某个品牌的所有联系,等等。客户流失分析非常重要,原因显而易见:客户流失意味着收入的直接损失。为了了解业务损失的数量,我们可以使用流失率指标。

什么是流失率,如何计算?

流失率是一项业务指标,计算在给定时间内离开产品的客户数量除以剩余客户总数。了解客户流失对企业的健康和粘性至关重要,但实际计算它可能会不必要的复杂。

流失率公式的计算方法是,流失率除以客户总数:

客户流失数量/客户总数

其中,流失客户的数量是指在这段时间内,你拥有的客户总数中有多少人离开了你的服务。

如何定义流失?

正如您在这里看到的,我们可能会遇到一个问题,即如何定义客户。

对于有订阅的企业来说,这非常容易—我们只需要那些没有续订订阅的客户,我们可以将这些客户定义为流失客户。当然,可能会出现这样的情况,一些客户在结束后没有立即续订,或者由于使用的具体情况而在一段时间后续订,但一般来说这是很清楚的。

如何定义零售中的流失?对我来说,有点难。我们不能将客户定义为“不良者”,因为他们停止购买我们的产品已经有一段时间了。他们可能会因为不同的原因停止购买:

  • 季节性的
  • 产品的使用时间

对于这种情况,我们可以像前面的情况一样使用一些业务规则。例如,我们可以使用频率指标(客户购买/使用我们产品的频率,以天/周/月为单位)。那么,怎么用呢?

首先,我们需要计算某段时间内的频率度量,而不是交易量。这很简单,公式如下:

  1. 选择测量频率的时间长度。
  2. 用事件发生的次数除以时间长度。

下一步,我们需要定义业务规则——必须跳过多少“频率”,我们才能将客户定义为流失。

例如:

顾客 A 每周购买一次我们的产品。我们定义,如果跳过 2 个频率,客户就会被搅动。在我们的例子中,这意味着,如果我们的客户 A 连续两周没有购买,我们会将其定义为流失客户。

这个方法很简单,但他只是陈述了客户流失的情况。

不幸的是,原创迷因需要许可证(图片由作者提供)

我们可以计算一下我们的损失,然后试着退回一部分。这种策略比留住客户的成本更高。客户保留是指公司将客户转化为回头客并防止他们流失的能力。

以下是我们从数据中获得的信息示例(参见之前的分析):

基于规则的客户流失分析(图片由作者提供)

我们也可以计算平均货币损失。要做到这一点,我只需将平均购买量乘以他们必须购买的时间。

规则库收入损失(作者图片)

要使用这种策略,我们需要定义有流失风险的客户,在这种情况下,我们需要预测未来一段时间的流失概率。这样的策略让我们有时间对有风险的客户采取一些行动,以防止他们流失。

数据科学的时代到了。

第一种方法,我想称之为买到死

购买到死(BTYD)类统计模型旨在捕捉非合同客户的行为特征,或者当公司无法直接观察到客户何时不再是某个品牌的客户时。目标通常是对客户流失和客户终身价值进行建模和预测。

BTYD 模型共同模拟两个过程:

  1. 重复购买过程,解释了客户在“活着”时购买的频率;
  2. 流失过程,模拟客户在任何给定时间段内流失的可能性。

BTYD 模型的常见版本包括:

在我的实验中,我将使用 lifetime 的包。

我将训练 BG/NBD 模型来估计给定时间段内的预期销售额,例如未来半年(180 天)。

未来 6 个月的预期购买数量(图片由作者提供)

因此,我们可以看到未来 6 个月预期销售额的下降趋势。我们来分析一下每个时间段的存活(流失)概率。

活着的概率(图片由作者提供)

同样的情况——我们的客户存活的可能性在下降。这个指标在动态分析中非常有用,因为在两个时间段之后,我们可以找到这个指标下降的地方,并开始采取一些措施来保持客户端。

比如我们拿两个客户来做这样的分析。

两个不同客户的存活概率(图片由作者提供)

橙色顾客存活的概率会略微下降,但蓝色顾客存活的概率会大幅下降。我们可以对 CRM 中的每个客户进行这样的分析,并配置一个触发器,在降幅巨大时向我们发出信号。

CRM 中的 Alam 示例(图片由作者提供)

更重要的是 CLTV。顾客终身价值是指顾客作为付费顾客的整个过程中会给你的品牌带来多少钱。一目了然,CLTV 告诉你一个客户对你的品牌有多大价值,并让你洞察他们的整体价值。从那以后,你会更好地理解你应该在留住客户上投资多少。

客户终身价值提示你是否可以期望某些客户成为回头客。如果他们的客户终身价值很高,他们很可能是你品牌的粉丝,会继续购买你的产品。如果没有,他们可能只是一个被动的客户,只购买了一次,需要付出额外的努力才能再次参与进来。

让我们分析一下 CLTV 分布。

CLTV 各时期的密度图(图片由作者提供)

我们可以看到,我们失去了 CLTV,这意味着我们失去了他们对我们品牌/商店的忠诚度。

我们可以为每个客户分析同样的事情:

客户的 CLTV 分析(图片由作者提供)

正如你所看到的,BTYD 算法非常好,它可以提供基于新近性、频率和货币的广泛的客户分析,但这也是这种方法的弱点。

让我们使用一些机器学习算法来预测未来 6 个月的客户流失。在这个实验中,我将使用 sci-kit-learn 中的 XGBoost。

因此,我可以分析变量的重要性,这将有助于我确定为什么客户想要离开。

我有在客户细分期间准备的所有数据,这将是我的特征,1- P(活跃)将是我的标签。以下是我在模型训练期间使用数据以避免数据泄漏的策略。

用于训练的数据(图片由作者提供)

同样,让我们检查我们的特征和目标之间的相关性。我将展示直接和间接相关的 10 大特征。

间接相关(图片由作者提供)

这些特征告诉我们,这些特征越大,我们流失的可能性就越小。这只是线性依赖,但有时很有趣。

例如,在这张图表上,你可以看到顾客在每个男包上花费的金额越大,流失的可能性就越小。

让我们分析同样的,但直接相关。

直接相关(图片由作者提供)

最有趣的是,在我们的案例中,只有一些城市与客户流失有直接关联。

好了,让我们建立模型并分析特征的重要性。

我将训练 XGBoost 回归模型来预测下一期的流失概率。这将是一个非常简单的模型,只显示功能和最有趣的特性的重要性。

XGBoost 功能重要性(图片由作者提供)

通常,重要性提供了一个分数,该分数指示每个特征在模型内的增强决策树的构造中有多有用或有价值。在决策树中,一个属性被用来做关键决策的次数越多,它的相对重要性就越高。

一个更有趣的方法是用 SHAP 值计算重要性。

在 Xgboost 中计算特性重要性的方法是使用 SHAP 包。它与模型无关,并使用博弈论中的 Shapley 值来估计每个特征对预测的贡献。

对模型输出幅度的平均影响(图片由作者提供)

这将获取整个数据集的 SHAP 值的平均值,并将其绘制为一个简单的条形图。

让我们继续,让 SHAP 总结剧情。

SHAP 摘要图(图片由作者提供)

我们没有使用典型的要素重要性条形图,而是使用每个要素的 SHAP 值的密度散点图来确定每个要素对验证数据集中个体的模型输出的影响程度。要素按所有样本的 SHAP 量值总和排序。有趣的是,关系特征比资本收益特征具有更大的总体模型影响,但是对于那些资本收益很重要的样本来说,它比年龄具有更大的影响。换句话说,资本收益对少数预测的影响很大,而年龄对所有预测的影响较小。

请注意,当散点不在一条线上时,它们会堆积起来以显示密度,每个点的颜色代表该个体的特征值。

此外,我想绘制 SHAP 瀑布。

SHAP 瀑布(作者图片)

瀑布图旨在直观地显示每个特征的 SHAP 值(证据)如何将模型输出从背景数据分布下的先前预期移动到给定所有特征证据的最终模型预测。当模型中的要素数量超过 max_display 参数时,要素按其 SHAP 值的大小排序,最小大小的要素组合在一起,位于图的底部。

好的,正如你所看到的,我的模型非常简单,所以很少有关于特征重要性的见解。为了使这种分析更有趣,我们需要一个更复杂的模型和更广泛的特性。

结论

因此,正如你所看到的,这些方法是一个强大的工具,可以帮助你预测客户流失,并且解释为什么你的客户流失。

识别对提供的解决方案不满意的客户的能力使企业能够了解产品或定价计划的弱点、运营问题以及客户的偏好和期望,从而主动减少客户流失的原因。

最后,再一次说明客户流失的重要性:

首先,一个被激怒的顾客很可能是一个不快乐的顾客。除了损失他们的消费,你还可能受到负面口碑、差评的影响,从而损害你的整体品牌价值。仅仅因为这个原因,就有必要联系那些处于危险中的客户,尝试修复关系。

其次,人们常说,保持现有客户比获得新客户成本更低,价值更高。关于这一点的统计数据和数字各不相同,有些人认为客户终身价值比获得或保留等单一成本维度更重要,但无论从哪个角度看,维持现有关系通常比放弃并从头开始更有意义。

你能在 Git 仓库中找到的所有代码— 链接

营销自动化——客户细分

原文:https://towardsdatascience.com/marketing-automation-customer-segmentation-5924b45556b5?source=collection_archive---------14-----------------------

你了解你的顾客吗?客户分析变得至关重要。这些见解推动了企业的销售、营销和产品开发工作,研究表明,使用客户分析的公司利润更高。

阿列克斯·多罗霍维奇在 Unsplash 上的照片

顾客可以随时随地获得信息,包括去哪里购物、买什么、付多少钱等等。这使得利用预测分析和数据来预测客户在与品牌互动时的行为变得越来越重要。

客户分析的目标是创建一个单一的、准确的客户视图,以决定如何最好地获取和保留客户,识别高价值客户并主动与他们互动。对顾客的购买习惯和生活方式偏好了解得越多,预测行为就变得越准确,顾客的旅程就变得越好。如果没有大量准确的数据,从分析中得出的任何见解都可能非常不准确。

在本文中,我将展示如何创建客户分析仪表板,以及如何在现实生活中使用这些信息。对于这个实验,我将使用 Kaggle 数据集— 零售店案例研究数据集

首先,我们来做探索性的数据分析,把我们的数据从不同的垃圾中清理出来。

该数据集包含以下表—客户、交易和产品。事务表包含以下列:

交易表头

  • transaction_id —事务标识符;
  • 客户标识—客户标识符;
  • 交易日期—交易的日期;
  • prod_subcat_code —产品子类别标识符;
  • prod_cat_code —产品类别标识符;
  • 数量——产品数量;
  • 费率——产品价格;
  • 税费—本次采购的税费;
  • total _ amount—采购价值+税;
  • Store_type —进行购买的商店的类型;

交易表信息

我在事务表中有将近 23K 的记录没有空值。它是一个玩具数据集,但在现实生活中,我们必须在使用前仔细检查和清理。

客户表包含以下列:

客户表格标题

  • customer_Id —客户标识符;
  • DOB——客户生日;
  • 性别—客户性别;
  • city_code —客户在商店中注册的城市;

с客户表信息

customer 表有 5647 个不同的客户,看起来有些客户没有关于性别和城市代码的信息。如何处理这样的问题,我将在后面说明。

产品表包含以下列:

产品表格标题

  • prod_cat_code —产品类别标识符;
  • 产品类别名称;
  • prod_sub_cat_code —产品子类别标识符;
  • prod_subcat —产品子类别名称;

产品表信息

product 表有 23 个唯一的子类别,没有空值记录。

让我们加入我们的表,并对我们的事务表进行深入分析。我想检查以下信息—日期变化、交易表中有多少客户,以及他们购买了多少最受欢迎的产品。

完整数据集分析

下一个分析将是我们的数量、价格、税收和价值列,以分析一些汇总统计数据。

汇总统计数据

正如我所写的,这是玩具数据集,所以我们没有任何异常值,我们唯一拥有的是负值,但这意味着我们已经获得了有关з购买回报的信息,我们将在进一步的分析中使用。

我们开始做客户细分吧。第一个是 RFM 分析。对我来说,这是了解你的客户最简单快捷的方法之一。那么,什么是 RFM 分析呢?

作者的 RFM 形象

RFM 是一种用于分析客户价值的方法。它通常用于数据库营销和直接营销,在零售和专业服务行业受到特别关注。

RFM 代表三个维度:

  • 最近度 —顾客购买了多久?
  • 频率——他们多久购买一次?
  • 货币价值——他们花了多少钱?

这种技术还有其他变体:

RFD新近度、频率、持续时间是 RFM 分析的修改版本,可用于分析观众/读者/冲浪导向的商业产品的消费者行为。

RFE新近度、频率、参与度是 RFD 分析的一个更广泛的版本,其中参与度可以定义为包括访问持续时间、每次访问的页数或其他此类指标。

RFM-I近期、频率、货币价值—互动是 RFM 框架的一个版本,修改后用于说明与客户营销互动的近期和频率(例如,控制非常频繁的广告活动可能产生的威慑效应)。

RFMTC新近性、频率、货币价值、时间、流失率由 I-Cheng 等人(2009)提出的一个扩展的 RFM 模型。该模型利用概率论中的伯努利序列,并创建公式来计算客户在下一次促销或营销活动中购买的概率。该模型已由 Alexandros Ioannidis 在输血和 CDNOW 数据集等数据集上实现。

我们需要做的第一件事是计算一段时间内数据集中每个客户的三个值— 最近度、频率、货币。我想以过去 3 个周期的半年为基础进行计算。

下一步是根据客户的近期、频率和货币价值创建三个不同的组,这将有助于我们命名我们的客户群。RFM 分数是最近值、频率值和货币值的简单总和,这个总和是 10、9、8 等整数值的结果。该分数将表明 RFM 分数的价值,它将允许我们对业务产品或客户做出决策。这是一个非常重要的指标,因为未来的决策过程涉及到用户或客户。

在最后,我们有三个时间段的 RFM 分析。

作者的 RFM 分析

但是,你会问——它是如何使用的?首先,我们可以计算不同时期的一些全局,并对其进行动态分析。

RFM 得分分析

这很有趣,但让我们用我们的 RFM 分数命名值。

RFM 分数名称分析

这里我们可以看到,在过去的 1.5 年里,我们增加了顶级客户的数量。

让我们分别深入探讨 RFM 价值观,并对其进行动态分析。

新近动态分析

我们延长了购买间隔时间,这表明客户参与度有所下降。

频率动态分析

降低中低消费群体的平均购买数量。

货币动态分析

在这里,我们可以看到高收入群体的收入略有增加,中低收入群体的收入有所减少。

为了得出一些结论,我们需要知道的下一步是对每个客户端进行深入分析,这有助于我们了解组之间的流量。

RFM 等级流程图

在这里,我们可以看到在过去半年中从一个组迁移到另一个组的用户数量。

正如你所看到的,RFM 分析很容易实现,但是为我们分析它提供了大量的变量。我展示的那部分,只是 RFM 能告诉你的关于你的客户的一小部分。

我们接着做进一步的分析。下一步是队列分析。我想对 2011 年做这样的分析。这种分析仅仅基于日期值。定义群组是群组分析的第一步。让我们试着根据每个客户进行第一笔交易的月份(由于发票日期而收到发票号)来创建每月分组。为了建立适当的群组,下一步是计算每个客户交易的时间偏移。这将允许我们以适当的方式报告每个群组的指标。为了创建时间偏移,我将创建一个函数,将日期拆分为年、月、日列。这将有助于根据时间日期轻松进行计算。

留存率图表

客户保持率是一个非常强大的指标,可以用来了解有多少客户仍然“活着”(或活跃)。在此之前,留存率向我们显示了活跃客户占总客户的百分比。

行为分析和客户分析的另一个有用指标是计算客户在商店购买的产品的平均数量,并将其可视化在类似的群组表中,如上面的留存分析。

顾客购买产品的平均数量

正如你在玩具数据集中看到的,我们全年的顾客行为基本没有变化。

现在是时候利用数据科学算法的力量来构建客户群了。首先,在开始构建模型之前,我们需要对数据进行预处理。我将向您展示数据预处理步骤中使用的几个概念和其他注意事项。在构建和预处理管道之后,我将向您展示如何构建称为 K 均值聚类的流行机器学习算法,该算法将基于我们计算的 RFM 分数和我们稍后计算的其他因素。这将有助于我们根据用户的客户行为指标来明确和识别用户。

什么是 K-Means 聚类,为什么使用这种算法?

收敛k——意为

  • K-Means 是识别不同模式的最流行的无监督学习方法之一
  • K-Means 简单快速
  • 适用于大型数据集

在构建 K-Means 算法之前,有一些关键的假设:

  1. 所有变量必须对称分布,不应有偏差。
  2. 所有变量应该具有相同或几乎相同的平均值。
  3. 所有变量应该具有相同的方差水平。

好了,让我们创造一些额外的因素,使集群更丰富和有趣。Ler 从客户的社会人口统计信息开始。我有我想使用的关于生日、性别和城市的信息。对于出生日期,我将在最大交易日期计算用户的年龄、性别,以及我将使用 One Hot Encoding 技术转换的城市。因此,我得到了下面的客户表,我将把它加入到 2014 年 12 月 2 日进行的最后一次 RFM 分析中。

客户建议的表格

下一个功能将建立在类别和交易信息的基础上。这将是每个客户按类别购买的平均值。

类别/交易特征

这就是我想在这个实验中使用的所有功能,但是数量和多样性只取决于您的业务需求和工程师的幻想。

由于算法限制,需要时间来预处理所有这些数据。我们可以使用一些提示和技巧:

  • 我们有几种方法来消除数据的偏斜。第一个是对数变换。但是对数变换只适用于正值。
  • 另一种消除偏斜的方法是广泛使用的 Z 变换,它对数据中的混合(正负)值很有效。

此外,我将在工作中解释不同的方法。这里有足够的信息来深入研究这项工作。

进一步的数据探索任务是识别偏斜度。偏斜度是对称(或缺乏对称)的度量。如果数据集在中心点的左侧和右侧看起来相同,则数据集的分布是对称的。直方图是显示数据偏斜度的有效图形技术。

通常,有 3 种类型的偏斜度:

  1. 左偏数据
  2. 正态分布数据
  3. 右偏数据

我将使用 z 变换,因为我得到了一个负值,我想在我的分析中使用。

我们需要做的下一件事是确定集群的数量。如何识别集群的数量?在 KMeans 算法中,有几种方法可以确定聚类数:

  • 目测法——所谓的弯头法(或弯头标准等)。)
  • 这种定量方法叫做轮廓系数
  • 实验和想象

肘形图

我有太多的因素,所以为了使我的分析有意义,我需要建立许多集群。我想留下 20 个微团做进一步分析。

此外,我想向您展示如何计算基本指标来确定 Kmeans 算法的“适合度”。

属性的相对重要性

这样的图表可以帮助你分析属性的相对重要性。

此外,还有一个更有用的图表——蜘蛛图,它可以帮助我们分析聚类之间存在差异的因素

蜘蛛图

在这里,我们可以看到,这四个分类的最大区别在于客户在自己的分类中购买的商品类别。

这就是我想在这个分析中展示的全部,现在是下结论的时候了。

结论

因此,正如你所看到的,这些方法是一个强大的工具,可以帮助你更好地了解你的客户。

细分可以让企业更好地利用营销预算,获得相对于竞争对手的竞争优势,更重要的是,展示出对客户需求的更好了解。它还可以帮助:

  • 营销效率——将庞大的客户群分解成更易于管理的部分,从而更容易识别目标受众,并使用最相关的渠道向最相关的人发起营销活动。
  • 确定新的市场机会——在将客户分组的过程中,您可能会发现您已经确定了一个新的细分市场,这反过来可能会改变您的营销重点和策略。
  • 更好的品牌策略——一旦你确定了客户的关键激励因素,如设计、价格或实际需求,你就可以恰当地给你的产品打上品牌。
  • 改善分销策略—确定客户在哪里购物以及何时购物可以为产品分销策略提供信息,例如在特定的商店销售什么类型的产品。
  • 客户保留——通过细分,营销人员可以识别出需要额外关注的群体、流失迅速的群体以及潜在价值最高的客户。它还可以帮助创建有针对性的策略,吸引客户的注意力,并为您的品牌创造积极、高价值的体验。

所以,不要害怕,开始让你的营销策略更有效率和利润。

你能在 Git 仓库中找到的所有代码— 链接

衡量营销活动

原文:https://towardsdatascience.com/marketing-campaigns-ca7dd3cd72bf?source=collection_archive---------17-----------------------

衡量多渠道营销活动的效果

(https://www.istockphoto.com

介绍

几乎不言而喻的是,消费者的需求和欲望是当今创造新产品和新服务,并制定相应的计划来销售它们以获取利润的关键问题。客户关系管理是针对客户群量身定制的促销活动[1]。一种闭环营销系统和方法提供了在线和离线测量跨渠道的营销计划的投资回报的能力,包括印象、页面浏览量和响应水平。在这里,我们提供了一种机制,通过考虑多种活动的影响来衡量营销部门对销售渠道的贡献[2,3]。传统上,转化研究是营销人员评估广告效果的标准技术。本文将提供各种数据科学技术的路线图,这些技术用于了解营销活动的影响,并向在线订阅业务的利益相关者传达重要的、可操作的见解。

衡量营销活动的成功

整个数据科学学科的核心是将业务问题转化为可衡量结果的概念。数据专业人员最常被问到的一个问题是:

  • 这场运动成功了吗?

最大的挑战之一是使用哪些指标来衡量营销活动的成功,因为有太多的指标。作为一名数据科学家,您会发现自己会反复使用大量的指标。几项研究的数据表明,对于营销团队来说,营销活动的成功通常是通过转化率来衡量的。也就是说,在所有接触过你的营销活动的人中,有多少人购买了该产品?

根据业务的不同,这可能意味着有人购买或订阅了你的服务。除此之外,许多订阅业务也关心留存。一旦用户注册了订阅,他们在一个月、三个月或十二个月后仍然是订阅者吗?特别值得关注的是,他的衡量标准可能特别难以衡量,因为这需要耐心。在用户最初订阅 90 天后,我们才能知道 90 天的保留率。

汇率

转化率是我们向最终转化为我们产品的人推销的百分比。在本文中,我们将关注订阅服务,并从订阅的角度讨论转换。

保留率

保留率是指在一段时间后仍保持订阅的人数百分比,我们将重点关注 1 个月的保留率。

你可以在本文的 GitHub 库找到我写的实现模型和生成图形的笔记本。

按渠道划分的每日营销范围

营销活动的一个关键方面是确定每天有多少用户在查看营销资产。这对于理解我们过去一个月的营销工作有多有效至关重要。

从图中的数据来看,很明显,在这个月的上半个月,每天大约有 300 名用户逗留。然而,我们在月中看到一个巨大的峰值。对此的一个可能的解释是,营销人员发出了一封大型营销邮件,这封邮件送达了许多不是网站日常访问者的用户。在深入研究和计算指标之前,可以考虑这些波动。

每日兑换率

当您想要了解您的营销活动的表现时,有必要了解关键指标在整个营销活动中是如何变化的。您的关键指标可以帮助您发现活动期间可能发生的问题,例如结账系统中的一个错误,该错误导致活动结束时转化率下降。随着时间的推移,指标也可以显示趋势,如在周末或特定假日获得更多订户。

从表中可以明显看出,除了一月份的一天外,转换率相对稳定。

每日订户质量

通过查看每天的保留率,用户质量会随着时间的推移而变化。当根据用户的订阅时间来查看一段时间内的保留率时,我们实际上是在进行一种简单的群组分析,帮助我们评估每天带来的订户的质量。如果我们看到这一指标随着时间的推移而上升,这可能意味着我们正在更好地转化对我们的产品真正感兴趣的用户,或者我们正在改善用户订阅后的入职流程。

客户细分

有证据表明,除了高级指标之外,对客户进行细分也很重要。术语“细分”是指根据具体特征分解指标。例如,除了查看整体转换率之外,还可能需要查看不同年龄组的转换率。有可能某个活动的整体转化率很低,但对 55 岁及以上的用户非常有效。数据分析团队没有称这次活动为失败,而是学会了一种新的向老年人营销的方式。这些结果可用于开展一项活动,让 55 岁及以上的用户获得不同于其他人的营销技巧。

比较语言转换率

数据科学家必须向业务利益相关者清楚地传达结果。提出正确的问题是这一过程的基础。因此,数据科学需要从整体角度解决这个问题。例如,在我们的案例中,我们观察了不同的年龄组,它们与转化有关。接下来,我们可以跨语言进行比较,随后,这将使我们了解哪些语言相对于其他语言转换得更好。

图中突出的是德语和阿拉伯语使用者的转化率比英语和西班牙语使用者高得多。

日常语言偏好

当我们进行跨语言比较时,我们可以了解哪些语言相对于其他语言转换得更好。我们还注意到英语和西班牙语的转换率要低得多。这可能会引发对不同语言之间的转换率差异进行更深入调查的冲动。

从数字上看,有一个明显的趋势:最流行的语言是英语。

跨年龄组的营销渠道

一些营销利益相关者可能想知道他们的营销渠道是否平等地接触到所有用户,或者一些营销渠道是否服务于特定的年龄人口统计。在营销团队中,经常会收到需要快速分析和可视化的请求。你越善于将结果可视化,你就越有可能将你的发现有效地传达给你的利益相关者。

该图中的数据有意思的是,电子邮件没有到达年龄较大的群体,脸书也没有到达太多 18 岁以下的人。

各年龄组的转换率

您的营销利益相关者要求提供每个年龄组的每日转化率报告,他们需要尽快得到。他们希望你每月更新一次这份报告。这是一个利用你的功能的绝佳机会。这些函数不仅可以帮助您立即得到这份报告,还可以帮助您每个月刷新数据。

订阅渠道的保留率

我们已经计算了总订户和保留订户,我们可以回答哪个渠道的保留率最高的问题。在图中,您可以看到每个订阅渠道的保留率。

从这个图中,我们可以看到哪些渠道在驱动用户保持率最长。在电子邮件的情况下,可以观察到大的峰值,通常下降到 0。这很常见,因为电子邮件通常是批量发送的,导致用户在同一组有限的日子里订阅。当保留率为 0 时,这意味着这些天没有人订阅。

利益相关者报告

让我们利用我们对营销活动的了解,制作利益相关者可能不知道要问的报告,但很高兴你看了。house ads 团队已经开始担心他们在转换率中注意到的一些违规行为。利益相关者带着他们注意到的有关指标变化的担忧来找数据科学家是很常见的。其数据科学家的工作是确定这些变化是自然波动还是需要进一步调查。

房屋广告的转换率

之前的例子已经指出了房屋广告转化率的下降。有趣的是,问题是用户看到的广告不是他们喜欢的语言。我们评估了这个错误的影响。虽然人们不能忽视与活动中的错误相关的数据,但人们可以估计如果没有问题,转换可能会是什么样子。

一周中的趋势

指标波动的最常见原因之一可能是由于客户在一周的不同日子里的行为差异。例如,一些企业在工作日的表现一直比周末好。

这个数字在几个方面很能说明问题。首先,与您可以看到的另一个数字不同,如果用户在一周的晚些时候订阅,保留率会更低,但这种差异很小,可能表明了其他情况,例如在周末发送更多的电子邮件,从而转化了低意向用户。因此,工作日的波动是常见的,即使有一致的模式,也不一定值得警惕。然而,这可能意味着当你试图最大限度地向顾客推销时,要进行修改。

每日房屋广告转换

既然你已经确认了房屋广告转化率自 1 月 11 日以来已经下降。自然,它要求需要确定下降的潜在原因。作为一名支持营销团队的数据科学家,一个人必须时刻面对波动的指标。因此,确定波动是由于用户行为的预期变化(即一周中各天的差异)还是技术实施或营销策略中的更大问题至关重要。在这里,我们将首先检查用户是否比平日更有可能在周末转换,并确定这是否是改变房屋广告转换率的原因。

对该图的进一步观察显示,电子邮件转换率特别高,可能反映了跟踪误差,但房屋广告似乎在一周内保持稳定,周二略有峰值。这需要进一步调查。

按语言转换房屋广告

我们已经排除了一周中某一天用户看到我们的营销资产时的自然波动,因为它们会导致房屋广告转化率下降,随着时间的推移,按语言进行转化将是合理的。也许这种新的营销活动并不适用于不同的文化。理想情况下,营销团队在发起活动之前会考虑文化差异,但有时会出现错误,而确定原因是数据科学家的工作。通常,数据科学家是确定营销活动出了什么问题的第一道防线。他们的工作是创造性地思考,找出原因。

这些数字令人震惊的是,英语转换率在 11 日左右下降,而且似乎两周内没有其他语言的广告。这可能是进一步调查的一个候选。

确认房屋广告错误

这个过程的下一步是用户是否看到正确语言的广告。一种可能的方法是查看有多少百分比的用户没有收到正确语言的广告。

从图表中可以看出,到目前为止,房屋广告表现不佳的最大原因是因为所有的广告都是英文的,而不是每个用户的首选语言。

确定丢失用户的数量

我们发现房屋广告的转化率有所下降。问题似乎是用户看到的广告语言不是他们喜欢的语言。为了了解总体影响,我们可以将预期的转换数据集限制在错误发生的那几天。接下来,分别合计该期间的预期和实际订户数。最后,我们对我们预期的订阅者数量和我们收到的订阅者数量进行了比较,这为我们提供了由于语言错误而损失的订阅者数量的估计值。我们得出结论,32 名订户已经流失。这可能看起来不多,但对于小公司来说,这可能是至关重要的,尤其是在扩展到新市场时。

结论

营销活动测量的相关性得到了当前研究结果的支持,因为客户关系管理的一个重要方面是通过定制的促销活动瞄准客户群。虽然大多数贡献集中于选择有希望的目标客户,但只有少数作者提出了针对所选目标群体的具体差别优惠的问题。总之,我们关注这两个问题,并展示了如何衡量营销活动的有效性。衡量竞选成功的方法有很多。也就是说,有些指标你可能会发现反复使用。因此,如果不透过这些不同的镜头,我们就无法提供必要的背景来解释一些关键指标所显示的内容。每个活动分析会因其性质而异,并需要特定的方法,但这些基本原则如果应用,至少会提供一些严格性,以最小化结果中的偏差。

👋感谢阅读。如果你喜欢我的作品,别忘了喜欢,在 medium 上关注我。这将激励我为媒体社区提供更多的内容!😊

参考

[1] Reutterer 等人(2009)提出了一种针对和定制直接营销活动的动态细分方法。互动营销杂志第 20 卷,第 3-4 期,第 43-57 期

[2] Ascarza 等人(2018):追求增强的客户保持管理:回顾、关键问题和未来方向。斯普林格科学+商业媒体有限责任公司 2017。

[3] Cruz,d .和 Fill,C. (2008):评估病毒式营销:分离关键标准,《营销情报与规划》,第 26 卷第 7 期,第 743-758 页。

营销增量提升测试 101

原文:https://towardsdatascience.com/marketing-incremental-lift-test-101-f2983af1da8e?source=collection_archive---------4-----------------------

什么是电梯测试?为什么重要?一步一步的指导如何设置它,并使用提供的模板分析您的结果。

Firmbee.com 在 Unsplash的照片

在市场上这么多不同的营销平台和策略中,选择能产生有效营销 ROI 的最佳策略组合可能是压倒性的。通常,由于担心失去潜在的营销机会,越来越多的美元被花费在额外的营销技术堆栈或活动上,而不知道额外的收益是否值得。为了避免浪费开支,Lift Test 是一种统计方法,用于在为项目分配预算之前评估您的选项。

电梯测试简介

提升测试通过将一个独立变量应用于测试组而不是维持组来帮助识别因变量的增量回报和因果效应。

例如,Lift Test 可以帮助您回答在脸书上投放广告(自变量)与不投放广告相比,可以从一组受众中提高多少转化率(因变量)。

然后通过假设检验方法评估提升测试结果。如果测试组和抵制组之间的提升具有统计显著性,则接受替代假设以支持在脸书投放广告将有助于增加转化率,并且拒绝零假设,即在脸书投放广告不会有助于增加转化率。

A/B 测试和 Lift 测试有什么区别?

提升测试是 A/B 测试的一种。提升测试的本质是通过不向坚持组提供处理来发现测试组的增量值。因此,你不只是衡量一个活动的绝对结果,而是量化如果没有这个额外的活动,你还能获得多少转化率。另一方面,A/B 检验将为两组都提供治疗,但只是不同的治疗,它不是用来寻找增量回报,而是绝对相关性。因此,在 A/B 测试中通常称为控制组,而在 Lift 测试中则称为保持组。

有什么统计学意义?

测量统计显著性是为了帮助您确信您的测试结果不是随机的,您希望测试结果的置信水平与您在计算样本量时设置的 alpha 水平(显著性水平)有关,参见样本量计算器模板中的公式。基于 P 值测试结果产量(参见显著性计算模板,如果 1- (P 值),观察显著性,大于目标显著性水平,您接受替代假设并拒绝零假设。

电梯测试用例示例:

  1. 考虑到人们可以从其他现有的活动中转化过来,一个新的活动值得发起吗?
  2. 通过使用新的供应商来帮助拓展潜在客户,我的增量投资回报率是多少?
  3. 与不提供任何折扣相比,当提供折扣以激励客户下第一个订单时,我的增量 CAC(客户采购成本)是多少?

启动电梯测试的逐步指南:

1.概述测试目标和测试变量(独立变量),如是否投放脸书广告。注意,总是建议一次只测试一个变量,以控制数据噪声。

2.根据目标,您将能够选择要用于衡量结果的 KPI,包括因变量,如转换率和每次收购的允许成本。

3.确定测试是单尾的还是双尾的。测试的类型将影响您在下一步如何计算所需的样本量。如果测试组的提升被认为只是一个积极的影响,那么它就是一个单尾测试。但是,如果电梯可以造成负面影响,如过度营销,可以推开客户不转换,那么它将是一个双尾测试。

4.根据不同的提升水平确定所需的最小样本量。首先,设置α和β,以获得所需的显著性和功效水平。样本大小将根据预期的维持组性能而有所不同,维持组的性能越高,相同提升级别所需的样本大小就越小。这同样适用于升力水平,升力越高,所需的样本量越小。

样本量计算器模板

5.根据所需的最小样本量,检查满足预期显著性所需的提升对您的测试场景是否有意义。如果是,估计收集所需样本量的测试费用。如果所需的升力太高,寻找更大的样本大小及其所需的升力,看看是否可以实现。同样的事情也适用于预算控制。如果较大的样本量需要超出预算的成本,那么您可以选择用较小的样本获得更高的提升。这是一种平衡行为。

6.准备测试受众,并确保在维持组和测试组之间随机选择样本。

比如可以用 Python 熊猫。DataFrame.sample 函数创建随机生成的两组(如果使用自定义受众列表)。请注意,添加 random_state 参数有助于为将来的验证复制相同的随机选择。

代码示例:

#import pandas packages
import Pandas as pd#Create a subset of audience for the test group
test_female_under_30_ios = df[(df.segment_name == 'female_age_under_30') & (df.ios_user_flag == 1)].sample(n = 4442, random_state = 1)

7.根据测试类型,准备其他测试材料,如活动创意、活动跟踪设置等。

8.通过量化因变量(如维持组和测试组之间的转换率)的提升来测量测试结果,以确定基于样本大小的提升水平是否达到所需的统计显著性。

9.根据统计显著性拒绝或接受零假设。如果要拒绝零假设(接受投放广告有帮助),那么就要计算业务盈利能力指标,以评估这种处理方式是否划算。如果每次收购的增量成本在允许的范围内,这意味着测试变量(例如,提供脸书广告)产生了足够的增量转换(例如,比维持组更多的转换),值得实施。

计算统计显著性的指标包括:

提升分析模板

注:n1=测试样本大小,n2 =维持样本大小

测试转换率:p1

保持转换速率:p2

测试标准误差(SE1): SQRT(p1×(1-p1)/n1)

维持标准误差(SE2): SQRT(p2×(1-p2)/n2)

Z 分数:(p1-p2)/SQRT(POWER(SE1,2)+POWER(SE2,2))

P 值(Excel): 1-常模。DIST(Z 分数,真)

P 值(Google Sheet): 1- NORM。DIST(Z 分数)

观察到的显著性:1 个 P 值

上面的公式是使用 Excel 和 Google Sheets 中的语法编写的,所以可以直接应用到您的 Excel/Google 工作簿中进行分析。

希望你喜欢这篇文章,并找到它的帮助。如果您有任何问题,请随时发表评论。我希望听到您的反馈!

在 Twitter 上向软件工程师营销是一个昂贵的好主意

原文:https://towardsdatascience.com/marketing-to-software-engineers-on-twitter-is-an-expensive-good-idea-733a1b13f367?source=collection_archive---------47-----------------------

软件工程师在推特上闲逛。

我知道这是一件趣闻,也是凭感觉,因为我职业生涯的大部分时间都是作为一名软件工程师度过的,而且十多年来我一直有一个 Twitter 账户。但你也可以更客观地证实这一点。

例如,在谷歌上搜索“Twitter 上要关注的程序员”,确实会得到实际的搜索量(每个地方的关键词)。当我输入其他职业,如律师、医生和教师,没有搜索量登记。

虽然我最初在 Twitter 上的存在主要是为了进行专业互动和推广业余爱好博客,但大约七年前,我开始自己创业,成为一名顾问。因此,社交媒体开始成为我提供的服务和任何产品的销售渠道。Twitter 也不例外。

我尽职尽责地在 Twitter 和 LinkedIn 上推广内容和产品,因为这就是“营销你的企业 101”最佳实践等等。我想很多创业者和独立人士都像我一样,死记硬背。

作者图片

提问:品牌应该在 Twitter 上向开发者营销吗?

但是出于我不会在这里让你厌烦的原因,大约四年前我结束了从写软件到开始开发营销业务的转变。对于这项业务,我们采取了一种金钱球/魔鬼经济学式的内容宣传方式。我们不承担工作,除非我们能模型化,至少在抽象上,我们创造的内容的投资回报率。

这让我最近问了一个多年前就应该问的问题:Twitter 是一个值得接触工程师的营销渠道吗?

常识和轶事经验说是的。但在我研究成功的影响者对该平台的使用时,挥之不去的疑虑一直在蔓延。

我并不怀疑他们能接触到人们并建立关系。这是毫无疑问的。我认为更多的是,他们对 Twitter 游戏的热爱导致他们看不到他们在平台上投入了多少劳动(和成本)来获得这些结果。

作者图片

这对这个领域的有影响力的人来说很好。但它可以转化为对品牌有吸引力的麻烦。这些天,我在帮助品牌营销部门避免在吸引人的麻烦上浪费金钱。

所以让我们从数据驱动的角度来看 Twitter,使用我现有的数据:我的推文和我的关注者。所有这些内容和人都严重扭曲了程序员。

搭建舞台:注意事项和方法

在深入研究之前,我想澄清几件事。

这里涉及的严格程度

首先,请理解,我不是要在这里发表一篇博士论文进行答辩。在我作为一名受薪软件工程师和开始开发营销业务的几年中,我是作为软件世界的专业管理顾问谋生的。我用来帮助客户的东西之一是从优秀的书 如何测量任何东西 中提取的。

任何事情都是可以衡量的。如果一个事物可以用任何方式观察到,那么它就适合某种测量方法。不管测量结果有多“模糊”,如果它告诉你的比你以前知道的更多,它仍然是一个测量结果。而那些最有可能被视为不可测量的事情,实际上总是可以通过相对简单的测量方法来解决。

所以收集这些数据并做出推论的目的并不是要有一个绝对无懈可击的案例。更确切地说,是把我们对这个渠道的概念从“我不知道,其他人也这么做,所以让我们试试吧”转变为有假设来进行实验。

作者图片

只关注 Twitter 追随者的建立和营销

大多数有影响力的开发者使用 Twitter 的方式相当简单。他们建立一个观众群,然后对观众说话。一路上的任何病毒式传播或标签成功都是额外收获。

我今天要看的是假设开发者营销品牌有兴趣以这种方式再造开发者影响者成功的数据。换句话说,我要看看成本和回报,就像一个开发工具品牌建立一个追随者,然后与这些追随者分享内容。

这意味着我不看赞助商的推文,不玩算法游戏,不购买关注者,也不瞄准标签。这些都是潜在可行的方法,可能会改变 Twitter 作为一个平台的整体投资回报率。但今天,我只想谈谈 Twitter 的“传统”活动,即建立追随者并与这些追随者分享内容。

方法论:如何收集 Twitter 数据

我将提供的最后一点内务管理是如何从 Twitter 中提取数据以及我提取了哪些数据的方法。

要从 Twitter 中获取数据,实际上可以使用原生 Twitter 功能来下载数据。他们会在 24 小时内给你寄去压缩的档案。如果你不喜欢等待或者想要更精细的控制, Twitter 也提供了一个 API

然而,对我来说,这两件事我都没做。Hit Subscribe 实际上与 Panoply 有关系,后者可以立即将各种来源的数据转换成关系格式。

这让我免去了争论 API 和导出的头痛。相反,它只是把一切都放入一个关系结构中。所以我直奔主题,就像这样:

作者图片

这让我可以访问我的推特账户上的所有数据。从那里,我使用了关于我的追随者(主要是程序员)和 tweets(历史上,主要是面向编程的)的信息。

这是我将用于分析的数据。不言而喻,尽管具有代表性,但这是一个样本量。为了将我们最初的实验框架构建成一个稳健的模型,我们需要在前进的过程中获取更多的数据。

但我认为我这里有有趣的对话。

看看一些原始数据和发现

说完这些,让我们开始研究一些数据。当我们寻求为内容渠道建立 ROI 模型时,我们需要了解两个主要变量:

  1. 总值
  2. 使用该成本产生的成果(收入)

在数字营销领域,由于变量的蝴蝶效应般的爆炸,将推文等活动与顶线收入联系起来变得很棘手。所以我们可以走捷径,用几种简单的方法进行推理:

  1. 考虑一个指标,比如一个网站的浏览量或点击数,并假设一个占位符估值,比如网站访问者或浏览量的美元价值。
  2. 将每次印象或点击的成本与某人必须支付的广告费用进行比较。因此,如果你能以比普通广告活动更低的成本获得印象和点击,我们可以认为这是一个“好”的渠道。

因为第一种选择因企业而异,所以我将坚持第二种选择。让我们回顾一下与广告平台相比,展示的成本。

因此,我们通过 Twitter 进行的营销活动有两种成本,如果你愿意的话:

  1. 建立追随者的成本
  2. 创建内容营销成本如下

现在让我们用我的数据开始对此进行推理。

用每个关注者的 Tweets 来近似劳动力

我所能想到的衡量建立一个追随者的成本的最直接的方法是假设在平台上创建内容是产生追随者的原因。换句话说,推文与关注者的比例是多少?

看着我的 3892 名粉丝(在我写这篇文章的时候),我为每个人添加了一个专栏,计算他们的推文与粉丝的比率。然后我取那列的平均值。该值为 15.4。换句话说,在我的粉丝中,每个粉丝的平均推文数量是 15.4 条。

现在这个推理显然是不完善的。很明显,除了发推特,人们还有其他吸引粉丝的方式。众所周知,詹姆斯·科米更换了他的推特账号,得到了验证,并立刻吸引了成千上万的追随者。

作者图片

但是我们既没有足够的时间去了解平台外的追随者来源,也没有足够的数据来提供信息。因此,我将通过使用中位数而不是平均值来减少干扰。这让我们消除了 Comeys 和那些在 Twitter 上表现糟糕的人的离群值,他们用许多许多的 tweets 尖叫着进入他们的零粉丝的空白。

事实上,使用中间值会大大拉平数据。在我的关注者中,推文与关注者的比例中位数是更合理的,每个关注者 4.1 条推文。

追随者吸引力是一个正反馈循环

当我在这里看我的数据时,我开始想知道随着 Twitter 账户规模的扩大,它们在吸引追随者方面是否变得更有效率。所以我把 Twitter 用户分成了四个不互相排斥的群体:

  1. 粉丝少于 1000 人的人。
  2. 粉丝超过 1000 人的。
  3. 粉丝超过一万的。
  4. 最后是那些粉丝超过 10 万的。

取这些较小部分的中间值揭示了一个明显的趋势。

作者图片

这似乎证实了我暗中的怀疑。通往 10 万 Twitter 粉丝的道路并不是简单地发布 40 万条推文。随着追随者的增加,吸引更多的追随者——因为需要更多的研究来确定——变得更加容易。想到的一些可能的解释包括平台外的名气和大量追随者更容易吸引追随者的社会证明。

然而,对于我们的实验框架的轮廓来说,这已经足够了。我们可以看到平台上存在一个正反馈回路。

品牌比个人更有效率

接下来,我想特别区分品牌的数据。说实话,我的假设是,品牌需要更加努力地工作,发布更多推文来吸引追随者。毕竟,品牌经常自我宣传,在 Twitter 上也相当无聊。

但是,有趣的是,事实并非如此。

我浏览并手动识别了我的追随者中的所有品牌。然后我对它们进行了同样的分析,发现了同样的趋势。唯一的区别是品牌的“效率”似乎是两倍多。

总体而言,品牌的推文与关注者的比率约为 1.3,这是关注者的趋势。

作者图片

现在,我们开始进入这样一个阶段,我们可以添加一些成本预测,以建立一个品牌追随者。我们可以看到平台上有多少内容创作对应了什么样的关注规模。所以我们需要估算出创建这些内容的成本。

但在此之前,我还想收集最后一份原始数据。这将告诉我们如何以及何时开始“促销”

没有链接的推文比有链接的推文更吸引人

多年来,我在 Twitter 和社交媒体上的一个主要使用案例是推广我在其他渠道创建的内容。这通常采用“适当”帖子的形式,其中我不只是转储一个链接并说,“在这里。”相反,我花时间写了一个关于内容的导语,包括一些标签,并链接到内容。

我想看看这些内容与简单地为平台创建没有链接的内容相比如何。

寻找其他内容或优惠会影响参与度吗?

作者图片

为了在我们的主题餐巾纸背面近似描述这一点,我将赞和转发作为参与度的标志。我很想包括甚至权衡对推文的回复,但是我没有这些数据。

在这种情况下,我的计算很简单。我查看了整体参与度,以每条推文的转发数和收藏数来衡量。然后我把我的推文按照是否包含链接进行了分类。

  • 我的推特平均获得 4.1 次点击。
  • 我平均每条带有链接的推文有 3.7 次点击。
  • 我的没有链接的推特平均获得了 9.54 次点击。

在这种情况下,我想坚持使用平均值,而不是使用中间值。我对剔除异常值不感兴趣,因为异常值代表大规模参与,这毕竟是我们所追求的。

建立活动成本模型

有了这些数据,我们现在有足够的数据来开始成本和 ROI 模型。我们可以看到如何建立一个追随者,这是主要的障碍。在此基础上,我们将讨论创建推广内容的成本和功效。

制作 Twitter 内容的成本

首先,让我们对发布一条推文的成本做一个大概的假设。我将称之为 15 分钟来生成一条平均推文,并估计这样做的劳动力成本为每小时 25 美元。

我的理由是,当然,你会在推特上回复一些诸如“谢谢!”在几秒钟内,你就可以把更多的时间投入到宣传和其他战略性的内容中。所以平均到 15 分钟。

至于成本,当然,任何人都可以发推特,你可能会让人们以最低工资来做这件事。但想必你需要一些营销知识。你有时也很可能会外包这项工作——而且成本比全职员工高。

但是在构建我们的模型时,为了便于讨论,我们将这些数字作为变量。这样,如果有人说,“Pff,25 美元是荒谬的,我们支付 10 美元,”我们可以简单地插入 10 美元,看看对 ROI 的预期影响。

作者图片

建立追随者的成本

考虑到这一点,建立一个追随者的成本是多少?

好吧,根据上面的品牌数据,你会发 2000 次微博来获得 1000 名粉丝,然后再发 9000 次微博来获得 10000 名粉丝。总共有 11000 条推文。

使用上面的成本数字,11,000 条推文意味着 2,750 个工时,成本为 68,750 美元。而且那个感觉就像它是方形的。如果我们假设这是入门级社交媒体专家两年的工资,这意味着我们预计入门级营销人员能够在几年内建立一个品牌的 10,000 名追随者。

同样值得一提的是,我正在考虑将建立追随者与推广内容和将人们与平台联系起来分离开来。换句话说,除了自我推销的推文,你不会建立一个追随者。你必须卷起袖子,创建特定于平台的内容来建立这些追随者(或者成为联邦调查局局长)。

为营销活动建立投资回报模型

为了开始建立 ROI 模型,我们如何将所有这些联系在一起?

好吧,这个难题的最后一个缺失部分是实际点击率(CTR),这让我们可以用每次点击成本(CPC)来讨论。你可以通过谷歌搜索找到不同的数字,但是让我们用 HubSpot 的数字,1.64%。(解释点击率作为关注者数量的函数下降的“原因”会很有趣,但鉴于我不理解这背后的原因,我将只使用他们的广义平均值。)

假设我们想要建立一个 10,000 人的追随者,然后向该追随者推广内容。这是我们的成本和回报结构。

  • 建造下面这座建筑需要 68750 美元。
  • 一旦你开始推广内容,你需要为每次 10K 展示和 164 次点击支付 6 美元。这是每千分之 0.60 美元的成本(CPM),以及 0.04 美元的 CPC。

因此,一旦你在这个平台上投入了将近 7 万美元,你就会获得极其丰厚的回报。这篇文章将谷歌广告的典型 CPM 定为 2.80 美元,你的 Twitter 追随者可能比谷歌搜索者更容易细分。这篇文章将搜索广告的点击费定为 3.80 美元,展示广告为 0.51 美元。

但显然,在考虑营销时,我们需要考虑对平台的投资。

让我们假设,在你建立了你的追随者之后,你创建了 10 条、100 条、1000 条和 10000 条推广推文。更进一步,让我们假设你应该为每条推广推文创建大约三条非推广推文,以避免失去追随者。这是 CPM 和 CPC 的情况。

作者图片

如何解释价值观和模式

在这篇文章中,我一直在谈论通过减少不确定性的总体视角来创建活动模型。到目前为止,这是相当抽象的,但是你可以通过上面的电子表格截图看到我们如何更具体地处理这个问题。

任何需要更多研究或数据的东西都会成为模型中的一个变量。然后,我们可以在进行过程中给变量添加置信因子(或者最终将它们视为常数)。

例如,如果你想说你可以用更少的推文建立 10K 追随者,我们可以相应地调整“关注推文”单元格,观察对投资回报率的影响。类似于“目标 CPC”和“目标 CPM ”,我们从范围的低端获取数据,从而产生悲观的投资回报预测。如果谷歌广告的成本实际上比你的利基市场高得多,那么谷歌广告的相对投资回报率就会变得更高。

相反,这个模型目前假设你的 100%的追随者看到每条推文,这个百分比肯定太高了。人们对 Twitter 的零星消费和算法本身可能会减少印象,这是一个相当重要的因素,需要更多的研究才能正确建模。

这整个模型目前只着眼于相对于可比广告支出的投资回报率。当我们充实这一点时,我们也将看看 Twitter 本身作为一个主要资格平台和品牌意识的价值。当然,我们将着眼于比“埃里克的追随者”更大、更有代表性的数据集

但即使是这个早期的模型也大大减少了模糊性,呈现出一幅相当清晰的画面。

全进或全出:不要走过场

在 Hit Subscribe,我们帮助客户开展的大多数活动都是有机流量活动。原因是,从投资回报率的角度来看,你网站的有机流量是最蓝筹的内容营销手段。但这也是一场持久战,在你开始获得(通常是惊人的)回报之前,需要大量的时间和投资。

事实证明,开发者营销 Twitter 实际上非常相似。

即使我将模型中的成本降低到每条推特 1 美元,如果没有大量的推广投资,我们也看不到正回报。

作者图片

我认为这太乐观了,因为如果你在推文创作上省钱,只是把任何旧东西放进 Hootsuite,我认为你需要让 10K 粉丝看到的推文数量将会飙升到 11K 以上。这里的午餐似乎不免费,甚至不便宜。

当然,我们将继续构建和完善这个模型。但是基于我在这里得到的信息,我想说开发者营销品牌有两个清晰的、不相关的 Twitter 策略选择:

  1. 为最低成本进行优化,敷衍了事地出现在 Twitter 上,这样你就不会完全从频道中消失。
  2. 将 Twitter 视为一个合法的潜在客户生成渠道,但要明白,在产生回报之前,对该平台的投资必须是实质性的。

我认为真正的、定性的教训是,建立这样一个渠道不仅需要时间和大量投资,还需要人才。渠道中有影响力的工程师,通常通过热爱工作,倾注大量的精力,这样做,他们变得很擅长。

(我不是其中之一——就我个人而言,我很不擅长 Twitter。)

因此,如果你想重现他们的成功,就需要时间、金钱、人才,以及有人愿意并准备好将它视为一流的内容创作平台,而不仅仅是公告和推广的仓库。

附录:工具列表

如果您对我在这个建模练习中使用的各种工具感兴趣,下面是它们:

马尔可夫决策过程和贝尔曼方程

原文:https://towardsdatascience.com/markov-decision-processes-and-bellman-equations-45234cce9d25?source=collection_archive---------7-----------------------

婴儿机器人强化学习指南

强化学习简介:第 2 部分

所有图片由作者提供。

介绍

在关于强化学习的 系列的第一部分 中,我们看到了如何评估代理的行为,以衡量它在给定问题上的表现。

问题环境被分成一组状态,每个状态都被赋予一个值,这个值反映了在那个状态下有多好。通过选择使机器人宝宝朝着增加状态值的方向移动的动作,我们能够帮助他找到一个简单网格级别的出口。

此外,我们设法用有限的理论做到了这一点。我们没有预先定义完整的强化学习问题,而是在需要时推导出我们的方程,从简单的方程开始,并建立在我们以前使用过的方程的基础上。事实证明,我们采取的简单步骤已经让我们接近于定义完整的强化学习问题。在这一部分,我们将采取实现目标所需的最后几步。

第 1 部分可以在这里找到…

密码

本文相关的 [Jupyter 笔记本](http://Reinforcement_Learning/Part 2 - Markov Decision Processes and Bellman Equations.ipynb) 可以在 github 上找到。这包含设置和运行下述级别和算法所需的所有代码。

马尔可夫过程(马尔可夫链)

在最后一部分,机器人宝宝设法找到了一个简单的网格水平的出路。不幸的是,它仍然没有回到妈妈身边,相反,它发现自己进入了一个新的层次,如下所示:

虽然这是一个相当小的水平,婴儿机器人可以看到出口,屋顶一直在漏水,所以地板上满是水坑。不幸的是,机器人宝宝并不是真的被设计成在雨天工作。水坑会减慢他的速度,更糟糕的是,会导致他打滑。结果是,如果他从一个有水坑的正方形开始,就不能保证他会朝着想要的方向移动。

然而,我们确实知道关于该系统的所有信息,包括水坑导致打滑的可能性:

  • 小水坑有 20%的机会打滑,所以 80%的时间会选择方向。
  • 大水坑有 60%的机会打滑,所以选择的方向只有 40%的机会被采用。

当打滑发生时,它将导致机器人宝宝向与选择的方向不同的方向移动。发生这种情况的概率将在其他可能的方向上平均分配。此外,我们最初只是观察环境。机器人宝宝将试图向出口走去,但受到系统动力学的支配。他无法控制他选择的路径,他的下一个状态将由他当前状态的转移概率决定。在这个阶段,没有行动或奖励。

所有这些都可以总结在下面的状态转换图中。

漏栅级的状态转移概率。

最初,机器人宝宝还没有决定向哪个方向移动。因此,从开始状态,他要么向东移动到 S1,要么向南移动到 S3,等概率为 0.5。

S1 有一个大水坑,所以,虽然机器人宝宝想搬到 S2,但这种情况发生的可能性只有 0.4%。更有可能的结果是,他会打滑,而不是结束在 S4 州或回到起点。因为打滑的概率是 0.6,这在两个可能的方向上平均分配,他到达 S4 的概率是 0.3,他回到起点的概率也是 0.3。

S4 也有一个大水坑,所以将与 S1 表现相同。来自 S4 的小机器人想要移动到出口,但是只有 0.4 的几率他会朝这个方向移动。相反,他可能会退缩,要么搬到 S1,要么搬到 S3,两者的概率都是 0.3。

类似地,如果他开始移动到 S3,其中包含一个小水坑,他的下一次移动带他到他想去的 S4 的机会是 0.8,打滑回到起点的机会是 0.2。S2 也有一个小水坑,所以从这里有 0.8%的机会他会移动到出口,0.2%的机会他会滑回 S1。

这些状态转移概率也可以用状态转移矩阵来表示,如下所示。这个矩阵告诉我们,从任何一个状态开始,到任何一个状态结束的可能性有多大。

泄漏电网等级的状态转移矩阵

请注意,离开任何状态的概率总和总是 1,如状态转移图上所示,以及状态转移矩阵中的每一行。此外,当机器人宝宝到达出口时,这是他不能再移动的最终状态。因此,在出口处,停留在出口处的转移概率为 1.0。

从关卡的起点开始,我们可以沿着一系列路径通过关卡,直到到达出口。这些路径中的每一条都代表一个事件,并且每个事件都将遵循由系统动力学定义的随机轨迹。由于状态转换的随机性,路径可以是任意长度。

因此,以下每个情节都是通过该级别的有效路径:

  • 出发,S1,S4,出口
  • 出发,S3,S4,S1,S2,出境
  • 出发,S1,S2,S1,S4,出境

对于上面给出的层次,及其伴随的状态转移图和矩阵,我们已经描述了一个 马尔可夫过程 (也称为 马尔可夫链 )。这是一个随机过程的模型,其中一系列事件发生,事件发生的概率仅取决于当前状态。

我们网格级别中的完整状态集构成了状态空间,它定义了系统中所有可能的状态。这些状态中的每一个都独立于先前的状态,因此满足 马尔可夫性质。 关于一个状态的所有信息都包含在那个状态中。因此,我们不需要知道过去发生了什么来预测未来会发生什么。

实际上,预先知道系统的转移概率是不太可能的。因此,为了估计从一个状态转移到另一个状态的可能性,可以观察多个事件,然后取平均值。这种随机抽取样本来计算估计值的方法被称为蒙特卡罗抽样,我们将在以后的文章中对此进行全面研究。

马尔可夫奖励过程

马尔可夫过程定义了一个状态空间和在这些状态之间移动的转移概率。它没有具体说明哪些州是好州,也没有说明从一个州搬到另一个州是否好。为此,我们需要在系统中添加奖励,并从马尔可夫过程转移到马尔可夫奖励过程。

在这个系列的第一部分中,我们定义了机器人宝宝每次从一个方格移动到下一个方格时,他将获得-1 的奖励。这鼓励他选择最短的路径通过关卡,因为他花的时间越长,他的奖励就越低。请记住,我们试图最大化总累积奖励,因此有一个大的负奖励是不好的。

在这个漏水的关卡中,我们已经指定水坑会导致机器人宝宝减速,大水坑比小水坑需要更长的时间。考虑到这一点,我们可以修改我们的奖励如下:

  • 小水坑的移动时间是标准方格的两倍。因此,考虑到这一点,移动到一个有小水坑的状态将给予-2 的奖励。
  • 类似地,大水坑需要 4 倍的时间才能通过,所以进入一个有大水坑的州会得到-4 的奖励。

在这里,我们已经定义了当机器人宝宝进入水坑时,处于水坑中的惩罚发生,因此当进入水坑状态时,增加的负奖励将被给予。当退出包含水坑的状态时,归属奖励也是完全合理的,但是我们试图强调踏入大水坑是不好的!

我们已经将这些奖励添加到状态转换图中,如下所示。每次转换获得的奖励以红色显示,位于相关转换概率下方。

漏级的国家奖励程序

请注意,我们仍然只是在观察系统,还没有引入动作的概念。因此,机器人宝宝将以当前状态的转移概率从一个状态转移到下一个状态,只是现在他每移动一步都会得到奖励。

从开始状态,机器人宝宝可以向两个可能的方向移动,他可以移动到 S1 的大水坑中,并获得-4 的奖励。或者,他可以搬到州立 S3,那里有一个小水坑,所以他会得到较少的负奖励-2。因为机器人宝宝还没有能力选择自己走哪条路,所以搬到 S1 或 S3 的可能性是相等的,两者发生的概率都是 0.5。

虽然机器人宝宝还不能影响他通过关卡的路径,但是回报的增加确实让我们可以评估沿着一条特定的路径走有多好。由此,我们可以计算出,在给定转移概率的情况下,任何特定的状态有多好。

在第 1 部分中,我们介绍了 返回 的概念。这是从时间步长' t '开始的总累积奖励。例如,对于样本路径{ 起点,S1,S4,出口 },返回将是(-4–4–1)=-9。请注意,虽然我们的系统中有一个“开始”状态,代表机器人宝宝进入网格级别的位置,但在计算回报时,没有必要从这个位置开始。例如,在时间步' t '我们可以说机器人宝宝处于状态 S1 ,然后从这个位置开始计算回报,直到剧集结束。

此外,由于状态转换的随机性质意味着,理论上,序列可能是无限长的,我们在回报计算中添加了一个折扣因子。这可以防止回报值变得过大,并将注意力集中在近期获得的回报上。在每个递增的时间步长,奖励乘以折扣因子的递增幂,并且折扣因子被选择为 0 和 1 之间的值。因此,每一步获得的报酬的贡献随着时间而减少。

这为我们提供了贴现回报公式:

等式 1:贴现回报

其中:

  • =回报(从时间‘t’开始,一集累积的奖励总额)
  • rₜ₊₁= t+1 时刻获得的奖励**
  • γ(γ)=第个贴现因子,其中 0 ≤ γ ≤ 1。

如果我们选择任何一个状态作为起点(即我们在时间't【T21 ']的位置),并沿着一条路径到该集的结尾,在每个时间步添加折扣奖励,我们会得到一个返回值,这将是对该状态值的一个非常粗略的估计,描述了在初始状态下有多好。如果返回值是一个很大的负值,那么这不是很好。**

显然,考虑到系统中路径的随机性,单个事件的返回值并不是对一个州价值的最准确估计。所以我们取期望值,实际上是无限期事件的平均值。这给了我们 状态值函数 v(s):

等式 2:状态值函数

因此,在时间' t '时,如果我们从状态' s '开始,并测量预期收益,我们将得到状态' s '的值,描述处于该状态有多好。

考虑到我们还没有在混合中引入动作,价值函数似乎没什么用处。我们可以计算在某个特定的状态下有多好,但是还没有任何方法可以利用这个知识让我们选择一条可以获得最大回报的道路。然而,通过对这个等式进行轻微的重新调整,我们可以使它变得更加强大。

再次查看等式 1,返回值从时间' t '开始。目前,这体现在所有未来的奖励上。虽然回报已经被贴现,因此未来的回报对最终回报的贡献较小,但如果你想完全准确地计算回报,理论上你需要考虑所有未来时间点获得的回报。这使得事情变得相当不切实际,因为对于每个状态,你都需要考虑将来可能获得的每个奖励。

但是可以改变等式 1,从用所有未来回报来表达,改为递归,用未来回报来表达:

等式 3:根据即时回报和下一次回报给出的时间 t 的回报。

现在回报是根据即时回报加上下一个时间点的贴现回报给出的。通过将其代入等式 2,我们还可以用即时回报和未来贴现回报来表示状态值:

等式 4:用即时回报和下次回报表示的状态价值函数。

但是 Gₜ₊₁ 只是下一个时间步的返回,在这一点上,我们将处于下一个状态,通过再次使用等式 2,就是下一个状态的期望值。所以我们也可以用递归的方式来表达状态值,使它成为即时奖励和下一个状态值的函数:

方程式 5:贝尔曼方程式

这种状态值函数的重排,将其分解为眼前的奖励和下一个状态的贴现值【γv(sₜ₊₁】被称为贝尔曼方程,其中可以说是强化学习的基本方程。利用这一点,可以简单地通过预测下一个状态来计算任何状态的值,而不是必须检查每个未来的状态。一旦知道了状态的值,就可以选择在这些状态之间移动的最佳动作,并且最终可以找到解决给定问题的最佳策略。**

现在,我们可以将此应用于马尔可夫奖励过程中的状态,以计算它们的值。为此,我们首先需要以稍微不同的形式表达贝尔曼方程,如下所示:

等式 6:用转移概率和回报概率表示的贝尔曼等式。

在等式 6 中,我们简单地从将状态值函数表示为期望值,改为对状态' s '中可能发生的每个转换求平均值。

关于这个等式,有几点值得注意:

  • 所有下一个状态和奖励的总和只是一种方便的写法,我们对所有下一个状态和奖励求和。因此,实际上有两个和:一个用于下一个状态,它使用移动到状态s’,的转移概率,另一个用于奖励,给定当我们从状态‘s’开始时接收奖励的概率’r’。
  • p(s′,r|s) 是移动到状态s′并得到奖励' r' 的概率,假设我们从状态' s '开始。**
  • 这些概率乘以立即获得的奖励和下一个状态的贴现值。

在这种格式中,我们可以将这个等式应用于我们的漏栅能级的状态。因此,例如,在开始状态,它有 2 个可能的转换,每个转换以 0.5 的概率发生,并且当分别移动到状态 S1S3 时,给出奖励-4 和-2。因此,其状态值由下式给出:

等式 7:起始状态的状态值。

由于这是一个非常简单的水平,我们知道它最终将结束于退出状态并终止,我们可以通过将贴现因子' γ '设置为 1 来进一步简化它。然而,我们仍然剩下用状态 1 和 3 的值表示的开始状态的值,我们还不知道。

在本系列的第一部分中,我们看到了如何使用迭代策略评估来计算状态值。从每个状态的值为零的初始假设开始,我们可以迭代地改进这个估计,直到我们收敛到真实的状态值。虽然我们当时没有明确说明,但我们已经在使用贝尔曼方程的部分形式来实现这一点。

将迭代策略评估应用于我们的马尔可夫奖励过程版本的泄漏水平,得到如下所示的状态值。这些值是在 32 次迭代后获得的,此时任何状态值的最大变化都收敛到小于 0.001(尽管下面显示的值只有 1 个小数位):

MRP 的状态值。

从收敛的状态值我们可以看到,从起始状态开始,移动到出口,平均来说,会发生-16.3 的奖励惩罚。类似地,如果我们已经到达状态 S2 ,那么我们可以预计,平均来说,到达出口会招致-4 的惩罚。

因此,现在我们知道了所有的状态值,我们可以将 S1和 S3的值代入上面的等式 7,以检查我们是否得到了起始状态的正确值:**

**v(开始)= 0.5 [-4-11.9]+0.5 [-2-14.8]=-16.35

类似地, S2 的值由 S1 和出口的值给出:

**v(S2)= 0.8 [-1]+0.2 [-4-11.9]=-0.8-3.18 =-3.98

下面显示了漏网格级别上策略评估的前 23 次迭代。可以看到值是如何收敛的(只显示了总共 32 次迭代中的前 23 次,因为在这一点之后,状态值的变化会以比我们显示的 1 个小数位更高的精度发生):

漏网格级 MRP 的迭代策略评估

从计算出的状态值中很容易看出,穿过网格的最佳路线将是起点,S1,S2,出口,从而招致最低的惩罚。然而,在 MRP 中,我们没有办法选择行动,因此也没有办法选择走哪条路。要做到这一点,我们需要添加行动,并转移到马尔可夫决策过程(MDP)。

马尔可夫决策过程

贝尔曼方程允许我们通过简单地一步预测下一个状态来计算状态值。使用这些值,我们可以看到哪些状态是好的,哪些状态应该避免。然而,在马尔可夫奖励过程中,我们无法控制我们要转移到哪个状态。为此,我们需要引入行动,转而采用马尔可夫决策过程(MDP)。

行动允许做出决定。因此,可以选择要去的国家和要获得的奖励。虽然,在一个随机系统中,你可能不总是得到所选择的行动或奖励。转移概率和奖励函数现在都依赖于动作。动作本身由一个策略选择。这定义了在任何特定状态下应该选择哪个动作。

通过对贝尔曼方程做非常细微的调整,我们可以修改它以考虑政策:

方程式 8:政策的贝尔曼方程式 π

公式 8 与公式 5 中的标准 Bellman 公式相比有细微的变化,很容易忽略这种变化。不同的是,现在状态's '和下一个状态sₜ₊₁的值都用策略π表示,我们将在下一个时间步移动到这两个状态。这意味着,如果我们在时间“ t ”处于状态“ s ”,我们将选择策略“ π 给出的动作,并且我们将在所有未来状态中继续根据该策略选择动作。

正如我们对 MRP 所做的那样,我们可以将这个等式转化为一个可用的形式,即通过采取特定行动' a ',以后续状态s '结束,并接收奖励' r' ,对所有这些量求和:

等式 9:策略下的状态值 π

这与等式 6 相同,在等式 6 中,我们用 MRP 的转移和回报概率来表示贝尔曼等式,只是现在增加了行动。

因此,当遵循策略' π ' 时,状态' s 的值等于:

  • 在特定状态下可以采取的所有行动的总和。
  • 每个动作都有发生的概率,这由策略决定。所以 π(a|s) 是假设我们处于状态' s '时,采取行动' a 的概率。对这些概率求和实际上是对该州所有行动的平均。
  • 采取行动获得的回报和采取行动后的下一个状态也是随机的,所以我们通过将它们发生的概率乘以立即获得的回报和下一个状态的贴现值求和来取平均值。

在本系列的第一部分中,我们只研究了确定性动作。当采取一项行动时,我们确切地知道下一个状态会是什么,以及采取行动会得到多少奖励。现在,在贝尔曼方程的完整形式中,一个动作的下一个状态和奖励由一个概率分布 p(s′,r|s,a)决定。这是移动到状态 s '并得到奖励 r '的概率,假设我们从状态 s '开始并采取行动 a。

下面显示了我们样本级别的 S4 州可能采取的行动:

国家 S4 行动,转移概率和奖励。

S4 是一个包含大水坑的州,所以在这个州采取行动有很大的机会导致打滑发生。结果,在采取所选择的行动之后,以期望的状态结束的概率只有 0.4。有 0.6%的机会打滑,结果却陷入了一个不是最初目标的状态。这个概率在其他可能的状态中平均分配。

因此,举例来说,从 S4 的 3 个可能的行动,北,东,西,婴儿机器人显然会选择向东移动,并到达出口。然而,他只有 0.4 的机会真正达到这个目标状态,并因此获得标准 1 奖励。更有可能的结果是他会滑倒。在这种情况下,有 0.3 的机会在 S1 结束,给他一个大的负奖励-4,或者他会得到-2 的奖励,并在 S3 结束,同样有 0.3 的机会发生这种情况。

q 值

如果你知道采取每一项行动的预期回报值,找到最佳行动就会变得容易得多。因此,由于单个行动值可以提供关于系统的大量知识,它们已经被分配了自己的值字母,并被称为 Q 值

(我们在看 多武装盗匪 的时候已经看过 Q 值。在这种情况下,它们被用来描述在单一状态土匪问题中可获得的行动的期望回报。)

在上面给出的等式 9 中,状态值函数由所有动作的总和给出,其中采取每个动作的概率乘以该动作的值。因此,接下来的状态和奖励的右边总和代表采取特定行动的价值。我们可以把它分离出来,给我们行动值函数,当采取行动' a 、状态' s 、政策' π '时:

等式 10:策略 的动作值函数π

对于上图所示的状态 S4,机器人宝宝想要采取将他引向出口的动作。使用等式 10,我们可以计算采取该行动的行动值,看看这是否是一个好的行动。由于这是一个有限的 MDP,我们将使用折现因子γ = 1。此外,由于根据定义,退出是一个终止状态,因此它的状态值为零。我们还没有计算 S1 和 S3 的状态值函数,如果机器人宝宝打滑,其他可能的状态可能会结束,所以现在我们只是用' V '的格式来表示它们。

这给出了在 S4 州采取东部行动的下列行动值:

  • ***q(S4,东)= 0.4 (1)+0.3 (4+V(S1))+0.3 (2+V(S3))

相比之下,在这种状态下采取另外两种可能的行动将得到:

  • ***q(S4,北方)= 0.4 (4+V(S1))+0.3 (2+V(S3))+0.3 (1)
  • ***q(S4,西部)= 0.4 (2+V(S3))+0.3 (4+V(S1))+0.3 (1)

这让我们看到如何计算每个动作的值,尽管不知道所有状态的值,我们还不能算出最终的动作值。为此,我们可以使用我们在第 1 部分中看到的迭代策略评估方法。

用贝尔曼期望方程进行政策评估

提醒一下,策略评估最初将所有状态的估计值设置为零,然后重复扫描所有状态以逐渐改进这些估计值,直到最终收敛于真实的状态值。

我们以前用这个来计算状态的值,其中动作是确定性的;当你采取一项行动时,你总是以期望的状态结束。现在事情变得更复杂了,因为行动现在是随机的;采取行动并不保证你会达到目标状态,因此,获得的回报也可能不同。因此,在这种情况下,我们需要使用完整的贝尔曼期望方程来实现策略评估,该方程将对一个状态中可能的操作以及选择操作可能导致的预期下一个状态和回报进行期望。

公式 9 中给出的贝尔曼期望公式以代码形式显示如下。这里很容易看出这两个和是如何被代码中的一个循环替换的。对于每个状态,第一个循环调用函数' get_ π',该函数返回所有可能的动作及其概率(即策略)。然后,第二个循环调用' get_p ,迭代当前动作所有可能的下一个状态,计算每个动作的 Q 值(这部分代码实现了等式 10)。

(完整代码实现,查看 github 笔记本 )

将上述函数与跨越状态的重复扫描相结合,允许我们计算所有状态的状态值。这与我们在第 1 部分中所做的略有不同,因为动作的结果不再是确定的。

例如,就像他在第一部分的第一个简单关卡中所做的那样,机器人宝宝通过扔硬币来决定选择走哪条路(除了现在在某些州他需要一个三面硬币!).换句话说,在任何状态下,选择行动的概率都是相等的。然而,由于关卡中的水坑,他最终到达的地方可能不是他希望到达的地方。下一个状态和他得到的奖励是由系统动力学决定的。

对此随机策略运行策略评估时获得的状态值如下所示。这些值最终在 63 次迭代后收敛。

漏网格级 MDP 上随机策略的迭代策略评估

可以看出,这些值比 MRP 获得的值差很多。当我们为 MRP 选择转移概率时,我们选择了指向退出方向的值。实际上,我们将动作硬编码到系统中。现在,在 MDP,我们随机选择动作,所以机器人宝宝将会花更多的时间探索关卡。

然而,尽管这些值比 MRP 中的值差,但是通过贪婪地按照这些值行动,机器人宝宝可以改进他的策略,并且从随机策略移动到从起点到终点寻找最佳路线的最优策略。

贝尔曼最优方程

为了在最短的时间内浏览我们的网格级别,或者在任何强化学习问题中获得最大的回报,在每个状态中,我们都希望选择给出最大预期回报的动作。换句话说,因为策略是决定为每个状态选择什么动作的东西,所以我们想要找到最优策略

对于任何一个州,如果我们搜索所有可能的政策,我们可以找到产生最大回报的行动。这就是 最优动作值函数 :

等式 11:通过在所有策略中采取具有最大行动值的行动,给出最佳行动值函数

然后,如果对于每个状态,我们知道哪一个是最优动作,我们可以简单地总是选择最优动作,并得到 最优状态值函数 :

等式 12:最佳状态值函数

因此,一个状态的最优价值函数是通过选择给出最大回报的行动,然后在所有未来状态中总是选择最优行动来给出的。

与最佳动作值函数一样,当状态值在所有策略中最大时,会出现最佳状态值函数。当这对于所有状态都成立时,每个状态的值等于或大于它在任何其他策略下的值,我们就找到了 最优策略

通过将方程 10 中的' q 的值代入方程 12 中的最优状态值函数,我们得到 贝尔曼最优方程。

方程 13:定义最优状态值函数的贝尔曼最优方程。

在下一部分中,我们将看到如何在策略和值迭代中使用贝尔曼期望和最优方程来找到最优策略。

现在,我们可以根据上面找到的随机策略的状态值贪婪地行动,以获得最优行动。由此我们可以计算出最优策略的状态值。最优策略的迭代策略评估如下所示。这实际上在 31 次迭代中收敛,并产生比随机策略给出的状态值好得多的状态值。

漏网格级 MDP 最优策略的迭代策略评估

使用这种最佳策略,机器人宝宝现在可以通过这个简单的泄漏关卡,尽管当他遇到水坑时可能仍然会打滑,但他会在最短的时间内到达出口。

下面显示了穿过该层的一个这样的路径。当机器人宝宝最终所处的实际状态与他期望的目标状态不匹配时,就会出现打滑。

婴儿机器人通过漏层遵循最优策略

摘要

在这个系列的第一部分,我们帮助机器人宝宝逃离一个简单的网格关卡。我们这样做是通过评估状态值,然后根据这些值选择一条路径,让我们找到通过关卡的最短路线。尽管我们当时并不知道,我们使用的方程是贝尔曼方程,我们操作的系统可以用马尔可夫决策过程来描述。我们现在已经讨论了这两个问题。

一个基本的马尔可夫过程定义了一组状态,每个状态满足马尔可夫性质,其中不需要过去的知识。转移概率定义了从一个状态转移到下一个状态的概率,在强化学习问题中,这些概率由当前策略给出。

当奖励被加入到马尔可夫过程中时,毫不奇怪,我们得到了一个马尔可夫奖励过程。贝尔曼方程让我们将转移概率与这些奖励结合起来,计算每种状态的价值,以此来衡量每种状态有多好。

虽然在马尔可夫奖励过程中,我们可以计算每个状态的值,但仍然不可能决定如何通过状态移动来最大化奖励。为了实现这一点,需要扩展它们以允许采取行动,这正是当我们转向马尔可夫决策过程时所发生的。当添加动作时,马尔可夫决策过程可以用来完全描述强化学习问题的环境,以及代理在该环境中如何行动。

下一步是什么

我们现在已经涵盖了描述强化学习问题所需的所有基础理论。此外,我们已经看到了如何使用策略评估来计算状态值,对于简单的问题,我们能够从中找到最佳策略。

在下一部分中,我们将扩展这一点,在策略和值迭代算法中使用我们刚刚看到的贝尔曼方程。这些将允许我们在更高级的设置中发现最佳策略。

****< Part 1                                                    Part 3 >** [**State Values and Policy Evaluation**](/state-values-and-policy-evaluation-ceefdd8c2369)[**Policy and Value Iteration**](/policy-and-value-iteration-78501afb41d2)**

使用 YOLOv5 进行掩模检测

原文:https://towardsdatascience.com/mask-detection-using-yolov5-ae40979227a6?source=collection_archive---------2-----------------------

图片来自维基百科

解释关键概念,然后使用 YOLOv5 实现简单的屏蔽检测

介绍

我最近在 Coursera 上完成了吴恩达教授的 DeepLearningAI 的卷积神经网络课程,课程的一部分深入到了计算机视觉领域。我对计算机视觉的能力以及它如何融入我们的日常生活非常着迷,这促使我更深入地研究计算机视觉,并启动项目来加强我的学习。

如果您只想查看 YOLOv5 模型的项目实施情况,请向下滚动

物体检测的工作原理

在实施一个项目之前,最好了解一些关于对象检测的基本概念以及它是如何协同工作的。让我们从定义对象检测开始:

{分类+定位} →检测

图像分类是将一种算法应用于图像来预测一个对象的类别,例如汽车。物体定位不仅预测物体的类别,而且通过在物体周围画一个包围盒来计算出物体的位置。目标检测包括分类和定位,并且检测不止一个目标&甚至不止一个类别。

3 个术语之间的视觉比较。汽车图片由马特·安东尼奥利·Unsplash.com

包围盒

一个标准的分类任务将涉及一幅图像通过一个多层的 Convnet,其中的矢量特征被输入到一个 softmax 单元,例如,输出预测的类别(算法试图检测的对象类别,即汽车、树木、行人)。诸如 YOLO 的对象检测模型通过将图像分割成网格单元来工作,其中如果边界框的中心位于单元中,则每个网格单元负责预测边界框。然后,它将输出预测的类,即边界框的坐标,如下所示:

标有蓝色的单元格预测边界框的中心位于单元格中。作者图片

显示与边界框关联的变量的图像。作者图片

要了解更多关于卷积神经网络的信息,请查阅由 Mayank Mishra 解释的卷积神经网络。他很好地解释了 Convnet 的工作原理

并集上的交集

当算法输出定位检测到的对象的包围盒时,如何判断算法是否运行良好?这就是并集上的交集(IoU)发挥作用的地方。通常,IoU 是两个边界框之间重叠的度量:算法预测边界框和地面真实边界框。

作者图片

IoU 的公式是交叉点的大小除以两个边界框的并集的大小。IoU 的阈值约为 0.5。值≥ 0.5 的借据被视为“正确”预测。

非最大抑制

参考下面的边界框图像,标记为 1–33 的单元格都预测边界框的中心位于它们的单元格中。

这将导致算法多次检测对象,而不是仅一次。这就是非最大值抑制的作用,它确保算法只检测每个对象一次。如前所述,每个单元输出 y = (P𝒸,bₓ,bᵧ,b𝓌,bₕ,c),P𝒸是存在物体的概率。非最大值抑制的作用是获取具有最高 P𝒸的边界框,丢弃任何 p𝒸≤0.6 的边界框,并“抑制”其他 IoU ≥ 0.5 的边界框。

视觉描绘非最大抑制。作者图片

锚箱

如果多个对象位于同一个网格单元中会怎样?边界框会是什么样的?锚盒的想法可以用在这里。查看下图,注意人和汽车的中点如何位于网格单元内。(为了简单起见,我将图像分成 3×3 的网格)

描述包含两个对象中点的网格单元的图像。图片由丹学长,

当前单元格输出 y = (P𝒸,bₓ,bᵧ,b𝓌,bₕ,c),单元格只能选择两个对象中的一个进行检测。但是对于锚盒(通常使用训练数据集的 k-means 分析预先定义),成本标签 y 变成(P𝒸、bₓ、bᵧ、b𝓌、bₕ、c、P𝒸₁、bₓ₁、bᵧ₁、b、b、c、p……)。)基本上根据锚盒有多少而重复,第一输出用锚盒 1 编码,第二输出用锚盒 2 编码,依此类推。每个输出单元检测一个对象类;锚盒 1 类似于汽车,因此输出 c 将用于汽车,下一个输出 c 将用于人,因为它被编码到锚盒 2。

作者图片

注意,表示对象类的每个输出单元 c 都受到对象的地面真实边界框的高 IoU 的影响。

使用 YOLOv5 进行掩模检测

模型

对于这个项目,我将使用 YOLOv5 来训练一个对象检测模型。YOLO 是“你只看一次”的首字母缩写。一种流行的架构,因为:

  • 速度(基本型号—每秒 45 帧,快速型号—每秒 155 帧,比 R-CNN 快 1000 倍)
  • 该架构仅包括单个神经网络(可以直接针对检测性能进行端到端优化)
  • 能够学习物体的一般表示法(图像的全局上下文提供了预测信息)
  • 开源

YOLOv5 型号与 EfficientDet 之间的比较,由 Ultralytics 提供图像

要了解关于该模型的更多信息,请访问他们的知识库: Ultralytics YOLOv5 Github 知识库

资料组

我在 Kaggle 上找到了这个人脸面具检测数据集,由 853 张图片组成,分为 3 类:带面具、不带面具和面具佩戴不当。每幅图像都带有一个 PASCAL VOC 格式的 XML 文件,其中包含其边界框的注释。这里有一个例子:

来自面罩检测数据集的示例图像

<annotation> <folder>images</folder> <filename>maksssksksss4.png</filename> <size> <width>301</width> <height>400</height> <depth>3</depth> </size> <segmented>0</segmented> <object> <name>with_mask</name> <pose>Unspecified</pose> <truncated>0</truncated> <occluded>0</occluded> <difficult>0</difficult> <bndbox> <xmin>70</xmin> <ymin>185</ymin> <xmax>176</xmax> <ymax>321</ymax> </bndbox> </object></annotation>

本项目需要的关键信息是:

  1. :图像的尺寸,单位为像素
  2. 整体 : xmin,ymin 表示边界框左上角的位置,而 xmax,ymax 表示边界框右下角的像素

格式化

在用模型训练数据之前,PASCAL VOC XML 格式的注释数据必须转换成 YOLO 格式,每个图像一个*.txt文件,其规格如下:(也用下面的示例图像 maksssksksss4.png 说明)

  • 每个对象一行
  • 每一行都是class x_center y_center width height格式。
  • 框坐标必须是标准化的 xywh 格式(从 0 到 1)。如果你的盒子是以像素为单位,那么用图像宽度划分x_centerwidth,用图像高度划分y_centerheight
  • 类别号是零索引的(从 0 开始)。

作者图片

我编写了一个函数,使用 XML.etree 库从 XML 文件中提取所需的信息,并计算 x_centre 和 y_centre。因为注释数据是以图像像素为单位的,所以我对最终值进行了归一化,以满足需求。

结果将是这样的:

作者图片

还需要以如下所示的特定方式格式化目录,其中训练和验证图像和标签被分离到每个独立的文件夹中

作者图片

我使用 Pathlib 库编写了另一个简单的函数。

请注意,上面提到的所有格式都可以使用 Roboflow 来完成,这是一个简单、代码化且没有麻烦的替代方法。用代码手动做是我个人的偏好

在训练模型之前,我们需要创建一个 projectdata。yaml 文件,指定训练和验证图像的位置和标签数量以及我们训练数据的标签名称。该文件的结构应该如下所示:

*# specify pathway which the val and training data is at
# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]*path: ../mask_detection/projectdata
train: images/train
val: images/val

*# Classes* nc: 3
names: ['no mask', 'mask worn incorrectly', 'mask on']

训练模型

为了使用自定义数据集训练模型,我在本地终端中使用以下参数运行了 train.py :

  • img: 输入图像尺寸
  • ****批量:批量大小
  • ****历元:历元数
  • ****数据:projectdata.yaml 文件的路径
  • cfg: 在预先存在的模型中进行选择📁**型号**
  • ****权重:初始权重路径,默认为 yolov5s.pt
  • ****缓存:缓存图像以加快训练速度

我选择了最小最快的型号 yolov5s。我还使用模型的预训练权重进行迁移学习,而不是重新训练新的权重,这非常耗时,并且由于高处理能力要求,不可能在笔记本电脑上训练。我使用“1”的批量大小,并为 10 个时期训练模型。

python mask_detection\yolov5\train.py --img 640 --batch 1 --epochs 10 --data projectdata.yaml
--weights yolov5s.pt --cfg mask_detection\yolov5\models\yolov5s.yaml --cache

作者图片

如果所有步骤都正确完成,该命令将输出以下内容并开始训练。关注 mAP@.5,看看 model 表现如何。一旦训练开始,在“运行”文件夹下,Yolov5 训练管道在测试图像上输入地面实况和预测结果,如下所示。

地面实况训练图像。作者图片

测试图像。作者图片

训练完成后,经过训练的模型将保存在您的“权重”文件夹/目录中,验证指标将记录在 Tensorboard 上。(按照建议,我选择将数据记录到 wandb 中)

培训结果。作者图片

图像高度和宽度的相关图

数据相关图。作者图片

目标检测模型的评估

受欢迎的挑战和比赛,例如:

所有 3 项挑战都使用平均精度(mAP)作为评估物体探测器的主要指标。地图到底是什么?首先,让我们来了解一些基本概念。

  • ****置信度:锚框包含分类器预测的对象的概率
  • I 并集上的交集(IoU): 边界框的交集面积除以预测边界框的并集面积
  • ****精度:真阳性数( TP )除以真阳性数( TP ) &假阳性数( FP )
  • ****召回:真阳性的数量除以真阳性的总和( TP ) &假阴性( FP )

只有满足以下条件,置信度得分和 IoU 才用于确定预测检测是 TP 还是 FP (注意:任何违反后两个条件的情况都使其成为 FP

  1. 置信度得分>阈值(如果< threshold, detection counts as a False Negative ( FN ))
  2. 预测的边界框具有比阈值更高的 IoU
  3. 预测类与地面真实类相匹配

随着置信度分数的增加,回忆单调下降,而精确度可以上升和下降,但是对于这个项目,所有类别(除了不正确佩戴的面具)都增加。

精确召回曲线。作者图片

虽然精确召回率可以用来评估目标检测器的性能,但是不容易在不同的检测器之间进行比较。为了查看整个事情进行比较,基于精度-召回曲线的平均精度(AP)** 开始起作用。根据定义,AP 正在寻找上面精确回忆曲线下的区域。均值平均精度(mAP) 是 AP 的均值。**

请注意,mAP 的定义和实现有所不同。

在 PASCAL VOC 挑战中,一个对象类的 AP 是针对 0.5 的 IoU 阈值计算的。因此,贴图是所有对象类的平均值。

对于 COCO 对象检测挑战,该图是所有对象类别和 10 个 IoU 阈值的平均值。

推理

既然模型已经训练好了,接下来是有趣的部分:对图像或视频进行推理!在本地终端中调用 detect.py,使用以下参数运行推理:(查看 detect.py 解析器以获得完整的参数列表)

  • ****权重:训练模型的权重
  • ****来源:输入运行推理的文件/文件夹,0 表示网络摄像头
  • iou-thres :非最大抑制的 iou 阈值,默认值:0.45
python yolov5\detect.py --source vid.mp4 --weights runs\train\exp\weights\best.pt --img 640 --iou-thres 0.5

作者 GIF

如你所见,该模型能够检测到口罩的存在!

结尾注释

这一模式远非完美,仍有改进的空间

  • 该模型不能检测不正确佩戴的面具,这是其中一个类别。这很可能是由于数据的巨大不平衡。只有一小部分数据由不正确佩戴的面具组成。一种可能的解决方案是应用数据平衡,以便该模型将更好地识别不正确佩戴的面具。
  • 可以使用更大的框架,例如 Yolov5x,而不是 Yolov5s,以实现更高的 mAP。但一个可能的缺点是训练如此庞大的模型需要额外的时间。

就这样,我的文章到此结束!这个项目对我来说真的很有趣,我喜欢学习新的和有趣的概念,尤其是在开始的时候,学习计算机视觉似乎是一项艰巨的任务,但我很高兴能够完成它!干杯!

LinkedIn 简介:肖恩·雅普

参考

[1] 约瑟夫·雷德蒙桑托什·迪夫瓦拉罗斯·吉斯克阿里·法尔哈迪你只看一次:统一的、实时的物体检测 (2015)

[2]吴恩达,卷积神经网络,深度学习。AI Coursera

[3]由 Mark Everingham、Luc Van Gool、Christopher K. I. Williams、John Winn 和 Andrew Zisserman 提出的 PASCAL 视觉对象类(VOC)挑战

用 BERT 进行屏蔽语言建模

原文:https://towardsdatascience.com/masked-language-modelling-with-bert-7d49793e5d2c?source=collection_archive---------0-----------------------

在任何数据集上微调您的模型

伯特的双向二头肌-作者图片。

B ERT,大家最喜欢的变形金刚花费 Google ~$7K 训练[1](还有谁知道 R & D 花费多少)。从那里,我们编写几行代码来使用同一个模型——全部免费。

由于两种独特的训练方法,掩蔽语言建模(MLM)和下一句预测(NSP),BERT 在 NLP 中获得了无与伦比的成功。

在许多情况下,我们可能能够将预先训练好的 BERT 模型开箱即用,并成功地应用到我们自己的语言任务中。

但通常,我们可能需要微调模型。

MLM 是如何运作的

与 MLM 的进一步训练使我们能够微调伯特,以更好地理解语言在更具体领域的特殊用途。

现成的 BERT —非常适合一般用途。使用 MLM·伯特进行微调,非常适合特定领域的使用。

在本文中,我们将深入了解什么是 MLM,它是如何工作的,以及我们如何用它来改进我们的模型。

屏蔽语言建模

MLM 包括给伯特一个句子,并优化伯特内部的权重,以在另一端输出相同的句子。

所以我们输入一个句子,要求 BERT 输出同样的句子。

然而,在我们实际给 BERT 输入句子之前,我们屏蔽了一些标记。

在这幅图中,在将我们的令牌传递给 BERT 之前,我们已经屏蔽了 lincoln 令牌,用【屏蔽】替换它。

所以我们实际上是在输入一个不完整的句子,然后让伯特帮我们完成它。

填补空白

这是什么效果?嗯,这就像我们很多人在学校里被问到的那些问题——在那里,给定一个句子,我们必须填补空白。

In Autumn the ______ fall from the trees.

你知道答案吗?很可能你知道,你知道是因为你考虑了句子的上下文。

我们看到单词落在树上——我们知道丢失的单词是从树上落下的东西。

很多东西从树上掉下来,橡子、树枝、树叶——但是我们有另一个条件,秋天——这缩小了我们的搜索范围,秋天最有可能从树上掉下来的东西是树叶

作为人类,我们综合运用一般的世界知识和语言理解来得出结论。对伯特来说,这个猜测将来自于大量阅读——并且非常好地学习语言模式。**

伯特可能不知道什么是秋天、树木和树叶,但他知道给定的语言模式和这些单词的上下文,答案很可能是树叶。

这个过程的结果——对伯特来说——是提高了对所用语言风格的理解。

该过程

所以我们明白 MLM 在做什么,但这实际上是如何运作的呢?我们在代码中需要遵循的逻辑步骤是什么?

1。我们标记化我们的文本。就像我们通常使用变形金刚一样,我们从文本标记化开始。

通过标记化,我们将得到三个不同的张量:

  • 输入 _ 标识
  • 令牌类型标识
  • 注意 _ 屏蔽

对于 MLM,我们不需要token _ type _ ids——在本例中 attention_mask 并不重要。

对我们来说, input_ids 张量最为重要。在这里,我们将有一个我们的文本的标记化表示——这是我们将修改前进。

2。创建一个 标签 张量。我们在这里训练我们的模型,所以我们需要一个标签张量来计算损失——并优化。

**标签张量就是input _ ids——所以我们需要做的就是复制一份。

3。 屏蔽 input_ids 中的令牌。既然我们已经为标签创建了 input_ids 的副本,我们就可以继续并屏蔽随机选择的令牌了。

BERT 论文在模型预训练期间使用 15%的概率屏蔽每个单词,并使用一些附加规则-我们将使用这种方法的简化版本,并指定每个单词被屏蔽的概率为 15%。

4。计算损失。我们通过我们的 BERT 模型处理 input_idslabel张量,并计算它们之间的损失。

利用这一损失,我们通过 BERT 计算所需的梯度变化,并优化我们的模型权重。

所有 512 个标记产生一个最终的输出嵌入—logits——其向量长度等于模型 vocab 的大小。预测的 token_id 是使用 softmax 和 argmax 转换从该 logit 中提取的。

损失计算为每个输出“令牌”的输出概率分布与真正的独热编码标签之间的差异。**

代码中的 MLM

好的,这些都很好,但是我们如何用代码演示 MLM 呢?

我们将使用拥抱脸的变形金刚和 PyTorch,以及bert-base-uncased模型。因此,让我们首先导入并初始化所有内容:

现在,我们进入每一个逻辑步骤,从以下步骤开始:

1。 标记化 —标记化很简单,我们已经初始化了一个BertTokenizer,我们现在要做的就是标记化我们的输入text

我们现在不担心填充/截断。我们应该注意的是前面描述的三个张量——token _ type _ idsattention_mask 不需要我们的任何关注——但是 input_ids 需要。

2。 创建标签 —下一步很简单,我们需要做的就是将我们的 input_ids 张量克隆到一个新的标签张量中。我们也将把它存储在inputs变量中。

3。 屏蔽 —现在我们需要屏蔽 input_ids 张量中的随机选择的记号。

为了创建屏蔽任何一个令牌的 15%的概率,我们可以使用torch.rand和每个值的条件< 0.15。总之,这些将产生我们的掩蔽阵列mask_arr

现在,我们使用mask_arr来选择放置掩码令牌的位置—但是我们不想将掩码令牌放置在其他特殊令牌之上,例如 CLSSEP 令牌(分别为 101102 )。

所以,我们需要增加一个附加条件。检查包含令牌 id101102 的位置。

现在这就是我们的屏蔽张量,为了应用它,我们将首先提取我们找到一个True值的索引位置,然后使用这个选择将这些位置的值设置为 103 (屏蔽令牌 id)。

现在我们可以在上面的 input_ids 张量中看到由 103 表示的掩码令牌。

4。 计算损失 —我们这里的最后一步与典型的模型训练过程没有什么不同。

有了 input_ids标签在我们的inputs字典中,我们可以将它传递给我们的model并返回模型损失。

培养

很好,我们已经完成了所有的要点——但是当微调一个模型时,所有这些看起来会怎么样呢?

有两种方法,(1)我们使用目前为止所学的一切来实现我们自己版本的训练功能,或者(2)我们使用 HuggingFace 的Trainer

Trainer显然是一种优化、易用的解决方案。我们将看看如何使用它——但首先,让我们试着自己实现它。

我们的实施

了解了所有这些之后,如果不尝试实现我们自己的培训功能,那将是一种浪费。

使用 PyTorch 为 MLM 训练 BERT 的演练

首先,我们需要数据。因为我们只是随机屏蔽了一些标记,所以我们几乎可以使用任何文本。我们不需要有标签的或特殊的数据。

在这里,我们将使用马库斯·奥勒留冥想,来源于这里并稍加预处理(干净版)。

首先,我们将导入/初始化并加载我们的文本数据。

然后我们进行标记化——这一次我们截断并填充每个序列——因为我们有许多不同长度的序列。

现在我们克隆输入标识来创建我们的标签张量。

接下来是我们的屏蔽代码,这次有一点不同,原因有二:

  • 我们的遮罩不应包括令牌(如之前的 CLSSEP )。
  • 我们有许多序列——不只是一个。

我们可以看到值 103 被分配在与在mask_arr张量中找到的真值相同的位置。

inputs张量现在准备好了——我们可以开始设置它们,以便在训练期间输入到我们的模型中。

在训练期间,我们将使用 PyTorch DataLoader来加载我们的数据。要使用它,我们需要将数据格式化成 PyTorch Dataset对象。

现在我们准备进入我们的训练循环。在开始我们的循环之前,我们需要设置三样东西:

  • 将模型移动到 GPU/CPU (GPU 如果可用)。
  • 激活模型训练模式。
  • 用加权衰减优化器初始化 Adam。

现在我们终于设置好了—我们可以开始训练了!我们将其格式化为 PyTorch 中的典型训练循环。

至此,我们完成了—我们已经实现了自己的 MLM 微调脚本。

运动鞋

切换到我们的Trainer实现——我们仍然需要做我们之前所做的一切,直到我们创建了我们的dataset——因为Trainer将期待这作为训练的输入。

我们将首先定义我们的训练参数,初始化Trainer——然后训练!

因此Trainer方法肯定要简单得多——它允许我们通过在初始化时简单地指定检查点和其他特性来实现它们。

好了,这就是我们开始用 MLM 微调模型所需要知道的一切。

MLM 有很多,但是概念和实现并不复杂——而且非常强大。

使用我们在这里学到的知识,我们可以采用 NLP 中最好的模型,并对它们进行微调以适应我们更特定于领域的语言用例——只需要未标记的文本——通常是很容易找到的数据源。

我希望你喜欢这篇文章!如果你有任何问题,请通过 Twitter 或在下面的评论中告诉我。如果你想要更多这样的内容,我也会在 YouTube 上发布。

感谢阅读!

参考

[1] 训练 SOTA 人工智能模型的惊人成本 (2019),同步评论

🤖带变压器的 NLP 课程

*所有图片均由作者提供,除非另有说明

使用 Shapefiles 掩蔽地理空间 3 级卫星图像:基于网格的方法

原文:https://towardsdatascience.com/masking-geo-spatial-level-3-satellite-images-using-shapefiles-a-grid-based-approach-c88d7a108f4a?source=collection_archive---------19-----------------------

如何使用相应区域的 shapefile 处理和屏蔽特定区域所需的大气三级数据

美国宇航局在 Unsplash 拍摄的照片

介绍

让我们先从遥感的概念说起。这是一项通过传感器(如卫星)收集数据的自然研究。这些传感器可以监测和收集地球不同方面的数据。其中一些包括植被数据、大气数据、海洋数据等。他们以热图或图像的形式提供数据。图像处理和屏蔽是从传感器收集的数据中提取信息所需的基本工具。本文重点介绍如何使用相应区域的 shapefile 处理和屏蔽特定区域所需的大气 NO2 数据。这里使用的数据是由臭氧监测仪器(OMI)收集的。数据是从 Earthdata 网站下载的,你可以从下面的链接下载数据。

https://search.earthdata.nasa.gov/search/granules?p = c 1266136111-GES _ DISC&pg[0][v]= f&pg[0][GSK]=-start _ date&q = OMI % 20no 2&TL = 1628603996.133!3 !!

数据描述

这里使用的数据是 OMI 卫星记录的 3 级二维网格卫星数据。数据的分辨率为(0.25 x 0.25)度网格。数据由对流层柱状二氧化氮气体组成。数据集的详细结构可以提取如下:

在文件名中使用您自己的文件路径

主数据字段位于数据集的数据字段子树下。有四个数据变量,如下所述:

ColumnAmountNo2: 总的 No2 柱密度。

columnaumntno 2 cloudscreened:滤除云噪声后的总 NO2 柱密度。

columnaumntno 2 drop:对流层区域 NO2 的柱密度。

columnaumntno 2 ropcloudscreened:无云噪声的对流层区域 NO2 的柱密度。

在本文中,我们将使用数据变量columnamountno 2 ropcloudscreened

工具和技术

Python 3.7 被用作提取和处理数据集的主要语言。这个版本很重要,因为另一个名为 geopandas 的包不能在 python 的更高版本上工作。Jupyter 笔记本用于执行脚本。数据集采用. he5 文件格式。为了从数据文件中读取和提取数据,需要一个名为 h5py 的专门包。所有这些都可以在 conda 环境中获得,您可以使用 Anaconda 通过给定的链接进行安装。

https://www.anaconda.com/products/individual

执行代码所需的包有:

导入数据

为了导入数据,需要名为 os 的包,这是 python 中的一个内置包。它遍历给定的路径,并将文件夹中包含的所有文件名读入 python 中的一个列表。使用如下所示的路径成功检索数据集名称后,需要使用 h5py 包提取数据。

在提取数据时,数据需要被清理,即所有小于零的像素值需要被过滤并用 NaN 值替换。数据提取和清理一次完成,节省了一些计算开销,也减少了代码的大小。清除数据后,沿轴=0 取所有数据的平均值,得到平均数据。

注:根据需要取平均值。如果每天都要进行一些分析,可以跳过均值步骤,单独运行每个数据的屏蔽。

整个过程需要分两步完成:

  • 收集所有数据文件名。
  • 使用 h5py 提取数据。

正在收集相关路径中的所有文件

def extractData(filenames):
    data = []
    for fname in filenames:
        fHandle = hdf.File(fname,'r')
        #Data extraction
        #Use any one of the data variable from data description
        dataNo2 = fHandle['HDFEOS/GRIDS/ColumnAmountNO2/Data Fields/ColumnAmountNO2TropCloudScreened'][:]
        dataNo2[dataNo2 < 0] = np.nan #cleaning 
        data.append(dataNo2)
    dataArray = np.array(data)
    mean = np.nanmean(dataArray, axis=0)
    return mean

这里, fHandle 内的路径是取自数据描述的路径。

读取形状文件

出于测试目的,使用了印度国家边界 shapefile。读取和处理形状文件需要 geopandas 。Geopandas 是 python 中的一个包,广泛用于地理数据处理。出于可视化的目的,使用 matplotlib。

创建纬度和经度列表

为了将图像数据转换成网格地理数据集,每个数据点的确切位置必须与全球坐标系统上的相应位置(纬度和经度)相关联。为了关联数据,使用数据的分辨率生成纬度和经度向量。由于 NO2 数据是世界数据,纬度的界限被设置为 [-90,90] ,经度的界限被设置为 [-180,180】。由于数据的分辨率为 0.25 度,我们创建一个间隔为 0.25 的等间距数组,并保持纬度和经度的界限。

从 shapefile 获取边界

为了将全局数据裁剪为 shapefile 的坐标,需要从我们正在使用的各个 shapefile 中提取纬度和经度边界。这将进一步用于在屏蔽后重新研磨数据,并将数据裁剪到所需的坐标。这可以通过用 shapefile 的边界生成另一组纬度和经度列表来完成。

一个 shapefile 可能由多个多边形组成,它需要从所有多边形中获取纬度和经度坐标。取其中的最大值和最小值将提供总 shapefile 的边界,如下所示。

def getBounds(shape):
    x1 = []
    y1 = []
    for i in range(len(shape)):
        if(isinstance(shape.iloc[i].geometry, shapely.geometry.polygon.Polygon)):  
            x = shape.exterior.iloc[i].coords.xy[0]
            y = shape.exterior.iloc[i].coords.xy[1]
            x1.append(min(x))
            x1.append(max(x))
            y1.append(min(y))
            y1.append(max(y))
        else:
            for poly in shape.iloc[i].geometry:
                x = poly.exterior.coords.xy[0]
                y = poly.exterior.coords.xy[1]
                x1.append(min(x))
                x1.append(max(x))
                y1.append(min(y))
                y1.append(max(y))return x1,y1def getBoundary(shape,res):
    x,y = getBounds(shape)
    my_lats = np.arange(np.min(y)-res/2, np.max(y)+res/2, res)
    my_lons = np.arange(np.min(x)-res/2, np.max(x)+res/2, res)
    return(my_lats,my_lons)

创建和裁剪地理数据框

到目前为止,我们一直使用文件中的原始数据。但是为了以后屏蔽数据,需要将这些数据转换成由地理点组成的地理数据框架。这可以使用 geopandas 库轻松完成。

创建数据框时,可使用 shapefiles 的纬度和经度边界裁剪数据。剪辑的概念可以用如下图所示的摄像机的概念来解释。

世界和视口框图

在我们的例子中,世界是经度从-180 到+180,纬度从-90 到+90 的实际数据。视区的坐标由 shapefile 的边界决定。

def createGeoData(lt,ln,mean_No,shape):
    lat = []
    lon = []
    data = []
    for i in range(len(lt)):
        for j in range(len(ln)):
            lat.append(lt[i])
            lon.append(ln[j])
            data.append(mean_No[i][j])

    Geo_Dataset = pd.DataFrame({'latitude':lat, 'longitude': lon, 'NO2':data})
    #clip data with shape file boundaries
    x1, y1 = getBoundary(shape,0.25)
    temp = Geo_Dataset[Geo_Dataset['latitude']>int(min(x1))]
    temp = temp[temp['latitude']<int(max(x1))]
    temp = temp[temp['longitude']>int(min(y1))]
    temp = temp[temp['longitude']<int(max(y1))]
    crc = {'init':'epsg:4326'}
    geometry = [Point(xy) for xy in zip(temp['longitude'], temp['latitude'])]
    geo_df = gpd.GeoDataFrame(temp,crs=crc,geometry=geometry)
    geo_df.reset_index(drop=True, inplace=True)
    return geo_df

屏蔽数据

由于数据被转换为由几何(点)组成的地理数据框,因此这些点可直接用于检查数据是否包含在 shapefile 的任何面中。这里使用了检查多边形内部点的概念。这是通过使用 shapely 库中的点和面包来执行的。shapefile 的任何一个多边形内的点保持不变,其余的点被赋予一个 NaN 值。

def mask(map1, geo_df):
    pol = map1.geometry
    pts = geo_df.geometry
    test = geo_df
    l,t,df = [],[],[]
    for k in range(len(pts)):
        flag = True
        for i in range(len(pol)):
            if(pol[i].contains(pts[k])):
                l.append(geo_df.latitude[k])
                t.append(geo_df.longitude[k])
                df.append(geo_df.NO2[k])
                flag = False
                break
            #end if
        #end for
        if(flag):
            l.append(np.nan)
            t.append(np.nan)
            df.append(np.nan)
        #end if
    #end for
    newdf = pd.DataFrame({'latitude':l, 'longitude': t, 'NO2':df})
    return newdf

重新划分数据

将数据转换为地理数据框时,数据被展平以便于裁剪。因此,在屏蔽数据之后,数据需要重新网格化以便可视化。

由于数据已经被裁剪,数据的形状应该等于边界纬度数组的长度乘以从 shapefile 获得的边界经度数组的长度。

注意:如果数据的形状与给定的条件不匹配,检查边界是否被正确检索,剪裁是否正确完成。

可以通过以下方式创建网格并用数据填充

def createGrid(my_lats, my_lons,mask):
    grd = np.zeros((len(my_lats),len(my_lons)))
    print(grd.shape, mask.NO2.shape)
    k = 0
    for i in range(len(my_lats)):
        for j in range(len(my_lons)):
            grd[i][j] = mask.NO2[k]
            k = k+1
        #end for
    #end for
    return grd

可视化

为了可视化数据,使用了 Matplotlib 。关于可视化没有太多要解释的😆。只需根据您的需要修改颜色栏参数。

def plot(grd, map1, x1,y1):
    plt.rcParams["font.weight"] = "bold"
    fig,ax = plt.subplots(figsize=(15,15))
    map1.plot(ax=ax, alpha=0.7, color='none')
    ax.set_title("No2 Distribution", fontweight='bold', size=20)
    ax.set_xlabel('Longitude (E)', fontsize = 20)
    ax.set_ylabel('Latitude (N)', fontsize = 20)
    bounds = [int(min(x1)),int(max(x1)),int(min(y1)),int(max(y1))]
    img = ax.imshow(grd,aspect='auto',interpolation='none', origin='lower', extent=bounds)
    cb = fig.colorbar(img)
    cb.ax.tick_params(labelsize=18)
    cb.set_label('mol cm^-2', labelpad=-57, size=14)
    ax.tick_params(labelsize = 20, width = 2.0)
    img.set_clim(0.1*1e16, 0.5*1e16)
    plt.show()

执行

现在让我们看看上述这些函数是如何工作的。有一个调用上述函数的序列。它在这里

filenames = []
for path, subdirs, files in os.walk(r'path to your own data'):
    for filename in files:
        f = path +'/'+filename
        filenames.append(str(f))mean_data = extractData(filenames)
latitude = np.arange(-90,90,0.25)
longitude = np.arange(-180,180,0.25)
m = readSHape(shpFile)
geo_df = createGeoData(latitude,longitude,mean_data,m)
msk = mask(m, geo_df)
my_lat,my_lon = getBoundary(m,0.25)
data = createGrid(my_lat,my_lon,msk)
plot(data,m, my_lon, my_lat)

结果

让我们来看看所有编码的输出😃

结论

如您所见,全局数据被隐藏在 shapefile 中。这些方法适用于所有地理区域或边界 shapefile。这是一个非常方便的地理空间分析工具。

双语机器翻译的大量预训练

原文:https://towardsdatascience.com/massive-pretraining-for-bilingual-machine-translation-3e26bfd85432?source=collection_archive---------16-----------------------

思想和理论

mBART 的引导之旅,这是一个编码器-解码器语言模型,打开了多语言序列到序列任务的有趣视角。

我不知道你怎么想,但这是我在阅读这些非常大的预训练模型时得到的感觉。阿琼肯Unsplash 上的照片

注意:这是三篇系列文章中的第一篇。
第一部分:面向双语机器翻译的海量预训练
第二部分: mBART50:可扩展多语言预训练的多语言微调
第三部分:多阶段预训练的多语言语音翻译

如果您在过去三年中从事过任何自然语言处理(NLP)任务,您肯定会注意到 BERT 或类似的大型预训练模型的广泛使用,作为对感兴趣的任务进行微调以实现出色结果的基础。

预先训练的模型允许人们用相对少的数据和训练时间在下游任务上实现高精度。通过大量的预训练,他们已经了解了自然语言的统计结构,并需要学习如何回答特定的任务。然而,由于它们庞大的体积,大多数人没有所需的资源来训练它们中的一个,并且不得不依赖于公开存在的模型。

尽管它们在 NLP 中广泛使用,但迄今为止,大量预训练的模型对机器翻译的影响相对较低。当然,也有过一些尝试,如【1】【2】【3】【4】(针对文档级翻译),但其影响有限,在实践中并未得到广泛部署。

我认为,这种有限影响的原因有三:

  1. 对于研究最多的语言对来说,机器翻译是一项资源非常丰富的任务。
  2. 机器翻译模型遵循编码器-解码器结构,而预训练模型仅由编码器组成,因此需要一些适应来将它们用于机器翻译。
  3. 这些模型非常大,并且它们在推断期间的计算时间对于编码器-解码器架构来说是不可行的。

mBART 是一个针对大量多语言数据进行预处理的编码器-解码器模型,其目标是改变机器翻译和相关任务的游戏。

姆巴特:它是什么,怎么训练的?

mBART [5]是一个基于 Transformer[6]的编码器-解码器模型,它根据来自多种语言的单语数据进行预训练,以便在机器翻译任务中进行微调。在这篇论文中,我们正在研究[5]它在来自不同语系的 25 种欧洲和亚洲语言上进行训练,这些语言是从 common crawl (CC25)中收集的。

训练目标是去噪损失。给定输入序列 X,模型在源端接收由噪声函数 g( X )生成的 X 的讹误版本作为输入。在目标端,目标是用自回归解码来重建原始序列。

噪声函数随机屏蔽连续区间中 35%的输入标记。而且多个句子同时馈入输入,噪声函数也会对它们的顺序进行置换。多输入句子的预训练允许模型在文档级机器翻译上进行微调。

模型本身具有庞大的规模:编码器和解码器中有 12 层,模型维度为 1024 个单元和 16 个注意头,总共约 680M 个参数。与 GPT-3 相比不算什么,但它仍然需要大量的计算资源来训练!

训练使用 256 个 Nvidia V100 GPUs 进行 500K 步,这相当于 2.5 周的训练,尽管有巨大的计算能力和使用 float16 precision 进行更快的训练。不要在家里尝试这个!

微调

作者在所有 25 种预训练语言的双语环境中微调了这个模型。英语总是这两种语言中的一种。此外,对句子级和文档级机器翻译都执行微调。这些模型与不同的基线进行比较,包括在较少语言(2 或 6)上预训练的 mBART、单语 BART 和随机初始化。

语言对分为以下几类:

  • ●资源:< 1M sentence pairs
  • medium resources: < 10M sentence pairs
  • high resources: > 10M 句对

结果可以总结如下:

  • 在低和中等资源语言对的 BLEU 分数方面有显著的提高。它区分了可用和不可用的系统,因为许多结果提高了 10 个以上的 BLEU 点。
  • mBART 对极低资源的语言对没有帮助(<10k sentence pairs), but read the section about unsupervised learning to see how this was overcome.
  • Marginal gains for high-resourced language pairs with little more than 10M sentence pairs. For the highest-resourced languages a decrement in BLEU score is observed.
  • 回译 [7]提供了对 mBart 预训练的进一步改进。然而,在预训练期间,可能需要更大的目标语言单语数据才真正有益。
  • 当目标语言资源不足时,对多种语言进行预训练会更有帮助。当高资源可用时,更多的语言会降低性能。也许在这种情况下,模型达到了它的容量极限。

对于资源非常丰富的语言对来说,预训练仍然没有用,但是对于其他语言来说,一些结果的改善是巨大的。并且单个预训练模型可以产生所有这些。

此外,我知道所有的目标语言对都使用相同的超参数集,所以仔细调优可能会得到更好的结果。显然,基线也是如此,但我不认为差距可以明显缩小。

然后,作者让我们高兴地研究了 mBART 在微调过程中对不可见语言的影响。

对看不见的语言进行微调

在另一项实验中,作者在 2 或 6 种语言上训练 mBART,然后在至少有一种语言在预训练中没有出现的语言对上进行微调。结果如下:

  • mBART 预训练对看不见的语言也很有帮助在预训练中有相似的语言是有益的,但不是必需的,并且在原始模型词汇中也没有必要有新语言的字母表。
  • 对两种看不见的语言进行微调会导致比一种看不见的语言更糟糕的结果。始终使用所有可用的数据!
  • 当看不见的语言在源端时,结果更糟。在源端进行归纳似乎比在目标端更困难。

一般来说,编码器-解码器模型在编码器中学习目标侧的特征,而解码器的工作更容易(例如在【8】处)。这可以解释为什么看不见的源语言更难获得更好的结果。对于不同的任务和不同的输入方式,都观察到了这种行为。我个人认为,这是由于注意力模型使得编码器在反向传播过程中可以从目标端接收到很多信息。然而,我不能在这里形成一个理论,我不知道这种现象是否被详细研究过。如果不是,它代表了一个有趣的研究课题。

尽管到目前为止信息量很大,但仍然缺少两个实验:文档级机器翻译的微调和无监督学习的微调。

文档级 MT

通过在 WMT 19 恩-德和特德 15 恩-ZH 两个方向上微调模型来进行实验。基线是一个模型(【9】),它是利用文档的层次结构,专门为文档级任务设计的。然而,[9]发表于 2018 年,我不确定是否能找到更好的基线。

结果表明,当在句子级工作时,在 mBART 上预训练的模型比随机初始化的相同模型的性能好得多。此外,只有经过微调的版本才能在文档级别产生任何有意义的结果。之前的工作 [10]应用了 BERT 损失,包括识别两个句子是否属于同一个文档,并且能够在没有预训练的情况下训练文档级模型。显然,需要特定于文档级别的损失,但可以在不同的培训阶段使用。如果在预训练期间完成,微调阶段会变得更容易。

最终结果是,预训练的模型优于韩的模型,也优于在句子层次上微调的模型。这也与[10]一致,并不令人惊讶,因为句子级机器翻译可以接收脱离上下文时有歧义的句子,但在更广泛的上下文中却可以准确翻译。

最后,作者还表明,mBART 是一个伟大的初始化无监督机器翻译。

无人监管的 MT

最后一个实验的目的是在无监督的学习环境下评估 mBART。作者提出了两种无监督的双语机器翻译场景:

  1. 通过回译学习:
    用 mBART 初始化的模型用于生成从目标语言到源语言的即时回译,并通过这种方式学习双语任务。当没有给出平行文本时,这是唯一可能的情况。
  2. 通过语言迁移学习:
    用 mBART 初始化的模型在一个语言对上进行微调,在另一个具有相同目标端语言的语言对上进行评估。当目标语言存在平行数据,而源-目标对不存在平行数据时,这种训练是有用的。

这里的结果是复杂的,但可以找到一些模式。

  • 对于基于回译的无监督机器翻译:
    mBART 在对相似语言、进行微调时类似于更传统的方法,而它为不相似语言提供了第一个非退化结果。我们仍然在谈论不能在实践中使用的模型,但这是重要的第一步。
  • 对于语言迁移:
    当在高资源语言上进行微调时,结果通常令人惊讶地好,在某些情况下,如果源端测试语言与微调语言非常不同,结果也是如此。然而,使用相似的语言通常会得到最好的结果。值得注意的是古吉拉特语的情况,这是一种资源非常匮乏的印度语言,它通过对其他印度语言进行微调而受益匪浅,而它自己的数据导致随机翻译(使用印地语-英语的 13.8 BLEU,而使用古吉拉特语-英语的 13.8 BLEU)。
  • 这两种方法也可以结合起来:从语言迁移开始,应用迭代回译。这些改进确实值得付出额外的努力。

我邀请读者深入到论文中去研究所有的结果,它们很多而且非常详细。因此,可能有适合您的用例的东西。值得注意的是,在无监督学习实验中,英语总是两种语言中的一种,在语言迁移实验中,英语总是目标语言。此外,在预训练期间观察到了两种微调语言,尽管是单语数据。

结束语

mBART 在机器翻译和其他基于一个文本到另一个文本的自然语言处理任务领域开辟了新的机会,例如参见[11][12][13]。

我发现更有趣的是,模型在预训练期间学习了语言的一些结构,这种结构似乎超越了语言的边界,允许语言之间的内在知识转移。特别是,看到语言转换可以明显优于对目标语言对的微调,对于某些应用程序来说,这确实是改变游戏规则的。

现在,我邀请你通过检查结果来批判性地阅读这篇论文,如果你想尝试 mBART,你可以在拥抱脸变形金刚公平序列中找到它。

你觉得多语预训后双语微调太局限?在本系列的下一篇文章中,我们将介绍 mBART50 (50 种预训练语言),它提出了一种通过多语言微调来改善结果的方法。

*

参考

[1] Clinchant、Stéphane、Kweon Woo Jung 和 Vassilina Nikoulina。"使用 BERT 进行神经机器翻译."第三届神经生成和翻译研讨会会议录。2019

[2]兰普勒,纪尧姆和亚历克西斯·康诺。"跨语言语言模型预训练." arXiv 预印本 arXiv:1901.07291 (2019)。

[3] Edunov、Sergey、Alexei Baevski 和 Michael Auli。"用于语言生成的预训练语言模型表示."计算语言学协会北美分会 2019 年会议论文集:人类语言技术,第 1 卷(长短论文)。2019

4郭、智宇和阮明乐。"使用 BERT 作为上下文编码器的文档级神经机器翻译."计算语言学协会亚太分会第一届会议暨第十届国际自然语言处理联合会议论文集:学生研究工作坊。2020.

[5]刘,,等.“面向神经机器翻译的多语种去噪预训练”计算语言学协会汇刊 8(2020):726–742。

[6]瓦斯瓦尼、阿希什等人,“你所需要的只是关注。”神经信息处理系统的进展。2017.

[7]森里奇、里科、巴里·哈多和亚历山德拉·伯奇。"具有子词单元的稀有词的神经机器翻译."计算语言学协会第 54 届年会论文集(第 1 卷:长篇论文)。2016.

[8] Kasai,Jungo 等,《深层编码器,浅层解码器:重新评估非自回归机器翻译》

[9] Werlen,Lesly Miculicich,等,“使用分层注意网络的文档级神经机器翻译”2018 自然语言处理经验方法会议论文集。2018.

[10]马钦·容奇斯-道蒙。“WMT 2019 微软翻译机:走向大规模文档级神经机器翻译。”

[11]马丁、路易斯等,“多语言无监督句子简化”arXiv 预印本 arXiv:2005.00352 (2020)。

[12]胜俣、仓知和住井护·小町。"使用预训练的编码器-解码器模型的更强的语法错误校正基线."计算语言学协会亚太分会第一届会议暨第十届国际自然语言处理联合会议论文集。2020.

[13]李,冼,等.“ arXiv 预印本 arXiv:2010.12829 (2020)。

中等会员

你喜欢我的文章吗?你是否正在考虑申请一个中级会员来无限制地阅读我的文章?

如果您通过此链接订阅,您将通过您的订阅支持我,无需为您支付额外费用【https://medium.com/@mattiadigangi/membership*

掌握 Apache Airflow:如何在 10 分钟内安装和设置环境

原文:https://towardsdatascience.com/master-apache-airflow-how-to-install-and-setup-the-environment-in-10-minutes-61dad52d5239?source=collection_archive---------3-----------------------

了解如何设置和配置环境来编写您的第一个 DAG。

Solen Feyissa 在 Unsplash 上拍摄的照片

Apache Airflow 是一个开源的工作流管理平台(来源,是现代数据科学家和工程师的必备技术。

今天,您将学习如何在虚拟机上安装平台,配置它,并通过终端和 Visual Studio 代码建立 SSH 连接。

这篇文章的结构如下:

  • 步骤 1:下载并安装 Ubuntu 服务器
  • 步骤 2:通过终端建立 SSH 连接
  • 步骤 3:安装 Apache Airflow
  • 步骤 4:通过 Visual Studio 代码建立 SSH 连接
  • 结论

步骤 1:下载并安装 Ubuntu 服务器

让我们从最简单的一步开始。我假设你已经安装了 VirtualBox 。如果不是这样,请在继续之前安装它。

我们将从下载 Ubuntu 服务器 ISO 文件开始。下载大约需要 1GB,所以不会花太长时间:

图 1 — Ubuntu 服务器下载过程(图片由作者提供)

下载时,您可以配置虚拟机。转到 VirtualBox,根据下图创建一台新机器:

图 2 — VirtualBox 机器规格(图片由作者提供)

从那里,只需点击几次下一个,并选择合适的 RAM 和存储配置。我选择了 4GB 的内存和 25GB 的存储空间——但也可以自由分配。

完成后,您的列表上将出现一个新的虚拟机:

图 3 — VirtualBox 机器列表(图片由作者提供)

让我们在下载 ISO 的时候再做一些调整。打开新机器的设置并进入网络。在高级下,点击端口转发按钮:

图 4 —虚拟机网络设置(图片由作者提供)

我们需要转发两个端口:

  1. Guest 8080 to Host 8250 (或者任何其他的,文档推荐 8080,但是那个在我的机器上被占用了)用于气流 UI
  2. 访客 22 到主机 2222 进行 SSH 连接

完成后,您的窗口应该如下所示:

图 5 —虚拟机端口转发配置(图片由作者提供)

这就是所有的配置。ISO 文件现在应该已经下载好了,所以运行虚拟机并加载 ISO 文件进行安装。像平常一样安装操作系统。你需要创建一个用户——我把我的叫做气流

下面是安装的截图:

图 6 — Ubuntu 服务器安装(图片由作者提供)

如果你看到类似的东西,那么你就在正确的轨道上。安装完成后,您可以重新启动虚拟机并使用您的用户登录。就这样——Ubuntu 服务器安装完毕!

步骤 2:通过终端建立 SSH 连接

我们现在可以从终端(或者 PuTTY,如果你在 Windows 上)建立一个 SSH 连接。

对于 macOS 和 Linux,您必须在终端中输入下面一行:

ssh -p 2222 airflow@localhost

如下图所示:

图 7 —通过终端的 SSH 连接(图片由作者提供)

请记住,气流表示安装时您拥有的用户名。

步骤 3:安装 Apache Airflow

Apache Airflow 的安装是一个多步骤的过程。整个事情都是基于 Python 的,Ubuntu Server 没有随 Python 3 一起发布。以下命令将改变这种情况:

sudo apt install python3-pip

现在您已经安装了 Python 3.8.x(或某个更新的版本),所以您已经准备好安装 Airflow 了。下面的终端命令就可以做到这一点:

sudo pip3 install “apache-airflow==2.0.2” — constraint “https://raw.githubusercontent.com/apache/airflow/constraints-2.0.2/constraints-3.8.txt"

请记住:

  • 用您想要的版本替换 2.0.2
  • constraints-3.8.txt 替换为您的 Python 版本。例如,如果你使用的是 Python 3.9.x,它应该是: constraints-3.9.txt

气流安装完毕!但这并不意味着它被配置了。您还需要初始化数据库并创建用户。以下命令为气流初始化数据库:

airflow db init

下面的代码创建用户:

airflow users create — username admin — firstname <your_first_name> — lastname <your_last_name> — role Admin — email <your_email>

完成后,您可以使用以下命令将两个 Airflow 服务器作为守护程序运行:

airflow webserver -D

就这样——Apache air flow 现在开始运行了!

要进行验证,请打开网络浏览器并转到localhost:8250(将 8250 更换为气流主机端口)。您应该会看到以下屏幕:

图 8 — Airflow 登录屏幕(图片由作者提供)

要继续,请输入一分钟前创建的数据库用户凭证,并点击登录。您将立即看到以下屏幕:

图 9-air flow 主屏幕(图片由作者提供)

就这样——你成功了!不要担心最初加载的大量 Dag。您可以从 web 应用程序中快速删除它们,或者指定不在气流配置中加载它们。

接下来,让我们看看如何从 Visual Studio 代码建立到虚拟机的远程 SSH 连接。

步骤 4:通过 Visual Studio 代码建立 SSH 连接

如果你和我一样,从主机到客户机的手动文件传输太麻烦了。幸运的是,一个免费的代码编辑器——Visual Studio Code——可以为您管理连接。

首先,安装一个名为 Remote — SSH 的免费插件:

图 10 —安装远程 SSH 插件(图片由作者提供)

在那里,按下左下角的蓝色小按钮,并选择连接到主机选项:

图 11 —连接到主机(图片由作者提供)

接下来,输入与您在终端中输入的命令相同的连接命令:

图 12 —连接命令(图片由作者提供)

Visual Studio 代码会要求您将连接配置添加到 SSH 配置列表中,因此选择第一个选项:

图 13 —保存连接信息(作者图片)

再次单击蓝色小按钮,连接到本地主机:

图 14 — SSH 本地主机连接(图片由作者提供)

一旦你这样做了,一个新的 Visual Studio 代码窗口将会弹出,你必须输入密码。这与您为 Ubuntu 服务器用户选择的密码相同:

图 15 —远程 SSH 认证(图片由作者提供)

最后,您可以点击打开文件夹按钮来打开远程主机上的任何目录。让我们打开/home/airflow文件夹:

图 16-访问 Airflow 根文件夹(作者图片)

就这样,你准备好创建你的第一个气流 DAG。确保将它们放在dags文件夹中(你必须先创建它),因为那是 Airflow 试图找到它们的地方。您可以随时修改配置文件,但这超出了今天的范围。

图 17 — Airflow 根文件夹(图片由作者提供)

让我们在下一部分总结一下。

结论

这就是你要的——安装在虚拟机中的 Apache Airflow。你可以在本地或用 Docker 安装 Airflow,但我发现这种方法在我的职业生涯中更常见。

接下来,我们将探索如何创建和安排您的第一个 DAG,如果您想了解更多,请继续关注博客。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

了解更多信息

保持联系

精通 Apache Airflow:用 Python 在几分钟内编写第一个 DAG

原文:https://towardsdatascience.com/master-apache-airflow-write-your-first-dag-with-python-in-minutes-6c50b5d4aab1?source=collection_archive---------7-----------------------

下面是如何用 Apache Airflow 编写您的第一个 ETL 管道。

照片由索伦·费伊萨Unsplash 拍摄

所以您已经配置了气流环境,但是接下来呢?你来对地方了。今天,您将一口气用 Python 编写第一个带有气流的 DAG。

如果您想了解如何设置 Apache Airflow 环境,这里有一篇适合您的文章:

本文假设您已经配置了 Airflow 环境,启动了 webserver 和 scheduler,并且使用 Visual Studio 代码连接到了虚拟机。

这篇文章的结构如下:

  • 问题描述
  • 用于 ETL 管道的 Python 函数
  • 写一个 DAG
  • 测试
  • 结论

问题描述

我们今天要做的事情相对简单——从虚拟 API 下载数据,对其进行转换,并将其保存为 CSV 格式。尽管如此,它将是一个完整的 ETL 管道。

幸运的是,网上有一个免费的虚拟 API—JSON 占位符。它包含虚假的用户数据等,这就是我们今天要用的。

数据看起来是这样的:

图 1-伪造的用户数据(作者提供的图片)

因此,从下一节开始,我们将定义几个 Python 函数来提取、转换和加载这些数据。

用于 ETL 管道的 Python 函数

让我们从在您的dags文件夹中创建一个 Python 文件开始——我将我的命名为etl_users.py

任何 ETL 管道都需要实现提取、转换和加载数据的功能。

说到提取,事情很简单——我们向 API 端点发出 GET 请求,并将响应转换为 JSON 格式。我们还将做一件特定于气流的事情— XCOM 推送。这样做会将提取的结果保存到 Airflow 的数据库中,因此您可以使用它在任务之间进行通信。

这是完整的提取代码:

如果您想知道— ti代表任务实例,一个特定于气流的东西,用于标识任务。

开始变形了。这一次我们将执行 XCOM pull——从前面的函数中获取数据。然后,我们将只保留感兴趣的字段——ID、姓名、用户名、电子邮件、地址、电话号码和公司名称。最后,这个转换后的用户版本再次通过 XCOMs 推送到气流数据库:

最后,让我们来看看装货。该函数还执行 XCOM pull 来获取转换后的用户,然后将它们转换为 Pandas 数据帧,最后保存到所需的位置:

这就是我们所需要的!请记住——您可以使用return关键字来代替 XCOM 推送,但是我发现这种方法更加明确。

写一个 DAG

Apache Airflow 基于 Dag(有向无环图)的思想。这意味着我们必须为管道的各个部分指定任务,然后以某种方式安排它们。

为了简单起见,我们今天只处理基于PythonOperator的任务,但是值得指出的是,您可以使用更多的操作符。

第一个任务将通过使用extract_users()函数执行用户提取。在 Airflow 中,您可以使用op_kwargs参数为函数指定关键字参数。第二个任务将转换用户,最后一个任务将他们保存到一个 CSV 文件中。

最后,我们必须安排任务,这样 DAG 才能形成。你可以使用>><<操作符来完成,就像你马上会看到的那样。

以下是完整的 DAG 代码:

如你所见,task_load_users会将 CSV 文件保存到data/文件夹中。默认情况下不会有它,如果不手动创建它,Airflow 会抛出一个错误,所以请在继续之前创建它。

最后,整个etl_users.py文件应该如下所示:

如果您现在要打开 Airflow 服务器(localhost:8250在我的机器上,但是请检查您的 VM 端口转发),您将会看到这样一个屏幕:

图 2-Apache air flow DAG 列表(图片由作者提供)

这意味着我们有测试所需的一切。

测试

首先,单击etl_users dag 并通过单击左上角的小开关按钮打开它:

图 3 —将 DAG 设置为活动(作者提供的图片)

您还可以在前面的图片中看到我们的 ETL 管道的简单流程——提取发生在转换之前,转换发生在加载之前。

我们已经安排 DAG 每天运行一次,但是您可以通过单击右上角的小播放按钮来手动触发它,您会立即看到 DAG 正在运行:

图 4 —手动触发 DAG(作者图片)

几乎立刻,您会在任务周围看到浅绿色或深绿色的边框。浅绿色表示任务正在运行,而它的深色兄弟表示任务已成功完成:

图 5 — DAG 正在运行(图片由作者提供)

最后,在执行完成后,您应该会看到所有任务周围有一个深绿色的边框,就像下图所示:

图 6 —成功的 DAG 执行(作者提供的图片)

不仅如此,你还可以在右上角看到“成功”的信息。

问题仍然存在— 我们如何验证 DAG 执行是否成功?嗯,很容易。如果您还记得代码,CSV 文件应该保存在data文件夹中。

这是它在我的机器上的样子:

图 7 —保存的 CSV 文件(作者提供的图片)

这就是你的第一条有气流的狗。我希望这很容易理解。让我们在下一部分总结一下。

结论

正如您今天所看到的,Apache Airflow 对于基本的 ETL 管道实现来说非常容易。我们已经完成了最常见的PythonOperator,现在您知道如何在 DAG 任务中运行任何 Python 函数。

您还知道如何使用 XCOMs 在任务之间传输数据——这是 Airflow 中的一个必须知道的概念。

还有很多东西需要学习,所以如果您想了解数据库连接如何与 Airflow 一起工作,请继续关注。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

了解更多信息

保持联系

Python 中的主类继承

原文:https://towardsdatascience.com/master-class-inheritance-in-python-c46bfda63374?source=collection_archive---------4-----------------------

使用直观的例子理解 Python 继承

David WirzbaUnsplash 上拍摄的照片

类和对象在 Python 中起着核心作用。每次你给一个变量赋值,你都在无意识地创建一个对象。这个对象属于一个特定的类,拥有特定的属性和方法。这些特征在之前的文章中有所涉及,在那篇文章中我提供了 Python 中类的快速概述。

但是 python 类不仅仅局限于这一方面,它们还具有继承的特征。继承的目标是重用一个已经构建好的类来创建一个新的类。通过这种方式,你不需要总是从头开始创建一个类,这个被称为子类的类将从另一个类父类继承属性和方法,这允许你减少代码行和冗余。

1.创建父类

作者插图

如前所述,子类基于父类。因此,第一步是创建父类。这个类将允许创建一个子类,避免编写相同的代码行。

例如,让我们定义一个medium_user类,它将使用__init__方法收集姓名、姓氏、用户名、电子邮件和布尔属性“subscriber”等信息,以检查用户是否是成员。而且有readclapis_member三种方法。

我们使用medium_user类创建一个对象,并执行所有的方法:

很好!我们定义了一个 medium 用户,它在 Medium 上没有任何订阅。但是在本例中,我们有一个中等会员,仍然缺少属性,比如他开始订阅的日期、会员类型和支付方式。要添加这些信息,我们需要定义子类。

2.创建子类

让我们构建medium_subscriber类,它将获得前面定义的medium_user类的属性和方法。为了逐步理解类继承是如何工作的,我们可以创建一个空类,简单地继承其他类的功能。

为了不添加任何属性或方法,使用了pass关键字。我们只指定了medium_subscriber类是medium_user类的子类。

和以前一样,我们构建了一个属于medium_subscriber类的新对象。如果我们尝试打印为medium_user类定义的属性和方法,我们肯定会注意到medium_subscriber继承了父类的所有功能。

3.使用 super()函数

在上一段中,我们只定义了一个空类,它继承了另一个类的属性和方法。但是我们想通过__init__构造函数方法添加属性。

medium_subscriber类也需要super()函数来继承父类的功能,否则,子类的构造函数方法会覆盖对父类__init__方法的继承。

首先,让我们在不使用 super()函数的情况下,看看它是如何工作的:

您可以观察到medium_subscriber类没有从medium_user类继承任何属性或方法。我们需要在__init__函数中使用super()函数添加一行代码。

现在,我们正确地添加了属性,而没有丢失父类的特征。首先,我们对medium_subscriber类说从另一个类获取属性和方法,然后,我们添加属性,比如他开始订阅的日期、成员类型和支付方式。

这个解决方案还有一个替代方案。您可以调用父级的__init__函数,来代替带有super()函数的行。是评论行,medium_user.__init__(self,s_name,s_surname,s_username,s_email)。通常最好使用super()函数来避免写入父类的名称。

最后的想法

这篇文章很好地总结了 Python 类中继承的概念。它提供了可重用性、可读性和冗余代码的减少。由于这些优点,它被广泛用于定义类。根据我的经验,我在使用 Pytorch 定义神经网络架构时遇到过这种情况。你可以在这里找到一个例子,我在这里建立了一个卷积自动编码器。在这种情况下,nn.Module是父类,它提供了构建 autoencoder 类的所有构件,比如线性层、卷积层、激活函数等等。我希望这篇文章对你有用。感谢阅读。祝您愉快!

你喜欢我的文章吗? 成为会员 每天无限获取数据科学新帖!这是一种间接的支持我的方式,不会给你带来任何额外的费用。如果您已经是会员, 订阅 每当我发布新的数据科学和 python 指南时,您都会收到电子邮件!

主数据管理早餐吃 AI,还是吃?

原文:https://towardsdatascience.com/master-data-management-eats-ai-for-breakfast-or-does-it-e053fcadad6?source=collection_archive---------29-----------------------

在福布斯上一篇广为流传和讨论的文章中,联合利华全球技术策略师纳兰·斯里拉姆(Nallan Sriram)为企业人工智能计划对主数据的需求提出了令人信服的论点。文章描述了主数据被孤立在 ERP 等运营系统中,当面临收入损失或运营费用增加时,关键决策者意识到需要正确的主数据。由于主数据为业务交易提供了背景,因此它是业务运营的基础。在早期,我们可以通过人工干预来管理主数据。但现在,随着云数据湖的出现,以及我们为业务运营和运营构建预测算法的愿望,对干净、有关联和统一的主数据的需求更加强烈。

机器学习从根本上取决于输入和训练数据的质量,如果基础主数据不干净,企业就不可能从 ML 中获取价值。为了确保主数据中存在适当的链接和关系,文章建议通过以下方式关注关键实体,如客户主数据、供应商主数据、产品主数据、供应主数据和员工主数据

  • 改进新客户和供应商入职的流程和控制
  • 通过外部来源丰富和验证数据
  • 改进运营和技术,以建立客户、供应商和产品之间的关系

随着企业的数字化转型、自动化和机器学习的采用,主数据变得更加重要。主数据肯定能把 AI 当早餐吃!然而,我们想在此补充几点。

传统的主数据应用程序无法满足现代转型企业的需求,这些企业希望通过利用数据来提升其运营。尽管旧的主数据技术有望打破数据孤岛,但它却饱受长配置周期、复杂部署以及硬编码规则的困扰,这使得添加新数据源以及基础应用程序使用主数据都变得非常麻烦。以地址数据为例。我们需要无可挑剔的地址数据来满足法律、合规和邮政要求。然而,对于也以数字方式提供服务的网络商店,地址数据可能是也可能不是强制性的,因为业务不需要它。为了在 ERP、合同、基于产品和其他应用程序系统之间建立联系,传统的 MDM 强制使用严格的地址结构,底层应用程序必须适应这种结构,即使它们需要或不需要。这导致 MDM 所有者和运营团队之间的大量协调,运营团队拥有客户旅程和主数据的一部分。这种跨部门的变更管理是乏味的、耗时的,也是不必要的。相反,如果我们有强大的算法,可以将带有变量的自由形式地址与结构化地址数据进行匹配,我们就不需要底层数据源和所有者付出这么多努力。如果我们仔细观察一下,为了能够匹配和链接源数据而对源数据进行的大量规范化和标准化是一种浪费,特别是当源系统不需要这种格式或具有这些属性的数据时。

有一个黄金记录的想法,即使消费应用程序实际上不能处理该记录的长度或字段,是遗留 MDM 在源系统上强加不必要的更改或过程的另一个例子。相反,主数据的上下文视图,交付企业系统可消费的高质量主数据,既实用又必要。

流程和部门间协作是经营成功企业的关键,但这些应该由业务驱动,而不是源于我们采用的系统的技术限制。为了帮助我们实现业务目标并充分利用 AI/ML,我们的主数据管理系统需要与时俱进并适应,在核心主流程中利用 AI。人工智能对于我们需要管理和掌握的大量和各种数据来说是不可或缺的。由 AI/ML 推动的敏捷数据控制可以为我们的预测分析之旅的平稳行驶和投资回报做好准备。It 不能只作为所掌握数据的消费者而停留在最后一个环节。它必须是我们数据管理和数据控制过程的润滑油。

Python 中的主数据结构字典从零到英雄,第 2 部分

原文:https://towardsdatascience.com/master-data-type-dictionary-in-python-from-zero-to-hero-part-2-6513aad883de?source=collection_archive---------20-----------------------

数据结构和算法

LeetCode 助你获得高薪数据科学职位

路易斯·基根在 Unsplash 上的照片

介绍

Python 是一种流行的脚本编程语言,它提供了各种数据结构,包括数组集合堆栈字符串字典等。它们拥有独特的特征,服务于不同的目标。因此,我们应该选择最符合我们需求的数据类型。

像 Javascript 和其他语言一样,Python 也提供散列表来存储由散列函数生成的数据元素的索引值。因此,当键值成为值的索引或标识符时,它使得数据访问和检索更快。概括地说,我们必须遍历整个数组/列表来访问元素,这对于大型列表来说可能很耗时。

在之前的博客文章中,我们已经讨论了字典的基础及其应用。在今天的帖子中,我们将深入探讨这个话题,并回答 5 个由主要技术人员提出的真实面试问题。

对于我的数据科学家同事来说,如果你正在准备数据相关的面试,这是必读的。

让我们回顾一下:Python 中的字典有三个主要特征。

#1 字典没有排序,所以我们不能用位置来访问元素;相反,我们必须使用键值对。

ictionary 是可变的,这允许我们更新它的元素。

#3 不允许重复键。

为了从字典中检索键、值和键值对,我们分别使用以下命令:

字典 _1.keys()

dictionary_1.values()

dictionary_1.items()

这些命令是构建模块,在我们试图回答更复杂的面试问题时会派上用场。

如何参与这篇博文?

对于我所有的编程帖子,我都花了很多时间从几十个面试问题池中精心挑选问题,根据难度级别对它们进行排序,并撰写专门为数据科学家量身定制的详细答案。

如果可能的话,我建议你先按现在的顺序阅读这篇文章,然后暂停一分钟,思考你将如何处理这个问题,然后再寻找解决方案。

完整的 Python 代码请参考我的Github

问题 1:计算一致字符串的数量

https://leetcode.com/problems/count-the-number-of-consistent-strings/

-给你一个允许的字符串,由不同的字符和一组字符串单词组成。如果字符串中的所有字符都出现在允许的字符串中,则该字符串是一致的。

-返回数组字中一致字符串的数量。

  • Input: allowed = "ab ",words = ["ad "," bd "," aaab "," baa "," badab"]
    — Output: 2
    —解释:字符串" aaab "和" baa "是一致的,因为它们只包含字符' a '和' b '

走过我的思考

Robinhood 在他们的面试过程中包含了这个问题。

快速翻译一下问题: 数组中有多少字符串同时出现在 允许的 字符串中?

字符串可以包含重复的字符。例如,' aaab '应该被计数,因为两个字符( a '和' b ')都出现在 允许的 字符串中。这是问题的断点。我们可以迭代 数组中的元素,并将其转换为一个集合,不允许重复。然后,统计减少列表中有多少元素( 新增 )还出现在 允许 字符串的另一个循环中。

解决办法

2

外卖食品

  • 一个集合在 Python 中是唯一的。它不允许重复。
  • issubset():当您试图理解两个集合之间的关系时,这很方便。
  • 这里有一个常见的误解:issubset()可以用来测试两个集合之间的关系,正如大多数数据科学家所假设的那样,实际上,它可以测试一个字符串和一个集合之间的关系,如问题 1 所示。

问题 2:一个盒子里的最大球数,微软

https://leetcode.com/problems/maximum-number-of-balls-in-a-box/

-您在一家球厂工作,在那里您有 n 个球,编号从下限到上限(包括上限)(即 n ==上限-下限+ 1),以及从 1 到无穷大的无限多个盒子。你在这个工厂的工作是把每个球放进盒子里,盒子上的数字等于球的数字总和。例如,球号 321 将被放入箱号 3 + 2 + 1 = 6,球号 10 将被放入箱号 1 + 0 = 1。
-给定两个整数 lowLimit 和 highLimit,返回球数最多的盒子中的球数。

  • Input: lowLimit = 1,highLimit = 10
    — Output: 2
    —说明:
    箱号:1 2 3 4 5 6 7 8 9 10 11 …
    球数:2 1 1 1 1 1 1 1 1 1 1 1 0 0…
    —箱号最多,有 2 个球。

走过我的思考

微软包括这个问题。

老实说,这没有任何意义,我花了几分钟才明白要点。快速翻译是合适的。

1.迭代从下限到上限的范围

2.计算每个数字的数字总和

3.统计每个位置出现的次数

在步骤 1 中,我们在 for 循环中迭代范围(下限,上限+1)。注意,我们必须在 highLimit 上加 1 才能包含它;否则,我们排除上界。

在步骤 2 中,我们将元素转换成字符串,并对数字进行迭代。记住,整数对象是不可迭代的,所以要转换成字符串;为了数学计算,把它变回整数。

在第 3 步中,我们创建一个新的字典来存储键-值对:为第一次出现的键-值对赋值 0,为重复出现的键-值对值加 1。

解决办法

2

外卖食品

  • 整数对象是不可迭代的,我们需要把它转换成字符串来访问。
  • 如果需要,将数据类型改回整数以进行数学计算。

安德烈亚斯·古尔霍恩在 Unsplash 上拍摄的照片

问题 3:相对排序数组,由亚马逊

https://leetcode.com/problems/relative-sort-array/

-给定两个数组 arr1 和 arr2,arr2 的元素是不同的,arr2 中的所有元素也在 arr1 中。
-对 arr1 的元素进行排序,使 arr1 中项目的相对顺序与 arr2 中的相同。arr2 中没有出现的元素应该按升序放在 arr1 的末尾。
—例一:
—输入:arr1 = [2,3,1,3,2,4,6,7,9,2,19],arr2 = [2,1,4,3,9,6]
—输出:[2,2,2,1,4,3,3,9,6,7,19]

走过我的思考

亚马逊问这个问题。

这个问题有两个部分。

1.对 arr1 和 arr2 中的共享元素进行排序,并保持 arr1 中的相对顺序。

2.按升序排列不在 arr2 中的元素。

先解决第一部分。保持 arr2 中的原始顺序相对容易,棘手的是有些元素出现不止一次。

怎样才能让这些重复的元素保持原来的顺序呢?

一本字典!

以下是方法。我们对每个元素的出现次数进行计数,并将它们乘以 arr2 中的元素,这允许我们在保持原始顺序的同时对出现次数进行计数。

花一些时间来弄清楚它是可以的,因为这需要我几轮的尝试和错误。

为了解决第二部分,我们对 arr1 中没有出现在 arr2 中的元素进行分组和排序。

最后,结合第 1 部分和第 2 部分的结果,我们就完成了。

解决办法

[2, 2, 2, 1, 4, 3, 3, 9, 6, 7, 19]

外卖食品

  • 理解 extend()和 append()之间的区别。
  • 使用字典存储出现的值。
  • 收藏。Counter()对于计数很有用。

问题 4:在一个数组中找到所有的重复项,脸书、亚马逊和微软

https://leetcode.com/problems/find-all-duplicates-in-an-array/

-给定一个长度为 n 的整数数组 nums,其中 nums 的所有整数都在范围[1,n]内,并且每个整数出现一次或两次,返回出现两次的所有整数的数组。

-您必须编写一个在 O(n)时间内运行的算法,并且只使用常量额外空间。

-输入:nums = [4,3,2,7,8,2,3,1]
-输出:[2,3]

走过我的思考

脸书、亚马逊和微软都包括它。

有两个触发词——一次和两次——我们必须根据它们的出现来选择案例。此外,我们必须在 O(n)时间和恒定的额外空间内完成。**

为了计算出现次数,我们创建了一个包含键值对的字典,并在 nums 数组上迭代它。或者,我们可以使用集合。Counter()来创建键值对。它们产生相同的结果。然后,选择值(即发生次数)等于 2 的事例。

解决办法

**[3, 2]**

外卖食品

  • 了解如何使用字典存储键值对。
  • 如何根据值的出现来选择值。

问题 5: 4Sum II,亚马逊和 Adobe

**https://leetcode.com/problems/4sum-ii/

-给定四个长度均为 n 的整数数组 nums1、nums2、nums3 和 nums4,返回元组(I,j,k,l)的数目,使得:

-0<= i, j, k, l < n
—num S1[I]+num S2[j]+num S3[k]+num S4[l]= = 0

走过我的思考

亚马逊和 Adobe 都问这个问题。

简单翻译一下:我们需要从每个整数数组中挑选一个元素,形成一个总和为 0 的元组。

一种粗暴的强制方法是使用四个嵌套的 for 循环迭代数组,并检查总和是否等于 0。然而,它的时间复杂度将是 O(n⁴)并且不能通过测试运行。

让我们再检查一下这个问题,寻找更好的方法。

我们感兴趣的是元组(I,j,k,l)的个数使得*nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0*.从另一个角度看,方程变成了*nums1[i] + nums2[j] = — (nums3[k] + nums4[l]),*并计算右边有多少对等于左边。

数数有多少对?

听起来很熟悉。

我们可以应用一个字典来存储键值对。

下面是代码分解。

  1. nums1nums2 计算成对和,并将和存储在字典中。第一次为 0,如果已经存在,则递增 1。
  2. 统计 nums3nums4 ( *— (nums3[k] + nums4[l])*)的成对和等于步骤 1 ( *nums1[i] + nums2[j]*)的负和的次数。

解决办法

2

外卖食品

  • 学习如何转换所提的问题,并从不同的角度看待它。
  • 用字典来计算。**

完整的 Python 代码请参考我的Github**

结论

  • 熟能生巧。
  • 在数据科学面试中破解编码问题的最佳方法是理解每一步的逻辑,然后编写代码。
  • 字典不是独立的数据类型;它通常与其他功能相结合。

Medium 最近进化出了它的 作家伙伴计划 ,支持像我这样的普通作家。如果你还不是订户,通过下面的链接注册,我会收到一部分会员费。

**https://leihua-ye.medium.com/membership **

我的数据科学面试顺序:

** </5-python-coding-questions-asked-at-faang-59e6cf5ba2a0>

喜欢读这本书吗?

请在 LinkedInYoutube 上找到我。

还有,看看我其他关于人工智能和机器学习的帖子。**

使用 ggplot2 实现主数据可视化:直方图、条形图和密度图

原文:https://towardsdatascience.com/master-data-visualization-with-ggplot2-histograms-bar-and-density-plots-86c8290c9adc?source=collection_archive---------10-----------------------

动手教程

关于何时以及如何在 R 中使用直方图、条形图和密度图的指南

卢克·切瑟在 Unsplash 上拍摄的照片

这是使用ggplot2包创建数据可视化系列的第二篇文章。教程列表如下:

  1. 散点图和箱线图
  2. 直方图、条形图和密度图
  3. 圆形图(饼图、蜘蛛图和条形图)
  4. 主题():为增加的工作流程创建您自己的主题()

在本文中,我们将介绍直方图、条形图和密度图之间的区别,何时使用它们,以及如何绘制不同的变化。

直方图和柱状图的主要区别在于直方图用于绘制定量变量的频率分布,而柱状图用于绘制分类变量的频率分布。

别浪费时间了,让我们开始吃吧。

数据和包

1995-2021 年间的每周汽油和柴油零售价格数据来自 Kaggle。数据集可以从这里下载。出于绘图目的,仅考虑 A1 汽油价格。通过提取给定价格的年、月和周数据来创建新列。此外,零售价格被分类为低、中、高和极限,并被分配给Price变量。另一个创建的变量是Half_yearly,用于将一年分为两个半年或两个类别进行演示。

除了在本系列的第 1 部分中已经讨论过的套件之外,使用的其他套件有:

:用于处理 R 中的日期和时间

山脊 :用于绘制密度山脊图

直方图

我们将使用geom_histogram()函数绘制直方图。直方图用于绘制连续的单个变量。基本上,直方图所做的是绘制变量在数据中出现的频率。

现在,让我们从绘制 1995-2021 年的汽油价格开始。因此,根据数据分布,可以调整仓。通过调整仓,我们划分 x 轴间隔大小。默认情况下,geom_histogram()中的bins值为 30。在下图中,我们绘制了 10、30 和 50 这三种不同箱子尺寸的数据。通过更改框的大小,x 轴间隔会发生变化。随着条柱数量的增加,x-间隔值不断变小,这从条柱的厚度可以明显看出。

作者图片

直方图的另一种变化是显示重叠。这可以通过两种方式实现。第一种是在母数据上重叠数据子集。在本例中,我们重叠了前一年的数据,并将其与 20 多年来的汽油总价格分布进行比较。这是通过在使用subset对数据进行子集化后向直方图添加层来实现的。假设我们想要比较 2 个不同年份的值与总分布,然后我们添加 3 层直方图。附加直方图的数据作为母数据的子集。在下图中,我们比较了 1995 年和 2020 年的价格分布。这张图清楚地显示了总量的分布情况以及汽油价格的变化,因此比较起来很容易。

作者图片

重叠直方图的第二种可能性是当数据集被分段时。如下例所示,通过在geom_histogram()中添加position = “identity”参数,堆叠直方图转换为重叠直方图,如下图所示。在比较这两个图时,可以看到重叠区域中计数的变化,因为之前堆叠的数据由于聚合而具有更高的计数,但是在第二个图中不是这种情况,因为数据现在彼此重叠,并且给出了半年数据如何比较的更好的图像。

默认绘图(左),position=" identity "(右)(图片由作者提供)

密度图

密度图表示数值变量的分布。使用geom_density() 功能绘制。它可以单独绘制,也可以通过添加图层叠加在直方图上。为了在直方图上重叠密度图,我们必须将aes(y=..density..)定义为geom_histogram()函数的参数。线条粗细或线条类型可由geom_density()函数中的以下参数控制:分别为sizelinetype

作者图片

频率图

像密度图一样,我们可以使用频率图。两者的区别在于,频率图连接直方图的计数,而密度图谈论分布。我们使用geom_frequency()功能进行绘图。

作者图片

条形图

条形图用于比较分类数据的性能。因此,为了使给定的数据分类,我们将汽油价格分为 4 个不同的类别,即低、中、高和极端价格范围。我们使用geom_bar()功能进行绘图。geom_bar()函数中的一个关键参数是stat=”identity”。还有另一个有趣的论点是positionposition参数告诉分类数据的条形如何排列。position参数的默认值将条形堆叠在一起,y 轴值是总的聚合值。当position=fill时,对百分比份额进行堆叠,y 轴的最大值为 1 或 100%。如果是position=dodge,则如half_yearly的数据所示,水平堆叠。

默认绘图(图片由作者提供)

位置=填充(图片由作者提供)

position =道奇(图片由作者提供)

密度脊线图

所有图中最后也是最有趣的是密度脊线图。这些图是沿 y 轴堆叠的密度图的延伸。它们在理解随时间和空间发生的变化时提供了视觉清晰度。geom_density_ridges()功能来自ggridges包。在该图中,我们可以观察到 2020 年不同月份的汽油价格分布。

作者图片

结论

在本文中,我们展示了直方图和条形图之间的区别,图表适用于哪种类型的变量,以及不同的变量。此外,我们还学习了如何构建以下地块:

  1. 直方图
  2. 密度图
  3. 频率图
  4. 条形图
  5. 密度脊线图

我希望这很有见地,在本系列的下一篇文章中,我们将讨论圆形图:饼图、蜘蛛图和条形图。

如果您错过了本系列的第一篇文章,或者对更多关于数据可视化的文章感兴趣,请查看以下内容:

*

完整代码的链接是这里是

您可以在 LinkedInTwitter 上与我联系,跟随我的数据科学和数据可视化之旅。*

使用 ggplot2 实现主数据可视化:饼图、蜘蛛图和条形图

原文:https://towardsdatascience.com/master-data-visualization-with-ggplot2-pie-charts-spider-plots-and-bar-plots-899a07a15827?source=collection_archive---------10-----------------------

关于在 R 中创建饼图、蜘蛛图和圆形条形图的指南

谢里·西尔弗Unsplash 上的照片

在使用 ggplot2 的数据可视化系列的第三部分中,我们将关注圆形图。教程列表如下:

  1. 散点图和箱线图
  2. 直方图、条形图和密度图
  3. 圆形图(饼图、蜘蛛图和条形图)
  4. 主题():为增加的工作流程创建您自己的主题()

因此,在循环可视化下,我们将介绍如何创建以下图表:

  1. 饼图
  2. 蜘蛛图
  3. 圆形条形图

此外,我们将讨论使用这些类型的可视化的利弊。

权力越大,责任越大,明智地使用饼状图和蜘蛛图。

数据和包

为了创建圆形图的视觉效果,我们将使用 Kaggle 的早餐谷物数据集。该数据集有 16 个领域的 77 种独特的谷物类型。

我们将创建两个新变量:manufacture(包含不同谷物制造商的数量)和谷类 _ 麸皮 _ 低(卡路里值在 80 到 120 之间的选定麸皮谷类品牌的过滤营养数据)。

在本系列的第三部分,像往常一样,我们将使用广泛使用的基本包ggplot2tidyverse。除此之外,对于绘制蜘蛛或雷达图,将使用ggradar包。

饼图

为了创建饼图,我们将使用manufact变量。虽然 R 中的基本绘图有pie()功能,但是ggplot2包中没有定义创建饼图的功能。为了让我们使用 ggplot2 绘制饼图,我们将使用geom_bar()coord_polar()函数来创建圆的线段。coord_polar()功能将笛卡尔坐标转换到极坐标系统,这样很容易创建圆形图。在coord_polar()函数中,ggplot()美学的 x 参数被指定为x=“ ”,而theta参数被指定为y值。

将条形图转换为饼图,在 ***geom_bar()*** 中设置 ***stat=“identity”*** ,并固定 ***width=1***

优点:比较少量数据点时有用。

缺点:难以解释大型数据集,难以描绘长期趋势

作者图片

饼图的修改导致了圆环图。可以通过控制ggplot()美学的 x 参数来控制甜甜圈的大小和厚度。 确保 x 参数的值位于 xlim 范围之间。

作者图片

靶心图

为了创建圆形条形图,在geom_bar()功能中设置参数stat=“identity”。径向向外时,确保按长度递增的顺序排列钢筋。用于将条形图转换为圆形方向,在coord_polar()功能中设置参数theta=“y”。如果彩条完成了一个完整的回合,那么图表将像一个靶心,因此得名。

作者图片

统计图

简单地改变靶心图中的单个参数会导致鸡冠图。如果在coord_polar()函数中theta=“y”变成了theta=“x”,我们得到的不是赋值theta=“y”,而是统计图。

作者图片

蜘蛛图

目前,ggplot2包中没有创建蜘蛛图或雷达图的功能。ggradar包与ggplot2包兼容,可用于创建蜘蛛图。在 ggradar()函数中,与在 ggplot()函数中一样,可以定义美学。需要的几个重要参数是:

values.radar :打印圆形网格线的最小值、中间值和最大值。

grid.min :网格的最小值

grid.mid :网格的中间值

grid.max :网格的最大值

优点:如果所有变量都有相同的尺度,就容易理解了。

缺点:刻度单位不同时比较困难,圆形图解释困难。

作者图片

绘制所有图表的完整代码。

结论

因此,在本教程中,我们看到了如何创建饼图,蜘蛛图,鸡冠图,牛眼图。确定了如何通过改变ggplot()函数或geom_bar()函数中的几个参数,将饼图轻松转换为除蜘蛛图之外的其他图表类型。我们进一步讨论了使用圆形图表类型(尤其是流行的饼图和蜘蛛图)的利与弊,并看到通常不鼓励使用这些图表,而是使用易于理解和解释的替代图表。

本系列或使用ggplot2包的可视化的进一步阅读。

参考

  1. https://www.kaggle.com/crawford/80-cereals
  2. https://blog . Scott logic . com/2011/09/23/a-critical-of-radar-charts . html # chart 2
  3. https://www.data-to-viz.com/caveat/spider.html

完整代码的链接是这里的。

您可以在 LinkedInTwitter 上与我联系,跟随我的数据科学和数据可视化之旅。

使用 ggplot2 的主数据可视化:散点图和箱线图

原文:https://towardsdatascience.com/master-data-visualization-with-ggplot2-scatter-and-box-plots-2f0c14cf2b26?source=collection_archive---------17-----------------------

实践教程

使用散点图和箱线图的数据可视化指南

照片由 Myriam JessierUnsplash 上拍摄

关注仪表板或数据可视化的用户天生依赖于ggplot2包。它是基于图形语法绘制数据的通用软件包。其背后的想法是使用美学、比例和层次等语义来构建可视化。

这里有一个 goto 教程系列,适合那些在手头时间有限的情况下寻找快速解决方案来完善其可视化效果的人。这是一个由四部分组成的系列,讨论如何使用ggplot2包和其他附加包绘制不同风格的图。这些教程如下:

  1. 散点图和箱线图
  2. 条形图、直方图和密度图
  3. 圆形图(饼图、蜘蛛图和条形图)
  4. 主题():为增加的工作流程创建您自己的主题()

在本教程中,我们将创建散点图和箱形图。在本教程之后,你将能够做出更好的可视化效果,如下所示。

学习从默认情节创建有效的可视化(图片由作者提供)

数据集和包

在本教程中,我们将使用大多数国家 1961 年至 2019 年间记录的全球温度变化。数据集可以从这里下载。目前,我们将关注发生在印度的温度变化。

本教程使用的包有:

tidyverse:用于为绘图目的以正确格式获取数据集的所有操作

ggplot2:用于绘制数据

ggforce:利用数据的密度分布控制抖动的宽度

patchwork:将不同的地块组合成一幅图像

一旦根据要求加载了包并处理了数据,我们就可以创建我们的第一个图了。我们将从散点图开始,然后转到箱线图。

散点图

这是做 EDA 时最受欢迎的 goto 图之一。这些图用来显示多个变量之间的关系。在下图中,顶部的图是默认的散点图,只使用了geom_point(),没有任何美感或附加层。

作者图片

因此,为了增加散点图的价值,我们在轴上添加了标题、副标题、题注、标题。对上述图的进一步补充是给数据添加一条拟合线,使其更有意义。拟合提供了更多的信息,给出了趋势的概述和变量之间的相关性。我们给数据添加了一个线性拟合,显示了多年来气温上升的积极趋势。通过将所有这些特征添加到上面的散点图中,我们使它更加不言自明。

有时数据的行为更复杂,在这种情况下,线性拟合不是一个选项。对于这些类型的情况,我们可以使用默认的平滑函数或定义我们自己的函数。

下面我们可以看到三个图,左边的一个使用默认的geom_smooth()函数,中间的一个使用线性拟合,最右边的使用用户定义的函数。

默认情况下,stat_smooth 或 geom_smooth 使用黄土(如果数据点少于 1000)或 GAM(如果数据点多于 1000)函数进行拟合。

从左到右:默认平滑、线性拟合、用户定义函数(图片由作者提供)

箱形图

当一个实验进行了很多次,并且想要了解结果的统计意义时,箱线图是相关的。它提供了关于四分位数(25%、50%或平均值和 75%)、四分位数间、标准差和异常值的信息。

我们将geom_boxplot()添加到默认的ggplot()层。然后我们添加geom_ jitter()层来添加数据点,并进一步添加来自ggforce封装的geom_sina()来控制抖动的宽度。geom_boxplot()美学中的colfill被定义为对月份进行颜色编码。

l 到 R:默认剧情,提升审美,增加主题(图片由作者提供)

通过增加数据点的透明度,强调数据分布,尤其是重叠的数据分布,可以进一步改善上述图。这是通过在geom_boxplot()中定义alpha实现的。alpha值的范围在(0,1)之间,其中 1 表示 100%透明。

使用geom_violin()功能可以使情节生动活泼。盒子情节的一个美学上令人愉快的变化是小提琴情节。

作者图片

如果我们比较小提琴图和盒子图,我们会看到轴旋转了两种情况。这通过coord_flip()功能实现。通过翻转轴,月份的顺序颠倒,为了使它回到日历中月份的自然顺序,我们使用了scale_x_discrete(limits = rev)

如果我们看上面的小提琴图,我们会发现它在视觉上很吸引人,但与盒子图相比,它缺少信息。要使小提琴情节像盒子情节一样信息量大而又不失魅力,可以借助图层。这就是ggplot2包装的美妙之处,可以添加任意层数。因此,通过添加箱线图层,我们向 violin 图添加了四分位数、标准差和异常值的信息,如下所示。

作者图片

geom_boxplot()功能中定义的coef变量定义了标准差臂的长度,默认值为 1.5。

结论

我们讨论了散点图和箱线图,并展示了如何通过添加图层和美学来大幅提高图的质量。通过增加信息含量,提高了地块的质量。添加了两种类型的信息:一种以平滑拟合的形式为图添加含义,另一种是描述性的,如添加轴标题、图标题和副标题,以及添加图形标题。

在下一篇文章中,我们将讨论条形图、直方图和密度图。

进一步阅读:

完整代码的链接是这里的。

您可以在 LinkedInTwitter 上与我联系,跟随我的数据科学和数据可视化之旅。

使用 ggplot2: theme()定制的主数据可视化

原文:https://towardsdatascience.com/master-data-visualization-with-ggplot2-theme-customization-8421695d24e2?source=collection_archive---------35-----------------------

自定义 ggplot2 主题,为高效工作流程创建您的个性化主题模板

Unsplash 上的 CHUTTERSNAP 拍照

这是使用ggplot2包掌握数据可视化系列的最后一篇文章。教程的完整列表如下:

  1. 散点图和盒状图( 链接 )
  2. 直方图、条形图和密度图( 链接 )
  3. 圆形图(饼图、蜘蛛图和条形图)( 链接 )
  4. 主题() : 自定义增加工作流

对于那些经常更改默认主题设置以使其可视化效果更具吸引力的人来说,主题定制是提高工作效率的关键。ggplot2包使用的默认主题是theme_gray()。因此,在本教程中,我们将使用theme_gray()函数来创建我们自己的定制函数theme_customized()。我们将把本教程分为以下几个部分:

  1. 数据集和包
  2. 提取主题函数
  3. 自定义主题功能
  4. 覆盖某些参数

作者图片

数据集和包

在本教程中,我们将使用地球表面温度数据集,重点关注 1750 年至 2015 年间的全球温度变化。数据集的链接在这里是。

我们将使用lubridate包来创建包含年和月信息的新变量。

除了ggplot2tidyverselubridate包,我们将使用extrafont包从我们的操作系统导入更多的字体到 R 中。因为我是一个 Windows 用户,所以争论将与 Windows 操作系统有关。查看使用 Apple 或 Linux 系统安装的参考。

因此,现在让我们开始定制主题,这将通过提取默认主题函数的源代码来完成。

提取主题函数

要获得 R 中函数的源代码,只需在 R 控制台中键入函数名,然后按 enter 键。这样,它将为您提供完整的代码。在我们的例子中,我们将使用theme_gray(),所以我们可以在控制台上运行theme_gray,我们将得到完整的源代码,如下所示。

我们将使用上述代码来创建我们的定制功能。在进一步定制之前,我们将去掉最后一个命令ggplot_global$theme…

自定义主题

在默认主题中可以定制很多东西,但目前,我们将专注于几个关键的东西。请随意探索其他可能性。

字体

R 中可用的默认字体系列有 sansserifmonosymbol 。如果你想在 R 中现有的字体中添加更多的字体系列,那么可以通过extrafont包来实现。使用下面的代码片段将字体添加到 R 中,以便在 Windows OS 中进行自定义。

要指定你选择的字体,只需在调用函数时在函数参数中声明即可。出于演示的目的,我指定了base_family=“Algerian”

theme_customized <- function(base_size=11, base_family = "Agerian", 
                             base_line_size = base_size/22, 
                             base_rect_size = base_size/22)

颜色;色彩;色调

也可以通过指定新颜色来覆盖默认颜色。例如,通过提供不同的fill值,绘图面板的背景颜色可从white变为不同的颜色,如下所示:

rect = element_rect(fill = "**white**", colour = "black", size = 0.5, linetype = 1)# replace plot panel background color to red
rect = element_rect(fill = "**red**", colour = "black", size = 0.5, linetype = 1)

使用element_text()功能中的color参数可以改变轴标题的字体颜色。

text = element_text(family = base_family, face = "plain", 
                    colour = "**black**", size = base_size, lineheight =
                    0.9, hjust = 0.5, vjust = 0.5, angle = 0, margin
                    = margin(), debug = FALSE)

可使用以下功能改变轴文本和刻度的颜色:

# axis text
axis.text = element_text(size = rel(0.8), colour = "grey30")# axis ticks
axis.ticks = element_line(colour = "grey20")

字体大小

theme_gray()的默认字体大小是 11,这对于某些显示媒体来说可能不合适。因此,可以通过将默认值分配给主题函数的base_size参数,将其更改为更理想的值。

theme_customized <- function(base_size=11, base_family = "Agerian", 
                             base_line_size = base_size/22, 
                             base_rect_size = base_size/22)

另一个需要注意的重要特性是rel()函数,它定义了相对于base_size值的相对大小。

所以,让我们自定义主题。

现在,我们知道如何在 r 中自定义主题。现在让我们通过可视化 1750 年至 2015 年期间的月平均温度变化来将其付诸实践。

那么对于当前定制的主题,让我们将base_size值设置为 15,阿尔及利亚,并更改配色方案,使用 Canva 的配色方案。

为了覆盖ggplot2的默认主题,我们将使用theme_set()函数,这样我们就可以实现theme_customized()

# overriding teh default theme
theme_set(theme_customized()) 

现在我们可以用新的定制主题重新绘制平均温度变化。

使用(L)默认主题和(R)自定义主题绘制(图片由作者提供)

覆盖某些参数

为了快速改变主题,我们将使用theme_update()功能。假设我们想在自定义主题中使用黑色而不是灰色的面板网格,那么我们只需要覆盖element_line()函数的值。

theme_customized = theme_update(panel.grid = element_line(colour = "black"))

仅将面板网格颜色从灰色覆盖为黑色(图片由作者提供)

结论

在关于使用 ggplot2 包掌握数据可视化的最后一个教程中,我们学习了定制我们自己的主题,这无疑可以提高工作流程,特别是如果您的工作涉及为需要不同颜色主题、字体类型和大小的不同部门创建视觉效果。除了定制你的主题,我们还进一步学习了使用set_theme()函数覆盖默认主题。后来我们看到,要在定制主题中做一些小的改变,我们可以直接使用theme_update()函数来改变 ceratin 函数参数的值,而不需要重新访问整个函数。

我希望你们都喜欢这个用ggplot2包设计的系列。如果你错过了这个系列的任何教程,链接就贴在下面。欢迎发表评论,分享你的观点和看法。

本系列或使用ggplot2包的可视化的进一步阅读。

参考

  1. https://cran . r-project . org/web/packages/svglite/vignettes/fonts . html
  2. https://r-coder.com/custom-fonts-r/
  3. https://ggplot2.tidyverse.org/reference/theme_get.html

完整代码的链接在这里是。

您可以在 LinkedInTwitter 上与我联系,跟随我的数据科学和数据可视化之旅。

机器学习大师:用 Python 从头开始做决策树

原文:https://towardsdatascience.com/master-machine-learning-decision-trees-from-scratch-with-python-de75b0494bcd?source=collection_archive---------7-----------------------

机器学习既简单又直观——这里有一个完整的从头开始的决策树指南

加里·本迪格在 Unsplash 上的照片

决策树是用于分类和回归的最直观的机器学习算法之一。阅读之后,你将知道如何完全从头开始实现一个决策树分类器。

这是许多即将开始的文章中的第五篇,所以如果你想了解更多,请继续关注这个博客。之前文章的链接位于本文末尾。

这篇文章的结构如下:

  • 决策树介绍
  • 决策树背后的数学
  • 递归速成班
  • 从头开始实施
  • 模型评估
  • 与 Scikit-Learn 的比较
  • 结论

你可以在这里下载相应的笔记本

决策树介绍

决策树是一种用于回归和分类任务的非参数模型。从头开始的实现将花费您一些时间来完全理解,但是算法背后的直觉是非常简单的。

决策树仅由两个元素构成——节点和分支。我们稍后将讨论不同类型的节点。如果你决定跟随,术语递归不应该感觉像一门外语,因为算法是基于这个概念。几分钟后你会得到一个递归的速成课程,所以如果你对这个话题有点生疏,不要着急。

让我们先来看一个决策树的例子:

图 1 —带有节点类型的决策树表示示例(作者图片)

如您所见,有多种类型的节点:

  • 根节点 —树顶端的节点。它包含一个能最好地分割数据的特征(一个能最准确地对目标变量进行分类的单一特征)
  • 决策节点 —评估变量的节点。这些节点有指向它们和远离它们的箭头
  • 叶节点 —进行预测的最终节点

根据数据集的大小(行和列),可能有成千上万种方式来排列节点及其条件。那么,我们如何确定根节点呢?

如何确定根节点

简而言之,我们需要检查每个输入特征如何独立地对目标变量进行分类。如果没有一个单独的特征在分类中 100%正确,我们可以认为这些特征不纯

为了进一步确定哪个不纯的特征是最纯的,我们可以使用度量。我们稍后将讨论公式和计算,但是您应该记住熵值的范围是从 0(最好)到 1(最差)。

然后,具有最低熵的变量被用作根节点。

培训过程

为了开始训练决策树分类器,我们必须确定根节点。那部分已经讨论过了。

然后,对于每个单独的分割,计算信息增益度量。简而言之,它表示基于特定分割的所有熵值的平均值。我们稍后将讨论公式和计算,但请记住,增益越高,决策分割越好。

然后,该算法执行贪婪搜索-检查所有输入要素及其唯一值,计算每个组合的信息增益,并保存每个结点的最佳分割要素和阈值。

以这种方式,树被递归地构建。递归过程可能会永远继续下去,所以我们必须手动指定一些退出条件。最常见的是节点处的最大深度和最小样本。这两者都将在后面的实现中讨论。

预测过程

一旦构建了树,我们就可以通过递归遍历树来预测看不见的数据。我们可以根据输入数据和每个节点的学习阈值来检查遍历方向(左或右)。

一旦到达叶节点,就返回最常见的值。

这就是决策树背后的基本理论和直觉。让我们在下一节讨论算法背后的数学。

决策树背后的数学

决策树代表的更多的是编码挑战,而不是数学挑战。对于学习部分,你只需要实现两个公式——熵和信息增益。

先说。如前所述,它在节点级别测量分裂的纯度。其值范围从 0(纯)到 1(不纯)。

这是熵的公式:

图 2 —熵公式(图片由作者提供)

正如你所看到的,这是一个相对简单的等式,所以让我们看看它的实际应用。假设你想计算以下向量的纯度:

图片 3 —熵输入(图片由作者提供)

总而言之,零和一是具有以下计数的分类标签:

图 4 —班级分布汇总(作者提供的图片)

从这一点来看,熵的计算非常简单(四舍五入到小数点后五位):

图 5 —熵计算(图片由作者提供)

0.88 的结果表明分裂远非纯粹。接下来我们用 Python 重复一下计算。以下代码实现了entropy(s)公式,并在同一个向量上计算它:

结果如下图所示:

图 Python 中的熵计算(图片由作者提供)

正如您所看到的,结果是相同的,表明公式实现正确。

接下来让我们看看信息增益。它表示基于特定分割的所有熵值的平均值。信息增益值越高,决策分裂越好。

信息增益可通过以下公式计算:

图 7 —信息增益公式(图片由作者提供)

让我们来看一个示例分割,并计算信息增益:

图 8 —信息增益计算的分割示例(图片由作者提供)

如你所见,熵值是事先计算好的,所以我们不必在它们上面浪费时间。计算信息增益现在是一个简单的过程:

图 9 —信息增益计算(图片由作者提供)

接下来让我们用 Python 实现它。下面的代码片段实现了information_gain()函数,并为之前讨论的分割计算了它:

结果如下图所示:

图 10-Python 中的信息增益计算(图片由作者提供)

如您所见,这些值是匹配的。

这就是决策树背后的数学。我再重复一遍——这个算法用代码实现比用数学方法理解更具挑战性。这就是为什么你需要额外的递归入门——接下来。

递归速成班

许多关于决策树的实现归结为递归。本节将简要介绍递归函数,但绝不是该主题的入门指南。如果这个术语对你来说是新的,如果你想理解决策树,请研究它。

简单来说,递归函数就是调用自身的函数。我们不希望这个过程无限期地进行下去,所以函数需要一个退出条件。你会发现它写在函数的顶部。

让我们来看看最简单的例子——一个返回整数阶乘的递归函数:

结果如下图所示:

图 11-Python 中的阶乘计算(图片由作者提供)

如您所见,该函数会调用自身,直到输入的数字不是 1。这就是我们函数的退出条件。

决策树分类器中需要递归来建立额外的节点,直到满足某些退出条件。这就是为什么理解这个概念至关重要。

接下来,我们将实现分类器。这将需要大约 200 行代码(减去文档字符串和注释),所以拥抱你自己。

从头开始实施

我们需要两节课:

  1. Node–实现决策树的单个节点
  2. DecisionTree–实现算法

先说Node类。它在这里存储关于特征、阈值、向左和向右的数据、信息增益和叶节点值的数据。所有的初始设置都是None。根节点和决策节点将包含除叶节点值之外的所有值,而叶节点将包含相反的值。

下面是该类的代码:

那是容易的部分。接下来让我们实现分类器。它将包含许多方法,所有这些方法都将在下面讨论:

  • __init__()–构造器,保存min_samples_splitmax_depth的值。这些是超参数。第一个用于指定分割节点所需的最小样本数,第二个指定树的最大深度。两者都在递归函数中用作退出条件
  • _entropy(s)–计算输入向量的杂质s
  • _information_gain(parent, left_child, right_child)计算父节点和两个子节点之间拆分的信息增益值
  • _best_split(X, y)函数计算输入特征X和目标变量y的最佳分割参数。它通过迭代X中的每一列和每一列中的每个阈值来使用信息增益找到最佳分割
  • _build(X, y, depth)函数递归构建决策树,直到满足停止标准(构造函数中的超参数)
  • fit(X, y)函数调用_build()函数并将构建的树存储到构造函数中
  • _predict(x)函数遍历树来分类单个实例
  • predict(X)函数将_predict()函数应用于矩阵X中的每个实例。

这太多了——没什么好争论的。花点时间理解下面代码片段中的每一行。这是有据可查的,所以注释应该会有所帮助:

你不需要一口气理解每一行代码。给它一点时间,一行一行地检查代码,并尝试解释为什么事情会成功。一旦你理解了算法背后的基本直觉,就没那么难了。

模型评估

接下来让我们测试我们的分类器。我们将使用来自 Scikit-Learn 的虹膜数据集。以下代码片段加载数据集,并将其分为要素(X)和目标(y):

接下来,让我们将数据集分成训练和测试部分。以下代码片段就是这样做的,比例为 80:20:

现在让我们开始训练。下面的代码片段使用默认超参数训练模型,并对测试集进行预测:

让我们来看看生成的预测(preds):

图 12 —测试集上的自定义决策树预测(图片由作者提供)

现在看实际的类标签(y_test):

图 13 —测试集类别标签(作者图片)

如您所见,两者完全相同,表明分类器非常准确。如果你愿意,你可以进一步评估性能。下面的代码打印测试集的准确度分数:

正如所料,1.0的值将被打印出来。不要让这个欺骗你——虹膜数据集非常容易正确分类,特别是如果你有一个好的“随机”测试集。不过,让我们将我们的分类器与 Scikit-Learn 内置的分类器进行比较。

与 Scikit-Learn 的比较

我们想知道我们的模型是否好,所以让我们将它与我们知道效果很好的东西——Scikit-Learn 的DecisionTreeClassifier类进行比较。

您可以使用以下代码片段来导入模型类、训练模型、进行预测以及打印准确性得分:

如您所料,我们得到了完美的准确度分数1.0

今天到此为止。让我们在下一部分总结一下。

结论

这是我写过的最具挑战性的文章之一。花了大约一周的时间才把一切都做好,并尽可能让代码易于理解。当然,你至少需要阅读几本书才能完全理解这个话题。请随意探索其他资源,因为这将进一步加深您的理解。

您现在知道如何从头开始实现决策树分类器算法。这是否意味着你应该抛弃事实上的标准机器学习库?不,一点也不。我来详细说明一下。

你能从头开始写东西并不意味着你应该这样做。尽管如此,了解算法如何工作的每个细节是一项有价值的技能,可以帮助你从其他 fit 和预测数据科学家中脱颖而出。

感谢您的阅读,如果您对更多从零开始的机器学习文章感兴趣,请继续关注博客。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

了解更多信息

保持联系

  • 媒体上关注我,了解更多类似的故事
  • 注册我的简讯
  • 在 LinkedIn 上连接
  • 查看我的网站

原载于 2021 年 4 月 8 日 https://betterdatascience.comhttps://betterdatascience.com/mml-decision-trees/

机器学习大师:用 Python 从头开始学习 K 个最近邻

原文:https://towardsdatascience.com/master-machine-learning-k-nearest-neighbors-from-scratch-with-python-5009177f523?source=collection_archive---------24-----------------------

机器学习既简单又直观——这里有一个从头开始的 K 近邻完整指南。

JJ 英Unsplash 上的照片(作者修改)

k 最近邻是最简单的机器学习算法之一,如果不是最简单的话。这是一种分类算法,它基于定义数量的最近实例进行预测。

今天,您将从头开始实施和调整 K 近邻算法。这是第四篇即将发表的文章,所以如果你想了解更多,请继续关注博客。之前文章的链接位于本文末尾。

这篇文章的结构如下:

  • K 近邻介绍
  • 数学落后 K 个最近邻
  • 从头开始实施
  • k 优化
  • 与 Scikit-Learn 的比较
  • 结论

你可以在这里下载相应的笔记本

K 近邻介绍

如前所述,K 近邻是实现起来最简单的机器学习算法之一。其对新实例的分类基于 K 个最近实例的目标标签,其中 K 是可调超参数。

不仅如此,K 还是唯一的强制超参数。根据数据的不同,更改其值可能会导致模型性能的提高或降低。今天,您将学习如何为任何数据集找到最优 K。

该算法最奇怪的地方在于它不需要任何学习——只需要简单的距离计算。距离度量的选择取决于您,但最常见的是欧几里德余弦距离。我们今天将学习欧几里得。

当谈到使用这种算法时,请记住它是基于距离的。正因为如此,在培训前对你的数据进行标准化可能是个好主意。

这就是理论的全部内容。在跳入代码之前,我们先简单谈谈背后的数学。

数学落后 K 个最近邻

距离的计算归结为一个简单的公式。您没有义务使用欧几里得距离,所以请记住这一点。

该距离被计算为两个向量的相应元素之间的平方差的平方根。当然,向量的大小必须相同。公式如下:

图片 1-欧几里德距离公式 v1(图片由作者提供)

该公式可以用更简洁的方式编写,如下所示:

图片 2-欧几里德距离公式 v2(图片由作者提供)

所以要记住这两个意思是一样的。

这就是你需要用 Python 实现的全部逻辑!让我们接下来做那件事。

从头开始实施

让我们从进口开始。我们需要 Numpy、Pandas 和 Scipy 用于逻辑,需要 Matplotlib 用于可视化:

我们现在将声明一个名为KNN的类,记住 Scikit-Learn API 语法。该类将具有以下方法:

  • __init__(k)–构造器,存储邻居数量(默认值为 3)和训练数据的值,初始设置为
  • _euclidean_distance(p, q)–从上面执行公式
  • fit(X, y)–基本上什么都不做,只是将训练数据存储到构造器中
  • predict(X)–计算X中每一行与KNN.X_train中每一行之间的距离(调用fit()后可用)。然后对距离进行排序,只保留前 k 个。然后通过计算统计模式进行分类。

我们实现fit()方法的唯一原因是因为我们希望拥有与 Scikit-Learn 相同的 API。您可以自由地删除它,并在predict()方法中做任何事情。

总之,这是整个类的代码:

接下来我们来测试一下算法。我们将使用来自 Scikit-Learn 的乳腺癌数据集。下面的代码片段加载它,并以 80:20 的比例进行训练/测试分割:

现在让我们“训练”模型并获得预测。您可以使用下面的代码片段来实现这一点:

如果您要打印出preds,您会看到以下内容:

图片 3-预测类(作者图片)

下面是实际的类(y_test):

图 4-实际课程(作者提供的图片)

如您所见,这两个阵列非常相似,但在几个地方有所不同。一个简单的准确度将告诉我们正确分类的实例的百分比:

以下是相应的精确度:

图片 5 — KNN 模型的准确性(图片由作者提供)

93%是我们能得到的最好成绩吗?不太可能。让我们来探索如何调整 K 的值,并在一个范围内找到最佳值。

k 优化

默认的 K 值(3)不太可能是最佳值。幸运的是,这个简单的算法很容易进行超参数优化。我们所要做的就是为一定数量的 K 值训练模型,并选择精度最高的一个。

值得一提的是,应该只测试奇数的 K 值,以避免潜在的联系。

以下代码片段针对 1 到 15 之间的每个奇数评估模型:

让我们想象一下精确度。下面的代码片段绘制了 X 轴上的 K 值和 Y 轴上的相应精度。最优的如题所示:

结果如下:

图片 6-最佳 K 值可视化(图片由作者提供)

k 值为 11 似乎最适合我们的数据集。考虑到这一点,您现在可以重新训练模型(model = KNN(k=11))。

接下来让我们比较一下 Scikit-Learn 模型的性能。

与 Scikit-Learn 的比较

我们想知道我们的模型是否好,所以让我们将它与我们知道效果很好的东西——Scikit-Learn 的KNeighborsClassifier类进行比较。

您可以使用以下代码片段来导入模型类、训练模型、进行预测以及打印准确性得分:

相应的精度如下所示:

图 7-sci kit-学习模型准确性(图片由作者提供)

如您所见,Scikit-Learn 的模型表现大致相同,至少在准确性方面是如此。请记住,我们在这里没有做任何调整,这可能会使准确率达到 98%以上。

今天到此为止。让我们在下一部分总结一下。

结论

今天,您已经完全从头开始学习了如何用 Python 实现 K 近邻。这是否意味着你应该抛弃事实上的标准机器学习库?没有,一点也没有。我来详细说明一下。

你能从头开始写东西并不意味着你应该这样做。尽管如此,了解算法如何工作的每个细节是一项宝贵的技能,可以帮助你从其他 fit 和预测数据科学家中脱颖而出。

感谢您的阅读,如果您对更多从零开始的机器学习文章感兴趣,请继续关注博客。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

了解更多信息

保持联系

原载于 2021 年 3 月 17 日 https://betterdatascience.comhttps://betterdatascience.com/mml-k-nearest-neighbors/

机器学习大师:用 Python 从头开始逻辑回归

原文:https://towardsdatascience.com/master-machine-learning-logistic-regression-from-scratch-with-python-acfe73a0a424?source=collection_archive---------15-----------------------

机器学习既简单又直观——这是一个完整的从头开始的逻辑回归指南

JJ 英Unsplash 上的照片(作者修改)

逻辑回归是你会遇到的最简单的分类算法。它类似于上周探讨的线性回归,但有一点不同。稍后会有更多的介绍。

今天,您将从头开始实施和调整逻辑回归算法。这是许多即将开始的文章中的第三篇,所以如果你想了解更多,请继续关注博客。之前文章的链接位于本文末尾。

这篇文章的结构如下:

  • 逻辑回归介绍
  • 逻辑回归背后的数学
  • 二元交叉熵损失简介
  • 从头开始实施
  • 阈值优化
  • 与 Scikit-Learn 的比较
  • 结论

你可以在这里下载相应的笔记本

逻辑回归介绍

逻辑回归是用于二元分类问题的基本机器学习算法。如今,它通常只用于构建基线模型。尽管如此,这仍然是一个非常好的第一个构建算法,因为它具有高度的可解释性。

在某种程度上,逻辑回归类似于线性回归。我们仍然在处理一个用于预测的直线方程。这一次,结果通过一个 Sigmoid 激活函数将真实值转换成概率。

概率告诉您实例属于正类的机会(例如,该客户的流失概率为 0.85)。然后,根据阈值将这些概率转化为实际类别。如果概率大于阈值,我们指定正类,反之亦然。

阈值值可以(也应该)根据问题和您正在优化的指标类型而改变。

我们来谈谈逻辑回归模型的假设[1]:

  • 观察值(数据点)是独立的
  • 独立变量之间几乎没有多重共线性(检查相关性并移除冗余)
  • 大样本量——至少 10 个案例,每个独立变量都有最不频繁的结果。例如,如果您有五个独立变量,并且最小频率结果的预期概率为 0.1,那么您需要的最小样本量为 500 (10 * 5 / 0.1)

训练逻辑回归模型意味着计算权重和偏差的最佳系数。这些可以通过称为梯度下降的迭代优化过程来计算。下一节将详细介绍这一点。

逻辑回归背后的数学

逻辑回归背后的数学很简单。我们还在处理一个直线方程:

图 1-直线方程公式(图片由作者提供)

但这一次,线方程的输出通过一个 Sigmoid(逻辑)函数传递,如下式所示:

图 2-Sigmoid 函数公式(图片由作者提供)

sigmoid 函数的作用是获取任何实数值,并将其映射到一个概率值,即介于 0 和 1 之间的值。这是一个 S 形函数,您可以使用下面的代码来可视化它:

这是视觉效果:

图 3-Sigmoid 函数(图片由作者提供)

sigmoid 函数返回值被解释为正类的概率。如果概率大于某个阈值(通常为 0.5),我们就指定正类。如果概率低于阈值,我们分配负类。

与线性回归一样,我们需要优化两个参数——权重和偏差。我们需要声明成本函数来执行优化。遗憾的是,我们熟悉的均方误差函数无法使用。嗯,理论上可以用,但不是个好主意。

相反,我们将使用一个二元交叉熵函数,如下式所示:

图片 4 —二元交叉熵损失公式(图片由作者提供)

如果它看起来像外语,请不要担心,我们将在下一部分解释它。

接下来,您需要在优化过程中使用这个成本函数来迭代地更新权重和偏差。为此,您必须计算与权重和偏差参数相关的二元交叉熵函数的偏导数:

图片 5 —二元交叉熵导数(图片由作者提供)

标量可以省略,因为它没有任何区别。接下来,您必须根据更新规则更新现有权重和偏差,如以下公式所示:

图片 6-梯度下降更新规则(图片由作者提供)

alpha 参数代表学习率。整个过程重复所需的迭代次数。

这些都是关于数学的!接下来我们来看看二元交叉熵损失函数。

二元交叉熵损失简介

二元交叉熵是用于评估二元分类模型的常见成本(或损失)函数。它通常被称为日志丢失,所以请记住这些是同义词。

这个成本函数“惩罚”错误的预测比“奖励”好的预测多得多。让我们看看它的实际效果。

示例 1 —为正确预测计算 BCE

假设您的模型以 90%的概率(0.9)预测了正类。这意味着该模型只有 10%的把握预测到负类。

问题:BCE 值是多少?

图片 7 —二元交叉熵计算—示例 1(图片由作者提供)

可以看到,BCE 值相当小,只有 0.1。这是因为模型对预测相当有信心。让我们看看如果不是这样会发生什么。

示例 2 —计算错误预测的 BCE

假设您的模型以 10%的概率(0.1)预测了正类。这意味着该模型有 90%的把握应该预测负类。

问题:BCE 值是多少?

图片 8 —二元交叉熵计算—示例 2(图片由作者提供)

正如你所看到的,在这种情况下,损失是相当大的——这是 BCE 惩罚错误预测比奖励正确预测多得多的完美证明。

Python 实现

我不太喜欢用手算数学。如果这同样适用于你,你会喜欢这一部分。以下函数在 Python 中从头开始实现 BCE:

我们需要safe_log()函数,因为log(0)等于无穷大。无论如何,如果你运行这段代码,你会发现我们的手工计算是正确的。

现在,您已经从头开始了解了实现逻辑回归算法所需的一切。让我们接下来做那件事。

从头开始实施

让有趣的部分开始吧!我们现在用下面的方法声明一个名为LogisticRegression的类:

  • __init__(learning_rate, n_iterations)–构造器,包含学习率和迭代次数的值,以及权重和偏差(最初设置为)
  • _sigmoid(x)–逻辑激活功能,你知道公式
  • _binary_cross_entropy(y, y_hat)—我们的成本函数——我们之前已经实施过了
  • fit(X, y)–通过梯度下降迭代优化权重和偏差。计算完成后,结果存储在构造函数中
  • predict_proba(X)–使用通过 sigmoid 激活函数的线性方程计算预测概率
  • predict(X, threshold)–根据阈值参数计算预测类别(二进制)

如果你理解逻辑回归背后的数学,用 Python 实现应该是个问题。这可以归结为大约 70 行有文档记录的代码:

接下来我们来测试一下算法。我们将使用来自 Scikit-Learn 的乳腺癌数据集。下面的代码片段加载它,以 80:20 的比例进行训练/测试分割,实例化模型,拟合数据,并进行预测:

如果您想知道,以下是最佳重量值(通过model.weights访问):

图 9 —优化的权重(图片由作者提供)

这里是最佳偏置(通过model.bias访问):

图 10 —优化的偏差(图片由作者提供)

培训部分到此结束。接下来我们来评价一下模型。

模型评估

这里我们保持简单,只打印准确度分数和混淆矩阵。您可以使用下面的代码片段来实现这一点:

以下是精确度值:

图片 11 —初始精确度(图片由作者提供)

这是混淆矩阵:

图 12 —初始混淆矩阵(图片由作者提供)

如您所见,该模型工作良好,准确率约为 95%。有六个假阴性,这意味着在六种情况下,当实际条件为“是”时,模型预测为“否”。尽管如此,比体面的结果。

让我们探索一下如何通过调整分类阈值来使结果更好。

阈值优化

不能保证 0.5 是每个分类问题的最佳分类阈值。幸运的是,我们可以通过改变predict()方法的threshold参数来改变阈值。

以下代码片段优化了准确性阈值,但您可以自由选择任何其他指标:

下面是阈值图表的样子:

图 13 —阈值优化曲线(图片由作者提供)

最佳阈值和相应获得的精度显示在图图例中。正如您所看到的,阈值或多或少与这个数据集无关,但对于其他数据集来说可能就不是这样了。

现在,您可以根据最佳阈值快速重新训练模型:

这是新的、改进的准确度分数:

图 14 —优化的精确度(图片由作者提供)

这是混淆矩阵:

图 15 —优化的混淆矩阵(图片由作者提供)

现在,您知道了如何训练自定义分类器模型,以及如何优化分类阈值。接下来让我们将其与 Scikit-Learn 模型进行比较。

与 Scikit-Learn 的比较

我们想知道我们的模型是否好,所以让我们将它与我们知道的运行良好的东西——Scikit-Learn 的LogisticRegression类进行比较。

您可以使用以下代码片段来导入模型类、训练模型、进行预测以及打印准确性和混淆矩阵:

以下是获得的准确度分数:

图 16—sci kit-Learn 模型的准确性(图片由作者提供)

这是混淆矩阵:

图 17 —来自 Scikit-Learn 模型的混淆矩阵(图片由作者提供)

如您所见,Scikit-Learn 的模型表现大致相同,至少在准确性方面是如此。在假阳性和假阴性之间有一些权衡,但总的来说,两种模型都表现良好。

让我们在下一部分总结一下。

结论

今天,您已经完全从零开始学习了如何用 Python 实现逻辑回归。这是否意味着你应该抛弃事实上的标准机器学习库?没有,一点也没有。我来详细说明一下。

你能从头开始写东西并不意味着你应该这样做。尽管如此,了解算法如何工作的每个细节是一项宝贵的技能,可以帮助你从其他 fit 和预测数据科学家中脱颖而出。

感谢您的阅读,如果您对更多从零开始的机器学习文章感兴趣,请继续关注博客。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

了解更多信息

保持联系

参考

[1]https://www . statistics solutions . com/assumptions-of-logistic-regression/

https://betterdatascience.com】原载于 2021 年 3 月 11 日https://betterdatascience.com/mml-logistic-regression/

机器学习大师:用 Python 从头开始多元线性回归

原文:https://towardsdatascience.com/master-machine-learning-multiple-linear-regression-from-scratch-with-python-ac716a9b78a4?source=collection_archive---------12-----------------------

机器学习既简单又直观——这里有一个完整的从头开始的多元线性回归指南

JJ 英Unsplash 上的照片(作者修改)

线性回归是你在学习机器学习时会遇到的最简单的算法。多元线性回归类似于上周介绍的简单线性回归,唯一的区别是多个斜率参数。多少?嗯,这取决于有多少输入要素——但一会儿会更详细。

今天你将亲手从头实现多元线性回归算法。这是许多即将到来的从头开始的文章中的第二篇,所以如果你想了解更多,请继续关注博客。

今天的文章结构如下:

  • 多元线性回归简介
  • 多元线性回归背后的数学
  • 从头开始实施
  • 与 Scikit-Learn 的比较
  • 结论

你可以在这里下载相应的笔记本

多元线性回归简介

多元线性回归与其简单版本的思路相同,即在给定输入数据的情况下找到最佳拟合线(超平面)。它的不同之处在于能够处理多个输入特性,而不是一个。

算法对要求相当严格。让我们列举并解释几个:

  • 线性假设 —模型假设变量之间的关系是线性的
  • 无噪声 —模型假设输入和输出变量无噪声—因此,如果可能,移除异常值
  • 无共线性-当输入变量高度相关时,模型会过度拟合
  • 正态分布-如果输入和输出变量呈正态分布,模型将做出更可靠的预测。如果不是这样,试着对你的变量进行一些变换,使它们看起来更正常
  • 重定标输入 —使用定标器或规格化器进行更可靠的预测

训练多元线性回归模型意味着计算线性方程公式的最佳系数。最佳系数可以通过迭代优化过程来计算,称为梯度下降

该算法计算每个系数的导数,并在每次迭代中更新它们。更新的程度取决于一个参数——学习率。高学习率会导致“错过”最佳参数值,低学习率会导致缓慢的优化。

在下一节,我们将讨论算法背后的数学。

多元线性回归背后的数学

多元线性回归背后的数学比简单回归的数学要复杂一些,因为你不能简单地将数值代入公式。相反,我们正在处理一个迭代过程。

我们正在求解的方程大致保持不变:

图片 1-多元线性回归公式(图片由作者提供)

我们没有一个单一的斜率β系数,而是有一个完整的β系数矩阵——表示为权重w 。仍然有一个截距值——表示为偏差b

我们必须声明一个成本函数才能继续。这是一个测量误差的函数,代表了我们想要最小化的东西。均方差(MSE)是线性回归最常见的成本函数:

图 2——均方误差公式(图片由作者提供)

简单来说,它代表实际值( yi )和预测值( y ha t)的均方差。 y 帽可以展开为:

图 3 —均方误差公式(v2)(图片由作者提供)

如前所述,我们将使用梯度下降算法来寻找最佳的权重和偏差。它依赖于每个参数的偏导数计算。您可以找到与以下每个参数相关的衍生 MSE 公式:

图 4——MSE 偏导数(图片由作者提供)

最后,更新过程可以总结为两个公式—每个参数一个公式。简而言之,从学习率和导数计算的乘积中减去旧的权重(或偏差)值:

图 5-多元线性回归的更新规则(图片由作者提供)

alpha 参数代表学习率。

整个过程重复所需的迭代次数。让我们通过用 Python 实现一个从头开始的解决方案来看看这在实践中是如何工作的。

从头开始实施

让我们从库导入开始。现在您只需要 Numpy 和 Matplotlib。这些修改是可选的,只是为了让视觉效果看起来更好一点:

开始运算。让我们用下面的方法声明一个名为LinearRegression的类:

  • __init__()–构造器,包含学习率和迭代次数的值,以及权重和偏差(最初设置为)。我们还将创建一个空列表来跟踪每个迭代中的损失。
  • _mean_squared_error(y, y_hat)–“私有”方法,用作我们的成本函数。
  • fit(X, y)–通过梯度下降迭代优化权重和偏差。计算完成后,结果存储在构造函数中。我们也在这里记录损失。
  • predict(X)–使用直线方程进行预测。

如果您理解这个简单算法背后的数学原理,用 Python 实现就很容易了。以下是该类的完整代码片段:

接下来我们来测试一下算法。我们将使用来自 Scikit-Learn 的糖尿病数据集。以下代码片段加载数据集,并将其拆分为要素和目标数组:

下一步是将数据集分成训练和测试子集,并训练模型。您可以使用以下代码片段来实现这一点:

以下是“最佳”权重矩阵的样子:

图 6 —优化的权重矩阵(图片由作者提供)

这是我们偏置项的最佳值:

图 7 —优化的偏置项(图片由作者提供)

这就是全部了!您已经成功地对模型进行了 10000 次迭代训练,并获得了一组非常好的参数。让我们通过标绘损失来看看他们有多好:

理想情况下,我们应该看到一条从高损耗值开始并迅速下降到接近零的线:

图 8 —每次迭代的损失(作者提供的图片)

它看起来很有前景,但我们如何知道损失是否足够低,以产生一个良好的质量模型?我们不能,至少不能直接。我们在损失方面能做的最好的事情是用不同的学习率训练几个模型,并比较损失曲线。下面的代码片段就是这样做的:

结果如下所示:

图 9 —不同学习率的损失比较(图片由作者提供)

对于我们的数据来说,0.5 的学习率似乎是最好的。您可以重新训练模型以适应以下代码片段:

这是测试集上相应的 MSE 值:

图 10 —测试集的均方误差(图片由作者提供)

从头开始构建、训练、评估和调整多元线性回归模型是多么容易!让我们将其与 Scikit-Learn 中的一个LinearRegression类进行比较,看看是否有任何严重的差异。

与 Scikit-Learn 的比较

我们想知道我们的模型是否好,所以让我们将它与我们知道的运行良好的东西——Scikit-Learn 的LinearRegression类进行比较。

您可以使用以下代码片段来导入模型类、训练模型、进行预测,并打印测试集的均方误差值:

以下是相应的 MSE 值:

图 11—sci kit-Learn 模型的均方误差(图片由作者提供)

如您所见,我们调整后的模型优于 Scikit-Learn 的默认模型,但差异并不显著。模型质量—检查。

让我们在下一部分总结一下。

结论

今天,您已经完全从零开始学习了如何用 Python 实现多元线性回归算法。这是否意味着你应该抛弃事实上的标准机器学习库?没有,一点也没有。我来详细说明一下。

你能从头开始写东西并不意味着你应该这样做。尽管如此,了解算法如何工作的每个细节是一项宝贵的技能,可以帮助你从其他 fit 和预测数据科学家中脱颖而出。

感谢您的阅读,如果您对更多从零开始的机器学习文章感兴趣,请继续关注博客。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

了解更多信息

保持联系

  • 关注我的媒体获取更多类似的故事
  • 注册我的简讯
  • LinkedIn 上连接
  • 查看我的网站

原载于 2021 年 3 月 1 日 https://betterdatascience.comhttps://betterdatascience.com/mml-multiple-linear-regression/

机器学习大师:用 Python 从零开始的随机森林

原文:https://towardsdatascience.com/master-machine-learning-random-forest-from-scratch-with-python-3efdd51b6d7a?source=collection_archive---------12-----------------------

机器学习既简单又直观——这里有一个关于随机森林的从头开始的完整指南

迪伦·莱格在 Unsplash 上的照片

我们已经知道一个单独的决策树可以出奇的好。用单棵树建造森林的想法似乎是自然的下一步。

今天,您将学习随机森林分类器是如何工作的,并从头开始用 Python 实现它。这是许多即将开始的文章中的第六篇,所以如果你想了解更多,请继续关注博客。之前文章的链接位于本文末尾。

这篇文章的结构如下:

  • 随机森林简介
  • 随机森林背后的数学
  • 从头开始实施
  • 模型评估
  • 与 Scikit-Learn 的比较
  • 结论

你可以在这里下载相应的笔记本

随机森林简介

就像决策树一样,随机森林是一种用于回归和分类任务的非参数模型。如果你理解了之前关于决策树的文章,那么理解这篇文章就没有问题了。

不用说,那篇文章也是这篇文章的先决条件,原因很明显。

整个随机森林算法是建立在弱学习器(决策树)之上的,给你一个用树做森林的类比。术语“随机”表示每个决策树都是用随机的数据子集构建的。

这是一张对比决策树和随机森林的绝佳图片:

图 1——决策树 vs .随机森林(来源:https://commons . wikimedia . org/wiki/File:Decision _ Tree _ vs . _ Random _ forest . png))

就这么简单。

随机森林算法基于打包方法。它代表了一种结合学习模型以提高性能(更高的准确性或一些其他指标)的概念。

简而言之:

  • N 个子集由原始数据集组成
  • 从子集中构建决策树
  • 对每个经过训练的树进行预测,最终预测作为多数投票返回

这里有一个图表来说明这些观点:

图片 2 —随机森林图(来源:https://commons . wikimedia . org/wiki/File:Random _ forest _ diagram _ complete . png))

接下来让我们回顾一下算法背后的数学。

随机森林背后的数学

好消息——今天没有数学!

随机森林背后的数学原理与决策树相同。你只需要实现两个公式——熵和信息增益。

如果这些听起来像外语,请参考上一篇文章。这两个概念在那里都有详细的讨论。

本文的其余部分假设您熟悉决策树的内部工作原理,因为从头开始构建算法需要用到决策树。

从头开始实施

这次我们需要三节课:

  1. Node -实现决策树的单个节点
  2. DecisionTree -实现单个决策树
  3. RandomForest -实现我们的集成算法

前两个类与前一篇文章中的相同,所以如果您已经编写了它们,请随意跳过。

先说Node级。它在这里存储关于特征、阈值、向左和向右的数据、信息增益和叶节点值的数据。所有的初始设置都是None。根节点和决策节点将包含除叶节点值之外的所有值,而叶节点将包含相反的值。

下面是该类的代码(与库导入一起):

接下来让我们实现决策树分类器。它将包含许多方法,所有这些方法都将在下面讨论:

  • __init__() -构造函数,保存min_samples_splitmax_depth的值。这些是超参数。第一个用于指定分割节点所需的最小样本数,第二个指定树的最大深度。两者都在递归函数中用作退出条件
  • _entropy(s) -计算输入向量的杂质s
  • _information_gain(parent, left_child, right_child)计算父节点和两个子节点之间拆分的信息增益值
  • _best_split(X, y)函数计算输入特征X和目标变量y的最佳分割参数。它通过迭代X中的每一列和每一列中的每个阈值来使用信息增益找到最佳分割
  • _build(X, y, depth)函数递归构建决策树,直到满足停止标准(构造函数中的超参数)
  • fit(X, y)函数调用_build()函数并将构建的树存储到构造函数中
  • _predict(x)函数遍历树来分类单个实例
  • predict(X)函数将_predict()函数应用于矩阵X中的每个实例。

是的,这是很多,但你应该已经觉得很舒服了。下面是单个决策树的代码片段:

最后,让我们建造森林。该类建立在单个决策树之上,具有以下方法:

  • __init__() -构造函数,保存森林中树的数量、最小样本分割和最大深度的超参数值。一旦模型被训练,它还将保存单独训练的决策树
  • _sample(X, y)函数将引导取样应用于输入特征和输入目标
  • fit(X, y)函数训练分类器模型
  • predict(X)函数使用单个决策树进行预测,然后对最终预测应用多数投票

就代码而言,这是一个比决策树简单得多的类。以下是完整的片段:

您可能无法一次完全理解所有内容,但如果您理解决策树,这不会是太大的挑战。

接下来让我们训练和评估我们的模型。

模型评估

接下来让我们测试我们的分类器。我们将使用来自 Scikit-Learn 的虹膜数据集。以下代码片段加载数据集并将其分为要素(X)和目标(y):

接下来,让我们将数据集分成训练和测试部分。以下代码片段就是这样做的,比例为 80:20:

现在让我们开始训练。下面的代码片段使用默认超参数训练模型,并对测试集进行预测:

让我们来看看生成的预测(preds):

图 3 —测试集上的自定义随机森林预测(图片由作者提供)

现在看看实际的类标签(y_test):

图 4 —测试集类别标签(作者图片)

如您所见,两者完全相同,表明分类器非常准确。如果你愿意,你可以进一步评估性能。下面的代码打印测试集的准确度分数:

如果您要运行上面的代码,1.0的值将被打印出来,表示一个完美的分类器。虹膜数据集非常容易正确分类,所以不要让这个欺骗了你。

让我们将我们的分类器与 Scikit 内置的分类器进行比较。

与 Scikit-Learn 的比较

我们想知道我们的模型是否好,所以让我们将它与我们知道效果很好的东西——Scikit-Learn 的RandomForestClassifier类进行比较。

您可以使用以下代码片段来导入模型类、训练模型、进行预测以及打印准确性得分:

如您所料,我们得到了 1.0 的完美准确度分数。

今天到此为止。让我们在下一部分总结一下。

结论

现在你知道了——如何从树木中建造一片森林。这比你想象的要容易,特别是如果你考虑到随机森林是当今性能最好的机器学习算法之一。

您现在知道如何从头开始实现决策树分类器算法。这是否意味着你应该抛弃事实上的标准机器学习库?没有,一点也没有。我来详细说明一下。

你能从头开始写东西并不意味着你应该这样做。尽管如此,了解算法如何工作的每个细节是一项宝贵的技能,可以帮助你从其他 fit 和预测数据科学家中脱颖而出。

感谢您的阅读,如果您对更多从零开始的机器学习文章感兴趣,请继续关注博客。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

了解更多信息

保持联系

原载于 2021 年 4 月 14 日 https://betterdatascience.comhttps://betterdatascience.com/mml-random-forest/

机器学习大师:用 Python 从头开始简单线性回归

原文:https://towardsdatascience.com/master-machine-learning-simple-linear-regression-from-scratch-with-python-1526487c5964?source=collection_archive---------20-----------------------

机器学习既简单又直观——这是简单线性回归的从头开始的完整指南

JJ 英Unsplash 上的照片(作者修改)

线性回归是你在学习机器学习时会遇到的最简单的算法。如果我们讨论的是简单线性回归,你只需要找到两个参数的值——斜率和截距——但是稍后会有更多的内容。

今天,您将亲手从头开始实现简单线性回归算法。这是许多即将到来的从头开始文章的第一篇,所以如果你想了解更多,请继续关注博客。

今天的文章结构如下:

  • 简单线性回归简介
  • 简单线性回归背后的数学
  • 从头开始实施
  • 与 Scikit-Learn 的比较
  • 结论

这里可以下载相应的笔记本

简单线性回归简介

顾名思义,简单线性回归简单。这是许多入门机器学习中使用的算法,但它不需要任何“学习”。这就像在公式中插入几个值一样简单——下一节将详细介绍。

一般来说,线性回归用于预测连续变量,如股票价格、重量等。

线性回归是一种线性算法,意味着输入变量(输入的内容)和输出变量(预测)之间的线性关系是假定的。如果数据集中的关系不是线性的,这并不是世界末日,因为有很多转换方法。

存在几种类型的线性回归模型:

  • 简单线性回归 —有一个输入变量和一个输出变量。比如用身高来预测体重。
  • 多元线性回归 —有多个输入变量和一个输出变量。例如,使用身高、体脂和身体质量指数来预测体重。

今天我们将处理简单的线性回归。关于多元线性回归的文章将于下周发表,如果你想了解更多,请继续关注博客。

线性回归很少被用作解决复杂机器学习问题的首选算法。相反,它被用作基线模型——这是更复杂的算法必须超越的一点。

算法对要求也相当严格。让我们列举并解释几个:

  • 线性假设 —模型假设变量之间的关系是线性的
  • 无噪声 —模型假设输入和输出变量没有噪声——因此如果可能的话移除异常值
  • 无共线性-当输入变量高度相关时,模型会过度拟合
  • 正态分布-如果输入和输出变量呈正态分布,模型将做出更可靠的预测。如果不是这样,试着对你的变量进行一些变换,使它们看起来更正常
  • 重定标输入 —使用定标器或规格化器进行更可靠的预测

现在,您已经了解了这个简单算法背后的足够多的理论。让我们在实现之前先看看数学。

简单线性回归背后的数学

本质上,简单的线性回归归结为求解几个方程。你只需要解直线方程,如下图所示:

图 1-直线方程公式(图片由作者提供)

如你所见,我们需要以某种方式计算贝塔系数。x 代表输入数据,所以这是您已经掌握的东西。

必须首先计算β1 系数。它代表直线的斜率,可通过以下公式获得:

图 2-线方程中的β1 系数(图片由作者提供)

Xi 代表输入特征的当前值,顶部有一条横杠的 X 代表整个变量的平均值。对于 Y 来说也是如此,但是我们现在看的是目标变量。

接下来,我们有β0 系数。可以用下面的公式计算:

图 3-线方程中的β0 系数(图片由作者提供)

这就是简单线性回归的全部内容!一旦计算出系数值,你就可以代入 X 的数值,得到预测值。就这么简单。

接下来让我们看看 Python 的实现。

从头开始实施

让我们从库导入开始。现在您只需要 Numpy 和 Matplotlib。这些修改是可选的,只是为了让视觉效果看起来更好一点:

现在来看算法实现。让我们用下面的方法声明一个名为SimpleLinearRegression的类:

  • __init__()–构造函数,包含 Beta 0 和 Beta 1 系数的值。这些最初被设置为None
  • fit(X, y)–根据输入的Xy参数计算β0 和β1 系数。计算完成后,结果存储在构造函数中
  • predict(X)–使用直线方程进行预测。如果事先没有调用fit()方法,它会抛出一个错误。

如果您理解这个简单算法背后的数学原理,用 Python 实现就很容易了。以下是该类的完整代码片段:

接下来,让我们创建一些虚拟数据。我们将 300 个数据点作为输入变量,300 个正态分布值作为目标变量。目标变量以输入变量为中心,标准偏差为 20。

您可以使用以下代码片段来创建和可视化数据集:

数据集的可视化如下图所示:

图片 4-源数据集(作者提供的图片)

接下来,让我们将数据集分成训练和测试子集。您可以使用 Scikit 中的train_test_split()功能——了解如何使用:

最后,让我们制作一个SimpleLinearRegression类的实例,拟合训练数据,并在测试集上进行预测。下面的代码片段就是这样做的,并且还打印 Beta 0 和 Beta 1 系数的值:

系数值显示如下:

图 5-β0 和β1 系数值(图片由作者提供)

这就是你的线方程公式。接下来,我们需要一种评估模型的方法。在此之前,让我们快速看一下predsy_test变量的样子。

下面是preds变量中的内容:

图片 6-简单线性回归模型的预测(图片由作者提供)

下面是实际测试数据的样子:

图 7 —测试集中的实际值(作者提供的图片)

不完全相同,当然,但总体上很相似。对于更定量的评估指标,我们将使用 RMSE(均方根误差)。下面是如何用 Python 计算它的值:

平均误差显示如下:

图 8 —测试集的均方根误差(图片由作者提供)

如你所见,我们的模型平均误差在 20 个单位左右。这是由于在声明数据集时引入了差异,因此我们无法进一步改进模型。

如果您想要可视化最佳拟合线,您必须在整个数据集上重新训练模型并绘制预测。您可以使用以下代码片段来实现这一点:

它看起来是这样的:

图片 9-整个数据集上的最佳拟合线(图片由作者提供)

这就是简单线性回归模型的全部内容。让我们将其与 Scikit-Learn 中的一个LinearRegression类进行比较,看看是否有任何严重的差异。

与 Scikit-Learn 的比较

我们想知道我们的模型是否好,所以让我们将它与我们知道效果很好的东西——Scikit-Learn 的LinearRegression类进行比较。

您可以使用以下代码片段来导入类、训练模型、进行预测以及打印 Beta 0 和 Beta 1 系数的值:

系数值显示如下:

图 10—sci kit-Learn 模型的β0 和β1 系数(图片由作者提供)

如你所见,系数几乎相同!接下来,让我们检查 RMSE 值:

图 11—sci kit-Learn 模型的均方根误差(图片由作者提供)

再次,几乎一模一样!模型质量—检查。

让我们在下一部分总结一下。

结论

今天,您已经完全从零开始学习了如何用 Python 实现简单的线性回归算法。

这是否意味着你应该抛弃事实上的标准机器学习库?没有,一点也没有。我来详细说明一下。

你能从头开始写东西并不意味着你应该这样做。尽管如此,了解算法如何工作的每个细节是一项宝贵的技能,可以帮助你从其他 fit 和预测数据科学家中脱颖而出。

感谢您的阅读,如果您对更多从零开始的机器学习文章感兴趣,请继续关注博客。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

了解更多信息

保持联系

原载于 2021 年 2 月 22 日 https://betterdatascience.comhttps://betterdatascience.com/mml-simple-linear-regression/

posted @ 2024-10-17 11:34  绝不原创的飞龙  阅读(258)  评论(0)    收藏  举报