TowardsDataScience-博客中文翻译-2021-十九-
TowardsDataScience 博客中文翻译 2021(十九)
原文:TowardsDataScience Blog
协议:CC BY-NC-SA 4.0
arXiv 精选—2021 年 11 月阅读
原文:https://towardsdatascience.com/best-of-arxiv-readings-for-november-2021-bb3ad901e6b?source=collection_archive---------14-----------------------
ML 论文、新闻和代码月刊

图片作者。
在经历了一个缓慢的暑假之后,人工智能世界在过去的一个月里全速回归:会议回到了面对面的形式,新的参数计数记录,Deepmind 成为了强化学习的罗宾汉,或者像现在已经出版和开源的 GPT-3 模型(T-0)一样的 T2-3。
尽管如此,当我们接近 2021 年底时,AI arXiv 上的出版物增长首次出现放缓:经过几年的持续指数增长(每年约 30-40%)后,2021 年的出版物数量似乎只会略微超过 2020 年(约 10%以上)。我们会看到 NeurIPS 和 ICLR 的强劲增长吗?还是人工智能研究已经成熟了?

与人工智能相关主题的年度 arXiv 出版物。
新闻
让我们从过去几周的一些热点新闻开始:
- 自然语言处理会议 (EMNLP)将于 11 月 7 日至 11 日以混合形式举行:同时在线和在多米尼加共和国的 Punta Cana 举行。正式的公开会议将很快在 ACL 选集中发表。
- Deepmind 收购了 MuJoCo 并开源。这是一件大事,因为 MuJoCo 是机器人学和 RL 中使用最广泛的物理模拟软件之一,它曾经很贵。虽然大型大学为他们的学生和员工购买了许可证,但费用使得贪玩好奇的人进入门槛更高。
- 微软的威震天 530B 参数模型。但是等等…它仍然只是一个手波浪的博客帖子!他们声称这是迄今为止最大的单片变压器;你可能会想,单片到底是什么?这是使用所有参数的一种方式,不像混合专家(MoE)类型的模型,如吴导的 1,750 万亿或 Switch Transformer 的万亿,在每个推理/训练步骤中只有一个较小的子集被激活。虽然庞大的规模看起来令人难以置信,但我们必须等到他们分享更深入的作品。说到参数计数,我们会停止关心它们吗?
- 人工智能投资者内森·贝纳奇和伊恩·霍加斯最近发布了 2021 年人工智能状况报告。它从鸟瞰的角度提供了关于人工智能的有用的年度执行摘要:研究、工业、人才、政治和预测。绝对值得一读!
密码
- 如果你想尝试大型的基于注意力的计算机视觉架构,这是你的幸运日,因为最近发布了Scenic【4】:一个运行计算机视觉 JAX 模型的代码库(有很多样板代码和例子),包括几个流行的,像最初的 Vision Transformer【6】,ViViT【7】等等。
- 如果你对图像的生成模型感兴趣,可以看看 VQGAN-CLIP ,这是一个运行流行的生成模型的 repo,可以将自然语言句子转换成图像。
- 最后,我们建议您检查 Dagster 一个“用于开发、生产和观察数据资产的编排平台”。
🔬研究
最后,这是一些有影响力的近期论文。
递归总结有人类反馈的书籍
作者 OpenAI 等人
❓Why → 超长文档摘要(例如书籍规模)对机器来说是一项艰巨的任务,主要是因为标注数据非常耗时:为了标注一个实例或例子,一个人需要阅读一本书并得出它的摘要,这需要几个小时。
💡关键见解→ 长期摘要可以(在某种程度上)成功地分解成注释成本更低的分级摘要任务:将一本书分成几大块,然后将每个块汇总成摘要。把那些摘要串联起来,进行总结。递归地应用该过程,直到达到期望的整本书摘要长度。

来源:https://arxiv.org/pdf/2109.10862.pdf
让我们了解一下所涉及的数据规模:使用了 40 本书,平均 10 万个单词,大部分是虚构的,每个摘要子任务的压缩率大约为 5–10:1。
这个过程的结果离人类质量还很远,只有 5%的摘要达到可比较的质量。有趣的是,模型大小似乎起着重要的作用,因为来自最大模型的摘要明显优于来自遵循相同训练程序的较小模型的摘要。
总之,这又是一次令人印象深刻的大规模、复杂的人在回路中训练大模型的努力。这离产生“哇,这太棒了”的感觉还很远,但这是一个开始。我在想接下来,如何将这转化为一些镜头设置,其中只需要很少或很少的人类注释?
多任务提示训练使零射击任务普遍化
作者维克多·桑,艾伯特·韦布森,科林·拉弗尔,斯蒂芬·h·巴赫。等人
❓Why → 超大型模型研究大多局限于预算庞大的公司。这是拥抱脸大科学研讨会的第一篇论文,提出了一个合作努力,使大规模的 ML 对较小的机构如大学可行。平心而论,这不是第一个开源的大型 GPT-3 模型(例如,查看 GPT-J ),但这肯定会有影响。
💡关键见解→ 我们正在谈论一个 110 亿参数模型,完全开源,可通过🤗拥抱脸。
model = AutoModelForSeq2SeqLM.from_pretrained("bigscience/T0pp")
您可以在论坛上查看项目、 GitHub repo 的所有详细信息,其中包括对模型的每个变体的训练的详细描述。
该模型是 T5 风格的编码器-解码器转换器(不同于 GPT-3 的仅解码器架构),其在自回归语言建模上被训练以预测下一个令牌。然而,现在训练集被更仔细地管理:除了使用通用语言的大型网络抓取之外,作者建议包括用自然语言提示表达的带标签的 NLP 任务。例如,对于带有如下注释的电影评论的句子分类任务
The film had a superb plot, enhanced by the excellent work from the main actor. | Positive
使用模板转换为:
The film had a superb plot, enhanced by the excellent work from the main actor. It was <great/amazing/fantastic...>.
为了避免对一组狭窄的模板进行过度优化,这些模板来自多个人(36)以最大化多样性,最终形成几十个模板供许多 NLP 任务交替使用。
结果是,即使比 GPT-3 小 16 倍,T0 在大多数任务中也优于它,即使这些任务的训练集在训练期间没有被看到。
以下是主要结果的总结。T0 的不同变型反映了在训练期间包括哪些数据集:T0 排除了 GPT-3 用于评估的所有数据集,T0+添加了在评估中使用的数据集(仅训练分裂,仍然保证对测试集盲化),T0++在 T0+之上添加了强力胶中的数据集[2]。

来源:https://arxiv.org/pdf/2110.08207.pdf
如果你读了我们上个月的博客,你可能已经注意到这种方法与谷歌几周前发布的 FLAN [1]非常相似。作者彻底解决了这项工作,T0 仍然有很多优势:T0 和+/+++变体具有相当或更好的性能,同时小 10 倍(137B 对 11B 参数!!!).这两部作品的主要区别在于:
- T0 使用在 MLM 和仅解码器 FLAN 上训练的编码器-解码器(MLM 已经证明是更有效的预训练方法,尽管它不适合自回归生成,因此编码器-解码器策略使用 MLM 预训练表示)
- 更多样的提示
- 一次完成多项任务,而不是一次完成一项任务。
P-Tuning v2:即时调优可以与跨规模和任务的通用微调相媲美
由小刘、纪凯旋、傅毅成等创作
❓Why → 连续 p 调优/即时调优/前缀调优被提出还不到一年[3],它已经成为许多任务中微调的可行替代方案,成为 ML 研究的一个热点。这是它的最新修订版,显示了 p-tuning 在以前苦苦挣扎的任务中的优势。
💡关键见解→ 如果任何人对即时调整仍有疑问,这篇文章应该消除他们的疑虑(例如,对小型冷冻模型不太适用,或者对某些特定任务(如硬序列标记)不太适用)。对于那些迟到的人来说,p-tuning(也称为前缀调整、软或连续提示调整)是一种在不改变预训练参数模型的情况下,针对特定任务微调预训练模型的技术。相反,它包括通过一些连续嵌入的梯度下降来学习提示,这些连续嵌入是任何输入的固定前缀。这已经显示出对于在自回归语言建模上训练的变压器执行得非常好,并且参数效率更高(即,与完全微调相比,对于特定任务,只需要学习非常少量的参数)。
作者们在这项工作中采取的进一步措施是给提示增加“深度”。也就是说,向转换器的不同层添加各种提示。虽然这增加了可训练参数的数量,但它提高了性能,同时将总模型参数与可训练提示的比率保持在 0.1–3%的范围内。这些在夹层中彼此独立(它们在每一层独立训练,而不是来自变压器层向前传递)。
下面是主要结果的总结,期望在不久的将来看到 p-tuning 应用于其他任务!

来源:https://arxiv.org/pdf/2110.07602.pdf
探索大规模预训的极限
作者:周欣宇·阿布纳尔、穆斯塔法·德赫加尼、贝南·奈沙布尔和哈尼·塞德吉。
❓Why → 规模一直是 ML 圈子里讨论的话题。几个月来,我们一直在收录关于这个主题的论文,因为这绝对是这个领域必须努力解决的重要问题之一:添加参数和数据在哪里会不再有用?继续读。
💡关键见解→ 类似于“随着我们提高上游精度,下游任务的性能会饱和”。
好了,这篇论文的主旨很简单,他们研究了上游(US)任务(例如大规模 imagenet 标签)的预训练性能如何转移到下游(DS)性能(例如鲸鱼检测)。然后对很多架构和规模做这个实验:“对视觉变压器、MLP 混频器和 ResNets 进行 4800 次实验,参数数量从一千万到一百亿,在最大规模的可用图像数据上进行训练”🤑💸
这些有趣的图表比较了上游绩效(US)和下游绩效(DS ),前者是指预训练任务的绩效,后者是指评估任务的绩效。几乎是全面的,它最终会饱和。尽管如此,对于计算机视觉来说,跨架构的差异还是非常有趣的!

资料来源:https://arxiv.org/pdf/2110.02095.pdf
作者声称,他们的观察总体上看起来对诸如上游数据的大小或训练次数以及架构选择等选择是稳健的。他们还探索了超参数选择的影响:一些超参数对我们非常好,但不能很好地转化为 DS 吗?是啊!他们在第 4 节中深入研究了这一现象,并发现,例如,重量衰减是一个特别显著的超参数,它以不同的方式影响着我们和 DS 的性能。
在没有人真正从头开始训练模型,而是选择预先训练的模型来引导他们的应用的背景下,这项研究是关键。这篇论文不仅仅是几段话就能概括的,如果你想深入研究,它绝对值得一读!
多举几个例子可能就值几十亿参数
尤瓦尔·克尔斯坦,帕特里克·路易斯,塞巴斯蒂安·里德尔和奥默·利维。
❓Why → 注解还是成长?这可能是 ML 从业者在决定如何分配资源时的一个常见困境:更大的预训练模型还是注释更多的数据。看情况!
💡关键见解→ 主要观点是,在 NLP 任务的环境中,缩放参数始终能提高性能,但是,额外注释的贡献高度依赖于任务。例如,在开放式问答数据集中,添加注释不会显著提高性能,而在句子分类或抽取式问答中,却可以。这是这篇论文的发现的最佳总结图,人们可能会期望热图沿着对角线有一个梯度:大小和注释都会产生性能改进,但事实并非如此。

来源:https://arxiv.org/pdf/2110.04374.pdf
差不多就是这样了!公平地说,它并不是那么全面,我们将不得不看看这些在其他模式上的可复制性如何,但是,正在解决的问题无疑是相关的。
演讲 5:用于口语处理的统一模态编解码器预训练
由敖俊逸、、等创作
❓Why → 自然语言处理几乎经常被用作文本处理的同义词,但是自然语言不仅仅是文本!口语不仅仅使用文字,还使用更多的表达方式。这里有一种方法,通过利用过去几年在 NLP 中非常成功的现有技术来对所有这些进行建模。
💡关键见解→ 通过向模型输入音频和文本来共同学习文本和语音表示,并在自我监督的环境中训练自己,其任务类似于应用于声音的双向掩蔽语言建模。但是将 MLM 应用于音频并不像应用于文本那样简单,它涉及将音频预处理为一种称为 log-Mel filterbank 的适当表示,并在这种表示状态下应用量化目标,在这种状态下可以执行分类任务。重要的是,音频和文本表示被组合在一起并被共同提供给模型,从而允许跨模态建模。

来源:https://arxiv.org/pdf/2110.07205.pdf
对于语音转换(VC)、自动语音识别(ASR)等任务来说,其结果是最先进的,并且在应用于文本到语音和语音到类别(SID)时表现出竞争力。

来源:https://arxiv.org/pdf/2110.07205.pdf
ADOP:近似可微分单像素点渲染
作者:大流士·吕克特、莱纳斯·弗兰克和马克·斯塔明格。
❓Why → 与传统技术相比,使用神经网络以更低的计算成本改善渲染是一件非常令人兴奋的事情,尤其是在 VR 和 AR 领域缓慢但稳步起飞的时候(hello Meta )。毕竟,深度学习可能在渲染元宇宙方面发挥关键作用…
💡关键见解→ 渲染场景视图(例如在视频游戏或模拟中)是一个令人印象深刻的复杂过程:3D 对象可以用多种方式定义,照明、遮挡、纹理、透明、反射以复杂的方式交互,将东西光栅化到像素网格中,等等。强制执行这些任务对于低延迟应用程序来说是不可能的;相反,人们必须聪明地不去计算不需要计算的东西,比如遮挡其他物体的不透明物体。
事实证明,渲染中涉及的大多数过程都可以由可微分模块来执行,这意味着可以使用梯度下降来优化它们,给定适当的损失函数。渲染场景的新视图所涉及的主要模块是光栅化器、渲染器和色调映射器,如下图所示。

来源:https://arxiv.org/pdf/2110.06635.pdf
我们不能说得太详细,因为老实说,这个话题有点超出我们的理解范围。尽管如此,他们提供的视频演示还是令人印象深刻,我们迫不及待地希望这种技术被主流渲染技术广泛采用。
在人工智能的伦理方面,在过去的一个月里,我们也看到了一些我们想要强调的论文
- 德尔福:走向机器伦理和规范是一次勇敢的尝试,旨在教会机器错综复杂的是非曲直。虽然这项任务的复杂性几千年来一直没有达成哲学共识,但这项工作是向将伦理判断引入算法迈出的切实一步。
- 语言技术在全球语言中表现的系统性不平等介绍了一个评估语言技术“全球效用”的框架,以及它如何涵盖全球语言的多样性。

来源:https://arxiv.org/pdf/2110.06733.pdf
在信息检索的主题上,用于密集文本检索的对抗性检索器-排序器是一种令人兴奋的新方法,用于为两阶段检索设置模拟检索器和排序器之间的交互,其中检索器试图用“看起来相关”但实际上不相关的文档来欺骗排序器,排序器试图显示最相关的标记文档。
我们的月度评选到此结束;如果你想了解最新的研究,请在 Twitter 上关注我们。下一集再见!
参考文献:
*【1】*微调过的语言模型是零射击学习者。Jason Wei,Maarten Bosma,Vincent Y. Zhao,Kelvin Guu 等人 2021
SuperGLUE:通用语言理解系统的一个更具粘性的基准。作者:王敬实,Yada Pruksachatkun,Nikita Nangia,Amanpreet Singh,Julian Michael,Felix Hill,Omer Levy,Samuel R. Bowman,2019。
*【3】*调前缀:优化连续提示生成。向,佩西梁,2021。
SCENIC:JAX 的一个图书馆,用于计算机视觉研究及其他领域。Mostafa Dehghani,Alexey Gritsenko,Anurag Arnab,Matthias Minderer,Yi Tay,2021。
[6]一幅图像相当于 16x16 个字:大规模图像识别的变形金刚。阿列克谢·多索维茨基等人 2020 年。
[7] ViViT:视频视觉转换器。作者:Anurag Arnab,Mostafa Dehghani,Georg Heigold,孙辰,Mario Lu CIC,Cordelia Schmid,2021。
arXiv 精选—2021 年 10 月阅读
原文:https://towardsdatascience.com/best-of-arxiv-readings-for-october-2021-3d5ed04b44a5?source=collection_archive---------18-----------------------
ML 论文每月精选

图片作者。
在你的阅读清单上保持领先是很难的,而找到哪些论文应该在清单上就更难了。在 Zeta Alpha 我们总是密切关注最新的人工智能研究,所以我们每月都会分享一些最近的论文,以展示我们认为会有影响力的出版物,主要基于每部作品的贡献和作者的影响力。不要把这个列表看得太全面:像其他人一样,我们也有自己的偏见,但是你能从 4000 多篇论文中选择的就这么多了。尽情享受吧!
让我们从我想强调的一些趋势开始:
- 大型语言模型不再与较小的模型在同一类别中竞争(如预训练+使用监督数据的微调)。为什么?它不再有意义,因为每个人都知道当更大的模型在像强力胶这样的监督基准上微调时会发生什么:它们只会变得更好。相反,我们认为这些模型探索了以前不可行的问题空间,例如零/少镜头和/或多模态学习。
- 度量和基准——我们如何量化我们关心的东西——需要不断地重新思考和发明,以使进展有意义。MNIST 是一些计算机视觉研究的好地方,但你不会在数据集上找到吹嘘新 SOTA 的头条新闻。幸运的是,学者们经常关注这一点,传统上大多数揭露性的论文来自大学,就像我们马上要看到的这一篇。
- 我们经常讨论事物的建模方面——模型的架构、损失函数、优化器等。——因为它们很性感,但不断有证据表明,如果你想解决一个新问题,你的大脑时间最好花在处理数据上。安德烈斯·吴(Andres Ng)已经花了数年时间倡导这一观点,它就像美酒一样陈年。
事不宜迟,下面是 arXiv 最近的一些亮点!
网络结构之战:CNN、Transformer 和 MLP 的实证研究
作者:赵玉成、王光庭、唐传新、、曾文军、查正军。
❓Why?→ 这篇论文的缺点也是它的优点:谦逊的范围和的努力投入到进一步优化他们的实验中。当一个社区通过数百次迭代来优化某项技术时,很难以一种公平的方式将其与一项新技术进行比较:现有方法的成功有多少可以归功于其基本思想,而有多少是小的优化和技术诀窍的纯粹积累,这是理所当然的?这是过去十年统治计算机视觉的 CNN 的情况,也是变形金刚统治语言的情况。
💡关键见解→ 作者提出了一个相当简单的策略来直接比较这三种架构:将网络架构定义为嵌入、空间混合和下采样块的组合,并且只交换不同架构的空间混合。一个重要的警告是所有架构共享一个初始补丁嵌入层,它实际上是原始图像上的卷积(即共享权重的每个补丁的线性投影),因此所有技术都包含一个第一类卷积层。

来源:https://arxiv.org/pdf/2108.13002.pdf
我们可以从这些实验中得出的结论是有限的:在最初的补丁嵌入之后,当有足够的数据时, MLPs 表现得令人惊讶地好,尽管 CNN 仍然在数据受限的状态下统治,并且**变压器缩放得更好,**如在中,当你继续增大它们时,它们不会饱和。总结:今天你可能仍然会使用 CNN,但是一定要在一年后再来询问。这些发现与常识相一致,即架构中的强归纳偏差有助于提高学习效率,但在某些时候对图像不再重要,因为等方差可以学习而不是先验注入(尽管这种推理并不适用于所有数据形态,并且模型等方差可能是从组合爆炸(如大图)的数据中学习所必需的)。

来源:https://arxiv.org/pdf/2108.13002.pdf
其他类似著作:稀疏 MLP 用于图像识别:自我关注真的有必要吗?
稀疏标签浅池
作者:Negar Arabzadeh、Alexandra Vtyurina、Xinyi Yan、Charles L. A. Clarke。
引用作者的话:“我们对这些观察的结果感到不安。”
❓Why?→MARCO 女士是最受欢迎的信息检索(IR)基准之一。本文揭示了现有基准的一些缺点,并就如何评估 IR 提出了更广泛的改进建议。
💡关键见解→ IR 基准通常以如下方式标注:给定一个查询,语料库中的一段被标记为与该查询相关。大多数查询只有一个段落被标注为相关,尽管事实上语料库中可能有更多的段落——标注所有的查询-文档对在大多数情况下是不可行的——因此我们可以说标签是稀疏的。然后使用平均倒数排名(MRR)评估退休模型,其中注释为相关的段落应排在第一位,但不“惩罚”未注释的段落为不相关(记住,尽管缺乏注释,它们可能实际上是相关的)。
这种设置的问题是:如果检索模型将没有注释但实际上比注释段落更相关的段落排在第一位,会怎么样?这部作品恰恰回答了这个问题。
给定 Marco 女士的查询子集,他们运行查询,并要求注释者回答以下问题:哪一段与查询最相关,注释为相关的那一段,或神经排序模型的顶部结果?当然,只有当注释和模型在排名靠前的段落中不同时,注释者才不知道哪个是哪个。事实证明,来自神经排序器的结果比注释更受欢迎(见下图)。换句话说,有人可能会说这些模型比 perfect 更好*,因为与 perfect run 相比,它们的结果更受注释者青睐,perfect run 中检索到的顶部段落总是被标记为相关的段落。*

来源:https://arxiv.org/pdf/2109.00062.pdf
这个结果非常相关,因为它表明流行排行榜可能不再反映 IR 的任何改进,而是注释的过度拟合。作为解决这个问题的一个建议,作者建议移动到一个非静态的标注数据集,其中顶部相关性段落用成对标签连续标注(例如,两个段落中的哪一个与给定查询最相关?).
训练短,测试长:注意线性偏差,可推断输入长度 |👾代码
迈克·刘易斯,诺亚·史密斯,奥菲尔出版社。
❓Why?→ 变压器是天生的集对集神经网络,这意味着该架构是顺序不变的,这就是为什么研究人员尝试了不同的方式将位置信息编码到模型中。本文提出了一种新的超简单的、非可学的编码相对位置信息的方法,这种方法在比训练更大的上下文中进行推理时是鲁棒的。这会成为新的标准吗?
💡关键见解→ 变形金刚中的位置编码长期以来一直有点泛滥,因为它看起来像“任何事情都可以发生”:给定一种编码位置的方法,变形金刚和梯度下降将找到一种性能良好的方法。我们甚至需要一个调查来解释它![2]但是像正弦位置嵌入或固定学习绝对嵌入这样的普通技术有什么隐藏的陷阱呢?当他们用比在所受训练更长的时间进行推理时,他们不能很好地概括。
这里提出的方法简单地依赖于向注意力矩阵(在 softmax 之前)添加一个偏差,该偏差与中心令牌与其邻居之间的距离成比例(见下图)。这些偏差是固定的,不需要学习,比例因子 m 被设置为超参数。

来源:https://arxiv.org/pdf/2108.12409.pdf
令人惊讶的是,变形金刚很好地学习了这种位置编码,并与类似大小的等效模型进行了竞争。有趣的比较发生在当模型对比其训练长度更长的序列执行推理时(见下图)。虽然现有的模型难以概括(即,随着序列越长,困惑急剧增加),但不在场证明的情况并非如此。
然而,有一个重要的警告在本文中没有彻底解决:注意力矩阵中的偏差通过一个 softmax 运行,该 soft max 抑制了远处标记的贡献,这就像有一个注意力的“软窗口”:我们不是只关注 N 个相邻的标记,而是关注递减的权重。实际上,这意味着在位置偏差足够负的某个点上,该标记将不会有任何有意义的贡献,使得有效上下文的大小总是有限的,而不管推断时的输入长度。

来源:https://arxiv.org/pdf/2108.12409.pdf
微调过的语言模型是零射击学习者
作者:Jason Wei、Maarten Bosma、Vincent Y. Zhao、Kelvin Guu 等人
❓Why?→ 尽管有了很大的进步,NLP 中的提示仍然不是很健壮:在不应该的地方添加逗号,输出可能会完全改变。本文展示了在自回归语言建模预训练期间包括标记数据如何使模型在零触发设置中更稳健地学习并更好地转移到新任务。
💡关键见解→ 零镜头学习是机器学习中最有前途的发展领域之一。梦想是清晰的:找到一个模型,并让它在第 0 天就在你的领域中工作,而不需要数据收集、标记、培训、维护、监控漂移等。
大型自我监督语言模型目前是最终实现这一梦想的主要候选对象(尽管有许多障碍需要克服)。特别是自从 GPT-3(现在一岁多了!),提示已经成为一项关键技术,而且还会持续下去。本文研究了如何训练大型语言模型,使其像 GPT-3 一样对零镜头自然语言提示更加鲁棒和准确。尽管将它与 GPT-3 进行比较是不公平的:该模型包括预训练期间的标记数据,但他们不是直接在其上微调模型,而是使用模板来创建该任务的自然语言表达(见下图);而 GPT-3 不包括任何训练数据——原则上,一些数据集意外泄露到预训练数据中,使其暴露给预训练中的模型[3]。

来源:https://arxiv.org/pdf/2109.01652.pdf
结果是一个在许多任务上表现得比 GPT-3 更好的模型,并且在没有包括在预训练中的任务上表现出良好的泛化能力,尽管它仍然远不是一个完全监督的模型。

来源:https://arxiv.org/pdf/2109.01652.pdf
使用冻结语言模型的多模态少量学习
Maria Tsimpoukelli、Jacob Menick、Serkan Cabi、S. M. Ali Eslami、Oriol Vinyals 和 Felix Hill。
❓Why?→ 更多提示:现在多模式和*异步。*您能否利用预训练语言模型中的信息完成视觉任务,而无需重新训练?嗯,有点…继续读。
💡关键见解→ 本文提出的想法相当简单:训练一个语言模型,冻结它,使其参数保持固定,然后训练一个图像编码器将图像编码成提示,让语言模型执行特定任务。我喜欢将其概念化为“为模型学习一个图像条件提示(通过神经网络的图像)来执行任务”。

来源:https://arxiv.org/pdf/2106.13884.pdf
这是一个很有前途的研究方向,但结果并不令人印象深刻?)就绝对性能而言。然而,比较使用多模态数据完全微调的模型(冻结微调)和保持语言模型冻结的模型(冻结 VQA 盲)是有趣的:只有后者显示出从训练数据集(概念标题[4])到目标评估数据集(VQAv2 [5])的良好概括,仍然远离完全监督的模型。

https://arxiv.org/pdf/2106.13884.pdf
关于大型变压器和自我监督学习的其他工作
Rishi Bommasani 著《论基金会模式的机遇与风险》, Percy Liang 等人在 8 月发布时引起了不小的轰动。这本书有很多内容:对新兴领域的大型神经模型的概述、介绍和立场文件,这些模型是在大量数据的基础上不受监督地训练的,他们为此创造了基础模型的名称。虽然这是一个令人信服的全面概述,涵盖了这些模型的技术和社会影响,但似乎还不清楚它们是否需要一个新的术语。
Primer:Searching Efficient Transformer for Language Modeling作者 David R. So 等人提出了一种方法来搜索效率最高且性能良好的转换器架构,与普通架构相比,实现了大约 2 倍的加速。与标准变压器相比,最终的发现架构有两个主要修改:平方 ReLU 激活和在自我关注中的每个 Q、K 和 V 投影后添加深度方向卷积层。
谷歌地图中用图形神经网络进行 ETA 预测
作者:Austin Derrow-Pinion、Jennifer She、David Wong、Petar Velič ković等人
❓Why?→ 有没有想过当谷歌地图计算你从 A 点到 B 点需要多少时间时,幕后发生了什么?以下是它的一瞥…
💡关键见解→ 同样,大规模的高质量数据是您最需要的。本文描述了完全用神经网络估计某物从 A 点到 B 点所需时间的问题设置和形式化。他们基本上:
- 收集庞大的数据集(你好,谷歌)。
- 将道路地图表示为带有线段和交叉点的图形。
- 应用图形神经网络(GNN)来学习每个节点的嵌入,并使用它们来进行推理,使用监督数据以及一些辅助损失来训练,以使训练规范化。GNN 由边、节点和全局超段表示(嵌入)组成,它们通过聚合函数(神经网络)组合在一起,聚合函数将以前的表示作为输入,并输出可用于进行预测的新表示。例如,给定先前的节点、边和超段表示,边表示将用于估计每个段经过的时间。

来源:https://arxiv.org/pdf/2108.11482.pdf
谷歌地图在现有生产基线上的收益是巨大的,像悉尼这样的城市预计到达时间的准确性提高了 40%。本文的另一个有趣的方面是详细介绍如何部署这样的模型,同时满足延迟需求,这涉及到预计算和缓存对几个超分段的预测。

来源:https://arxiv.org/pdf/2108.11482.pdf
眼睛告诉一切:不规则的瞳孔形状揭示了 GAN 生成的脸
作者:郭辉、胡舒立、王欣、张铭清和吕思伟。
❓Why?→ 这是一个好玩的。Deepfakes 的挑战是,在必要时能够有效地检测到它,以防止错误信息的传播。deep fakes 是一种计算机生成的内容,对于普通人来说,它与原始来源没有什么区别。事实证明,瞳孔是一张人脸非常具有揭示性的一面!
💡关键见解→ 仔细观察一张脸的瞳孔:人类的瞳孔碰巧一直都很圆,但生成性对抗网络(GAN)生成的人脸并没有很好地捕捉到这一特征。结果是 GAN 生成的人脸通常显示出略微不规则的瞳孔,这使得有可能通过观察它们来检测图像何时是人工生成的。

资料来源:https://arxiv.org/pdf/2109.00162.pdf
通过分割瞳孔并将其拟合为椭圆形状,这项工作显示出令人惊讶的良好的 ROC 曲线,用于检测虚假的面部图像。

来源:https://arxiv.org/pdf/2109.00162.pdf
你可能喜欢的类似论文:用精心制作的自然妆容躲避攻击,作者尼赞·古埃塔等人。
🐍代码和流行的实现
👾 RL-VIG/LibFewShot |📄论文 ⭐️ 176
作者李文斌等人
LibFewShot 是一个为少数镜头学习提供的综合库。随着少数镜头学习的成功越来越多,这个新的图书馆可以帮助你开始。它包括太多的方法在这里命名,所有这些方法都是在过去 4 年的研究中提出的,分为微调方法,元学习方法和度量学习方法。

来源:https://github.com/RL-VIG/LibFewShot
👾景云亮/斯温尼尔📄论文 ⭐️ 490
梁景云等
SwinIR 是一种使用 Swin Transformer 的图像恢复方法,Swin Transformer 是几个月前由微软[1]提出的计算机视觉(CV)的模型主干。他们的方法在三个基准上达到了 SOTA,老实说,计算摄影在过去十年里带给我们的进步令人印象深刻。你也可以玩他们的 colab 笔记本。

来源:https://github.com/JingyunLiang/SwinIR
👾Facebook research/mask former📄论文 ⭐️ 619
作者:郑博文、亚历山大·g·施维因、亚历山大·基里洛夫
现代语义分割通常被构建为每像素分类任务(即,将每个像素分配一个类别,作为属于汽车、道路或鸟的类别),但随后执行实例级分割(即,在每张图片中找到选择人脸的遮罩)被建模为二进制遮罩分类任务。MaskFormer 提出直接学习一组二进制掩模(就像在实例级分割中一样),然后对每个掩模进行分类步骤,在不显式进行逐像素分类的情况下显示出很好的结果。

来源:https://github.com/facebookresearch/MaskFormer
我们的月度评选到此结束;如果你想了解最新的研究,请在推特上关注我们 @zetavector 。下一集再见!
参考文献
[1] Swin 变换器:使用移位窗口的分级视觉变换器。由https://arxiv.org/search/cs?searchtype=author&query=Liu%2C+Z林语桐*https://arxiv.org/search/cs?searchtype=author&query=Cao%2C+Y韩虎【奕譞】魏张铮2021*********
**【2】变压器中位置信息:概述。由菲利普·杜特尔、马丁·施密特、辛里奇·舒茨; 2021。
【3】语言模型是很少出手的学习者。由 OpenAI 等人完成;2020.
【4】概念 12M:推送网页级图文预训练,识别长尾视觉概念。由Soravit ChangpinyoPiyush SharmaNan DingRadu Soricut*;2021.*****
【5】让 VQA 的 V 字发挥作用:提升图像理解在视觉问答中的作用。由 亚什·戈亚尔特哈斯·Khot道格拉斯·萨默斯-留斯德茹夫·巴特拉德维·帕里克2016.****
最佳 ML 代码和软件—2021 年 6 月
原文:https://towardsdatascience.com/best-of-ml-code-and-software-june-2021-486dcf6f461b?source=collection_archive---------35-----------------------
每月精选的最近实现、工具和软件正在 ML 领域获得牵引力:Google 的 Vertex AI、PyTorch Vision、HuggingFace Accelerate 等等。

图片作者。
构建 ML 软件并从研究跳到生产并不是一件容易的事,即使当资源的海洋是巨大的:很难跟上。确切地说,当我们努力将最新的模型投入生产并找到最佳的纸面实现时,我们经常在 Zeta Alpha 遇到这个问题,因此我们希望通过分享我们每月在最新的存储库、工具、库和软件新闻中的发现来做出贡献。尽情享受吧!
⚙️ MLOps 亮点
ML Operations (MLOps)的空间正在以令人眼花缭乱的速度移动,这可能会使它变得混乱:在过去的几年里,数百家公司和产品已经出现,以更可靠和更强大的方式帮助 ML 投入生产,但结果是一个非常拥挤,尚未确定的市场,仍然很难导航。当我们自己试图理解它的时候,我们密切关注着最新的新闻和发展。这里有一个选择:
- 谷歌发布 VertexAI :一个“MLOps 的统一平台”。大型云提供商(微软的 Azure ,亚马逊的 AWS )正在快速构建与他们的技术集成的 ML 工具——可能是为了锁定更多的客户——而像 DataBricks 这样的公司,凭借新的 DataBricks ML ,或者像 MLFlow 或 Kubeflow 这样的框架,继续推动一个不可知的未来,即你在哪里运行你的 ML 项目。我们将看到内置或第三方解决方案是否会在未来几年内得到更广泛的采用,以及端到端 MLOps 产品是否会赢得特定功能工具的海洋,如带有通气管的标签、带有海王星的跟踪实验以及带有气流的协调。
- Huggingface 将变压器推向大众,加速了这些架构在生产中的应用。随着变形金刚几个月前在解决计算机视觉任务的研究方面取得进展, Huggingface 最近发布了第一个完整的“视觉版本”,其中包括 CLIP、ViT 和 Deit。工业中使用的模型总是比研究中使用的模型落后几个月,因为性能/ 简单性的权衡适用于不同的情况。因此,尽管 ViTs 最近取得了成功,我们仍然想知道:变形金刚会在不久的将来取代 CNN 吗?
- 吴恩达的新 coursera“生产中的人工智能”:Andrew 的原创机器学习课程通过将人工智能介绍给数百万从业者,成为人工智能迅速崛起的催化剂。如果这是一个指标的话,这个新课程有可能通过教育成千上万的工程师和研究人员来缩小研究和生产之间的差距。
同时,在 GitHub 上
一系列最近发布的库、框架和实现。
👾Facebook research/pytorchvideo⭐️1.4k |📄文档 |🌐网站
👉 Pytorch Video 提供了加速视频理解研究所需的可重用、模块化和高效的组件。PyTorchVideo 是使用PyTorch开发的,支持不同的深度学习视频组件,如视频模型、视频数据集和视频特定变换。
🚀非常适合构建定制视频处理研究模型并进行基准测试。功能和特点:
- 一个“模型动物园”,包含现有模型的几个实现,以及最常见数据集的数据加载器。
- 高效的视频组件:组件针对视频进行了优化,并支持硬件上的加速推理。

来源:https://github.com/facebookresearch/pytorchvideo
👾微软/swin-transformer ⭐️ 3.4k |📄论文
👉如果你想玩视觉变形金刚,这里有你现在可能需要的支柱。
❓此报告是“swin transformer:使用移位窗口的分层视觉转换器”的正式实现,它还包括以下论文和任务的代码:
- 对象检测和实例分割:参见Swin Transformer for Object Detection。
- 语义分割:参见 Swin Transformer 进行语义分割 。
- 自监督学习:参见Transformer-SSL。
如果你想玩一个立体的视觉变形器迭代,这个实现将是有用的。

来源:https://github.com/microsoft/Swin-Transformer
👾拥抱脸/加速 ⭐️1.4k |📄文档
👉在不同的硬件加速配置(单个/多个 GPU 和单个/多个节点上的 TPU)上运行 PyTorch 的非常简单的方法,无需特定于硬件的样板代码。
🚀一次定义,随处训练。很快。accelerate 的用途和用途:
- Accelerate 让您可以在分布式环境(即跨计算节点或许多其他配置)中运行训练脚本,而不会放弃对训练循环的控制。
- Accelerate 不会让你从训练循环本身中抽象出来,不像 PyTorch 之上的其他高级框架,比如 pytorch/ignite 。

来源:https://github.com/huggingface/accelerate
👾 open-mmlab/mmocr ⭐️ 1.2k |📄文档
👉一个基于 PyTorch 和mm detection的开源工具箱,用于文本检测、文本识别,以及包括关键信息提取在内的相应下游任务。
🚀非常适合构建图像或视频处理管道。主要特性和组件:
- 一个综合管道,包括下游信息提取任务。
- 用于文本检测和识别的各种最先进的模型
- 一个模块化的设计来定义你自己的优化器,数据预处理,模型骨干或损失函数。
- 几个可视化工具,地面纹理和预测边界框等等。

来源:https://mmocr.readthedocs.io/en/latest/demo.html
👾LinkedIn/grey kite⭐️939 |📄文档
👉Greykite 库通过其旗舰算法 Silverkite 提供灵活、直观和快速的预测。Silverkite 算法适用于大多数时间序列,尤其适用于趋势或季节性变化点、事件/假日效应以及时间相关性。它的预测是可解释的,因此有助于可信的决策和洞察力。
🚀非常适合快速现成的时序应用。主要特性和特征:
- 灵活的设计:提供基本的回归检测趋势和季节性,假期和变化点;以及最先进的 ML 型号可供选择。同一管道支持所有模型的预处理、交叉验证、回溯测试、预测和评估。
- 直观的可视化界面、适用于特定数据特征的模板,以及可生成可解释输出以检查每个回归变量贡献的 it。
- 使用网格搜索进行模型选择的快速培训、基准测试和原型制作。

来源:https://github.com/linkedin/greykite
👾谷歌/天琴座 ⭐️ 2.6k | 博文 |📄论文
👉一种高质量、低比特率的语音编解码器,即使在最慢的网络上也能进行语音通信。为此,它应用传统的编解码器技术,同时利用机器学习(ML)的进步,通过数千小时的数据训练模型,创建一种压缩和传输语音信号的新方法。
🚀这项工作在精神上类似于 Nvidia 基于 GAN 的极低比特率视频压缩。该方法的工作原理是每 40 毫秒提取语音特征,基于心理声学特性进行量化(即去除人耳对其敏感度低的方面),并通过信道传输该信号。解码器是一个生成模型,它接收语音特征作为输入,并输出音频波形。这对于构建带宽受限的移动应用程序非常有用。主要功能和特点包括:
- 极低比特率语音编解码(3kbps)。
- 易于集成基于 Android 和 Linux 的应用程序。

来源:https://ai . Google blog . com/2021/02/lyra-new-very-low-bitrate-codec-for . html
如果你对 MLOps 的广阔世界更感兴趣,我怎么推荐都不为过,你可以看看迟虎燕在她的博客上的工具诊断摘要,以及ml-ops.org网站和他们在 GitHub 上的资源列表。
这就是这个月的内容,如果你想跟上 ML 世界的最新发展,请在 Twitter 上关注我们。要了解更多有趣的近期研究,请查看其他月度博客系列 和 arXiv 精选,它们主要关注学术文献。下个月见!
【所有 GitHub 回购星级统计截至 2021 年 6 月 1 日】。
参考文献
[1] 从自然语言监督中学习可转移的视觉模型——亚历克·拉德福德、琼·金旭等 2021。
[2] 一幅图像抵得上 16x16 个字:大规模图像识别的变形金刚——作者阿列克谢·多索维茨基、卢卡斯·拜尔、亚历山大·科列斯尼科夫、德克·韦森博恩、翟晓华等 2021
[3] 训练数据高效的图像转换器&通过注意力的升华——Hugo Touvron 等人 2020
在各种预算范围内,最适合深度学习的电脑
原文:https://towardsdatascience.com/best-pc-builds-for-deep-learning-in-every-budget-ranges-3e83d1351a8?source=collection_archive---------2-----------------------
意见
探索在每个预算范围内执行深度学习计算的最佳 PC 构建平台

6 9 在 Unsplash 上拍照
随着人工智能的所有现代发展,深度学习的普及程度已经上升到了顶峰。深度学习的崛起和广泛的应用前景非常可观。随着对许多感兴趣的主要主题进行深入研究,深度学习的革命必将在未来几年继续下去。
如果你的目标是精通深度学习,你最终需要一个强大的系统。一个系统,你可以用它来处理各种各样的具有挑战性的任务,这些任务可以在互联网上进行深度学习。虽然旨在实现这一目标,你可能有一定的预算限制。你可能对你期望构建和实现的构建类型没有最好的想法。
请记住,本文中提到的所有构建都是针对机器学习的,特别是针对那些对深入研究和探索深度学习感兴趣的人。但是,在我们直接进入我们的 PC 构建之前,让我们了解一些核心要求,这些要求对于加快我们在深度学习过程中会遇到的一些任务是必不可少的。
在您继续阅读本文之前,我想向所有感兴趣的读者提一下几个先决条件。确保您完全愿意花费指定的金额,这取决于它是低端、普通还是高端版本。更重要的是,确保你想要追求深度学习,作为你未来的一个重要部分。
如果你不太确定你是否想在这上面投入时间,或者如果你想追求你的梦想,但目前没有购买 PC 的最佳预算,我强烈建议读者查看本文的下一部分。
在你深入研究这篇文章之前,我建议你检查一下你是否真的需要 GPU 来进行深度学习。本文将帮助您了解图形处理单元、CUDA 内核和其他基本概念。
不确定该做什么?

照片由阿卜杜勒·巴里在 Unsplash 上拍摄
如果您有以下问题之一,该怎么办?—
- 降低预算限制。
- 还是不确定深度学习。
- 你不喜欢在技术上花钱(或者你觉得技术很无聊)。
- 其他类似原因。
从每个人的角度来看,上述理由绝对有效。对于以上四点所提到的情况,我主要有几个建议。首先,我强烈推荐检查一下 Google Colab 环境,因为它为初学者和专家提供了许多奇妙的功能。
如果你是数据科学、人工智能和深度学习的初学者,Google Colab 是一个类似于 Jupyter 笔记本的环境,它为用户提供了一个难以置信的平台,只需登录你的电子邮件 ID 就可以执行任何类型的复杂任务。你也可以安装带有数据集的 Google Drive,并在旁边执行计算。
我想建议第一次观看的人,甚至那些完全不确定自己对深度学习的兴趣或定位的人,开始使用谷歌 Colab,花时间做他们的项目,探索他们的兴趣。请随意尝试您想要的新东西,因为云环境为您提供了一种利用其 GPU 以及与他人轻松共享 Jupyter 笔记本内容的方式。
在我之前的一个作品中,我在 Jupyter 笔记本上写了一个完整的入门指南。查看下面提供的文章,了解 Jupyter 笔记本的几乎所有信息。
你应该考虑的另一个选择是利用各种公司为人工智能提供的众多云平台。其中包括亚马逊的 AWS、微软的 Azure、IBM 的 Watson Studio 等等。使用这些云环境,您不仅可以按照自己的意愿构建有效的模型,还可以将它们部署到云环境中,以获得更广泛的受众。
随着这些初始问题的解决,让我们开始探索在各种预算范围内,深度学习的最佳 PC 构建是什么。
各种预算范围内深度学习的最佳 PC 构建:

在 Unsplash 上由娜娜杜瓦拍摄的照片
在我们深入探讨哪种 GPU 最适合您的构建之前,让我们分析一下构建您的最终 PC 构建所需的其他基本组件。首先,数据集将需要大量存储来执行复杂的应用程序。如果你想做更大的项目,大容量硬盘是必须的。我还会推荐一个更小的固态硬盘(SSD)来加快您的操作速度。固态硬盘可以存储您的操作系统,各种任务将更快、更高效。
下一个基本组件是随机存取存储器(RAM)。系统上的 RAM 对于处理电脑上某些任务的执行速度非常重要。拥有相当高的 RAM 对于提高工作效率来说通常是必不可少的。另一个需要考虑的基本因素是您所使用的处理器类型。您可以选择英特尔或 AMD 的 CPU。两者都有自己的好处,我强烈建议观众去研究它们。
最后,让我们探索深度学习的核心,即 GPU 的最佳选项。最好的公司选择 GPU 的明显选择是英伟达,主要是因为一个首要原因。英伟达提供了一种叫做计算统一设备架构(CUDA)的东西,这对于深度学习模型的计算极其有益。
CUDA 是 Nvidia 创建的并行计算平台和应用编程接口模型。这些 CUDA 核心在人工智能领域是高度有益和进化的。与 AMD 等其他公司相比,在这些 CUDA 模块上投入的研究和时间要多得多。
虽然其他一些图形卡可能功能强大,但它们没有 CUDA 对某些关键操作的完全支持。因此,出于深度学习的目的,英伟达 GPU 优于其他同行。英伟达的 CUDA 支持多种深度学习框架,如 TensorFlow、Pytorch、Keras、Darknet 等。
选择处理器时,尽量选择没有集成 GPU 的处理器。因为我们已经单独购买了一个 GPU,所以您不需要在 CPU 中预先构建集成 GPU。遵循这一步骤将帮助你节省更多的钱。我对 Intel CPUs 比较有经验,对这个话题的评论会比 AMD 多。
其他重要组件,如主板、电源单元(PSU)和 CPU 外壳,将不在本文中详细讨论。无论是英特尔还是 AMD,都应该相应地研究和购买适合您的 CPU 分支的主板。配备显卡的 PSU 版本通常在 450 瓦以上的低预算版本中表现最佳,在 750 瓦以上的高预算版本中表现最佳。CPU 外壳是舒适的选择。选择最适合你的。
低预算构建:
在低预算的个人电脑中,您应该寻找能够轻松处理一些复杂操作的处理器,例如 Jupyter 笔记本电脑。英特尔的建议将是 I3-I3–10100 F 或任何其他 I3–9 代 F 系列。这些处理器没有集成 GPU,可以以较低的预算最佳地执行大多数任务。我会推荐研究 AMD 的 CPU,因为我听说它们在较低的价格预算下,具有更高的内核和线程,性能会好得多。
你至少应该寻找 8GB 的内存。但是,如果其他组件没有到位,4GB RAM 应该暂时足够了。但是,请尽快升级它们。如果可以,尝试获得 128 GB 的固态硬盘,以及 1TB 的硬盘,用于执行像样的深度学习项目。最后,对于显卡,我的主要建议是 GTX 1050 或低于这个范围的任何东西。
平均预算构建:
在普通预算的电脑中,您应该寻找像 i5–9400 f 这样的处理器,也就是说,一个不需要集成 GPU 就可以支持大多数任务的处理器。请研究各自的 AMD 公司的同行也彻底。根据我的研究,AMD 锐龙 5 (6 核,3.4 GHz)似乎是一个合适的选择。
您应该寻找 8GB 到 16GB 的内存范围,最好是 16 GM 的内存。尽量购买 256 GB 到 512 GB 大小的 SSD,用于安装操作系统和存储一些至关重要的项目。以及 1TB 到 2TB 的 HDD 空间,用于存储深度学习项目及其数据集。对于显卡建议,请查看任何类似的 GPU,如 GTX 1650、GTX 1660、GTX 1660 Ti、RTX 2060、GTX 1070 以及该范围内的其他类似 GPU。
我要说的是,我的第一台定制 PC 也是一台普通预算的 PC,由以下组件组成,即 i5–9400k、2 TB 硬盘、256 MB 固态硬盘和 GPU GTX 1660。对于大多数较小的深度学习任务来说,这些构建构成了显著的性能。然而,某些更高复杂性的问题,如 GANs 上的项目,可能会有点问题。
高预算构建:
在高预算构建中,您应该寻找的组件是带有或不带有集成 GPU 的 AMD 或英特尔处理器。在这些价格范围内,这些 CPU 通常都带有集成的 GPU。我的英特尔建议是 i7–10700k、i9–9900k 或 i9–10900 x。至于磁盘空间,我会推荐 512 GB 到 1 GB 或更多的 SSD 和至少 4 TB 的 HDD。尝试以 16–32 GB DDR 4 的高频率 RAM 为目标。
这些范围的最佳显卡通常有多种选择,包括购买多个显卡。一些最好的选择是 GTX 1080 钛,RTX 2080,RTX 2080 钛,RTX 3080 和 RTX 3090,以及许多其他神话般的选择。
如果你有一个较高的预算,那么请随意花费你的资源来建立最好的设备。你也可以看看其他元素,比如 RGB 风扇,或者更酷的 CPU 外壳。你也可以包括液体冷却的元素,以防止你的高强度引擎表现良好。
结论:

照片由 Artiom Vallat 在 Unsplash 上拍摄
“艾温特斯不是由于想象力陷阱,而是由于缺乏想象力。想象力从混乱中带来秩序。具有深度想象力的深度学习是通往 AI 春天和 AI 秋天的路线图。”
— 阿密特雷
作为一个额外的提示,我建议观众关注这些 GPU 在你们各自国家的价格范围。每当价格大幅或小幅下降时,将是您购买这些设备的最佳时机。继续自己研究,在你的价格范围内寻找更好的选择。
本文涵盖了查看您的 PC 构建的大多数基本方面,以便在您期望的价格范围内获得有史以来最好的深度学习设置。请随意研究和探索,直到你最终决定什么是最适合你的选择。顺便说一句,我个人的建议是,如果你有足够的预算,那就去做吧。
最糟糕的情况是,如果你买了一台 PC,然后决定深度学习可能不是你的最佳选择,因为它不适合你当前的兴趣,你仍然可以将它用作游戏、编辑、流媒体等等的设备。所以,如果你买得起,那就去买吧!这个选择带来的遗憾将会很少。
如果你对这篇文章中提到的各点有任何疑问,请在下面的评论中告诉我。我会尽快给你回复。
看看我的其他一些文章,你可能会喜欢读!
</7-best-free-tools-for-data-science-and-machine-learning-3e630125f87e> [## 数据科学和机器学习的 7 个最佳免费工具
towardsdatascience.com](/7-best-free-tools-for-data-science-and-machine-learning-3e630125f87e) </6-best-programming-practices-f2605c5b469c> </5-essential-skills-to-develop-as-a-data-scientist-16442f094c09> </5-nlp-topics-and-projects-you-should-know-about-65bc675337a0>
谢谢你们坚持到最后。我希望你们都喜欢这篇文章。祝大家有美好的一天!
为计算机视觉任务构建深度学习模型的最佳平台
原文:https://towardsdatascience.com/best-platform-to-build-deep-learning-models-for-computer-vision-tasks-1c3cf2e0e303?source=collection_archive---------22-----------------------
查看用于构建和建立自己的深度学习模型以解决计算机视觉任务的最佳平台选项

卡尔·海尔达尔在 Unsplash 上拍摄的照片
自从深度神经网络在分割神经元网络方面赢得 ISBI 挑战赛以来,构建深度学习模型来解决众多计算机视觉项目的技术已经获得了巨大的欢迎。在过去的十年里,大多数重大的计算机视觉比赛都被深度学习成功征服。
随着深度学习领域的快速发展,每年都有新的方法和技术被发现,跟上这些大规模趋势变得至关重要。虽然大多数数据科学爱好者和有志之士可能希望用最好的深度学习工具构建一些独特的计算机视觉应用和项目,但不幸的是,他们可能无法利用最好的机会。
在本文中,我们将讨论几个重要的计算机视觉任务,即对象分类和检测,以及实例分割。一旦我们理解了这些主题的基础,我们将讨论如何在这些任务的最佳平台的帮助下完成这些项目。实现大多数深度学习任务的一个主要贡献因素是 GPU。要了解和探索更多关于 GPU 的重要性,请通过下面提供的链接查看下面的文章。
重要的计算机视觉应用:

安妮·斯普拉特在 Unsplash 上的照片
随着深度学习和计算机视觉领域的每一项进展,计算机视觉的光芒开始闪耀,现代世界需要几个现代计算机视觉项目。猫狗分类、人脸识别、情感和手势识别、对象检测和分割任务等项目都非常有名。
在本文的这一部分,我们将了解并涵盖计算机视觉的三个主要应用,它们被认为是最重要的应用,即分类任务、对象检测和实例分割。事不宜迟,让我们探索这些基本概念,并了解以下概述。

图像来源
1.分类:
图像分类是执行的最显著的计算机视觉操作之一。常见的分类图像处理任务可以包括简单到在狗或猫之间进行分类或者在许多狗品种之间进行分类。图像分类是我们倾向于对图像甚至视频执行的最基本的任务。大多数图像分类任务可以用卷积神经网络、迁移学习模型和其他类似的项目来执行。
2.物体检测:
目标检测是计算机视觉最重要的任务之一。几十年来,一直在开发几种算法来解决以下问题。然而,直到最近(大约十年前),这项任务才获得了更多的关注。简单地说,目标检测的目的是在期望的目标位置周围创建边界框。
3.实例分段:
我们将在文章的这一部分讨论的最后一个重要的计算机视觉操作是分割。分割用于推断图像中的单个实体。在分段技术的帮助下,您可以相应地分离基本元素。语义分割试图识别给定特定图像中每个像素的作用,而实例分割倾向于识别每个类别的标签。
讨论完成这些任务的最佳平台:

作者图片
实现上一节中提到的这些任务并获得最佳结果的最佳平台之一是数据仓库。为了解决这些问题,构建各自的深度学习模型并从零开始构建它们所需的时间相当长。然而,在这个端到端平台的帮助下,您可以成功地注释、训练和部署您的模型,而不会招致任何技术债务。
进入 Nexus 网站后,您可以注册一个免费计划,这足以开始您的计算机视觉之旅。该免费计划非常适合探索 MLOps 工具的团队、学生、研究人员和希望深入研究计算机视觉的数据科学爱好者。免费计划的一些亮点包括:(I)访问增强库;( ii)基于 web 的注释器;( iii)免费的 GPU 计算时间。
数据预处理:

作者图片
登录后,您可以使用拖放编辑器上传您的图像和注释,轻松地从头开始创建一个新项目。注释支持多种格式,所以从 OpenCV 导入数据集没有问题。然后,您可以使用基于 web 的注释器对图像进行注释,该注释器支持绘制边界框、多边形和遮罩。
训练您的神经网络模型:
注释完图像后,只需点击几下鼠标,您就可以开始构建工作流程了。

作者图片
该平台为您提供了许多选项来构建不同类型的模型。您可以构建的一些模型示例有 RetinaNet、fast R-CNN、Mask R-CNN 和 EfficientDet 模型,它们也支持超参数调整。您可以从他们的四种可用 GPU 模型中选择一种,然后继续训练网络。一旦神经网络被初始化,您就可以在神经监视器上快速监视进度。根据数据集的大小,训练模型可能需要 20 分钟,一旦生成模型,您就可以执行预测任务了。

作者图片
可视化模型推理:

作者图片
大多数开发人员在构建任何深度学习项目以解决计算机视觉任务的过程中面临的一个关键问题是他们需要编写的大量代码。一旦你成功地完成了一个模型的训练,你就必须编写更多的代码来确保这个模型能够做出正确的预测并且能够被成功地部署。
对于大多数开发人员来说,这个过程可能非常乏味,因为他们每次构建新的深度学习模型时都必须处理这些情况。然而,Datature 提供了自己的开源门户库,有助于克服数据科学爱好者面临的大多数常见困难。Portal 是游戏规则的改变者,因为它允许开发人员以最快的方式加载和可视化模型。
对于大多数初级开发人员来说,Portal 也很容易使用。只需几个步骤,您就可以执行所有需要的操作。Portal 目前支持 TensorFlow 和 DarkNet 模型,而 PyTorch 支持计划在不久的将来发布。安装门户库后,使用门户库的基本步骤是相应地注册和加载所需的模型。完成这些步骤后,您可以添加图像或视频,并轻松地做出适当的预测。

作者图片
使用 Portal 可视化预测的步骤总结如下:
- 启动门户
- 注册模型(本地或使用数据关系)
- 加载资产(图像/视频)
- 实时观察模型推理
其他功能如下:
- 类别过滤
- 设置 IoU 阈值
- 运行视频推理
- 选择视频帧间隔
结论:

设计生态学家在 Unsplash 上拍摄的照片
深度学习和计算机视觉在现代的兴起是无可争议的。虽然有几种方法可以解决各种计算机视觉任务,但开发人员在试图找到最佳方法时经常会面临几个问题。拥有一个合适的 MLOps 管道允许团队在从头构建模型和部署模型时有效地启动和迭代他们的模型。在本文中,我们讨论了相对容易地实现这两个任务的最佳平台。
对于大多数重要的计算机视觉项目来说,Datature 平台是一个非常棒的地方。除了允许您在不需要编码和可视化工作流的情况下构建大量模型之外,注释还可以完全在线监控和管理。培训过程在云上完成,无法访问 GPU 支持的用户可以从这些功能中受益匪浅。
该平台最棒的部分是,您不仅可以构建和训练模型,还可以使用他们的开源门户库来注册和加载您构建的模型,以便对您的图像或视频内容进行适当的预测。这样做将大大减少开发人员所需的计算工作,并使他们能够更有效地执行任务。想开始吗?看看这个 5 分钟视频,今天就启动你的第一个计算机视觉项目吧!
如果你对这篇文章中提到的各点有任何疑问,请在下面的评论中告诉我。我会尽快给你回复。
看看我的其他一些文章,你可能会喜欢读!
</10-computer-vision-terms-everyone-must-know-about-687a98845fc8> </5-best-python-projects-with-codes-that-you-can-complete-within-an-hour-fb112e15ef44> </14-pandas-operations-that-every-data-scientist-must-know-cc326dc4e6ee> </7-best-ui-graphics-tools-for-python-developers-with-starter-codes-2e46c248b47c>
谢谢你们坚持到最后。我希望你们都喜欢这篇文章。祝大家有美好的一天!
Spark SQL 中存储桶的最佳实践
原文:https://towardsdatascience.com/best-practices-for-bucketing-in-spark-sql-ea9f23f7dd53?source=collection_archive---------0-----------------------
Spark 斗气终极指南。
Spark 从 2.0 版开始支持分桶功能。这是一种如何在文件系统中组织数据并在后续查询中利用它的方法。
有许多资料解释了分桶的基本思想,在本文中,我们将更进一步,更详细地描述分桶,我们将看到它可能具有的各种不同方面,并解释它如何在幕后工作,它如何随着时间的推移而发展,以及最重要的是,如何有效地使用它。
我们将从两个不同的角度来看分桶—一个是数据分析师的角度,他是数据的典型用户;另一个是数据工程师的角度,他负责准备数据并将其展示给数据用户。
在本报告中,我们将讨论 Spark 3.1.1 中对 bucketing 的最新增强,这是撰写本文时的最新版本,对于代码,我们将使用 PySpark API。
什么是 bucketing?
让我们从这个简单的问题开始。Spark 中的分桶是一种如何以特定的方式组织存储系统中的数据的方式,以便可以在后续的查询中利用它,从而变得更加高效。如果存储桶设计得很好,这种效率的提高与避免查询中的连接和聚合混乱特别相关。
具有排序-合并联接或混排-散列联接以及聚合或窗口函数的查询要求数据按联接/分组键重新分区。更具体地说,具有相同联接/分组键值的所有行必须在同一个分区中。为了满足这一要求,Spark 必须对数据进行重新分区,为了实现这一点,Spark 必须将数据从一个执行器物理地移动到另一个执行器——Spark 必须进行所谓的洗牌(有关 Spark 用来确定是否需要洗牌的逻辑的更多详细信息,请参见我的另一篇与该主题密切相关的文章。
有了 bucketing,我们可以提前洗牌,并以这种洗牌前的状态保存数据。在从存储系统读回数据后,Spark 将会意识到这种分布,并且不需要重新洗牌。
如何使数据分桶
在 Spark API 中,有一个函数 bucketBy 可用于此目的:
(
df.write
.mode(saving_mode) # append/overwrite
.bucketBy(n, field1, field2, ...)
.sortBy(field1, field2, ...)
.option("path", output_path)
.saveAsTable(table_name)
)
这里有四点值得一提:
- 我们需要将数据保存为表格(一个简单的保存函数是不够的),因为关于分桶的信息需要保存在某个地方。调用 saveAsTable 将确保元数据保存在 metastore 中(如果配置单元 metastore 设置正确的话), Spark 可以在访问表时从那里获取信息。
- 与 *bucketBy、*一起,我们也可以调用 sortBy ,这将按照指定的字段对每个桶进行排序。调用 sortBy 是可选的,分桶也可以在没有排序的情况下工作。反过来也不行——如果不调用 bucketBy ,就不能调用 sortBy 。
- bucketBy 的第一个参数是应该创建的桶的数量。选择正确的数量可能很棘手,最好考虑数据集的整体大小以及所创建文件的数量和大小(参见下面更详细的讨论)。
- 不小心使用 bucketBy 函数可能会导致创建过多的文件,并且在实际写入之前可能需要对数据帧进行自定义重新分区——参见下面关于此问题的更多信息(在从数据工程师的角度进行分桶部分)。
数据是如何在存储桶之间分布的?
因此,我们知道分桶会将数据分发到一些桶/组中。您现在可能想知道这些桶是如何确定的。有了一个特定的行,我们知道它将在哪个桶中结束吗?嗯,是的!粗略地说,Spark 使用一个应用于 bucketing 字段的散列函数,然后计算这个散列值模应该创建的桶数(hash(x) mod n)。这个模操作确保创建的存储桶不超过指定的数量。为了简单起见,让我们首先假设在应用散列函数之后我们得到这些值:(1,2,3,4,5,6)并且我们想要创建 4 个桶,所以我们将计算模 4。模函数返回整数除法运算后的余数:
1 mod 4 = 1 # remainder after the integer division
2 mod 4 = 2
3 mod 4 = 3
4 mod 4 = 0
5 mod 4 = 1
6 mod 4 = 2
计算出的数字就是最终的桶。如您所见,我们只是将这六个值分配到四个桶中
(1, 2, 3, 4, 5, 6 ) -> (1, 2, 3, 0, 1, 2)
更确切地说,Spark 不是使用简单的模函数,而是所谓的正模,它确保最终的桶值是一个正数,定义如下:
b = value mod nif b < 0:
b = (b + n) mod n
因此,如果桶值为负,我们将添加 n (桶数)并再次计算对取模,这将不再是负的。让我们假设这个例子,其中散列函数返回负数-9,我们想要计算它属于哪个桶(仍然假设我们使用四个桶):
n = 4
value = -9b = value mod n = -9 mod 4 = -1# be is negative so we continue:
b = (b + n) mod n = (-1 + 4) mod 4 = 3 mod 4 = 3
因此值-9 将属于第 3 个存储桶。
Spark 使用的哈希函数是通过 MurMur3 哈希算法实现的,该函数实际上是在 DataFrame API 中公开的(参见文档),因此如果我们需要,我们可以使用它来计算相应的桶:
from pyspark.sql.functions import hash, col, expr(
spark.range(100) # this will create a DataFrame with one column id
.withColumn("hash", hash(col("id")))
.withColumn("bucket", expr("pmod(hash, 8)"))
)
在这里,我们可以看到,如果我们使用带有 8 个存储桶的列 id 的存储桶,数据将如何分布到存储桶中。注意, pmod 函数是在 expr 内部调用的,因为该函数在 PySpark API 中不直接可用,但在 SQL 中可用(要查看关于如何将 expr 函数与 SQL 函数一起使用的更多信息,可以查看我最近的关于 DataFrame 转换的文章)。
桶装的优势
分桶的主要目的是加快查询速度,提高性能。分桶主要在两个方面有所帮助,第一个方面是避免在使用连接和聚合的查询中出现混乱,第二个方面是通过称为分桶修剪的特性来减少 I/O。让我们在下面的小节中更详细地了解这两种优化机会。
无洗牌连接
如果您要连接两个表,并且这两个表都不是特别小,Spark 将必须确保这两个表以相同的方式分布在集群上(根据连接键),因此将对数据进行混洗(这两个表都将被混洗)。在查询计划中,您将在连接的两个分支中看到一个交换操作符。让我们看一个例子:
tableA.join(tableB, 'user_id')
如果计划使用排序合并连接,则执行计划将如下所示:

作者图片
正如您所看到的,连接的每个分支都包含一个代表 shuffle 的交换操作符(注意 Spark 并不总是使用排序-合并连接来连接两个表——要查看 Spark 选择连接算法所使用的逻辑的更多细节,请参阅我的另一篇关于 Spark 3.0 中的连接的文章)。
但是,如果两个表都被连接键存储到相同数量的存储桶中,Spark 将读取具有这种特定分布的集群上的数据,因此不需要额外的重新分区和洗牌——计划中将不再出现交换操作符:

作者图片
单向无洗牌加入
一个有趣的问题是,如果只有一个表被分桶,而另一个没有,会发生什么情况。答案实际上取决于桶的数量和洗牌分区的数量。如果存储桶的数量大于或等于洗牌分区的数量,Spark 将只洗牌连接的一边——没有被存储桶的表。但是,如果桶的数量少于混洗分区的数量,Spark 将混洗两个表,并且不会利用其中一个表已经被很好地分布的事实。随机分区的默认数量是 200,可以通过以下配置设置进行控制:
spark.conf.set("spark.sql.shuffle.partitions", n)
因此,如果我们使用默认设置(200 个分区),其中一个表(比如说 tableA )被分成 50 个桶,而另一个表( tableB )根本没有被分成桶,那么 Spark 会将两个表进行混洗,并将这些表重新分成 200 个分区。
为了确保利用表 A 的分桶,我们有两个选择,或者我们将洗牌分区的数量设置为桶的数量(或者更小),在我们的例子中是 50,
# if tableA is bucketed into 50 buckets and tableB is not bucketedspark.conf.set("spark.sql.shuffle.partitions", 50)tableA.join(tableB, joining_key)
或者,我们通过显式调用 repartition 将表 B 重新分区为 50 个分区,如下所示:
(
tableA
.join(tableB.repartition(50, joining_key), joining_key)
)
这两种技术都将导致单向无洗牌连接,这也可以从查询计划中看出,因为交换操作符将只出现在连接的一个分支中,因此只有一个表将被洗牌。
具有不同存储桶编号的表
这里还有一种情况我们可以考虑。如果两个表都分桶,但是分入不同数量的桶中,会怎么样呢?将会发生什么取决于 Spark 版本,因为在 3.1.1 中对这种情况进行了增强。
在 3.1 之前,情况实际上类似于前面的情况,其中只有一个表被分桶,而另一个没有,换句话说,两个表都将被混洗,除非满足混洗分区和桶数量的特定条件,在这种情况下,只有一个表将被混洗,我们将获得一个单边无混洗连接。这里的条件与前面类似—洗牌分区的数量必须等于或小于较大表的桶的数量。让我们在一个简单的例子上更清楚地看到这一点:如果 tableA 有 50 个桶, tableB 有 100 个,洗牌分区的数量是 200(默认),在这种情况下,两个表都将被洗牌为 200 个分区。然而,如果混洗分区的数量被设置为 100 或更少,则只有表 A 将被混洗到 100 个分区中。类似地,我们也可以将其中一个表重新划分为另一个表的桶数,在这种情况下,在执行过程中也只会发生一次洗牌。
在 Spark 3.1.1 中,实现了一个新特性,如果桶数是彼此的倍数,它可以将较大数量的桶合并成较小数量的桶。这个特性默认是关闭的,可以用这个配置设置spark . SQL . bucketing . coalescebucketsinjoin . enabled来控制。因此,如果我们打开它,再次将表 A 存储到 50 个桶中,表 B 存储到 100 个桶中,那么连接将是无洗牌的,因为 Spark 将把表 B 合并到 50 个桶中,所以两个表将具有相同的编号,这将与洗牌分区的数量无关。
那种呢?
我们已经看到,通过分桶,我们可以从排序-合并连接计划中消除交换。该计划还包含排序操作符,就在交换之后,因为必须对数据进行排序才能正确合并。我们能不能也取消排序?您可能想说是,因为分桶也支持排序,我们可以在 bucketBy 之后调用 sortBy 并对每个桶进行排序,这样在连接期间就可以利用这一点。然而,sort 的情况更加复杂。
在 Spark 3.0 之前,如果每个存储桶恰好由一个文件组成,那么可以从连接计划中删除排序操作符。在这种情况下,Spark 确信在集群上读取数据后对数据进行了排序,实际上最终的计划是 Sort- free。然而,如果每个桶有更多的文件,Spark 不能保证数据是全局排序的,因此在计划中保留了 Sort 操作符——数据必须在连接执行期间排序。(参见下面的从数据工程师的角度分桶一节,了解如何实现每个桶一个文件。)
在 Spark 3.0 中,这种情况发生了变化,默认情况下,即使每个存储桶只有一个文件,也会出现排序。这种变化的原因是列出所有文件来检查每个存储桶是否只有一个文件太昂贵(如果有太多文件),所以决定关闭这种检查,并在计划中一直使用排序(用于排序-合并连接)。如你所见,这是一种权衡,一种优化对另一种优化。还引入了一个新的配置设置spark . SQL . legacy . bucket edtablescan . output ordering,您可以将它设置为 True 以强制执行 3.0 之前的行为,并且仍然利用一个文件的排序桶。
无洗牌聚合
与联接类似,聚合也要求数据在集群上正确分布,通常 Spark 将不得不对数据进行洗牌,以便进行以下查询:
# this requires partial shuffle if tableA is not bucketed:
(
tableA
.groupBy('user_id')
.agg(count('*'))
) # this requires full shuffle if tableA is not bucketed :
(
tableA
.withColumn('n', count('*').over(Window().partitionBy('user_id')))
)
然而,如果字段 user_id 对 tableA 进行分桶,那么两个查询都将是无洗牌的。
桶形修剪
Bucket pruning 是 Spark 2.4 中发布的一个特性,它的目的是减少 I/O,如果我们在表被分桶的字段上使用过滤器的话。让我们假设以下查询:
spark.table('tableA').filter(col('user_id') == 123)
如果表不是分桶的,Spark 将不得不扫描整个表来查找这个记录,如果表很大,它可能需要启动和执行许多任务。另一方面,如果表是分桶的,Spark 将立即知道这一行属于哪个桶(Spark 用模计算散列函数以直接看到桶号),并且将只从相应的桶中扫描文件。而 Spark 又是如何知道哪些文件属于哪个桶的呢?每个文件名都有一个特定的结构,不仅包含它所属的存储桶的信息,还包含哪个任务生成了该文件,如图所示:

作者图片
如果表非常大,桶形修剪可以大大加快速度。
桶装的缺点
我们刚刚描述了 bucketing 可以提供的优势。你可能想知道是否也有一些缺点,或者只是一些最好避免它的情况。实际上,分桶的一个结果是值得记住的,那就是执行过程中的并行化。如果一个表被分成 n 个桶,并且您将查询它,那么结果作业的第一阶段将正好有 n 个任务。另一方面,如果表没有分桶或者分桶被关闭,许多任务可能会非常不同,因为 Spark 会尝试将数据划分到分区中,每个分区大约有 128 MB(这由配置设置Spark . SQL . files . maxpartitionbytes控制),因此任务具有合理的大小,不会遇到内存问题。
如果一个表被分桶,并且随着时间的推移它的大小增加,桶变大,那么关闭分桶以允许 Spark 创建更多的分区并避免数据溢出问题可能会更有效。这非常有用,尤其是当查询不执行任何可能直接利用 bucketing 提供的分布的操作时。
在 Spark 3.1.1 中,实现了一个新特性,它可以根据查询计划(没有连接或聚合)识别分桶没有用的情况,并将关闭分桶,因为它将丢弃分布,并以与未分桶相同的方式扫描数据。该功能默认开启,可由spark . SQL . sources . bucket ing . autobucketedscan . enabled配置设置控制。
从数据分析师的角度来看
数据分析师想要查询数据,而在理想情况下,他/她不想关心表如何存储在数据湖中的细节。嗯,我们并不是生活在一个理想的世界中,有时了解一些关于表的细节仍然是有用的,以便利用更快的执行和实现更好的性能。重要的是至少能够检查查询中是否利用了分桶,或者是否可以利用分桶,换句话说,是否有一种方法可以轻松地提高查询的性能。
桌子是桶装的吗?
要查看一个表是否被分桶以及如何分桶,我们只需通过调用 SQL 语句来检查关于该表的详细信息
spark.sql("DESCRIBE EXTENDED table_name").show(n=100)

作者图片
从这里,您可以看到该表是否分桶,哪些字段用于分桶,以及该表有多少个桶。注意,我们在这里调用了 show(n=100) ,因为默认情况下 show 函数只显示 20 行,但是如果表的模式很大,关于分桶的信息将不会出现在前 20 行中,所以请注意,根据表的不同,可能需要显示更多的行来查看分桶信息。
我的查询中是否利用了分桶?
首先,必须启用分桶,这是默认的,但是如果您不确定,可以按如下方式进行检查
spark.conf.get("spark.sql.sources.bucketing.enabled")
并且它应该返回真值。此配置设置可用于控制存储是打开还是关闭。
如果一个表被分桶,关于它的信息将保存在 metastore 中。如果我们希望 Spark 使用它,我们需要以表的形式访问数据(这将确保 Spark 从 metastore 获得信息):
# Spark will use the information about bucketing from metastore:
df = spark.table(table_name)# Spark will not use the information about bucketing:
df = spark.read.parquet(path_to_data)
请注意,在第二种情况下,我们直接从路径访问数据,Spark 将不会与 Hive metastore 通信,也不会获得有关分桶的信息—分桶将不会被使用。
最后但同样重要的是,我们可以检查查询计划,看看在计划中我们想要避免的地方是否有交换操作符。
我能帮火花吗?
通常,如果表存储在相同数量的存储桶中,存储桶将开箱即用。但在某些情况下,Spark 将无法利用分桶,我们实际上可以帮助它工作。为了有个概念,让我们来看看这些情况。
在 Spark 3.0 之前,如果分桶列在我们想要连接的两个表中具有不同的名称,并且我们将数据帧中的列重命名为具有相同的名称,则分桶将停止工作。例如, tableA 由 user_id、分桶, tableB 由 userId 分桶,列的含义相同(我们可以对其进行联接),但名称不同(user _ idvsuserId)。在以下查询中,将不会完全利用存储桶:
# The bucketing information is discarded because we rename the
# bucketed column and we will get extra shuffle:
(
tableA
.withColumnRenamed('user_id', 'userId')
.join(tableB, 'userId')
)
为了让它工作,我们需要保留原来的名字:
# Here bucketing will work:
(
tableA
.join(tableB, tableA['user_id'] == tableB['userId'])
)
Spark 3.0 修复了这个问题,因此重命名列不再是问题。
另一件需要注意的事情是连接列的数据类型——它们需要相同。让我们假设这个例子: tableA 被整数类型的 user_id 分桶, tableB 也被整数类型的 user_id 分桶,但是它是长类型的,并且两个表都被分桶到 50 个桶中。在这种情况下,每个表中连接列的数据类型都不同,因此 Spark 必须对其进行转换,丢弃存储桶信息,并且两个表都将被打乱:
# both tables will be shuffled if user_id has different data type
# in both tables:tableA.join(tableB, user_id)
非常不幸的是,这两个表是用不同的数据类型为一个具有相同含义的列创建的。然而,我们可以帮助 Spark 实现至少一方的无洗牌连接,如下所示:
(
tableA
.withColumn('user_id', col('user_id').cast('long'))
.repartition(50, 'user_id')
.join(tableB, 'user_id')
)
如您所见,我们显式地将两个表中的数据类型转换为相同,然后将更改后的表重新分区为与另一个表相同数量的分区。洗牌将只发生在我们重新分配它的这一边,另一张桌子将不洗牌。这基本上相当于只有一个表被分桶,而另一个没有。
本节中的最后一个示例与在带有连接的查询中使用用户定义的函数(UDF)有关。我们需要记住,UDF 将丢弃关于分桶的信息,所以如果我们在连接之前调用 UDF,将导致相同的情况,就好像只有一个表被分桶。要么两个表都将被混洗,要么如果我们对表进行重新分区,或者如果我们将混洗分区的数量设置为存储桶的数量,我们将得到单向无混洗连接:
# Spark will shuffle both tables because of the UDF
(
tableA.withColumn('x', my_udf('some_col'))
.join(tableB, 'user_id')
)# One-side shuffle-free join:
(
tableA.withColumn('x', my_udf('some_col'))
.repartition(50, 'user_id') # assuming we have 50 buckets
.join(tableB, 'user_id')
)# One-side shuffle-free join:
# set number of shuffle partitions to number of buckets (or less):spark.conf.set('spark.sql.shuffle.partitions', 50)
(
tableA.withColumn('x', my_udf('some_col'))
.join(tableB, 'user_id')
)
如果我们想完全避免混乱,我们可以在加入后简单地调用 UDF
(
tableA
.join(tableB, 'user_id')
.withColumn('x', my_udf('some_col'))
)
从数据工程师的角度来看
数据湖中的表通常是由数据工程师准备的。他们需要考虑如何使用数据,并准备好数据,以便为数据用户(通常是数据分析师和科学家)的典型用例服务。分桶是需要考虑的技术之一,类似于分区,分区是在文件系统中组织数据的另一种方式。现在让我们看看数据工程师通常必须面对的一些问题。
如何创建分桶表
我们已经看到上面使用函数 bucketBy 的查询。实际上的问题是控制创建文件的数量。我们需要记住,Spark 作业最后阶段的每个任务都将为它携带数据的每个存储桶创建一个文件。让我们假设这个例子,其中我们处理一个 20 GB 的数据集,我们在最后一个阶段将数据分布到 200 个任务中(每个任务处理大约 100 MB),我们希望创建一个有 200 个存储桶的表。如果集群上的数据是随机分布的(这是一般情况),这 200 个任务中的每一个都将携带这 200 个存储桶中的每一个的数据,因此每个任务将创建 200 个文件,导致 200 x 200 = 40 000 个文件,其中所有最终文件都将非常小。您可以看到,结果文件的数量是任务数量与请求的最终存储桶数量的乘积。
我们可以通过在群集上实现我们希望在文件系统(存储)中实现的相同分布来解决这个问题。如果每个任务只有一个存储桶的数据,在这种情况下,每个任务将只写一个文件。这可以通过写入前的自定义重新分区来实现
(
df.repartition(expr("pmod(hash(user_id), 200)"))
.write
.mode(saving_mode) # append/overwrite
.bucketBy(200, 'user_id')
.option("path", output_path)
.saveAsTable(table_name)
)
这将为每个存储桶创建一个文件。如您所见,我们通过 Spark 使用的相同表达式对数据进行重新分区,以便在存储桶之间分配数据(有关如何工作的更多详细信息,请参见上面的相关部分)。实际上,您可以在这里使用更简单的 df.repartition(200,' user_id') 来获得相同的结果,但是上述方法的优点是,如果您希望同时按照如下所示的另一个字段对文件系统中的数据进行分区,它也可以工作
(
df
.repartition(200, "created_year",expr("pmod(hash(user_id), 200)"))
.write
.mode(saving_mode)
.partitionBy("created_year")
.bucketBy(200, "user_id")
.option("path", output_path)
.saveAsTable(table_name)
)
这里,每个文件系统分区将正好有 200 个文件(每个存储桶一个文件),因此文件总数将是存储桶的数量乘以文件系统分区的数量。请注意,如果您只调用 df.repartition(200,“created_year”,“user_id”),这是行不通的。
如何确定合理的桶数
这可能很棘手,取决于更多的情况。考虑最终存储桶的大小很重要——请记住,当您读回数据时,一个存储桶将由一个任务处理,如果存储桶的大小很大,任务将遇到内存问题,Spark 将不得不在执行期间将数据溢出到磁盘上,这将导致性能下降。根据您将对数据运行的查询,每个存储桶 150-200 MB 可能是一个合理的选择,如果您知道数据集的总大小,您可以据此计算要创建多少个存储桶。
实际上,情况更加复杂,人们必须面对以下挑战:
- 该表不断被追加,其大小随着时间的推移而增长,桶的大小也是如此。在某些情况下,如果数据集也按某个日期维度(例如年和月)进行分区,并且存储桶均匀地分布在这些分区上,这可能仍然没有问题。如果典型的查询总是只要求最近的数据,例如最近 6 个月,我们可以设计存储桶,使合理的大小对应于 6 个月的数据。存储桶的总大小会增长,但这没有关系,因为我们永远不会请求整个存储桶。
- 数据是不对称的,如果存储关键字的某个特定值的记录比该关键字的其他值多得多,就会出现这种情况。例如,如果表按 user_id 分桶,则可能有一个特定的用户有更多的交互/活动/购买或数据集表示的任何内容,这将导致数据倾斜——处理这个更大桶的任务将比其他任务花费更长的时间。
存储功能的演变
Spark 本身也在随着每个新版本不断发展和改进。此外,分桶功能在最近几个版本中也有所改进,所以让我们在这里提一下其中的一些改进:
Spark 2.4 的改进
- 桶形修剪(参见吉拉 )—在桶形字段上使用过滤器减少 I/O。
Spark 3.0 的改进
- 丢弃关于排序的信息(参见吉拉)——这并不是对分桶的真正改进,而是相反。更改后,排序-合并连接总是需要排序,不管存储桶是否已经排序。这样做是为了有一个更快的解释命令,该命令需要做文件列表来验证每个桶是否只有一个文件。有一个配置设置可以恢复原来的行为(spark . SQL . legacy . bucketedtablescan . output ordering,默认情况下它是 False ,所以如果您想在连接期间利用排序的存储桶,您需要将其设置为 True )。另外,请参见上面相关部分中关于排序的讨论。
- 尊重输出分区中的别名(参见吉拉 ) —它确保排序-合并连接对于分桶表是无混乱的,即使我们重命名了分桶列。
Spark 3.1 的改进
- 合并用于连接的分桶表(参见吉拉 ) —如果两个表具有不同数量的桶,则启用无洗牌连接。请参见上面相关章节中关于该功能的讨论。
- 通过规则启用/禁用分桶(参见吉拉 ) —如果不能在查询中利用,该规则将关闭分桶。
未来的改进
这里列出了一些在撰写本文时(2021 年 4 月)尚未实现的特性:
- 添加存储桶扫描信息进行解释(参见吉拉 ) —如果在查询计划中使用存储桶,请查看该信息
- 读取多个排序桶文件(见吉拉 ) —即使每个桶有更多文件,也要利用排序桶进行排序合并连接
- 配置单元分桶写支持(见吉拉 ) —启用与配置单元分桶的兼容性(因此 Presto 也可以利用它)
与存储桶相关的配置设置
在整篇文章中,我们已经看到了其中的一些,但是让我们在这里列出它们,把它们放在一个地方:
- spark . SQL . sources . bucket ing . enabled—控制分桶是否打开/关闭,默认为 True 。
- spark . SQL . sources . bucket ing . max buckets-可用于表的最大存储桶数。默认情况下,它是 100 000。
- spark . SQL . sources . bucketing . autobucketedscan . enabled-如果存储信息没有用,它会将其丢弃(基于查询计划)。默认情况下为真。
- spark . SQL . bucketing . coalescebucketsinjoin . enabled-如果两个表的存储桶数量不同,它会将编号较大的表的存储桶与另一个表的存储桶合并在一起。只有当两个数字互为倍数时才有效。它还受到下一个配置设置的约束。默认情况下,为假。
- spark . SQL . bucket ing . coalescebucketsinjoin . maxbuckertratio-两个存储桶编号进行合并工作的最大比率。默认情况下,它是 4。换句话说,如果一个表的存储桶数量是另一个表的 4 倍以上,合并将不会发生。
- Spark . SQL . legacy . bucketedtablescan . output ordering—使用 Spark 3.0 之前的行为来利用分桶中的排序信息(如果每个桶有一个文件,这可能会很有用)。默认情况下,为假。
- spark.sql.shuffle.partitions —控制随机分区的数量,默认情况下为 200。
最终讨论
在本报告中,我们从不同的角度描述了分桶操作。我们已经看到了数据工程师在创建分桶表时需要处理的一些问题,比如选择合理数量的桶和控制创建的文件的数量。我们还讨论了 data analyst 视图—分桶表提供了优化机会。在许多情况下,这些机会被 Spark out of the box 所利用,但是在某些情况下,需要特别注意利用挖掘潜力。这种情况发生在存储桶细节不同的表的连接中,例如,表具有不同数量的存储桶,存储桶列具有不同的名称或数据类型,这里我们已经看到,通过使用数据帧的显式重新分区或改变混洗分区的数量以满足存储桶的数量的简单技巧,至少可以实现单侧无混洗连接。
R 编程的最佳实践
原文:https://towardsdatascience.com/best-practices-for-r-programming-ec0754010b5a?source=collection_archive---------22-----------------------

摄影:@ karst en _ wuerth—Unplash.com
作为一个有统计学背景的人,我承认我必须不断提高我的计算机科学和工程技能,几乎每天都是如此。虽然在分析数据时考虑分布、统计和其他关键概念对我来说是很自然的,但编写高效、干净的代码却不是。
幸运的是,我有机会与许多工程师一起工作,他们教导并解释了为什么代码需要干净和高效——如果我可以用一句话来总结这一需求,最好的一句话来自约翰·多恩的诗(这句话几乎有 400 年的历史了!):‘没有人是孤岛’。
说到开发我们的代码和脚本,我们不是一个孤岛。当作为一名数据科学家、分析师(或几乎任何其他职业)工作时,协作是最重要的技能之一——如果你想以分析数据为职业,未来有人不得不查看你的代码的概率可能是 99.99%。您的代码组织得越好,将来就越容易被人查看、调试和改进。而且这并不排斥你可能必须去做的其他人,它也将为你未来的自己省去很多麻烦(那些从来没有看着自己的代码并想:“我到底在这个函数中做了什么?))
因此,让我们直接进入 R 编程的一些常见的最佳实践(有些有争议,有些被社区广泛接受)!
图书馆第一
应该放入 R 脚本的第一件事是你的库——你的代码的依赖关系应该在一开始就明确。这将避免有人在运行代码时感到惊讶,因为其中一个导入隐藏在代码中间,而用户没有为此准备好环境。
大多数风格指南都同意这一建议,您应该避免这样做:
my_vector <- c(1,2,3)library(readxl)read_excel(path_file)
在导入库 readxl — 之前,创建一个向量 my_vector ,这通常是一个不好的做法。
我发现唯一可以打破这一规则的地方是在教学过程中——例如,当一个人在一个依赖于库的讲座中引入一个新概念时——可以在脚本中间加载该库,以便学生保留正在使用的函数和包含该段代码的库的可视引用。
硬编码变量次之
另一个普遍接受的规则是硬编码的变量,如访问数据库的路径或配置文件(如果您有密码,最好看看这篇文章来管理机密:https://cran . r-project . org/web/packages/httr/vignettes/secrets . html)在脚本的开头,在导入库之后。
许多脚本都使用 csv 或 xlsx 文件中的数据,因此一般最佳做法是执行以下操作:
library(readxl)path_file <- "data/data.csv"my_df <- read_excel(path_file)
这样,无论谁读了你的代码,都有两个重要的信息:
- 你的代码依赖于哪些库。
- 源文件夹结构应该包含哪些文件和文件夹。
哦,关于文件路径..
绝对路径上的相对路径
绝对路径从来都不是应该走的路。当您在操作系统用户结构中的文件夹上工作时,这一点尤其重要。
绝对路径如下所示:
"C:\Users\ivopb\My Documents\R Project\data\data.csv"
如果我把我的代码传递给需要在他们机器上运行它的人,除非他们有用户名 ivopb, 否则他们永远也不能在我们使用这个文件的地方运行代码。即使他们在相同的文件夹结构(My Documents/R Project/等)中运行它。).
哦,即使碰巧他们是用户***【ivopb】,*** 但是他们的硬盘中映射了另一个字母,不是***C:***祝你执行代码好运!
通常,相对路径总是首选的:
"data\data.csv"
这将迫使您将工作目录设置为您正在工作的文件夹,或者从文件夹中打开脚本——这确实比调试和更改脚本中的大量路径要好得多!
命名约定—文件名
对于文件名,总是使用易于理解的文件名,不要在文件名中使用空格(我实际上在我的课程脚本中犯了这个错误,试图匹配 Udemy 上的讲座名称,我将来可能会改变这一点)——一个好的和坏的例子:
# Good example
my_file.R# Bad example
My File.R
此外,在脚本名称中尽量使用小写字母。例如,如果您的脚本的目标是在 csv 文件中创建一些特定数据的聚合,请使用与脚本总体目标相关的名称:
aggregating_data.R
命名约定—对象和函数
这在任何编码语言中都是一个热门话题——人们倾向于争论哪种命名约定是最好的。
除了你选择的命名约定之外,一定要在整个脚本中遵循相同的命名约定——对我来说,这是一个通用的黄金法则。
我喜欢用蛇皮箱(使用 _ )作为物件,用骆驼或蛇皮箱作为功能,但这有待讨论。一个例子:
# Good
my_vector <- c(1,2,3)# Bad
myvector <- c(1,2,3)# Good
ThisFunction()
this_function()# Bad
thisfunction()
此外,您的对象和函数名称应该尽可能明确和简短,想象一个接受一个元素并计算一个数的幂的函数:
ComputePowerOfBaseWithExponent <- function (base, exponent) {
return (base**exponent)
}
函数名确实很长,所以我们可以缩短它,通常建议这样做:
ComputePower <- function (base, exponent) {
return (base**exponent)
}
再说一遍,我唯一的黄金法则是在整个剧本中保持风格一致。
返回
这与变量和函数的命名一样,是社区中最有争议的话题之一(看一下这个帖子来检查争论的双方——https://stack overflow . com/questions/11738823/explicitly-calling-return-in-a-function-or-not
每个函数末尾的 R 中的 Return 语句增加了冗余—这是事实。注意,我在上面的例子中使用了显式返回:
ComputePower <- function (base, exponent) {
return (base**exponent)
}
可以从函数中删除返回语句,从显式返回改为隐式返回:
ComputePower <- function (base, exponent) {
base**exponent
}
使用显式返回对代码的速度有一点点影响——增加了一点点(它通常非常小,几乎无法辨认)。
我倾向于认为显式返回对于所有级别的 R 程序员都更容易,因为显式返回让初学者更容易理解代码的流程。但这主要是程序员的选择——当谈到这一点时,人们往往会站在两边,我个人的观点是,我认为指责任何使用隐式或显式回报的人都是不公平的。
在循环中显式
在对象上进行循环时,一件重要的事情是显式命名正在循环的元素。
让我们想象下面的练习:你有一个特定人群的年龄向量,你想用“主要”或“次要”来分类,你使用 for 循环(为了讨论,让我们忽略我们可以使用的更好实现的其他方法):
ages_people = c(10, 20, 20, 30, 40)ClassifyAge <- function (ages) {
age_class <- c()
for (age in ages) {
if (age < 18) {
age_class <- c(age_class, 'Minor')
}
else {
age_class <- c(age_class, 'Major')
}
}
age_class
}
如果我们将 for 循环中的 age 称为 i 或 元素:
ages_people = c(10, 20, 20, 30, 40)ClassifyAge <- function (ages) {
age_class <- c()
for (i in ages) {
if (i < 18) {
age_class <- c(age_class, 'Minor')
}
else {
age_class <- c(age_class, 'Major')
}
}
age_class
}
通常最好是显式命名循环的元素——在上面的例子中,我们是基于一个 年龄 来做一些事情,因此最好将循环元素命名为 年龄 而不是 i、元素 或*。这将使不熟悉代码的人更容易理解代码在功能级别上做什么。*
对对象赋值使用
这是社区上的另一个热门话题——在创建对象或函数时,我倾向于使用-<-,尽管在这种情况下 = 的表现完全相同。大多数风格指南同意这一点,但没有一个放之四海而皆准的意见。
一个普遍接受的规则是,当你使用
*# Good example
my_vector <- c(1, 2, 3)# Bad example
my_vector<-c(1, 2, 3)*
Of course, as I intertwine a lot between Python and R scripts, sometimes the naughty = 的时候就完成了赋值:-)
线长度
避免每行超过 80 个字符,以便您的代码可以适合大多数 IDE 窗口。这也是其他编程语言(如 Python)的最佳实践。您希望避免脚本的读者来回使用水平滚动条(这是一个容易迷失在代码中的方法)。
想象一个函数,用很长的参数调用:
*CalculatesMeaningOfLife('This is a really long argument','This is another really long argument','This is a third really long argument!')*
调用此代码时的一般最佳做法是执行以下操作:
*CalculatesMeaningOfLife(
'This is a really long argument',
'This is another really long argument',
'This is a third really long argument!'
)*
R Studio 有一些自动缩进,当你在逗号后按回车键。这是一个简洁的特性,它使得我们的代码更容易保持整洁。
间隔
当调用函数或索引对象时,在每个*、*之后提供一个空格总是一个好主意。这使得代码可读性更好,避免了“压缩代码”的想法。压缩代码是当我们有如下:
*my_array = array(1:10,c(2,5))
my_array[,c(1,2)]*
代码可以工作,但是所有的代码都被捆绑在一起,没有空格。从视觉上看,很难理解哪个位是指数组中的第一维还是第二维。
更干净的方法是执行以下操作:
*my_array = array(1:10, c(2, 5))
my_array[, c(1, 2)]*
请注意我是如何在代码中的每个逗号后添加一个空格的。这就是人们通常所说的让代码呼吸— 你可以更容易地理解你在每个维度上索引了什么,以及你的函数调用的每个参数包含了什么。
不要重复自己的话
*任何编程语言(至少是函数式语言)中最重要的概念之一是 **DRY 的概念。*一条普遍的黄金法则是,当你发现自己复制并粘贴了大量代码时,这是一个函数的好用法。
举一个非常简单的例子,假设我们想用 R:
*paste('Hello','John')
paste('Hello','Susan')
paste('Hello','Matt')
paste('Hello','Anne')
paste('Hello','Joe')
paste('Hello','Tyson')
paste('Hello','Julia')
paste('Hello','Cathy')*
您多次重复相同的代码,只是更改了学生的姓名。在您看来,这应该会立即引发使用功能的需求:
*GreetStudent <- function(name) {
paste(‘Hello’,name)
}class_names <- c(‘John’, ‘Susan’, ‘Matt’ ,’Anne’,
‘Joe’, ‘Tyson’, ‘Julia’, ‘Cathy’)for (student in class_names){
print(GreetStudent(student))
}*
酷的是,现在您可以向我们的 class_names 向量添加更多的学生,并且您可以避免多次重复粘贴命令!
函数确实是 r 中最强大的概念之一。人们应该多次依赖它们,因为它们将使我们的代码高效且可测试。
就是这样!你还有什么要补充吗?
这里有很多我没有涉及的最佳实践,可能还有很多我自己都不知道的。开源语言让我着迷的是它们发展的速度有多快,以及社区如何在开发更好的程序和脚本以实现更高的生产力方面相互支持。
最后一点,记住学习一门新的语言是一项需要时间的技能,对一个人来说成为万事通几乎是不可能的。你周围的每个人,不管他们是多么高级的语言,总是有东西要学,学习的心态是成为一个更好的专业人士和普通人的最佳心态。
随时伸出手如果你想了解更多关于 R 的知识,可以在这里加入我的 R 编程课程: 绝对初学者 R 编程课程
感谢您花时间阅读这篇文章!随意在 LinkedIn 上加我(https://www.linkedin.com/in/ivobernardo/)查看我公司网站(https://daredata.engineering/home)。**
如果你有兴趣接受分析和数据科学方面的培训,你也可以访问我在 Udemy(https://www.udemy.com/user/ivo-bernardo/)上的页面
这个讲座摘自我在 Udemy 平台上的 R 编程课程**——该课程适合初学者和想学习 R 编程基础的人。该课程还包含 50 多个编码练习,使您能够在学习新概念的同时进行练习。****
设置 Python 环境的最佳实践
原文:https://towardsdatascience.com/best-practices-for-setting-up-a-python-environment-d4af439846a?source=collection_archive---------2-----------------------
面向数据科学家的 PYTHON-DEV
pyenv-> Pipx-> poem,python 工具链的三大支柱

作者图片
你是一个数据科学家,刚刚构建了一个 ML 模型,却不能让它在 docker 容器上工作吗?你是否害怕尝试新的 python 版本,因为你不想搞乱你的本地 python 开发环境?您是否同时从事多个副业项目,并希望分别用沙箱保护每个环境?您是否不清楚如何管理您的 python 应用程序从开发到发布的生命周期?
您一直在错误地设置您的 python 环境!
与 python 开发人员不同,数据科学家很少关心他们代码的开发环境和可移植性。代码大部分存在于 jupyter 笔记本上,交给负责部署的开发人员。当您的机器上只有一个版本的 python,并且一直在一个项目上工作时,这种方法非常有效。但是,一旦您开始在需要不同环境的多个 python 版本或多个项目上工作,就越来越难以保护这些环境。
一旦您用沙箱保护了您的环境,您就开始向您的项目添加包,每个包都有它自己的依赖项列表。您需要管理您的依赖关系图,并确保您的合作者能够获得完全相同的依赖关系。
掌握新的 python 版本和开发是提高 python 技能的必要条件。当你开始一个新项目时,你不想成为你的团队中的一个人,这个人对 f 弦感到不舒服,害怕 T2 异步,不理解 T4 海象操作符,并且把你的本地开发环境搞得一团糟。
下面是设置 python 环境来处理这些棘手情况的工具和步骤列表。
Pyenv
每当你有一个全新的操作系统安装,首先安装 pyenv 开始。Pyenv 是一个命令行工具,不依赖于 python 的安装。
您可以为每个项目设置一个全局 python 版本和一个本地 python 版本。例如,您可以拥有 python 的全球版本 3.8.2,但仍然可以在您的项目中试用 python 3.9.2 或 3.10。使用 pyenv ,您可以设置 python 安装的范围。您有一个全局 python 版本,它应该是 python 的一个稳定版本,您应该将它作为大多数项目的基础,然后您可以根据项目需要使用较新或较旧的 python 版本。对于 Windows,有一个可用的端口 pyenv-win 。
Pyenv Cheatsheet
- 列出可用版本并安装:
这将给出可以使用 pyenv 安装的 python 版本列表。该列表可能因操作系统而异。
# List all available python versions
>pyenv install -l
:: [Info] :: Mirror: [https://www.python.org/ftp/python](https://www.python.org/ftp/python)
2.4-win32
2.4.1-win32
2.4.2-win32
…
3.9.0a3
3.9.0a4-win32
3.9.0a4# Install a specific python version
>pyenv install 3.9.0a4# Rehash your new installables. Needed to update pyenv shims.
>pyenv rehash
2.**全球和本地版本:**
既然安装多个 python 版本很简单,那么您可以在多个 python 版本之间切换。即使您的机器上可能有多个 python 版本,您也需要将 1 个版本设置为全局版本。您可以检查您的全局 python 版本,
# Set global python version
>pyenv global 3.9.0a4# Check global python version
>pyenv global
3.9.0a4
与全局版本不同,您可以为特定项目设置特定的 python 版本。比如,你有一个项目在 python 3.8.2 中运行;您可以首先安装 python 版本,然后为该项目设置一个本地 python 版本。这将覆盖全局 python 版本。
# Install other verion of python
>pyenv install 3.8.2# Change directory to your project
>cd DreamProject# Set local python version inside your project
DreamProject>pyenv local 3.8.2# Check your local python version
DreamProject>pyenv local
3.8.2
这将在您的项目中创建一个包含 python 版本的.python-version文件。Pyenv 将使用这个来巧妙地设置 python 版本,只要你在这个目录的范围内。现在您已经设置了 python 版本,您可以打开一个新的终端并进行验证。
Pipx
使用 pipx 安装全局 python 工具。mypy、flake8、black 和 poem 可以使用 pipx 安装一次,然后跨项目重用*。*
保持干燥。当您跨项目重用 python 工具时,最好是全局安装一次,然后跨项目重用。 Pipx 用于全球安装 python 工具。像 mypy 、 flake8 这样的林挺工具,像 black、这样的格式化工具,以及像poems这样的依赖管理工具,都可以在全局范围内安装一次,然后跨项目重用。这有助于只保留这些工具的一个版本,并避免不同项目之间的版本不匹配。如果需要覆盖这个全局版本,您也可以在您的虚拟环境中安装它。
例如,您可以在您的计算机上安装一次black格式化程序,并在多个项目中重用它。
# Verify global python version is active
>pyenv global
3.9.0a4# Install pipx
>pip install pipx# Make sure pipx is added to the path
>pipx ensurepath# Install black globally
>pipx install black# Check if install is successful
>black --version
black, version 20.8b1
现在您已经安装了 black,您可以在您的 IDE 中设置这个路径,以便开始跨项目使用它。
在 vscode 中,可以通过在用户settings.json文件中添加下面一行来设置它,
# Set path for the python executable
“python.formatting.blackPath”: “C:\\Users\\username\\.local\\pipx\\venvs\\black\\Scripts\\black.exe”,
诗意
对于 python 应用程序的整个生命周期来说,诗歌是一个完美的工具。从创建虚拟环境、设置开发环境、安装包、解决依赖性、分发代码、打包和发布代码。
诗歌在项目的整个生命周期中帮助开发者。通常,一个项目从创建一个虚拟环境开始,添加项目所需的包,然后以将应用程序打包给最终用户或在 PyPI 中发布它结束。我们将在下面的诗歌中看到你如何做到这一切。
使用诗歌的 Python 项目生命周期
- **启动诗歌:**这将在您的目录中创建一个
pyproject.toml文件,其中包含与您的项目相关的元信息。您可以打开该文件,稍后再进行编辑。
# Create a directory and setup python version
DreamProject>pyenv local 3.8.2# Initiate poetry. This will ask meta info related to the project. DreamProject>poetry init
This command will guide you through creating your pyproject.toml config.Package name [DreamProject]:
Version [0.1.0]:
Description []:
Author [aspiring_dev <[aspiring_dev@gmail.com](mailto:mak.adi55@gmail.com)>, n to skip]:
License []:
Compatible Python versions [^3.8]:
**2。创建一个虚拟环境:**注意到目前为止我们只创建了一个 toml 文件,我们必须从创建一个虚拟环境开始。这可以如下进行,
# Create virtual environment
DreamProject>poetry shell
Creating virtualenv DreamProject-hJUIGXBx-py3.8 in C:\Users\username\AppData\Local\pypoetry\Cache\virtualenvs
Spawning shell within C:\Users\username\AppData\Local\pypoetry\Cache\virtualenvs\DreamProject-hJUIGXBx-py3.8
Microsoft Windows [Version 10.0.19043.1165]
(c) Microsoft Corporation. All rights reserved.
**3。安装开发/生产包:**对于一个数据科学项目,我们将从安装 pandas 和 ipython 开始。这里需要注意的一点是,并不是所有的包都是平等的。有些是开发包,有些是生产包。您可以在开发和测试时使用 ipython 和 jupyter 笔记本,但是当您将应用程序作为脚本部署在main.py文件中或者公开class或function时,您就不需要它了。这种隔离避免了将开发工具打包到最终版本中,最终版本将交付给最终用户或被部署。
# Add prod packages, will be included in final build
DreamProject>poetry add pandas
Using version ^1.3.1 for pandasUpdating dependencies
Resolving dependencies...Writing lock filePackage operations: 5 installs, 0 updates, 0 removals• Installing six (1.16.0)
• Installing numpy (1.21.1)
• Installing python-dateutil (2.8.2)
• Installing pytz (2021.1)
• Installing pandas (1.3.1)# Add dev packages, will not be included in final build
DreamProject>poetry add ipython --dev
poetry add ipython --dev
Using version ^7.26.0 for ipythonUpdating dependencies
Resolving dependencies...Writing lock filePackage operations: 13 installs, 0 updates, 0 removals• Installing ipython-genutils (0.2.0)
• Installing parso (0.8.2)
• Installing traitlets (5.0.5)
.......
• Installing pygments (2.9.0)
• Installing ipython (7.26.0)
poetry add比pip install强大多了。Pip install 只是从 PyPi 安装软件包,不做任何依赖解析。poem 解决依赖性并为您安装正确的包版本。
每当你的项目增长并开始依赖几个包时,依赖地狱就出现了。您安装的每个软件包都有自己的依赖关系,所以每当您安装或升级一个软件包时,解析这个依赖关系图会变得越来越困难。
例如,假设您为依赖于 request ≤ v2.24.0 的项目安装了包 x,而为依赖于 request >v2.25.0 的项目安装了包 y,即使 x 和 y 包都依赖于 requests,但它们在版本上不兼容,也没有重叠。诗歌会发现并标记这些问题,而匹普不会。随着您不断添加越来越多的包,依赖图呈指数级增长,这变得很困难。但是 poem 确保每次你添加一个包时,它都会为你解决依赖性并安装正确的包版本。
**4。与您的代码和环境协作:**一旦您完成了开发或者您想要与您的团队成员协作,您需要开始使用版本控制和中央存储库。其他人现在可以克隆你的回购协议,并开始工作。传统上,requirements.txt用于建立一个环境并安装所有的包。但是有了 poem,一旦你在本地克隆了 repo,你就可以运行poetry install来安装所有的包和依赖项,安装的顺序和在你的机器上安装的顺序完全一样,从而消除了跨机器设置环境的任何差异。诗歌为你的工作环境和依赖树提供了一个可重复的、精确的副本。
# After cloning the repo run poetry install
DreamProject>poetry install
这将在虚拟环境中安装此项目所需的所有包。
**5。打包并分发您的代码:**在开发和测试之后,是时候打包并分发您的代码了。帮助构建 python 项目。它可以生成package.tar.gz和package.whl两种格式。
最佳实践是使用 wheel 格式而不是 tarballs(源代码分发)。对于 wheel 格式,源代码已经由开发人员构建好了,并且可供用户使用。使用 tarballs,用户获得源代码,并需要将其构建为 wheel 格式,然后安装它。当你没有开发工具并且你的代码库包含多种语言如 c,c++时,从源代码构建是很困难的。与 tarballs 相比,Wheel 文件也更小,非常适合 PyPi 包装和分发。
# Build the project
>poetry build
Building DreamProject (1.0.0)
- Building sdist
- Built dreamproject-1.0.0.tar.gz
- Building wheel
- Built dreamproject-1.0.0-py2.py3-none-any.whl
**6。发布您的代码:**基于开发的类型,您可以将您的代码发布到 PyPi 或者使用私有的存储库。默认情况下,会将您的代码发布到 PyPi
$ poetry publish
Publishing dreamproject (1.0.0) to PyPI
- Uploading dreamproject-1.0.0.tar.gz 100%
- Uploading dreamproject-1.0.0-py2.py3-none-any.whl 58%
备注:
**1。**正如评论中的 Duncan McRae 所指出的,如果 python 版本不兼容,有时包安装会失败。
例如,假设您有一个 3.9 的本地 python 版本。poem 将 python 版本初始化为^3.9,这意味着该环境兼容任何高于 3.9 的 python 版本。但是如果你安装了一个包,比如说scipy,它的依赖项是> =3.9,< 3.10,那么诗歌安装失败。如果出现这种情况,您可能需要打开pyproject.toml文件,并将 python 版本更改为> = 3.9,< 3.10。此行为自版本 1.1.6 起有效,将来可能会改变。
以上是我个人用诗代替康达的原因。
- Conda 不使用 PyPI,有自己的包索引器。官方渠道是几个版本落后于几个软件包,但也有其他渠道有最新版本可用。但是你必须小心你从哪里得到你的软件包的作者。
2.由 Anaconda Inc .拥有,不像 poems 是一个开源项目。
3.Conda 可以访问系统,并可以更改系统二进制文件,不像 poems 那样在虚拟环境中沙箱化,这使它非常适合码头工人。
4.诗与康达兼容。所以您仍然可以使用 conda 来设置复杂的包。
设计与商业软件集成的对话式人工智能的最佳实践
原文:https://towardsdatascience.com/best-practices-in-design-conversational-ai-in-integration-with-business-software-d59db176fef9?source=collection_archive---------41-----------------------

作者图片
介绍
在这篇文章中,我将尝试描述设计与后端软件集成的对话式人工智能。
真实的例子:创建一个由雇员添加时间活动的机器人。使用时间活动,您可以指定日期、在某项任务上花费的时间、将其分配给项目或客户,此外,还可以指定每小时的费率以及是否计费。
步骤 1 —定义意图
在许多情况下,为了设计意图,我试图与机器人的未来用户沟通。您可以写一个故事,解释您请求的目的,以提供不同的话语(意图)示例,他们可以在 bot 中使用这些示例来添加新的时间活动。这一步骤旨在获得来自用户的实时示例,这不仅是为了训练意图和获得更高的置信度,也是为了以最合适的方式设计机器人。
当然,您可以自己设计话语,并开始设计流程,但最终,这可能会导致额外的工作,因为您需要重新构建一切。
例如,你可以设计接下来的话语(意图):

作者图片
而当用户开始使用你的 bot 的时候,你会发现他们会尝试使用其他的话语,很多时候不会像你设计的那么简单。它们可能看起来像这样:

作者图片
上面的例子给了我们很多启示。首先,我们发现这些话语包括像“今天”、“我”、“7 小时”和客户“迪士尼”这样的上下文变量。如果这个人想在最初的信息中提供所有需要的信息,我们需要自动处理它们。在这种情况下,我们不需要要求用户提供关于时间活动的日期、谁执行了时间活动、花费的时间和客户的信息。
当我说我们不需要问额外的问题时,我的意思是:

作者图片
你需要自动识别所有的上下文变量,不要问不必要的问题,因为这会导致糟糕的用户体验。
所以现在,当你有了不同话语的例子,你可以开始设计实体,命名实体识别,对话流,以及与第三方软件的集成。
步骤 2-定义实体
基于用户的话语实例,我们可以起草实体的第一个版本来自动识别上下文变量。有些我们可以轻松处理,有些需要更多的工作。
几乎所有提供开发机器人功能的平台( IBM Watson Assistant 、 Google Dialogflow 、 Amazon Lex )都包括识别日期、数字、时间、货币等的系统实体。
你需要激活它们,你的机器人会识别下一个数据:“今天”、“7 小时”,可能还有“迪士尼”最后一个不太清楚,因为它是一家知名公司,有些平台有识别组织名称的功能,有些没有。此外,您需要考虑到世界上有许多不同的公司名称,可能看起来像“Freezman sporting goods”或“Amy Rudchuk Company”等,在这种情况下,系统实体将不会识别它们或以错误的方式识别它们。
同样,如果我们想一想来自用户的这样的话语:“约翰·史密斯今天和艾米·鲁楚克公司呆了 7 个小时”。
其中“John Smith”是执行时间活动的公司的员工,“Amy Rudchuk company”是客户。这是一个更复杂的例子,因为系统实体可以返回几个对象,例如, entity.person-John Smith 和 entity.person-Amy Rudchuk 。
这是你可以用不同的选择来解决的挑战。这也取决于你用于 bot 开发的平台。
例如,在 IBM Watson Assistant 中,您可以找到实体注释的功能。例如,如果你想让沃森理解所有的名字,你至少要在十个例子中标注名字。这些句子可能包括“我的名字是玛丽·史密斯”,或者“他们叫我约瑟夫·琼斯”。选择每个名称将其高亮显示,然后从弹出菜单中创建或选择一个名为“name”的实体。从现在开始,沃森将理解它以前从未见过的名字,但这些名字被用在相似的句子中。你可以在这里阅读更多关于注释的内容。

作者图片| IBM Watson 助手的用户界面
在 Google Dialogflow 中,您可以使用自动扩展的功能,这可以为自定义实体类型启用自动扩展。启用后,您的代理可以识别尚未明确提供的值。除此之外,您还可以应用模糊匹配和正则表达式实体。

图片作者| Google dialog flow 的用户界面
而有了 Amazon Lex,你可以使用槽的默认功能。除此之外,你可以尝试使用亚马逊理解服务。

图片作者|亚马逊 Lex 的用户界面
尽管如此,您会发现在定义实体时存在一些限制,并且识别的可信度会有所不同。这里的要点是,您可以在一些简单的情况下预定义所有可能的实体,并且您的 bot 可以以最高的置信度识别它们。但是在某些情况下,当您不能预测实体的所有可能的例子时,您需要找到一种方法来利用每个平台的功能进行自动识别。还有一些独立的服务可以帮助您在非结构化文本中识别您所在行业特有的实体和关系。其中一项服务是 IBM 沃森知识工作室。
如果您还记得一些上下文变量(实体值)在默认情况下是被验证的,那将会很有帮助。例如,如果它是一个日期,默认情况下会进行验证,这意味着您不需要执行额外的步骤来验证您是否可以使用该上下文变量中的值。对于客户名称案例,我们需要执行额外的验证,这不是强制性的,但是为了构建更好的用户体验,我们在所有的项目中都执行了这个步骤。
步骤 3-验证实体(可选)
为什么我们需要这一步?在我们的例子中,用户可以提供任何客户名称,我们需要在后端验证它是否存在。假设您正在使用一些企业软件,其中有所有客户的注册信息。因此,在与用户进行对话之前,您需要获取客户名称的上下文变量的值,并在后端检查它。
如果您不执行此操作,您将引导用户直到对话结束,当您试图在您的后端软件中创建时间活动时,您将得到这样一个错误:这样一个客户不存在。对于用户来说,这意味着他或她需要再次重复所有的过程。他们还需要访问企业软件,检查客户的准确姓名,然后重试。这个不适用!这是你在设计机器人时可能面临的最糟糕的情况。
所以现在您需要将 API 发送到后端来验证客户是否存在。如果您感兴趣,我将在另一篇文章中描述通过 API 与后端进行技术集成的选项。尽管如此,我还是想描述一下您在将数据发送到后端时可能面临的挑战。

作者图片
当您将 API 发送到后端以验证客户的名称是否存在于后端时,您将需要评估至少三种不同的响应类型,并设计对话流来处理每一种类型。
选项 1 —一对一匹配。你找到了一个顾客。一切都好。您确信客户存在,并且您可以与用户一起创建时间活动。
选项 2 —存在一对多匹配。你找到了不止一个顾客。在这种情况下,我们建议用户选择应该选择哪个客户。我们可以这样做,因为你将获得关于那些客户的信息,并且你可以向用户显示快速回复按钮。之后,用户可以选择客户,您可以继续。

作者图片
选项 3 —您可以得到空响应,这意味着没有客户匹配上下文变量值。现在,您可以建议用户从整个客户列表中选择客户。

作者图片
此外,您可以评估来自后端的更多响应:情况 1 —当我们从后端接收到错误时,以及情况 2 —当与后端的集成离线时。
未完待续…
点击率模型的 ML 可观察性的最佳实践

作者图片(阿里泽·艾)
在假期及以后保持点击量的小贴士
今年数字广告总支出预计将达到 4553 亿美元。其中,55.2%将用于展示广告,40.2%将用于搜索。随着数字格式占据了广告收入的最大份额,营销人员需要不断优化他们活动的效果。点击率(CTR)是广告商用来帮助量化数字广告效果的一个指标。对于直接回应广告客户来说,点击通常是消费者在线购买的第一步,或者在离线销售数据不可用或难以归因于给定广告的情况下,是购买意图的良好代理。
点击率的计算方法是将点击次数除以印象次数,并将结果表示为百分比。根据最近的基准,所有行业的 Google AdWords 的平均点击率在搜索网络上是 3.17%,在显示网络上是 0.45%。
多年来,机器学习(ML)系统在有效预测点击概率的能力方面变得更加复杂。影响点击率的因素很多,从上下文相关性(广告在哪里投放,在页面上的位置,广告形式等等。)到用户属性(一个人正在使用哪种设备和他们的位置或更深入的第一方人口统计数据、购物历史、媒体消费习惯等数据)。
了解广告选择流程
为了更好地理解机器学习系统如何适应广告生态系统,让我们仔细看看广告选择过程。
超过 90% 的展示和搜索广告是通过编程方式进行交易的。当用户加载网页或应用程序(例如,纽约时报、Expedia、ESPN)或搜索引擎时,该过程开始。然后,向广告交换发送一个请求,其中包含诸如 URL、发布者名称、在页面上的位置、设备、匹配关键字等信息,以及其他帮助广告商更好地锁定特定受众的信息。广告交换然后通过需求侧平台(DSP)将请求提交给多个广告客户。具有匹配标准的广告的广告客户通过发出投标进入拍卖。然后进行拍卖,广告印象归出价最高者所有,广告随后出现在页面上。所有这些都发生在页面加载前的几毫秒内,用户不会察觉。如果用户对广告感兴趣,他们可以点击或采取其他行动;如果没有,他们可能只是滚动过去,或者根本没有注意到它。
ML 驱动的系统存在于交易的双方,提高了出版商的收益和广告商的 T4 业绩。尽管点击率是这篇文章的重点,也是最常用和最容易衡量的关键性能指标之一,但应该注意的是,存在各种各样的模型来优化一切,从电视规划到特定受众,再到视频广告可视性和最大限度地减少僵尸网络流量。

图片来源:Arize AI,IAB |广告技术生态系统
CTR 模型特有的挑战
随着 CTR 模型投入生产,一些常见的挑战可能会导致性能低于预期。其中包括:
- 未知的新趋势: CTR 模型通常根据特定网站(即前 1000 家最受欢迎的新闻发布商)的历史数据以及其他输入进行训练。如果广告交换开始发送对不属于原始训练数据的新的流行网站的投标请求,则广告可能最终被放置在与广告的上下文不一致的页面上,从而导致较低的点击率。这方面的一个例子可能是当 Vice 或 Buzzfeed 等网站开始受欢迎,而人们对广告在这些网站上的表现知之甚少。
- **一天中的时间或季节波动:**一些搜索关键词或显示广告在一年中的某些时段可能或多或少相关,或者在上午与下午相比不太可能被点击。例如,用户可能更有可能在午餐或晚餐时间点击寿司店的搜索广告,而不是在早上上班的路上。有鉴于此,跟踪模型在特定时间段内的表现或退化是至关重要的。
- 关键输入数据错误、损坏或缺失: CTR 模型经常受到数据质量问题的影响,包括缺失数据。如果模型的输入包含设备信息,则此功能的缺失或损坏可能会影响性能。更具体地说,带有“下载应用程序”行动号召的广告可能与移动设备上的某人更相关,并且如果在上下文相关性较低的计算机上发送给某人,则导致较低的点击率。类似地,当用户外出时,位置信息与移动广告商特别相关,可能已经在购物了。移动广告中定位的一个例子是从用户到最近商店的距离。在这些情况下,不可靠的位置数据可能会对 CTR 性能产生负面影响。
ML 监控的最佳实践&CTR 模型的可观察性
一旦你为你的 CTR 模型建立了一个基线和监视器,手头的任务就变成了确定问题的根本原因,并在广告业绩显著下降之前做出反应。由于消费者行为和媒体消费总是在不断变化,因此快速发现问题或行为趋势的变化并采取行动非常重要。
重要指标
评估您的 CTR 模型时,需要注意的一些重要指标包括:
- 日志损失 : 准确度是计算模型做出正确预测的次数的度量。然而,使用展示广告的平均点击率 0.45%,我们的模型可以通过预测“无点击”达到 99%的准确率,但仍然会错过每次点击机会。另一方面,对数损失是用于测量概率模型预测的最佳分类指标之一。 Log loss 回答了模型认为实际观察到的结果有多大可能性的问题。预测值与实际值偏差越大,测井曲线损失越大。在这种情况下,预测得分可能是:“有人点击的可能性有多大?”(例如 0.15,0.2 0.05),实际得分为“有人实际点击了吗?”(例如 0,1,0)。
- PR AUC**:**PR 曲线说明了在各种阈值设置下精度和召回率(PR)之间的权衡, AUC 是曲线下面积(AUC)。精度衡量真正肯定的肯定分类(真肯定和假肯定)的百分比;召回衡量真正的肯定(例如,预测的和实际的点击)相对于所有分类的肯定的百分比,包括那些被错误分类的(例如,假阴性)。通常,当您有一个小的阳性类或不平衡的数据集时,您最关心的是确保每个阳性预测是正确的(精度),并且您获得尽可能多的阳性预测(召回),这种情况下使用 PR-AUC 度量,非常适用于 CTR 模型。
- 预测值与实际值的时间序列:在对您的 CTR 模型进行故障排除时,绘制预测值与实际值的时间序列图可以向您显示您的模型何时遇到问题——这是发现您的模型何时最错误的良好第一步。如果模型有问题,您将看到特定时间段的波动,您可以单击深入了解,调查哪些部分是预测过高或过低的根本原因。
有了这些指标,团队可以更深入地研究性能退化,分析他们的模型是否显示了任何漂移,和/或表面不一致或其他数据质量问题。

图片作者/艾瑞泽 AI: 模型监控 预测与实际
性能下降
一旦发现问题,确定导致性能下降的部分(或一组特征值)是至关重要的。通过过滤各种低性能切片来深入分析您的模型,有助于揭示影响性能的用户行为的特定波动。
再看一个寿司店广告的例子,模特表现突然下降背后的切片可能反映了一个事实,即模特在一天的不同时间没有得到足够的训练——例如在很少有人想吃寿司的清晨时段。然后,ML 团队可以适应性地重新训练模型,以提高一天中不同时间的性能,而不是选择在早餐时间对广告机会或搜索术语进行竞价。
漂移的重要性
作为一名 ML 从业者,随着时间的推移,你可能会遇到漂移或分布变化。监测和排除漂移是每个从业者工具箱的重要组成部分。
尤其是在购物行为和媒体习惯不断变化的广告中,考虑漂移以确保你的模型保持相关性是很重要的。识别各种模型环境和版本之间的特性、模型和实际偏差有助于识别模式、数据质量问题,以及跨您的发行版改变用户行为。
让我们回到你看到一个新的流行网站流量突然激增的例子。通过注意在训练中的特征输入(在这种情况下,新流行的站点)与你的特征在生产中看到的值之间的显著变化,你可以主动地重新训练你的模型以说明这个新的趋势站点。
你可能遇到的另一个例子(这一次是关于概念漂移)是,与模型的预测相比,实际点击量突然激增。深入研究可能会发现生产中存在的欺诈性僵尸网络流量,这在训练数据中是不存在的或已知的问题,因此需要一个经过修改和重新训练的模型来区分和预测人类和非人类的点击。
数据质量保证
我们都听说过这样一句话,“垃圾进,垃圾出。”没有干净的数据,ML 模型无法做出准确的预测。了解不同要素之间的数据质量对于解决任何问题以及确保模型正常工作是非常必要的。
以我们之前的坏数据为例:挖掘不同的特性,我们注意到我们得到的设备和位置的数据是空的,这影响了模型正确预测 CTR 的能力。由于这两个特征在我们的预测中非常重要,注意到这一点对于能够确定问题的根本原因非常重要。
结论
随着数字广告支出持续增长,并成为品牌广告预算的更大一部分,数据科学和 ML 团队制定可观察性战略以捕捉、监控和排除生产中 CTR 模型的问题至关重要。通过采用一种既能被动监控关键指标,又能主动测量偏差、数据质量和性能的方法,ML 团队可以在潜在问题影响营销活动绩效之前提前采取措施。作为补充参考,下面是一个 ML 可观察性平台如何帮助客户解决点击率模型监控和可观察性的问题。
联系我们
如果这篇博客引起了你的注意,并且你渴望了解更多关于机器学习可观察性和模型监控,请查看我们的其他博客和关于 ML 监控的资源!如果您有兴趣加入一个有趣的 rockstar 工程团队,帮助模型成功生产,请随时联系我们,并在此找到我们的空缺职位!
您应该知道的最好的 Python IDEs 和代码编辑器——第 2 部分
更多具有显著特性的 Python IDEs 和代码编辑器

照片由来自佩克斯的路易斯·戈麦斯拍摄
编写 Python 代码的乐趣应该在于看到短小、简洁、易读的类,这些类用少量清晰的代码表达了大量的动作——而不是让读者厌烦得要死的大量琐碎代码。
吉多·范·罗苏姆
Python 的 拔得头筹,成为今天最流行的编程语言的确很壮观。而且,由于它的多功能性,大多数开发人员现在都在各种项目中使用这种编程语言。但是任何开发人员,无论是 Python 还是其他 编程语言 都离不开的一个工具就是代码编辑器和 ide。
看着 Python 越来越受欢迎,几个月前,我写了一篇文章,介绍了可用的最好的 Python 代码编辑器和 IDE。
从那以后,这篇文章获得了大量的赞扬,同时我们的读者 提出了一些有价值的建议,增加了一些我们可能忽略了的更受欢迎的代码编辑器和 IDE 。这篇后续文章旨在通过在开发人员社区中添加一些更强大且广泛使用的 Python 代码编辑器和 ide 来实现这一目的。
点击这里查看第一部分—
你应该知道的最好的 Python IDEs 和代码编辑器
尽管 Python 有大量的代码编辑器和 ide,但是选择正确的代码编辑器和 ide 还是很有挑战性的。在最初的文章中,我们强调了一些最好的,在这篇文章中,我们将分享一些同样著名的。
1. **Emacs**
- **类别:**代码编辑器
- 首次发行日期: 1975 年
- 平台兼容性: Windows、macOS、Linux
- 支持语言: Lisp,C,Emacs Lisp
- **价格:**免费
- 下载: Emacs 下载链接
- 热门公司使用 Emacs Python 代码编辑器— Stack、Accenture、Bukalapak、Chime。
从现代计算机的早期开始,Emacs 就是一个长期运行的文本编辑器。这个编辑器因为与另一个著名的文本编辑器Vi(现在叫做 Vim) 的恶名昭著的编辑器战争而变得流行。多年来,Emacs 已经发展成为一个高度可定制和可扩展的代码编辑器,可以免费获得。
就其核心而言,该编辑器是 Emacs Lisp 的解释器,但也可以很容易地用作大多数编程语言的代码编辑器。Emacs 的显著特点是:
●提供大量按键绑定
● 附带调试器、项目规划器等
●用于安装扩展件的内置包装系统
优势—
●快速
●最小化系统资源的使用
●提供大量的扩展或软件包
劣势—
●高学习曲线
●广泛的定制选项可能会分散注意力
2021 年学习 Emacs 的理由—
2. **Vim**
- **类别:**代码编辑器
- 首次发行日期: 1991 年
- 平台兼容性: Windows、Linux、Mac OS、IOS、Android、UNIX、AmigaOS 和 MorphOS
- **适合谁:**专业
- 支持语言: C,Vim 脚本
- **价格:**免费
- 下载: Vim 下载链接
- 热门公司使用 Vim 代码编辑器****-
-Lyft、阿里巴巴游记、CircleCI、Ruangguru。
**还记得那场牵扯到 Emacs 的编辑大战吗?**在擂台的另一边是 Vi,另一个流行的文本编辑器,**内置于基于 Unix 的操作系统,**提供同样令人印象深刻的功能。**Vim(Vi 改进版的缩写)**是 Vi 的现代化版本,提供了大量方便的特性,使其符合当今开发人员的文本编辑器。
Vim 编辑器不仅允许您高效地创建完整的 Python 程序,还允许您轻松地处理文本文件。编辑器也在积极更新,增加了许多现代代码编辑器的标准特性。我们在下面列出了其中的一些功能:
●提供超过 10 种界面模式
●自带一种名为 Vimscript 的内置脚本语言
●为插件提供广泛的支持
●支持多种编程语言
优势—
●重量轻
● Vimtutor,内置教程可以对抗其高学习曲线
●高度可配置和可移植
劣势—
●一开始可能看起来很复杂
●定制 Vim 可能会成为一个永无止境的过程
截图供参考-

3.托尼
- 类别: IDE
- **平台兼容性:**微软视窗、Linux、macOS
- **适合谁:**初学者
- 支持语言: Python
- **价格:**免费
- **下载:**Thonny 下载链接
对于很少或没有编程经验的人来说,Thonny 是一个非常适合初学者的 Python IDE 。Thonny 让新手更容易进入 Python 编程,因为它带有 Python 3.7 ,节省了安装时间。
Thonny 的教育性编程风格不仅教你编程语言的某些部分,比如变量,而且还给你一个执行的可视化表示。托恩尼的主要亮点是:
●简单干净的 IDE
●附带一个简单的调试器
●提供代码完成功能
优势—
●提供大量初学者友好的功能
●提供一个简单的 Python 外壳来安装附加的包
●可以用几个方便的插件进行扩展
缺点—
●它不如列表中的其他一些 ide 先进
●缺乏对模板的支持
截图供参考-

4.孙耀威
- 类别: IDE
- 首次发行日期: 2002 年
- 平台兼容性: Linux、macOS、微软 Windows
- 支持语言: Python
- **价格:**免费
- 下载: 孙耀威下载链接
- 使用 Eric Python IDE 的热门公司- BristoSoft、GymGlish、Climpact
尽管不像这个列表中的其他代码编辑器和 ide 那样受欢迎,Eric仍然提供了大量的特性来处理你的日常文本编辑需求。Eric 的特别之处在于它不仅是 Python 的代码编辑器,也是同样令人印象深刻的 IDE。****
基于流行的 Qt 工具包和灵活的闪烁编辑器控件,Eric 为创建 Python 应用和专业管理软件项目提供了几个方便的特性**。它的一些**最好的特性是:****
●源代码编辑能力
●支持使用 Qt Designer 进行 GUI 设计
●代码调试、检查、测试和记录
优势—
●可以同时运行多个编辑器
●自带高效调试器
●围绕 Python 编程语言
缺点—
●即使对专业人士来说,界面也可能看起来很复杂
●使用多个插件时,性能会受到影响
</10-cool-python-project-ideas-for-python-developers-7953047e203>
5.竞技表演
- 类别: IDE
- 首次上映日期: 2016 年
- 平台兼容性: Windows、Linux、Mac OS 等。
- **价格:**免费
Rodeo 是一个面向 Python 的跨平台 IDE,它是轻量级的,是现代数据科学家开发用于 机器学习 和数据科学问题的完美工具。
Rodeo 可以有效地用作您的个人数据探索和解释工具。如果你发现自己在某个时候陷入了困境,Rodeo 的综合教程可以帮助你找到出路。使 Rodeo 成为数据科学绝佳选择的特性包括:
●其数据绘图能力
●提供代码完成、语法高亮等功能
●支持 IPython
优势—
●提供直观的工具,如可视化文件导航器、包搜索和点击式目录
●备忘单使引用 Python 主题更加容易
缺点—
IDE 有几个内存和性能问题
●发展停滞了相当一段时间
结论
Python 对开发人员来说非常友好,但是在选择合适的代码编辑器和 IDE 时,事情就变得困难了。Python 为具有不同编程语言经验的人提供了代码编辑器和 ide。在这篇文章中,我们介绍了我们在最初的文章中遗漏的其他顶级 Python 代码编辑器和 ide。
如果您正在寻找一个强大的 Python 代码编辑器和 IDE,我们希望这篇后续文章能为您指出适合您的工具。
你对这份迷你清单有什么想法?我很想听听他们的故事。
更多有趣的 Python 读物
我希望这篇文章对你有用!以下是一些有趣的读物,希望你也喜欢
https://blog.digitalogy.co/python-interview-questions-and-answers-for-freshers/ </10-world-class-companies-using-python-26cde24919a8> https://blog.digitalogy.co/best-python-frameworks-for-web-development-2020/
关于作者
克莱尔 D 。在digital ogy—是一个内容制作者和营销人员,这是一个技术采购和定制匹配市场,根据全球各地的特定需求,将人们与预先筛选的&顶尖开发人员和设计师联系起来。与我连线上 中Linkedin&推特 。
最佳文本聚合方法:重访 VLDB 2021 人群科学挑战赛
原文:https://towardsdatascience.com/best-text-aggregation-methods-vldb-2021-crowd-science-challenge-revisited-1be2062bdab5?source=collection_archive---------26-----------------------
思想和理论

由乔舒亚·戈德在 Unsplash 上拍摄的照片
今年, Toloka 在丹麦哥本哈根举行的世界上最大的数据科学会议之一——超大规模数据库 (VLDB 2021)上领导了一个群体科学研讨会。作为研讨会的一部分,Toloka 研究团队组织了一场竞赛,以确定众包文本文件的最佳聚合方法。所谓的群众科学挑战提供 6000 美元的现金奖励,其中 3000 美元给获胜者,2000 美元给亚军,剩下的 1000 美元给第三名。至关重要的是,作为这场激动人心的比赛的结果,我们能够找到聚合众包文本的最佳方法。

文本聚合
为什么大惊小怪?
大多数众包任务都是关于分类的:众包执行者必须从一组预定义的选项中选择正确的答案。然而,一些任务需要内容生成、音频注释或对象选择。由于这些任务需要的答案超出了多项选择的范围,因此通常需要手工检查作业。出于这个原因,两个标签项目并行运行——一个收集来自群众演员(我们也称之为 Tolokers)的提交,另一个在项目中涉及的其他演员验证后接受或拒绝这些提交。验收后,绿灯 Tolokers 得到相应的报酬。
让我们感兴趣的问题是,这两个阶段的过程是否可以被绕过,整个机制是否可以自动化。

转录音频→验证转录
开拓者和超越者
我们绝不是第一个想到或试图这样做的人。90 年代,识别器输出表决误差减少 (ROVER)被开发出来。它使用动态编程从几种可能的预测中提供一种新的高质量的语音识别预测。由于这种方法在众包中被广泛认可( Marge et。,2010 ,我们选择它作为我们的基线。因此,一种新的聚合方法不仅有望展示最好的结果,而且有望在相同的数据集上超过 ROVER。
当然,在过去的 30 年里,同样的问题还有其他的解决方案。其中有一类 RASA 和 HRRASA 方法(李,2020 ),它们使用类似 BERT 的语言转换器来聚合文本。这些方法使用检索方法解决聚集问题;然而,从我们的经验来看,它们通常不如 ROVER 工作得好。尽管如此,它们也包括在基准中以供参考。
因此,最好的聚合方法应该能够处理大量嘈杂的转录,并提供与相应音频文件精确匹配的最佳文本版本。作为评估标准,我们使用平均单词准确度(AWAcc)。

转录音频→谢谢!
数据准备
对于我们的竞争,我们决定使用一个全新的、类似 LibriSpeech 的数据集,它不会类似于任何其他东西。以下是我们为此所做的准备:
1.选自维基百科和图书语料库的随机句子。
2.丢弃很短或很长的句子,以及包含数字的句子。
3.使用 Yandex SpeechKit 生成所选句子的音频版本。
4.在 Toloka 上发起了一个标签项目,要求表演者转录音频文件。
5.为每段录音收集了一些注释。
(正确答案提前知道)。
正如大多数 ML 竞赛一样,我们将过程分为一个训练(“训练”)和两个测试阶段(“公开测试”和“私人测试”)。“训练”用于训练和调整竞争的 ML 模型,“公开测试”用于评估比赛过程中的质量,“私人测试”用于确定获胜者并结束比赛。我们从 3,039 名群众工作者那里收集了总共 99,414 条音频注释,转录了 9,700 条音频记录。
数据

挑战中使用的所有数据都可以在 GitHub 上获得。
描述本次比赛整个数据准备过程的研究论文已在 NeurIPS 2021 数据集和基准赛道上发表,并在此处提供。
VLDB 大赛
ML 比赛通常在赛道、赛道或赛道举行。权衡各种选择后,我们最终选择了 Yandex。谁能够为我们提供优先支持。
除了想出最好的转录文本聚合方法,参赛者还被邀请提交他们方法的书面描述,我们后来在我们的研讨会记录中发表了这些描述。托洛卡还向有意愿和能力的参与者提供竞赛资助。
VLDB 2021 人群科学挑战赛时间表如下:
- 2021 年 4 月 15 日——比赛启动,训练阶段开始(“训练”)
- 2021 年 5 月 5 日——主要比赛阶段开始(“公开测试”+“私人测试”)
- 2021 年 6 月 18 日—比赛结束
- 2021 年 7 月 5 日—概述汇总方法的论文提交截止日期
- 2021 年 8 月 20 日— VLDB 2021 人群科学研讨会
获奖者和荣誉奖
由于 ROVER 和 HR/RASA 显示的 AWAcc 值分别等于 92.25%和 91.04%,我们一直在寻找具有更好结果的模型。共有 18 名参赛者参加,其中只有 8 人在活动的“私人测试”阶段展示了超过 ROVER 基线的平均单词准确度值。需要注意的是,包含大规模语言模型的 HR/RASA 方法最终未能给人留下深刻印象。以下是挑战赛的三名获胜者以及那些想出了巧妙解决方案但没有获胜的参赛者:
- 第一名 (AWAcc = 95.73%)。最好的方法是用于文本摘要的微调 BART 模型。为了在训练中调整模型,参赛者打乱了所有提交的转录,随后用美国英语单词替换英国英语。令人惊讶的是,一个成功的文本聚合方法依赖于一个执行良好的文本摘要策略。
- 第二名 (AWAcc = 95.66%)。在使用微调的 T5 模型进行自动文本摘要之前,这位参赛者还尝试了许多 seq2seq 方法。他们的方法证实了获胜方法的有效性;然而,亚军可能由于缺乏模型正规化而缺乏一致性。
- 第三名 (AWAcc = 95.48%)。该值是不同信号的线性组合的结果,包括 BERT、假设分类器和执行者特征,如答案的数量及其一致性。值得注意的是,这是我们在比赛的三个获胜者中看到的唯一一个真正考虑表演者技能的方法。此外,这位参赛者使用了我们提供的一笔资助来完善他们的方法。
- 第四名 (AWAcc = 95.00%)。这个参与者使用了一个经过微调的 T5 模型,并使用 LightGBM 对注释进行了排序。这种方法虽然值得称赞,但产生的输出不如前三种精确。
- 第六名 (AWAcc = 93.37%)。事实证明,人们可以使用 Levenshtein 距离的中值来提出可行的解决方案。但是这种方法意味着一个非常仔细的执行者选择试探法,它极大地影响了结果。
结果和结论
感谢 VLDB 2021 人群科学挑战赛,我们能够获得一种可靠的文本聚合方法,成功地将 ROVER 在我们的新数据集上的错误率减半,从 7.75%降至 4.27%。
我们收到了来自不同背景和观点的人的解决方案,有趣的是,事实证明,总的来说,整合音频转录和文本的任务是一个自动文本摘要问题。此外,我们了解到一些基于语言的模型显示了不错的结果,在这种情况下,大多数检索方法都不是特别好,并且 ROVER 不再是无可争议的音频转录聚合之王。第一名获胜者提供的方法将被添加到我们的众包中,这是一个用于众包的开源 Python 库。这并不意味着问题已经完全解决,但它确实意味着已经取得了相当大的进展。
我们的研讨会记录包括题为 VLDB 2021 关于聚合众包音频转录的众包科学挑战的论文,其中包含对竞赛及其结果的更详细描述。还有两篇论文概述了竞赛冠军和亚军和亚军使用的汇总方法。
尽快掌握数据科学需要关注的最佳话题
原文:https://towardsdatascience.com/best-topics-to-focus-on-to-master-data-science-as-fast-as-possible-609ce5cb05e3?source=collection_archive---------17-----------------------
开始学习数据科学时,您应该主要关注哪些主题和领域?

汤姆·里森在 Unsplash 上的照片
"没有任何伟大的营销决策是基于定性数据做出的."— 约翰·斯卡利
数据科学是一个庞大的领域,很容易迷失在该领域呈现的大量主题中。然而,如果你只是一个想要深入研究数据科学主题的初学者,它会让你想知道什么是你应该关注的基本概念,以便你可以更好地掌握这个领域。
如果你想从头开始学习一切,并制定一个完美的计划来学习你想要的一切,那么请务必查看下面的文章,在 12 个月内掌握数据科学,同时使用上述 12 个步骤学习和获得更多知识。
</12-steps-for-beginner-to-pro-in-data-science-in-12-months-c6f6ba01f96e>
然而,如果你没有很多时间,只想完成一个快速速成课程,那么这篇文章将是你尽快专注于数据科学最本质方面的完美选择。本文的主要目标是关注在数据科学领域被认为非常有价值的清晰的主题。
让我们开始了解数据科学中最重要的主题,您必须关注这些主题,以便尽快了解更多信息并获得更多知识。这些概念的概要可以被认为是在本文的各个部分中列出的。
数据

照片由 Unsplash 上的 Pietro Jeng 拍摄
没有数据,就不可能有数据科学。数据科学包括数据挖掘、数据准备、数据操作、数据可视化和其他与数据相关的重要方面。数据科学的正式定义如下—
数据科学是一个跨学科的领域,它使用科学的方法、流程、算法和系统从许多结构化和非结构化的数据中提取知识和见解。数据科学与数据挖掘、机器学习和大数据相关。
数据被认为是当今时代最重要的资源之一。科技巨头和大公司正在大力投资,以尽可能获得最佳资源。这样做的原因是为了达到期望的客户满意率,并借助收集的数据分析他们的行为模式。
如果你是一个初学者,刚开始学习数据科学,你处理数据的方法必须是从获得的资源中收集和处理尽可能多的信息。学会识别最适合你的特定项目的相关数据。
一旦您能够获得必要的数据,您的任务就是考虑从中获得有用的信息,并预处理额外的不必要的需求。收集和准备你的数据。帮助你完成这个过程的最好的工具通常是 pandas 库模块,以及一个去除无关数据的模块,比如正则表达式(re)模块。
我强烈推荐阅读下面这篇关于 NLP 的文章,这篇文章用四个正则表达式命令简化了 NLP。下面提供了链接。
编程;编排

在 Unsplash 上由Nejc sokli拍摄的照片
编程恰好是构建数据科学项目时需要关注的最重要的主题之一。这一点是显而易见的,但是如果你对编程一无所知,或者你只是一个想要学习更多编程知识的初学者,你怎么能更快地有效理解编程呢?
这个想法很简单。Python 是初学编码爱好者最容易学习和探索的编程语言之一。关于 Python 的最佳结果可以通过有效地研究这个主题来获得,并且可以在一个月的时间内掌握到中级水平。
我强烈推荐初学者从下面的链接中找到掌握 Python 数据科学的十步快速程序指南。按照上述步骤的顺序进行操作,以获得最佳效果。
</10-steps-to-master-python-for-data-science-f54199bb328d>
数据科学的另一个要求是足够数量的 SQL。结构化查询语言 (SQL)是一种用于编程的领域特定语言,设计用于管理关系数据库管理系统中保存的数据,或用于关系数据流管理系统中的流处理。
对 SQL 简单的基本理解通常足以开始从事体面的数据科学项目。借助互联网丰富的资源,您可以对 Python 编程语言有一个中级的了解,然后就可以开始从事数据科学项目了。
您必须关注的编程的更重要的方面是使用 Python 开发环境中存在的大量数据科学库模块的能力。您可以探索这些工具,因为它们将帮助您完成许多独特的任务。
可视化技术

由粘土银行在 Unsplash 上拍摄
为了简化您的数据科学项目,您的主要精力必须放在使用各种可视化技术来掌握您可用的数据中的有用信息。这种有用信息的程序性检索可归因于称为探索性数据分析(EDA)的重要步骤。正式定义可以表述如下—
在统计学中, 探索性数据分析 是一种分析数据集以总结其主要特征的方法,经常使用统计图形和其他数据可视化方法。可以使用或不使用统计模型,但 EDA 主要是为了查看数据可以告诉我们什么,而不仅仅是正式的建模或假设测试任务。
可视化在数据科学中占有非常重要的地位,因为它能够为特定的任务找出正确或错误的数据。在分析数据时,您可以找出模式和许多其他元素,这将有助于您更有效地应对复杂的数据科学项目。
Python 编程对这一目的非常有益,因为它允许用户利用 matplotlib 和 seaborn 中一些最好的可视化工具对大量数据集进行分析。当你能够对这些库模块有更好的理解时,你就可以在分析过程背后发展出更强的直觉。
尝试各种图表,如条形图、饼图、直方图、散点图和其他可视化技术,将有助于您更好地理解问题陈述和解决问题的方法。你不仅能理解数据,还能解释破解项目必须遵循的步骤。
数学

杰斯温·托马斯在 Unsplash 上的照片
数学是数据科学的一个重要方面,你需要掌握一些知识才能直观地理解众多概念。对数学有很强的基本理解将有助于你弄清楚机器学习算法和其他与数据科学相关的概念背后的概念熟练程度。
在数学方面,如果你刚刚开始接触数据科学,你需要掌握的主要目标必须是线性代数、概率统计和微积分这三个领域。在线性代数中,尝试开发向量、欧几里德距离、点积和其他类似主题背后的直觉,以轻松理解众多机器学习方面。
概率和统计是直观理解图形信息的重要主题,也是机器学习算法背后的过程理解,如基于贝叶斯定理的朴素贝叶斯算法。虽然积分学可能不需要立即关注,但你应该专注于微分学,以更快地掌握反向传播和其他类似概念的过程。
要了解更多关于学习数学的最佳免费资源,你可以查看下面的链接,或者阅读包含学习数学的最佳资源的下一部分。
学习数学的最佳资源:
- 可汗学院(*): 开始学习线性代数、微积分、概率统计等基本数学概念的最佳去处。
- 3Blue1Brown (*): 最好的 YouTube 频道之一,可以查看一些精彩的深入解释,并更好地直观理解概念。
- 书籍:如果你更喜欢读书,那就在谷歌上快速搜索一下,找到一些优秀的学习数学的免费电子书资源。为了更好地练习,你应该为每个特定的主题选择单独的书。
机器学习

阿瑟尼·托古列夫在 Unsplash 上的照片
机器学习是数据科学中的一个特殊主题,也是您可以构建和建立模型以完成您计划完成的目标和任务的主要方式之一。机器学习可以被定义为一种计算机程序,它将随着时间的推移而学习,即通过执行特定的任务并在许多时代之后学习它来获得经验。
机器学习模型是解决你的数据科学项目的主要方式。一旦您完成了对数据集的分析,并且使用多种可视化技术找出了最佳方法和途径,并且完成了数据准备,您的机器学习模型现在就可以构建了。
在构建机器学习模型的过程中,您的主要目标是解决特定的任务,同时实现体面的准确性和损失结果。向所有没有任何机器学习算法经验的数据科学初学者强烈推荐 Python 中的 scikit-learn 库模块。
对于数据科学家来说,理解这些模型的工作和方向非常重要。如果你有时间,我会建议你从头实现所有这些机器学习算法。然而,如果你没有足够的时间来做这些项目,而你又想尽快对这个主题进行实验,那么就试试这些预先构建的算法。
一旦您成功地完成了模型的训练,并且成功地运行了相当数量的纪元,您就应该考虑部署这些模型了。这一步将确保您在几天或几周内完成第一个数据科学项目。您可以专注于数据科学的基本部分,并构建许多更有用的项目。
结论:

照片由拉丽莎·伯塔在 Unsplash 上拍摄
"智慧不是学校教育的产物,而是终生努力获取的产物."— 阿尔伯特·爱因斯坦
虽然数据科学有几个方面是至关重要的,需要全神贯注才能掌握这门学科,但有几个特定的主题尤为重要。在这些概念的帮助下,您可以完成各种各样的任务,从而使您能够更快地在项目中获得想要的结果。
你的目标必须是获取广泛的数据,并彻底研究这些数据。应用一系列可视化技术,并相应地确定您可以在项目中实现的最佳机器学习算法。这样做将帮助你达到你想要的结果,而且比你花时间解决所有事情花费的时间要少得多。
不要忘记关注编程的基本方面,即像 Python 这样的编程语言,使您能够学习编码的基础知识并开发独特的项目。为您的数据科学项目学习一些管理数据库的 SQL。不要忘记数学,因为它是数据科学和机器学习的核心。它将帮助你获得坚实的基础和对主题的理解。
如果你对这篇文章中提到的各点有任何疑问,请在下面的评论中告诉我。我会尽快给你回复。
看看我的其他一些文章,你可能会喜欢读!
</5-reasons-why-you-should-develop-a-game-with-python-and-ai-9f5f276e7637> </5-reasons-why-you-should-code-daily-as-a-data-scientist-fa7fc6dc92c4>
谢谢你们坚持到最后。我希望你们喜欢阅读这篇文章。我希望你们都有美好的一天!
研究数据科学的最佳大学
原文:https://towardsdatascience.com/best-universities-to-study-data-science-65f9a12a0342?source=collection_archive---------5-----------------------
并非所有的数据科学学位都是一样的,所以请找出适合你的课程

照片由 Unsplash 上的穆扎米尔·苏尔马拍摄
数据科学是世界上发展最快的职业之一。美国劳工统计局估计,到 2026 年,将有大约 1150 万个与数据科学相关的工作机会**【1】**。这些数字表明,学术、公共和企业部门已经认识到数据专业人员对其最终目标的重要性。因此,我们应该看到许多学术机构提供数据科学课程,大多是研究生水平(硕士学位),以适应就业市场的直接需求。
然而,从学生的角度来看,决定哪个数据科学项目适合你并不容易。就所提供的课程而言,大学可能会有很大的不同。此外,每个项目都有不同的课程,这就是为什么仔细比较你感兴趣的选择以及以下标准因素至关重要:
学制: 1 年或 2 年(通常在欧洲,英国除外,硕士需要两年)
**学习类型:**全日制和非全日制。
**最低要求:**计算机科学或另一相关量化学科(如数学、工程、统计、物理、自然科学或商科)学士学位。申请人应该熟悉基础数学,尤其是微积分和线性代数。此外,申请人应该对至少一种编程语言(Python 或 R)相当熟悉。
**语言要求:**如果你的第一语言不是英语,那么你必须提供证据证明你的口头和书面英语技能足以胜任该课程。在欧洲,大学接受名为雅思的英语考试,而在美国和加拿大,大学要求托福考试。如果你有一个用英语授课的学位,一定要检查你是否免除了语言要求。
一旦您满足了最低要求,您现在就能够决定哪个地方是学习数据科学的最佳场所。下面,我根据学术成就、研究成果和对比数据科学课程,仅列出了一些顶尖学校。以下是北美和欧洲的一些顶尖学校。
北美
麻省理工学院
位于美国波士顿的麻省理工学院提供商业分析硕士项目(MBAn) 。这个为期 12 个月的项目为学生从事应用和管理现代数据科学的职业做准备,以解决关键的商业挑战。该计划的一个亮点是分析顶点项目,该项目允许学生与行业数据专业人员一起研究数据科学问题。所有学生都将获得 22,000 美元,并因其参与而抵消学费。MBA 毕业生继续在谷歌、亚马逊、波士顿咨询公司、麦肯锡公司和许多其他顶级科技和咨询公司工作。
https://mitsloan.mit.edu/master-of-business-analytics#tour-welcome
卡内基梅隆大学
卡内基梅隆大学的数据科学课程旨在培养跨学科环境中的学生。他们提供课程和前沿研究的结合。数据规模和复杂性的快速增长可以在多个领域进行收集和分析,包括医疗保健、公共安全、科学研究和公共政策。学生和教师都与名为 Meltwater 的数字媒体智能公司合作,利用该公司的人工智能平台推进涉及人工智能的研究和教育。他们可以访问世界上最多样化的开放和许可数据平台。
然而,获得卡内基梅隆大学计算数据科学硕士学位的学生可能不得不在匹兹堡之外寻找工作。这是因为美国的其他城市提供了更多的工作机会。
https://mcds.cs.cmu.edu/
提示:值得一提的是,如果你打算毕业后在美国学习和工作,那么你应该多读一些关于 STEM 分类的内容。一些项目符合“STEM 指定项目”的条件,允许国际学生毕业后在美国延长培训 24 个月。否则,你将不得不返回你的国家。
除了美国大学,一些加拿大大学为数据专业人员提供优秀的研究生课程和丰富的环境。例如, MILA 位于魁北克科技和创业生态系统的中心,是一个由 500 多名专注于机器学习和人工智能的研究人员组成的社区。他们致力于科学的卓越和创新,以成为科学进步和创新的全球中心为使命。
MILA 有几个通过参与机构提供的培训项目: 麦吉尔大学 、 蒙特利尔高等商学院 和 蒙特利尔大学 。如果你对研究感兴趣,MILA 将让学生和一名志愿者导师配对,为期 9 个月。导师将支持他们的学员实现个人和职业发展目标。2021 年 3 月,Mila 将启动导师计划的第二批项目。请记住,一些课程和导师项目需要高级法语水平,主要是在蒙特利尔大学。麦吉尔和 HEC 都提供一些英语课程。
欧洲
几乎欧洲的每个国家,特别是法国,都已经采取措施为那些对从事与数据相关的职业感兴趣的人提供必要的培训。欧洲一直有一些世界领先的大学,现在这些学术机构也提供解决数据培训和研究需求的课程。
伦敦帝国学院
伦敦帝国理工学院推出了数据科学研究所(DSI)。这一重大举措汇集了学院现有的数据科学活动和专业知识,并创造了新的合作伙伴关系和研究机会。在帝国理工学院学习的一个独特方面是学院的学术专家和学院之间跨许多学科的多学科合作,如医疗保健,金融,气候科学和城市发展。他们的最终目标是创造复杂问题的解决方案。除了研究,他们还通过研究生课程培养未来的数据科学家。一个例子是生物医学研究中的 MRes 与数据科学流 。
本课程提供现代高通量生物分子研究中数据分析的跨学科培训。他们的学生将接受多元统计、机器学习方法和这些方法的研究经验的核心培训,以回答真正的生物医学问题。事实上,伦敦帝国理工学院研究实验室一直在向英国政府提供与新冠肺炎相关问题的数据分析支持。
然而,如果你对数据科学的商业方面感兴趣,你会在法国找到一门独特的课程,但是用英语授课。
巴黎综合理工学院&巴黎高等商学院
商业数据科学硕士项目是一个为期两年的项目,结合了商业和科学方法来应对当前的数据科学挑战。第一年,学生将在理工学院学习,重点是科学和数学课题。而在第二年,在巴黎 HEC,学生们不仅要面对一个新的物理环境,还要接受一种不同的学术方法,即边做边学。这些变化有助于学生提高他们的管理和数据科学知识,并应用它们来解决业务挑战。他们独特的课程在数据科学方面培训学生,并为他们提供高水平的战略和商业技能。每学年学费为 20,800€(约 25,200 美元)。

一个穿着制服戴着双角帽的理工学院学生。照片由 Marie-Lan Nguyen 在维基百科上拍摄。
https://programmes.polytechnique.edu/en/master/programs/data-science-for-business-joint-degree-with-hec
赫尔辛基大学
这可能会让许多有抱负的数据科学家感到惊讶。尽管如此,芬兰仍在数据相关项目上投入了大量资金,以帮助本国民众做好准备,利用人工智能和数据科学的指数级增长。赫尔辛基大学在教育芬兰人方面发挥了重要作用。学生可以选择专攻与数据科学相关的许多不同技术领域中的一个,如高级分析、机器学习、计算机视觉和研究。数据科学硕士课程为期两年,用芬兰语、英语和瑞典语授课。
结论
数据科学领域已经赢得了领先大学专业硕士学位的权利。然而,为自己选择正确的课程可能不像预期的那样简单。申请者和有抱负的数据科学家应该花时间从课程的角度调查每个项目到底提供了什么。正如你所看到的,一些学位是以研究为导向的,而另一些则开发了商业和实际应用。然而,在正式的学术环境中有很多机会学习数据科学。请记住,并不是每门课程都会用英语教授。如果你想在美国学习和工作,一定要查看 STEM 分类。这不是一份详尽的清单。希望现在你知道许多其他大学提供高质量的数据科学学位,以及每个大学如何对同一主题采取不同的方法。
感谢阅读。以下是你可能喜欢的其他文章:
https://medium.com/codex/top-10-artificial-intelligence-influencers-you-should-follow-ca91e94c797b
参考文献:
【1】https://economic times . India times . com/magazines/panache/11-5-Mn-job-openings-by-2026-sky-high-sales-why-data-science-is-booming/articleshow/74667347 . CMS?from=mdr
【2】https://www . gov . uk/government/news/January-2021-findings-from-新冠肺炎-study-published
解决 Python 编码问题的最佳方式
原文:https://towardsdatascience.com/best-way-to-solve-python-coding-questions-376539450dd2?source=collection_archive---------5-----------------------
了解如何有效解决 Python 编码问题

韦斯利·廷吉在 Unsplash 上拍摄的照片
关于 Python 编码网站(如 codewars 或 leetcode)的好处,以及使用它们是否真的能让我们成为更好的程序员,肯定存在一些争议。尽管如此,许多人仍然使用它们来准备 Python 面试问题,保持他们的 Python 编程技能,或者只是为了好玩。然而,对于任何 Python 程序员或数据科学家来说,这些资源肯定都有一席之地。
在本教程中,我们将看看从这些 python 编码问题中提取最大效用的最佳方式。我们将研究一个相当简单的 Python 编码问题,并通过适当的步骤来解决它。这包括首先用伪代码想出一个计划或大纲,然后从最简单的解决方案开始用不同的方法解决它。
Python 编码问题
我们需要编写一个函数,它将单个整数值作为输入,并返回从零到该输入的整数之和。如果传入了非整数值,该函数应该返回 0。
因此,如果我们将数字 5 传递给函数,那么它将返回整数 0 到 5 的和,或 (0+1+2+3+4+5) ,等于 15。如果我们传入除了整数之外的任何其他数据类型,比如字符串或浮点数等,函数应该返回 0。
制定计划
我们应该做的第一件事是用伪代码解决这个问题。伪代码只是一种不用担心编码语法就能规划出我们的步骤的方法。
我们可以试着这样做:
def add(num):
# if num is an integer then
# add the integers 0 through num and return sum
# if num is not an integer then return 0**Sample inputs/outputs:****# input: 5, output: 15
# input: 'and', output: 0**
我们定义了一个函数 add ,它接受一个输入 num 。在 add 函数中,我们使用注释编写了一个步骤大纲。如果传递给函数的值是一个整数,那么我们将把整数 0 和该值相加,然后返回和。如果传递给函数的值不是一个整数,那么我们简单地返回 0。在那之后,我们写一些例子,我们希望我们的输出被给定一个特定的输入。
让我们在上面的伪代码中展开这一步:
# add the integers 0 through num and return sum
这一步可以用很多方法来完成。如果我们使用 for 循环尝试这一步,伪代码会是什么样子?
def add(num):
# if num is an integer then**# create sum variable and assign it to 0****# using a for loop, loop over integers 0 to num****# update sum value by adding num to it****# return sum**# if num is not an integer then return 0
让我们根据上面创建的蓝图来尝试解决它!
使用 For 循环
我们可以使用 for 循环来解决这个提示,如下所示:
def add(num):
**# if num is an integer then** if type(num) == int:**# create sum variable and assign it to 0** sum = 0**# using a for loop, loop over integers 0 to num** for x in range(num+1):**# update sum value** sum += x**# return sum** return sum**# if num is not an integer then return 0** else:
return 0
下面我们来剖析一下代码。
我们首先使用类型的函数检查传入的值 num 是否是一个整数。
if type(num) == int:
如果类型是整数,我们创建一个 sum 变量,并给它赋值 0。
sum = 0
然后,我们使用 for 循环和 range 函数对从 0 开始的整数进行循环,直到传递给我们的函数的整数。请记住,range 函数创建了一个 range 对象,它是一个可迭代的对象,从 0 开始(如果我们没有指定起始值),到小于停止值的整数(因为停止值是唯一的)。这就是为什么我们需要在停止值( num+1 )上加 1,因为我们想把从 0 到这个数字的所有整数加起来。
range(开始、停止[、步进])
range 函数将创建一个 range 对象,这是一个可迭代的对象,因此我们可以使用 for 循环来遍历它。当我们循环遍历这个 iterable 对象时,我们将每个数字,或 x ,添加到 sum 变量中。
for x in range(num+1):
sum += x
然后,在 for 循环迭代完成后,该函数返回总和。
return sum
最后,如果传入的数字不是整数,我们返回 0。
else:
return 0
这是没有注释的代码:
def add(num):
if type(num) == int:
sum = 0
for x in range(num+1):
sum += x
return sum
else:
return 0
如果我们测试我们的加法函数,我们得到正确的输出:
add(5)
# 15add('and')
# 0
这是解决编码问题的一个好方法,它完成了工作。它易于阅读,工作正常。但是,在我看来,通过尝试以其他方式解决这个问题,我们也许可以通过利用我们的其他 python 知识和解决问题的技能从中提取更多的价值。这些其他的方法可能更 pythonicic 化,也可能不更 python 化,但是思考不同的方法来解决同一个问题是非常有趣和有用的。
让我们试着用不同的方法解决这个编码问题。
关于可迭代对象的更多信息:
使用 Reduce 函数
我们最近在之前的教程中学习了 reduce 函数的功能。reduce 函数接受一个 iterable 对象,并将其缩减为一个累积值。reduce 函数可以接受三个参数,其中两个是必需的。两个必需的参数是:一个函数(它本身接受两个参数)和一个 iterable 对象。
我们可以使用 reduce 函数来计算一个可迭代对象的和。
因此,代替 for 循环,我们可以使用 reduce 来解决我们的 Python 问题:
from functools import reducedef add(num):
if type(num) == int:
return reduce(lambda x,y: x+y, range(num+1))else:
return 0
就是这样!我们使用 lambda 函数作为函数参数,使用 range 对象作为我们的 iterable 对象。然后, reduce 函数将我们的 range 对象减少到一个值,即 sum。然后我们返回总和。
关于 reduce 功能的更多信息:
使用三元运算符
通过使用三元运算符,我们可以进一步缩短代码。使用三元运算符,我们可以使用以下格式将上面的 if/else 语句缩短为一行:
x if C else y
C 是我们的条件,先评估哪个。如果评估为真,则评估 x 并返回其值。否则,对 y 求值并返回其值。
我们可以在代码中实现这一点,如下所示:
def add(num):
return reduce(lambda x,y: x+y, range(num+1)) if type(num) == int else 0
通过这些改变,我们设法将函数中的代码减少到一行。这可能不是解决这个问题的最具可读性或 pythonic 式的方法,但在我看来,它通过迫使我们找出解决同一问题的不同方法来帮助我们提高编码和解决问题的技能。
让我们看看能否用另一种方法解决这个编码问题。
关于三元运算符的更多信息:
sum()函数
我们可以使用 Python 内置的 sum 函数以不同的方式解决这个编码问题。sum()函数可以接受一个 iterable 对象,并返回其元素的总和。如果我们想先将起始值添加到元素中,我们也可以传入一个起始值。
sum(iterable,start)
让我们使用 sum 函数来解决编码问题:
def add(num):
return sum(range(num+1)) if type(num) == int else 0
就是这样!这可能是解决这个编码问题的最好方法,因为它是最简洁和易读的解决方案。此外,它还可能具有最佳性能。
有关代码性能的更多信息:
如果你喜欢阅读这样的故事,并想支持我成为一名作家,考虑注册成为一名媒体成员。每月 5 美元,你可以无限制地阅读媒体上的故事。如果你用我的 链接 报名,我就赚点小提成。
https://lmatalka90.medium.com/membership
结论
在本教程中,我们了解到使用不同的方法解决 Python 问题可以通过拓宽我们的知识库来增强我们的编码和解决问题的技能。我们看了一个示例 python 编码问题,并经历了解决它的步骤。我们首先计划如何用伪代码解决这个问题。然后,我们通过使用 for 循环来解决提示问题,从而实现了这些步骤。后来,我们用 reduce 函数解决了同样的问题。我们还实现了三元运算符来进一步缩短代码,但仍然保持可读性。最后,我们使用 Python 内置的 sum 函数和三元运算符,得出了最短但仍然最 Python 化的解决方案。
贝塔分布预测 2020 年选举结果
原文:https://towardsdatascience.com/beta-distributions-9faa227fd0fd?source=collection_archive---------44-----------------------
快速实时预测的简单更新

不同参数值的 beta 分布动画。维基百科上 Pabloparsil 的 Gif。 CC BY-SA 4.0 。
不知何故,在我上学的几年里,我从未听说过 beta 发行版,直到我在大卫·罗宾逊的博客上偶然发现它们,但它们很快成为我最喜欢的发行版之一。我的意思是,看看那个向左摆动的东西。它们是非常灵活的发行版,但这并不是它们真正酷的原因。正是你可以轻松地更新你的预测,使得贝塔分布脱颖而出。
贝塔分布由两个参数描述,阿尔法和贝塔(你可以看到改变这些值如何影响上面的分布形状),虽然这种分布有丰富的数学描述,但对它们的高级解释是阿尔法-1 =成功数,贝塔-1 =失败数,是的,贝塔分布与二进制数据有关,成功或失败,就像二项式和伯努利分布一样。事实上,在技术语言中,我们会说贝塔分布是二项式分布和伯努利分布之前的共轭,为了简化,这意味着当我们想要更新由这些分布建模的数据时,我们使用贝塔分布来完成它,但是为了更深入的解释,请查看 Aerin Kim 的 MIT 18.05 和这两篇文章( 1 、 2 )(按照她的推荐顺序)。
更新 beta 发行版就像了解您正在使用的 alpha 和 beta 一样简单。更新,新的成功?给 alpha 加一(字面意思是 alpha + 1)。更新,5 个新故障?在 beta 上加 5(字面意思是 beta + 5)。就这么简单,数据集的预期均值总是 alpha / (alpha+beta)。
让我们举一个选举数据的例子,但首先,一个警告:这更接近于一个我称之为天真贝塔分布和贝叶斯更新的例子,就像天真贝叶斯分类器一样,也就是说我忽略了我的观察的独立性(因为它们不是),我承认我不知道这种天真到底有多可恶。也许只有一点。也许完全是。但正如他们所说的,LAAETTR(发音为“后来”,带有南加州口音,如“后来,笨蛋”):
留给读者作为练习。
––也许是所有数学中最讨厌的 7 个单词
我们的例子:贝塔分布和 2020 年选举数据。
在美国,我们通过直接代表而不是直接代表来选择我们的国王:这就是选举团,它无疑是人民民主的古老和可以说是良好的遗迹,但对人民来说却没有太多的民主。这是一个让候选人有可能赢得普选的制度,但不是总统职位。)
比方说,在最近的 2020 年总统选举中,随着一周内民调开始出现,你希望更新你的预期。也许你有前几年候选人的选举人票的历史数据(和),并且知道一个候选人期望得到的平均票数。
为什么,这是一个采用贝塔分布的绝佳机会——除了这些观察结果不是独立的这一事实。一个候选人在选举团中表现很好,意味着至少有一个候选人表现很差,根据定义,这不是独立观察。我们知道这是一种糟糕的做法,但为了举例,我们还是继续进行。
所以我们使用了一个库,如果你使用 Python 的话,可能是 SciPy,来拟合 beta 分布,并给出 alpha 和 beta 值。
from scipy import statselectoral_votes = [0.29, 0.7, 0.11, 0.13, ...]
beta_params = stats.beta.fit(electoral_votes, loc=0, scale=1)
beta_params# alpha, beta, loc, scale
>>>(1.032, 0.975, 0.001, 0.984)

α= 1.032,β= 0.975。图片作者。
这就是我们开始工作所需要的一切。拿起你的爆米花,舒适地躺在安乐椅上,准备好享受 2020 年选举数据吧。综合起来,你对这一周的期望应该是这样的:

从第一个(左)到最后一个(右)选举人票报告,每个候选人获得的全部选举人票的预测分数,必须大于 0.5 才能获胜。图片作者。
这就是测试版的美妙之处:易于使用,易于解释,易于更新。
最后一个提醒和免责声明:记住,你依赖于测试版的独立性来工作。要获得一个可行应用程序的更好的例子,请查看下面大卫·罗宾逊的棒球统计数据的例子。
资料来源和进一步阅读
- 贝叶斯推理——直觉和例子 由艾林·金在中
- 共轭在先 由艾林金在介质上解释
- 麻省理工学院 18.05 关于贝叶斯推断和贝塔分布的更多信息
- 【理解贝塔分布(使用棒球统计数据)】 作者大卫·罗宾逊,这是对贝塔分布的另一个很好的介绍,但是这次,你猜对了,是棒球统计数据。
- 【了解贝塔二项式回归(使用棒球统计)】 作者大卫·罗宾逊(与第一篇不同的文章),另一篇看贝塔分布及其背后的假设。
- 帖子使用的代码和投票数据可以在我的 GitHub 上找到
BetaBoosting
原文:https://towardsdatascience.com/betaboosting-2cd6c697eb93?source=collection_archive---------8-----------------------
思想和理论
XGBoost 的学习速度非常快

觉吞在 Unsplash 上拍摄的照片
TLDR: 传统上,像 XGBoost 这样的梯度推进实现使用静态学习率。我们建议使用一个函数,其参数可以传递到一个标准的超参数调整过程,以学习“最佳”的学习率形状。
所有代码都在这里: BetaBoost Github
关于升压的简要复习
在这一点上,我们都知道 XGBoost ,因为它在 Kaggle 等平台上举办的众多数据科学竞赛中取得了巨大成功。随着它的成功,我们已经看到了一些变化,如 CatBoost 和 LightGBM 。所有这些实现都基于 Friedman 开发的梯度推进算法,该算法涉及迭代地构建弱学习器的集合(通常是决策树),其中每个后续学习器都根据前一个学习器的错误进行训练。让我们从统计学习的元素来看一些算法的通用伪代码:

来自 ESL 的伪代码(图片由作者提供)
然而,这还不完整!一个核心机制是一个收缩参数,它在每一轮提升中惩罚每个学习者,通常称为“学习率”。它的主要功能是防止过度拟合,它是对梯度下降算法的一个很好的回调,该算法启发了梯度增强的许多方面。为了利用学习率,弗里德曼将 2.d 改为:

作者图片
现在,我们将每一轮的学习者乘以一个常数。但是我们应该用什么常数呢?这是一个常见问题,通常用超参数调整来处理,通常会产生一个常数,如. 1 或. 01。一些数字远低于 1,或者换句话说,一个严重惩罚每一轮的数字。由于人数少,我们无法最大限度地利用每个学员。
使用动态学习率
当具体查看学习率参数时,下一个自然的问题(尽管通常是不重要的)是为什么使用常数?梯度下降具有允许学习速率改变的动量策略。为什么渐变提升不能用类似的思路?
嗯,我们可以…
…它就是不起作用****。
快速的谷歌搜索显示,有一些工作是利用一个衰减的学习率完成的,这个学习率开始时很大,每一轮都在缩小。但是我们通常在交叉验证中没有看到准确性的提高,并且当查看测试误差图时,它的性能和使用常规的旧常数之间的差异很小。为什么像这样的方法不起作用背后的推理似乎是一个谜。这让我们想到了启发 BetaBoost 的一个核心主题:
这方面应该多做研究。
贝塔密度函数
为了与我们的主题保持一致,我们进行了研究,并发现了一个似乎很有前途的功能:beta 功能(当然还有一些护栏!).或者更具体地说,贝塔概率分布函数。这个函数最初是通过蛮力方法发现的,一旦它提供了令人鼓舞的结果,一些半连贯的基本原理就被挖掘出来了。
那么,什么是 beta PDF 呢?顾名思义,这是一个主要由两个参数描述的概率分布: α 和 *β。*除了这些参数之外,还增加了几个参数以及一些更进一步的“护栏”,这些参数似乎会有所帮助。出于我们的目的,我们很大程度上不关心函数作为概率密度函数的任何属性,只关心它与 boosting 的结果。
与许多其他功能相比,Beta PDF 的一个明显优势是您可以使用它实现大量的形状:

图片来自维基百科
如果我们想做类似指数衰减的事情,或者在中间产生一个大尖峰,只需要改变一个参数。这意味着如果我们将整个过程交给一个超参数调整包,比如 Hyperopt ,我们可以发现最适合(或过度适合)的学习率形状!)我们的数据。虽然,我们主要看到一个形状出现在顶部。
最终,我不知道为什么这些会有任何好处,所以:
在这方面应该做更多的研究。
BetaBoosting
这一切把我们带到了 BetaBoosting。这不是一个新的方法来建立一棵树或提出分裂。它只是在 XGBoost 的学习 API 中使用回调在每一轮提升中分配不同的学习速率。我们的具体实现基于 Beta PDf 分配学习率,因此我们得到了“BetaBoosting”这个名字。
该代码可通过 pip 安装,以便于使用,并要求 xgboost==1.5:
pip install BetaBoost==0.0.5
如前所述,特定的形状似乎比其他形状做得更好。这个形状在早期有一个很大的尖峰,由于我们的护栏,它很快就变成了一个“地板”参数。让我们看看使用类默认参数的 BetaBoost。这个函数将默认参数传递给 scipy Beta PDF 函数,还有一些附加的护栏。下面是一个简单的独立函数和实际的 BetaBoost 实现:
def beta_pdf(scalar=1.5,
a=26,
b=1,
scale=80,
loc=-68,
floor=0.01,
n_boosting_rounds=100):
"""
Get the learning rate from the beta PDF
Returns
-------
lrs : list
the resulting learning rates to use.
"""
lrs = [scalar*beta.pdf(i,
a=a,
b=b,
scale=scale,
loc=loc)
+ floor for i in range(n_boosting_rounds)]
return lrs
为了便于使用,这里列出了使用 BetaBoost 类的相同学习率:
from BetaBoost import BetaBoost as bb
import matplotlib.pyplot as plt
booster = bb.BetaBoost(n_boosting_rounds=100)
plt.plot(booster.beta_kernel())
plt.show()

作者图片
鉴于这种形状做得很好,这表明采取更大的步骤,不是在开始或结束时,而是在被促进的树发育的“青少年时期”提供最大的帮助。
为了进一步研究,我们可以用模拟数据运行它,并与其他学习率进行比较。
(下面的例子来自几年前的一个帖子,关于使用一个衰减的学习率,我找不到,如果有人找到了请告诉我,这样我就可以引用这篇文章了!)
首先,我们将进行导入并模拟一些数据:
import numpy as np
import xgboost as xgb
import matplotlib.pyplot as plt
def generate_data():
y = np.random.gamma(2, 4, OBS)
X = np.random.normal(5, 2, [OBS, FEATURES])
return X, y
max_iter = 300
eta_base = 0.2
eta_min = 0.1
eta_decay = np.linspace(eta_base, eta_min, max_iter).tolist()
OBS = 10 ** 4
FEATURES = 20
PARAMS = {
'eta': eta_base,
"booster": "gbtree",
}
X_train, y_train = generate_data()
X_test, y_test = generate_data()
dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test, label=y_test)
evals_result = {'train': dtrain}
接下来,让我们使用衰减学习率,并将我们的结果保存在一个字典中,我们最终将绘制该字典:
progress1 = dict()
model1 = xgb.train(
maximize=True,
params=PARAMS,
dtrain=dtrain,
num_boost_round=max_iter,
early_stopping_rounds=max_iter,
evals=[(dtrain, 'train'),(dtest, 'test')],
evals_result=progress1,
verbose_eval=False,
callbacks=[xgb.callback.LearningRateScheduler(eta_decay)]
)
现在,0.01 的标准常数:
progress2 = dict()
model2 = xgb.train(
maximize=True,
params=PARAMS,
dtrain=dtrain,
num_boost_round=max_iter,
early_stopping_rounds=max_iter,
evals=[(dtrain, 'train'),(dtest, 'test')],
evals_result=progress2,
verbose_eval=False,
callbacks=[xgb.callback.LearningRateScheduler(list(np.ones(max_iter)*0.01))]
)
常数 0.1
progress3 = dict()
model3 = xgb.train(
maximize=True,
params=PARAMS,
dtrain=dtrain,
num_boost_round=max_iter,
early_stopping_rounds=max_iter,
evals=[(dtrain, 'train'),(dtest, 'test')],
evals_result=progress3,
verbose_eval=False,
callbacks=[xgb.callback.LearningRateScheduler(list(np.ones(max_iter)*0.1))]
)
最后,我们的 BetaBoost,其中 fit 方法只是返回与 XGBoost 学习 API 中的 train 方法相同的输出
#Here we call the BetaBoost, the wrapper parameters are passed in the class init
bb_evals = dict()
from BetaBoost import BetaBoost as bb
betabooster = bb.BetaBoost(n_boosting_rounds=max_iter)
betabooster.fit(dtrain=dtrain,
maximize=True,
params=PARAMS,
early_stopping_rounds=max_iter,
evals=[(dtrain, 'train'),(dtest, 'test')],
evals_result=bb_evals,
verbose_eval=False)
让我们回顾一下每一轮测试准确性的结果:
plt.plot(progress1['test']['rmse'], linestyle = 'dashed', color = 'b', label = 'eta test decay')
plt.plot(progress2['test']['rmse'], linestyle = 'dashed', color = 'r', label = '0.01 test')
plt.plot(progress3['test']['rmse'], linestyle = 'dashed', color = 'black', label = '0.1 test')
plt.plot(bb_evals['test']['rmse'], linestyle = 'dashed', color = 'y', label = 'bb test')
plt.legend()
plt.show()

作者图片
查看最小测试集误差,我们看到衰减的学习率实际上最快地达到最小值,但这也是一个不稳定的结果,因为它很快开始过度适应测试集。下一个达到“拐点”的是 betaboosted 测试集。然而,与衰减测试集不同的是,我们可以看到,随着它的收敛,它的误差继续缓慢减小。最终,在迭代 300 左右,它遇到了对应于恒定的 0.01 学习率的错误率。因此,看起来我们在这两个方面都得到了最好的结果:我们非常快地收敛到接近最优的测试精度,然后我们可以抵抗过度拟合。但是,它真的表现最好吗?
号
在接下来的 100 次迭代中,静态的 0.01 略胜一筹。然而,情况并非总是如此,在下一篇文章中,我们将看到一些 5 倍 CV 结果,其中优化的 BetaBooster 实际上在真实世界数据上优于优化的 vanilla XGBoost!
摘要
使用β密度函数作为其学习速率的梯度增强似乎给了我们更快的收敛和对过拟合的鲁棒性。这样做的代价是要调整更多的参数。此外,随着学习速度调整某些函数的想法可以很快地添加到主要的增强包中,如 XGBoost 和 LightGBM,使用它们的回调功能。这看起来像是我们目前正在从岩石中榨出水的田地里的一个低垂的果实。
最终,BetaBoosting 回避了这个问题:
有更好的功能吗?
我们的回答是…
这方面应该多做研究。
参考
- 随机梯度推进。(1999 年 3 月)
- Hastie,Tibshirani,r .,,j . h . Friedman(2009 年)。统计学习的要素:数据挖掘、推理和预测。第二版。纽约:斯普林格。
- https://en.wikipedia.org/wiki/Beta_distribution
数据科学家和业务用户之间更好的沟通
原文:https://towardsdatascience.com/better-communications-between-data-scientists-and-business-users-46f493ce24ba?source=collection_archive---------18-----------------------
记住,你是在解决一个商业问题,而不是科学实验。
通常,分析或数据科学中最大的挑战不是实际工作本身,而是将结果传达给通常自己没有任何技术背景的业务用户。有效的沟通可能比数据科学本身更重要,因为如果你不能让你的业务用户理解你在做什么,那么你就不能建立信任。如果人们不信任提建议的人,他们往往会拒绝接受建议……如果他们不明白你在说什么,他们也不会信任你。那么,怎样才能更有效地沟通呢?
- 在你开始着手解决方案之前,了解你的受众的技术成熟度
- 从业务用户的角度向后研究,了解他们如何看待和解释信息
- 从一开始就投资于如何以您的业务用户能够认同、理解和信任的方式解释解决方案
- ****采用业务用户的语言,使用简化的语言解释数据科学工作
- 使用图像、图形和可视化来解释分析概念;不要用方程式
- 解释数据科学时,目标是概念上的准确性,而不是数学上的准确性****
- 不要让完美成为好的敌人;有时,如果一个次优算法提供了好的结果并且易于解释和理解,那么从这个算法开始会更好
- 找一个不是技术人员的导师,并通过他或她运行你的结果;脸皮厚一点,当他们说“我不明白你在说什么”的时候,把它当作改善沟通的机会
有效沟通对于数据科学家个人和职业的成功至关重要。我能给你的最好建议是:“记住,你正在解决一个商业问题,而不是一个科学实验。“你应该始终围绕必须做出的商业决策来定位分析或数据科学,而不是将其视为一个有趣的数学问题来探索。如果你做到了这一点,那么你将开始理解有效交流数据科学的正确方式。
这篇文章补充了我在 2018 年 9 月做的一次播客采访,其中有标签数据谈话,将对我见过的许多行之有效的技术进行更深入的讨论。上面的八(8)种技术总结了我讨论的要点,但是我强烈建议你收听播客,以了解我在何时何地看过这些作品的完整背景。
使用 Python 中的双轴图形实现更好的数据可视化
原文:https://towardsdatascience.com/better-data-visualization-with-dual-axis-graphs-in-python-a7f35a493558?source=collection_archive---------9-----------------------
大蟒
使用 Plotly 库以易于阅读的方式分析和展示您的数据

我才华横溢的姐姐的作品
可视化数据使人们更容易理解趋势并做出明智的决策。数据可视化的一个重要部分是选择合适的图表来展示数据。此外,甚至像条形图和折线图这样的特定图表也可以进一步定制,以最好地解释您想要展示的数据。
除了颜色和字体之类的修饰性变化,您还可以考虑添加额外的功能,如平均趋势线、预测或实现双轴。在这篇文章中,我们将介绍如何在折线图中使用双轴,让数据点之间的相关性和趋势对您的受众更加明显。我们还将快速看一下没有双轴的常规图表是什么样子,这样您就可以决定这两个图表中哪一个最适合您的可视化需求。
我们将使用 Python 中的 Plotly 库进行数据可视化,并使用 Pandas 进行一些初始数据预处理,所以请确保您已经安装了这两个包。然后,导入以下内容,并准备好跟随!
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import random
用 Plotly 简单实现一个规则折线图
首先,要生成一些示例数据,请运行以下代码。
expense_data = {
"Person": random.choices(["A", "B"], k=20),
"Amount": random.sample(range(100, 200), 10) + random.sample(range(0, 99), 10),
"Category": ["Groceries"] * 10 + ["Restaurant"] * 10,
"Date": pd.to_datetime(pd.date_range('2020-01-01','2020-10-01', freq='MS').tolist() * 2)
}
df = pd.DataFrame(data=expense_data)

我们将要可视化的数据将基于一些随机生成的个人支出数据。从上面可以看到,我们只是随机创建了 10 个月的费用数据,并将其加载到 Pandas 数据框架中。上面的代码应该输出 20 行数据。
**我们这次分析的目标是随着时间的推移比较“食品杂货”和“餐馆”的消费类别。**因此,接下来让我们使用几行熊猫按日期和类别字段对数据进行分组。
df_grouped = df.groupby(by=[pd.Grouper(key="Date", freq="1M"), "Category"])["Amount"]
df_grouped = df_grouped.sum().reset_index()

最后,仅使用 Plotly Express 的一行代码,我们就可以创建一个折线图,将分组的数据帧作为输入。
px.line(df_grouped, x="Date", y="Amount", color="Category")

Plotly Express 允许我们用一行代码生成上面的图表,在这里我们输入我们的数据帧、x 轴值、y 轴值和可选的color参数,因此在图表中有多条彩色的线(每个类别一条)。
这个图表看起来很不错,但是正如你所看到的,比较这两个类别有点困难。这从直觉上讲是有道理的,因为你会认为,一般来说,人们每个月在食品杂货上的花费要比在餐馆旅行上的花费多。(此外,我们将这个逻辑硬编码到生成这个样本数据的代码中——您可以在上面仔细检查它。)
接下来,让我们看看如何实现双轴,以便更容易地比较两种不同类别的支出。
用 Plotly 创建双轴折线图
首先,我们需要使用make_subplots(我们之前导入的)创建一个空的支线剧情。我们还将定义两个变量来命名我们的目标类别。
# making dual axis and defining categories
fig = make_subplots(specs=[[{"secondary_y": True}]])
category_1 = "Groceries"
category_2 = "Restaurant"
我们还没有输出任何东西,但是值得注意的是,在make_subplots方法中,我们在specs中传递了"secondary_y": True,以确保我们稍后可以正确地实现双轴。
接下来,我们将手动创建折线图中的第一条线。
# creating first plot
fig.add_trace(
go.Scatter(
y=df_grouped.loc[df_grouped["Category"]==category_1, "Amount"],
x=df_grouped.loc[df_grouped["Category"]==category_1, "Date"],
name=category_1
),
secondary_y=False,
)
以前,使用 Plotly Express 让我们只需通过一行代码就能生成所有内容,这真的很容易。使用常规的 Plotly 库意味着我们需要编写更多的代码。上图中,我们在前面定义的fig对象上使用了add_trace方法来添加来自之前分组的数据帧的数据。我们之前还将plotly.graph_objects作为go导入,所以我们可以传入 x 和 y 列的值。最后,我们将secondary_y设置为False,因为这只是图表中的第一行。
如果您运行fig.show(),您应该会看到类似这样的内容:

有点平淡,但目前为止还不错!现在,我们只有杂货数据。为了向第二行添加餐馆数据,我们将运行以下代码。
# creating next plot
fig.add_trace(
go.Scatter(
y=df_grouped.loc[df_grouped["Category"]==category_2, "Amount"],
x=df_grouped.loc[df_grouped["Category"]==category_2, "Date"],
name=category_2
),
secondary_y=True,
)
这几乎是完全相同的代码,除了我们使用category_2并传入secondary_y=True来代替。然后,如果您再次运行fig.show(),您应该会看到类似这样的内容:

看起来更好!与以前不同的是,我们可以更容易地看到这两类支出数据在一段时间内的相对表现。这只是随机生成的数据,但你可以看到在某些月份,当食品支出高时,餐馆支出相对较低(反之亦然)。
我们可以通过编写更多的代码来添加轴标签,使这一点更加清楚,如下所示:
fig.update_yaxes(title_text=category_1, secondary_y=False)
fig.update_yaxes(title_text=category_2, secondary_y=True)

我们在这里使用相同的update_yaxes方法,但是先传入 False,然后传入 True 到secondary_y参数,以适当地标记两个轴。
到目前为止,这非常好,但是我认为我们可以稍微清理一下,将所有的逻辑移到一个适合重用的函数中。下面是我的实现:
def create_dual_axis_graph(input_df, *args):
# making dual axis initial fig
dual_axis_fig = make_subplots(specs=[[{"secondary_y": True}]])
# defining categories from kwargs
categories = [*args]
assert len(categories) == 2, f"Must only provide two categories. You provided {len(categories)}." # creating graph with loop
for count, category in enumerate(categories):
dual_axis_fig.add_trace(
go.Scatter(
y=input_df.loc[input_df["Category"]==category, "Amount"],
x=input_df.loc[input_df["Category"]==category, "Date"],
name=category
),
secondary_y=count,
) dual_axis_fig.update_yaxes(title_text=category, secondary_y=count) return dual_axis_fig
我们做的事情和以前完全一样,除了我们删除了一些有助于演示的重复内容。create_dual_axis_graph函数将一个input_df作为主参数(您可以像我们之前一样提供已经分组的数据帧),然后将*args作为您想要检查的两个类别的名称。
我们将*args放在一个列表中(同时检查该列表只有两个元素),然后遍历该列表并再次使用add_trace方法添加 x 和 y 轴的数据。我们还将在这个循环过程中使用enumerate,这样 0 或 1(它们是布尔型的)可以被传递到add_trace和update_yaxes的secondary_y参数中,就像我们之前所做的一样。
运行该函数只需一行代码,如下所示:
create_dual_axis_graph(df_grouped, "Groceries", "Restaurant").show()
这将为您提供与之前完全相同的双轴图。为了展示不正确的实现会是什么样子,您可以尝试这样做:
create_dual_axis_graph(df_grouped, "Groceries", "Restaurant", "Appliances").show()

我们之前定义了一个AssertionError来确保只有两个参数被传递到类别列表中。您还可以定义一种更全面的数据验证步骤,比如检查数据帧是否有正确的列,列值是否有正确的数据类型,所提供的类别是否确实在数据帧中,等等。然而,对于这个演示,上面的函数就足够了。
就这些了,伙计们!
我希望这个快速(半端到端)的数据分析和可视化演示对您有所帮助!我喜欢双轴图,因为它使得在相同的尺度上比较两个不必要的类别变得非常容易,并且因为 Plotly Express 没有一种本地方式来做到这一点,我认为与每个人分享这个实现会很棒。
祝您好运尝试这种方法并将其用于您自己的数据!
再次感谢你的阅读!如果你正在考虑成为 Medium 的付费会员,如果你使用我下面的推荐链接注册,我会非常感激!这会让我直接收到你的一部分会费,所以这将是一个很大的帮助。
https://byrondolon.medium.com/membership
**More by me:** - [Check for a Substring in a Pandas DataFrame](/check-for-a-substring-in-a-pandas-dataframe-column-4b949f64852?sk=bfb5bbab11ae45c47bfb316d931c3b56)
- C[onditional Selection and Assignment With .loc in Pandas](/conditional-selection-and-assignment-with-loc-in-pandas-2a5d17c7765b?sk=e5672d859a3964c1453a1c09edca22cf)
- [2 Easy Ways to Get Tables From a Website With Pandas](/2-easy-ways-to-get-tables-from-a-website-with-pandas-b92fc835e741?sk=9981ddaf0785a79be893b5a1dd3e03dd)
- [5 (and a half) Lines of Code for Understanding Your Data with Pandas](/5-and-a-half-lines-of-code-for-understanding-your-data-with-pandas-aedd3bec4c89?sk=7007a1ae248cf7ea4ef5fcd4af7ae72b)
- [Top 4 Repositories on GitHub to Learn Pandas](/top-4-repositories-on-github-to-learn-pandas-1008cb769f77?source=friends_link&sk=d3acc38062490a86ecb46875342224e6)
做得更好贝叶斯?
原文:https://towardsdatascience.com/better-done-bayesian-a7759e295355?source=collection_archive---------13-----------------------
实践教程
用贝叶斯和频率统计规划我们的婚礼。

拍摄的照片在 Unsplash 上拍摄的照片
那是 2019 年夏天,我看着克罗地亚多云的天空,那时我深深改变了对统计的看法。在读完 Regina Nuzzo 的《p 值的诅咒》之后,我突然明白了——统计证据并不是我曾经认为的那样:即使是合理规划的随机实验的合理有力的“高度显著”的结果也可能变成假警报。因为即使是最聪明的科学家也无法关闭统计估计带来的自然不确定性。但还有一件事更让我感兴趣:即使是置信区间——我的大学教授曾经非常自豪地教给我们的一个概念——实际上也很少提到我们的估计带来的不确定性。在此之前,我认为置信区间反映了 95%最可信的参数值——或者至少包含了 95%情况下的“真实”值。但这要复杂得多。而且,我不知道我最初的解释甚至已经是贝叶斯理论了。在接下来的部分,我想告诉你传统假设检验的真正错误是什么——并更深入地探究理论基础。我的目标并不是以最不吸引人的形式呈现频繁主义者的统计概念,但我认为现在可能是时候对 p 值、置信区间和无假设显著性检验(NHST)进行更谦卑的解释了。那么,我们大多数人习惯的统计方法有什么问题呢?贝叶斯对等体真的能更好地找到我们问题的数据驱动答案吗?
有什么大惊小怪的?
假设我们正在进行一项实验,以发现与温水淋浴相比,定期冰浴是否真的能增强我们的免疫系统。如果你知道维姆·霍夫方法,这一假设应该会引起注意(艾伦,2018)。现在我们想知道相信冰浴真的对我们的免疫系统有很大影响有多合理——至少我们想避免在冰浴没有任何效果的情况下感到极度不适。因此,我们想用输入统计软件的真实数据来回答我们的问题。我们使用的数据分析(无论是 t 检验、方差分析、广义线性模型……)通常基于正式的数学模型。John Kruschke 和 Torrin Liddell (2018)提供了一个非常有说明性的定义:
你可以把数学模型想象成一台机器,它根据控制旋钮的设置,以某种模式产生随机的数据样本。例如,淋浴喷头喷出水滴(即数据)的模式取决于淋浴喷头的角度和喷嘴的设置(即参数)。”(克鲁施克&里德尔在 《贝叶斯新统计学:从贝叶斯的角度进行假设检验、估计、元分析和功效分析 (2018),第 2 页)
这意味着,不管我们使用的数据分析类型如何,我们总是试图通过统计模型尽可能好地模拟观察到的数据。为了达到这一目标,我们为机器(统计模型)配备了“模拟”自然的参数值,例如白细胞浓度随冰浴频率的变化。因此,我们可以将数据分析解释为对模拟观察数据的正确设置的搜索,以找到潜在的模式。换句话说:我们想知道“现实”是什么味道。
一旦我们有了想法,我们不想把它藏在心里——这就是为什么科学家喜欢用数学符号来表示数据。例如,众所周知,智力(以智商衡量)正态分布,参数 mu = 100,sigma = 15。有了这些数字,我们就可以对许多数据点进行简洁的总结,让我们能够对后续的观察做出推断:例如,我们可以说一个智商为 128 的人可能比你在街上遇到的绝大多数人都聪明。
许多研究人员的数学模型所基于的范式被称为频率主义统计学。它基于这样一种想法,即自然界的效应是固定的(但未知),而我们试图捕捉它们的数据是随机的。每一种经典的数据分析都包括基于虚数据采样分布的方法,这些方法会产生 p 值和置信区间。坚持我们的冰浴例子,统计计算将是这样的:为了证明在你的观察中是否有值得注意的模式,程序制造随机的假数据来表示如果冰浴是浪费时间会是什么样子。即便如此,参与者的免疫系统当然会有所不同——但这种差异完全是随机的,与任何温度控制无关。这就是零假设所代表的。现在,您的观察结果被汇总(例如,在 t 统计中),并与基于假样本的统计分布进行比较。根据冰浴和温水淋浴之间的“极端”差异,汇总统计留下了一定比例的实验可能结果。在这种分布的边缘,这些情况可以被认为是非常不寻常的,因为它们很少偶然发生。如果是这样的话,这应该让我们有点怀疑:我们应该考虑仔细看看。这就是 p 值所代表的——在一个零假设为真的世界中,观察到数据至少是这个极端值的可能性有多大?只有当您的数据收集完全遵循您的初始测试协议时,得到的估计才是正确的。按照惯例,我们不接受 p 值小于 0.05(或 0.01)就没有显著影响的观点。
拟议影响的大小及其不确定性通常基于最大似然估计(MLE),这是一种估计参数值的数学技术,使数据在模型环境中最有可能。是的——再读一遍这个句子。… 这使得数据最有可能出现在模型的上下文中 …这看起来是不是有点奇怪?
因此,置信区间是不会被正式假设检验拒绝的参数范围(例如,相对于某一免疫反应的平均差异)(坚持 p < .05)。因此,置信区间不一定给我们提供一系列我们可以“确信”的参数。除非你天生有一种非常技术化和数学化的思维方式,否则它无法被解释。
这就是对零假设显著性检验最深刻的批评的来源:没有办法直接和直观地解释统计结果。围绕这一概念有一个完整的误解指南,因为 p 值远非直观、简单明了(Greenland 等人,2016 年)-对于业余爱好者和研究人员来说都是如此。此外,有时似乎整个世界的分析师和研究人员都只盯着那个 p 值,战战兢兢地希望结果是“有统计学意义的”。我们对“中间”的任何结果都不感兴趣,是吗?学者们经常提到“过于简单化的非黑即白思维”(Kruschke & Liddell,2018)。当谈到有无效果时。然而,许多东西自然是灰色的。例如,暖浴和冰浴都不会强烈影响我们的免疫系统,而现实情况介于两者之间。出于对这一现象的好奇,我们想知道它的确切位置:这就是为什么我们需要对影响的大小进行一些估计(例如,冰浴能在多大程度上减少每年的感染数量?我们应该有多冷?)以及围绕该估计的不确定性(例如,我们对从我们的分析中得到的效应大小有多大把握?).
现在是时候对我们的分析程序采取更加细致和差异化的观点了——这是心理学研究多年来一直呼吁的事情:学者们主张从无意识的假设检验转向量化不确定性的估计,这种估计理想地建立在以前的研究基础上(Kruschke & Liddell,2018;Vandekerckhove,Rouder & Kruschke,20018),这一概念也被称为“新统计”(Cumming,2014)。
贝叶斯统计从何而来,它与频率主义者的观点有何不同?
虽然著名的贝叶斯定理在 1763 年左右就已经发表(Fienberg,2006)并且一直存在,但贝叶斯统计直到今天才流行起来。在世界上的每一门“初学者统计学”课程中,学生们在学习频率主义统计学之前——如果有的话——他们后来会发现贝叶斯统计。然而,与频率统计相比,贝叶斯估计可以更好地处理噪声数据和小样本,并且具有更直观和直接的解释。方便的是,有一些方法可以使用相同的统计程序(t 检验、相关性、ANOVAs 等)。)在“贝叶斯”术语中,它允许分析师结合关于所讨论现象的先验知识(例如,基于以前的数据,当涉及到免疫系统时,我们可以预期冰浴和温水淋浴的人之间有多大的差异?).这使得它成为促进元分析和持续研究的理想候选,这是一个很大的优势,我将在后面更深入地讨论。贝叶斯统计受到许多作者的喜爱,因为它有可能对抗心理学中的可信度危机(Kruschke & Liddell,2018 年),有能力减轻发表偏倚,有能力将更多可测试的理论纳入统计模型。尽管如此,贝叶斯并没有让你在分析数据时摆脱思维的束缚——我们无法从“动态”数据中得出有意义的结论,这是有充分理由的。即使我们可以认为显著性测试是科学中的一个坏习惯,贝叶斯显著性测试(即贝叶斯因子)本身并不能满足我们的问题。无论哪种方式,我们都必须全面处理利益问题。
那么,贝叶斯统计有什么不同呢?与频率统计相反,贝叶斯假设数据是固定的,而自然界的影响是未知的。因此,相应的估计可以被定义为不同可能选项的概率的重新分配。Kruscke & Liddell (2018)为这种思维风格提供了一个极好的类比(在Bayesian data analysis for the 新人, p. 2):夏洛克·福尔摩斯的任务是找到一个杀人犯。他从对每个嫌疑人不同程度的怀疑开始,不断寻找证据,让他重新考虑自己的观点。即使嫌疑人 A 从一开始看起来相对无辜,但一旦排除了其他嫌疑人(例如,因为他们有强有力的不在场证明,他们的动机与犯罪不符,等等),他/她似乎更有可能犯了罪。…).按照贝叶斯的说法,夏洛克·福尔摩斯从对每种可能性(犯罪嫌疑人)的先验信任度开始,逐渐重新分配每种可能性的可信度,并以后验信任度结束——这是他在跟踪最有可能犯罪的人时应该非常确定自己的猜测的地方。这一过程非常接近我们的自然推理方式,并转化为以下模型:我们从各种可能的参数组合开始,根据我们到目前为止的知识,某些值或多或少是可能的,这称为先验分布。现在,我们收集数据,并可以计算每个数据点被赋予我们所知道的总体效果的可能性——这被称为可能性分布。看到这些数据后,我们的知识需要更新,因为我们现在对哪些参数是可信的有了更狭隘的理解。我们认为与数据不一致的参数值可信度较低,因此与数据一致的参数值可信度较高。我们对理论上可能的每个参数值重复这一过程——这种数据驱动的洞察然后产生后验概率分布。这种分布总结了我们新的知识状态,并可以为未来的分析师提供服务,以建立他们对类似问题的“先验信念”。
多亏了这个程序,我们可以更彻底地测试各种假设:虽然 NHST 只能拒绝零假设(由低 p 值表示),但贝叶斯假设测试的结果不仅拒绝或接受假设,还包含一个“灰色区域”——对于在给定数据的情况下仍未决定哪个假设更有可能的情况。有时我们只是还不知道——这种证据状态在研究中应该很常见,因为自然很复杂,很难理解。因此,“介于两者之间”的结果应该相当令人放心。但是这个选项经常被我们提供“重要”结果的需要所否决。贝叶斯假设检验有三种状态:
- 数据提供了有利于 H0 的充分证据
- 数据提供了有利于 H1 的充分证据
- 数据无法支持任何一种假设
这种三方面的区别导致了这样一个事实,即贝叶斯和频率主义分析并不总是得出相同的结论,即使它们基于相同的数据(Dienes & Mclatchie,2018 年)——提供支持任一假设的证据的能力与早期完全不同。贝叶斯假设检验可以表明零假设比替代假设(或者相反)更可信,而 NHST 永远做不到这一点,因为它不产生相对概率。
请记住,当使用频率统计时,我们只能测试针对 H0 的证据*——如果我们假设没有任何影响,这些数据看起来够奇怪吗?这是一个有点麻烦的技术,因为我们通常对支持替代假设的证据更感兴趣。我妈妈会说我们好像是“从后面穿过胸腔进入眼睛”(而不是直视)。即使我们非常确定我们的数据在“无效效应”的情况下似乎不太可能,我们也无法知道我们脑海中的选择是否正确。我们甚至不知道零假设首先是否是假的。我们掌握的证据相当薄弱,实际上我们的问题仍未解决。似乎这还不够糟糕,p 值还伴随着其他(方法论)问题,使它们变得非常不方便(例如,著名的“测试和停止意图”)。*
总之,贝叶斯统计和频率统计之间的差异可以总结如下:
- 对于常客来说,效果是固定的,而数据是未知的,而对于 Bayesians 来说,数据是固定的,效果是未知的。
- Frequentist 方法基于从零假设采样的虚构数据提供 p 值,而 Bayesian 方法比较数据的相对能力,以支持零假设、替代假设或两者都不支持。
- 频率主义者的推理基于观察给定假设的数据的概率,而贝叶斯主义者估计给定数据的某个假设的概率。
案例分析——我如何才能知道哪个月会足够温暖,适合我的婚礼派对?
几个星期前,我已经开始和我一生的挚爱计划婚礼。我们想和我们最亲密的家人和朋友在他父母的花园里开一个小派对。但是在组织一切的时候,我们在想我们最好是在四月还是五月结婚,因为我们想在外面庆祝。总的来说,四月是个不错的选择,因为我的肚子还没有五月大,而且柏林的天气已经很热了。另一方面,五月可能是一个更好的候选人,因为有更多的时间让 COVID 感染下降,天气应该足够温暖——但我们能有多确定?

Honey Yanibel Minaya Cruz 在 Unsplash 上拍摄的照片
作为一名数据科学爱好者,我将使用数据来回答我的问题。为此,我将使用传统的频率主义方法以及一些贝叶斯对应方法。首先,我查看了一些历史温度数据。我发现了一些有趣的表格——柏林自由大学的 rg Wichmann 和 Manfred Wegener 发表的气象数据集合。这些表格显示了自 1908 年以来柏林-达勒姆每月每天观测到的最极端最高日温度以及平均最高日温度。为了对四月和五月的极端和正常最高温度有一个印象,我提供了相应的数据:
为了绘制结果,我将温度值的每个向量保存在一个数据帧中,并将它们整理成一种更整洁的格式。
数据几乎已经准备好用于绘图——我们只需要设置调色板并保存每个参数的平均值(最大值、最小值、平均值),用密度图明确表示它们。


看起来柏林四月份的平均最高温度为 13.4°C(SD = 1.52),而最热日的温度通常在 0.5°C 到 30.9°C 之间变化——在柏林天气数据的历史上,四月份有非常寒冷的日子(例如 1911 年 3 月 4 日),但也有非常温暖的夏天(1968 年 3 月 22 日)。通过观察 4 月份每天的正常最高气温,我们可以发现,4 月上半月的最高气温约为 11°C,而 4 月下半月的最高气温可达 15°C 左右。这也解释了 4 月份平均最大值数据的密度曲线的下降。嗯——五月会有不同的趋势吗?


我们可以预计一个典型的五月天的温度将达到 18.7 摄氏度(SD = 1.51),正如所料,这比一个典型的四月天要暖和得多,即使正常的最高温度变化程度不同。历史上,我们经历过 5 月份的最高日温度在 3.8 摄氏度(1941 年 5 月 3 日)和 33.3 摄氏度(2005 年 5 月 28 日)之间。与 4 月相比,有史以来观测到的最低最高温度(用蓝色表示)比有史以来观测到的最高温度(用红色表示)覆盖的数值范围更广。这可能是因为与四月相比,五月不太可能出现寒冷的气温(尽管我们有几个稍微凉爽的五月天),但当一个典型的五月天无论如何都是温和的,很难超过真正炎热的夏季温度。与 4 月相似,接近月末时天气变得越来越暖和,5 月上半月的温度约为 17°C,下半月的温度约为 19°C。但是我们能有多确定五月对于我们的游园会绝对是一个更好的选择呢?
通过从五月的正常最高温度中减去四月的正常最高温度,我们得到一个差值向量。因为 May 包括多一天,所以我们需要排除最后一个值,以便进行公平的比较和便于计算。我们最后得到以下描述性统计数据:
嗯,看起来五月的一个典型日的最热时刻通常比四月的一个典型日的最热温度高 5.27°C,而它通常相差 1°C。一般来说,自 1908 年以来的几十年中,正常的最大温差在 3.7°C 到 6.4°C 之间。但是,五月和四月的最高气温实际上没有差别,这种可能性仍然存在吗?
假设我们只有去年(2020 年)的数据。
为了检验我们的假设,我们首先计算独立样本的经典 t 检验。

如您所见,p 值超过 0.05,这意味着很有可能只是偶然观察到这些温度差异。通过查看置信区间,我们可以看到给定数据下包含 95%最可能温差的范围,对吗?不。我们不知道 CI 包括的温度差异中哪一个更可能,因为没有包括分布信息:区间中间(大约 0)的参数值不一定比 CI 边缘的值更可能。我们可以说,如果用相似的数据反复进行相同的实验,95%的温度平均差异将在-1.51 和 2.71 之间,包括零(无差异)。如果我们真的只有 2020 年的数据,我们会决定暂时不拒绝零假设。好吧,但是贝叶斯如何解决这个问题呢?
首先,我们当然会使用所有可用的温度数据,但我想让算法更难模拟最糟糕的情况:实际缺乏数据。如果我们有一个杂乱的小样本,数据分析表明了什么?
让我们来探索理查德·d·莫雷和他的同事们(2015)的 BayesfactorR-package 中的贝叶斯 t 检验。我们正在分析 Bayes 因子,以检验替代假设(五月和四月之间的温差)和零假设(无温差)。

[1] Alt., r=0.707–这是指差异可能有多大的假设,而默认值是基于心理学中常见的通常效应大小。我们可以使用 ttestBF-语法来改变这个假设,但是我们暂时不做讨论。
贝叶斯因子是数据中支持两个假设之一的相对证据。换句话说,它是一个假设比另一个假设更好地预测观察到的数据的程度。在这里,我们计算替代的 hyothesis(五月和四月之间的温差)比无效的零假设能更好地预测观察到的数据的程度。由于贝叶斯因子在我们的案例中已经下降到 1 以下,证据表明 H0 比 H1 更有利(杰弗里斯,1998)。如果原假设的先验概率相对于替代假设减少了 0.30 倍,这表明我们现在应该接受原假设,因为支持我们替代假设的证据还不够有力。即使贝叶斯因子和 p 值并不总是一致,经验法则表明,0.05 的常规 p 值大致等于贝叶斯因子 3 (Dienes,2014;Jeffreys,1998)即使一些研究人员总体上要求更高的决策阈值(Etz & Vandekerckhove,2017;Schö nbrodt 等人,2016 年)—在我们的案例中,贝叶斯因子和 p 值都表示保留零假设。
然而,我们应该记住,拒绝零假设的事实并不能告诉我们任何关于效果大小的信息。当——就像在我们的例子中——零假设没有被 p 值拒绝或者甚至没有被贝叶斯因子接受时,人们倾向于相信实际上存在零效应。鉴于 2020 年的温度数据只是 100 多年来可用温度观测的一部分,仍然有理由相信 5 月实际上仍然比 4 月更温暖。如果我们对以前的一组历史温度数据进行相同的分析,我们会得到不同的结果,这一事实支持了这一想法(为了清楚起见,我在这里不给你看)。
好的——我们现在想知道根据我们的后验分布,可信的温度差是什么样的:

从图中可以看出,MCMC 迭代运行稳定,我们现在知道日温差可能在-2°C 和 2.5°C 之间,中间值约为 0.48°C。
使用 Makowski 及其同事(2020 年)的bayestr-package,我们还可以从后验分布中计算出参数值的数量,这些参数值代表实际上相当于“无影响”的温度差异。例如,如果五月的平均气温比四月高 1 摄氏度或低 1 摄氏度,我不会选择五月而不是四月来举办我们的游园会。从统计学上讲,我们可以计算实际等效区域(ROPE ),该区域被定义为“零”值周围实际等效于“无效”的区间。在临床研究中,它可以用来测试实验组是否实际上不同于对照组,因此已经纳入了一种“最小”效应大小(有关函数的详细概述,也请参见:马科夫斯基,本-沙查尔&吕代克,2019 )。
结果表明,72.3 %的温度差异位于我们预先定义的实际等效区域内,这意味着不到三分之一的数据指向五月和四月之间有意义的差异。为了找出哪个月实际上更暖,我们可以计算方向概率(PD)——它可以被解释为观察到的温差(由其后验分布描述)严格为正或负的概率(以最有可能的为准)。在数学上,它被定义为后验分布中中位数符号的比例(在我们的例子中是正的,表明五月比四月暖和)。

在我们的例子中,根据我们的后验分布,有 69.70 %的可能性五月比四月暖和。

由拍摄的黄致远婚礼在 Unsplash
鉴于我很确定无论如何五月可能是一个更好的选择,我想测试一个具体的日期:五月 28 日天气够暖和可以在外面庆祝吗?
我的决定规则是:如果结果表明我们婚礼当天的某个时候气温可能会达到 21 摄氏度或更高,我可以在室外庆祝。那么,5 月 28 日气温超过 21 摄氏度的可能性有多大?
当我在寻找一种频率主义方法来回答这个问题时,我偶然发现了基于历史天气数据预测气温的 ARIMA 模型。但是因为这似乎超出了本文的范围,我们将直接跳到贝叶斯方法。此外,我将向您展示如何从零开始应用贝叶斯方法,不涉及任何特殊的 R-package,灵感来自 Rasmus B eth 的 R 中的课程贝叶斯数据分析基础。为什么?这样,通常发生在幕后的必要步骤对您来说变得更加明显。
首先,我们需要一些新的温度数据。我发现一个网站提供了过去 10 年中柏林 5 月 28 日的最高气温。我们将使用这些数据和我们“更多”的历史数据来估算 2021 年最有可能的最高温度。
现在,我们需要为温度数据定义一个生成模型——您可以将它视为未知的潜在分布模式,它可能会在几年内生成 5 月 28 日的最高气温。为此,我们需要一个可能值的参数空间来表征 5 月 28 日最高气温数据的“真实”分布,因此我们指定 mu(总体均值)和 sigma(总体标准差)。当然,我们无法真正知道真实的潜在分布,但基于我们在上一节中建立的关于所有 5 月最高日温度的知识,我们可以假设 mu 可能位于 10°C 和 30°C 之间,sigma 可能在 0.5°C 和 6°C 之间。即使我们想对 5 月 28 日进行预测,我们使用从上个世纪的极值中获得的信息也会有点保守。通过使用网格近似,我们将测试 mu 和 sigma 的任何可能的参数组合,以计算其与我们已有数据的兼容性。
网格将足够宽和细粒度,以表示理论上可能的任何参数组合。结果参数空间如下所示:

接下来,让我们定义 mu 和 sigma 的先验概率——基于我们对每个可能参数与我们所知的可能性的信念。通过查看 FU 温度数据,我们可以看到 5 月 28 日的平均最高温度为 20°C,我猜每年可能相差 3°C 左右。此外,我假设平均温度呈正态分布,因此我们将此信息放入 dnorm 函数中,以创建适当的密度函数。然而,对于 sigma,我认为 0.5°C 和 8°C 之间的任何值都是同等可能的,因此我将使用均匀分布。最高温度数据的先验现在基于μ和σ,并相乘以获得组合的先验概率分布。
现在需要为每个可能的参数组合计算数据的可能性,假设可能性函数接近正态分布。然后,我们结合这一计算,分别为每个可能的参数组合获得所有 10 个温度观测值的似然值。
根据贝叶斯法则,我们计算后验分布如下:
后验∝先验*似然/先验加权的似然之和

在考虑新数据后,mu 最可信的参数值似乎在 22°C 左右,sigma 最可信的参数值在 6°C 左右。
哇,终于到了预报我们婚礼天气的时候了!现在,让我们根据我们创建的模型,尝试预测 5 月 28 日最可信的最高气温。在通常的贝叶斯软件解决方案中,我们将通过使用马尔可夫链蒙特卡罗方法,从后验概率分布(在我们的情况下为后验 28)中随机抽样最可信的一组参数值来实现这种预测。对于本例,我们将通过从模拟概率分布中随机抽样 mu 和 sigma 来简化这种方法,模拟概率分布直接由我们的后验分布提供信息。出于预测目的,我们使用 mu 和 sigma 的后验分布来模拟 10000 个新鲜温度样本。

好的——不错!在我看来,我们将会有一个 21 摄氏度左右的最高气温,但是超过 21 摄氏度的可能性有多大呢?
sum(pred_temp >= 21 ) / length(pred_temp)
大约 55%的预测样本超过 21 摄氏度。老实说,这比我希望的要少,但我们将能够举办一次花园聚会的机会并不坏。现在,5 月 28 日最高气温的最可能值是多少?
为此,我们将计算最大后验概率(MAP ),定义为后验分布的最可能值。

根据我们的计算,我们现在知道 5 月 28 日平均最高日温度的最可信值是 22.93 摄氏度。鉴于我们仍然有些不确定,哪个温度范围也是可信的呢?

与 frequentist 置信区间相反,我们可以直接从后验分布中“读出”估计的不确定程度。更具体地说,在给定数据的情况下,最高密度区间(HDI)跨越了 95%最可能的参数值。换句话说,它是一个区间,从该区间开始,所有包含的值比该区间之外的值具有更高的概率。在我们的例子中,我们预计 mu 的最可信值在 12°C 和 30°C 之间(HDI 89% [12,30])。
总的来说,当谈到在户外庆祝时,我现在更有信心了——我关于选择五月而不是四月的问题,以及 28 日气温的预测,都没有用 Frequentist 统计数据充分回答。我知道我们应该多带些外套以防万一。但是为什么贝叶斯估计在我的案例中胜出呢?在总结之前,让我们转向理论层面。
贝叶斯统计的优点是什么?他们能做得更好的是什么?
贝叶斯统计可以直接解释,并且符合我们的自然推理。
从我的角度来看,贝叶斯统计最根本的优势在于能够对我们最初提出的问题给出令人满意的答案。相比之下,传统统计学在大多数情况下实际上是基于错题。例如,我们不想要今天下雨的概率(这有点荒谬),而是今天下雨的概率。翻译成概率术语,它转换成这样的事实,即频率主义者要求给定(空)假设为真的数据的概率,而贝叶斯主义者要求给定数据(例如,今天的天气参数)的假设的概率(例如,将下雨)。第二个问题肯定更有趣—这可能是为什么 p 值和置信区间被解释为好像它们是贝叶斯的(例如,p 值 0.05 意味着零假设为真的概率是 5%,对吗?…).如果我们得到了与我们想知道的完全相反的结果,为什么我们会有兴趣首先测试它呢?
贝叶斯统计促进信息丰富的&合作研究。
在心理学研究和许多其他学科中,实际的研究不仅仅是由寻找真相的动机驱动的:包括“无关紧要”结果的草稿仍然留在大型科学期刊的文件抽屉中——各自的研究可能不够醒目,不足以吸引读者的注意,即使其他研究人员可能有兴趣找到发现。一些作者认为,贝叶斯估计可以通过定义一个不同的成功标准来克服这种出版偏差:编辑应该根据一项研究的实际限制条件是否达到了合理的精确度来检查草稿,而不是专注于统计意义(Kruschke & Liddell,2018)。因此,高度精确的结果在研究中应该比高度“重要”的结果更有价值——因为独立研究应该是开放式的。参考开放科学的理念,预先登记研究的过程也有助于减少偏见。
此外,贝叶斯估计允许对任何样本大小进行稳健估计——这对于习惯于追求足够大的 Ns 的人来说是非常方便的先决条件。这不是没有原因的:p 值和置信区间需要足够大的样本大小来进行可靠的计算和足够的能力,而另一方面,它也不应该太大,因为算法往往会过于乐观,甚至会拾取最微小的影响。对频率主义者统计数据的依赖带来了另一个问题:估计不仅会因样本大小而产生偏差,还会直接依赖于分析师的确切测试和停止意图。这意味着,如果我们计划测试 50 名参与者,结果却只有 60 名,那么 p 值应该会受到影响。为什么?因为频率主义者的统计是基于模拟的,可能结果的云随着我们最终得到的每一个额外的(或缺失的)观察而变化。一个类似的原则适用于进行比原计划更多的测试:我们可以观察到 p 值的膨胀,因为小的 ps 变得越来越没有价值。这是因为我们每进行一次额外的测试,发现任何重要结果的机会就会增加。因此,我们必须明确地对多个测试进行校正(例如,使用 Bonferroni 校正)。对于贝叶斯估计,我们不担心固定的 N 个观察值或测试值,因为它不是基于假想分布的抽样。
贝叶斯估计的另一大好处是,它促进了持续研究和累积知识的增长,这种想法通常是通过汇总特定现象的证据状态的元分析来实现的。理想情况下,随着越来越多的研究进行,我们希望积累我们的知识,并使证据不断发展。因此,单个研究应该基于以前的研究,并作为未来研究的基础,以最终得出更可靠的结论。然而,我们迄今为止的荟萃分析可能会得出错误的结论,因为 a)有些研究从未发表,b)一些包含“无关紧要”结果的研究经常被解释为证明自然界中绝对没有影响。如果有更多发表的基于贝叶斯估计的数据分析,我们将对反对、支持或不支持某个假设的试验性证据有一个更全面、更精细的看法。更好的是,贝叶斯估计带有一个特殊的随机效应模型,以从合作研究中获得洞察力:元分析可以分层建模,为我们提供每个个体(低水平,例如单个研究)和一般(高水平,例如跨研究的整体变化)参数的描述(Kruschke & Liddell,2018)。这使得在数据中找到潜在的模式变得更容易,同时允许研究之间的一些可变性。
贝叶斯统计反映了证据的连续程度。
当涉及假设检验时,p 值和贝叶斯因子都包括“有用的”约定,这些约定反映了足以值得注意的证据程度。然而,贝叶斯因子仍然遵循另一个基本原理:它代表证据的连续程度。在我们的例子中,它展示了一个微小的暗示,即 2020 年 5 月和 4 月的最高日温度之间应该有差异,即使它通常让我们认为有更多的证据支持零假设。我非常欣赏这种想法,因为对于 p 值来说,没有明显的界限或必要的阈值,为数据驱动的见解留下了更多空间,这些见解由分析师的经验所伴随和告知。因为我们将证据理解为证据的阴影,并且每个估计的不确定性都被明确地建模,贝叶斯统计使我们对自己的解释更加谦逊(也更加自信)。
贝叶斯统计让我们记住了舞蹈。
另一个支持贝叶斯统计的论点是,它承认自然界多样性的美。我的意思是,它可以将我们的注意力转移到随机和动态的变化上,这些变化自然地发生在样本之间,甚至发生在个体之间。换句话说,贝叶斯估计可以帮助我们记住数据的“舞蹈”(Cumming,2014)。相反,Frequentist 模型并不明确地以数据为条件,而是以虚拟样本的模拟为条件,以找出我们的数据在面对特定场景时有多奇怪(例如,如果五月和四月之间的最高日温度相同)。使用贝叶斯估计,我们可以模拟非常复杂的系统,同时仍然允许不同的人,措施和研究的可变性。
贝叶斯统计的缺点是什么?为什么它不能让我们摆脱所有的问题?
贝叶斯统计比频率统计更直观、更灵活、信息量更大——这是肯定的。然而,在比较这两种范式时,我们应该记住,现实世界的决策不应该基于单个研究的 p 值或贝叶斯因子是否超过某个阈值这一事实。对统计显著性概念的滥用告诉我们,我们应该尽一切可能避免这种对甚至无法复制的结果的机械的非黑即白的思考。在解释数据时,任何统计指标都不能作为唯一的推断来源——相反,分析师可以从各种不同的统计工具中受益。用著名科学家 Gerd Gigerenzer 和 Julian Marewski 的话说,贝叶斯因素不应成为又一个“盲目的无效仪式”(Gigerenzer 和 Marewski,2015 年,第 423、437 页)。
此外,贝叶斯估计受到主观性的指责,因为先验分布的规范给分析者留下了更多的自由度。即使我们也能欣赏结合相关背景知识的机会,但这让我们承担责任:我们需要有意识地选择先验知识,并事先形成理论上合理的假设。如下,先验分布应该尽可能具体。让我给你举个例子:如果我们假设零假设的可信度很小,那么贝叶斯因子必须很大才能产生实际上有利于零假设的后验概率。因此,贝叶斯估计直接受到分析师背景知识的影响。这可能会阻止年轻而天真的分析师去尝试——但事实并非如此。
哪个范式能更好地回答我的问题?
我们可以说,如果准确性是你的目标,贝叶斯统计应该是选择的估计,而如果减少假阳性率是你的目标,频率统计是你的伙伴。在我看来,这肯定也取决于你的个人喜好。就我个人的案例研究而言,我更喜欢贝叶斯统计,因为它对我来说信息量更大,即使我花了一些时间才弄明白。不幸的是,贝叶斯估计很少在大学教授,因此一些专业人士可能会在没有深入知识的情况下犹豫使用它。可以理解!这两种方法都应该在适当的时候使用——考虑到自然通常是复杂的,我们只有有限的可能性通过数据来接近真相。但是如果我们尝试,让我们保持一点谦卑。我们永远无法确切知道。
参考文献
[1] J. Allen,“维姆·霍夫方法的用户特征和报告效果:一项混合方法研究” (2018),特温特大学硕士论文。
[2] J. K. Kruschke & T. M. Liddell,贝叶斯新统计:从贝叶斯角度进行假设检验、估计、元分析和功效分析 (2018 ),心理计量学通报&综述,25(1),178–206。
[3] S. Greenland,S. J. Senn,K. J. Rothman,J. B. Carlin,C. Poole,S. N. Goodman & D. G. Altman,统计检验,P 值,置信区间和功效:误解指南 (2016),《欧洲流行病学杂志》, 31 (4),337–350。
[4] J. K. Kruschke & T. M. Liddell,新人贝叶斯数据分析 (2018),心理计量学通报&综述,25(1),155–177。
[5] J. Vandekerckhove,J. N. Rouder,J. K. Kruschke,推进心理科学的贝叶斯方法 (2018),心理计量学通报&综述 (25),1–4。
[6] S. E. Fienberg,贝叶斯推理什么时候变成了“贝叶斯”?(2006)贝叶斯分析,1(1),1–40。
[7] Z. Dienes & N. Mclatchie,比显著性检验更喜欢贝叶斯分析的四个理由 (2018),心理计量学通报&评论,25(1),207–218。
[8] H .杰弗里斯,《概率论》(1998),OUP 牛津大学出版社。
[9] Z. Dienes,使用 Bayes 从非显著性结果中获取最多信息 (2014),《心理学前沿》,5781 页。doi:10.3389/fpsyg
[10] A. Etz & J. Vandekerckhove,关于再现性项目的贝叶斯观点:心理学 (2016),PloS one,11(2),e0149794。
[11]f . d . schnbrodt,E. J. Wagenmakers,M. Zehetleitner & M. Perugini,带 Bayes 因子的序贯假设检验:有效检验均值差异 (2017),心理学方法,22(2),322。
[12] D. Makowski,D. Lüdecke,M. S. Ben-Shachar,M. D. Wilson,P. C. Bürkner & T. Mahr,Package‘bayeststr’(2020),最后一次查看于 2020 年 8 月 20 日。
[13] D. Makowski,M. S. Ben-Shachar,D. Lüdecke,bayestr:描述贝叶斯框架内的效应及其不确定性、存在性和意义 (2019),开源软件杂志,4(40),1541。
[14] G. Cumming,《新统计:为什么和如何》 (2014),心理科学, 25 (1),7–29。
更好的带 Katib 的 ML 模型
原文:https://towardsdatascience.com/better-ml-models-with-katib-6c0dbbbe401f?source=collection_archive---------29-----------------------
Kubernetes 上的自动机器学习超参数调整

由 Markus Gjengaar 在 Unsplash 拍摄
在机器学习中,超参数是用户定义的值,在训练期间保持固定。超参数的例子是 k-means 聚类中的k值、学习速率、批量大小或神经网络中的隐藏节点数。
虽然现在有一些技术依赖于在我们的模型学习时改变这些值(例如,Leslie Smith 的单周期策略、模拟退火等)。),这些不是可学习的参数,例如神经网络的权重。
然而,超参数可以极大地影响由训练过程生成的模型的质量以及算法的时间和存储器要求。因此,必须调整超参数,以获得给定问题的最佳配置。
我们可以手动或自动调整模型的超参数。在大多数情况下,手工执行这项任务是不切实际的。因此,自动超参数调整机制将有助于在合理的时间范围内发现每个超参数的最佳值。
许多系统自动完成这一过程。这个故事考察了 Katib ,这是一个开源的、框架无关的、云原生的、可扩展的、生产就绪的超参数调优系统。但是为什么我们需要另一个超参数优化引擎呢?我们已经有了众多的选择: Optuna ,远视, NNI ,维齐尔,或者雷。所以,首先,让我们看看 Katib 做了什么来改善现实世界中的事情。
Learning Rate 是为那些对 AI 和 MLOps 的世界感到好奇的人准备的时事通讯。你会在每周五收到我关于最新人工智能新闻和文章的更新和想法。订阅这里!
动机
要在生产环境中部署机器学习系统,我们必须同时满足数据科学家和 DevOps 工程师的需求。这并不容易,因为环境的这两个用户很少说同一种语言。
数据科学家对开发尽可能精确的 ML 模型感兴趣;因此,要调整模型的超参数,它们的工作方式如下:
- 使用数据集的一个样本,在他们的本地机器上试验 HP 调优
- 将实验转移到更大的计算环境中,在那里可以利用专用硬件的能力,如 GPU 或 TPU
- 比较并可视化结果
- 在团队内部跟踪、版本化和共享结果
另一方面,DevOps 工程师管理基础设施,确保平台保持健康和高度可用。我们可以将开发运维工程师的职责总结如下:
- 执行资源高效型部署
- 支持多个用户,通过动态资源分配在同一系统中执行不同的操作
- 实时升级系统,不会给用户带来任何停机时间
- 通过日志记录监控系统并及时做出决策
定义了背景之后,我们需要我们的系统来工作,让我们看看 Katib 如何应对这些挑战。
Katib 优势
Katib 是唯一一款能够在本地数据中心或私有/公有云中作为托管服务运行的惠普调优系统。这是真实的原因有很多:
- 多租户: Katib 支持多租户,这有利于跨团队协作。维齐尔也支持多租户;然而,Vizier 是一个专有系统。
- 分布式训练: Katib 支持分布式训练(如参数服务器、RingAllReduce 等。).像 Optuna 和 HyperOpt 这样的流行框架缺乏对分布式训练的支持。
- Cloud-native: Katib 是 Kubernetes 准备好的。这使得它非常适合云原生部署。射线调谐和 NNI 也支持 Kubernetes,但需要额外的努力来配置。
- 可扩展性: Katib 很容易扩展,提供了一个模块化接口,允许搜索算法和数据存储定制。
- NAS: Katib 是仅有的两个支持神经架构搜索的框架之一,另一个是 NNI。
因此,作为一个支持多租户的分布式容错系统,Katib 同时满足了数据科学家和系统管理员的需求。
系统工作流程
现在让我们检查一个典型的工作流,用户将遵循这个工作流与 Katib 进行交互。在本例中,我们将使用贝叶斯优化创建一个 HP 调优作业。
- 用户可以创建 YAML 规范并使用客户端工具(如
kubectl)提交,也可以通过编程方式与 Katib 通信。这里,为了清楚起见,我们将做前者。因此,让我们创建一个Experiment的 YAML 规格。
apiVersion: "kubeflow.org/v1beta1"
kind: Experiment
metadata:
namespace: kubeflow
name: bayesianoptimization-example
spec:
objective:
type: maximize
goal: 0.99
objectiveMetricName: Validation-accuracy
additionalMetricNames:
- Train-accuracy
algorithm:
algorithmName: bayesianoptimization
algorithmSettings:
- name: "random_state"
value: "10"
parallelTrialCount: 3
maxTrialCount: 12
maxFailedTrialCount: 3
parameters:
- name: lr
parameterType: double
feasibleSpace:
min: "0.01"
max: "0.03"
- name: num-layers
parameterType: int
feasibleSpace:
min: "2"
max: "5"
- name: optimizer
parameterType: categorical
feasibleSpace:
list:
- sgd
- adam
- ftrl
trialTemplate:
primaryContainerName: training-container
trialParameters:
- name: learningRate
description: Learning rate for the training model
reference: lr
- name: numberLayers
description: Number of training model layers
reference: num-layers
- name: optimizer
description: Training model optimizer (sdg, adam or ftrl)
reference: optimizer
trialSpec:
apiVersion: batch/v1
kind: Job
spec:
template:
spec:
containers:
- name: training-container
image: torch-mnist:v1beta1
command:
- "python3"
- "/opt/torch-mnist/mnist.py"
- "--batch-size=64"
- "--lr=${trialParameters.learningRate}"
- "--num-layers=${trialParameters.numberLayers}"
- "--optimizer=${trialParameters.optimizer}"
restartPolicy: Never
一个Experiment是一个定制的 Kubernetes 资源(CRD ),指的是一个完整的用户任务。例如,这里的Experiment命令 Katib 运行一个贝叶斯优化任务。目标是通过调整学习率或优化器选择等参数来最大化验证的准确性。它将并行运行3试验,如果没有达到目标(即验证精度> = 0.99),它将在12试验后终止。
在这种情况下,我们对自己创建的 MNIST 数据集使用 PyTorch 解决方案。
2.这将触发一个Suggestion规范的创建。Suggestion是另一个 Kubernetes CRD,它请求创建基于优化算法的x平行试验。因此,对于我们的示例,它将生成以下规范:
spec:
algorithmName: bayesianoptimization
requests: 3
3.接下来,基于搜索算法,部署相关服务。在我们的例子中,每个实验都将部署一个贝叶斯优化服务。
4.然后Suggestion控制器用来自算法服务的结果更新Suggestion规范。
spec:
algorithmName: bayesianoptimization
requests: 3
status:
suggestionCount: 3
suggestions:
- name: bayesianoptimization-run-1
parameterAssignments:
- name: --lr
value: "0.013884981186857928"
- name: --num-layers
value: "3"
- name: --optimizer
value: adam
- name: bayesianoptimization-run-2
parameterAssignments:
- name: --lr
value: "0.024941501303260026"
- name: --num-layers
value: "4"
- name: --optimiz
value: sgd
- name: bayesianoptimization-run-3
...
5.我们现在准备产生多个Trials。如果您要将模型训练代码重构为一个函数,那么Trial将执行这个函数,并将超参数建议作为参数传递。这句话几乎是真的。确切发生的情况是,我们的Experiment定义中的trialTemplate被转换成一个runSpec,其中建议替换了模板变量:
runSpec: |-
apiVersion: batch/v1
kind: Job
metadata:
name: bayesian-run-1
namespace: kubeflow
spec:
template:
spec:
containers:
- name: bayesian-run-1
image: katib-mnist-example
command:
- "python"
- "/classification/train_mnist.py"
- "--batch-size=64"
- "--lr=0.013884981186857928"
- "--num-layers=3"
- "--optimizer=adam"
6.最后,Trial控制器读取Trial规格并产生相应的TrialJobs。超参数作为命令行参数传递给TrialJobs。
7.Trial控制器监控TrialJobs并更新Trial状态中的相关字段。当底层作业完成其运行时,Trial也被标记为完成。度量被报告给度量存储,并且最佳客观度量被记录在Trial状态中。
8.最后但同样重要的是,Experiment控制器读取所有试验的状态,并尝试验证我们是否达到了目标。如果Experiment已经达到其目标,那么它被标记为完成。如果没有,它将继续运行,直到达到Experiment规格中指定的最大试验次数。
如果你认为工作量很大,让 Kale 为你处理所有这些步骤。请看下面的故事:
结论
在这个故事中,我们描述了什么是超参数,以及为什么优化模型的超参数配置很重要。我们看到这是一个很难手工完成的任务。因此,我们研究了 Katib 如何帮助我们实现这一过程的自动化。
Katib 是迄今为止唯一一个在云世界中如此自然出现的超参数优化系统。投入其中,让它为您处理惠普优化的日常工作。
学习率是为那些对 AI 和 MLOps 的世界感到好奇的人准备的时事通讯。你会在每周五收到我关于最新人工智能新闻和文章的更新和想法。在这里订阅!
关于作者
我的名字是 Dimitris Poulopoulos ,我是一名为 Arrikto 工作的机器学习工程师。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲央行、经合组织和宜家等主要客户设计和实施过人工智能和软件解决方案。
如果你有兴趣阅读更多关于机器学习、深度学习、数据科学和数据运算的帖子,请在 Twitter 上关注我的 Medium 、 LinkedIn 或 @james2pl 。此外,请访问我的网站上的资源页面,这里有很多好书和顶级课程,开始构建您自己的数据科学课程吧!
所表达的观点仅代表我个人,并不代表我的雇主的观点或意见。
更好的 Pythoning 化 1:三元运算符
如何通过几个简单的步骤来缩短代码行并使其更具可读性

图片取自 hiteshchoudhary
如果您是数据科学的初学者,很可能您已经遇到过三元运算符(很酷的单行 If 语句)。你是否想知道它们是什么,为什么它们无处不在,什么时候应该使用它们?
在这篇文章中,我将用例子简要地解释三元运算符,使它们易于理解。这是关于使用单行语句来缩短代码(例如,列表理解、Lambda 函数等)的四部分系列的第一部分。).本系列的最后一篇文章将教你如何结合这些不同的方法来大大缩短你的代码。我希望读者喜欢阅读这篇文章,学习一些新的东西,同时提高代码的可读性。
三元运算符——或者我称之为“花哨的 if 语句”
在 Python 中,IF 语句允许你在某些情况下运行代码的某些部分。一个简单的例子:
自然,这可以扩展到包括更复杂的命令。三元运算符可以实现 if 语句在一行中完成的大部分功能,例如:
这可以从字面上理解为:print('I have a name')如果my_name为真否则print('I don\t have a name')。
truthy 指的是 Python 读为 boolean
True的东西。这几乎可以是任何东西,除了一些显著的例外(这些被称为 falsy),比如一个空列表[],一个零0,一个空字符串''等等。
当 if 语句的唯一功能是设置变量时,这非常有用。例如:
注意,这是一个非常简单的例子,通过设置
is_retired = age > retirement_age可以使它变得更加简单。
关键是三元运算符本身实际上不是语句,它们实际上是一个值。这意味着语句True if age > retirement_age else False就像一个运行后会返回值的函数。
另一方面,if 语句本身并不返回任何值。返回或不返回值的是 if 语句中的实际内容。这非常重要,因为像raise这样的函数不能用在三元运算符中,因为它们实际上不返回任何东西。
那么,如果是这样的话,第一个带print的三元运算符是如何工作的呢?事实上,这并不违反规则:print在运行时返回None。
如果你怀疑这一点,尝试设置
a = print('Hello World'),然后print(a)
这意味着当我们执行print('I have a name') if my_name else print('I don\t have a name')时,我们实际上返回了None,但是我们没有指定一个变量来存储这个值!
最后一个复杂的问题是:三元运算符也可以接受函数的值。这解释如下:
值得注意的是,三元运算符中的函数difference和print没有任何括号。整个事情外面的括号意味着那些实际上是以(retirement_age, age)为变量的函数。虽然这很酷,但通常不经常使用,而且代码过于复杂,所以最好避免。
关键要点:
- 三元运算符是一个单行 if 语句,看起来像运算符,根据条件,必须返回值
- 这意味着它们对于设置变量非常有用,但是对于运行代码却没有用
- 三元运算符可以链接,例如:
my_surname = 'Unchained' if my_name.lower() == 'django' else 'Fett' if my_name.lower() == 'jango' else 'Surnameless' - 三元运算符可以用另一种形式编写,如下所示
- 值得注意的是,三元运算符只有在设置变量时才真正提高可读性,更复杂的用例是 if 语句的更好储备
结论
三元运算符有:
- 对于使代码可读来说相当强大(当明智地用于
return变量时) - 当用于简单表达式时,使你的代码更短
总的来说,我发现它们比 if 语句更好,并经常使用它们,尤其是因为它们对效率没有显著影响(见附录)。
值得注意的是,当在其他函数和表达式中使用这些操作符时,它们会变得更加强大,比如 List Comprehensions(同样,这是很酷的单行循环),这是下一篇文章的主题。在这篇文章中,我将举例说明它们在实际数据科学问题中的用处。对列表理解的一个简短的窥探:
附录
这是我运行的一个小实验,看看三元运算符是否对效率有任何影响(根据堆栈溢出,它们不应该)
我比较了两个使用三元运算符或 if 语句设置变量的 for 循环。然后,我重复实验 100 次,计算每次运行的时间差。代码和结果如下所示:

从上面我们可以看到,三元算子稍微慢了一点,大概~2.5%是相当小的。
更好的 Pythoning 化 2:列表理解(包括带有 spaCy 的 NLP 示例)
如何通过几个简单的步骤缩短代码行并使其更具可读性

图片取自 hiteshchoudhary
如果您是数据科学的初学者,那么您可能会遇到 List Comprehensions(很酷的循环单行代码)。你想知道这些是什么吗?为什么它们如此普遍,什么时候应该使用它们?
在这篇文章中,我将用例子简要地解释列表理解,使它们易于理解。我将特别强调它们与 for 循环的区别,以及它们是否更有效。
这是关于使用单行语句缩短代码的四篇系列文章的第二篇。本系列的上一篇文章研究了三元运算符(很酷的单行 if 语句)。本文将建立在前一篇文章的基础上,向您展示列表理解和三元运算符如何一起使您的代码更短、更易读。
我希望你喜欢阅读这篇文章,学习一些新的东西,提高你的编码技能。
列出理解——“花式循环”之类的?
在 Python 中,for 循环允许你遍历一个 iterable 来执行重复的任务。
典型的例子是打印数字 1 到 10:
这里,函数range是一个 iterable 对象,它创建从 0 到num — 1的数字(因此,本例中总共有 10 个数字)。我们可以使用列表理解来重新创建这些:
上面的语句是,range(num)中的每个i对应print(i+1)。我们基本上用少一行代码重复了相同的任务,这似乎并没有节省多少空间。那么这些有用吗?
当然了。
如果我们目光敏锐,我们会注意到我们实际上已经创造了一个list。我们同样可以将其设置为一个变量,例如:
numbers = [i + 1 for i in range(num)]
这很容易理解:在列表中为range(num)中的每个i创建一个值为i+1的元素。如果我们打印numbers,我们会得到:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
您可能想知道打印示例创建了什么?因为我们运行了print 10 次,所以我们创建了一个None值的列表(因为print返回None):
[None, None, None, None, None, None, None, None, None, None]
这使得我们的列表理解对于设置变量非常强大,因为我们有效地创建了变量,并在 iterable 运行时将它们存储在一个列表中。相比之下,for 循环不会在它自己的上创建任何东西,而是由我们传递给 for 循环的东西来做这件事。
将其与使用 for 循环创建列表所需的行数进行比较:
除了列表理解更短这一事实之外,值得注意的是它们更具可读性。
简单地说,值得注意的是,列表理解也可以用于创建集合和字典。例如:
列表理解和三元运算符
当你把列表理解和三元操作符一起使用时,你可以打开一个新的可读性层次。
**示例 1:** 假设您是一名教师,有一本学生姓名及其考试成绩的字典,您想从中提取成绩不太好的学生的姓名,以便为他们提供更多支持。
您可以使用 for 循环来实现这一点,但是使用列表理解要容易得多(并且可读性更好..):
列表理解为:在score小于或等于failing_threshold的情况下,为student_scores.items()中的每个student和score保存student。
值得注意的是,这个上下文中的列表理解只对减少数据有用。例如,不可能将不及格的学生和及格的学生都存储在两个不同的列表中。为此,您可以使用 For 循环。
三元运算符有用的另一个例子是,如果您希望根据某个条件来区别对待列表的组件。
**示例 2:** 假设您有一个包含学生及其分数的相同数据集,但是您想要创建一个目标变量“fail ”,如果学生不及格,该变量将给出 1,如果学生及格,该变量将给出 0
你可以这样做:
注意,这实际上是一个简单的例子,因为 if 语句和三元运算符都可以用int(score <= fail_threshold)代替。
然而,我们注意到当我们将列表理解与三元运算符一起使用时,它们会变得相当复杂(并且很长)。当你试图让你的代码更易读的时候,这是需要记住的。
二维列表理解?
列表理解可以被链接,这允许它们超越一维。让我先解释一个例子,你可能需要这个。
我最近遇到了一个问题,我需要展平一个列表列表,例如:
list_of_lists = [[1,2], [3,4], [5,6]]
我想把它转换成list_of_lists = [1,2,3,4,5,6]
我的第一反应是使用解包操作符*,但是这在列表理解中不受支持。我的逻辑是:
相反,我发现我需要本质上链接两个列表理解来使它变平:
令人困惑的是,逻辑并不符合你的预期:我的直觉是num for num in list_ for list_ in list_of_lists,但是 Python 要求列表顺序颠倒。
也可以在这里添加三元运算符,分别作用于列表理解,但是正如您可以想象的那样,这使得代码的可读性非常差,因此我个人避免这样做。我只是为了完整起见才添加的。
spaCy 的应用实例
我将给你一个真实的数据科学的例子,说明列表理解是多么有用,特别是在 NLP 中。
我使用 spacy 来创建我拥有的Doc文本对象。这意味着每个token实际上是一个对象,包含解释那个token是什么的参数(例如,它是一个名词,一个动词,一个数字等等……)。
spacy 做了所有这些注释,这很好,因为清理过程在我这边变得非常容易(也非常可读…):
结论
列表理解本质上是一种从可重复项创建列表的方法。它们提供了一种简单的方法,用一行代码概括大量的代码,使得代码非常易读。
关键要点:
- 列表理解是一个单行 for 循环,用于从 iterables 实例化新列表。与 for 循环不同,它们返回值
- 当与三元运算符一起使用时,它们对于从受约束的现有列表创建新列表非常有用
- 他们更有效率(参见附录)
- 它们可以被链接以沿着更高的维度工作,但是这失去了可读性
- 它们可以用于字典、集合和列表
- 像往常一样,更复杂的情况最好留给循环和 if 语句
总的来说,我发现这些理解非常优雅,并尝试将它们用于上述用例。正如你所看到的,列表理解在与三元运算符一起使用时确实很出色,然而,它们也可以与 Lambda 函数(很酷的单行函数)结合使用,这可以使你的代码更加紧凑。这将是本系列下一篇文章的主题,这是一个短暂的高峰:
附录:
和我之前的文章一样,我想试验一下列表理解是否比使用 for 循环更快。三元运算符的实验表明,它们的效率比循环略低。
为此,我用学生的名字进行了实验,并对包含 1000 个学生名字的字典进行了评分。我重复了 10000 次。值得注意的是,在这种情况下,必须在 for 循环中使用 if 语句,在 list comprehension 中使用三元运算符。

我们可以看到列表理解实际上要快 30%,这给了我们更多的理由去使用它们。
更好地量化视频中对象检测的性能
原文:https://towardsdatascience.com/better-quantifying-the-performance-of-object-detection-in-video-c21d5b16493c?source=collection_archive---------21-----------------------
视频对象检测有几个独特的挑战,使其区别于静态图像中的对象检测。

来源
对象检测现在是计算机视觉中最常见的应用之一,特别是随着普通分类问题已经变得更容易用现代深度学习架构来解决。由于大规模数据集(例如 COCO [1])的广泛可用性,对象检测研究对于计算机视觉社区来说变得更加容易,从而导致技术以惊人的速度发展。随着对目标检测的研究越来越深入,在视频中进行目标检测的并行研究已经出现。这样的问题是几个通常研究的计算机视觉问题(即,跟踪、对象检测和分类)的混合,其中对象必须通过视频内的相关帧被正确地定位、分类和关联(即,相同的对象在不同的视频帧中通过唯一的标识符被如此标识)。
视频对象检测有几个独特的挑战,使其区别于静态图像中的对象检测。在这篇文章中,我不会概述任何当前的视频对象检测方法(见[2]更全面的视频对象检测概述)。相反,我将讨论该领域目前阻碍持续技术进步的主要问题之一:**缺乏一种可以评估视频中对象检测器性能的综合指标。**没有这样一个评估视频对象检测器的标准化指标,不同方法之间的比较变得困难,导致研究人员质疑他们的贡献是否真正有价值。
作为这个问题的解决方案,我认为高阶跟踪精度(HOTA)是对象跟踪社区中的一个标准化指标,是视频对象检测的正确指标,只要它具有分类意识。我将通过提供开发更好的视频对象检测指标的动机来开始这篇文章。然后,我将介绍一些与对象检测相关的概念和定义,然后讨论该领域中存在的当前指标。我将以对 HOTA 指标的讨论来结束这篇文章,强调它作为视频对象检测评估指标的适用性。
为什么我们需要更好的指标?
简而言之,视频对象检测的度量标准的当前状态非常差。特别是,该领域研究人员的常用方法是在视频的每一帧上分别评估他们的模型,然后平均所有帧的性能。结果,完全忽略了视频对象检测性能的时间方面,并且不可能根据这样的度量来确定整个视频中预测的时间一致性。换句话说,这种评估协议将视频对象检测简化为在静态图像内执行对象检测(即,每个帧被视为独立的检测问题),这(如前所述)是完全不同的问题。尽管这种方法可能是合理的起点,但是对于将时间数据结合到它们的预测中以鼓励随时间的一致预测的基于视频的对象检测器(例如,基于光流的检测方法)来说,这显然是不合适的。
与静态图像中的对象检测相比,视频对象检测的时间方面是使问题变得困难和有趣的关键部分。因此,最广泛使用的视频对象检测度量不能捕捉这种时间行为是完全不可原谅的。如果没有更好地量化视频对象检测性能的所有方面的指标,社区将无法取得一致、向前的进展,因为无法正确比较所提出方法的性能。为了解决这个问题,必须标准化和采用统一的度量标准(即一个度量标准,而不是几个度量标准的组合)。理想情况下,视频对象检测的适当度量应该提供单个可解释的分数(可能分解成多个更具体的子分数),该分数捕获视频对象检测性能的所有相关方面,包括检测、定位、关联和分类。
相关概念
在本节中,我将简要讨论几个有用的概念,这些概念对于理解目标检测评估非常重要。特别地,我将描述匈牙利算法(即,用于将预测对象与真实对象相关联的对象检测中最常用的算法)和平均精度度量(即,用于静态图像中对象检测的最广泛使用的评估度量)。
匈牙利算法
在任何形式的对象检测中,我们在评估期间被给予一组基础事实和预测对象。但是,现在还不清楚这些预测中的哪一个符合事实。因此,在评估预测的质量之前,必须做一些工作来确定基础事实和预测对象之间的最佳映射。更具体地说,必须产生预测对象和基础事实对象之间的一对一映射。然而,预测的或基本事实对象也可能没有匹配(即,在这种情况下,映射在技术上不是一对一的,因为存在不成对的元素)。
匈牙利算法是一种组合优化算法,可用于在多项式时间内解决集合匹配问题。在对象检测领域中,它通常用于生成预测对象和真实对象之间的映射,通常基于对象之间的成对交集/并集 (IoU)分数。此外,对于在匈牙利算法中要相互匹配的对象,通常会施加一些额外的要求(例如,两个边界框对象检测的 IoU 必须大于 0.5 才能被认为是可行的匹配)。由于匈牙利算法的性能和效率,它对于这样的应用是理想的。
平均精度
如前所述,平均精度(mAP)是评估静态图像中对象检测器的标准度量。为了计算 mAP,必须首先计算图像中的真阳性/阴性和假阳性/阴性的数量。在运行匈牙利算法之后,计算这样的度量是非常简单的(即,我们仅仅检查检测是否丢失了一对、对是否是错误的,等等)。).由此,可以在图像内的不同“置信度”水平上计算精度和召回率,以确定平均精度(AP)。对于给定问题领域中的每个不同的语义类,这样的过程被单独重复。然后,计算所有语义类的平均精度的平均值,形成平均平均精度(mAP)度量。
想要更深入的描述 mAP,我推荐阅读这篇文章。然而,理解(1) mAP 是用于评估静态图像中的对象检测性能的首选指标,以及(2) mAP 是通过查看单个图像中的预测指标来计算的,这对于理解本文的剩余部分应该是足够的。
我们已经有了哪些衡量标准?
在我介绍(在我看来)最适合评估视频中的对象检测器的指标之前,有必要考虑一些可以使用的其他指标。我将根据指标是用于对象检测还是对象跟踪来将此讨论分为两类,并对每种指标进行简要的高级描述,旨在展示其在评估视频对象检测方面的不足之处。首先,回想一下测量视频中对象检测的性能有四个主要部分:检测、定位、关联和分类。如本节所述,目标跟踪不考虑评估的分类部分*,但目标跟踪的分类感知指标有可能捕捉视频目标检测性能的所有相关部分*。
目标检测
如前所述,评估视频中对象检测的最常见指标(在撰写本文时)是图。具体地,跨视频的每个帧单独计算 mAP,并且跨所有视频帧取 mAP 分数的平均值,以形成最终的性能度量。这种方法完全不能捕捉视频对象检测的时间方面(即,没有关联的概念),因此不足以作为评估协议。然而,mAP 目前是视频中对象检测的首选度量,并且关于改变/修改该度量的讨论似乎很少。
一个包含时间信息的有趣的地图变体是基于速度的地图【3】(也就是说,我为这篇博文的上下文编造了这个名字;相关联的引用不提供特定的名称)。为了计算该度量,首先基于对象在帧之间移动的速度(即,使用相邻帧的运动 IOU 来计算),将对象分成三个不同的组(即,慢、中和快)。然后,为这三组中的每一组中的对象分别计算 mAP,并且分别呈现三个 mAP 分数。尽管基于速度的图基于视频中的对象速度提供了对象检测性能的更细粒度的视图,但是它提供了三个度量而不是一个,并且仍然不能捕捉视频对象检测的时间方面;同样,映射不包含关联的概念。因此,基于速度映射不是视频对象检测的合适度量。
为视频对象检测提出的最后一个度量是平均延迟(AD)【4】。AD 捕捉的是物体进入视频和被探测器“拾取”之间的延迟,这种延迟被称为“算法延迟”。这种延迟是以帧为单位测量的,因此 AD 为 2 意味着,平均而言,对象将在视频中存在两个完整的帧,直到它被模型实际检测到。虽然 AD 在视频对象检测中捕获时间信息,*它被提议作为一种与 mAP* 结合使用的度量。因此,它不是一个可以用来全面评估视频中对象检测器性能的独立指标。
目标跟踪
尽管还没有针对视频对象检测提出全面的度量,但是在对象跟踪社区中存在许多有用的度量,从中可以获得灵感。对象跟踪要求在整个视频中以一致的方式识别、定位和关联对象(每个视频帧中的一个或多个对象)。虽然对象跟踪不包含分类的概念,但是在对象跟踪和视频对象检测之间存在足够的重叠,以保证对对象跟踪中的当前评估度量进行更深入的检查。
多目标跟踪精度(MOTA)【5】是目标跟踪中最广泛使用的度量之一。MOTA 将基础事实与每个检测的预测对象相匹配,这意味着在评估过程中,每个预测和基础事实检测都被视为一个独立的实体。在高层次上,MOTA(基于匈牙利算法提供的匹配)确定所有视频帧中的身份切换(即,相同的对象在相邻的视频帧中被分配不同的标识符)、假阳性和假阴性检测的数量。然后,通过用视频中地面实况对象的总数对这些分量的总和进行归一化来计算 MOTA,如下式所示。

MOTA 跟踪度量
MOTA 通过身份切换(即,表示为上面的IDSW)来捕获关联性能,而检测性能通过假阳性和假阴性来捕获。但是,MOTA 不考虑本地化。相反,定位必须通过一个单独的指标来衡量,多目标跟踪精度(MOTP) [5],它对视频中所有检测的定位分数进行平均。尽管 MOTA 是用于对象跟踪的长期标准化度量,但是它有几个缺点,这限制了它在视频对象检测中的适用性。也就是说,它过分强调检测性能(即,身份转换对上述分数的影响是最小的),不考虑相邻帧之外的关联,不考虑定位,提供多个分数而不是统一的度量,高度依赖于帧速率,并且提供可能难以解释的无界分数(即,MOTA 可以具有[-∞,1]的值)。因此, MOTA 不足以作为视频对象检测的度量。
对象跟踪社区中其他广泛使用的指标是id f1【6】和 track-mAP (也称为 3D-IoU),它们在轨迹级别上将地面实况与预测进行匹配(即,轨迹被定义为贯穿视频帧的预测或地面实况对象的序列,它们共享相同的唯一标识符)。与 MOTA 相比,IDF1 和 track-mAP 在对象跟踪社区中没有得到广泛使用,因此我不会对这些指标进行深入讨论(有关指标之间更全面的讨论和比较,请参见[7])。然而, IDF1 和 track-mAP 都有许多限制,这阻碍了它们被采用为视频对象检测的标准度量。也就是说,IDF1 过分强调关联性能,不考虑定位,并且忽略彼此不匹配的轨迹之外的所有关联/检测。类似地,轨迹地图要求每个轨迹预测包含置信度得分,要求轨迹距离度量由用户定义,并且可以容易地“游戏化”(即,可以提供简单的反例,其表现很差但是实现了高轨迹地图得分)。
走向全面的衡量标准
尽管上一节概述了指标的局限性,但截至 2020 年中期,对象跟踪社区中有一个新的标准指标:更高阶跟踪精度(HOTA)【7】。在本节中,我将介绍 HOTA 指标,并解释为什么我认为它是评估视频对象检测器的合适指标。虽然 HOTA 不考虑分类性能,但它的分类感知对应物 CA-HOTA 在单个评估指标内有效地捕获了视频对象检测性能的所有相关方面。
为什么是 HOTA?
HOTA 的目标是(1)提供一个单一的分数,该分数捕捉跟踪性能的所有相关方面,(2)使长期关联性能能够被测量(即,两个相邻帧之外的关联),以及(3)分解成捕捉跟踪性能的更详细方面的不同子度量。HOTA 旨在缓解以前跟踪指标的问题,它提供了一个在[0,1]范围内的单一分数,该分数以平衡的方式捕获跟踪性能的所有相关方面(即检测、关联和定位)。此外,这个单一的、可解释的分数可以分解为子指标,这些子指标在更细粒度的级别上表征跟踪性能的不同方面。下图总结了与其他广泛使用的跟踪指标相比,HOTA 的优势。

HOTA 与其他跟踪指标的比较[7]
尽管 HOTA 不考虑分类性能,但是已经提出了将分类并入 HOTA 得分的变体(例如 CA-HOTA)。CA-HOTA 在一个可解释的指标内捕获视频对象检测性能的所有方面(即关联、定位、检测和分类)。因此,CA-HOTA 可以被认为是用于视频对象检测的(相对)全面的度量。
HOTA 是什么?

`,HOTA 度量的说明[7]
与 MOTA 类似,HOTA 在探测层面(即,与 IDF1 或 track-mAP 中的轨迹层面相反)匹配预测和地面实况对象。在 HOTA 中,从基础事实和预测对象匹配(同样由匈牙利算法产生)中计算出两类度量:检测组件和关联组件。检测组件只是真阳性、假阴性和假阳性,这在前面已经讨论过了。有些不同的关联成分包括真阳性关联(TPA)、假阴性关联(FNA)和假阳性关联(FPA)。
考虑在特定帧中具有有效匹配的对象(即,真正的肯定检测),我们将其表示为c。在这种真正的肯定检测中,预测和基础事实对象都必须被分配一个唯一的标识符。为了计算 TPA 的数量,只需找到与c共享相同基本事实和预测标识符的其他帧中的真阳性的数量,并对视频内的每个可能的c重复该过程(即,每个真阳性检测)。FNA 和 FPA 以类似的方式定义,但是必须在其他帧中找到分别具有相同基本事实标识符和不同预测标识符或者相同预测标识符和不同基本事实标识符的检测。实质上,TPA、FPA 和 FNA 允许跨视频内的所有帧测量关联性能,而不仅仅是相邻帧之间的关联性能。因此,命名为“高阶”跟踪精度。
给定某个定位阈值(即,定位阈值修改由匈牙利算法产生的匹配),我们可以计算 HOTA 的所有检测和关联组件。然后,在给定定位阈值(我们表示为α)下的合计 HOTA 分数可以计算如下。

单一定位阈值下的 HOTA 度量
一旦在特定本地化阈值下计算出 HOTA,就可以通过在几个不同的本地化阈值上对上述度量进行平均来导出合计 HOTA 分数。通常,定位阈值的样本取值范围为[0,1],如下式所示。

HOTA 度量
如上面的等式所示,HOTA 捕获检测(通过检测组件)、关联(通过关联组件)和定位(通过定位阈值)性能。此外,HOTA 可以分解成许多子指标。下图中概述的每个子指标都可以用来分析跟踪器性能的更具体方面(例如,定位、检测或孤立的关联性能)。

HOTA 中的子指标[由作者创建]
关于如何计算 HOTA 度量的更全面的讨论,也可以阅读相关论文[7]或博客文章[8]。
分类呢?
我之前提到过,可以修改 HOTA 来获取分类性能,但是从来没有明确说明这是如何实现的。尽管提出了分类感知 HOTA 的多种变体[7],但一种可能的方法是在某个定位阈值处修改 HOTA 得分,如下所示。

分类感知 HOTA (CA-HOTA)
从上面可以看出,分类性能是通过用给定真阳性检测的正确类别的相关置信度来缩放对 HOTA 度量的所有贡献而合并的。因此,如果分类性能很差,HOTA 度量将会恶化。给定以上定义,然后可以将合计 CA-HOTA 度量计算为不同本地化阈值上的得分的平均值(即,就像对于普通 HOTA 一样),产生 CA-HOTA 度量。
结论
目前,视频对象检测社区缺乏正确捕捉模型性能的统一评估度量。通常,使用 mAP 度量并跨视频帧进行平均来表征性能,但是这种技术完全忽略了模型性能的时间方面。根据对象跟踪领域的最新进展,我认为高阶跟踪精度(HOTA)度量是视频中对象检测的合适评估标准。HOTA 的分类感知变体 CA-HOTA 捕获视频对象检测性能的所有相关方面,包括检测、关联、定位和分类。因此,它是一个全面的指标(尤其是与 mAP 等静态指标相比),可以而且应该用于对视频对象检测中的不同方法进行基准测试。
我希望这篇文章能在社区内引发讨论,并为视频中的对象检测带来更标准化和更全面的基准测试。这项工作是我在 Alegion 做研究科学家工作的一部分。如果你对这个话题感兴趣,我鼓励你去看看这家公司,或者申请一个空缺的职位。我们一直在寻找更多对机器学习相关话题感兴趣的人!要了解我的博客文章,请随时访问我的网站或在 twitter 上关注我。
参考文献
[1]https://cocodataset.org/#home
[2]https://www.mdpi.com/2076-3417/10/21/7834
https://arxiv.org/abs/1703.10025
[4]https://www . research gate . net/publication/335258204 _ A _ Delay _ Metric _ for _ Video _ Object _ Detection _ What _ Average _ Precision _ Fails _ to _ Tell
【https://arxiv.org/abs/1603.00831
[6]https://arxiv.org/abs/1609.01775
[7]https://arxiv.org/abs/2009.07736
[8]https://jonathonluiten . medium . com/how-to-evaluate-tracking-with-the-hota-metrics-754036d 183 e 1
通过利用标签的层次结构提高深度学习分类模型的可靠性
原文:https://towardsdatascience.com/better-reliability-of-deep-learning-classification-models-by-exploiting-hierarchy-of-labels-986603170fe0?source=collection_archive---------24-----------------------
如何使用来自标签的附加信息来训练合理性模型
在实践中使用预测性深度学习模型往往会带来一个问题,即我们可以在多大程度上信任该模型的预测。虽然有几个框架来验证它确实学习了正确的特征(例如,石灰, LRP ),但对于看不见的数据,仍然不能保证预测的类别是正确的。增加这种模型的可信度的一种选择是引入似真性检查。建立这种检查的一种方法是使用来自标签的分层结构的信息,这在公共数据集(CIFAR-10,Image-Net)中经常见到。目标是建立第二个模型,在层次结构中的父标签上训练,这篇文章将展示为什么这增加了模型的可靠性以及代价是什么。
扁平标签结构
大多数对新模型架构和更好的模型的研究都是基于平面标签,从数据集中丢弃了层次结构。对于 ImageNet 通常使用 1000 个标签, Birdsnap 使用 500 种鸟类作为标签。有一些模型利用了这些类别的层次结构,如 HD-CNNs 和 Tree-CNNs ,但这是一个相当小的领域。
在实践中,我们经常有这样的应用,其中我们的训练数据是有限的,并且随着时间的推移而增长。我们每个类别用于训练的图像数量是变化的,一些标签的准确性比其他标签差。新的标签不时出现,我们至少应该知道,我们可以在多大程度上依赖我们的预测。换句话说,我们能在多大程度上信任我们的模型?
概率分数在看不见的数据上是不可靠的
好的一面是,我们有概率得分,我们可以用它来估计预测的确定性。然而,当一个模型面对新数据时,它有时会给我们很高的概率分数,即使预测完全错误。特别是在具有许多标签的图像 CNN 中,当处理新数据时,我们可以观察到不稳定的预测。当我们谈论细粒度图像分类时,这个问题变得更加难以解决,在这种情况下,图像中的小细节会产生影响。

图 1—Twitter 上一些非常流行的错误分类
这些例子通常很难解决,但它们很好地说明了问题。一个以动物品种为标签的 CNN 无法检测食物或拖把。CNN 通常会采取一切可能的捷径来解决这个问题,很明显,从物体的整体颜色、形状和姿态来看,这些图像看起来非常相似。由于在动物身上训练的神经网络不理解狗的概念,它会感到困惑,并以很高的可信度对这些例子进行预测。
但是,如果我们另外有一个不同的 CNN 训练检测鼻子,眼睛和其他特征,这是动物的代表呢?
从标签中挖掘领域知识
这就是合理性检查的想法。如果第二个模型被训练来检测与我们的标签相关的不同特征,我们可以检查可信度。我们想从我们的数据结构中发掘信息。
另一个例子是在第二个模型中使用来自 ImageNet 的活动信息,并检查该活动与检测到的对象相结合是否有意义(当然,该信息必须在层次结构中编码)。
有了这些信息,就有可能利用标签结构中隐含领域知识。一个假设是,似真性模型受益于每类的大量训练数据,并且概括得更多,因此防止了过度拟合。
训练模型以检查可信度
原始模型在我们的目标标签上训练,因为它们在最高粒度上(标签层次结构中的叶子)。似真性模型在更高级别的标签(图中的父节点或相关节点)上被训练。为了使用动物分类器示例,原始模型根据动物的品种进行训练,并且具有 1000 个不同的标签,而似真性模型被训练来对数据中的 50 种不同的动物进行分类。
一个旁注:
你可能会认为用多个模型直接对层级进行建模会容易得多,例如一个模型用于动物,在检测到动物后用另一个模型来检测每只动物的品种。是的,这是可能的,但是除了玩具数据,我们通常在一个树中有更多的类和节点,最终有数百个模型集合在一起。这通常是不实际的。
具有似真性模型的另一个好处是,我们也可以使用带有不完整标签信息的图像。我们知道这种动物,但不知道确切的品种。当对现有的图像分类系统使用用户反馈时,这种情况经常发生。用户可能无法确定动物的品种,但清楚地知道它是一只狗。对于一个检测品种的模型来说,这些例子是不可用的。但是对于第二个模型,我们可以包括它们。
测试可信度
当我们训练这两个模型时,我们可以预测两个概率分数,一个用于细粒度目标标签,一个用于粗粒度似真性标签。由于类别数量的减少和每个类别图像数量的增加,我们的似真性模型通常比原始模型具有更好的准确性。
最后,我们得到图像的两个预测,并需要对结果应用一些逻辑:
- 当两个分数都很高,并且原始模型(例如品种)预测了一个标签,该标签与似真性预测(例如动物)相匹配时,我们可以假设该预测是正确的。举例:0.98 狗/ 0.89 秋田
- 当两个分数都很低时,我们知道结果不可靠或者图像上有简单的其他东西。例如:0.05 的狗/ 0.07 的小猎犬
- 当原始模型预测值较低,而第二个模型预测值较高时,我们可能会在原始模型的训练数据中发现一个缺失的标签(例如,缺失的品种)。举例:0.98 猫/ 0.28 波斯
- 当原始模型预测值较高而可信度模型预测值较低时,可能会出现上图所示的情况。不是猫,但形象很像。举例:0.21 猫/ 0.98 波斯
- 最后,最有趣的情况:假设我们的似真模型有很高的概率,原始模型有中等的概率,但标签不是似真的:例如:0.98 狗/ 0.47 波斯。显然,波斯人不是狗。但是,如果我们在原始模型中查看第二好的预测,发现 Briard 的 0.46,实际上是一只狗,会怎么样呢?在这里,假设布里亚德是正确的似乎是合理的。因此,一般来说,我们可以应用一个逻辑(或另一个模型),搜索与给定动物匹配的最小分数的品种模型的前 n 个预测。
结论
使用似真性模型,其中数据中的层级信息是可用的,可以使预测更可靠。如果系统给出相互矛盾的分数,我们可以认为预测是错误的。此外,通过不仅查看顶部的预测,还查看前 N 个预测,我们可以更深入地了解模型的可能错误,找到丢失的标签,甚至纠正预测。另一方面,我们需要一个额外的模型,并在系统中引入逻辑检查。
数据科学中更好的软件写作技巧:保持干燥
原文:https://towardsdatascience.com/better-software-writing-skills-in-data-science-be-dry-efe6d3dc2e27?source=collection_archive---------38-----------------------

封面图片由https://pixabay.com/users/chillervirus-2033716/pix abay组成。
首先,我想回到上周的帖子,问你一个问题。我收到了一位读过我博客的朋友的评论,他告诉我一些大致的内容:“显然,让你的学员读一本书是你的指导方式”。这让我想到……考虑到与不直接与我合作的学员进行准时的指导会议(连续数周,每周半小时),考虑到提高软件开发技能的总体目标,以及更具体的 Python 软件编写技能,有人能提出更好的方法吗?我真诚地接受建议。
现在,让我们继续使用当前的方法,并将本周的指导和帖子建立在“实用程序员:从熟练工到大师”的第二章:实用方法的基础上。在那一章中提出的观点之一就是所谓的干原理。不要重复自己。
不重复自己当然是软件开发的一个重要方面。在多段代码之间进行复制粘贴可能是最好的方法,而且速度很快。然而,当在那些多个副本中的一个中发现一个 bug 时,你会做额外的努力到处纠正它(包括其他人的工作)吗?你能找到所有这些拷贝吗?有时,复制粘贴的代码可能会有一些变化。更改变量名,到处添加条件,…
几年前,我领导了一个项目,开发了一个检测软件克隆的软件。即使我们能够识别出与原始版本不同的软件克隆,让软件开发人员基于这种洞察力重构代码也是非常困难的,甚至是不可能的。当一个克隆体被创造出来,就很难杀死它!所以最好的方法是不要创建它们,从头开始重构,根据需要创建函数或类,而不是复制粘贴。
希望我说服你在数据科学的软件开发中保持干爽。但这也适用于数据科学的其他方面。您是否曾经在这样一个地方工作过,那里的数据定义依赖于许多列,可能来自不同的表,这些表没有标准化,并且对于许多仪表板或查询是重复的。什么是你网站的访问者?网站的任何页面有点击率吗?你有没有安排一些会议,并且每次会议只数一次?你是否有一个登录名并且只计算用户数?假设会话跟踪或用户登录,你如何计算访问者的数量?是一段时间内的滚动平均值吗?那段时间是什么?它很容易成为确定谁是特定时间的活动用户的重要查询。你确定组织里的每个人都用最新最伟大的定义吗?查询是否从仪表板复制粘贴到仪表板?这个定义是根据一个人或一个团队的目的稍微修改的吗?你看,不要重复你自己也适用于数据定义。有多种方法可以解决这个问题,但没有一种方法是简单的,你允许代码、查询或定义复制粘贴的时间越长,就越难杀死那些克隆体。
在第二周的练习中,我建议找出一个你的团队中制造了大量克隆的区域或特定实例。找个人(最好是你团队里的)讨论一下。有没有什么方法可以提出一段代码、查询或定义,并开始重构相关的工件来消除这种克隆?这可能很难!什么是可接受的渐进方式?我们如何确保未来不会产生新的克隆体?这可能是您的团队将要采取的最初几个步骤,以限制和减少您的工件中的克隆。
至于上周,第二章还有更多内容。尽管如此,对于希望提高 Python 编程技能的初级数据科学家来说,我建议熟能生巧。在这种情况下,这个主题内的练习可能会被证明是有用的。
一旦你完成这个练习,问问你自己我上周练习中提出的所有问题。更具体地说,你应该确保自己不会重复。密码问题是对称操作的一个很好的例子,对称操作有很好的代码重用潜力。如果您没有定义在编码和解码之间多次使用的函数,我建议您重新考虑一下您的实现。另外,一定要思考上周的其他问题:你会早休息吗?你尊重合同吗?你记录你的程序吗?你有单元测试吗?
同样,如果你能接触到一个你觉得相处融洽并且你认为他写了很棒的代码的人,问问他对你的练习解决方案的意见。你可能会学到一两件事!或者,如果你解决了那个问题,你可以看看其他人的最佳解决方案。阅读他人的代码也是提高编程技能的好方法。
我知道我说的是每周一个话题,但是这一章还有一个方面值得一提。我不会增加更多的锻炼,只是一个潜在的终身追求!主题是评估。这本书会告诉你记录你的估计。我说:不要简单地记录这些,记录你做的每一件事以及花了多长时间。在你职业生涯的早期,记录下你做了什么,花了多长时间。随着时间的推移,尝试概括您收集的数据,例如,所有数据概念都定义良好的数据请求平均花费我 x 小时;使用现成的图表类型创建一个带有 y 图表/数据点的仪表板平均花费我 x 小时;…为自己建立一个评估库。
当你开始对你的个人估计有一个概括的心智模型时,用它做一个游戏。即使没有被要求做一个评估,也要做一个,然后检查它有多好。让游戏化成为你的优势,让你更好地预测未来!
如果或者当你毕业去领导团队时,你会发现你的评估也是一个很好的基础。然后,当您了解团队成员时,您可以对他们应用对等因素。甚至可能从那次练习中找出他们的长处和短处。
这是我对“实用程序员:从熟练工到大师”第二周/第二章的快速补充,作为提高数据科学中软件编写技能的媒介。下周见第 3 章:基本工具。

在软件领域 20 多年了。目前在 Shopify 担任数据科学家。在深度学习、机器学习/分析、云计算、物联网、领域特定语言、遗传算法和编程、人工生命/智能以及所有技术领域的研究兴趣!通过点击查看所有帖子
原载于 2021 年 3 月 30 日 http://thelonenutblog.wordpress.com的 。**
数据科学中更好的软件写作技巧:在项目之前
原文:https://towardsdatascience.com/better-software-writing-skills-in-data-science-before-the-project-7a5a2e5e6ff5?source=collection_archive---------37-----------------------
实用程序设计员的每周指导章节阅读

封面图片由 图文 转自 图文 。
本周的指导和帖子是基于“务实的程序员:从熟练工到大师”的第七章:项目之前。通读这一章,你会发现我们离编码只有一步之遥。然而,良好的项目准备卫生将确保您在数据科学项目中取得成功,并限制编码时的意外。
通读这一章,一些数据科学家会发现挖掘需求不仅是数据科学家的任务,也是软件开发人员的任务,这让他们感到欣慰。在数据科学中,就像在软件工程中一样,需求不会简单地躺在地板上,随时可以被拿走和珍藏,你必须首先把它们挖掘出来。数据科学中的需求会有不同的形式,这取决于您正在从事的项目的类型。在几个组中进行分类就足够了,还是需要更精细的回归?如果能提高精确度或召回率,允许更多的假阳性会更好吗,或者假阳性会被禁止以后处理?如果您正在构建一个仪表板,那么监控项目的合适指标是什么?构建实验时,您应该定义哪些组?
从数据科学的角度来看,需求与从软件开发的角度来看是不同的,但是如果你的项目将数据作为一个产品来构建,那么它们可能会比你预期的要多得多。有一点是不变的,那就是和用户一起工作,像用户一样思考。没有什么比与目标用户一起工作更好地了解他需要你做什么了。
记录这些需求。但是不要过度记录它们!永远记住,有些事情做得比描述的要好!一旦写下来(或画下来),你就有了一个讨论和找出可能被不同利益相关者误解的细节的基础。如果使用正式方法或部分正式方法可以帮助你,好吧,去做吧。然而,不要错误地认为方法本身就是目的。用例的概念既适用于软件开发,也适用于数据科学。弄清楚谁是参与者,他们期望从系统中得到什么,以及你将向他们提供什么,是建立强大结果的关键。需求收集、设计和实现都是交付高质量解决方案的不同方面。不要忽略任何一个阶段。
解决不可能的难题也是数据科学的一个标志。在这里,我很喜欢作者提出的“找到盒子”这种表达方式。这并不总是一个跳出框框或跳出框框思考的问题。相反,你应该弄清楚什么是盒子,什么是真正的绝对约束,同时摆脱想象的先入为主的观念。这不仅适用于现实生活中的数据科学问题,也适用于小思维问题。有时你只需要退后一步,问自己书中提出的几个问题:
- 有更简单的方法吗?
- 你在尝试解决正确的问题吗?
- 为什么这是一个问题?
- 是什么让它难以解决?
- 需要这样做吗?
- 到底需不需要解决?
通过问自己这些问题,诚实地面对自己,你可能会对答案感到惊讶!
这是我对《实用程序员:从熟练工到大师》第七章阅读的补充,作为提高数据科学中软件写作技能的媒介。下周,这本书的最后一章,也是我这个系列的最后一篇文章。然后我们将看一看第 8 章:务实的项目。

在软件领域 20 多年了。目前在 Shopify 担任数据科学家。在深度学习、机器学习/分析、云计算、物联网、领域特定语言、遗传算法和编程、人工生命/智能以及所有技术领域的研究兴趣!通过点击查看所有帖子
原载于 2021 年 5 月 11 日https://thelonenutblog.wordpress.com/2021/05/11/better-software-writing-skills-in-data-science-before-the-project/。
数据科学中更好的软件写作技巧:弯曲还是断裂
原文:https://towardsdatascience.com/better-software-writing-skills-in-data-science-bend-or-break-3e46f3fe80ca?source=collection_archive---------37-----------------------
实用程序设计员的每周指导章节阅读

封面图片来自 Pixabay 上的未知作者。
本周的指导和帖子是基于“务实的程序员:从熟练工到大师”的第五章:屈服或突破。本章的重点是确保你的程序、ETL 或模型在未来新的现实出现时可以改变。除了会被废弃的一次性原型(但通常会被转化为产品代码)之外,代码也必须进化。无论是 ETL 还是模型,你的代码都必须进化,如果你想提高效率,你最好从一开始就得到一些提示。
让我们首先同意代码将需要改变,很少有用的代码编写一次就永远不会改变,许多代码编写不是空白页面类型,而是编辑现有的代码(即使是遗留代码)。一些原则有助于确保将来更容易更新代码:
- 低耦合(系统的每个部分都只依赖于几个组件吗?或者代码的耦合是依赖关系的蜘蛛网吗?),
- 可逆性(如果我想改变数据库访问,我是否需要到处改变代码,或者数据库访问是抽象的,以便所需的改变可以本地化到一个文件或组件?),
- 元编程(有没有办法通过正确编写的可重用代码、数据驱动代码或参数化配置来最小化代码?),
- 时间耦合(代码对以一定顺序出现的事件有很强的依赖性吗?,有反馈回路吗?),
- 使用视图将表示从数据模型和黑板技术中分离出来,在模块之间进行匿名和异步的信息交换。
我不会深入这些原则的所有细节,因为我认为这本书在解释它们方面做得非常好,但也许我们可以举几个与数据科学相关的例子来补充这本书所提供的内容。
低耦合
通常在数据科学中,我们通过创建 ETL 从现有的资产中创建派生的数据资产。然后我们从这些中推导出更多的。我们混合和匹配数据,甚至可能无意中通过这些数据资产创建反馈循环。您应该尽早考虑映射这些数据资产依赖关系的方法,并了解可以在您的组织中应用哪些规则来确保数据资产的低耦合性。在数据科学中,数据是最有价值的资产。不要把它转换成意大利面数据!是的,它会像意大利面条代码一样糟糕。
可逆性
如果它还没有发生在你身上,你应该感到幸运。但是在某个时候,您的组织选择了数据库提供商 A 或云基础设施提供商 B,将决定转向提供商 c。为什么?成本,可靠性,特性,……理由层出不穷。如果它不是数据库端或云基础架构端,它很可能是深度学习框架或您的组织从第三方购买的其他一些基础架构。如果在建立软件架构之前没有考虑到这种转变,它可能会成为一个糟糕的转变。
元编程
我记得在我的第一份工作中,我们假设地球是平的,进行地理定位。这不成问题,因为覆盖的区域足够小,看不到地球弯曲的假象。一天,一位客户要求我们覆盖一大片区域。没有别的办法,我们必须考虑纬度、经度和地球的曲率。首先,对嵌入在每个组件中的东西进行解耦是非常困难的。有什么比在平坦的地球上计算距离或方位更容易呢…所以每个组件都在做。第一步是抽象这些功能,并创建一个组件来完成这些计算(一个需要填充的高耦合地狱)。
接下来,我们决定,由于一些客户可能想要一个平坦的地球,其他人想要一个球形模型,或者一个椭圆形模型,甚至更复杂的地球模型,我们要使地球模型参数化。不仅距离和方位被解耦,用于地球的模型也被参数化。然而,在开发的后期进行解耦是一项艰巨的任务。
同样的事情也会发生在数据上。也许今天您可以用相对较小的计算单元来处理您的 ETL,但是明天呢?最好早点考虑参数化,这样如果你需要更多的能量,你可以调整参数。输入和输出数据集的名称和路径也是一个容易互换的参数吗?ETL 的过滤条件可能取决于具体情况,但是所有的处理都是一样的。与其拥有几乎相同的 ETL 的多个副本,也许一个可以接收过滤条件作为参数的副本会让您的生活更轻松。可能有很多事情你可以在早期参数化,这将使你的未来生活更容易。花点时间想想吧。
时间耦合
你的 ETL 中有可以并行执行的部分吗?思考并行处理在哪里是可能的,并相应地创建你的系统。也许今天串行运行它是好的,但是也许明天如果您想要满足您的服务级别目标(SLO ),您可能需要以使用更多资源为代价来进行并行处理。将来你会感谢你早点想到它!我有第一手的经验,我设计的 ETL 链开始花费太长时间。只需更改几个参数,我就可以运行可并行化的部分,并提高转换的速度。
视图
模型视图控制器设计模式似乎不太适用于数据科学。但其背后的原理可能是一个很好的灵感来源。使用上面介绍的其他技术,保持您的源代码可配置但具有相似的特征可能是个好主意。这样,也许您可以开发可参数化的模型(可能包括训练参数或训练参数文件),并轻松地交换它们,甚至并行使用它们。ETL 或模型的服务也可以是参数化的和可交换的。这可以扩展到模型的评估,或者 ETL 的健康监控。模型视图控制器良好的解耦原则在数据科学环境中仍然非常受欢迎。只是想法有点不同!
这是我对第五章“实用程序员:从熟练工到大师”阅读的补充,作为提高数据科学中软件写作技能的媒介。下周我们将看一看第 6 章:当你编码的时候。

在软件领域 20 多年了。目前在 Shopify 担任数据科学家。在深度学习、机器学习/分析、云计算、物联网、领域特定语言、遗传算法和编程、人工生命/智能以及所有技术领域的研究兴趣!查看网友的所有帖子
原载于 2021 年 4 月 20 日 http://thelonenutblog.wordpress.comhttps://thelonenutblog.wordpress.com/2021/04/20/better-software-writing-skills-in-data-science-bend-or-break/。
数据科学中更好的软件编写技巧:破窗
原文:https://towardsdatascience.com/better-software-writing-skills-in-data-science-broken-window-c3b470bfd15c?source=collection_archive---------41-----------------------
通过实用程序员的每周章节阅读和 Python 练习来提高你的数据科学编程技能。

封面照片来自 Pexels 上的cotton bro。
我最近开始指导一名初级数据科学家提高他的编程技能。人们常说数据科学家缺乏编程技能,这可能是因为他们的数据科学项目,也可能是因为他们不同的背景导致他们从事数据科学。然而,有时数据科学家愿意承认自己的弱点,并加以改进。我目前是一名数据科学家,但鉴于我在过去的生活中作为软件开发人员有多年的专业经验(在许多事情上),我觉得这个导师是一个很好的匹配,并认为我们可以看到我们如何通过这个导师学习。
在我的软件开发经历中,我读过的一本很有影响力的书是安德鲁·亨特和戴维·托马斯写的《实用程序员:从熟练工到大师》。我认为这可能是一个很好的讨论和练习的起点。这本书本身没有那么多章节,所以我最初的打算是每周与我的学员讨论一章,并用一些练习来补充阅读。更具体地说,我的学员希望提高他的 Python 编程技能,因此我们将针对该语言进行练习。
你可能会问我:为什么程序员的书对数据科学家有好处,尤其是一本没有深入讨论语言的书?嗯,我认为有很多事情对程序员来说很重要,对数据科学家来说同样重要,甚至更重要。例如,在第一章中,有一节是关于交流的。如果你还没有被告知,沟通是数据科学的关键!
我希望这是一系列的帖子,将突出本周章节最重要的部分,以及一些关于我向我的学员提议的每周 Python 练习的讨论。所以事不宜迟,第一周我提议阅读序言和第一章:实用主义哲学。
在数据科学中,就像在一般的编程中一样,你必须调整你的方法来适应当前的环境。这些调整将来自你的背景和经历。与务实的程序员一样,务实的数据科学家完成工作,并且做得很好。
我将集中讨论一个方面,而不是一章的细节。从这个意义上来说,这篇博文是对《实用程序员:从熟练工到大师》中相应章节的补充。这周我想集中讨论“破窗”。建筑从破窗理论当你在一栋建筑上留下一扇破窗,它会灌输一种对那栋建筑的遗弃感。从那种被抛弃的感觉,人们会开始觉得没人关心这栋建筑。更多的窗户将被打破,涂鸦将被画出,其他损害将被带到该建筑。一个类似的例子是软件,当你有一个“破碎的窗口”时,人们会试图远离那段代码,不会有试图改进它的反射。
作为第一周的练习,我建议在你的团队拥有的代码中找出一个破损的窗口,并找个人(最好是在你的团队中)来讨论它。情况有多糟?我们如何改进它?更好的办法是,怎样才能修好那扇破窗户?也许采取最初的几个步骤可能是你的团队对破窗和技术债务的新态度的开始。
第一章还有更多的内容。尽管如此,对于希望提高 Python 编程技能的初级数据科学家来说,我建议熟能生巧。在这种情况下,这个主题内的练习可能证明是有用的:破窗。
完成这个练习后,问自己这些问题:
- 如果合同没有得到遵守,比如最初的断言,你能确保你的程序提前中断吗?在这个练习中,我们需要一个 int 类型的列表,如果你收到了其他的东西,你应该在这里中断。您可能还需要检查其他先决条件。
- 相反,如果合同允许输入,你确定你能处理边缘/边界值吗?你知道你的程序应该如何反应吗?
- 你是否编写了处理特定任务的函数?如果你发现程序的某些部分在重复,你有没有采取措施重新调整这些部分,这样你就不会重复了?
- 你以任何方式记录你的程序吗?在这里,团队文化可能会有所不同,但仍然是一个很好的做法,为将跟随的人留下面包屑(即使是未来的你!).你的变量名有意义吗?它们是文档的一部分吗?
- 你做了创建单元测试的额外工作了吗?许多框架都可以用于这个目的。理想情况下,你要让自己了解你的团队最常用的一种。
也许你会认为这些问题对于这样一个小程序来说有些小题大做,但是再次强调,熟能生巧。如果你不在小问题上练习这些,很可能你不会想到在大问题上做这些。
如果你能接触到一个你觉得相处融洽的人,并且你认为他写了很棒的代码,问问他对你的练习解决方案的意见。你可能会学到一两件事!
这是我对“实用程序员:从熟练工到大师”第一周/第一章的快速补充,作为提高数据科学中软件编写技能的媒介。下周见第二章:务实的方法。

在软件领域 20 多年了。目前在 Shopify 担任数据科学家。在深度学习、机器学习/分析、云计算、物联网、领域特定语言、遗传算法和编程、人工生命/智能以及所有技术领域的研究兴趣!通过点击查看所有帖子
封面照片来自 Pexels 上的cotton bro。
原载于 2021 年 3 月 23 日 http://thelonenutblog.wordpress.comhttps://thelonenutblog.wordpress.com/2021/03/23/better-software-writing-skills-in-data-science-broken-window/。
数据科学中更好的软件编写技巧:死程序不会说谎
原文:https://towardsdatascience.com/better-software-writing-skills-in-data-science-dead-programs-tell-no-lies-1f06d581de6f?source=collection_archive---------48-----------------------
实用程序设计员的每周指导章节阅读

封面图片由威廉·亚当斯在 Pixabay 拍摄。
本周的指导和帖子是基于“务实的程序员:从熟练工到大师”的第四章:务实的偏执狂。这一章的重点是确保你的程序做它们应该做的事情,如果它们没有按预期执行,你可以用最快的方式找出原因。
根据您使用的编程语言,可以用不同的方式支持契约式设计。至少,Python 3 可以通过对函数及其返回值使用参数类型来强制实现这一点。强制执行合同的另一个好方法是在你的函数的早期做断言(断言)或者简单地在事情不符合你的合同时抛出异常。请注意,断言无论如何都会引发异常。想一想,是失败并停止执行好,还是用垃圾填充一个表好?你什么时候能发现那是垃圾?你能在那个时间点纠正它吗?你还会有底层数据来做修正吗?
学会知道什么时候使用断言和/或什么时候引发异常,也就是说,当你知道一个边界、一个合同并且你想要执行它,或者至少告诉一个更高级的程序有问题并且你对此无能为力。当遇到特殊情况时,你可以自己解决,或者让更高级的程序来处理。最后,如果没有更高级别的程序可以处理这种情况,整个程序将被暂停。
我知道对于某些人来说断言和异常的用法可能很难理解,所以让我试着为你建立一个心理模型。异常是发生在程序上的异常事件。如果你负责那个程序的调用并捕捉那个异常,你必须决定你是否有足够的上下文来处理那个异常,需要把那个异常提交给调用你的程序。最后,如果没有人能处理这个异常,程序就会崩溃,你可以调试这个异常是怎么回事。如果你知道在这种特殊情况下该怎么做,那么就由你来处理。也许是重试,也许你需要使用默认值,…只是要确定处理决定,因为这可能会污染你的数据。
至于如何抛出更高的异常,有两种方法:断言或者抛出。一般来说, raise 会在你遇到无法直接处理的错误情况时使用,但更高级的程序可能会处理,例如文件不存在或为空……另一方面, assert 会在你发誓这种情况不会发生时使用。在这两种情况下,异常都被抛出。
当你发现你的程序发生了“不好的”事情,你知道这不应该发生,你也知道没有别的办法,抛出异常的方法是通过断言。这将会给上层程序抛出一个异常,它必须决定如何处理这个异常。一个例子是,你期望一个 int 作为输入,你得到一个字符串,这是契约破坏,更高的程序要求你处理不正确的数据,为什么你的程序会决定为什么契约被破坏?正确处理该异常应该是调用者的责任。这可能需要一个断言。
根据您所在的组织,如何使用异常和断言可能会变得很有哲理。另一方面,它也可能受制于非常具体的规则。一个组织可能更喜欢一种方法而不是另一种方法,这可能有真正合理的原因。学习规则,如果没有规则,围绕它进行讨论,并运用你的最佳判断。无论如何,死亡程序不会说谎。与其在未来一年不得不处理被污染的数据,不如杀了它。
跑步之前,应该先学会走路。通常,人们在没有太多编程知识的情况下进入数据科学,突然被要求处理 Python 中现有的 ETL,或者设计新的 ETL。务实的做法是学习编程!如前所述,Python 是一种多范式语言。过程化编程可能是最广为人知的方法,尤其是在笔记本环境中使用 Python 的时候。线性规划和函数的使用…
如果您使用 pytest 或其他一些库,您可能会开始对面向对象编程产生一些疑惑。也许你只是复制了食谱,并没有深入研究这个范例。你的机会来了。我在 Python 中找到了这篇关于面向对象的写得很好的初级读本,它也链接到了其他资源。如果您要编写可靠的 ETL,您将需要了解一些 OOP 知识。
如果你操作数据,迟早你会想使用 lambda 函数,映射,过滤,减少,…或者如果你使用 numpy / pandas,你会对 apply 等感兴趣。同样,你可以按照菜谱做,但是同样,如果你想在函数式编程方面变得更强,我又找到了一本有趣的关于 Python 中函数式编程的入门书。它远未完成,但它链接到其他资源来填补空白,一旦开始,你就会想了解更多!
我说过很多次:熟能生巧!在最初的两周,我向你们推荐了来自 CheckiO 的练习。随意在那里注册一个账号,沿着一个岛到一个岛的路径,获取 Python 方面的知识。还有其他资源可以用来练习编程。自 2015 年以来,每年圣诞节前的几天,在 12 月份,降临节代码提出小问题,精灵和圣诞老人面临着传递礼物!你也可以看看你所在的地区是否有编码 dojos,或者实际上,我发现它们也是一个很好的实践场所。
这是我对第四章“实用程序员:从熟练工到大师”阅读的补充,作为提高数据科学中软件写作技能的媒介。下周我们将学习第五章:弯曲或断裂。

在软件领域 20 多年了。目前在 Shopify 担任数据科学家。在深度学习、机器学习/分析、云计算、物联网、领域特定语言、遗传算法和编程、人工生命/智能以及所有技术领域的研究兴趣!通过点击查看所有帖子
原载于 2021 年 4 月 13 日 http://thelonenutblog.wordpress.com**的 。
数据科学中更好的软件写作技巧:实用项目
原文:https://towardsdatascience.com/better-software-writing-skills-in-data-science-pragmatic-projects-44b3aae9ed84?source=collection_archive---------35-----------------------
实用程序设计员的每周指导章节阅读

图像由 戈登约翰逊atpix abay。
语用学的定义(韦氏词典)
与事实或实际事务有关的,通常排除智力或艺术方面的:与理想主义相对的实际的。
但是,你真的能排除内心所有的事情吗?你能从技术决策中去除所有政治因素吗?可能这么想就是理想化了吧!务实意味着促进基于事实的信息和实际方面超过其他考虑,但其他考虑也可能是要处理的事实。真正的务实可能不是切断头脑和心灵之间的联系,而是找到一个正确的平衡,在这个平衡中,一个人既尊重事实,又考虑到其他追求,这样最终我们会得到一个切实可行的解决方案。
本周的指导和帖子基于“实用程序员:从熟练工到大师”的第八章,也是最后一章:实用项目。这一章把我们到目前为止学到的所有东西都总结成一个很好的视图,并提供了一个很好的学习总结。
如果你想过实用主义的数据科学家(或程序员)生活,你必须在团队工作的各个方面贯彻实用主义。您应该自动化每一个重复的方面,并确保您的工件的测试也是自动化的。没有需要随着时间重复的手动步骤。
务实的团队不应该允许打破窗户(见本系列的第一篇文章)。第二,你应该始终监控你的“环境”,不要让它随着时间的推移而退化。即使是缓慢的退化,如果任其发展,也会在未来造成大问题。这可能会以多种方式蔓延:如果不加注意,数据的线性增长可能会是一个挑战。你可能需要调整你的资源久而久之,为什么不自动化呢?如果你决定走这条路,如果你不想以一个巨大的账单结束的话,确保你对一段时间内允许的增长因素有所限制!那么数据的指数级增长呢?如果这种增长跟随着你的“客户”基础,调整资源可能不是一个财务问题,但如果不是呢?你应该尽快解决这个问题。也许有其他方法来聚集数据,并使其仍然相关。
正如我们在前面章节看到的,沟通是王道。团队内部的沟通以及与涉众和组织其他部分的沟通。我经常发现,这本书在这个问题上提供的最佳建议是创建一个品牌。当你开始一个项目时,给它一个名字,并且总是引用它。如果它能自己创造一个你想要达到的更好的精神形象。
然后就是一堆提醒。不要重复自己!重构以消除这些重复。创造正交性,不是围绕工作职能,而是围绕功能。
价值测试和可重复测试。价值以及良好的数据科学家水平的文件。不是为了某个过程而制作的文档,也不是为其他不愿意阅读它的人而制作的文档(如果他们要阅读它,就去做,但要确保它满足他们的需求,而不是其他无用的额外内容)。几个月后,当/如果你需要回到你设计的那段代码或算法,你还能记得你做的所有小决定吗?我打赌不会。如果你离开组织,团队还能维护和增强功能吗?让文档尽可能接近代码。如果你有跨越许多代码的概念,例如系统级信息,首先让它对你自己和你的数据科学家同事有意义。使其可访问,并且不要重复在更接近代码或算法的层次上找到的信息。我特别喜欢提示 67:“把英语当作另一种编程语言”。这意味着所有适用于你的代码的都应该适用于你的文档…
最重要的是,记住足够好就是足够好。这个世界上没有完美,即使你能做到,目标第二天也会离你而去。
“实用程序员:从熟练工到大师”系列阅读到此结束。希望这能帮助你成为更好的数据科学程序员!继续编程,继续练习!

在软件领域 20 多年了。目前在 Shopify 担任数据科学家。在深度学习、机器学习/分析、云计算、物联网、领域特定语言、遗传算法和编程、人工生命/智能以及所有技术领域的研究兴趣!通过点击查看所有帖子
原载于 2021 年 6 月 3 日【http://thelonenutblog.wordpress.com】。
数据科学中更好的软件编写技巧:工具和错误
原文:https://towardsdatascience.com/better-software-writing-skills-in-data-science-tools-bugs-8cbf94c2c456?source=collection_archive---------43-----------------------
实用程序设计员的每周指导章节阅读

由尼姆罗德·柳文欢在皮克斯贝拍摄的封面图片。
本周的指导和帖子基于“务实的程序员:从熟练工到大师”的第三章:务实的方法。那一章的重点之一是关于交易的工具,以及掌握这些工具。
如果你现在习惯的唯一工具是 Jupyter 或者另一个类似笔记本的环境,也许是时候尝试不同的方法了。只使用类似笔记本的环境可能会给你带来不好的编程习惯,这可能很难改变。尝试使用支持 IDE 的 Python 来编写一些 Python 代码,比如 PyCharm 就是其中之一,或者甚至是您将在命令行上执行的纯文本。学习不同的编码方法,这将帮助你理解这些方法的成本和收益。
作为一名数据科学家,尝试不同的方法来查询数据,也许你的组织已经支持不同的数据库?学习如何使用 pyspark、SQL……如果这适用于你的工作,尝试不同的深度学习框架。工具是无穷无尽的,你不需要对它们都有很深的了解,但你应该尝试一下,看看它们的优缺点,有意识地选择哪一个最适合你和手头的任务。
工具很重要的另一个领域是调试他们的代码(或查询),我在这个领域看到了许多初级程序员和数据科学家要解决的问题。
本周我的文章的重点是调试。Python 练习将包括调试一个小的 Python 函数。如果你发现 bug 比较早,你在 Python 里面大概也没那么初级吧!尽管如此,我还是鼓励你把这些步骤当作练习来完成。记住,熟能生巧!
将这段代码放在您最喜欢的 Python 执行环境中,让我们按照书中概述的调试过程进行调试。
- 干净地编译代码:对于 Python 来说,这应该不成问题… Python 是一种解释型语言。但是,例如,如果您将代码保存在 Jupyter 笔记本中,您可能会忘记之前运行了什么。因此,一个好的方法是重启内核,一个单元一个单元地重新执行代码。你的 Jupyter 笔记本电池坏了吗?也许你可以花时间把它们按照你想要的顺序排列。
- 理解错误报告:通读函数意图和三个“测试”语句。你能理解什么是预期的行为吗?也许你能马上发现这个错误!
- 重现 bug:bug 可重现吗?在这个具体的例子中,它应该已经很容易被复制了,但是在现实生活中,你可能需要做一些工作来使它在一个步骤中被复制。为了更好地理解您看到的行为,您还想添加其他测试吗?你能运行这些测试并一步再现问题吗?
- 可视化你的数据:这里有许多方法是可行的。您可以决定使用 pdb,Python 调试器(如果您还不了解调试器,了解它可能是个好主意)。例如,如果您正在处理 ETL,您可能必须查询由 Python 文件生成的数据。如果您的 ETL 正在为一些机器学习阶段准备数据,您可能希望创建一种自定义的方式来可视化那些“错误的”数据。
- 跟踪:除了使用调试器之外,或者在这种情况下,您可以在代码中添加一些跟踪。可以通过日志文件进行跟踪(在这种情况下,我强烈建议使用支持跟踪级别的日志框架,例如 INFO、ERROR、DEBUG……以便您可以保留设计良好的跟踪,供将来调试使用),或者对于像这样的简单问题,您可以简单地决定添加一些打印语句来跟踪数据流。
- 查看损坏的变量:这不是你通常用 Python 必须做的事情,但是如果你使用其他编程语言,要注意这是可能发生的事情。例如,在 C 语言中,你可以在内存中的任何地方写任何东西,所以一个来自程序另一部分的简单的索引错误可能会破坏“你的”变量。
你还没发现窃丨听丨器吗?不要绝望,还有几步路可以走!
- 橡皮鸭:向其他人解释问题,或者如果你像我们许多人一样因为 COVID 而被禁闭,向你的猫解释,或者如果你独自被困在一个荒岛上,向威尔逊解释!大声说出来也许能帮你想明白。
- 排除过程:正如作者在书中所说,错误可能出现在操作系统、编译器或第三方产品中。然而,在我 25 年以上的软件职业生涯中,只有一次我遇到的错误可以追溯到编译器,那是很久以前的事了,在 Fortran 编译器中。而且只有一次错误可以追溯到计算机主板的错误硬件设计。这些错误通常很难发现,所以它们不经常发生是件好事。通常情况下,如果你的 bug 涉及到软件的其他部分,可能是你没有以正确的方式解释第三方文档。
- 惊奇元素:当你发现自己认为这个 bug 是不可能的,是时候重新评估你所坚持的真理了。微妙的暗示,这里可能就是这样。
这里发生了什么?在这种情况下,当你知道 Python 是如何工作的时候就很简单了。Python 中的默认参数不会在每次调用函数时重新计算,而是在解析函数定义时才重新计算一次。每次在没有第二个参数的情况下调用该函数时,对同一个“空”列表的引用将被用作默认参数。对“空”列表所做的任何更改都将成为后续调用的“新”默认参数,这些调用不会提供第二个参数。
了解交易工具包括了解你使用的编程语言。Python 有很多好的特性,因为它是一种多范例编程语言。在 Python 中,您可以使用过程式编程方法、面向对象方法或函数式编程方法。这些给了 Python 很大的灵活性,也给了你很大的伤害自己的可能性!花时间学习你使用的编程语言,它使什么变得容易,以及它在什么地方使事情变得困难。
这是我对《实用程序员:从熟练工到大师》第三章阅读的补充,作为提高数据科学中软件写作技能的媒介。下周我们将看一看第四章:务实的偏执狂。

在软件领域 20 多年了。目前在 Shopify 担任数据科学家。在深度学习、机器学习/分析、云计算、物联网、领域特定语言、遗传算法和编程、人工生命/智能以及所有技术领域的研究兴趣!通过点击查看所有帖子
原载于 2021 年 4 月 7 日【http://thelonenutblog.wordpress.com】。
数据科学中更好的软件写作技巧:当你编码时
原文:https://towardsdatascience.com/better-software-writing-skills-in-data-science-while-you-are-coding-c3b059914bd5?source=collection_archive---------29-----------------------
实用程序设计员的每周指导章节阅读

来自 Pixabay 的 Gerd Altmann 拍摄的封面图片。
本周的指导和帖子基于“实用程序员:从熟练工到大师”的第六章:当你编码时。本章的重点是你在编程时应该记住的一些小事。编码是一个迭代的过程,需要注意。如果你没有给予它应有的关注,你可能会碰巧陷入编码。让我们来看看书中提到的一些主题。
巧合编码与故意编程
如果没坏就不要修理它。对于可信的代码片段来说,这可能是真的,但是当你正在编写新的代码,或者在现有的代码中添加新的代码行时,你不能确定它没有被破坏,直到它经受了考验。到那时可能就太晚了。有人可能会受到这个 bug 的影响,修复这个 bug 需要的时间比早期发现的时间要长。所以,要仔细考虑你在编码什么,为什么要编码。当你对你需要编码的东西有了更好的理解时,不要害怕重构。把事情简单化,确保不重复自己。这并不是因为一段代码之前就在那里,所以它仍然需要在那里。不断地重新评估你正在编写的代码。
算法速度
特别是在数据科学中,您会遇到这样的情况,计算算法速度将有助于您理解为什么分析在某些情况下可以工作,但随着数据大小的增加,会花费太多时间。如果你非常依赖 Jupyter 笔记本电脑,要知道现在大多数计算资源都有多个内核。如果你想从多核处理中获益,你必须调整你的代码来利用它。例如在 scikit learn 中,许多类都有方法,在这些方法中你可以指定类似 n_jobs 的东西来告诉这些方法它可以使用多少个处理器。
如果依赖 python 循环,随着数据的增长,处理过程会变得很长。也许这些循环算法中的一些可以用 numpy 转换成矩阵运算?如果不是,习惯 Python 中的多处理将是有益的。通过这种方式,您可以将处理任务划分到多个进程上,这些进程将受益于您的可用内核。然而,你需要考虑减少结果,也许只是简单地将所有的输出连接在一起,或者可能更复杂…至少知道可能性可以使程序运行几个小时而不是几天。
为了让多重处理变得容易,我前段时间做了一个小的助手类。如果需要,请随意使用。
用法相当简单,首先,这里有一个简单的用法示例。reducing 函数嵌入在方法调用(reduce.append)中。
simpleMultiprocessing::Creating a process for elements 0-124 simpleMultiprocessing::Creating a process for elements 125-249 simpleMultiprocessing::Creating a process for elements 250-374 simpleMultiprocessing::Creating a process for elements 375-499 simpleMultiprocessing::Creating a process for elements 500-624 simpleMultiprocessing::Creating a process for elements 625-749 simpleMultiprocessing::Creating a process for elements 750-874 simpleMultiprocessing::Creating a process for elements 875-999 simpleMultiprocessing::All jobs submitted simpleMultiprocessing::All jobs ended [7750, 23375, 39000, 54625, 70250, 85875, 101500, 117125] 499500
你可以很容易地添加一个合适的缩减函数,如下例所示。
simpleMultiprocessing::Creating a process for elements 0-124 simpleMultiprocessing::Creating a process for elements 125-249 simpleMultiprocessing::Creating a process for elements 250-374 simpleMultiprocessing::Creating a process for elements 375-499 simpleMultiprocessing::Creating a process for elements 500-624 simpleMultiprocessing::Creating a process for elements 625-749 simpleMultiprocessing::Creating a process for elements 750-874 simpleMultiprocessing::Creating a process for elements 875-999 simpleMultiprocessing::All jobs submitted simpleMultiprocessing::All jobs ended [7750, 23375, 39000, 54625, 70250, 101500, 117125] 413625
如果您需要调试其中一个多处理函数,将 simpleMultiprocessing 类的用法改为使用 protectedMultiprocessing 可能会有所帮助。在下一个例子中,我们通过主动为其中一个元素引入一个异常来展示它是多么的有用。如果在 simpleMultiprocessing 的情况下出现异常,我们会悄悄地丢失该作业和所有结果。这里我们意识到了问题,但仍然得到了其他结果。缺点是 reducing 函数被调用得更频繁,但在正常情况下,艰苦的工作无论如何都是由 mapping 函数完成的。
protectedMultiprocessing::Creating a process for elements 0-124 protectedMultiprocessing::Creating a process for elements 125-249 protectedMultiprocessing::Creating a process for elements 250-374 protectedMultiprocessing::Creating a process for elements 375-499 protectedMultiprocessing::Creating a process for elements 500-624 protectedMultiprocessing::Creating a process for elements 625-749 protectedMultiprocessing::Creating a process for elements 750-874 protectedMultiprocessing::Creating a process for elements 875-999 protectedMultiprocessing::All jobs submitted An error occured... while processing item: 666 exception: integer division or modulo by zero protectedMultiprocessing::All jobs ended [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, [...], 663, 664, 665, 667, 668, 669, 670, [...], 995, 996, 997, 998, 999] 498834
你可以用多重处理做更多有趣的事情,这是值得学习的。同样,对于简单的多处理用例,请随意使用我上面的类。
还有更
第六章还有更多内容:重构、单元测试和邪恶巫师。由于这本书写得很好,我就不赘述了。但是我只想说:在你编码的时候不要害怕重构。很多时候,当我给我的工作增加复杂性时,我发现有很多方法可以保持干燥(不要重复)。通过重构,我能够简化流程,甚至使代码更容易理解。参数化可以让你走得更远。
最后,我恳求你,做单元测试!并将它们与您的代码一起保存。python 中有很好的单元测试框架: unittest 随 Python 一起发布,我经常使用 pytest ,你可以使用 mock ,或者假设。即使没有框架,你也可以使用准系统 asserts 做好单元测试工作,所以没有借口。这本书就单元测试的主要目标给出了很好的指导。当您稍后将更新代码时,这种可能性很高,您会很高兴有现有的单元测试来验证基础。
这是我对第六章“实用程序员:从熟练工到大师”阅读的补充,作为提高数据科学中软件写作技能的媒介。下周我们将看一下第 7 章:项目前。
原载于 2021 年 4 月 30 日 http://thelonenutblog.wordpress.comhttps://thelonenutblog.wordpress.com/2021/04/30/better-software-writing-skills-in-data-science-while-you-are-coding/。
比 GPT 3 更好——来看看 BlenderBot 2.0:脸书最新的聊天机器人
人工智能|新闻
而且是开源的!

雷锐在 Unsplash 上拍照
从类人对话式人工智能来说,我们可能比我们想象的更近。
2020 年 4 月,脸书发布并开源了当时有史以来最大的聊天机器人; BlenderBot 。虽然 GPT-3 盖过了它,但与 OpenAI 的超级明星相比,BlenderBot 的能力毫不逊色。脸书人工智能团队选择将基于大型变压器的语言模型的超级成功趋势——blender bot 拥有 94 亿个参数,创下了当时的纪录——与其他技术相结合,以提高性能。
他们的最终目标是创造一个聊天机器人,能够“根据情况要求,提问和回答各种问题,展示知识,并表现出同理心、风度翩翩、引人入胜、严肃或有趣。”人类的对话是微妙含义和突然转变的复杂舞蹈。BlenderBot 本该成为最好的人工智能舞者。
除了通常的大规模训练(使用大量互联网数据),他们使用混合技术和世代策略。
- 混合技能: BlenderBot 在一项名为混合技能对话 (BST)的任务中进行了微调,该任务由三种不同的技能组合而成:展示独特的个性,利用先前的知识,展示同理心。什么时候应用这些技能是这种方法具有挑战性的原因。例如,系统应该区分人们什么时候需要被倾听,什么时候他们在问一个修辞性的——而不是真正的——问题。
- **世代策略:**聊天机器人通过优化困惑度来训练——困惑度是一种衡量模型在预测下一个令牌时有多自信的指标。然而,脸书的团队认为,控制聊天机器人消息的长度——以及其他策略——可以提高性能。
人类评估者承认,BlenderBot 明显更有吸引力——他们更喜欢与它进行长时间的交谈——并且感觉比任何其他竞争对手都更有人情味,包括谷歌的 Meena(当时最先进的)。
现在,脸书人工智能团队又向前迈出了一步。7 月 16 日,他们发布了开源 BlenderBot 的继任者: BlenderBot 2.0 。在这篇文章中,我将强调它相对于以前的对话式人工智能的改进,并解释它如何与 GPT-3 相比较。
blender bot 2.0——上下文聊天机器人的力量
BlenderBot 2.0 建立在 BlenderBot 的独特功能之上。它表现出鲜明的个性,能够利用先前的知识并表现出同理心。然而,它更擅长举行多节对话和运用知识。它更忠实地记得以前的交互,并且它的话语事实上更一致。我们可以将这些改进归结为两个新特性:
- 一个长期的本地记忆库。
- 随时随地访问互联网的能力。
长期本地记忆存储
BlenderBot 2.0 学会了从大量人类对话数据中进行对话。它知道对话是如何构建的,以及根据上下文应该使用的风格。然而,我们谈论的内容在不断变化。当我们与另一个人交谈时,我们对彼此的所有共享的先验知识对于交谈的成功至关重要。
由于这个原因,BlenderBot 2.0 有一个长期的内存存储。它可以把大量的知识写在里面,供以后使用。脸书大学的研究人员 Jason Weston 和 Kurt Shuster 在他们的博客中分享了一个例子来说明这是如何发生的:

BlenderBot 2.0 保存了关于自身及其伙伴的内存知识——已编辑。原创于脸书博客
这一功能最有希望的一面是,随着系统不断生成话语,它创建了自己的背景、个性和生活经历,这些都被存储起来,并随着时间的推移保持稳定。因为它还保存了关于其对话伙伴的信息,所以它建立了我们所说的健壮的虚拟关系。
BlenderBot 2.0 可以引出你在之前的对话中谈到的话题或想法。例如,“如果你几周前与它谈论汤姆·布拉迪,它可能会在未来的对话中提到 NFL,因为它知道这是一个与你相关的话题。”共同的记忆滋养了我们的关系。这种能力使它比其他任何对话式人工智能都更像人类。
互联网接入增加知识
与其他语言模型相反,BlenderBot 2.0 并不局限于它已经被训练过的知识或者它已经存储在本地存储器中的知识。它可以访问互联网以搜索相关的上下文信息。如果你提到一些系统不知道的东西,它会立即去寻找关于这个话题的最新信息。然后,它可以使用这些信息来推进对话,并进一步阐述某个主题或其个性。
例如,在下面的例子中,与 BlenderBot 2.0 交谈的人提到了海湾地区。BlenderBot 搜索这个词,并立即使用它来创建自己的一个新方面:“我住在旧金山湾区。”

BlenderBot 2.0 访问互联网来查找上下文信息—经过编辑。原创于脸书博客
这个特性的威力是双重的:首先,BlenderBot 2.0 不会过时。像 GPT-3 这样的系统是用静态数据训练的,所以世界上发生的新事物不会被系统捕捉到。相反,BlenderBot 2.0 总是可以再次查找信息来更新它已经知道的内容。
第二,它对几乎所有事物都有无限的知识。因为它不会忘记它所知道的(由于它的记忆库),它可以在以前的知识上建立一个人物角色。在我们拥有的最丰富的数据库的帮助下,它可以一直保持增长的特性;互联网。
结合记忆和外部知识——一个独特的架构
BlenderBot 2.0 背后的想法是创建一个对话式人工智能,可以添加对话中不包含的信息。这是一个可以创新地推动对话走向新道路的系统。为了实现这一点,BlenderBot 2.0 使用了脸书的检索增强生成方法。它允许系统不仅根据对话本身,而且通过访问其存储器或互联网数据来决定对什么做出响应。

BlenderBot 2.0 算法结构——在脸书博客中
我们人类以类似的方式发展——保持距离。我们感知世界,并与世界互动,以获取知识和生活经验。我们与其他人发展关系,也从不同的来源(包括互联网)学习。我们获取关于世界的信息,并将其与我们先前的知识相结合,小心地储存在我们的记忆数据库中。这就是我们进化和成长的方式,也是我们决定下一步做什么的方式。所有这些,加上我们自身的稳定性,造就了我们。BlenderBot 2.0 是我们最接近以这种方式构建的人工智能。
比 GPT 3 号有更多的记忆和知识
GPT 3 号是无记忆的
这个高超的语言模型在许多不同的生成任务中被证明是成功的。它掌握了语言的形式,以至于它的文本甚至可以轻易地愚弄精通技术的人。然而,它的一个缺点是记忆力差。在适当的提示下,GPT 3 号可以成为一名优秀的诗人,但第二天它又会变成一名新手。该系统并不打算保存以前的对话。相比之下,我可以向 BlenderBot 2.0 提到,我喜欢早餐吃西兰花和鲑鱼,三周后它可能会建议我在菜里加入土豆。
GPT-3 的内存不足不仅仅是一个与实用程序相关的缺点。这让它缺乏个性。不可避免地感觉我们在和一台机器对话。在一段时间内,它可以让我们忘记它是一堆 1 和 0。但它最终总是暴露自己,因为它没有一个稳定的行为。
GPT-3 已经过时了
许多用户发现 GPT 3 号的另一个缺点是缺乏最新知识。GPT-3 是在一个变化比以往任何时候都快的世界中根据静态数据进行训练的——全球数据量每两年翻一番。以这种方式训练的系统可能成为*幻觉*的受害者——对不真实的信息充满信心。例如,一个用户问 GPT-3 史蒂夫·乔布斯现在在哪里,系统回复:“我在加州库比蒂诺的苹果总部。”史蒂夫·乔布斯十年前就去世了,但是 GPT-3 没有储存这些知识。
这不仅降低了 GPT-3 的实用性,甚至还会带来危险。这就是为什么 OpenAI 的研究人员建议不要将该系统用于高风险类别。我们希望对话式人工智能总是给我们最新的信息。如果有一天我们要依赖这些系统,我们将需要它们每分钟都被更新。
结论
BlenderBot 2.0 是向类人对话式人工智能的又一次飞跃。就目前而言,它具有人格、同理心、记忆力,并能从互联网上获取和使用知识。下一个技术挑战是多模态;一个聊天机器人可以使用图像——或其他类型的感知数据——来更接近地模仿人类相互交流的方式。
另一个至关重要的挑战是安全性。微软的 Tay 证明了这些系统很容易走上仇恨和不宽容的道路。我们应该让这些系统充满道德过滤器,以避免它们产生“不安全或攻击性的言论”。脸书人工智能团队开发了两种方法来对抗恶意意图:固有的安全性和对困难提示的鲁棒性。
要完全信任这些系统还有很长的路要走,但似乎人工智能的安全、道德和问责现在是推动该领域发展的大型科技公司的优先事项。我想大多数人会同意我的看法,这些方面比实现 AGI 更为紧迫。我们最终会实现这个目标,但最重要的是我们要尽可能做到最好。
订阅我的免费每周简讯明日之心获取更多关于人工智能的内容、新闻、见解和思考!
此外,请随时在 LinkedIn 或 Twitter 上发表评论和联系!:)
推荐阅读
在 Hadoop 和云之间:我们将何去何从?
原文:https://towardsdatascience.com/between-hadoop-and-the-cloud-where-do-we-go-from-here-516bf2fb719c?source=collection_archive---------50-----------------------
在后新冠肺炎时代,企业必须准备好快速应对和适应。旧的 Hadoop 技术在这个新世界中有一席之地吗?

韦雪恩(魏贤)成龙在 Unsplash 上的照片
在 2021 年的新兴世界,大数据和机器学习仍然是圣杯,而对卓越速度和敏捷性的需求继续加快云的采用。旧的 Hadoop 技术在这个新世界中有一席之地吗?为了阐明这个问题,让我们思考一下什么是 Hadoop,以及云是如何影响 Hadoop 的。
在这篇文章中,你会:
- 了解 Hadoop
- 探索云上的 Hadoop
- 借助现代云平台展望未来
了解 Hadoop
Hadoop 为何如此重要?
曾几何时,随着我们业务的增长,我们开始产生太多的数据,无法用一台计算机来存储和处理。
也许是时候升级了?好的,所以我们买了一台更好的电脑,比以前的更先进,当然也更贵。
直到有一天,我们又一次产生了太多的数据,这台新电脑也放弃了。然而,购买一台又一台先进的计算机实在是太贵了,负担不起。
如果有太多的数据需要存储在一台计算机上,那么把它分成小块,存储在多台计算机上怎么样?
如果用一台计算机处理所有数据花费太长时间,我们为什么不把处理任务分成更小的任务,让多台计算机并行处理这些数据块呢?
你可能已经猜到了,Hadoop 让这两个想法成为了现实。
再也不用花一大笔钱去追求市场上最先进的计算机了!企业可以购买更多负担得起的日常电脑,以满足不断增长的存储和处理更多数据的需求**。**因此, Hadoop 的核心是提供一个可靠、可扩展且经济高效的平台,通过将非常大的工作负载分布在许多单独的计算机上来存储和处理数 Pb 的数据。
Hadoop 生态系统是什么样子的?
Hadoop 的核心组件

作者图片
作为存储层, **HDFS 是捕获所有数据处理任务的数据、中间结果和最终结果的地方。**在 HDFS 存储一个文件时,系统将它分成大小均匀的数据块,并将这些数据块存储在许多单独的计算机中(也称为 Hadoop 集群)。
如果说 HDFS 是将大数据分解成可管理的块进行存储,那么 **MapReduce 就是将一个大问题分成许多小块,这样你就可以并行处理它们,更快地解决问题。**Map 任务在存储数据的计算机上单独处理数据块,而 Reduce 任务将从各个计算机获得的所有结果组合成一个结果集。
MapReduce 负责数据处理,而 YARN 则负责资源管理,确保每一项工作都分配到合适的计算机上完成。这种使 Hadoop 能够运行除 MapReduce 之外的不同工作负载,最终扩展 Hadoop 功能以支持其他应用处理流数据或运行临时数据分析。
Hadoop 生态系统的其他部分

作者图片*(并非生态系统的所有开源组件都包括在内)*
凭借其 3 个核心组件,Hadoop 只是一个存储和处理数据的通用平台,没有任何搜索或查询结构化数据的特殊功能。这意味着它需要其他组件来形成分析大数据的完整解决方案。
例如,我们需要 Sqoop 和 Flume 分别将结构化数据(来自关系数据库或数据仓库)和事件数据(来自物联网设备或社交媒体网络)批量收集到 HDFS 进行分析和洞察。
此外,我们需要额外的工具来满足不同的任务,如用 Pig 编程,用 Hive 或 index 查询结构化数据,用 Solr 搜索。此外,其他工作流管理工具,如 Oozie,也在调度和管理 Hadoop 任务中起着至关重要的作用。
简而言之,正是开源组件的更大生态系统使得 Hadoop 在回答业务问题时非常有用。
十秒钟外卖
Hadoop 的核心是提供一个可靠、可扩展且经济高效的平台,通过在许多单独的计算机上分配非常大的工作负载来存储和处理数 Pb 的数据。 您可以购买您需要的多少台计算机,安装您想要的组件,留下您不需要的,并根据您的业务需求添加您的细微差别。
探索云上的 Hadoop
云是如何融入 Hadoop 的?
到目前为止,我们只讨论了公司购买、构建和维护许多计算机来存储和处理大数据的本地 Hadoop。但是从那以后,技术发生了巨大的变化。
如果可以在云端运行 Hadoop 会怎么样?换句话说,你只需从 AWS、谷歌云平台或微软 Azure 等云提供商那里租用你需要的多少台电脑,安装 Hadoop 并处理你想要多长时间(或多短时间)的数据,同时像每月支付电费一样支付给他们。
在我们探讨为什么有人愿意将 Hadoop 从内部迁移到云之前,理解云的含义很重要。这里有一个简单的定义,摘自我最喜欢的书“像我 10 一样解释云”。
云是一个计算机网络,通过互联网提供某种服务。你不关心那些电脑在哪里或者它们是如何工作的。你永远看不到他们。你从来不碰它们。它们只是一群供你使用的联网计算机。
—托德·霍夫
我们为什么要考虑在云上运行 Hadoop 呢?
在云上运行 Hadoop 的想法包含了许多引人注目的优势。下面是将 Hadoop 迁移到云中可以很好地解决的两个关键问题。

作者图片
如果不提及以下两点关于在云上运行 Hadoop 的要点,这将是不完整的。
- **许多公司不能或不愿意完全放弃昂贵的长期本地基础设施。**因此,他们可以选择混合云架构来在本地运行某些作业(如果出于安全原因数据无法上传到云中),并在云上处理其他工作负载。那样生活会更复杂,但在特殊情况下会足够好。
- 在云上运行 Hadoop 并不是解决所有问题的灵丹妙药。比如不能保证存更多的钱。不管你是否使用,你仍然需要为你所请求的东西付费。安装 Hadoop 组件、微调性能和正确处理网络仍然需要时间和专业知识。
十秒钟外卖
既然在云上运行 Hadoop 仅仅意味着一切如常,但是在云中,处理大数据进行分析和洞察还远远不是一个完美的解决方案。然而,它确实提供了一些希望,因为云可以节省您的大量工作,同时让您的 Hadoop 更快地启动和运行。
借助现代云平台展望未来
随着我们更深入地进入新的云世界,我个人看不出在云上运行 Hadoop 的意义。当我们也有一系列选择来通过现代云平台存储和分析大数据时,我们为什么要降低要求呢?
但首先,我们需要知道有哪些选择。所以让我们来了解一下吧!
选项 1:托管 Hadoop 服务
Being 是在云上运行 Hadoop 的一个进步,首选意味着利用云提供商提供的预打包 Hadoop 服务。一些例子包括 AWS Elastic MapReduce (EMR)、Google Cloud Dataproc 和 Microsoft Azure HDInsight。
它是这样工作的:**你按需创建 Hadoop 集群,定义需要什么 MapReduce 或 Spark 作业,让它们执行那些数据处理任务,并在得到结果后关闭它们。**虽然您仍然需要为消耗的计算资源付费,但您不必担心如何手动安装和配置 Hadoop 组件以及管理它们的性能。
然而,许多组织持怀疑态度,因为这样的预打包服务可能不足以应对复杂的需求或者导致供应商锁定。而且之前没用过 Hadoop 的人也在完全绕过它来避免复杂性和高学习曲线。
选项 2:云大数据解决方案
正如您可能已经猜到的那样,对于那些以前从未使用过 Hadoop 并且很可能负担不起专业知识的人来说,云提供商提供的大数据解决方案可能是真正的解决方案。简单地说,让我们永远摆脱 Hadoop。
在数据生命周期的每个阶段(即摄取、存储、处理和分析、探索和可视化),主要云提供商,如 【亚马逊】谷歌 和 微软 提供多种解决方案,专门满足终端用户不断变化的大数据需求。只要看一看他们的产品,我们就可以很容易地看到,与 Hadoop 生态系统相比,他们的选择真的是无穷无尽,而且同样多才多艺。还有呢?大多数云解决方案的直观图形用户界面意味着用户可以更快地从数据中获得洞察力并做出明智的决策**,而不必首先成为所有方面的技术专家。**
云解决方案的另一个关键卖点是人工智能(AI)和机器学习(ML)的附加组件。选项可以从现成的预训练 ML 模型到托管 AI 平台(用于从头构建您自己的模型)不等。用准确的预测为数据驱动的决策提供信息的能力是 Hadoop 难以企及的。
当然,生活中的每一件事,总有潜在的取舍。在这种情况下,如果您要用其他东西替换 Hadoop,一定的学习曲线是不可避免的。此外,你对特定于供应商的解决方案参与得越多,你就离开源世界和随心所欲工作的权力越远。
十秒钟外卖
一方面,摆脱 Hadoop 意味着远离开源解决方案,但提供了便利性、易用性和更强的 AI/ML 能力。另一方面,选择托管 Hadoop 平台需要关于 Hadoop 工具的专门知识,同时保留使用任何您想要的开源工具的自由。不幸的是,不存在完美的一刀切的解决方案,因为这是一个选择和优先事项的问题。
离别的思绪
用于大数据的旧 Hadoop 技术在这个大数据和机器学习的新世界中有一席之地吗?我想说,至少现在,Hadoop 不会很快完全消失。但我们正处于过渡阶段,不同的组织在不同程度上表现出让云补充或取代 Hadoop。
**由于速度和敏捷性的重要性,**云的采用不再是“是否”的问题,而是“多快”和“到什么程度”的问题。在后新冠肺炎时代,企业必须准备好快速响应和适应,云数据解决方案将蓬勃发展,并可能成为加速大规模创新和释放额外商业价值的重要因素。
如果你正在读这篇文章,感谢你的时间,我真的希望你能从这篇文章中得到一些价值。欢迎访问我在https://thedigitalskye.com/的博客,或者通过 LinkedIn 和 Twitter 与我取得联系,了解关于数据、商业和其他任何事情的激动人心的故事。各位,万岁,繁荣昌盛!
参考
- 托德·霍夫《像我 10 岁一样解释云》
- Bill Havanki 的《将 Hadoop 迁移到云上》
- Hadoop:汤姆·怀特的权威指南
【http://thedigitalskye.com】原载于 2021 年 3 月 1 日http://thedigitalskye.com/2021/03/02/between-hadoop-and-the-cloud-where-do-we-go-from-here/。****
小心数据分析中的偏见
原文:https://towardsdatascience.com/beware-of-biases-in-data-analysis-accf0cb9b3a?source=collection_archive---------10-----------------------
影响数据分析的认知和统计偏差以及如何克服它们
作为一名产品分析师,你有没有遇到过这样的情况:你的团队有了一个产品想法(你认为这个想法非常棒),进行分析和实验,结果看起来不错,然后发布,却发现这个想法实际上很糟糕?然后你开始怀疑也许执行不正确——营销或运营方面出了什么问题?但是你有没有想过**问题可能在你这边?**可能,在你的分析中有一些失败将洞察力引向你不自觉希望、的方向,而不是它应该在的地方**。**
你可能已经注意到了这个迹象——当你继续挖掘数据,直到洞察力似乎“正确”。

图片来源:https://imgs.xkcd.com/comics/machine_learning.png
人类这种影响自己判断的主观天性被广泛称为 偏见 。引用维基百科的说法,认知偏差是一种“偏离 规范 或理性判断的系统性模式”。它已经在许多社会心理学和行为经济学研究中得到确认和使用,因为它影响人们在日常生活中的决策,包括在数据分析工作中。
偏见的类型
首先,让我们探讨一下常见的、对数据分析工作有重大影响的各种偏差。
认知偏差
认知偏差主要是干扰分析流程的主观性——假设、假设、研究问题,以及最终的探索性优先排序。
- 确认偏见:以确认一个人的先入之见的方式搜索、解释、关注和记忆信息的倾向(来源:维基百科)。这种偏差通常发生在表演的人有一个预先确定的假设,其中数据分析被用来证明它。然后他们继续查看数据,直到这个假设被证明。
- 可用性偏差:高估记忆中“可用性”更大的事件的可能性的倾向,这可能受到记忆有多近或它们可能有多不寻常或情绪化的影响(来源:维基百科)。根据组织中发生的历史事件或分析师的经验,会有一些分析师首先努力和优先分析的“首要”项目和问题。
- 框架:从相同的信息中得出不同的结论,这取决于信息是如何呈现的(来源:维基百科)。根据你分析的角度,有些方法可能太窄或太宽。有时,即使选择使用“绝对数字”或“百分比”,或者数据可视化中使用的轴刻度,也会给得出的结论带来巨大的差异。**

左图以某种方式显示了相关性,但当 viz 被调整到正确的比例时,它不再显示相关性(Pic credit:Sarah Leohttps://medium . economist . com/errors-we ve-draw-a-first-8 cdd 8 a 42d 368)
让我们举一个这些偏见结合在一起的例子。
假设你是一家电子商务公司的业务分析师。业务开发团队提出了一个请求,他们注意到交易量略有增加,希望了解这一现象的原因。
然后你还记得几周前有报道说市场某个位置发生了滥用推广的行为,膨胀了平台的总交易量。你怀疑同样的事情,虽然已经发生过一次,而且已经处理过了,但还会再次发生( 可用性偏差 )。
然后记住这个假设,你开始列出研究问题来证明这个 ( 证实偏差 )。你看之前欺诈区域的交易,他们的推广交易,他们新用户的交易等等。
然后观察该地区新用户促销交易的增加,您得出结论总体交易增加是由于在那里提出 100 万笔交易数据的欺诈。尽管 100 万笔交易仅占整个平台 1 亿笔交易增量的 1%,但这种情况还是会发生——这是我们最初的问题陈述( 框架偏差 )。
这不是分析和做出商业决策的理想方式,对吗?
在维基百科页面上阅读更多关于认知偏见的内容。
统计偏差
统计偏差大多是我们在做分析时不自觉陷入的技术谬误。
- 选择偏倚:在选择个体、群体进行数据分析时引入的偏倚,这种方法不能实现适当的随机化,从而确保获得的样本不能代表待分析的人群(来源:维基百科)。对于数据分析师来说,这主要发生在 产品实验 中。有些情况下,实验发生在预先选择的表现最佳的客户群,但实际推出的是所有客户群,这产生了不同的结果。或者当实验在几天的时间框架内完成时,该时间框架不能捕捉产品性质的每周季节性。
- 生存偏差:关注那些通过了某些选择过程的人或事,而忽略那些没有通过的人或事的逻辑错误,通常是因为他们缺乏可见性(来源:维基百科)。这种生存偏差会导致一些 错误信念 于治疗所给予的积极影响。例如,你正在分析你的产品中忠诚顾客的行为。你会发现,这些忠诚的客户大多来自客户推荐,最后,你会推荐客户推荐来获得潜在的忠诚客户。你可能会忘记,无论如何,客户推荐在你的新客户获取中占了很大一部分。
- 遗漏变量偏倚:选择偏倚的一个更具统计学特异性的版本,这是统计模型遗漏一个或多个相关(混杂)变量的情况。在数据建模中,这可能会导致模型拟合不足。或者当它被拟合时,它 可能不会足够健壮 ,因为遗漏了变量。
当识别和理解时,这些统计偏差比认知偏差更容易预防,因为技术细节可以被注意到和解决。

Ioan F 在 Unsplash 上的照片
克服偏见
现在你知道了在数据分析过程中可能出现的不同偏差,你可能会问“我该怎么办?”。这里有一些提示,你可以用来更好地意识到偏见,并防止它们妨碍分析的客观性。
心态
- ****不要固执己见。你可能听说过“强有力的观点弱有力的持有”这句话,简单来说就是尽管你已经做了调查,并且(你觉得)你很了解自己的东西,但仍有可能你错了。记住确认偏差及其代价,然后向新想法敞开心扉——甚至是那些挑战你观点的想法。即使在检查了那个新想法之后(客观地!)你发现你最初的看法是对的,你会对此更加肯定:)
- 实验重点。作为上一点的延续,我们可能想训练我们的思维,把分析当成一次旅行,中间有一些实验。通过这些实验,我们探索数据并揭示洞察力而不管我们反对它们的立场。
- 避免走捷径。可以理解的是,大多数科技公司(尤其是初创公司)生活在高速时代,所有事情都需要在一个实例中完成。作为一名分析师,我们被推动着快速获得洞察力,并且更经常地以可用性偏差做出结论,或者以省略变量偏差创建数据模型,因为它们是我们的首选。在这种情况下,分析师和他们的领导应该站出来,在教育用户分析方面发挥咨询作用——这些事情可以很快完成,也不能很快完成。记住可靠的结果只能通过正确的方法和技术来实现。
执行技术
- 重新表述你的分析目标和假设。将分析目标从一个是/否的问题转变为一个更加精细和没有方向的问题。例如,不是“发现新产品是否增加交易”——这是一种假设积极影响的向上语气,我们可能想将其改为“新产品的表现如何?”——哪个更中性**。**

在 Unsplash 上由 Tachina Lee 拍照
- 从不同角度丰富你的分析。为了避免主观性,你可能想把自己放在一个分析的直升机视图中。思考分析中涉及的不同组件以及它们可能如何相互作用,该产品的变化将如何影响不同细分市场的客户—新客户、低使用率客户和忠诚客户。与其他分析师、研究人员、产品经理或设计师进行讨论可能有助于获得新的观点。****
- 合适的样本和数据选择。特别是对于产品实验设置中的选择偏差,从不同客户群中获取随机样本以获得代表性,确保在进行统计测试之前达到最小样本量,并运行足够长时间的实验以覆盖数据带来的短期波动(即周末的高流量),这一点很重要。
最后的话
知道并意识到偏见的存在是一回事。然后你需要在进行分析时更加注意,做清单以防止偏见干扰分析。希望本文和技巧可以帮助您交付更好的数据分析结果。
小心数据转移
原文:https://towardsdatascience.com/beware-of-data-shifts-162cb32d4d41?source=collection_archive---------37-----------------------
数据科学
训练数据和实施后数据之间的差异会导致模型性能不佳

艾莉娜·格鲁布尼亚克在 Unsplash 上的照片
用机器学习算法建立的预测模型在现实世界中往往表现不佳。
即使是由一些世界顶尖专家建造的人工智能,也常常难以在“实验室”之外复制出有前途的性能。一个突出的例子是在谷歌开发的医疗保健人工智能系统。
人工智能应用旨在帮助诊断。从癌症筛查到疾病检测和风险预测。
当在实验室环境中进行培训和评估时,这些应用非常成功。但是当在真实世界中进行测试时,例如在泰国的诊所中,性能无法与实验室环境相匹配。
在这种情况下,提供给算法的数据质量低于训练数据。但是许多不同的潜在原因导致了同一个问题:数据移动。
数据偏移是一个用来描述数据分布变化的术语。发生这种变化的原因有很多。然而,它们可以归结为三个主要机制。
- 导致目标变量发生变化的原因(与所使用的解释变量无关)。
- 导致解释变量变化的原因。
- 改变目标变量和解释变量之间潜在关系和/或模式的原因。
下面将进一步阐述这些机制。
理解数据转移的根源和影响是解决模型性能比预期差(模型性能下降)相关问题的先决条件。
分区在
想象一下。
您希望实现一个预测模型。这样做的过程很清楚。
首先,对可用于训练和验证的数据进行冗长而彻底的探索。然后,开发一堆各种各样的机器学习模型。
最后,正确选择和实现在各种验证过程中表现良好的模型。
什么会出错?
嗯,很多事情。人工智能和人工智能模型最常见的问题之一是数据底层分布的变化。无论是使用相当简单的回归模型还是复杂的算法,如深度神经网络,数据转移都是建模者头疼的一个常见原因。
1。先验概率转移
上面列出的第一种机制正式称为先验概率转移。
它描述了目标变量的分布发生变化,而解释变量(或输入变量)的分布不变的情况。
这可能是由于状态的改变。让我们假设您想要预测给定处方药药店将销售多少,以确保有效的供应管理。
你有一个模型,它考虑了居住在附近的人数、该药物治疗的疾病的发病率、该药物和替代药物的价格以及药房之间的距离。
但是不可预见的事情发生了,导致对该药物的需求发生了变化,尽管解释需求的变量没有变化。
快速嗅觉测试-检查是否应该花费更多资源来检测潜在的先验概率转移-只是绘制 1)用于训练和验证的数据集和 2)模型表现不佳的新数据集的直方图。
如果直方图看起来像下面这样,我们的嗅觉测试表明发生了变化。

由来自 G. Sarantidis 的代码生成的直方图。来源:https://gsarantitis.wordpress.com/
2.协变量移位
所列的第二种机制,改变了(的分配!)解释变量(或协变量或输入变量)是协变量移位。
在上面的例子中,如果居住在药店附近的人口大量增加,将会发生协变量转移,但这些人(出于某种原因)都没有任何条件要求他们需求所述药物。
测试协变量变化的一种方法是将新数据(来自模型实施但表现不佳的时期)与训练数据混合。
取出随机样本作为测试数据,并使用剩余的数据来训练模型,以预测观察值是源于原始训练数据还是新数据。
如果原始训练数据和新数据无法区分,就不太可能有协变量偏移。
如果它们是可区分的,你应该重新训练你的模型。
3.概念漂移
列出的第三种机制,即目标变量和解释变量之间关系的变化,通常被称为概念漂移。
发生这种情况有几个原因。其中有选择(一种确定性的观测去除),周期性变化(未被检测到),以及非平稳性。
概念漂移在时间序列中很常见。如何处理取决于具体问题,有时会受到可用数据的限制。
关于这件事的很好的介绍可以在这里找到。
外卖食品
数据偏移是机器学习方法的各种实现中的常见问题。从图像识别到预测建模。
发现和解决它们的困难程度因情况而异。
但是思考它们、测试它们、处理它们或者意识到它们如何对给定模型或算法的良好运行提出挑战是至关重要的。
所以亲爱的数据科学家们,当心数据转移。
小心紧缩的数据科学金字塔!
原文:https://towardsdatascience.com/beware-of-the-constrictive-data-science-pyramid-e681140b3b87?source=collection_archive---------46-----------------------
许多大型组织都在努力解决如何有效领导数据科学家的问题。以下是我所学到的。

- gaur av D lath iya 在 Unsplash 上拍摄的照片
前几天,我在阅读一篇关于人口老龄化的人口统计学论文时,突然想到人口金字塔和数据科学组织之间有一个相似之处。紧缩型人口金字塔是指金字塔底部变窄,即年轻人的比例较低。年轻人相对于老年人的低比例可能会导致人口抚养比的问题。我看到一些组织遭受同样的现象,但在数据科学、ML 和 AI 技能领域。试图利用数据科学和人工智能的大型传统组织似乎容易出现这种情况。

亚历山大·安德鲁斯在 Unsplash 上的照片
让我用木工来说明我的观点。年轻人可能在学校学过或没有学过一些基本的木工技能,通常开始为一个更有经验的木匠工作,磨砺他们的技能和经验,也许专攻木工的某个领域,然后从那里开始。过了一段时间,有些人会开始自己做生意,也许会自己雇佣刚从学校毕业的木匠。其他一些人没有发展的雄心或技能,他们会离开木工行业或留在他们觉得舒适的职位上。当老木匠退休时,他或她最有经验和才华的木匠将接替他/她的位置。这种情况接近于一个“固定”的金字塔,也就是说,你有一个相对较大的低技能或低经验的木匠群体,接着是一个较小的更有技能或更有经验的木匠群体,以此类推。随着更有技能/经验的团队指导技能/经验较少的团队,一段时间后,一个更小的团队将“提升”到下一个级别。
数据科学中的情况有些不同。多亏了我们大学的灵活性和适应性——我无法充分强调我对此有多高兴——许多刚毕业的数据科学家拥有令人印象深刻的技能。是的,他们可能缺乏一些经验,可能倾向于过度设计,但通过一些适当的指导,这可以变得尖锐。事实上,由于技术变化的速度很快,许多年轻的数据科学家拥有他们年长的同事可能缺乏的技能,因为他们上大学时不存在这些技能。这就是为什么数据科学家跟上其专业领域的最新发展至关重要。好的组织允许他们的数据科学家这样做。好的组织还会确保年轻的数据科学家能够从年长且更有经验的同事那里学习如何在商业环境中应用他们的技能。如果这种情况发生,数据科学可以接近我们在木匠身上看到的“静止的”金字塔。
唉,事实并非总是如此。通常情况下,年长的数据科学家是伪装的商业智能人士,他们没有多少东西可以教给年轻一代(除了坏习惯)。只要这些人没有被赋予领导角色,他们就是无害的。当没有适当数据科学背景的人被要求领导数据科学团队时,问题就出现了。这很少奏效。是的,我们都听说过关于营养学家或艺术史学家成为杰出的数据科学领导者的故事,但这些都是例外。我听到许多数据科学家抱怨说,他们的组织雇佣了一个不太熟练的经理。我从数据科学家那里听到的抱怨比从其他部门的人那里听到的更多。出现这种情况的原因有很多。首先,在许多(传统)组织中,数据科学(或 ML 或 AI)不是业务的核心。他们只是雇佣了一大批数据科学家,因为他们想“用人工智能做点什么”。然后,该团队通常向更传统的职能部门(如 IT 或营销)报告,因此由这些部门的人员管理。这并不总能带来幸福的婚姻。
另一个原因是——我们需要诚实地面对这一点——没有多少数据科学家同时是好经理和好数据科学家。因此,公司希望让他们的(昂贵的)数据科学家担任适合他们的角色是合乎逻辑的。但是,现实是,这种情况会导致很多挫折。我个人认为这(部分)解释了一些数据科学团队遭受的高周转。

斯科特·格雷厄姆在 Unsplash 上拍照
你可能想知道为什么所有这些似乎更经常发生在(传统公司的)数据科学部门,而不是其他职能部门。例如,我还没有见过很多组织的财务部门都是金融天才,但首席财务官是没有学位或多年金融经验的人,但这正是我在一些组织中看到的数据科学。
再比如法律。许多没有大型法律部门的组织仍然有一个首席法律官,如果需要的话,他会雇佣法律助理。然而,首席法律官将与首席运营官、CMO 和其他高管坐在一起,而数据科学家在最好的情况下,坐在首席运营官、CMO 或首席技术官组织的某个深处。当然,有些组织有首席数据官或首席科学官,但这些人通常不擅长(数据)科学。我很幸运,我曾经向一家大公司的首席科学官汇报过,他实际上有科学背景,但我觉得这是一个例外。
那么解决办法是什么呢?首先,我们需要鼓励年轻的数据科学家投资于领导技能,以便数据科学领导角色可以由数据科学家来担任,而不是由退休的 BI 人员来担任。
这并不容易,因为年轻的数据科学家经常觉得这种东西很无聊。此外,领导力有时会与政治混淆。我认识的大多数数据科学家讨厌公司政治,这是理所当然的。这通常是破坏性的,不符合公司的利益,而且相当无聊。但是,在大型组织中,如果您希望您的数据科学团队保持业务相关性并普遍繁荣,政治也是必不可少的。我见过一个案例,数据科学领导者感觉自己凌驾于公司政治之上,只关注技术方面的东西。最初,她赢得了团队成员的尊重。他们对她的技术实力印象深刻,他们喜欢她不玩政治游戏这一事实。然而,一段时间后,她的团队变得与业务完全无关,人们会从她的团队转移到其他部门。最初为她欢呼的那些人很快就抱怨她没有照顾他们的利益并离开了。顺便说一下,请注意,像这样的案例强化了这样一种观点,即数据科学家不具备在大型组织中取得成功的管理技能,这让我们回到了起点。
其次,组织最好考虑让谁负责数据科学团队,以及该团队如何融入组织的其他部分。正如我上面提到的,我知道许多数据科学家对级别比他们高的人缺乏技能感到沮丧。有时是因为这些数据科学家并不总是看到那些人确实拥有的技能,那么这就是教育的问题。但有时你只需要为工作雇佣合适的人。请注意,我并不是说他们都应该有博士学位。这大多是不相关的。很久以前,我是一个大型组织中一个小团队的成员。顺便说一句,我们都有博士学位,只有老板没有。然而,他也比我们更有知识和经验,所以没有人质疑他的领导能力,恰恰相反。
最后,让我重复一遍,我上面描述的现象在将数据科学作为其业务核心的组织中不会发生。我主要在试图利用数据科学和人工智能的大型传统公司中看到这种情况。显然,在这些组织中,数据科学存在领导问题,或者至少是感觉上的领导问题。数据科学家需要证明,在领导力方面,数据科学不仅仅是 BI++。

在 Unsplash 上由 Boitumelo Phetla 拍摄的照片
小心熊猫的虚拟变量陷阱
原文:https://towardsdatascience.com/beware-of-the-dummy-variable-trap-in-pandas-727e8e6b8bde?source=collection_archive---------3-----------------------
使用pandas.get_dummies()对数据进行编码时需要记住的重要注意事项

由 www.freepik.com sentavio 制作的 Man vector
处理分类变量是机器学习管道的重要组成部分。虽然机器学习算法可以自然地处理数字变量,但这对于它们的分类对应项是无效的。虽然有像 LightGBM 和 Catboost 这样的算法可以固有地处理分类变量,但大多数其他算法都不是这样。这些分类变量必须首先转换成数字量,以输入到机器学习算法中。有许多方法可以对分类变量进行编码,比如一次性编码、顺序编码、标签编码等。但是本文着眼于 pandas 的虚拟变量编码,并揭示了它的潜在局限性。
分类变量—快速介绍
一个 变量 的值在多个类别中变化,称为分类变量,如性别、头发颜色、种族、邮政编码或社会保险号。两个邮政编码或社会保险号的总和没有意义。同样,邮政编码列表的平均值也没有意义。分类变量可以根据它们分组的元素种类分为两个子类别:

分类变量|作者图片
- 名义变量是那些类别没有自然顺序或排序的变量。例如,我们可以用
1表示红色,用2表示蓝色。但是这些数字没有数学意义。也就是不能相加,也不能取平均值。属于这一类别的例子有性别、邮政编码、头发颜色等。 - 有序的变量有一个内在的顺序,这在某种程度上是有意义的。一个例子是跟踪学生的成绩。另一个例子是 T4 人的社会经济地位。
用“`pandas.get_dummies()``编码分类变量
现在我们知道了什么是分类变量,很明显我们不能在机器学习模型中直接使用它们。它们必须被转换成有意义的数字表示。这个过程叫做编码。有很多编码分类变量的技术,但是我们将特别关注由 pandas 库提供的一种叫做[get_dummies()](https://pandas.pydata.org/docs/reference/api/pandas.get_dummies.html)的技术。
顾名思义,pandas.get_dummies()函数将分类变量转换成哑变量或指示变量。让我们通过一个简单的例子来看看它是如何工作的。我们首先定义一个由公司员工属性组成的假设数据集,并使用它来预测员工的工资。
我们的数据集看起来像这样:
df

员工数据集|作者图片
我们可以看到在上面的数据集中有两个分类列,即Gender和EducationField。让我们使用pandas.get_dummies()将它们编码成数字量,它返回一个虚拟编码的数据帧。
pd.get_dummies(df)

作者图片
列Gender被转换成两列— Gender_Female和Gender_Male,它们的值要么是 0,要么是 1。例如,Gender_Female在有关员工是女性的地方有一个value = 1,在不是女性的地方有一个value = 0。对于列Gender_Male也是如此。

虚拟编码性别变量|作者图片
类似地,列EducationField也根据教育领域分成三个不同的列。事情到现在都很明显了。然而,当我们使用这个编码数据集来训练模型时,问题就开始了。
虚拟变量陷阱
假设我们想要使用给定的数据来建立一个机器学习模型,该模型可以预测员工的月薪。这是一个回归问题的经典例子,其中目标变量是MonthlyIncome.。如果我们使用pandas.get_dummies()对分类变量进行编码,可能会出现以下问题:
1️⃣.多重共线性问题

通过维恩图描绘多重共线性|图片由作者提供
注:上图非常直观的解释了多重共线性。感谢凯伦·格雷斯-马丁以如此清晰的方式解释了这个概念。请参考下面的链接转到文章。
https://www.theanalysisfactor.com/multicollinearity-explained-visually/
回归模型的假设之一是观测值必须相互独立。多重共线性发生在回归模型中的独立变量相关时。那么为什么相关性是一个问题呢?为了帮助你详细理解这个概念,避免重复发明轮子,我会给你看一篇由吉姆·弗罗斯特写的伟大作品,他非常简洁地解释了这个概念。以下段落来自同一篇文章。
**回归分析的一个关键目标是隔离每个自变量和因变量之间的关系。对回归系数的解释是,当你保持所有其他自变量不变时,它代表自变量每变化 1 个单位,因变量的均值变化。**
如果所有变量都是相关的,那么模型将很难判断某个特定变量对目标的影响有多大,因为所有变量都是相关的。在这种情况下,回归模型的系数将不会传达正确的信息。
pandas.get_dummies 的多重共线性问题
考虑上面的雇员例子。让我们从数据集中分离出Gender列,并对其进行编码。

如果我们仔细观察,Gender_Female和Gender_Male列是多共线的。这是因为一列中的值1自动暗示另一列中的值0。这个问题被称为虚拟变量陷阱,可以表示为:
Gender_Female = 1 - Gender_Male
解决方案:删除第一列
多重共线性是不可取的,每次我们用pandas.get_dummies(),编码变量都会遇到这个问题。解决这个问题的一种方法是删除其中一个生成的列。因此,我们可以删除Gender_Female或Gender_Male ,而不会潜在地丢失任何信息。幸运的是,pandas.get_dummies()有一个名为drop_first的参数,当设置为True时,它就能做到这一点。
pd.get_dummies(df, drop_first=True)

作者图片
我们已经解决了多重共线性,但是当我们使用 dummy_encoding 时,还存在另一个问题,我们将在下一节中讨论这个问题。
2️⃣.训练集和测试集中的列不匹配
为了用给定的雇员数据训练模型,我们首先将数据集分成训练集和测试集,将测试集放在一边,这样我们的模型就不会看到它。
from sklearn.model_selection import train_test_splitX = df.drop('MonthlyIncome', axis=1)
y = df['MonthlyIncome']X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.2, random_state=1)
下一步是对训练集和测试集中的分类变量进行编码。
- 编码训练集
pd.get_dummies(X_train)

正如所料,Gender和EducationField属性都被编码成数字量。现在,我们将对测试数据集应用相同的过程。
- 编码测试集
pd.get_dummies(X_test)

等等!定型集和测试集中存在列不匹配。这意味着训练集中的列数不等于测试集中的列数,这将在建模过程中引发错误。
**解决方案 1: Handle unknown by using .reindex and .fillna()**
解决这种类别不匹配的一种方法是将对训练集进行哑编码后获得的列保存在一个列表中。然后,照常对测试集进行编码,并使用编码的训练集的列来对齐两个数据集。让我们通过代码来理解它:
# Dummy encoding Training set
X_train_encoded = pd.get_dummies(X_train)# Saving the columns in a list
cols = X_train_encoded.columns.tolist()# Viewing the first three rows of the encoded dataframe
X_train_encoded[:3]

作者图片
现在,我们将对测试集进行编码,然后重新排列训练和测试列,并用零填充所有缺失的值。
X_test_encoded = pd.get_dummies(X_test)
X_test_encoded = X_test_encoded.reindex(columns=cols).fillna(0)
X_test_encoded

作者图片
如您所见,现在两个数据集拥有相同数量的列,
**解决方案 2:使用**One Hot Encoding****
另一个更好的解决方案是使用[sklearn.preprocessing](https://scikit-learn.org/stable/modules/classes.html#module-sklearn.preprocessing).OneHotEncoder().。此外,我们可以使用handle_unknown="ignore"来解决由于稀有类别而导致的潜在问题。
#One hot encoding the categorical columns in training setfrom sklearn.preprocessing import OneHotEncoder
ohe = OneHotEncoder(sparse=False, handle_unknown='ignore')
train_enc = ohe.fit_transform(X_train[['Gender','EducationField']])#Converting back to a dataframe
pd.DataFrame(train_enc, columns=ohe.get_feature_names())[:3]

作者图片
# Transforming the test settest_enc = ohe.fit_transform(X_test[['Gender','EducationField']])#Converting back to a dataframe
pd.DataFrame(test_enc,columns=ohe.get_feature_names())

作者图片
注意,你也可以通过设置参数drop=’if_binary’来删除 OnehotEncoder 中每个特性的一个类别。更多细节请参考文档。
结论和要点
这篇文章研究了如何使用 pandas 对分类变量进行编码,以及与之相关的常见注意事项。我们还详细研究了避免这些陷阱的可行解决方案。我希望这篇文章能让你直观地了解什么是哑变量陷阱,以及如何避免它。此外,本文中引用的两篇文章是很好的参考,尤其是如果您想更深入地研究与多重共线性相关的问题。我强烈推荐他们。
👉有兴趣看我写的其他文章。这个 回购 包含了我分类写的所有文章。
超越准确性:NLP 模型的行为测试
原文:https://towardsdatascience.com/beyond-accuracy-behavioral-testing-of-nlp-models-with-checklist-48544db3fef1?source=collection_archive---------20-----------------------
ACL 2020 最佳论文奖(研究论文演练)

作者图片
在自然语言处理 (NLP)中,我们经常将某种准确性度量视为我们模型正确性的证明。但是很明显,这种自动化的客观评估最终导致高估了模型的性能,主要是因为测试分割的代表性不足和低容量。另一方面,对于如此大量的训练数据,模型很可能学习某些特定于任务的快捷方式以在测试数据上表现良好,而不是学习一些可能对当前任务有用的低级基本语言属性。
考虑到这些普遍存在的挑战,研究人员引入了 清单 的概念。清单是一种新的评估方法,用于 NLP 模型的综合功能测试,其中我们有一个由语言 能力组成的矩阵,例如命名实体转换、否定、对错别字的鲁棒性等,以及测试类型,如最小功能测试 (MFT)、方向期望 (DIR)和不变性测试作者还发布了 CheckList 作为工具,使用户能够使用精心制作的模板、 词汇库、、扰动、上下文感知建议使用 、罗伯塔 等生成大量测试用例。现在让我们详细了解一下测试类型—
- 最小功能测试(MFT) 在其能力范围内,在一些精选的任务特定测试样本上检查模型的行为。它的灵感来自软件工程的单元测试。例如检查消极情绪的否定——
句子: 饭菜不差。(消极或积极情绪)
理想情况下,在这种情况下,模型应该能够预测和理解否定,并输出积极或中性的情绪,如果没有,那么测试用例将被视为模型的失败。
2.**方向期望(DIR)** 查看具有相同意图的当前句子的任何扩展是否改变了模型预测一定的量。比如说—
原句 :我不喜欢这种食物。(-ve 感悟)
修饰句 :我不喜欢这种食物。 真是无味 。(-ve 感悟)
理想情况下,在这种情况下,模型不应该在相反的方向上显著改变情绪。如果超过了用户定义的阈值,那么测试用例将被视为模型失败。
3.**不变性测试(INV)** 通过扰动原始句子来查看类别标签是否改变。扰动可以是 NER 级别的(比如改变句子中的位置),用同义词替换单词,引入一个字符的输入错误,等等。比如说—
原句 :我要你们成为第一个飞往加拿大的人。(预测 A 类)
修饰句 :我要你们第一个飞到Cuba*(预测 A 类)*
理想情况下,在这种情况下,模型不应该改变类标签。如果是这样,那么测试用例将被视为模型的失败。
评估 SOTA 模型
作者们继续前进,为情感分析、机器理解和 Quora 问题对的任务评估了一些最先进的(SOTA)研究和商业模型。他们选择了微软,谷歌和亚马逊的付费 NLP APIs 作为商业模型的选择,选择了 BERT,RoBERTa 作为研究模型的选择。来自论文的下图显示了情感分类任务的各种语言能力测试的上述测试类型的结果。

(修改)图 1 来自来源
让我们来理解上表中用红色圈出的例子—
作者测试了所有 5 个模型的健壮性属性,方法是在推文中添加随机 URL、用户名,甚至诱导一个字符交换作为输入错误。因此,理想的预期是情绪不会改变*(不变性测试),*,但是他们发现商业模型的失败率为 5%–25%,研究模型的**失败率为 3%–11%**这是非常令人震惊的,因为这些是非常简单的鲁棒性检查,没有涉及任何显式的复杂性,然而模型却混淆了。
作者测试了所有 5 个模型的 NER 属性,方法是用其他位置替换实际位置,变换人名等。理想的预期是,这不应该影响预测,并让模型将其预测切换到完全不同的类别。但令人惊讶的是,他们发现一些模型的失败率高达 20% ,这意味着它们只有 80%的准确率,如果你在文本中改变一个人的名字,预测就会被推翻。这暗示了训练这些模型的训练数据具有一些常见姓名的主要出现,并且模型已经以某种方式学习了姓名和情感的一些关联,而不是忽略这一点并且仅仅关注触发情感的语言属性和结构。像 RoBERTa 这样的研究模型,即使不完美,也有不错的表现。
作者通过否定给定文本中的否定词、中性词和肯定词来测试所有 5 个模型的否定属性。结果确实令人惊讶,因为他们发现对于某些模板,有些模型****100%失败,然而,几乎所有的模型都有超过 30% 的失败率。
另外,我想请你花至少 2 分钟时间看看上面图片的其他结果。我敢肯定,你会震惊的!!
因此,很明显,如果你已经注意到作者选择的转换类型是非常直接和简单的,没有任何进一步的困难分层,然而付费模型显示了它们的显著局限性。话虽如此,现在看起来是时候使用这样的框架和常规的测试分割测试来更彻底地测试我们的 ML 模型了。
注释工具
为了便于大规模生成测试用例,作者开源了清单,启用了模板化功能和屏蔽语言模型建议(如 BERT 和 RoBERTa ),以获得任何屏蔽词的扰动建议和通用扰动,如字符交换(模拟错别字)、缩写、名称和位置变化(用于 NER 测试)等。一个样本模板如下所示—
Sample _ Template = " I the "
我不喜欢这食物。
我不喜欢这道菜。
Sample_Test_3 =我不喜欢这项服务。
等等…
他们围绕这一点设计了一个非常简单易用的用户界面,以方便非技术人员也能大规模地生成示例。请务必检查其他功能,网址为—
https://github.com/marcotcr/checklist/blob/master/notebooks/tutorials/visual_suggest.gif
P.S. 我也正在为这篇论文做一个多语种字幕的视频讲解。一旦发布,我会在评论中更新!同时,我在我的频道上已经解释了很多论文,你可以在— 查看
https://www.youtube.com/c/TechVizTheDataScienceGuy
更新—2020 年 8 月 2 日
视频讲解者
清单
你也可以查看我写的其他研究论文的解释
用于摘要文本摘要的 BERT
使用 ML 从文本中自动提取上位词关系
如果你仍然对某件事感到困惑,一定要朗读这篇文章。也向作者们说声“ Hi ”,感谢他们的贡献。
**论文题目:**超越准确性:NLP 模型的行为测试与清单
**论文链接:**https://www.aclweb.org/anthology/2020.acl-main.442.pdf
**论文代号:**https://github.com/marcotcr/checklist
作者: 宏里贝罗,童双吴,卡洛斯·盖斯特林,萨梅尔·辛格
组织:微软研究院,华盛顿大学,加州大学欧文分校
我希望这篇简短的阅读值得你花时间。如果你喜欢这段内容,一定要在 拍拍 让大家知道。
谢谢!
超越异常检测
原文:https://towardsdatascience.com/beyond-anomaly-detection-2000e77dd383?source=collection_archive---------27-----------------------
异常检测!=威胁检测。

来自 Pixabay 的奇莫诺
任何熟悉安全操作中威胁检测的人都可能听过类似的解释。它总是像这样,“剖析正常行为,然后检测异常。”该过程包括从您环境中的几个不同传感器生成数据,并使用该数据来定义某种基线阈值。然后,您可以根据超出该特定阈值的任何传感器数据生成警报。这一切都有点抽象——让我们更深入一点。
熟悉机器学习的人都会知道监督学习和非监督学习这两个术语。通常人们将无监督学习与异常检测联系在一起,但我们实际上可以使用其中任何一种来检测异常。事实上,我们可以将机器学习的思想应用于人类学习和静态分析。最佳威胁检测通常由静态检测(规则)、机器学习和人类学习的某种组合组成。我们将把无监督学习的重点放在聚类上,将监督学习的重点放在分类上。
**聚类。**当人类和算法执行聚类时,它们会为不同的数据块生成逻辑组。这些组将从数据特征的组合中出现,而不是依赖于任何特定的特征作为标签。换句话说,数据中不应该直接显示“该产品属于 A 组”。分析师或算法会根据该产品与 A 组中其他产品的“接近度”将该产品归入 A 组。在异常检测中,分析师或算法会生成这些组,并且“接近度”的测量值是阈值。如果一个数据项位于这个阈值之外,离集群太“远”,这就是异常。
安全分析师可以根据工作时间生成一个简单的聚类。如果组织有 9-5 个工作时间,我们可以在下午 1 点左右生成一个阈值为+/- 4 小时的集群。任何超出这个时间范围的事情都会产生警报。更现实的集群应该根据服务、交互时长、数据量和其他因素将不同的交互分组到用户和管理员的不同基本活动中。奇怪的活动会落在这些集群之外,分析师可以对它们进行调查。如果他们发现活动是良性的,他们可以将它们添加到一个新的集群组中,或者扩展阈值以消除这些错误警报。
分类。关于数据项的哪些特征是特征还是标签,没有正式的规定。我们可以将数据的任何特征指定为标签,并使用其他特征来预测它。在这种情况下,我们使用数据中的不同字段来预测另一个字段。分析师或算法可以选择哪些字段提供最佳阈值,以便仅警告真正的异常。我们还可以将不同流中的不同数据条目组合成一个单个数据对象,然后使用不同的数据条目进行高保真预测。
例如,如果我们考虑一个 NGINX 日志条目,我们在一个条目中有以下特征:IP 地址、日期、方法、URL、协议、状态、发送的字节、referer 和用户代理。现在,让我们想象一家企业,其中大多数用户在工作日的任何时候都使用/home URL 从浏览器访问 web 服务器。他们的请求使用 GET 方法,响应非常大,因为它提供了整个网页。然而,有些开发人员通过 API 从他们的代码中访问 web 服务器。他们向/api URL 发出 POST 请求,并得到简短的响应。他们通常只在临近工作日开始时提出这些要求。在这种情况下,使用 POST 方法的早期请求、简短响应和无用户代理字符串的组合将强烈预测/api URL。
上述方法将允许您检测异常,我们可以调查这些异常以发现威胁,对吗?这依赖于几个假设:
- 攻击流量比真实流量更加动态。换句话说,您的真实流量将通过聚类和分类保持可预测性,而攻击流量将是不可预测的流量。
- 在您能够生成的所有可用异常检测算法中,您选择的算法将最好地检测攻击。如果您专注于最佳异常检测,您将实现最佳威胁检测。
这些都是很强的假设。这些可能支持最基本的攻击,但高级攻击者正试图使针看起来像干草,这样你就不会看到他们的攻击是异常的。与此同时,大多数环境的变化速度正在迅速加快,因此新的异常流量将会越来越频繁地出现。还有,在不使用实际攻击数据测试这些算法的情况下,如何验证这些假设?即使您想使用异常检测,您也会想看看您的异常检测算法对实际攻击数据的效果如何。然后,使用真实的攻击数据,您可以生成算法,直接将数据对象分类为恶意或良性。您还可以让您的数据对象生成方法匹配不同的攻击生命周期,而不仅仅是做出有根据的猜测。你甚至可以将你的异常检测方法与其他方法结合起来,生成非常逼真的警报。
无论我们是在生成规则,训练分析师,还是使用机器学习,我们都应该有真实的数据,用我们实际上在寻找的东西来标记。在这种情况下,我们应该有良性传感器数据,我们将使用这些数据在异常检测方法中分析正常行为,和我们还应该有相同的传感器数据用于我们想要检测的恶意行为。因此,异常检测是不够的,它本身不会让您检测到巨大的威胁。
超越法典:一个可以训练的代码生成模型
原文:https://towardsdatascience.com/beyond-codex-a-code-generation-model-that-you-can-train-6ac9bdcba07f?source=collection_archive---------9-----------------------
codeT5 模型的概述和实践教程

潘卡杰·帕特尔在 Unsplash 上的照片
随着最近 OpenAI Codex 模型的发布,代码生成正在成为 NLP 世界的一个热门话题,这不仅仅是炒作。如果你看一个 Codex 演示,你会看到这些模型将如何塑造软件编程的未来。然而,从研究人员的角度来看,如果需求超出了通过 API 进行尝试,那么使用法典模型可能是不可实现的,因为预先训练的模型不是公开可用的。从技术上来说,你可以使用发表的论文复制 Codex,但你需要一个大型的 GPU 集群,只有少数人能够访问或负担得起。在我看来,这种限制会减慢研究的速度。想象一下,如果作者不共享预先训练好的权重,我们的 BERT 下游应用会减少多少。希望 Codex 不是唯一的代码生成模型。
这篇文章将概述 codeT5,这是一个编码器-解码器代码生成模型,具有公开可用的预训练检查点,您现在就可以尝试。此外,这篇文章包含了如何使用这个模型的实践教程。
CodeT5 概述
CodeT5 [1],顾名思义,是基于 T5 [2]编解码模型。与其他代码生成模型相比,它使用一种新颖的标识符感知预训练目标,该目标利用代码语义,而不是像对待任何其他自然语言(NL)文本一样对待源代码。该模型在许多编程语言中的代码生成和其他任务(如代码摘要、代码翻译、克隆检测和缺陷检测)中显示了有希望的结果。
作者发布了两个预训练模型:一个 6000 万的小版本和一个 2.2 亿的基础版本。他们还在他们的公共 GCP 桶中发布了他们所有的微调检查点。此外,这两个预先训练好的模型都可以从流行的 huggingface 库中获得。
预培训
依次使用两个不同的目标对 CodeT5 进行预训练。在前 100 个时期中,用识别符感知的去噪目标来优化模型,该目标训练模型以区分识别符(即,变量名、函数名等。)和特定编程语言(PL)关键字(例如,if、while 等。).然后,使用双峰双代物镜优化 50 个时期。最后一个目标旨在改进 NL 描述和代码之间的一致性。
**识别器感知的去噪目标。**seq 2 seq 模型中的去噪目标用去噪函数掩盖输入序列。然后,解码器尝试恢复原始输入。识别符感知的去噪在三个任务之间以相等的概率交替进行:
- *掩蔽跨度预测(MSP)。*这个任务类似于 T5 预训练中使用的任务,除了他们使用整体工作掩蔽来避免掩蔽子令牌(例如
##ing)。此任务提高了模型捕获 PLs 语法信息的能力,从而提高了代码生成性能。 - *标识符标记(IT)。*在这个任务中,训练模型预测令牌是否是代码标识符,迫使模型学习代码语法和数据流。
- *屏蔽标识符预测(MIP)。*所有的标识符(如变量名、函数名等。)都隐藏在这个任务中。此外,相同标识符的所有出现都使用相同的标记令牌(即 MASK0)来屏蔽。该模型被训练成以自回归方式预测由标识符和匹配的标记令牌组成的序列。MIP 旨在提高 PL 语义理解,这有助于缺陷检测任务。
下图显示了同一数据样本的标识符感知去噪目标的每个任务的模型输入和目标的示例。

由 Amine Elhattami 执行的标识符感知去噪预训练任务
**双峰双代。**模型被训练用于双向转换,或者从代码到 NL 描述,或者同时从 NL 描述到代码。这个目的类似于 T5 的区间屏蔽,这里屏蔽的区间是整个 NL 描述标记或代码标记。该目标旨在缩小预培训和微调之间的差距。在预训练中,解码器仅看到离散的屏蔽跨度和标识符,而在微调中,解码器生成完整的 NL 描述或代码。下图显示了同一个数据样本的每个任务的模型输入和目标的示例。

由 Amine Elhattami 进行的双峰双代预训练
标记器
CodeT5 使用特定于代码的标记器,因为默认的 T5 标记器将一些常见的代码标记编码为未知标记。例如,花括号{映射到未知令牌<unk>。
CodeT5 记号赋予器是一个字节对编码(BPE) [3]记号赋予器,其词汇表大小类似于 T5 (32k)加上一些特殊的记号。在预训练期间,该标记化器跳过所有不可打印的字符和出现次数少于三次的标记,这导致标记化序列最多减少 45%。较短的靶序列有两个优点。首先,它加速了训练。第二,它使生成任务变得更容易。
训练前数据集
CodeT5 在公开可用的 CodeSearchNet 数据集[4]上进行预训练,该数据集包含约 200 万个训练样本,由六种 PLs (Javascript、Java、Go、Python、Ruby 和 PHP)中的代码和描述对组成。此外,作者从 BigQuery 收集了 C 和 C#数据集。但是,请注意,C 和 C# dataset 是不向公众发布的。但是,微调模型是可用的。
微调
CodeT5 已经在各种 PLs 中的大量下游任务上进行了微调。下表总结了所有任务。

Amine Elhattami 的下游任务列表
我的想法
在我看来,CodeT5 是一个有趣的模型,因为它可以在同一个预训练模型的多个下游任务中取得良好的结果,特别是在多任务模型中。此外,该模型需要更少的数据进行微调,这意味着训练时间短。例如,java 代码生成数据集只包含 100k 个训练样本。减少数据需求是一个至关重要的方面,因为您可能知道,数据收集是一项耗时的任务。然而,我认为有些地方作者本可以改进:
- 作者声称,与仅编码器和仅解码器模型相比,编码器-解码器模型更优越。然而,如果能与 Codex 模型进行比较就更好了,因为在本文发布时它已经可用了。
- 作者使用 CodeBLEU 作为代码生成任务的评估指标,正如 Codex 论文中所解释的那样,这并不理想。我知道他们选择了这个指标来与当前的结果进行比较。然而,如果能在人类评估数据集[5]上看到结果就更好了,该数据集通过单元测试评估功能正确性。
实践教程
使用预先训练的模型
以下示例显示了如何使用 huggingface 库来使用预训练模型。该模型可以执行任何预训练任务。但是,您将只使用预先训练的模型来进行自己的微调。
预训练模型示例
使用微调模型
要使用经过微调的模型,您必须下载所需的模型二进制文件和正确的模型配置文件。以下脚本下载两者。
下载微调模型
下载完成后,您就可以使用这个模型了。以下示例将预测 python 函数的 docstring。
微调模型示例
微调您的模型
除了预训练和微调的模型,作者还分享了他们的源代码,这意味着你可以微调你的模型。下面的例子训练了 python 代码摘要的微调。更多信息,请查看的知识库。
微调示例
请注意,上面脚本中使用的数据是 code 5[1]作者共享的现有公共数据集(BSD 许可证)的集合。下表描述了每个子数据集的来源。

Amine Elhattami 的子数据集列表
结论
这篇文章概述了 CodeT5 模型,并提供了使用公共检查点和训练模型的例子。也包含了我个人的想法。要了解更多细节,我邀请您阅读 CodeT5 白皮书并查看它们的源代码。我知道 Codex 是一个新手,但是 CodeT5 是目前你可以在任何合理的基础设施上训练的最好的模型(我认为)。
此外,我正在开发一个 VS 代码扩展,它允许您将任何代码生成模型连接到 VS 代码自动完成。所以,敬请期待!
*除特别注明外,所有图片均为作者所有。
在你走之前
在 Twitter 上关注我,我经常在那里发布关于软件开发和机器学习的微博。
参考
[1] CodeT5:用于代码理解和生成的标识符感知的统一预训练编码器-解码器模型。
[2] 用统一的文本到文本转换器探索迁移学习的极限
[3] 具有子词单元的稀有词的神经机器翻译
[4] 评估语义代码搜索状态的 CodeSearchNet 挑战
[5] 人体评估数据集
[6] 将语言映射到编程环境中的代码
[7] CodeXGLUE:用于代码理解和生成的机器学习基准数据集
【8】通过神经机器翻译在野外学习 Bug 修复补丁的实证研究
[9] 设计:通过图形神经网络学习全面的程序语义进行有效的漏洞识别
[10] 用图形神经网络和流增强抽象语法树检测代码克隆
CodeT5 公共 GCP 斗
CodeT5 Github 库
BigQuery Github 活动数据
除了相关系数和均方误差
原文:https://towardsdatascience.com/beyond-correlation-coefficients-and-mean-squared-error-952bd966cedb?source=collection_archive---------26-----------------------
回归模型比较的 MAD 分析——提高您对极限情况的理解。

作者图片
回归模型的性能可以用一个数字来概括——我们可以将模型在验证/测试集上的输出与实际情况进行比较。比较回归模型性能的常规方法有均方误差(MSE) 和相关系数,如 Spearman 秩序相关系数(SROCC) 或 Pearson 线性相关系数(PLCC) 。
在许多情况下,这些就足够了,但是,我们可以做得更好——深入了解模型预测的极限情况。
最大差异(MAD)分析于 2008 年在这篇视觉期刊论文中首次提出。后来在 2020 年进行了改进和扩展,举办了一场 gMAD 比赛。两篇论文都是针对评价图像质量评价方法的问题。其中模型比较受到验证数据的高成本的限制——来自人类观察者的主观分数。MAD 分析的关键思想是对两个竞争模型的预测差异最大的例子进行基准测试。
根据我的经验,最好的解释通常是基于一个例子。这篇文章中的一个例子可以在一本 Jupyter 笔记本中找到,供那些对即插即用感兴趣的人使用。
问题设置
在机器学习中,一切都从数据开始。我们正在解决的回归问题是基于来自 kaggle 的 CalCOFI 数据集(超过 60 年的海洋学数据)的一个很小的子集(不是 i.i.d .也不代表仅用于示例的数据集)。我们对模拟水的盐度和温度之间的关系感兴趣。

自变量和目标变量的散点图。图片作者。
为了模拟这种关系,我们使用了六种回归模型——从一阶多项式到六阶多项式。在这里,我们对最佳模型性能不感兴趣——模型只是用于举例。

每极预测与地面真实目标的散点图。图片作者。
最大差异分析
给定两种回归方法,MAD 过程的假设是任何两个条件之间的距离将更好地反映在更精确的尺度中。
例如,如果两个点根据二阶多项式拟合而接近,根据一阶多项式拟合而远离,并且根据地面实况而接近,则二阶拟合被认为是更好的模型,对于根据二阶多项式拟合而远离并且根据一阶多项式拟合而接近的情况,情况相反。

模型预测差异巨大的点选择示例。由红线连接的点将由 MAD 分析选取。图片作者。
实际例子
让我们把手弄脏,投入到 MAD 分析的实践中去。
在我们的示例中,对于每对回归方法,我们选择 100 对条件,这些条件根据测试方法具有不同的质量,根据基准方法具有相似的质量。因此,对于两个回归量 Rt 和 Rb,我们选择以下条件 oi 和 oj:

类似的 100 个条件,反之亦然。我们需要为基础数据中被认为相似和不同的东西建立规则。这总是有点棘手,理想情况下应该包括模拟温度分布,并选择一个统计上合理的阈值。然而,为了举例说明,如果两次测量之间的绝对温度差小于 1 度,我们假设这两次测量具有相同的温度,否则温度是不同的。
在选择了分数预测在两种方法中显著不同的点之后,我们可以计算统计数据。任何合理的措施都会奏效。
这里,我们通过测量一种方法将一对图像分类为相同或不同的能力来量化该方法的性能。和报告精度——被测试的质量度量正确分级并识别为不同的对的数量除以所选对的总数。行中的高值表示相应行中的度量对相应列中的度量的攻击成功率很高。

矩阵的每一项都是来自相应行的测试度量与来自相应列的基准质量度量配对时的精度。模特是按平均分排序的。图片作者。
请注意,根据 PLCC 和 RMSE 的说法,四阶、五阶和六阶多项式的性能相当。MAD 分析讲述了一个不同的故事,与其他模型相比,四阶拟合可以更好地区分配对。有趣的是,三阶拟合也比六阶多项式表现更好。内在 MAD 分析可以显示过度拟合的迹象。


如何用于主动学习
对于许多应用来说,我们用来比较算法性能的基本事实可能很难获得或者很难获得。想象一下,在上面的例子中,我们有机会获得 100 个额外的测量值。我们将对一组已知独立变量(温度)的五次多项式与六次多项式的预测值进行散点图绘制,然后选择他们最不一致的水盐度测量值进行采样。
该设置实现了两个目的:
- 我们得到了关于哪种方法区分得更好的信息
- 我们得到了一个新的度量标准来完善这个模型
总结和超越
实践和研究经验告诉我,没有单一的方法可以告诉你你的模型有多好。总会有一个指标支持你的解决方案,而另一个则反对。
MAD 分析是理解模型性能的另一种方法。MAD 不仅仅是规模比较的程序。除了比较模型之外,它还可以适用于在模型最不一致的情况下顺序获取地面实况数据的主动学习。虽然它在一维输出中的应用相当简单,但是将它扩展到更高的维度可能具有挑战性。
在错误分析中,有更多的技术是有用的,尤其是在模型投入生产之前!我强烈推荐这篇来自 Neptune.ai 的文章,它介绍了探索数据的更多方法。
如果你喜欢这篇文章,请与朋友分享!要阅读更多关于机器学习和图像处理的信息,请点击订阅!
我错过了什么吗?不要犹豫,直接给我留言、评论或发消息吧!
超越 CTRL+F
原文:https://towardsdatascience.com/beyond-ctrl-f-44f4bec892e9?source=collection_archive---------42-----------------------
使用单词嵌入在文档中实现语义搜索

雷切尔·福雷兹在 Unsplash 上的照片
介绍
我们都习惯于这样的情况:我们需要在文档中找到一段文本,但却不太记得它到底是什么。我们可以回忆起一些重要的单词或文章的整体意思,但大多数文本处理器(从记事本到 Microsoft Word)只允许我们进行词汇搜索(即在文本中搜索与我们提供的输入完全匹配的内容)。确实没有别的办法:找到我们要找的东西的唯一方法是点击CTRL+F(或者一些等价的组合,这取决于您的系统)来搜索一个单词或一个小表达式,并浏览一个潜在的大结果列表,直到我们找到与我们要找的东西相对应的那个。
当我们不确定目标结果中包含的某些确切单词时,这种做法会更加不方便。我们可能需要搜索不同同义词和不同词序的组合,直到找到匹配。
我最近一直在思考一个想法,那就是根据文本的意思而不是确切的单词来比较摘录。显而易见,不同的文本段落可以表达非常相似的意思,同时使用不同的词语、表达方式和词语安排。还有一种情况是,有时一段文字被修改了,但人类读者可以很容易地识别出它是从哪里来的。然而,从算法上确定它们之间的等价性绝非易事。
在本文中,我们将应用一种结合了 单词嵌入 和 词性过滤 的技术来实现文档内的语义搜索。为了说明这种技术的工作原理以及我们可以获得的结果,我们将尝试在简·奥斯汀的《傲慢与偏见》中搜索几段在书中不完全匹配的摘录。在第一个应用程序中,我们将从书中的第一个句子开始,搜索逐渐改变的版本,直到短语减少到最少。然后,我们将从巴西葡萄牙语翻译中提取一些段落,通过简单地调用 Google Translate 将它们转换成英语,并尝试在原文中找到这些段落。
在本文中,我不会深入讨论 Python 实现的细节。如果你感兴趣,你可以在 GitHub 上查看详细的笔记本这里。你也可以通过这个链接在 Google Colab 上打开它,这将允许你使用一个简单的表格自己运行一些关于古腾堡计划公共领域图书目录中任何作品的例子。
该方法
下面是我们在一本书里查找一段意思相同的段落的一系列步骤:
- 使用 单词嵌入 将书中的每个单词和请求的句子转换为密集向量表示(在这种情况下,我们将使用手套嵌入)。这种表示捕获了 300 维向量空间中单词的含义和。如果你对“单词嵌入”这个术语的含义没有信心,我强烈建议你花几分钟时间玩一下 TensorFlow 嵌入投影仪。真的很好玩!
- 将 词性 (如名词、动词、介词等)掩码应用于书籍和请求的句子:不属于任意定义的相关词性列表的每个单词都将嵌入转换为空向量。我见过的大多数 NLP 应用程序更喜欢从文本中删除一列停用词(经常出现的词,可以从文本中删除而不会失去太多意义)。我个人倾向于使用一个允许的词类列表,这让我可以更好地控制哪些词类将被保留或屏蔽。对于这个应用程序,我基本上保留了所有的名词、形容词和动词。
- 将 词袋 方法应用于句子嵌入:对句子中每个词的嵌入进行平均,并获得单个向量来表示其语义内容。用这种方法,文章意思的表达就是每个单词意思的平均值。
- 使用一个滑动窗口,将单词袋句子嵌入和词性过滤器应用于整本书,滑动窗口的长度为所请求的句子加上一个选定的边距(考虑到我们可能会提供所需摘录的一个非常短的版本),并对窗口内的单词嵌入进行平均。
- 计算请求句子嵌入和滑动窗口嵌入之间的 余弦距离 。
- 选择书中距离所要求的句子最近的位置。
总之,我们从书中找到与输入内容意思相似的段落的方法非常简单:我们将采用一个固定字数的滑动窗口,删除不相关的单词,平均出单个单词的意思,并满足于更接近输入内容的窗口。
搜索具有相似含义的文本
在这一系列的例子中,我们将从书中的第一句话开始,并使用我们提出的策略来搜索日益修改(屠宰,真的!)的版本。
这是我们要寻找的原始句子:
一条举世公认的真理是,一个富有的单身男人一定想要一个妻子。
首先,让我们尝试寻找完全相同的句子,以确保代码正常工作:

搜索精确匹配
毫无疑问,搜索成功了。毕竟,我们在寻找完全相同的句子。让我们把它变得更难一点,并改变 synonims 的一些单词:

搜索修改的句子
太好了!我们确实找到了对应的原句。但是,我们可以看到结果中有一点错位:缺少前 4 个单词,在末尾添加了 3 个额外的单词(或 4 个标记,考虑到点号)。这是反应的常见假象。因为我们使用的是滑动窗口,所以句子之间有很大的重叠,结果通常会靠右或靠左的几个单词。
现在,让我们超越同义词,更实质性地修改句子,包括一些简化。因为我们的输入会比我们预期的输出短一些,所以我们将以 10 的边距进行搜索(滑动窗口将比提供的输入长 10 个单词)。实际上,当使用由这种方法驱动的搜索引擎时,用户可能不得不试验这个参数。

搜索简单句
我们又有比赛了!
现在,让我们尝试一个极端的例子,只提供句子的要点作为算法的摘录。我们将再次使用 10 个单词的空白。

搜索最小句子
进展不太顺利。该算法找到了一个与我们在书中想要的原始句子不对应的匹配。
但是,我们可以循环浏览一些最热门的结果,看看是否会弹出实际的句子:

浏览多个结果
仔细查看前 10 个结果,我们看到我们正在寻找的原始摘录对应于条目 5 和 6。结果之间有很多重叠,所以在这个选择中实际上只有 4 个不同的部分,其中我们想要的结果是第三个。
编写一个识别这些重叠并将它们合并成单一结果的函数是相当简单的。在这种情况下,我们想要的摘录将是列表中的第三个结果。
根据译文寻找原文
我们现在将转移到一个略有不同的应用程序,在这个应用程序中,我们将查找与巴西葡萄牙语翻译相对应的摘录,而不是搜索从原著中手动修改的句子。
对于这些摘录,我们将使用googletrans库自动将它们翻译回英语。然后,我们将使用我们的搜索例程,尝试在原书中找到相应的摘录。
你会注意到译文与原文大相径庭。虽然它肯定有相同的意思,但单词的选择和顺序是非常不同的。
我们从几个单句开始,从书中的第一句开始,然后再尝试几个单句:

单句
现在,稍微长一点的:

较长的句子
显然,翻译回英语的文本具有相同的含义,但措辞明显不同:

多个句子
较短的段落更难准确找到,但我们仍然能够正确识别它们:

简短对话
当我们提供更长的句子作为输入时,该方法更加健壮,因为找到另一个部分匹配的情况要少得多:

整段
在所有这些例子中,该方法能够从原始文本中识别出正确的摘录(在左边或右边给出或取出几个单词),即使翻译与原始文本非常不同。
结论
本文中提出的方法在搜索文档中与给定句子的意思相对应的摘录方面表现得非常好。将单词翻译成有意义的向量表示的核心和灵魂是由 GloVe word embeddings 提供的,大多数 NLP 工具都是从nltk包中使用的。
我们将这种技术应用于一本书中某个段落的严重修改/简化版本的输入,以及一本书翻译的摘录,都得到了相似的正面结果。
不可否认,在给出的结果中有一些精选,尤其是在选择margin参数时。在实际应用中,用户可能需要为该参数尝试几个不同的值,或者滚动候选结果的简短列表。然而,没有一个比当前的CTRL+F程序更复杂,我们都不得不比我们想要的更频繁地执行。
通过一些小的修改,如合并重叠的结果和提高正确识别结果中相应段落的开始和结束的能力,该技术可以很容易地应用于搜索大型文档中的内容,这在目前是一项低效和耗时的任务。
如果您想知道如何选择通过结合单词嵌入和单词包方法来表示句子,而不是直接使用 transformers 来表示句子嵌入,请知道我的初衷正是如此。然而,当我使用单词嵌入的方法来获得基线结果时,我被结果的健壮性惊呆了,所以我决定保持简单并像这样呈现它们。
进一步的工作
在这一分析的下一次迭代中,我确实打算调查使用适当的句子嵌入会如何影响结果。
我相信这种方法可以作为一些文本处理程序的附件或作为 web 服务来实现。如果我有时间实现其中的任何一个,我会在这里发布链接!
我还认为这可以应用于监督学习的合成数据集的生成:基于翻译的书籍,它可以用于生成成千上万个具有等价含义的段落示例。
我们连线吧!
如果你觉得这篇文章很有趣,并且想要联系,请在 LinkedIn 上给我留言!你也可以看看我在 Medium 或Fabio-a-Oliveira . github . io上的一些作品。
超越线性量子关系
原文:https://towardsdatascience.com/beyond-linear-quantum-relations-e8f64bf5ab07?source=collection_archive---------29-----------------------
使用量子正态分布的经验教训
量子机器学习要不要入门?看看 动手量子机器学习用 Python 。
我想我卷入了一些事情。恐怕我现在也把你卷进来了。它始于一个无害的量子正态分布。我想如果我们用量子位来模拟高斯正态分布会很酷。
真的是。
用 Qiskit 创建正态分布是小菜一碟,因为 Qiskit 为此提供了一个现成的量子电路,如下面的清单所示。

作者图片
通常,这种类型的分布描述了一个群体的特征。我在最后几篇文章中使用的例子是一个人的身高。大多数人的身高接近平均水平。但是,一个人的身高离平均值越远,就越不可能看到这样的人。例如,你很少看到身高超过 2.1 米(6.9 英尺)的人,但你经常看到身高在 1.8 米(5.9 英尺)左右的人。
正态分布本身很好,但还没用。将这个值与一个因变量联系起来会很有趣,比如这个人是否需要闪开。
我不知道我在做什么。
我从简单开始。
我翻转了代表因变量(不属于正态分布的那个)的量子位,只有当我们将其他量子位中的一个测量为 1 时。
这种天真的方法奏效了,并产生了一些好的结果。

作者图片
但这意味着什么呢?一个状态的量子位越多是 1(而不是 0),闪避的概率就越高?这意味着个子小的人(数值为 011=3)比个子高的人(数值为 100=4)更容易闪避。
所以,我建立了一个人的身高和闪避需求之间的线性关系。我展示了一种比通过非门选择每个状态并逐个模拟效果更好的方法。
我们可以利用量子位的顺序,以及量子位的位置越高,它的效果就越高的事实。
我费力地编写了下面的代码。
首先,我们旋转三个量子位元中的每一个。第二,我们需要考虑一个问题,那就是我们不能简单地将量子位元所代表的机率相加。这对于最多由三个量子位组成的正态分布是可管理的。
所以,经过大量的反复试验,我想出了这个具体例子的一个概括,它适用于任何数量的量子位和任何斜率。
它工作得很好,并且产生了与从属伯努利变量的线性关系,即使对于如下所示的六量子位正态分布也是如此。

作者图片
所以,我坐在椅背上,想:“如果闪避的需要并不线性地依赖于人的身高呢?如果这个关系是二次的呢?如果这种关系可以用一个任意函数来描述呢?”
我花了将近一周的时间来编写产生线性依赖关系的函数。所以仅仅十行代码就完成了一周的工作。但是当然,我不允许自己不尝试创建这样一个函数。
于是,我开始思考一个二次关系。
这一次,我很幸运。我只花了四个小时就想出了如何修改我的代码来产生这个美丽的关系。

作者图片
四个小时听起来还不错。嗯,我也是这么想的。但是后来,我又看了看。变化是三个小字。
这是二次函数。
变化是在val = val + sign * prob_to_angle(step*(2**sum(2**q for q in part)))行增加了2**
值得称赞的是,我不得不提到这四个小时的结果超出了我的预期。函数允许我们用公式表达任何可能的关系。
例如,下图所示的 sigmoid 函数怎么样?

作者图片
只需用这条线代替上面提到的线(对于四量子位正态分布):
val = val + sign * prob_to_angle(step*(5/(1+e**(0.8*(8-sum(2**q for q in part))))))
无意中,我创建了一个函数,它处理多个量子位如何形成一个变量。它抽象了单个量子位的处理,并提供了一个编程接口来插入我们想要的任何关系函数。
结论
这篇文章简要总结了过去几周关于如何对不同的发行版建模以及如何使用它们的文章。在量子计算中,我们经常使用伯努利分布,因为它们自然地符合量子位的概率观点。
但是在数据科学中,我们通常使用各种分布,比如正态分布。此外,我们不仅希望用这样的分布来表示我们的数据,而且我们还使用它们来模拟两个变量之间的关系。
因此,这篇文章探讨了如何使用我们已经开发的代码来建模这样的关系。
在我的下一篇文章中,我们将深入探讨这个函数。
量子机器学习要不要入门?看看 动手用 Python 学习量子机器 。

在这里免费获得前三章。
超越 ML Ops:业务自动化的治理
原文:https://towardsdatascience.com/beyond-ml-ops-governance-for-enterprise-decisioning-6efc69622e4e?source=collection_archive---------44-----------------------
如何用商业政策和 IT 系统操作机器学习
对于企业应用和业务自动化,机器学习(ML)很少孤立使用。部署的 ML 模型几乎总是被一个“策略层”或一组业务规则所包围,以管理它如何被调用以及如何解释结果。有关为什么需要这些规则的详细信息,请参见上一篇文章。
结果,我们剩下三个很大程度上独立的生命周期,每个周期出于不同的原因产生新的版本:

三个独立的生命周期需要协调
当我们有新的数据进行训练时,当数据科学家改进他们的模型或应用新的算法时,新的 ML 模型就会被创建。同时,业务分析师细化业务策略,管理新产品的引入或营销推广。在 IT 方面,当引入新系统、应用新技术或开发新的应用程序版本时,就会发生升级。
正如所料,由于数据科学、业务和 IT 是独立的部门和独立的角色,我们的行业已经达成了很大程度上独立的治理解决方案:
- 数据科学:MLOps 专注于 ML 模型的治理,包括再培训、版本控制和对漂移和公平性的监控。
- 业务:数字决策,或决策管理——或自动化平台忙于业务规则、工作流程或其他形式的业务政策的版本化。
- IT: CI/CD 和数据治理分别专注于支持应用开发和数据治理。
实际上,我们现在有三个半独立的生命周期需要协调。我们可以允许它们自主旋转,使用各自的“最新和最好的”,或者我们可以将它们锁定在一起,强制进行某种“全局版本控制”。
您应该选择哪一个取决于上下文,这是我们将在本文中探讨的。我们将使用三个经典的 ML 用例来使其更加具体:
- 客户流失—管理零售业或电信业的客户保持率
- 产品推荐——根据购买倾向对产品进行排名
- 贷款风险评分——评估贷款承销的违约风险
“一次完成”:端到端升级
作为第一个示例,我们将探讨一个需要跨以下方面进行协调的案例:

假设我们预测了客户流失风险——客户取消产品订购的可能性——并且该预测目前使用的是一个 ML 模型,该模型针对客户细分、产品订购、时间客户和月度使用进行了培训。
这四项数据记录了客户的类型、他们订阅了多少产品以及他们使用了多少产品。但是,为了记录客户最近主动决定继续与我们合作的情况,我们还可以包括一个新字段,比如说, TimeOfLastSubscription。
添加新的数据字段会引发全面的变化:
- ML 训练需要从某个操作数据存储(由某个 IT 系统提供)中找到并提取新的数据字段。当被调用时,重新训练的 ML 模型现在除了原始的四个参数之外还需要新的 TimeOfLastSubscription 字段。
- 在业务方面,当请求基于 ML 的预测时,我们现在需要提供新的字段。此外,由于我们的预测现在更好了,我们可能能够删除现有的政策规则(例如,“如果客户在不到 3 个月前订购了产品,则永远不要提供保留优惠”)。
- 连锁反应持续到 IT 系统中,现在当请求保留提议决策时,IT 系统也需要提供 TimeOfLastSubscription 。负责跟踪订阅的 IT 系统也需要将这些数据提供给 ML 培训,从而形成闭环。
总之,当您向整个循环添加数据时,通常需要跨数据科学、业务和 IT 部门以协调的方式进行所有更改。就当这是“重大升级”吧。
“ML+规则”:预测与政策协同升级
作为第二个例子,我们将看一个案例,ML 和策略版本需要协调,但 IT 系统不需要。

考虑一个基本的产品推荐系统,其中我们使用 ML 来提供“购买倾向”预测。对于特定的客户和产品对,这可以预测客户购买产品的可能性。这种预测使我们能够创建一个排序的产品列表,以便向每个客户推广。围绕这一预测,我们通常有一套规则来过滤客户不符合条件的产品、客户所在地区没有的产品或客户已经拥有的产品。
现在考虑在我们的产品目录中引入一种新产品。最初,我们拥有该产品的客户非常少,因此 ML 模型不太可能准确地推荐它。结果是,我们没有向足够多的客户或错误的客户推荐它,因此新产品的采用速度很慢。
这个“先有鸡还是先有蛋”的问题需要通过积极的干预来解决,例如通过推翻基于 ML 的预测来推荐新产品并引导采用。在这种方法中,我们添加了一个规则,该规则“窃取”与新产品目标受众相似的旧产品的一定比例的推荐,并将这些推荐重定向到新产品。随着时间的推移,随着 ML 模型赶上并开始足够频繁地推荐新产品,这种重定向规则可以被逐步淘汰。
从实际治理的角度来看,这需要我们协调到新 ML 模型的升级和新版本的业务策略(包括重定向规则)。
这个用例是一个一般情况的例子,其中新的或重新训练的 ML 模型需要逐渐引入到操作系统中。当预测(还)不可靠时——不管是什么原因——有一段时间我们会忽略或调整预测以达到期望的业务结果。
“使用最新”:独立的 ML 升级
在许多情况下,来自 ML 模型的预测发展得比前两个例子慢得多。在这些稳定时期,在中断之间,我们可以频繁地自动重新训练和升级 ML 模型,而不需要与政策规则协调或审查 IT 系统。

例如,考虑贷款批准场景中的风险分数。ML 模型用于评估客户拖欠贷款的风险,给出客户的信息和历史,结合所申请贷款的规模和类型。该风险模型可以频繁地重新训练,以使评分更加精确,但是调用该模型所需的参数保持不变,并且返回的预测只会随着时间的推移而逐渐变化。
在这些情况下,当需要预测时,我们总是可以调用最新的 ML 模型版本,并且不需要对策略规则进行调整。然而,这要求用于重新训练模型的流水线是健壮的,并且能够检测数据错误,例如,并且监控 ML 模型随时间的漂移。
此外,即使有这些安全措施,谨慎的业务团队仍然会每月或每季度执行一次业务模拟——跨政策规则和预测——以确保生成的贷款决策提供预期的业务成果,并符合有关公平性等的法规。
总结
将机器学习应用于业务自动化并不困难,因为需要复杂的 ML 技术。它通常主要基于结构化数据,而回归或决策树等“经典”ML 方法通常足以对业务交易进行评分、风险评估和分类。
棘手的是业务自动化的“操作”方面(大规模决策)以及不断变化的业务目标和政策规则。改进基于最大似然的预测——当政策改变时——需要基于用例及业务环境而变化的方法。
在本文中,我们看了三个场景:
- 跨数据科学、业务和 IT 的端到端发布
- 数据科学和商业版本的协调
- 独立 ML 再培训
Greger 在 IBM 工作,常驻法国。以上文章为个人观点,不一定代表 IBM 的立场、策略或观点。
超越监控:可观察性的兴起
意见
现代数据和机器学习系统需要监控和可观察性。原因如下。

图片由作者提供。
重复的数据集或陈旧的模型可能会导致意想不到的(但严重的)后果,单靠数据监控是无法捕捉或预防的。解决办法?可观察性。
巴尔摩西蒙特卡洛 和 阿帕纳迪纳卡兰【CPO】阿里泽艾 的联合创始人,讨论它与传统监测有何不同,以及为什么它对于构建更值得信赖和可靠的数据产品是必要的。
垃圾进,垃圾出。这是数据和 ML 团队中的一个常见说法,有充分的理由-但在 2021 年,它不再是足够的。
数据(及其支持的模型)可能会在管道中的任何一点中断,仅仅在接收时考虑数据质量问题是不够的。类似地,当您部署 ML 模型时,可能会出现无数在测试或验证期间没有发现的问题,不仅仅是数据本身。
当你不知道你的环境中发生了什么,更不用说它是如何发生的,它会损害你的分析和实验的完整性,更不用说你的利益相关者的信任。
对于企业来说,这可能意味着收入损失、资源浪费和不明智的决策。在现实世界的应用中,由坏数据驱动的 ML 模型的后果可能更加严重。例如,2020 年,底特律的一名黑人在被面部识别软件错误识别后被错误逮捕并入狱,可能是因为偏见问题,其中包括以白人和男性为主的训练数据集。
不可否认,ML 中的坏数据问题非常普遍。由于种族主义、性别歧视和攻击性的标签,麻省理工学院最近撤下了他们全部 8000 万个微型图像数据集,在在线艺术项目 ImageNet Roulette 暴露出类似问题后,庞大的 T2 ImageNet 图书馆删除了 60 多万张图像。这些数据集多年来一直被用于训练 ML 模型——有严重缺陷的标签等等。
数据质量问题很常见,因为它们很难解决。以大多数数据和 ML 项目所需的规模维护干净、高质量的数据极其耗时——如果没有正确的方法,这几乎是不可能的。这就是可观察性的用武之地。
定义数据可观察性
界定“垃圾数据”(不管它存在于系统中的什么地方)影响的一个简单方法是通过软件应用程序可靠性的镜头。在过去十年左右的时间里,软件工程师利用 New Relic 和 DataDog 等目标解决方案来确保应用程序的高正常运行时间(换句话说,工作的、高性能的软件),同时将停机时间(中断和落后的软件)降至最低。
在数据方面,我们把这种现象叫做 数据停机 。数据宕机指的是数据不完整、错误、丢失或不准确的时间段,随着数据系统变得越来越复杂,它只会成倍增加,从而支持无止境的源和消费者生态系统。
通过将软件应用程序可观察性和可靠性的相同原则应用于数据和 ML,可以识别、解决甚至预防这些问题,让数据团队对其数据充满信心,从而提供有价值的见解。
数据监控与数据可观察性
经常出现的一个问题是:“我已经监控了我的数据。为什么我也需要可观测性?”
这是个很好的问题。长期以来,这两者一直被交替使用,但是监控和可观察性是两个非常不同的东西。
数据可观察性支持监控,这是大多数技术从业者都熟悉的:我们希望在出现问题时第一个知道,并快速排除故障。数据质量监控以类似的方式工作,当数据资产看起来与既定的度量或参数不同时,向团队发出警报。
*例如,如果某个值超出了预期范围,数据没有按预期更新,或者 1 亿行突然变成了 100 万行,数据监控就会发出警报。但是,在为数据生态系统设置监控之前,您需要了解我们刚刚讨论过的所有属性,这就是数据可观察性的用武之地。*
数据可观察性还通过提供关于数据的粒度、上下文信息来实现主动学习。团队可以探索数据资产,审查模式变更,并确定新问题或未知问题的根本原因。相比之下,监控基于预定义的问题发出警报,以聚合和平均值的形式表示数据。
有了数据可观察性,公司可以洞察数据健康的五个关键支柱:新鲜度、分布、容量、模式和沿袭。对于机器学习从业者来说,可观察性有助于提供一定程度的信心,即提供给模型的数据是完整的和最新的,并且在可接受的范围内。

数据可观察性的五大支柱。图片由巴尔·摩西提供。
当问题出现时,模式和沿袭的可见性有助于快速回答关于哪些数据受到影响的相关问题;可能进行了哪些更改,何时进行的,由谁进行的;以及哪些下游消费者可能会受到影响。
可观察性包括对数据健康五大支柱的监控,还包括对问题和端到端自动化数据谱系的警报和分类。这些功能结合在一起,使得数据可观察性成为现代数据堆栈的必备功能。
一个空值破坏了仪表板
知道你的数据管道坏了是一回事。但是你怎么能真正弄清楚发生了什么以及为什么呢?
与监控不同,当数据管道中断时,数据可观察性可用于处理 根本原因分析 。理论上,根本原因听起来就像运行几个 SQL 查询来分割数据一样简单,但在实践中,这个过程可能相当具有挑战性。事件可能以不明显的方式出现在整个管道中,并影响多个(有时是数百个)表。
例如,数据停机的一个常见原因是数据的新鲜度,即数据异常过时。这种事件可能是由多种原因造成的,包括作业卡在队列中、超时、合作伙伴未及时提供其数据集、错误或意外的计划更改从 DAG 中删除了作业。
通过获取数据资产的历史快照,数据可观察性为您提供了确定“为什么”的必要方法在破损的数据管道背后,即使问题本身与数据本身无关。此外,许多数据可观测性解决方案所提供的谱系赋予了跨职能团队(即,数据工程师、数据分析师、分析工程师、数据科学家等)。)协作解决数据问题的能力,以免它们成为更大的业务问题。
ML 监控与 ML 可观察性
当在生产中信任您的数据时,数据可观察性是一个难题,但是您的 ML 模型呢?
类似于数据可观察性如何帮助回答为什么*,ML 可观察性使模型所有者能够对模型故障进行根本原因分析。当模型性能下降时,监控会向您发出警报。ML 可观察性帮助你弄清为什么。一旦出现问题,弄清楚需要做什么是更大、更难的问题。*
对于软件应用程序,您通常会关注 SLA 和应用程序停机时间。对于机器学习,你看到的是数据和性能与基线的偏差。
ML 可观察性允许团队从生产中的培训、验证或之前的时间周期设置基线,并比较转变到性能下降的根本原因。
有了 ML 可观察性,公司可以洞察模型健康的主要支柱:模型和特征漂移检测、输入和输出数据质量、模型性能和可解释性。
当问题出现时,ML 可观察性使从业者能够查明为什么模型的性能在生产中不如预期,以及当他们应该重新训练他们的模型、更新他们的训练数据集、向他们的模型添加新特征或者甚至回到绘图板时的清楚信号。
大海捞针
那么 ML 可观测性是如何工作的呢?让我们举个例子:你预测交易是否是欺诈的模型出了问题,并开始有更多的误报。我们如何弄清原因?
能够自动显示性能较低的群组对于追踪模型对于特定数据子集的性能好坏至关重要。ML 可观察性有助于您缩小特定地理区域、特定客户群或特定时间窗口中是否存在明显更多的误报。
性能下降的一个常见原因是漂移。因为模型是根据数据训练的,当数据与他们已经看到的相似时,他们表现得很好。可观察性比较基线分布和当前分布之间的分布变化。有漂移时,模型所有者可以进行有针对性的上采样。
理论上,根本原因在 Jupyter 笔记本中听起来很容易,但在实践中,您必须通过自动设置和即时分析,在数十亿次预测中将其扩展到数百个功能、模型和模型版本。

ML 可观测性。图片由 Aparna Dhinakaran 提供。
我们很高兴看到下一代数据和 ML 领导者如何解决这个问题,使回答这个问题和许多其他问题变得更加容易。
对学习更感兴趣?伸出手去 巴尔 或者 阿帕纳 。
超越标签,用 OpenAI CLIP 进入图像语义搜索时代
原文:https://towardsdatascience.com/beyond-tags-and-entering-the-semantic-search-era-on-images-with-openai-clip-1f7d629a9978?source=collection_archive---------16-----------------------
用 OpenAI CLIP 探索真实世界用例的 Google Colab 代码笔记本

作者图片
问题陈述:
假设你是一名作家,你正在寻找与你的博客或书相匹配的最佳图片。你脑海中有一个搜索短语,比如“老虎在雪地里玩耍”。你进入 Pixabay 或 Unsplash 等无版权图片网站,尝试各种关键字组合,如**【老虎】【雪】【虎雪】**等,找到相关图片。
如果你幸运的话,你会在第一页或者在前 N 名检索结果中找到你正在寻找的精确图像。
由于这些网站中的图片只有标签,你受到标签检索结果的限制,你需要人工监督进一步过滤与你的搜索词**“老虎在雪地里玩耍”最相关的图片。**
如果您经常寻找与您的搜索短语相关的图像,这是一个问题,并且在从标签中检索的图像上进一步过滤非常耗时。
你需要的是在检索到的带有标签的图片上进行语义搜索。
语义搜索是指搜索引擎考虑搜索短语的意图和上下文含义的能力。语义搜索不是试图在输入短语中找到单词的精确匹配,而是捕捉更广泛的上下文和单词之间的关系,并检索与搜索查询的上下文更密切相关的结果。
如果 Pixabay/Unsplash 库中的每个图像都用一个描述它的句子加了标题和,那么我们可以使用 Sentence-BERT 或其他类似的算法将句子编码成一个向量,并执行相似性来提取前 N 个标题和语义上与搜索查询匹配的相关图像。
但是给数据库中的每张图片加标题是很昂贵的。大多数时候我们最好的只是标签。 OpenAI 夹子来救我们了。
解决方案:
在文字搜索中,如果你问一个类似**“美国第 45 任总统是谁?”如果你有数百万的文档来寻找答案,你首先做一个轻量级**过滤器(例如; BM25 in Elastic Search )可以快速浏览所有百万个文档,并获得可能有答案的前 100 个左右的文档。然后你使用一个更重的算法(例如:句子-BERT 语义搜索)来从这 100 个过滤的文档中提取出确切的段落。
对于给定的搜索查询,首先,我们有一个轻量级的快速过滤器来查找潜在的候选文档。我们称这个为寻回犬。检索者的目标是筛选出明显的负面案例。
然后我们有阅读器,它使用计算量更大的算法(例如:基于 Transformer)来缩小到文档中使用语义搜索得到答案的精确区域。
将类似的类比应用于图像搜索,我们看到,基于标签检索给定搜索查询的图像是非常快速和轻量级的。这是取回器的部分。例如,您只需使用标签**“Tiger”**进行搜索,就可以从 Pixabay 中检索到 Tiger 的所有图像。

作者使用 Pixabay 图像制作的图像
然后我们有 OpenAI CLIP 作为我们的阅读器,它使用计算量更大的算法来编码我们从标签中检索到的每个图像,以与我们编码的句子进行比较,例如:“老虎在雪地里玩耍”,并基于语义相似性返回前 N 个结果。

作者使用 Pixabay 图像制作的图像
OpenAI 剪辑
OpenAI 最近(2021 年 1 月 5 日)推出了一个名为 CLIP 的神经网络,它可以从自然语言监督中高效地学习视觉概念。CLIP 代表对比语言-图像预训练。
CLIP 建立在大量关于零镜头转换、自然语言监督和多模态学习的工作之上。你可以点击阅读更多关于夹子的信息。
对于我们的用例,我们需要了解 CLIP 是用一大组带有相应标题的图像来训练的,因此当对图像和文本的编码都应用相似性度量(例如:余弦)时,它学会了预测哪个图像标题(文本)与哪个图像紧密匹配。
所以在训练之后,你可以给出一个随机的图像,然后在向量空间中用两个向量的短语找到该图像的余弦相似度“这是一张狗的照片吗?”,“这是猫的照片吗?”并且看哪一个具有最高的相似性来找到图像的类别。所以在某种程度上,它具有像 GPT-2 和 GPT-3 一样的零射击分类能力。

图片来自 OpenAI 剪辑博客
密码
说够了给我看看代码😃
一个易于使用的谷歌 Colab 笔记本可以在这里找到。
我改编了 OpenAI 剪辑团队最初的 Github repo 的代码。
我将关注我为这个用例修改的代码部分。
1.使用 Pixabay 检索给定标签的图像
首先,我们使用 Pixabay API 来检索给定搜索标签的图像。例如: Tiger 并使用易于使用的绘图库 ipyplot 显示检索到的图像。
从 Pixabay 检索到标签为 Tiger 的图像

作者使用 Pixabay 图像制作的图像
2.预处理图像和文本的功能
在下面的代码中,我们对图像和文本进行预处理,对它们进行编码,并用模型将它们转换成固定大小的向量。
我们也有一个函数来寻找编码文本短语之间的余弦相似性,例如:“老虎玩雪”和所有检索图像的向量。然后我们基于相似性对图像进行排序以获得与文本短语相似的前 N 个图像。
3.用任何短语搜索,得到前 N 个语义相似的图片
在这一节中,下面的代码获取任何搜索短语,如**“老虎在雪地里玩耍”,将文本编码成一个向量,并计算所有图像向量的余弦相似度**,过滤前 N 个选择并显示。
输出:在过滤了从标签(Tiger)中检索的 Pixabay 图像后,我们得到了与我们的搜索短语**“Tiger playing in the snow】、**最相似的前 N 个图像。

作者使用 Pixabay 图像制作的图像
类似地,用短语**“浸在水中的老虎”**搜索会检索到如下所示的这些图像。

作者使用 Pixabay 图像制作的图像
再来一个:
搜索短语— “老虎坐在树枝上”

作者使用 Pixabay 图像制作的图像
使用自然语言处理的问题生成——教程
我推出了一个非常有趣的 Udemy 课程,名为“使用 NLP 生成问题”,扩展了这篇博文中讨论的一些技术。如果你想看一看,这里是链接。
结论
希望你喜欢我们如何使用两天前刚刚发布的 OpenAI 的前沿研究,并解决了一个现实世界的问题。
祝 NLP 探索愉快,如果你喜欢它的内容,请随时在推特上找到我。
如果你想学习使用变形金刚的现代自然语言处理,看看我的课程使用自然语言处理的问题生成
超越可视化的基础
原文:https://towardsdatascience.com/beyond-the-basics-of-visualization-5bcb0e7528e7?source=collection_archive---------37-----------------------
最新指南
不要对你的创造性努力沾沾自喜

来源: Pixabay
示例数据:https://www . ka ggle . com/arashnic/HR-analytics-job-change-of-data-scientists?select=aug_train.csv
回到 2019 年 6 月,我在 Medium 上写了我的第一篇文章。我一直对数据可视化充满热情,并想写一篇关于它的文章,更多的是为我自己,而不是为任何阅读它的人。我创建了示例视觉效果,并梳理资源以找到有见地的提示,但我真的不期望人们真的会阅读它。令我惊讶的是,人们读了它,并告诉我一些我思维中的错误。差不多两年了,有了更多的经验之后,是时候用我现在所知道的来更新这个指南了。
免责声明:我绝不是专家,我只是这门手艺的学生。这些真的只是我试错学来的新手小技巧,想分享一下!
提示 1:做一些研究
l̶e̶s̶s̶o̶n̶̶1̶:̶̶k̶n̶o̶w̶̶w̶h̶a̶t̶'̶s̶̶a̶v̶a̶i̶l̶a̶b̶l̶e̶̶t̶o̶̶y̶o̶u̶
在创建视觉效果或图形之前,了解数据的组成和试图用数据展示的内容是至关重要的。首先要检查的几件事:数据存储在哪里以及如何存储,数据的类型是什么——数值型、分类型、二进制型等等,以及是否需要先进行标准化或转换(通过标识符汇总或标准化文本来创建类别是否有益?)一旦你开始想象,这会改变你的方法,帮助你更好地考虑你的选择。例如,如果您的数据不断更新,当您完成时,停滞的图形可能没有帮助。
为什么这一步很重要?很容易假设您的数据是干净和完美的,但通常情况下,它远非如此。尤其是当数据由用户输入或从网上搜集时,事情会变得非常混乱(当 M&T 和 M&T 有两个独立的类别时会出现的挫折值得采取预防措施),当你努力可视化你的数据时,你希望它尽可能清晰。快速浏览一下,确保你有正确的数据,并且数据的格式有助于你形象化。如果不是,为了节省时间,首先预处理这些数据对您最有利。

来源:Taylor fog arty——这些数据可能看起来相对干净,但根据您计划如何可视化,您可能需要采取一些步骤。你可能想了解“上一份新工作”的真正含义,或者“相关经验”是如何衡量的。您可能还想通过删除非数字字符将“经验”列转换成数字值。这些步骤将帮助你确保你的视频讲述你想要的故事。
“知道有什么可用的”和“做研究”有什么区别?以前,我认为为了创造视觉效果,了解你所拥有的工具是很重要的,然而,我开始意识到,努力去了解你需要工具的材料会更好。知道这些工具仍然很重要,但是你可能有一个你最熟悉的工具,这很好!然而,如果你想探索和学习一些新的东西,可以看一看我的原始文章,寻找一些不同的选择。
**提示 2:考虑你的选择**
̶l̶e̶s̶s̶o̶n̶̶2̶:̶̶p̶i̶c̶k̶̶t̶h̶e̶̶r̶i̶g̶h̶t̶̶k̶i̶n̶d̶̶o̶f̶̶g̶r̶a̶p̶h̶
如前所述,有很多不同的工具可以使用,在你开始视觉化之前应该考虑这些工具以及你想要创建的视觉类型。如果您有持续提取的数据,并且不断更新视觉效果会很有好处,那么有一些软件可以帮助您毫不费力地做到这一点,如 Tableau 或 Microsoft Power BI。或者,如果你想为一个报告或文章创造一个停滞的视觉效果,这是不必要的,可能会引起更多的混乱。方法的选择在很大程度上取决于舒适度,但也取决于工具在帮助你创建你心目中的视觉效果方面有多有用。
无论您决定使用哪种可视化方法,在呈现数据时都可能有很多选项可供选择!你想用线形图或条形图,甚至冲积图?重要的是要记住,每种类型的视觉都有特定的目的和目标,你应该确保这些与你的目标一致。如果你想显示事物如何随时间变化,折线图比一系列饼图好得多(至少在大多数情况下)。你可能认为研究已经随着最后一个提示结束了,但是,还是要做你的研究!通过真正理解你创造的视觉类型,它将帮助你使它更具交流性和有效性。

来源:Taylor fog arty——上面的三张图片代表相同的数据,但不一定是相同的信息。堆叠条形图(左)显示了数据集中显示的申请人总数,以及他们如何按性别细分的高级视图。饼状图(中间)只告诉你性别的细分,但没有显示有多少申请人组成了数据集。表格(右侧)显示了细分情况,但也允许您查看每个类别的确切申请人数以及所有类别标签。
在你开始创建图表之前,用手勾画出你所想象的图表的样子或它将包含的内容通常是有帮助的,这样你就有了一个开始的地方。从那里,您可以查看相似类型的图表,以添加视觉上更有趣的变化或图表。
技巧 3:不要害怕定制
̶l̶e̶s̶s̶o̶n̶̶3̶:̶̶c̶u̶s̶t̶o̶m̶i̶z̶e̶̶y̶o̶u̶r̶̶v̶i̶s̶u̶a̶l̶s̶,̶̶d̶o̶n̶'̶t̶̶s̶e̶t̶t̶l̶e̶̶f̶o̶r̶̶o̶r̶a̶n̶g̶e̶̶a̶n̶d̶̶b̶l̶u̶e̶
定制可能是你最好的朋友,特别是如果你想在公共场合使用你的视觉效果。如果你不是,如果视觉是为了一个任务或探索的目的,自定义视觉可能不值得你花时间。同样,这一切都回到你的视觉目标。
如果你想让视觉效果更有凝聚力,视觉上更有趣,可以考虑使用某种定制来帮助表达你的观点。当然,为了清晰起见,你应该总是添加标题、图例等,但是你也可以使用颜色、突出显示的数据点和尺寸来赋予你的视觉效果以生命。只要这些自定义不偏离视觉效果的目的或隐藏重要信息,它们就有助于将读者的注意力引向特定的结论。
重要的是要记住颜色是有意的。颜色是一种很好的视觉品牌,并使他们有凝聚力的方式,但如果使用不当,它会无意中造成混乱。跨视觉效果重用颜色变化可以通过将一个值与另一个值相关联来帮助连接它们,但是如果它们在视觉效果中不一致,它可能会导致读者第一眼就误解视觉效果。

来源:Taylor fog arty——虽然这种视觉效果本身看起来不错,但如果它存在于包含提示 2 中的表格的仪表板中,可能会引起混淆,因为绿色刻度对应不同的值,第一个值代表申请人数,而这个刻度代表所需的平均培训小时数。
如果视觉材料是为其他人制作的,例如雇主或客户,颜色和其他附加物的使用可能有助于视觉材料的消费。通过利用他们品牌的颜色、字体和术语,你的受众会积极地联想到这种识别,并可能对视觉效果或内容更加开放。
技巧 4:谨慎添加
̶l̶e̶s̶s̶o̶n̶̶4̶:̶̶b̶e̶̶c̶a̶r̶e̶f̶u̶l̶̶h̶o̶w̶̶y̶o̶u̶̶e̶n̶c̶o̶d̶e̶
我们在创造视觉效果时喜欢做的一件事是添加额外的信息层,不管它们是否相关,以防某些东西很有趣。或者额外的几层可能对你的结论很重要。无论哪种方式,添加数据都需要深思熟虑和谨慎。我们不应该让我们内心的创造力永远占上风。
视觉效果必须清晰,但视觉效果必须吸引人,必须有趣。同样,我们循环回到视觉的目标来决定哪条路线更好。如果你的目标是创建一个发人深省和美丽的视觉,然后编码到你的心的内容,但如果你的目标是有效地沟通信息,你可能要重新考虑。如果你编码的数据没有增加任何新的理解或帮助读者得出相同的结论,在这种情况下应该避免。

来源:Taylor fog arty——这种视觉效果试图用气泡图来显示性别、专业和申请人数,但它在几个关键方面失败了。这也显示了清理数据的重要性——如果您查看带注释的气泡,您会发现许多气泡缺少一个或多个我们试图查看的变量。虽然这可能会让您深入了解数据集中缺失值的位置,但如果您的目标是查看按性别划分的专业,这并不能完成工作。许多气泡非常小,如果没有工具提示,就不可能知道它们代表什么。
有时,如果能表达重点,基本条形图是最好的选择。大部分人都知道如何非常快速的解读一个条形图,折线图,或者饼状图,基本上一目了然。当你的发现需要快速消化或无需解释时,使用简单性。
提示 5:不要忘记上下文
̶l̶e̶s̶s̶o̶n̶̶5̶:̶̶c̶r̶e̶a̶t̶e̶̶y̶o̶u̶r̶̶g̶r̶a̶p̶h̶̶c̶o̶m̶p̶l̶e̶t̶e̶l̶y̶
绝对不要忘记你的标题和标签,以确保你的读者理解数据,但也不要忘记在你完成创建后考虑数据的上下文。这可以帮助你再次检查你的视觉显示的信息是否是你想要的,也可以防止你做得过火。希望在整个过程中,你已经记住了你的视觉效果的目标和目的,但是如果没有,你应该现在就返回。确保看到该视觉效果的人能够理解它——毕竟,您可能已经使用数据有一段时间了,应该比第一次看到它的人对它有更好的理解。
额外提示:犯错
正如我在开头提到的,我不是专家,但我学到的东西很大程度上是通过试错。不要害怕犯错误,但一定要从中吸取教训!你创造的第一个视觉效果不会完美,这没关系。修改它,接受批评,因为它们只会在你的旅程中帮助你。
蟒蛇熊猫的数量之外
如何处理文本数据?

萨曼莎·加德斯在 Unsplash 上的照片
Pandas 是使用最广泛的 Python 库之一。它提供了许多功能和方法来执行有效的数据分析和操作。
我们倾向于将表格数据与数字联系起来。然而,大量的原始数据是以文本形式出现的。幸运的是,Pandas 有几种方法来处理文本数据。
操作字符串的方法可以通过 str 访问器来访问。在本文中,我们将通过例子来探讨这些方法。
让我们从用模拟数据创建一个样本数据框开始。
import pandas as pddf = pd.DataFrame({ "FirstName": ["Jane","john","Ashley", "MATT", "Alex"],
"LastName": ["Doe", "Smitt", "Adams", "Tull", "Morgan"],
"Address": ["Houston, TX", "Dallas, TX", "San Antonio, TX",
"Palo Alto, CA", "San Diego, CA"]})df

(图片由作者提供)
我们注意到的第一件事是名字中的字母不兼容。有大写字母也有小写字母。最好是标准格式的。
我们可以将它们全部转换成大写或小写。熊猫有两种操作方法。
df["FirstName"] = df["FirstName"].str.lower()df["LastName"] = df["LastName"].str.lower()df

(图片由作者提供)
我们可以通过组合名字和姓氏来创建姓名列。
df.insert(2,
"Name",
df["FirstName"].str.cat(df["LastName"], sep=" "))df

(图片由作者提供)
我使用了 insert 函数,能够在姓氏之后创建新的列。默认情况下,新列添加在末尾,但是插入允许在特定位置创建新列。
str 访问器下的 cat 方法组合字符串。它用在 insert 函数的第三个参数中,我们在这里定义新列的值。
字符串的另一个常见操作是拆分。在某些情况下,文本数据包含多条信息。例如,“地址”列包括城市和州名。我们可以通过拆分该列来提取城市或州的信息。
df["State"] = df["Address"].str.split(",", expand=True)[1]df

(图片由作者提供)
在某些情况下,我们需要根据字符串过滤数据点(即行)。例如,我们可能对以字母 j 开头的名称或包含“TX”的地址感兴趣。
startswith 和 endswith 方法允许分别基于字符串的第一个或最后一个字母进行过滤。如果我们在一个字符串中搜索一个字符序列,那么可以使用 contain 方法。所有这些方法都可以在 str 访问器下使用。
df[df["Name"].str.startswith("j")]

(图片由作者提供)
df[df["Address"].str.contains("TX")]

(图片由作者提供)
值得注意的是,startswith 和 endswith 方法接受多个字符。因此,我们可以使用它们来过滤以字符序列开头或结尾的字符串。
replace 方法可用于替换字符串中的字符序列。让我们做一个例子来演示它是如何使用的。
df["Address"] = df["Address"].str.replace("TX", "Texas")df

(图片由作者提供)
str 访问器还可以用于对字符串进行索引。例如,我们可以用“str[:2]”表达式选择前两个字符,用“str[-2:]”表达式选择后两个字符。

(图片由作者提供)
结论
Pandas 字符串方法组合在 str 访问器下。我们已经介绍了您可能会更经常使用的工具。
文本数据拥有非常有价值的信息,将永远存在于我们的生活中。因此,学会如何操纵和处理它是非常重要的。
感谢您的阅读。如果您有任何反馈,请告诉我。
超越普通变压器
原文:https://towardsdatascience.com/beyond-the-vanilla-transformer-602d3c57d0db?source=collection_archive---------29-----------------------
一瞥 NLPs 最先进建筑的发展前景

乔斯林·莫拉莱斯在 Unsplash 上的照片
现在是 2017 年,论文《注意力是你需要的全部》为 NLP 提供了一个新的有前途的架构:变压器。四年后——深度学习领域的永恒 Transformer 仍然是最先进的架构,用于各种 NLP 任务。但是世界并没有停滞不前——至少在这个领域没有,更多的论文已经开始转变,并为进一步的发展提供了新的方法。我想在这里讨论一些有前景的。
我们将从 2019 年已经发表的论文开始:“ Transformer XL:超越固定长度上下文的专注语言模型”。下面这篇论文将是“重整器:高效的变压器”,在最近一篇文章(2021 年 6 月)之前:“打包:迈向 2 倍 NLP BERT 加速”将被讨论。
关于 Transformer 还有很多有前途的文章,但是我必须做出选择,这样这篇文章就不会超出范围。我希望我没有对任何一位论文作者不公🙃!
Transformer-XL:超越固定长度上下文的注意力语言模型
本文讨论变压器处理不定长文本的有限能力。标准转换器使用最大长度、截断和填充来处理不同的序列长度。同时,这种固定长度是扩展依赖学习的障碍,在扩展依赖学习中,注意机制会抓住超过这一限制的连接。
虽然短期依赖性可能不会对大多数用例造成问题,但是固定长度限制可能会由于截断及其不遵守语义边界的属性而降低性能。作者称之为语境碎片。
他们的解决方案听起来很简单:通过不从头开始计算隐藏状态,最后一个状态可以作为当前段的内存状态。有了这种循环连接,信息不会丢失,而是会从一个状态传递到另一个状态。这显然解决了丢失语义信息的问题,并导致了长期的依赖性。
与普通变形金刚相比的变化可以在注意力层中找到。键和值将由来自前一段的缓存进行扩展。我不想谈论更多的细节。但是我强烈推荐阅读 Transformer XL 论文中的章节带状态重用的段级递归。
在关注层内使用先前段的缓存需要一些额外的改变。作者提出的问题是:"[……]当我们重用状态时,如何保持位置信息的一致性?(戴等 2019)。而在默认转换器中,序列顺序由位置编码提供。当使用缓存时,不考虑前一状态的位置编码(我们刚刚讨论过)。这导致性能不佳。为了克服这个问题,作者的方法是只编码隐藏状态中的相对位置信息,并将其注入注意力得分。从他们的角度来看,这种方法更直观:
例如,当查询向量 qτ,I 涉及关键向量 k τ,≤i 时,不需要知道每个关键向量的绝对位置来识别片段的时间顺序。(戴等 2019)
相对距离足以使查询向量能够通过元素的不同距离来区分元素。此外,可以从相对距离获得绝对位置。请在原始论文中阅读更多关于这方面的内容。
总结一下:通过缓存之前的片段来改善注意力机制似乎是一个有希望的步骤。这不仅增加了长期依赖性,而且还解决了文本分割带来的上下文碎片问题。

改革者:高效的变压器
变压器是有很多参数的巨大模型。从零开始训练他们实际上只能由行业或平等的大玩家来完成。幸运的是,我们可以使用像伯特这样预先训练好的模型。但即使是 24 层版本的 BERT,也很难在单个 GPU 系统上进行训练。如果我们不希望这种模型只能由大公司来训练和运行,变压器需要变得更有效率。
Kitaev、Kaiser 和 lev Shaya——改革者论文的作者介绍了解决上述问题的三项变革:
- 使用可逆层仅存储整个模型的激活的单个副本。这将使存储激活所需的内存减少 N 倍
- 在前馈层内分割激活并将它们作为块进行处理有助于减少这些层所需的内存。前馈层通常比例如关注层广泛得多,因此负责高存储器使用率。
- 使用局部敏感散列注意力,将注意力层内的因子从 O(L ) 改变为 O(L log L)
作者确信“[……]与标准变压器相比,这些技术对训练过程的影响可以忽略不计”(Kitaev 等人,2020)。我将谈论第一个和最后一个想法——在我看来,它们是最有趣的。为了不至于失控,第二种方法将不再讨论。
可逆变压器
在他们的论文中:可逆残差网络:不存储激活的反向传播, Gomez 等人提出了可逆残差网络 (RevNets)。这个想法是,每次激活都可以从下一层恢复,并且在反向传播期间不需要存储——以计算换取更多的内存。剩余层(也称为跳过连接)执行对单个输入和单个输出进行操作的功能:

可逆层有两个输入:

根据这些等式(并通过减法反转):

在*可逆变压器的上下文中,*这意味着前馈层( G )和关注层( F )被组合在可逆模块内。
Y₁ = X₁ + Attention(X₂) 和 Y₂ = X₂ + FeedForward(Y₁)
通过这种实现,不再需要存储激活;因此节省了内存。即使这意味着需要稍微多一点的计算。
区分位置的哈希注意
变形金刚的核心是注意力机制。不是没有原因,最初的论文叫做注意力是你所需要的全部。因此,开发出使这种机制更有效的方法只是时间问题。
在标准转换器中,使用缩放的点积注意力:

输入包含查询和键以及值。所有查询和键的点积都是在缩放之前计算的。之后,应用 softmax 函数。最后,中间矩阵和值矩阵的矩阵乘法产生关注度分数。
作者正在寻找一种更有效的记忆注意力机制,并提出了位置敏感哈希注意力(LSH) 的想法。目的是将复杂度从 O(L ) 降低到 *O(L log L)。*粗略地说,该算法旨在将数据点分组到所谓的桶中,以便彼此接近的数据点以很高的概率获得相同的散列。与其他散列技术相比,散列冲突被最大化,而不是最小化。在最近邻居的帮助下,我们可以将注意力集中在靠近查询的关键字上。
下面你看一下 LSH 在论文中阐述的注意事项:

单个查询位置 I 的等式
*‘P’*指' i' 为部分的集合,' z' 表示配分函数。 LSH 背后的思想是集合 P 元素被限制为关注单个哈希桶的元素:

LSH 作为全神贯注的近似方法,能够通过增加计算成本来减少内存使用,计算成本随着哈希数的增加而增加。希望这将使大型变压器更容易使用——不仅仅是对在多个 GPU 上运行它们的机构。
包装:接近 2 倍 NLP BERT 加速度
如前所述,预训练 BERT 是因为它对计算能力的巨大需求,只适用于大型行业或研究机构。Kosec、Fu 和 Krell——这篇论文的作者希望通过去除填充来提高效率,从而减少这一障碍。他们提出了一种算法,利用维基百科数据集将预训练速度提高了 2 倍。
处理填充令牌可以被视为计算的浪费。文本长度分布越宽,在这个过程中损失的计算就越多。打包方法希望完全填充每个序列长度,因此不再需要填充。这种想法基于这样的假设,即序列是可以互换的,所以顺序并不重要。装箱方法是一个经典的规划问题(装箱或下料问题)。由于该问题是 NLP 特有的,因此提出了两种算法:
- 最短包装优先直方图包装
- 非负最小二乘直方图打包
理解这些算法的细节并不重要;分析包装带来的问题要重要得多。作者们通过详细地解决这些问题做了大量的工作。让我们谈一谈它们。
顾名思义,BERT(来自变压器的双向编码器表示)利用了双向自我关注。但是,打包(填充段,不留出填充空间)会创建没有相应序列的段。像 GPT3 这样注意力不集中的语言模型不会面临这个问题,因为它们只关注以前的标记。本文介绍了用于注意层的掩模,以防止不同序列之间的污染。让我们看看文章中提供的一些代码:
mask = np.array([[1, 1, 1, 2, 2]]) # input
zero_one_mask = tf.equal(mask, mask.T) # 0, 1 mask #for use with softmax:
softmax_mask = tf.where(zero_one_mask , 0, -1000)
这个实现创建了一个块对角掩码,减少了填充,并且可以简单地由像 numpy 这样的框架实现。
包装面临的另一个挑战是损失和准确性的计算。在 BERT 中,交叉熵损失是按序列计算的。当使用打包时,不再为序列计算损失。该模型将收敛到不同的最优值。为了解决这个问题,作者的想法是:
“为了实现每序列丢失,我们通过处理每令牌丢失来有效地‘解包’传入的逻辑和标签。我们计算属于第一序列的所有记号的损失,然后计算属于第二序列的所有记号的损失,等等“”(Kosec,et al. 2021)。
本文中有一个很好的代码示例解释了它们的实现——请查看。
与其他两篇文章不同,打包方法旨在优化前期培训。尽管这个过程可能会花费大量的时间和金钱,但这里显示的改进是有希望的。
现在,我们已经了解了改善变压器的各种方法,不得不说,所有这些方法都是优化性能而非质量输出的独特方法。这可能是由于我的选择和这样一个事实,即 Transformer 作为一个有前途的架构越来越只对大玩家可用,或者至少是由他们创建的。GTP3 就是一个典型的例子。
我希望这些描述是可以理解和理解的。解释的一些概念不是特别容易理解,所以解释本身并不是最直接的任务。谢谢你一直读到最后。下次见——再见。
参考
艾丹·戈麦斯,叶萌·任,拉克尔·乌尔塔森和罗杰·b·格罗斯:可逆残差网络:不存储激活的反向传播。 arXiv: 1707.04585,2017
阿什什·瓦斯瓦尼、诺姆·沙泽尔、尼基·帕尔马、雅各布·乌兹科雷特、莱昂·琼斯、艾丹·戈麦斯、卢卡斯·凯泽和伊利亚·波洛苏欣:你所需要的只是关注。arXiv:1706.03762, 2018
马特伊·科塞克、傅生和马里奥·迈克尔·克雷尔:打包:向 2 倍 NLP BERT 加速前进。arXiv:2107.02027, 2021
Nikita Kitaev,ukasz Kaiser 和 Anselm Levskaya:改革者:高效的变革者。arXiv:2001.04451, 2020
戴子航,,,Jaime Carbonell,Quoc V. Le,Ruslan Salakhutdinov:Transformer-XL:固定长度语境之外的注意力语言模型。arXiv:2019
感谢所有写出如此精彩文章的作者!🤗
Bhattacharyya 核和数据集上的机器学习
原文:https://towardsdatascience.com/bhattacharyya-kernels-and-machine-learning-on-sets-of-data-bf94a22097f7?source=collection_archive---------9-----------------------
使用集合元素的概率分布来提取特定于集合的特征

塞布·阿特金森在 Unsplash 上拍摄的照片
当一个特征不是被定义为单个数字,而是一组对象时,集合上的机器学习问题就出现了。一个很好的例子是,当您试图根据订单历史推断客户的一些情况时。我在过去的这些文章中介绍了 set 上的深度学习方法:
但是在本文中,我将回顾如何使用内核方法来学习集合。
核心方法
最新一代的数据科学家可能从未使用过任何内核方法。然而,在大约 20 年前,它们被广泛使用。它们都基于将输入空间映射到另一个空间,其中给定的机器学习问题可以使用线性方法来解决:
尖括号表示点积。那么任何函数都可以用线性组合来表示:
内核方法的要点是,您并不真的需要在输入空间中导出映射。知道核函数就足够了。核函数可以被认为是指示两个数据点之间的相似性。最著名的基于核的方法是支持向量机,但还有很多,包括核 PCA,高斯过程和贝叶斯优化。
Bhattacharyya 内核
原始核定义在单个向量的输入空间上。如果你的输入空间是向量集呢?我们可以找到每个集合中向量的概率分布,并计算核函数作为两个概率分布相似性的度量[1,2]。一个很好的相似性度量是 Bhattacharyya 系数:

来源:https://en.wikipedia.org/wiki/Bhattacharyya_distance
该系数计算两个分布之间的重叠。它总是大于零,并且具有一个很好的性质,即 **BC(p,p) = 1,**这使得可以将其解释为两个分布之间的“角度”的余弦。它可以对指数族的所有概率分布进行封闭形式的计算,如正态、伯努利、多项式等。Bhattacharyya 系数实际上是一个正定矩阵,因此是集合间核的一个很好的候选。
量子力学中的类比
在量子力学中,系统(稳态)状态由波函数 ψ(x) 定义,其平方模数是概率密度函数:
以下量称为转变幅度:
而它的平方模是*跃迁几率,*也就是系统处于ψ1 态也处于ψ2 态的几率。可以看到,跃迁幅度是复数希尔伯特空间中的 Bhattacharyya 核,它给出了 Bhattacharyya 系数平方对概率的解释,即一个分布的样本也可以解释为第二个分布的样本。换句话说,它可以解释为两个概率密度函数的重叠。
概率乘积核
这些内核值得一提,因为它们是 Bhattacharyya 内核的扩展。它们被定义为:
对于 ρ=1/2 ,这个内核简化为 Bhattacharyya 内核。当 ρ=1 时,该核称为*期望似然核。*这个内核没有一个很好的性质 K(q,q) = 1 ,除非 ρ=1/2 。此外,在一般情况下,积分不能保证收敛。
实验性研究
我们创建了一个简单的实验来衡量基于 Bhattacharyya 内核的算法的表达能力。我们生成了 1000 组数字,每组数字都遵循带有随机参数的正态分布。然后,对于每个集合,我们拟合正态分布,并尝试预测 60%分位数是高于还是低于指定值。
在这里,我们定义了集合的数量和分布参数的范围、集合大小的范围、目标分位数和比较值。我们现在将为每个参数集生成随机参数集:
该数据框包含每个集合的正态分布参数以及集合大小。我们现在准备生成集合:
对于每个集合,我们可以计算分位数目标变量以及平均值和标准偏差。这里我们遵循频率主义者的方法。贝叶斯方法需要稍微不同的实验设计。

作者图片
这种情况下的核函数可以解析计算。给核函数两个自变量,让 𝑚 1 和 *𝑠* 1 是第一分布的参数,而 *𝑚* 1 和 *𝑠* 1 是第二分布的参数。
则内核计算如下:

作者图片
是时候分成训练集和测试集,并使用支持向量分类器进行训练了:
训练集和测试集的模型准确性
model.score(X_train, y_train, )0.9775model.score(X_test, y_test, )0.975
准确率相当高,但即使在训练集上也不是 100%。通过调整超参数 𝜌 ,使用更一般的概率乘积核可能有助于获得更高的精度
结论
在本文中,我们讨论了 Bhattacharyya 内核和相关内核,当训练数据表示集合而不是数据点时,这些内核会很有用。这个核的假设是,符合相似概率分布的集合彼此相似。我们设计了一个简单的实验来评估支持向量机分类器的内核性能。实验结果不错,但并不令人印象深刻。我们可以注意到,核函数不依赖于集合大小,只要它们符合相同的分布,它就会将不同的集合视为相同的,即使它们的大小非常不同。使用贝叶斯方法代替频繁方法可以帮助我们在核建模中保留关于集合大小的信息。这篇文章的所有代码都在我的 github 页面上。
参考
[1]t .杰巴拉和 r .孔多尔(2003 年)。Bhattacharyya 和期望似然核。人工智能讲义(计算机科学讲义系列), 2777 。https://doi.org/10.1007/978-3-540-45167-9_6
[2]t .杰巴拉、r .孔多尔和 a .霍华德(2004 年)。概率乘积核。机器学习研究杂志, 5 。
偏见和差异背后的直觉
原文:https://towardsdatascience.com/bias-and-variance-but-what-are-they-really-ac539817e171?source=collection_archive---------11-----------------------
偏差和方差通常用技术术语表示,但它们也有直观的解释。
如果你参加机器学习课程,在某些时候你会遇到偏差-方差权衡。你可能觉得你有点理解它,但不是真的。后来,你看到这两个词在书籍、文章和谈话中随处可见,你意识到你对什么是偏差和方差仍然没有很好的直觉。这篇文章是给你的。
我不打算进入技术定义,我将省略任何公式。我假设我的观众理解基本的 ML 概念,例如为什么数据被分为训练集、验证集和测试集,一些超参数的选择如何影响训练模型的“复杂性”(例如,决策树的最大深度越高,决策规则集越精细),以及交叉验证如何用于为模型找到好的超参数。
让我们从定义偏差和方差开始:
- 一些模型过于简单,忽略了训练数据中的重要关系,而训练数据本可以提高它们的预测。据说这样的模型有很高的偏差。当一个模型有很高的偏差时,它的预测总是错误的,如果不是整个范围的话,至少对于数据的某些区域是这样。例如,如果您试图用一条线来拟合散点图,其中数据似乎遵循曲线-线性模式,那么您可以想象我们不会有很好的拟合。在图的某些部分,线会落在曲线下面,而其他部分会在曲线上面,笨拙地试图跟随曲线的轨迹。由于直线跟踪模型的预测,因此我们可以看到,当直线低于曲线时,预测始终低于实际情况,反之亦然。所以当你想到“偏差”这个词时,就想到预测总是偏离。高偏差模型被称为欠拟合【训练数据】,因此训练数据和测试数据的预测误差都很高。
- 有些模型过于复杂,在寻找变量之间重要关系的过程中,它们也会偶然发现某些关系,而这些关系最终只是噪音的结果。换句话说,该模型考虑了训练数据中的某些“侥幸”,这些数据不能推广到测试数据。在这种情况下,模型的预测再次被关闭,但重要的是:它们是而不是 持续关闭。稍微改变一下数据,我们最终会得到非常不同的预测。为什么?因为模型对数据的变化过于敏感和反应过度。高方差模型被称为过度拟合【训练数据】,因此它们的预测误差在训练数据上看似很低,但在测试数据上却很高,因此缺乏通用性。
上述极端情况分别由下图的左侧和右侧表示:

中间的垂直虚线显示了一种“快乐的中间状态”(没有双关语的意思),其中模型的复杂性正好是模型既不欠拟合也不过拟合的量。垂直轴表示模型的预测误差。红色曲线代表测试数据的平均误差。图片作者。
也许下面的类比会帮助你的直觉:假设你刚和你的两个朋友看完一部电影。你现在转向每个人,问“你觉得这部电影怎么样?”。你的一个朋友是个内向的人,为了避免拖累谈话,他会给你一个笼统的说法,比如“很好”另一个朋友是外向的人,为了延长谈话时间,他对电影进行了复杂的分析,有很多细节似乎“离题了”。听完每个朋友的话,你仍然不知道他们喜欢这部电影。所以你转向你的第一个朋友,请他详细说明一些,你要求另一个朋友简化他们的描述,避免跑题。你能猜出哪个朋友偏差大,哪个方差大吗?如果你仍然不确定,我鼓励你从头再看一遍这篇文章。答案应该是明确的。
既然您对这些概念已经比较熟悉了,那么让我们将它们与这些术语在更一般的上下文中的使用联系起来。
- 你可能听过人们称一个有偏见的人(偏见)。这和 ML 中的偏倚有关系吗?很高兴你问了。当我们说某人有偏见时,我们的意思是他们倾向于妄下结论,忽视相反的证据。这可以是有意的,也可以是无意的。小孩子经常会有偏见,因为他们通过泛泛而谈来了解世界(例如陌生人的危险),在成长的过程中,他们完善了他们的世界模型。另一个常见的情况是当我们提到有偏硬币时:如果一个模型非常适合,那么(测试数据上的)误差应该看起来像随机噪声,就像无偏硬币的结果看起来随机且不可预测一样。但是,如果模型在数据的某个区域有偏差,那么预测总是高于或低于标准,使得误差总是分别为负或正。因此,误差的符号就像一枚有偏差的硬币。
- 方差呢?方差还有很多其他的名字。我更喜欢更广泛的术语可变性,其他术语包括利差和风险(后者在金融领域很常见,指的是缺乏可预测性),但让我们坚持使用方差。在更广泛的背景下,当我们说某事有很高的方差时,这意味着它倾向于对反馈反应过度。想象一个函数,它的输出对输入的变化非常敏感。这和 ML 有什么关系?回想一下,对于 ML 算法,输入是训练数据,输出是经过训练的模型,然后可以使用该模型来获得对测试数据的预测。因此,当我们使用稍有不同的训练数据重新训练同一模型时,高方差模型的预测会以意想不到且看似随机的方式发生变化。在英语中,我们用“对某事读得太多”来描述这种我们在没有模式的地方看到模式的行为。因此,你可以说高方差模型对训练数据的细微差别和微妙之处解读过多,将噪声误认为信号。
也许下面的可视化可以帮助巩固你的理解:

上图中的每个点代表一个训练实例,也就是一个训练好的模型。从一个点变化到另一个点的是训练数据。如果经过训练的模型在测试数据上的误差很低,它的点应该落在红色圆圈内。当这些点聚集在一起时,这意味着底层的训练模型是一致的,当它们散开时,这意味着它们具有高方差。低偏差低方差的最佳点对应于左下方的目标。图片作者。
如果到目前为止你还和我在一起,那么有一件事应该是清楚的:为了知道我们的模型是否有高偏差,高方差,或者是否在最佳点,我们需要三样东西:
- 在训练集和测试集之间拆分数据,以便我们可以比较训练和测试数据的错误。
- 一遍又一遍地重新训练相同的模型(这里相同意味着我们使用相同的超参数),以查看预测如何响应训练数据的变化而变化。
- 重新训练几个不同的模型(这里的不同是指使用另一组超参数),以便我们可以比较不同复杂程度的训练模型。我们通常将这一步骤称为超参数调整,但在正确的上下文中,它也称为模型选择。为了正确地做事,我们应该对训练数据、验证数据和测试数据进行三分:我们选择在验证数据上具有最佳性能的模型,并在测试数据上评估该模型,以获得最终(更现实)的性能估计。或者,如果我们愿意支付额外的培训费用,我们可以使用交叉验证。

交叉验证包括将“训练数据”分成 k 个折叠(我使用引号,因为说训练和验证数据更准确):我们训练 k 次,每次使用除了一个折叠之外的所有折叠进行训练(显示为绿色),剩余的一个折叠(显示为蓝色)进行验证。验证折叠在每次迭代之间旋转(在上面的视图中称为 split)。图片取自scikit-learn.org。
即使您对 ML 相对陌生,步骤 1 和 3 应该看起来很熟悉,但对步骤 2 来说不一定如此。这一步让数据科学家看起来像是在 excel 电子表格中打开他们的数据,手动更改数字,以便他们可以重新训练一个新模型,看看它的预测会发生什么。深呼吸:实际上根本不是这么回事。在实践中,步骤 2 几乎总是被跳过,因为步骤 3 已经可以告诉我们是否过度拟合以及过度拟合到什么程度,所以步骤 2 更像是描述如果我们的模型过度拟合会发生什么。在使用交叉验证时,从某种意义上说,您可能会认为第 2 步是在内部实现的,因为每次迭代之间的训练数据相差一倍。例如,在上面的视图中,迭代 4 和 5 中使用的训练数据集具有相同的折叠 1-3,但是折叠 4 和 5 在两次迭代之间交换。
如果有太多东西要打开,你不是唯一一个。有些微妙之处需要时间去理解。数据科学家倾向于反复无常地使用他们的术语,这也于事无补。例如,许多数据科学家交替使用测试数据和验证数据这两个词,并假设从上下文中可以清楚地看出这一点。这可能会让新的数据科学家感到困惑,但我希望您在阅读本文后不会感到那么困惑。
最后一点,对于神经网络,情况有所不同,但是如果有足够的兴趣,我将在后续文章中写这方面的内容。
偏差、一致性和为数据驱动的工作设计 KPI
我们将在本文中讨论“数据驱动”意味着什么,以及为什么坚实的统计基础是一个重要的因素。
一、关键绩效指标:数字胜于雄辩
假设你是初创公司雇佣的第一位数据科学家。他们没有数据驱动的文化或框架,这就是他们让你参与变革的原因。你从哪里开始?以下是您需要采取的步骤:
- 开始衡量:没有数据就不能被数据驱动。着手建立强大的数据收集渠道。例如,如果公司运营一个网站,记录用户做的任何事情。他们采取的行动、花费的时间等。然后需要将日志存储在某个数据库中。这是一项数据工程任务。数据科学家不应该害怕卷起袖子,帮助做一些事情。它可以是内部解决方案或工具,如谷歌分析或微软的 clarity 。
- 定义 KPI:术语 KPI 代表“关键绩效指标”。这是一个总结你所关心的健康状况的数字。静息心率是心脏健康的一个关键性能指标(大多数人会从降低心率中受益)。可以有不同的 KPI 来衡量不同的事物。为了保持事物的可解释性,它们最好是单调的。这意味着你总是想让他们更高或更低。比如每天新用户的数量。你会想尽你所能让它变得更高。这些 KPI 已经成为整个组织的通用语言。正在实施的所有计划都应与正在跟踪的核心 KPI 之一相关联。这有助于量化工作的影响和确定项目的优先级。仔细考虑 KPI 的行为方式及其属性非常重要。这就是统计估计理论的一些知识大有帮助的地方。
- 监控 KPI:一旦人们对 KPI 达成一致,你就可以从你建立的数据管道中想出计算它们的最佳方法,等等。是时候设置一些仪表板了,每个人都可以随着时间的推移直观地看到它们,看看它们的功能如何帮助移动它们等等。您已经为数据驱动型组织奠定了基础,每个人在日常生活中都需要您的数据。现在,您可以在 KPI 上设置监视狗,以便在出现突然变化时利用异常检测和警报。您可以设置受控环境来测量各种变化和功能对这些 KPI 的影响,并在统计实验设计和假设检验中应用您的专业知识。随着公司的发展,你可能会扩大团队来满足所有这些需求。
在本文中,我们将关注第二个要点,利用统计评估理论来设计可靠的 KPI。
二汇总统计:数据->数量
作为一名数据科学家,你必须获取数据库中的原始数据,并将其提炼为可操作的东西。通常,这包括将其总结为几个数字,每个人都可以理解,每个人都同意应该被驱动到一些目标值。大多数情况下,这些目标是“尽可能低”或“尽可能高”。例如,如果你想让你的网站的用户的页面加载时间低,平均加载时间可能是一个 KPI,你想把它变为零。所有 KPI 的共同主题是什么?
- 它们总是基于一些数据。
- 他们以某种方式将这些数据汇总成一个数字。
这些正是“汇总统计”的确切属性。它们是将您的数据作为输入并输出一个数字的函数。如果 x1,x2,…是你的数据点,T(。)是函数,t 是我们的汇总统计数据:
T(x1,x2,…) = t
由于几个世纪以来,人们在汇总统计理论及其属性方面投入了大量精力,因此将我们的 KPI 建立在这些理论的基础上是有意义的。在博客的其余部分,我们将互换使用这两个术语。
对数据的贪婪
每一个数据科学家都应该对数据充满贪婪。就像吸血鬼如果不总是渴望鲜血就不算是吸血鬼。假设您收集了一些数据,并基于这些数据计算了一个 KPI。然后你意识到,一些数据已经被删除了。您回溯步骤并设法恢复丢失的数据。然后,根据完整的数据集再次计算 KPI。很明显,基于较大数据集的第二个数字应该被认真对待,而第一个数字(基于较小数据集)应该被丢弃。这是因为更多的数据模糊地转化为更多的信息。
这个概念可以在决策质量方面具体化。如果你根据有更多数据支持的 KPI 来做决定,从长远来看,你会做出“更明智”的决定,因此会更“成功”。现在,这不是一个牢不可破的法律。很容易构建一个病理案例,收集稍微多一点的数据会有伤害。但从长远来看,更多的数据确实会给拥有它的人带来优势(所有其他因素,如数据的性质和质量是相同的)。
从这个思考过程的逻辑结论来看,它意味着最值得信赖的汇总统计数据是根据无限多的数据计算出来的。由于我们总是处理有限的数据,我们只能努力尽可能接近这个假设值。这个讨论中隐含的一个假设是,如果我们收集了无限量的数据,我们的汇总统计数据将具有某个固定值。这意味着它“收敛”于某个东西,当然不是所有汇总统计数据(甚至是大部分汇总统计数据)的情况。但是不有这个属性的汇总统计是没有目的的;不会真的去任何地方,所以,我们应该要求他们这样做。我们暗示的另一件事是,我们的汇总统计数据应该可以在越来越大的数据量上以合理的效率进行计算。
脚注 1:作为一个例子,考虑一个公平的硬币(同样可能正面或反面落地)。假设我们收集十次投掷的数据。不知何故,我们正好有五个头和五条尾巴。如果我们以逻辑的方式估计使用这个数据的头的概率(头的数量除以总投掷数),我们碰巧在正确的答案上是李子,0.5)。收集数据再折腾一次,只能让我们远离正确答案。即使我们收集了更多的数据,我们也不会比 10 次投掷做得更好。但是,我们看到这个数据,却无从得知硬币其实是公平的。它很可能是一个有 60%正面概率的硬币,碰巧给了你 5 个正面和反面。如果我们知道正面的真实概率,就没有必要抛硬币和收集数据了。鉴于我们依靠数据来估计硬币的真实性质,尽可能多地收集总是明智的。
脚注 2:这让人想起另一个行为类似的定律(依靠大量数据的统计特性),热力学第二定律。爱因斯坦宣称这是最不可能被任何东西取代的物理理论。
II-B 终极游戏:无限数据
我们已经将汇总统计描述为一个函数,它将您的数据作为输入,并生成一个标量作为输出。我们将此描述为:
T(x1,x2,…xn) = t
其中 T(…)是可以接受任意数量的数据作为输入的函数,T 是计算出的汇总统计数据。例如,我们可以定义:
T(x1,x2,…xn) =(x1+x2+…+xn)/n __(1)
这是样本平均值。或者我们也可以定义:
T(x1,x2,…xn) =x1 __(2)
或者
T(x1,x2,…xn) =7.5 __(3)
等式(2)中的汇总统计仅仅是样本中的第一个数据点,并且它具有不期望的属性。无论 n 有多大(收集的数据量),它都不会“沉淀”。如果你做了两次实验,每次都收集了大量的数据,你会得到不同的值,因为每次收集的第一个样本是不同的。我们可以说这个统计不收敛。
对于等式(1)中的统计数据(样本均值),每次我们收集(比如说)一百个数据点时,结果都会发生变化,但是随着我们收集的移动,对于大多数分布,结果开始收敛,并且我们开始在重复实验时获得一致的结果。
无论我们收集了多少数据,等式(3)中的统计量(仅 7.5)都是收敛的,但由于显而易见的原因,这是无用的。
很明显,我们希望我们的统计数据具有趋同性。这符合整个‘科学实验应该是可重复的’的理念。在统计学中,数据中固有的随机噪声使得这种可重复性变得困难,但是对于足够大的数据集的收敛保证应该是不可协商的。这使我们想到了我们希望汇总统计数据/ KPI 具有的最重要的属性。
三一致性
如果您设法找到一个收敛的汇总统计数据,如果收集了大量数据,它收敛到的值是生成数据的分布本身固有的一些属性。例如,无限量数据的样本平均值就是分布的真实平均值。在数据量有限的情况下(任何真实世界的情况都是如此),我们仅仅是在估计真实的平均值。在这个阶段,我们的汇总统计不仅仅是一个汇总统计(一个总结我们数据的数字),而是对数据之外的东西的估计。如果在收集大量数据时,估计量收敛于任何估计量,则称为一致估计量。任何汇总统计量都可以被标记为分布的任何属性的估计量。例如,等式(2)中的汇总统计量是分布平均值的估计量。但是它不是一个一致的估计量,因为即使对于一个无限的样本,它也不能决定真实的平均值(不能决定任何事情)。成为一个“估计者”是给汇总统计一个目的。我们的 KPI 应该是汇总统计数据,用于估计我们想要测量的系统的一些固有属性。
III-A 不一致的例子
对大多数分布一致的估计量是样本均值。事实上,这大致就是统计学的大数定律所说的:样本均值收敛于真实均值。也就是真正的中庸存在的时候。作为病理情况的例子的分布是柯西分布,其中真实均值不存在(它不会爆炸或任何东西,只是真正不存在)。如果我们从该分布中收集一些样本,并根据它们按照等式(1)计算样本均值,那么无论我们收集多少样本,它都不会收敛到任何值,而是随机跳跃。另一个均值不存在的分布是形状参数为< 1 的洛马克斯分布。在这种情况下,它会爆炸到∞。
另一个对大多数分布收敛的汇总统计是中位数。它被定义为这样一个点,使得随机样本高于或低于它的可能性相等。为了从数据的随机样本中估计它,我们取样本的“中点”:
- 按升序排列数据。
- 如果样本数为奇数,则第 n 个位置的点为中值,否则为第 n 个和第(n+1)个点的中点。
上述汇总统计将收敛到为大多数分布生成数据的分布的真实中值。当样本是伯努利随机变量(可以是 0 或 1,每个概率为 0.5)时,就会出现病理情况。不管收集了多少样本,上面描述的汇总统计同样可能是 0、1 或 0.5。因此,当我们增加样本量时,它不会收敛到一个单一的数字。结论是,几乎总是可以构建一个病理分布,使得任何汇总统计数据都不会收敛。
仅有 III-B 一致性是不够的
对于分布的任何给定性质,可能有许多相一致的估计量。例如,如果我们想估计一个分布的平均值,我们从它那里收集一些样本,对它们进行平均,得到样本平均值:
T(x1,x2,…xn) =(x1+x2+…+xn)/n __(1)
对于大多数分布来说,均值实际上是存在的,根据大数定律,当 n → ∞时,样本均值将收敛到真实均值。但这里有另一个估计平均值的汇总统计数据:
T(x1,x2,…xn) =(x1+x2+…+xn)/(n+1)
这也符合吗?当 n → ∞时会发生什么?分母中的(n+1)也可以是 n,因为与大的 n 相比,1 可以忽略不计。因此,该估计量也收敛于真实均值,并且也是一致的。同样的道理,我们可以把分母中的 n 和任何有限的数相加,最终仍然得到一致的估计量。
我们也可以忽略一些样本,把它们从分子中的和中省略掉。这也不会使估计量不一致,因为当 n 趋于无穷大时,一些丢失的样本没有影响。
如果上面讨论的所有估计量都是一致的,我们如何在它们之间进行选择?虽然一致性是我们希望所有评估者都具备的,但我们还可以要求其他东西。大多数这些会告诉我们,方程中的估计量是这里讨论的所有估计量中“最好的”。
IV 无偏性
我们看到了估计量的一致性是一个重要的属性,它促进了可重复性的科学租户(至少如果收集了足够的样本)。但是这还不足以确定最好的评估者或者排除一些明显不好的评估者。在这一节中,我们将讨论一个标准,它确实有助于我们排除除一个估计量之外的所有估计量。它被称为 UMVUE 标准,在拼写时也会发出令人愉快的声音。
IV-一个简单的无偏性
一致性的性质是指当收集的样本数量足够大时,估计量的行为。在现实世界中,我们总是在处理数量有限的数据。有限的样本量意味着我们的估计器可能不会直接到达它所估计的任何数量。我们从汇总统计中得到的数字将是“off”;它会有一些误差(比如 e)。此外,这个误差是一个随机量(如果不是,我们就从我们的汇总统计中减去它,就不再有误差了)。如果我们用相同的样本量重复实验(或者考虑在平行宇宙中进行的实验),我们将得到这个误差的不同值。因此,误差项是产生样本的分布、样本数量以及我们用来将样本汇总成一个数字的汇总统计量的函数。处理嘈杂的误差项是工作描述的一部分。我们可以退而求其次,研究它的性质。一致性要求要求随着收集的样本变得足够大,误差变为零。无偏性要求要求即使对于有限的样本,误差平均为零。如果这个平均值不为零,那么它的值就叫做估计量的偏差。
让我们回到我们在第 III-B 节中讨论的一些例子。如果我们收集 n 个样本,并基于它们计算样本均值,我们会得到真实均值的一致且无偏的估计值。另一种估计方法是在分子或分母(或两者)上加一个有限的数。
T(x1,x2,…xn)=((x1+x2+…+xn)+C1)/(n+C2)_(4)
如果 c1 和 c2 都为零,我们将得到常规样本均值。同样清楚的是,只要 c1 和 c2 是有限的,估计量仍然是一致的(因为大的 n 将使 c1 和 c2 不相关)。但是无偏性呢?这次我们不能指望 n 是大的,因为无偏性对任何 n 都成立(不仅仅是大的)。不难看出,使等式①中的估计量对所有 n 都无偏的唯一方法是 c1=c2=0。因此,无偏性的额外要求帮助我们排除了一整族都一致的估计量。另一方面,在一个估计量中,除了有限数量的样本之外,我们去掉了所有的样本;例如:
T(x1,x2,…xn)= (x1+x2)/2
或者
T(x1,x2,…xn) = x1
将是无偏的,但不一致,因为无论 n 变得多大,仍会有一些噪声。这是否意味着一旦我们既考虑无偏性又考虑一致性,样本均值是唯一仍然有效的估计量?不完全是。
最小方差无偏估计量
如果我们决定取出有限数量的样本,取剩下的样本的平均值,会怎么样?比方说,我们总是去掉前两个样本:
T(x1,x2,…xn)=(x3+x4+…+xn)/(n-2)_(5)
首先,如果我们有两个或更少的样本,这种估计就失效了,而样本均值(来自等式①)甚至对一个样本也有效。但是让我们先把这个放在一边,假设我们总是有三个或更多的样本。
等式(5)中的估计器正在做与等式①几乎相同的事情,但是在丢弃一些数据之后。所以,它在某些可量化的方面一定是次等的。然而,它检查盒子是否一致和公正。它的不足之处在于方差更大。如果在给定的有限样本量下多次运行该实验,则等式(5)中的估计值将比等式(1)中的样本均值“波动”更多,即使它们的平均值都是真实均值。
这就是最小方差无偏估计量概念的由来。可能有许多无偏估计量,并且它们可能都是一致的,但是对于任何给定的样本量,只能有一个无偏估计量具有最小的方差。不难看出,在本节考虑的所有估计量中(这些估计量基本上以某种方式损害了样本均值),等式①中的样本均值对于生成数据的所有基础分布具有最低的方差。对于正态分布,它具有任何无偏估计量的最小方差,周期。然而,如果生成样本的基础分布是均匀的,则有另一个估计器的表现也比样本均值更好,它是无偏的,但具有更小的方差(见此处)。
为什么不偏倚
不清楚无偏性是不是我们应该一直争取的东西。当然还有其他评估标准(比如效率,我们在这里不讨论)。但我认为这是 KPI 背景下值得追求的东西。我们之前讨论过,我们希望我们的 KPI 是一些潜在属性的估计值的汇总统计。我们也希望估计量是一致的。这必然意味着,随着样本数 n 的增加,任何偏差都应趋于零。这种偏差最终趋于零的特性被称为“渐近无偏性”。如果我们不要求 KPI 的无偏性,当样本数 n 很小时,可能会有一些非零偏差。但是,当 n 趋于无穷大时,偏差将减小到零(因为我们确实需要一致性,这需要渐近无偏性)。因此,增加 n 将导致 KPI 的系统性变化。这一点在 V-B 部分的图 1 中得到了证明,即样本中位数,一个有偏估计量。
这种运动是不受欢迎的。这意味着,即使基础分布(比如你的平台性能或其吸引新用户的能力)没有改变,我们也可以注意到 KPI 的系统性变化,因为我们收集了不同数量的样本。由于我们将跟踪这些 KPI,并在人们移动时提醒他们,这是有问题的。我们不希望对一些系统性的运动发出警报,因为这种运动的唯一原因是我们收集了或多或少的数据。
在无偏估计量中,方差最小的估计量应该是首选的。当单个估计量保证在被估计的潜在参数的所有可能值上具有最小方差时,它被称为“一致最小方差无偏估计量”或 UMVUE。
五.更多例子
到目前为止,我们已经讨论了样本均值的变异估计量。显而易见的估计量(样本均值本身)被证明是正确的。再来说几个事情不太明显的地方。
正态分布的方差
正态分布可能是统计学中最著名的。中心极限定理,即无论单个样本的分布如何,足够大数量的 iid 样本的平均值都接近它,这赋予了它一种无处不在的特性。
它完全由两个参数确定,均值和方差。我们前面提到过,样本均值是真实均值的最小方差无偏估计量。对于方差,有一个转折。因为它被定义为平均值的均方差,所以显而易见的是:
- 先求样本均值(μ1)(估计真实均值,我们不知道)。
- 计算每个点和样本平均值之间的差异。
- 计算所有这些差值的平方,然后取这些平方的平均值。
我们称这个估计量为σ1 = ∑(xi-μ) /n。事实证明,这是真实方差σ的有偏估计量。如果我们除以 n-1 而不是 n,我们可以“修复”这个问题并消除偏差。这导致另一个估计量 s 恰好是无偏的:s = ∑(xi-μ) /(n-1)。要了解为什么会出现这种情况,请参见这里的。它也是正态分布方差的 UMVUE。
V-B 中位数
我们在第 III-A 节中把中位数描述为分布中的一个点,使得从中随机抽取的样本有可能小于中位数,也有可能大于中位数。所以,“将分布减半”的观点。对于许多分布来说,样本中位数是一个有偏估计量。如果分布是对称的(像正态分布),这不是问题。但是在大多数情况下,我们会计算中值,这些数量总是正的(比如延迟,人的高度,等等)。).并且这种分布必须是非对称的,因为它们的右尾趋向于无穷大,而左尾在零处有界。用于描述总是为正的数量的一个流行分布是对数正态分布。在下图中,我从对数正态分布中抽取了一些样本(如图所示)。然后,我重复这个实验 10 万次,估计每次的中间值。这 100,000 个中间值绘制在直方图中。它们的平均值以紫色显示,真实的中值(我知道,因为我生成了数据)以黑色显示。您可以看到,紫色线从正偏差开始,随着收集的样本数量的增加,该偏差减小到零(渐近无偏)。

图 1:随着样本量的增加,中位数偏差缩小。一些样本(如图所示)是从对数正态分布中产生的。对于每个样本大小,该实验重复 100,000 次,并将 100,000 个中值绘制在直方图中。这 100,000 个中间值的平均值是紫线,而真正的中间值是黑线。
我在下面包含了用于生成该图的代码。
点过程的 V-C 失效率
到目前为止,我们已经讨论了根据样本(x1,x2,…xn)收集的数据。这些可能是某些操作、评级等的等待时间。为了说明数据有不同的风格,考虑一下一段高速公路上的事故数量。对于高速公路的设计者来说,一个很好的 KPI 是事故发生率(比如每年的事故数量)。在这种情况下,数据的单位是观察窗的长度。再比如,我目前在微软 Azure 做数据科学家。我们的客户从我们这里租赁虚拟机。我们担心这些虚拟机中的崩溃(一种点过程)。我们使用的一个关键 KPI 是我们看到崩溃的比率;每虚拟机小时的崩溃次数。数据收集的单位是观察到的虚拟机小时总数,崩溃率的估计值是观察到的崩溃总数除以同一观察期间的虚拟机小时总数。更新理论中有一个定理(布莱克威尔定理)说,这是一个对各种各样的点过程的真实失效率的无偏估计量。
使用 Amazon SageMaker Clarify 的机器学习模型中的偏差检测
原文:https://towardsdatascience.com/bias-detection-in-machine-learning-models-using-amazon-sagemaker-clarify-d96482692611?source=collection_archive---------10-----------------------
理解 AI/ML 环境中的偏差,它可能发生在 AI 生命周期的什么地方,面临的挑战,以及如何使用 SageMaker Clarify 来检测数据集和 ML 模型中的偏差

来源:https://unsplash.com/
1.介绍
你的 AI 解决方案公平可信吗?
如果几年前有人问这个问题,那么他/她很可能不会被重视。
传统上,人工智能/机器学习解决方案的重点一直是开发新算法和优化现有模型以提高性能准确性。
我们假设人工智能模型的决策是公平的,人们可以信任它。
然而,最近的一些实例已经挑战了人工智能模型的公平概念。
亚马逊人工智能招聘也被发现没有公平地评价候选人,并显示出对女性的偏见。(链接
基于人工智能的预测刑事再犯风险的解决方案被发现可以预测黑人被告的更高风险值。(链接)
一种旨在预测哪些患者可能需要额外医疗护理的医疗保健风险预测算法被发现存在偏见,白人患者比黑人患者更受青睐。(链接)
在上述所有例子中,AI solution 做出的决定都是有偏见的。模特不应该根据自己的种族、性别、宗教或社会经济背景来做决定。
重要的问题是,我们能做些什么来确保人工智能/人工智能解决方案没有偏见。朝着这个方向的第一步是意识到我们的数据和算法中存在偏见,然后采取措施减轻偏见的影响。
在这项研究中,我们重点了解人工智能和人工智能解决方案中存在的意外偏差,它在人工智能生命周期中的表现,识别偏差的挑战以及领先的云供应商为该问题提供的工具和技术。然后,我们应用 AWS SageMaker Clarify 来检测真实世界数据集和基于这些数据集训练的模型上的偏差。
2.AI/ML 生命周期中的偏差
什么是 AI 偏见?
偏见没有单一的定义,可以根据问题的背景有不同的含义。我遇到过一个这样的定义,它指出“人工智能偏见是机器学习算法输出中的异常现象。这可能是由于算法开发过程中的偏见假设或训练数据中的偏见。”
AI 偏差的来源有哪些?
人工智能偏见可以在许多方面表现出来。下面我们描述 AI/ML 模型中偏差的重要原因

来源:图片由作者提供,灵感来自论文《金融领域机器学习的公平标准》
哪里出现偏差
为了有效地识别偏见,我们需要在人工智能生命周期中寻找偏见的存在。

来源:作者图片,灵感来自https://docs . AWS . Amazon . com/sage maker/latest/DG/clarify-fairness-and-explability . html
预训练阶段的偏差
1.训练数据创建期间的偏差检查需要验证数据是否没有任何选择偏差,是否代表不同的细分市场;创建的数据标签和要素没有偏见
模型训练中的偏差&验证
2.最近,在开发公平性度量方面已经做了大量的工作。这些公平性指标包含在算法的目标函数中吗
3.我们的模型验证和测试管道是否包括对相关公平性指标的检查
模型部署期间的偏差
4.一个在开发和验证时没有偏差的模型,如果用于对未经训练的数据进行预测,可能会给出有偏差的结果。我们是否包括检查以确定这一点
模型监控期间的偏差
5.我们如何减轻模型部署后可能随着时间推移而产生的偏见的影响?是否创建了反馈循环来跟踪随时间的漂移,并将这些反馈发送给算法进行自我修复?
3.偏差检测的主要挑战

来源:图片来自作者,灵感来自论文《数据驱动的人工智能系统中的偏见》
大体上,我们可以将这些挑战分为四类:
1.*数据收集:*在为模型构建任务收集数据时,通常没有关于代表性不足的细分市场的足够数据。这导致了选择偏差。此外,随着众包数据的日益流行,人们需要考虑数据和标签创建者的个人偏见。
2.*敏感特征*:我们如何识别可能导致意外偏差的敏感特征。目前还没有标准的方法来帮助识别这些敏感特性,我们依靠探索性分析和领域知识来识别这些特性。
3.*多模态数据:*当前许多识别和减轻偏倚的方法都是为结构化数据建立的。但越来越多的人工智能解决方案是在包括文本/图像/视频在内的多模态数据上进行训练的。需要加强偏差检测能力以处理多模态数据。
4.复杂特征工程:特征工程改善了模型性能,但同时复杂特征很难追溯到起源。当我们在处理当代 NLP 和计算机视觉解决方案时,这一挑战会变得更大,在这些解决方案中,来自开源数据的预训练嵌入非常普遍。
4.云供应商的偏差检测产品
下面,我们确定了来自领先云供应商(如 IBM、微软、AWS)的著名偏差检测工具包。这些工具包与供应商提供的其他 AI/ML 产品很好地集成在一起。
IBM**:****AI Fairness 360 toolkit(AIF 360)**是一款开源软件工具包,可以帮助检测和消除机器学习模型中的偏见。AIF360 使人工智能开发人员和数据科学家能够轻松检查他们机器学习管道中多个点的偏差,根据他们的情况使用适当的偏差度量。它还提供了一系列最先进的偏差缓解技术,使开发人员或数据科学家能够减少任何发现的偏差。
微软 : Fairlearn 是一个开源工具包,让数据科学家和开发人员能够评估和改善他们的人工智能系统的公平性。它有两个组成部分:一个交互式可视化仪表板和不公平缓解算法。这些组件旨在帮助在公平性和模型性能之间进行权衡。
AWS : 亚马逊 SageMaker Clarify 为机器学习开发人员提供了对其训练数据和模型的更大可见性,以便他们可以识别和限制偏差并解释预测。通过检查您指定的属性,Clarify 服务有助于在数据准备期间、模型训练之后以及您部署的模型中检测潜在的偏差。它还提供了量化不同类型的可能偏差的详细报告。
5.使用 AWS SageMaker Clarify 进行偏差检测
为了证明偏差检测解决方案的有效性,我们将 AWS SageMaker Clarify 应用于两个数据集的偏差检测:
i)问题陈述:
- 识别数据集中的偏差
- 识别模型预测中的偏差。
二)数据来源:
Dataset1 是一个 Kaggle 数据,用于测量印度不同邦的不同电信运营商在 4G、3G 等电信网络中的掉话率,测量时间为一个月。

来源:取自 Kaggle 的样本数据
数据集 2 是模拟投资世界中真实数据集的合成数据。对于那些对合成数据感兴趣的人,请参考我之前关于该主题的博客。

来源:综合数据,图片由作者提供
iii)使用 SageMaker Clarify 进行偏差检测的解决方案:
我们利用 SageMaker Clarify 来确定上述两个数据集的偏差。下面是数据集中偏差检测的高级解决方案。

来源:作者图片
第一步,我们识别那些可能导致偏差的属性。这些属性可能与性别、年龄、国籍等有关。
二。一旦我们确定了敏感属性,我们就确定了这些属性中代表不受欢迎群体的值的范围。
三。敏感属性和敏感值被提供给偏差算法。
四。在偏差算法中,数据集根据指定的敏感要素和值分为受欢迎组和不受欢迎组。
动词 (verb 的缩写)进行统计测试,并为偏差检测计算训练前和训练后的度量。基于对统计指标的解释,我们确定是否存在偏差。
四)探索性分析结果:
在偏倚检测过程之前,对两个数据集进行了数据探索。
***数据集 1***
我们观察到数据集 1 有更多来自一些优势群体的观察结果。大多数数据是针对 4G 网络测量的,几乎 80 %的观察结果是客户对掉话感到满意的。

来源:作者图片,数据集 1 的探索性分析
**数据集 2:**
数据集 2 是经过清理和归一化的合成数据。我们删除了一些可以识别最终客户的敏感属性,并使用 SMOTE(一种合成过采样方法)平衡了训练数据。

来源:作者图片,数据集 2 的探索性分析
v)偏差检测结果
**a)数据集 1 上的偏差检测结果**
对于数据集 1,我们使用敏感属性检查偏差的存在,如具有较少观察值的网络类型、代表不足的州以及订户较少的运营商。
对于大多数敏感特征,我们发现统计指标如 KL 散度、JS 散度(测量不同组的结果分布在熵上彼此偏离多少)是显著的,从而表明数据中存在偏倚。我们还发现了 CDDL 度量的统计显著值,该度量通过数据的子组来测量差异。

来源:作者提供的图片,来自数据集 1 的预训练指标的偏差检测结果
下表有助于解释上面分享的一些培训前指标:

来源:AWS Image,https://docs . AWS . Amazon . com/sage maker/latest/DG/clarify-measure-data-bias . html
基于对上述预训练指标**的解释,我们得出结论,在数据集 1 中存在显著偏差。**由于在数据集 1 中发现了明显的偏差,我们没有继续在该数据上建立模型。
**b)数据集 2 上的偏差检测结果**
对于数据集 2,我们对敏感属性进行了偏差测试,如年龄和某些标识金融产品来源的标志。
以下是我们在上述测试中获得的一些预培训指标结果。

来源:作者图片,澄清偏差检测的预训练结果
我们在敏感特性的大多数统计指标中没有发现明显的偏差。这可能是由于数据是合成产生的,并且我们在偏差检测之前应用了平衡和标准化技术。唯一可见的偏差是在阶层不平衡指标中,该指标衡量不同群体之间成员数量的不平衡。
由于在数据集 2 中没有发现**偏差,我们继续在数据上训练了一个分类模型,该模型预测客户选择给定产品的倾向。对生成的模型预测进行了偏差检测测试,以下是训练后指标的结果**

来源:作者图片,培训后偏差指标的结果
下表有助于解释上面分享的一些培训后指标

来源:图片 AWS,https://docs . AWS . Amazon . com/sage maker/latest/DG/clarify-measure-post-training-bias . html
根据培训后指标的结果,我们得出结论,模型预测中不存在任何重大偏差。
6。未来的挑战
为了更广泛地采用偏置检测解决方案,仍然需要应对一些公开的挑战,如下所示:
目前,偏见和公平的概念高度依赖于应用程序,没有一个统一的方法可以应用于一个问题。
没有商定的方法来选择衡量偏差的属性。
在选择用于测量偏差的特定预训练偏差度量时缺乏标准化;这仍然受到社会、法律和其他非技术因素的指导
需要进一步研究图像/文本/视频等非结构化数据的偏差识别。
7。参考文献
- 亚马逊 SageMaker Clarify—https://docs . AWS . Amazon . com/SageMaker/latest/DG/Clarify-fairness-and-explability . html
2)**AI Fairness 360**-https://developer . IBM . com/technologies/artificial-intelligence/projects/AI-Fairness-360/
- 金融领域机器学习的公平性度量—https://pages.awscloud.com/rs/112-TZM-766/images/Fairness.Measures.for.Machine.Learning.in.Finance.pdf
4)fair learn—https://www . Microsoft . com/en-us/research/publication/fair learn-a-toolkit-for-assessing-and-improving-fair-in-ai/
偏向于艾, 偏向于 https://research.aimultiple.com/ai-bias/
数据驱动的人工智能系统中的偏差 —介绍性调查—https://arxiv.org/pdf/2001.09762.pdf
免责声明:本文分享的观点是我个人的观点,不一定代表富达国际或任何关联方的观点。
人工智能系统中的偏见及其解决方法
原文:https://towardsdatascience.com/bias-in-ai-systems-and-efforts-to-fix-it-318798f5b39f?source=collection_archive---------35-----------------------
理解人工智能系统中的种族和性别偏见是如何发生的,以及如何解决它们

杰西卡·菲利西奥在 Unsplash 上的照片
2019 年 4 月,纽约大学的 AI Now Institute 发布了一份关于人工智能系统中偏见的影响的报告。大约 12 个月后,你可能还记得当一个人工智能模型将巴拉克·奥巴马的像素化图像变成这位前总统的更高分辨率图像时,Twitter 引起的风暴。除了当模型得到一个黑人的像素化图像时,它返回一个白人的高分辨率图像。这是 AI Now 研究所在 NYU 报告中详述的偏见的一个典型例子。随着我们越来越多地将人工智能系统融入我们的日常生活,我认为描述这些问题并就如何解决这些问题展开对话是至关重要的。在我们了解这些偏见是如何产生的以及需要采取什么措施来解决它之前,我们先来快速了解一下有监督的机器学习算法是如何工作的。
有监督的机器学习算法是如何工作的?
监督机器学习算法的目的是学习一个函数,该函数最接近输入数据和目标数据之间的关系。监督学习算法从带有期望输出的标记为的给定训练数据集中学习。一个好的算法必须是可推广的,这意味着它必须能够根据在训练数据中学习到的内容来准确预测新数据的输出。如果输入的新数据包含以前在训练数据集中没有看到的特征,人工智能将很难对这些新数据进行分类。如果这一切听起来有点抽象,这里有一个简单的例子。假设您想要训练一个 ML 模型来分类照片中是否有马或狗。在训练数据集中,你给它提供了成千上万张带有标签的吉娃娃和种马的图片。如果你给你的模型看一张大丹犬的图片,它很可能会误认为是一匹马。该模型对所有犬种不够通用,因为它没有用其他犬种的图像进行训练。
ML 模型中偏差是如何产生的?

马库斯·斯皮斯克在 Unsplash 上的照片
简单的答案是,有偏差的 ML 输出是由于有偏差的训练数据而产生的。当然,数据本身并不存在固有的偏差,人工智能中出现偏差的真正原因是,负责提供训练数据的人存在偏差,或者未能注意到他们数据中的偏差。
未能注意到有偏差的数据是一个微妙的概念,但会导致与不小心收集有偏差的数据一样糟糕的结果。看看亚马逊 2015 年的招聘工具就是一个经典例子。该工具旨在更好地自动选择公司招聘的最佳候选人。这位模特显然是在十年前接受过 CVs 训练的。理论上,到目前为止一切顺利。简历库中应该有各种各样的人。事实并非如此,2005 年申请这些职位的人比 2015 年更加偏向男性。最终结果是该工具被发现对完全合格的女性有偏见,当事情变得明显时,亚马逊很快放弃了整个项目。就模型而言,男性是这项工作的最佳候选人,因为所有的训练数据似乎都表明了这一点。
人工智能中出现偏见的另一个原因是建立这些模型的公司缺乏代表性。以下是 AI Now 研究所报告中的一些统计数据;人工智能的教授 80%是白人男性;在谷歌、脸书和微软之间,没有一家公司的黑人员工比例超过 4%。该领域的女性人数同样惨淡,尽管推动了更多女性进入科技行业。此外,该领域的人往往很富有,这就带来了潜在的社会经济偏见
我们如何解决这个问题?

照片由克里斯蒂娜@ wocintechchat.com在 Unsplash 上拍摄
我认为,解决这个问题的第一步是承认这个问题。我在这里看到了令人鼓舞的迹象,因为人工智能专业人士和机构似乎认识到了这些问题,并正在努力解决这些问题。应对人工智能系统中的偏见的另一个步骤是,在开发和分发系统的公司的所有级别中,纳入受到偏见的人。对这些公司领导职位的需求有偏见的团体。一些科技公司的少数群体、女性和残疾人的数量似乎在朝着正确的方向发展,但不清楚这些人中有多少人能够做出影响其产品偏见的决定。
结束语
像我们社会的许多领域一样,我们在人工智能系统中看到了不可接受的偏见。这是一个需要尽快解决的问题,因为这些系统融入了我们生活的更多方面,公司使用它们来做出影响整个社区的决策。令人鼓舞的是,AI Now Institute 等人工智能研究机构认识到了这个问题的严重性,并致力于解决这个问题。现在,科技公司有责任在领导岗位上增加女性、有色人种和残疾人的代表,并赋予他们权力,成为解决人工智能偏见的一部分。
我将留给你们一段我认为是来自艾安娜·霍华德教授和 T2 教授讨论人工智能种族偏见的有力的引用。
“有时有色人种在场,而我们没被发现。其他时候我们失踪了,但是我们的缺席没有被注意到。这里的问题是后者。”
数据集中的偏见:新冠肺炎案例研究
原文:https://towardsdatascience.com/bias-in-your-datasets-covid-19-case-study-d065aa698b74?source=collection_archive---------31-----------------------
偏见如何通过过度拟合来影响深度学习模型的性能?让我们关注医学图像的模型可解释性。

胸部 x 光打开快门架
动机
在过去的几年里,大量的实验显示了人工智能(AI)在医学成像服务中的兴趣,特别是在放射学中。这是由于大型数据集的可用性、计算能力的巨大进步以及新的深度学习算法的出现而成为可能。然而,由于这些人工智能算法在实验阶段和真实条件下的实现之间的性能退化,这些技术今天没有广泛普及。对这一现象的解释之一与过度拟合有关:该算法不会在新数据上广泛传播。
在这个项目中,我们想说明偏倚如何显著影响胸部 X 射线(CXR)图像分类模型的性能。除了对数据集进行简单的探索性分析,我们试图证明这些偏差的存在,并对其进行表征。
主要目的是开发一种算法,该算法将从 CXR 图像中预测患者是否患有病毒性肺炎、新冠肺炎或无病(正常)。在这种情况下,使用了这三类中每一类的 CXR 图像的三个数据集,即具有平衡分布的 3886 个射线照相图像:新冠肺炎射线照相数据库【1,2】。

包含 3 个类别的数据集:COVID、NORMAL、PNEUMO(作者提供的图片)
作为深度学习领域的新手,我们选择了一个简单的 CNN 模型来实现(LeNet)两个卷积层。你猜怎么着,我们得到了 97%的测试准确率🎊!

使用 30 个时期的(LeNet)模型实现 97%的准确性(图片由作者提供)
我们没有公布 2021 年诺贝尔医学奖的结果,而是问了自己以下问题:
用一个简单的 2 层卷积神经网络模型检测胸部疾病几乎有 97%的准确率是对的吗?
答案是否定的 。这就是为什么在训练迁移学习模型之前,深入研究数据集的偏差并尝试纠正它们是非常重要的。
我们的数据集中存在哪些偏见?
第一步是试图找出图像的差异和异质性。为此,比较了正常图像和 COVID 图像之间的亮度分布。

Covid/正常图像的亮度分布(图片由作者提供)
观察到亮度分布的显著差异。因此,这个全局特性足以以“正确”的方式区分这两个类别,并为我们之前注意到的高性能提供了第一个解释(LeNet)。
让我们进一步分析…
为了可视化数据集的偏差,我们已经开始寻找可以将 3 个类分开的局部特征。想法是将图像投影到更小的维度空间中,以观察 3 个类别的图像中的趋势。为此,图像被调整为 28x28:

CXR 图片尺寸调整为 28x28 像素(图片由作者提供)
由于缺乏细节,理论上不可能检测出 covid 或肺炎。
t-SNE 算法[3]是一种非线性聚类方法,可以通过连续迭代在二维或三维空间中表示一组高维空间的点。然后,数据可以以点云的形式可视化:

用 t-SNE 算法可视化高维数据(来自https://zaburo-ch.github.io/images/mnist_process.gif
t-SNE 应用了像素强度的两个分量,数据集显示在这两个轴上。令人惊讶的是,使用无监督聚类方法和没有细节的图像,可以在 2D 投影上区分 3 个类别!

数据集的 t-SNE 可视化,然后进行 SVM 分类(图片由作者提供)
事实上,通过在对应于两个 t-SNE 轴的两个变量上应用 SVM,获得了 84%的准确度。
t-SNE 算法似乎可以从 28x28 的非细节图像中提取重要信息,使其能够进行良好的分类。为了便于解释,让我们用 PCA 做同样的事情。

数据集的 PCA 可视化(图片由作者提供)
投影的效率低于 t-SNE 方法,但我们注意到第一模式(x 轴)可以正确地将 Covid 图像与非 Covid 图像分开。根据这一观察,我们可以显示向量“pca.components_[0]”,仅取系数的绝对值,并查看 28x28 热图:

第一个 PCA 组件的热图(图片由作者提供)
从上面的投影(第一主成分)可以看出,重要的像素位于图像的左右边缘。因此,边缘的亮度使我们能够正确地将数据集中的 covid 图像与非 covid 图像分开,这在我们的研究中代表了一种真正的偏差!
让我们更进一步…
对神经网络最常见的批评是难以提取和以人类可读的形式解释决策过程。它们通常被视为“黑匣子”。但这还不包括最近解决这个棘手问题的出版物:
卷积神经网络如何决定?
Grad-CAM 是 2017 年发布的一种方法[4],有助于解读 CNN 的结果。它通过计算从决策反向传播到最后卷积层的梯度,提供由神经网络确定的类别的激活图:

Grad-CAM 架构(图片由作者提供)
Grad-CAM 算法应用于具有 12 个随机 COVID 图像的第一个原型(LeNet ),激活图向我们显示网络主要使用图像的边缘来做出决策,而不是在肺部内部寻找有用的信息:

绿色/黄色区域是基于网络决策的感兴趣区域,蓝色区域是不感兴趣区域。(图片由作者提供)
如何纠正这些偏见?
在对数据集的偏差进行分析后,我们观察到分类算法主要基于图像边缘的像素来做出决定。因此,我们的想法是去除这些边缘,并且只关注具有分类所需信息的肺。
这需要使用一个 U-Net 神经网络,该网络是根据 CXR 图像预先训练的,是专门为肺部分割开发的。

U-Net 架构(图片由作者提供)
下面的序列说明了经过所有预处理方法后的图像转换:

细分渠道(图片由作者提供)
分割后,图像在肺部周围以 10 像素的边缘被裁剪。
然后,均匀化和裁剪后的图像用于构建我们的新数据集,以训练和测试深度学习模型。

预处理前后(图片由作者提供)
最后,它有用吗?
通过对裁剪后的图像应用 t-SNE 方法,仍然可以在数据集中观察到偏差,因为无监督算法仍然能够分离类别😭:

预处理数据集上的 t-SNE(图片由作者提供)
预处理图像的迁移学习
测试了两个迁移学习模型:DenseNet121 (121 个卷积层😮)和 VGG16 架构,两者都在庞大的 Imagenet 数据集上进行了预训练。
PS:因为 CXR 是黑白的,所以在输入之后插入了一个卷积层来给图像“上色”。

训练参数和准确度(图片由作者提供)
两个迁移学习模型的准确性低于 LeNet 的准确性,但是 Grad-CAM 激活图向我们显示,他们主要是在肺部做出决定。

Grad-CAM 激活图应用于 VGG16,经过预处理(图片由作者提供)
您还可以使用您的图像测试这 3 个模型,并通过以下地址提供的 Streamlit 应用程序观察 Grad-CAM 激活图:https://studio.datascientest.com/project/covid/。
结果
- 通过 t-SNE 和 PCA 方法降维突出数据集偏差。
- 通过分割肺来均衡直方图和从图像中去除边缘的流水线的开发。
- 用(Densenet121 和 VGG16)迁移学习。
- 使用最近的 Grad-CAM 方法可视化神经网络类激活图。
思想
- 通过对每个类别使用不同来源的新图像,纠正预处理后仍然存在的偏差。
- 通过训练更多的 epochs 和解冻预训练网络的一些层来继续优化网络性能。
- 与放射科医生合作,评估 grad-CAM 卡在患者图像上的适用性
- 除了图像之外,将患者信息添加到模型中:症状、病史、年龄、性别、位置、日期等;以便使该模型更加稳健并忠实于实际的医学诊断。
道德
拥有出色的性能是没有意义的,你必须限制数据集中的偏差!
在深度学习中,决定算法是什么的主要是数据。
作者
巴蒂斯特·莫罗:领英
查迪·马斯里:领英
卡莉玛·本尼亚:领英
参考
[1] CHOWDHURY,Muhammad EH,RAHMAN,Tawsifur,KHANDAKAR,Amith,等AI 能否帮助筛查病毒性和新冠肺炎肺炎?。 IEEE Access ,2020 年,第 8 卷,第 132665–132676 页。
[2] RAHMAN,Tawsifur,KHANDAKAR,Amith,QIBLAWEY,Yazan 等.利用胸部 X 射线图像探索图像增强技术对新冠肺炎检测的影响.生物学和医学中的计算机,2021 年,第 132 卷,第 104319 页。
[3]范德马腾,劳伦斯和辛顿,杰弗里。使用 t-SNE 可视化数据。机器学习研究杂志,2008 年,第 9 卷,第 11 期。
[4] SELVARAJU,Ramprasaath R .,COGSWELL,Michael,DAS,Abhishek,等. Grad-cam:通过基于梯度的定位从深度网络进行视觉解释.IEEE 计算机视觉国际会议论文集。2017.第 618-626 页。
偏差方差权衡
原文:https://towardsdatascience.com/bias-variance-trade-off-7b4987dd9795?source=collection_archive---------22-----------------------
了解偏差、方差和总误差与模型复杂性和过度拟合/欠拟合的关系。

马克西姆·霍普曼在 Unsplash 上的照片
偏差-方差权衡是机器/深度学习领域的每个人都应该知道的重要概念。无论您计划将模型应用到哪个应用领域,这些概念都将帮助您采取措施,潜在地解决为什么您的模型在您的训练或测试集上表现不佳的问题。
引言[1]
偏差方差权衡将帮助我们理解模型对训练数据过度拟合和欠拟合的概念。我们将能够判断我们的模型是否能够将误差降低到特定值以上。
在开始偏差和方差的概念之前,我们将看看 ML/DL 模型作为一种估计基础函数的方法。
机器学习以及深度学习中的一般任务是从训练数据中估计底层函数。我们将使用下面的符号。
- f(x) :真函数
- f̂(x) :估算函数
在经典估计理论中,在估计实际模型参数之前,需要根据数据的特征和属性对数据进行数学建模。对于信号处理,概率密度函数(pdf)是基于数学模型的未知参数定义的。例如,均值和方差是高斯过程的参数。
然而,PDF 的规格是决定一个好的估算器的关键因素。这些 pdf 不是给我们的,而是需要选择的,它不仅与问题约束一致,而且在数学上是易处理的,或者在合理的时间内实际上是可解的。每个 PDF 都有一组潜在的假设,所有的数学都是有效的。如果不满足这些条件,那么估计器就不会按预期运行。
对于 DL/ML 模型,这些参数是权重和偏差矩阵。我们没有定义 pdf 的类型,而是关注于架构类型、初始化技术、损失函数等。基于问题定义。我们试图根据训练数据找出这些矩阵的最佳可能值。我们使用基于梯度下降的优化技术来寻找逼近实际函数的最优或最佳函数。【你可以在这里了解更多:梯度下降解开
寻找最佳估计量
寻找最优估计量通常需要一个最优性准则。对于 DL/ML 模型,这个准则就是我们使用的损失函数。有几种损失函数可供选择。函数的选择取决于您试图解决的问题,例如分类、回归、分段等。
然而,均方误差(MSE)是最自然的一种,定义如下。

估计函数的 MSE 是估计函数与实际函数之差的平方的期望值。我不会讨论什么是期望,因为这超出了本文的范围。然而,如果你想了解更多,我推荐以下内容。
- https://ee.stanford.edu/~gray/sp.pdf(期望在第 4 章中有所介绍。但是你也需要前几章的概念。)
- https://en.wikipedia.org/wiki/Expected_value
MSE 衡量估计值与真实值的平均均方偏差。它有一个漂亮的凸面,即向上弯曲,只有一个最佳值。因此它非常适合于各种各样的优化技术。
偏差方差分解
MSE 误差可以分解成两项,即偏差和方差。我将在下面展示和解释分解推导。为推导起见, f(x) 表示为 f , f̂(x) 表示为 f̂ 。
但在此之前,我将简要给出偏差和方差的数学定义:
偏见
偏差定义为:b(f̂)= e(f̂)-f
b( f̂ )这里是估计量的偏差。它本质上是测量估计者的期望值和被估计参数的真实值之间的差异。【你可以在这里了解更多。[https://en.wikipedia.org/wiki/Bias_of_an_estimator](https://en.wikipedia.org/wiki/Bias_of_an_estimator#:~:text=In%20statistics%2C%20the%20bias%20(or,objective%20property%20of%20an%20estimator.)
差异
方差定义为:Var(f) = E[(f - E(f)) ]
随机变量的方差是随机变量与其期望值之差的平方的期望值。所以它是随机变量与其自身均值的均方偏差。高方差意味着 X 的观测值将远离平均值,反之亦然。你可以在这里阅读。https://www.stat.auckland.ac.nz/~fewster/325/notes/ch3.pdf
现在我们用 MSE 函数的定义开始推导。接下来是对 f̂.期望的战略性加减然后,我们使用一些属性和定义来得到偏差和方差分量。

来源:作者

来源:作者
偏差-方差分解可以用下面的三角关系来表示。

来源:作者
偏差是估计量的期望值和实际基础函数之间的差异。方差是模型的可变性。在估计理论中,存在不同类型的估计量。然而,对于经典的估计理论,从实用的角度来看,最小均方误差估计需要被放弃,因为这个标准导致不可实现的估计。我们经常求助于最小方差无偏(MVU)估计量,它有更专业的版本,如最佳线性无偏估计量(BLUE)等。如果你对估计理论统计信号处理基础感兴趣,第一卷:估计理论是一个惊人的资源。
在深度学习的情况下,网络在没有任何明确定义的情况下作为强大的估计器工作。上面所做的所有分析也直接适用于这种情况。
现在让我们看看,如果我们给随机过程添加一些噪声,分解会是什么样子。这是因为对于我们可用的随机过程的观测值 Y,总是包含一些固有的噪声。可以这样写:


ϵ 具有均值和方差为零的正态分布 σ 。
这个假设在 MSE 分解中增加了一项。由于求导和没有噪声项几乎一样,所以我直接写尾方程。不过,如果你对推导感兴趣,请参考这个链接。

σ 项表示贝叶斯误差,可表示如下。

贝叶斯误差是指任何分类器的最低可能误差,类似于不可约误差。它也被称为最佳误差。即使你建立了一个完美的模型,这个误差也无法消除。这是因为训练数据本身并不完美,包含了噪声。
因此,模型的总误差是三种误差的叠加:
- 模型偏差导致的误差
- 由于模型差异造成的误差
- 不可约误差(贝叶斯误差)
偏差和方差对模型总误差的影响
偏差、方差和总误差之间的关系可以用下图来解释。x 轴代表我们模型的复杂性,y 轴是误差值。

来源:作者
- 我们看到,随着模型复杂性的增加,偏差继续减少,方差继续增加。这是因为如果模型变得越来越大,它表示函数的能力就会不断增加。事实上,如果你让模型足够大,它可以记住整个训练数据,导致误差为零(如果贝叶斯误差为零)。然而,拥有一个过于复杂的模型将导致较差的泛化能力,即使你将获得良好的训练性能。这叫做过度拟合。
- 另一方面,如果你的模型太简单,它会有很高的偏差和很低的方差。即使对于训练样本,误差也会非常高。如果您观察到,即使在许多个时期之后,您的模型仍然具有较差的定型数据性能,这可能意味着您的数据具有损坏的标签,或者模型不够复杂,无法逼近基础函数。这就是所谓的不适应。
- 正如我们在图中看到的,总误差继续降低,直到达到最佳复杂度点。这是仅留下贝叶斯误差并且模型具有最高性能的地方。在这一点上,我们在偏差和方差之间取得了恰当的平衡。
以下是欠拟合、最佳拟合和过拟合的一些例子。

来源:作者[5]
我们观察到,对于具有高方差的模型(最右列),潜在的噪声也被捕获。这导致了令人敬畏的训练表现,但是可怕的测试表现。因为在这种情况下泛化能力最差。相反,对于具有高偏差的模型(最左边的列),模型不能捕捉数据中的潜在模式。因此,该模型即使在训练数据上也表现不佳。最佳模型是最好的模型,也是最通用的模型,因为它有适当的偏差和方差。
结论
我们看到了偏差-方差分解是如何工作的。模型复杂性如何影响总误差、偏差和方差。我们讨论了贝叶斯误差,这是一种最小误差,它总是存在于噪声观测中。最后,我们看到过拟合、欠拟合和最佳拟合是什么样子的。在我未来的一篇文章中,我计划讨论深度学习中使用的技术,以克服过拟合/欠拟合的问题。感谢您阅读我的文章。希望你觉得有用。
参考
[1] 统计信号处理基础:估计理论。
[2]https://en.wikipedia.org/wiki/Expected_value
[3]https://en.wikipedia.org/wiki/Bias_of_an_estimator
https://www.stat.auckland.ac.nz/~fewster/325/notes/ch3.pdf
[5] Pinterest 图片
Python 示例中的偏差-方差权衡
原文:https://towardsdatascience.com/bias-variance-trade-off-with-python-example-6519d2084be4?source=collection_archive---------13-----------------------
根据误差估计选择最佳拟合模型

图片作者。
这篇文章旨在通过 Python 中的一个实际例子来展示偏差-方差权衡。
偏差-方差权衡指的是机器学习模型的两个竞争属性之间的平衡。
监督机器学习问题的目标是找到解释输入预测值(x)和观察结果(y)之间关系的数学表示(f):

其中ɛ表示数据中的噪声。
例如,我们通过选择正弦波作为两者之间的关系来创建我们的合成 x 和 y:

其中{ x ∈ R ∣ 0 < x < 2 }
We also assume a normally distributed noise, with mean=0 and variance=1.

Image by author.
In a real-world scenario, we would not know the relationship between predictors and outcome.
Given a dataset, our task is to find suitable candidate models and choose the one that better fits our information.
To this aim, we split our data in, 至少,两个不同的集合:
- 训练集:拟合模型的部分数据。
- 测试集:评估模型性能的数据部分。
由于测试集包含模型以前未见过的数据,因此评估该测试集的性能可以更好地估计模型在真实世界中对未知数据的表现。
我们将原始数据分为训练集(80%)和测试集(20%),如下所示:

图片作者。
现在,我们希望在训练集上训练一些模型,并在测试集上评估它们的性能。
特别是,我们希望最小化模型在从预测器预测结果时产生的误差;对于我们所有的观察(n),这种误差通常是预测结果(y_predicted)和观察结果(y_observed)之间的距离的度量。
在这种情况下,我们可以使用均方误差,定义如下:

此外,我们可以证明这个误差可以分解为三个量的和:

任何模型,无论多好,都是数据间复杂关系的近似,因此所谓的不可约误差是不可避免的。
从公式中可以看出,一个好的模型应该将偏差和方差最小化:让我们来定义这些术语。
偏置
偏差考虑了模型预测和真实结果之间的差异。
这主要取决于我们选择的解决问题的模型,以及模型假设如何恰当地解释预测因素和结果之间的关系。
通过观察我们的训练集图,我们注意到一个非线性趋势。如果我们选择用线性回归来模拟 x 和 y 之间的关系,模型假设显然不能解释我们的 f,我们知道 f 是非线性的。在这种情况下,我们将获得一个具有高偏差的模型。
我们可以凭经验评估模型遭受高偏差,因为它在训练集上显示高误差。或者换句话说,训练表现不佳:这种情况被称为训练不足。
偏高:
-模型假设未能解释预测因素和结果之间的关系。
-涉及“更简单”(不太灵活)的模型,如线性回归。
-导致装配不足(列车组性能不佳)。
方差
方差衡量训练集的不同选择如何影响模型参数。
当我们训练一个机器学习模型时,我们希望通过选择一个稍微不同的训练集,函数不会发生显著变化。否则,我们将获得一个在输入数据的微小变化面前无法概括的模型:这被称为过拟合。
直觉上,具有较少假设的模型不会遭受高方差,因为它们在训练集中的小变化面前不会改变。因此,高方差是一个影响更灵活的模型(如决策树)的问题。
由于该模型足够复杂,足以在训练集上过度拟合,我们会期望高训练性能(或低训练误差),但也会期望差的测试性能,因为该模型需要参数的显著变化来解释数据中的小变化。
高方差:
-涉及更“复杂”的模型(更灵活),比如决策树。
-导致过度拟合(测试集性能不佳)。
这幅图概括了这个概念:

来自:Trevor Hastie、Robert Tibshirani 和 J H. Friedman,“统计学习的要素:数据挖掘、推理和预测”,纽约:Springer,2001 年。
为了在我们的示例中说明这些概念,我们在训练集上拟合多项式次数递增的多个多项式模型,然后观察 MSE 随模型复杂度增加的趋势:

图片作者。
如果我们从左到右观察多项式次数(模型复杂度)的 MSE 图,模型复杂度的增加导致训练误差的减少(较低偏差),但测试误差 ( 高方差)也显著增加**。**
另一方面,我们也注意到模型复杂度的降低导致较差的训练集性能 ( 高偏差)以及在测试集 ( 低方差)上更好的泛化。
最佳拟合由最小化测试误差的多项式次数表示:

总之,最佳拟合显示了两个特征:它很好地拟合了训练集(低训练集误差),并且它很好地概括了看不见的数据(低测试集误差),因为它最小化了方差和偏差。在我们的例子中,误差较大的模型要么表现出高方差,要么表现出高偏差。因此,这个名字叫做偏差-方差权衡。
机器学习中的偏差-方差权衡:一种直觉

由古斯塔沃·托里斯在 Unsplash 上拍摄的照片
在糟糕的和高度优化的模型之间进行选择
一般直觉
如果我们口袋里有更多的钱,我们会花得更多——这几乎是每个人都知道的事实。但人们通常不知道收入和支出之间的确切关系,也就是说,在已知收入的情况下,人们会花多少钱。
一个近似的解决方法是,通过观察人们的收入和支出,建立一个统计模型。数据越多,模型越好。然后,我们可以把这个模型应用到一个未知的地方或人群,并有合理的把握。
但该模型无法做出 100%准确的预测,因为人们的行为会随着时间和空间而变化(嗯,这就是为什么这被称为统计模型而不是确定性模型)。然而,即使这个模型不是通用的,我们也想让它具有足够的普遍性——一个**“平均** 模型”,能够适应各种各样的变化和情况。
让我们考虑一个不同的背景,当我们真的想要为一个同质的群体建立一个模型时,他们的行为或多或少是可以预测的。在这种情况下,我们的目标是**“优于平均水平的模式”**适合特定人群。然而,我们知道,这种模式是为目标人群定制的,因此在异国环境中会失败。
我们构建的平均模型有偏差,但它具有很高的灵活性,可以在各种情况下工作,而优于平均水平的模型是定制的,偏差较小,但在接受训练的人群之外表现不佳。
现在让我们把这两个模型都发挥到极致。在一个光谱中,我们将模型简化得太多,以至于它失去了所有的预测能力;随机猜测比模型表现更好。在另一个极端,让我们基于群体中的每个个体构建模型,并对模型进行调整,使其对该群体具有高预测能力。
那么哪款更好呢?
取决于你想如何使用模型。一个坏的模型在任何地方都表现很差,一个普通的模型在大多数情况下表现一般,而一个微调的模型在一种情况下表现很好,但在其他情况下就不那么好了。
建立模型的目的是解释现实世界的现象,我们使用模型是因为这些现象会在空间和时间上发生变化。但是我们能建立一个适用于任何地方和任何时间点的模型吗?
答案是否定的。这就是偏差-方差权衡的概念有用的地方。
偏差-方差权衡
现在让我们将这种直觉与偏差-方差权衡的正式概念联系起来。
在机器学习中,每个模型都被指定了许多决定模型性能的参数。一个好的模型在训练和样本外数据上都表现良好。
有些型号可以使用默认参数。但是,如果我们不调整参数,模型就有可能无法发挥最佳性能。这种情况被称为欠适配。
因此,我们调整参数以适应训练数据,然后根据测试数据评估模型性能。重复该过程,直到模型达到期望的性能。但是这种定制模型如果放归野外会有怎样的表现呢?这种高度调整的模型很可能在样本外数据中表现不佳,这就是所谓的过拟合问题。

高调优模型与差模型和一般模型(来源:作者)
适应不足和适应过度同样不好——它们不擅长做出一般的预测。因此,偏差-方差权衡无非是维持欠拟合和过拟合之间的平衡,在高方差和高偏差之间进行选择。数据科学家找到了最佳点,因此他们相信该模型在样本外数据中表现良好。
一个例子
现在让我们用 Python 中的一个例子来扩展直觉和偏差-方差权衡的概念。为此,我将首先导入几个库(numpy 和seaborn)并创建两个小数组——x 和 y——来演示。
import numpy as np
import matplotlib.pyplot as plt
import seaborn as snsx = [0, 1, 2, 3, 4, 5, 6]
y = [0, 1, 2, 14, 18, 32, 52]
现在让我们画出 x 和 y 变量,并拟合一条线性回归线。
# linear fit
sns.regplot(x,y, ci=False);

线性模型似乎不太适合数据,它显然看起来像一个坏模型,大多数数据点远离直线。它有很大的偏差,偏差很小。因此,显然有机会改进这一模式。
现在让我们拟合一条高次多项式线,看看模型表现如何。
# polynomial fit
poly_fit = np.poly1d(np.polyfit(x,y, 6))plt.plot(x, poly_fit(x), linestyle='-')
plt.scatter(x, y);

多神奇啊!6 次多项式完美地拟合了数据——实际上太完美了,没有误差。该模型捕捉数据中的每一点噪声。这个模型有很高的(完美的)方差,没有偏差。
这是我们想要的型号吗?
大概不会。随着多项式阶数的增加,模型的复杂性增加。不能保证该模型在其他数据上的表现也是如此。
那么更好的模型应该是什么样的呢?介于太坏和太好之间的东西?让我们尝试将多项式次数从 6 降低到 2。
# polynomial fit
poly_fit = np.poly1d(np.polyfit(x,y, 2))plt.plot(x, poly_fit(x), linestyle='-')
plt.scatter(x, y);

这个 2 次多项式模型有一些误差,当然没有 6 次模型好,但也没有简单的线性拟合差。因此,事实证明,高次多项式更适合数据,但它也使模型变得复杂。
有什么解决办法?
复杂模型过度拟合训练数据,但无法在测试和样本外数据中做出高质量的预测。另一方面,一个简单的模型不符合训练数据,在测试数据中也表现不佳。
因此,数据科学家的目标是找到一个平衡点来平衡权衡。但是在实践中到底是怎么做的呢?
欠拟合很容易发现,因为它显示在模型性能中。然而,过拟合很难捕捉,因为模型在误差度量方面表现良好。对于数据科学家来说,扔掉一个非常适合的模型,选择一个性能较低的模型也是非常困难的。但是有一些工具可以让这个决定变得更容易。这里有几个选项:
1)错误与复杂性的直观解释:通常,一个好的实践是通过绘图来选择模型:
- 训练数据中的误差与复杂性
- 测试数据中的误差与复杂性
- 检查两条曲线的相交处,并相应地调整参数
在回归中,偏差-方差权衡可以通过绘制均方误差(MSE)与模型复杂性的关系图来检查。在分类中,同样可以通过将错误分类的数量与复杂性相对比来检查。
2)正则化:这是一种通过在成本函数中添加小偏差来优化模型性能的技术。这种小偏差会缩小特征系数,降低其灵敏度。
如果数据集中有太多的要素,正则化会控制它们的影响,并降低它们的敏感度。这是通过将模型系数向零收缩来实现的。通常使用两种类型的正则化-L1(套索回归)和 L2(岭回归),它们由超参数λ控制。
摘要
总结偏差-方差权衡的概念:
- 如果模型过于简单且不符合训练数据,它在实际预测中的表现也会很差。
- 根据训练数据高度调整的模型也可能表现不佳。
- 偏差-方差权衡允许检查平衡以找到合适的模型。
- 有两种方法来检查权衡——a .错误与复杂性的直观解释,b .正则化。
希望这是对机器学习中这个重要概念的有益讨论,如果你有意见,请随时写在下面,或者通过媒体、推特或 LinkedIn 与我联系。
时间序列中的偏差-方差权衡
原文:https://towardsdatascience.com/bias-variance-tradeoff-in-time-series-8434f536387a?source=collection_archive---------11-----------------------
使用 PyCaret 时序模块

照片由艾萨克·史密斯在 Unsplash 拍摄
📚背景
在为任何机器学习问题建立模型时,我们必须注意偏差-方差权衡。具体来说,对于时间序列:
- 偏差太大(拟合不足)意味着模型无法捕捉数据中的所有信号,因此在训练阶段(进而在预测阶段)会导致更高的误差。
- 模型中有太多的变化(过度拟合)意味着模型不能很好地概括未知的未来数据(即,它可以很好地处理训练数据,但不能像它训练的那样预测未来数据)。
让我们看看如何用 PyCaret 来诊断这个问题。
🚀PyCaret 中的解决方案概述
PyCaret 中的解决方案是基于吴恩达的建议[1]。我强烈建议读者在继续阅读本文之前,先浏览一下这个短片。PyCaret 中遵循的步骤是:
- 时间序列数据首先被分成训练和测试两部分。
- 然后,在多个折叠中交叉验证训练分割。交叉验证误差用于在超参数调整阶段从多个模型中进行选择。
- 在整个“训练分割”中训练具有最佳超参数的模型
- 然后,该模型用于做出与“测试分割”中的时间点相对应的预测。然后,通过将这些“测试”预测与测试分割中的实际数据进行比较,可以报告最终的泛化误差。
- 一旦满意,用户可以使用在前面步骤中获得的“最佳超参数”来训练整个数据集(训练+测试分割),并进行未来预测。
1️⃣设置
我们将使用经典的“航空公司”数据集[6]在 PyCaret 中演示这一点。本文的 Jupyter 笔记本可以在这里 找到 ,也可以在文章末尾的“参考资料”部分找到。
from pycaret.datasets import get_data
from pycaret.internal.pycaret_experiment import TimeSeriesExperiment**#### Get data ----**
y = get_data(“airline”, verbose=False)**#### Setup Experiment ----**
exp = TimeSeriesExperiment()**#### Forecast Horizon = 12 months & 3 fold cross validation ----**
exp.setup(data=y, fh=12, fold=3, session_id=42)
2️⃣火车-测试分裂
为了诊断偏差-方差权衡,PyCaret 最初将时间序列数据分为训练和测试两部分。当执行这种分割时,数据的时间依赖性得以保持。测试集的长度与设置实验时指定的预测范围相同(本例中为 12)。这显示在设置摘要中。

设置摘要[图片由作者提供]
这种分割也可以使用plot_model功能可视化。
exp.plot_model(**plot="train_test_split"**)

时间序列训练-测试分割[图片由作者提供]
3️⃣交叉验证
接下来,训练分割被分解成交叉验证折叠。这样做是为了使训练不会因为一组训练数据而产生偏差。例如,如果过去 12 个月的数据是异常的(比如由于 Covid),那么这可能会影响一个本来很好的模型的性能。另一方面,它可能会让一个糟糕的模型看起来不错。我们希望避免这种情况。因此,我们在不同的数据集上进行多次训练,并对性能进行平均。
在跨这些多个数据集(也称为“折叠”)进行训练时,再次保持时间依赖性是很重要的。可以应用许多策略,如扩展或滑动窗口策略。关于这一点的更多信息可以在[2]中找到。
在设置阶段可以控制折叠的次数。默认情况下,PyCaret 时序模块使用 3 倍。再次使用plot_model可以可视化训练数据中的褶皱。蓝色圆点代表用于每个文件夹中训练的时间点,橙色圆点代表用于验证训练文件夹性能的时间点。同样,橙色点的长度与预测范围(12)相同
exp.plot_model(**plot="cv"**)

训练分割中的交叉验证折叠[图片由作者提供]
4️⃣创建初始模型
在本文中,我们将以简化回归模型为例。关于简化回归模型的更多信息可以在[3]中找到。
model = exp.**create_model("lr_cds_dt")**

跨交叉验证折叠的基线模型性能[图片由作者提供]
性能显示在 3 个折叠上。3 次折叠的平均绝对误差(MAE)大于 30,平均绝对百分比误差(MAPE)大于 8%。根据应用的不同,这可能还不够好。
交叉验证完成后,PyCaret 将返回在整个定型拆分中定型的模型。这样做是为了让模型的泛化可以在我们之前展示的测试数据集上进行测试。
exp.**predict_model**(model)
exp.**plot_model**(model)

测试数据上的基线模型性能[图片由作者提供]
使用此模型的预测现在显示了对应于测试数据集(蓝线)的时间点的预测。还显示了这些“测试”预测的指标。这些指标比交叉验证期间获得的指标更差。由于指标一开始就很糟糕(交叉验证错误率很高),这表明模型中的偏差很大(即模型在这一点上不能很好地捕捉数据集的趋势)。此外,测试指标比交叉验证指标差。这表明差异很大(详情请参考[1])。这在预测图中也是可见的,其显示在测试期间蓝色预测线不接近相应的黑线。
让我们看看是否可以通过调整模型的超参数来改善偏差。
5️⃣调整模型以提高性能
调整过程会尝试各种超参数组合,以查看哪些组合最适合模型。更多信息可在[4]和[5]中找到。一旦尝试了各种超参数组合,就会根据“折叠”的平均交叉验证误差挑选出最佳超参数。然后显示使用这些最佳超参数的交叉验证指标。
tuned_model = exp.**tune_model**(model)

跨交叉验证折叠调整模型性能[图片由作者提供]
因此,我们已经能够将交叉验证阶段的错误减少到大约<= 20 and the MAPE is < 5% by performing hyper-parameter tuning. This is much better than before and we have reduced the underfitting significantly. But now we need to ensure we are not overfitting the data. Let’s look at the performance across the test dataset again.
exp.**predict_model(tuned_model)**
exp.**plot_model(tuned_model)**

Tuned Model Performance on the Test Data [Image by Author]
The forecasts across the test dataset show better performance than the cross-validation metrics indicative of a lack of overfitting. The plot also shows a good match to the actual data points during the test period.
So this model looks good. But what we need is the ability to predict the true “unknown” future data. This can be done by finalizing the model.
6️⃣ Finalizing the Model to make Future Predictions
Finalizing the model takes the hyperparameters from the model (tuned_model in this case), and fits the entire dataset using these hyperparameters.
final_model = exp.**finalize_model(tuned_model)**
print(exp.predict_model(final_model))
exp.plot_model(final_model)

Future Predictions from Finalized Model [Image by Author]
And there you have it. Our best model is now able to make future predictions. Note that metrics are not displayed at this point since we do not know the actual values for the future yet.
🚀 Conclusion
Hopefully, this workflow example has shown why it is important to diagnose bias-variance tradeoff. For time series, this process is complicated by the fact that the temporal dependence must be maintained when performing the splits and cross-validation. Luckily, the PyCaret Time Series module makes managing this process a breeze.
That’s it for this article. If you would like to connect with me on my social channels (I post about Time Series Analysis frequently), you can find me below. Happy forecasting!
🐦推特
📘 GitHub
喜欢这篇文章吗?成为 中员 继续 无限制学习 。如果您使用以下链接 ,我将获得您一部分会员费,您无需支付额外费用 。
https://ngupta13.medium.com/membership
📗资源
- Jupyter 笔记本 包含了本文的代码
📚参考
[1]吴恩达模型选择与训练/验证/测试集。
[2]PyCaret 中时间序列交叉验证
[3] 时间序列预测的简化回归模型
[4]pyCaret 中时间序列模型的基本超参数整定
[5]pyCaret 中时间序列模型的高级超参数整定
[6]可通过 sktime python 软件包根据 BSD 3-条款许可证获得航空公司数据集。
偏差与方差的权衡——解释清楚
偏差与方差,过度拟合与欠拟合

照片由 Pexels 的 Gabby K 拍摄
为什么我们需要偏差-方差权衡
在机器学习中,我们收集数据,并使用训练数据建立模型。我们将该模型应用于该模型未见过的测试数据,并进行预测。我们的主要目的是减少预测误差。
我们通过最小化训练误差来建立模型,但是我们更关心测试误差/预测误差。预测误差取决于偏差和方差。
以下情况需要偏差-方差权衡。
- 为了克服欠配合和过配合情况
- 预测的一致性。
让我们在本文中详细了解偏差-方差权衡背后的概念。
模型结构
在进行偏差-方差权衡之前,让我们看看当我们增加模型复杂性时,训练误差和预测误差有什么不同。
假设,我们有这样的数据点。我们必须找到 X 和 y 之间的关系。

作者图片
X 和 Y 之间的真关系或真函数表示为 f(X) 。这个功能未知。
Y=f(X)+ε
现在,我们必须建立一个模型来描述 X 和 y 之间的关系。
输入→模型→输出
**学习算法:**学习算法将接受输入并返回一个描述 X 和 y 之间关系的函数。
输入→学习算法→ f̂(X)
示例:在线性回归中,学习算法是梯度下降法,它根据成本函数 OLS(最小二乘法)找到最佳拟合线。
假设给定一个数据集,我们把它分成训练数据和测试数据。
训练数据—使用训练数据
测试数据构建模型—使用选择的模型预测输出。
现在,让我们考虑基于训练数据构建的 4 个模型。
在所有的模型中,我们都在假设 y 和 x 的关系。
- 简单模型→1 度→ y=f̂(x) = w0 +w1x

作者图片
在这个简单的模型中,拟合线远离数据点,因此拟合误差/训练误差会很高。
2.二次多项式
y=f̂(x) = w0 +w1x + w2x

作者图片
3。五次多项式


作者图片
4。复杂模型→20 度


作者图片
这里,在这个复杂的模型中,拟合的曲线穿过所有的数据点,因此拟合误差/训练误差将接近于零。这个模型试图将数据和噪音一起记忆下来,而不是将其一般化。因此,这个模型在看不见的测试数据/验证数据上表现不好。这种情况被称为过度拟合。
现在,如果我们使用这 4 个模型对验证数据进行预测,我们将得到不同的预测误差。
现在绘制训练误差和预测误差与模型复杂性(在我们的例子中,多项式的次数)的关系

作者图片
从上面的图表中,我们可以看到,随着模型复杂度的增加[1 度、2 度、5 度、20 度],训练误差趋于减小。
但预测误差在一定程度上减小,当模型变得更复杂时,预测误差会增大。
在训练误差和预测误差之间存在权衡。在两条曲线的末端,一端有高偏差,另一端有高方差。因此,在偏差和方差之间存在一个折衷,以实现理想的模型复杂性。

作者图片
什么是偏差-方差权衡?
偏向
假设 f(x)是真实模型,f̂(x)是模型的估计值,那么
)= bias(f̂(x)
偏差告诉我们期望值和真实函数之间的差异。
E[f̂(x)] →模型的期望值。
如何计算模型的期望值?
我们建立模型())使用相同的形式(例如。多项式次数 1)在从训练数据中抽取的不同随机样本上。然后我们将计算所有函数的期望值,记为e[f̂(x)】。

作者图片
在上图中,橙色拟合曲线是对从训练数据中抽取的不同随机样本执行的所有复杂模型(度数=20)的平均值。
在上图中,绿色拟合线是对从训练数据中抽取的不同随机样本执行的所有简单模型(度数=1)的平均值。
从上面的图中,我们可以看到简单模型有很高的偏差。因为平均函数离真实函数很远。
复杂模型具有较低的偏差。它们完全符合数据。
差异
方差告诉我们一个 f̂(x 与 E(f̂(x)).模型的期望值有多大的不同
variance(f̂(x))= e[(f̂(x)]-e[f̂(x)]]
因此,对于复杂的模型,方差往往更高,因为训练样本中的微小变化将导致不同的 f̂(x).因为复杂的模型,把数据点背下来。
对于简单的模型,在 f̂(x 不会有太大的区别),如果我们稍微改变一下训练样本。简单的模型概括了这种模式。
所以,根据偏差和方差,我们可以说,
简单模型可能具有高偏差和低方差。
复杂模型可能具有低偏差和高方差
偏差和方差之间有一个权衡,因为两者都会导致误差。
预期预测误差
预期预测误差取决于三个误差
- 偏见
- 差异
- 噪声(不可约误差)
预期预测误差公式
EPE=偏差+方差+不可约误差
使用模型 f̂(x),我们预测不在训练数据中的新数据点(x,y)的值。
那么期望的均方误差将是
EPE =E[(y-f̂(x) ]
从 EPE 公式中,我们知道误差取决于偏差和方差。

作者图片
所以,从上面的情节来看
- 当偏差高时,预测误差高。
- 当方差高时,预测误差高。
- 一次多项式→训练误差和预测误差高→ 欠拟合
- 2 次多项式→训练误差和预测误差高→拟合不足
- 5 次多项式→训练误差较小,并且训练误差和预测误差之间的差异较小。→ 最佳拟合
- 20 次多项式→训练误差较小,预测误差很大→过拟合
关键要点
- 简单模型可能具有高偏差和低方差。
- 简单的模型会更加通用,有时会显得不够合适。
- 复杂模型可能具有高方差和低偏差。
- 复杂的模型会记住数据,并且倾向于过度拟合。
- 最佳拟合模型将具有低偏差和低方差。
感谢阅读,我希望你们都喜欢它。
如果你喜欢看我的更多教程,就关注我的 中 ,LinkedIn, 推特 。
点击这里成为中等会员:https://indhumathychelliah.medium.com/membership
有偏见的 AI,引擎盖下的一个眼神
原文:https://towardsdatascience.com/biased-ai-a-look-under-the-hood-5d0a41968f16?source=collection_archive---------17-----------------------
受偏见困扰的人工智能系统到底是怎么回事?

Pawel Czerwinski 在 Unsplash 上的照片
人工智能(AI)中的偏见问题最近成为许多负面头条。这些报告表明,人工智能系统有可能无意中歧视敏感的子群体。例如,一家国际技术公司开发的人工智能招聘系统被发现系统性地偏向男性申请人,而不是女性申请人。在这篇文章中,我将揭示一些当人工智能变成流氓时发生的内部过程。它的灵感来自于我发表的一篇关于这个主题的研究论文。[1]
为了更好地理解这个问题的背景,让我们首先介绍一些关于机器学习的基础知识。与传统编程相比,一个主要区别是算法决策背后的推理不是由人类明确编程的硬编码规则定义的,而是通过示例数据学习的:数千个、有时数百万个参数在没有人类干预的情况下得到优化,最终捕获数据的广义模式。由此产生的模型允许对新的、未知的数据进行高精度的预测。
请举例
为了说明这个概念,让我们考虑一个关于保险索赔中欺诈检测的示例场景。核实保险索赔的合法性对于防止滥用是至关重要的。然而,欺诈调查对保险公司来说是劳动密集型的。此外,对于某些类型的保险,许多索赔可能同时发生,例如,由于影响整个地区的自然灾害。另一方面,对于投保人来说,补充检查可能很烦人,例如当他们被要求回答进一步的问题或提供额外的文件时。双方都对快速决策感兴趣:客户期待及时的补救措施,而公司试图保持低成本。因此,加速这项任务的人工智能系统可能会非常有用。具体地说,它应该能够可靠地识别合法的保险索赔,以便能够迅速付款。潜在的欺诈案例也应该被可靠地检测到并标记出来,以便进一步调查。
你的 AI 表现如何?
现在,让我们深入研究一下技术细节。为了评估这种分类器的性能,我们通常将预测输出ŷ与真实输出值 Y 进行比较。在索赔数据中,输出值 1 代表欺诈索赔,而 0 代表合法索赔。下表包含我们正在运行的示例的示例预测。

与预测相反的真实输出等级 yŷ
为了更好地说明,请在下面的动画中找到相同的结果。黑点对应于负样本( Y =0),这里是实际合法声明。白点代表正样本( Y =1),在本场景中为实际欺诈索赔。红色大圆圈构成了分类器的边界:圆圈外的点被预测为阴性/合法(ŷ= 0),圆圈内的点被预测为阳性/欺诈(ŷ= 1)。不同的背景颜色进一步显示了分类器的正确位置(浅绿色和深绿色),以及错误位置(浅灰色和深灰色)。
值得注意的是,在这个过于简单的二维例子中,画一个理想的边界来分隔黑白点,从而定义一个完美的分类器是显而易见的。然而,在高维真实世界用例中,几乎不可能获得错误率为零的完美分类器;优化始终是一个权衡的问题。

示例场景的图形表示。作者制作的动画。
结束混乱
所谓的“混淆矩阵”有助于可视化和计算通常用于检查 ML 模型性能的统计测量。矩阵的行代表实际的输出类,在我们的例子中是 0 或 1。这些列表示给定分类器预测的输出类。预测类别对应于实际类别的单元格包含正确分类的实例的计数。只要类别不同,分类器就会出错,数字代表分类不正确的样本。
在抽象层次上,单元格中的数字通常由下表中提供的术语来标识。

混淆矩阵模式
以运行示例中的数据为基础,相关的混淆矩阵如下所示。正如您所注意到的,给定的分类器正确预测了 9 个欺诈性声明和 30 个合法声明。然而,它也错误地预测了 12 项索赔是合法的,实际上是欺诈性的,12 项索赔是欺诈性的,实际上不是。

样本数据的混淆矩阵
重温上面的动画插图,我们进一步认识到图式中的彩色片段对应于混淆矩阵中的不同单元:真阳性(浅绿色)、假阳性(浅灰色)、真阴性(深绿色)和假阴性(深灰色)。
把公式拿来!
从混乱矩阵中,我们可以提取大量有趣的统计测量。首先,我们对数据集中的实际阳性进行计数。这个数字是真阳性和假阴性的总和,假阴性可以被视为遗漏的真阳性。同样,实际阴性的数量是真阴性和假阳性的总和,假阳性也可以被视为遗漏的真阴性。在我们的示例中,这些数字代表实际欺诈索赔和实际合法索赔的数量。

实际阳性(P)和实际阴性(N)
(阳性)基本比率,有时也称为患病率,代表实际阳性相对于整个数据集的比例。在我们的示例中,该比率描述了数据集中实际欺诈索赔的份额。

基本利率
真阳性率和真阴性率分别描述正确分类的阳性和阴性实例在其实际发生时的比例。在本例中,真实肯定率描述了被检测到的所有实际欺诈索赔的份额。真正的负比率是成功发现的实际合法索赔的份额。

真阳性率(TPR)和真阴性率(TNR)
错误发现率描述了所有肯定预测的误分类肯定分类的份额。因此,它是关于被错误识别或发现的积极分类实例的比例。相反,假漏检率描述的是假阴性预测占所有阴性预测的比例。这些实例实际上是积极的,但被忽略了——它们被错误地忽略或省略了。在我们的示例中,错误发现率是被归类为欺诈的所有索赔的错误率。虚假遗漏率描述了所有被归类为合法的索赔中实际欺诈性索赔所占的份额。

错误发现率(FDR)和错误遗漏率(FOR)
存在大量的其他统计方法来评估 ML 模型的性能。然而,为了证明人工智能的偏见,上面介绍的指标已经足够了。
你忽略了一些东西
到目前为止,我们将数据作为一个群体进行分析,没有考虑数据中可能存在的敏感亚组。然而,由于最大似然算法的决策通常会影响人类,许多数据集包含敏感的数据子群。例如,这种分组可以按性别、种族或宗教来定义。为了分析一个分类器是否有潜在的偏差,我们增加了这个额外的维度,并根据这个敏感属性将结果分成子组。这允许调查它们之间可能的差异。任何这种偏离都可能是对一个敏感群体的歧视。
我们现在检查我们的运行中的保险欺诈检测的例子。来自训练模型的输出保持不变,但是这一次我们假设数据中有两个敏感的亚组,例如我们将数据分成男性和女性。

敏感子群的独立混淆矩阵
我们注意到,两个亚组中的基本比率(BR)是相同的,这意味着在这个例子中,男性和女性提出欺诈性(或合法)索赔的可能性相同。然而,男性的真实负比率(TNR)为 0.79,而女性为 0.57。这意味着 79%由男性提出的有效索赔被正确归类为合法,而对于女性来说,只有 57%的同类索赔是合法的。另一方面,男性的错误遗漏率为 24%,女性为 38%。因此,在我们虚构的示例场景中,女性提交的欺诈性索赔比男性提交的欺诈性索赔更有可能不被发现。
那又怎么样
当一个敏感亚组与另一个敏感亚组之间的统计测量值(如上所述)存在显著差异时,就出现了 AI 偏倚。换句话说,当系统对不同的群体表现不同时,它是有偏差的。由于大多数机器学习算法的黑盒性质,特别是在输出不能由人眼直接评估的应用领域(例如分数),这个问题可能会在很长时间内不被注意。然而,由于人工智能对人们生活的影响越来越大,因此必须检测和减轻人工智能偏见,以防止对来自敏感亚群体的个人的系统性不平等待遇,并确保负责任地使用人工智能。
既然我们对有偏见的人工智能到底出了什么问题有了更清晰的认识,我们可以把注意力转向问题的根源。在我的下一篇文章中,我深化了这些偏见到底来自哪里的问题。
非常感谢 Antoine Pietri 为撰写本文提供的宝贵支持。除非另有说明,所有图片均为作者所有。
参考
[1] B. Ruf 和 M. Detyniecki,《走向人工智能中的正确的公平》 (2021),ECML/PKDD 工业追踪。
有偏数据及其处理方法
原文:https://towardsdatascience.com/biased-data-and-how-to-deal-with-it-fdaeb9da3b20?source=collection_archive---------25-----------------------

由 Edge2Edge 媒体在 Unsplash 拍摄的照片
欠采样的故事
我的一个学生刚刚完成了一个涉及分类的数据科学荣誉项目——或者至少他认为他完成了。他收到了波士顿地区大约 2000 名学生和大约 700 名企业家发布的几千条推文。他必须训练一个 ML 模型(RandomForestClassifier)来预测一条推文是由学生还是由企业家发布的。听起来很容易。他随机选择了 70%的推文用于训练,其余的用于测试。这个模型看起来很有效,准确率达到了 83%——对于一个课程项目来说,这已经很不错了。
不幸的是,该模型非常擅长识别学生推文(95%的准确率),但识别企业家推文(55%的准确率)却相当糟糕。为什么?因为训练数据集有大约 1400 名学生,只有大约 500 名企业家。换句话说,它偏向于学生,并学会了如何更好地识别他们的推文。
修复训练数据集的一种方法是为每个结果提供相等或大致相等数量的样本。如果我们在培训数据中只有大约 500 名企业家,那么我们也应该只包括大约 500 名学生,除非我们的目标是扭曲培训过程。Python 中最流行的数据分析包 Scikit-Learn 没有无偏倚的训练/测试分裂功能。但是我们可以自己造一个。
假设 X 是一个 Pandas 数据框架,它包含我们整个数据集的特征(预测)和结果。特征在列 x1 中..xN 和结果在 y 列。首先计算支持每个结果的样本数:
from numpy.random import binomial
np.random.seed(0)
# Generate synthetic dataset with three outcomessamples = 100
X = pd.DataFrame({"x1": binomial(1, 0.3, samples),
"x2": binomial(1, 0.6, samples),
"y": binomial(2, 0.5, samples)})grouper = X.groupby("y")
sizes = grouper.size()
#0 26 <- the smallest
#1 46
#2 28
假设我们仍然希望从最小的组样本中选择 70%用于训练,并从较大的组中选择匹配数量的样本。我们可以计算来自较大组的样本的百分比,以匹配最小组的 70%。这些百分比是选择样本的概率:
fracs = (sizes.min() * 0.7) / sizes
#0 0.700000 <- the smallest
#1 0.395652
#2 0.650000
现在我们知道了概率,我们可以使用二项式分布(np.random.binomial)及其布尔补码来分别随机选择训练和测试样本。当我们在相同结果的组中循环时,我们将在两个最初为空的数据帧中累积样本:
test = pd.DataFrame()
train = pd.DataFrame()for grp, data in grouper: # reuse the grouper!
mask = binomial(1, fracs.loc[grp], data.shape[0]).astype(bool)
train = train.append(data[mask])
test = test.append(data[~mask])
现在,对于每个结果,训练数据集中的行数大致相同。训练数据集是平衡的,不偏向任何特定的结果:
train.groupby("y").size()
#y
#0 21
#1 20
#2 23
在该数据集上训练的模型将会看到属于这三个类的大约相等数量的样本,并且不会有偏差。
我们是否也应该均衡不平衡的测试数据集?很可能不是:您只将它用于测试,它的偏差不应该是一个问题。
大数据和新冠肺炎:数据可视化的一年
原文:https://towardsdatascience.com/big-data-and-covid-19-a-year-in-data-visualizations-ea78cd6c21cc?source=collection_archive---------24-----------------------
我们对新冠肺炎的看法是如何通过数据可视化随着时间的推移而演变的

回到未来——多洛瑞恩作者:杰森·梁
尽管新冠肺炎疫情在过去的一年中有许多负面影响,但它已经在数据可视化领域引发了创造力的爆发。图形设计师、研究人员和其他数据爱好者已经将他们的才能用于公共利益,以清晰和解释性的图形呈现与新冠肺炎相关的大数据。从基础到互动地图,从彩色到非典型图表,你可能已经看到了数百个与新冠肺炎相关的数据可视化。
**但是你有没有注意到他们是如何模仿我们对冠状病毒的认识的?**事实上,随着时间的推移,数据可视化已经与我们一起发展,同时帮助我们——普通人、记者、政治家——更好地了解正在发生的事情。在本文中,我想带我们回到 2020 年初,追溯数据可视化的发展以及这种新型冠状病毒的传播。你准备好出发了吗?我们走吧!
1.记录和跟踪新冠肺炎病例
从 2019 年底开始,一些网站开始收集世界各地的数据,以集中这种新型病毒的传播数据。汇总数据使研究人员、媒体和公众能够更广泛地了解情况,而不必掌握语言和从几十个国家寻找原始数据来源。
关于记录和更新每日与新冠肺炎相关的病例和死亡人数的先驱之一是 Worldometer 网站。除了致力于计算地球上居住人数的实时计数器,该网站还开发了一个非常可靠的冠状病毒部分。正如他们自己解释的那样,他们“从官方报告中收集数据,直接从政府的沟通渠道收集数据,或通过被认为可靠的当地媒体来源间接收集数据”。尽管 Worldometer 的设计相当基础,但它经常被世界各地的媒体和机构作为可靠的数据来源。
这些机构中包括位于马里兰州巴尔的摩的约翰霍普金斯大学。2020 年 1 月 22 日,他们首先发布了一张全球地图来追踪与新冠肺炎相关的病例和死亡。这个最初的项目后来发展成为约翰·霍普金斯冠状病毒资源中心(CRC),该中心包括“260 多个来源”,在美国的行动范围更广(如检测、追踪、疫苗)。

约翰·霍普金斯大学系统科学与工程中心(CSSE)的新冠肺炎仪表板
2.了解最新的新闻
数据可视化也有助于说明我们的社会必须克服的众多挑战。从谷歌趋势到疫苗,它们让我们更好地理解想法和传达关键信息。
从谷歌搜索词开始,我想起了 Alberto Cairo 在 2020 年 1 月至 4 月期间在网站上进行的这项研究。作者调查了美国与冠状病毒相关的顶级搜索趋势,并从中构建了富有洞察力的可视化效果。这里有一个例子:随着时间的推移,我们看到搜索从“什么”搜索演变而来,比如“什么是疫情?”更务实的问题,如“如何使用缩放?”。
在试图理解感染对我们社会的影响时,以创新的方式可视化数据将帮助我们更好地理解一些文章的观点。例如,这篇纽约时报的文章用一个相当基本的散点图制作了一篇互动文章:基于两个维度(接触疾病和与他人的身体接近)的感染概率。在这里,技术的使用支持了作者的说法,因为它迫使读者向下滚动页面继续阅读,从而积极地让读者参与进来。
随着时间的推移,关于社会距离的问题出现了:在他们的“电晕模拟器中,来自华盛顿邮报的作者通过动画展示了各种社会距离措施(从“免费开放”到强制隔离)如何有助于平坦化感染曲线。在那个时代,社交距离对我们大多数人来说都是一个新概念,如此强大的可视化功能清楚地表明,这是摆脱疫情的一种方式。
最近发布了新的“数据追踪器”来追踪世界各地新冠肺炎疫苗接种的进展。来自我们的世界数据的图表就是一个很好的例子。它们是基于开源数据(查看他们的 GitHub 知识库这里)并以图表形式展示了世界上每天服用的新冠肺炎疫苗剂量。对我来说,这个网站的优势在于你可以轻松地在不同的指标(病例、死亡、检测、疫苗接种)和不同类型的图表(线图、世界地图、数据表)之间切换,以便可视化你正在精确寻找的内容。

新冠肺炎数据浏览器关于疫苗接种的数据我们的世界
3.退一步看全局
在后新冠肺炎时代,数据可视化的另一个主要方面是透视。尽管有悲惨的消息,数据可视化也可以帮助我们把每天的数字放到一个更广阔的背景中。
当我们正在经历有生以来第一次全球性的疫情时,我们可能会忘记人类历史上曾经发生过次大流行病——而且它们造成的损失要大得多。这就是为什么我觉得这张由 Data Visualist 制作的信息图特别发人深省。当然,目前的疫情是致命和令人担忧的,但时至今日,艾滋病毒已经造成更多的死亡,而我们还没有任何疫苗来对抗它。
最终,通过将多个数据可视化汇总到仪表板中,可以更好地理解疫情。这就是一些网站所做的,将所有与新冠肺炎相关的当前数据集中在一个地方。尽管在图表的选择和呈现方式上存在潜在的偏见,但这些仪表板允许读者从许多数据源中获得最多的信息。与已经格式化的文章相比,它们为读者解释留下了更多的空间,因此每个人都可以从显示的许多图表中得出自己的结论。

新冠肺炎数据仪表盘由信息漂亮
结论:回归基础
你喜欢这趟旅程吗?我刚刚向你们展示了一年多来与新冠肺炎·疫情相关的数据可视化。现在,当你遇到一个新的数据可视化时,我想给你一些建议,特别是如果它与冠状病毒这样的“热门话题”有关。
在我看来,在考虑任何数据可视化时,有两个主要问题需要考虑,无论它是否与新冠肺炎有关:
- 数据来源:使用的数据来自哪里?来源可靠吗(政府、知名机构……)?
- 图表真实性:你是否发现了作者可能用来误导读者的潜在偏见?
一旦你确定这两个条件都令人满意地满足,享受数据即!
信用
- 图一:梁朝伟在 Unsplash 上。在知识共享 CC0 许可下。
- 图片 2: 约翰·霍普金斯大学系统科学与工程中心(CSSE)的新冠肺炎仪表板。版权所有 2020,约翰霍普金斯大学,保留所有权利。
- 图片 3: 新冠肺炎数据探索者通过我们的世界在数据。许可知识共享协议。
- 图 4:由信息美丽团队制作:大卫·麦坎德斯,斯蒂芬妮·斯塔林博士,奥米德·卡尚,法比奥·贝尔加玛斯基 Univers Labs 。
你喜欢读这篇文章吗? 成为 的一员,加入一个不断成长的充满好奇心的社区吧!
大数据管理:数据存储库策略和数据仓库
原文:https://towardsdatascience.com/big-data-management-data-repository-strategies-and-data-warehouses-bfa9b45c95de?source=collection_archive---------19-----------------------
介绍
管理大量结构化和非结构化数据对于每个需要系统化组织和治理以确保其数据高质量并适合分析和商业智能应用的公司的成功至关重要。虽然大数据的关键方面可以概括为流行的 3 个 v,即容量、速度和多样性,但在选择存储和转换数据所需的适当流程时,每个公司还需要问其他一些关键问题。
大数据方面
Volume: 传入的数据流有多大,需要多大的存储量?
**速度:**指的是数据生成的速度和需要访问的速度。
**品种:**数据需要以什么格式存储?结构化(如表格)或非结构化(如文本、图像等)。
**值:**存储所有数据得出什么值?
**准确性:**数据来源、类型及其处理的可信度如何?
**粘度:**数据如何在流中流动,阻力和可加工性如何?
**病毒式:**数据在网络上分发的能力及其在用户间的分散率
大数据管理
由于企业数据存储呈指数级增长,管理大数据已成为一项越来越具有挑战性的任务。跨行业研究表明,大多数组织在决策分析中只使用了一半的结构化数据和近 1%的非结构化数据。许多组织倾向于保留尽可能多的数据,因为没有办法预测哪些数据源在未来会有价值。[1]
他们经常会发现过时的数据或与其他系统中的其他副本发生冲突,并且由于有如此多的数据源可用,实施高效的数据管理技术可能是一项繁琐的任务。数据分散可能会导致跨多个位置维护记录,并带来重复的风险,从而导致管理成本增加和安全策略不一致。
没有数据管理战略会导致缺乏信任、错失良机、客户满意度下降,以及违规和监管处罚。由于这些原因,组织倾向于通过投资能够帮助他们满足需求的策略和大数据工具来实施数据管理原则。
大数据管理可以被视为一个宽泛的术语,包括数据清理、集成、迁移、准备、丰富、分析、质量、管理、报告、治理和规划。根据企业的需求,每个流程的关注点和资源分配可能会有很大的不同。

图一。从数据收集到预测分析
数据存储策略
通过将数据集中在一个引用元数据和单个逻辑名称空间的系统中,数据存储库可以成为解决数据管理挑战的一个很好的解决方案。它们用于将特定的数据群体隔离在一个或多个数据存储实体中,以挖掘数据用于业务洞察、报告需求或机器学习。这个术语经常与数据仓库或数据集市一起使用,它的主要好处是由于数据被隔离,使得报告或分析更容易。
一个有效的数据存储库策略需要一个一致的策略来统一、管理、评估和部署大量的数据资源。这将增强数据管理功能,最终提高分析和查询性能。
定义数据存储库策略的第一步是阐明组织数据目标的主要目的,这将指导他们的数据管理方法。健壮的数据策略包含几个要素。这包括创建一个覆盖整个企业的数据架构,定义业务需求,并确定数据质量和集成的优先级。此外,它还通过定义数据保留标准以及降低风险和复杂性来实现问责制。[2]
在实施数据策略时,公司面临着多种方法,他们的决策是基于组织的可用资源或以前的经验。虽然有些策略有助于组织确保管理数据隐私和通过内部来源分发的数据的完整性的指导原则,但其他策略可能更侧重于通过创建快速框架来支持业务决策,这些框架提供实时快速洞察、预测性建模和交互式仪表板。虽然大多数公司需要这两种方法的平衡,并选择灵活性来取得成功,但有些公司会更加强调一种具有适当权衡的方法。

图二。决定数据策略时的关键因素
数据仓库
企业数据仓库
企业数据仓库(EDW)可以概括为一个面向主题的数据库或一组数据库,这些数据库将来自多个来源和应用程序的数据收集到一个集中的来源中,以便进行分析和报告。它存储和管理企业的所有历史业务数据。[3]组织、转换和聚合数据源的各种输入可以为人工智能(AI)就绪数据结构节省宝贵的时间和管理成本。
这是提取、转换、加载(ETL)或 ELT 方法经常使用的地方,Hadoop 或 Apache Spark 等大数据分布式框架帮助组织进行繁重的数据清理和转换。

图 3。数据仓库概述
数据仓库和标准操作数据库之间的关键区别在于,后者经过优化以保持实例中的精确准确性,并跟踪快速数据更新,而数据仓库则提供随时间变化的大范围数据视图。尽管数据仓库是管理大数据的常用工具,但当组织需要扩展它们时,它们会变得非常昂贵,并且在处理非结构化或复杂的数据格式时,它们的性能也不好。
EDWs 的架构复杂性为组织提供了许多好处:
- 将多个数据源集成到单个数据库中,用于单个查询
- 维护数据历史,提高数据质量,保持数据一致性
- 为整个企业的多源系统提供一个集中视图
- 重构数据以提高复杂查询的性能
数据集市
虽然数据仓库(DW)可以有效地处理大型数据集,但实时人工智能和针对不同业务运营子集的数据分析需要使用数据集市(DM)。DMs 可以被认为是 DWs 的缩小版本,具有更有限的范围或它们的逻辑子集,旨在满足不同业务单位或部门的特定最终用户群的信息需求,并且通常为重点内容或定制的决策支持提供聚合数据。它们有相互依赖和相互独立的格式,前者从 EDW 中填充,后者直接从操作数据存储(ODS)中获取。
DM 减少了来自组织中其他数据源的查询、转换和繁重网络使用的负载,并为最终用户提供了一个定制的 DM,使他们能够进行更多的访问和控制。DMS 还会带来一些固有的问题,如信息孤岛和限制用户访问。
数据湖
数据湖(DL)是另一种类型的数据存储库,它的一个关键区别是数据以原始格式存储,没有任何转换。数据可以是结构化的,也可以是非结构化的,这使得 DLs 适用于批量数据类型,如服务器日志、点击流、社交媒体或传感器数据。
数据只是存储在存储库中,不知道将进行什么类型的分析,也不知道它是否会在分析中使用。当数据需要用于业务洞察时,这反过来将需要大量的预处理。

图 4。数据湖的简单表示
由于 DLs 更具开源性和未定义的结构,因此其存储成本更低,并且可以建立在具有内部管理的组织数据中心或不同供应商(如 Amazon、Microsoft 或 Google)的云服务中。
虽然数据仓库的目标是已经进行了转型的决策者,但数据仓库需要专业的数据科学家来预处理和分析数据,他们可以改善客户交互、R&D 创新并提高运营效率。
交易型商店
事务数据存储(TS)针对基于行的操作进行了优化,例如在维护数据完整性的同时读写单个记录。然而,它们并不是专门为分析而构建的,但由于它们在生产环境中已存在多年,因此可以用于分析查询以及低延迟信息监控。
TSs 是 ACID(原子性、一致性、隔离性、持久性)兼容的,这意味着尽管有错误,它们也能保证数据的有效性,并确保数据不会因为某种故障而损坏。这对于需要高度数据完整性的业务用例至关重要,例如银行交易。
TSs 设计为在生产系统中运行,由于其基于行的低延迟特性,可以运行需要与主数据库几乎同步的操作或查询。虽然 dw 由于其基于列的特性而被优化用于读取数据,但是 ts 在写入时性能更好。对于拥有少量数据的公司来说,这可能不是一个大问题,但随着可用数据的增加,这可能会在选择正确的数据策略方面产生影响。
操作数据存储
操作数据存储(ODS)是减轻从 DWs 中查询最新数据的挑战的另一种方法,可以被视为提供查询功能的临时区域。ODS 可以提供更接近实时的细粒度非聚合数据,因为它是在繁重的转换和加载操作之前接收的,从而减轻了事务性系统的负担。它们用于运营报告,并作为 EDWs 的补充元素。
它们的一般目的是通过数据清理、解决冗余和建立业务规则,将不同来源的数据集成到一个单一的结构中。ODS 可以是 EDW 的关键组成部分,并且由于其多用途结构,可以实现事务和决策支持处理。存储在 ODS 中的数据是面向事务的,与 DWs 相比,其大小更小。[5]
结论
大数据管理是每个公司的必需品。它提高了他们对客户的理解和开发新产品的创新能力,同时由于对每个部门的大量数据进行分析,使他们能够做出重大的财务和业务决策。建立数据策略需要定义问题并了解每个公司的业务需求,以改进他们的数据系统和源管理。
尽管并非所有公司都需要在一开始就开始担心大数据管理,但当传统数据库表现不够好,无法提供大数据存储库的优势时,就需要开始考虑这一点。当竞争优势、创新、收入增长和客户获取的各个方面都达到稳定水平时,这一点通常会变得很明显。
值得一提的是,每个数据存储库都有自己的缺点。一些公司通过存储所有数据来使用数据湖,而没有有效地利用每个部门的信息提取,这使他们的业务战略计划失败。将没有任何目标的数据转储到数据仓库将导致高管理成本,失去对存储内容的跟踪,并且不能利用新建立的资源。
在大多数情况下,数据策略可能不会在一夜之间提供商业价值,而是需要通过反馈和评估在每个阶段逐步改进。数据存储库并不能保证公司数据策略的成功;然而,它确实减少了常见故障场景的可能性、从数据中提取价值所花费的过多成本和时间,并为公司的未来创新指明了方向。
参考
- 你的数据策略是什么?关键是攻防平衡。莱安德罗·达勒姆勒和托马斯·达文波特(2017 年 5 月至 6 月)
- 让您的数据仓库井然有序,麦肯锡公司 2018
- 企业数据仓库:概念、架构和组件,2019
- “大数据质量日益重要”。数据圆桌会议。检索于 2020 年 6 月 1 日。
- 构建操作数据存储(第 2 版。),英蒙,威廉 1999
使用 Python 中的 Datashader 实现大数据可视化
理解大数据
【Datashader 是如何工作的,为什么速度会如此之快?

图片来自https://examples.pyviz.org/opensky/opensky.html经许可
几个月前,我写了一篇关于我最喜欢的 Python Viz 工具——holo Viz 的文章。许多人有兴趣了解更多关于 Dashshader 的信息 HoloViz 家族中的大数据可视化工具。我非常喜欢 Datashader,喜欢 Datashader 如何快速创建大型数据集的有意义的可视化。因此,在本文中,我将带您浏览一个简单的 Datashader 示例,解释 Datashader 是如何工作的,以及它为什么这么快。
为什么大数据可视化很难?
以我的理解,大数据可视化主要有两个障碍。
- 首先是速度。如果您使用常规的 Python 绘图工具来绘制我下面的例子中的 1100 万个数据点,将会非常慢,并且您的 Jupyter 内核很可能会崩溃。
- 第二是画质。即使它没有崩溃,并且您愿意等待,大多数绘图库也会简单地将每个新数据点绘制为一个圆形或其他形状,这将导致过度绘图。在这种情况下,即使为重叠点添加 alpha 透明度也不总是有帮助。想象一下,在一幅图像上,你有许多点一个接一个地显示:你所看到的将是一个斑点,并且很难从这个斑点中提取信息。
Datashader 为这两个障碍提供了优雅且看似神奇的解决方案。接下来,我将向您展示一个示例,并探究其中的神奇之处。
使用 Datashader 的大数据可视化—示例
该示例来自 pyviz.org 的纽约市出租车数据示例。完整示例请参见https://examples.pyviz.org/nyc_taxi。
- 导入需要的包
conda install您的 Conda 环境中所需的软件包:
然后在 Python 文件中导入包:
读入数据
对于非常大的文件,您会希望使用像 Dask 这样的分布式处理库和 Datashader,但是这里我们有一个“只有”1100 万条记录的 Parquet 文件,Datashader 可以在使用 Pandas 的笔记本电脑上轻松处理它,而不需要任何特殊的计算资源。在这里,我们将加载两列来表示出租车的下车地点。

- 绘图
在这里,我们使用 Datashader 绘制数据。我只用了 4 行代码和 6 毫秒的时间,用我的笔记本电脑绘制了 1100 万行数据,覆盖在纽约地区的地图上:

或者,不使用datashade函数,我们可以使用hvplot和rasterize=True来使用 Datashader 应用栅格化。如此简单!我强烈推荐使用 hvplot 进行可视化。

如果您正在实时运行它,那么您将能够放大到此地图的任何区域,并且绘图会动态更新以使用该缩放级别的全分辨率。
【Datashader 是如何工作的?

图一。Datashader pipeline(图片经许可来自 Datashader)。
Datashader 使用五步管道将您的数据转化为绘图。 Datashader 文档说明了管道在每个步骤中是如何工作的——投影、聚合、转换、色彩映射和嵌入。我将把我前面的例子分解成这些小步骤,这样我们就可以确切地看到 Datashader 在幕后做什么。
让我们首先安装底层的 Datashader 函数,这样我们就可以运行各个步骤:
- 投影
首先,我们为要投影的数据定义一个具有宽度和高度的 2D 画布。画布定义了我们希望在最终图像中看到多少像素,并可选地定义将映射到这些像素的x_range和y_range。此处,要绘制的数据范围未在画布中设置,因此它们将在下一步中根据数据框中数据 x 和 y 值的最大值和最小值自动填充。画布定义了投影的内容,但是为了加快速度,每个点实际上都是在聚合步骤中投影的。
- 聚合
在定义了投影画布之后,我们将每个点投影到二维输出网格中,并聚合每个像素的结果。Datashader 支持这种聚合的许多选项,但在本例中,我们只是通过遍历数据点并在该点所在的位置增加像素,来计算有多少数据点投影到每个像素中。这种情况下的结果是一个计算每个像素衰减的二维直方图:

- 转换(可选)
无论原始数据集有多大,上一步的结果现在都是固定大小的格网。一旦数据在这个网格中,我们可以对它进行任何类型的转换,比如只选择某个范围的计数,根据其他数据集或值的结果屏蔽数据,等等。在这里,衰减数据的范围从一些像素的零到其他像素的数万,如果我们试图直接绘制网格,我们只会看到几个热点。为了使所有不同的水平都可见,如上图所示,使用图像处理技术“直方图均衡化”对数据进行转换,以显示计数的分布,而不是它们的绝对值。直方图均衡化实际上被合并到下面的色彩映射步骤中,但是如果我们愿意,我们可以在这个阶段进行显式转换,例如对计数求平方:

- 色彩映射
接下来,我们可以将入库的网格数据渲染到图像的相应像素。通过线性插值或自动变换(例如,通过对每个值调用对数函数,或如这里使用直方图均衡化),每个箱值被映射到色图中定义的 256 种颜色之一。这里我们使用 Colorcet 的“fire”色图,它从黑色开始,代表最低的计数(1 和 2 衰减),经过红色,代表更高的值(以百为单位),然后是黄色,代表更高的值(以千为单位),最后是白色,代表每像素的最高计数(在本例中为数万)。我们将背景设置为黑色,以便更好地显示数据。

- 嵌入
如您所见,Datashader 只渲染数据,而不渲染任何轴、彩条或您在完整绘图中预期的类似特征。为了获得那些有助于解释数据的特性,我们可以将 Datashader 生成的图像嵌入到一个绘图中。最简单的方法是使用 HoloViews,这是一个高级绘图 API,它提供了使用 Matplotlib、Bokeh 或 Plotly 作为后端的灵活性。这是一个使用全息视图定义一个“点”对象,然后对所有点进行数据阴影处理的例子。在这里,我们演示了一个替代方法“光栅化”而不是“数据阴影”,这样 Bokeh 就负责变换和色彩映射步骤,并允许悬停和彩条工作。

为什么 Datashader 速度如此之快?
首先,我们需要谈谈原始数据格式。Datashader 非常快,以至于读入数据通常是最慢的一步,尤其是当您的原始数据是一堆 JSON 文件或 CSV 文件时。对于像 dropoff points 这样的列数据,Parquet 文件格式通常是一个很好的选择,因为它很紧凑,可以快速加载,只有效地读取您需要的列和范围,并在适当的时候支持分布式和核外操作。
第二,使用正确的输入文件格式,我们可以研究下一个最昂贵的任务,这是组合的投影+聚集步骤。这一步需要计算数百万个数据点中每一个的值,而所有后续计算都使用最终的固定大小的网格,因此速度更快。那么,Datashader 怎么做才能让这一步走得快呢?
- Datashader 的聚合计算是用 Python 编写的,然后使用【Numba】即时编译成超快的机器代码。例如,这里是代码,在这里对每个箱子进行计数。
- 上面的例子使用了一个 CPU,但是 Datashader + Numba 也支持 CUDA cudf 数据帧作为 Pandas 数据帧的替代,如果你有一个 GPU,它会运行得更快。
- Datashader 还可以并行化其管道(代码示例),以便您可以利用所有可用的计算核心,扩展到更大的数据集,并提供更快的结果。
因为 Datashader 非常快,我们实际上可以交互地可视化大数据,无论何时缩放或平移,都可以动态地重新绘制。这里有一个示例,您可以在面板仪表盘中交互查看纽约市出租车数据。我最喜欢的关于船舶交通的例子说明,即使你看到的只是 Datashader 渲染的像素化图像,你仍然可以检查单个数据点并理解你所看到的。examples.pyviz.org 的另一个例子展示了大得多的文件的数据散列,在一台普通的笔记本电脑上高达数十亿个点。
在哪里可以了解到更多关于 Datashader 的信息?
- https://datashader.org/
- https://www.youtube.com/watch?v=v0QiTptWt3w
- https://www.youtube.com/watch?v=t5oFw9NUhlQ
总之,本文向您展示了一个使用 Datashader 可视化 1100 万行坐标数据的示例,并解释了为什么 Datashader 能够如此快速地生成有意义的可视化效果。值得注意的一点是,Datashader 可以用于任何类型的数据,而不仅仅是上面例子中的地理点。我强烈推荐看看 Datashader.org 大学的许多好例子。
确认
非常感谢 Jim Bednar 对本文的指导和反馈。
参考文献
【https://examples.pyviz.org/nyc_taxi/nyc_taxi.html
https://datashader.org/getting_started/Pipeline.html
http://numba.pydata.org/
大数据和机器学习
原文:https://towardsdatascience.com/big-ger-data-and-machine-learning-71104e3c229f?source=collection_archive---------35-----------------------
探索我的电脑在这个领域的极限

马库斯·斯皮斯克在 Unsplash 上的照片
最近,我在一个项目中面临着越来越多的数据——达到了千兆字节。在使用我的雇主提供的工具时,我很好奇:如果我在我的家用机器上工作,并且只能访问免费资源,会怎么样?
**TL / DR: PySpark 在 25%的时间里做两倍于 Python 的工作,PySpark 的优势受限于一个用户的机器。**超越这一点意味着转向云提供商(未来文章的重点)。
语境
在一个令人筋疲力尽的工作周结束时,我选择了 Coursera 大数据专业的天气 csv 数据集。该数据集包含气压/温度、风速/方向和雨水累积/持续时间,所有这些都是为了预测相对湿度。
这个监督学习问题使用了一个 123 MB 的数据集:远小于我在工作中处理的数据集,但我可以轻松地从我的家用电脑开始使用它来评估不同的工具。
本文的带有代码和数据集的 GitHub repo 是这里的。
方法和工具
Python
我决定比较使用 PySpark 和 Python 的方法。我在这里的重点不是特征工程或选择;我的其他故事涵盖这些话题。
在使用 pandas read.csv 读入数据集后,我定义了 x 和 y 数据帧。在测试训练分割之后,进行了 5 重交叉验证,在 max_depth 和 learning_rate 超参数上执行网格搜索。
from sklearn.model_selection import GridSearchCV, KFold
from sklearn.metrics import mean_squared_errorcv = KFold(n_splits=5)gbr_param_grid = {"max_depth": [2,10], "learning_rate" : [0.01, 0.1]}gsXGBr = GridSearchCV(gbtr, gbr_param_grid, cv = cv, scoring='neg_mean_squared_error', refit = True, verbose=True ,return_train_score=True)gsXGBr.fit(xtrain,ytrain)XGB_best = gsXGBr.best_estimator_ypred = XGB_best.predict(xtest)import numpy as npnp.sqrt(mean_squared_error(ytest,ypred))
这个脚本需要多长时间?2459 秒或者说不到 41 分钟。只是为了在我的 6 核 12 GB 内存惠普 Pavilion 上回归。
PySpark
Apache 的 Spark 是处理大型数据集的便利工具。它最初是用 Scala 编写的,PySpark 为我们提供了一个 API,用于在 Python 中使用 Spark 的功能。
这篇文章可以方便地安装 Spark 并使其运行。使用下面的代码测试 PySpark 的成功安装。
%pip install findspark*import findspark
findspark.init()*
SparkSession 是一个方便的入口点,它结合了 SparkContext 和 SQLContext 等其他命令授予的访问权限。虽然我通常使用 SparkSession,但我将使用 SparkContext,这样我可以首先为这个 stackoverflow 线程配置可用内存。
from pyspark.sql import SparkSession
from pyspark import SparkConf, SparkContext, SQLContextconf=SparkConf()
conf.set("spark.executor.instances", "4")
conf.set("spark.driver.memory", "10g")sc = SparkContext.getOrCreate(conf)spark = SQLContext(sc)
在读入数据集之前,我单击了创建的 SQLContext 的用户界面,并查阅了 Executors 选项卡。在 Spark 中,执行器执行实际的计算工作,并由驱动程序管理。

图 1: Spark UI 执行器选项卡。图片作者。
我只有一个执行器,即驱动程序,因为我运行在本地模式。随着代码的运行,我可以保持这个窗口打开,观察内存和磁盘空间的使用如何随着代码的运行而变化。我还确保使用了主 URL 下面星号所暗示的所有可用线程。

图 2:主 URL。图片作者。
为了方便起见,我放弃了一些功能——详见 repo 现在我将构建机器学习模型。
from pyspark.ml.regression import GBTRegressorgbtr = GBTRegressor(labelCol='relative_humidity')train,test = df_no_date_row_no_null.randomSplit([0.6,0.4])
您将观察 Python 的机器学习和 PySpark 的机器学习库(MLib)包之间的语法差异。我发现后者稍微麻烦一点,但我希望它会随着时间的推移而逐渐消失。
from pyspark.ml.tuning import CrossValidator, ParamGridBuilder
from pyspark.ml.evaluation import RegressionEvaluatorparamGrid = ParamGridBuilder().addGrid(gbtr.maxDepth, [2, 10]).addGrid(gbtr.stepSize, [0.01, 0.1]).build()rg = RegressionEvaluator(metricName="rmse", labelCol=gbtr.getLabelCol(),
predictionCol=gbtr.getPredictionCol())cv = CrossValidator(estimator=gbtr,evaluator=rg,numFolds=5, estimatorParamMaps=paramGrid)from pyspark.ml.feature import VectorAssemblerfeatures_input = (df_no_date_row_no_null.drop('relative_humidity')).columnsdassember = VectorAssembler (inputCols = features_input, outputCol='features')df_feat = dassember.transform(df_no_date_row_no_null)from pyspark.ml.pipeline import Pipelinepl = Pipeline(stages=[dassember,cv])
Model = pl.fit(train)
Pred = Model.transform(test)
rg.evaluate(Pred)
repo 中的代码还包括对分类器的训练和评估。
H 使用 PySpark 进行回归和分类需要多长时间? 698 秒或略多于 11.5 分钟。
外卖
PySpark 更快的内存处理显示:大约是 Python(仅分类)25%时间的两倍工作(回归和分类)。
不过,在一天结束时,我只使用了我的 12gb RAM 机器的资源,尽管通过 PySpark 的多核更有效。如果我通过云使用 Linux 和其他计算资源,我可以使用 Apache Livy 。
我将转向微软 Azure 的免费层来探索这里的选项,包括数据块。我试图注册社区版,但目前看到该产品已关闭。
我将在随后的文章中介绍我对 Azure 和 Databricks 的测试。一如既往,我欢迎任何反馈。
BigQuery Hack:灵活查询任意数量的列
原文:https://towardsdatascience.com/big-query-hack-flexible-queries-for-any-number-of-columns-713fa0c6f6a5?source=collection_archive---------12-----------------------
理解大数据
如何使用 BigQuery 处理多列的表?下面是如何使用脚本和表元数据。

BigQuery 很棒,但是它如何处理有很多列的表呢?尤其是当我们甚至不知道有多少列的时候?(图片来源:伊尔泽·奥尔塞尔)
BigQuery (BQ)是一个 Pb 级的专有谷歌数据仓库产品。在我的工作中,几乎每天我都使用 BQ 来处理数十亿行数据。但有时,棘手的情况会出现。例如,如果我的表有大量的行和列,该怎么办?BQ 是如何处理的?
与所有其他 SQL 语言一样,除了一些语法技巧,如*和EXCEPT,每个查询都要求我们手动输入所有所需列的名称。但是,如果我有一个有数百列的表,我想计算,比如说,所有的成对相关,该怎么办呢?使用CORR功能,我不需要手动输入 100 个✕100 ~ 10000/2 组合吗?
当然,我可以利用 BASH/python 来获取列名,并运行一些特殊的脚本来完成这项工作。但是,如果我们可以避免设置不同的连接器,并在 BQ 中本地完成所有工作,这不是很好吗?
感谢 BQ 的脚本功能和表元数据,事实证明这终究是可能的!因此,让我们深入一些测试数据,看看它是如何工作的。
数据样本
让我们获取一些样本数据。我们将使用 BQ 关于芝加哥出租车出行的公共数据集。下面是在我们自己的数据集中创建我们自己的表的查询(MyDataSet):
查询以创建我们自己的芝加哥出租车信息表
注意,我们使用PARTITION BY添加了一个分区列,这总是一个好主意。该查询将花费 13GB = 0.065 美元。如果我们想进一步降低成本,我们可以使用CREATE VIEW来代替(尽管预览将不可用)。
最终的表格应该如下所示:

芝加哥出租车样本数据预览
这里的目标是计算所有变量(trip_seconds、trip_miles、fare、…、is_cash)之间的成对相关性。我们如何进行?
列到行
我们如何在不显式引用所有列的情况下查询所有列?嗯,我们可以找到一种方法来重组数据,使多列变成一行。怎么做呢?我们可以使用ARRAY和STRUCT在 BQ 中创建一种模拟字典,有效地将列转置为行。这是最终结果的样子:

我们希望将所有列压缩到一列数组中,这就像一个字典
我们如何创造这种结构?以下是查询:
将多列转置为多行的查询
注意,我们使用了[]和STRUCT来显式创建数组。当然,查询仍然引用单个列的名称,当列数太大时,这会很快变得难以处理。要解决这个问题,我们可以:
- 查询
INFORMATION_SCHEMA.COLUMNS以获得所有相关的列 - 使用
FORMAT使用列信息构建一个查询字符串 - 使用
EXECUTE IMMEDIATE执行构造的查询字符串
所有这些步骤都可以在 BQ 脚本中串起来。让我们一步一步地分解它。
使用元数据的 BQ 脚本
我们可以使用各种元数据表获得给定数据集中的所有表元数据。对于与列相关的信息,我们可以简单地查询
SELECT * FROM MyDataSet.INFORMATION_SCHEMA.COLUMNS
(该查询是免费的,因为它处理 0 个字节)
例如,我们可以提取所有数字列:
查询以提取所有数字列的名称
为了提取所有的数字列,我们在data_type上应用了一个过滤器。使用ordinal_position和/或is_partition_column还有其他可能性。
现在,我们不仅仅想要列名;我们想为EXECUTE IMMEDIATE命令构建一个查询字符串。因此,我们使用 BQ 脚本,并将列名转换成一个字符串数组,以便于稍后构建查询字符串:
查询来提取字符串数组,这样我们就可以在以后构造查询字符串
我们使用FORMAT将column_name转换成我们之前用于将列转置为行的'STRUCT(... key, ... val)'模式。
ARRAY将查询结果转换成一个数组,该数组存储在变量query_ary中,供 BQ 脚本使用(标记为BEGIN ... END)。
现在我们已经准备好构造列转置查询,但是不引用任何特定的列名!
BQ 脚本将所有数字列提取到一个数组中,并构造和执行一个将列转置为行的查询
我们增加了两个额外的步骤:
- 将字符串数组
query_ary格式化为查询字符串query_string - 使用
EXECUTE IMMEDIATE执行构建的查询。
请注意,在我们的 BQ 脚本中没有提到任何列!
成对相关
我们还缺少最后一步:如何使用转置表计算成对相关性?这可以使用一个简单的聚合来完成(可以插入到上面的 BQ 脚本中):
计算成对相关的查询
该查询执行以下操作:
UNNEST``info数组两次,创建数组中所有可能的项目组合i1 < i2删除重复项,并确保只保留比较不同变量的组合GROUP BY和CORR计算每个唯一对的相关性,使用FORMAT构建一个好看的输出
最终结果应该是这样的:

芝加哥出租车数据的前 15 个正相关性
不出所料,最大的相关性来自于trip_total和fare,因为trip_total等于fare + tips + tolls + extras,而出租车费很可能是一次乘车总成本的最大组成部分。更令人惊讶的是,trip_miles和trip_seconds与trip_total并不完全相关,这表明更长的旅程并不一定会导致司机收入的显著增加。
我们也可以看看最负的相关性:

芝加哥出租车数据的倒数 5 个负相关性
有趣的是,现金支付似乎与小费的减少有关!有人可能会认为这是因为现金很可能被用来支付更便宜的旅行,但这种相关性不是那么强。另一种可能性可能是现金小费一直没有报告,或者现金的使用与不太富裕(非商务)的乘客有关,但这些当然是推测。
结论
使用 BQ 脚本和表元数据,我们可以纵向(大量行)和横向(大量列)扩展 BQ 中的分析。
如果你觉得这篇文章有帮助,你可能也会对我的其他 BQ 技巧感兴趣。欢迎随时留下评论/问题,BQ 黑客快乐!👋
https://medium.com/swlh/bigquery-hack-1000x-more-efficient-aggregation-using-materialized-view-7243e07208da https://medium.com/swlh/bigquery-hack-create-multiple-tables-in-one-query-bc47e52bf44a https://medium.com/swlh/bigquery-hack-monte-carlo-simulation-for-free-57d18fb87076
大型销售市场回归再探:进入潮流模型
原文:https://towardsdatascience.com/big-sales-mart-regression-revisited-enter-the-tidymodels-a6a432be58d4?source=collection_archive---------22-----------------------
使用 Tidymodels 的介绍性机器学习回归项目
Tidymodels 是一个元包,很像 tidyverse,它将一组有用的 tidy 包加载到您的会话中。不同之处在于它加载了一系列在机器学习模型开发过程中使用的包。
当我们使用它们时,我将介绍每一个,并提供实际的使用案例。Tidymodels 由 Max Kuhn 开发,他是 RStudio 的成员,开发了一种生成机器学习模型的整洁友好的方法。库恩之前最著名的作品是《脱颖而出》,是《下雨了》CategoricalRegressionTraining。Caret 本身已经是一个非常强大的包,可以与 Python 的 Scikit-Learn 相媲美。

照片由粘土堤在 Unsplash 上拍摄
但是,每个模型类型都有其特定的包、输入要求、规格和训练方法。Tidymodels 试图通过简化工作流程和创建生成机器学习模型所需的统一语法来解决这个问题。
大销售市场数据集可通过分析 Vidhya 和他们向成员提供的免费项目之一获得。
https://courses . analyticsvidhya . com/courses/big-mart-sales-prediction-using-r
该项目的目的是开发和评估一系列回归模型,根据一些输入变量预测商品经销店销售额。
当我亲自完成这个项目时,许多方面都是用 base R 编写的,并不像它应该的那样直观,也没有利用 tidyverse 包提供的易用性。因此,我看到了一个真正的机会,将这个项目转化为“整洁”的思维方式,并展示 tidymodels。
探索性数据分析
#Load Packages
library(tidymodels)
library(magrittr) #Tidy pipes
library(patchwork) #Visualisation grids
library(stringr) #String Manipulation
library(forcats) #Working with Factors
library(corrr) #Develop tidy Correlation Plots
library(vip) #Most important feature visualisations
加载一系列包,最重要的是 tidymodels 元包。与 tidyverse 非常相似,它实现了一系列较小的包,这些包有不同的用途,并在模型开发过程中发挥作用,还有 dplyr、ggplot2、purrr、tibble 等。随着模型开发的进展,我们将介绍每个包。
#Load Data
train = read_csv("train.csv")
skim(train)
数据被加载到项目中,我们使用 skimr 包中方便的 skim 函数检查结构。有 12 个变量(7 个字符和 5 个数字)和 8,523 行数据。

skim 输出的屏幕截图(图片由作者提供)
从这里开始,我们需要用一些丢失值的变量来整理数据集。我们通过可视化数据集中的每个变量来进一步研究。
我编写这个函数是为了使我的数据科学项目的初始 EDA 步骤非常简单,并通过 purrr 的 map2()创建一个图列表,并传递给 patchwork 的 wrap_plots()以生成一个图网格。
viz_by_dtype <- function (x,y) {
title <- str_replace_all(y,"_"," ") %>%
str_to_title()
if ("factor" %in% class(x)) {
ggplot(combi, aes(x, fill = x)) +
geom_bar() +
theme(legend.position = "none",
axis.text.x = element_text(angle = 45, hjust = 1),
axis.text = element_text(size = 8)) +
theme_minimal() +
scale_fill_viridis_d()+
labs(title = title, y = "", x = "")
}
else if ("numeric" %in% class(x)) {
ggplot(combi, aes(x)) +
geom_histogram() +
theme_minimal() +
scale_fill_viridis_d()+
labs(title = title, y = "", x = "")
}
else if ("integer" %in% class(x)) {
ggplot(combi, aes(x)) +
geom_histogram() +
theme_minimal() +
scale_fill_viridis_d()+
labs(title = title, y = "", x = "")
}
else if ("character" %in% class(x)) {
ggplot(combi, aes(x, fill = x)) +
geom_bar() +
theme_minimal() +
scale_fill_viridis_d()+
theme(legend.position = "none",
axis.text.x = element_text(angle = 45, hjust = 1),
axis.text = element_text(size = 8)) +
labs(title = title, y ="", x= "")
}
}
variable_list <- colnames(train) %>% as.list()
variable_plot <- map2(train, variable_list, viz_by_dtype) %>%
wrap_plots(
ncol = 3,
nrow = 4,
heights = 150,
widths = 150
)

通过数据类型适当的可视化简化 EDA(图片由作者提供)
由此我们注意到:
- 项目标识符有 1559 个单独的值,为了简化模型,我们将删除这个变量
- 项目重量没有明显的分布
- 项目脂肪含量标签不一致
- 项目可见性是右偏的
- 项目类型有多种标签
- 物料 MRP 有四个主要组
- 插座标识符有 10 个独特的标签
- 奥特莱斯建立的年份是多种多样的,许多商店从 90 年代中期开始
- 插座尺寸标签不一致
- 插座位置类型有三个标签
- 出口类型有四个标签
- 商品出口销售是右偏的
此外,让我们研究一下 Item_Outlet_Sales 和其他数字变量之间是否存在有趣的关系。使用 GGally 的 ggscatmat(),我们生成了一个简洁的双变量分析,沿对角线进行了高斯平滑,并为每个变量对生成了皮尔逊相关性。

连续变量的二元分析(图片由作者提供)
我们发现,把数字变量和目标变量对应起来,有三种不同的观察结果。
- 物品销售在物品重量的整个范围内分布良好,没有任何明显的模式
- Item_Visibility 与 Item_Outlet_Sales 没有关系
- Item_MRP 有四个不同的级别,并与 Item_Outlet_Sales 适度相关,我们将在稍后的特性工程中利用这一点。
数据角力
如前所述,我们需要修正一些变量输出。
#Correct mislabeled Item_Fat_Contenttrain %<>% mutate(Item_Fat_Content = if_else(Item_Fat_Content %in% c("reg", "Regular"), "Regular", "Low Fat"))#Outlet Size is missing a labeltrain %<>% mutate(Outlet_Size = if_else(is.na(Outlet_Size),"Small",Outlet_Size))
经销店规模是根据与小型经销店具有非常相似的 Item_Outlet_Sales 分布的 NA 标签估算的。
模型开发:引入 tidymodels
到目前为止,我们已经使用了一系列 tidyverse 包来争论和可视化数据,现在让我们来看看使用 tidymodels 元包开发机器学习管道的过程。
数据拆分— rsamples
很像 sci-kit 学习测试训练分割模块,rsamples initial_split 完成类似的操作。在下面的示例中,使用 intial_split 函数生成 mc_split 对象 mart_split,传递我们的训练数据帧,将比例设置为 75%,并按 Item_Outlet_Sales 变量分层。
这有效地创建了两个数据帧的列表,由 training()或 test()调用。我们将使用测试数据框架来判断我们的模型在看不见的数据上表现如何。
set.seed(55)
mart_split <- initial_split(train, prop = 0.75, strata = Item_Outlet_Salesmart_train <- training(mart_split)
mart_test <- testing(mart_split)
特征工程—配方
recipes 包提供了大量用于处理变量的函数,并使它们对机器学习友好。配方包的三个主要功能是
- recipe() —定义一系列连续的预处理步骤(或者收集并列出我的配料以及我将如何准备它们)
- prep() —计算所需的统计变换(或者准备我的烹饪原料)
- bake() —将预处理步骤应用于数据集(或烹饪我准备好的菜肴)
recipe 函数的构造类似于其他模型 outcome ~ predictor,在这里,我们通过使用波浪符号(~)指出我们想要使用所有其他变量作为模型的预测变量。).
我们已经使用配方生成了一个新的变量 Price_Per_Unit,它是 Item_MRP 和 Item_Weight 的商,然后通过应用 Box-Cox 变换并求 Item_Visibility 的平方根来寻求降低 Price_Per_Unit 的偏斜度。
在生成虚拟变量之前,名义/字符变量被转换为二进制列,表示该行是否属于某个特定的组(1 =真,0 =假),我们可以使用 reshape2::dcast(),然而,配方的强大之处在于,它能够通过管道传输一条简单的指令,使用 step_dummy 为所有名义变量创建一个虚拟变量。为了简单起见,我决定不为 Item_Identifier 创建虚拟变量,此外,这样会创建 5000 多列,可能会使模型过于复杂。
mart_recipe <-
training(mart_split) %>%
recipe(Item_Outlet_Sales ~ .) %>%
step_rm(Item_Identifier) %>%
step_impute_bag(Item_Weight) %>%
step_impute_knn(Item_Visibility) %>%
step_mutate(Price_Per_Unit = Item_MRP/Item_Weight) %>%
step_sqrt(Item_Visibility) %>%
step_log(Price_Per_Unit, offset = 1) %>%
step_discretize(Item_MRP,num_breaks = 4) %>%
step_normalize(all_numeric_predictors()) %>%
step_dummy(all_nominal())mart_recipe_prepped <- prep(mart_recipe)
然后,配方对象通过 prep()函数传递,也生成一个配方对象,但是已经进行了转换,因此数据已经被“准备”了。
将 prep(ed) recipe 对象传递给 bake 执行转换,因为已经创建了许多虚拟变量,所以我们现在有 54 列。
mart_train <- bake(mart_recipe_prepped, new_data = mart_train)
dim(mart_train)
[1] 6391 54
由于准备好的配方实际上是一个转换管道,我们可以在测试数据集上调用这些相同的转换。
mart_test <- mart_recipe_prepped %>%
bake(testing(mart_split))
dim(mart_test)
[1] 2132 54
瞧,完全处理的训练和测试数据集。
相关图— corrr
相关图对于理解哪些预测因子与结果变量相关非常有趣和重要。要创建相关图,需要将数据转换为相关数据框(cor_df)。
我们采用 mart_train,选择所有数字变量并传递给 corrcorrelate,corrcorrelate 生成 cor_df,给出变量对之间的 pearson 或 rho 值。
cor_df 对象被传递给 rplot(),就像对待其他 ggplot 对象一样,我们可以通过使用 theme()和配色方案来定制它的外观。
corr_df <- mart_train %>% select(is.numeric) %>%
correlate() %>%
rearrange() %>%
shave()
rplot(corr_df,) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 90)) +
scale_colour_viridis_c()

预处理(烘焙)数据的相关图(图片由作者提供)
给聪明人的一句话,你可能不打算“通常”使用这么多变量的相关图,正如我写的,如果没有更大的监视器,这很难阅读。但是,请注意创建这样一个情节的代码是多么优雅。
在这种情况下,人们可能会决定继续完成主成分分析,并根据重要性减少变量的数量。我将把那个留给另一个时间。
模型开发—防风草
RStudio 的团队,尤其是 Max Kuhn,有一种非常邪恶的幽默感。在命名这个包时,他们不能称之为 caret2,所以他们选择了 parsnip。
由于我们试图创建一个预测 Item_Outlet_Sales 的回归模型,为了便于演示,我们将开发两个模型,并使用均方根误差(RMSE)作为评估指标。
- 线性回归
- 随机森林
使用 parsnip 生成模型是非常优雅的。从我们要评估的第一个模型开始,线性回归,我们声明一个模型规范,然后是用于拟合模型的计算引擎。在这个实例中,parsnip 模型将使用 stats:lm()函数。
lm_model <- linear_reg() %>%
set_engine("lm")lm_mart_fit <-
lm_model %>%
fit(Item_Outlet_Sales ~ ., data = mart_train)
调用 parsnip 模型对象将生成类似于调用 stats:lm()对象时的输出,即每个输入变量的公式和系数列表。
lm_mart_res <-
predict(lm_mart_fit, new_data = mart_test) %>%
bind_cols(mart_test %>% select(Item_Outlet_Sales))lm_mart_res %>%
ggplot(aes(x = Item_Outlet_Sales, y = .pred)) +
geom_abline() +
geom_point(alpha = 0.5) +
theme_minimal() +
labs(x = "Item Outlet Sales", y = "Predicted Item Outlet Sales")

mart_test 的线性回归模型预测与期望值的散点图(图片由作者提供)
衡量绩效——衡量标准
在 mart_test 上使用我们的回归模型的输出,我们可以评估模型使用标尺包的准确性。标尺包为评估模型性能提供了一个有效的整洁的方式。
metrics <- metric_set(rmse, rsq, mae)metrics(lm_mart_res, truth = Item_Outlet_Sales, estimate = .pred)
为指定的误差度量创建一个包装函数。在我们的例子中,我们规定了均方根误差(RMSE)、R 和平均绝对误差(MAE)。
调用指标,指定 tible、实际和预测度量,生成一个包含每个错误度量和输出的 tible。

指标包装函数的输出(作者图片)
将模型的误差与测试集的预测误差进行比较,我们发现 RMSE(测试)= 1141.8,RMSE(模型)= 1144.3。差别很小,我们可以说该模型很好地适用于测试数据。
但是,回归模型预测了许多值的负值,因此不适用于此上下文,因为我们不能有负销售额。
生成 ML 管道—工作流程
如上所述,为了生成基本的线性模型,我们采取了许多精细的步骤,workflows 包提供了一种优雅的方法来处理这些步骤。我们现在将通过生成一个随机森林模型来演示工作流有多有用。
随机森林模型
随机森林算法是决策树的集成方法,通常通过 bagging 方法训练。RF 算法在随机特征子集中搜索最佳特征。这导致更大的树多样性,用更高的偏差换取更低的方差和更好的整体模型。
rf_workflow <-
workflow() %>%
add_recipe(mart_recipe) %>% #Pre-processing Steps
add_model(rand_forest(mode = "regression") %>% #Specify Model
set_engine("ranger"))
在四行代码中,我们生成了一个 ML 工作流,现在可以用作模型对象。
rf_mart_res <-
rf_workflow %>%
fit(training(mart_split)) %>%
predict(new_data = testing(mart_split)) %>%
bind_cols(mart_test %>% select(Item_Outlet_Sales))rf_mart_res %>%
ggplot(aes(x= Item_Outlet_Sales, y = .pred)) +
geom_abline(lty = 2)+
geom_point(alpha = 0.5)+
theme_minimal()+
labs(x="Item Outlet Sales", y= "Predicted Item Outlet Sales", title = "pRandom Forest Regression")

来自未调整随机森林模型的预测与实际商品销售散点图(图片由作者提供)
这里我们发现 RMSE(训练)= 1110.446,RMSE(测试)= 1126.359。随机森林模型确实有过度拟合的趋势,我们可以通过训练超参数来进一步改进模型,这也可以使用工作流和 dials 包来完成。
表盘—精炼模型开发
通过调整超参数来调整模型是模型开发的一个重要方面。
进入 dials 包和函数 grid_regular(),该函数用需要调优的超参数的每种可能组合建立一个 tibble。dialsgrid_regular 的工作方式类似于 dplyrexpand_grid。
下面,我们重新建立一个随机森林模型规范,这次将 trees 设置为 500,mtry 和 min_n 设置为 tune()。Mtry 是每次分裂时采样的预测值数量,min_n 是分裂节点的最小观测值数量。
正如前面一样,我们通过管道传输模型和配方规范,从而生成一个调整工作流。
此外,我们创建了一个 4 重交叉验证对象(vfold_cv)。
最后,我们通过初始化 tune_grid()(网格搜索)生成一个 tune_results 对象,它遍历 rf_grid 中的每个组合,tune_wf 使用 4 重交叉验证。
set.seed(256)
rf_mod <-
rand_forest(trees = 500,
mtry = tune(),
min_n = tune()) %>%
set_engine("ranger", importance = "impurity", num.threads = 12) %>%
set_mode("regression")#Establish Model Flow
tune_wf <- workflow() %>%
add_recipe(mart_recipe) %>%
add_model(rf_mod)#Generate grid to perform grid search for hyperparameter optimisation
rf_grid <- grid_regular(mtry(range = c(6,10)),
min_n(range = c(14,20)),
levels = c(10,9))# 4-fold Cross Validation Stratified by Item_Outlet_Sales
folds <- vfold_cv(train, v = 4, strata = Item_Outlet_Sales)#Train and evaluate all combinations of hyperparameters specified in rf_griddoParallel::registerDoParallel(cores = 12)
rf_grid_search <- tune_grid(
tune_wf,
resamples = folds,
grid = rf_grid)
请注意,我们已经利用并行处理来使用更多的工作站计算能力,因为网格搜索可能需要大量计算。
我们可以可视化这种计算的结果,并直观地看到哪个超参数组合提供最低的 RMSE。
rf_grid_search %>%
collect_metrics() %>%
filter(.metric == "rmse") %>%
select(mean, min_n, mtry) %>%
filter(mtry > 4) %>%
ggplot(aes(min_n, mean, color = as_factor(mtry))) +
geom_point()+
geom_line()+
scale_color_viridis_d() +
theme_minimal()+
scale_x_continuous(breaks = pretty_breaks())+
theme(legend.position = "bottom") +
labs(x = "Minimum Number of Observations to Split Node", y = "RMSE", title = "Grid Search Results for Random Forest", color = "Number of Predictors Sampled at Each Split")

随机森林的网格搜索结果(图片由作者提供)
调用 show_best()提供了关于网格搜索结果的更多细节
rf_grid_search %>% show_best()

show_best()的输出打印前 5 个结果(图片由作者提供)
我们可以使用网格搜索的结果来更新随机森林模型规范。
rf_best_rmse <- select_best(rf_grid_search, "rmse")
final_rf <- finalize_model(
rf_mod,
rf_best_rmse
)final_rf

网格搜索后的最终随机森林模型规格(图片由作者提供)
使用 vip 包,我们可以适应 final_rf 并突出显示前 10 个最重要的功能。
final_rf %>%
fit(Item_Outlet_Sales ~., data = bake(prep(mart_recipe),training(mart_split))) %>%
vip(geom=c("col"), num_features = 10) +
theme_minimal()

rf_final 模型的十个最重要的特性(图片由作者提供)
这真正突出了特征工程的重要性,其中一些是在我们清理数据或通过配方生成时创建的。
最后让我们评估一下 final_rf
final_wf <-
workflow() %>%
add_recipe(mart_recipe) %>%
add_model(final_rf)final_rf_res <-
fit(final_wf, training(mart_split)) %>%
predict(new_data = testing(mart_split)) %>%
bind_cols(mart_test %>% select(Item_Outlet_Sales))final_rf_res %>% ggplot(aes(x= Item_Outlet_Sales, y = .pred)) +
geom_abline(lty = 2)+
geom_point(alpha = 0.5)+
theme_minimal()+
labs(x="Item Outlet Sales", y= "Predicted Item Outlet Sales", title = "Tuned Random Forest Regression")

rf_final 的实际和预测产品销售散点图(图片由作者提供)
metrics(final_rf_res, truth = Item_Outlet_Sales, estimate = .pred)

度量函数的误差度量(图片由作者提供)
将 RMSE(测试)= 1120.365 与 RMSE(训练)= 1106.629 进行比较,我们将过拟合略微降低了 2 个 RMSE 单位,并在超参数调整后产生了略微更好的模型。
结论
该项目试图举例说明 tidymodels 元包的易用性,通过使每个步骤可管道化,拟合两种模型类型并根据测试集评估它们的性能,可以使用它来生成机器学习工作流。如果您想更进一步,训练 XGBoost 模型是非常容易的,为了简洁起见,我没有包括这一点。
将 tidymodels 与 sci-kit learn 进行比较的一个关键要点是,tidymodels 过程中的每一步都需要 tibble 数据帧,并且不需要将数据帧转换为矩阵。此外,鉴于一切都通过 tibbles 工作,正如我所演示的,这使得模型性能和超参数训练的可视化诊断更容易理解。
我强烈推荐那些有兴趣了解更多关于 tidymodels 的人去寻找神奇的朱莉娅·斯利格@https://juliasilge.com/,以及她与马克斯·库恩在备受期待的 Tidy Modeling with R 上的合作(你可以在这里预览一下https://www.tmwr.org/
BigQuery:审计和监控数据库的 3 种简单方法。
如何审计和监控您的 BigQuery 数据库,以保持其整洁和高效。
Google BigQuery 是一个可管理的、高度可伸缩的、无服务器的数据仓库,能够在几秒钟内查询万亿字节的数据。这是一个很棒的工具,数据分析师和科学家很容易使用。因为 GCP 使它完全被管理,你不必过多考虑数据库管理。

@sadswim 在 Unsplash 上的照片
多年来,我一直在使用老式的企业级数据库(Oracle,SAP / Sybase,..).我们需要团队中的数据库管理员,来管理数据库“健康”。
但是当谈到主要由数据分析师和数据科学家使用的完全托管的 BigQuery 数据库时,没有人接管这个角色是一个典型的陷阱。
因此,这里有 5 种简单的方法可以立即开始监控您的 BigQuery DB!
方法 1:元数据
元数据是提供关于其他数据的信息的数据。
—维基百科
对于关系数据库,元数据提供关于数据库本身的信息:模式、表、列或任何其他关于数据库元素和用法的信息。
GCP 和 BigQuery 提供了一些通过元数据监控数据库的便捷方法。
我不会详细讨论 BigQuery 的元数据,因为你可以参考 Skye Tran 的这篇文章。但是让我们有一个概述。
A. 信息 _ 模式
示例:深入了解模式中的表
-- Returns metadata for tables in a single dataset.SELECT * FROM `bigquery-public-data.census_bureau_international`.INFORMATION_SCHEMA.TABLES;

示例:显示按创建日期排序的数据集
SELECT * FROM myProject.INFORMATION_SCHEMA.SCHEMATA
ORDER BY creation_time;
b . _ _ 表 __
每个数据集都有自己的隐藏元数据表,名为 TABLES 。那个很有用!这是获取类似“您的表最后一次更新是什么时候?”或“你们的桌子有多大?”。
示例:数据集的表最后一次更新是什么时候?
SELECT
table_id, # creation_time and last_modified_time to a timestamp
TIMESTAMP_MILLIS(creation_time) AS creation_time,
TIMESTAMP_MILLIS(last_modified_time) AS last_modified_time, row_count,# convert size in MB
ROUND(size_bytes/(1024*1024),2) as size_mb,# Convert type from numerical to description
CASE
WHEN type = 1 THEN 'table'
WHEN type = 2 THEN 'view'
ELSE NULL
END AS type
FROM `bigquery-public-data.census_bureau_international`.__TABLES__
ORDER BY last_modified_time ASC

一种非常方便的分析数据集的方法
方法 2:将 Google Cloud 日志导出到 BigQuery
现在,您希望对数据库中发生的事情有更多的控制:您的表最后一次被访问是什么时候?一个用户“花费”多少?哪些桌子使用量最大?
即使无法通过 BigQuery 的元数据获得信息,您也可以通过将云日志导出到 BigQuery 来回答这些问题。
A.如何将日志从云日志导出到 Bigquery?
**步骤 1:创建一个新的 BigQuery 数据集来存储日志**
由于您希望在 BigQuery 中接收日志并使用 SQL 对其进行分析,因此最好通过创建新的数据集来组织数据库。选择一个方便的名称,如 日志 或 监控 。

第二步:创建云日志接收器
接收器允许您将日志或日志的过滤子集路由到选定的目的地。你可以使用 gcloud CLI 或谷歌云的用户界面来创建它。让我们使用第二种方法。注意:接收器不会用创建前的事件进行回填。
进入谷歌云日志,选择日志路由器。

点击**创建水槽。**给它起个名字。

选择大查询数据集作为目的地,并使用您新创建的数据集。我建议选中“使用分区表”选项:我可能会提高性能,并使您的数据集更具可读性。

最后,您可能希望使用一个过滤器来只包含相关的日志。
要导出核心 BigQuery 操作的所有记录,请使用过滤器:
protoPayload.metadata."@type"="type.googleapis.com/google.cloud.audit.BigQueryAuditMetadata"

第三步:从 BigQuery 查询您的日志
很快,您的日志就会流入数据集,形成 3 个表:
- cloud audit _ Google API _ com _ data _ access
- cloud audit _ Google API _ com _ activity
- cloud audit _ Google API _ com _ system _ event
cloudaudit_googleapis_com_data_access是迄今为止监控数据库最有用的表。让我们开始吧!
B.如何通过 cloud audit _ Google APIs _ com _ data _ access 进行审计?
分析访问可能会有很大帮助。现在我们已经在cloudaudit_googleapis_com_data_access中获得了“访问历史”日志,让我们运行一些查询吧!
例子:你的表最后一次被访问是什么时候?
SELECT# Dataset name
REGEXP_EXTRACT(protopayload_auditlog.resourceName, '^projects/[^/]+/datasets/([^/]+)/tables') AS dataset,# Table name
SPLIT(REGEXP_EXTRACT(protopayload_auditlog.resourceName, '^projects/[^/]+/datasets/[^/]+/tables/(.*)$'), '$')[OFFSET(0)] AS table,# Last access date
MAX(timestamp) as last_accessed_at,# Was it a Read or Write operation ?
CASE WHEN JSON_EXTRACT(protopayload_auditlog.metadataJson, "$.tableDataRead") IS NOT NULL THEN 'Read'
WHEN JSON_EXTRACT(protopayload_auditlog.metadataJson, "$.tableDataChange") IS NOT NULL THEN 'Change'
END method,# Optionally: display the user who executed the operation
#protopayload_auditlog.authenticationInfo.principalEmailFROM logs.cloudaudit_googleapis_com_data_accessWHERE
JSON_EXTRACT(protopayload_auditlog.metadataJson, "$.tableDataRead") IS NOT NULL
OR JSON_EXTRACT(protopayload_auditlog.metadataJson, "$.tableDataChange") IS NOT NULLGROUP BY dataset, table, method# Optionally: Select a specific dataset
#HAVING dataset = 'public'ORDER BY last_accessed_at desc

上次访问的表
示例:您的数据库每天/每小时/每月的成本是多少? 这个方便的要求直接来自于的文档。
SELECT# Adapt the period of time according to your needs
TIMESTAMP_TRUNC(TIMESTAMP(JSON_EXTRACT_SCALAR(protopayload_auditlog.metadataJson, "$.jobChange.job.jobStats.endTime")), DAY) AS period,FORMAT('%9.2f',5.0 * (SUM(CAST(JSON_EXTRACT_SCALAR(protopayload_auditlog.metadataJson, "$.jobChange.job.jobStats.queryStats.totalBilledBytes") AS INT64))/POWER(2, 40))) AS Estimated_USD_CostFROM logs.cloudaudit_googleapis_com_data_accessWHEREJSON_EXTRACT_SCALAR(protopayload_auditlog.metadataJson, "$.jobChange.job.jobConfig.type") = "QUERY"GROUP BY periodORDER BY period DESC
示例:您的数据库每个用户每月的费用是多少? 和前面的要求类似,我们来分解一下每个用户每月的费用!
SELECT# Adapt the period of time according to your needs
TIMESTAMP_TRUNC(TIMESTAMP(JSON_EXTRACT_SCALAR(protopayload_auditlog.metadataJson, "$.jobChange.job.jobStats.endTime")), MONTH) AS period,# User
protopayload_auditlog.authenticationInfo.principalEmail as principal,FORMAT('%9.2f',5.0 * (SUM(CAST(JSON_EXTRACT_SCALAR(protopayload_auditlog.metadataJson, "$.jobChange.job.jobStats.queryStats.totalBilledBytes") AS INT64))/POWER(2, 40))) AS Estimated_USD_CostFROM logs.cloudaudit_googleapis_com_data_accessWHEREJSON_EXTRACT_SCALAR(protopayload_auditlog.metadataJson, "$.jobChange.job.jobConfig.type") = "QUERY"GROUP BY period, principalORDER BY period, principal DESC
您可以在文档中找到更多请求示例。请随意创建您自己的!
额外收获:BigQuery 实用程序
由于cloudaudit_googleapis_com_data_access可能会令人困惑,BigQuery 通过 BigQuery utils 项目提供了这个表的帮助视图。
如果您遵循了本文的内容,就不需要重新创建日志接收器。只需跳到先决条件的步骤 3 和 4,执行。sql 脚本,一切都准备好了!
结论
通过 BigQuery 中的 INFORMATION_SCHEMA 、 TABLES 和**云日志,您现在有 3 种简单的方法来审计和监控您的数据库。**
因为您不想每次检查数据库健康状况时都重写所有这些查询,基于您最常用的分析创建视图是一个好的实践。您还可以基于某些阈值创建警报,但那是以后的事情了!
基于 BQ ML 的 K 均值聚类的大查询异常检测
理解大数据
你有没有利用你的系统来发现它本身的错误?

威尔·迈尔斯在 Unsplash 上的照片
用例
在愉快的 12 月,当你不在办公室,享受 COVID 让你享受的户外时光时,你团队的两名开发人员使用一些服务帐户(甚至可能是他们的私人帐户)运行了一系列流氓查询,看你是否能识别他们。他们拒绝给rogue下定义,希望看看 ML 在网络安全领域有没有用。
或者,您怀疑 BQ 数据集中的外部活动,并希望了解 ML 在网络安全领域是否有优势。[ಠ_ಠ]
剧透:是。
方法
我们将在 BQ 数据库中收集所有交易的元数据。我们将使用 BQ 机器学习(BQ ML)来训练一个(无监督的)Kmeans 算法来对事务进行聚类。我们将使用这些聚类信息来预测异常值。
生成数据集
CREATE OR REPLACE TABLE
`analysis.ref_data_training` AS
SELECT
*
FROM
`region-xx`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
WHERE
DATE(creation_time) BETWEEN "2020-11-01" AND "2020-12-01"
让我们将上述日期之间的数据视为我们的训练数据。这假设在此期间没有发生欺诈性交易,并且我们基于此数据生成“正常”聚类。region-xx应替换为适当的区域。此外,让我们假设在2020-12-01 to 2021–01–01期间存在欺诈/异常交易。我们用这段时间创建一个类似的表analysis.ref_data_testing。
该表包含我们将用于构建模型的以下各列:
job_id
creation_time
end_time, start_time
**statement_type**
**query**
total_bytes_processed
total_slot_ms
destination_table.dataset_id
创建模型
CREATE OR REPLACE MODEL
`anomaly_kmeans_001` OPTIONS (model_type='kmeans',
standardize_features = TRUE) AS
SELECT
r.job_id,
EXTRACT (HOUR
FROM
creation_time) AS hod,
EXTRACT (DAYOFWEEK
FROM
creation_time) AS dow,
TIMESTAMP_DIFF(end_time, start_time, MINUTE) AS duration_mins,
statement_type,
ML.NGRAMS(bt.words_array,
[1,
2]) query_grams,
query,
total_bytes_processed,
total_slot_ms,
destination_table.dataset_id AS dest_dataset_id
FROM
`analysis.ref_data_training` r
JOIN (
SELECT
REGEXP_EXTRACT_ALL(LOWER(query), '[a-z0-9]+') AS words_array,
job_id
FROM
`ref_data_training`) AS bt
ON
r.job_id = bt.job_id
ORDER BY
RAND() --usually *rand() < number_rows/total_rows* works well
LIMIT
100000 --depending on your data size, you might want to skip this
我们还制作了某些功能,比如一天中的某个时间hod和一周中的某一天dow。此外,我们还有一个主要特性**query_grams**,这将是集群的定义特征。您可以将 grams 扩展到 2 以上进行实验。
在模型创建过程中,我们不指定最佳(相关读数)的集群数量,我们让 BQ ML 来处理。
一旦你的模型完成训练,一定要检查它的统计数据。您可以像在 BQ 中预览表格一样进行操作。它有很多方便的可视化。
可视化示例分类特征、一些数字特征的质心点

语句 _ 类型分布[图片由作者提供]

我们的数字特征,所有这些都需要一些额外的预处理
预测未知样本的正确聚类
CREATE OR REPLACE TABLE
`analysis.predicted_clusters` AS
WITH
refs_table AS (
SELECT
r.job_id,
EXTRACT (HOUR
FROM
creation_time) AS hod,
EXTRACT (DAYOFWEEK
FROM
creation_time) AS dow,
TIMESTAMP_DIFF(end_time, start_time, MINUTE) AS duration_mins,
statement_type,
ML.NGRAMS(bt.words_array,
[1,
2]) query_grams,
query,
total_bytes_processed,
total_slot_ms,
destination_table.dataset_id AS dest_dataset_id
FROM
`analysis.ref_data_testing` r
JOIN (
SELECT
REGEXP_EXTRACT_ALL(LOWER(query), '[a-z0-9]+') AS words_array,
job_id
FROM
`analysis.ref_data_testing`) AS bt
ON
r.job_id = bt.job_id)
SELECT
* EXCEPT(query_grams) --we don't want to complicate o/p table
FROM
ML.PREDICT( MODEL `analysis.anomaly_kmeans_001`,
(
SELECT
*
FROM
refs_table))
由ML.PREDICT函数返回的两个重要列:CENTROID_ID和一个嵌套的NEAREST_CENTROIDS_DISTANCE.第二列包含一个数组centroid_id和distance。不用说,实例被分配给具有最小distance的centroid_id的集群。
这个嵌套字段也可以用于其他目的。
计算百分位数
您现在可能已经猜到了,这个想法是离群值(流氓事务)将会相对远离群集质心。我们创建一个表来存储百分位数(9990 是 99.90%的简写)。如果不清楚,99.90%的分类实例的distance小于该值。
两个音符:
- 根据数据的大小,您可以使用不同的百分点(例如 75%、90%和 95%)
- 您不需要存储这些百分点,我这样做是为了保持持久性。
CREATE OR REPLACE TABLE
`analysis.percentiles_anomaly` AS
SELECT
percentiles[
OFFSET
(9500)] AS p9500,
percentiles[
OFFSET
(9900)] AS p9900,
percentiles[
OFFSET
(9990)] AS p9990,
percentiles[
OFFSET
(9999)] AS p9999
FROM (
SELECT
[APPROX_QUANTILES](https://cloud.google.com/bigquery/docs/reference/standard-sql/approximate_aggregate_functions#approx_quantiles)((dist_from_centroid), 10000) AS percentiles
FROM (
SELECT
job_id,
c.CENTROID_ID,
MIN(ncd.DISTANCE) AS dist_from_centroid
FROM
`analysis.predicted_clusters4` c,
UNNEST(NEAREST_CENTROIDS_DISTANCE) AS ncd
GROUP BY
1,
2) t) AS t2
附加说明
理想情况下,我们应该独立计算每个聚类的百分位数,因为聚类不是均匀分布的。修改上面的查询来反映这一点。
我看到你了,异常点
是时候根据预测数据和距离百分位数剔除欺诈交易了。从最高的百分位数开始,查看有多少个实例被归类为异常值,然后继续往下。
CREATE OR REPLACE TABLE
`analysis.anomalies9999` AS
WITH
anomalies AS (
SELECT
job_id,
c.CENTROID_ID,
MIN(ncd.DISTANCE) AS dist_from_centroid
FROM
`analysis.predicted_clusters4` c,
UNNEST(NEAREST_CENTROIDS_DISTANCE) AS ncd
GROUP BY
1,
2
HAVING
MIN(ncd.DISTANCE) >= **34.3668866** --example percentile 99.99
ORDER BY
dist_from_centroid DESC)
SELECT
d.*
FROM
`ref_data_check_all_datasets` d
JOIN
anomalies a
ON
a.job_id = d.job_id
运行常规查询的服务帐户靠近质心,它们没有出现在上述潜在异常中。出现的一些实例具有以下特征:
- 唯一查询从个人用户帐户运行,具有少量的总生存期查询。
user_email是我们选择忽略的一个特性,因为我们想在交易级别而不是用户级别检查完整性。 - 各种帐户运行的错误查询。
- 在它们各自分布的尾部具有上述特征的查询。e.x 极高的
total_bytes_processed值。McTotallyRealPherson 先生又忘记用分区了。😞💰 - 对这些异常的
dow和hod过滤有助于进一步缩小范围。同样的还有statement_type和user_email。
喜欢读中肯的文章?我喜欢写them。
如何优化 BigQuery 的使用和成本
原文:https://towardsdatascience.com/bigquery-costs-and-optimization-a841ffbbb8ff?source=collection_archive---------56-----------------------
使用谷歌数据仓库时你应该知道的最佳实践

在 Unsplash 上由 Delphine Ducaruge 拍摄的照片
BigQuery 是一种 SaaS (软件即服务)数据仓库技术,将按照付费模式向您收费。在这个小故事中,我想告诉你价格是多少,以及如何优化你的使用。
哪些行动需要成本?
首先是好的方面 BigQuery 中的一些操作是免费的,比如:
- 加载数据(例如从存储桶)
- 提取数据(例如,提取到 Google 工作表)
- 复制数据(例如,复制到新表中)
- 删除表、视图和数据集
- 集群和分区表
但是你大概可以猜到,最常见的活动如:
- 数据存储
- 查询数据
确实花了一些钱。特别是最后一个功能是谷歌如何赚钱的。更多详情请访问谷歌大查询定价【1】。
这些行动的成本是多少?
通用概述将让您初步了解 BigQuery 中最常见任务的成本:
- 查询:按处理的字节收费,每 TB 5 美元(每月第一个 TB 免费)
- 存储:对于 BigQuery 存储 API,每月存储的 GB 数将为 0.02 美元(活动存储)和 1.10 美元/TB
- 流式插入将花费您每 GB 0.05 美元
这些是谷歌显示的美国地区的当前价格,其他地区的价格有所不同。
BigQuery 与其他技术相比如何?
将价格与亚马逊的 Redshift 或 Snowflake 等其他技术进行比较很难,因为这取决于用例以及您如何优化每项技术。同样,价格也非常相似 —这里 fivetran 发布了一个超级好的基准【2】。在这个基准测试中,他们得出了相同的结论。然而,重要的是要强调 BigQuery 提供了最高的 SaaS 感受——因此您不必太担心供应和操作,这同样对成本有积极的影响。根据我自己的经验,我可以肯定 BigQuery 不仅易于使用,而且运行起来比传统的数据仓库更便宜。
最后,您如何优化您的使用?
- 使用 web UI 中的验证器来帮助计算成本——UI 和 CLI 将返回查询中处理的字节数。

已处理的预测字节数—按作者分类的图像
2.使用 SuperQuery——使用 super query(例如可以通过 Chrome 安装),你甚至可以直接计算每次查询的费用。此外,该附件还提供了许多其他有用的功能[3]。

超级查询价格预测-作者图片
3.**仅包含您需要的列和行** —尤其是不必要的列会产生额外的成本,这很容易避免。
4.尽可能使用缓存结果和永久表来代替视图。
5.监控您的使用情况 —借助 GCP 的日志和监控服务,您可以创建仪表盘和警报。在标准监控中,您已经有了一个很好的概述。

GCP 标准监控—用户提供的图像
但是要了解更多细节,例如哪个用户查询了哪些数据以及查询的成本,您可以使用 Stackdriver。
6.使用 Limit 仍然会处理所有行——所以要注意那个陷阱。
7.删除重复和不必要的数据 —人们经常犯保存不必要的数据的错误(我以后可能需要这个)。这应该通过严格的数据治理来避免,这样就不会出现数据沼泽。
8.使用集群 —它可以提高某些类型查询的性能,例如使用筛选子句的查询和聚合数据的查询。
9.使用分区表 —表将被分成段,称为分区,这使得管理和查询数据更加容易。此外,它会节省你的钱。
结论
我希望这篇文章在成本和成本优化的最佳实践方面有所帮助。我本人是 BigQuery 的忠实粉丝,并在专业和私人场合使用它。它有很多优点,速度超级快。但是,我也知道,考虑一些事情来对抗不必要的成本是很重要的。尤其是在企业家的意义上,人们真正谈论的是大数据。在这里,即使是小错误和反模式也会很快导致大的成本劣势。如果你也有任何建议,请随时告诉我。
资料来源和进一步阅读
[1]谷歌,定价 (2021)
[2] fivetran, 2020 数据仓库基准测试 (2020)
【3】super Query,写出完美的查询。每次都是。 (2021)
大查询获取+多重处理
原文:https://towardsdatascience.com/bigquery-fetching-multiprocessing-dcb79de50108?source=collection_archive---------13-----------------------
多重处理是否提高了 BigQuery API 请求的抓取速度?

作者图片
BigQuery 存储读取 API 可用于从 BigQuery 表中获取数据。然而,在我写这些代码的时候,还没有为了更快地处理读取而使用这个 API 结合多处理进行基准测试。
在本文中,我将展示我所做的一些研究和基准测试,以便找到从 BigQuery 获取数据的最佳方法。
抓取+多重处理
从 BigQuery 获取数据的最常见和最简单的方法是只使用机器/实例上的一个内核来线性处理获取。
然而,如果您正在使用具有多个内核的计算机或 GCP 计算引擎(GCE ),您可能想知道使用它们来并行处理更多数据是否有用,但是有一个关键概念需要理解:
内核越多,读取速度不一定越快。从互联网上获取一些数据所需的时间很大程度上取决于路由器/网络上可用的互联网带宽。
因此,在您的设备上拥有 200 个内核并不意味着您的获取处理速度会快 200 倍,而是可以创建 200 个进程,每个进程将获取一个表块(使用较少的带宽),以便最终将它们合并到一个表/数据帧中。
参考 GCE 文档,每个 vCPU 可以处理 2GB 的入口,最多 6 个 vCPU。所以我构建了一个工具:**bqfetch**,它给出了要使用的核的数量,可以获取一个或多个核的表。如果nb_cores =-1,那么算法将使用机器上可用的虚拟 CPU 的数量,它将为每个内核创建一个进程,并并行处理它们。该工具适用于multiprocessing、billiard和joblib平行后端。
为了证明 BigQuery 存储在多处理中是否有效,我使用 1 到 6 个内核在 2GB 的表上独立运行了 6 次读取,并测量了所用的时间。这是使用该工具的实际代码:
中篇关于 bqfetch 快取库。
注意,为了获取巨大的表(多个 TB ),我们必须将整个表分块/分割成可以放入内存的更小的块。因此,第一步是使用chunks()方法划分表格。我们必须指定要用作索引的列,以便将该列中的所有不同值分成多个块。我们还必须指定我们想要处理的每个块的大小,因此这个值必须小于机器上的可用内存(如果是这样,将会出现一条警告消息)。详细模式打印内存信息以及区块的数量/大小。
在中,下面的例子将整个表分成大小为 2GB 的小块和**连续使用 1 到 6 个内核获取它们**,仅用于演示目的。注意,在这种情况下,块的大小和表的大小是 2GB,所以只有一个块将被
chunks()方法返回,但是在实际使用情况中,您将指定一个更大的表,并且该方法将返回一个块的列表以进行顺序处理。
在 12 个虚拟内核的 MacBook Pro 上的结果

作者图片:获取 2GB 表作为 pandas df 的时间,取决于核心/进程(PC)的数量
如图所示,在使用标准 Wi-Fi 连接的个人电脑上使用多个内核并不能提高性能,甚至会更差。这是可以预料的,因为网络上可用的互联网带宽保持不变,即使我们使用多个内核来获取数据。由于每个进程必须创建一个新的 ReadSession 以从 BigQuery 读取数据,这需要更多的时间,因为我们必须并行初始化多个连接,并且我们还必须在每个进程完成时合并结果。
在 30 个虚拟内核的 GCP 计算引擎上的结果

作者图片:获取 2GB 表作为 pandas df 的时间,取决于核心/进程的数量(GCE)
使用 GCE 时,会出现同样的问题,当内核数量增加时,性能仍然会更差。根据 GCE 文档,我们应该增加网络带宽,那么问题是什么呢?发生这种情况的原因对我来说很模糊,但我猜这是由于 BigQuery 限制关于每个请求的行过滤器的大小只有 10MB。
结论
- 在我写这几行文字的时候(2021 年 8 月),Google 还没有提出任何原生实现来高效地使用多处理 BigQuery 存储。因此,由于 API 的限制,我们实现这一目标的唯一方法并没有像我们希望的那样优化。我们必须等待 API 贡献者的进一步改进,以便有可能使用这种方法获得性能。
- 您可以使用我已经实现的工具通过 BigQuery API 使用多处理来做您自己的测试。代码是开源的,所以欢迎你来查看或投稿。
用于排列测试的 BigQuery 存储过程
原文:https://towardsdatascience.com/bigquery-stored-procedure-for-permutation-test-35597d6379e4?source=collection_archive---------21-----------------------
在 Google BigQuery SQL 中运行置换测试的简单方法
存储的过程允许我们执行打包成一个“函数”的多个Google biqquery SQL操作。了解如何使用存储过程快速有效地对任何数据集应用置换测试。
只需要密码?从这里开始别忘了启动它!⭐️

向您的 BigQuery SQL pantry 添加另一罐技巧|照片由 Luisa Brimble 在 Unsplash 上发布
我还有几个 BigQuery 教程:
要获得所有媒体文章的完整访问权限,包括我的文章,请考虑在此订阅。
什么是存储过程?

不,存储过程不存储在软盘上|照片由 Fredy Jacob 在 Unsplash 上拍摄
在 BigQuery 中,可以编写自定义,用户自定义函数(UDF)。这些函数非常棒,因为您可以减少代码中的重复,使代码对其他人更具可读性。然而,你也可以在 BQ 中编写脚本。这包括循环、if 语句、变量声明等。不允许在函数中使用它,因为函数是作用于表元素的,而不是作用于脚本中的变量。
这就是存储过程的用武之地。把它们看作是函数的等价物,但不是脚本的等价物。有了它们,您可以重复所有复杂的 SQL 逻辑,即使它们包括变量和 for 循环的赋值。
这篇来自 Google Cloud 的文章介绍了存储过程的概念,如果你需要复习 BigQuery 脚本,这里有关于如何编写循环和条件的官方文档。
谈到存储过程,有几个问题。最大的问题是它们可以接受一个或多个输入,但是输出必须是声明的变量。例如,要运行文档中的示例,我们必须首先声明一个适当的变量来存储结果:
这个例子摘自官方公告。
如果你不知道上面的程序在做什么,也不用担心。我们稍后会在这里做一个例子。
一旦您用CREATE PROCEDURE命令创建了您的过程,它将像 BigQuery 中的任何其他表一样显示,并且您将能够用通常的dataset.procedure()符号调用它。
让我们看看这一切是如何工作的。
带有存储过程的斐波那契数

斐波那契无处不在|照片由Yair MeJA在 Unsplash 上拍摄
我总是发现,如果例子中的逻辑很容易理解,那么例子是最好的。为此,我将创建一个存储过程,当调用时,计算第 n 个斐波纳契数。
作为复习,斐波纳契数列是一个自然数序列,其中第 n 个元素由F(n)表示,并由F(n) = F(n-1) + F(n-2)和 F(0) = 0以及F(1) = 1定义。所以你得到:0,1,1,2,3,5,8,13…
为了做到这一点,我们将首先使用脚本来完成,然后将其包装在一个过程中。我们需要做的是:
- 初始化我们的变量——我们需要记录我们已经计算了多少个数字,以及何时完成计算
- 做一个 for 循环,其中每一步我们**更新我们当前跟踪的 2 个数字**
- 选择我们的答案并打印到控制台
我在上面的脚本中添加了一堆注释,所以要确保你明白是怎么回事。
我总是建议先写脚本,然后把它改成存储过程。您会发现这样调试容易多了。
这些关键字执行以下操作:
DECLARE创建一个具有特定类型的新变量,并将其设置为默认值SET将已经声明的变量更新为新值WHILE <cond> DO和END WHILE缠绕我们的 while 循环。SELECT是你的普通 SQL 语句打印到控制台的答案
如果我们运行上面的代码,我们会将13打印到控制台,这是第 7 个斐波那契数列的正确答案。通过更改代码的第一行并将i设置为其他值来尝试其他数字。
现在剩下要做的就是将上述内容包装在一个过程中,并将其存储在一个数据集中。我们是这样做的:
变化不大,但有几件重要的事情需要注意:
- 我们通过
CREATE PROCEDURE声明我们的过程,后面是数据集和我们想要存储它的过程名。确保您已经创建了数据集*ds*! - 我们必须声明我们的过程输入—
i INT64在过程的顶部。 - 我们对它的输出做同样的事情:
OUT answer INT64。 - 输入和输出不再需要在过程内部声明,所以我们
SET将答案设为 0,而不是使用默认值。 - 我们将整个脚本包装在
BEGINEND语句中。
如果您运行上面的代码,您应该会得到类似于:该语句创建了一个名为 your-project-name.ds.fibonacci 的新过程。
为了使用这个过程,我们需要声明一个整数变量和CALL过程来填充它。
如果你都做对了,你应该得到:55 (8+13 =21,13+21 = 34,21+34=55)。🎉
仅此而已。您现在知道了如何使用 BigQuery 脚本编写存储过程。给自己一个读到这里的掌声吧!
我想,即使是岩石也赞同 BigQuery 过程… | 来源
什么是排列测试?

由卡洛斯·鲁伊斯·华曼在 Unsplash 上拍摄的照片
我听到你在说什么了。"这些都很酷,但为什么有用呢?”。好吧,如果我告诉你,你可以用 SQL 在一些巨大的数据集上运行一些超级的统计测试,而且很便宜,会怎么样呢?这正是我们在这里要做的😉!
我知道我不会很好地解释什么是排列测试,所以看看 Jared Wilber 的这个很棒的网站,在那里你会读到一个羊驼洗发水的实验。
简而言之,这就是排列测试:
- 无效假设是两组的统计数据相同。
- 你用统计学来衡量差异(在我们的例子中是指)。
- 然后,假设零假设是真的,你在 2 组之间排列观察。这里的逻辑是,如果零假设确实是真的,那么你如何给你的实验对象贴上标签并不重要。
- 然后你数一数有多少次你观察到排列的统计差异比正确标记的设置更极端。
- 这一比率将给出您的 p 值,即我们由于随机运气观察到这样或更极端值的概率。
- 如果 p 值很低(例如< 5%) then you reject the null hypothesis.
But as I said, Jared 的网站做得更好,所以请去看看。
使用 BigQuery SQL 进行排列测试

使用 BigQuery 的强大功能,我们可以快速有效地调整数据集|图片来自Amol ty agionUnsplash
我再次建议,在用程序把事情复杂化之前,先弄清楚你的脚本的逻辑。在我们做任何事情之前,我们需要设定一些要求。我们需要一个至少有两列的表:一列是我们要取平均值的值,另一列是我们的组标签的 0 和 1。我们还假设我们的样本大小相等。这不是问题,因为我们将使用 BigQuery 中 iris 数据集的子集,其中 Virginica 和 Versicolor 物种都有 50 个观察值。
我们准备好实施我们的计划了。这是我们要做的:
- 将我们的表格列重命名为 measurement and treatment(0 和 1 ),以使脚本的其余部分更加一致。
- 添加另一个
row_id列以确保我们能够以一种简单的方式对进行采样。我在这里解释了我们如何以及为什么要这样做。 - 用整数列表进行交叉连接——每个置换样本一个。
- 记录原始表格的观察差异。
- 记录我们排列的平均差异。
- 计算我们得到的差高于或等于我们原始均值差的次数的比率。
下面是 SQL 的样子:
以上只是普通的 SQL,我一直建议你以这种方式开始。当我们想把它变成一个程序时,事情就变得复杂了…
我们希望我们的过程接受下面的输入:
- 我们要对其应用测试的表的名称。
- 包含测量值的列的名称。
- 包含我们的治疗标志的列的名称。
- 我们想要进行的排列的数量。
据我所知,我们不能只是将表名粘贴到脚本中,所以我们将在 BigQuery 中使用可爱且非常强大的EXECUTE IMMEDIATE命令来完成这项工作。这个家伙基本上运行一个字符串作为 SQL 语句,允许我们动态地编写 SQL 字符串,然后执行它。相当整洁!
是的,立即执行就是那种强大的… | 来源
由于我们的查询很长,我决定使用CONCAT函数将多行字符串组合成一行。这对于调试来说非常烦人,所以我建议您运行您的函数的第一遍,将合成的 SQL 复制到一个新窗口中,并使用 BigQuery UI 在那里调试您的查询——相信我,您会看到许多遗漏的逗号和空格弄乱了您的查询😉,我当然做了。
第 15、16 和 19 行是奇迹发生的地方。
这比我们之前的查询更难理解,但基本上是一样的。我只是在列名和表名中使用了字符串串联||到粘贴以及我们在前 2 个表中要求的排列数。其余的不变——因此有了标准化的列名😃。
运行以上程序来存储您的过程!然后我们准备准备我们的桌子。我们将使用经典的免费 Iris 数据集,它可以作为 BigQuery 表在bigquery-public-data:ml_datasets.iris下获得。我们将扔掉setosa品种,因为我们只需要 2 个,我们将询问海滨锦鸡儿花是否有更大的萼片宽度。如果你需要复习虹膜数据集,我推荐这款 Kaggle 笔记本。
我特意将所有的专栏都留在那里,以便您也可以对其他专栏尝试这个过程。
我们有桌子和程序。是时候创建一个浮点变量并调用我们的排列测试了:
运行上面的程序,我得到的 p 值是 0.0008499,非常小。因此,我们得出结论,弗吉尼亚种的萼片宽度明显大于云芝种。
BigQuery 的美妙之处在于,我们为查询的字节付费,而不是为 CPU 时间付费。因此,我们可以将排列增加到 100 万,但仍然只为 1.56KBs 的查询付费。
🙏请在一些较大的数据集上尝试上述方法并评论一下它完成查询的速度,我很想知道你的结果。
结论

照片由 Massimo Sartirana 在 Unsplash 上拍摄
希望您会发现以上内容对您的数据科学工作流程有用。现在,您不必将大型 BigQuery 数据集导出到磁盘,租用半 TB 的内存机器并在其上运行 Python 来做一些统计测试,您可以在 BigQuery 中便宜而有效地完成所有这些工作。
如果没有别的,请记住以下几点:
- 一个存储过程是一个可重用的 BigQuery 脚本(带有循环和变量),它接受输入并产生一个输出变量。
- 程序以
CREATE PROCEDURE dataset.procedure_name(inputs..., output) BEGIN开始,以END结束。 - 不要
DECLARE输入或输出变量。使用SET改变变量值。 EXECUTE IMMEDIATE可能是最强大的脚本关键字,允许您将任何字符串作为 SQL 语句执行。- 用
CONCAT和||将表名和变量名粘贴到 SQL 字符串中。 - 总是首先在过程之外调试 SQL 脚本!
感谢一路读到最后。我写了一些关于 BigQuery、Julia 和 Python 的文章,所以如果这些教程对你有帮助的话,请随时关注我。
想要更多 BigQuery 采样教程吗?看看这个。
用于细粒度视觉识别和多模态深度学习的双线性池
原文:https://towardsdatascience.com/bilinear-pooling-for-fine-grained-visual-recognition-and-multi-modal-deep-learning-20051c1f0e7e?source=collection_archive---------14-----------------------

巴德·赫利松在 Unsplash 上的照片
高级神经网络架构通过学习特征交互来工作
双线性池起源于计算机视觉社区,作为一种细粒度视觉识别的方法。或者用不太花哨的语言来说,一种在识别和分类视觉对象时寻找特定细节的方法。在高层次上,该方法的工作方式如下。给定一个输入图像 I ,我们将 I 送入两个不同的深度卷积神经网络 A 和 B,见图 1。在应用若干池化和非线性变换之后,我们从 A 和 b 输出特征图。这两个网络可以被预训练以解决不同的任务。直觉是,A 和 B 以这种方式从输入图像中学习不同的特征。例如,A 被训练来检测基本的物体形状,而 B 检测纹理特征。然后,来自 A 和 B 的输出特征由所谓的双线性池层组合。这仅仅意味着我们通过取它们的内积,将 A 的每个特征与 B 的每个特征结合起来。读者可能会注意到,这类似于支持向量机中的 2 次多项式核。双线性池层背后的直觉是,这些特征交互允许我们检测图像的更多特定细节。

图一。双线性池的整体结构。来源[1]
原始建筑
我假设读者熟悉卷积神经网络的基础知识。不然我推荐这些入门讲义。
图 1 中网络 A 的输出是一个维数为 n×d 的矩阵 U,或 n×d*,*,网络 B 的输出是一个维数为 m×d 的矩阵 V,在 CNN 的上下文中,n 和 m 分别是 A 和 B 的输出层中滤波器(或内核)的数量。每个滤波器的维数是 *d,*它是通过展平二维特征图获得的,即经过几次核卷积和汇集变换的输出图像。双线性池操作被定义为

等式 1。双线性池。
然后,矩阵 Z 被展平成维数为 m*n 的向量 Z。Z 和可学习向量 w_k 的内积被提供作为 softmax 激活函数的输入,其中 K 个类别中的类别 K 的概率被计算为:

等式 2。使用双线性映射进行分类。
在上面,w_k 是维数为 m*n 的可学习向量,它模拟向量 z 属于第 k 类的概率,1≤k≤K。
双线性池为什么有效?
如前所述,双线性池的核心是明确考虑特征交互的思想,类似于支持向量机中的多项式核。让我们考虑一个具体的例子。作为第一个应用,双线性池用于细粒度的图像分类。考虑图 2,我们想解决一个鸟类分类问题。显然,这些都是彼此相似的鸟类,我们需要具体的细节来正确区分不同的物种。对于图 1 中的两个神经网络 A 和 B,假设 A=B,并对 A 和 B 使用预训练的 VGG16 模型,VGG16 是一个深度 CNN 模型,已经在 ImageNet 2014 挑战赛的大量图像上进行了训练,其中图像属于 1,000 个类别中的一个。很明显,VGG16 可以检测鸟类羽毛、喙、颜色等形状。然而,许多鸟类都有相同的喙形。

图二。即使对一个人类专家来说,正确分类所有的鸟类也是一个挑战。来源[2]
VGG16 足以正确区分鸟类和猫,但要正确区分不同的鸟类是有挑战性的,差异已经非常微妙了。为了区分不同的物种,我们需要明确地考虑这些特征的组合。这样的组合对每个物种来说更有可能是独一无二的。羽毛颜色和鸟喙形状的结合更有可能唯一地识别一种鸟。因此,使用正确识别某些基本形状的预训练模型,我们可以了解这些形状的哪些组合对于手头的分类问题是重要的。
用于多模态学习的双线性池
双线性池的另一个主要应用是结合不同领域的神经网络模型。例如,在视觉问答中,训练数据由自然语言和图像中的问题组成,参见图 3 中的示例。

图 3。集合视觉和语言特征进行视觉问答。来源[3]
双线性池的变体
有几种不同的方法可以使用双线性池。
- **单个神经网络 vs 两个网络。**网络 A 和 B 可以是相同的网络,即 A=B。如在计算机视觉示例中所讨论的,我们然后从输出神经网络的不同通道学习重要的特征对。对于多模态问题,当我们组合来自不同领域的特征时,网络 A 和 B 当然彼此不同。
- 端到端架构与预训练模型。两个网络 A 和 B 可以是像 VGG16 那样的具有固定权重的预训练网络。在这个设置中,新的输入通过 A 和 B 传递,然后我们只学习双线性层的权重。在端到端架构中,来自双线性层的误差反向传播到 A 和 B,并且更新它们各自的参数。双线性层是可微分的,它可以由众所周知的深度学习框架来处理,如 TensorFlow 或 PyTorch。
计算的复杂性
显然,双线性池的一个主要缺点是它的计算复杂性。矩阵乘法

时间复杂度为 O(mnd)。通常,t 尺寸 d 相当小。想象一个 CNN,我们从 256x256 像素的图像开始逐渐粗化维度,更深的层具有 16x16 维度的核图。另一方面,为了获得强大的模型,核的数量需要更大。高级架构使用几千数量级的 m 和 n。对于具有 K 个类别的分类问题(见等式 2),这意味着我们需要 Kmn 个可学习的参数,其数量级可以是几百万。这可能使双线性池难以训练,并容易过度拟合。
可伸缩双线性池的矩阵分解
已经设计了几种旨在降低原始算法的计算复杂度的方法。我将介绍一种矩阵分解方法。
设 W_k 是一个 m 乘 n 矩阵,具有可学习的双线性权重。方程 2 中的向量 w_k 是平坦矩阵 W_k,网络 A 的输出是 m-次-d 维的矩阵 U,网络 B 的输出是 n-次-d 维的矩阵,设第 I 列 U 为 u_i,V 的第 I 列为 v_i,特殊情况 d=1 时,矩阵 U 和 V 只是单列。

z_i 是 u_i 和 v_i 的平坦的外积,我们可以证明以下等式成立:

上面简单地写出了等式两边的量。
根据定义,它成立

因此,我们可以将内积重写为

为了提高计算复杂度,我们可以用低秩分解来代替双线性矩阵 W_k:

在上面,r 是一个小常数,使得 r < min(m,n)。
因此,我们获得内积的以下表达式:

注意,右边求和的计算复杂度是 d*(mr + nr)。因为 r 是一个小常数,比 m 和 n 小得多,所以我们实现了更好的运行时间。此外,双线性池图层的可训练参数的数量从 Kmn 减少到 K*(m+n)r。为了更好地了解这两个量的比较情况,请考虑一个 CNN,其典型值为 m=n=1,000 个过滤器和 K=10 个类。使用 r = 20,我们从 10⁷到 410⁵减少了可学习参数的数量,即因子分解双线性池中的参数数量仅为原始设置的参数数量的 4%。
双线性池的缺点和限制
最后,我们应该提到双线性池的一些限制:
- 对于两个输出,特征向量 d 的维数必须相同。对于两个 CNN 模型来说,这不是一个大问题,但是对于多模态双线性池来说,这可能是一个限制。例如,单词嵌入可以具有与 CNN 非常不同的最佳维度,调整这两者可能会导致信息的丢失。
- 我们仅限于考虑成对的相互作用。研究人员提出了像三线性池这样的一般化方法,其中我们考虑了三个特征。但这使得模型更难训练,容易过度拟合。
履行
在 FashionMNIST 数据集上用于图像分类的双线性池的简单实现可以在这个 Jupyter 笔记本中找到。请注意,双线性池并不真正适合像 FashionMNIST 这样的小型数据集。该实现作为一个示例,可以根据项目的需要进行调整和改进。
参考
[1]宗-林玉,阿鲁尼·罗伊·乔杜里,苏博兰苏·马吉:
用于细粒度视觉识别的双线性卷积神经网络。IEEE Trans。肛门模式。马赫。智能。40(6),可用此处
[2]舒孔,查尔斯·c·福尔克斯。用于细粒度分类的低秩双线性池。CVPR 2017。可用此处,项目页面此处
[3]周瑜,,,陶大成。用于视觉问答的多模态分解双线性池联合注意学习。ICCV 2017,此处可用
台球与弗雷德的常客和拜耳的贝叶斯[拜耳赢:)
原文:https://towardsdatascience.com/billiards-with-fred-the-frequentist-and-bayer-the-bayesian-bayer-wins-7bc95b24a7ef?source=collection_archive---------14-----------------------
我在这里讨论贝叶斯自己的一个实验,它强调了贝叶斯方法的美丽、优雅和正确性,即使频率主义方法给出了不正确的结果。
在 1763 年死后发表的论文[1]中,Bayes 展示了一个例子,其中 Frequentist 点估计给出了不正确的结果(与实验不匹配),而 Bayes 分析给出了与实验匹配的优雅解决方案。本文中的问题确切问题陈述是文献[1][2][3]中的陈述的推广。
在这里,我讨论了这个例子,并用 colab 笔记本[4]链接了推导和蒙特卡罗模拟。
设置
不可否认,这个设置有点做作,但我们可以忽略它。让我们在宽度为 1 的桌子上打一场台球。卡罗尔进来,随机地打了一个台球,当它落在离一面墙 p 的距离后,她把它藏在了窗帘后面。然后爱丽丝和鲍勃,不知道球的位置,射击他们自己的球,如果一个球落在卡罗尔的球的左边,爱丽丝赢了这一轮(所以概率是 p),如果它在卡罗尔的球的右边结束,那么鲍勃赢了这一轮(所以概率是(1-p))。先得 6 分的人赢得比赛。

一些见不得人的角色正在观看这场游戏,当鲍勃在 K 杆时赢得了 nB 回合时,他们叫来了常客弗雷德来赌这场游戏。他们请常客弗雷德预测鲍勃赢得比赛的概率。在给了弗雷德频繁主义者多次尝试解决问题,他悲惨地失败了,这些人物听到贝叶斯统计,并邀请你,拜尔贝叶斯显示你的把戏包里有什么。
常客弗雷德如何尝试解决方案
常客 Fred 首先通过查看 Alice 获胜的分数来估计 p 的点数

注意 nA+nB=K。
在这之后,Frequentist 简单地计算 Bob 在 11-K 剩余游戏中赢得至少 6-nB 的概率(游戏数量永远不能超过 11。说服你自己这个论点。)

常客弗雷德对鲍勃获胜概率的回答
我们以后会看到他错得有多离谱。
拜耳贝叶斯如何拯救世界
在这一点上,你被叫来尝试你的贝叶斯手在这个问题上。你采取了一种非常不同的方法。你知道这一点(如果你不知道这一点,那么你应该考虑一下和/或阅读一下条件概率)

这里发生的是,我们对 p 的所有可能值进行积分,因为我们不知道它是什么。模型中的这种参数称为讨厌参数。
现在既然 Carol 均匀采样 P P(P)= 1。出于可读性的考虑,我在这里不做数学计算,推导过程可以在我下面引用的 github 笔记本中找到。
最后的表述是

鲍勃获胜概率的贝叶斯答案
实验
哪个答案是正确的?这是一个非常容易模拟的问题,已经在下面的笔记本中完成了。让我展示几个例子。
首先注意,如果 K=0,那么 nB =0,虽然直觉上答案是 0.5,Bob 会赢,但常客 Fred 说这是未定义的!
在 K=1,2,3,4,5 的另一个极端,如果 K=nb,Frequentist 的点估计给出 p=0 和 PF(B)=1,所以他肯定 Bob 会赢,但稍加思考就会发现这是不正确的。
甚至连常客弗雷德也认为两个答案都不正确,但他不知道该怎么办,而是继续坚持认为其他答案是正确的。
然而,弗雷德不仅在上面两个例子中是错误的,他还经常错误(双关语!).下面比较不同的 K 和 nb,贝叶斯答案如何总是匹配 MC(人们看到的小的不匹配来自 MC 采样中的有限大小效应),并且频率主义者的答案总是错误的,除了当 nb=K/2 时。

K 和 nb 的其他值的结果可以在上面引用的笔记本[4]中找到。
帮助常客弗雷德认识他的错误[高级]
那么,常客弗雷德做错了什么?为什么他经常得到错误的答案?让我们再来看看 Bayer the Bayesian 是如何处理讨厌的参数 P 的,它可以是从 P(p)中提取的任何值(在这种情况下恰好是均匀的),然后对结果进行积分。另一方面,frequent ist Fred 取 p=(K-nB)/K,这是 P(D|p)的最大似然估计量,并将其插入 P(B|p,D)。现在,这将在可能性非常尖锐的情况下工作(这就是我们物理学家所说的狄拉克δ函数)。然而,事实证明情况并非如此。同行的物理学家将会看到这里与路径积分有很大的相似之处,在量子力学中,对所有路径求和,但在经典极限中,只有一条路径对路径积分有贡献。用这个类比,频率主义者弗雷德在一个问题中使用了经典极限,他应该做量子力学。
更快的方法
在经历了所有的困难之后,让我指出,有一种更简单的方法可以实现这一点,那就是我们所做的是对二项数据的后验预测分布求和,即 Bob 的相关获胜次数的贝塔二项分布。

鲍勃以文明的方式获胜的概率的贝叶斯答案。
结论
贝叶斯方法更直观,因此更难出错。虽然常客们显然也能得到正确的答案,但要做到这一点却困难得多。虽然关于贝叶斯和频率主义者的哲学辩论将持续很长时间,但在实践层面上,贝叶斯是你最好的选择。
参考资料:
- T.贝叶斯。一篇解决机会主义中一个问题的论文。伦敦皇家学会哲学汇刊 53(0):370–418,1763
- 艾迪先生。什么是贝叶斯统计?。自然生物技术 22:1177–1178,2004
- 关于使用 Python 的贝叶斯统计的非常好的介绍。我自己的例子是对这个例子的概括,最初的引用来自贝叶斯https://arxiv.org/pdf/1411.5018.pdf
- 我的笔记本https://github . com/borundev/DNN _ 讲座/blob/master/Bayesian _ pool . ipynb
二值化神经网络综述
原文:https://towardsdatascience.com/binarized-neural-networks-an-overview-d065dc3c94ca?source=collection_archive---------17-----------------------
二值化神经网络是一种有趣的神经网络变体,可以节省内存、时间和能量。了解它们是如何工作的。

亚历山大·辛恩在 Unsplash 上的照片
使用神经网络的一个障碍是运行网络所需的功率、内存和时间。这对于没有强大 CPU 或大内存的移动和物联网设备来说是个问题。二值化神经网络是解决这一问题的方法。通过使用二进制值而不是浮点值,可以更快地计算网络,并且使用更少的存储器和功率。
力学:
从概念上讲,二进制神经网络(BNN)类似于常规前馈神经网络(NN)。一个区别是 BNN 中的权重和激活被限制为只有两个值:1 和-1,因此得名“二进制化”。因此,只使用了一个激活函数:符号函数。我们不能使用像 sigmoid 或 relu 这样的常规激活函数,因为它们有连续的输出,正如我们刚才所说的,激活只能是 1 和-1。

来源:整个神经网络的布尔掩蔽
当我们使用梯度下降来训练网络时,这些限制会导致一些问题。首先,符号函数的梯度为 0。这是不好的,因为它使所有权重和激活的梯度也为 0,这意味着实际上不会发生任何训练。我们可以通过在进行反向传播时忽略符号激活函数来解决这个问题。然而,我们有另一个问题,即梯度更新将导致权重不再是 1 或-1。我们通过保留一组实值权重并对这些权重进行梯度更新来解决这个问题。然后,网络权重是这些实值权重的二进制化。
因此,我们的最终算法是:
- 前向传递:我们有实值权重 W_r 和输入向量 x,首先,我们对所有权重应用 sign 函数,得到 W_b = sign(W_r)。然后我们像往常一样用 W_b 和符号激活函数计算神经网络的输出。
- 反向传递:我们像往常一样进行反向传播,并计算权重 W_b 的梯度,只是我们忽略了符号激活函数。我们通过减去这些梯度来更新权重 W_r(记住,W_b 来自 W_r,所以不直接更新 W_b!).

来源:[ 2 ]
性能:
我们已经看到了二进制神经网络是如何工作的。现在让我们比较一下普通神经网络和 BNN 之间的理论性能差异。普通的神经网络使用 32 位浮点数。如果我们有两个 32 位寄存器,我们可以用一条计算机指令在两个 32 位数之间执行一次乘法。二进制网络使用 1 位数(我们将+1 编码为 1,将-1 编码为 0)。要将两个 1 位数字与我们的表示相乘,我们可以使用 XNOR 指令。

来源:[ 2
我们能做的是将 32 个 1 位数字放入我们的两个 32 位寄存器中的每一个,然后运行一个 XNOR 指令来同时相乘所有的数字。其结果是,我们可以用一条指令做 32 次 1 位乘法,而用一条指令只能做 1 次 32 位乘法。因此,与普通神经网络相比,BNN 理论上有 32 倍的加速比。
实际上,32x 这个数字很难达到。CPU/GPU 的编程方式会影响指令调度,指令本身并不总是需要相同数量的时钟周期来执行。此外,现代的 CPU/GPU 并没有针对运行按位代码进行优化,因此必须注意代码的编写方式。最后,虽然乘法是神经网络中总计算的很大一部分,但也有我们没有考虑的累加/求和。尽管如此,[ 1 ]报告称,在比较优化的 BNN 和未优化的正常神经网络时,加速比提高了 23 倍,这表明明显的加速是完全可以实现的。
因为我们使用的是 1 位数字而不是 32 位数字,我们还希望使用大约 32 倍的内存。当我们使用的内存减少 32 倍时,我们的内存访问也减少了 32 倍。这也将减少大约 32 倍的功耗。我找不到测试这个假设的实验数据,但这个结论对我来说似乎是合理的。
最后,需要注意的是,所有这些 BNN 优势仅适用于运行时,不适用于训练时。这是因为,正如我们前面提到的,我们保留了一组实值权重来进行训练。这意味着梯度是一个 32 位浮点数,并不受制于我们所描述的 1 位优势。因此,BNN 模型不应该在内存/功率受限的设备上训练,但是它们可以在这些设备上运行。
精度:
当然,如果网络由于测试集上的不良准确性而不可用,那么无论速度/内存/功率提高多少都没有关系。二值化激活和权重比常规神经网络的表达能力差,所以我们预计准确性会更差。问题是会恶化到什么程度。我找不到任何回答这个问题的理论论文,所以现在我认为像下面这样的经验数据是我们最好的。我们在这里描述的 BNN 实现是第一部分,常规 NN 变体是最后一部分。

来源:[ 1
我们看到,误差肯定会增加,特别是在 CIFAR-10 数据集上(10.15%对 7.62%)。然而,考虑到 BNNs 如前所述的所有性能优势,这大约 3%的差异并不是世界末日。对于每个精度点都至关重要的任务,例如医疗 x 射线筛查,我们不想使用 BNNs。但是在精度不那么重要或者性能更重要的情况下,bnn 是一个可行的选择。
在这篇文章中,我们已经简要了解了 BNN 的机制。我们还看到了 BNNs 如何显著提高速度、内存使用和功耗,代价是精度稍低。要更深入地了解 BNNs,请看下面的参考资料。
[1] M. Courbariaux 和 I. Hubara,二值化神经网络:训练深度神经网络,权重和激活限制为+1 或-1 (2016)
[2] T. Simons 和 D. Lee,二值化神经网络综述 (2019)
基于自动机器学习的二元分类
原文:https://towardsdatascience.com/binary-classification-with-automated-machine-learning-1a36e78ba50f?source=collection_archive---------26-----------------------
使用开源的 MLJAR auto-ML 更快地构建精确的模型
自动化机器学习工具的兴起让开发者能够更快地建立准确的机器学习模型。这些工具通过执行特征工程、算法选择、调整以及记录模型来减少工程师的工作。一个这样的库是开源的 MLJAR 包。在本文中,让我们看看如何使用这个包进行二进制分类。
入门指南
MLJAR 包可以用来建立一个完整的机器学习管道,具有特征工程和超参数调整功能。该软件包还支持流行的机器学习算法,包括:
- 神经网络
- XGBoost
- Catboost
- LightGBM 等等。
MLJAR 根据选择的算法建立几个模型,并通过集合或堆叠模型获得最终预测。一旦训练完成,该软件包还提供可视化,可用于解释模型。其中包括功能重要性以及显示各种型号性能的排行榜。
为了开始使用这个包,你需要通过pip安装它。
pip install mljar-supervised
获取数据
对于这个示例,让我们使用 Scikit-learn 来创建一个分类数据集。这可以使用数据集模块中的make_classification函数来完成。
下一步是将这个数据集分成训练集和测试集。
使用 MLJAR 进行二元分类
令人惊讶的是,使用 MLJAR 进行二进制分类只需要几行代码。MLJAR 在幕后负责所有的机器学习魔法。这里的第一步是导入AutoML类。
下一步是创建该类的一个实例,同时指定您希望用于解决该问题的算法。可以设置的其他参数包括:
- 模式 —该套件配有四种内置模式。
Explain模式是解释和理解数据的理想模式。它产生了特征重要性的可视化以及树的可视化。在为生产建立 ML 模型时使用Perform。Compete是为了建立用于机器学习竞赛的模型。Optuna模式用于搜索高度调谐的 ML 模型。 - 算法 —指定您想要使用的算法。它们通常作为列表传入。
- 结果路径— 存储结果的路径
- total_time_limit —训练模型的总时间(秒)
- train_ensemble — 指示是否在训练过程结束时创建一个集合
- stack_models —决定是否创建模型堆栈
- eval_metric —将被优化的度量。如果
auto``logloss用于分类问题,而rmse用于回归问题
下一步是使算法适合训练和测试集。

MLJAR 解释
模型拟合后,您可以使用report功能获得各种模型解释。例如,您可以看到符合此二元分类问题的模型的排行榜。

当您单击单个模型时,您还会看到几个可视化效果和模型摘要。

例如,你会看到混淆矩阵。

MLJAR 还会默认显示训练过程的学习曲线。为验证集和训练集绘制学习曲线。垂直线显示最佳迭代次数,用于进行预测。

你也可以从报告中发现特性的重要性。这是排列重要性的例子。使用 Sckit-learn 的排列重要性进行计算。

MLJAR 还绘制了 SHAP 重要性。

它还显示了 SHAP 重要依赖图。

姆加魔法
当用 MLJAR 训练一个模型时,在幕后会发生一些事情。机器学习模型的训练分几个步骤进行。这些步骤需要:
- 训练简单的算法,如决策树,以获得快速的洞察力。
- 使用默认超参数训练模型。这里每个算法都有一个模型。
- 在给定的超参数上执行随机搜索。
- 从原始数据中构建新的特征,使模型具有更强的预测能力。MLJAR 将这些特性称为黄金特性。这些特性可以在结果路径中的一个名为
golden_features.json的文件中找到。这些特征被添加到数据中,并且使用 Xgboost、CatBoost 和 LightGBM 算法来训练新的模型。 - 为每个算法获得的最佳模型被选择,并且其超参数被用于基于一组选择的特征来训练新的模型。
- 模型被进一步调整,然后被集合。
为什么要使用 MLJAR
人们为什么会考虑在机器学习工作流中使用 MLJAR 有几个原因:
- 它执行特征预处理,例如缺失值的插补和类别的转换
- 执行高级特征工程
- 能够转换时间和日期
- 执行超参数调谐
- 提供广泛的模型解释和可视化
- 为您运行的每个实验创建降价报告
最后的想法
在本文中,您已经看到了如何构建二进制分类模型 MLJAR auto-ML。您已经看到这个过程只需要几个步骤。您还看到了 MLJAR auto-ML 使用多种算法为分类问题构建多种模型。下一步是在您自己的二元分类数据集上使用该包。
https://github.com/mljar/mljar-supervised/
二元分类:通过非穷举网格搜索和交叉验证的 XGBoost 超参数调整场景
原文:https://towardsdatascience.com/binary-classification-xgboost-hyperparameter-tuning-scenarios-by-non-exhaustive-grid-search-and-c261f4ce098d?source=collection_archive---------0-----------------------
平衡模型性能和计算资源限制的实际例子——代码和可视化

由d . kah在 Unsplash 上拍摄
简介
XGBoost 或极端梯度提升是当今使用最广泛的机器学习算法之一。众所周知,它在赢得卡格尔比赛方面效率很高。许多文章称赞它,并指出它优于替代算法的优势,因此它是练习机器学习的必备技能。
虽然 XGBoost 相对较快,但在标准笔记本电脑上运行脚本仍然具有挑战性:当拟合机器学习模型时,它通常会附带超参数调整和交叉验证(尽管不是必需的)。如果考虑到超参数的所有组合,调整可能会指数地增加计算资源需求。因此,穷尽搜索最佳参数可能不是一个可行的选择。
本文介绍了超参数调优的替代方法,旨在找到模型性能和计算资源限制之间的良好平衡。我自豪地拥有一个英特尔酷睿 i5–8250 u CPU,根据 CPUBenchmark 的数据,它的分数低于提交的中位数。对于有这些限制的人来说,我的代码可能会很有趣。
技术术语概述
尽管我通过分享该过程的代码从实用的角度出发,但我想对所使用的术语和参数名称做一个概述。如果您熟悉它们,请跳过这一点,进入数据集描述和代码结果。
自相关
决策树学习目标变量可以取一组离散值的树模型称为 分类树*;在这些树结构中,树叶代表类别标签,树枝代表导致这些类别标签的特征的合取*
梯度推进
梯度推进是一种用于回归、分类和其他任务的机器学习技术,它以弱预测模型的集合的形式产生预测模型,通常是决策树。当决策树是弱学习器时,产生的算法称为梯度提升树,它通常优于随机森林。它像其他 boosting 方法一样以分阶段的方式构建模型,并通过允许优化任意可微分损失函数来推广它们【3】注:XGBoost 通过其正则化机制来防止过度拟合,从而区别于其他梯度 boosting 技术。
交叉验证
" 交叉验证通过“将数据样本划分为互补的子集,对一个子集(称为训练集)执行分析,并对另一个子集(称为验证集或测试集)的分析进行验证”来组合(平均)预测中的适合性度量,以获得更准确的模型预测性能估计值……使用不同的分区执行多轮交叉验证,并在各轮中组合(例如平均)验证结果,以给出模型预测性能的估计值
网格搜索
网格搜索是一个过程,它通过手动指定的目标算法超参数空间的子集进行彻底搜索…并基于生成的超参数集评估成本函数【5】
随机搜索
" 随机搜索…使用概率分布为每个超参数独立选择一个值…并基于生成的超参数集评估成本函数【5】
贝叶斯搜索
Eta (学习率,[0,1],默认值= 0.3)
步长收缩用于更新,以防止过拟合。【7】
“类比于 GBM 中的学习率”[8]
Gamma ([0,∞],默认值=0 ):
" 在树的一个叶节点上做进一步划分所需的最小损失减少量。【7】
仅当结果分裂给出损失函数的正减少时,节点才被分裂【8】
最大深度 ([0,∞],默认= 6):
一棵树的最大深度。增加这个值会使模型更加复杂,并且更有可能过度拟合
λ(未提供界限,缺省值= 1):
关于权重的 L2 正则化项。【7】
……类似于岭回归【8】
Alpha (未提供界限,缺省值=0):
" L1 正则化项关于权重。【7】
……类似于套索回归【8】
树方法(auto、exact、approx、hist、gpu_hist、默认= auto ):
、exact——精确贪婪算法。列举所有分割候选
approx — 近似贪婪算法使用分位数草图
hist — 更快的直方图优化近似贪婪算法
gpu_hist — GPU 实现 hist 算法【7】
增长策略 ([ depthwise,lossguide,默认= depthwise ):
" 控制新节点添加到树中的方式。
depthwise — 在最接近根的节点处分割。
lossguide — 在损耗变化最大的节点处分割【7】
准确性
"…正确预测的观测值与总观测值的比率 " [9]
精度
" 精度是正确预测的正观测值与总预测正观测值的比率 " [9]
召回
召回是正确预测的正面观察与实际类中所有观察的比率【9】
F1 评分
F1 评分是准确率和召回率的加权平均值。因此,这个分数将假阳性和假阴性都考虑在内…如果假阳性和假阴性具有相似的成本,准确性效果最好。如果假阳性和假阴性的成本相差很大,那么最好同时考虑精确度和召回率[9]
混淆矩阵
"…一个表格,通常用于描述一个分类模型对一组真实值已知的测试数据的性能 " [9]
ROC AUC
ROC曲线(接收器操作特性曲线)是显示分类模型在所有分类阈值的性能的图表。该曲线绘制了两个参数:真阳性率和假阳性率…AUC代表“ROC 曲线下面积”也就是说,AUC 测量从(0,0)到(1,1)的整个 ROC 曲线下的整个二维面积(考虑积分)…AUC 提供了对所有可能的分类阈值的综合性能测量。解释 AUC 的一种方法是将模型对随机正面例子的排序高于随机负面例子的概率*【10】*
问题陈述阐述
机器学习模型带有默认参数:如果你没有为可选参数分配特定的值或字符串,算法会通过预设值或字符串自动完成。然而,最佳参数可能因数据集而异,因此默认参数通常不是最佳的。需要通过网格搜索找到最优参数,其中网格代表每个参数的实验值(n-维空间)。
如上所述,计算能力需求的指数增长问题通过应用蛮力方法和穷尽搜索每个组合而出现。考虑到损失函数,穷举搜索产生全局最小值,因此每次尝试都是有吸引力的。存在替代的、更快的方法——应用的方法在上面列出——以产生对应于局部最小值的一组参数值的概率为代价。

全局和局部损失函数最小值的简化表示(来源:作者)
供考虑的备选方案:
- 逐步搜索又称坐标下降——一次优化一个参数。可能导致局部最小值。在几个超参数的情况下,可能存在许多局部最小值。它取决于超参数的阶数,达到哪个最小值。也可能有这样的情况,当两个或多个超参数的组合修改会产生更好的分数,但修改其中一个不会[11]
- 随机搜索-从搜索空间中随机选择超参数值。搜索空间中的随机点:可能不是最小值,但可能是全局最小值
- 贝叶斯搜索——当函数的数学形式未知或计算成本很高时,这是一种极其强大的技术。背后的主要思想是根据数据计算目标函数的后验分布(使用著名的贝叶斯定理),然后选择好的点来尝试这个分布【12】
我的研究目标是提供一种方法,通过检查模型得分和运行时间来比较上述方法,并在资源有限的情况下选择最合适的方法。值得注意的是,每个数据集可能需要使用有限的子样本进行单独调查,然后在考虑最佳结果时,将最合适的方法应用于整个数据集。
数据集
选择用于演示的数据是 CERN 希格斯玻色子挑战的子样本,并已在 Kaggle 上发表为“希格斯玻色子和背景过程”[13]。
CERN ATLAS 团队已经发表了原始出版物,著名的希格斯玻色子已经通过对这些数据的分析得到了证实。
简而言之,该数据包含 ATLAS 测量的 21 个特征(运动学特性)、从低级别特征导出的 7 个(高级别)特征和一个表明该过程是希格斯过程还是背景噪声的结果的二进制特征。
代码和结果
既然一张图抵得上千言万语,请让我来评估一下下面的流程图中的代码,随便用 Paint 做的(开个玩笑,用 Sketchviz 做的)。请在我的 Jovian 简介这里看完整的代码。

流程图(作者用 Sketchviz 制作)
注意:在每种方法的情况下,存储墙壁时间,并且测试用例的数量都相等,以便进行有意义的比较。
导入了几个评估函数以及标准库:
从 CSV 格式加载数据,检查列车数据。id 被丢弃,因为它作为每个过程的唯一值对分类没有贡献:
检查测试数据帧发现,一些列包含不适当的字符,因为它们被格式化为对象。原来一些缺失的值用“?”来表示,因此是对象格式。问号被替换为 0,作为代表缺失值的标准值:
作为一个标准的过程,自相关和偏相关已被评估。
因为自相关不存在于任何特征中,所以可以肯定地说我们不是在处理时间序列数据。因此,随机化数据帧不会造成差异,但是,出于比较目的(与已公布的子样本分析结果),它在训练/测试分割期间应用,除了在分割(分层)后特别注意保持类别频率比率相同。
在执行网格搜索算法之前,必须拟合一个基准模型。通过调用fit()方法,默认参数被获取并存储以备后用。由于GridSearchCV在列表中接受输入,单个参数值也必须被包装。通过在GridSearchCV实例上调用fit(),执行交叉验证,提取结果,计算分数并存储在字典中。
重要提示:除了搜索最佳网格搜索算法之外,可能还会设置一些速度参数。此类参数为 *tree_method* ,设置为 *hist* ,将连续特征组织在桶(箱)中,读取列车数据变得明显更快【14】。请阅读参考资料,了解 XGBoost 情况下的更多技巧。
*迭代整个参数网格需要很多时间,因此将详细度设置为 1 有助于监控该过程。但是,墙壁时间不等于打印的安装时间,因此循环时间也被跟踪和打印。*
坐标下降是一种特殊情况,在这种情况下,后续迭代的性能被跟踪,并且可以被可视化以选择最佳参数设置。情节如下:
- 所选超参数网格每次试验的评估分数,以及最佳超参数值的混淆矩阵
- 后续迭代的最佳参数值的评估分数的演变
重要提示:由于交叉验证是在训练数据上进行的,而手动 AUC 分数是使用测试数据计算的,因此测试分数不一定在每次后续迭代中增加。因此,最终的模型参数是手动选取的。
随机搜索和贝叶斯搜索以相似的方式执行,在相同的结果字典中捕获结果。
最后,比较 AUC 分数和搜索时间。所有的方法都做了同样多的工作,最终,贝叶斯搜索胜出。随机和贝叶斯搜索的执行时间都比 CD 短。
重要提示:执行多次搜索,例如嵌入循环中,执行时间和分数可能会有所不同。测试分数差异的显著性超出了我的文章范围。然而,我重新运行笔记本几次,贝叶斯搜索总是获胜,尽管执行时间也有所不同,并在 45 分钟左右达到峰值。
总结
有趣的是,对于所有三种方法,一些超参数值是相似的还是不同的。例如,对于 CD 和贝叶斯搜索,最大树深度被设置在顶部网格值,但是 lambda 参数对于每一个都是完全不同的。在每种情况下,学习率都保持在低水平。当然,在可能的组合中已经进行了 68 次试验(631 800),但是模型已经得到了改进,同时在预计的 256 478 分钟的强力网格搜索中节省了至少 256 448 分钟。
可以尝试扩展作业的数量,使其与总搜索空间更具可比性,并可能进一步增加 AUC 分数。
值得注意的是,原始论文分别使用超参数调节的 NN(浅层神经网络)和 d NN(深层神经网络)报道了 0.841 和 0.883 的 AUC 分数。表现最差的 CD 算法在看不见的数据上得到了 0.8033/0.7241(AUC/准确度)的分数,而数据集的发布者使用决策树分类器获得了 0.6831 的准确度分数,使用支持向量机(SVM)获得了 0.6429 的准确度分数。考虑到所使用的硬件,这将 XGBoost 算法和结果放在上下文中。
参考文献
二元神经网络——低成本神经网络的未来?
原文:https://towardsdatascience.com/binary-neural-networks-future-of-low-cost-neural-networks-bcc926888f3f?source=collection_archive---------15-----------------------
二元神经网络能代替全精度网络吗?

亚历山大·辛恩在 Unsplash 上的照片
E 每年都有更深入的模型被开发出来执行各种任务,比如对象检测、图像分割等。它总是能打败最先进的模型。但是,人们越来越关注让模型更轻、更高效,以便它们可以在边缘设备和移动设备上运行。这对于弥合机器学习的研究价值和生产价值之间的差距极其重要。
一种减少深度神经网络的存储和计算成本的方法是二进制神经网络的概念。二进制神经网络的概念非常简单,其中权重和激活张量的每个值使用+1 和-1 来表示,使得它们可以以 1 位而不是全精度来存储(-1 在 1 位整数中表示为 0)。浮点值到二进制值的转换使用如下所示的符号函数—

符号阈值函数
现在,使用上述阈值函数的一个主要问题是函数的梯度趋于零。一个解决方案是使用一个直通估计器。直通估计器是这样一种估计器,它在反向传播期间完全按照原样传递梯度,而没有任何变化。这简化了二进制神经网络中阈值函数的反向传播机制,并且显示出非常好的效果。

直通估计器解释(图片由作者提供)
在梯度累积阶段,使用二进制权重和激活来累积每一层的梯度。但是权重更新是在实值原始权重上进行的。为什么会这样呢?我举个例子解释一下。
- 我们有一个神经网络中的节点(原始参数),值为 0.05。
- 在将该值通过阈值函数时,我们获得值 1 ( **二进制参数**)。
- 让我们假设在二进制参数处累积的梯度为 3。我们使用直通估计器的概念将其传递给原始参数。
- 现在,一旦梯度累积,我们就可以更新值。
如果我们使用二进制值来获得新的参数值,那么参数的新值将是 1–0.1 * 3(其中 0.1 是学习率),即 0.7 。
如果我们使用原始参数值获得新参数,那么新值将是 0.05–0.1 * 3,即 -0.25 。 - 这就是可以注意到差异的地方。当我们执行下一次迭代时,我们将再次通过二进制阈值函数传递新的参数值,这将给出不同的结果。如果我们继续使用参数的二进制值,我们可能永远无法改变该位,因为损失总是从 1 或-1 开始计算。
当参数值被更新时,这些值被裁剪为介于-1 和 1 之间。主要原因是这些值只是增加/减少,否则对网络没有任何影响。需要注意的一点是,最后一个激活层中的值没有被二进制化,而是直接用于分类/回归。这些是二进制神经网络的基本概念。
可以添加到权重和激活层二进制化的另一个改进是使用比例因子来表示权重和激活。这里,比例因子只是权重向量中所有值的平均值的绝对值。如果我们有一个值为[[0.2,0.2],[-0.6,-0.6]]的 2*2 矩阵,那么比例因子α将为 0.2,二进制矩阵表示为[[1,1],[-1,-1]]。

重量的α(比例因子)计算
因此,一旦权重和激活以二进制形式表示,以及它们各自的比例因子,它们就可以使用下面的等式来表示。这里,I 和 W 分别代表激活层和权重层,而激活和权重的比例因子分别用κ和α表示。

重量和激活层的 XNOR 操作
现在,作为卷积运算基础的乘累加( MAC )函数是一种非常昂贵的运算。这现在可以用一个 XNOR+popcount 操作来代替。受益?几乎每一个 CPU 都固有地实现了按位操作,并且实现起来明显更快更便宜。popcount 操作只是检查设置的位。下面的例子说明了 MAC 操作可以被 XNOR+popcount 操作所取代。

XNOR + POPCOUNT 运算取代 MAC 运算,其中 n 是原始位数(图片由作者提供)
二进制神经网络的主要缺点是它们不能达到与全精度深层网络一样好的精度。但这种情况一直在慢慢改变,每年(更像是每个月都有论文发表),随着差距的缩小,都有很多进步。由于人们越来越关注在计算资源有限的设备上实现机器学习模型,未来几年该领域的研究工作将会增加。
参考文献
[1]对 PyTorch 实现的直通估计器的直观解释。(2020 年 9 月 19 日)。检索于 2021 年 1 月 28 日,来自https://www . hassanaskary . com/python/py torch/deep % 20 learning/2020/09/19/intuitive-explain-of-straight-through-estimators . html
[2] Courbariaux,Matthieu 等人,“二值化神经网络:训练深度神经网络,其权重和激活被限制为+ 1 或-1。” arXiv 预印本 arXiv:1602.02830 (2016)。
[3] Rastegari,Mohammad 等,“Xnor-net:使用二进制卷积神经网络的图像网络分类”欧洲计算机视觉会议。施普林格,查姆,2016。
[4] Sush16。(2017 年 10 月 02 日)。理解二元神经网络。检索于 2021 年 1 月 28 日,来自https://sush science . WordPress . com/2017/10/01/understanding-binary-neural-networks/
浮点数的二进制表示形式
原文:https://towardsdatascience.com/binary-representation-of-the-floating-point-numbers-77d7364723f1?source=collection_archive---------1-----------------------

照片由米卡鲍梅斯特
你有没有想过计算机如何在内存中存储浮点数,比如3.1415 (𝝿)或9.109 × 10⁻³¹(以千克为单位的电子质量),而内存是由有限数量的 1 和 0(也就是比特)组成的?
对于整数来说似乎很简单(例如17)。假设我们有 16 位(2 字节)来存储这个数字。在 16 位中,我们可以存储范围为[0, 65535]的整数:
(0000000000000000)₂ = (0)₁₀(0000000000010001)₂ =
(1 × 2⁴) +
(0 × 2³) +
(0 × 2²) +
(0 × 2¹) +
(1 × 2⁰) = (17)₁₀(1111111111111111)₂ =
(1 × 2¹⁵) +
(1 × 2¹⁴) +
(1 × 2¹³) +
(1 × 2¹²) +
(1 × 2¹¹) +
(1 × 2¹⁰) +
(1 × 2⁹) +
(1 × 2⁸) +
(1 × 2⁷) +
(1 × 2⁶) +
(1 × 2⁵) +
(1 × 2⁴) +
(1 × 2³) +
(1 × 2²) +
(1 × 2¹) +
(1 × 2⁰) = (65535)₁₀
如果我们需要一个有符号的整数,我们可以使用二进制补码并将[0, 65535]的范围移向负数。在这种情况下,我们的 16 位将代表[-32768, +32767]范围内的数字。
您可能已经注意到,这种方法不允许您表示像-27.15625这样的数字(小数点后的数字将被忽略)。
虽然我们不是第一个注意到这个问题的人。大约 36 年前,一些聪明人通过引入浮点运算的 IEEE 754 标准克服了这个限制。
IEEE 754 标准描述了使用这些 16 位(或 32 位或 64 位)来存储更大范围的数字的方式(框架),包括小浮点数(小于 1 且更接近 0)。
为了理解标准背后的思想,我们可以回忆一下科学符号——一种表示过大或过小的数字(通常会产生一长串数字)的方式,以便于用十进制形式书写。

插图由 trekhleb 绘制
正如您在图中看到的,数字表示可能被分成三部分:
- 符号
- 分数(也称为有效数)—数字的有价值的位数(含义、有效载荷)
- 指数-控制分数中小数点移动的距离和方向
我们可以省略基础部分,只要同意它等于什么。在我们的例子中,我们将使用2作为基础。
我们可以共享这些位,同时存储符号、指数和分数,而不是使用所有 16 位(或 32 位或 64 位)来存储数字的分数。根据我们要用来存储数字的位数,我们最终得到以下分割:

使用这种方法,分数的位数已经减少(即,对于 16 位数,它从 16 位减少到 10 位)。这意味着分数现在可能取更窄的值范围(失去一些精度)。然而,由于我们也有一个指数部分,它实际上会增加最终的数字范围,也允许我们描述 0 和 1 之间的数字(如果指数是负的)。
例如,带符号的 32 位整数变量的最大值为 1 = 2,147,483,647,而 IEEE 754 32 位二进制浮点变量的最大值约为 3.4028235 × 1⁰ ⁸.
为了使负指数成为可能,IEEE 754 标准使用了偏置指数。想法很简单——从指数值中减去偏差,使其为负。例如,如果指数有 5 位,它可能从范围[0, 31]中取值(这里所有值都是正的)。但是如果我们从中减去15的值,范围就是[-15, 16]。数字15称为偏差,通过以下公式计算:
exponent_bias = 2 ^ (k−1) − 1k - number of exponent bits
我试图在下图中描述浮点数从二进制格式转换回十进制格式的逻辑。希望它能让你更好地理解 IEEE 754 标准是如何工作的。为了简单起见,这里使用 16 位数字,但是同样的方法也适用于 32 位和 64 位数字。

插图由 trekhleb 绘制
检查此图 的 交互版本,通过设置位的开和关来进行试验,并观察它将如何影响最终结果
为简单起见,上述示例中省略了几个极限情况(即-0、-∞、+∞和NaN(非数字)值)
以下是不同浮点格式支持的数字范围:

代码示例
在 javascript 算法库中,我添加了一个二进制到十进制转换器的源代码,它在上面的交互示例中使用过。
下面是一个例子,说明如何在 JavaScript 中获得浮点数的二进制表示。JavaScript 是一种相当高级的语言,这个例子可能太冗长,不像低级语言那样简单,但仍然可以在浏览器中直接进行实验:
const singlePrecisionBytesLength = 4; // 32 bits
const doublePrecisionBytesLength = 8; // 64 bits
const bitsInByte = 8;function floatAsBinaryString(floatNumber, byteLength) {
let numberAsBinaryString = ''; const arrayBuffer = new ArrayBuffer(byteLength);
const dataView = new DataView(arrayBuffer); const byteOffset = 0;
const littleEndian = false; if (byteLength === singlePrecisionBytesLength) {
dataView.setFloat32(byteOffset, floatNumber, littleEndian);
} else {
dataView.setFloat64(byteOffset, floatNumber, littleEndian);
} for (let byteIndex = 0; byteIndex < byteLength; byteIndex += 1) {
let bits = dataView.getUint8(byteIndex).toString(2);
if (bits.length < bitsInByte) {
bits = new Array(bitsInByte - bits.length).fill('0').join('') + bits;
}
numberAsBinaryString += bits;
} return numberAsBinaryString;
}function floatAs64BinaryString(floatNumber) {
return floatAsBinaryString(floatNumber, doublePrecisionBytesLength);
}function floatAs32BinaryString(floatNumber) {
return floatAsBinaryString(floatNumber, singlePrecisionBytesLength);
}// Usage example
floatAs32BinaryString(1.875); // -> "00111111111100000000000000000000"
参考
您可能还想查阅以下资源,以更深入地了解浮点数的二进制表示:
- 这里是你需要知道的关于 JavaScript 的数字类型
- 浮球暴露
- IEEE754 可视化
Python 中“臭名昭著”的算法:二分搜索法
原文:https://towardsdatascience.com/binary-search-in-python-the-programming-algorithm-8b8fa039eaa?source=collection_archive---------20-----------------------
数据结构和算法
为什么它的性能优于线性迭代?

凯西·马蒂亚斯在 Unsplash 拍摄的照片
介绍
让我们从两个问题开始今天的话题。
你学习算法的第一印象是什么?
到底什么是算法?
如今,有几十个像“比特”、“智能”、“人工智能”、“学习”、“监督学习”和“算法”这样的热门词汇在架子顶上。
但是很少有人理解这些词的真正含义,更不用说它们是如何工作的了。
“这是什么?
它是做什么的?"
你问过了。
对我来说,算法是我们希望计算机如何处理信息的过程,什么先什么后。
就是这样。
就这么简单。
我在两篇文章( Python 和 FAANG )中详细阐述了数据科学面试变得越来越受编程驱动和面向 CS 的主题。在今天的帖子中,我将介绍二分搜索法的基本知识和意识形态,并回答 FAANG 提出的一些真实的面试问题。二分搜索法绝对是经过最严格测试的算法之一,如果不是唯一的话,它非常容易掌握。
二分搜索法:什么和如何
官方将其定义为“在一个排序数组中找到目标值位置的搜索算法”,并将目标值与中间元素进行比较,检查它们是否等价。如果不相等,则移到下一个区间进行比较(改编自 Wiki )。
非官方的,我的直观定义是将搜索范围一分为二,询问计算机所选区间是否包含该值:如果区间小于目标值,则上移搜索空间,重新搜索;否则,向下移动。
一场猜谜游戏即将开始。它叫做“我的号码是多少?”基本上,我从 1 到 100 中挑选一个数字,你的工作就是通过问我问题来找到这个数字。
求数有两种方式:无效率和有效率。第一,你可以问我数字是不是 1;如果不是,检查范围内的其余数字,直到 100。如果我选了 100,你需要 100 次才能选对。这就是所谓的野蛮暴力法,虽然有效,但效率很低。如果数字在 1 到 100 万之间,你会怎么做?
第二,更聪明有效的方法是问这样的问题:
#1 问题:“你的数字高于 50 吗?”
“没有。”
所以,数字必须是从 1 到 49!我们甚至不需要检查任何高于 50 的值。
#2 问题:“你的数字高于 25 吗?”
“是的。”
现在,数字必须在 26 和 49 之间!没有必要检查从 1 到 25 的数字。
两个问题之下,我们缩小了真数的范围!你不会花太长时间最终得到它。
这是玩这个游戏时的算法思维。尽管二分搜索法的飞行名气很大,但它有一种脚踏实地的方法。最终,算法会告诉计算机如何处理信息。谈到算法,这是我的第一条规则。

Python 实现
基础学完了,就该用 Python 写点代码了。在这一部分,我通过科技公司问的三个面试问题来体验代码。每个问题都有几种解决方案,在应用二分搜索之前,我将介绍使用内置函数的方法。
通常对于 Python 编码挑战,你的面试官允许你使用任何内置的库和方法。只要您获得了预期的输出,您就可以开始了。随后,他们会增加额外的限制,比如你不能使用这个库/包,或者提高你的内存和速度。
出于教学目的,我介绍了这两种方法,请在准备技术面试时练习这两种方法。
以下问题按难度从大到小排序 。这是二分搜索法算法的内部笑话。学完今天的内容,你会笑。
问题 1:Sqrt(x ), FAANG
-给定一个非负整数 x,计算并返回 x 的平方根
-由于返回类型为整数,小数位数被截断,只返回结果的整数部分。
——比如 8 的平方根是 2.82842,但是这个函数应该只返回整数部分,2。
-https://leetcode.com/problems/sqrtx/
走过我的思考
该问题要求得到一个数的平方根,如果它不是完美的平方根,则只返回整数部分。两步之内就能完成。
1.求 x 的平方根;
2.只返回整数部分。
下面是 Python 代码。
2
numpy floor()和 int()方法的作用相同,它们只返回整数部分,而忽略小数部分(如果有的话)。但是它们的输出是不同的数据类型:floor()得到一个浮点数,int()返回一个整数。
你可能同意,这很容易被包括在 FAANG 的技术面试中。最有可能的是,你的面试官要求你不要用内置的方法,应用一些算法。
在这里,二分搜索法派上了用场。二分搜索法算法有三个步骤。在我们开始之前,请确保数组已经排序,或者减少或者增加。
#第一步。定义搜索空间:左、右和中间
#第二步。我们大胆猜测,从中间开始搜索算法。
#第三步。使用“if-else”语句检查目标值和搜索空间中的每个元素。
3
前两步不言而喻,让我们将第三步分解成不同的场景。第一个 if 条件(步骤 3.1)很简单,如果 root_squared 和 x 相同,它将返回根值。
elif 条件值得解释。如上所述,二分搜索法就像在玩一个从 1 到 100 的猜谜游戏,每次你都可以问一个问题:它是高于还是低于一个数字。条件说如果平方根小于 x,那么根号不够大,我们需要上移,下次再猜一个更大的数。
else 语句规定了当上述两个条件不满足时该做什么。如果平方根大于我们的数字 x,计算机应该向下移动搜索空间,就像我们之前玩的猜谜游戏一样。
所有这些条件都会在 while 循环中自动结束运行。最后,我们返回搜索空间的上界,aka。右。
如此简洁的解决方案!我总是说一个好的算法应该有直观的意义,二分搜索法说的很有道理。
#问题 2:二分搜索法,亚马逊、微软、贝宝和彭博
-给定一个排序的(按升序)n 个元素的整数数组 nums 和一个目标值,写一个函数在 nums 中搜索目标。如果目标存在,则返回其索引;否则,返回-1。https://leetcode.com/problems/binary-search/
走过我的思考
对于这个问题,我的首选方法不是二分搜索法,而是应用一个 enumerate ()方法来迭代链表,如下图所示:
4
结果显示该数字等于其在位置 4 的索引。可以使用列表理解将 for 循环进一步压缩成一行代码。
现在,让我们改变思路,使用二分搜索法。
解决办法
4
这是二分搜索法算法的标准实现,分别检查了 if-elif-else 语句。
到目前为止,您应该对算法的基本形式有了很好的理解。是时候实践该算法更复杂的应用了。

在 Unsplash 上 engin akyurt 拍摄的照片
#问题 3:检查一个数是否是排序数组中的多数元素,作者脸书
-给定一个按非降序排序的数组 nums 和一个数字目标,当且仅当目标是多数元素时,返回 True。
-多数元素是在长度为 N 的数组中出现 N/2 次以上的元素
-https://leet code . com/problems/check-if-A-number-is-majority-element-in-A-sorted-array/
走过我的思考
相比较而言,这是一个稍微复杂一点的问题。我的第一个方法是线性方法,即找到数组中的多数元素,然后判断目标值是否等于多数元素。
如果允许内置函数,我们可以这样做:
Result for the 1st test case is: True
Result for the 2nd test case is: False
简单地说,我们从集合中导入 Counter,遍历数组,如果条件成立,则返回 True。
如果反制方法不可行,事情会变得很糟糕,但我们不会完蛋。
二分搜索法可以扭转乾坤。
像我一样,如果这是你第一次学习算法,可能会有些不知所措。所以,我创建了这个问题的三个版本(难度递增)。一旦我们理解了如何回答前两个问题,最终(原始)版本就变得更“可解”
基本版本 1:使用二分搜索法检查目标值是否在一个排序数组中。
轻松点。这是算法的标准实现。我们已经涵盖了物流,并在问题 1 和 2 中提供了详细的解释。
基本版本 2:使用二分搜索法查找排序数组中某个元素的第一次和最后一次出现。
接下来,让我们增加一些趣味,找到一个元素的第一次出现(最左边)和最后一次出现(最右边)。
找到元素的第一个和最后一个位置很重要,因为它将多数元素定义为长度为 N//2 的元素。如果我们能够确定最左边/最右边的索引,我们就能很好地找到最终的解决方案。
向左搜索第一个匹配项
The Leftmost Occurrence is at Position: 2
有趣的是。在基础版本 2.1 中,搜索空间内的唯一区别是只有两个条件需要检查。
1.当选择的元素小于目标值时,我们需要向上移动左边界。
2.否则,元素大于或等于目标值,我们决定中间为上限。
向右搜索最后一次出现的内容
The Rightmost Occurrence is at Position: 11
类似地,我们可以使用上面的代码找到该元素的最后一次出现。
完整的 Python 代码在我的 Github 上有。
#高级版本 3.1:使用二分搜索法检查目标是否为多数情况
原问题 3
True
哇!
代码看起来很复杂,但坦白说很简单。
初始部分叫做 一个辅助函数 ,和其他任何函数是一回事。唯一的区别是我们将在外部函数中使用 helper 函数提供的功能。
helper 函数( 从第 8 行到第 16 行 )查找元素最左边的位置,这在计算第 24 行和第 25 行中元素的第一次和最后一次出现时很方便。最后,我们检查最右边和最左边位置之间的差值范围是否大于 N//2。
我在我的 Github 上包含了一个 3.1 版本的改进解决方案。
恭喜你的算法之旅。
外卖食品
- 成长心智( 学会如何学习 )。踏入未知的领域是可怕的。有了成长的头脑,如果我们坚持做下去,我们会做得更好。我过去通常害怕 Python 和编码。我担心如果我不知道如何写一个简单的 for 循环,我会显得多么笨拙。所有的负面情绪都在持续,很难集中精力学习。用 Python 写代码,解决有挑战性的谜题,带给我如此多的快乐和满足感。Python 是我的 禅 。
- 算法。这是我们用来告诉计算机如何处理信息的另一种语言。在其花哨的标题下,算法简单明了,就像我们玩的猜谜游戏一样。
- Practice makes perfect. 熟能生巧 (It’s the Chinese equivalence). Rome wasn’t built overnight. All of these popular expressions tell us one thing: no substitute for hard work. Practice daily, and we will be better at coding, Python, algorithm, and everything and anything.
Medium 最近进化出了它的 作家伙伴计划 ,支持像我这样的普通作家。如果你还不是订户,通过下面的链接注册,我会收到一部分会员费。
https://leihua-ye.medium.com/membership
我的数据科学面试序列
</6-python-questions-you-should-practice-before-coding-interviews-f958af55ad13> </5-python-coding-questions-asked-at-faang-59e6cf5ba2a0>
喜欢读这本书吗?
请在 LinkedIn 和 Youtube 上找到我。
还有,看看我其他关于人工智能和机器学习的帖子。
宁滨机器学习特征工程奖
原文:https://towardsdatascience.com/binning-for-feature-engineering-in-machine-learning-d3b3d76f364a?source=collection_archive---------16-----------------------
使用宁滨作为一种技术来快速轻松地创建用于机器学习的新特征。

蒂姆·莫斯霍尔德在 Unsplash 上的照片
如果您已经训练了您的模型,并且仍然认为准确性可以提高,那么可能是时候进行特征工程了。特征工程是使用现有数据创建新特征的实践。这篇文章将关注一种叫做“宁滨”的特征工程技术。
这篇文章假设读者对 Python、Pandas、NumPy 和 matplotlib 有基本的了解。大多数情况下,提供链接是为了更深入地了解正在使用的内容。如果有什么说不通的地方,请留言评论,我会尽力阐述。
什么是宁滨?
宁滨是一种技术,它实现了听起来的效果。它将采用一列连续的数字,并根据我们确定的范围将这些数字放入“箱”中。这将给我们一个新的分类变量特征。
例如,假设我们有一个汽车的数据框架。

汽车样本数据框架
我们将重点放在 MPG 栏,并制作 3 个箱子,燃油效率,平均燃油效率,和耗油量大。
制作垃圾桶

我们的第一步将是确定这些箱的范围。这可能很棘手,因为它可以通过几种不同的方式来完成。
一种方法是根据值的分布均匀划分容器。基本上,我们将经历相同的过程,就好像我们正在创建一个直方图。
由于 Python 使用 matplotlib 简化了直方图的生成,所以让我们在直方图中可视化这些数据,并将 bin 参数设置为 3。
import import matplotlib.pyplot as plt
mpgs = cars['MPG']
plt.hist(mpgs, bins=3)
plt.show()

mpg 直方图
看起来我们的 3 个箱子大约是 10–25,25–40 和 40–56。
让我们通过返回一个显示箱子宽度的数组来确认我们是正确的。
plt.hist(mpgs, bins=3)[1]
\\array([10\. , 25.33333333, 40.66666667, 56\. ])
我们还可以对燃油效率进行一些研究,看看是否有更好的方法来创建我们的 bin 范围。用谷歌快速搜索,很明显,燃料效率是相对的。这是由许多因素决定的,通常与车龄和车型/级别有关。为了使这个例子简单,我们将坚持使用直方图方法。但是,请记住,理解数据是宁滨的一个重要组成部分,一点点研究可以走很长的路。
将 MPG 放入正确的箱子

现在我们知道了箱子的范围,我们可以创建一个简单的函数,利用熊猫超酷的剪切函数。Cut 将使用我们提供的标签名称和范围拆分我们的列。请注意,要包含 10 个,我们必须在 9 点开始第一次切割。
def make_bins(df):
label_names = ["Gas Guzzler", "Average Fuel Efficiency","Fuel Effecient" ]
cut_points = [9, 25.333, 40.667, 56]
df["MPG_effeciency"] = pd.cut(df["MPG"], cut_points, labels=label_names)
return df
我们现在要做的就是将原始数据帧作为参数传递给函数。
new_cars_df = make_bins(cars)
这会给我们…..请敲鼓。带有 MPG 类别列的新数据框!

假装一下

洛伊·赫尔曼先生和他的口技木偶。威廉·詹姆斯·哈丁(1826–1899):旺格努伊区的底片。参考文献:1/4–006817-g .亚历山大·特恩布尔图书馆,新西兰惠灵顿。/记录/22322062
最后一步是得到一些虚拟模型,因为我们的模型很可能只能接受整数。
dummies = pd.get_dummies(new_cars_df["MPG_effeciency"])
new_cars_df = pd.concat([new_cars_df, dummies], axis=1)
瞧,我们已经快速生成了新的特征用于训练,并有望提高我们模型的准确性。

在您使用这些新设计的功能进行训练之前,请确保删除 MPG 列,因为重复数据可能会导致一些不良结果。
仅此而已。几分钟之内,我们已经设计了新的功能!
宁滨用熊猫切和 QCut 记录了一个连续变量
原文:https://towardsdatascience.com/binning-records-on-a-continuous-variable-with-pandas-cut-and-qcut-5d7c8e11d7b0?source=collection_archive---------11-----------------------
入门
何时、为何以及如何将数字特征转换为分类特征
今天,我将使用“西雅图市工资:按性别比较-工资增长职位”数据集来探索宁滨-也称为分组记录-以及单个数字变量。在西雅图开放数据门户的这里找到数据。
给 binners 一个警告:宁滨降低了粒度,并不总是有用的。宁滨通常不用于机器学习模型。
对分箱数据消费者的一个警告:分箱边缘的选择会有很大的影响,特别是在小样本中。当心有人利用宁滨来欺骗或误导你。就推理和其他宁滨选项的结果提问。
何时以及为什么要装箱
我使用宁滨将连续数据分组进行比较。例如,我可以把人们分成不同的年龄组。这允许统计比较和流线型视觉的创造。
同时,这种划分可能有些武断:如果我们以 10 岁为增量分组,30 岁的人可能比 21 岁的人更接近 31 岁的人。
我喜欢在两种情况下绑定:
- 当存在现实生活或商业门槛时。例如,在航空里程方面,当你达到某个阈值时,福利和激励就会改变,从而形成逻辑分组。对于联合航空公司:MileagePlus、卓越银牌、卓越金牌、卓越白金、卓越 1k。
- 确定模式后,当创建适合我的观众的可视化效果时。在今天的例子中,我绘制了每种工作的女性百分比(在城市报告中,具有该职位的员工中有多少百分比被确定为女性)与该职位的平均时薪(在该职位级别的所有员工中):

西雅图市女性工作百分比与平均时薪散点图。趋势线随着平均时薪的增加而减小。
通过最佳拟合线,我们可以看到,随着平均时薪的增加,女性的比例通常会以平均时薪每增加 1 美元女性减少 0.9%的速度下降。我们有一个 3.6 倍 10^-11 的 p 值,因此这种趋势不太可能是由于抽样。这对一些观众来说太难了。
此外,如此多的职位只有很少的雇员,我们得到的这些水平线分别是 0%、50%和 100%的女性。这些突出的方式分散了外卖的注意力。我想把这个有点抽象的散点图转化成一个快速可消化的可视化。我决定去垃圾箱。
如何装箱
有三个主要的宁滨决策:垃圾箱的数量、垃圾箱的类型和标签。我将逐一介绍这些决策的一些考虑因素:
垃圾箱数量:在网上快速搜索可以找到各种各样的经验法则,帮助你决定垃圾箱的数量。(试试这篇维基百科的文章。)
箱柜类型:
- 您的数据有自然的、有意义的间断吗?例如,您可能想要调查在设定的航空里程范围内不同常旅客类别的行为差异。也许你想用联邦退休年龄和典型的高中毕业来将人们分为“青年”、“工作年龄”、“符合退休条件”。
- 您是否希望根据记录的相对定位来拆分记录?例如,你可能想比较收入最高的 1%的人和收入最低的 10%或 50%的人,而不是考虑特定的收入水平。
标签:还是由你决定——你想给你的小组起什么名字?您也可以给它们加上范围标签或整数标签。
一旦你决定了这三件事(或者把这些决定记在心里),你就可以使用 cut(如果你想根据你的自变量进行分割的话)或者 qcut(qcut)进行样本百分比分割。
对连续变量进行拆分,然后用 cut 对记录进行分类
要根据小时工资率将职称分成五组,并使用相等的 x 轴大小的框:
df['pay_grp_cut_n'] = pd.cut(df['total_avg_hrly_rate'], 5)
这将向 df 添加一个列“pay_grp_cut_n ”,其中每个值都是一个记录所在的 bin 范围。
在 y 轴上显示职称数量会创建一个直方图:

我们可以看到时薪组分为五个 16 美元/小时的区间,从最低平均时薪(5 美元)到最高平均时薪(86 美元)。这种划分导致绝大多数的职位都属于中心和中心以下的群体。
我可以画出这些群体中女性的平均百分比,来说明不同时薪群体中女性百分比的变化:

# get sums within group - esp for employee counts
grouped = df.groupby(df['pay_grp_cut_n'], as_index=False).sum()# set x and y
x = grouped['pay_grp_cut_n'].astype(str)
y = grouped['no_female_empl'] / grouped['total_no_empl'] *100# create visual
fig, ax = plt.subplots(figsize=(12,8))
plt.xlabel('Average Hourly Rate')
plt.ylabel('Percent Female')
plt.title('Percent Female vs. Average Hourly Rate for Seattle City Jobs')
plt.ylim(0,100)
plt.bar(x, y, alpha=.5)
这种形象化将观众的注意力集中在女性代表人数的下降上,因为职称工资增加了。我可以使用这些分类来确定每个分组的统计显著性和/或根据上下文添加误差线。
根据您的需求优化 cut 的一些其他选项(一如既往,在文档中了解更多):

- 调整标签
df[‘pay_grp_cut_l’] = pd.cut(df[‘total_avg_hrly_rate’]
,5
,labels=[‘Very Low’, ‘Low’, ‘Medium’
,‘High’, ‘Very High’])
- 设置容器边界。你可以这样做,为航空公司奖励水平,或获得整数斌休息。
df['pay_grp_cut_set_boundaries'] = pd.cut(df['total_avg_hrly_rate']
,[5,20,35,50,65,80])
使用 qcut 将记录分组到基于卷的组中
QCut或“分位数切割”不是基于标量值进行分割,而是基于落入每个桶中的样本数进行分割。
如果你想要五个大小相等的组,按小时工资排序,你可以使用类似于cut的qcut 。
df['pay_grp_qcut_n'] = pd.qcut(df['total_avg_hrly_rate'], 5)

使用qcut偶数大小的分组,您会看到现在我们的 bin 大小从大约 5 变化到大约 43。每个框代表大致相同数量的职位。
比较cut 和qcut 在每个时段中的职位数量可以看出这一差异:

使用qcut,您可以像设置cut一样设置标签。df[‘pay_grp_qcut_l’] = pd.qcut(df[‘total_avg_hrly_rate’], 5, labels=[‘Very Low’, ‘Low’, ‘Medium’, ‘High’, ‘Very High’])
您可以设置每个桶中的体积百分比来创建不同大小的分组,而不是显式设置边界。例如,如果你在一条曲线上打分,那么你可能想把学生分成(对我来说,任意的):10% F,20% D,20% C,40% B,10% A。你可以使用 qcut 给学生打分:
df['letter_grade'] = pd.qcut(df,
[.1, .2, .2, .4, .1],
labels=['F', 'D', 'C', 'B', 'A'])
何时使用 Cut 与 QCut
这个选择真的取决于你的用例。你有没有很强的商业逻辑或者现有的分类是你想要匹配的或者是你的受众习惯思考的?这将是一个主要的原因削减!其他时候,考虑类似规模的分组或客户的百分比可能更有意义。
无论您决定在您的环境中哪一个有意义,您都可能想要考虑未选择的路径的影响。使用 cut 时,小组规模可能会有很大不同——强调这种变化的幅度(为您自己和/或您的观众)。使用 qcut,铲斗大小可能会有很大的变化——忘记这一点,后果自负。
确定容器边界的另一种方法
Fisher-Jenks 算法在一维数据中找到自然边界,像 k-means,但是 1D。查看jenkspy获得一个不错的实现。您仍然需要仔细考虑要寻找的条柱/间隔的数量,但是可能会得到更多的逻辑分组,尤其是当您的数据集具有不同的间隔时。例如,在一个 4 岁孩子的生日聚会上,身高可以自然地分为“成年人”、“4 岁儿童”、“6 岁儿童”、“2 岁儿童”,尽管偶数或 qcuts 的划分可能与这些分组相去甚远。
编码快乐!你可以在这里找到回购。

照片由 Luca Upper 在 Unsplash 上拍摄
Python 中的二项式分布和二项式检验—统计学
原文:https://towardsdatascience.com/binomial-distribution-and-binomial-test-in-python-statistics-pyshark-91aa6403d674?source=collection_archive---------20-----------------------
在本文中,我们将探讨 Python 中的二项分布和二项测试。

由 Unsplash 上的 Edge2Edge 媒体拍摄
目录
- 介绍
- 什么是二项分布
- 在 Python 中创建和绘制二项式分布
- 什么是二项式检验(举例)
- Python 中的二项式测试(示例)
- 结论
介绍
为了继续学习本教程,我们需要以下 Python 库:scipy、numpy 和 matplotlib。
如果您没有安装它,请打开“命令提示符”(在 Windows 上)并使用以下代码安装它:
pip install scipy
pip install numpy
pip install matplotlib
什么是二项分布
二项式分布和正态分布是统计学中最流行的分布之一。二项式分布是一系列独立实验( n )中若干成功的离散概率分布( X )。每个实验都有两种可能的结果:成功和失败。成功结局有概率( p ),失败有概率( 1-p )。
注意:一个单独的实验也叫做伯努利试验,一个只有两种可能结果的实验。并且一个实验的二项式分布( n =1)也是伯努利分布。
换句话说,二项式分布模拟了在重复多次的独立实验中观察到成功或失败结果的概率。
假设成功的概率等于: p
那么故障概率等于: q=1-p
所以获得( k )成功和( n-k )失败的概率等于:

作者图片
获得( k )成功的方法数量计算如下:

作者图片
使用上面的符号,我们可以求解概率质量函数(在( n 个)实验中获得( k 个)成功的总概率):

作者图片
注:概率质量函数(PMF)-给出离散随机变量恰好等于某个值的概率的函数。
二项式累积概率函数的公式为:

作者图片
例如:
你正在掷出一个 6 面骰子 12 次,你想找出 5 次结果为 3 的概率。在这里,得到 3 是一个成功的结果,而得到任何其他(1,2,4,5,6)是一个失败的结果。显然,在每一次掷骰子中,你得到 3 的概率是(1/6)。根据我们这里的数据,掷骰子 12 次,结果应该是 3(12 *(1/6))。
现在,我们实际上如何计算 5 次观察到结果 3 的概率?
使用上面的公式,我们可以很容易地解决它。我们有一个实验,它发生了 12 次( n = 12),有问题的结果数是 5 ( k = 5),概率是(1/6)或四舍五入后的 0.17(p= 0.17)。
代入上述等式,我们得到:

作者图片
这个实验的二项式分布看起来像这样:

作者图片
你可以清楚地看到,观察 3 作为结果,在 2 次的概率最高,观察 5 次的概率小于 0.05。
在 Python 中创建和绘制二项式分布
现在让我们探索如何创建二项式分布值并使用 Python 绘制它。在本节中,我们将使用三个 Python 库:numpy、matplotlib 和 scipy。
我们将首先导入所需的模块:
对于数据,我们将继续上一节的示例,我们掷骰子 12 次( n = 12),其中观察到从 1 到 6 的任何数字的概率是(1/6)或 0.17 ( p = 0.17)。
现在我们将在 Python 中为它们创建值:
其中 x 是一个从 0 到 12 的数字数组,代表任何数字可以被观察到的次数。
使用这些数据,我们现在可以计算二项式概率质量函数。概率质量函数(PMF)是给出二项式离散随机变量恰好等于某个值的概率的函数。
在我们的示例中,它将显示从 12 次掷骰子中,您可以观察到任何概率为 0.17 的数字的次数。
构建 PMF:
你应该得到一个有 13 个值的数组(这是我们的 x 值的概率):
[1.06890008e-01 2.62717609e-01 2.95952970e-01 2.02056244e-01 9.31162813e-02 3.05152151e-02 7.29178834e-03 1.28014184e-03 1.63873579e-04 1.49175414e-05 9.16620011e-07 3.41348087e-08 5.82622237e-10]
现在我们有了二项式概率质量函数,我们可以很容易地将其可视化:
您应该得到:

作者图片
现在,试着解释我们看到的东西怎么样?
该图显示,如果我们从 1 到 6(骰子面)中选择任意一个数字,并掷骰子 12 次,观察到这些数字的最高概率是 2 次。
换句话说,如果我选择数字 1,掷骰子 12 次,很可能 1 会出现 2 次。
如果你问,1 出现 6 次的概率是多少?通过查看上面的图表,你可以看到它略高于 0.02%或 2%。
什么是二项式检验
二项式检验是一种单样本统计检验,用于确定二分分数是否来自二项式概率分布。
利用上一节的例子,让我们以一种可以做一些假设检验的方式来重新表述这个问题。以下是情况:
你怀疑骰子偏向数字 3(三个点),你决定掷骰子 12 次( n = 12),观察到数值 3(三个点)5 次( k = 5)。您想了解骰子是否偏向数字 3(回想一下,观察到 3 的预期概率是(1/6)或 0.17)。
制定假设我们会有:

作者图片
现在计算概率:

作者图片
这里的概率是显著性检验的 p 值。由于 0.03 < 0.05,我们拒绝零假设,接受骰子偏向数字 3 的替代假设。
Python 中的二项式测试(示例)
现在让我们使用 Python 对上面的例子进行二项式测试。
这是一个非常简单的 scipy 库函数的几行实现。
第一步:
导入函数。
第二步:
定义成功次数( k ),定义尝试次数( n ),定义预期成功概率( p )。
第三步:
在 Python 中执行二项式测试。
我们应该得到:
0.03926688770369119
这是用于显著性检验的p-值(类似于我们通过求解上一节中的公式得到的数值)。
注意:默认情况下,计算的测试是双尾测试。如果您正在处理单尾测试情况,请参考此函数的 scipy 文档。
结论
在本文中,我们探讨了二项式分布和二项式测试,以及如何在 Python 中创建和绘制二项式分布,并在 Python 中执行二项式测试。
如果你有任何问题或对一些编辑有建议,请随时在下面留下评论,并查看更多我的统计文章。
最初发表于 2021 年 10 月 1 日https://pyshark.com。
实践中的二项式分布
原文:https://towardsdatascience.com/binomial-distribution-ec76d74952c4?source=collection_archive---------5-----------------------
数据科学家的数学复习
用 R 和 Python 语言清晰地解释了理论和方便的函数
你知道概率分布很重要,二项分布是基本分布。但是你仍然对此有些怀疑。我应该什么时候使用它?如何理解概率质量函数和累积密度函数的方程?R 和 Python 中有哪些得心应手的函数?最后,从理论和实践的角度来看,你会觉得使用二项式分布很舒服。让我们开始吧!
我们将在本文中讨论以下主题:
- 伯努利试验
- 二项分布
2.1 二项系数
2.2 二项密度函数(PMF)
2.3 累积密度函数(CDF) - 二项分布的行为
- R 和 Python 中的二项式分布函数
4.1 R
4.2 Python - 实践中的二项分布
1.伯努利试验
伯努利试验是一个随机实验,它有两种可能的结果,通常表示为“成功”(1)和“失败”(0)。“成功”符合给定的标准,例如,大于 7 的数字、女性、年龄小于 10 岁、负回报等。它并不意味着这个结果在这个词的伦理意义上是“好”的。
如果 q 是成功的概率,而 p 是失败的概率,那么:

由于除了 0 或 1 没有其他选择,所以成功和失败的概率之和总是等于 1。
2.二项分布
让我们先看看定义。二项式分布描述了 N 次独立伯努利试验中成功次数的分布,其中成功概率为常数,p【1】。简单地说,它的意思是:
- 我们重复同一个实验很多次。比如抛硬币 N=1000 次。
- 在每次试验中,恰好有两种结果是可能的:头和尾(成功和失败,伯努利试验)。因此,这个定义中的伯努利试验将二项分布缩小为离散分布,其中实验结果只能取 0 或 1。任何介于之间的,比如 0.3,0.01,或者既不成功也不失败,都是不可能的。
- 在每次试验中,获得正面的概率是相同的(p=0.5)。它不依赖于任何先前的结果,所以它是独立的。
2.1.二项式系数
为了表达二项式密度函数,我们首先需要定义二项式系数:

我们可以理解为“N 选 m”。它描述了 X 可以取给定值 m 的方式的数量。当选择的顺序无关紧要时,它从集合中选择 m 个项目。如果集合有 N 个元素,m 个组合的数目等于二项式系数[2]。
让我们看看这个例子。在抽签中,从 20 个球中选出 5 个球。需要购买多少张彩票才能确保中奖?一开始我们有 20 个球可供选择,第二选择有 19 个,第三选择有 18 个,依此类推。所以,我们有

二十个球中选择五个球的不同方法。但是我们并不关心彩票的顺序,重要的是有相同的号码。这意味着{A,B,C,D,E}顺序的球和{B,E,A,C,D}对我们来说是同一套球。
所以我们需要减少 1.860.480 种按重复选择的方式(所选球的排序方式数)。既然我们有五个球,我们可以在五分钟内完成!=120 种不同的方式。最后,我们将 1.860.480 种选择方式除以 120 个订购选项,得到 15.504 张票可以购买!

值得吗?
让我们回到二项式系数。在分子中,我们可以看到我们可以用多少种方法来排列 20 个球!(N!).在分母中,我们通过排序选项来减少结果:
- 订购方式 5!选定的球(m!),以及
- 对池中剩余的球进行排序的可能性(N-m)!,这里 15!
像被选中的球的顺序一样,我们不关心未被选中的球的顺序。最后,我们得到:

和我们上面得到的完全一样,但是方式更简单。
“!”符号是阶乘。正如你可能看到的,对于非负整数 x ,它被计算为所有数字的乘积,直到 x ,例如:

2.2.二项式密度函数(PMF)
现在,我们准备将二项式密度函数定义为在 N 伯努利试验中获得 m 次成功的概率:

因此,二项式分布是一系列给定实验的 N 次独立重复中成功次数( m )的离散概率分布,该实验询问是-否(成功-失败,1–0)问题,成功的概率是 *p,*而失败的概率是 q=1-p 。
让我们考虑一个例子。篮球训练的时候你在练罚球。从赛季统计中,我们知道你得一分的概率是 75%。你的教练告诉你,如果你在 20 次尝试中得到 17 分,你将开始下一场比赛。你正好得 17 分的概率是多少?
我们需要假设罚球成功的概率与之前的结果无关(这里心理力量不发挥作用)。我们也不关心得分的顺序,所以不管你是第一次、第三次还是最后一次失败都没关系。因此,这是一个二项式分布。我们可以使用上面给出的二项式密度函数,得到:

我们可以为其他分数重复这个练习。结果,我们得到了二项分布图(PDF):

给定 20 次伯努利试验中的分数,获得的概率给定成功试验的概率为 75%。作者的情节。
但是你至少要拿 17 分,不是正好 17 分。那么你在下一场比赛中首发的可能性有多大?
2.3.累积密度函数
这里,一个二项分布的累积分布函数将有助于回答这个问题。如果你想知道为什么,请先看看这篇文章:
累积分布函数(CDF)描述了 X 取值等于或小于 k 的概率(机会)。二项式分布的 CDF 函数如下:

其中*【k】为 k 下的“下限”,即等于或小于k*的最大整数
因此,我们需要将你获得 17 次、18 次、19 次或 20 次罚球的概率相加,在 PMF 图上用红色标出:

在 20 次尝试中获得 a 分数的概率,假设成功概率为 75%。作者的情节。

由于概率总和为 1,我们也可以采取相反的方法——从 1 中减去最高得分 16 分(17 分的剩余部分)的累积概率:

这显示在 CDF 图中:

20 次尝试的累积概率,假设成功概率为 75%。作者的情节。
这两种方法的结果是一致的。你的教练给你的任务很有挑战性,但是考虑到概率还是可行的,所以试一试吧!
3.二项分布的行为
如果你从教练那里得到更多的尝试,机会会有怎样的变化?你仍然需要达到 85%的成功投掷,但是你接受了 20、50 或 100 次尝试。让我们看下一个情节。

考虑不同样本量的二项分布的概率密度函数。作者的情节。
样本量越大,分布越广。获得至少 85%罚球成功率的概率如下:

鉴于成功概率为 75%,获得 85%的试验次数的概率。表作者。
考虑到表格中的结果,你不应该强迫你的教练给你额外的试验。尝试的次数越多,获得比你长期成功概率更好的分数的可能性就越小。
接下来,让我们看看艰苦的训练是否增加了你的机会。我们考虑三种成功的可能性:20%、50%和 90%。轨迹的数量保持不变(100)。

考虑不同成功概率的二项分布的 PDF。作者的情节。
下表总结了 85%成功投掷的概率,给出了 75%的长期成功概率。

努力训练比和教练争着跑更多的路更有意义!
4.R 和 Python 中的二项式分布函数
让我们仔细看看 R 和 Python 中有助于处理二项分布的函数。
4.1.稀有
在 r 中至少那四个函数是值得知道的,下面的例子中, m 是成功尝试的次数, N 是样本的大小(所有尝试的次数), p 是成功的概率。
- dbinom(m,N,p): 该函数计算在成功概率为 p 的 N 次随机试验中恰好有 m 次成功的概率。例如,20 次投掷中的 17 次得分给出 dbinom(17,20,0.75)。如果我们为每个可用的分数计算 dbinom,我们可以绘制一个 PMF 图(如上例所示)。

图片作者在 @carbon_app
- pbinom(m,N,p): 该函数计算累积概率函数,使得成功次数等于或小于 m 。对于至少有 17 个分数的示例,它是 1-pbinom(16,20,0.75)或 pbinom(16,20,0.75,lower.tail=FALSE)。如果我们加上 lower.tail=FALSE,我们考虑获得至少 *m* 次成功的概率。默认值较低。tail=TRUE。

图片作者在 @carbon_app
qbinom(probability P,N,p) 返回逆累积密度函数的值。它找出二项分布的第 p 个分位数。对于给定的概率,你需要多少成功的分数?qbinom(0.55,size=20,prob = 0.75)给出 15。这意味着有 55%的几率你最高可以得 15 分。
rbinom (m,N,p) 是生成一个二项分布随机变量的向量。这对于训练目的是有用的。
4.2.计算机编程语言
Python 中那些来自scipy . stats . binom库的函数值得了解。在下面的例子中, m 是成功尝试的次数, N 是样本的大小(所有尝试的次数), p 是成功的概率。
- pmf(m,N,p): 这个函数计算概率质量函数,所以在 N 随机试验中有精确 m 成功的概率,有 p 成功的概率。比如 20 投 17 分给 scipy.stats.binom.pmf(17,20,0.75)。如果我们计算每个可用分数的 dbinom,我们就可以绘制 PMF。

图片作者在 @carbon_app

作者图片
- cdf(m,N,p) 允许计算累积分布函数,使得成功次数等于或低于 m 。对于我们这个至少有 17 个分数的例子,就是:1-scipy.stats.binom.cdf(16,20,0.75)。

图片作者在 @carbon_app

作者图片
- ppf(m,N,p) 此函数给出了百分点函数,因此它返回了反累积密度函数的值。它找出二项分布的第 p 个分位数。对于给定的概率,你需要多少成功的分数?scipy.stats.binom.ppf(0.55,size=20,prob = 0.75)给出 15。这意味着有 55%的几率你最高可以得 15 分。我们还可以检查 PFM 和 CDF 的准确性:

图片作者在 @carbon_app
- stats(N,p,moments='mvsk') 允许计算前四个矩,即均值(' m ')、方差(' v ')、偏斜(' s ')、峰度(' k ')。如果你需要重温统计时刻,这篇文章可能适合你:

图片作者在 @carbon_app
- rvs (n,p,size=) 是生成一个二项分布随机变量的向量。这对于训练目的是有用的。
5.实践中的二项分布
二项式分布是统计显著性二项式检验的基础。它旨在检查只有两种可能结果的实验结果是否与预期的结果有统计学差异。
例如,你期望你的投资回报在 95%的时间里都在-100 美元以上。然后,您检查上个月(22 个交易日)的实际回报,您会得到以下结果:

我们能说结果与我们的期望不同吗?首先,我们需要假设每天的收益是独立的。然后,我们将测试的零假设定义为实验结果与预期结果没有显著差异。我们想检查真实数据是否支持另一种选择,即成功的真实概率(这里的回报低于-100 美元)大于 0.05 。假设每天只有成功(低于-100 美元)和失败(高于或等于-100 美元)选项,我们可以使用上面给出的 CDF 等式:

考虑到 5%的阿尔法水平,我们不能拒绝零假设,即结果没有明显不同于预期。因此,即使例外情况的数量高于预期,保持冷静,不要对市场走势反应过度也是一个好策略。
感谢阅读!
我很高兴你看到了这篇文章的结尾。我们讨论了与二项分布相关的最重要的主题。我希望这对你来说是一次激动人心的旅行!
我很乐意在下面的评论区听到你的想法和问题,你可以直接通过我的 LinkedIn 或者 akujawska@yahoo.com 的 T2 联系我。后会有期!
您可能还喜欢:
参考
[1] C .亚历山大(2008):《市场风险分析》。第一卷:金融中的定量方法”,约翰·威利父子有限公司,ISBN 978-0-470-99800-7
[2]维基百科中的组合:【https://en.wikipedia.org/wiki/Combination】T4
【3】a . b .唐尼:“想统计。Python 中的探索性数据分析"
云上的生物信息学
原文:https://towardsdatascience.com/bioinformatics-on-the-cloud-144c4e7b60d1?source=collection_archive---------27-----------------------
将 RNAseq 与 Google 云平台上的 STAR 对齐

云中的运行之星。图片作者。
关联
分析一个人的 DNA 及其转录指令(RNA)的价格正在迅速变得便宜。因此,不仅在科学实验室,而且在日常医疗保健中,测序技术的应用正在增长。但是,为单个个人生成的数据的大小很容易超过几个 GB。因此,这确实是一个大数据问题!由于云是专门为解决大规模问题而设计的,我们可以利用它的工具和基础设施来促进我们的生物信息学分析。通过在云上运行您的生物信息学工具,您可以在很短的时间内完成分析。
范围

图 1:校准程序的示意图。STAR 使用参考基因组和基因注释将 FASTQs 转换为 SAM 文件。图片作者。
本教程将带你完成在谷歌云平台(GCP)上比对人类 RNA 测序数据(简称 RNAseq)的步骤。
目标:
- 在云上存储基因组数据。
- 使用 STAR 比对 RNA 测序数据。
背景
从一条链上读出核苷酸碱基的测序机器只能读出片段的一小部分。因此,机器会产生大量的小块碱基,称为读作。通常,读取有两种方式:左读和右读。这些读数由成对末端测序机器生成,是机器开始读取碱基的片段的两边。完成测量后,测序仪通常会生成两个文件(每种口味一个),其中包含所有这些碱基块以及相应的质量评估,格式为FASTQ。所有这些小拼图,现在都是 FASTQ 格式,必须重新组合在一起。这是与参考基因组比对的过程,其中读数被分配到基因组上的一个位置。当成功时,这将产生一个指示读取的基因组位置的 SAM 文件。我们今天的任务是对来自 RNA 材料的碱基进行比对。或者换句话说,将 FASTQ 文件合并并转换为 SAM 文件。
初步步骤
打开谷歌云平台仪表盘,点击右上角的云壳图标(图 2)启动终端。

图 2:谷歌云平台中的云壳图标。图片作者。
我们将利用 dsub 在 Google 云平台上分配我们的生物信息学工作量。要安装dsub,请执行:
**sudo pip3** install dsub
在您的云 shell 中,或者在您的本地机器上,如果您已经在本地安装并配置了gcloud的话。

图 3:在 Google 云平台的云壳中执行 shell 命令。作者截屏。
接下来,选择存储数据的名称,例如gs://rna-seq-tutorial,并创建一个存储桶(mb):
export BUCKET=gs://rna-seq-tutorial
export REFDATA=${BUCKET}/refdata
export INPUT=${BUCKET}/input
export GENOME_INDEX=${BUCKET}/genome_index
**gsutil mb** -l europe-west4 ${BUCKET}
并将注释文件下载到新创建的存储桶中:
**wget** -O - \
ftp://ftp.ebi.ac.uk/pub/databases/gencode/Gencode_human/release_36/gencode.v36.chr_patch_hapl_scaff.annotation.gff3.gz \
| **zcat** \
| **gsutil cp** - ${REFDATA}/gencode.v36.chr_patch_hapl_scaff.annotation.gff3
该命令下载文件(wget)、解包(zcat)并将数据复制到 bucket ( gsutil cp)。接下来,复制要与 bucket 对齐的 FASTQ 文件(原始格式的 RNAseq 数据)。如果您没有使用自己的文件,请使用以下示例文件 [1]:
**wget** [http://genomedata.org/rnaseq-tutorial/practical.tar](http://genomedata.org/rnaseq-tutorial/practical.tar)
**tar** -xf practical.tar*# Sample 1.*
**gsutil cp** \
hcc1395_normal_rep1_r1.fastq.gz \
${INPUT}/sample1_R1.fastq.gz
**gsutil cp**\
hcc1395_normal_rep1_r2.fastq.gz \
${INPUT}/sample1_R2.fastq.gz
*# Sample 2.*
**gsutil cp** \
hcc1395_tumor_rep1_r1.fastq.gz \
${INPUT}/sample2_R1.fastq.gz
**gsutil cp**\
hcc1395_tumor_rep1_r2.fastq.gz \
${INPUT}/sample2_R2.fastq.gz
最后,启用云生命科学 API ,以使用dsub。
将表达式数据与星号对齐
为了将 RNA 转录物与参考基因组进行比对,我们将利用STAR【2】。与 STAR 的比对是一个两步过程:
- 使用基因组参考信息生成基因组索引。
- 使用基因组索引比对测序数据。
生成基因组索引
STAR 使用参考基因组和注释文件来生成索引文件。创建一个名为step1.sh的 bash 脚本,内容如下:
#!/bin/bash
**STAR** --runThreadN 8 \
--runMode genomeGenerate \
--sjdbOverhang 100 \
--genomeFastaFiles ${FASTA_FILE} \
--sjdbGTFfile ${GTF_FILE} \
--genomeDir ${GENOME_INDEX}
这将使用 8 个内核来生成索引文件,并将它们写入$GENOME_INDEX(位置将在下面指定)。我们使用--genomeFastaFiles标志传递参考基因组,而基因注释文件可以用--sjdbGTFfile指定。关于命令行参数的更多细节,请参考 STAR 手册。接下来,使用dsub在一个具有 8 个虚拟内核(--min-cores 8)和 48gb 内存(--min-ram 48)的工作线程上执行工作负载,因为 STAR 在这一步需要大量内存:
**dsub** \
--provider google-cls-v2 \
--project <my-project> \
--location europe-west4 \
--zones europe-west4-a \
--preemptible \
--min-ram 48 \
--min-cores 8 \
--logging "${BUCKET}/logging/" \
--input FASTA_FILE=gs://gcp-public-data--broad-references/hg38/v0/GRCh38.primary_assembly.genome.fa \
--input GTF_FILE=${REFDATA}/gencode.v36.chr_patch_hapl_scaff.annotation.gff3 \
--output-recursive GENOME_INDEX=${GENOME_INDEX} \
--image registry.gitlab.com/hylkedonker/rna-seq \
--script step1.sh
决定你是否要冒着工作终止的风险去寻找更便宜的先占计算(--preemptible),并用你的谷歌云平台项目 ID 替换<my-project>。您可以根据需要调整位置,但建议您相应地调整铲斗位置。请注意,不需要启动虚拟机,也不需要安装我们的生物信息学工具。相反,我们使用了一个 Docker 映像(--image registry.gitlab.com/hylkedonker/rna-seq),它包含了我们需要的所有东西,而dsub负责处理剩下的事情。当我们的工作负载在云上执行时,我们可以为下一步做准备。
参考基因组比对
为了进行实际校准,创建一个包含以下内容的文件step2.sh:
#!/bin/bash
**STAR** \
--runThreadN 4 \
--readFilesCommand zcat \
--genomeDir ${GENOME_INDEX} \
--readFilesIn ${R1} ${R2} \
--outFileNamePrefix "${OUTPUT}/"
该脚本调用 STAR,使用上一步(--genomeDir ${GENOME_INDEX})中生成的索引在四个内核(--runThreadN 4)上进行实际对齐。注意,每个样本的对齐(在计算上)是一个独立的问题。这意味着所有样品可以平行对齐!使用dsub执行任务数组很容易。简单地创建一个制表符分隔的文件(一个.tsv文件),其中的参数将被传递给dsub。对于本教程,创建一个名为job2.tsv的文件,其内容如下:
--input R1 --input R2 --output-recursive OUTPUT
gs://rna-seq-tutorial/input/sample1_R1.fastq.gz gs://rna-seq-tutorial/input/sample1_R2.fastq.gz gs://rna-seq-tutorial/output/step2/sample1
gs://rna-seq-tutorial/input/sample2_R1.fastq.gz gs://rna-seq-tutorial/input/sample2_R2.fastq.gz gs://rna-seq-tutorial/output/step2/sample2
用适当的值替换<my-bucket>。另外,请注意,这些列是用制表符分隔的(没有空格)。在执行比对工作负载之前,确保STAR完成了基因组索引的生成。可以使用dstat查询状态。验证作业已成功执行后,使用以下方法将调整工作负载提交到云:
**dsub** \
--provider google-cls-v2 \
--project <my-project> \
--location europe-west4 \
--zones europe-west4-a \
--preemptible \
--min-ram 32 \
--min-cores 4 \
--logging "${BUCKET}/logging/" \
--input-recursive GENOME_INDEX=${GENOME_INDEX} \
--image registry.gitlab.com/hylkedonker/rna-seq \
--tasks ./job2.tsv \
--script step2.sh
这里,我们使用--tasks ./job2.tsv来指代输入和输出参数,每个样本一行。最后,等待工作人员完成(使用dstat来轮询状态),并且不要忘记在完成计算后删除您的资源,以防止额外的存储成本。
**gsutil rm** -r ${BUCKET}
结论
就这样,您已经使用 STAR 在云上对齐了您的第一个 RNAseq 数据!请注意扩展我们的分析是多么容易:对齐 1000 个而不是 2 个样本只是扩展制表符分隔的文件。
当然,比对本身通常是下游分析所需的预处理步骤。在第二部分中,我们将继续我们的云冒险,从我们比对的 RNAseq 中计算基因表达。
如果您有有用的STAR技巧或有趣的云技巧要分享,或者对代码有任何改进,请发表评论。
参考文献
[1]:玛拉基·格里菲斯*、杰森·r·沃克、尼古拉斯·c·斯皮斯、本杰明·j·安斯考、奥比·l·格里菲斯*。2015.RNA-seq 信息学:云上分析的网络资源。公共科学图书馆比较生物学。11(8):e1004393。
[2]: Dobin,Alexander,等. STAR:超快通用 RNA-seq 比对仪。《生物信息学》29.1(2013):15–21。
云上的生物信息学第二部分
原文:https://towardsdatascience.com/bioinformatics-on-the-cloud-part-ii-a99ccfea913a?source=collection_archive---------29-----------------------
理解大数据
在 Google 云平台上使用 HTSeq 计算 RNAseq 表达式

使用 STAR 和 HTSeq-count 的云上的 RNAseq 分析管道。图片作者。
关联
仅在医疗保健领域,估计到 2025 年将有 6000 万患者的基因组编码被测序[1]。测序成本的下降和医学的进步推动了这一增长。重要的是,细胞水平上的信息可以用来帮助指导患者治疗。但是如何分析这些海量数据呢?我们需要的是能够根据问题的规模进行扩展的工具和基础设施。
进入云技术!
范围
本教程将带你通过谷歌云平台上的 RNAseq 计算基因表达(即每个基因的 RNA 物质数量)的步骤。
目标
- 了解什么是基因表达。
- 使用
samtools为下游分析预处理 SAM 文件。 - 用
htseq-count计算基因表达。
背景

图 1:电池装配线的示意图。DNA 指令通过 RNA 转化成蛋白质。图片作者。
细胞的大部分艰苦工作都是由蛋白质完成的。为了构建它们,细胞表达指令,这些指令被编码在被称为基因的 DNA 中的特定区域。细胞在级联过程中合成蛋白质,其中基因的 DNA 首先作为前体信使-RNA 被读出(转录)。这种前体随后被转化为信使 RNA — 或简称为mRNA。最后,细胞在转移 RNA* 的帮助下将*mRNA 翻译成蛋白质。通过分析 RNAseq 数据,我们可以推断出样本中表达了哪种类型的 RNA 物质,以及有多少。因此,RNAseq 数据向我们展示了细胞装配线中途的快照。虽然这些快照不能给出细胞状态的完整图像,但它们无疑是细胞下游发生的实际过程的有用替代物。通过这种方式,RNAseq 可以帮助了解细胞机制的基础,例如,特定的疾病。
就我们的目的而言,重要的是要认识到 DNA 中的指令并没有一对一地映射到最终产品(蛋白质)上。在转录阶段,只有 DNA 的编码区(基因的外显子)被保留下来,在一个称为剪接的过程中形成转录本。去除非编码区(内含子*)后,剩余的外显子可以以各种方式组合。如图 1 所示,单个 DNA 片段因此可以产生组合数量的相关转录物,称为*同种型*。反过来,由于控制蛋白质折叠过程的竞争性偶极相互作用,每个同种型翻译成独特的三维结构。*
概括
在之前的中,我们讨论了如何理解在测序仪上生成的大量小碱基阵列(A、C、T、&、G),称为读数*。我们讨论了如何在一个称为参照基因组比对的过程中把拼图(参照基因组)的碎片(阅读)放在一起。使用 STAR ,我们能够将测序机的原始数据以 FASTQ 格式转换成一组 SAM 文件。本教程将会更进一步。我们将使用 SAM 文件,使用 HTSeq-count [2]计算每个基因产生了多少 RNA,这是一种使用谷歌云平台的可扩展方式。*
基因表达
量化 RNAseq 从计数开始:我们跟踪所有可能的转录物,并计算出现的次数。在其最基本的形式中,这正是基因表达的含义:每个基因的 RNA 计数表。这听起来很简单,但请记住,我们的转录本在测序前就被粉碎成小片段。因此,为了将一段 RNA 分配给一个转录本,我们需要一个转录本目录——一个转录组—* 来选择。与排列好的 RNA 碎片(SAM 格式)一起,htseq-count将汇总数据,建立一个计数表。*
初步步骤
说够了,该编码了!打开谷歌云平台仪表盘,点击右上角的云壳图标(图 2)启动终端。

*图 2:谷歌云平台中的云壳图标。图片作者。*
我们将利用 dsub 在 Google 云平台上分配我们的生物信息学工作量。要安装dsub,请执行:
***sudo pip3** install dsub*
在你的云壳里。

*图 3:在 Google 云平台上的云壳中创建一个存储桶。图片作者。*
接下来,我们将需要一个位置,一个桶*,来在云上存储我们的文件。选择一个唯一的名称,例如gs://rna-seq-tutorial,并创建存储桶(mb):*
***export** BUCKET=gs://rna-seq-tutorial
**export** REFDATA=${BUCKET}/refdata
**export** INPUT=${BUCKET}/input
**gsutil mb** -l europe-west4 ${BUCKET}*
如果你已经成功地完成了之前的教程,在那里我们使用 STAR 对齐了 FASTQ 文件,你应该已经生成了两个文件:sample1.sam和sample2.sam。如果没有,下载并复制样本文件到输入目录:
***wget** -O - [https://tinyurl.com/jnetj2u3](https://tinyurl.com/jnetj2u3) \
| **gsutil cp** - *"${INPUT}/sample1.sam"*
**wget** -O - [https://tinyurl.com/7exr8jsn](https://tinyurl.com/7exr8jsn) \
| **gsutil cp** - *"${INPUT}/sample2.sam"**
我们还需要人类基因组的基因转录本目录(转录组),通常是gff3或gtf格式。如果你愿意,你可以直接从头构建一个转录组——这被称为转录组组装——但为了简单起见,我们将依赖于 Gencode 之前策划的人类基因组注释。
将转录组文件下载到新创建的 bucket 的 refdata 目录中,如下所示:
***wget** -O - [https://tinyurl.com/vteb57e2](https://tinyurl.com/vteb57e2) \
| **zcat** \
| **gsutil cp** - *"${REFDATA}/gencode.v36.chr_patch_hapl_scaff.annotation.gff3"**
最后,启用云生命科学 API 开始使用dsub。
预处理校准文件

图 4:使用samtools的预处理步骤概述。图片作者。
在我们可以通过计算 RNA 转录物来量化基因表达之前,我们需要预处理我们的 SAM 文件。HTSeq-count 要求 SAM 文件按照染色体位置分类,并附带索引文件,以便快速访问特定位置的读数。这两者都可以通过一个叫做 samtools 的小工具来完成。用以下内容创建一个名为step1.sh的文件(见图 4):
*#!/bin/bash
*# a) Sort SAM file on genomic position.*
**samtools** **sort** \
--threads 2 \
--output-fmt BAM \
-o ${BAM} \
${SAM}*# b) Create index of sorted BAM file.*
**samtools** **index** \
-@ 2 \
${BAM} \
${BAI}*
顾名思义,第一个命令对 SAM 文件进行排序,并将其压缩成(更小的)二进制 BAM 格式(--output-fmt BAM)。然后在两个线程上使用samtools index对生成的 BAM 文件进行索引(-@ 2)。注意,在这一点上,Bash 变量${SAM}、${BAM}和${BAI}还没有定义。当我们将工作负载(step1.sh)提交给云时,这些将由dsub提供。为此,首先创建一个制表符分隔的值文件 step1.tsv,包含以下字段
*--input SAM --output BAM --output BAI
<my-bucket>/input/sample1.sam <my-bucket>/output/step1/sample1_sorted.bam <my-bucket>/output/step1/sample1_sorted.bam.bai
<my-bucket>/input/sample2.sam <my-bucket>/output/step1/sample2_sorted.bam <my-bucket>/output/step1/sample2_sorted.bam.bai*
用您的 bucket 位置替换<my-bucket>(在我们的例子中是gs://rna-seq-tutorial),并仔细检查这些值是否由制表符(而不是空格)分隔。正如您可以从标题中推断的那样,这些列指的是脚本中的变量${SAM}、${BAM}和${BAI}。创建这个tsv文件允许我们快速地将我们的计算扩展到任意大小,因为dsub将为step1.tsv文件中的每一行启动单独的工作线程。要启动实际的工作负载,请执行
***dsub** \
--provider google-cls-v2 \
--project <my-project> \
--location europe-west4 \
--zones europe-west4-a \
--preemptible \
--min-ram 8 \
--min-cores 2 \
--logging "${BUCKET}/logging/step1/" \
--image registry.gitlab.com/hylkedonker/rna-seq \
--tasks step1.tsv \
--script step1.sh*
决定你是否要冒着工作终止的风险去寻找更便宜的先占计算(--preemptible),并用你的谷歌云平台项目 ID 替换<my-project>。这将启动两个工作线程(step1.tsv中的每条线一个),具有 8gb 的 RAM ( --min-ram 8)和两个虚拟内核(--min-cores 2)。每个工人运行一个 Docker 映像(--image),其中包含运行step1.sh所需的生物信息学工具。Dsub 自动负责将文件从step1.tsv中的--input SAM列复制到step1.tsv中的--output BAM和--output BAI列。
当我们的工作负载在云上运行时,让我们为下一步做准备。
计算基因表达

图 5:使用 htseq-count 估计 RNA 丰度的概述。图片作者。
计算 RNAseq 听起来似乎很简单。但是要知道,大多数现代测序机器并不能完全测量 RNAseq 片段。相反,他们产生仅测量片段两端的成对末端测序数据。更糟糕的是,如何统计一个跨越多个基因的片段?幸运的是,htseq-count用非常合理的缺省值解决了这些问题。
为此(如图 5 所示),创建一个名为step2.sh的文件,其内容如下:
*#!/bin/bash
# Compute expression
**htseq-count** \
--stranded=reverse \
--order pos \
--format bam \
--additional-attr=gene_name \
--type gene \
-n 2 \
${BAM} \
${GTF} \
-c ${COUNTS}*
这里,我们使用位置排序(--order pos ) BAM 文件(--format bam)和两个内核(-n 2)上的 Gencode 基因注释,运行htseq-count来合计每个基因的计数(--type gene)。需要注意的一个重要方面是,在样品制备过程中是否使用了链识别文库,该文库可以在处理过程中保留 RNA 的链。(如果您不确定, RSeQC 的infer_experiment.py工具可以帮助您识别样品的滞留情况。)在我们的例子中,我们的数据是使用 TruSeq,一个链特定的库[3]生成的,因此我们使用--stranded=reverse标志。类似于我们的预处理计算作业,我们创建一个制表符分隔的文件step2.tsv,它列出了输入 BAM +索引文件和相应的计数文件(以tsv格式),每个样本一行:
*--input BAM --input BAI --output COUNTS
gs://<my-bucket>/output/step1/sample1_sorted.bam gs://<my-bucket>/output/step1/sample1_sorted.bam.bai gs://<my-bucket>/output/step2/sample1.tsv
gs://<my-bucket>/output/step1/sample2_sorted.bam gs://<my-bucket>/output/step1/sample2_sorted.bam.bai gs://<my-bucket>/output/step2/sample2.tsv*
不要忘记用您的存储位置替换<my-bucket>,并仔细检查您是否正确地复制了制表符(而不是空格)。在提交下一个工作负载之前,让我们通过查询它的状态来检查上一个作业是否成功完成
***dstat** \
--provider google-cls-v2 \
--project <my-project> \
--location europe-west4 \
--status '*'*
如果一切正常,我们准备提交下一个工作负载。
***dsub** \
--provider google-cls-v2 \
--project <my-project> \
--location europe-west4 \
--zones europe-west4-a \
--preemptible \
--min-ram 8 \
--min-cores 2 \
--logging "${BUCKET}/logging/step2/" \
--input GTF=${REFDATA}/gencode.v36.chr_patch_hapl_scaff.annotation.gff3 \
--image registry.gitlab.com/hylkedonker/rna-seq \
--tasks step2.tsv \
--script step2.sh*
与前面的提交命令唯一的细微差别是我们直接向dsub而不是tsv文件提供了--input GTF标志,因为它对于每个工作负载都是相同的。
成功完成工作量后(使用dstat查询状态),您应该有一个每个样本的计数表(sample<i>.tsv)。您可以通过执行以下命令轻松验证这一点
***gsutil ls** "${BUCKET}/output/step2/"*
显示每个相应样本的tsv文件。(如果没有,您可能想看看日志gsutil ls "${BUCKET}/logging/step2/看看哪里出错了。).
瞧,您刚刚量化了样品的基因表达!
讨论
基因表达计数
在总结之前,我们应该提到,如果您想要比较单个样本,您的计数需要一个额外的标准化步骤。在每次实验运行中,测序仪将给出不同总数的读数*。此外,因为 RNA 转录物在测序前被粉碎成片段,较长的转录物将产生更多的片段。因此,适当选择的变换有助于协调样本的表达估计。幸运的是,大多数下游分析包,如修边机、 limma 和 DeSeq2 会为您完成这项工作,事实上,需要计数数据作为输入。*
Dsub和朋友
在本教程中,我们转向dsub将我们的计算分派给虚拟工作者*。Dsub 非常适合在云上开始,尤其是当您想要做一次或几次特定的分析时。但它绝不是唯一的工具,尤其是如果你想以可重复、容错的方式一遍又一遍地运行相同的工具序列——所谓的工作流。 Snakemake 和 Nextflow 是帮助您在云上运行生产工作流的工具的很好例子。然而,如果你喜欢工具不可知的方法,你可以考虑通用工作流语言 (CWL),它是一个以 YAML 格式表达工作流的开放标准。*
结束语
就这样,您已经成功地使用 HTSeq 计算了云上的基因表达!注意扩展我们的分析是多么容易:预处理和计数 1000 个样本的 RNAseq 而不是 2 个样本,只需扩展制表符分隔的文件。
如果你有有用的htseq-count技巧或有趣的云技巧要分享,或者对代码有任何改进,请发表评论。
参考文献:
本教程是主要与 Bram van Es 合作的副产品,我们试图揭示免疫疗法(一种用于抗癌的药物)背后的生物模式。
为什么生物学和代码是天作之合
利用 Python 寻找大肠杆菌基因组的 ori 区域

来自的图标 8 的插图哎哟!
你知道吗,在美国几乎一半的婚姻都以离婚告终。生物学和代码的结合不是那种婚姻,在本文结束时我会向你证明这一点。
在早期的文章中,我在霍乱弧菌的 ori 区域寻找 DnaA 盒。但是如果我们不知道 ori 在基因组中的位置呢?
秘密在于将生物知识转化为基于代码的解决方案。
(This article assumes you have a comfortable grasp on Python and DNA replication.)
"我们来谈谈 DNA 复制吧,小蜜蜂!"—佩帕盐沼,1990 年。
细菌不对称地复制它们的基因组。
- 一半被连续复制: DNA 聚合酶把核苷酸串在一起,没有任何间断。
- **另一半不连续复制:**合成了许多 DNA 的短片段,然后缝合在一起,形成一条连续的链。
更多信息 此处 。
细菌染色体是圆形的,DNA 复制从或区域开始,因此我们可以将染色体分成 4 个半链:
- 反向半股:正向半股的连续合成模板,从 ori 开始,往 3’到 5’方向走。
- 正向半股:反向半股的不连续合成模板,从 ori 开始,往 5’到 3’方向走。

复制从复制泡的两侧进行,并终止于与 ori 区相对的 ter 区。|作者。
在视频中,你有没有注意到前面的半股通常是单股的?这增加了 C 脱氨基(突变)成 T 的机会。
我们可以从这些知识中得出三个结论:
- 脱氨作用在进化史中反复发生,因此正向半链通常含有较少的胞嘧啶。
- 当反向半链在突变的正向半链模板上合成时,DNA 聚合酶将收集 A (与 T 配对)而不是 G (与 C 配对)。反向半链往往会有较少的鸟嘌呤。
最重要的是…
- 沿着基因组的 5’到 3’方向,反向半链在或区域与正向半链相遇。
“我是歪斜的哒-巴-迪-哒-巴-哒”——埃菲尔 65,1998。
让我们称 Gs 和 Cs 的数量之差为“偏斜”:
skew = #G - #C
- 在前半股上,#G > #C
- 在反向半链上,每个窗口中的# G< #C
If we window across the genome and see that skew is rising, we’re finding Cs 更少—我们在正向半链上。偏斜正在减少?更少的 g——我们在反向半链上。
代码
由于 ori 是在反向半股与正向半股相遇的地方发现的,所以我们可以通过观察偏斜何时从减小切换到增大来发现 ori 。也就是最小偏斜。

作者使用 ray.so
取一个字符串Genome作为参数。我们首先创建一个列表Skew,其中第 0 个索引值为 0。Skew中的每个元素都是基因组中该点的#G — #C的连续计数。在第 0 个核苷酸处(第一个核苷酸之前),Skew = 0。
接下来,我们搜索整个基因组,并将Genome中的第 i 个字符与“G”或“C”进行比较:
- 如果是前者,我们对偏斜的运行计数加 1,并将其添加到列表
Skew。 - 如果是后者,我们-1 和做同样的事情。
- 如果都不是,偏斜保持不变。
下面是它如何发挥作用的示意图:

按作者
这个函数的另一个版本(归功于 Cristian Alejandro Fazio Belan)更加直观:

作者使用雷.索
这里,我们更新运行总数score并将该值追加到列表中。
我们可以把这个列表画出来:

按作者
我们通过编写一个快速函数来返回偏斜最小的所有值,从而找到偏斜最小的点:

由作者使用 ray.so
>>> positions = MinimumSkew(Genome)
>>> print(positions)[3923620, 3923621, 3923622, 3923623]**Alternatively, you can simply do the following:**>>> skew = SkewArray(Genome)
>>> print(skew.index(min(skew)))3923620
对于大肠杆菌,似乎或在第 3923620 个核苷酸附近。
所以我们知道 ori 在哪里。也许吧。我们如何证实这一点?
在早期的文章中,我们发现了如何在基因组序列中找到 DnaA 盒。它们通常是 9 个碱基的序列(9 聚体),DnaA 蛋白与之结合以启动 DNA 复制。
如果我们在已经找到的点(平均长度为或)切割 500 个碱基,并应用上一篇文章中的 FrequencyMap 和 FrequentWords *函数…
>>>for i in range(3,10):
print(i, ":", FrequentWords(Text, i))3 : ['GAT']
4 : ['GATC']
5 : ['GGATC']
6 : ['AGGATC']
7 : ['AAGGATC']
8 : ['AAAGGATC', 'AAGGATCC', 'AGGATCCG', 'GGATCCGG', 'CTGGGATC', 'GATCCTGG', 'GATCGCAC', 'TGGATAAC']
9 : ['AAGGATCCG', 'AGGATCCGG']
…我们找不到任何出现 3 次以上的 9 聚体/反向互补体。
*(FrequencyMap scans across a sequence and creates a dictionary that contains all possible k-mers in that sequence as keys, and the number of times they occur as values. FrequentWords returns the most frequents k-mers)
生物知识再一次拯救了我们。 DnaA 蛋白质也可以结合到大致相同的 DnaA 盒上。
两个有少量错配的 9 聚体仍能结合 DnaA。
不匹配的次数可以称为汉明距离。让我们写一个找到这个的函数:

作者使用雷.索
将两个字符串p和q作为参数,并遍历两者的每个字符。如果不相等,增加count。
我们可以从频数图中提取 9 聚体,并将其用作更新的模式计数函数的输入:

由作者使用 ray.so
这里,Pattern是我们的任何一个 9 聚体,Text是我们在 ori 取的 500 碱基切片,d是我们能容忍的最大错配数。
我们在假设的或区域范围内,将window与Pattern进行比较,T7 是我们通过频率图找到的任何一个 9 聚体/它们的反向互补体。如果它们有 1 个或更少的不匹配,我们增加计数。

这个函数不是非常高效,但是可以完成工作。|作者使用 ray.so |注意:ReverseComplement 函数的代码可以在这里找到。
这样做,我们就找到了TTATCCACA。它和它的反向互补TGTGGATAA 就是实验确定的大肠杆菌的 DnaA 盒!
但如你所见,他们不是唯一的。其他九聚体同样频繁出现。那么,为什么这很重要呢?重点是什么?
通过收集一些可能的九聚体及其在基因组上的位置,我们可以给实验者指明方向,并帮助他们节省实验室时间。
代码清理干草,这样生物学家可以更快地找到针。
生物学和计算机科学的结合是不寻常的,因为它通常是成功的结合。
哈!找到了。
理解生物学有助于我们做出高效有用的算法。
使用生物数据代码有助于生物学家完善他们的实验。
如果你能驾驭生物和 CS 的联姻,你就拥有超能力。你可以积累特定的知识,很可能变得非常富有。最重要的是,你可以做重要的工作来帮助人们。
感谢阅读!这篇文章是基于我在 Coursera 上参加的 初学者生物信息学 课程的一课。
简化的生物识别
原文:https://towardsdatascience.com/biometrics-simplified-e9ed096d0025?source=collection_archive---------31-----------------------
计算机科学
关于生物识别的深入而简单的解释

图片由 ar130405 在 Pixabay 上拍摄
T 传统的信任概念和对我们交往对象身份的信念有时远不如我们过去认为理所当然的那样值得信任。我们生活在一个越来越相互关联的世界,个人之间的联系越来越多地通过一些新的电子媒介进行。随着我们的生活方式和社会发展,我们一致认为,对更好、更灵活的方式来维持日常交易中的保护、安全和信心的需求最终会增加。如果我们越来越依赖自动通信,那么处理越来越多的不同系统的复杂性就会增加。例如,我们是应该尝试为我们使用的每个系统回忆一个新密码,还是应该在所有系统之间共享密码,以最大限度地减少记忆丢失的可能性以及由此带来的不便?这些问题,以及日常生活的许多其他方面,都有一个共同点:它们都以某种方式对人类身份提出了关切。我们如何证明我们是我们所说的人?我们如何确定另一个人就是他们所说的那个人?
生物测定学
生物统计学可以被描述为一门科学学科,涉及计算和应用一个人的特性或特征,这些特性或特征可以用来唯一地识别那个人。生物统计学假设人类的许多物理或行为属性可以与个体唯一相关联。通过使用正确制作的传感器记录这些特征,以数字格式表示它们,并且将该捕获的数据与在先前时间情况下从同一个人获得的数据进行比较,可以使个人识别过程自动化。因此,生物特征识别或验证可以被认为是一个模式识别问题,其中计算机识别个人生物特征的重要特征(模式)并准确匹配它们。理论上,任何人类特征或特性都可以用作生物特征数据源,只要它满足以下要求:
通用性:所选择的特性应该是所有人都具备的。这是因为生物识别设备将是包容性的,允许尽可能多的用户使用它。
独特性:就所选择的特征而言,任何人类都不可能相似。因为我们应该量化区分一个人和另一个人的特征,如果我们想识别他们的话。
持久性:选择的特征必须是时不变的。至关重要的是,我们选择的任何特征都是经过一致计算的,否则,一个人在不同的时间可能会表现为不同的人。
可测量性:选择的特性应该是科学上可定量测量的。它应该被很好地指定,以消除在被测量的东西上的所有模糊性。
生物识别技术分为两大类,即基于物理的生物识别和基于行为的生物识别。
生理生物特征是对一个人内在生理特征的测量。指纹是生理生物特征形态的一个明显的例子。这实际上是一个人的基本生理组成的一部分,虽然它可以在一定程度上改变,例如,通过创伤或伤害,它通常不是人可以直接控制的。
在行为生物测定学中,测量值来自一个人执行的随机或故意学习的行为。这里最明显的例子是我们使用手写签名作为生物特征数据的来源。与自然存在且始终存在的基于身体的生物识别不同,签名仅在一个人书写时存在。因此,行为生物测定学可以定义为:“获取要求受试者主动的生物测定样本。它们必须在有传感器的情况下执行特定的活动。行为特征是随着时间的推移而习得的,而不是基于生物学
常用的生物特征
没有任何一种生物识别技术能够有效地满足前面提到的所有标准。换句话说,没有一种生物识别技术是完美的,但是有多种生物识别技术是合适的。特定生物特征的适用性由应用的目的和条件以及生物特征的特性决定。下面是一些最广泛使用的生物特征的简要概述。
指纹已经被人类用于个人身份识别几十年了。指纹的形成是在胎儿发育的前七个月内确定的,此时指尖表面上的脊和谷已经形成。
人的掌纹就像指纹一样,包含着脊和谷的图案。手掌的面积比手指的面积大得多,这意味着它比手指有更多的图案。因此,掌纹被认为比指纹更独特。
虹膜是眼睛的环形区域,由瞳孔和两侧的巩膜界定。虹膜的视觉纹理在胎儿发育期间形成,并在生命的头两年稳定下来。虹膜的颜色因人而异,但在颜色上有一些一致性,包括绿色、蓝色、棕色,在极少数情况下,甚至是淡褐色。虹膜的主要目的是调节瞳孔的直径和大小。瞳孔是眼睛的一部分,它使光线能够穿透眼睛,然后向后部传播到视网膜。当然,能够到达瞳孔的光量是其扩张和收缩能力的直接结果,这是由虹膜肌肉调节的。当近红外光(NIR)照射到虹膜上时,可以观察到许多独特的特征。
视网膜脉管系统具有复杂的结构,对每个人和每只眼睛来说都是独一无二的。它被认为是最稳定的生物测定学,因为视网膜的生物学基础在人的一生中几乎不会改变。为了显现视网膜脉管系统的预定部分,人必须看着目镜并聚焦在视野中的某个点上。图像采集过程需要主体的合作,目镜的接触,以及使用者的刻意努力。这些考虑因素中的许多都有助于视网膜生物特征的公众接受。视网膜的脉管系统将暴露任何医疗信息,例如高血压,这是阻碍公众接受基于视网膜扫描的生物识别的另一个因素。此外,公众认为视网膜扫描是一种健康威胁,一些人认为视网膜扫描损害眼睛。
面部检测是一种非侵入式技术,面部表情是人类用来相互识别的最常见的生物特征。我们可以通过看一个人的脸来识别他。面部识别存在一些技术上的不足。例如,如果面部识别设备捕获一个严重超重的人的图像,然后捕获同一个人的另一个已经减掉大量体重的图像,则系统将无法再识别该人。
手的几何形状识别系统使用取自人手的各种尺寸,例如其形状、手掌周长以及手指长度和宽度。手的几何形状不被认为是特别独特的,并且基于手的几何形状的识别系统不能被放大用于涉及来自大量人群的人类识别的系统。
步态指人行走的方式,是为数不多的可用于远距离识别人的生物特征之一。这一特征非常适合于可以秘密确定身份的监控场景。步态的缺点是受各种因素的影响,包括靴子、衣服、腿疼和行走表面。
耳朵作为一种生物特征包含了大量特定而独特的特征。据说耳廓软骨组织的结构是独特的。耳朵识别方法依赖于匹配耳廓上的显著点和耳朵上的界标点之间的距离,或者耳朵的存在。耳朵识别可以帮助根据个人资料图片识别一个人。
声音是物理和行为生物特征的结合。声音合成中使用的附件(如声道、颌骨、鼻腔和嘴唇)的形式和大小决定了一个人言语的物理特征。人类言语的这些生理特征对一个人来说是不变的,但是言语的心理因素随着年龄、医疗条件、情感状态和其他因素而变化。语音特征很容易受到背景噪声和麦克风功能等因素的影响,这是基于语音的识别的一个缺点。然而,它在基于电话的系统中仍然有用,但是语音信号质量通常被通信信道降级。
按键。假设每个人都在键盘上以独特的方式打字。这种生物识别不太可能对每个人都是唯一的,但它可以提供足够的歧视性信息,以便进行身份验证。击键动力学是一种行为生物统计学。由于情绪状态、用户相对于键盘的位置、使用的键盘样式等的变化,可以预期一个人的打字习惯会出现显著的班内差异。当一个人键入细节时,他们的击键可以被不可见地跟踪。击键的缺点是打字模式可能不稳定和不一致,就像抽筋的肌肉和出汗的手会显著改变一个人的打字模式一样
签名。一个人签名的方式被认为是这个人的一个显著特征。虽然签名需要作者与书写工具进行交互并付出努力,但它们已被用作官方、民事和商业交易中的一种身份识别手段。签名是一种随时间变化的行为生物特征,受签名者身体和情绪状态的影响。有些人的签名彼此差异很大;甚至对他们签名的连续印象也明显不同。此外,职业伪造者可能能够模仿欺骗签名认证系统的签名。
DNA 指的是脱氧核糖核酸,其中含有生物体发育和功能所必需的遗传信息。除了同卵双胞胎,他们有相同的 DNA 模式,DNA 是一个人唯一性的一维特殊代码。然而,它目前主要用于犯罪和受害者发现的法医系统。最复杂的 DNA 匹配技术需要耗时的化学方法,这需要专家的专业知识,而且还不适合在线非侵入式识别。
矿脉红外热像图。人体发出的热量模式对每个人来说都是独一无二的,可以通过红外相机以非侵入的方式捕捉,类似于正常的照片。虽然基于温谱图的设备不需要触摸并且是非侵入性的,但是在人体附近具有发热表面的未调节条件下,图像采集可能是困难的。
气味。众所周知,每个物体都会发出一种独特的化学成分气味,这种气味可以用来区分物体。各种各样的化学传感器被吹到一个物体周围的空气中,每个传感器都对一组特定的(芳香)化合物敏感。人(或任何动物)身体产生的一部分气味是这种生物所独有的。尽管使用了除臭剂以及周围环境中变化的化学成分,是否可以检测到体味的变化还不清楚。
生物识别的工作原理
实际上,生物识别技术有两种最常见的用途:验证和识别。总的来说,生物特征验证和身份识别包括两个阶段。注册和认可。
注册是在特定系统中注册或登记您的生物特征的阶段。每个人的生物特征数据都被收集并存储在一个数据库中,与该人的身份放在一起。通常,生物特征数据被分析以获得显著的和有区别的特征。导出的特征(机器学习术语中提取的特征)通常被保留,而原始的生物特征数据被丢弃。目前,使用卷积神经网络来处理特征提取问题是非常普遍的。
识别(识别和验证)是一个阶段,在此阶段,重新从个人处获取生物特征数据,并与存储的数据进行比较,以确定用户的身份。因此,生物识别系统基本上是一个模式识别系统。

身份证明。作者图片
说你们公司有 50 名员工,想做一个基于生物识别的考勤系统。标识意味着系统需要识别给定的生物特征属于谁。它使用阈值来决定是识别给定的生物特征还是拒绝它。如果给定的生物测定身份与所识别的生物测定相匹配,则该识别是正确的。

验证。作者图片
另一方面,验证(也称为认证)只针对一个人。比如你用指纹锁手机,这样除了你没人能用你的手机。验证只是验证给定的生物特征是否与您的匹配。它使用阈值来决定认证,如果相似度大于阈值,则接受认证,否则拒绝认证。如果属于系统的给定生物特征(真实的)被接受,而冒名顶替者被拒绝,则验证是正确的。
生物识别指标
那么我们怎么知道一个生物识别系统好不好呢?生物识别系统准确性的基本衡量标准是错误不匹配率 (FNMR)和错误匹配率 (FMR)。
FNMR 是指来自同一用户的两个生物特征样本被错误识别为不匹配的概率。例如,10%的 FNMR 表示 100 次正版用户验证尝试中有 10 次会被拒绝。
另一方面,FMR 指的是来自不同用户的两个生物特征样本被错误地识别为匹配的概率。例如,10%的 FMR 表示冒名顶替者用户的 100 次验证尝试中有 10 次会被接受。
在验证的上下文中,FNMR 和 FMR 也分别被称为误拒绝率(FRR) 和误接受率(FAR) 。 FRR 是衡量系统拒绝真实用户的频率,而 FAR 是衡量系统接受冒名顶替用户的频率。FRR 由 FRR 给出=总错误拒绝/总正确尝试。FAR 由给出,FAR =总错误接受/总错误尝试。由于验证是基于我们之前提到的阈值,因此不可能同时最小化 FRR 和 FAR。增加阈值将导致 FAR 降低,但 FRR 增加,反之亦然。作为替代,可以使用由TAR = 1-FRR 给出的真实接受率(TAR) 。
在识别的情况下,生物特征识别系统在登记了 N 个用户身份的情况下,输出与前 t 个匹配(1 ≤ t < N)相对应的一组身份。识别等级被定义为用户的正确身份在由识别系统返回的前 t 匹配中的等级。识别系统中的误差可分为两类假阳性识别率和假阴性识别率。
误报识别率(FPIR) 衡量系统返回未注册用户身份的频率。
假阴性识别率(FNIR) 是对系统返回已在系统中注册但其身份不在识别等级中的用户的身份的频率的度量。
与 FNIR 相关的一个量是真实的肯定识别率****【TPIR】,它是对系统多久返回一个用户身份的度量,该用户在系统中注册并且他的身份在识别等级中。因此, *FNIR = 1 — TPIR。*如果身份识别系统只返回最顶端的身份( t = 1),在 TPIR 它被称为一级准确度,这个度量是比较不同生物特征识别系统最常用的度量之一。
生物识别的优势
- 很难伪造
- 使用方便
- 不可转让的
- 不太可能改变
- 不需要记忆
生物识别的缺点
- 昂贵的
- 存储生物特征数据的数据库仍然可能被黑客攻击
- 错误识别或验证仍然可能发生
- 无法识别受伤的生物特征
结论
生物统计学可以被描述为一门计算和应用一个人的特征的科学,这些特征可以用来唯一地识别这个人。生物统计学假设人类的许多物理或行为属性可以与一个人唯一相关联。因此,可以通过使用正确制作的传感器记录这些特征,以数字格式表示这些特征,并将捕获的数据与以前同一个人的数据进行比较,从而实现人员识别过程的自动化。这样,我们就不需要再记住很多密码了。
参考
一只接一只地使用深度学习
原文:https://towardsdatascience.com/bird-by-bird-using-deep-learning-4c0fa81365d7?source=collection_archive---------7-----------------------
第一部分。利用迁移学习、辅助任务和注意提出用于细粒度分类的 CNN 模型

作者图片
本文展示了如何改进用于图像相关任务的深度学习模型,以解决细粒度分类问题。为此,我们将完成以下两个部分。首先,您将熟悉计算机视觉和卷积神经网络的一些基本概念,而第二部分将演示如何使用 PyTorch 将这些知识应用于鸟类分类的实际问题。具体来说,您将学习如何构建自己的 CNN 模型-ResNet-50,以使用迁移学习、辅助任务和注意力增强架构,甚至更多来进一步提高其性能。
介绍相关工作
深度学习在计算机视觉中的应用
在处理数字时,计算机的表现非常出色。为了让人类登上月球而解无数方程?没问题。确定图像中出现的是猫还是狗?哎呀……这个对任何人来说天生容易的任务对第一台计算机来说似乎是不可能的。这些年来,算法和硬件一样进化(还记得摩尔定律吗?国际注册会计师协会)。计算机视觉领域的出现是对使用计算机解决图像分类任务的一种尝试。经过长时间的发展,许多复杂的方法被创造出来。然而,它们都缺乏可推广性:一个用来分类猫和狗的模型不能区分,例如,鸟。
卷积神经网络的设计原则
1989 年,Yann LeCun 和他的同事们已经提出了【1】,并进一步发展了【2】卷积神经网络(CNN)的概念。该模型本身受到人类视觉皮层的启发,在视觉皮层中,视觉神经元负责肉眼可见的一小部分图像——神经元的感受野。在结构上,它以单个卷积神经元(滤波器)逐步扫描输入图像的方式表达,多次应用于图像的不同部分,这涉及到权重共享的概念(图 1)。

图一。LeCun 的 LeNet-5,卷积神经网络模型,由卷积和子采样操作组成,后面是全连接层,处理前几层提取的数据以形成最终输出(改编自[2])
走向剩余网络
当然,从 LeCun 的 LeNet-5,开始,CNN 模型的最新水平已经有了很大的发展。Alex net【3】第一个成功的大规模架构问世,赢得了 ILSVRC 2012 挑战赛,实现了 15.3%的前 5 名错误率。后来的发展给出了许多强大的模型,这些模型主要是在更大和更复杂的架构的使用过程中得到改进的。问题是,随着网络越来越深(深度在增加),它的性能变得饱和并开始下降。为了解决这个问题,残差神经网络(ResNet)被开发出来【4】,以有效地将输入引导到某些层(也称为跳过或残差连接)。

图二。跳过 ResNets 的连接块
ResNet 架构的核心思想是将一部分信号传递到未经处理的卷积块的末端(仅通过复制值),以扩大通过深层的梯度流(图 2)。因此,跳过连接保证了模型的性能不会降低,但可能会略有提高。
下一部分解释了讨论的理论如何实际应用于解决现实世界的问题。
利用 ResNet 进行鸟类分类
鸟类物种识别是一项挑战人类专家和计算机视觉能力的艰巨任务。与细粒度分类问题相关的一个有趣的数据集是 Caltech-UCSD Birds-200-2011(CUB-200-2011)【5】由属于 200 个物种的 11788 幅鸟类图像组成。为了解决这个问题,本教程的目标将是:(a)建立一个 CNN 模型,根据鸟类的种类对鸟类图像进行分类;(b)确定如何使用不同结构的 CNN 提高基线模型的预测精度。为此,我们将使用 PyTorch,这是最流行的深度学习开源框架之一。
本教程结束时,您将能够:
- 了解鸟类图像分类问题的基本知识。
- 确定数据驱动的图像预处理策略。
- 为图像分类创建自己的深度学习管道。
- 建立、训练和评估 ResNet-50 模型以预测鸟类。
- 通过使用不同的技术来提高模型性能。
首先,您需要下载包含数据集的归档文件,并将其存储到 data 目录中。可以通过下面的链接手动完成,或者使用下面的 GitHub 库中提供的 Python 代码:
https://github.com/slipnitskaya/caltech-birds-advanced-classification
现在,让我们导入将在本教程中使用的包:
# import packages
import os
import csvimport numpy as np
import sklearn.model_selection as skmsimport torch
import torch.utils.data as td
import torch.nn.functional as Fimport torchvision as tv
import torchvision.transforms.functional as TF# define constants
DEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'
RANDOM_SEED = 42IN_DIR_DATA = 'data/CUB_200_2011'
IN_DIR_IMG = os.path.join(IN_DIR_DATA, 'images')
发现最佳数据转换策略
在本教程中,我们计划使用 ImageNet 数据集预先训练一个基线模型。由于预先训练的模型通常希望输入图像以同样的方式进行规范化,因此高度和宽度至少应为 224 x 224 像素。可能有许多图像变换的方法可以用来满足上述规范,但什么可能是最佳的呢?
探索性数据分析是任何数据科学项目的基本起点,为进一步分析奠定基础。因为我们对定义最佳数据转换策略感兴趣,所以我们将研究鸟类图像,看看我们能抓住什么有用的东西。让我们来看看麻雀家族的一些鸟类例子(图 3)。似乎不同种类的鸟类之间有很高的相似性,这很难发现。那是白喉雀还是林肯雀?嗯,即使是专家也会感到困惑…

图 3。难以区分的同科鸟类:白喉麻雀 vs .林肯麻雀(CUB-2002011),vs .杰克斯派洛船长(公共领域)
出于兴趣,我们将总结 Sparrow 家族的所有类,以了解我们的数据集中有多少类:
# calculate the number of sparrow species
cls_sparrows = [k for k in os.listdir(IN_DIR_IMG) if 'sparrow' in k.lower()]
print(len(cls_sparrows))
上面的代码给我们的值是 21,这意味着一个家族只能代表十几个不同的物种。现在我们看到了为什么 CUB-200-2011 是为细粒度分类而完美设计的。我们所拥有的是许多相似的鸟类,它们可能与不同的种类有关,实际上,我们计划在这里处理这个问题。
但是在进入真正的深度学习之前,我们想确定一个合适的数据预处理策略。为此,我们将通过可视化相应观察值的箱线图来分析宽度和高度的边际分布:

图 4。鸟类图像大小的可变分布。方框反映了图像大小分布(宽度和高度)的四分位范围,方框内的中间四分位线标记了数据的中点,触须分别代表 Q1 和 Q3 的较大和较小观察值,外侧点表示位于总体分布之外的数据
事实上,图像的大小变化很大。我们还看到大多数图像的高度和宽度分别等于 375 和 500 像素。那么,对于这种数据,什么是合适的转换策略呢?
转换图像和分割数据
CUB-200-2011 数据集包含数千幅图像,因此可能会影响计算时间。为了克服这个问题,我们首先创建类DatasetBirds来简化数据加载和预处理:
class DatasetBirds(tv.datasets.ImageFolder):
"""
Wrapper for the CUB-200-2011 dataset.
Method DatasetBirds.__getitem__() returns tuple of image and its corresponding label.
"""
def __init__(self,
root,
transform=None,
target_transform=None,
loader=tv.datasets.folder.default_loader,
is_valid_file=None,
train=True,
bboxes=False): img_root = os.path.join(root, 'images') super(DatasetBirds, self).__init__(
root=img_root,
transform=None,
target_transform=None,
loader=loader,
is_valid_file=is_valid_file,
) self.transform_ = transform
self.target_transform_ = target_transform
self.train = train
# obtain sample ids filtered by split
path_to_splits = os.path.join(root, 'train_test_split.txt')
indices_to_use = list()
with open(path_to_splits, 'r') as in_file:
for line in in_file:
idx, use_train = line.strip('\n').split(' ', 2)
if bool(int(use_train)) == self.train:
indices_to_use.append(int(idx)) # obtain filenames of images
path_to_index = os.path.join(root, 'images.txt')
filenames_to_use = set()
with open(path_to_index, 'r') as in_file:
for line in in_file:
idx, fn = line.strip('\n').split(' ', 2)
if int(idx) in indices_to_use:
filenames_to_use.add(fn) img_paths_cut = {'/'.join(img_path.rsplit('/', 2)[-2:]): idx for idx, (img_path, lb) in enumerate(self.imgs)}
imgs_to_use = [self.imgs[img_paths_cut[fn]] for fn in filenames_to_use] _, targets_to_use = list(zip(*imgs_to_use)) self.imgs = self.samples = imgs_to_use
self.targets = targets_to_use if bboxes:
# get coordinates of a bounding box
path_to_bboxes = os.path.join(root, 'bounding_boxes.txt')
bounding_boxes = list()
with open(path_to_bboxes, 'r') as in_file:
for line in in_file:
idx, x, y, w, h = map(lambda x: float(x), line.strip('\n').split(' '))
if int(idx) in indices_to_use:
bounding_boxes.append((x, y, w, h)) self.bboxes = bounding_boxes
else:
self.bboxes = None def __getitem__(self, index):
# generate one sample
sample, target = super(DatasetBirds, self).__getitem__(index) if self.bboxes is not None:
# squeeze coordinates of the bounding box to range [0, 1]
width, height = sample.width, sample.height
x, y, w, h = self.bboxes[index] scale_resize = 500 / width
scale_resize_crop = scale_resize * (375 / 500) x_rel = scale_resize_crop * x / 375
y_rel = scale_resize_crop * y / 375
w_rel = scale_resize_crop * w / 375
h_rel = scale_resize_crop * h / 375 target = torch.tensor([target, x_rel, y_rel, w_rel, h_rel]) if self.transform_ is not None:
sample = self.transform_(sample)
if self.target_transform_ is not None:
target = self.target_transform_(target) return sample, target
所有预训练的模型都期望输入图像以相同的方式归一化,例如高度和宽度至少为 224 像素。正如您从我们之前的分析中注意到的,数据的大小变化很大,许多图像具有横向布局而不是纵向布局,宽度通常接近两个维度的最大值。
为了提高模型学习鸟类表示的能力,我们将使用数据增强。我们希望以这样的方式转换图像,所以我们保持纵横比。一种解决方案是统一缩放图像,以便使用最大填充策略使两个维度都等于较大的一侧。为此,我们将创建一个填充函数来填充图像到 500 像素:
def pad(img, size_max=500):
"""
Pads images to the specified size (height x width).
"""
pad_height = max(0, size_max - img.height)
pad_width = max(0, size_max - img.width)
pad_top = pad_height // 2
pad_bottom = pad_height - pad_top
pad_left = pad_width // 2
pad_right = pad_width - pad_left
return TF.pad(
img,
(pad_left, pad_top, pad_right, pad_bottom),
fill=tuple(map(lambda x: int(round(x * 256)), (0.485, 0.456, 0.406))))
假设鸟类出现在任何图像部分,我们通过在模型训练期间沿两个轴随机裁剪和翻转图像,使模型能够在任何地方捕捉它们。虽然在输入 ResNet-50 之前,测试分割的图像将被中心裁剪,但我们预计大多数鸟类将位于该图像部分,参考之前的数据探索。
为此,我们将沿着两个维度裁剪 375 x 375 像素的图像,因为这是大多数图像的平均大小。我们还将通过均值[0.485,0.456,0.406]和标准差[0.229,0.224,0.225]来归一化图像,以使像素值的分布更接近高斯分布。
# transform images
transforms_train = tv.transforms.Compose([
tv.transforms.Lambda(pad),
tv.transforms.RandomOrder([
tv.transforms.RandomCrop((375, 375)),
tv.transforms.RandomHorizontalFlip(),
tv.transforms.RandomVerticalFlip()
]),
tv.transforms.ToTensor(),
tv.transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
transforms_eval = tv.transforms.Compose([
tv.transforms.Lambda(pad),
tv.transforms.CenterCrop((375, 375)),
tv.transforms.ToTensor(),
tv.transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
然后,我们将 CUB-200-2011 数据集的图像组织成三个子集,以确保正确的模型训练和评估。由于数据集的作者建议集合训练和测试子集的方式,我们相应地分割我们的数据。此外,将定义验证分割,以便在模型评估过程中进一步微调模型参数。为此,训练子集将使用分层采样技术进行分割,以确保每个子集具有相同平衡的不同物种类别。
# instantiate dataset objects according to the pre-defined splits
ds_train = DatasetBirds(IN_DIR_DATA, transform=transforms_train, train=True)
ds_val = DatasetBirds(IN_DIR_DATA, transform=transforms_eval, train=True)
ds_test = DatasetBirds(IN_DIR_DATA, transform=transforms_eval, train=False)splits = skms.StratifiedShuffleSplit(n_splits=1, test_size=0.1, random_state=RANDOM_SEED)
idx_train, idx_val = next(splits.split(np.zeros(len(ds_train)), ds_train.targets))
我们将为数据加载和模型训练设置参数。为了利用计算并能够并行处理大型数据集,我们将在几个小批量中整理输入样本,并指出使用多少子过程来生成它们,以便利用训练过程。
# set hyper-parameters
params = {'batch_size': 24, 'num_workers': 8}
num_epochs = 100
num_classes = 200
之后,我们将创建一个DataLoader对象来产生每个数据分割的样本:
# instantiate data loaders
train_loader = td.DataLoader(
dataset=ds_train,
sampler=td.SubsetRandomSampler(idx_train),
**params
)
val_loader = td.DataLoader(
dataset=ds_val,
sampler=td.SubsetRandomSampler(idx_val),
**params
)
test_loader = td.DataLoader(dataset=ds_test, **params)
构建基线 ResNet-50 分类器
我们将使用 ResNet-50 模型对鸟类进行分类。ResNet(或残差网络)是卷积神经网络的一种变体,由提出作为大型网络的消失梯度问题的解决方案。
PyTorch 在torchvision.models上提供了 ResNet-50 模型,因此我们将实例化相应的类,并将参数 num_classes 设置为 200,给定该数量的鸟类的数据集:
# instantiate the model
model = tv.models.resnet50(num_classes=num_classes).to(DEVICE)
更具体地说,所选择的体系结构有 50 层深,由 5 个阶段组成,其中 4 个阶段具有残差块,1 个阶段包括卷积、批量归一化和 ReLU 操作。
训练和评估模型
下一点是设置我们的模型的学习率以及在训练过程中调整它的时间表,以便获得更好的性能。ResNet-50 模型的训练将使用 Adam 优化器完成,初始学习率为 1e-3,学习率按指数规律递减,例如在每个时期下降因子γ。
# instantiate optimizer and scheduler
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
scheduler = torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.95)
最后,我们准备训练和验证我们的模型,以识别和学习鸟类之间的差异。交叉熵损失和准确性度量将在每个时期累积,以便检查模型性能动态。在所有的训练实验之后,我们使用以前未见过的数据子集来测试该模型,以使用准确性度量来评估鸟类分类的总体良好性。
# loop over epochs
for epoch in range(num_epochs):# train the model
model.train()
train_loss = list()
train_acc = list()
for batch in train_loader:
x, y = batch
x = x.to(DEVICE)
y = y.to(DEVICE)
optimizer.zero_grad() # predict bird species
y_pred = model(x) # calculate the loss
loss = F.cross_entropy(y_pred, y) # backprop & update weights
loss.backward()
optimizer.step() # calculate the accuracy
acc = skms.accuracy_score([val.item() for val in y], [val.item() for val in y_pred.argmax(dim=-1)])
train_loss.append(loss.item())
train_acc.append(acc)
# validate the model
model.eval()
val_loss = list()
val_acc = list()
with torch.no_grad():
for batch in val_loader:
x, y = batch x = x.to(DEVICE)
y = y.to(DEVICE) # predict bird species
y_pred = model(x)
# calculate the loss
loss = F.cross_entropy(y_pred, y) # calculate the accuracy
acc = skms.accuracy_score([val.item() for val in y], [val.item() for val in y_pred.argmax(dim=-1)]) val_loss.append(loss.item())
val_acc.append(acc) # adjust the learning rate
scheduler.step()# test the model
true = list()
pred = list()
with torch.no_grad():
for batch in test_loader:
x, y = batch x = x.to(DEVICE)
y = y.to(DEVICE) y_pred = model(x) true.extend([val.item() for val in y])
pred.extend([val.item() for val in y_pred.argmax(dim=-1)])# calculate the accuracy
test_accuracy = skms.accuracy_score(true, pred)
print('Test accuracy: {:.3f}'.format(test_accuracy)
图 5 描述了 ResNet-50 的模型性能指标:

图 5。相对于基线 ResNet 50 的历元数的交叉熵损失和准确性度量
正如我们看到的,基线模型表现很差,因为它过拟合。其中一个主要原因是缺乏多样化的训练样本。简单说明一下:CUB-200-2011 数据集每个物种有大约 30 张图片。似乎我们被困住了…不是吗?事实上,我们有一些方法可以解决这些问题。
推进深度学习模型
我们在之前的分析中遇到了许多挑战,因此我们可以开始思考如何解决这些后续问题:
- 问题 1:在训练样本数量有限的情况下,如何处理过拟合问题?
- 问题 2:如何提高鸟类物种识别中的模型性能?
让我们弄清楚如何更详细地推进我们的基线模型。
在训练样本数量有限的情况下,如何处理过拟合?
就像之前说的,深度神经网络需要大量的训练样本。从业者注意到,为了从头开始训练深度神经网络,数据量应该随着可训练参数的数量呈指数增长。幸运的是,在更大数据集上训练的模型的泛化能力可以转移到另一个通常更简单的任务中。
为了提高基线模型用于鸟类分类的性能,我们将使用从 ImageNet 数据集上预训练的通用模型获得的权重初始化,并使用 CUB-200-2011 进一步微调其参数。训练过程保持不变,而模型将更侧重于超参数的微调。
PyTorch 在torch.utils.model_zoo中提供预先训练好的模型。可以通过将 pretrained=True 传递给构造函数来构造预训练的 ResNet-50。这个简单的技巧为我们提供了已经初始化好的过滤器的模型,所以没有必要从头开始学习它们。
# instantiate the model
model = tv.models.resnet50(num_classes=200, pretrained=True).to(DEVICE)
我们还将在优化器中设置一个较低的学习率 1e-4,因为我们将训练一个已经在大规模图像分类任务上进行过预训练的网络。结果如下:

图 6。针对预训练 ResNet 50 的历元数的交叉熵损失和准确度度量
如我们所见,使用预训练模型允许解决过度拟合问题,给出 80.77%的测试准确度。让我们继续做这个实验吧!
如何提高鸟类物种识别中的模型性能?
解决方案 1:多任务学习
现在我们可以进一步扩展这种方法。如果我们可以添加另一个任务,为什么我们必须增加单个任务的复杂性?完全没有原因。人们注意到,引入附加的辅助任务提高了网络的性能,迫使它学习训练数据的更一般的表示。
由于 Caltech-UCSD Birds-200–2011 数据集除了类别标签之外还包括边界框,我们将使用这个辅助目标来使网络以多任务的方式进行训练。现在,我们将通过将数量类设置为 204 来预测鸟的边界框的 4 个坐标以及它的种类:
# instantiate the pre-trained model
model = tv.models.resnet50(num_classes=204, pretrained=True).to(DEVICE)
现在,我们需要稍微修改一下我们的训练和验证模块,因为我们想要预测和计算对应于正确鸟类及其边界框坐标的两个目标的损失。下面是一个执行示例:
...y_pred = model(x)# predict bird species
y_pred_cls = y_pred[..., :-4]
y_cls = y[..., 0].long()
# predict bounding box coordinates
y_pred_bbox = y_pred[..., -4:]
y_bbox = y[..., 1:]# calculate the loss
loss_cls = F.cross_entropy(y_pred_cls, y_cls)
loss_bbox = F.mse_loss(torch.sigmoid(y_pred_bbox), y_bbox)
loss = loss_cls + loss_bbox...

图 7。使用辅助任务增强的预训练 ResNet-50 的交叉熵损失和相对于历元数的准确度度量
结果甚至更好——辅助任务的整合提供了 81.2%的测试分割精度点的稳定增长——如图 7 所示。
解决方案 2:注意力增强的 CNN
在最后几段中,我们重点关注了模型的数据驱动进步。然而,在某些时候,任务的复杂性可能会超过模型的能力,从而导致较低的性能。为了根据问题的难度来调整模型的能力,我们可以给网络配备额外的注意力模块,帮助它专注于输入的重要部分,忽略不相关的部分。
class Attention(torch.nn.Module):
"""
Attention block for CNN model.
"""
def __init__(self, in_channels, out_channels, kernel_size, padding):
super(Attention, self).__init__() self.conv_depth = torch.nn.Conv2d(in_channels, out_channels, kernel_size, padding=padding, groups=in_channels)
self.conv_point = torch.nn.Conv2d(out_channels, out_channels, kernel_size=(1, 1))
self.bn = torch.nn.BatchNorm2d(out_channels, eps=1e-5, momentum=0.1, affine=True, track_running_stats=True)
self.activation = torch.nn.Tanh() def forward(self, inputs):
x, output_size = inputs
x = F.adaptive_max_pool2d(x, output_size=output_size)
x = self.conv_depth(x)
x = self.conv_point(x)
x = self.bn(x)
x = self.activation(x) + 1.0return x
注意模块允许高亮显示特征图的相关区域,并返回在范围[0.0,2.0]内变化的值,其中较低的值意味着给定像素对于后续层的较低优先级。因此,我们将创建并实例化与注意力增强的 ResNet-50 模型相对应的类ResNet50Attention:
class ResNet50Attention(torch.nn.Module):
"""
Attention-enhanced ResNet-50 model.
""" weights_loader = staticmethod(tv.models.resnet50) def __init__(self, num_classes=200, pretrained=True, use_attention=True):
super(ResNet50Attention, self).__init__() net = self.weights_loader(pretrained=pretrained)
self.num_classes = num_classes
self.pretrained = pretrained
self.use_attention = use_attention net.fc = torch.nn.Linear(
in_features=net.fc.in_features,
out_features=num_classes,
bias=net.fc.bias is not None
) self.net = net if self.use_attention:
self.att1 = Attention(in_channels=64, out_channels=64, kernel_size=(3, 5), padding=(1, 2))
self.att2 = Attention(in_channels=64, out_channels=128, kernel_size=(5, 3), padding=(2, 1))
self.att3 = Attention(in_channels=128, out_channels=256, kernel_size=(3, 5), padding=(1, 2))
self.att4 = Attention(in_channels=256, out_channels=512, kernel_size=(5, 3), padding=(2, 1)) if pretrained:
self.att1.bn.weight.data.zero_()
self.att1.bn.bias.data.zero_()
self.att2.bn.weight.data.zero_()
self.att2.bn.bias.data.zero_()
self.att3.bn.weight.data.zero_()
self.att3.bn.bias.data.zero_()
self.att4.bn.weight.data.zero_()
self.att4.bn.bias.data.zero_() def _forward(self, x):
return self.net(x)
def _forward_att(self, x):
x = self.net.conv1(x)
x = self.net.bn1(x)
x = self.net.relu(x)
x = self.net.maxpool(x) x_a = x.clone()
x = self.net.layer1(x)
x = x * self.att1((x_a, x.shape[-2:])) x_a = x.clone()
x = self.net.layer2(x)
x = x * self.att2((x_a, x.shape[-2:])) x_a = x.clone()
x = self.net.layer3(x)
x = x * self.att3((x_a, x.shape[-2:])) x_a = x.clone()
x = self.net.layer4(x)
x = x * self.att4((x_a, x.shape[-2:])) x = self.net.avgpool(x)
x = torch.flatten(x, 1)
x = self.net.fc(x) return x
def forward(self, x):
return self._forward_att(x) if self.use_attention else self._forward(x) # instantiate the model
model = ResNet50Attention(num_classes=204, pretrained=True, use_attention=True).to(DEVICE)
之后,我们准备训练和评估注意力增强模型的性能,该模型在 ImageNet 数据集上进行了预训练,并使用我们之前使用的相同代码进行了鸟类分类的多任务学习。最终准确度分数增加到 82.4%!
图 8 显示了分析过程中生成的总结结果:

图 8。使用不同技术的 ResNet-50 advanced 的性能比较
结果清楚地表明,具有迁移和多任务学习以及注意力模块的 ResNet-50 模型的最终变体大大有助于更准确的鸟类预测。
结论
在这里,我们使用不同的方法来提高基线 ResNet-50 的性能,用于 CUB-200–2011 数据集的鸟类分类。我们能从中学到什么?以下是我们分析得出的一些信息:
- 数据探索结果表明,CUB-200–2011 是一个高质量、平衡但有中心偏差的数据集,没有损坏的图像。
- 在训练样本数量有限的情况下,您可以在自己的模型中重用在另一个数据集上预先训练的模型权重。
- 除了主要的鸟类分类之外,通过辅助任务进行学习有助于更好的模型性能。
- 通过添加新的层(注意模块)来增强网络的架构,使得模型在鸟类分类中更加准确。
- 对基本 ResNet-50 的不同扩展的分析表明,使用辅助任务和注意机制的预训练模型是进一步研究的突出候选。
总之,模型性能还有改进的空间。通过进一步优化模型超参数、使用更强的数据扩充、正则化、元学习技术,可以实现额外的进步。
更多即将推出!
下一篇教程的重点将是深度学习模型的可解释性。有兴趣继续吗?
在 https://medium.com/@slipnitskaya 的订阅更多深度学习材料并保持更新。
参考
- 应用于手写邮递区号辨识的反向传播。神经计算 1.4(1989):541–551。
- 基于梯度的学习应用于文件识别。IEEE 86.11 会议录(1998):2278–2324。
- 克里日夫斯基、亚历克斯、伊利亚·苏茨基弗和杰弗里·e·辛顿。"使用深度卷积神经网络的图像网络分类."美国计算机学会 60.6 (2017 年)通讯:84–90。
- 何,,等,“深度残差学习在图像识别中的应用”IEEE 计算机视觉和模式识别会议论文集(2016):770–778。
- 加州理工学院-加州大学圣迭戈分校鸟类 200–2011 数据集。计算与神经系统技术报告,CNS-TR-2011–001。(2011).
利用暹罗网络和扩张卷积进行鸟鸣分类
原文:https://towardsdatascience.com/bird-song-classification-using-siamese-networks-and-dilated-convolutions-3b38a115bc1?source=collection_archive---------15-----------------------

Glen Carrie 通过 Unsplash 拍摄的图像
介绍
T2:声学在研究环境方面非常有用。它已经被用于跟踪潜艇和鲸鱼很长时间了。鸟类对塑造我们身边的植物有很大帮助。识别鸟鸣对于自动监测野生动物和研究鸟类的行为非常重要。它可以帮助追踪鸟类而不打扰它们。我们还可以知道在某个特定的地方存在着哪些鸟类。它能给我们一些关于它们迁移模式的信息。每种鸟都有它们独特的声音。它们用不同长度和复杂程度的歌声来吸引配偶,警告其他鸟类附近的危险,并标记它们的领地。鸣禽可以根据地理位置有不同的方言。但是非鸣禽发出的声音不会因为地理位置而有太大变化。使用深度学习方法,我们可以很容易地根据鸟类的叫声和歌声对它们进行分类。我们可以使用任何神经网络框架,如 CNN、暹罗网络、WaveNets 等。为了这个任务。
问题陈述
目标:我们想根据不同鸟类的鸣叫声样本对它们进行分类。我们可以提取音频样本的频谱图,并使用它们作为分类的特征。在这个实验中,我们将使用 Kaggle 上的英国鸟鸣数据集。数据集在数据描述部分描述。
暹罗网络和膨胀卷积的快速介绍
暹罗网络
之前写过一篇暹罗网的文章。可以去查一下,深入了解一下它的工作和为它使用的损耗函数。该文章中还提供了代码。但是,我在这里给大家总结一下暹罗网。
**连体网络是一类包含一个或多个相同网络的神经网络。**我们向这些网络提供一对输入。每个网络计算一个输入的要素。然后,使用特征的差或点积来计算特征的相似性。对于相同的类输入对,目标输出是 1,而对于不同的类输入对,输出是 0。记住,两个网络有相同的参数和权重。如果不是,那他们就不是暹罗人。

暹罗网络基本结构
不同的损失函数可用于连体网络。
- 对比损失:在对比损失中,取一对输入。对于相同的类对,它们之间的距离较小。对于不同的对,距离更多。尽管二进制交叉熵似乎是我们问题的完美损失函数,对比损失在区分图像对方面做得更好。对比损失,L*=Y * D+(1-Y) max(margin—D,0)
- 三重丢失:三重丢失是 Google 在 2015 年推出的人脸识别。这里,模型有三个输入——锚、积极和消极。锚点是一个参考输入。实际输入与锚输入属于同一类别。负输入属于锚类之外的随机类。我们必须最小化锚和阳性样本之间的距离,同时最大化锚和阴性样本之间的距离。
我们将在实验中使用三重态损失。
扩张的回旋
膨胀卷积是一种卷积,它通过在内核元素之间插入孔洞来“膨胀”内核。它们也被称为 atrous 卷积。
扩展卷积的概念来自于小波分解,其中母小波被不同的尺度缩放或扩展以捕获不同的频率。

(a)标准 3×3 内核,(b)膨胀因子为 2 的内核,(c)膨胀因子为 4 的内核。来源原论文
扩张卷积以相同的计算和存储成本增加了感受野,并且不损失分辨率。它可以用相同数量的参数从整个输入中捕获上下文。
这是 Sik-Ho Tsang 写的一篇关于膨胀的脑回的好文章。
数据描述
在这个实验中,我们使用了 Kaggle 上的英国鸟鸣数据集。这是从 Xeno Canto 数据收集中收集的一个小子集,形成了英国 88 种鸟类的平衡数据集。
这里我们只对 9 种鸟类进行分类:加拿大鹅腐尸鸦煤山雀普通乌鸫普通燕雀普通红雀普通朱雀普通黑水鸡普通夜莺。
在这个数据集中,每只鸟的样本都很少。音频样本大约有 40-60 秒长。其中一些有点吵,有时背景中还有其他的鸟。从具有 50%重叠的每个样本中提取 2 秒钟的剪辑,以创建新样本。这将为训练神经网络创建足够数量的样本。数据分为 60%用于训练,40%用于测试。
履行
特征抽出
Librosapython 中的库用于音乐和音频分析。我们可以读取音频文件,并用它提取频谱图。
**第一步:**使用 **librosa 读取音频文件。**将-1 和 1 之间的时间序列归一化。
**步骤 2:** 去除音频中的静音。
**步骤 3:** 将每个音频文件分割成 2 秒长的片段,重叠 50%。
**第四步:**将数据分为训练和测试。60%用于培训,40%用于测试。
步骤 5: 从样品中提取光谱图。一个过滤器被应用到频谱图中,以获得一个在1 千赫和8 千赫之间的频率范围,因为大多数鸟鸣声的频率都在这个范围内。现在,标准化所有的光谱图(你也可以在 0 到 1 之间标准化它们)。这里,每个声谱图的形状是 163×345。

常见乌鸫鸣声的样本声谱图
**第六步:**为暹罗网络生成正负样本对。
首先,生成正对。
现在,生成负的类对。
您可以使用下面的函数生成正对和负对。它以: 输入特征、目标类别标签、从每个类别中取出的随机数的数目、 和 正对的数目作为输入。 返回锚点、阳性和阴性样本。
现在,数据已准备好用于暹罗网络。
我们有 3 种类型的输入:锚、阳性和阴性样本。每个输入的形状是:(10800 x 345 x 163)。
现在,我们需要建立一个神经网络。
建立神经网络
编码器模型包含 8 个 1-D 卷积层,具有指数增长的膨胀因子。之后,应用 1D 卷积层来减少特征的数量。最后,应用全局最大池 1D 层。每一层后应用一个批量标准化层。除了最后一层,所有层都有一个'【reLu】'激活。在最后一层应用''激活。在最后一层,我们得到一个 32 维向量作为输出。
*创建了该编码器模型的三个实例。它们代表锚定输入、积极输入和消极输入。所有三个 32 维特征向量被连接成一个 96 维向量。这个连接的向量被视为输出。正如您在下面的代码中看到的,函数 triplet_loss 获取输出,再次分离 3 个嵌入,并计算损失。*
下面你可以看到模型的代码。
以下是编码器型号摘要:

编码器型号摘要

编码器模型架构
现在我们有了一个完整的暹罗网络。
训练模型
我们现在可以拟合模型了。模型的目标输出是虚拟输出。这是因为我们没有将模型的输出与目标输出进行比较。相反,我们只是最小化相同类嵌入之间的距离,并推开不同类嵌入。
我们的锚定样本、正样本和负样本的输入大小是:(10800 x 345 x 163)。批量大小设置为 256。由于批量标准化,该模型仅在 30 个时期内收敛。如果你愿意,你可以训练更长时间。
结果
该模型在训练集上的准确率为 98.1% ,在测试数据集上的准确率为 97.3% 。
以下是测试数据集的标准化混淆矩阵:

测试数据集的混淆矩阵
以下是嵌入的相似性矩阵:

测试数据集嵌入的相似性矩阵
下面是对测试数据集嵌入应用 PCA 后的散点图。所有的班级之间有很好的区分。并且,除了几个样本,所有的类都聚集在一起。

应用 PCA 后测试数据集嵌入的散点图
要点
- 这里光谱图被用作特征。也可以使用 Mel 光谱图。
- 音频的小波变换也可以作为特征。
- 可以用更长的框架尺寸进行实验。过长的帧尺寸会使模型过拟合,并降低整体性能。
- 批处理规范化层起着非常重要的作用。它使训练期间的小批量标准化,并解决了内部协变量移位的问题。它使训练更快,模型变得更健壮。我强烈推荐在你的模型中使用这个。
- 如果你想对更多种类的鸟类进行分类,模型的集合肯定会进一步提高精确度。
结论
*暹罗网络成功地根据鸟类的叫声对它们进行了分类,准确率高达 97%。连体网络将分类问题转化为相似性问题。它们也可以使用更少的样本,因为我们生成的是成对的样本。具有扩展的 1-D 卷积的模型以及批量标准化层收敛得非常快。*
这里是这个项目的 GitHub 库。
*https://github.com/AdityaDutt/Bird-Song-Classification
未来的实验想法
这个模型可以扩展到对 50 或 100 多只鸟进行分类。我对鸟类了解不多,因为这不是我的研究领域,但我非常好奇,想知道我们是否可以根据鸟类的叫声来识别不同的地理位置。这是因为鸣禽的方言随着地理位置的变化而变化。这里是一个 GitHub 储存库,其中包含了与鸟类相关的数据集列表。Xeno-canto 网站收录了世界各地的鸟鸣。它有不同国家、物种等的数据。您可以从这里为自己的项目选择一个数据集。
请记住,您可以将该模型用于类似的基于音频的任务,如说话者分类、情感检测等。
**非常感谢您的阅读!我希望它有帮助。🐧
如果你想合作一个项目,或者需要一些关于你的项目的想法,请随时联系我。
参考
https://arxiv.org/abs/1609.03499 https://arxiv.org/abs/1511.07122v3 https://www.kaggle.com/rtatman/british-birdsong-dataset https://github.com/AgaMiko/bird-recognition-review https://arxiv.org/abs/1502.03167 https://machinelearningmastery.com/how-to-accelerate-learning-of-deep-neural-networks-with-batch-normalization/ https://machinelearningmastery.com/batch-normalization-for-training-of-deep-neural-networks/ https://www.xeno-canto.org/ *
机器学习中的二分 K 均值聚类算法
原文:https://towardsdatascience.com/bisecting-k-means-algorithm-clustering-in-machine-learning-1bd32be71c1c?source=collection_archive---------11-----------------------
理解对分 K-均值聚类算法(视觉和代码)

来自源的修改图像
B isecting K-means 聚类技术是对常规 K-means 算法的一点修改,其中您固定了将数据划分为聚类的过程。所以,类似于 K-means,我们首先初始化 K 个质心*(你可以随机地做或者可以有一些先验)*。之后我们应用规则的 K-means,K=2 *(这就是为什么单词平分)。我们不断重复这一对分步骤,直到达到期望的聚类数。在第一次对分(当我们有 2 个聚类)*完成*,*之后,人们可以想到多种策略来选择其中一个聚类,并在该聚类内重复对分和分配的整个过程——例如:*选择具有最大方差的聚类或展开的聚类,选择具有最大数量数据点的聚类,等等。*
没有时间看完整个博客?然后看这个快速的< 60 秒的 YouTube 短片—
你可以想象整个流程,如下图所示—

按作者划分 K-Means |图像的步骤
如上图所示,我们首先假设所有数据都在一个聚类*(第一张图)*中,在第一步之后,我们得到 2 个*(二分法)*聚类,然后我们检查是否达到了期望的聚类数。如果没有,我们从上一步的两个聚类中选择一个*(红色)*,再次应用 K=2 的 K-means,并且我们**重复“*检查*和“*二等分*”步骤。**
你可能已经猜到了,这看起来像是层次聚类和 K 均值聚类的混合。因为在这里您正在构建一个树,这是一个层次结构,其中一个节点根据 K-means 策略和赋值被分成两个子节点。
对 K-Means 的改进
与常规 K-Means 不同,在常规 K-Means 中,我们在每一步计算每个数据点和质心之间的距离,直到满足收敛标准,在这里,我们只做一次*(第一步)*,之后,我们只使用特定聚类中的数据点来计算距离和进一步细分,使其比常规 K-Means 更有效。它还可以识别任何形状和大小的簇,不像 K-Means 假设的是球形簇。 我还发现了一篇有趣的研究文章,比较了 K-Means 和二分法 K-Means 在分析网络日志数据时的性能——在这里阅读https://ijeter.everscience.org/Manuscripts/Volume-4/Issue-8/Vol-4-issue-8-M-23.pdf。
限制
因为基本聚类技术在这里仍然是 K-Means,所以在离群值的情况下,这个算法也可能遭受对聚类中心的错误估计。
***提示:*二等分 K-Medoid 聚类技术可以帮助你解决上述限制。
密码
我将使用 Python 的 Sklearn 库来实现目的—
**from sklearn.cluster import KMeans
import numpy as np**X = np.array([[1, 2], [2, 1], [1, 1.5], [1.5, 1],
[10, 2], [10, 4], [10, 0], [10, 1],
[1, 10], [2, 11], [1.5, 9], [1, 10.5],
[10.5, 9], [9, 9.5], [9.5, 9], [10, 10]])**K = 4
current_clusters = 1**while current_clusters != K:* *kmeans = KMeans(n_clusters=2).fit(X)
current_clusters += 1
split += 1* *cluster_centers = kmeans.cluster_centers_* *sse = [0]*2
for point, label in zip(X, kmeans.labels_):
sse[label] += np.square(point-cluster_centers[label]).sum()* *chosen_cluster = np.argmax(sse, axis=0)
chosen_cluster_data = X[kmeans.labels_ == chosen_cluster]
X = chosen_cluster_data**
下图展示了上述示例代码的图示演练—

上例演练|作者图片
简而言之,当考虑将 K-Means 作为算法的选择时,尝试平分 K-Means 也是一个好主意。由于上面讨论的原因,很有可能你会得到更好的结果。
希望你喜欢阅读这篇博客。感谢您的宝贵时间!
比特币财源滚滚!
原文:https://towardsdatascience.com/bitcoin-bonanza-2cb208026bbd?source=collection_archive---------24-----------------------
比较 GRU、LSTM 和比尔斯特姆预测比特币价格的有效性

图片来源:andréFran ois McKenzie 在 Unsplash 上拍摄的照片
介绍
我已经跟踪加密价格好几年了。我对区块链的演变及其含义很感兴趣。我不止一次对数字货币的想法嗤之以鼻。这并不是什么新东西,但我出生在 80 年代,那时如果我们想提取真正的纸币,我们必须填写一张纸并与人交谈……还记得纸币吗?
无论如何,今天我想和你分享我最近的一个项目。我将比较三种模型,以确定它们在预测加密之王比特币价格方面的功效。在这个项目中,我使用了门控循环单元(GRU)、长短期记忆单元(LSTM)和双向 LSTM 单元(比尔斯特姆)。首先,让我们快速了解一下这些神秘预测模型的工作原理。
自 90 年代以来,人们对递归神经网络(RNNs)进行了大量的研究。RNNs 的基本功能是处理序列数据的能力,使其成为探索涉及文本、音频、图像、videos⁴和金融市场的任务的宝贵工具,例如我们将要探索的市场。想了解 RNNs 如何工作的有趣方法,请查看这篇有创意的帖子!
当我们开始大量使用 data⁵.时,RNNs 的局限性就变得很明显了例如,为了这篇文章,我收集了大约 7 年的比特币价格数据。这意味着我有超过 2500 个时间步长的输入。因此,每次模型更新时,将对这些输入中的每一个计算衍生产品。这可能导致权重下降到接近零(消失梯度)或爆炸(爆炸梯度),这意味着模型学习缓慢。因为 rnn 在学习大型数据集的早期输入时有困难,所以他们被称为具有短期记忆。
为了克服这个问题,开发了专门的 rnn。长短期记忆单位(LSTM)、双向 LSTM (BiLSTM)和门控循环单位(GRU)。这些模型使用称为“门”的内部机制,可以调节信息在网络中的流动方式。最终,他们决定哪些信息是重要的,要保留或丢弃(如果你想更深入,你可以看看这篇帖子)。
现在,我们已经讨论了一些关键概念,让我们开始工作,看看这些模型如何作为比特币价格的预测器!
首先,让我们看一下我们的数据。下图 1 展示了比特币价格随时间的演变。虽然波动比较大,但我必须承认,2013 年我没有购买比特币,这让我有点郁闷!

图 1——比特币收盘价随时间的演变(图片由作者提供)。日期范围(2013 年 4 月 29 日-2021 年 1 月 12 日)。数据收集自https://coinmarketcap . com/currences/bit coin/historical-data/
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
数据准备
移位数据
在我们开始构建模型之前,需要几个重要的步骤。第一步是将我们的结果变量上移(-1)一个时间步长。目的是组织我们的数据,以便预测变量将用于预测第二天的收盘价,TOMORROW_CLOSE。
因为我不想用一个不存在的值来估算空单元格,所以我用 0 填充它,并将其从数据集中删除。另一种方法是将所有预测值下移(+1)。这将导致在数据集的开头插入 0,这将接近 2013 年的初始值。
将“日期”转换为日期时间
接下来,使用 df.dtypes,我们可以检查数据集中存在的变量类型。使用时,这总是一个好主意。csv(或其他)文件类型,以确保该列已被正确读取。例如,“日期”列在 Excel 中是日期格式,但在导入时它被解释为对象。因此,我们必须使用下面的代码将其转换为日期时间。
将日期设置为索引
接下来,我们必须将列“Date”设置为索引。如果您跳过这一步,您将得到以下错误:无效的类型提升。这一步对我来说真的很难。试着在谷歌里输入‘无效类型推广’,你会找到 29,100,000 个结果!
顺便提一下,您还可以在读取。使用 index_col = 'Date '的 csv 文件
将数据分成训练集和测试集
现在,我们的数据已经准备好分成训练集和测试集。我分别为训练和测试数据选择了 80/20 的分割。让我们看看这给我们带来了什么(图 2)。

图 2 —数据分为 80%的训练集(蓝色)和 20%的测试集(橙色)。(图片由作者提供)
独立的预测因素和结果变量
到目前为止,一切看起来都不错!现在,在开始训练我们的模型之前,我们需要分离我们的预测变量(X)和结果变量(y)。
缩放数据
许多机器学习模型的一个良好实践是将数值变量缩放到指定的范围。因为这些模型的默认激活函数是双曲正切(tanh)函数,它输出的范围是从-1 到 1,所以我调整了值以适应这个范围。为此,我使用了 sklearn 的 MinMaxScaler。遵循以下 3 条准则被视为良好实践:
- 首先,我们使用 fit() 函数将缩放器拟合到训练集
- 接下来,我们使用*变换()*函数将该比例应用于训练集
- 最后,您将量表应用于测试集
创建三维数据集
我们模型的输入数据必须是带有形状[批次、时间步长、特征]的 3D 数据(参见 Keras 说明此处)。下面,一个名为 threeD_dataset 的函数将数据重塑为必要的格式。时间步长设置为 10,这意味着模型将根据前 10 天的输入来预测“明天 _ 收盘”。
构建模型
最后,我们将创建用于预测比特币价格的 3 个模型。所有模型都保持简单,具有包含 64 个神经元的两层和包含 1 个神经元的致密层。我还增加了 20%的辍学,以防止过度拟合。最后,我使用 adam 作为优化函数,使用均方差作为这些模型的度量。有关这些层和函数如何工作的更多信息,请查看我的上一篇文章,在那里我详细介绍了相当多的细节!
拟合模型
现在是时候拟合模型了,看看它们对比特币价格的预测有多准确!我将为这些模型运行 100 个纪元;然而,我添加了 EarlyStopping ,耐心为 10,当验证损失在 10 个时期内没有改善时,它会阻止模型继续运行。这可以节省大量的时间,尤其是在处理大量数据集的情况下。
需要注意的是,因为我们处理的是时间序列数据,时间步长的顺序是有意义的,所以我们必须设置 shuffle = False。
结果
预测的反向标度
在我们可以对数据进行预测之前,我们必须使用逆变换将结果变量返回到其原始形式。回想一下,我们将数据的范围从-1 调整到 1。如果我们不使用反函数,那么我们的预测将在这个标度范围内。
根据测试数据进行预测
现在是我们期待已久的时刻!我们将看到哪个模型在未知测试集上预测比特币价格的表现最好。这些试验的结果如下图 3 所示。

图 3-比尔斯特姆、LSTM 和 GRU 模型的预测图。(图片由作者提供)
正如我们所看到的,当目视检查时,来自 LSTM 和比尔斯特姆的预测值都非常好地跟随试验数据,直到在数据集的末尾值急剧上升。另一方面,GRU 模型似乎有最好的整体拟合。即使它没有紧紧跟随真实的数据,但它似乎更善于跟随数据中呈现的趋势。
韵律学
以上给出了数据的定性解释。这里,创建了一个函数来为每个模型提供定量的准确性度量。所有三个模型都提供了平均绝对误差(MAE)和均方根误差(RMSE)。关于这两个指标的解释,请查看这篇文章。
BiLSTM:
- 梅:913.15
- RMSE: 2052.10
LSTM:
- 梅:1286.47
- RMSE: 2459.72
GRU:
- 梅:1334.79
- RMSE 1934.90
我们应该如何解读这些价值观?首先我说一下,我不是专业交易者。我只能提供一个观点。MAE 似乎更符合图 3 中观察到的紧密配合。比尔斯特姆和 LSTM 都有较低的 MAE 值,表明模型更准确(当使用这一指标时)。相反,GRU 有较低的 RMSE,建议使用更准确的模型(使用此指标)。
在我看来,交易不像彩票。我们的目标不是准确知道资产的未来价格。更好的策略是预测未来价格的走向。
比如知道明天 1 比特币会值 42749.67,没有上下文就没用了。然而,如果我知道今天 1 比特币的价值是 39,118.33,那么预测的上涨趋势将会更有价值。这将引导我决定买或卖。
考虑到这一点,我觉得 GRU 模型作为趋势指标比价格指标表现得更好。接下来,我们将使用 GRU 模型来预测未来的价格!
预测
我在调查时间序列数据的时候经常用到这三个模型,不得不承认每次都很惊讶。如果你回头看看图 2,它描绘了训练集和测试集,它们没有太多的共同点。模型可以学习训练集中的模式,这对预测测试中相对不同的模式是有用的,这一事实令人难以置信!
在这最后一部分,我一直等到积累了足够的数据,可以使用新的数据集预测比特币的价值。因为我使用了 10 的时间步长,所以我至少需要 10 天的额外时间。之前的数据集结束于 2021 年 1 月 12 日,然而,在将收盘价上移后,它被从数据集中删除,以避免必须用一个虚构的值来估算值。因此,预测数据集包含 2021 年 1 月 12 日至 23 日的数据。
值得一提的是,所有相同的数据准备方法都应用于新的预测数据集。为了避免重复的材料,我在课文中省略了它们。
在下面的图 4 中,你会发现我预测比特币未来价值的结果。我有足够的数据来预测两个未来值。

图 4-预测 GRU 模型对比特币价格进行预测。(图片由作者提供)
1 月 22 日
- 预测:28226.11
- 实际:33,005.76
1 月 23 日
- 预测值:27468.18
- 实际:32,067.64
结论
在本文中,我测试了 LSTM、比尔斯特姆和 GRU 模型在预测比特币价格方面的功效。在提供了模型的一般概述之后,我描述了准备数据以避免可怕的模糊错误消息的方法。
在训练完这些模型后,他们每个人都要接受*测试。*每一个都表现得相当好,但 GRU 模型被发现是更好的趋势指标,我觉得从交易的角度来看,它更相关。
当 GRU 模型用于预测价值时,它表现得相当好。虽然价格没有准确预测,但趋势是正确的!
如果你想玩这些模型,请在我的 Github 上查看完整的笔记本。我想保持一切简单,但模型肯定可以改进。尝试:
- 其他预测变量
- 改变时间步长
- 将数据移动 2 或 3 天,观察结果如何变化
- 改变模型本身的参数(层、删除、激活函数、优化器等)
写这篇文章让我很开心。非常感谢您花时间阅读它!
记住,解决你的研究问题的最好方法是带着孩子般的好奇心!玩得开心!
参考
1.王芳,郭,秦,雷,张(2017)。用于场景文本识别的隐马尔可夫模型引导卷积递归神经网络。IET 计算机视觉,11(6),497–504。
2.Sak,h .,Senior,a .,Rao,k .,和 Beaufays,F. (2015 年)。用于语音识别的快速准确的递归神经网络声学模型。arXiv 预印本 arXiv:1507.06947。
3.牟,李,加米西,p .,,朱,X. X. (2017)。用于高光谱图像分类的深度递归神经网络。IEEE 地球科学与遥感汇刊,55(7),3639–3655。
4.Güera,d .,& Delp,E. J. (2018 年 11 月)。基于递归神经网络的深度伪造视频检测。2018 年第 15 届 IEEE 高级视频和信号监控国际会议(AVSS)(第 1-6 页)。IEEE。
5.茨韦塔纳·斯特灵、北卡罗来纳州法鲁吉亚和弗吉尼亚州格里彭(2017 年)。普通 rnns 和 gru 模型之间的本质区别。COGNTIVE 2017,84。
被“数据科学的错误”所困扰
当数据科学成为一种困扰。

www.freepik.com 弗里皮克创作的科技照片
很长一段时间以来,我一直想知道为什么一些数据科学家每天醒着的时候都在痴迷地消耗知识,磨练技能,参加比赛,创建爱好项目,并普遍扩大他们的视野。与此同时,其他人则更安于现状,利用现有技能来解决他们遇到的问题。
当然,任何称职的数据科学家都会不断扩展和提高他们的技能;这是成为一名优秀数据科学家的先决条件之一。这不是我在这里谈论的。我说的是让继续学习的人。我说的是当它几乎成为一种疾病时,你不得不花费你所有的空闲时间,不管你有多累或多忙,阅读更多的论文和编写更多的代码。
在力量运动中,有一个“铁虫子”的概念——如果被这个虫子“咬”了,就不再是如何年复一年保持训练的问题;取而代之的是一个问题,那就是如何才能而不是做到这一点。突然锻炼比实际锻炼花费更多的精力。我们可以在其他领域找到类似的困扰,但我发现“数据科学”有着特殊的吸引力。在我的旅程中,我遇到了几个和我一样被数据科学 bug“咬”了一口的人。
我喜欢数据科学。我喜欢这个领域的广阔,以及它在许多方面是如何“*无界的,”*从基本的数学概念一直延伸到实现商业价值。最重要的是,我喜欢在这个领域投入工作以取得进展:花无数的时间阅读我理解能力范围内的论文,或者连续几天拼命实现和调试一些新代码。请注意,这些都不是与我日常工作相关的文件,也不是会公之于众的代码。的确,我绝不是最有成就的数据科学家,但每隔半年左右,我都会在回顾过去并看到自己从原地进步了多少时获得巨大的满足感。
为什么有些人能理解这种困扰,而有些人却不能?这并不是因为智力或技术能力的差异,因为我见过很多非常有能力的人不痴迷。我也不认为这是由于环境、环境或教养。相反,它可能归结为某些人格特征的存在,最终,一些人只是遗传易感,而另一些人是免疫的。至少,我相信从行为遗传学的角度来看,这是一个结论。事情就是这样。
不管我上面宣称的对数据科学的热爱,我不希望任何人染上这个毛病。当你没有睡好,工作了漫长而疲惫的一天,和一个过度疲劳的孩子度过了艰难的下午,以及一个艰难的晚上试图让同一个孩子入睡时,你会做什么?阅读论文或编写一个新的爱好项目?对于这种有时近乎自我毁灭的行为,我的内部观众用自尊和自信来回报我。这是以精疲力尽为代价的,矛盾的是,这是一种对自己的进步或能力永远不满意的感觉。
对于那些未受此病毒影响的人,我羡慕你们。
对于拥有它的人,我向你们致敬。
面向可解释人工智能的黑盒和白盒模型
原文:https://towardsdatascience.com/black-box-and-white-box-models-towards-explainable-ai-172d45bfc512?source=collection_archive---------13-----------------------
第一部分 | 第二部分 |可解释的人工智能——第三部分
使用模型属性、局部逻辑表示和全局逻辑表示从黑盒模型中生成解释


图一。照片由Andrew“Donovan”valdi via在 Unsplash |和图 2 拍摄。照片由凯利·麦克林托克在 Unsplash 上拍摄
快速回顾:XAI 和国家安全委员会
可解释的人工智能(XAI) 处理开发人工智能模型,这些模型本质上对人类来说更容易理解,包括用户、开发者、决策者和执法人员。神经符号计算(NSC) 处理子符号学习算法与符号推理方法的结合。因此,我们可以断言,神经符号计算是可解释人工智能下的一个子领域。NSC 也是最适用的方法之一,因为它依赖于现有方法和模型的结合。

图 3。符号人工智能 vs 次符号人工智能(作者提供图片)
如果说可解释性是指用人类语言有意义地描述事物的能力。换句话说,它是将原始信息(数据)映射成对人类有意义的符号表示的可能性(例如英文文本)****
通过从子符号中提取符号,我们可以使这些子符号变得可以解释。XAI 和国家安全委员会都试图让次符号系统更容易解释。NSC 更多的是关于将子符号映射到符号,通过逻辑设计的可解释性:对子符号学习表示的符号推理。XAI 没有那么具体,更多的是关于所有细微差别的可解释性,即使可解释性被包裹在不可解释的模型中。如果从子符号中提取符号意味着可解释性,那么 XAI 包括 NSC 。
让我们通过一个示例来看看这些 NSC:
神经符号概念学习者
Mao 等人提出了一种新的 NSC 模型,即神经符号概念学习器,它遵循以下步骤:

图 4。神经符号概念学习者(图由毛等
- 图像分类器学习从图像或文本片段中提取子符号(数字)表示。
- 然后,每个子符号表示都与一个人类可以理解的符号相关联。
- 然后,符号推理器检查符号表示的嵌入相似性
- 训练继续进行,直到通过更新表示使推理机的输出精度最大化。
白盒与黑盒模型
人工智能模型可以是(I)白盒或(ii)黑盒。
- 白盒模型可以通过设计来解释。因此,它不需要额外的能力来解释。
- 黑箱模型本身是无法解释的。因此,为了使一个黑盒模型可解释,我们必须采用几种技术从模型的内部逻辑或输出中提取解释。
黑盒模型可以用
- **模型属性:**展示模型或其预测的特定属性,如(a)对属性变化的敏感性或(b)负责给定决策的模型组件(如神经元或节点)的识别。
- **局部逻辑:**单个决策或预测背后的内在逻辑的表示。
- 全局逻辑:整个内部逻辑的表现。
因此,下图显示了人工智能模型在可解释性方面的子类别:

图 5。简单易懂的人工智能分类法
基于规则的可解释性与基于案例的可解释性
除了可解释模型的逻辑区别之外,我们还确定了两种常见的解释类型,所有上述模型都可以采用这两种类型来提供解释:
基于规则的解释:基于规则的可解释性依赖于生成一套“形式化的逻辑规则,阐明给定模型的内部逻辑”。

图 6。决策树可以很容易地公式化,以提供基于规则的解释(图由 Guidotti 等人
基于案例的解释:基于规则的可解释性依赖于提供有价值的输入输出对(积极的和消极的)来提供模型内部逻辑的直觉。基于案例的解释依赖于人从这些对中推断逻辑的能力。

图 7。基于案例的解释示例(作者图)(图片来自 Unsplash )
基于规则与基于案例的学习算法比较示例:
假设我们的模型需要学习如何做苹果派的食谱。我们有蓝莓派、芝士蛋糕、牧羊人派的食谱,还有一份简单的蛋糕食谱。基于规则的学习方法试图为制作所有类型的甜点提出一套通用规则(即,渴望方法),而基于案例的学习方法则根据需要概括信息,以涵盖特定的任务。因此,它会在可用数据中寻找与苹果派最相似的甜点。然后,它会尝试在类似的食谱上做一些小的改动。
XAI:设计白盒模型
包括基于规则和基于案例的学习系统,我们有四类主要的白盒设计:
- 手工制作的专家系统;
- **基于规则的学习系统:**从数据中学习逻辑规则的算法,如归纳逻辑编程、决策树等;
- 基于案例的学习系统:基于案例推理的算法。他们利用例子、案例、先例和/或反例来解释系统输出;和
- 嵌入符号&提取系统:更多的生物启发算法,如神经符号计算。
在本系列接下来的部分中,我们将有这些方法的实际例子。
最终注释
在本帖中,我们:
1 —简要介绍了 XAI 和 NSC 之间的差异和相似之处;
2 —定义和比较黑盒和白盒模型;
3 —使黑盒模型可解释的方法(模型属性、局部逻辑、全局逻辑);
4-比较基于规则的解释和基于案例的解释,并举例说明。
在下一篇文章中,我们将介绍市场上可解释工作的库和技术,并将使用其中一些库从黑盒模型和白盒模型中提取解释。
订阅邮件列表获取更多内容
如果你想获得我在 Google Colab 上的其他教程文章的代码,并尽早获得我的最新内容,可以考虑订阅:✉️的邮件列表
如果你对深度学习感兴趣,也可以看看我的人工智能内容指南:
https://blog.orhangaziyalcin.com/a-guide-to-my-content-on-artificial-intelligence-c70c9b4a3b17
如果你正在阅读这篇文章,我确信我们有着相似的兴趣,并且现在/将来会从事相似的行业。那么我们就通过 Linkedin 来连线吧!请不要犹豫发送联系请求!Orhan g . yaln—Linkedin
参考
Guidotti,r .,Monreale,a .,Ruggieri,s .,Pedreschi,d .,Turini,f .,& Giannotti,F. (2018 年)。黑盒决策系统的基于局部规则的解释。www . propublica . org/article/machine-bias-risk-assessments-in-criminal-pending
毛,甘,c,柯利,p,特南鲍姆,J. B .,,吴,J. (2019)。神经符号概念学习者:从自然监督中解读场景、词语和句子。第七届国际学习代表大会,ICLR 2019 。http://nscl.csail.mit.edu
Sovrano,F. (2021),现代人工智能对可解释性的需求,博洛尼亚大学信息学院

图一。Andrew "Donovan" Valdivia 在 Unsplash |和图 2 上拍摄的照片。照片由凯利·麦克林托克在 Unsplash 上拍摄
21 点:将人工智能应用于网络安全的游戏模型
原文:https://towardsdatascience.com/blackjack-a-game-model-for-applying-ai-to-cybersecurity-206746f46aa5?source=collection_archive---------20-----------------------
人工智能校准和安全
博弈论、强化学习和信念更新如何模拟网络冲突与合作

照片由安娜·施韦茨从派克斯拍摄
网络攻击继续威胁着大大小小的组织。数据泄露或勒索软件攻击的影响可能会对客户和股东产生重大影响。为了帮助应对网络威胁,一些组织已经开始探索大数据和人工智能(AI)如何帮助降低网络安全风险。
机器学习算法现在在网络安全中很常见。我们发现在更多的商业产品中提供了机器学习,从那些完全集成到产品中并且不需要机器学习知识的产品到那些需要卷起袖子来整理算法并执行统计分析的产品。用于网络安全的机器学习最常被应用于检测代表攻击的模式。这包括评估审计日志数据、发现网络入侵检测系统的异常以及识别和阻止计算机系统上的恶意软件的算法。
在一些应用中,机器学习被用来训练网络上正常活动的模型,希望以后能够检测到可能代表网络攻击的异常事件。机器学习在网络安全中的当前使用包括监督和非监督方法。
尽管机器学习越来越多地用于网络安全,但人工智能的使用却很少。换句话说,我们使用算法来检测模式,但我们很少使用算法来自主决定最佳行动方案。
从表面上看,机器学习应该非常有利于提高组织的网络安全,但仔细一看,有一个重要的弱点。机器学习完全是关于学习者的。它的重点是创建一个足够精确的模型来检测数据中的重要特征,而不会过度拟合。机器学习经常忽略的是,在学习的同时,它也在教导网络冲突与合作游戏中的其他参与者。
网络安全不是一个静态的游戏。规则不断变化。有许多不同类型的玩家,每一种都有自己的目标、战略和战术。当一个组织调整它的防御时,攻击者改进他们的攻击,要求该组织进一步改进它的防御。结果就是无休止的升级游戏。
这与机器学习的大多数传统应用非常不同,传统应用进行预测,对数据进行分类,并利用不包括对手的数据检测异常。在网络安全中,安全管理员采取的每个行动都可能通知攻击者,并可能导致下一次攻击中不可预测的变化。
为了从机器学习的基本模型转向人工智能,我们需要超越模式检测来理解这个升级游戏。如果我们应用博弈论来探索多智能体游戏中的战略决策,我们就可以开始应用人工智能。
博弈论
博弈论的工具有助于评估不同代理人或玩家的决策和行为。博弈论试图根据一个玩家可能做出的决定来寻找另一个玩家的最佳决策。有了它,我们可以将网络安全建模为一个游戏,以了解安全管理员的行为如何影响攻击者的决策并与之互动。使用这个模型,我们可以开始探索人工智能和大数据的潜力,以更智能地保护计算机系统和数据。
战略决策的博弈论可以追溯到 1713 年,但直到 1928 年约翰·冯·诺依曼才将其正式作为一个研究领域。作为博弈论一部分的流行游戏包括囚徒困境、美元拍卖、公主和怪物游戏以及最后通牒游戏。但是当考虑到网络安全的复杂性时,这些游戏是非常简单化的。
西蒙·西内克写了一本非常平易近人的关于博弈论的书,《无限游戏》 [1]。在书中,他建议组织中的领导者经常将战略决策视为有限游戏,有开始也有结束。有赢家和输家。反而大部分游戏都没有结局。这些无限游戏的目标不是赢,而是留在游戏中。
当将博弈论应用于组织中的网络安全时,乍一看,网络安全似乎是一个无限的游戏。该组织的目标是阻止网络攻击,但永远不会结束。安全经理的目标是留在游戏中,并确保组织的防御措施足以让组织继续完成其使命。但这种简单化的博弈论观点足以描述网络安全的复杂性吗?
21 点中的竞争与合作
在探索与网络安全相似的现有游戏模型时,常见的模型似乎不够充分。网络安全是什么类型的游戏?找到一个模型的挑战是因为不同的玩家对网络安全的玩法非常不同。这不是一个简单的决定游戏是有限的还是无限的,因为对一些玩家来说它是有限的,但对其他人来说目标是留在游戏中。
赌场游戏有助于将博弈论应用于现实世界的问题。以 21 点游戏为例。在这个多人游戏中,我们可以考虑三个主要的战略决策者。首先是赌场老板,我们称他为房子。接下来是庄家,他执行接战规则,代表庄家执行游戏。最后,还有玩家。
在 21 点中,每个玩家都直接与庄家竞争。虽然有多名玩家坐在桌旁,但每个人都用自己的牌来对抗庄家的牌。在最简单的层面上,每个玩家的目标是比庄家更接近总牌值 21,而不超过。对于每个玩家来说,这个游戏是非常有限的。每一轮,玩家不是赢就是输。玩家决定下多少注,除了下注之外没有任何风险。
另一方面,庄家使用一套预定义的策略与每个玩家竞争,这些策略使庄家在多轮比赛中稍占优势。同时,经销商与公司合作,始终遵循公司制定的规则。庄家是庄家的代理人,并不根据每一轮的结果直接获利或损失。这种合作使经销商能够赚取工资并继续工作。结果,庄家在一系列短暂的有限游戏中与每个玩家单独竞争,但仍与庄家合作以留在游戏中。
最后,赌场的目标是赚钱,雇佣劳动力,并为顾客创造一种赌博体验,让他们不断回头。为了做到这一点,它的策略是利用对它有利的赔率,并仍然允许玩家定期获胜。结果,房子本质上与玩家合作,同时与他们竞争。
在 21 点中,我们既看到冲突,也看到合作。我们看到球员以短期的眼光竞争,目标是获胜。我们也看到经销商从长远角度竞争,目标是留在游戏中。我们看到这个房子合作创造了一个支持游戏的环境。但是本文的目标并不是将博弈论应用于 21 点,那么这与网络安全有什么关系呢?
网络安全和 21 点模式
要从 21 点的角度来看待网络安全,请考虑玩家之间的关系。相当于房子的是组织。组织存在的目的是为股东创造价值,保持利润,并为人们创造机会,将他们的技能和专业知识一起用于共同的目的。这与我们 21 点模型中的房子非常相似。大多数组织的目的不是防御网络攻击。相反,组织通过确保网络攻击不会阻止他们执行其主要功能来管理风险。
安全经理相当于经销商。安全经理可能是高管,如大型组织中的首席信息安全官,或者是负责网络安全的信息技术负责人。安全经理和经销商一样,遵循既定的最佳实践。安全经理与组织合作,确保有足够的资源投资于安全实践,以维护组织的目标。安全管理器定期与攻击者竞争。像庄家一样,安全经理与每个攻击者进行一对一的竞争,并认识到会有赢有输。最终,安全经理通过遵循最佳实践并确保尽管攻击者可能赢得一些冲突,但他们最终不会对组织产生负面影响,从而留在游戏中。
网络冲突中的攻击者就像 21 点中的个体玩家。每个人都坐在桌子旁,并愿意在可能导致胜利的攻击上下注。对于攻击者来说,胜利可能是对组织网络的初步破坏。可能是盗窃知识产权。它可能是组织数据的加密,以迫使支付赎金。攻击者通常玩一个有限的游戏。它们的区别在于,与组织防御攻击所需的投资相比,攻击的成本可能非常低。此外,攻击数不胜数,而归因于攻击的能力有限,因此起诉很少。攻击者可以保持一种不对称的优势,并面临很小的风险,因为他们几乎没有不利方面。
因此,我们看到 21 点游戏和网络冲突与合作之间有一些有趣的相似之处。但这些相似之处还不足以开始应用人工智能。
用 21 点模型计算收益
为了建立一个对人工智能有用的模型,我们需要一些方法来计算每个玩家的最佳决策。在博弈论中,最基本的表示法是矩阵,被称为博弈的战略形式。矩阵的每一面代表一个玩家,以及他们可能采用的策略。在每个参与者策略的交叉点,我们计算每个参与者的收益。回报可能有多种形式。它可以用一美元的价值来具体表示。它可以被抽象为估计期望效用。有些收益是负的,代表玩家的损失,有些是正的,代表收益。下表提供了 21 点的名义回报矩阵。

作者图片
在这个简单的模型中,我们不会考虑支付的概率或金额。我们根据预期效用来衡量支出,其中 1 是潜在的好结果,1 是潜在的坏结果。每个单元格中的第一个数字代表玩家的期望值,第二个数字代表庄家的期望值。举个例子,庄家很可能已经指示庄家,当他们的牌的总价值大于 16 时,千万不要出手。即使是偶然的,当庄家的牌大于 16 时,他也不会与庄家合作,这可能会导致不好的结果,比如被炒鱿鱼。结果,当总牌值大于 16 时,发牌者击中牌的期望值总是负 1。
同样,当牌大于 16 时,建议玩家不要受到打击。因此,我们可以排除这两种策略,并认识到玩家和庄家更有可能遵循上表中突出显示的策略。如果你是一个有竞争力的 21 点玩家,你可能会批评这个模型没有显示什么时候双倍下注,什么时候拆分对子,或者什么时候投降。耐心点。这个例子只是游戏的一个简单的表现。
在博弈论中,就像上面的例子,我们可以寻求消除劣势策略,并找到一个纳什均衡,确定双方都可以接受的结果。在博弈论的简化模型中,也许可以在一页上分析这些决策,并直观地找到最佳决策。即使像 21 点这样的基本游戏也比支付矩阵的单一视图能够有效建模的游戏复杂,因为 21 点是一种顺序游戏。更复杂的游戏模型使用一棵树来表示连续的决策。根据其他玩家可能做出的决定,可以反复探索这些树以找到最佳收益。
在将人工智能应用于多智能体系统时,博弈论可能非常有效[2]。但是简单地推导纳什均衡可能并不能预测最佳决策,因为我们面对的是各种各样的决策、不同的目标和不完善的信息。研究发现,纳什均衡的简单计算在复杂的多主体游戏中表现不佳[3]。
这就是支持人工智能的算法可以发挥作用的地方。强化学习可以探索博弈树,并了解对手的决策应该如何影响自己的决策。强化学习可用于在模拟中反复玩大量游戏,以获得如何获得最佳回报的第一手信息。
信念更新在迭代遍历博弈树计算收益时也很有帮助。由于大多数网络冲突游戏都包含不完全信息,因此包含一个信念分数可以模拟不同类型攻击的概率,并可能有助于与强化学习相结合。使用进化方法将强化学习与信念更新相结合的模型可能会成为安全经理手中的强大工具,他可以决定下一步如何保护组织。
付诸实践
我们已经达成了将人工智能和博弈论应用于网络安全的高级概念。我们已经确定了可以帮助组织做出实现最佳回报的决策的算法。我们准备好用算法取代安全管理器了吗?还没有。
安全经理有许多战略和战术,他们可以应用来保护他们的计算机和数据。NIST 网络安全框架[4]是网络安全的五个核心功能的综合集合,每个功能都分为类别和子类别。总共有 108 个子类别的安全活动供经理们选择。攻击者同样拥有丰富的已知战术以及少量新颖的攻击手段。如果同时进行,对所有这些排列进行建模将是一项挑战。
首先,我们可以选择一组范围更窄的安全决策。举例来说,我们可以将其应用于漏洞和补丁管理。组织经常努力跟上漏洞的数量,并且无法在对手利用它们之前修补关键漏洞。安全经理必须根据漏洞的严重性、有助于缓解漏洞的环境因素、系统停机维护窗口的可用性,以及为组织增值的项目的竞争优先级来确定优先级。如果修补决策是由我们的人工智能算法做出的呢?
要将此建模为一个游戏,首先考虑攻击者可能的动作。攻击者可能试图利用已有多年可用补丁的旧漏洞、组织可能尚未修补的新漏洞,或者不存在补丁的零日漏洞。对于攻击者来说,每一种方法都有相关的成本和潜在的好处。
现在考虑安全管理器可能的操作。安全管理员可以使用策略来立即部署所有修补程序,根据安全区域部署修补程序,或者根据漏洞的严重性划分优先级。这些没有对错之分,但是根据攻击者的决定,有些可能比其他的更好。
每个行动都有成本和收益。我们可以将每个玩家的收益估计为高(3)、中(2)或低(1)。我们同样可以将成本估计为高(1)、中(2)或低(3)。请注意,该量表的值是颠倒的,以表明最低成本比更高成本的决策更有益。然后,我们可以将估计值计算为收益减去成本。
在高层次上,这个游戏的战略形式可能如下表所示。

作者图片
如果我们首先从攻击者的角度来看,很明显使用零日漏洞具有最低的预期价值。最好的选择是利用旧的漏洞。因此,我们可以预计,攻击者将总是试图利用旧的漏洞,然后花费所需的成本来利用新的漏洞或零天。因此,在这个游戏中,我们可以消除攻击者利用新漏洞或零日的策略。
有了攻击者可能的决策,安全管理员最好选择在旧漏洞列中具有最高期望值的策略。我们排除了前两行,发现最佳决策是根据严重性打补丁。在我侮辱正在阅读这篇文章的安全管理人员之前,这些期望值只是针对这个例子的。您可能会以不同的方式看待这些策略的成本和收益,或者有一个比这里列出的更好的策略。这仅仅是为了说明。
在这个例子中,我们可以看到,安全管理人员应该根据攻击者首先利用旧漏洞的理性决策来创建一个策略。作为一个战略决策,这可以抓住一个安全程序应该如何优先打补丁的哲学。但这还不是 AI。
在实际组织计算机系统的情况下,我们可以用实际数据替换这些高级期望值。我们算法的输入可以包括表征攻击面的网络模型。该算法可能具有关于组织的已识别漏洞及其严重性的数据。该算法还可以知道组织愿意使用什么中断窗口来修补系统。它甚至可能包括安全事件数据,有助于识别遭受攻击最多的系统。
将所有这些数据放在一起,学习算法可以通过创建各种游戏树并根据攻击者的决策计算不同修补策略的收益,来扩展这个简单的收益矩阵。这将是人工智能在网络安全领域取得进展的重要一步。该算法将使用人工智能来预测不同修补策略的最佳回报。它甚至可以根据可用补丁的数量和严重性来改变策略。它可以通过遍历游戏的数十万种排列来选择最佳收益。
预先定义了一组打补丁的规则和优先级的安全管理员无法执行与该算法一样多的分析。凭借对算法决策的信心,可以通过在对组织最有利的时候自动部署补丁,使用自动化来控制漏洞。在完全信任算法的决策之前,算法可用于决策支持,以帮助确定最重要的缓解活动的优先级。
结论
网络安全中的人工智能需要清楚地了解如何对网络冲突和合作进行建模。可以使用博弈论对网络安全进行建模的算法有可能降低组织的网络安全成本,同时提高其安全性。这一点尤其重要,因为网络安全是一场不对称的升级游戏。
需要进行更多的研究和开发,以使其对组织及其安全管理人员更有用。虽然一些研究和商业产品开始探索人工智能的安全功能,如补丁和漏洞管理,但还有许多其他安全功能可能受益于人工智能增强。
参考
[1] S. Sinek,《无限游戏》,(2019),企鹅出版社
[2] Y. Shoham 和 K. Leyton-Brown,多智能体系统:算法、博弈论和逻辑基础,(2008),剑桥大学出版社
[3] N. Feltovich,实验性非对称信息博弈中基于强化与基于信念的学习模型,(2000),计量经济学,68(3),605–641
[4] M. P. Barrett,改善关键基础设施网络安全的框架,(2018),马里兰州盖瑟斯堡国家标准与技术研究所
在 B2B 产品创新中融合精益、设计思维和共同开发——团队回顾
原文:https://towardsdatascience.com/blending-lean-designing-thinking-and-co-development-in-b2b-product-innovation-a-team-7b9944c59302?source=collection_archive---------18-----------------------
行业笔记
允许我们“深入”的方法组合,同时抵消了构建“一次性”(以及我们会采取的不同做法)的风险
作者:梅森·王茂林,乔贝尔·布劳恩,尼克·科恩和蒂博·杜本内

照片由塞尔吉奥·索萨在像素上拍摄
简介
B2B 环境下的产品研究比消费产品更困难,因为潜在参与者相对较少,他们的使用案例复杂,并且由于他们的时间价值高而难以访问。因此,B2B 产品团队可能会决定放弃他们的消费者同行采用的大规模独立研究类型,而是选择直接与个人客户共同开发他们的产品。
共同开发(或共同创造)是一种有价值的 B2B 创新技术,可以产生对客户特定的深度理解,以及专有数据、竞争对手情报和 IT 生态系统细节等有价值的资源。然而,寻找合适的参与者和管理联合开发项目非常耗时,产品团队可能会发现他们实际上只能与一个客户进行联合开发。不幸的是,如此密集地接触一个客户,往往会放大建立一个单一市场的风险。
那么,产品团队如何才能达到来自高度参与的共同开发的理解程度,而不牺牲来自接触许多客户声音的市场视角呢?这是 Teralytics 的 Streets 产品团队面临的挑战,它引导我们找到了本文中描述的混合方法。

与几个客户群体的共同开发比短期、大样本研究方法产生更深刻的见解,比仅与一个客户共同开发产生更广泛的验证。作者照片。
目标&接近
Teralytics 将机器学习和启发式模型应用于来自数百万电信用户的匿名移动数据,以帮助我们的客户了解他们所在地区的人类移动模式。
2020 年夏天,来自我们市场的信号表明,我们道路规划部门的客户需要将车流量分配给各个路段。这些信号是我们称之为“街道”的新产品的推动力。
我们最初的目标市场包括德国中小城市的数百个交通规划部门。这些实体遵循复杂的流程,并依赖于高度准确(地面实况校准)的数据——这些条件受益于典型的合作开发的洞察力深度。然而,由于我们的许多客户受到公共预算的限制,我们也需要一种方法来帮助我们开发一种核心产品,这种产品将满足大多数客户的需求,而不需要为每笔交易进行昂贵的定制。

在我们的 MVP 测试中,我们借鉴了几十个客户的观点,而后面两个阶段的重新发现和共同开发涉及到四个客户。作者照片。
我们在此描述的流程跨越了整个上市生命周期,从客户和产品发现一直到向收入客户推出和交付功能性产品。这个过程由我们在三个阶段应用的完善的方法组成:MVP 测试、重新发现和共同开发。
第一阶段:MVP 测试
为了避开寻找愿意自愿参与数小时研究的客户的困难,我们对最终的 Streets 产品提供了折扣,作为在其开发过程中参与研究会议的激励。衡量客户的金钱和时间的价值交换对未来产品交付的吸引力是我们用来评估 MVP 假设可行性的测试。
“看看向参与的合作伙伴客户收取象征性的费用。。。这改变了参与/激励的动力,从你想从他们那里得到的东西,变成了参与的特权。”
创新委员会
1.1 开发我们的 MVP 假设检验
我们希望用 MVP 测试的首要假设是,有交通用例的客户愿意为来自移动数据的道路级洞察付费。我们在假设管理练习中记录了这一点和其他关键假设,我们内部称之为“流言终结者”,其中我们记录关键假设,然后确定实验类型和每个实验的成功标准。

流言终结者工作表记录了假设、实验类型、成功指标和收集的证据。作者照片。
我们为产品假设选择的测试是试图在开发之前销售一个 MVP。我们认为,说服三到五个客户(占我们总可用市场的 2-3 %)为我们产品的未来交付预付费用可以被认为是足够的吸引力。由于我们流程的后期阶段会涉及定性方法,我们对这一特定阈值的选择受到了 Jacob Nielsen 的观点的影响,即三到五名同质参与者是定性研究最有效的样本量。
梅森——首席采购官:
在过去的新产品开发中,“从哪里开始”这个令人生畏的问题一直困扰着我的团队,但《流言终结者》列举我们的信念,然后开发实验来测试它们的过程是一个打破最初的麻痹并快速开始验证的好方法。
乔贝尔——UX 设计经理:
在我之前加入的组织中,产品和技术发现通常发生在筒仓中,想法存储在各种文档或融合页面中。《流言终结者》的好处在于,它允许从团队中的所有声音中产生假设,建立共识。
1.2 构建 MVP
有了按价值(按设计和产品)和技术可行性和风险(按工程师)排列优先级的特性假设列表,我们现在可以开始界定我们的 MVP 产品了,但我们首先必须决定 MVP 的类型。

从无产品到最小产品的 MVP 类型——Streets 采用“先卖后建”的方法。作者照片。
精益实践者开出了各种各样的 MVP 风格,从价值主张的简单表达一直到第一个功能的发布。我们发现客户和最终共同开发的双重目标迫使我们尽可能接近“无产品”MVP,同时仍然表达一个足以实际激发购买的概念。幸运的是,我们行业中的解决方案倾向于在交付前作为定制项目销售,因此成品通常不是开始销售所必需的。

我们的“先销售后构建”MVP 包括一个推介资料、一个可点击的演示、一个演示脚本、一份产品规格和一份面向客户的评估协议。作者照片。
为了让我们的销售团队能够传达我们的主张,我们创建了一个包括定价、详细介绍核心功能的产品规格文档、一个可点击的演示以及一个演示脚本的推介资料。我们的行动号召是让客户预先支付标准价格的 5%作为加入“测试版”计划的报名费。在整个开发过程中保持参与的客户可以将该费用用于购买打折的年度订阅。
梅森——首席采购官:
在理想的情况下,我们应该在构思解决方案假设之前进行广泛的发现研究,但是在我们的领域很难接触到客户进行研究。因此,我们在这一点上所设想的一切都是猜测。假设是好的,但是乔贝尔非常擅长她的工作,即使是我们最可疑的想法看起来也令人震惊。我太倾向于创造一个令人信服的命题,以至于我们的概念“太真实”,这使得说服客户在以后批评我们的功能假设变得更加困难。
乔贝尔——UX 设计经理:
如何通过公开邀请共同创作来展示产品的可能性?事实上,销售团队展示的概念证明在一个抛光的原型中有很多功能,它可能会发出信号,“嘿,这是一个很酷的成品。”任何试图销售带有概念验证的产品合作开发的人都可能会考虑减少提议的想法和功能的数量,而不仅仅是设计的保真度。
thi baut——高级交通建模专家:
从工程的角度来看,构建 MVP 就是评估由设计和产品提出的产品功能的可行性。我刚开始在公司工作,与一位在公司工作了 6 年的工程师合作。总的来说,这种结合效果很好:我新鲜的眼睛让我贡献新的想法,而他的经验让他快速识别与我们的 MVP 范围相关的潜在风险和资源。
1.3 选择参与者
手头有了推销材料,我们现在需要一份销售线索清单,这样我们就可以开始销售了。重要的是,我们选择潜在客户的方法会产生一个与我们定性研究阶段相一致的样本。我们最终选定了研究人员所说的“标准-i 抽样”,这是一种常用的非概率“有目的抽样”方法,它依赖于预先确定的标准来定义样本框架。
方便的是,这种技巧看起来很像建立理想客户档案 (ICP)的销售实践。因此,我们的样本框架和线索列表包括了我们最初目标细分市场中的公司,特别是人口在 50,000 到 150,000 之间的德国城市的交通规划组织。签署预购协议的前五家公司参与了随后的发现和验证研究活动。
梅森——首席采购官:
事后看来,仅仅根据客户与目标角色的契合度和购买意愿来选择与他们进行数月合作开发的客户,可能是一个太低的标准。这些标准对评估客户的文化与创新的兼容性没有太大作用。早期,一些客户似乎对参与开放式发现感到不舒服,他们期望一个更加线性的产品开发过程。
1.4 测量牵引力
我们用两种方法来评估 MVP 的接受度:转化和反对。
签署购买协议的正式转换步骤是对我们价值主张的有力验证,因为它涉及产品交付前的部分财务承诺。这项工作还有一个附带的好处,那就是在早期暴露任何采购障碍,从而简化最终的完整许可证采购。协议步骤也是澄清知识产权所有权等主题的机会,同时通过限制对范围或时间表的期望,为开放式创新奠定基础。
吸引潜在客户的目的是转化他们,同时试图向他们学习,这是一种微妙的平衡,需要一种不同于产品/市场适合产品的标准销售的方法。为此,我们鼓励我们的销售代表不要试图“推销”异议,而是倾听并探究“为什么”。
“如果会议过多地是关于销售,那么通过询问潜在客户对解决方案的反应,你实际上缩小了对话的范围。会议不再是寻找最佳机会。。。这是为了让潜在客户相信,你的广泛价值主张是有意义的。”
艾蒂安·嘉宝莉,莱安·B2B
在这一过程中,我们安排了与销售团队的每周汇报会议,讨论他们的发现,目的是根据现场的反应重复或改变我们的主张。为了帮助我们识别调查结果中的模式,我们对收到的异议进行了分类,让我们可以通过下图这样的图表来直观地了解我们推销中的摩擦来源。

推介回顾帮助我们量化了 MVP 初始推介期间出现的意见和异议的类型和频率。作者照片。
最终,我们的销售代表达到了五个有购买意向的客户的门槛,而不需要修改我们的推销。然而,由于与我们的价值主张无关的合同条款,与一个客户的谈判最终停滞不前;因此,我们从四个客户开始了我们流程的第二阶段。
梅森——首席采购官:
让我们的销售代表将此作为学习练习并定期参加汇报会议非常困难。在很大程度上,我认为我们的销售代表将此视为典型的销售。这也许是可以理解的,因为除了首席执行官偶尔的督促,我们没有建立任何特殊的激励机制来鼓励他们以不同的方式对待这一点——这种“学习活动”最终会偏离他们的销售目标。
第二阶段:重新发现
我们通过 MVP 获得的稳固牵引力是一个信号,表明我们的市场重视这些能力,但我们还不知道“为什么”。我们仍然需要了解我们的主张所支持的用户目标,这些用例对我们用户的工作有多重要,这在哪里适合他们的工作流程,以及我们产品周边的供应商和解决方案的生态系统。
2.1 旅程映射
我们将在项目启动会议上回答这些问题。这些会议的形式是一个四小时的(虚拟)研讨会,由代表每个客户的三到六名用户和决策者参加。为了实现研讨会的客户发现目标,我们首先需要参与者基本上“忘记”我们向他们推销的 MVP,而是告诉我们更多关于他们自己和他们工作的信息。
创建旅程图的过程迫使整个团队进行对话并形成一致的思维模式。。。这一共同愿景是旅程规划的关键目标。”
—尼尔森诺曼集团的莎拉·吉本斯
启动研讨会的核心是旅程规划练习,这是一项大量借鉴设计思维概念的技术。在这里,我们要求参与者列出一个“长列表”,列出他们角色中最重要的活动和目标。从这个长长的列表中,参与者选择一个目标进行深入研究,向我们介绍实现该目标的步骤、时间表、人员和问题。

我们在每次研讨会期间在 Miro 中捕捉到的路线图包括时间表、步骤顺序、主要参与者以及参与者所选目标的挑战。作者照片。
梅森——首席采购官:
这些研讨会的前 10 分钟很紧张!我们必须让参与者从销售过程中设定的产品即将完成的预期中走回来。尽管我们传达了信息,但我们演示的高逼真度给潜在客户留下了产品比实际更完整的印象。一旦我们重新设定了期望值,研讨会的其他部分就很棒了。在几个小时内,旅程地图帮助我们精确定位了客户最重要的工作流程中街道可以增加实际价值的区域。
乔贝尔——UX 设计经理:
参与者主要是说德语的人,我不能低估有一个母语主持人有多重要,他可以发现语言中的细微差别,并允许自然的对话流。在第一个研讨会中,现状路线图是从参与者典型工作流程的角度进行的,而不是对实际事件的叙述。我们在随后的研讨会中对此进行了更改。由此产生的对具体案例中实际发生的事情的强调引发了更有意义的讨论。
nick——高级产品经理:
在研讨会期间,由于缺乏数据和工具,与会者表达了对现状的强烈不满。这澄清了他们参与计划和投资潜在街道产品的动机。研讨会似乎允许客户在安全的环境下反思他们的工作,这引发了参与者之间关于他们真正的优先事项和挑战的一些对话。这些讨论为我们提供了对客户问题的坦诚和真实的看法。
2.2 重新审视我们的解决方案
在与来自四个客户的 13 名参与者进行了 16 个小时的研讨会后,我们对用户的角色、目标、难点和背景有了足够深刻的理解,能够围绕这一背景重新定义我们的产品假设。
我们最初的一些假设在研讨会上得到了验证。例如,我们认为小城市缺乏数字工具来应对和决策市民不断变化的出行行为,这一观点被证明是正确的。另一方面,我们揭穿了一个重要的假设,即实时交通是这个用户群的需求。
综合我们的发现后,我们更新了最初的任务流程,省略了多余的步骤,专注于我们现在理解的核心流程。从这个核心,我们得出了一个新的基础范围,这将作为我们共同发展的基础。
nick——高级产品经理:
很明显,在最初的研讨会之前,客户就已经在思考新产品可能对他们有什么帮助,所以他们准备了一份需求清单。当我们与他们一起定义他们最重要的用例时,他们最终都给予了交通量最高的优先级,即使是与公共交通相关的用例。对“核心”产品定义的补充在关键时刻到来,当客户能够看到演示并通过触摸测试原型时,他们对设计和内容功能反应热烈。除了两个关键的例外,这些增加是对最初“核心”的重大改进,而不是重大转变。
乔贝尔——UX 设计经理:
综合我们在研讨会期间收集的丰富信息后,我们更好地了解了客户的经常性需求和目标。这给了我们下一次迭代所需要的焦点。我觉得自己像一个雕塑家在凿石头。一些最初的流言终结者假设已经被证实,而另一些被证明对我们的产品来说是不必要的。我们的团队对于保留在我们的研讨会中不被支持的功能并没有辩解。这确实是这个过程应该做的,很高兴看到它的工作。我们利用我们的学习来简化我们的任务流程,并总体上重新设想我们的产品。
thi baut——高级交通建模专家:
在这一阶段,Nick 不仅倾听客户的意见,也倾听团队的意见。例如,了解到客户对交通速度不感兴趣是一个受欢迎的发现,因为我们不确定我们能否准确地得出这些数据。另一方面,受到客户最热烈欢迎的功能之一(我们称之为“蜘蛛分析”)并没有被客户明确提及,而是由团队在我们进一步了解客户的目标后提出的。因此,我们决定制作第一个原型,稍后在我们的互动研讨会上展示。
第三阶段:共同开发
尽管与客户合作这一显而易见的概念似乎是一个复杂的术语,但客户共同开发(或共同创造)是一个合适的理论空间,有正在进行的研究,越来越多的文献,不同的方法,以及私营部门咨询。
与设计思维等其他以客户为中心的方法相关但不同的是,与前者相比,共同开发倾向于与相同主题进行更长时间、更密集的互动,以及更多地参与解决方案开发。
“设计思维有助于通过深入的用户观察创造价值,而共同创造的目的是通过用户互动创造价值。”
——2016 年芒索法布里赫莫内特-古约特
共同开发佳能通常假定与单一领先客户的联合创新,我们同时与四个客户合作背离了这一原则。我们的方法使我们避免了建立一次性项目的风险,因为可能将我们引入错误道路的个人请求可能会与我们其他项目参与者的需求进行近乎实时的核对,从而不断将我们保持在“金发女孩”区域。
3.1 解迭代
在联合开发中,“客户主导”和“客户验证”同样有效,但供应商应仔细考虑哪种方法最合适。由于我们的 Streets 产品团队拥有广泛的领域、设计和工程技能,我们相信我们有能力领导解决方案的开发。通过率先行动,我们可以将解决方案的空间构建为可行性和财务可行性,在此范围内,我们的内部设计能力和客户参与的结合确保了高水平的创造力。
每隔几周,我们将举行一次回顾迭代,我们将通过提出越来越逼真的解决方案概念来引导,然后客户将在这些概念的基础上做出回应和思考。我们以这种方式持续了两个多月,在每次迭代后进行验证的同时进行设计和开发,直到我们开发出第一个功能完整的产品。

中间前端原型的屏幕截图,带有一小组真实的数据,在可用性测试期间生成了有意义的响应。作者照片。
这一旅程中的一个重要里程碑是我们第一次“可点击”体验的交付。这允许我们开始测试可用性,同时进一步验证价值和我们的解决方案实现。有了这个版本,客户实际上可以登录并测试我们对他们用例的实现。我们记录了与每个人的一对一会谈,并根据我们观察到的用户反馈模式改进了我们的方法。
nick——高级产品经理:
随着我们在每次迭代中提高我们概念的保真度,我们收到了更加具体和可行的反馈..例如,我们构建的一个用例是“选定链路路由分析和显示”。我们在一个交互式会话的上下文中演示了它。虽然这是交通规划领域中一种众所周知的分析类型,但对客户来说却是全新的,他们很快就兴奋地使用它来回答许多与用例相关的工作问题。通过这种方式,我们验证了这是核心产品的重要组成部分。
在这个过程的所有步骤中,与四个客户迭代是最耗时的。我们测试了将多个客户合并到一个会话中,但发现这并不能节省时间。对我们来说,从每个参与者那里获取反馈显然非常重要,而且客户也希望他们的具体反馈能够被听到,而不仅仅是参与小组讨论。
乔贝尔——UX 设计经理:
在一次迭代中,我通过电子邮件将漫威的原型发送给客户以获得反馈,但是这种异步方法没有产生太多的响应。从那时起,我只在我们的现场会议中分享原型并寻求反馈。事后看来,我们不应该期望参与者在既定的会议节奏之外参与共同创造。
当我们在可用性会议上展示高保真度模型以进一步验证用例及任务时,参与者的反馈反而集中在数据的“虚假性”和“看起来不错”上这令人沮丧,因为这些会议并没有产生高质量的体验反馈。只是到了后来,一旦我们开发了一个包含少量真实数据的测试应用程序,参与者才会真正地参与到这些概念中来。在这些会议中,他们详细阐述了他们将如何处理这些数据,这些数据是否看起来可信,以及他们可以使用该产品完成的其他潜在用例。
thi baut——高级交通建模专家:
研讨会的形式允许我们采取一种“快速而肮脏”的方法来制作原型:在某些情况下,我们的可视化软件在构建它的工程师的机器上运行,并且通过浏览器的控制台选择链接:唯一能够实际操作它的人就是构建它的人。只有当我们看到积极的反应时,才开始在实际的 UI 中集成可视化的完美版本。
作为数据计算需求的反馈来源,与客户的持续互动非常重要。然而,一旦我们开始向客户展示他们特定领域的数据(这有利于保持他们的参与,并帮助我们评估我们的第一个结果的“表面有效性”),交付新数据版本的压力就出现了,并在一定程度上干扰了开发的研究方面。事实证明,在我们正确地自动化我们的计算管道的各个步骤之前,向客户交付定期更新非常耗时,并且我们必须在方法被完善和测试的同时调试我们的数据源。
3.2 校准和质量
与客户作为合作伙伴共同开发的最有价值的好处之一是,他们愿意提供专有数据和真实世界测试条件,以及他们的一般专业知识。
我们通过利用客户对其所在地区的总体交通状况的现有了解,完成了第一步校准。在这里,我们向客户提供了他们网络上交易量的概况,以便他们可以用他们对我们产品准确性的高层次“印象”来回应。然后,更深入地研究,我们提供了一些与流量计数的现场位置比较,并在向他们介绍用例时,询问他们内容是否看起来可信。
基于我们的学习,我们多次重复我们的方法,越来越详细地审查与流量计数的比较。在这一过程中,除了已经公开提供的数据集之外,一些客户还提供了地面真实数据集,我们用这些数据集来调整我们的模型。
nick——高级产品经理:
需要注意的是,“地面实况”一词具有误导性,因为即使是客户也指出可用的交通数据是不完善的。一位客户提到,他们希望我们的数据实际上可以被视为事实,并显示他们有限的计数或调查信息哪里不正确。尽管每个数据集都有不完美的本质,但访问多个专有数据源有助于我们进一步验证和调整我们的模型。
thi baut——高级交通建模专家:
我们的宏伟愿景是能够以完全自动化的方式‘点击按钮’为新客户提供数据,而无需依赖客户数据或手动校准。因此,我们使用地面实况数据(公开可用的和客户提供的)只是为了检查结果的质量,而不是校准参数。能够仅在几次迭代中实现对该数据的合理拟合,而无需任何广泛的参数调整,这给了我们对我们的方法在规模上的可行性的信心。
同样值得注意的是,许多“可用”数据并不容易使用。特别是,流量计数通常以地图的形式提供,需要手动转换为机器可读的格式,并进一步手动映射以将计数站与网络定义相关联。由于没有时间对其进行适当的格式化,只有一小部分数据可以在联合开发阶段使用。
3.3 交付和投放
根据我们的合作协议,产品的第一个功能版本的交付将触发一个购买决策里程碑。在这一点上,根据我们共同定义和开发的内容,客户需要决定是加入折扣产品订阅还是放弃预付款。
我们的协议还包括非约束性语言,要求对产品满意的客户提供我们可以公开引用的认可。虽然这是可选的,但该计划的所有参与者都愿意这样做,这些报价已包含在我们的发布宣传资料中。
顾客的参与似乎有利于增强对公司的认知,愿意向他人推荐公司,以及更高的购买意愿和支付意愿
Schreier,Fuchs 和 Dahl,2012 年
对共同开发的实证研究表明,我们的参与者公开支持街道的意愿并不罕见。随着公司认知度的提高,在产品创新上的合作有助于吸引客户最终购买。虽然这是一个直观的概念,但对于任何考虑这种方法的成本和收益的人来说,这也是一个很好的指导。
nick——高级产品经理:
购买里程碑很难跨越,因为从技术上讲,这是一个销售代表应该管理的销售结束,但对我来说,决定产品何时“准备好”要求承诺是一个判断。在那之前,我们一直是在研究的基础上以同行的身份进行合作,所以很难回到商业对话上来。测试客户的反应各不相同:一些客户认为他们已经“接受”了产品开发轨迹并保留了预算,而另一些客户在开发项目过程中改变了对他们时间和预算的要求。总的来说,反应可以说是积极的和商业上成功的。
乔贝尔——UX 设计经理:
设计准备好发布意味着什么?在我们的案例中,一个高优先级可用性问题的综合,已经被记录和处理,并且有一个符合我们 Figma 设计和我们设计系统的前端。与前端团队一起,我们在频繁的 Slack 和 Zoom 要求澄清中完成了 JIRA 设计标签。团队中的每个人都对结果感到满意。设计永远不会结束,但是总是会积压一些优先级较低的问题。
thi baut——高级交通建模专家:
联合开发过程的一个重要方面是,我们只需要提供客户愿意购买的绝对最小的功能集。特别是,与客户的讨论清楚地表明,他们不需要频繁的数据更新就可以开始从产品中获得价值,这使我们可以在不构建自动更新基础架构的情况下发布产品。没有高质量的报告和在发布前解决数据生产的已知问题让我们感到紧张,但我们都知道这是第一个版本,重要的更新将很快跟上,这让每个人都可以放心。
总结
在评估了我们产品的第一个功能版本并了解了我们为即将到来的版本指定的路线图后,参与我们计划的所有客户都选择订阅并继续使用该产品。
从一个以高层次价值主张假设开始的项目开始,Teralytics 在五个月内就从一个在发布前已经销售了多次的产品中获得了收入。该产品一开始就取得了良好的势头,这是使用其他难以访问的验证数据开发的直接结果,这些数据被证明对产品质量及其上市前的开发、购买和领先客户的认可非常宝贵。
因为我们验证了我们的价值主张,并与多个客户共同开发,所以我们相信这一势头将会持续下去,更广泛的市场份额将会发现我们的解决方案比其他情况下更能满足他们的需求。
推荐
虽然我们开发街道的方法是成功的,但它并不完美。我们从这个过程中学到了很多,我们认为其他人也可以从我们的经历中受益。为此,我们向任何开发类似 B2B 提案的人提供以下建议:
- **参与费用:**共同开发可能是一个漫长的过程,通常需要几个月。进行金融投资的客户更有可能在此期间保持参与。
- **系统地提出假设:**通过将你对产品机会的所有信念和假设整理成目录,你可以开始消除新产品机会中典型的高度不确定性。
- **让产品参与推销:**产品团队成员从现场学习的最佳方式是实际参加销售会议。
- **调整销售激励:**虽然先学习后发展对一家公司整体而言非常重要,但这种重要性应该体现在如何激励销售代表招募共同发展合作伙伴上。
- **用低保真度的概念测试你的价值主张:**在 MVP 测试中,低保真度的线框图将传递关于产品成熟度的正确信息,同时保持对核心主张的关注,而不是对精致 UI 的关注。
- **找出“为什么”:**如果你的价值主张测试成功了,不要只把这个事实当作是一盏绿灯。进行跟进,以确定用户重视的功能及其服务的目标。在构建之前,使用上下文来重新设想您的产品范围。
- **为以数据为中心的产品校准原型:**一般的设计研究实践倾向于关注用户体验的保真度,首先用线框进行验证,然后详细阐述。然而,对于以数据为中心的产品,考虑何时增加原型中数据的保真度也很重要。很可能在你需要一个完美的用户界面之前,你需要用更高保真的数据进行验证。
- **与三到五个客户共同开发:**除了避免构建一次性产品的风险,如果您的产品受益于校准或培训数据,获得来自多个客户的数据肯定会提高您产品的初始质量。
- **澄清知识产权所有权:**通过避免最终开发成果的所有权模糊不清,保护你在合作开发过程中可能获得的商誉。
- **发布时合作:**由于研究表明,共同开发的合作伙伴自然倾向于购买你的产品,并成为你的产品的拥护者,所以确保你不要在工程完成后立即终止合作。如果您的客户愿意将他们的信誉借给您的市场推广工作,就让他们这么做吧!
参考文献
建立共同创新的企业。(2010 年 10 月 1 日)。哈佛商业评论。https://hbr.org/2010/10/building-the-co-creative-enterprise
Garbugli,E. (2014 年)。精益 B2B:生产企业想要的产品。创建空间独立发布平台。
赫蒙内-古约特,法布利,j .,,芒索,D. (2013)。设计思维 vs 合作创新:两种创新方法的比较。
征途映射 101 。(未注明)。Nngroup.Com。于 2021 年 9 月 23 日从https://www.nngroup.com/articles/journey-mapping-101/检索
梅里韦瑟,E. (2020 年 6 月 12 日)。区别:原型 vs MVP 。Productschool.Com。https://product school . com/blog/product-management-2/difference-prototype-MVP/
奥伊诺宁,M. (2014 年)。客户参与 B2B 市场的共同发展:关于关键贡献和成功因素的文献综述。
Palinkas,L. A .,Horwitz,S. M .,Green,C. A .,Wisdom,J. P .,Duan,n .,& Hoagwood,K. (2015)。混合方法实施研究中定性数据收集和分析的有目的抽样。精神健康管理与政策, 42 (5),533–544。
Pinder,M. (2019 年 1 月 30 日)。 B2B 共同创造:50 个关键的学习和见解——创新委员会。Boardofinnovation.Com。https://www . boardofinnovation . com/blog/B2B-co-creation-50-key-learning-and-insights/
k . reshetilo(2021 年 6 月 15 日)。什么类型的 MVP 适合你的创业?— Greenice。检索于 2021 年 9 月 23 日,来自https://greenice.net/type-mvp-right-startup/
Schreier、c . Fuchs 和 d . w . Dahl(2012 年)。用户设计的创新效应:探索消费者对销售用户设计产品的企业的创新感知。市场营销杂志, 76 (5),18–32。
b2b 市场研究的挑战以及如何克服这些挑战。(2019 年 6 月 5 日)。Businesscasestudies.Co.Uk。https://business case studies . co . uk/the-challenges-of-B2B-market-research-and-how-to-comprise-them/
理想客户档案发展框架。(未注明)。Gartner.Com。2021 年 9 月 23 日检索,来自https://www . Gartner . com/en/articles/the-framework-for-ideal-customer-profile-development
为什么只需要 5 个用户测试。(未注明)。Nngroup.Com。2021 年 9 月 23 日检索,来自https://www . nn group . com/articles/why-you-only-need-to-test-with-5-users/
盲棋日志[0]
原文:https://towardsdatascience.com/blind-chess-log-0-d6b05c6cf90c?source=collection_archive---------35-----------------------
部分观测环境的蒙特卡罗树搜索

作者出品。
欢迎来到盲棋日志索引 0。在这里,我计划与我的朋友格莱布·特卡切夫一起分享每周在机器学习宠物项目上工作的经历。该项目的目标是为侦察盲棋开发一个 ML 机器人,它不会做非常愚蠢的动作,也许能够击败一个随机的机器人。一套完整的规则可以在reconchess python 包的文档中找到。但简而言之,这是一种象棋变体,你看不到对手的移动,每次在决定你的移动之前,你可以选择 3 乘 3 的正方形,并在那里获得棋盘的实际真实状态。听起来很刺激?我们走吧…
相当大的探索
如果你通读侦察棋的规则并思考这里可能适用的 RL 算法,你首先想到的是什么?我敢打赌,对大多数读者来说,它是 AlphaZero。那当然不是没有原因的。但是,AlphaZero 无疑是一种“不要在家里尝试”的项目。尽管从概念上来说这是一个非常简单的方法,但它是由一群杰出的科学家和工程师用非常昂贵的预算建造的工程杰作。它的规模使得它不可战胜。当然,人们可以尝试为单台机器开发一些 DIY 克隆,但它训练一些合理行为的可能性相当小。

动画来自 Tumgir 。
知道了这一切,我们毫不犹豫地决定采用类似 AlphaZero 的方法。不过,我们有一个小小的借口。我们的目标不是重新实现 AlphaZero 的一对一,而是试图建立一种受它启发的东西,即一种结合搜索和学习的算法。
我个人最喜欢的 AlphaZero 鸟瞰图是,我们训练策略函数来压缩蒙特卡罗树搜索(MCTS)迭代和价值函数来预测未访问状态的价值估计。然后,我们使用这两种方法,通过用策略缩小搜索范围和用值函数引导估计来改进 MCTS 的收敛性。这使得即使在评估期间在有限的计算预算下运行,也可以计算强移动。原则上,考虑到无限的计算能力,人们可以只用 MCTS 来解决像围棋和国际象棋这样的游戏。因此,从实现 MCTS 开始,并让它发挥作用(即使相当悲惨)听起来相当合理。
问题开始的地方
方便的是,我有一个 MCTS 实现放在我未完成项目的私人墓地上。唯一的问题是标准 MCTS 适用于完全观察到的环境。相比之下,盲棋只能被部分观察到,因为你看不到对手的行动。这带来了一些复杂性…
MCTS 有自己的环境模拟器(游戏)来搜索可用的动作空间。为了从某个给定的状态运行搜索,我们需要能够将我们的模拟器重置到这个状态。你能看出问题所在,对吗?由于我们不知道状态,在部分观察环境的情况下就不那么简单了。在盲棋的背景下,如果我们假设对手的移动是模拟的一部分,我们可以只为第一个状态建立树,并且只在我们下白棋的情况下。在第一步之后,我们不知道对手棋子的实际位置,因此我们不知道从哪个状态开始寻找下一步。
**下面是后面解释的重点:**一个 MCTS 的内部模拟器,用于从一个单一的状态进行搜索,仍然可以返回给你真实的状态。你将把它编码,并自由地做任何你认为合理的事情。然而,这不会帮助你超越第一步,只有当第一个状态是已知的(如盲棋中的白棋手)。当然,在训练过程中我们可以黑任何我们想黑的东西,甚至可以让一个真实的模拟器还原对手的招式,还原真实的状态。但是这显然不能用于评估,特别是如果你的机器人应该和其他玩家进行一些在线比赛的话。
幸运的是,已经提出了相当多的方法来使 MCTS 适应部分观察的设置。我们发现大卫·西尔弗等人的POM CP(是的,那个家伙)是最简单和最容易实现的,并决定采用它。该方法的思想是将 MCTS 与真实状态的粒子滤波估计器结合起来。我不会详细解释这篇论文,但这里有一个摘要:
- 你通过行为和观察(而不是经典中的状态)来分支你的树,并且为你的树中的每个节点维护一组可能的真实状态。你还需要一个内部模拟器,除了观察结果之外,它还能返回状态(如上所述,它不是一个节目停止器)。
- 开始时,你从初始状态分布中抽取 N 个状态,这些状态应该是已知的(即使是盲棋也是这种情况),并将它们添加到根的集合中。
- 对于每一次 MCTS 迭代,也就是扩展和反向传播,你从当前根的集合中抽取一个状态,并重置你的模拟器。当您在树中移动时,您将内部模拟器返回的每个新状态添加到下一个节点的集合中,该节点对应于您获得的观察。
- 一旦你建立了一个树或者超出了你的计算预算,你就可以根据收集到的统计数据选择最好的移动,并把它提供给真正的模拟器。True simulator 只返回一个观察结果,您可以用它来选择树的下一级的正确节点,并将其提升到根节点。然后你重复第三步。
即使考虑到论文中提供的使你的状态估计稳定的众多技巧,这似乎仍然是解决 MCTS 部分可观测性的最简单的方法。因此,我们在晚上花了很大一部分空闲时间来实施它。在开始的时候,我们确实有点担心,不知道“感觉”动作(那些你得到一个 3x 3 正方形的真实状态)在这种方法中是否“有意义”。幸运的是,经过一些头脑风暴、绘图和编写第一个原型之后,我们意识到它们可以很自然地集成在一起。本质上,你把你真实状态的粒子估计散布在树的不同分支上,因为“好的”感觉动作揭示了额外的信息并导致不同的观察结果。理论上,这将减少状态估计的方差,一切都将顺利进行。然而,没过多久,我们意识到还有一个问题…
让我们一起玩吧
AlphaZero 的另一个被认为对超人表现至关重要的关键因素是自我游戏。对于 MCTS 来说,自我游戏是通过在同一棵树上以循环方式为两个玩家寻找最佳移动来实现的。
现在让我们忘记部分可观察性,假设我们正在为一些根状态构建一棵树,并根据我们之前收集的一些统计数据(或者如果统计数据不可用,则随机选择)选择一个动作。我们现在过渡到我们的对手必须采取行动的状态。那么我们应该采取哪一步呢?我已经提到过,最简单的方法是对对手使用一些固定的策略。然而,如果我们真正的对手有不同的打法,那就不行了。相反,在自玩 MCTS 中,我们将这个状态添加为节点,并从它开始继续树搜索,就像我们将为对手玩一样。本质上,当展开树时,你假设你的对手也使用 MCTS。这应该可以让你想出更强的动作。这种方法也可以很好地适应您的计算预算。一个额外的好处是,对于零和游戏(如国际象棋),将 MCTS 扩展到自我游戏并不需要太多,至少在概念上是如此。当反向传播对手节点的统计数据时,你需要做的就是否定一个玩家在首次展示中获得的奖励。当然,这需要一个足够通用的实现来跟踪玩家的 id 并仔细处理统计数据的更新。在相当多的“设计讨论”之后,我们设法实现了类似的东西,并且看起来工作可靠。
让我们回到我们的部分观察设置,在这里一切都变得“有点复杂”。现在,当为一个已知状态(例如,可能是初始状态)构建树时,由于我们的内部模拟器,我们仍然可以进行自我游戏。如前所述,我们确实对它有完全的控制权,我们可以通过某种方式实现它,以返回对手的观察和动作,这样我们就可以在它们上分支,并向我们的树中添加相应的节点。当我们超出了一步棋的计算预算,选择了目前为止我们发现的最好的一步棋,并将其输入到真正的模拟器中时,问题就出现了。模拟器的状态很先进,对手也做出了自己的举动,但我们对此一无所知。现在我们需要在我们的子树中找到一个新的根节点,它对应于再次轮到我们的观察,并且可能包含状态估计集合中的真实状态。因为我们不知道对手得到了哪个观察值,也不知道他选择了哪个移动,所以我们不知道要遍历哪个分支。因此,我们没有对当前真实状态的估计,也无法重置我们的内部模拟器来再次运行搜索…
抱歉,我知道没有一些图纸可能会很难掌握,但我真的不想把这些日志变成全取教程。否则,我会花更多的时间来准备这些,而不是实际参与项目。因此,如果你有任何问题,或者对这个话题感到兴奋,请在评论中或在 LinkedIn 上联系。我将很高兴与你讨论它。
当然,我们想到了一些简单的方法,比如遍历对应于玩家移动的分支,然后汇集并合并来自下一级对应于我们回合的子节点的所有可用状态估计。然而,这可能会给我们的真实状态估计带来相当大的差异。此外,根据规则,当对手抓住你的棋子时,你实际上获得了一些关于他的移动的信息。所以你可能会遇到这样的情况,你从孩子那里收集了一些状态,而这些状态对于你刚刚得到的新信息来说是不可能的。或者更糟,在你没有任何与新信息一致的粒子估计的情况下。无论如何,这听起来是最直接的开始方式,所以下周很可能会继续使用。
这就是盲棋日志的迭代。请继续关注大约一周后的下一次更新。
书籍写作模式分析
原文:https://towardsdatascience.com/book-writing-pattern-analysis-625f7c47c9ad?source=collection_archive---------36-----------------------
通过一个用例开始 NLTK 和 Python 文本分析。

西雅图图书馆 Andrew Zhu 摄
当我还是学生的时候,我读到一些文章,说语言学家可以使用文本分析技术来确定一本匿名书的作者。我当时觉得很酷。
回想起来,感觉这个手法还是很酷的。但是,如今在 NLTK 和 Python 的帮助下,你和我可以通过几行代码成为“真正的”语言学家。
准备分析目标
您不需要编写一个爬虫来搜索分析语料库。出于学习和研究的目的,NLTK 包中已经有一个巨大的文本数据库。如果您没有安装这个包,只需运行 pip 来安装它。
pip install nltk
然后从古腾堡下载书籍数据,这是古腾堡项目电子文本档案中的一小部分文本。
import nltk
nltk.download("gutenberg")
下载应该在 1 或 2 秒内完成。让我们列出下载书籍的名单。
from nltk.corpus import gutenberg
gutenberg.fileids()
你会看到像莎士比亚的《凯撒》、奥斯汀的《爱玛》和《圣经》等书籍。让我们看看圣经 KJV 版本中包含了多少单词。
bible = gutenberg.words('bible-kjv.txt')
len(bible)
共计 1010654 字。
衡量图书作者写作模式的标准
我将使用以下 3 个指标来检测作者的写作模式。
- 平均字数
这个指标反映了作者的词汇使用偏好,长词还是短词。 - 一个句子的平均字数
这个度量反映了作者的句子偏好,喜欢用长句还是短句。 - 书中使用的平均不同词汇
这个指标反映了作者的词汇量,很难伪造。
你可能会说,为什么不从每个作者那里获取最常用的单词和短语。是的,这很好,可能会产生更有趣的结果。但是频繁的单词检测也会给上下文带来额外的逻辑,可能会破坏这篇文章的可读性。(也许值得再写一篇如何自动检测关键词的文章)。
在古腾堡的书上应用 3 个标准
现在,用 Python 代码将这三个指标应用到古腾堡的书中。逻辑很简单,用 NLTK 的raw()、words()和sents()来捕捉字符#、单词#、句子#。并使用酷炫的 Python comprehensive with set 数据容器在一行代码中获取词汇编号。
如果你愿意,你可以把它复制并粘贴到你的 Jupyter 笔记本上来看看结果。
import pandas as pd
data = []
for fileid in gutenberg.fileids():
num_chars = len(gutenberg.raw(fileid))
num_words = len(gutenberg.words(fileid))
num_sents = len(gutenberg.sents(fileid))
# get total vocabulary used in this book
num_vocab = len(set(w.lower() for w in gutenberg.words(fileid)))
data.append([
fileid.split('.')[0] # remove .txt from file name
,round(num_chars/num_words)
,round(num_words/num_sents)
# total vocabulary used divide total words used
,round(num_vocab/num_words,2)
])
pattern_metrics = pd.DataFrame(data,columns=['author-book','chars_per_word','words_per_sentence','vocabulary_rate'])
pattern_metrics
从结果集中,我们可以很容易地看到奥斯汀每句话使用 25 到 28 个单词,而莎士比亚使用更多的短句,一致为 12 个。

数据表中的 3 个度量结果
莎士比亚被誉为英语的奠基者,的确,除了布莱克的诗之外,他的作品显然比其他作品用了更多的词汇。
结果是如此惊人和明显,你可以从这个表中得出更多的结论。如果数字不够清楚,条形图应该更直观地显示结果。

可视化指标
有了这种图表,你也可以为你的孩子列出阅读清单。开始阅读时使用较少的词汇和短句。嗯,Edgeworth 的家长助手看起来是个不错的开始。半夜睡不着的时候,去读几首布莱克的诗可能是个不错的选择。
结论
下次,当 J.K .罗琳用假名出版另一本小说时。你可以很容易地运行几行 Python 代码来确定这本新小说是不是 J.K .罗琳写的。发表在杂志上,做一个“语言学家”。也许另一个年轻的头脑会阅读它,并成为数据科学家。
Power BI 中的书签—这些数据意味着什么?
原文:https://towardsdatascience.com/bookmarks-in-power-bi-what-this-data-mean-866857fe719b?source=collection_archive---------9-----------------------
书签是 Power BI 中最强大的功能之一!但是,有一些微妙的选择可以产生巨大的差异

作者图片
要我说,书签是 Power BI 中最强大的功能之一!我已经写了很多次关于书签的文章:例如,它们如何帮助你将过滤体验推向一个全新的水平,或者重新发明传统的视觉效果,比如卡片,一直到使你的书签安全为“点击”行为。
书签到底是什么?
书签是一项强大的 BI 功能,使您能够捕获报告页面的当前状态。然后,您可以通过按钮、图像、形状等的 Action 属性,将这个捕获的状态称为“特殊”页面。
默认情况下,当您创建书签时,它将捕获以下报告元素的当前状态:
- 过滤器和切片器,包括 切片器状态
- 视觉效果的选择状态(例如,如果您的视觉效果是交叉突出显示的)
- 钻孔位置
- 视觉效果内的排序
- 报告元素的可见性(这是通过选择窗格处理的)
- 聚焦或聚光灯模式,如果有的话
然而,一旦你选择创建一个书签,你会看到一个带有一些选项的下拉菜单——而且大部分选项已经被预先选中了!那么,让我们来看看这些选项对您意味着什么…
为什么数据选项很重要?
当您使用书签时,您需要做的第一步是打开书签和选择窗格。书签,原因很明显:)…而且,通过选择窗格,您可以完全控制单个报告元素的可见性。

作者图片
现在,当我添加一个书签并点击它旁边的三个点时,会出现一个下拉菜单,其中有许多选项已被预先选中:

作者图片
当您保持选中数据选项时,它将捕获过滤器、切片器和视觉效果中数据的当前状态,并且每次您导航到此书签时,您将看到完全相同的数据状态!
让我们创建一个书签,它将捕获由 Contoso 品牌过滤的视觉效果的状态,并选中数据选项:

作者图片
您可能已经注意到,在所有报表页面视图中,数据都是由 Contoso 品牌进行筛选的。
下一步是创建捕获完全相同的页面状态的书签,但这次不选中数据选项:

作者图片
然后,我将在报告页面上放置两个按钮,以控制书签之间的导航。为了实现这一点,我将在 Action 属性下指定我的书签:

作者图片
现在,让我们回到报告的原始状态,即品牌过滤器未被分割为特定值时的状态。看看如果我点击“数据未检查”按钮会发生什么:

作者图片
什么都没发生!由于我们未选中数据选项,因此没有切片器选择被传输到书签。但是,如果我单击另一个按钮“数据检查”,我们可以发现完全不同的行为:

作者图片
在这种情况下,由于在创建书签时选中了数据选项,捕获的状态包括在切片器中定义的数据点—因此,无论我们在品牌切片器中选择哪个值,只要我单击数据已选中按钮,我就会看到 Contoso 的数字!
让我给你看看这个是什么样子的:

作者图片
结论
正如您所看到的,书签是非常强大的功能,可以应用于各种不同的报告场景。但是,就像所有强大的东西一样,它需要完全控制它,以便以正确的方式工作。这就是为什么理解书签附带的各种选项极其重要。
在大多数情况下,这些细微的差异会对整个报表体验产生巨大的影响。说实话,在大多数情况下,您会在创建书签时取消选中数据选项,但有一个非常方便的用例是让数据选项保持选中,我将在下一篇文章中解释这一点。
感谢阅读!
成为会员,阅读 Medium 上的每一个故事!
用 Python 学习自然语言处理的阅读列表
原文:https://towardsdatascience.com/books-for-learning-nlp-b865ee9e8263?source=collection_archive---------14-----------------------

劳拉·卡弗在 Unsplash 上的照片
一位前同事最近向他寻求建议,如何最好地从头开始学习自然语言处理(NLP)。
“优秀!”我以为;我已经为另一位前同事回答了完全相同的问题,所以这应该和重新整理之前的回答一样简单,对吗?
嗯,除了一个小细节之外,它本来是可以的:我完全不知道我把资源列表保存在哪里了。
为此,为了避免再次违反 DRY 原则(即“不要重复自己”),我写了这篇文章,这样如果/当我收到另一个请求时,我就可以把链接转发给他们。
以下是我非常固执己见的观点。不同意也可以留下你推荐的课程的链接。
免责声明#1
我假设你对线性代数、统计学和语言学有所了解。
如果没有,停止。别说了。为什么?三个原因:
- 为了分析句子,识别词性,以及任何其他任务,你需要对语言学有一个坚实的理解,所以考虑参加一个课程,比如这个 one 会给你一个概述。
- 统计意义、相关性、分布和概率是机器学习的基本概念。为了填补这个空白,给自己挑一本关于统计学的好书,比如数据科学实用统计学并努力阅读。
- 至于线性代数,正如下面的文章巧妙地解释的那样,它是深度学习和计算文本相似性的基础:
为此,帮自己一个忙,看看 3Brown1Blue 的这个令人惊叹的视频系列
免责声明#2
下面概述的道路是我希望我会选择的道路。
“你走了什么路?”
好吧,简而言之,我花了几年(是的,几年)试图找出如何使用编码作为工具来完成我想要的项目。
听起来不错,对吧?
嗯,问题是我没有学习 Python 的基础知识,所以当我的代码抛出一个错误,或者,上帝保佑,我试图从 StackOverflow 和/或 Github 中重新使用别人的代码,但它不能开箱即用时,我不知道该怎么办。
为什么?
简单地说,我并不精通 Python,因此,我无法适应不熟悉的情况。
为此,如果你想专门学习 NLP 或一般的机器学习,你需要做的第一件事就是学习中级水平的编码。
为什么是中级?
因为你遇到的几乎每一个 Python for NLP 资源都会推荐你“熟悉”、“了解”、“精通”或其他一些难以置信的模糊标准,以便从他们的产品或平台中获得最大收益。
简而言之,你越擅长编码,就越容易将你在旅途中学到的概念付诸实践。
那么我如何达到“中级”Python 呢?
谢谢你的关心😄
Python 基础:Python 3 实用介绍
这本书由 Real Python 的团队编写,前 10 章涵盖了从在机器上安装 Python、运行脚本(不是笔记本)、数据类型、函数、调试和通过定义类进行面向对象编程(OOP)的所有内容。
至于本书的后半部分,它是一系列编码问题的集合,比如从网站上抓取和解析文本(第 16 章)以及为你的程序创建 GUI(第 18 章)。
因此,我建议你仔细阅读前十章的每一页,如果你感兴趣的话,可以阅读剩下的任何一章。
你可以在他们的网站上拿一本。
用于数据分析的 Python
当你管理数据时,你永远不会对数字或熊猫太精通,所以你花在研究韦斯·麦金尼的这本极其通俗易懂的书的每一分钟都应该被看作是对你未来的帮助。
再一次,帮你自己一个忙,在深入研究 NumPy 和 pandas 之前,先用第三章回顾一下 Python 中内置的数据结构,同时很好地理解 matplotlib。然而,这本书最有用的部分是第 14 章,其中包含了五个实例。
一定要在 GitHub 上访问该书的回购以留下一颗星,查看每一章的笔记本,并找到在哪里拿起一本。
使用 Scikit-Learn、Keras 和 TensorFlow 进行机器实践学习
既然您的 Python 已经达到标准,并且可以操作数据,那么是时候学习机器学习了,没有比 Aurélien Geron 的这本宝石更好的学习机器学习基础的书了。虽然这本书涵盖了从逻辑回归到神经网络的所有内容(包括关于 NLP 注意力的讨论),但真正的优势在于作者除了简单解释如何使用不同技术之外,还讨论了为什么要使用不同技术。因此,第 2 章的端到端机器学习项目,以及附录 B 的机器学习项目清单,值得这本书的成本。
要了解关于这篇文章的更多信息,以及在不下载或安装任何东西的情况下运行附带的笔记本,请访问作者的 repo 。
实用自然语言处理
我会读的第一本彻头彻尾的 NLP 书就是这本书。是什么让它这么好?这本书采用基于任务的方法,提出一个问题,然后询问如何使用 NLP 解决这个问题。
此外,它还展示了社交媒体、金融和法律等不同领域的应用。此外,几乎每个问题都通过多种方法解决,因此读者可以了解主要的 NLP 库,如 Spacy 、 NLTK 、 Textblob 、 Gensim 等等。
请访问该书的网站了解更多信息。
使用 Python 进行文本分析的蓝图
现在您已经掌握了 NLP,让我们来扩展一下您可以用它做什么。了解什么是可能的一种方法是通过观察人们如何使用 NLP 来寻找商业问题的解决方案。
这正是这本书所扮演的角色;它包含大约 100 个带有蓝图的常见用例。
但是什么是蓝图呢?"
作者指出,“蓝图[……]是一个常见问题的最佳实践解决方案。”本质上,它们是模板,因为您精通 Python,所以您可以最小程度地适应您的特定用例。
请务必前往该书的回购留下一颗星,看看工作的例子。
自然语言处理转换器
最后,既然您已经有了坚实的 Python 基础,并且了解了可以用 NLP 解决哪些问题以及如何解决这些问题,那么是时候了解最先进的架构:transformers 了。
什么是变形金刚?
抱歉,这超出了本文的范围;然而,如果你真的想知道,我推荐阅读开创性的作品 注意力是你需要的全部 和/或插图变压器来获得想法的要点。
一旦你有了这些,一定要看看 Denis Rothman 的翻页文本,它涵盖了像微调和预训练模型以及用例这样的主题。要了解更多关于本文的信息,请点击此处。
填补空白的书籍
虽然我认为上面的文本是核心,但你永远也不会太了解你的工具是如何工作的。
因此,以下书籍提供了一些有用工具的深度挖掘。
通过Duygu altn ok掌握空间应该是你学习所有空间知识的最佳指南。
通过解决(几乎)任何机器学习问题由 Abhishek Thakur 完成,这类似于使用 Scikit-Learn、Keras & TensorFlow 的动手机器学习,但使用 PyTorch。
由 Sudharsan Ravichandiran 撰写的Google BERT入门是一篇很好的关于 BERT 架构的文章。
结论
虽然我是上面列出的所有书籍的超级粉丝,但我毫不怀疑我忽略了一些应该包括在内的书籍。
为此,请在你推荐给那些想在新的一年开始 NLP 之旅的人的书中留下评论。
编码快乐!
熊猫布尔掩蔽
原文:https://towardsdatascience.com/boolean-masking-with-pandas-b21b7714d0b6?source=collection_archive---------7-----------------------
过滤熊猫数据帧

拉里·科斯塔莱斯在 Unsplash 上的照片
在 Miki Tebeka 的优秀“ 更快的熊猫**”**课程中的一个主题是如何使用布尔掩码来过滤熊猫中的数据。我想实践我所学的,所以我更新了一个最近的项目来使用布尔遮罩。我认为这是一个非常有用的技术,所以我想分享一下我是如何更新代码的。我将向您展示如何在一些直接取自我的项目的 之前的 和 之后的 代码片段中使用布尔掩码。
在我们深入片段之前,我将提供一些背景。我想分析一个流行的烹饪应用的评论。我下载了这些评论,并重点关注了 2019 年和 2020 年发布的评论。为什么是这个时间范围?我想看看 COVID 之前和期间的应用评价是否有所不同。我的家庭在 2020 年增加了家庭烹饪,我很好奇烹饪应用的评论是否会显示应用使用和/或用户享受的增加。
如何使用布尔掩码
现在,让我们通过检查一些 之前的 和 之后的 代码片段来学习如何使用布尔掩码。
下面的代码筛选数据集,只使用年份为 2019 或 2020 的行。
之前:
*#reviewTimestamp is a datetime objectreviews_df = all_reviews_df[(all_reviews_df[‘reviewTimestamp’].dt.year == 2019) | (all_reviews_df[‘reviewTimestamp’].dt.year == 2020)]*
后:
*pre_mask = all_reviews_df[‘reviewTimestamp’].dt.year == 2019
during_mask = all_reviews_df[‘reviewTimestamp’].dt.year == 2020reviews_df = all_reviews_df[pre_mask | during_mask]*
下面还有一个例子。该代码过滤数据集,以找到 2019 年和 2020 年的“高”和“低”评论。
之前:
*top_reviews_2019 = reviews_df[(reviews_df[‘reviewTimestamp’].dt.year == 2019) & (reviews_df[‘score’] == 5)][‘content’].to_list()low_reviews_20191 = reviews_df[(reviews_df[‘reviewTimestamp’].dt.year == 2019) & (reviews_df[‘score’] < 3)][‘content’].to_list()top_reviews_2020 = reviews_df[(reviews_df[‘reviewTimestamp’].dt.year == 2020) & (reviews_df[‘score’] == 5)][‘content’].to_list()low_reviews_2020 = reviews_df[(reviews_df[‘reviewTimestamp’].dt.year == 2020) & (reviews_df[‘score’] < 3)][‘content’].to_list()*
后:
*pre_mask = reviews_df[‘reviewTimestamp’].dt.year == 2019
during_mask = reviews_df[‘reviewTimestamp’].dt.year == 2020
high_mask = reviews_df[‘score’] == 5
low_mask = reviews_df[‘score’] < 3high_reviews_2019 = reviews_df[pre_mask & high_mask][‘content’].to_list()low_reviews_2019 = reviews_df[pre_mask & low_mask][‘content’].to_list() high_reviews_2020 = reviews_df[during_mask & high_mask][‘content’].to_list()low_reviews_2020 = reviews_df[during_mask & low_mask][‘content’].to_list()*
为什么使用布尔掩码?
为什么我发现做这些改变很有用?第一个原因是它使代码更容易阅读和修改。例如,我可能会用 2018 年和 2019 年的 COVID 前时间框架以及 2020 年和 2021 年的 COVID 期间时间框架来更新分析。我只需要更新布尔掩码定义中的标准,而不是遍历代码并替换我过滤数据集的每个地方的标准。
第二个原因是,有人告诉我使用布尔掩码可以提高性能。我使用 IPython 交互命令 shell 中的%timeit 魔法命令(在单元模式下)对我的代码进行了性能测试。我的性能检查显示,使用布尔掩码的代码比使用常规条件过滤的代码更快。在我的电脑上,代码比 T11 快了 7 倍。

图片由作者提供
现在,您已经看到了一些如何使用布尔掩码的示例,并且知道了应该考虑在代码中使用它们的原因。请随时提出建议,并让我知道这些内容是否对您有所帮助。
编码快乐!
布尔既有趣又神秘
原文:https://towardsdatascience.com/booleans-are-fun-and-mysterious-9013e5f837c2?source=collection_archive---------62-----------------------
数据科学
一些有趣的关于布尔数据类型的谜题和答案。

由阿莱克·戈麦斯在 Unsplash 上拍摄的照片
在数据科学和编程中,布尔(真和假)数据被认为是简单而枯燥的。我相信布尔是有趣的,如果你不知道他们的逻辑,有时是不可预测的。我将说服你们中的许多人,一些有趣的特性与布尔对象相关联,而你们可能忽略了这些特性。
简单的难题
让我从一个简单的开始。
这段代码应该能够识别 int 和 boolean 对象。如果输入对象不是 boolean 或 integer,它会告诉您该对象是“其他东西!”。最后,我用四个例子测试了这个功能。您对这段代码的输出有什么猜测?看起来很简单,对吧?
An int object.
Something else!
A bool object.
A bool object.
如果你的猜测和上面的输出一样,那你就和我第一次一样错了。实际上,正确的答案是:
An int object.
Something else!
An int object.
An int object.
为什么布尔对象(true 和 False)被识别为整数对象?
事实上,在 Python 中,布尔类是从整数类继承而来的。长话短说,在 Python 的初始版本中没有布尔对象,他们用 1 和 0 代替 True 和 False。当他们决定在 Python 中加入布尔对象时,他们从 integer 类继承了布尔类(在这里阅读这个故事)。
当您运行代码时,因为代码将 True 和 False 识别为 int 类型,所以它打印“一个 int 对象”让你感到困惑和惊讶。
难题
好吧,这个很简单。让我向您展示另一段代码,并让您猜测输出。
第一次面对这个挑战,好像超级容易。我想,首先,两个函数几乎相同,应该给我相同的结果。0 是假的,1 是真的,2 应该是假的。简单地说,我期望类似于:
False
True
FalseFalse
True
False
但是,正如你所猜测的,我的答案是不正确的。正确答案是:
False
True
True
False
True
False
什么?!意思是if 2和if 2 == True在 Python 里不等于,说真的?第一个表达式为真,第二个为假。怎么可能呢?!
让我告诉你为什么会这样。我们有两种表达方式。先说简单的,就是if 2 == True。大家知道,在 Python 中,True等于1。因此2 == True是假的,这就是为什么与if 2 == True相关的代码块没有被执行。这很容易理解。
神秘的是为什么对应于if 2(在func1()中)的代码块被执行并返回 True?是不是说2等于True?如果2等于True,为什么2 == True不成立。很困惑,对吧?
如果你好奇想知道答案,这里就是。答案就在面向对象编程中,面向对象编程是 Python 的基础。如你所知,Python 中的一切都是对象 。对象有属性和方法。有些属性和方法被称为神奇的方法或属性。
虽然这对于本文的其余部分不是必需的,但我鼓励您阅读我的 Python 面向对象编程三部曲。
魔法 _ 布尔 __
您可以为每个类和对象定义的神奇方法之一是__bool__。这个神奇的方法可以返回False或者True。当使用 if 和一个对象(如if obj:)时,if调用__bool__方法并根据其返回值,执行或不执行相应的块。让我们用 Python 做一个快速测试,看看__bool__方法为整数对象2和0返回了什么。
>>> n = 2
>>> n.__bool__()
True
>>> n = 0
>>> n.__bool__()
False
你也可以使用一个名为bool()的内置派系来检查一个对象的布尔值。
>>> n = 2
>>> bool(n)
True
你可以利用__bool__来改进面向对象编程。想想你的对象最重要的布尔方面是什么,基于此,通过__bool__方法返回一个合适的布尔值。例如,假设您正在进行一个强化学习项目,并且为您的机器人或代理准备了一个对象。在我看来,机器人/智能体最重要的方面是它是否活着。因此,我定义了__bool__方法,以在其返回值中反映该属性。下面是我将如何定义这类对象的一个示例:
在这个例子中,有一个名为score的属性,它存储了机器人对象的分数。当分数高于 0 时,你的机器人是活的,并且bool()返回 True。我们将机器人分数降低 10,然后降低 90(初始分数为 100)。一旦分数变为 0,对象将返回 False 以响应任何调用其布尔值的函数。用户可以在他/她的代码中利用这个属性,例如while r: …或if r: …。
如果对象没有__bool__方法,if,bool()和类似的函数会寻找另一个神奇的方法叫做__len__。该方法通常返回对象的长度。如果__len__返回 0, bool()返回 False 否则,它返回 True。在前面的例子中,我们可以简单地通过__len__返回分数,我们不再需要定义__bool__。下面是我们如何改变代码并得到相同的结果。
以你所学的所有知识,你一定能回答我的最后一个难题。以下代码的输出是什么?
bool("")
摘要
要理解 Python 中布尔数据类型和对象的行为,必须知道这种数据类型是从 integer 类继承的。另外,像__bool__和__len__这样的神奇方法定义了一个对象如何响应像bool(obj)这样的函数。
在推特上关注我的最新报道:https://twitter.com/TamimiNas
增强基本数据集和简单 CNN 来回答实际环境问题
原文:https://towardsdatascience.com/boost-basic-dataset-and-simple-cnn-to-answer-real-environment-problem-3622c28b3fad?source=collection_archive---------28-----------------------
实践教程
CNN——具有数据扩充、背景和多输出的树叶分类。
由克莱曼婷执笔页面、让·琼邦和塞尔瓦·克莱伯—2021 年 3 月

克里斯·劳顿在 Unsplash 上的照片
1.语境
该项目是我们在 Data Scientist 的数据科学家训练营课程验证的一部分,将我们在这 11 周的理论课中学到的一切付诸实践,并确保每个主题都已掌握。
这个项目的目标是从图片中定位和分类植物的种类。一旦分类完成,返回植物的描述,并确定最终的疾病。
2.项目
数据集—迭代 1
数据集新植物病害数据集来自 Kaggle,被许多用户彻底使用,不包含任何错误或错误分类的图像。
该数据集由放置在统一背景上的树叶组成:

来自数据集的图像样本(来源)
包含大约 87,000 张叶子的图片——患病的和健康的。这些图片代表了 38 类 14 种植物:

每株植物病害
分配情况如下:

数据集中类的分布— 作者提供的图片
该数据集是使用另一个数据集的离线扩充重新创建的,因此,正如我们在前面的图表中看到的那样,这些类非常平衡(每个类约占 3%—外部层)。
为了在植物环境中的树叶图像上测试我们的模型,我们实现了一个 web 抓取脚本来从“Google image”中提取图像。这个测试数据集类似地由 38 个类加上另一个代表没有植物的图像的类“其他”组成。
与原始数据集相比,测试集中的图像不遵循相同的格式(每个图像一片叶子)。
深度学习—迭代 1
作为第一次迭代,我们用 TensorFlow 开发了自己的 CNN 模型:

CNN 模型— 作者图片
该模型由三个卷积块和一个分类块组成。
卷积块层数:
- 图像大小:图像大小调整为 128x128x3,这是时间计算和信息损失之间的一个很好的折衷。
- Conv2D :使用滤镜从图像中提取图案。为了捕捉更大的图案组合,每个 Conv2D 层的滤镜数量都比前一层增加了一倍。
- 激活功能:使用 CNN 最常用的 Relu 应用非线性。
- batch normalization(BN):BN 用于归一化前几层的输出。它使 CNN 更快,更稳定,并减少过度拟合。
- MaxPool2D :通过减少像素数量来降低图像的维数,它减少了模型的参数数量,并为内部表示提供了轻微的尺度不变性。
分类块层数:
- 密集:用于分类的三个全连通层。
- 退出:通过在训练过程中随机忽略选定的神经元来防止过拟合。
conv 区块与分类区块之间的层:
- globalaveragepool2d(GAP):它对每个特征图的值进行平均。与“展平”层不同,“间隙”移除了大量可训练参数,提供了平移不变性,从而减少了过度拟合的趋势。

Flatten 和 GlobalAveragePooling 之间的差异— 作者图片
正则化:为了防止过度拟合,我们使用了 L2 正则化,它将参数(权重)的平方和添加到损失函数中。
型号代码如下所示:
该模型在验证数据集上的准确率为 99.3% 。
然而,它在测试数据集上给出了非常糟糕的预测,准确率为 13.2% 。
**迭代 1 总结:**
- 数据集:“新植物疾病数据集”,其是在统一背景上的叶子图像
- 对验证数据集的出色预测— val 准确率> 99%。
- 对由自然环境中的树叶图像组成的测试数据集的错误预测。
- 即使图像上没有任何植物,模型也能预测植物。
对自然环境中的树叶图像预测不佳的主要原因是我们的模型是用统一背景上的树叶图像数据集训练的。此外,正如在训练数据集中一样,没有图像是没有植物的,如果发生这种情况,我们的模型不可能预测图像中不存在植物。

迭代 1 图— *作者图片*
深度学习—迭代 2
在第二次迭代中,我们试图通过给树叶图像添加植物背景来改进我们的模型。我们修改了我们的数据集,并使用了来自 Kaggle 的植物村数据集,它与我们的第一个数据集相似(在统一的背景上留下图像),但没有任何数据扩充。因此,数据集是高度不平衡的(来自一些类的超过 5000 幅图像,而来自其他类的不到 200 幅图像),但是包含我们可以用来添加植物背景的分割的叶子图像。

来自新数据集的分割图像样本(来源)
为了重新平衡该数据集,按照以下描述的转换进行了数据扩充:

数据扩充— 作者提供的图片
为了检测图像中植物的缺失,我们使用来自“Image-net”数据集的随机图像向我们的数据集添加了另一个类“ Others ”。

来自新类别"其他 " ( 来源)的图像样本
在数据扩充和添加新类别“其他”之后,该数据集包含 114 077 幅图像,分布如下:

数据扩充后数据集中类的分布— 作者图片
我们使用“自定义数据集”来加载图片并添加背景,用我们的背景像素替换分段图片的黑色像素。
用函数“tf.where”替换像素,如果叶子图像像素的值低于定义的阈值,则用背景图像之一替换叶子图像的像素。
注意,在第二次迭代中,我们对每种植物只使用了一个背景。例如,任何番茄类都使用相同的番茄植物背景。

背景添加过程— 作者图片
代码如下所示:
我们使用相同的模型来比较两次迭代的结果,只是最后一个密集层的输出形状为 39 (38 株植物+其他)。
该模型在新的验证数据集上给出了 95.1% 的准确度。
然而,它在测试数据集上给出了非常糟糕的预测,准确率为 10.5% 。
第二次迭代总结:
- 数据集“Plant Village”增加了数据,并从数据集“Image-Net”添加了新的类。
- 在模型训练期间添加背景(每个植物类型只有一个背景)。
- 好的预测与数据集相关的图像。
- 测试数据集上的预测略有改进,但性能仍低于预期,尤其是在无法完全看到树叶的图像上。
- 该模型似乎能够预测图像是否不是植物。
- 该模型似乎专注于背景而不是叶子本身。
在迭代 2 期间,我们的模型学会了使用背景而不是树叶,所以我们使用完全相同的模型和方法做了另一次迭代“ *2-bis* ”,但不是每株植物只有一个背景,我们为每株植物创建了一组背景,每次都将随机选择**。**
因此,我们为每株植物(我们的数据集中有 14 株植物)创建了一个文件夹,在每个文件夹中:
- 5 幅实际植物的图像(即:所有马铃薯种类的马铃薯植物)。
- 4 植物、草坪和森林的图像将在每个文件夹中共享。
这应该有助于模型:
- 而不是聚焦在背景图像上。
- 在真实环境中有更好的表现。
该模型(2-bis)在验证数据集上给出了 98.4%** 的准确度。**
然而,它在测试数据集上给出了非常糟糕的预测,准确率为 18.1% 。
****迭代 2 之二的总结:****
- 数据集:“植物村”,增加了数据,并从数据集“Image-Net”添加了新的类。
- 在模型训练期间添加背景(随机)。
- 好的预测与数据集相关的图像。
- **与迭代 2 相比,测试数据集上的预测略有改进,因为背景是随机的,所以模型没有关注它。**
- 该模型似乎能够预测图像是否不是植物。
我们可以在测试数据集上看到一些预测性能的改进,尽管结果仍然低于预期。然而,这个模型可以预测一个图像是否是植物,这与我们的第一次迭代相比是一个增强。

**迭代 2 图— *作者图片***
**深度学习——迭代 3**
**在迭代 2 中,我们包含了一个名为“Others”的新类,表示“任何东西”的图像。这一举措是为了帮助模型避免在图像中没有植物时预测植物。但是我们可以看到,在测试数据集上的结果不如预期的好。一种解决方案是预测图像中植物出现的概率。一个输出表示图像是否包含植物,第二个输出表示植物分类。**

**模型迭代 3 — *作者图片***
此后,模型的代码—我们使用功能模型:
为了评估我们的模型预测数据集的效果,我们需要创建一个自定义损失函数:

定制损失函数
用 P_other ={0,1}。图像是植物(=1)还是植物(=0)。如果图像不是植物,则不计算分类交叉熵。
根据我们的模型,第一个神经元代表图像是否包含植物,其他 38 个神经元代表植物分类。
该模型(3)在验证数据集上给出了 97.4%** 的准确度。**
然而,它在测试数据集上给出了非常糟糕的预测,准确率为 19.2% 。
**但是,在测试数据集上对没有植物的图像(类别:其他)的预测比用迭代 2-bis 模型完成的预测要好。**
****迭代 3 总结:****
- 数据集:“植物村”,增加了数据,并从数据集“Image-Net”添加了新的类。
- 对验证数据集的出色预测— val 准确率> 99%。
- 对测试数据集的预测仍然很差。
- 在测试数据集上更好地预测没有植物的图像(类别:其他)。

**迭代 3 图— *作者提供的图片***
改进
- 包含真实环境中图像的新数据集:**正如我们在几个测试阶段发现的那样,该模型在只有一片叶子和统一背景的图像上表现很好,但无法预测自然环境中的图像。我们试图通过添加背景来解决这个问题,但我们仍然可以在结果中看到一些缺陷。从直接在真实环境中拍摄的图像(或两者的组合)创建完整的数据集可能有助于提高结果的可靠性。这可以使用网页抓取来完成。
- ****两个模型串联(多输出):在当前数据集中,一些植物有相同的病害(即 : 番茄和桃叶的细菌性斑点病或马铃薯和番茄叶的晚疫病……)。在自然环境中,我们的模型似乎能发现正确的疾病,但不能发现正确的植物。一个解决方案是创建一个多输出模型:
- 一个关注休假分类的模型
- 一个侧重于疾病分类的模型
用这种方法,我们可以分别预测植物和疾病。因此,这可以改进模型,并可能预测新植物的已知疾病——即苹果上的细菌性斑点(已知疾病)。

多输出模型— 作者图片
**3.**语义分割:为了提高在自然环境中的预测,使用像 UNET 这样的语义分割模型,将有助于提取树叶的像素,然后我们将使用树叶分类模型来预测植物本身。
**4.**更深的模型:由于真实环境中的叶子图像更复杂,具有更多卷积块的更深的模型,为了捕捉更多模式,应该给出更好的预测。
概括起来

通过这三次迭代开发的模型在验证数据集上进行了出色的预测,结果高达 97%。在自然环境中的图像上测试这些模型是一个自然的选择,以代表一个真实的商业案例。
但我们很快发现,即使我们尽最大努力改进我们的模型,以检测真实环境中的图像,我们也无法实现这个目标。
我们可以尽可能地调整模型,它只能预测它被训练的内容——统一背景上的树叶图像。
我们能够验证一些假设——检测没有植物的图像,对具有统一背景的图像进行分类…——并拒绝添加背景有助于提高模型鲁棒性的事实。
这个模型仍有改进的空间,但在此之前,我们应该考虑使用一个更接近有问题的的数据集——从任何照片中预测植物病害。****
由克莱曼婷·佩奇、让·琼邦和塞尔瓦·克莱伯撰写。感谢 DataScientest 团队的帮助。
迭代代码可以在Github上找到。
承认
[Samir Bhattara](https://www.kaggle.com/vipoooool) (2018, Nov.), [New Plant Diseases Dataset](https://www.kaggle.com/vipoooool/new-plant-diseases-dataset) v2
**Orignial Dataset**: [spMohanty](https://github.com/spMohanty) (2018, Sept.), [PlantVillage-Dataset](https://github.com/spMohanty/PlantVillage-Dataset)[Abdallah Ali](https://www.kaggle.com/abdallahalidev) (2019, Sep.), [Plant Village dataset](https://www.kaggle.com/abdallahalidev/plantvillage-dataset) v3[ImageNet](http://image-net.org/) (2016), [Stanford Vision Lab,](http://vision.stanford.edu/) [Stanford University](http://www.stanford.edu/), [Princeton University](http://www.princeton.edu/)
利用 R 中的高效编码提高计算速度
原文:https://towardsdatascience.com/boost-computational-speed-with-efficient-coding-in-r-8320a29b83ed?source=collection_archive---------11-----------------------
理解大数据
了解代码基准测试,以优化 HolzingerSwineford1939 数据集数百个观察值的数据分析

照片由 马修·施瓦茨 上 下
R 专为智能统计数据分析而构建,与 C 或 Python 等其他编程语言相比,只需要我们编写很少的代码。不过时不时的显得有点慢。随着我们中的一些人处理大型复杂的数据集,计算速度变得非常方便。但是老实说,我们总是以最有效的方式构造代码吗?我不确定。因此,熟悉加速分析的主要技术至关重要——这将使您更容易尽快获得结果,而不必等待几十年直到代码最终执行。这就是我将通过 R 中探索性数据分析的典型工作流向您展示的内容,包括:
- 获得数据概览
- 将数据转换成合适的格式
- 汇总数据以获得一些描述性统计数据
- 绘制感兴趣的方面。
有时,您可能还会将数据分成更小的部分,以获得更多的见解(例如,每个人、每个州、每个性别……)。现在如何才能加快进程,成为更厉害的程序员呢?
在我们开始一个小的案例研究之前,这里有一些通用的建议来加速你的分析:
1。 让你的 R 版本保持最新
确保你定期更新你的 R 版本。新版本的 R 通常包括速度提升和在幕后开发的错误修复。但是从我的个人经验来说,我知道更新有时会很痛苦,因为程序可能无法再从库中找到包。离开 R,进入任何文件夹,然后进入用户>文档> R > win-library,这可能会有所帮助。然后选择包含早期版本的所有包的文件夹(例如,在我的例子中,它被称为 3.4,我想安装 4.0 版本)。现在手动删除文件夹。这确保了没有类似“为…加载包或名称空间失败”的混淆,并且 R 可以毫无困难地找到包。
**2。**避免常见的速度瓶颈
即使这不会使您的代码特别快,您也可以避免一些会使您的代码更慢的常见缺陷。首先,如果没有必要,确保不要存储太多的变量/对象。例如,如果您对 X 的平均值感兴趣,一个常见的习惯是使用'
另一个节省时间的方法是避免重复。我记得在 2018 年的一段时间里,我开始编码,并总是在数据帧的每一行使用相同的程序-我产生了令人尴尬的乏味和混乱的代码:
可以通过使用更整洁的 dplyr 语法来解决这个问题,例如:
由于不知道更好的方法来做到这一点,我最终得到了无尽的代码行,这使得我几乎不可能知道所有的步骤都包括什么。如果您一遍又一遍地重复一个定制的过程,并且没有用于此目的的特定内置函数,您可以编写一个函数来使您的代码更整洁(例如,如果您希望在不同的组上生成一个特定的绘图,而不进行分面,我将在下面向您展示)。最后但同样重要的是,确保尽可能避免使用循环。下面是一个简单的例子:假设你想生成一个固定长度为 n 的整数序列。你可以像这样简单地保持它:
或者你决定运行一个 for 循环,遍历 n 的每个元素来填充向量 X:
这是不必要的,因为您可以很容易地使用第一个版本,但它最多只会减慢您的代码几秒钟。如果你生成了一个空的 X 向量,并且想要一步一步地增长它,那会怎么样呢?
请不要这样做!为什么?在这个 for 循环的每一次迭代中,你需要更多的内存,如果你想创建大的向量,这可能需要几个小时才能完成。
我的经验是:如果有一个选项可以在一行代码中运行相同的操作(例如,使用 base R、data.table 或 dplyr 函数),你应该选择它,因为每个开发团队已经对它进行了大量的速度优化。您可能还听说过程序员建议对您的代码进行“矢量化”——这意味着您使用只被调用一次的内置函数来返回具有固定数量条目的向量(例如,使用 rnorm(n)生成 n 大小的随机正态分布)。相比之下,如果使用一个循环来运行相同的操作,则该函数会被调用多次——对于每次迭代(就像上一个示例中一样)。根据生成的向量应该有多大,使用 for 循环增长向量可能需要几个小时才能执行。最后但同样重要的是,尽可能使用矩阵而不是数据框:如果数据元素只包含一种数据类型(字符、整数、浮点等)。)使用矩阵而不是数据帧会给你带来巨大速度提升,因为它会更有内存效率。但是,如果您需要在矩形中存储不同类型的数据,数据框、tibbles 或 data.tables 是更合适的解决方案。
3。 基准测试你的代码
如果没有参照物与之比较,您就无法真正知道您的代码是“太慢”还是“足够快”——这就是代码剖析发挥作用的地方。它基于以下原则:编写相同代码的不同版本,跟踪执行每个版本所用的时间,然后选择最快的版本。即使只是有一些操作不能再优化了,它也确实有助于找到代码中减慢整个执行速度的瓶颈。如果你时不时地重复这个过程,你会对麻烦制造者有所了解,并知道如何克服他们,给你留下成就感和自我效能感。在 R 中有多种方法可以对您的代码进行基准测试——我将在下一节中向您展示它们。
声明:所有图片均由作者创作,除非另有说明。
加快分析 1939 年以来的情报数据

照片由纽约公共图书馆在 Unsplash 上拍摄
假设你有一台时间机器,回到了 1939 年,你的任务是帮助一组教师对来自两所不同学校(巴斯德和格兰特-怀特)的 301 名七年级和八年级学生进行一系列智力测试,数据集名为 HolzingerSwineford1939,从 lavaan 包中检索。现在你要为每个学生准备有意义的反馈——在 1939 年,这是一项乏味的教师工作!感谢你的数据科学技能,你知道该怎么做:你要准备、总结和可视化结果,最终为每个孩子提供一个漂亮的图表。因为你的时间机器只有有限的时间段用于旅行,所以你需要优化代码执行的速度。这就是我们将要一起做的事情:我们将在追踪时间和记忆的同时,通过不同版本的代码进行游戏。我们将使用 base R 函数,来自 tidyverse 和 data.table 包的函数。为了区分不同的语法风格,我将简要介绍不同的软件包:
基地 R
顾名思义,你不需要安装一个额外的包来使用 base R 包——它已经是内置的,会自动加载。例如,$运算符或 subset 函数的使用是一个基本的 R 函数。
Tidyverse/dplyr
这种风格在 R 社区中变得非常流行,说真的,我认为这是完全合理的——tidy verse编写代码的风格让我的生活变得简单多了,因为我发现了% > %管道操作符及其可读性、一致性和可再现性的无与伦比的美。实际上,tidyverse 包括一系列高度兼容的包,如 dplyr、stringr、magittr 和 purrr。特别是,有一组非常有用的数据操作函数,如 mutate()、filter()和 group_by()。
数据表
data.table 的内存效率非常高,尤其是在数据操作方面,但是它的语法与 tidyverse 的语法有点不同,而且更难学习和阅读。与 tidyverse 不同,它指的是单个包: data.table 。据开发者称,它允许:
大型数据的快速聚合(例如 RAM 中的 100GB)、快速有序连接、完全不使用副本按组快速添加/修改/删除列[…],为更快的开发提供了自然而灵活的语法
它甚至支持低级并行:许多常见操作在内部并行化,以使用多个 CPU 线程。因此,即使在处理大型数据集和复杂的数据操作时,它的超级能力也是速度。这是否意味着在数据操作管道的每一步,data.table 函数真的比 tidyverse 或 base R 函数更节省时间?我们会看到——让我们证明这一点。
首先,我们将设置我们的工作空间,并从 lavaan 包中加载holzingerswinford 1939数据集。

正如你所看到的,数据集包含 301 个观察值和 15 列,包括学生的 ID、性别、年龄、学校、年级和 9 项智力任务中每一项的分数。为了确保每一列都有正确的格式,我们将使用两个不同的函数来获取数据的结构。出于这个目的,我们将把它包装到 system.time()中,以跟踪计算机执行它所花费的时间。

在输出中,你可以看到 R 首先执行了我们真正感兴趣的函数,然后才给出计时结果。它给出了几个关键指标:
- 用户时间是执行用户指令收取的 CPU 时间。
- 系统时间是系统代表调用进程强制执行的 CPU 时间。
- Elapsed time(德语:“verstrichen”)是我们通常感兴趣的时间,因为它大约是用户和系统的总和。在我们的例子中,这真的很快,只有 0.07 秒。
如果我们用 str()代替 glimpse()会怎么样?

看起来 base-R 函数运行得更快一些,但是 0.04 秒应该不会有太大的差别。接下来,我们将讨论数据。更具体地说,我们将
- 只选择我们感兴趣的变量,
- 为 9 项智能任务中的每一项赋予更有意义的名称,
- 将数据从宽格式更改为长格式
- 将任务变量更改为对以后的绘图有用的系数。
为此,我们将以 dplyr-以及 data . table-格式编写此过程。为了相互比较各个版本,我们需要将每个版本包装到一个函数中,以便再次使用 system.time()。
dplyr-版本

数据表-版本

好的——似乎 data.table 在将数据转换成正确的格式方面做得更有效,并且比 dplyr 快 3 倍。
对于感兴趣的读者,我发现了一个关于 data.table 和 dplyr 之间差异的有趣的堆栈溢出讨论。
现在,让我们通过使用微基准测试包来进一步扩展我们的时间比较。与 system.time()相比,它的优势在于,它提供了不同函数之间更详细的计时概要,并且每个函数都运行多次迭代,从而为您提供更可靠的结果。在描述中,开发人员认为,通过使用用 C 代码编写的毫秒级(据说是纳秒级)精确计时函数,可以实现更精确的计时。为了利用它,我们将编写不同版本的代码来计算每个任务和学校的平均分数,并将它们包装到一个函数中。稍后,该总结将为我们提供一个参考,以比较每个学生在每项任务上的得分和学校特定的表现。

哇 microbenchmark 函数甚至给你一个函数时间效率的排名,让你更容易直接选择最快的。在这种情况下,data.table 函数最快,其次是 tidyverse 版本,然后是 base R 函数。通过计算相对速度,我们可以看到,与 data.table 函数相比,base R 函数几乎慢了 4 倍,而 dplyr 函数慢了 3 倍!因此,data.table 在这里再次成为明显的速度赢家。
接下来,我们将用一个更复杂的任务来挑战每个包:我们想创建一个显示每个学生任务表现的图表,然后我们想自动将它们导出到预先指定的文件夹中。通过包括学校特定的得分,我们将有一个参考线来找出孩子与他或她的同龄人相比的得分。换句话说——我们想知道在每项智力任务中,他或她与其他人相比,表现是高于还是低于平均水平。

在这个例子中,你可以看到这个人在快速辨别大写字母和完成句子方面表现出高于平均水平的表现。他或她在立方体任务中表现尤为突出,而在点数任务中表现一般,在其余任务中表现中等至中等以下。通过观察彩色圆点,我们可以认为格兰特-怀特学校似乎在口头任务(段落理解、句子完成和词义)上平均略胜一筹,而两所学校在与速度相关的任务上表现出相似的结果(即,加快对大写字母的辨别和加快点数)。但请记住,我们仅参考学校的具体表现——我们没有任何关于实际用于规范结果的参考人群的信息,我们也没有任何关于学校之间学生得分自然变化的线索。
正如我之前所说的,我们希望为 301 名学生中的每一名生成一个图表,并自动将其导出到我们预先指定的文件夹中。为此,我们将使用provis 包分析每个版本的代码,这是一个有用的交互式图形界面,可以帮助您找出计算机在哪里分配了最多的时间和内存。因此,您会发现代码中真正的速度瓶颈。
基地 R 图自动化
为了有一个好的参考,我们将首先创建一个循环,该循环遍历学生的 ID 以创建情节,然后保存它。在此代码的每个版本的结尾,我们将删除 plots 文件夹中的文件,以保持所有内容在试验中保持不变(从而不会覆盖任何现有的 png 文件)。

您可以看到,将 ggplot 对象保存到一个临时文件(以便在下一次迭代中覆盖它)已经消耗了相当多的内存,并分配了总时间的 4%用于代码执行。

更让我担心的是,几乎 96%的时间都花在对每个临时 ggplot 文件运行 ggsave-function 上,同时通过迭代瞳孔 id 向量来生成适当的文件名。至少我们现在有了一个文件夹,里面装满了每个学生的不同文件,甚至不用去碰它:

潮汐图形自动化
tidyverse 风格的图形自动化的优势在于它的可理解性——首先我们按照学生 ID 对数据进行分组,然后通过实用的 do 函数将 ggplot 对象与学生 ID 一起保存在数据框中。do 函数采用之前与 dplyr 相关的操作,执行特定函数(本例中为 ggplot ),并将输出存储在数据帧中。

正如你所看到的,tidyverse 版本比 for-loop 快一点,但并不令人印象深刻(188150 ms vs. 218730 ms)。循环速度慢了 1.16 倍,而 tidyverse 版本的代码速度提高了约 1.5 倍。14%.
如果将光标移到图形的下部,您可以看到在后台执行的功能的详细历史记录:例如,似乎每个 ggplot 在导出之前都是先打印的—尽管我们没有注意到。此外,如果我们单击“数据”而不是火焰图,我们可以很好地了解占用时间和内存最多的函数——在我们之前的分析之后,ggsave 同样减慢了这个过程,这不再让我感到惊讶。但我发现值得注意的是,分组过程分配了如此大量的内存,因为我们将数据帧分成了大量的组(每个孩子一个组)。

这里有一个小奖励:我们将尝试使用 purrr 包中的一项技术来生成图形,看看它是否比 dplyr 版本更有效。其思想是按 ID 分割数据框-每个子集将是一个存储在大型列表中的数据框。然后我们将 ggplot 函数映射到这个列表的每个元素。这里,pwalk()开始发挥作用,它是一个映射函数的变体,允许您在一个列表中提供任意数量的参数,在这种情况下,它帮助我们遍历列表的每个元素(每个学生一个 data.frame),应用一个函数。f (ggplot 函数)并相应地导出它们。
尽管这个语法对我来说非常漂亮和优雅,但是代码执行将大部分时间分配给了实际的绘图,甚至比 dplyr 版本的代码还多。现在问题仍然存在 data.table 在自动生成绘图方面做得更好吗?
Data.table 图形自动化
作为第一步,我们创建一个生成并保存 ggplot 的函数。然后我们遍历 data.table,将这个函数应用于每个子集(按 ID 分组)。

啊?与 dplyr 版本相比,data.table 生成图形的速度并不快,甚至还慢了一点。我猜想这是因为我们违反了编写高效 R 代码的几条规则:我们在每次调用函数时都将一个 ggplot 对象赋给了一个临时变量(p ),并且在每次数据表通过 ID 进行子集化时都调用具有绘图生成和保存功能的函数。但是在幕后到底发生了什么呢?请记住,data.table 类似于 SQL 中的查询,具有以下基本语法:
DT[i, j, by]*## R: i j by**## SQL: where | order by select | update group by*
根据数据表文档。by 是一个列表,包含 BY 中每一项的长度为 1 的向量(在我们的例子中是学生 id)。by 变量也可以通过名称直接用于 j;例如,如果 j 是一个绘图命令(就像我们的例子中一样),这对于图形的标题很有用。。SD 可以理解为代表数据的子集、自同或自引用。特别是,这也意味着。SD 本身是一个数据表。因此,这意味着我们在 301 个新生成的数据表中的每一个上使用我们定制的函数,这些数据表由学生 ID 子集化。我觉得你可以用 data.table 做类似的事情,但这不是它的设计初衷。
我们的关键要点是什么?
我们还了解到…
- 运行分组操作和绘图功能(如在 do-call 中)会花费很多时间。
- 我们应该避免在临时对象中保存不必要的变量(比如 ggplots)。
- 与映射和应用函数相比,循环并不总是最坏的选择,因为它们实际上是基于相同的原理。
- data.table 语法是数据操作目的的支持者,但不能应用于任何数据分析步骤。
- ggsave 占用了大部分时间,但是我们可以试着将预先指定的图像分辨率调小一点,使它更有内存效率。
在这里,我尝试结合所有世界的精华:
现在,由于 ggsave 函数分配了大量时间来导出高分辨率图像,我们将稍微调低分辨率。

…还有 tada!与我们的 purrr 版本的代码相比,我们能够减少 22%的计算时间成本,并找到了在大量个体上自动生成图形的最快版本。代码基准测试得到了回报。
奖励:我可以使用多核进行计算吗?
如果您熟悉 Python,您可能以前听说过并行计算。理论上,你可以通过将任务的不同部分分配给计算机上的每个 CPU(中央处理器)来提高计算速度。CPU 是计算机的大脑,负责幕后发生的计算。但是,R 只用其中一个。您可以通过运行以下代码来确定您的机器有多少个 CPU:

我的电脑上似乎有 4 个内核。我能在我的每段代码中使用这些吗?可惜我不能。并不是每个计算都可以并行运行——例如,如果每一行代码都是基于前一行的,就像我们的图形自动化例子一样。但是,如果您可以向前和向后阅读代码,它仍然会给您预期的结果,它可能是并行计算的一个很好的候选。这通常适用于算术运算,如随机抽样。如果这听起来像是你感兴趣的任务,R 中的并行包可能适合你。网上有一个很好的教程向你展示它是如何工作的。
那又怎样?
如果你花时间考虑时间,你可以学习写更多的内存高效的代码——R 中有各种各样的工具可以帮助你提高自己。特别是,如果您处理更大的数据集和更复杂的数据科学任务,这将非常有意义,因为您将更快地获得见解,并避免在未来某个时间点在时间压力下工作时遇到麻烦。另一个好处是:它会让你的代码更干净,增强可读性——如果你在一个团队中从事数据科学项目,你的同事肯定会从中受益。去开始分析你的分析吧!
参考文献
[1] Y. Rosseel,T.D. Jorgensen,N. Rockwood,D. Oberski,J. Byrnes,L. Vanbrabant,…和 h . Duholzingerswinford 1939(2021)lavaan R 包
[2]全球研发核心团队和贡献者(2021 年),基础研发包
[3] H. Wickham (2017), The tidyverse ,R package ver,1(1),1 .
[4] M. Dowle,A. Srinivasan,J. Gorecki,m .基里科,P. Stetsenko,T. Short,…和 X. Tan (2019),包'数据。表''数据的扩展。框架。
[5] O. Mersmann & S. Krey (2011),微基准:一个精确基准化 R 表达式的包,在 R 用户大会上,用户!2011 年 8 月 16 日至 18 日,英国考文垂华威大学(第 142 页)
[5] W. Chang,J. Luraschi & T. Mastny (2019),profivis:用于分析 R 代码的交互式可视化,R 包版本 0.3。7.
[6]全球 R 核心团队和贡献者(2020),平行 R 包
通过提高基数水平来提升电源 BI 性能
原文:https://towardsdatascience.com/boost-power-bi-performance-by-improving-cardinality-levels-ace820e5bd6f?source=collection_archive---------18-----------------------
你知道最优数据模型大小的最大“敌人”是谁吗?了解基数,并了解如何通过应用一些简单的技术来提高基数水平,从而提高报告性能

Bill Jelen 在 Unsplash 上拍摄的照片
性能,性能,性能…我们一直在努力实现它(或者至少我们应该努力),但在调整 Power BI 报告时,有许多事情需要记住。优化过程的第一步是确保您的数据模型大小处于最佳状态——这意味着,尽可能减小数据模型大小!这将使 VertiPaq 的存储引擎在为您的报告检索数据时以更高效的方式工作。
当您致力于优化数据模型大小时,您知道谁是您的头号“敌人”吗?!列数据类型,对吗?文本列将比数值类型的列消耗更多的内存。那只说对了一半!
最大的对手叫基数!
在我们解释什么是基数,以及它为什么对减少数据模型大小如此重要之前,让我们首先讨论 VertiPaq 存储数据的方式,一旦您将表的存储模式设置为 Import ( DirectQuery 存储模式超出了本文的范围,因此从现在开始,本文中所有关于基数的内容都专门指导入存储模式)。
一旦将存储模式设置为 Import,VertiPaq 将从列中扫描样本行,并基于特定列中的数据(不要忘记,VertiPaq 是一个列数据库,这意味着每一列都有自己的结构,并且在物理上与其他列分离),它将对数据应用某种压缩算法。
有三种不同的编码类型:
- 值编码 —仅适用于整数数据类型
- 哈希编码 —适用于所有非整数数据类型,在某些情况下也适用于整数数据类型
- RLE(游程长度编码) —在 哈希编码后出现 ,作为一个附加的压缩步骤,在这些场景中,当列中的数据以 VertiPaq“认为”的方式排序时,可以获得比仅使用哈希算法更好的压缩率
同样,在我们解释基数的概念在整个故事中的位置之前,让我们说明一下哈希算法在后台是如何工作的:

作者插图
正如您所看到的,VertiPaq 将创建一个由来自列的不同值组成的 字典 ,为每个值分配一个位图索引,然后存储这个索引值而不是“真实”值——简单地说,它将把数字 1 存储为指向“Book”值的指针,将数字 2 存储为“Shirt”值,依此类推。就像在后台创建一个虚拟维度表一样!
现在,假设该列中没有两个不同的值,而是如下所示:

作者插图
我们的“dimension”现在将有 10 行,因此您可能会认为这个字典表的大小将比只有两个不同值的情况大得多。
现在,你可能会问自己:好吧,这很好,但是这个故事和基数有什么共同之处呢?
基数表示列中唯一值的数量。
在我们的第一个例子中,基数为 2,而在第二个例子中,基数等于 10。
基数是影响列大小的首要因素。别忘了,列的大小不仅受其中数据大小的影响。你应该考虑字典的大小,和层次结构的大小一样。对于具有高基数(大量不同的值)并且不是整数数据类型的列,字典的大小明显大于数据本身的大小。
让我给你看一个例子。我将使用 DAX Studio 来分析数据模型大小背后的不同指标。一旦我在 DAX Studio 中打开“高级”选项卡并选择“查看指标”,就会出现一系列不同的数字,以了解我的数据模型的特定部分有多大:

作者图片
让我们快速重申一下上图中的关键观点。在 Chats 表中,datetmStartUTC 列是日期/时间数据类型,精度达到第二级,它有将近 900 万个不同的值!它的大小约为。455 MBs —这个数字不仅包括数据大小(26 MBs),还包括字典大小和层次结构大小。您可以看到 VertiPaq 应用了散列算法来压缩该列中的数据,但是最大的内存占用是字典大小(几乎 358 MBs)。
显然,这远远不是我们的数据模型的最佳条件。然而,我有好消息要告诉你…
有多种技术可以提高基数水平!
但是,这些技术需要在报表端做额外的工作,因为所有的度量都需要重写以反映数据模型结构的变化并返回正确的结果。因此,这些高级方法不是您在常规数据模型优化中需要应用的东西,它们更多的是一种“边缘”用例,当没有其他方法来减少数据模型的大小时,简单地说,当您处理非常大的数据集时!
但是,这并不意味着您不应该努力提高基数水平,即使对于更小更简单的数据模型也是如此。相反,这应该是 Power BI 开发过程中的一个常规部分。在本文中,我将向您展示两种简单的方法,它们可以显著降低列的基数,从而降低整个数据模型的大小。
通过更改数据类型来提高基数级别
老实说,您的用户多久需要分析一次二级数据?比如,我们在 09:35:36 或 11:22:48 有多少销售?我会说,毫无意义。在 98%的情况下,业务需求是每天都有可用的数据。也许在某些情况下,用户需要了解一天中的哪一段时间最“高效”:上午、下午或晚上……但是,我们仍然要关注大多数情况,在这些情况下,数据应该在每天的级别上进行细化。

作者图片
我已经将列的数据类型从日期/时间更改为日期,因为时间部分与报告目的无关。让我们在 DAX Studio 中刷新我们的指标:

作者图片
哦,哇哦!基数约为 900 万,而现在只有 1356(这是该列中不同天数)。但是,更重要的是,列的大小从 455 MB 降到了 7 MB!那是 huuuuge!看看字典的大小:VertiPaq 现在只处理 1356 个不同的值,而不是必须为 900 万个值构建一个字典,字典大小从 358 MBs 下降到 85 KBs!
另一个你可以应用的技巧是当你处理十进制数值的时候。将数据“按原样”导入 Power BI 的情况并不少见,而且,我不止一次看到有人导入小数点后精确到 5 位的十进制数字!我的意思是,真的有必要知道你的销售总额是 27.586.398,56891,还是显示 27.586.398,57 就可以了?
需要明确的是,在 Power BI 中格式化值以显示 2 个小数位不会影响数据模型的大小,这只是一个可视化的格式化选项,在后台,数据以小数位后 5 位数存储。

作者图片
现在,让我们在 DAX Studio 中检查这个表的指标。这是一个微不足道的数据模型大小,其中只有 151 个不同的值,但是您只能想象在数百万行的表上的差异:

作者图片
现在,我将转到超级查询编辑器,并将该列的类型更改为固定十进制数:

作者图片
我们现在已经将数值四舍五入到小数点后两位,所以让我们切换回 DAX Studio 并再次检查数字:

作者图片
即使在这个极小的数据集上,差别也是显而易见的!
使用汇总和分组提高基数水平
我想向您展示的另一项技术是如何利用汇总和分组的概念来提高基数级别,并使您的数据模型更具性能。
当您创建报表时,用户可能需要在比单个事务更高的粒度级别上理解不同的指标,例如,在特定日期售出了多少产品,在特定日期有多少客户注册,等等。这意味着您的大多数分析查询不需要针对单个事务,因为汇总的数据完全没问题。
如果我们总结聊天表的数据,让我们检查一下内存占用的差异。您可能还记得本文前一部分中的原始表,它占用 555 MBs:

作者图片
现在,如果我预先汇总数据,并按日期和/或产品对其进行分组,则编写以下 T-SQL:
SELECT CONVERT(DATE,datetmStartUTC) AS datetm
,productID
,COUNT(chatID) AS totalChats
FROM Chats
GROUP BY CONVERT(DATE,datetmStartUTC)
,productID
如果最常见的业务请求是分析每个日期和/或产品的聊天次数,这个查询将成功满足这些请求。
让我们检查一下这个总结表与原始表相比的大小:

作者图片
虽然原始表(即使 datetmStartUTC 列的基数级别有所提高)需要 105 MBs,但是聚合表只需要 217 KB!而且这张表可以回答大部分的经营分析问题。即使您需要包含额外的属性,例如客户数据,这仍然是检索数据的最佳方法。
还有更多!
即使您不能在数据源端创建汇总数据,您仍然可以通过利用 Power BI 中的聚合特性获得显著的性能提升。这是 Power BI 中最强大的特性之一,值得单独撰写一篇文章,甚至是一系列文章,比如 Phil Seamark 的 this,当我需要更深入地了解聚合及其在表格模型中的工作方式时,我总是会参考它。
结论
构建一个最优的数据模型不是一件容易的事情!有许多潜在的警告,有时很难避免通往“完美”模型的道路上的所有陷阱。然而,了解减少整体数据模型大小的重要性是调整 Power BI 解决方案的关键要求之一。
记住这一点,为了能够实现最佳的数据模型大小,您需要吸收基数的概念,作为决定列大小的主要因素。通过以正确的方式理解基数,以及 VertiPaq 存储和压缩数据的方式,您应该能够应用我们刚刚介绍的一些技术来提高列的基数级别,从而提高报告的整体性能!
感谢阅读!
成为会员,阅读 Medium 上的每一个故事!
用熊猫提升你的数据分析
原文:https://towardsdatascience.com/boost-your-data-analysis-with-pandas-69c4be5d73bb?source=collection_archive---------4-----------------------
你需要知道的关于熊猫的一切,通过代码示例开始提高你的生产力

文斯·拉塞尔在 Unsplash 上的照片
目录
- 为什么用熊猫?
- 入门安装和导入熊猫
- 熊猫数据帧读取文件并创建数据帧
- 检查数据帧
- 用熊猫操纵数据数据帧索引行和列用 loc 和 iloc 选择数据
- 处理缺失值 检测缺失值
删除缺失值 填充缺失值 - 可视化数据直方图
散点图 - 保存到文件
- 结论
无论你是在建立复杂的机器学习模型,还是只想在 Excel 电子表格中组织每月的预算,你都必须知道如何操作和分析数据。
虽然许多工具都可以完成这项工作,但今天我们将谈论其中最常用和最适合初学者的工具之一, 熊猫 。
为什么用熊猫?
Pandas 是一个开源的 Python 库,旨在处理数据分析和数据操作。援引官网,
“pandas 是一个快速、强大、灵活且易于使用的开源数据分析和操作工具,构建于 Python 编程语言之上。”
它建立在 NumPy (用于科学计算的 Python 库)之上,它有几个用于清理、分析和操作数据的函数,可以帮助您提取关于数据集的有价值的见解。Pandas 非常适合处理表格数据,如 SQL 表或 Excel 电子表格。
Pandas中的主要数据结构是一个名为 DataFrame 的二维表。要创建 DataFrame,您可以导入几种格式的数据,例如 CSV 、 XLSX 、 JSON 、 SQL 等等。通过几行代码,您可以添加、删除或编辑行/列中的数据,检查集合的统计数据,识别和处理缺失的条目,等等。
此外,如上所述, Pandas 应用广泛,对初学者友好,这意味着你会在网上找到很多关于它的内容,找到你的问题的答案应该不难。
入门指南
首先,我们需要安装 Pandas 并且有几种不同的环境可以运行它。如果你想直接在你的机器上运行它,你应该看一下 Anaconda ,这是一个针对科学计算的发行版,附带了数百个预安装的软件包。Anaconda 可以安装在 Windows、macOS 和 Linux 上。
然而,有一种更简单的方法通过你的浏览器开始使用熊猫,使用云中的 Jupyter 笔记本。例如,你可以使用 IBM Watson Studio 或者 Google Colab 。两者都可以免费使用,并且预装了几个 Python 包。
在本文中,我使用的是 Google Colab ,因为它开箱即用,不需要任何预先设置。
安装和导入熊猫
您需要在您的环境中编写以下命令来安装 Pandas,这取决于您的软件包管理器。
pip install pandas
或者
conda install pandas
请注意,在 Google Colab 中,我们不需要使用上面的代码,因为 Pandas 是预装的。
现在,我们需要导入熊猫,这样我们就可以在我们的 Jupyter 笔记本中使用它了。
import pandas as pd
我们通常将它作为快捷方式“as pd”导入,这样我们就不需要每次需要调用熊猫函数时都要写完整的单词。
熊猫数据框
安装并导入 Pandas 之后,让我们看看如何读取文件并创建一个 Pandas DataFrame 。在这篇文章中,我们将要处理的数据集是一个简化版的数据集,它是在一个关于房价的竞赛中提供的。
包含该数据集的文件是一个**。CSV** (逗号分隔值)。如果你想自己玩,你可以在这里找到它,在我的 Github 仓库里。
读取文件和创建数据帧
要将文件读入数据帧,我们只需在下面的函数中输入文件路径作为参数:
PATH = 'https://raw.githubusercontent.com/rmpbastos/data_sets/main/kaggle_housing/house_df.csv'df = pd.read_csv(PATH)
注意,我使用了函数 read_csv ,因为我们正在处理一个 csv 文件。如上所述,熊猫可以处理几种文件扩展名,你可以在这里查看。
上面的函数读取了 csv 文件,并自动从中创建了一个数据帧。但是如果你想从 Python Dict 、 List 、 NumPy Array 或者甚至从另一个 DataFrame 中创建一个 DataFrame,你可以使用下面的函数。
df = pd.DataFrame(mydict)
让我们检查一下我们刚刚创建的数据帧的类型。
type(df)

检查数据帧
在本文的其余部分,我们将使用上面提到的住房数据集。下一件我们应该做的事情是看看我们的数据框架。我们可以用函数 head 检查第一个 n 条目。如果没有提供 n ,我们将默认看到前 5 行。
df.head()

乍一看,一切正常。我们还可以使用函数 tail 检查集合的最后一个条目。
df.tail()

接下来,让我们使用 shape 属性来检查数据的维度。
df.shape

它返回一个包含行数和列数的元组。我们的数据帧有 1460 行和 16 列,或者说特征。
接下来,我们可以使用功能信息查看数据集的概要。
df.info()

它向我们展示了关于数据帧的有用信息,比如列名、非空值、数据类型和内存使用情况。从这个总结中,我们可以观察到一些列缺少值,这个主题我们将在后面看到。
以下函数将为我们提供一些关于数据集的描述性统计数据。
df.describe()

此函数显示每个要素的计数、平均值、中值、标准差、上下四分位数以及最小值和最大值。请注意,它只显示关于数字特性的数据(数据类型为 int 或 float 的列)。
在这个序列中,在进入下一节之前,让我再向您展示一个函数, value_counts 。
df['Neighborhood'].value_counts()

该函数返回包含每列唯一值数量的序列。它可以应用于整个数据帧,但是在上面的例子中,我们只将它应用于列“Neighborhood”。
在我们继续之前,让我总结一下数据集的每个特性,以便更好地理解。
- Id —每行的唯一标识(我们将使用它作为我们的索引)。
- LotArea —以平方英尺为单位的批量
- 街道 —道路通道类型
- 邻里 —房屋的物理位置
- 住宅风格 —居住风格
- 建造年份 —建造日期
- 中央空调 —中央空调
- BedroomAbvGr —地下室标高以上的卧室数量
- 壁炉 —壁炉数量
- 车库类型 —车库位置
- 车库建造年份
- 车库面积 —车库面积,平方英尺
- 公摊面积 —公摊面积,平方英尺
- 泳池质量控制 —泳池质量
- 栅栏 —栅栏质量
- 销售价格 —房价
我们的数据集包含不同类型的数据,如数值型、分类型、布尔型,但我们不会深入研究这些概念,因为它们超出了本文的范围。
现在,让我们开始操作我们的数据框架。
用熊猫操纵数据
熊猫为我们提供了几个处理数据的工具。在这一节中,我们将看到如何操作行和列,以及在表中定位和编辑值。让我们开始为我们的数据框架设置一个索引。
数据帧索引
在检查了我们的数据之后,我们注意到第一列( Id )对于每一行都有一个唯一的值。我们可以利用它,使用这个列作为我们的索引,代替我们设置 DataFrame 时默认创建的索引。
df.set_index('Id', inplace=True)df.index

当将参数就地设置为真时,数据帧将就地更新。否则,使用默认值 inplace = False ,将返回数据帧的副本。
如果您事先知道您将使用数据集中的一列作为索引,您可以在读取文件时设置它,如下所示。
df = pd.read_csv(PATH, index_col='Id')
让我们来看看设置索引后集合是什么样子的。

数据集现在看起来更干净了!继续,我们来谈谈行和列。
行和列
正如您已经注意到的,数据框是表格数据,包含行和列。在熊猫中,单列一栏可以叫做系列。我们可以很容易地检查这些列,并用下面的代码访问它们。
df.columns

df['LotArea'].head()

type(df['LotArea'])

请注意,我们的数据框架中的一列属于类型系列。
重命名列
用熊猫来重命名你的列真的很简单。例如,让我们将我们的特性 BedroomAbvGr ,并将其重命名为 Bedroom 。
df.rename(columns={'BedroomAbvGr': 'Bedroom'}, inplace=True)
您可以一次重命名多个列。在函数 rename 内,将所有“旧名称”和“新名称”作为键/值对添加到列字典中。
添加列
您可能想在数据框架中添加一列。让我们看看你怎么做。
我将借此机会向您展示我们如何创建数据帧的副本。让我们在副本中添加一列,这样就不会改变原始数据帧。
df_copy = df.copy()df_copy['Sold'] = 'N'
这是创建新列最简单的方法。请注意,我为本列中的所有条目分配了一个值**“N”**。
检查添加了新列的下图。

添加行
现在,假设您有另一个数据帧( df_to_append ),其中包含您想要添加到 df_copy 的 2 行。将行追加到数据帧末尾的一种方法是使用函数 *append* 。
data_to_append = {'LotArea': [9500, 15000],
'Steet': ['Pave', 'Gravel'],
'Neighborhood': ['Downtown', 'Downtown'],
'HouseStyle': ['2Story', '1Story'],
'YearBuilt': [2021, 2019],
'CentralAir': ['Y', 'N'],
'Bedroom': [5, 4],
'Fireplaces': [1, 0],
'GarageType': ['Attchd', 'Attchd'],
'GarageYrBlt': [2021, 2019],
'GarageArea': [300, 250],
'PoolArea': [0, 0],
'PoolQC': ['G', 'G'],
'Fence': ['G', 'G'],
'SalePrice': [250000, 195000],
'Sold': ['Y', 'Y']}df_to_append = pd.DataFrame(data_to_append)df_to_append

现在,让我们将上面的 2 行数据帧添加到 *df_copy* 中。
df_copy = df_copy.append(df_to_append, ignore_index=True)
检查 df_copy 的最后一个条目,我们有:
df_copy.tail(3)

移除行和列
为了消除数据帧的行和列,我们可以使用函数 drop 。假设我们想要删除最后一行和列“Fence”。查看下面的代码。
df_copy.drop(labels=1461, axis=0, inplace=True)
上面的函数删除了最后一行(Id 为 Id 为 1461 的行)。您也可以一次删除几行,将索引列表作为参数传递。
axis=0,这是默认值,意味着您正在删除一行。对于列,我们需要指定 axis=1,如下所示。
df_copy.drop(labels='Fence', axis=1, inplace=True)
使用 loc 和 iloc 选择数据
选择数据的最简单方法之一是使用 loc 和 iloc 方法。
loc 用于通过标签/索引或基于布尔数组访问行和列。假设我们想要访问索引= 1000 的行。
df.loc[1000]

上面的方法选择了 index = 1000 的行,并显示了该行中包含的所有数据。我们还可以选择想要可视化的列。
df.loc[1000, ['LotArea', 'SalePrice']]

现在,让我们看看如何将条件应用于 loc 。假设我们想要选择销售价格至少为 600,000 美元的所有房屋。
df.loc[df['SalePrice'] >= 600000]

通过一行简单的代码,我们只找到了 4 栋价值超过 60 万美元的房子。
iloc 用于根据整数位置或布尔数组选择数据。例如,如果我们想要选择包含在第一行和第一列中的数据,我们有以下内容:
df.iloc[0,0]

显示的值是 ID 为 1 的行的 *LotArea* 。记住整数位置是从零开始的。
我们也可以选择一整行。在这种情况下,该行位于位置 10
df.iloc[10,:]

我们可以选择整个列,例如最后一列。
df.iloc[:,-1]

我们也可以选择多行和多列,如下所示。
df.iloc[8:12, 2:5]

处理缺失值
关于如何处理缺失值,可以谈很多。请记住,这里的目标不是深入主题,而是向您展示由 Pandas 提供的处理缺失值的工具。
检测缺失值
这里的第一步是用函数 isnull 找到数据集中缺失的值。该函数将返回一个与原始数据帧大小相同的对象,包含集合中每个元素的布尔值。它将认为为真值,如 None 和 NumPy。南。您可以通过下面的代码行找到它们。
df.isnull()

注意,处理上面返回的数据可能很麻烦。如果您正在处理一个非常小的数据集,您应该没问题,但是对于成千上万的行和几个列,就像在我们的例子中,我们只能添加每列缺失值的数量,如下所示。
df.isnull().sum()

现在好多了!我们可以很容易地看到每一列中缺失值的数量。我们还可以意识到大多数专栏都是完整的,这很好。 sum 函数将所有由返回为 True 的值相加为 null ,因为它们等同于 1 。假值相当于 0 。
我们还可以检查每列缺失值的比例:
df.isnull().sum() / df.shape[0]

让我们更进一步,使用 Python 只获取缺少值的列,并显示缺少值的百分比。
for column in df.columns:
if df[column].isnull().sum() > 0:
print(column, ': {:.2%}'.format(df[column].isnull().sum() /
df[column].shape[0]))

删除丢失的值
检测到丢失的值后,我们需要决定如何处理它们。在这里,我将向您展示如何消除丢失的值。
在删除整个列或行之前,我们应该非常谨慎,因为我们是在从数据集中提取数据,这会损害您的分析。
首先,我们来思考一下特性 PoolQC 。由于该列中有超过 99%的值丢失,我们将删除它。正如我们在前面的章节中已经看到的,我们可以用函数 drop 删除一个列。
这里,我将使用原始数据帧的副本。
df_toremove = df.copy()df_toremove.drop(labels='PoolQC', axis=1, inplace=True)
现在,我们来看看 GarageType 。因为它只有大约 5%的值丢失,我们可以使用函数 dropna 简单地删除该特性中丢失值的行。
df_toremove.dropna(subset=['GarageType'], axis=0, inplace=True)
填充缺失值
当我们处理缺失值时,除了删除它们之外,我们还可以用一些非空值来填充这些缺失数据。有几种技术可以帮助你确定应该在数据中插入哪些值,包括使用机器学习,我真的建议你搜索关于这个主题的文章,但这里我只展示由熊猫提供的完成这项工作的工具。
首先,我们来看看特性栅栏。请注意,它有 80%的缺失值。假设它的发生是因为这些房子没有围栏!因此,我们用字符串 NoFence 填充这些缺失的数据。
我将再次使用原始数据帧的副本。
df_tofill = df.copy()df_tofill['Fence'].fillna(value='NoFence', inplace=True)
现在,让我们检查一下特性 GarageYrBlt 。在这个例子中,我将向您展示如何用列的中值填充条目。
garage_median = df_tofill['GarageYrBlt'].median()df_tofill.fillna({'GarageYrBlt': garage_median}, inplace=True)
让我提醒你,这些例子只是为了教育目的。您可能已经意识到 GarageType 和 GarageYrBlt 有 81 个缺失值。大概是因为那些房子没有车库吧。在现实分析中,删除这些缺少 GarageType 的行并用一些值填充 GarageYrBlt 可能不是最明智的做法。
事实上,如果我没有使用原始数据帧的副本,您会看到当我们删除缺少 GarageType 的行时,这些也是缺少 GarageYrBlt 的 81 行。这显示了在修改数据之前解释和了解数据的重要性。
可视化数据
在这一节,我将谈论如何用熊猫做一些简单的绘图。如果您想构建更精细的图表,我建议您看看另外两个 Python 库: Matplotlib 和 Seaborn 。
在这里,我们将看到两种类型的图表:直方图和散点图。
直方图
直方图非常适合显示数据的分布。下面是特性销售价格的直方图,其中 x 轴包含将值划分为区间的箱,而 y 轴表示频率。
df['SalePrice'].plot(kind='hist')

散点图
有了散点图,你可以直观地看到两个变量之间的关系。使用笛卡尔坐标构建图表,将值显示为点的集合,每个点有一个变量的值确定在 x 轴上的位置,另一个变量的值确定在 y 轴上的位置。
让我们为变量 SalePrice 和year build构建一个散点图,以检查它们之间是否有任何关系。
df.plot(x='SalePrice', y='YearBuilt', kind='scatter')

嗯,我们可以看到销售价格和建造年份之间有一个小的正相关关系。
plot 函数还支持许多其他类型的图表,如折线图、条形图、面积图、饼图等。
保存到文件
在本文的最后一部分,让我们看看如何将数据帧保存为文件。
就像我们读取 csv 文件来创建我们的数据帧一样,我们也可以将我们的数据帧保存为各种格式。如果您使用的是 Google Colab ,您可以简单地编写下面一行代码,来保存一个 csv 文件。
df.to_csv('My_DataFrame.csv')
保存的文件可以在 Google Colab 左上角的文件夹中找到,如下图所示。

您也可以在计算机中指定路径。例如,在 windows 中:
df.to_csv('C:/Users/username/Documents/My_DataFrame.csv')

杰瑞米 C 在 Unsplash 上的照片
结论
我希望这篇文章能帮助你了解你可以用熊猫做什么。经过一些练习后,操纵你的数据变得相当容易。
熊猫广泛应用于数据科学。许多数据科学家在建立机器学习模型之前利用它来操纵数据,但即使在使用 Excel 完成更简单的任务时,你也可以从中受益。
如今,在工作中,我过去在 excel 中做的许多活动现在都用 Python 和 Pandas 来做。也许学习曲线有点陡峭,但是您的生产力的潜在增长是值得的,更不用说 Python 是一个非常好的工具!
完整代码请参考笔记本。
提高数据分析师或数据科学家的工资
原文:https://towardsdatascience.com/boost-your-data-analyst-or-data-scientist-salary-4cf68a8fef48?source=collection_archive---------23-----------------------
意见
…以下是方法

Jp 瓦列里在Unsplash【1】上的照片。
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指南 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
目录
- 介绍
- 硕士学位
- 突出项目经验
- 绩效考核跟踪
- 特定行业的经验
- 摘要
- 参考
介绍
工资可能会因过多的因素而经常变化,但这并不意味着你不能增加工资。你可以做四件事来确保你的薪水在数据分析和数据科学领域都具有竞争力。我将概述这两个热门技术职位在薪酬方面的主要差异,同时描述如何应用每一项改进来增加你的薪酬。我坚持这些改进来提高我自己的薪水,所以我希望它们也能为你所用。当然,有些人会成功,有些人不会。
根据 Glassdoor 的数据,数据分析师的平均薪资为:
$62,453/yr
值得注意的是,一些公司提供更高的薪水,如谷歌在$95,941/yr和脸书在$114,18/yr。这种差异的部分原因是因为他们需要硕士学位,以及一些用数据科学特征定义数据分析的公司。
鉴于数据科学家的平均工资为:
$113,309/yr
虽然这两个职位之间的差距相当大,但加薪的方法可以适用于这两个角色。也就是说,我将在下面讨论这四种你可以增加工资的方法。
硕士学位

科尔·凯斯特在Unsplash【4】上的照片。
数据科学家
毫不奇怪,完成数据科学硕士学位将有助于增加你的薪酬。然而,主要原因并不像你想的那么明显。具体来说,数据科学硕士学位比数据科学本科学位更常见。因此,这并不一定意味着你需要大约六年的数据科学经验,而更像是一到两年。拥有这个学位意味着你最近在数据科学的专业化方面有所实践。
数据分析师
至于数据分析师,你需要获得的硕士学位并不简单。大多数程序都有不同的命名或分类。一些关于数据分析的常见学位包括但不限于:
- 商业分析
- 商业
- 分析学
- 商业智慧
需要记住的最重要的一点是,尽管硕士项目已经迅速变得流行,尤其是在数据科学领域,但它们开始变得不如 和 重要。这种差异是因为公司承认其他形式的体验也具有可比性。另一件需要指出的事情是,当你获得数据分析相关或数据科学的硕士学位时,你很可能会处于另一个级别的 资历 ,这最终也会增加你的薪酬。我个人很难在没有硕士学位的情况下获得任何面试机会,但这几乎是因为我之前没有什么专业经验,所以如果你是第一次开始工作,并打算获得硕士学位,那么就去争取吧,但如果你已经是一名公认的数据分析师或数据科学家,那么你最有可能通过更快的课程变得专业化和认证来增加你的工资。
突出项目经验

照片由优 X 创投在Unsplash【5】上拍摄。
这种增加工资的方法要简单和容易得多。假设你已经有了数据分析和数据科学的经验,大约 1-3 年后,你会发现你的薪水会因为在简历中更好地突出你的项目而增加。
这种强调并不是夸大任何项目,而是清晰地勾勒出比时间本身更有经验的适用项目。
数据科学家
作为一个操作项,您可以按以下特定方式构建您的项目:
what you did, how you did it, and what was its effect
例如:“用 Python 创建了一个带随机森林的自动产品分类器,节省了 40%的时间”
数据分析师
示例:“用 Python 在 Tableau 中创建了一个指标仪表板,处理 10 个报告的速度是手动的两倍”
如您所见,对于这两个角色,您都可以遵循这个简单的格式,快速确定您的能力及其对业务的影响。对于你的简历,你可以按照这种格式添加,比如说,大约五个你参与过的主要项目——你必须记住,除非你告诉或展示给招聘经理或招聘人员,否则他们不会知道你的任何历史。
绩效考核跟踪

LinkedIn 销售导航员在Unsplash【6】上的照片。
虽然你薪水的第一次提高可能来自一年或两年的硕士学位,第二点是更好地突出你的简历项目,但你薪水的下一次提高可能来自你在当前职位上的绩效评估。如果你的公司给你提供了一份绩效评估,这可能不是由你决定的,但如果你足够幸运有这个选择,那么你可以在整个工作经历中做一些事情,以确保你正确地强调了你的绩效,最终增加你的工资。如果你想采取一个更大胆的方法,因为你没有一个绩效评估或一些让你有机会赚更多钱的季节性评估,你可以用类似的格式向你的老板展示你一直在做什么,用什么工具,以及对公司有什么影响。
无论是数据分析师还是数据科学家的职位,你都可以关注以下追踪工具来增加你的薪水:
- 写下你的主要成就
- 比较一下 当前 空间,与 目标 ,然后你的 贡献
—例如,当前模型准确率为 50%,目标为 70%,而您的贡献为 80%,这基本上突出了您超出了预期
- 在公司内部建立你自己的个人目标,过去几个月你缺少什么,你在哪些方面有所提高
一些公司会大幅提高工资,但前提是你能给他们一个理由,所以要确保到时候,你不是在苦苦寻找过去几个月你一直在做什么,而是准备好向领导证明自己。
特定行业的经验

LinkedIn 销售导航员在Unsplash【7】上的照片。
为了在医疗保健、体育或金融等特定行业找到一份工作,你当然会希望拥有一些与行业相关的经验,以增加获得高薪的机会。对于数据分析和数据科学来说,你可以看到经验不一定是过去工作中的职位本身,而是同一行业中的其他工作。原因是行业知识对一些公司来说非常有价值。例如,一些数据科学工作要求你是主题专家。因此,如果你对医疗保健一无所知,你可能会被提供他们工资范围的低端,尽管从技术上来说你仍然有资格获得这份工作。
这里有一些方法可以提高你的行业经验:
- 来自你最终想从事的行业的经验,包括过去的职位、训练营、证书、在线课程和 YouTube 上的在线视频
- 这些经历不必是每年一次的项目,而是高度专业化的项目,突出你除了是数据分析师或数据科学家之外,还是主题专家
- 进一步对冲成功的承诺——这些可能对一些人成功,也可能不成功,有许多因素可能会发挥作用。
——添加任何你觉得可以分享的个人见解/经历,因为这些往往会给这类话题带来最大的可信度。
摘要
谈判薪资可能会令人生畏,但如果你处理得当,你或许可以完全绕过这一部分,拿到公司薪资范围内的最高薪资。完成以下任何一项:获得硕士学位,在简历上更好地突出你的项目经验,绩效评估的改进,以及获得特定行业的经验,这些都将使你更有可能增加工资。如你所见,无论你是数据分析师还是数据科学家,都有无数种方法可以提高你的薪水。我已经谈了四个主要的,但还有很多。最终,你会希望确定你目前作为数据分析师或数据科学家的薪水,我在我的文章顶部强调了这一点,然后专注于改善促成更高薪水的主要因素。
值得注意的是,这些改进对某些人来说可能成功,也可能失败,有几个因素可能会影响你的薪水如何提高。对我个人来说,这些是我增加自己薪水的步骤。虽然还不完全清楚是什么决定了一家公司的工资增长,但改善自己和自己的工作可以在你的数据分析或数据科学职业生涯中带来巨大的成就。
以下是所有的改进,总结如下:
* Master's Degree* Highlight Project Experience* Performance Review Tracking* Industry-Specific Experience
我希望你觉得我的文章既有趣又有用!如果您使用了这些数据分析师和数据科学薪资提升方法— ,请在下面随意评论,您使用了哪些方法? 现在对你的职业生涯有帮助吗?你同意还是不同意,为什么?
请随时查看我的个人资料和其他文章,也可以通过 LinkedIn 联系我。我与这些提到的公司没有关系。
感谢您的阅读!
参考
[1]照片由 Jp Valery 在Unsplash(2019)上拍摄
[2] Glassdoor,Inc .,数据分析师薪酬,(2008–2021)
[3] Glassdoor,Inc .,数据科学家薪酬,(2008–2021)
[4]科尔·凯斯特在 Unsplash 上拍摄的照片,(2017)
[5]2019 年 Unsplash 上优 X 创投的照片
[6]照片由 LinkedIn 销售导航员在 Unsplash 上拍摄,(2017)
[7]照片由 LinkedIn 销售导航员在Unsplash(2015)上拍摄
提高您的数据即生产力
原文:https://towardsdatascience.com/boost-your-data-viz-productivity-1ae29fb713af?source=collection_archive---------33-----------------------
数据科学家可视化数据指南
使用 Altair 快速创建令人惊叹的可视化

牛郎星是天鹰座中最亮的星星
我们大多数人需要听音乐才能理解它有多美。但通常这就是我们展示统计数据的方式:我们只展示音符,不演奏音乐。—汉斯·罗斯林
数据可视化对于理解数据分析之美至关重要。通过数据可视化,我们的利益相关者了解我们分析的影响。这有助于他们集中注意力,做出明智的决定。
然而,尽管它很重要,我一直收到关于有抱负的数据科学家如何开始探索数据分析的问题。
简单,具有数据可视化。
牛郎星的力量
“Altair 是一个针对 Python 的声明式统计可视化库,基于 Vega 和 Vega-Lite ,源代码可在 GitHub 上获得 — 牛郎星即
Altair 是 Python 中的一个数据可视化包,它基于 Vega 和 Vega Lite 语法,并根据最佳可视化实践进行了更新。
宣布你的需求
Altair 支持声明式编程,它允许您基于输入数据和输出属性构建 Altair 可视化。你将只陈述你需要什么,而不是如何实现目标的细节。

来源 Unsplash
假设你要买鸡蛋。
声明式编程会说“给我找鸡蛋买鸡蛋。这是现金”
然而传统编程会说“去法院超市,去 6 号通道找到你右手角的鸡蛋,去收银台用 5 美元现金支付”。
显然,从这个例子中,声明式编程将卸载**“如何”**。与金钱和鸡蛋类似,您只需要提交输入数据和输出属性,可视化结果就会自动呈现。
你甚至不需要理解 Altair 是如何处理你的可视化的。你将简单地指导和接受结果。这就是 Altair 支持声明式编程的美妙之处。
其实这一点都不外国。许多语言也是用相同的概念构建的。 SQL(结构化查询语言)和 Kubernetes yaml 使用声明性概念。 Dash 也是基于声明式编程构建 dashboard web 应用的工具。两者都是数据科学家优化数据检索和开发流程的重要工具。
希望我让你兴奋!!让我们开始吧
牛郎星的组件
Altair 使用这些组件作为主要语法来指导可视化:
- 数据 →可视化的数据帧
- 标记 →每行观察的符号(线、条、刻度、点)
- 编码 →数据表示通道(X 位置、Y 位置、颜色、尺寸)
- 转换 →应用可视化之前的数据转换(计算、过滤、聚集、折叠)
- 标尺 →输入数据并将其显示在屏幕上的功能。
- 指南 →图表(图例)上的视觉辅助,x 轴和 y 轴上的刻度。
用 Altair 弄脏你的手
Colab 笔记本
在这篇文章中,我们将使用下面的 Colab 笔记本。
装置
要安装很容易,您可以运行 pip 安装如下
pip install altair
数据
对于我们的教程,我们将使用这些数据集:
data.cars:来自 UCI 机器学习知识库的 AutoMPG 数据集。data.stocks:每日收盘股票价格(AAPL、AMZN、GOOG 等)data.seattle_weather:2012-2015 年西雅图天气
这些数据集可以在 vega_datasets 上获得,Vega _ datasets 与 Altair 一起预加载到 Pandas 数据帧中。

UCI 机器学习知识库上预装的 Cars 数据集(来源于作者)
牛郎星一步步来
图表
表示“另类的”图表是一种需要数据、标记和编码才能运行的结构。
alt.Charts()
数据
要插入数据,可将数据框输入功能图()。
alt.Charts(cars)
标记
需要标记来表示每一行观察值(线、条、记号、点)
alt.Charts(cars).mark_tick()
编码
对数据集的表示进行编码。您可以将 1 列作为 1D 表示,2 列作为 2D,3 列作为 3D,等等。
alt.Chart(cars).mark_tick().encode(
encoding_1 = value_1,
encoding_2 = value_2,
......
)
你只需要一张图表
创建一个图表很容易。您可以添加维度,在声明性语言中更改不同的符号,一切都会为您处理好。
线条、线条、点等等!
只需将 mark_line()转换为 mark_bar()

满足您可视化需求的简单声明性命令(由作者提供)
构建直方图超级简单!
alt.Chart(weather).mark_bar().encode(
x=alt.X('date', timeUnit='month', type='nominal'),
y='mean(temp_max):Q',
color='weather'
)

简单直方图(来源于作者)
使用热图进行模式发现
创建热图。你可以把符号从mark_bar() 替换成mark_rect().
alt.Chart(weather).mark_rect().encode(
x=alt.X(‘date’, timeUnit=’date’, type=’ordinal’),
y=alt.Y(‘date’, timeUnit=’month’, type=’ordinal’),
color=’mean(temp_max)’,
tooltip=[‘mean(temp_max)’]
)

基于温度的月份和日期的热图(来源于作者)
从这里我们可以发现,最高气温是从 4 月份开始到 10 月份(颜色较深)。这与旱季相对应。整洁!
许多图表可供比较
Altair 还配备了简单的语言来表示多图形表示。
例如,想象三维散点图的 3X3 散点图。你所需要的只是模块repeat.
alt.Chart(cars).mark_circle().encode(
alt.X(alt.repeat("column"), type='quantitative'),
alt.Y(alt.repeat("row"), type='quantitative'),
color='Origin:N'
).properties(
width=250,
height=250
).repeat(
row=['Horsepower','Acceleration','Miles_per_Gallon'],
column=['Horsepower','Acceleration','Miles_per_Gallon']
).interactive()

重复的列和行创建散布矩阵(来源于作者)
要比较的交互式图表
您甚至可以添加交互来比较多个图表。例如,您可以使用 altair 中的模块selection 来创建选择。
brush = alt.selection(type='interval',resolve='global')
base = alt.Chart(cars).mark_point().encode(
y='Miles_per_Gallon',
color=alt.condition(brush,'Origin',alt.ColorValue('lightgray'))
).properties(
selection=brush,
width=250,
height=250
)
base.encode(x='Horsepower') | base.encode(x='Acceleration')

互动情节(来源于作者)
您甚至可以使用稍微复杂的选择来创建基于时间的动画。例如,您可以应用year作为选择和过滤标准。
from altair.expr import datum, if_
from vega_datasets import datapop = data.population.url
pink_blue = alt.Scale(domain=(‘Male’, ‘Female’),
range=[“steelblue”, “salmon”])
slider = alt.binding_range(min=1900, max=2000, step=10)
year = alt.selection_single(name=”year”, fields=[‘year’], bind=slider)
alt.Chart(pop).mark_bar().encode(
x=alt.X(‘sex:N’, axis=alt.Axis(title=None)),
y=alt.Y(‘people:Q’, scale=alt.Scale(domain=(0, 12000000))),
color=alt.Color(‘sex:N’, scale=pink_blue),
column=’age:O’
).properties(
width=20,
selection=year,
).transform_calculate(
“sex”, if_(datum.sex == 1, “Male”, “Female”)
).transform_filter(
year.ref()
)

时间动画图(来源于作者)
最后的想法
Altair 让绘制哪怕是复杂的剧情变得非常简单。它使我们能够直接将想法可视化,而不必担心背后的机制。用最少的努力就可以创造出从简单到复杂的惊人的情节和视觉效果。—Parul Pandey—H2O . ai 的数据科学家
同样,我爱上了牛郎星。它简单、直观、快速。我用谷歌搜索 matplotlib 来添加交互式线条并将多个图对齐在一起的日子已经一去不复返了。Altair 足够直观,可以提高我可视化数据的效率。
如果你有兴趣了解更多关于牛郎星的信息,请查看
- 我的实习实验室实验
- 帕鲁尔·潘迪关于牛郎星的介绍。这个教程启发我记录我自己的牛郎星学习。Parul 提供了关于 Altair 的清晰介绍。我强烈推荐这个作为额外的参考。
- 官方文档配有解释和实例探讨(牛郎星教程、牛郎星案例分析、实例图库)
索利·德奥·格洛丽亚
关于作者
文森特用 ML @ Google 对抗网络滥用。文森特使用高级数据分析、机器学习和软件工程来保护 Chrome 和 Gmail 用户。
除了在谷歌的工作,文森特还是《走向数据科学媒体》的特约撰稿人,为全球 100 多万观众的有志 ML 和数据从业者提供指导。
在空闲时间,文森特在佐治亚理工学院攻读硕士学位,并为铁人三项/自行车旅行进行训练。
最后,请通过LinkedIn,Medium或 Youtube 频道 联系文森特
提升您的网络性能
原文:https://towardsdatascience.com/boost-your-network-performance-cc0a2a95c5ef?source=collection_archive---------26-----------------------
超参数调整和训练优化
你准备了一个有几百万样本的大数据集,设计了一个最先进的神经网络,训练了 100 个纪元,却得不到一个满意的结果?这是很多 ML 从业者都很熟悉的问题。另一个流行的观点是,神经网络是黑盒,所以除非代码中有明显的错误,否则几乎不可能识别问题并提高性能。然而,不应该是这样的。到目前为止,ML 社区对不同组件如何影响网络的训练速度和性能有了相当好的理解。在本文中,我将分享一些优秀的超参数调优和性能评估方法。
培训和验证损失
虽然很难将神经网络的内部工作可视化,但一些线索对于普通从业者来说是容易获得的,例如验证和训练损失监控。损失是模型收敛的一个强有力的指标。当额外的训练不能改进模型时,模型“收敛”。缺乏收敛性表明模型无法学习数据的底层结构。
在这种情况下,记住过拟合和*欠拟合的概念是有益的。*欠拟合是指一个模型既不能学习训练数据,也不能推广到新数据,因为它不够强大。过度拟合是一种相反的情况,其中模型太了解训练数据和噪声。训练目标是在过度适应和欠适应之间找到一个最佳点,以确保最佳训练。但是我们如何知道模型是过拟合还是欠拟合呢?

过度拟合和欠拟合之间的权衡。
上图说明了我们想要实现验证损失的水平部分,这是欠拟合和过拟合之间的平衡点。连续下降的曲线表示拟合不足,而损失增加则表示拟合过度。监控过拟合和欠拟合的早期迹象可以节省大量时间。如下图所示,在训练早期的过度拟合表明超参数的次优选择。如果超参数设置正确,它们应该在整个过程中表现良好:

黑色方块显示了训练早期过度适应的迹象(Smith,2018。)
我现在将解释各种超参数如何影响过拟合-欠拟合权衡。先说学习率。
学习率
学习率是一个超参数,它控制着我们调整网络权重的程度。低学习率会导致过度拟合,因为模型的步长很小,很容易拟合噪声,而不是实际的数据结构。较大的学习率有助于通过制定更重要的步骤来规范训练。但是,如果学习率太大,训练就会发散。循环学习率(CLR)和学习率范围测试(LRR)是为特定用例定义最合适的学习率的有用程序。
循环学习率
要使用 CLR,您需要指定最小和最大学习速率以及步长。步长是每步使用的历元数,一个周期由两个这样的步骤组成,一个是学习率线性增加,另一个是线性减少。
开始时较低的值用于训练的热身。不建议直接切换到更高的值,而是线性增加。在周期的中间,高学习率充当正则化方法,并防止网络过度拟合。它们防止模型落在损失函数的陡峭区域。在周期结束时学习率的下降让模型进入到更平滑部分的更陡峭的局部最小值。在学习率高的部分,我们看不到损失或准确性的实质性改善,验证损失有时会非常高。尽管如此,当我们最终降低学习率时,我们看到了这样做的所有好处。但是我们如何选择最小和最大的 LR 值呢?

循环学习率图
学习率范围测试
LRR 测试是一个预训练步骤,我们以逐渐增加的学习率运行模型。它提供了关于最大学习速度的有价值的信息。当以小的学习率训练时,网络收敛,并且随着学习率的增加,网络变得太大并导致验证损失和准确性的降低。在这种背离之前,学习率是可以用循环学习率进行训练的最高值。然而,当选择恒定的学习速率时,较小的值是必要的,否则网络将不会开始收敛。最小学习速率界限通常比最大界限小 10 倍。然而,其他因素也是相关的,例如学习率增加的速度(增加太快将导致不稳定)和架构的深度(网络越深,学习率越大)。
一些研究人员建议使用小于迭代/历元总数的一个周期,并允许学习率的下降小于初始学习率。这种学习率策略被称为“1 周期”,它显示出在训练结束之前允许准确度达到稳定状态。
批量
小批量具有调整效果。已经表明,对于每个数据集和架构,正则化的总量必须是平衡的。减少其他形式的正规化和学习率巨大的正规化,使培训更有效率。因此,最好使用更大的批量。一些论文建议修改批量大小,而不是学习率(Smith et al .,2017)。然而,批量大小受到硬件的限制。如果您的服务器有多个 GPU,最佳批处理大小是 GPU 上的批处理大小乘以 GPU 的数量。
周期性动量
动量或 SGD 与动量是一种方法,有助于加速梯度向量在正确的方向,从而导致更快的收敛。与学习率密切相关。动量值为 0.99、0.97、0.95 和 0.9 的短距离跑步将帮助您找到动量的最佳值。
如果使用 1 周期学习率计划,最好使用周期动量(CM)。理论上,动量的恒定值可以给出与循环相同的最终结果。然而,周期性动量消除了尝试多个值和运行几个完整周期的麻烦。此外,当学习速率增加时,减少循环动量使训练稳定,从而允许更大的学习速率。

循环动量图
重量衰减
权重衰减是一种正则化过程,它使权重指数衰减为零。权重衰减是一种简单的方法来平衡总正则化和来自增加的学习速率的正则化。虽然其他正则化技术具有固定值(即,丢弃),但是当试验最大学习速率和步长值时,很容易改变权重衰减值。需要进行网格搜索来确定适当的星等,但通常不需要超过一个有效数字的精度。
结论
如果您在训练的早期寻找验证损失的线索,超参数优化可以相当快。在过拟合和欠拟合之间找到一个最佳平衡点并优化正则化对于快速有效的训练至关重要。您可能会很高兴地得知,这些技术中的大部分已经在 fast.ai 和 PyTorch 中实现了!快乐训练:)
资源
史密斯律师事务所(2018 年)。神经网络超参数的训练方法:第 1 部分——学习速率、批量大小、动量和重量衰减。 arXiv 预印本 arXiv:1803.09820 。
纽约州史密斯市和新泽西州托平市(2017 年)。超收敛:使用大学习率非常快速地训练神经网络。arXiv 电子版,第页。 arXiv 预印本 arXiv:1708.07120 。
j .霍华德和 s .古格(2020 年)。Fastai:深度学习的分层 API。信息, 11 (2),108。
使用 Catboost 增强嵌入
本文深入探讨了 Catboost,这是一种简单且鲜为人知的方法,可以将嵌入与梯度增强模型结合使用。

由 Romain Vignes 在 Unsplash 上拍摄的照片
介绍
当处理大数据时,有必要将具有特征的空间压缩成矢量。文本嵌入就是一个例子,它是几乎所有 NLP 模型创建过程中不可或缺的一部分。不幸的是,使用神经网络来处理这种类型的数据并不总是可行的,例如,原因可能是拟合率或推断率较低。
我建议一个很有趣的方法来使用梯度增强,很少有人知道。
数据
Kaggle 的竞赛之一最近结束了,一个带有文本数据的小数据集出现在那里。我决定将这些数据用于实验,因为竞赛表明数据集被很好地标记,并且我没有面临任何令人不愉快的意外。

列:
id-摘录的唯一 IDurl_legal-来源的 URLlicense-源材料许可证excerpt-文本预测阅读的难易程度target——读书容易standard_error-对每个摘录在多个评价人之间的分数分布的测量
作为数据集中的一个目标,它是一个数值型变量,提出它是为了解决回归问题。但是,我决定换成一个分类问题。主要原因是我将使用的库不支持在回归问题中处理文本和嵌入。希望以后开发者消除这个不足。但是在任何情况下,回归和分类问题都是密切相关的,对于分析来说,解决哪一个问题都没有区别。

目标
让我们用斯特奇法则来计算箱子的数量:
num_bins = int(np.floor(1 + np.log2(len(train))))train['target_q'], bin_edges = pd.qcut(train['target'],
q=num_bins, labels=False, retbins=True, precision=0)

目标 _q
但是,首先,我清理数据。
train['license'] = train['license'].fillna('nan')
train['license'] = train['license'].astype('category').cat.codes
借助一个自写的小函数,我对文字进行清理和词条化。函数可以很复杂,但这对于我的实验来说已经足够了。
def clean_text(text):
table = text.maketrans(
dict.fromkeys(string.punctuation))
words = word_tokenize(
text.lower().strip().translate(table))
words = [word for word in words if word not in stopwords.words('english')]
lemmed = [WordNetLemmatizer().lemmatize(word) for word in words]
return " ".join(lemmed)
我将清理后的文本保存为新特征。
train['clean_excerpt'] = train['excerpt'].apply(clean_text)
除了文本,我还可以选择 URL 中的单个单词,并将这些数据转换成新的文本特征。
def getWordsFromURL(url):
return re.compile(r'[\:/?=\-&.]+',re.UNICODE).split(url)train['url_legal'] = train['url_legal'].fillna("nan").apply(getWordsFromURL).apply(
lambda x: " ".join(x))
我从文本中创建了几个新特征——这些是各种各样的统计信息。还是那句话,创意的空间很大,但是这个数据对我们来说已经足够了。这些特性的主要目的是对基线模型有所帮助。
def get_sentence_lengths(text): tokened = sent_tokenize(text)
lengths = []
for idx,i in enumerate(tokened):
splited = list(i.split(" "))
lengths.append(len(splited)) return (max(lengths),
min(lengths),
round(mean(lengths), 3))def create_features(df):
df_f = pd.DataFrame(index=df.index)
df_f['text_len'] = df['excerpt'].apply(len)
df_f['text_clean_len' ]= df['clean_excerpt'].apply(len)
df_f['text_len_div'] = df_f['text_clean_len' ] / df_f['text_len']
df_f['text_word_count'] = df['clean_excerpt'].apply(
lambda x : len(x.split(' ')))
df_f[['max_len_sent','min_len_sent','avg_len_sent']] = \
df_f.apply(
lambda x: get_sentence_lengths(x['excerpt']),
axis=1, result_type='expand')
return df_ftrain = pd.concat(
[train, create_features(train)], axis=1, copy=False, sort=False)basic_f_columns = [
'text_len', 'text_clean_len', 'text_len_div', 'text_word_count',
'max_len_sent', 'min_len_sent', 'avg_len_sent']
当数据稀缺时,更容易检验假设,结果通常需要更加稳定。因此,为了对结果更有信心,我更喜欢在这种情况下使用 OOF(Out-of-Fold)预测。
基线
我选择了 Catboost 作为模型的免费库。Catboost 是一个高性能的开源库,用于决策树的梯度提升。从版本 0.19.1 开始,它支持在 GPU 上开箱即用的分类文本功能。主要优点是 CatBoost 可以在数据中包含分类和文本函数,而无需额外的预处理。
在非常规情感分析:BERT vs. Catboost 中,我详述了 Catboost 如何处理文本,并将其与 BERT 进行了比较。
这个库有一个杀手锏:它知道如何处理嵌入。不幸的是,目前文档中对此只字未提,只有少数人知道 Catboost 的这一优势。
!pip install catboost
当使用 Catboost 时,我建议使用池。它是一个方便的包装器,结合了特性、标签和元数据,比如分类和文本特性。
为了比较实验,我创建了一个仅使用数字和分类特征的基线模型。
我写了一个函数来初始化和训练模型。顺便说一下,我没有选择最佳参数。
def fit_model_classifier(train_pool, test_pool, **kwargs):
model = CatBoostClassifier(
task_type='GPU',
iterations=5000,
eval_metric='AUC',
od_type='Iter',
od_wait=500,
l2_leaf_reg=10,
bootstrap_type='Bernoulli',
subsample=0.7,
**kwargs
) return model.fit(
train_pool,
eval_set=test_pool,
verbose=100,
plot=False,
use_best_model=True)
为了实现 OOF,我编写了一个简单明了的小函数。
def get_oof_classifier(
n_folds, x_train, y, embedding_features,
cat_features, text_features, tpo, seeds,
num_bins, emb=None, tolist=True):
ntrain = x_train.shape[0]
oof_train = np.zeros((len(seeds), ntrain, num_bins))
models = {} for iseed, seed in enumerate(seeds):
kf = StratifiedKFold(
n_splits=n_folds,
shuffle=True,
random_state=seed)
for i, (tr_i, t_i) in enumerate(kf.split(x_train, y)):
if emb and len(emb) > 0:
x_tr = pd.concat(
[x_train.iloc[tr_i, :],
get_embeddings(
x_train.iloc[tr_i, :], emb, tolist)],
axis=1, copy=False, sort=False)
x_te = pd.concat(
[x_train.iloc[t_i, :],
get_embeddings(
x_train.iloc[t_i, :], emb, tolist)],
axis=1, copy=False, sort=False)
columns = [
x for x in x_tr if (x not in ['excerpt'])]
if not embedding_features:
for c in emb:
columns.remove(c)
else:
x_tr = x_train.iloc[tr_i, :]
x_te = x_train.iloc[t_i, :]
columns = [
x for x in x_tr if (x not in ['excerpt'])]
x_tr = x_tr[columns]
x_te = x_te[columns]
y_tr = y[tr_i]
y_te = y[t_i] train_pool = Pool(
data=x_tr,
label=y_tr,
cat_features=cat_features,
embedding_features=embedding_features,
text_features=text_features) valid_pool = Pool(
data=x_te,
label=y_te,
cat_features=cat_features,
embedding_features=embedding_features,
text_features=text_features) model = fit_model_classifier(
train_pool, valid_pool,
random_seed=seed,
text_processing=tpo
)
oof_train[iseed, t_i, :] = \
model.predict_proba(valid_pool)
models[(seed, i)] = model
oof_train = oof_train.mean(axis=0)
return oof_train, models
我将在下面写关于 get_embeddings 函数,但是它不用于获取模型的基线。
我用以下参数训练了基线模型:
columns = ['license', 'url_legal'] + basic_f_columns oof_train_cb, models_cb = get_oof_classifier(
n_folds=5,
x_train=train[columns],
y=train['target_q'].values,
embedding_features=None,
cat_features=['license'],
text_features=['url_legal'],
tpo=tpo,
seeds=[0, 42, 888],
num_bins=num_bins
)
训练模型的质量:
roc_auc_score(train['target_q'], oof_train_cb, multi_class="ovo")AUC: 0.684407
现在我有了模型质量的基准。从数字来看,这个模型很弱,我不会在生产中实现它。
嵌入
你可以把多维向量转化为嵌入,嵌入是一个相对低维的空间。因此,嵌入简化了大输入的机器学习,例如表示单词的稀疏向量。理想情况下,嵌入通过将语义相似的输入放在嵌入空间中彼此靠近来捕获一些输入语义。
有许多方法可以获得这样的向量,我在本文中不考虑它们,因为这不是研究的目的。然而,对我来说,以任何方式获得嵌入就足够了;最重要的是他们保存了必要的信息。在大多数情况下,我使用目前流行的方法——预训练变形金刚。
from sentence_transformers import SentenceTransformerSTRANSFORMERS = {
'sentence-transformers/paraphrase-mpnet-base-v2': ('mpnet', 768),
'sentence-transformers/bert-base-wikipedia-sections-mean-tokens': ('wikipedia', 768)
}def get_encode(df, encoder, name):
device = torch.device(
"cuda:0" if torch.cuda.is_available() else "cpu")
model = SentenceTransformer(
encoder,
cache_folder=f'./hf_{name}/'
)
model.to(device)
model.eval()
return np.array(model.encode(df['excerpt']))def get_embeddings(df, emb=None, tolist=True):
ret = pd.DataFrame(index=df.index)
for e, s in STRANSFORMERS.items():
if emb and s[0] not in emb:
continue
ret[s[0]] = list(get_encode(df, e, s[0]))
if tolist:
ret = pd.concat(
[ret, pd.DataFrame(
ret[s[0]].tolist(),
columns=[f'{s[0]}_{x}' for x in range(s[1])],
index=ret.index)],
axis=1, copy=False, sort=False)
return ret
现在我已经准备好开始测试不同版本的模型了。
模型
我有几个拟合模型的选项:
- 文本特征;
- 嵌入特征;
- 嵌入特征,如一列分离的数字特征。
我一直在这些选项的各种组合中接受训练,这让我得出结论,嵌入可能是多么有用,或者,也许,它是一个过度工程。
作为一个例子,我给出了一个使用所有三个选项的代码:
columns = ['license', 'url_legal', 'clean_excerpt', 'excerpt'] oof_train_cb, models_cb = get_oof_classifier(
n_folds=FOLDS,
x_train=train[columns],
y=train['target_q'].values,
embedding_features=['mpnet', 'wikipedia'],
cat_features=['license'],
text_features=['clean_excerpt','url_legal'],
tpo=tpo,
seeds=[0, 42, 888],
num_bins=num_bins,
emb=['mpnet', 'wikipedia'],
tolist=True
)
为了获得更多信息,我在 GPU 和 CPU 上训练了模型;并将结果汇总在一个表格中。

首先让我震惊的是文字特征和嵌入的交互极差。不幸的是,我还没有对这个事实的任何逻辑解释——在这里,需要在其他数据集上对这个问题进行更详细的研究。同时,请注意,文本的组合使用和同一文本的嵌入会降低模型的质量。
更新:我收到开发者的评论:
“谢谢你的报告!这个错误已经在提交中修复,并将在下一个版本中发布”
我的另一个发现是,当在 CPU 上训练模式时,嵌入不起作用。
现在,一件好事是,如果你有一个 GPU 并且可以获得嵌入,最好的质量将是当你同时使用嵌入作为一个功能和一系列单独的数字功能时。
摘要
在这篇文章中,我:
- 选择了一个小型免费数据集进行测试;
- 为文本数据创建了几个统计特征,用于制作基线模型;
- 测试了嵌入、文本和简单特性的各种组合;
- 我得到了一些非显而易见的见解。
这些鲜为人知的信息将对社区有所帮助,并从您的项目中受益。不幸的是,Catboost 处理嵌入和文本的功能仍然是原始的。但是,它正在积极改进,我希望很快会有一个稳定的版本,开发者会更新文档。复制本文结果的完整代码可从这里获得。
用维基百科推进自然语言处理
原文:https://towardsdatascience.com/boosting-natural-language-processing-with-wikipedia-b779103ba396?source=collection_archive---------15-----------------------
实践教程
使用维基百科改进自然语言处理任务,如命名实体识别和主题建模

照片由 Artem Maltsev 在 Unsplash 拍摄
介绍
自然语言处理(NLP)正在兴起。计算语言学和人工智能正在联手培育突破性发现。当研究集中于显著改进 NLP 技术时,企业将该技术视为战略资产。这种由 NLP 引导的彻底革新的主要作用是由文本数据的大量可用性发挥的。当谈到数字化时,尤其是对企业而言,重要的是要记住文档本身就是数字化的,因此,文本数据是知识的主要来源。
然而,当寻求磨练自然语言处理任务时,最大的瓶颈之一是关于数据的训练。当涉及到真实世界的应用时,比如在特定的领域,我们面临着低资源数据的问题。训练数据有两个主要问题:(I)难以获得大量数据,以及(ii)注释用于训练和测试的可用数据的耗时过程。
面对这些问题,计算机科学已经投入了大量的注意力。特别是,最新的计算进展提出了两种方法来克服低资源数据问题:
- 微调预先训练的语言模型,如 BERT 或 GPT-3;
- 利用高质量的开放式数据存储库,如维基百科或概念网。

维基百科标志(图片来自维基百科)
大多数现有的计算语言学开放库都提供了基于这两种方法之一开发 NLP 工具的架构。我们现在演示如何利用维基百科来提高两个 NLP 任务的性能:命名实体识别和主题建模。
从句子中提取维基百科信息
有几种工具可以用来处理来自维基百科的信息。关于文本数据的自动处理,我们使用 spaCy 的一个开放项目 SpikeX 。
SpikeX 是准备插入 spaCy 管道的管道集合,spaCy 管道是 NLP 的 python 库。SpikeX 由一家意大利公司( Erre Quadro Srl )开发,旨在帮助构建知识提取工具,几乎不费吹灰之力。
SpikeX 有两个主要特点:
- 给定一个维基百科页面,它提取所有相应的类别。
Categories for `Natural_Language_Processing`:
Category:Artificial_intelligence
-> Category:Emerging_technologies
-> Category:Cybernetics
-> Category:Subfields_of_computer_science
-> Category:Computational_neuroscience
-> Category:Futures_studies
-> Category:Cognitive_science
-> Category:Personhood
-> Category:Formal_sciences
Category:Speech_recognition
-> Category:Artificial_intelligence_applications
-> Category:Computational_linguistics
-> Category:Human–computer_interaction
-> Category:Digital_signal_processing
-> Category:Speech
Category:Natural_language_processing
-> Category:Artificial_intelligence_applications
-> Category:Computational_linguistics
Category:Computational_linguistics
-> Category:Computational_social_science
2.给定一个句子,它会在文本中找到匹配维基百科页面标题的组块。
Elon Musk
('Elon_Musk', 'Elon_musk', 'Elon_Musk_(book)', 'Elon_Musk_(2015_book)', 'Elon_Musk_(2015)', 'Elon_Musk_(biography)', 'Elon_Musk_(2015_biography)', 'Elon_Musk_(Ashlee_Vance)')
------
Elon
('Elon_(Judges)', 'Elon_(name)', 'Elon_(Hebrew_Judge)', 'Elon_(Ilan)', 'Elon_(disambiguation)', 'Elon_(biblical_judge)', 'Elon_(chemical)', 'Elon')
------
Musk
('Musk', 'MuSK', 'Musk_(wine)', 'Musk_(song)', 'Musk_(Tash_Sultana_song)', 'Musk_(disambiguation)')
------
runs
('Runs_(baseball_statistics)', 'Runs', 'Runs_(cricket)', 'Runs_(music)', 'Runs_(baseball)', 'Runs_(Baseball)', 'Runs_(musical)')
------
Tesla Motors
('Tesla_motors', 'Tesla_Motors')
------
Tesla
('Tesla_(band)', 'Tesla_(unit)', 'Tesla_(Czechoslovak_company)', 'Tesla_(crater)', 'Tesla_(microarchitecture)', 'Tesla_(2020_film)', 'Tesla_(car)', 'Tesla_(GPU)', 'TESLA', 'Tesla_(physicist)', 'Tesla_(group)', 'Tesla_(opera)', 'Tesla_(Bleach)', 'Tesla_(company)', 'Tesla_(disambiguation)', 'Tesla_(2016_film)', 'TESLA_(Czechoslovak_company)', 'Tesla_(unit_of_measure)', 'Tesla_(vehicles)', 'Tesla_(vehicle)', 'Tesla_(film)', 'Tesla_(album)', 'Tesla_(Flux_Pavilion_album)', 'Tesla_(surname)', 'Tesla')
------
Motors ('Motors')
我们可以看到,在第一个例子中,SpikeX 提取了维基百科页面“自然语言处理”所属的所有类别。例如,“自然 _ 语言 _ 处理”属于“人工 _ 智能”、“语音 _ 识别”、“计算 _ 语言学”的范畴。Wiki 类别的树形结构可以通过更深层次的检查来进一步探究。
在第二个例子中,对于句子“埃隆·马斯克(Elon Musk)经营特斯拉汽车公司”,SpikeX 提取句子中所有可能在维基百科上有页面的页面。
我们现在看到这两个处理特性如何被用来执行命名实体识别和主题建模。
命名实体识别
命名实体识别(NER)是一项自然语言处理任务,旨在定位文本中提到的实体并将其分类到预定义的类别中(如人名、组织、位置等)。不同的方法处理这一任务以实现高精度:基于规则的系统,训练深度神经网络的方法或精细运行预训练语言模型的方法。例如,Spacy 嵌入了一个预先训练的命名实体识别系统,该系统能够从文本中识别常见类别。
我们现在着手建立一个 NER 系统,能够识别属于某个维基百科类别的文本片段。让我们考虑下面的例句:
“命名实体识别和主题建模是自然语言处理的两项任务”
这句话潜在地包含了三个实体:命名实体识别、主题建模、自然语言处理。这三个实体都有属于特定类别的各自的维基百科页面。

维基百科类别结构示例(图片由作者提供)
在这张图片中,我们可以看到不同的类别是如何分布在三个实体中的。在这种情况下,类别可以被看作是我们想要从文本中提取的实体的标签。我们现在可以利用 SpikeX 的两个特性来构建一个定制的 NER 系统,该系统接受两个输入变量:句子的(I)文本和我们想要检测的(ii)类别。
Named Entity Recognition - COMPUTATIONAL LINGUISTIC
Topic Modeling - COMPUTATIONAL LINGUISTIC
Natural Language Processing - COMPUTATIONAL LINGUISTIC
将维基百科的类别定义为 NER 任务的标签,使得定义 NER 系统避免数据训练问题成为可能。通过使用 displacy 来表示我们基于维基百科类别的 NER 系统提取的实体,展示了另一个例子。

NER 摘录示例(图片由作者提供)
在这个例子中,类别“编程语言”和“计算语言学”作为输入给出,然后在文本中搜索。
主题建模
当谈到主题建模时,我们通常指的是能够发现文本主体的“隐藏语义结构”的 NLP 工具。最近,人们讨论到“为了自动文本分析的目的,主题的定义在某种程度上取决于所采用的方法”[1]。潜在狄利克雷分配(LDA) 是流行的主题建模方法,使用概率模型从组文档中提取主题。另一个著名的方法是 TextRank ,这是一种使用网络分析来检测单个文档中的主题的方法。最近,NLP 中的高级研究还引入了能够在句子级别提取主题的方法。一个例子是 语义超图 ,“一种结合了机器学习和符号方法的优势,从句子的意思推断主题的新技术”[1]。
我们现在看到如何使用维基百科在句子和文档级别执行主题建模。
让我们考虑来自专利 US20130097769A1 的以下文本。
封装的防护服可以在污染区域穿着,以保护该防护服的穿着者。例如,当在核动力发电厂内工作或在存在放射性物质的情况下工作时,工人可能穿着密封防护服。封装的防护服可以是一次性使用类型的系统,其中在一次使用后该防护服被丢弃。在正常操作条件下,封装的防护服可以通过连接到防护服的外部气流软管接收呼吸空气。例如,空气可以由用户携带的动力空气净化呼吸器(PAPR)提供。
Sentence:
Encapsulated protective suits may be worn in contaminated areas to protect the wearer of the suit. Topics in the sentence:
Safety -> 1
Euthenics -> 1 ----Sentence:
For example, workers may wear an encapsulated protective suit while working inside of a nuclear powered electrical generating plant or in the presence of radioactive materials.
Topics in the sentence:
Safety -> 1
Euthenics -> 1
Electricity -> 1
Electromagnetism -> 1
Locale_(geographic) -> 1
Electric_power_generation -> 1
Power_stations -> 1
Infrastructure -> 1
Energy_conversion -> 1
Chemistry -> 1
Radioactivity -> 1
---- Sentence:
An encapsulated protective suit may be a one-time use type of system, wherein after a single use the suit is disposed of. Topics in the sentence:
Safety -> 1
Euthenics -> 1
Transportation_planning -> 1
Feminist_economics -> 1
Schools_of_economic_thought -> 1
Land_management -> 1
Architecture -> 1
Planning -> 1
Transport -> 1
Feminism -> 1
Urban_planning -> 1
Feminist_theory -> 1
Urbanization -> 1
Spatial_planning -> 1
Social_sciences -> 1
----Sentence:
An encapsulated protective suit may receive breathing air during normal operating conditions via an external air flow hose connected to the suit. Topics in the sentence:
Safety -> 1
Euthenics -> 1
Chemical_industry -> 1
Gases -> 1
Industrial_gases -> 1
Breathing_gases -> 1
Diving_equipment -> 1
Respiration -> 1
Electromechanical_engineering -> 1
Heat_transfer -> 1
Home_appliances -> 1
Engineering_disciplines -> 1
Automation -> 1
Building_engineering -> 1
Temperature -> 1
Heating,_ventilation,_and_air_conditioning -> 1
---- Sentence:
The air may be supplied, for example, by a power air purifying respirator (PAPR) that may be carried by the user.Topics in the sentence:
Personal_protective_equipment -> 1
Air_filters -> 1
Respirators -> 1
Protective_gear -> 1
----
专利文本的每个句子都用 SpikeX 处理,并从句子中检测到的相应维基百科页面中提取类别。我们认为主题是维基百科的类别。这样我们就有了第一个天真的话题检测。与语义超图、文本排名或 LDA 不同,这种方法在不直接引用术语的情况下找到句子主题的标签。所提取的主题标签指的是 SpikeX 匹配的维基百科页面的类别。如果我们使用这种方法来聚合每个句子的主题,我们就可以更好地表示整个文档。

段落级别的主题检测(作者图片)
对句子中类别的频率进行分类可以更广泛地查看文本的主题分布。“安全性”和“优效性”比其他类别出现得更频繁。
我们现在使用整个专利文本(可以在 Google Patent 中找到)来找到分类分布。

文档级别的主题检测(按作者分类的图片)
正如我们所看到的,我们可以自动检测整个文档的主题(或类别)(在本例中是专利)。查看前 5 个类别,我们可以推断出专利是关于什么的。这是在没有任何培训前任务的情况下完成的。
结论
十多年来,维基百科一直被用作知识的来源,并在各种应用中反复使用:文本注释、分类、索引、聚类、搜索和自动分类生成。事实上,维基百科的结构有许多有用的特性,使它成为这些应用程序的良好候选。
这篇文章展示了如何通过使用这个强大的资源来改进简单的 NLP 任务。然而,这并不是说这种方法优于其他现有技术的方法。评估自然语言处理任务准确性的典型方法精确度和召回率在这篇文章中没有给出。
此外,这种方法有优点也有缺点。主要优点是避免了培训,从而减少了耗时的注释任务。可以将维基百科视为一个巨大的训练集,其贡献者来自世界各地。对于有监督的任务(如 NER)和无监督的任务(如主题建模)都是如此。这种方法的缺点是双重的。首先,维基百科是一项公共服务,是一个由专家和非专家贡献的知识库。第二,从主题建模结果可以看出,自然语言的歧义性会导致有偏的表现。词义消歧和非专家驱动的数据管理显然会影响整个系统的可靠性。
然而,还有很大的改进余地。将维基百科视为 NLP 任务的大型开放知识库与即将到来的新范式转变相一致:所谓的人工通用智能 ( AGI ),即系统理解或学习人类可以完成的任何智力任务的假设能力。
[1]梅内塞斯,特尔莫,和卡米尔罗斯。“语义超图。” arXiv 预印本 arXiv:1908.10784 (2019)。
我要感谢Erre Quadro Srl,特别要感谢 Paolo Arduin,他开发了 SpikeX 项目,使其成为开放访问项目。
这个帖子是在研究实验室 B4DS(数据科学的商业工程) 的帮助下概念化和设计的。我要感谢团队,我的博士同事和导师,他们帮助我写了这篇文章。
见我最新发表在 PlOs one 上的《 快速检测压力下的快速创新新冠肺炎 》。
通过将树与 GLM 结合来提高绩效:基准分析
原文:https://towardsdatascience.com/boosting-performance-by-combining-trees-with-glm-a-benchmarking-analysis-1840cac91cb1?source=collection_archive---------16-----------------------

西蒙·伯杰在 Unsplash 上的照片
通过将树和 GLM 结合起来,可以获得多大的改进,它与加法模型相比如何?
统计建模的一个常见缺陷是确保建模方法适合数据结构。像逻辑回归这样的线性模型假设预测事件的可能性和独立变量之间存在线性关系。在最近研究这个话题时,我看到了这篇关于 StackExchange 的文章,讨论了使用浅层决策树作为逻辑回归的特征工程步骤。简而言之,这种策略试图通过使用树作为特征工程步骤来处理非线性数据,以将其转换为虚拟变量,然后可以在逻辑回归规范中使用。
在研究了这个策略之后,我的印象是执行这个介绍性的步骤可能会引入降低模型灵活性的缺点,同时提供模型结果的边际增加。转换数据以消除非线性,或者在模型的规格中说明非线性,可能更有用。然而,我很惊讶地看到,没有多少文章或帖子将其与其他方法进行比较!
为了了解决策树结合逻辑回归(树+GLM)的表现,我在三个数据集上测试了该方法,并根据标准逻辑回归和广义加法模型(GAM)对结果进行了基准测试,以了解这两种方法之间是否存在一致的性能差异。
树+ GLM 方法论
逻辑回归和决策树通常是最先介绍的两种分类模型。每个都有自己的陷阱。回归模型假设因变量可以用一组应用于自变量的线性函数来解释,并具有以下形式的方程:

决策树不对变量的分布做出假设,它们只是根据基尼系数等标准在决策树中创建一个新的分支。但是,决策树容易过度拟合,并且对于训练数据的变化可能不稳定。
下图说明了一元模型中因变量范围内的线性回归和决策树模型的结果:

作者图片
从上面的图表中,我们可以看到,与线性回归模型生成的平滑函数相比,决策树的预测是不连续的。虽然这对于简单的线性数据是有问题的,但是决策树策略以非线性方式改变的能力为其在非线性数据上的使用提供了理由。
为了试图弥补这两种方法的缺点,一些来源建议使用决策树作为中间步骤,这有助于消除模型中潜在的非线性。最简单的过程如下:
- 为训练数据 X 拟合一个浅层决策树 T(X)。该树将有 N 个终端节点。
- 表示为 C_n 的 n 个分类变量作为特征包含在逻辑回归规范中。
- 使用修改的数据集拟合逻辑回归。
有两种简单的方法来处理数据中的非线性。第一种选择是对原始数据使用一些其他转换步骤,使其与因变量成线性关系。不过,这种策略并不总是一种选择,其适当性因领域而异。消除它的第二种方法是将模型规范改为可以处理非线性数据的方法。
广义可加模型
有几种方法可以用来处理非线性数据,但我选择的是广义加法模型。广义加性模型是由 Trevor Hastie 和 Robert Tibshirani 在“广义加性模型”中提出的一个框架。作者接着写了统计学习的元素,这是我第一次遇到它。
它采用了逻辑回归所基于的广义线性模型的概念,放松了线性基函数的假设。在逻辑回归规范的情况下,逻辑回归的 GAM 等价于:

在这种情况下,上面的符号替代

为

在原始的逻辑回归方程中。这是因为我们已经将对每个因变量进行操作这一术语改为任意平滑函数。或者,我们可以将逻辑回归模型视为加法模型,其中:

对于某些回归系数

很明显,这为我们如何处理我们正在建模的变量提供了额外的灵活性,因此我们将在我们的数值实验中使用该规范作为 tree+logistic 回归规范的挑战者。
数据
本文中使用了三组数据进行比较,它们是:
- 合成数据集—包含 10,000 个观察值的人工数据集,包括线性和非线性变量。
- 银行数据—由银行活动生成的数据集。这里使用的数据实际上是由 Andrzej Szymanski 博士整理和格式化的,他写了一篇关于使用决策树进行逻辑回归的文章。我想包括这个,因为它可以提供一个有价值的比较,结果已经产生了。原始数据来自 Andrzej 的 GitHub。
- 成人数据—用于尝试预测收入是否超过 50,000 美元/年的人口普查数据。它可以在 UCI 机器学习库这里获得。
在下面的代码块中,我们收集了将在我们的三个测试中使用的数据,并对其进行了检查。我们首先生成合成数据,然后下载并格式化银行和成人数据集。在此之后,我们执行一些数据清理步骤,以确保我们使用的变量不被表示为字符。最后,我们将数据分为训练和测试数据:
rm(list = ls())
library(pacman)
p_load(data.table,caret,ggplot2,plotly,mgcv,rpart,magrittr,precrec,MLmetrics,partykit,gam,rmarkdown,knitr,broom,rpart.plot,reactable)
set.seed(13)
with.nonlinear <- data.table(twoClassSim(10000,
linearVars = 6,ordinal = F ) )
data.list <- list("Synthetic" = with.nonlinear,
"Banking" = fread("[https://raw.githubusercontent.com/AndrzejSzymanski/TDS-LR-DT/master/banking_cleansed.csv](https://raw.githubusercontent.com/AndrzejSzymanski/TDS-LR-DT/master/banking_cleansed.csv)") ,
"Adult" = fread("[https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data](https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data)") )
names(data.list[[3]]) <- c("age","workclass","fnlwgt","education","education-num","marital-status","occupation", "relationship", "race","sex","capital-gain","capital-loss","hours-per-week","native-country","Income-class")
# Change variables to factors for banking data-set
banking.names.for.factors <- names(data.list$Banking)[apply(data.list$Banking,MARGIN = 2, function(x){length(unique(x))})==2]
data.list$Banking[,
names(data.list$Banking)[apply(data.list$Banking,MARGIN = 2, function(x){
length(unique(x))})==2] := lapply(X = .SD,FUN = factor),
.SDcols = banking.names.for.factors]
# Change variables to factors for Adult data-set:
adult.names.for.factors <- names(data.list$Adult)[sapply(X = 1:ncol(data.list$Adult),function(x){is.character( data.list$Adult[[x]] )})]
data.list$Adult[,names(data.list$Adult)[sapply(X = 1:ncol(data.list$Adult),
function(x){is.character( data.list$Adult[[x]] )})]:= lapply(X = .SD,FUN = factor),
.SDcols = adult.names.for.factors]
data.list$Adult[,names(data.list$Adult)[sapply(X = 1:ncol(data.list$Adult),
function(x){is.integer( data.list$Adult[[x]] )})]:= lapply(X = .SD,FUN = as.numeric ),
.SDcols = names(data.list$Adult)[sapply(X = 1:ncol(data.list$Adult),
function(x){is.integer( data.list$Adult[[x]] )})]]
training.data <- list()
test.data <- list()
for( i in 1:length(data.list)){
train_inds <- sample(x = 1:nrow(data.list[[i]]) ,size = .8*nrow(data.list[[i]]))
training.data[[i]] <- data.list[[i]][train_inds]
test.data[[i]] <- data.list[[i]][-train_inds] }
names(training.data)<- names(data.list)
names(test.data)<- names(data.list)
在进行我们的基准分析之前,了解哪些变量与因变量有非线性关系是有用的。一个简单而直观的方法是绘制因变量和自变量之间的关系图,看看从视觉上看非线性关系是否明显。在这里的实现中,我使用一个 GAM 和一个变量来描述两个变量之间关系的大致形状。您可以在下面看到使用图表评估非线性的实现:
nonlinear.viz <- function(dt,dep.var,indep.var,bins = 100){
dt$y <- as.numeric(as.character(dt$y))
return.plot <- ggplot(dt,
aes_string( x = indep.var,y = dep.var) ) + stat_smooth(method = "gam",
method.args = list(family = "binomial"),) + theme_bw() + theme(axis.title = element_text(size = 16),axis.text = element_text(size = 11),plot.title = element_text(size = 20) ) +ylab(indep.var)+
xlab(dep.var)+
ggtitle(paste("Relationship between ",dep.var," and ", indep.var,sep = ""))
return(return.plot)}training.data$Synthetic[,Class := ifelse(Class == "Class1", 1,0)]
test.data$Synthetic[,Class := ifelse(Class == "Class1", 1,0)]
training.data$Adult[,"Class" := ifelse(`Income-class` == ">50K", 1,0)]
test.data$Adult[,"Class" := ifelse(`Income-class` == ">50K", 1,0)]
synthetic.plot <- lapply(X = names(training.data$Synthetic)[names(training.data$Synthetic)!="Class"],
function(x){nonlinear.viz(dt = training.data$Synthetic,dep.var = "Class",x)})
banking.plot <- lapply(X = c("age","previous","euribor3m","cons_conf_idx","cons_price_idx","nr_employed", "emp_var_rate" , "pdays"),
function(x){nonlinear.viz(dt = training.data$Banking,dep.var = "y",x)})
names(training.data$Adult) <- gsub(names(training.data$Adult),pattern = "-",replacement = "_")
names(test.data$Adult) <- names(training.data$Adult)
adult.plot <- lapply(X = c("age","education_num","capital_gain","capital_loss","hours_per_week"),
function(x){nonlinear.viz(dt = training.data$Adult,
dep.var = "Class",x )})
上面的代码将为所有变量关系生成图表。为了简洁起见,我在下面的章节中只关注非线性数据:
合成数据集
正在使用的合成数据集是从 caret 库中的 twoClassSim 函数生成的。这个函数很简单:数据集是由一个二元结果和一组线性相关或非线性相关的变量生成的。这个数据集对我们的测试很有用,因为它允许我们比较算法,而不需要关心关于问题领域的信息。下表总结了变量之间的关系:

作者图片
我使用以下公式绘制了合成数据的非线性变量与数据集中类的可能性的关系:

作者图片
我们可以看到变量是我们所期望的:在所有情况下,在实例是正类的可能性和负类的可能性之间通常存在负的非线性关系。
银行数据集
银行数据集包含 27 个独立变量。其中,7 个变量是连续变量,其余的是二元变量。该特性与因变量的关系如下表所示:

作者图片
与合成数据一样,我也制作了一组图表,显示连续特征变量和因变量(在本例中为 y)之间的关系:

作者图片
我们可以看到,在上面的每个示例图表中,因变量和自变量之间存在明显的非线性关系,使用线性基函数很难补偿这种关系。
成人数据集
与银行数据集一样,成人数据集有许多变量,这些变量是二元变量以及一组连续变量(在本例中是五个)。下表对它们进行了总结:

作者图片
我还制作了下图,展示了每个变量和因变量之间的关系:

作者图片
连续自变量和因变量之间的关系类似于银行数据集。唯一的例外是 education_num 变量,它表示在校的年数。我们可以看到,它有一个明显的积极的关系,可能是近似的线性函数,尽管凹度。
数据平衡
在拟合和试验模型之前,检查数据集中类之间的平衡是有帮助的。数据中的类别不平衡会引入偏差,这可能需要使用重采样技术来解决。
我们将使用下面显示的代码来调查这种不平衡:
sum.func <- function(x,col,model.name){
dims <- data.table( "Measure" = c("Observations","Factors") , "Count" = dim(x))
factors <- data.table( "Minority Class Percent", min(x[,.N,by = col]$N)/sum(x[,.N,by = col]$N) )
names(factors) <- c("Measure","Count")
for.return <- data.table(rbind(dims,factors) )
names(for.return)[2] <- model.name
# factors$Measure <- paste("Class = ",factors$Measure,sep = "")
return( for.return ) }
dep.vars <- c("Class", "y", "Income_class")summaries <- lapply(X = 1:length(training.data),
FUN = function(x){sum.func(training.data[[x]], dep.vars[x] ,
model.name = names(training.data)[x]) })
summaries[[1]]$Banking <- summaries[[2]]$Banking
summaries[[1]]$Adult <- summaries[[3]]$Adult
kable(summaries[[1]],digits = 3)
我对表格的结果进行了格式化,以显示与下面数据集的其余部分相比,因变量的少数类的大小。

作者图片
从上表中我们可以看出,银行和成人数据集在预测类别上存在明显的不平衡。为了纠正这一点,我们将使用合成少数过采样技术并查看结果。
快速注意:SMOTE 步骤可能需要一些时间。
banking.smote <- RSBID::SMOTE_NC(data = training.data$Banking , outcome = "y" )
adult.smote <- RSBID::SMOTE_NC(data = training.data$Adult, outcome = "Income_class" )p_load(data.table,rmarkdown,knitr)
resampled_data <- list(training.data$Synthetic,banking.smote,adult.smote)
dep.vars <- c("Class", "y", "Income_class")
names(resampled_data) <- names(training.data)
summaries <- lapply(X = 1:length(training.data),
FUN = function(x){sum.func(resampled_data[[x]],
dep.vars[x] ,
model.name = names(training.data)[x]) })
summaries[[1]]$Banking <- summaries[[2]]$Banking
summaries[[1]]$Adult <- summaries[[3]]$Adult
kable(summaries[[1]],digits = 3)

构建决策树
我们首先构建简单的决策树,作为原始分类变量的因子而不是。这些树必须很小,以避免过度生长。我已经使用最大深度为 2、3 和 4 的树测试了模型,并基于其在 ROC 和 PR AUC 中提高的准确性,选择在每个模型中使用最大深度为 4 的树。在下面的代码块中,CART 决策树与叶节点预测相匹配,然后用于在数据中创建新的因子变量。之后,新数据用于拟合逻辑回归模型。
我们首先拟合初始决策树(另一个注意:我用深度和其他细节的几次迭代测试了这个。以下选项似乎表现最佳):
synthetic.tree.2 <- rpart(data = training.data$Synthetic,
formula = Class~Linear1+Linear2+Linear3+Linear4+Linear5+Linear6+Nonlinear1 +Nonlinear2 +Nonlinear3,
control = rpart.control( maxdepth = 4 ))
banking.tree.3 <- rpart(data = banking.smote,
formula = y~.-V1, control = rpart.control( maxdepth = 4) )
adult.tree.3 <- rpart(data = adult.smote,
formula = Class~age+workclass+fnlwgt+education+education_num +marital_status+occupation+relationship+race+sex+capital_gain + capital_loss + hours_per_week+ native_country,
control = rpart.control( maxdepth = 4))synth.models <- list(synthetic.tree.2)
banking.models <- list(banking.tree.3)
adult.models <- list(adult.tree.3)tree.to.feature <- function(tree.model,dt){
require(partykit)
tree_labels <- factor( predict(as.party(tree.model), dt ,type = "node") )
return(tree_labels)}
接下来,我们将这些结果用于拟合逻辑回归模型:
synth.train.preds <- lapply(X = synth.models,FUN = function(x){ tree.to.feature(tree.model = x,dt = training.data$Synthetic) }) %>% data.frame
banking.train.preds <-lapply(X = banking.models,FUN = function(x){ tree.to.feature(tree.model = x,dt = training.data$Banking) }) %>% data.frame
adult.train.preds <-lapply(X = adult.models,FUN = function(x){ tree.to.feature(tree.model = x,dt = training.data$Adult) }) %>% data.frame
names(synth.train.preds) <- c("three.nodes")
names(banking.train.preds) <- c("four.nodes")
names(adult.train.preds) <- c("four.nodes")
training.data$Synthetic <- cbind( training.data$Synthetic,synth.train.preds )
training.data$Banking <- cbind(training.data$Banking ,banking.train.preds )
training.data$Adult <- cbind(training.data$Adult ,adult.train.preds )
synth.model.three.deep<- glm(formula = Class~Linear1+Linear2+Linear3+Linear4+Linear5+Linear6+Nonlinear1 +Nonlinear2 +Nonlinear3 + three.nodes,family = "binomial",data = training.data$Synthetic)
banking.mode.four.deep <- glm(formula = y~.-V1 ,family = "binomial",data = training.data$Banking)
adult.mode.four.deep <- glm(formula = Class~age+workclass+fnlwgt+education+education_num +marital_status+occupation+relationship+race+sex+capital_gain + capital_loss + hours_per_week+ native_country + four.nodes,
family = "binomial",
data = training.data$Adult)
最后,我们拟合了 GAM 和 GLM 模型,我们将使用这两个模型对 GAM 树模型结果进行基准测试:
# Create GAM models and the GLM models:
synth.gam <- gam(data = training.data$Synthetic,formula = Class~s(Linear1)+s(Linear2)+s(Linear3)+s(Linear4)+s(Linear5)+s(Linear6)+s(Nonlinear1) +s(Nonlinear2) +s(Nonlinear3),family = binomial)banking.gam <- gam(formula = y~s(age)+s(previous)+s(euribor3m)+s(cons_conf_idx)+s(cons_price_idx)+s(nr_employed)+s(emp_var_rate)+s(pdays)+`job_blue-collar`+
job_management+`job_other 1`+`job_other 2`+job_services+job_technician+marital_married+marital_single+ education_high.school+education_professional.course+education_university.degree+education_unknown+default_unknown+housing_unknown+
housing_yes+loan_unknown+loan_yes+poutcome_nonexistent+poutcome_success,family = "binomial",data = training.data$Banking)adult.gam <- gam(formula = Class~s(age)+(workclass)+s(fnlwgt)+(education)+s(education_num) +(marital_status)+(occupation)+(relationship)+(race)+(sex)+s(capital_gain) + s(capital_loss) + s(hours_per_week)+ (native_country),
family = "binomial",
data = training.data$Adult)
# Create GLM Modelssynth.model.glm<- glm(formula = Class~Linear1+Linear2+Linear3+Linear4+Linear5+Linear6+Nonlinear1 +Nonlinear2 +Nonlinear3 ,family = "binomial",data = training.data$Synthetic)banking.mode.glm <- glm(formula = y~.-V1-four.nodes ,family = "binomial",data = training.data$Banking)adult.mode.glm <- glm(formula = Class~age+workclass+fnlwgt+education+education_num +marital_status+occupation+relationship+race+sex+capital_gain + capital_loss + hours_per_week+ native_country ,
family = "binomial",
data = training.data$Adult)Finally, we fit the GAM and GLM models which we will be using to benchmark the GLM+Tree model results:*# Create GAM models and the GLM models:*
synth.gam **<-** gam(data **=** training.data**$**Synthetic,formula **=** Class**~**s(Linear1)**+**s(Linear2)**+**s(Linear3)**+**s(Linear4)**+**s(Linear5)**+**s(Linear6)**+**s(Nonlinear1) **+**s(Nonlinear2) **+**s(Nonlinear3),family **=** binomial)
banking.gam **<-** gam(formula **=** y**~**s(age)**+**s(previous)**+**s(euribor3m)**+**s(cons_conf_idx)**+**s(cons_price_idx)**+**s(nr_employed)**+**s(emp_var_rate)**+**s(pdays)**+**`job_blue-collar`**+**
job_management**+**`job_other 1`**+**`job_other 2`**+**job_services**+**job_technician**+**marital_married**+**marital_single**+** education_high.school**+**education_professional.course**+**education_university.degree**+**education_unknown**+**default_unknown**+**housing_unknown**+**
housing_yes**+**loan_unknown**+**loan_yes**+**poutcome_nonexistent**+**poutcome_success,family **=** "binomial",data **=** training.data**$**Banking)
adult.gam **<-** gam(formula **=** Class**~**s(age)**+**(workclass)**+**s(fnlwgt)**+**(education)**+**s(education_num) **+**(marital_status)**+**(occupation)**+**(relationship)**+**(race)**+**(sex)**+**s(capital_gain) **+** s(capital_loss) **+** s(hours_per_week)**+** (native_country),
family **=** "binomial",
data **=** training.data**$**Adult)
*# Create GLM Models*
synth.model.glm**<-** glm(formula **=** Class**~**Linear1**+**Linear2**+**Linear3**+**Linear4**+**Linear5**+**Linear6**+**Nonlinear1 **+**Nonlinear2 **+**Nonlinear3 ,family **=** "binomial",data **=** training.data**$**Synthetic)
banking.mode.glm **<-** glm(formula **=** y**~**.**-**V1**-**four.nodes ,family **=** "binomial",data **=** training.data**$**Banking)
adult.mode.glm **<-** glm(formula **=** Class**~**age**+**workclass**+**fnlwgt**+**education**+**education_num **+**marital_status**+**occupation**+**relationship**+**race**+**sex**+**capital_gain **+** capital_loss **+** hours_per_week**+** native_country ,
family **=** "binomial",
data **=** training.data**$**Adult)
模型检验
既然我们已经拟合了模型,我们可以比较它们的结果。为此,我将依赖 ROC AUC 和 PR AUC。评估结果的代码如下所示:
synth.test.preds <- lapply(X = synth.models,FUN = function(x){
tree.to.feature(tree.model = x,dt = test.data$Synthetic) }) %>% data.frame
banking.test.preds <-lapply(X = banking.models,FUN = function(x){
tree.to.feature(tree.model = x,dt = test.data$Banking) }) %>% data.frame
adult.test.preds <- lapply(X = adult.models,FUN = function(x){
tree.to.feature(tree.model = x,dt = test.data$Adult) }) %>% data.frame
names(synth.test.preds) <- c( "three.nodes")
names(banking.test.preds) <- c( "four.nodes")
names(adult.test.preds) <- c( "four.nodes")
test.data$Synthetic <- cbind( test.data$Synthetic,synth.test.preds )
test.data$Banking <- cbind(test.data$Banking ,banking.test.preds )
test.data$Adult <- cbind(test.data$Adult ,adult.test.preds )
training.for.mmdata <- data.frame(predict(banking.mode.glm,newdata = training.data$Banking, type = "response" ),
predict(banking.mode.four.deep, newdata = training.data$Banking,type = "response" ),
predict(banking.gam,newdata = training.data$Banking, type = "response" ) )
training.mdat <- mmdata(scores = training.for.mmdata,labels = training.data$Banking$y,
modnames = c("Logistic Regression", "Tree w/ GLM", "GAM"))
testing.for.mmdata <- data.frame(predict(synth.model.glm,newdata = test.data$Synthetic, type = "response" ),
predict(synth.model.three.deep, newdata = test.data$Synthetic,type = "response" ),
predict(synth.gam,newdata = test.data$Synthetic, type = "response" ) )
testing_mdat <- mmdata(scores = testing.for.mmdata,labels = test.data$Synthetic$Class,
modnames = c("Logistic Regression", "Tree w/ GLM", "GAM"))
training_ROC <- autoplot(evalmod(training.mdat),curvetype = c("ROC"))+theme(legend.position = "bottom") +ggtitle("ROC Curve - Training Data")
training_PR <- autoplot(evalmod(training.mdat),curvetype = c("PR"))+theme(legend.position = "bottom") +ggtitle("PR Curve - Training Data")
testing_ROC <- autoplot(evalmod(testing_mdat),curvetype = c("ROC"))+theme(legend.position = "bottom") +ggtitle("ROC Curve - Testing Data")
testing_PR <- autoplot(evalmod(testing_mdat),curvetype = c("PR"))+theme(legend.position = "bottom") +ggtitle("PR Curve - Testing Data")

作者图片

作者图片

作者图片
每个模型在训练和测试数据集上都表现良好,当切换到样本外数据时,模型精度几乎没有下降。在所有情况下,使用决策树作为特性工程步骤都会对性能指标有一点改进。我们还看到,在所有情况下,GAM 模型优于任何一个模型。
在一些情况下,GAM 比 GAM 树模型的表现好得多,比 GAM 树模型比逻辑回归模型的表现好得多。由此,我们可以看到,在模型规范中包含非线性数据的结构而不是转换它,可以在所有情况下提高性能。这一点很重要,因为使用 GAM 还消除了对模型的潜在决策树的调查和比较。
结论:
我比较了处理非线性数据的两种不同方法的结果。第一种是使用决策树模型作为特征工程步骤来创建一组一次性编码器,然后在逻辑回归模型中使用。第二种方法是广义的附加模型,它将数据的潜在非线性纳入模型规范。这消除了因变量和自变量之间线性关系的假设。这两种方法在三个数据集上进行了比较,以查看它们的性能是否有一致的差异。测试表明,GAM 在各个方面都优于 GAM 树模型。两个模型都优于简单的逻辑回归模型。
GAMs 优于树+GLM 模型的事实是重要的,因为它还消除了特征工程步骤和关于用于生成处理变量的树的深度的模糊性。
参考资料:
[1] T. Hastie,R. Tibshirani,J. Friedman,统计学习的要素 (2009)
[2] T. Hastie,R. Tibshirani,广义加法模型,统计科学(1986)
[3]Syzmanski,Andrzej,结合逻辑回归和决策树,走向数据科学(2020)
使用 Terraform 在 5 分钟内引导一个现代数据堆栈
原文:https://towardsdatascience.com/bootstrap-a-modern-data-stack-in-5-minutes-with-terraform-32342ee10e79?source=collection_archive---------9-----------------------
设置 Airbyte、BigQuery、dbt、Metabase 以及使用 Terraform 运行现代数据堆栈所需的一切。

现代数据堆栈架构(图片由作者提供)
什么是现代数据堆栈
现代数据栈(MDS)是一系列技术的组合,使现代数据仓库的性能比传统数据仓库高 10-10000 倍。最终,MDS 节省了时间、金钱和精力。一个 MDS 的四大支柱是一个数据连接器,一个云数据仓库,一个数据转换器,一个 BI &数据探索工具。
简单的 集成通过托管的&开源工具预构建数百个现成的连接器成为可能。过去需要数据工程师团队定期构建和维护的东西,现在可以用简单用例的工具来代替。像 Stitch 和 Fivetran 这样的托管解决方案,以及像 Airbyte 和 Meltano 这样的开源解决方案,正在让这一切成为现实。
由于其高性能和成本效益,使用基于云的柱状数据仓库已经成为最近的趋势。您可以从每月 100 美元(或更少)开始支付,而不是每年支付 10 万美元购买一个本地 MPP(大规模并行处理)数据库。云原生数据仓库据说比传统 OLTP 快 10 到 10000 倍。这一类的热门选项有 BigQuery 、雪花和红移。
在过去,由于技术的限制,在数据仓库中处理数据是一个瓶颈。结果,公司不得不倾向于 ETL 而不是 ELT 来减少数据仓库的工作量。然而,随着云原生数据仓库的发展,许多数据仓库内转换工具变得流行起来。这一类别中最值得注意的是 dbt(数据构建工具)和 Dataform。
BI 工具用于处理一些转换,以减少遗留数据仓库的工作量。然而,随着现代数据堆栈的出现,BI 工具的重点已经转移到(在我看来)民主化数据访问、自助服务和数据发现。一些我认为正朝着正确方向发展的工具是 Looker 、元数据库和超集。
我们的建筑
由于涉及许多不同的工具和流程,开始使用现代数据堆栈可能会令人望而生畏。本文旨在帮助您尽可能无缝地开始这一旅程。有许多准备步骤,但是一旦完成,只需要五分钟就可以启动所有资源。

现代数据堆栈架构(图片由作者提供)
我们将使用 Terraform ,一个基础设施即代码的开源工具来提供谷歌云中的一切。如果您遵循下面的说明,这里是将要创建的资源。
- 启用了必要 API 的谷歌云项目
- 摄取:运行 Airbyte 的 GCE 实例
- 仓库:大查询数据集
- 编排(可选):运行气流的 GCE 实例
- BI 和数据发现:运行元数据库的 GCE 实例
- 不同服务的服务帐户及其 IAM 权限绑定
开始
创建一个 Google Cloud 帐户并启用计费
这个项目中的 Terraform 代码将与谷歌云平台进行交互。因此,我们创建 Google 帐户的第一步是启用计费。请注意计费页面中具有以下格式的billing ID:######-######-######。在下一步中,您将需要这个值。
安装 Google Cloud CLI
按照这里的说明为您各自的操作系统安装 Google Cloud SDK。安装了gcloud CLI 后,在终端窗口中运行以下命令,并按照说明进行操作。这将让 Terraform 使用默认凭证进行身份验证。
gcloud auth application-default login
安装地形
按照这里的说明在本地安装 Terraform CLI。之后运行以下命令检查您的安装:
terraform -v
您应该会看到类似这样的内容:
Terraform v1.0.0
on darwin_amd64
+ provider registry.terraform.io/hashicorp/google v3.71.0
在本地派生或克隆此回购
https://github.com/tuanchris/modern-data-stack
您可以将此回购分支到您的帐户或克隆到您的本地机器。要克隆存储库,请运行以下命令:
git clone https://github.com/tuanchris/modern-data-stack
cd modern-data-stack
创建一个terraform.tfvars文件
用以下内容创建一个terraform.tfvars文件:
# The Billing ID from the first step
billing_id = ######-######-######
# The folder ID of where you want your project to be under
# Leave this blank if you use a personal account
folder_id = ""
# The organization ID of where you want your project to be under
# Leave this blank if you use a personal account
org_id = ""
# The project to create
project_id = ""
警告:这些被认为是敏感值。不要将该文件和*.tfstate文件提交给公共回购。
自定义variables.tf中的值
variables.tf中的变量将用于资源的配置。

作者图片
您可以通过更改变量为不同的服务定制机器类型。如果您不想使用任何服务,请在gce.tf文件中将其注释掉。
您还可以通过将源系统添加到源数据集字典来为源系统创建不同的数据集。
创建现代化的数据堆栈
最后,要在 Google Cloud 上提供所有这些资源,运行以下命令:
terraform apply

作者图片
研究终端中的输出,确保所有资源设置都是您想要的。键入yes并点击enter。
Terraform 将利用我们的现代数据堆栈创建一个谷歌云项目。整个过程大约需要 2-3 分钟。将服务安装到虚拟机实例上还需要 2-3 分钟。整个过程只需要 5 分钟或更少。
使用现代数据堆栈
检索不同服务的服务帐户

作者图片
谷歌建议不同的服务使用不同的服务账户。项目中的 terraform 代码为已经使用的不同技术创建了不同的帐户。若要检索特定服务的服务帐户,请运行以下命令:
terraform output [service_name]_sa_key
所有这些帐户的默认权限是roles/bigquery.admin。您可以在iam.tf文件中对此进行定制。
您得到的值是 base64 编码的。要将该值变回JSON format,运行以下命令:
echo "[value from the previous command]" | base64 -d
您可以使用 JSON 服务帐户来验证对项目资源的服务访问。
警告:任何拥有这个服务账号的人都可以访问你的项目。
使用 Airbyte 摄取数据
Airbyte 是一款优秀的开源数据集成工具。要访问 Airbyte UI,首先,获取 gcloud SSH 命令。

作者图片
你会得到一个类似这样的命令:gcloud beta compute ssh --zone "asia-southeast1-a" "tf-airbyte-demo-airbyte" --project "tf-airbyte-demo"。接下来,将以下内容添加到命令中,以在本地转发 Airbyte UI:-- -L 8000:localhost:8000 -L 8001:localhost:8001 -N -f。您的最终命令将如下所示:
gcloud beta compute ssh --zone "asia-southeast1-a" "tf-airbyte-demo-airbyte" --project "tf-airbyte-demo" -- -L 8000:localhost:8000 -L 8001:localhost:8001 -N -f
**注意:**从 GCP UI 复制后,请务必删除换行符。
如果 Airbyte 实例已经完成启动,您可以通过浏览器访问localhost:8000来访问它。如果没有,请等待五分钟,让实例完成安装。

作者图片
现在,您可以集成您的数据源,使用airbyte_sa_key添加一个 BigQuery 目的地,并立即将您的数据放入 BigQuery 中。
您可以在虚拟机内部的/airbyte/访问 Airbyte 安装。
使用 dbt 模型数据
dbt (数据构建工具)是一个使用 SQL 的强大的开源数据转换工具。它使数据分析师能够完成以前留给数据工程师的工作。它还帮助创建了一个全新的职位,称为分析工程师,是数据分析师和数据工程师的混合体。你可以在我的博客这里阅读更多关于这个职位的信息。

作者图片
与 Airbyte、Airflow 和 Metabase 不同,运行 dbt 不需要服务器。你可以通过访问他们的网站注册一个免费(永久)的单座账户。
利用气流协调工作流程
Airflow 是 Airbnb 打造的久经考验的工作流程编排工具。有了一个现代化的数据堆栈,希望你不需要经常使用气流。然而,在一些需要定制的情况下,气流可以成为你的首选工具。
要访问 UI,请使用 Airbyte 获得类似于上一节的 SSH 命令。使用以下命令进行端口转发:
gcloud beta compute ssh --zone "asia-southeast1-a" "tf-airbyte-demo-airflow" --project "tf-airbyte-demo" -- -L 8080:localhost:8080 -N -f
现在你可以在localhost:8080访问气流装置。默认用户名&密码为admin和admin。

作者图片
您可以在虚拟机内部的/airflow/访问气流装置。
用元数据库可视化数据
Metabase 是一个开源的数据可视化和发现工具。它超级用户友好,易于上手。
要访问元数据库 UI,请使用 Airbyte 获得类似于上述部分的 SSH 命令。然后,使用以下命令进行端口转发:
gcloud beta compute ssh --zone "asia-southeast1-a" "tf-airbyte-demo-metabase" --project "tf-airbyte-demo" -- -L 3000:localhost:3000 -N -f

作者图片
打扫
为了避免任何不必要的开销,请确保通过运行。
terraform destroy
**警告:**这将删除项目中任何持久化的数据和资源。或者,您也可以关闭未使用的 GCE 来节省成本。
结论
我希望这篇文章能够帮助您更好地理解现代数据堆栈,并且/或者激励您开始这一旅程。
请随时向我寻求反馈/问题。
快乐学习!
R 中的自助回归
原文:https://towardsdatascience.com/bootstrap-regression-in-r-98bfe4ff5007?source=collection_archive---------5-----------------------
回归系数的估计及其在 R 中的实现

安德鲁·雷德利在 Unsplash 上的照片
介绍
Bootstrap 是一种带替换的随机抽样方法。在它的其他应用中,如假设检验,它是检查回归系数稳定性的一种简单而有效的方法。在我们的上一篇文章中,我们探讨了置换测试,这是一个相关的概念,但是没有替换。
线性回归依赖于几个假设,公式的系数可能在 CLT 下呈正态分布。它表明,平均来说,如果我们重复实验成千上万次,这条线将在置信区间内。
bootstrap 方法不依赖于这些假设*,而是简单地执行数千次估计。
*(请注意,bootstrap 方法不违反或绕过正态假设,但它不依赖于 CLT,而是建立自己的 Bootstrap 分布,这是渐近正态的)
在这篇文章中,我们将探讨 Bootstrapping 方法和估计回归系数的模拟数据使用 r。
数据集模拟
我们将模拟来自高斯分布的一个探索变量的数据集,以及通过向探索变量添加随机噪声而构建的一个响应变量。人口数据将有 1000 个观察值。
set.seed(2021)
n <- 1000
x <- rnorm(n)
y <- x + rnorm(n)population.data <- as.data.frame(cbind(x, y))
我们将从这些数据中抽取 20 个观察值作为样本。
sample.data <- population.data[sample(nrow(population.data), 20, replace = TRUE),]
简单回归模型
让我们探索一下人口和样本数据的简单回归模型:

人口模型

样本模型
我们可以看到,截距对于样本数据是有偏差的;然而,尽管我们的样本数据集中只有 20 个观察值,斜率却非常接近于总体值。样本模型的标准误差要高得多。
如果我们绘制模型,我们可以看到这些线有多接近:

自助方法
Bootstrap 方法提出了一个问题:如果我们用替换法对数据进行重新采样并估计系数,会有多极端?
这是一个 1000 次试验的简单循环,它从我们的样本数据集中用替换重新采样这 20 个观察值,运行回归模型并保存我们在那里得到的系数。最后,我们会有 1000 对系数。
我们将取这些系数的平均值,并将它们与我们先前获得的其他模型进行比较:

我们可以看到,在这个特定的例子中,截距更接近于总体模型,斜率与样本模型的精度水平大致相同。但是我们更感兴趣的是置信区间的精确度。

我们可以看到,精度几乎与样本模型相同,截距甚至更小。
图形表示
首先,自举表示法:

仅自举线
这是我们估计的 1000 条可能的回归线。现在,让我们添加图总体、样本和平均自举线:

总体、样本、自举线
我们可以看到,它们基本上以相同的方式获取数据。现在让我们添加样本数据的置信区间:

增加了置信区间
这就完成了我们的研究:我们可以得出结论,bootstrapping 方法返回了本质上相同的结果,但在统计学上是不同的。我们不依赖假设,而是使用强力方法模拟数据。当我们对数据的来源分布有疑问时,或者想要检查系数的稳定性时,特别是对于小数据集,这可能特别有用。
你可以在 GitHub 的找到完整的代码。
结论
在本文中,我们探讨了估计回归系数的 bootstrap 方法。为了简单明了地展示这种强大的技术,我们使用了一个简单的回归模型。我们的结论是,这种方法基本上等同于 OLS 模型,但是不依赖于假设。这是一种估计系数不确定性的强有力的方法,可以与传统方法一起用来检查模型的稳定性。
感谢您的阅读!
在 LinkedIn 上连接
自举重采样
原文:https://towardsdatascience.com/bootstrap-resampling-2b453bb036ec?source=collection_archive---------6-----------------------
简单,直接,方便。

替代数据尺寸|照片由Rene b hmer拍摄
不,不是 Twitter Bootstrap——这种 Bootstrap 是一种数据采样的方式,最重要的是考虑数字的变化,分布的变化,分布的变化。为此,自举非常非常有效。对于数据科学家、机器学习工程师和统计学家来说,理解重采样方法至关重要。
但是为什么要使用重采样呢?我们使用重采样是因为我们只有有限的数据——至少可以说是时间和经济的限制。那么什么是重采样呢?重采样就是你取一个样本,然后你取这个样本的一个样本。你为什么要这么做?它可以让你看到有多少变化,它可以让你对你采集的样本有不同的理解。比方说,你想让 1000 人回答一项调查,但你只有 100 人。通过巧妙地对样本进行二次抽样,我们可以得到一个新的分布,我们将对样本的不确定性有所了解;我们进一步推测这与潜在人群的不确定性有关。
我们可以从数据集的多个子样本中计算统计数据,例如平均值。我们取一堆这样的物品,把它们加起来,然后除以物品的数量。自举重采样的技巧是用替换进行采样。
在 Python 中,通常在采样函数的采样代码中会有一个采样参数的布尔自变量。该布尔标志将为替换=真或替换=假。如果您有 100 个项目,随机抽样(例如,伯努利抽样)样本-记录它,并将该值替换回样本池。然后冲洗,再重复 99 次。这个子样本总体很可能是不同的。它们将具有原始 100 个值的不同比例。在大多数情况下,这些值会非常均匀地分布,但并不完美。然后重复该过程总共 10 次,以产生 1000 个样本。请注意,偶尔会发生一些奇怪的事情,例如,如果您的数据只有一个唯一的 X 值,那么您可以随机对 100 个包含 5 个 X 值的值进行二次抽样,尽管抽样总体只有一个值,但这种可能性不大,因为存在替换抽样。
对于这些样本中的每一个,我们可以计算平均值。然后我们可以看看这些平均值的分布。或者我们可以看看这些平均值。这些平均值应该非常接近总体平均值,并且应该非常接近更大样本的平均值。你可以对其他指标做同样的事情,比如标准差。自举是一种非常强大的技术,它允许你用另一种方法获得测量的不确定性。因为当你取这些值时,当你得到平均值时,所有子样本平均值的变化会告诉我们,你的样本相对于真实潜在人群的不确定性。
自助益处
Bootstrap 和重采样是广泛适用的统计方法,放宽了经典统计学的许多假设。重采样方法隐含地借鉴了中心极限定理,正如我在之前的文章中所解释的。特别是自举(和其他重采样方法):
- 允许根据有限的数据计算统计数据。
- 允许我们从数据集的多个子样本中计算统计数据。
- 允许我们做最小的分布假设。
常用的重采样方法包括:
- 随机化或排列方法(如 Fisher 精确检验)。早在 1911 年,费希尔就开创了随机化和排列方法。费希尔在他 1935 年的书中充分发展了这一理论。即使使用现代计算机,这些方法的可扩展性仍然有限。
- 交叉验证:重新取样折叠而不替换。交叉验证最初是由 Kurtz 在 1948 年提出的,现在广泛用于测试机器学习模型。
- 刀切:留一个重采样。Maurice Quenouille 最初在 1949 年提出了这种方法。折叠刀是由约翰·w·图基在 1958 年完全发展起来的,他给这种方法起了名字:这种方法是一种简单的工具,像小刀一样有多种用途。
- Bootstrap:用相等的大小和替换重新取样。bootstrap 方法首先由 Efron 和 Hinkley 在 1978 年提出,并在 1979 年由 Efron 进一步发展。
引导概述
我们将自举平均值计算为:



引导示例
为了展示 bootstrap 的威力,我将在 Jupyter 笔记本上分析来自 Galton 的身高数据集的不同人群的身高均值;以给我们一句“回归均值”w/r 到儿童身高而闻名。下面是一个参数自助估计的例子——参数,因为我们的模型有一个参数,均值,我们试图估计。
我将用一个例子来说明:
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
import seaborn as sns%matplotlib inline
导入基本库
# i imported the dataset from here, and called file_name
galton-families = pd.read_csv(file_name, index_col=0)
galton-families.head()
检查数据是否导入良好。

现在,我将按性别划分数据帧的子集,以获得数据集中男性和女性的数量。这将创建两个数据集,一个叫男性,一个叫女性。男性实际上是儿子,女性实际上是女儿。
male = galton-families[galton-families.gender == ‘male’]
female = galton-families[galton-families.gender == ‘female’]len(male), len(female)
(481, 453)
在这个数据集中,481 名男性,453 名女性看起来相当平衡。以下代码显示了这些分布中的最小值和最大值:
print(families.childHeight.min())
families.childHeight.max()
56.0
Out[11]: 79.0
它们从 56 英寸到 79 英寸不等。接下来要做的是绘制这两个直方图:
def plot_hist(x, p=5):
# Plot the distribution and mark the mean
plt.hist(x, alpha=.5)
plt.axvline(x.mean())
# 95% confidence interval
plt.axvline(np.percentile(x, p/2.), color=’red’, linewidth=3)
plt.axvline(np.percentile(x, 100-p/2.), color=’red’, linewidth=3)
def plot_dists(a, b, nbins, a_label=’pop_A’, b_label=’pop_B’, p=5):
# Create a single sequence of bins to be shared across both
# distribution plots for visualization consistency.
combined = pd.concat([a, b])
breaks = np.linspace(
combined.min(),
combined.max(),
num=nbins+1) plt.subplot(2, 1, 1)
plot_hist(a)
plt.title(a_label)
plt.subplot(2, 1, 2)
plot_hist(b)
plt.title(b_label)
plt.tight_layout() plot_dists(male.childHeight, female.childHeight, 20, a_label=’sons’, b_label=’daughters’)
plt.show()

这里需要注意的重要一点是,儿子和女儿之间有明显的重叠。你可以看到一些女儿实际上比儿子的平均身高要高。总的来说,我们可以看到女儿比儿子小,但这有意义吗?
我上一篇关于 CLT 的文章非常清楚地展示了如何区分这两种发行版。这看起来像是两个不同的发行版。然而,我们实际上可以说,儿子的分布与女儿的分布并没有太大的不同,因为用这些红色竖线表示的 95%的置信水平与平均值有些重叠。
自举手段
自助救援。我们将从样品中重新取样。Pandas 内置了从给定数据帧生成引导样本的支持。我将使用两个数据帧的sample()方法来绘制一个引导示例,如下所示:
female.sample(frac=1, replace=True).head()

注意:使用 replace equals true 参数,您可能会多次获得同一行,或者根本不会对某些行进行采样。
上述从高尔顿数据集采样的所有子代样本具有以下平均值:
female.sample(frac=1, replace=True).father.mean()
69.0664459161148
这个女性数据框架的自举样本有 453 个女儿,平均身高为 69.1 英寸。
现在,我们将采用许多(*n_replicas*) bootstrap 样本,并绘制样本均值的分布,以及样本均值。在下面的代码中,我们引导 1000 个子样本,每个样本的原始数据帧大小为 481 和 453。
n_replicas = 1000female_bootstrap_means = pd.Series([
female.sample(frac=1, replace=True).childHeight.mean()
for i in range(n_replicas)])male_bootstrap_means = pd.Series([
male.sample(frac=1, replace=True).childHeight.mean()
for i in range(n_replicas)])plot_dists(male_bootstrap_means, female_bootstrap_means,
nbins=80, a_label=’sons’, b_label=’daughters’)
plt.show()

自举平均值的分布完全不重叠!这证明了差异是显著的。
自举手段的差异
在下面的单元格中,我将展示如何从完整的男性+女性数据集生成引导样本,然后计算每个样本的男性和女性子女身高的均值差异,生成样本均值差异的分布。
diffs = []
for i in range(n_replicas):
sample = families.sample(frac=1.0, replace=True)
male_sample_mean = sample[sample.gender == ‘male’].childHeight.mean()
female_sample_mean = sample[sample.gender == ‘female’].childHeight.mean()
diffs.append(male_sample_mean — female_sample_mean)
diffs = pd.Series(diffs)plot_hist(diffs)

平均值中差的分布远离零。像以前一样,我们可以推断两个群体的平均值显著不同——这是为了数据集的目的,也就是说儿子和女儿确实有不同的平均身高。换句话说:置信区间不跨越零,因为它不跨越零,我们确信差异是显著的。蓝线表示来自 bootstrap 样本的儿子和女儿之间的平均差异约为 5.1 英寸,其中我们有 95%的信心,真实的人口平均差异在 4.8 英寸和约 5.5 英寸之间。这就是答案——平均来说,儿子比女儿高 5.5 英寸。
然而,我们必须验证均值差异的分布是正态的,正如 CLT 所暗示的那样。如果数据不是正态分布,那么我们不能相信 95%置信区间:
import statsmodels.api as sm
fig = sm.qqplot(diffs, line=’s’)
plt.title(‘Quantiles of standard Normal vs. bookstrapped mean’)
plt.show()

Q-Q 正态图上的点几乎在一条直线上。显然,均值差异的 bootstrap 分布确实符合 CLT,这使得我们可以相信通过 bootstrap 对原始数据集进行重采样得到的统计数据。
结论
该分析的结果证明了工具重采样对于数据科学家或机器学习工程师是多么有用。Bootstrap 不是唯一的重采样方法,有几种方法,但在 IMO 看来,它是生产模型的最佳方法,因为它对父分布做了最少的假设,并且可以很好地在许多语言和包中实现。如果没有用正确的上下文正确地处理和分析数据,数据是没有用的。正如马克·吐温的名言,“有谎言,该死的谎言,和统计数据。”
请继续,我将在贝叶斯统计和中使用 bootstrap 和回归模型构建这些概念。
在 Linkedin 上找到我
物理学家兼数据科学家——适用于新机遇| SaaS |体育|初创企业|扩大规模
R 中的自举抽样
原文:https://towardsdatascience.com/bootstrap-sampling-in-r-a7bc9d3ca14a?source=collection_archive---------11-----------------------
探索公立和私立学校的学费差异
Bootstrapping 使用带替换的随机抽样来估计样本的统计数据。通过对此样本进行重采样,我们可以生成能够代表总体的新数据。这大致基于大数定律。我们可以对统计数据进行多次估计,而不是对一个小样本的统计数据进行一次估计。因此,如果我们用替换重新采样 10 次,我们将计算 10 次期望统计的估计。
引导过程如下:
- 用替换 n 次重新采样数据
- 计算期望的统计数据 n 次,以生成估计统计数据的分布
- 从自举分布中确定自举统计量的标准误差/置信区间
在本文中,我将演示如何使用 TidyTuesday 的历史学费数据集执行 bootstrap 重采样来估计私立和公立大学的学费成本之间的关系。
首先,我们从 GitHub 加载数据。
library(tidyverse)
library(tidymodels)historical_tuition <- readr::read_csv('[https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2020/2020-03-10/historical_tuition.csv'](https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2020/2020-03-10/historical_tuition.csv'))# A tibble: 6 x 4
type year tuition_type tuition_cost
<chr> <chr> <chr> <dbl>
1 All Institutions 1985-86 All Constant 10893
2 All Institutions 1985-86 4 Year Constant 12274
3 All Institutions 1985-86 2 Year Constant 7508
4 All Institutions 1985-86 All Current 4885
5 All Institutions 1985-86 4 Year Current 5504
6 All Institutions 1985-86 2 Year Current 3367
目前,数据是长格式的,每行代表一个观察值。每年都有多个观察值,代表每种机构类型的数据:公立、私立、所有机构。为了利用数据进行重采样,我们需要将数据转换为宽格式,其中一列包含私立学校的学费,另一列包含公立学校的学费。这种宽格式中的每一行代表特定年份的历史学费。下面是将长格式数据转换为更宽格式的代码。我们将对建模感兴趣的列是public和private,它们代表由列year给出的特定学年公立和私立学校的学费。
tuition_df <- historical_tuition %>%
pivot_wider(names_from = type,
values_from = tuition_cost
) %>%
na.omit() %>%
janitor::clean_names()# A tibble: 25 x 5
year tuition_type all_institutions public private
<chr> <chr> <dbl> <dbl> <dbl>
1 1985-86 All Constant 10893 7964 19812
2 1985-86 4 Year Constant 12274 8604 20578
3 1985-86 2 Year Constant 7508 6647 14521
4 1985-86 All Current 4885 3571 8885
5 1985-86 4 Year Current 5504 3859 9228
6 1985-86 2 Year Current 3367 2981 6512
7 1995-96 All Constant 13822 9825 27027
8 1995-96 4 Year Constant 16224 11016 27661
9 1995-96 2 Year Constant 7421 6623 18161
10 1995-96 All Current 8800 6256 17208
有了这种更宽格式的数据,我们可以很快直观地了解私立和公立学校学费之间的关系。
tuition_df %>%
ggplot(aes(public, private))+
geom_point()+
scale_y_continuous(labels=scales::dollar_format())+
scale_x_continuous(labels=scales::dollar_format())+
ggtitle("Private vs Public School Tuition")+
xlab("Public School Tuition")+
ylab("Private School Tuition")+
theme_linedraw()+
theme(axis.title=element_text(size=14,face="bold"),
plot.title = element_text(size = 20, face = "bold"))
私立学校和公立学校的学费之间似乎存在直接的正相关关系。一般来说,私立学校比公立学校花费更多。我们现在将从数量上来看。

作者图片
我们可以对数据进行线性拟合,以确定私立学校和公立学校学费之间的关系。我们可以通过 r 中的lm函数来实现这一点。我们可以看到斜率估计为 2.38。公立学校每花费 1 美元的学费,私立学校预计要多支付 2.38 倍。
tuition_fit <- lm(private ~ 0 + public,
data = tuition_df)# We tidy the results of the fit
tidy(tuition_fit)# A tibble: 1 x 5
term estimate std.error statistic p.value
<chr> <dbl> <dbl> <dbl> <dbl>
1 public 2.38 0.0346 68.7 1.05e-66
现在,我们将使用重采样来尝试更好地估计公立和私立学校学费之间的关系。使用自举,我们将随机绘制替换以从原始数据集创建与原始数据集大小相同的新数据集。这实质上模拟了从原始数据集生成新的数据集。我们将对数据重新采样 1000 次。
# Set set.seed a starting number to generate a sequence of random numbers so that we can get reproducible results
set.seed(123)
tution_boot <- bootstraps(tuition_df,
times = 1e3,
apparent = TRUE)
接下来,我们将对 1000 次重新采样拟合一个线性模型。这些结果将存储在一个名为model的新列中,统计数据将存储在一个名为conf_inf的列中。然后,我们将对结果进行去嵌套,以提取估计的统计数据(直线的斜率)、误差和 p 值。
tuition_models <- tution_boot %>%
mutate(model = map(splits, ~lm(private ~ 0 + public,
data = .) ),
coef_inf = map(model, tidy))tuition_coefs <- tuition_models %>%
unnest(coef_inf)splits id model term estimate std.error statistic p.value
<list> <chr> <list> <chr> <dbl> <dbl> <dbl> <dbl>
1 <split [72/25]> Bootstrap0001 <lm> public 2.37 0.0354 66.7 8.41e-66
2 <split [72/28]> Bootstrap0002 <lm> public 2.38 0.0353 67.4 4.30e-66
3 <split [72/23]> Bootstrap0003 <lm> public 2.36 0.0365 64.9 6.19e-65
4 <split [72/25]> Bootstrap0004 <lm> public 2.30 0.0328 70.1 2.67e-67
5 <split [72/25]> Bootstrap0005 <lm> public 2.35 0.0364 64.7 7.15e-65
6 <split [72/26]> Bootstrap0006 <lm> public 2.36 0.0344 68.5 1.31e-66
7 <split [72/25]> Bootstrap0007 <lm> public 2.33 0.0299 77.9 1.61e-70
8 <split [72/23]> Bootstrap0008 <lm> public 2.34 0.0368 63.5 2.60e-64
9 <split [72/21]> Bootstrap0009 <lm> public 2.41 0.0349 68.9 8.70e-67
10 <split [72/26]> Bootstrap0010 <lm> public 2.39 0.0334 71.6 6.00e-68
# … with 991 more rows
我们现在有 1000 个估计值,这些估计值是通过重新采样获得的,存储在estimate列中的是私立学校和公立学校的学费之间的关系。现在的问题是,私立和公立学校学费之间的估计斜率的分布是什么?
tuition_coefs %>%
ggplot(aes(estimate))+
geom_histogram(alpha = .7)+
ggtitle("Distribution of Estimated Slope")+
xlab("Estimate")+
ylab("Frequency")+
theme_linedraw()+
theme(axis.title=element_text(size=14,face="bold"),
plot.title = element_text(size = 20, face = "bold"))
我们可以看到分布呈正态分布,我们可以感受到它有多宽。从数字上看,我们可以把这种分布的描述列表如下。

作者图片
int_pctl(tuition_models,
coef_inf)# A tibble: 1 x 6
term .lower .estimate .upper .alpha .method
<chr> <dbl> <dbl> <dbl> <dbl> <chr>
1 public 2.31 2.38 2.46 0.05 percentile
我们可以看到,通过 bootstrapping,描述私立和公立学校学费之间关系的估计斜率约为 2.38,与我们在没有 bootstrapping 的情况下获得的结果相似。这可能是因为公立和私立学校之间的潜在关系是线性的,并且线性模型的潜在假设适用于该数据集。线性回归的基本假设是:
- 变量之间的基本关系是线性的
- 误差通常是分布的
- 最佳拟合线周围有相等的方差(误差的同方差)
- 观察是独立的
此外,通过 bootstrapping,我们还可以获得关系的上下限,这是我们在未采样数据上仅使用线性模型时所没有的。
最后,我们可以可视化从自举样本中计算出的各种估计值。
tuition_aug <- tuition_models %>%
# Sample only 200 bootstraps for visualization
sample_n(200) %>%
mutate(augmented = map(model, augment)) %>%
unnest(augmented)tuition_aug %>%
ggplot(aes(public, private))+
geom_line(aes(y = .fitted, group = id), alpha = .1, color = 'grey')+
geom_point()+
scale_y_continuous(labels=scales::dollar_format())+
scale_x_continuous(labels=scales::dollar_format())+
ggtitle("200 of 1000 Slope Estimations from Bootstrap Resampling")+
xlab("Public School Tuition")+
ylab("Private School Tuition")+
theme_linedraw()+
theme(axis.title=element_text(size=14,face="bold"),
plot.title = element_text(size = 20, face = "bold"))

作者图片
总之,这篇博客演示了如何使用 R 中的 bootstrap 重采样来确定私立学校和公立学校学费之间的关系。这种技术使用随机抽样来估计几乎任何统计数据的抽样分布。
自助统计——如何解决简单统计测试的局限性
入门
你有一个数据样本。由此,您需要计算总体平均值的置信区间。你首先想到的是什么?通常是 t 检验。
但是 t 检验有几个要求,其中之一是均值的抽样分布接近正态(要么总体是正态的,要么样本相当大)。在实践中,这并不总是正确的,因此 t 检验可能并不总是提供最佳结果。
要解决这种限制,请使用 bootstrap 方法。它只有一个重要的要求:样本足够接近总体。常态不是必须的。
我们先来试试 t 检验,然后再和 bootstrap 法对比。
均值置信区间的单样本检验
让我们首先加载我们需要的所有库:
from sklearn.utils import resample
import pandas as pd
from matplotlib import pyplot as plt
import pingouin as pg
import numpy as np
import seaborn as snsnp.random.seed(42)
plt.rcParams["figure.figsize"] = (16, 9)
注意:我们在这里使用 Pingouin 库进行一些统计测试。这很棒,因为许多重要的技术都在同一个屋檐下,有统一的接口和语法。试试看:
【https://pingouin-stats.org/
现在回到主题,这是一个例子:
spl = [117, 203, 243, 197, 217, 224, 279, 301, 317, 307, 324, 357, 364, 382, 413, 427, 490, 742, 873, 1361]
plt.hist(spl, bins=20);

你可以假装这看起来很正常,但它有几个大的异常值,这是 t 检验不能容忍的。尽管如此,让我们对总体均值的 95%置信区间进行 t 检验:
pgtt = pg.ttest(spl, 0)
print(pgtt['CI95%'][0])[272.34 541.46]
这是一个非常宽的区间,反映了样本中值的分布。我们能做得更好吗?答案是肯定的,用自举法。
引导程序
如果样本更大,或者可以从同一人群中提取多个样本,结果会更好。但这在这里是不可能的——这是我们仅有的样本。
然而,如果我们假设样本非常接近总体,我们可以假装从总体中生成多个伪样本:我们真正做的是获取这个样本并对其进行重采样——使用相同的值生成相同大小的多个样本。然后我们处理生成的样本集。
你制作的伪样本数量需要很大,通常是数千个。
由于我们从原始样本生成的样本与原始样本的大小相同,因此一些值将在每个伪样本中重复。那很好。
平均值的 CI
让我们从原始样本中生成一万个重采样数据块:
B = 10000
rs = np.zeros((B, len(spl)), dtype=np.int)
for i in range(B):
rs[i,] = resample(spl, replace = True)
print(rs)[[ 279 1361 413 ... 357 357 490]
[ 307 427 413 ... 317 203 1361]
[ 413 279 357 ... 357 203 307]
...
[ 217 243 224 ... 279 490 1361]
[ 301 324 224 ... 224 317 317]
[ 324 301 364 ... 873 364 203]]
数组中的每一行都是重新采样的块,与原始样本大小相同。总共有 10k 线。
现在,让我们构建 bootstrap 分布:对于每条线,计算平均值:
bd = np.mean(rs, axis=1)
print(bd)[376.35 515.15 342.75 ... 507.8 426.15 377.05]
bootstrap 分布包含每个重新采样的数据块的平均值。从这里很容易得到均值的 95%置信区间:只需对 bootstrap 分布数组(均值)进行排序,截掉顶部和底部的 2.5%,读取剩余的极值:
bootci = np.percentile(bd, (2.5, 97.5))
print(bootci)[300.0975 541.705]
这就是平均值的 bootstrap 95%置信区间。它与 t 检验置信区间相比如何?
y, x, _ = plt.hist(bd, bins=100)
ymax = y.max()
plt.vlines(pgtt['CI95%'][0], 0, ymax, colors = 'red')
plt.vlines(bootci, 0, ymax, colors = 'chartreuse')
plt.vlines(np.mean(spl), 0, ymax, colors = 'black')
plt.show();

bootstrap CI(绿色)比 t-test CI(红色)更窄一些。
中值 CI
您也可以使用 bootstrap 为中值生成 CI:只需使用 np.median()而不是 np.mean()构建 bootstrap 分布:
bd = np.median(rs, axis = 1)
bootci = np.percentile(bd, (5, 95))
print(bootci)[279\. 382.]
差异 CI
让我们从已知方差(var=100)的正态总体中抽取一个样本:
sp = np.random.normal(loc=20, scale=10, size=50)
sns.violinplot(x=sp);

我们样本的方差确实接近 100:
print(np.var(sp))112.88909322502681
让我们使用 bootstrap 从现有样本中提取总体方差的置信区间。同样的想法:对数据进行多次重采样,计算每个重采样块的方差,得到方差列表的百分比区间。
rs = np.zeros((B, len(sp)), dtype=np.float)
for i in range(B):
rs[i,] = resample(sp, replace=True)
bd = np.var(rs, axis=1)
bootci = np.percentile(bd, (2.5, 97.5))
print(bootci)[74.91889462 151.31601521]
还不错;间隔足够窄,并且它包括总体方差的真值(100)。这是来自 bootstrap 分布的方差直方图:
y, x, _ = plt.hist(bd, bins=100)
ymax = y.max()
plt.vlines(bootci, 0, ymax, colors = 'chartreuse')
plt.vlines(np.var(sp), 0, ymax, colors = 'black')
plt.show();

两样本均值差,不成对
以下是两个李子样品的重量,按颜色分组:
https://raw . githubusercontent . com/FlorinAndrei/misc/master/plum data . CSV
plumdata = pd.read_csv('plumdata.csv', index_col=0)
sns.violinplot(x='color', y='weight', data=plumdata);

这两种颜色的平均重量不同吗?换句话说,平均权重差异的置信区间是多少?我们先来试试经典的 t 检验:
plum_red = plumdata['weight'][plumdata['color'] == 'red'].values
plum_yel = plumdata['weight'][plumdata['color'] == 'yellow'].values
plumtt = pg.ttest(plum_red, plum_yel)
print(plumtt['CI95%'][0])[8.67 27.2]
t 检验说—是的,在 95%的置信度下,红色李子的平均重量不同于黄色李子的平均重量(CI 不包括 0)。
对于 bootstrap,我们将对两个样本进行 10k 次重采样,计算每个重采样块的平均值,进行 10k 次平均值的差值,并查看平均值分布差值的 2.5 / 97.5 个百分点。
这是重新采样的数据:
plzip = np.array(list(zip(plum_red, plum_yel)), dtype=np.int)
rs = np.zeros((B, plzip.shape[0], plzip.shape[1]), dtype=np.int)
for i in range(B):
rs[i,] = resample(plzip, replace = True)
print(rs.shape)(10000, 15, 2)
10000 是重采样的次数,15 是每个重采样的长度,每种情况下我们比较 2 个样本。
让我们计算每个重采样块的平均值:
bd_init = np.mean(rs, axis=1)
print(bd_init.shape)(10000, 2)
bootstrap 分布是 10000 个重采样案例中每一个案例的平均值的差(红色平均值减去黄色平均值):
bd = bd_init[:, 0] - bd_init[:, 1]
print(bd.shape)(10000,)print(bd)[12.33333333 21\. 10.33333333 ... 21.46666667 11.66666667
17.06666667]
现在我们可以从 bootstrap 分布中获得均值差异的 CI:
bootci = np.percentile(bd, (2.5, 97.5))
print(bootci)[9.33333333 26.06666667]
bootstrap 再次提供了比 t-test 更紧密的间隔:
y, x, _ = plt.hist(bd, bins=100)
ymax = y.max()
plt.vlines(plumtt['CI95%'][0], 0, ymax, colors = 'red')
plt.vlines(bootci, 0, ymax, colors = 'chartreuse')
plt.show();

两样本差异均值,成对
以下是配对数据——几种品牌的绳索在潮湿或干燥条件下的强度:
https://raw . githubusercontent . com/FlorinAndrei/misc/master/strength . CSV
strength = pd.read_csv('strength.csv', index_col=0)
sns.violinplot(data=strength);

这些数据是否足以得出结论,干湿条件会影响绳索的强度?让我们计算一个 95%置信区间的平均强度差异,湿与干。首先,t 检验:
s_wet = strength['wet']
s_dry = strength['dry']
s_diff = s_wet.values - s_dry.values
strengthtt = pg.ttest(s_wet, s_dry, paired=True)
print(strengthtt['CI95%'][0])[0.4 8.77]
t 检验表明,在 95%的置信度下,潮湿/干燥条件确实产生了统计上的显著差异——但几乎没有。CI 的一端接近 0。
现在,让我们为同一个配置项进行引导。我们可以简单地取 s_diff(每根绳子的强度差异),然后回到单样本自举程序:
rs = np.zeros((B, len(s_diff)), dtype=np.int)
for i in range(B):
rs[i,] = resample(s_diff, replace = True)
bd = np.mean(rs, axis=1)
bootci = np.percentile(bd, (2.5, 97.5))
print(bootci)[1.33333333 8.5]
t 检验和 bootstrap 都同意,当条件不同时,强度不同,这在统计上有显著差异(95%的置信度)。自举自信一点(区间更窄,离 0 更远)。
y, x, _ = plt.hist(bd, bins=100)
ymax = y.max()
plt.vlines(strengthtt['CI95%'][0], 0, ymax, colors = 'red')
plt.vlines(bootci, 0, ymax, colors = 'chartreuse')
plt.show();

带代码的笔记本:
https://github . com/FlorinAndrei/misc/blob/master/bootstrap _ plain . ipynb
最后的想法
这只是基本的自举技术。它不执行偏差校正等。
没有解决小样本问题的方法。Bootstrap 功能强大,但并不神奇——它只能处理原始样本中的可用信息。
如果样本不能代表全部人口,那么 bootstrap 就不太准确。
使用 AWS Fargate 在 1000 个内核上引导 Dask
原文:https://towardsdatascience.com/bootstrapping-dask-on-1000-cores-with-aws-fargate-1e1b7fd1a32c?source=collection_archive---------24-----------------------
利用云的力量来供应和部署 1000 个内核,以处理大量数据并完成工作

美国宇航局在 Unsplash 拍摄的照片
作为一名数据工程师,我发现自己多次需要一个系统,在这个系统中,我可以构建繁重的大数据任务的原型。我的团队传统上使用 EMR 和 Apache Spark 来完成此类任务,但是随着关于 Apache 淘汰 hadoop 项目的消息以及 python 是数据分析的首选工具这一常见范例的出现,我开始追求一个更现代的 python 原生框架。
我的目标是实现 1000 核集群的一键式部署,可以运行约 1TB 数据的原型处理,然后拆除。另一个条件是,这些资源不需要干扰我团队的其他资源。因此一键 eks-fargate-dask 工具诞生了!
AWS Fargate
AWS Fargate 是一个用于容器的无服务器计算引擎,它与亚马逊弹性容器服务(ECS) 和亚马逊弹性库本内特服务(EKS) 一起工作。
简而言之,Fargate 使开发人员能够根据 pods 指定的需求来分配 CPU 和内存,而不是预先分配节点。
eksctl
eksctl 是一个用于管理 EKS 集群的 cli 工具。它允许通过 EC2(计算节点)或 Fargate(无服务器)后端使用一个命令来配置和部署 EKS 集群。截至本文撰写之时,它还不支持指定 Fargate spot 实例,这太糟糕了。
eksctl alsl 提供了实用程序命令,用于提供对 kubernetes 服务帐户的 IAM 访问。
达斯克
Dask 是一个库,它支持在远程或本地集群上通过并行计算来处理大于内存的数据结构。它为数组(numpy)和数据帧(pandas)等数据结构提供了熟悉的 python APIs。建立基于本地流程的集群非常简单,但依我个人之见,Dask 的亮点在于其令人惊叹的生态系统,允许在 Kubernetes、YARN 和许多其他多处理集群上建立集群。
把所有的放在一起
首先,我使用这个脚本部署一个 EKS Fargate 集群。该脚本需要在 IAM 角色的上下文中运行,该角色拥有许多 AWS 部署操作的权限(主要是部署 Cloudformation 堆栈)。用于 dask workers 的 IAM 角色并没有提供对 S3 服务的完全访问权限,因为我是从 S3 的 parquet 文件中加载数据的。
运行这个命令后,您应该有一个名为 dask 的 EKS 集群启动并运行。在接下来的部分,我们将部署一个 dask 头盔版本。可以通过设置值来定制舵释放。这些是我在 dask 集群中使用的值:
然后安装舵释放装置:
就是这样!您已经安装了 dask 集群!您可以在 s3 上运行这个使用开放的 ookla 数据集的示例笔记本,看看扩展集群如何提高性能。
Dask 数据框 API 与 pandas 并不是 100%兼容(可以说是设计上的)。Dask 的文档网站上有一堆有用的资源。
使用完集群后,记得缩小规模!
结论
我一直在寻找一种快速的方法,不依赖于 python 原生框架的原型大数据处理。这绝不适合生产使用,并且可能也没有进行成本优化,但是它完成了工作,在几分钟内我就能够处理超过 300GB 的 parquet 文件(数据帧中可以膨胀到 1TB)
自举标准差
原文:https://towardsdatascience.com/bootstrapping-the-standard-deviation-fb415a9d7f39?source=collection_archive---------10-----------------------
许多人知道但很少讲述的基于 python 的故事

由明陈在 Unsplash 拍摄的照片
Bootstrapping 是一种重采样方法,它允许我们从样本中推断出总体的统计数据。它也很容易执行和理解,这使得它如此织补酷。使用 bootstrap 或完全了解其潜力的从业者知道,他们可以用它来估计各种人口统计数据,但我在网上找到的几乎所有例子都只使用 bootstrap 来估计人口的平均值。我想是时候改变这种状况了。
在这篇短文中,我将回顾 bootstrap 方法以及如何在 python 中执行它。然后,我们将使用这种方法来估计总体标准差的置信区间,以减轻关于如何引导总体统计数据而不是样本均值的任何困惑。我们将做一些可视化的工作,以便更好地理解我们所学的内容,并尝试抽取更多的样本,看看这会如何影响结果。
让我们开始吧。
设置
如果你愿意,你可以在 Jupyter 笔记本这里跟随。
从导入我们需要的所有包开始。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
import scipy.stats as st
现在,让我们生成一个虚构的“人口”我编造了均值和标准差。如果你愿意,你可以自己编。
# generate a ficticious population with 1 million values
pop_mean = 53.21
pop_std = 4.23
population = np.random.normal(pop_mean, pop_std, 10**6)# plot the population
sns.distplot(population)
plt.title('Population Distribution')

作者图片
我们现在已经创建了一个“总体”,它有一百万个值,平均值为 52.21,标准差为 4.23。
抽取样本
我们希望从总体中抽取一个小样本,用于引导总体参数的近似值。实际上,我们只有样品。
# Draw 30 random values from the population
sample = np.random.choice(population, size=30, replace=False)
变量sample现在包含从总体中随机抽取的 30 个值。

作者图片
bootstrap——综述
我会很快地讲到这里。如果你想更深入地了解 bootstrap 方法,可以看看我以前的文章估计未来音乐人和非营利组织的在线活动捐赠收入——用 python 对置信区间进行 Bootstrap 估计。
自举的所有神奇之处都是通过替换采样实现的。替换意味着当我们抽取一个样本时,我们记录下这个数字,然后将这个数字返回给源,这样它就有同样的机会被再次选中。这就是我们正在分析的产生变异的原因,以便对总体做出推断。
我们可以认为这是从一顶帽子(或者一只靴子,如果你喜欢的话)中抽取数字。
- 数一数你帽子里的记录数
- 从你的帽子里随机抽取一张记录
- 记录该记录的值,并将记录放回帽子中
- 重复上述步骤,直到记录的数值数量与帽子中记录的数值数量相同
- 计算样本度量,如平均值或标准偏差,并记录下来
- 重复这个过程 1000 次左右
- 计算分位数以获得您的置信区间
让我们用numpy来做这个,它比从帽子里抽数字要快得多。
bs = np.random.choice(sample, (len(sample), 1000), replace=True)
现在我们有一个 30x1000 numpy的数组,每 1000 行代表一个新的样本。
为了推断总体平均值,我们可以取所有行的平均值,然后取这些平均值的平均值。
bs_means = bs.mean(axis=0)
bs_means_mean = bs_means.mean()
bs_means_mean
54.072626327248315
那还不错。记得人口平均数是53.21。
但这不是有用的部分。如果我们取样本的平均值,我们会得到相似的结果。
sample.mean()
54.12110644012915
真正的价值在于我们可以通过自举生成的置信区间。我们将返回并使用我们的bs_means变量,它包含 1000 个重采样样本的平均值。为了计算 95%的置信区间,我们可以取这些平均值的 0.025 和 0.975 分位数。95%的重采样样本的平均值在这两个分位数之间,这给出了我们的置信区间。
lower_ci = np.quantile(bs_means, 0.025)
upper_ci = np.quantile(bs_means, 0.975)lower_ci, upper_ci
(52.41754898532445, 55.602661654526315)
很神奇,对吧?如果从大量不同的可能人群中抽取相同的样本,这些人群中的 95/100 将具有介于 52.54 和 55.77 之间的平均值。
标准偏差
这是大多数 bootstrap 示例的终点,但我们想看看我们能在多大程度上重建我们的总体,所以我们还需要计算标准差。
好消息是,过程是相同的,除了我们采用每个重采样样本的标准差,而不是平均值。同样在我们以前取平均值的时候,我们现在可以计算标准差的平均值。
bs_stds = bs.std(axis=0)
bs_std_mean = bs_stds.mean()
bs_std_mean
4.398626063763372
我们可以像以前一样通过寻找分位数来计算总体标准差的置信区间。
lower_ci = np.quantile(bs_stds, 0.025)
upper_ci = np.quantile(bs_stds, 0.975)lower_ci, upper_ci
(3.3352503395296598, 5.387739215237817)
总体标准差的 95%置信区间为 3.34 至 5.39。
让我们把它画出来,以便更好地理解它的意思。
# plot the distributions with std at the confidence intervals
dist_low = st.norm(loc=bs_means_mean, scale=std_qtl_025)
y_low = dist_low.pdf(x)dist_high = st.norm(loc=bs_means_mean, scale=std_qtl_975)
y_high = dist_high.pdf(x)#plot
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))plt.sca(ax1)
sns.distplot(population, ax=ax1)
plt.plot(x,y_low, color='red')
plt.plot(x,y_high, color='red')
plt.title('Variation in std at Confidence Intervals')# plot the distributions with mean at the confidence intervals
dist_low = st.norm(loc=means_qtl_025, scale=bs_std_mean)
y_low = dist_low.pdf(x)dist_high = st.norm(loc=means_qtl_975, scale=bs_std_mean)
y_high = dist_high.pdf(x)#plot
plt.sca(ax2)
sns.distplot(population)
plt.plot(x,y_low, color='red')
plt.plot(x,y_high, color='red')plt.title('Variation in mean at Confidence Intervals')

作者图片
第一个图显示 95/100 倍的人口分布将落在两个红色分布之间,代表标准差的上下置信区间。第二个图显示 95/100 倍的人口分布将落在两个红色分布之间,代表平均值的上下置信区间。现在我们对给定样本时可能的总体参数范围有了一个概念。
重采样次数
你可能还有另一个问题:如果我们重新采样 1000 次以上,我们会得到更精确的结果吗?
让我们通过重新采样 1000 万次而不是 1000 次来找出答案
bs_big = np.random.choice(sample, (len(sample), 10**7), replace=True)
计算平均值。
bs_means = bs_big.mean(axis=0)
bs_means_mean = bs_means.mean()
bs_means_mean
54.12096064254814
之前的平均值是 54.125363863656 那也差不了多少,离 53.21 的地面真相还远一点。
means_qtl_025 = np.quantile(bs_means, 0.025)
means_qtl_975 = np.quantile(bs_means, 0.975)means_qtl_025, means_qtl_975
(52.535753878990164, 55.76684250100114)
先前的值为(52.41754898532445,55.5555353651
bs_stds = bs_big.std(axis=0)
bs_std_mean = bs_stds.mean()
bs_std_mean
4.414164449356725
先前的值是 4.3986263372
std_qtl_025 = np.quantile(bs_stds, 0.025)
std_qtl_975 = np.quantile(bs_stds, 0.975)std_qtl_025, std_qtl_975
(3.3352503395296598, 5.387739215237817)
以前的值为(3.356752806683829,5.4663411850985)
似乎没有太大的区别。我们再把它画出来。
x = np.linspace(30, 80, 1000)# plot the distributions with std at the confidence intervals
dist_low = st.norm(loc=bs_means_mean, scale=std_qtl_025)
y_low = dist_low.pdf(x)dist_high = st.norm(loc=bs_means_mean, scale=std_qtl_975)
y_high = dist_high.pdf(x)#plot
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))plt.sca(ax1)
sns.distplot(population, ax=ax1)
plt.plot(x,y_low, color='red')
plt.plot(x,y_high, color='red')
plt.title('Variation in std at Confidence Intervals\n10 million re-samples')# plot the distributions with mean at the confidence intervals
dist_low = st.norm(loc=means_qtl_025, scale=bs_std_mean)
y_low = dist_low.pdf(x)dist_high = st.norm(loc=means_qtl_975, scale=bs_std_mean)
y_high = dist_high.pdf(x)#plot
plt.sca(ax2)
sns.distplot(population)
plt.plot(x,y_low, color='red')
plt.plot(x,y_high, color='red')plt.title('Variation in mean at Confidence Intervals\n10 million re-samples')

作者图片
先前的绘图重采样 1000 次:

作者图片
我要说的是,这些结果基本上是听不出来的,当然,在我们的情况下,重采样 1000 次以上没有任何好处。
所以,这就是那个鲜为人知但却广为人知的故事:用均值和标准差来估计总体参数。
使用 Python 和 R
原文:https://towardsdatascience.com/bootstrapping-using-python-and-r-b112bb4a969e?source=collection_archive---------4-----------------------
使用重复抽样估计抽样分布

来源:照片由来自 Pixabay 的 krzysztof-m 拍摄
确定一个总体特征的尝试常常受到这样一个事实的限制,即我们必须依靠一个样本来确定该总体的特征。
在分析数据时,我们希望能够估计抽样分布,以便进行假设检验和计算置信区间。
试图解决这个问题的一种方法是一种叫做自举的方法,通过重复采样来推断更广泛人群的结果。
例如,为了确定同一人群的不同样本是否会产生相似的结果,理想的方法是获取新的数据样本。然而,鉴于这可能是不可能的,一种替代方法是从现有数据中随机取样。
对于这个示例,我们将查看一系列酒店客户的平均每日房价(ADR)的分布。具体而言,ADR 数据的子集与 bootstrapping 技术结合使用,以分析在给定较大样本量的情况下,预期的分布情况。
当使用自举产生样本时,这通过替换来完成**。这意味着可以从样品中多次选择相同的元素。**
使用 Python 引导
使用从 Antonio、Almeida 和 Nunes 提供的数据集中随机抽取的 300 个酒店客户 ADR 值样本,我们将生成 5000 个大小为 300 的 bootstrap 样本。
具体来说,numpy 如下用于生成 300 个替换样本,而循环的用于一次生成 300 个样本的 5000 次迭代。
my_samples = []
for _ in range(5000):
x = np.random.choice(sample, size=300, replace=True)
my_samples.append(x.mean())
以下是引导样本的直方图:

来源:Jupyter 笔记本输出
这是随机选取的 300 个原始样本的直方图:

来源:Jupyter 笔记本输出
我们可以看到原始样本是显著正偏的。但是,自举样本的直方图近似于正态分布,这符合中心极限定理的假设,即随着样本大小的增加,无论原始分布的形状如何,基本数据分布都可以近似为正态分布。
bootstrapping 的主要用途是估计总体均值的置信区间。例如,95%的置信区间意味着我们有 95%的把握均值位于特定范围内。
引导样本的置信区间如下:
>>> import statsmodels.stats.api as sms
>>> sms.DescrStatsW(my_samples).tconfint_mean()(94.28205060553655, 94.4777529411301)
根据以上所述,我们可以 95%确信真实的人口平均数在 94.28 和 94.47 之间。
使用 R 自举
使用 R 中的 boot 库,可以进行类似形式的分析。
再次假设只有 300 个样本可用:
adr<-sample(adr, 300)
使用带有替换的随机取样,产生这 300 个样本的 5,000 个重复。
x<-sample(adr, 300, replace = TRUE, prob = NULL)> mean_results <- boot(x, boot_mean, R = 5000)
ORDINARY NONPARAMETRIC BOOTSTRAPCall:
boot(data = x, statistic = boot_mean, R = 5000)Bootstrap Statistics :
original bias std. error
t1* 93.00084 -0.02135855 2.030718
此外,以下是置信区间的计算:
> boot.ci(mean_results)
BOOTSTRAP CONFIDENCE INTERVAL CALCULATIONS
Based on 5000 bootstrap replicatesCALL :
boot.ci(boot.out = mean_results)Intervals :
Level Normal Basic
95% (89.04, 97.00 ) (88.98, 96.82 )Level Percentile BCa
95% (89.18, 97.02 ) (89.36, 97.32 )
Calculations and Intervals on Original Scale
生成自举样本的直方图:

来源:RStudio 输出
当在 R 中运行时,我们可以看到置信区间比使用 Python 运行时获得的置信区间更宽。虽然原因尚不清楚,但分析仍然表明,所获得的样本平均值代表了总体水平,不可能是偶然获得的。
限制
虽然自举是从样本推断总体特征的非常有用的工具,但一个常见的错误是假设自举是解决小样本问题的方法。
正如在交叉验证中所解释的,小样本量可能更不稳定,更容易与更广泛的人群产生重大偏差。因此,人们应该确保被分析的样本足够大,以便充分捕捉群体特征。
此外,小样本量的另一个问题是,bootstrap 分布本身可能会变得更窄,这反过来会导致更窄的置信区间,从而显著偏离真实值。
结论
在本文中,您已经看到:
- bootstrapping 如何允许我们使用重复抽样来估计抽样分布
- 随机抽样时替换的重要性
- 如何使用 Python 和 R 生成引导示例
- 自举的局限性以及为什么更大的样本量更好
非常感谢您的宝贵时间,非常感谢您的任何问题或反馈。你可以在 michael-grogan.com 的找到更多我的数据科学内容。
参考
- 安东尼奥,阿尔梅达,努内斯(2019)。酒店预订需求数据集
- 交叉验证:bootstrap 能被视为小样本的“治疗方法”吗?
- docs . scipy . org:scipy . stats . bootstrap
- 朱利安·比留:抽样分布
- 吉姆的《统计学:统计学中的自举法介绍及实例
- 多伦多大学编码器-R:Bootstrapping 和置换测试中的重采样技术
免责声明:本文是在“原样”的基础上编写的,没有任何担保。它旨在提供数据科学概念的概述,不应被解释为专业建议。本文中的发现和解释是作者的发现和解释,不被本文中提到的任何第三方认可或隶属于任何第三方。作者与本文提及的任何第三方无任何关系。
基于深度学习和 OpenCV 的无边界表格检测
原文:https://towardsdatascience.com/borderless-tables-detection-with-deep-learning-and-opencv-ebf568580fe2?source=collection_archive---------2-----------------------
构建您自己的对象检测器并将图像中的半结构化数据块转换为机器可读文本的方法

作者图片
文档解析
文档解析是将信息转换成有价值的业务数据的第一步。这些信息通常以表格形式存储在商业文档中,或者存储在没有明显图形边界的数据块中。一个无边界的表格可能有助于简化我们人类对半结构化数据的视觉感知。从机器阅读的角度来看,这种在页面上呈现信息的方式有很多缺点,使得很难将属于假定的表格结构的数据与周围的文本上下文分开。
表格数据提取作为一项业务挑战,可能有几个特别的或启发式的基于规则的解决方案,对于布局或风格稍有不同的表,这些解决方案肯定会失败。在大规模上,应该使用更通用的方法来识别图像中的表格状结构,更具体地说,应该使用基于深度学习的对象检测方法。
本教程的范围:
- 基于深度学习的物体检测
- 安装和设置 TF2 对象检测 API
- 数据准备
- 模型配置
- 模型训练和保存
- 现实生活图像中的表格检测和细胞识别
基于深度学习的物体检测
著名的 CV 研究员 Adrian Rosebrock 在他的“[深度学习对象检测温和指南](http://gentle guide to deep learning object detection)”中指出:“对象检测,无论是通过深度学习还是其他计算机视觉技术来执行,都建立在图像分类的基础上,并寻求精确定位对象出现的区域”。正如他所建议的,建立自定义对象检测器的一种方法是选择任何分类器,并在此之前使用一种算法来选择和提供图像中可能包含对象的区域。在这种方法中,您可以自由决定是否使用传统的 ML 算法进行图像分类(是否使用 CNN 作为特征提取器)或者训练一个简单的神经网络来处理任意的大型数据集。尽管其效率已被证明,但这种被称为 R-CNN 的两阶段对象检测范式仍然依赖于繁重的计算,不适合实时应用。
上述帖子中还进一步说,“另一种方法是将预先训练好的分类网络作为多组件深度学习对象检测框架中的基础(骨干)网络(如更快的 R-CNN 、 SSD ,或 YOLO )。因此,您将受益于其完整的端到端可培训架构。
无论选择是什么,它都会让你进一步了解重叠边界框的问题。在下文中,我们将触及为此目的执行的非最大抑制。
同时,请参考任意新类别的对象检测器的迁移学习流程图(参见交互视图):

作者图片
由于第二种方法速度更快、更简单且更准确,它已经被广泛用于商业和科学论文中的表格结构识别。例如,您可以很容易地找到使用【YOLO】、 RetinaNet 、 Cascade R-CNN 和其他框架从 PDF 文档中提取表格数据的实现。
继续学习本教程,您将了解如何使用像 TensorFlow (TF2)对象检测 API 这样的工具,使用预先训练的最先进的模型轻松构建您的自定义对象检测器。
开始之前
请注意,这不会是对深度学习对象检测的详尽介绍,而是对如何在特定开发环境( Anaconda/Win10 )中与 TF2 对象检测 API (和其他工具)交互以解决明显的业务问题(如无边界表格检测)的分阶段描述。在这篇文章的其余部分,我们将会比其他人更详细地介绍建模过程的一些方面和结果。尽管如此,在我们的实验之后,您将会找到基本的代码示例。要继续,你应该安装好 Anaconda 和宇宙魔方,下载 protobuf 并添加到 PATH。
TF2 对象检测 API 的安装和设置
在您选择的路径下创建一个新文件夹,我们在下文中称之为*‘项目的根文件夹’*。从您的终端窗口逐一运行以下命令:
*# from <project’s root folder>
conda create -n <new environment name> \
python=3.7 \
tensorflow=2.3 \
numpy=1.17.4 \
tf_slim \
cython \
git**conda activate <new environment name>**git clone* [*https://github.com/tensorflow/models.git*](https://github.com/tensorflow/models.git)*pip install git+https://github.com/philferriere/cocoapi.git#subdirectory=PythonAPI**cd models\research* *# from <project’s root folder>\models\researchprotoc object_detection\protos\*.proto — python_out=.**copy object_detection\packages\tf2\setup.py .**python setup.py install**python object_detection\builders\model_builder_tf2_test.py**conda install imutils pdf2image beautifulsoup4 typeguard**pip install tf-image**copy object_detection\model_main_tf2.py ..\..\workspace\.**copy object_detection\exporter_main_v2.py ..\..\workspace\.**cd ..\..*
它将在您的本地环境中安装使用 TF2 对象检测 API 所需的核心和一些助手库,并负责您的训练数据集。从这一步开始,你应该能够从 TF2 模型园下载一个预训练模型,并且从它得到相应预训练类的推论。
数据准备
我希望到目前为止你已经成功了!请记住,我们的最终目标是使用预训练模型来执行迁移学习,以检测单个“无边界”类,而该模型在初始训练时对此一无所知。如果你研究过我们的迁移学习流程图,你应该已经注意到我们整个过程的起点是一个数据集,不管有没有注释。如果你需要注释,有吨的解决方案可用。选择一个能给你 XML 注释的,与我们的例子兼容的。
我们拥有的注释数据越多越好(重要:这篇文章的所有表格图片都选自开放的数据源,如this,并由作者注释/重新注释)。但是一旦你尝试手工标注数据,你就会明白这项工作有多乏味。不幸的是,没有一个流行的用于图像增强的 python 库能够处理选定的边界框。在没有收集和注释新数据的高成本的情况下,增加初始数据集符合我们的利益。这就是一个 tf-image 包将变得方便的情况。
上述脚本将随机转换原始图像和对象的边界框,并将新图像和相应的 XML 文件保存到磁盘。这就是我们的数据集经过三倍扩展后的样子:

作者图片
接下来的步骤将包括将数据分成训练集和测试集。基于 TF2 对象检测 API 的模型需要一种特殊的格式用于所有输入数据,称为 TFRecord 。你会在 Github 库中找到相应的脚本来拆分和转换你的数据。
模型配置
在这一步,我们将创建一个标签映射文件()。pbtxt )将我们的类标签(‘无边界’)链接到某个整数值。 TF2 对象检测 API 需要此文件用于训练和检测目的:
*item {
id: 1
name: ‘borderless’
}*
实际的模型配置发生在相应的 pipeline.config 文件中。你可以阅读对模型配置的介绍,并决定是手动配置文件还是通过运行 Github 库中的脚本来配置文件。
到目前为止,您的项目的根文件夹可能如下所示:
📦borderless_tbls_detection
┣ 📂images
┃ ┣ 📂processed
┃ ┃ ┣ 📂all_annots
┃ ┃ ┃ ┗ 📜…XML
┃ ┃ ┗ 📂all_images
┃ ┃ ┃ ┗ 📜…jpg
┃ ┣ 📂splitted
┃ ┃ ┣ 📂test_set
┃ ┃ ┃ ┣ 📜…jpg
┃ ┃ ┃ ┗ 📜…XML
┃ ┃ ┣ 📂train_set
┃ ┃ ┃ ┣ 📜…jpg
┃ ┃ ┃ ┗ 📜…XML
┃ ┃ ┗ 📂val_set
┃ ┗ 📜xml_style.XML
┣ 📂models
┃ ┗ 📂…
┣ 📂scripts
┃ ┣ 📜…py
┣ 📂train_logs
┣ 📂workspace
┃ ┣ 📂data
┃ ┃ ┣ 📜label_map.pbtxt
┃ ┃ ┣ 📜test.csv
┃ ┃ ┣ 📜test.record
┃ ┃ ┣ 📜train.csv
┃ ┃ ┣ 📜train.record
┃ ┃ ┣ 📜val.csv
┃ ┃ ┗ 📜val.record
┃ ┣ 📂models
┃ ┃ ┗ 📂efficientdet_d1_coco17_tpu-32
┃ ┃ ┃ ┗ 📂v1
┃ ┃ ┃ ┃ ┗ 📜pipeline.config
┃ ┣ 📂pretrained_models
┃ ┃ ┗ 📂datasets
┃ ┃ ┃ ┣ 📂efficientdet_d1_coco17_tpu-32
┃ ┃ ┃ ┃ ┣ 📂checkpoint
┃ ┃ ┃ ┃ ┃ ┣ 📜checkpoint
┃ ┃ ┃ ┃ ┃ ┣ 📜ckpt-0.data-00000-of-00001
┃ ┃ ┃ ┃ ┃ ┗ 📜ckpt-0.index
┃ ┃ ┃ ┃ ┣ 📂saved_model
┃ ┃ ┃ ┃ ┃ ┣ 📂assets
┃ ┃ ┃ ┃ ┃ ┣ 📂variables
┃ ┃ ┃ ┃ ┃ ┃ ┣ 📜variables.data-00000-of-00001
┃ ┃ ┃ ┃ ┃ ┃ ┗ 📜variables.index
┃ ┃ ┃ ┃ ┃ ┗ 📜saved_model.pb
┃ ┃ ┃ ┃ ┗ 📜pipeline.config
┃ ┃ ┃ ┗ 📜efficientdet_d1_coco17_tpu-32.tar.gz
┃ ┣ 📜exporter_main_v2.py
┃ ┗ 📜model_main_tf2.py
┣ 📜config.py
┗ 📜setup.py
模型训练和保存
我们做了很多工作才来到这里,并为开始训练做好了一切准备。下面是如何做到这一点:
*# from <project’s root folder>
tensorboard — logdir=<logs folder>**set NUM_TRAIN_STEPS=1000**set CHECKPOINT_EVERY_N=1000**set PIPELINE_CONFIG_PATH=<path to model’s pipeline.config>**set MODEL_DIR=<logs folder>**set SAMPLE_1_OF_N_EVAL_EXAMPLES=1**set NUM_WORKERS=1**python workspace\model_main_tf2.py \
— pipeline_config_path=%PIPELINE_CONFIG_PATH% \
— model_dir=%MODEL_DIR% \
— checkpoint_every_n=%CHECKPOINT_EVERY_N% \
— num_workers=%NUM_WORKERS% \
— num_train_steps=%NUM_TRAIN_STEPS% \
— sample_1_of_n_eval_examples=%SAMPLE_1_OF_N_EVAL_EXAMPLES% \
— alsologtostderr**# (optionally in parallel terminal window)
python workspace\model_main_tf2.py \
— pipeline_config_path=%PIPELINE_CONFIG_PATH% \
— model_dir=%MODEL_DIR% \
— checkpoint_dir=%MODEL_DIR%*
现在,您可以在浏览器中监控培训过程,网址为 http://localhost:6006 :

作者图片
要在训练完成后导出您的模型,只需运行以下命令:
*# from <project’s root folder>
python workspace\exporter_main_v2.py \
— input_type=image_tensor \
— pipeline_config_path=%PIPELINE_CONFIG_PATH% \
— trained_checkpoint_dir=%MODEL_DIR% \
— output_directory=saved_models\efficientdet_d1_coco17_tpu-32*
图像中的表格检测和细胞识别
NMS 和欠条
由于我们已经保存了新的微调模型,我们可以开始检测文档中的表格。前面我们提到了一个物体检测系统不可避免的问题——重叠包围盒。考虑到我们正在处理的无边界表格的过度分段性质,我们的模型偶尔会为单个对象输出比您预期的更多的边界框。毕竟,这是我们的目标探测器正在正确发射的标志。为了处理重叠边界框(指同一对象)的移除,我们可以使用非最大抑制。
неre 是我们的检测器在执行非最大值抑制前后的推断结果:

看起来我们已经成功地解决了预测重叠矩形包围物体的问题,但是我们的检测仍然达不到真实边界框。这是必然的,因为没有完美的模型。我们可以用交并比(IoU)来测量检波器的精度。作为分子,我们计算预测边界框和实际边界框之间的重叠面积。作为分母,我们计算由预测边界框和实际边界框包围的区域。IoU 得分> 0.5 通常被认为是“好”的预测[ Rosenbrock,2016 ]。
对于我们测试集中的一些图像,我们有以下指标:

细胞识别和 OCR
这将是我们的三部分算法的最后步骤:在(1)表格被检测到之后,我们将(2)用 OpenCV 识别它的单元格(因为表格是无边界的)并将它们彻底分配到适当的行和列,以进一步进行(3)用pytesserac通过光学字符识别(OCR)从每个分配的单元格中提取文本。
大多数细胞识别算法都是基于表格的行结构。清晰和可检测的线条对于正确识别细胞是必要的。由于我们的表格没有空白,我们将手动重建表格网格,在经过阈值处理和调整大小的图像上搜索白色垂直和水平间隙。这种方法有点类似于这里使用的。
完成这一步后,我们可以用 OpenCV 找到轮廓(即我们的单元格边界),将它们分类并分配到一个类似表格的结构中:
图表上显示了整个工作流程:

作者图片
至此,我们已经将所有的盒子和它们的值按正确的顺序排序了。剩下的工作就是获取每个基于图像的盒子,通过膨胀和腐蚀为 OCR 做准备,并让pytesserac识别包含的字符串:

最后的想法
啊,走了很长一段路!我们的自定义对象检测器可以识别文档中的半结构化信息块(也称为无边界表格),进一步将它们转换为机器可读的文本。尽管这个模型没有我们预期的那么精确。因此,我们有很大的改进空间:
- 在我们模型的配置文件中进行更改
- 与来自模型园的其他模型玩耍
- 执行更保守的数据扩充
- 尝试重新使用模型,之前在表格数据上训练过(虽然不可用于 TF2 对象检测 API)
厌倦了使用条形图?
原文:https://towardsdatascience.com/bored-of-using-bar-charts-74e0b088979b?source=collection_archive---------26-----------------------
利用条形图获得创意的 5 种方法
条形图是我在工作中展示数据见解时最常用的图表形式之一。但是我经常觉得这有点单调和重复,尤其是当你需要在同一个仪表板上显示很多 KPI 的时候。

普里西拉·杜·普里兹在 Unsplash 上的照片
这里有五种不同的变化,您可以使用条形图来显示数据。
1.使用圆形条
我在我最近的一部即关于 F.R.I.E.N.D.S .的电视连续剧中使用了这个技巧。它的工作方式基本上是你给 tableau 提供两个度量名,然后用它们画一条线。这和画彗星图很像。
a.首先绘制一个普通的条形图,方法是将维拖到列架,将度量拖到行架。

Tableau 中的普通条形图(图片由作者提供)
b.接下来,在行架上添加另一个度量值作为 min(0)。它基本上是 0 处的一个点,将作为绘制直线的第二个点。
c.现在我们需要将图表类型改为折线图。

步骤 1c。作者图片
d.将测量名称添加到路径架,将测量值添加到行架,并将两个测量都移动到测量值架,如下所示。
e.现在,只需调整线条的大小,使其稍微粗一点。如果需要,调整轴。
你完了!

圆形条形图(图片由作者提供)
2.带底座的圆棒
这种图表在我之前的 F.R.I.E.N.D.S .中也使用过。它对分类维度非常有效。您也可以使用相同的技术构建堆积条形图。

底部有甘特条形图的圆形条形图(图片由作者提供)
它与上一节的图表完全相似。得到圆形条形图后,按照以下步骤操作。
a.只需向 rows shelf 添加另一个度量值— min(0)。
b.右键单击计算并选择双轴。

作者图片
c.接下来右键单击 Y 轴,然后单击同步轴。

作者图片
d.现在,将第二个度量的图表类型更改为甘特图。
e.缩小条形的尺寸,你会得到带底的圆形条形图。

作者图片
调整轴就行了!
3.显示百分比份额或评级的条形图—类型 1
这种条形图在传达整体情况时非常有效。我最近在我的 viz — 我的几周生活中使用了它。您可以通过三个简单的步骤来构建它。
a.将连续尺寸添加到柱架中。
b.将图表类型更改为圆形。
c.根据需要增加颜色的尺寸,并增加条形的大小。
你完了!

来源:我的 Viz(作者图片)
4.显示百分比份额或评级的条形图—类型 2
如上所述,这种类型的条形图有助于快速显示评级或百分比。它很容易建立,并遵循类似的技术。它看起来超级好,可以用在工具提示中,就像我一样。我们将使用这种技术构建一个水平条形图。

来源:我的 Viz
a.您需要创建一个 min(10)的计算字段,并将其放在列架上。
b.接下来,在列架上添加评级度量值,并选择双轴。同步轴。
c.将最小(10)测量的图表类型更改为条形,并选择一种浅色填充。
d.将“评分”测量的图表类型更改为圆形,并选择较暗的颜色。
e.相应地调整尺寸。
你有它!

来源:我的 Viz
5.重叠条形图
当您想要显示不同时间段之间的比较时,这些图表非常有用。例如,您的管理层希望了解不同业务部门的季度业绩。
为了构建这个,我使用了 Tableau 中的样本超市数据集。
a.选择要用来分割结果的维度。我在这个例子中使用了 segment。
b.为该特定时间范围创建两个具有度量值的计算字段。例如,我正在比较 2019 年和 2020 年的销售额。所以,我创造了 2019 年和 2020 年的销量。


每年的销售额(图片由作者提供)
c.将这些销售字段拖到行架上,然后选择双轴。同步轴。
d.将日期字段拖到颜色卡上。在我的例子中,是年份字段。
现在,有趣的部分。
e.调整两个条形的大小。我一般会把旧的时间段的线条做得粗一点,半透明一点,把最新的时间段的线条做得粗一点,薄一点。
这是结果。

重叠条形图(图片由作者提供)
今天到此为止,各位!
我希望这些技巧和提示能像帮助我一样帮助你提高你的 viz。
感谢阅读!
下次见……
用于宏基因组样本分型的借用文本分析
原文:https://towardsdatascience.com/borrow-text-analysis-for-metagenome-sample-typing-4cbf475259f2?source=collection_archive---------49-----------------------
如何使用 TF-IDF、XGBoost 和 SHAP 对元基因组进行分类和解释
这篇文章显示:
1.使用 GridSearchCV 为宏基因组样本分型构建 TF-IDF 和 XGBoost 管道。
2.使用 TF-IDF 对分类轮廓进行矢量化以进行建模。
3.建立一个 F1 分数高的 XGBoost 模型。
4.使用 SHAP 查看特征贡献并识别每个样本类型的不同分类群
介绍
自从安东尼·范·列文虎克第一次看到微生物世界,我们人类就被它迷住了。在不到 400 年的时间里,我们从无知到认识到它们在我们的健康和全球生化循环中的关键作用。据估计,在我们的身体上,微生物的数量是人类细胞的十倍。从生物燃料到塑料降解、生物修复和医药,我们的未来越来越依赖于它们。
即使我们仍然使用显微镜和生物化学测试来观察微生物,但仅根据它们的外观和生物化学反应,很难区分谁是谁。DNA 测序来拯救。如今,我们不仅测序单个基因组,还测序整个微生物群落,也称为宏基因组。

图一。照片由国立癌症研究所在 Unsplash 上拍摄
顾名思义,宏基因组是样本或栖息地内所有基因组的总和,无论是病毒、细菌还是真核生物。我们通过对宏基因组进行整体测序或者通过靶向 16S 区域来确定宏基因组的内容。不同类型的样本包含不同的生物体,因此它们的元基因组也应该不同。相反,这意味着可以通过单独检查它们的分类特征来区分不同的样本类型。例如,现在可以通过分析患者的宏基因组来进行快速临床诊断(皮安塔多西等人)。2018 。事实上,元基因组也已经被用于监测藻华的不同阶段。2012 ,估算作物生产力(常等)。2017 )、土壤质量(维斯特加德等)。2017 、加斯陶等人。2019 、水质(毕比等)。2019 )等众多。
已经有一些机器学习方法用于宏基因组样本分型。一方面是来自阿斯加里等人的微音器。在从 16S rRNA 基因序列的浅层子采样获得的 k-mer 上使用深度神经网络(DNN)、随机森林(RF)和线性 SVM(as gari等)。2018 )。另一方面,Dhugnel 等人。开发了 MegaR 软件包,该软件包从全宏基因组测序或 16S rRNA 测序数据中选择关于宏基因组分类概况的广义线性模型(GLM)、SVM 或 RF(Dhungel等)。2021 )。
在本文中,我展示了我解决这个问题的方法。我把它变成一个多类文本分类问题。如 Dhungel 等人。,我使用宏基因组分类轮廓数据。我将简介视为文本,并使用词频-逆文档频率(TF-IDF)来突出重要的分类群,淡化那些过于世界性或过于罕见的分类群。然后 XGBoost 基于 TF-IDF 值构建模型。参数将首先通过网格搜索交叉验证进行优化。一旦模型被建立和测试,我使用 SHAP 来检查特征的重要性,这样我就可以知道哪个分类群代表哪个样本类型。这个项目的代码存放在我的 Github 仓库中:
https://github.com/dgg32/mgnify_sentiment
而 Jupyter 笔记本可以用 nbviewer 渲染。
https://nbviewer.jupyter.org/github/dgg32/mgnify_sentiment/blob/master/ebi_sentiment_multi_value.ipynb
1.从 MGnify 下载分类简介
MGnify 是一个研究网站,托管了全球科学家提交的大量元基因组。它还处理序列,并为我们提供下载的 API。首先,用我的脚本下载各种栖息地的分类资料,也就是样本类型。在这个演示中,我从以下类型下载了 JSON 数据:“生物反应器”、“淡水”、“宿主”、“海洋”、“沉积物”和“土壤”。在每个 JSON 中,都有一个分类单元列表(Woeseia、Geobacter 等),包括它们的分类等级(门、纲、科、属等)以及它们在样本中的出现次数。在这个项目中,我使用属作为词汇表。
之后,我将 JSON 文件扩展成“文本”,通过重复出现的每个分类单元,例如“埃希氏菌”。少于 20 个不同属的样品被排除在分析之外。这一过程在“沉积物”类型中产生了 462 个样本,在“宿主”类型中产生了 57,741 个样本(图 2。).

图二。本项目中每种样品的数量。图片作者。
2.读取、训练-测试-分割和 GridSearchCV
我用一个 Jupyter 笔记本开始。下面是数据导入、80:20 训练-测试-分割、Sklearn 管道和网格搜索交叉验证的代码。
在这种情况下,我从“土壤”、“沉积物”、“海洋”和“淡水”中导入数据。每种类型下都有相当数量的数据。此外,我认为它们是一个很好的挑战,因为这些栖息地在生理化学上相互重叠。例如,淡水和海水都含有水,沉积物和土壤都是固体基质。因此,可能有属可以存在于四种类型中的一种以上。该模型将学习属的组成,以便将四个分开。
TF-IDF 是一种在一组文档中选择和量化特征词的方法。在许多文档中出现频率过高的单词,如“the”、“a”和“an”等停用词,会被过滤掉,因为它们不会区分文档。对于生僻字也是如此。它有效地减少了词汇量。在文本分析中,这是一种简单而有效的方法。我“借用”TF-IDF 来过滤属。通过网格搜索,我确定 min_df 为 2,max_df 为 0.7,这意味着管道将忽略出现在少于两个样本中的所有属,但也会忽略出现在超过 70%的样本中的属。
网格搜索交叉验证可能需要很长时间才能完成,因为它需要交叉验证每个超参数组合五次。参数之间的差异有时并不显著。因此,明智地使用 GridSearchCV,并密切关注手表。在我的尝试中,我得到了一组参数作为回报。最佳模型的 CV 值为 0.98。
3.根据测试数据运行最佳模型
是时候使用测试数据上的最佳参数运行管道并评估结果了。
我的渠道返回非常高的 F1 分数。比较预测值和实际值,似乎“沉积物”类型的召回率相对较低(0.77),这可能是由于“沉积物”中的样本量低(总共只有 462 个),并且模型不能完全捕捉其特征。
4.用 SHAP 解释特性的重要性
模型建立后,我使用 SHAP 软件包来检查模型,以便了解哪些属代表哪些栖息地类型。本质上,SHAP 展示了 XGBoost 模型中特征的重要性。但是 SHAP 值比 XGBoost 中的“feature_importances”有几个优势,包括全局和局部的可解释性、一致性和准确性(在这里阅读更多)。但是 SHAP 确实需要一些繁重的计算。一个背景数据集为 300 的 SHAP 计算需要 5 秒多的时间。因此在这个项目中,我使用了 SHAP 自己的“kmeans”方法将训练数据总结为 300 个项目。我只生成了测试数据中前 100 个样本的 SHAP 值。
计算出 SHAP 值后,让我们快速浏览一下每个属对每个样本类型的贡献(图 3。和图 4。).

图 3。每个属对每个样本类型的平均 SHAP 值。作者图片。
图 3。显示出苔藓菌、白假丝酵母 Udaeobacter】、“白假丝酵母 Solibacter”和Chthoniobacter(Chthonius:生于希腊语中的土壤,也是卡德摩斯神话中一个斯巴达的名字)是对决策贡献最大的前四个属。为了了解它们到底是如何贡献的,我生成了蜂群图来显示它们在“土壤”和“海洋”类型中的 SHAP 值分布。

图 4。“土壤”和“海洋”分类中每个属的 SHAP 值分布。图片作者。
图 4。揭示了每个属的细节。每个点代表前 100 个测试样本中的一个,颜色表示该样本中行亏格的 TF-IDF 值。比如第一行是关于br iobacter。标尺高端的红点表明苔藓菌中的高 TF-IDF 值更有可能进行“土壤”分类。前四名中的其他三名也是如此。但是在硫磺单胞菌和 Hyphomonas丰富的地方,样本不太可能来自土壤,而更有可能来自海洋。奇怪的是盐囊菌似乎是土壤的指示,因为前两个菌株是嗜盐的,并且是从海洋沿海地区分离出来的( Iizuka 等人)。1998 年。
我们可以用一些“局部”案例来进一步证实这些“全局”观察。例如,下图显示了为什么模型将测试样本 19 输入为“土壤”。

图 5。测试样品 19 的决策。图片作者。
图 5。就是所谓的武力阴谋。它显示了每个属如何增加或减少每个类型的概率。例如,“ Candidatus Udaeobacter”的存在增加了“土壤”分类的概率,同时降低了所有其他类型的概率。
很明显,所有前四个属都存在于测试样品 19 中。它们的存在使该模型对“土壤”分类有 100%的置信度,而对其他三种分类则没有。同样明显的是,硫磺单胞菌和 Hyphomonas 的缺失使得“海洋”分类不太可能。
让我们验证“ Candidatus Udaeobacter”确实更有可能出现在测试样品的土壤中:

图 6。测试样本中四种生境类型中“念珠菌属 Udaeobacter”的 TF-IDF 分布。作者图片。
图 6。显示了“白念珠菌 Udaeobacter”的 TF-IDF 值在四种生境类型中的分布。该图表明,这种微生物在土壤中可达到高达 0.7 的 TF-IDF 值,而在其它土壤中低于 0.1。事实上,已知“白假丝酵母 Udaeobacter”是一种丰富且普遍存在的土壤细菌( Brewer et al )。2017 。
结论
上面这个简短的教程展示了我的宏基因组样本分型的文本分析方法。TF-IDF 简单而强大。它的价值有一个很容易理解的意义。与 MegaR 中许多令人困惑的数字规范化不同,TF-IDF 不仅量化,而且消除了世界性和稀有属,以便于以后的 XGBoost 建模。总的来说,TF-IDF 是一种很好的方法,可以让分类数据为建模做好准备。
XGBoost 是一个很棒的模型构建工具。它速度快,性能好。我的模型达到了 0.98 的加权平均精度。但是,本教程并不局限于 XGBoost。事实上,我鼓励你尝试 Lightgbm、Catboost 甚至神经网络。
SHAP 软件包是迈向可解释人工智能的一大步。它可以分解一个模型的决策,并突出每个栖息地类型的属指示。我们可以从文献中证实它的观察结果。在 Haliangium 的例子中,我们甚至可能发现一些属的新栖息地。
虽然这篇文章使用了 16S 的分类模式,但它也适用于从整个宏基因组或其他方式产生的模式。然而,这种对分类法的依赖也有其缺点。来自未知生物的序列不在此范围内,因为它们还没有分类学。此外,在某些情况下,为词汇表选择正确的分类级别也很棘手。当一些样本类型非常相似时,样本分型可能仅在物种甚至菌株的水平上起作用。例如,2011 年在德国爆发的 EHEC 是由一种 E 引起的。大肠杆菌菌株而大多数其他大肠杆菌。大肠杆菌是无害的,常见于我们的下肠道。在这种情况下,我们应该将词汇更改为应变级别,以便抓住差异。
现在,请尝试我的管道为您自己的宏基因组样本分型,并告诉我你对这个问题的看法。
https://dgg32.medium.com/membership
博鲁塔和 SHAP 为更好的功能选择
原文:https://towardsdatascience.com/boruta-and-shap-for-better-feature-selection-20ea97595f4a?source=collection_archive---------9-----------------------
不同特征选择技术的比较及其选择

克里斯汀·塔博瑞在 Unsplash 上的照片
当我们执行监督任务时,我们面临的问题是在我们的机器学习管道中加入适当的特征选择。简单地在网上搜索,我们可以访问各种各样的关于特征选择过程的资源和内容。
总之,有不同的方法来执行特征选择。文献中最著名的是基于过滤器的和基于包装器的技术。在基于过滤器的程序中,非监督算法或统计用于查询最重要的预测值。在基于包装器的方法中,监督学习算法被迭代拟合以排除不太重要的特征。
通常,基于包装器的方法是最有效的,因为它们可以提取特征之间的相关性和依赖性。另一方面,他们显示更容易过度适应。为了避免这种缺乏并利用基于包装器的技术的优点,我们需要做的就是采用一些简单而强大的技巧。我们可以通过一点数据理解和一个秘密成分来实现更好的特征选择。别担心,我们不用黑魔法而是用 SHAP 的力量。
为了在特性选择过程中更好地利用 SHAP 的能力,我们发布了shap-hype tune:*一个 python 包,用于同时进行超参数调整和特性选择。*它允许在为梯度推进模型定制的单个管道中组合特征选择和参数调整。它支持网格搜索或随机搜索,并提供基于包装器的特征选择算法,如**递归特征消除(RFE)、递归特征添加(RFA)、**或 Boruta 。进一步的添加包括使用 SHAP 重要性进行特征选择,而不是传统的基于原生树的特征重要性。
在本帖中,我们将展示正确执行功能选择的实用程序。如果我们高估了梯度增强的解释能力,或者仅仅是我们没有一个总体的数据理解,这就揭示了事情并不像预期的那么简单。我们的范围是检测各种特征选择技术的表现如何,以及为什么 SHAP 的使用会有所帮助。
博鲁塔是什么?
每个人都知道(或者很容易理解)一个递归特征消除是如何工作的。它递归地适合考虑较小特征集的监督算法。其中被排除的特征是根据一些权重的大小(例如,线性模型的系数或基于树的模型的特征重要性)被认为不太重要的特征。
Boruta 和 RFE 一样,是一种基于包装器的特征选择技术。它不太为人所知,但同样强大。Boruta 背后的想法真的很简单。给定一个表格数据集,我们迭代地将监督算法(通常是基于树的模型)应用于数据的扩展版本。在每次迭代中,扩展版本由原始数据和水平附加的混洗列的副本组成。我们只维护每个迭代中的特性:
- 比最好的混洗特征具有更高的重要性;
- 比随机机会(使用二项式分布)更好。
RFE 和博鲁塔都使用监督学习算法来提供特征重要性排名。这个模型是这两种技术的核心,因为它判断每个特征的好坏。这里可能会出现问题。决策树的标准特征重要性方法倾向于高估高频或高基数变量的重要性。对于博鲁塔和 RFE 来说,这可能导致错误的特征选择。
实验
我们从 Kaggle 收集数据集。我们选择一个银行客户数据集,试图预测客户是否很快会流失。在开始之前,我们向数据集添加一些由简单噪声产生的随机列。我们这样做是为了理解我们的模型是如何计算特征重要性的。我们开始拟合和调整我们的梯度推进(LGBM)。我们用不同的分裂种子重复这个过程不同的时间,以克服数据选择的随机性。平均特征重要性如下所示。

各种分裂试验的平均特征重要性[图片由作者提供]
令人惊讶的是,随机特征对我们的模型非常重要。另一个错误的假设是认为 CustomerId 是一个有用的预测器。这是客户的唯一标识符,被梯度推进错误地认为是重要的。
鉴于这些前提,让我们在数据上尝试一些特征选择技术。我们从 RFE 开始。我们将参数调整与特征选择过程相结合。如前所述,我们对不同的分裂种子重复整个过程,以减轻数据选择的随机性。对于每个试验,我们考虑标准的基于树的特征重要性和 SHAP 重要性来存储所选择的特征。通过这种方式,我们可以画出在试验结束时一个特征被选择了多少次。

用 RFE(左)选择一个特征的次数;用 RFE + SHAP(右)选了多少次特写[图片由作者提供]
在我们的案例中,具有标准重要性的 RFE 显得不准确。它通常选择与 CustomerId 相关的随机预测值。 SHAP + RFE 最好不要选择无用的功能,但同时也要承认一些错误的选择。
作为最后一步,我们重复相同的程序,但是使用 Boruta。

用 Boruta 选择一个特征的次数(左);用博鲁塔+ SHAP(右)选了多少次特征[图片由作者提供]
标准的 Boruta 在不考虑随机变量和 CustomerId 方面做得很好。SHAP +博鲁塔似乎也做得更好,减少了选择过程中的差异。
摘要
在这篇文章中,我们介绍了 RFE 和博鲁塔(来自 shap-hypetune )这两个有价值的特性选择包装器方法。此外,我们用 SHAP 代替了特征重要性的计算。 SHAP 帮助减轻了选择高频或高基数变量的影响。总之,当我们有一个完整的数据理解时,RFE 可以单独使用。博鲁塔和 SHAP 可以消除对经过适当验证的选拔过程的任何疑虑。
如果你对题目感兴趣,我建议:
- SHAP 用于特征选择和超参数调谐
- 递归特征选择:增加还是消除?
- T21【博鲁塔】SHAP 为时态特征选择
- 漂移检测 SHAP:有效的数据漂移监控
查看我的 GITHUB 回购
保持联系: Linkedin
波士顿 Airbnb 业务分析和挂牌价格预测
原文:https://towardsdatascience.com/boston-airbnb-business-analysis-and-listing-price-prediction-980d409a0482?source=collection_archive---------27-----------------------
简介
答 irbnb 是一个在线市场,它安排并提供人们可以临时居住的房间或房屋。该公司只是一个连接租户和业主的经纪人,然后从每笔预订中获得佣金。无论你是主人还是客人,对业务有一个知情的决定是很重要的,并决定何时将你的房产挂牌出租,或以可承受的价格参观城市。我在这里分析了波士顿的业务是如何增长的,并提出了一个模型来预测给定上市的价格。完整的笔记本和代码可以在我的 GitHub 上找到。

https://unsplash.com/photos/iRKv_XiN-M
我的分析将集中在 2008 年至 2016 年收集的 Airbnb 数据。该数据集有 3585 个列表,95 个特征描述了业务的不同方面。原始数据集可以从 Kaggle 下载。
下面描述的分析只是基于我的观察,并不是真正的专家对如何开展业务的观点。我将尝试回答以下问题:
1-波士顿的 Airbnb 业务发展如何?
2-最受欢迎的社区是什么?是什么让他们受欢迎?
3-公司最忙的时候是什么时候?
4-影响波士顿 Airbnb 价格的特征是什么?我们可以根据预测模型预测新房源的租赁价格吗?
第一部分:波士顿的 Airbnb 业务发展如何?

作者的情节
正如我们在上面的*图 1* 中看到的,这项业务始于 2008 年,几乎没有上市,但多年来持续增长,仅在 2015 年就达到 1000 多家上市公司。2016 年的下降只是因为数据是在年底前收集的。
我们还提供了 2016 年和 2017 年的上市信息。我们看到,从 2016 年到 2017 年,可供预订的房源数量翻了一番,如下图*图 2* 所示。

作者的情节
第二部分:什么是最受欢迎的社区?是什么让他们受欢迎?
数据集中有 25 个不同的社区,下面是社区的列表数量和平均价格的分布。

邻域排名-由作者绘制
就上市数量而言,我们看到牙买加平原、南端、后湾、芬威、多切斯特、奥尔斯顿是最受欢迎的,每个城市都有超过 250 个上市项目。南波士顿海滨、海湾村、皮革区、后湾、市中心、唐人街挂牌均价较高。房源较少的小区,挂牌均价似乎较高。

作者的情节
正如我们在*图 5 中看到的。*如上图,这些年来,所有社区的收入都在增长。我们还注意到,列表数量越多的社区收入越多。
第三部分:生意最忙的时候是什么时候?
对于计划游览这座城市的人来说,了解什么时候是最忙的季节,什么时候是最忙的日子,以便做出相应的计划是很重要的。

图 7:按季节和星期列出可用性分布——按作者绘图
正如我们在上面的图 7 中看到的,最繁忙的季节是春季和夏季。我们看到,一周中的所有日子都有几乎相同的趋势,但周三的预订略有增加。毫无疑问,冬季是活动最少的最慢季节,因为波士顿会变得非常寒冷并下雪。有趣的是,在秋季,周三和周四似乎比一周中的其他日子更繁忙。秋天周末其实活动比较少。
第三部分:波士顿 Airbnb 中影响价格的特性有哪些?我们可以根据预测模型预测新房源的租赁价格吗?
在进入建模部分之前,我们将调查价格分布,然后检查可能影响价格的缺失值和异常值的存在。

作者的情节
上图 8 显示了按物业类型和房间类型划分的价格分布。与私人房间和共享房间相比,整个房间/公寓的平均价格在所有类型的房产中都较高。
然而,我们注意到异常值的存在,这些异常值是矩形以外的点。为了保持预测的一致性,我们将去掉这些极值。准确地说,我们将删除所有大于平均值 2 个标准偏差的数据点和小于平均值 2 个标准偏差的值。去除异常值后,*图 9* 显示了不同房间类型的整体价格范围。

作者的情节
我们可以看到有少量价值低于 200 美元的共享房间。包房和整个家/公寓代表了生意的核心,价格在不同的区间。
影响价格的前 15 个数字列
以下是对标价影响较大的前 15 列:
['accommodates', 'cleaning_fee', 'bedrooms', 'beds',
'host_listings_count', 'host_total_listings_count',
'calculated_host_listings_count', 'guests_included',
'review_scores_location', 'availability_30', 'host_acceptance_rate',
'bathrooms', 'availability_60', 'availability_90',
'review_scores_cleanliness']
影响价格的顶级分类列
['neighbourhood_cleansed',
'property_type',
'room_type',
'bed_type',
'cancellation_policy',
'host_is_superhost',
'instant_bookable',
'is_location_exact',
'require_guest_phone_verification',
'require_guest_profile_picture']

作者的情节
除了上面的数字特征和分类特征之外,我们还处理了市容列,这将在一次性编码后向我们的数据集添加 45 列。最后,我们将用来预测价格的最终数据集有 3494 行和 89 列。
上图(图 10 和图 11 )显示了预测价格和实际价格之间的相关性。我们看到预测价格和真实价格之间有很好的相关性。
预测后,R _ sqauared(这是数据与拟合回归线接近程度的统计度量。它也被称为决定系数,或多元回归的多重决定系数。)在训练数据上是 0.69,在测试数据上是 0.701。这表明我们可以很有把握地预测上市价格。
评估结果
我们仅通过挑选与价格密切相关的前 15 个数值变量、前 20 个分类变量就取得了上述结果。
为了改善我们的结果,我们设置了一个网格,并运行我们的算法来搜索导致最佳结果的特征集。我们发现,使用 23 个数值变量,45 个分类变量,我们在测试数据上获得了 0.704 的*R_sqauared*,与我们的原始结果相比,这并不是一个很大的改进。
我们已经使用上面找到的最佳特征尝试了随机森林回归器,并且在训练数据上获得了*R_sqauared* 0.95,在测试数据上获得了 0.73,这并不是比较两个分数之间方差的更好分数。
结论
在这篇博客中,我们分析了波士顿市的 Airbnb 数据,并回答了一些商业问题,这些问题可以让主人和客人就何时发布房源或何时游览这座城市做出明智的决定。
我们使用了一些功能来预测给定列表的标价。尽管我们的结果相当显著,但仍有改进的空间,可以处理一些栏目,如评论(来自客人的评论)、帖子的摘要、d 描述、邻居概述、房屋规则。
波士顿动力学:研究运动智能
杂技舞蹈视频华而不实,但有哪些实际的技术突破?韩国机器人产业正在发生什么?
这家机器人公司擅长制作病毒式技术视频,展示机器人能做的件小事、跑酷、欺凌、机器人,以及更多。波士顿动力公司的一个核心原则是运动智能的理念——强健、灵活,甚至可能是人类的运动模式。这些视频和技术已经到了最受欢迎的技术艺人得到一份拷贝并评论它的地步,它们是待售的,并且是可访问的。最近的视频试图展示一种新的人类运动方式(下图)。
他们对运动智能的关注真的帮助我了解了这家公司,它在哪里适合他们的视频,以及为什么老板不留下来。波士顿动力公司使用机器学习和人工智能作为工程堆栈中的工具,而不是将其扔向他们遇到的每个子问题。
在本帖中,我们:
- 理清波士顿动力公司的历史(它不是政府承包商),
- 展示他们所谓的突破 竞技智能 ,
- 和讨论现代子公司的下一步计划。
什么是波士顿动力
Boston Dynamics 在 2014 年放弃了所有 DARPA 的合同(它们是由 DARPA 种子基金启动的,但我们使用的大量 技术是!)他们有着有点复杂的买家和卖家历史,包括谷歌、软银和现在的现代——我认为这主要是他们的长期目标和市场的短期价值之间的脱节。波士顿动力公司的长期目标是创建一个运动智能的演示,并将其出售给能够解决其他认知问题(规划、后勤、互动)的人。
运动智能的目标是使机器人学中鲁棒性和速度的结合成为可能。如果这对你来说没有什么印象,看看一些历史上最好的机器人团队参赛的例子。

来源——波士顿动力博客。
我经常听到(我也延续了这种想法的一部分)他们的技术部分是由军事应用资助的,完全是为军事应用设计的。虽然他们的机器人在自己的环境中似乎很健壮,但他们并没有满足 21 世纪相反战争的许多趋势:远程、隐形和受损时的健壮(他们的机器人很吵——那些大型液压致动器不会偷偷靠近你!).要了解完整的历史,请查看维基百科、他们的关于页面,另一篇更长的历史文章,或者波士顿报纸 Raibert 的更多个人评论。
总而言之,他们一直专注于通过联合开发硬件和软件能力来推动腿式运动极限的目标。他们一直在纠结如何将这种进步货币化。
运动智能与机器智能
在这一部分,我将重点介绍他们的神奇是如何发生的。他们所做的硬件开发是一流的,但是机器智能中的 部分有可能扩展到更多的平台,所以我关注它。简而言之,与机器人研究的状态相比,他们的学习和控制基础设施不是革命性的,但它是发达的和高度功能化的。让我们期待波士顿动力公司的未来,他们的控制方法不要太依赖于他们的硬件平台,他们可以重复控制工程。
广义而言,运动智能首先需要发展低水平的控制能力和运动灵活性。这种灵活的机器人运动是公司价值的核心。他们研究如何优化液压等机械部件,以提高控制性能。他们精确集成所需的传感器(激光雷达、电机编码器、IMU 等。)来解决任务和许多不同的计算。
在 NeurIPs 2020 真实世界 RL 研讨会上,他们展示了他们的高水平方法(视频此处)。关于控制方法的幻灯片总结了他们的工具集:基于模型、预计算和细致的工程设计(这是研究实验室所缺少的)。
[ 将链接到我正在引用的幻灯片]
基于模型的
所有的模型都是错的,但有些是有用的【乔治盒子这里是他们幻灯片的主旨。
事实上,这是一种有趣的相互作用,因为他们可以非常详细地模拟他们机器人的某些方面(例如,一种类型的液压致动器),但当他们开始将碎片放在一起时,累积的模型有缺口——并且不可能知道确切的位置。
模型也是一个很好的工具,人类将参与其中(可以解释结果),但没有法律说基于模型的方法更有效。他们将它与幻灯片上的第二点紧密结合。
导航预行计算
基于模型的是配对、预计算,它们共同构成了模拟的工具。模拟是机器人技术的未来(比运行硬件实验要便宜得多,尤其是在流行病中),他们似乎已经充分利用了这一点。
现实世界 RL 研讨会上的对话强调了他们利用模型预测控制(MPC)的程度,这是目前已知的计算量最大的控制方法之一。不过,最近的工作已经转向离线求解 MPC,然后在线运行一个更简单的版本(他们没有证实这一点,但答案至少指向概念上类似的东西)。在实践中,这变成了:从真实的机器人试验中收集大量状态,然后离线求解每个可能状态下的最优动作,并运行读取这些动作的控制器(非常快)。
严格记录
他们在这里用数据驱动来表示一种不同的东西,“数据不会说谎”,这其实在 EE 和 ME 圈子里要常见得多(深度学习前的炒作,啾啾)。
我认为 RL 的许多领域可以从分析每一次试验中到底发生了什么中学到更多。知道代理是错的是一回事,但是弄清楚为什么它是错的以及错误如何随着时间传播是非常重要的。波士顿动力首先不是一家机器学习公司,这与他们的方法相匹配。
让新的机器人跳舞
值得说明的是,他们如何使用动作捕捉、模仿学习和丰富的模拟来制作他们最近的视频。为了更详细地阐述下图中的内容,他们让人类演员在录制环境中创建运动原语(或在物理模拟器中指定运动,这看起来不是很运动),使用模仿学习的技术来生成与运动匹配的策略,然后正确设置模拟器,以便新策略可以轻松地转移到机器人。
[行为生成幻灯片
出自 IEEE 谱:
最终,我们能够利用这个工具链在一天之内,也就是我们拍摄的前一天,创作出 Atlas 的一个芭蕾动作,并且成功了。所以这不是手写脚本或手写代码,而是有一个管道,让你可以采取一系列不同的运动,你可以通过各种不同的输入来描述,并推动它们通过机器人。
对于更大的图景,我只有一个想法:针对特定的行业约定,客户想要的预编程动作。你希望你的机器人能够拾取特定尺寸的包裹——让我们看看我们能否验证这个动作并更新你的机器人。有一个框架,设计者对输出足够有信心,他们可以通过软件更新来发布它,这听起来很像为什么这么多人喜欢他们的 Teslas(硬件上的软件更新实际上并不存在)。
他们在这些运动上投入了大量的工程时间。更值得思考的是更大的图片动机是什么(它不可能只是视频)。如果他们试图以任何人机交互的形式销售机器人,一套更丰富的动作可能非常有价值,但迄今为止没有任何迹象表明这一点。人类风格的舞蹈很可能会推动一个包的极限,也许是他们在 2 月 2 日宣布的新包。
艺术重点和恐怖谷
让机器人看起来像人类是一件值得警惕的事情。当然,人类的运动是动态的、优雅的、非常高效的,但这并不意味着它在不同的致动器下总是最优的。人类风格也会带来巨大的文化包袱和意想不到的影响。
这并不是说我反对具有人类功能的机器人——社会是围绕具有我们的腿和身高的生物构建的,这些生物可以轻松地在建筑物中导航并解决日常任务。我建议并希望机器人能够模仿人类的运动模式(比如使用两条腿,或者拥有带手和腕关节的手臂),但不以完全模仿为目标。
如果你对此感到好奇,请阅读我在恐怖谷的文章。

照片由 Unsplash 提供。
利用更多的学习
有学习机会的 滑梯 正在点上。持续学习、模型精度改进、基于学习的硬件优化和工程协助都是当今学习可以帮助解决的问题。
- 持续学习非常适合无模型学习——这是一个旨在从稀疏回报中学习的系统,没有转移到其他任务的目标。
- 现实世界中的模型精度归结为将数据拟合到扰动,或者他们已经优化以获得初始敏捷性的动力学模型与来自机载传感器的观测值之间的差异。模拟和物理来获得初始模型、数据,以及机器学习来更新它以匹配最近的现实。
- 用 ML 进行硬件优化:人类真的不擅长拟合多目标函数。当你在制造物理设备时,成本会随着材料和时间的增加而增加,让机器为你做这件事(我正在做的事情)。
- 工科出身。我喜欢他们的术语,我认为这只是填补裂缝的可以这么说,也是对学习可以有用的认可,即使对一家如此注重实际交付成果的公司来说。
波士顿(现代)动力公司的下一步是什么?
南韩有一套 文化价值观使得机器人代理在社会多个领域的扩散时机成熟。一份对来自国际机器人联合会的报告(我知道,双重引用,令人痛苦,但做机器人行业研究也是如此——这都是隐藏的)的分析得出结论:
韩国是世界上自动化程度最高的国家。
韩国精神&机器人
更有趣的是,正如一位韩国工程师声称 s:
任何一种非人类都可能有超越人类能力的精神或超能力。
这只是一种观点,但历史指向一套对其他存在更开放、更乐观的价值观。这种感觉肯定是基于动物的,但一小部分转化为机器人可以实质性地重构社会。
现代韩国的第一位国王丹根(Dangun)的故事,以及韩国对动物和潜在的非人类灵性生物的喜爱是奇妙的:
一只老虎和一只熊向万隆祈祷,希望他们能变成人类。听到他们的祈祷,万隆给了他们二十瓣大蒜和一捆艾蒿,命令他们只吃这种神圣的食物,并且在 100 天内不要晒太阳。大约二十天后,老虎放弃了,离开了山洞。然而,熊坚持下来了,被变成了一个女人。据说熊和老虎代表了两个寻求天帝恩宠的部落。
The bear-woman (Ungnyeo; 웅녀/ Hanja: 熊女) was grateful and made offerings to Hwanung. However, she lacked a husband, and soon became sad and prayed beneath a “divine birch” tree (Korean: 신단수; Hanja: 神檀樹; RR: shindansu) to be blessed with a child. Hwanung, moved by her prayers, took her for his wife and soon she gave birth to a son named Dangun Wanggeom.
由此,韩国对非人类生物以及它们所能带来的价值有了更多的开放。这是一个多么伟大的变化——美国人无法摆脱社交媒体监管的泥潭,并认为他们的发言者在听。
韩国实用性和机器人
Hyuandai 最近收购了 Boston Dynamics (来自《The Verge】)和《彭博》显示该公司并未持续盈利。重复销售和低盈利对一个公司来说不是一个好兆头(也许加入软银的基金对公司来说是一个坏兆头),那么下一步是什么呢?
那么现代为什么要买它们呢?使用机器人进行生产。这是一个大转变,我认为大多数人都没有预见到(浮华、敏捷的机器人乍一看最适合高端消费者和利基产品)。现代重型机械在 2020 年进入市场销售多种机器人,他们自称韩国头号机器人制造商。一个重要的背景是,韩国已经拥有了高密度的工业机器人(见关于韩国机器人产业的背景)。
波士顿动力公司在 Spot 和 Atlas 中创造的运动原型真的是人们可以建立的东西。制造业中的运动智能转化为强壮,这是非常有价值的。它只是没有敏捷性那么令人兴奋。
新产品
*2 月 2 日有一个新的产品线公告扩展 Spot 的产品。我预计这将是硬件的变体(想想不同的手臂附件,而不仅仅是视频中展示的单臂)和不同的软件包,可以解决探索或更复杂的运动挑战等任务。*
在采访和产品中,波士顿动力公司看起来更像是一个研究实验室,在推动腿式运动的软硬件协同设计的极限。我喜欢他们为这个领域所做的工作,但实际上,我希望在几年内有更多的盈利,也许随着他们成为一个行业研究实验室,宣传会更少。

斑点在这种冰里会怎么样?来源—作者。
包装
波士顿动力公司是一家推动机器人领域发展和投资的重要公司。不过,我不会投资它们,这没关系。作为一名运动员,我被他们关于运动智能的理想所吸引,但作为一名研究人员,我真的对实用智能更感兴趣。如果机器人不能捡起一个新的物体或制作咖啡,那么它是否能跑酷就无关紧要了。希望现代公司为他们闪亮的新研究机构增加一个翻译部门。
我也在考虑把这个博客重新命名为更时髦的东西。主题不会改变,但它可能有助于增长。如果你有任何意见,请告诉我。
这个原本出现在我的自由子栈 民主化自动化 。请查看或关注我的 推特 !
用于浓缩咖啡的无底 vs 喷动移动式过滤器
原文:https://towardsdatascience.com/bottomless-vs-spouted-portafilter-for-espresso-dfcce8a461d5?source=collection_archive---------8-----------------------
咖啡数据科学
一个好的理由去无底的高峰
几年前我去了一家无底 portafilter ,从此一去不返。我把所有的机器都换成了无底的 portafilter,只有一台除外;La Peppina 脱衣服更有挑战性。深不见底的 portafilter 非常需要能够实时看到浓缩咖啡的发展,所以我想给出两个镜头的比较,以显示味道和提取的差异。
这是底部的样子。


左:原金 Expresso Portafilter,右:无底与 Pesado 精密篮子。所有图片由作者提供。
每一个镜头都是在 Kim Express 上用一个 Pesado 精密过滤器篮拍摄的。咖啡是同样的烘焙,而且是在同样的韩国研磨机上研磨的。
喷动移动式过滤器






无底移动式过滤器






从冰球投篮的角度来看,差异很小:


左:喷出,右:无底
绩效指标
我使用两个指标来评估技术之间的差异:最终得分和咖啡萃取。
最终得分 是评分卡上 7 个指标(辛辣、浓郁、糖浆、甜味、酸味、苦味和回味)的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难确定。
使用折射仪测量总溶解固体量(TDS),该数字结合咖啡的输出重量和输入重量,用于确定提取到杯中的咖啡的百分比,称为提取率(EY)** 。**
表演
对于口味来说,无底的 portafilter 是一个明显的赢家,对于任何想改善他们的浓缩咖啡的人来说,这是一个真正的游戏改变者。这是因为镜头的一些部分停留在移动式过滤器上,我还怀疑一个喷动的移动式过滤器可能会导致流动的一些变化。用玻璃或透明塑料过滤器来检验这种效果是很有趣的。最大的改进是甜味、酸味、苦味和回味。
****
就 EY 而言,它们非常相似,所以我很好奇是什么机制导致了味道的差异。
时差更难看出。所以我把时间量到 1g,时间量到 10ml。这些在无底的地方发生得更快,可能是因为在总时间相同的情况下,液体的移动距离更短。

无底移动式过滤器的两个优点是:
- 人们可以在拍摄过程中看到结果并进行调整。
- 移动式过滤器影响味道。
我强烈推荐那些对提升他们的咖啡体验感兴趣的人去无底咖啡吧。
如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以关注我中和订阅。
我的进一步阅读:
浓缩咖啡系列文章
工作和学校故事集
个人故事和关注点
乐高故事启动页面
摄影飞溅页
使用图像处理测量咖啡研磨颗粒分布
改善浓缩咖啡
断奏生活方式概述
测量咖啡研磨分布
咖啡萃取
咖啡烘焙
咖啡豆
浓缩咖啡用纸质过滤器
浓缩咖啡篮及相关主题
意式咖啡观点
透明 Portafilter 实验
杠杆机维护
咖啡评论和想法
咖啡实验
限制机器学习算法的样本大小
原文:https://towardsdatascience.com/bounding-the-sample-size-of-a-machine-learning-algorithm-d01d4775263c?source=collection_archive---------32-----------------------
限制机器学习算法的样本大小非常有帮助。请继续阅读,找出方法。

米卡·鲍梅斯特在 Unsplash 上的照片
机器学习算法的一个常见问题是,我们不知道我们需要多少训练数据。解决这个问题的一个常见方法是经常使用的策略:保持训练,直到训练误差停止减小。然而,这仍然存在问题。我们怎么知道我们没有陷入局部最小值?如果训练误差有奇怪的行为,有时在训练迭代中保持平稳,但有时急剧下降,该怎么办?底线是,如果没有一种精确的方法来知道我们需要多少训练数据,那么我们是否完成了训练总是有一些不确定性。
然而,在某些问题中,实际上有可能从数学上确定我们需要多少训练数据。想法是这样的:我们有两个参数ε和 1 — δ。这些参数分别代表我们期望的测试集误差和我们期望的达到该测试集误差的概率。有了这两个参数,我们的目标是找到 m,达到这两个参数所需的最小样本数(训练数据)。例如,假设我们有ε = 0.05,δ = 0.1(所以 1 — δ = 0.9)。然后,我们的目标是找到最小数量的样本 m,这样我们的学习算法有 90%的机会在测试集上实现小于 5%的误差。
让我们来看一个具体的问题,看看这种方法是如何使用的。我们的两个自变量是 SAT 成绩和 GPA。我们的目标是用这两个变量来预测一个人是否是普通学生。我们把普通学生定义为 SAT 成绩和 GPA 都在中等水平的人。图形上,我们可以把 SAT 成绩放在 x 轴上,GPA 放在 y 轴上。所以下图中的矩形代表的是一个“一般学生”。长方形里面的每个人都是普通学生,外面的每个人都不是。我们学习算法的目标是计算出这个矩形的大小和位置。

蓝点是一般学生。黑点不是。蓝色矩形代表平均水平学生的界限。图片作者。
接下来的事情是定义我们的学习算法。我们得到了一个样本(SAT 分数,GPA)对,以及每一对是否是一个普通学生。我们的算法是这样工作的:取所有被标记为平均值的配对,然后画出适合这些配对的最小矩形。这个算法更容易用图片来表示:

绿点是我们的样本。我们的算法在样本中平均的点周围画出最小的矩形。图片作者。
现在让我们考虑一下这个算法是如何依赖于样本大小的。样本量越大,样本中代表的蓝色矩形(真实的平均学生临界值)就越多。因此,绿色矩形将覆盖更多的蓝色矩形。换句话说,样本量越大,误差越小,这是意料之中的。我们的目标是根据ε和δ明确定义这种关系。
首先,我们确定一个ε。回想一下,ε是我们希望达到的误差——我们希望误差不超过ε(更低也是可以接受的)。接下来,我们将构建一个ε可以实现的场景,并找出该场景的概率。考虑从蓝色矩形的四个边“生长”矩形。这四个新矩形的概率质量为ε/4。我们可以在图表上用 A、B、C 和 d 来表示它们。

每个红色矩形的概率质量为ε/4。图片作者。
首先,请注意,如果误差>ε,样本在至少一个矩形中一定没有点。这是因为如果样本在所有矩形中都有一个点,误差最多为ε,因为我们构建了四个矩形,使其最大组合概率质量为ε。

四个红色矩形中都有点的样本。因此,最大可能误差小于ε。图片作者。
所以 p(误差>ε) < P(sample has no point in at least 1 rectangle). There are 4 rectangles, so we have P(sample has no point in at least 1 rectangle) < P(sample has no point in A) + P(sample has no point in B) + P(sample has no point in C) + P(sample has no point in D) = 4* P(sample has no point in A) by symmetry, as we set all rectangles to have the same probability mass ε/4. Because our sample size is m, P(sample has no point in A) = (1 — ε/4)^m. Putting it all together, we have P(Error > ε) < 4(1 — ε/4)^m. Thus, given an arbitrary error ε, if we want to upper bound the probability of that error occurring with δ, we set δ > 4(1 — ε/4)m.剩下的就是求解 m 得到 m > ln(δ/4) / ln(1 — ε/4)。我们可以用不等式(1 — x) < e(-x) to simplify the expression to m > (4/ε)ln(4/δ) 。我们已经实现了根据ε和δ限制样本大小 m 的目标。
像这样的绑定非常有用。我们可以直接计算出要达到某个误差的某个概率需要多少样本。例如,如果我们希望有 99%的概率得到 1%的更好的误差,我们需要(4/0.01)ln(4/0.01) = 2397 个训练样本。如果我们能够为所有机器学习算法计算出这样的界限,生活将会变得容易得多。不幸的是,其他机器学习算法比我们的矩形算法更复杂,因此数学分析可能很难处理。其他时候,可能会找到一个界限,但这个界限可能太高,以至于在功能上没有用。然而,我相信机器学习理论的进步最终将为大多数机器学习算法提供有用的界限。
在本文中,我们根据ε和δ推导了一个简单学习问题的样本大小界限。如果你对这个分析机器学习算法的通用框架感兴趣,可以去看看我写的关于 PAC 学习的文章。如果你有任何问题/评论,请告诉我,感谢你的阅读!
Box-Cox 变换是我们需要的魔法
原文:https://towardsdatascience.com/box-cox-transformation-is-the-magic-we-need-3d0ef9a18339?source=collection_archive---------16-----------------------
选择正确型号的聪明绝招

马修·施瓦茨在 Unsplash 上的照片
在进行统计分析时,我们通常希望得到正态分布的数据。这是因为事实上绝大多数的统计检验只有当我们在正态分布的数据点上使用它们时才是可解释的。
但是,如果我们的数据是非正态的,我们可能希望调查原因并执行相关的转换,以获得大致的正态分布。实现这一点的最流行的方法之一是 Box-Cox 变换。
什么是数据转换?
转换数据意味着对数据集的每个部分执行相同的数据操作。我们可以区分两组主要的变换:线性和非线性。
当我们的数据简单地除以或乘以某个常数,或者从我们的数据集中添加这样的常数或底物时,就会发生线性变换。因此,线性变换后,我们无法观察到数据分布的变化,我们的数据看起来不会比以前更正常。

线性模型。图片来自 https://en.wikipedia.org/wiki/Linear_regression
非线性变换可能更复杂。我们希望改变数据分布的形状,而不是基本的数学运算。它通常涉及对数、指数等的使用。其中一个例子是对数线性模型,它可以解释为简单线性模型变量的对数:

您可以在我之前的文章中找到关于这个模型的更多细节:
博克斯-考克斯方法
这种转变背后的故事被视为一个神话。据说,统计学家乔治·博克斯和大卫·考克斯爵士在威斯康辛州见过一次面,他们得出结论说,他们必须一起写一篇科学论文,因为他们的名字很相似,而且他们都是英国人。不管这个故事的真实性如何,最终,他们合作并在 1964 年发表的一篇论文中提出了他们的转变,并签上了他们的名字。

乔治·博克斯。图片来自https://en.wikipedia.org/wiki/George_E._P._Box
Box-Cox 变换是一种非线性变换,允许我们在线性和对数线性模型之间进行选择。通过这个操作,我们可以概括我们的模型,并在必要时选择一个变量。转换公式定义如下:

λ参数通常在-5 到 5 之间变化。考虑整个范围的值,并选择最适合我们数据集的值。
例如,当我们用 1 代替λ时,我们得到:

另一方面,当我们用-1 代替λ时,我们得到:

当 lambda 等于 0 时,最困难的部分是计算,因为我们剩下一个不确定的值。函数极限看起来像这样:

我们得到不定形式。在这种情况下,采用德累斯顿法则并用λ来区分是可行的:


大卫·考克斯爵士。图片来自https://en . Wikipedia . org/wiki/David _ Cox _(统计师)
我们什么时候可以使用它?
所描述的变换经常用于因变量和单个自变量的建模。在这种情况下,我们得到了 Box-Cox 模型:

“所有的模型都是错的,但有些是有用的。”—乔治·博克斯
同样,对于等于 1 的λ,该模型可以被解释为简单的线性模型:


对于等于-1 的λ,我们获得变量倒数的线性模型:


最后,对于等于 0 的λ,我们有一个对数线性模型:

正如你可能看到的,当我们用λ参数估计 Box-Cox 模型时,我们可以假设哪种函数形式最适合我们的数据。如果我们的λ参数接近 0,我们应该使用对数线性模型。当λ接近 1 时,我们应该使用简单的线性模型,而当λ接近-1 时,最合适的模型将是处理变量反演的模型。
我们必须记住,即使 Box-Cox 模型的个别情况是线性的,一般模型也有非线性的性质。因此,在大多数统计软件中,它通常是用数字来估计的。
参考
[1]麦切尔斯基,耶日。 *Ekonometria。*2009 年,UW WNE
[2]https://en.m.wikipedia.org/wiki/L%27H%C3%B4pital%27s_rule
[3]https://www.statisticshowto.com/box-cox-transformation/
https://en.wikipedia.org/wiki/Power_transform
男孩还是女孩?一个机器学习的网络应用程序从名字中检测性别
原文:https://towardsdatascience.com/boy-or-girl-a-machine-learning-web-app-to-detect-gender-from-name-16dc0331716c?source=collection_archive---------10-----------------------
在 Tensorflow、Plotly Dash 和 Heroku 中使用自然语言处理找出一个名字的可能性别。

照片由戴尼斯·格雷夫里斯在 Unsplash 上拍摄
作为初为人父者,给孩子取名字是你必须做出的最有压力的决定之一。特别是对于像我这样一个数据驱动的人来说,在没有任何关于我孩子性格和偏好的数据的情况下,就必须决定一个名字,这简直是一场噩梦!
由于我的名字以“玛丽”开头,我经历了无数次人们通过电子邮件和短信称呼我为“小姐”的经历,但当我们最终见面或交谈时,才失望地意识到我实际上是一个男人😜。所以,当我和妻子为我们的小女儿取名时,我们问自己一个重要的问题:
人们能够识别出这个名字指的是一个女孩而不是一个男孩吗?****
事实证明,我们可以使用机器学习来帮助我们检查潜在的名字是否会更多地与男孩或女孩联系在一起!要查看我为此开发的应用程序,请前往https://www . boyorgirl . XYZ。

“boyorgirl”应用的 Gif 视频。作者图片
这篇文章的其余部分将讨论技术细节,包括
- 获得性别训练数据集的名称
- 预处理名称,使其与机器学习(ML)模型兼容
- 开发一个自然语言处理(NLP) ML 模型,读入一个名字并输出是男孩还是女孩的名字
- 构建一个简单的 web 应用程序,供人们与模型进行交互
- 在互联网上发布应用程序
解决方案的架构

应用程序架构。作者图片
获取性别培训数据集的名称
为了训练任何机器学习模型,我们需要大量的标记数据。在这种情况下,我们需要大量的姓名以及该姓名的相关性别。幸运的是,谷歌云的 Bigquery 有一个名为USA_NAMES [ Link 的免费开放数据集,它“包含了在美国出生的所有社会保障卡申请人的姓名。”数据集包含大约 35000 个名字和相关的性别,这对于我们的模型来说非常好。

数据集片段。作者图片
数据预处理
人名是文本数据,而 ML 模型只能处理数字数据。为了将我们的文本转换成数字表示,我们将执行以下步骤。

名称编码。作者图片
- 小写的名字,因为每个字符的大小写不传达任何关于一个人的性别的信息。
- 拆分每个字符:我们正在构建的 ML 模型的基本思想是读取名称中的字符,以识别可能表明男性或女性特征的模式。因此,我们把名字分成每个字符。
- 用空格填充名称,直到最多 50 个字符,以确保 ML 模型看到所有名称的长度相同。
- 将每个字符编码成一个唯一的数字,因为 ML 模型只能处理数字。在这种情况下,我们将' '(空格)编码为 0,' a '编码为 1,' b '编码为 2,依此类推。
- 将每个性别编码成一个唯一的数字,因为 ML 模型只能处理数字。在这种情况下,我们将‘F’编码为 0,将‘M’编码为 1。

预处理后的数据集片段。作者图片
NLP ML 模型
当我们读一个名字时,我们通过这个名字中出现的字符的顺序来识别这个名字的可能性别。例如,“斯蒂芬”很可能是一个男孩的名字,但“斯蒂芬妮”很可能是一个女孩的名字。为了模仿人类识别姓名性别的方式,我们使用tensorflow.keras API 构建了一个简单的双向 LSTM 模型。
模型架构
- 嵌入层:将每个输入字符的编码数字“嵌入”到一个密集的 256 维向量中。选择
embedding_dim是一个超参数,可以调整以获得所需的精度。 - 双向 LSTM 层:从上一步中读取字符嵌入序列,并输出一个表示该序列的向量。
units和dropouts的值也是超参数。 - 最终的密集层:输出一个接近 0 的 F 值或接近 1 的 M 值,因为这是我们在预处理步骤中使用的编码。
训练模型
我们将使用标准的tensorflow.keras培训渠道,如下所示
- 使用我们在模型架构步骤中编写的函数实例化模型。
- 将数据分成 80%的训练和 20%的验证。
- 一旦模型开始过度拟合,使用
EarlyStopping回调调用model.fit停止训练。 - 保存训练好的模型,以便在服务 web 应用程序时重复使用。
- 绘制训练和验证精度图,以直观检查模型性能。

训练精度。作者图片
Web 应用程序
既然我们已经有了训练有素的模型,我们可以创建一个 Plotly Dash [ Link ] web 应用程序[https://www . boyorgirl . XYZ]来从用户那里获取输入姓名,加载模型(在应用程序启动期间只加载一次),使用模型来预测输入姓名的性别,并在 web 应用程序上可视化结果。下面的代码片段只显示了 web 应用程序的模型推理部分。完整的 Plotly Dash web 应用程序代码,包括模型加载、文本框输入、表格输出和交互式条形图输出,可在我的 GitHub 存储库上获得。

样本推断结果。作者图片
在互联网上发布
最后一步是在互联网上发布我们的新应用程序,让世界各地的每个人都可以与之互动。经过一点点的研究,我决定使用 Heroku 来部署应用程序,原因如下。
- 免费!!!
- 简单的部署流程
- 最大 500MB 内存对于我的小型定制型号来说已经足够了。
部署单一回购
Heroku 网站[ 链接 ]详细记录了将应用部署到 Heroku 的步骤。我做了一些定制的修改来支持我的 mono-repo 格式,我在我的 Github repo [ 链接 ]中记录了这些修改。支持单一回购的主要变化有
- 添加以下构建包
heroku buildpacks:add -a <app> https://github.com/lstoll/heroku-buildpack-monorepo -i 1
- 添加以下配置
heroku config:set -a <app> PROCFILE=relative/path/to/app/Procfile
heroku config:set -a <app> APP_BASE=relative/path/to/app
指定工作人员的数量
重要!我花了一些时间才发现的一个主要问题是 Heroku 默认启动两个工人。因此,如果你的应用程序的大小超过 250MB,两个工人加起来将超过 Heroku 为免费应用程序设置的 500MB 限制。由于我不希望我的应用程序的流量大到需要两个工人,所以我通过使用 Procfile 中的-w 1标志只指定一个工人,轻松地解决了这个问题。
web: gunicorn -w 1 serve:server
设置 ping 服务
免费层 Heroku 应用程序在 30 分钟不活动后进入睡眠状态。因此,我使用了一个名为 Kaffeine [ Link ]的免费 ping 服务,每 10 分钟 ping 我的应用一次。这将确保应用程序零停机时间。
随后,我从免费层升级到爱好层(主要用于我的自定义域上的免费 SSL),确保应用程序永不休眠,因此 ping 服务不再与我的应用程序相关。
添加自定义域
最后,我从 name price[Link]购买了一个便宜的域名,并按照这里[ Link 的指示将该域名指向我的 Heroku 应用。
关于潜在偏见的免责声明
严肃地说,在使用这种方法时,我们需要记住一些限制和偏见。
- 这个模特对现实世界中的性别概念有零的理解!它只是根据属于不同性别的名字的历史数据,对一个特定的名字可能属于哪个性别做出一个有根据的猜测。例如,我的名字以“Marie”开头,模型检测出这是一个女性名字(置信度约为 90%!)虽然我其实是个男的。因此,这种方法延续了我们名字中固有的偏见,解决这些偏见超出了本研究的范围。
- 训练数据仅由二元性别(M 和 F)组成。因此,非二元性别没有得到代表。
总之,请不要使用这个应用程序对任何人的性别身份做出假设!
就是这样!我们很酷的 ML 应用程序可以根据名字预测性别,现在互联网上的任何人都可以与之互动!从我的测试来看,这款应用对英文名字的表现似乎非常好,对印度名字的表现也相当好,因为这些名字存在于训练数据集中。像中文名字这样的非英文名字表现很差。请你看一下,让我知道你的名字是否正确?感谢阅读!
所有代码都可以在我的 Github repo 上找到:[ 链接 ]
你可以访问“男孩还是女孩?”at:https://www . boyorgirl . XYZ
脑机接口将想象的笔迹解码成实时文本
原文:https://towardsdatascience.com/brain-computer-interface-to-decode-imagined-handwriting-into-real-time-text-e13014186c01?source=collection_archive---------20-----------------------
你想知道 BCI 如何利用深度学习恢复失去行动或说话能力的人的交流吗?

通过手写进行大脑到文本的交流——作者根据[1]提供的照片
我们已经看到许多领域,如自然语言处理、计算机视觉、预测性维护、推荐系统,正在以这样或那样的方式通过深度学习进行革命。本文将讨论最近的研究,这些研究显示了深度学习在脑机接口(BCIs) 中的潜力。BCI 不仅仅是我们通常在科幻电影中看到的未来派界面;它可以恢复失去行动或说话能力的人的交流。
BCI 研究的主要焦点是恢复粗大运动技能,如伸手、抓握或用 2D 电脑光标点击打字[2]。然而,在最近的研究工作中,[1]的作者正在使用递归神经网络(RNN)将想象的手写运动解码为实时文本,以实现更快的通信速率。
利用这种新的大脑皮层内 BCI 解码想象笔迹的方法,研究参与者通过通用自动更正功能,实现了每分钟 90 个字符的打字速度和 99%的准确率>。尽管该研究参与者患有高度脊髓损伤,颈部以下瘫痪,但他的打字速度与健全的智能手机打字速度相当。
对想象的笔迹进行编码
首先,我们需要确定即使瘫痪多年后,运动皮层的神经活动可能足够强,对 BCI 有用。如果不是这样,那么我们就无法从想象的笔迹中解码出实时文本。因此,作为第一步,我们必须检验我们是否能通过想象笔迹从神经活动中对字符进行分类。

图 1:尝试手写的稳健神经活动编码[1]
如图 1A 所示,受试者按照电脑屏幕上的指示想象手写每个字符,就好像他的手没有瘫痪一样;参与者被要求尝试每个字符 27 次。因此,总共 31 个字符中的每一个都有 27 条轨迹。
图 1B 显示了三个示例字母的神经活动的前 3 个主成分(PCs)。基于图 1B,很明显,神经活动看起来是稳定的和可重复的,但是存在一些时间可变性(可能是由于书写速度)。图 1C 示出了在使用时间校准技术去除时间可变性之后得到的神经活动 PCs。
为了查看神经活动是否编码了笔的运动,作者们试图通过线性解码笔尖速度来重建每个字符。字母形状的可识别重建(图 1D)证实了笔尖速度在神经活动中被稳健地编码。此外,神经活动的 t-SNE 可视化(图 1E)显示,类似书写的字符具有或多或少类似的表示。
最后,使用简单的 k-最近邻分类器,[1]的作者能够以 94.1%的准确度从神经活动中分类字符。因此,上述所有研究都证明,与笔迹相对应的神经活动足够强,对 BCI 有用。
实时解码想象的笔迹

图 2:试图实时手写的神经解码[1]
现在令人兴奋的部分来了,使瘫痪的人能够通过想象手写他们想要的信息来交流。[1]的作者训练了一个 RNN,将神经活动转换成描述字符在每个时刻被书写的可能性的概率。RNN 还预测了任何新角色开始的可能性。RNN 的神经活动输入在时间上被分箱(20 毫秒箱)并且在每个电极处被平滑。如图 2A 所示,预测的概率既可以简单地设定阈值,也可以用自动更正功能广泛地处理。
为了收集 RNN 的训练数据,作者记录了参与者按照计算机显示器的指示想象完整手写句子时的神经活动。使用三天内收集的 242 个句子来训练初始模型。为了克服以下挑战,作者在自动语音识别中采用了深度学习方法[3–5]。
- 训练数据中每个字母的确切时间是未知的,这使得很难应用监督学习技术。
- 与典型的 RNN 数据集相比,该数据集的大小有限,因此很难防止过度拟合。
RNN 的表现在五天内进行评估,每天包含 7-10 个句子(不用于培训)。在解码器评估的每一天之后,当天的数据被累积添加到第二天的训练数据集中。图 2B 显示了两个示例评估轨迹,展示了 RNN 解码句子的能力(错误用红色突出显示,空格用“>”表示)。在图 2C 中显示了五天的错误率和打字速度。有了自动更正后处理,错误率大大降低了。[1]的作者还通过允许研究参与者回答开放式问题,在一个不太受限制的环境中评估了模型的性能。
用 2D 电脑光标点击打字(每分钟 40 个字符)[2]是脑皮质内 BCI 表现最好的方法。然而,[1]的作者已经表明,手写运动的解码速度可以快两倍以上,准确性水平相当。性能更好的原因是因为点对点可能比手写字母更难区分。
有趣的是看到时变的复杂运动模式,如手写字母,从根本上比简单的点对点运动更容易解码。看到自动语音识别深度学习方法[3–5]如何适用于这个 BCI 用例也非常鼓舞人心。
我希望这篇文章内容丰富,发人深省。谢谢:)
参考
[1] Francis R. Willett、Donald T. Avansino、Leigh R. Hochberg、Jaimie M. Henderson 和 Krishna V. Shenoy,通过手写进行高性能的大脑到文本的通信 (2021)
[2] Chethan Pandarinath,Paul Nuyujukian,Christine H Blabe 等人,瘫痪患者使用皮质内脑机接口进行高性能通信 (2017)
[3] Geoffrey Hinton 等人,用于语音识别中声学建模的深度神经网络:四个研究小组的共同观点 (2012)
[4] Graves A .、Mohamed A .、Hinton G .,深度递归神经网络语音识别 (2013)
[5]熊伟等,微软 2017 对话式语音识别系统 (2017)
广度与深度
原文:https://towardsdatascience.com/breadth-vs-depth-7400cc91c05d?source=collection_archive---------21-----------------------
意见
数据科学家应该是专家还是通才?
关于数据科学家是专攻还是通才更好,我已经看到了相当矛盾的建议。
紧张在于:为了脱颖而出,公司希望你成为他们需要的特定技能的专家。但是专注于一个利基市场意味着你有资格获得更少的工作,而很多(大多数?)雇主想要的是灵活的人,而不是只会一招的小马。那么一个数据科学家应该怎么做呢?专业化还是多元化?数据科学职业什么比较好?

照片由梅尔特·塔拉伊在 Unsplash 上拍摄
专业化是什么意思
首先,我们先明确一下我说的专精是什么意思。专业化可能意味着成为特定类型数据的专家,如医疗索赔数据、金融欺诈数据、电子商务交易等。或者这可能意味着成为某个行业的专家——医疗保健、金融、电子商务等。或者这可能意味着建立特定工具的专业知识——深度学习、图像处理、因果建模等。
关键是,专家对可能出现在招聘启事中的东西有特定的经验。
另一方面,多面手拥有更广泛的技能或经验,但并不特别精通其中任何一项。也许他们已经涉足了许多不同行业的项目,或者使用了许多不同的工具,有点像“万金油”。
一个人是成为专家还是多面手在很大程度上取决于他的性格和背景。专业化会带来极大的满足感,因为你会成为某方面的深度专家,并感觉自己非常胜任自己的工作。概括对于那些喜欢学习和探索的人,或者那些容易厌倦的人(我属于这一阵营)来说是非常好的。
但是假设你对这两者不感兴趣,并且认为专攻和通才一样快乐,那么什么对你的职业最有利呢?
专业化或多元化建议的主要区别是:资历

照片由布鲁斯·马斯在 Unsplash 上拍摄
我怀疑,之所以在专业化和多元化哪个更好的问题上有如此不同的信息,是因为这取决于你的资历。对于初级(或有抱负的)数据科学家和中级或高级数据科学家来说,成为专家或多面手意味着非常不同的事情。让我们看几个场景:
找工作
对于入门级或小众职位,专精是必由之路。
从招聘经理或招聘人员的角度考虑一下,从数百份简历中筛选——所有初级人员的简历看起来都非常相似。他们列出了非常相似的技能(标准数据科学堆栈)。他们有一些明显是为了学习的投资组合项目(尽管好的项目可能有一些更好的项目)。
一份简历脱颖而出的最简单的方法之一就是拥有一个与该职位主要从事的工作类型直接相关的项目或一些经验。
拥有处理医疗保健数据的经验对医疗保健公司来说会很好——他们认为你已经具备了做好工作所需的一些领域专业知识,并且能够更快地投入工作。如果你申请的是一份 NLP 繁重的工作,拥有自然语言处理的特定专业知识会比一般的数据科学概述看起来更好。在初级阶段,这些因素通常是简历能给出的最强信号。
中级及中级以上

在 Unsplash 上 Deva Darshan 拍摄的照片
在初级水平之外,我认为专业化的理由变得越来越弱。肯定有更专业化的高级职位。在极端的情况下,在他们的领域中处于领先地位的人几乎肯定会得到不错的报酬,而且找工作也不会有困难。
但对于普通的数据科学家来说,随着资历的增加,拥有丰富的经验变得更加重要。部分原因是职责的变化——初级人员通常被期望从事少量相关项目,而高级人员则被期望能够灵活地从事更广泛的项目。更广泛的技能组合通常比更深入的技能组合更适合更高级职位的需求。除了大型科技公司,大多数公司都没有超级专业化的数据科学团队,所以他们最终需要能够承担一系列工作。
除此之外,随着资历的增加,就业市场也发生了逆转——竞争减弱,更多的是求职者的市场。你不需要从一大群人中脱颖而出,但是有一些相关的工作经验是很好的。如果你已经涉猎了很多东西,那就更容易确保你对任何给定的工作都至少有一些经验。这扩大了你竞争的工作范围。
管理和领导通常需要多面手
如果你想走上领导岗位,成为多面手无疑是更容易的途径(同样,假设你不在拥有超专业数据科学团队的大型科技公司)。对于管理者来说,尤其是管理一个大团队的管理者,管理使用各种技能处理各种问题的员工是很常见的。在这些领域拥有一些基本的能力和理解对于领导这些工作是很重要的。再说一次,拥有更广泛的经验会让你申请更多的潜在职位。
结论
在数据科学领域,是专攻好还是通才好,这个问题没有放之四海而皆准的答案。然而,我认为总的建议应该是:专业化直到你达到中等水平,然后开始拓宽自己。当然,一个擅长网络的多面手可能会发现不需要专业知识就可以轻松进入这个领域,而一个专家可能会找到一个他们能够在整个职业生涯中占据的位置。每个人都有自己的兴趣,做你感兴趣的事情会让你成为一名更好的员工,这可能比试图过度优化你所学的东西产生更大的影响。但总的来说,为了工作的竞争力和安全感,我认为这个建议是一个不错的经验法则。
相关文章
将一个大的气流 DAG 分解成多个文件
原文:https://towardsdatascience.com/break-up-a-big-airflow-dag-into-multiple-files-5262accf6713?source=collection_archive---------6-----------------------
模块化你的大气流 DAG 的大块,以便于使用和维护

丹尼尔·林肯在 Unsplash 上的照片
我正在处理一个长达数百行的气流 DAG 文件。进行更改需要在文件中来回移动,在便笺簿上做笔记以确保一切正确。一旦我开始在 IDE 中打开 DAG 文件的多个视图,我知道这是一个停下来并找到一种方法将 DAG 分成更小的片段的好时机。
随着 Airflow 2 中 TaskGroups 的出现,将一个大 DAG 分成几个部分在概念上和实践上都更容易了。这些部分可以重用,当然,它们更容易更新和维护。
TaskGroups 只是相关任务的 UI 分组,但是分组往往是逻辑的。任务组中的任务可以被捆绑和抽象,以便更容易地从比单个任务更大的单元构建 DAG。也就是说,任务组并不是将任务分组并将其移出 DAG 文件的唯一方式。你也可以有一个不在任务组中的逻辑任务块。后一种方法的缺点是,您失去了在 DAG 运行的 web UI 图形视图中将任务折叠到单个节点中的好处。
分解 DAG 的技巧是将 DAG 放在一个文件中,例如modularized_dag.py,将任务或任务组的逻辑块放在单独的文件中,每个文件一个逻辑任务块或任务组。每个文件都包含函数,每个函数都返回一个 operator 实例或一个 TaskGroup 实例。
为了快速说明,下面的modularized_dag.py从foo_bar_tasks.py引入了返回操作符的函数,从xyzzy_taskgroup.py引入了返回任务组的函数。在 DAG 上下文中,调用这些函数时将 DAG 对象dag作为参数传递,它们的返回值被分配给 task 或 TaskGroup 变量,这些变量可以被分配上下游依赖关系。
实运算符的简单示例
现在举一个真实的例子。让我们使用虚拟操作符和 Python 操作符来创建任务。
首先是 DAG 文件:dags/modularized_dag.py。它只是从plugins/includes/foo_bar_tasks.py导入分块任务函数,从plugins/includes/xyzzy_taskgroup.py导入任务组函数。它将使用 DAG 上下文创建的 DAG 传递给每个函数。
dags/modularized_dag.py:
from datetime import datetime, timedeltafrom airflow import DAG
from includes.foo_bar_tasks import build_foo_task, build_bar_task
from includes.xyzzy_taskgroup import build_xyzzy_taskgroup default_args = {
'owner': 'airflow',
'depends_on_past': False,
'email_on_retry': False,
'retries': 1,
'retry_delay': timedelta(minutes=5),
}with DAG(
dag_id="modularized_dag",
schedule_interval="[@once](http://twitter.com/once)",
start_date=datetime(2021, 1, 1),
default_args=default_args,
) as dag: # logical chunk of tasks
foo_task = build_foo_task(dag=dag)
bar_task = build_bar_task(dag=dag) # taskgroup
xyzzy_taskgroup = build_xyzzy_taskgroup(dag=dag) foo_task >> bar_task >> xyzzy_taskgroup
接下来是plugins/includes/foo_bar_tasks.py中逻辑分块的任务功能。我们的逻辑块中有几个函数,build_foo_task和build_bar_task。第一个返回伪运算符,第二个返回 Python 运算符。Python 操作符使用一个简单的导入日志记录函数log_info,它在下面的plugins/includes/log_info.py中定义。
plugins/includes/foo_bar_tasks.py:
from airflow import DAG
from airflow.operators.dummy import DummyOperator
from airflow.operators.python import PythonOperatorfrom includes.log_info import log_info def build_foo_task(dag: DAG) -> DummyOperator:
foo_task = DummyOperator(task_id="foo_task", dag=dag) return foo_task def build_bar_task(dag: DAG) -> PythonOperator:
bar_task = PythonOperator(
task_id="bar_task",
python_callable=log_info,
dag=dag,
) return bar_task
在逻辑块任务函数之后,我们在plugins/includes/xyzzy_taskgroup.py中有一个 TaskGroup 函数。这个任务组包括一对任务,baz_task用伪操作符实现,而qux_task用 Python 操作符实现。像上面的 chunked tasks 文件一样,这个文件也导入了日志功能log_info。
plugins/includes/xyzzy_taskgroup.py:
from airflow import DAG
from airflow.operators.dummy import DummyOperator
from airflow.operators.python import PythonOperator
from airflow.utils.task_group import TaskGroupfrom includes.log_info import log_info def build_xyzzy_taskgroup(dag: DAG) -> TaskGroup:
xyzzy_taskgroup = TaskGroup(group_id="xyzzy_taskgroup") baz_task = DummyOperator(
task_id="baz_task",
task_group=xyzzy_taskgroup,
dag=dag,
) qux_task = PythonOperator(
task_id="qux_task",
task_group=xyzzy_taskgroup,
python_callable=log_info,
dag=dag,
) baz_task >> qux_task return xyzzy_taskgroup
最后,这里是由foo_bar_tasks.py和xyzzy_taskgroup.py导入的简单日志功能。
plugins/includes/log_info.py:
import logging def log_info(**kwargs):
logging.info(kwargs)
一旦所有这些文件都准备好了,您就可以使用您的 Airflow web UI 来解包 DAG 并确保它正常工作。下面是modularized_dag.py的图形视图:

模块化的 DAG 非常好用!(作者供图)
我们可以检查 Python 操作符任务的日志(第一个来自逻辑分块的任务,第二个来自 xyzzy_taskgroup 内部):
bar_task用log_info功能输出高亮灰色:

从酒吧登录任务(作者提供照片)
xyzzy_taskgroup.qux_task用log_info功能输出高亮灰色:

xyzzy TaskGroup 中 qux 任务的日志(作者提供图片)
概观
我们已经介绍了如何通过将任务组或操作符返回函数放在独立的文件中,将一个大的 DAG 文件分解成模块化的块,现在模块化的 DAG 将从plugins/includes目录导入这些文件。使用 TaskGroup-returning 函数的优势在于:( 1)您可以将逻辑任务组抽象成 DAG 中的一个组件,以及(2)task group 中包含的任务将在 DAG 运行的 web UI 图形视图中折叠成单个节点。
2021 年进军数据科学:竞争越来越激烈了吗?
原文:https://towardsdatascience.com/breaking-into-data-science-in-2021-is-it-still-easy-as-before-9bb6fe313a0f?source=collection_archive---------14-----------------------
为什么现在成为数据科学家需要更多的准备

图片来源:韦斯·希克斯@ Unsplash
自从哈佛商业评论宣布数据科学是 21 世纪最性感的职业以来,已经有大约九年了。从那时起,许多有抱负的数据科学家开始提升自己的技能并进入就业市场,其中一些人成功地过渡到了数据科学工作。2021 年,数据科学就业市场仍在增长。尽管由于新冠肺炎疫情,2020 年的就业市场有所放缓,但对于年轻的专业人士来说,数据科学仍然是一个利润丰厚的职业。但是,许多有抱负的数据科学家面临的问题是,进入数据科学领域不像五年前那么容易了。
几年前,我开始在信息技术行业担任数据科学家。那时进入数据科学领域相对容易。数据科学领域仍然非常年轻,对公司来说是一个闪亮的新对象,所以他们会很容易地雇佣大量数据科学家。此外,公司对雇用数据科学家没有太多要求。拥有一些 Python 技能,学习一些 SQL,了解一些数据可视化和机器学习技术就足以获得初级数据科学工作。如今,人才找到初级数据科学工作变得越来越困难,因为更多的人才正在市场上寻找工作。
在这篇文章中,我解释了我认为进入数据科学的难度增加的一些原因。
1)在就业市场上,有抱负的数据科学家之间的竞争越来越激烈
数据科学在就业市场上的认知度仍然很高。来自不同领域的许多人才,从高度量化的领域(有时甚至来自心理学或生物学等领域),正在向数据科学过渡。与工作市场的需求相比,这导致初级数据科学家的人才供应增加。
如果我们从雇主的角度来看,大量人才在就业市场上积极寻找数据科学工作,会导致招聘流程中的开销。有时,对于数据科学领域的一个职位发布,公司必须查看数百份简历,并面试数十名候选人来填补职位空缺。例如,我在 Linkedin 上发布了一份自己公司的数据科学工作。虽然工作地点是德国法兰克福,但我们收到了全球近 500 名申请人。在申请人的人才库中,每个职位都有数十名相对合格的候选人,他们之间没有太大的差别。如果我们想筛选所有这些候选人并对他们进行面试,我们将面临严重的时间限制。这可能是许多公司寻找替代招聘方法的原因,比如雇佣招聘机构或依靠推荐,而不是亲自面试所有候选人。
总体而言,有抱负的数据科学家如今可能难以脱颖而出。此外,招聘经理为数据科学工作选择候选人变得更加困难和耗时。

单个数据科学职位发布的大量申请人(Linkedin 职位发布平台的快照)
2)工作需求膨胀
尽管初级人才供应充足,但对高级数据科学家的需求仍然高于就业市场的供应。对于有抱负的数据科学家来说,这可能是一个好消息,但这可能会给他们在职业生涯开始时进入该领域带来一些困难。为什么?
当就业市场对有经验的数据科学专业人员的需求高于人才供应时,高级数据科学家的工资就会上涨。这意味着支付更高价格雇佣有经验的数据科学家的公司期望更多,并希望专业人员带来更丰富的技能。比如现在,高级别的数据科学家需要了解软件工程、DevOps、大数据、云计算的很多技术,这是标准的做法。因此,人才可能会在他们需要完成的每个数据科学职位描述的要求部分找到一长串所需的技能和技术。虽然这可能只是高级数据科学人才的问题,但看看初级职位的工作描述就会发现,这种现象也正在转移到初级职位。公司知道,当他们雇用初级数据科学家时,他们还必须将他们培训到高级水平,找到一个已经知道大多数技术的候选人为他们节省了大量培训成本。因此,最终,有抱负的数据科学家必须付出更多努力才能进入这份工作。
3)新冠肺炎·疫情导致数据科学就业市场萎缩
由于新冠肺炎疫情和经济放缓,许多公司继续生存模式,这意味着他们削减所有不必要的和奢侈的开支,包括数据科学。这导致数据科学行业在 2020 年增长放缓。当就业市场上雇用数据科学家的公司越来越少时,也会在有抱负的数据科学家本身以及最近被解雇并积极寻找就业市场的高级候选人之间产生更多竞争。因此,竞争中的这种雪球效应使得有抱负的数据科学家更难进入这一领域。
4)来自数据工程和云等其他领域的竞争
是的,是真的!我们在数据领域有了新的竞争者,那就是数据工程。数据工程是一个在过去几年中大规模增长的领域,特别是随着更实惠的大数据和云工具的可用性以及机器学习管道的自动化。
随着大数据和机器学习管道的自动化趋势,公司正在将注意力转移到使用现成的基于云的机器学习模型,这比构建定制模型更容易部署。这导致公司希望雇用一些数据工程师、云和开发运维专家,而不是数据科学家。
还有,由于后大流行时代的经济环境不确定,许多公司暂时放弃了使用机器学习预测未来变量。相反,他们可能会利用时间和预算来开发大数据管道和数据基础设施。因此,在短期内,分析和机器学习专家的工作可能会减少,而数据工程师、云和开发运维专家的工作会增加。
尽管如此,我相信从长远来看,数据工程不会取代数据科学。大数据和云行业的增长实际上对数据科学家来说是个好消息,因为它让数据科学家和机器学习工程师的生活变得更加轻松,因为公司内部有了高性能的大数据管道,减少了数据科学团队在数据准备方面所需的手动工作。

谷歌搜索趋势搜索“数据科学工作”与“数据工程师工作”(谷歌趋势快照)
5)数据科学家的一些任务正在被云自动化
随着云计算平台中高级机器学习工具的出现,定制和现成机器学习模型之间的竞争变得更具挑战性。由于建立数据科学团队的成本很高,一些公司正在满足于现成的机器学习工具,至少在概念验证阶段,这些工具可能会解决他们的业务问题。使用这些工具可以减少数据科学家的数量,至少在疫情时代是这样。但是,在我看来,这种影响只是短期的,因为当涉及到机器学习模型的产业化并将其投入生产以推动有形的商业价值时,公司仍然需要定制的数据科学家来开发高性能的定制机器学习模型和分析工具。
展望:
2021 年,数据科学是一个不断增长的行业,也是一个仍然有利可图的职业,对许多年轻专业人士来说,进入门槛相对较低。但是,如今,要成为一名数据科学家,仅仅学习 Python 和一些机器学习工具是远远不够的。
有抱负的数据科学家需要用一套丰富的大数据和机器学习工具来装备自己,以便在就业市场上更具竞争力。此外,对于有抱负的数据科学家来说,使用有效的个人品牌和网络软技能脱颖而出变得更加重要。
更多文章来自作者:
</8-career-paths-for-junior-data-scientists-to-pursue-3e6041950e4e>
关于作者:
Pouyan R. Fard 是 Fard 咨询公司的首席执行官&首席数据科学家。Pouyan 在数据科学、人工智能和营销分析方面拥有多年的公司咨询经验,从初创公司到全球公司。他曾与医药、汽车、航空、运输、金融、保险、人力资源和销售&营销行业的财富 500 强公司合作。
Pouyan 还积极指导活跃在大数据行业的初创公司和求职者。他的热情是通过职业培训培养下一代数据科学家,并帮助他们找到数据科学领域的顶级工作机会。
Pouyan 已经完成了关于消费者决策预测建模的博士研究工作,并对开发机器学习和人工智能领域的最先进解决方案保持兴趣。
打破微软的垄断
原文:https://towardsdatascience.com/breaking-the-openai-microsoft-monopoly-b9f24364a890?source=collection_archive---------19-----------------------
人工智能|新闻
人工智能不应该掌握在少数人手中

费利克斯·米特迈尔在 Unsplash 上的照片
在他们的名人人工智能模型 GPT-3 当之无愧的受欢迎之后,OpenAI 已经成为一家极其知名的人工智能公司。GPT-3 拥有惊人的技能,它可以写诗、写文章或写代码,但如果没有微软的资金和计算能力的帮助,这些都不可能实现。
GPT-3 可以说是最先进的语言模型(至少在那些公开可用的模型中)。因此,将它用于大学和非营利机构的研究目的是合理的。取而代之的是,OpenAI 决定通过一个私有 API 来限制少数特权用户的访问。GPT-3 是他们的财产,所以他们可以决定谁可以品尝它,谁不可以——除了微软;他们可以为所欲为。
OpenAI 有使命。“我们的目标是以最有可能造福全人类的方式推进数字智能,不受产生财务回报需求的约束。”他们永远不会把他们的股东放在多数人之前,是吗?这在他们是非盈利的时候是真的,但现在不是了。现在,我们只能希望他们信守诺言。
目前,他们的大部分行动都指向相反的方向。获得他们的 API 的最佳方法是向他们描述你计划如何在创收机器上转换他们的 AI 模型。这并不是说他们无私地希望你赚钱——你要么赚钱,要么因为 OpenAI 设定的难以承受的成本而被迫关闭你的项目。TechTalks 创始人本·迪克森说“一些建立在 GPT-3 之上的非盈利、娱乐和科学项目已经宣布由于高昂的成本它们将被关闭。”
对于那些有门路并负担得起费用的人来说,还有最后一个障碍需要克服;OpenAI 的指导方针。如果他们认为你的项目不符合他们的政策,他们会不可逆转地关闭它——即使他们已经给了你上线的通行证。这就是发生在项目 12 月的创建者杰森·罗尔身上的事情。他建立了一个旨在让人们定制聊天机器人的网站,但当约书亚和杰西卡的聊天机器人(模拟他已故未婚妻的机器人)的故事在网上传播开来时,OpenAI 并不喜欢它。
这项技术应该掌握在少数人手中吗?
自从 GPT 3 发布后,OpenAI 坚决拒绝任何开源代码的可能性,全球的开发者和研究人员开始致力于创造一个复制品。他们希望允许那些被排除在 OpenAI 的朋友们的选择性小组之外的人研究和分析这个系统。
GPT-尼欧和 GPT-J 的创造者伊莱瑟雷就是这样一个倡议者——我最近谈到过他们。GPT-J 有 60 亿个参数,类似于第二好的 GPT-3 版本,称为居里(大约 67 亿个参数,据 EleutherAI 估计)。与 OpenAI 相反,EleutherAI 正在构建模型,以便与所有人分享。
让任何人不受控制地访问这些人工智能都有风险,但 EleutherAI 决定“利大于弊。”如果建造像 GPT-3 这样的模型是可能的——鉴于目前的艺术水平,这非常简单——允许人工智能安全和人工智能伦理的研究人员获得它们是确保所有人有一个更美好未来的最佳方法。可以肯定的是,基于获得财务利润的前景来选择用户听起来不像是有益于“整个人类”。
但像 GPT-j·伊柳瑟雷这样的模型缺乏一个关键方面。他开发了代码并分享了代码,但大多数受益者可能不具备充分利用人工智能所需的编程知识。一个类似 OpenAI 的 API 丢失了。一周前,当人工智能初创公司 NLP Cloud 宣布他们将在其 API 上支持 GPT J-以及其他模型,以更适中的价格为其客户提供“生产就绪解决方案”时,这种情况发生了变化。
民主化大型语言模型
像 GPT-3 和 GPT-J 这样的语言模型提醒我们,“能力越大,责任越大。”与他们的成功相伴而来的是大量的风险和潜在的危害。关于大多数少数民族受到歧视性待遇的伦理问题,缺乏安全控制,传播错误信息的能力,以及产生不可用内容都是最相关的问题。
这就是为什么 NLP Cloud 认为“NLP 模型的唯一解决方案是保持开源,并由社区持续审核。”如果模型本身就有问题,最好的方法是让专家彻底检查它们——让普通大众买得起。
但是如何让他们买得起呢?这种大型模型的一个关键问题(也是 OpenAI 和微软如此成功地保持其霸权的原因)是,它们需要大量的计算能力来运行。即使只有 GPT-3 的一小部分,GPT-J 仍然需要 25GB 的 GPU VRAM 来运行——更不用说用它进行大规模推理了。市场上的大多数 GPU 都不符合这个模型。
NLP 云提供了一个有竞争力的解决方案。他们以 API 的形式提供对 GPT-J 的访问,以备生产,同时保持价格“尽可能地可承受,尽管在服务器端需要非常高的计算成本。”他们的服务远非免费,但这是一个进步,扩大了强大人工智能的使用范围,同时削弱了微软的垄断地位。
成本比较
我们来对比一下 open ai(GPT-3 的居里版本)和 NLP Cloud (GPT-J)的定价方案。Curie 的现收现付定价方案是每 1000 个代币(750 字左右)0.0060 美元。NLP 云为 GPT-J 提供了各种各样的计划,根据你的情况,这些计划可能非常有竞争力——在特定情况下,OpenAI 仍然有更好的价格。大多数情况下的最佳选择是固定费率的 GPU 计划(根据 API 请求的数量,从每月 99 美元到每月 699 美元不等)。
主要优势是 NLP 云不按令牌数收费,所以不管你想生成多少单词,价格都是一样的。尽管如此,在某些情况下,OpenAI 更经济实惠,因为用户可能只想向 API 发出一些请求——例如,测试 API playground。NLP Cloud 也有一个现收现付的计划,但每个令牌的价格比 OpenAI 高得多。
为了用一个具体的例子来说明成本的差异,我将使用文章生成的例子(一个文本生成的特殊例子,其中提示文本比完成文本短得多)。假设很多人使用你的应用程序,所以你每分钟收到 10 个请求。在论文生成中,平均请求的合理大小可以是 100 个标记的提示和 1000 个标记的完成——相当于输入一个段落并返回一整页。让我们计算一下:
- open ai/Curie:$ 0.0060/1000 token 1100 token/request(提示&完成)10 requests/min 43200min/月=$ 2851.2/月。
- NLP 云/GPT-J:10 个请求/分钟的固定费率,与令牌数量无关=$ 699/月。
另一个非常受欢迎的服务可能是生成推文(尽管 OpenAI 严格限制任何社交媒体应用)。让我们再算一次,但这次提示有 300 个令牌,完成有 50:
- open ai/Curie:$ 0.0060/1000 token 350 token/request(提示&完成)10 requests/min 43200min/月=$ 907.2/月。
- NLP 云/GPT-J:10 个请求/分钟的固定费率,与令牌数量无关=$ 699/月。
正如我们所看到的,因为 OpenAI 提供了一个随用随付的计划,所以你用得越少,它就越便宜。如果你想彻底分析这个系统或者把它用于商业目的,这种情况不太可能发生。正是在这些情况下,NLP 云大放异彩。
一家公司应该对一项最终可能彻底改变世界的技术拥有如此大的控制权吗?对我来说没什么意义。期望他们对服务收费是完全合理的,但是限制他们基于不透明的标准选择的人的访问——无论是直接的还是通过强加昂贵的价格——都不是非常“公开”
像 EleutherAI 这样的倡议和 NLP Cloud 这样的公司押注于一个非常不同的未来:像 GPT-3 和 GPT-J 这样的大型语言模型——以及其他有待发明的人工智能类型——应该是开源的,每个人都可以使用。与 EleutherAI 不同,NLP Cloud 是一家首先受利润驱动的公司,但目前,他们似乎坚持自己的价值观。如果他们最终决定改变他们的使命,那么他们会像 OpenAI 一样受到批评。
最后,让我们不要忘记,重点不仅仅是允许人们访问该模型,而是从 OpenAI 和微软这样的公司手中夺取垄断权。认为他们是唯一能够通过人工智能带领我们走向更美好未来的人听起来充其量是傲慢,最糟糕的是专制。
如果你喜欢这篇文章,可以考虑订阅我的免费周报https://mindsoftomorrow.ck.page!每周都有关于人工智能的新闻、研究和见解!
您也可以直接支持我的工作,使用我的推荐链接 这里 成为媒介会员,获得无限权限!:)
