TowardsDataScience-博客中文翻译-2016-2018-三十四-

TowardsDataScience 博客中文翻译 2016~2018(三十四)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

我们应该害怕 AI 吗?

原文:https://towardsdatascience.com/should-we-be-afraid-of-ai-ee10f6f77697?source=collection_archive---------6-----------------------

在技术、媒体和广告世界,我们不断听到人工智能将如何改变一切。这些讨论大多是关于人工智能将如何使流程和产品变得更好更快的鼓励。但是这里的利害关系也是我们成为人类的原因。

人工智能有很多好处。毫不奇怪,人工智能的一个应用是软件。

许多人工智能支持的软件倡议正试图减少招聘的偏见,如unity。作为数十年招聘研究的成果,Unitive 简化了审查过程,因此人类的无意识不会在性别、种族或其他身份因素方面影响招聘。

班卓琴使用人工智能进行预测。数据是从世界各地的社交网络和网站上收集的,用于对可能发生的事件进行有用的预测,如特定地点的极端天气事件或恐怖袭击。

这些应用代表了人工智能的一些优势。然而,这种外包给人工智能的做法正是埃隆·马斯克所担心的。众所周知,他告诫人们不要过度依赖他所谓的人类“最大的生存威胁”

与任何技术一样,人工智能也存在被滥用的真实可能性。这里的一个主要问题是隐私。人们并不总是意识到,也不一定同意使用他们的个人数据来增加公司的利润或跟踪感兴趣的人。

AI Now 是试图监控 AI 的组织之一。由凯特·克劳福德(Kate Crawford)和梅雷迪思·惠特克(Meredith Whittaker)组成的多学科倡议正试图分析人工智能对社会不平等、劳动力和医疗保健的影响。他们最近发表了一份关于如何让人工智能“更加公平公正”的报告

我们仍然有时间探索一个充满人工智能的世界的好处和潜在陷阱。人工智能对个人的影响现在大多是间接的,而且往往过于间接,人们不会注意到。这将在不久的将来改变。已经有一些工作类型最容易受到早期机器学习浪潮的影响,比如卡车司机和工厂工人。事实上,那些在过去几十年中失去的蓝领工作已经成为一个政治热点可以主要归因于自动化而不是外包

但我们认为的许多工作在技术上是安全的,比如医学、法律和金融领域的工作,也同样可能屈服于人工智能。《哈佛商业评论》指出这 5 个步骤几乎适用于所有工作,无论薪水如何:

  1. 收集数据
  2. 分析数据
  3. 解释结果
  4. 确定推荐的行动方案
  5. 实施行动方案

机器很有能力掌握这一进展,不会像人类医生那样有来自有限资源的先天偏见。

然而,情商(EQ)目前是衡量人类劳动价值的一个重要因素。理解、互动和激励其他人是人工智能在未来几年很难复制的事情。领导力和同理心将是让人工智能陷入困境的原因……就目前而言。

已经有聊天机器人通过了图灵测试,或者非常迷人,以至于人类似乎不在乎他们是否在和机器人说话。微软 Xiaoice 背后的人工智能是基于“情感计算、”的,这是一种优先于任务完成的关系。意思是,确保和你谈话的人对你感到满意,而不是对你提供的东西感到满意。这是人类互动的一个基本原则,也是人工智能准备不仅从卡车司机那里抢工作,还从治疗师和男朋友那里抢工作的一个原则。

应该读 Udacity AI 纳米学位还是 AI 硕士学位?

原文:https://towardsdatascience.com/should-you-do-a-udacity-ai-nanodegree-or-an-ai-masters-degree-6c39bb7101ec?source=collection_archive---------6-----------------------

我创造了自己的人工智能硕士学位。其中包括两个 Udacity 纳米学位,以及其他课程。

  1. Udacity 深度学习纳米学位
  2. 人造纳米度

Udacity 的课是我上过的质量最高的课。

我从未获得过真正的硕士学位,但无论如何让我们比较一下。

成本

我去我大学的开放日看研究生学习。我调查的计算机科学项目是两年内每年 42,000 美元。你需要先付 50%。

我没有多余的 42,000 美元。所以我去了别处。

创建我自己的学习路径,我总共花了 3500 美元。各种课程、书籍和工具。3500 美元不是免费的,但远低于 84000 美元。

预先支付一切意味着我也没有任何债务。

时间

如果我报名参加计算机科学项目,至少需要 2 年才能完成。

我自己的课程已经学了一年,快完成了。

然而,学习这些技术是永无止境的。每周都有一个新的艺术基准要了解。每周!很好玩。

学习

我想学习计算机科学,因为我想了解人工智能。这比什么都更能激发我的兴趣。

但是大学提供的课程似乎什么都教,除了我所追求的。

上网后,我可以研究任何我想研究的东西。我直奔我想学的东西的来源。这很难。但是学习新事物总是很难。你不妨把精力投入到你想学的东西上。

反馈

在我的本科学位期间,我交了作业,有时三个月都得不到反馈。到那时,这对我来说已经不重要了。考试也是如此。

Udacity 的评审人员会在你提交项目后的 24 小时内给你反馈和建议,有时会在一小时内。更不用说 Udacity 论坛和 Slack 频道了。这些对我的学习是非常宝贵的。与其一次在一个问题上坚持几个星期,不如(几乎)立即就能得到帮助。

质量

我是视觉学习者。我必须亲眼目睹事情的发生才能理解它们。阅读大量的课堂笔记对我来说不是最好的学习方式。

Udacity 的动画团队做了大量的工作来配合他们的讲座。我经常发现自己反复观看观想十几次,让这个概念在我的脑海中扎根。

Udacity 还与行业专家合作。在我参加的纳米学位课程中,有来自 IBM 和 Google 的人提供了他们的见解。

内容

我自己的硕士学位是否可以和真正的硕士学位相提并论?

我不知道答案,但是这样看。

大学硕士学位经受住了时间的考验。它们是为你将来的学习和研究做准备的。许多公司仍然认为它们是有价值的,甚至是必需的证书。

当然,我的硕士学位会有一些漏洞,纳米学位不会涵盖你需要知道的一切,因此得名。但更重要的是,我创造了自己的道路,其中包含了我想学的东西。这使得学习变得更加愉快。

最好的课程是那些激发你兴趣去拓展知识的课程。Udacity 课程为我做到了这一点。

机遇

两个月前,我开始做机器学习工程师。从那以后,我从事了一系列需要我在纳米学位中学到的技能的项目。

然而,我也不得不根据项目的要求学习更多的东西。

有了硕士学位,我能申请更多的机会吗?可能吧。但是我没有。

相反,我知道我正在学习的技能是有价值的,并确保建立一个在线文件夹来作为我工作的证明。

Udacity 也与科技公司合作,并提供职业服务来帮助你找到一个角色,然而,我还没有利用这些。

进一步学习

我只记得我所学的 1%。这就是为什么我的口号是继续学习

现实世界中的大多数数据并不像你在一些课程中发现的那样整齐地打包,包括纳米学位。你必须不断地想出新的方法来以一种可以使用人工智能技术的格式获取数据。

从纳米学位或硕士学位毕业并不是你学习旅程的结束,而是一个新旅程的起点。

你永远不会为你所接受的挑战做好充分准备,但是有了你所获得的基础技能,你将能够学到你所需要的。

总结

完成 AI 纳米学位后,我是不是最好的人工智能工程师?

号码

我读传统的人工智能硕士会不会更好?

也许吧,但我不打算做。

我能按要求学习新技术并应用于新问题吗?

是的。

我学的课程让我兴奋吗?

是的。

我的知识中有陷阱吗?

是的,但是我可以和在这些方面比我强的人在一起,并向他们学习。或者,我可以找出我的弱点,并加以解决。

如果你想节省成本和时间,直接进入人工智能的前沿,我会推荐人工智能纳米学位等课程。

如果你想接受更传统、更全面的教育,并有望继续深造、攻读博士学位之类的课程,那就去攻读人工智能硕士学位吧。

你可以用这些技能解决很多问题。它们需求量大是有原因的。

不断学习。

本帖开始是我对 问题的回答一个 Udacity 纳米学位和一个人工智能硕士学位有什么区别?Quora 上。

LinkedIn 上与我联系。

在 YouTube上看我

你应该去争取吗?使用 MLB 数据的基础窃取预测器

原文:https://towardsdatascience.com/should-you-go-for-it-a-base-steal-predictor-using-mlb-data-6087a206ff66?source=collection_archive---------13-----------------------

棒球运动中最令人兴奋的事情之一是偷垒。如果跑垒者计时正确,会有两种结果:

或者他们不…

有时甚至会发生令人惊奇的事情。

Those moves by Jayson Werth

偷垒是一场精心策划的赌博,游戏的形势决定了成功的机会。要决定是否去做,需要跑垒员和经理的正确判断,这种判断只能从打了几十年的高水平棒球中获得。然而,如果只需点击一个按钮就能做出这个决定,那会怎么样呢?我决定为我的第三个 Metis 项目建立一个预测模型,并创建了一个 Flask app ,部署在 Heroku 上。

数据

获取数据:

为了建立这个模型,我需要许多偷垒情况及其结果的例子。幸运的是 Kaggle 有这样一个由 Sportsradar 提供的数据集。这个 MLB 数据集托管在谷歌的 Bigquery 平台上,包含了 2016 赛季每一场比赛的信息。我最终将这些数据上传到 PostgreSQL 服务器,因为初始数据集包含 760,000 多行和 145 个要素,这对于加载到本地内存来说太大了。

在探索这个数据集的过程中,最初的一个怪癖是试图只提取基本窃取事件。最初,我试图通过在描述中对“steal”进行通配符搜索来找到它们:

 SELECT *  
  FROM baseball  
  WHERE description LIKE '%steal%';

但是这个查询太小了,因为它只返回了 500 个条目。例如,2017 年 MLB 赛季有:

The total of the top 10 teams was 1098 SB (stolen bases).

所以只有 500 个整数太低了。深入挖掘,我发现多个偷垒事件在描述中遗漏了信息。因此,我最终使用以下命令来查询偷窃事件:

 SELECT *
    FROM baseball
    WHERE rob1_outcomeid LIKE '%CS%'
    OR rob1_outcomeid LIKE '%SB%'
    OR rob2_outcomeid LIKE '%CS%'
    OR rob2_outcomeid LIKE '%SB%'
    OR rob3_outcomeid LIKE '%CS%'
    OR rob3_outcomeid LIKE '%SB%';

由于每个 rob(跑垒者)都有一个结果 id,通过寻找“SB”(偷垒)或“CS”(偷垒被抓)的出现,我就能够抓住偷垒事件。

有了 145 个特征,每个剧本都有很多可用的信息。虽然这些特征中有很多最终都不具有预测性,但有几个特征我认为是有信息的,但不能反映实时情况。例如,关于投球类型、投球速度和投球位置的信息对跑垒员来说非常有用。这些特征将允许跑垒者估计他们到达下一个垒大约需要多少时间。然而,在现实世界中,跑步者或管理者无法获得这些信息,所以我决定在模型中限制这些特征。

作为替代,我将来自方图的玩家统计数据加入我的数据集。具体来说,我利用了投手的投球类型分布统计数据作为投球类型和速度的代理,而击球手的平板训练统计数据作为投球位置的代理。这反映了跑垒员如何根据他们过去的倾向猜测投手会投出什么球。

数据清理:

虽然 Sportsradar 的数据很全面,但我仍然需要清理数据。该数据集包含 760,000+个条目,我必须对其进行过滤,以仅过滤出基本的盗窃事件。我取消了任何摘球活动或季后赛活动。我的推理是,偷球不同于普通的偷球,季后赛的行为也不同于常规赛的行为。这些数据削减留给我 3000+基地盗事件。许多功能,如游戏 ID,出席,venueName 也被排除在外,因为我觉得他们不会预测。

数据插补:

除了子集之外,还有一些条目缺少投手或击球手的统计数据。当所列的投手或击球手从 Fangraphs 统计中缺失时,就会发生这种情况。由于数据集的年份差异(2016 年与 2015 年),这是意料之中的。假设有 2016 年的球员没有参加 2015 年的比赛是合理的(比如菜鸟)。为了解释这些缺失值,我最终用从训练数据中计算出的相应中值来输入这些特征。

特征生成:

有了大量的分类变量,我最终不得不虚拟化许多特征,使它们能够被我的模型解释。在这样做的时候,我确保不会陷入虚拟变量陷阱 (DVT)。例如,为了确定击球手的惯用手,我创建了一个列“is_hitter_R ”,而不是两个列,因为这将落入该数据集的 DVT 中(只有一个击球手是双手并用的)。

我使用的另一种特征工程涉及 box-cox 变换。许多玩家统计特征不是正态分布和紧密分组的,所以为了纠正这一点,我应用了 box-cox 变换,其中每个特征都用优化的 lambda 进行了变换。

建模:

优化指标:

作为一名经理,这个应用程序可以尝试优化多个可能的指标。首先是最大化基础抢断的数量(最小化错误否定),然而这样的策略可能太冒险,因为那可能导致太多出局。第二是尽量减少被抓住的偷窃事件(尽量减少误报),但是这种策略可能过于被动,没有利用可能的得分机会。相反,我决定对 F1 进行优化,这将带来一个平衡的方法

型号选择:

在用其他模型进行实验后最大化 F1 时,两个模型表现最好:逻辑回归(LR)和梯度推进树

这两个模型最终在训练集上获得了相似的 F1 分数。因此,我选择 LR 模型有两个原因:LR 模型的特征重要性更容易解释,LR 模型的运行时间更快。如果我试图部署一个实时应用程序,后者会很重要。

功能重要性:

从 LR 模型来看,这些是每个结果最重要的特征:

BC refers to the box-cox representation of the feature

最主要的特征是跑垒员是否在一垒。在所有特征中,它的预测性似乎是第二接近的两倍。这在物理上是有意义的,因为一垒上的跑垒员在其他任何一个垒上都有更好的机会去偷一垒。

模型性能:

我的 LR 车型的测试 F1 成绩是 0.924。与测试分数的微小差异意味着我的模型对新数据概括得很好,没有过度拟合。学习曲线强化了这一点:

在完整数据集上重新训练模型,它能够生成以下混淆矩阵:

最终 F1 分数为 0.9354,模型性能正好介于训练和测试 F1 分数之间。解释这些结果的一种方法是将被抓到的偷窃(CS)事件的数量等同于本可以被挽救的运行次数。对于模型能够分类的 922 个 CS 事件,节省的运行的大概估计是 123 个运行。我利用了我在网上找到的这个回合来翻译每一次抢断尝试的比赛情况(除以 2 是保守的)。

有了这个模型,我还构建了一个交互式 Flask 应用程序,它可以根据用户选择的输入进行预测,如图所示

如果你想自己玩,你可以在这里访问

未来工作:

虽然我最终得到了一个工作模型,但是如果我想进一步扩展这个项目,我可以实现一些改进:

  • 多名跑垒员:用目前的模型,只能准确预测单个跑垒员事件。虽然如果有多个跑垒员,它可以预测盗垒的成功,但这种预测不能解释多次出局。
  • 跑垒员信息:我的模型目前没有考虑跑垒者的能力。因此,我想包括跑垒者的跑垒统计数据。可以利用的一些统计数据是一个跑垒员前一年偷垒的数量,以及像他们 40 码冲刺时间这样的指标。
  • 更多数据:我相信获取更多数据将有助于极大地改进这个模型。如果我从其他 MLB 赛季获得数据来纠正 CS 和 SB 事件之间的不平衡,我相信我会发现更多的预测特征。

这个模型和 Flask 应用程序的代码和数据可以在我的 Github repo 获得。

你的顾客应该被人类还是人工智能欺骗?

原文:https://towardsdatascience.com/should-your-customers-be-conned-by-a-human-or-ai-6a87fbecdefe?source=collection_archive---------14-----------------------

《礼宾》vs《绿野仙踪》MVP

“从我的脑海中,我会说你正在寻找一个博斯基,一个吉姆·布朗,一个戴西小姐,两个叶忒罗和一个利昂·斯平克斯,更不用说有史以来最大的艾拉·费兹杰拉!”

使用“礼宾”或“绿野仙踪”这样的行话感觉就像 11(或 12 或 13)罗汉在讨论他们将要实施的骗局,这是受到真实的信心诡计的启发。

MVP 和原型制作与诈骗没有太大区别。我们希望从前期投资很少的人那里获得诚实的反馈金,以避免构建一切。你应该考虑人们有什么问题以及他们的解决方案。

人工智能大会

谈到 AI 通常从奇点或它是如何变得神奇开始。当真正的讨论开始时,关注的焦点是自动化,因为它可以削减成本或节省人员。我们应该考虑人工智能如何成为辅助的、增强的、代理的,甚至是为人类需求而生成的。

通过 MVP,您可以了解人们面临的真正问题,因此您可以迭代地构建解决这些问题的东西。人类为机器提供目的。大多数情况下,人需要参与解决机器不能很好处理的异常情况。

对于具有人工智能的产品,你需要问一些重要的问题:你的客户会信任人类优先还是机器优先的系统?你想让人们期待一个有着各种怪癖的人会出现吗?还是想从机器上冷效率和缺乏偏见?

我们将讨论每个模型的优缺点,以及如何避免在构建人工智能、机器学习、深度学习和其他机器智能时的常见陷阱。

看门人

Connie, Hilton’s robot concierge.

“礼宾”是你自己解决顾客问题的方式。你把界面简化为人类和顾客之间的直接交流。以人性化的方式解决顾客的问题。

特别是,你正在学习如何通过自己动手来解决这些问题。在礼宾解决方案的情况下,最有价值的学习来自于接触所有你在构思服务时没有想到的案例。

人工智能通常会扮演自动化或辅助角色,帮助扮演门房的人更快地完成工作。随着时间的推移,服务得到了改进,使更多的人类任务从机械到复杂实现了自动化,并消除了决策过程中的干扰。

StitchFix 是一家采用礼宾模式来提供服务的公司的典范。随着时间的推移,他们在如何决定库存哪些服装方面变得更有创造力。 StitchFix 的算法帮助设计师决定给顾客送什么衣服。

Brad Klingenberg,造型算法总监,做了一个关于人工智能循环使用中的人类的精彩演讲。不仅仅是一个人工智能反馈周期,还有多个包括设计师、客户、仓库等的工具。:

当你需要大规模的时候,门房 MVP 技术就失效了。一般来说,这是一个很好的问题,但这表明你需要找到另一种方式来做事情,而不仅仅是增加人数。

当计划使用人工智能时,您可能无法访问数据,或者无法训练正确的模型来取代大量的人工干预。

绿野仙踪

《绿野仙踪》就是你让它看起来像是由一台机器完成的,但实际上是一个人在幕后操纵。你构建了一个服务的 UX 外观,看起来是全机械化的,但实际上是有人在幕后操作。当您知道基础知识并将其构建到外观中时,这是最好的,但不要假设很多例外。

客户的期望是,这是一项应该能够正常工作的服务。如果它不起作用,它会把错误很好地传达给他们。他们不期望与一个人(或自主代理)进行复杂的对话。

《绿野仙踪》人工智能 MVP 的强大之处在于,幕后的人类正在从交互中创建带标签的数据。人类将采取机器最终应该采取的理想行动。

Expensify ,一个伟大的费用管理服务,是他们收据智能扫描技术的一个很好的例子。当他们第一次开始解析收据的照片时,他们会自动做一些事情,但会使用 Mechanical Turk 来解析收据(除了一些争议)。如果你不熟悉机械土耳其人,这是亚马逊的一项服务,它将短期任务外包给真人,每项任务收取几分钱。

MTs 人工协助存在一些与零工经济相关的问题。当你不知道人类在做这项工作时,人们不会担心把他们当人看待。

虽然《绿野仙踪》并不总是适合这项服务。大多数聊天机器人就是一个很好的例子。他们在与客户的对话中提出了自动化系统的想法,但最初确实需要人类来驱动大部分系统。这是对《绿野仙踪》的错误使用,因为你没有正确设定期望值。

门房大战绿野仙踪

总之,MVP 模型最大化了不同的东西,但仍然试图抓住客户需求的核心。

你对顾客和他们的问题了解得越少,礼宾部就能更好地帮助你发现问题。

你认为你越了解你的顾客和他们的问题,《绿野仙踪》就能越好地帮助你验证和否定这些知识。

关于这两位 MVP 的更深入的背景,请查看由艾伦·程蚱蜢牧人发表的一些伟大的帖子。

人类优先还是 AI 优先?

Human head and horse body or horse head with human body?

除了了解你的客户和他们的问题之外,你还可以测试他们对人类优先或人工智能优先界面的感受。不管怎样,你都应该建造结合了人类和机器精华的半人马系统。

当考虑这两个选项时,你需要考虑随着时间的推移你将建立的信任。再问一次:你想让人们期待一个有着各种怪癖的人是可以得到的吗?还是想从机器上冷效率和缺乏偏见?

最后,它归结为你试图融入人们生活的利基。当与客户谈论你的 MVP、进行用户研究或测试你的原型时,这里有一些问题:

  • 你更信任谁来做这件事:人还是机器?为什么?上一次是什么时候?
  • 你更相信专家还是机器?为什么?上一次是什么时候?
  • 解决这个问题时,异常有多重要?你上一次不得不处理异常是什么时候?
  • 上次出了问题,你需要知道什么?什么类型的解释有帮助?哪些类型的解释没有?

Empathy Mapping for the Machine during our NYC Media Lab Summit workshop.

和你的最终客户一起跑步锻炼也是有益的。在 Philosophie,我们已经使用机器的移情映射来帮助理解与服务交互的人类的期望。混淆映射可以帮助理解系统的错误案例如何影响客户结果。这些练习通过询问与客户实际需求相关的注重结果的问题,避免了人工智能术语。

人类应该在处理异常的循环中,但我们应该始终考虑如何以有意义的方式解决人们的问题。你需要考虑你的客户是想要一个人还是一台机器来帮助他们解决问题。

连体网络和三重损耗

原文:https://towardsdatascience.com/siamese-network-triplet-loss-b4ca82c1aec8?source=collection_archive---------3-----------------------

介绍

深度学习迅速崛起到人工智能的前沿,这是由大量可用数据推动的。深度学习概念在它所应用的几乎所有用例中都表现得非常好,例如计算机视觉、医疗保健、NLP 等。但是,当缺乏可用的训练数据时,它很难执行。在许多用例中,模型可用于训练的数据量相当低,这阻碍了模型学习有助于预测的特征的能力。一个这样的用例是你为一个组织建立一个面部识别系统。

一次性学习

一次性学习是从单个样本中学习表示的技术。以前面提到的例子为例,假设有一个组织,它想要一个面部识别系统来允许其员工进入大楼,而您被赋予了构建这样一个系统的任务。这项任务的问题是,组织可能不会为每个员工提供超过 10 张图片。因此,构建和训练一个典型的卷积神经网络是行不通的,因为它无法学习给定数据量所需的特征。所以,这是一个一次性的学习任务,你可以建立一个相似度函数来比较两幅图像,并告诉你是否匹配。

假设,左边的图像是该组织员工的脸。由于没有太多的数据来构建 CNN,您可以构建一个相似性函数来比较右边的图像和左边的所有图像。相似性函数将返回一个值,如果该值小于或等于一个阈值,您可以说这两个图像是相似的,否则它们不是。

暹罗网络

在暹罗网络中,我们获取一个人的输入图像,并找出该图像的编码,然后,我们获取相同的网络,不对权重或偏差进行任何更新,并输入不同人的图像,再次预测其编码。现在,我们比较这两种编码来检查这两个图像之间是否有相似之处。这两种编码充当图像的潜在特征表示。同一个人的图像具有相似的特征/编码。利用这一点,我们比较并判断两幅图像是否是同一个人。

三重损失

你可能想知道,如何训练网络?您可以通过获取锚点图像并将其与正样本和负样本进行比较来训练网络。锚图像和正面图像之间的相异度必须低,而锚图像和负面图像之间的相异度必须高。

Triplet Loss Funciton

上面的公式表示三重损失函数,使用该函数计算梯度。变量“a”表示锚图像,“p”表示正图像,“n”表示负图像。我们知道 a 和 p 之间的相异度应该小于 a 和 n 之间的相异度。另一个称为裕度的变量是一个超参数,它被添加到损耗方程中。Margin 定义了相异点应该有多远,即如果 margin = 0.2 并且 d(a,p) = 0.5,那么 d(a,n)应该至少等于 0.7。边距有助于我们更好地区分两幅图像。

因此,通过使用该损失函数,我们计算梯度,并且在梯度的帮助下,我们更新暹罗网络的权重和偏差。为了训练网络,我们取一个锚定图像并随机采样正图像和负图像,计算它的损失函数并更新它的梯度。

结论

使用这样的新方法,深度学习正在不断缩小人类水平表现的差距。我相信在几年之内,人工智能甚至可以在其应用的某些领域超越人类水平。因此,人工智能和人类一起可以拯救生命,让人们的生活更轻松。

确认

所有图片均取自吴恩达深度学习课程

暹罗网络和斯图尔特·威茨曼靴子

原文:https://towardsdatascience.com/siamese-networks-and-stuart-weitzman-boots-c414be7eff78?source=collection_archive---------14-----------------------

在之前的一篇文章中,我写了如何使用 R-CNN 模型来检测和分割出第二阶段模型要使用的衣服。在他的文章中,我用 Pytorch 暹罗神经网络建立了一个第二阶段模型的例子。这个想法是,通过结合这两个模型,你可以获取一个原始图像,只分割出衣服,然后将这些衣服与衣服项目数据库进行匹配,以找到类似的项目。

因此,这篇文章的第一部分将重点放在建立暹罗网络上,在接近结尾时,我将展示一个使用我的细分模型的输出的例子,以及暹罗网络如何从鞋子推广到它从未见过的其他物品。

什么是暹罗网络,我们为什么要关心?

暹罗式网络的目标不是对对象进行分类,而是确定项目是相似还是不同。这些真的可以是任何东西。脸书用它们进行面部识别,最初的应用是签名验证,我已经用它们来看艺术家风格游戏角色

你通过初始化两个网络“塔”来训练暹罗网络,其中你保持它们的权重相等,并通过每个塔馈送输入来进行成对比较。通过最小化相似输入之间的距离和最大化不相似输入之间的差异,训练网络来确定呈现给它的两个对象是相同还是不同。

Image of a siamese architecture for facial recognition by Andrew Ng in his deep learning course

暹罗网络没有回答经典的分类问题,X 是什么?相反,它们回答了这个问题,物体 X 和 Y 相似吗?

也就是说,我认为有理由问,如果你可以训练一个标准网络来进行这些识别,为什么还要费心去构建一个连体结构来进行成对比较呢?

作为回应,暹罗网络有许多我认为非常有用的特性。最主要的一点是,他们能够超越他们所受的训练进行归纳,能够分辨出他们不一定接触过的不同阶层之间的差异。另一个特性是,由于它们可以推广到没有被明确训练过的类,暹罗网络不需要每次被要求观察新事物时都被重新训练。

下面看一些网络认为相似然后又不同的鞋子的例子。

Lower scores indicate similarity, so the network finds these to be similar! I guess these could be similar?

在上面的例子中,模型为每只鞋生成嵌入,并且嵌入之间的欧几里德距离很小。所以网络认为这些鞋子相当相似。

Higher score and yep, these are dissimilar

技术实现

在这篇文章中,我用 Pytorch 在 jupyter 笔记本上建立了我的暹罗网络。我使用了一个自定义数据集函数,从头开始训练网络,并在笔记本上进行测试。

在 github 这里随意查看笔记本

我从网上收集了 220 张鞋子的图片,并把它们分成不同的款式。我用了 6 个类别“鞋跟”、“靴子”、“便鞋”、“凉鞋”、“运动鞋”、“平底鞋”。暹罗网络基本上是通过展示几双鞋来训练的,它必须判断这两幅图像是否来自同一类别。

jupyter 笔记本中的 SiameseNetworkDataset 类本质上是通过索引引用给定的图像,并将它与数据集中的另一个图像配对。它返回图像对和目标 0 或 1,这取决于它们是否匹配。在训练过程中,该数据集被调用来生成样本,并显示了暹罗网络的另一个有用特征,其中数据集的有效大小远高于其实际大小。在这种情况下,我有 200 个左右的训练图像,所以当你选择第一个图像时,有 199 个其他图像与之配对。所有这些都是有效的成对比较,可以在训练中使用。总的来说,暹罗网络的这一特点让你可以用很少的数据来训练它们,但更多的数据仍然更好。

对比损失函数本质上测量两个输出之间的欧几里德距离,并相应地调整它们,以使相似图像之间具有更短的距离,同时增加不同输入之间的距离。

These are dissimilar

训练循环运行了 50 个纪元,在我的 Nvidia 1080 GPU 机器上完成可能需要一个小时。

很酷…但是有点不实用?

我同意这一点。实际上,必须对数据库中的所有内容进行成对比较是非常不切实际的。例如,如果你有数百万张图片,你会在几个小时或几天内找到匹配,这太可怕了。因此,我们需要找到一种方法,使用暹罗网络的专业化来确定相似性,这种方法并不可怕。

退一步说,在机器学习的许多领域,我们发现如果我们能够以一种有意义的方式浓缩样本的表示,它可以极大地帮助我们的分析。原始图像非常大,即使将彩色图像调整到 224x224 像素,也意味着要浏览 15 万个值(224x224x3)。你也可以把它们描述为非常稀少,就什么信息对我们真正重要而言。因此,如果您可以创建一个有用的嵌入来在一个不太复杂的空间中表示该图像,那么您可以使用其他方法/模型非常快速地匹配相似的图像。

暹罗网络允许你很好地扮演这个角色,创建图像的嵌入,因为它们被优化以确定相似性。您可以输入 150K 的原始图像值,并获得 128 个值的输出嵌入(这是我的网络输出向量的长度)。然后,当您将该图像与另一个图像进行比较时,您可以看到输出嵌入的 128 个值是多么相似。

举个例子,拿下面这张鞋子的图片,通过暹罗网络传递。鞋子作为一个 224x224x3 的数组输入,并作为一个长度为 128 的向量输出。我觉得这个挺优雅的!

Example of output embedding of an image of a high heeled shoe. I am unsure what the 128 values map to, but to me that does not really matter because they turn out to be quite effective.

在大规模环境中,您可以使用一个经过训练的暹罗网络来提取数据库中所有图像的特征嵌入,然后您可以构建其他模型或应用其他方法来匹配该数据库。这利用了这样的事实,即通过暹罗网络馈送的相似图像也将具有相似的嵌入,并且这扩展到它从未暴露的图像/类,并且仍然为相似的图像产生相似的嵌入。

讨论暹罗网络结果

我已经展示了这个网络的一些成功之处,但是展示它的局限性也很重要。因为这个网络是在一个非常小的数据集上训练的,所以在很多情况下它仍然不能很好地评估。

These are similar which is good

These should also be similar but they are not

While these are not super similar, they rate more similarly than I think they should

这三个例子展示了这个网络的一些弱点,这些弱点是在一小组图片上训练出来的。随着更多的数据和更长的训练时间,这些问题可能会得到解决。

另一个问题是,图像在技术上可能是相似的,但是从不同的角度看将会返回不同的结果。这个问题在像面部识别这样的情况下得到解决,其中向模型提供人脸的多个角度以进行优化,从而允许模型处理侧视图或部分障碍。在下图中,我将每个人都标记为“游手好闲者”,因此从技术上讲,它们应该是相似的,但是模型将它们评估为完全不同

我发现的另一个有趣的事情是,当我使用边界框而不是来自 Mask R-CNN 模型的分段靴子时,它实际上与靴子的分段图像非常相似。这可能是因为背景相当干净,但如果这在其他图像中是一致的,这意味着您可能不需要全掩模 R-CNN 模型,并且可以使用较轻重量的对象检测模型并使其表现良好。如果这是一个持续的趋势,这是一个很酷的发现!

然而,我跑题了,这篇文章的目的是要说明,你可以在第一阶段模型中分割图像,将它传递给第二阶段的暹罗网络,然后将它与一些已知的图像进行匹配。虽然这个网络很小,有一些问题需要改进,但在结合我的 Mask R-CNN 图像分割模型进行测试时,它仍然表现很好,因此无需进一步讨论…

欢迎来到丛林!

例如,如果一家公司希望能够从用户那里获取一幅野外图像,并将他们商店中与图像中的服装相似的商品返回给用户。给一个像下面这样的原始图像供料是相当困难的,因为在这个图像中有大量的“噪声”。在这种情况下,噪音意味着除了衣服以外的任何东西。即使您能够对图像中不同类型的服装进行分类,也很难在没有首先定位到这些商品的情况下返回良好的相似商品。

因此,为了解决信噪比问题,你可以使用一个图像分割模型,就像我的客户训练的多类掩模 R-CNN 模型。它穿过图像并定位到衣服上。

然后,您可以使用这些生成的图像掩码只返回衣服项目。

最后一步是打电话给我在这篇文章中概述的关于这些物品的暹罗网络,这样你就可以寻找类似的已知服装物品。

为了便于说明,这里有一个使用这些成对比较的例子。左边的鞋子可以代表我们正在测试的已知鞋子中的图像,右边的鞋子是从上面的原始输入图像中提取的靴子。

这第一对图像没有很好的分数,所以我们会说它们不相似。

在这种情况下,您可以在数据库中返回 Stuart Weitzman 的靴子,它与原始输入图像中模型上看到的靴子相似,也是 Stuart Weitzman 的靴子。

超越他们的训练

我已经说过,暹罗网络是有用的,因为它们有能力超越他们所受的训练进行归纳。因此,为了展示这一点,在我运行分割模型的原始图像中,还有一个方格手袋。由于我从原始图像中提取了这个手提包,所以我决定进行一些测试,并发现经过鞋子训练的暹罗网络在寻找类似的包时表现良好。

第一个图像右边是提取的手提包图像,左边是与之匹配的黑色手提包。该网络发现他们很不相似,得分为 0.77

现在看第二张图片。我们再一次在右边找到了提取的手提包,在左边我在网上找到了一个格子手提包的图片。该模型将这些评估为具有 0.43 的相异分数,这意味着它认为它们相当相似。

这最后一点是一个很酷的小测试,我不确定我在一小组图像上训练的暹罗网络是否能够通过。我猜它有助于方格图案使包相当独特。然而,这仍然说明了暹罗网络可以推广到它们没有明确训练过的图像类型的想法。

结束语

在这篇文章中,我介绍了什么是暹罗网络,为什么它们有用,我是如何建立这个网络的,以及如何使用一个网络作为第二阶段的模型来让你将来自野外的图像中的物品与衣服库中的物品进行匹配。

这篇文章结合我以前的图像分割文章,展示了如何建立一个可能的完整的端到端深度学习管道,以解决各种领域中一些非常真实的商业问题,而不仅仅是服装。它甚至不一定是我在这里展示的具体型号。

对于第一阶段的模型,您可能不需要完整的图像分割模型,可能只需要一个简单的对象检测模型就可以了。这将使训练更快,因为建立对象检测数据集比建立完整的图像分割数据集更容易。

在第二阶段,我展示了一个暹罗网络如何有助于构建特性嵌入。我真的很喜欢暹罗网络如何能够进行超出其训练范围的概括,但你可以使用一个经过训练的模型来完成这项任务,该模型可以对特定领域的图像进行分类,然后重新调整它的用途以进行特征提取。就我个人而言,我喜欢在这里使用暹罗网络,因为它被明确地训练来进行相似性比较,而不是重新利用另一个模型来做这项工作。

十年 Twitter 数据的可视化(第一部分——数据集)

原文:https://towardsdatascience.com/side-project-10-years-of-twitter-8fd5724f7b1a?source=collection_archive---------6-----------------------

本文是数据可视化项目生产笔记的一部分:

[## @tanyofish 的 10 年推特

10 年间超过 10.2 万条推文的可视化

tany.kim](http://tany.kim/twitter)

10 年前的今天,我开通了我的推特账户,从那以后我已经发了超过 102,000 条推特。是的,我经常发微博。这是一个私人账户,我主要用韩语发微博,所以请不要马上离开来关注我。

作为一名数据可视化设计师,我一直想从我自己的推文中做出一些东西,可能是我能获得的最个性化、最大规模和最强大的数据集。 在实际的设计和编码之前,我一直在思考这些数据的哪些方面会让自己设计起来有趣,让别人开心。在这个项目开始时,我想发现的包括:

  • 我真的经常发微博吗,即使是在工作时间,甚至是刚睡醒的时候?
  • 我多久用 Twitter 和朋友聊天一次?
  • 电脑和电话,我更常使用哪一个发微博?
  • 我和 Twitter 朋友的关系网是什么样的(它更具探索性,最终会有很多想法)?

在这篇文章中,我描述了我想用这个可视化项目展示什么,以及相应地我是如何生成数据集的。

获取和清理数据

我认为有两种方法可以检索你所有的推文——1)下载并存档你的推文,这个选项可以在你的帐户设置下找到,2)使用 Twitter 的 Rest API。众所周知,没有一个数据集的格式是完美的,没有丢失的信息,所以我必须彻底清理数据集。我可以写一篇关于这个过程的全新文章,但是我的 Python 代码可以更好地解释这个过程。几个亮点是

  1. 关于时间戳,来自下载档案的旧推文数据只有最新的,而不是小时、分钟或秒。因为我想知道一天中我发推特的时间,所以我需要这些数据。为此,我使用 rest APIs 获取每条 tweet 的所有完整元数据,这些 tweet 的 ID 可以在存档中找到。
  2. 再说一次,我想知道我什么时候发微博。每条 tweet 的元信息现在包括精确到秒的时间戳,但是,它是用 UTC 表示的,所以我必须将所有的时间戳转换成正确的时区。为此,我制作了一个 JSON 文件,列出了我过去 10 年居住和旅行过的地方,包括时区

为此,我查看了护照上的印章,并查看了我的机票预订电子邮件。因为我不知道我搬到另一个时区的确切时间,所以我把搬家/旅行开始日期的所有推文都转换到了新的时区。我知道这不是完美的清理,但考虑到整个数据量(+10 万条推文),这是可以接受的。

一条 tweet 的 JSON 数据如下所示:

[## 获取状态/查找— Twitter 开发人员

编辑描述

dev.twitter.com](https://dev.twitter.com/rest/reference/get/statuses/lookup)

数据集:“推特”和“朋友”

现在我有+102K 的 tweets,包含正确的时间和时区信息以及其他元数据。那接下来是什么?设计数据可视化时,明确您想要传递的信息是至关重要的。澄清消息并不意味着你限制用户将要探索的见解或故事,而是帮助你找出你必须关注原始数据的哪些方面。

在对我的推文数据进行了大量的迭代和构思之后,我最终得到了两个主题——推文和朋友

小鸟叫声

Tweets 视图显示了我在宏观和微观角度发推文时的。首先,它用柱状图显示了每月的推文数量。在这个条上,一个滑块被覆盖以选择时间跨度,在该范围内进行进一步的分析。关于所选的时间跨度,我添加了一个可视化的 7 天 24 小时矩阵,每个 7X24 块代表我在所选的时间跨度内,在所选的小时和天的组合中发了多少条推文。

当然,发推的时间告诉了我一些有趣的事情(例如,我一起床就发了很多推),我也想利用一条推的所有元数据。在硕果累累的数据中,我重点关注了四类——交互、媒体、语言、来源

互动有三种类型——提及、转发和引用。提及是对另一个用户的直接引用,通常是以@开头的推文,带有用户名。转发和引用是引用其他公开推文的方式。

媒体有四种类型— 照片、视频和网址。事实上,一条 tweet 可以同时包含照片和 URL,但是在这个分析中,URL 意味着 twee 只包含外部源的链接。

正如我之前提到的,我主要用韩语发微博,但是在乞讨的时候,我主要用英语发微博。所以我加了这一类,看看语言超时使用的变化。这两种语言——朝鲜语和英语——是我包含的语言类型。分析中没有指定其他或未定义的(主要是纯表情符号推文)语言。

Source 指的是我发微博时使用的媒介。一些例子是“iPhone 的 Twitter”(iOS 的官方应用程序)和“Twitter Web 客户端”。在这个分析中,我将这些来源归纳为两大类— 大屏幕和小屏幕。大屏幕包括我用在大屏幕上的网络客户端,那是我的电脑。小屏幕意味着包括 iPhone、Android 和 Windows Phone 应用程序在内的移动设备以及移动浏览器。如果您通过第三方服务上的共享按钮发布推文,源将被指定为服务,例如“Ask FM”或“YouTube”这些第三方来源从技术上来说来自大屏幕或小屏幕,但我没有包括这些,因为我想将来源视为我用于推特的物理设备。

在挖掘从早期步骤获得的数据到前端使用的最终数据集时,我希望优化文件大小和格式,以便 Javascript 代码完成最少的工作。现在一个单独的 tweet 数据如下所示。数组第二项中的单个字母代表类别的类型(例如,p 代表照片,k 代表韩语)。整个+102K 的最小化数据的大小现在是 3.6M!

*["2017-04-15 13 6", ["p", "f", "k", "s"]]*

老友记

我在推特上认识了很多很棒的人。作为一个 10 年的 Twitter 用户,我没有太多的追随者,主要是因为我大部分时间都在保护我的账户。我上面描述的分析显示,我有 349 个好友,这还不包括已删除的账户。最初我想包括那些被删除的账户,尽管我无法检索他们唯一的数字 Twitter ID。然后我意识到,如果我从我的 tweets 文本中手动追踪所有那些被删除的帐户(大部分包括@),可能会违背那些朋友在 Twitter 上抹去他们痕迹的意图。因此,349 个好友是截至 2017 年 4 月保持其账户活跃的人。

通过分析我的 Twitter 好友,我可以发现哪些有趣的事实?我的一些即时想法是我给他们发了多少封短信,以及我和他们聊了多久。通信的计数和持续时间很容易被挖掘;Count 是指对特定朋友自己的推文“回复推文”的次数。当朋友的 ID 被简单地包含在推文中时,她或他的 ID 不被包含在内;持续时间是第一次提及和最后一次提及之间的时间差。

除了计数和持续时间,我想做一些更个人化和面向社区的事情。

出于一些个人方面的考虑,我手动将每个朋友标记为以下人员— 1)我在现实世界中首先遇到的人,2)我仅通过 Twitter 交谈的人,3)我首先在 Twitter 上遇到的人,然后是本人,4)非人类(即机构或事件账户)或名人。在可视化中,这四个类别是可视化的颜色编码。一个朋友的数据简介是这样的:

*{
  "name": "exampleUser",
  "points": [
    [
      "2017-04",
      32
    ],
    [
      "2017-03",
      69
    ],
    [
      "2017-02",
      27
    ]
  ],
  "first": "Feb  6, 2017",
  "count": 128,
  "duration": 53,
  "id": "931827750",
  "common": 9,
  "category": 2
}*

Twitter 允许我通过连接到我朋友的朋友来建立我的网络。考虑到 Twitter 的这种性质,我想知道当我与其他人交谈时,都有哪些人参与其中。当一个回复的线程生成时,通常在一条推文中会提到多个 Twitter 账户。通过分析这些提及,我得出了一个社区的数据集— 这些人参与了与朋友的对话。

最后,我分析了我所有 twitter 好友的计数、持续时间和共享好友数量的分布。朋友部分更像是一个视觉分析工具,超越了一组交互式可视化。可以用多种方式选择朋友,包括传统的搜索/下拉菜单,以及可视化的交互式特征。选择一个朋友会触发所有这些可视化的更新,并指定该朋友的计数、持续时间和共享朋友数量的排名。

下一步是什么?

该项目现已在 http://tany.kim/twitter可用

在下一篇文章中,我将描述数据可视化的设计过程,包括可视化形式和交互的决策。

Onepanel.io GPUs 上的傻股票交易

原文:https://towardsdatascience.com/silly-stock-trading-on-onepanel-io-gpus-51cde1772bd1?source=collection_archive---------11-----------------------

ur 首席执行官 Mathieu Lemay 最近写了一篇关于各种流行的人工智能模型在罗夏墨迹测试中看到了什么的文章。那很有趣。这让我想到当只有噪音时,我们人类能看到多少信号。我想看看当我们使用深度学习通过首席执行官的个人资料照片预测一家公司的股票市场表现,并使用首席执行官的星座交易股票时会发生什么。我们与 Onepanel.io 合作,在 GPU 上实现这个想法。

Using AI to interpret horoscopes and generate alpha. Mary Kate MacPherson made the bot a logo and everything. The tagline is “Your Fortune Awaits!”

当然,这些都是可怕的想法。你能从这里学到的很简单:坏主意会导致糟糕的模型性能。更重要的是,在数据科学确认该项目在统计学上有意义之前,你不能进行机器学习。

我将使用 Onepanel.io 平台带您了解这个人工智能项目从注册到项目执行的全过程,这会让您感受到我们从他们的解决方案中获得的价值。给你一点背景知识,我非常喜欢 DigitalOcean,但是他们没有 GPU 实例。当您想要在分布式协作中为深度学习项目启动一个开发实例时,AWS 很棒,但是很贵,而且有些机械,即使是从 AMI。我们从 Onepanel.io 中得到的,你将在本文中看到的,是一个平台,我们可以在这个平台上轻松地在一个 GPU 项目的团队中协作,而无需安装并运行所有的库,共享密钥等等。这是一个很棒的界面。

这篇文章的代码可以在 Onepanel.io 这里找到:https://c . onepanel . io/Daniel-lemay-ai/projects/star-sign-trade-stocks/code

开始:为您的团队旋转 GPU 的 10 个步骤

根据星座买卖股票的第一步是通过注册程序

不要忘记点击你的电子邮件中的链接来验证你的电子邮件地址。如果你被提示输入信用卡,那是为了支付你将要启动的 GPU。有指令做这一切东西,但是 TL;像我这种 DR 的人,就是想飞过去,有一个有 GPU 库,源码控制,安全等等的工作环境。

Log in and make a project

Set the details of the project

Create a project workspace

Set the workspace details

The instance will take a few minutes to spin up, so note the time message and the status color

While we wait, let’s invite our team members to the project. No SSH key exchange required!

Great! Our instance is up. Let’s run Jupyter. Notice that tensorboard and terminals are also available with one click in the LAUNCH menu.

Make a new notebook to show the GPU is working

Copy-paste example code from keras.io Running!

这两条线显示 GPU 正在工作:

from tensorflow.python.client import device_lib
print(device_lib.list_local_devices())

OK. It all works!

我们现在有了一个低成本的 GPU 实例,安装了所有正确的东西。那很容易。我们能够共享对项目的访问,这样我们就可以在团队成员之间进行协作。现在是时候用系统做项目了!

利用占星术进行投资组合管理

让我们来看看星座和股票交易之间的关系是如何吸引人,但却毫无意义。即使我们找到了相关性,它们也应该是随机的,而不是因果关系。那是因为星座是随机的,而随机,虽然经常很优雅,却什么都预测不到。先从根据各公司 CEO 的星座投资股市开始,看看会发生什么……好玩!

[## dcshapiro/onepanel

GitHub 是人们构建软件的地方。超过 2800 万人使用 GitHub 来发现、分享和贡献超过…

github.com](https://github.com/dcshapiro/onepanel)

搜集星座:建立一个数据集

我使用 Travis Riddle代码从《纽约邮报》获取星座数据。我只是做了一些修改,让它能在 Python 3 中工作。我还对脚本做了一点修改,使它每天抓取所有的标志,而不是一次一个标志。如果主机生气并阻塞了我的虚拟机的 IP 地址,这使得脚本更容易恢复。我没有使用花哨/昂贵的 IP 轮换策略,我只是让我们撕开看看会发生什么。

首先,我在 3 天的范围内运行脚本。效果很好。接下来,我在 2014 年 1 月 1 日到 2017 年 12 月 31 日的日期范围内运行它。结果进来的时候就存了,以防万一。只坠毁过一次。我继续说道。完成了。那是 4 年的星座数据。我很确定这属于公平使用条款,但出于版权原因,我不会发布数据集。

Here is a look at the raw horoscope text, publication date, star sign, and sentiment

Horoscope sentiment is a bit more positive than negative, which makes sense for a feel good marketing thing

共有 17,186 行星座数据:4 年中的每一天对应一个星座(123654 = 17,520)。所以我们每年会错过大约 7 天的星座运程。我假设那是没有论文发表的时代,所以没有占星术。现在我们有了“我能预见未来”的数据,让我们来学习数据和市场之间的关系,每天根据这些“信息”进行交易。

仅供参考, Onepanel.io 有一个平台的数据集部分,你可以毫无痛苦地获取数据集来训练模型。它有像 MNIST 和许多其他的东西,一般来说比你自己把数据拉进一个公共数据集要少。

All the data.

您还可以将 S3 桶或任何东西捕捉到正在运行的实例上,或者将您自己的数据集添加到系统中。

我们通常解释文本的方法是使用 spaCy 将星座文本转换成向量,或者使用 FastText 训练一个定制的嵌入模型,然后训练一些神经模型从输入数据中预测东西。但是让我们简单点。我使用 TextBlob 将文本转换成基于情感的决策。这并不完全是现代投资组合理论。要使用深度学习来计算真实资产管理的资产分配,你需要大量的 GPU 和专业知识。对于这个项目,我们决定保持它的美好和简单。

from textblob import TextBlob
def sentiment(horoscope):
    analysis = TextBlob(horoscope.lower())
    if analysis.sentiment.polarity > 0:
        return 1
    elif analysis.sentiment.polarity == 0:
        return 0
    else:
        return -1

为了决定我们是否应该交易,我们测量星座运势,如果它是积极的,我们买入一只股票(或者持有,如果我们已经在),否则我们卖出。我们把钱平均分配在首席执行官的星座运势为正的股票上。我们跟踪持有情况,以了解我们的投资组合价值随时间的变化。我们将该策略的盈利(亏损)与投资组合的同等权重买入并持有策略进行比较,看看我们的积极策略是否跑赢了市场。让我们非常慷慨地假设费用是 0 美元,尽管实际上费用和税收在主动自动交易策略中起着巨大的作用。

Our data source gives a whole new meaning to non-traditional data sources used to make investment decisions.

现在,在我们进入图表之前,我们需要选择一个投资组合,并获得首席执行官的生日。

我们用 stocker 来模拟股票市场。最后,由于 stocker 中的怪异之处,我们只是从 stocker 中取出股票历史数据集,并使用这些数字来做我们自己的回溯测试模拟。系统中的公司列表(tickers)可以在这里找到,这是寻找首席执行官的起点。

One CEO per astrological sign. What could possibly go wrong?

结果

我们模拟了 5 年的每日交易,以下是我们的发现:

**Psychicbot**
Initial Investment: $100.00
Final Balance:      $200.34
Annualized Return:    19.0%

我们赚了$$$!?一个基于星座的交易机器人是如何赚钱的?

Hold on….

所以,那是 理应失败的 。为什么会成功?好吧,让我们来看看这是否只是我一生中最大的牛市中的测量结果。让我们后退一步,将结果与这些股票以及 IVV 的基准进行比较。如果我们赚了钱,但少于买入并持有等权重投资组合,或 ETF 的市场,那么这是一个赚钱策略,比简单地持有市场赚得少。这个想法叫做 alpha 。从逻辑上讲,我们不应该从没有信息的东西中赚钱,所以 alpha 应该是 0 或者负的。所以,让我们来看看…

**Equal Weight (EQWT)** Initial Investment: $100.00
Final Balance:      $177.75
Annualized Return:    15.5%

我们比 EQWT 多赚了$$$!?

And this is how the IVV index did over the same period… See: calculator here and growth rate formula here.

所以……IVV 的年增长率为 9.86%,这大约是同等权重结果的 2/3,大约是我们星座情绪机器人回报的一半。

那么…为什么用星座运势交易股票比传统投资策略更有效呢??魔法?

让我们总结一下我们的现状:

**Annualized Return:**IVV                 9.9%  
Equal Weight       15.5%
Psychicbot         19.0%

A quick look behind the curtain.

为什么会成功?

答案:偏见+运气+不收费=假

偏见是一种狡猾而微妙的东西,它会毁掉一个精心设计的实验。这里的偏见是,我们只在投资组合中包括首席执行官几年没有变化的股票,而首席执行官的变化通常意味着公司的问题。这给了 EQWT 一个优势。我们当时不可能知道这些公司不会更换 CEO。所以,我们有点不小心作弊了,选择稳定的股票导致我们选择表现良好的股票。这种策略的偏差只是相对于 IVV 而言的。对于 EQWT,我们投资于相同的股票,因此我们的情绪机器人最终在线上或线下的位置基本上是一个随机变量。

此外,我们假设费用为 0 美元。这太低了。在现实生活中,积极的策略,我们可以支付 50%至 100%的总利润的费用。有时更多。净收入在这里很重要,因为净利润被再投资,所以有复合效应。积极策略中较低的费用会带来更高的利润。相比之下,IVV 等 ETF 的费用非常低,EQWT re-balanced monthly 等策略的费用也非常低。

Source: Chapter 3 of Narang, Rishi K. Inside the Black Box: A Simple Guide to Quantitative and High Frequency Trading. Vol. 883. John Wiley & Sons, 2013.

那么,你应该相信这种基于占星术的投资策略吗?绝对不行!好运并不意味着好主意。

Bias is totally a thing (credit: xkcd)

有时,一种方法的不可能性或愚蠢性并不像这里介绍的基于占星术的投资组合管理方案那样明显。有时候很难知道这种方法没有价值。如果你想证明一个策略是错误的,有时你会遇到一些策略,它们的阿尔法值来自偏见,或者仅仅是运气。想象一下,在根据星座运势交易时,有多少 12 只股票的组合,谁的首席执行官生日正确,而且赚的钱不比 EQWT 和 IVV 多。甚至像修改测试周期这样简单的事情也会让“阿尔法”蒸发。你可以用数字撒谎,但纸牌屋很快就会倒塌。当策略转移到纸上交易时,回报不会实现。或者,当参数被测试时,理论就分崩离析了。使用深度学习的真正投资组合管理(例如invest fai)不仅要对数字,甚至对数字所基于的假设进行严格的测试和再测试。阿尔法模型不仅仅是数字;它们是关于想法的。

这又是一次模拟,但这次考虑了使用滑索的交易成本:

Portfolio value using zipline. Initial value is 1 billion dollars. When taking into account fees, we lose almost $1e15 (Also known as $15,000,000,000) before swinging up to $2e10.

上面的图表看起来更真实。所以,基本上,因为我们不能负债 150 亿美元,这个模型在第一年就损失了所有的钱。即使我们一开始有 10 亿美元,我们也会全部输掉。之后的一切都无关紧要了。是的,它最终依靠杠杆推动市场上涨,但这是不相干的怪异之处,因为没有保证金账户让我们在那一点上仍然存在。现在我们终于可以看到这个策略是一个可怕的想法。即使存在知道哪些股票几年内不会更换 CEO 的偏见,以及在没有费用的情况下产生超额回报的运气,这种策略也会损失 10 亿美元。

现在你可能很好奇为什么收费这么高。开始了。如果你通过卖出其他 100 美元的股票来买入一只 100 美元的股票,你在买卖时要支付费用。比方说的费用是 1% ,尽管机构投资者的费用要低得多。这意味着我们通过卖出和买入移动 100 美元的成本为 1+0.99 美元,总共 1.99 美元(忽略按实际美元金额购买股票的量化误差)。所以我们需要在交易中获得 2%的利润才能达到收支平衡。即使费用只有几个基点,但公司仍然是有利可图的,因此该战略需要做得比机会更好,并有足够的利润来支付费用,以避免仅在费用上就达到 0 美元。

产生扣除费用后的净利润的策略是资产管理公司所依赖的阿尔法模型。这些模型需要大量的 GPU 计算能力来运行模拟,所以我们应该更多地使用这些强大的 GPU。

CEO 直面公司业绩

好的。所以我们展示了用占星术交易看起来像一件事(其实不是)。一些更具预测性的模型怎么样?现在,我们已经收集了 CEO 星座的数据集,让我们使用股票代码+“CEO”的图像搜索结果,获取数据来训练一个模型,以预测每家公司的回报。例如:“APPL 首席执行官”。我们知道这应该没有成功的机会。现在让我们通过做实验来证明它。

Image search result for “APPL CEO”

Gobbling up pictures from the interwebz...

首先,我们使用图像搜索 API 获取首席执行官的图像。我们可以使用谷歌的“知识图搜索 API”从公司代码中获取 CEO 的名字。我们还可以使用图像识别 API 或基于 dlib 的库来检查图像中的人脸,并丢弃没有人脸的照片。

让我们看看我们从什么开始:

显然,对于一些公司来说,刮刀没有得到任何结果,而另一些公司找错了人,比如奥巴马总统和公司的某个人站在一起。有时候照片完全不相关。我们通过过滤掉不包含人脸的图像来丢弃它们。受欢迎的人物会跳到这些文件夹中,因为他们与相同的 CEO 和公司关键词相关,例如“埃隆·马斯克”、“比尔·盖茨”、“比尔·阿克曼”、“沃伦·巴菲特”等等。在移除重复图片之后,我最终收集了大约 7GB 的图片进行分类。我们可以抓取多少图像没有真正的上限。你只要坚持下去,直到你不再喜欢它。图像文件的数量是 39,262。

我们收集了 2305 家公司的价格数据,其中 1596 家在测试期结束时价值更高。69%的公司价值更高。这还没有考虑股票分割或股息。另外,请注意 stocker 从 Quandl 获取数据,他们每天只允许您获取 50 个查询,除非您有帐户(免费的那种)。因此,没有帐户会导致代码停止运行。我们继续…

我们需要在 GPU 中进行这种将图像嵌入的处理。要将数据集上传到 S3 存储桶,请执行以下操作(使用真正的 AWS 密钥):

# install AWS cli
pip install awscli# set the AWS credentials
export AWS_ACCESS_KEY_ID=BLAHBLAHBLAHKEYGOESHERE
export AWS_SECRET_ACCESS_KEY=SECONDRANDOMSTRINGYTHINGHERE# upload files in current directory to onepanel-lemayai-datasets
aws s3 sync . s3://your-awesome-dataset/

并从 CLI 将数据集下载到实例,如下所示:

# set the AWS credentials
export AWS_ACCESS_KEY_ID=BLAHBLAHBLAHKEYGOESHERE
export AWS_SECRET_ACCESS_KEY=SECONDRANDOMSTRINGYTHINGHERE# download files in current directory 
aws s3 sync s3://your-awesome-dataset/ .

我们可以使用 Onepanel.io作业功能来完成这些 GPU 图像转换和分类任务。我在过去讨论过 SageMaker 如何比独立的虚拟机好得多,因为它们只在你关心的任务期间运行。作业以同样的方式工作,但是不会将您局限于定制的 SageMaker 库。

与此相关的是,SageMaker 在本地不可用,但 Onepanel.io 正在为整个平台开发本地私有云部署选项,这对我们的许多企业客户(例如政府、医疗和金融科技)至关重要,他们无法将其数据集迁移到公共云。

现在是有趣的部分。我们把图像转换成嵌入!如 keras 应用页面所述,我们可以将图像转换成嵌入向量。

第一步是知道层的名称。我们用下面的代码得到这个结果:

从这里我们知道我们想要的输出图层在最后,就在实际的分类任务之前。如果我们选择“展平”的输出,我们会得到一个非常大的形状(每个图像 25,088 个要素),因此我们在输出中选择第一个完全连接的图层的输出,该图层只有 4,096 个要素。

最后,我们可以将嵌入向量设置为输入数据 (x) ,将相应的盈亏价格设置为输出数据 (y) ,以训练一个 DNN (f) ,根据嵌入向量预测价格。每个预测都采用 y=f(x) 的形式。借助 test_train_split 函数,我们可以根据训练数据进行训练,并使用测试数据验证结果。

这是二进制分类的一个很好的例子,在 keras.io 网站的“二进制分类的 MLP”下也有一个很方便的例子。

下面是将图像数据集转换为 CSV 文件中的嵌入向量的代码:

下面是用于训练和测试二元分类模型的代码:

最后,结果如下:

Why are there more TRUE than FALSE?

为什么真的比假的多?我们知道这不是任何类型的集合不平衡,因为我们在代码中对此进行了修正。如果这个结果是真的,那么我们可以用 CEO 的脸来预测股市的赢家和输家……这是怎么回事??

事实证明,我们的刮刀刮出了许多小变化的相同图片(例如上面提到的沃伦·巴菲特和埃隆·马斯克),这导致了一些测试和训练数据非常相似。移除完全重复的图像并不是一个足够强大的过滤器来真正消除数据中的这个问题。有效地拥有同一个 CEO 的多个形象,并在培训和测试之间认出这些 CEO,就是作弊。所以,再次强调,不要因为结果好就相信结果好。相信他们,因为他们有意义,并帮助你预测事情。

如果你正在经历脚本和驱动程序安装的痛苦,或者通常不喜欢启动和运行机器学习基础设施的过程, Onepanel.io 可能会让你非常感兴趣。新功能会定期上线。这个解决方案被打包到一个简单的 web 界面中。它只是工作。因此,总之,在本文中,您从头到尾详细了解了一个机器学习项目,包括启动服务器、连接团队、收集数据集、对股票数据进行一些分析,以及以一些预测性的东西结束。你看到了你不应该仅仅因为投资策略赚钱就相信它们。

如果你喜欢这篇文章,那么请点击关注按钮,拍拍这个东西,看看我过去读过的一些文章,比如“如何为人工智能项目定价”和“如何聘请人工智能顾问”另外,查看 Onepanel.io

在下一篇文章中,我将介绍我们已经研究了很长时间的东西,它可以帮助企业在内部审计期间自动分析非结构化报告。

下次见!

丹尼尔

daniel@lemay.ai ←问好。
LEMAY . AI
1(855)LEMAY-AI

您可能喜欢的其他文章:

多任务深度学习的 3 种数据技术。

原文:https://towardsdatascience.com/silver-gold-electrum-3-data-techniques-for-multi-task-deep-learning-2655004970a2?source=collection_archive---------20-----------------------

TLDR;这篇文章对多任务学习技术进行了高度的介绍,然后概述了三种实用的数据准备方法,我称之为银、金和银金矿。

什么是多任务学习?

多任务学习 (MTL)是学习共享表征互补任务任务以提高给定目标任务结果的过程。

数据科学领域之外的 MTL 的一个很好的例子是健身房的组合练习,例如俯卧撑和引体向上,它们相互补充,以最大限度地增加全身的肌肉。

单独俯卧撑主要锻炼胸部,其次是背部。而引体向上主要锻炼背部,其次是上胸部。然而,当一起做时,引体向上和俯卧撑相辅相成,为胸部和背部提供比单独做时更好的增益。

为了更好地理解这个概念,让我们后退一步,回顾一下机器学习和深度学习的基础知识。

机器学习 ML 的目标是找到特性来训练模型,该模型将输入数据(如图片、时间序列或音频)转换为给定的输出(如字幕、价格值、转录)。在传统的数据科学中,这些特征通常是手工选择的。

A canonical example of a feed forward deep neural network.

深度学习(DL) 中,我们通过将我们的输入表示为向量,并通过一系列巧妙的线性代数运算将其转换为给定的输出,来学习提取这些特征。

然后我们使用一个叫做损失函数的等式来评估我们的输出是否是我们所期望的。该过程的目标是使用来自每个训练输入的损失函数的结果来指导我们的模型提取将在下一次传递中导致较低损失值的特征。

“多任务学习 (MTL)是通过组合****任务损失函数来学习共享表征以提高给定目标任务的结果的过程。”

通过在相关任务之间共享表示,我们可以使模型更好地概括每个原始任务。

例如,让我们看看两个 NLP 任务词性标注句法短语分块。如果我们使用相同的表示层,并通过结合我们的位置损失和分块预测来更新我们的权重,我们可以将我们的结果提高 0.7 的 F1 分数。当 MTL 模型共享所有相同的参数,但是通过在输出层直接组合两个或更多不同的损耗来更新时,这被称为硬参数共享

另一方面,选择性参数共享,利用下游任务的分级性质,并且仅在相关层更新任务损失。想法是上游任务的更好的表示将导致更好的整体结果。在我们的分块示例中,使用软参数共享导致 1.2 F1 分数比我们的独立结果高。

From left to right. F1 results on standalone chunking, MTL (Hard Parameter sharing), MTL (Soft Parameter Sharing)

一个多任务学习的聪明例子是通过将预测人阅读时的凝视位置的任务与压缩句子结合起来进行的。

An example of gaze tracking.

在对象检测模型中,诸如 RetinaNetfaster CNN之类的最先进的区域提议网络使用多任务学习来组合来自区域提议和分类任务的损失。

RetinaNet MultiTask Architecture Image Src

MTL 为什么工作

多任务学习似乎直觉上可行,原因如下:

  • ****隐性数据扩充——通过一起学习两个相关的任务,我们可以在每个任务之间转移隐性理解。
  • ****聚焦表征——MTL 将习得的特征表征聚焦在正在学习的任务之间的交集上。
  • 注意 规则化——MTL 提供监督防止模特过度配合主任务 在这种情况下任务应该是并行学习的。**

警告

然而,在执行多任务学习时会面临一些挑战。

  • 让它发挥作用并不容易。
  • 很难找到好的任务对,大多数任务对在某些有害的性能上没有任何改进。
  • 当两个或更多的任务重叠太多,MTL 往往提供微不足道的收益。
  • 如果一个网络不够宽,MTL 伤害所有的任务。

根据经验,更多的任务内数据会比简单地增加更多的任务带来更好的结果。然而,在处理不平衡数据集时,它被证明是有效的。我希望在未来我们可以建立一个框架来尽量减少这些警告。这些挫折通常是为 MTL 准备数据的结果。下面,我将概述三种适用于 MTL 的最佳实践数据技术。

关于多任务学习的更深入的阅读,我强烈推荐 Sebastian Ruder 的帖子和来自 BIU CS 89–687 课程的 Yoav Goldberg 的幻灯片,以及来自 Yoav 的书的第 20 章。

MTL 数据技术

Assorted metal coins. Image Src

如前所述,多任务学习的最大驱动力之一是数据。多任务学习面临的一个挑战通常是给定数据集中所有任务缺乏统一的预先标记或黄金标记的数据。

例如,如果一个人想要在带有词性任务的 SNLI 数据集上用纯金色标签执行多任务学习,他们需要用 POS 标签手动注释 570,000 个人类书写的英语句子对中的每一个。

这种注释是昂贵的,并且通常是禁止的,下面我提出了三种不同的技术,可以应用于处理给定数据集的直接金标记的缺乏,我称之为银、金和银金矿。

白银:

因为我们没有 POS 值,所以我们可以使用一个预先训练好的标记器,比如 Spacy 或 AllenNLP,来为我们的 SNLI 任务生成 POS 标记,并根据它们计算我们的损失。虽然不能保证标签是正确的,但是我们可以希望它们足够接近来指导我们的模型学习我们的主要 SNLI 任务所需的 POS 的正确特征。这种方法的优点是我们的主要 SNLI 任务的 POS 覆盖将是完整的,缺点是我们在我们的模型中引入了噪声。

金色:

虽然我们可能没有给定任务(如 SNLI)的黄金 POS 数据,但我们仍然可以利用来自单独数据集(如 TreeBank)的黄金数据,然后我们可以根据 treebank 计算 POS 任务的损失,并根据 SNLI 数据集计算 SNLI 任务的损失。这种方法的优点是我们保证树库值没有噪声。缺点是,在树库和 SLNI 数据集之间的 POS 标签和句法结构之间可能存在不均匀的覆盖。

银金矿:

Electrum 结合了上述黄金和白银技术,交替或组合加权损失。希望来自 treebank 数据集的黄金值将有助于调节白银数据中的噪声,但白银数据中的正确值将为我们的最终模型提供更好的覆盖范围。这种方法的缺点是需要计算额外的损失和两倍的数据。

行动号召

在我自己的实验中,金、银和银金矿的数据准备方法对我很有效。在未来的帖子中,我希望通过一个基本的 MTL 任务为这种方法提供更好的基准,并可能提供一个简单的 API 来管理 MTL 的数据集和损失。

如果这是你会在下面发现有趣的评论或者发推特给我@ python coder。希望有合作者

资源

Python 中的简单和多元线性回归

原文:https://towardsdatascience.com/simple-and-multiple-linear-regression-in-python-c928425168f9?source=collection_archive---------0-----------------------

Python 中线性回归的快速介绍

大家好!在简单介绍了“熊猫”库NumPy 库之后,我想提供一个用 Python 构建模型的快速介绍,还有什么比最基本的模型之一线性回归更好的起点呢?这将是关于机器学习的第一篇文章,我计划在未来写一些更复杂的模型。敬请期待!但是现在,让我们关注线性回归。

在这篇博文中,我想重点介绍线性回归的概念,以及它在 Python 中的实现。线性回归是一种统计模型,用于检验两个(简单线性回归)或多个(多元线性回归)变量(因变量和自变量)之间的线性关系。线性关系基本上意味着当一个(或多个)自变量增加(或减少)时,因变量也增加(或减少):

如你所见,线性关系可以是正的(自变量上升,因变量上升),也可以是负的(自变量上升,因变量下降)。正如我所说的,我将重点关注回归模型在 Python 中的实现,所以我不想过多地钻研回归背后的数学,但我会写一点关于它的内容。如果你想写一篇关于这方面的博文,请不要犹豫给我回信!

稍微了解一下数学

变量 Y 和 X 之间的关系由以下等式表示:

**Y`i = mX + b**

在这个等式中, Y 是因变量——或者是我们试图预测或估计的变量;x 是独立变量——我们用来做预测的变量;m 是回归线的斜率——它代表了 XY 的影响。换句话说,如果 X 增加 1 个单位, Y 将增加正好 m 个单位。(“全公开”:只有当我们知道 XY 有线性关系时才成立。在几乎所有的线性回归情况下,这都不会是真的!) b 是常数,也称为 Y 截距。如果 X 等于 0,Y 将等于 b ( 警告):参见之前的完整披露!).这在现实生活中不一定适用——我们不会总是知道 XY 之间的确切关系或者有一个确切的线性关系。

这些警告将我们引向一个简单的线性回归。在 SLR 模型中,我们基于数据构建模型——斜率和 Y 轴截距来自数据;此外,我们不需要 XY 之间的关系是完全线性的。SLR 模型还包括数据中的误差(也称为残差)。我现在不会过多地讨论它,也许在以后的文章中,但残差基本上是 Y 的真实值和 Y 的预测/估计值之间的差异。需要注意的是,在线性回归中,我们试图预测一个连续变量。在回归模型中,我们试图通过找到“最佳拟合线”来最小化这些误差——误差的回归线将是最小的。我们试图将黑线的长度(或者更准确地说,是蓝点与红线的距离)最小化,尽可能接近零。它与最小化均方误差(MSE)误差平方和(SSE) 相关(或等效),也称为“残差平方和”。(RSS)但是这可能超出了这篇博客的范围:-)

在大多数情况下,我们会有不止一个自变量——我们会有多个变量;它可以小到两个独立变量,大到数百个(理论上甚至数千个)变量。在这些情况下,我们将使用多元线性回归模型(MLR)。回归方程与简单回归方程非常相似,只是变量更多:

**Y’i = b0 + b1X1i + b2X2i**

这篇文章的数学部分到此结束:)准备好用 Python 实现它了吗?

Python 中的线性回归

在 Python 中有两种主要的方法来执行线性回归——使用 Statsmodelsscikit-learn 。使用 Scipy 库也是可能的,但是我觉得这不如我提到的另外两个库那么常见。让我们来研究一下在这两种情况下进行线性回归:

统计模型中的线性回归

Statsmodels 是“一个 Python 模块,它为许多不同的统计模型的估计,以及进行统计测试和统计数据探索提供了类和函数。”(来自文档)

PandasNumPy 一样,获取或安装 Statsmodels 的最简单方法是通过 Anaconda 包。如果出于某种原因,你有兴趣以另一种方式安装,请查看此链接。安装后,每次需要使用它时,您都需要导入它:

**import statsmodels.api as sm**

让我们看看如何实际使用 Statsmodels 进行线性回归。我将使用我在 DC 大会上的数据科学课中的一个例子:

首先,我们从 sklearn (我提到的另一个库)导入一个数据集:

**from** **sklearn** **import** datasets *## imports datasets from scikit-learn*
data = datasets.load_boston() *## loads Boston dataset from datasets library* 

这是波士顿房价的数据集(链接到描述)。因为它是为测试和学习机器学习工具而指定的数据集,所以它附带了数据集的描述,我们可以通过使用命令打印数据来查看它。DESCR(这只适用于 sklearn 数据集,而不是每个数据集!虽然会很酷…)。为了更好地理解变量,我添加了描述的开头:

Boston House Prices dataset
===========================

Notes
------
Data Set Characteristics:  

    :Number of Instances: 506 

    :Number of Attributes: 13 numeric/categorical predictive

    :Median Value (attribute 14) is usually the target

    :Attribute Information (in order):
        - CRIM     per capita crime rate by town
        - ZN       proportion of residential land zoned for lots over 25,000 sq.ft.
        - INDUS    proportion of non-retail business acres per town
        - CHAS     Charles River dummy variable (= 1 if tract bounds river; 0 otherwise)
        - NOX      nitric oxides concentration (parts per 10 million)
        - RM       average number of rooms per dwelling
        - AGE      proportion of owner-occupied units built prior to 1940
        - DIS      weighted distances to five Boston employment centres
        - RAD      index of accessibility to radial highways
        - TAX      full-value property-tax rate per $10,000
        - PTRATIO  pupil-teacher ratio by town
        - B        1000(Bk - 0.63)^2 where Bk is the proportion of blacks by town
        - LSTAT    % lower status of the population
        - MEDV     Median value of owner-occupied homes in $1000's

    :Missing Attribute Values: None

    :Creator: Harrison, D. and Rubinfeld, D.L.

This is a copy of UCI ML housing dataset.
http://archive.ics.uci.edu/ml/datasets/Housing

This dataset was taken from the StatLib library which is maintained at Carnegie Mellon University.

运行 data.feature_namesdata.target 将分别打印自变量和因变量的列名。也就是说,Scikit-learn 已经将房价数据设置为目标变量,并将 13 个其他变量设置为预测变量。让我们看看如何对这个数据集进行线性回归。

首先,我们应该将数据加载为 pandas 数据框以便于分析,并将房屋价值中值设置为我们的目标变量:

**import** **numpy** **as** **np**
**import** **pandas** **as** **pd**# define the data/predictors as the pre-set feature names  
df = pd.DataFrame(data.data, columns=data.feature_names)

*# Put the target (housing value -- MEDV) in another DataFrame*
target = pd.DataFrame(data.target, columns=["MEDV"])

我们在这里所做的是获取数据集并将其作为熊猫数据框加载;之后,我们设置预测值(如 df),即数据集中预设的独立变量。我们也在设定目标——因变量,或者我们试图预测/估计的变量。

接下来,我们要拟合一个线性回归模型。我们需要选择我们认为能很好预测因变量的变量——这可以通过检查变量之间的相关性,通过绘制数据并直观地搜索关系,通过对哪些变量能很好预测 y 等进行初步研究来完成。对于第一个例子,让我们以 RM——房间的平均数量和 LSTAT——较低地位人口的百分比为例。需要注意的是,Statsmodels 默认情况下不添加常量。让我们先看看回归模型中没有常数的情况:

*## Without a constant*

**import** **statsmodels.api** **as** **sm**

X = df["RM"]
y = target["MEDV"]

*# Note the difference in argument order*
model = sm.OLS(y, X).fit()
predictions = model.predict(X) # make the predictions by the model

*# Print out the statistics*
model.summary()

输出:

解读桌子这是一张很长的桌子,不是吗?首先我们有因变量,模型和方法。 OLS 代表普通最小二乘法,方法“最小二乘法”意味着我们试图拟合一条回归线,这将最小化到回归线的距离的平方(见本文的前一部分)。日期和时间是不言自明的:)观察次数也是如此。残差和模型的 Df 与自由度相关——“统计数据最终计算中可自由变化的值的数量。”

系数 3.6534 意味着 RM 变量增加 1, MDEV 的预测值增加 3.6534 。其他几个重要的值是 R 平方——我们的模型解释的方差的百分比;标准误差(是统计抽样分布的标准偏差,通常是平均值);假设检验的 t 分数和 p 值——RM具有统计上显著的 p 值; RM 有 95%的置信区间(意味着我们以 95%的置信度预测 RM 的值在 3.5483.759 之间)。

如果我们想在模型中添加一个常量,我们必须使用命令X = sm.add_constant(X)来设置它,其中 X 是包含输入(独立)变量的数据框的名称。

**import** **statsmodels.api** **as** **sm #** import statsmodels

X = df["RM"] *## X usually means our input variables (or independent variables)*
y = target["MEDV"] *## Y usually means our output/dependent variable*
X = sm.add_constant(X) *## let's add an intercept (beta_0) to our model*

*# Note the difference in argument order*
model = sm.OLS(y, X).fit() *## sm.OLS(output, input)*
predictions = model.predict(X)

*# Print out the statistics*
model.summary()

输出:

解读表格 —常数项的系数不同。如果没有常数,我们将强制我们的模型通过原点,但是现在我们有一个 y 截距在 -34.67 。我们还将 RM 预测器的斜率从 3.634 更改为 9.1021

现在让我们尝试拟合一个包含多个变量的回归模型——我们将使用我之前提到的 RM 和 LSTAT。模型拟合是相同的:

X = df[[“RM”, “LSTAT”]]
y = target[“MEDV”]model = sm.OLS(y, X).fit()
predictions = model.predict(X)model.summary()

输出是:

Note: this table looks different because I’ve updated my Jupyter Notebook

解释输出 —我们可以看到,该模型的 R 平方值更高,为 0.948,这意味着该模型解释了因变量中 94.8%的方差。每当我们向回归模型中添加变量时,R 会更高,但这是一个相当高的 R。我们可以看到 RMLSTAT 在预测(或估计)中值房屋价值方面具有统计显著性;毫不奇怪,我们看到当 RM 增加 1MEDV 将增加 4.9069,当 LSTAT 增加 1MEDV减少-0.6557。你可能还记得,LSTAT 是较低地位人口的百分比,不幸的是,我们可以预计它会降低房屋的中值。同样的逻辑,房子里的房间越多,通常它的价值就会越高。

这是统计模型中一元和多元线性回归的例子。我们可以在回归模型中使用尽可能少或尽可能多的变量——最多 13 个!接下来,我将演示如何在 SKLearn 中运行线性回归模型。

SKLearn 中的线性回归

当谈到 Python 中的机器学习时,SKLearn 几乎是黄金标准。它有许多学习算法,用于回归、分类、聚类和降维。查看我关于 KNN 算法的帖子获得不同算法的地图和更多 SKLearn 的链接。为了使用线性回归,我们需要导入它:

**from** **sklearn** **import** linear_model

让我们使用之前用过的数据集,波士顿房价。该过程在开始时是相同的——从 SKLearn 导入数据集并加载到波士顿数据集中:

**from** **sklearn** **import** datasets *## imports datasets from scikit-learn*
data = datasets.load_boston() *## loads Boston dataset from datasets library*

接下来,我们将数据加载到 Pandas(与之前相同):

# define the data/predictors as the pre-set feature names  
df = pd.DataFrame(data.data, columns=data.feature_names)

*# Put the target (housing value -- MEDV) in another DataFrame*
target = pd.DataFrame(data.target, columns=["MEDV"])

现在,和以前一样,我们有包含自变量的数据框(标记为“df”)和包含因变量的数据框(标记为“target”)。让我们用 SKLearn 拟合一个回归模型。首先,我们将定义 X 和 y,这一次我将使用数据框中的所有变量来预测房价:

X = df
y = target[“MEDV”]

然后我会拟合一个模型:

lm = linear_model.LinearRegression()
model = lm.fit(X,y)

lm.fit()函数适合线性模型。我们希望使用模型进行预测(这就是我们在这里的目的!),所以我们将使用 lm.predict():

predictions = lm.predict(X)
print(predictions)[0:5]

print 函数将打印 y 的前 5 个预测(为了“节省空间”,我没有打印整个列表。移除[0:5]将打印整个列表):

[ 30.00821269  25.0298606   30.5702317   28.60814055  27.94288232]

记住,lm.predict()使用我们拟合的线性模型来预测 y(因变量)。你一定注意到了,当我们用 SKLearn 运行线性回归时,我们不会像在 Statsmodels 中那样得到一个漂亮的表(好吧,它不是那么漂亮…但它相当有用)。我们能做的是使用内置函数返回分数、系数和估计截距。让我们看看它是如何工作的:

lm.score(X,y)

会给出这样的输出:

0.7406077428649428

这是我们模型的 R 分。你们可能还记得,这是解释预测方差的百分比。如果你有兴趣,在这里阅读更多。接下来,让我们检查预测值的系数:

lm.coef_

将给出以下输出:

array([ -1.07170557e-01,   4.63952195e-02,   2.08602395e-02,
         2.68856140e+00,  -1.77957587e+01,   3.80475246e+00,
         7.51061703e-04,  -1.47575880e+00,   3.05655038e-01,
        -1.23293463e-02,  -9.53463555e-01,   9.39251272e-03,
        -5.25466633e-01])

截距:

lm.intercept_

这将给出以下输出:

36.491103280363134

这些都是我之前提到的多元回归方程的(估计/预测)部分。查看文档,了解关于 coef_ 和 intercept_ 的更多信息。

所以,这是一个快速(但相当长!)关于如何用 Python 进行线性回归的介绍。实际上,您不会使用整个数据集,但是您会将数据拆分为用于训练模型的训练数据和用于测试模型/预测的测试数据。如果你想了解它,请看看我的下一篇博文。与此同时,我希望你喜欢这篇文章,我会在下一篇文章中“看到”你。

感谢您的阅读!

简单的网络抓取入门

原文:https://towardsdatascience.com/simple-beginning-to-web-scraping-ef2f2287aff9?source=collection_archive---------10-----------------------

Photo by Jay Wennington on Unsplash

当您需要数据仓库中不容易获得的数据时,或者当数据可以在线获得但不能通过 API 获得时,Web 抓取几乎是您的首选技术,您可以使用 API 通过 HTML 请求提取信息。

假设我们的目标是找到流行的印度博客平台。记住这个用例,现在让我们看看如何为我们的分析找到信息。

数据源:

在谷歌上快速搜索关键词——印度博客,这个网站会出现在第一个结果中。这个网站列出了一些最受欢迎的印度博客和他们的博客链接。因此,这个网站成为我们的数据来源,我们将从那里收集信息,供我们进一步分析。

工具箱:

对于这个分析,我们将使用 Python 编程语言。以下是此分析所需的软件包列表。

  • 请求—对于 HTML 请求
  • bs4——著名的解析 html 内容和收集所需数据的工具
  • re —用于正则表达式和模式匹配
  • matplotlib —用于可视化

让我们加载所需的库:

import requests
from bs4 import BeautifulSoup, Comment
import pandas as pd
import re
import matplotlib.pyplot as plt

HTTP 请求

web 抓取的第一步只是发出一个 HTTP 请求,获取 URL 内容(记住这一步只是收集 URL 的内容,并不抓取所需的信息)。

url='https://indianbloggers.org/'
content = requests.get(url).text

对于使用get()的请求,创建一个带有 url 内容的请求对象,而.text方法提取对象/ URL 的内容。

初始化所需的数据对象:

为了进一步进行分析,我们将需要一些数据对象,这里我们正在初始化那些将在后续步骤中使用的对象。

#initalizing an empty dictionary that would be written as Pandas Dataframe and then CSV
d = {'title':[],'links':[]}#initializing blog hosting category
cat = {'blogspot':0,'wordpress':0,'others':0}

正如你所看到的,我们已经创建了两个字典——一个用于肌酸 a 熊猫数据框架,另一个用于我们想要收集信息的必需博客平台。所以基本上是 Blogspot vs WordPress(我们还有其他的,可以包括从自定义域到 medium.com 的任何东西)

开始刮

soup = BeautifulSoup(content, "html.parser") for link in soup.find_all('a',):
    if len(link.text.strip()) > 1 and bool(re.match('^http',link['href'])) and not bool(re.search('indianbloggers|twitter|facebook',link['href'])):
        d['title'].append(link.text)
        d['links'].append(link['href'])
        #finding the blog hosting type
        if re.search('blogspot',link['href']):
            cat['blogspot']+=1
        elif re.search('wordpress',link['href']):
            cat['wordpress']+=1
        else:
            cat['others']+=1
        #d['len'].append(len(link.text.strip()))

从上面的代码中,您可以注意到已经使用 BeautifulSoup 函数启动了抓取,该函数使用了我们在 HTTP 请求后提取的内容。那只是刮的开始。正如我们在目标中定义的那样,我们在这里提取链接——尤其是域名,以分析哪个博客平台(由 URL 的域名定义)受欢迎。考虑到这一点,我们可以确定我们需要抓取锚链接(带有 HTML 标签‘a’的超链接)。在这个过程中,我们需要做一些数据清理步骤。例如,有一些标签什么都没有,这需要被绕过,我们也不需要获得网站中社交媒体个人资料 URL 的超链接。因此,我们设法用一些正则表达式和 if 条件来清理数据。因为我们提取多个 URL,所以我们需要通过 for 循环迭代我们的数据提取,以提取域信息并统计各个类别——blogpost、WordPress 等——还需要构建追加到我们在上一步中创建的字典中,该字典可以转换为 Pandas 数据框。

输出数据帧:

上一步结束时,我们已经获得了所有需要的信息。为了更进一步,我们将把字典对象‘d’转换成 Pandas 数据框,这在数据分析中更加灵活和有用。然后,可以将数据框保存在您的计算机上,以供将来参考或进一步分析。同时,让我们也打印一些关于数据帧和数据摘要的信息。

blog_list = pd.DataFrame(d).set_index('title')
print(blog_list.head())
blog_list.to_csv('blog_list.csv', encoding='utf-8')
print(str(len(blog_list.index))+' rows written')
print(cat)
>>> 
                                            links
title                                            
Amit Agarwal               [http://www.labnol.org/](http://www.labnol.org/)
Jyotsna Kamat  [http://www.kamat.com/jyotsna/blog/](http://www.kamat.com/jyotsna/blog/)
Amit Varma             [http://www.indiauncut.com/](http://www.indiauncut.com/)
Sidin Vadukut              [http://www.whatay.com/](http://www.whatay.com/)
Hawkeye           [http://hawkeyeview.blogspot.in/](http://hawkeyeview.blogspot.in/)
363 rows written
{'wordpress': 49, 'blogspot': 106, 'others': 208}

正如您在结果中看到的,对象“cat”为我们提供了可视化所需的数据。

可视化流行领域:

有了生成的字典“cat ”,现在让我们使用 matplotlib 来可视化数据(不太美观)。

#plotting the blog hosting type 
plt.bar(range(len(cat)), cat.values(), align='center')
plt.xticks(range(len(cat)), cat.keys())
plt.show()

给出了这个图:

虽然“其他”类别(包括自定义域名和任何其他博客平台)赢得了这场比赛,但 WordPress 和 Blogspot 之间——博客帖子成为了赢家——这也可能是第一批移动者主要在博客帖子平台上的原因,然后他们可能会变得受欢迎,并最终出现在这个网站上。

最终注释:

尽管如此,这篇文章的目的只有一个,那就是找到流行的博客平台。这篇文章旨在帮助你开始掌握网络抓取的基础知识。如果你有兴趣了解更多关于网络抓取的知识,你可以查看一下这个 Datacamp 教程。这里使用的完整代码可以在我的 Github 上获得。这个帖子最初出现在 DS+ 上。

张量流基因组变异调用的简单卷积神经网络

原文:https://towardsdatascience.com/simple-convolution-neural-network-for-genomic-variant-calling-with-tensorflow-c085dbc2026f?source=collection_archive---------1-----------------------

生物技术创业公司中的人工智能/机器学习

毫无疑问,使用深度神经网络的最新进展的快速发展已经改变了我们可以解决从图像识别到基因组学的各种问题的方式。许多创业公司(Viome/CZ bio hub/Deep Genomics)都强调在他们的研究和产品中使用“人工智能/机器学习”。硅谷其他相对“大”的生物技术初创公司,如 VerilyCalicoGrail 要么由 Alphabet 资助,要么与谷歌有着深厚的联系。

当然,这些公司将专注于应用机器学习、深度神经网络和对他们可以收集的大量数据进行挑战性的统计分析(通过各种来源的投资)。).Google Research 还发表了一篇论文,介绍了使用 Google 内部计算能力从 DNA 序列数据中进行单核苷酸多态性(SNP)调用的“deep variant”,并将其作为云服务提供

在一家为基因组学提供研究仪器(单分子实时 DNA 测序仪)的公司工作,并负责分析基因组学数据和算法开发的日常工作,“DeepVariant”的工作当然吸引了我们的注意。这项工作令人印象深刻,使一般设计的神经网络(Inception v2)的东西,它不是最初设计的。

虽然我已经在生物信息学领域工作了 10 多年,但我在“变异体呼叫”这个子领域工作不多。变体呼叫的算法和工具集中于从测序数据中识别基因组之间的微小差异。在过去的几年里,我主要致力于“从头”重建基因组,即在没有基因组先验知识的情况下构建基因组序列。然而,最近,我开始对现代机器学习工具和理论感兴趣,特别是人工神经网络(ANN)的形式。把解决一些小问题作为一个练习可能是一个很好的练习,所以我最近考虑把变体调用作为 ANN 的一个应用。

什么是变体调用?

基因组学中的“变异体调用”是什么?人类基因组大约有 60 亿个字母。如果你觉得基因组像一本书,那就是一本由“A”、“C”、“G”、“T”60 亿个字母组成的书。现在,每个人都有自己独特的基因组。然而,科学家发现人类基因组的大部分是相同的。随着人类基因组计划,科学界构建了一套序列作为人类基因组“参考”,作为基因组分析工作的基础书籍。每个人的 DNA 测序技术提供了信息,例如,书中的一小段文字,可以用来识别每个人的基因组“书”与参考书的差异,而不是每次从头开始重写书。

有了人类基因组参考,科学家和商业服务提供商就可以对短 DNA 片段进行测序,并将这些片段读数“映射”到参考,从而识别这些微小的差异。由于不需要像从头开始的方法那样从零开始重建基因组序列,这是一种更容易和更便宜的方法来获得一些有用的遗传信息。虽然这种方式更便宜,但也存在一些问题。如果有一些更个人化的特定 DNA 序列不在参考文献中,那么在将读数分配给参考文献的作图过程中会导致错误。参考文献中也有许多相同或接近相同的序列。如果一个读数不包含一些“独特的”签名,那么我们不知道在哪里放置读数。还有排序错误。不是所有我们从序列发生器得到的读数都是 100%准确的。

基本上,为了正确地称呼变体,我们需要确定(1)一个读数在基因组中的正确位置,(2)作图读数与参考读数之间的正确比对,以及(3)用于从比对中识别变体的正确统计。通常情况下,(1)和(2)由“基因组比对器”或“基因组映射器”负责。比如“ bwa ”就是恒力研发的一款流行的基因组比对仪。一旦我们绘制了 DNA 片段阅读图谱,生物信息学从业者可以通过生成一些“堆积”视图(见下文)来可视化它们。在大多数情况下,序列数据与参考数据的差异是明显的。通过一些简单的计数算法,我们将有一个合理的好的变体调用程序。与此同时,基因组和生物信息学过程会引入人为因素,结合测序错误,使得可靠的变异调用相对棘手

A “pile-up” view of DNA fragment reads for a heterozyguous variant G to A

如果你阅读“DeepVariant”预印本,你可以看到作者为“精密度 FDA 真相挑战”竞赛开发了这项工作。我认为挑战的一个目标是建立一个标准的评估变量集,以便人们可以用它来测试变量调用管道和算法。挑战赛的组织者为那些变异体生成了一个“高质量变异体”数据集,这些变异体可以在阅读参考作图过程不是问题的那些区域中用多种测序技术调用。这些数据集用于评估不同调用算法的质量。

使用 CNN (Inception v2)进行变体调用

The architecture of the DeepVariant caller

DeepVariant 预印本展示了它如何使用谷歌的 DNN 基础设施来制作一个赢得 PrecisionFDA 挑战的变体调用程序。我不认为我能在这里进入 DeepVariant 方法的更多细节。在此期间,概念相当简单。正如我们在上面的堆积图中看到的,大多数情况都很简单,但也会有一些困难的情况。在一些复杂的比对情况下,大多数时候,仔细查看比对视图的人可以比一些简单的算法更好地调用变体。如果这样的图像可能包含从那些模糊的变体调用情况中获得的适当信息,那么对于图像分类工作良好的神经网络将可能能够在调用那些变体方面做得更好,而手动编码的算法可能不能很好地捕捉一些边缘情况。

作者将潜在候选变体的序列比对数据转换成“堆积”图像。不同的颜色和 alpha 通道用于编码阅读序列,根据碱基质量和阅读链。他们使用挑战组织者在人类基因组中识别的几乎所有高置信度变体调用来训练神经网络,并将调用的变体分为三类:纯合变体、杂合变体和无变体。预印本中的表格总结了评估结果:

Evaluation Results from the DeepVariants preprint

DeepVariant 在 Variant 调用许多不同的排序数据类型时表现出良好的性能。然而,正如作者在预印本中指出的,当使用图像分类器进行基因组变异调用时,这将是次优的。在将序列数据转换为图像的过程中,可能会丢失许多有价值的信息。使用单分子测序,错误率可能会更高。人们已经可以从视觉上看到单分子测序的堆积图像与短阅读测序的图像有很大不同。由于单分子技术的不同性质,这种堆积图像可能无法捕获用于单分子测序的正确信息。

An example of pile-up image from single molecule sequencing data.

在过去的几个月里,我一直在用 Tensorflow 构建神经网络模型,用于各种测序相关的分析。虽然我通常不怎么研究变异体调用问题,但我认为作为一个小练习来测试它是有用的,以查看我们是否可以通过对神经网络学习的数据进行编码,从单分子 DNA 测序数据中调用变异体。

一个更简单的用于变体呼叫的 CNN

不同的 DNA 测序方法有不同的错误模式。在单分子 DNA 测序中,由于没有放大信号的化学步骤,人们得到微弱的原始信号。此外,单分子 DNA 测序通常通过实时观察单分子事件来完成。在 DNA 片段阅读中,我们得到了额外的碱基或者错过了一些碱基。我们称这样的错误为“插入-删除”错误。目前大多数单分子技术都比其他的镜头读取技术有更高的错误率。然而,单分子技术允许我们读取很长的 DNA 片段。相比之下,通常单分子技术读取 DNA 的时间是非单分子 DNA 测序技术的 10 到 100 倍。更多的错误使许多事情变得更具挑战性。另一方面,较长的 DNA 片段读数有助于解决歧义,因为较长的 DNA 片段可能包含基因组中独特的信息。我们将能够正确地识别一个读数来自基因组的什么地方。

“indel”错误的影响是,它使比对(DNA 阅读片段与参照片段之间的碱基对碱基对应)“更模糊”。因此,关于变体的信息可能不集中在变体位点,而是分散开来。像 DeepVariant 一样,如果我们能够以简洁的方式收集变异位点以外的信息,神经网络将能够使用这些额外的信息进行更好的分类。我们也没有像谷歌那样的资源来训练一个大的神经网络模型。我们能不能制造一个小的神经网络变体呼叫者,可以使用有限的资源来训练它?

事实上,使用 Google 的 Tensorflow 构建一个用于变体调用的小型卷积神经网络并使用有限的资源训练一个小型神经网络是非常简单的。我构建了一个快速原型,我称之为“ VariantNET ”。我们不生成对齐堆积图像,并使用大型图像分类器 CNN 进行变体调用。我们将比对信息总结成三个 15×4 的矩阵。我们首先做一些简单的统计来建立一个候选变量列表。对于每个候选物,我们在两侧添加 7 个碱基侧翼碱基。包括变异候选位点,我们同时考虑参考文献中的 15 个碱基。

对于每个位置,我们使用独热码来生成矩阵。也就是说,对于每个位置,我们跟踪“A”/“C”/“G”和“T”每个基数的 4 个计数。一个矩阵追踪编码参考序列的基线和通过一个位置支持的阅读数。另外两个 15×4 矩阵追踪测序数据和参考之间的差异。一个矩阵被设计用于追踪序列数据中所有碱基的差异,另一个矩阵集中于参考序列中缺失的碱基。我们认为这种总结比排列堆积图像更能简明地捕捉有用的信息。例如,如果读数中有一个额外的碱基,它通常只是堆积图像中的一个简单标记,我们可能会丢失关于额外碱基是哪种 DNA 核苷酸的信息。

VariantNET for variant calling

对于每个候选变体站点,一个 15 乘 4 乘 3 形状的“张量”被发送到一个几乎令人尴尬的简单卷积神经网络 (2 个卷积+ maxpool 层,后面是 3 个全连接+丢弃层)用于变体调用。我们设计网络输出,将候选人称为“杂合变异体”、“纯合变异体”、“非变异体”或“复合变异体”。除了对候选位点的变异类型进行分类,变异网络还被训练来预测可能的变异碱基。我们使用这种更简单的 CNN 进行变体呼叫的初步实验结果显示,在最小调整的情况下,具有相当好的性能。在示例中,我们只使用了一个小的训练集。当使用来自 21 号染色体的预先识别的变异体调用时,训练通常运行不到 10 分钟。我们在 22 号染色体上测试预测,我们通常得到 98%以上的召回率和 PPV。由于我们没有对比对进行任何优化,也没有使用除 PacBio 测序仪生成的碱基之外的任何其他信息,因此进一步优化可以使其达到更高的变体调用准确性也就不足为奇了。

下一步是什么?

我还没有进行更大规模的变异调用实验,所以现在还没有直接的比较。导致学术论文撰写的全面评估可能需要一段时间。我还没有做那件事的计划。我认为这个小练习已经表明,假设错误不是系统性的,可以使用小的神经网络而不是大的神经网络来提高更多噪音测序数据的变体呼叫准确性。

VariantNET 可能处理大多数孤立的 SNP 呼叫。当附近有变体或者变体是小的 indel 时,那么我们当前将变体调用放入“复杂变体”桶中。这可能并不理想。对于那些复杂的变异体,像 VariantNET 这样的分类器可以起到增加候选体附近确实有变异体的置信度的作用。我们可以为最终的变体调用产生从头共识,以避免由阅读和参考之间的较大差异引起的比对假象。

我确信还有其他人也在研究使用神经网络进行变异调用。无论如何,使用 ANN 进行变体调用似乎是显而易见的事情。幸运的是,正如我们在这里展示的,我们可能不需要大型机器来完成这项工作。我们使用非常简单的神经网络和来自测序读数的非常少的信息,但是我们在第一次尝试中获得了相当好的结果。令人兴奋的是,除了碱基之外,结合其他有用的信息和使用更好的预处理算法可以进一步提高变体调用的质量。我不确定此刻我会沿着这条线做多少工作。然而,如果任何读者对一些讨论感兴趣,请让我知道。这是一个有趣的东西,结合了当今的两个热门话题:机器学习和基因组学!!

附言

感谢 亚历山大·巴甫洛夫加里宁 指出他们对当前生物学和医学深度学习技术现状的伟大而全面的综述论文:http://www.biorxiv.org/content/early/2017/05/28/142760,里面有很多有用的信息和讨论。我强烈推荐。

部署 Web 应用程序+ ML 模型+API—教程

原文:https://towardsdatascience.com/simple-deployment-of-web-app-ml-model-apis-tutorial-2ece8e66d98c?source=collection_archive---------9-----------------------

了解如何部署由逻辑回归模型提供服务的 web 应用程序。我们将创建一个应用程序来预测数据科学家年收入超过 10 万美元的概率。

如果不投入生产,创造一个 ML 模型有什么意义?计算模型的指标并将其调整到更好的性能并不是数据科学家工作的终点。你能做的远不止这些。事实上,部署一个可伸缩的模型比看起来容易得多。知道如何做到这一点,肯定会给你的简历增加很大的价值,因为大多数数据科学家不会走那么远。您可以将本教程视为成为数据科学独角兽的第一步。

我们在这里做什么?

我们将在 AWS Lambda 中部署一个逻辑回归模型,然后用 API Gateway 创建 API 端点。这样你就有了一个可扩展的服务模型,你只需要做一个简单的 POST 请求,它就会把预测结果返回给你。

然后,我们将构建一个带有 HTML 表单的 Flask 应用程序,以获取一些答案来填充我们的模型。该应用程序向我们的 API 发出请求,将用户重定向到另一个页面,并在其上展示模型预测。

在这里,您可以访问我们在本教程中开发的工作应用程序。你爱怎么玩就怎么玩。

This is how our Flask App will look like.

第一:模型

这篇文章的主要目的不是开发一个模型,但是你可以自由地查看我们在这里使用的模型是如何开发的。这是一个简单的逻辑回归模型。要部署它,我们基本上有两种选择:

  1. 将模型导出为序列化对象,加载到 AWS lambda 并开始进行预测。
  2. 参数化模型,将所有系数和截距手动加载到λ。

我选择第二个选项,因为我希望模型对任何人都是透明的。应该清楚系数是什么,分数是怎么算出来的。一个系列化的模型不会让我们看到细节。

在这篇由本·韦伯撰写的关于数据科学的文章中,你会找到关于如何向 AWS Lambda 部署序列化模型的说明。

参数化:那是什么鬼东西?

逻辑回归模型可以写成这样:

log-odds = b0 + b1x1 + b2x2 + ... + bnxn **Where**:
**b0** is the intercept
**b1,b2, bn** are the coefficients
**x1, x2, xn** are the variables

我们训练我们的模型并得到所有系数的值。所以这只是一个手工写方程的问题:将所有系数和截距相加。然后为了得到 0 到 1 之间的分数(概率),我们做:

scores = 1 / (1 + exp(-(b0 + b1x1 + b2x2 + ... + bnxn)))

第二:λ

登录 AWS 控制台,转到 IAM 并创建一个至少附加了这些权限策略的角色:

  • AWSLambdaFullAccess
  • 亚马逊 3 完全访问
  • CloudWatchFullAccess

IAM Role Permissions

然后你可以去 Lambda,点击进入“创建函数”。现在我们将定义函数的基本配置。

Choose the runtime to be Python 3.7, and the role to be the one you just created.

现在,您转到函数代码,将以下内容添加到已经创建的 lambda 函数中:

这段代码是做什么的?

该函数接收一个 json 作为事件参数,并将其处理为正确的格式。接下来,我们用下面将要定义的帮助函数计算分数,然后我们构建一个响应并返回它。就这么简单。

现在我们将创建一些辅助函数。转到文件>从模板新建> Python 文件:

添加以下代码,并将其保存为 normalizer.py:

创建一个新的 Python 文件,将其命名为 pre_treatment.py:

最后,我们将添加一个计算分数的函数。请注意,这里的模型系数是硬编码的。命名为 scorer.py。

搞定了。现在让我们为我们的模型创建一个 API。在设计器>添加触发器,点击 API 网关。

点击 configuration required,选择 create a new API,然后保存 lambda 函数。如果您返回到 API 网关,您应该会看到一个可用的端点。这就是你用来访问你的 API 的那个。

要测试您的 API,只需向端点发送一个 POST 请求,如下所示(用您刚刚创建的 url 替换 URL):

您应该期望得到计算的分数作为响应。大概是这样的:

{ “isBase64Encoded”: False, 
  “headers”: {“Content-Type”: “application/json”}, 
  “statusCode”: 200, 
  “body”: {“score”: 350}
}

太好了!我们刚刚创建了一个可伸缩的服务,它在给定输入的情况下运行我们的模型。现在,我们构建了一个 web 应用程序,它向我们的服务发送请求,并期望得到答案。

完整的项目有更多的功能,看看这里:

[## andresionek 91/ka ggle-top 20-预测器

预测数据科学家的年收入是否超过 10 万美元-andresionek 91/ka ggle-top 20-预测者

github.com](https://github.com/andresionek91/kaggle-top20-predictor)

第三:Flask 应用

用下面的文件夹结构创建一个项目(你可以从我的 github 中克隆它)。

有两个 HTML 页面(index.html 和 score.html)存储在模板文件夹中。所有的 css,图片和 js 都在静态文件夹中。我们对这个应用程序感兴趣。py:

将我们的应用程序部署到 beanstalk 也很简单。

  1. 首先确保在文件夹中创建了 git 存储库。确保代码被提交并推送到主服务器。
  2. 打开终端并运行pip install awsebcli来安装 Beanstalk 命令行界面
  3. 然后cd到你的项目文件夹并运行eb init
  4. 运行之后,您可以运行eb create来创建您的应用程序
  5. 最后eb open会打开你的 app 网址

要进行额外的部署和更新:

  1. 首先提交/推送代码
  2. 然后运行eb deploy

完整烧瓶项目可从以下网址获得:

[## andresionek 91/数据-科学家-价值

计算数据科学家报酬的 Flask 应用程序-andresionek 91/data-scientist-value

github.com](https://github.com/andresionek91/data-scientist-value)

这是一个将 ML 模型部署为服务的教程,创建一个 API,最后使用 Flask 构建一个 web 应用程序来请求我们的模型的 API。我知道这个教程可能过于简单,但是你可以通过简单的网上搜索找到大量关于每个主题的详细资料。这个想法只是为了证明这是可能的,而且并不复杂!

我希望这篇文章能帮助你找到成为更有价值的数据科学家的方法!

使用 DataExplorer 包在 R 中进行简单快速的探索性数据分析

原文:https://towardsdatascience.com/simple-fast-exploratory-data-analysis-in-r-with-dataexplorer-package-e055348d9619?source=collection_archive---------0-----------------------

Image Courtesy: https://pixabay.com/en/calculator-calculation-insurance-1680905/

订阅 1littlecode YT 频道更多 R 教程

探索性数据分析在整个数据科学工作流程中扮演着非常重要的角色。事实上,这占用了整个数据科学工作流程的大部分时间。有一句很好的引言(不确定是谁说的):

“在数据科学中,80%的时间花在准备数据上,20%的时间花在抱怨需要准备数据上。”

随着 R 成为许多数据分析师的首选语言,EDA 需要一名 R 程序员将几个来自臭名昭著的tidyverse世界的包放到他们的 R 代码中——即使是最基本的带有一些条形图和直方图的 EDA 也是如此。

最近,我遇到了这个包 DataExplorer ,它似乎只用一个函数create_report()就完成了整个 EDA(至少是典型的基本 EDA ),这个函数生成了一个很好的可呈现的 Rmarkdown html 文档。这只是一个自动生成的报告,如果您想要控制想要在其上执行 EDA 的内容,DataExplorer 为此提供了几个绘图功能。

这篇文章的目的是解释使用DataExplorer包在 R 中你能有多快。

安装和装载

让我们从加载库开始我们的 EDA:

#Install if the package doesn't exist 
#install.packages('DataExplorer) 
library(DataExplorer)

资料组

我们将用于此分析的数据集是发布在 Kaggle 上的巧克力棒评分。数据集可以在这里下载。将输入数据集加载到 EDA 的 R 会话中:

choco = read.csv('../flavors_of_cacao.csv', header = T, stringsAsFactors = F)

数据清理

在继续之前,需要对数据类型进行一些重新格式化。比如可可。百分比应该是一个数字值,但由于%符号的存在而被读作一个字符,因此需要固定。

choco$Cocoa.Percent = as.numeric(gsub('%','',choco$Cocoa.Percent))
choco$Review.Date = as.character(choco$Review.Date)

变量

在 EDA 中,首先要做的是检查输入数据集的维度和变量的时间。

plot_str(choco)

给出了这个图:

这样,我们可以看到我们有一些连续变量和一些分类变量。

人类寻找缺失的价值

在深入分析之前,查看用于分析的输入数据是否有缺失值非常重要。

plot_missing(choco)

给出:

幸运的是,这个数据集中没有缺失值。

连续变量

直方图是分析师分析/表示连续变量的最好朋友。

plot_histogram(choco)

给出了这个图:

也许,你是密度图的粉丝,DataExplorer已经有了一个函数。

plot_density(choco)

给出了这个图:

多变量分析

这标志着单变量分析的结束和双变量/多变量分析的开始,从相关性分析开始。

plot_correlation(choco, type = 'continuous','Review.Date')

给出了这个图:

与相关图类似,DataExplorer具有绘制箱线图和散点图的功能,语法与上面类似。

分类变量—柱状图

到目前为止,我们已经看到了 EDA 绘图的种类,DataExplorer让我们为连续变量绘图,现在让我们看看我们如何能为分类变量做类似的练习。没想到,这变成了一个非常简单的功能plot_bar()

plot_bar(choco)

给出了这个图:

最后,如果你只有几分钟时间(就像 maggi noodles 广告中那样,两分钟!)只要简单地使用create_report()就可以了,它在 html 中给出了一个非常好的可展示/可分享的渲染 markdown。

create_report(choco)

希望这篇文章能帮助您执行简单快速的 EDA,并使用典型的 EDA 元素生成可共享的报告。要了解更多关于 R 中的探索性数据分析,请查看这个 DataCamp 课程

参考

数据集
Kaggle 内核
源代码—Github
data explorer—CRAN

这篇文章最初发表在数据科学+

通过 Python 中的 TensorFlow 使用 ML 进行简单的房价预测

原文:https://towardsdatascience.com/simple-house-price-predictor-using-ml-through-tensorflow-in-python-cbd2b637904b?source=collection_archive---------6-----------------------

现实职业正在进入 21 世纪,正如你可以想象的那样,房屋清单充斥着互联网。如果你曾经考虑过买房、租房,或者只是想看看城里最贵的房子是什么样的(我们都去过),那么你很可能去过 Zillow、Realtor.com、Readfin 或 Homesnap。如果你去 Zillow 网站搜索你附近的房子,你会看到这样的列表:

这肯定是一个审美清单,像所有分类广告一样,它有一个要价;在这种情况下,379,900 美元。但是如果你继续向下滚动,你会看到一个标题为“家庭价值”的标签,展开窗口会给你一个“Zestimate”

Zestimate 是 Zillow 预测的房子的价值;这是他们最好的猜测。Zillow 给出了这个定义,“Zestimate 住宅估价是 Zillow 的估计市场价值。这不是评估。用它作为一个起点来确定一个家的价值。

但是 Zillow 是怎么把价格猜的这么准的?要价和 Zestimate 的差价只有 404 美元。但这肯定不是手动完成的,对吗?Zillow 的数据库中有超过 1.1 亿套住房(并非目前全部在市场上),手工进行这些估算是不可行的。你可能会认为这是某种形式的算法,你可能是对的。但考虑到房屋估价的复杂性,即使是传统的算法也可能表现不佳,而且复杂得不可思议。房屋价值取决于位置、浴室数量、面积、楼层数、车库、游泳池、邻近价值等。我想你明白了。这就是本文主题发挥作用的地方,机器学习!

在这篇文章中,我将带你使用 python 中的神经网络构建一个简单的房价预测工具。喝杯咖啡,打开一个新的 Google Colab 笔记本,让我们开始吧!

步骤 1:选择模型

在我们开始告诉计算机做什么之前,我们需要决定我们将使用什么样的模型。我们需要首先问自己目标是什么。在这种情况下,我们有一些关于房子的输入(位置、浴室数量、条件等),我们需要产生一个输出:价格。这是一个数字输出,这意味着我们可以在一个连续的尺度上表达它(稍后会详细介绍)。给定这些参数,我们可以选择利用神经网络来执行回归。谷歌机器学习框架 Tensorflow 是一个很好的基础,可以在其上建立这样一个模型。

如果你不熟悉神经网络是如何工作的,这将有助于理解这里发生的事情,简单地谷歌一下或找到一个 YouTube 视频,有一个很好的资源。

第二步:收集数据

我们将要使用的数据集来自 Kaggle.com。如果你不熟悉 Kaggle,这是一个很好的机会去那里看看!本质上,它是一个存放数据科学应用数据集以及举办竞赛(通常有可观的现金奖励)的网站。事实上,Zillow 举办了一场比赛来帮助改进 Zestimate。当我告诉你奖金是 120 万美元时,我不是在开玩笑。有一天…

无论如何,去 Kaggle.com 创建一个账户,只需要几秒钟,而且是免费的。找到“编辑配置文件”并向下导航到“创建新的 API 令牌”这将创建一个名为“kaggle.json”的文件,您可以下载该文件。这是一个包含你的用户名和 API 密匙的文件,所以不要把它给任何人,也不要编辑它的内容(如果你不小心丢失了它或者改变了它,你可以让旧的过期,换一个新的)。

导航到 Kaggle 的“竞争”标签,搜索“房价:高级回归技术”您将看到有一个“Data”选项卡,我们将从这里提取数据。

旁注:你需要接受与比赛相关的条款和条件来下载数据,但这并不需要参与比赛,不用担心。

现在我们有了得到这个面包所需要的一切…我指的是数据。

第三步:建立模型

我们将要构建这个模型的环境是 Google Colab,一个免费的在线 python 笔记本环境。在浏览器中输入 colab.research.google.com,开始一个新的 Python 3 笔记本。

对于以前没有使用过笔记本的人来说,在移动下一个单元格之前,您可以通过点击 run 来编译每个单元格。

让我们从安装和导入依赖项开始:

import tensorflow as tf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler

Tensorflow 是我们将使用的机器学习框架,pandas 将作为我们的数据框架,numpy 将协助数据操作,matplotlib 是我们的数据可视化工具,sklearn 将为我们提供一种扩展数据的方法。

下一个命令将安装 Kaggle API,我们将结合 kaggle.json 文件使用它来将数据直接导入到环境中。

!pip install kaggle

下一行使用内置的 Colab 文件工具,它允许我们将“kaggle.json”上传到笔记本。只需执行下面的命令,并使用出现的按钮上传文件。

from google.colab import files
files.upload()

Kaggle API 需要该文件位于特定的位置,以便进行身份验证。这次就相信我吧。执行此命令创建目录并放置文件。

!mkdir -p ~/.kaggle
!cp kaggle.json ~/.kaggle/!chmod 600 ~/.kaggle/kaggle.json

现在我们已经准备好使用 API 导入数据了!转到 Kaggle 竞赛页面上的数据选项卡并按下以下按钮,这会将您需要的特定命令直接复制到您的剪贴板:

当然,你可以复制下面的代码,但这是你从不同的数据集/比赛中获取数据的方式。重要提示:您需要放置“!”在 Colab 中的命令前面,如果您在本地运行,就不需要这样做。

!kaggle competitions download -c house-prices-advanced-regression-techniques

如果您运行该行并收到“错误 403:禁止”,那么您可能不接受 Kaggle 竞争的条款和条件。

执行以下命令,查看当前目录中文件的名称(我们刚刚下载的内容):

!ls

现在来看一大段代码。下一个单元格正在读取。csv 文件并构建一个数据框架来存放它们。我们可以使用这个数据框架与我们的数据进行交互。这段代码获取数据帧,删除这里不需要的“Id”列,然后将数据分成两个独立的数据帧:一个用于分类值,另一个用于连续值。

#Build the dataframe for train data
train=pd.read_csv('train.csv',encoding='utf-8')
train.drop(['Id'], axis=1)
train_numerical = train.select_dtypes(exclude=['object'])
train_numerical.fillna(0,inplace = True)
train_categoric = train.select_dtypes(include=['object'])
train_categoric.fillna('NONE',inplace = True)
train = train_numerical.merge(train_categoric, left_index = True, right_index = True)

那么,我们为什么要将数据分成数字列和分类列呢?这是因为它们是两种不同的数据类型。一个由连续谱上的数字数据组成,另一个包含与类别相关联的字符串。我们需要区别对待他们。

附注:如果您想查看数据帧的内容以帮助可视化,只需调用 head()函数,如下所示。

train.head()

运行以下命令来隔离异常变量。Sklearn 将帮助我们去除数据中的异常值。这将使那些更准确地代表非异常情况的数据点的学习过程更容易。

from sklearn.ensemble import IsolationForestclf = IsolationForest(max_samples = 100, random_state = 42)
clf.fit(train_numerical)
y_noano = clf.predict(train_numerical)
y_noano = pd.DataFrame(y_noano, columns = ['Top'])
y_noano[y_noano['Top'] == 1].index.valuestrain_numerical = train_numerical.iloc[y_noano[y_noano['Top'] == 1].index.values]
train_numerical.reset_index(drop = True, inplace = True)train_categoric = train_categoric.iloc[y_noano[y_noano['Top'] == 1].index.values]
train_categoric.reset_index(drop = True, inplace = True)train = train.iloc[y_noano[y_noano['Top'] == 1].index.values]
train.reset_index(drop = True, inplace = True)

下一段代码获取数据帧,将其转换为矩阵,并应用所谓的最小最大缩放器。该过程将值缩小到指定的范围,以使训练更容易。例如,从 100 到 1000 的数字列表可以转换为 0 到 1 的范围,其中 0 表示 100,1 表示 1000。

col_train_num = list(train_numerical.columns)
col_train_num_bis = list(train_numerical.columns)col_train_cat = list(train_categoric.columns)col_train_num_bis.remove('SalePrice')mat_train = np.matrix(train_numerical)
mat_new = np.matrix(train_numerical.drop('SalePrice',axis = 1))
mat_y = np.array(train.SalePrice)prepro_y = MinMaxScaler()
prepro_y.fit(mat_y.reshape(1314,1))prepro = MinMaxScaler()
prepro.fit(mat_train)prepro_test = MinMaxScaler()
prepro_test.fit(mat_new)train_num_scale = pd.DataFrame(prepro.transform(mat_train),columns = col_train_num)
train[col_train_num] = pd.DataFrame(prepro.transform(mat_train),columns = col_train_num)

下面的代码将把分类特征散列成我们的模型可以理解的数字输入。哈希是另一篇文章的主题,如果你感兴趣,可以在谷歌上搜索一下。

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
COLUMNS = col_train_num
FEATURES = col_train_num_bis
LABEL = "SalePrice"FEATURES_CAT = col_train_catengineered_features = []for continuous_feature in FEATURES:
    engineered_features.append(
        tf.contrib.layers.real_valued_column(continuous_feature))for categorical_feature in FEATURES_CAT:
    sparse_column = tf.contrib.layers.sparse_column_with_hash_bucket(
        categorical_feature, hash_bucket_size=1000)engineered_features.append(tf.contrib.layers.embedding_column(sparse_id_column=sparse_column, dimension=16,combiner="sum"))

现在,我们将隔离输入和输出变量,然后将它们分成测试集和训练集。创建测试序列时要使用的经验法则是 80%测试和 20%训练,我已经在下面完成了(test_size=0.2)。这里的结果是测试和训练的输入和输出集

# Build the training set and the prediction set
training_set = train[FEATURES + FEATURES_CAT]
prediction_set = train.SalePrice# Split the train and prediction sets into test train sets
x_train, x_test, y_train, y_test = train_test_split(training_set[FEATURES + FEATURES_CAT] ,
                                                    prediction_set, test_size=0.2, random_state=42)
y_train = pd.DataFrame(y_train, columns = [LABEL])
training_set = pd.DataFrame(x_train, columns = FEATURES + FEATURES_CAT).merge(y_train, left_index = True, right_index = True)y_test = pd.DataFrame(y_test, columns = [LABEL])
testing_set = pd.DataFrame(x_test, columns = FEATURES + FEATURES_CAT).merge(y_test, left_index = True, right_index = True)

现在,我们可以将连续和分类特征重新组合在一起,然后通过调用 DNNRegressor 函数并传入特征、隐藏层和所需的激活函数来构建模型框架。这里我们使用了三层,每层的节点数量都在减少。激活函数是“relu”但是尝试使用“leaky relu”或者“tanh”看看你是否得到更好的结果!

training_set[FEATURES_CAT] = training_set[FEATURES_CAT].applymap(str)
testing_set[FEATURES_CAT] = testing_set[FEATURES_CAT].applymap(str)def input_fn_new(data_set, training = True):
    continuous_cols = {k: tf.constant(data_set[k].values) for k in FEATURES}

    categorical_cols = {k: tf.SparseTensor(
        indices=[[i, 0] for i in range(data_set[k].size)], values = data_set[k].values, dense_shape = [data_set[k].size, 1]) for k in FEATURES_CAT}# Combines the dictionaries of the categorical and continuous features
    feature_cols = dict(list(continuous_cols.items()) + list(categorical_cols.items()))

    if training == True:
        # Converts the label column into a constant Tensor.
        label = tf.constant(data_set[LABEL].values)# Outputs the feature columns and labels
        return feature_cols, label

    return feature_cols# Builds the Model Framework
regressor = tf.contrib.learn.DNNRegressor(feature_columns = engineered_features, 
                                          activation_fn = tf.nn.relu, hidden_units=[250, 100, 50])categorical_cols = {k: tf.SparseTensor(indices=[[i, 0] for i in range(training_set[k].size)], values = training_set[k].values, dense_shape = [training_set[k].size, 1]) for k in FEATURES_CAT}

执行以下功能将开始训练过程!这需要几分钟的时间,所以伸个懒腰吧!

步骤 5:训练模型

regressor.fit(input_fn = lambda: input_fn_new(training_set) , steps=10000)

让我们把结果可视化吧!这段代码将导入我们的数据可视化工具,计算预测值,获取实际值,然后将它们绘制成图表。

步骤 6:评估模型并可视化结果

import matplotlib.pyplot as plt
import matplotlibev = regressor.evaluate(input_fn=lambda: input_fn_new(testing_set, training = True), steps=1)
loss_score = ev["loss"]
print("Final Loss on the testing set: {0:f}".format(loss_score))import matplotlib.pyplot as plt
import matplotlib
import itertoolsev = regressor.evaluate(input_fn=lambda: input_fn_new(testing_set, training = True), steps=1)
loss_score = ev["loss"]
print("Final Loss on the testing set: {0:f}".format(loss_score))
reality = pd.DataFrame(prepro.inverse_transform(testing_set.select_dtypes(exclude=['object'])), columns = [COLUMNS]).SalePricey = regressor.predict(input_fn=lambda: input_fn_new(testing_set))
predictions = list(itertools.islice(y, testing_set.shape[0]))
predictions = pd.DataFrame(prepro_y.inverse_transform(np.array(predictions).reshape(263,1)))matplotlib.rc('xtick', labelsize=30) 
matplotlib.rc('ytick', labelsize=30)fig, ax = plt.subplots(figsize=(15, 12))
plt.style.use('ggplot')
plt.plot(predictions.values, reality.values, 'ro')
plt.xlabel('Predictions', fontsize = 30)
plt.ylabel('Reality', fontsize = 30)
plt.title('Predictions x Reality on dataset Test', fontsize = 30)
ax.plot([reality.min(), reality.max()], [reality.min(), reality.max()], 'k--', lw=4)
plt.show()

还不错!要获得更好的结果,请尝试更改激活函数、层数或层的大小。或许完全使用另一种模式。这不是一个庞大的数据集,所以我们受到信息量的限制,但这些技术和原理可以转移到更大的数据集或更复杂的问题上。

如有任何疑问、意见、担忧或建议,请随时联系我。

我也想给朱利安·海杜克大声喊出来,他的模型是。点击这里查看他的视频:https://www.kaggle.com/zoupet

简单介绍使用 TorchFusion 和 PyTorch 的条件性 GANs

原文:https://towardsdatascience.com/simple-intro-to-conditional-gans-with-torchfusion-and-pytorch-404264a3267c?source=collection_archive---------8-----------------------

人类非常善于认识事物,也非常善于创造新事物。长期以来,我们一直致力于教计算机模仿人类识别事物的能力,但创造新事物的能力长期以来一直未能被人工智能系统所掌握。直到 2014 年,Ian Goodfellow 发明了生成式对抗网络。在这篇文章中,我们将对生成对抗性网络进行一个基本的概述,并且我们将使用它们来生成特定数字的图像。

生成性对抗网络概述

想象一下,你是一名艺术家,正试图画一幅非常逼真的奥巴马画像,让法官误以为这幅画是真的。你第一次这样做,法官很容易发现你的照片是假的,然后你一次又一次地尝试,直到法官被愚弄,认为照片是真的。生成敌对网络是这样工作的,它由两个模型组成,

绘制图像的生成器 和试图区分真实图像和由鉴别器绘制的图像的 鉴别器

从某种意义上说,两者是相互竞争的,生成器被训练来愚弄鉴别器,而鉴别器被训练来正确区分哪些图像是真实的,哪些是生成的。最终,生成器将变得如此完美,以至于鉴别器将无法区分真实图像和生成的图像。

下面是由 GAN 发生器创建的样本。

Source: Karras et al, 2017 (http://arxiv.org/abs/1710.10196)

GANs 分为两大类,无条件 GANs 随机生成任意类图像,有条件 GANs 生成特定类图像。在本教程中,我们将使用条件 gan,因为它们允许我们指定我们想要生成的内容。

工具设置

训练 GANs 通常很复杂,但多亏了 Torchfusion,一个建立在 PyTorch 基础上的研究框架,这个过程将会超级简单和直接。

通过 PyPi 安装火炬融合

pip3 install torchfusion

安装 PyTorch

如果你还没有安装 torchfusion,去pytorch.org下载 PyTorch 的最新安装文件。

现在您已经完全设置好了!

接下来,导入几个类。

定义发生器网络和鉴别器

在上面,我们指定要生成的图像的分辨率为 1 x 32 x 32。

为生成器和鉴别器模型设置优化器

现在我们需要加载一个数据集,我们将尝试从中抽取样本。在这种情况下,我们将使用 MNIST。

下面我们创建一个学习者,torchfusion 有各种各样的学习者,他们高度专业化,用于不同的目的。

现在,我们可以调用训练函数来训练这两个模型

通过将 save_outputs_interval 指定为 500,学习者将在每 500 次批量迭代后显示示例生成的输出。

这是完整的代码

仅经过 20 个时期的训练,就生成了下图:

现在到了最激动人心的部分,使用你训练过的模型,你可以很容易地生成特定数字的新图像。

在下面的代码中,我们生成了数字 6 的新图像,您可以指定 0-9 之间的任何数字

结果:

生成对抗网络是一个令人兴奋的研究领域,torchfusion 通过最佳 GAN 算法的优化实现使它变得非常简单。

火炬融合由我和摩西·奥拉芬瓦(I and Moses Olafenwa)开发和维护,这是我们努力实现人工智能民主化并让地球上每个人和组织都可以使用它的一部分。

火炬传递的官方回购是 https://github.com/johnolafenwa/TorchFusion

火炬融合的教程和文档可以从https://torch fusion . readthedocs . io获得

你可以随时在推特上通过 @johnolafenwa 联系我

线性回归

原文:https://towardsdatascience.com/simple-linear-regression-2421076a5892?source=collection_archive---------2-----------------------

"正确问题的近似答案比近似问题的精确答案更有价值。"约翰·图基

线性回归是一种线性方法,用于模拟标量因变量 y 和一个或多个独立变量x之间的关系,与逻辑回归不同,这里的因变量可以取连续的值范围。使用称为线性假设的线性预测函数对关系进行建模,其未知模型参数根据数据进行估计。让我们从一个线性假设开始。

其中

我们可以用如下简洁的符号来表示。

上述等式表明,给定新的输入特征向量 x ,输出的预测值将由假设 h 给出。所以预测的准确性取决于输入特征的 权重。

如果我们用大小为 m 的向量来表示 m 训练示例的实际输出值,一种合理的方式是使用训练集来使的值接近于y .我们将的实际差值定义为 代价函数****

所以现在这个等式变成了寻找 权重 对于哪个 代价函数 J 最小。

其中
Y :为 m 个训练样本的输出向量。
X
:是大小为 m*n 的矩阵,其中每第 I 行属于第 I 个训练集。
Q :为 n 训练特征的大小为 n 的权重向量。
所以

这导致了

示例: 给定训练集此处
X =索赔数量
Y =所有索赔的总支付金额,单位为千瑞典克朗

Plot of Y w.r.t. X.

以上将解决

最后,这个模型将会是

****

The plot of data along with model fitting the data.

用 Python 编写的简单机器学习模型,只有 5 行代码

原文:https://towardsdatascience.com/simple-machine-learning-model-in-python-in-5-lines-of-code-fe03d72e78c6?source=collection_archive---------0-----------------------

在这篇博客中,我们将训练一个线性回归模型,并期望在新的输入上执行正确。

任何机器学习模型的基本思想是,它暴露于大量的输入,并且还提供适用于它们的输出。通过分析越来越多的数据,它试图找出输入和结果之间的关系。

考虑一个非常原始的例子,当你必须根据天气决定是否穿夹克时。你可以访问我们称之为的训练数据

+---------------------+---------------+
| Outside Temperature | Wear a Jacket |
+---------------------+---------------+
| 30°C                | No            |
| 25°C                | No            |
| 20°C                | No            |
| 15°C                | Yes           |
| 10°C                | Yes           |
+---------------------+---------------+

不知何故,你的大脑找到了输入(温度)和输出(决定穿夹克)之间的联系。

因此,如果温度是 12 摄氏度,你仍然会穿夹克,尽管你从来没有被告知这一特定温度的结果。

现在,让我们转到一个稍微好一点的代数问题,这个问题将由计算机来解决。

在我们开始之前,不要忘记安装 scikit-learn ,它提供了易于使用的功能和预定义的模型,节省了大量时间

pip install scikit-learn

样本训练集

这里,X 是输入,y 是输出。

给定训练集,您很容易猜到输出(y)是(x1 + 2x2 + 3x3)。

如何生成训练集

ML 模型-线性回归

使用线性回归模型很简单。创建一个模型,训练它,然后使用它:)

训练模型

我们已经准备好了训练集,所以创建一个线性回归模型,并将训练数据传递给它。

测试数据

X = [[10,20,30]]

结果应该是 10 + 202 + 303 = 140。让我们看看我们得到了什么…

结局:【140。]
系数:[ 1。2.3.]

你注意到刚才发生了什么吗?该模型可以访问训练数据,通过这些数据计算分配给输入的权重,以达到期望的输出。在给出测试数据时,它成功地得到了正确的答案!

如果你想更深入地研究机器学习,使用 Python 我更喜欢从这本书开始。

[## Python 机器学习简介

机器学习已经成为许多商业应用和研究项目不可或缺的一部分,但这个领域是…

shop.oreilly.com](http://shop.oreilly.com/product/0636920030515.do?sortby=publicationDate)

我也做了很多实验,修补代码。在我尝试公开 scikit 的功能的地方,可以随意使用 ML 原型。如果你觉得这篇文章有趣,别忘了鼓掌。

创建动画图形的简单方法

原文:https://towardsdatascience.com/simple-method-of-creating-animated-graphs-127c11f58cc5?source=collection_archive---------6-----------------------

数据科学工具包

介绍

答在我最近的一篇文章发表后,许多人向我询问如何用 Python 制作动画图表的技巧。事实上,经常会出现静态图表已经不够用的情况,为了说明我们正在处理的问题,我们需要更强大的工具。当然,有许多库允许我们制作动画,有时甚至是交互式图形,比如 Bokeh、Pygal 或我个人最喜欢的 Plotly。然而,这一次我们将采用传统的方法——我将向您展示如何仅使用“简单的”Matplotlib 和一些命令行技巧来创建令人印象深刻的图表。在文章中,我将只放置代码中最重要的部分。但是在我的 GitHub 上,你可以找到用来创建可视化展示的完整笔记本。

Figure 1. Gradient descent visualization coming from my previous article

Matplotlib 动画 API

寻找我可以在这篇文章中使用的有趣的例子,我决定说明洛伦兹吸引子。其优雅的形式和独特的属性使其成为创造引人注目的视觉效果的绝佳材料。洛伦兹吸引子以对几乎相同的初始条件产生完全不同的结果而闻名。让我们尝试使用 Matplotlib 库中的专用动画 API 来可视化这个属性。我们将在三维空间中创建三个独立的轨迹,并呈现它们在不同时间点的行为。首先,当然,我们必须导入所有必要的依赖项。

将帮助我们执行动画的类是FuncAnimation ( 链接)。然而,为了使用它,我们首先必须准备一个基本的空图表和一个函数,该函数将在每次迭代中执行,以更新当前帧中呈现的数据。在我的例子中,创建和样式化图表的过程被提取到一个单独的辅助函数中— create_blank_chart_with_styling,您可以在完整的笔记本中查看它的细节。在其他事情中,它负责选择背景颜色,调用轴或缩放它们。创建图表后,我们还定义(目前为空)数据序列,用符号表示相应的轨迹。

我们动画的核心是图表更新功能,它将当前渲染帧的索引作为参数,并确保在图表上显示一组适当的数据。在版本中,我在每一帧中使用 Matplotlib,获取一个我们在构造函数中提供的干净的图形,并将当前选择的数据添加到其中。这意味着在每一帧中,我必须添加我想要显示的所有元素。顺便说一句,值得注意的是,该库还包含另一种模式,即在上一次迭代中获得的图中添加更多元素。

Figure 2. Lorenz Attractor created using the Matplotlib animation API

最后,我们创建一个FuncAnimation类的实例,给出参数:初始图形、更新函数、帧数以及它们应该改变的时间间隔。我们现在可以选择输出文件格式和我们的动画质量。我们工作的结果可以在图 2 中看到。

让我们阅读神经网络思想

M atplotlib 动画 API 很棒,但我经常选择将单独的帧渲染为 png 图像,然后使用 ImageMagick 将它们组合成一个移动的 gif 这是一个在 Linux、Mac 以及 Windows 上可用的非常有用的工具。我这样做是因为创建一个更新图表的函数并不总是那么明显和方便——例如,当我们想要可视化我们的神经网络的学习过程时,使用 Keras 进行训练。

Figure 3. Fages obtained in successive epochs of neural network learning process.

由于使用了keras.callbacks.LambdaCallback ( link ),我们可以在每次迭代后访问我们的模型,收集所有必要的数据并进行可视化。我们所要做的就是将我们的渲染方法作为.fit()方法的一个参数来传递。我为完成这项任务而创建的函数如下所示。

假设我们已经定义了模型的架构(参见如何做),我们现在可以开始训练了。让我们不要忘记添加我们的回调。我们可以这样做。

结果,在每个时期,我们未来动画的一个单独的帧被创建。获得的所有图像在图 3 中并排显示。现在我们唯一要做的就是将它们相互结合,创造出流畅的动画。幸运的是,使用 ImageMagic,我们只需要一个命令。

Figure 4. Visualization showing the boundaries of classification during the neural network learning process.

结论

我希望我的提示和例子对你有所帮助,你会在工作中、在大学里或者在下一篇关于媒体的文章中用到它们。你需要的只是一点创造力和一些空闲时间。如果你喜欢这篇文章,分享出来,在 TwitterMedium 上关注我,在 GitHubKaggle 上查看我正在做的其他项目。保持好奇!

成功数据治理的简单指标

原文:https://towardsdatascience.com/simple-metrics-for-a-successful-data-governance-ea55b1887d46?source=collection_archive---------0-----------------------

最近,许多公司已经实施了数据治理框架。数据治理不应被认为是一次性的,而是一项持续的工作,以确保数据在组织的优先级中得到适当的重视。高级管理人员倾向于问这样的问题“我们到了吗?”展示数据治理的有效性。显示成功数据治理进度的一种方式是通过监控某些关键指标。让我与您分享识别任何数据治理功能成功的 4 大指标。

1)数据质量得分的提高

2)遵守数据管理标准和流程

3)风险事件的减少

4)降低数据校正成本

1)数据质量得分的提高

每一个产生/拥有数据的职能部门都应该监控其产生的数据的质量。简单地说,质量被定义为数据的完整性、准确性和及时性。这些维度中的每一个都可以有一个三维分数,也可以有一个适当加权的综合分数。关键是要确保对这些进行测量和监控,以进行改进。

2)遵守数据管理标准和流程

作为框架的一部分,几乎所有的公司都建立了某种标准/政策,需要所有员工遵守。这些文档说明了在各种情况下需要遵循的准则。例如,应该限制对生产数据的访问,但是在特殊情况下,IT 部门可以通过适当的控制程序进行修改,并获得一定的批准。必须有一个认证流程(自我认证或通过其他方式),通过该流程,每个部门都应确认遵守标准和政策。

3)风险事件的减少

每当出现数据质量问题时,都有可能导致风险事件。

事件可以是

A)监管机构因误报而施加的处罚/罚款

b)由于不良数据导致的不准确决策

c)由于错误报告导致的客户损失

一旦实施了数据治理,公司应该会看到此类风险事件的减少。如果风险事件持续发生,这表明治理功能出现故障。

4)降低数据校正成本

公司需要花费成本来纠正不良数据或增强数据以满足其需求。数据治理的核心原则是“在源头修复”,即坏数据不是由这些数据的消费者修复的,而是在它产生的源头修复的。有时这可能是在组织边界内,或者可能来自外部供应商。一个组织应该跟踪整改成本,以确保将其保持在最低水平。

一个更加成熟的数据治理功能可以确定其他成功指标,例如即将出台的法规对关键数据资产的影响等等。

如果您的组织正在评估数据治理职能的成功进展,以上 4 个简单指标应该提供一个起点。

这篇文章发表在 LinkedIn 的 https://www . LinkedIn . com/pulse/simple-metrics-successful-data-governance-suriya-n-subra manian-fcca

你可以在 https://www.linkedin.com/in/suriyansubramanian/的 LinkedIn 上关注我

应用中的简单 NLP 搜索 Scala 中的逐步指南

原文:https://towardsdatascience.com/simple-nlp-search-in-your-application-step-by-step-guide-in-scala-22ca1ce3e475?source=collection_archive---------1-----------------------

全文搜索很容易使用。但是自然语言固有的模糊性导致搜索结果存在误报。为了获得更准确的结果,我们需要改变方法,向搜索引擎提供更多特定领域的数据。

改善搜索结果最常见和最容易的方法是引入过滤器,即多个输入字段(文本字段、单选按钮等)。)以属性命名。这样我们就知道如何构造查询,然后返回特定的结果。结合一些近似的字符串匹配算法,我们可以获得非常精确的搜索结果。不幸的是,过滤器需要具有多个字段的表单,代价是简单的 UX。(参见图 1 )。

Figure 1

如果我们希望坚持使用单个文本字段,并且仍然有准确的搜索结果(见图 2 )会怎么样?当然,人们需要使用自然语言处理(NLP)工具。但是 IT 行业的每个人都知道 NLP 很难掌握,大多数人认为这是一种高度学术化的方法。如何轻松地利用这一点来改善特定领域的搜索结果?

Figure 2

领域

领域的特殊性是该方法的关键部分。机器学习算法还远远没有准备好回答一般的问题。即使算法存在,它们也离我们很远。为了简单起见,我们必须缩小范围。通常,当我们需要引入一个搜索表单时,我们在某个区域内操作,即在 ebay.com 找到一辆车,我们指定车的类型、生产年份、制造商、型号等..

对于本文,让我们以电影放映的领域为例,即:电影、剧院和日期时间的元组。我们也可以假设我们知道电影院的地理位置和电影的类型。我们将通过标题(或只是流派)、影院名称(或只是地点)以及放映的日期和时间来查询电影放映,这是我们需要从用户那里收集的数据。我们想要处理的示例表达式:

  • 明天旧金山的火星人:查询旧金山所有明天上映火星人的影院,
  • 下周 amc 的《归来者》:查询 AMC 剧场下周《归来者》的所有演出,
  • cinemark 下周三:查询 Cinemark 影院下周三将上演的所有节目,
  • 6 月 11 日旧金山的戏剧:查询旧金山所有剧院将于 6 月 11 日上演的戏剧。

所有表达式都从自然语言转换为以下形式的查询:

对自然语言处理的需求

很难从自然语言中提取信息。如果我们假设只有几种输入语句,如【电影名称】****【剧院位置】【时间表情】,那么就有可能为这种语句显式地编写解析器。但是,即使有人设法做到了这一点,这样的算法将是不可维护的。有了 NLP 工具,我们可以在不需要显式编程的情况下解决这个问题。

此外,一些语句在结构上极其相似,例如:【电影名称】【时间表达式】【剧院名称】【时间表达式】——不可能明确区分这两种语句。NLP 工具还关心【MOVIE _ NAME】【THEATER NAME】的结构,那么当从语句中提取信息时,它拥有比显式解析器更多的数据来做出决定。

解决方案的描述

对于我们的例子,我们需要的信息提取的唯一子任务叫做命名实体识别。正确标记了语句之后,我们就能够编写我们的查询。我们所说的标记是指为语句中的每个单词分配一些特定于领域的元信息,例如:

  • 明日旧金山的火星人——(电影 _ 名字:火星人)(介词:在)(影院 _ 地点:旧金山)(时间 _ 表情:明日)
  • amc 下周三——(剧场 _ 名称:amc)(时间 _ 表情:下周三)

工具

当试图解决这个问题时,我们的第一次尝试是尝试斯坦福命名实体识别器,它给了我们惊人的结果,但不幸的是,由于 GNU GPLv2 许可,它不能用于商业。

最后,我们决定使用 ScalaNLP 套件中的 Epic 库。Epic 实现了许多 NLP 算法,但是我们遇到的缺点是缺少文档,因此它的使用远非简单明了。

抽样资料

为了训练命名实体识别器(NER ),我们需要为算法提供样本数据。如果我们没有任何现实生活中的数据,那么我们可能会根据可能的模式生成一些随机语句,例如:

  • [影院 _ 位置][时间 _ 表情]中的[电影 _ 名称]
  • [影院 _ 位置]中的[电影 _ 流派][时间 _ 表情]

输入的格式取决于我们使用的库。描述训练数据的学术标准 CoNLL 涵盖了我们所需要的更多。幸运的是,有一种方法可以简化标记,即:

训练样本的最佳大小取决于领域的复杂性,应该根据经验进行验证。

你可以在 GitHub 查看我们如何生成样本数据的例子。

训练 NER

我们需要对标记语句之间的关系进行编码,然后构建一些一致的解释以供进一步重用。解决这个问题的统计工具被称为条件随机场(CRF)。在 ScalaNLP 中,有两种可用的 CRF 实现。第一个 epic.sequences.CRF 是普通的线性链 CRF,第二个 epic.sequences.SemiCRF 是半马尔可夫线性链的实现,它应该以较小的精度代价具有更好的性能。

将输入数据加载到序列阅读器
ScalaNLP 具有内置的用于 CoNLL 数据的解析器—epic . corpora . conllsequencereader,它接受我们在示例数据一节中提出的数据输入。

应用分段函数
我们通过将输入数据转换为epic . sequences . segmentation【Any,String】来训练 CRF。分段是将相同的标签组合成一行。

我们使用的分段函数:

构建 CRF
将输入分段后,我们可以构建 CRF:

使用经过训练的通用报告格式来标记序列

epic . preprocess . tokenize只是通过空格进行标记。

分段携带标记序列。当我们呈现一个样本表达式时,我们得到一个带有标记段的字符串:

【电影 _ 名称: 火星人 】【介词: 】【剧场 _ 地点: 三藩 】【介词: 】【时间 _ 表情:2016 年 6 月 11 日唯一缺少的部分是 TIME_EXPRESSION s。我们需要类型 DateTime 的从的显式参数。我们可以使用 PrettyTime::NLP 来解析显式的时间表达式,比如:2016 年 6 月 11 日,但是如果我们想要获得更复杂的东西,比如下周三明天,我们应该再次使用 NLP 方法,即训练 CRF 用于时间表达式。结果相当惊人。 crf 一旦经过训练,马上就能发挥作用。解释的准确性将根据领域的复杂性和训练样本的大小而变化。在我们的案例中,我们对准确性感到惊讶——即使对于含糊不清的陈述, crf 也做得很好。****

对于 20 万条输入语句的样本量(用simple-ner-search-dataset-generator生成),我们用 ner-trainer 对 ner 进行了训练,得到如下结果:

通过安装 ner-trainer 并通过调用ner-trainer-l film-screenings.tar.gz加载序列化的示例,您可以在互动会话中亲自检查这一点。

权衡

不幸的是,训练 CRF 非常耗时(以小时计算)。为了不浪费时间,需要序列化 SemiCRF 对象。序列化是以牺牲二进制兼容性为代价的。此外,SemiCRF 可能是一个相当重的物体,因此会增加额外内存的成本。

Epic 库不好用。文档不是很有帮助,也缺乏严肃的静态类型。即使在这个简短的例子中,我们也无法避免将作为的实例。

结论

目前可用的库很好地覆盖了问题的困难部分。权衡是可能克服的,而且其中许多相对容易解决,所以将来可能会消失。尽管如此,我们还是有可能构建非常复杂的基于自然语言处理的搜索,而不会淹没在复杂的数学中。即使是新手也应该能够在几天内实现搜索。

资源定位符

你们所有人都觉得被邀请去使用 NER 训练器和数据集生成器在你们的领域进行测试和黑客攻击。请在评论中提供反馈,说明这种方法如何为您服务。

该帖子最初在 tech.evojam.com 发表。

调整深度神经网络的简单参考指南

原文:https://towardsdatascience.com/simple-reference-guide-for-tuning-deep-neural-nets-e2d37d6fa933?source=collection_archive---------20-----------------------

入门指南

考虑到涉及到如此多的参数,设计深度神经网络可能是一项痛苦的任务,而且似乎没有通用公式适合所有的用例。我们可以使用 CNN 进行图像分类,使用 LSTMs 进行 NLP 相关的任务,但是仍然需要特征的数量、特征的大小、神经元的数量、隐藏层的数量、激活函数的选择、权重的初始化等。在不同的使用案例中会有所不同。

Image Dataset: with neighboring pixels being related.

这些参数的变化可归因于不同类型的数据,需要独立于其他数据集的分析。像图像数据集将具有不同的属性,因为相邻位置的像素是相关的,但是在关系数据库中,条目可以是随机的,没有关系。因此,为此需要一种不同的方法。

我们能够概括数据类型的类型和适合它们的神经网络结构,如用于图像、音频、视频的 CNN 和用于 NLP 相关任务的 RNN/lstm 等。但是,为了最大限度地发挥它们的性能,我们应该让它们变得更聪明。什么是神经网络的智能?概括而不是记忆神经网络可以被认为是智能神经网络。这种行为在任何形式的学习中都是可取的。

dim(h) < dim(xi) <- undercomplete autoencoder || overcomplete autoencoder -> dim(h) ≥ dim(xi)

为简单起见,本文只讨论自动编码器,这是一种特殊类型的前馈神经网络,它对隐藏层中的输入进行编码,并从该隐藏表示中进行解码。CNN 是自动编码器的一个例子,例如,CNN 以与自动编码器相同的方式对 MNIST 函数中的数字进行分类,其中网络试图近似从隐藏层重构输出信息的函数。每个神经网络架构都有自动编码器作为其基本块。因此,通过对它们的讨论,我们可以扩展不同深度学习架构的思想。

在本文中,我们将探索微调网络的技术,以获得更好的验证准确性,从而实现更好的预测。此外,我们还将研究这些技术背后的一些数学知识,以加深对这些技术背后的理解。

创建智能自动编码器有什么问题?

嗯,我们真正想从神经网络中得到的是从可用数据中归纳出 T1,而不是 T2 记忆 T3。记忆的问题是模型可能会过度拟合。因为深度学习模型很复杂,并且倾向于过度拟合目标函数。考虑非常基本情况,其中模型在训练数据集上被广泛训练,使得训练数据集上误差最小化并接近零。有可能神经网络没有捕捉数据的趋势,只是记住了用非常复杂的函数再现整个数据的方法。

让我们使用偏差 v/s 方差权衡的概念来更清楚地理解这一点。看看下面的图,x 轴代表模型的复杂性,而 y 轴代表误差。随着复杂度的增加,训练误差趋于减小,但方差增大,验证误差增大。

Blue: Training Error, Red: Validation Error. Initially bias will be high with model being primitive. With training error approaching zero, model will overfit resulting in high variance.

我们想要对变化更敏感的模型,以捕捉稀疏但重要的特征的微小细节。因此,欠拟合数据根本不是一个选项。因为更复杂的模型对变化更敏感。只有在深度学习的背景下进行关于过度拟合的讨论才有意义。

对于示例以过完备自动编码器为例,在这种情况下,它们可以学习简单琐碎的编码,即在整个网络中复制粘贴值。比如将输入(xi)复制到隐藏层(h),然后再从 h 复制到输出层(x hat )。显然,错误将是最小的,但没有学习😉

It is also a type of overfitting as autoencoders captures all the variations in the mapping of weights in training data. Remember, above figure doesn’t mean that undercomplete autoencoders doesn’t have overfitting problems instead cause for them is different like in complex network architecture.

让我们建立在上述讨论的想法上,为了深度学习自动编码器的成功,必须消除过度拟合。当然,也有其他问题,如没有足够的数据大量参数,相关特征是否被学习,何时停止训练。从这里我们可以说智能自动编码器是对我们可以观察到的信息进行归纳,并从中了解重要趋势,从而能够做出预测的编码器。让我们开始探索这些技术,目的是培养直觉,找到使用它们的理由和合适的例子,以增加我们的学习。

  1. 数据集扩充
  2. 提前停止
  3. l2 正则化
  4. 避免普通的自动编码器:噪声和稀疏
  5. 参数共享和捆绑
  6. drop 和 DropConnect 的集成方法

数据集扩充

在计算机视觉分类任务中,模型通过更多的训练数据学习得更好。但是大数据的问题是它增加了训练时间。

嗯,深度学习模型中的参数数量是巨大的(百万量级)。如果一开始就没有足够的可用数据,这显然会有所帮助。但是,如果你已经有了足够的数据会有帮助吗?是的,因为它将增加数据集中的相关特征,这有助于自动编码器学习重要的稀疏特征,而不是不相关的丰富特征。

数据扩充是一种从现有数据中创建新数据的技术,目的是增加原始数据中的相关特征。请参见下图,了解数据扩充。

Invariance: data is robustly classified at difference in translations, rotations, size, viewpoints and illumination.

以这种方式增加用于分类的最明显的特征成为最相关的特征。在 ML 管道中哪里增加我们的数据?首先是离线增强应用变换并将图像添加到数据集。但是,它会根据应用的变换数量增加大小。其次,在线增强是在输入到我们的学习模型之前应用于小批量的。在这里,看到一些张量流脚本应用于这样的转换,并假设我们不关心图像边界外的东西。

这是什么意思?假设图像的某个部分什么也没有,即它是未知空间,那么我们需要如下不同的变换。例如,一些黑色背景的旋转图像。

From the left, we have the constant, edge, reflect, symmetric and wrap transformations applied. Courtesy: Nanonets

Tensorflow 脚本基于上述对小批量数据应用简单转换的假设。

**# 1\. Flip: 'x' = A placeholder for an image.** shape = [height, width, channels]
x = tf.placeholder(dtype = tf.float32, shape = shape)
flip_2 = tf.image.flip_up_down(x)
flip_5 = tf.image.random_flip_left_right(x)**# 2.** **Rotate: 'y' = A batch of images
# To rotate in any angle. In the example below, 'angles' is in radians** shape = [batch, height, width, 3]
y = tf.placeholder(dtype = tf.float32, shape = shape)
rot_tf_180 = tf.contrib.image.rotate(y, angles=3.1415)**# 3\. Noise: 'x' = A placeholder for an image.** shape = [height, width, channels]
x = tf.placeholder(dtype = tf.float32, shape = shape)**# Adding Gaussian noise**
noise = tf.random_normal(shape=tf.shape(x), mean=0.0, stddev=0.5,
dtype=tf.float32)
output = tf.add(x, noise)

可以类似地为随机裁剪、换行、颜色通道移动等编写其他增强。

提前停止

顾名思义,这给了我们一些想法,我们可以通过在训练时尽早停止来避免过度适应。但是多早停止呢?基本上,我们的目标是在训练误差趋于零,验证误差即将爆发之前停止。

Patience Parameter P: If you are at step k and there was no improvement in validation error in the previous p teps then stop training and return the model stored at step k − p.

这些提前停止规则通过将原始训练集分成新的训练集和验证集来工作。在确定过度拟合何时开始时,验证集上的误差被用作原始训练误差的替代。有了 Keras,你可以简单地用下面的方法做到这一点。

keras.callbacks.EarlyStopping(monitor='val_loss',
                              min_delta=0,
                              patience=0,
                              verbose=0, mode='auto')

min_delta是是否将某个时期的损失量化为改善的阈值。如果损失差异低于min_delta,则量化为无改善。最好让它为 0,因为我们感兴趣的是损失何时变得更严重。patience自变量代表当你的损失开始增加(停止改善)时,在停止之前的周期数。mode争论取决于你监控的数量的方向(应该是减少还是增加),因为我们监控损失,我们可以使用min

现在,如果我说提前停止也是一种正则化技术。这个说法是真的吗?让我们看少量的数学来理解早期停止的可见工作的背后。记住,正则化是在学习神经网络中对权重&偏差添加一些约束的任何技术。

Update rule for Stochastic Gradient Descent Method. Let ‘τ’ be maximum value gradient of delta(wi). Apply inequality to above equation and we get:

Clearly, t controls how far wt can go from the initial w0. It controls the space
of exploration.

提前停止停止只允许 t 更新参数维度越重要,与其相关的损失就越大,因为使用上述等式,我们控制学习速率和t。只有与梯度相关的损失仍然是主导因素,这实际上意味着只有损失越大的重要参数才占更多。因此,与不太重要的参数相比,重要参数的比例缩小较少,这将导致更好的精度。这类似于 L2 正则化,参见下文。

L2 正则化

正则化是在学习时分配给模型的约束。L2 正则化是权重衰减正则化,它使权重更接近原点,同时更多地缩小不太重要的要素。

让我们以直观的方式来理解真误差的概念。该误差可以用下面的给定形式表示,其中经验误差项是基于估算程序,因为我们不知道 f(x)。

where yi = f(xi) + ε, ε is small value

主要目的是将模型复杂性对真实误差的影响联系起来。显然,它将训练误差加上一些东西。那是什么东西?利用斯坦引理和一些数学知识,我们可以证明

When a small change in the observation causes a large change in the estimation(fhat(xi)). The error will be more.

这和复杂模型有关系吗?是的,上述观察结果与模型越复杂,对观察结果的变化越敏感这一事实有关。因此,我们可以说真实误差=经验训练误差+小常数+ω(模型复杂度)。这个ω是正则化的基础。因此,在正则化中,我们的目标是最小化由于模型复杂性而导致的误差,而模型复杂性又与偏差-方差权衡相关。

The intuition for adding this term is that training error doesn’t drive to zero. w influence gradient and update rules from above equations.

以上加入更新规则和 SGD 的公式是什么意思?等式上面提到的两个运算在数学上表示权重矩阵在重要性方向上的缩放,即具有主要特征值和次要特征值的权重矩阵被缩小,但是不太重要的特征被缩小得更多。该正则化操作有效地首先旋转权重矩阵,然后对角化它,然后再次旋转它。这里,在等高线图上可以看到这些操作的效果。参考这篇文章的等高线图,只看那部分。

weight vector(w∗) is getting rotated to (w̃). Geometrically it is visible that all elements are getting shrunken down but for some more shrinking is there like the one in the direction of w1. Important features gets more weight assigned.

这是 Tensorflow 脚本,用于在基于上述公式的神经网络模型中使用正则化。第一个例子是仅在一层上使用它,第二个例子是在所有层上使用它。

**# Code 1:**
# Loss function using L2 Regularization
regularizer = tf.nn.l2_loss(weights)
loss = tf.reduce_mean(loss + beta * regularizer)
# Optimizer.
 optimizer = tf.train.GradientDescentOptimizer(0.5).minimize(loss)**# Code 2:** #Loss for all trainable variables, 0.001 is beta above
vars   = tf.trainable_variables() 
regularizer = tf.add_n([ tf.nn.l2_loss(v) for v in vars ]) * 0.001
# Let's say you wan't to regularize biases
regularizer = tf.add_n([ tf.nn.l2_loss(v) for v in vars
                    if 'bias' not in v.name ]) * 0.001# More descriptive code
regularizers = tf.nn.l2_loss(weights_1) + tf.nn.l2_loss(weights_2) + tf.nn.l2_loss(weights_3) + tf.nn.l2_loss(weights_4) +         tf.nn.l2_loss(weights_5) + tf.nn.l2_loss(weights_6)loss = tf.reduce_mean(loss + beta * regularizers)

避免普通的自动编码器:噪声和稀疏

考虑如上所述的过完备普通自动编码器的情况。显然,他们容易过度适应和琐碎的学习。因此,在这些情况下,使用这些普通的自动编码器不会有太大的好处。解决这一问题的一种方法是向输入中添加噪声,这将迫使神经网络不学习琐碎的编码,而是专注于更多的概括。

A denoising encoder simply corrupts the input data using a probabilistic process (P (x(tilda)ij |xij )) before feeding it to the network. These are known as Denoising Autoencoders.

# Generate corrupted MNIST images by adding noise with normal dist                       # centered at 0.618 and std=0.618 
noise = np.random.normal(loc=0.618, scale=0.618, size=x_train.shape)
x_train_noisy = x_train + noisenoise = np.random.normal(loc=0.618, scale=0.618, size=x_test.shape)
x_test_noisy = x_test + noise# np.clip to move out of bound values inside given interval
x_train_noisy = np.clip(x_train_noisy, 0., 1.)                       x_test_noisy = np.clip(x_test_noisy, 0., 1.)

Plot describes neurons firing for different features like strokes, edges for MNIST dataset digits. Clearly we can see more meaningful patterns are captured by denoising AE as compared to Vanilla AE.

随着高斯噪声的加入,这些隐藏的神经元成为边缘检测器,PCA 不能给出这些边缘检测器。此外,噪声可以应用于目标类别,这将导致具有随机分析的软目标,而不是硬目标。

稀疏自动编码器也用于解决稀疏参数的这种问题,当特征与要观察的特征相关时,这将导致神经元在罕见的情况下放电。可以写成 Lˇ(θ)= L(θ)+ω(θ),其中 L(θ)是平方误差损失或交叉熵损失,ω(θ)是稀疏性约束,它强制触发重要特征的神经元。

奖励:收缩型自动编码器,正则项ω(θ)= | | j x(h)||^ 2 是编码器的雅可比矩阵。雅可比矩阵的(j,l)项捕捉到第1个神经元的输出变化,而第个神经元的输入变化很小。L(θ) —捕捉数据中的重要变化&ω(θ)—不捕捉数据中的变化,因为雅可比使神经元对变化不敏感。通过这种权衡,我们可以只捕捉最重要的特征。对于稀疏 AE 可以进行类似的论证。

参数共享&捆绑

共享权重 简单来说就是使用相同的权重向量来进行运算。这样做的主要动机是限制参数的数量。

1=𝑤𝑥[1:3], 2=𝑤𝑥[3:5], 3=𝑤𝑥[5:7]

我们可以通过一个直观的假设来大幅减少我们的参数,如果一个特征在一点上很重要,那么它在另一点上也很重要。示例:如果在特定位置检测边缘很重要。因此,由于图像的 的 平移不变结构,对于所有位置,边缘重复自身。这将导致更快的收敛。此外,我们限制了灵活性,这也可以作为避免过度拟合的正则化机制。考虑这样一种情况,我们希望并行处理两组图像,但也希望各列共享参数。

def function(x, reuse):
  with tf.variable_scope(layer_name) as s:
    output = tf.contrib.layers.convolution2d(inputs = x, num_outputs = 10, kernel_size = [3, 3], stride = [1, 1], padding = 'VALID', reuse = reuse, scope = s)
  return output

output1 = function(image1, False)
output2 = function(image2, True)

权重绑定概念基于与上述相同的想法,具有相同的动机来减少向下参数,但应用于自动编码器单元,其中编码器权重和解码器权重被绑定和使用。它减少了自动编码器的容量,并作为一个正则化。

Tie the weights of the encoder and decoder i.e., W∗=WT

整体到辍学和 DropConnect

集成组合不同模型的输出以减少泛化误差,模型可以是不同的分类器。这里,它们是在不同的超参数、特征和训练数据的不同样本上训练的相同神经网络的不同实例。 Bagging 是一种跨整个数据集的方法,它根据训练数据的子集训练模型。因此,一些训练示例没有显示给定的模型。它允许不同的神经元跨训练数据集捕捉不同的相关特征。所有模型平均预测产生的误差?

Expect Square Error is given by: Expectation of error made by average prediction of all models.

从上面可以看出,模型之间的独立性越强,误差就越小,只有(V/k)。非常好,因为当神经网络的结构变化很大时,误差理想地变得非常小。但是,随着单个模型数量的增加,要处理的训练参数的数量会激增。这使得训练在计算上变得昂贵。

如果我们能减少这些参数不是很好吗?此外,不同的架构将帮助我们增加模型之间的差异。这两个问题通过退学解决了。它给出了组合许多不同网络的近似方法,并在没有任何显著开销的情况下训练几个网络。它在所有网络之间共享权重,并为每个训练实例采样不同的训练网络。只有活动参数从正向和反向传播中更新。不要聚集 2^n 稀疏网络,而是通过训练期间每个节点打开的时间来缩放其输出。

Dropout refers to dropping out units. i.e. Temporarily remove a node and all its incoming/outgoing connections resulting in a thinned network.

它应用于每个训练示例中的特征,导致某些特征对网络不可用。因为一个神经元不能完全依赖于一个输入,所以这些网络中的表示往往更加分散,网络不太可能过度适应。这种情况发生是因为丢失给隐藏单元添加了屏蔽噪声,这阻止了协同适应,本质上隐藏单元不会依靠其他单元来检测特定特征,因为那些单元可能会被丢失。这使得隐藏单元更加健壮。

**# Simple keras implementation of MNIST for dropout**import tensorflow as tf
mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(512, activation=tf.nn.relu),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test)

什么是 dropconnect ?假设我们决定随机丢弃权重子集,而不是丢弃节点。其行为方式与辍学类似。从伯努利分布中提取的二进制掩码被应用于原始权重矩阵。

Courtesy: nickcdryan

不是在每次训练中随机丢弃连接,而是由于输入数据类或连接对更深层的贡献,连接会丢弃并保持丢弃。

tf.nn.dropout(W, keep_prob=p) * p 
OR
tf.layers.dropout(W, rate=1-p) * p

结论

何时使用这些技术的直觉我们可以创建有效的深度神经网络,这些网络在其核心内更智能,同时具有学习任何特定任务的功能。有了这些知识,我们对创建更好的深度学习架构有了更好的理解。但是,这绝不意味着这个讨论是完整的,因为随着更好的精度更快的收敛也是一个期望的行为。让我们看看后续文章中关于衔接的内容。

感谢艾西瓦娅的改进。基线内容改编自来自 IITM 的 CS7015(DL) ,由 Mitesh M. Khapra 教授主讲的精彩课程。感谢阅读!!

简单强化学习:时间差异学习

原文:https://towardsdatascience.com/simple-reinforcement-learning-temporal-difference-learning-53d1b3263d79?source=collection_archive---------18-----------------------

Exploration Image: Credit to Photographer https://www.pexels.com/@valentinantonucci

所以最近我读了很多关于强化学习的书,还看了大卫·西尔弗的 强化学习简介 视频系列,顺便说一下,这些视频非常棒,我强烈推荐它们!从传统的统计学和机器学习背景来看,就研究生院和工作项目而言,这些主题对我来说有些新。因此,就我个人的学习而言,并与感兴趣的人分享我的学习,我想我会通过一个中等的帖子来存档,同时试图使这些概念尽可能简单易懂。

为什么我们要使用强化学习而不是其他监督学习方法呢?为了回答这个问题,我想出了这个适时的例子:

假设你是 NFL 的超级粉丝,你想预测即将到来的赛季的胜利数。在赛季初,你可能会看到一些变量,如:过去赛季的胜利,受伤球员的数量,天气预报,第一年首发球员的数量等。然后你拟合一个模型,预测一个 9 胜赛季。你有一个很好的团队,但一个未经证实的新四分卫(与去年相比只少了 1 场比赛)。在前 5 场比赛后,你的球队战绩为 5-0,你的新四分卫已经被誉为未来的名人堂成员。

在这个例子中,使用监督学习模型,你必须等到赛季结束后才能学习和做出任何改变。然而,通过强化学习,你可以在学习过程中获得信息,帮助你修正最初的预测。这个应用程序在任何时候都可以很好地工作,只要有一个时间或时间步长组件,您就可以不断地接收信息,并对您的目标或估计进行调整。

现在让我们看一个使用随机漫步(图 1)作为环境的例子。这是萨顿和巴尔托在《T4 强化学习:导论》一书中找到的一个例子。你可以在他们的网站上免费下载数字第二版。基本思想是,你总是从状态“D”开始,以 50%的概率随机向左或向右移动,直到到达终点或结束状态“A”或“G”。如果你在状态“A”结束,你得到的奖励是 0,但是如果你在状态“G”结束,奖励是 1。从“B”到“F”状态没有奖励。

Figure 1: Random Walk Example [1]

在这个例子中使用强化学习的目的是看看我们是否可以通过无模型方法准确预测这些状态中的每一个的值。基础真值仅仅是每个状态相对于结束于状态‘G’获得奖励的概率。因此,我在下面添加了一个表格,标明了我们要评估的每个州的标签。让我们讨论一下我们的模型,现在我们知道了我们的数据/环境和目标值,时间差异是什么。

-----------------------
| state | probability |
-----------------------
| a | 0.0 | 
| b | 0.167 |
| c | 0.333 |
| d | 0.50 |
| e | 0.667 |
| f | 0.833 |
| g | 1.0 |
-----------------------

简单介绍

所以为了讨论这些算法,我将尝试用一种简单的方式来解释它们。请随意参考大卫·西尔弗讲座或萨顿和巴尔托的书,以获得更多的深度。时间差异是一个主体在事先没有环境知识的情况下通过片段从环境中学习。这意味着时间差异采用无模型或无监督的学习方法。你可以把它看作是从尝试和错误中学习。

让我们学习希腊语

你会在这篇文章中注意到一些符号,我们将讨论 3 种算法:TD(0),TD(1)和 TD( λ )。我将展示每一个方程,我们将解释它们,但让我们快速定义至少一些超参数的符号(希腊字母有时令人生畏)。

  1. Gamma (γ): 贴现率。介于 0 和 1 之间的值。价值越高,折扣越少。
  2. λ(λ):信用分配变量。介于 0 和 1 之间的值。值越高,您可以分配给更后面的状态和操作的信用就越多。
  3. Alpha (α): 学习率。我们应该接受多大的误差,从而调整我们的估计。介于 0 和 1 之间的值。较高的值调整积极,接受更多的误差,而较小的值调整保守,但可能更保守地向实际值移动。
  4. 增量(δ): 数值的变化或差异。

所以我们开始的第一个算法是 TD(1)。在一集结束时,TD(1)以与蒙特卡罗相同的方式更新我们的值。所以回到我们的随机行走,随机向左或向右,直到在“A”或“G”着陆。一旦情节结束,则对先前的状态进行更新。正如我们上面提到的,如果λ值越高,信用就可以分配得越多,在这种情况下,λ等于 1 就是极限。这是一个重要的区别,因为 TD(1)和 MC 只在偶发环境中工作,这意味着它们需要一个“终点线”来进行更新。

现在让我们看看算法,试着理解一下。Gt(图 2)是我们这一集看到的所有奖励的贴现总和。因此,当我们在我们的环境中旅行时,我们跟踪所有的奖励,并以折扣(γ)将它们加在一起。所以让我们表现得好像我们在大声朗读这个:在给定的时间点(时间,t+1)的即时回报(R)加上未来回报(Rt+2)的折扣(γ)等等。你可以看到,我们在未来对γ^T-1.的折现(γ)更大因此,如果γ=0.2,你在第 6 步贴现回报,你的贴现值γ变成γ⁶–1,等于 0.00032。仅 6 个时间步长后明显变小。

Figure 2: Sum of Discounted Rewards

现在,我们将对我们的价值评估 V(S)进行更新。重要的是要知道,当你开始时,你真的没有一个好的开始估计。你用随机值或全零初始化,然后对估计值进行更新。对于我们的随机游走序列,我们将‘B’和‘F’之间所有状态的值初始化为零[0,0,0,0,0,0,1]。我们不考虑终端状态,因为它们是已知的。记住我们只是试图预测非终态的值,因为我们知道终态的值。

我们将使用我们在本集看到的上述 Gt 的折扣奖励总和,并从先前的估计中减去它。这被称为 TD 误差。我们的最新估计减去先前的估计。然后,我们乘以α项,以调整我们希望更新误差量。最后,我们只需将之前的估计值 V(St)与调整后的 TD 误差相加,即可完成更新(图 3)。

Figure 3: TD(1) Update Value toward Action Return

所以这是第一集。我们做了 1 次随机行走,积累了奖励。然后,我们在每一个时间步取这些奖励,并将其与我们最初的估计值(全部为零)进行比较。我们权衡差异并调整我们先前的估计。然后重新开始。你刚学了 TD(1)或者 MC 更新!

既然我们已经解释了 TD(1),那么 TD(0)就更容易理解了。让我们看看图 3 的括号内,因为这是唯一的区别。我们不使用折扣奖励的累积和(Gt)我们只看即时奖励(Rt+1),加上仅领先 (V(St+1))一步的的估计值的折扣(图 4)。

Figure 4: TD(0) Update Value toward Estimated Return

这是 TD(0)和 TD(1)更新之间的唯一区别。请注意,我们刚刚将图 3 中的 Gt 替换为提前一步的估计。

当我们使用估计来更新估计时,我们称之为自举。这种类型的技术比 TD(1)或 MC 有更高的偏差,因为你是从估计值中进行估计,而不是从观看整个剧集中进行估计。然而,这往往具有较低的方差。TD(0)的另一个好处是,它可以学习没有终端状态的环境,而 TD(1)则不能。

假设我们想要在一集结束之前进行值更新(TD(1))并且使用多于 1 步的超前(TD(0))来进行我们的估计。这就是 TD(λ)发挥作用的地方。要知道 TD(λ)有两种实现:前视和后视。前瞻视图查看前面的所有 n 步,并使用λ从本质上衰减那些未来的估计。在这篇文章中,我们将继续使用 TD(λ)的后向视图,但是已经证明前向视图和后向视图是等价的,Sutton 表明如果感兴趣的话,这里的就是

TD(λ)的后向视图在每一步更新值。所以在每集的每一步之后,你都要更新之前的所有步骤。问题是你如何恰当地权衡或分配前面所有步骤的功劳?答案是使用一种叫做资格追踪(ET)的东西。ET 基本上记录了进入给定状态的频率和最近次数(图 4)。它将信用分配给相对于我们的最终状态频繁访问和最近访问的状态。lambda (λ)和 gamma (γ)项用于贴现这些轨迹。

Figure 4: Eligibility Traces

如果你直觉地思考这个问题,我们知道状态‘F’将会被频繁地访问,并且在最近结束于我们的最终状态‘G ’,因此将会收到许多更新。因此,ET 将根据 TD 误差(图 5,αδtEt(s))的比例向状态“F”分配更多信用。然而,相对于终止于状态‘G’而言,状态‘B’不会被频繁地访问,因此该状态的值不会被频繁地更新,并且将保持接近于其初始化时的 0。从这里开始,我们不断更新我们先前的估计。

Figure 5: Update with Respect to TD Error (δt) and Eligibility (Et(s))

所以我希望这是一种简单的学习方式。它的要点是我们做一个初始估计,探索一个空间,并根据我们的探索努力更新我们先前的估计。强化学习的困难部分似乎是在哪里应用它,环境是什么,我如何正确地设置我的奖励,等等,但至少现在你理解了状态空间的探索和用无监督的无模型方法进行估计。

1.理查德·萨顿《学习用时间差异的方法预测》机器学习,第 3 卷第 1 期,1988 年,第 9–44 页。,doi:10.1007/bf00115009。

2.西尔弗,大卫,导演。大卫·西尔弗的 RL 课程——第四讲:无模型预测YouTube ,YouTube,2015 年 5 月 13 日,www.youtube.com/watch?v=PnHCvfgC_ZA.

3.RL 创始人理查德·萨顿的免费下载,强化学习:简介

4.这允许你编写 LaTex 并保存为图像。可能有更好的,但这是我用的。在线乳胶编辑

原载于 2018 年 10 月 29 日【medium.com

用 Python 中的 ML 进行简单的股票价格预测——ML 学习指南

原文:https://towardsdatascience.com/simple-stock-price-prediction-with-ml-in-python-learners-guide-to-ml-76896910e2ba?source=collection_archive---------2-----------------------

介绍

机器学习的一个最突出的用例是“金融科技”(为那些不是时髦词汇爱好者的人准备的金融科技);其中很大一部分在股票市场。在过去 50 年的大部分时间里,金融理论家和数据科学家被用来理解市场,以增加投资回报。然而,由于问题的多维性质、系统的规模以及随时间的内在变化,即使有传统数据分析工具的帮助,人类也难以解决这个问题。然而,随着机器学习应用中最近进步的开始,该领域已经发展到利用非确定性解决方案“学习”正在发生的事情,以便进行更准确的预测。

在本文中,我将演示一个简单的股票价格预测模型,并探索“调整”该模型如何影响结果。这篇文章旨在易于理解,因为它是一个介绍,所以更高级的读者可能需要忍受我。

第一步:选择数据

机器学习和预测建模中最重要的步骤之一是收集好的数据,执行适当的清理步骤并认识到局限性。

在这个例子中,我将使用一只股票 Zimmer Biomet(股票代码:ZBH)的股价数据。只需前往 finance.yahoo.com,搜索所需的股票。一旦你进入所需股票的主页,只需导航到“历史数据”标签,输入你想包含的日期范围,然后选择“下载数据”我选择了 5 年,但是你可以选择你想要的时间。

现在我们有了数据,让我们继续看看我们有什么。只需在 Excel 中打开文件。

看起来我们这里有些好东西。您可能会注意到所有的字段都是数值,除了那个讨厌的日期值…我们需要解决这个问题。我们要传递到模型中的值需要采用最容易理解的格式。因此,我们需要执行一些“数据预处理”步骤。在我们的例子中,我们将在 1 后面插入一个新列,命名为“日期值”,并将第 1 列中的所有日期复制到第 2 列中。然后选择所有数据,并将类型从“日期”更改为“文本”结果应该如下所示:

好了,现在把文件保存为“choose_a_name.csv”(确保是 a)。csv”而不是 excel 默认格式之一)。

在我们开始之前,让我们谈谈限制。您会注意到,我们提供给这个模型的唯一数据是日期和价格。在历史价格之外,还有许多外部因素影响价格。高度稳健的模型可能利用外部数据,如新闻、一年中的时间、社交媒体情绪、天气、竞争对手的价格、市场波动、市场指数等。这是一个非常基础的模型,但是随着时间的推移,你可以学习建立一个对整个市场更加“了解”的模型的技巧。话虽如此,我们继续吧。

第二步:选择模型

现在我们已经清理了数据,我们需要选择一个模型。在这种情况下,我们将使用神经网络来执行回归函数。回归将在一个连续的尺度上产生一个数值,与可用于分类工作的模型相反,这将产生一个分类输出。在这种情况下,我们试图预测股票在任何一天的价格(如果你试图赚钱,这一天还没有发生)。

为了建立我们的模型,我们将使用 TensorFlow…嗯,一个叫做 TFANN 的简化模块,代表“TensorFlow 人工神经网络”为了做到这一点,我们将使用 Google Colab。如果你不熟悉 Colab,只需导航到 colab.research.google.com,这是一个免费的虚拟 python 笔记本环境。(对于那些将要跟进但不知道自己在做什么的人,只需将下面的代码复制粘贴到一个“单元格”中,然后在创建新的单元格并复制更多代码之前点击 run)。

步骤 3:构建模型

首先我们需要安装 TFANN。打开一个新的 Colab 笔记本(python 3)。Colab 有许多无需安装即可访问的库;但是,TFANN 不在其中,因此我们需要执行以下命令:

!pip install TFANN

现在让我们导入我们的依赖项:

import numpy as np
import matplotlib.pyplot as mpl
from sklearn.preprocessing import scale
from TFANN import ANNR
from google.colab import files

NumPy 将用于我们的矩阵运算,Matplotlib 用于图形,sykit-learn 用于数据处理,TFANN 用于 ML goodness,google.colab 文件将帮助我们将数据从本地机器上传到虚拟环境。

现在我们需要导入已经处理过的数据。为此,我们将执行以下命令,这将为我们提供一个窗口来上传。csv 文件。

files.upload()

很简单,对吧?

您现在有一个包含该文件的虚拟文件夹。如果你不相信我,执行下面的命令,它将打印当前目录下的文件名。

!ls

现在我们终于可以进入这个项目的核心部分了。执行以下命令:

#reads data from the file and ceates a matrix with only the dates and the prices 
stock_data = np.loadtxt('ZBH_5y.csv', delimiter=",", skiprows=1, usecols=(1, 4))
#scales the data to smaller values
stock_data=scale(stock_data)
#gets the price and dates from the matrix
prices = stock_data[:, 1].reshape(-1, 1)
dates = stock_data[:, 0].reshape(-1, 1)
#creates a plot of the data and then displays it
mpl.plot(dates[:, 0], prices[:, 0])
mpl.show()

您应该会得到一个漂亮的图形,如下所示:

请注意,y 轴上的刻度不再是美元,x 轴上的刻度不再是任意的整数日期值。我们缩小了数据规模,以使学习过程更加有效。尝试编写一些代码,将 y 轴的刻度返回到美元,将 x 轴的刻度返回到年!

现在,我们需要构建模型。在这种情况下,我们将使用一个输入和输出神经元(输入日期,输出价格),并将有三个隐藏层,每层 25 个神经元。每一层都有一个“tanh”激活功能。如果你不理解这些概念,请随时谷歌一下,然后回来,理解神经网络原理的基础知识将对你的进步非常有帮助。

#Number of neurons in the input, output, and hidden layers
input = 1
output = 1
hidden = 50
#array of layers, 3 hidden and 1 output, along with the tanh activation function 
layers = [('F', hidden), ('AF', 'tanh'), ('F', hidden), ('AF', 'tanh'), ('F', hidden), ('AF', 'tanh'), ('F', output)]
#construct the model and dictate params
mlpr = ANNR([input], layers, batchSize = 256, maxIter = 20000, tol = 0.2, reg = 1e-4, verbose = True)

我们现在已经初始化了模型,并准备好训练!

步骤 4:训练模型

#number of days for the hold-out period used to access progress
holdDays = 5
totalDays = len(dates)
#fit the model to the data "Learning"
mlpr.fit(dates[0:(totalDays-holdDays)], prices[0:(totalDays-holdDays)])

一旦训练完成,我们可以执行以下命令来看看我们做得如何。

#Predict the stock price using the model
pricePredict = mlpr.predict(dates)
#Display the predicted reuslts agains the actual data
mpl.plot(dates, prices)
mpl.plot(dates, pricePredict, c='#5aa9ab')
mpl.show()

不算太差!但是我们可以做得更好。

让我们考虑一些可以增加模型逼真度的方法。我们可以把这个想成“我们可以转动什么旋钮”来调整我们的模型。首先是简单地降低误差容限。

第一次试验,误差容限设定为. 2;然而,我们可以把它降低到一个更小的数字,比如说 0.1,让我们试一试!

只需进行以下更改。请注意,我还更新了变量的名称,以便我们已经创建/观察的值不会改变。当然这不是最有效的方法,但我相信你可以创造一个更好的方法!

#Number of neurons in the input, output, and hidden layers
input2 = 1
output2 = 1
hidden2 = 50
#array of layers, 3 hidden and 1 output, along with the tanh activation function 
layers = [('F', hidden2), ('AF', 'tanh'), ('F', hidden2), ('AF', 'tanh'), ('F', hidden2), ('AF', 'tanh'), ('F', output2)]
#construct the model and dictate params
mlpr2 = ANNR([input2], layers, batchSize = 256, maxIter = 10000, tol = 0.1, reg = 1e-4, verbose = True)

使用以下命令再次运行该模型,我们会得到新的结果:

holdDays = 5
totalDays = len(dates)
mlpr2.fit(dates[0:(totalDays-holdDays)], prices[0:(totalDays-holdDays)])

一旦它完成训练:

pricePredict2 = mlpr2.predict(dates)
mpl.plot(dates, prices)
mpl.plot(dates, pricePredict, c='#5aa9ab')
mpl.plot(dates, pricePredict2, c='#8B008B')
mpl.show()

更好看!如你所见,喜欢容错…嗯…降低了误差。所以你可能想知道“为什么不把误差设置成一个非常小的数字呢?”这将是一个很好的问题。继续自己尝试,重新执行刚才运行的代码,将公差设置为 0.05。您将观察到的是,您使用的最大迭代次数将在执行达到所需的错误级别之前停止执行。那么,为什么不增加最大迭代次数呢?嗯,问题出在给定的模型参数上。模型本身有局限性,我们构建的模型的最低可实现误差可能只有 0.8(我还没有为这个模型检查过这一点)。在这种情况下,添加多少次迭代都没有关系,无论运行多少次迭代,模型的结构都不会产生更好的结果。它只是被封顶了。

这里要问的下一个逻辑问题是“我们如何改变模型以达到更大的误差?”这就是我们将要探索的!

模型有所谓的“超参数”这些是管理模型的参数,它们定义了如何创建模型。改变这些可以给我们更好(或者更差)的结果。示例包括:每个隐藏层中的神经元数量、隐藏层的数量、激活函数等。

我们的目标是“调整”这些超参数,以实现比我们的第一个模型更低的误差容限。在我看来,最简单的方法就是增加隐藏层中神经元的数量。我绝不是这个主题的主要知识来源,但我敢说,增加神经元的数量和/或隐藏层的数量可以提高模型表示给定数据的抽象级别。所以让我们试试吧!

将每个隐藏层中的神经元数量从 50 增加到 100,并将容差设置为 0.075:

好多好多!橙色线是最新的预测。请注意,它比上一个模型更好地跟踪了最近的价格。

我认为我们创造了一个很好的模式,我对结果很满意!但是这个项目可以继续学习更多关于超参数的知识。尝试改变激活功能,除了“tanh”,或者增加一个额外的层。

要添加另一层,请参考这行代码:

layers = [('F', hidden), ('AF', 'tanh'), ('F', hidden), ('AF', 'tanh'), ('F', hidden), ('AF', 'tanh'), ('F', output)]

通过在输出节点前添加另一个层(“AF”,隐藏)、(“AF”,“tanh”)来添加一个附加层。这将在层被馈送到下一层之前添加该层和应用于该层的激活函数。

layers = [('F', hidden), ('AF', 'tanh'), ('F', hidden), ('AF', 'tanh'), ('F', hidden), ('AF', 'tanh'),('F', hidden), ('AF', 'tanh'), ('F', output)]

或者,也许你想在每一个隐藏层有不同数量的神经元,减少它们是一种常见的方法。以下示例在输出之前从 100 个节点逐渐减少到 25 个节点:

layers = [('F', 100), ('AF', 'tanh'), ('F', 50), ('AF', 'tanh'), ('F', 25), ('AF', 'tanh'), ('F', output)]

所以,你有它!一个关于机器学习和神经网络的简单介绍,你可以在家里用大约一个小时免费完成!

我要感谢 Nicholas T. Smith,他的模型影响了这篇文章的创作。

最后,如果您有任何问题、意见、建议或顾虑,请随时联系我们!

用 R 中的例子简单解释了逻辑回归

原文:https://towardsdatascience.com/simply-explained-logistic-regression-with-example-in-r-b919acb1d6b3?source=collection_archive---------0-----------------------

我假设读者熟悉线性回归模型及其功能。在这里,我试图用尽可能简单的解释来解释逻辑回归。当我自己试图理解逻辑回归时,我没有得到任何全面的答案,但是在对这个话题做了彻底的研究后,我想到了这篇文章。请注意,这更多的是一篇介绍性文章,要深入这个主题,您必须了解数据分析及其实现的许多不同方面。

话虽如此,我们还是开始吧。我们知道,线性模型假设响应变量是正态分布的。我们有形式为 Yi = β0 + β1X+ εi,的方程,其中我们预测 X 的某个值的 Y 值。我们知道这是线性的,因为对于 X 的每个单位变化,它将在一定程度上影响 Y 值 β1。此外,误差项 εi 是假设正态分布,如果误差项添加到 Y 的每个输出,则 Y 也正态分布,这意味着对于 X 的每个值,我们得到 Y,并且 Y 对该正态分布有贡献。现在,当 Y 的值可以是-∞到+ ∞时,这都是好的,但是如果值需要为真或假,0 或 1,是或否,那么我们的变量不遵循正态分布模式。我们所有的是 0 和 1 的计数,它只对发现概率有用,例如,如果你有五个 0 和十五个 1,那么得到 0 的概率是 0.25,得到 1 的概率是 0.75。但是我们如何用这个概率来做一个平滑的分布,拟合一条线(非线性的)尽可能接近你所拥有的所有的点,假设那些点不是 0 就是 1。

要做到这一点,你必须想象概率只能在 0 和 1 之间,当你试图用一条线来拟合这些点时,它不可能是一条直线,而是一条 S 形曲线。

Linear vs Logistic

如果你有更多的 1,那么 S 将向上倾斜,如果你有更多的 0,那么它将向下倾斜。请注意,Y 轴上的数字 0 表示总计数的一半在左边,总计数的一半在右边,但情况并不总是如此。

现在问题来了,我们如何将 1 和 0 的二进制信息映射到使用连续变量的回归模型?我们做这种映射的原因是因为我们希望我们的模型能够发现预期结果为真的概率。下面我将描述我们是如何进行映射的。请记住,逻辑回归的主要前提仍然是基于一个典型的回归模型,有一些方法上的变化。

现在,要找到预期结果的概率,我们必须始终遵循两件事。

1-概率不能为负,所以我们在我们的正态回归模型中引入一个称为指数的项,使其成为逻辑回归。

2-由于概率永远不会大于 1,我们需要将结果除以比它本身更大的数。

基于这两点,我们的逻辑回归公式展开如下:

1.回归公式使用公式 Yi = β0 + β1X+ εi. 给出 Y

2.我们必须使用指数,这样它就不会变成负数,因此我们得到 P = exp( β0 + β1X+ εi )。

3.我们将 P 除以比它本身大的数,使它保持小于 1,因此我们得到 P = e(β0+β1X+εI)/e(β0+β1X+εI)+1。

4.经过一些计算后,第三步中的公式可以改写为 log(p/(1-p))=β0+β1X+εI .

5.log(p / (1-p))称为概率的赔率。如果你仔细观察,它是预期结果为真的概率除以预期结果不为真的概率,这叫做 logit 函数。

工作:

当您计算 1 和 0 的总数时,您可以很容易地计算 log(p / (1-p))的值,我们知道该值等于β0+β1X+εI。现在您可以将该值放入公式 P = e(β0+β1X+εI)/e(β0+β1X+εI)+1 和

从另一个角度来看,假设您已经有了截距和斜率的回归公式,您只需要输入 X 的值来预测 y。但您知道在逻辑回归中它不是这样工作的,这就是为什么您将 X 值放在这个公式 P = e(β0+β1X+εI)/e(β0+β1X+εI)+1 中,并将结果映射到 X-上如果该值高于 0.5,则您知道它接近于期望的结果(即 1),如果该值低于 0.5,则您知道它接近于不期望的结果(即 0)。

稍微涉及一下指数的功能

假设你在某个地方投资了一美元。现在,一年内它将增长其先前价值的 50%,所以在 2018 年,如果它是 1 美元,那么在 2019 年它将变成 1.5 美元,在 2020 年它将变成 2.25 美元。为什么是 2.25?因为 1 美元产生了 0.5 美元,这 0.5 美元开始赚取自己的利息,也就是 0.25 美元,随着时间的推移,每个新芽不断赚取自己的利息,这就是为什么我们有上面显示的 S 形曲线。

R 中的示例

需要记住的事情,

1-线性回归方法试图最小化残差,这意味着最小化((MX+c)-y)的值。而逻辑回归模型则试图在考虑了手头的所有变量后,尽可能准确地预测结果。

2-它计算数据集中每个点的概率,该点可以是 0 或 1,并将其提供给 logit 函数。

3-使用逻辑回归后得到的系数告诉我们特定变量对对数概率的贡献有多大。

数据来源于加州大学洛杉矶分校,它有 4 个变量,称为录取,GRE 分数,GPA 和他们的本科学校排名。我们的目标是建立一个模型,以便在给定学生简介的情况下,预测该学生被录取的概率。

df <- read.csv(“https://stats.idre.ucla.edu/stat/data/binary.csv")
 str(df)
 ## ‘data.frame’: 400 obs. of 4 variables:
 ## $ admit: int 0 1 1 1 0 1 1 0 1 0 …
 ## $ gre : int 380 660 800 640 520 760 560 400 540 700 …
 ## $ gpa : num 3.61 3.67 4 3.19 2.93 3 2.98 3.08 3.39 3.92 …
 ## $ rank : int 3 3 1 4 4 2 1 2 3 2 …

我们看到变量不是整数就是数字。

sum(is.na(df))## [1] 0

没有空值

summary(df)##      admit             gre             gpa             rank      
 ##  Min.   :0.0000   Min.   :220.0   Min.   :2.260   Min.   :1.000  
 ##  1st Qu.:0.0000   1st Qu.:520.0   1st Qu.:3.130   1st Qu.:2.000  
 ##  Median :0.0000   Median :580.0   Median :3.395   Median :2.000  
 ##  Mean   :0.3175   Mean   :587.7   Mean   :3.390   Mean   :2.485  
 ##  3rd Qu.:1.0000   3rd Qu.:660.0   3rd Qu.:3.670   3rd Qu.:3.000  
 ##  Max.   :1.0000   Max.   :800.0   Max.   :4.000   Max.   :4.000

我们可以注意到,由于变量 admit 的平均值小于“0.5”,所以拒绝的数量大于接受的数量。

xtabs(~ admit +rank ,data=df) ##         rank
 ## admit  1  2  3  4
 ##     0 28 97 93 55
 ##     1 33 54 28 12

我们这样做是为了检查录取是否在每个等级类别中分布得足够好。如果假设一个等级只有 5 个接纳或拒绝信息,那么就没有必要在分析中包括该等级。

现在,我们运行我们的 logit 函数,但在此之前,我们还必须将秩变量从整数转换为因子。

df$rank <- as.factor(df$rank)

 logit <- glm(admit ~ gre+gpa+rank,data=df,family="binomial")

 summary(logit)## 
 ## Call:
 ## glm(formula = admit ~ gre + gpa + rank, family = "binomial", 
 ##     data = df)
 ## 
 ## Deviance Residuals: 
 ##     Min       1Q   Median       3Q      Max  
 ## -1.6268  -0.8662  -0.6388   1.1490   2.0790  
 ## 
 ## Coefficients:
 ##              Estimate Std. Error z value Pr(>|z|)    
 ## (Intercept) -3.989979   1.139951  -3.500 0.000465 ***
 ## gre          0.002264   0.001094   2.070 0.038465 *  
 ## gpa          0.804038   0.331819   2.423 0.015388 *  
 ## rank2       -0.675443   0.316490  -2.134 0.032829 *  
 ## rank3       -1.340204   0.345306  -3.881 0.000104 ***
 ## rank4       -1.551464   0.417832  -3.713 0.000205 ***
 ## ---
 ## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
 ## 
 ## (Dispersion parameter for binomial family taken to be 1)
 ## 
 ##     Null deviance: 499.98  on 399  degrees of freedom
 ## Residual deviance: 458.52  on 394  degrees of freedom
 ## AIC: 470.52
 ## 
 ## Number of Fisher Scoring iterations: 4

简要解释

gre 中每一个单位的变化都会使被录取的对数几率增加 0.002,其 p 值表明它在决定录取方面有一定的意义。

2-平均绩点每增加一个单位,录取几率的对数就增加 0.80,p 值表明它在决定录取方面有一定的意义。

3-排名的解释与其他人不同,从排名第一的大学去排名第二的大学会将被录取的几率降低-0.67。从等级 2 到等级 3 将减少-1.340。

零偏差和剩余偏差之间的差异告诉我们,该模型是一个很好的拟合。差异越大,模型越好。零偏差是当方程中只有截距而没有变量时的值,剩余偏差是当考虑所有变量时的值。如果差异足够大,那么认为模型是好的是有道理的。

预言;预测;预告

假设一个学生的 GRE 成绩为 790 分,GPA 为 3.8,他就读于一所排名第一的大学。现在你想预测那个男孩将来被录取的机会。

x <- data.frame(gre=790,gpa=3.8,rank=as.factor(1))
 p<- predict(logit,x)
 p##       1 
 ## 0.85426

我们看到这个人有 85%的机会被录取。

参考文献

匿名。“Logit 回归| R 数据分析示例”。数字研究与教育研究院。【https://stats.idre.ucla.edu/r/dae/logit-regression/

匿名。“逻辑回归解释了”。学习营销。http://www . learn by marketing . com/methods/logistic-regression-explained/

计数模型:理解对数链接功能。theanalysisfactor.com。https://www . the analysis factor . com/count-models-understanding-the-log-link-function/

匿名。《指数函数直观指南& e》。BETTEREXPLAINED.COM。https://better explained . com/articles/an-intuitive-guide-to-index-functions-e/

匿名。“视频 7:逻辑回归——简介”。数据挖掘。https://www.youtube.com/watch?v=gNhogKJ_q7U

Aggarwal,a .逻辑回归。简体”。IITR 数据科学集团。https://medium . com/data-science-group-iitr/logistic-regression-simplified-9 B4 EFE 801389

匿名 YES NO GAME(青年组比赛)。年轻的天主教徒。https://young-天主教徒网/2017/12/30/yes-no-game-youth-group-game/

辛普森悖论与数据解释

原文:https://towardsdatascience.com/simpsons-paradox-and-interpreting-data-6a0443516765?source=collection_archive---------0-----------------------

通过数据找到正确视图的挑战

统计学家、布莱奇利公园的前密码分析师爱德华·休·辛普森在 1951 年的一篇技术论文中描述了以他的名字命名的统计现象。辛普森悖论突出了我最喜欢的关于数据的事情之一:对真实世界的良好直觉的需要,以及大多数数据是一个更大、更复杂的领域的有限维表示。数据科学的艺术是透过数据来看,使用和开发方法和工具来了解隐藏的现实。辛普森悖论展示了怀疑和解释现实世界数据的重要性,以及试图从单一数据角度看整个故事而将更复杂的事实过于简化的危险。

这个悖论相对来说很简单,对于没有受过统计训练的观众来说,它常常是一个混淆和误导的原因:

辛普生悖论: 将数据分组时出现的一种趋势或结果,当数据合并时,这种趋势或结果会逆转或消失。

辛普森悖论最著名的例子之一是加州大学伯克利分校的性别偏见。1973 学年开始时,加州大学伯克利分校的研究生院录取了大约 44%的男性申请人和 35%的女性申请人。故事通常是这样的,学校因性别歧视被起诉,尽管这实际上不是真的。然而,学校确实害怕诉讼,所以他们让统计学家彼得·比克尔查看了这些数据。他的发现令人惊讶:在 6 个部门中,有 4 个部门在统计上有明显的性别偏见,偏向女性,而在其余 2 个部门没有明显的性别偏见。比克尔的团队发现,女性倾向于申请总体录取比例较小的部门,这一隐藏变量影响了被录取申请人比例的边际值,从而逆转了数据整体中存在的趋势。从本质上讲,当比克尔的团队改变他们的数据观点来解释学校被分成几个系时,结论发生了逆转!

A visual example: the overall trend reverses when data is grouped by some colour-represented category.

辛普森悖论会让决策变得困难。我们可以尽可能地对我们的数据进行审查、重组和重新采样,但是如果从所有不同的分类中可以得出多个不同的结论,那么选择一个分组来得出我们的结论,以便获得洞察力和制定策略,这是一个微妙而困难的问题。我们需要知道我们在寻找什么,并选择最好的数据观点来公平地呈现事实。让我们考虑一个简单的商业例子。

草莓 vs 桃子

假设我们在软饮料行业,我们试图在我们生产的两种新口味中进行选择。我们可以对这两种口味的公众意见进行抽样调查——假设我们选择这样做,在一个繁忙的地区为每种口味设立两个抽样摊位,并在每个摊位询问 1000 人是否喜欢这种新口味。

我们可以看到,80%的人喜欢“罪恶的草莓”,而只有 75%的人喜欢“热情的桃子”。所以“罪恶的草莓”更有可能是更受欢迎的口味。

现在,假设我们的营销团队在进行调查时收集了一些其他信息,例如品尝饮料的人的性别。如果我们按性别划分数据会发生什么?

这表明 84.4%的男性和 40%的女性喜欢“罪恶的草莓”,而 85.7%的男性和 50%的女性喜欢“热情的桃子”。如果我们停下来想一想,这似乎有点奇怪:根据我们的样本数据,一般来说,人们更喜欢“罪恶的草莓”,但男性和女性分别喜欢“热情的桃子”。这就是辛普森悖论的一个例子!我们的直觉告诉我们,当一个人的性别未知时,无论是男性还是女性都喜欢的味道也应该是他们喜欢的,但奇怪的是,发现这不是真的——这是悖论的核心。

潜伏的变数

当存在将数据分割成多个独立分布的隐藏变量时,就会出现辛普森悖论。这样一个隐藏变量被恰当地称为潜伏变量,它们通常很难识别。幸运的是,在我们的软饮料例子中,情况并非如此,我们的营销团队应该很快就能发现品尝新口味的人的性别正在影响他们的看法。

解释这一悖论的一种方法是考虑潜在变量(性别)和一点概率论:

P(喜欢草莓)= P(喜欢草莓|男人)P(男人)+ P(喜欢草莓|女人)P(女人)

800/1000 = (760/900)×(900/1000) + (40/100)×(100/1000)

P(喜欢桃子)= P(喜欢桃子|男人)P(男人)+ P(喜欢桃子|女人)P(女人)

750/1000 = (600/700)×(700/1000) + (150/300)×(300/1000)

我们可以把性别的边际概率(P(男人)和 P(女人))看作是权重,在“罪恶的草莓”的情况下,导致总概率明显偏向男性观点。虽然在我们的“热情的桃子”样本中仍然存在隐藏的男性偏见,但它并不那么强烈,因此女性意见的更大比例被考虑在内。这导致一般人群偏好这种风味的边际概率较低,尽管当在样本内分开时,每种性别更可能偏好这种风味。

对正在发生的事情的想象:

Each coloured circle represents either the men or women that sampled each flavour, the position of the centre of each circle corresponds to that group’s probability of liking the flavour. Notice that both groups lie further to the right (have higher probability) for liking Peach. As the circles grow (i.e. sample proportions change) we can see how the marginal probability of liking the flavour changes. The marginal distributions shift and switch as samples become weighted with respect to the lurking variable (sex).

在这个例子中,我们的发现是非常不确定的,因为根据我们的营销团队想要实现的目标,选择任何一种数据观点都是有权衡的。考虑分组并意识到我们的发现是不确定的,这比得出一个不确定的结论对我们的业务更有用,报告这一点是正确的,这样我们就可以回到绘图板,重新取样并计划一项更深入的研究,以产生真正的洞察力。

我们参考哪些数据?

在一些实验中,我们的样品的加权可能是由于我们的取样方法中的一些误差。事实上,我们上面构建的软饮料示例在生成随机样本方面存在固有缺陷。知道我们看到的是糟糕的采样数据,还是真实的悖论,这一点绝对重要。然而,如果我们实际上尽了最大努力来生成一个独立和无偏见的样本,但最终仍然处于类似的情况下,会怎么样呢?从一个有产品的企业的角度来看:不管我们的抽样方法如何,我们的产品对某些人口统计数据更有吸引力,这将反映在我们的数据中,并可能表现为一个潜在的变量。在前面提到的加州大学伯克利分校的研究中,女性更有可能选择的部门就是这种情况。

If only choosing the right data-viewpoint were so easy.

有了直觉,就有可能通过探索性的数据分析发现潜伏的变量。然后,我们必须决定是将数据分成单独的分布,还是将数据组合在一起。正确的决定完全取决于具体情况,这也是为什么数据科学存在于数学/统计学、计算机科学和商业/领域知识的交叉点的部分原因:我们需要了解我们的数据,更重要的是,我们想要从我们的数据中得到什么,以便选择采取哪种方法。在我们的软饮料商业例子中,我们决定报告我们的发现是不确定的,尽管顾客最初似乎更喜欢“罪恶的草莓”味道。在加州大学伯克利分校的研究中,按系划分和解释数据是合乎逻辑的,因为没有系外的入学竞争。如果我们想知道医院的存活率;我们也许应该把数据分开,看看带着不同疾病来到医院的分类人群。这将有助于我们做出明智的决定,哪家医院最适合特定的病人,这可能是我们最关心的问题。在每种情况下,关键是解释与底层领域相关的数据,并采取最合适的数据观点。

这是一个总结——感谢阅读!

如果你喜欢这篇关于辛普森悖论和通过数据观点解读数据的文章,请随时联系我( 汤姆·格里格 )了解任何想法或疑问!

辛普森悖论:如何用相同的数据证明相反的论点

原文:https://towardsdatascience.com/simpsons-paradox-how-to-prove-two-opposite-arguments-using-one-dataset-1c9c917f5ff9?source=collection_archive---------3-----------------------

(Source)

理解一个统计现象和问为什么的重要性

想象一下,你和你的搭档正在寻找一家完美的餐厅享用一顿愉快的晚餐。知道这个过程可能会导致数小时的争论,你开始寻找现代生活的神谕:在线评论。这样,你就找到了你的选择,与你的搭档选择的索菲娅餐厅相比,推荐卡洛餐厅的男女比例更高。然而,就在你即将宣布胜利的时候,你的搭档用同样的数据得意洋洋地说,既然索菲亚的被更高比例的所有用户推荐,它就是明显的赢家。

这是怎么回事?谁躺在这里?点评网站是不是算错了?事实上,你和你的伴侣都是对的,你已经不知不觉地进入了辛普森悖论的世界,在那里,一家餐馆可能比它的竞争对手更好也可能更差,锻炼可以降低和增加疾病的风险,同样的数据集可以用来证明两个相反的论点。与其出去吃饭,也许你和你的伴侣应该花一个晚上来讨论这个迷人的统计现象。

当数据集被分组时出现的趋势在数据被聚合时逆转时,就会出现辛普森悖论。在餐馆推荐的例子中,确实有可能卡洛的比索菲亚的被更高比例的男女推荐,但是被更低比例的 所有评论者 推荐。在你宣布这是精神错乱之前,这里有一张表可以证明这一点。

Carlo’s wins among both men and women but loses overall!

数据清楚地表明,当数据分离时,卡洛的是首选,但当数据合并时,索菲亚的是首选!

这怎么可能呢?这里的问题是,只看单独数据中的百分比忽略了样本大小,即回答问题的受访者人数。每个分数显示了在被问及的用户中会推荐这家餐馆的用户数量。卡洛的回答来自男性,远多于女性,而索菲亚的回答则相反。由于男性倾向于以较低的比率认可餐馆,当数据被合并时,这导致了对卡洛餐馆的较低的平均评级,因此这是一个悖论。

要回答我们应该去哪家餐馆的问题,我们需要决定数据是否可以合并,或者我们是否应该单独查看。我们是否应该汇总数据取决于生成数据的过程——也就是数据的因果模型。在看到另一个例子后,我们将讨论这意味着什么以及如何解决辛普森悖论。

相关反转

辛普森悖论的另一个有趣的版本出现了,当在分层的群体中指向一个方向的相关性在对总体进行聚合时变成了在相反方向的相关性。让我们看一个简化的例子。假设我们有两组患者每周锻炼小时数与患病风险的数据,一组是 50 岁以下的患者,另一组是 50 岁以上的患者。这是显示锻炼和患病概率之间关系的单个图表。**

Plots of probability of disease versus hours of weekly exercise stratified by age.

(示例可在本 Jupyter 笔记本中重现)。

我们清楚地看到负相关,表明每周运动量的增加与两组人群患该疾病的风险降低相关。现在,让我们将数据结合到一个单独的图上:

Combined plot of probability of disease versus exercise.

这种关联已经完全 颠倒了 如果只显示这个数字,我们会得出结论,锻炼会增加患病的风险,这与我们从单个图表中得出的结论相反。运动如何既能降低又能增加患病风险?答案是否定的,要想解决这个悖论,我们需要超越我们看到的数据,并通过数据生成过程进行推理——是什么导致了这些结果。

解决悖论

为了避免辛普森悖论导致我们得出两个相反的结论,我们需要选择将数据分组或汇总在一起。这看起来很简单,但是我们如何决定做哪一个呢?答案是想因果:数据是如何产生的,基于此,哪些因素影响了我们 没有显示 的结果?

在运动与疾病的例子中,我们直观地知道运动不是影响疾病发生概率的唯一因素。还有其他的影响,如饮食、环境、遗传等等。然而,在上面的图表中,我们只看到了概率与锻炼时间的关系。在我们虚构的例子中,让我们假设疾病是由运动和年龄引起的。这表现在以下疾病概率的因果模型中。

Causal model of disease probability with two causes.

在数据中,疾病有两种不同的原因,但通过汇总数据并只看概率与运动,我们完全忽略了第二个原因——年龄。如果我们继续绘制概率与年龄的关系图,我们可以看到患者的年龄与患病概率呈正相关。

Plots of disease probability vs age stratified by age group.

随着患者年龄的增长,她/他患病的风险增加,这意味着即使运动量相同,老年患者也比年轻患者更容易患病。因此,为了评估只是锻炼对疾病的影响,我们会希望保持年龄不变改变每周的运动量。

将数据分组是做到这一点的一种方法,通过这样做,我们可以看到,对于给定的年龄组,锻炼降低了患病的风险。也就是说,控制对于患者的年龄来说,运动与较低的患病风险相关。考虑到数据生成过程和应用因果模型,我们通过保持数据分层以控制额外的原因来解决辛普森悖论。

思考我们想要回答什么问题,也可以帮助我们解决悖论。在餐馆的例子中,我们想知道哪家餐馆最有可能让我们和我们的伙伴都满意。尽管除了餐厅的质量之外,可能还有其他因素影响评论,但在无法获得这些数据的情况下,我们希望将这些评论组合在一起,并查看整体平均水平。在这种情况下,汇总数据最有意义。

在运动与疾病的例子中要问的相关问题是,我们个人是否应该进行更多的运动来降低我们个人患疾病的风险?因为我们是一个 50 岁以下或 50 岁以上的人(对不起,那些正好 50 岁的人),那么我们需要看正确的组,不管我们在哪个组,我们决定我们确实应该锻炼更多。

思考数据生成过程和我们想要回答的问题需要超越仅仅查看数据。这也许说明了从辛普森悖论中学到的关键一课:仅有数据是不够的。数据从来都不是完全客观的,尤其是当我们只看到最后的情节时,我们必须考虑我们是否了解整个故事。

我们可以通过询问是什么导致了数据,以及哪些影响数据的因素没有显示出来,来尝试获得更完整的图片。通常,答案表明我们实际上应该得出相反的结论!

现实生活中的辛普森悖论

这一现象并不像某些统计概念那样,是一个理论上可能但实际上从未发生的人为问题。事实上,在现实世界中有许多关于辛普森悖论的著名研究案例。

一个例子是关于两种肾结石治疗效果的数据。查看分成治疗组的数据,显示治疗 A 对大小肾结石都有更好的效果,但是汇总数据显示治疗 B 对所有病例都有更好的效果!下表显示了回收率:

Treatment data for kidney stones (Source)

怎么会这样呢?这个悖论可以通过考虑领域知识提供的数据生成过程——因果模型——来解决。事实证明,小结石被认为是不太严重的病例,治疗 A 比治疗 B 更具侵入性。因此,医生更有可能为小肾结石推荐较差的治疗 B,因为患者更有可能在第一时间成功康复,因为病例不太严重。对于大而严重的结石,医生通常会采用更好但更具侵入性的治疗方法 A。尽管治疗方法 A 在这些病例中表现更好,但由于它适用于更严重的病例,治疗方法 A 的总体治愈率低于治疗方法 b。

在这个现实世界的例子中,肾结石的大小——情况的严重性——被称为混杂变量,因为它既影响独立变量治疗方法——也影响非独立变量恢复。混淆变量也是我们在数据表中看不到的,但可以通过绘制因果图来确定:

Causal diagram with confounding factor

问题中的效果,恢复,是由治疗和结石的大小(情况的严重性)引起的。此外,治疗方法的选择取决于结石的大小,使大小成为一个混杂变量。为了确定哪种治疗方法实际上更有效,我们需要通过将两组分开并比较组内而不是组间的恢复率来控制混杂变量。通过这样做,我们得出结论,治疗 A 是优越的。

这里有另外一种思考方式:如果你有小结石,你更倾向于治疗 A;如果你有一颗大结石,你也会选择处理 A。因为你必须要么有一颗小结石,要么有一颗大结石,你总是选择处理 A,这样矛盾就解决了。

有时查看汇总数据是有用的,但在其他情况下,它可能会掩盖真实情况。

证明一个论点和反面

第二个真实的例子展示了辛普森悖论如何被用来证明两个相反的政治观点。下表显示,在杰拉尔德·福特总统任内,他不仅降低了每个收入阶层的税收,而且从 1974 年到 1978 年在全国范围内提高了税收。看一下数据:

All individual tax rates decreased but the overall tax rate increased. (Source)

我们可以清楚地看到,从 1974 年到 1978 年,每个税级的税率都在下降,而同一时期的总税率却在上升。现在,我们知道如何解决这个悖论:寻找影响总体税率的其他因素。总体税率是单个等级税率和的函数,也是每个等级的应纳税所得额的函数。由于通货膨胀(或工资增长),1978 年高税率的高收入阶层收入增加,低税率的低收入阶层收入减少。所以整体税率提高了。

除了数据生成过程之外,我们是否应该汇总数据还取决于我们想要回答的问题(也许还有我们试图提出的政治论点)。从个人层面来说,我们只是一个人,所以我们只关心我们支架内的税率。为了确定从 1974 年到 1978 年我们的税收是否增加了,我们必须确定我们税级的税率是否发生了变化,以及我们是否转向了不同的税级。个人支付的税率有两个原因,但在这部分数据中只有一个原因。

为什么辛普森悖论很重要

辛普森悖论很重要,因为它提醒我们,我们看到的数据并不是所有的数据。我们不能只满足于数字或一个图形,我们必须考虑数据生成过程——因果模型——负责数据。一旦我们理解了产生数据的机制,我们就可以寻找不在图上的影响结果的其他因素。大多数数据科学家都没有学习因果思考的技能,但这对于防止我们从数字中得出错误的结论至关重要。除了数据之外,我们还可以利用我们的经验和领域知识(或该领域专家的经验和知识)来做出更好的决策。

此外,虽然我们的直觉通常很好地服务于我们,但在并非所有信息都立即可用的情况下,它们可能会失败。我们倾向于专注于眼前的事物——我们所看到的都是存在的——而不是深入挖掘,使用我们理性、缓慢的思维模式。特别是当有人有产品要卖或者有计划要实施的时候,我们不得不对这些数字本身持极度怀疑的态度。数据是一种强大的武器,但它既可以被那些想要帮助我们的人使用,也可以被邪恶的行为者使用。

辛普森悖论是一个有趣的统计现象,但它也证明了防止操纵的最佳屏障是理性思考和问为什么的能力。

参考

  1. 维基百科关于辛普森悖论的文章
  2. 斯坦福百科关于辛普森悖论的文章
  3. 辛普森悖论:高级分析中的警示故事
  4. 朱迪亚·珀尔的《为什么之书:因果的新科学》
  5. 现实生活中的辛普森悖论
  6. 理解辛普森悖论

一如既往,我欢迎讨论和建设性的批评。可以通过推特 @koehrsen_will 或者我的个人网站 willk.online 联系到我。

CIKM AnalytiCup 2018 第二名解决方案

原文:https://towardsdatascience.com/simtext-2nd-solution-for-cikm-analyticup-2018-b3347e026e67?source=collection_archive---------12-----------------------

Conference on Information and Knowledge Management (CIKM) will be held at Torino, Italy, 22–26 October 2018.

这是我为 CIKM AnalytiCUP 2018 做的解决方案总结,是一个关于短文本语义相似度和知识转移的比赛。

问题定义

这项挑战的目标是建立一个跨语言的短文本匹配模型。源语言是英语,目标语言是西班牙语。参与者可以通过应用先进的技术来训练他们的模型,以对问题对是否具有相同的含义进行分类。

Overview of this dataset. We are asked to distinguish the intents between sentence 1 and sentence 2. Label being 1 indicates that spn_1 and spn_2 have the same meaning.

概观

Overview of the workflow. It is a 2-stage training framework where the first stage is to aggregates the word features and hand-crafted features using various symmetric models. And the second stage is inspired by the idea of knowledge distillation, I fine-tuned each model trained in the first stage with the soft labels.

特征工程

除了预先训练的单词嵌入,我还额外创建了三种特征来丰富句子信息。

  1. 距离特征

我测量句子向量之间的距离,句子向量可以通过三种方式构建:

  • 词袋模型
  • 带 TF/IDF 的词袋模型
  • 基于 TF/IDF 的加权平均单词嵌入

2.主题特征

在这个数据集中有许多常见的模式,因为当客户咨询相同的意图时,他们倾向于使用相同的前缀或后缀。

例如:

  • “我想”创造一个论点
  • “我想”和一个人说话
  • “我想”问是否…

我们可以假设句子有相同的前缀或后缀,主题相同。为了捕捉共现信息,我用 LDA/LSI 对句子进行了矢量化,并用余弦距离比较了它们之间的差异。

3.文本特征

文本特征都是关于句子的性质,例如:

  • 句子的长度:句子越长,概率应该越低。
  • 停用词和唯一词的数量:它可以显示冗余的程度。
  • 词语的多样性:它通常反映了上诉的复杂性。

最后,我创建了 56 个统计特征。以下是功能重要性和相关性热图的概述:

The feature importances, generated by a random forest classifier

The correlation heatmap of all my features

模型

由于一些模型仍在开发中,我目前只在我的 github 上传了部分解决方案。在清理完我的代码后,我会分享它们。回到主题,我尝试了三种基于不同假设的模型。

可分解注意力

可分解注意力是判断两句话是否相同的一个非常标准的解法。简而言之,可分解注意力将 sent1 中的单词与 sent2 中的相似单词对齐。

Figure from A Decomposable Attention Model for Natural Language Inference

这在这个数据集中很有帮助,因为有如此多的表面模式不断重复。例如:

  • 什么是
  • —什么是区号?
  • 什么事?
  • —什么是愿望清单?
  • 怎么才能拿到
  • —我如何获得订单?
  • —我如何获得退款?

你可以找到这么多可能的选择,这就是我们要解决的核心问题。如果我们只关注前面提到的统计特征,模型在这些情况下会失败,因为我们将一个单词编码为标识符,并放弃了它的意义。为了清楚起见,该模型会将“我如何才能获得订单”和“我如何才能获得退款”视为相同,因为它们共享了如此多的词(“如何”、“可以”、“我”、“获得”、“该”)。然而,由于“订单”和“退款”之间的区别,人类知道它们是不一样的。

你可能会说我们可以用 TF/IDF 来解决这个问题,但有时关键字不同但语义相同,就像这样:

  • 我想和一个男人说话
  • 我想和人类说话
  • 我想和一个员工谈谈

这些应该认为是一样的。顾客真正想要的是与人交谈,不管这个人是女人、男人还是雇员。

可分解的注意力比较它认为相关的东西。如果两个词确实有关联,也没关系。但是,如果没有,它可以更新上下文嵌入并使它们不同。一般来说,可分解的注意力建立了每个单词的类比关系,这让我们很容易抓住句子之间的显著差异。

除了可分解注意力之外,我还为这个任务设计了另外两个模型。

为什么不用可分解注意力呢?

在我看来,可分解注意力有两个缺点:

  1. 当应用注意力时,我们丢弃了单词的顺序,这意味着我们也丢失了像短语或单词之间的依赖关系这样的信息。这可能是一场灾难,因为我们被禁止使用任何其他外部数据。一旦特征消失了,我们就再也找不回来了。
  2. 冷启动词。我发现 google translator 倾向于将一些相似的概念总结成一个单一的概念,这导致训练数据缺乏词汇的多样性。然而,测试数据是原始的西班牙语句子,并没有那么简单。我想这就是为什么即使可分解的注意力在本地简历上做得很好,它总是大大超过 LB。
  3. 为了应对这两个弱点,我深入研究了另外两个模型。RNN 模型用于重建依赖关系,而 CNN 模型用于捕捉区域语义表示。让我们从 RNN 模型开始。

比较传播递归神经网络

简而言之,我遵循 Cafe 的精神,也提出了其他的想法,使它更好地完成这项任务。

The high level overview of CAFE. Figure from A Compare-Propagate Architecture with Alignment Factorization for Natural Language Inference

  1. 我用 MLP 替换了 FM 层,并将所有交互特征混合为一个矢量。我发现在尝试用 DeepFM 改变 FM 部分时效果更好。在我看来,这是因为 MLP 可以塑造高层次的互动,可以很好地与辍学正规化。
  2. 至于交互层,我加了求和运算,同时比较各种特征。有趣的是,这样一个简单的动作将 LB 分数提高了 0.015。
  3. 我将这个模型修改为对称架构。原因我会在正规化部分讲。

密集增强卷积神经网络

在实现 Cafe 时,我想出了一个主意。为什么不重复增加和转发的循环,这使得模型更好地融合了本地和序列信息。我试了一下。这个想法对 RNN 来说失败了,但对 CNN 来说却成功了。我认为这是因为 RNN 保留了每个时间步长的冗余信息,而 CNN 没有。CNN 只关注地区信息,这也是这场竞争的关键部分。

让我们回到可分解注意力的第一个缺点——掉话序。例如,它不是“我的”和“你的”。我们不应该独立地比较这几类词。我们需要的是看着它们附近的单词,比较整个短语。此外,该方法还减轻了冷启动字的影响。就像 word2vec 的核心信念一样,我们可以通过一个词的邻居来理解它的意思。

DACNN 的架构是可分解注意力的扩展。我设计了一个比较循环,将结果与原始嵌入重复连接起来,就像 DenseNet 一样。这对于特征重用和正则化是一个很好的想法,使得 DACNN 在几乎相同的性能下运行速度比 CPRNN 快 3 倍。

我们还尝试通过应用两次软对齐来对齐句子本身。这是另一种在语义摘要中起重要作用的自我注意方式。

模型种类

正如我们在上一节中看到的,这三个模型基于不同的假设。每个模型之间的相关性也可以表明这一事实。

The correlation matrix of prediction from each model

所以我不打算谈论不同型号之间的差异。相反,我将展示如何在模型内部创建变体。方法很简单。如果我们在同一个网络中插入不同的输入,直觉上预测会不同。

我为每个模型准备了三种类型的输入:

  1. 字级输入。我从官方的预训练嵌入中查找每个单词。我没有直接训练嵌入层,而是在它上面放置一个公路层来微调权重。
  2. 字符级输入。我按照论文“字符感知神经语言模型”来创建字符级嵌入。这里是它的架构概述。

The way to costruct word embedding from char level.Figure from Character-Aware Neural Language Models

  1. 具有元特征的单词级输入。元特征在特征工程中得到了很好的讨论。在公路图层之后,我将它们与交互功能连接起来。

这三个输入确实产生不同的预测,并在打包时导致显著的提升。

The LB socre of single model and blended.

你可能会问,为什么我们不同时接受各种输入呢?的确,这将是一个很好的尝试。准确地说,我们可以试验 2 - 1 种组合。我训练了其中的三个,因为我只有一台电脑。我相信我们可以通过包装所有类型的模型来进一步提高性能。

全体

受“提取神经网络中的知识”的启发,我为我的合奏使用了两级堆叠。第一层是各种模型的简单混合。我使用混合预测作为伪标签,并用它们微调所有模型。

第二层是 DART(漏失符合多重加性回归树),它从微调模型中获取输入。

至于伪标签,我使用软标签而不是硬标签有两个原因:

1.训练数据有噪声。我可以用传递法则做一个简单的证明。

  • 规则 1:假设 A 和 B 相同,B 和 C 也相同。我们会认为 A 和 C 是相同的。
  • 规则 2:假设 A 和 B 相同,B 和 C 不相同。我们会认为 A 和 C 是不同的。

规则 1 和规则 2 分别只适用于 75%和 95%的情况。我认为标签没有绝对的规则,可能因人而异。

2.软标签适合正则化,通常更有意义。关于软标签在“通过惩罚置信输出分布来正则化神经网络”和“用有噪声的标签学习”中的好处,有充分的讨论。特别是当采用对数损失作为评估标准时,我们希望输出的分布更加平滑,而不是更加极端。此外,在一个没有完美答案的任务中,我认为用概率来表示等级关系的程度会更有意义。

正规化

软标签

我们已经在合奏部分讨论过了。

拒绝传统社会的人

我倾向于在两个地方使用 dropout,而不是在每个密集层后设置小比率的 dropout:

  • 与其他公司相比,我们的训练数据实在是太少了。也就是说,我们不能构建一个大模型,否则维度的诅咒会惩罚我们。

    所以我使用嵌入 dropout 在训练批次中随机丢弃一些单词。这一举动可以被认为是一种数据扩充。通过嵌入 dropout,我们可以仅使用少量数据来概括像 CAFE 这样的复杂模型。

We can see that embedding dropout (ED) improve the performances of all models dramatically.

  • Concat-Feature dropout:
    我将 dropout 放在交互层之后。它遵循随机森林的精神,因为交互层只不过是一个特性池。该模型有时关注来自求和与相乘的特征,有时选择来自点和连接的特征。这种策略有助于模型对不同的数据视图进行归纳。

对称

在“NLP 中的外推法”中,他们观察到对称架构是一般化的关键。我认为这在这个任务中是有意义的——相似性度量也是对称的。我们期望 Sim(A,B)应该与 Sim(B,A)相同。但是,我们通常不会把它放在心上。当创建交互特征时,我们总是应用连接操作,该操作破坏了对称性。

那么去掉这个功能怎么样?
没那么容易。根据 Cafe 的消融研究,concat 功能是模型性能的功臣。

The ablation from CAFE, we can see the scroe descreases significantly when removing Concat Feat

为了掌握对称性和连接特性,我做了两次连接操作。第一次用于[Sent1,Sent2],第二次用于[Sent2,Sent1]。最后,平均这两个结果。

顺便说一下,我尝试了其他方法来解决对称的问题。例如,我们可以将训练数据加倍,一个用于句子对,另一个用于句子对。或者,我们可以在测试阶段对对****和对的预测进行平均。然而,这两种解决方案背后都有一定的成本,这就是我最终放弃它们的原因。****

性能比较

The log loss of blending methods are measured by corresponding out-of-fold predictions.

参考

  1. 一种用于自然语言推理的带有对齐因子的比较传播结构
  2. 自然语言推理的可分解注意模型
  3. 字符感知神经语言模型
  4. 用于句子分类的卷积神经网络
  5. DART:退出者遇到多重加法回归树
  6. DeepFM:一种基于因子分解机的神经网络用于 CTR 预测
  7. 密集连接的卷积网络
  8. 提取神经网络中的知识
  9. 用于自然语言推理的增强型 LSTM
  10. 自然语言处理中的外推
  11. 从单词嵌入到文档距离
  12. 用嘈杂的标签学习
  13. 规范和优化 LSTM 语言模型
  14. 通过惩罚置信输出分布来正则化神经网络
  15. R-net:具有自匹配网络的机器阅读理解
  16. 使用数百万个表情符号来学习任何领域的表达,以检测情绪、情感和讽刺

聚类问题的模拟退火:第一部分

原文:https://towardsdatascience.com/simulated-annealing-for-clustering-problems-part-1-3fa8994a3ebb?source=collection_archive---------9-----------------------

Image source: Wikipedia

嘿,在这篇文章中,我将尝试解释如何在聚类问题中使用模拟退火 (AI 算法),这是一种用于逼近给定函数全局最优值的概率技术。首先,我想解释一下什么是模拟退火,在下一部分,我们将看到文章中的代码,它是这篇研究论文的实现。

模拟退火(SA) 广泛应用于搜索空间离散(不同且个体化的城市)的搜索问题(例如:寻找两个城市之间的最佳路径)。在这本由斯图尔特·拉塞尔彼得·诺威格撰写的书中可以找到一个带有例子的精彩解释。 AIMA

伪代码的 python 代码可以在这里找到。

[## aima code/艾玛-python

算法的 Python 实现来自 Russell 和 Norvig 的“人工智能-现代方法”…

github.com](https://github.com/aimacode/aima-python/blob/master/search.ipynb)

为了直观地理解什么是模拟退火,我们需要对爬山有一个简要的了解。爬山是一种旨在寻找系统最佳状态的算法。让我们快速地看一个例子。

假设有 5 个状态名为 A、B、C、D、E,我们有我们的人工智能算法,在这种情况下是爬山法,最初是在状态 A 上。让我们按降序分配状态的能量值,并且假设具有最少能量的状态将是最佳的。为了便于理解,我们取一个与能量成反比的参数Optimal Points,它决定了一个状态有多好。因此,最佳点应该以递增的顺序排列,让我们为状态 A、B、C、D、e 设置值 6、7、8、9、10。

这里 E 是最佳状态,因为它的能量较少,A 是最差状态,因为它的能量较多。

该算法的目标是选择最优状态(最小能量)作为最终状态。爬山方法是一种简单的方法,它基本上比较当前状态的相邻状态的能量,并选择三个状态中具有最小能量的一个状态作为下一个状态。 在我们的例子中,它比较当前状态的相邻状态的最优点,并选择三个状态中具有更多最优点的一个状态作为下一个状态。

Pseudocode of Hill-Climbing Algorithm

def hillClimbing(system):
    current_state = system.initial_state
    while(True):
         if energy(neighbour_left_current) <=  energy(neighbour_right_current):
    next_state = neighbour_left_current
  else:
    next_state = neighbour_right_current
  if (energy(next_state) < energy(current_state)):
    current_state = next_state
  else:
    final_state = current_state
    return final_state

移动到比当前状态更优化(更少能量)的状态被认为是好移动,而移动到比当前状态更不优化(更多能量)的状态被认为是坏移动。严格来说,爬山只需要好的动作。

现在我们可以看到,算法在状态 E 上结束,因为它具有最小的能量,因此是最佳状态。

但是,这种方法有一个问题。如果我们将值 5、6、7、6 和 8 分别分配给状态 A、B、C、D 和 E,初始状态为 A,我们将永远不会到达状态 E,因为算法将选择 C 作为最终状态,因为 C 比其相邻状态具有更多的最佳点(更少的能量),并且当当前状态和下一状态相同时,算法将停止。正如我们所看到的,这不是全局最优。这就是爬山的问题,它可能会在局部最优状态结束,并将其标记为最终状态

模拟退火借助一个叫做温度的参数解决了这个问题(在 SA 这里 ) 了解更多关于温度参数的信息)。假设你正在灌装一个空水瓶。最初,你会冲过去把水倒进去,对吗?当水到达瓶子的边缘时,你会放慢速度,小心地倒酒。SA 也做了类似的事情。最初,温度被设置为一个较高的值,并不断降低,直到为零。

当温度持续下降时,模拟退火算法将开始采取行动并进入新的状态。还有一个与温度参数成正比的概率因子。这个概率因子告诉我们算法有多大可能移动到一个新的状态,即使它导致一个坏的移动。

如果温度高,那么概率因子就高。换句话说,在初始阶段,算法最有可能做出导致错误移动的动作,因为温度会很高,因此概率因子 P_E 会很高。在最后阶段,温度会很低,概率因子 P_E 会很低,因此它最不可能做出不好的举动。

SA 用这种方法消除了“陷入局部最优的机会”问题。它确保在开始阶段(当温度高时)探索所有的状态,并且当温度降低时,它小心地选择一个状态作为下一个状态。

Pseudocode for Simulated Annealing

def simulatedAnnealing(system, tempetature):
    current_state = system.initial_state
    t = tempetature
    while (t>0):
          t = t * alpha
          next_state = randomly_choosen_state
          energy_delta = energy(next_state) - energy(current_state)
          if(energy_delta < 0 or (math.exp( -energy_delta / t) >= random.randint(0,10))):
             current_state = next_state
    final_state = current_state
    return final_state

这里α(即< 1)是温度下降的衰减率。概率因子是math.exp(-energy_delta / t )

这是 s a 的一个非常基本的版本,我们将在下一部分中修改它,同时尝试使用 SA 将对象放入集群中。如果我解释的对你没有任何意义,请参考这个视频,因为了解 SA 对进一步深入真的很重要。很快将会有另一部分,将会是解释这篇论文的代码。

注:SA 有几个版本解释不同。有一些例子,初始温度设置为零,并开始增加,直到一个极限。这里 P_E 应该是math.exp(energy_delta / t )和 alpha > 0。请不要被这样的例子所迷惑。只要确定你理解了这个概念。

聚类问题的模拟退火:第二部分

原文:https://towardsdatascience.com/simulated-annealing-for-clustering-problems-part-2-a095dd100dc?source=collection_archive---------8-----------------------

嘿,大家好,这是这个系列的第二部分,也是最后一部分。在这篇文章中,我们将把这张纸转换成 python 代码,从而获得对什么是模拟退火以及它如何用于聚类的实际理解。****

本系列第 1 部分 涵盖了模拟退火( SA )的理论解释,并附有一些例子。推荐你读一读。然而,如果你对 SA 非常了解或熟悉,我认为你可以理解你将要阅读的大部分内容,但如果有什么不确定的,你可以随时转到第 1 部分阅读。我不打算解释整篇论文,只解释实用部分。

因此,让我们从了解集群的含义开始。聚类是一种无监督学习技术,其目标是基于对象之间的相似性将标签附加到未标记的对象上。让我们快速进入一个可以使用聚类的真实示例,这样您会有更好的理解。假设有一个购物网站,你可以在那里查看衣服,配饰,如果你喜欢就买。

Items in the Shopping Website

假设这些是您访问过的购物网站上提供的商品。当你反复查看鞋子、衬衫、牛仔裤和手表等少数商品时,你会发现越来越多的商品被推荐给你。你注意到了吗?这是怎么发生的呢?事情是这样发生的:网站会统计你浏览一个产品的次数。基于这个数字,项目被聚类成喜欢的和不喜欢。当你反复看一些产品时,也许你是想买你喜欢的那种相似的产品。因此,该网站将衬衫、鞋子、牛仔裤和手表放在“喜欢”集群下(换句话说,给它们贴上喜欢的标签),并将其他浏览次数较少的商品放在“不喜欢”集群下。这些标签只是例子。它们可以被命名为类似于【可能购买】【可能不购买】的任何东西,这取决于网站的开发者。

After Clustering

对不起,我的演讲技巧不好,但我希望你去的想法。现在其他网站可以使用这些信息,向你展示关于鞋子、衬衫等的广告。这是一个很基本的例子。在现实生活中,可能有更多的因素影响聚类(不仅仅是你查看它的次数)。

从程序上来说,它看起来会像这样:

Example of how the code looks

根据您查看项目的次数,项目将被聚类。基于发生聚类的因素称为** 内部聚类准则。这里的内部聚类标准是你查看一个项目的次数。内部聚类标准的另一个流行的例子是距离,用于 K-Means 聚类 (参考 Mubaris Hassan 的这篇帖子以获得更好的解释)。**

现在您已经了解了聚类和内部聚类标准,我们的目标是使用模拟退火,按照预定义的内部聚类标准进行聚类。****

让我们使用一个示例场景开始实现本文中所写算法的代码。假设有 10 个对象(1 到 10)和 6 个标签(A 到 F ),初始状态如下:

initial_state = {1:’A’, 2: ‘B’, 3:’A’, 4:’B’, 5:’C’, 6:’B’, 7:’A’, 8:’None’, 9:’None’, 10:’None’ }

这里,对象 1 至 7 被标记,而对象 8 至 9 没有被标记。

让我们把未使用的标签放在一个列表中

unused_labels = ['D', 'E', 'F']

基本算法步骤是:

  1. 称为“初始温度”的变量被设置为高,并持续降低,直到称为“最终温度”的低温值。****
  2. 当温度持续下降时,将“初始状态”作为“当前状态”。****
  3. 对当前状态进行操作,并根据定义的内部聚类标准计算其能量。如果这个“扰动状态”(扰动状态)与当前状态不同,则选择它作为“下一状态”
  4. 计算下一个状态和当前状态的能量之差。
  5. 仅当能量差小于零或“概率因子”(取决于当前温度)大于或等于 0 到 1 之间的随机十进制数(或 0 到 10 之间的随机整数)时,下一状态的值才被放入当前状态。
  6. 这取决于温度值和一个名为“最大迭代次数”的参数。****

存在类似于、【成本增加次数】、、最大随机扰动迭代次数、、【接受率】、【概率ε】、(不要与上述概率因子混淆)和、【Beta】、** (0 < beta < 1】、**的参数,使用这些参数来计算初始和最终温度。****

initial_temperature = avg_cost_increase / math.log( num_cost_increases / ((num_cost_increases * acc_ratio) — (1-acc_ratio) * (max_iter — num_cost_increases)))final_temperature = -beta * avg_cost_increase / math.log(prob_e)

****“alpha”定义为温度持续下降的衰减率。

alpha = math.pow(final_temperature / initial_temperature , 1 / num_temp)

最大值、接受率、概率ε和β的值为:

avg_cost_increase = 200
acc_ratio = 0.75 
prob_e = 0.00000000001
beta = 0.125
max_iter =  4 * num_objects

****所有这些数值和公式都取自论文本身。我不想在这里解释所有的参数,因为我们必须更深入地挖掘,我认为这将稍微偏离我们的实际主题。但是,如果您非常感兴趣,请参见论文的参考资料部分。

这是我们到目前为止所做的代码。让我们看看模拟退火函数:

在解释这一点之前,我需要解释两个叫做“value”的函数,它计算一个状态的能量“action _ on ”,它干扰当前状态,直到出现变化,并使受干扰的状态成为下一个状态。****

这是代码中最重要的部分。我们需要计算状态的能量,为此,我们需要定义一个状态何时会高能或低能。让我们定义,当有更多的对象被标记为 F 时,状态将具有较少的能量,而当有较少的对象被标记为 F 时,状态将具有较高的能量。因此,算法将总是努力使状态具有最低的可能能量,因此,它将尝试将最大数量的对象放入 F 簇中,换句话说,将最大数量的对象标记为 F。****

因此,这里的内部聚类标准是将最大数量的对象标记为 F。你可以尝试任何其他标签。您可以尝试不同的内部聚类标准,如标记为 B 的对象数量应该等于标记为 A 的对象数量,标记为 A 的对象数量应该是标记为 C 的对象数量的 1/3,以及更多涉及不同标签的此类数学等式。请确保您理解了这一段,因为这是您在各种情况下执行本准则的关键点。

现在让我们来看看代码中对当前状态进行操作以产生下一个状态的部分:

我们初始化两个列表 L(已用标签)和 Lc ( L 补码-未用标签列表),并将当前状态复制到称为扰动状态的新变量中。选择一个随机对象,进入循环后,在[0,|L|]之间选择一个随机整数 m。如果 m = 0,并且存在一个未使用的簇标签(即|L| < k),那么较早选择的随机对象将从未使用标签列表中获得一个随机标签。如果使用的标签的长度和标签的总数(k)相等,那么这意味着没有未使用的标签,并且所选择的对象将从使用的标签列表中获得一个随机标签。

现在我们需要检查扰动状态是否不同于当前状态。可能有这样一种情况,一个对象获得了它已经拥有的相同标签。例如:对象 3 已被随机选择,其中一个条件(m > 0 或 l 的长度等于 k)为真,标签 A 从已用标签列表中随机选择。在这种情况下,扰动后的状态将与当前状态相同。不会有变化。所以我们将运行这个循环,直到扰动状态不等于当前状态,最后返回扰动状态。****

所以我们把微扰态作为 nex 态,之后通过值函数计算下一个态的能量。如果下一个状态的能量小于当前状态的能量,或者如果概率因子大于或等于 0 到 10 之间的随机整数,则我们将下一个状态的值放入当前状态。

  1. 这个过程持续运行(最大迭代次数乘以初始和最终温度的差值)次。

以下是最终代码:

以下是输出:

在这里,每次“最终状态能量”都有不同的值,因为在每次执行时,算法会随机选择许多值。您可以对参数进行一些调整,看看结果是如何受到影响的。通过足够大的最大迭代次数和足够小的(1-接受率)、β和概率ε,您可以获得更好的结果。****

就是这样,伙计们,我尽了最大努力将论文的一小部分转换成简单的语言。我希望你明白整个概念。如果你觉得一下子处理所有这些很困难,那也没关系。如果你有什么不确定的,请再读一遍。如果您有任何不明白的地方或发现任何技术或语法错误,请留下您的回复。此外,不要忘记尝试在您的系统上运行这个程序,并调整参数以获得更好的结果。你可以在这里** 一下。**

非常感谢你的时间。祝您愉快!!

用 Python 或 Moneyball 模拟网球比赛

原文:https://towardsdatascience.com/simulating-tennis-matches-with-python-or-moneyball-for-tennis-a3359df0d072?source=collection_archive---------4-----------------------

Photo by Moises Alex on Unsplash

在过去的几个月里,我想了很多关于体育博彩的事情。当然,监管方面的变化是有帮助的,但对我来说,很难看到一个有这么多广泛可用数据的问题而不去尝试。

我是打网球和看网球长大的。当我开始真正进入这项运动时,皮特·桑普拉斯或多或少已经退役,阿加西还没有完全恢复过来,但仍然是一个竞争者,像萨芬这样的新人(刚刚在美国公开赛决赛中战胜桑普拉斯)已经建立了危险和天才球员的声誉。然后是罗杰·费德勒。他颠覆了一切——忘掉世界纪录吧,他提供了一些我所见过的最惊人的比赛数据。这是教科书式的胜利,胜利与失误的比率,第一发球的百分比,以及转换的破发点。虽然你不需要看统计数据,但你可以或多或少地看他的任何比赛,看到任何投篮近乎完美的执行。后来,当我因为极度焦虑而停止观看他的比赛时(特别是当他和拉法比赛时),我注意到你可以从他的一次发球得分中解读出他的比赛进行得如何。这仍然是我用来追踪他在锦标赛中表现的指标。总之,这是模拟系统的一些个人背景。

我们的目标:我们对预测网球比赛感兴趣。虽然有几种方法可以做到这一点,但我们想采取一种逐点的方法。假设一个球员的发球是 iid。设𝑝𝑠1 是一号选手发球得分的概率,𝑝𝑠2 是二号选手发球得分的概率。如果一个玩家赢得一分,另一个玩家必须失去一分,所以玩家 1 赢得回报的概率就是𝑝𝑟1 = 1 𝑝𝑠2.因此,我们可以忘记返回概率。虽然你可以用递归方程和一点组合学计算出赢得比赛的概率,但我们想用模拟来代替。我们将假设 6 场比赛中的所有盘都以抢七局结束,我们打 3 盘三胜制。

为了增加复杂性,让我们假设赢得点数的概率在“大点数”上变化。一个大的点被定义为一个能让你赢得一局或一盘的点(所以包括抢七局中的设定点)。所以我们把𝑝𝑠1,𝐵和𝑝𝑠2,𝐵的概率相加,作为一名球员在一个大点上发球得分的概率。否则,概率仍然是𝑝𝑠1and 𝑝𝑠2.

我们的目标是用以下方式来编排我们的分数:40–15 | 6:4 6:7 3:3,也就是说,对于正在进行的比赛和抢七局,先列出发球的球员。对于集合(无论是进行中的还是完成的),首先列出玩家 1,然后是玩家 2。这将有助于我们逐点跟踪游戏,并在调试时使事情变得更容易,因为任何奇怪的分数组合都会脱颖而出,并提示我们逻辑中可能存在的问题。

概述:作为一种快速方法,我们将通过设置一系列函数来解决这个问题:

  1. 一个函数 simulate_set ,它跟踪该组中的游戏,并确定该组是否将进入决胜局
  2. 一个名为的玩家服务器的功能,为服务器和返回者增加点数,并跟踪大点数
  3. 函数是 BigPoint ,它更像是一个辅助函数,用于确定和一个伴随函数 getBigPointProbability,,它也作为一个辅助函数,如果一个点被确定为大点,则返回新的概率
  4. 一个函数 simulate_tiebreak ,用于播放决胜局
  5. 函数 getScore ,其功能相当于记分板
  6. 两个函数 printSetMatchSummarypointsMatchSummary ,它们打印有用的更新,例如“玩家 1 赢了第 16 盘比赛到第 2 盘”和“玩家 1 赢了第 3 盘比赛到第 1 盘”。这些功能并不是明确必需的,但我认为它们提供了一个很好的美学触觉

构建功能:

在完成一个模拟或任何代码结构之后,回过头来写它永远也不会抓住整个过程——所有写的和删除的行,所有的“是!”破解逻辑的时刻,最终导致“该死!回到绘图板”运行结果。因此,下面呈现的是必要功能的完整副本:

控制流程:

上面的代码有一个运行所有代码的部分。我们考虑了大多数重要参数的默认值,如玩家名、ps1 和 ps2、bigpoint1 和 bigpoint2。我喜欢认为 ps1 和 ps2 是第一发球的百分比,但是我们可以做很多有趣的特征工程来使概率更有洞察力。如果我们想要运行 10 次、100 次、1000 次或更多次此匹配的模拟,以便了解置信区间,我们可以按如下方式更改我们的控制代码:

#this control flow module runs 1000 simulations
#and stores the winner of each simulation in winner=[]winner = []
p1 = "A"
p2 = "B"
a = 0.64
b = 0.62
p1_big_point = 0.70
p2_big_point = 0.68#run 1000 runs of the simulation
for ii in range(0, 1000):
    completed_sets = []
    S = 0
    gamesMatch = 0
    pointsMatch1, pointsMatch2 = 0, 0
    setsMatch1, setsMatch2 = 0, 0
    pointsTie1, pointsTie2 = 0, 0
    pointsGame1, pointsGame2 = 0, 0

    while S < 5 and max(setsMatch1, setsMatch2) < 3:
        gamesSet1, gamesSet2, gamesMatch, S, pointsMatch1, pointsMatch2 = simulateSet(a, b, gamesMatch, S, 
                                                                                      pointsMatch1, pointsMatch2, completed_sets)
        print()
        if gamesSet1 == 6 and gamesSet2 == 6:
            pointsTie1, pointsTie2, gamesMatch, pointsMatch1, pointsMatch2 = simulateTiebreaker(p1, p2, a, b, gamesMatch, 
                                                                                                pointsMatch1, pointsMatch2, completed_sets)setsMatch1, setsMatch2 = printSetMatchSummary(p1, p2, gamesSet1, gamesSet2, S, 
                                                      pointsTie1, pointsTie2, setsMatch1, setsMatch2)if gamesSet1 == 6 and gamesSet2 == 6:
            if pointsTie1 > pointsTie2:
                completed_sets.append([gamesSet1+1, gamesSet2])
            else:
                completed_sets.append([gamesSet1, gamesSet2+1])
        else:
            completed_sets.append([gamesSet1, gamesSet2])pointsMatchSummary(p1, p2, setsMatch1, setsMatch2, pointsMatch1, pointsMatch2)

当我们的代码运行时,输出如下所示(只是一小段代码)。请注意,在游戏结束时,代码显示玩家 A 与玩家 B 赢得的分数:

A 0-0|[0-0]
A 15-0|[0-0]
A 15-15|[0-0]
A 30-15|[0-0]
game point
A 40-15|[0-0]
game point
A 40-30|[0-0]
  A: 4, B: 2
B 0-0|[0-1]
B 0-15|[0-1]
B 0-30|[0-1]
B 15-30|[0-1]
B 15-40|[0-1]
B 30-40|[0-1]
  B: 2, A: 4 -- A broke
A 0-0|[2-0]
A 0-15|[2-0]
A 15-15|[2-0]
A 15-30|[2-0]
A 15-40|[2-0]
  A: 1, B: 4 -- B broke
B 0-0|[1-2]
B 15-0|[1-2]
B 30-0|[1-2]
game point
B 40-0|[1-2]
game point
B 40-15|[1-2]
  B: 4, A: 1

如何利用这个进行投注:现在,我不打算泄露我所有的秘密,但网球投注是统计方法的一个相当好的目标。我还没有用过这个,但是我不会在全部比赛中下注(或者除此之外),我会用它来赌下一分。给定输出,我们可以解析许多次运行,以查看玩家在 40–15 或 30–30 上获胜的频率。

这是不是有点简单化了?

是啊!大部分模拟都是。在这种情况下,我们的重点是获得一些游戏流程的框架,我们缩小了整个比赛的跟踪 ps1 和 ps2。

a.对于模拟的改进,我有一些想法,可以归类为统计/模型改进和编码/软件工程改进:

统计:

最初,我们认为我们可以通过整合更多的数据来进行更准确的模拟,而不仅仅是赢得服务器的单一概率。然而,经过更多的思考,我们相信我们仍然可以用奇异的概率工作。为了设置一个合适的开始概率,我们可以从已完成的比赛中获取球员的统计数据,具体来说,重要性的指标将是:第一发球百分比,第一发球得分(%),第二发球百分比,第二发球得分(%),转换的破发点(%),防守的破发点(%)。我们可以对它们进行平均,以获得一个全面的指标,或者继续我们以发球为重点的模拟,并构建一个类似于首次发球百分比/L2 范数(metrics_listed_above)的指标。我们可以对其他指标运行这个作为分子,并对照历史匹配来查看哪个指标具有最强的预测能力。L2 标准的使用将它放在其他度量标准的上下文中。我们还应该实现大点,这样服务器的断点就被认为是大点。

这引出了我们模拟的另一个问题。它关注的是球员发球得分,但在真正的比赛中,得分是波动的。我们使用了一个固定的概率,即使是计算这个固定概率的最好方法也不能真正涵盖比赛中表现起伏的事实。模拟这个问题的一个更准确的方法是使用动态计算的发球获胜概率。一场网球比赛可以被表示为离散的状态空间。这使我们能够用马尔可夫链来模拟比赛,因为游戏中的每个点都是一个状态,并且存在进入下一个状态的转移概率,这可以编码到转移矩阵中。与大多数马尔可夫模型一样,实现可能会有点乏味,但值得指出的是,这是可行的,并且可能是利用根据我们上面列出的指标收集的数据的更好方法。

从模拟的想法退一步,如果我们的目标是预测获胜者,我们怀疑网球将是分类算法的一个伟大领域。我们相信分类算法可以适当地利用可以归因于运动员和比赛的丰富的特征集。例如,上面列出的重要指标只是在匹配过程中创建和生成的所有统计数据的子集。同样,每场比赛都有自己的特点,最简单的就是天气条件。我们可以在匹配级别上对齐这些值,即在匹配结束时计算的统计数据,甚至可以下至点级别,以便获得大量数据。查看每个球员的历史比赛,我们可以计算出击败某种类型对手的概率。

然而,所有这些都假设玩家 A 和玩家 B 是有比赛历史的真实玩家,而不仅仅是为了模拟而构建的

工程:

为解决这个问题而编写的代码有几个独立的函数和一个控制这些函数之间流程的主循环。虽然这是功能性的,可以作为产品级代码,但我们相信,当以面向对象的方式处理时,解决方案可以更好地被综合。网球适合这种实现方式,因为每个运动员都有不同的属性,而比赛、比赛和比赛都有共享的属性。首先,我们想要创建一个玩家类,它将保存诸如赢得一个点的概率、赢得一个大点的概率、赢得的集合和赢得的游戏等属性。每个玩家都是这个类的对象。我们可以在这个类中实现一个 addPoint 函数,这样每个玩家对象都可以跟踪自己的点。这将有助于我们实现一个事件日志类型的触发器,如果玩家对象的点数达到一定数量,就会发生诸如平局或大比分之类的事件。

接下来,我们想要创建一个类 Match 和类 Set 和 Game,分别扩展 Match 和 Set。与 Player 类类似,会有许多 getter 和 setter 函数来跟踪每个比赛、集合和游戏的属性。其中最重要的是 getScore,其中 Match、Set 和 Game 通过继承拥有自己的副本,因为这个函数在自己的类中,所以不需要函数参数。继承的另一个有趣的优点是 Set 和 Game 中的 isTiebreak 和 playTiebreak 函数。如果一个游戏或一组游戏进入了抢七局和 playTiebreak,isTiebreak 将返回一个布尔值来执行逻辑。这样做的原因是因为在网球比赛中,一场比赛或多或少是一个原子单位,通过这个单位可以组成一组比赛。因此,当两名球员的得分为 40-40 时,他们实际上是在打迷你抢七局,只是得分在平分(D)和优势(A)之间波动,而不是像在一盘结束时的抢七局中那样的数值。理论上,我们可以让 Game 成为基类,Set 将扩展 Game,Match 将扩展 Set,但这还没有完全想好。

我们相信以上是在生产层面上解决这个问题的最佳布局。这为将来提供了更大的灵活性,因为我们可以很容易地为每个类添加更多的属性。然而,所提交的代码只是一个概念证明。我们可以运行模拟,并最终理解定期运行是否有价值。在这个问题的范围之外,如果我们考虑测试模型的有效性,基于函数的脚本方法允许快速的概念验证。一旦我们在我们的模型中发现了有效性,我们就可以以上述面向对象的方式设置生产级代码,同时仍然保持核心程序流逻辑(在这种情况下,用于确定平局打破、大比分、相对于平局和优势的得分变化的参数)并优化我们的功能。

结论:

随着模拟复杂性的增加,我认为有必要转向面向对象的方法。如果你对体育博彩不感兴趣,但对编码感兴趣,这可能是一个很好的机会,可以采用函数式方法进行模拟,并将其转化为面向对象的程序,以更好地学习多态性的原则。如果你对体育博彩感兴趣,那么就去获取公开的比赛数据,并改进统计分析。网球是一项伟大的算法博彩运动,因为它有大量的数据和运动的本质,即 1 对 1,而不是模拟一个团队。玩得开心,祝你好运!

用 Python 中的马尔可夫链模拟文本

原文:https://towardsdatascience.com/simulating-text-with-markov-chains-in-python-1a27e6d13fc6?source=collection_archive---------2-----------------------

在我的上一篇文章中,我在马尔可夫链蒙特卡罗方法的背景下介绍了马尔可夫链。这篇文章是那篇文章的一个小附录,展示了你可以用马尔可夫链做的一件有趣的事情:模拟文本。

Pixabay

马尔可夫链是一个模拟的事件序列。序列中的每个事件都来自一系列相互依赖的结果。特别是,每个结果决定了接下来可能会发生哪些结果。在马尔可夫链中,预测下一个事件所需的所有信息都包含在最近的事件中。这意味着知道马尔可夫链的全部历史并不能比只知道上一个结果更好地帮助你预测下一个结果。

马尔可夫链通常不是近期事件的可靠预测,因为现实世界中的大多数过程比马尔可夫链允许的要复杂得多。然而,马尔可夫链被用来检验一系列事件的长期行为,这些事件以固定的概率相互关联。

对于世界上非独立事件的任何序列,并且在有限数量的结果可能发生的情况下,可以计算将每个结果相互关联的条件概率。通常情况下,这只是简单地采取计算特定结果在观察到的序列中一个接一个出现的频率的形式。

要生成基于某个文本的模拟,请计算使用的每个单词。然后,对于每个单词,存储下一个使用的单词。这是文本中单词的分布取决于前面的单词。

为了模拟唐纳德·特朗普的一些文字,让我们使用他在 2016 年竞选中的演讲集这里

首先导入 numpy 和包含特朗普演讲的文本文件:

import numpy as np
trump = open('speeches.txt', encoding='utf8').read()

然后,将文本文件拆分成单个单词。注意,我们保留了所有的标点符号,所以我们的模拟文本有标点符号:

corpus = trump.split()

然后,我们定义一个函数来给出演讲中所有的词对。我们使用惰性求值,产生一个生成器对象,而不是用每一对单词填充我们的内存:

def make_pairs(corpus):
    for i in range(len(corpus)-1):
        yield (corpus[i], corpus[i+1])

pairs = make_pairs(corpus)

然后,我们实例化一个空字典,并用我们对中的单词填充它。如果单词对中的第一个单词已经是字典中的一个关键字,只需将下一个单词添加到该单词后面的单词列表中。否则,在字典中初始化一个新条目,其键等于第一个单词,值为长度为 1 的列表:

word_dict = {}for word_1, word_2 in pairs:
    if word_1 in word_dict.keys():
        word_dict[word_1].append(word_2)
    else:
        word_dict[word_1] = [word_2]

最后,我们随机挑选一些单词来启动这个链,并选择我们想要模拟的单词数量:

first_word = np.random.choice(corpus)chain = [first_word]n_words = 30

在第一个单词之后,链中的每个单词都是从特朗普实际演讲中跟随该单词的单词列表中随机抽取的:

for i in range(n_words):
    chain.append(np.random.choice(word_dict[chain[-1]]))

最后一个join命令以字符串形式返回链:

' '.join(chain)

当我运行这段代码时,我的第一个结果是:

我将能够投票。找回来了。我们要编造一个彻头彻尾的谎言,然后被证明。“期间正好相反。我们有一些出席者。我的病人真的

这里好的一点是,我们使用字典实际上是在链中查找下一个单词。当然,您可以将所有这些都打包到一个函数中,我将它作为一个练习留给读者。

有很多工具可以用来发'马克维奇'短信,我鼓励你去查一下。但是对于刚刚学习马尔可夫链的人来说,这里的代码是一个容易的起点。但是改进的可能性是无限的。例如,您可能要求第一个单词大写,这样您的文本就不会从句子中间开始:

while first_word.islower():
    first_word = np.random.choice(corpus)

我希望这有助于你们开始进入马尔可夫链的广阔世界。如果这段代码可以在不牺牲清晰度的情况下得到改进,请留下评论!

模拟 2018 年世界大赛

原文:https://towardsdatascience.com/simulating-the-2018-world-series-45bc16e3aa27?source=collection_archive---------14-----------------------

美国职业棒球大联盟赛季的一个有趣的部分是,162 场比赛的艰苦努力在季后赛中变成了 5 或 7 场赢家通吃的系列赛。每个系列只播放一次,这允许随机性进入方程。更好的团队并不总是赢。

如果我们真的可以多次播放这个系列并找到最有可能的结果呢?这是模拟背后的基本思想:向方程或模型提供输入,多次重复该模型,然后找到与期望结果匹配的出现次数。

棒球模拟可以非常复杂和精细,甚至可以是针对投手、棒球场和其他因素调整的逐个击球手的模拟。这种细节水平令人钦佩,但我决定采取一种新的,不同的方法来模拟。

相反,我会看击球手(得分)和投手(允许得分)对一个球队的对手和其他类似对手的球队的比赛表现,以模拟得分和系列赛获胜者。

所有项目代码都在我的 GitHub 上。

数据

这个项目的数据包括投球和击球的年度团队统计数据,这是我为之前的项目预测季后赛球队收集的。这些数据将允许我们将一个球队的统计数据与他们联盟中的其他球队进行比较。数据示例如下:

Sample of the batting data used

Sample of the pitching data used

除了年度统计数据,该项目还需要每个团队 2018 年的逐场比赛结果。同样,baseball-reference.com 是一个有用的资源,因为我们可以导航到一支球队的 2018 年赛程,并收集所需的数据,如主队和客队以及对手的得分。

流程

这个模拟的基本假设是我们可以

  1. 在他们的联盟(美国或国家)中找到一个球队最相似的击球和投球“邻居”(即每个类别中季末统计数据最相似的球队)。然后,我们可以看到一个球队在常规赛中分别与对手加上对手的“邻居”在击球和投球方面的表现。
  2. 利用与类似对手比赛的结果,我们可以在常规赛中创建得分(击球手)和允许得分(投手)的分布。然后,我们将通过从得分分布中随机抽取每个队的得分来“模拟”一场击球比赛。我们将通过从允许得分分布中随机抽取每个队的允许得分值来单独“模拟”一场投球比赛。比赛的获胜者是得分值(击球)或允许得分值(投球)较高的一方。
  3. 接下来,我们通过使用第(2)点中描述的方法继续模拟游戏来模拟系列赛,直到其中一个团队达到 3 胜(5 场系列赛)或 4 胜(7 场系列赛)。
  4. 对击球手重复系列模拟过程 20,000 次,对投手重复 20,000 次,总共 40,000 次模拟。
  5. 计算一个队赢得系列赛的百分比;这表示从模型中预测的该队将赢得系列赛的总概率(> 50% =系列赛获胜者)。

实际上,我们想知道一个队的击球手和投球人员在与另一个队“相似”的对手比赛时表现如何(例如,一个队的击球手与对手相似的投球人员比赛时表现如何,以及一个队的投球人员与对手相似的击球手比赛时表现如何),并使用这些信息来模拟比赛。

我们可以在已经完成的季后赛系列赛中测试这一过程,以提供对其准确性的早期看法,并模拟世界大赛的获胜者。

让我们以红袜队对洋基队系列赛为例,逐一介绍每一个步骤:

The function to simulate the batting outcome is the code on the left; the pitching function can be found in the linked code on GitHub.

类似团队表现

虽然季后赛棒球不同于常规赛棒球,我们可以假设一支球队在常规赛中的表现与他们在季后赛中的表现相似。因此,如果我们能发现一支球队如何对抗对手,以及与对手相似的其他球队,我们就能为他们的季后赛表现找到一个合理的代理。这一概念是以下段落中提出的建模的关键。

我们将如何定义相似性?

为了计算相似性,我们可以用一个最近邻模型来拟合我们的击球和投球数据集。无监督机器学习算法计算点之间的距离,并返回最接近输入值的点。

# Example: Find the closest 5 neighbors to the Yankeesneighbors = NearestNeighbors(n_neighbors = 5)neighbors.fit(df)# Find the distance from the Yankees on our fitted data frame and index values 
distance, idx = neighbors.kneighbors(df[df.index == 'NYY'], n_neighbors=5)

因为我们的目标是进行足够多的比赛,我将邻居限制在对手球队联盟中最相似的 5 支球队(加上对手)。这意味着对于扬基队和红袜队,我们将寻找美国联盟中最常见的五支球队。

如果我们要扩展到美国和国家联盟,洋基队最相似的邻居都是红袜队没有打过的国家联盟球队,这不会帮助我们创建我们的分布。因此,为了更高的样本,我们牺牲了一些潜在的更好的相似性邻居。

使用邻居,我们可以看到扬基队击球手在面对类似红袜队投手的比赛中的表现(例如,他们通常得分多少分?)以及洋基队的投手面对类似红袜队打者的球队表现如何(例如,他们通常允许多少分?).

# Note how we ensure that the opponent is in the opposite category (i.e. batting performance is against the other team's pitching neighbors).nyy_batting_performance = df_nyy[df_nyy.opponent.isin(bos_pitching_neighbors.index)]nyy_pitching_performance = df_nyy[df_nyy.opponent.isin(bos_batting_neighbors.index)]

这产生了一个洋基队对红袜队的表现的数据框架,以及五支以与他们的投手战果最相似的结果结束的球队:

A sample of the Yankees performance in games against teams similar to the Red Sox pitching staff

模拟游戏

这个过程的最重要部分是第一步,而剩下的大部分可以通过一系列的if语句和for循环来完成。

对于一个游戏模拟,我们只是从每个队的击球数据帧中随机选择一个值,然后比较结果,得分高的就是赢家。同样,对于投手,我们遵循同样的过程,但放弃最少得分的队是赢家。

下面的代码提供了一个游戏模拟,确保两个分数永远不会相同:

## Draw a random number from the distribution of runs in games against similar opponentsteam1_score = np.random.choice(runs_for_team1)
team2_score = np.random.choice(runs_for_team2)## Repeat simulations until the score is not the same while team1_score == team2_score:

    team1_score = np.random.choice(runs_for_team1)
    team2_score = np.random.choice(runs_for_team2)## If team 1’s score is higher, that team wins. Otherwise, team 2 is credited with the win. if team1_score > team2_score:

    team1_wins += 1

elif team2_score > team1_score:

    team2_wins += 1

模拟连续剧

在上一部分的基础上,我们可以通过重复这个过程来模拟五到七场比赛,直到一支队伍达到我们期望的获胜场次:

## Start each team with 0 winsteam1_wins = 0
team2_wins = 0## Once one of the teams reaches the desired number of games to win, we append either a 1 (if team  1 wins) otherwise a 0 (indicating team 2 wins)if (team1_wins == num_games_to_win) | (team2_wins == num_games_to_win):

    winner.append([1 if team1_wins == num_games_to_win else 0])
    total_games.append(team1_wins + team2_wins)

    ## Stop the simulation and start fresh once we have a winner break

到目前为止,这个过程代表一个单一系列的模拟。

重复该过程并计算百分比

如前所述,单个游戏或系列引入了随机性,但这种随机性最终应该成为一个重复互动的有凝聚力的故事。

出于这个原因,我们将重复这个过程数千次——在这个例子中是 20,000 次,包括投球和击球——并计算一个队赢得模拟系列赛的百分比。然后这个数字就变成了我们的球队赢得系列赛的概率,超过 50%的是我们预测的球队。

管用吗?

这个过程是符合逻辑的,但是它有效吗?要全面评估这个模型的能力,需要大量的回溯测试,几十年的数据是最有帮助的。为了这篇文章,我在 2018 年季后赛结果上进行了测试,以提供示例输出。

到目前为止,运行该系列的算法,包括通配符游戏,导致 8 个正确预测中的 6 个。假设猜对的几率为 50/50,对于 2018 年的季后赛,我们能够将选出赢家的几率提高 25 个百分点。当然,这样一个小样本并不重要,但是值得注意。

唯一不正确的预测是与红袜队的两场系列赛——相当讽刺,因为他们现在在世界系列赛中。

Probability of each team winning the series and accuracy of predictions

2018 世界大赛预测

那么,谁会赢得世界大赛呢?该模型预测道奇队,并对 67%的预测率相当有信心,但前两次押注红袜队不会产生很好的结果。

和任何概率一样,它只是说,根据模型,道奇队赢的可能性更大,而不是说他们每次都会赢。

结论和后续步骤

概率可以是一种有趣的方式来处理一个静态的、一次性的事件,同时理解结果并不完全可行。洋基队不能赢得 52%的系列赛,但我们可以看到谁可能在一场比赛或系列赛中有优势。

有几种方法可以继续这个项目:

  • 回测!这个数据只代表了季后赛的一小部分。代码以这样一种方式设置,即运行抓取算法可以在任何赛季、任何年份和任何球队中进行,然后可以用这些球队调用这些函数。
  • 说到函数,我认为它们可以被进一步压缩以简化运行它们的调用。我很想听听任何人对建议的反馈,以尽量减少运行每个模拟所需的呼叫次数。
  • 引入额外的统计数据可能会进一步提高准确性。当计算相似性时,我把自己限制在棒球参考上,但这并不意味着这是唯一或最好的数据。

这些只是一些建议,如果有人有兴趣从这里拿起火炬。

在体育运动中,总会有随机因素、人为干预和纯粹的运气。最终,数据和模拟永远不会 100%准确地告诉我们谁是赢家,也不会复制坐下来观看比赛的兴奋感,但当我们将数据纳入画面时,我们可以通过不同的视角来看待比赛和比赛,这也可以提供有趣的见解。

如果您有任何问题或反馈,我很乐意收到您的来信!在 jordan@jordanbean.com 给我发邮件或者通过 LinkedIn 联系我。

模拟器:应用深度强化学习的关键训练环境

原文:https://towardsdatascience.com/simulators-the-key-training-environment-for-applied-deep-reinforcement-learning-9a54353f494f?source=collection_archive---------6-----------------------

深度强化学习(DRL)是目前人工智能中最令人兴奋的领域之一。现在还为时尚早,但这种技术可以应用于明显且服务不足的市场:希望自动化或优化工业系统和流程效率的企业(包括制造、能源、HVAC、机器人和供应链系统)。

但是建立应用 DRL 有一个关键因素:模拟环境。在这篇博客中,我们将告诉你模拟器可以做什么,你为什么需要它们,以及你如何使用 Bonsai 平台+模拟器来解决实际的业务问题。

什么是模拟?

让我们从定义术语“T2 模拟”开始,因为这是一个相当抽象的概念。模拟的范围从飞行模拟器到电子和机械部件或整个城市模型的模拟。

模拟 是对现实世界过程或系统随时间的运行的模仿

本质上,存在某种系统,该系统具有许多输入,将一些数学函数应用于这些输入,并以可视数据(如机器人模拟器)或纯数据(如能量模拟器, EnergyPlus )的形式传回输出。

计算机科学家使用模拟已经有一段时间了,可以追溯到 20 世纪 50 年代末。在过去的 20 年里,不断增长的计算能力和大量的数据使得模拟的逼真度和价值都有了显著的提高。许多领先的工业模拟几乎完全符合物理现实或业务流程。

一个巨大的影响是数字游戏产业的发展。游戏玩家希望获得更加身临其境的体验,需要高保真的图形和虚拟世界中更真实的物品行为。在过去的 30 年里,游戏中间件公司开发并交付了强大的 3D 和 2D 物理引擎。

工业模拟

通过利用这些软件产品和各种数学库,企业能够模拟具有大量组件的复杂系统,允许主题专家(SME)在真实世界中构建系统之前测试和评估系统。用例包括数字双胞胎、机器人、调整小型和大型工业机器、多种电气和物理系统,以及优化供应链等业务流程。

虽然存在大量基于单个模型的定制和非常专业的模拟,但是也存在许多能够运行和模拟基本上无限数量的模型的模拟器平台。例子有 MATLAB Simulink (工程和制造) ANSYS (工程) AnyLogic (供应链) Gazebo (机器人) TRNSYS (能源),等等。

模拟+深度强化学习

强化学习(RL)被定义为:

“一个领域的 机器学习 关心的是如何让 软件代理 应当采取 行动 在一个环境中获得最大化的累积报酬”

换句话说,RL 训练智能体通过在给定环境中尝试大量动作来学习如何行动的策略,优化定义的奖励函数。

深度强化学习(DRL)遵循相同的方法,使用深度神经网络来表示策略。

强化学习需要大量的“反复试验”——或与环境的互动——来学习一个好的政策。因此,模拟器需要以一种经济有效且及时的方式获得结果。

想象一下,试图教一个机器人走路,通过观察一个真实的,物理的机器人尝试和跌倒 100,000 次,然后才能成功和持续地行走。或者训练一个人工智能玩围棋,实际上是和一个人类对手玩几十万局。模拟器允许这些情节在数字世界中发生,训练人工智能发挥其全部潜力,同时节省时间和金钱。

一些模拟对环境进行建模,其中代理可以采取连续的动作来影响环境的状态;其他模拟模型设置,其中离散输入产生不同的输出。这两种类型的模拟都可以用于强化学习。

模拟+深度强化学习+盆景

Bonsai 是一个人工智能平台,允许企业将控制编程到工业系统中,也是唯一一个使用深度强化学习对工业系统进行编程控制的商业产品。

使用 Bonsai 平台,企业可以建立一个大脑(一个 ai 模型),连接他们选择的模拟器,并在那个环境中训练大脑学习一个期望的行为。

要了解更多关于构建模拟并将 DRL 应用于您的企业的信息,请访问我们的入门页面。

用文本挖掘唱歌

原文:https://towardsdatascience.com/sing-song-with-text-mining-cd8508ab51a5?source=collection_archive---------8-----------------------

文本分析应用于许多领域,目标是发现隐藏在文本中的相关信息。自然语言处理(NLP)是一种用于文本挖掘的方法。它试图通过标记化、聚类、提取关系和使用算法识别主题来解码书面语言中的歧义。自然语言处理是人工智能的一个分支,代表着人类和计算机之间的桥梁;它可以广义地定义为通过软件对自然语言(如语音和文本)的自动操作。对于这份工作,我使用了这些参考资料:
https://www . ka ggle . com/devisangeetha/sing-a-song-lyrics-is-here/
https://www . data camp . com/community/tutorials/R-NLP-machine-learning
https://www.kaggle.com/rtatman/nlp-in-r-topic-modelling
https://www.tidytextmining.com/

探索性数据分析

每位艺人的歌曲数

song_grp<-lyrics %>%group_by(artist)%>%summarise(song_cnt=unique(length(song)))%>%arrange(desc(song_cnt))
song_grp[1:10,] %>%
  ungroup(artist, song_cnt) %>%
  mutate(song_cnt = color_bar("lightblue")(song_cnt)) %>%
  mutate(artist = color_tile("green","green")(artist)) %>%
  kable("html", escape = FALSE, align = "c", caption = "Artist With Highest song Count") %>%
  kable_styling(bootstrap_options = 
                  c("striped", "condensed", "bordered"), 
                full_width = FALSE)

标记化

已加载 tidytext 库使用 unnest_tokens()函数开始标记化。这个函数至少需要两个参数:输出列名(即 word)和输入列名(即 text)。获取歌词数据集并将其传输到 unnest_tokens()中,然后删除停用词。它们是过于常见的词,可能不会给我们的结果增加任何意义。有不同的列表可供选择,但在这里我使用了 tidytext 包中名为 stop_words 的词典。将歌词标记成单词后,我使用 anti_join()删除了停用的单词,然后使用 distinct()删除了任何重复的记录。最后,我删除了所有少于四个字符的单词,因为在歌词中这些通常是感叹词。

lyrics_filtered <- lyrics %>%
  unnest_tokens(word, text) %>%
  anti_join(stop_words) %>%
  distinct() %>%
  filter(nchar(word) > 3)
head(lyrics_filtered)##   artist                  song      word
## 1   ABBA Ahe's My Kind Of Girl wonderful
## 2   ABBA Ahe's My Kind Of Girl     means
## 3   ABBA Ahe's My Kind Of Girl   special
## 4   ABBA Ahe's My Kind Of Girl    smiles
## 5   ABBA Ahe's My Kind Of Girl     lucky
## 6   ABBA Ahe's My Kind Of Girl    fellow

字频率

在音乐中,无论是重复还是罕见,单个词频都有很大的重要性。两者都会影响整首歌本身的可记忆性。歌曲作者可能想知道的一个问题是词频和热门歌曲之间是否有关联。所以我总结了每首歌的字数,为了简单评估,我还总结了所有数据集中最常用的词。

full_word_count <- lyrics %>%
  unnest_tokens(word, text) %>%
  group_by(song) %>%
  summarise(num_words = n()) %>%
  arrange(desc(num_words)) full_word_count[1:10,] %>%
  ungroup(num_words, song) %>%
  mutate(num_words = color_bar("lightblue")(num_words)) %>%
  mutate(song = color_tile("green","green")(song)) %>%
  kable("html", escape = FALSE, align = "c", caption = "Songs With Highest Word Count") %>%
  kable_styling(bootstrap_options = 
                  c("striped", "condensed", "bordered"), 
                full_width = FALSE)

每首歌字数最多的艺人

lyrics_filtered %>% 
  filter(word == "angel") %>%
  select(word, song, artist) %>%
  arrange() %>%
  top_n(10,song) %>%
  mutate(song = color_tile("lightblue","lightblue")(song)) %>%
  mutate(word = color_tile("green","green")(word)) %>%
  kable("html", escape = FALSE, align = "c", caption = "angel word per song and artist") %>%
  kable_styling(bootstrap_options = 
                  c("striped", "condensed", "bordered"), 
                full_width = FALSE)

顶字

lyrics_filtered %>%
  count(word, sort = TRUE) %>%
  top_n(10) %>%
  ungroup() %>%
  mutate(word = reorder(word, n)) %>%
  ggplot() +
  geom_col(aes(word, n), fill = "blue") +
  theme(legend.position = "none", 
        plot.title = element_text(hjust = 0.5),
        panel.grid.major = element_blank()) +
  xlab("") + 
  ylab("Song Count") +
  ggtitle("Most Frequently Used Words in Lyrics") +
  coord_flip()

文字云

相关性:找出艺术家“U2”创作的歌曲中单词之间的相关性

对于变量之间的比较或按行分组,整齐的数据是一种有用的结构,但在行之间进行比较可能具有挑战性。大多数寻找成对计数或相关性的操作需要首先将数据转换成宽矩阵。widyr 包使得诸如计算计数和相关性之类的操作变得简单。一个有用的函数是 pairwise_count()函数。前缀 pairwise_ 意味着它将为单词变量中的每一对单词生成一行。输入中每对文档和单词对应一行,而输出中每对单词对应一行。这也是一个整齐的格式。目标是检查单词之间的相关性,这表明它们一起出现的频率相对于它们单独出现的频率。重点是 phi 系数,这是衡量二进制相关性的常用指标。这相当于皮尔逊关联,单词 X 和 Y 要么都出现,要么都不出现,而不是一个出现另一个。widyr 中的 pairwise_cor()函数让我们可以根据单词在同一部分出现的频率来找到单词之间的 phi 系数。它的语法类似于 pairwise_count()。它使用 ggraph 来可视化二元模型:可视化 widyr 包找到的词的相关性和簇。

set.seed(12345)
word_corr %>%
  filter(correlation > .75) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "kk") +
  geom_edge_link(aes(edge_alpha = correlation), show.legend = FALSE) +
  geom_node_point(color = "blue", size = 5) +
  geom_node_text(aes(label = name), repel = TRUE) +
  theme_void()

基于 LDA 的无监督学习

主题建模是一种对这种文档进行无监督分类的方法,类似于对数字数据进行聚类,这种方法可以找到自然的项目组。潜在狄利克雷分配(LDA)是一种特别流行的拟合主题模型的方法。它将每个文档视为主题的混合,并将每个主题视为单词的混合。潜在狄利克雷分配是主题建模最常用的算法之一。每个文档都是主题的混合体。我们设想每个文档可能包含来自几个主题的特定比例的单词。每个话题都是单词的混合。LDA 是一种数学方法,用于同时估计这两者:找到与每个主题相关联的词的混合,同时还确定描述每个文档的主题的混合。我使用了 topicmodels 包中的 LDA()函数,设置 k = 5,创建了一个五主题 LDA 模型。该函数返回一个包含模型拟合的全部细节的对象,例如单词如何与主题相关联,以及主题如何与文档相关联。

对数据集进行子采样

数据集很大,处理整个数据集需要更多的计算时间,所以最好用子样本来处理它。

set.seed(1234) 
row_indexes <- sample(1:nrow(lyrics), 1600, replace = F) 
texts_subsample <-slice(lyrics, row_indexes)

创建文档术语矩阵进行清洗,将术语矩阵转换成 tidytext 语料库,去除停用词并应用 LDA

在第二种方法中,我以前使用过 tm 包来应用 LDA。

开始创建文档术语矩阵:以文档为行,术语为列,以词的频率计数为矩阵单元的矩阵。使用 tidyr 包中的 tidy 函数,我可以将文档术语矩阵转换为 tidytext 语料库,变量在列中,每个观察值在一行中,频率词在单元格中。通过这种方式,我已经准备好清除文本中的停用词,并应用 LDA 建模。

LDA 输出能够给出:

  1. 估计每个主题对每个文档的贡献
  2. 估计每个单词对每个主题的贡献

第二个对于大文档很有帮助。

viewsCorpus <- Corpus(VectorSource(texts_subsample$text)) 
viewsDTM <- DocumentTermMatrix(viewsCorpus)
viewsDTM_tidy <- tidy(viewsDTM)
viewsDTM_tidy_cleaned <- viewsDTM_tidy %>% 
  anti_join(stop_words, by = c("term" = "word")) %>%
  filter(nchar(term) > 3)
top_terms_by_topic_LDA <- **function**(input_text, 
                                   plot = T, 
                                   number_of_topics = 5) 
{    
  Corpus <- Corpus(VectorSource(input_text))
  DTM <- DocumentTermMatrix(Corpus) 
  unique_indexes <- unique(DTM$i) 
  DTM <- DTM[unique_indexes,] 
  lda <- LDA(DTM, k = number_of_topics, control = list(seed = 1234))
  topics <- tidy(lda, matrix = "beta") 
  top_terms <- topics  %>% 
    group_by(topic) %>% 
    top_n(10, beta) %>%
    ungroup() %>% 
    arrange(topic, -beta) 
  **if**(plot == T){
    top_terms %>% 
      mutate(term = reorder(term, beta)) %>% 
      ggplot(aes(term, beta, fill = factor(topic))) + 
      geom_col(show.legend = FALSE) + 
      facet_wrap(~ topic, scales = "free") + 
      labs(x = NULL, y = "Beta") + 
      coord_flip() 
  }**else**{ 
    **return**(top_terms)
  }
}
top_terms_by_topic_LDA(viewsDTM_tidy_cleaned$term, number_of_topics = 5)

我选择了五个主题来列出前十个单词,可能两个就足够了,因为它们非常相似。

词干

词干是用来去掉单词中所有的词尾变化,例如,“钓鱼、“、“渔夫”可以简化为“

viewsDTM_tidy_cleaned <- viewsDTM_tidy_cleaned %>% 
  mutate(stem = wordStem(term))
top_terms_by_topic_LDA(viewsDTM_tidy_cleaned$stem, number_of_topics=5)

仓库代码在rpubs.com

新加坡 HDB 转售单位价格

原文:https://towardsdatascience.com/singapore-hdb-resale-flat-prices-c4d8567c21e9?source=collection_archive---------5-----------------------

Image via PixaBay

在新加坡,大多数人通常会选择由 HDB 住房发展局建造的公共住房作为他们的第一个家。这些房屋通常被称为 HDB 公寓,可以在新建时直接从 HDB 购买,也可以在公开市场上从其他 HDB 房主那里购买(以下称为转售公寓)。

虽然我对如何在不久的将来买房子保持开放的选择,但我决定四处看看,了解转售公寓的市场价格。我很高兴偶然发现了一个关于 data.gov.sg 的相当全面的数据集,它列出了从 1990 年到 2018 年出售的转售公寓的细节。以下概述了我从数据中发现的一些见解

在这里,你可以随意访问底层的可视化

目前的转售单位价格比过去要低

在这篇文章中,我的分析基于四居室公寓的价格,原因如下

  • 根据数据,它们是最常购买的公寓之一,也是大多数城镇和地区最常见的公寓类型之一
  • 四居室公寓在面积和价格方面处于所有可供选择的中间位置,因此我相信它不太容易成为异类

Median Price of 4-Room Resale Flat Over Time

这张图表显示了从 1990 年到 2017 年,四居室公寓的转售价格中位数是如何增长的。我们可以立即看到转售价格在 1997 年首次见顶,之后由于亚洲金融危机,价格开始下降。从 2004 年开始,价格再次开始逐渐上涨,并在 2013 年创下新高,然后再次下降。这一下降与同年实施的几项冷却措施相一致,如 TDSR 框架和调整 ABSD。你可以在这里阅读更多的和这里

到 2017 年,一套四居室公寓的转售价格中位数比 2013 年低 11%。

便利很重要

我们知道转售单位的价格在很大程度上取决于它的位置。便利也是主观的,因为它涉及到一所房子离最近的捷运站有多远,或者那个捷运站离市区或个人的工作场所有多远。我们可以尝试从谷歌地图 API中获取一些信息。

在尝试了几个 API 之后,我决定使用莱佛士广场捷运作为市区的代理。使用 Google Maps APIs,我查询了从 Raffles Place MRT 到数据中与每个转售公寓单元相关的地址所需的旅行时间。我决定这样做的原因将在后面的文章中解释。

Travelling Duration vs Median Resale Price for a 4-Room Resale Flat

HDB 将数据中的每个地址归入一个城镇,这应该是大多数新加坡人都熟悉的。在图表中,在中心区(由 Marina、Outram、Newton 和其他几个地方组成)的一套四居室公寓,到莱佛士广场地铁站的平均旅行时间不到 20 分钟,平均转售价格为 80 万美元。当我们观察到去莱佛士广场地铁站的旅行时间较长的城镇时,这种情况会减少。在森巴旺,同样一套四居室公寓的价格不到这个价格的一半,而且租期可能也更长。

不同城镇的价格上涨(或下跌)速度不同

我们在第一张图表中看到,价格从 1997 年开始上涨,从 2013 年开始下降。让我们来看另一个视图,在这个视图中,我们可以看到不同城镇的价格是如何变化的。

Price Change from 1997 to 2017 for 4-Room Resale Flat

Price Change from 2013 to 2017 for 4-Room Resale Flat

这两个图表显示了价格从 1) 1997 年到 2017 年,2) 2013 年到 2017 年的变化。虽然从 1997 年到 2013 年,所有城镇的价格普遍上涨,但位于中心位置的房屋价格涨幅更大,中心地区的房屋价格上涨了一倍,而 Pasir Ris 的涨幅为 15%。

2013 年至 2017 年的图表也显示了一个有趣的模式。虽然大多数地方的价格下降,但中心地区的价格在四年内上涨了 44%!

结论

在这篇文章中,我们可以看到,尽管转售价格自 20 世纪 90 年代以来普遍上涨,并在 2013 年实施降温措施后略有下降,但价格升值并不是全面的。这项工作还帮助我估算出在我感兴趣的地区买一套转售公寓应该付多少钱。我希望这将是有用的信息给你,如果你正在考虑得到一个转售单位!

笔记

为什么使用从家庭住址到莱佛士广场捷运的旅行时长

  1. 莱佛士广场捷运是新加坡主要的捷运交汇处之一,位于新加坡市中心。因此,这是一个我认为适合用来确定一个房子有多中心的代理
  2. 虽然一个人可能认为在三巴旺的房子如果离他工作的地方 5 分钟路程就很方便,但我相信转售单位价格将在很大程度上受到大多数人如何看待三巴旺便利的影响
  3. 只需将莱佛士广场地铁站和住宅位置作为谷歌地图应用编程接口的输入,该应用编程接口将帮助我确定从住宅到莱佛士广场的最佳路线。这将是一个足够好的代理人的最佳路线,一个人可能会采取前往莱佛士广场捷运

Pharo 中的单层感知器

原文:https://towardsdatascience.com/single-layer-perceptron-in-pharo-5b13246a041d?source=collection_archive---------2-----------------------

面向对象的神经网络方法

在这篇文章中,我将描述我在 Pharo 中实现的单层感知器。它将支持多类分类(一个或多个神经元)。每个神经元将被实现为一个对象。这个项目的代码可以从 Smalltalkhub 使用这个 Metacello 脚本获得(在你的 Pharo 图像的操场上做):

Metacello new 
repository: '[http://smalltalkhub.com/mc/Oleks/NeuralNetwork/main'](http://smalltalkhub.com/mc/Oleks/NeuralNetwork/main');
configuration: 'MLNeuralNetwork';
version: #development;
load.

我将从说明设计问题和实现这个项目每个部分的不同方法开始。这将是相当长的,所以这是我的最终设计:

什么是感知器?

首先,我们需要定义一个感知器。它是人工神经网络的最基本形式,然而,大多数人无法清楚地定义它实际上是什么。

现在,我将感知器称为遵循感知器学习过程的人工神经网络。

这个定义暗示了对感知机是什么以及它们能做什么的一些限制。

感知器的限制

  • 它们只能收敛于线性可分的输入(参见 XOR 问题,Minski & Pappet)。但是,如果输入是线性可分的,那么无论初始权重和学习速率如何,感知器都保证收敛于此(参见 1962 年由 Block 和 Novikoff 证明的感知器收敛定理)
  • 感知器(如上定义)只能有一层神经元。事情是这样的(Geoffrey Hinton 的机器学习神经网络课程的第 3 周),感知器学习程序只能应用于单层神经元。隐藏层中的神经元需要某种反馈来计算它们的误差并更新权重。这就是为什么我们需要一个不同的学习算法(例如,反向传播,将在下一阶段实现)。
  • 感知器只能在线学习(一次一个例子)。这是因为感知器学习是基于将输入向量与基于二进制分类器误差(该误差可以是-1、0 或 1)的权重相加(或相减)。

设计问题

如何表示权重

当谈到神经网络的面向对象实现时,这可能是必须回答的最重要的问题。权重应该属于神经元吗?如果是,应该是发送还是接收神经元?或者也许他们应该属于一层?或者也许是整个网络?也许我们甚至应该将它们作为单独的对象来实现?

作为只有一层的前馈网络,因此没有连接两个神经元的权重,单层感知器简化了这个问题。基本上,我们有三个选择:

  1. 每个神经元的输入权重作为向量存储在该神经元内。
  2. 所有输入权重的矩阵存储在网络中。
  3. 权重被实现为对象并连接到神经元。

第二种选择是最有效的(向量矩阵乘法),但不是非常面向对象。这个实现中的神经元是什么?显然,网络只是一个权重矩阵+一些学习规则。神经元应该是具有学习率的激活函数吗?但是话说回来,将它们存储在网络中会更有效率。所以基本上我们不需要Neuron类。我们只需要一个矩阵和几个操作它的函数。对我来说这听起来不像面向对象。

在这种情况下,第三种选择是过度设计。这只会让整个事情变得更复杂。在多层神经网络中,将权重实现为对象可能会有一些意义,其中每个权重是两个神经元之间的连接(我们可以将输入视为假神经元)。它连接两个神经元,在它们之间发送信号,并且具有可以更新的“强度”。结果,神经元不知道其他神经元。它们只是接收、处理和发射信号。我假设这样的实现不会很快,但是它可以用于建模目的。我将在一篇关于多层网络的文章中详细阐述这个想法。

第一个选项看起来最适合单层感知器。而且非常容易实现,所以我会坚持下去。

激活功能

在这个项目中有两种表示激活函数的方式:

  1. 将它们实现为方法
  2. 将它们实现为类

第一种方法速度更快,占用的内存更少。我们用抽象方法activationactivationDerivative创建了一个基类神经元。每个子类将是一种特殊类型的神经元,如BinaryThresholdNeuronSigmoidNeuron,实现相应的激活功能。

实现激活的另一种方式是用两个抽象方法value:derivative:创建一个基类ActivationFunction。这种方法更加灵活,因为如果有人想使用一个新的激活函数,他将能够将其实现为一个子类,只需定义它是什么以及它的派生函数是什么。然后,他将能够将这类对象传递给现有的神经元。每当我们需要创建一个函数时,重新实现整个神经元似乎是不符合逻辑的。

所以真正的问题可以听起来像这样(当然,它可能听起来更好):
神经元是由它们的激活来定义的吗?具有不同的激活是否意味着是完全不同类型的神经元?

共享或单独激活和学习率?

激活率和学习率既可以由感知器的所有神经元共享,也可以分别存储在每个神经元中。问题是:我们需要有不同激活和不同学习率的神经元吗?

让我们假设我们没有。事实上,在大多数情况下,一个网络(或一层)的所有神经元都具有相同的学习速率和相同的激活。如果网络有许多神经元(大多数网络都有),那么我们将存储同样多的次数。如果激活函数被实现为一个类,那么我们将为每个神经元创建一个单独的类实例。

然而,如果我们想要并行化由神经元完成的计算,那么对每个神经元(或每个神经元块)具有单独的学习速率和单独的激活会更好。否则,它们会在每一步都互相阻止对方访问共享内存。此外,这个“重”神经元占据的总内存仍然很小。我认为,这样的神经元(或一组神经元)将很容易放入 GPU 单核的本地存储器中。

但是单层感知器通常不会执行繁重的计算。它们对于建模更有用。这就是为什么我们可能应该采取“分离”的方法,允许用户用完全不同的神经元(像积木一样)构建一个网络。

顺便说一下,对于多层网络来说,一个好主意是在一层中共享相同的激活和学习速率,但是允许用户拥有完全不同的层。最后,他应该可以建立一些复杂的网络,比如图片上的卷积网络。但这不是这篇文章的主题。

数据洗牌

在线感知器对接收训练样本的顺序很敏感。在每个训练示例之后进行权重更新,这就是为什么训练向量#(#(0 1) #(1 1))#(#(1 1) #(0 1))会产生不同的权重向量。根据示例的顺序,感知器可能需要不同次数的迭代才能收敛。

这就是为什么,为了测试这种学习的复杂性,感知机必须通过从训练集中随机选择的例子来训练。

履行

综上所述,这是我设计的单层 peceptron:

神经元类

Object subclass: #Neuron
   instanceVariableNames: 'weights activation learningRate'
   classVariableNames: ''
   package: 'NeuralNetwork'

权重用范围[0,1]内的随机数初始化。我不确定这是否是一个好的范围,但在简单的例子中,它工作得很好。

BinaryThreshold是默认激活函数,默认学习率为 0.1。这些参数可以使用访问器activation:learningRate:进行更改。

initialize: inputSize
   "Creates a weight vector and initializes it with random values. Assigns default values to activation and learning rate" activation := BinaryThreshold new.
   learningRate := 0.1.

   weights := DhbVector new: (inputSize + 1).

   1 to: (inputSize + 1) do: [ :i |
      weights at: i put: (1 / (10 atRandom))].
   ^ self

我们还需要在每个输入向量前加上 1 作为偏差单位。

prependBiasToInput: inputVector
   “this method prepends 1 to input vector for a bias unit”

   ^ (#(1), inputVector) asDhbVector.

根据《数值方法》一书,每个函数都应该实现value:方法。我想强调的是,从数学的角度来看,神经元是一种功能。

虽然内部表示使用了 DhbVector,但我希望用户编写类似于perceptron value: #(1 0).的内容,而不是perceptron value: #(1 0) asDhbVector.

value: inputVector
   "Takes a vector of inputs and returns the output value"

   | inputDhbVector |
   inputDhbVector := self prependBiasToInput: inputVector.
   ^ activation value: (weights * inputDhbVector).

我们需要访问器来设置激活的学习速率。出于调试目的,我还为权重添加了一个简单的访问器。所有这些访问器都是琐碎的,所以我不会把代码放在这里。

当然,还有感知机学习规则。

learn: inputVector target: target
   "Applies the perceptron learning rule after looking at one training example"

   | input output error delta |
   output := self value: inputVector.
   error := target - output.

   input := self prependBiasToInput: inputVector.

   delta := learningRate * error * input * 
      (activation derivative: weights * input).

感知器类

单层感知器(根据我的设计)是神经元的容器。它唯一的实例变量是neurons数组。

Object subclass: #SLPerceptron
   instanceVariableNames: ‘neurons’
   classVariableNames: ‘’
   package: ‘NeuralNetwork’

为了创建一个SLPerceptron的实例,我们需要指定输入向量的大小和类的数量,这等于我们的感知器(多类分类)中神经元的数量。

initialize: inputSize classes: outputSize
   “Creates an array of neurons”
   neurons := Array new: outputSize.

   1 to: outputSize do: [ :i |
      neurons at: i put: (Neuron new initialize: inputSize). ]

单层感知器的输出是该层中每个神经元的标量输出向量。

value: input
   “Returns the vector of outputs from each neuron”
   | outputVector |

   outputVector := Array new: (neurons size).

   1 to: (neurons size) do: [ :i |
      outputVector at: i put: ((neurons at: i) value: input) ].

   ^ outputVector

如果我们要求 SLPerceptron 学习,他会将那个请求传递给他所有的神经元(基本上,SLPerceptron 只是一个神经元的容器,提供了操纵它们的接口)。

learn: input target: output
   "Trains the network (perceptron) on one (in case of online learning) or multiple (in case of batch learning) input/output pairs" 1 to: (neurons size) do: [ :i |
     (neurons at: i) learn: input target: (output at: i) ].

测试

我用 BinaryThreshold 激活函数在 4 个线性可分的逻辑函数上测试了我的 SLPerceptron、OR、NAND 和 NOR,它收敛于所有这些函数。

下面是对 AND 函数的测试。其他 3 个看起来完全一样(只有预期输出值不同)。

testANDConvergence
   "tests if perceptron is able to classify linearly-separable data"
   "AND function" | perceptron inputs outputs k |
   perceptron := SLPerceptron new initialize: 2 classes: 1.
   perceptron activation: (BinaryThreshold new).

   "logical AND function"
   inputs := #(#(0 0) #(0 1) #(1 0) #(1 1)).
   outputs := #(#(0) #(0) #(0) #(1)).

   1 to: 100 do: [ :i |
      k := 4 atRandom.
      perceptron learn: (inputs at: k) target: (outputs at: k) ].

   1 to: 4 do: [ :i |
      self assert: (perceptron value: (inputs at: i)) equals: (outputs at: i) ].

而这个测试(或者更确切地说是一个演示)表明单层感知器无法学习 XOR 函数(不是线性可分的)。

testXORDivergence
   "single-layer perceptron should not be uneble to classify data that is not linearly-separable"
   "XOR function"

   | perceptron inputs outputs k notEqual |
   perceptron := SLPerceptron new initialize: 2 classes: 1.
   perceptron activation: (BinaryThreshold new).

   "logical XOR function"
   inputs := #(#(0 0) #(0 1) #(1 0) #(1 1)).
   outputs := #(#(0) #(1) #(1) #(0)).

   1 to: 100 do: [ :i |
      k := 4 atRandom.
      perceptron learn: (inputs at: k) target: (outputs at: k) ].

   notEqual := false.

   1 to: 4 do: [ :i |
      notEqual := notEqual or:
         ((perceptron value: (inputs at: i)) ~= (outputs at: i)) ].

   self assert: notEqual.

我也试图测试Sigmoid功能,但是测试失败了。这意味着要么感知器(如本文开头所定义的)不能将 sigmoid 作为其激活,要么我对如何用 sigmoid 实现感知器没有足够好的理解。

下一步是什么?

  • 具有批量学习和不同学习规则的单层神经网络的实现
  • 具有反向传播的多层神经网络的实现

R 中的奇异值分解及实例

原文:https://towardsdatascience.com/singular-value-decomposition-with-example-in-r-948c3111aa43?source=collection_archive---------7-----------------------

如果你熟悉矩阵和向量,那么理解什么是 SVD 不会花太多时间,但是,如果你不熟悉矩阵,我建议你先掌握它。

SVD 是这样一种方法,我们用矩阵的形式表示数据,然后我们减少它的列数以表示相同的信息。为什么数据不会丢失?有人可能会问。这个问题的答案是 SVD 的本质,我们将看看它是如何工作的。

基本上,SVD 做的是把一个矩阵分解成三个其他的矩阵,它们被称为 u,v 和 d。

1- A 是 m*n 元素的实矩阵。

2- U 是具有 m*m 个元素的正交矩阵

3- V 是具有 n*n 个元素的正交矩阵。

4- D 是具有 m*n 个元素的对角矩阵。

正交矩阵是这样一种矩阵,如果乘以其他数,它的性质不会改变。例如,如果你有一个矩阵“X ”,你用它乘以任何其他矩阵,得到矩阵“Y ”,然后如果你从“Y”中取出“S ”,那么你得到与“X”相同的矩阵,“S”只是一个标量值,叫做特征值。

X*λ = Y (1)

Y= S*X (2)

其中λ是 X 的倍数,S 是 y 的公倍数。

对角矩阵是指从上到下只有非零对角线数的矩阵。对角线以外的地方会有零。

为了更清楚,想象一下你在一个 3D 平面里拿着一支铅笔,现在如果你在铅笔的轴上乘以一个数,它会移动到 3D 平面的另一个地方,但是你的铅笔的长度仍然是一样的。

那么,我们知道 SVD 把矩阵分解成三个分量,那么它有什么用呢?用途是当我们把它们相乘时,我们得到的矩阵和之前的一样。但是请记住,我们不只是将它们相乘,而是使用这个公式——a = u * d * v^t,其中 t 表示矩阵 v 的转置

要记住的一件事是,你的对角矩阵 D 可能只给你一个对角线数的列表,然后你将不得不在非对角线的地方补零。此外,请记住,U 的列数将与 d 的行数相同。

但真正的问题是,这些对我们有什么帮助?让我们看看。

当我们将矩阵 A 分解成 U,D,V 时,所有三个矩阵中最左边的几列代表了我们恢复实际数据所需的几乎所有信息。请记住,我没有说全部,我说的是几乎全部,例如 92%的信息只存在于总列数的 5%的列中。考虑到您已经极大地减少了数据集的大小,这是一笔不错的交易。这意味着奇异值分解在矩阵 A 的所有列之间找到了某种联系,用较少的列表示相同的信息。现在,除了最左边的列之外的列被删除,因为它们被认为是错误的,并且该过程通过删除原始矩阵的几乎 90%的列来减小矩阵的大小。

现在让我们看看它在 r 中是如何工作的。请记住,在每一段代码之后,您都会看到输出以及对该输出的一个小解释。

**install.packages(“pixmap”,repos = “http://cran.us.r-project.org")library(pixmap)
 image<- read.pnm(“flower.ppm”)**image@size

[1] 300 400

str(image)

具有 8 个插槽的正式类“pixmapRGB”[包“pixmap”]

#..@ 红色 : num [1:300,1:400]0.894 0.878 0.851 0.816 0.8…

#..@ 绿色 : num [1:300,1:400]0.29 0.275 0.255 0.235 0.231…

#..@ 蓝色 : num [1:300,1:400]0.525 0.51 0.494 0.471 0.463…

#..@ channels: chr [1:3]"红色" "绿色" "蓝色"

..@ size : int [1:2] 300 400

..@ cellres : num [1:2] 1 1

..@ bbox:num[1:4]0 400 300

#..@ bbcent : logi FALSE

red.img <- matrix(image@red,nrow = image@size[1], ncol = image@size[2])

 blue.img <- matrix(image@blue,nrow = image@size[1], ncol = image@size[2])

 green.img <- matrix(image@green,nrow = image@size[1], ncol = image@size[2])

 str(red.img)

num [1:300,1:400] 0.894 0.878 0.851 0.816 0.8 …

我们看到在每种颜色矩阵中都有相同数量的行和列。

我们将它们分成三种颜色的原因是因为在 R 中,这三种颜色构成了 R 中每种颜色的基础。
但是在我们的例子中,我们将只使用红色,所有图像之间的差异可以在下面看到。

image(red.img)

Red matrix color

image(green.img)

Green matrix color

image(blue.img)

Blue Matrix color

plot(image)

Original Image

从上面给出的图片中,我取红色矩阵进行分解。

为了获得更清晰的图片,这里是红色矩阵的快照。记住,这个矩阵很快就会分解成三个分量。

View(red.img)

你会看到 R 中的“svd”命令会将红色矩阵分解成三个部分。它们是 d,u,v,给出了各自的行和列。

comp<- svd(red.img)
 str(comp)

# 3 的列表

# $ d:num[1:300]205.2 37.1 33.1 20.4 15.4…

# $ u:num[1:300,1:300]-0.0431-0.0427-0.0421-0.0419-0.0418…

# $ v:num[1:400,1:300]-0.0300

为了让下面的图片更清晰,我们也有他们每个人的快照。

View(comp$v)

v matrix

View(t(comp$d))

Transpose of v

现在,您可以看到“v”矩阵的行变成了转置矩阵中的列。

View(comp$d)

你看到它是一个列表并且一个列表不与一个矩阵相乘,所以我们需要在它与其他组件相乘时将其转换为对角矩阵。但是,让我们来感受一下使用“diag”命令后的效果。

d <- diag(comp$d)
 View(d)

matrix ‘d’ after imputing zeros

这是数字按对角线排列后的样子。这里需要注意的重要一点是,只有“d”中的几个起始列比其他列具有更大的权重,并且随着从左到右权重不断降低,因此我们只需要矩阵最左侧的那些列。让我们取其中的 25 个,它们可能代表了几乎 90%的信息。注意:我没有计算百分比,这只是一个假设。

现在,在我们将这些矩阵的前 25 列相乘之前,我们需要知道,“u”将保持不变,但“v”必须被转置,以便遵循矩阵法则。

compressed.image<- (comp$u[,1:25] %*% diag(comp$d[1:25]) %*% t(comp$v[,1:25]))

 image(compressed.image)

Final Image we Recovered

记住,左矩阵的列必须总是等于右矩阵的行。如果出现错误,请检查您的列和行。

看到这最后一个图像不像我们之前看到的那样清晰,但很明显它是一朵花的图像;但是我们已经减少了列的数量,因此与表示原始红色矩阵所需的空间相比,我们需要非常少的内存来显示该图像。

参考资料:

匿名。(2016)."什么是特征向量?"。雷奥索斯。【https://www.youtube.com/watch?v=ue3yoeZvt8E

无名氏。“奇异值分解”。RPUBS。https://rpubs.com/aaronsc32/singular-value-decomposition-r

怀特,J. (2009 年)。用 R 中的奇异值分解进行图像压缩。RBLOGGERS。https://www . r-bloggers . com/image-compression-with-the-SVD-in-r/

更快部署机器学习模型的六条规则

原文:https://towardsdatascience.com/six-rules-for-deploying-your-machine-learning-models-faster-b5b071a4a29e?source=collection_archive---------11-----------------------

数据科学和机器学习几乎可以改善组织的任何方面,但前提是你的想法得到应用。在过去的一年里,我们学到了很多关于更快地构建和部署机器学习模型的知识,我们希望分享一些我们在这里学到的东西。

“cheetah running on brown field” by Cara Fuller on Unsplash

形势

在我们的组织中,我们需要尽快从我们的分析投资中获得回报。我们需要更快地将机器学习模型部署到生产中。最重要的是,我们不希望伟大的想法变成分析用的架子,坐在那里等着被使用。

传统上,我们将每个数据产品都构建为定制的解决方案。每个定制解决方案之间很少重用。我们需要的是数据产品的装配线。

因此,我们建立了一个装配线,用于构建、测试和部署数据产品,我们称之为机器学习平台。有了它,我们现在可以在几分钟内将模型部署到生产环境中。我们不再需要等待很长时间才能享受到分析投资的回报。

我们一路走来学到了什么

一路上,我们学到了一些关于如何安全快速地构建、测试和部署机器学习模型的重要规则。这些规则改变了我们的工作方式,希望你会发现它们对你和你的组织有用。

  1. 拥抱自助服务

在我们的机器学习平台存在之前,由数据科学家创建的模型将被移交给 IT 部门,以便他们可以为每个模型创建数据管道和模型部署环境。一些模型甚至在部署前被改写成不同的语言。

我们构建了机器学习平台,为模型构建者提供自我部署通过内部模型治理流程批准的模型的能力。自助服务是加快速度的关键。

2。 使用容器从基础设施中提供抽象

容器提供了一种隔离和版本化模型的好方法。如果您的组织使用标准的服务器负载,您可能会发现很难在该标准服务器上安装您的依赖项和工件。集装箱解决了这个问题。可能是服务器管理员安装软件包的时间太长了。容器也可以解决这个问题。您可能需要在一段时间内托管同一模型的新版本和遗留版本,每一个版本都需要一组不同的依赖项。容器也有助于版本控制策略。

您的企业可能全是云,有些是云,或者没有云,但是即使您目前没有使用云,您也可能正在考虑使用云。集装箱非常便于携带。如果您采用基于容器的方法,您可以在本地或云中的任何地方运行这些模型。

3。 数据科学家需要关心代码质量。

让您的数据科学家能够自助地将模型部署到生产环境中,同时还要承担编写生产质量代码的责任。

这可能意味着你的模型构建团队必须升级他们的软件工程游戏。了解一点 Python 语法,调用一个 API,并不能让你成为一个好的软件工程师。当您构建一个组织将在生产系统中使用的软件时,软件质量至少与数据和模型质量同等重要。

这可能意味着采用像测试驱动开发和代码审查这样的实践。这可能意味着尝试结对编程。当你这么做的时候,你应该仔细考虑如何以及何时使用笔记本电脑,以及这对软件质量的影响。幸运的是,这些模式在软件工程界是众所周知的,并且非常适合大多数团队。

4。 如果不是自动化的,那就没有完成。

平台速度和稳定性都依赖于模型部署平台和过程的自动化。如果你想走得更快,在自动化的采用上不要妥协。

在我们的机器学习平台上,我们已经自动化了整个模型生命周期。持续集成和持续交付推动了平台上的模型测试和模型部署。

我们还自动化了底层平台基础设施的配置和部署。在此过程中,我们的团队学会了将这些自动化的虚拟机视为可处置的资源。没有人登录服务器进行管理,所有管理任务都是自动化的。这意味着无论我们向外扩展多少,每台服务器的配置都是一致的。我们不升级服务器,而是自动使用新的基础架构重新部署平台。

5。 搭建支持整个型号生命周期的平台。

到目前为止,我一直专注于构建、培训和部署,但这只是机器学习模型生命周期的第一部分。随着时间的推移,许多型号会出现漂移,性能下降。部署的模型需要监控和改装。每个部署的模型都应该记录所有的输入、输出和异常。模型部署平台需要提供日志存储和模型性能可视化。

在我们的机器学习平台上,每个模型都以一种通用的格式记录每次执行。每个托管模型应用程序都以一种通用的方式发出日志。我们路由并存储这些日志,使用它们来监控模型性能并帮助识别漂移。最后,我们会自动创建模型仪表板,以提供关于每个模型执行情况的更多信息。

密切关注模型性能是有效管理机器学习模型生命周期的关键。作为模型整个生命周期的一部分,你不能忽视模型监控。

6。 基于通用开发方法标准化

软件工程师已经提出了很好的方法和设计模式,我们可以用它们来构建可移植的、有弹性的应用程序。如果您的模型构建者了解这些方法,其中许多方法可以很容易地适用于机器学习应用程序。利用现有资源。

The Machine Learning Platform’s unofficial motto — #noShelfWare

获得结果

整合这六条规则帮助我们更快地获得结果,我希望它们也能帮助您的组织。数据科学应该是创造有影响力的软件。白皮书、仪表盘、文字云、饼状图已经不再有用了,如果它们曾经有用的话。获得结果需要努力。

这不是一条容易的路。史蒂夫·乔布斯说过,“一个伟大的想法和一个伟大的产品之间有着巨大的工艺。”为了快速进入市场,你可能需要戴上你的 DevOps 帽子。这意味着你的团队可能需要提升他们的软件工程技能。

但是,值得。在我们的组织中,过去有时需要 12 个月的时间,现在只需要几分钟。更重要的是,我们不是在构建分析货架产品。

尺寸并不代表一切

原文:https://towardsdatascience.com/size-isnt-everything-ecc1aa9b12f3?source=collection_archive---------10-----------------------

理解“大坏数据怪物”

数据前景是巨大的。字面上。无论是你不断产生的数据(你今天早上闯的红灯,你最近在 Instagram 帖子上收到的赞数,你午餐吃的新鲜沙拉,等等。)或者看似出现在你关注的每个订阅源上的无休止的“大数据”文章;你根本无法离开这个话题。那么,你如何理解这一切,你应该知道些什么呢?

虽然这自然是一个“大”问题,但我首先要承认大数据的三个关键要素:

  1. 仅仅因为有大量的数据存在(并且数据以天文数字的速度增长),并不意味着它一定是可怕的或压倒性的。
  2. 存储/安全/分析技术也在快速发展。
  3. 更多数据=更好的决策能力。

让我们花点时间更细致地看一下其中的每一项。

首先,我想解决“可怕的大坏数据”这个怪物。很少甚至没有“大数据”的背景,人们可能会有点神经质;我明白了。所有这些关于人工智能/机器学习、机器人窃取工作以及“老大哥”在你身后看的谈论可以理解地产生一点不确定性。让我们面对现实吧——当然,在我们理解它们之前,我们对大多数“新”主题都有同样的感受。

数据并不可怕,也不是一些有自己思想的自主生物。它只是用于分析和推理的事实或统计数据的集合。好吧,但是什么让数据成为“大数据”尽管这个答案看起来很简单或者微不足道,但是这两者之间的区别引起了很多争论。然而,依我拙见,区别相当简单..尺寸。

“好吧,别开玩笑了,威尔。但它必须有多大?”我会反驳,“足够大。”如果它太大,以至于您的常用工具无法快速捕获和处理,我会说它“太大了”

不管怎样,撇开语义不谈,比吉斯给了我们一个很大的公正,他们宣称,“大小不是一切。”然而,重要的是我们是如何走到这一步的。为此,我指出了现代技术。随着数字足迹达到前所未有的高度,可以安全地假设(传统上不建议)从数据到“大数据”的语义转变的最大原因只是我们现在可以收集并存储的数据量。

现在让我们暂时回到现代科技。

需要认识到的第二个关键因素是:虽然数据在快速增长,但围绕数据的技术也在快速增长。这些进步不仅包括更大/更好的数据管理系统、高效的数据输入解决方案和强大的安全增强功能,还包括更具可扩展性的分析工具。

数据科学领域最重要的事情之一是理解数据到底在说什么。幸运的是,新技术的出现也在不断缩小这一差距。这种分析工具允许用户相当快速地访问数据,并使用可视化得出结论,以帮助业务人员做出更多由数据驱动的决策。虽然这些工具在历史上需要技术团队来构建这些仪表板,但机器学习和自然语言处理的发展现在也为非技术用户访问他们的数据打开了大门。

但是这是什么造成的呢?

随着越来越多的公司接受这些关于数据驱动决策的力量的“现代”观点,分析工具的发展受到了极大的推动。与此同时,公司的日常决策方式也在急剧变化,为此,这些工具必须提供快速、有效和可靠的答案,而且没有任何延迟。

公司再也不能等待几周甚至几个月来进行缓慢的趋势评估、群组分析或客户保持预测。公司和个人做出强有力决策的速度只会越来越快,分析解决方案也必须如此。

我的结论是:虽然我曾经拒绝接受我的大部分日常活动被记录在未知的网络空间的想法,但我知道要接受它。它为我提供了一丝希望,有一天,医学、商业和娱乐的进步将远远超过我们曾经希望完成的任何事情。

评估:为您的企业进行市场评估

原文:https://towardsdatascience.com/sizing-up-market-sizing-for-your-business-c569e45730ef?source=collection_archive---------0-----------------------

你知道你的市场规模吗?了解市场规模可以帮助你计算出你的企业相对于市场有多大,以及它有多大的潜力。以下是计算市场规模的方法。

你的市场有多大?

投资者在投资你的企业之前首先考虑的事情之一是你的市场有多大。你的总潜在市场(TAM)是指如果你的企业拥有 100%的市场份额——如果每一个潜在客户都是你公司的客户,并且你没有竞争对手,那么理论上你的企业会有多大。这是一个重要的考虑因素,因为市场越大,企业就越大!

显然,很少有企业会接近 100%的市场份额,TAM 是用来比较不同企业的标准,而不是衡量特定企业的标准。如果你正在考虑投资一家 TAM 为 1000 万美元的公司和另一家 TAM 为 1 亿美元的公司,后一家公司更有潜力,因为它的市场更大。如果你假设一个成功的企业可能拥有他们 TAM 的 10%(比 100%更现实),那么比较这些企业就变得更容易了,因为 100 万美元< $10M.

But how do you figure out your TAM? What if you are a new business who does not yet understand fully who your customers will be? What if you are in a new market that is growing and changing every day?

This week we’ll cover techniques and considerations for sizing your TAM. Specifically:

  • 第 2 部分— 自上而下的市场规模
  • 第 3 部分— 自下而上的市场评估
  • 第 4 部分— 使用可比数据
  • 第 5 部分— 评估新市场

正如你将看到的,市场规模的确定需要你大量的创造力,因为你需要做出许多假设来进行估算。接下来,我们将从自上而下的市场规模估算开始。

从顶部开始

我们评估您的潜在市场总量(TAM)的第一种方法是自上而下的分析。顾名思义,在自上而下的分析中,我们将从最大可能的规模估计开始,并使用关于我们的业务和市场的信息和假设来减少它。

举个例子,让我们假设我们想要开始一个名为 番茄学 的新业务,按需提供番茄。番茄学的市场有多大?我们将从今天消费者在食品上的花费开始。

有许多公开的市场数据来源,特别是在美国,新的 Data.Gov 倡议提供了大量关于商业规模的原始数据。你可以找到从国家贸易数据父母在孩子身上花了多少钱的一切信息。劳工统计局发布了一份年度消费者支出调查(CES ),它告诉我们平均每个家庭每年在水果和蔬菜上花费 751 美元,在美国每年总共花费 944 亿美元。

不是每个购买水果和蔬菜的人都想要按需购买或者送货上门。事实上,只有在大城市开设植物学课程才有意义。大约 30%的人口(根据消费电子展)生活在大城市,所以我们假设只有 30%的销售可以由番茄学服务。这将我们的估计降低到 283 亿美元。

此外,并不是所有购买的水果和蔬菜都是西红柿!根据美国农业部的数据,只有 5%是西红柿(在美国被法律归类为蔬菜)。这就把我们的估计降低到了 14 亿美元。

当然,不是每个人都会按需订购他们的西红柿!超市总会有一些市场份额,所以我们假设 20%的家庭会按需订购番茄。这使我们的估价达到了 1 . 4 亿美元。

最后,我们的商业模式假设当西红柿直接送到你家门口时,消费者会购买更多的西红柿!我们的预期是番茄消费量增长 10%。这使我们的估价增加到 1 . 54 亿美元。

我们自顶向下分析的一个简短版本可能如下所示:

对于一个真正的自上而下的分析,你会在更严格的假设下继续这个过程,尽可能得到最精确的市场规模。显然,如果您错过了任何重要的假设,那么使用这种技术您会高估您的 TAM。这就是为什么,接下来,我们将讨论自底向上的估计!

(注 : Tomatology 是个很烂的主意。然而,如果你基于这个想法开始创业,我希望你能信任我。)

努力向上

虽然自上而下的市场规模估算通常很容易做到,但它可能会产生误导。你真能到达整个市场吗?即使你能做到,你要花多少钱?好消息是,自下而上的市场规模让我们对这些因素有了一个清晰的认识。

要做一个自下而上的分析,你要从你业务的基本单位(你的产品、价格、客户)开始,并估计你能把这些单位扩大到多大。

回到我们公司的例子, 番茄学 (番茄按需配送!),一个自下而上的市场评估需要从西红柿的价格开始,在我的地区,一个大西红柿的价格大约是 1 美元。我们当地的客户调查告诉我们,消费者每周去一次市场,会买 3 个西红柿。这意味着普通消费者每年会购买 150 美元的西红柿。

我们能接触到多少消费者?根据商业广告、广告牌和其他渠道的效果,我们的营销主管认为我们可以在我们的家乡加利福尼亚州奥克兰市接触到大约 35,000 个家庭。这使我们的估价达到了 530 万美元。

最后,我们将假设根据我们的运营计划和可用资本,我们可以扩展到前 30 个城市。这给了我们 110 万个家庭的观众,总计 1 . 56 亿美元。

我们自底向上分析的简短版本可能如下所示:

这就像我们的自上而下模型一样,简单而真实的自下而上模型将包括更多的步骤来获得更好的估计。

请注意,我们的自下而上模型忽略了一些重要因素,如我们需要多长时间才能接触到消费者、客户流失率以及是否存在竞争。请记住,我们正在努力确定我们的潜在市场总量,这只是我们的市场潜力。您的商业计划中的市场现实将需要解决这些其他问题,并确定您的 TAM 中真正可实现的百分比。

现在我们有了自上而下和自下而上的市场规模估算经验,我们在估算市场规模时选择哪一个呢?明天继续收听,答案可能会让你大吃一惊!

在过去的几天里,我们回顾了自上而下和自下而上的市场评估方法。基于你作为方法的一部分所做的假设,它们都有优点和缺点。

那么,我应该使用自顶向下还是自底向上呢?

都是。就其本身而言,自上而下或自下而上的分析都不能给你一个完整的描述。自上而下隐藏了接触不同客户群的困难,而自下而上则假设在你知道如何接触的客户群中总会有更多的客户。

当你的自上而下和自下而上的模型彼此一致时,你对你的市场规模有一个很好的估计。这可能需要更新你的假设来达成一致,但是这些更新应该是积极的改进,使最终的估计更加准确。这相当于将你的作业与朋友的作业进行比较,看你是否得到了相同的答案。

幸运的是,我们对番茄学【自上而下】和自下而上的模型,我们假设按需番茄交付的领导者,大致同意约 1 . 5 亿美元的市场规模。如果你没有那么幸运,重新检查你的假设,看看差距可能在哪里。如果你不能让这两个评估一致,那么你的市场或你的业务可能会出现根本性的问题。

还有一件事…

使用可比数据,我们可以对我们的估计更有信心。可比公司是指在商业模式、产品类型或市场地位上与你相似的公司。一个好的比较对象是一家已经具有一定规模的公司,并且为你将要服务的相同客户提供服务(现在和将来)。

对于 Tomatology,我们假设的按需番茄交付的领导者,比较对象可能包括:

  • Instacart
  • 亚马逊生鲜
  • 装箱
  • 邮戳

通过观察这些可比企业的规模,你可以确定你的估计是否现实。如果你的市场估值是$1B,但是没有一家现有的同类公司的收入超过 1000 万美元,那么你可能高估了这个市场的潜力(或者你有一个发展这个市场的聪明方法!).如果你的估值是 1 亿美元,而你的一些可比公司的业务是 2 亿美元,那么你可能有点太小了。把它作为你估价的第三次检查!

接下来,我们将看看如何确定新市场的规模,这些市场没有现有客户或任何可比较的客户。这需要我们变得更有创造力!

未来是朦胧的,请再试一次。

虽然在我们讨论了所有这些之后,市场规模的确定看起来很简单,但是更有趣的市场是那些还不存在的市场。这些都是新的市场,由不断变化的消费者需求、技术创新或资源可用性的变化创造。新市场缺少我们在之前的规模估算练习中使用的所有输入!

不要害怕,你仍然可以估计一个新市场的规模,尽管会不太准确。为此,你需要做出更大胆的假设。

让我们假设 番茄学 (我们假设的按需番茄配送公司)陷入困境,因为消费者没有像我们估计的那样按需购买番茄。所以,我们想出了一种新产品,叫做番茄苹果,是番茄和苹果的杂交品种。但是苹果的市场规模有多大呢?今天没有人购买它们,所以我们不能使用我们目前使用的自上而下或自下而上的方法。

或者我们可以吗?

即使苹果还不存在,消费者每天还是会购买其他食物。新产品要么会成为现有产品的替代产品,要么会为消费者目前不再购买的产品创造新的需求。了解您的产品属于哪个类别很重要,因为每个类别的尺寸都不同:

替代产品:替代产品的市场评估与现有产品的市场评估完全相同。你只需为你要取代的产品确定市场规模,并假设你的新产品能取代多少市场。

新需求:新需求评估更加困难,需要你了解你的潜在客户现在有多少购买力,有多少钱可以花在新的东西上。这也是为什么新产品往往将更富裕的客户群定位为奢侈品(iPhone、特斯拉等。)因为这些顾客有更大的购买力,因此有能力购买新的东西。

在了解你的业务潜力和你能创造的价值时,确定你的市场规模是重要的一步。这也是一个有用的练习,可以帮助你理解在发展业务时需要克服的主要障碍。如果你在评估你的市场时遇到任何问题,请给我写信。

喜欢这个系列吗?在数据驱动每日档案页面查看类似内容。

深度学习的 Skejul 会议

原文:https://towardsdatascience.com/skejul-meetings-with-deep-learning-5efab285b111?source=collection_archive---------3-----------------------

厌倦了试图与某人见面,却找不到日期或时间?我也是。

问题是

当你的人在世界各地,在不同的时区,甚至在同一个房间时,安排一次会议是不容易的。我们都超级忙,对吧?

也许你没有正确利用你的时间,也许你某一天有很多会议,而其他时间却没有。如果有一个完美的日历,有多余的时间,所有的会议和活动都有条不紊,那不是很好吗?

你猜怎么着?深度学习拯救世界!

斯克尤尔

http://skejul.com

我很高兴见到了 Skejul 的首席执行官马修·拉蒙斯先生,对系统及其后端做了简短的解释。

Skejul 是一种人工智能(AI),它代表你工作,而不需要你花费大量时间来设置偏好、声明优先级、管理其他人的联系信息,或者维护关于你去的地方和你喜欢做的事情的信息。

它还简化了协调涉及人、地点和事物的活动的复杂过程。

但是它是怎么做到的呢?

深度学习中的序列模型

什么是序列?

简而言之,就是相关事件、运动或事物相互遵循的特定顺序。在斐波纳契数列的例子中,那些“事物”是数字,它们有一个关联它们的函数,我们称之为递归关系:

如果你是一名程序员,也许你会发现这段 Python 代码更有用:

**def fib(n): 
   if n==1 or n==2: 
      return 1 
   return fib(n-1)+fib(n-2)**

这段代码是递归的。当你根据问题本身来定义问题时,就会出现递归。

所以编程和数学都很酷。但这和深度学习有什么关系。

Deep Learning With Python, F. Chollet. Page 196.

在深度学习中,有一种特定类型的神经网络(NN),它能够通过迭代序列元素来处理序列,并保持一种状态,其中包含与迄今为止所见相关的信息。就好像它们有“记忆”一样。是一种逐渐处理信息的方式。

这种类型的神经网络被称为递归神经网络(RNN),这种类型的神经网络有一个内部循环,其状态在处理两个不同的独立序列之间重置。

时间序列的 RNN

因此,Skejul 寻求解决这个问题的一个方法是使用 RNN(和其他种类的神经网络)来处理时间序列。时间序列是在许多时间段(每周、每天等)收集的数据。)

是一种序列类型的数据,其中的元素在时间上是相关的。例如股票价格加密货币价格等等。

RNN 特别擅长时间序列预测,我的意思是,尝试使用单个时间点之前的 x 的值来查看某个时间段的 x 的值。

虽然 rnn 对于顺序数据非常有用,但它们也有一些问题,比如学习“长期依赖性”,想想看,就像相关信息和需要它的点之间的差距变得非常大。

为了解决这个问题,hoch Reiter schmid Huber(1997)引入了长短期记忆网络(LSTMs),这是一种特殊的 RNN,能够学习长期依赖性。

关于 LSTMs 的更多信息,请查看这篇惊人的帖子

Keras 中的 LSTM 模型(代码改编自此处的)

没拿到代码也不用担心。这只是为了展示在喀拉斯建造一个 LSTM 是多么容易。我会在 Keras 上做介绍。

from keras.layers.core import Dense, Activation, Dropout
from keras.layers.recurrent import LSTM
from keras.models import Sequential
import timedef build_model(layers):
    model = Sequential()

    model.add(LSTM(
        input_shape=(layers[1], layers[0]),
        output_dim=layers[1],
        return_sequences=True))
    model.add(Dropout(0.2))

    model.add(LSTM(
        layers[2],
        return_sequences=False))
    model.add(Dropout(0.2))

    model.add(Dense(
        output_dim=layers[3]))
    model.add(Activation("linear"))

    start = time.time()
    model.compile(loss="mse", optimizer="rmsprop")
    print("> Compilation Time : ", time.time() - start)
    return model

使用这个简单的代码,您可以在 Keras:)中创建一个序列模型。

时间序列和 Skejul

因此,Skejul 所做的是使用自己的专有算法来做出有根据的猜测,确定与任何数量的客人举行会议的最佳时间和日期。

马修告诉我,这种算法使用深度学习技术,他们一直在探索 ConvNets残差 NN深度强化学习

但是数据呢?你可能会想,他们是如何训练神经网络的?

这是有趣的部分,你可以成为私人测试版的一部分,算法也可以从你这里学习!你可以在这里报名

Skejul 做的很多事情是从你的日历中获取数据,但不仅仅是你的会议,还有你对会议的回复,你何时接受,何时拒绝等等。

他们将在今年春天发布该软件的免费版本,在仲夏发布商业版本。Skejul 将有如此多的功能,新的功能将逐步增加,如在应用程序中举行会议的视频平台,为会议和聊天添加媒体。

他们声称,使用他们的算法和平台,你可以通过他们的 Skejul Activity Forecasting Engine(SAFE)为你的会议提供比不知情的猜测更好的建议。此外,他们已经有超过 25 个国家和城市的预激活成员,如:伦敦,孟买,墨西哥城,旧金山,新加坡,柏林,罗马,布宜诺斯艾利斯,都柏林,迪拜,香港和更多!

请保持关注以获取更多信息;).

摘要

  • 安排会议不是一件小事,让我们用深度学习和 AI 来解决。
  • 深度学习是一个非常重要的领域,有很多应用,这里显示的是预测序列模型中的值。
  • 序列是相关事件、运动或事物相互遵循的特定顺序。
  • 递归神经网络(RNN)是一种具有内部循环的神经网络,其状态在处理两个不同的独立序列之间重置。他们拥有类似记忆东西。
  • RNN 在学习“长期依赖”方面有问题,所以 LSTMs 来帮忙了。LSTM(长短期记忆)网络解决了这个问题。
  • 你可以在 Keras 中简单快速地实现一个 LSTM 模型。
  • Skejul 正在使用 RNN、LSTMs、ConvNets、残差神经网络、深度强化学习等解决与全球不同人实时安排会议的问题。

如需了解更多信息,请在 Linkedin 上关注我:

[## 法维奥·巴斯克斯| LinkedIn

查看 Favio Vázquez 在世界上最大的职业社区 LinkedIn 上的个人资料。Favio 有 12 个工作列在他们的…

www.linkedin.com](https://www.linkedin.com/in/faviovazquez/)

神经网络协方差学习收敛性的一个证明

原文:https://towardsdatascience.com/sketching-a-proof-of-convergence-for-covariance-learning-in-neural-networks-fbfc0c875bea?source=collection_archive---------5-----------------------

(我提供了一个冗长的、有点技术性的解释,详细阐述了我的著作协方差 作为一个 全网络成本函数 ,它允许网络 训练新插入的神经元 ,特别是对于专家神经网络的混合。这项工作旨在促进 机器智能的发展,使其能够在新的经验发生时学习 。)

先来点背景:

神经网络功能强大。

神经网络正在诊断癌症,并在数百种语言之间进行翻译。使用深度神经网络,复杂的分类任务现在成为可能。随着我们依赖神经网络进行日益复杂的活动,我们可以预计这些网络将扩展到令人难以置信的深度。这些网络具有巨大的潜在价值。然而,训练非常深的神经网络会带来一些挑战…

过度拟合是一个问题。

当一个神经网络被训练来分类数据时,它最终学会了完美地排序——但是,它只会完美地排序你的训练数据,因为它记住了整个集合。当给定新数据时,这些过度拟合模型表现不佳。从一个随机网络(执行随机分类)移动到一个记忆数据网络(执行精确分类,即它是“过拟合”)是一个大飞跃,而良好泛化网络(对新数据表现良好)位于附近的点。当给定新数据时,一旦分类器开始恶化,研究人员就停止他们的训练。这是一个难题,要解决的事实是最小化‘损失函数’并不是我们真正想要的。我们实际上想要一个好的概括!

培训——时间就是金钱。

更深层次的神经网络需要更长的训练时间,并且通常需要更大的数据集才能很好地学习。你可以使用 GPU(或 TPU)来减少时间和成本,但那只是一次性的改进。从根本上来说,随着关系网越来越深,培训成本将大幅上升。 摩尔定律已死,因此“计算机硬件的改进将继续使深度神经网络更便宜”的说法不攻自破。

而且,学习需要无处不在。

神经网络在网络的深度上存储学习:简单的局部特征(如边缘的位置)通常在较低层被区分,而较高层对更抽象的特征(如“动物”、“工具”、“建筑物”)进行分类。不幸的是,神经网络是使用来自输出层* — 的反向传播来训练的,它们自上而下地学习。因此,必须在低层学习的特性只能通过向下扩散通过多层的信号来教授。这被称为“消失梯度”问题。残差和跳过连接是时髦的解决方法,但是它们没有消除自上而下学习的问题。(残差本质上放大了梯度,而跳跃连接有效地拉平了网络的深度两个还是从最上面一层学起,往下。)*

协方差是治愈的方法

具体来说,协方差(以及它的表亲,负相关)就是解。当两个信号趋向于以相反方向出现时,就会出现负协方差:如果一个信号为“开”,另一个信号为“关”,反之亦然。对于神经网络,如果神经元在正确分类数据时是“开”的,而在错误分类数据时是“关”的,则记录负协方差。(此外,负协方差也记录在逆条件中:正确分类数据时为“关”,错误分类数据时为“开”。)记录负协方差的神经元本质上是错误检测器。他们告诉我们:‘如果这个神经元在放电,那么我们就有可能得到错误的答案。我们应该倾听这些神经元,找出哪些教训没有被吸取。**

协方差消除了自上而下的学习

今天的神经网络都受到自上而下学习的困扰——它们的“损失函数”或“成本函数”是在输出层发现的误差。(损失函数问:“神经网络得到正确的答案了吗?”)同时,协方差 可以在任意层发现错误,而不仅仅是最顶层的输出层!负协方差是一个错误检测器,专门指向对错误“负责”的神经元。**

换句话说:如果神经网络是企业,那么“损失函数”就是一份备忘录,在到达员工之前,它会经过许多管理层。“损失函数”得出的结果是“我们的企业赔钱了!”并告诉上层管理人员“做一些不同的事情”。然后,这些经理向所有中层经理传达一个信息,坚持要求他们“做一些不同的事情”。当这个消息传到所有员工手中时,他们应该改变什么还不清楚。这份备忘录一开始就含糊不清,随着它在层级中的传递,变得越来越淡化。

继续商业隐喻:负协方差就像一份有针对性的备忘录,在个人绩效评估之后。协方差询问每个神经元/员工:“是这个员工做了导致我们产品失败的工作吗?”整个网络正在审核中,消息“做一些不同的事情”仅发送给需要做一些不同事情的神经元/员工!**

因此,当损失函数仅在输出层定义时,协方差在在网络中的每个神经元定义。有了协方差,学习就发生在任何需要的地方,与层无关。

协方差节省时间和金钱

训练一个非常深的神经网络会增加时间,因为“业务备忘录”在通过额外的层时会变得稀释。相比之下,协方差以它的“备忘录”为目标,可以给每个神经元发出禁令,而不管深度。有了协方差,额外的层不会冲淡信息,因此,它们不会延长训练时间。

协方差节省了重新训练的时间。传统的训练创造了一个静态的神经网络;如果新数据被包括在网络的训练中,它通常从零开始被重新训练。假设新数据需要对一些底层特性进行更改?在较低层发生有意义的变化之前,网络需要向下发送大量的“备忘录”。负协方差避免了这个问题,通过立即识别对错误负责的特定神经元,而不需要向下移动层级。**

随着神经网络变得更加深入,它们无法使用自上而下的学习快速进行重新训练。深度网络的频繁更新变得极其昂贵,而且新数据可能在他们完成对旧数据的训练时到达!负协方差消除了重新训练的滞后和成本,允许难以置信的深度神经网络随着每一批新数据更新。对于许多应用程序来说,这种能力是玩具模型和可用产品之间的区别。**

协方差将特征检测推到最低层,以延迟过拟合

这一点需要一点努力:通过在呈现负协方差的神经元上应用反向传播,网络被向下“推”,检测尽可能最低层的特征。当特征在早期被识别出来,网络就更难陷入记忆。收敛的证明要求最终达到完美的精度,但是当网络依赖于早期特征检测时,这种精度不太可能来自记忆。

为了展示这一切是如何发生的:

想象一个神经网络,其中最后一层仅仅是它下面一层的复制;电线正在全力连接单个神经元。这两层的反应是一样的。因此,最后一层实际上是不相关的,所有真正的计算都发生在较低层。我们可以说,分类问题已经被“推下”到更低的层。

如果我们制造一个神经网络,其层数比所需的多,我们希望训练会导致特征检测的‘下推’,消除额外的层。这是因为额外的层允许网络以更大的特异性进行分类——我们需要足够的层来指定我们的分类,但是太多的特异性会让网络记住(“过拟合”)训练数据。

因此,如果分类任务被我们的训练算法“下推”,那么网络仍然能够获得所有训练数据的准确性(这是“它需要的层”的定义)。然而,没有必要的深度完美地记忆数据;它只有足够的层数来学习有效的分类。这种特性可以扩展到应用于所有层的所有特征检测:如果网络在可能的最低层捕获那些特征,那么只有足够的深度来允许分类,而没有足够的深度来允许完美的记忆。一个将特征检测“推”到最低可能层的网络将延迟过拟合——这就是我认为协方差所实现的。

那么,负协方差如何“下推”特征检测呢?

如果一个神经元记录了负协方差,它就是在说“当网络出错时,我就开火”。为了能够识别错误,该神经元必须接收关于正在发生的错误的信息数据。也就是说:到达那个神经元的信息是参与了的错误。(如果不是这样,神经元将无法检测错误,因此,它将不会记录负协方差——该陈述是同义反复的!)通过从该神经元反向传播,其下的神经元被抑制,这是对导致错误的信息的抑制。任何在错误期间活动的特征*将被阻止,结果,分类开始依赖于正确的特征,因为它们是唯一没有被阻止的特征。*****

这种“沮丧”适用于每一层;反向传播不鼓励在较低层检测到的任何导致较高层出现负协方差的特征。(这正是“损失函数”在输出层所做的;“损失函数”实际上只是限制在最顶层的负协方差。通过推广这一活动,负协方差让我们在所有层都这样做。)对进行正确分类的更高层神经元可能会阻止其一些输入,因为这些输入也会传播到具有负协方差的神经元。这意味着更高层的神经元,在这种沮丧的情况下,开始更密切地倾听输入神经元,而这些神经元是自己正确分类的。在极端情况下,输入神经元将执行正确的分类,并将其传输到更高层。在最上层,这种情况相当于当其下层输入是单个正确分类的神经元时,输出神经元触发。这就是我们定义为‘下推’的特征检测!****

因此,使用共变神经元的反向传播训练的网络将倾向于抑制任何层的神经元的活动,这些神经元涉及错误。保持活跃的神经元是那些已经正确分类特征的神经元。那些正确分类器之上的层是有效冗余的。这样做的影响是:正确的分类被“下推到”较低层,而仅仅是复制到较高层(除非较低层不能自己完全分类,在这种情况下,较高层神经元从较低层接收一些活动组合——这是“需要更多层”的一个例子)。****

收敛证明的草图:

没有收敛性的证明,训练算法可能跳跃,而不会在训练数据上达到完美的精度。(它可以达到完美的精确度,但是我们没有数学上的保证!)我将介绍几个技巧,来解决负协方差的收敛问题:**

半学习

在通过我们的神经网络运行所有训练数据之后,我们将正确分类的输入从错误分类的输入中分离出来,并针对每个神经元测量这两组之间的负协方差。然后,我们根据负协方差的程度,通过反向传播在每个神经元上应用梯度下降。假设,在应用梯度下降的“学习”之后,我们发现错误分类的数量增加了!在这种情况下,将“学习”的速度减半,然后再试一次。继续将学习率减半,直到错误数量不再增加。现在你有相同或更少的错误分类,你再次测量负协方差…我将这个过程称为将学习率减半的网络“半学习”。它保证错误率不会增加。****

半学习的停止点

半学半会什么时候停?即使是最轻微的学习率也会导致错误数量的增加。当错误数为正时,会发生这种情况吗?回答这个问题需要仔细观察:

当仍然存在误差时,一些神经元表现出负协方差。也就是说,它们在错误分类时倾向于“开”,在正确分类时倾向于“关”,反之亦然。如果唯一具有负协方差的神经元是输出神经元之一(错误触发的神经元,导致错误分类),那么这种情况相当于在输出层具有错误分类的传统“损失函数”。这在现有文献中已经被证明是一致的。

现在,假设有一个错误分类(它必然包括一个输出神经元上的负协方差),即也在更深的层中的另一个神经元上显示负协方差。如果“半学习”可以找到消除误差的共变神经元的小变化,而不产生新的误差,那么网络仍然收敛。****

存在一个“半学习”率,它消除了现有的误差,而没有产生新的误差。这是因为输出层上的错误分类器必须依赖错误神经元及其输入多于正确分类器。(如果正确分类器比错误分类器更依赖错误神经元*,那么它们必然也会错误分类输入。正确-根据定义,输出层上的分类器必须利用主要正确的输入!)因为输出层上的错误分类神经元比其他输出神经元更依赖于下层错误神经元,所以错误神经元的变化对错误分类器的影响将大于对正确神经元的影响* …可以使用一些小的“半学习”率来消除错误分类,而无需过多地改变正确神经元!******

因此,我们已经证明了在输出层的单个神经元具有负协方差的情况下的收敛性(这只是传统的“损失函数”,现有文献中已经证明了收敛性),以及在某个较低层的附加神经元呈现负协方差的情况下的收敛性(上一段中的“错误神经元”)。通过归纳,我提出任何层上呈现负协方差的额外神经元同样受到约束,并且同样收敛,结果。与正确分类的神经元相比,每个错误神经元在输出层与错误分类的关联 必然更强* ,因此,这些错误神经元的微小变化对错误分类器的影响比对正确分类器的影响更大。这保证了误差不会增加,并且可以减少到零。*********

就这些吗?

我并不打算暗示协方差允许网络总是比现有方法收敛得更快。相反,协方差能够训练插入的神经元簇,提供更快的 再训练 。你可以在现有网络内的任何地方培养一个新的神经元集群,并根据新数据对其进行训练,而网络的其余权重则被“冻结”。我建议在专家混合神经网络中的错误检测神经元上植入这些簇。每个集群本质上充当一个“专业专家”,从错误检测器中提取特征,帮助纠正错误!网络适应新的数据,而不会忘记旧的教训(健忘是重新训练深度网络的祸根!)…我希望负协方差将促进异常深层网络的发展,这些网络快速成长并适应新信息**,而不会失去他们在过去学到的核心洞察力*。*****

缓慢的泄漏会使船只和公司沉没…

原文:https://towardsdatascience.com/slow-leaks-sink-ships-and-companies-36daaad993b4?source=collection_archive---------17-----------------------

机器学习拯救世界!

小而慢的泄漏会使船只沉没——以此类推,如果不及早发现和修复,小而慢的泄漏也会给任何企业造成重大损失。

小漏有意思吗?假设一家电子商务企业在最后一天发现采购量下降了 50%,整个公司将被召集起来,从首席执行官一直到 R&D 支持人员,尽快找出原因。现在假设在最后一天收入下降了 1%——很可能没有人会注意到。但是,如果每天下降 1%,收入下降 50%只需要 2.5 个月。什么时候会被注意到?仅仅两周之后,收入就已经下降了 13%,一个月后下降了 27%。如果被遗漏或忽略,损失可能与大停电一样大。

有哪些缓慢的业务泄露的例子?

  • 特定平台和操作系统版本的新版本发布后,重要业务流程中的错误(例如,结账或显示的广告)。起初,很少有用户受到影响,但随着更多的用户下载新版本,泄漏变成了洪水。
  • 营销活动的变化会导致某个细分市场的转化率下降,并在很长一段时间内不为人知,从而导致潜在客户/客户的流失。
  • 一个竞争对手改进了他们的广告定位策略,赢得了更多的广告出价,导致您的广告浏览量和转换率逐渐下降。
  • 一个重要特性令人困惑的用户界面/UX 变化会导致特性使用的缓慢和逐渐减少,以及客户流失的缓慢增加,因为沮丧的用户会停止使用产品。
  • 您企业的客户支持行动手册的变化会导致票证处理时间增加,从而慢慢增加支持成本。
  • 还有更多…

这些泄露看起来像什么?

对于上面的每个示例,泄漏应该在至少一个正在测量的 KPI(指标)中可见。例如,衡量某个功能的使用情况、完成结账的次数或流失率的指标应该显示逐渐下降或上升。这些泄露通常以的形式出现,即收益、转换率等指标的趋势变化。

但是,在船下沉之前检测这些缓慢的泄漏有两个问题…

首先,对所有相关指标进行手动检查是不可行的——可能需要跟踪数千个指标,尤其是在测量不同细分市场中的每个 KPI 时:例如,针对用户群的不同细分市场、不同操作系统和设备类型等测量结账数量。这种缓慢的泄漏可能发生在任何一种情况下,可能根本不会在聚合级别上显示出来。

其次,除非您查看足够大的时间窗口和时间尺度(聚合级别—每小时、每天等),否则在图中很难注意到缓慢的泄漏。).但是什么才够大呢?一天?一周?一个月?什么是正确的时间尺度?

让我们用一个移动应用程序的例子来检验这两者。下图显示了针对所有用户(所有地理位置、平台和应用版本)的移动应用崩溃总数:

“崩溃”有明确的每日模式,但崩溃总数的趋势没有明显变化。

然而,在使用特定版本的基于 iOS 的设备上,崩溃的数量逐渐增加。当以每小时的时间尺度查看 iOS 和有问题版本的崩溃指标时,很难注意到第一天开始增加时的变化:

即使撞车的数量增加了,如果你看这个图表的仪表板,在每小时的时间尺度上,泄漏会被发现,直到它变得更大。

那么,在这种情况下,我们如何快速检测到缓慢泄漏(崩溃的增加)?让我们改变一下时间尺度——让我们来看看每天的撞车总数:

每个数据点代表每天的撞车总数,很容易看出 8 月 4 日看起来比以前高,并且有潜在的趋势变化。

这两个挑战都表明,手动检测泄漏需要大量分析师的努力,他们必须不断浏览至少数千张图表,在多个时间尺度上查看它们,并希望能够发现这种情况。即便如此——更高的坠机数字代表着有意义的增长,这难道就那么明显吗?

有一个更好的解决方案——基于机器学习的多尺度异常检测。

多尺度异常检测

时间序列的异常检测包括学习时间序列的正常行为,并检测与其显著偏离的异常。

下图显示了一个测量会话数量的时间序列,以及两个显示与正常模式相比有所下降的异常情况:

在我们的 构建异常检测系统 的权威指南中,我们描述了健壮的大规模异常检测系统的构成。

假设手头有一个异常检测软件,我们可以将它应用于我们在多个时间尺度上收集的每个指标,例如,每分钟、每小时、每天甚至每周的崩溃次数。

让我们看看上面的应用崩溃例子。

在每小时的粒度上,碰撞的增加没有超过每小时的正常范围(阴影区域):

在日常生活中,情况大不相同。崩溃的数量明显超过正常范围,将其记录为异常:

如果被忽视,这一事件就会扩大,泄漏开始变成洪水:

在这种情况下,崩溃的增加是通过在多个时间尺度上自动分析相同的指标(iOS 设备和一个版本的应用程序的崩溃数量)来检测的——尽管在每小时的时间尺度上泄漏是缓慢的,并且没有导致任何人的小时异常,但在每天的时间尺度上它显示为重大异常,从而实现早期检测。

多尺度分析真的有必要吗?适应/检测权衡

我们可以争辩说,如果我们等一天,泄漏就会在每小时的时间尺度上显现出来。然而,它可能永远不会在每小时的时间尺度上被探测到。所有已知的用于异常检测的时间序列建模方法(来自 ARIMA、霍尔特-温特斯、LSTMs 等)都将趋势估计作为学习正常行为过程的一部分,并且必须适应时间序列行为的微小变化。在衡量企业时,适应性至关重要,因为没有什么是一成不变的。这意味着,如果泄漏与学习算法的适应速率相比较慢,则该算法将持续跟踪泄漏,将其视为正常的行为变化。

下图说明了正常行为算法如何适应衡量会话数量的指标的缓慢下降趋势:

当趋势发生变化时,每日级别的相同指标会记录异常,从而能够检测到趋势的变化。

总之,人工检测缓慢泄漏几乎是不可能的。异常检测算法非常适合检测时间序列正常行为中的变化,但由于缓慢泄漏可能仍然“隐藏”在噪声下,需要这些算法进行调整,因此多尺度方法可确保检测到缓慢泄漏。

SlowFast 解释道:双模 CNN 用于视频理解

原文:https://towardsdatascience.com/slowfast-explained-dual-mode-cnn-for-video-understanding-8bf639960256?source=collection_archive---------11-----------------------

受灵长类视觉机制启发的最先进的深度学习架构

检测图像中的对象并对其进行分类是一项比较著名的计算机视觉任务,因 2010 年的 ImageNet 数据集和挑战而普及。虽然 ImageNet 已经取得了很大进展,但视频理解仍然是一项令人烦恼的任务——分析视频片段并解释其中发生的事情。尽管最近在解决视频理解方面取得了一些进展,但当代算法仍远未达到人类水平的结果。

来自脸书人工智能研究公司 SlowFast 的一篇新的论文提出了一种分析视频片段内容的新方法,在两个流行的视频理解基准上实现了最先进的结果——Kinetics-400 和 AVA。该方法的核心是在同一视频片段上使用两个并行卷积神经网络(CNN)——一个慢速路径和一个快速路径。

作者观察到,视频场景中的帧通常包含两个不同的部分——帧中完全不变或变化缓慢的静态区域,以及指示当前正在发生的重要事情的动态区域。例如,一个飞机起飞的视频将包括一个相对静态的机场,一个动态对象(飞机)在场景中快速移动。在两个人见面的日常场景中,握手通常是快速和动态的,而场景的其余部分是静态的。

因此,SlowFast 使用慢速、高清晰度 CNN(快速路径)来分析视频的静态内容,同时并行运行快速、低清晰度 CNN(慢速路径),其目标是分析视频的动态内容。该技术部分受到灵长类动物视网膜神经节的启发,其中 80%的细胞(P 细胞)以低时间频率工作,并识别精细细节,约 20%的细胞(M 细胞)以高时间频率工作,并对快速变化做出反应。类似地,在 SlowFast 中,慢速路径的计算成本是快速路径的 4 倍。

High-level illustration of the SlowFast network. (Source: SlowFast)

SlowFast 如何工作

慢速和快速路径都使用 3D ResNet 模型,一次捕获几帧并对其运行 3D 卷积运算。

慢速路径使用大的时间步幅(即每秒跳过的帧数) τ ,通常设置为 16,允许每秒大约 2 个采样帧。快速路径使用小得多的时间步幅τ/α,α通常设置为 8,允许每秒 15 帧。通过使用明显更小的通道尺寸(即回旋宽度;使用的滤波器数量),通常设置为慢信道大小的⅛。快速通道的通道尺寸标记为 β 。更小的信道大小的结果是,尽管具有更高的时间频率,快速路径比慢速路径需要少 4 倍的计算。

An example instantiation of the SlowFast network. The dimensions of kernels are denoted by {T×S², C} for temporal (T), spatial (S), and channel © sizes. Strides are denoted as {temporal stride, spatial stride ^ 2}. The speed ratio (frame skipping rate) is α = 8 and the channel ratio is 1/β = 1/8. τ is 16. The green colors mark higher temporal resolution, and orange colors mark fewer channels, for the Fast pathway. The lower temporal resolution of the Fast pathway can be observed in the data layer row while the smaller channel size can be observed in the conv1 row and afterward in the residual stages. Residual blocks are shown by brackets. The backbone is ResNet-50. (Image & Description from SlowFast)

High-level illustration of the SlowFast network with parameters (Image: SlowFast)

横向连接
如直观图示所示,来自快速通道的数据通过整个网络的横向连接被馈入慢速通道,从而允许慢速通道知道来自快速通道的结果。单个数据样本的形状在两个路径之间是不同的(Fast 是{αT,S,βC}而 Slow 是{T,S,αβC}),需要 SlowFast 对快速路径的结果执行数据转换,然后通过求和或串联将其融合到慢速路径中。

本文提出了三种数据转换技术,实践证明第三种是最有效的:

  1. 时间到通道:将{αT,S,βC}重塑并转置为{T,S,αβC},意思是将所有α帧打包到一帧的通道中。
  2. 时间间隔采样:简单地从每α帧中采样一帧,所以{αT,S,βC}变成{T,S,βC}。
  3. 时间步长卷积:对具有 2βC 输出通道的 5×12 内核执行 3D 卷积,步长= α。

有趣的是,研究人员发现,双向横向连接,即也将慢通路馈入快通路,不会提高表现。

结合路径
在每个路径的末端,SlowFast 执行全局平均池,这是一个旨在降低维度的标准操作。然后,它连接两个路径的结果,并将连接的结果插入到完全连接的分类层中,该分类层使用 Softmax 对图像中发生的动作进行分类。

数据集

SlowFast 在两个主要数据集上进行了测试 DeepMind 创建的 Kinetics-400 和谷歌创建的 AVA。虽然两个数据集都包括视频场景的注释,但它们略有不同:

  • Kinetics-400 包括来自数十万个 YouTube 视频的 10 秒钟短场景,有 400 种人类动作(例如握手、跑步、跳舞),每种动作都在至少 400 个视频中出现。
  • AVA 包括 430 个 15 分钟的带注释的 YouTube 视频,有 80 个原子视觉动作。每个动作都被描述并位于一个边界框内。

结果

SlowFast 在两个数据集上都取得了最先进的结果。在 Kinetics-400 中,它比最佳前 1 名分数高出 5.1% (79.0%对 73.9%),比最佳前 5 名分数高出 2.7% (93.6%对 90.9%)。它还在新的 Kinetics-600 数据集上取得了最先进的结果,该数据集类似于 Kinetics-400 数据集,但有 600 种人类行为,每种行为都在至少 600 个视频中出现。

对于 AVA 测试,SlowFast 研究人员首先使用了一种版本的更快的 R-CNN 对象检测算法,结合现成的人员检测器,提供了一组感兴趣的区域。然后,他们在动力学数据集上对 SlowFast 网络进行预训练,最后在感兴趣的区域上运行它。结果是 28.3 地图(平均精度中值),比 AVA 最先进的 21.9 地图有了巨大的进步。值得注意的是,比较的结果也在 Kinetics-400 和 Kinetics-600 上进行了预训练,与之前的结果相比,SlowFast 没有特别的优势。

有趣的是,该论文将仅慢速和仅快速网络的结果与组合网络进行了比较。在 Kinetics-400 中,慢速仅获得 72.6%的前 1 名成绩和 90.3%的前 5 名成绩,而快速仅获得 51.7%的前 1 名成绩和 78.5%的前 5 名成绩。

这表明,尽管两种途径的得分都明显低于最先进的得分,但慢速和快速途径的组合允许对屏幕上发生的事情有更深入的了解。在 AVA 数据集上观察到了类似的结果。

计算

与标准 ResNet 实现相比,SlowFast 在计算方面更轻,在慢速网络中需要 20.9 GFLOPs 才能达到收敛,在快速网络中需要 4.9 GFLOPs,而在同一数据集上的普通 3D ResNet-50 基线中需要 28.1 至 44.9 GFLOPs。

实施细节

SlowFast 是在 PyTorch 中实现的,并且将是开源的。

结论

SlowFast 提出了一种新颖而有趣的视频理解方法,利用了真实世界场景的直观结构,并从生物机制中获得了一些灵感。该论文表明,模型的进一步优化,如使用更深的 ResNet 或应用其他已建立的计算机视觉技术,可以获得更好的结果,并进一步提高我们使用软件理解现实世界情况的能力。

要了解最新的深度学习研究,请订阅我在 LyrnAI 上的简讯

小企业、大数据和自助服务分析的神话

原文:https://towardsdatascience.com/small-business-big-data-and-the-myth-of-self-service-analytics-ee927d5fdbee?source=collection_archive---------4-----------------------

成功的中小企业营销人员完全了解竞争需要什么:强大的网站、内容策略、CRM 和多渠道参与计划。但是随着所有策略的叠加,数据也在叠加。越来越难知道什么是有效的,客户旅程中的哪些步骤是最重要的。

这不是一个新问题,但这是一个大型企业通过投资大数据战略和分析平台已经在很大程度上解决的问题。据 IDG 称,78%的大型企业将数据战略视为改变其经营方式和获得竞争优势的核心。

软件巨头 SAP 的 CMO 陈美琪·琼斯对中小企业分析挑战的总结再好不过了:

“尽管软件资源的使用越来越多,但小型企业并没有获得实时数字互联的好处…人们认为只有大型组织才能负担得起分析平台,投资回报根本不足以保证成本。虽然这在大数据的早期可能是正确的,但在今天却完全不是这样。”— 格言,2017 年 3 月 8 日,“小企业拥抱大数据的时候到了

那么小企业如何竞争呢?

琼斯认为解决方案是自助分析(就像 SAP 自己的产品一样)。现在,像 Domo、ClearStory 和 Tableau 这样的平台比传统的分析系统成本更低、灵活性更高,为“民主化数据”开辟了可能性。Gartner 也顺应了这一趋势,预计到 2020 年,80%的企业报告将是自助式的。这个市场正获得如此大的吸引力,以至于《个人电脑杂志》有一个排名表,列出了顶级自助服务系统。大量的新软件解决方案给人的印象是,必须有一个适合每个用例的解决方案。

但是自助分析是中小企业营销的灵丹妙药吗?

我和我在 Deducive 的同事不这么认为,最大的自助服务公司之一 Domo 的数据战略总监布伦特·戴克斯也不这么认为:

“自助服务分析不会神奇地将您的所有员工转变为“公民”数据科学家。” —福布斯,2016 年 11 月 15 日“自助分析和自给自足的幻觉

《数据策略》的作者伯纳德·马尔也同意这一观点:

“自助服务分析应该是数据科学团队的补充,而不是替代。”— Forbes ,2016 年 10 月 25 日"为什么我们必须重新思考自助式商务智能、分析和报告"

在我们看来,为了让中小企业营销人员获得竞争优势,并证明大数据的投资回报率,分析必须以激光聚焦的方式来回答特定的问题。此外,中小企业不应该构建通用的分析能力,而应该寻求特定行业的工具。饮料行业的动向对保险公司来说无关紧要。最重要的竞争优势,如由机器学习算法驱动的预测建模,需要比基线分析应用程序更具针对性。

迄今为止,还没有很多特定于行业的工具。我们需要建造它们。

(本文改编自最近在deducive.com上的一篇帖子。)

小数据,并得到它

原文:https://towardsdatascience.com/small-data-and-getting-it-4b3ed795982c?source=collection_archive---------15-----------------------

为什么还要麻烦小 N 呢?

大数据很好很好:随着我们数据集的样本量( n )接近无穷大,我们可以根据这些数据中越来越细微的偏差和趋势,做出越来越自信和笼统的断言。

Handy visualization of statistical power from rpsychologist.com

在许多情况下,大样本量是主要的关键,例如火箭科学:精确度是王道,学术声誉岌岌可危,跨越一些统计置信阈值可能会验证对我们的生存至关重要的一些事情的一生的调查,比如大爆炸理论:

I’ve never seen anybody more excited by standard deviations

正如大数据一样伟大,也有理由为小数据(带有故意讽刺的大写字母)做准备,在这里我将加入制作它的合唱团。

或多或少

对于一些应用来说,大数据可能大,比如直觉概念化和讲故事。还有一个事实是,获取大量高质量的数据集存在障碍。

在这里,我引用《科学美国人》的艾米莉·雷阿斯的话,她在她的文章“我们的大脑有一张数字地图”中提到了“人类顶叶皮层中数字数量的地形图”:

有一个小的大脑区域沿着一个连续的“地图”代表着数量正如我们沿着一条心理“数字线”组织数字,左边一个数字,右边一个数字,数量映射到大脑的空间。这个大脑区域的一侧对小数字做出反应,邻近的区域对大数字做出反应,以此类推,数字表示向远端增加。

此外,

[荷兰乌特勒支大学的这些研究人员]发现,顶叶皮层图代表相对数量,而不是绝对数量。

例如,当以十为单位考虑货币时,我们所关心的只是多了或少了个逗号。在给昂贵的东西定价时,我们不会想象一堆正确大小的百元钞票,我们只是将 T21 与其他类似东西的市场价格(本质上只是一个符号,甚至不是一个我们可以概念化的数字)进行比较。我们了解三角洲。我们这些虚弱的生物不得不将大量的数字抽象到外部设备中,以便进行操作,特别是为了获得意义。我们降低维度,我们分类,我们绘制数据,把它降低到我们可以消化和行动的规模。我们把大数据变小,看它和它隐含的模式。

Speaking of Digestion

麦当劳在售出第 990 亿个汉堡后,停止公布这一数字。没人在乎了。他们只是在 990 亿人面前扔了个“大于号”。宋飞有一个关于这个的片段。他明白了。再卖出 100-150 亿美元不会改变我对麦当劳的看法。

斯大林在统计学上是对的。虽然我不同意,因为 100 万人死亡肯定是非常悲惨的,但我同意人们很难想象大的数字、总量和平均数。这些不会像个人账户(由附带的小数据支持)那样在情感上打动我们。

少即是多

2013 年 10 月,五次当选的 CMO·艾伦·邦德参加了数字脉冲峰会,主持了一个关于“小数据”的小组讨论,并带回了这个定义:

小数据将人们与及时、有意义的见解(源自大数据和/或“本地”来源)联系起来,这些见解通常以可视化方式进行组织和打包,以便可访问、可理解并可用于日常任务。

我不想把重点放在让大数据变小的实践上,因为我们已经用 python 的可视化库做了很多,而是更多地关注小批量、本地来源(我敢说是手工的吗?我想成为下流的布鲁克林潮人吗?)数据,并突出其个人成分。小数据比大数据具有更大的个体相关性和情感权重的能力。仅仅因为我们不能在数据集上运行最先进的、渴望样本的机器学习模型,并不意味着它没有意义!(我现在这样告诉自己,就像面包屑一样,就在我几周内学会如何利用神经网络之类的东西之前。)

在 LitHub 的文章“小数据是新的大数据”中,Marta Bausells 写道:在“亲爱的数据”中,一组插图明信片代表了他们在一年的生活中收集的看似平凡的数据,Giorgia Lupi 和斯蒂芬妮 Posavec 写道:

从生活中收集的数据可以是这个世界的快照,就像一张照片捕捉到了瞬间一样。

Excerpt from Dear Data

摘自玛丽亚·波波娃的前言:

Lupi 和 Posavec 从大数据均质化聚合控制中重新获得了个人的诗意粒度。出现的是一个小数据的美丽及其故意解释、模拟可视化和缓慢传输的案例——一个对无限小、不完整、不完美、但惊人的人类细节的庆祝,通过这些细节,我们从生活中所有可能经历的不可理解的浩瀚中汲取意义。

我和我的一些数据科学训练营同学要感谢 Jaime Cheng 带我们来听 Lupi 在哥伦比亚大学与 The Pudding 一起谈论亲爱的数据、以及更一般的小数据。

作为一名正在恢复的电影业工作者和低成本独立电影的爱好者,我认为平凡中有神奇:关于人性和社会的一些最深刻和最相关的真相只能在个体、正常的人类尺度上看到,这就是为什么我不能忍受超级英雄电影。老实说,炸丨药先生比托尼·史塔克更有关系。

Take the Mundane and make it Extra: Indie filmmaking 101

这个比喻开始变质了,所以我们继续。

虽然多种形式的寓言是道德和行为影响的主要载体之一(咳咳广告),但小数据的应用并不严格限于讲故事:在他的中期文章“为什么小数据是人工智能的未来”中,Bradley Arsenault 认为公司可能很快就会处理小数据,因为:

许多致力于真正新颖解决方案的人工智能公司不得不手动收集这些解决方案的数据集。对人工智能初创公司的资本投资中有很大一部分被投入到收集使他们的产品工作所需的数据集。

如果你能让你的机器学习模型很好地处理小数据,那么你就能在研究、调查、实验或任何你用来生成数据的事情上节省时间和金钱。

明白了吗

数据科学最难的部分之一是获得好的数据来使用(并管理它)。从互联网络下层区域搜罗的数据并不总能激发人们对其收集和组织方法的信心。也许它又旧又硬。雇主提供的数据可能不完整、不可用或根本不存在。

也许我们受到了亲爱的数据的创造者的启发,我们想尝试收集我们自己的数据,你知道,为了娱乐和运动。我们如何得到它?让我们得到它。

我发推文给 Lupi,问她如何收集她的小数据:

http://www.reporter-app.com/

用手吗?如果你像 Giorgia 一样有才华,你可以利用这种模拟魅力来销售价值不菲的咖啡桌书籍,但我没那么有才华。当我知道我将在熊猫中工作并在网上可视化我的数据时,我看不到中间模拟步骤的意义,而且我不会画画。

使用电子表格?当然,但是保存 GPS 数据呢?我更愿意在移动设备上收集数据,在移动设备上浏览电子表格一点也不好玩。

我喜欢这个专门构建数据收集应用的想法。不过我用的是安卓手机,所以 Lupi 的推荐记者对我不起作用。我去寻找替代方案,结果出奇地少。SocialCops 有一款兼容 android 的数据收集应用,名为 Collect ,但它们的价格让我感到害怕。我不是一个完全资助的非政府组织。

My project(s) might take longer than the free one-week trial

这是我发现开放数据工具包 (ODK),“一个开放和热情的社区,就像你一样!”他们的安卓数据收集工具 ODK 收集看起来很有前景。

ODK 收集首先是一个笨拙的:它是一个开源社区项目,而不是一个精致的消费者应用程序,所以在开始记录数据之前,你必须阅读一些文档并熟悉它。(我提交了一份与定位服务相关的错误报告,并收到了一份自行修复的邀请..!确实是开源的。一旦我找到一周的空闲时间来学习 Android 开发环境,我就会让它发生。)

这里有一个在 ODK 收集小数据的快速入门:

  • 使用 ezpz 工具 ODK 构建构建您的空白调查,如我所做:
  • 通过以一种非常特殊的方式格式化一个电子表格来构建您的空白调查
  • 将^转换为正确格式。使用此工具将 xls 转换成 XML
  • ODK 收集应用程序中将空白表格全部加载到你的安卓设备中
  • 让我们开始填写空白表格并提交!

Making a Survey about Laundromats

ODK 收集的好处是你可以把它和谷歌文档连接起来:通过在空白表格的设置标签中设置submission_url,你可以让每个提交的表格自动填充到谷歌表单的一行中。我们可以高枕无忧,我们的数据被备份在云中,以后在 Pandas 中以 xls 或 csv 格式下载/导入这些数据将变得很简单。

以下是我在 ODK 收集填写表格时的一些截屏:

我提交填写好的表单,我的 google 表单被配置为自动填充,所以数据出现了——包括经纬度坐标、布尔值、浮点数、时间戳和 uid。你真的可以骗过你的表格。

The first row of my small data set!

然后,我们可以将电子表格数据下载为. csv 或。xls 和导入熊猫(在 jupyter 笔记本中):

比笔和写字板流畅多了,可持续!任何数量的训练有素、合格的数据收集人员都可以使用该表格进行调查,所有人都填写同一个电子表格。我要提到的是,ODK 是面向非网格数据收集的:在偏远地区,只要有重要的人道主义项目要开展,无论有没有 cel 数据,你都可以使用这一工具。

另一种****收集调查数据的方式可能更明显,那就是通过发出谷歌表单来众包。这些很容易创建并一起发送出去。响应滚滚而来,web 应用程序中有漂亮的小可视化,你当然可以通过点击按钮将数据转换成电子表格形式,以便下载和进一步调查。

****

Google forms: EZPZ

We could then bring this spreadsheet into pandas again.

发送电子邮件或网络调查的一个缺点是,你会相信回答者会提交准确的信息,但情况并不总是如此:你可能会用质量代替数量,这不符合小数据的精神!

已经写了如何正确收集数据。知道有一种错误的调查方式。就像在许多领域一样,即使你有技术来有效地做这件事,你也可能做得不正确。不要那样做。在你走之前,不要只看这篇博文。

我希望这能激励不同学科和不同技能水平的数据科学家考虑创建他们自己的小数据集——并且用爱来创建它们!丙:

进一步阅读

“甚至有一本马丁·林德斯特罗姆的营销研究书, 小数据:揭开巨大趋势的微小线索”提到了加里·克莱因博士,为今日心理学撰稿。

小步预测

原文:https://towardsdatascience.com/small-steps-a-experimental-case-for-compound-prediction-2555cdcec78f?source=collection_archive---------18-----------------------

复合预测的一个实验案例

揭示变量之间的抽象非线性关系是机器学习提供的效用。然而,从已知输入直接跳到抽象相关的期望值会产生最准确的结果吗?在一系列更密切相关的变量可以首先被预测并反馈到模型中以预测最终产出的情况下会发生什么?

假设这种方法的一般结果是很棘手的。一方面,传统的工程方法表明,复合误差、不确定性和多次预测迭代的舍入将导致输出预测的不准确性增加。然而,输入和输出变量之间的关系越抽象,机器学习模型就越难准确预测输出,尤其是在有多种可能的输入情况并且模型没有过度拟合的情况下。也许简单地进行实验是最好的。

为了从实验上检验这一概念,有必要获得具有数学上精确的输入和输出的数据。为此,我使用了一个六连杆机构的运动学数据,该数据是针对输入角度以及沿着其中一个杆的特定销的位置(枢轴位置)而迭代计算的。这些数据既有越来越抽象相关的变量,也有已知的输出。

正在讨论的机制如下:

Vector loops based on which the mechanism’s kinematics are analyzed

在这种情况下,DC 杆的角度旋转了一整圈,以计算每个位置的运动系数(一阶和二阶)、角度和角速度(1 度增量)。对沿着条形 DC 的销 O2 的不同位置重复该过程,同时保持条形 DC 的总长度。

运动学变量之间的一般关系如下:

分析这两种方法精度的过程包括预测一阶运动系数(h’)。第一种方法,姑且称之为“复合预测”方法,包括顺序计算θ、h、w 以及随后的 h’值。第二种方法,让我们称之为“巨大的飞跃”方法,包括使用上面给出的最终关系中的变量直接预测 h′。

数据可视化

为了直观显示运动变量的复杂性,可以参考下列图表(按照抽象程度增加的顺序,按照顺序求解的顺序)。

Linkage angles with respect to the input angle Theta 2

First order kinematic coefficients ( h ) with respect to input angle Theta 2

Angular velocities (w) with respect to input angle Theta 2 and input angular velocity w_1 (1 rad/s).

First order kinematic coefficients ( h ) with respect to input angle Theta 2 and input angular velocity w_1 (1 rad/s)

模型设置

对于这个实验,有必要创建一个在两种情况下都保持不变的模型。在不同情况下改变模型会产生太多的变量,以至于无法根据最终结果得出结论。由于这是一个回归任务,但也是非线性的,所以我选择使用神经网络(Scikit 中的 MLPRegressor 为了简单起见而学习)。手动优化模型参数后,我决定采用 150,75,25,10 的锥形隐藏层模式,以“relu”作为激活函数,500 个连续时期的截止容差为. 000010,最大迭代次数为 10,000 次。

两种情况下的培训设置;然而,会有很大的不同。“巨大飞跃”方法将在数学求解最终结果所需的最少数量的输入变量上进行训练。“复合预测”方法将基于中间变量(θ,然后是一阶运动系数(h 值),然后是角速度(w 值),然后是二阶运动系数(h '值)的连续预测来求解。

结果

提醒一下,两种情况下的输出变量都是 h'3、h'4、h'5 和 h'6。此外,平均 R 值(决定系数)将用于比较结果。

让我们从分析“巨大飞跃”预测案例的结果开始:

Second order kinematic coefficients predicted based on input theta 2 and link lengths

可以看出,这些预测并不那么精确。它们确实显示了一个具有合理累积准确性的总体趋势;不过波动比较大。这些结果不适合任何工程任务,并且不是最佳的。

现在,让我们看看复合预测方法在整个预测过程中的结果。

Predicted values of theta based on link lengths and input Theta 2

First order kinematic coefficients ( h ) predictions based on link lengths, input theta 2, and theta prediction values

Angular velocities ( w ) based on link lengths, predicted theta values and first order coefficients

Second order kinematic coefficients ( h’ ) based on link lengths, predicted theta values, first order coefficients, and angular velocities

讨论

基于决定系数,“复合预测”方法的结果远比“巨大飞跃”方法更准确(平均 R 为 0.9773 对 0.8745)。尽管基于预测值进行预测会产生复合误差,但这是事实。给定必要的输入参数,输入和输出变量之间的关系对于“巨大飞跃”方法中使用的当前模型来说简直太抽象了。另一方面,该模型足够稳健,能够对中间变量进行准确的顺序预测,最终达到对最终产出的准确预测。

我想承认这些结果有一些局限性;虽然,这远远不是一个完整的列表。首先,网络的大小在案例之间没有改变。也许如果对用于“巨大跳跃”方法的网络进行足够的调整,它将具有更好的准确性。第二,测试规模只有几千个数据点,拥有更多可能会改善结果。第三,网络参数是通过几次反复试验选择的,决不是要理解为这个特定任务的最佳网络。第四,决定系数可能不是给定模型有效性的最佳衡量标准。

结论/TLDR

我希望通过这篇文章和小实验传达的是,可能有这样的情况,即做出更小、更简单的预测,直到最终的预测,这是一个值得探索的策略!例如,预测土地的价值、建筑物的价值、家具/器具的价值等,而不是基于一堆指标来预测房子的价值。然后根据这些值进行最终预测。

我并不打算把这个测试的结果作为一般规则来传达,只是作为一个发人深省的例子来提出这个问题,以便进行更深入、更详细的探索。

如有任何问题,请联系我们。此外,如果有人想要数据集,请给我发消息,我可以让它可用。

小胜利:用 Django 和 AWS 构建一个 Web 应用并建立信心

原文:https://towardsdatascience.com/small-victories-building-a-web-app-with-django-and-aws-and-building-confidence-8ee9d29d744e?source=collection_archive---------4-----------------------

^^^That 是我用手机在电脑屏幕上拍的照片,前几天我高兴地把它上传到了我的个人社交媒体上。(是的,我真的是那种极客…)它代表了我的第一个 web 应用程序原型的成功测试,该应用程序在现实世界中运行(托管在我建立的免费 AWS 实例上)。我是 11 月 8 日拍的上图,原型机还在成功运行。

我称之为一个小小的胜利,因为我意识到,对于技术领域更有经验的人来说,这似乎非常容易。但对于一个在我今年早些时候参加数据科学训练营之前从未上过正式计算机科学课的人来说,终于更全面地理解了 web 应用程序这样的东西是如何工作的,这是一个启示。我自己能做到这一点真是太棒了。

Ooh, what’s that under there? Looks exciting!

这篇文章是我非常喜欢的 Chipy(芝加哥 Python)导师项目的要求系列文章的第三篇。自从我在的上一篇文章以来,在我曾经很有能力的导师乔·贾辛斯基的帮助下,我已经了解了姜戈很多新的方面。今天,我想我会把重点放在这个应用程序将要做的数据收集上,而不仅仅是为用户提供一个微小的服务。

正如我之前提到的,我是一个完全的数据极客——就我而言,一个人能收集的数据越多越好。我长期使用基于 SQL 的数据库,包括运行我的主要客户项目MyBodyGallery.com的大型数据库。我很高兴 Django 自带了创建 SQLite 数据库的内置功能(如果我想的话,以后我可以改成更好的 Postgres 或 MySQL)。我不一定需要一个数据库作为这个应用程序的一个功能(我没有存储数据的,但它是一个受欢迎的附加功能。

我这次指导的主要目标是让我创建的数据科学模型(一个纹身书流行度计算器)在现实世界中运行。我本可以让 web 应用程序告诉人们计算器的答案,然后消失在太空中,而不存储他们的查询或其他任何关于他们或他们与应用程序的用户交互的信息。但是第二个 Joe 向我提到,我们可以将用户查询存储在一个表中(在 Django 中称为模型,只是为了让事情变得更加混乱——阅读文档这里),这让我的大脑转动起来,我想到了一些其他类型的数据,这些数据非常适合存储用于未来的分析项目。

With all the right data, we can take over the world!!! (I’m probably dating myself with this cartoon reference.)

我成功的 web 应用程序的手机照片可能很有吸引力,但这里有一个非常基本的原型应用程序界面的截图,用户可以在这里输入他们的书名查询。屏幕最初看起来是这样的:

Pink is my favorite test color.

然后,一旦用户输入他们的查询,它会在同一个页面上输出如下内容:

Note: Right now all the queries result in a hard-coded number of 20 libraries — the web app does not incorporate the calculator model yet.

用户查询存储在一个 SQL 表中(在 Django-speak 中称为模型),在本例中称为 QueryLog。Joe 教我如何进入并充实表将收集的数据。Django models 文档有许多可以包含的字段类型——如果您有兴趣的话,一定要读一读。稍后我可能会添加一些其他字段,但是现在我将收集一些显而易见的信息,比如查询本身、它是否被查看过、它是何时创建的以及它最后一次被修改的时间。乔建议添加一个“desc”字段,这基本上允许我在输入任何特定查询后进行记录;我也可以将这个领域用于其他各种可能的用途。

对我来说,重要的是跟踪查询来自哪里。这在表中有两种形式:首先,我想记录原始网站(这将在以后的课程中介绍——“website _ origin”的代码现在只是一个占位符)。至少,我会把这个放在我的 centerfortattoo.org和 tattoohistorian.com网站上,这样我就能,比如说,快速地找出哪个网站的流量更大。我也有一个想法,我可以把这个代码放在 Github 上作为开源,其他面向纹身的网站也可以嵌入计算器。如果发生这种情况,我想知道这些查询是从哪里发出的,以此来跟踪还有谁在使用这个应用程序。

其次,我认为跟踪每个查询的 IP 地址会很有趣。我可以利用这些 IP 来分析用户的地理分布。Joe 建议使用 Django-ipware 来实现这一目的,它确实有效(我让我值得信赖的测试员,也就是我那令人敬畏的男朋友从远处输入一些查询来进行测试)。下面是我的代码中概述所有数据库表字段的部分:

This models.py script sets up all the different types of fields in the QueryLog table. I can add more if I want to. I just then need to run manage.py make migrations and then migrate to make those additions actually happen.

当您运行构建所有股票框架代码的初始 Django manage.py startapp 命令时,Django 会自动创建一个漂亮的管理仪表板。您可以通过在测试 IP 的末尾添加/admin/并导航到它来访问这个仪表板。您还需要将自己设置为超级用户才能使用它。这是通过 AWS 运行的管理仪表板的外观——当你从自己的机器上运行服务器时,它看起来更好,但 Joe 提到我们必须在托管版本中调整一些东西。但现在还有效,所以谁在乎呢?

这已经是一个很长的帖子,所以我没有时间来解释这个问题,但 Joe 教我如何添加代码,以便在“计算器”(这是这个应用程序的名称)下的管理面板中,你可以访问“查询”,它提供了 QueryLog 表中的所有数据。瞧:

目前,我们将管理仪表板 QueryLog overview 设置为显示查询、查询创建日期和任何修改日期。稍后我会添加一些我想看的其他东西的专栏,比如 IP 和网站来源。

是的,在测试代码的时候,你肯定会对我的思维状态有所了解。“他妈的耶”,“我喜欢猫!”,还有《狗真恶心》(那只狗刚走过来,流了我一胳膊的口水)肯定是令人兴奋的、有头脑的书名。我要补充的是,问题 14-17 来自我的男朋友,我想这告诉了你他有多棒。得到一句“我爱你!”通过你的原型网络应用程序发送信息,甚至发送两次,是非常令人惊奇的。

Love you right back, honey! (Readers: I’m a woman in tech. I can be a bit sappy. Deal with it.)

如果您单击用户输入查询条目的行号之一,您可以看到关于每个查询的更多信息。你也可以进去改变这里的一切。您还可以在管理面板中将某些字段设置为不可更改的(您可以在这里看到创建和修改日期以及 IP 的示例——这提醒了我也需要对查询本身执行此操作)。下面是我们设置 IP 跟踪之前的完整查询记录的一个示例(因此是硬编码的 1.1.1.1 占位符地址):

好了,今天有时间就写这么多。但是请继续关注:尽管这个项目只需要一个由三部分组成的博客,我肯定会创建至少第四部分来宣布最终项目的启动和运行。我想我能做到。我知道我能做到。我给这篇文章加了副标题:建立一个网络应用程序……建立自信是有原因的。

我在这个新冒险中的每一步都让我对自己的编码技能越来越有信心。我甚至考虑在 40 多岁的时候重返校园,攻读某种计算机科学学位,以增加我的收藏。(我真的很后悔没有从一开始就获得这个学位,尽管幸运的是,今天我们有很好的继续教育机会,比如针对我们这些处于职业生涯中期的人的训练营和导师项目。)

对于我的下一步,至少,在导师计划于 12 月中旬结束之前,我需要花一点时间清理计算器模型(及其各种子模型)并为用户输入的查询编写一个适当的数据管道。然后我需要想出如何将它嵌入我现有的 Wordpress.com 网站(目前的想法是用 iframe,但我知道 Wordpress 用 iframe 会很奇怪…)。咻。我能做到!如果我能让它看起来漂亮,那将是锦上添花。我一定会得到一个漂亮的蛋糕来庆祝!

Belle’s got the right idea. Maybe some pastries and wine are in order too 😃

智能城市:普通市民一直是缺失的一环

原文:https://towardsdatascience.com/smart-cities-ordinary-citizens-were-the-missing-link-all-along-7487e1753e10?source=collection_archive---------2-----------------------

首尔一名学生的一条推文让每年的汽车出行减少了 230 万次

当你听到的都是自动驾驶汽车和人工智能等高科技概念时,很容易感到与智能城市的对话疏远。但到目前为止,实际建设智能城市的经验告诉我们,我们必须首先从人开始。当城市在搞清楚技术的用途之前就购买了昂贵的技术,这就犯了错误。在阿姆斯特丹,市民不仅提供想法,还提供资金、人才和专业知识来创建真正需要的智能城市解决方案。

第一步:合适的人——公民、政府和人才

2012 年,首尔一名学生的一条推文使每年的汽车出行减少了 230 万次,每年为居民节省了 40 万美元,并使城市在夜间更加安全。这条推文是对市长的一个建议,移动电话公司的电话和短信数据可以用来绘制城市地区的深夜出行地图。这些数据可以用来在首尔地铁停止运营的午夜和凌晨 5 点之间为公交车引入更好的路线。当市长将这个想法转发到他的脸书主页上时,3 万多名居民立即支持了这个计划。

韩国电信免费提供了超过 30 亿条匿名电话和短信记录,他们与首尔市政府一起对这些记录进行了分析。因此,如果一个人用他们的移动电话从市中心打电话,然后,一个小时后,从城外发短信,这将被标绘为一次旅行。他们很快确定了最繁忙的路线,并提供了“夜猫子”巴士来覆盖它们。试点项目立即取得了成功,除了已经提到的改进之外,还减少了非法出租车的数量,减少了污染,振兴了深夜经济。

与公民接触至关重要

智慧城市要想运转,首先需要的是人。使用交通工具、呼吸空气和制造废物的是公众。他们产生的数据是对诊断问题和找到解决方案都至关重要的反馈。过去,城市只是打击无证出租车,或者依靠耗时的人工问卷来确定该地区最需要的交通工具。首尔的解决方案使用已经数字化的预先存在的被动数据进行高效分析。我们不要忘记,首先提出解决方案的也是一个公民——避开了在市政厅召开冗长而昂贵的解决问题会议的通常过程。从数以千计(如果不是数百万的话)不同经验和专业知识的公民中众包想法,比询问一小组政府官员要好。

合适的人并不总是最明显的选择

然而,你仍然需要合适的管理人员来协调你的智能城市。在首尔夜班车事件中,如果市长没有在社交媒体上与市民互动,并积极选择分享推文,该项目就不会存在。在运营阿姆斯特丹智能城市六年后,Ger Baron 向市政府建议,他们需要一名首席技术官来调解其智能城市过渡。这既是为了防止私营企业的需求超过公众的需求,也是为了确保这座城市愿意灵活地制定法规,以跟上创新的步伐。该市拒绝了 Baron 提出的候选人,而是更愿意给他这个职位,因为他有这样一个新项目所需要的确切经验。

当荷兰首都的市政当局决定他们也需要一个“夜间市长”来解决该市政党区的噪音、垃圾和暴力问题时,他们举行了投票。一个由五名专家、音乐节与会者和公众组成的小组选择雇用一名经验丰富的俱乐部发起人,而不是另一名公务员。Mirik Milan 已经与酒吧老板和用户建立了关系,了解规则,最重要的是,对夜生活有着真正的理解和热情。在接受《卫报》采访时,他说他想做些不同的事情,因为当人们抱怨时,城市当局的本能是“实行宵禁,收紧法规,关闭场所,禁止东西。这是可以理解的:如果你在市政厅,对晚上发生的事情毫无头绪,你怎么能制定好的法律呢?”

他所不具备的是官僚专业知识或权力,这就是为什么与日间市长办公室的联系如此重要。米兰告诉花旗集团,他最自豪的成就之一是能够向场馆授予 24 小时许可证。他确保他们不在居民区,并能证明他们会策划他们的议程,以确保他们为城市增加文化价值,而不仅仅是促进夜生活和旅游经济。此外,当俱乐部成员在凌晨 5 点被驱逐出会场时,街道上突然出现了很多混乱。24 小时营业的许可证让夜晚更自然地结束,这意味着当人们离开时,他们是在一个可管理的流中这样做,并直接回家睡觉,而不是继续聚会。对俱乐部和居民都好

解决方案应该惠及所有人

24 小时营业执照之所以成为可能,是因为与阿姆斯特丹夜生活相关的反社会行为和犯罪减少了。同样,解决方案来自于选择正确的人。该市的警察太忙了,无法对每一个电话作出反应,等到有人向市政当局投诉时,处理几天或几周前造成问题的人已经太晚了。所以安装了“方形主机”。他们是训练有素的社会工作者,可以充当警察、居民、俱乐部和狂欢者之间的无所畏惧的交汇点。虽然他们的主要目的是让参加聚会的人保持秩序,但他们也可以为那些寻找方向、选择哪个俱乐部或最近的厕所的人提供友好的建议。下一阶段包括计划创建一个应用程序,以便居民可以立即将任何问题转达给社区官员,社区官员将通知地面上的广场主持人。

你需要的最后一群人是人才,那些拥有促进创新的技术专长的人。在首尔,数据科学家必须用算法或人工智能来收集和分析证据。市长想要的市民投诉实时应用程序可能需要前端和后端开发人员,UX 和用户界面设计师。因此,想要成为智能城市的人必须吸引人才,激发创意,并为创新者的蓬勃发展提供支持。借助城市数据、阿姆斯特丹智能城市挑战赛和循环挑战赛等激励措施,阿姆斯特丹正积极推动变革,通过一个共同的目标将各个群体联系起来——改善城市区域。就国内而言,荷兰已确保其拥有具有竞争力的基础设施、优惠的税收和稳健的国际旅游框架,这也是网飞和优步等几家大型科技公司将欧盟总部设在阿姆斯特丹的原因。

对于创业公司来说,阿姆斯特丹是一些孵化器、加速器和政府支持的计划的所在地,如 StartupDelta 和 Startup Amsterdam。稍远一点的代尔夫特大学继续培养年轻人才,他们与美国阿姆斯特丹的 AMS 学院和麻省理工学院密切合作。埃因霍温仍然被认为是世界上最具硬件创新的城市之一。根据经济合作与发展组织的数据,2013 年,该市平均每 10 万居民拥有 23 项专利,与之最接近的竞争对手圣地亚哥只有 9 项。

步骤 2:基础设施—连接性、隐私和安全性

正如我们刚才提到的,在许多项目成为现实之前,您的智能城市将需要高速宽带、传感器和物联网连接等基础设施。然而,它在我们的列表中排在第二位,因为在过去,城市规划者在知道它将有什么用途之前就仓促行事,大量投资于基础设施。这就是为什么你必须首先依靠人们来确定问题并提出解决方案,这样你就知道需要建立什么。

但是,如果没有收集和分析城市数据所需的传感器、节点和应用程序网络,这些智能城市计划很难奏效。对阿姆斯特丹来说幸运的是,荷兰政府已经投资了高速宽带。然而,对于像物联网这样的庞大网络来说,大都市需要低电池使用量、远程和低带宽的网络,而 LoRaWAN(远程广域网)正是这种网络。它允许东西在没有 3G 或 WiFi 的情况下与互联网“对话”。

连接物体、设备和人

物联网成立于阿姆斯特丹,是一个“全球化、众包、开放、免费和去中心化的物联网网络”。他们的设备成本大约是目前最流行的 LoRaWAN 网关的 20%,提供 10 公里的覆盖半径,服务多达 10,000 个节点。网关是所有事物和互联网之间的路由器,而节点是附在每个“事物”上使其连接的设备。例如,可以在运河船上放置一个节点来探测水。如果节点中的传感器检测到泄漏,它将通过 LoRaWAN 网络向网关无线发送警报,网关连接到互联网,并可以向您的手机发送消息。

目前,在各大洲 23 个国家的 82 个城市中有 1380 个活跃的网关。24777 名开发人员已经注册,他们已经部署了 11444 个应用程序。考虑到每个网关仅花费€200 英镑,而且仅用 10 个网关就覆盖了整个阿姆斯特丹市,这还算不错。该公司现在还为开发人员推出了支持 LoRaWAN 的 Arduino 单元,以及一种更简单的设备(node ),该设备已经包含温度、运动和光线传感器,适用于那些希望参与其中但不太懂技术的人。本着该项目的精神,他们也将开放所有的代码和设计。

信用:下一个网络

平衡公私利益

物联网是利用众筹来避免官僚主义拖延的一个例子。说到智能城市,政府制定政策和立法的通常方法可能效率低下。随着数据的实时收集和创新发展步伐的加快,预测或调整法规以适应新趋势和变化变得越来越困难。直到最近,阿姆斯特丹仍在使用基于五年前统计数据的交通管理模型,这些模型已不再适用,因为自 2011 年以来,汽车使用量下降了四分之一,摩托车使用量增加了一倍。

然而,一个有助于引导城市发展的独特愿景是必要的,以避免过去规划不当的发展所犯的错误。经常被引用的例子是美国州际高速公路系统的破坏性影响,它很好地改善了各州之间的交通,但是,通过直接穿过市中心,该项目也破坏了街区,导致大量人口和企业在郊区流离失所。通常,越是贫困的公民损失越大。

正如阿姆斯特丹的第一任首席技术官 Ger Baron 必须尽力平衡公共和私人利益一样,同样的规则也必须适用于全国和全世界。这正是联合国试图通过其国家城市政策指令鼓励的。该政策侧重于为城市的长远未来发展一个包容性的全球基础设施。这意味着为所有社会成员服务,不论性别、种族、财富、阶级,也不论他们是否喜欢在凌晨睡觉或聚会。它试图涵盖更广泛的问题,如生产可持续能源和回收日益减少的原材料库存,但也对每个城市特有的较小问题提出建议,如阿姆斯特丹运河船上的大声音乐或巴塞罗那的停车位。在 Eli5,我们为 Mobypark 创建了一个平台,这个应用程序允许你在世界上最繁忙的一些城市租赁停车位,包括我们的家乡阿姆斯特丹。与一些路边停车费相比,这为司机节省了高达 70%的费用,平均 20 分钟就能找到一个停车位,这也意味着租用的停车位得到了充分利用。此外,停车位所有者可以从租赁中获得少量收入。

在数据共享方面重建信任

当许多人想到数据时,他们想到的第一个词是“隐私”。公众必须有信心,不仅他们的信息在城市数据库中是匿名和安全的,而且他们可以相信政府会负责任地使用他们的数据。这意味着使用公共数据来造福城市,而不是被企业滥用来获利。

DECODE——即分散化的公民数据生态系统——是一个为期三年的项目,由 EU-资助,旨在改善数据共享的体验。他们的一个试点项目将于 2017 年底在阿姆斯特丹和巴塞罗那推出,1000 名测试人员将能够准确选择他们想要上传的关于自己的信息。重要的是,他们还可以决定如何使用以及由谁使用。因此,他们可以选择参与一个特定的计划来管理他们街道上的垃圾,同时向私营公司隐瞒这些信息。DECODE 还将利用区块链技术来确保信息安全,防止黑客攻击。

来自英国创新慈善机构 Nesta 的 Tom Symons 正在研究 DECODE,他告诉《新科学家》杂志(New Scientist)说,“人们并不能真正控制他们的数据”。DECODE 已经公开批评网络公司不共享他们从公众那里收集的数据,以造福社会,就像韩国电信对夜猫子风险投资所做的那样。

步骤 3:合作:国际、国家和个人

所以现在你有了合适的人,技术,法律基础设施,来自你的城市和市民的数据,你就有了开创性的智慧城市想法。

现在你需要开发、验证和实现你的项目。为此,你必须找到资金,最好是一些专家的指导。您可以通过地方、国家或国际层面的捐赠、众筹、激励、竞赛、奖励、公共部门支持或私营部门投资来筹集资金。

正如物联网所证明的,众筹可以成为项目融资的直接解决方案。鹿特丹的另一项提议是,在一个办公楼开发项目告吹后,建造一座临时木桥,连接该市被公路和铁路封锁的部分地区。8000 多名捐赠者每人给了€25 英镑——奖励是把他们的名字刻在一块木头积木上——理事会批准了这个计划。Luchtsingel 桥现在有 390 米长,有 18 个桥,连接鹿特丹的北部和中心。荷兰在线平台 Voor Je Buurt 现在每年处理数十万欧元的公民众筹捐款,以资助对其社区至关重要的项目。

用人们的语言与他们交谈

由于他们自己忙碌的生活,很难让社区对可持续发展这样的大问题感到兴奋。但你不能只是假设公民想要什么。否则,你的冒险会失败。碳扫盲项目认为他们找到了答案。去年,他们开展了一项让曼彻斯特及其周边地区的人们对气候变化感兴趣的计划,最终招募了令人印象深刻的 4000 人。他们的方法只是不关注你认为重要的事情,而是关注对你试图参与的社区来说重要的事情。这篇阿姆斯特丹智能城市文章中引用的例子是减少开车去看比赛的足球迷的数量,不是告诉他们这对环境更好,而是提到他们关心的事情,如省钱,不用担心停车,与朋友一起旅行,可以在比赛时分享啤酒。或者通过与团队本身合作来传达信息,并促进对作为一个集体共同努力减少排放的自豪感。

我们现在已经兜了一圈,回到了人民身边。通过合作,你让更多的人参与进来。更多的人意味着更多的数据。更多的数据意味着更多的项目,更多的专家。他们需要基础设施和援助来启动他们的项目。所有这些造就了一个智能城市。

2017 年智能家居状况

原文:https://towardsdatascience.com/smart-homes-safety-stability-and-trust-4ff1e270b2ee?source=collection_archive---------1-----------------------

Shiny sparkly hyper-futures always turn people off. This looks like the childless home of an Alpha class in Gattaca.

智能家居仍然是一个年轻的类别,但它反映了数字化、连接性、效率和安全性的深刻趋势。对于平台领导者来说,进一步殖民家园也是一场漫长的游戏。更有趣的是,这可能是对我们正在出现的气候危机的必要回应。然而,随着这一类别的成熟,在建立信任和价值方面存在巨大挑战。

虽然我们似乎正在走向智能结构的未来,这些智能结构能够感知其居民,并积极地模拟和管理他们的需求以及房屋的物理需求,但智能家居的全面承诺尚未实现,可能需要十年才能实现任何有意义的存在。

市场

分析师估计,到 2020 年,该市场的价值将在 500 亿美元至 1500 亿美元之间——这是一个相当广泛的分布,现在包括 wifi 扬声器和 Alexa 语音助手等产品,但大多数都没有集成的家庭管理系统。一个支持 Spotify 的 wifi 扬声器几乎算不上物联网,也无助于家庭的智能。类似地,使用智能手机控制照明也只不过是界面更新。因此,值得注意的是,“智能家居”的标签正逐步被“互联”和“智能”所取代。

不进行大规模的改造和更强的人工智能,更便宜的公用事业账单和知道你是谁的房间的承诺仍然遥不可及。

目前的智能家居市场由安全和娱乐主导,这两者都不是新的类别,而且都主要依赖于愚蠢的技术。从战略上讲,安全性是构建更多服务的支柱和(希望)收入渠道。娱乐主要是由集成了流媒体音乐服务(如 Spotify)的无线扬声器驱动的。

在这些部分之后是连接的固定装置,如照明、门铃和锁,以及各种传感器。这些往往服务于更高端的早期采用者和技术极客。也有一些利基交钥匙家庭自动化供应商,主要迎合富裕的技术人员,但普通人不太关心不均衡的未来。

不进行大规模的改造和更强的人工智能,更便宜的公用事业账单和知道你是谁的房间的承诺仍然遥不可及。然而,智能家居的愿景继续推动着双方的市场,朝着未来努力,在未来,家居可以主动降低我们的水电费,管理我们的废物循环,简化我们的时间表,个性化我们的娱乐,保护我们的家庭,保护我们的健康和福祉。

玩家

消费物联网和智能家居市场一直很大&很分散,但现在显示出顶级平台玩家越来越占据主导地位。市场可以分为三组提供商:有线服务、网络巨头和第三方设备制造商。

目前的市场更多的是由供应和愿景主导,而不是需求。

在美国,美国电话电报公司的 Digital Life & Comcast 的 Xfinity line 各自销售基于其现有集线器构建的智能家居解决方案,主要销售支持第三方设备生态系统的远程监控安全选项。这一策略主要是让人们呆在他们的客厅中心,并通过一些不久的将来的机器用户来对冲电话用户的下降。值得注意的是,威瑞森停止了自己的智能家居努力,转而支持其合作伙伴 Nexia。

网络巨头们也在用他们的网络中心占领客厅,但像亚马逊、谷歌和三星这样的数据驱动提供商更有兴趣把它们作为进入他们的云的入口。他们推销娱乐解决方案,如互联网接入、音乐流媒体和灯光控制,吸引互联网用户,而不是有线电视和电信公司的电视用户。

从历史上看,苹果的这种试探性姿态是一个信号,表明他们认为这个类别还不成熟。

亚马逊与 Alexa 的区别在于,它的语音界面带有 API。他们的平台主要是你家的百货商店,并增加了按需仪表盘按钮。谷歌通过 Nest 和 Nest Cam 追求家庭设施管理和安全,最近推出了其 Alexa 竞争对手 home,据传将宣布一个家庭安全解决方案。他们提供了一个与谷歌无处不在的数据机器紧密相连的高端技术产品系列。三星已经采取了一种围绕众多传感器类型构建的模块化方法——一种更实惠、更独特的产品,迎合了想要为家庭安装仪器的修补匠。

值得注意的是,苹果拥有 HomeKit,这是一个用于数据管理和可视化的开发平台。他们没有制造品牌设备,更喜欢依赖第三方供应商,如飞利浦 Hue 照明系统。从历史上看,苹果的这种试探性姿态是一个信号,表明他们认为这个类别还不成熟。

虽然互操作协议主要集中在少数几个标准上,但 M&A 的活跃表明了巨大的机会。事实上,目前的市场更多地是由供给和愿景主导,而非需求。

驱动程序和启用程序

消费物联网设备的爆炸式增长得到了资金容易获得的创新者的支持,这些创新者能够获得廉价而强大的组件和全球制造链。这是一系列试验,试图看看什么是坚持。设备出现了寒武纪大爆发,但几乎没有全面整合。大部分人还是看不到价值。

这是向家庭行为剖析迈出的一步,这对于提供有意义的个性化服务是必要的,但也开始让人感到侵扰和潜在的危险。

采用的主要障碍是成本和不便。随着市场证明价值,组件成本将稳步下降,但在深度学习解决方案投入使用之前,不便将是一个障碍。这种解决方案将利用声音、视觉、数据 API 和训练有素的分类器,而不需要给你的家重新布线。

从主电流中通过算法提取设备特征的能力已经显示出前景。这可以使学习系统通过电器监控来优化能源使用,对水和 HVAC 有类似的模型。由 GE 和 LG 等公司领导的烤箱等联网电器开始获得预测性维护能力,但大型电器可能每 10 年才更新一次,因此存在翻新障碍。

像 Nest Cam 这样的门口摄像头开始接受机器视觉生物识别。这是向家庭行为建档迈出的一步,这是提供有意义的个性化服务所必需的,但也开始感觉到侵扰和潜在的危险,这取决于服务提供商的数据卫生。

Toto 提供了一种可以进行简单代谢分析的马桶,但改造升级周期又是一个障碍。大多数房主永远不会更换他们的陶瓷马桶,如果他们这样做,他们可能不会选择在房子的墙壁之外分享他们最隐私的数据。

随着家庭面临更直接的经济和环境压力,更积极的气候变化可能会推动更多的采用。

解决方案还需要更加灵活和本地化,以应对区域压力,特别是在全球变暖和气候变化重塑环境条件的情况下。例如,一些家庭需要控制空气质量,防止灰尘侵入和过敏原,而其他家庭可能需要优化水的收集。随着家庭面临迫在眉睫的经济和环境压力,更积极的气候变化可能会推动更多的采用。

这一切都在持续的当前转移更多的能力(和责任)回到边缘。电力、食物和水的集中管理不如分散、局部和自我维持的管理可行。

这一切都在持续的当前转移更多的能力(和责任)回到边缘。

为了实现显著的市场渗透,互联解决方案将需要成为新住宅的一部分。正如建筑法规引领绿色发展一样,将更多联网设施引入新住宅也是必要的(人们可能会认为太阳能渗透率是联网家庭解决方案需求的一个指标)。改造之路只能走这么远,如果有承包商参与,许多人不会在意。然而,我们只能通过修复现有的大量住房来减少能源浪费。因此,广泛的增长将由要求下一代节能电器的进步建筑规范下的新住宅引领,随后是翻新的竞争和监管压力。

挑战

有许多挑战应该贯穿于产品策略中。这些问题包括漏洞和入侵、恶意软件和僵尸网络、关键服务中的漏洞、对隐私和数据所有权的担忧、无利可图的遗留平台的衰退以及平台所有者规定条款和服务的能力。这些都是在住房拥有率下降和西方经济增长降温的背景下制定的。未来的家很可能不再是乌托邦式的幻想,而是更注重性价比。

随着市场的增长,如何处理数据和用户如何管理信任将是一个巨大的挑战。

一个基本的挑战是可用性。机械锁很容易使用,电灯开关也一样。拿起智能手机,进行身份验证,启动应用程序,浏览菜单来开灯,并不是一种持久的替代方式。因此,飞利浦色调水龙头,但许多供应商仍然只是使基本任务更加困难。

比可用性更深的是,家是建立在信任和安全之上的。增加连接性为世界打开了更多的孔,正如最近婴儿监视器被网络不满者攻击的故事所显示的那样。同样, Defcon 用一个伪造的客人 ID 击败了八月锁。在采用率足够高以提供有趣的攻击面之前,漏洞通常不会被发现。更多的用户引来更多的入侵。

如何处理数据和用户如何管理信任是一个巨大的挑战。亚马逊的 Alexa 是一个电子商务前端,在你家里有一只耳朵(而且它可以被传唤作证指控你)。Alexa 团队的创始人之一,【Nikko Strom 说“我们收到了数量惊人的数据,我们可以对其进行处理。”这是关于信任:你希望公司在你的房子里攫取更多的土地份额吗?许多用户不会采用将数据传输到第三方的互联家庭解决方案。

这是跨服务生态系统分布功能的一个非常真实的结果:所有权、访问和责任越来越多地在用户和提供商之间共享,并有硬 EULAs 来描述它们。

此外,企业数据所有权已经超出了修复和修补的范围。在制造商禁止他们在现场进行自己的维修后,农民们正在从乌克兰下载非法黑客软件,以便快速修复他们连接的 John Deere 拖拉机。随着采用的增长和用户开始理解其品牌锁定的含义,这种情况将在互联家庭领域出现。

这种水平的读写能力正在慢慢被那些被锁在系统之外或者面临功能被弃用的用户所了解。一位智能家居用户最近发布了他们家中加湿器漏水的图片,因为网络证书过期了。

这是跨服务生态系统分布功能的一个非常真实的结果:所有权、访问和责任越来越多地在用户和提供商之间共享,并有硬 EULAs 来描述它们。商业领袖们首先考虑的是如何将他们的平台更深地融入我们的生活。第二,关于如何帮助我们在一些增值能力。

家庭必须带来稳定,而变化威胁着这种稳定。

这给我们带来了最大的挑战:家庭必须带来稳定,而变化威胁着这种稳定。庇护所、安全、家庭、隐私、营养、休息——忽视这些或试图改变这些品质或无意中改变这些品质的技术将会失败。

向前看(略)

在发达经济体,房屋和建筑正朝着更高效、更自动化的未来缓慢前行。未来的互联家庭解决方案将由两个相互冲突的引擎形成:个人授权和平台锁定。它们将拥有更多传感功能,与现有设施和设备的耦合更紧密,与用户配置文件和时间表的集成更紧密,以及复杂的深度学习系统,可以对机器和居民进行观察、分类、建模、预测、管理和推荐。许多这些功能将由服务提供商远程管理和维护,他们的目标和责任与用户不同。

未来的互联家庭解决方案将由两个相互冲突的引擎形成:个人授权和平台锁定。

不能有效地将信任传递到家庭中的供应商将会失败,他们公开的失败将会抑制市场的采用。一个强大的差异化优势将通过将功能和数据完全保留在现场来增强家庭及其成员的能力——这是大多数数据优先服务提供商无法想象的。

创新者正试图解决由一系列深层潮流驱动的需求:在 VUCA 世界中寻找安全和稳定;加速人类世的气候混乱;提高家居效率以更好地管理资源和财务开销的需求;我们通过数字网络的无处不在的连通性,以及我们的日程、责任和关系的数字化;智能手机让我们期待直接、易用的界面和功能,以及跨界面点的配置文件和偏好的连续性。

但是家的变化是缓慢的——它是包裹在信任和安全周围的基础设施,嵌入在冰冷的建筑规范和繁琐的成本结构中。这仍然是一个有远见的长期游戏,有许多障碍要克服。

智能公共交通

原文:https://towardsdatascience.com/smart-public-transport-a3afa46fc5e3?source=collection_archive---------3-----------------------

我经常乘坐公共交通工具;一辆去地铁站的公共汽车,在登上去伦敦郊区的火车之前,在地铁上打开一两个开关——这就是我每天早上去上班的旅程。天气好的时候,我花 3 ~ 4 个小时通勤;想象一下糟糕的一天需要多长时间?

美好的一天是在到达公交车站的 3 分钟内赶上公交车,每趟地铁的等待时间不超过 2 分钟,火车上没有延误。不错吧?那么什么构成了糟糕的一天呢?幸运的是,我只有大约 235,459,607 个例子,因为公共交通系统太棒了。

几周前,我在去雷丁的路上,决定途经伦敦帕丁顿。那天气温大约是 27 度,不幸的是我不得不搭贝克鲁线;可以说是有史以来最糟糕的地铁线路。为什么?车厢老旧、布满灰尘、肮脏,而且几乎没有通风或冷却系统。我终于到达了帕丁顿,在流了大约 2%的汗后,我震惊地发现,我应该赶上的火车——一整列火车——被取消了,因为“一名工作人员不在”。我不得不额外等了 20 分钟,和大约 70 多名乘客一起等下一趟火车。震惊甚至不足以形容我的感受。一列火车怎么会因为一个员工没来上班而被取消呢?更糟糕的是,我不知道哪个员工缺席了——是司机吗?可能是警卫?或许是清洁工?现在,我不责怪这个人,因为他们可能有一个合法的理由;疾病,假期或其他什么。更确切地说,我指责这个系统允许如此多的事情发生在一个单点故障上。

每延迟一分钟,对车站资源(站台空间、厕所、售票系统等)的人均压力就会增加一分钟。随着站的大小,这变得非常大和昂贵。

我昨天 18:00 左右在伦敦滑铁卢——艾格姆有延误,影响了从温莎&伊顿到雷丁和滑铁卢的整条线路——那里人满为患,可能比平时多了 200 多人。如果在那一瞬间出现紧急情况,人们会如何出站?有多少人会在潜在的踩踏事故中受伤?我可以整天讲故事,但这不是这个博客的目的。

令人尴尬的是,火车/铁路等公共交通系统不断受到天气(是的,即使是一点点降水也会造成重大问题)、信号故障、工作人员缺失或不足,当然还有“偶尔”罢工等问题的困扰。

我们利用一些运输系统已经超过 150 年了,但仍然不能把它做好;也许是时候将其中的人为因素最小化,让数据和数据科学一起发挥更突出的作用了。

想象一个 24 小时,365.25 天,智能设计的公共交通系统。没有罢工或信号故障的一致而舒适的服务。我一直在使用地铁,所以它们将是这篇文章的主要焦点(是的,我知道标题是智能公共交通)。然而,所提到的一切都可以适用于任何形式的公共交通——火车、公共汽车、电车、出租车等。不管怎样,这一切看起来会是怎样的呢?它是如何工作的?

第一步是将所有形式的公共交通转换为电动或绿色燃料系统。这将有助于环境的脱碳,使国家变得更加可持续和生态友好。公共交通系统节省的能源最终会减轻国家电网的压力。

为了提高无障碍性,每个车站都将配备无障碍通道、盲文和手语设施。为了降低复杂性,一张类似于 oyster 的预付卡将允许进入整个英国的任何交通系统;消除了对所有那些蹩脚的纸质机票、旅行卡、装满零钱的口袋和许多位于后端的冗余遗留系统的需求。

地铁将安装传感器,以精确测量车上有多少乘客,并根据这些数据调整网络服务——当乘客密度高时,增加地铁数量,当乘客密度低时,减少地铁数量。大约 5 ~ 7 分钟的最大等待时间将确保试管 24/7 运行。

传感器也将嵌入主要的管道组件,如电池、通风系统、制动器、发动机、门、散热器等,以获取用于测量管道使用、功耗、组件健康、发动机温度和许多其他尺寸的数据。捕获的数据最终将被外推用于预测性维护,管道将在主要部件损坏之前向工程师/维护人员发送信息。

每列火车也将安装超高速无线网络;允许你在飞行中规划和调整你的旅程。管道将连接到著名的外部数据源,如天气或新闻。例如,天气数据将允许基于输入自动调节车厢气候——27 度的温度将启动空调以保持地铁格外凉爽,而在寒冷的日子里,将启动加热以保持地铁温暖舒适。当事件或事故发生时,新闻数据可能特别有用,并根据接近实时的信息向乘客提供替代路线。USB 充电端口也将具有(为什么不呢?).

列车和车站站台上将是交互式的触摸屏,显示时间、天气、新闻、厕所信息、车厢内可用座位、帮助和援助、每个车站的连接(沃伦街将显示维多利亚和北线)、每个车站的著名地标(查林十字路口将显示特拉法尔加广场和国家美术馆)、服务于机场的列车的到达/离开信息、每个车站晚点时的当地出租车信息以及紧急服务的详细信息。每辆列车都将充当一个信息亭,确保乘客无论身在何处都能获得信息。

如前所述,火车站/终点站基础设施将具有弹性/智能。例如,如果发生紧急情况,车站需要疏散,将自动联系所有应急服务,出口将被清楚地标记和突出显示,栅栏将立即禁用并保持打开,直到事故停止。出口路径会以类似于飞机跑道的方式点亮。此外,遍布车站各处的交互式触摸屏面板将以箭头的形式显示最近出口的方向,显示急救程序,并包括一个帮助按钮——这样,如果需要紧急帮助,紧急服务将立即找到乘客并做出迅速反应。

所有的运输系统将共享一个分散的数据库;使它们始终保持同步。例如,火车上的突然中断会被公共汽车服务立即发现,并最大限度地减少对乘客旅程的干扰。如果紧急服务需要访问数据,例如事件发生后的闭路电视镜头,那么他们可以很容易地获得这些数据。

智能交通并非完全理想化。支撑这一想法的许多技术已经存在。我们现在面临的挑战是有效地结合和实施这项技术,最终鼓励广泛采用。

希望在未来的某个时候,开始工作将永远是美好的一天。

存储数据的巧妙方式

原文:https://towardsdatascience.com/smart-way-of-storing-data-d22dd5077340?source=collection_archive---------1-----------------------

让我们来谈谈位打包、重复数据删除等等

位打包就是让数据表示像手套一样适合你的数据。这是一个非常形象的比喻,但可能会有点混乱,所以让我们直接看第一个也是最简单的例子:

00000001 00000000 00000001

上面看到的是一个布尔数组的二进制表示:true, false, true。在大多数编程语言中,布尔值以 8 位存储,其中0false,而>=1true。这一切都是有意义的,因为 CPU 是如何读取数据的,但是如果我们知道我们要存储一个布尔值数组,我们可以使用一个位数组:

00000101

在这种情况下,bool 数组可以表示为一个字节数组,其中 size 是ceil(size/8)。当我们请求索引i处的元素时,我们需要从i创建两个索引:

  1. 字节索引floor(i/8)
  2. 位索引i mod 8,或者你也可以做i — (byteIndex * 8)如果你不想做运算。

为了找出索引i处的值是true还是false,我们需要从比特索引1 << bitIndex创建一个比特掩码,然后应用下面的表达式:bitArray[byteIndex] & mask != 0

正如我们所看到的,从位数组中读取布尔值需要一些计算,但在最好的情况下可以将存储数据的大小减少 87.5%。

现在我们来谈谈数字。数字以字节存储:

  • 1 字节:0… 256
  • 2 字节:0…65536
  • 4 字节:0… 4,294,967,296
  • 8 字节:0… 18,446,744,073,709,551,616

但是如果我们知道我们的数据是由较小的数字组成的呢?

四分之一字节可以代表数字 0…3,一半字节可以代表数字 0…15。

我们可以使用与位数组中相同的技术——计算两个索引,并通过几次位移操作得到值。

00000001 00000010 00000011 00000000

其中值为1, 2, 3, 0。可以变成:

00111001

实现了 75%的减少。我将让读者去思考如何用半字节表示保存一个数组。

存储一个 6 位数字有意义吗?

如果我们存储的数不是二位数的幂(1,2,4,8),我们将不得不面对这样一个事实,即一个数存储在两个字节之间。这意味着我们必须先读取第一个字节,然后再读取第二个字节。所以一般来说这是可能的,但老实说我从未见过有人这样做。然而,我所看到的是——将两个小数字的元组一起存储在一个字节中。例如 FlexBuffers 类型定义是:

  • 2 个较低的位代表子的位宽(8,16,32,64)
  • 6 位代表实际类型

如果我不知道我的数字会有多大呢?

在这种情况下,你可以选择尽可能大的尺寸,或者应用可变长度数量技术。

在这种技术中,我们取一个代表数字的比特流,并将其分成 7 个比特。第 8 位成为“标志”位。如果下一个 7 位分区不包含所有的0,标志位将被设置为1,如果您对细节感兴趣,请查看维基百科文章

协议缓冲区中使用了可变长度数量技术,这对格式非常重要,这是编码文档解释的第一件事。

有趣的是,如果你看看 UTF-8 编码。这基本上是相同的技术,只是在扫描字节方面有一点小小的调整。字节序列中的第一个字节,它编码一个 Unicode 字符告诉你序列有多长。如果字节以0开始(从左到右方向),则只有这一个字节。如果 unicode 字符需要两个字节,那么第一个字节的“开始”将是11,如果是三个字节,则是111,依此类推。

在我们转向重复数据消除之前,我还想讨论一项技术。我说的是存储增量

假设您正在存储一个时间戳序列,表示为 unix 时间。如果我们按原样存储时间戳,每个条目将消耗 4 个字节。然而,如果我们只按原样存储第一个条目,而所有其他条目只作为增量存储,那么我们可以对所有后续条目使用小得多的数字表示。最佳情况下,事件之间的间隔总是小于 255 秒(4 分 15 秒)。因此,我们可以用 1 字节存储时间戳,节省大约 75%的空间。

现在我们来谈谈重复数据消除。

每个数据都有某种重复。重复数据删除技术试图找到这些重复数据并【消除】它们。

消除是一个很强的词,我们不能因为一个值存储了两次就删除它。我们能做的,是间接地储存价值。一个很好的重复数据删除的老例子是 GIF 格式。在 GIF 中,一种颜色用 24 位——3 字节来表示。它存储在调色板中。一个调色板可以容纳 256 个条目(3 * 256 = 768 字节)。存储图像中的每个像素都存储为 1 字节调色板索引。

让我们做一些数学

我们有 768 字节的开销,每像素 66%的收益。这意味着,如果我们有超过 384 像素:384 * 3 = 384 * 1 + 768我们弥补了调色板的成本,并开始了我们的旅程,以减少 66%的空间。

同样的技术可以应用于大数字、文本串或任何其他在我们的数据集中重复出现的数据。这种技术的唯一问题是,我们需要知道数据有多少种不同的表现形式。使用 GIF,调色板是以某种方式创建的,一些颜色可能被“挤压”成一种颜色。这不是图像的问题,但是你可能不想对文本做同样的事情。

如果你仔细阅读前面的章节,你可能已经知道答案了。我们可以将调色板索引存储为可变长度的量。

我们还可以做另一件聪明的事情。我们可以尝试使用大数定律。在一个大的数据集中,我们可以假设一些条目会比其他条目出现得更频繁。在这种情况下,我们可以为 X 个最常出现的值创建一个小调色板,使用另一个调色板/数组来存储不经常出现的数字,这些值将存储在一个位打包数组中,该数组将指示该数字是否经常出现。好的,这很抽象,让我们举个小例子。

假设我们正在存储数字,我们知道7, 13, 42是我们通常存储的三个最常用的数字。现在让我们看一个数据序列的例子:

Initial: 7, 7, 7, 13, 13, 13, 2345, 42, 42, 7, 13, 6543, 7=>Index:    1, 1, 1, 2, 2, 2, 0, 3, 3, 1, 2, 0, 1
Frequent: 7, 13, 42
Other:    2345, 6543

所以我们看到我们有一个 13 个条目的索引,它存储从03的数字。这是我们存储的一系列值。如果值大于0,则表示“频繁”的号码:1 -> 7, 2 -> 13, 3 -> 42。如果是0,那么我们需要从“其他”数组中取出下一个数字。

这意味着我们不能通过索引来访问值,我们只能遍历它们,但是由于索引是一个在03之间的数字,我们可以用四分之一字节来存储 13 个值,用 2 个字节来存储 5 个其他值。让我们再计算一下:

  • 索引:ceil(13 / 4) = 4字节
  • 频率+其他:5 * 2 = 10字节

总计14字节与13 * 2 = 26字节相比。

看起来,如果你有很多条目,并且大数定律站在你这边,那么争论是值得的。

一个用例是当你处理一个稀疏值序列时,大数定律肯定是对你有利的。我说的稀疏值序列是指一个序列,其中许多值可以是“默认”或null(缺少值)。在这种情况下,我们的索引可以只是一个位数组,表示没有值。我们不需要“频繁”数组,我们只需要“其他/值”。

Initial: 23, 45, null, null, null, null, null, 3=>Index:  1, 1, 0, 0, 0, 0, 0, 1
Values: 23, 45, 3

另一种技术是基于大数定律的 T2 霍夫曼编码。我认为理解其背后概念的最好方法,是看一下莫尔斯电码。在莫尔斯电码中,最常用的字符用最短的序列表示,不常用的用最长的序列表示。这样,当你用莫尔斯电码交流时,你可能会花更少的时间传输。霍夫曼编码有点复杂,因为它是二进制格式,其中莫尔斯码是三进制的(短、长、无声),但想法非常接近。

可能有更聪明的方法来存储数据,但遗憾的是,这是我所能得到的。我很乐意在评论中看到更多的技巧。如果你愿意,你可以鼓掌。

将类序列化/反序列化到 Tensorflow 图或从 tensor flow 图序列化/反序列化类的智能方法

原文:https://towardsdatascience.com/smart-way-to-srialize-deserialise-class-to-from-tensorflow-graph-1b131db50c7d?source=collection_archive---------6-----------------------

Photo by John Fowler on Unsplash

自动将您的字段与张量流图绑定

将类字段自动绑定到图中的 tensorflow 变量并恢复它们,而不用手动从图中获取每个变量,这是不是很酷?

本文的代码可以在 这里找到, 一个笔记本版本可以在 这里找到

想象你有一个Model

通常,你首先建造你的模型,然后训练它。之后,你想从保存的图中得到旧的变量,而不是从头开始重建整个模型。

<tf.Variable 'variable:0' shape=(1,) dtype=int32_ref>

现在,假设我们刚刚训练了我们的模型,我们想要存储它。通常的模式是

现在你想执行推理,也就是通过加载存储的图来取回你的东西。在我们的例子中,我们想要名为variable的变量

INFO:tensorflow:Restoring parameters from /tmp/model.ckpt

现在我们可以从图中找回我们的variable

name: "variable" op: "VariableV2" attr { key: "container" value { s: "" } } attr { key: "dtype" value { type: DT_INT32 } } attr { key: "shape" value { shape { dim { size: 1 } } } } attr { key: "shared_name" value { s: "" } }

但是,如果我们想再次使用我们的model类呢?如果我们现在试着打电话给model.variable,我们没有收到

None

一个解决方案是重新构建整个模型,然后恢复图形

INFO:tensorflow:Restoring parameters from /tmp/model.ckpt <tf.Variable 'variable:0' shape=(1,) dtype=int32_ref>

你已经可以看到这是浪费时间。我们可以通过以下方式将model.variable直接绑定到正确的图节点

name: "variable" op: "VariableV2" attr { key: "container" value { s: "" } } attr { key: "dtype" value { type: DT_INT32 } } attr { key: "shape" value { shape { dim { size: 1 } } } } attr { key: "shared_name" value { s: "" } }

现在想象一下,我们有一个非常大的嵌套变量模型。为了正确恢复模型中的每个变量指针,您需要:

  • 命名每个变量
  • 从图表中获取变量

如果我们可以自动检索在模型类中设置为字段的所有变量,会不会很酷?

TFGraphConvertible

我创建了一个类,叫做TFGraphConvertible。你可以使用TFGraphConvertible来自动序列化反序列化一个类。

让我们重新创建我们的模型

它公开了两个方法:to_graphfrom_graph

序列化-到图形

为了使序列化一个类,你可以调用 to_graph 方法来创建一个字段名字典- > tensorflow 变量名。你需要传递一个fields参数,一个我们想要序列化的字段的字典。在我们的情况下,我们可以通过所有的测试。

{'variable': 'variable_2:0'}

它将创建一个字典,将所有字段作为键,将相应的 tensorflow 变量名作为值

反序列化-从图形

为了反序列化一个类,您可以调用 from_graph 方法,该方法获取之前创建的字典并将每个类字段绑定到正确的 tensorflow 变量

None <tf.Tensor 'variable_2:0' shape=(1,) dtype=int32_ref>

现在你有你的model回来了!

完整示例

我们来看一个更有趣的例子!我们将为 MNIST 数据集训练/恢复一个模型

我们去拿数据集吧!

Using TensorFlow backend.

现在是时候训练它了

0.125
0.46875
0.8125
0.953125
0.828125
0.890625
0.796875
0.9375
0.953125
0.921875

完美!让我们将序列化模型存储在内存中

{'x': 'ExpandDims:0', 
'y': 'one_hot:0', 
'forward_raw': 'dense_1/BiasAdd:0', 
'accuracy': 'Mean:0', 
'loss': 'Mean_1:0', 
'train_step': 'Adam'}

然后我们重置图表并重新创建模型

INFO:tensorflow:Restoring parameters from /tmp/model.ckpt

当然,我们的变量在mnist_model不存在

--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-21-9def5e0d8f6c> in <module>() ----> 1 mnist_model.accuracy AttributeError: 'MNISTModel' object has no attribute 'accuracy'

让我们通过调用from_graph方法来重新创建它们。

<tf.Tensor 'Mean:0' shape=() dtype=float32>

现在mnist_model已经准备好了,让我们看看测试集的准确性

INFO:tensorflow:Restoring parameters from /tmp/model.ckpt 
1.0

结论

在本教程中,我们已经看到了如何序列化一个类并将每个字段绑定回张量流图中正确的张量。请注意,您可以将serialized_model存储为.json格式,并从任何地方直接加载。这样,您可以通过使用面向对象编程直接创建您的模型,并检索其中的所有变量,而不必重新构建它们。

感谢您的阅读

弗朗西斯科·萨维里奥·祖皮奇尼

原载于gist.github.com

为机器学习编码分类数据的更智能方法

原文:https://towardsdatascience.com/smarter-ways-to-encode-categorical-data-for-machine-learning-part-1-of-3-6dca2f71b159?source=collection_archive---------0-----------------------

实践教程

探索类别编码器

更好的分类数据编码意味着更好的模型性能。在本文中,我将向您介绍来自类别编码器包的各种编码选项,用于 Python 中的 scikit-learn 机器学习。

Enigma for encoding

TL;DR;

当您有可能提供值的名义数据或序号数据时,请使用类别编码器来提高模型性能。

对于名义列,尝试 OneHot、Hashing、LeaveOneOut 和 Target 编码。避免对高基数列和基于决策树的算法使用 OneHot。

对于序数列,请尝试 Ordinal (Integer)、Binary、OneHot、LeaveOneOut 和 Target。赫尔默特、求和、倒向差和多项式不太可能有帮助,但如果你有时间或理论上的理由,你可能想试试它们。

对于回归任务,Target 和 LeaveOneOut 可能不会很好地工作。

路标

Map

在这篇文章中,我将讨论术语、一般用法和五个经典编码选项:序数、一个热点、二进制、BaseN 和散列。在未来,我可能会评估贝叶斯编码器和对比编码器与统计假设测试的根源。🚀

早先的一篇文章中,我认为我们应该将数据分类为七种类型之一,以便更快地建立更好的模型。以下是七种数据类型:

无用—对机器学习算法无用,即—离散
标称—无顺序组—离散
二元—非此即彼—离散
序数—有顺序组—离散
计数—出现次数—离散
时间—有时间成分的循环数—连续
区间—无时间成分的正数和/或负数—连续

在这里,我们关心的是名义数据和序数数据的编码。具有名义数据的列中的值无法以任何有意义的方式排序。名义数据通常是一位热码(又名哑元)编码,但有许多选项可能对机器学习有更好的表现。

Rank

相反,序数数据可以按等级排序。概括地说,顺序数据可以用三种方式中的一种进行编码,但我认为可以肯定地说,它的编码通常没有经过仔细考虑。

  1. 可以假设它与区间数据足够接近(值之间的幅度相对相等),从而可以这样对待它。社会科学家一直用李克特量表做这个假设。例如,“从 1 到 7,1 表示极不可能,4 表示既不可能也不太可能,7 表示极有可能,您向朋友推荐这部电影的可能性有多大?”这里,3 和 4 之间的差以及 6 和 7 之间的差可以合理地假设为相似。
  2. 它可以被视为名义数据,其中每个类别与另一个类别没有数字关系。您可以尝试一键编码和其他适用于名义数据的编码。
  3. 这两个数字之间的差异可以忽略不计。你可以用不同的编码来训练你的模型,看看哪种编码效果最好。

在这个系列中,我们将看看从版本 1.2.8 开始的分类编码器 11 编码器。* 更新:版本 1.3.0 是截至 2019 年 4 月 11 日 PyPI 上的最新版本。*

这些编码方法中有许多在统计界有不止一个名字,有时一个名字可能意味着不同的事情。我们将遵循类别编码器的用法。

非常感谢威尔·麦金尼斯创建和维护这个包。它很大程度上来源于 StatsModel 的 Patsy 包,而 Patsy 包又是基于这个 UCLA 统计参考

对分类信息进行编码的方式有无数种。类别编码器中的那些对于大多数用途应该是足够的。👍

快速小结

下面是分类编码器函数的列表,包括它们的描述和它们最适合编码的数据类型。

经典编码器

第一组五个经典编码器可以在一列(序数)到 k 列(OneHot)的连续嵌入信息上看到。对于机器学习从业者来说,这些编码非常有用。

序数 —通过 k 将字符串标签转换为整数值 1。序数。
OneHot —每个值对应一列,用于与所有其他值进行比较。名词,序数。
二进制 —将每个整数转换成二进制数字。每个二进制数字占一列。一些信息丢失,但维度更少。序数。
BaseN —序数、二进制或更高级编码。名词,序数。没有增加多少功能。大概避免。
哈希——像一个热点但维度更少,一些信息因碰撞而丢失。名词,序数。
Sum—就像 OneHot 一样,除了一个值在所有列中保持不变并编码为-1。

对比度编码器

五个对比度编码器都有多个问题,我认为这些问题使得它们不太可能对机器学习有用。对于在列中找到的每个值,它们都输出一列。他们的陈述意图如下。

【反转】 —将某个级别的因变量平均值与之前所有级别的因变量平均值进行比较。
后向差异 —将某一级别的因变量平均值与前一级别的因变量平均值进行比较。
多项式 —正交多项式对比。k=4 级的多项式编码所采用的系数是分类变量中的线性、二次和三次趋势。

贝叶斯编码器

贝叶斯编码器在其编码中使用因变量的信息。它们输出一列,可以很好地处理高基数数据。

目标 —使用 DV 的均值,必须采取措施避免过度拟合/响应泄漏。名词,序数。用于分类任务。
leave one out—类似目标但避免污染。名词,序数。用于分类任务。
weight of evidence
—v 1.3 新增,2019 年 4 月 11 日单据中未记录。这个方法在这个帖子里有解释。
詹姆斯-斯坦 —即将在 v1.4 中发布,此处用代码描述。
M-估计量 —即将在 v1.4 中发布。在此
的代码中描述。简化的目标编码器。
**

使用

类别编码器遵循与 scikit-learn 的预处理器相同的 API。它们有一些额外的便利,例如能够轻松地将编码器添加到管道中。此外,如果向编码器传递数据帧,它将返回一个 pandas 数据帧。以下是二进制编码的代码示例:

我们将在未来的实现中解决一些问题。但是如果您熟悉 scikit-learn 的 API,您应该能够直接进入前五种。

请注意,默认情况下,所有类别编码器都会自动估算缺失值。但是,我建议您在编码之前自己填充缺失的数据,这样您就可以测试几种方法的结果。我计划在下一篇文章中讨论输入选项,所以如果你想确保不会错过,请在 Medium 上关注 me

术语

你可能会看到评论者互换使用以下术语:维度特征向量系列自变量。我也会:)同样,你可能会看到观察互换使用。

k 是数据列中唯一值的原始数量。 基数意味着很多唯一值(一个大的 k) 。包含数百个邮政编码的列是高基数特性的一个例子。

High cardinality theme bird

高维度是指一个矩阵有多个维度。高维度伴随着维数灾难——关于这个话题的详细讨论可以在这里找到。其要点是,高维度需要大量的观测数据,并经常导致过度拟合。

A wand to help ward off the Curse of Dimensionality

稀疏数据是一个相对于其他值有很多零的矩阵。如果您的编码器转换您的数据,使其变得稀疏,一些算法可能无法很好地工作。稀疏性通常可以通过标记来管理,但许多算法并不能很好地工作,除非数据是密集的。

Sparse

深入分类编码器

事不宜迟,我们来编码吧!

序数

OrdinalEncoder 将每个字符串值转换为整数。列中的第一个唯一值变为 1,第二个变为 2,第三个变为 3,依此类推。

当您用 OrdinalEncoder拟合 _ transform时,编码前的实际值不会影响它的变化。第一个值可能是 10,第二个值可能是 3。现在他们将分别是 1 和 2。

如果列包含名义数据,在使用 OrdinalEncoder 后停止是个坏主意。您的机器学习算法会将变量视为连续的,并假设值在有意义的范围内。相反,如果您有一个值为 car、bus、truck 的列,您应该首先使用 OrdinalEncoder 对这个名义数据进行编码。然后使用一种适用于名义数据的方法再次对其进行编码,我们将在下面探讨这种方法。

相反,如果您的列值确实是有序的,这意味着分配给每个值的整数是有意义的。作业要用心做。假设您的列中有字符串值“第一”、“第三”和“第二”。应该通过向 OrdinalEncoder 传递一个字典列表将这些值映射到相应的整数,如下所示:

**[{"col": "finished_race_order", 
  "mapping": [("First", 1), 
              ("Second", 2), 
              ("Third", 3)]
}]**

下面是所有代码示例的基本设置。你可以在这个 Kaggle 内核获得完整的笔记本。

这是未转换的 X 列。

下面是将颜色列值从字母转换成整数的 OrdinalEncoder 代码。

所有的字符串值现在都是整数。

Scikit-learn 的 OrdinalEncoder 和 Category Encoder 的 OrdinalEncoder 做的事情差不多,但是不太用户友好。Scikit-learn 的编码器不会返回熊猫数据帧。相反,如果您传递一个 DataFrame,它将返回一个 NumPy 数组。它还输出从 0 开始的值,而 OrdinalEncoder 默认输出从 1 开始的值。

在 pandas 中,您可以通过将字符串值映射到整数来完成序号编码。但是一旦你知道如何使用分类编码器,那就是额外的工作了。

OneHot

一键编码是处理标称数据,也可能是序数数据的经典方法。在 Kaggle 的机器学习教程系列中,它被称为“分类数据的标准方法”。也有 编码、指示符编码,偶尔还有二进制编码。是的,这是令人困惑的。😉

That’s one hot sun

独热编码器为每个值创建一列,以便与所有其他值进行比较。对于每个新列,如果一行包含该列的值,则该行获得一个 1 ,如果不包含,则获得一个 0 。它看起来是这样的:

color_-1 实际上是一个无关的列,因为它都是 0——没有变化,它没有帮助你的模型学习任何东西。它可能是为缺失值设计的,但是在类别编码器的 1.2.8 版本中,它没有任何用途。

独热编码可以执行得非常好,但是新特征的数量等于 k,唯一值的数量。如果数据集具有高基数要素,这种要素扩展会造成严重的内存问题。对于基于决策树的算法来说,一位热编码数据也可能是困难的——参见这里的讨论。

熊猫 GetDummies 和 scikit-learn 的 OneHotEncoder 函数执行与类别编码器 OneHotEncoder 相同的角色。我发现分类编码器 OneHotEncoder 更好用一些。

二进制的

二进制编码可以被认为是一位热编码器和散列编码器的混合体。Binary 比 one-hot 创建更少的功能,同时保留列中值的一些唯一性。它可以很好地处理高维有序数据。

Binary

它是这样工作的:

  • 如果类别还不是数字形式的,则由 OrdinalEncoder 进行编码。
  • 然后这些整数被转换成二进制代码,例如 5 变成 101,10 变成 1010
  • 然后,该二进制字符串中的数字被拆分到单独的列中。因此,如果一个序号列中有 4–7 个值,那么将创建 3 个新列:一个用于第一位,一个用于第二位,一个用于第三位。
  • 每个观察值都以二进制形式跨列编码。

它看起来是这样的:

第一列没有方差,所以它对模型没有任何帮助。

只有三个层次,嵌入的信息就变得混乱了。有许多碰撞,模型不能从特征中收集很多信息。如果一列只有几个值,就对它进行一次热编码。

相比之下,当列的基数较高时,二进制确实会大放异彩——例如,美国的 50 个州。

二进制编码比一键编码创建的列少。它的内存效率更高。它还减少了较高基数的维数问题的机会。

对于序号数据,大多数在序号形式下彼此接近的值将在新列中共享许多相同的值。很多机器学习算法可以学习到特征是相似的。二进制编码对于高基数的序数数据来说是一种不错的折衷。

如果你已经成功地使用了二进制编码,请在评论中分享。对于名义数据,具有更细粒度控制的哈希算法通常更有意义。

巴森

当 BaseN base = 1 时,它基本上与一个热编码相同。当 base = 2 时,基本上与二进制编码相同。麦金尼斯这种编码器,“实际上,这增加了很少的新功能,很少有人在实际问题中使用基数-3 或基数-8 或除了序数或二进制以外的任何基数。”

Base 3

BaseN 存在的主要原因是可能使网格搜索更容易。您可以将 BaseN 与 scikit-learn 的 Gridsearchv 一起使用。然而如果您要使用这些编码选项进行网格搜索,您可以将编码器作为 scikit-learn 管道的一部分,并将选项放在您的参数网格中。我看不到使用 BaseN 的令人信服的理由。如果你有,请在评论中分享。

BaseNEncoder 的默认基数是 2,相当于 BinaryEncoder。

散列法

哈希编码器实现了哈希技巧。它类似于一键编码,但是新的维度更少,并且由于冲突会丢失一些信息。除非有大量重叠,否则冲突不会显著影响性能。关于散列技巧和选择输出特征数量的指南的精彩讨论可在这里找到。

这是序数栏,再次提醒一下。

这是带输出的哈希编码器。

n_components 参数控制扩展列的数量。默认为八列。在我们有三个值的示例列中,缺省值导致五列全是 0。

如果将 n_components 设置为小于 k ,则编码数据提供的值会有一点减少。你的维度也会更少。

您可以将自己选择的哈希算法传递给 HashingEncoder 默认是 md5 。哈希算法在一些 Kaggle 竞赛中非常成功。如果您有高基数特性,那么值得尝试为名义数据和序数数据使用哈希编码。👍

包装

Exercise break

目前就这些。这里有一个回顾和建议何时使用编码器。

对于名义列,尝试 OneHot、Hashing、LeaveOneOut 和 Target 编码。避免高基数列的 OneHot。

对于序数列,请尝试 Ordinal (Integer)、Binary、OneHot、LeaveOneOut 和 Target。赫尔默特、求和、倒向差和多项式不太可能有帮助,但如果你有时间或理论上的理由,你可能想试试它们。

贝叶斯编码器可以很好地完成一些机器学习任务。例如,Owen Zhang 使用留一编码方法在一个 Kaggle 分类挑战中表现良好。

*** 2019 年 4 月更新:我更新了这篇文章,以包括关于即将推出的编码器的信息,并修改了结论。****

我写的是数据科学、 PythonSQL 和 DevOps。查看我的其他文章,如果你对这些感兴趣,请点击这里关注我。😀

感谢阅读!

闻起来像机器学习的进步

原文:https://towardsdatascience.com/smells-like-machine-learning-progress-611a2851acec?source=collection_archive---------4-----------------------

注意:我想指出的是,我是作为机器学习的实践者来探讨这个话题的,而不是作为化学家、神经科学家或香水设计师。如果在读完这篇文章后,你决定……原谅这个双关语……把你的鼻子放在不属于它的地方,我将不负任何责任。

对于某些类型的刺激,机器学习已经取得了相当大的进展。

计算机视觉系统在越来越多的任务上超越了人类,并在从医学成像到自动驾驶汽车(以及收割机器人)的广泛技术中发挥着核心作用。

关于声音处理的一般问题的进展,可能被一个特定应用,即语音识别的日益流行所掩盖。

迄今为止,很少有人关注嗅觉。最近的发展表明,这种情况即将改变。

主观体验玫瑰的气味可能暂时仍是生物的专属。然而,这并不能阻止机器学习预测各种气味的数字和语言体验。

在很大程度上,机器学习是围绕竞赛来组织的。这一特殊领域的核心竞争是梦境嗅觉预测挑战。[1] 476 种不同的气味分子,以低浓度和高浓度呈现,由 49 个人在 21 个维度上进行评级。这就是“挑战”的开始。

评级可变性至少有两个来源。首先,由于遗传和环境原因,个体的实际嗅觉是不同的。[2]其次,描述词在语言上的模糊性使问题更加复杂。我对“麝香”的感觉可能和你不同。

文献中指出了在 0 到 100 的范围内匿名化评级的一些显著差异。[3]例如,个体 46 显示出在 50 左右评级趋势。显然,29 号个体有更强烈的观点,并表现出对 100 分的偏好。个人 10 依次将其等级均匀地分布在 0 到 100 之间。

环戊烷硫醇是一种具有强烈气味的调味成分,通常被描述为大蒜[4]。该研究中的 9 名受试者完全同意这种看法,并给这种分子打了 100 分的大蒜最高分。然而,三分之一的参与者根本不认为这是一种大蒜味。其余的在极端分数之间分配得相当均匀。

参与者对气味的强度和愉悦程度基本一致。评分变化最大的两个属性是“木质”和“温暖”。有趣的是,“冷”的描述比“暖”的描述更符合事实。

由于这些个体差异,梦嗅觉预测挑战分为两部分:子挑战#1 处理群体水平上的预测,而子挑战#2 基于模型预测个体嗅觉等级的能力来评估模型。

除了评级,数据集还提供了 4,884 种化学特征。让我们以丁酸甲酯为例,讨论特征的一个子集,莫罗-布罗托自相关。

这种特殊的分子显示出令人愉快的水果气味,由五个碳原子、十个氢原子和两个氧原子组成。除去氢,原子按以下方式排列:

Methyl Butyrate (without hydrogen atoms)

我们可以从分子图的角度来考虑这种排列,节点代表原子,边对应于原子之间的键。两个原子之间的边/键的数量称为距离。

我们例子中的每个原子至少有一个距离为 1 的邻居。对于一些对,例如碳原子 2 和碳原子 4 的对,有一个距离为 2 的路径。丁酸甲酯分子中的最大距离是 6。

为了计算莫罗-布罗托自相关[6],我们需要两个循环。设 i 表示外环的索引,设 j 为内环的索引。外部循环从 1 迭代到最后一个原子的索引减去 d 。对于给定的距离 d ,内循环从 i+d 迭代到最后一个索引。我们必须决定的另一个因素是,每个原子的属性。一个常见的选择,也是下面例子中使用的,是原子质量。

对于由距离为 d 的路径连接的每对原子【T10(I,j)】,我们计算原子 i 的质量乘以原子 j 的质量。原子质量和距离为 d 的莫罗-布罗托自相关是这些乘积的总和。

假设我们将距离 d 设为 2。为了获得特征值,我们必须考虑以下对:(1,3),(2,4),(3,5)和(3,6),(4,7)。设 w_k 表示原子 k 的质量。然后,特征值是以下计算的结果:

w _ 1 * w _ 3+w _ 2 * w _ 4+w _ 3 * w _ 5+w _ 3 * w _ 6+w _ 4 * w _ 7

既然我们已经讨论了数据集,并了解了一组常用的特征,我们可以继续研究最先进的技术。梦嗅觉预测挑战的获胜者是密歇根大学研究人员提交的模型,李等人(2017)[3]对此进行了描述。

获胜的模型有三个关键特征:(1)随机森林的使用,(2)单个目标的重新加权以及(3)包含四克特征。

特征空间远大于样本空间。4885 个基本功能与 992 个评级形成鲜明对比。因此,需要采取措施来防止过度拟合的风险。为数不多的可用数据点充斥着异常值,证明了嗅觉感知的非线性。出于这些原因,作者认为随机森林是合适的,这是一种流行的学习方法,可以在数据集的不同部分训练一组单独的决策树。

为了进一步减少异常值对模型的影响,使用个人评级和所有 49 名受试者的平均评级(群体评级)的仿射组合对目标进行重新加权:

*重新加权目标= alpha *个人评分+ (1 - alpha) 群体评分

最后,数据集提供的基本特征被丰富为四个字母的特征,即通过在分子名称上滑动窗口产生的四个字母的字符序列。例如,“丁酸甲酯”包含以下附加特征:“甲基”、“乙基”、“htyl”、“tyra”、“yrate”、“rate”。

按照刚刚概述的方法,测试数据中预测等级和实际等级之间的报告相关性对于气味强度约为 0.4,对于愉快度接近 0.3。

总的来说,19 个语义描述符变得更难预测,相关性低于 0.2。特别是,对于个人强烈反对的描述词“温暖”和“木头”,预测和实际评分之间几乎没有线性关系。相比之下,关于描述符“水果”和“甜食”的表现与愉悦属性的结果相当。

5 重交叉验证表明 0.2 的小值是 alpha 的合适选择,alpha 是调节单个目标值重新加权的参数。

简单的化学特征,如分子量或官能团的存在,几乎没有预测能力。在 21 个属性中,超过 20%的前 5 个特征是莫罗-布罗托自相关。值得注意的是,基于前 15 个特性的随机森林实现了与访问全部特性集的模型相当的性能。

因此,在梦嗅觉预测挑战中获胜的参赛作品是一个传统的随机森林,它能够根据一些化学特征和小而嘈杂的数据集以中等精度预测个体的嗅觉感知。

在其他应用中,这开辟了使用机器学习作为现有香水设计方法的替代或补充的可能性。据估计,全球香水、除臭剂和止汗剂的市场价值约为 700 亿美元。[7]由机器学习支持的设计过程可能与定制和小众香水的增长趋势特别相关。

我期待着(也嗅到了)带有工作名称的产品的发布,比如“随机森林的气味”,当然还有“深层香水”。

感谢您的阅读!如果你喜欢这篇文章,请点击拍手按钮并关注我,以接收更多关于令人兴奋的机器学习应用程序的信息。

笔记

[1] Keller,a .,Gerkin,R.C .,Guan,y .,Dhurandhar,a .,Turu,g .,Szalai,b .,大陆,J.D .,Ihara,y .,Yu,C.W .,Wolfinger,r .和 Vens,c .,2017 .从气味分子的化学特征预测人的嗅觉。科学,p.eaal2014。

[2] Menashe,I .,Man,o .,Lancet,d .和 Gilad,y .,2003 年。不同的人有不同的鼻子。自然遗传学34 (2),第 143 页

[3]李,h .潘瓦尔,b .奥门,G.S .和关,y . 2017。根据大规模化学信息特征精确预测个性化嗅觉。千兆科学

[4]环戊烷硫醇,thegoodscentscompany.com

[5]丁酸甲酯,thegoodscentscompany.com

[6] Todeschini,r .和 Consonni,v .,2008 年。分子描述符手册(第 11 卷)。约翰·威利的儿子们。

[7]2012-2024 年全球香水、除臭剂和止汗剂市场规模(以十亿美元计),statista.com

那么,你有多少 ML 模型没有造出来?

原文:https://towardsdatascience.com/so-how-many-ml-models-you-have-not-built-e692f549b163?source=collection_archive---------12-----------------------

Source : Pixabay

好奇怪的问题!!这是你看了标题后会想到的。也许你认为“不是”这个词是偶然的。

嗯,在过去的几年里,我们很多人都遇到过这样的文章

“十大机器学习算法每个数据科学家都应该 知道

"每个数据科学家都应该知道的前 20 个 R 包"

"每个数据科学家都应该知道的前 30 个 Python 库"

不胜枚举。任何新的数据科学追求者仅仅通过在互联网上看到“应该知道”类型的文章就已经挥舞起白旗了。

Source

一天结束时,由于信息量太大,一个人不知道首先从哪里开始。

从一个有抱负的数据科学家的角度来看,我上面描述的是一个问题。

给我造一个 ML 模型

由于“应该知道”类型的文章,有一个更大的问题,问题的承担者是公司——初创公司和大型跨国公司。

你问的问题是什么?

每个人都想分享最新的“数据科学”。

Adapted from Dan Ariely’s original Quote

许多公司想做数据科学,因为

他们认为他们的竞争对手正在这么做

他们不想被视为落后者

他们相信会有很好的投资回报

但对于这些公司中的许多人来说,数据科学完全是一个新领域,因此他们的工作描述通常很奇怪,面试过程甚至更奇怪。

一些受“应该知道”类文章影响的公司告诉求职者

这是我们面临的问题,告诉我们有哪些机器学习算法可以应用?

新培养的数据科学家很快脱口而出 2-3ML 算法,并被倾心的公司聘用。在适当的时候,算法被实现。这位数据科学家给公司留下了良好的印象,他的模型准确率高达 90% .这些模型已投入生产。但是你瞧,这个模型并没有给公司带来它所希望的投资回报率。发生了什么事?

事实是,数据科学家没有商业头脑,认为他/她的 KPI 只是构建“好的”ML 模型。这家公司有商业头脑,但没有机器学习/统计知识。理想的婚姻从未发生过。

修船人的故事

我们都听说过这个故事或者这个故事的变体。

Source : Pixabay

一家轮船公司雇用了一名工程师来修理轮船的发动机。工程师的工具箱里有所有的工具。经过一番分析后,工程师拿出一把锤子,敲击发动机的一个部件。发动机开始工作了。第二天,工程师把发票寄给了轮船公司,仅仅 5 分钟的工作就要支付 10,000 美元的巨额费用。

船公司经理大吃一惊,要求工程师逐项列出发票。该法案内容如下

用锤子敲打——2 美元

知道去哪里——9998 美元

现在你可能认为我强调领域知识和经验,是的,你猜对了。

修船人—数据科学家类比

故事中的工程师工具箱里有所有的工具,但他只选择了锤子(也许是最简单的工具)来修理发动机。此外,最重要的是,他知道问题出在哪里。同样,一个数据科学家不应该选择先用基础分析解决问题吗?而是直接实现机器学习算法?

最小化损失函数

“所有的模型都是错的,有些是有用的”。

在大多数机器学习算法中,我们试图最小化损失函数。

模型是现实的抽象。这里的词是抽象。这不是真的。

你想想,构建机器学习算法的过程本身就有更大的‘损失函数’。那就是我们与现实不同。

那么,我们是不是应该少建一些模型来最小化这个更大的‘损失函数’呢?

嘿,数据科学家,像 CEO 一样思考

我们这些数据科学家经常陷入非常技术性的思维。我们只考虑哪种 ML 算法适用于 x,y,z 问题。如何做特征选择?如何减少特征的数量?如何提高模型的精度?

我们不认为最大似然算法会给公司带来什么好处。通过我的 ML 算法我能为公司省多少钱。投资回报率会是正数吗?

我们忘记问的最重要的问题是“这个商业问题真的需要机器学习算法吗”?

我知道最后一句话会引起轩然大波。你们中的许多人会感到震惊,可能会问“你是想让我们失业吗?”

相反,没有。

有许多商业问题确实需要机器学习方法,但不是所有的。大多数业务问题都可以通过简单的分析或基线方法来解决。

会让我们失业的是机器学习的过度杀伤。我见过用机器学习算法来解决非常琐碎的问题,更糟糕的是,这些公司在这个想法上投入了大量资金。这是一颗定时炸弹。一旦公司意识到投资回报率为负,他们就会完全回避数据科学实践。我们都知道赢得一个被责骂的顾客有多难。没有数据科学,就没有数据科学家。

尊重

我相信,当数据科学家说“对不起,你的业务问题不值得使用机器学习算法”时,这极大地提高了数据科学家在客户/公司眼中的地位。照吩咐去做比违背要容易得多。当数据科学家拒绝时,它会做两件事

  1. 它展示了数据科学家拥有丰富的知识,因此也知道局限性
  2. 它展示了数据科学家不仅了解业务,还关心客户/公司的福祉(业务方面)

时间到了,数据科学审计员来了

业界对数据科学的前景既兴奋又警惕。许多已经实施了数据科学解决方案的人由于投资回报率低而不再抱有幻想。

进入数据科学审核员

我预见到一个新的工作角色将被创造出来“数据科学审计员”,公司将雇佣有经验的数据科学家(统计学家/应用数学家)来审计数据科学项目。

在我最近的一个咨询项目中,我感觉自己就像一名审计员。我被要求即兴创作一个由数据科学家建立的 ML 模型,但经过分析发现,所应用的 ML 算法不仅是错误的,而且对于给定的业务问题,没有 ML 算法会起作用!!

客户只是被骗了。

反响——客户对数据科学家没有好感,感觉在情感和金钱上都受到了欺骗。

也许,下次不要问数据科学家“你已经建立了多少 ML 算法”

宁愿问

“您还没有构建多少 ML 算法”

如果你喜欢我的文章,给它一些掌声,你也可以在下面发表评论,表达你对这篇文章的看法。

你可以联系我

领英

推特

我的博客:分析洛卡

那么 AI 有什么新的?三十年后,我决定参加人工智能进修课程,这就是我的发现

原文:https://towardsdatascience.com/so-whats-new-in-ai-i-decided-to-take-an-ai-refresher-course-thirty-years-later-b4c7ae077cc4?source=collection_archive---------3-----------------------

我毕业时获得了人工智能学位,当时相当于一部 iPhone 的计算能力的成本是 5000 万美元。很多事情都变了,但令人惊讶的是,很多事情还是老样子。

停止疯狂!

W 当我今天早上醒来,在 Flipboard 上查看我的 AI 故事每日新闻时,我觉得我应该继续睡觉。很明显,我们所知的世界即将终结。在我大约三分之一的个性化新闻文章中,人工智能标题清晰响亮。以下是其中的一些:

人工智能专家列出了人工智能的真正危险

限制人工智能的缺点

新报告概述了人工智能的一些反乌托邦元素

关于新兴人工智能风险的新报告描绘了一个严峻的未来

埃隆·马斯克退出人工智能伦理研究小组

AI 会奴役人类吗?可能不会,但它可能会在自动取款机上抢劫你

NatWest 雇佣“数字人”Cora 与客户聊天,并帮助解决简单的银行业务

人工智能是对文明的威胁吗?

当像斯蒂芬·霍金埃隆·马斯克这样的聪明人说,我引用他的话,“全人工智能的发展可能会导致人类的灭亡”和“人工智能是我们最大的生存威胁”时,我有什么资格反驳。当享誉全球的管理咨询公司麦肯锡(McKinsey)在全球首席执行官中引起广泛关注时,它坚定地表示,“我们估计,全球劳动力市场上人们被雇佣从事的所有活动中,约有一半可能会实现自动化”,那么,假设我们都注定要失败似乎也不无道理。

The Telegraph newspaper reports that experts believe robots will take over most jobs within 30 years.

但简而言之,我相信这是很多媒体头条抓取废话。为什么我有资格对这个话题发表意见?自从我从苏塞克斯大学获得人工智能和计算机科学学位后,我已经观察人工智能三十多年了。这要追溯到人们认为 AI 意味着人工授精的时代。任何在人工智能历史的许多篇章中生活、呼吸和工作过的人,都对最近的说法抱有一定程度的怀疑。

艾是历史上非常寒冷的冬天

自从人工智能出现以来,它就一直处于反复无常的状态。在 70 年代,80 年代,90 年代,甚至是 21 世纪初,大规模的宣传和投资围绕着人工智能迅速展开,随后被降级到内陆地区,因为预期总是远远达不到。在 20 世纪 90 年代初,试图找到一份拥有人工智能学位的工作是一条通往失业的必经之路。我不得不将自己重塑为一名地理信息系统(GIS)工程师。至少 GIS 使用了人工智能算法,如两个地点之间的最短路线和知识表示技术。但我的许多人工智能专业的毕业生都无法通过他们的教育选择来成就事业,除非他们进入学术界或研究领域。

但是现在有些事情真的不同了。人工智能可能真的开始兑现它的承诺了。人工智能已经悄悄进入我们的日常生活,通过技术实现了许多日常服务:

  • 亚马逊 Alexa ,这个价值 49 美元的冰球,坐在我们的厨房里,它能理解我在说什么,而且通常会给我合理的答案。它的语音转文本识别真的很好。你应该看看相关的应用程序,它发现了许多不知情的青少年,他们问了 Alexa 可疑的问题,不知道这些问题都被转换成文本供他们的父母查看。
  • 脸书非常擅长面部识别。每天都有数十亿用户上传数百万张照片。脸书扫描这些照片,找出人脸,然后给他们起名字。由于隐私法的原因,这一功能在欧洲并不常见,但这项技术正在大规模地做一些通常属于人类的事情。
  • 谷歌最近展示了其 DeepMind AlphaGo 团队,计算机可以在古老的围棋比赛中击败世界最佳选手。这在几年前被认为是不可能的,因为游戏中的移动数量超过了宇宙中的原子数量。但他们的深度神经网络已经能够自我学习击败世界最佳的策略。

人工智能正在为各种服务提供动力,从聊天机器人和虚拟代理到智能机器人和自动驾驶汽车。所有这些都是人工智能的例子,表明计算机可以完成通常需要人类智能的活动,如视觉感知或语音识别,决策,以及在复杂的世界中感知和导航。

我们生活在一个指数增长的世界里

当我学习人工智能时,课程包括语音识别、自然语言处理、视觉识别、机器学习、神经网络和推理。我记得一份试卷给我们出了一个难题,如何检测汽车牌照。我编写了第一个神经网络来解决旅行推销员问题——如何找到十个地理位置之间的最短驾驶距离。我记得有一个长期项目是给一台机器编程,学习如何进行数学推理。但当时真的感觉我们离日常生活中可以使用的东西还很远。这些节目真的很慢。数据集非常小。这些系统不能从一个话题概括到另一个话题。而所谓的人工智能强调 人工高于智能。

但是有些事情已经改变了。很难想象 iPhone 只有十几岁。很难想象一个没有脸书的世界。很难想象一个世界,如果我需要找到一些信息,我不会搜索谷歌。计算能力和数据的指数级增长使得数字世界成为可能。这推动了人工智能的转变。一些有趣的事实证明了我们指数世界的力量:

  • 如果自 1971 年以来,一辆汽车的速度与计算芯片的速度一样快,那么它的行驶速度将达到每小时 420,000,000 英里。
  • 如今的数据存储比 1993 年便宜了 28,450 英镑。
  • 据估计,到 2020 年,地球上 70 亿人口中的每一个人每秒都会产生 1,700,000 字节的数据。这相当于这个星球上的每个人每秒钟都会发出 100 多封没有图片的电子邮件。

据说全球 80%的数据都是近两年才产生的。在物联网、移动设备、工业传感器、健身设备和社交媒体活动的推动下,这一数字将继续呈指数级增长。我不得不查找一个 Zettabyte 的大小(10 的 21 次方),因为据估计,到 2020 年将会产生 44 Zettabytes 的数据。

这个指数级的世界已经产生了看起来可行的人工智能应用。在过去的三年里,随着面部识别的进步,图像识别的错误率已经从 28%下降到 7%。语音识别率已经下降到人类的准确性领域。

Error rates for recognising images have dropped from 28% to 7% over the past few years. Courtesy of Benedict Evans

And similarly speech recognition error rates have dropped precipitously from 26% to 4%. This is approaching human levels.

谷歌免费提供尖端的机器学习软件 tensor flow

但是还有其他的事情在发生。以前写软件做机器学习之类的事情真的很难。机器学习是指计算机能够自己学习,而不必像你写软件时那样被明确告知规则。

考虑深度神经网络,它是驱动最新一轮人工智能歇斯底里的基础技术。根据大脑神经元的松散模型,下面的示意图显示了一个深度神经网络,它可以学习识别狗的图片,并区分类似的动物,如狼或猫。

A deep neural network that learns to identify pictures of dogs from other animals. The program is not told what features differentiate the animals but rather learns for itself from seeing thousands of examples. Courtesy of Fortune.

在所谓的监督训练中,神经网络被输入许多动物的图片。向神经网络展示一张物体的图片,并告诉它是否是一只狗。深度神经网络由神经元层组成,这些神经元层代表关于对象的越来越多的抽象。第一层发现基本的视觉特征,如线条边缘或纹理或颜色。然后,更高的层次开始将这些放在一起,以看到更全面的特征,如鼻子或爪子或腿或尾巴。然后最高层把它们放在一起“看”一匹马、一只狗或一只狼。在所有这些情况下,机器在看到许多训练示例后,已经自己学习了模式。它能以 90%的准确率识别一张照片是狗还是狼。

这种神经网络软件的非凡之处在于,机器没有被告知动物之间的区别,而是自己学习。升起机器!

编写软件来做到这一点真的很难。让机器识别物体、单词或句子将花费我好几个月的时间,即便如此,结果也是有限的。三十年前,我们没有足够的计算机能力来进行多层次的学习,而是只有一个层次,而且我们只有很小的数据集。

今天,谷歌是世界上最大的人工智能公司。它能够吸引该学科中最优秀和最聪明的头脑。他们正在研究自动驾驶汽车、语音识别、智能推理、海量搜索和大多数经典的人工智能问题。他们已经免费提供他们的人工智能软件来驱动他们的服务是免费的! TensorFlow 现在是一个开源软件项目,它从谷歌获得了最好的人工智能软件库,并允许社区使用它。

你可以在几分钟内设置一个机器学习程序——你不是天才!

这个 TensorFlow 软件不仅代表了人工智能和机器学习的艺术水平,而且使用起来也相对简单。正如最近在 KDnuggets 的一篇文章标题是“神经网络 AI 很简单。所以……别再假装自己是天才了。情有可原。但现实是,在黄金时间做 AI 确实需要工作和专业知识。然而,建立并运行一个神经网络演示几乎是小菜一碟。

我最喜欢的软件库是 Keras ,也是免费的。它涵盖了 Tensorflow 和其他机器学习引擎,使构建和训练神经网络变得更加简单。

A combinaton of Keras and TensorFlow is a great toolkit to start machine learning programming.

人工智能学生学习的第一个程序是 MNIST。这是一个让机器从视觉上学习手写数字 0 到 9(如下)之间的区别的任务。一台计算机被展示 6 万幅图像样本,并学会识别这些数字的视觉差异。

使用 Keras,下面的代码是您构建和训练深度神经网络所需的全部内容——这是一个卷积神经网络,特别适合视觉识别。这些机器学习识别数字的准确率达到 99.6%。

Keras 中的编程步骤如下灰框所示。理解具体的代码指令并不重要,重要的是要注意实现程序只需要五个主要的概念性步骤。

  1. 加载 Keras 的软件库以及矩阵和向量数学
import numpyfrom keras.datasets import mnistfrom keras.models import Sequentialfrom keras.layers import Densefrom keras.layers import Dropoutfrom keras.layers import Flattenfrom keras.layers.convolutional import Conv2Dfrom keras.layers.convolutional import MaxPooling2Dfrom keras.utils import np_utilsfrom keras import backend as KK.set_image_dim_ordering('th')

2.设置随机数

# fix random seed for reproducibilityseed = 7numpy.random.seed(seed)

3.加载 60,000 幅图像的训练数据,并将其存储在正确形成的矩阵和向量中

# load data(X_train, y_train), (X_test, y_test) = mnist.load_data()# reshape to be [samples][pixels][width][height]X_train = X_train.reshape(X_train.shape[0], 1, 28, 28).astype('float32')X_test = X_test.reshape(X_test.shape[0], 1, 28, 28).astype('float32')

4.构建输入和输出数据,以便用于培训

# normalize inputs from 0-255 to 0-1X_train = X_train / 255X_test = X_test / 255# one hot encode outputsy_train = np_utils.to_categorical(y_train)y_test = np_utils.to_categorical(y_test)num_classes = y_test.shape[1]

5.建立模型,对数据进行训练,并输出数据的准确性

def baseline_model():# create modelmodel = Sequential()model.add(Conv2D(32, (5, 5), input_shape=(1, 28, 28), activation='relu'))model.add(MaxPooling2D(pool_size=(2, 2)))model.add(Dropout(0.2))model.add(Flatten())model.add(Dense(128, activation='relu'))model.add(Dense(num_classes, activation='softmax'))# Compile modelmodel.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])return model# build the modelmodel = baseline_model()# Fit the modelmodel.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=10, batch_size=200, verbose=2)# Final evaluation of the modelscores = model.evaluate(X_test, y_test, verbose=0)print("CNN Error: %.2f%%" % (100-scores[1]*100))

这个程序是机器学习掌握的教程

为了证明它有多简单,我喜欢这个由@datitran 用 TensorFlow 写的浣熊探测器。这个程序使用 TensorFlow 最新的库进行对象检测。

A racoon detector built on TensorFlow’s object detector APIs.

人工智能将成为无处不在的赋能工具包

在过去的几个月里,我一直在卷起袖子,把手弄得很脏,为神经网络编程。一天下午,我突然有一种似曾相识的感觉,随后恍然大悟。

大约三十年前,第一个商业 SQL 关系数据库出现在 IBM、Ingres 和 Oracle 等公司。数据库将储存、管理和分析以表格形式组织的数据。它们本身并没有给最终用户带来任何明显的好处,但它们是一套技术和工具,让的企业能够创造出无穷无尽的应用。如今,我很难想象全球有哪家公司没有由关系数据库以及现在的非 SQL 数据库支持的应用程序。它已经成为无处不在的 T4,它们所能实现的应用数量仅仅是想象力极限的函数。****

同样,今天人工智能市场的发展正受到难以置信的强大和可访问的人工智能工具包和技术的推动。这些工具包允许构建无限的应用程序。DeepIndex 允许你查看近 300 个人工智能应用,其中大部分都是用这些工具包构建的。

这些工具可以轻松地用于实现有价值的应用程序,这意味着在未来几年,我们甚至可能不会谈论人工智能和机器学习,因为它将如此普遍,并融入所有技术的结构中。

人工智能将在数千个用例中证明真正的经济价值

我现在想知道人工智能的经济价值。因此,我在过去几个月里绘制了数百个人工智能用例,并查看了数百家人工智能公司以及大量的技术工具包和框架。我想知道人工智能现在是如何在公司各部门、公司和行业中使用的。我想知道人工智能是否有真正的价值。我很难确定未来几年不会使用人工智能的单一功能和行业。

虽然今天人工智能的许多企业应用都处于规划和实验阶段,但人工智能的商业应用将从帮助更好地管理和分析企业数据财富开始。机器学习在发现海量数据集中的模式方面非常出色。它的应用将使公司增加收入,降低成本,提高生产力,改善产品和服务。机器学习真正擅长的一些任务包括:

  • ****识别视觉模式,例如识别场景中的人脸和物体,在视觉上检测生产线上的缺陷,在病理切片上发现癌症标记,或从检查照片中估计汽车的损坏程度,或确定品牌标志何时被无证使用。
  • ****预测,例如哪些客户可能流失,哪些消费者最有可能转变为付费客户,或者确定何时应该更换零件以提供预测性维护。或者预测哪些信用卡交易可能是欺诈。或者一个人会根据别人的推荐喜欢哪些电影。以及我们网络中的哪些活动违反了网络安全。
  • ****语音和自然语言处理,例如自动筛选和排列简历或确定客户的情绪,以帮助呼叫中心代理更好地响应客户。

当然,围绕传感和反应技术有一整套用例,如机器人和自动驾驶汽车。

那么谁来从 AI 身上赚钱呢?

在检查人工智能使用案例时,很明显我们现在正进入一个真正的人工智能黄金时代。成千上万的新公司都在竞相抢占他们的份额。我将把我的分析留到另一篇论文中,但有几个关键主题似乎表明了经济** 价值正在向何处转移:**

  • ****数据是 AI 的关键。要训练机器变得聪明,拥有数据训练集至关重要。拥有数据集的人处于有利地位。几年前,优步(Alibaba)或 AirBnB 等新贵可以颠覆整个行业,而现在,一些价值和权力转移回了现有企业。谁能比拥有大量承保索赔历史数据的保险公司更好地利用人工智能呢?这家金融服务公司对消费者的购买行为了如指掌?或者是用户搜索信息最多的搜索公司?
  • 全球科技巨头正在为人工智能领域的领导地位展开军备竞赛。据 CBInsights 报道,2016 年科技巨头在人工智能领域的投资超过 200 亿美元。谷歌可以说是世界上最大的人工智能公司。但它正与亚马逊、微软和 IBM 争夺主导地位。人工智能初创公司几乎没有机会颠覆这些巨头关注的人工智能基础设施和平台。很少有创业公司会在云计算上比微软花费更多或更聪明,或者比谷歌的张量处理单元建立更好的人工智能芯片,或者比亚马逊建立更好的物体识别软件库。
  • ****国家也在进行人工智能军备竞赛。中国并不羞于在 AI 问题上发出自己的声音。它认为自己比美国具有结构性优势,包括更具支持性的监管框架(特别是在数据隐私和使用方面),其政府支持的人工智能生态系统包括对不断增长的技术和工程人才的巨额投资,以及大规模的数据和可用性。中国的 AI 公司比如百度或者 Face++真的很好,有海量的数据集。中国人指出,他们的移动市场是美国的 3 倍,移动支付是美国的 50 倍,这是一个巨大的数据优势。
  • ****人工智能初创企业比比皆是,但它们需要获得独特的数据集、深厚的领域知识、雄厚的资金以及吸引日益紧缺的人工智能人才的能力。这不是一个车库里的应用程序会改变世界的案例。2016 年,VC 和 PE 对人工智能公司的投资超过 60 亿美元,其中大部分是机器学习横向应用。

人工智能的淘金热开始了。但是看起来越来越像是最大的公司和国家将获得经济价值的最大份额。

最后的反思——学习人工智能既容易又难

在过去的几个月里,我决定休假去研究人工智能。我真的很想弄清楚什么是真实的,什么不是。了解人工智能的现状在很大程度上是一个大数据问题。关于正在发生的事情的信息量、种类和速度是巨大的。这反映了一个真正蓬勃发展的行业。跟上最新的人工智能研究、技术、工具、初创公司、用例就像从消防水管喝水一样。如果你在谷歌上搜索神经网络,你会看到 140 万篇文章。随着 d eep 神经网络,胶囊网络,卷积网络,LSTM,BatchNorm激活函数,随机梯度下降,降维,嵌入,辍学,残差网络,Keras,Tensorflow,递归神经网络(RNNs),残差网络,数据角力,Python,内核,前馈,监督 Vs 非监督等等的首字母缩略汤,很容易变得不知所措。互联网已经被证明是能够找到信息的真正繁荣,但问题是有太多的信息。

所以我决定回到学校。我需要回到一所受信任和尊重的学校的教室,这所学校以其教学法而闻名。那我做了什么?我报名参加了一个大型开放式在线学习课程(MOOCs)。我选择了吴恩达教授的 Coursera 深度学习课程,他是斯坦福大学的兼职教授,曾在谷歌和百度工作。他是一位出色的教师,了解人工智能的教学方法。成本仅仅是我的时间和月费,比你的星巴克咖啡还少。MOOCs 已经民主化教育,这是大约三十年前我第一次上人工智能课程以来的一个巨大变化。

在线课程既有趣又有挑战性。我发现它们重新激活了我大脑中的部分区域,在那里,我的导数和微积分、大规模维度矩阵和向量空间、编程(现在是 Python)和机器学习算法的知识出人意料地处于休眠状态。它回来了。几十年后,这种材料变得异常熟悉。编程肯定比以前容易得多——有数百个库处理所有困难的部分。

事情越是变化,它们就越是一成不变

我会对工作场所产生真正的影响,但我们应该忽略这种夸张。工作岗位最终会被取代,但在很大程度上,人工智能将被证明是生产力的繁荣。是的,人工智能确实令人担忧,比如黑客攻击的数字风险,自主无人机远程攻击等物理风险,以及虚假宣传和国家监控带来的政治风险。但是,这些机器还远远没有达到真正取代我们的普通智能水平。当今天的神经网络学习猫和狗之间的视觉差异时,它不具备人类那样的概括和持有这些动物的任何概念的能力。它不知道它们还活着。他们是宠物。应该轻轻地抚摸它们。他们应该得到食物。他们有感情。它知道的很少。

三十年前,我们研究了一般智力和狭义智力的概念。一般智力还有很长的路要走,但是狭窄已经有了很大的改善。人工智能真正改变的是,工具、技术和算法真的进化了。现在大规模实现人工智能要容易一百倍甚至更多倍。而且便宜很多。现在人工智能的经济机会很大,令人兴奋。淘金热正在进行,经济利益将再次被少数人和大多数人攫取。

但是如果你问我三十年来发生了什么变化。一切都变了,但从概念上来说,并没有什么真正的改变。

作者 作者 西蒙·格林曼

我热爱技术以及如何将技术应用于商业领域。我很幸运地在互联网早期共同创立了MapQuest.com服务,并继续利用技术来发展、创新和改造公司和行业。我目前经营着自己的咨询公司 DigitalInnovators.a 帮助董事会和高管让他们的公司实现人工智能。

如果你喜欢这首曲子,我希望你能按下拍手按钮👏所以其他人可能会偶然发现它。你可以直接给我发电子邮件在 LinkedIntwitter 上找到我,或在 Simon Greenman 上关注我。

所以你将管理一个数据科学团队

原文:https://towardsdatascience.com/so-youre-going-to-manage-a-data-science-team-31f075809ffd?source=collection_archive---------0-----------------------

我见过你们这些人不会相信的事情。仪表板上着火的数据透视表。r 脚本在 Hadoop 集群附近的黑暗中闪闪发光。

但是(很抱歉鲁特格尔·哈尔剽窃了他的精彩独白)我也看到了很多数据科学是通过技术实现的——首先没有将人或流程考虑在内,我想我应该提出一些源于我引导客户和合作伙伴通过这些水域的经验的想法。

作为一名崭露头角的企业人类学家,(恢复中的)技术总监和国际养猫人,我经常惊讶于对技术技能和工具的重视程度,而不是实际建立一个有效的团队。

作为一名训练有素的工程师(尽管有明显的量化倾向),我对让数据科学团队成功所需的技术、技能组合甚至数据类型的意见非常着迷,因为实际上很少有关于哪些是关键因素的硬数据。

因此,我将从所涉及的技术和科学后退一步,看看流程应该如何工作,以及不管你的背景如何,在管理数据科学团队时应该考虑的一些事情。

人员、流程、技术

几年前,我(被我的前首席技术官)反复灌输卓越是一个过程,这句格言一直伴随着我,因为他指的是个人和团队成长意义上的“卓越”,而不是利用科技炒作或搭乘六适马列车。

请注意,工具和技术至关重要,但你必须放眼全局。

以深度学习为例: Tensorflow 可能是目前的首选库,但 Keras 会给你一个更好的抽象,也让你利用 CNTK 作为后端,并可能在迭代问题时获得更快的周转,所以我认为它应该是你(和你的团队)需要投资的更高级的工具。

如果你从长远来看,从纯统计/回归方法到 RNNs 的整个过程意味着一个深刻的承诺,不仅是学习它们背后的科学,而且是理解它们在你必须解决的一系列挑战中的位置。

相信我,选择工具并不是你需要首先解决的问题——你应该首先解决的是你的团队,然后是团队运作的环境。

第一个错误

组织(和管理者)犯的第一个错误是认为向你汇报的数据科学家就是你的整个团队

无论人们对矩阵管理和跨职能团队的需求谈论了多少,人类都有一种将人(和事物)分类到漂亮整洁的箱子里的自然倾向,当你必须激励和推动人们时,就会涉及到额外的偏见——毕竟,作为一名经理,你的主要职责是确保你被分配的团队团结一致地工作,在数据科学领域(尤其是在该领域的新公司),也需要证明你的价值。

我的意思是团队的价值——你可能凭借自己的能力成为一名奇才,但你的工作是确保你的团队能够实现目标,并且在你的直接下属内部和外部都清楚地定义了目标和期望。

所以你的实际的团队由各种各样的利益相关者组成——产品所有者、管理层,以及(同样重要的)技术角色中的其他每个人,因为你所做的事情(以及你所获得的洞察力)不可避免地会影响业务的其余部分,以及它是如何构建/实现/部署的等等。您并不存在于真空中,而是您拥有的数据(或者,更多情况下,没有)和业务需要改进的数据之间的管道(我在这里有意避免逆向流动,即当业务要求您改进已经实现的东西时)。

在大数据炒作期间,我以前见过非常类似的事情发生,我们成功解决这一问题的方法是通过建立人员“小组”来解决每个具体问题-每个小组由通常的三人组成,即数据科学家(通常是您的直接下属)、实施者(可能是也可能不是)和领域专家(通常是产品所有者或业务利益相关者)。

我使用上面的术语“实现者”,因为根据您正在处理的问题,问题域可能需要:

  • 数据转换的快速迭代(在这种情况下,您可以用开发人员或 DBA 来担当这个角色)
  • 整合数据可视化(前端开发人员或设计人员)
  • 或者弄清楚如何大规模部署模型(架构师或开发人员)

不管是哪种方式,最终结果都是,在更正式的组织中,你会发现自己不得不与管理同行混合和匹配时间表,因此,如果你能清楚地沟通总体目标是什么,以及应对特定挑战需要什么样的技能,这将会有所帮助。

从里到外都不辜负这个角色

你有丰富的实践经验,你的团队尊敬你,你让自己参与关于架构、特性工程、算法选择和模型评估的各种讨论——这很好,除了管理与此无关。

管理一个团队需要你走出自己的舒适区,处理好优先事项,遵守截止日期,指导人们的职业生涯,以及在商业环境中领导人们和交付成果所带来的所有混乱、不科学的问题。

这里最重要的是避免成为冒名顶替综合症的牺牲品——记住,你得到这份工作是有原因的,对吗?成为一名经理并不意味着你停止做科学工作——事实上,你可能会比你通常做的更多的科学工作(但在更高的层次上),仅仅因为你需要了解你的扩展团队在做什么,识别陷阱或障碍,并把人们引向正确的方向。

要做到这一点,你需要学会如何有效地沟通——不仅仅是在团队内部,还要在团队外部,而且经常是与没有相同背景(技术或其他)的人沟通。

将流程落实到位

随着工作的到来和你所有的豆荚排好队,你的团队开始建立一个挑战的管道来通过(通常有多个子挑战,因为你开始钻事情)。那么,你如何将这些挑战分配给你的团队,同时让每个人都开心呢?

在我们解决这个问题之前,我们需要后退一步,想想人们最有可能如何度过他们的时间。

在扩大数据科学团队的规模时,基本上有两个约束,它们都归结为时间:理解问题和制定解决方案所花费的时间,以及实施和推广它所花费的时间。

实际上,通常发生的情况是:

  • 你的团队 80%的时间将花在挖掘数据的意义上:搜寻数据集、做 ETL 和做初始特性选择。到目前为止,第一部分是工作中最不吸引人的部分,但它与人类对数据和问题领域获得直观感受的需求非常契合,因此你应该置身事外。无论如何,每天都要站起来(如果这是你的事情),和团队坐在一起讨论他们在做什么,但是当被要求/需要时,尽量只利用你自己的专业知识——不要微观管理人们,而是帮助他们从长远角度出发,把他们正在做的事情变成可重复的过程。
  • 剩下的 20%的时间通常花在弄清楚如何让你的数据和模型对公司的其他人可用上——这是大多数数据科学团队忽略的地方。

碰巧的是,交付数据科学比生成报告和仪表板有更多的。所以你(作为一个经理)应该期望花费大量的时间(在早期可能高达 80%),检查上面的 20%,并与你的团队合作,将他们所做的转化为可重复的、可度量的过程,或者通过利用持续集成工具来比较迭代之间的模型,或者通过定义检查和平衡:什么特性被添加到了模型中?它在新数据集上的表现如何?考虑到您的数据(或业务流程)的更新速度,它多久会过时?

一个好的经理知道在“快速失败”方法和不仓促行事之间要取得平衡——尽一切可能让人们去尝试新方法(这是让人们开心的一个重要部分),但是定义你要用来衡量结果的尺度——我们是否从新模型或工具中获得更快的周转?它是否在不影响性能的情况下表现得更好?我们是否获得了诸如自动消除偏差或防止过度拟合之类的附带好处?

根据您的公司、资源和流程,开始时可能需要相当长的时间,但这里的想法是,当您开始交付解决方案时,您构建一组其他人将使用的 API、基础架构或数据集,为它们定义路线图,并对它们进行迭代——因此您与其他团队构建的桥梁在这里将是无价的。

用科学发展你的团队!

很快,你就会发现谁有解决特定问题的诀窍或专业知识。然而,不要把看起来像钉子的东西都分配给他们,把这些人和以前从未做过的人配对

让他们拓宽视野,再一次把它变成一个可重复的过程,同时也把它展示给他们的同伴。一定要介入引导讨论,但要记住,个人成长来自于学习新的东西并将它们传递下去,如果每个人都清楚这些过程,并且如果他们将这些过程视为工作的一个组成部分,那么你的团队将会更加有效(和快乐)。

不要因为效率而陷入流程中,或者为了自己的利益而开始计算 KPIs 相反,把流程看作是给你们所有人正在做的工作增加结构(因此意味着什么),并从改善手册中吸取经验。

让数据科学成为公司文化的一部分

一旦其他一切就绪,确保组织理解您的团队角色的最佳方式包括走出团队——这意味着再次利用您的沟通技巧:

  • 在其他团队中培养一种以数据为中心的文化,让他们明白这并不是真的要存储大量的原始数据,而是要确保你拥有的数据集能够被清楚地识别,并且容易获取(在这方面有关于个人身份信息和适当的数据卫生的常见警告)。
  • 就可以以最小的开发/集成开销进行交换的通用数据表示(或桥格式)达成一致,并就其他团队访问您的团队生成的训练模型的 API 达成一致。
  • 解决真正困难的问题,比如从面向批处理的流程转移到事件流。欺诈检测、推荐引擎和其他业务所依赖的主要工具需要即时访问数据,而且(从经验来看)无论从技术上还是从业务角度来看,没有什么比处理流数据更好的了。
  • 了解企业想要什么。没有什么是真正必要的,实际上是不可能的(即使考虑到最近围绕数据科学的大肆宣传,这似乎很难),并且会有很多人耐心地引导人们回到可行性领域,但请记住,你被选为经理是因为你擅长建立桥梁,在所有方面。

最重要的是,不要害怕——你仍然在做数据科学

即使上面的一些在一开始对你来说并不自然,也不要担心。你会没事的,只要你不断地重新训练你自己的心智模式,让你知道你的团队(和你)在大局中所扮演的角色。

请放心,您将能够花费大量时间进行实际的数据科学研究,即使只是因为上述概述的大多数业务和团队相关方面的发展比您预期的要慢得多——没有优化人类组织的梯度下降算法,而且,从各方面考虑,我认为这是一件好事。

(本文 原载于 LinkedIn )

使用 Apache Spark 和 Neo4J 进行社交网络分析

原文:https://towardsdatascience.com/social-network-analysis-using-apache-spark-and-neo4j-1ccba3c8af9a?source=collection_archive---------6-----------------------

了解社会系统和互动的旅程

Photo by Matthew Cabret on Unsplash

我对社会网络分析(SNA)感兴趣已经有一段时间了,从小规模问题开始,最终使用手机数据解决大规模问题。以我目前在 Praekelt 的角色,我们可以利用这些概念来接触难以接触到的个人,例如,鼓励他们进行 HIV 检测。

作为学习曲线的一部分,我发现 Apache Spark 在处理能力方面提供了实质性的提升,当与图形数据库(Neo4J)结合时,完全改变了必要的东西。在这篇文章中,我试图给出 SNA 可能有用的地方,一些 SNA 术语和指标,以及一个可以用来大规模分析社交网络的代码链接。

为了将这篇博文建立在真实数据的基础上,我使用了 Statnet R 包中的一个数据集。这些数据是基于哈里斯、弗洛里、塔博尔、贝尔曼、琼斯和乌德里的数据通过模拟生成的。由于数据是通过模拟生成的,因此不存在匿名或隐私问题。这些数据是一个不变的、无方向的友谊网络,由 1,461 个模拟个体组成,包括他们的年级、性别和种族。

查看社交网络时,理解一些词汇很重要。下面我们找到了一些常用词:

  1. 节点:个人的图形化表示。
  2. 边:边代表两个个体(节点)之间的关系
  3. 度:连接一个节点的边数。这些可以进一步细分为入度(即传入边沿的数量)或出度(传出边沿的数量)。
  4. 组件:这是一组独立的个体(在图中表示为节点),它们相互连接。

A graph representation of part of thesimulated social network used in this blog post

现实社会网络中有许多有趣的观察结果。其中之一是,如果一个人有两个朋友(一个三联体),那么这两个朋友也很有可能是朋友。这就是所谓的。当试图影响社交网络中的信息传播或连通性时,这可能是有用的。

Demonstration of triadic closure

第二个有用的度量被称为 聚类系数 这衡量一个集群中实际连接的百分比,与可能连接的数量进行比较。较高的聚类系数表示图中的高连通性。

(【物以类聚】)是现实世界网络的属性。个人更有可能与和他们至少有一些相似之处的其他个人联系在一起。在下面的图表中,我们展示了模拟数据集中种族的同质性,然而,这也与性别和年级有关。

另一个有用的度量是给每个节点分配一个影响级别。有很多方法可以实现这一点,但最广为人知的可能是 PageRank。 下图证明了这一点,其中,与联系较少的个人相比,联系较多的个人被分配了较高的 PageRank (PR)。

能够处理大型社交网络是很有用的,考虑到边的数量,这些很快成为难题。这得益于大规模并行处理平台,如 Apache Spark。我在我的 github 页面(https://github.com/chopley/spark_social_network_analysis)上放了一个教程来指导用户完成这个过程。特别是 Apache Zeppelin 文件将引导新用户完成计算上述值的过程。本教程还将指导您设置 Neo4J 并生成上面的图。

我希望你玩得开心!如果你觉得这个有用,请给我一个掌声!

  1. Mark S. Handcock、David R. Hunter、Carter T. Butts、Steven M. Goodreau 和 Martina Morris (2003 年)。 statnet :网络数据统计建模软件工具。网址http://statnetproject.org
  2. Harris KM,Florey F,Tabor J,Bearman PS,Jones J,Udry JR (2003)。"全国青少年健康纵向研究:研究设计."北卡罗来纳大学技术报告。网址http://www.cpc.unc.edu/projects/addhealth/design.

社交网络数据:Twitter vs FB vs Google vs 其他所有人

原文:https://towardsdatascience.com/social-network-data-twitter-vs-fb-vs-google-vs-everyone-else-830ea0291c86?source=collection_archive---------3-----------------------

这是关于技术如何塑造我们的社会联系的三篇系列文章中的第三篇。第一篇文章试图让你相信我们的在线和离线社交网络非常重要。第二篇概述了一些 T2 策略,设计者可以用来设计更好的社交网络。

如果我是你的朋友,谁拥有这些信息?脸书说我们中的任何一个都可以向世界展示我们的友谊。但是这让许多脸书用户感到惊讶,所以他们不断报告这是一个安全漏洞。关于我们社会互动的信息提出了独特的挑战。

这篇文章着眼于社交网络数据的来源,并对它们的质量、可用性和道德合法性进行评级。我的博士研究使用了 Twitter,但我已经用脸书数据、引用网络和离线网络做了工作。我还怀疑谷歌坐拥有史以来最有价值的社交网络信息,即使它不知道如何处理这些信息。

推特

Twitter 非常适合研究:默认情况下它是公开的,平台很乐意与用户分享(有限的)数据。它也有一种“城市广场”的氛围,是一个讨论当今重大问题的地方。

在我的博士学位中,我开发了一个工具,它使用 Twitter 数据来帮助地方政府改善和定位他们的服务。有一个问题,正如布兰克所说:

英国的推特用户比其他互联网用户更年轻、更富有、受教育程度更高,而其他互联网用户又比离线的英国人更年轻、更富有、受教育程度更高

类似的情绪在英国以外也是如此。在整个研究过程中,我已经意识到了这个问题。作为回应,我有两个论点:1)有数据总比没有数据好,所有的数据都有偏差,2)年轻人与当地政治无关,所以他们是一个可以接触到的好群体。

即便如此,Twitter 对更富裕、更有权力的人的过度描绘总是让它感到力不从心。社会的某些部分是“难以触及的”,如此难以参与,以至于几乎任何试图增加参与的系统都会失败。长期失业的人、不讲英语的人、露宿者——这些群体将需要不同的、可能是高度资源密集型的方法来增加他们的民主参与。一个让他们失望的系统不一定是完全失败的,如果它可以服务于其他不那么严重的弱势群体。尽管有这种逻辑,Twitter 在大多数时候确实是最有优势的。也有少数例外,可能为以后的工作指明方向。例如,对于行动不便的人或者不喜欢面对面交流的人来说,Twitter 是一种政治包容的手段。

Twitter 的另一个问题是让计算机处理数据。直觉上,推文应该对软件来说是高度易读的,包含非常丰富的元数据的简短文本——时间、地点、作者、标签、@提及。这还不是故事的全部。也许部分是因为推文的简洁性,有意义的推文活动分散在多条消息、讽刺性的转发、用户简介、图片中的文本、子推等上下文信息中。这些对计算机来说很难理解。

尽管有这些缺点,你会猜想 Twitter 应该是一个令人惊叹的研究平台。但是你多久能从 Twitter 数据中看到真正惊人的见解呢?感觉有点累了。

数据政治:Twitter 可能有各种各样的政治问题,但就数据而言,它非常透明:(本质上)一切都是公开的。当然,有些人会在公共场合说一些事情,并希望他们没有这样做。我认为任何保护人们免受这种危险的系统都是幼稚和家长式的。Twitter 非常明确,你的推文是公开的——这是 Twitter 服务的核心部分——我不认为这有什么道德问题。(虽然跟我提过很多次。)

数据质量:不完整,不具有人口统计学代表性,我的猜测是,将 Twitter 数据与其他来源结合起来将是其未来最丰富的应用。

数据可用性: Twitter 有一个可爱的 API(一个获取数据的计算机可读接口)。

脸谱网

脸书是最大的社交网络,所以你可能会猜测它一定有最好的数据。我想你可能错了。脸书的许多手势——也许尤其是“表示友好”——都以一次性乏味著称。脸书的原始友谊数据可能只不过是谁和谁一起上学的列表。(大多数情况下——我知道脸书有一些小众社区,它们编码了不同的关系。)Facebook Messenger 的互动可能更能表明有意义的社会关系——但话说回来,它可能只是告诉你他们最亲密朋友的相对较短的名单。

脸书提供了一个页面,在这里你可以看到他们对你的了解。我最近让一些学生使用这个工具,并告诉全班他们觉得它有多准确。从你在报纸上听到的,每个人都会被脸书的窗户送到你的潜意识里。事实上,大约一半的学生认为它有相当准确的信息,另一半认为它基本上是错误的。

数据质量:未知。很多人——包括营销公司和脸书本身——都有动机让人们觉得脸书的数据比实际情况要好。 WhoTargets。Me 是一个监测脸书政治广告的项目,在英国 2017 年大选前,我们看到了许多针对性很差的广告。这不一定直接反映 FB 的社交网络数据,但它可能是指示性的。

数据政治:绝大多数脸书用户不知道脸书有什么数据,也不知道如何浏览其隐私设置。众所周知,脸书也因其与俄国的关系而成为政治猜疑的对象。合法性不足。

数据可用性:脸书是一个有围墙的花园。几乎不可能在它上面建造任何东西。你可以要求用户安装一个 Chrome 插件,我们在 WhoTargets.me 项目上就是这么做的。不过,大多数情况下,研究人员都被脸书拒之门外。

谷歌

My Gmail network, visualised. Whose data is this for me to publish? (I’ve obscured uncommon names)

如果脸书没有强大的社交网络数据,谁有呢?Gmail。电子邮件是冗长、耗时的交流方式:它们是昂贵的信号。他们代表了各种各样的网络联系,不仅仅是你的朋友:专业的,社会的,甚至是与银行,能源供应商等的客户关系。Gmail——为此做好准备——拥有大量来自非 Gmail 账户持有人的网络数据。即使你不使用 Gmail,你一半的电子邮件(和相关的网络数据)仍然会被谷歌处理掉。如果电子邮件中的一个人有 Gmail 帐户,Gmail 可以看到收件人的完整列表。一个使用 Gmail 的自由职业者可以将整个公司结构的社交结构泄露给 Gmail(假设你的公司还没有使用 Google Apps……)。

数据质量:大概难以置信。

数据政治:谷歌的历史有些清白。它没有被指控选举了特朗普。很多人都有过这样的经历:在脸书分享的内容超过了他们的预期,而在谷歌上分享的却更少。他们甚至试图在 Google +平台上使用他们的社交网络数据,但是失败了——可能主要是因为实施而不是隐私政治。

数据可用性:与脸书不同,Gmail 的社交网络数据并非完全无法获取。我使用麻省理工学院的沉浸工具生成了上面的可视化效果。用户必须给出明确的许可,正如他们应该做的那样。

所有其他的

我想强调几个不太明显的社交网络数据来源。一个有趣的例子是同路人数据——来自位置数据的社交网络数据。

Co-traveller analysis carried out by the NSA. (via the Washington Post)

即使你有一群人非常好的位置数据,也很难知道他们是在互动,还是只是站得很近。除非你从统计学的角度来看:即使有非常低分辨率的位置数据,你也可以开始对社交互动做出强有力的推断,只要你有足够的位置数据点来工作。这里有很多很好的贝叶斯分析要做,但直觉很简单——如果两个人经常在不同的地方彼此靠近,他们可能认识彼此。

上面的信息图是为了解释美国国家安全局如何使用同路人分析来秘密跟踪潜在目标。但是你也可以在人们的许可下使用它,如果你建立了一个他们可以信任的平台,并且提供了一个合适的有说服力的提议。

最后,我想提一下学术引用网络,这是我和我的 Who Cites 一起工作的。项目。学术引用占据了一个特别有趣的伦理位置。学术研究几乎总是由国家支付部分费用,因此公开相关数据似乎是合理的。它还有可能揭示关于谁应该与谁一起工作,以及谁的工作最有影响力的有用信息。这与非市场合作(公共资源)的更广泛的想法一致,科利·多克托罗很好地概括了这一点。

摘要

在三篇文章中(第一篇第一篇和第二篇这里),我试图解释我在博士期间学到的一些东西。用非论文的语言写出来,对帮助我理清我认为我已经学到的东西,并思考下一步该去哪里有着难以置信的帮助。我已经感觉到另一个帖子,这次是关于道德的,即将到来…

社交网络、恐怖主义和数据隐私

原文:https://towardsdatascience.com/social-networks-terrorism-and-data-privacy-b72e2b012793?source=collection_archive---------6-----------------------

By Martin Grandjean — Own work : http://www.martingrandjean.ch/wp-content/uploads/2013/10/Graphe3.png, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=29364647

我正试图开始一个新的小项目来帮助我跟上世界上发生的事情。我订阅了《经济学人》,但这些问题一直堆积在咖啡桌上,无人阅读,所以我努力改变这种状况,确保我不会持有愚蠢或无知的观点。

我的想法是每隔几周左右挑选一些我认为有趣的文章,总结它们,也许解释一点背景,并形成至少一个半可辩护的观点。

这里什么都没有。

本周有两篇关于科技公司如何运作以及这对恐怖主义、美国政治和信息隐私意味着什么的文章。这些文章是:

恐怖和互联网

在过去的十年中,互联网已经从一个大型的、分布式的、开放的网站集合变成了一个非常小的强大的、流行的、封闭的网站群。谷歌和 Facebooks 已经成为培育社区的平台,而这些社区对社会的影响并不总是积极的,由于这些平台是集中的,它们的支持者正在为发生在它们身上的事情受到一些指责。主要问题是假新闻、暴力和极端主义宣传、版权规避以及其他一些相对来说不那么重要的东西。

大部分讨论将是关于极端主义的宣传,因为这是原始文章和姐妹文章所强调的。

脸书、Youtube 和其他社交平台已经花费了数亿美元来维持高质量的产品。他们的运营团队打击垃圾邮件、欺诈、处理安全问题,以及执法部门通常处理的其他好事情。其中之一就是监控潜在的极端组织的皈依者。似乎令人毛骨悚然,但很有必要。抱怨似乎是这些公司做得不够,但对于一个已经做了很多的公司来说,这是一个相当强硬的声明。

科技公司的运营通常被视为成本中心。增加主要成本中心的成本通常是你想对公司做的相反的事情。问题是这些活动对你的底线有多大帮助,这种激励是否足以涵盖合理的反恐努力。

事实上,有几个问题是我感兴趣的,尽管在思考这如何影响社会时可能被认为是理所当然的。我在这里只是稍微绕一下路,因为我对获得真实答案的技术可行性感兴趣。总之,问题是:

  • 我们如何知道社交平台上的招聘意义重大?
  • 为了减少对社会的不良影响而去刷洗互联网的成本值得吗?我们在这方面能有多有效?
  • 是谁的责任?

为此做实际工作会非常有趣,但很耗时,但这是我的个人博客,而不是博士论文,所以我将通过一个攻击计划来解决工作。我会把这个放在我未来技术项目的候选名单中。

衡量招聘率和寻找细分似乎相当困难。显然,大多数对恐怖主义的定量分析研究都集中在基于地点的恐怖袭击频率上(根据 Young 的测量恐怖主义,一篇超级有趣的文献综述)。这是有道理的,因为在此之前,任何有关恐怖活动的信号都很难从公开数据中衡量。这让我对军事情报中使用的方法非常好奇。

但是,如果恐怖组织通过营销转化模式招募的人数在增加,那么应该有办法通过这个平台来衡量。例如,你可以从 Twitter 的消防水管中获取信息,过滤那些带有极端主义宣传的链接,然后简单地统计一下。毫无疑问,IS 社交媒体经理有多个账户,但我们应该看到这两种情况下的趋势,因为它应该与一个常数成比例(除非扩展单个工具是可行的,这不是一个疯狂的想法)。如果您真的担心这个因素,您可以运行一个重复数据消除方案,它可以变得像您喜欢的那样复杂。这绝对是可能的,因为我知道一些大型的科技组织已经在这么做了。这是相当资源密集型的,因为它有大量的数据,但科学家在没有特殊数据访问权限的情况下也可以做到。

应该有类似的东西可以在 Youtube 和脸书上工作,我很有信心联邦调查局和国家安全局已经这样做了。尽管他们并没有真正谈论他们的成功率。正如我前面提到的,大多数对恐怖主义的统计分析将袭击的频率视为一般恐怖活动的信号。对于打击恐怖主义的总体目标来说,这很好,但如果我们想从社交网络方面了解招募工作的情况,我们需要更精细的东西。

这让我想起了一个博士生,他曾经秘密为美国某个地方的毒枭工作,然后写了一本关于他的经历的书。

我有更多的技术想法,但我不想让任何非技术读者感到厌烦,所以我们应该继续。我将跳过关于媒体版权的讨论,因为它不像恐怖主义和政治那样引人注目,因为我感觉这篇文章已经很长了。然而,这是一个很好的例子,说明过多的监管会扼杀技术进步,所以有点遗憾的是,我不会在这里过多地谈论它。

上述方法可能在某种程度上适用于分析假新闻,但有一个很大的区别:极端主义宣传(通常)对人类来说是非常明显的,但假新闻不是,我认为这是部分原因。我愿意不加分析地相信假新闻是重要的,但我对通过社交媒体招募恐怖分子有点怀疑。这看起来可能是一个奇怪的观点,因为恐怖分子会试图让这种方法奏效是完全合理的,但我认为这是一个简单得多的技术问题。我也看到了这些平台积极删除极端内容的强烈动机,但这与这些平台目前的做法相冲突(根据《经济学人》的文章)。

进入下一个问题:这是谁的问题?我想大多数人都会同意,科技公司应该监管自己的平台,但当我们讨论如何监管时,这个问题变得有趣了。

总的来说,我认为让公司做新的技术工作,以有趣的方式改变我们的生活是一件好事,但它需要经过大量的思考。我们已经看到了大约十年的大规模社交媒体,我们正试图确定它的哪些部分很糟糕。我认为联邦调查局和国家安全局迫使脸书在打击外国恐怖分子的斗争中采取符合美国最大利益的行动是正确的。但是如果不是恐怖分子而是另一个国家呢?如果敌人变成某些美国公民呢?所以这就成了问题。

这实际上导致了一些关于这些公司正在收集人们的私人数据的有趣讨论,这是本文后半部分的主题。你永远不知道这些数据库什么时候会被用来对付你,或者在那种情况下如何保护自己。GoogBookSoft 也是国际公司——如果有人因为你争取跨性别权利而决定在莫斯科的机场拘留你,会发生什么?

这篇文章批评科技公司只在影响到他们的底线时才投入资源,尽管打击假新闻最近已经成为一个社会优先事项,但如果公司认为他们可以忽视假新闻而不受惩罚,这种情况可能不会持续下去。

这是一个很好的批评。科技公司真的需要理解它们在社会中的长期角色,即作为公民对抗政府的工具。文章称,如果维护平台质量的自身利益还不够,那么唯一的求助手段就是法律。暂且忽略公民权利,我认为,如果它试图将市场推向正确的方向,而不是破坏性地、强有力地这样做,这可能是好的。这一点很重要,因为在这些问题上的强硬立场会减缓较小的竞争对手的进展,这些竞争对手可能没有资源来完全遵守。

但是有很多原因可以解释为什么你根本不希望政府介入。互联网是人们对抗日益强大的政府的巨大工具。Youtube 和 Twitter 在阿拉伯之春革命中的作用,以及维基解密帮助监控举报者的行为,非常清楚地表明了这一点。我在这里提供了一个有点滑坡的论点,但我认为这是完全有效的,因为我们正在玩一个每个玩家都在不断争夺更多控制权的游戏。自从第一只阿尔法雄性大猩猩被赋予统治地位来领导其余的笨蛋大猩猩以来,这一点就一直如此。

这其实是一个很大的哲学问题。我们想要安全和结构,还是无政府和自由?

最后,我认为如果你的兴趣是反恐,这种讨论会分散你的注意力。为此,我们真的需要从根本上解决问题,为什么人们一开始就想加入极端组织,并以其他方式缓和这些情绪。这是一个我想在以后的文章中多探讨一点的领域。

我认为,极端分子的招募是一个非常有趣的例子,说明了互联网(及其随后与社交网络的演变)带来的更强大的社区建设的更广泛影响。看看它是如何帮助恐怖分子的,可能会很容易说这对社会是一件坏事,但这将是一个错误。这只是不同,我们需要学习新的方法来应对一个可以在其他观点(有效或无效)中找到安慰和认可的社会。

未来的燃料

我真的很喜欢阅读和思考这两篇文章。我花了很多时间试图理解这波新的免费互联网产品的成本。我把它看作是“没有免费的午餐”定理的一种应用——每样东西都有它的成本,只是找到它的问题。

我们在自己的数据中没有发现很多价值。这只是总体上的问题,对一家公司来说,匿名与否并不重要,只要他们能影响你的行为,这是他们想要的。即使是拥有数据的公司也没有真正理解它在具体方面的价值(文章称,数据是不可替代的)。这体现在“数据交易”中,即公司同意相互提供对方的数据库,在某些情况下,公司宁愿收购其他公司,也不愿为自己的数据谈判价格。这基本上是以物易物,在如此先进的行业中看到这种经济倒退非常有趣。但我不是经济学家,所以这可能不是很有见地。我很想知道其他商品不容易估价的市场。

公司希望尽可能多地囤积数据,以获得竞争优势。对于一种实际上永远用不完的资源来说,这似乎不是最佳选择。这篇文章谈到印度政府将中央身份系统作为公共基础设施,并询问强迫公司开放其数据是否会缓解一些反垄断问题。这可能会,但不幸的是,这也加剧了隐私问题,因为更多的公司将获得这些数据,而大规模的交换更有可能导致泄露。类似 HIPAA 的法规可能会在这里发挥作用,但看到它给医疗和生物技术初创公司带来的额外负担,我确信它会大大减缓创新。

我认为如果有选择的话,我更喜欢数据公开,即使存在隐私问题。相互竞争的公司中存在太多的低效问题,这对社会没有好处。只有在行业已经发展起来的情况下,旨在人为维持竞争的监管才有意义。在此之前,你只是在扼杀创新。

我不会说脸书或谷歌应该成为公共基础设施。这实际上是一个可怕的想法——与道路、污水或水不同,搜索引擎可以被巧妙地操纵,以帮助政府积聚更多的权力。正如我在之前的总结中提到的,确保这种情况不会发生非常重要,因为互联网给了我们(人民)很多对抗政府的手段。

数据驱动的巨头与 20 世纪初工业时代的公司有两个有趣的不同之处:数据很少被出售或交易,客户对他们得到的东西相当满意。我对这一领域的历史了解不多,但我认为反垄断调查的一个原因是消费者价格欺诈。最大的区别是互联网服务是免费的,每个人都知道这是可能的,因为公司愿意为眼球时间付费。但这篇文章不是关于广告的,是关于数据的,特斯拉、GE 这样的公司是不会这么操作的。他们只是对产品进行创新,以获取更多价值。我认为广告的情况更令人怀疑,因为它促进了消费主义,对于健康经济的一些指标来说,这可能是好的,但对于正在挣扎的阶层来说,可能有不利影响。

无论如何,真正的问题是一小撮强大的垂直科技行业正在积聚太多的力量。亚马逊、谷歌和脸书是全球排名前三的互联网公司,这三家公司都非常强大,它们的利润都依赖于消费主义。与贫富差距的讨论密切相关,贫富差距的趋势令人担忧。

也就是说,也有不少其他公司出于明显的良好目的使用数据。特斯拉、优步、通用电气和英特尔都收集了大量的驾驶数据,以竞争自动驾驶汽车业务。公用事业公司收集关于你如何使用物理资源生活的数据,比如电和水。我认为这类数据更能证明个人价值。也许我的 Instagram 点击流只对广告商有价值,但我的驾驶和公用设施数据非常有价值,只要不让其他人知道就行(比如保险公司)。

互联网公司的许多可怕之处在于,它们试图以非常可疑的理由改变你的行为。如果你真的有动力,你当然可以提出一个荒谬的论点来反对更高效的交通,但我认为很明显,特斯拉和优步为社会做出了巨大的贡献。脸书想成为你一直看着的电话簿,这真的很奇怪。谷歌在这方面有更多的理由,因为有效获取知识极其重要,如果它必须由广告驱动,那么我想我们可能不得不接受这一点。亚马逊坐在中间:他们的激励驱使他们走向促进消费主义的极端,但我确实相信他们通过他们的平台和基础设施为社会做了好事。

这里的问题似乎是关于激励。资本主义的驱动力是亚马逊希望人们买一堆东西的原因,即使这对它自己的顾客有长期的损害。有大量的用户行为研究挖掘大脑的成瘾中心,让你点击并购买东西。为一个有用的产品特性和一个破坏性上瘾的特性找到一个好的阈值是一项复杂的任务,但应该不是不可能的。不幸的是,除了行为数据之外,很难测量这些东西——我们可能不得不等到我们可以将 MRI 机器塞进耳机或帽子里(尽管心电图可能是有效的?噪音很大,但小型化设备今天已经存在)。我认为走法律途径并不是不合理的,因为心理学方法在今天的互联网服务中相当普遍。

这也可能是一家公司生产抗成瘾产品的潜在途径。想象一下,如果你的浏览器可以告诉你,你正在表现出强迫或上瘾行为的迹象,或者指出你在相当无用的东西上花了很多钱。也许它可以检测出你对有针对性的在线广告反应有点太好了。我自己也愿意为这样的东西付钱。如果这艘船已经在数据隐私上航行,我们至少应该为了我们自己的个人利益最大限度地利用它。

我的感觉是,收集个人数据是不可逆转的社会变革之一,就像农业或资本主义一样。一旦世界看到了收集、交易和融合数据源以构建新产品的效率提升,似乎就没有回头路了。在这方面,我的观点相当自由,我认为在社会的大多数领域,变化通常是一件好事。自然保证了权力不会在一个地方集中太久。

也就是说,我仍然认为隐私很重要。解释这种风险的简洁方法是引用马克·吐温关于谎言、该死的谎言和统计数据的经典名言。定量研究和定性研究之间的区别比一个更严格或使用更多数据的定量研究要明显得多。我没有任何证据表明这会导致糟糕的决策,但我希望如此。我们的社会在统计学和实验设计方面还没有达到必要的水平。这可能会改变,但我对此表示怀疑。

几年前有部有趣的马特·达蒙电影叫《极乐世界》。我最喜欢的一个场景是,当他的角色正在接受一个执法机器人的采访时,执法机器人在他排队等候某事时发现了他涉嫌流氓行为。机器人根据一堆关于他的数据和他的犯罪记录来判断他犯罪的可能性。它迅速决定对他判刑,但整个场景的笑话是,他只是在错误的时间出现在错误的地点。

这个场景展示了一些事情,比如权威机构在自动决策过程中缺乏严谨性,但也是一个潜在的论点,即利用我们现有的资源来扩大执法规模,而不是将这些资源用于更小但更精确的过程。这些都是常见的道德问题,所以它们并不新鲜,但即使我们从定性发展到定量,我们也必须认清它们的本质。在许多情况下,对科技公司来说,精度并不那么重要,只要他们测量的信号按照他们想要的方式发展。我想我从来没有听说过一个产品团队会优先考虑客户的个人福祉。

通过确保作为一个社会,我们对我们允许机器做的事情保持高度警惕,很多问题都可以得到解决。即使他们没有自主决定事情,他们影响我们决策的事实仍然非常重要。我认为隐私是保护人们免受统计数据暴政的一个方面。现在尤其重要的是,有人可以说决策或过程是定量的,因为他们有数据。我认为,如果你的听众没有将统计学正确应用于现实世界问题的背景,这是一件很难反驳的事情。

或许这表明该行业需要一点监管。我一点也不喜欢许可和更多的找工作的官僚主义,所以也许有办法让公司对他们的分析负责。也许它的工作原理类似于个人医疗数据的 HIPAA 合规性,在这种情况下,您可以对存储和传输敏感医疗数据的安全实践进行审核。也许根据公司分析的统计严谨性来审计公司是合理的,至少对于那些被认为在处理重要个人数据或提供重要服务的公司来说是如此。

我确实觉得用用户数据强制开放的想法非常有趣。使用数据来制造更好的产品是相当新的,因此开放应该鼓励所有这些数据的创新使用。这也部分解决了某些技术行业垂直行业的权力集中问题,因为这限制了它们的竞争优势。在此之前,最重要的是要弄清楚如何保护个体消费者。我认为保护的两个部分是来自压迫性的政府程序和公司的产品界面,如果能增加他们的利润,他们会很乐意让你的精神和财务健康受到损害。我很想知道是否有我没有想到的其他领域。

#socialMediaOuch!

原文:https://towardsdatascience.com/socialmediaouch-37b27f3e7561?source=collection_archive---------7-----------------------

Study of Leonardo da Vinci’s St. Jerome in the Wilderness, Private collection

“我们所创造的世界是我们思考的过程。不改变我们的思维,就无法改变。”[人名]阿尔伯特·爱因斯坦(犹太裔理论物理学家)

今天,你我经历了 86164.1 秒的变化,就看你怎么定义一天了。你可以说,今天早上的我已经不是那一天结束时的我了,在那 86,164.1 秒里,我发生了一连串的变化,说来也怪,我们每个人都是如此。跨越多少年?

一年包含了 31,536,000 秒的微小变化。毫无疑问,去年的我已经不是现在的我了,我是说一秒钟前,哦,几秒钟前…你明白了。

仅去年一年就有超过 3100 万个小的连续变化。

3100 万,或者更准确地说,因为变化正在我们所有人身上发生,一系列的变化大致跨越了

T5 7515284153 人

这是一个很大的变化。

是的,我们在睡觉的时候也在改变,所以即使我们没有意识到,这个总数仍然是有价值的。

# social media——嗡嗡声进入我们的眼睛、耳朵和思想,随着接触的每一秒,我们都在改变自己。许多人的共同想法。

试想一下,在历史上的大部分时间里,士兵们都是按着同样的节拍前进的——这是一种有组织的控制方式,同时在整个团队中创造出一种团结感,“ 我们是一体的。 “与#socialMedia 惊人的相似。

只是观察一下。

嘿,随着机器学习和深度学习开始组织并推动代表我们个人#socialMedia 活动的数据产生特定结果,将会或可能会发生什么——我们可以期待什么类型的结果?

有趣的问题,汉克。一定要说。

比如说,考虑像亚马逊这样的实体的全球存在。这同样适用于脸书或谷歌。考虑一下,作为人类,我们共享某些生物结构,如果你分析代表行为模式的数据,这是一件好事,因为人类结构的相似性使得一组基础算法、非常大规模的经济可以用于分析,甚至提议的行动(或者甚至改变,记住上面的内容,我们生来就是为了改变)。

7515284153

全球影响(如果每个人都以某种方式使用社交媒体应用。他们还没有考虑到这个趋势)!

让我们用美元/印象数来说明这个数字。让我们考虑一下全球人口的百分之一

7,515,284,153 x 0.01 = 75,152,841.53 人

让我们说,只是为了有一个开始的地方(你必须从某个地方开始到某个地方),1%的人使用某种形式的社交媒体,比如说,他们一天中的 10%,或者:

86,164.1 秒 x 0.1 = 8,616 秒的潜在影响

在全球 1%的 75,152,841 人中,一天之内,我们假设的社交媒体影响是:

8,616(秒)x 75,152,841(假设人群集)= 647,516,878,056 秒基础印象

现在,让我们用这个数字来确定实施人工智能的商业价值。

如果我是一个全球商业实体,不知何故,我能够给每个人每秒的印象贴上一个标签,你知道,就像营销行业是如何工作的,那么,你就可以赚很多钱。多少钱?

在一天中,以平均每天 10%的时间影响全球 1%的人口——在某些情况下更少,在其他情况下更多,一天的印象价值的各种假设:

@ $0.01(一美分)每印象/秒= 0.01 美元 x 647,516,878,056 = 6,475,168,780 美元

每天超过 60 亿美元!

宝贝,这就是我想从事的行业!

对,所以,这只是一个模型。减少每秒每印象的值,或改变群体大小等。把它演完。不管怎么说,这都是个大数目。

这里更重要的一点是,通过#socialMedia 来推动特定结果有着非常真实的价值。人工智能、机器和深度学习相结合,是一个伟大的开端,通过数据预测分析,开始引导观众走向可预测的结果。

“就像云计算迎来了当前初创企业的爆炸一样……机器学习平台可能会推动下一代消费者和商业工具的发展。” 人工智能的民主化:对技术创新意味着什么

这还不是最可怕的部分。

如果我拥有并出售人工智能即服务(AIaaS ),通过#socialMedia 来推动特定的成果,我认为这些成果将对销售产品的公司有巨大的价值。你觉得呢?

可怕的是,当你考虑成功的小创业,特别是商业成功时,通常会有一些投资花在让成功的赚钱机器更有效率上。想想 iPhone,Amazon,或者更好的 AWS,当他们在时间内取得一定程度的成功时,发生了什么。持续投资。因此,这意味着这些漂亮的小机器和深度学习算法,随着它们通过更有效的商业见解和由此产生的商业决策来提高效率和收入,从而证明它们的价值,这些回报将产生更多的投资,目标是推动更好的结果。驱动特定结果的趋势线是什么?切入正题,人口控制成果。

socialMediaOuch!

一枚戒指统治一切——一台#社交媒体机器和深度学习基板,推动理想的业务成果。我相信华盛顿有人已经想通了,他们已经为企业号准备好了他们的“谢谢”。

干杯,

一卷

汉克·m·格林是谁?

“我就是我说过的我,一个讲故事的人。但是,你可能会问,我从哪里来,要到哪里去?掌握着我去哪里的钥匙,它将决定我从哪里来。”

读一读汉克·m·格林@【https://sites.google.com/view/time-a-trilogy/ 写的《第一册:十个》的草稿

十、第一章在 YouTube 上阅读

推特@hankmgreene 或https://twitter.com/hankmgreene

https://www.facebook.com/hankmgreene 脸书

Flipboard: HankMGreene

带 Tensorflow 的软标志激活功能[带 TF 的手动后撑]

原文:https://towardsdatascience.com/soft-sign-activation-function-with-tensorflow-manual-back-prop-with-tf-5a04f3c8e9c1?source=collection_archive---------13-----------------------

GIF from this website

因此,论文“二次特征和分块的深度架构”自 2009 年就已经存在,然而我最近在阅读“理解训练深度前馈神经网络的困难”时发现了该论文中介绍的激活函数(我也就此事做了一篇论文总结,如果有人对感兴趣,请点击此处)。)

只是为了好玩,让我们比较许多不同的情况,看看哪个给我们最好的结果。

案例 a) Tanh 激活函数 与 AMS Grad 案例 b)软签激活函数 与 AMS Grad 案例 c) ELU 激活函数 与 AMS Grad

软标志激活功能

红线 →软标志激活功能
蓝线 →双曲正切激活功能
绿线 →软标志功能的导数
橙线 →双曲正切激活功能的导数

如上所述,我们可以直接观察到软符号激活函数比双曲正切激活函数更平滑的事实。(具体来说,该函数名义上是多元增长,而不是指数增长。)并且这种更温和的非线性实际上导致更好更快的学习。在更详细的解释中,研究人员发现,柔和的手势可以防止神经元饱和,从而提高学习效率。(要了解更多信息,请阅读这篇博文。)

网络架构/数据集

红框 →输入图像
黑框 →与不同激活函数的卷积运算
橙框 →分类的软 Max 运算

如上所述,我们将使用的基础网络架构是 ICLR 2015 中展示的全卷积网络。最后,我们将用来评估我们网络的数据集是 CIFAR 10 数据。

结果:情况 a) Tanh 激活功能 与 AMS Grad (CNN)

左图 →一段时间内的训练精度/成本
右图 →一段时间内的测试精度/成本

如上所述,对所有卷积网络使用 tanh 的图像分类任务似乎需要更长的时间来收敛。在 21 世纪末期,该模型只能在训练图像上达到 69%的准确度(在测试图像上达到 68%的准确度),然而该模型似乎在正则化方面做得很好。

结果:情况 b)软标志激活功能 与 AMS Grad (CNN)

左图 →一段时间内的训练精度/成本
右图 →一段时间内的测试精度/成本

我其实很惊讶,软标志激活功能的表现不如 tanh。花费更长的时间来收敛并不总是意味着激活函数不好,然而对于这种设置,软符号激活函数可能不是最佳选择。

结果:情况 c) ELU 激活功能 与 AMS Grad (CNN)

左图 →一段时间内的训练精度/成本
右图 →一段时间内的测试精度/成本

对于图像分类,传统的 relu 类激活似乎是最好的选择。因为它们不仅在训练/测试图像上具有最高的精度,而且收敛得更快。

交互代码

对于 Google Colab,你需要一个 Google 帐户来查看代码,而且你不能在 Google Colab 中运行只读脚本,所以在你的操场上复制一份。最后,我永远不会请求允许访问你在 Google Drive 上的文件,仅供参考。编码快乐!同样为了透明,我在 github 上上传了所有的训练日志。

要访问案例的代码,点击这里,日志的点击这里。
点击此处查看案例 b 的代码,点击此处查看日志。
要访问案例 c 的代码,请点击此处,要查看日志,请点击此处。

遗言

另外,这篇博文在比较许多其他激活功能方面做得非常出色,所以如果有人感兴趣,请查看一下。

如果发现任何错误,请发电子邮件到 jae.duk.seo@gmail.com 给我,如果你想看我所有写作的列表,请在这里查看我的网站。

同时,在我的推特这里关注我,并访问我的网站,或我的 Youtube 频道了解更多内容。我还实现了广残网,请点击这里查看博文 pos t。

参考

  1. 图瑞安、伯格斯特拉和本吉奥(2009 年)。组块的二次特征和深层结构。人类语言技术会议录:计算语言学协会北美分会 2009 年度会议,配套卷:短文,245–248。从https://dl.acm.org/citation.cfm?id=1620921取回
  2. 作为神经网络激活函数的软设计。(2017).赛菲克·伊尔金·塞伦吉尔。检索于 2018 年 5 月 28 日,来自https://sefiks . com/2017/11/10/soft sign-as-a-neural-networks-activation-function/
  3. 对一个不很深的神经网络的深入研究。第 2 部分:激活函数。(2018).走向数据科学。2018 年 5 月 28 日检索,来自https://towards data science . com/deep-study-of-a-not-very-deep-neural-network-part-2-activation-functions-FD 9 BD 8d 406 fc
  4. (2018).Proceedings.mlr.press .检索于 2018 年 5 月 28 日,来自http://proceedings.mlr.press/v9/glorot10a/glorot10a.pdf
  5. 【论文摘要】了解训练深度前馈神经网络的难度。(2018).中等。检索于 2018 年 5 月 28 日,来自https://medium . com/@ SeoJaeDuk/paper-summary-understanding-the-difference-of-training-deep-feed-forward-neural-networks-ee34f 6447712
  6. 导数双曲函数。(2018).Math2.org。检索于 2018 年 5 月 28 日,来自http://math2.org/math/derivatives/more/hyperbolics.htm
  7. 2017 年深度学习优化实现亮点(feat。塞巴斯蒂安·鲁德)。(2018).中等。检索于 2018 年 5 月 28 日,来自https://medium . com/@ SeoJaeDuk/implementation-of-optimization-for-deep-learning-highlights-in-2017-feat-sebastian-ruder-61e 2 CBE 9 b 7 CB
  8. Wolfram|Alpha:让世界知识可计算。(2018).Wolframalpha.com。检索于 2018 年 5 月 28 日,来自http://www.wolframalpha.com/input/?I = f(x)+% 3D+x % 2F(1% 2B % 7Cx % 7C)
  9. Numpy 向量(N,)。(2018).Numpy 向量(N,1)维-> (N,)维转换。堆栈溢出。检索于 2018 年 5 月 29 日,来自https://stack overflow . com/questions/17869840/numpy-vector-n-1-dimension-n-dimension-conversion
  10. CIFAR-10 和 CIFAR-100 数据集。(2018).Cs.toronto.edu。检索于 2018 年 5 月 29 日,来自 https://www.cs.toronto.edu/~kriz/cifar.html
  11. [ ICLR 2015 ]追求简单:具有交互码的全卷积网。(2018).走向数据科学。检索于 2018 年 5 月 29 日,来自https://towards data science . com/iclr-2015-力争简单-所有卷积网与交互式代码手册-b4976e206760
  12. [谷歌]连续可微分指数线性单位与互动代码。(2018).中等。检索于 2018 年 5 月 29 日,来自https://medium . com/@ SeoJaeDuk/Google-continuously-differentiable-index-linear-units-with-interactive-code-manual-back-2d 0a 56 DD 983 f

软技能是雇佣优秀数据科学家的决定性因素

原文:https://towardsdatascience.com/soft-skills-are-the-decisive-factor-in-hiring-great-data-scientists-69be3c1fd75a?source=collection_archive---------7-----------------------

当人们听到“数据科学家”这个头衔时,他们通常会想到一个有数字头脑的人,擅长数学和统计,并且只在有数据支持的情况下推广策略。虽然这是真的,但它描绘了一幅可悲的不完整画面。事实是,最优秀的数据科学家因其技能而大放异彩,利用他们的创造力和沟通能力将自己与普通专业人士区分开来。

硬技能在整个工业革命中受到重视,逻辑和决定论允许我们建造机器,以便我们理解每个运动部件,并使用明确的指令指挥它们。通过控制每一个输入到输出,我们的机器被认为是可靠的,可控的,并使我们在我们的工业雄心中保持竞争力。但这种显式控制正迅速成为一种过时的工程方法,因为它不再生产与信息时代同步的产品。

今天的机器需要适应,需要自己学习。这需要对基于规则的软件中所没有的复杂性的理解。数据科学家需要机器一起工作,让他们做计算,让我们做训练。生产一台能够提供智能输出的机器是一项复杂的工作,涉及人类参与和创造力的许多方面。

数据科学家必须在比传统工程师更高的抽象层次上工作,因为我们创造的技术与用户需求更直接地重叠。我们的应用程序产生的输出是决策,而不是像可排序列表或索引照片这样的传统特性。这就是为什么数据科学需要软技能来理解人们以及他们做出日常决策的方式。

我们需要意识到,我们已经进入了机器比人更擅长“硬技能”的时代。许多候选人以及刚接触机器学习的组织未能意识到这一点,认为数据科学是关于技术和数字的。当然,我们对数字很在行,但这与在白板上解公式或在追求某种终极理论时推导方程的意义不同。现在,科学和企业都把这些任务推给了机器,把解释和策略留给了我们人类。

数据科学家非常擅长混合和调整算法,这样数学和统计学就能解决并汇聚成重要的输出。这不是你可以硬连线到机器中的东西,而是在多次尝试准备数据并转动我们算法的“旋钮”后观察到的东西。这就是在数据科学中做数学的意义

对于那些不太熟悉机器学习生态系统的人来说,给数据科学专业带来太多硬技能通常意味着重新发明轮子。半个多世纪的机器学习已经过去,这个行业很少需要从头开始构建新的算法。伟大的数据科学家是变化和迭代的大师,他们混合和匹配现有的解决方案,直到现实世界用一个有效的产品来验证他们的努力。它是在多次尝试后知道你在看什么;不要天真地试图预先计划一种方法,使用仅仅在象牙塔后面发展起来的“专业知识”。

软技能允许数据科学家通过我们的机器学习努力巧妙地应对挑战,因为正是软技能将技术与最重要的事情联系起来;用户反馈。任何行业的领域专家几乎都是非技术性的,但是他们拥有成功构建智能软件的重要知识和经验。没有他们的智慧和我们的算法之间的桥梁,我们在真空中产生一切,在上下文中什么也没有。

软技能在雇用数据科学家时更具决定性,因为那些能够制作智能软件进行有效沟通的人是稀有品种。他们明白,数学和统计只是一个更复杂旅程的起点,没有更柔和的触摸是无法实现的。那些能够通过与人交谈,理解他们的痛点,并哄骗机器成为它需要的样子来解决问题的人。

对于那些希望进入数据科学的人来说,首先要确保你对数学和统计学的理解是概念上的。智能软件不是在白板上实现的,它诞生于领域专家和训练机器的人才之间的有效对话。你的硬技能永远比不上今天的智能软件,也不会让你在一个为人们构建产品的职业中脱颖而出。学会清晰地说话,简化你的思维,尽可能地去除行话,对机器的终点和你的起点建立一种欣赏。你的事业会感谢你的。

简化的 Softmax 函数

原文:https://towardsdatascience.com/softmax-function-simplified-714068bf8156?source=collection_archive---------2-----------------------

回归公式如何提高深度学习模型的准确性

TL;这是我致力于机器/深度学习和自然语言处理主题系列的第一篇文章。这篇文章讨论了 Softmax 回归,其中我们计算输入向量的指数,以便将数据集归一化为值总和为 1 的概率分布。适合多维分类,而不是二元分类。

序言

我对机器学习(ML)产生了浓厚的兴趣,特别是探索自然语言处理(NLP)领域。通过研究论文和算法,引起我对这个领域的好奇心;总的来说,人工智能在优化实验结果方面总是有改进的空间,100 行代码如何能够让行业自动化那些否则需要漫长而乏味的时间才能完成的任务。在我们必须学习一个数据集的情况下,然后输出有意义的信息,这些信息是认知的或与现实世界的期望一致的,并迭代地这样做,以通过增量变化来实现更高的准确性,这对我来说绝对是令人着迷的。

对我的学术旅程的洞察对大多数人来说是独特的,因为我的大多数课程都与产品工程和数据分析有关。然而,我想给这次学术经历增添一些额外的趣味。为了做到这一点,我决定报名参加学校计算机科学系开设的自然语言处理课程。

该课程在揭示大量可供学习的主题方面做得非常出色,随着该领域取得如此多的进展,我非常有动力开始撰写与 ML、NLP 和深度学习相关的概念。然而,随之而来的是一个挑战。课内外学习的概念已经是数学密集型的,充满了令人困惑的符号和推导。我想以这样一种方式简化它们,任何对某些主题有热情的人都可以很容易地理解它们,甚至可能将它们应用于研究、职业、创业或黑客马拉松。

所以在最初的几堂课中,教授带我们浏览了与语言建模相关的材料;这是智能系统使用的技术,用于准确预测任何给定文本中的单词或句子。直到教授引入了一个特殊的术语叫做最大回归的 S之前,这些内容都是有意义的。我被那些看起来像法语(或者更像拉丁语)的符号淹没了。)对我来说。通过几个小时的自学和一杯热腾腾的榛子咖啡,这个概念很快就有了意义。

为了以一种更加简化和进步的方式解释它,我们将首先从定义开始,然后理解所涉及的符号,最后看到函数本身的编码实现。

定义

Softmax 回归是逻辑回归的一种形式,它将输入值归一化为值的向量,该向量遵循总和等于 1 的概率分布。输出值在范围[0,1]之间,这很好,因为我们能够避免二进制分类,并在我们的神经网络模型中容纳尽可能多的类或维度。这就是 softmax 有时被称为多项式逻辑回归的原因。

顺便说一下,Softmax 回归的另一个名字是最大熵(MaxEnt)分类器。

该函数通常用于计算训练数据集时的预期损失。softmax 回归的已知用例在判别** 模型中,如交叉熵噪声对比估计。这些只是试图优化当前训练集以增加预测正确单词或句子的可能性的各种技术中的两种。(我们将在接下来的几篇文章中触及上述技术,敬请关注。)**

如果你从一开始就看它,这个定义可能听起来微不足道,但在机器学习和 NLP 领域,这个回归函数作为一个基线比较器是有用的。设计新解决方案的研究人员必须进行实验,并将 softmax 结果作为参考。然而,应该注意的是,softmax 并不像 SigmoidReLU (整流线性单元)那样理想地用作激活功能,而是用于多层或单层之间。

注释

分类器函数涉及一些高级符号,我们接下来将深入探讨。下图展示了 Softmax 函数的样子。让我们试着一点一点去理解。

A mathematical representation of the Softmax Regression function

  1. 给定一个独热编码矩阵 θ、形式的净输入参数,我们的目标是预测训练的特征集x;** 每一个都有自己设定的权重,都是 j 的一类。一个独热矩阵由二进制值组成,数字 1 代表列的 iᵗʰ位置的元素,而其余的是 0(相对较大的矩阵有稀疏的风险,我们将在下一篇文章中讨论)。**
  2. 在公式中,我们计算输入参数的指数和输入中所有现有值的指数参数总和。Softmax 函数的输出是参数的指数与指数参数之和的比值。
  3. θ ,在高层次上是向量中每个出现元素的得分之和。在一般形式中,我们说θ是权重矩阵 w 的转置,乘以特征矩阵 x.
  4. 术语 w₀x₀是需要在每次迭代中添加的偏差。

代码实现

实现代码非常容易,有趣的是,考虑到我们有必要的 Python 助手函数,它只有一行代码。在下面的 Github 要点中,我使用了 NumpyTensorflow 来编写 Softmax 函数,如前一节所述。这两个提到的库普遍用于执行数学和神经网络相关的操作。

结论

在下一篇文章中,我们将进一步了解如何利用 softmax 函数作为对数损失神经网络的一部分进行计算,以最小化单词嵌入中的预测误差。我们将获取文本样本,这将允许我们理解关于 NLP 及其在现实世界中的实际应用的更深层次的概念。

敬请关注。😃

引用的作品

** [## Softmax 函数和 Sigmoid 函数的区别

在学习逻辑回归概念时,主要的困惑是用于计算的函数…

dataaspirant.com](http://dataaspirant.com/2017/03/07/difference-between-softmax-function-and-sigmoid-function/)

https://sebastianraschka . com/FAQ/docs/soft max _ regression . html**

传播和分享知识。这篇文章是致力于理解 NLP 核心概念的系列文章中的第一篇。如果这篇文章激起了你的兴趣,请鼓掌,因为它总是激励我写出更多的信息内容。此外,请关注我的个人资料,获取更多与技术相关的文章。—哈姆扎

软件架构模式

原文:https://towardsdatascience.com/software-architecture-patterns-98043af8028?source=collection_archive---------0-----------------------

分层架构

这是大多数企业级应用程序中最常见的架构模式。假设层数为 n ,这也被称为 n 层模式。这是 JAVA EE 应用程序的事实模式。

层的示例场景

Source: https://www.oreilly.com/ideas/software-architecture-patterns/page/2/layered-architecture

表示层

网页、UI 表单和最终用户交互 API 的呈现

业务层

可访问性、安全性和身份验证背后的逻辑发生在这一层。这包括 ESB(企业服务总线)、中间件和其他各种请求拦截器来执行验证。

持久层

这是数据的表示层。这包括 DAO(数据访问对象)表示、ORM(对象关系映射)和其他在应用程序级别表示持久数据的模式。换句话说,这展示了 RAM 中的持久数据。它通常位于下层的磁盘中。

数据库层

简单的数据库扩展到 San(存储区域网络)

层的组成

层由组件组成。这些组件比对象类和包更抽象。一个组件可以演示一组执行单一任务的包。

“组件加强了关注点的分离”

关键概念

封闭层

这展示了 隔离层 的概念,它以更严格的方式分隔每一层,只允许顺序通过各层,而不允许旁路。如图所示,这加强了层的更好的解耦,使得整个系统对于变化更加可行。

Source: https://www.oreilly.com/ideas/software-architecture-patterns/page/2/layered-architecture

打开图层

开放层允许系统绕过层并触及下面的层。这是在任务关键型系统中完成的,在这些系统中,延迟会造成很大的损失。通常这些层意味着通信开销。因此,有时绕过层并直接从正确的层寻找数据是合理的。

Source: https://www.oreilly.com/ideas/software-architecture-patterns/page/2/layered-architecture

模式分析

采用分层模式可能会误导并导致一种称为 “架构陷坑反模式” 的反模式,这种反模式展示了具有不执行任何逻辑的层,但增加了通信开销。因此,这些层必须以执行特定任务的方式进行设计,以补偿整个系统的通信开销和可维护性。

模式可测试性

由于分层的性质,这个值更高。通过传递虚拟消息并使用虚拟接口来演示直接层,可以单独测试每一层。

性能和可扩展性

由于有通信开销,这可能很低。这可能需要转换消息类型等。就可伸缩性而言,添加更多层不是一个选择。该模式不会无限扩展。

尽管有起有落,开发工作还是少了很多,因为一旦确定了通信协议,不同的团队就可以在不同的层上工作,并在每个团队的成员之间分配组件。

用爬山搜索算法解决幻灯片难题

原文:https://towardsdatascience.com/solve-slide-puzzle-with-hill-climbing-search-algorithm-d7fb93321325?source=collection_archive---------0-----------------------

爬山搜索算法是局部搜索和优化技术中最简单的算法之一。Miroslav Kubat 在《机器学习导论》一书中是这样定义的:

Hill Climbing Algorithm Steps

步骤 3 中的评估函数计算当前状态与最终状态的距离。所以在 3x3 幻灯片拼图的情况下,我们有:

Final State: 
1 2 3
4 5 6 
7 8 Consider Current State: 
1 2 3 
4 5 6 
7   8

评估函数 dF 计算每个瓦片达到其最终状态所需的移动的总和。由于图块 1 至 7 已经位于正确的位置,因此不需要移动它们。然而,瓦片 8 从其最终位置移开。

dF(8) = m(1)+m(2)+m(3)+m(4)+m(5)+m(6)+m(7)+m(8)
= 1

爬山评估可能的下一步,选择距离最短的一步。它还检查是否已经观察到移动后的新状态。如果为真,那么它跳过这步棋,选择下一步最好的棋。由于空缺的瓷砖只能由其邻居填充,爬山有时会被锁定,无法找到任何解决方案。这是这个算法的主要缺点之一。

另一个众所周知的缺点是局部最优。该算法根据即时距离(成本)决定下一步行动(状态),假设现在的小改进是达到最终状态的最佳方式。但是,选择的路径可能会导致后期成本更高(步骤更多)。

类似于爬上一座小山后进入一个山谷。

为了避开局部最优,我建议使用深度优先的方法。

深度优先法爬山

想法是遍历一条路径一个确定的步骤数(深度)以确认它是最好的移动。

  1. 对当前状态的所有可能的下一步(状态)进行循环。
  2. 调用步骤 1,直到达到深度 d。这会生成一棵高度为 d 的树。
  3. 选择最小成本(dF)的移动(状态)
  4. 返回 dF,以便在depth-1级别进行评估。

我观察到深度优先的方法提高了到达最终状态的整体效率。但是,它占用大量内存,与使用的深度值成比例。这是因为系统必须根据使用的深度跟踪未来状态。

以下是各种深度的移动距离图表的简要比较:

Puzzle Initial State

Depth=0, Puzzle Unresolved even after 480 steps

Depth=1, Puzzle Unresolved in 48 Steps

Depth=3, Puzzle Unresolved in 34Steps (Note fewer hills)

Depth=6, Puzzle Unresolved in 26 Steps (Even fewer hills)

这里可以进行现场评估。尝试各种深度和复杂性,并查看评估图。有时,由于锁定(没有新状态),谜题仍未解决。

或者,如果你只是有解谜的心情,试试自己对抗由爬山算法驱动的 bot

每当你输给机器人时,点击这篇文章的“喜欢”按钮:-)

玩得开心!

已编辑:Live evaluation 和 bot 目前无法在移动设备上运行。

用 Python 解决简单的分类问题——水果爱好者版

原文:https://towardsdatascience.com/solving-a-simple-classification-problem-with-python-fruits-lovers-edition-d20ab6b071d2?source=collection_archive---------1-----------------------

Photo credit: Pixabay

在这篇文章中,我们将使用 Python 最流行的机器学习工具 Scikit-learn 在 Python 中实现几个机器学习算法。使用简单的数据集来训练分类器以区分不同类型的水果。

这篇文章的目的是确定最适合手头问题的机器学习算法;因此,我们希望比较不同的算法,选择性能最好的算法。我们开始吧!

数据

水果数据集是由爱丁堡大学的伊恩·默里博士创建的。他买了几十个不同品种的橘子、柠檬和苹果,并把它们的尺寸记录在一个表格里。然后密执安大学的教授将水果数据稍微格式化,可以从这里下载。

让我们看看前几行数据。

%matplotlib inline
import pandas as pd
import matplotlib.pyplot as pltfruits = pd.read_table('fruit_data_with_colors.txt')
fruits.head()

Figure 1

数据集的每一行都代表一片水果,由表的列中的几个要素表示。

数据集中有 59 种水果和 7 个特征:

print(fruits.shape)

(59,7)

数据集中有四种水果:

print(fruits['fruit_name'].unique())

['苹果' '橘子' '橘子' '柠檬]]

除了普通话,其他数据都很平衡。我们只能顺其自然了。

print(fruits.groupby('fruit_name').size())

Figure 2

import seaborn as sns
sns.countplot(fruits['fruit_name'],label="Count")
plt.show()

Figure 3

形象化

  • 每个数值变量的箱线图将使我们对输入变量的分布有一个更清晰的概念:
fruits.drop('fruit_label', axis=1).plot(kind='box', subplots=True, layout=(2,2), sharex=False, sharey=False, figsize=(9,9), 
                                        title='Box Plot for each input variable')
plt.savefig('fruits_box')
plt.show()

Figure 4

  • 看起来颜色分数可能具有近似高斯分布。
import pylab as pl
fruits.drop('fruit_label' ,axis=1).hist(bins=30, figsize=(9,9))
pl.suptitle("Histogram for each numeric input variable")
plt.savefig('fruits_hist')
plt.show()

Figure 5

  • 一些属性对是相关的(质量和宽度)。这表明了高度的相关性和可预测的关系。
from pandas.tools.plotting import scatter_matrix
from matplotlib import cmfeature_names = ['mass', 'width', 'height', 'color_score']
X = fruits[feature_names]
y = fruits['fruit_label']cmap = cm.get_cmap('gnuplot')
scatter = pd.scatter_matrix(X, c = y, marker = 'o', s=40, hist_kwds={'bins':15}, figsize=(9,9), cmap = cmap)
plt.suptitle('Scatter-matrix for each input variable')
plt.savefig('fruits_scatter_matrix')

Figure 6

统计摘要

Figure 7

我们可以看到数值没有相同的标度。我们需要对我们为训练集计算的测试集应用缩放。

创建训练集和测试集并应用缩放

from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

构建模型

逻辑回归

from sklearn.linear_model import LogisticRegressionlogreg = LogisticRegression()
logreg.fit(X_train, y_train)print('Accuracy of Logistic regression classifier on training set: {:.2f}'
     .format(logreg.score(X_train, y_train)))
print('Accuracy of Logistic regression classifier on test set: {:.2f}'
     .format(logreg.score(X_test, y_test)))

逻辑回归分类器对训练集的准确率:0.70
逻辑回归分类器对测试集的准确率:0.40

决策树

from sklearn.tree import DecisionTreeClassifierclf = DecisionTreeClassifier().fit(X_train, y_train)print('Accuracy of Decision Tree classifier on training set: {:.2f}'
     .format(clf.score(X_train, y_train)))
print('Accuracy of Decision Tree classifier on test set: {:.2f}'
     .format(clf.score(X_test, y_test)))

决策树分类器在训练集上的准确率:1.00
决策树分类器在测试集上的准确率:0.73

K-最近邻

from sklearn.neighbors import KNeighborsClassifierknn = KNeighborsClassifier()
knn.fit(X_train, y_train)
print('Accuracy of K-NN classifier on training set: {:.2f}'
     .format(knn.score(X_train, y_train)))
print('Accuracy of K-NN classifier on test set: {:.2f}'
     .format(knn.score(X_test, y_test)))

K-NN 分类器在训练集上的准确率:0.95
K-NN 分类器在测试集上的准确率:1.00

线性判别分析

from sklearn.discriminant_analysis import LinearDiscriminantAnalysislda = LinearDiscriminantAnalysis()
lda.fit(X_train, y_train)
print('Accuracy of LDA classifier on training set: {:.2f}'
     .format(lda.score(X_train, y_train)))
print('Accuracy of LDA classifier on test set: {:.2f}'
     .format(lda.score(X_test, y_test)))

LDA 分类器在训练集上的准确率:0.86
LDA 分类器在测试集上的准确率:0.67

高斯朴素贝叶斯

from sklearn.naive_bayes import GaussianNBgnb = GaussianNB()
gnb.fit(X_train, y_train)
print('Accuracy of GNB classifier on training set: {:.2f}'
     .format(gnb.score(X_train, y_train)))
print('Accuracy of GNB classifier on test set: {:.2f}'
     .format(gnb.score(X_test, y_test)))

GNB 分类器在训练集上的准确率:0.86
GNB 分类器在测试集上的准确率:0.67

支持向量机

from sklearn.svm import SVCsvm = SVC()
svm.fit(X_train, y_train)
print('Accuracy of SVM classifier on training set: {:.2f}'
     .format(svm.score(X_train, y_train)))
print('Accuracy of SVM classifier on test set: {:.2f}'
     .format(svm.score(X_test, y_test)))

SVM 分类器在训练集上的准确率:0.61
SVM 分类器在测试集上的准确率:0.33

KNN 算法是我们尝试过的最精确的模型。混淆矩阵提供了对测试集没有错误的指示。然而,测试集非常小。

from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
pred = knn.predict(X_test)
print(confusion_matrix(y_test, pred))
print(classification_report(y_test, pred))

Figure 7

绘制 k-NN 分类器的决策边界

import matplotlib.cm as cm
from matplotlib.colors import ListedColormap, BoundaryNorm
import matplotlib.patches as mpatches
import matplotlib.patches as mpatchesX = fruits[['mass', 'width', 'height', 'color_score']]
y = fruits['fruit_label']
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)def plot_fruit_knn(X, y, n_neighbors, weights):
    X_mat = X[['height', 'width']].as_matrix()
    y_mat = y.as_matrix()# Create color maps
    cmap_light = ListedColormap(['#FFAAAA', '#AAFFAA', '#AAAAFF','#AFAFAF'])
    cmap_bold  = ListedColormap(['#FF0000', '#00FF00', '#0000FF','#AFAFAF'])clf = neighbors.KNeighborsClassifier(n_neighbors, weights=weights)
    clf.fit(X_mat, y_mat)# Plot the decision boundary by assigning a color in the color map
    # to each mesh point.

    mesh_step_size = .01  # step size in the mesh
    plot_symbol_size = 50

    x_min, x_max = X_mat[:, 0].min() - 1, X_mat[:, 0].max() + 1
    y_min, y_max = X_mat[:, 1].min() - 1, X_mat[:, 1].max() + 1
    xx, yy = np.meshgrid(np.arange(x_min, x_max, mesh_step_size),
                         np.arange(y_min, y_max, mesh_step_size))
    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])# Put the result into a color plot
    Z = Z.reshape(xx.shape)
    plt.figure()
    plt.pcolormesh(xx, yy, Z, cmap=cmap_light)# Plot training points
    plt.scatter(X_mat[:, 0], X_mat[:, 1], s=plot_symbol_size, c=y, cmap=cmap_bold, edgecolor = 'black')
    plt.xlim(xx.min(), xx.max())
    plt.ylim(yy.min(), yy.max())patch0 = mpatches.Patch(color='#FF0000', label='apple')
    patch1 = mpatches.Patch(color='#00FF00', label='mandarin')
    patch2 = mpatches.Patch(color='#0000FF', label='orange')
    patch3 = mpatches.Patch(color='#AFAFAF', label='lemon')
    plt.legend(handles=[patch0, patch1, patch2, patch3])plt.xlabel('height (cm)')
plt.ylabel('width (cm)')
plt.title("4-Class classification (k = %i, weights = '%s')"
           % (n_neighbors, weights))    
plt.show()plot_fruit_knn(X_train, y_train, 5, 'uniform')

Figure 8

k_range = range(1, 20)
scores = []for k in k_range:
    knn = KNeighborsClassifier(n_neighbors = k)
    knn.fit(X_train, y_train)
    scores.append(knn.score(X_test, y_test))
plt.figure()
plt.xlabel('k')
plt.ylabel('accuracy')
plt.scatter(k_range, scores)
plt.xticks([0,5,10,15,20])

Figure 9

对于这个特定的日期集,当 k=5 时,我们获得最高的精确度。

摘要

在这篇文章中,我们关注的是预测的准确性。我们的目标是学习一个具有良好泛化性能的模型。这种模型最大限度地提高了预测精度。我们确定了最适合手头问题(即水果类型分类)的机器学习算法;因此,我们比较了不同的算法,并选择了性能最好的算法。

创建这篇文章的源代码可以在这里找到。我将很高兴收到关于上述任何反馈或问题。

解决墨西哥城的自行车站问题

原文:https://towardsdatascience.com/solving-bike-stations-problem-in-mexico-city-f35b1cfd3ff1?source=collection_archive---------9-----------------------

Photo by Wayne Bishop on Unsplash

几年前,我住在墨西哥城,是名为 eco bici T1 的城市自行车系统的常客。这个系统真的很容易使用,在过去的几年里它变得如此受欢迎真是令人惊讶。然而,由于墨西哥城是一个巨大的城市,对于用户来说,关于在不同的取货站分配自行车的许多问题是日常事务。我们分两节课总结一下这些问题:接送问题和落车问题。这些问题中的第一个是当用户想要骑自行车时缺少可用的自行车。第二类问题依赖于你可以归还自行车的免费停车位的稀缺。从现在起,我将集中讨论第一类问题。

一名 EcoBici 用户抱怨自行车在取货站的分配不合理。这只是这个庞大的交通系统每天都会遇到的问题的一个例子。

我将在接下来的文章中解释一个基于公开可用的数据的每日预测模型。首先,我试图通过使用 ARIMA 模型来模拟每天的出行次数,但我意识到如果我想让这个模型真正准确和有用,我需要模拟每个车站的每日出行次数,这将涉及到创建大约 400 个 ARIMA 模型。经过一些考虑,我决定使用著名的 LSTM 网络(如果你不熟悉他们,看看这里)。

首先,让我们看看按性别划分的旅行总次数。

从这张图表中很容易看出周末的季节性影响,而且只有 24%的日常出行是由女性完成的。这段时间从 2017/01/01 到 2017/03/31。

在研究期间关于 EcoBici 系统的事实

448 个站点
41%的站点每天最多有 5 场活动
27,593 次平均每日出行
5,072 辆平均每月有用的自行车
34.7 岁是用户的平均年龄

数据

该模型旨在根据每个车站最近 3 周的活动预测一整周的活动。为此,我需要“打包”28 天的行程(21 天作为输入,7 天作为输出),为此,我移动了 28 天的时间段,从 2017 年 1 月 1 日开始,到 2017 年 3 月 3 日结束,得到 62 组 28 天的行程。最后一个需要乘以站的数量,我们总共有 27,776 个实例,应该分成训练集和验证集。此外,正如我们之前看到的,周末有很强的季节性影响,所以我引入了一个分类变量来表示工作日(星期一、星期二、星期三……)

最后,数据集的结构为:
(#stations*#sets,#days,trips+one-hot encoding for weekdays)
=(448 * 62,28,1+7) = ( 27776,28,8)
这 27776 个实例需要划分为训练集和验证集。通过将 75%的实例设置为训练集,我们有:20,832 个训练实例和 6,944 个验证实例。

模型结构

我使用一个批量大小为 32 的 LSTM 层、一个 p=0.5 的下降层和一个 7 个单位的密集层来连接输出。而且我用的是 keras亚当优化器,学习率 0.0005。最后,作为损失函数,我考虑了均方误差。

业绩和预测

我运行了 300 个时期的训练过程,但是为了更好的可视化,这里是前 100 个时期的损失值的图。

损失值如下所示:

Loss function values over epochs

可视化预测的一种方法是计算网络的预测值,并将这些值与真实值进行比较。由于我们有大约 6900 个测试实例,我决定简单地随机选取一个实例,并绘制预测值与真实值的对比图。下面是一些相应的 MAPE(平均百分比误差)值的例子。

MAPE 8.3%

MAPE 9.1%

MAPE 18.7

摘要

我引入了一个 LSTM 模型来预测墨西哥城 EcoBici 系统的自行车使用量。该模型的输入是 21 天内的旅行次数,以预测随后 7 天的旅行次数,此外,该模型将一周中的某一天视为一次性编码向量。

该模型产生的平均 MAPE(测试集的平均值)为 21%,这意味着还有很多需要改进的地方。

后续步骤

为了获得更好的结果,可以添加更多的信息:假期、允许识别站点是否在线的布尔变量、每天有用自行车的数量等。

应测试输入内容的不同组合。也许考虑到前 21 天可能会有很多噪音,

由于我打算让这个模型成为一个可操作的工具,所以我认为聚合级别应该以小时为基础。

换句话说,更多的信息,更好的结果,这可能会导致更好的自行车分布在不同的车站。

这款车型的代码可在这里获得。

我的下一篇文章将展示该模型的第二个版本。请随意评论!

使用 lightFM 通过推荐系统解决业务用例

原文:https://towardsdatascience.com/solving-business-usecases-by-recommender-system-using-lightfm-4ba7b3ac8e62?source=collection_archive---------2-----------------------

对 LightFM、推荐系统和代码重用食谱概念的简单介绍。

在这篇帖子中,我将写一些关于推荐系统的内容,它们是如何在许多电子商务网站中使用的。这篇文章还将涉及使用矩阵分解算法,使用 lightFM 软件包和我的推荐系统食谱来构建简单的推荐系统模型。这篇文章将关注业务用例以及简单的实现。这篇文章只涉及算法的基本直觉,如果你想理解算法背后的数学,还会提供资源链接。

动机

我是一个狂热的读者和开源教育的信徒,并通过使用在线课程、博客、Github 存储库和参加数据科学竞赛,不断扩展我在数据科学和计算机科学方面的知识。在互联网上搜索优质内容时,我遇到了各种学习链接,这些链接要么关注使用 ABC 语言的特定数据/建模技术实现算法,要么关注使用一系列算法(如分类、预测、推荐系统等)的广义概念的业务影响/结果。)但具体怎么做就不细说了。因此,我的想法是写一些博客,将业务用例与代码和算法直觉结合起来,以提供数据科学如何在业务场景中使用的整体视图。

随着世界变得越来越数字化,我们已经习惯了大量的个性化体验,而帮助我们实现这一点的算法属于推荐系统家族。几乎每个基于网络的平台都使用一些推荐系统来提供定制内容。以下是我最钦佩的公司。

什么是个性化?

个性化是一种根据每个用户的需求动态定制内容的技术。个性化的简单例子可以是网飞上的电影推荐、电子商务平台的个性化电子邮件定向/重新定向、亚马逊上的商品推荐等。个性化帮助我们实现这四个 r-

  • 认识:了解客户和潜在客户的概况,包括人口统计、地理位置以及表达和分享的兴趣。
  • 记住:回忆顾客的历史,主要是他们浏览和购买的商品所表达的行为
  • 接触:根据行动、偏好和兴趣为客户提供合适的促销、内容和推荐
  • 相关性:在数字体验的背景下,根据客户是谁、他们在哪里以及现在是一年中的什么时候来提供个性化服务

4 R’s of personalization

为什么要个性化?

个性化对用户和公司都有很多好处。对于用户来说,这让他们的生活变得轻松,因为他们只能看到与他们更相关的东西(除非是广告,即使它们是个性化的)。因为商业利益数不胜数,但这里我想提几个-

  • 增强客户体验:个性化通过显示相关内容来减少混乱并增强客户体验
  • 交叉销售/追加销售机会:根据客户偏好提供相关产品可以提高产品知名度,最终销售更多产品
  • 增加购物篮的容量:个性化的体验和针对性最终会增加购物篮的容量和购买频率
  • 提高客户忠诚度:在数字世界中,客户保留/忠诚度是许多公司面临的最突出的问题,因为找到特定服务的替代品相当容易。根据《福布斯》的一篇文章,44%的消费者表示他们可能会在个性化体验后再次光顾

Benefits of personalization

矩阵分解导论

矩阵分解是推荐系统家族中的算法之一,顾名思义,它分解一个矩阵,即将一个矩阵分解成两个(或更多)矩阵,这样一旦你将它们相乘,你就可以得到你的原始矩阵。在推荐系统的情况下,我们通常会从用户和项目之间的交互/评级矩阵开始,矩阵分解算法会将该矩阵分解为用户和项目特征矩阵,这也称为嵌入。交互矩阵例子可以是电影推荐者的用户电影评级、交易数据的用户产品购买标志等。

典型地,用户/项目嵌入分别捕获关于用户和项目属性的潜在特征。本质上,潜在特征是用户/项目在任意空间中的表示,其表示用户如何评价电影。在电影推荐器的例子中,用户嵌入的例子可以表示当潜在特征的值高时用户喜欢观看严肃类型的电影,当潜在特征的值低时喜欢观看喜剧类型的电影。类似地,当电影更多地由男性驱动时,电影潜在特征可能具有高价值,而当电影更多地由女性驱动时,该价值通常较低。

有关矩阵分解和因式分解机器的更多信息,您可以阅读这些文章—
矩阵分解:Python 中的简单教程和实现
入门指南—因式分解机器&它们在巨大数据集上的应用(用 Python 编写代码)

HandOn:用 Python 中的 LightFM 包构建推荐系统

在动手操作部分,我们将为不同的场景构建推荐系统,这些场景我们通常会在许多使用 LightFM 包和 MovieLens 数据的公司中看到。我们使用的是小型数据,其中包含 700 名用户对 9000 部电影的 100,000 个评分和 1,300 个标签应用

数据

让我们从导入数据、推荐系统指南预处理指南文件开始,这是实际操作部分。我编写了这些可重用的通用食谱代码来提高生产率和编写干净/模块化的代码;你将会看到,通过使用这些食谱,我们可以用 10-15 行代码构建一个推荐系统(事半功倍!).

# Importing Libraries and cookbooks
from recsys import * ## recommender system cookbook
from generic_preprocessing import * ## pre-processing code
from IPython.display import HTML ## Setting display options for Ipython Notebook# Importing rating data and having a look
ratings = pd.read_csv('./ml-latest-small/ratings.csv')
ratings.head()

Ratings data

正如我们所看到的,评级数据包含用户 id、电影 id 和 0.5 到 5 之间的评级,时间戳表示给出评级的时间。

# Importing movie data and having a look at first five columns
movies = pd.read_csv('./ml-latest-small/movies.csv')
movies.head()

Movies data

电影数据由电影 id、标题和所属类型组成。

预处理

正如我之前提到的,要创建一个推荐系统,我们需要从创建一个交互矩阵开始。对于这个任务,我们将使用 recsys cookbook 中的create _ interaction _ matrix函数。该函数要求您输入一个 pandas 数据框架和必要的信息,如用户 id、项目 id 和评级的列名。如果 norm=True,它还需要一个额外的参数阈值,这意味着任何高于上述阈值的评级都被视为正面评级。在我们的例子中,我们不需要标准化我们的数据,但是在零售数据的情况下,任何特定类型的商品的购买都可以被认为是积极的评价,数量并不重要。

# Creating interaction matrix using rating data
interactions = create_interaction_matrix(df = ratings,
                                         user_col = 'userId',
                                         item_col = 'movieId',
                                         rating_col = 'rating')
interactions.head()

Interaction data

正如我们所看到的,数据是以交互格式创建的,其中行代表每个用户,列代表每个电影 id,评级作为值。
我们还将创建用户和项目字典,以便稍后通过使用 create_user_dictcreate_item dict 函数将 user_id 转换为 user_name 或将 movie_id 转换为 movie_name。

# Create User Dict
user_dict = create_user_dict(interactions=interactions)
# Create Item dict
movies_dict = create_item_dict(df = movies,
                               id_col = 'movieId',
                               name_col = 'title')

构建矩阵分解模型

为了构建一个矩阵分解模型,我们将使用 runMF 函数,它将接受以下输入-

  • 互动矩阵:上一节创建的互动矩阵
  • n_components: 为每个用户和项目生成的嵌入数
  • 损失:我们需要定义一个损失函数,在这种情况下,我们使用扭曲损失,因为我们最关心的是数据的排序,即我们应该首先显示哪些项目
  • epoch: 运行的次数
  • n_jobs: 并行处理中使用的内核数量
mf_model = runMF(interactions = interactions,
                 n_components = 30,
                 loss = 'warp',
                 epoch = 30,
                 n_jobs = 4)

现在我们已经建立了矩阵分解模型,我们现在可以做一些有趣的事情。有各种各样的用例可以通过在 web 平台上使用这个模型来解决,让我们来研究一下。

用例 1:向用户推荐商品

在这个用例中,我们希望向用户展示,根据他/她过去的互动,他/她可能有兴趣购买/查看的商品。典型的行业例子是亚马逊上的“推荐给你的交易”或网飞上的“用户最佳照片”或个性化电子邮件活动。

对于这种情况,我们可以使用sample _ re commendation _ user函数。该函数将矩阵分解模型、交互矩阵、用户字典、项目字典、user_id 和项目数量作为输入,并返回用户可能有兴趣交互的项目 id 列表。

## Calling 10 movie recommendation for user id 11
rec_list = sample_recommendation_user(model = mf_model, 
                                      interactions = interactions, 
                                      user_id = 11, 
                                      user_dict = user_dict,
                                      item_dict = movies_dict, 
                                      threshold = 4,
                                      nrec_items = 10,
                                      show = True)Known Likes:
1- The Hunger Games: Catching Fire (2013)
2- Gravity (2013)
3- Dark Knight Rises, The (2012)
4- The Hunger Games (2012)
5- Town, The (2010)
6- Exit Through the Gift Shop (2010)
7- Bank Job, The (2008)
8- Departed, The (2006)
9- Bourne Identity, The (1988)
10- Step Into Liquid (2002)
11- SLC Punk! (1998)
12- Last of the Mohicans, The (1992)
13- Good, the Bad and the Ugly, The (Buono, il brutto, il cattivo, Il) (1966)
14- Robin Hood: Prince of Thieves (1991)
15- Citizen Kane (1941)
16- Trainspotting (1996)
17- Pulp Fiction (1994)
18- Usual Suspects, The (1995) Recommended Items:
1- Dark Knight, The (2008)
2- Inception (2010)
3- Iron Man (2008)
4- Shutter Island (2010)
5- Fight Club (1999)
6- Avatar (2009)
7- Forrest Gump (1994)
8- District 9 (2009)
9- WALL·E (2008)
10- Matrix, The (1999)print(rec_list)[593L, 260L, 110L, 480L, 47L, 527L, 344L, 858L, 231L, 780L]

正如我们在这种情况下看到的,用户对《黑暗骑士崛起(2012)》感兴趣,所以第一个推荐是《黑暗骑士(2008)》。该用户似乎也非常喜欢戏剧、科幻和惊悚类型的电影,并且有许多相同类型的电影推荐,如《黑暗骑士》(戏剧/犯罪)、《盗梦空间》(科幻、惊悚)、《钢铁侠》(科幻惊悚)、《禁闭岛》(德拉姆/惊悚)、《搏击俱乐部》(戏剧)、《阿凡达》(科幻)、《阿甘正传》(戏剧)、《第九区》(惊悚)、《瓦力》(科幻)、《黑客帝国》(科幻)

类似的模型也可以用于构建类似“基于您最近的浏览历史”推荐的部分,只需改变评级矩阵,以包含最近的和基于特定项目的浏览历史访问的交互。

用例 2:用户对商品的推荐

在这个用例中,我们将讨论如何推荐针对某个特定项目的用户列表。这种情况的一个例子是,当您正在对某个项目进行促销,并希望围绕该促销项目向可能对该项目感兴趣的 10,000 名用户发送电子邮件时。

对于这种情况,我们可以使用sample _ re commendation _ item函数。该函数将矩阵分解模型、交互矩阵、用户字典、项目字典、item_id 和用户数量作为输入,并返回更可能对项目感兴趣的用户 id 列表。

## Calling 15 user recommendation for item id 1
sample_recommendation_item(model = mf_model,
                           interactions = interactions,
                           item_id = 1,
                           user_dict = user_dict,
                           item_dict = movies_dict,
                           number_of_user = 15)[116, 410, 449, 657, 448, 633, 172, 109, 513, 44, 498, 459, 317, 415, 495]

正如您所看到,函数返回了一个可能对项目 ID 1 感兴趣的用户 id 列表。另一个你可能需要这种模型的例子是,当你的仓库里有一个旧库存需要清理,否则你可能不得不注销它,你想通过给可能有兴趣购买的用户一些折扣来清理它。

用例 3:商品推荐

在这个用例中,我们将讨论如何推荐针对某个特定项目的项目列表。这种模型将帮助您找到相似/相关的项目或可以捆绑在一起的项目。此类模型的典型行业用例是产品页面上的交叉销售和向上销售机会,如“与此商品相关的产品”、“经常一起购买”、“购买此商品的客户也购买此商品”和“查看此商品的客户也查看过”。
“买了这个的顾客也买了这个”“查看了这个商品的顾客也查看了”也可以通过购物篮分析解决。

为了实现这个用例,我们将使用由矩阵分解模型生成的项目嵌入来创建余弦距离矩阵。这将帮助我们计算相似性 b/w 项目,然后我们可以向感兴趣的项目推荐前 N 个相似的项目。第一步是使用create _ item _ emdedding _ distance _ matrix函数创建一个物品-物品距离矩阵。该函数将矩阵分解模型和交互矩阵作为输入,并返回一个 item_embedding_distance_matrix。

## Creating item-item distance matrix
item_item_dist = create_item_emdedding_distance_matrix(model = mf_model,
                                                       interactions = interactions)## Checking item embedding distance matrix
item_item_dist.head()

Item-Item distance

正如我们所看到的,矩阵的行和列都有电影,值代表它们之间的余弦距离。下一步是使用 item_item_recommendation 函数获得关于 item_id 的前 N 个项目。该函数将项目嵌入距离矩阵、项目 id、项目字典和要推荐的项目数作为输入,并将相似项目列表作为输出返回。

## Calling 10 recommended items for item id 
rec_list = item_item_recommendation(item_emdedding_distance_matrix = item_item_dist,
                                    item_id = 5378,
                                    item_dict = movies_dict,
                                    n_items = 10)Item of interest :Star Wars: Episode II - Attack of the Clones (2002)
Item similar to the above item:
1- Star Wars: Episode III - Revenge of the Sith (2005)
2- Lord of the Rings: The Two Towers, The (2002)
3- Lord of the Rings: The Fellowship of the Ring, The (2001)
4- Lord of the Rings: The Return of the King, The (2003)
5- Matrix Reloaded, The (2003)
6- Harry Potter and the Sorcerer's Stone (a.k.a. Harry Potter and the Philosopher's Stone) (2001)
7- Gladiator (2000)
8- Spider-Man (2002)
9- Minority Report (2002)
10- Mission: Impossible II (2000)

正如我们看到的“星球大战:第二集-克隆人的进攻(2002)”电影,我们得到了它的下一部上映的电影是“星球大战:第三集-西斯的复仇(2005)”作为第一推荐。

摘要

像任何其他博客一样,这种方法并不是对每个应用程序都完美,但是如果我们有效地使用它,同样的想法也可以起作用。随着深度学习的出现,推荐系统有了很大的进步。虽然还有改进的空间,但我对目前为止它对我的作用感到满意。以后我可能会写一些基于深度学习的推荐系统。

与此同时,我希望您喜欢阅读,并随时使用我的代码为您的目的进行尝试。此外,如果对代码或博客帖子有任何反馈,请随时联系 LinkedIn 或给我发电子邮件,地址是 aayushmnit@gmail.com。

用交互代码解决深度学习中链接神经元的内部同变移位[TF 中的手动反推]

原文:https://towardsdatascience.com/solving-internal-co-variate-shift-in-deep-learning-with-linked-neurons-with-interactive-code-61859388af76?source=collection_archive---------9-----------------------

GIF from this website

所以我仍然在写我的期末论文,但是我真的很想写这篇论文。“ 用链接的神经元解决深度学习中的内部同变量移位 ”和往常一样,让我们执行手动反向传播,看看我们是否能胜过自动微分。

激活功能

我喜欢这篇论文的原因之一是因为它在介绍各种激活函数方面做了一件令人惊奇的工作。我从来不知道唰激活功能的存在,所以这是一个很好的发现。

链接神经元/实现

红框→ 链接神经元的数学公式。

本文的主要贡献是链接神经元,这意味着梯度的导数中至少有一个非零,这将解决神经元死亡的问题。这是一个非常有趣的提议。此外,这种“链接神经元”的实现也非常简单。

Implementation from here

所以基本上,我们连接每个激活函数的输出,并传递到下一层,很简单!现在让我们来看看实际情况。

当我们给这一层一个形状张量[?,28,28,32]输出为[?28,28,64],因为它在信道维度中被连接。

网络架构(图形/ OOP 形式)

红圈 →卷积运算
蓝/白圈 →不同输入的激活功能
黑圈 →串接输出层

所以以上是我们网络的基本积木,每一层都是由卷积,2 激活,最后是均值池运算组成。现在让我们看看 OOP 表单。

使用上述架构,我们将创建 5 个完全卷积网络,并在 MNIST 数据集上进行测试。

结果(自动微分)

右上 →训练图像的平均时间成本
左上 →训练图像的平均时间精度
左下 →测试图像的平均时间成本
右下 →测试图像的平均时间精度

使用自动微分,我能够在 100 个历元内获得 85%的准确度。学习率是 0.0003,但是我做了额外的实验,将学习率设置为 0.003,并且能够在相同的时间内达到+92%。

结果(扩张反向传播)

右上 →训练图像的平均时间成本
左上 →训练图像的平均时间精度
左下 →测试图像的平均时间成本
右下 →测试图像的平均时间精度

对于这个案例,我得到了一个非常令人失望的结果。该模型甚至无法达到 20%的准确率,而且随着时间的推移,成本实际上还在增加!我再三检查了我是否正确地进行了求导,结果似乎是正确的。这绝对是我想要深入研究的案例。

互动代码\透明度

对于 Google Colab,您需要一个 Google 帐户来查看代码,而且您不能在 Google Colab 中运行只读脚本,因此请在您的操场上创建一个副本。最后,我永远不会请求允许访问你在 Google Drive 上的文件,仅供参考。编码快乐!

要访问自动微分的代码,请点击此处。

要访问扩张反向传播的代码,请点击此处。

为了使这个实验更加透明,我已经将我的命令窗口的所有输出上传到我的 github,要访问自动微分模型的输出,请单击此处,要访问手动反向传播,请单击此处

最后的话

我不确定这种方法是否能完全取代批量标准化,但是这种方法确实很有趣。

如果发现任何错误,请发电子邮件到 jae.duk.seo@gmail.com 给我,如果你想看我所有写作的列表,请在这里查看我的网站。

同时,在我的 twitter 上关注我这里,访问我的网站,或者我的 Youtube 频道了解更多内容。如果你感兴趣的话,我还做了解耦神经网络的比较。

参考

  1. Molina,C. R. R .,& Vila,O. P. (2017)。用链接神经元解决深度学习中的内部协变量移位。 arXiv 预印本 arXiv:1712.02609
  2. 适合 ML 初学者的 MNIST。(2018).张量流。检索于 2018 年 4 月 18 日,来自https://www . tensor flow . org/versions/r 1.1/get _ started/mnist/初学者
  3. 梯度下降优化算法综述。(2016).塞巴斯蒂安·鲁德。检索于 2018 年 4 月 18 日,来自http://ruder.io/optimizing-gradient-descent/index.html#adam
  4. 用交互式代码实现英伟达用于自动驾驶汽车的神经网络。(2018).走向数据科学。检索于 2018 年 4 月 18 日,来自https://towards data science . com/implementing-neural-network-used-for-driving-cars-from-NVIDIA-with-interactive-code-manual-aa 6780 BC 70 f 4
  5. CIFAR-10 和 CIFAR-100 数据集。(2018).Cs.toronto.edu。检索于 2018 年 4 月 18 日,来自https://www.cs.toronto.edu/~kriz/cifar.html
  6. JaeDukSeo/个人 _ 日常 _ 神经网络 _ 实践。(2018).GitHub。检索于 2018 年 4 月 18 日,来自https://github . com/JaeDukSeo/Personal _ Daily _ neural network _ Practice/blob/master/y _ ndi via/d _ upload . py
  7. 欢迎阅读链接神经元的文档!—链接神经元 0.1.0 文档。(2018).linked-neurons . readthedocs . io . 2018 年 4 月 19 日检索,来自https://linked-neurons.readthedocs.io/en/latest/
  8. JaeDukSeo/个人 _ 日常 _ 神经网络 _ 实践。(2018).GitHub。检索于 2018 年 4 月 19 日,来自https://github . com/JaeDukSeo/Personal _ Daily _ neural network _ Practice/blob/dd6f 52 b 24 f 45 CDB 73 b 46 de 5 eeca 07 B3 be 1b 7 a 195/3 _ tensor flow/archieve/7 _ auto _ CNN . py
  9. TensorFlow 等同于 numpy .重复问题#8246 tensorflow/tensorflow。(2018).GitHub。检索于 2018 年 4 月 19 日,来自 https://github.com/tensorflow/tensorflow/issues/8246
  10. Ramachandran,p .,Zoph,b .,& Le,Q. V. (2018 年)。搜索激活功能。

用 Python 和 OpenCV 解拼图

原文:https://towardsdatascience.com/solving-jigsaw-puzzles-with-python-and-opencv-d775ba730660?source=collection_archive---------8-----------------------

源代码在这里

2018 年初,我收到了一个很棒的星球大战 5000 块拼图(你可以在亚马逊这里找到它)。完成这个拼图花了我大约 2 个月的耐心和毅力,但现在我可以满意和高兴地看着我的杰作。

然而,我仍然记得当我必须完成拼图的中心部分时,它是由一个巨大的达斯·维德和卢克·天行者组成的(剧透警告:达斯·维德的儿子!!).我基本上发现自己坐在一千件黑色和深蓝色的衣服前,寻找匹配的衣服成了一件真正的痛苦。

They are all black!!!!!!!!

这时候,我决定给计算机视觉一个机会,尝试编写一个程序,能够通过查看它们的形状来找到匹配的碎片。

在这第一部分,我将解释我是如何从每一件作品中提取出四个边的,以便在将来匹配形状。在这里,我将展示一个输出图像,以明确我在这里试图实现的目标:

1.创建数据集

首先要做的是在最佳光线条件下(用我的手机)拍摄 200 多张照片。请注意,我拍了拼图背面的照片,因为我不需要拼图内容,只需要它的形状。我还固定了相机和拼图的位置,这样从整个图像中裁剪出碎片就成了一件小事:

img = cv2.imread(join('images', filename))
img = img[1750:2500, 1000:2000]

Example of picture of puzzle piece and cropping

2.分段

由于数据集内的光线条件和块颜色都不会改变,因此使用简单的二进制阈值分割来实现分割。
在应用二值化之前,对灰度图像应用中值滤波器,以去除拼图块上的白噪声。然后使用均值滤波器平滑二值化图像:

gray   = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray   = cv2.medianBlur(gray, ksize=5)
thresh = cv2.threshold(gray, 130, 255, cv2.THRESH_BINARY)[1]
thresh = cv2.blur(thresh, ksize=(3, 3))

一旦获得了阈值图像,我通过使用cv2.connectedComponents OpenCV 函数并采用具有最大面积的连通分量(即拼图块本身)来清除潜在的假阳性区域(标记为拼图块像素的背景像素)。最后,我进一步把它裁剪成一个正方形的图像,这样可以在不丢失部分图像的情况下进行旋转。以下是此阶段的输出图像示例:

Puzzle piece segmentation and post-processing

3.找出 4 块的角

为了分开拼图的每一面,我们需要正确地找到拼图的四个主要角。这是最关键的部分,因为如果角是正确的,所有接下来的步骤将完美地工作。

在第一步中,我找到了角点的大概位置,而在第四节中,我将解释如何改进角点检测以获得准确的位置。

3a。[不成功] Canny、Hough 变换和 KMeans

在我的第一次尝试中,我使用霍夫变换找到拼图块的主线,并试图将它们分成 4 个不同的子集(每边一个)。在这里,我将简要解释算法步骤:

  1. 通过应用cv2.Canny功能对二值化图像进行边缘检测。
  2. 应用霍夫变换进行直线检测:cv2.HoughLines。对于该函数返回的每一行,我们以参数形式获得其系数。
  3. 通过估计棋子的方向来移除不需要的线:因为我们期望通过棋子的四个角的四条线形成一个矩形,所以我将具有相同方向的线组合在一起,以便修剪不属于这个组的线。
  4. 用 KMeans 对线进行聚类:我们可以根据它们的系数,将所有的线分成 4 个不同的聚类,每条线代表一面。
  5. 计算每个聚类的平均线。
  6. 计算四条平均线之间的交点,最终获得四个角。

Blue lines are all the hough lines after the pruning phase. Green lines are the mean lines for each cluster of lines.

尽管简单明了,但这种算法并没有被证明是健壮的:这种情况尤其发生在拼图的一边只有几条线或者没有线的时候,使得聚类结果变得不可预测。此外,这些线并不总是足够接近真实的边线,使得它们的交点离真实的角太远。

3b。哈里斯角点检测器和最大矩形估计

在第二次尝试中,我应用了 Harris 角点检测,以找到最佳候选角点,并使用一种能够始终检测到正确角点的算法来改进这种估计,该尝试被证明是准确和稳健的。

  1. 我首先应用了cv2.Harris函数,它返回一个新的浮点图像,在这里计算每个像素的‘角度’值(越高,越健壮
  2. 然后,我发现哈里斯图像的局部最大值高于某个阈值。在这一段之后,我有了离散的点,这些点代表了拼图块的候选角。好的一面是,对于我的数据集中的每个拼图块,该算法都返回一个候选角点,其中存在一个真实角点。请看这里的例子:

Candidate corners obtained by finding local maxima of the Harris corner detection function

3.给定所有候选角点,找出最大化一个函数的四个角点集合:
-由四个点形成的形状的“矩形度”:四个角越接近 90°,越好
-形状的面积:形状越大越好(这是因为我们期望我们能找到的最远的点就是真正的角点本身)

这个算法被证明对我所有的数据集图像都是成功的。耶!

4.改进角点检测

在进入下一个阶段之前,我旋转拼图块,使其水平(或垂直,取决于你的观点…)并使用 Canny 边缘检测器计算其边缘。

然后,我通过选择一个以检测到的角为中心的窗口,并从穿过拼图块中心的 45°或 135°方向的直线中找到最远的点,来优化检测到的角的位置。如您所见,结果相当准确:

Refinement of the 4 puzzle corners. The small circles are centered on the refined corner.

5.分开四边

现在我们有了一些好的拼图角落,我们需要将拼图块的周边分成四个边。每条边都是一条相连的曲线,从一个角开始,到另一个角结束。

最简单的想法非常有效:计算通过四个角的四条线,并根据最接近该点的线对每个周界点进行分类。
然而,在某些情况下,一侧有一个很大的突起,并且它的一部分被归类为属于错误的一侧,因为它最接近错误的线!
为了解决这个问题,我将这个简单的方法修改成了一个更健壮的方法:

  1. 应用“最近线”的想法,直到一个最大阈值:如果一个点远离所有四条线,它就不会被分类
  2. 对所有未分类的点应用滞后算法:对于每个未分类的点,检查其邻域中的周界点是否已被分类;如果这是真的,设置同一个“侧类”的要点,并继续。当所有的点都被分类后,算法结束。

最后的结果是惊人的!这里有一个例子:

In the final classification step each perimeter pixel gets assigned a different ‘side class’. In this image the four classes are shown with different colors.

我们需要的最后一个信息是每一面的方向:我们需要知道这一面是向内还是向外!(如果算法告诉我们连接两个都要出去的边,那就糟了…)
这一步非常简单,因为我们只需要检查每个边的平均点(通过平均属于同一边的所有点坐标获得)和拼图块的重心是否位于由连接其两个角的边缘线确定的同一半平面上;如果这个条件为真,那么侧面是进去的,否则是出来的。

结论

虽然我决定用蛮力的方法来完成我的星球大战拼图,但我真的很喜欢将计算机视觉算法应用到拼图中。即使这个任务乍一看似乎很简单,但需要使用大量的算法(二值化、均值滤波、边缘检测、角点检测、连通分量,……以及大量的几何图形!).

请分享你对这项工作的看法和可能的改进,也许我们可以一起建造一个完全自主的解谜机器人:)

用 sequence 2 序列模型求解 NLP 任务:从零到英雄

原文:https://towardsdatascience.com/solving-nlp-task-using-sequence2sequence-model-from-zero-to-hero-c193c1bd03d1?source=collection_archive---------6-----------------------

今天我想解决一个非常流行的 NLP 任务,叫做命名实体识别 (NER)。简而言之,NER 是一项从一系列单词(一个句子)中提取命名实体的任务。例如,给出这样一句话:

"吉姆在 2006 年购买了 300 股 Acme 公司的股票."

我们想说“Jim”是一个人,“Acme”是一个组织,“2006”是时间。

为此,我将使用这个公开可用的 Kaggle 数据集。这里我将跳过所有的数据处理代码,把重点放在实际的问题和解决方案上。你可以在这个笔记本里看到完整的代码。在这个数据集中,有许多实体类型,如 Person (PER)、organization(ORG)和其他,对于每个实体类型,有两种类型的标签:“B-SOMETAG”和“I-SOMETAG”。b 代表实体名称的开始,I-代表该实体的延续。因此,如果我们有一个像“世界卫生组织”这样的实体,相应的标签将是[B-ORG, I-ORG, I-ORG]

以下是数据集中的一个示例:

import pandas as pd
ner_df = pd.read_csv('ner_dataset.csv')
ner_df.head(30)

所以我们得到一些序列(句子),我们想预测每个单词的“类”。这不是像分类或回归这样简单的机器学习任务。我们得到一个序列,我们的输出应该是一个大小相同的序列

有很多方法可以解决这个问题。在这里,我将执行以下操作:

  1. 建立一个非常简单的模型,将这项任务视为每个句子中每个单词的分类,并将其作为基准。
  2. 使用 Keras 建立序列对序列模型。
  3. 讨论衡量和比较我们结果的正确方法。
  4. 在 Seq2Seq 模型中使用预先训练的手套嵌入。

请随意跳到任何部分。

词汇包和多类分类

正如我之前提到的,我们的输出应该是一系列的类,但是首先,我想探索一种有点幼稚的方法——一个简单的多类分类模型。我希望将每个句子中的每个单词视为一个单独的实例,并且对于每个实例(单词),我希望能够预测其类别,即 O、B-ORG、I-ORG、B-PER 等中的一个。这当然不是建模这个问题的最佳方式,但是我想这样做有两个原因。我想在尽可能保持简单的同时创建一个基准,我想展示当我们处理序列时,序列到序列模型工作得更好。很多时候,当我们试图模拟现实生活中的问题时,并不总是清楚我们正在处理的是什么类型的问题。有时我们试图将这些问题建模为简单的分类任务,而实际上,序列模型可能会好得多。

正如我所说的,我将这种方法作为基准,并尽可能保持简单,因此对于每个单词(实例),我的特征将只是单词向量(单词包)和同一句子中的所有其他单词。我的目标变量将是 17 个类中的一个。

def sentence_to_instances(words, tags, bow, count_vectorizer):
    X = []
    y = []
    for w, t in zip(words, tags):
        v = count_vectorizer.transform([w])[0]
        v = scipy.sparse.hstack([v, bow])
        X.append(v)
        y.append(t)

    return scipy.sparse.vstack(X), y

所以给出这样一句话:

“世界卫生组织称已有 227 人死于禽流感”

我们将得到每个单词的 12 个实例。

the             O
world           B-org
health          I-org
organization    I-org
says            O
227             O
people          O
have            O
died            O
from            O
bird            O
flu             O

现在我们的任务是,给定句子中的一个单词,预测它的类别。

我们的数据集中有 47958 个句子,我们将它们分为“训练”和“测试”集:

train_size = int(len(sentences_words) * 0.8)train_sentences_words = sentences_words[:train_size]
train_sentences_tags = sentences_tags[:train_size]
test_sentences_words = sentences_words[train_size:]
test_sentences_tags = sentences_tags[train_size:]# ============== Output ==============================Train: 38366 
Test: 9592 

我们将使用上面的方法将所有的句子转换成许多单词的实例。在train数据集中,我们有 839,214 个单词实例。

train_X, train_y = sentences_to_instances(train_sentences_words,           
                                          train_sentences_tags, 
                                          count_vectorizer)print 'Train X shape:', train_X.shape
print 'Train Y shape:', train_y.shape# ============== Output ==============================
Train X shape: (839214, 50892)
Train Y shape: (839214,)

在我们的X中,我们有 50892 个维度:一个是当前单词的热点向量,一个是同一句子中所有其他单词的单词包向量。

我们将使用梯度推进分类器作为我们的预测器:

clf = GradientBoostingClassifier().fit(train_X, train_y)
predicted = clf.predict(test_X)
print classification_report(test_y, predicted)

我们得到:

 precision  recall    f1-score   support

      B-art       0.57      0.05      0.09        82
      B-eve       0.68      0.28      0.40        46
      B-geo       0.91      0.40      0.56      7553
      B-gpe       0.96      0.84      0.90      3242
      B-nat       0.52      0.27      0.36        48
      B-org       0.93      0.31      0.46      4082
      B-per       0.80      0.52      0.63      3321
      B-tim       0.91      0.66      0.76      4107
      I-art       0.09      0.02      0.04        43
      I-eve       0.33      0.02      0.04        44
      I-geo       0.82      0.55      0.66      1408
      I-gpe       0.86      0.62      0.72        40
      I-nat       0.20      0.08      0.12        12
      I-org       0.88      0.24      0.38      3470
      I-per       0.93      0.25      0.40      3332
      I-tim       0.67      0.15      0.25      1308
          O       0.91      1.00      0.95    177215

avg / total       0.91      0.91      0.89    209353

好吃吗?很难说,但看起来没那么糟。我们可能会考虑几种方法来改进我们的模型,但这不是本文的目标,正如我所说,我希望保持它是一个非常简单的基准。

但是我们有一个问题。这不是衡量我们模型的正确方法。我们获得了每个单词的精确度/召回率,但是它没有告诉我们任何关于真实实体的事情。这里有一个简单的例子,给定同一个句子:

世界卫生组织称已有 227 人死于禽流感

我们有 3 个带有 ORG 类的类,如果我们只正确预测了其中的两个,我们将获得 66%的单词准确率,但是我们没有正确提取“世界卫生组织”实体,所以我们对实体的准确率将是 0!

稍后我将在这里讨论一种更好的方法来度量我们的命名实体识别模型,但是首先,让我们构建我们的“序列对序列”模型。

序列对序列模型

先前方法的一个主要缺点是我们丢失了依赖信息。给定一个句子中的单词,知道左边(或右边)的单词是一个实体可能是有益的。不仅当我们为每个单词构建实例时很难做到这一点,而且我们在预测时也无法获得这些信息。这是使用整个序列作为实例的一个原因。

有许多不同的模型可以用来做这件事。像隐马尔可夫模型(HMM)或条件随机场(CRF)这样的算法可能工作得很好,但在这里,我想使用 Keras 实现一个递归神经网络。

要使用 Keras,我们需要将句子转换成数字序列,其中每个数字代表一个单词,并且,我们需要使所有的序列长度相同。我们可以使用 Keras util 方法来实现。

首先,我们拟合一个Tokenizer,它将帮助我们将文字转化为数字。仅将其安装在train装置上非常重要。

words_tokenizer = Tokenizer(num_words=VOCAB_SIZE, 
                            filters=[], 
                            oov_token='__UNKNOWN__')
words_tokenizer.fit_on_texts(map(lambda s: ' '.join(s),                      
                                 train_sentences_words))word_index = words_tokenizer.word_index
word_index['__PADDING__'] = 0
index_word = {i:w for w, i in word_index.iteritems()}# ============== Output ==============================
print 'Unique tokens:', len(word_index)

接下来,我们将使用Tokenizer创建序列,并填充它们以获得相同长度的序列:

train_sequences = words_tokenizer.texts_to_sequences(map(lambda s: ' '.join(s), train_sentences_words))
test_sequences = words_tokenizer.texts_to_sequences(map(lambda s: ' '.join(s), test_sentences_words))train_sequences_padded = pad_sequences(train_sequences, maxlen=MAX_LEN)
test_sequences_padded = pad_sequences(test_sequences, maxlen=MAX_LEN)print train_sequences_padded.shape, test_sequences_padded.shape
# ============== Output ==============================
(38366, 75) (9592, 75)

我们可以看到在train集合中有 38,366 个序列,在test中有 9,592 个序列,每个序列中有 75 个标记。

我们也想做一些类似于我们的标签的事情,我在这里跳过代码,和以前一样,你可以在这里找到它。

print train_tags_padded.shape, test_tags_padded.shape# ============== Output ==============================
(38366, 75, 1) (9592, 75, 1)

我们在train集合中有 38366 个序列,在test中有 9592 个序列,每个序列中有 17 个标签

现在我们已经准备好构建我们的模型了。我们将使用双向长短期记忆 ( LSTM )层,因为它们被证明对此类任务非常有效:

input = Input(shape=(75,), dtype='int32')emb = Embedding(V_SIZE, 300, max_len=75)(input)x = Bidirectional(LSTM(64, return_sequences=True))(emb)preds = Dense(len(tag_index), activation='softmax')(x)model = Model(sequence_input, preds)
model.compile(loss='sparse_categorical_crossentropy',
              optimizer='adam',
              metrics=['sparse_categorical_accuracy'])

让我们看看这里有什么:

我们的第一层是Input,它接受形状向量(75,)并匹配我们的X变量(在训练和测试中,我们的每个序列中有 75 个标记)。

接下来,我们有了Embedding层。这一层将把我们的每一个符号/单词转换成一个 300 大小的密集向量。可以把它想象成一个巨大的查找表(或字典),用标记(单词 id)作为关键字,用实际的向量作为值。该查找表是可训练的,即,在模型训练期间的每个时期,我们更新那些向量以匹配输入。

Embedding层之后,我们的输入从长度为 75 的向量变成了大小为(75,300)的矩阵。75 个标记中的每一个现在都有一个大小为 300 的向量。

一旦我们有了这个,我们可以使用Bidirectional LSTM层,对于每个单词,它将在句子中双向查看,并返回一个状态,这将有助于我们稍后对单词进行分类。默认情况下,LSTM层将返回一个向量(最后一个),但是在我们的例子中,我们希望每个令牌都有一个向量,所以我们使用return_sequences=True

它看起来像这样:

这一层的输出是一个大小为(75,128)的矩阵— 75 个记号,一个方向 64 个数字,另一个方向 64 个数字。

最后,我们有一个Time Distributed Dense层(当我们使用return_sequences=True时,它变成了Time Distributed

它获取LSTM层输出的(75,128)矩阵,并返回所需的(75,18)矩阵——75 个标记,每个标记的 17 个标记概率和一个__PADDING__的标记概率。

使用model.summary()方法很容易看出发生了什么:

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, 75)                0         
_________________________________________________________________
embedding_1 (Embedding)      (None, 75, 300)           8646600   
_________________________________________________________________
bidirectional_1 (Bidirection (None, 75, 128)           186880    
_________________________________________________________________
dense_2 (Dense)              (None, 75, 18)            627       
=================================================================
Total params: 8,838,235
Trainable params: 8,838,235
Non-trainable params: 0
_________________________________________________________________

您可以看到我们所有的层及其输入和输出形状。此外,我们可以看到模型中的参数数量。你可能注意到我们的嵌入层有最多的参数。原因是我们有很多单词,我们需要为每个单词学习 300 个数字。在这篇文章的后面,我们将使用预先训练的嵌入来改进我们的模型。

让我们训练我们的模型:

model.fit(train_sequences_padded, train_tags_padded,
          batch_size=32,
          epochs=10,
          validation_data=(test_sequences_padded, test_tags_padded))# ============== Output ==============================
Train on 38366 samples, validate on 9592 samples
Epoch 1/10
38366/38366 [==============================] - 274s 7ms/step - loss: 0.1307 - sparse_categorical_accuracy: 0.9701 - val_loss: 0.0465 - val_sparse_categorical_accuracy: 0.9869
Epoch 2/10
38366/38366 [==============================] - 276s 7ms/step - loss: 0.0365 - sparse_categorical_accuracy: 0.9892 - val_loss: 0.0438 - val_sparse_categorical_accuracy: 0.9879
Epoch 3/10
38366/38366 [==============================] - 264s 7ms/step - loss: 0.0280 - sparse_categorical_accuracy: 0.9914 - val_loss: 0.0470 - val_sparse_categorical_accuracy: 0.9880
Epoch 4/10
38366/38366 [==============================] - 261s 7ms/step - loss: 0.0229 - sparse_categorical_accuracy: 0.9928 - val_loss: 0.0480 - val_sparse_categorical_accuracy: 0.9878
Epoch 5/10
38366/38366 [==============================] - 263s 7ms/step - loss: 0.0189 - sparse_categorical_accuracy: 0.9939 - val_loss: 0.0531 - val_sparse_categorical_accuracy: 0.9878
Epoch 6/10
38366/38366 [==============================] - 294s 8ms/step - loss: 0.0156 - sparse_categorical_accuracy: 0.9949 - val_loss: 0.0625 - val_sparse_categorical_accuracy: 0.9874
Epoch 7/10
38366/38366 [==============================] - 318s 8ms/step - loss: 0.0129 - sparse_categorical_accuracy: 0.9958 - val_loss: 0.0668 - val_sparse_categorical_accuracy: 0.9872
Epoch 8/10
38366/38366 [==============================] - 275s 7ms/step - loss: 0.0107 - sparse_categorical_accuracy: 0.9965 - val_loss: 0.0685 - val_sparse_categorical_accuracy: 0.9869
Epoch 9/10
38366/38366 [==============================] - 270s 7ms/step - loss: 0.0089 - sparse_categorical_accuracy: 0.9971 - val_loss: 0.0757 - val_sparse_categorical_accuracy: 0.9870
Epoch 10/10
38366/38366 [==============================] - 266s 7ms/step - loss: 0.0076 - sparse_categorical_accuracy: 0.9975 - val_loss: 0.0801 - val_sparse_categorical_accuracy: 0.9867

我们在测试集上获得了 98.6%的准确率。这个准确度并不能告诉我们太多,因为我们的大多数标签都是“0”(其他)。我们希望像以前一样看到每个类的精度/召回率,但是正如我在上一节中提到的,这也不是评估我们模型的最佳方式。我们想要的是一种方法,看看有多少不同类型的实体我们能够正确预测。

序列对序列模型的评估

当我们处理序列时,我们的标签/实体也可能是序列。正如我之前所展示的,如果我们有“世界卫生组织”作为真正的实体,预测“世界卫生组织”或“世界卫生”可能会给我们 66%的准确性,但两者都是错误的预测。我们希望将每个句子中的所有实体包装起来,并与预测的实体进行比较。

为此,我们可以使用优秀的 seqeval 库。对于每个句子,它寻找所有不同的标签并构造实体。通过对真实标签和预测标签进行操作,我们可以比较真实的实体值,而不仅仅是单词。在这种情况下,没有“B-”或“I-”标签,我们比较的是实体的实际类型,而不是词类。

使用我们的预测值,这是一个概率矩阵,我们希望为每个句子构建一个具有原始长度(而不是我们所做的 75)的标签序列,以便我们可以将它们与真实值进行比较。我们将对我们的LSTM模型和我们的单词包模型都这样做:

lstm_predicted = model.predict(test_sequences_padded)lstm_predicted_tags = []
bow_predicted_tags = []
for s, s_pred in zip(test_sentences_words, lstm_predicted):
    tags = np.argmax(s_pred, axis=1)
    tags = map(index_tag_wo_padding.get,tags)[-len(s):]
    lstm_predicted_tags.append(tags)

    bow_vector, _ = sentences_to_instances([s], 
                                           [['x']*len(s)], 
                                           count_vectorizer)
    bow_predicted = clf.predict(bow_vector)[0]
    bow_predicted_tags.append(bow_predicted)

现在我们准备使用seqeval库来评估我们的两个模型:

from seqeval.metrics import classification_report, f1_scoreprint 'LSTM'
print '='*15
print classification_report(test_sentences_tags, 
                            lstm_predicted_tags)
print 
print 'BOW'
print '='*15
print classification_report(test_sentences_tags, bow_predicted_tags)

我们得到:

LSTM
===============
             precision    recall  f1-score   support

        art       0.11      0.10      0.10        82
        gpe       0.94      0.96      0.95      3242
        eve       0.21      0.33      0.26        46
        per       0.66      0.58      0.62      3321
        tim       0.84      0.83      0.84      4107
        nat       0.00      0.00      0.00        48
        org       0.58      0.55      0.57      4082
        geo       0.83      0.83      0.83      7553

avg / total       0.77      0.75      0.76     22481

BOW
===============
             precision    recall  f1-score   support

        art       0.00      0.00      0.00        82
        gpe       0.01      0.00      0.00      3242
        eve       0.00      0.00      0.00        46
        per       0.00      0.00      0.00      3321
        tim       0.00      0.00      0.00      4107
        nat       0.00      0.00      0.00        48
        org       0.01      0.00      0.00      4082
        geo       0.03      0.00      0.00      7553

avg / total       0.01      0.00      0.00     22481

差别很大。你可以看到,弓模型几乎不能预测任何正确的事情,而 LSTM 模型做得更好。

当然,我们可以在 BOW 模型上做更多的工作,并获得更好的结果,但总体情况是清楚的,序列到序列模型在这种情况下更合适。

预训练单词嵌入

正如我们之前看到的,我们的大多数模型参数都是针对Embedding层的。训练这一层非常困难,因为有许多单词,而训练数据有限。使用预先训练好的嵌入层是很常见的。大多数当前的嵌入模型使用所谓的“分布假设”,该假设认为相似上下文中的单词具有相似的含义。通过建立一个模型来预测给定上下文中的单词(或者反过来),他们可以产生单词向量,这些向量很好地代表了单词的含义。虽然这与我们的任务没有直接关系,但使用这些嵌入可以帮助我们的模型更好地表示单词,以实现其目标。

从简单的共现矩阵到复杂得多的语言模型,还有其他方法来构建单词嵌入。在这篇的帖子中,我试图使用图像来构建单词嵌入。

这里我们将使用流行的手套嵌入。Word2Vec 或任何其他实现也可以工作。

我们需要下载它,加载单词向量并创建嵌入矩阵。我们将使用这个矩阵作为嵌入层的不可训练权重:

embeddings = {}
with open(os.path.join(GLOVE_DIR, 'glove.6B.300d.txt')) as f:
    for line in f:
        values = line.split()
        word = values[0]
        coefs = np.asarray(values[1:], dtype='float32')
        embeddings[word] = coefsnum_words = min(VOCAB_SIZE, len(word_index) + 1)
embedding_matrix = np.zeros((num_words, 300))
for word, i in word_index.items():
    if i >= VOCAB_SIZE:
        continue
    embedding_vector = embeddings.get(word)
    if embedding_vector is not None:
        embedding_matrix[i] = embedding_vector

现在来看看我们的模型:

input = Input(shape=(75,), dtype='int32')emb =  Embedding(VOCAB_SIZE, 300,                             
                embeddings_initializer=Constant(embedding_matrix),
                                           input_length=MAX_LEN,
                                           trainable=False)(input)x = Bidirectional(LSTM(64, return_sequences=True))(emb)preds = Dense(len(tag_index), activation='softmax')(x)model = Model(sequence_input, preds)
model.compile(loss='sparse_categorical_crossentropy',
              optimizer='adam',
              metrics=['sparse_categorical_accuracy'])model.summary()# ============== Output ==============================
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_2 (InputLayer)         (None, 75)                0         
_________________________________________________________________
embedding_2 (Embedding)      (None, 75, 300)           8646600   
_________________________________________________________________
bidirectional_2 (Bidirection (None, 75, 128)           186880    
_________________________________________________________________
dropout_2 (Dropout)          (None, 75, 128)           0            
_________________________________________________________________
dense_4 (Dense)              (None, 75, 18)            627       
=================================================================
Total params: 8,838,235
Trainable params: 191,635
Non-trainable params: 8,646,600
_________________________________________________________________

一切都和以前一样。唯一的区别是,现在我们的嵌入层有恒定的不可训练的权重。您可以看到,总参数的数量没有变化,而可训练参数的数量要少得多。

让我们来拟合模型:

Train on 38366 samples, validate on 9592 samples
Epoch 1/10
38366/38366 [==============================] - 143s 4ms/step - loss: 0.1401 - sparse_categorical_accuracy: 0.9676 - val_loss: 0.0514 - val_sparse_categorical_accuracy: 0.9853
Epoch 2/10
38366/38366 [==============================] - 143s 4ms/step - loss: 0.0488 - sparse_categorical_accuracy: 0.9859 - val_loss: 0.0429 - val_sparse_categorical_accuracy: 0.9875
Epoch 3/10
38366/38366 [==============================] - 138s 4ms/step - loss: 0.0417 - sparse_categorical_accuracy: 0.9876 - val_loss: 0.0401 - val_sparse_categorical_accuracy: 0.9881
Epoch 4/10
38366/38366 [==============================] - 132s 3ms/step - loss: 0.0381 - sparse_categorical_accuracy: 0.9885 - val_loss: 0.0391 - val_sparse_categorical_accuracy: 0.9887
Epoch 5/10
38366/38366 [==============================] - 146s 4ms/step - loss: 0.0355 - sparse_categorical_accuracy: 0.9891 - val_loss: 0.0367 - val_sparse_categorical_accuracy: 0.9891
Epoch 6/10
38366/38366 [==============================] - 143s 4ms/step - loss: 0.0333 - sparse_categorical_accuracy: 0.9896 - val_loss: 0.0373 - val_sparse_categorical_accuracy: 0.9891
Epoch 7/10
38366/38366 [==============================] - 145s 4ms/step - loss: 0.0318 - sparse_categorical_accuracy: 0.9900 - val_loss: 0.0355 - val_sparse_categorical_accuracy: 0.9894
Epoch 8/10
38366/38366 [==============================] - 142s 4ms/step - loss: 0.0303 - sparse_categorical_accuracy: 0.9904 - val_loss: 0.0352 - val_sparse_categorical_accuracy: 0.9895
Epoch 9/10
38366/38366 [==============================] - 138s 4ms/step - loss: 0.0289 - sparse_categorical_accuracy: 0.9907 - val_loss: 0.0362 - val_sparse_categorical_accuracy: 0.9894
Epoch 10/10
38366/38366 [==============================] - 137s 4ms/step - loss: 0.0278 - sparse_categorical_accuracy: 0.9910 - val_loss: 0.0358 - val_sparse_categorical_accuracy: 0.9895

准确度变化不大,但正如我们之前看到的,准确度不是正确的衡量标准。让我们以正确的方式对其进行评估,并与我们之前的模型进行比较:

lstm_predicted_tags = []
for s, s_pred in zip(test_sentences_words, lstm_predicted):
    tags = np.argmax(s_pred, axis=1)
    tags = map(index_tag_wo_padding.get,tags)[-len(s):]
    lstm_predicted_tags.append(tags)print 'LSTM + Pretrained Embbeddings'
print '='*15
print classification_report(test_sentences_tags, lstm_predicted_tags)# ============== Output ==============================LSTM + Pretrained Embbeddings
===============
             precision    recall  f1-score   support

        art       0.45      0.06      0.11        82
        gpe       0.97      0.95      0.96      3242
        eve       0.56      0.33      0.41        46
        per       0.72      0.71      0.72      3321
        tim       0.87      0.84      0.85      4107
        nat       0.00      0.00      0.00        48
        org       0.62      0.56      0.59      4082
        geo       0.83      0.88      0.86      7553

avg / total       0.80      0.80      0.80     22481

好多了,我们的 F1 成绩从 76 分提高到了 80 分!

结论

序列到序列模型是许多任务的非常强大的模型,如命名实体识别(NER)、词性(POS)标记、解析等等。有许多技术和选项来训练它们,但最重要的是知道何时使用它们以及如何正确地建模我们的问题。

用动态编程解决问题

原文:https://towardsdatascience.com/solving-problems-with-dynamic-programming-ea4a872dae61?source=collection_archive---------0-----------------------

此内容最初出现在 好奇洞察

动态编程是一种非常有用的解决问题的通用技术,它涉及到将问题分解成更小的重叠子问题,存储从子问题计算出的结果,并在问题的更大块上重用这些结果。动态编程解决方案总是比简单的暴力解决方案更有效。对于包含 最优子结构 的问题特别有效。

动态编程以有趣的方式与计算机科学中的许多其他基本概念相关联。例如,递归类似于(但不等同于)动态编程。关键的区别在于,在简单的递归解决方案中,子问题的答案可能会被计算很多次。缓存已经计算过的子问题的答案的递归解决方案被称为 记忆化 ,这基本上是动态编程的逆过程。另一种变化是当子问题实际上根本没有重叠时,在这种情况下,这种技术被称为 分治 。最后,动态编程与 数学归纳法 的概念联系在一起,可以认为是归纳推理在实践中的具体应用。

虽然动态编程背后的核心思想实际上非常简单,但事实证明,在非平凡的问题上使用它相当具有挑战性,因为如何根据重叠的子问题来构建一个困难的问题通常并不明显。这就是经验和实践派上用场的地方,这也是这篇博文的想法。我们将为几个众所周知的问题构建简单的和“智能的”解决方案,并看看如何使用动态编程解决方案来分解问题。代码是用基本的 python 编写的,没有特殊的依赖性。

斐波那契数

首先我们来看一下 斐波那契数列 中的数字计算问题。问题的定义非常简单——序列中的每个数字都是序列中前两个数字的和。或者,更正式地说:

F _ n = F _ n1+F _ N2,以 F_0=0F_1=1 作为种子值。

(注意:Medium 没有能力正确地呈现方程,所以我使用了一个相当简单的解决方案,用斜体显示数学符号……如果真正的意思没有很好地表达出来,我道歉。)

我们的解决方案将负责计算每个斐波纳契数,直到某个定义的限制。我们将首先实现一个简单的解决方案,从头开始重新计算序列中的每个数字。

**def** **fib**(n):  
    **if** n **==** 0:
        **return** 0
    **if** n **==** 1:
        **return** 1 **return** fib(n **-** 1) **+** fib(n **-** 2)**def** **all_fib**(n):  
    fibs **=** []
    **for** i **in** range(n):
        fibs.append(fib(i)) **return** fibs

让我们先在一个相当小的数字上试一试。

%time print(all_fib(10))[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Wall time: 0 ns

好吧,可能太琐碎了。让我们试试大一点的…

%time print(all_fib(20))[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]
Wall time: 5 ms

运行时间现在至少是可测量的,但仍然相当快。让我们再试一次…

%time print(all_fib(40))[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986]
Wall time: 1min 9s

升级得很快!显然,这是一个非常糟糕的解决方案。让我们看看应用动态编程时是什么样子的。

**def** **all_fib_dp**(n):  
    fibs **=** []
    **for** i **in** range(n):
        **if** i **<** 2:
            fibs.append(i)
        **else**:
            fibs.append(fibs[i **-** 2] **+** fibs[i **-** 1]) **return** fibs

这一次,我们保存每次迭代的结果,并计算新的数字,作为先前保存的结果的总和。让我们看看这对函数的性能有什么影响。

%time print(all_fib_dp(40))[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986]
Wall time: 0 ns

通过不在每次迭代中计算完整的 recusrive 树,我们基本上已经将前 40 个数字的运行时间从大约 75 秒减少到几乎即时。这也恰好是幼稚递归函数的危险的一个很好的例子。我们新的斐波那契数函数可以计算第一个版本的线性时间与指数时间的附加值。

%time print(all_fib_dp(100))[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073L, 4807526976L, 7778742049L, 12586269025L, 20365011074L, 32951280099L, 53316291173L, 86267571272L, 139583862445L, 225851433717L, 365435296162L, 591286729879L, 956722026041L, 1548008755920L, 2504730781961L, 4052739537881L, 6557470319842L, 10610209857723L, 17167680177565L, 27777890035288L, 44945570212853L, 72723460248141L, 117669030460994L, 190392490709135L, 308061521170129L, 498454011879264L, 806515533049393L, 1304969544928657L, 2111485077978050L, 3416454622906707L, 5527939700884757L, 8944394323791464L, 14472334024676221L, 23416728348467685L, 37889062373143906L, 61305790721611591L, 99194853094755497L, 160500643816367088L, 259695496911122585L, 420196140727489673L, 679891637638612258L, 1100087778366101931L, 1779979416004714189L, 2880067194370816120L, 4660046610375530309L, 7540113804746346429L, 12200160415121876738L, 19740274219868223167L, 31940434634990099905L, 51680708854858323072L, 83621143489848422977L, 135301852344706746049L, 218922995834555169026L]
Wall time: 0 ns

最长增长子序列

Fibonacci 问题是一个很好的开始例子,但并没有真正抓住用最优子问题来表示问题的挑战,因为对于 Fibonacci 数来说,答案是非常明显的。让我们在难度上更上一层楼,来看一个叫做 最长增长子序列 的问题。目标是找到给定序列中最长的子序列,使得子序列中的所有元素按升序排序。请注意,元素不需要连续;也就是说,它们不需要彼此相邻出现。例如,在序列[10,22,9,33,21,50,41,60,80]中,最长的递增子序列(LIS)是[10,22,33,50,60,80]。

事实证明,很难用“蛮力”解决这个问题。动态编程解决方案更简洁,也更适合问题定义,所以我们将跳过创建不必要的复杂的简单解决方案,直接跳到 DP 解决方案。

**def** **find_lis**(seq):  
    n **=** len(seq)
    max_length **=** 1
    best_seq_end **=** **-**1 # keep a chain of the values of the lis
    prev **=** [0 **for** i **in** range(n)]
    prev[0] **=** **-**1 # the length of the lis at each position
    length **=** [0 **for** i **in** range(n)]
    length[0] **=** 1 **for** i **in** range(1, n):
        length[i] **=** 0
        prev[i] **=** **-**1 # start from index i-1 and work back to 0
        **for** j **in** range(i **-** 1, **-**1, **-**1):
            **if** (length[j] **+** 1) **>** length[i] **and** seq[j] **<** seq[i]:
                # there's a number before position i that increases the lis at i
                length[i] **=** length[j] **+** 1
                prev[i] **=** j **if** length[i] **>** max_length:
            max_length **=** length[i]
            best_seq_end **=** i # recover the subsequence
    lis **=** []
    element **=** best_seq_end
    **while** element **!=** **-**1:
        lis.append(seq[element])
        element **=** prev[element] **return** lis[::**-**1]

这里的直觉是,对于给定的索引 i ,我们可以通过查看所有索引 j < i 和 if length(j)+1 > iseq[j] < seq[i] 来计算最长递增子序列的长度 length(i) (意味着在 jj 位置有一个数字增加了该索引处的最长子序列,使得它现在比最长记录子序列更长乍一看,这有点令人困惑,但是请仔细阅读,并说服自己这个解决方案找到了最佳子序列。“prev”列表保存构成子序列中实际值的元素的索引。

让我们生成一些测试数据并进行测试。

**import** numpy **as** np  
seq_small **=** list(np.random.randint(0, 20, 20))  
seq_small[16, 10, 17, 18, 9, 0, 2, 19, 4, 3, 1, 14, 12, 6, 2, 4, 11, 5, 19, 4]

现在,我们可以运行一个快速测试,看看它是否适用于一个小序列。

%time print(find_lis(seq_small))[0, 1, 2, 4, 5, 19]
Wall time: 0 ns

仅根据目测,输出看起来是正确的。让我们看看它在更大的序列上表现如何。

seq **=** list(np.random.randint(0, 10000, 10000))  
%time print(find_lis(seq))[29, 94, 125, 159, 262, 271, 274, 345, 375, 421, 524, 536, 668, 689, 694, 755, 763, 774, 788, 854, 916, 1018, 1022, 1098, 1136, 1154, 1172, 1237, 1325, 1361, 1400, 1401, 1406, 1450, 1498, 1633, 1693, 1745, 1765, 1793, 1835, 1949, 1997, 2069, 2072, 2096, 2157, 2336, 2345, 2468, 2519, 2529, 2624, 2630, 2924, 3103, 3291, 3321, 3380, 3546, 3635, 3657, 3668, 3703, 3775, 3836, 3850, 3961, 4002, 4004, 4039, 4060, 4128, 4361, 4377, 4424, 4432, 4460, 4465, 4493, 4540, 4595, 4693, 4732, 4735, 4766, 4831, 4850, 4873, 4908, 4940, 4969, 5013, 5073, 5087, 5139, 5144, 5271, 5280, 5299, 5300, 5355, 5393, 5430, 5536, 5538, 5559, 5565, 5822, 5891, 5895, 5906, 6157, 6199, 6286, 6369, 6431, 6450, 6510, 6533, 6577, 6585, 6683, 6701, 6740, 6745, 6829, 6853, 6863, 6872, 6884, 6923, 6925, 7009, 7019, 7028, 7040, 7170, 7235, 7304, 7356, 7377, 7416, 7490, 7495, 7662, 7676, 7703, 7808, 7925, 7971, 8036, 8073, 8282, 8295, 8332, 8342, 8360, 8429, 8454, 8499, 8557, 8585, 8639, 8649, 8725, 8759, 8831, 8860, 8899, 8969, 9046, 9146, 9161, 9245, 9270, 9374, 9451, 9465, 9515, 9522, 9525, 9527, 9664, 9770, 9781, 9787, 9914, 9993]
Wall time: 4.94 s

所以它仍然很快,但是差别是明显的。对于序列中的 10,000 个整数,我们的算法已经需要几秒钟才能完成。事实上,即使这个解决方案使用了动态编程,它的运行时仍然是 O(n2) 。这里的教训是,动态编程并不总是能产生快如闪电的解决方案。同样的问题,应用 DP 也有不同的方法。事实上,这个问题有一个解决方案,它使用二分搜索法树,运行时间为 O(nlogn) 时间,比我们刚刚提出的解决方案要好得多。

背包问题

背包问题 是另一个经典的动态规划练习。这个问题的一般化由来已久,并且有许多变体,除了动态编程之外,实际上还有多种方法可以解决这个问题。尽管如此,这仍然是 DP 练习的一个常见例子。

其核心问题是一个组合优化问题。给定一组项目,每个项目都有一个质量和一个值,确定在不超过总重量限制的情况下产生最高可能值的项目集合。我们将看到的变化通常被称为 0–1 背包问题,它将每种物品的副本数量限制为 0 或 1。更正式地说,给定一组 n 个项目,每个项目都有重量 w_i 和值 v_i 以及最大总重量 W ,我们的目标是:

maxσv _ IX _ I,其中σW _ IX _ I≤W

让我们看看实现是什么样子,然后讨论它为什么工作。

**def** **knapsack**(W, w, v):  
    # create a W x n solution matrix to store the sub-problem results
    n **=** len(v)
    S **=** [[0 **for** x **in** range(W)] **for** k **in** range(n)] **for** x **in** range(1, W):
        **for** k **in** range(1, n):
            # using this notation k is the number of items in the solution and x is the max weight of the solution,
            # so the initial assumption is that the optimal solution with k items at weight x is at least as good
            # as the optimal solution with k-1 items for the same max weight
            S[k][x] **=** S[k**-**1][x] # if the current item weighs less than the max weight and the optimal solution including this item is 
            # better than the current optimum, the new optimum is the one resulting from including the current item
            **if** w[k] **<** x **and** S[k**-**1][x**-**w[k]] **+** v[k] **>** S[k][x]:
                S[k][x] **=** S[k**-**1][x**-**w[k]] **+** v[k] **return** S

这种算法背后的直觉是,一旦你已经解决了在某个重量 x < W 和某个数量的物品 k < n 的物品的最佳组合,那么就很容易解决多一个物品或一个更高的最大重量的问题,因为你可以检查通过合并该物品获得的解决方案是否比你已经找到的最佳解决方案更好。那么如何得到初始解呢?继续沿着兔子洞往下走,直到到达 0(在这种情况下,答案是 0)。乍一看,这很难理解,但这正是动态编程的魅力所在。让我们运行一个例子来看看它是什么样子的。我们将从一些随机生成的权重和值开始。

w **=** list(np.random.randint(0, 10, 5))  
v **=** list(np.random.randint(0, 100, 5))  
w, v([3, 9, 3, 6, 5], [40, 45, 72, 77, 16])

现在,我们可以在一个约束条件下运行该算法,该约束条件是项目的权重之和不能超过 15。

knapsack(15, w, v)[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45],
 [0, 0, 0, 0, 72, 72, 72, 72, 72, 72, 72, 72, 72, 117, 117],
 [0, 0, 0, 0, 72, 72, 72, 77, 77, 77, 149, 149, 149, 149, 149],
 [0, 0, 0, 0, 72, 72, 72, 77, 77, 88, 149, 149, 149, 149, 149]]

这里的输出是给定的最大权重(将其视为列索引)和最大项目数(行索引)的最佳值数组。注意输出是如何遵循看起来有点像波前图案的。这似乎是动态编程解决方案中经常出现的现象。右下角的值是我们在给定约束条件下寻找的最大值,也是问题的答案。

我们对动态编程的介绍到此结束!在现实世界中使用这种技术肯定需要大量的练习;动态编程的大多数应用都不是很明显,需要一些技巧才能发现。就我个人而言,这对我来说一点都不自然,甚至学习这些相对简单的例子也需要花很多心思。看起来这类问题在实践中并不经常出现,这可能有一定的道理。然而,我发现,简单地了解动态编程以及它如何适应更一般的问题解决框架,已经使我成为一名更好的工程师,这本身就使得花时间去理解它是值得的。

对本文的评论,请查看原贴 好奇洞察

关注我的Twitter获取新帖子更新

使用数据科学解决现实世界的问题

原文:https://towardsdatascience.com/solving-real-world-problem-using-data-science-e2236159a1a9?source=collection_archive---------3-----------------------

Source: Betsol

数据科学的世界每天都在发展。这个领域的每一个专业人士都需要更新,不断学习,否则就有落伍的风险。你必须有解决问题的欲望。所以我决定研究并解决一个现实世界中的问题,这个问题是我们大多数人在职业生涯中都面临过的。面试中的技术回合!

有多少次你经历了一场技术面试,你觉得自己表现得很好,然后一个问题出现了,把你难住了?从那以后,整个面试就走下坡路了,因为现在你已经失去了信心,招聘人员也失去了兴趣。

但是完全根据 3 个小时的面试来判断一个应聘者的技术能力公平吗?这是两端的损失,因为现在公司失去了一个潜在的候选人,候选人也失去了一个机会。

要是有一种方法能让招聘人员在面试大厅之外了解候选人的技术能力就好了。各种各样的评分系统——给出理想的分数来衡量候选人的技术知识,从而帮助招聘人员做出明智、公正的决定。听起来像梦里的场景,对吧?

因此,我决定启动一个名为“Scorey”的项目,旨在破解这一挑战。

Scorey 根据公开来源帮助搜集、汇总和评估候选人的技术能力。

设置问题陈述

当前的面试场景偏向于“候选人在 3 小时面试中的表现”,而没有考虑其他因素,例如候选人的竞争性编码能力,对开发人员社区的贡献,等等。

我们将采取的方法

Scorey 试图通过汇总各种网站的公开数据来解决这个问题,例如:

  • 开源代码库
  • StackOverflow
  • 厨师长
  • Codebuddy
  • 代码力
  • 黑客地球
  • SPOJ
  • git 奖

一旦收集到数据,算法就会定义一个综合评分系统,根据以下因素对候选人的技术能力进行评级:

  • 等级
  • 解决的问题数量
  • 活动
  • 名声
  • 贡献
  • 追随者

然后给候选人打分,满分为 100 分。这有助于面试官全面了解候选人的能力,从而做出公正、明智的决定。

设置项目

对于这个项目的整个范围,我们将使用 Python,一个 Jupyter 笔记本&抓取库。因此,如果你是一个喜欢笔记本的人,那么这一部分就是为你准备的。如果没有,请随意跳过这一部分,继续下一部分。

**def color_negative_red(val):
    *"""*
 *Takes a scalar and returns a string with*
 *the css property `'color: red'` for negative*
 *strings, black otherwise.*
 *"""*
    color = 'red' if val > 0 else 'black'
    return 'color: %s' % color*****( Set CSS properties for th elements in dataframe)*
th_props = [
  ('font-size', '15px'),
  ('text-align', 'center'),
  ('font-weight', 'bold'),
  ('color', '#00c936'),
  ('background-color', '##f7f7f7')
  ]

*# Set CSS properties for td elements in dataframe*
td_props = [
  ('font-size', '15px'),
    ('font-weight', 'bold')
  ]

*# Set table styles*
styles = [
  dict(selector="th", props=th_props),
  dict(selector="td", props=td_props)
  ]**

这将使您的 dataframe 输出看起来整洁,干净,真的很好!

现在我们已经有了我们要解决的问题的要点以及我们将如何去做,让我们开始编码吧!

第一步:抓取个人网站

我们需要汇总一个人在互联网上的整个编码存在。但是我们从哪里开始呢?咄!他/她的个人网站。当然,前提是我们有权访问候选人的个人网站。我们可以从那里解析所有必要的链接。**

**from** **bs4** **import** BeautifulSoup
**import** **urllib**
**import** **urllib.parse**
**import** **urllib.request**
**from** **urllib.request** **import** urlopen

url = input('Enter your personal website - ')

html = urlopen(url).read()
soup = BeautifulSoup(html, "lxml")

tags = soup('a')

**for** tag **in** tags:
    print (tag.get('href',**None**))

当我们运行这段代码时,我们得到下面的输出:

这里我们使用的是 BeautifulSoup ,这是一个流行的抓取库。使用这段代码,我们可以直接链接到候选人的在线个人资料。

现在,如果你必须在一个更精细的层次上评估一个程序员,你会从哪里开始呢?

  1. Github

首先,让我们使用 Github API 来获取我们需要的特定用户的所有信息。

对于我们的用例,我们只需要电子邮件、存储库数量、追随者、可雇佣者(对或错)、当前公司和最后记录的活动。

  1. StackOverflow

啊。Devs 可能不相信上帝,但 StackOverflow 绝对是他们的圣殿。你可能已经知道,在 StackOverflow 上获得声誉是非常困难的。对于这一步,您可以使用 StackExchange 的 API——它为您提供用户数据,如信誉、回答数量等。

然后,我们将这些新属性添加到现有的数据帧中。

现在,我们将瞄准并收集全球竞争性编程平台,如 CodeChef、SPOJ、Codebuddy、Hackerearth、CodeForces & GitAwards(以深入了解他们的项目)。

如你所见,所有这些刮擦给了我们很多信息。代码是很容易解释的。我还使用注释进行了记录,以便于理解。

在不深入代码本质的情况下,我想把重点放在过程上。但是如果你在执行代码时遇到任何问题,你可以大声告诉我。:)现在我们已经有了所有的数据,我们将继续创建一个评分算法。

第二步:评分系统

下一步是根据以下参数对候选人进行评分:

  • 排名(25 分)
  • 解决的问题数量(25 分)
  • 声誉(25 分)
  • 关注者(15 分)
  • 活动(5 分)
  • 贡献(5 分)

所以如果你仔细阅读这段代码,你就会明白我们如何创建一个评分系统。虽然在这一点上它非常基础,但我们可以使用机器学习来创建一个强大的动态评分系统。

最终得分

基于我们上面看到的分数系统,算法现在将为候选人的技术能力分配一个最终分数。

所以用户 poke19962008分是 100 分中的 64 分!这会让招聘人员在面试室外了解候选人的技术能力。

步骤 3:预测建模

当你试图解决一个现实世界中的问题并"有效化解决方案时,考虑最终用户的需求是很重要的。
在这种情况下,是招聘人员。
我们如何利用机器学习的力量为招聘人员增加价值?

经过头脑风暴,我发现了以下用例—
1。预测候选人的技能组合是否能满足管理层需求的模型
2。预测招聘后候选人流失概率的模型
3。使用遗传算法将候选人链接分配到各自的团队

让我们试着编写第一个用例——预测公司的满意度
,假设招聘人员使用 Scorey 筛选候选人已经有一段时间了,现在有一个 100 名候选人的数据库。
招聘后,根据候选人的表现,招聘人员使用新的二进制属性“满意度”更新数据库,该属性的值为 0 或 1。
现在让我们创建一个虚拟数据库,并尝试使用 Scikit-Learn、Pandas、Numpy 创建一个模型,并构建一个预测模型。

  1. 导入数据和库
  2. 清理数据-移除重复项和空值
  3. 使用标签编码器处理分类数据
  4. 将数据集分为训练和测试
  5. 使用 kNN 分类器进行预测
  6. 检查准确性

使用这些步骤,你将得到一个利基模型,它将能够根据潜在趋势预测候选人是否适合该公司。
对于 eg——拥有更高声誉并对开源做出贡献的候选人更有可能保留更长时间。

第四步:仪表板

我做了一个仪表板。这仍然是一项正在进行中的工作,我很乐意分享一些界面截图。

这就是了。您自己的端到端产品。
总结一下——
1。我们发现了一个问题
2。有条不紊地思考如何解决这个问题。使用网络搜集收集数据
4。建立一个算法评分系统。机器学习建立预测模型
5。传达结果的仪表板

我们使用的技术栈— Python: BeautifulSoup,Urllib,Pandas,Sklearn

所以这篇文章到此为止。我们拿了一个现实生活中的问题,尝试用数据和算法去解决!

下次你去面试时,你可以向招聘人员推销这个系统。😃

那么下一步是什么?

整个项目的代码可以在 Github 上找到——这里是

  • 集成用于规则生成的机器学习组件
  • 动态处理缺失数据异常

如果你认为这个项目很酷,并且愿意贡献自己的一份力量,我们非常欢迎你!让我们为社区建造一些令人兴奋的东西。

您可以通过LinkedInTwitter与我联系,以获取数据科学&机器学习的每日更新。****

用数据解决员工流失

原文:https://towardsdatascience.com/solving-staff-attrition-with-data-3f09af2694cd?source=collection_archive---------3-----------------------

时不时地,我喜欢跳到 Kaggle 上,看看是否有我可能想玩的有趣的数据集。本周早些时候,我偶然发现了一个关于员工流失的虚构数据集。
您可以使用下面的链接找到数据集:

[## 人力资源分析

为什么我们最优秀、最有经验的员工会过早离开?

www.kaggle.com](https://www.kaggle.com/ludobenistant/hr-analytics)

一位名叫卢多维克·贝尼斯坦特的先生分享了这个数据集,他提出了这样一个问题:“为什么我们最优秀、最有经验的员工都过早地离开了?”
他还提出了一个挑战,那就是“享受这个数据库,并尝试预测哪些有价值的员工将会在下一个离开”,这是我肯定会做的。

然而,我必须承认,尽管他的问题很有趣,我却没有兴趣回答。我还有其他问题要问:

  1. 我能预测下一个离开的员工是谁吗?
  2. 我能否创建一个有助于留住员工的系统?

我承认,问题 1 离 Ludovic 想知道的并不是很远,但是我在这个实验中真正的目标是想出一个解决问题 2 的系统。

描述数据集

数据集是模拟的,包含以下字段:

  • 员工满意度
  • 上次评估
  • 项目数量
  • 平均每月小时数
  • 在公司度过的时间
  • 他们是否发生过工伤事故
  • 他们在过去 5 年中是否有过晋升
  • 部门
  • 薪水
  • 员工是否已经离职

制定方法

为了解决这个问题,我决定结合使用三种分析方法:

  • 描述性分析:哪些观察有助于我们形成关于员工流失的各种假设?
  • 预测分析:哪些员工将要离开?
  • 规定性分析:对于那些可能离职的员工,你有什么见解或建议?

预测员工流失

只是为了好玩,我想我会先把简单的东西拿出来:建立一个机器学习模型来预测哪些员工会离开或不会离开。

我想我应该指出这种东西什么时候会在现实世界中使用。如果我在现实世界中应用这个算法,我可能会在绩效评估之后或者在“上次评估”被填充的时候运行这个算法。我认为这样做会使模型无缝地融入组织的工作流程。

对于那些可能对我的设置感到好奇的人,我正在使用一个名为 AnacondaPython 环境,我用它来管理我所有的包,并且我正在使用带有后端的 Keras api 来开发我的模型。然而,我打算很快学习张量流。

对于这个任务,我创建了一个有 1 个输入层,4 个隐藏层和一个输出层的模型。准确度分数是(我很确定这里发生了一些过度拟合)。代码如下:

Neural Network Architecture for Predicting Staff Attrition

这个模型产生了 97%的准确率。

发展一个假设

有了创建的模型,我可以预测谁将离开组织,接下来我需要找出原因。为此,我决定使用相关性分析来确定哪些因素对员工流失影响最大。

我发现与流失最相关的变量是工作满意度,得分为 -0.39 。负相关意味着离职的可能性随着工作满意度的下降而增加(有道理吧?)。我还观察到,离开的员工比留下的员工对工作的满意度低 34%。

我有了一个良好的开端,但我还没有完全完成。

最大的问题是:什么因素有助于工作满意度?

在得知员工因为对工作不满意而离职后,我需要知道为什么会这样,以及如何提高工作满意度。为了找到解决员工工作满意度的方法,我对影响工作满意度的因素做了更深入的调查。

我做了另一个关于工作满意度的相关性分析,我发现在公司花费的时间和参与的项目数量对工作满意度的影响最大。其他因素如员工的平均月工作时间和他们最近的评估也有影响。

创造洞察力

现在我有了一个机器学习模型,可以预测一名员工是否会离开,我也知道什么有助于工作满意度,我需要建立一个系统,为可能很快离开的员工提供提高工作满意度的建议。我认为创建一个“保留概况”是有用的,它总结了没有离开组织的工作人员的特点。这样做将使我能够将可能离职的工作人员的概况与这一"保留概况"进行比较,并容易产生可操作的见解。

我要补充的是,如果这个系统在野外使用,我们也会考虑员工对组织的价值(这就需要回答 Ludovic 的问题)。

以下是我为创建保留配置文件而编写的代码:

现在我已经有了一个保留配置文件,下一步是创建一个系统,该系统将结合我之前创建的模型,为用户提供关于如何对待可能离开公司的员工的建议。

我想到的逻辑相当简单:

  1. 使用机器学习模型来寻找可能离开组织的员工
  2. 将此人的分数与之前创建的保留档案进行比较
  3. 根据分数和属性与工作满意度的相关性…
  4. 提出可行的建议,以提高留住人才的可能性

我得到的输出如下所示:

This member of staff will leave.I’ve noticed that this member of staff’s ‘number_project’ is below the norm. You may want to consider increasing his/her ‘number_project’ by 2.8155514094640495

我承认这不是最好看的,但我认为这是一个很好的开始。最终产品是一个可操作的洞察。

最后的想法

说明性分析有助于增强刚担任管理职位的员工的决策能力,这些员工可能正在担任此类职位或正在接受此类职位的培训。我想在某些情况下,它甚至可以用来评估这些职位的潜在候选人。

我个人认为,对于这种类型的场景,说明性分析对于找到员工不满的根本原因并找到加强员工和管理层之间关系的方法是有用的。检验这个系统是否真的能够传递价值的最好方法是在现实生活中进行尝试。

我们无法从数据中确定的一件事是组织中项目的质量,我确实相信相关性本身可能不足以确定提高工作满意度的最佳方式。也许有了更多的数据,我们可以更好地理解影响工作满意度的因素。

*更新: 我的一个朋友提到,这种类型的项目对于组织内各部门制定战略目标会很有用。之前没想到,但我绝对同意她的说法(感谢 Shades)。

我希望这个实验是有用的,我希望你学到了一些东西。我在这方面很新,我会喜欢你的反馈。请尽可能诚实,建设性的批评总是受欢迎的。

这个实验的代码可以在 这里 找到。

如果你想知道其他人是如何处理这些数据的,请点击以下链接:

[## 人力资源分析

为什么我们最优秀、最有经验的员工会过早离开?

www.kaggle.com](https://www.kaggle.com/ludobenistant/hr-analytics/kernels)

其他人的想法给我留下了深刻的印象。

下一步是什么?

既然我已经克服了这个挑战,我将使用一个类似的数据集来测试这个方法:IBM 员工流失数据集。我想这一次我会真正回答这个问题。😃

[## IBM HR Analytics 员工流失和绩效

预测你有价值的员工的流失

www.kaggle.com](https://www.kaggle.com/pavansubhasht/ibm-hr-analytics-attrition-dataset)

回头见。

将猎人-猎物问题作为单智能体问题求解

原文:https://towardsdatascience.com/solving-the-hunter-prey-problem-as-a-single-agent-problem-using-relative-coordinates-31c3b1daf441?source=collection_archive---------14-----------------------

在本文中,我们讨论如何使用猎人相对于猎物的相对坐标将(N,N)网格上的双代理猎人-猎物问题简化为(2N-1,2N-1)网格上的单代理网格世界问题。

The hunter agent (blue) capturing its constantly spawning prey (red)

虽然我们在这里描述的方法是解决猎人-猎物问题的许多独特方法之一,但它最大的效用是简单地重复利用以前在 解决单智能体网格世界问题 (我们以前的帖子)中使用的经典强化学习技术,而不需要引入任何新技术!当然,我们不能将这个解决方案扩展到更复杂的多智能体问题,但它确实是一个强化学习的例子,在这个例子中,添加额外的物理或几何约束可以绕过对更高级方法的需求。

使用相对坐标实现猎人-猎物的 Python 代码可以在我的 Github 中找到:

***** ***当前代码实现正在重新完成(我现在正在升级我的许多 repos) * *

    • 完成后将使用链接更新这篇博文****

更多我关于深度学习和强化学习的博客、教程、项目,请查看我的 和我的 Github

如何将猎人-猎物问题格式化为固定环境下的单代理问题

尽管广义的猎人-猎物问题确实需要一个动态的第二智能体,在捕获猎物后在网格周围产卵的最简单版本可以简化为单智能体在猎人相对于猎物的相对网格坐标中找到原点(0,0)的静态环境。这种将参考系固定在运动物体上的方法,是二体经典力学物理问题中非常常用的一种方法,用来获得更简单的运动方程。

为了说明相对坐标是如何工作的,考虑一个位于全局笛卡尔坐标(2,4)的猎人和一个位于全局笛卡尔坐标(1,1)的猎物。用猎物坐标减去猎人坐标,我们得到(2,4) - (1,1) = (+1,+3)作为在笛卡尔坐标中猎人相对于猎物的相对位置。如果猎人能够以某种方式学会在这个坐标系中导航并到达(0,0),那么我们将使猎人与猎物在同一个网格方块上重合(也称为猎人捕获猎物!).

通过将参照系固定在猎物上,我们不再需要关心全球地球参照系——我们可以单独在猎物参照系中工作。这意味着我们可以关注 S_{hunter,relative}的相对状态空间,而不是更令人生畏的直积 S_{hunter} x S_{prey}全局状态空间。这样做不仅缩小了我们的状态搜索空间,以更快地训练我们的代理,而且还消除了在翻译等价的物理情况下训练代理的许多冗余,即,现在教(2,4)处的猎人在(1,1)处捕捉猎物也教(3,5)处的猎人在(2,2)处捕捉猎物,因为猎人与猎物的相对位置(+1,+3)是等价的。

为了确切地了解我们如何建立单代理框架,让我们从一个大小为(N,N)的全局网格开始。作为与单个智能体合作的交换,我们将不得不扩展我们的相对位置状态空间网格,以容纳所有可能的相对位置。具体来说,这个数字是一个大小为(2N-1,2N-1)的放大的状态空间网格,其整数值为[-N+1,N-1] x [-N+1,N-1]。这背后的推理是给定 x 或 y 的特定笛卡尔方向,全局网格上任意 2 个网格点之间的最大位移是 N 个网格正方形。因此,通过考虑正位移和负位移,我们有 2*N-1 个可能的网格平方位移的完整范围(这里的-1 来自共享的零网格平方距离)。一旦我们确定了这个扩大的(但固定的)网格状态空间,我们就可以简单地将我们看似双智能体的猎人-猎物问题解决为在[-N+1,N-1] x [-N+1,N-1]网格上搜索(0,0)的单智能体网格世界问题!

使用 AuDaS 在几分钟内解决 Kaggle Telco 客户流失挑战

原文:https://towardsdatascience.com/solving-the-kaggle-telco-customer-churn-challenge-in-minutes-with-audas-2273fed19961?source=collection_archive---------9-----------------------

更新:我开了一家科技公司。你可以在这里找到更多

A uDaS 是由 Mind Foundry 开发的自动化数据科学家,旨在让任何人,无论有没有数据科学背景,都可以轻松构建和部署质量受控的机器学习管道。AuDaS 通过允许业务分析师和数据科学家在模型构建过程中轻松插入他们的领域专业知识,并提取可操作的见解,为他们提供支持。

在本教程中,我们将看到如何使用 AuDaS 在几分钟内建立一个分类管道。目标是使用来自 Kaggle 的数据预测电信客户流失。在这种情况下,当客户决定取消订阅或不续订时,他们会感到不安。这对电信公司来说代价很高,因为获得新客户比留住现有客户更昂贵。通过预测模型,电信公司可以预测哪些客户最有可能流失,并采取适当的决策来留住他们。

在本教程中,我们将遵循标准的数据科学流程:

  1. 数据准备
  2. 管道施工和调整
  3. 解释和部署

数据准备

首先,我们将数据加载到 AuDaS 中,在本例中,它是一个简单的 csv,有 21 列和 3333 行:

每行代表一个客户,每列代表一个属性,包括语音邮件数量、总分钟数(日/夜)、总呼叫数(日/夜)等。

AuDaS 自动扫描数据,检测每个列的类型,并提供灯泡突出显示的数据准备建议。在这里,数据科学家的业务分析师可以根据相关建议和适当的答案来介绍他们的领域知识。

在这种情况下,我们知道“语音邮件消息数”列中缺少的值实际上应该用 0 来填充,只需单击:

一旦我们做到了这一点,并删除了不包含任何预测功能的客户 id 和电话号码,我们就能够获得所有数据准备步骤的完整审计跟踪。如果我们愿意,我们也可以很容易地恢复到预先准备好的数据版本。

AuDaS 还会自动为您生成漂亮的数据可视化效果。

您还可以通过加入其他数据集来丰富数据集(如果适用)。AuDaS 支持您通常会做的所有其他数据准备步骤。现在,我们对数据感到满意,我们将建立我们的分类管道。

处理数据

AuDaS 允许您快速设置分类过程,为此您只需选择目标列并指定模型验证框架和评分标准。

然后,AuDaS 使用我们的贝叶斯优化器 OPTaaS 启动并搜索可能的管道(特征工程和机器学习模型)及其相关超参数的解决方案空间。AuDaS 还对其评估的所有管道进行审计跟踪,如果需要,您可以查询这些跟踪。

我以前写过使用贝叶斯优化的直觉和优势。OPTaaS 也可以作为一个 API 获得,你可以联系我要一个密钥。

部署解决方案

一旦 AuDaS 找到了最好的管道,它将对从一开始就展示出来并且从未在任何模型训练中使用过的 10%的数据进行最终质量检查。这 10%的性能指标在最后给出,AuDaS 提供了其选择的最终管道的完全透明性(特征工程、模型、超参数值)。

然后,该模型可以通过自动生成的 RESTful API 集成到您的网站、产品或业务流程中。功能相关性由 LIME 提供,对于我们的最终模型,预测客户流失的主要功能是每日总费用。

更完整的教程可以在这里找到。如果你有兴趣尝试奥达斯,请不要犹豫,联系 out

团队和资源

Mind Foundry 是牛津大学的一个分支机构,由斯蒂芬·罗伯茨(Stephen Roberts)和迈克尔·奥斯本(Michael Osborne)教授创建,他们在数据分析领域已经工作了 35 年。Mind Foundry 团队由 30 多名世界级的机器学习研究人员和精英软件工程师组成,其中许多人曾是牛津大学的博士后。此外,Mind Foundry 通过其分拆地位,拥有超过 30 名牛津大学机器学习博士的特权。Mind Foundry 是牛津大学的投资组合公司,其投资者包括牛津科学创新牛津技术与创新基金、牛津大学创新基金Parkwalk Advisors

用数据科学解决“X 先生转移问题”

原文:https://towardsdatascience.com/solving-the-mr-x-transfer-problem-with-data-science-ab49f38f621c?source=collection_archive---------14-----------------------

在现代足球世界中,我们能够衡量每个球员和球队的表现。这给了我们一堆数据,可以用作机器学习和统计的有价值的信息来源。现代足球比赛建立在统计数据的基础上,遵循既定的规则。每个赛季,俱乐部都必须接受寻找新球员的挑战,这些新球员要么应该提高他们的比赛水平,要么支持另一名离开俱乐部的球员。

All credits and rights to Mitch Rosen https://unsplash.com/photos/g9SNY0aLMF0

对于这篇文章,让我们假设我们有一个球员 x 在夏天离开了俱乐部,现在我们必须找到一个合适的替代者。找到一名球员替代另一名球员的最简单的方法是分析老球员的给定统计数据,并找到一些进球和助攻数量几乎相同的球员。这种方法给我们带来了一个大问题:这种假设让我们完全忽略了球员在哪个球队踢球,以及他的球队在一个赛季中表现出了什么样的踢球风格,这对我们的指标也有很大的影响。对于本文,我们将使用不同的方法。让我们假设我们可以用数字来定义离开的玩家的优势和劣势。通过这样做,我们将能够专注于个人指标,而不是仅仅关注目标和助攻。这将使我们能够寻找与老球员相比在特定领域具有相同天赋的球员——这也可以理解为潜力。这意味着我们将寻找有潜力的新球员来取代老球员。

在这篇文章中,我们将使用 FIFA 19 球员属性,因为它们使我们能够使用超过 14000 名球员的个人优势和技能,并且它们也是球员个人数字素质和技能的良好指标。您可以在此处找到数据集:

https://www . ka ggle . com/aishwarya 1992/FIFA-19-player-database

定义指标

在我们开始之前,我们必须看看我们想要替换的球员:

  • 向前
  • 左脚和右脚
  • 年龄:33 岁
  • 联赛:西甲

现在让我们来看看前锋位置的 10 大参数以及球员的这些属性:

  • 步速:90
  • 加速度:89
  • 冲刺:91
  • 敏捷:87
  • 控球:94
  • 拍摄:93
  • 完成:94
  • 标题:89
  • 定位:95°
  • 沉着:95

如果我们将这个玩家的个人资料可视化,我们会得到这样的结果:

这个球员的参数形象告诉我们,我们必须更换一个“世界级球员”。上面列出的所有参数都接近或高于 90。现在我们知道了我们想要取代什么,我们必须寻找有潜力取代这种“世界级球员”的球员。

听起来是个有趣的任务。😎

定义配置文件

在我们开始寻找有潜力取代老球员的球员之前,我们必须指定我们希望球员所处的重要条件:球员不应超过 26 岁,因为我们希望有人能够从一开始就表现出高水平,但也有改进和适应的空间。除此之外,球员应该在欧洲顶级联赛之一踢球,因为这意味着球员习惯于在一个赛季踢很多比赛,也习惯于在最高水平上竞争。

个人资料:

  • 我们如何处理和评定这类参数?
  • 对于这个问题,我想具体说明我们的参数以及如何划分这些参数。考虑一个足球运动员的表现,我们有两个非常重要的因素:身体素质和技术。如果我们现在看一下我们选择的参数,我们可以将它们分成两个新的参数:

body_gene =配速+速度+加速度+敏捷

前锋 _ 基因=控球+射门+射门+头球+定位+沉着

对于这种方法,我们将使用算术平均值。算术平均值的公式如下:

对于我们的老玩家,指标如下:

  • 身体基因= 89.25
  • striker_gene = 93.2

这允许我们使用平均值作为球员身体和射手能力的指标。如果我们现在应用这两个参数,并为数据集中的所有玩家计算它们,我们将得到下面的图:

Formula arithmetic mean

该图包含我们数据集中的所有玩家。现在我们不得不减去那些没有在五个联赛中比赛的和/或年龄超过 26 岁的球员。在这一步之后,我们得到相同的图,但是只有相关和合适的样本。

仔细观察我们的图会发现,它可以很容易地分为两类。第一个从左下角区域开始,在(50,30) (x,y)处停止。第二个从(50,40)开始。对于我们的任务——找到一个与我们的老玩家潜力相当的玩家——我们只能关注第二个集群,因为那里有真正优秀的玩家。我们要考虑的下一件事是,如果我们今天签下他们,我们想要那些有潜力表现出色的球员。正因为如此,我们关注所有身体基因和前锋基因至少有 70 分的球员。这导致了下面的图:

既然我们已经选择了球员,我们可以用 k-means 把他们分成不同的类别。K-means 是一种将选择的点分成多个聚类的算法。对于我们的例子,我们将把样本分成十个组。这使我们对我们的球员进行了如下划分:

显而易见,最适合我们任务的星团是星团‘8’。如果我们仔细观察聚类 8 中的点,我们可以看到这些点是我们定义的两个参数之间的最佳连接。此外,我们还有一个“离群值”,它独立于集群中其他真正优秀的参与者..聚类 2 和聚类 5 包含部分合适的玩家,因为它们在参数中的一个方面都非常好,但在两个方面都不好。我们寻找的球员需要在这两方面都很优秀或者很有潜力。

x = body_gene , y = striker_gene (over 14000 players)

我们选择了哪些球员?

x = body_gene , y = striker_gene (1426 players)

在集群 8 中,我们找到了八名符合我们要求的玩家,现在我们必须仔细查看他们的个人资料。通过分析分离的参数,我们看到我们有优秀的球员,但他们都有一些斗争考虑一个或两个参数相比,我们的原始球员的参数。但是在我们旅程的这一点上,我们可以说我们已经发现了八个非常有趣的球员。

x = body_gene , y = striker_gene (168 players)

上面所有的球员都很年轻,但就他们的职业生涯阶段而言,他们的发展还很远。如果我们现在想选择一名球员来代替我们的老队员,我们当然应该考虑比球员参数更多的因素,因为每支球队都踢得不同,阵容中有不同的球员。这让我们有了一个不可或缺的信念:如果某个球员在 A 队表现很好,不一定在 B 队也很好,因为 B 队对球员的表现也有很大的影响。但是在这篇文章中,我们关注于相似的玩家类型和属性,认为这是一个有趣的任务。

x = body_gene , y = striker_gene

结果

现在是时候看看我们选择的球员了,当然还有我们想要选择的球员。我想对你们大多数人来说,很明显,我们想在这个夏天寻找一个替代者:克里斯蒂亚诺罗纳尔多。众所周知,取代像罗纳尔多这样的球员是一项不可能的任务,但对于这项有趣的任务,我想发现那些有潜力成为前锋位置真正替代者的球员。我敢肯定,如果我们看看我们发现的八名球员的名字,你们大多数人都会在 2019 年夏天的下一次转会中至少将两名球员作为皇家马德里的转会目标。如果我们记得我们必须替换一个身体基因为 89.25,前锋基因为 93.2 的球员,我们会发现我们没有这样的球员,但是如果我们看一下我们选择的所有球员的年龄以及他们的身体和前锋基因,我们就知道我们选择了最有潜力的球员,有一天可能成为像罗纳尔多一样的球员。

这些是我们通过数据分析和聚类算法选出的球员。我个人认为这些球员是伟大的、有天赋的、年轻的,但也是昂贵的选择。我希望你喜欢这篇文章,并从中得到一点乐趣。⚽️

All of the players above are very young but also very far in their development in reference to their career-stage. If we now want to select one player to replace our the old one we should definteley consider more factors than the player’s parameters because every team plays differently and has different players in the squad. That leads us to the indispensable conviction that if a certain player plays really well in team A — does not have to bee immediately good in team B since the team has a big impact on a player’s performance as well. But for this article we focused on similar player-types and attributes considering this to be a fun task.

The results

Now it’s time to look at the players we have selected and of course which player we want to choose. I think for the most of you it’s clear that we wanted to search an alternative for the transfer of the summer: Cristiano Ronaldo. As we all know it’s an impossible task to replace a player like Ronaldo but for this fun task I wanted to discover the players with the potential to become a real alternative considering their skillset for the forward position. I’m sure that if we take a look at the names of our discovered eight players most of you would minimum take two players as an real transfer target for Real Madrid in the next transfer summer 2019. If we remember that we have to replace a player with a body_gene of 89.25 and a striker_gene of 93.2 we see that we don’t have a player that is in the direct space of this quality but if we take a look at the age of all our selected players and their body and striker_genes then we know that we have selected the players with the highest potential to maybe become one day a player like Ronaldo.

selection with body and striker mean

So these are the players we selected with our data analysis and cluster-algorithm. Personally I would evaluate those players as a great, talented, young but also expensive choice. I hope you enjoyed this article and had a little bit of fun. ⚽️

解决多臂强盗问题

原文:https://towardsdatascience.com/solving-the-multi-armed-bandit-problem-b72de40db97c?source=collection_archive---------1-----------------------

多臂土匪问题是一个经典的强化学习例子,我们有一个带 n 个臂(土匪)的老丨虎丨机,每个臂都有自己操纵的成功概率分布。拉任何一只手臂都会给你一个随机奖励,成功的话 R=+1,失败的话 R=0。我们的目标是按顺序一个接一个地拉动手臂,这样从长远来看,我们可以获得最大的总回报。

多臂土匪问题的重要性在于我们(代理人)无法获得真正的土匪概率分布——所有的学习都是通过试错法和价值估计的方式进行的。所以问题是:

我们如何设计一个系统的策略来适应这些随机的回报?

这是我们针对多兵种土匪问题的目标,拥有这样的策略将在许多现实世界的情况下证明非常有用,在这些情况下,人们希望从一群土匪中选出“最好的”土匪,即 A/B 测试、阵容优化、评估社交媒体影响力

在本文中,我们使用一种经典的强化学习技术来解决多臂强盗问题,这种技术由一个ε-贪婪代理和一个学习框架报酬-平均抽样来计算行动值 Q(a)以帮助代理改进其未来行动决策,从而实现长期报酬最大化。这个多臂 bandit 算法解决方案的 Python 代码实现可以在我的 Github 中找到,网址是:

https://github . com/ankonzoid/learning x/tree/master/classical _ RL/multi armed _ bandit

请参考我们的附录,了解关于ε贪婪代理的更多细节,以及如何使用平均回报采样方法迭代更新 Q(a)。在下一节中,我们将解释在 multi-armed bandit 环境中部署这样一个代理的结果。

我关于深度学习和强化学习的更多博客、教程和项目可以在我的和我的 Github 找到。

结果:代理选择了哪些土匪?

考虑我们的 Python 代码示例,其中有 10 个硬编码的盗匪,每个盗匪都有自己的成功概率(请记住,我们的代理对这些数字视而不见,它只能通过对盗匪进行单独采样来实现这些数字):

**Bandit #1 = 10% success rate
Bandit #2 = 50% success rate
Bandit #3 = 60% success rate
**Bandit #4 = 80% success rate (best)**
Bandit #5 = 10% success rate
Bandit #6 = 25% success rate
Bandit #7 = 60% success rate
Bandit #8 = 45% success rate
**Bandit #9 = 75% success rate (2nd best)**
**Bandit #10 = 65% success rate (3rd best)****

通过检查,我们将期待我们的代理长期挑选出 Bandit #4 作为最强的信号,Bandit #9 紧随其后,Bandit #10 紧随其后,以此类推。

现在来看结果。我们以 10%的 epsilon 探索概率对 agent 进行了 2000 次从头开始的实验,每次实验对 agent 进行 10000 集的训练。代理选择的强盗的平均比例作为集数的函数如图 1 所示。

Fig 1) Bandit choices by the epsilon-greedy agent (epsilon = 10%) throughout its training

在图 1 中,我们可以看到,在训练开始(< 10 episodes) as it is in its exploratory phase of not knowing which bandits to take advantage of yet. It is until we reach later episodes (> 100 集)时,强盗的选择均匀地分布在所有强盗中约 10%。我们是否看到一个明显的贪婪机制优先于决定哪个强盗应该获得更高的优先级,因为到目前为止所采样的奖励。不出所料,在训练的中后期阶段,4 号、9 号和 10 号强盗是被代理人选中的。最后,几乎不可避免的是,在训练结束时,代理人倾向于几乎总是选择 Bandit #4 作为“最佳”Bandit,其平台期约为 90%(由于固定的 epsilon exploration 参数,应始终保持约 10%)。

尽管在这个问题中,最佳策略是选择强盗 4,但是你会注意到,这并不意味着拉强盗 4 就一定会在给定的拉中击败任何其他强盗,因为奖励是随机的;在长期平均回报中,你会发现土匪#4 占优势。此外,使用我们的代理来解决这个问题并没有什么特别之处——这只是可以适应性地最大化长期回报集合的许多方法之一。绝对存在这样的情况,完全探索性的(ε= 100%),或完全贪婪的代理人(ε= 0%),或介于两者之间的任何人,可能最终在有限的几集里获得比我们的ε= 10%贪婪的代理人更多的奖励。在我看来,部署这样一个代理的主要吸引力在于,可以自动最小化重新选择已经显示出一些失败迹象的强盗。从商业和实践的角度来看,这可以节省大量的时间和资源,否则会浪费在寻找“最佳”强盗的优化过程中。

附录:ε-贪婪代理“个性”和报酬平均抽样“学习规则”

简而言之,ε-贪婪代理是(1)完全探索代理和(2)完全贪婪代理的混合体。在多臂土匪问题中,一个完全探索性的代理将以统一的速率对所有土匪进行采样,并随着时间的推移获得关于每个土匪的知识;这种代理的警告是,这种知识从来没有被用来帮助自己做出更好的未来决策!在另一个极端,一个完全贪婪的代理人会选择一个强盗,并永远坚持自己的选择;它不会努力尝试系统中的其他强盗,看看他们是否有更好的成功率来帮助它实现长期回报的最大化,因此它是非常狭隘的!

为了得到一个拥有两个世界的最好的有点令人满意的代理,ε贪婪代理被设计为在任何状态下给ε机会(例如 10%)来随机地探索土匪,并且在所有其他时间贪婪地对其当前的“最佳”土匪值估计采取行动。围绕这一点的直觉是,贪婪机制可以帮助代理专注于其当前最“成功”的盗匪,而探索机制让代理探索可能存在的更好的盗匪。

剩下的唯一问题是:我们如何给代理定义一个强盗的“价值”概念,以便它可以贪婪地选择?借鉴强化学习,我们可以定义行动价值函数 Q(s,a)来表示从状态 s 采取行动 a 的预期长期回报。在我们的多臂强盗的例子中,每一个动作都将代理带入一个终结状态,因此长期回报就是直接回报,我们将动作价值的定义简化为

其中 k 是一个(强盗)在过去被选择的次数的计数器,而 r 是每次选择强盗的随机奖励。通过一些额外的算术操作,这个定义可以递归地重写为

由于我们不知道从知道 Q(a)的“真实”值开始,我们可以使用这个递归定义作为迭代工具,在每集结束时近似 Q(a)。

为了将ε-贪婪代理与我们的动作值 Q(a)估计配对,我们让ε-贪婪代理在时间的随机ε-概率上选择一个强盗,并让代理在其余时间从我们的 Q(a)估计中贪婪地选择一个动作

有了这两个概念,我们现在可以着手解决多臂土匪问题!

一些重要的数据科学工具,不是 Python、R、SQL 或 Math

原文:https://towardsdatascience.com/some-important-data-science-tools-that-arent-python-r-sql-or-math-96a109fa56d?source=collection_archive---------2-----------------------

一些你可能想熟悉的必要的、重要的或者很酷的数据科学工具

如果你问任何一位数据科学家,要想在这个领域取得成功,你需要知道什么,他们可能会告诉你以上几点的组合。每一份 DS 的工作描述都会提到 Python 或 R(有时甚至是 Java lol)、SQL 和数学,还夹杂着一些火花、AWS/cloud 体验,并以一部分流行词汇结束。

Random pic from travel. West Lake in Hangzhou, China.

虽然这些是不可否认的必备条件,但现实是大多数数据科学家并不存在于真空中——你不太可能获得完美的数据,在自己的环境中在本地机器上构建模型,然后只需保存这些权重并收工。现代数据科学家需要必要的 CS 技能,以使他们的工作成为可能,并在其他工程师的 leu 中可用。你不会把你的 jupyter 笔记本通过电子邮件发给你的老板来展示你的工作。

这些可能并不适用于所有职位,但是以我的经验和观点来看,这些工具可以像你的面包和黄油 Python 一样重要(或者一样方便)(尽管 Python 肯定是最重要的)。我不打算深入解释这些事情,但我会解释为什么你会想了解它们,以成为一个好的数据科学家——一个能够构建生产就绪的应用程序,而不是在你的本地机器上凌乱的、探索性的笔记本。

Linux

应该不用说。让我震惊的是,有多少数据科学家可能不熟悉命令行。使用 bash 脚本是计算机科学中最基本的工具之一,由于数据科学中很大一部分是编程性的,所以这项技能非常重要。

Check out my dude the Linux Penguin

几乎可以肯定,您的代码将在 linux 上开发和部署,因此我鼓励尽可能使用命令行。像数据科学一样,Python 也不存在于真空中,你几乎肯定必须通过一些命令行界面处理包/框架管理、环境变量、你的$PATH和许多其他东西。

Git

也应该不用说。大多数数据科学家知道 git,但并不真正了解 git。因为数据科学的定义非常模糊,所以我们中有很多人没有遵循良好的软件开发实践。我甚至很久都不知道什么是单元测试。

Source

当在一个团队中编码时,知道 git 变得巨大。你需要知道当团队成员提交冲突时,或者当你需要挑选部分代码进行错误修复、更新等时,该怎么做。将代码提交给开源或私有的 repo(如 Github)也允许你使用像工作服这样的东西进行代码测试,还有其他框架可以在提交时方便地将代码部署到生产环境中。就 git 和开源回购协议提供的功能而言,偶尔承诺一个只有你使用的回购协议只是冰山一角。

REST APIs

你已经训练了一个模型——现在呢?没人想看你的 jupyter 笔记本或者某种蹩脚的交互式 shell 程序。此外,除非您在共享环境中接受培训,否则您的模型仍然只对您可用。仅仅有模型是不够的,这是大量数据科学家碰壁的地方。

Preach fam

为了实际服务于来自模型的预测,通过标准 API 调用或有助于应用程序开发的东西使其可用是一个好的实践。像亚马逊 SageMaker 这样的服务已经获得了巨大的欢迎,因为它能够无缝地以生产就绪的方式制作模型。你可以用 Python 中的 Flask 之类的东西自己构建一个。

Source

最后,有许多 Python 包在后端进行 API 调用,因此理解什么是 API 以及如何在开发中使用 API 有助于成为更有能力的数据科学家。

Docker&Kubernetes

我个人最喜欢的两个——docker 允许用户拥有一个生产就绪的应用程序环境,而不必为需要在其上运行的每一项服务集中配置生产服务器。与安装完整操作系统的大型虚拟机不同,docker 容器运行在与主机相同的内核上,并且更加轻量级。

Love this guy

想象一下像 Python 的venv这样的 docker 容器,它有更多的功能。更高级的机器学习库,如谷歌的 Tensorflow,需要特定的配置,在某些主机上可能难以排除故障。因此,docker 经常与 Tensorflow 一起使用,以确保为训练模型提供一个开发就绪的环境。

Lil’ guy thinking about containerized, scalable applications

随着市场趋向于更微的服务和容器化的应用,docker 是一项巨大的技能,并且越来越受欢迎。Docker 不仅适用于训练模型,也适用于部署。将你的模型想象成服务,你可以将它们容器化,这样它们就有了运行它们所需的环境,然后可以与你的应用程序的其他服务无缝交互。这使得你的模型既可扩展又可便携。**

Source

Kubernetes (K8s)是一个跨多个主机大规模管理和部署容器化服务的平台。本质上,这意味着您可以在一个可水平扩展的集群中轻松管理和部署 docker 容器。

I wish Kubernetes also had a fun whale

当 Google 使用 Kubernetes 来管理他们的 Tensorflow 容器(以及其他东西)时,他们更进一步,开发了 Kubeflow :一个在 Kubernetes 上训练和部署模型的开源工作流。容器化的开发和生产正越来越多地与机器学习和数据科学相结合,我相信这些技能对于 2019 年的数据科学家来说将是巨大的。

One more for the fans

阿帕奇气流

现在我们变得更加小众,但是这个很酷。Airflow 是一个 Python 平台,使用有向无环图(Dag)以编程方式创作、调度和监控工作流。

DAG

这基本上意味着您可以轻松地将 Python 或 bash 脚本设置为在您需要的时候运行,无论您需要多频繁。与不太方便和可定制的 cron 作业相反,Airflow 让您可以在一个用户友好的 GUI 中控制您的计划作业。超级毒品。

弹性搜索

一样小众。这个有点特别,取决于你是否有搜索/NLP 用例。然而,我可以告诉你,在一家财富 50 强公司工作,我们有大量的搜索用例,这是我们堆栈中最重要的框架之一。与用 Python 从头开始构建不同,Elastic 用一个方便的 Python 客户端提供了你需要的一切。

Source

Elasticsearch 让您能够以容错和可伸缩的方式轻松地索引和搜索文档。数据越多,运行的节点就越多,查询的执行速度就越快。Elastic 使用 Okapi BM25 算法,该算法在功能上非常类似于使用 TF-IDF(term frequency——逆文档频率,Elastic 曾使用该算法)。它有很多其他的功能,甚至支持像多语言分析器这样的定制插件。

Elasticsearch index

因为它本质上是在查询和索引中的文档之间执行相似性比较,所以它也可以用于比较文档之间的相似性。我强烈建议不要从 scikit-learn 导入 TF-IDF,而是看看 Elasticsearch 是否能为您提供开箱即用的一切。

自制 (mac OS)

Ubuntu 有apt-get,Redhat 有yum,Windows 10 甚至有 OneGet ,我是从下面的一个评论得知的。这些包管理器通过 CLI 帮助安装,管理依赖关系,并自动更新您的$PATH。虽然 mac OS 开箱即用,但家酿软件可以通过终端命令轻松安装,这是本文的重点,因为它是我最喜欢的东西之一。

Beer

假设出于某种违反直觉的原因,您想在本地安装 Apache Spark。你可以去https://spark.apache.org/downloads.html,下载它,解压它,自己把spark-shell命令添加到你的$PATH中,或者在终端中键入brew install apache-spark就可以上路了(注意你还需要安装 scala 和 java 来使用 spark)。我知道这只是一个 mac OS 特有的东西,但我太喜欢它了,我不能不包括它。

还有更多…

我可能每天都会下载几个新的包或框架(这让我的电脑很懊恼)。这个领域变化如此之快,以至于很难跟上新的东西,更难分辨什么是真正有用的。然而,在我看来,以上的一切都将继续存在。希望你喜欢它,并随时通过 LinkedIn 联系我。以后再说。

关于工作板和机器学习的一些说明

原文:https://towardsdatascience.com/some-notes-on-job-boards-and-machine-learning-be1889e6a8a8?source=collection_archive---------7-----------------------

Image via, used under

找工作最难的部分之一是首先找到申请什么。用户知道自己想要什么工作、工作地点和工资范围,但招聘信息板很难搞清楚。

与其让求职者在无穷无尽的清单中寻找合适的东西,为什么不使用机器学习来做一些排序呢?至少,一个算法可以清理掉一些杂物,让用户专注于严肃的选项。充其量,它可以找到一个完美的职业发展机会。

首先,机器学习算法必须学习职位发布的样子。也就是说,它必须知道如何提取标题,位置,薪酬范围等。从一个文本块。这些信息构成了数据库,程序从中提取信息,将工作发送给用户。然后,一旦程序能够提取所有这些信息,它需要能够根据经验和偏好向求职者提供好的建议。

所有这些后端计算意味着用户只能看到系统总库存的一小部分。只有少数工作会出现在用户的提要中,应用程序在提供未来选择时会考虑这些工作的匹配程度。

这种系统最困难的部分是从用户反馈中微调推荐。随着用户数量的增加,对新回复进行再培训的需求将呈指数级增长,而快速、可靠地改善每个人的个人资料将需要大量的时间和金钱。然而,规模问题并不妨碍构建一个基本的程序架构。

和大多数事情一样,机器学习可能会彻底改变我们找工作的方式。更有针对性的推荐可以节省求职者的时间和精力,也让公司的招聘过程不那么痛苦。通过仔细减少给用户的选择,一种算法可以让漫长而艰苦的求职成为过去。

申请经济学背景的数据科学工作的几点思考

原文:https://towardsdatascience.com/some-thoughts-in-applying-for-data-science-jobs-with-an-economic-background-69f043a5902c?source=collection_archive---------11-----------------------

作为一名应届经济学博士毕业生,我最近申请了数据科学家的工作,并将在几周后开始我的数据科学家生涯。这整个经历对我来说是开放的和充实的。一路走来学到了很多,刷新了对行业的认识。趁着记忆犹新,我写下一些简短的想法,与和我有相似背景的人分享,他们也对转型感兴趣。

总体印象

如今,数据科学在科技界是一个非常宽泛的概念。任何与数据相关的东西都可以称为数据科学。机器学习技术和计算能力的发展大大增强了它的能力。所以,机器学习和编码方面的知识是进入这个领域的必备知识。除此之外,我认为数据科学世界非常欢迎受过经济学培训的人。有许多职位需要很好地理解因果推理,用建模的眼光来看待一些更复杂的反馈循环会有所帮助。我发现我在处理观察数据和内生性方面的经验被我采访过的团队所重视。

DS 战队的例子

下面是两个需要很好理解因果推理的例子:

1.实验平台团队

几乎所有数据驱动的公司每天都要进行数百次实验。实验平台团队提出了有助于快速实施和评估实验的方法。在科技界,人们进行随机对照试验,这听起来可能很简单,但实际上包含许多陷阱。当 RCT 不可行时,就需要对观测数据进行因果推断。如果您是估计平均治疗效果和/或边际治疗效果的专家,并且对在大数据上应用这些传统推理工具感到兴奋,那么这将是一个非常合适的选择。

例如,在优步的实验平台上有一篇关于他们所做工作的信息丰富的博文:https://eng.uber.com/xp/

2.脸书大学的营销科学 R&D 团队

同样,这个团队专注于开发评估脸书各种产品营销活动的指标和方法。和许多其他团队一样,他们结合使用倾向评分匹配、重新加权和其他技术。这篇文章非常清晰地介绍了他们所做的项目类型。

这只是我有限的求职经历中的两个例子。肯定还有很多要探索的。当我在写这份总结的时候,我发现了这篇最新的综述论文,这篇论文全面概述了经济学博士在科技公司的工作。

如何准备

我们(传统培养的经济学博士)需要赶上的两件事是机器学习和编码(python,数据结构和算法)。有许多关于这些的在线资源。《统计学习简介(ISLR)这本书是机器学习很好的参考。如果你对以下问题感到满意,那你就对了:

1.什么是偏差-方差权衡?

2.如何处理模型过度拟合?L1 和 L2 正规化的利与弊是什么?

3.写一个 python 代码实现快速排序,说说时间复杂度。

4.编写一个 python 类来实现 K 近邻分类。

5.XGboost 和随机森林有什么区别?

6.使用 SQL 查找每个班级学生成绩的中位数。

我是如何准备的

除了自学之外,我还参加了 Insight Fellowship 计划,该计划有助于创建一个协作学习环境并加快过渡。我向任何想快速过渡到数据科学的人强烈推荐这个项目。你可以从他们的博客特别是这篇文章中获得更全面的信息。他们在旧金山、西雅图、纽约和多伦多都有项目,而且发展很快!

关于医疗保健中机器学习的一些思考

原文:https://towardsdatascience.com/some-thoughts-on-machine-learning-in-healthcare-e1cef9cec3cc?source=collection_archive---------8-----------------------

我最近在 USSOCOM 做了一个关于医疗保健中的机器学习(ML)的演讲,我想发表它以获得反馈。在 ML 任务中,找到合适的 ML 工具来克服问题和找到合适的问题来解决是不同的挑战。跨学科团队可以最好地克服这些挑战。这个博客仅限于我自己的经历,但就我的职业生涯跨越不同领域而言(协调学术 ML 研究小组,帮助深度学习初创公司,研究医学,研究商业,并在演讲系列中采访许多 ML 先驱),我希望它带来一个广阔的视角。我可以在每个要点的基础上进行构建,并且会根据读者的反馈进行构建。

ML 在医疗保健领域的前景怎么强调都不为过。在众多承诺中,我将着重谈几个:

  • 我们可以改变我们对健康的看法。被动、主动的预防医学体系让位于前瞻性预测医学和被动健康监测。
  • 我们可以改变患有罕见疾病的人的生活,他们中的许多人花了十年或更长时间才得到正确的诊断,这不是因为临床医生从未听说过他们的疾病,而是因为他们在实践中从未见过它。
  • 在过去的 20 年里,我们已经有了大量的临床证据,而且增长速度还在继续加快。我们正在达到一个饱和点,我们可以教人们如何遵循这些东西,即使在我离开医学的几年里,我教育的大部分领域已经过时了。ML 既可以帮助监测大量潜在信号,也可以整合最新信息,无论是来自新的临床研究还是新疾病爆发时的实时信息。

也就是说,医疗改革的步伐可能会让你失望。

  • 发达国家医疗保健的激励结构是围绕下行最小化而不是上行最大化建立的。我们对临床医生的错误惩罚过度,而对他们的成功奖励过度,随着我们转向基于价值的模式,这些支出的相对规模不会发生实质性变化。因此,护理者通过尝试新的东西(尤其是新的和未经证实的)通常会获得很少或没有收获,而由于偏离护理标准而遭受重大损失。
  • 我相信这就是为什么医疗保健组织倾向于不承担风险,即使给他们一些余地。以加拿大的医疗体系为例,该体系向各省提供整体拨款。这种模式的好处之一是,各省可以试验如何实施医疗保健系统,并随着时间的推移相互学习。在实践中,试验从未体现过(相反,各省实施了类似的模式,并大多通过削减资金的传统政策机制来节省资金)。即使有一些力量推动医疗保健系统进行创新,这些结构内的激励因素(医疗保健工作者的职业价值观,谁得到晋升,谁受到惩罚)和围绕这些结构的激励因素(医疗事故侵权,对糟糕的医疗保健结果的负面公众反应)导致系统向平均值收敛。
  • 第二,从医学的角度来说,照顾他人是“奇怪的”,而其他关系却不是。我们将这种怪异的关系正常化,将关怀行为纳入仪式中。围绕护理者的仪式在不同的民族和不同的时间有所不同,但护理总是仪式化的。我认为这是人类的需要。目前对这些仪式性角色的广泛需求将减缓医疗保健的根本变化。
  • 顺便说一下,面向病人的医疗保健技术应该专注于创造这种治愈感。在吸引用户方面,创造这种治愈感可能比拥有功效更重要。看看被揭穿的补品的持久流行就知道了。
  • 对于 ML 来说,转变医疗保健存在严重的技术障碍,尽管这些障碍并不是医疗保健所独有的。一些公司已经封存了大量潜在数据。很多数据都没有结构化。这种非结构化数据的保真度不是很高——一些人可能拥有完整的信息,另一些人可能没有,并且报告的信息可能会因观察者之间的差异而受到不可接受的影响。
  • 以我的经验来看,在回答问题的 ML 从业者和提出这些问题的护理者之间仍然有很大的差距。我认为这部分是由于各种类型的护理人员在培训中很少接触 ML,这反过来使得 ML 研究人员更难从该领域找到合适的合作者。

如果我是一个投资者,这些将是我的论点:

  • 在医疗保健的所有领域中,ML 将在未来五年对网络安全产生最显著的影响。我们已经看到对医院的网络攻击快速增长,越来越多地涉及影响患者护理和安全的勒索软件。政府对患者数据安全的重视程度非常苛刻。我预计政府将授权医院投资更好的网络安全技术。作为前兆,联邦调查局刚刚向医院发出了另一份私人行业通知(PIN ),警告他们存在网络漏洞。如果这对于政府来说是一个足够重要的优先事项,那么这将是一个要求,同时为组织购买新系统提供资金。我怀疑基于 ML 的网络安全解决方案将最适合捕捉这一价值。
  • 供应链创新将有望对医院产生重大影响。许多在医院工作的人花费他们的时间来帮助材料流向正确的位置(例如,保持手术室供应的网络,护士一天多次给所有病人分发他们的药物)。除了无人驾驶汽车,我们正在进入一个更加无人驾驶的时代。
  • 发展中国家将超越发达国家。在世界上的许多地方,医疗保健有一个主要的上行最大化组件。尽管我们必须在“全新护理或当前标准护理”之间做出选择,但许多人被迫选择“全新护理或不护理”,因为他们无法用现有资源满足医疗保健需求。世界上的其他地方是风险厌恶型的,技术人才是流动的,ML 的现成实现对于解决主要的医疗保健需求来说已经足够好了。求解均衡。

关于 Coursera 深度学习专业化的几点思考

原文:https://towardsdatascience.com/some-thoughts-on-the-coursera-deep-learning-specialization-e4de77f15b65?source=collection_archive---------4-----------------------

最近完成了 Coursera 上的深度学习专精。这个专业要求你参加一系列的五门课程。我想这让我有点像独角兽,因为我不仅完成了的一门 MOOC,还完成了的五门相关课程。

所以,我想分享一下我的想法。但是,我不想把这篇文章正式地当成一件事,所以把它当成一些未经修饰的思考:

  • 你学习的东西的种类;
  • 你做的事情的种类;而且,
  • 49 美元/月,值得吗?

放弃

但是,首先:我可能不是这个专业的目标受众。因此,您的里程可能会有所不同。这门课程似乎是面向那些拥有计算机背景、希望在“深度学习”领域获得一份行业工作的人。我不是那样的。我有博士学位,并且是排名前十的计算机科学系的终身教职教师。我获得这个证书并不是为了推进我的职业生涯或者进入这个领域。相反,我参加了这一系列课程,方便地排序为“专业化”,从一个显然在吴恩达对深度学习了解很多的人那里学习更多关于深度学习的知识。

“为什么?”你可能会问。第一,能够聪明地谈论和思考似乎是一件有用的事情——几乎每个计算机科学部门都在试图雇用从事人工智能/人工智能/深度学习的人,你真的无法逃避关于它的对话。二、因为刻意练习。三,因为我也想一年被引用 12000 次,因为我写了一些关于深度学习的东西。

总之。

你学到的东西的种类

专业化的第一门课程提供了对神经网络如何工作的基本的、表层的理解,以及我们如何和为什么使它们深入。Andrew 将会谈到为什么你应该深入学习,尽管你可能已经想这么做了,因为你正在学习这门课程。他把人工智能比作电。呃…

我发现第一门课的技术内容足够深入(没有双关语的意思)。Andrew 很好地传达了深层微积分背后的直觉——他详细到足以让你思考:“是的,我明白。我可以做到。我不想这么做,但我肯定能做到。”

第二道和第三道菜更元。他们:指导你如何有效地构建机器学习项目(例如,你应该将多少数据放入训练/开发/测试集?);诊断您的模型的问题(例如,它是一个偏见问题吗?方差问题?两者都有?您需要更多数据还是不同的架构?);并且,教你可以用来解决这些问题的策略(例如,什么时候使用什么优化器,如何初始化权重矩阵)。

第四和第五门课程是最酷的:它们教你卷积神经网络和递归神经网络,并带你了解计算机视觉、人脸识别、图像字幕、自然语言处理、音乐生成、神经风格转换等方面的前沿架构。在你做这些之前,你肯定需要学第一门课,但是你可以…也许跳过第二和第三门课。我不推荐,但是如果你很急,我又不是你爸。做你想做的。

总的来说,我认为这门课程的知识性内容是学术和应用知识的完美结合。他谈到了具体学术论文背后的见解和直觉,还谈到了像矢量化这样的实际实现细节。

你做的事情

我欣赏专业化的一点是,它不仅仅是讲座和测验:有实际的编程任务,你实际上可以对深度神经网络进行编程。当然,有很多自举——他们不只是让你前进和随机梯度下降。相反,所有的作业都在 Jupyter 的笔记本上做了注释,相关的理论信息在你要写的代码上方的单元格块中被很好地格式化了。

此外,因为有五门课程,所以进度很快。这些任务开始时相当简单——用 numpy 旋转一些向量和数组来实现单个神经元向前传递的一次迭代。在课程结束时,您将使用 Keras 等更高级的深度学习编程框架来实现实际的深度神经网络,该网络可以识别面部表情并生成(糟糕的)莎士比亚十四行诗。

49 美元/月,值得吗?

这是一个复杂的问题,取决于你期望从课程中得到什么。49 美元/月已经很多了。大概有 5 个网飞会员——或者大约 50 个网飞用户。所以,是的,尽管我对这个课程总体上是积极的,但我不认为我能明确地说答案是肯定的。

首先,我个人认为:

我喜欢这种专业化,并认为这是值得的,因为信息的组织方式最大限度地增加了我搜索的可能性。仅仅通过阅读大量免费提供的公共领域知识,我可能就能更便宜、更快、更有效地学到我在那门课程中学到的一切。但是,我不得不投入更多的前期工作,这需要时间,反过来,这可能意味着我永远不会这样做,因为没有人有时间。

有了这个专业,我知道什么是我知道的,什么是我不知道的,如果我想的话,大概知道如何让后者成为前者。我还可以与比我了解深度学习的人(例如,所有 ML/AI 教员候选人)进行关于深度学习的大致可理解的对话,并非常得意地评判所有了解较少的人。这门课程也让我大致了解了该领域的最新进展,现在我对如何将它应用到我自己的研究中有了很好的理解。

所以,对我来说是值得的。

但这句话出自一个人之口,这个人很幸运,有多余的钱,而且并不渴望这门课程能让我进入一个新的领域,帮我找到一份新工作。

如果你想进入深度学习领域,并在人工智能的某个高端领域找到一份工作,我认为 49 美元/月是一种相对便宜的方式,可以让你在简历上显示出你了解深度学习。课程结束时,你会获得一份证书,可以放在你的 LinkedIn 个人资料上。我不确定那个证书是否有用。

只是为了得到一些非常不科学的实证数据,就在一个多星期前,我把证书添加到了我的 LinkedIn 个人资料中。根据提供给非 LinkedIn 专业会员的非常粗略的指标,我注意到我的 LinkedIn 个人资料每周被查看的次数略有增加(显然,比前一周增加了 25%)。此外,第二个最受欢迎的搜索是“Python +统计学+机器学习+数据科学”,第三个最受欢迎的是“计算机视觉”。不过要记住,我之前在 LinkedIn 上被推荐过“python”、“机器学习”和“数据科学”。但是,我对计算机视觉没有兴趣。所以,你想怎么做就怎么做。

如果你现在就想深入学习某个特定的项目,那么这门课程对你来说可能太慢了。有许多免费的在线教程,介绍如何将带有预训练权重的高级深度学习框架用于许多开箱即用的应用(如面部识别和语音合成)。

如果你有更多的时间投资于深度学习的理论基础,并希望在完成课程后成为一名有效的深度学习者,那么…你可能会失望。还记得我说过的作业是强自举的吗?这有助于减少你不得不花在作业上的时间,但也使你很难轻松地将知识转移到课程之外。

在过去的一周左右,我个人一直在做一个兼职项目,它比我想象的要困难得多。不要误解我,很多知识肯定是可以转移的。但是,我必须阅读大量的文档并搜索大量的代码示例,然后才能做任何与我在课程中所做的相近的事情。哦,在课程结束后,他们会收回他们为作业提供的笔记本,所以你不可能回去重新学习你做过的事情。(如果您参加了本课程,您可能应该保存这些笔记本以供以后参考)。

所以:不好意思,值不值得我无法回答。这不是一个明确的“是”——这取决于你的目标、时间限制和可支配收入。不过,希望这篇评论至少给你一个权衡利弊的起点。

现在,像老板一样走下去。

机器学习/数据科学入门问答

原文:https://towardsdatascience.com/some-useful-advice-and-q-a-for-machine-learning-data-science-starters-part-i-54f8abd531d5?source=collection_archive---------3-----------------------

我们讨论了一些对机器学习/数据科学“初学者”有用的建议和问答。我们涵盖了开启旅程所需的关键书籍、课程、基础知识、数学和编程工具。

在获得电子工程博士学位后,我在 R&D 做了 8 年的工程师。我在半导体设备领域工作,仅在过去一年左右的时间里,我才开始学习和实践机器学习(ML)和相关的数据科学(DS)概念和技术。

除了参加许多在线 mooc建立我的 GitHub repos 之外,我还花时间在 Medium 上写了一些关于数据科学和机器学习主题的文章。他们中的一些人得到了很好的回应,并激发了有趣的讨论。在这段时间里,我的许多来自类似技术背景的朋友都问我是如何继续学习的,以及我专注于哪些方面来学习必不可少的 ML/DS 概念。此外,我在我参加的一些社交媒体论坛上默默地观察了数百个这样的问题。在我的个人收件箱中,我收到了来自完全陌生的人的电子邮件,他们讨论我的 Github 代码的问题,或者在作为一名机械工程师辛苦工作一整天后,寻求如何管理时间学习数据科学的技巧!

作为回应,我试着列出迄今为止在我的旅程中我所拥有并发现有价值的最重要的见解。当然,对于一个有经验的从业者来说,这些可能看起来很平常。但是,我的目标是给像我这样的初学者一些入门的思路。与此同时,我会试着写下我从朋友和陌生人的收件箱中收到的一些经常重复的问题的答案。

这将是高度偏向以我自己的经验。而且没有方差因为样本集只包含一个心智——我的:)因此,如果你继续读下去,请应用一个合适的过滤器(卷积与否),然后放上最终的分类标签:-)

初学者的一般问答

“我 是计算机科学/工程专业的学生。我如何进入机器学习/深度学习/人工智能领域?”

—你很幸运。当我还是学生的时候,这个领域仍然有点“冷”,我从来没有听说过:(不管你的主要研究领域是什么,你都可以阅读和获得关于机器学习的知识。请不要仅仅因为有人在网上滔滔不绝地谈论或者你在你朋友的 LinkedIn 个人资料上看到证书,就直接去 Coursera 注册 Ng 教授的课程。

  1. 从 YouTube 上一些很酷的视频开始。读几本好书或文章。例如,你读过《大师算法:对终极学习机的追求将如何重塑我们的世界》吗?而且我敢保证你会爱上这个很酷的关于机器学习的互动页面?
  2. 先学会明确区分流行语— 机器学习、人工智能、深度学习、数据科学、计算机视觉、机器人学。阅读或听专家们关于每一个问题的演讲。观看 Brandon Rohrer 的精彩视频,他是一位有影响力的数据科学家。或者这个关于数据科学相关的各种角色的清晰定义和区别的视频。
  3. 明确你想学什么的目标。然后,去上 Coursera 课程。在开始学习这门课程之前,确保你已经熟悉了 MATLAB,并且知道如何做矩阵乘法。或者考华盛顿大学的另一个也不错。请不要在学习基础课程之前学习 deeplearning.ai 课程。
  4. 关注一些好的博客 : KDnuggetsMark Meloon 关于数据科学生涯的博客Brandon Rohrer 的博客打开 AI 关于他们研究的博客
  5. 如果你已经开始学习和实践机器学习,但对自己的理解没有信心,你可以尝试 Simplilearn 的这个 12 个重要的机器学习面试问题 指南,调整你的学习指南针。
  6. 最重要的是,培养对它的感觉。加入一些好的社交论坛,但是抵制住诱惑,不去关注耸人听闻的标题和发布的新闻。做你自己的阅读,了解它是什么和不是什么,它可能去哪里,它可以打开什么可能性。然后坐下来思考如何应用机器学习或将数据科学原理融入日常工作。构建一个简单的回归模型来预测您下一顿午餐的成本,或者从您的能源提供商那里下载您的用电数据,并在 Excel 中绘制一个简单的时间序列图来发现一些使用模式。 如果能下到那种个人水平,那么恋情自然有保障 。当你完全迷上机器学习后,你可以看这个视频

“W有哪些关于 AI/机器学习/深度学习的好书可以看?”

—这个问题似乎有很多可靠的答案。我不会把我自己的偏见堆积起来,而是倾向于给你一些显示最有用的精选收藏的顶级链接,

  1. 10 本机器学习和数据科学的免费必读书籍作者马修·梅奥
  2. 关于机器学习和人工智能的初学者必读书籍 —作者 AnalyticsVidhya。
  3. 这个牛逼的 GitHub 回购
  4. 来自 machinelearningmastery.com 的各层次从业者的可靠指南。

"N 现在告诉我一些最适合初学者的在线课程"

—同样,几个链接和一些建议。首先是链接,

  1. 顶级机器学习 MOOCs 和在线讲座:综合调查。
  2. 为机器学习和数据科学选择有效课程的 15 分钟指南
  3. 最好的机器学习课程——班级中央职业指导

建议是,只有你才能通过这些 MOOCs 决定正确的学习顺序和速度。有些人非常喜欢上在线课程,并能保持足够的动力去下载所有的编程材料并练习它们。有些人充满热情,但无法在网上视频讲座中保持清醒。介于两者之间的还有很多。作为一个初学者,你可以从在线课程中获得大量的知识并建立坚实的基础,但你必须掌握它们的节奏并正确地接近它们。

“OK,那么你上网络课程有什么特别的小技巧?付费课程/证书值得吗?”

  1. 研究最佳课程的精选列表(如上),并全部参观。应该不会花你什么钱。列出要求和难度,以及所涵盖主题的广度
  2. 永远为你想学的东西保留一份个人路线图。它应该几乎像一个时间序列,即在确定的时间点要实现的明确目标。
  3. 戴上数据科学家的帽子,尝试用这个时间序列来适应课程。它是否与你想要在不久的将来获得的有价值的概念和工具相匹配,即教给你这些概念和工具?它是否深入到了您已经知道但想要进一步完善的框架和专业领域?根据课程的实用性和你的个人需求给课程打分。
  4. 列出一个季度的前 5 门课程。我发现用季度来思考很有用。
  5. 现在,寻找成本的影响,阅读前 5 名学生的评论。尽量快速判断哪个评论者的个人情况最像你,并给那个评论高度加权。
  6. 我大部分时间都参加了旁听课程/自由选择课程。我只为课程/证书付费,我认为这些课程/证书会提高我在这个领域的可信度。测验并不重要,但编程作业/笔记本很重要。大多数被审核的课程会让你免费下载笔记本。这就是你所需要的。相信我,如果你认真努力,你可以把这些笔记本做得比老师提供的版本好得多。
  7. 如果你有一定的开支预算,我建议你去找当地提供证书的大学或者有课堂选择的训练营课程。这也适用于职业人士,因为他们大多在晚上或周末投递。只有当你从 it 部门获得高度可信的证书时才花钱——最好是从好的大学附属夏令营或项目中获得。
  8. 如果你需要从头开始温习编程语言技能,Udemy 上几乎没有专注且节奏轻松的课程。一般来说,这些课程旨在用您选择的语言教授您编程的基本知识,而没有更深层次主题的负担。我发现,Coursera 或 edX 课程大多由学术研究人员提供,最适合于主题学习,而不是作为编程 101。另一方面,Udemy 课程非常适合复习基础知识。等待 Udemy 的 10 美元优惠活动(他们几乎每个月都有),然后打包购买这些课程。我特别喜欢何塞·马西亚尔·波尔蒂利亚的关于 Python、R、SQL 和 Apache Spark 的课程。
  9. 互联网是一所大学,图书馆也是一所大学。根据你的需要考虑和利用任何在线资源——整体的或零碎的。如果你对 Gits 一无所知,可以找一些关于 Gits 的短期课程。如果你需要了解一门特定语言的快速网页清理技术,只需观看一门更大课程的讲座。如果你真的认为基本的数据结构是神秘的,那就去参加大一计算机科学课程吧。哈瓦德的 CS50 就是一个很优秀的。或者甚至有一个为商务人士设计的版本有着不同的味道。

抄袭托尔斯泰却反其道而行之,“每一个坏的过程都是相似的,每一个伟大的过程都有其独特的伟大之处 ”。培养发现顶级课程伟大之处的眼光。

“So、开启旅程需要哪些绝对的基岩知识?”

——除了学习新事物的好奇心和为之努力的热情,什么都没有。你必须获得知识,实践,并在过程中内化概念。但即便如此,结构化学习方法还是有一些基本要点。同样,这是我个人的经验,因此需要根据你的个人情况和目标进行彻底的重新调整。

By Camelia.boban (Own work), via Wikimedia Commons

  • 用数字让自己适应数据和模式。并接受数据可能来自任何类型的信号或来源的事实——电子表格财务、银行交易、广告点击、医院病历、可穿戴电子设备、亚马逊 echo、工厂装配线、客户调查。因此,它们可能是混乱的、不完整的和难以解读的,学习如何耐心和聪明地处理它们对于以后构建伟大的模型是有用的。这不是一门硬知识,而是一种才能。
  • 你应该对高中水平的数学非常非常熟悉,包括基础微积分。这里有一篇关于它的文章。具体来说,关于多元函数、线性代数、导数和图形的概念应该是清楚的。

  • 熟记基本统计学原理。大多数(如果不是全部的话)经典机器学习只不过是用计算机编程和优化技术的接口包装起来的合理的统计建模。深度学习是一个不同的领域,与之相关的理论仍在积极开发中。然而,如果你对基础统计学有扎实的掌握,你就离成为一名优秀的机器学习实践者还有很长的路要走。这是一本优秀的免费在线书籍。或者说,加州大学圣地亚哥分校的这门课程确实以一种有趣的方式确定了基础知识。或者,如果你喜欢看有趣的 YouTube 视频,你可以试试这个频道

  • 熟悉至少一种高级编程语言是有用的。因为,除非你是机器学习领域的博士研究员,致力于一些复杂算法的纯理论证明,否则你应该主要使用现有的机器学习算法,将它们应用于解决新问题,并基于这些技术创建酷的预测模型。这需要戴上编程的帽子。虽然没什么特别的需要。仅仅是对特定语言的语法、变量、数据结构、条件、函数和类定义的基本熟悉。关于“数据科学的最佳语言”有大量的争论和积极的讨论。当争论激烈进行时,拿起你的咖啡,阅读这篇有见地的文章来获得一个想法,看看你的选择。或者,在 KDnuggets 上查看这篇文章。

  • 学习 Jupyter 基础 。对于数据科学家来说,这是一个非常棒的编程和实验工具。不仅要学习如何编码,还要学习如何使用 Jupyter 编写完整的技术文档或报告,包括图像、降价、LaTex 格式等。这是我根据 markdown 功能整理的 Github 笔记本。请记住,Jupyter 项目最初是 IPython 的一个分支,但后来发展成为一个成熟的开发平台,支持您能想到的任何数量的编程语言。

  • 熟悉 Linux/命令行界面、git 和堆栈交换对于您开始实际实现非常有帮助。令人惊讶的是,这比听起来要难。特别是,对于像我一样的许多工作专业人士来说,使用基于 Windows 或 Mac 的企业级工具已经成为一种根深蒂固的天性。对于软件工具的技术帮助,我们期望弹出一个闪亮的小电子手册。注册一个账号,在 Stack 论坛上发布一个框架良好的问题,对我们来说太多了。但是尽早学习它们,并且拥抱开源文化。你会发现,甚至在你在 stack overllow:)上打完你的问题之前,整个世界都渴望解决你的问题,你还会惊喜地发现,安装一个强大的软件库并不像那些极客让你相信的那样令人生畏。就像“ pip 安装… ”一样简单

第一部分到此为止。在第二部分中,我希望涵盖另外两个方面最重要的问答,

  • 一些对初学者有用的关键机器学习/统计建模概念,
  • 其他非常需要的技能,如在社交/专业平台上引人注目,以及定期关注构建材料。

如果您有任何问题或想法要分享,请通过tirthajyoti【AT】Gmail . com联系作者。你也可以查看作者的 GitHub 资源库 中其他有趣的 Python、R 或 MATLAB 代码片段和机器学习资源。如果你像我一样,对机器学习/数据科学/半导体充满热情,请随时在 LinkedIn 上添加我在 Twitter 上关注我。

从无到有:GANs 的进展如何?

原文:https://towardsdatascience.com/something-from-nothing-where-are-we-at-with-gans-18bdccc3af17?source=collection_archive---------6-----------------------

克洛伊·布莱斯维特

早在 2014 年,Ian Goodfellow 就向我们介绍了生成式对抗网络,简称 GAN,这是一种可以在无人监督的情况下工作的深度机器学习。Yoshua Bengio 与 Goodfellow 一起编写了深度学习教材。

“为了让计算机变得智能,它们需要拥有知识。但问题是他们从哪里获得这些知识?”蒙特利尔大学蒙特利尔学习算法研究所(MILA)所长 Yoshua Bengio 教授问道。

“以前,研究人员试图直接传授知识。这是经典的人工智能,我们告诉计算机事实和规则,但不幸的是,我们知道的许多事情是不可传达的,它们是直觉的。”

本质上,有些事情我们知道,但不能,或者就是不解释。

“我们在过去几年取得的进展非常惊人,但这主要是基于监督学习,即人类告诉计算机如何解释图像、声音或文本。我们认为,我们现在所做的这种学习有一些局限性,人类能够应对。”

问题是如何让计算机在无人监督的情况下学习,而不是硬编码事实和数字。

“我们不想告诉计算机解释(某些)数据的基本概念是什么。”

本吉奥强调,他不确定最佳的前进方式是什么,他高兴地承认,开发自主学习人工智能可能有多种方式。这种清晰路径的缺乏导致了许多创新,GANs 在生成性学习领域处于领先地位。

“检验计算机是否理解我们输入的数据的一种方法是,让计算机生成应该来自同一分布的新示例。”

例如,也许一个程序已经看到了成千上万张不同的新面孔的图像。为了查看计算机是否理解了这组训练图像,程序员可以请求计算机根据数据集生成一张全新的、完全新奇的脸。这项任务比看起来更难,因为“自然”图像与计算机生成的图像非常不同。

多年来,机器学习中出现了许多生成模型,但生成对抗网络的成功来自于它们的对抗性。

“GANs 与传统的机器学习非常不同。我们有这两个网络,生成器和鉴别器,它们中的每一个实际上都在优化一个不同的东西,所以使一个表现良好的东西会使另一个变得更差。”

“gan 以及许多具有潜在空间和内部表示的生成网络的一个优点是,我们实际上可以玩表示,并在表示之间进行插值,或从表示中进行加减。

“我们观察到的第一件事是训练 GAN 可能不稳定。有时候,训练进行得很顺利,你可以看到生成的图像越来越好,但突然间,事情变得糟糕起来,训练目标开始以奇怪的方式前进。”

这种不稳定性的主要原因与它作为一种生成模型如此成功的原因是一样的。

研究人员已经开始面临的其他常见障碍包括模式崩溃,即图像重复多次;缺失模式,没有足够的多样性进入生成的数据集;缺乏明确的质量量化措施。

那么,既然要克服这样的挑战,为什么还要继续研究 GANs 呢?

“嗯,它与以前在机器学习方面所做的事情如此不同,你知道,它可能会在未来给我们带来更好的东西!”

注意:这篇文章是基于本吉奥在 4 月 29 日至 30 日的最佳会议上关于人工智能的演讲。他是一个主题演讲人,这是他第一次与最优秀的人交谈。

歌曲流行度预测器

原文:https://towardsdatascience.com/song-popularity-predictor-1ef69735e380?source=collection_archive---------6-----------------------

Mohamed Nasreldin、Stephen Ma、Eric Dailey、Phuc Dang 的项目

简介

DJ Khaled 大胆宣称总能知道一首歌什么时候会流行。我们决定通过问三个关键问题来进一步调查:热门歌曲是否有某些特征,对一首歌的成功影响最大的因素是什么,以及老歌甚至可以预测新歌的受欢迎程度吗?预测一首歌会有多流行不是一件容易的事。为了回答这些问题,我们利用了哥伦比亚提供的百万首歌曲数据集,Spotify 的 API,以及机器学习预测模型。我们提出了一个模型,可以预测一首歌有多大可能成为热门歌曲,通过将其列入 Billboard 的前 100 名来定义,准确率超过 68%。

背景

2017 年,仅在美国,音乐产业就创造了 87.2 亿美元的收入。由于流媒体服务(Spotify、Apple Music 等)的增长,这个行业继续繁荣发展。流行歌曲获得了大部分收入。2016 年前 10 名艺人总共创造了 3.625 亿美元的收入。关于是什么让一首歌流行的问题在之前已经被研究过,并取得了不同程度的成功。每首歌曲都有关键特征,包括歌词、时长、艺术家信息、温度、节拍、音量、和弦等。先前的研究认为歌词可以预测一首歌的受欢迎程度,但收效甚微。

数据采集&预处理

获取数据

选择的数据集是哥伦比亚大学提供的百万首歌曲数据集,从 Echo Nest 中拉出。我们选择这个数据集是因为它有大量的特征和大小。这个数据集的主要问题是提供的格式。为每首歌曲提供了单独的 h5 文件。提供了一个脚本来将数据集转换为 mat 文件,以便在 matlab 中使用。我们修改了脚本,以便它可以生成一个 csv,我们可以用它来训练我们的模型。数据集也太大了。所有 100 万首歌曲的容量约为 280 GB。谢天谢地,有一个随机选择的子集,只有 10,000 首歌曲。

数据集中的每首歌曲都包含 41 个特征,通过音频分析、艺术家信息和歌曲相关特征进行分类。

音频分析功能:速度,持续时间,模式,响度,关键,拍号,部分开始

艺术家相关特征:艺术家熟悉度、艺术家受欢迎程度、艺术家姓名、艺术家位置

歌曲相关特征:版本,标题,年份,歌曲热度

刮广告牌歌曲

百万首歌曲数据集中的原始数据带有歌曲热度特征。然而,大约有 4500 首歌曲没有这个功能,这几乎是我们使用的子集的一半。因此,我们想找到一种新的方法来分类一首歌是否流行。我们决定使用 BillBoard Top 100 来确定受欢迎程度。如果一首歌至少出现在 100 强排行榜上一次,那么它将被列为热门歌曲。

我们使用 BeautifulSoup 编写 python 脚本来抓取 billboard.com,得到 1958 年到 2012 年出现在排行榜上的所有歌曲。我们停在了 2012 年,因为数据集中最近的歌曲都是在 2012 年发布的。在获得 billboard 上的歌曲列表后,我们回到我们的 10,000 首歌曲数据集,并相应地对它们进行分类。在我们的数据集中的 10,000 首歌曲中,有 1192 首被归类为热门歌曲。

清洗数据集

由于旧的不推荐使用的数据,数据集中的许多字段不可用。许多数据字段丢失,并且没有 echonest API 来填充数据,因为 API 被 Spotify 修改了。因此,许多领域不得不放弃。有些要素只缺少合理的数量,我们决定用平均值来填充缺少的值。一个例子是艺术家熟悉度字段,它只有 10 个缺失值。

艺术家 ID 和模式这两个要素被修改,以更好地反映它们在数据集中的属性。数据中的每个艺术家都由一个字符串唯一标识,所以我们决定对他们进行标签编码。调式是歌曲在制作过程中使用大调还是小调。虽然这个值很简单,0 表示次要,1 表示主要,但是还有一个名为 mode_confidence 的值,它描述了所选模式准确的概率。有了这两个值,我们组合了从-1(小调)到 1(大调)的特性。值-1 表示 100%确信该键是次要的,1 表示 100%确信该键是主要的。小调的置信度范围在-1 和 0 之间,大调的置信度范围在 0 和 1 之间。这大大增加了这个值的重要性,我们将在下一节看到。

该过程可以总结如下:

  1. 从 labrosa Columbia 下载数据子集
  2. 将数据格式从 h5 转换为数据帧
  3. 刮掉出现在排行榜前 100 名歌曲
  4. 数据中的分类歌曲
  5. 清理数据集

数据探索

在收集数据并对其进行清理以供使用后,我们通过研究特征的重要性、数据集中的趋势以及确定这些特征的最佳值,继续进行数据探索。

特征重要性

在这里,我们可以看到最终数据集中每个要素的 f1 值。我们在这里可以看到一个有趣的趋势,即歌曲的实际音乐方面与艺术家信息合理地纠缠在一起。诸如速度、模式和响度之类的技术特征与诸如熟悉度、热度和辨识度之类的艺术家信息一样重要。

艺人熟悉度

艺人熟悉度与歌曲热度

正如我们所料,艺术家的熟悉程度与热度值相关。Y 轴是根据歌曲热度 Y,其中 0 是最低分,1 是最高分。熟悉度在 x 轴上,范围也是从 0 到 1,根据 Echo Nest 的算法描述艺术家的“熟悉”程度。当这个值接近 1 时,歌曲的热度也接近 1(谁能想到呢?).

艺人位置

艺人经度 vs 歌曲热度

我们也可以在上面的图表中看到一些有趣的趋势。虽然通常在也产生点击的区域中有更多的活动,但是我们可以看到点击集中在这些特定的区域。大多数活动来自世界的西部,在北美,我们也可以看到东海岸和西海岸之间的分界线。因此,我们可以期待模型使用这一点来预测一首歌是否是热门歌曲。

速度和持续时间

我们对热门歌曲的分布感兴趣,所以我们隔离了热度值为 1 的所有歌曲,并绘制了这些歌曲的不同特征的分布。我们可以看到,热门歌曲通常使用的节奏有一个范围,在这个范围内有两个峰值,分别为 100 bpm 和 135 bpm。热门歌曲的时长平均在 200 秒左右,一般在 3 到 4 分钟之间。

Optimal values for key selected features

对于登上 Billboard 前 100 名的歌曲,我们研究了之前使用 f1 评分检测到的一些顶级特征的平均值和标准偏差,结果相当合理。节奏约为 122 bpm,标准偏差为 33 bpm,艺术家熟悉度为 61%,标准偏差为 16%,大多数歌曲都是大调,但标准偏差相当大,响度约为-10 dB,艺术家热度约为 0.43。艺术家信息显示,这些艺术家中的大多数都是“昙花一现”,因为他们缺乏热情和熟悉度。

模式选择&调谐

我们在不同的模型上训练我们的数据来预测一首歌是否是热门歌曲。在调整之前,Xgboost 在 0.63 曲线下面积(AUC)分数处似乎是具有最高准确度的。下表显示了我们尝试的一些模型的结果。

Models considered and their AUC scores

在 XGBoost 上进行网格搜索以进一步提高 AUC 分数。每个参数都进行了调整,一些值同时被过度调整。例如,n 估计值和学习率被一起调整,因为较高的 n 估计值需要较低的学习率来产生最佳结果。调整后 AUC 值从 0.632 增加到 0.68。随机预测将产生 0.5 的 AUC 分数。

结果

这个项目展示了预测音乐热度的可能性,确定了流行音乐的趋势,并使用 Spotify 的 API 开发了特征提取工具。XGBoost 在训练模型上提供了最佳预测,AUC 得分为 0.68。

我们决定用我们的模型预测一些新歌。下面的演示展示了我们的脚本的运行。

自从 Spotify 收购 EchoNest 以来,许多不同的功能都发生了变化,包括通过 ID 查找歌曲信息的简单方法。因此,这个演示使用了一种非常迂回的方式来获取歌曲信息。首先,使用 API 上的搜索端点运行搜索,以获取 Spotify ID。使用 Spotify ID 音频功能和深入的音频分析,可以抓取歌曲。然后进行一些功能工程,以便将 Spotify 数据转换回可用于我们模型的格式。我们开发的用于将 Spotify API 数据映射到我们的训练数据的脚本可以在这里查看。

以下是我们的模型预测的其他一些歌曲的结果,以及与 Spotify hotness 结果进行比较的结果:

结论

在这项工作中,我们不确定是否有可能比随机预测更好地预测一首歌是否会流行。在对来自 Spotify 的新歌测试我们的模型后,我们观察到正确预测一首坏歌比预测一首热门歌曲简单得多。预测非热门歌曲可能更容易,因为我们的数据是倾斜的,只有 1200 首热门歌曲。接下来,我们将探讨艺术家所在地或发行日期等其他特征如何影响歌曲的受欢迎程度。此外,我们可以考虑使用完整的数据集,看看是否可以改进我们的模型。另一种选择是使用 Spotify API 来收集我们自己的数据。

虽然 DJ Khaled 没有配备强大的数据科学和机器学习工具,但他是正确的,热门歌曲中确实存在某些趋势。

完整源代码可以在这里查看

你迟早会面临这个问题

原文:https://towardsdatascience.com/soon-or-later-you-will-face-this-problem-c5f204e9f55a?source=collection_archive---------3-----------------------

source: kaggle

几天前在 kaggle 举办的梅赛德斯-奔驰比赛结束了,这场比赛是我经历过的最艰难的比赛之一(我并不孤单),在这篇文章中我将解释为什么,并分享一些我们可以从中吸取的教训。这篇文章旨在简短,我写这篇文章是为了与你分享我的团队在这场比赛中的经验,解释为什么解决呈现给我们的问题仍然被认为是一个困难的问题,并列出一些你在解决一个兼职项目或在一家公司工作的机器学习问题时可能会遇到的问题。

是什么让奔驰竞争如此艰难?

首先让我向你介绍来自戴姆勒的任务,当这个比赛开始时,它带来了这个问题:

你能减少一辆奔驰花在测试台上的时间吗?

关于这项任务,还有一点更有趣的信息:

“在这场比赛中,戴姆勒向卡格勒挑战,以解决维数灾难并减少汽车在测试台上花费的时间。竞争对手将使用代表梅赛德斯-奔驰汽车功能不同排列的数据集来预测通过测试所需的时间。获胜的算法将有助于加快测试速度,从而在不降低戴姆勒标准的情况下降低二氧化碳排放。”

解决这个问题的方法是把它当作回归问题,给定特征建立模型来预测 y(测试时间)。

在数据科学项目中,有许多事情可能会出错,但以下是许多竞争对手发现的常见问题,在就解决该问题的最佳方法展开公开讨论之前,以下是这场比赛为何具有传奇色彩的原因:

  • 小数据集和许多要素
  • 极端值
  • 敏感指标
  • CV 和 LB 不一致

(1).小数据集和许多要素

每当你想要解决任何机器学习问题时,大多数时候,最理想的做法是首先寻找将帮助你训练模型的数据(数据收集或收集)。但有时你找不到你想要的具体数据,或者你找不到足够的数据,这是一个行业直到今天仍然面临的问题。在 Mercedes Benz 数据集中,训练数据由 3209 个训练示例和 300 多个特征组成(8 个分类特征,其余为数字特征),您可能会猜测从如此少的数据中构建强大的机器学习模型具有挑战性。

但是如果我们没有足够的数据会怎么样呢?

当我们没有足够的数据时,我们的模型很可能有很高的方差,这意味着过度拟合变得更加难以避免。

过度适应的悲伤

你永远也不想吃太多。当我们的模型学习到包括噪声数据点(例如离群值)并且这最终未能概括,另一种认为过度拟合的方式是当模型过于复杂时发生,例如相对于观察值的数量有太多的参数。过度拟合的模型具有较差的预测性能,因为它对训练数据中的微小波动反应过度。提交给 kagglers 的数据集导致许多竞争对手过度适应,这就是为什么公共和私人排行榜之间有很大的变化(我不会详细说明这一点,如果你真的想了解公共和私人排行榜之间的差异,请在评论中问我)。

(2).极端值

噪声通常会成为一个问题,无论是在你的目标变量上还是在某些特性上。对于小数据集,离群值变得更加危险和难以处理。离群值很有趣。根据具体情况,它们要么值得特别关注,要么应该被完全忽略。如果数据集包含相当数量的异常值,重要的是要么使用对异常值鲁棒的建模算法,要么过滤掉异常值。谈到梅赛德斯-奔驰绿色制造大赛的比赛,目标变量(y)中有一些异常值,大多数 y 值在 70 到 120 之间,发现像 237 这样的值对我们来说是一个警告。

(3).敏感指标

模型评估用于量化预测的质量,无论何时训练机器学习模型,理想情况下,您都希望选择一个评分指标(用于模型评估),该指标将指导您了解所做的更改是否提高了模型的性能/预测能力。对于分类问题,通常使用准确度、负对数损失和 f1,对于 Kaggle 上的回归问题,通常使用 MSE(均方误差)、MAE(平均绝对误差)或这些指标的一些变体。他们有不同程度的鲁棒性,但在这场比赛中,他们选择了 R,这是一个非常有趣的选择。因为度量太简单了,所以使用传统的 Kaggle 技术,如元集成或深度学习,都是徒劳的。也许我应该写一个关于评估指标和损失函数的帖子?你告诉我。

对于梅赛德斯-奔驰绿色制造竞赛,评分标准与 RMSE 或 MAE 等 Kaggle 竞赛使用的传统标准相反。相比之下,R 是一个非常不稳定的度量,对异常值非常敏感,并且非常容易过度拟合。因为容易过度拟合,所以公排行榜的领袖在私排行榜上摔得那么惨。一个简单的几乎没有特征的模型是概括所选指标的最佳方式,但许多 Kagglers 都很虚荣,宁愿在公共排行榜上看到更高的排名。除了训练数据之外,我们的预测应该基于看不见的数据(测试集),在梅赛德斯-奔驰中也有一些异常值,所以如果对于给定的看不见的实例,我们的模型预测 y = 133,而真实值是 219,R 对我们的模型不利很多(记住,R 是一个非常敏感的度量)。虽然从训练集中移除离群值降低了公共 LB 上的分数,但这是要采取的适当行动,因为它仍然给出了相对于其他的最佳分数。

(4).不一致的 CV

CV =交叉验证。

当我们没有成功地建立一个对你的模型进行适当验证的设置时,就会出现 CV 不一致的问题,这可能会导致你认为你做得很好,而实际上并不是。交叉验证是我所知道的评估机器学习模型的最好方法之一(如果不是最好的话),但是对于小数据集,许多功能和工具甚至交叉验证都可能失败(特别是当使用 R 时)。

如果你不熟悉交叉验证,这份草案可能会帮助你。

使用 K 倍交叉验证的评估程序

5-Fold

  1. 将数据集分成 K 个相等的分区(或“折叠”)。
  2. 将褶皱 1 作为测试集,将其他褶皱的并集作为训练集
  3. 计算测试精度
  4. 重复步骤 2 和 3 K 次,每次使用不同的折叠作为测试设置。
  5. 使用平均测试精度作为样本外精度的估计。

合理的事情要做

在这里,我将尝试提出一些解决方案,如果你面临上面提到的一些问题,你可以使用。有些我的团队用过,有些我们没有。

  • 坚持使用简单的模型:在这次竞赛中,首先使用的算法是基于决策树的模型,在与 Steven 合作后,他告诉我简单的线性模型得分也很高,有时甚至超过了 Random Forest 和 xgboost 等更复杂的模型,这让我感到惊讶。
  • 执行特征选择:这可能是本次比赛中最有价值的事情,数据集包含 300 多个特征,从一些特征的相关矩阵图中(因为有许多特征,所以选择了 15 个特征),相关矩阵帮助我们认识到有许多冗余特征,这是不好的,如果我们将冗余信息添加到我们的模型中,它会一次又一次地学习相同的东西,这没有帮助,只要有可能,我们就想删除冗余特征。

correlation matrix done using seaborn (for plotting) and pandas(for data representation)

  • 使用集成模型:集成方法使用多种学习算法来获得比单独使用任何组成学习算法更好的预测性能。特别是如果你的模型在不同的事情上做得很好(例如:一个擅长分类反面例子,另一个擅长分类正面例子),将两者结合起来通常会产生更好的结果。我们最终的模型是我的模型(大部分是 xgboost)和 Steven 的模型(RF、SVR、GBM、ElasticNet、Lasso 等)的组合。无需深入细节,我可以告诉你的是,结合我们的模型,我们得到了改进。

最终注释

这篇文章并不是我们为梅赛德斯-奔驰绿色制造竞赛准备的解决方案,而是带来一些你在研究新问题或从事数据驱动项目时可能会发现的问题。寻找好的大数据是我们一直想要的,理想情况下,我们希望有至少 50K 训练样本的数据集。这篇文章没有描述完整的解决方案,还有一些细节我省略了。

关于我的团队(🏎本茨🏎)

在这次比赛中,我和史蒂文在 3835 支队伍中名列第 91 位。

Kaggle profile: Steven Nguyen

我特别感谢史蒂文·阮在梅赛德斯-奔驰比赛和我写这篇文章时给予的支持。

进一步阅读

让我知道你对此的想法,如果你有一个主题的建议,你会喜欢看我写的。

和往常一样,如果你喜欢这些作品,请留下你的掌声👏推荐这篇文章,让别人也能看到。

SOPR:公共关系和狙击手思维挑战

原文:https://towardsdatascience.com/sopr-public-relations-and-the-sniper-mind-challenge-c37f7223a849?source=collection_archive---------3-----------------------

公共关系一直被认为是一种与魔鬼的交易,目的是扩大你的营销范围,维护你的声誉。这个行业总是被外人视为编造故事的大师或炒作的兜售者,但 21 世纪“假新闻”的困扰以及社论和 T2 付费媒体之间界限的模糊,对这个行业几乎没有帮助。

媒体的碎片化和公关有时对所有可用渠道发送垃圾信息的盲从,加上对其可信度的挑战,这影响了信任度,产生了一个可能难以解决的多维挑战。

与此相反,由国际公共关系协会在保加利亚索非亚举办的 SOPR 会议和颁奖典礼绝不是一件严肃的事情。我的任务是向来自 27 个国家的与会者讲述“狙击手思维”及其对现代公关专业人士的影响,我概述了当前的形势,并重点讲述了活跃在商界的每个人感受到的差异。

20 分钟很难做多少事。因此,任何演讲者所能希望的是将关键信息传达出去,并希望它能融入听众的感知和他们对问题的意识,从而引发新的思维过程。在这一点上,我并不失望。

公共关系(PR)正在发生变化,这种变化是由专业人士而不是他们的客户主导的。为了理解为什么这很重要,我需要描绘一个更广阔的图景。

一切都是数据。一直都是。当数据传到我们手中的渠道受到限制时,我们对自己认为观察到的现实的感知也受到限制。这使得一切公式化。例如,在 60 年代杰罗姆·麦卡锡(Jerome McCarthy)提出 4Ps 产品、价格和促销之前,市场营销就一直遵循同样的规定性方法。

那些 4p 今天已经被经验、无处不在(或每一个地方)、交换(价值)和传福音的 4e 所取代。

从一种营销口号到另一种营销口号的转变是市场最基本层面——消费者——转变的直接结果。

消费者因技术而赋能,通过设备而联系,比以往任何时候都更知情、更具移动性和更有发言权,他们已经打破了传统的条块分割的孤岛,这种孤岛允许他们通过一对多、自上而下的模式进行营销。他们的注意力和忠诚度要么失去了,要么被共同的价值观、赋予他们生活意义的能力以及在他们需要的时候帮助他们做一些有用的事情的方法所赢得。

所有这些都很重要,因为它是由数据驱动的,这使得一切都可以测量。如果可以衡量,就可以量化,如果可以量化,就可以改进。

在这个极具挑战性的环境中,信任和感知是一切的基础。

信任是任何关系交换发生的必要条件,信任本身由接触、感知、评估、联系这四个步骤组成。

这些步骤中的每一步本身都相对脆弱。谨慎、努力和真实性在实现这一切的过程中起着关键作用。就其本身而言,它们需要意识、明确理解的认同感、共同的价值观和同理心。

感知的出现需要五个组成部分:刺激、注意力识别、翻译、行为,每一部分都与一个特定的、直接相关的属性相关联。

所有这些都很重要,因为它是由数据驱动的,这使得一切都可以测量。如果可以衡量,就可以量化,如果可以量化,就可以改进。

大数据的问题

然而,数据本身并不是没有问题。作为大数据特征的四个向量:数量、速度、多样性和准确性在处理它们时带来了独特的挑战。它们中的每一个都以自己的方式延伸到我们现代分析和理解数据向我们揭示的确切内容的能力的极限。

碰巧的是,并非只有商界感受到了这一挑战。自上世纪 90 年代以来,美国陆军战争学院一直在教导学生,他们现在是在一个由波动性、不确定性、复杂性和模糊性所支配的 VUCA 世界中运作。

对于那些没有立即建立联系的人来说,大数据的 4v 与 VUCA 世界的组成部分完全对应。数据在每个上下文中可能有不同的标签,但它的行为是相同的,因为它响应相同的动态。

公共关系的新角色

这使我们回到 SOPR 会议。现代公共关系专业人士生活在大数据的 4V 世界和军事的 VUCA 世界中,他们被夹在面临危机、需要传播信息并迫切希望让自己的声音被听到的客户和越来越抵制自上而下的广播和宣传的观众之间。

为了适应挑战,这个行业正在发生变化。在我的主题演讲后,我与之交谈的人都非常清楚他们角色的微妙之处。需要温和地引导他们的客户远离谎言,走向真正的交流。他们都非常清楚以一种与其价值观和观念产生共鸣并创造信任的方式与观众建立联系的必要性。

简而言之,他们意识到公共关系正在从简单的传播信息和宣传形象转变为交流共同的价值观和创造客户与受众之间的共同接触点。

当一个对通信至关重要的行业认识到挑战,并开始缓慢的审慎变革过程时,商业乃至政治世界从 20 世纪向 21 世纪的转变就有了真正的希望,比预期的要快得多。

狙击思维:消除恐惧,应对不确定性,做出更好的决定可以在亚马逊或任何书店买到。

你可以在这里阅读样本章节。

原载于davidamerland.com

抱歉,各位!Excel 不是企业报表解决方案

原文:https://towardsdatascience.com/sorry-folks-excel-is-not-an-enterprise-reporting-solution-af6da19d2b81?source=collection_archive---------10-----------------------

我走在数据管理的边缘

在最近的一次会议上,我进行了一次令人沮丧的谈话。我与之交谈的人有一个固执的经理。他幻想自己是 MS Excel 的“超级”用户。

即使有了更好的数据管理工具,他仍然坚持在电子表格中存储大量的数据集和报告。更糟糕的是,他强迫拥有更好技能的员工接受他同样的低标准。

技能低下且固执的经理是罪魁祸首吗?

我的“Excel 受害者”与她的团队有关,可以很容易地避免多少数据问题。一名员工不知道如何正确使用公式,导致多次报告错误的总数。她的失态清单还在继续。大部分原因是缺乏数据知识或对细节的关注,而这是标准报告工具可以轻松克服的。

甚至当我的 Excel 受害者恳求她的经理使用组织内免费提供的更好的数据管理工具来获得自动化和准确的结果时,他拒绝了

相反,他紧紧抓住 MS Excel 不放,好像它是救世主一样——用它作为逃避学习或感到某种程度的控制的借口,甚至在他报告错误结果的时候也是如此!

我翻了个白眼,因为我以为大家都知道 Excel 不是企业报表解决方案。我幻想着给经理打电话开导他。

也许我会因为他不相信员工的建议而责骂他?然后我可以阐明他如何改进他的组织——就在这个月!在我看来,它以悔恨和哭泣的道歉结束。罪犯被抓的时候不都是对不起的吗?

在他们的组织中谁需要一个扩展农场?

我怀疑真正的对话会有不同的结局。许多较小的组织或较大组织中的部门不了解 Excel 的相关问题。它灵活、强大且易于使用。然而,如果你想让一个数据问题变得更糟,给用户 Excel 进行跟踪。突然间,部门里的每个人都必须管理自己的微型数据库。

数据的准确性取决于每个创作者的技能和对细节的关注。

电子表格可以管理某些任务。老实说,这个列表太短了,我可以用 Excel 跟踪它。

如果每个人都有个人数据库,那你怎么知道哪个是真相?办公室里谁对小部件销售或投诉的统计最准确?如果你对某样东西进行累计,那么你如何管理变化?假设你卖出了 1000 件产品,有三分之一被退回。你是如何调查的?如何防止自动求和出现在错误的列中?什么时候数据变得太多而无法管理?谈论重复劳动。你明白了。

将数据放在中心以消除孤岛

当组织开始认真对待数据,并希望将其视为受管理的资产时,乐趣就开始了。作为一名顾问,我目睹了很多“香肠是如何制作的”。当工具实现过程开始时,我参与了从令人信服到筋疲力尽的内部讨论。

一个常见的讨论是“我们如何测量 <空白>”。当个人或部门自主太久,不同的业务规则就会发展。

有时这些商业规则显示出缺乏技巧,并且不是基于真正的商业推理。

“只是不要把 x 计算在内,因为我们并不总是看到关于它的电子邮件。”如果另一个部门发现 x 至关重要或者解决了数据管理问题,那么你就有了一场史诗般的争论。他们所谓的计算是下一个雷区。

看着激情在会议中碰撞并不有趣。但是这些激情必须碰撞!消除孤岛,使组织对目标有一个共同的理解。你无法推动一个支离破碎的组织前进。

寻找更好的解决方案

当大公司认真对待数据管理时,他们会寻找工具来支持这些工作。像 SAS 这样的公司已经从事数据管理工作几十年了。这些工具中的许多都允许从数据源中提取数据,重新调整为可用的格式,然后提供给用户进行可视化和分析。这是真正的数据驱动的企业工具大放异彩的地方。

抱歉,华生,但我没被打动

原文:https://towardsdatascience.com/sorry-watson-but-im-not-impressed-4b07332ec6f9?source=collection_archive---------9-----------------------

当我最喜欢的聊天应用程序(我自己和超过 10 亿其他人都在使用)自己决定何时使用自动完成功能,何时不使用它时,我会对机器学习、人工智能或任何你更喜欢使用的术语印象深刻。目前,它的性能远远没有达到我认为的真正智能,因为它甚至无法判断我在用哪种语言聊天(尽管聊天会话的语言通常取决于我在聊天的人,因此这应该是所谓智能系统的一个可靠提示)。显然,我可以关闭自动完成功能,以避免一种语言中的单词被另一种语言中完全不相关的单词自动完成(就我希望看到它们出现在那里而言),但在某些情况下——例如,当输入 3 个字符后,20 个字符的单词的正确建议出现了——我肯定很乐意使用自动完成功能。

当然,已经有一些基于机器学习的令人印象深刻的表现——比如 IBM 的沃森击败了最好的人类危险游戏选手,或者谷歌的 DeepMind 在棋盘游戏 Go 中获胜。但这些基本上都是只会一招的小马。这些系统在完成一项特定任务时非常强大,但在大多数其他任务中或多或少是无用的。我在某个地方听过一个非常惊人的对比(如果我记得是从谁那里听来的,我会把它归功于作者),那就是一个 9 岁的孩子炫耀从书本中获得的事实知识,但缺乏必要的生活经验来将其用于任何体面的用途。

另一方面,人类的智慧通常表现为在一系列事情上表现优秀。让我感到惊讶的是,向计算机解释(就编程而言)一些大多数人认为相对容易的任务是多么困难。因为我经常使用数据库,所以让我给你举一个这个领域的具体例子:在一个在线购物的数据库中,数据是由客户填写的,你不可避免地会得到一些记录,其中这个人的名字填写在应该包含姓氏的字段中,反之亦然。网上购物者的首要任务是获得他们想要的任何东西,而不是数据库卫生。对于人类来说,大多数名字/姓氏的转换都很容易发现,但是创建一个具有可比水平的计算机算法所需要的努力通常比简单地让人类手动完成要大得多——当然,除非数据库非常大。

这是否意味着我认为一个真正聪明的华生永远不会存在?当然不是,但我也不认为它真的就在眼前。人工智能和机器学习正在取得巨大进展;有趣的事情正在自然语言处理等领域发生;我欢迎所有这些领域的突破。然而今天,我可能还没有被打动。但是对于普通人来说,也需要几年时间才能在很多事情上达到优秀的水平。

为了您的方便,您可以访问 https://janvanhaver.com/

听起来很简单,为什么不是每个人都这么做呢?

原文:https://towardsdatascience.com/sounds-simple-enough-so-why-isnt-everybody-doing-it-9a70764e5d57?source=collection_archive---------4-----------------------

实时。数据驱动。分析。如果数据无处不在,每个人都在使用它,那你为什么没有呢?为什么如此多的组织仍然依赖静态、过时的报告来做出决策?

如今,实时数据似乎无处不在。早间新闻正在分享最新突发事件的观众视频,随着前方交通堵塞,我们早上开车去上班的路线可以在几秒钟内改变,零售商可以在我们了解自己之前预测我们将要购买的东西。在一个完美的世界中,管理层将关注财务状况、运营瓶颈和客户需求变化的实时快照,并能够及时发现新出现的风险,以预防意外事件,而不是对意外事件做出反应并从中恢复。许多公司已经将分析纳入他们的决策过程;那不是分析学吗?概括地说,主要区别如下:

对于许多组织来说,从大型复杂的组织到小型灵活的组织,甚至是我们当中精通技术和分析的公司,真正的障碍仍然存在。细微差别各不相同,但归结起来有三个主要挑战:1)战略投资,2)运营,3)技术。如果没有组织所有级别的支持和正确的实施策略,即使是最好的组织也会失败。那么真正阻碍我们的是什么呢?通常,正是回答类似下面的问题阻止了组织推进分析。

在我接下来的文章中,请关注关于克服这些障碍的想法和技巧。

用 ARIMA 预测西班牙主要经济总量

原文:https://towardsdatascience.com/spains-main-economic-aggregates-forecasted-using-arima-b00e285514d5?source=collection_archive---------12-----------------------

首先,我想对马诺斯·安托尼乌在的这篇文章中分享他对欧元区 GDP 的分析表示由衷的感谢。我受到了它的启发,它促使我复制并扩展他的分析,特别是针对我目前居住的国家,也就是西班牙。如果你没有读过他的文章,我鼓励你去读!

按照他的蓝图,我将利用欧盟统计局数据库中的可用信息做一些时间序列建模和预测。

欧盟统计局数据库是一个神奇的经济统计资料库,可以在线查阅,幸运的是我们也可以直接从 R!

下面是欧盟统计局如何描述他们的方法:

“欧统局的主要作用是处理和发布欧洲层面的可比统计信息。我们试图达成一种包含概念、方法、结构和技术标准的共同统计“语言”。

欧统局不收集数据。在成员国,这是由统计当局完成的。他们核实和分析国家数据,并将其发送给欧盟统计局。欧统局的作用是使用统一的方法整合数据,并确保它们具有可比性。欧统局实际上是欧洲一级唯一的统计数据提供者,我们发布的数据尽可能统一。”

我要做的是使用 R 中的 eurostat 包 从 Eurostat 下载一些数据,分析时间序列,为以下 6 个总量中的每一个建立模型并预测未来 8 个季度:

  1. GDP ( 按市场价格计算的国内生产总值)
  2. 消费(最终消费支出)
  3. 总资本(总资本形成)
  4. 货物和服务的出口()
  5. (货物和服务的)进口
  6. 薪金(工资和薪金)

我们将有 6 个时间序列,从 1995 年开始,到 2018 年 Q2 奥运会结束。

我们将做 ARIMA 造型。

ARIMA 模型(自回归综合移动平均)

  • 自回归模型(AR)中,我们使用变量过去值的线性组合来预测感兴趣的变量
  • 移动平均模型(MA)中,我们不使用预测变量的过去值,而是使用过去的预测误差
  • ARIMA 结合了自回归模型和移动平均模型,同时还对序列进行差分(积分在此上下文中的意思是差分的逆运算)来处理非平稳性。
  • 与基于数据趋势和季节性描述的指数平滑模型相比, ARIMA 模型旨在描述数据的自相关性。

季节性的 ARIMA 模型包括季节性的条款。我们将讨论一个ARIMA(p,d,q)(P,D,Q)m模型,其中:

  • p = 自回归的顺序 非季节性 部分
  • d = 一阶差分参与度为 非季节性 部分
  • q = 顺序移动平均 非季节性 部分
  • P = 自回归的顺序 季节性 部分
  • D = 一阶差分所涉及的度为 季节性 部分
  • Q = 顺序移动平均 季节性 部分
  • m = 每年的观察次数

数据采集&探索性分析

在使用 eurostat API、下载并导入数据之后(查看完整的 R 代码以了解详细信息),我们来看看第一行和最后一行:

head(data, 20)

in millions of Euros at current prices

tail(data, 20)

in millions of Euros at current prices

这是 6 个时间序列的图:

in millions of Euros at current prices

我们将逐一研究这个时间序列。

让我们首先关注 GDP 时间序列。

in millions of Euros at current prices

本地生产总值数列显示上升趋势及明显的季节性。

我们可以用两个图来检验季节性:

in millions of Euros at current prices

in millions of Euros at current prices

这两个图让我们理解 GDP 行为是季节性的,在 Q2 和第四季度表现较高,在 Q1 和第三季度表现较低。

和 ARIMA 一起做模特

为了开始我们的建模,我们将首先创建一个数据子集来训练模型,然后能够在看不见的数据(我们将有目的地展示的数据)上测试其性能:

train_set <- window(data, end = c(2016, 4))

然后我们使用forecast包中的auto.arima()函数来拟合一个自动 ARIMA 模型:

arima_train <- auto.arima(**train_set**[, "GDP"], 
                          ic = "aicc", 
                          approximation = FALSE,
                          stepwise = FALSE,
                          lambda = "auto")

auto.arima()适合不同的模型,选择 ARIMA(0,1,2)(0,1,0)[4]作为最佳模型。

注:ARIMA 使用最大似然估计。这意味着它找到了最大可能获得数据的参数值。

为了让这个模型被接受,我们应该在正态分布的残差及其包含在 ACF 边界内的滞后中看不到任何模式。让我们在我们的模型对象上使用checkresiduals()来检查它:

残差看起来确实像白噪声。我们准备好了。

现在让我们在完整的数据集上检查这个模型的性能,包括我们给出的季度。我们可以一次计算几个准确度分数:

round(accuracy(forecast(arima_train, h = 5), data[, "GDP"]), 3)

在这些准确性指标中,我们可以看看 MAPE(平均绝对百分比误差)。在这种情况下,对于测试集,我们得到 1.7%的 MAPE。这本身并不是非常有用,但如果我们有几个想要比较的模型,它会有所帮助。除此之外,1.7%似乎是一个相当低的误差百分比,我们将使用该模型进行预测。

我们现在继续扩展模型,以使用所有可用的信息(以便考虑我们之前发布的最新季度):

arima_full <- auto.arima(**data**[, "GDP"],
                         ic = "aicc", 
                         approximation = FALSE,
                         stepwise = FALSE,
                         lambda = "auto")

这又导致了我们的 ARIMA(0,1,2)(0,1,0)[4] 模型。

然后,我们用它来预测未来 8 个季度,并绘制:

**arima_full** %>% 
 **forecast**(h = 8) %>% 
  **autoplot**() +
   labs(title = "Spain's quarterly GDP forecast: ARIMA modelling",
        subtitle = "In millions of euros (€), 2018-19",
        y = "GDP (€)")+
   scale_x_continuous(breaks = seq(1995, 2020, 1)) +
   theme(axis.text.x = element_text(angle = 45, hjust = 1))

Modeled with ARIMA(0,1,2)(0,1,0)[4]

根据我们的预测,西班牙未来 8 个季度的国内生产总值显示出持续的上升趋势,同时也正确地捕捉到了季节性。根据这一预测,2020 年第二季度国内生产总值按现价计算将增至 3262.93 亿€,较 2018 年同期增长 6.87%,平均每季度增长 0.86%。

这是完整的预测,包括置信区间:

现在,我们将继续为其他指标重复同样的过程。我将避免技术细节,只绘制预测图,并在最后将数字表合并成一个表。

消费

Modeled with ARIMA(2,1,0)(0,1,1)[4]

总资本

Modeled with ARIMA(0,1,0)(1,1,1)[4]

出口

Modeled with ARIMA(2,0,0)(2,1,1)[4] with drift

进口

Modeled with ARIMA(2,0,0)(0,1,1)[4] with drift

薪水

Modeled with ARIMA(2,1,3)(0,1,0)[4]

预测摘要

在这里查看完整的 R 代码

从零开始使用 Python 中的垃圾邮件分类器

原文:https://towardsdatascience.com/spam-classifier-in-python-from-scratch-27a98ddd8e73?source=collection_archive---------1-----------------------

我们都面临着收件箱里垃圾邮件的问题。让我们用 python 构建一个垃圾邮件分类程序,它可以判断给定的消息是否是垃圾邮件!我们可以用概率论中一个简单而有力的定理来达到这个目的,这个定理叫做贝耶定理。它在数学上表示为

Baye’s Theorem

问题陈述

我们有消息 m = (w 1 ,w 2 。。。。,w n ,其中(w 1 ,w 2 。。。。,w n 是消息中包含的一组唯一单词。我们需要找到

如果我们假设一个单词的出现独立于所有其他单词,我们可以将上述表达式简化为

为了分类,我们必须确定哪个更大

1.正在加载依赖项

我们将使用 NLTK 来处理消息,使用 WordCloud 和 matplotlib 来实现可视化,使用 panases 来加载数据,使用 NumPy 来生成列车测试拆分的随机概率。

2.正在加载数据

我们不需要“未命名:2”、“未命名:3”和“未命名:4”列,因此我们将其删除。我们将列“v1”重命名为“label”,将“v2”重命名为“message”。在“label”列中,“ham”被替换为 0,“spam”被替换为 1。最后我们得到以下数据框架。

3.列车-测试拆分

为了测试我们的模型,我们应该将数据拆分为训练数据集和测试数据集。我们将使用训练数据集来训练模型,然后在测试数据集上对其进行测试。我们将使用 75%的数据集作为训练数据集,其余的作为测试数据集。对这 75%数据的选择是均匀随机的。

4.可视化数据

让我们看看哪些是垃圾邮件中重复最多的单词!为此,我们将使用 WordCloud 库。

这导致以下结果

不出所料,这些消息大多包含“FREE”、“call”、“text”、“铃声”、“奖金申领”等词语。

类似地,ham 消息的单词 cloud 如下:

5.培训模式

我们将实现两种技术:单词包和 TF-IDF。我将逐一解释。让我们首先从 Bag 的话开始。

预处理 : 在开始训练之前,我们必须对消息进行预处理。首先,我们将把所有的字符都变成小写。这是因为“free”和“FREE”的意思相同,我们不想把它们当作两个不同的词。

然后,我们对数据集中的每个消息进行标记化。标记化是将消息拆分为若干部分并丢弃标点符号的任务。例如:

https://nlp.stanford.edu/IR-book/html/htmledition/tokenization-1.html

像“去”、“去”、“去”这样的词表示同样的活动。我们可以用一个单词“go”来代替所有这些单词。这就是所谓的词干。我们将使用波特斯特梅尔,这是一个著名的词干算法。

然后,我们继续删除停用词。停用词是那些在任何文本中出现频率极高的词。例如像“the”、“a”、“an”、“is”、“to”等词。这些单词没有给我们任何关于课文内容的信息。因此,如果我们从文本中删除这些词,应该没有关系。

可选:您也可以使用 n 元语法来提高准确性。截至目前,我们只处理了 1 个字。但是当两个词在一起时,意思就完全变了。例如,“好”和“不好”的意思是相反的。假设一个文本包含“不好”,把“不好”看作一个标记比“不好”和“好”更好。因此,当我们将文本分割成两个(或更多)单词的标记时,有时准确性会得到提高。

单词袋:在单词袋模型中,我们找到了“词频”,即每个单词在数据集中出现的次数。因此对于单词 w,

TF-IDF : TF-IDF 代表词频-逆文档频率。除了术语频率之外,我们还计算逆文档频率。

例如,数据集中有两条消息。“hello world”和“hello foo bar”。TF('hello ')是 2。IDF('hello ')是 log(2/2)。如果一个词出现的次数很多,说明这个词给出的信息少。

在这个模型中,每个单词都有一个分数,即 TF(w)*IDF(w)。每个单词的概率计算如下:

加法平滑:那么如果我们在测试数据集中遇到一个不是训练数据集的一部分的单词呢?在这种情况下,P(w)将为 0,这将使 P(spam|w)未定义(因为我们必须除以 P(w ), P(w)为 0。还记得公式吗?).为了解决这个问题,我们引入了加法平滑。在加法平滑中,我们在分子中添加一个数字α,并在分母中添加α乘以概率所在的类别数。

使用 TF-IDF 时

这样做是为了使任何单词的最小概率现在应该是一个有限的数。分母中的加法是使垃圾邮件中单词的所有概率的总和为 1。

当α= 1 时,称为拉普拉斯平滑。

6.分类

为了对给定的消息进行分类,我们首先对其进行预处理。对于处理后的消息中的每个单词 w,我们找到 P(w|spam)的乘积。如果训练数据集中不存在 w,我们将 TF(w)取为 0,并使用上述公式找到 P(w|spam)。我们将这个乘积乘以 P(垃圾邮件),得到的乘积就是 P(垃圾邮件|消息)。同样,我们找到 P(ham|message)。无论这两个概率中哪一个更大,相应的标签(spam 或 ham)都被分配给输入消息。请注意,我们不是按照公式中给出的 P(w)来除。这是因为两个数字都将除以这个数,这不会影响两者之间的比较。

7.决赛成绩

资源

  1. 数据集:https://www.kaggle.com/uciml/sms-spam-collection-dataset
  2. http://machine learning . wustl . edu/ml papers/paper _ files/icml 2003 _ rennie STK 03 . pdf
  3. 标记化:https://NLP . Stanford . edu/IR-book/html/html edition/token ization-1 . html
  4. 词干:https://NLP . Stanford . edu/IR-book/html/html edition/stemming-and-lemma tization-1 . html
  5. 停用词:https://NLP . Stanford . edu/IR-book/html/html edition/dropping-common-terms-stop-words-1 . html
  6. https://www.youtube.com/watch?v=PrkiRVcrxOs
  7. 链接到代码:https://github.com/tejank10/Spam-or-Ham

基于逻辑回归的垃圾邮件检测

原文:https://towardsdatascience.com/spam-detection-with-logistic-regression-23e3709e522?source=collection_archive---------2-----------------------

Source

我还记得我上机器学习课的第一天。第一个用来解释机器学习如何工作的例子是“垃圾邮件检测”。我认为在大多数机器学习课程中,导师都提供了相同的例子,但是,在多少课程中,你实际上实现了这个模型?我们讨论机器学习如何参与垃圾邮件检测,然后继续讨论其他事情。

介绍

这篇文章的目的是逐步了解垃圾邮件过滤器的工作原理,以及它是如何让每个人的生活变得更轻松的。此外,下次当你看到一封“你中了彩票”的邮件而不是忽略它时,你可能更愿意将其报告为垃圾邮件。

Courtesy : Google images(Medium post)

上面的图像给出了垃圾邮件过滤的概述,每天都有大量的电子邮件到达,一些进入垃圾邮件,其余的留在我们的主收件箱中(除非你定义了进一步的类别)。中间的蓝框——机器学习模型,它是如何决定哪些邮件是垃圾邮件,哪些不是。

在我们开始讨论算法和代码之前,后退一步,尝试将垃圾邮件检测的简单解释与每月活跃的 Gmail 帐户(大约 10 亿)联系起来。这幅画看起来很复杂,不是吗?让我们来了解一下 gmail 是如何对大量账户进行过滤的。

Gmail 垃圾邮件检测

我们都知道谷歌拥有的数据,显然不是纸质文件。他们有维护客户数据的数据中心。在 Google/Gmail 决定将电子邮件分为垃圾邮件或非垃圾邮件类别之前,在它到达您的邮箱之前,数据中心有数百条规则适用于这些电子邮件。这些规则描述了垃圾邮件的属性。Gmail/Google 使用的垃圾邮件过滤器有几种常见类型

【公然拦截】- 甚至在邮件到达收件箱之前就将其删除。

批量邮件过滤器- 该过滤器帮助过滤通过其他类别但却是垃圾邮件的邮件。

类别过滤器- 用户可以定义自己的规则,根据具体内容或电子邮件地址等对邮件进行过滤。

空发件人处置- 处置所有没有 SMTP 信封发件人地址的邮件。记得当你收到一封电子邮件说,“没有送到 xyz 地址”。

空发件人报头标签验证- 通过检查安全数字签名来验证消息。

有一些方法可以避免垃圾邮件过滤,直接把你的邮件发送到收件箱。要了解更多关于 Gmail 垃圾邮件过滤器的信息,请观看来自谷歌的这个信息视频。

创建垃圾邮件检测器:预处理

继续我们的目标,创建我们自己的垃圾邮件检测器。让我们来谈谈上图中间的那个蓝盒子。这个模型就像一个小孩,除非你告诉这个小孩,盐和糖的区别,否则他/她不会认出来。类似的想法,我们应用在机器学习模型,我们告诉模型什么样的电子邮件可以是垃圾邮件或不是垃圾邮件。为了做到这一点,我们需要从用户那里收集数据,并要求他们过滤一些垃圾邮件或非垃圾邮件。

Kaggle Spam Detection Dataset

上图是为垃圾邮件研究收集的带标签电子邮件的快照。它包含一组由 5,574 封电子邮件组成的英文消息,根据合法(ham)或垃圾邮件进行标记。

现在我们有了带有标记的电子邮件的数据——垃圾邮件或非垃圾邮件,我们下一步应该做什么?我们需要训练机器,让它足够聪明,能够自己对电子邮件进行分类。但是,机器无法读取完整的声明并开始对电子邮件进行分类。这里我们将需要使用我们的 NLP 基础知识(查看我的上一篇博客)。

我们将首先对消息文本进行一些预处理,如删除标点符号和停用词。

**def** text_preprocess(text):
    text = text.translate(str.maketrans('', '', string.punctuation))
    text = [word **for** word **in** text.split() **if** word.lower() **not** **in**  stopwords.words('english')]
    **return** " ".join(text)

一旦预处理完成,我们将需要对数据进行矢量化——即收集每封电子邮件中的每个单词及其频率。矢量化将生成一个矩阵。

vectorizer = TfidfVectorizer("english")
message_mat = vectorizer.fit_transform(message_data_copy)
message_mat

该向量矩阵可用于创建训练/测试分割。这将帮助我们训练模型/机器变得智能,并测试其结果的准确性。

message_train, message_test, spam_nospam_train, spam_nospam_test = train_test_split(message_mat, message_data['Spam/Not_Spam'], test_size=0.3, random_state=20) 

选择模型

现在我们有了训练测试分割,我们需要选择一个模型。有大量的模型,但是对于这个特殊的练习,我们将使用逻辑回归。为什么?

一般当有人问,什么是逻辑回归?你告诉他们什么——哦!这是一种算法,用于将事物分为两类(大多数情况下),即使用二分变量测量结果。但是,逻辑回归如何将事物分类成类似于- 二项式 (2 个可能值)、多项式 (3 个或更多可能值)和序数(处理有序类别)的类别。在这篇文章中,我们将只关注二项式逻辑回归,即模型的结果将分为两类。

逻辑回归

根据维基百科的定义,

逻辑回归通过 估计概率* 使用 逻辑函数 来衡量分类因变量与一个或多个自变量之间的关系。***

从定义来看,逻辑函数在分类中起着重要的作用,但是我们需要理解什么是逻辑函数,以及它如何帮助估计在一个类中的概率。

Courtesy — Google image(Quora post)

上图中提到的公式称为逻辑函数或 Sigmoid 函数,曲线称为 Sigmoid 曲线。Sigmoid 函数给出了一条 S 形曲线。当 z → ∞时,Sigmoid 函数的输出趋于 1,当 z→∞时,输出趋于 0。因此,Sigmoid/logistic 函数产生的因变量的值将始终位于[0,1]之间,即属于一个类别的概率。

系统模型化

对于垃圾邮件检测问题,我们已经标记了邮件,但我们不确定新的传入邮件。我们需要一个模型来告诉我们一条消息是垃圾邮件还是非垃圾邮件的概率。假设在本例中,0 表示负类(没有垃圾邮件), 1 表示正类(有垃圾邮件),我们将使用逻辑回归模型。

***from** **sklearn.linear_model** **import** LogisticRegression
**from** **sklearn.metrics** **import** accuracy_score

Spam_model = LogisticRegression(solver='liblinear', penalty='l1')
Spam_model.fit(message_train, spam_nospam_train)
pred = Spam_model.predict(message_test)
accuracy_score(spam_nospam_test,pred)*

因此,我们首先定义模型,然后拟合训练数据,这一阶段称为训练您的模型。一旦训练阶段结束,我们就可以使用测试分割来预测结果。为了检查我们的模型的准确性,我们可以使用准确性得分度量。此指标将预测结果与获得的真实结果进行比较。运行上述代码后,我们获得了 93%的准确率。

在某些情况下,93%可能是一个不错的分数。为了获得更准确的结果,我们可以对收集到的数据做很多其他的事情,比如词干化和长度标准化。

摘要

正如我们看到的,我们使用以前收集的数据来训练模型,并预测新收到的电子邮件的类别。这表明以正确的方式标记数据的重要性。一个错误会让你的机器变得愚蠢,例如,在你的 gmail 或任何其他电子邮件帐户中,当你收到邮件时,你认为这是一封垃圾邮件,但你选择忽略它,可能下次当你看到那封邮件时,你应该报告它是一封垃圾邮件。这个过程可以帮助很多其他人,他们收到了相同类型的电子邮件,但不知道什么是垃圾邮件。有时错误的垃圾邮件标签也会将真正的电子邮件移到垃圾邮件文件夹中。所以,在你给一封邮件贴上垃圾邮件或非垃圾邮件的标签之前,你必须小心。

参考:

  1. Kaggle 垃圾邮件检测数据集
  2. Github 回购
  3. 自然语言处理—主题建模
  4. Gmail 垃圾邮件检测

垃圾邮件、嘻哈音乐和自然语言处理

原文:https://towardsdatascience.com/spam-hip-hop-natural-language-processing-156780b9210b?source=collection_archive---------4-----------------------

了解 NLP 的基础知识以及如何构建一个简单的垃圾邮件过滤器。

由于大会为期 12 周的数据科学沉浸式计划节奏很快,我们在 5 周内已经覆盖了很多地方。为了在这样的项目中取得成功,我们每个人都必须融合自己的学习风格。对于我们处理的每一个新话题,我的方法是把话题浓缩成我能理解的要点。对基础知识有了扎实的理解后,我发现我对材料的整体记忆更强了,而且我可以很快积累关于该主题的额外细节的知识。我读到过埃隆·马斯克也有类似的方法,所以我一定是做对了什么!

这周我被介绍给了 NLP。从未听说过它,我承认这个缩写本身就让我望而生畏。NLP 代表自然语言处理。都清理好了吗?没有吗?好吧,如果我告诉你“自然语言”是一堆单词。一条短信。一封邮件。一次演讲。歌词。一本小说。会议纪要。更好,对吗?

好了,现在是最后一部分:加工。我们所说的处理是什么意思?我们需要一组基于文本的文档(例如书籍),并将内容分解成最适用的块(单词、句子、短语等)。).这个将我们的文本文档分割成小块或大块的过程被称为标记化。从那里,如果有必要,我们还可以做一些进一步的操作来更好地组织这些块。例如,如果我们在处理单词,我们可能想要识别词类(形容词、名词、动词等。)或将单词简化为基本形式或词根形式。在后一个叫做的词汇化过程中,“穿梭”变成了“穿梭”,“狼”变成了“狼”

一旦我们的语言块被组织起来,更先进的自然语言处理技术可以被应用于理解语言。也许我们想探究一部作品中是否有共同的主题。或者,我们可能想分析一个著名公众人物的一系列演讲的意图或真实性。我们正在分析的语言的情绪是另一个调查的候选对象,就像确定关于一家公司的推文主要是正面的还是负面的。

以下是 NLP 在实践中的一些例子:

  • 这本书是谁写的?帕特里克·尤拉使用自然语言处理技术来量化单词长度的分布,最常见的单词,以及其他写作风格的选择,当他帮助确定 JK·罗琳是《布谷鸟的呼唤》的作者时
  • 哪些说唱歌手词汇量最大?马特·丹尼尔斯利用自然语言处理技术筛选嘻哈歌词,根据专辑中的词汇种类对艺术家进行排名,并对他们的风格选择提出一些理论。

Outkast’s Deep Vocabulary & Unique Style Confirmed with NLP.

  • 谷歌搜索和其他谷歌项目。谷歌的人在不断调整和改进他们的自然语言处理技术,这样他们就可以通过你的随机搜索,如“我的蛋奶酥不会膨胀”或“为什么我在阳光下打喷嚏?”来弄清楚你到底在问什么

除了 Google 之外,NLP 还有一个我们大多数人认为理所当然的常见用途:垃圾邮件过滤器。在本文的剩余部分,让我们深入探讨如何为文本消息构建一个简单的垃圾邮件过滤器——同样的方法也适用于电子邮件垃圾邮件过滤器。我的 Jupyter 笔记本中描述这个练习的全部内容可以在我的公共 Github 库这里找到。

步骤 1:获取、导入和浏览数据。

像往常一样,获取数据通常是最困难的部分。幸运的是,在这个练习中,我们可以访问垃圾短信收集库,这是一个超过 5000 条短信的集合,每条短信都标有“ham”(合法短信)或“Spam”(不请自来或不受欢迎的短信)。为了收集这些数据,进行了大量的工作,这些数据从多个来源进行了整理,包括新加坡国立大学计算机科学系、José María Gómez Hidalgo 和 Caroline Tagg 等人的个人努力。

我使用熊猫导入文件。我们可以看到前 5 行是什么样子——基本上只是每条短信的内容以及它是否是垃圾邮件。

请记住,我们的目标是从内容中预测消息是否是垃圾邮件。为此,我们将所有“垃圾”消息设为 1,将“垃圾”消息设为 0。

使用 1 和 0 来表示 spam vs ham 允许我们做一些有趣的事情。例如,现在我们可以取该列的平均值,以获得垃圾邮件占邮件总数的百分比。从 100%中减去 86.6%,也就是说 86.6%的消息是合法的。

这将成为我们模型的基线,因为我们可以随机猜测一封邮件不是垃圾邮件,我们的正确率为 86.6%。这列 1 和 0 现在将成为我们二元分类模型(如逻辑回归)的目标特征。

步骤 2:为建模准备数据并使用计数矢量化提取要素。

在仔细阅读短信时,我们注意到有重复的内容——多条内容完全相同的短信。这些重复不会增加任何额外的价值,所以我们可以用一个简单的命令删除它们。请注意,这稍微影响了我们的基线,将其增加到 87%多一点:

好了,真正的奇迹发生了。使用 sci-kit learn 的特征提取库,有一个函数叫做 CountVectorizer。CountVectorizer 转换我们的文本消息数据,对每条文本消息中的每个单词进行分离和分类,并为整个文本消息正文中的每个唯一单词创建一个特征列!结果就是所谓的稀疏矩阵。

可以将稀疏矩阵视为在大部分为零的表中存储数据的有效方式。它不是记录所有这些零,而是记录非零值的位置和值。在我们的例子中,该表有 5169 行——每条文本消息占一行,8444 列——在我们的文本消息正文中出现的每个唯一的单词占一列。在一个常规的表格中,总计超过 4300 万个单元格,但是稀疏矩阵只需要记录其中的 4 万个。计数矢量器将数字 1 放入这 4 万个单元格中的每一个,其中文本消息实际上包含 8444 个单词中的一个。

为了更好地形象化,让我们看看数据集的第一条文本消息中的单词“cine”。我已经把我们的稀疏矩阵转换成一个数据帧,用于探索目的。我们可以看到在稀疏矩阵的第一行中,单词“cine”的值是 1。

我们还可以查看其他特征,如文本中的总字数、美元符号($)等特殊字符的出现次数,以及其他可以帮助我们确定短信是否为垃圾邮件的项目。然而,现在让我们使用我们的稀疏单词矩阵作为特征,看看它们是否能帮助我们预测火腿或垃圾邮件。

Fun Fact — Spam musubi is a popular snack in Hawaii. Photo Cred: Joey Rozier

第三步:创建一个模型,看看它是否超过我们的基线。

由于这是一个二元分类问题,逻辑回归是一个模型的合理选择。在我上周的文章中,我检验了线性回归来预测爱荷华州埃姆斯的房屋销售价格。逻辑回归与线性回归的不同之处在于,尽管两种方法都为不同的特征变量分配权重,但逻辑回归模型并不预测连续变量的。相反,它预测只有两个选项的结果的概率,比如抛硬币,正面或反面。

好的,让我们继续分割我们的数据,并将训练数据输入逻辑回归求解器。

Sci-kit learn 完成了繁重的工作,我们现在有了一个模型!换句话说,我们现在有了每个独特单词的最佳系数,来帮助我们判断一条消息是否是垃圾邮件。我们可以通过将系数放入数据帧来查看这些权重。通过对这些值进行排序,我们可以看到最有可能出现在垃圾邮件中的 10 个单词:

之前我们留出了一些数据用于测试。让我们使用我们模型对测试数据应用我们新奇的垃圾邮件过滤器,看看结果:

我们的准确率是 98%,这让我们的基线相形见绌。我们对此感觉良好,但我们需要意识到我们的假阳性和假阴性。详细的分析表明,我们错误地过滤掉了 2 封有效的垃圾邮件,而另一方面,有 23 封垃圾邮件被遗漏,并意外地被标记为垃圾邮件。这些值可以接受吗?最终这取决于客户。如果我们为电子邮件提供商设计过滤器,他们可能会提出更严格的要求。

第四步:改进模型或尝试另一种技术…?

上面描述的方法实际上在幕后结合了几个额外的参数。我调整了停用词,即在标记化过程中被忽略的词。功能的最大数量限于 5000 个最常出现的单词。只考虑出现在至少两个文档中的单词。所有这些参数都是特定于 CountVectorizer 类的。

我们还可以做很多其他的改进。我们可以使用 TF-IFD(术语频率,逆文档频率)矢量器对每个单词进行加权,而不是简单地对每个单词进行计数,以强调在一个文档中出现频率高于整个文档中其他部分的单词。我们还可以添加前面讨论过的其他特性,如消息长度、特殊字符或其他我们认为可能预测垃圾邮件的项目。这些额外的功能将与我们的术语矢量化过程分开管理,它们肯定有可能影响我们的模型。

作为最后一个想法,肯定有更多的 NLP 方法还没有出现在我的工具包中。有人在课堂上建议,多项式朴素贝叶斯方法可能更适合这种应用。我不熟悉这个概念,但我的初步研究表明,它可以让我们根据字数而不是单词出现次数来调整我们的模型计算。如果我发现自己参与了类似的 NLP 项目,我会花一些时间消化 McCallum 和 Nigam 对朴素贝叶斯文本分类事件模型的比较,期望它能改进我的模型。

垃圾邮件还是火腿:自然语言处理介绍第 2 部分

原文:https://towardsdatascience.com/spam-or-ham-introduction-to-natural-language-processing-part-2-a0093185aebd?source=collection_archive---------2-----------------------

Spam … or ham?

这是我的自然语言处理基础系列的第二部分。如果你还没看第一部分,可以在这里找到

在这一部分中,我们将从头到尾地介绍如何用 Python 3 构建一个非常简单的文本分类器。我们将使用垃圾短信收集数据集,该数据集根据短信是“垃圾短信”还是“垃圾短信”(非垃圾短信)来标记 5574 条短信。

我们的目标是建立一个预测模型,它将确定一个文本消息是垃圾邮件还是火腿。代码见这里

我们开始吧!

导入数据后,我更改了列名,使其更具描述性。

import pandas as pddata = pd.read_csv("spam.csv", encoding = "latin-1")
data = data[['v1', 'v2']]
data = data.rename(columns = {'v1': 'label', 'v2': 'text'})

我们数据集的前几个条目如下所示:

通过简单地浏览我们的数据,我们对我们正在处理的文本有了一些了解:口语。这个特定的数据集也有 87%的邮件被标记为“垃圾邮件”,13%的邮件被标记为“垃圾邮件”。当稍后评估我们的分类器的强度时,类别不平衡将变得重要。

数据清理

清理文本数据与常规数据清理略有不同。文本规范化比去除离群值或杠杆点更受重视。

根据维基百科:

文本规范化是将文本转换成以前可能没有的单一规范形式的过程。

正确使用时,它可以减少噪音,将具有相似语义的术语分组,并通过给我们一个更小的矩阵来降低计算成本。

我将介绍几种常见的标准化方法,但是请记住,使用它们并不总是好主意。保留判断何时使用数据科学中人的因素的权利。

没有免费的午餐定理: 从来没有一个解决方案对所有的事情都有效。用您的数据集尝试它,以确定它是否适合您的特殊用例。

案例规范化

大小写是否提供了关于文本消息是垃圾邮件还是垃圾邮件的任何相关信息? HELLOhello 或者 Hello 语义相同吗?你可以根据以前的知识认为垃圾邮件倾向于使用更多的大写字母来吸引读者的注意力。或者,你可以争辩说这没有什么区别,所有的单词都应该简化为相同的大小写。

删除停止字

停用词是没有增加预测价值的常用词,因为它们随处可见。它们类似于电影《T2:超人总动员》中的反派评论:

当每个人都是超级的时候,没有人会是【超级】

英语中一些常见的停用词:

  • a
  • 因为

关于什么时候删除停用词是个好主意,有很多争论。这种做法在许多信息检索任务(如搜索引擎查询)中使用,但在需要对语言进行语法理解时可能是有害的。

删除标点符号、特殊符号

我们必须再次考虑标点符号和特殊符号对分类器预测能力的重要性。我们还必须考虑每个符号功能的重要性。例如,撇号允许我们定义缩写,并区分像 it'sits 这样的单词。

词干匹配/词干匹配

这两种技术都减少了变形形式,使具有相同词条的单词规范化。词汇匹配和词干匹配的区别在于,词汇匹配通过考虑单词的上下文来进行这种归约,而词干匹配则不会。缺点是目前没有准确率非常高的 lemmatiser 或 stemmer。

Examples of stemming from Stanford NLP

不太常见的规范化技术包括纠错、将单词转换为其词性或使用同义词词典映射同义词。除了错误纠正和同义词映射之外,还有许多用于其他规范化技术的预建工具,所有这些工具都可以在 nltk中找到。

对于这个特殊的分类问题,我们将只使用案例规范化。基本原理是很难将词干分析器或词尾分析器应用到口语中,而且由于文本消息非常短,删除停用词可能不会给我们留下太多工作。

def review_messages(msg): # converting messages to lowercase msg = msg.lower() return msg

作为参考,这个函数进行了大小写规范化,删除了停用词和词干。

from nltk import stemfrom nltk.corpus import stopwordsstemmer = stem.SnowballStemmer('english')stopwords = set(stopwords.words('english')) def alternative_review_messages(msg): # converting messages to lowercase msg = msg.lower() # removing stopwords msg = [word for word in msg.split() if word not in stopwords] # using a stemmer msg = " ".join([stemmer.stem(word) for word in msg]) return msg

我们应用第一个函数来归一化文本消息。

data['text'] = data['text'].apply(review_messages)

向量化文本

在本系列的第一部分中,我们探索了最基本类型的单词矢量器,单词袋模型,由于其简单性,它对于我们的垃圾邮件或业余爱好者分类器来说不是很好。

相反,我们将使用 TF-IDF 矢量器(术语频率—逆文档频率),这是一种类似的嵌入技术,它考虑了每个术语对文档的重要性。

虽然大多数矢量器都有其独特的优势,但使用哪一种并不总是很清楚。在我们的例子中,选择 TF-IDF 矢量器是因为它在对文本消息等文档进行矢量处理时简单而高效。

TF-IDF 通过计算文档和词汇表中每个术语之间的 TF-IDF 统计量来对文档进行矢量化。文档向量是通过使用每个统计信息作为向量中的一个元素来构建的。

文件 j 中术语 i 的 TF-IDF 统计量计算如下:

在解决了 TF-IDF 之后,我们必须决定矢量器的粒度。将每个单词指定为自己的术语的一种流行的替代方法是使用分词器。记号赋予器根据空白和特殊字符将文档分割成记号(从而将每个记号分配给它自己的术语)。

例如,短语what ' s how on可能被拆分为 what,s,going,on

标记器能够提取比单词级分析器更多的信息。然而,分词器不能很好地处理口语,可能会遇到拆分 URL 或电子邮件的问题。因此,我们将使用单词级分析器,它将每个单词分配给它自己的术语。

在训练矢量器之前,我们将数据分为训练集和测试集。我们 10%的数据用于测试。

from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(data['text'], data['label'], test_size = 0.1, random_state = 1)# training the vectorizer from sklearn.feature_extraction.text import TfidfVectorizervectorizer = TfidfVectorizer()X_train = vectorizer.fit_transform(X_train)

构建和测试分类器

下一步是选择要使用的分类器类型。通常在这一步中,我们会选择几个候选分类器,并根据测试集对它们进行评估,看看哪一个效果最好。为了保持事物,我们可以假设支持向量机足够好地工作。

SVM 的目标是找到

C 项用作影响目标函数的正则化。

较大的 C 值通常会导致超平面具有较小的裕度,因为它更强调精度而不是裕度宽度。诸如此类的参数可以通过网格搜索精确调整。

from sklearn import svmsvm = svm.SVC(C=1000)svm.fit(X_train, y_train)

现在,让我们来测试一下。

from sklearn.metrics import confusion_matrixX_test = vectorizer.transform(X_test)y_pred = svm.predict(X_test)print(confusion_matrix(y_test, y_pred))

成绩一点都不差!我们没有假阳性,大约 15%的假阴性。

让我们用几个新例子来测试一下。

def pred(msg): msg = vectorizer.transform([msg]) prediction = svm.predict(msg) return prediction[0]

在我看来是对的:)

我希望你喜欢本教程的第 2 部分。同样,完整的代码可以在这里找到

检查第三部分!

感谢您的阅读!

如果你喜欢这篇文章,可以看看我关于数据科学、数学和编程的其他文章。通过 Medium 关注我的最新动态。😃

作为一个业余爱好项目,我还在www.dscrashcourse.com建立了一套全面的免费数据科学课程和练习题。

如果你想支持我的写作,下次你报名参加 Coursera 课程时,可以考虑使用我的会员链接。完全公开—我从每一次注册中获得佣金,但不会对您产生额外费用。

再次感谢您的阅读!📕

2018 年火花+人工智能峰会-概述

原文:https://towardsdatascience.com/spark-ai-summit-2018-overview-7c5a8d7be296?source=collection_archive---------6-----------------------

上周参加了 Spark+AI 峰会,想分享一下学到的东西。

特种宽银幕电影

Spark +AI 峰会的大局观来自于大局观大师——马克·安德森。他的公司安德森·霍洛维茨databricks 的早期投资者,该公司由阿帕奇火花的创造者运营。

https://data bricks . com/session/fireside-chat-with-Marc-Andre essen-and-Ali-gho DSI

根据 Marc 的说法,AI 可能是添加到现有产品中的一个功能,也可能是一个完整的“架构变化”。现有产品的一个特征可以是 DSLR 相机的自动对焦。一个架构的改变是一个拍照无人机,它可以自动飞行,检测正确的场景,拍摄正确的照片。
A16Z 团队在人工智能将带来架构变革而不仅仅是一个附加功能的想法上下了大赌注。

如同任何新的架构一样,它需要新的软件范例。安德烈·卡帕西在介绍 软件 2.0 时,他的主旨在这一点上是正确的。

在经典的软件开发 1.0 中,开发人员以代码的形式描述预期的行为。

使用软件 2.0,行为不是被编程的,而是从精心准备的数据和标签中学习的。

像神经网络这样的机器学习模型可以从数据和标签中学习行为。学习到的行为甚至可以比根据规则编程的东西表现得更好。然而,这并不意味着不再需要编程。而是改变编程过程。软件开发人员 2.0 通过进行正确的数据采样、标记、模型选择和调整进行编程。

一般景观-两种类型的问题。

每个公司都有自己的故事,与迈向新架构的人工智能相关,但总的主题是清楚的。要解决的问题可以分为两大类:“新工具”和“大规模性能”。

新工具

新软件开发过程需要新的工具。这花了几十年的时间,但现在我们有了一套令人惊叹的专用于软件 1.0 的工具。我们有现代化的 ide、复杂的自动化测试框架、构建工具、docker、CI/CD 工具、github 等等。即使是半途而废的软件开发车间现在也可以建立一个自动化的过程,在这个过程中,很容易将生产中执行的代码与软件库中的代码联系起来。

不幸的是,对于人工智能驱动软件的工具却不能这么说。共同的主题是,科学家正在做的数据可能是使用各种软件组件进行的数百次离线实验。将这些模型投入生产并非易事。很多时候,并不清楚。生产中运行的确切模型是什么?它是根据什么数据训练的?训练数据是如何收集的?将新算法引入生产流水线需要什么?

从获得正确的训练数据到标记,再到管理训练,再到服务于能够调试现有模型缺点的模型,开发端到端的管道是未来十年左右的挑战。

We can only dream it’s that easy….

这就是为什么 Spark AI 峰会的最大亮点之一是 databricks 宣布了名为 mlflow 的新产品。

mlflow image from databricks announcement.

mlflow 似乎处于早期阶段,但它看起来非常有前途。

然而,mlflow 只是拼图的一小部分。这个高层图上的每个小方框都需要一套工具。每个公司都有自己的一套工具来解决他们的具体问题。特斯拉拥有复杂的图像标签集成开发环境。Netfix 引入了他们的 Scala DLS,用于被称为玻色子的分层数据采样。加州大学洛杉矶分校的团队推出了基于 Spark 的大调试,它可以快速找到错误,扭曲聚合。

很明显,软件 2.0 工具集还处于起步阶段,但发展非常迅速。

规模化性能

Spark AI Summit 表明,大数据真正变大的时候终于到了。当您的到达率达到每天 100 TB 时,以旧的可靠的 json 格式存储数据不再是一种选择。很明显,在数据处理方面,这些公司正在回归基础。

Pinterest 团队做了一个惊人的演示,使用 VGG 和位置敏感的哈丁删除了几乎重复的图片。他们每天会收到 2000 亿张图片。随着这种流入,每一点都很重要。他们使用可变字节编码和高度优化的原始集合等技术来处理如此大量的数据。

LinkedIn 推出了大象博士,它会自动调整 Spark 作业,然后让这些作业进入跨越 100 Pb 数据的 Spark 集群。

StichFix 找到了将 mix 效果分层模型的训练并行化的方法——https://databricks . com/session/moment-based-estimation-for-hierarchical-models-in-Apache-spark。他们能够在 40 分钟内对 1.2 亿行数据集进行训练。

脸书为 Spark Shuffle 引入了新的优化,这应该会出现在 Spark 的下一个版本中。

Spark 流越来越强大,有状态流处理支持基于事件时间的窗口和流连接。

结论

很明显,人工智能将推动新产品架构,这将推动向模型驱动行为的移动。支持软件开发 2.0 的新工具的开发与老式的性能优化相结合,将是未来十年软件开发创新的主要驱动力。我们才刚刚开始。

我鼓励你在这里了解更多并获得录制的视频:【https://databricks.com/sparkaisummit/sessions

Clojure 中的 Spark 机器学习

原文:https://towardsdatascience.com/spark-machine-learning-in-clojure-1d5a2c97924a?source=collection_archive---------6-----------------------

虽然 Spark 是在 Scala 中实现的,但是我们可以使用 Spark 平台来完成机器学习任务,这要感谢 Sparkling 库

在这张工作表中,我们将演示在机器学习的分类任务中使用 Sparkling。让我们首先加载依赖项

(ns itchy-garden
  (:require [sparkling.conf :as conf]
            [sparkling.core :as s]
            [sparkling.ml.core :as m]
            [sparkling.ml.classification :as cl]
            [sparkling.ml.transform :as xf]
            [sparkling.ml.validation :as v]) (:import [org.apache.spark.api.java JavaSparkContext]
           [org.apache.spark.sql DataFrame SQLContext]
           [org.apache.spark.ml.classification NaiveBayes LogisticRegression
            DecisionTreeClassifier RandomForestClassifier GBTClassifier ]
           [java.io File])) ;;outputnil

让我们加载一个 libsvm 格式的数据集。这包括大约 3k 个实例,其中每个实例都有一个值为 0 或 1 的目标变量,以及多个连续值的特征。

请注意,Spark 的 ML 库实现仅适用于正标签,标签在 1,-1 范围内的数据集不能开箱即用,标签需要更改为正。

(defn download-dataset
  []
  (let [svm-dataset-path
        "http://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/binary/svmguide1"
        tmpfile (.getPath (File/createTempFile "svmguide" "svm"))
        _ (spit tmpfile (slurp svm-dataset-path))]
    tmpfile))(def dataset-path (download-dataset))

交互效度分析

我们将在这个数据集上训练一个二进制分类器,并在 areaUnderROC 曲线度量上使用交叉验证来评估它的性能。

这个 API 使用中间件模式(受的启发)来指定这些工件:

  • 处理函数进行交叉验证
  • add-dataset 函数采用一个函数,该函数返回 Spark 数据帧中的数据集
  • 估计量是所使用的分类器或回归量的类型。在这种情况下,我们将使用逻辑回归分类器。
  • 这种情况下的评估器是二元分类评估器。如果我们有一个多类分类问题,一个多类评估将适用。分类的默认度量是 ROC 曲线下的面积。

run-pipeline 函数将执行处理程序并返回交叉验证的 areaUnderROC 指标。

(let [cvhandler (-> m/cv-handler
                    (m/add-dataset (partial m/load-libsvm-dataset dataset-path))
                    (m/add-estimator cl/logistic-regression)
                    (m/add-evaluator v/binary-classification-evaluator))]
  (m/run-pipeline cvhandler));;output: areaUnderROC score(0.989250155930387)

前面的示例使用了逻辑回归的默认选项以及赋值器。在下一个示例中,我们将指定

  • 分类器的超参数(弹性网参数)
  • 评估者的不同评估指标(精确召回曲线下的面积)
(let [cvhandler (-> m/cv-handler
                    (m/add-dataset (partial m/load-libsvm-dataset dataset-path))
                    (m/add-estimator cl/logistic-regression {:elastic-net-param 0.01})
                    (m/add-evaluator v/binary-classification-evaluator {:metric-name "areaUnderPR"} ))]
  (m/run-pipeline cvhandler));;output: area under Precision Recall(0.9941958048724657)

我们还可以更改交叉验证处理程序本身的参数。让我们将折叠次数更改为 5 次(从默认的 3 次)

(let [cvhandler (-> (partial m/cv-handler {:num-folds 5})
                    (m/add-dataset (partial m/load-libsvm-dataset dataset-path))
                    (m/add-estimator cl/logistic-regression)
                    (m/add-evaluator v/binary-classification-evaluator))]
  (m/run-pipeline cvhandler));;output(0.9894297378637298)

训练-验证分割

除了使用交叉验证,我们还可以使用单一折叠,并根据百分比分割训练测试集。

我们将使用训练验证处理程序,而不是交叉验证处理程序,而其他参数保持不变。

(let [tvhandler (-> m/tv-handler
                    (m/add-dataset (partial m/load-libsvm-dataset dataset-path))
                    (m/add-estimator cl/logistic-regression)
                    (m/add-evaluator v/binary-classification-evaluator))]
  (m/run-pipeline tvhandler));;output (0.9919497271895795)

让我们指定一个不同的训练与验证比率,其中训练集是 60%,其余的是验证集。

(let [tvhandler (-> (partial m/tv-handler {:train-ratio 0.6} )
                    (m/add-dataset (partial m/load-libsvm-dataset dataset-path))
                    (m/add-estimator cl/logistic-regression)
                    (m/add-evaluator v/binary-classification-evaluator))]
  (m/run-pipeline tvhandler));;output(0.9897219862173144)

网格搜索

通常分类器使用多个超参数,我们希望找到给出最佳分类分数的超参数的值。SparkML 为此提供了网格搜索功能。参见链接了解 Scikit-learn 中的网格搜索

我们将指定一系列正则化值,并为每个值找到交叉验证的分数。

(defn addregularization
  "sets the regularization parameters to search over"
  [regparam est]
  (v/param-grid [[(.regParam est) (double-array regparam)]]))(let [cvhandler (-> m/cv-handler
                    ;;search for the best value for the regularization parameter 
                    (m/add-grid-search (partial addregularization [0.1 0.05 0.01]))
                    (m/add-evaluator v/binary-classification-evaluator)
                    (m/add-estimator cl/logistic-regression)
                    (m/add-dataset (partial m/load-libsvm-dataset dataset-path)))]
  (m/run-pipeline cvhandler));;output(0.9730089312309409 0.9773629797090069 0.9853807421182689)

这 3 个分数对应于正则化的三个值,我们可以看到最后一个值(0.01)返回了 AucROC 度量上的最佳交叉验证分数。

使用深度学习的说话人区分

原文:https://towardsdatascience.com/speaker-differentiation-using-deep-learning-68b2dede498f?source=collection_archive---------10-----------------------

上周,我在 ICSEE2018 上发表了一篇关于神经网络系统的会议论文,该系统能够快速区分双麦克风音频中的扬声器。这与酒会问题有关。在我的工作中,这个想法是一个神经网络学习如何使用每个说话者的少量干净的训练数据来将语音分成多个箱(一个非常乐观的假设)。一个进一步简化的假设是,有正常的背景噪音,但没有困难的东西,如背景音乐或噪音。这里最难的部分,或者取决于你的观点,最容易的部分,是应该有最少的预处理。神经网络对音频的每个片段进行预测,当在给定的对话中检测到每个语音签名时,说话者就被识别出来。

在更一般的有多个说话者的鸡尾酒会问题中,这要困难得多,这个想法是这些说话者可以被识别,因为我们知道谁在说话,他们在哪里,他们说话有多大声。在这种情况下,扬声器的位置是相关的,而在我们的工作中,人们对麦克风说话的相对位置是相似的,因此我们专注于扬声器的声音,而不是声音的力量或相对位置。

We used 2 microphones to record human voices.

该领域还有其他关于从单麦克风和双麦克风信号中提取特征的工作,让我们跳过所有这些。我们的目标是看看某一种神经网络是否只需要基本的预处理就能完成这项工作。

我的合著者默罕默德·阿斯尼、托尼·马修、米奥德拉·博利奇莱奥·格雷布勒在这篇论文上与我一起工作了很长时间。我觉得我们花了大约一年的时间。回溯到拨款和创意阶段,超过一年。该项目从需求收集延伸到解决方案架构,然后是数据收集,最后是开发、分析、起草、提交论文,并在会议上进行演示。这些事情发生得很慢。在你知道之前,这篇论文应该会出现在 IEEE Xplore 和谷歌学术网站上。

最终,我们开发了一种深度学习解决方案,用于区分同时来自两个麦克风源的音频中的人声。为了更好地理解这个解决方案,让我们简单地讨论一下自动编码器、卷积、MFCC 等等。我不会在本文中涵盖我们所做的一切,也不会介绍现有技术。相反,我想从解决方案架构的角度向您介绍我们所做的事情。

自动编码器 (AE)将输入的维度缩小到潜在空间表示(AE 的编码器部分),然后尝试重建压缩数据(解码器)。这种编码器-解码器系统旨在将输入压缩到某个较低维度的潜在空间中,以保存输入的基本信息。换句话说,它可以被看作是一个自动化的特征提取器。卷积 AEs,(CAEs) 基于 AEs,其中卷积层用于编码/解码,而不是 MLP 中的层。

因此,我们使用 CAE 进行自动特征提取并生成精确的潜在空间表示,但我们没有在原始音频上这样做。梅尔频率倒谱 (MFCC)提供了音频特征的短期频谱表示。MFCC 是音频振幅频谱表示的一种紧凑形式。当用作特征提取的预处理步骤时,它降低了计算成本,并且它被广泛地知晓并用于人类语音材料。因此,如下图所示,在使用 CAE 对原始音频进行分类之前,我们对其进行了 MFCC 预处理。

Single microphone audio preprocessing leading to the AI model’s input

这项工作的基本目的是评估 CAE 的准确性,因为网络输出的叶片数量增加了。我们希望在不进行大量预处理的情况下,同时使用来自两个麦克风源的输入。我们对这个项目的预期是,无论数据集的大小和质量如何,随着扬声器(桶)数量的增加,模型的准确性最终会降低。我们预料到了这一点,因为随着输出标签的可能性越来越多,问题变得越来越难。直觉告诉我们,有两个人说话,你有 50%的几率猜对,但是有 10 个人说话,你只有 10%的几率猜对。因此,当说话的人可能是许多人中的一个时,就很难区分出是谁在说话。

下面的混淆矩阵显示了区分 3 个扬声器的双麦克风结果。系统在 12 次尝试中识别了 3 个扬声器中的 2 个,但是第三个扬声器被第一个扬声器混淆了两次,被第二个扬声器混淆了一次。

Confusion matrix for 3 speakers in a dual microphone setup

让我们更详细地讨论一下上述实验是如何进行的,以及 CAE 是如何设计的。使用两个麦克风同时收集数据,并保存到单独的 WAV 文件中。我们必须收集自己的数据,因为双麦克风数据集很难找到。我们复制了一个公共语音数据集的短语,有效地将其扩展到双麦克风领域,用于我们的窄应用和小数据集。我们以 44100 Hz 的采样率进行记录,每个音频片段由 10 秒的持续时间组成。录音中的平均房间噪音水平为 47 分贝。在我们的新录音中,我们有 6 名 30 岁以下的发言者,其中 3 名是男性,3 名是女性。收集的样本被转换为每个麦克风信号的 MFCC 表示,以便我们可以比较单麦克风和双麦克风的性能。

在我们的系统中,解码器(DNN)使用编码数据(由编码器(CNN)生成的数据)的相关特征,通过将扬声器放入桶中来区分原始音频中的扬声器

Block diagram showing the MFCC input for 2 audio snippets concatenated before entering an encoder, followed by a decoder and a softmax at the output. The width of the output was the same as then number of possible individuals (speakers) in each experiment.

对于每个实验,我们使用 K 倍交叉验证来确保结果有效。1 个麦克风的结果如下所示。

Test results for a single microphone (one MFCC input).

现在我们来看看两个麦克风的结果:

Test results for a dual microphone (two MFCC inputs).

在比较单麦克风和双麦克风的结果时,我们注意到的第一件事是,与单麦克风源相比,当给定来自 2 个麦克风源的音频时,模型表现更好。这是好消息。这意味着我们使用两个麦克风的想法并不愚蠢。我们还在两个结果中看到,随着可能的扬声器(桶)数量的增加,性能会下降。随着说话者类别数量的增加,模型的准确性降低。为了得到更一般的结论,我们发现,给定从两个麦克风同时收集的小样本音频,CAE 可以区分音频中的扬声器。

希望这篇文章能让你更好地理解这篇论文的内容,我们发现了什么,以及我们是如何做到的。这项工作得到了加拿大自然科学和工程研究委员会(NSERC)和统一计算机智能公司( UCIC.io )的慷慨资助。自从这个项目开始以来,Mohamed 已经在 lemay.aistallion.ai 工作。

参加这个两年一度的 IEEE 会议真的很有用。它比我去的上一次会议更具技术性(tmls 2018——更多关于那次旅行这里),面积略大于 TMLS 的三分之一。但我确实很喜欢这两场会议。我遇到了一些非常有趣的人,看到了一些精彩的演讲,从这次经历中我可以告诉你,信号处理领域正在发生很多变化。仍然有优秀的特征工程工作在进行,也有大量关于 ML/AI 方法处理语音和信号的新论文。深度学习专场也有一些精彩的讲座。我在中途认出了一些演讲者,他们是我在 youtube 视频上看到的演讲人。就像书呆子看名人一样。非常激动人心的时刻。

如果你喜欢我最近论文中的这篇文章,那么看看我过去最常阅读的一些文章,比如“如何为人工智能项目定价”和“如何聘请人工智能顾问

下次见!

丹尼尔

您可能喜欢的其他文章:

面向初学者的谱聚类

原文:https://towardsdatascience.com/spectral-clustering-for-beginners-d08b7d25b4d8?source=collection_archive---------3-----------------------

聚类是探索性数据分析中使用最广泛的技术之一。其目标是将数据点分成若干组,使得同一组中的点相似,而不同组中的点彼此不相似。

谱聚类由于其简单的实现和在许多基于图的聚类中有前途的性能而变得越来越流行。它可以通过标准的线性代数软件有效地解决,并且通常优于传统的算法,例如 k-means 算法。

在这里,我们将尝试非常简要地解释它是如何工作的!

要执行谱聚类,我们需要 3 个主要步骤:

  1. 创建我们要聚类的 N 个对象之间的相似度图。
  2. 计算其拉普拉斯矩阵的前 k 个特征向量,以定义每个对象的特征向量。
  3. 对这些特征运行 k-means 将对象分成 k 个类。

第一步:

表示一组数据点 x 1,.。。 x N 的形式为相似图 G =( VE )。

Similarity Graph

有不同的方法来构建表示数据点之间关系的图形:

  1. ε-邻域图:每个顶点都连接到半径为ε的球内的顶点,其中ε是一个实值,为了捕捉数据的局部结构,必须对其进行调整。
  2. k-最近邻图:每个顶点连接到它的 k-最近邻,其中 k 是控制数据的局部关系的整数。

Different similarity graphs

在上面的例子中,我们画了 3 个集群:两个“月亮”和一个高斯。

在ε-邻域图中,我们可以看到很难选择一个有用的参数ε。如图中ε = 0.3,中月上的点已经连接的非常紧密,而高斯中的点几乎没有连接。如果我们有“不同尺度”的数据,即在空间的不同区域,数据点之间的距离不同,这个问题总是会发生。然而,k-最近邻图可以连接“不同尺度”上的点。我们可以看到低密度高斯中的点与高密度月球中的点相连。

第二步:

现在我们有了我们的图,我们需要形成它相关的拉普拉斯矩阵。

注意:谱聚类的主要工具是图拉普拉斯矩阵。

我们现在要做的就是计算 L 的特征向量 u _ j

第三步:

运行 k 均值:

应用:图像处理中的光谱聚类

Original image (left) and segmented image using spectral clustering (right)

加成:k 怎么选?

通过将点投影到非线性嵌入中并分析拉普拉斯矩阵的特征值,可以推断出数据中存在的聚类的数量。当相似图不完全连通时,特征值λ = 0 的重数给我们一个 k 的估计。

结论

在处理经验数据的每个科学领域中,人们试图通过识别数据中相似行为的组来获得对数据的第一印象。在本文中,我们介绍了谱聚类算法如何通过使用拉普拉斯矩阵的底部特征向量将图的顶点嵌入到低维空间中来工作。

请继续关注,如果你喜欢这篇文章,请留下👏!

参考

[1] 利用线性谱聚类进行图像分割,Sandeep Reddy【2】机器学习中的图形,Michal Valko

虚拟现实中的语音输入

原文:https://towardsdatascience.com/speech-as-input-in-virtual-reality-bb892f9bb41?source=collection_archive---------14-----------------------

Photo credit: Jason Rosewell

为更动态的虚拟环境使用语音和自然语言处理。

人们很久以来就一直想和计算机对话。由于深度学习,语音识别变得明显更加强大,而且明显不那么令人沮丧——即使是对于不太受欢迎的语言。

Kanda ,我们开始研究语音识别和自然语言处理(NLP)技术,为增强现实(AR) &虚拟现实(VR)制作流畅的对话界面。丹麦语。

T3 丹麦语是出了名的难学。人类和机器都是如此。这是我们一路走来获得的一些见解。

语音识别的现状

语音识别是人类非常擅长的一项任务。基于理查德·李普曼 1997 年的论文“机器和人类的语音识别”【1】,人类水平的语音识别经常被引用为测量的 4%的单词错误率

另一项研究发现,使用仔细的多重转录,人类转录者之间平均有 4.5%的不一致。当要求执行快速转录时(转录大约。仅 5 小时 1 小时英语音频),不同意上升至 9.6%【2】。这些是我们可以用来评估自动语音识别系统有效性的基线。

当李普曼在 1997 年发表他的论文时,他注意到语音识别技术已经取得了很大的进步,在理想情况下错误率已经低于 10%。然而,在自发语音或嘈杂条件下,错误率会增加到 30-40%。

快进到 2018 年。(嗖!)

在这一点上,我们已经习惯了每天与我们的设备对话。想想 Alexa,想想 Cortana,想想 Siri。2017 年,微软宣布他们已经达到了比人类水平略好的机器转录错误率——在 Switchboard 数据集【3】上为 5.8% vs 5.9%。

Photo credit: Bence Boros

小生境语言

所有这些都很棒。但是这些结果是针对英语的,英语是世界上最常用的语言之一。神田总部设在丹麦,我们的客户来自丹麦。我们说丹麦语。于是就有了那个。

语音转文本(STT)是您希望避免为其构建自己的模型的任务之一——任务的普遍性与您成功所需的庞大数据量相结合,使得依赖于一个公共提供商成为理想选择。

幸运的是,微软 Azure 和谷歌云都提供了丹麦 STT API。但是由于缺乏全面的学术研究和测试结果,我们需要自己评估这些 API 的准确性。

为了这个任务,我们设计了自己的小测试。

我们准备并转录了一些丹麦的演讲录音。有些是对着笔记本电脑麦克风大声朗读的新闻文章和电影评论,有些是对着耳机大声朗读的电影对白,还有一些是发音模糊或音频质量下降的自由格式视频博客。

我们试图覆盖广泛的场景,尽管测试的规模确实非常小。首先,谷歌云 STT API 的表现远远超过了 Azure STT API 。所以我们将暂时依赖 Google API。

即使这样,结果也远远低于我们在英语中看到的 STT 5-6%的错误率。在我们的丹麦测试中,谷歌云 STT API 的平均错误率为 28%** 在良好的录制条件下,结构化内容的错误率约为 10%,在嘈杂的条件下,非结构化语音的错误率高达 60%。这实际上可与 1997 年 STT 的英语表演相媲美。出于好奇,一些测试结果如下所示:**

A selection of results from our Google Cloud SST tests.

指挥与控制

所以,也许丹麦语流畅的会话语音界面还有一段路要走。但是,如果我们将范围缩小到关键字驱动的方法,并采取适当的措施来强化和验证输入,【命令和控制】类型的接口在具有广泛可用的工具和服务的 VR 中是可能的。****

当你考虑到这是自 70 年代以来基于文本的叙事游戏进行交互的方式时,这种方法可能看起来有点古老。然而,能够以说话的方式与虚拟环境进行交互可以为 VR 体验增加一层新的物理性、熟悉性和可信度。

这种互动不一定是明确的,比如“去北方”、“玩五分钱游戏”或“拿起物品”。我们可以倾听玩家在体验过程中的自发话语,如命名实体、感兴趣的领域或情绪指标,并让虚拟环境对此做出反应。

Photo credit: Lux Interaction

这都是关于环境的

当你开始记录语音并观察 STT 模型所犯的错误时,你会意识到许多听起来非常相似的语言特征在不同的上下文中意味着完全不同的东西。这些字叫做同音字

上下文可能意味着之前出现的单词,我们正在谈论的话题或者我们正在交谈的人。因此,语境决定了我们正在听的和期望可能听到的单词。

谷歌 STT API 支持可选输入speech context,其中可以包含一些单词和短语,以便在结果中进行优先排序。当听的时候,谷歌 STT 模型会产生一些可能的选项。 言语语境 用于确定这些选项中哪些最有可能是正确的,我们期望听到什么。

Context is used to select the best candidate among words that sound the same.

另一个问题是,当在 STT 转录寻找关键字时,可能会出现小的语法错误,例如错误地将“计算机的”转录为“计算机”或“计算机”。如果这个变化没有改变单词的意思,我们仍然应该试着去发现它并做出反应。

我们的可用 NLP 工具列表是有限的,因为大多数不支持丹麦语。然而,对小的语法和打字错误的一个补救方法是做 模糊字符串搜索 :测量近似(而不是精确 ) 关键词匹配。近似关键词匹配的一个度量是Levenshtein distance,这是一种衡量 word 编辑距离的方式。****

Levenshtein distance measures the number of edits necessary to change one string to another.

Levenshtein 方法通过测量将一个字符串更改为另一个字符串需要多少次编辑来确定两个字符串之间的距离。有效性可以是字符的改变、插入或删除。使用可能编辑的最大数量(等于最长字符串的长度),可以计算归一化单词距离度量。

使用上下文和模糊字符串搜索,我们能够显著降低预定关键字的错误率。经过多次测试,我们能够以 12%的错误率检测出丹麦关键词,这是我们最初测试的两倍多。

基于这些结果,我们认为丹麦的语音识别服务现在可以实际应用了。至少对于基于关键字的界面是这样。

Photo credit: Adam Solomon

走向

随着语音识别、NLP 和深度学习领域的所有重大举措,很高兴看到不太受欢迎的语言开始得到支持。

“外国”语言模型的性能落后于目前可能的英语,但通过一些额外的工具和技巧,丹麦语语音识别可以用于生产。

在像丹麦语这样的语言中,我们仍然在等待能够可靠地应用真正聪明的自然语言处理技术。就我个人而言,我想知道改进的机器翻译是否可以通过在其他语言中提供英语 NLP 工具箱来帮助我们更好地理解语言。**

从积极的方面来看,虚拟现实中流畅的对话式语音界面似乎并不遥远。即使是晦涩、怪异、难学的语言,比如丹麦语。

现在,我们可以开始使用关键词检测来使虚拟环境更加动态和反应灵敏。

参考

[1] 李普曼,R.P .,1997。机器和人类的语音识别。言语交际22 (1),第 1–15 页。

[2] Glenn,M.L .,Strassel,s .,Lee,h .,Maeda,k .,Zakhary,r .和 Li,x .,2010 年 5 月。一致性、容量和效率的转录方法。在 LREC

[3] 熊,w .,Droppo,j .,黄,x .,塞德,f .,萨尔茨,m .,斯托尔克,a .,于,d .,茨威格,g .,2016。在会话语音识别中实现人类对等。 arXiv 预印本 arXiv:1610.05256

使用神经网络的语音分类:基础

原文:https://towardsdatascience.com/speech-classification-using-neural-networks-the-basics-e5b08d6928b7?source=collection_archive---------7-----------------------

最近,我开始研究一个语音分类问题,因为我对语音/音频处理知之甚少,所以我不得不回顾一下最基本的内容。在这篇文章中,我想回顾一下我学到的一些东西。为此,我想研究“语音 MNIST”数据集,即一组记录的口语数字。

你可以在这里找到数据集

数据集包含以下内容:

  • 3 个扬声器
  • 1,500 个录音(每个扬声器每个数字 50 个)

如题所述,这是一个分类问题,我们得到一段录音,需要预测其中所说的数字。

我想尝试不同的方法来解决这个问题,并逐步了解什么更好,为什么。

首先,我们来了解一下录音到底是什么。我将使用优秀的librosa库:

wav, sr = librosa.load(DATA_DIR + random_file)
print 'sr:', sr
print 'wav shape:', wav.shape# OUTPUT
sr: 22050
wav shape: (9609,)

load方法返回 2 个值,第一个是实际声波,第二个是‘采样率’。如你所知,“声音”是一种模拟信号,为了使其数字化,并能够用类似于numpy阵列的东西来表示,我们必须对原始信号进行采样。简而言之,采样只是从原始信号中“选择”有限数量的点,并丢弃其余的点。我们可以将这些选定的点存储在一个数组中,并对其执行不同的离散操作。奈奎斯特-香农采样定理表明,如果我们的采样速率足够高,我们就能够捕获信号中的所有信息,甚至完全恢复它。

Signal sampling representation. The continuous (analog) signal is represented with a green colored line while the discrete samples are indicated by the blue vertical lines.

采样率非常重要,我们稍后会在不同的算法中用到它。它的标度是赫兹,即每秒的点数(样本数)。在我们的示例中,sr=22050 我们每秒有 22050 个样本,我们的波形大小为 9609,我们可以使用以下公式计算音频长度:

length = wav.shape[0]/float(sr) = 0.435 secs

实际上,我们的实际采样率不是 22050,librosa隐式地对我们的文件进行重新采样,以获得更标准的 22050 SR。要获得原始采样率,我们可以使用sr=Falseload方法:

wav, sr = librosa.load(DATA_DIR + random_file, sr=None)
print 'sr:', sr
print 'wav shape:', wav.shape
print 'length:', sr/wav.shape[0], 'secs'# OUTPUT
sr: 8000
wav shape: (3486,)
length: 0.43575 secs

音频长度与预期保持一致。

当我们处理具有不同采样率的文件时,重采样非常有用。我们暂时坚持这一点。

实际声音是这样的:

plt.plot(wav)

如你所见,这是一个非常复杂的信号,很难从中找出规律。就算放大看,还是挺复杂的。

plt.plot(wav[4000:4200])

200 samples out of 9000 of the original file

首先,我们将尝试“原样”使用这些波形,并尝试建立一个神经网络来为我们预测口语数字。实际上,几乎从来没有这样做过。我这样做只是为了理解从原始文件到完整解决方案的不同步骤。

但首先,我们需要准备数据集。正如我们前面看到的,我们有 1500 个由 3 个说话者说出的数字的录音。将数据分割成经典的 80-20 训练测试分割可能不是一个好主意,因为我们的训练数据将包含与测试数据中相同的扬声器,并且可能会提供非常好的结果,而对其他扬声器提供非常差的结果。测试我们算法的正确方法是在两个扬声器上训练它,在第三个扬声器上测试它。这样,我们将有一个非常小的训练和测试集,但对于本文的目的来说,这已经足够了。在现实生活中,我们必须在许多不同性别、种族、口音等的人身上测试我们的算法,以便真正了解我们的算法有多好。

我们的数据看起来像这样:

X = []
y = []
pad = lambda a, i: a[0: i] if a.shape[0] > i else np.hstack((a, np.zeros(i - a.shape[0])))
for fname in os.listdir(DATA_DIR):
    struct = fname.split('_')
    digit = struct[0]
    wav, sr = librosa.load(DATA_DIR + fname)
    padded = pad(wav, 30000)
    X.append(padded)
    y.append(digit)X = np.vstack(X)
y = np.array(y)print 'X:', X.shape
print 'y:', y.shape# OUTPUT
X: (1500, 30000)
y: (1500,)

我们将使用一个简单的 MLP 网络与一个单一的隐藏层开始:

ip = Input(shape=(X[0].shape))
hidden = Dense(128, activation='relu')(ip)
op = Dense(10, activation='softmax')(hidden)
model = Model(input=ip, output=op)model.summary()# OUTPUT
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, 30000)             0         
_________________________________________________________________
dense_1 (Dense)              (None, 128)               3840128   
_________________________________________________________________
dense_2 (Dense)              (None, 10)                1290      
=================================================================
Total params: 3,841,418
Trainable params: 3,841,418
Non-trainable params: 0
_________________________________________________________________

让我们来训练它:

model.compile(loss='categorical_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])history = model.fit(train_X,
          train_y,
          epochs=10,
          batch_size=32,
          validation_data=(test_X, test_y))plt.plot(history.history['acc'], label='Train Accuracy')
plt.plot(history.history['val_acc'], label='Validation Accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()

您可以看到,我们在训练数据上的准确性还可以,但在测试数据上却很糟糕。

我们可以尝试不同的网络架构来解决这个问题,但正如我前面所说,在实践中,raw waves 几乎从未使用过。所以我们将转向更标准的方式来表示声音文件:声谱图!

在讲光谱图之前,我们先来讲讲余弦波。

余弦波看起来像这样:

signal = np.cos(np.arange(0, 20, 0.2))
plt.plot(signal)

你可以看到这是一个非常简单的信号,其中有一个清晰的模式。我们可以通过改变余弦波的振幅和频率来控制余弦波。

signal = 2*np.cos(np.arange(0, 20, 0.2)*2)
plt.plot(signal)

通过将不同频率的不同余弦波叠加在一起,我们可以实现非常复杂的波。

cos1 = np.cos(np.arange(0, 20, 0.2))
cos2 = 2*np.cos(np.arange(0, 20, 0.2)*2)
cos3 = 8*np.cos(np.arange(0, 20, 0.2)*4)
signal = cos1 + cos2 + cos3
plt.plot(signal)

我们可以(至少)用两种方式来表示上面的波。我们可以使用非常复杂的整个 100 大小的信号,或者,我们可以只存储该信号中使用的频率。这是一种更简单的数据表示方式,占用的空间也少得多。这里我们有 3 个不同振幅的不同频率。那三个频率到底是什么?这是一个很好的问题,答案是:这取决于采样率(我稍后将展示如何)。

我们需要一种方法,给定一个原始波(时间的函数),将返回给我们其中的频率。这就是傅立叶变换的作用!我不会深究傅立叶变换是如何工作的,所以让我们把它当作一个黑匣子,给我们一个声波的频率。如果你想更好的理解,我推荐这个视频。

我们需要确定我们的波的采样率是多少,或者类似地,我们的信号的长度是多少。为了方便起见,我们用一秒钟。我们有 100 品脱,所以我们的采样率是 100 赫兹。

现在我们可以对信号进行傅立叶变换。我们将使用“快速傅立叶变换”算法来计算 O(nlogn)中的离散傅立叶变换。为此我们将使用numpy

fft = np.fft.fft(signal)[:50]
fft = np.abs(fft)
plt.plot(fft)

我们在这里看到 3 种频率:4、7 和 14 位每秒,正如我们建立我们的信号(欢迎您检查)。

这里我们只使用返回值的前半部分,因为 FFT 的结果是对称的。

原来每一个声音(甚至是人的语音)都是由很多这样的不同频率的基本余弦波组成的。

我们有办法从任何声音信号中获取频率,但人类语音不是静态噪声,它会随着时间的推移而变化,因此为了正确地表示人类语音,我们将把我们的记录分成小窗口,并计算每个窗口中使用的频率。为此,我们可以使用短时傅立叶变换

D = librosa.amplitude_to_db(np.abs(librosa.stft(wav)), ref=np.max)
librosa.display.specshow(D, y_axis='linear')

我们可以在录音中间看到一些低频声音。这是典型的男性声音。这就是光谱图!它向我们展示了录音不同部分的不同频率。

让我们看一下代码:

librosa.stft为我们计算短时傅立叶变换。返回值是一个矩阵,其中 X 是窗口号,Y 是频率。STFT 值是复数。我们只需要使用它的实部来找到频率系数。

np.absstft的绝对值,如果是复数,则返回实部的绝对值。

librosa.amplitude_to_db将数值转换为分贝。

概括一下:

傅立叶变换 —将时间幅度信号转换为频率幅度函数的过程

离散傅里叶变换 (DST) —傅里叶变换离散信号

快速傅立叶变换(FFT)——一种能够以 O(nlogn)而不是 O(n)计算傅立叶变换的算法

短时傅立叶变换(STFT)——将记录分成小窗口并计算每个窗口 DST 的算法

很好,现在我们能够计算数据集中每个文件的光谱图,然后用它们来分类数字。光谱图的真正好处是它们像 2D 图像,所以我们可以对它们使用图像分类技术,特别是卷积神经网络!

ip = Input(shape=train_X_ex[0].shape)
m = Conv2D(32, kernel_size=(4, 4), activation='relu', padding='same')(ip)
m = MaxPooling2D(pool_size=(4, 4))(m)
m = Dropout(0.2)(m)
m = Conv2D(64, kernel_size=(4, 4), activation='relu')(ip)
m = MaxPooling2D(pool_size=(4, 4))(m)
m = Dropout(0.2)(m)
m = Flatten()(m)
m = Dense(32, activation='relu')(m)
op = Dense(10, activation='softmax')(m)model = Model(input=ip, output=op)model.summary()# OUTPUT
Layer (type)                 Output Shape              Param #   
=================================================================
input_2 (InputLayer)         (None, 1025, 40, 1)       0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 1022, 37, 64)      1088      
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 255, 9, 64)        0         
_________________________________________________________________
dropout_3 (Dropout)          (None, 255, 9, 64)        0         
_________________________________________________________________
flatten_2 (Flatten)          (None, 146880)            0         
_________________________________________________________________
dense_3 (Dense)              (None, 32)                4700192   
_________________________________________________________________
dense_4 (Dense)              (None, 10)                330       
=================================================================
Total params: 4,701,610
Trainable params: 4,701,610
Non-trainable params: 0
____________________________

好多了!在我们的测试集上,我们得到了大约 65%的准确率,这离完美还差得很远,但这比使用原始波形要好得多。借助更多的数据和对我们网络的更多微调,我们可能会得到更好的结果。

结论

我们看到了一个非常基本的语音分类实现。为机器学习表示声音一点也不简单,有很多方法,也做了很多研究。傅立叶变换是信号处理的基础,几乎无处不在,是处理声音的基础。

你可以在这里找到我的实验代码。

下一个要探索的话题:

  • 梅尔标度光谱图
  • 梅尔频率倒谱系数

语音识别:懒狗初级读本

原文:https://towardsdatascience.com/speech-recognition-a-lazy-dog-primer-6504ab4dccaf?source=collection_archive---------3-----------------------

我和一个好朋友最近在吃饭时聊起了语音识别应用。没错,我们就是那些人。隔着一张桌子,刻板的极客们对技术、创业和变革变得兴致勃勃。你可以走进几乎任何一家硅谷咖啡店,买一杯超定制的拿铁咖啡,仅仅五分钟后,你就可以成为风险投资或移动开发领域的迷你专家——或者至少感觉自己是专家。

回到我们的故事。我们正在进行有趣的讨论,在讨论过程中,我的朋友让我解释自动语音识别(ASR)实际上是如何工作的。我有点困惑,被迫检查我的假设,但意识到你不需要成为底层技术的专家,就能判断语音到文本的质量或对产品适合度和用户体验进行推理。那天晚上剩下的时间里,我们投入到了语音识别的深度探索中,揭开神秘的面纱,鼓励这个领域的奇妙创造力涌现出来。我们有时也会触及我知识的极限,促使我回头去追赶。

这是我关于语音识别的愚蠢的“懒狗入门”——只是为了吊你的胃口。如果你真的想了解 ASR,我鼓励你参加课程,阅读同行评审的论文(从深度学习方法到旧的 hmm、DTW、模型),亲自动手,了解声学模型、频谱图和解码器。你会喜欢的。

与此同时,带走这些信息中的一些。你永远不知道什么时候你会在排队买咖啡的时候被迫跳进一场语音识别辩论。

人类最清楚。暂时如此。

尽管有这些缺陷、盲点和特性,以自动语音识别为特色的应用程序正开始为广大用户提供真正的价值。语音到文本有许多风格和体现:手机伴侣应用程序,笨重的客户服务导航系统,自称的智能扬声器,过度宣传的智能助手,以及我最喜欢的——智能电梯

直观地说,基于机器的语音识别模仿了人们理解语音的过程。人类已经进化了他们的身体器官,能够产生可辨别的声音(通过声带、共振和发音),甚至在嘈杂的环境中接收和辨别这些声音(外-中-内耳管道),并应用他们过去的经验推理和解码不清楚的话语成为连贯、有意义的信息(通过计算和编码的经验)。

机器遵循相似的路径。为了便于解释,我们将在这本初级读本中使用一个更传统的语音识别模型。就拿名句敏捷的棕狐狸跳过懒狗来说吧,从语音生成,一直到语音识别。

1.制作:只要说一句话

当说出这句话时,敏捷的棕色狐狸跳过懒惰的狗,“你产生了在你周围传播的声音。你可以把声音的原始结构想象成一个波形。

组成单词的基本声音单位被称为音素,你可以把它们想象成上面波形中的小段。它们是元音如/e/、/a/、/o/和辅音如/p/、/b/、/k/,通常用斜线表示。其中一些音素非常接近,很容易混淆,尤其是在嘈杂的信道中,例如在打电话时。例如:/p/和/b/在“ P aul ”和“ball”中相似;/g/和/k/在“goal”和“coal”中类似。

如果我们仅仅改变句子中的几个音素,波形看起来是相似的,但是意思完全偏离了:

音素混淆在嘈杂的情况下会加剧——这是我们句子的模糊版本。听到声音,解释它,并把它拼凑成有意义的东西不是一件容易的事情。

2.有人听到了吗?

这就是机器开始工作的地方。它需要倾听、捕捉声音,并将其转换成我们可以使用的标准格式。幸运的是,很长时间以来,麦克风一直是一种商品(例如,在移动设备、笔记本电脑、扬声器等中)。)而且捕捉到的声音质量也尽善尽美。机器使用廉价、无处不在的音频电路记录声音,并将其存储为相应的波形——然后开始工作。

出于所有实际目的,我们不会担心用于清理传入声音的硬件和软件过滤器的魔力,而只是假设质量足够高。

3.音素:解析那个声音!

还记得音素吗?在这个阶段,我们的算法将波形分割成它的组成声音单元:音素。在理想情况下,我们的波形将被转换成以下音素序列:

/ðəkwɪk braʊn·福克斯·ʤʌmps ˈoʊvərðəˈleɪzi dɔg/

然而,由于噪音、口音、犹豫、言语障碍和特殊习惯,会有一定程度的不确定性。在这些情况下,算法(称为解码器)会分支(思考:对冲他们的赌注)并考虑相同声音的替代音素序列:

  • 你可能会说/ dɔg/,但是/达克/和/dʌk /也是可行的猜测。
  • 在嘈杂的环境中,你可能会说出 /ˈleɪzi /或/ ˈleɪsi /。

在这个阶段,我们可能会做出艰难的选择,选择一个音素序列。然而,聪明的算法很可能会将多个候选者带到语音识别过程的后续阶段。通过这种方式,他们将不同类型的信号(从声音到意义)结合起来,并推迟做出决定,直到所有的证据都汇总起来。在上面的例子中,假设算法评估了备选方案,并携带得分为 0.7 的序列/ dɔg/ 和得分为 0.2 的序列/ dʌk /

4.话:蕾丝还是懒?

好的,这不是一个单独的阶段,但为了清楚起见,我们将假装它是。实际上,解码器在更长的序列上进行优化,并基于概率矩阵生成可能的句子。

之前,我们已经确定了一组候选音素序列——基于原始波形的合理序列。在这个阶段,我们把这些序列解码成可能的单词。例如,我们会解码/ dɔg/ →“狗”、/dak/ →“医生”、/ dʌk/ →“鸭子”。这不是一个直接的、确定的映射,因为人类产生的语音受到许多因素的影响:地理、年龄和语音模式、发音能力、教育等。

例如,假设单词“dog”的发音带有美国南方口音、苏格兰口音、波士顿口音、澳大利亚口音和东欧口音。这些重音会导致不同的音素序列,但最终需要映射到单词“dog”中。

就像以前一样,该算法评估许多备选方案/候选单词,对它们进行评分,并沿着管道进一步传播,而不是进行单一的最佳猜测。在我们的例子中,基于语音(和历史)证据,单词在这个阶段被分配概率分数:例如,“”的分数为 0.73,“文档”的分数为 0.55,以及“鸭子”的分数为 0.18。

请记住,像“ doc 这样的单词的证据可以从几个可能的音素序列中获得——例如,从美国口音下的 /dak/ 或东欧口音下的/ dɔk /中获得。语音识别需要适用于所有人,而不仅仅是电视节目主持人发音和标准口音的母语人士。

“The quick brown fox jumps over the lazy dog” OR “The quick brown fax bumps over the lady doc”? Credit: Roy Jones.

5.句子:人类会怎么做?

在这个最后阶段(出于解释目的,此处人为分离),该算法评估候选词的所有组合——它在前面阶段已经识别的好猜测。它查找这些单词的组合(例如,“懒 doc ”、“懒狗”、“莱西 doc ”等)。)在其知识库中,被称为语言模型。语言模型是使用大量人类生成的文本构建的,从口语转录的语音到新闻故事。它们对共现统计进行编码,例如单词“ dog ”跟在单词“lazy”后面的频率与其他单词的频率。使用这些语言模型统计数据,算法可以推断一个人说出特定短语和句子的可能性有多大。

例如,“跳过”比“颠簸提供”更可能是一个人说出的短语。短语“懒狗”比“莱西多克”更有可能,但是“多克女士”也有合理的分量。

如果你想玩准语言模型,你可以使用谷歌的搜索引擎作为代理。试一试:

在我们的例子中,当面对“ðəkwɪk braʊn·福克斯·ʤʌmps ˈoʊvərðəˈleɪzi dɔg”时,该算法从音素、单词、短语,最后评估候选句子的总体概率,例如:

  • "快速的棕色人种跳过了懒惰的医生"
  • "敏捷的布朗克斯撞倒了一只带花边的狗"
  • "敏捷的棕色狐狸跳过懒惰的狗"
  • "T30 快速棕色传真取消了对多克女士的报价"

有了分段(音素/单词/短语)概率分数,该算法识别出最佳句子,即给定原始信号时具有最高总体概率的句子。在我们的例子中,最佳句子可能是“ ”这只敏捷的棕色狐狸跳过了那只懒惰的狗 ”,因此算法会产生它作为输出。

在这一点上,根据语音识别系统的工作表现,你会 a)高兴地跳过或者 b)痛苦和沮丧地咆哮。

限制与进步

在移动设备上,计算是有限的,时间是至关重要的——你不想在看到转录之前等待一两分钟。网络经常是不稳定的,这使得总是在云中执行语音识别,然后将结果发送回你的手机是不切实际的。由于这些限制,有限的语音识别模型通常部署在移动设备上。这意味着探索的替代语句更少,优化的范围更窄,语言模型等资源的覆盖范围更有限。

然而,当网络延迟允许时,语音到文本引擎的移动部署由强大的云部署支持,以提高准确性。

深度学习的最新进展对自动语音识别领域产生了重大影响。例如,最近的模型正在寻求同时学习 ASR 系统的所有元素:发音、声学和语言模型。目标是构建高精度系统,减少人工参与(即特征工程),并减少内存占用,非常适合部署在移动设备上。

作为一个语音到文本的超级用户,我真的很期待得到我的手(voice on?)拥有多种语言的可靠而准确的模型的智能助手。我们绝不是在那里,但我们肯定已经跨过了价值超越挫折的门槛。


如果你喜欢这个帖子,请鼓掌👏让我知道:)

Lucian LitaYoyo Labs的创始人,之前是 BlueKai、Intuit 和 Siemens Healthcare 的 Level Up 分析和数据领导者。

树莓 Pi 3 B 上的语音识别

原文:https://towardsdatascience.com/speech-recognition-on-raspberry-pi-3-b-8351c418dc25?source=collection_archive---------11-----------------------

网上分享的大多数 Raspberry Pi 语音转文本示例似乎依赖于各种云解决方案(例如谷歌云语音转文本)进行实际的音频处理。本文将向您展示如何在您的 Raspberry Pi 上配置一个不需要第三方云服务的“离线”语音处理解决方案。

我们将使用 CMUSphinx ,一组由卡耐基梅隆大学开发的连续语音、非特定人语音识别系统。

第一步。打开您的虚拟环境(除非您想要全局安装)。使用 virtualenv 的好处在我之前关于 OpenCV 的文章中有解释。我的名为“cv ”,我通过发出以下命令启动它:

workon cv

我的 shell 提示符会相应地改变:

第二步。更新包列表并获取包的新版本(可能需要几分钟):

sudo apt-get update 
sudo apt-get upgrade

第三步。如果您要使用麦克风(相对于处理音频文件或从其他设备接收音频流),请验证您的声卡配置:

cat /proc/asound/cards

我的树莓派 3B 显示如下:

(cv) pi@raspberrypi:~ $ cat /proc/asound/cards
 0 [ALSA ]: bcm2835_alsa - bcm2835 ALSA 
            bcm2835 ALSA 
(cv) pi@raspberrypi:~ $

第四步。安装 Bison (GNU 解析器生成器):

sudo apt-get install bison

第五步。安装 ALSA(高级 Linux 声音架构)库:

sudo apt-get install libasound2-dev

第六步。下载并解压 sphinxbase (最新版本为 5 个真实版本,此处显示):

wget [https://sourceforge.net/projects/cmusphinx/files/sphinxbase/5prealpha/sphinxbase-5prealpha.tar.gz](https://sourceforge.net/projects/cmusphinx/files/sphinxbase/5prealpha/sphinxbase-5prealpha.tar.gz)tar -xzvf sphinxbase-5prealpha.tar.gz

第七步。安装 SWIG。SWIG 是一个接口编译器,它将用 C 和 C++编写的程序与 Python 等脚本语言连接起来:

sudo apt-get install swig

第八步。进入刚刚提取的 sphinxbase 目录并编译 sphinx base——确保没有错误:

cd sphinxbase-5prealpha 
./configure --enable-fixed 
make clean all 
sudo make install

第九步。下载并解压 pocketsphinx (同样,最新版本是 5prealpha,此处显示为),但首先向上一个目录:

cd .. wget [https://sourceforge.net/projects/cmusphinx/files/pocketsphinx/5prealpha/pocketsphinx-5prealpha.tar.gz](https://sourceforge.net/projects/cmusphinx/files/pocketsphinx/5prealpha/pocketsphinx-5prealpha.tar.gz)tar -xzvf pocketsphinx-5prealpha.tar.gz

第十步。进入刚刚提取的 pocketsphinx 目录并编译 pocket sphinx——确保没有错误:

cd pocketsphinx-5prealpha 
./configure 
make 
sudo make install 
export LD_LIBRARY_PATH=/usr/local/lib 
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig

第十一步。获取一些音频文件进行测试。我们将使用来自开放语音库的几个美国英语样本:

wget [http://www.voiptroubleshooter.com/open_speech/american/OSR_us_000_0019_8k.wav](http://www.voiptroubleshooter.com/open_speech/american/OSR_us_000_0019_8k.wav) wget [http://www.voiptroubleshooter.com/open_speech/american/OSR_us_000_0030_8k.wav](http://www.voiptroubleshooter.com/open_speech/american/OSR_us_000_0030_8k.wav)

第十二步。这是我在一个样本上运行斯芬克斯。我下载的 wav 文件:

pocketsphinx_continuous -samprate 8000 -hmm en-us-8khz -infile OSR_us_000_0030_8k.wav

正如你从我下面的屏幕记录中看到的,这个过程不是很快,所以我需要优化:

[## 使用 Sphinx 解析一个小的。wav 文件

迈克尔·阿拉托尔采夫录制

asciinema.org](https://asciinema.org/a/3UNRmoCxmNOj5KfkKpR810ZUB)

出了问题怎么办?
如果你第一次编译或运行 pocketsphinxcontinuous 时遇到错误,请在下面的评论中分享你的错误信息,我会添加一些故障排除步骤。在我的例子中,我必须帮助编译器找到一些库。我还不得不下载一个 8kHz 的 Sphinx 声学模型,以便处理我的。wav 样本。

祝你好运!

原载于 2018 年 6 月 28 日www.alatortsev.com

语音合成即服务

原文:https://towardsdatascience.com/speech-synthesis-as-a-service-5c65d17e62f4?source=collection_archive---------4-----------------------

MLaaS 第 2 部分:墙上的扬声器,谁的声音最好听?

目录

听起来很自然的机器人声音

随着文本到语音系统性能的不断提高,术语“机器人声音”可能很快会被重新定义。

一次一个改进,我们将会把语音合成看作是一种补充,有时是人类配音天才和播音员的竞争对手。

描述 WaveNet[1]、Tacotron[2]、DeepVoice[3]和其他系统的出版物是通过声学形式的图灵测试的重要里程碑。

然而,训练语音合成器仍然是一项耗时、耗费资源,有时甚至令人沮丧的任务。Github 知识库上发布的关于复制研究成果的问题和演示就是这一事实的证明。

相比之下,本系列涵盖的所有云计算平台——Amazon Web Services、Google Cloud、Microsoft Azure 和 IBM Watson——都可以在服务调用时实现文本到语音的转换。

这为快速开发具有越来越灵活、听起来越来越自然的语音的引人入胜的对话应用程序提供了令人兴奋的机会。

本文提供了一个用例列表、语音合成标记语言(SSML)的介绍以及四种服务的比较,包括示例输出、示例代码和一个小型研究的结果。

语音合成可以做什么?

如果您的目标是一次性地将一小段或中等长度的文本转换成语音,目前还没有任何技术可以与录音棚中配音人员的工作相媲美。

另一方面,如果你想反复制作大量个性化文本的录音,语音合成几乎肯定是正确的选择。

以下是文本到语音转换服务特别适合的十种应用:

  • 联络中心:除非您的客户有真正独特和非常具体的查询,否则提供自动化支持可能是一个可行的选择。即时回复,加上一定程度的灵活性(从客户姓名的正确发音开始),有助于获得和保留客户。
  • 创造语言学习材料:一个以人类为母语的人并不总是能够展示正确的发音。语音合成可以与跟踪语言学习者的兴趣和他所取得的进步的方法相结合,以生成个性化的音频内容。
  • 多语言内容:一些组织使用语音合成为其全球员工创建并定期更新多种语言的培训材料。
  • 内容再利用:文本到语音转换扩大了内容创作者的机会范围。通过更自然的语音,文章可以到达那些喜欢在通勤上班或在健身房锻炼时听有声书和播客的人。结合视觉内容,它还可能打开更具成本效益的视频营销的大门。
  • 敏捷视频(再)制作:动画内容的脚本,比如 explainer 视频,随着项目成员提出新的想法和客户要求最后的修改而不断发展。文本到语音服务可以生成始终符合最新版本脚本的语音。在项目结束时,最终的脚本可以被专业的人造录音所取代。
  • 提醒:虚拟助理产品的一个受欢迎的特性是能够设置提醒。计算机生成的语音可以让你清醒,有助于习惯的形成,并保留那些有可能从最前面溜走的待办事项的记忆。这里有很大的个性化空间。你更喜欢被轻柔平静的声音叫醒吗?或者你想用一句激励人心的名言开始你的一天吗?
  • 人工播音员:FM Wakayama 是一家私人资助的非营利组织,制作社区广播,它开发了一种人工播音员,用于天气预报、一般新闻和紧急信息。当 2017 年 9 月台风袭击和歌山市时,这种基于云的系统继续全天可靠且经济高效地提供灾害信息。
  • 智能家居设备:无论是机器人吸尘器让你知道它卡在哪里,冰箱让你确认自动生成的购物清单,还是安全系统通知你有人入侵:语音合成让智能家居设备有了声音。
  • 同步:定时信息是语音合成过程的副产品。语音标记描述了在给定的音频流中单词的发音或相关动作的开始和结束位置。在游戏中,这些信息通过使角色的面部表情与他们的讲话内容同步来帮助他们活灵活现。
  • 测试:语音合成即服务为基于语音的应用领域带来了高效的分割测试。可能的实验范围远远超出了口语内容。使用 SSML,实验者可以尝试不同的声音,表情和韵律设置。

SSML

语音合成服务的输入或者作为原始文本提供,或者以语音合成标记语言(SSML) 文档的形式提供。

SSML 文件定义了说什么和怎么说。

因为我们将要讨论的所有四个服务都使用这种标记语言,所以我认为提供一个关于大多数常用元素和属性的介绍会很有帮助。

根元素

SSML 文档中根元素的名称是speak

一句最简单的“你好,世界!”-style 示例如下所示:

“Hello, world!” in SSML

请注意,versionxml:lang有时会被遗漏,尽管规范声明它们是必需的属性。

解释

say-as元素定义了如何解释包含的文本。支持 SSML 标准的语音合成器为此元素的interpret-as 属性提供了不同的设置。

例如,为了拼出原本会被当作单词来读的字符串,服务可以支持拼出解释。

Instructing the speech synthesizer to spell out Google’s ticker symbol

文本结构

可选元素p sw分别用于定义段落、句子和单词。

语言属性由子元素继承。例如,假设您想为说美国英语的人学习德语创建一个资源。在这种情况下, en-US 被应用于根元素,而 de-DE 被设置用于文档中的单个元素。

Text structuring and the use of multiple languages in SSML

破裂

有时候,沉默可能是最吸引人的内容。

在 SSML,讲话是用break元素停顿的。暂停的长度由time属性决定。

Creating a moderately dramatic pause in SSML

请注意,合成器可能会自动在句子或段落后添加停顿。

强调

emphasis实现了名字的承诺。可选的level属性可以设置为三个可能值之一:减少中度强烈

Emphasizing words in SSML

代替

在语音输出中,sub元素中包含的单词被替换为不同的单词。

常见的用例包括缩写和符号。

The chemical symbol Fr is substituted with the name “Francium”.

韵律学

prosody元件控制合成语音的音高、语速和音量。

volume可根据预定义水平或相对于当前音量的变化进行设置:

It’s getting loud in here.

语音rate可以通过预定义的级别或默认速率的百分比来指定。

Setting the speech rate with pre-defined values and relative to the default rate.

类似地,pitch也有预设和百分比设置:

Still waiting for the neural singing feature …

标记

mark标签是一个自结束标签,需要一个name属性。

它的唯一目的是在 SSML 文档中放置一个标记。它不影响语音合成过程的输出。

标记可用于检索文档中特定位置的计时信息。

The self-closing mark tag does not affect the output.

谁的声音最好听?

在这一部分,我们来看看四种语音合成服务:亚马逊 Polly、谷歌云文本到语音、微软的认知服务文本到语音和 IBM Watson 文本到语音。

为了获得这些服务生成的语音的主观评级,进行了一项小型研究。三名参与者(两名女性,一名男性)听了转换成 MP3 文件的维基新闻文章摘录。

这五篇文章涵盖了一辆汽车撞进牙科诊所[4],2026 年 FIFA 世界杯的比赛场地[5],微软收购 Github 的计划[6],韩国领导人的一次会晤[7]以及 Netta 在欧洲电视网歌曲大赛上的胜利[8]。

在不知道服务和声音名称的情况下,参与者被随机地一次呈现一个语音输出。他们被要求按照从 1(最差)到 5(最好)的等级来评价他们所听的演讲的自然程度和愉快程度。

对于四种服务中的每一种,使用一种男性和一种女性声音。这总共产生了 120 个评级(三个主题,五篇文章,四个服务,每个服务两个声音)。文本作为原始文本发送给 API,没有经过任何 SSML 优化。

研究完成后,生成的语音样本的播放列表被上传到 SoundCloud。

下表概述了调查结果:

亚马逊波利

亚马逊的文本到语音转换服务 Polly 于 2016 年底宣布。

在撰写本文时,它支持 25 种语言,从丹麦语和澳大利亚英语到葡萄牙语、巴西语和土耳其语。

更多的声音有几个好处。生成的语音可以用于对话,代表不同的人物角色,实现更高程度的本地化。

波利为美国英语提供了八种不同的声音。研究中使用的声音名字分别是乔安娜马修

应该注意的是,亚马逊已经承诺不会取消任何通过 Polly 提供的当前或未来的声音。

在我进行的实验中,Polly 获得了第二高的综合评分。就演讲的愉快程度而言,亚马逊的服务击败了谷歌的云转文本 API。

以下是呈现给参与者的演讲输出:

Samples generated with the Amazon Polly voices Joanna and Matthew

可以为用mark元素指定的位置以及单词和句子的级别获得语音标记。此外,Polly 还允许您检索代表说话者说一个单词时面部和嘴部位置的视位

控制台是试验 SSML 并获得可用功能集的第一印象的好方法。

每秒允许 100 个请求。输入最多可包含 3,000 个计费字符。SSML 标签不算计费字符。每个请求的输出限于 10 分钟的合成语音。

定价模型很简单。在最初的 12 个月里,第一批 500 万个字符出现在亚马逊上。在这一层之上,请求按现收现付的方式计费,每 100 万个字符 4 美元。

Speech synthesis with Amazon Polly

Polly 支持我们提到的所有 SSML 标签以及两个扩展:呼吸声音效果

自闭[amazon:breath](https://docs.aws.amazon.com/polly/latest/dg/supported-ssml.html#breath-tag)标签指示人工扬声器进行指定长度音量的(相当逼真的)呼吸。

声音效果包括耳语、轻声说话和改变声道长度以使扬声器听起来更大或更小。

Deep voice and heavy breathing Amazon’s SSML extensions

谷歌云文本到语音

谷歌 DeepMind 的研究人员发表的 WaveNet 论文[1]被引用了 250 多次,是语音合成近代史上的一个重要里程碑。

为复制 DeepMind 研究人员取得的成果而兴起的 Github 知识库已经被标上星号和分叉数千次。[9, 10, 11]

在那篇论文描述的一项研究中,受试者被要求对 WaveNet 生成的语音、实际人类语音和两个竞争模型的输出的自然度进行评级。在本文报告的研究中使用的从 1 到 5 的相同尺度上,WaveNet 样本的平均意见得分为 4.2,人类语音为 4.5,竞争模型小于 4。

去年 11 月,谷歌终于发布了期待已久的云文本到语音转换服务的 alpha 版本。在撰写本文时,该服务正处于测试阶段,并且“不打算在关键应用中实时使用”。

这项服务提供基于 WaveNet 的语音合成,以及谷歌所说的标准语音(T5)和非 WaveNet 语音(T7)。

六种可用的 WaveNet 语音是美式英语。根据文档,这些声音与谷歌助手、谷歌搜索和谷歌翻译中使用的声音相同。

这 28 种标准声音涵盖了几种欧洲语言,还包括一些针对亚洲市场的女声。

与其他服务不同的是,这些声音有技术标识符,而不是容易记忆的名字。例如,我使用的两种声音分别被称为 en-US-Wavenet-Aen-US-Wavenet-C.

这是实验中使用的输出播放列表:

Samples generated with the Google Cloud Text-to-Speech voices en-US-Wavenet-A and en-US-Wavenet-C

我自己的结果与 WaveNet 论文中报道的结果相当。在四个竞争对手中,谷歌的服务取得了最高的自然度得分和最好的综合评分。

如果自然的声音是首要考虑,那么这很可能是你的正确选择。

然而,应该指出的是,Amazon Web Services 和 IBM Watson 都提供了更多的功能。谷歌云文本到语音既不支持定时信息,也不支持 SSML 扩展。

WaveNet 功能的额外价格为超过免费层覆盖的前 100 万个字符的请求的每 100 万个字符 16 美元。

每月有 400 万个字符可以用标准语音免费合成。随后的请求会让您为每一百万个字符支付 4 美元。

除了限制每分钟 300 个请求和每个请求 5000 个字符之外,还有每分钟 150000 个字符的配额。

如果你决定使用 Java SDK,确保从名称空间com . Google . cloud . texttospeech中的包 v1beta1 导入(而不是从 v1 包)。

Speech synthesis with Google Cloud Text to Speech

微软认知服务文本到语音

微软的认知服务文本到语音转换(Text To Speech)目前提供预览版。这项服务的最大优势是它提供的本地化程度。

跨越 32 种语言的 80 种声音覆盖了无与伦比的欧洲和亚洲地区。

然而,在这一点上,数量和质量之间存在明显的权衡。两个声音 ZiraRUSBenjaminRUS 产生的输出在实验中得到最差的评分:自然度 3.2,愉悦度 3.33。

可以通过以下播放列表访问为实验生成的样本:

Samples generated with the Microsoft Cognitive Text To Speech voices ZiraRUS and BenjaminRUS

微软的定制功能使用录音室录音和相关脚本作为训练数据,创建了一个独特的声音模型。这项功能目前在私人预览,并仅限于美国英语和中国大陆。

免费层每月覆盖五百万个字符。在 S1 层,用默认声音合成的每一百万个字符的价格是 2 美元。定制模式的语音转文本服务的价格是每 100 万个字符 3 美元,外加每个模式每月 20 美元的费用。

控制台似乎只对其前身 Bing 文本到语音转换 API 可用。

该服务支持没有扩展的 1.0 版本,并限制每个请求的输入为 1024 个字符,这只是一篇新闻文章长度的一小部分。

现存的唯一一个官方 Java 库用于 Android 的开发。然而,与 REST API 的交互是一个简单的两步过程。客户端首先通过提供订阅密钥来获得令牌。这个令牌——有效期为 10 分钟——然后用于从 API 获取合成语音。注意,声音是在 SSML 文档中使用[voice](https://docs.microsoft.com/en-us/azure/cognitive-services/speech-service/how-to-text-to-speech#specify-a-voice)标签指定的。

Speech synthesis with Microsoft Cognitive Services Speech to Text

沃森文本到语音

IBM 为其沃森文本到语音服务引入了两个有趣的 SSML 扩展:富有表现力的 SSML语音转换 SSML。

第一个扩展可用于美国英语语音 Allison 并通过 express-as 元素实现。标签有一个type属性,有三种可能的自描述设置:好消息道歉不确定性

Expressive SSML in Watson Text To Speech

人们可以很容易地看到富有表现力的 SSML 如何增强客户支持解决方案和其他旨在实现逼真对话的应用程序。

虽然 Watson 文本到语音仅支持 7 种语言的 13 种声音,但第二个 SSML 扩展可以创建新的声音。

除了普遍使用的各种默认声音的好处之外,独特的声音可以通过令人难忘的差异化用户体验来增强品牌推广工作。

使用[voice transformation](https://console.bluemix.net/docs/services/text-to-speech/SSML-transformation.html#transformation)元素,客户可以应用内置的转换或定义他们自己的变化,根据三种现有的美国英语替代方案创建新的声音。

使用类型属性的值年轻柔和,可以使三个现有声部的声音更加年轻和柔和

要应用自定义转换,必须将type属性设置为自定义。这通过可选属性提供了对语音不同方面的细粒度控制。可调节的声音特征包括音调、速率、音色、呼吸和声门张力。

在我进行的实验中,Watson 文本到语音的表现略好于微软的服务,但没有达到亚马逊和谷歌提供的自然和愉悦的水平。

实验中用过的声音的名字是艾利森迈克尔。参与者评定的生成样本可通过以下播放列表获得:

Samples with the IBM Watson voices Allison and Michael

除了w标签,我们提到的所有 SSML 元素都被支持。然而,对于美国英语以外的语言,[say-as](https://console.bluemix.net/docs/services/text-to-speech/SSML-elements.html#say-as_element)指令仅限于两种解释:数字字母

可以获得单词和标记的定时信息

精简版计划限制在 10,000 个字符以内。在标准层下,前一百万个字符的合成对消费者是免费的。随后的请求按每 1000 个字符 0.02 美元的费率收费,这使得沃森文本到语音转换成为四种服务中最贵的。

一个网络演示展示了基本功能和 SSML 扩展。

虽然单个请求的正文最多可以有 5,000 个字符,但是每分钟发送的请求数量没有限制。

Java SDK 无缝且直观地工作:

Speech synthesis with IBM Watson

结论

  • 一系列论文描述了新的机器学习方法,这些方法大大缩小了机器生成的语音和人类语音之间的差距。
  • 语音合成服务利用了这些方法,并为训练定制模型的资源密集型过程提供了替代方案。
  • 语音合成即服务加快了灵活的基于语音的应用程序的开发,并使多语言内容的创建、测试和重新利用变得更加简单和经济高效。
  • 语音合成服务的输入作为原始文本或以语音合成标记语言(SSML)格式提供。SSML 文件定义了说什么和怎么说。
  • 谷歌云文本到语音转换功能有限,但获得了最高的自然度评级和最佳的总体主观评级。
  • 亚马逊 Polly 在演讲的愉悦性方面胜过了竞争对手,获得了第二好的总体评分。
  • Watson 文本到语音和 Amazon Polly 提供了丰富的功能集,包括有用的 SSML 扩展和定时信息。
  • 微软认知服务“文本到语音”提供了最广泛的声音,但是得到了最差的主观评价。

感谢您的阅读!如果你喜欢这篇文章,请点击“鼓掌”按钮,跟随我了解更多关于云中机器学习服务的信息。

此外,让我知道如果你有一个项目在这个空间,你想讨论。

参考

[1]范·登·奥尔德,a .,迪耶曼,s .,曾,h .,西蒙扬,k .,维尼亚尔斯,o .,格雷夫斯,a .,卡尔奇布伦纳,n .,老 a .,卡武克库奥卢,k .,2016。Wavenet:原始音频的生成模型。 arXiv 预印本 arXiv:1609.03499

[2]王,y .,斯凯里-瑞安,R.J .,斯坦顿,d .,吴,y .,韦斯,R.J .,贾伊特利,n .,杨,z .,肖,y .,陈,z .,本吉奥,s .和勒,q .,2017 年。Tacotron:走向端到端语音合成。 arXiv 预印本 arXiv:1703.10135

[3]平,w .,彭,k .,吉比安斯基,a .,阿里克,s .,坎南,a .,纳朗,s .,赖曼,j .和米勒,j .,2018。深度语音 3:使用卷积序列学习缩放文本到语音。在徐健。第六届国际学习代表会议

[4]维基新闻撰稿人。一辆空中轿车冲进加州圣安娜的牙科诊所。在 Wikinews,你可以写的免费新闻来源。

[5]维基新闻撰稿人。足球:加拿大、墨西哥和美国联合申办 2026 年世界杯。在 Wikinews,你可以写的免费新闻来源。

[6]维基新闻撰稿人。微软宣布计划以 75 亿美元收购 GitHub。在 Wikinews,你可以写的免费新闻来源。

[7]维基新闻撰稿人。韩美峰会取消几天后,韩国领导人文在寅和金正日会晤。在 Wikinews,你可以写的免费新闻来源。

[8]维基新闻撰稿人。Netta 为以色列赢得欧洲歌唱大赛。在 Wikinews,你可以写的免费新闻来源。

[9]https://github.com/ibab/tensorflow-wavenet

https://github.com/tomlepaine/fast-wavenet

https://github.com/basveeling/wavenet

演讲:跨行业大数据分析的承诺

原文:https://towardsdatascience.com/speech-the-promise-of-cross-industry-big-data-analytics-73fbec8e4d0?source=collection_archive---------16-----------------------

我最近在 多伦多机器学习峰会 2018 上发表了一篇演讲( 幻灯片 )。

………………………………….

下面的文章紧跟在演讲之后。

我是普拉杰克塔,普拉杰克塔·哈尔卡·尼甘。我是一名训练有素的经济学家,不知何故,我成功地催眠了三个不同大陆的三家央行,让它们相信我是一个好央行。一路走来,我写了两本书,搬到了加拿大,成为了一名母亲,然后我做了意想不到的事情——我跳上了大数据和机器学习的潮流。

我在 TELUS,目前专注于数据估值和人工智能生态系统战略。我今天要分享的观察和见解从我在 TELUS 的研究和互动中受益匪浅。然而,本文所表达的观点是我个人的,并不代表我过去或现在的雇主的官方立场。

………………………………………..

这是一个满是盲人的房间。如果不是,我们怎么会错过“房间里的大象?”你能看见它吗?你呢。你呢。没有吗?

我用一个比喻来解释。你听说过六个盲人和大象吗?这个寓言起源于古印度文献,它出现在我上学时的一本语言教科书中,并且一直伴随着我。

引用约翰·萨克斯的诗,

“有六个印度尼西亚人
很有学问
他们去看大象
虽然他们都是盲人
但是每个人的观察
都可以满足他的心灵”

据说,一个遥远国度的国王想知道大象长什么样。所以他宣布奖励任何能准确描述他的人。六个盲人决定试试他们的运气,他们去寻找一头大象。当他们遇到一个,他们试图破译它看起来像什么。因为他们是盲人,他们不得不用手抓住大象。然而事实是,因为大象太大了,他们每个人只能抓住一部分——一个抓住象牙,另一个抓住尾巴,还有一个抓住腿,等等。每个人都很高兴,并返回告诉国王,急于为自己要求奖励。每个盲人都确信自己发现了大象的全部真相,并小心翼翼地保护自己的发现不被其他五个人发现。回到皇家法庭,他们轮流描述大象。抓着象牙的人说大象光滑而锋利,摸着腿的人说它多毛、粗壮,抓着尾巴的人说它短小但细长而敏捷。国王完全糊涂了。他认定他们都在愚弄他,他们中没有一个人真的找到了一头大象——他以不诚实为由把他们都关了起来。

大数据使得打破行业垂直市场的幻想成为可能

这个房间里的所有人都是瞎子,就像这个寓言中的六个人。我们都为不同垂直行业的公司工作。因此,我们经常陷入孤立考虑客户的陷阱。我们敏锐地观察我们的目标细分市场,但仅限于他们做出的与我们行业相关的选择。我为 TELUS 工作,我思考如何让客户享受并增加他们的移动互联网使用。你可能为一家银行工作,你会考虑是什么让客户申请一张新的信用卡或办理抵押贷款。零售业的其他人想知道为什么顾客会在特定的地点购买特定的商品等等。

我们忽略了一个微妙的事实,那就是我的客户也是你的客户——购买移动套餐的人还需要抵押贷款,还需要购买食品杂货,还需要购买去夏威夷的机票。在一些基本的神经经济学层面,这个人基于一些有限的经验法则、信念和固有的思维方式做出所有这些决定。大数据使得揭示客户行为世界背后的这些信念和经验法则成为可能。

所以当我说这是一个盲人的房间时,我的意思是我们对完整的顾客视而不见,就像六个人对整头大象视而不见一样。

我们的顾客在寓言中用大象来象征,她就是这个房间里的大象。我们对她的描述不够充分,因为我们对她的了解只是部分真相。

部分真相是有用的,但作用非常有限。

我们的信息和数据,无论是关于客户的位置、行为还是他们使用的网络,都只能告诉我们客户生活的一小部分。我们的数据庞大、专有且极具价值,但我们能够得出的见解仅限于一种背景。

Predicament of our partially understood customers

我们如何利用大数据更全面地了解客户?线索在于结合来自不同来源、背景和行业的数据集。我在 TELUS 工作的核心是数据评估框架。我的一个重要收获是,我们在模型中使用的数据集越不相关,尤其是在预测模型中,它们就越有可能揭示不同环境下客户行为之间意想不到的相关性。这些意想不到的相关性让我们越来越接近客户使用的有限经验法则。

顺便说一下,我在这里提到客户数据只是因为它是最广泛可用的,但这个原则适用于员工数据、供应商数据、基础设施数据、流行病学数据等等。

在大数据分析中,1 +1 = 11

当我偶然看到一项关于国际发展的研究时,我对从不相关的数据集中发现真知灼见的前景产生了兴趣。

布朗大学的经济学家丹尼尔·bjrkegren 和创业金融实验室(EFL)的达雷尔·格里森在 2015 年进行了一项研究,并发表了一篇论文。他们发现,在他们研究的一个中等收入的南美国家,手机通话行为是预测商业贷款还款概率的一种极其准确的方式。他们对超过 5000 个申请贷款的企业家的移动使用相关行为指标和一个财务记录不佳的个人样本进行了机器学习模型训练,预测的还款率优于征信机构的模型。他们的方法构成了向这些人群提供新形式信贷的产品设计的基础。

这很直观-

  1. 一个负责任的借款人可能会小心地管理他们的余额,以便更顺利地使用。
  2. 一个电话被回复的人可能有更强的社会联系
  3. 如果企业家在许多不同的地方使用她的电话,那么她很可能是在招揽生意

耐人寻味不是吗?虽然大多数加拿大人都有丰富的金融历史,但这项实验仍然与我们公司感兴趣的加拿大市场的特定部分超级相关——新移民、刚进入劳动力市场的大学毕业生、企业家和中小企业,以及其他不容易直接建立信用风险档案的人。

另一个超级有趣的案例是谷歌购买万事达卡交易数据,数据混合帮助公司更好地了解客户。谷歌一直在追踪点击谷歌广告导致的在线销售,那里没有新闻。然而,当我看到广告时,我并不总是立即买东西。你通常会在逛商场时认出某样东西,因为两天前你在电子邮件旁边看到了它的广告。那么,如果你在网下的商场里购买,谷歌怎么会知道呢?向谷歌付费的广告商又怎么会知道这种客户行为呢?今年 8 月,谷歌和万事达卡提出了一种分析数据的方法,以建立用户档案,并将它们与线下交易数据进行匹配,以获得线下销售的准确图像。他们不在个人层面跟踪交易,而是依赖用户档案。

答对了。现在,公司可以利用一个全新的信息宇宙,了解不同客户群体在观看谷歌广告后的离线行为,从而更好地调整他们的产品,以适应市场口味。

在大数据分析中,1+1 不等于 2,它等于 11。

类似的方法可用于获取位置数据,并在总体水平上预测国际旅行模式。或支付趋势,以预测哪些客户群更有可能在支付每月抵押贷款时面临现金流挑战。金融和移动使用信息也可以预测生活事件的概率,从而允许零售商有针对性地提供优惠。分析的可能性数不胜数…

通过合作,而不是竞争,看到全部真相

数据是一种非常有价值的资产,通常受到严密保护,这不仅是出于隐私原因,也是出于竞争原因。跨行业的数据协作并不常见,因为我们都在努力保守我们的秘方。让我们再一次用这个比喻来看看我们这样做错过了什么。

在大象的比喻中,六个瞎子是在说谎吗?不,他们只是没有意识到自己认知的局限性。他们每个人都有一部分真理,实际上是六分之一的真理。如果我们改变这个比喻,这样六个人中的每一个都可以互相分享他们对大象的了解,并对大象的长相给出一个整体的定义,那该多好?他们本可以非常准确地描述一个。

记住这六个盲人指的是谁——他们是你和我,这个房间里的盲人。合作,而不是竞争,会使盲人将他们的部分真理结合成整体真理!

还有一件事……

我一直在说——让我们和房间里的大象说话吧……但是有没有人问过大象她到底想不想被人说话呢?

我们这里的大象指的是“消费者”。消费者希望他们的信息被与他们交易的组织知道吗?组织如何利用这些信息为股东释放商业价值?可能是,也可能不是…这取决于组织使用这些信息的方式。

在 TELUS,我们以“设计隐私”为生活准则,这是一种从概念开始就将隐私融入我们的模型和流程的原则和方法。我们不仅在为
大数据和其他数据用途开发数据治理模型,并在其中构建最佳实践,还在我们的设计流程中构建这些治理机制。我们特别关注去识别模型和再识别风险管理。这里有一个 TELUS 信任模型的快照,它是我们处理客户数据的基础。

这种跨行业的数据协作在保护客户隐私的同时是可能的,其中协作者承诺在收集、共享和分析数据时是透明的、负责任的和合乎道德的。需要明确数据的使用方式和时间,以及对这些数据使用的控制措施。在这样做的时候,作为一个公司或组织这样做是不够的。因此,在构建跨行业数据协作时,要小心选择合作对象。维护所有相关方对数据隐私的高水平承诺至关重要。

我们行业中围绕隐私的所有工作都基于这样一个假设,即客户不希望他们的数据被收集。这是真的,但也只是半真半假。事实的另一半是,只要他们的信息将被使用或共享的方式以及目的是透明的,客户实际上就会喜欢精心策划的个性化推荐、产品和服务。业界和学术界围绕不同的隐私模型开展了大量工作。这项工作有望最大限度地保护隐私,同时还能与分析相平衡。

所以我把这个留给你们:

更好地了解我们的客户、我们的行业和我们的世界不仅有利可图;我们有责任了解它们;在他们允许的范围内。我们还能怎样把顾客放在第一位?我们还能如何从尊重和理解的角度来解决这些问题呢?

“于是,印度尼西亚的六个男人
吵了很久
各持己见
异常强硬
他们每个人都是对的
所有人都是错的。”

很乐意继续谈话。问我一个问题或写信给我。

在科学环境中剖析和优化 Python 算法。

原文:https://towardsdatascience.com/speed-up-jupyter-notebooks-20716cbe2025?source=collection_archive---------3-----------------------

根据我在过去一年中获得的一些技巧,找到瓶颈并大幅提高运行时性能。

虽然我们都知道过早的微优化是万恶之源,主要是因为 Donald Knuth 的论文“使用 Go To 语句的结构化编程”[1],但最终在数据探索过程中的某个时刻,您掌握的不仅仅是当前的“工作”解决方案。

我们通常遵循的启发式方法考虑:

  1. 让它工作。
  2. 使正确
  3. 使它快速

在直接跳到第三点并开始重构我们的代码之前,重要的是确定性能瓶颈在哪里,以便对我们想要遵循的操作过程做出明智的决定。

如果我们需要用最少的工作获得最大的收益,这是一个基本的步骤。说实话,在这种情况下,最大的错误之一是做出无知的猜测,并微调我们认为是这个问题的主要驱动因素。通过剖析我们的代码,我们消除了这个漏洞,因为我们将准确地知道问题在哪里。

既然我们在这里使用 Jupyter 笔记本,我们也可以利用它带来的便利,比如魔法命令。魔法命令毫无疑问是扩展笔记本电脑功能的绝佳增强功能之一。详细来说,我们将看看:

  • %time%timeit
  • %prun%lprun
  • %mprun%memit
  • %%heat
  • snakeviz可视化分析会话的输出

并研究以下内容:

  • pythonic 式编码方法
  • 使用矢量化的循环优化方法
  • 不同算法的优化

我们的第一个目标是找出让我们头疼的原因。一般来说,性能分析包括测量您想要优化的资源,无论是内存使用还是 CPU 时间。

在接下来的例子中,我们将考虑如果我们的任务是“CPU 受限”(因此花费在 CPU 上的时间),如何努力优化,以及与之相反,如何以及为什么要特别关注内存密集型任务。

注意:在本文中,我不是投入并行或高性能计算来解决性能瓶颈问题。这超出了这篇文章的范围,可能是一个在将来写的想法。

用蒙特卡罗积分逼近π

蒙特卡罗模拟是一种通过随机生成样本来估计问题答案的方法。它们主要适用于计算对可能是高维的系统的解的“强力”近似,例如使用了蒙特卡罗树搜索DeepMind 的 AlphaGo Zero

我们将定义一个使用随机生成的数据点评估 pi 的慢速方法,然后寻找优化的方法。请记住,半径为 1 的圆所覆盖的面积正好等于圆周率的四分之一。

我们通过取圆的面积与正方形面积之比得到圆周率的值,

unit quarter-circle

我们用生成的随机点来近似这个区域。

π ≈ 3.1417

考虑下面的代码,其中我们近似积分:

在 while 循环中,我们生成一个随机点,并检查它是否落在圆内。如果是的话,我们将in_circle加 1。我们这样做n次,并返回比率乘以 4,以便估计 pi(第 19 行)。

或者用更数学的术语来说:

在哪里

注意:更糟糕的是,迭代代码可以用递归解决方案来实现。递归版本可以在这里找到

在开始犹豫不决的优化迭代之前,在没有任何分析器开销的情况下,测量我们想要优化的函数的总执行时间并将其保存在某个地方供以后参考是很重要的。

神奇的命令%time可以为比较不同函数的运行时间提供一个有用的工具(即基准测试)。

在[1]中:**%time** estimate_pi()

CPU times: user 6.2 s, sys: 11.8 ms, total: 6.21 s
Wall time: 6.25 s

如果我们对标准化%time感兴趣,使用:

在[2]中:**%timeit** -r 2 -n 5 estimate_pi()

其中-r表示运行次数,而-n 表示循环次数。我们得到的是:

6.29 s ± 73.7 ms per loop (mean ± std. dev. of 2 runs, 5 loops each)

我们的第一种方法用了 6.29 秒来估算圆周率,我们会记住它,稍后再来讨论。

cProfile

为了真正了解什么占用了大部分执行时间,python 附带了一个很棒的分析器,它可以逐个函数地分解执行功能。它通过给出性能的高级视图,使我们的注意力缩小到关键功能。

在[3]中:**%prun** estimate_pi()

注意:您应该记住,剖析通常会增加代码的开销。

对于每个功能,报告显示:

  • 呼叫次数
  • 花费在其上的总时间(总时间),不包括调用子功能的时间
  • 每个呼叫花费的时间(按百分比计算,不包括和包括)
  • 包括所有子功能调用的总时间(累计时间)

输出将被写入标准输出。如果我们希望保存输出供以后检查,例如用 pstats ,使用 -D 选项保存到磁盘上。

在[4]中:**%prun** -D pi.prof estimate_pi()

*** Profile stats marshalled to file 'pi.prof'.

另一个有用的选项是 -s ,它支持对特定列进行排序。例如,按降序对累积时间进行排序:

[5]: **%prun** -s cumulative estimate_pi()

有趣的似乎是调用内置函数pow()random()的次数。在我们处理如此大量的调用之前,让我们先来看看一个更方便的库,它可以提供更具体的报告。

线条轮廓仪

%lprun命令产生每行代码花费的时间,给我们一个逐行报告。因为默认情况下没有提供,所以用 pip 安装库

!pip install line_profiler

并在笔记本中手动加载扩展。

%load_ext line_profiler

使用与%prun相似的语法,可以像 pi(e)一样容易地定位代码中的热点,唯一的区别是需要显式定义函数。

在[6]中:**%lprun** -f estimate_pi estimate_pi()

注意第 10 行的 if 语句花费了大量时间(29.1%)。请记住,我们甚至可以将上面的报告着色,给我们一个更直观的方式来查看热点。

我们所要做的就是在单元的顶部插入%%heat命令(使用!pip install py-heat-magic安装后加载扩展%load_ext heat,它允许我们看到完全红色的,而循环倾斜高成本的 CPU 时间,清楚地显示优化的空间。

我只想简单地提一下,有一个很好的库叫做snakeviz,它将概要文件显示为旭日,其中函数表示为弧线。

更多信息可在这里找到。

使最优化

在深入研究涉及外部库依赖的方法之前,让我们提出一个想法,让事情变得更加 pythonic 化!

Python 意味着代码不仅要有正确的语法,还要遵循 Python 社区的惯例,并按照预期的方式使用语言。

请记住,对函数的每个调用都与开销时间相关,因此循环中的绝大多数调用都会让我们陷入困境。如果满足某个条件, while 循环只是将计数器加 1。为了简化代码,我们引入了**sum()** 方法,一个生成器表达式和 pow()的移除。

通过做这三个改变,我们已经将函数调用减少了 30.37% ,速度提高了 41.5 %。

在[7]中:**%prun** estimate_pi()

在[8]中:%timeit -r 2 -n 5 estimate_pi()

3.68 s ± 2.39 ms per loop (mean ± std. dev. of 2 runs, 5 loops each)

通过矢量化进行优化

假设我们事先确切地知道应该生成多少个随机数,我们可以简单地尝试将所有的放在循环的前面或外面。

还记得第 10 行的 if 语句吗,它占用了将近 30%的计算时间。这个 if 语句需要的唯一信息是两个坐标,因此也可以放在循环之外。

如果选项可用,我们应该避免循环代码。特别是在数据科学中,我们熟悉 NumPy 和 pandas,它们是针对数值计算的高度优化的库。NumPy 的一大优势是内部基于 C 数组的数组,这些数组存储在一个连续的内存块中(基于数据缓冲区的数组)

在这里,我们将所有随机点创建为一个形状为(n, 2)的数组(第 9 行),并计算该点落入圆中的次数(第 10 行)。

如果我们现在测试 numpy 版本,

在[9]: **%timeit** estimate_pi()

388 ms ± 9.24 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

结果为 388 毫秒,因此while 循环快 16 倍。Numpy 的语法类似于标准的 python 方法,我们写的是np.sum()而不是sum(),本质上我们不再遍历列表,而是使用 numpy 的矢量化例程。

内存分析

处理大型数据集需要清楚地了解后台的内存消耗和分配过程。如前所述,有一些工具可以监控笔记本电脑的内存使用情况。

以熟悉的方式使用%memit%timeit

【10】中:**%memit** estimate_pi()

peak memory: 623.36 MiB, increment: 152.59 MiB

我们看到该函数为 1e7 模拟使用了大约 600 兆字节。我的假设是分配大数组贡献了大部分。用%mprun来证明这个假设,它检查每一行的内存使用情况。

在[11]中:**%mprun** -f estimate_pi estimate_pi()

非常有趣的似乎是行 4 ,其中增量是 162.8 MiB,然而在下一行,整体内存使用只增加了 0.1。这里发生的是,我们在赋值的右边分配,然后再次丢弃内存,因为inside不再是一个 numpy 数组。

下面是一个和上面一样的 liner,除了不是分配一个 shape (n, 2)的大数组,而是按需分配 x 和 y 点。尽管我们牺牲了可读性,重写表达式减少了赋值操作的数量,从而产生了更快的解决方案,280 ms(快 22 倍)。

在[9]中:**%timeit** estimate_pi()

280 ms ± 3.06 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

被遗忘

创建阵列会对可用的系统内存产生限制。分配过程与输入参数n成线性比例。例如,如果我们试图将模拟的数量设置为1e10,我们的内核将在创建数组时崩溃。幸运的是,这种方法不需要一个大的阵列,相反,我们将它分成更小的块,这使我们能够独立于系统内存扩展模拟的数量。

这里我们预定义了数组的大小(第 9 行),等于 80 MB。我们将模拟的数量拆分为处理 80 MB numpy 数组,每次增加inside

如果我们预先模拟将n设置为1e10,我们将尝试分配一个 80 GB 的数组(!)的尺寸,在标准机器上根本不可行。使用更新的方法,计算时间与n的计算时间相等。

用不同的算法优化

如果我们测试后一种 numpy 解决方案,我们估计 pi 为 3.1426944,相对误差为 0.035%280 毫秒。蒙特卡洛方法是一个很好的概念,可以得出一个答案,这个答案并不立即具有通过随机程序可以推导出来的所有特征。

可能会有不同的计算方法,以更有效的方式解决这个问题。对任何编程执行来说,最大的提升就是改变解决问题的一般方式。不出所料,这是最难实现的改变,因为需要对编码进行升级和改造。

Chudnovsky 算法

虽然有许多方法可以计算具有高位数精度的圆周率[3],但一种非常快速的方法是 Chudnovsky 算法,该算法由 Chudnovsky 兄弟于 1989 年发表,其形式如下:

尼克·克雷格·伍德的网站上有一篇很棒的文章。该算法的实现是一项重要的任务,留给读者作为练习。

剖析这种方法导致,

在【12】:%timeit -r 1 -n 1000 pi_chudnovsky(10**100)

13.6 µs ± 72 ns per loop (mean ± std. dev. of 7 runs, 10 loops each)

13.6 微秒,这不仅比我们的 numpy 蒙特卡罗版本快了 20,000 倍,而且它还成功地计算了圆周率的前 100 位。

结论

在进行优化之前,我们应该对可能的瓶颈进行剖析并避免不成熟的假设(而剖析器从不说谎)。为了监控 CPU 时间消耗和内存占用,Jupyter 提供了方便的魔术命令,可直接在笔记本电脑上执行。优化的基本方法包括在显式循环中使用生成器表达式和列表理解。纯粹的 python 编码在极少数情况下是一个有指导意义的建议,因此应该被科学库中的优化的 equal 方法所取代,从而带来巨大的速度提升。

注意:考虑对 Jupyter Notebook 中的优化持保留态度,因为它有一些方面,如执行单元时的非线性工作流,乍一看似乎很方便,但由于它上面还有另一个抽象层,我们无法控制如何读取状态并将其保存在内存中。抽象发生得越多,就越难揭示潜在的问题。(如果我说错了,请指正。)

第二部分计划探索 Cython 和 python 中并行计算的可能性。

我欢迎反馈和建设性的批评。

干杯!🙇

参考

[1]唐纳德·e·克努特,结构化程序设计与 Go To 语句,1974 年,https://pic.plover.com/knuth-GOTO.pdf

[2] Eric C. Anderson,蒙特卡罗方法与重要性抽样,1999,http://IB . Berkeley . edu/labs/slat kin/eriq/classes/guest _ lect/MC _ lech _ notes . pdf

[3]沃尔夫拉姆研究,http://functions.wolfram.com/PDF/Pi.pdf

杰克·范德普拉斯。(2016), Python 数据科学手册

西里尔·罗森。(2014 年), IPython 交互式计算和可视化食谱

加布里埃尔·拉纳罗。(2013), Python 高性能编程

加速您的算法第 1 部分— PyTorch

原文:https://towardsdatascience.com/speed-up-your-algorithms-part-1-pytorch-56d8a4ae7051?source=collection_archive---------1-----------------------

“low angle photography of yellow hot air balloon” by sutirta budiman on Unsplash

加速你的 PyTorch 模型

这是我写的系列文章中的第一篇。所有帖子都在这里:

  1. 加速您的算法第 1 部分— PyTorch
  2. 加速您的算法第 2 部分— Numba
  3. 加速您的算法第 3 部分—并行化
  4. 加速您的算法第 4 部分— Dask

这些与 Jupyter 笔记本 搭配在这里可以得到:

[Github-speedupyourlightms[ka ggle]

(编辑-28/11/18) —增加了 torch.multiprocessing 部分。

索引:

  1. 介绍
  2. 如何检查 cuda 的可用性?
  3. 如何获得更多关于 cuda 设备的信息?
  4. 如何在 GPU 上存储张量和运行模型?
  5. 如果您有多个 GPU,如何选择和使用它们?
  6. 数据并行性
  7. 数据并行性的比较
  8. torch .多重处理
  9. 参考
***NOTE:*** This post goes with ***Jupyter Notebook*** available in my Repo on Github:[[SpeedUpYourAlgorithms-Pytorch](https://nbviewer.jupyter.org/github/PuneetGrov3r/MediumPosts/blob/master/SpeedUpYourAlgorithms/1%29%20PyTorch.ipynb)]

1.简介:

在这篇文章中,我将展示如何使用torchpycuda来检查和初始化 GPU 设备,以及如何让你的算法更快。

PyTorch 是建立在 torch 之上的机器学习库。它得到了脸书人工智能研究小组的支持。经过最近的发展,它已经获得了很大的普及,因为它的简单性,动态图形,因为它是本质上的 pythonic。它在速度上仍然不落后,在很多情况下甚至可以超越。

pycuda 让你从 python 访问 Nvidia 的 cuda 并行计算 API。

2.如何检查 cuda 的可用性?

“brown dried leaves on sand” by sydney Rae on Unsplash

要使用Torch检查您是否有可用的cuda设备,您只需运行:

import torchtorch.cuda.is_available()
# True

3.如何获得更多关于 cuda 设备的信息?

“black smartphone” by rawpixel on Unsplash

要获取设备的基本信息,您可以使用torch.cuda。但是要在你的设备上获得更多信息,你可以使用pycuda,一个围绕CUDA库的 python 包装器。您可以使用类似以下的内容:

import torch
import pycuda.driver as cuda
cuda.init()## Get Id of default device
torch.cuda.current_device()
# 0cuda.Device(0).name() # '0' is the id of your GPU
# Tesla K80

或者,

torch.cuda.get_device_name(0) # Get name device with ID '0'
# 'Tesla K80'

我编写了一个简单的类来获取关于兼容 GPU 的信息:

要获取当前的内存使用情况,您可以使用pyTorch的功能,例如:

import torch# Returns the current GPU memory usage by 
# tensors in bytes for a given device
torch.cuda.memory_allocated()# Returns the current GPU memory managed by the
# caching allocator in bytes for a given device
torch.cuda.memory_cached()

运行应用程序后,您可以使用一个简单的命令来清除缓存:

# Releases all unoccupied cached memory currently held by
# the caching allocator so that those can be used in other
# GPU application and visible in nvidia-smi
torch.cuda.empty_cache()

但是,使用该命令不会释放张量所占用的 GPU 内存,因此它不能增加 PyTorch 可用的 GPU 内存量。

这些内存方法只适用于 GPU。这才是真正需要它们的地方。

4.如何在 GPU 上存储张量和运行模型?

.cuda魔法。

“five pigeons perching on railing and one pigeon in flight” by Nathan Dumlao on Unsplash

如果你想在 cpu 上存储一些东西,你可以简单地写:

a = torch.DoubleTensor([1., 2.])

这个向量存储在 cpu 上,你对它的任何操作都将在 cpu 上完成。要将其传输到 gpu,您只需做.cuda:

a = torch.FloatTensor([1., 2.]).cuda()

或者,

a = torch.cuda.FloatTensor([1., 2.])

这将为它选择默认设备,可以通过以下命令看到:

torch.cuda.current_device()
# 0

或者,你也可以这样做:

a.get_device()
# 0

你也可以发送一个模型到 GPU 设备。例如,考虑一个由nn.Sequential制成的简单模块:

sq = nn.Sequential(
         nn.Linear(20, 20),
         nn.ReLU(),
         nn.Linear(20, 4),
         nn.Softmax()
)

要将此发送到 GPU 设备,只需:

model = sq.cuda()

你可以检查它是否在 GPU 设备上,因为你必须检查它的参数是否在 GPU 上,比如:

# From the discussions here: [discuss.pytorch.org/t/how-to-check-if-model-is-on-cuda](https://discuss.pytorch.org/t/how-to-check-if-model-is-on-cuda/180)next(model.parameters()).is_cuda
# True

5.如果您有多个 GPU,如何选择和使用它们?

“selective focus photography of mechanics tool lot” by NeONBRAND on Unsplash

您可以为当前应用程序/存储选择一个 GPU,该 GPU 可以不同于您为上一个应用程序/存储选择的 GPU。

正如在第(2)部分已经看到的,我们可以使用pycuda来获得所有的cuda兼容设备和它们的Id,我们在这里不讨论。

考虑到您有 3 个cuda兼容设备,您可以像这样初始化并分配tensors给一个特定的设备:

cuda0 = torch.device('cuda:0')
cuda1 = torch.device('cuda:1')
cuda2 = torch.device('cuda:2')
# If you use 'cuda' only, Tensors/models will be sent to 
# the default(current) device. (default= 0)x = torch.Tensor([1., 2.], device=cuda1)
# Or
x = torch.Tensor([1., 2.]).to(cuda1)
# Or
x = torch.Tensor([1., 2.]).cuda(cuda1)**# NOTE:**
**#** If you want to change the default device, use:
torch.cuda.set_device(2) # where '2' is Id of device**#** And if you want to use only 2 of the 3 GPU's, you
**#** will have to set the environment variable 
**#** *CUDA_VISIBLE_DEVICES* equal to say, "0,2" if you 
**#** only want to use first and third GPUs. Now if you 
**#** check how many GPUs you have, it will show two*(0, 1)*.
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "0,2"

当您在这些Tensor上进行任何操作时,您可以不考虑所选的设备,结果将保存在与Tensor相同的设备上。

x = torch.Tensor([1., 2.]).to(cuda2)
y = torch.Tensor([3., 4.]).to(cuda2)# This Tensor will be saved on 'cuda2' only
z = x + y

如果你有多个 GPU,你可以在它们之间分配应用程序的工作,但是这会带来它们之间的通信开销。但是如果你不需要太多的信息,你可以试一试。

实际上还有一个问题。在PyTorch中,默认情况下所有的 GPU 操作都是异步的。虽然它在 CPU 和 GPU 之间或两个 GPU 之间复制数据时进行必要的同步,但如果你在命令torch.cuda.Stream()的帮助下创建自己的流,那么你将不得不自己负责指令的同步。

PyTorch的文档中举一个例子,这是不正确的:

cuda = torch.device('cuda')
s = torch.cuda.Stream()  ***#*** *Create a new stream.*
A = torch.empty((100, 100), device=cuda).normal_(0.0, 1.0)
with torch.cuda.stream(s):
    ***#*** *because sum() may start execution before normal_() finishes!*
    B = torch.sum(A)

如果您想要充分发挥多个 GPU 的潜力,您可以:

  1. 将所有 GPU 用于不同的任务/应用,
  2. 将每个 GPU 用于集合或堆栈中的一个模型,每个 GPU 具有数据的副本(如果可能),因为大多数处理是在拟合模型期间完成的,
  3. 在每个 GPU 中使用带有切片输入和模型副本的每个 GPU。每个 GPU 将分别计算结果,并将它们结果发送到目标 GPU,在那里将进行进一步的计算,等等。

6.数据并行?

“photography of tree in forest” by Abigail Keenan on Unsplash

在数据并行中,我们将从数据生成器获得的一批数据分割成更小的小批,然后发送到多个 GPU 进行并行计算。

PyTorch中,使用torch.nn.DataParallel实现数据并行。

但是我们将看到一个简单的例子,看看到底发生了什么。为此我们将不得不使用nn.parallel的一些功能,即:

  1. 复制:在多个设备上复制Module
  2. 分散:将第一维度的input分布在这些设备中。
  3. 收集:从这些设备中收集并连接第一维度的input
  4. parallel_apply:将我们从 Scatter 获得的一组分布式的input应用到我们从 Replicate 获得的相应的一组分布式的Module
# Replicate module to devices in device_ids
replicas **=** nn**.**parallel**.**replicate(module, device_ids)# Distribute input to devices in device_ids
inputs **=** nn**.**parallel**.**scatter(input, device_ids)# Apply the models to corresponding inputs
outputs **=** nn**.**parallel**.**parallel_apply(replicas, inputs)# Gather result from all devices to output_device
result = nn**.**parallel**.**gather(outputs, output_device)

或者,简单地说:

model = nn.DataParallel(model, device_ids=device_ids)
result = model(input)

7.数据并行比较

“silver bell alarm clock” by Icons8 team on Unsplash

我没有多个 GPU,但我能够找到一个由 Ilia Karmanov 在这里和他的 github repo 比较大多数使用多个 GPU 的框架在这里的伟大帖子。

他的结果是:

【最后更新:(2018 年 6 月 19 日)】即他的 github 回购。PyTorch 1.0、Tensorflow 2.0 以及新 GPU 的推出可能会改变这一点…

因此,如您所见,即使必须在开始和结束时与主设备通信,并行处理也绝对有帮助。而且PyTorch给出结果的速度比所有的都快,仅在多 GPU 的情况下比Chainer快。Pytorch也很简单,只需调用一次DataParallel

8.torch .多重处理

Photo by Matthew Hicks on Unsplash

torch.multiprocessing是 Python multiprocessing模块的包装器,其 API 与原始模块 100%兼容。所以可以用Queue的、Pipe的、Array的等等。这些都在 Python 的多重处理模块中。除此之外,为了使它更快,他们增加了一个方法share_memory_(),它允许数据进入任何进程都可以直接使用它的状态,因此将该数据作为参数传递给不同的进程不会复制该数据。

你可以分享Tensors,model 的parameters,你可以随心所欲的在 CPU 或者 GPU 上分享。

**Warning from Pytorch: (Regarding sharing on GPU)
**  CUDA API requires that the allocation exported to other processes remains valid as long as it’s used by them. You should be careful and ensure that CUDA tensors you shared don’t go out of scope as long as it’s necessary. This shouldn’t be a problem for sharing model parameters, but passing other kinds of data should be done with care. Note that this restriction doesn’t apply to shared CPU memory.

你可以在这里的“池和进程”部分使用上面的方法,为了获得更快的速度,你可以使用share_memory_()方法在所有进程之间共享一个Tensor(比方说)而不被复制。

**# Training a model using multiple processes:**import torch.multiprocessing as mp
def train(model):
    for data, labels in data_loader:
        optimizer.zero_grad()
        loss_fn(model(data), labels).backward()
        optimizer.step()  ***#*** *This will update the shared parameters*model = nn.Sequential(nn.Linear(n_in, n_h1),
                      nn.ReLU(),
                      nn.Linear(n_h1, n_out))model.share_memory() **#** Required for 'fork' method to workprocesses = []
for i in range(4): # No. of processes
    p = mp.Process(target=train, args=(model,))
    p.start()
    processes.append(p)for p in processes: p.join()

您也可以使用一组机器。更多信息请参见此处

9.参考资料:

  1. https://documen.tician.de/pycuda/
  2. https://pytorch.org/docs/stable/notes/cuda.html
  3. https://discuse . py torch . org/t/how-to-check-if-model-is-on-cuda
  4. https://py torch . org/tutorials/初学者/blitz/data _ parallel _ tutorial . html
  5. https://medium . com/@ iliakarmanov/multi-GPU-Rosetta-stone-d4fa 96162986
Suggestions and reviews are welcome.
Thank you for reading!

签名:

加速您的算法第 2 部分— Numba

原文:https://towardsdatascience.com/speed-up-your-algorithms-part-2-numba-293e554c5cc1?source=collection_archive---------4-----------------------

使用 Numba 获得 C++/Fortran 般的速度

“brown snake” by Duncan Sanchez on Unsplash

这是我写的系列文章中的第三篇。所有帖子都在这里:

  1. 加速您的算法第 1 部分— PyTorch
  2. 加速你的算法第二部分——Numba
  3. 加速您的算法第三部分——并行化
  4. 加速你的算法第 4 部分— Dask

而这些与 相配套的 Jupyter 笔记本 可在此处获得:

[Github-speedupyourlightms[ka ggle]

索引

  1. 介绍
  2. 为什么是 Numba?
  3. Numba 是如何工作的?
  4. 使用基本的 numba 功能(就@jit 吧!)
  5. @矢量化包装器
  6. 在 GPU 上运行您的函数
  7. 进一步阅读
  8. 参考
***NOTE:*** This post goes with ***Jupyter Notebook*** available in my Repo on Github:[[SpeedUpYourAlgorithms-Numba](https://nbviewer.jupyter.org/github/PuneetGrov3r/MediumPosts/blob/master/SpeedUpYourAlgorithms/2%29%20Numba.ipynb)]

1.介绍

N umba 是一个即时的 python 编译器,也就是说,每当你调用一个 python 函数时,你的全部或部分代码都会被转换成机器码“即时”执行,然后它就会以你的本机机器码速度运行!它由 Anaconda 公司赞助,并得到了许多其他组织的支持。

有了 Numba,你可以加速所有计算密集型的 python 函数(比如循环)。它还支持 numpy 库!因此,您也可以在计算中使用 numpy,并加快整体计算速度,因为 python 中的循环非常慢。你也可以使用 python 标准库的数学库的许多功能,比如 sqrt 等。有关所有兼容功能的完整列表,请查看此处的。

2.为什么是 Numba?

[ 来源 ]

S o,为什么 numba?当有很多其他的编译器像 cython ,或者任何其他类似的编译器或者类似 pypy 的时候。

原因很简单,在这里你不必离开用 python 写代码的舒适区。是的,你没看错,你根本不需要为基本的加速而改变你的代码,这可以和你从类似的带有类型定义的 cython 代码中得到的加速相媲美。这不是很好吗?

你只需要添加一个熟悉的 python 功能,一个围绕你的函数的装饰器(包装器)。一个用于类的包装器也正在开发中。

所以,你只需要添加一个装饰就可以了。例如:

from numba import jit@jit
def function(x):
    # your loop or numerically intensive computations
    return x

它看起来仍然像一个纯 python 代码,不是吗?

3.numba 是如何工作的?

“question mark neon signage” by Emily Morter on Unsplash

N umba 使用 LLVM 编译器基础设施从纯 Python 代码生成优化的机器码。使用 numba 运行代码的速度与 C、C++或 Fortran 中的类似代码相当。

下面是代码的编译方式:

[ 来源

首先,Python 函数被获取、优化并转换成 Numba 的中间表示,然后在类似 Numpy 的类型推理(因此 python float 是 float64)的类型推理之后,它被转换成 LLVM 可解释代码。然后,这些代码被送入 LLVM 的实时编译器,以给出机器码。

您可以根据自己的喜好,在 CPU(默认)或 GPU 上运行时或导入时生成代码。

4.使用基本的 numba 功能(就@jit 吧!)

Photo by Charles Etoroma on Unsplash

小菜一碟!

或者最佳性能 numba 建议在你的 jit 包装器中使用nopython = True参数,这样它就不会用到 Python 解释器。或者你也可以使用@njit。如果你的nopython = True包装器因错误而失败,你可以使用简单的@jit包装器,它将编译你的部分代码,循环它可以编译,并把它们变成函数,编译成机器码,把剩下的交给 python 解释器。
所以,你只需要做:

from numba import njit, jit@njit      # or @jit(nopython=True)
def function(a, b):
    # your loop or numerically intensive computations
    return result

当使用@jit时,确保你的代码有 numba 可以编译的东西,比如一个计算密集型的循环,可能有它支持的库(numpy)和函数。否则,它将无法编译任何内容。

最重要的是,numba 还会在函数首次作为机器码使用后对其进行缓存。所以在第一次之后,它会更快,因为它不需要再次编译代码,因为你使用的参数类型与你之前使用的相同。

如果您的代码是可并行化的,您也可以将parallel = True作为参数传递,但是它必须与nopython = True一起使用。目前,它只在 CPU 上工作。

你也可以指定你希望你的函数拥有的函数签名,但是它不会为你给它的任何其他类型的参数进行编译。例如:

from numba import jit, int32@jit(int32(int32, int32))
def function(a, b):
    # your loop or numerically intensive computations
    return result**#** or if you haven't imported type names
**#** you can pass them as string@jit('int32(int32, int32)')
def function(a, b):
    # your loop or numerically intensive computations
    return result

现在你的函数将只接受两个 int32 并返回一个 int32。这样,你可以更好地控制你的功能。如果你愿意,你甚至可以传递多个功能签名。

您也可以使用 numba 提供的其他包装器:

  1. @矢量化:允许标量参数用作 numpy ufunc s,
  2. @ gu 矢量化:产生 NumPy 个广义ufunc s,
  3. @stencil :声明一个函数作为类模板操作的内核,
  4. @jitclass :对于 jit 感知类,
  5. @cfunc :声明一个函数作为本机回调使用(从 C/C++等调用),
  6. @overload :注册自己的函数实现,用于 nopython 模式,例如@overload(scipy.special.j0)

Numba 还有提前(AOT)编译,产生一个不依赖 Numba 的编译后的扩展模块。但是:

  1. 它只允许常规函数(非 ufuncs),
  2. 您必须指定一个函数签名。您只能指定一个,因为许多指定在不同的名称下。

它还为您的 CPU 架构家族生成通用代码。

5.@矢量化包装器

“gray solar panel lot” by American Public Power Association on Unsplash

通过使用@vectorize wrapper,你可以将只在标量上操作的函数转换为数组,例如,如果你正在使用只在标量上工作的 python 的math库。这提供了类似于 numpy 数组操作(ufuncs)的速度。例如:

@vectorize
def func(a, b):
    # Some operation on scalars
    return result

您还可以将target参数传递给这个包装器,对于并行化代码,它的值可以等于parallel,对于在 cuda/GPU 上运行代码,它的值可以等于cuda

@vectorize(target="parallel")
def func(a, b):
    # Some operation on scalars
    return result

如果您的代码计算量足够大或者数组足够大,使用target = “parallel”“cuda”进行矢量化通常会比 numpy 实现运行得更快。如果不是这样,那么它会带来创建线程和为不同线程拆分元素的时间开销,这可能比整个进程的实际计算时间要长。因此,工作应该足够繁重以获得加速。

这个伟大的视频有一个例子,加速纳维尔斯托克斯方程计算流体力学与 Numba:

6.在 GPU 上运行您的函数

“time-lapsed of street lights” by Marc Sendra martorell on Unsplash

你也可以通过@jit 这样的包装器在 cuda/GPU 上运行函数。为此,您必须从numba库中导入cuda。但是在 GPU 上运行你的代码不会像以前那么容易了。在 GPU 上数百甚至数千个线程上运行函数需要进行一些初始计算。您必须声明和管理网格、块和线程的层次结构。也没那么难。

要在 GPU 上执行一个函数,你必须定义一个叫做**kernel function****device function**的东西。首先让我们看一个**kernel function**

关于内核函数,需要记住以下几点:

a)内核在被调用时显式声明它们的线程层次,即块数和每个块的线程数。您可以编译一次内核,然后使用不同的块和网格大小多次调用它。

b)内核不能返回值。所以,要么你必须对原始数组进行修改,要么传递另一个数组来存储结果。为了计算标量,您必须传递一个 1 元素数组。

# Defining a kernel function
from numba import cuda@cuda.jit
def func(a, result):
    # Some cuda related computation, then
    # your computationally intensive code.
    # (Your answer is stored in 'result')

所以为了启动一个内核,你必须传递两个东西:

  1. 每个块的线程数,
  2. 块数。

例如:

threadsperblock = 32
blockspergrid = (array.size + (threadsperblock - 1)) // threadsperblock
func[blockspergrid, threadsperblock](array)

每个线程中的内核函数必须知道它在哪个线程中,知道它负责数组的哪些元素。Numba 使获取这些元素的位置变得很容易,只需一次调用。

@cuda.jit
def func(a, result):
    pos = cuda.grid(1)  # For 1D array
    # x, y = cuda.grid(2) # For 2D array
    if pos < a.shape[0]:
        result[pos] = a[pos] * (some computation)

为了节省将 numpy 数组复制到特定设备,然后再将结果存储到 numpy 数组中所浪费的时间,Numba 提供了一些函数来声明和发送数组到特定设备,如:numba.cuda.device_arraynumba.cuda.device_array_likenumba.cuda.to_device等。为了节省不必要的拷贝到 cpu 的时间(除非必要)。

另一方面,**device function**只能从设备内部调用(通过内核或另一个设备函数)。有利的一点是,你可以从一个**device function**返回值。因此,您可以使用函数的返回值来计算kernel functiondevice function中的内容。

from numba import cuda@cuda.jit(device=True)
def device_function(a, b):
    return a + b

你也应该看看 Numba 的 cuda 库支持的功能。

Numba 在其 cuda 库中还实现了原子操作随机数生成器共享内存实现(以加速数据访问)等。

ctypes/cffi/cython 互操作性:

  • cffi—nopython 模式支持调用 CFFI 函数。
  • ctypes——在 nopython 模式下支持调用 ctypes 包装函数…
  • Cython 导出函数可调用

7.进一步阅读

  1. https://nb viewer . jupyter . org/github/continuum io/GTC 2017-numba/tree/master/
  2. https://devblogs.nvidia.com/seven-things-numba/
  3. https://devblogs.nvidia.com/numba-python-cuda-acceleration/
  4. https://jakevdp . github . io/blog/2015/02/24/optimizing-python-with-numpy-and-numba/
  5. https://www.youtube.com/watch?v=1AwG0T4gaO0

8.参考

  1. http://numba.pydata.org/numba-doc/latest/user/index.html
  2. https://github.com/ContinuumIO/gtc2018-numba
  3. http://Stephan hoyer . com/2015/04/09/numba-vs-cy thon-how-to-choose/
Suggestions and reviews are welcome.
Thank you for reading!

签名:

加速您的算法第 3 部分—并行化

原文:https://towardsdatascience.com/speed-up-your-algorithms-part-3-parallelization-4d95c0888748?source=collection_archive---------5-----------------------

Python 并行编程简介

Photo by drmakete lab on Unsplash

这是我写的系列文章中的第三篇。所有帖子都在这里:

  1. 加速您的算法第 1 部分— PyTorch
  2. 加速你的算法第二部分——Numba
  3. 加速您的算法第三部分——并行化
  4. 加速你的算法第 4 部分— Dask

而这些与 相配套的 Jupyter 笔记本 可在此处获得:

[Github-speedupyourlightms[ka ggle]

索引

  1. 简介
  2. 池和过程
  3. 穿线
  4. 达斯克
  5. torch.multiprocessing
  6. 延伸阅读
  7. 参考文献
***NOTE:*** This post goes with ***Jupyter Notebook*** available in my Repo on **Github**:[[SpeedUpYourAlgorithms-Parallelization](https://nbviewer.jupyter.org/github/PuneetGrov3r/MediumPosts/blob/master/SpeedUpYourAlgorithms/3%29%20Prallelization.ipynb)]
and on **Kaggle**:
[[SpeedUpYourAlgorithms-Parallelization](https://www.kaggle.com/puneetgrover/speed-up-your-algorithms-prallelization)]

1.简介 ^

随着时间的推移,数据呈指数级增长,而处理器计算能力的增长却停滞不前,我们需要找到高效处理数据的方法。我们做什么呢

GPU 是一种解决方案,而且非常有效。但是,GPU 不是为了机器学习的目的而制造的,它们是专门为复杂的图像处理和游戏而制造的。我们让我们的算法在现有的 GPU 上工作,它实际上得到了回报。现在,谷歌推出了一款名为 TPU(张量处理单元)的新设备,它是为 TensorFlow 上的机器学习工作负载量身定制的,结果看起来很有希望。英伟达也没有退缩。

但是我们会在未来的某个时候碰到天花板。即使我们采用当今可用的任何巨大数据集,单个机器或计算单元也不足以处理这样的负载。我们将不得不使用多台机器来完成任务。我们将不得不并行化我们的任务。

在本帖中,我们将探讨一些你在 Python 中大部分时间会用到的方法。然后稍微介绍一下 Dasktorch.multiprocessing

2.池和进程 ^

Photo by Alexander Popov on Unsplash

Python 的multiprocessing库的PoolProcess方法都为我们的任务启动了一个新的进程,但是方式不同。Process每次呼叫只进行一个过程:

import multiprocessing as mp
p = mp.Process(target= ##target-function,
               args=   ##args-to-func)
# This call will make only one process, which will process
# target-function with given arguments in background.

但是这个过程还没有开始。要启动它,您必须:

p.start()

现在,您可以将它留在这里,或者通过以下方式检查流程是否完成:

p.join()
# Now it will wait for process to complete.

不检查进程是否已经完成有许多用途。例如,在客户端-服务器应用程序中,数据包丢失或无响应进程的概率非常低,我们可以忽略它,这可以为我们带来可观的加速。[取决于应用程序的流程]

对于多个进程,你将不得不制作多个Process。你可以随意制作多个。当您调用它们上的.start()时,它们都将启动。

processes =[mp.Process(target=func, args=(a, b)) for (a, b) in list]for p in processes: p.start()
for p in processes: p.join()

另一方面,Pool启动固定数量的进程,然后我们可以给这些进程分配一些任务。因此,在特定的时刻,只有固定数量的进程在运行,其余的都在等待。进程的数量通常被选择为设备的内核数量,如果将该参数留空,这也是默认行为。

pool = mp.Pool(processes=2)

现在有很多方法可以让你使用这个Pool。在数据科学中,我们可以不用担心的是Pool.applyPool.map,因为它们在任务完成后立即返回结果。Pool.apply只接受一个参数,只使用一个进程,而Pool.map接受许多参数,并将它们放到我们的Pool进程中。

results = [pool.apply(func, (x)) for x in X]
# Or 
results = pool.map(func, (arg)) **#** Takes only one argument

但是Pool.map只接受一个参数(iterable ),它将这个参数分成若干块。要发送许多参数,你可以像 this 这样做。

考虑我们前面的客户机-服务器应用程序的例子,这里要运行的最大进程数是预定义的,所以如果我们有很多请求/包,一次只有其中的n(池中的最大进程数)会运行,而其他的会在队列中的进程槽中等待轮到它。

Squaring of all elements of a vector

**# How can we use it with Data Frame?
# A:** You can use some parallelizable functiondf.shape
# (100, 100)
dfs = [df.iloc[i*25:i*25+25, 0] for i in range(4)]with Pool(4) as p:
    res = p.map(np.exp, dfs)
for i in range(4): df.iloc[i*25:i*25+25, 0] = res[i]**#** It can come in handy for preprocessing of data.

用什么,什么时候用?

如果你有很多任务,但其中没有多少是计算密集型的,你应该使用Process。因为如果它们是计算密集型的,它们可能会阻塞您的 CPU,您的系统可能会崩溃。如果您的系统可以一次性处理它们,它们就不必排队等待机会。

当你有固定数量的任务并且它们是计算密集型的,你应该使用一个Pool。因为如果你一下子放开它们,你的系统可能会崩溃。

3.穿线 ^

Photo by Hello I'm Nik on Unsplash

穿线!用 python?

python 中的线程名声不好。人们是正确的。实际上,线程在大多数情况下并没有正常工作。那么问题是什么呢?

问题是 GIL(全局解释器锁)。GIL 是在 Python 开发的早期引入的,当时操作系统中甚至没有线程的概念。选择它是因为它简单。

GIL 一次只允许一个 CPU 绑定的进程。也就是说,它一次只允许一个线程访问 python 解释器。因此,线程Lock是整个解释器,直到它完成。

对于单线程程序来说,它很快,因为只有一个Lock需要维护。随着 python 的流行,很难有效地消除 GIL 而不损害所有相关的应用程序。这就是它还在的原因。

但是,如果你的任务不受 CPU 限制,你仍然可以使用多线程并行(y)。也就是说,如果你的任务是 I/O 受限的,你可以使用多线程并获得加速。因为大部分时间这些任务都在等待其他代理(如磁盘等)的响应。)在此期间,他们可以释放锁,让其他任务同时获取它。

**NOTE: (From official page** [**here**](https://wiki.python.org/moin/GlobalInterpreterLock)**)** The GIL is controversial because it prevents multithreaded CPython programs from taking full advantage of multiprocessor systems in certain situations. Note that potentially blocking or long-running operations, such as **I/O**, **image processing**, and [**NumPy**](https://wiki.python.org/moin/NumPy) **number crunching**, happen ***outside*** the GIL. Therefore it is only in multithreaded programs that spend a lot of time inside the GIL, interpreting CPython bytecode, that the GIL becomes a bottleneck.

所以,如果你的任务是 IO 绑定的,比如从服务器下载一些数据,读/写磁盘等等。,您可以使用多线程并获得加速。

from threading import Thread as t
import queue
q = queue.Queue()  # For putting and getting results of threadfunc_ = lambda q, args: q.put(func(args))threads = [t(target=func_, args=(q, args)) for args in args_array]
for t in threads: t.start()
for t in threads: t.join()
res = []
for t in threads: res.append(q.get()) 
**#** These results won't necessarily be in order

为了保存线程的结果,你可以使用类似Queue的东西。为此,你必须像上面那样定义你的函数,或者你可以在你的函数中使用Queue.put(),但是你必须改变你的函数定义,以包含Queue作为参数。

现在,你在队列中的结果不一定是有序的。如果你希望你的结果是有序的,你可以传入一些计数器作为参数,作为 id,然后使用这些 id 来识别结果来自哪里。

threads = [t(func_, args = (i, q, args)) for i, args in 
                                         enumerate(args_array)]
# And update function accordingly***NOTE:*** Multiprocessing with Pandas 'read.csv' method doesn't give much speedup for some reason. As an alternative you can use [**Dask**](/speeding-up-your-algorithms-part-4-dask-7c6ed79994ef).

线程 vs 进程?

一个进程是重量级的,因为它可能包含许多自己的线程(至少包含一个),并且它有自己分配的内存空间,而线程是重量级的,因为它在父进程的内存区域工作,因此执行速度更快。

进程内线程之间的通信更容易,因为它们共享相同的内存空间。,而进程间的通信(IPC-进程间通信)较慢。不过话说回来,共享相同数据的线程可能会进入竞争状态,应该使用Locks或类似的解决方案来处理。

4.达斯克 ^

Photo by Trevor Cole on Unsplash

Dask是一个并行计算库,它不仅帮助并行化现有的机器学习工具(PandasNumpy )[ ,即使用高级集合 ],还帮助并行化低级任务/功能,并可以通过制作任务图来处理这些功能之间的复杂交互。[ 即使用低级调度程序 ]这类似于 Python 的线程或多处理模块。

他们还有一个独立的机器学习库dask-ml,它与现有的库如sklearnxgboosttensorflow集成在一起。

from dask import delayed as delay@delay
def add(x, y):
    return x+y
@delay
def sq(x):
    return x**2# Now you can use these functions any way you want, Dask will 
# parallelize your execution. And as the name suggest Dask 
# will not execute your function callings right away, rather
# it will make a computational graph depending on the way you are
# calling functions on inputs and intermediate results. To compute
# final result:
result.compute()

Dask 做任何事情都有一种天生的并行性。对于它如何处理数据帧,您可以将它看作是一种分而治之的方法,它将您的数据帧分成块,然后并行应用您给定的函数。

df = dask.DataFrame.read_csv("BigFile.csv", chunks=50000)
# Your DataFrame has been divided into chunks and every function
# you apply will be applied to all chunks separately and in 
# parallel.# It has most of Pandas functions which you can use:
agg = df.groupby(["column"]).aggregate(["sum", "mean"])
agg.columns = new_column_namesdf_new = df.merge(agg.reset_index(), on="column", how="left")
# It have not compute result up until now,# but with .compute() it will compute now in parallel.
df_new.compute().head()

它们也有在机器集群上运行它们接口。

关于Dask的完整介绍,请看我的帖子这里

5.火炬.多重处理 ^

Photo by Matthew Hicks on Unsplash

torch.multiprocessing是 Python multiprocessing模块的包装器,其 API 与原始模块 100%兼容。所以可以用Queue的、Pipe的、Array的等等。这些都在 Python 的多重处理模块中。除此之外,为了使它更快,他们增加了一个方法share_memory_(),它允许数据进入任何进程都可以直接使用它的状态,因此将该数据作为参数传递给不同的进程不会复制该数据。

你可以分享Tensors,model 的parameters,你可以随心所欲的在 CPU 或者 GPU 上分享。

**Warning from Pytorch: (Regarding sharing on GPU)
**  CUDA API requires that the allocation exported to other processes remains valid as long as it’s used by them. You should be careful and ensure that CUDA tensors you shared don’t go out of scope as long as it’s necessary. This shouldn’t be a problem for sharing model parameters, but passing other kinds of data should be done with care. Note that this restriction doesn’t apply to shared CPU memory.

你可以在这里的“池和进程”部分使用上面的方法,为了获得更快的速度,你可以使用share_memory_()方法在所有进程之间共享一个Tensor(比方说)而不被复制。

**# Training a model using multiple processes:**import torch.multiprocessing as mp
def train(model):
    for data, labels in data_loader:
        optimizer.zero_grad()
        loss_fn(model(data), labels).backward()
        optimizer.step()  ***#*** *This will update the shared parameters*model = nn.Sequential(nn.Linear(n_in, n_h1),
                      nn.ReLU(),
                      nn.Linear(n_h1, n_out))model.share_memory() **#** Required for 'fork' method to workprocesses = []
for i in range(4): # No. of processes
    p = mp.Process(target=train, args=(model,))
    p.start()
    processes.append(p)for p in processes: p.join()

您也可以使用一组机器。更多信息请参见此处

**NOTE:** For little introduction (kind of) on usage of **Pycuda**, see Jupyter Notebook's PyCuda section [here](https://nbviewer.jupyter.org/github/PuneetGrov3r/MediumPosts/blob/master/SpeedUpYourAlgorithms/3%29%20Prallelization.ipynb#5.-Pycuda-(Optional)).

6.延伸阅读 ^

  1. https://blog . rise ml . com/comparising-Google-TPU v2-对抗-NVIDIA-v100-on-resnet-50-C2 BBB 6 a 51 e 5 e
  2. https://medium . com/synced review/Google s-TPU-chip-goes-public-in-challenge-to-NVIDIA-s-GPU-78 ced 56776 b5
  3. https://sebastianraschka . com/Articles/2014 _ multi processing . html
  4. https://towards data science . com/how-I-learn-to-love-parallelised-apply-with-python-pandas k-and-numba-f 06 b0b 367138
  5. https://www.geeksforgeeks.org/multiprocessing-python-set-2/
  6. https://www . geeksforgeeks . org/multi threading-in-python-set-2-synchron ization/
  7. https://medium . com/idealo-tech-blog/parallelisation-in-python-an-alternative-approach-b 2749 b 49 a 1 e
  8. https://stack overflow . com/questions/990102/python-global-interpreter-lock-Gil-workrance-on-multi-core-systems-using-task
  9. https://stack overflow . com/questions/38666078/fast-queue-of-read-only-numpy-arrays
  10. https://medium . com/@ rvprasad/data-and-chunk-size-matter-when-using-multi processing-pool-map-in-python-5023 c 96875 ef
  11. https://stackabuse.com/parallel-processing-in-python/

7.参考文献 ^

a)池和过程:

  1. https://docs.python.org/3/library/multiprocessing.html
  2. https://www . elli cium . com/python-multi processing-pool-process/

b)穿线:

3.https://realpython.com/python-gil/

4.https://stack overflow . com/questions/29270818/why-a-python-I-o-bound-task-not-blocked-by-the-Gil

5.https://stack overflow . com/questions/27455155/python-multi processing-combined-with-threading

6.https://stack overflow . com/questions/6893968/how-to-get-the-return-value-from-a-thread-in-python

7.https://stack overflow . com/questions/200469/a-process-and-a-thread 的区别是什么

c)达斯克

8.【https://ml.dask.org

9.https://docs.dask.org/en/latest/

d)火炬.多重处理:

9.https://pytorch.org/docs/stable/multiprocessing.html

10.https://pytorch.org/docs/stable/notes/multiprocessing.html

d) Pycuda:

11.https://documen.tician.de/pycuda/tutorial.html

12.https://github.com/inducer/pycuda/tree/master/examples

13.https://www3.nd.edu/~zxu2/acms60212-40212-S12/Lec-12-02.pdf

Suggestions and reviews are welcome.
Thank you for reading!

签名:

使用自适应 softmax,第 1 部分,将深度学习语言模型的速度提高 1000%

原文:https://towardsdatascience.com/speed-up-your-deep-learning-language-model-up-to-1000-with-the-adaptive-softmax-part-1-e7cc1f89fcc9?source=collection_archive---------5-----------------------

您希望将语言建模(LM)任务的速度提高 1000%,而准确性几乎没有下降吗?最近,脸书人工智能研究小组(FAIR) 的一篇论文,作者是格雷夫等人(2017) ,名为“GPU 的高效 softmax 近似”,展示了如何通过他们的“自适应 softmax”,在语言建模最耗时的方面之一,计算繁重的 softmax 步骤中获得大规模加速。使用 adaptive softmax 带来的巨大加速只带来了最小的准确性成本,因此任何正在进行语言建模的人都应该考虑使用它。在这篇博文的第 1 部分,我将全面解释自适应 softmax,然后在第 2 部分我将带你一步一步地完成 Pytorch 实现(附带 Jupyter 笔记本,它使用 Pytorch 的内置AdaptiveLogSoftmaxWithLoss函数。

In my experiment (see Part 2 of this blog), the adaptive softmax version of my model trained 3x faster than the same model using a traditional softmax. Final accuracy was nearly the same.

您可能知道,语言建模是自然语言处理(NLP)中最基本和最重要的任务之一。它包括创建一个模型,当给定一个单词序列作为输入时,该模型可以预测序列中的下一个单词(这就是在手机键盘上启用预测文本功能的原因)。为了做到这一点,语言模型中的最后一个计算步骤涉及从语言模型的词汇表中的大量单词中选择要选择的单词。由于词汇表通常包含 10 或 100 个成千上万的单词,这最后一步是非常计算和耗时的。

Predictive texting… Did you mean “auto cucumber” or “autocorrect”?

那么语言模型如何从词汇表中选择一个单词作为它的预测呢?在标记化/数值化预处理步骤之后,模型的典型输入可能是大小为 [seq_length,bs] 的张量,目标也可能是大小为 [seq_length,bs] (实际上是将输入移动到未来的一个时间点),其中 bs 是给定迷你批次中的示例数量, seq_length 是任何给定示例的长度。在访问嵌入后(数据现在的大小为【seq _ length,bs,emb _ SZ】),通常数据通过多层使用 LSTM 或 GRU 单元的递归神经网络(RNN),得到大小为【seq _ length,bs,NH】的最终隐藏状态输出,其中 nh 是最终层的维度。目标是计算 p(w|h) …即给定最终隐藏状态 h 的单词 w 的概率(这里, h 是给定示例和时间点的最终隐藏状态输出,长度为 nh 的向量)。

从隐藏状态输出中获得预测的 softmax 解决方案包括首先使用完全连接的线性层转换输出,输出特征的数量等于词汇表的大小(因此从大小 [seq_length,bs,nh] 到大小 [seq_length,bs,vs] ,其中 vs 是词汇表的大小)。然后将 softmax 公式 exp(x[i]) / sum(exp(x)) 应用于词汇表中的所有单词,为每个单词产生一个概率值(在 0 和 1 之间)。最后,通常使用负对数似然(NLL)损失将这些预测与目标进行比较。

Model design for a small RNN-network, with vs=25520 and nh=300. Notice that the last step is a fully-connected linear layer, that transforms the dimensionality from 300 to 25520.

将输出从大小 [seq_length,bs,nh] 转换为大小 [seq_length,bs,vs] 的步骤非常庞大!这最后一步的计算成本与你的词汇量成线性关系,如前所述,如果你想要一个像样的语言模型,词汇量将会很大。对于 nhvs 的典型值,此变换的权重矩阵可以是 size [1,000 x 200,000],它应用于数据集中每个示例的每个时间步长。这一步主导了训练和测试时的计算,对于任何语言模型来说都是一个主要的耗时步骤。

Grave 等人的 adaptive softmax 是解决这个问题的一个非常好的解决方案。要理解它,你首先需要理解层次化的 softmax,这是之前加速 softmax 的尝试(例如 Morin & Bengio,2005 )。你首先将每个单词 w 分配到一个唯一的簇 C(w) 。分层的 softmax 然后将 softmax 分成两个阶段:首先预测聚类 C ,然后对该聚类的所有单词进行 softmax。你可以将给定最终隐藏状态 h 的单词 w 的条件概率因式分解为 p(w|h) = p(w | C(w),h) * p( C(w) | h) …即给定隐藏状态 h 的单词 w 的概率,就是给定 C(w) 的概率简单来说,首先只需预测簇,然后预测簇中的哪个单词。这将把计算时间从与词汇表大小成线性减少到词汇表大小的平方根数量级。

Grave et al., 2017

然而,正如 Grave 等人的论文中所解释的,分层的 softmax 实际上在 GPU 上并不工作得那么好(对此的解释超出了本文的范围)。他们的自适应 softmax 是为 GPU 定制的分层 softmax 的简单变体。它利用了 Zipf 定律…观察到在任何语料库中,单词分布的大部分概率质量只被一小部分词汇覆盖。例如,在 Penn Treebank 数据集中,文档中 87%的单词仅被 20%的词汇覆盖。adaptive softmax 利用这一信息,根据单词的常见程度将词汇表中的单词分配到聚类中。

为了理解这种方法,最好从最简单的自适应 softmax 开始,其中词汇表被划分为两个集群,Vᴴᴱᴬᴰ和 Vᵀᴬᴵᴸ.在你的语料库中,少量的最频繁出现的单词应该进入 Vᴴᴱᴬᴰ,而 Vᵀᴬᴵᴸ应该包含剩余的不频繁出现的单词。所以在你的语料库中,一个词出现在 Vᴴᴱᴬᴰ的可能性比出现在 Vᵀᴬᴵᴸ(即 p(Vᴴᴱᴬᴰ) > p(Vᵀᴬᴵᴸ的可能性大得多,但是 Vᵀᴬᴵᴸ的词应该比 Vᴴᴱᴬᴰ.的多得多

在这个 2-聚类示例中的第一步是计算头部中所有单词的 softmax,加上对应于选择尾部聚类的 1 个额外的“单词”。也就是说,首先对 Vᴴᴱᴬᴰ + 1 个单词进行 softmax,其中额外的“单词”是它属于尾簇的概率。对于 Vᴴᴱᴬᴰ的单词, p(w|h) 简单来说就是 pᴴᴱᴬᴰ(w|h) …也就是说,只要计算给定 h 的单词在 Vᴴᴱᴬᴰ出现的概率。如果选择了与尾类别相对应的“单词”,那么只需要对 Vᵀᴬᴵᴸ).中的所有单词进行额外的 softmax 对于这些单词, p(w|h)是 pᴴᴱᴬᴰ(tail|h) * pᵀᴬᴵᴸ(w|h) …即,如果 pᴴᴱᴬᴰ(w|h) 表示“尾簇”,则取“尾簇”在头部的概率,乘以所选单词在尾部的概率。对于仅使用这种双集群方法,Grave 等人观察到比完整的 softmax 快 5 倍!

但是,通过使用更多的集群,您可以获得更大的收益…最佳组合似乎是 2-5 个集群。该方法与 2-聚类示例相同,除了第一个 softmax 将覆盖头部中的所有单词,再加上表示尾部聚类的许多附加“单词”。例如,对于 5 个集群的实现,初始 softmax 将超过 Vᴴᴱᴬᴰ + 4 个字。如果在初始 softmax 中选择了尾部聚类“单词”中的一个,那么将只在所选尾部中的单词上计算额外的 softmax。使用与上述相同的原理,最频繁的单词被分配到最小的簇中…头部和第一个尾部将具有更频繁的单词但具有更小的词汇量,最后一个尾部将具有不太频繁的单词和更大的词汇量。

Figure 3 from Grave et al., 2017. This figure shows a clustering with 4 clusters: a head and 3 tails. The head contains a small number of the most frequent words, whereas the tails contain larger numbers of less frequent words.

还有一个以最小的准确性代价提高速度的窍门,那就是每个集群被赋予不同的容量。以上, nh 是最终隐藏状态输出容量的度量。您需要高容量来正确预测最频繁出现的单词。然而,根据定义,生僻字只出现几次,因此无法通过您的模型很好地学习……为这些字使用高容量是一种浪费。因此,Grave 等人通过应用一个投影矩阵,将每个额外的尾部聚类的维数减少了 4 倍,从而减少了尾部聚类的 softmax 的最终隐藏状态输入的维数(一旦我们通过这篇博客文章的第 2 部分中的示例实现,这将变得更加清楚)。

就是这样!您可以使用上面概述的原则(或通过使用动态编程),试验聚类的数量和单词在聚类之间的分布,以找出哪些单词最适合您的数据集。总体而言,自适应 softmax 提供了巨大的速度提升(高达 10 倍!)在整个 softmax 上,以最小的精度代价。[查看我在 CNN 的博客文章,它也可以加速 NLP 的训练]。当你需要从大量可能的类别中进行选择时,自适应 softmax 会很有帮助,其中一些类别比其他类别更常见。这不仅适用于语言建模,也适用于许多其他 NLP 任务(神经机器翻译(NMT)、语音到文本等)。),可能对于许多非语言应用程序也是如此。查看这篇博文的第 2 部分来一步步了解自适应 softmax 的 Pytorch 实现,它使用了 Pytorch 的内置AdaptiveLogSoftmaxWithLoss函数。

参考资料:

Grave,Edouard 等人,“GPU 的高效 softmax 近似”arXiv 预印本 arXiv:1609.04309v3 (2017)。

莫兰,弗雷德里克,约舒厄·本吉奥。"分层概率神经网络语言模型."Aistats。第五卷。2005.

使用自适应 softmax,第 2 部分:Pytorch 实现,将深度学习语言模型的速度提高 1000%

原文:https://towardsdatascience.com/speed-up-your-deep-learning-language-model-up-to-1000-with-the-adaptive-softmax-part-2-pytorch-d47fe9a56152?source=collection_archive---------6-----------------------

在这篇博文的第一部分中,我解释了自适应 softmax 是如何工作的,以及它是如何将你的语言模型加速 1000%的。在第 2 部分中,我将带您一步一步地完成 Pytorch 实现(附带一个 Jupyter 笔记本,它使用 Pytorch 的内置AdaptiveLogSoftmaxWithLoss函数。

对于预处理,你将需要 fastai(见https://docs.fast.ai/),一个运行在 Pytorch 之上的深度学习库,它简化了训练神经网络。【对于想学习最前沿深度学习技术的人,我强烈推荐网上免费提供的杰瑞米·霍华德的 fast.ai 课程:https://course.fast.ai/】。我决定使用 Wikitext-2 数据集,这是一个相对较小的数据集,包含大约 200 万个令牌和大约 3.3 万个词汇。一旦数据被下载并正确格式化为 csv 文件,fastai 就可以轻松地快速标记、数字化并创建一个用于训练的数据加载器。我还下载了 GloVe 预训练单词向量,用于模型的单词嵌入。最后,我创建了一个处理训练的 modeler 类。

对于模型,我创建了一个简单版本的准递归神经网络(QRNN),它比传统的递归神经网络(RNNs)具有更好的预测精度,并且速度快 16 倍(参见 Bradbury 等人,2016)。我构建的网络相对较小,只有 4 层,每层有 300 个隐藏单元…我的目的是创建一个可以相对较快地达到一个不错的(如果不是最先进的)结果的网络。梯度裁剪的使用允许使用大的学习率( lr =1),这与内斯特罗夫的动量一起帮助训练快速收敛。

第 1 部分描述了数据如何通过网络传输。最后一个 QRNN 层的输出 x 的大小为【seq _ length = 70,bs=50,NH = 300】,其中 seq_length 为序列的长度, bs 为批量大小, nh 为最后一层的维数。

x, new_h = self.rnn(x, self.hidden)

常规 Softmax

对于常规的 softmax,最后一个 QRNN 层之后的下一步是完全连接的线性层(这里称为 fc1 ),它将输出转换为具有与词汇表大小相等的多个输出特征(因此从大小【seq _ length,bs,nh】】到大小【seq _ length,bs,vs】,其中 vs 是您的词汇表大小)。对于大多数语言模型来说,计算时间由这个操作决定。

#self.fc1 = nn.Linear(nh, vs)
x= self.fc1(x)

然后,模型输出这些值的 log-softmax,负 log-likelihood 用于计算损失。

return F.log_softmax(x.view(-1,vs),dim=1)
...
loss = self.criterion(output, target)

自适应 Softmax

自适应 softmax 的方法略有不同。最后一个 QRNN 层的输出 x 仍然是大小【序列长度=70,bs=50,NH = 300】。然后将输出调整到 [seq_lengthbs,nh]* ,并输入到AdaptiveLogSoftmaxWithLoss函数,该函数为您计算损失。

x,new_h = self.rnn(x, self.hidden)
x=x.view(-1,x.size()[2])
#self.out=nn.AdaptiveLogSoftmaxWithLoss(nh, vs, cutoffs=[round(vs/15), 3*round(vs/15)], div_value=4)
return self.out(x,target)
...
loss= output.loss

让我们看看 AdaptiveLogSoftmaxWithLoss 函数是做什么的。你可以看到我指定了截止值= [round(vs/15),3*round(vs/15)]。这意味着我将把我的 25520 个单词分成 3 组。头部聚类包含 1701 个最常见的单词(即,词汇表的 1/15),加上两个“单词”来指示两个尾部聚类的可能性,总共 1703 个单词。第一个尾簇包含接下来的 3402 个最常用的单词(即词汇表的 2/15),第二个尾簇包含剩余的 20417 个最不常用的单词(即词汇表的 12/15)。为了做到这一点,我需要确保我的词汇表(这里称为 itos )是按照从最常见到最不常见的单词的顺序组织的。

正如我在第 1 部分中提到的,这些集群中的每一个都被赋予了不同的容量,其相对大小由赋予 AdaptiveLogSoftmaxWithLoss 函数的 div_value 指定。为 4 的 div_value 意味着每个附加集群的容量将比前一个集群小 4 倍。在这种情况下,首簇的容量为 300,第一个尾簇的容量为 75,第二个尾簇的容量仅为 18。这意味着对于头部聚类中最常见的单词,它将直接将维度从 300 转换为 1703 输出特征(因为 1703 是头部中词汇单词的数量)。然而,对于第一个尾部聚类,在第二个线性层将维度转换为 3402 个输出特征之前,初始线性层将首先将维度减少到 75 个特征。维度的初始减少加快了处理时间(与从 300 个输入要素到 3402 个输出要素的直接线性变换相比)。对于最后一个尾部聚类中最不常用的单词,发生类似的过程。

(out): AdaptiveLogSoftmaxWithLoss(
    (head): Linear(in_features=300, out_features=1703, bias=False)
    (tail): ModuleList(
      (0): Sequential(
        (0): Linear(in_features=300, out_features=75, bias=False)
        (1): Linear(in_features=75, out_features=3402, bias=False)
      )
      (1): Sequential(
        (0): Linear(in_features=300, out_features=18, bias=False)
        (1): Linear(in_features=18, out_features=20417, bias=False)
      )
    )

结果

传统 softmax 网络的最终损耗为 4.84(困惑度= 127),而自适应 softmax 网络的最终损耗为 4.88(困惑度= 132)。这是不到 1%的最终损失差异(和 4%的困惑差异)。另一方面,自适应 softmax 网络在 7.80 分钟(7 分 48 秒)完成计算,而传统 softmax 网络在 24.55 分钟完成计算。因此,两种方法的结果在准确性方面非常相似,但自适应 softmax 网络的运行速度快 3 倍!这些结果与 Grave 等人在 Text8 数据集(与我使用的 Wikitext-2 数据集大小相似)上的实验相匹配…与完整的 softmax 相比,最终损失几乎相同,但加速几乎是 3 倍。

Plotting time vs loss for the two approaches. Even though the final result is nearly the same, the adaptive softmax network completes training 3x quicker than an identical traditional softmax network.

Plotting epoch vs loss for the traditional and adaptive softmax approaches. Training proceeds almost identically between the two approaches, although the traditional softmax network completes with a 1% lower loss than the adaptive softmax network.

那么自适应的 softmax 相比传统的 softmax 有多好呢?如果我决定进行更多时期的训练,很可能最终的损失会更大。然而,Grave 等人(2017)和其他 NLP 研究人员(例如 Dauphin 等人,2016)表明,他们实际上能够使用 adaptive softmax 在各种数据集上实现最先进的语言建模结果。因此,您应该考虑将自适应 softmax 添加到您的语言建模工具箱中,因为它以最小的准确性成本提供了超过完整 softmax 的巨大速度。参见第 1 部分了解自适应 softmax 如何工作的完整解释。

参考资料:

布拉德伯里,詹姆斯,等。“准递归神经网络。”arXiv 预印本 arXiv:1611.01576 (2016)。

多芬,扬恩 n .等人,《用门控卷积网络进行语言建模》arXiv 预印本 arXiv:1612.08083 (2016)。

格雷夫,爱德华,等,“GPU 的有效软最大近似”arXiv 预印本 arXiv:1609.04309v3 (2017)。

用广播和 PyTorch 加速你的 Python 代码

原文:https://towardsdatascience.com/speed-up-your-python-code-with-broadcasting-and-pytorch-64fbd31b359?source=collection_archive---------6-----------------------

Image credit: Saffu at https://unsplash.com/photos/E4kKGI4oGaU

广播使得向量化您的代码成为可能,在 Numpy 的底层 C 实现中执行数组运算,而不必制作不必要的数据副本。根据不同的情况,这可以给你的代码带来显著的加速。此外,事实证明,如果您在 Numpy 中使用广播,您可以轻松地将代码移植到 PyTorch,然后在您的 GPU 上运行相同的代码,从而获得更高的速度!

当我做硕士论文的时候,我花了很多时间处理大量的激光雷达数据。其中一个步骤是移除属于场景中静态对象(建筑物、栅栏等)的所有点测量。场景中的每个静态对象都被建模为一个矩形对象,这实质上意味着我必须检查每个激光雷达测量值是否落在任何矩形内。我论文中使用的激光雷达工作在 10Hz,每次扫描包含大约 100,000 到 150,000 次测量,这意味着一秒钟的激光雷达数据对应于需要处理的 1-150 万个激光雷达点。那时我不了解 Python 或广播,所以我的这个处理步骤的实现不是那么快或有效。现在,我将以这个问题为例,展示如何使用 broadcasting 和 PyTorch 编写一个非常快速的算法实现。

如何确定一个点是否在矩形中

有一个简单的公式可以用来确定一个点是否在矩形内。如果我们假设矩形的每个角(x,y)被表示为 A,B,C,D,并且我们所讨论的点位于(x,y)点 P,那么公式可以被表示为

AP denotes the vector from point A to point P. The · sign denotes dot multiplication between the vectors.

如果这两个条件都满足,则该点位于矩形内,否则不满足。

没有广播的实现

如果我们以“标准”的方式实现算法,我们会得到这样的结果:

def in_boxes(boxes, points):
  # (N, 4, 2) = boxes.shape
  # (M, 2) = points.shape w = np.zeros(points.shape[0])
  for (i, point) in enumerate(points):
   in_box = False
   for box in boxes:
     (A, B, C, D) = box
     AP = (point — A)
     AB = (B — A)
     AD = (D — A)
     cond0 = 0 < np.dot(AP, AB) < np.dot(AB, AB)
     cond1 = 0 < np.dot(AP, AD) < np.dot(AD, AD)
     in_box = in_box or (cond0 and cond1)
   if in_box:
     w[i] = 1
   else:
     w[i] = 0
  return w

输入参数对应于出现的框和我们想要检查的点。盒子由形状为(N,4,2)的数组表示,其中N 对应于盒子的数量,4反映了我们有角(A,B,C,D),而2反映了每个角的 xy 位置。我们想要研究的点由形状为(M, 2)的数组表示,其中M对应于点的数量,2反映每个点的 xy 位置。

在我的 MBP 2014 上用 3 个盒子和 1,000,000 个积分运行这个功能大约需要 21.47 秒。让我们看看使用 Numpy 广播重写函数时会发生什么。

广播,我怎么用?

在我们继续实现之前,让我们快速讨论一下如何使用广播。判断一个点是否在矩形中的算法的核心部分是计算向量AP,即每个点和每个坐标的P-A。所有的 A 坐标可以存储在一个形状为(N, 2)的数组A中。类似地,我们有M点,这些点存储在形状为(M, 2)的数组P中。现在,如果我们以下面的方式给数组增加一个额外的维度,我们将增加秩(维度的数量),数组将有新的形状

>>> A.shape
(M, 2)
>>> P.shape
(N, 2)
>>> A = A[:, None, :]
>>> P = P[None, ...]
>>> A.shape
(M, 1, 2)
>>> P.shape
(1, N, 2)

正是在这个阶段,广播开始发挥作用。如果我们现在选择计算两个数组之间的差,我们将得到一个形状为(M, N, 2)的数组

>>> (P - A).shape
(M, N, 2)

因此,Numpy 正在广播大小为 1 的每个维度中的数据,以便匹配两个数组的大小。这意味着 Numpy 本质上在第一维度上重复了 N 次A数组,在第 0 维度上重复了 M 次P数组。这种数据重复是在底层 C 实现中执行的,并且利用了指针,这意味着不会为了执行重复而复制数据(也就是说,我们不会因为必须复制数据而耗尽空间)。

这基本上展示了如何使用广播。通过向我们的数组添加额外的 1 维,并确保它们以相同的秩结束,我们可以执行任何类型的算术运算,并以我们想要的方式结束结果排序,而不必使用 for 循环。至此,让我们看看如何使用广播实现in_boxes算法

广播的实现

使用广播实现算法非常简单。为了更容易理解发生了什么,我在每一行都添加了注释,描述每个操作的结果形状。由于 Numpy 的np.dot()方法不支持广播,我将数组逐元素相乘(因为它支持广播),然后在最后一个维度上求和,因为这个操作对应于点积。

def in_boxes_bc(boxes, points):
  # (N, 4, 2) = boxes.shape
  # (M, 2) = points.shape (A, B, C, D) = np.split(boxes, 4, axis=1)  # (N, 1, 2)
  AM = (points[None, ...] - A)  # (N, M, 2)
  AB = (B - A)  # (N, 1, 2)
  AD = (D - A)  # (N, 1, 2) 

  AM_AB = np.sum(AM * AB, axis=-1)  # (N, M)
  AB_AB = np.sum(AB * AB, axis=-1)  # (N, 1)
  AM_AD = np.sum(AM * AD, axis=-1)  # (N, M)
  AD_AD = np.sum(AD * AD, axis=-1)  # (N, 1)

  cond0 = (0 < AM_AB) & (AM_AB < AB_AB)  # (N, M)
  cond1 = (0 < AM_AD) & (AM_AD < AD_AD)  # (N, M)

  in_box = cond0 & cond1  # (N, M) = in_box.shape
  w = np.any(in_box, axis=0)
  return w

在我的 MBP 2014 上用 3 个盒子和 1,000,000 个点运行这个版本的算法大约需要 0.36 秒。与之前花费的时间 21.47 秒相比,这意味着我们实现了到 60 倍的速度提升!

使用 PyTorch 在 GPU 上运行

该算法的广播变体的真正巧妙之处在于,它非常容易移植到 PyTorch,这允许我们在 GPU 上运行相同的算法,从而可以进一步加快算法的速度!Numpy 和 PyTorch 都以相同的方式实现广播,唯一的警告是 PyTorch 对一些数学函数及其参数有稍微不同的命名方案。(cuda()函数用于将数据移动到 GPU,而cpu()用于将数据从 GPU 移回)。

def in_boxes_torch(boxes, points):
  boxes = torch.DoubleTensor(boxes).cuda()
  points = torch.DoubleTensor(points).cuda()

  dd = torch.chunk(boxes, 4, dim=1)
  (A, B, C, D) = dd AM = (points[None, ...] - A)
  AB = (B - A)
  AD = (D - A) AM_AB = torch.sum(AM * AB, dim=-1)
  AB_AB = torch.sum(AB * AB, dim=-1)
  AM_AD = torch.sum(AM * AD, dim=-1)
  AD_AD = torch.sum(AD * AD, dim=-1) cond0 = (0 < AM_AB) & (AM_AB < AB_AB)
  cond1 = (0 < AM_AD) & (AM_AD < AD_AD)

  in_box = cond0 & cond1
  # PyTorch does not have anything corresponding to np.any()
  w = (torch.sum(in_box, dim=0) > 0)
  return w.cpu()

使用与之前相同的场景(3 个盒子和 1,000,000 个点),但这次在 GTX 980 Ti 上运行大约需要 0.026 秒* ,与使用广播的版本相比速度增加了 ~14x ,与算法的第一个版本相比速度增加了 ~826x

广播可以用来使某些类型的算法运行得更快,这很酷(尽管应该注意到情况并不总是这样,所以在开始使用广播进行任何类型的计算之前要小心)。能够快速移植代码在 GPU 上运行的额外好处是非常惊人的,特别是因为 ML/DL 领域的大多数人通常都可以使用非常强大的 GPU。速度上的差异很重要,因为这可能是等待几分钟算法完成与等待几小时(甚至几天)算法完成之间的差异!).

非常感谢 Adam Fjeldsted 校对这篇文章!

关于在 GPU 上运行代码,有两点值得注意:

  1. 功能 *in_boxes_torch* 包括将数据移动到 GPU
  2. 第一次使用 PyTorch 将数据移动到 GPU 比后续的移动花费更多的时间,因为建立到 GPU 的连接会有一些开销(这种开销与您试图移动到 GPU 的数据大小无关,在我的机器上大约是 2 秒)。因此,在运行和计时 *in_boxes_torch* 函数之前,我先将一些虚拟数据移入和移出 GPU。

加速卷积神经网络

原文:https://towardsdatascience.com/speeding-up-convolutional-neural-networks-240beac5e30f?source=collection_archive---------2-----------------------

Source: http://yesofcorsa.com/wp-content/uploads/2017/04/High-Speed-Photo.jpg

加速卷积神经网络训练而不显著影响精度的方法综述。

有趣的是,完全连接的层是神经网络占用大量内存的主要原因,但速度很快,而卷积虽然参数数量很少,但却消耗了大部分计算能力。实际上,卷积是如此的计算饥渴,以至于它们是我们需要如此多的计算能力来训练和运行最先进的神经网络的主要原因。

我们能设计出既快速又高效的卷积吗?

某种程度上——是的!

有一些方法可以在不严重降低模型精度的情况下加速卷积。在这篇博文中,我们将考虑以下方法。

  • 卷积核的因子分解/分解
  • 瓶颈层
  • 更宽的回旋
  • 深度可分卷积

下面,我将深入研究所有这些方法的实现和背后的原因。

简单因式分解

让我们从 NumPy 中的以下示例开始

>>> from numpy.random import random
>>> random((3, 3)).shape == (random((3, 1)) * random((1, 3))).shape
>>> True

你可能会问,为什么我要给你看这个愚蠢的片段?答案是,它表明你可以写一个 NxN 矩阵,把卷积核想象成 2 个较小的矩阵/核的乘积,形状为 Nx1 和 1xN。回想一下,卷积运算需要in_channels * n * n * out_channels 参数或权重。此外,请记住,每个重量/参数都需要激活。因此,参数数量的任何减少都将减少所需的操作数量和计算成本。

假设卷积运算实际上是使用张量乘法来完成的,而张量乘法是多项式的,依赖于张量的大小,正确应用因式分解应该会产生明显的加速。

在喀拉斯,它看起来像这样:

# k - kernel size, for example 3, 5, 7...
# n_filters - number of filters/channels
# Note that you shouldn't apply any activation
# or normalization between these 2 layers
fact_conv1 = Conv(n_filters, (1, k))(inp)
fact_conv1 = Conv(n_filters, (k, 1))(fact_conv1)

不过,请注意,不建议使用最接近输入卷积层的因子。此外,分解 3x3 卷积甚至会损害网络性能。最好为更大的内核保留它们。

在我们深入这个主题之前,有一个更稳定的方法来分解大内核:只是堆叠较小的内核。例如,不使用 5x5 卷积,而是堆叠两个 3x3 卷积,或者如果您想要替换 7x7 内核,则堆叠 3 个卷积。有关更多信息,请参见[4]。

瓶颈层

瓶颈层背后的主要思想是通过减少输入通道的数量(也称为输入张量的深度)来减少内核大于 1×1 的卷积层中的输入张量的大小。

这是它的 Keras 代码:

from keras.layers import Conv2D# given that conv1 has shape (None, N, N, 128)conv2 = Conv2D(96, (1, 1), ...)(conv1) # squeeze
conv3 = Conv2D(96, (3, 3), ...)(conv2) # map
conv4 = Conv2D(128, (1, 1), ...)(conv3) # expand

几乎所有的 CNN,从革命性的概念 1 到现代的 DenseNet,都在以这样或那样的方式使用瓶颈层。这种技术有助于保持参数的数量,从而降低计算成本。

更宽的回旋

另一种加速卷积的简单方法是所谓的宽卷积层。你看,你的模型卷积层数越多,速度就越慢。然而,你需要大量卷积的表示能力。你是做什么的?你使用更少但更胖的层,其中脂肪意味着每层更多的果仁。为什么有效?因为对于 GPU 或其他大规模并行机器来说,处理单个大块数据比处理大量较小的数据更容易。更多信息可以在[6]中找到。

# convert from
conv = Conv2D(96, (3, 3), ...)(conv)
conv = Conv2D(96, (3, 3), ...)(conv)
# to
conv = Conv2D(128, (3, 3), ...)(conv)
# roughly, take the sqrt of the number of layers you want
# to merge and multipy the number to
# the number of filters/channels in the initial convolutions
# to get the number of filters/channels in the new layer

深度可分卷积

在深入研究这种方法之前,要知道它非常依赖于可分离卷积在给定框架中的实现方式。就我而言,TensorFlow 可能会对这种方法进行一些特定的优化,而对于其他后端,如 Caffe、CNTK 或 PyTorch,还不清楚。

Vincent Vanhoucke, April 2014, “Learning Visual Representations at Scale”

这个想法是,不是在图像的所有通道上联合卷积,而是在每个深度为channel_multiplier的通道上运行单独的 2D 卷积。in_channels * channel_multiplier个中间通道连接在一起,并使用 1x1 卷积映射到out_channels。[5]这样一来,需要训练的参数就少得多。[2]

# in Keras
from keras.layers import SeparableConv2D
...
net = SeparableConv2D(32, (3, 3))(net)
...
# it's almost 1:1 similar to the simple Keras Conv2D layer

事情没那么简单。请注意,可分卷积有时不是训练。在这种情况下,将深度倍增从 1 修改为 4 或 8。还要注意,这些算法在小数据集上效率不是很高,比如 CIFAR 10,此外还有 MNIST。另一件要记住的事情是,不要在网络的早期阶段使用可分卷积。

Source: V. Lebedev et al, Speeding-up Convolutional Neural Networks Using Fine-tuned CP-Decomposition

CP 分解和高级方法

上述因式分解方案在实践中工作良好,但是非常简单。它们可以工作,但是还没有达到极限。有许多工作,包括 V. Lebedev 等人的[3],向我们展示了不同的张量分解方案,这些方案大大减少了参数的数量,从而减少了所需的计算量。

受[1]启发,下面是如何在 Keras 中进行 CP 分解的代码片段:

# **kwargs - anything valid for Keras layers,
# like regularization, or activation function
# Though, add at your own risk# Take a look into how ExpandDimension and SqueezeDimension
# are implemented in the associated Colab Notebook
# at the end of the articlefirst = Conv2D(rank, kernel_size=(1, 1), **kwargs)(inp)
expanded = ExpandDimension(axis=1)(first)
mid1  = Conv3D(rank, kernel_size=(d, 1, 1), **kwargs)(exapanded)
mid2  = Conv3D(rank, kernel_size=(1, d, 1), **kwargs)(mid1)
squeezed = SqueezeDimension(axis=1)(mid2)
last  = Conv2D(out,  kernel_size=(1, 1), **kwargs)(squeezed)

遗憾的是,它不起作用,但是它给了你在代码中应该是什么样子的直觉。顺便说一下,文章顶部的图片是 CP 分解如何工作的图形解释。

应该注意诸如 TensorTrain 分解和 Tucker 这样的方案。对于 PyTorch 和 NumPy,有一个名为 Tensorly 的很棒的库,它为你做所有的底层实现。在 TensorFlow 中没有与之接近的东西,但还是有一个 TensorTrain(又名 TT 方案)的实现,这里是。

收场白

完整的代码目前可以作为一个带有特斯拉 K80 GPU 加速器的合作笔记本获得。给自己做一份拷贝,享受修改代码的乐趣。

如果你正在读这篇文章,我想感谢你,并希望上面写的对你有很大的帮助,就像对我一样。请在评论区让我知道你的想法。你的反馈对我很有价值。

另外,如果你喜欢这篇文章,别忘了鼓掌😏或者关注我更多类似的文章。

参考

[1]https://medium . com/@ krishnate jakrothapalli/hi-rain-4e 76039423 e 2
【2】f . Chollet,Xception:具有深度方向可分离卷积的深度学习,https://arxiv.org/abs/1610.02357v2
【3】v . lebe dev 等人,使用微调 CP 分解加速卷积神经网络,https://arxiv.org/abs/1412.6553
【4】c . Szegedy 等人,重新思考 Inception 架构

加速您的算法第 4 部分— Dask

原文:https://towardsdatascience.com/speeding-up-your-algorithms-part-4-dask-7c6ed79994ef?source=collection_archive---------4-----------------------

与 Dask 并行运行您的 Pandas/Numpy/Sklearn/Python 代码

Photo by Raul Cacho Oses on Unsplash

这是我写的系列文章中的第四篇。所有帖子都在这里:

  1. 加速你的算法第一部分— PyTorch
  2. 加速你的算法第二部分—数字
  3. 加速您的算法第 3 部分—并行化
  4. 加速您的算法第 4 部分— Dask

而这些与 Jupyter 笔记本 搭配在这里可以得到:

[Github-speedupyourlightms[ka ggle

(Edit-1/2/2019)添加了 dask . distributed . local cluster 的更多信息/可能用法

索引

  1. 简介
  2. 数据类型
  3. 延迟
  4. 分发
  5. 机器学习
  6. 延伸阅读
  7. 参考文献
***NOTE:*** This post goes with ***Jupyter Notebook*** available in my Repo on **Github**:[[SpeedUpYourAlgorithms-Dask](https://nbviewer.jupyter.org/github/PuneetGrov3r/MediumPosts/blob/master/SpeedUpYourAlgorithms/4%29%20Dask.ipynb)]
and on **Kaggle:** [[SpeedUpYourAlgorithms-Dask](https://www.kaggle.com/puneetgrover/speed-up-your-algorithms-dask)]

1.简介 ^

随着对机器学习算法并行化需求的增加,由于数据大小甚至模型大小的指数增长,如果我们有一个工具可以帮助我们并行处理Pandas的数据帧,可以并行处理Numpy的计算,甚至可以并行处理我们的机器学习算法(可能是来自sklearntensorflow的算法),而没有太多麻烦,这将是非常有用的。

但这样的库确实存在,它的名字叫DaskDask是一个并行计算库,它不仅帮助并行化现有的机器学习工具(PandasNumpy )[ ,即使用高级集合 ],还帮助并行化低级任务/功能,并可以通过制作任务图来处理这些功能之间的复杂交互。[ 即使用低级调度程序 ]这类似于 Python 的线程或多处理模块。

他们还有一个独立的机器学习库dask-ml,它与现有的库如sklearnxgboosttensorflow集成在一起。

Dask 通过绘制任务之间的交互图,将分配给它的任务并行化。通过使用Dask.visualize()方法来可视化您正在做的事情将会非常有帮助,该方法可用于它的所有数据类型和您计算的复杂任务链。该方法将输出您的任务的图表,如果您的任务在每一层都有许多节点(即您的任务链结构在许多层都有许多独立的任务,例如数据块上的可并行化任务),那么Dask将能够并行化它们。

**Note:**
Dask is still a relatively new project. It has a long way to go. Still if you don't want to go through learning a completely new API (like in case of PySpark) Dask is your best option, which surely will get better and better in future. 
Still Spark/PySpark is ways ahead and will still keep on improving. It is a well established Apache project. I will publish a post on PySpark in coming months.(Today: April'19)
If you want to start with PySpark, read this comment [here](https://medium.com/@grover.puneet1995/i-have-stated-in-third-section-4f8206c4f081).

2.数据类型 ^

Photo by Kai Oberhäuser on Unsplash

Dask中的每种数据类型都提供了现有数据类型的分布式版本,如Pandas中的DataFramenumpy中的ndarrayPython中的list。这些数据类型可能比你的内存大,Dask将以Blocked的方式对你的数据并行(y)运行计算。Blocked通过执行许多小计算来执行大计算,即以块为单位,块的数量是chunks的总数。

a)数组:

Many Numpy arrays in a grid as Dask Array

Dask Array 通过将非常大的数组分成块并并行执行这些块来对它们进行操作。它有许多可用的 numpy 方法,你可以用它们来加速。但是其中的部分没有实现。

Dask 数组可以从任何类似数组的结构中读取,只要它支持类似 numpy 的切片,并且通过使用dask.array.from_array方法具有.shape属性。也可以从.npy.zarr文件中读取。

import dask.array as da
import numpy as nparr = numpy.random.randint(1, 1000, (10000, 10000))darr = da.from_array(arr, chunks=(1000, 1000))
# It will make chunks, each of size (1000, 1000)
darr.npartitioins
# 100

当你的数组非常大的时候(也就是说,它们放不进内存)可以使用它,而numpy对此无能为力。所以,Dask把它们分成数组块,给你并行操作。

现在,Dask对每一个方法进行懒惰的评估。所以,要真正计算一个函数的值,你必须使用.compute()方法。它将在块中并行计算结果,同时并行处理每个独立的任务。

result = darr.compute()

  1. Numpy faster than Dask for smaller number of elements; 2) Dask taking over Numpy for around 1e7 elements; 3) Numpy not able to produce results for higher number of elements as it is not able to put them on memory.

b)数据帧:

5 Pandas’ DataFrames each providing monthly data (can be from diff files) in one Dask DataFrame

Dask Arrays类似,Dask DataFrame通过将文件划分为块,并对这些块并行地执行计算功能,来对无法容纳在内存中的非常大的数据文件进行并行计算。

import dask.dataframe as dd
df = dd.read_csv("BigFile(s).csv", blocksize=50e6)

现在,您可以应用/使用pandas库中的大多数功能,并在此处应用。

agg = df.groupby(["column"]).aggregate(["sum", "mean", "max", "min"])
agg.columns = new_column_names # see in notebook
df_new = df.merge(agg.reset_index(), on="column", how="left")
df_new.compute().head()

c)袋子:

Dask Bag s 对包含多种数据类型元素的Python``listlike 对象进行并行化计算。当您试图处理 JSON blobs 或日志文件之类的半结构化数据时,这很有用。

import dask.bag as db
b = db.from_txt("BigSemiStructuredData.txt")
b.take(1)

Dask bags 逐行读取,.take方法输出指定行数的元组。

Dask Bag对这类 Python 对象集合执行mapfilterfoldgroupby等操作。它使用 Python 迭代器以较小的内存占用并行完成这一任务。它类似于 PyToolz T21 的平行版本或者 PySpark RDD 的 Pythonic 版本。

filtered = b.filter(lambda x: x["Name"]=="James")\
                     .map(lambda x: x["Address"] = "New_Address")
filtered.compute()

3.延期 ^

Photo by Andrea Cau on Unsplash

如果您的任务有点简单,并且您不能或不想使用这些高级集合来完成,那么您可以使用低级调度程序来帮助您使用dask.delayed接口并行化您的代码/算法。dask.delayed也做懒计算。

import dask.delayed as delay@delay
def sq(x):
    return x**2
@delay 
def add(x, y):
    return x+y
@delay 
def sum(arr):
    sum=0
    for i in range(len(arr)): sum+=arr[i]
    return sum

您可以根据需要在这些函数之间添加复杂的交互,使用前一个任务的结果作为下一个任务的参数。Dask不会立即计算这些函数,而是会为您的任务制作一个图表,有效地整合您使用的函数之间的交互。

inputs = list(np.arange(1, 11))#Will be addin' dask.delayed to list
temp = []
for i in range(len(inputs)):
    temp.append(sq(inputs[i]))  # Compute sq of inputs and save 
                                # delayed in list
inputs=temp; temp = []
for i in range(0, len(inputs)-1, 2):
    temp.append(add(inputs[i]+inputs[i+1])) # Add two consecutive
                                            # results from prev step
inputs = temp
result = sum(inputs) # Sum all results from prev step
results.compute()

您可以用许多可能的小块为任何可并行化的代码增加延迟,并获得加速。它可以是你想要计算的许多函数,比如上面的例子,或者使用pandas.read_csv并行读取许多文件。

4.分发 ^

Photo by Chinh Le Duc on Unsplash

首先,到目前为止,我们一直使用Dask的默认调度程序来计算任务的结果。但是您可以根据自己的需要从Dask的可用选项中进行更改。

Dask附带四个可用的调度程序:

  • "threaded":由线程池支持的调度程序
  • "processes":由进程池支持的调度程序
  • "single-threaded"(又名"sync"):一个同步调度器,适合调试
  • distributed:用于在多台机器上执行图形的分布式调度程序
result.compute(scheduler="single-threaded") # for debugging
# Or
dask.config.set(scheduler="single-threaded")
result.compute()**NOTE: (from official page** [**here**](https://render.githubusercontent.com/view/ipynb?commit=33efceb9ba76b16ce3bf51d6210546e257f0874b&enc_url=68747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f6461736b2f6461736b2d7475746f7269616c2f333365666365623962613736623136636533626635316436323130353436653235376630383734622f30355f64697374726962757465642e6970796e62&nwo=dask%2Fdask-tutorial&path=05_distributed.ipynb&repository_id=39199909&repository_type=Repository#Some-Questions-to-Consider:)**)**
Threaded tasks will work well when the functions called release the [GIL](https://wiki.python.org/moin/GlobalInterpreterLock), whereas multiprocessing will always have a slower start-up time and suffer where a lot of communication is required between tasks.# And you can get the scheduler by the one of these commands:
dask.threaded.get, dask.multiprocessing.get, dask.local.get_sync
# last one for "single-threaded"

但是,Dask多了一个调度器,dask.distributed,出于以下原因,可以优先选择它:

  1. 它提供对异步 API 的访问,特别是 Futures
  2. 它提供了一个诊断控制面板,可以提供关于性能和进度的宝贵见解
  3. 它处理数据局部性更加复杂,因此在需要多个进程的工作负载上比多处理调度程序更有效。

您可以通过导入和创建一个Client来创建Daskdask.distributed调度程序。

from dask.distributed import Client
client = Client() # Set up a local cluster# You can navigate to [http://localhost:8787/status](http://localhost:8787/status) to see the 
# diagnostic dashboard if you have Bokeh installed.

现在,您可以通过使用client.submit方法将您的任务提交给这个集群,将函数和参数作为它的参数。然后我们可以通过使用client.gather.result方法来收集我们的结果。

sent = client.submit(sq, 4) # sq: square function
result = client.gather(sent) # Or sent.result()

您还可以通过使用dask.distributed.progress来查看当前单元格中的任务进度。您还可以通过使用dask.distributed.wait明确选择等待任务完成。

更多信息请看这里

**Note: (Local Cluster)** At times you will notice that **Dask** is exceeding memory use, even though it is dividing tasks. It could be happening to you because of the function you are trying to use on your **dataset** wants most of your data for processing, and multiprocessing can make things worse as all workers might try to copy **dataset** to memory. This can happen in aggregating cases.
Or maybe you want to restrict Dask to use only specific amount of memory. In these cases you can use **Dask.distributed.LocalCluster** parameters and pass them to **Client**() to make a **LocalCluster** using cores of your Local machines.**from** dask.distributed **import** Client, LocalCluster
client = **Client**(n_workers=1, threads_per_worker=1, processes=False,
                memory_limit='25GB', scheduler_port=0, 
                silence_logs=True, diagnostics_port=0)
client 'scheduler_port=0' and 'diagnostics_port=0' will choose random port number for this particular client. With 'processes=False' **dask**'s client won't copy dataset, which would have happened for every process you might have made.
You can tune your client as per your needs or limitations, and for more info you can look into parameters of **LocalCluster.** You can also use multiple clients on same machine at different ports.

5.机器学习 ^

Photo by James Pond on Unsplash

Dask也有帮助并行运行最流行的机器学习库的库,比如sklearntensorflowxgboost

在机器学习中,你可能会面临几个不同的缩放问题。扩展策略取决于您面临的问题:

  1. 大型模型:数据适合 RAM,但训练时间太长。许多超参数组合、许多模型的大型集合等。
  2. 大型数据集:数据比 RAM 大,采样是不可行的。

因此,您应该:

  • 对于内存适配问题,只需使用 scikit-learn(或者你最喜欢的 ML 库);
  • 对于大型模型,使用dask_ml.joblib和您最喜欢的 scikit-learn 估算器;和
  • 对于大型数据集,使用dask_ml估算器。

a)预处理:

dask_ml.preprocessing包含sklearn中的一些功能,如RobustScalarStandardScalarLabelEncoderOneHotEncoderPolynomialFeatures等。,还有一些自己的如CategorizerDummyEncoderOrdinalEncoder等。

您可以像使用Pandas数据框一样使用它们。

from dask_ml.preprocessing import RobustScalardf = da.read_csv("BigFile.csv", chunks=50000)rsc = RobustScalar()
df["column"] = rsc.fit_transform(df["column"])

您可以使用DaskDataFrame上的Dask的预处理方法,从sklearnmake_pipeline方法制作一个管道。

b)超参数搜索:

Dask有来自sklearn的用于超参数搜索的方法,如GridSearchCVRandomizedSearchCV等。

from dask_ml.datasets import make_regression
from dask_ml.model_selection import train_test_split, GridSearchCV
X, y = make_regression(chunks=50000)
xtr, ytr, xval, yval = test_train_split(X, y)gsearch = GridSearchCV(estimator, param_grid, cv=10)
gsearch.fit(xtr, ytr)

如果你使用partial_fit和你的估算器,你可以使用dask-mlIncrementalSearchCV

**NOTE: (from Dask)**
If you want to use post-fit tasks like scoring and prediction, then underlying estimators scoring method is used. If your estimator, possibly from sklearn is not able to handle large dataset, then wrap your estimator around "dask_ml.wrappers.ParallelPostFit". It can parallelize methods like "predict", "predict_proba", "transform" etc.

c)模型/估计器:

Dask有一些线性模型(LinearRegressionLogisticRegression等)。)、一些聚类模型(KmeansSpectralClustering)、一个用Tensorflow 聚类操作的方法、使用Dask训练XGBoost 模型的方法。

如果你的训练数据很少,你可以使用sklearn的模型和Dask,或者使用ParallelPostFit的包装器(如果你的测试数据很多)。

from sklearn.linear_model import ElasticNet
from dask_ml.wrappers import ParallelPostFitel = ParallelPostFit(estimator=ElasticNet())el.fit(Xtrain, ytrain)
preds = el.predict(Xtest)

如果你的数据集不大但是你的模型很大,那么你可以使用joblib。许多sklearns算法是为并行执行而编写的(您可能已经使用了n_jobs=-1参数),使用joblib来利用线程和进程来并行化工作负载。要使用Dask进行并行化,您可以创建一个Client(您必须这样做),然后将您的代码包装在with joblib.parallel_backend('dask'):周围。

import dask_ml.joblib
from sklearn.externals import joblibclient = Client()with joblib.parallel_backend('dask'):
    # your scikit-learn code**NOTE:** Note that the Dask joblib backend is useful for scaling out CPU-bound workloads; workloads with datasets that fit in RAM, but have many individual operations that can be done in parallel. To scale out to RAM-bound workloads (larger-than-memory datasets) you should use Dask's inbuilt models and methods.

如果你的训练数据太大,无法放入内存,那么你应该使用Dask的内置估算器来加速。您也可以使用Daskwrapper.Incremental,它使用底层估计器的partial_fit方法对整个数据集进行训练,但它本质上是顺序的。

Dask的内置估算器通过各种优化算法(如admmlbfgsgradient_descent等)很好地扩展了大型数据集。以及L1L2ElasticNet等正则化子。

from dask_ml.linear_model import LogisticRegressionlr = LogisticRegression()
lr.fit(X, y, solver="lbfgs")

再举一个使用Dask的例子,你可以在这里阅读我的帖子中的Dask部分。这是一个从探索到训练模型的完整过程。

6.延伸阅读 ^

  1. https://mybinder.org/v2/gh/dask/dask-examples/master?urlpath=lab
  2. https://towards data science . com/how-I-learn-to-love-parallelised-apply-with-python-pandas-dask-and-numba-f 06 b0b 367138
  3. https://docs.dask.org/en/latest/
  4. https://ml.dask.org

7.参考文献 ^

  1. https://ml.dask.org
  2. https://docs.dask.org/en/latest/
Suggestions and reviews are welcome.
Thank you for reading!

签名:

加速你的代码(1):庞加莱球空间中均值漂移聚类的例子

原文:https://towardsdatascience.com/speeding-up-your-code-1-the-example-of-the-mean-shift-clustering-in-poincaré-ball-space-d46169bfdfc8?source=collection_archive---------7-----------------------

来自本系列:

  1. 庞加莱球空间中均值漂移聚类的例子(本帖)
  2. 用 Numpy 对循环进行矢量化
  3. 批处理和多线程
  4. 用 Numba 实时编译

你好社区!

这是一系列文章中的第一篇,我将描述使用 Python 和 Numpy 构建快速聚类算法的步骤,该算法将在特定的“双曲线”空间中使用。

因为我想展示一个真实的开发案例,所以在第一篇文章中,我将描述我必须达到的目标,详细描述我必须实现目标的环境以及我在那里的原因,然后是代码的第一个原始版本。

所以让我们开始吧!

为什么会这样?

2017 年 5 月,在《人工智能世界》杂志上,来自脸书人工智能研究所的 Maximilian Nickel 和 Douwe Kiela 发表了一篇论文。这篇论文的内容有望对代表学习领域产生巨大的影响。

严格来说,表示学习技术的目标是翻译属于一个集合(例如,一本书)的对象(例如,单词)的“含义”,考虑到它们之间存在的属性(例如,语义),目标是具有一个随后可以被 AI 算法使用的基础。对象表现得越好,后续的算法就越有效。

这些技术的尖端使用“嵌入”:每个对象由多维空间中的一个点来表示,并且该点将理想地“嵌入”该对象相对于集合所具有的所有属性。因此,具有相似含义的对象将发现它们的嵌入在几何上彼此接近。这就是为什么我必须建立一个聚类算法。

这种多维空间通常是“平面”型的,也就是说,具有我们在现实空间中看到的几何性质,也就是我们在学校里学过的那些。相反,在提到的论文中,他们使用了一个特殊的“弯曲”空间:庞加莱球模型。这是因为这种空间非常适合表示层次结构,因此集合中的潜在层次结构很容易表示。事实上,它们使用低得多的维度在许多领域显示了最先进的结果。

这个庞加莱球是什么样子的?作为例子,下面有两个二维球(即一个圆)表示。你看到的弧线就是所谓的“测地线,也就是两点之间最短的步行距离。这是相对于“平坦的”欧几里得空间的最明显的区别之一,在欧几里得空间中,点之间的最短穿行是一条直线。另一个很大的不同是,在圆之外没有任何东西可以存在:实际上,离中心很远的点(“在无穷远处”)位于圆盘圆周上。因此,连接你在左图中看到的点的弧线都有相同的长度。令人兴奋,不是吗?

Left: the lines connecting the points have all the same distance. Right: the animation of a rotation within the Poincaré disk. Credits: Wolfram.com

目标

我必须建立一个算法,将空间中彼此靠近的点组合在一起。我需要这个算法在没有预先指定聚类数的情况下工作。然后我选择均值漂移程序。

该过程将每个点向其最近的点群移动,并且单个参数定义了最近的点群有多远。如果最近的大块太远,该点将自己形成一个孤立的簇。

这是二维庞加莱盘中结果的动画,其中算法将以 13 个聚类结束:

Mean shift clustering in Poicaré disk.

您可以注意到,圆边界附近的点(相对距离似乎很小)不会聚集。相反,靠近圆心的点,其相对距离似乎比圆周上的点要大,实际上会聚集在一起。

这是我们所在的弯曲空间的影响,庞加莱球:正如我已经提到的,你离中心越远,距离实际上就越大,比你在照片上看到的要大。

可以说很多细节,但那超出了本帖的范围。但是,如果你想了解更多关于均值漂移过程和花哨的庞加莱球空间模型,只需搜索网络,有大量的资源。

履行

描述性地,为了实现均值漂移过程,我们必须用所有其他点的加权和来代替每个点 P 。应用于每个点的权重取决于它与所考虑的点的距离( P )。并且必须重复这个过程,直到所有的点都聚集在一起。

您可以在网上找到该算法的几种实现,基本上适用于每种编程语言。但是没有人会在这个空间工作!

原因是我们计算点与点之间距离的方式。所有这些算法都是为在“平坦的”欧几里得空间中工作而设计的,因此它们以欧几里得方式计算点之间的距离。相反,在这个特定的空间中,距离是更复杂的。

这是用 Python 和 Numpy 写的基本代码。我从杰瑞米·霍华德的精彩课程中得到这个版本:

The basic code

这是一个通用的 meanshift 实现。对于我们的例子,区别在于我们定义点之间的区别的方式:

如您所见,Numpy 的广播功能在编写简单代码方面帮助很大。为了理解广播,请看高斯函数:它接受两个元素作为输入( d 作为距离, bw 作为带宽)。它们都可以是数字,或者任何 n 维数组(向量、矩阵、张量),如果它们的形状兼容,Numpy 会知道如何以适当的方式处理它们。在我们的例子中,我们为函数提供一个向量( dists )和一个数字(sigma)。

为了完整起见,庞加莱球模型中两点之间的距离定义为:

Definition of distance in the Poincaré Ball space

那么,搞定了?是也不是。它是有效的,你之前看到的动画就是用这种算法制作的。但是很慢:在我的笔记本电脑(i7–4750 HQ CPU @ 2.00 GHz,8GB RAM)上,对于集群 1200 点,每步需要 14 秒,算法收敛需要 10 步。

所以我需要改进代码。

加快代码速度

可以做很多很好的尝试来改进它:使用近似技术、随机矩阵、多线程、GPU 等等。

但我们是程序员,有义务多动脑,少蛮力。所以我想尝试的第一个尝试是向量化两个循环:一个在 dist_poinc 函数中,另一个在 mean 算法中。

在下一篇文章中,我会展示原因和结果。但是作为开胃菜,看看这个情节:

Percentage of execution time of a vectorized product with respect to a looped one.

是的,你读得不错:一个简单操作的矢量化版本的执行时间不到完成循环所需时间的 1.3%。

难道不值得一试吗?

加速您的代码(3):批处理和多线程

原文:https://towardsdatascience.com/speeding-up-your-code-3-batches-and-multiprocess-52d2d34a4091?source=collection_archive---------3-----------------------

来自本系列:

  1. 庞加莱球空间中均值漂移聚类的例子
  2. 用 Numpy 对循环进行矢量化
  3. 批处理和多线程(这篇文章)
  4. 用 Numba 实时编译

在上一篇文章中,我们展示了我们算法的矢量化版本会随着向量数量的增加而变慢,我们将这一特性与以下事实相关联:对于 N 个向量,我们处理的是 N 个矩阵。

现在,我们将实现一种算法,每次处理一批向量,即批处理版本。利用这个技巧,我们将对顺序为 n x N 的矩阵进行计算,其中小的 n 是一批中要考虑的向量的数量。这个技巧的一个很好的副作用是,我们还可以并行计算。

更新代码

均值漂移过程中的第一个操作是计算每个向量到所有其他向量的距离,在庞加莱球空间中,距离为:

Distance in Poincaré ball

按照我们的 1000 个二维向量的例子,为了计算距离公式的分子,我们需要第一个 n 元素的这个 n x 1000 矩阵:

Batched version of the vectorized numerator of the distance formula.

然后像以前一样,得到的矩阵中每个元素的分量(都是向量,还记得隐藏维吗?)都得平方总结。

在分母上,我们必须对这个结构进行编码:

Batched version of the vectorized denominator of the distance formula.

距离函数的其余部分很容易。使用 Numpy 语言,下面是计算数据集子样本(批处理)和整个数据集之间的距离所需的代码。只有修改过的行被注释:

Batched version of the code for the Poincaré ball distance.

整个 meanshift 算法几乎保持不变:

Code for one iteration of the meanshift algorithm, batched version

最大的不同是,这里我们动态地更新矢量,也就是说,我们根据已经移动的矢量计算出的距离来移动矢量。实际上:在第一批中,距离是以传统方式计算的,产生的移位向量被放置在原始数据集中。因此,我们将有一个数据集,其中第一个 n 个向量被移位,而其他向量没有被移位。当我们考虑第二批时,将针对该混合数据集计算距离,对于其他批也是如此。

虽然这个版本的算法的稳定性需要更好的研究,但我们可以相当肯定的是,使用小高斯宽度()我们不会遇到问题。

最后,在我们在前一篇文章中介绍的位置循环=bad 之后,我们回到另一个循环,因为为了移动所有的向量,我们必须为每一个可能的批次运行这个过程。但是好消息是每个批处理都是相互独立的,所以我们可以并行化这个循环!

为了利用我们的多核处理器,我们将使用 Python 的ThreadPoolExecutor函数:

关于 ThreadPoolExecutor 的细节超出了本系列文章的范围,但简而言之:

  1. 修改 __shift 函数,以恢复该函数已移动的向量的位置;这是追踪移动的向量并将其放入数据集中正确位置所必需的。
  2. 定义了一个字典(future _ shift),它包含所有要并行执行的函数,每个批处理一个;函数的数量将取决于所选择的批量大小,例如,如果数据集包含 1000 个向量,并且选择的批量大小为 200,则字典将包含 5 个函数。
  3. 一旦执行了每个函数,数据集中由跟踪号指定的位置(此列表中的点 1)处的相对位移矢量就会更新。

仅此而已!现在,我们在速度执行方面获得了多少?让我们用通常的二维向量集合来检查一下:

***

Comparison of the execution time for the mean shift algorithm, absolute on the left, relative on the right.*

不出所料,水货版更快。数据集越大,它的性能就越好:对于移动一个由 18k 个向量组成的数据集,并行版本只需要一次移动所有向量所需时间的 5%。这是因为旧版本在多项式时间 O(N)中执行,而并行版本在线性时间中执行:不管数据集大小如何,我们总是使用固定大小的矩阵执行操作( n_batches x N ,在前面的示例中 n_batches =100)。

结论

所有的数值算法都有一个要达到的目标:在合理的时间内获得合理精确的结果。所以,一般来说,在保持精度不变的情况下,加快算法的执行速度就像金子一样。如果考虑生产环境,更快的执行意味着更早地释放硬件资源;在相同的单位时间内可以执行更多的线程,这意味着省钱。更多:在实时应用中,执行速度可以区分可能和不可能。

对于“我如何才能提高速度?”这个问题,第一个天真的答案是通常是“购买更快的硬件!”,但看看接下来的图,我们比较了算法的原始版本(在第一篇文章的中描述)和这里解释的版本:

***

Comparison between the algorithm in the first post (‘looped’) and the one in the present post (‘batched & parallel’).*

我们需要 0.4%多一点的时间来执行一次迭代,这意味着并行矢量化算法比循环算法快 250 倍。或者,如果你喜欢,快 25000%。

你能想到购买硬件的速度快 250 倍吗?这就像从 2009 年构建的英特尔赛扬处理器(~4 GFLOPS)过渡到 2017 年构建的英特尔 I9(~ 1000 GFLOPS)。是的,你需要一个时间机器。

更好的优化代码,不是吗?

如果你想自己试试,可以在这里找到代码

使用并行技术的快速计算机视觉流水线

原文:https://towardsdatascience.com/speedy-cv-pipelines-using-parallelism-d7bebad2ff5f?source=collection_archive---------12-----------------------

如果你曾经使用 OpenCV、MoviePy 或任何其他海量的库编写过自己的代码来处理视频,你可能会面临处理速度非常慢的问题。

Unfortunate is ze who has to wait 20 minutes to watermark a 5 minute 4k video

这是因为我们编写的代码基本上是为了在单核上运行而编写的。我们有一个庞大的任务,需要处理大量的数据,没有现成的解决方案可以简化我们的生活。然而,我们想要的是一个完全不同的故事。蠢朋克的一些歌词最好地概括了这一点

努力吧,努力吧…..更难、更好、更快、更强

看到更快这个词,你脑子里第一个想到的可能就是排比。当我们考虑并行视频处理时,这是必须的,对吗?

方法 1

我们可以将帧一个接一个地分配给空闲的内核。似乎是一个简单而明显的解决方案,不是吗?

First thoughts: How to NOT parallelize video processing across cores

然而不幸的是,这并不十分奏效。事实上,在很多情况下,这最终会比我们简单的单核代码的性能更差。要了解原因,我们必须深入了解视频本身是如何存储的。由于视频编码是顺序的,当一个内核解码一帧时,其他内核必须处于空闲状态。他们不能开始处理下一帧,直到该核心解码了前一帧(这里是一个关于视频压缩如何工作的技术快速介绍)。

joblib这样的库也试图以类似的方式并行化作业,因此没有提供我们希望看到的那种加速。这意味着我们必须寻找更好的替代方案

方法 2

聪明的阿德里安在他的博客中强调了另一种加速视频处理的方法。在这篇博文中,他讨论了将帧解码过程转移到另一个线程,并存储解码后的帧,直到主处理线程需要检索它。

New frames are decoded in a dedicated thread and enqueued to the back of a Queue. They are then dequeued from the front of the list as and when needed by the main processing thread (source: pyimagesearch)

尽管这本身是一个绝妙的想法,但是这种方法的一个很大的局限性是它只能同时利用机器的两个线程/内核。此外,出于某种原因,Adrian 博客中的代码似乎没有直接扩展到 Python 3(参见帖子上的评论。或许 Python 改变了他们的multithreading库的内部工作方式?)不管怎样,如果我们朝这个方向努力,我们应该能够达到一个水平,至少比我们开始的时候稍微好一点。

但是仍然没有达到我们期望的速度。我们希望让 Threadripper 或 Xeon 在同一视频中大规模分配工作负载。为了能够做到这一点,让我们回头看看方法 1。我们第一种方法的主要问题是内核之间的相互依赖。这是不可避免的,因为视频编码从根本上来说是“分块”的。

然而,从逻辑上讲,通过强制内核在完全不同的预分配片段上工作,应该很容易解决这个问题。这是我们最后的方法

方法 3

为了做到这一点,我们所要做的就是让每个内核寻找视频的一个完全不同的片段,并对其进行操作

A better way to distribute video processing across your cores

假设我们有 10,000 帧和 4 个内核,这意味着我们将每个内核专用于这 10,000 帧中固定的连续季度(=2500)。这样,内核就不必相互等待来处理下一帧。在此之后,剩下的唯一任务是以正确的顺序重新组装已处理的帧。遵循这种方法可以让我们轻松地并行处理我们的视频处理流水线

在 Python 中做到这一点非常简单。作为参考,这可能是您的普通视频处理代码的样子:

A normal code to perform an operation on a video

如果我们必须并行化这段代码,我们必须使用 python multiprocessing

Parallelizing the video processing by distributing video fragments across cores

大部分已经完成了。然而,仍然遗漏了一个重要的部分。我们只剩下加工过的碎片。我们仍然需要合并这些碎片。这可以通过以下方式使用ffmpeg轻松完成:

Merging the video fragments that are generated by our parallel processing code

我们做到了!一种并行化视频处理管道的方法,可根据我们投入的内核数量进行扩展。

A speed-up of 6x is observed with 6 cores and 2x with 2 cores for the simple task of video blurring

你不必相信我的话,😄。自己试试吧,在下面的评论中告诉我。所有的代码都可以在 https://github.com/rsnk96/fast-cv 的 GitHub 中找到

备注:

  • 如果你想知道cv2.set(CAP_PROP_POS_FRAMES)如何跳到一个特定的帧,而不必使用前面的帧解码,这是因为它跳到了最近的关键帧。查看视频链接,更好地理解这一点
  • cv2.set(CAP_PROP_POS_FRAMES) 已知没有准确寻找指定帧。这可能是因为它寻找最近的关键帧。这意味着在视频片段的地方可能会有几帧重复。所以不建议对关键帧用例采用这种方法。
  • 最佳性能实际上可能通过方法 2 和 3 的组合来获得。但是要把它编码起来需要更多的努力。如果有人设法拼凑出一个代码,请在评论中告诉我!😃
  • **:包含对if ret==False: break的检查是正常的做法,但是为了简单起见,我在这里避免了它
  • 这篇文章是我最近在 Pysangamam 和 Pycon India 发表的演讲的摘要。https://www.youtube.com/watch?v=v29nBvfikcE

特朗普总统每周讲话中的人际动机!

原文:https://towardsdatascience.com/spiking-interpersonal-motives-in-this-weekly-address-by-president-trump-d9acb03f0ba1?source=collection_archive---------3-----------------------

发现总统的思想和内心

我分析了唐纳德·j·特朗普总统(dt。2017 年 4 月 14 日),你可以在访问这个白宫网站链接。在我的观察中,我发现,除了更高水平的安全和社会福祉相关的价值观飙升之外,这个每周讲话还有一个重要的人际/社会动机。

你可以通过人类动机、价值和人格特质的镜头,在下面找到我分析的细节。该分析是基于对每周讲话的语音记录的认知计算和分析。

首先,这是每周电视讲话的要点(摘要)
几个世纪以来,犹太人经历了一次又一次的迫害——然而,他们坚持下来,繁荣起来,提升了这个世界。这是一个神圣的崇敬和崇拜的日子;这是一个神圣的时刻,用我们人民的信念来充实我们国家的精神。我们祈求力量和智慧来实现一个更美好的明天——一个所有信仰的善良的人们,基督教徒、穆斯林、犹太教徒和印度教徒,都能随心所欲,凭良心礼拜的明天。我还想给那些挣扎中的美国人一个特别的信息,他们长期以来一直感受到艰难困苦的滋味。我们为所有公民享有安全与和平的权利而战,为所有上帝的孩子有权知道的有尊严地工作和生活而战。

认知分析

1.预测的动机

人类的动机就是渴望或寻求改变。激励情绪是从一个人的内心和思想中唤起的情感力量。

我发现养成(7.5)和归属(8.4/10)的动机很重要(在上周的演讲中并不重要)。).这些动机与众不同,表明在游戏中有更高的人际/社会动机,而不是只有工具性动机。(物质世界方面)

这意味着什么?

  • 养育动机表明了美国公民的关怀态度,这种态度更多的是在当前的背景下体验(相对于过去或未来的焦点)
  • 归属动机是面向未来的(期待..).这在心理上意味着总统渴望成为社区的一员。(即成为人民主席)

2.预测的价值取向(信念和目标)

价值观传达了对一个人来说什么是最重要的。它们是“合意的、跨情境的目标,其重要性各不相同,是人们生活中的指导原则”——它们与具体的行为状态密切相关——沙洛姆·施瓦茨博士。

被发现在安全、刺激和普遍主义维度上占主导地位的预测价值取向(沙洛姆·施瓦茨博士模型)表示以下方面。,

*社会秩序、家庭安全、归属感、健康/幸福

*尊重传统、国家安全

*社会公正、世界和平、诚实、宽容

3.预测的人格倾向

基于海洋模型的人格相关性表明了以下几个关键方面

  • 更高的平等主义取向
  • 不那么占优势,也不那么保守的防御姿态
  • 适度的合作&友好的态度(Vs)与对立的态度(例如,采取不太严厉措施的国家)
  • 更高水平的保守(计划可预测结果的能力)以及承担风险和/或运用创造力的意愿。
  • 对负面情绪(风险/损失)更敏感。

4.发现语境主题:独特而重要的方面(词云)

5.总结——将动机、价值观和个性倾向联系起来

  1. 特朗普总统正在通过加强与美国人民的联系和关心美国人民来强调公民福利。这将如何显化和进化将会很有意思。
  2. 似乎强调国家安全、秩序和人民福祉,我认为这与保卫国家/公民免受外来威胁有关。
  3. 鉴于美国复杂和不祥的外交形势,我预计至少会有一些认知信号,可能表明某种专制和防御/战争姿态。例如,上一次每周讲话传达了更高层次的自信和意志坚定。本周更多的是温柔!特别是关于朝鲜局势,这可能意味着他可能会采取与美国盟友和其他国家建立和平的方式,而不是继续咄咄逼人或好战的姿态。

随着未来几周事件的展开,看看我们是否能找到任何基于上述推测的预测将会很有趣。

限制

这种分析可能有如下所述的局限性,因此我的发现和推测可能不正确。

  1. 以人民为中心的演讲恰逢犹太人的逾越节和复活节。由于这一点,认知取向可能不会为总统深入参与的其他政治和国家方面提供线索。
  2. 每周讲话(文本数据)内容的大小可能较小,可能无法进行统计意义上的预测。

声明:
此处提及的观点均为本人观点。
本文使用的信息/数据来自公共领域的可用信息。但对其准确性、完整性、及时性或正确性不做任何明示或暗示的陈述或保证。我不对任何错误或不准确负责,不管是什么原因造成的。(读者)

脉冲神经网络,下一代机器学习

原文:https://towardsdatascience.com/spiking-neural-networks-the-next-generation-of-machine-learning-84e167f4eb2b?source=collection_archive---------1-----------------------

每个远程关注机器学习最新进展的人都听说过当前用于机器学习的第二代人工神经网络。这些一般都是全连接的,接受连续值,输出连续值。虽然它们让我们在许多领域取得了突破性进展,但它们在生物学上是不准确的,并没有真正模仿我们大脑神经元的实际机制。

第三代神经网络,即脉冲神经网络,旨在弥合神经科学和机器学习之间的差距,使用生物逼真的神经元模型来执行计算。一个脉冲神经网络(SNN)从根本上不同于机器学习社区所知道的神经网络。snn 使用尖峰信号运行,尖峰信号是在时间点发生的离散事件,而不是连续值。锋电位的出现是由代表各种生物过程的微分方程决定的,其中最重要的是神经元的膜电位。本质上,一旦神经元达到某个电位,它就会出现尖峰,该神经元的电位就会被重置。最常见的模型是泄漏集成点火(LIF)模型。此外,snn 通常稀疏连接,并利用专门的网络拓扑。

Differential equation for membrane potential in the LIF model

Membrane potential behavior during a spike

Spike trains for a network of 3 neurons

A full spiking neural network

乍一看,这似乎是一种倒退。我们已经从连续输出转向二进制输出,这些尖峰脉冲串不太好解释。然而,尖峰脉冲序列为我们提供了处理时空数据的增强能力,换句话说,就是现实世界的感官数据。空间方面指的是这样一个事实,即神经元只连接到它们本地的神经元,所以这些神经元天生就单独处理输入的大块(类似于 CNN 使用过滤器的方式)。时间方面指的是尖峰脉冲序列随着时间的推移而出现,因此我们在二进制编码中失去的,是尖峰脉冲的时间信息。这允许我们自然地处理时态数据,而没有 RNNs 增加的额外复杂性。事实上,已经证明,脉冲神经元从根本上来说是比传统人工神经元更强大的计算单元。

鉴于这些社交网络在理论上比第二代网络更强大,人们很自然会想为什么我们看不到它们的广泛使用。当前 SNNs 实际使用中的主要问题是训练的问题。虽然我们有无监督的生物学习方法,如赫比学习和 STDP,但没有已知的有效的监督训练方法,用于 SNNs,提供比第二代网络更高的性能。由于尖峰序列是不可微的,我们不能使用梯度下降训练 snn 而不丢失尖峰序列中的精确时间信息。因此,为了将 SNNs 正确地用于现实世界的任务,我们需要开发一种有效的监督学习方法。鉴于这些网络中的生物现实主义,这是一项非常困难的任务,因为这样做将涉及确定人类大脑实际上是如何学习的。

我们即将解决的另一个问题是,在普通硬件上模拟 SNNs 是非常计算密集型的,因为它需要模拟微分方程。然而,神经形态硬件,如 IBM 的 TrueNorth,旨在通过使用专门的硬件模拟神经元来解决这一问题,这些硬件可以利用神经元尖峰行为的离散和稀疏特性。

因此,社交网络的未来仍不明朗。一方面,它们是我们当前神经网络的自然继承者,但另一方面,它们远不是大多数任务的实用工具。在实时图像和音频处理中有一些当前真实世界的 SNNs 应用,但是关于实际应用的文献仍然很少。大多数关于 SNNs 的论文要么是理论性的,要么显示了在简单的全连接第二代网络下的性能。然而,有许多团队致力于开发 SNN 监督学习规则,我对社交网络的未来保持乐观。

Garoppolo 效应:使用 Python 探索 NFL 数据教程

原文:https://towardsdatascience.com/sports-analytics-exploring-nfl-data-using-python-3f70721a9c60?source=collection_archive---------10-----------------------

Photo by Ashton Clark on Unsplash

吉米·加罗波洛刚刚与旧金山 49 人队签署了 NFL 历史上最大的合同。在赛季中期被交易后,他为他们首发了 5 场比赛,并带领 49 人队赢得了所有这些比赛。

我想探究加罗波洛被交易后 49 人队发生了什么变化,并更多地了解他是如何帮助球队的。为了进行这一分析,我使用了一个关于 2017 年 NFL 比赛的数据集。你可以使用 NFL scrapeR 获取数据。我用这个工具下载了 NFL 2017 年的比赛数据,并包含了一个直接的链接,可以在那里下载 2017 年的 NFL 数据。

出于我们的目的,我们将专注于分析 2017 赛季的 49 人队数据,这是一个关于如何使用 Python 2.7 完成这项工作的演练。我在代码中加入了一些注释来帮助您理解。由于吉米·加罗波洛只为 49 人队首发了 5 场比赛,这些情节不会都有类似的观察次数,但让我们看看我们可以学到什么有趣的东西。

**import** **pandas** **as** **pd # data manipulation library**
**import** **numpy** **as** **np # numerical computation library**
**import** **datetime** **as** **dt** 

**import** **matplotlib.pyplot** **as** **plt # plotting library**
**from** **matplotlib** **import** cm # color maps for plotting
plt.style.use('ggplot') # use the ggplot plotting style

%matplotlib inline # show plots in line in a jupyter notebook

**from** **__future__** **import** division # division without truncating decimals 

现在,让我们将数据读入一个名为 nfl 的变量。

nfl = pd.read_csv('https://raw.githubusercontent.com/ryurko/nflscrapR-data/master/data/season_play_by_play/pbp_2017.csv', low_memory=False)

因为我们想比较球队在交易前后的表现,所以我们可以添加一个额外的列,表明某个日期是在 Jimmy Garoppolo 为 49 人队开始比赛的日期之前或之后。这样做将允许我们比较 Jimmy 开始工作之前和之后的数据,因为我们可以基于该列的值聚集数据。

首先,我们将 date 列转换为 datetime 格式,这样我们就可以将它们与我们想要检查的日期进行比较。

nfl['Date'] = pd.to_datetime(nfl['Date'])

然后我们可以创建一个名为 Jimmy 的列,如果比赛日期在 2017 年 12 月 3 日或之后,则为 yes,否则为 no。

nfl['Jimmy'] = np.where( nfl['Date']>=pd.datetime(2017,12,3), 'yes', 'no')

现在,如果我们检查我们的 nfl 数据框架,我们会看到最后一列现在是吉米。

我们可以从 2017 年的 NFL 数据中获得 49 人的特定数据,方法是对 NFL 数据进行子集化,使主队或客场队为 SF 49 人。

niners = nfl[ (nfl["HomeTeam"] == 'SF') | (nfl["AwayTeam"] == 'SF') ]

接下来,我们可以看看达阵得分。为了检查触地得分信息,我们可以检查主队或客队是 SF,发生了得分比赛,发生了触地得分,进攻的球队是 SF,并且没有拦截者,拦截者是拦截球的球员。

niners_td = nfl[((nfl["HomeTeam"] == 'SF') | (nfl["AwayTeam"] == 'SF')) & (nfl["sp"] == 1) & (nfl["Touchdown"] == 1) & (nfl["DefensiveTeam"] != 'SF') & pd.isnull(nfl["Interceptor"]) ]

本赛季我们有 31 次触地得分。

现在,我们可以通过对数据帧进行分组来检查在没有吉米和有他的情况下有多少次触地得分。

niners_td.groupby('Jimmy').Touchdown.sum()

吉米·加洛波洛出场和不出场都是达阵

现在让我们来绘制吉米开始和没有开始比赛时的达阵次数。

tds = niners_td.groupby('Jimmy').Touchdown.sum() *# score the touchdown information in tds*

fig, ax = plt.subplots(figsize=(8, 6), dpi = 72) *# Get access to the figure and axes to modify their attributes later*

ax.set_title("Total Number of Touchdowns", fontsize = 18) *# Chart title*
ax.set_xlabel('Jimmy', fontsize = 15) *# X-axis label*
ax.set_ylabel('Number of Touchdowns', fontsize = 15) *# Y-axis label*
plt.xticks(fontsize = 13)
plt.yticks(fontsize = 13)

mycolors = ['#A6192E', '#85714D'] *# Using scarlet and gold colors*

tds.plot(kind='bar', alpha = 0.9, rot=0, color = mycolors) *# Plot a Bar chart*
plt.show()

虽然这个图很好,但我们也应该检查一下每场比赛的达阵次数,因为吉米只打了 5 场比赛。

我们可以看到,当吉米·加罗波洛开始时,49 人队每场比赛大约多得分 1 次。这并不意味着他要对他打球时的每一次触地得分负责,但这只是显示了他打球时触地得分的次数。

随着时间的推移,触地得分和拦截

为了从不同的角度来看触地得分的情况,我们可以采用时间序列的方法来观察一段时间内触地得分和拦截的次数。我们可以标记出 Garoppolo 开始游戏的时间点,看看我们可以观察到什么变化。

*# get sum of touchdowns by game day*
td_by_date = niners.groupby('Date')['Touchdown'].sum()
td_by_date;*# get sum of interceptions by game day*
inter_by_date = niners.groupby('Date')['InterceptionThrown'].sum()
inter_by_date;

现在让我们把它画出来。

fig, ax = plt.subplots(figsize=(8, 6), dpi = 80) *# set plot size* 

mycolors = ['#A6192E', '#85714D'] *# Using scarlet and gold colors*

f1 = td_by_date.plot(color = mycolors[0]) *# plot the touchdowns*
f2 = inter_by_date.plot(color = mycolors[1]) *# plot the interceptions*

ax.set_title("Touchdowns and Interceptions over Time", fontsize = 18) *# Chart title*
ax.set_xlabel('Game Date', fontsize = 15) *# X-axis label*
ax.set_ylabel('Count', fontsize = 15) *# Y-axis label*
plt.xticks(fontsize = 12)
plt.yticks(fontsize = 12)

plt.axvline(dt.datetime(2017, 12, 3), color = 'black') *# add a vertical line*
plt.legend(loc='upper center', frameon=True, facecolor="white") *# add a legend with a white background*

plt.show()

黑色竖线右边的线是吉米开始的游戏。我们注意到,在他开始为 49 人队比赛之前,他们在触地得分方面处于下降趋势,在他开始后,他们的进攻开始再次起飞。

不同游戏类型的比较

我们还可以比较加罗波洛没有首发和首发时不同类型的打法。这可以给我们一个总体的感觉,当他开始比赛时,某些比赛的流行程度如何改变,而当他没有开始比赛时,因为比赛的类型可以随着不同的四分卫而改变。为了比较不同的打法类型,我们使用 niners 数据框架,而不是上面定义的 niners_td 数据框架,因为我们关心的是比赛中的整体打法,而不仅仅是 49 人队进攻时的打法。

fig, ax = plt.subplots(2, 1, figsize=(10, 8), dpi = 85) *# specify a plot with 2 rows and 1 column*

*# get plays where Jimmy did not start and did start*
f1 = niners[niners['Jimmy']=='no']['PlayType'].value_counts().plot(kind='barh', ax=ax[0]) 
f2 = niners[niners['Jimmy']=='yes']['PlayType'].value_counts().plot(kind='barh', ax=ax[1])

f1.set(title = "Before Jimmy's Starts", xlabel='Count', ylabel='Play Type')
f2.set(title = "After Jimmy's Starts", xlabel='Count', ylabel='Play Type')f1.set_xlim(0,805) # use the same scale for both plots
f2.set_xlim(0,805)fig.tight_layout() *# prevent overlapping axis labels*

plt.show()

当然,比赛的数量不同,因此比赛的次数也不同,但是如果我们使用两个图中的颜色来匹配哪种比赛最频繁,我们会看到在两个图中,最常见的比赛是传球、跑动和开球,但是我们注意到,在吉米开始之前,打门更常见,而在吉米开始之后,射门更常见。这可能表明,吉米的发挥可以帮助 49 人队更接近得分位置,并有机会获得更多的投篮机会。

最后,让我们更深入地研究一下 49 人队的进攻数据。

让我们来看看 49 人队进攻时获得的码数排名靠前的比赛。像以前一样,我们将子集化我们的数据,以获得 49 人队进攻时的数据。

niners_offense = nfl[((nfl["HomeTeam"] == 'SF') | (nfl["AwayTeam"] == 'SF')) & (nfl["DefensiveTeam"] != 'SF') ]

我们可以创建一个名为 most_yards 的新数据框架,它采用了 49 人队进攻获得最多码数的 50 次观察。

most_yards = niners_offense.sort_values(by='Yards.Gained', ascending=False)[:50]

我们可以看到,这 50 个按码数计算的顶级游戏中有 20 个发生在 Jimmy 开始时,但是由于出现的次数不同,我们将查看整体值,而不是像以前一样将图分开,因为这些不同的观察结果会导致条形图中条形数的变化。

我们注意到马奎斯·古德温是上个赛季获得最多码数的接球手。

passes = most_yards[most_yards["PlayType"] == 'Pass']fig, ax = plt.subplots(figsize=(8, 6), dpi = 75)

f1 = passes['Receiver'].value_counts().plot(kind='barh')
f1.set(title = "Players with the most Yards after receiving Passes", xlabel='Count', ylabel='Player Name')

plt.show()

我们可以看到马特·布雷达和卡洛斯·海德是上赛季最成功的跑垒者之一。

runs = most_yards[most_yards['PlayType'] == 'Run']fig, ax = plt.subplots(figsize=(6, 5), dpi = 75)

f1 = runs['Rusher'].value_counts().plot(kind='barh')
f1.set(title = "Players with the most Yards from Rushing", xlabel='Count', ylabel='Player Name')

plt.show()

结论

我希望您喜欢这篇使用 NFL 数据的 Python 数据分析指南。现在你可以去下载 NFL 的数据,用不同的信息进行试验,看看你会发现什么有趣的东西!

感谢您花时间阅读这篇文章,并随时在 LinkedIn 上发表评论或联系。

参考资料:

  1. 熊猫数据框文档
  2. 熊猫剧情文档
  3. Matplotlib 文档
  4. NFL 刮刀
  5. 个人 Github 知识库与本代码笔记本

用 R +谷歌云机器学习进行 App Store 评论挖掘

原文:https://towardsdatascience.com/spotify-app-review-mining-with-r-google-cloud-machine-learning-feb6f9c3b75f?source=collection_archive---------8-----------------------

这篇文章描述了如何用 R 和 itunesr(由 阿卜杜勒马耶德拉贾 )从 iTunes 中导出数据,然后是可视化的评分和评论。它还涵盖了如何在进行基本的情感分析之前,通过使用 Google Cloud 机器学习 API 进行语言处理,使用 googleLanguageR 来翻译评论。

为什么要在意 app 评分和评论?

评论包含了关于什么有效,什么无效的有价值的见解,因此应该被视为一座金矿。评论可能是一个应用程序性能不佳的唯一信息来源。因此,如果有人问为什么要关心免费、有价值和主动提供的用户反馈 2018,你最好确保你在正确的地方。只要跟随你的网购行为,你就会找到答案。

关于应用评级和评论重要性的关键见解:

用户共享意味着公司关怀

购买非定制的应用分析工具或构建定制平台

处理评论挖掘可能具有挑战性,但会给你提供有价值的见解,有助于创造更好的服务,并有望提高用户忠诚度。为了获得积极的效果,你需要一种工作方法。不幸的是,随着时间的推移,App Store 无法帮助你区分正面和负面评论。此外,您需要定义一个系统化的流程,在对类似的反馈进行分析之前对其进行分组。对正面和负面的评论、合格的 UX 改进中的错误或者更大的特性建议进行分类,将会提高效率并促进未来的优先级。

那么,从哪里开始呢?你可以选择使用 Appbot、MobileAction、App Annie 或 SensorTower 等非定制但功能强大的工具支付有时很昂贵的订阅费用,或者自己创建一个定制的解决方案并节省数千美元。相反,我会使用这些工具导出历史数据,然后在 Tableau 中构建我的个人挖掘解决方案,或者在 r。

免责声明:App Store Connect 的一个缺点是,你只能导出每个国家/市场的最新 500 条评论,并且只能导出与评论相关的评分。这将影响所有的汇总报告,因为美国的最后 500 个评论可以在一周内收集,但像匈牙利这样的较小市场可能涵盖前 12 个月的观察。可以每天或每周转换数据以保存历史数据。如果不是,小心你的发现。

创建灵活的解决方案的好处是有机会交叉检查数据,并根据不同的场景安排自动化任务。此外,通过减少代码和可视化的数量,您可以在一秒钟内对应用程序进行免费的基准研究。

用 R 和 itunesr 查看分析

为什么选择 R?r 是一种用于定性和定量分析的统计编程语言,由科学家开发,具有大量用于统计、机器学习和数据科学的库。R 的一个巨大优势是可以用 R Markdown 创建交互式 web 应用程序。因此,这是在组织中快速、交互式地分发数据的有效方式。如果你对 R 完全陌生,可以在 Coursera 上看看 R 编程课程。

我的灵感来自阿卜杜勒·马耶德·拉吉,他也是 itunesr 软件包的作者,在阅读了分析 iOS 应用商店 iTunes 评论的之后。Gregory E Kanevsky 的文章分析了 PodCruncher 应用程序在 iTunes 上的评分和评论,这是另一个很好的启发。

今天,我使用 itunesr 获取应用洞察,以进行基准测试和确定未来发展的优先顺序。而且还可以通过 Slackr 将负面评价自动化并直接推送到 Slack。我希望你能找到自己的创造性的方法,在你的组织内分发评审数据。

我还是一个 R 的新手用户,所以就冒昧的拉伸一下干巴巴(不要重复自己)的原则。请耐心等待。

Selected tools and packages for analysis and visualization (iTunes, RStudio, Google Translate API, Google Cloud, ggplot2 & dplyr.)

我们到底在找什么?

探索性评论可以通过多种方式和技术来完成。我们的目的是通过分析来熟悉每个市场的实际表现:

  • 应用评级分布
  • 用户感受(负面/正面)
  • 每个应用版本的平均评分
  • 每月每天的平均评分
  • 平均评论字符长度
  • 使用 googleLanguageR 进行文本翻译
  • 文本情感分析

1.RStudio 中的准备工作

从下载 R 和 IDER studio开始。其次,我们需要为我们的市场可视化收集所有需要的 Apple Store 国家代码的列表。要获取应用程序数据,我们需要 iOS 应用程序 ID,它可以在 iTunes URL 中找到。只需谷歌你喜欢的应用程序,并复制 ID。

现在,安装并加载所需的库。您可以通过编写 Install (- library)在源代码中完成此操作,或者从 CRAN 存储库中单击 Packages > Install。itunesr 可以直接从 CRAN 安装,但是我确实推荐从 Github 安装最新的开发版本。

# Install and load libraries
devtools::install_github("amrrs/itunesr")
remotes::install_github("ropensci/googleLanguageR")library(itunesr)
library(googleLanguageR)
library(openxlsx)
library(ggplot2)
library(writexl)
library(tidyr)
library(dplyr)
library(sentimentr)
library(scales)
library(tidyverse)
library(tidytext)
library(DataExplorer)# Spotify iOS App ID
appstoreID = 324684580# Get information about the Spotify App
getAttributes(appstoreID,'se')# Create this df for later purpose
df_App_allMarkets = NULL

函数getAttributes在我们的 RStudio 控制台中显示应用程序、开发者、包、URL 和类别的标题。

2.收集市场评论和评级

好吧,让我们踢它!接下来,我们将创建一个空数据框,用于保存 Apple 允许我们导入的最后 500 条评论。 (Spotify 在 65 个市场 都有存在,但对于这个例子,我只用了其中的 12 个)。然后我们为 iTunes 中的第二个和最后一个评论页面设置变量,然后创建一个 for 循环,该循环将遍历每个市场的所有评论,并将它们绑定到一个主数据框架中。

## 1\. Prepare to loop through last 500 reviews per market# Spotify App Store Country Codes 
appMarketsSpotify <- c("se", "us", "dk", "de", "hu", "it", "nl", "no", "br", "ca", "ch")# Each page has 51 reviews between each pagination
no_ratings <- 500 #500
no_reviews_per_page <- 51
ratings <- no_ratings/no_reviews_per_page# Round up pagination & set variables for second and last page
ratings <- ceiling(ratings) #round up to 10
reviewStartPage <- 2
reviewEndPage <- ratings

在合并之前,下一段代码将遍历给定市场的每个评论页面。然后,我们将变量df_App$Date从默认的 POSIXt 转换为 Date,在最后创建本地市场数据框之前,按索引对列进行排序和重新排序。最后,我们使用rbind(df_App_allMarkets, df_App_Market).将所有数据框绑定在一起,因为您可能会收到重复的评论,所以有必要使用命令unique(data frame)删除它们,这取决于评论和市场的数量,脚本可能需要几分钟时间。☕

## 2\. Loop through all App markets and bind them together
for (appMarket in appMarketsSpotify) {

# Creates a df with first review page (1)                        
df_App <- getReviews(appstoreID,appMarket,1)# Create a for loop and merge all tables in to one single df
for (page in reviewStartPage:reviewEndPage){
  df_App <- rbind(df_App, getReviews(appstoreID,appMarket, page))
}# Convert 'Date' from POSIXt to Date and sort df by date (ascending)
df_App$Date <- as.Date(df_App$Date)
df_App <- df_App[order(df_App$Date),]# Reorder columns in our df by column index and add market suffix 
df_App <- df_App[c(7, 4, 5, 1, 6, 2, 3)]
df_App$Market=appMarket# Create df for each local market
df_App_Market <- print(appMarket)
df_App_Market <- df_App# Bind all markets together into one single df
df_App_allMarkets <- rbind(df_App_allMarkets, df_App_Market)# Remove dublicated reviews
df_App_allMarkets <- unique(df_App_allMarkets)### End loop
}

Loop through each market and bind all data frames to one

在可视化我们的数据框之前,让我们检查输入数据集的维度,以了解我们正在处理的内容。我使用库 DataExplorer 通过编写对我们的数据框架进行快速 EDA。plot_str(df_App_allMarkets)

Explore your variables with DataExplorer

现在,让我们简单地通过编写View(df_App$Market)并按回车键来预览和探索我们的聚合数据框架df_App$Market。在 RStudio GUI 中的全局环境下,我们可以研究我们的数据框,看到有 6908 个收集的观察值,分为 8 列。

Master data frame including all ratings and reviews in RStudio

Simple qplot showing the distribution of ratings

要了解每个市场的评论数量,请使用table(df_App_allMarkets$Market)table(df_App_allMarkets$Rating)查看评分分布。用qplot(df_App_allMarkets$Rating)进行图形可视化绘图审查。

2.1 将数据框导出到 Excel

我们可能需要稍后返回并处理我们的数据框,因此,与其偶尔重新运行上面的脚本,不如将所有检查导出到 SQL 数据库、Excel 或 CSV 文件中,这样会更有效。在此之前,我们需要做一些小的调整,例如,将国家后缀改为国家名称。

# Sort df by rating 1-5
df_App_allMarkets$Rating <- factor(df_App_allMarkets$Rating, 
levels = c("1", "2", "3", "4", "5"))# Convert data types & rename country codes before visualization 
df_App_allMarkets$Rating <- as.numeric(df_App_allMarkets$Rating)
df_App_allMarkets$Date <- as.Date(df_App_allMarkets$Date)df_App_allMarkets$Market <- revalue(df_App_allMarkets$Market, 
  c("se" = "Sweden", 
    "us" = "USA", 
    "de" = "Germany",
    "hu" = "Hungary",
    "it" = "Italy",
    "nl" = "Netherlands",
    "no" = "Norway",
    "br" = "Brazil",
    "ch" = "Switzerland",
    "gb" = "Great Britain",
    "ca" = "Canada",
    "dk" = "Denmark"))

现在,让我们使用 R 包openxlsx将 df 导出为 Excel 文件。文件 AppStoreReviews.xlsx 将存储在您的本地工作目录中。如果你不确定你的归途,写下getwd()并按回车键。

#Save as Excel to back up collected reviews
write_xlsx(df_App_allMarkets, path = ("AppStoreReviews.xlsx"), col_names = TRUE)

Save a local XLSX file as a backup for the future

现在,我们甚至可以在 R 中创建预定任务,并在我们的主电子表格中添加新的评论,无论是在本地还是在 Google Drive 上。

恭喜,您刚刚为自己节省了数百美元,因为您没有购买一个或多或少做同样事情的工具。

2.2 可视化评级和评论

现在是可视化的时候了,我们将使用 ggplot2 进一步探索,并希望从我们收集的评论中获得一些有价值的见解。注意我们只处理每个市场最新的 500 条评论,所有评分都与一条评论配对。Spotify 音乐在 App Store 的评分是 4.7 星。这比平均评分为 3.9 的点评高出 20 %,mean(df_App_allMarkets$Rating)如前所述,撰写点评的用户通常比那些只给出评分的用户更不满意。

2.3 缺乏足够的数据

由于每个市场内提交 Spotify 应用评论的时间段不同,你不能根据最近 500 条评论得出任何重要结论。如果我们继续我们的主数据框架,我们会注意到,用户评论和评级更频繁的市场将比那些评论较少的市场分布相对不均匀。因此,在汇总所有市场的数据时,我们需要小心我们的假设。让我们通过qplot(df_App_allMarkets$Date).来形象化这个模式

Reviews by date

很明显,大多数审查是在过去 60 天内进行的。实际上只有在美国,在过去的 7 天里有+500 条评论。(但这不是一个普通的应用程序,🇸🇪).加油

如果你在每个市场总共只有大约 200 条评论,那么你是安全的,但是在我们的情况下,我们在过去的 365 天里有 166,952 条评论和 2,858,871 个评级,因此我们被敦促收集更多的数据。因为这篇文章的目的是展示什么是可能的原则,而不是确切的数字,所以我把钱花在了昂贵的许可证以外的东西上。

3.审查数据分析

3.1 应用评级分布

问题:我们需要比较每个市场的收视率分布,以了解差异。关于评级的一个常见假设是,要么你是一个快乐的用户,要么是一个愤怒的批评者,这将反映出图表中你看到大量的 1 星和 5 星评级。

解法:让我们用geom_bar.来绘制分布图

### App rating distribution per marketggplot(df_App_allMarkets, aes(x=as.factor(Rating), fill=as.factor(Rating))) +
geom_bar(col="white")+
    theme_bw() +
    labs(title="App rating distrubution per market", 
    x="Ratings 1-5", y="No of Ratings")+theme(plot.title = element_text(family = "Circular Std",     color="black", face="bold", size=22, hjust=0))+scale_fill_manual("Ratings", values = c("1" = "#DA393B", "2" = "#EE6D45", "3" = "#F7E458", "4" = "#68E194", "5" = "#5F9CEF"))+
facet_wrap(~Market, scales = 'free_x')

App rating (1–5) distribution per market

见解: 1 星或 5 星评级似乎是最受欢迎的评级。最满意的用户来自匈牙利、瑞典、挪威和意大利。然而,大多数不满意的用户是在巴西、加拿大、德国和瑞士。我会分析为什么这么多匈牙利用户乐于给出 5 星评级,并对德国所有 1 星评级进行关键字分析。此外,用每周的平均评分绘制一个线形图,以了解历史发展情况。

3.2 用户感受(负面/正面)

问题:在同一个地块上用 1-5 颗星来比较 12 个不同的市场可能很难读懂。因此,让我们去掉所有中性的 3 星评级,将其分解为负面(1-2 星)和正面(4-5 星)评级。

解决方案:首先基于df_App_allMarkets.创建一个新的数据框,接下来我们将变量 Rating 从数值转换为字符,然后用正负字符替换 ratings。最后,将结果绘制为每个市场的总份额。

### User feeling for each market# Create a new df based on df_App_allMarkets
df_Ratings_Simplified <- data.frame("Date" = df_App_allMarkets$Date, "Rating" = df_App_allMarkets$Rating, "AppVersion" = df_App_allMarkets$App_Version, "Market" = df_App_allMarkets$Market)# Convert ratings to vector and replace ratings with text
df_Ratings_Simplified$Rating <- as.character(df_Ratings_Simplified$Rating)# Remove all ratings with 3-stars from df
df_Ratings_Simplified <- df_Ratings_Simplified[!df_Ratings_Simplified$Rating == "3", ]# Replace 1-2 star ratings with text Negative, and 4-5 stars with text Positivedf_Ratings_Simplified$Rating[df_Ratings_Simplified$Rating == '1'] 
<- 'Negative'+df_Ratings_Simplified$Rating[df_Ratings_Simplified$Rating == '2'] 
<- 'Negative'+df_Ratings_Simplified$Rating[df_Ratings_Simplified$Rating == '4'] 
<- 'Positive'+df_Ratings_Simplified$Rating[df_Ratings_Simplified$Rating == '5'] 
<- 'Positive'# Plot user feelings for each market
ggplot(df_Ratings_Simplified, aes(Rating, group = Market)) + 
geom_bar(aes(y = ..prop.., fill = factor(..x..)), stat="count") + 
geom_text(aes( label = scales::percent(..prop..), y= ..prop.. ), size = 4, stat= "count", vjust = -0.4) +theme_bw() +
theme(legend.position="none")+
scale_fill_manual("Ratings", values = c("1" = "#ED5540", "2" = "#68E194"))+
labs(y = "Rating", fill="Rating") +
scale_y_continuous(labels=scales::percent, limits = c(0, 1)) +ylab("relative frequencies") +
xlab("Procent") +  labs(title="User feeling per market", x="Reviews", y="Amount")+
labs(caption = "(Negative = 1-2 stars, Positive = 4-5 stars)")+facet_wrap(~Market, scales = 'free_x')

Distribution between negative and positive ratings

见解:理解满意和失望用户的动机和区别同样重要。除了美国、加拿大、巴西和德国的用户更不满意之外,每个市场的结果似乎是一样的。通过分析这些评论,你可能会发现相似之处。

3.3 每个工作日的用户感受

问题:正面或负面的评级可以很容易地分割,以报告每月、每周或每周的数据。如果我们需要了解评论何时发布,以及用户在一周中的感受有何不同,我们可以通过可视化每个工作日的感受来做到这一点。

解决方案:首先,我们将可变日期(2018–08–23)转换为工作日,例如周六。然后我们用一个堆叠的条形图来绘制结果,显示正面和负面评论的数量,包括总数。如果你需要比较市场的不同,只需取消下面最后一行的注释。

### Plot feelings by weekday 
df_Ratings_Feeling_Week <- df_Ratings_Simplified
df_Ratings_Feeling_Week$Date <- format(as.Date(df_Ratings_Feeling_Week$Date), '%A')ggplot(df_Ratings_Feeling_Week, aes(x = as.factor(Date), fill = Rating, label = Rating)) +
  geom_bar(stat = "count")+
  theme_bw() +
  scale_fill_manual("Ratings", values = c("Positive" = "#68E194", "Negative" = "#ED5540"))+
   theme(plot.title = element_text(family = "Circular Std", color="black", face="bold", size=26, hjust=0)) +ylab("relative frequencies")+
  xlab("Procent")+ 
  labs(title="User feeling per weekday", x="Weekday", y="Ratings")+
  labs(caption = "(Negative = 1-2 stars, Positive = 4-5 stars)")+
     scale_x_discrete(limits=c("Måndag","Tisdag","Onsdag","Torsdag","Fredag","Lördag","Söndag"))#facet_wrap(~Market, scales = 'free_x')

见解:工作日的分布是均匀的。评论的数量在周三和周日给出,负面和正面评论的份额在周一有一个小的例外。

3.4 每个应用版本的平均评分

问题:为了了解用户对每个版本及其功能的接受程度,我们可以按市场绘制每个应用版本的平均评分。

解决方案:首先,我们汇总每个应用版本的所有评分,并计算平均评分。然后,我们重命名列,并按升序排列等级。最后,删除评分为零的行,在我们的例子中是第 10、11、12、16、22 和 38 行。然后画出结果。

### Average ratings per App version
# Creates a df with mean values for each app version
df_MeanRatingsVersion <- aggregate(df_App_allMarkets$Rating ~ df_App_allMarkets$App_Version, df_App_allMarkets, mean)# Rename df columns
names(df_MeanRatingsVersion)[1]<- "Version"
names(df_MeanRatingsVersion)[2]<- "Rating"# Sort by ratings ascending
df_MeanRatingsVersion$Version <- factor(df_MeanRatingsVersion$Version, levels = df_MeanRatingsVersion$Version[order(-df_MeanRatingsVersion$Rating)])# Strip specific rows and round mean values
df_MeanRatingsVersion <- 
df_MeanRatingsVersion[-c(10, 11, 12, 16,22,38), ]df_MeanRatingsVersion$Rating <- 
round(df_MeanRatingsVersion$Rating, digits = 2)# Plot average ratings for each app version
ggplot(df_MeanRatingsVersion, aes(x = Version, y = Rating, label=Rating)) +
  geom_bar(fill = "#29E58E", stat = "identity")+
  geom_text(position = 'identity', stat = 'identity', size = 4, vjust = -0.4)+

theme_bw() +
  labs(title="Average ratings for each App Version", size=60) +
  labs(x="App Version", y="Avg. Rating")

Plot showing App average rating sorted both by version and rating

见解:基于上述数据的故事,希望由 Spotify 内部的人讲述会比外部的人更好。无论如何,很难把握这个评级是与评论时的特定应用版本有关,还是更具一般性。但是,从长期角度来看平均评级,我们可以看到平均评级会随着时间的推移而提高。

3.5 每月每天的平均评分

问题:根据你的应用类别和对周期性行为的敏感度,了解平均评分在每个月是否有变化可能会很有趣。例如,研究高使用率和高/低收视率之间是否有关联是很有价值的?

解决方案:绘制该月每天的平均评分。开始计算平均评分和重命名列。然后,我们使用POSIXlt将日期转换为一个月中的某一天,并将日期和评级拆分到不同的列中。将评级四舍五入到 1 位数,然后绘制数据。

### Calculate average ratings for each day and change column names
df_MeanRatingsDays <- aggregate(df_App_allMarkets$Rating ~ df_App_allMarkets$Date, df_App_allMarkets, mean)
names(df_MeanRatingsDays)[1]<- "Date"
names(df_MeanRatingsDays)[2]<- "Rating"# Convert dates to day of  month
df_MeanRatingsDays$Date <- unclass(as.POSIXlt(df_MeanRatingsDays$Date))$mday# Split Day of month and avg. rating to separate columns 
df_MeanRatingsDays <- aggregate(df_MeanRatingsDays$Rating ~ df_MeanRatingsDays$Date, df_MeanRatingsDays, mean)
names(df_MeanRatingsDays)[1]<- "Day"
names(df_MeanRatingsDays)[2]<- "Rating"# Round Ratings to 1 digit
df_MeanRatingsDays$Rating <- 
round(df_MeanRatingsDays$Rating, digits = 1)# Plot mean ratings for each day of month
ggplot(df_MeanRatingsDays, aes(x = Day, y = Rating, label = Rating))+
  geom_bar(fill = "#29E58E", stat = "identity")+
  theme_bw() +
  geom_text(position = 'identity', stat = 'identity', size = 4, vjust = -0.4)+labs(title="Average ratings by day of month", size=60) +
  theme(plot.title = element_text(family = "Circular Std", color="black", face="bold", size=26, hjust=0)) +
  labs(x="Day of Month", y="Avg. Rating")+scale_x_discrete(limits=df_MeanRatingsDays$Day)+
  scale_y_continuous(limits = c(0,5))

Plot showing how the monthly rating changes during the month

见解:除了相当均匀的分布(这只是一个月中某一天不会影响平均评级的标志)之外,没有令人惊叹的见解可以建立其他东西。如果你在金融或医疗行业,这种模式可能会有所不同。我还建议按时间、工作日和月份来研究评级。

3.6 平均评论字符长度

我们的下一个图可能更好地定义为 EDA(探索性数据分析),而不是解决问题,但我想通过查看密度和平均评论长度来了解每个市场的评论长度之间是否有任何差异。因为我们已经知道每个市场的评级分布,所以看看它是否与评论长度相关会很有趣。

所以让我们先统计一下每篇评论的时长,然后按市场统计平均时长。接下来,我们重命名我们的列,并将它们与我们的主数据框架合并在一起,然后对数字进行舍入,然后绘制评论密度,包括市场的平均长度。(现在你可以呼吸了)

### Count length of reviews and create a sorted df_App_allMarkets$Review <- as.character(df_App_allMarkets$Review)
df_App_allMarkets$ReviewLength <- nchar(df_App_allMarkets$Review)# Count the average review lenght for each market
df_MeanLengthMarket <- aggregate(df_App_allMarkets$ReviewLength ~ df_App_allMarkets$Market, df_App_allMarkets, mean)names(df_MeanLengthMarket)[1]<- "Market"
names(df_MeanLengthMarket)[2]<- "AvgReviewLength"df2_App_allMarkets <- 
merge(df_App_allMarkets,df_MeanLengthMarket, by  = "Market")# Round numbers before visualizing
df2_App_allMarkets$AvgReviewLength <- round(df2_App_allMarkets$AvgReviewLength, digits = 2)ggplot(data=df2_App_allMarkets, aes(x=ReviewLength)) + 
  geom_density(aes(y = ..count..), color="#1F3161", fill = "#68E193", alpha=0.6) +
  geom_vline(aes(xintercept = df2_App_allMarkets$AvgReviewLength), linetype = "dashed", size = 0.5)+

facet_wrap(~Market, scales = 'free')+
  geom_text(data=df2_App_allMarkets, mapping=aes(x=AvgReviewLength, y=2, label=AvgReviewLength), check_overlap = TRUE, size=5, angle=0, vjust=1, hjust=-0.5)+
    ylim(0,5)+
    xlim(5,600)+theme_minimal()+
    labs(title="Review Character Length", subtitle = "The average length per review for each market", x="Review Length", y="")+
     theme(plot.title = element_text(family = "Circular Std", color="black", face="bold", size=22, hjust=0)) +
     theme(axis.title = element_text(family = "Circular Std", color="black", face="bold", size=12)) +
     theme(plot.subtitle = element_text(family = "Helvetica", color="black", face="plain", size=14))+
     theme(strip.text = element_text(face="bold", size=12))  +
     theme(panel.border = element_blank(), panel.grid.major = element_blank(),
     panel.grid.minor = element_blank(), axis.line = element_line(colour = "black"))

Plot split by market showing the average review length

而且没错,似乎是高收视率和人物少的搭配。我们之前知道的是,美国、加拿大、巴西和德国是最不满意的,并期望巴西是平均字符长度最高的市场。此外,我们匈牙利快乐的营员似乎除了“tkéletes”和“hibátlan”之外没有更多的话要说。

Distribution of review length for each rating

为了扩大假设,即消极用户有更多的事情要说,反之亦然,让我们删除geom_vline,从facet_wrap切换到Rating

很明显,快乐的用户没什么可说的,尽管一星评分者写的单词更少,如“垃圾”、“劣质应用”等。给出 2-3-4 星的用户实际上是值得一读的,因为他们经常激励他们的评级。当分析一个不太受欢迎的应用程序时,请注意高评分的长评论。这些评论可能是假的。

4.文本情感分析

4.1 使用 googleLanguageR 翻译评论

在我们的书面评论中可以找到更多的黄金,而不仅仅是每个评级的平均长度。为了进行文本挖掘和基本情感分析,我们必须将所有 12 个市场的书面评论翻译成英语。这可以通过作者马克·埃德蒙森的 googleLanguageR 包的谷歌云机器学习 API 来完成。在进一步操作之前,请遵循认证指南

谷歌是伟大的,但没有什么是免费的,所以在翻译+100.000 评论之前,请确保你知道成本。在我的情况下,我得到了一些免费的学分,但如果你没有,我会建议你从你的数据中随机选取一个样本,如下所示。

Translating reviews with Google Cloud Machine Learning API

首先加载并运行您的*。json 身份验证文件,然后选择一个样本大小,并创建一个新的向量,在翻译之前将对其进行翻译。(注意,这可能需要几分钟时间)。

### Prepare for translation of market reviews with Google Translate# Include Gooogle Cloud Service Identity
  gl_auth("API Translate-xxxxxxxxxxxx.json")# Sample 5000 random rows
  df2_App_allMarkets_sample <- sample_n(df2_App_allMarkets, 5000)
  View(df2_App_allMarkets_sample)# Convert Reviews to character vector
  text <- as.character(df2_App_allMarkets_sample$Review)# Create a new df from translated reviews (automatic lang.detection)
  df_Translation <- gl_translate(text, target = "en")# Add english translated reviews to original df
df2_App_allMarkets_sample$Review_translated <- df_Translation$translatedText

要预览和检查结果,请编写:head(df2_App_allMarkets_sample$Review_translated, 10)

4.2 使用 sentimentr 执行情感分析

sentimentr 旨在快速计算句子级别的文本极性情感,并选择性地按行聚合。让我们继续进行情感分析,对每篇翻译后的评论进行正面或负面评分。最后,我们将这些情绪得分与我们的主数据框架绑定在一起,用于未来的绘图。

## 4\. Perform sentiment analysis on each review

# Create a copy of df2_App_allMarkets_sample
  df_ReviewSentiment <- df2_App_allMarkets_sample

# Check  names of the columns and drop those not needed
  names(df_ReviewSentiment)
  df_ReviewSentiment <- subset(df_ReviewSentiment, select = -
  c(Author_URL, Author_Name, ReviewLength, Title))

# Add translated reviews in our data frame
df_ReviewSentiment$ReviewTranslated <-
  as.character(df2_App_allMarkets_sample$Review_translated)

# Perform sentiment analysis and round values
df_ReviewSentiment$reviews_sentiment <- reviews_sentiment %>%    
  sentiment_by(by=NULL)df_ReviewSentiment$reviews_sentiment <- 
  round(df_ReviewSentiment$reviews_sentiment, digits = 2)

查看情感评分最高:head(df_ReviewSentiment$reviews_sentiment, 3)和最低:tail(df_ReviewSentiment$reviews_sentiment, 3).的评论

Top 3 positive reviews and bottom 3 most negative

4.3 用星级评定验证情感得分

从上图来看,一切似乎都功能齐全,但进行情感分析远比这复杂。所以问题是——我们能在多大程度上根据客户的书面意见预测他们的评级?

让我们检查一下我们的评分是否与书面评论的平均情感分数相关。

# Correlate sentiment score with ratingsggplot(df_ReviewSentiment, aes(Rating, reviews_sentiment$ave_sentiment, group = Rating)) +
    geom_boxplot(fill="#29E58E") +
    theme_minimal()+
    labs(title="App reviews sentiment score per market", y="Average sentiment score")+
    geom_jitter(shape=16, size=0.7, position=position_jitter(0.3))

Boxplot showing the review distribution for each rating

箱线图是一种通过四分位数以图形方式描绘数字数据组的方法。它帮助我们将平均分和每个评论可视化为一个单独的点。它可能不适合挂在你的墙上,但结果是令人满意的。虽然我们有太多得分低于零的五星异常值,但平均得分与星级相关。还有,接近平均水平的评论分布清晰,这很好。

4.3 审查每个市场的情绪得分

为了全面了解应用的感知如何随着时间的推移而变化,我们可以将每个市场从第一次收集评论到最后一次收集评论的应用评论数据中的平均情绪得分可视化。如果这是你的 polestar 指标,我会建议监控平均情绪得分,并使用 Twitter 的 AnomalyDetection 包在得分下降到定义的具体阈值时发出警报。

(注意:小心你的建议,因为每个市场的周期不同。提高声音前先检查 x 音阶)。

# App reviews sentiment score
  ggplot(test, aes(x = Date, y = reviews_sentiment$ave_sentiment, fill=Market)) + 
    geom_smooth(colour="black", size=1) +
    theme_bw() +
    theme_minimal()+
    labs(title="App reviews sentiment score per market", 
          subtitle = "Time period differs due to the amount of reviews in the near future", 
          x="Date", 
          y="Reviews Sentiment Scores")+
    facet_wrap(~Market, scales = "free_x")

Visualization of the sentiment score by date and market

4.4 文本挖掘——如何将评论分解成有价值的见解

为了充分理解每个评论的核心,以及每个单词如何影响应用程序的整体感知,我们需要将评论句子分解成单词。这可以通过标记化来实现。在标记化的过程中,一些像标点符号和停用词的字符被丢弃,以将噪声变成信号。

我们想要实现的目标:

  • 把句子分成单个的单词
  • 删除停用词
  • 画出 100 个最常见的单词
  • 给单词添加情感分数
  • 画出最消极和积极的单词
  • 创建一个显示两极分化的词云
# Create a new data frame with only words
  TranslatedText <- as.vector(df_Translation$translatedText)
  TranslatedText <- data_frame(line = 1:5000, text = TranslatedText)# Split reviews to individual words - "Tokenization"
  tidy_df <- TranslatedText %>%
    unnest_tokens(word, text)

# Remove stop words
  data(stop_words)

  tidy_df <- tidy_df %>%
    anti_join(stop_words)

  tidy_df %>%
    count(word, sort = TRUE)

# Visualize words that occur +100 times
tidy_df %>%
count(word, sort = TRUE) %>%
  filter(n > 100) %>%
  mutate(word = reorder(word, n)) %>%

 ggplot(aes(word, n)) +
  theme_minimal()+
  labs(title="Words that occur more than 100 times", subtitle = "Occurring individual words in our sampled reviews", x="", y="Contribution to sentiment")+
  geom_col() +
  xlab(NULL) +
  coord_flip()

How often each word occur in the review

毫不奇怪,像“应用程序”、“音乐”、“Spotify”和“歌曲”这样的词出现得更频繁。但更有意思的是,“溢价”似乎和“付出”、“讨厌”一样,都是热门话题。我会过滤掉所有出现这些词的评论,然后进行进一步的分析。

现在,让我们在 bing 词典的帮助下,将这些单词分成两个独立的组,积极的和消极的。

# Add sentiment scores to each word
  get_sentiments("bing") 

  bing_word_counts <- tidy_df %>%
    inner_join(get_sentiments("bing")) %>%
    count(word, sentiment, sort = TRUE) %>%
  ungroup()

  bing_word_countsbing_word_counts %>%
    group_by(sentiment) %>%
    top_n(25) %>%
    ungroup() %>%
    mutate(word = reorder(word, n)) %>%# Visualize the distrubution of word sentiment
    ggplot(aes(word, n, fill = sentiment)) +
    geom_col(show.legend = FALSE) +
    theme_minimal()+
    labs(title="Distribution of word sentiment", subtitle = "Words that contribute to positive and negative sentiment", x="", y="Contribution to sentiment")+
    facet_wrap(~sentiment, scales = "free_y") +
  coord_flip()

Plot showing the most frequent negative and positive words

我会让你分析这个,但有趣的是,人们对这个应用程序有着根本不同的看法。研究对立面并观察它们如何随着时间的推移而变化将会很有趣。

最后,我们将使用相同的数据,但使用一个词云的可视化,其中一个词的频率由大小反映。

library(reshape2)
library(wordcloud)

# Word cloud showing 200 words
 tidy_df %>%
    anti_join(stop_words) %>%
    count(word) %>%
    with(wordcloud(word, n, use.r.layout=FALSE,max.words = 200))# Word cloud showing 200 words by sentiment score
  tidy_df %>%
    inner_join(get_sentiments("bing")) %>%
    count(word, sentiment, sort = TRUE) %>%
    acast(word ~ sentiment, value.var = "n", fill = 0) %>%
    comparison.cloud(colors = c("#D9383A", "#68E193"),
                     use.r.layout=FALSE,
                     max.words = 200)

尽管每个单词的大小不同还有改进的空间,但是很容易理解哪些单词是最常用的。这些云可以按市场和/或应用程序版本划分,以跟踪变化和趋势。

是我中途把你弄丢了,还是你读完了整篇文章?无论如何,我真的很喜欢你关于评级和评论挖掘的反馈和想法。

弗雷德里克·塞德洛夫
收藏家银行的数字分析主管&用户研究

Spotify 数据项目第 1 部分——从数据检索到第一视角

原文:https://towardsdatascience.com/spotify-data-project-part-1-from-data-retrieval-to-first-insights-f5f819f8e1c3?source=collection_archive---------13-----------------------

到目前为止,2018 年对我们这些数据书呆子来说是很棒的一年。有很多很好的选择来获得有趣的数据,例如最大的数据科学社区 Kaggle,拥有超过 10,000 个来自各种行业的已发布数据集。或者,谷歌(碰巧也拥有 Kaggle)新推出的数据集搜索工具,让寻找数据集来练习数据肌肉变得像安装 Pandas(或任何其他数据科学库)一样简单。

如果你愿意尝试一些好的数据,你可以选择 API。Twitter、Slack 和谷歌等科技公司(又来了!)提供 API,以便其他人可以在这些 API 的基础上构建应用程序。没有什么可以阻止你使用它们来提取数据和进行数据分析。

在这一系列文章中,我将描述我如何利用 Spotify Web API 自动检索数据(主要是本文的主题),以及如何使用 Python、SQL 和 Bash 等数据科学工具从数据中获得洞察力(将在后续文章中讨论)。

注意:如果你只对编码感兴趣,请随意跳到本文末尾,在那里你会找到所有用于这个项目的笔记本、工具和参考资料。

资料检索

为了访问 Spotify 的平台,你需要在 developer.spotify.com创建一个账户。之后,您可以直接进入 Spotify Web API 控制台,通过一个易于使用的界面开始探索不同的 API 端点,而完全不需要任何 Jupyter 笔记本!

本质上,API 基于请求/响应工作。你问 API 关于 2010 年至 2012 年黄金岁月的歌曲,API 的回答是我们这一代的一些最佳歌曲,如 this gem 。然而,由于与 API 的通信是以机器可读的格式(如 JSON)完成的,所以您将希望使用编程语言来完成这一任务。也就是说,如果你想利用 Spotify 目录中的数百万行音乐数据。

因为我使用的是 Python,所以有一个非常好的库叫做 Spotipy ,这使得访问 Spotify API 的过程变得更加容易。

一旦你安装了 Spotipy,下面的代码足以让它启动并运行(使用你自己的 cid 和来自你的 Spotify 开发者帐户的密码):

import spotipy from spotipy.oauth2 import SpotifyClientCredentials cid ="xx" secret = "xx" 
client_credentials_manager = SpotifyClientCredentials(client_id=cid, client_secret=secret) 
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)

现在您可以开始实际的数据检索了。通过观察 Spotify API 的不同端点,你可能会问自己:我应该获取什么数据?

这是你需要开始挖掘并找出你感兴趣的东西的地方。在这个例子中,我只使用了 50 多个可用端点中的 2 个。您可能会发现其他一些端点对您的分析也很有用。

我知道我想处理跟踪数据。这就是为什么我使用了搜索端点(而不是获得几个轨道端点,因为它需要提供轨道 id,而我没有)。

搜索端点很容易使用,因为只需要两个参数:q 和 type。第一个可以是任何关键词,如“roadhouse blues”或“2018”。类型可以是专辑、艺术家、播放列表或曲目。

这个端点也有一些限制:

  • 限制:每个查询最多可以返回 50 个结果
  • offset:这是要返回的第一个结果的索引,所以如果您想获得索引为 50–100 的结果,您需要将 offset 设置为 50 等。

此外,最大偏移量被限制为 10.000,这意味着您无法获得比单次搜索更多的结果。趣闻:我第一次做数据检索的时候(2018 年 4 月底)最大偏移量是 100.000。希望我不是他们决定砍掉它的原因:)

为了解决这些限制,我使用了一个嵌套的 for 循环,在这个循环中,我在外部循环中将偏移量增加了 50,直到达到最大偏移量。在将返回的结果追加到列表中时,内部 for 循环执行实际的查询。

for i in range(0,10000,50): 
  track_results = sp.search(q='year:2018', type='track',       limit=50,offset=i) 
    for i, t in enumerate(track_results['tracks']['items']):   artist_name.append(t['artists'][0]['name']) track_name.append(t['name']) track_id.append(t['id']) popularity.append(t['popularity'])

在我将数据加载到 pandas 数据框架中之后,我得到了以下结果:

artist_name	popularity	track_id	track_name 0	Drake 100	2G7V7zsVDxg1yRsu7Ew9RJ	In My Feelings 1	XXXTENTACION	97	3ee8Jmje8o58CHK66QrVC2	SAD! 2	
Tyga 96	5IaHrVsrferBYDm0bDyABy	Taste (feat. Offset) 3	
Cardi B 97	58q2HKrzhC3ozto2nDdN4z	I Like It 4	
XXXTENTACION	95	0JP9xo3adEtGSdUEISiszL	Moonlight

这已经足够了,正如我将在本文的第二部分展示的那样,届时我将更深入地挖掘 Spotify 提供的“流行”功能。由于我也想做一些更高级的分析(提示:机器学习),我还包括了由 get 几个音频特征端点提供的数据。

此端点仅要求提供轨道 id。这不成问题,因为我在之前的查询中有 10.000 个音轨 id。

这里的限制是每个查询最多可以提交 100 个曲目 id。

同样,我使用了嵌套的 for 循环。这一次,外部循环以 100 为一批提取跟踪 id,内部 for 循环执行查询并将结果追加到 rows 列表中。

此外,当音轨 ID 没有返回任何音频特征(即没有返回任何音频特征)时,我必须执行检查,因为这会导致问题:

for i in range(0,len(df_tracks['track_id']),batchsize): 
 batch = df_tracks['track_id'][i:i+batchsize] 
 feature_results = sp.audio_features(batch) 
  for i, t in enumerate(feature_results): 
   if t == None: 
    None_counter = None_counter + 1 
   else: rows.append(t)

作为回报,我为我的歌曲获得了一系列的音频特征,比如舞蹈性、音量、声音等等。然而,这些特性将是本系列的下一篇文章的一部分。

在使用流行特性进行数据分析之前,我想向您展示我如何在 Linux 终端(命令行/ Bash)上设置 cron 作业,以便在我睡觉时自动进行数据检索!

这非常简单:您只需要您的 Python 文件(如果您使用的是 Jupyter 笔记本,您可以将其下载为. py 文件),然后创建一个 Bash 脚本(。sh 文件),它将在 Python 中运行该文件:

#!/usr/bin/env bash python3 /home/user/SpotifyDataScript.py

最后,您打开 crontab 编辑器,在所需的时间和日期设置 cron 作业,如下所示:

30 00 * * 4 /home/user/Spotify.sh

瞧!你不用再担心了,数据现在会被自动检索。正如您从 Spotify 开发者仪表盘上截取的截图中所看到的,现在每周都会从 API 中自动提取数据。

如果你想了解更多关于 Bash 脚本和 cron 作业的信息,我推荐 data36 的这个系列文章以及这个快速参考指南

注意:尽管这对我来说已经很好了,我还是建议在设置 API 调用的自动化时要小心。通过使用更长的时间间隔来触发数据,例如每周一次甚至每月一次,尽量减少对提供方的影响。

数据探索:流行特征

正如所承诺的,我现在将使用检索到的数据从中获得一些见解。在本文中,我将重点介绍流行功能,根据 Spotify 官方文档的说法它的意思是:

“流行曲目。该值介于 0(最不受欢迎)和 100(最受欢迎)之间。曲目的受欢迎程度是一个介于 0 和 100 之间的值,100 是最受欢迎的。受欢迎程度主要基于播放的总次数。诸如单曲和专辑中的重复曲目的流行度评级是不同的。注意:该值不会实时更新,因此可能会落后于实际受欢迎程度。”

尽管 Spotify 对这一功能并不太精确,但这对于数据分析来说应该足够了。理想情况下,应该有另一个功能,如每个轨道的流数量,然而,Spotify 目前没有通过他们的 API 分享这些信息。

关于人气特性,需要了解的一件重要事情也在 2013 年一位名叫 Sascha 的用户发布的SO 帖子中进行了解释:

“Spotify 的受欢迎程度的确是基于流媒体的数量,但它不是基于总播放量,而是基于一个很短的时间段。这就是为什么你会经常在艺人简介上看到一个更受欢迎的数字排在第一位,而播放次数却比第二位少。

我们已经使用 API 数作为我们流流行度的百分比,让人们了解他们的曲目当前的流行度。所以请记住,这个数字可以增加,但也很容易减少。”

所以基本上,它代表了某首歌在某个时刻的受欢迎程度。这也解释了为什么它会随着时间的推移而变化,我可以从我每周的数据检索中注意到这一点。

由于我在 2018 年 8 月开始定期收集数据,我决定将以下 3 个数据检索纳入我的分析:

  • 2018 年 8 月 7 日
  • 2018 年 8 月 30 日
  • 2018 年 9 月 20 日

由于 Spotify 提到的流行度计算的所谓延迟,这应该很好地涵盖了 7 月、8 月和 9 月,这样我就可以将我的分析作为“2018 年夏季最受欢迎的歌曲”

为此,我将 3 个 CSV 文件加载到 Pandas 数据帧中,并将它们合并成一个数据帧。通过使用外部连接作为合并方法,保留了各自的流行性:

# loop over dataframes and merge into one dataframe 
# outer join in order to keep the popularity column from each file
for df_, files in zip(df_from_each_file, all_files): 
# all_files are here to provide the column suffix (0920,0830 etc) 
df = df.merge(df_, how='outer', on=merge_columns, suffixes=('',str(files)[-8:-4])

这已经是该分析的整个数据准备阶段中最棘手的部分。在那之后,我计算了一个总体受欢迎分数以及一个平均受欢迎分数。

按总体受欢迎程度分数排序的新数据框架如下所示:

artist_name	track_name	popularity	popularity_mean 3	Drake In My Feelings	300.0 100.000000 4	
XXXTENTACION	SAD! 288.0 96.000000 12	
Cardi B I Like It	288.0 96.000000 6	
Tyga Taste (feat. Offset)	287.0	95.666667 10	
Post Malone	Better Now	287.0 95.666667

当谈到 2018 年夏季热播时,似乎没有什么能比得上德雷克的《在我的感觉中》。

按艺术家对数据帧进行分组揭示了一些更有趣的见解,例如前 100 名中每个艺术家的曲目数量:

track_name artist_name 
Drake 5 
XXXTENTACION	5 
Travis Scott	5 
Post Malone	5 
Juice WRLD	3

每一个好的数据分析也应该有一些可视化。在这个例子中,我可视化了前 10 首歌曲在测量期间的个人受欢迎程度得分。这是可视化的一部分(查看文章末尾的笔记本文件以获得完整视图):

今天就到这里吧!检索并分析了大量数据,以了解 2018 年夏天最受欢迎的歌曲和艺术家。

在下一篇文章中,我将深入挖掘音频特征数据,并尝试不同的聚类算法。如果你对此感兴趣,请务必在 Twitter ( @tgel0 )上关注我,因为我会首先在那里发布新闻。如果你想和我打招呼或什么的,这也是联系我的最好方式(我很乐意)。

正如承诺的那样,以下是链接:

  • 数据检索笔记本放在 github 上或者作为 nbviewer 渲染
  • github 上的数据探索笔记本或作为 nbviewer 渲染
  • 非常感谢 Spotify 的 Web API,也感谢 Spotify 的创造者让我的生活变得更简单
  • 最后但同样重要的是,如果没有 Python 库 PandasNumpyMatplotlib 以及构建和维护它们的出色人员,这是不可能的
  • 如果你喜欢听音乐,而不仅仅是阅读,我已经根据这一分析创建了一个 Spotify 播放列表

原载于 2018 年 9 月 27 日tgel 0 . github . io

Spotify 重新包装

原文:https://towardsdatascience.com/spotify-rewrapped-e2a7cc94fb4e?source=collection_archive---------6-----------------------

Spotify 每年 12 月都会以酷炫的年终特价带给我们惊喜。然而,今年的一些报道让人感到可疑。这个不起眼的中等账户决定进行调查。

Photoshop skills: level 9000

每年我都期待 Spotify 的总结。2016 年是歌曲、艺术家和流派的前五名。花在听音乐上的时间,不同歌曲的数量,以及关于一周中你最喜欢哪一天听音乐的非常酷的见解。此外,你的热门歌曲播放列表。2017 年还带来了分钟数、热门歌曲播放列表和一个很酷的另一个播放列表,名为“The ones that away ”,可能是过去一年很酷的推荐。
今年带来了 Spotify Wrapped ,它告诉你许多统计数据(我们将分析)和两个播放列表:Top 100 和 Tastebreakers。我需要承认,我爱上了前卫的❤.它们应该让你在新的一年里听到 Spotify 惊人的推荐算法为你量身定制的新内容。

尽管这一次并不是一切都那么美好。 Spotify Wrapped 在 12 月前几天被泄露,并不是每个用户都对提供的见解感到高兴。只要在 Reddit 的 r/spotify 中快速浏览一下,就足以意识到前 5 名艺术家或前 5 名歌曲中的大多数都很奇怪。尤其是我的,看起来很奇怪;就好像我最后的几个月根本不算在内。

Charly and his famous bi-color moustache

像每一个音乐和数据极客一样,我用 Last.fm 记录(并不断咨询和控制)我的听力故事。所以,我知道我的数据不准确。10 月份和 11 月份的大部分时间,我都在不停地听 Charly García 的音乐,尤其是他的一个乐队项目:Serú Girán

有点跑题:这两个名字都是阿根廷摇滚的精华部分,是阿根廷摇滚的精华。自 1967 年以来,Charly 一直在从事不同的优秀项目,他仍然非常活跃。在 1978 年至 1982 年期间,以及在 1992 年持续一年的短暂复出期间,Serú Girán 是他的主要乐队。信不信由你,他们被认为是“阿根廷披头士”。

Judge by yourself 💥💥💥💥

我也一直想用 Python 的熊猫库研究一点时间序列操作和可视化,所以这看起来是一个很好的借口。

技术

和我的大多数数据项目一样,我的主要盟友是Python 3熊猫 matplotlib我还与 SeabornSpotipy 合作,为 Spotify Web API 做 Python 包装,并与 Pylast 合作,为 Last.fm API 做 Python 包装。就环境而言,我只使用了 Jupyter 笔记本电脑和版本化我的作品。可以在我的公众 Github 账号查看数据库创建、数据分析、数据可视化的完整代码。

** [## alexing/spotify_rewrapped

Spotify 重新包装。通过在 GitHub 上创建一个帐户,为 alexing/spotify_rewrapped 开发做出贡献。

github.com](https://github.com/alexing/spotify_rewrapped)

这些数据是从 Last.fm 的 API 中删除的,还用 Spotify 的 API 丰富了一点。此外,根据 GDPR 法律,我联系了 Spotify 客户支持,试图访问我的全部收听历史数据并获得更多见解。到写这篇文章的时候,我还没有收到回信。

数据分析

数据集由我从 1 月 1 日到 12 月中旬的收听历史组成。Spotify Wrapped 于 12 月 1 日发布,所以这一年还没有结束并不重要。

df.head()

Most of this features I won’t be using, like the listener_count, mbid, playcount and url.

让我们通过逐一浏览 Spotify 的见解(至少是有趣的……)来开始分析,并决定它们是真是假。

I got the email in Spanish, sorry. You probably get the main idea, though.

1.今年你在 Spotify 上听了 8486 首不同的歌曲。

.

嗯,这个很容易检查。只需要询问数据帧中的唯一值。

.

unique_songs = df[df.date < '2018-12-01'].drop_duplicates(subset=['artist', 'title', 'album']).shape[0]
unique_songs

6538

这意味着 Spotify 的数字和我的数字之间有 1948 首歌曲的差异。

假的!

考虑到 Wrapped 发行日期之后的歌曲没有计算在内,所以在数量上有相当大的差异。

2.你开始了 2018 年,听了《浪费的生命》Pearl Jam 的 Brendan O' Brien Mix,你发现的第一个艺术家是 Faces。

哦,这原来是辣的,而且超级容易检查。让我们开始吃吧。

df.loc[df['timestamp'].idxmin()]

事实上,我听的第一首歌是浪费的生命(开始 2019 年的精彩歌曲,对吗?!)。Spotify 的第一个目标。1–1 是这场比赛的部分比分。

现在,这是灰色部分,它开始变得不那么科学严谨。我们如何衡量被发现的艺术家?我用了手头的东西,决定用Spotify API 的功能来获取用户的顶级艺术家。这可以让你每次请求获得多达 50 位艺术家,其中一个有趣的参数让你在long_term(根据几年的数据计算,包括所有可用的新数据)medium_term(大约过去 6 个月)和short_term(大约过去 4 周)之间进行选择。有一个偏移量参数来平衡限制,以便在列表中进一步前进,但是如果偏移量超过 50,它会返回一个异常。基本上每个学期只能接触到前 100 个。在每个术语收到的 100 位艺术家中,我创建了一个集合,这样就不会出现重复,然后如果一个新的艺术家不在这个集合中,我会认为这是一个“发现”。

ranges = ['short_term', 'medium_term', 'long_term']
top_artists = set()
for a_range in ranges:
    results = sp.current_user_top_artists(time_range=a_range, limit=50)
    top_artists =top_artists.union({item['name'] for item in results['items']})
    results = sp.current_user_top_artists(time_range=a_range, limit=50, offset=49)
    top_artists =top_artists.union({item['name'] for item in results['items']})

基本上,第一个不在片场的艺术家将是我的第一个发现

reverse_df = df.iloc[::-1]
for i, row in reverse_df.iterrows():
    if row['artist'] not in top_artists:
        print("Song n# %d of the year" % (len(df) - i))
        print(row['artist'])
        print("Played on %s" % str(row['date']))
        break

年度歌曲第 74 首
惠特尼
播放时间 2018–01–01 16:04:00

df[df[‘artist’] == ‘Faces’]

太神奇了。不仅我第一个发现的艺术家不是面孔,而且今年我显然从未听过他们。所以这句话是:

对/错

Apparently Spotify calls me an overachiever 💪🏻

3.听了 58776 分钟。

.

.

这也是一件容易检查的事情。

.

df[df.date < '2018-12-01'].duration.astype('int').sum() / 1000 / 60

26860 . 868686868626

如果我们从 58776 分钟开始,有 281 分 13 秒的差距。如果我们计算今年(4:05)听的歌曲的平均持续时间,有 69 首歌曲的误差。

又一个热门,Spotify!这种说法是:

4。你和你最喜欢的艺术家荷西·德克勒一起度过了 41 个小时,这是他们的荣幸。

毫无疑问,今年我最喜欢的艺术家是荷西·德克勒。

Being retwitted by your favorite artist is better than Radiohead’s In Rainbows. Word.

如果你之前浏览过这个博客,你可能知道我对他的音乐和歌词做了深入的分析,他的专辑是我那漫长时光的配乐。关于快乐是他的那部分我真的怀疑,但我知道他喜欢它。

现在让我们检查小时数。

.

top_listened = df[df.date < '2018-12-01'].groupby(by=['artist']).agg('sum')['duration'].sort_values(ascending=False)[:1]
top_listened = top_listened / 1000 / 60 / 60 # ms / s / m -> h
top_listened

那是 42 小时 40 分钟。这意味着,如果我今年从 Drexler 那里听到的歌曲的平均值是 3:41, Spotify 的数字相差近 22 首歌曲

对不起,斯波提…但这是另一个

错误的

Any excuse that I can get to embed a Drexler song, I’ll use.

.

5.排行榜

有趣的部分来了。看着顶级艺术家的部分,我意识到一切似乎并不准确。如上所述,查理·加西亚塞鲁吉兰都不见了。此外,在热门歌曲中,有 3 首属于马丁·奥利弗的第二张专辑,这张专辑在 4 月份发行时我非常喜欢。CirrusfromBonobo,我在一月和二月每天都在重复收听。事实上,我知道今年我最着迷的曲目是安德森的《色彩》。帕克和肯德里克·拉马尔——我的天啊多么有感染力的节拍。当然色彩也无处可寻。

我们不会进入流派,因为我真的不太相信它们。一个和另一个之间的界限变得如此模糊和武断,我有点看不到这一点。我只想说:“墨西哥人?那是什么意思?”

顶级艺人

Spotify 榜单如下:荷西·德克勒、电台司令、北极猴子、吸血鬼周末、古斯塔沃·塞拉蒂

df[df.date < '2018-12-01'].groupby(by=['artist']).agg('count')['track'].sort_values(ascending=False)[:10]

I knew it.

真的很有趣。北极猴电台司令倒相差 20 首(可以接受,也许?).塞鲁吉兰和查理·加西亚怎么样了?!

首先, scrobble 是 Last.fm 发明的一个术语,用来描述你听的歌曲的日志。一个 scrobble 每复制一首歌。

从图表中我们可以清楚地看到,在这一年的下半年有一个很大的增长。穿红色衣服的查理·加西亚在九月中旬大幅增加,而塞鲁吉兰则从十一月开始飙升。这与 Spotify 标记为顶级的其他艺术家相比如何?Spotify 的顶级艺术家是否会在某个时间范围内与现实相符?

首先,让我告诉你。那些艺人那个顺序在整个 2018 年都没有发生过。但是如果我们不顾顺序,只关心他们五个是顶级艺术家,会发生什么?

The possible ranges are between 2018-06-18 and 2018-06-19
The possible ranges are between 2018-08-07 and 2018-08-08
The possible ranges are between 2018-08-16 and 2018-11-16

这就是可能性域。如果 Spotify 顶级艺术家是在 6 月 16 日、8 月 7 日或 8 月 16 日和 11 月 16 日之间的 3 个月内计算的,那么不管顺序如何,他们都是可以的。这可能没问题,我们可以假设 Spotify 是在 11 月中旬计算出这个列表的。
让我们继续追踪报道。

df[df.date < '2018-12-01'].groupby(by=['title', 'artist']).agg('count')['track'].sort_values(ascending=False)[:20]

我就知道! Tints 是我的 2018 顶级曲目。另一方面,Spotify 表示,我最喜欢的 5 首歌曲依次是: Estocolmo (实际上是 17 首) Los días eternos (18 首) Cirrus (不在前 20 首)Black trecle(5 首)和 Shangai Safari (8 首)。这里发生了 WTF?

The possible ranges are between 2018-05-14 and 2018-05-21

Estocolmo and Los días eternos have exactly the same values everyday. Every time I listened to Martin Oliver’s album I did sequentially, so that probably explains it.

所有灰色线条都是我实际排名前 20 的歌曲,而不是 Spotify 的。Spotify 热门曲目出现的唯一时刻是在 5 月的一周,这是无视顺序的。回家 Spotify,你醉了!****

大错误

结论

我并没有从中吸取太多。有些东西真的很容易看到,比如他们是如何计算出顶级艺术家的,然后塞鲁吉兰查理加西亚可能会在我的前五名中占据重要地位。其他的东西是可以理解的,一点点的误差应该被原谅,比如我花在听荷西·德克勒和全球范围内我所有的音乐上的时间。但是有些东西基本上无法解释。
比如说
怎么了?其实并不是 2018 年我没有发现他们……也是我这辈子都没有听过他们的事实。

artist = pylast.Artist(“Faces”, network, username=’alexing10')
print(“Faces has %d scrobbles.” % artist.get_userplaycount())

面孔没有 0 个阴囊。

最大的谜团是顶部的轨道。那是怎么回事?怎么会差这么远?
我猜他们认为 Spotify Wrapped 是他们需要在 12 月前快速发布的产品,为了减少资源或计算时间,他们没有使用所有用户的收听历史,而是随机抽取一些样本并从中进行计算。总而言之,我不得不说这是非常草率的。

我仍然希望 Spotify 会把我在 GDPR 的数据反馈给我,或许那时我们会对这个谜有更多的了解。

有些见解我决定不去核实,一方面是因为很难做到,另一方面是因为我真的不相信它们。例如,Spotify 告诉我我最喜欢的子类别是“现代摇滚”。那是什么?比如,有没有一年可以作为一个枢纽?1992 年以前发行的摇滚专辑都不是现代摇滚?格里塔·范·弗利特是现代摇滚吗尽管他们所有的歌听起来都无耻地像 1973 年以前的齐柏林飞艇?

Why that song out of that album? It was all released in 1951.

Spotify 还告诉我我听过的最老的歌是的 T4 的录音,当然还有塞隆尼斯·蒙克的。我很确定他们没有得到我的剧本或者坦哥·雷恩哈特 30 年代和 40 年代的录音…或者任何古典作曲家的任何作品。肖邦的钢琴前奏曲出版于 1839 年,马尔塔·阿格里齐在 1977 年录制了它们的最终版本,Spotify 将它们收录在目录中的“翻唱”日期:2002 年。就这样…

明年的想法:与其花时间检查你听得最多的黄道星座(说真的,这他妈的是什么?);他们可以检查每个人的最佳专辑。那可能是个更好的主意。

再次,你可以在我的公众 github 账号查看数据库创建、数据分析、数据可视化的完整代码。

** [## alexing/spotify_rewrapped

Spotify 重新包装。通过在 GitHub 上创建一个帐户,为 alexing/spotify_rewrapped 开发做出贡献。

github.com](https://github.com/alexing/spotify_rewrapped)

附赠曲目

这是我 2018 年的顶级专辑:

You can check the full list here

而且,虽然远不准确,但这是我的 Spotify 2018 年前 100 名播放列表。我非常喜欢它。

非常感谢,新年快乐!****

Spotify 的“这是”播放列表:50 位主流艺术家的终极歌曲分析

原文:https://towardsdatascience.com/spotifys-this-is-playlists-the-ultimate-song-analysis-for-50-mainstream-artists-c569e41f8118?source=collection_archive---------3-----------------------

Source: http://www.shekclifestyle.com/home/2017/5/15/summer-playlist

每个艺术家都有自己独特的音乐风格。从献身于木吉他的艾德·希兰,到精通说唱艺术的德雷克。从能在流行歌曲中唱一些疯狂高音的阿黛尔,到在 DJ 台上创造 EDM 魔术的 Kygo。音乐是关于创造力、独创性、灵感和感情的,它是跨越差异连接人们的完美门户。

Spotify 是目前最大的音乐流媒体服务。拥有超过 3500 万首歌曲和 1.7 亿月活跃用户,是音乐人接触观众的理想平台。在该应用程序上,可以通过各种参数浏览或搜索音乐,如艺术家、专辑、流派、播放列表或唱片公司。用户可以创建、编辑和共享播放列表,在社交媒体上共享曲目,并与其他用户一起制作播放列表。

此外,Spotify 推出了各种为用户量身定制的有趣播放列表,其中我最欣赏以下三个:

  • 每周发现:每周生成的播放列表(每周一更新),为用户带来两个小时的定制音乐推荐,将用户的个人品味与类似听众喜欢的歌曲混合在一起。
  • 发布雷达:一个个性化的播放列表,允许用户了解他们最常听的艺术家发布的最新音乐。
  • 每日混音:一系列播放列表,具有“近乎无止境的回放”功能,将用户喜爱的曲目与新的推荐歌曲混合在一起。

我最近发现了‘这是”播放列表系列。Spotify 最好的原创功能之一,“这是”兑现了流媒体革命的一个主要承诺——将伟大艺术家的作品典藏起来,供后代发现和欣赏。

每张专辑都献给一位不同的传奇艺术家,记录了经典专辑的巅峰时刻。“这是:坎耶·韦斯特”。“这是:魔力红”。“这是:埃尔顿·约翰”。Spotify 提供了一条捷径,为我们提供了最伟大艺术家的最佳歌曲精选列表。

方法

这个项目的目的是分析 Spotify 上不同艺术家制作的音乐。重点将放在从广泛的流派中理清 50 位不同艺术家的音乐品味。在整个过程中,我还识别出不同的艺术家群体,他们有着相似的音乐风格。

在研究中,我将访问 Spotify Web API ,它提供来自 Spotify 音乐目录的数据。这可以通过对 API 端点的标准 HTTPS 请求来访问。

Spotify API 提供了每首歌曲的曲目信息,包括音频统计数据,如舞曲乐器节奏。每个特征测量一首歌曲的一个方面。关于每个功能如何计算的详细信息可以在 Spotify API 网站上找到。本文中的代码片段可能有点难以理解,尤其是对于数据初学者来说,所以请耐心等待。

下面是我的方法的简要总结:

  • 从 Spotify API 获取数据。
  • 处理数据以提取每个艺术家的音频特征。
  • 使用 D3.js 可视化数据。
  • 应用 k-means 聚类将艺术家分成不同的组。
  • 分析所有艺术家的每个特征。

现在让我们从 Spotify 上 50 位不同艺术家的“这是”播放列表中检索音频特征信息。

Source: https://blog.prototypr.io/have-you-heard-about-the-spotify-web-api-8e8d1dac9eaf

获取数据

第一步是在 API 网站中注册我的应用程序,并为将来的请求获取密钥(客户端 ID 和客户端秘密)。

Spotify Web API 使用不同的 URIs(统一资源标识符)来访问播放列表、艺术家或曲目信息。因此,获取数据的过程必须分为两个关键步骤:

  • 获取多个音乐家的“这是”播放列表系列。
  • 获取每位艺术家的播放列表曲目的音频功能。

Web API 凭据

首先,我为Client IDClient Secret凭证创建了两个变量。

spotifyKey <- "YOUR CLIEND ID"
spotifySecret <- "YOUR CLIENT SECRET"

之后,我请求一个访问令牌,以便授权我的应用程序检索和管理 Spotify 数据。

library(Rspotify)
library(httr)
library(jsonlite)

spotifyEndpoint <- oauth_endpoint(NULL, "https://accounts.spotify.com/authorize",
"https://accounts.spotify.com/api/token")spotifyToken <- spotifyOAuth("Spotify Analysis", spotifyKey, spotifySecret)

这是播放列表系列

第一步是拉艺术家们的“这是”系列是为每一个人拿到 URIs。以下是我选择的 50 位音乐家,以他们的受欢迎程度、现代感和多样性作为主要标准:

  • Pop :泰勒斯威夫特、爱莉安娜·格兰德、肖恩·蒙德兹、魔力红、阿黛尔、贾斯汀比伯、艾德·希兰、贾斯汀汀布莱克、查理·普斯、约翰·梅耶、洛德、第五和声、拉娜·德尔·雷、詹姆斯亚瑟、扎拉拉尔森、Pentatonix。
  • 嘻哈/说唱:肯德里克·拉马尔、波斯特·马龙、德雷克、坎耶·韦斯特、阿姆、未来、50 美分、李尔·韦恩、维兹·卡利法、史努比·道格、麦克摩尔、Jay-Z
  • 布鲁诺·马斯,碧昂斯,安立奎·伊格莱希亚斯,斯蒂维·旺德,约翰·传奇,艾丽西亚·凯斯,亚瑟,蕾哈娜。
  • EDM / House : Kygo,The Chainsmokers,Avicii,Marshmello,加尔文·哈里斯,马丁·盖瑞斯。
  • 摇滚:酷玩乐队,埃尔顿·约翰,一个共和国,剧本,杰森·玛耶兹。
  • 爵士乐:弗兰克·辛纳屈、迈克尔·布伯、诺拉·琼斯。

Source: http://www.thedrum.com/news/2017/11/29/spotify-wraps-up-2017-making-humorous-goals-2018-using-its-data-and-artists

我基本上是转到每个音乐家的个人播放列表,复制 URIs,将每个 URI 存储在一个. csv 文件中,并导入。csv 文件转换成 r。

library(readr)playlistURI <- read.csv("this-is-playlist-URI.csv", header = T, sep = ";")

对于每个播放列表 URI,我应用了“RSpotify”包中的getPlaylistSongs,并将播放列表信息存储在一个空的 data.frame 中

# Empty dataframe
PlaylistSongs <- data.frame(PlaylistID = character(),
                            Musician = character(),
                            tracks = character(),
                            id = character(),
                            popularity = integer(),
                            artist = character(),
                            artistId = character(),
                            album = character(),
                            albumId = character(),
                            stringsAsFactors=FALSE)# Getting each playlist
for (i in 1:nrow(playlistURI)) {
  i <- cbind(PlaylistID = as.factor(playlistURI[i,2]),
             Musician = as.factor(playlistURI[i,1]),
             getPlaylistSongs("spotify",
                              playlistid = as.factor(playlistURI[i,2]),
                              token=spotifyToken))
  PlaylistSongs <- rbind(PlaylistSongs, i)
}

音频功能

首先,我编写了一个公式(getFeatures),它提取任何特定 ID 的音频特征并存储为一个向量。

getFeatures <- function (vector_id, token) 
{
  link <- httr::GET(paste0("https://api.spotify.com/v1/audio-features/?ids=", 
  vector_id), httr::config(token = token))
  list <- httr::content(link)
  return(list)
}

接下来,我在另一个公式(get_features)中包含了getFeatures。后一个公式提取音轨 ID 向量的音频特征,并在 data.frame 中返回它们

get_features <- function (x) 
{
  getFeatures2 <- getFeatures(vector_id = x, token = spotifyToken)
  features_output <- do.call(rbind, lapply(getFeatures2$audio_features, data.frame, stringsAsFactors=FALSE))
}

使用上面创建的公式,我能够提取每个音轨的音频特征。为此,我需要一个包含每个曲目 ID 的向量。Spotify API 的速率限制是 100 首曲目,所以我决定为每位音乐家创建一个带有曲目 id 的向量。

接下来,我将get_features公式应用于每个向量,获得每个音乐家的音频特征。

之后我把每个音乐人的音频特征 data.frame 合并成一个新的,all_features。它包含每个音乐家的“这是”播放列表中所有曲目的音频功能。

library(gdata)all_features <- combine(TaylorSwift,ArianaGrande,KendrickLamar,ShawnMendes,Maroon5,
PostMalone,Kygo,TheChainsmokers,Adele,Drake,JustinBieber,Coldplay,
KanyeWest,BrunoMars,EdSheeran,Eminem,Beyonce,Avicii,Marshmello,
CalvinHarris,JustinTimberlake,FrankSinatra,CharliePuth,MichaelBuble,
MartinGarrix,EnriqueIglesias,JohnMayer,Future,EltonJohn,FiftyCent,
Lorde,LilWayne,WizKhalifa,FifthHarmony,LanaDelRay,NorahJones,
JamesArthur,OneRepublic,TheScript,StevieWonder,JasonMraz,JohnLegend,
Pentatonix,AliciaKeys,Usher,SnoopDogg,Macklemore,ZaraLarsson,JayZ,
Rihanna)

最后,我使用aggregate函数计算了每个音乐家的音频特征的平均值。所得的数据帧包含每个音乐家的音频特征,表示为他们各自播放列表中音轨的平均值。

mean_features <- aggregate(all_features[, c(1:11,17)], list(all_features$source), mean)names(mean_features) <- c("Musician", "danceability", "energy", "key", "loudness", "mode", "speechiness", "acousticness", "instrumentalness", "liveness", "valence", "tempo", "duration_ms")

下图是mean_features data.frame 的一个子集,供你参考。

音频功能描述

Spotify Web API 指南中可以找到每个功能的描述:

  • 可跳舞性:描述一个曲目是否适合跳舞。这是基于音乐元素的组合,包括速度、节奏稳定性、节拍强度和整体规律性。值 0.0 最不适合跳舞,1.0 最适合跳舞。
  • 能量:从 0.0 到 1.0 的度量,代表强度和活动性的感知度量。通常,高能轨道感觉起来很快,很响,很嘈杂。例如,死亡金属具有高能量,而巴赫前奏曲在音阶上得分较低。对该属性有贡献的感知特征包括动态范围、感知响度、音色、开始速率和一般熵。
  • :音轨所在的调。整数使用标准音高分类符号映射到音高。例如,0 = C,1 = C♯/D♭,2 = D,等等。
  • 响度:音轨的整体响度,单位为分贝(dB)。响度值是整个轨道的平均值,可用于比较轨道的相对响度。响度是声音的质量,是与体力(振幅)相关的主要心理因素。值的典型范围在-60 和 0 db 之间。
  • 调式:表示一个音轨的调式(大调或小调),其旋律内容来源的音阶类型。大调用 1 表示,小调用 0 表示。
  • 语速:语速检测音轨中是否存在口语单词。越是类似语音的录音(例如脱口秀、有声读物、诗歌),属性值就越接近 1.0。高于 0.66 的值描述可能完全由口语单词组成的轨道。介于 0.33 和 0.66 之间的值描述可能包含音乐和语音的轨道,可以是分段的,也可以是分层的,包括说唱音乐。低于 0.33 的值很可能代表器乐和其他非语音类曲目。
  • Acousticness :从 0.0 到 1.0 的音轨是否声学的置信度度量。1.0 表示音轨是声学的高置信度。
  • 乐器性:预测音轨是否不包含人声。“Ooh”和“aah”在这种情况下被视为乐器。Rap 或口语词轨道明显是“有声的”。乐器度值越接近 1.0,轨道不包含人声内容的可能性就越大。高于 0.5 的值旨在表示乐器轨道,但随着该值接近 1.0,置信度会更高。
  • 活跃度:检测录像中是否有观众。较高的活跃度值表示音轨被现场执行的概率增加。高于 0.8 的值表示该轨迹很有可能是实时的。
  • 效价:从 0.0 到 1.0 的一个量度,描述一首曲目所传达的音乐积极性。高价的音轨听起来更积极(例如快乐、愉快、欣快),而低价的音轨听起来更消极(例如悲伤、沮丧、生气)。
  • 速度:轨道的整体估计速度,单位为每分钟节拍数(BPM)。在音乐术语中,速度是给定作品的速度或节奏,直接来源于平均节拍持续时间。
  • Duration_ms :以毫秒为单位的音轨持续时间。

数据可视化

雷达图

雷达图有助于以更直观的方式比较这些音乐家的音乐氛围。第一个可视化是来自 chart.js JavaScript 库的 radar 图表的 R 实现,并评估了 10 位选定音乐家的音频特性。

为了绘图,我将调、响度、速度和持续时间毫秒值标准化为从 0 到 1。这有助于使图表更加清晰易读。

mean_features_norm <- cbind(mean_features[1], apply(mean_features[-1],2, function(x){(x-min(x))/diff(range(x))}))

好的,让我们以十个音乐家为一批来绘制这些交互式雷达图。当您将鼠标悬停在每条径向线上时,每个图表都会显示数据集标签,显示所选特性的值。下面的代码详细介绍了第一批十位音乐人的雷达图制作过程。其他四个批次的代码已被省略,但雷达图显示。

第一批:泰勒·斯威夫特、爱莉安娜·格兰德、肯德里克·拉马尔、肖恩·蒙德兹、魔力红、波斯特·马龙、基戈、链烟者、阿黛尔、德雷克

第二批:贾斯汀比伯、酷玩乐队、坎耶·韦斯特、布鲁诺·马斯、艾德·希兰、阿姆、碧昂斯、阿维西、马什梅洛、加尔文·哈里斯

第三批:贾斯汀·汀布莱克、弗兰克·辛纳屈、查理·普斯、迈克尔·布伯、马丁·盖瑞斯、安立奎·伊格莱希亚斯、约翰·梅耶、未来、埃尔顿·约翰、50 美分

第四批:洛德,李尔·韦恩,维兹·卡利法,第五和声,拉娜·德尔·雷,诺拉·琼斯,詹姆士·亚瑟,一个共和国,剧本,斯蒂维·旺德

第五批:杰森·玛耶兹、约翰·传奇、宾得尼克斯、艾丽西亚·凯斯、亚瑟、史努比·道格、麦克摩尔、莎拉·拉尔森、Jay-Z、蕾哈娜

聚类分析

另一种找出这些音乐家音乐曲目差异的方法是将他们分组。聚类算法的一般思想是根据数据的相似性将给定的数据集分成多个组。

在这种情况下,音乐家将根据他们的音乐偏好被分组到不同的集群中。与在查看数据之前定义群体不同,聚类让我能够找到并分析已经有机形成的音乐家群体。

在对数据进行聚类之前,重新调整数据集的数值变量非常重要。由于我有混合的数字数据,其中每个音频特征都与另一个不同,并且具有不同的测量值,因此运行 scale 函数(也称为 z 标准化)是一个给予它们同等权重的好做法。之后,我将音乐家作为行名,以便能够在情节中作为标签显示它们。

scaled.features <- scale(mean_features[-1])
rownames(scaled.features) <- mean_features$Musician

我应用了 K 均值聚类方法,这是无监督统计学习方法中最流行的技术之一。它用于未标记的数据。该算法在数据中寻找组,组的数量由变量 K 表示。该算法反复工作,根据所提供的变量将每个数据点分配给 K 个组中的一个。数据点基于相似性进行聚类。

在这种情况下,我选择了K = 6——可以根据我在选择艺术家时使用的六种不同流派(流行音乐、嘻哈音乐、节奏布鲁斯、EDM、摇滚和爵士乐)来形成聚类。

在我对每个音乐家应用 K-Means 算法后,我可以绘制出数据的二维视图。在第一个图中,x 轴和 y 轴分别对应于第一和第二主成分。特征向量(用红色箭头表示)表示每个变量对主成分的方向影响。

让我们来看看对我的数据集应用 K-Means 算法所得到的聚类。

在上图中可以看到,x 轴是 PC1 (30.24%) ,y 轴是 PC2 (16.54%) 。这是前两个主要部分。PCA 图显示,PC1 根据响度/能量对声学/醇厚度来区分艺术家,而 PC2 似乎根据化合价对音调、速度和乐器性来区分艺术家。

因为我的数据是多元的,所以检查所有的二元散点图是很繁琐的。相反,单个“汇总”散点图更方便。从数据中得出的前两个主要成分的散点图已显示在图表中。同样,百分比是由总体可变性的每个分量解释的方差:第一分量捕获了关于多元数据的 30.24%的信息,第二分量捕获了关于多元数据的 16.54%的信息。

如果你有兴趣了解这个算法背后的数学,我建议你温习一下主成分分析

让我们看看哪些艺术家属于哪些集群:

k_means$cluster

我还绘制了另一张雷达图,包含每个星团的特征。比较每个聚类创建的歌曲的属性是有用的。

集群 1 包含四个艺术家:酷玩乐队、阿维西、马什梅洛和马丁·盖瑞斯。他们的音乐大多是现场演奏和器乐演奏,通常声音洪亮,充满活力,节奏很快。这并不令人惊讶,因为四位艺术家中有三位表演 EDM / House 音乐,而 Coldplay 以他们的现场音乐会而闻名。

集群 2 包含两位艺术家:弗兰克·辛纳特拉和诺拉·琼斯(有爵士迷吗?).他们的音乐在声学和大调音阶调式上得分很高。然而,他们在其余所有属性上得分较低。典型的爵士乐。

集群 3 包含十位艺术家:波斯特马龙、凯戈、链烟者、阿黛尔、洛德、拉娜·德尔·雷、詹姆士亚瑟、一个共和国、约翰·传奇和艾丽西亚·凯斯。该集群在几乎所有属性上得分平均。这表明这一组艺术家在风格和创作方面是平衡的和多才多艺的,因此在这一组中呈现了流派的多样性(EDM,Pop,R & B)。

集群 4 包含 15 位艺术家:爱莉安娜·格兰德、魔力红、德雷克、贾斯汀比伯、布鲁诺·马斯、加尔文·哈里斯、查理·普斯、安立奎·伊格莱希亚斯、未来、维兹·卡利法、第五和声、亚瑟、麦克莫尔、扎拉·拉尔森和蕾哈娜。他们的音乐适合跳舞,声音洪亮,节奏快,充满活力。这个团体中有许多流行和嘻哈流派的年轻主流艺术家。

集群 5 包含 10 位艺术家:泰勒·斯威夫特、肖恩·蒙德兹、艾德·希兰、迈克尔·布雷、约翰·梅耶、埃尔顿·约翰、脚本、斯蒂维·旺德、杰森·玛耶兹和潘塔托尼克斯。这是我最喜欢的组合!泰勒·斯威夫特?艾德·希兰?约翰·梅耶?杰森·玛耶兹?埃尔顿·约翰?我想我听了很多创作型歌手的歌。他们的音乐大多是大调音阶,同时在所有其他属性上达到完美的平衡(平均分)。

集群 6 包含九位艺术家:肯德里克·拉马尔、坎耶·韦斯特、阿姆、碧昂斯、贾斯汀·汀布莱克、50 美分、李尔·韦恩、史努比·道格和 Jay-Z。你已经看到了这里的趋势:其中七位是说唱歌手,甚至碧昂斯和 JT 也经常与说唱歌手合作。他们的歌曲有大量的口语单词和类似演讲的部分,持续时间长,并且经常现场表演。对说唱音乐有更好的描述吗?

按特征分析

下面的图表显示了每个音乐家的每个特性的值。下面的代码详细说明了制作 danceability 分叉条形图的过程。其他特征的代码已被省略,但随后会显示每个特征的绘图。

可跳舞性

如果你想让你的迷恋者印象深刻,试着多听听未来,德雷克,维兹·卡利法,史努比杜古和阿姆。另一方面,不要试图跟着弗兰克·辛纳屈或拉娜·德尔·雷的曲子跳舞。

能量

如果你听很多马克斯梅洛、加尔文·哈里斯、安立奎·伊格莱希亚斯、马丁·盖瑞斯、阿姆、Jay-Z 的音乐,你就是一个相当精力充沛的人。如果你是弗兰克·辛纳特拉和诺拉·琼斯的粉丝,情况正好相反。

响度

响度排名和能量排名差不多。

语音

所有说唱乐迷:你最喜欢肯德里克·拉马尔的哪首歌?还是 50 美分?还是 Jay-Z?嗯,我很惊讶阿姆没有排名更高,因为我个人认为他是所有说唱歌手的山羊。

声音

声音与响度和能量正好相反。辛纳特拉先生和琼斯夫人在他们的职业生涯中发布了一些强有力的原声歌曲。

仪表化

EDM 为了胜利!马丁·盖瑞斯、Avicii 和 Marshmello 制作的歌曲几乎没有人声。

活跃度

那么表演现场录音最多的 5 位艺术家是谁呢?杰森·玛耶兹、酷玩乐队、马丁·盖瑞斯、坎耶·韦斯特和肯德里克·拉马尔,按此顺序。

化合价

配价是描述音轨所传达的音乐积极性的特征。布鲁诺·马斯、斯蒂维·旺德和安立奎·伊格莱希亚斯的音乐非常积极,而拉娜·德尔·雷、酷玩乐队和马丁·盖瑞斯的音乐听起来相当消极。

节奏

未来、马希梅洛和维兹·卡利法是速度之王。他们制作每分钟节拍数最高的曲目。还有史努比狗狗,lol?他往往需要一些时间来说出他的神奇的话。

持续时间

最后但并非最不重要的是,贾斯汀·汀布莱克的歌曲,其次是埃尔顿·约翰和阿姆的歌曲,有时长得令人难以忍受。相比之下,弗兰克·辛纳屈、莎拉·拉尔森和五弦琴喜欢较短的音乐。

结论

哇,我在 Spotify 数据上做这个分析和可视化项目时获得了很多乐趣。谁能想到詹姆斯·亚瑟和波斯特·马龙在一个集群里?还是说肯德里克·拉马尔是游戏里最快的说唱歌手?或者说马希梅洛会在制作充满活力的歌曲方面击败马丁·盖瑞斯?

无论如何,你可以在 my GitHub repository 这里查看完整的 R Markdown、用于处理和可视化数据的单独 R 代码以及原始数据集。从我自己的角度来看,R 在数据可视化方面比 Python 好得多,有像 ggplotplot.ly 这样的库。我强烈建议您尝试一下 R!

— —

如果你喜欢这首曲子,我希望你能按下鼓掌按钮👏这样别人可能会偶然发现它。你可以在 GitHub 上找到我自己的代码,在【https://jameskle.com/】上找到更多我的写作和项目。也可以在 推特 上关注我直接发邮件给我 或者 在 LinkedIn 上找我。 注册我的简讯 就在你的收件箱里接收我关于数据科学、机器学习和人工智能的最新想法吧!

使用电子商务监控解决方案通过双样本假设检验发现转换率下降

原文:https://towardsdatascience.com/spotting-conversion-rate-drop-with-two-sample-hypothesis-testing-using-e-commerce-monitoring-24542ada6122?source=collection_archive---------4-----------------------

简介

假设您有一个在线商店,您的客户必须完成一系列常见的步骤才能买东西:访问->添加到购物车->结帐->购买。假设一些客户在某个步骤卡住了,没有通过漏斗。假设你想知道这是不是因为一些技术问题。如果是,那么某个技术问题会在多大程度上影响您的收入变化?

前一段时间,我被要求帮助一家名为 Kuoll 的初创公司解决这样的问题,这是一个防止网上商店损失的电子商务监控解决方案。它估计 JavaScript 和 HTTP 错误等转换阻塞造成的损失,保留收入并控制变化。该团队改变了根据整个漏斗中每一步的转化率下降来衡量收入表现损失的问题。

转换率下降问题可以表述如下。假设有一些具体的电子商务错误,这是一个在你的网站购买漏斗的某个步骤的阻碍。让我们将用户分为两类:A 类用户和 B 类用户。A 类用户是在该步骤中没有遇到该特定拦截器的在线商店购物者,B 类用户是在同一步骤中遇到该特定拦截器的购物者。 N —类型为 AM 的用户总数——其中成功通过漏斗步骤的用户数(姑且称之为转化的用户)。 P —类型 BQ 的用户总数——其中转化的用户数。

问题:有没有因为这个特定的错误/拦截器导致转化率下降?

这个问题类似于经典的 A/B 测试问题。现在很流行。毫无疑问,使用双样本假设检验的模型种类繁多。我们测试了其中一些。这里需要注意的是,我们在某一点上卡住了。小观察数就是这种情况。它包括小样本量(其中 NP 不够大)和极端频率(其中比例 M/NQ/P 接近零或一)。我们习惯于谈论从海量数据中获取价值。但如果我们在没有足够数据的情况下不得不下结论呢?统计学的挑战性和艰巨性在于从有限的数据中得出一般性的结论。

双样本假设检验解决方案

为了更深入地研究数学,让我们记住下面的定义。

  • 一个 假设 是关于一个概率模型的陈述。
  • 一个 零假设 H₀ 是一个关于概率模型的特定陈述,可能会被拒绝。
  • 一个 替代假设 H₁ 是一组与原假设相矛盾的假设。
  • 统计 是可以从数据样本中计算出来的数值。
  • p 值 是假设零假设为真,观察到至少与实际观察到的一样极端的检验统计的概率。
  • 一个I 型错误 是当零假设为真时拒绝该假设。第一类错误的概率称为 测试的显著性 水平,表示为 α
  • 一个 第二类错误 当其为假时不拒绝零假设。第二类错误的概率称为 β ,但是 β 的值通常取决于哪个特定的替代假设为真。
  • 对于一个特定的备选假设,假设检验的 功效1-β,即拒绝一个特定的真备选假设的概率。

现在让我们考虑 2x2 列联表,其中一个二元变量由两行表示,另一个由两列表示:

其思路是使用 样本比例 p̂₁=a/mp̂₂=c/n 以便比较相应的未知 人口比例 p₁p₂ 。比较这些比例的传统策略是统计假设检验。它通常由以下步骤组成。

1.陈述了 null的替代假设
在零情况下(在零假设下),比例 p₁p₂ 之差为零,双侧检验比例为 1。在大多数文献中,在单侧检验的情况下,比例 p₁p₂ 的差也是零,但是一些假设“它大于(小于)零”并且比率“大于(小于)一”。我们将使用第二个变量来表示单侧检验的零假设。
在我们的案例中 H₀ : 错误/阻断器不会导致转换下降H₁ : 错误导致转换下降。数学上h₀:p₁p₂h₁:p₁>p₂

2.定义 置信区间 和对应的 显著性水平α(α)
如果原假设为真, α 为拒绝原假设的概率。

3.选择一个 测试统计 来运行您的测试/实验。
这里你应该决定比较两个比例 p₁p₂ 时要考虑哪个。比较这些量的常用方法是差值和比值。另一个常见的衡量标准是优势比。

4.然后应计算出 p 值

5.比较 p 值和 alpha。
如果 p 值小于α,则应拒绝零假设,否则不能拒绝。

6.力量* 分析。对于大样本,各种检验的功效大致相同。然而,对于小样本来说,功率的差异可能相当大。功效分析应在用于分析数据的测试统计数据上进行。因此,您必须比较各种测试的功效,以确定使用哪种测试。本文不涉及功耗分析。我们进行了实验,但我们对测试统计数据的选择主要是由于后面将讨论的比较研究。*

下面是一些测试和相应的测试统计数据的列表(这个例子应用于我们的数字),我们发现它们可以解决我们的问题。

两比例 Z-检验

无效假设和替代假设分别是:
h₀:
p₁p₂h₁:p₁>p₂

这里 p 值是使用 z 分布得到的。让我们考虑一些(还有很多)比例的差异、比率和优势比的 z 检验。

1)对于足够大的样本,比例差近似正态分布。两个比例之差的 z 值由以下公式给出

在给定数据的情况下, p 值为

我们可以使用 Python 代码作为计算该值的示例:

2)对于足够大的样本,比例比的对数近似呈正态分布。用于检验比率是否等于 1:

在哪里

在带有数字 M、N、PQ 的情况下, p 值为:

计算该值的 Python 代码:

3)对于足够大的样本,比例比值比的对数近似呈正态分布。检验比值比是否等于 1 的检验统计量:

在哪里

在有数字 M、N、PQ 的情况下, p 值为:

计算该值的 Python 代码:

还有一个测试统计的修正版本,其中 z 乘以

两个比例之差的方差不等的双样本 t 检验

无效假设和替代假设分别是:
h₀:p₁p₂h₁:p₁>p₂

这里我们考虑 t 分布

有自由度的

在我们的例子中

****

p 值为

这种概率是使用带自由度的 1 尾 t 分布得到的

计算该值的 Python 代码:

费雪精确测验(中 P 版)

无效假设和替代假设分别是:
h₀:p₁p₂h₁:p₁>p₂

该测试使用超几何分布。Fisher 精确检验的 p 值是通过求和超几何概率来计算的。让我们考虑 2x2 表提供的给定数字:

以下是其他表格,在“有误差的转换”的比例上有更大的差异,但边际总数相同:

其中 x 介于 0 和 Q 之间。p 值是每个表的概率之和,其中只包括观察表概率的一半:

计算该值的 Python 代码:

二项式检验

无效假设和替代假设分别是:
h₀:p₁p₂h₁:p₁>p₂

在这种情况下,假设:
(1)某总体概率 p0=M/N (类似地,我们可以使用 Q/P )。
②下 H₀x∾binomial(p,p₀)。所以在从总体中随机抽取的 P 个样本中,如果有 X 个正面结果,那么 p₂=X/P 就是样本比例。
我们观察到 Q 的正计数,因此 p 的值为

计算该值的 Python 代码(我们使用了 Fisher 精确测试中观察值的一半概率):

应该注意的是,有一些测试我们没有使用,因为它们是双面的。如果我们想知道是否有因特定阻断剂引起的转换率变化,我们可以使用它们。这些测试是:

卡方独立性检验

无效假设和替代假设是
H₀ : 数据来自特定的离散分布
H₁ : 数据来自不同的分布

该测试的测试统计数据为

其中
Oij —第 i 行和第 j 列对应的观察计数;

—对应于行 i 和列 j. 的预期计数

考虑到我们的 2x2 表,在提供测试统计数据的情况下,计算出 p

而且对应的是 1 个自由度的 Chi 平方分布。

计算该值的 Python 代码:

【似然比检验】

无效假设和替代假设是h₀:数据来自特定的离散分布
H₁ : 数据来自不同的分布

这个测试是似然比测试的一个例子。在 rxc 表的一般情况下, G 测试的测试统计为

其中
Oij-对应于行 i 和列 j 的观察计数;

—对应于行 i 和列 j. 的预期计数

假设零假设为真并且 n 足够大,该测试统计具有一个近似的卡方分布,具有 (r-1)(c-1) 个自由度。
在我们的案例测试统计中:

p-值是在考虑 LR 具有一个自由度的近似卡方分布的情况下得到的。**

计算该值的 Python 代码:

讨论

自从 1900 年以来,一直有很多关于解决 2 x2 T1 桌子问题的争论。在这个问题上仍然没有达成共识。下面是一个简短的回顾,它引导我们找到了自己的解决方案。

测试假设的传统方法(用于测量差异)是对大样本使用皮尔逊卡方检验(或z-单侧检验情况下的比例差异检验),对中间样本大小使用耶茨卡方检验(具有连续性校正),对小样本使用费希尔精确检验。一些科学家已经开始质疑这个解决方案。例如,一些人认为费希尔精确检验和耶茨检验不应该使用[3]。

E.Pearson 推荐了他的卡方检验的一个版本,其中将表达式(ad BC)2(n1)/mnrs(参见原始的 2x2 表)与具有一个自由度的卡方分布进行比较,即与原始分布相差因子(n1)/N。对于大样本量,与原始版本的差异很小,但在小样本量的分析中,这种差异变得至关重要[2]。

当卡方检验在小样本情况下无效时的标准通常基于零假设下的最小期望细胞数,其等于(mm和 NN中的较小者)乘以(rrs ) /N 中的较小者)。大多数建议是,如果最小预期数小于 5,则不应使用卡方检验。这条规则通常被认为是科克伦的。他指出,数字 5 似乎是随意选择的,当有新的证据时,这些建议可能需要修改。[2]但这反而成了一种普遍的做法。

当基线比例很小(接近 0)或很大(接近 1)时,比率度量通常优于差异,因为它将差异表示为百分比而不是数量。

在极端情况下, 2x2 表格的某些单元格为零,需要特殊的方法。在这里,我们可以使用 Fisher 精确检验、二进制检验,或者将零改为一个小的正数,如 0.01。

I.Campbell (2007)在论文中提出的比较研究和论证数据提供了一组令人信服的证据,表明在分析 2×2 表时,就 I 型误差和功效而言(研究中考虑了双边检验)[2]:

(1)当所有预期数字至少为 1 时,通过'n1'卡方检验进行分析(K. Pearson 卡方检验,但用n1代替n1)

(2)否则,通过 Fisher–Irwin 检验进行分析,根据 Irwin 规则进行双边检验(根据观察结果尽可能或尽可能少地从任一尾部获取表格)。

我们的解决方案

我们对上述测试统计数据进行了实验,在我们为客户提供的报告框架内对结果进行了比较,并决定采用 I.Campbell 的研究并对其进行修改,以进行单侧测试。

我们选择测试统计的规则是:

(1)在所有预期数至少为 1 的情况下,我们通过'N*-1 ' z 检验来分析比例差异
)这里我们找到最小预期数,即
min(M+Q,N+P-(M+Q))min(N,P)/(N+P)
,并将其与 1 进行比较

(2)否则,我们通过 Fisher–Irwin 检验(单侧检验的中间 P 版本)进行分析

应该提到的是,我们决定报告 p 值,而不是在假设检验中做出是/否的决定,因为我们希望向我们的客户展示证据的力度,而不是做出正式的决定。假设检验由以下步骤组成:

1.陈述无效假设和替代假设(h₀:p₁p₂h₁:p₁>p₂);

2.计算检验统计量(根据每种类型的观察值的样本大小,使用上述规则选择正确的检验);

3.计算一个p-值;

4.解释并报告结果。

进一步研究

我们决定将问题扩展到这样一种情况,即不是单独考虑每个阻碍因素,而是考虑一组影响转化率下降的阻碍因素。

结论

乔治·博克斯:“所有的模型都是错误的,但有些是有用的”。

指称

  1. https://OCW . MIT . edu/courses/mathematics/18-05-introduction-to-probability and-statistics-spring-2014/readings/MIT 18 _ 05s 14 _ reading 19 . pdf
  2. https://onlinelibrary.wiley.com/doi/pdf/10.1002/sim.2832http://www.iancampbell.co.uk/twobytwo/twobytwo.htm
  3. https://NCSs-wpengine . net DNA-SSL . com/WP-content/themes/NCSs/pdf/Procedures/ncss/Two _ proportions . pdf,NCSS 文档。
    https://www.ncss.com/software/ncss/ncss-documentation/NCSS 文档主页提供了大量的统计理论资源
  4. Bret Hanlon 和 Bret Larget 的课堂笔记可在http://www.stat.wisc.edu/~st571-1/获得
  5. 维基百科资源:
    https://en.wikipedia.org/wiki/Binomial_test https://en.wikipedia.org/wiki/Fisher%27s_exact_test https://en.wikipedia.org/wiki/Z-test https://en.wikipedia.org/wiki/Student%27s_t-test https://en.wikipedia.org/wiki/Likelihood-ratio_test https://en.wikipedia.org/wiki/Chi-squared_test

冲刺可视化轨道(第 1 部分):Matplotlib

原文:https://towardsdatascience.com/sprinting-into-the-visualization-track-part-1-matplotlib-6c069ac91e40?source=collection_archive---------6-----------------------

“A race on the running track at Anglo-Chinese School in Singapore” by Goh Rhy Yan on Unsplash

我们已经用 DataFrame 走了很久,

[## 开始走数据科学之路(下) :熊猫数据框架

在第 1 部分中,我们开始走这条路,一路上,我们遇到了系列。

towardsdatascience.com](/beginning-to-walk-the-data-science-road-part-2-pandas-dataframe-c3e898499d90)

并获得了相当大的势头。现在,我们准备开始冲刺。在这篇文章中,我们将开始研究可视化。到目前为止,我们看到的都是数字,文本,数组。无聊的东西。可视化是我们可以更好地交流我们的发现的方法。在这篇文章中,我们将看看可能是最流行的可视化库— Matplotlib 。特别是,我们将使用 Matplotlib 库中的 pyplot 模块。

一如既往,我们将寻求解决问题。首先,我们来看一个在图像处理中使用的著名图像——Lenna 图像。之后,我们将使用温度变化数据集在 pyplot 上再玩一些。

这篇文章的完整代码可以在下面的资源库中找到。

** [## bajracharya-kshitij/matplotlib

边解题边探索 matplotlib。为 bajracharya-kshitij/matplotlib 开发做出贡献,创建一个…

github.com](https://github.com/bajracharya-kshitij/matplotlib)

重要的事情先来。使用 anaconda 和 Python 3 安装 matplotlib。之后,导入 pyplot 模块。

import matplotlib.pyplot as plt

问题 1

Lenna 图像是图像处理中广泛使用的测试图像。

a)找出其广泛使用背后的原因。调查一下它有什么特别之处。

b)为图像的 RGB 值创建堆叠直方图。

c)表示饼图中(50,100)处像素的 RGB 值。

d)表示饼图中(100,100)处像素的 RGB 值。这个饼状图有什么不寻常的地方?

e)生成该图像的负片。

解决方案 1

快速的谷歌搜索应该会显示 Lenna 图片的结果。原图可以在这里找到,是 512x512 的 tif 图像。在这篇文章中,我将使用在这个链接中找到的图像,这是一个 220x220 的 png 图像。

注意:

关于这一形象的使用一直存在一些争议。但是用于测试的图像的裁剪版本对于工作是安全的。

让我们使用imread来读取图像lenna.png

img = plt.imread('lenna.png')

如果你现在打印img,你会看到它是一个 3D 数组,每个条目的值在 0 和 1 之间。其他图像没有必要具有介于 0 和 1 之间的条目。例如,原始 tif 具有 0 到 255 之间的条目;只有我们选择的图像的值在 0 和 1 之间。然而,所有的 2D 图像都会形成一个 3D 阵列。如果你检查img.shape,你会得到(220,220,3),表明这是一个三维数组。前两个维度代表图像的维度。但是最后那个3代表什么?

lenna 图像有 3 个颜色通道—红色( R )、绿色( G )和蓝色( B )。3代表这三个颜色通道。因此,前两个维度给出一个像素,最后一个给出该像素的 3 个颜色通道的值。为了更清楚起见,img[0][0][0]给出了第一个像素的 R 通道的像素值,img[219][219][2]给出了最后一个像素的 B 通道的像素值,所有剩余像素也是如此。

让我们现在显示图像。为此,我们使用imshow

plt.imshow(img)

然而,单独这样做,我们会在结果中看到类似这样的内容。

<matplotlib.image.AxesImage at 0x119434fd0>

为了显示图像,我们需要使用plt.show(),之后我们将看到下图

如果你使用的不是 Jupyter 笔记本,每次你需要显示一个图形时,你都必须使用plt.show()。幸运的是,Jupyter 笔记本有一个魔法函数,你可以用它来显示图像,而不需要每次都调用 show 函数。你需要做的就是添加下面一行。

%matplotlib inline

然后你可以简单地使用plt.imshow(img),它将返回图像。

那么,这张图片有什么特别之处呢?

为了理解这一点,让我们生成此图像的灰度版本。为此,首先我们将原始图像复制到一个新的 NumPy 数组中,并找到 3 个颜色通道的平均值。

import numpy as np
img_gray = np.copy(img)
img_gray[:] = img.mean(axis=-1,keepdims=1)

这将为每个像素在 3 个条目的每一个中放置平均值。这里,axis=-1将取最里面的轴,即每个像素的所有 3 个值,并求其平均值。当我们这样做的时候,其中一个维度被删除,得到的数组将是 2D。但是,我们希望通过用平均值替换三个值中的每一个来保留一个像素的所有三个值。这可以通过保留原始数组的尺寸的keepdims=1来实现。现在,plt.imshow(img_gray)将显示如下图像。

灰度图像的形状仍然保持(220,220,3)。让我们把它弄平,这样我们就可以在一个维度上得到所有的像素值。我们reshape它来获取像素值。

pixels = img_gray.reshape(220*220*3)

所以,pixels.shape现在返回(145200,)。现在我们有了平面阵列中的所有像素,让我们为这些像素值绘制一个直方图。

plt.hist(pixels,bins=255)

hist函数将所有像素值作为第一个参数。它还需要一个我们设置为 255 的bin参数。

什么是垃圾箱?

为了更好地解释直方图和条柱,请查看此链接

当您运行上面包含hist函数的代码块时,它返回两个数组。第一个数组的前 5 个条目如下所示:

6.,     0.,     0.,     9.,     6.

第二个数组如下所示:

0.12679739,  0.12989876,  0.13300014,  0.13610151,  0.13920288

那么,这些数字是什么?如果仔细观察,您会发现两个数组都有 256 个条目,比我们在bins中设置的多一个。现在,如果你生成一个线性间隔的数组,比如

np.linspace(pixels.min(),pixels.max(),256)

它将生成与上面第二个数组完全相同的数组。因此,bins正在做的是,从像素阵列中获取最小和最大值,生成 256 个线性间隔的数字,然后创建块(其中 255 个)。因此,第一个块将具有范围0.12679739-0.12989876,第二个块将具有范围0.12989876-0.13300014,以此类推,直到上限等于pixels.max()的最后一个块。那么第一个数组呢?嗯,它是值落在相应块内的频率。因此,有 6 个像素的值落在第一个范围内,9 个像素的值落在第四个范围内,依此类推。为什么是 256?你可以选择任何你喜欢的数字。我选择 256 是因为这是一个很好的数字,因为在灰度图像中有 256 种不同的亮度。如果没有为bins提供值,缺省值是 10。

使用这些值,hist函数将生成一个如下所示的直方图

从图中可以看出,lenna 图像几乎覆盖了整个面元范围。几乎每个箱都有强度值。正如在这个链接中提到的,Lenna 图像包含了细节、平坦区域、阴影和纹理的良好混合,可以很好地测试各种图像处理算法。这就是该图像被视为标准测试图像的原因。

现在,让我们分别看看每个颜色通道。我们在单独的数组中提取对应于每种颜色的像素。

img_r = img[:,:,0]
img_g = img[:,:,1]
img_b = img[:,:,2]

如果你检查这些数组的shape,你会得到(220,220)。所以我们现在有三个 2D 阵列。像前面一样,让我们为这三个元素创建一个平面一维数组。

img_r_pixels = img_r.reshape(220*220)
img_g_pixels = img_g.reshape(220*220)
img_b_pixels = img_b.reshape(220*220)

现在,我想看看这三个像素的亮度是如何分布的。如果所有的颜色都可以并排比较就好了。我们可以使用subplot来做到这一点。

plt.subplot(1,3,1)
plt.hist(img_r_pixels,bins=100)plt.subplot(1,3,2)
plt.hist(img_g_pixels,bins=100)plt.subplot(1,3,3)
plt.hist(img_b_pixels,bins=100)

如果你用过 MATLAB,你可能对支线剧情很熟悉。subplot函数有三个参数——第一个是行数,第二个是列数,第三个是索引号。然后对于plt.subplot(1,3,2)上面的第二个支线剧情表示我们要取剧情,把它分成 1×3 的格子,这样一共 3 个支线剧情都是可能的,然后我们要用第 2 个支线剧情。之后,我们用plt.hist(img_g_pixels,bins=100)绘制绿色像素的直方图。这里我们用bins=100。同样,您可以使用任何您喜欢的数字。或者直接跳过。

然后我们有这样的东西:

但这看起来不太好。这些地块非常拥挤,纵轴上的数字相互重叠。让我们在结尾加上plt.tight_layout()让它更漂亮一点,就像

plt.subplot(1,3,1)
plt.hist(img_r_pixels,bins=100)plt.subplot(1,3,2)
plt.hist(img_g_pixels,bins=100)plt.subplot(1,3,3)
plt.hist(img_b_pixels,bins=100)plt.tight_layout()

很好。我们还可以使用hist函数中的histtype参数来生成不同类型的直方图。现在,直方图在宽度方向上看起来仍然有点拥挤;这个数字比我们想要的要小得多。所以,让我们用plt.figure来设置支线剧情的大小。

plt.figure(figsize=(15,5))
plt.subplot(1,3,1)
plt.hist(img_r_pixels,bins=100,histtype='barstacked')plt.subplot(1,3,2)
plt.hist(img_g_pixels,bins=100,histtype='step')plt.subplot(1,3,3)
plt.hist(img_b_pixels,bins=100,histtype='stepfilled')plt.tight_layout()

figsize将元组作为参数—元组的第一个条目是宽度,第二个条目是高度,以英寸为单位。我们可以将这些值更改为最适合该图的值。对于上面的例子,我们现在有一个类似于

好多了。现在,只有 3 种颜色,但还是让我们通过给这些图添加颜色来使它更清晰。

plt.figure(figsize=(15,5))
plt.subplot(1,3,1)
plt.hist(img_r_pixels,bins=100,histtype='barstacked',color='r')plt.subplot(1,3,2)
plt.hist(img_g_pixels,bins=100,histtype='step',color='g')plt.subplot(1,3,3)
plt.hist(img_b_pixels,bins=100,histtype='stepfilled',color='b')plt.tight_layout()

接下来,让我们标记坐标轴,并给每个支线剧情一个标题。使用xlabelylabel作为轴,使用title作为子剧情标题。

plt.figure(figsize=(15,5))
plt.subplot(1,3,1)
plt.hist(img_r_pixels,bins=100,histtype='barstacked',color='r')
plt.title('Histogram for Red Pixels')
plt.xlabel('Pixel Intensity')
plt.ylabel('Frequency')plt.subplot(1,3,2)
plt.hist(img_g_pixels,bins=100,histtype='step',color='g')
plt.title('Histogram for Green Pixels')
plt.xlabel('Pixel Intensity')
plt.ylabel('Frequency')plt.subplot(1,3,3)
plt.hist(img_b_pixels,bins=100,histtype='stepfilled',color='b')
plt.title('Histogram for Blue Pixels')
plt.xlabel('Pixel Intensity')
plt.ylabel('Frequency')plt.tight_layout()

最后,让我们把这三个支线剧情叠加成一个

colors = ['red','green','blue']
plt.hist([img_r_pixels,img_g_pixels,img_b_pixels],bins=100,stacked=True,color=colors,normed=1)
plt.title('Stacked Histogram')
plt.xlabel('Pixel Intensity')
plt.ylabel('Frequency')

这里,hist接受一个像素值数组,这个数组的每个元素都用color参数赋予适当的颜色。stacked=True创建堆积直方图。由于 3 个颜色通道具有不同的频率范围,如单独的子图所示,我们使用normed=1标准化直方图。

使用normed=1,强度值将以这样一种方式绘制,即强度值和相应箱宽度的乘积总和等于 1。有关normed的更多信息,请参见此链接

在我们的例子中,如果我们设定

x = plt.hist([img_r_pixels,img_g_pixels,img_b_pixels],bins=100,stacked=True,color=colors,normed=1)

打印出 x,我们将看到它返回一个元组—第一个元素是每种颜色的像素强度数组,第二个元素是 bin 大小数组。我们将把它设置为

r = x[0][0]
g = x[0][1]
b = x[0][2]
bins = x[1]

如果我们检查每一个的尺寸(像r.size,我们会看到rgb的尺寸是 100,而bins的尺寸是 101 (100 个间隔)。然后,如果我们找到总和,

def getSum(frequency_array, bins_array):
    _sum = 0
    for i in range(frequency_array.size):
        _sum += frequency_array[i] * (bins_array[i+1]-bins_array[i])
    return _sum

print("red px: ", getSum(r,bins))
print("green px: ", getSum(g,bins))
print("blue px: ", getSum(b,bins))

我们会回来的

red px:  0.333333333333
green px:  0.666666666667
blue px:  1.0

显示总和为 1,因此强度已经被归一化。

只有直方图?pyplot 能做的就这些吗?

我们已经看到了很多使用直方图的东西。但这只是 pyplot 可以生成的各种图之一。查看官方 matplotlib 网站中的图库页面,查看可以使用 pyplot 绘制的所有各种类型的绘图。现在,让我们转移到一些其他类型的情节。

接下来,让我们看看饼状图。让我们取(50,100)处的一个像素,并找出该像素处的主色。

intensities = img[50][100]

intensities给出一个类似于

array([0.8745098 , 0.7058824 , 0.64705884], dtype=float32)

因此,在(50,100)处,3 种颜色有 3 个强度值。要绘制一个代表该像素亮度的饼图,我们需要做的就是

plt.pie(intensities)

饼状图将被绘制成

但目前看起来不太好看。第一,它不是一个规则的圆。让我们解决这个问题。

plt.pie(intensities)
plt.axis('equal')

好多了。现在,我们不能真正区分哪个部分代表哪个颜色。请注意,这个饼图中的蓝色和绿色不一定表示蓝色和绿色部分。这只是 pyplot 分配的 3 种默认颜色。所以,让我们给馅饼添加一些更多的信息。

colors = ['red', 'green', 'blue']
explode = (0, 0.1, 0)
plt.pie(intensities,labels=colors,colors=colors,autopct='%1.2f%%',explode=explode)
plt.axis('equal')

好多了。plt.pie这里以intensities数组为数据。它使用colors数组将labelscolors应用于截面。autopct=’%1.2f%%’格式化区段的百分比,对于explode参数,它只是从圆形饼图中分离出一个区段。我们将explode=(0,0.1,0)定义为我们想要将第二个元素(绿色元素)分解 0.1。如上图所示,绿色部分已被分离。因此,从这个饼图中我们可以看到,在 pixel (50,100)处,像素值几乎相似,但红色比其他两个略占优势。

让我们再次做同样的事情;这次是像素(100,100)。

intensities2 = img[100][100]
print(intensities2)
colors = ['red', 'green', 'blue']
plt.pie(intensities2,autopct='%1.2f%%',labels=colors,colors=colors)
plt.axis('equal')

太奇怪了。它看起来不像普通的馅饼。如果你把各部分加起来,它甚至不是 100%。那么,为什么会这样呢?如果你看看文件,你会发现

每个楔形的分数面积由x/sum(x)给出。如果sum(x) < 1,那么 x 的值直接给出分数面积,数组不会被归一化。生成的饼图将有一个大小为1 - sum(x)的空楔形区

如果你打印出intensities2,你会得到

array([0.34509805, 0.07843138, 0.24705882], dtype=float32)

的确,如果你把它们都加起来,总和在 1 以下。这就是为什么数组没有被规范化,并且有一个空的楔形,一个空的部分覆盖了大约 33%的饼图。

现在,要生成图像的负片,我们只需要从 255 减去原始亮度值。

plt.imshow(255-img)

就这么简单。但是让我们来硬的,看看会发生什么。首先,我们为 3 个颜色通道中的每一个通道生成一个反向像素阵列。

img_r_pixels_inv = 255 - img_r_pixels
img_g_pixels_inv = 255 - img_g_pixels
img_b_pixels_inv = 255 - img_b_pixels

然后我们把这些组合成一个数组。

pixels_inv = np.append(img_r_pixels_inv,(np.append(img_g_pixels_inv,img_b_pixels_inv)))

我们一个接一个地为每种颜色添加像素,现在如果我们检查pixel_invshape,我们将得到(145200,)即 2202203。接下来我们reshape将这些像素还原到原始的三维空间并绘制图像。

img_inv = pixels_inv.reshape(220,220,3)
plt.imshow(img_inv)

这很有趣,但这不是我们想要的形象。为什么会这样?如果你检查255-imgimg_inv,你会发现它们是两个不同的数组。原因是在后一种方法中,我们首先堆叠所有的 R 像素,然后是 G 像素,最后是 B 像素。我们应该做的是取第一个 R 像素、第一个 G 像素和第一个 B 像素,它们将形成数组的第一个分量,并对所有像素重复同样的操作。

让我们试试别的东西。让我们首先用全零初始化一个(220,220,3)数组img_inv。然后,我们为 3 个通道中的每一个找到逆像素。我们使用两个循环,找到每个颜色通道的i*j像素的倒数。

img_inv = np.zeros((220,220,3))
for i in range(220):
    for j in range(220):
        img_inv[i][j][0] = 255 - img_r_pixels[i*j]
        img_inv[i][j][1] = 255 - img_g_pixels[i*j]
        img_inv[i][j][2] = 255 - img_b_pixels[i*j]

现在,如果我们检查img_inv,我们将得到一个看起来像这样的图像

那确实是一件很好的艺术品,但不是我们想要的。然而,我们可以看到,这可以用来如果你想加密你的图像。当然,这是一种非常幼稚的加密方法,但如果你愿意,你也可以这样做。

上面的方法行不通,因为我们不想要第i*j个像素;我们想要第[i][j]个像素。让我们最终做到这一点。

img_inv = np.zeros((220,220,3))
for i in range(220):
    for j in range(220):
        img_inv[i][j][0] = 255 - img_r[i][j]
        img_inv[i][j][1] = 255 - img_g[i][j]
        img_inv[i][j][2] = 255 - img_b[i][j]

最后,我们在img_inv中有了我们需要的负像。

让我们使用savefig将该图像保存为一个新文件。

plt.axis('off')
plt.savefig('lenna_negative.png',dpi=300)

plt.axis('off')从图像中删除轴和标签。savefig的第一个参数是文件名,而dpi定义了我们希望图像拥有的每英寸点数。

图像将保存在记事本所在的文件夹中。您可以提供一个不同的路径来将其保存在您想要的位置。

所以,pyplot 只对图像起作用?

不,绝对不行。这只是一个应用。事实上,大多数时候,我们会处理文本数据。就像我们接下来要看的一样。

现在,让我们离开图像。在本节中,我们将使用温度变化数据集,通过 pyplot 探索更多的曲线图。

问题 2

给定来自Kaggle上此链接的 globallandtemperaturesbycount . CSV 数据集,使用 1960 年至 2009 年期间的数据

a)显示尼泊尔的年气温

b)比较美国、英国和中国的年气温

c)从(b)中找出温度的平均值和范围

解决方案 2

数据集在一个 csv 文件GlobalLandTemperaturesByCountry.csv中,所以让我们首先使用 pandas 来读取它。

import pandas as pd
df = pd.read_csv('GlobalLandTemperaturesByCountry.csv')

如果我们检查这个数据帧的info,我们会看到它有 4 列— dt即日期、AverageTemperatureAverageTemperatureUncertaintyCountry。您可以使用headtail查看更多信息,它列出了从 1743 年到 2013 年所有国家的月平均气温。一些月份的数据丢失了。很难看到所有这些数据,所以让我们只看一个特定的国家。在这里,我们看看尼泊尔。

df_nepal = df[df['Country']=='Nepal']

现在,我们只有df_nepal中尼泊尔的条目。如果我们检查info,我们看到它仍然有 2613 个条目。我们不想要 18 世纪的数据。此外,很多 20 世纪以前的数据都丢失了。所以,让我们来看看从 1960 年初到 2009 年底的 50 年间的数据。

df_nepal = df_nepal[(df_nepal['dt'] >= '1960-01-01') & (df_nepal['dt'] < '2010-01-01')]

因此,我们过滤掉数据,只剩下 600 个条目。现在我们有 50 年的月平均气温。让我们把它改成年平均温度。

start_year = 1960
year = np.zeros(50)
avg_temp = np.zeros(50)
for i in range(0,df_nepal.shape[0],12):
    new_df_index = int(((i+12)/12)) - 1
    year[new_df_index] = start_year + new_df_index
    avg_temp[new_df_index] = np.mean(
                      [df_nepal.iloc[i:i+12]['AverageTemperature']])
df_nepal_annual = pd.DataFrame([],columns=['year','avg_temp'])
df_nepal_annual['year'] = year
df_nepal_annual['avg_temp'] = avg_temp

我们从start_year = 1960开始,设置yearavg_temp保存 50 年及其各自的年平均温度,并暂时将其设置为全零。接下来,我们遍历 600 个条目,其中 600 由df_nepal.shape[0]给出,我们采取 12 的步骤,以便每 12 个条目被分组在一起,并且结果由new_df_index给出的单个索引来表示。使用此new_df_index,条目被追加到yearavg_temp中。对于avg_temp中的每个条目,取连续 12 行的平均值,并设置为当年的年平均温度。最后,创建一个新的数据帧df_nepal_annual,并将yearavg_temp的更新数组设置到该数据帧的列中。

如果我们现在检查df_nepal_annual,这个数据帧中正好有 50 个条目,只有两列——year 和 avg_temp。我们现在可以绘制 avg_temp 对应的年份

plt.plot(df_nepal_annual['year'],df_nepal_annual['avg_temp'])

以获得以下情节。

我们可以看到,在过去的半个世纪里,尼泊尔的气温一直在稳步上升。

现在,我们想将同样的概念扩展到绘制其他国家的温度。这里,我们来看看三个国家——美国、英国和中国。因为我们将对所有国家做同样的事情,所以让我们把上面的代码放到函数中。

def getDataForCountry(df,countryName):
    df_country = df[df['Country']==countryName]
    return df_country[(df_country['dt'] >= '1960-01-01') &   (df_country['dt'] < '2010-01-01')]

getDataForCountry提取 1960 年至 2009 年(含)50 年间的数据。

让我们定义另一个函数来计算年平均温度。

def getAvgTempByYear(df):
    start_year = 1960
    year = np.zeros(50)
    avg_temp = np.zeros(50)
    for i in range(0,df.shape[0],12):
        new_df_index = int(((i+12)/12)) - 1
        year[new_df_index] = start_year + new_df_index
        avg_temp[new_df_index] = np.mean([df.iloc[i:i+12]['AverageTemperature']])
    df_annual = pd.DataFrame([],columns=['year','avg_temp'])
    df_annual['year'] = year
    df_annual['avg_temp'] = avg_temp
    return df_annual

现在,使用这个函数getAvgTempByYear,我们可以对所有三个国家进行计算。为了更好地进行比较,让我们在一个图中绘制所有国家的图表。

df_usa = getDataForCountry(df,'United States')
df_usa = getAvgTempByYear(df_usa)
plt.plot(df_usa['year'],df_usa['avg_temp'],'r--')df_uk = getDataForCountry(df,'United Kingdom')
df_uk = getAvgTempByYear(df_uk)
plt.plot(df_uk['year'],df_uk['avg_temp'])df_china = getDataForCountry(df,'China')
df_china = getAvgTempByYear(df_china)
plt.plot(df_china['year'],df_china['avg_temp'],'#0be3df')

我们可以使用红色虚线r--,使用类似#0be3df的六进制代码,或者简单地使用默认颜色,而不需要明确定义。最终的图看起来会像这样

让我们也为这些线条添加一个图例。

plt.legend(['USA','UK','China'],loc=(0.2,0.25))

第一个参数是标签,第二个参数是loc,它是图例的位置。loc当给定一个元组时,将图例放置在绘图左下方的该百分比处。所以在这种情况下,20%来自左边,25%来自底部。

可能很难手动确定图例的最佳放置位置。因此,我们可以使用loc='best',pyplot 将图例放在可能的最佳位置。这一次,让我们也加入一个网格,这样就可以很容易地可视化这些值。

plt.legend(['USA','UK','China'],loc='best')
plt.grid()

所以,左上角似乎是这个剧情传说的最佳位置。正如我们所看到的,美国和英国的气温变化非常相似,在 20 世纪 70 年代末到 80 年代初有所不同,在 80 年代末,美国似乎每年都比英国热。这些年中国似乎相对更冷。

最后给三国画个boxplot

plt.boxplot([df_usa['avg_temp'],df_uk['avg_temp'],df_china['avg_temp']],labels=['USA','UK','China'])

使用单个箱线图可以传达许多信息,如中位数、四分位数和极差。盒状图由盒状图和须状图组成。根据文件,方框从数据的下四分位数延伸到上四分位数,中间有一条线。触须从框中延伸出来,以显示数据的范围。

美国和英国的平均气温非常接近 9 度,而中国的平均气温在 7 度左右。美国的范围超过 1.5,最高和最低温度分别略高于 10 度和低于 8.5 度。中国也有 1.5 左右的类似区间。英国的范围约为 2。

可视化是一种重要的技术,通过这种技术,大量的信息可以以一种更紧凑的方式传达。此外,它比纯文本、数字和表格更具视觉吸引力。和往常一样,这并不是 pyplot 所能做的详尽列表。但现在如果我们需要任何情节,至少我们知道去哪里找。**

SPRITE 案例研究#2:极化 Porterhouse 的案例(以及一些更新)

原文:https://towardsdatascience.com/sprite-case-study-2-the-case-of-the-polarizing-porterhouse-and-some-updates-7dfe4d1564fc?source=collection_archive---------0-----------------------

在我之前的文章中,我通过一个例子简单介绍了 SPRITE——cart horse Child。

REGULAR HUMAN CHILD DEMANDS BREAKFAST WILL HAVE 12lb OF OATS PLS

这是我能找到的最简单的案例研究,也是最有趣的,因为它是好马和孩子的交叉。

案例研究探讨了基本问题:给定样本的常规汇总统计数据(均值、标准差和 n),符合该描述的假设样本的属性是什么

这种情况下的答案是,如果你有 45 个孩子,他们平均吃了 19.4 个胡萝卜(SD=19.9),那么大多数符合描述的样本至少有一个孩子吃了至少 60 个胡萝卜,因此是一匹马。

许多人有异议和观点:

你怎么能确定‘胡萝卜’是完整的胡萝卜呢?

几个原因。我希望你觉得它们很有说服力:

a)在这项研究中,以及同一作者的许多其他类似研究中,它们一直被称为“胡萝卜”。有时它们被明确称为“小胡萝卜”(只是不在本文中)。但是在感兴趣的论文中也没有使用其他语言——切片、切块、缩略等。在美国,以我的经验(作为一个肮脏的偷工作的移民),当人们提到“胡萝卜”时,他们总是指小胡萝卜。

b)这里是作者对这项研究的文字描述——这种特殊的超级太空胡萝卜在照片和菜肴中都有展示。他们就在那里。看看他们橙色的荣耀。

现在,我想,我希望,我是合理的。我也花了比平时更多的时间去思考胡萝卜。我不想仓促行事,但也非常希望有一些当前的和合适的东西来最终介绍雪碧——我已经断断续续玩了很久了——然后马童出现了。你认为我有多长时间有机会向人们介绍法医元科学技术??

如果我没理解错 SPRITE 的话,你列举的很多问题,难道不能用适当的统计推导来解决吗?没有你的循环重的方法,一些样品是不可能的。

是的,你绝对可以找到适当的统计关系来解决精灵问题。(我们可以在某个时候详细讨论它们。)是的,我的方法也有点丑。它也是 a)多用途 b)直观 c)简单。

(目前正在做一些优化。)

问题是:我不是统计学家。我甚至不确定如何开发更神秘的工具,即使我开发了,我也不确定其他人是否会使用它们。根据我的经验,人们会被他们理解的事物所吸引。

你知道你使用的洗牌法背后的所有假设吗?它赋予你的解决方案什么样的属性?会生成一类答案还是所有答案?

非常好的问题,还不是 100%确定。但是——我有不止一种方法,而且它们在相同种类的解决方案上相当集中。我会尽我所能解释它们。

你见过类似的方法吗,XYZ?

我现在有了!我已经收到了四封关于这个问题的电子邮件,都是来自致力于解决这个问题的人(而且都是以不同的方式)和有额外分析建议的人。我感谢你们所有人给我发来这些东西,我学到了很多东西(即使是在几天内),我想和所有相关的人谈谈。请和谢谢你。

你的马和胡萝卜的笑话是糟糕的和/或不恰当的。

“摆在委员会面前的建议是:不要再开马的玩笑了。所有赞成的人?”

一些零散的答案

“所有反对的人?”

* 嘶声!*

(是的,我去了。但是我现在在浪费时间。)

案例研究# 2——两极分化住宅的案例

今天,我们要做的事情比胡萝卜的例子稍微复杂一点,那就是 a) 在没有 SD 的情况下工作,而不是在一系列 SD 上采样以建立一个合理的 SD,b) 在上面的基础上引入一个简单的约束

为了让 SPRITE 提供有用的信息,约束非常有用。它们允许我们将大量的可能数字减少到更小的数字。或多或少,任何约束都可以用来以某种方式照亮子画面。

下面的例子来自 Wansink 等人(2003 年)的论文:“探索不同年龄和性别的舒适食品偏好”。它提出了一项关于不同性别和年龄的人对舒适食品偏好的调查。该论文目前有 330 篇引文。下面是表 2 中的结果:

以防不明显,这是一个方法表。它涉及到一项针对美国人的大规模调查,调查者对所提供的食物是否符合“舒适食品”的标准进行评级。标度从 1 到 5——所以 1 是在犯下重罪后站在小巷里被吃掉,5 是在家看《网飞》时在羽绒被下被吃掉。

忽略其他错误,让我们来谈谈(‘牛排或牛肉’)。

对于男性来说,牛排的平均值为 3.2,我想这意味着它“有点”让人舒服。

而对于女性来说,平均值为 2.8,这“略低于令人欣慰的水平”。

总之。

根据表格,当你用单因素方差分析比较这两个值时,你得到的 F 值是 17.8。在这种情况下,ANOVA 返回与 t 值完全相等的 F 值,t = F。换句话说,对同一组进行常规的旧 t 检验将返回 t 值 4.22。这是一个很大的区别。

因此,为了方便起见,让我们从假设这些组之间的相同的 SDs 开始,然后反算SDs。

(我们还不需要 SPRITE,但我们可以用它来精确地再现上面的内容——只需运行它而不受规模限制,并迭代地改变 SD,直到我们得到 SD=1.47 的解,这给出了 4.2179 的 t…可爱!)

所以,现在我们的假设数据集是:

男性:平均值= 3.2,标准差= 1.47,n = 401

女性:平均值= 2.8,标准差= 1.47,n = 602

唯一的问题是…?

恶作剧问题。百分之百没问题。

以下是针对每种情况的 SPRITE 解决方案示例:

好吧,那就这样吧。

对吗?当然不是。

事实上,这份报纸继续把它的脚完全放进去:

另一种检验男性和女性对安慰性食物评价不同的一般趋势的方法是构建一个百分比接受度的替代测量,将对食物评价为 4 =同意或 5 =非常同意的人编码为接受该食物为安慰性食物的人[93]。在这样做的过程中,发现女性对糖果和巧克力的接受百分比更高[69%对 58%;v2 = 4.8p 在这一过程中,发现女性对糖果和巧克力的接受率更高[69%对 58%…] ,但对牛排或牛肉等与膳食相关的食物的接受率较低[52%对 77%]

这就是我们的限制。

让我们从男人开始:我们必须采用上面那些相当平坦的分布,并以某种方式将 77%的个体值塞进 4 或 5 个容器中。

这可能吗?

嗯,平均值低于 4,所以在我们最受约束的可能情况下,将会有no 5 .显然,这是愚蠢的,因为许多美国男人对牛排有什么接近蒸汽般的浪漫,但我们现在让它过去。

如果我们只对从 1 到 4 的值运行 SPRITE,我们会得到最大可能的解决方案,这真的很奇怪:

这是数据能做到的最好的字面意思——除了 1 和 4 什么都没有。平均值仍然在它应该在的地方(3.2),但即使在这种完全疯狂和极端的情况下,我们只有 1.33 的标准差。

但是你可能还记得以前,我们编造了那个 SD。所以违反它不是一个问题。问题是,这是获得大于 4 的多个值的绝对最佳情况,而不是 77% —它达到了 73.3%。

然而,女性数据可以存在。雪碧会把它弹出来。

…只是看起来很滑稽。

是的,看起来很傻,但事实上我们得到了我们想要的——足足 59.4%的值是 4 或 5(也就是所有的 4),超过了 52%的阈值。

因此,与其最大化我们的分布,不如强制我们的样本的 52%都是 4s。使用 SPRITE 很容易做到这一点:我们需要从 313 个 4 开始,当我们在剩余的 n 个中分割剩余的和时,可以找到样本参数。

具体来说:我们现在需要找到一个平均值为 1.5 的 n=289 的样本,当我们将它添加到 n=313 个 4 的巨大堆栈中时,我们就得到我们的总体平均值。

所以,这里有两个解决方案:

现在,上面的第一种情况将给出最大 SD(都是关于 1 的),它只比我们开始时的假设值差一点点:SD=1.39。

然而,我们现在面临的前景是,样本中只有极少量的 3,而没有任何 5。你认为这些分布,或者你从 1 到 3 打乱数值的类似分布,是现实的吗?他们不是。但它们是唯一能用的。

结论

如前所述,“男人”的案子是不可能的,“女人”的案子简直是不可能的。

即使牛排是有史以来最奇怪的两极分化的食物,是世界各地战争和骚乱的形式,将人们分成一种烹饪阿崔迪斯和哈康宁(这里显示了我的年龄),也没有可能重建论文中给出的数字。

论文中还有其他不一致的地方,但它们将不得不等待。

下一次,我们会看一些更复杂的东西。

虚假统计显著性:为什么大型实验设计可能是危险的

原文:https://towardsdatascience.com/spurious-statistical-significance-why-a-large-design-of-experiment-could-be-dangerous-418eceb189c0?source=collection_archive---------4-----------------------

在半导体工艺或产品设计中,经常会涉及大量的变量。很多时候,在初始学习周期阶段,大量的 PCM()过程控制监视器 )将被插入到布局设计中。这些是 IC 设计参数的各种可能组合,它们与工艺变量混合在一起,进行详尽的 实验设计(DoE) 研究,希望发现统计上显著的关系(或确认一些现有的但未经验证的理论),这可以导致良好的设计理解并简化开发过程,即在项目的后期阶段只需要一组较小的实验。

标准 IC 设计参数的例子可以是——有源单元间距、栅极长度、栅极-漏极重叠、晶体管宽度、宽长比、终端单元宽度和形状等。工艺变量包括(但不限于):离子注入能量/剂量/角度、各种薄膜(例如栅极电介质、场氧化物、氮化物掩模)参数、硅或氧化物蚀刻比率和配方、金属成分和沉积变量等。

从统计角度来说,这些工艺/设计变量中的每一个都与一个假设相关联,该假设有可能说明其与一个或多个输出参数的关系,即表示最终设备性能或可靠性的数量。

然而,关键问题是:在存在大量假设的情况下,即使遵循标准/严格的统计显著性检验方法,是否也有可能出现错误发现?

不幸的是,答案是肯定的,这是“假设-购物”的结果。一个简洁的演示就是 这里的

(非常)粗略地说,如果您使用任何统计建模技术(比如线性回归)测试至少 20 个假设(对应于调查 20 个 PCM 变量中的任何一个是否与特定器件输出参数相关),并列出 P 值,您可能会发现至少一个 P 值小于 0.05(这通常是拒绝零假设的黄金标准边界值),即使所有 20 个变量实际上都与输出参数不相关。现在,考虑到 P 值解释的普遍性和诱人的简单性,它们很难在假设检验场景中被忽略,您有义务报告这一发现,即这一特定的过程/设计参数将被标记为控制变量,它可以以统计显著的方式影响输出。

下面的图表说明了当你试图从一大组变量中发现具有统计显著性的关系时,存在大量假设的潜在危险。在本例中,所有的 x 变量都是完全随机生成的,输出 y 变量也是如此,即对于任何场景,在 xy 之间都不应该有任何统计上的显著关系。

但是随着假设数量的增加,统计显著 P 值的数量和假设数量之间存在明确的正相关关系(由正斜率线性拟合线显示),即更大的实验组更有可能发现 yx 之间的关系,即使它们基本上是由不相关的随机过程产生的。如图所示,一个明显的趋势是,随着 alpha 值阈值从 0.05 降低到 0.01,这种正相关性变得“弱”。

有趣的是,这种现象与产生变量和输出的潜在自然过程的性质无关。我用 R 编写了一小段代码来生成这个图,并使用了 rnormrunif 函数来运行它,即从正态高斯均匀分布中提取了 xy 变量,但是上面的图的一般性质保持不变。基本 R 代码在 GitHub 里。

现在,在半导体设计领域,大多数时候输入/输出的功能关系是相互关联的,这使得这种现象更加复杂,难以确定和隔离。此外,如果一个人不止一次地进行类似的实验,这种伪性质很容易被发现,但是在半导体设计中,由于与大的/重复的实验周期相关联的大的成本和开销,学习周期信息通常被用于调整未来的实验。

一般来说,谨慎的做法是在设计 DoE 时从较小的变量子集开始,并在使用尽可能小的 P 值时得出因果关系的结论。与社会科学或医学研究不同,半导体设计中的统计建模不必符合 0.05 作为 alpha 值。在分析了具有最显著输入变量的第一组数据并看到最高 P 值仅为 0.0001 后,为什么不将其降至最小可能值?

有许多研究和可用的方法来避免这个陷阱。希望在另一篇文章中写下它们。这是一个很好的介绍性演示。

原载于 2017 年 7 月 4 日【https://www.linkedin.com

使用 Apache Spark SQL 和数据框架扩展 SQL——概念、架构和示例

原文:https://towardsdatascience.com/sql-at-scale-with-apache-spark-sql-and-dataframes-concepts-architecture-and-examples-c567853a702f?source=collection_archive---------0-----------------------

使用您友好的 SQL,轻松地大规模辩论、聚合和过滤数据!

Source: Pixabay

注意

本文涵盖了与 Spark、SQL 和 DataFrames 相关的详细概念。除此之外,我们还将介绍一个使用 Spark SQL 和 DataFrames 大规模使用 SQL 的实践案例研究。如果第一眼看上去这篇文章有点让人不知所措或者很长,你可以在opensource.com的以下链接中找到同样的内容

我希望这有助于您开始使用 Spark 和 SQL 的旅程!

介绍

不管宣传以及通常被称为‘NoSQL’数据库的新数据库的出现,关系数据库都将存在。原因很简单,这些数据库强制执行基本的结构和约束,并提供了一个很好的声明性语言来查询数据,这是我们喜欢的 SQL!然而,规模一直是关系数据库的一个问题。21 世纪的大多数企业都承载着丰富的数据存储和存储库,并希望最大限度地利用其“大数据”来获得可操作的见解。关系数据库可能很受欢迎,但除非我们投资适当的大数据管理策略,否则它们不会很好地扩展。这包括考虑潜在的数据源、数据量、约束、模式、ETL(提取-转换-加载)、访问和查询模式等等!

Large Scale Data Science in Apache Spark: https://www.slideshare.net/databricks/largescale-data-science-in-apache-spark-20

本文将介绍在利用关系数据库的强大功能方面取得的一些优秀进展,但是是“大规模的”,使用 Apache Spark 的一些较新的组件——Spark SQL 和 DataFrames。最值得注意的是,我们将涵盖以下主题。

1.扩展关系数据库的动机和挑战

2.了解 Spark SQL 和数据框架

  • 目标
  • 架构和功能
  • 表演

3.一个关于 Spark SQL 的真实案例研究,包含实际操作示例

因此,我们将着眼于人们努力工作的主要挑战和动机,并投入时间在 Apache Spark 中构建新的组件,以便我们可以大规模执行 SQL。我们还将了解 Spark SQL 和 DataFrames 的主要架构、接口、特性和性能基准。最后,也是最重要的一点,我们将通过利用 Spark 的 Databricks 云平台 ,使用 Spark SQL 和 DataFrames,基于【KDD 99 杯赛数据 进行入侵攻击分析的真实案例研究!

为大数据扩展关系数据库的动机和挑战

关系数据存储易于构建和查询。此外,用户和开发人员通常更喜欢用类似人类的可读语言(如 SQL)编写易于解释的声明性查询。然而,随着数据的数量和种类开始增加,关系方法无法很好地扩展以构建大数据应用程序和分析系统。以下是一些主要挑战。

  • 处理不同类型和来源的数据,可以是结构化的、半结构化的和非结构化的。
  • 构建进出各种数据源的 ETL 管道,这可能会导致开发大量特定的定制代码,随着时间的推移,这会增加技术债务。
  • 能够执行基于传统商业智能的分析和高级分析(机器学习、统计建模等)。)后者在关系系统中执行肯定是有挑战性的。

大数据分析不是昨天才发明的东西!借助 Hadoop 和 Map-Reduce 范式,我们在这一领域取得了成功。这是强大的,但通常很慢,而且给用户提供了一个低级的、过程化的编程接口,要求人们为非常简单的数据转换编写大量代码。然而,一旦 Spark 发布,它就真正改变了大数据分析的方式,专注于内存计算、容错、高级抽象和易用性。

从那时起,Hive、Pig 和 Shark(演变为 Spark SQL)等几个框架和系统为大数据存储提供了丰富的关系接口和声明式查询机制。挑战依然存在,这些工具要么是基于关系的,要么是基于过程的,我们不可能两全其美。

然而在现实世界中,大多数数据和分析管道可能包含关系代码和过程代码的组合。因此,强迫用户选择任何一个都会使事情复杂化,并增加用户开发、构建和维护不同应用程序和系统的工作量。Apache Spark SQL 建立在前面提到的 SQL-on-Spark 的基础上,称为 Shark。Spark SQL 不是强迫用户在关系型或过程型 API 之间做出选择,而是试图让用户无缝混合这两种 API,并在大数据上执行大规模数据查询、检索和分析。

了解 Spark SQL 和数据框架

Spark SQL 本质上试图通过两个主要组件来弥合我们之前提到的两个模型之间的差距——关系模型和过程模型。

  • Spark SQL 提供了一个 DataFrame API,可以在外部数据源和 Spark 内置的分布式集合上执行关系操作——大规模!
  • 为了支持大数据中各种不同的数据源和算法,Spark SQL 引入了一种称为 Catalyst 的新型可扩展优化器,可以轻松添加数据源、优化规则和数据类型,以进行机器学习等高级分析。

本质上,Spark SQL 利用 Spark 的强大功能在大数据上执行大规模的分布式、健壮的内存计算。Spark SQL 提供了最先进的 SQL 性能,并且还保持了与所有现有结构和组件的兼容性,这些结构和组件由 Apache Hive (一个流行的大数据仓库框架)支持,包括数据格式、用户定义函数(UDF)和 metastore。除此之外,它还有助于从大数据源和企业数据仓库(如 JSON、Hive、Parquet 等)获取各种数据格式,并执行关系和过程操作的组合,以进行更复杂的高级分析。

目标

让我们来看看一些关于 Spark SQL 的有趣事实,它的用法、采用和目标,其中一些我将再次无耻地从 Spark 中关于 关系数据处理的优秀原创论文中复制。Spark SQL 于 2014 年 5 月首次发布,现在可能是 Spark 中开发最活跃的组件之一。Apache Spark 绝对是最活跃的大数据处理开源项目,有数百名贡献者。除了只是一个开源项目,Spark SQL 实际上已经开始被主流行业采用!它已经被部署在非常大规模的环境中。脸书提到了一个很好的案例研究,他们谈到了【Apache Spark @ Scale:一个 60 TB 以上的生产用例】在这里,他们正在为实体排名做数据准备,他们的 Hive 工作过去需要几天时间并面临许多挑战,但他们能够使用 Spark 成功地扩展和提高性能。一定要看看他们在这次旅程中面临的有趣挑战!

[## Apache Spark @Scale:一个 60 TB 以上的生产用例——脸书代码

脸书经常使用数据驱动的决策分析。在过去几年中,用户和产品的增长…

code.fb.com](https://code.fb.com/core-data/apache-spark-scale-a-60-tb-production-use-case/)

另一个有趣的事实是,Databricks Cloud(运行 Spark 的托管服务)的 2/3 客户在其他编程语言中使用 Spark SQL。在本文中,我们还将展示一个在数据块上使用 Spark SQL 的实际案例研究。敬请关注!Spark SQL 的创建者定义的主要目标如下。

  1. 使用一个程序员友好的 API 支持 Spark 程序(在本地 rdd 上)和外部数据源中的关系处理。
  2. 使用已建立的 DBMS 技术提供高性能。
  3. 轻松支持新的数据源,包括半结构化数据和服从查询联合的外部数据库。
  4. 借助图形处理和机器学习等高级分析算法实现扩展。

架构和功能

我们现在来看看 Spark SQL 和 DataFrames 的关键特性和架构。这里需要记住的一些关键概念是围绕着 Spark 生态系统的,这个生态系统一直在不断发展。

RDDs 或“弹性分布式数据集”也许是 Spark 所有成功故事背后的最大贡献者。它基本上是一种数据结构,或者更准确地说,是一种分布式内存抽象,允许程序员在大型分布式集群上执行内存计算,同时保留容错等方面。您还可以并行处理大量计算和转换,并跟踪整个转换过程,这有助于高效地重新计算丢失的数据。Spark 爱好者确实读过关于 RDDs 的优秀论文, 【弹性分布式数据集:内存集群计算的容错抽象】 此外,Spark 还使用了驱动程序和工人的概念,如下图所示。

您通常可以通过从文件、数据库读入数据、并行化现有集合甚至转换来创建 RDD。通常情况下,转换是根据我们处理数据的方式将数据转换成不同方面和维度的操作。它们也被延迟评估,这意味着即使你定义了一个转换,结果也不会被计算,直到你应用了一个动作,这通常需要一个结果被返回到驱动程序(然后它计算了所有应用的转换!).

向数据科学家同行和朋友 Favio Vázquez 和他关于使用 Apache Spark 进行深度学习的优秀 文章大声疾呼 从中我获得了一些优秀的想法和内容,包括上图。一定要去看看!

[## 使用 Apache Spark 进行深度学习—第 1 部分

第一部分全面讨论了如何使用 Apache Spark 进行分布式深度学习。这一部分:什么是火花…

towardsdatascience.com](/deep-learning-with-apache-spark-part-1-6d397c16abd)

现在我们已经了解了 Spark 工作的一般架构,让我们更深入地了解一下 Spark SQL。通常, Spark SQL 作为一个库运行在 Spark 之上,正如我们在覆盖 Spark 生态系统的图中所看到的。下图更详细地展示了 Spark SQL 的典型架构和接口。

该图清楚地向我们展示了各种 SQL 接口,可以通过 JDBC/ODBC 或命令行控制台访问,以及集成到 Spark 支持的编程语言中的 DataFrame API(我们将使用 Python!).DataFrame API 非常强大,允许用户 最后 混合程序和关系代码!像 UDF(用户定义函数)这样的高级函数也可以在 SQL 中公开,供 BI 工具使用。

Spark 数据框架非常有趣,可以帮助我们利用 Spark SQL 的强大功能,并根据需要组合其过程范例。Spark 数据帧基本上是具有相同模式的行(行类型)的分布式集合。它基本上是将 Spark 数据集 组织成命名列。这里要注意的一点是, 数据集 ,是 DataFrame API 的扩展,提供了一个类型安全、面向对象的编程接口。因此,它们只在 Java 和 Scala 中可用,因此我们将关注数据帧。

Source: PySpark-Pictures — Jeffrey Thompson

DataFrame 相当于关系数据库中的一个表(但是有更多的优化),也可以用类似于 Spark (RDDs)中“本地”分布式集合的方式进行操作。Spark 数据帧有一些有趣的属性,下面会提到其中一些。

  1. 与 rdd 不同,数据帧通常跟踪它们的模式,并支持各种关系操作,从而实现更优化的执行。
  2. 数据帧可以从表中构造,就像您的大数据基础架构中现有的 Hive 表一样,甚至可以从现有的 rdd 中构造。
  3. 数据帧可以通过直接的 SQL 查询进行操作,也可以使用数据帧 DSL(特定于域的语言),其中我们可以使用各种关系运算符和转换器,比如 where 和 groupBy
  4. 此外,每个数据帧也可以被视为行对象的 RDD,允许用户调用过程化 Spark APIs,如 map
  5. 最后,给定但要记住的一点是,与传统的数据帧 API(pandas)不同,Spark 数据帧是懒惰的,因为每个数据帧对象代表一个计算数据集的逻辑计划,但在用户调用特殊的“输出操作”如 save 之前不会执行。

这将使你对 Spark SQL、数据框架、基本特性、概念、架构和接口有足够的了解。让我们通过查看性能基准来结束这一部分。

表演

发布一个没有正确优化的新特性可能是致命的,而构建 Spark 的人做了大量的性能测试和基准测试!让我们来看看一些有趣的结果。展示一些结果的第一张图如下所示。

Performance of Shark, Impala and Spark SQL on Big Data benchmark queries

在这些实验中,他们使用 AMPLab 大数据基准测试比较了 Spark SQL 与 Shark 和 Impala 的性能,该基准测试使用了 Pavlo 等人开发的 web 分析工作负载。该基准测试包含四种类型的查询,使用不同的参数执行扫描、聚合、连接和基于 UDF 的 MapReduce 作业。使用柱状拼花格式压缩后,数据集的数据量为 110 GB。我们看到,在所有查询中,Spark SQL 都比 Shark 快得多,总体上与 Impala 相当。Catalyst optimizer 负责这一点,这减少了 CPU 开销(我们将简要介绍这一点)。这个特性使得 Spark SQL 在许多查询中与基于 C++和 LLVM 的 Impala 引擎竞争。与 Impala 最大的差距是在**query 3a**中,Impala 选择了一个更好的连接计划,因为查询的选择性使得其中一个表非常小。

下图显示了数据帧和常规 Spark APIs 以及 Spark + SQL 的更多性能基准。

Spark DataFrames vs RDDs and SQL

最后,下图显示了不同语言中数据帧与 rdd 的一个很好的基准测试结果,这从一个有趣的角度展示了数据帧可以优化到什么程度!

Comparing Spark DataFrames and RDDs

性能秘诀——催化剂优化器

为什么 Spark SQL 这么快,这么优化?原因是,基于 Scala 中的函数式编程结构,有了新的可扩展优化器 Catalyst。虽然我们不会在这里详细讨论 Catalyst,但它值得一提,因为它有助于优化数据帧操作和查询。

Catalyst 的可扩展设计有两个目的。

  • 使向 Spark SQL 添加新的优化技术和功能变得容易,特别是解决围绕“大数据”、半结构化数据和高级分析的各种问题。
  • 能够轻松扩展优化器—例如,通过添加特定于数据源的规则,可以将过滤或聚合推到外部存储系统中,或者支持新的数据类型。

Catalyst 支持基于规则和基于成本的优化。虽然在过去已经提出了可扩展的优化器,但是它们通常需要复杂的特定于领域的语言来指定规则。通常,这导致了很长的学习曲线和维护负担。相比之下,Catalyst 使用 Scala 编程语言的标准特性,例如模式匹配,让开发人员可以使用完整的编程语言,同时仍然可以轻松地指定规则。

Catalyst 的核心包含一个通用库,用于表示树并应用规则来操作它们。在这个框架之上,它有特定于关系查询处理的库(例如,表达式、逻辑查询计划),以及处理查询执行的不同阶段的几组规则:分析、逻辑优化、物理规划,以及将部分查询编译成 Java 字节码的代码生成。有兴趣了解关于 Catalyst 的更多细节并深入了解吗?你可以从 Databricks 查看 的一篇优秀文章!

[## 深入了解 Spark SQL 的 Catalyst 优化器

Spark SQL 是 Spark 最新的、技术含量最高的组件之一。它支持 SQL 查询和…

databricks.com](https://databricks.com/blog/2015/04/13/deep-dive-into-spark-sqls-catalyst-optimizer.html)

Spark SQL 实践案例研究

我们现在将基于真实世界的数据集做一个简单的教程,看看如何使用 Spark SQL。我们将使用 Spark 数据框架,但重点将更多地放在使用 SQL 上。我将在另一篇文章中详细讨论 Spark 数据帧和常见操作。我喜欢使用云服务来满足我的机器学习、深度学习甚至大数据分析需求。与其痛苦地建立自己的 Spark 集群,不如使用云中最好的一个!我们将使用 Databricks 平台来满足我们的 Spark 需求!Databricks 是由 Apache Spark 的创始人创办的一家公司,旨在帮助客户使用 Spark 进行基于云的大数据处理。

最简单的方法(也是免费的)是去 试用数据块页面注册 使用 社区版 的账户,在那里你可以获得一个基于云的集群,这是一个单节点集群,有 6 GB 和无限的笔记本,对于一个免费版本来说还不错!如果您有分析大数据的迫切需求,我绝对推荐您使用 Databricks 平台!

现在让我们开始我们的案例研究,如下面的快照所示,您可以在 Databricks 的主屏幕或自己的 Spark 集群中随意创建一个新笔记本。

你也可以导入我的笔记本,里面有整个教程,但是一定要运行每一个单元,玩它,探索它,而不只是通读它。不确定如何在数据块上使用 Spark?跟随 这篇简短却有用的教程 今天就开始吧!

[## Apache Spark 教程:Apache Spark 入门教程

Apache Spark 是一个强大的开源处理引擎,围绕速度、易用性和复杂的分析而构建…

databricks.com](https://databricks.com/spark/getting-started-with-apache-spark)

本教程将使您熟悉基本的 Spark 功能,以处理经常从数据库或平面文件中获得的结构化数据。我们将通过 Spark 利用 DataFrames 和 SQL 的概念来探索查询和聚合关系数据的典型方法。我们将处理来自 1999 年 KDD 杯的一个有趣的数据集,并尝试使用 dataframe 之类的高级抽象来查询数据,data frame 已经在 R 和 Python 之类的流行数据分析工具中获得成功。我们还将了解使用您已经学习过的 SQL 语言构建数据查询有多容易,并从我们的数据中检索有见地的信息。由于 Spark 在后端高效地分发这些数据结构,这使得我们的查询尽可能地可伸缩和高效,因此这也可以大规模发生,而无需我们做更多的工作。我们首先加载一些基本的依赖项。

**import pandas as pd
import matplotlib.pyplot as plt
plt.style.use('fivethirtyeight')**

资料检索

我们将使用来自 1999 年 KDD 杯的数据,这是用于第三届国际知识发现和数据挖掘工具竞赛的数据集,该竞赛与 KDD-99 第五届知识发现和数据挖掘国际会议同时举行。竞赛任务是建立一个网络入侵检测器,一个能够区分不良连接(称为入侵或攻击)和 良好、正常连接 的预测模型。该数据库包含一组要审计的标准数据,其中包括在军事网络环境中模拟的各种入侵。**

我们将使用包含近 50 万个网络交互的精简数据集**kddcup.data_10_percent.gz**,因为我们将从 web 本地下载这个 Gzip 文件,然后对其进行处理。如果您有一个良好、稳定的互联网连接,请随意下载并使用作为**kddcup.data.gz** 的完整数据集。

使用来自 web 的数据

在数据块中处理从网上检索的数据集可能有点棘手。幸运的是,我们有一些优秀的实用程序包,比如**dbutils**,可以帮助我们简化工作。让我们快速看一下本模块的一些基本功能。

****dbutils.help()** This module provides various utilities for users to interact with the rest of Databricks.**fs: DbfsUtils** -> Manipulates the Databricks filesystem (DBFS) from the console
**meta: MetaUtils** -> Methods to hook into the compiler (EXPERIMENTAL)
**notebook: NotebookUtils** -> Utilities for the control flow of a notebook (EXPERIMENTAL)
**preview: Preview** -> Utilities under preview category
**secrets: SecretUtils** -> Provides utilities for leveraging secrets within notebooks
**widgets: WidgetsUtils** -> Methods to create and get bound value of input widgets inside notebooks**

在数据块中检索和存储数据

我们现在将利用 python **urllib**库从他们的 web 存储库中提取 KDD 杯 99 数据,将其存储在一个临时位置,然后将其移动到 Databricks 文件系统,这样可以方便地访问这些数据进行分析

****注意:如果你跳过这一步直接下载数据,你可能会得到一个**InvalidInputException: Input path does not exist**错误

构建 KDD 数据集

现在,我们已经将数据存储在 Databricks 文件系统中,让我们将数据从磁盘加载到 Spark 的传统抽象数据结构中,即弹性分布式数据集(RDD)

您还可以使用下面的代码来验证我们的数据(RDD)的数据结构的类型。

****type(raw_rdd)****

在我们的数据上建立一个火花数据框架

Spark 数据帧是一种有趣的数据结构,表示分布式数据集合。通常,Spark 中所有 SQL 功能的入口点是**SQLContext**类。为了创建这个调用的一个基本实例,我们只需要一个**SparkContext**引用。在 Databricks 中,这个全局上下文对象作为**sc**可用于此目的。

分割 CSV 数据

RDD 中的每个条目都是逗号分隔的数据行,在解析和构建数据帧之前,我们首先需要对其进行拆分。

检查特征(列)的总数

我们可以使用下面的代码来检查数据集中潜在列的总数。

****len(csv_rdd.take(1)[0])****Out[57]: 42****

数据理解和解析

KDD 99 杯赛数据由从连接数据中捕获的不同属性组成。数据中属性的完整列表可在此处获得,有关每个属性\列描述的更多细节可在此处找到。我们将只使用数据集中的一些特定列,其细节如下所述。**

我们将根据它们在每个数据点(行)中的位置提取下面的列,并构建一个新的 RDD,如下所示。

构建数据框架

现在我们的数据已经被干净利落地解析和格式化了,让我们构建我们的数据框架吧!

您现在还可以使用下面的代码来检查我们的 dataframe 的模式。

*****df.printSchema()*****

构建临时表

我们可以利用registerTempTable()函数构建一个临时表,在我们的数据帧上大规模运行 SQL 命令!需要记住的一点是,这个临时表的生命周期是与会话联系在一起的。它创建一个内存中的表,该表的作用域是创建它的集群。数据使用 Hive 高度优化的内存列格式存储。

您还可以查看saveAsTable(),它使用 Parquet 格式创建了一个永久的物理表,存储在 S3。所有集群都可以访问该表。包括文件位置的表元数据存储在 Hive metastore 中。

*****help(df.registerTempTable)*****

*****df.registerTempTable("connections")*****

大规模执行 SQL

让我们看几个例子,看看如何基于数据帧在表上运行 SQL 查询。在本教程中,我们将从一些简单的查询开始,然后查看聚合、过滤器、排序、子查询和透视。

基于协议类型的连接

让我们看看如何根据连接协议的类型获得连接总数。首先,我们将使用正常的 DataFrame DSL 语法来执行聚合,从而获得这些信息。

我们是否也可以使用 SQL 来执行相同的聚合?是的,我们可以利用我们之前为此构建的表!

你可以清楚地看到,你得到相同的结果,你不需要担心你的后台基础设施或代码是如何执行的。只写简单的 SQL!

基于好坏(攻击类型)签名的连接

我们现在将运行一个简单的聚合来检查基于良好(正常)或不良(入侵攻击)类型的连接总数。

我们有许多不同的攻击类型。我们可以用条形图的形式把它形象化。最简单的方法就是使用 Databricks 笔记本本身的优秀界面选项!

这给了我们以下好看的条形图!您可以根据需要点击**Plot Options**进行进一步定制。

另一种方法是自己写代码来做。您可以将聚合数据提取为 pandas DataFrame,然后将其绘制为常规条形图。

基于协议和攻击的连接

让我们根据下面的 SQL 查询来看看现在哪些协议最容易受到攻击。

嗯,看起来 ICMP 连接和 TCP 连接受到的攻击最多!

基于协议和攻击的连接统计

让我们看一下与这些协议和对我们的连接请求的攻击相关的一些统计测量。

看起来 TCP 请求中传输的平均数据量要高得多,这并不奇怪。有趣的是,攻击从源传输到目的地的平均数据负载要高得多。

根据 TCP 协议按服务和攻击类型过滤连接统计信息

让我们更仔细地看看 TCP 攻击,因为我们有更多相关的数据和统计数据。我们现在将根据服务、攻击类型汇总不同类型的 TCP 攻击,并观察不同的指标。

有许多攻击类型,前面的输出显示了其中的一个特定部分。

根据 TCP 协议按服务和攻击类型过滤连接统计信息

现在,我们将根据查询中的持续时间、文件创建和根用户访问施加一些限制,来过滤一些攻击类型。

有趣的是, 多跳攻击 能够获得对目的主机的根访问权限!

基于服务过滤 TCP 攻击类型的子查询

让我们尝试基于服务和攻击类型获取所有 TCP 攻击,使得这些攻击的总体平均持续时间大于零(**> 0**)。为此,我们可以使用所有聚合统计信息进行内部查询,然后提取相关查询,并在外部查询中应用平均持续时间过滤器,如下所示。

这真好!现在,查看这些数据的一种有趣方式是使用一个数据透视表,其中一个属性表示行,另一个属性表示列。让我们看看是否可以利用 Spark 数据帧来做到这一点!

从聚合数据构建数据透视表

在这里,我们将基于之前获得的 DataFrame 对象,基于类型和服务来聚合攻击。为此,我们可以利用 Spark 数据帧和数据帧 DSL 的强大功能。

我们得到了一个漂亮整洁的数据透视表,显示了基于服务和攻击类型的所有事件!

后续步骤

我鼓励你出去玩玩 Spark SQL 和 DataFrames,你甚至可以 导入我的笔记本 在你自己的账户里自己玩。

关于本文中使用的所有代码和笔记本,请随意参考我的 GitHub 资源库 。我们在这里没有涉及的内容包括以下内容。

  • 连接
  • 窗口功能
  • Spark 数据帧的详细操作和转换

网上有很多文章/教程,所以我建议你去看看。您可以查看一些有用的资源,包括来自 Databricks 的 Spark SQL 完整指南。

**[## SQL 指南-数据块文档

查看 Azure 数据块文档 Azure 文档

docs.databricks.com](https://docs.databricks.com/spark/latest/spark-sql/index.html)**

考虑使用 JSON 数据,但不确定是否使用 Spark SQL。他们支持!查看这篇关于 Spark SQL 中的 JSON 支持的优秀指南。

** [## Spark SQL 中的 JSON 支持简介

在这篇博客文章中,我们介绍了 Spark SQL 的 JSON 支持,这是我们在 Databricks 上一直致力于开发的一项功能,旨在使它…

databricks.com](https://databricks.com/blog/2015/02/02/an-introduction-to-json-support-in-spark-sql.html)

对 SQL 中的窗口函数和秩等高级概念感兴趣?看看这篇关于 Spark SQL 中 窗口函数的精彩文章

[## Spark SQL 中的窗口函数介绍

在这篇博文中,我们介绍了 Apache Spark 1.4 中添加的新窗口函数特性。窗口功能…

databricks.com](https://databricks.com/blog/2015/07/15/introducing-window-functions-in-spark-sql.html)

我还将写一篇后续文章,以直观的方式介绍其中的一些概念,这对你来说应该很容易理解。敬请期待!

你可以通过 这个链接 直接进入我在 Databricks 上的笔记本,然后直接导入并摆弄它

[## 大规模使用 SQL-Spark SQL 教程-数据块

迪潘然(DJ)萨卡尔

databricks-prod-cloudfront.cloud.databricks.com](https://databricks-prod-cloudfront.cloud.databricks.com/public/4027ec902e239c93eaaa8714f173bcfc/3137082781873852/3704545280501166/1264763342038607/latest.html)

本教程的所有代码和资源都可以在 我的 GitHub上找到

[## 全民数据科学

我的博客和文章的代码和资源,与大家分享数据科学和人工智能的知识和学习…

github.com](https://github.com/dipanjanS/data_science_for_all/tree/master/tds_spark_sql_intro)

你也可以访问我的教程作为一个 Jupyter 笔记本 以防你想离线使用。

[## Jupyter 笔记本浏览器

Spark SQL 为 Spark 带来了对 SQL 的原生支持,并简化了查询存储在 RDDs

nbviewer.jupyter.org](http://nbviewer.jupyter.org/github/dipanjanS/data_science_for_all/blob/master/tds_spark_sql_intro/Working with SQL at Scale - Spark SQL Tutorial.ipynb)

有反馈给我吗?或者有兴趣和我一起从事研究、数据科学、人工智能甚至发表一篇关于TDS的文章?你可以在LinkedIn联系我。

[## Dipanjan Sarkar —数据科学家—英特尔公司| LinkedIn

查看 Dipanjan Sarkar 在世界最大的职业社区 LinkedIn 上的个人资料。Dipanjan 有 6 份工作列在…

www.linkedin.com](https://www.linkedin.com/in/dipanzan/)

感谢 Durba 编辑此文。**

面试的 SQL 摘要

原文:https://towardsdatascience.com/sql-cheat-sheet-for-interviews-6e5981fa797b?source=collection_archive---------0-----------------------

用例子和样本代码 DIY

SQL结构化查询语言是一种设计用于管理关系数据库管理系统(RDBMS) 中数据的语言。在本文中,我将带您了解每个程序员都应该知道的常用 SQL 命令。如果你需要为面试而温习 SQL 知识,这篇文章是完美的。你所要做的就是尝试给出的例子,并刷新你很久以前在数据库系统课上所学的内容。😉

注意:一些数据库系统要求在每条语句的末尾插入一个分号。分号是指示每个 SQL 语句结尾的标准方式。我将使用 MySQL 作为例子,它要求在每个语句的末尾有一个分号。

设置示例数据库

示例数据库将用于演示每个命令。您可以通过单击链接找到两个 SQL 脚本 DLL.sqlInsertStatements.sql

将文件保存到本地机器后,打开终端,使用以下命令登录到 MySQL 控制台。(我假设你已经安装了 MySQL。)

mysql -u root -p

然后会提示您输入密码。

现在执行以下命令。我们将把我们的数据库命名为“ 大学 ”。

**CREATE DATABASE** university;**USE** university;**SOURCE** <*path_of_DLL.sql_file>;***SOURCE** <*path_of_InsertStatements.sql_file>;*

Figure 1: Executed queries to setup the database

现在让我们开始刷新我们以前学过的 SQL 命令。

数据库相关命令

1.查看当前可用的数据库

**SHOW DATABASES**;

2.创建新的数据库

**CREATE DATABASE** <*database_name*>;

3.选择要使用的数据库

**USE** <*database_name*>;

4.从导入 SQL 命令。sql 文件

**SOURCE** <*path_of_.sql_file>;*

5.删除数据库

**DROP DATABASE** <*database_name*>;

与表格相关的命令

6.查看数据库中当前可用的表

**SHOW TABLES**;

Figure 2: Tables in university database

7.创建新表格

**CREATE TABLE** <*table_name1*> (
    <*col_name1*> <*col_type1*>, 
    <*col_name2*> <*col_type2*>, 
    <*col_name3*> <*col_type3*>
    **PRIMARY KEY** (<*col_name1*>),
   ** FOREIGN KEY** (<*col_name2*>) **REFERENCES** <*table_name2*>(<*col_name2*>)
);

完整性约束创建表

您可能需要为表中的某些列设置约束。创建表时可以施加以下约束。

  • 不为空
  • 主键 ( 列名 1,列名 2,… )
  • 外键 ( col_namex1 ,…, col_namexn ) 引用 表名(col_namex1 ,…, col_namexn)

您可以包含多个主键,这将创建一个复合串联 主键

例子

创建表格讲师。

CREATE TABLE instructor (
    ID CHAR(5),
    name VARCHAR(20) NOT NULL,
    dept_name VARCHAR(20),
    salary NUMERIC(8,2), 
    PRIMARY KEY (ID),
    FOREIGN KEY (dept_name) REFERENCES department(dept_name))

8.描述表格的列

您可以使用下面给出的命令来查看表的列,包括类型和键等详细信息。图 3 显示了几个例子。

**DESCRIBE** <*table_name*>;

Figure 3: Details of table columns

9.插入表中

**INSERT INTO** <*table_name>* (<*col_name1>*, *<col_name2>*, *<col_name3>*, …)
    **VALUES** (<*value1>*, *<value2>*, *<value3>*, …);

如果要将值插入到表的所有列中,则不需要在开头指定列名。

**INSERT INTO** <*table_name>*
    **VALUES** (<*value1>*, *<value2>*, *<value3>*, …);

10.更新表格

**UPDATE** <*table_name>*
    **SET** <*col_name1>* = *<value1>*, *<col_name2>* = *<value2>*, ...
    **WHERE** <*condition>*;

11.删除表格的所有内容

**DELETE FROM** <*table_name*>;

12.删除表格

**DROP TABLE** <*table_name*>;

查询相关命令

13.挑选

SELECT 语句用于从特定的表中选择数据。

**SELECT** <*col_name1>*, *<col_name2>, …*
     **FROM** <*table_name>*;

您可以选择表格的所有内容,如下所示。也参考图 4。

**SELECT * FROM** <*table_name*>;

Figure 4: Select all from department and course tables

14.选择不同

表中的一列可能经常包含重复值。选择不同的允许您检索不同的值。

**SELECT DISTINCT** <*col_name1>*, *<col_name2>, …*
     **FROM** <*table_name>*;

Figure 5: SELECT DISTINCT example

15.在哪里

您可以在 SELECT 语句中使用 WHERE 关键字,以便为您的数据包含条件。

**SELECT** <*col_name1>*, *<col_name2>, …*
     **FROM** <*table_name>
*     **WHERE** <*condition*>;

您可以包含以下条件:

  • 比较文本
  • 数字的比较
  • 逻辑运算包括

例子

浏览下面的示例语句。请注意条件是如何包含在 WHERE 子句中的。

SELECT * FROM course WHERE dept_name=’Comp. Sci.’;
SELECT * FROM course WHERE credits>3;
SELECT * FROM course WHERE dept_name='Comp. Sci.' AND credits>3;

Figure 6: Usage of WHERE in SELECT

16.分组依据

GROUP BY 语句通常与聚合函数一起使用,如 COUNTMAXMINSUMAVG 对结果集进行分组。

**SELECT** <*col_name1>*, *<col_name2>, …*
     **FROM** <*table_name>*
     **GROUP BY** <*col_namex>*;

示例

列出每个系的课程数量。

SELECT COUNT(course_id), dept_name 
     FROM course 
     GROUP BY dept_name;

Figure 7: Number of courses for each department

17.拥有

具有子句的被引入 SQL,因为 WHERE 关键字不能用于比较聚合函数的值。

**SELECT** <*col_name1>,* <*col_name2>, ...*
    **FROM** <*table_name>*
    **GROUP BY** <*column_namex>* **HAVING** <*condition>*

示例

列出提供一门以上课程的每个系的课程数量。

SELECT COUNT(course_id), dept_name 
    FROM course 
    GROUP BY dept_name 
    HAVING COUNT(course_id)>1;

Figure 8: Departments offering more than one course

18。排序依据

ORDER BY 用于对结果集进行升序或降序排序。如果不指定 ASC 或 DESC,ORDER BY 将按升序排序。

**SELECT** <*col_name1>*,<*col_name2>, …*
**FROM** <*table_name>*
**ORDER BY** <*col_name1>,* <*col_name2>, …* **ASC**|**DESC**;

示例

按照学分的升序和降序列出课程。

SELECT * FROM course ORDER BY credits;
SELECT * FROM course ORDER BY credits DESC;

Figure 9: Courses sorted according to credits

19.在...之间

之间的子句用于选择给定范围内的数据。这些值可以是数字、文本甚至日期。

**SELECT** <*col_name1>*,<*col_name2>, …*
    **FROM** <*table_name>*
    **WHERE** <*col_namex>* **BETWEEN** <*value1>* **AND** <*value2>;*

例子

列出薪水在 50 000 到 100 000 之间的教师。

SELECT * FROM instructor 
    WHERE salary BETWEEN 50000 AND 100000;

Figure 10: Instructors who get a salary in between 50 000 and 100 000

20.喜欢

WHERE 子句中使用 LIKE 运算符来搜索文本中的指定模式。

LIKE 使用了两个通配符运算符。

  • % (零个、一个或多个字符)
  • _ (单个字符)
**SELECT** <*col_name1>,* <*col_name2>, …*
    **FROM** <*table_name>*
    **WHERE** <*col_namex>* **LIKE** <*pattern>*;

例子

列出课程名称包含“to”的课程以及课程 id 以“CS-”开头的课程。

SELECT * FROM course WHERE title LIKE ‘%to%’;
SELECT * FROM course WHERE course_id LIKE 'CS-___';

Figure 11: Use of wildcard operators with LIKE

21.在…里

在子句中使用,可以允许在一个 WHERE 子句中有多个值。

**SELECT** <*col_name1>,* <*col_name2>, …*
    **FROM** <*table_name>*
    **WHERE** <*col_namen>* **IN** (<*value1>*, *<value2>*, …);

例子

列出计算机系的学生。Sci。、物理和电子。英语。

SELECT * FROM student 
    WHERE dept_name IN (‘Comp. Sci.’, ‘Physics’, ‘Elec. Eng.’);

Figure 12: Students in the departments of Comp. Sci., Physics, and Elec. Eng

22.加入

JOIN 用于根据两个或多个表中的公共属性合并它们的值。下面的图 13 描述了不同类型的 SQL 连接。注意左外接头右外接头的区别。

Figure 13: Types of joins (Source: http://files.zeroturnaround.com/pdf/zt_sql_cheat_sheet.pdf)

**SELECT** <*col_name1>,* <*col_name2>, …*
    **FROM** <*table_name1>*
    **JOIN** <*table_name2>* **ON** <*table_name1.col_namex>* = *<table2.col_namex>*;

示例 1

选择所有包含相关部门详细信息的课程。

SELECT * FROM course 
    **JOIN** department 
    ON course.dept_name=department.dept_name;

Figure 14: All the courses with department details

示例 2

选择所有先修课程及其课程详细信息。

SELECT prereq.course_id, title, dept_name, credits, prereq_id 
    FROM prereq 
   ** LEFT OUTER JOIN** course 
    ON prereq.course_id=course.course_id;

Figure 15: All the prerequisite courses with their course details

示例 3

选择所有课程及其课程详细信息,无论它们是否有先决条件。

SELECT course.course_id, title, dept_name, credits, prereq_id 
    FROM prereq 
    **RIGHT OUTER JOIN** course 
    ON prereq.course_id=course.course_id;

Figure 16: All the courses with their course details, regardless of whether or not they have prerequisites

23.视图

视图是使用语句的结果集创建的虚拟 SQL 表。它包含行和列,非常类似于一般的 SQL 表。视图总是显示数据库中的最新数据。

创建视图

**CREATE VIEW** <*view_name*> **AS**
    **SELECT** <*col_name1>*, <*col_name2>*, …
    **FROM** <*table_name*>
    **WHERE** <*condition*>;

删除视图

**DROP VIEW** <*view_name*>;

例子

创建由 3 个学分的课程组成的视图。

Figure 17: A view consisting of courses with 3 credits

24.聚合函数

这些函数用于获得与正在考虑的数据相关的累积结果。以下是常用的聚合函数。

  • COUNT(col_name) —返回行数
  • SUM(col_name) —返回给定列中值的总和
  • AVG(列名) —返回给定列的平均值
  • MIN(col_name) —返回给定列的最小值
  • MAX(col_name) —返回给定列的最大值

25.嵌套子查询

嵌套子查询是包含嵌套在另一个查询中的 SELECT-FROM-WHERE 表达式的 SQL 查询。

例子

查找 2009 年秋季和 2010 年春季提供的课程。

**SELECT DISTINCT** course_id 
    **FROM** section 
    **WHERE** semester = ‘Fall’ **AND** year= 2009 **AND** course_id **IN** (
        **SELECT** course_id 
            **FROM** section 
            **WHERE** semester = ‘Spring’ **AND** year= 2010
    );

Figure 18: Courses offered in Fall 2009 and in Spring 2010

希望这篇文章对你有用。

感谢大家的阅读!😃

祝你面试好运!

简而言之的 SQL:第 1 部分—基本的真实场景

原文:https://towardsdatascience.com/sql-in-a-nutshell-part-1-basic-real-world-scenarios-33a25ba8d220?source=collection_archive---------3-----------------------

本系列关注现实世界中最常见的数据科学和分析问题,旨在用 SQL 解决这些问题。

Photo by Carlos Muza on Unsplash

更新(到原帖):

  1. SQLFiddle 上的查询链接已被移除。未来的更新包括嵌入 SQL 的 Jupyter/IPython 笔记本的链接。
  2. 这里的大多数查询都是用 ANSI SQL 编写的。为了便于执行,PostgreSQL 9.6 和 MySQL 5.6 包含在一起,以展示窗口函数等特性(MySQL 不支持这些特性)。您可以在本地安装其中一个或两个来测试我们的查询。
  3. 本文已经扩展为一个由 3 部分组成的系列,第三部分涵盖了 SQL 中典型的、重要的任务。

如果您熟悉 SQL 的语法和编写基本的选择查询,您可能会发现本系列有助于快速复习或学习更多的技巧和诀窍,以编写更清晰和优化的查询,如如何计算六周的滚动平均销售额。

这是本系列的第一篇文章,将回顾 SQL 概念以及一些基本问题,这些问题将通过基本的检索、连接、过滤、聚合和转换来回答。
第二篇
文章将涵盖更复杂的场景,以及如何使用窗口函数、子查询、移动平均、常用表表达式和排序来处理这些场景。
第三篇
文章将涵盖 SQL 中典型的、重要的任务——例如旋转、从每个组中检索顶级结果的不同方法、处理重复项以及性能查询调优。

SQL 简介

SQL(结构化查询语言)是为管理数据库中的数据而设计的通用编程语言。由于它的标准语法,它支持所有的关系数据库以及一些 NoSQL(不仅仅是 SQL)。SQL 之所以受欢迎,是因为它的用法像英语一样易于理解,还因为它可以直接访问数据的存储位置,而不是将数据复制到其他应用程序,这使得分析相对方便。

借助 SQL,我们可以:

  • 定义数据(DDL),例如,将缩写值标准化为完整的状态名
  • 处理数据(DML ),例如用一个单词替换一个空白或空值
  • 从数据库(DQL)中检索数据,例如获得本月的销售数字

在本系列的范围内,我们将只处理用于检索的查询( SELECT )。对于我们的大多数查询,我们还将使用 SQL:2011 版本的 ANSI SQL——一种在大多数数据库上兼容的标准。为了演示,我们将使用 MySQL 5.6 和/或 PostgreSQL 9.6。

注意:针对 SQL 发布的最新标准(ISO/IEC 或 ANSI)是 SQL:2016 ,对 JSON 功能有额外的支持。

创建数据库并插入数据

在开始查询数据之前,我们需要创建一个数据库并将数据加载到其中。

数据库 是一个有组织的数据集合,由表格等结构和其他元素组成。一个在行(元组)和列(属性)中存储数据。模式指的是如何构建数据库(或划分成数据库表)的蓝图。

下面的命令集为我们的数据库构建了模式:

Build Schema (Create tables and Insert data)

在这里,我们创建两个表,分别是由PRODUCT _ ID(产品的主键,销售的外键)关联的产品销售

检索数据

**SELECT**命令用于从数据库中检索数据。

以下是一些获得销售数据的不同方法的基本查询:

  • 所有细节来自一张表
  • 结果限制在前 N 行(用于测试或取样)
  • 表中的特定列
  • 列名的别名(使信息可读)
  • 不同的列值(一列或多列中的唯一值)

Basic SELECT queries on Sales table

连接表格

连接表允许我们组合多个数据集,以获得更完整的结果集和全面的分析。

数据建模(数据库设计)规范化是一个过程,用于将数据组织在单独的结构良好的表中,以最大限度地减少冗余,并避免插入、更新和删除异常。这种分离也有助于简化逻辑,提高精确装配特定用途所需物品的灵活性。这种装配是通过“连接”操作来完成的。

假设我们有一个单独的表 ProductSales 存储我们所有的数据:

Raw Data into ProductSales table

比如说,企业希望通过产品名称来了解产品,而不仅仅是品牌名称。这意味着他们可以要求我们将“诺基亚”更新为“诺基亚 Lumia”,将“三星”更新为“三星 S5”。在这种情况下,如果有一百万行,改变每一行 Product_Name 是“诺基亚”或“三星”的操作在计算上是相当昂贵的。

相反,如果我们以这样一种方式构建我们的数据,即在一个单独的表中取出产品数据,每种产品有一行信息,那么销售表中的每笔销售都可以与一个产品 ID 相关联。这叫做一对多关系。现在对 Product_Name 的任何更改都只是一行操作,所有与更新产品相关的销售数据都可以通过 Product_ID 上的join轻松访问。

连接的用例:

  • 为了组合相关的数据集,例如,为了找到已售出产品的名称,我们将把销售表和产品表连接起来
  • 例如,为了执行比较——为了执行同比分析,我们可以将相似数据的分区按年份值进行组合
  • 使用表格作为查找资源,例如,为了获得运输交付类型的状态,存储状态代码的枚举器以映射到相应的文本会更有效。

连接的类型

  1. 内部连接:内部连接是一个连接,它只返回两个表中那些连接条件为真的结果。

例如— 获取已销售产品的详细信息:

Inner Join

在本例中,从结果集中可以观察到,没有产品“LG”的销售,因为在 Sales 表中没有产品“LG”的列表(或者没有 Product_ID ) )。

连接条件通过一个**ON**子句指定。我们还可以使用AND操作符向它添加多个条件。例如,获取 2017 年销售的产品明细:

Inner Join with condition

2.外部联接:外部联接是返回一个或两个表的所有结果的联接(取决于联接类型——左、右或全),并且不满足联接条件的行返回空值。

为了更好地解释这一点,我们以前面的例子为例,稍微修改了一下需求— 获取所有产品及其相应的销售信息,如果有的话:

Left Join

在这里,我们有每一个产品清单以及每一笔销售。对于“LG”,结果集显示该产品存在于我们的数据库中,但是还没有销售。这是一个**LEFT JOIN**的例子。

一个RIGHT JOIN以类似的方式工作,但是相反,即返回右边表格的所有行,左边不匹配的行作为空值返回。尽可能使用左连接(右连接之上)是一种标准做法。

注意: FULL JOIN 在 MySQL 中不支持,但通过UNION可以完成类似的查询。这篇文章的下一次更新将包括关于在 PostgreSQL 等其他数据库中使用的完全连接自连接的主题。工会工会所有将在下一篇帖子中涉及。

过滤和排序数据

通过过滤数据集,我们可以根据搜索条件限制我们的结果。

  • 集中分析,例如,将销售趋势的结果缩小到特定区域
  • 要限制集合条件的数据集,例如,获取平均评分为 4 或更高的产品,其总评论数至少为 10
  • 减少用于计算的数据集大小,例如——对一个假设进行采样

以下是过滤中常用的一些运算符:

过滤数据的基本方法是使用WHERE子句以及一个或多个适合您的搜索条件的操作符。

以下是一些常用的运算符:

  • 比较运算符 : =(等于)、<>!=(不等于),以及其他一些不言自明的运算符— ><>=<=
  • 逻辑运算符:ANDORNOTIN(在一组值中查找)、BETWEEN(具有开始和结束范围)、LIKE(匹配相似的值)

整理

SQL 查询中的排序是可选的。默认情况下,如果主键存在,则结果按主键的顺序返回,否则按随机顺序返回。如果我们希望以特定的方式对结果进行排序,我们必须显式地添加一个ORDER BY子句,后跟一个列名列表进行排序,最后是订单类型(ASC — 升序,DESC — 降序 )

让我们从一个简单的例子开始— 获取一部“iPhone”的所有销售细节:

Filter Data

请注意,在第一个查询中,我们已经按 Product_ID(如果已知)进行了筛选。在第二个查询中,我们将 SalesProducts 表连接起来,并筛选出以“-Phone”结尾的产品。注意“%”是一个通配符,它可以搜索其位置上的任何文本。

再举一个例子— 获取 2015 年 11 月 1 日到 2017 年 10 月 1 日之间的销售明细,按日期排序:

Filter and Sort

这里,在第一个查询中,我们使用了一组比较运算符。在第二个查询中,我们使用BETWEEN来搜索相同范围内的日期值。

现在,如果我们需要获得产品的销售细节——“诺基亚”、“三星”和“LG”,该怎么办?或者说这是我们需要搜索的大约 20 种产品的列表。与其包含 20 个AND条件,不如使用IN操作符来编写这个查询:

Filter with IN

聚集

当我们沉浸在周围数以百万计的细节中时,我们经常会失去上下文,并希望从中寻找有意义的信息。通过汇总数据,我们可以观察到每月总计或按类别划分的销售订单平均值等洞察。这有助于我们更深入地了解我们的数据,并允许我们提出更深入的问题。在高层次上,我们还可以识别数据中的模式和趋势。

为此,我们将使用 SQL 中内置函数的集合,这些函数汇总或汇总我们的值。一些基本的包括最小值、最大值、平均值、总和、计数,更具分析性的包括标准差、方差和等级。

让我们从使用一些基本功能开始,例如—

Basic Aggregation

这对初学者来说很好,但是除了告诉我们表包含多少行或者价格的最小/最大值是多少之外,它实际上没有多少业务洞察力。如果我们想知道每件产品的销售额是多少呢?小组来了,由来救援!

**GROUP BY**允许您将数据分成组,这些组可以彼此独立地进行聚合。

例如— 获取我们数据库中每种产品的总销售额、平均价格和总销售量:

Aggregate by Product

现在这给出了一个更全面的图片!

:使用COALESCEIFNULL(或等效物)可以用指定值替换空值。

让我们考虑另一个示例— 对于从 2016 年 10 月 1 日开始销售的每件产品,获取每年的总销售额、平均价格和总数量,并只返回那些至少销售了 10 件商品的产品,按产品名称和年份排序。

现在可能有很多要处理,但下面是对其解决方案的分解分析:

Aggregation with multiple conditions

注意:HAVING子句在执行聚合后应用过滤器。

聚合是 SQL 分析的核心部分,是任何优秀的数据科学家/工程师都必须掌握的。随着本系列的继续,我们将学习更多类似的复杂场景以及如何处理它们。

内置函数的数据转换

在收集的数据质量差、需要清理的情况下,通常需要进行数据转换;这种过程被称为数据争论(或蒙骗)。还需要转换来以更易于阅读的格式呈现数据报告。

以下是使用内置函数的季度和月度销售报告的一些示例:

Quarterly and Monthly Sales

第一个查询显示季度销售报告。这里,MONTHYEAR函数将日期值转换成整数形式的相应月份和年份值,而CAST用于价格以从整数转换成小数。CASE函数(一个IF-ELSE的变体)检查然后检查条件并将每个日期值映射到季度桶中,之后结果按季度分组。类似地,为了显示月度销售报告,我们需要对进行分组,如第二个查询所示。

SQL 中有许多更方便的函数,您可以在您正在使用的 SQL 版本的文档中找到它们。更多的内容将在本系列的后续文章中讨论。

参考

在您等待下一篇文章的时候,请查看 SQL 上一些有趣的链接以获取更多知识:

[## 结构化查询语言- Wikibooks,开放世界的开放书籍

这本 Wikibook 提供了对 SQL、其起源、基本概念和组件的简短描述,以及大量示例…

en.wikibooks.org](https://en.wikibooks.org/wiki/Structured_Query_Language) [## 数据分析的 SQL 教程

本教程是为想用数据回答问题的人设计的。对许多人来说,SQL 是“肉和土豆…

community.modeanalytics.com](https://community.modeanalytics.com/sql/tutorial/introduction-to-sql/) [## 数据科学的 SQL 提示和技巧

获取 Ben Sullins 为数据科学专业人士(工程师、开发人员、数据挖掘人员、程序员和其他人员)提供的 12 个必备 SQL 技巧

bensullins.com](https://bensullins.com/sql-tips-tricks-data-science/)

希望这篇文章对你有帮助!如果你喜欢这篇文章,请为它鼓掌。有什么想法吗?把它们写在下面的评论里。

SQL:所有非技术人员都需要知道的一项技术技能

原文:https://towardsdatascience.com/sql-the-one-technical-skill-all-non-technicals-need-to-know-843db07d9bc8?source=collection_archive---------4-----------------------

技术领域的商业、营销或战略人员指南。

如果你想从事技术工作,你会被大量的数据包围,无论是营销活动的打开率,应用内的用户活动,还是网络性能。根据经济学家的说法,数据已经成为新的石油,各公司都在加强他们的数据收集和分析团队,以优化他们的平台并创建“数据驱动的战略”。

在 Tumblr 全球增长战略品牌团队的实习期间,我成为了这一趋势的一部分。我需要了解我们的用户如何在国际上与平台互动,以便推动用户增长、保留和货币化。更具体地说,我需要一种方法来浏览、组织和理解每天来自全球 3 . 5 亿多个博客的数据,为此我需要 SQL。

简而言之,如果你想使用大量的数据,你需要知道如何使用 SQL

首先,我想说我不是 SQL 方面的专家。事实上,科技公司的大多数人不需要成为专家。重要的是,我们了解足够多的 SQL,能够提取、组织和利用我们的角色所需的数据,无论是作为业务分析师、营销经理还是产品经理。换句话说,我们需要知道“足够危险”。

什么是 SQL?

SQL ,表示结构化查询语言,是一种访问和操作数据库的语言。不要让这个定义吓倒您——使用 SQL 实现基本功能并不需要太复杂。可以把它看作是通过提供一系列标准来选择您想要访问的数据的一种方式。如果你想知道有多少用户在万圣节登录并发布了他们的服装照片,你的列表可能包括:

  • 2016 年 10 月 31 日登录
  • 张贴的图片
  • 图片描述包含单词“服装”或“#服装”

然后,您将生成类似如下的查询:

一旦您理解了语法,您将开始看到提取数据是多么的逻辑和简单。然而,SQL 真正令人兴奋的地方是,当你开始将整个公司的数据拼凑在一起,以便形成新的见解。例如,您想了解您的电子邮件营销活动如何为 2017 年 Q2 世博会在墨西哥的日活跃使用量做出贡献。如果收集了正确的数据,您可以将整个组织的数据表拼接在一起,回答这个问题并优化墨西哥的电子邮件活动。

为什么这很重要?

学习 SQL 很重要有两个原因。首先,它允许您直接处理原始数据,而不是要求其他人向您提供有组织的数据集。这允许你在战略上更快地行动,独立地领导项目,并且成为你的团队的技术资产。

其次,SQL 增加了你的经济护城河——沃伦·巴菲特用这个术语来描述你相对于同行业其他人的竞争优势。SQL 是目前市场上最受欢迎的技能之一,它肯定会让你从你的同行中脱颖而出。

怎样才能学好 SQL?

有大量免费资源可以帮助您学习 SQL 的基础知识:

  1. 可汗学院——这是我曾经入门的一个。他们使用的慢节奏和沙盒系统对我们这些很少或没有编码经验的人特别有帮助。
  2. Code Academy — Code Academy 因提供高质量的课程计划和项目而在技术社区享有盛誉。虽然你可以从一些免费的模块开始,但最终你会看到每月 20 美元——这对他们提供的内容来说并不算太坏。
  3. W3 Schools —如果你有一些技术背景,我会推荐 W3 Schools 的命令和 SQL 特性 DIY 列表。他们用例子清楚地解释概念,甚至有一个 SQL 接口供你使用。

一旦你掌握了基础知识,请查看本指南中的 Google BigQuery ,这是一款工具,可以让你在任何你想要查询的数据集上运行类似 SQL 的查询。对于少量的处理能力来说,它非常简单而且免费。

这是所有的乡亲。

随时联系并在 Twitter 或 LinkedIn 上聊天!

数据科学家的 SQL 技巧—检查数据质量

原文:https://towardsdatascience.com/sql-tricks-for-data-scientists-checking-data-quality-2fc17a306366?source=collection_archive---------10-----------------------

所有的数据科学家都知道一些 SQL,但是除了将数据放入“真实”的分析环境中,它还可以有更多的用途。

在某种程度上,SQL 是数据科学中被遗忘的秘密——被认为是从它经常驻留的数据库中获取数据的必要但有点不酷的手段,没有熊猫或 tidyverse 的缓存。

从某些方面来说,这也很公平,因为大多数 SQL 实现中提供的函数范围往往无法满足数据准备人员的需求,他们需要将表连接在一起,并应用过滤器来减少要传输到执行分析的环境中的数据量——通常是在 R 或 Python 中。

关于 SQL 的书籍使问题变得更加复杂,因为很难找到比简单的 SELECT 语句和连接的核心范围更远的书籍,可能还增加了一些聚合函数。

然而,许多人经常使用 SQL,因为我们使用的数据存储在一个符合 SQL 的数据库中,如果我们想用它做些什么,我们必须需要编写一个查询,如果我们要编写一个查询,我们最好把它做好。

类似地,对于许多分析来说,第一步是将一堆数据移动到 R 或 Python 中,我们可能会这样做——至少,我们可能会尝试移动最小但最有用的数据表。因此,确定每一列的有用性,并突出可能导致该行或列从最终模型中排除的缺失值和极值的分析可能是有用的。

确定特定列中缺失值的比例似乎应该是现成的。它不是,但仍然可以用最少的麻烦来实现,尽管需要一些技巧。

SELECT CAST

(SUM (CASE WHEN column1 is NULL THEN 1 ELSE 0 END)

as float) / COUNT(*) AS ProportionMissing

FROM YourDB.YourTable

实际上,我们正在做的是通过 CASE 语句实现 Excel 的 SUMIF。显然,我们需要对 float 进行强制转换,因为 SUM 返回一个整数,如果我们忘记了强制转换,查询在几乎所有情况下都会返回 0。

这个查询的要点是,如果任何特定列中的缺失程度意味着该列是无用的,那么将该列移到您的建模环境中就是浪费时间。

另一个基本的数据质量检查是寻找极端情况。很明显,在 SQL 中有 MAX()和 MIN()函数,但是进一步研究多个极端变量也是有用的。检测极值的一种合理的常见方法是寻找相对于平均值有过多标准偏差的值——下面使用 4 个标准偏差作为基准。

WITH STATS (Col1_AVG,Col1_SD) AS
    (SELECT STDEV(Col1),AVG(Col1)
    FROM Db1.Tbl1)

 SELECT Col1,DWT_AVG,DWT FROM STATS JOIN Tbl1
 ON 1=1
 WHERE ABS(Col1-Col1_AVG)/Col1_SD > 4

我们使用公共表表达式(以关键字‘WITH’开始的部分),因为我们要将聚合函数的结果与它们所基于的值进行比较。上面的版本返回了极值本身,因此可以研究它们的合理性(当数据是手动收集的时,极值来自转录错误并不罕见),但是反转大于号显然只是修剪了值。

罗伯特·德格拉夫最近的一篇关于媒体的文章是 【解释:最后一英里

他还是即将出版的《管理您的数据科学项目 》一书的作者

在推特上关注他:https://twitter.com/RobertdeGraaf2

SQL 教程:如何编写更好的查询

原文:https://towardsdatascience.com/sql-tutorial-how-to-write-better-queries-108ae91d5f4e?source=collection_archive---------1-----------------------

结构化查询语言(SQL)是数据科学行业中不可或缺的技能,一般来说,学习这项技能相当容易。然而,大多数人忘记了 SQL 不仅仅是编写查询,这只是前进道路上的第一步。确保查询是可执行的,或者它们适合您正在工作的环境,这完全是另外一回事。

这就是为什么本 SQL 教程将为您提供一些步骤,您可以通过这些步骤来评估您的查询:

  • 首先,你将从学习 SQL 对于数据科学工作的重要性开始;
  • 接下来,您将首先了解更多关于 SQL 查询处理和执行的知识,以便您能够正确理解编写定性查询的重要性:更具体地说,您将看到查询被解析、重写、优化并最终被评估;
  • 记住这一点,你不仅会复习一些初学者在编写查询时会犯的查询反模式,还会学到更多关于那些可能错误的替代方案和解决方案;您还将了解更多关于基于集合的查询方法与基于过程的查询方法的对比。
  • 您还将看到,这些反模式源于性能考虑,并且除了改进 SQL 查询的“手动”方法之外,您还可以通过使用一些其他工具来帮助您查看查询计划,以更结构化、更深入的方式来分析您的查询;而且,
  • 在执行查询之前,您将简要地更深入地了解时间复杂性和大 O 符号,以了解执行计划的时间复杂性;最后,
  • 您将简单地得到一些关于如何进一步调优您的查询的提示。

你对 SQL 课程感兴趣吗?参加 DataCamp 的数据科学 SQL 简介课程!

为什么要学数据科学的 SQL?

SQL 远未消亡:它是数据科学行业工作描述中最受欢迎的技能之一,无论你申请的是数据分析师、数据工程师、数据科学家还是其他任何角色。2016 年 O'Reilly Data Science 薪酬调查的 70%受访者证实了这一点,他们表示在自己的专业背景下使用 SQL。此外,在这项调查中,SQL 远远超过 R (57%)和 Python (54%)编程语言。

你明白了:当你想在数据科学行业找到一份工作时,SQL 是一项必备技能。

对于 20 世纪 70 年代早期开发的语言来说,这已经不错了,对吗?

但是为什么它被如此频繁地使用呢?为什么它已经存在了这么长时间却没有死?

有几个原因:第一个原因是,公司大多将数据存储在关系数据库管理系统(RDBMS)或关系数据流管理系统(RDSMS)中,您需要 SQL 来访问这些数据。SQL 是数据的通用语言:它让您能够与几乎任何数据库进行交互,甚至在本地构建自己的数据库!

似乎这还不够,请记住,有相当多的 SQL 实现在供应商之间是不兼容的,并且不一定遵循标准。因此,了解标准 SQL 是你在(数据科学)行业中找到出路的一项要求。

最重要的是,可以肯定地说,SQL 也已经被更新的技术所接受,例如 Hive,一个用于查询和管理大型数据集的类似 SQL 的查询语言接口,或者 Spark SQL,您可以使用它来执行 SQL 查询。同样,您在那里找到的 SQL 将不同于您可能已经学习过的标准,但是学习曲线将会容易得多。

如果你确实想做一个比较,就把它当作学习线性代数:通过把所有的努力投入到这个科目中,你知道你也能够用它来掌握机器学习!

简而言之,这就是为什么您应该学习这种查询语言:

  • 这很容易学,即使对完全的新手来说也是如此。学习曲线非常简单且循序渐进,因此您很快就可以编写查询了。
  • 它遵循“学一次,用在任何地方”的原则,所以这是一个伟大的投资你的时间!
  • 这是对编程语言的极好补充;在某些情况下,编写查询甚至比编写代码更受欢迎,因为它更具性能!

你还在等什么?😃

SQL 处理和查询执行

为了提高 SQL 查询的性能,您首先必须知道当您按快捷键运行查询时内部发生了什么。

首先,将查询解析成“解析树”;分析该查询以查看它是否满足语法和语义要求。解析器创建输入查询的内部表示。这个输出然后被传递给重写引擎。

然后,优化器的任务就是为给定的查询找到最佳的执行或查询计划。执行计划确切地定义了每个操作使用什么算法,以及如何协调操作的执行。

为了找到最佳的执行计划,优化器会列举所有可能的执行计划,确定每个计划的质量或成本,获取有关当前数据库状态的信息,然后选择最佳的执行计划作为最终的执行计划。因为查询优化器可能并不完美,所以数据库用户和管理员有时需要手动检查和调整优化器生成的计划,以获得更好的性能。

现在您可能想知道什么被认为是“好的查询计划”。

正如你已经读到的,计划成本的质量起着巨大的作用。更具体地说,评估计划所需的磁盘 I/o 数量、计划的 CPU 成本、数据库客户端可以观察到的总响应时间以及总执行时间等都是必不可少的。这就是时间复杂性概念的由来。稍后你会读到更多这方面的内容。

接下来,执行选择的查询计划,由系统的执行引擎进行评估,并返回查询结果。

从上一节中可能还不清楚的是,垃圾输入、垃圾输出(GIGO)原则在查询处理和执行中自然地显现出来:制定查询的人也掌握着 SQL 查询性能的关键。如果优化器得到一个错误的查询,它只能做同样多的事情…

这意味着当你写一个查询时,有些事情可以做。正如您在简介中已经看到的,责任是双重的:不仅要编写符合特定标准的查询,还要收集查询中潜在性能问题的想法。

一个理想的起点是在您的查询中考虑问题可能潜入的“点”。一般来说,有四个条款和关键字,新手可能会遇到性能问题:

  • WHERE条款;
  • 任何INNER JOINLEFT JOIN关键字;而且,
  • HAVING条款;

诚然,这种方法简单而幼稚,但作为初学者,这些子句和语句是很好的指针,可以肯定地说,当你刚刚开始时,这些地方就是错误发生的地方,讽刺的是,它们也是很难发现的地方。

然而,您还应该认识到,性能需要一个上下文才有意义:当您考虑 SQL 性能时,简单地说这些子句和关键字不好是不可取的。在您的查询中有一个WHEREHAVING子句并不一定意味着它是一个糟糕的查询…

请看下一节,了解更多关于反模式和构建查询的替代方法。这些提示和技巧是作为指南。实际上,如何以及是否需要重写查询取决于数据量、数据库以及执行查询的次数等。这完全取决于您的查询目标,并且对您想要查询的数据库有一些先验知识是至关重要的!

1.仅检索您需要的数据

当您编写 SQL 查询时,“数据越多越好”的思维定势并不是您必须遵循的:您不仅会因为获取了超过实际需要的数据而有模糊见解的风险,而且您的性能可能会因为查询提取了太多数据而受到影响。

这就是为什么寻找SELECT语句、DISTINCT子句和LIKE操作符通常是个好主意。

当您编写查询时,首先可以检查的是SELECT语句是否尽可能紧凑。你的目标应该是从SELECT中删除不必要的列。通过这种方式,您可以强迫自己只提取符合查询目标的数据。

如果您有包含EXISTS的相关子查询,您应该尝试在该子查询的SELECT语句中使用一个常量,而不是选择一个实际列的值。当您只检查存在性时,这尤其方便。

记住相关子查询是使用外部查询中的值的子查询。请注意,尽管NULL在这种情况下可以作为一个“常量”工作,但这非常令人困惑!

考虑下面的例子来理解使用常数的含义:

SELECT driverslicensenr, name 
FROM Drivers 
WHERE EXISTS (SELECT '1' FROM Fines 
              WHERE fines.driverslicensenr = drivers.driverslicensenr);

提示:知道拥有一个相关子查询并不总是一个好主意是很方便的。你总是可以考虑去掉它们,比如用一个INNER JOIN重写它们:

SELECT driverslicensenr, name 
FROM drivers 
INNER JOIN fines ON fines.driverslicensenr = drivers.driverslicensenr;

SELECT DISTINCT语句仅用于返回不同的值。DISTINCT是一个如果可以的话,你绝对应该尽量避免的条款;与您在其他示例中看到的一样,只有在查询中添加这个子句,执行时间才会增加。因此,考虑一下你是否真的需要这个DISTINCT操作来获得你想要完成的结果总是一个好主意。

当您在查询中使用LIKE操作符时,如果模式以%_开头,则不会使用索引。它将阻止数据库使用索引(如果存在的话)。当然,从另一个角度来看,您也可以认为这种类型的查询可能会检索太多不一定满足您的查询目标的记录。

同样,您对存储在数据库中的数据的了解可以帮助您制定一个模式,该模式将正确地过滤所有数据,只找到对您的查询真正重要的行。

2.限制你的结果

当你无法避免过滤掉你的SELECT语句时,你可以考虑用其他方式限制你的结果。这就是诸如LIMIT子句和数据类型转换等方法的用武之地。

您可以在查询中添加LIMITTOP子句来设置结果集的最大行数。以下是一些例子:

SELECT TOP 3 * FROM Drivers;

注意您可以进一步指定PERCENT,例如,如果您通过SELECT TOP 50 PERCENT *更改查询的第一行。

SELECT driverslicensenr, name FROM Drivers LIMIT 2;

此外,您还可以添加ROWNUM子句,这相当于在查询中使用LIMIT:

SELECT * 
FROM Drivers 
WHERE driverslicensenr = 123456 AND ROWNUM <= 3;

您应该总是尽可能使用最有效的,也就是最小的数据类型。当您提供一个较大的数据类型,而一个较小的数据类型就足够了时,总会有风险。

但是,当您将数据类型转换添加到查询中时,只会增加执行时间。

另一种方法是尽可能避免数据类型转换。这里还要注意,并不总是能够从查询中删除或省略数据类型转换,但是在包含它们时一定要小心,并且当您这样做时,要在运行查询之前测试添加的效果。

3.不要让查询变得不必要的复杂

数据类型转换把您带到了下一点:您不应该过度设计您的查询。尽量保持简单高效。这可能看起来太简单或太愚蠢,甚至不能作为提示,尤其是因为查询可能会变得复杂。

然而,您将在下一节提到的示例中看到,您可以很容易地将简单的查询变得比实际需要的更复杂。

当您在查询中使用OR操作符时,很可能您没有使用索引。

记住索引是一种数据结构,可以提高数据库表中数据检索的速度,但这是有代价的:需要额外的写操作和额外的存储空间来维护索引数据结构。索引用于快速定位或查找数据,而不必在每次访问数据库表时搜索数据库中的每一行。可以通过使用数据库表中的一列或多列来创建索引。

如果您不利用数据库包含的索引,您的查询将不可避免地需要更长的时间来运行。这就是为什么最好在查询中寻找使用OR操作符的替代方法;

考虑以下查询:

SELECT driverslicensenr, name 
FROM Drivers 
WHERE driverslicensenr = 123456 OR driverslicensenr = 678910 OR driverslicensenr = 345678;

您可以通过以下方式替换操作员:

SELECT driverslicensenr, name 
FROM Drivers 
WHERE driverslicensenr IN (123456, 678910, 345678);
  • 两个SELECT语句带一个UNION

提示:这里,你需要小心不要不必要地使用UNION操作,因为你要多次遍历同一个表。同时,您必须意识到,当您在查询中使用一个UNION时,执行时间将会增加。UNION操作的替代方法是:重新制定查询,将所有条件放在一个SELECT指令中,或者使用OUTER JOIN代替UNION

提示:这里也要记住,即使OR——以及下面几节将要提到的其他操作符——可能不使用索引,索引查找也不总是首选!

当您的查询包含NOT操作符时,很可能没有使用索引,就像使用OR操作符一样。这将不可避免地降低您的查询速度。如果您不知道此处的含义,请考虑以下查询:

SELECT driverslicensenr, name FROM Drivers WHERE NOT (year > 1980);

这个查询的运行速度肯定会比您预期的要慢,这主要是因为它的表述比实际情况要复杂得多:在这种情况下,最好寻找一种替代方法。考虑用比较运算符代替NOT,如><>!>;上面的例子可能真的会被改写成这样:

SELECT driverslicensenr, name FROM Drivers WHERE year <= 1980;

看起来已经整洁多了,不是吗?

AND操作符是另一种不使用索引的操作符,如果以过于复杂和低效的方式使用,会降低查询速度,如下例所示:

SELECT driverslicensenr, name 
FROM Drivers 
WHERE year >= 1960 AND year <= 1980;

最好重写这个查询并使用BETWEEN操作符:

SELECT driverslicensenr, name 
FROM Drivers 
WHERE year BETWEEN 1960 AND 1980;

另外,ALLALL操作符是一些你应该小心使用的操作符,因为将它们包含在你的查询中,索引将不会被使用。这里有用的替代方法是聚合函数,如MINMAX

提示:在使用建议的替代方法的情况下,您应该意识到这样一个事实,即许多行上的所有聚合函数,如SUMAVGMINMAX,都可能导致长时间运行的查询。在这种情况下,您可以尽量减少要处理的行数,或者预先计算这些值。您再次看到,当您决定使用哪个查询时,了解您的环境、您的查询目标……是非常重要的!

此外,在计算或标量函数中使用列的情况下,不使用索引。一个可能的解决方案是简单地隔离特定的列,使其不再是计算或函数的一部分。考虑下面的例子:

SELECT driverslicensenr, name 
FROM Drivers 
WHERE year + 10 = 1980;

这看起来很时髦,是吧?相反,尝试重新考虑计算,并将查询重写为如下形式:

SELECT driverslicensenr, name 
FROM Drivers 
WHERE year = 1970;

4.没有暴力

最后一个技巧实际上意味着您不应该过多地限制查询,因为这会影响它的性能。对于连接和HAVING子句来说尤其如此。

当连接两个表时,考虑连接中表的顺序是很重要的。如果您注意到一个表比另一个表大得多,您可能希望重写查询,以便将最大的表放在连接的最后。

  • 连接上的冗余条件

当您向连接中添加太多条件时,您基本上是在迫使 SQL 选择某个路径。然而,这可能并不总是更有效的方法。

最初将HAVING子句添加到 SQL 中是因为WHERE关键字不能用于聚合函数。HAVING通常与GROUP BY子句一起使用,将返回的行组限制为仅满足特定条件的那些行。但是,如果在查询中使用这个子句,就不会使用索引,正如您已经知道的那样,这可能会导致查询的执行效果不太好。

如果你正在寻找一个替代方案,考虑使用WHERE条款。考虑以下查询:

SELECT state, COUNT(*) FROM Drivers WHERE state IN ('GA', 'TX') GROUP BY state ORDER BY stateSELECT state, COUNT(*) FROM Drivers GROUP BY state HAVING state IN ('GA', 'TX') ORDER BY state

第一个查询使用WHERE子句来限制需要求和的行数,而第二个查询对表中的所有行求和,然后使用HAVING丢弃它计算的总和。在这些类型的情况下,带有WHERE子句的替代选项显然是更好的,因为您不会浪费任何资源。

您会看到,这不是限制结果集,而是限制查询中的中间记录数。

请注意这两个子句的区别在于,WHERE子句引入了单个行的条件,而HAVING子句引入了聚合或选择结果的条件,其中单个结果,如MINMAXSUM、…是从多个行中产生的。

你看,当你考虑到它们需要尽可能高的性能时,评估质量、编写和重写查询并不是一件容易的工作;当您编写希望在专业环境中的数据库上运行的查询时,避免反模式和考虑替代方案也将是您的职责的一部分。

这个列表只是一些反模式和技巧的一个小概述,希望对初学者有所帮助;如果您想深入了解更多高级开发人员认为最常见的反模式是什么,请查看本讨论。

基于集合和过程的查询方法

上述反模式中隐含的事实是,它们实际上归结为基于集合的方法与构建查询的过程方法之间的差异。

查询的过程化方法是一种很像编程的方法:您告诉系统做什么以及如何做。

这方面的一个例子是连接中的冗余条件或滥用HAVING子句的情况,就像上面的例子一样,其中通过执行一个函数然后调用另一个函数来查询数据库,或者使用包含循环、条件、用户定义函数(UDF)、游标等的逻辑来获得最终结果。在这种方法中,您经常会发现自己在请求数据的一个子集,然后从数据中请求另一个子集,以此类推。

毫不奇怪,这种方法通常被称为“逐步”或“逐行”查询。

另一种方法是基于集合的方法,您只需指定要做什么。您的角色包括为希望从查询中获得的结果集指定条件或要求。如何检索数据,由决定查询实现的内部机制决定:让数据库引擎决定执行查询的最佳算法或处理逻辑。

由于 SQL 是基于集合的,所以这种方法比过程方法更有效就不足为奇了,这也解释了为什么在某些情况下,SQL 比代码运行得更快。

提示基于集合的查询方法也是数据科学行业大多数顶级雇主要求你掌握的方法!您经常需要在这两种方法之间切换。

注意如果你发现自己有一个过程化的查询,你应该考虑重写或者重构它。

从查询到执行计划

知道反模式不是静态的,而是随着您作为 SQL 开发人员的成长而发展的,并且当您考虑替代方案时有许多要考虑的事实也意味着避免查询反模式和重写查询可能是一项相当困难的任务。任何帮助都可以派上用场,这就是为什么用一些工具优化查询的更结构化的方法可能是可行的方法。

还要注意上一节提到的一些反模式源于性能问题,比如ANDORNOT操作符以及它们缺乏索引使用。思考性能不仅需要更结构化的方法,还需要更深入的方法。

无论如何,这种结构化和深入的方法将主要基于查询计划,正如您所记得的,查询计划是查询的结果,它首先被解析为“解析树”,并准确地定义了每个操作使用什么算法以及如何协调操作的执行。

正如您在简介中所读到的,您可能需要检查和调优由优化器手动生成的计划。在这种情况下,您需要通过查看查询计划来再次分析您的查询。

为了掌握这个计划,您需要使用数据库管理系统提供的工具。您可能拥有的一些工具如下:

  • 有些包具有可以生成查询计划的图形表示的工具。看一下这个例子:

  • 其他工具将能够为您提供查询计划的文本描述。一个例子是 Oracle 中的EXPLAIN PLAN语句,但是该指令的名称根据您使用的 RDBMS 而有所不同。在其他地方,你可能会发现EXPLAIN (MySQL,PostgreSQL)或者EXPLAIN QUERY PLAN (SQLite)。

请注意如果您正在使用 PostgreSQL,您会发现EXPLAINEXPLAIN ANALYZE的不同之处,前者只是得到一个描述,说明计划者打算如何执行查询而不运行它,而后者实际执行查询并返回预期与实际查询计划的对比分析。一般来说,实际的执行计划是您实际运行查询的计划,而估计的执行计划是在不执行查询的情况下计算出它将做什么。虽然在逻辑上是等价的,但是实际的执行计划更有用,因为它包含了关于执行查询时实际发生的事情的更多细节和统计信息。

在本节的剩余部分,您将了解更多关于EXPLAINANALYZE的内容,以及如何使用这两个工具来了解更多关于您的查询计划和查询的可能性能的内容。

提示:如果你想更多地了解EXPLAIN或者更详细地看例子,可以考虑读一下 Guillaume Lelarge 写的书“理解解释”

时间复杂性&大 O

现在,您已经简要地检查了查询计划,您可以开始更深入地研究,并借助计算复杂性理论以更正式的术语来考虑性能。理论计算机科学中的一个领域,主要是根据计算问题的难度对其进行分类。这些计算问题可以是算法,也可以是查询。

然而,对于查询,您不一定要根据它们的难度来分类,而是根据运行它并获得一些结果所花费的时间来分类。这具体被称为时间复杂性,为了清楚地表达或度量这种类型的复杂性,您可以使用大 O 符号。

使用大 O 符号,您可以根据运行时相对于输入的增长速度来表示运行时,因为输入会变得任意大。大 O 符号排除了系数和低阶项,这样您就可以专注于查询运行时间的重要部分:增长率。当以这种方式表达时,去掉系数和低阶项,时间复杂度被认为是渐近描述的。这意味着输入大小趋于无穷大。

在数据库语言中,复杂性衡量的是随着数据表和数据库大小的增加,一个查询需要运行多长时间。

注意数据库的大小不仅会随着更多数据存储在表中而增加,而且数据库中存在索引这一事实也会影响数据库的大小。

正如您之前看到的,执行计划定义了每个操作使用的算法,这使得每个查询执行时间都可以在逻辑上表示为查询计划中涉及的表大小的函数,这被称为复杂性函数。换句话说,您可以使用大 O 符号和您的执行计划来估计查询复杂性和性能。

在下面的小节中,您将对四种类型的时间复杂性有一个大致的了解,并且您将看到一些示例,说明查询的时间复杂性如何根据您运行它的上下文而变化。

提示:索引是故事的一部分!

不过请注意,不同的数据库需要考虑不同类型的索引、不同的执行计划和不同的实现,因此下面列出的时间复杂度非常笼统,可以根据您的具体设置而有所不同。

在这里阅读更多。

总而言之,您还可以查看备忘单后面的来根据时间复杂度和查询的执行情况评估查询的性能:

SQL 优化

考虑到查询计划和时间复杂性,您可以考虑进一步调优 SQL 查询。你可以从特别注意以下几点开始:

  • 用索引扫描替换不必要的大表全表扫描;
  • 确保您应用了最佳的表连接顺序;
  • 确保您正在以最佳方式使用索引;和
  • 缓存小表全表扫描。

恭喜你。您已经完成了这篇博文的结尾,这篇博文只是让您对 SQL 查询性能有了一点了解。希望您对反模式、查询优化器以及用于检查、评估和解释查询计划复杂性的工具有了更多的了解。然而,还有更多的发现!如果你想了解更多,可以考虑读读 R. Ramakrishnan 和 J. Gehrke 写的《数据库管理系统》这本书。

最后,我不想隐瞒 StackOverflow 用户的这句话:

“我最喜欢的反模式不是测试您的查询。

这适用于以下情况:

-您的查询涉及多个表。

-您认为您有一个针对查询的最佳设计,但不想测试您的假设。

-您接受第一个有效的查询,不知道它是否接近优化。"

如果你想开始学习 SQL,可以考虑参加 DataCamp 的数据科学 SQL 入门课程!

最初发表于T5【www.datacamp.com】

SQLAlchemy-Python 教程

原文:https://towardsdatascience.com/sqlalchemy-python-tutorial-79a577141a91?source=collection_archive---------0-----------------------

我们经常遇到作为关系数据库的数据。为了使用它们,我们通常需要编写原始的 SQL 查询,将它们传递给数据库引擎,并将返回的结果作为普通的记录数组进行解析。

SQLAlchemy 提供了一种很好的与数据库交互的“Pythonic 式”方法。因此,您可以利用 SQLAlchemy 的 Pythonic 框架来简化您的工作流并更高效地查询数据,而不是处理传统 SQL(如 MySQL、PostgreSQL 或 Oracle)的特定方言之间的差异。

关于数据科学的其他故事可以在这里找到

安装软件包

pip install sqlalchemy

连接到数据库

为了开始与数据库交互,我们首先需要建立一个连接。

import sqlalchemy as db
engine = db.create_engine('dialect+driver://user:pass**@host**:port/db')

连接到各种数据库的一些例子可以在 这里 找到

查看表格详细信息

SQLAlchemy 可以用来通过反射从数据库中自动加载表。反射是读取数据库并基于该信息构建元数据的过程。

示例

询问

TableMetaData已经被导入。元数据以metadata.的形式提供

ResultProxy: *.execute()* 方法返回的对象。可以通过多种方式使用它来获取查询返回的数据。

ResultSet: 在 ResultProxy 上使用诸如 *.fetchall()* 之类的获取方法时,查询中要求的实际数据。

处理大型 ResultSet

我们使用.fetchmany()来加载最佳行数,并克服大数据集情况下的内存问题

while flag:
    partial_results = ResultProxy.fetchmany(50)
    if(partial_results == []): 
	flag = False
    //
	code
   //
ResultProxy.close()

转换为数据帧

df = pd.DataFrame(ResultSet)
df.columns = ResultSet[0].keys()

过滤数据

让我们看一些原始 SQLite 查询和使用 SQLAlchemy 的查询的例子。

其中

**SQL :**
SELECT * FROM census 
WHERE sex = F**SQLAlchemy :** db.select([census]).*where*(census.columns.sex == 'F')

中的

**SQL :**
SELECT state, sex
FROM census
WHERE state IN (Texas, New York)**SQLAlchemy :**
db.select([census.columns.state, census.columns.sex]).where(census.columns.state.*in_*(['Texas', 'New York']))

与,或,非

**SQL :**
SELECT * FROM census
WHERE state = 'California' AND NOT sex = 'M'**SQLAlchemy :**
db.select([census]).where(db.*and_*(census.columns.state == 'California', census.columns.sex != 'M'))

排序依据

**SQL :**
SELECT * FROM census
ORDER BY State DESC, pop2000**SQLAlchemy :**
db.select([census]).*order_by*(db.desc(census.columns.state), census.columns.pop2000)

功能

**SQL :**
SELECT SUM(pop2008)
FROM census**SQLAlchemy :**
db.select([db.*func.sum*(census.columns.pop2008)])

其他功能包括平均值、计数、最小值、最大值

分组依据

**SQL :**
SELECT SUM(pop2008) as pop2008, sex
FROM census**SQLAlchemy :**
db.select([db.func.sum(census.columns.pop2008).label('pop2008'), census.columns.sex]).*group_by*(census.columns.sex)

截然不同的

**SQL :**
SELECT DISTINCT state
FROM census**SQLAlchemy :**
db.select([census.columns.state.*distinct*()])

案例&投

case()表达式接受匹配的条件列表和条件匹配时返回的列,如果没有匹配的条件,则接受一个else_

cast()将表达式转换成特定类型的函数

举例

当结果只包含单个值时,我们对结果使用.scalar

加入

如果您有两个已经建立了关系的表,那么只需将每个表中需要的列添加到 select 语句中,就可以自动使用这种关系。

select([census.columns.pop2008, state_fact.columns.abbreviation])

例子

创建数据并将其插入表格

通过将不存在的数据库传递给引擎,sqlalchemy 会自动创建一个新的数据库。

更新数据库中的数据

db.update(table_name).values(attribute = new_value).where(condition)

删除表格

db.delete(table_name).where(condition)

放下一张桌子

table_name.drop(engine) #drops a single tablemetadata.drop_all(engine) #drops all the tables in the database

这个故事的 IPython 笔记本和其他资产可以在 这里 找到

再见😃

我的其他故事

posted @ 2024-10-13 15:17  绝不原创的飞龙  阅读(87)  评论(0编辑  收藏  举报