TowardsDataScience-博客中文翻译-2019-四十二-

news/2024/10/14 11:51:22

TowardsDataScience 博客中文翻译 2019(四十二)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

井字游戏的经验教训:实用强化学习技巧

原文:https://towardsdatascience.com/lessons-learned-from-tic-tac-toe-practical-reinforcement-learning-tips-5cac654a45a8?source=collection_archive---------12-----------------------

回顾我在开发第一个强化学习代理时做错的所有事情,这样你就可以把它做对了

就在最近我发了一篇介绍强化学习和深度 Q 网络的帖子。但众所周知,理解理论和在现实世界中实际实施之间存在巨大差异。

我花了一段时间才找到对 DQN 来说有价值的第一次挑战。我看到的大多数教程都实现了一个 DQN +卷积网,并试图设计一个击败雅达利或末日游戏的代理。这似乎分散了注意力:我看不出浪费时间设计图像处理网络来解决强化问题有什么意义。这就是我选择井字游戏的原因:它相当简单,所以我可以在我的 MacBook 上训练它,因为我可以编写游戏代码,所以不需要图像处理,但它仍然需要策略设计才能获胜。

虽然我认为这将是直截了当和简单的,但我很快就意识到我错了——因此,我想描述一下我在解决这个挑战时学到的一些最重要的经验。顺便说一下,的代码可以在我的 GitHub 页面找到。

1.把它分解成尽可能简单的任务

听起来很明显,这是我们偶尔都会忘记的事情。如果你读过我的对 DQN 的介绍,你可能记得我给了一个非常非常简单的游戏作为“Hello World”练习:一个需要填补空缺的代理(如果你还没有——别担心,我们很快就会回来)。这个练习不是我凭空想出来的。

当我决定实现井字游戏时,我坐下来一次写了几乎所有需要的代码:游戏类、玩家类、体验重放类、Q 网络类、双深度 Q 网络实现——然后推送 play。你猜怎么着?它什么也没学到。甚至不知道什么是有效或无效的移动,这是做任何事情的绝对基础。

现在去弄清楚是什么导致了这一切——是我代表各州的方式吗?这是超参数问题吗?代码有 bug 吗?如果有,在哪里?犯错误的可能性如此之多,却不知道从哪里开始。

所以我决定把它简化成我遇到的最简单的问题:代理能区分有效和无效的移动吗?然后,让我们训练一个代理,它只学习区分空缺和非空缺的位置。没别的了。这很快证明了自己,因为我能够隔离并修复我的网络实现中的几个 bug。然而,代理人拒绝学习。由于现在网络已经正确实施,我花了一段时间才意识到我错过了什么:

2.简单的任务只对你来说简单

如前所述,我给代理的简单任务是填充 4 单元板的所有空位。空单元格用“0”表示,填充单元格用“1”表示。你需要玩多少游戏才能理解其中的逻辑?可能不会太多。但你是人,而电脑不是。

Board representation. The second cell is filled, so a good action would be to choose any other cell

我认为几百个游戏应该足够了,但是事实证明我的实现需要大约 2500 个游戏来掌握这一点。事实证明,100-200 个游戏是不够的,成本几乎没有变化。更令人困惑的是,成本确实很低——但后来我发现,这是由于网络冷启动和培训次数不足(见我的实现)。基本上,我没有给网络足够的培训来学习任何东西——因为我低估了代理人学习这些有多难。

底线——对我们人类来说似乎简单的东西对计算机来说可能一点也不简单(反之亦然——计算 147x819 需要多长时间?).将模型训练得更长。

3.如何(不)定义下一个状态

在这一点上,我能够回到井字游戏的挑战。网络在工作,代理在学习。我可以很容易地看到它挑选出哪些动作是有效的,哪些是无效的,当我检查它如何玩时,很明显它学会了如何赢——它连续三次的尝试非常明显,我很高兴——但不是太多。尽管它学到了什么,但很明显他没有注意到他的对手在做什么,也没有努力尝试阻止他的对手连续三次。无论我训练它多长时间,我给网络增加了多少层,或者我调整了多少超参数——都没有改变这一点。

我花了比我想象的更长的时间才意识到我做错了什么。这与我看到的几乎所有 DQN 代码都是单人游戏的事实有很大关系——我不知道如何处理多人游戏。只有当我发现这个家伙的游戏实现时,我才明白我做错了什么——为此我必须解释我是如何设计这个游戏的。看看下面描述的游戏:

玩家 X 执行向奇数状态的转换,玩家 o 执行向偶数状态的转换。这正是我如何向模型的内存缓冲区添加记录的:如果 s=0 并且玩家 X 选择了左中间的单元格,那么 s'=1 。玩家 O 随后收到状态 s=1 并过渡到 s=2 。这是我添加到模型体验回放记忆中的两个单独的记录。

但是这意味着当轮到一个玩家玩的时候,他永远不会输。再来看 s=3 :玩家 O 选择了中上单元格,过渡到 s=4 。他还没输。现在轮到玩家 X 了,他做出了显而易见的选择,并转换到 s=5 ,然后赢了。直到现在,玩家 O 才知道他输了——因此,为了下一次有更好的判断,玩家 O 在 s=5 处收到的负奖励需要向后传播两个状态,直到 Q 值为 s=3 。理论上,由于贝尔曼方程的递归性和网络的反复训练,这应该不是问题。理论上。

实际上,这是行不通的——我认为有两个原因。第一个,也是更直观的一个,模型认为从 s=3 过渡到 s=4 没有风险,因为它不知道选择如何从 s=4 过渡的不是他。就模型所知,当处于 s=4 时,他可以简单地选择不同的动作,防止他失败。

一旦我意识到这一点,修复就很容易了——我所需要做的就是将下一个状态定义为玩家将看到的下一个棋盘表示——因此对于玩家 O,如果 s=3 并且动作是顶部中间单元格,那么s’= 5而不是4——现在模型可以知道这个动作将导致他输掉游戏。

第二个原因是什么?嗯—

4.请记住,网络只是一个近似值

在这个调试过程中,我检查了几次网络学习到的 Q 值,试图看看这是否有助于找到我做错了什么。我花了一段时间才意识到这毫无意义,我会解释原因。

这可能是一个回到我上面描述的我的“填充板”例子的解决方案的好点。如果你看一下我在那里实现的 Q 表和 Q 网络算法,你可以看到我在测试它们时绘制了所有 Q 值的预测。表中的 Q 值是有意义的(尽管由于训练过程中“较少选择的道路”有时会有点偏差),但 Q 网络预测值并非如此。这些和表格算法计算出来的完全没有关系。

仔细想想,这其实并不奇怪。请记住,网络只是一个近似值——你实际上要求它做的是预测最佳行动,这对应于它预测的最高 Q 值。想一想:你并不是真的要求网络学习正确的 Q 值,而只是要求最佳动作会有最高的预测值。这是两件完全不同的事情。当您记住成本函数在最小化时使用网络自己的预测时,网络无法预测正确的 Q 值就更有意义了-它没有可比较的基础事实。这是一个提醒:

Deep Q-Network cost function

我猜这里的关键信息是,虽然他们被称为深度 Q 网络,但 Q 值并不是他们实际学到的。令人困惑,但这就是生活。

最后的话

在发现新领域时,实现理论知识是最大的挑战之一。知道如何工作让它工作是不一样的。我希望这篇文章能在你的强化学习和深度 Q 网络之旅中对你有所帮助,我也很乐意听到你在开发自己的算法时学到的经验教训。让它发生。

在一家非科技公司作为一名孤独的数据科学家实习的经验教训

原文:https://towardsdatascience.com/lessons-learned-interning-as-a-lone-data-scientist-at-a-non-tech-corporate-b751dd79d8a8?source=collection_archive---------25-----------------------

Photo by Noah Silliman on Unsplash

对于我在 Medium 上的第一篇文章,我面临着两个可预见的老问题:“我应该写些什么?”以及“人们会觉得我写的东西有用吗?”。我觉得我最近在一家财富 500 强公司完成的实习,在那里我完成了一个面向产品的自然语言处理项目,为我提供了回答这两个问题的材料。

“我会写下我在一个如此流行的领域实习时学到的无数非技术性和技术性的东西,你不能改变睡姿而不迎头撞上一条相关的新闻。我有一个不寻常的视角,因为我独自在一家并非技术出身的公司工作。接下来,“对于对数据科学和 Medium 编程感兴趣的读者,我的帖子将提供一些参考点,如果这些读者走上与我相似的职业道路,会有什么样的期望。对于更倾向于其他行业/兴趣的人来说,尽管他们在睡梦中看到了“人工智能”和“机器学习”这两个术语,但感觉有一堵无形的墙阻止他们了解这些概念的日常实现是什么样子,我的帖子将试图在这面墙上打几个洞。

好吧,自我放纵的理由分类,这是我学到的:

1.问题构建和问题分解可能(而且经常)比编制解决方案更难

我可以感觉到经验丰富的数据科学家要么点头表示同意,要么对我所面临的问题的简单解决方案进行推理。不幸的是,考虑到就业立法,我无法真正记录我所处理的问题的本质,但我可以肯定地说,这比编写解决方案更让我夜不能寐。

一般来说,大公司的业务问题可能会跨越多个部门,每个部门都理所当然或错误地最关心与他们相关的后果。鉴于我实习期间的情况,提出一个问题公式,充分解决不同经理经常出现的分歧,证明是非常具有挑战性的。

现代劳动力变得专业化的程度进一步加剧了这种恰当的问题结构的困难。当问题是基于数据的时候,就像我的问题一样,很自然,不是每个部门的每个人都知道机器学习的能力和局限性。毕竟,这些人首先在他们自己的领域是熟练的,而机器学习毕竟是一个在最近 5 到 10 年才进入公众意识的领域。

经理可能会要求您做在广度或深度上超出当前可能(更有可能)的事情,或者要求不开发数据科学潜力的交付成果(不太可能)。

因此,为业务问题找到一个清晰的定义,并确定一个可实现的范围,比听起来要困难得多。做对了,你就成功了一半。弄错了,你会让冒名顶替综合症成为你最好的朋友。理想情况下,您应该为不同团队的经理提供他们在最终模型中寻求的解决方案,但我知道管理预期是一个巨大的挑战,作为一名数据科学家,我应该继续努力。

2.快速学习数据科学中的一个新的子领域是一项可以实现的重要技能

我开始实习的时候,只有不到一年的编程教育。在那段时间里,我从未见过一个关于自然语言处理的网页或演讲幻灯片。

在我第一天得知我将查看社交媒体文本数据后,走出办公室,你可以想象我当时惊慌失措的心情。我花了几个星期疯狂地试图理解简单问题的答案。NLP 的概述是什么样的?在 NLP 问题中,到底什么被认为是特征?我到底应该如何将文本转换成机器可读的输入呢?什么库是 NLP 任务中的主力?我以前学到的东西有适用的吗?

幸运的是,有很多资料和社区支持我选择的语言(Python ),数据科学家可以依赖。我从谷歌搜索和专门的编程网站学到了将近 90%我需要知道的东西。此外,我意识到强烈的滚雪球效应的存在。当你刚开始学习时,学习全新事物的惰性是最大的。但是当你让(雪)球滚动起来时,事情就变得容易了。

这并不等于说我确切地知道要找什么材料,在哪里找,这意味着

3.退出和重新启动经常发生

我花了很多精力去理解和学习 NLP 库。然而,我经常会在学习某个库的速成班中进行到一半,并在意识到由于这样或那样的原因它不能完全按照我想要的那样做之前做大量的笔记。我不得不重新开始做一些别的事情,这引起了很多沮丧的叫喊(下面会有更多)。我浏览了 NLTK(自然语言工具包,我所阅读的 NLP 库的 OG)、TextBlob 和 spaCy 等等。

导致我放弃我从一些库学到的大部分知识的问题包括:从一方面了解到 NLTK 不适合生产,到另一方面意识到 TextBlob 在我的特定问题上表现不佳。

退出和重启并不局限于学习图书馆这样的特定领域。它还扩展到更一般的任务;例如,仅仅理解 NLP 模型的流程就让我倒退了很多次。我是一名视觉学习者,看到一个流程的缩小视图以及一个步骤如何与另一个步骤相关联对我来说很重要。我经常会想“好吧,在花了几天时间之后,我终于明白了 C 和 D 的关系”。

然后我会意识到 C 和 D 实际上并不存在;它们只是占位符,以某种复杂的方式与 K 和 T 相关。我会放弃并重新开始,但是这些行为伴随着坚持,最终让我到达了我需要去的地方。

4.NLP 问题中的等级不平衡可能是慢性疼痛的来源

在分类问题中,当因变量中至少一个类别的数据点明显少于其他类别时,就会出现类别不平衡。假设我想根据“非垃圾邮件”和“垃圾邮件”对电子邮件进行分类。如果在我的训练数据中有 1000 个“非垃圾邮件”的例子和 100 个“垃圾邮件”的例子,这将是一个类别不平衡。

这种不平衡会对模型性能产生负面影响,但是当您的要素是数字时,处理这些不平衡通常不是什么大问题。您可以对多数类进行过采样,对少数类进行欠采样,甚至创建从现有数据中“学习”的合成数据点。

但是如果你的特征不是数字的,而是文本的,会发生什么呢?你创造了那些合成数据点吗?这是我发现自己面临的问题,但我正在处理社交媒体用户生成的文本,所以创建没有真正用户生成的人工数据点是不是“作弊”?我想是的。过采样和欠采样怎么办?当你的数据集很小的时候,这是不可能的。不幸的是,这就是我发现自己的处境。更不幸的是,对于这个问题,我还没有找到比“等待更多数据”更复杂的解决方案。

5.挫折是游戏的一部分,但意外的突破也是游戏的一部分

实习进行到一半的时候,一个朋友问我怎么样了。接下来,我无意中说出了一句意味深长的话(至少我的朋友是这么告诉我的):“10 天中有 7 天,我会用头撞墙。10 天中有 1 天,我试图爬过去,但却摔了个嘴啃泥。但在第九天,我设法跑过它,有时还绕着它跑。

Gif via Giphy

这准确地描述了我的进步。我会花几个小时尝试做一些简单的事情,比如加载预先训练好的单词嵌入,但都失败了。我让我的终端经历了几天的绞肉机,试图通过更新和重装让特定版本的包和库(看看你,TensorFlow 和 Keras)一起工作。

我没有计算机科学背景,所以大多数时候,我不知道我从栈溢出中复制粘贴了什么。到最后,情况变得如此糟糕,以至于我的电脑不再把熊猫当成图书馆;我甚至不能加载我的数据。

我的救星是那些陈词滥调的淋浴顿悟时刻,就我所见,这在我看来是数据科学家中的一个普遍现象。我会在一段代码上工作到晚上,没有进展就辞职。第二天早上,我的手经常会自己动起来,神奇地做出有用的东西。也许我睡觉的时候,我的大脑在后台嗡嗡作响,重新整理信息。

关键是,突破几乎从未通过认知蛮力的应用来实现。我学会了耐心,并希望我的潜意识思维能拯救我,这种情况发生了很多次。

最终

回顾我实习之初的心态,我低估了数据科学家所承担的非技术责任的重要性。尽管如此,整件事仍是一次令人惊奇的经历,我希望继续在 Medium 上记录我在这个领域学到的东西。

标记地标的经验教训(或者 Kaggle 如何踢我的屁股)

原文:https://towardsdatascience.com/lessons-learned-labeling-landmarks-or-how-kaggle-kicked-my-butt-8cea2a5be2b8?source=collection_archive---------17-----------------------

One of the easier landmarks to identify among ~15,000 others.

到目前为止,我已经在这场 Kaggle 竞赛中苦干了大约 5 个月——这可以分解为大约 99%的精力用于构建、改进和调试我的数据管道,最后 1%用于深度学习模型本身。随着继续培训和优化我的模型变得成本高昂,我希望从我的经历中获得我所能获得的(阅读:证明几个月的努力和大约 200 美元的 AWS 账单)以及一个简短的教训列表,这些教训有望在下一个项目中为我(和你)节省一些时间和金钱。

( Kaggle ,对于不知道的人来说,是 Google 在 2017 年收购的一个数据科学竞赛平台,也是数据科学入门的绝佳资源)。

1.使用 GitHub

Octocat ❤ (source)

从一个真正令人震惊的开始!这个并不太令人兴奋,也不难实现。在项目期间,我的“版本控制”是将我的 EC2 实例的状态保存为 AWS 映像,并在下次我想从我离开的地方开始时简单地从该映像启动。老实说,这不是一个可怕的方法,尽管每个月都有几个额外的钱,除非我的图像被破坏或取消注册,否则我所有的工作都会丢失(这从未发生过,但我有几次接近了)。

但是 GitHub 提供的不仅仅是另一种保存更改的方式。Jupyter 笔记本在模块化或多代码路径方面并没有提供太多东西,所以我最终使用了“科学怪人”笔记本:分散在各处的注释块,决定运行什么和以什么方式运行的布尔变量,以及带有不知什么版本的各种方法的笔记本副本。一旦我过渡到 GitHub 的版本控制,我就能够使用新的分支进行实验,而不必担心保留我的工作代码。例如,在使我的模型过度适应数据子集以确保它正确训练时,我不再需要担心用“should_subset”变量添加额外的流;相反,我可以随心所欲地分支添加[:1]。

Because OF COURSE we all carefully read EVERY line of our code before we run it each time…

然而,Jupyter 也不能很好地使用 Git,也不能提供模块化,这就引出了我的下一课:

2.。操场的 ipynb,。py 代表真正的工作

Is it just me or does the Jupyter logo look like someone with orange slices in their mouth? (source).

这可能会引起争议,因为 Jupyter 似乎是用于研究目的的事实上的工具,但是当您将自己所有的代码都写在 Jupyter 笔记本上时,您就放弃了很多。Python 不仅为您提供了适当的 Git 集成(而 Jupyter 是……缺乏的),还允许您轻松地编写库或“模块”!这意味着无论你在哪里调用一个方法,它都可以来自同一个代码块,而 Jupyter 笔记本不能在笔记本之间轻松地共享代码。

仅仅使用 Jupyter 会导致多个笔记本上有大量复制粘贴的代码,这些代码需要与源代码保持同步——这不是您在试图追踪数据管道中的 bug 时想要的!

这并不是说 Jupyter 在 Kaggle 项目中没有一席之地——我肯定会继续使用它进行数据探索和可视化。但是我也会在我的主 Python 文件中定义大多数方法,并将它们导入到我的笔记本中——这样我就知道在笔记本中工作的代码也将在我的管道中工作。不管你怎么做,可视化每一步的数据都是非常重要的(提示 3…)

3.可视化您对数据执行的每个转换

MS Paint seems to be this site’s visualization tool of choice.

我怎么强调都不为过。还记得我提到过试图追踪我管道中的一个 bug 吗?那是在大约一个月不知道它的存在之后,这是一个充满令人困惑的错误和糟糕结果的月份。在搜寻文档时,我看到了这篇文章,其中一个像素偏移花费了开发人员两个月的调试时间!

每次更改前后都要可视化数据,以确保操作按预期执行。如果是图像,就展示出来。如果是 CSV 数据,对汇总统计数据进行健全性检查,并确保替换 NaN 值。即使使用 NLP 数据,您也可以在词干前后打印文本,或者在 2D 或 3D 图上绘制嵌入向量。

Example of word embeddings reduced to 3D vectors. If instead, “man” is to “woman” as “king” is to “taco”, then you may have a bug to squash (source).

这些小检查将为您节省大量调试时间,意味着您不必回头再做。另外,您可以将可视化代码保存在单独的 Jupyter 笔记本中,这样它就不会碍事了!

4.针对正确的指标进行优化

Not quite as intuitive as accuracy or MSE (source).

这可能是一个很大的要求,但仍然很重要。许多在线 ML(专业人士称之为机器学习)教程提供了加载数据和训练模型的代码,它们几乎总是使用内置的度量标准之一,如分类准确性或均方误差。但是,如果你试图在大脑扫描中检测肿瘤,而竞争值回忆超过准确性(也就是说,你想尽可能多地抓住病例,以一些假阳性为代价),那么准确性不会训练你的模型表现良好!

See? Deep learning as easy as Copy-Paste! (source)

在开始处理数据之前,尤其是在开始处理模型之前,请务必查看竞争指标。有时一个标准指标就足够了,有时你不得不在一些随机的源代码文件中编写一个定制的目标函数,并且由于 Tensorflow 非常有趣的图形系统而遇到几乎无法诊断的错误(我的第一个 StackOverflow 帖子,遗憾的是没有得到答复)。

Wow, 3 whole upvotes! (Not going to link you to my embarrassing StackOverflow questions)

长话短说,当你甚至没有为正确的事情进行优化时,你不能指望挤掉数百个 ML 博士。

5.选择一个让你兴奋的比赛

When you learn coding just for the THRILLS (source)

这可能令人惊讶,但我的热情并不在于给历史地标的“业余”(蹩脚)智能手机图像贴上标签。随着我继续做这个项目,最初的兴趣消退了,我发现越来越难说服自己打开笔记本电脑,在上面多花几个小时。

与之形成鲜明对比的是,就在上周,我为一场办公室竞赛设计了一个快速行进的疯狂机器人;结果并不令人印象深刻(我在提交截止日期后的几个小时发现了一个 bug,但它就这样过去了),但我发现时间过得很快,像深度工作的风格,即使是在一整天的编程工作之后。我会把这作为未来比赛的一个教训,甚至是关于 Kaggle 的个人笔记:在排行榜上有一个排名来展示你的劳动成果是很好的,但如果你不能找到一个保持参与和不断改进的理由,你就无法做到最好。

外卖食品

写连贯的英语显然比写代码更难。但你应该看到,虽然 Kaggle 在让数据科学变得简单方面做得很好,但专业人士正在发布最先进的分数,因为他们有坚实的基础和从许多失败中建立的直觉,其中许多我还没有遇到过。

试图自学数据科学和机器学习可能很残酷,但我也从未在任何其他领域看到更多的合作和高质量的免费资源。坚持下去!感谢阅读!

PS:如果有人想尝试一下谷歌地标识别挑战赛,请查看我的内核,下载数据集到 S3 的 TFRecord 文件!

更多信息请关注我的 Twitter @Eli_password123!

使用 Google Cloud BigQuery ML 的经验教训

原文:https://towardsdatascience.com/lessons-learned-using-google-cloud-bigquery-ml-dfd4763463c?source=collection_archive---------11-----------------------

云自动机器学习工具(第 1 部分)

使用德国信贷数据的全程 ML 演示

动机

我经常听到的一个新流行语是“为大众民主化人工智能”。通常接下来是一个建议的云机器学习工具。这些工具的统称似乎是 AML,或自动机器学习。作为一名数据科学家,我很想研究这些工具。一些问题浮现在我的脑海:AML 到底能做什么?我可以在我通常的建模工作流程中使用这些工具吗?如果有,如何实现,为了什么利益?我作为一个拥有 ML 技能的人类的有用性会很快消失吗?

我的计划是演示最流行的 AML 工具,每次都使用相同的“真实”数据集,比较运行时间、拟合指标、生产步骤以及一些用户界面截图。

在我最近的工作中,我需要建立和部署金融欺诈检测模型。我不能在公开的博客文章中使用专有数据,所以我将使用众所周知的公开数据集德国信用数据。注意,成本矩阵是每个假阴性 5 DM,每个假阳性 1 DM。尽管数据很小,但我将介绍所有用于真实数据的技术。所有演示的代码将在我的 github 上。

我的计划是涵盖这些流行的反洗钱工具:

  • 第一部分(本帖):谷歌云平台上的谷歌大查询(GCP) 。

第 2,3,4 部分即将推出,希望(!) :

  • 第二部分: H2O 的 AutoML ,以及思科的 Kubeflow 超参数调优。重点是算法对比和超参数选择。
  • 第三部分:在谷歌云平台(GCP)上使用 Keras 的 tensor flow 2.0。
  • 第 4 部分:使用 Scala 的 AWS 上的数据块 MLFlow

BigQuery ML —步骤 1)创建数据

让我们开始吧。谷歌的 BigQuery 提供了大量免费的公共数据集。你可以在这里搜索它们。我没有看到任何信用数据,所以我用谷歌的 BigQuery 沙箱上传了我的。BigQuery sandbox 是谷歌的 GCP 自由层云 SQL 数据库。这是免费的,但你的数据每次只能保存 60 天。

https://cloud.google.com/free/

https://cloud.google.com/bigquery/docs/sandbox

对于所有的谷歌云工具,你必须首先创建一个谷歌云账户和一个项目。接下来,分配沙盒资源给项目按照这些指示。现在转到https://console.cloud.google.com/bigquery,这是网络用户界面。接下来,固定您的沙盒启用项目(见左下截图)。接下来,使用 Web UI 加载您的数据。我把我的表叫做“allData”。

德国信贷数据是一个非常小的数据集,只有 998 行。通常,最佳实践是将您的数据拆分为 train/valid/test,但由于这很小,我将拆分为 80/20 train/test,并使用交叉验证技术将 train 扩展为 train/valid。注意:我创建了一个假的“uniqueID”列(见右下截图),以帮助随机拆分。

Create train and test tables

下面是我用来创建“trainData”和“testData”的 SQL,它们是从“allData”中随机抽取的行。

CREATE TABLE cbergman.germanCreditData.testData AS
SELECT *
FROM `cbergman.germanCreditData.allData`
WHERE MOD(ABS(FARM_FINGERPRINT(CAST(uniqueID AS STRING))), 5) = 0;CREATE OR REPLACE TABLE cbergman.germanCreditData.trainData AS
SELECT *
FROM `cbergman.germanCreditData.allData`
WHERE NOT uniqueID IN (SELECT DISTINCT uniqueID FROM `cbergman.germanCreditData.testData`
);

现在,我已经在 BigQuery 中加载了分别包含 199 行和 798 行的表。检查随机样本做了正确的事情:

SELECT count (distinct uniqueID)
FROM `cbergman.germanCreditData.allData`
where response = 2;# repeat for train, test data...

请参见下面的最后一行,我最终得出每个所有/训练/测试数据集的负(响应=1)与正(响应=2)比率分别为 30%、29%、32%,这看起来是一个很好的采样:

大查询 ML —步骤 2)训练一个 ML 模型

在写这篇文章的时候,API 给了你 3 个算法的选择:回归,逻辑回归,或者 K-最近邻。

更新 2019 年 12 月:自撰写本文以来,谷歌已向 BigQuery ML 添加了 2 种新算法:多类逻辑回归和 Tensorflow!

在创建你的模型之前,通常你必须:1)确保业务目标明确:“尽可能自动地抓住最多的欺诈资金”。在我的工作中,欺诈资金被进一步分为不同类型的欺诈,例如第三方欺诈。2)接下来,您通常必须将其转化为数学模型算法:在这种情况下,分类选择 API 方法逻辑回归。3)接下来,你定义损失函数,这在真实的公司中是很棘手的,因为一个部门可能会说新用户更重要;而风险部说所有的欺诈都更重要。例如,在我工作的一家公司,他们无法就一项损失指标达成一致。然而,这个问题在这里得到了解决,这个公共数据的创建者给出了一个成本矩阵,每个假阴性 5 DM,每个假阳性 1 DM。

完成业务定义后,请看下面的屏幕截图,如何通过从查询编辑器运行 SQL 查询来训练基本模型。在训练细节下,每次迭代的损失是递减的,这是我们预期的;由于这是一个逻辑回归,损失是对数损失。

Train a model in BigQuery ML

下面是创建模型并检查模型是否适合训练和测试数据的 SQL。

# Create the base model
CREATE OR REPLACE MODEL cbergman.germanCreditData.baseModel OPTIONS(input_label_cols=['response'], model_type='logistic_reg') AS 
SELECT * EXCEPT (uniqueID) 
FROM `cbergman.germanCreditData.trainData`;# Model fit on train data
SELECT *
FROM ML.EVALUATE(MODEL `cbergman.germanCreditData.baseModel`, 
(SELECT * EXCEPT (uniqueID)FROM `cbergman.germanCreditData.trainData`);# Model fit on test data
SELECT *
FROM ML.EVALUATE(MODEL `cbergman.germanCreditData.baseModel`, 
(SELECT * EXCEPT (uniqueID)FROM `cbergman.germanCreditData.testData`);# To view your linear beta-values
SELECT * from ML.WEIGHTS(MODEL cbergman.germanCreditData.baseModel);# To get test data confusion matrix
SELECT *
FROM ML.CONFUSION_MATRIX(MODEL `cbergman.germanCreditData.baseModel`,
(SELECT* EXCEPT (uniqueID)FROM `cbergman.germanCreditData.testData`);

我的基线逻辑回归在 1 分 36 秒内训练,在 0.7 秒内运行测试,训练 ROC_AUC = 0.84,测试 ROC_AUC = 0.75,回忆= 0.41,成本 38 * 5 + 12 = 202 DM。

我注意到火车 AUC 是 0.84,所以发生了一些轻微的过度拟合。我并不感到惊讶,因为所有的变量都被使用了(选择*),而且逻辑回归是一个线性模型,它要求所有的输入都是独立的。创建基线线性模型的一部分是清理共线输入。我知道如何在 Python 中做到这一点,所以这是我稍后将转向的地方。

同时,我们可以检查并保存逻辑回归模型系数的β值,以及排除验证数据的混淆矩阵和性能指标。注意:除非您另外指定,否则默认阈值将是 0.5。我计算了标准化和非标准化的默认混淆矩阵,并将它们保存在模型比较表中(我备份了 Google Sheets 中的系数和性能统计表,WebUI 中非常简单的菜单导航,因为我知道我的免费数据将在 60 天后消失)。

步骤 3)特征工程

下面是一个有经验的从业者如何获得更好的模式的“秘制酱”。我现在切换到 Jupyter 笔记本,因为我知道如何在 Python 中清理共线输入。我首先检查数字列的相关性。下面,右边突出显示的红框,我们看到数量和持续时间相关 63%。这是有道理的,贷款的金额和期限都可能一起增加,我们可以在 pair-plots 中证实这一点(左边红色轮廓的小图)。下面,底部一行显示了所有的数字变量对响应 1 或 2 绘制,显然没有什么看起来相关。我将删除持续时间字段。

Top left: pair-plots amount and duration. Top right: Numeric variables only correlations. Bottom: Plot response vs each numeric variable.

相当多的变量是字符串类别。我想对字符串变量进行 VIF 分析,为此我已经用 Python 实现了信息 R 包,有时称为“使用信息值的证据权重”。信息或 WOE 宁滨的想法不仅仅是通过一键编码添加新变量,而是实际上按照响应变量的线性升序对类别进行分类和编号。例如,如果您有类别为“汽车”、“船”、“卡车”的变量“车辆”,那么将选择转换为数字 1、2、3(例如代表汽车、船、卡车)来表示它们给出的关于响应变量的“信息增益”。所以,你的回答不会是 1,2,3,而是一个信息对齐的数字。

我在本文底部的参考资料部分添加了几个关于“信息宁滨”的链接。

在我做了信息线性宁滨后,我可以计算波动率指数并重新运行相关性,见下面的结果。

Left: VIF factors. Right: correlation heatmap

VIF 因子在左上方。有趣的是,就方差解释而言,工作和电话看起来密切相关。也许失业/非居民不太可能有电话?另一个方差-覆盖率对看起来像性别与其他债务人相关。嗯,这表明已婚/离异女性更有可能有一个共同申请人。工作和电话位于冗余差异解释器的顶部,因此基于 VIFs,我将放弃电话字段。

右上方的相关性现在看起来清晰多了。唯一担心的可能是 n_credits 与 credit_his 的关联度为 40%,而 property 与 housing 的关联度为 36%。基于相关性,我会放弃 n_credits 和 property。

总之,我删除了持续时间、n_credits、属性和电话字段,并添加了对数字特征计算的对数转换。我最初的 21 个字段现在变成了 64 个全数字字段。主要是因为增加了数字变换:均值、中值、最大值、最小值和对数变换。由于使用了信息宁滨而不是热编码,我的类别字段数保持不变。

接下来,我将通过弹性网套索变量选择运行我所有的转换变量。(注意:如果有人问我谁是我心目中的英雄,我的第一反应会是特雷弗·哈斯蒂!).通常使用 k 倍交叉验证,k=10 倍是最佳实践。与每折叠 N/k 的样本数相比,更多折叠的代价是平均运行次数更多(k=10)。由于我的数据很小,我选择了 k=4 折叠交叉验证,因此每折叠有 199 个样本。我以下面的模型结束。

Top left: Confusion matrix. Middle left: ROC curves. Top right: Standardized coefficients. Bottom: Precision, Recall curves vs Threshold.

在左中上方,ROC 曲线看起来相当一致。在底部上方,训练和有效的精确召回曲线似乎在阈值= 0.9 附近相交,这显示了令人放心的一致性。在右上角,最大的系数是“支票账户”。我可以查看信息宁滨,以升序排列 A11(负余额)、A12 ( < 200DM), A13 (> = 200DM)、A14(无支票账户)来预测获得贷款。我们还注意到金额和期限与获得贷款负相关。奇怪的是,“工作技能水平”似乎对预测“好”或“坏”的贷款结果没有太大影响,对于“非技术-非居民”对“非技术-居民”对“管理/官员”。也许这一切都有道理,我可能会想与领域专家检查这一点。

目前,我坚持使用这个逻辑回归模型,它在 3.6 秒内训练,在 0.5 秒内运行测试数据,训练 ROC_AUC = 0.81,测试 ROC_AUC = 0.83,成本为 11 * 5 + 34 = 89 DM。 我们比基本型号节省了 50%的成本!!并且使用更少的变量,训练和验证之间的差异更小。这种模式显然是一种改进,如果我们参加比赛,我们会在 Kaggle 排行榜上,因为 top score 的测试 AUC 约为 78%。很好。

在特征工程之后,接下来的步骤通常是:
1)算法比较
2)超参数调整
3)阈值调整

我认为,通过尝试其他算法,进行超参数和阈值调整,我们甚至可以做得比我们自己的 83%更好,但我将在本博客系列的稍后部分演示这一点。

步骤 4)创建使用 BigQuery 模型的 ML 管道

回到我如何在现实生活的 ML 流水线中使用 BigQuery。在我目前的公司,用户并不期望他们的信用申请得到立即的回应。因此,我们可以使用批处理进行“实时”评分。下面是我的 BigQuery 批处理管道可能的样子:

  1. 以上面的特征工程 Python 脚本为例,在 allData 上运行一次。
    最终结果:另一个名为“transformedData”的 bigQuery 表。
  2. 像以前一样将转换后的数据分成训练/测试
  3. 使用交叉验证训练另一个 GLM 模型,与之前的过程相同,但仅限于“trainTransformedData”表(而不是“trainData”),并且仅选择我的最终模型中的最终特征(而不是 select *)。
    最终结果:glmModel 而不是 baseModel。
  4. 将 glmModelCoefficients,modelComparison metrics 保存为 Google Sheet(更永久,回想一下 GCP 大查询免费层每 60 天消失一次)。
    最终结果:多了两个表:glmModelCoeffiecients,modelComparisons(带有 Google Sheets 中的备份)
  5. 采用与步骤 1)中相同的要素工程 Python 脚本,将其转换为批处理作业,每隔几个小时仅对尚未转换的新数据运行一次。
    最终结果:另一个名为“testTransformedData”的 BigQuery 表,标记为 model_run=false。
  6. 进行实时预测-将另一个批处理作业添加到在上述步骤 1)后每 1.5 小时运行一次的批处理作业编制器中。
    最终结果:所有传入的新数据每 2 小时运行一次,批量实时获得推理分类。

步骤 6)要运行 BigQueryML,只需在 Java 或 Python 脚本中添加一条 SQL 语句:

# SQL to run inference on new data
SELECT*
FROMML.EVALUATE(MODEL `cbergman.germanCreditData.glmModel`, (
SELECT   'chk_acct_woe', 'credit_his_woe', 'purpose_woe', 'saving_acct_woe', 'present_emp_woe', 'sex_woe', 'other_debtor_woe', 'other_install_woe', 'housing_woe', 'job_woe', 'foreign_woe','amount_logmean', 'installment_rate_logmedian', 'present_resid_logmedian', 'age_logmedian',  'n_people_max'
FROM `cbergman.germanCreditData.testTransformedData`
WHERE model_run = false);# Tag inferenced data so it won't be re-inferenced
UPDATE `cbergman.germanCreditData.testTransformedData`
SET model_run = true;

摘要

我们使用 Google 云平台 BigQuery ML 工具进行了自始至终的 ML 建模。我们使用原始 Python、Scikit-learn、pandas、matlab、seaborn 来进行特征工程。把它变成一个脚本来进行特性工程,作为一个额外的数据工程步骤来创建转换后的 BigQuery 表。实现了一个逻辑回归模型,其测试 ROC_AUC = 0.83,成本为 11 * 5 + 34 = 89 DM(这将使我们进入 Kaggle 排行榜前 10 名)。

我的印象是,就像现在的 BigQuery ML 一样,如果没有额外的特性工程工作,你还不能得到一个值得 Kaggle 使用的好模型,但是你可以得到一个快速的基线模型。谷歌显然正在把资源放在它的 BigQuery ML 产品上,上个月有两个新的算法。仅此一点就说明这是一款值得关注的产品。即使是现在,我也要说这是一个值得学习的 AML 工具,并放入你的云 AI/ML 从业者工具箱中。

下一篇帖子,我将演示使用 Tensorflow 2.0 在相同的数据上构建深度神经网络。

资源

  1. BigQuery 文档页数:https://cloud.google.com/bigquery/docs/
  2. 博客作者谷歌的 BigQuery O'reilly book 作者:https://towards data science . com/how-to-do-hyperparameter-tuning-of-a-big query-ml-model-29ba 273 a 6563
  3. 一般反洗钱:【https://www.automl.org/book/
  4. 我的 github:【https://github.com/christy/MachineLearningTools
  5. 开放信用数据集:https://archive . ics . UCI . edu/ml/datasets/statlog+% 28 german+credit+data % 29
  6. 本文中提到的“信息宁滨”的 r 包:https://cran . r-project . org/web/packages/Information/index . html
  7. 对“信息宁滨”的进一步解释:http://u analytics . com/blogs/information-value-and-weight-of-evidence banking-case/

请随意使用我的截图和代码,但请做一个好公民,如果你想在自己的工作中使用它们,请记得注明出处。

如果你对我的文章或人工智能或人工智能有任何反馈、评论或有趣的见解要分享,请随时在我的 LinkedIn 上联系我。

让我提醒你一下:在机器学习中,准确性不是一切。

原文:https://towardsdatascience.com/let-me-recall-you-this-accuracy-isnt-everything-in-machine-learning-8e3a84ce0a8?source=collection_archive---------42-----------------------

为什么在评估你的机器学习模型时,回忆如此重要?

source

数据科学专业人士每天都在思考一件事:这个模型真的有效吗?数据就像一个活生生的生物,几乎每天都在变化和变得混乱。最后,我们想要的只是找到一种方法来处理它并做出好的预测,但是我们怎么知道我们的结果有多有价值呢?

嗯,最基本的事情之一是评估我们结果的成功率,或者说我们正确预测了多少测试数据。如果这个数字很高,理论上我们的模型做得很好。我们喜欢称这个值为精度

起点是理解我们试图预测什么。它可以是一个数字,一个类,甚至是一个是/否问题的答案。了解这些之后,我们就可以定义评估性能的参数了。对于本文,我将使用一个模型来尝试预测客户在网上购物体验后留下的评论是好是坏,这是一个典型的分类问题,有两种可能的结果:

0 =不是好评论

1 =是好的评论

为了回答这个问题,我做了传统的步骤:数据清理和特征选择,然后我训练了几个模型,挑选了一个并试图改进它。你可以在我的 GitHub 上找到完整的项目,包括我使用的数据集,在这里。

最初,我尝试了 3 种分类算法:KNN、随机森林和支持向量机(SVM),使用了 scikit-learn 上提供的原生函数,并在每个模型上调整了一个参数。让我们来看看结果:

Source: author

让我们开始看看“F1 的准确性”一栏。在这里我们可以看到结果非常相似,每个都是 80%左右,这意味着从所有的预测来看,算法在 80%的时间里都是正确的,如果我们只有这些信息,这看起来很好。但是,当我们查看类“0”和“1”的召回时,这些值是完全不同的。但这意味着什么呢?

通俗地说,回忆列显示了一个模型在正确预测一个类的真实正面方面有多好。在上面的例子中,如果我们检查类别“0”的召回,在 KNN 算法中我们得到的值是 0.13。这意味着该模型只在 13%的时间里正确地分类了那个类。看起来很糟糕,确实如此!另一方面,我们可以观察到,类别“1”的召回率比类别“0”高得多,这推动了整体准确性的提高。

所以,在第一次尝试后,我选择了随机森林,因为它的召回率和准确率都比其他两种算法高。为了提高我的结果的质量,我使用了一些技术,如 上采样 少数类,以及 Gridsearccv来调整三个超参数。我不会在本文中讨论这些细节,因为我将在后面写更多关于模型改进的内容。

最主要的一点是:成功了!让我们来看看我改进后的结果:

source: author

像以前一样,让我们从 F1 分数开始,它从 80%跃升到 93%,表明该模型预测的准确性更高。但是当我们查看召回时,特别是对于“0”类,它从 24%增加到 96%,这是一个相当好的改进,不是吗?现在,这两个类都有了更加稳定和可靠的结果,即使对于部署来说还不理想,它也提供了更多的提示,告诉我们如何让它更好地工作。

今天就到这里。精确度很好,但绝对不是评估机器学习性能的唯一参数。目标是强调回忆的意义和重要性,我希望这篇文章对任何学习数据科学魔力的人都有用!

资源:

维基百科,精确和召回。可在:https://en.wikipedia.org/wiki/Precision_and_recall

GitHub 库:https://github.com/lucasmoratof/customers_review_project

让孩子们进图书馆

原文:https://towardsdatascience.com/let-the-kids-into-the-library-8ae59af7e3fc?source=collection_archive---------12-----------------------

在云中建立数据驱动型公司的固执尝试。

声明:在 Spotify 工作 5 年后,我现在在谷歌的云团队工作。观点是我自己的,而不是我过去或现在雇主的观点。

Photo by bantersnaps on Unsplash

在云中建立数据驱动型公司的 10 个步骤

Photo by Justin Wang on Unsplash

一天,我订购了一个新的耳机,它到达时已经坏了。所以我联系了我购买它的公司要求一个新的。他们甚至没有要求照片证明,就寄给我一双新的。

起初,我认为一定有很多人欺骗他们的支持服务来免费获得第二个耳机。
但后来我意识到这家公司很可能是数据驱动型的。你是想投资解决 1%的边角案例,还是应该专注于 99%并改进你的产品?雇用一个支持团队来处理少数收到坏耳机的顾客,与不问问题就运送一副全新耳机相比,成本是多少?

能够像这样自信地做出数据驱动的决策,不仅能为您的公司节省时间和资金,还能带来许多其他好处,例如:

  • 消除产品开发中的偏见。有多少产品因为某人有了一个伟大的想法而失败?
  • 了解顾客想要什么。通过实验,您可以在趋势发生之前识别它们,并且更加主动。

在了解 【资料网】 的概念之前,我写了这篇文章。下面给出的 10 个步骤可以看作是分布式域驱动架构的实现指南,由 Zhamak Dehghani 描述。

1.改变比工具更重要

突发新闻:选择更快的数据仓库不会让您的公司更加数据驱动。

许多公司往往天真地认为,开始将所有数据推送到云、下一代数据仓库就足够了,奇迹就会开始发生。虽然更快的洞察途径是必要的(因为没有人愿意等待 4 个小时来完成一个查询),但这是不够的。更重要的是不同的团队在做出数据驱动的决策时如何合作。阅读【Spotify 上的 DIBB 框架】。

这就是为什么在评估云数据仓库时,您不应该将所有精力都放在运行速度最快的基准测试上。相反,您应该评估:

  • 发现、共享、复制、转换数据集的难易程度,以及是否支持列表一致性或高并发性等关键协作特性。
  • 获取数据是多么容易。例如,如果您必须安装一个 native client,打开一个防火墙端口,连接到不同的实例…或者如果所有数据都可以通过一个简单的 URL 并从同一个 API 安全地访问。【beyond corp 研究论文】。
  • 随着数据的增长和时间的推移,扩展有多容易。因为如果你不得不继续依赖基础设施团队来扩展你的集群,它最终会成为一个瓶颈。因此,请确保诸如重新集群和 vacuum 之类的维护任务得到完全管理或毫不费力,并确保新的数据仓库将以无服务器的方式满足您未来的需求。
    就这一点而言,大数据格局每 6 个月都会发生或多或少的变化,所以选择一个盟友【持续创新】,这样你就不会以构建明天的遗产而告终。

2.从数据基础架构到数据运营

30 年的建筑应用可以简单地总结如下:

【单片应用】 = > 【多层架构】 = > 【微服务】

没有理由为什么同样的变化不能应用于数据工程。DevOps 原则毕竟不是软件工程独有的。
贵公司是否仍有基础设施团队维护和调整您的数据仓库?你所有的分析仍然是集中的吗,就像软件开发过去集中在大型计算机上一样?是时候让数据跟随微服务革命了!

但是,请不要马上解雇您的基础架构团队。这个团队的自然发展是让他们向上移动,开始成为一个数据运营团队。【为什么做 data ops】。为了避免孤立的实现,您的公司将需要他们有价值的工作来引导数据工程堆栈朝着正确的方向发展。正如开发人员所倡导的那样,他们的新使命是让其他团队在他们的数据之旅中取得成功,例如通过构建公司特定的框架(这就是【Scio】在 Spotify 诞生的方式)、模板或测试工具。他们应该拥有不同的自助服务工具,供数据工程师用于 CI/CD、数据治理、数据访问和匿名化、编排、计划和事件交付。

如下图所示,该团队的一些数据工程师也可以嵌入其他产品领域,以便在您组织的不同部门教授和提升数据专业知识。
数据分析不再是一个团队的工作,它应该是所有团队都可以自主完成的事情它应该是用例驱动的
每个产品领域应该能够定义和跟踪他们的关键指标,例如,MAU(每月活跃用户),以便他们能够迭代和改进他们正在发布的功能。

就像一些公司【决定不要首席技术官】一样,你应该质疑在你的公司里雇佣一个分析/数据(科学)主管是否有意义,或者相反,数据应该是一个分布在不同任务中的专业领域,以遵循【康威定律】。

3.降低壁垒

现在,您的公司可能只有一个人手不足的数据分析团队,他们以一种漂亮的星形模式仔细分类您的所有数据,就像一位老图书管理员会仔细整理和分类他所有的书籍一样。

如果你想让你的公司转型,变得更加数据驱动,你必须让孩子们进入图书馆。通过这个类比,我的意思是:让你的所有员工,而不仅仅是数据专家,访问数据。这个概念并不新鲜,也被称为数据民主化

没有人应该再拥有数据仓库,它应该是多租户的。数据应该属于它所源自的不同产品领域,因为这些团队拥有可以确认数据确实正确的业务逻辑。

数据运营团队应该提供工具来降低所有员工的门槛,而不仅仅是 Java 或 Python 开发人员。

  • ETL/ELT 应该对每个人来说都很容易做到,也许是通过 SQL 而不是 Java,也许是使用一个具有拖放界面的数据集成工具,例如【CDAP】或【马蒂利翁】。
  • 确保容易采用机器学习。现在,您可以使用 AutoML 产品或直接用 SQL 编写 ML 来获得很好的结果。【大查询 ML】。当然,如果你的 ML 专家想要培训和部署定制模型,也应该是可能的。看看【kube flow】也许吧。

参考资料:

  • 以安全的方式实现数据分析、可视化和机器学习的民主化是重中之重【对于 Twitter 的数据平台团队】。
  • 观看【来自 Spotify 的此番谈话】关于“降低摩擦”,透露 25%(!!)的员工现在使用数据仓库。

4.关于这个语义层

一开始,拥有一个语义层似乎是一个好主意,这样孩子们就知道去图书馆哪里找到他们最喜欢的书。
在遗留数据仓库中,数据通常被建模为数据仓库或 Kimball 星型模式,以支持语义层。但是这些方法现在已经【25-30 岁】如果说 NoSQL 的崛起已经扰乱了数据建模一次,那么大数据和云可能是标准化数据模型的又一枚钉子。
事实是,维护一个对公司每个人都有意义并且每个人都容易查询的总体语义层真的很难。随着时间的推移,这种语义层甚至有可能因为缺乏灵活性而降低您的分析速度。

为了说明这一点,我们举一个例子,定义一个语义层来表示 Spotify 这样的应用程序,见下文。

给定这个简化的雪花图式,下面是一个请求示例:给我 2018 年在瑞典演奏的前 10 名艺术家。
数据模型应该允许这样的查询,而不必在复杂且容易出错的查询中连接 5 或 6 个表,这样的查询最终会扫描整个数据集。您所做的查询应该定义您的数据模型

对于不擅长编写 SQL 查询的人来说,从生成的<top_played_artist>表中找到前 10 名艺术家不是更容易吗?</top_played_artist>

为了实现真正的数据驱动,你必须释放数据,让不同的团队随心所欲地复制粘贴、构建管道和分割数据,以解决他们的问题,而不是强迫他们根据通用的语义法则格式化数据。
这就是数据契约发挥作用的地方。

请注意,我并没有完全放弃保留语义层的想法。如果你不知道你在找什么,它会很有用。对于 BI 仪表板中的数据探索,表示不同数据点集合在一起的语义层是有意义的。但是它应该被定义为一个逻辑层,而不是在物理表上强制任何特定的模式。【LookML】。

补充阅读:
[【Kimball 维度建模在现代数据仓库中是否仍然相关?]](https://discourse.getdbt.com/t/is-kimball-dimensional-modeling-still-relevant-in-a-modern-data-warehouse/225/5)

5.数据契约

你可以说是【API 指令】改变了亚马逊,诞生了 AWS。我相信,如果你想建立一个数据驱动的公司,你应该考虑采用类似的原则,并像对待 API 端点一样对待数据。您的开发 ETL/ELT 管道的团队应该开始使用数据契约进行交流,通过【SLOs】进行衡量。

回到我们上面的前 10 名艺术家的例子,这里有一个使用数据契约解决这个问题的典型过程:

  1. 首先,我们不要多此一举。也许另一个团队已经创建了一个数据端点(=共享数据集),可以解决我们的问题。在你的【数据目录】里找吧。
  2. 如果没有找到现有的数据集,去和拥有计算前 10 名艺术家所需数据的团队谈谈。如果多个团队都有这个数据,找到真相来源。两个选项:

a)查看公司数据谱系,事实的来源可能是起点(最上游的数据集)。通常,它是来自 OLTP 系统的数据转储或【CDC】。
不用说:不要把你的数据管道直接连接到他们的 OLTP 系统。

b)查看数据治理元数据标记,可能有一个(下游)数据集被提升为真实的来源。
这被称为 MDM(主数据管理),如果你正在转向 BigQuery,我推荐关于这个主题的【这篇优秀的读物】。

3.一旦你找到要交谈的团队,就数据契约达成一致,并让他们为你公开一个数据端点,就像你在两个团队之间构建一个松散耦合的微服务架构一样。

如果上面的团队 2 不精通数据工程,也许团队 1 可以计算前 10 名艺术家,并在数据集中公开,或者你可能同意另一个团队 3 为公司的其他人做这件事。

这个数据契约是关于数据模式和服务级别目标的协议:可用性、响应时间、质量等。通过相互交谈,两个团队知道他们已经创建了这个链接,如果需要更新,他们将必须就新的合同达成一致。这个契约确保了这个实现不会在几个月后雇佣新的工程师时变成一个过时的依赖。

你可能已经发现我们反规格化了我们的雪花模式。为了使查询更简单,我们牺牲了一些一致性和存储空间。没有更复杂的语义层来容纳两个团队。SQL 初学者现在可以编写查询。

最佳实践是对您的模式进行版本化,并将它们上传到您在数据契约文档中引用的公司模式注册中心中。

6.放护栏,以后再关心成本

Photo by Dominik QN on Unsplash

您不应该回避使用上述数据契约方法复制数据。云中的存储很便宜,你只需为你使用的东西付费,如果成本成为一个问题,你可以调整旋钮。

尝试在云中使用星型架构*来优化存储空间,就像在连接到互联网时关心使用哪种 TCP 变体一样,这在 90 年代很有趣。相反,把你的工程时间花在【夸张】用例上。现在,您不再受以前数据中心容量的限制,可以开始接收更多日志和数据了。如果由于数据驱动的决策,您可以获得 100 倍的额外收入,那么花 1000 美元购买存储是完全可以的。

*在发明列存储之前,星型模式曾经是压缩事实表的好主意:)

7.数据大学

Photo by Vasily Koloda on Unsplash

将一些软件/后端工程师转变为数据工程师,并运行一个内部【数据大学】项目!

使用像 Apache Beam 这样的框架,如果您是一名懂 Java 或 Python 的软件开发人员,您应该能够很快学会如何创建您的第一个数据管道。

8.数据质量不是可选的

【不正确的数据比没有数据更糟糕】。为了确保数据质量,您可以:

  • 培养质量第一的心态,委托你的数据工程师去测试他们正在做的事情。这可能比雇佣一个专门的 QA 测试团队更有效。游戏化可以鼓励正确的行为。例如:为数据管道引入不同级别的测试认证,当你升级时有一个奖励系统。在 Spotify 上阅读关于【TC4D】的内容。
  • 将您的业务流程分解成多个工作流程。既然您让不同的产品团队开发他们自己的数据管道,他们将需要某种编排工具,如【气流】。如果出现问题,需要重新处理数据,Airflow 可以重试或回填给定的工作流。
    能够将计算追溯到物化的东西通常是至关重要的,并且气流还可以绘制不同转换步骤的谱系(上游输入&下游输出)。
    【dbt】或【data form】可能是另一种选择,如果您的管道都是用 SQL 编写的(或者您可以将它与 Airflow 结合使用)。

  • 创建一个存储生产数据副本的测试环境,以便您可以运行验收测试。实施 DevOps 支柱,如 CI/CD(运行您构建的内容)、代码评审、【基础设施即代码】 …
  • 验证您选择的工具是否包含某种测试框架。比如:如果你所有的管道都是用 SQL 写的,或者都是用图形用户界面实现的,那你怎么写测试呢?下面是一个用 SQL 编写的【简单上游健康检查】的例子。
  • 在 Stackdriver 或 Grafana 中设置监控。在不符合 SLO 的情况下发送警报。这里有几件你可以监控的事情:
    ——数据是否按时交付?例如:在每日分区中每天上午 8 点。
    -数据完整吗?使用【数据计数器】。
    -数据是否正确?它必须根据数据协定中约定的模式进行格式化。
    -数据一致吗?运行一些端到端的测试,检查不同系统的数据是否意味着相同的事情,否则船可能会沉。

  • 尽量避免突变(DML)为了避免副作用,保留你的原始文件(ELT 而不是 ETL),对你所有的表进行分区,保持你的任务“纯净”,就像【功能数据工程】指南中描述的那样。

参考:【Spotify 如何解决数据质量】

9.建立一些控制

通过让孩子进入图书馆,你实际上制造了混乱:)
数据治理是拼图中的重要一块,为这种混乱带来一点秩序。因此,制定一些规则是很重要的;由您新组建的数据运营团队撰写的黄金路径。让您的数据工程师成为这一转变的向导。
到处都是数据契约,就像微服务一样,这是一个大混乱,直到你带来类似【Istio】的东西。
如果你存储个人信息,需要匿名,如果你打开了数据仓库的大门,数据到处都是,你怎么办?这可能是一个很好的解决方案:【加密删除】。

关于这个主题的一些最后的建议:启用审计日志,为您的数据设置一个保留期,使用【最小特权原则】并实现【ITGCs】。

10.发现新数据

你知道谷歌照片和 Spotify 有什么共同点吗?它们都非常适合发现新照片和音乐!几年前,当第一批数码照片和 MP3 文件开始出现时,我们当时使用的应用程序反映了我们以前制作相册和制作混音带的非数码习惯。

这是因为(正如埃隆·马斯克解释的),用类比推理比从基本原则推理更容易。
当迁移到云时,你必须抓住机会,消除所有现有的偏见和已知的限制。直到你到了一个什么都不能推断的地步。你回到了基本原则,你可以开始构建一个新的更好的解决方案。这种思维模式最终被 Google Photos 和 Spotify 应用到了他们的产品开发中,为生活带来了新的数字体验:我们现在不再对照片进行分类,而是将所有东西上传到云端,因为我们每天给孩子拍 500 张照片,但没有时间对它们进行分类。我们让 Spotify 根据我们的心情推荐歌曲,而不是听一两个播放列表。

获取无限的照片和音乐改变了我们的习惯。我们可以说,数据也在发生同样的转变。公司正在存储越来越多的数据,运行 A/B 测试,发布 canary 并比较关键指标,以验证他们的选择。过去,你必须仔细分类并删除冗余数据,否则你的数据仓库会很快填满。如今,这已经不重要了,就像谷歌照片和 Spotify 一样,你应该彻底改变处理数据的方式,专注于发现。

Photo by Aaron Burden on Unsplash

感谢阅读!
随时在 Twitter 上联系 @tdelazzari

让我们将机器学习应用于行为经济学

原文:https://towardsdatascience.com/lets-apply-machine-learning-in-behavioral-economics-eb952d0f2300?source=collection_archive---------10-----------------------

Photo by Headway on Unsplash

目前,机器学习(ML)在行为经济学或社会科学中没有得到很好的应用,这种缺乏使用来自于对这种不同方法的不熟悉。然而,随着时间的推移,随着机器学习成长起来的一代科学家将进入社会科学,并产生这些技术在计算机视觉中产生的影响。

机器学习和行为经济学之间的互动可以是互利的。一方面,ML 可以用来挖掘大量的数据,并找到促成不同行为出现的行为类型变量。另一方面,嵌入用于识别偏差和错误假设的 ML 算法将达到更高的性能。本文旨在为最先提到的最大似然法在行为经济学研究中的应用提供一种意义,即识别在塑造人们行为中起重要作用的变量。更具体地说,这篇文章简单解释了随机森林和梯度推进机等 ML 技术如何帮助行为经济学或社会心理学等相关领域的研究。

行为经济学是一个研究领域,它研究心理、认知、情感、文化和社会因素对人类决策的影响,以及这些决策如何偏离理性思维所隐含的决策。换句话说,人类不会被认为是足够理性的主体,心理变量和环境将被强调为人类决策的基本决定因素。这种方法有助于更好地预测人类行为,在某些情况下,理性思维存在方向性偏差,允许设计微调政策来改善人们的决策。

正如丹尼尔·卡内曼在他的优秀著作《思考,快与慢》中所说:“我们(人类)是模式的追寻者。“为了理解这些模式,行为经济学家在分析人们的行为时考虑了个人的心理特征和背景。然而,很难大规模地应用这种基于个人和环境的方法。机器学习可以通过检测模式并在大量数据中搜索对形成模式有影响的变量来显著解决这一挑战。

机器学习通常是关于模式识别的,它有助于自动检测数据中的模式,然后使用检测到的模式作为预测未来行动的工具。然而,对最大似然法的关注主要集中在它的预测能力上,而对它的解释能力关注较少。例如,虽然使用 ML 可以更准确和更早地诊断癌症是非常有益的,但是 ML 可以提供的更重要的东西是关于在增加癌症风险中具有更大权重的变量的洞察力。这一知识有助于研究人员和决策者更好地控制这些变量,降低癌症风险。换句话说,最大似然法不仅给了我们对目标变量的预测能力,也给了我们发现哪些输入变量在预测目标变量时更重要的知识。

为了了解 ML 在行为经济学中的应用是如何工作的,让我们来看看决策树模型,这是一个机器学习算法家族,从对一个项目的观察到关于该项目的目标值的结论。这种模型的一种形式称为分类树,其中目标变量具有一组离散的值。在这些模型中,树的分支代表输入变量的合取,这些合取导致代表目标变量的类标签的叶子。另一种决策树模型是回归树,其中目标变量具有连续值。使用决策树集成来达到高预测准确度的两个著名模型是随机森林和梯度推进机。这些基于决策树的算法的目标是建立一个模型,该模型基于几个输入变量来预测目标变量的值。这些模型的重要方面是这些模型中输入变量的数量没有限制。换句话说,他们不太担心维数灾难。

使用这些技术建立模型和进行解释的一般步骤如下:首先,数据被分成两组,一组是训练数据,其通常包括建立模型所基于的大部分数据,另一组是测试数据,通过该测试数据来验证模型。在基于训练和测试数据创建最有效的模型之后,我们将达到可以预测数据中观察到的行为的模型。这个模型现在给我们知识来识别对目标变量的预测有最大贡献的变量。数据分析中的这一过程被称为特征重要性。例如,如果我们有关于大量观察的数百个输入数据,包括个人和背景相关的变量,通过使用这种方法,我们可以发现哪些变量在引导人们表现出不同行为方面是至关重要的。

Figure 1: Decision tree path (source: http://blog.datadive.net/interpreting-random-forests/)

这些模型也提供了局部解释的可能性。换句话说,我们可以了解在每个单独的预测中最重要的顶级输入变量。例如,两个人可能出于完全不同的原因表现出相同的行为。因此,查看对某一特定行为的每个预测,并对最能解释该行为的变量进行分组,将有助于我们了解哪些特征对驱动该行为更有影响。这种可能性是由基于决策树的模型的性质决定的,在这种模型中,从分支到每片树叶都有一条特定的路径,代表每个观察的目标值(图 1)。因此,机器学习的这些强大能力不仅解决了数据规模的挑战,还使我们能够在数千或数百万人口中为一个人匹配正确的政策。换句话说,机器学习使得在正确的环境下将正确的轻推瞄准正确的人成为可能。

领英:【https://www.linkedin.com/in/atanehkar/】T2

让我们成为一个* —学习并编写一个路径规划算法来驾驶无人机

原文:https://towardsdatascience.com/lets-be-a-learn-and-code-a-path-planning-algorithm-to-fly-a-drone-4d5b566fa1ae?source=collection_archive---------10-----------------------

在本教程中,我们将学习并编写一个非常著名的算法,通常用于路径规划,称为 a*(A-Star)

  • 简介
    我们将使用 Udacity 提供的开源模拟器,让一架无人机从起点飞到终点。规划是任何自动驾驶汽车的核心能力之一。任何自动驾驶车辆在开始执行任务之前,都需要有一个计划,这个计划无非是车辆为了安全高效地从某个初始位置移动到某个目标位置而必须采取的一系列行动。从一个规划问题开始,我们需要有以下内容——A)一组所有可能的集合,车辆可以在其中找到自己(它需要在其中运行的环境的地图), b)开始状态和目标状态。c)允许车辆从一种状态转移到下一种状态的一组动作。最后,d) —从一种状态转换到另一种状态时每个可能动作的成本。
  • 搜索空间、动作集和成本
    那么我们能想到的代表“搜索空间”的最简单的表示法是什么呢?让我们考虑一个自上而下的二维世界观。我们可以把这个世界分成小网格。接下来,我们需要在这个表示中加入障碍。一种常见的方法是将任何包含障碍的格网单元标记为不可行。不允许车辆进入这些牢房。所有剩余的网格单元被标记为空闲单元。准备一个计划意味着找出一条路径,这条路径将通过一系列自由网格单元从起始状态到达目标状态。

Image 1

接下来我们需要的是动作场景。我们可以将移动车辆的右、左、上、下和对角运动视为我们的动作空间。对于成本函数,我们可以简单地从将向右向左向上向下的动作视为成本为 1 开始。对于对角线运动,我们可以计算出,如果横向和垂直运动花费 1,那么根据毕达哥拉斯定理,对角线运动将花费 2 的平方根。每当我们制定计划时,我们可以把这个成本加起来(从起点到目标地点),并用它来比较不同的计划。

  • 广度优先搜索(BFS) 现在我们有了网格世界,我们需要建立一个从开始状态到目标状态的步骤序列。那么我们如何建立这个计划呢?通过“广度”进行实际搜索的过程可以归结为几个步骤,我们将不断重复,直到我们达到目标。广度优先搜索的主干由这些基本步骤组成:
    1 .将网格中的节点/顶点添加到要“访问”的节点队列中。
    2。访问队列中最顶端的节点,并将其标记为这样。
    3。如果该节点有任何邻居,检查它们是否被“访问过”。
    4。将仍然需要“访问”的任何相邻节点添加到队列中。
    5。从队列中删除我们访问过的当前节点。

    让我们通过从上图 1 所示地图的起始位置搜索目标位置来看看这些步骤的实际操作。我们将维护两个“队列”(称为“队列”和“已访问”),一个用于跟踪我们需要访问的节点,另一个用于列出我们已经访问过的节点。因此,从“start”位置开始,让我们将它作为队列中的第一个元素。这是 BFS 算法的第 1 步,转到第 2 步,我们将“访问”“开始”节点。访问一个节点的过程实际上意味着我们注意到它的存在,并检查它的相邻节点。在这种情况下,“开始”的相邻节点是节点 A3、B4 和 A5;因此,我们将把它们添加到我们的队列中。一旦我们访问了节点“start”并将其邻居添加到队列中,我们就可以让节点“start”出列,因为我们已经完成了需要对它做的所有事情。这时我们的 2 个队列会是这样的:
    队列->A3—B4—A5;Visited - > Start 从我们的先进先出(FIFO)队列中取出下一个元素,我们将访问节点 A3,检查其相邻的空闲节点 A2 和 B3,将这些相邻节点添加到队列中,并将 A3 从队列移至“Visited”。我们更新后的队列将是这样的:
    queue->B4—A5—A2—B3;再举一个例子,我们的 FIFO 队列中的下一个节点是 B4。事情变得有点有趣了。我们看到 B4 有节点 B3,“开始”,C4 和 B5 作为它的邻居。我们已经在地图上标出了障碍物和禁飞区,所以我们不考虑 C4 和 B5。接下来,我们可以在“已访问”列表中看到“开始”节点,因此我们将忽略它。最后,我们看到 B3 已经出现在队列中,所以我们也将忽略这个节点,因为它已经包含在我们的队列中。这样,我们已经检查了 B4 的所有相邻节点。我们会将它移出队列,并将其插入“已访问”列表。在访问 B4 的情况下,您可以看到 BFS 算法是如何巧妙地识别出“开始”节点先前已被访问过并且节点 B3 已经在队列中列出的事实。更新后的队列会是这样的:
    queue->A5—A2—B3;参观- >开始-A3-B4
    接下来我们拿 A5,重复同样的程序。我们继续这个过程,直到我们找到我们的“目标”位置。
    BFS 算法的一个非常重要的特点是,它非常适合于我们想要找到任何节点到起始节点的最短距离的情况。事实上,许多 BFS 算法会跟踪每个节点的“父”节点。父节点是第一个发现有问题的节点的节点。回头看看上面我们所做的迭代,让我们考虑一下我们“访问”A3 的情况。当我们在 A3 时,我们发现 A2 和 B3 是新发现的节点。现在,当在我们的队列中添加 A2 和 B3 时,如果我们只记下是 A3 帮助我们发现了 A2 和 B3 节点,我们将有一种非常方便的方法来确定从“开始”节点到任何节点的最短距离。例如,如果我们的“目标”是 A2,一旦我们发现 A2(当我们将“访问”A3 时),我们可以注意到 A3 是它的父节点。然后,追溯“已访问”列表,我们可以发现“开始”节点将是 A3 的“父”节点。像这样,我们找到了从“开始”到 A2 的最短路径,如 A2 < - A3 < -“开始”。虽然这可能看起来是一个非常简单的例子,但我鼓励您对您感兴趣的任何节点进行这个练习,并自己发现,如果您保存有关“父”节点的信息并通过“已访问”列表追溯它,您将总是找到从“开始”到该节点的最短路径。不用说,这将保持良好,如果你改变你的'开始'节点到任何其他位置。

  • 启发式
    现在我们有了一张地图,我们的起点和目标位置,以及一个准备计划的方法,我们可以开始给我们的算法增加一点智能。现在,如果你在上面的广度优先搜索示例中看到,我们是在先来先服务的基础上访问节点的。例如,如果您喜欢先查看右边的节点,那么每次我们在任何节点时,它右边的节点将获得 FIFO 队列中的优先级,并且我们将总是在其他节点(左、上、下和对角线节点)之前访问这个“右边”的节点,即使其他节点离我们的目标位置更近。这似乎不是一个非常智能的系统。给定我们需要遍历的世界地图,我们可以粗略估计目标位置离所有其他节点有多远。有几种常见的方法可以做到这一点。一个例子是将从我们正在访问的节点到目标位置的欧几里德距离(或者换句话说,x 和 y 距离的平方和的平方根)作为判断访问该节点有多明智的标准。

另一种常见的方法是采用曼哈顿距离,它是到达目标的剩余 x 和 y 距离的总和。

这两种方法都忽略了障碍,并且会被低估,但它会告诉你你计划访问的节点是带你走向你的目标还是走得更远。使用这个距离,我们可以优先考虑我们想要首先访问的节点。在上面的 BFS 部分,我们看到我们随机选择相邻节点的顺序。但是现在我们可以使用这个距离信息来“访问”距离我们的“目标”最近的节点。

这些距离估计就是所谓的试探法,它们帮助我们找到规划问题的解决方案。如你所见,试探法并不完美——它们忽略了追踪不同路径的障碍和困难/成本,并且总是被低估。

所以我们得到了一个代价函数和一个启发式,接下来让我们把它们结合起来!

  • 为了给搜索过程提供指导,我们现在可以使用两个函数。我们有到目前为止已经采取的行动的总和的成本函数,让我们称之为“G ”,我们有我们的启发式函数“H ”,它是达到目标状态的剩余成本(在我们的情况下,与剩余距离成比例)的表示。如果我们把这两个量加在一起,我们就得到了一个从开始一直到目标的计划总成本的估计值,尽管我们还不知道具体如何一直到目标。让我们回到我们的例子。我们将从起始状态开始,并扩展到右侧、上下的所有相邻节点,我们可以为每个节点添加一个标签,其中包含操作的总成本“G”。如果计算所有相邻节点的总成本=成本+启发式算法,我们可以看到向右或向下移动的总成本最低,这就是我们要选择的方向。根据行动的实际成本加上来自计划中最后一个节点的启发,选择总成本最低的路径的过程就是著名的算法,称为 A star。

  • 坐标框架
    到目前为止,我们一直在考虑如何通过连接网格中的单元找到从开始状态到目标状态的路径。但是在找到到达目标位置的路径之前,我们首先需要表示车辆的当前位置。我们将使用两个不同的坐标来表示我们的车辆的位置。第一个框架可能是我们最熟悉的一个,即使用纬度和经度来定义位置,这被称为大地框架。大地坐标系只是一个球面坐标系,其中典型的坐标‘r’、theta (θ)和 phi (φ)分别由高度、经度和纬度表示。我们将地球表面的海拔高度设置为 0,而不是中心的海拔高度为 0。

一个球形系统实际上做运动规划有点困难,因为很难用角度量来计算距离。因此我们将它们转换成更方便的本地坐标系,称为地心地球固定(ECEF)坐标系。在 ECEF,空间中的每一个点都用 x,y 和 z 来表示。然而,如果这个坐标系的原点在地球表面,会更有用。这样我们就有了自己的 ECEF 相框。

  • 共线性检查
    现在我们有了从 A*算法输出的计划,我们知道如何从起点到达目标位置。但是如果我们把这个计划,网格单元的序列发送给自动驾驶仪,我们真正要求车辆做的是通过一系列短目标行进。在我们一直在做的例子中,我们会告诉自动驾驶仪从我们的起始位置到目标位置。自动驾驶仪要做的是从当前位置出发,向下一格,然后停下来。接下来,我们发送下一个航路点,它将再次向下移动一个网格单元并停止。接下来,我们发送航路点,向右移动一个网格单元,然后停止等等。我们真正想让我们的车做的是向下,转向,一路行驶到最后一个网格单元,这是我们的目标位置。

接下来的问题是,我们如何将这一系列的网格单元转化为路点?我们可以使用的一种方法是获取网格单元的原始列表,只获取位于直线上的任何状态序列的开始和结束单元的网格单元。假设我们有 3 个点,如下所示。如果这三个点在同一条线上(它们共线),那么由这三个点定义的三角形的面积为零。如果我们以如下所示的矩阵形式指出这三个点的坐标,那么这个矩阵的行列式表示由这三个点形成的面积。如果这个矩阵的行列式为 0,三角形的面积为 0,这三个点共线。

在本博客的下一部分,我们将使用旧金山市的地图以及我们在这一部分学到的方法,并将它们结合起来编写一个 3D 运动规划算法。如果听起来让你兴奋,请继续关注!

直到下一次…干杯!!

让我们成为一个* —学习并编写驾驶无人机的路径规划算法—第二部分

原文:https://towardsdatascience.com/lets-be-a-learn-and-code-a-path-planning-algorithm-to-fly-a-drone-part-ii-b0489dcb9c94?source=collection_archive---------10-----------------------

在这一部分中,我们将建立在我们在第 1 部分中学到的理论基础上,并用 Python 编写 A*算法。

  • Unity 模拟器、Python 环境安装和启动文件 在开始编码之前,我们需要安装好设置和工具。我们首先从这里下载适合您操作系统的 Unity 模拟器。接下来,我们安装所需的 Python 库。我鼓励你创建一个独立的 Python 环境(在你选择的任何 IDE 中),以保持它的整洁和独立。遵循 github repo 中的安装说明。最后,我们下载这个 github repo 来获得我们的启动文件。通过检查您是否能够运行上面提供的 github repo for starter 文件的步骤 4 中提供的说明,确保您的设置正确。
  • Starter Code 从这个项目开始,我们提供了两个脚本,motion_planning.py 和 planning_utils.py。在这里,您还会发现一个名为 colliders.csv 的文件,其中包含模拟器环境的 2.5D 地图。一个 2.5D 地图只不过是一个 2D 地图(x,y 位置)和额外的障碍物“高度”信息。一旦我们开始编码,我们将更深入地研究这个文件。
    motion _ planning . py 中的 main 函数与 simulator 建立“Mavlink”连接,并创建“MotionPlanning”类的“drone”对象。运动规划类包含了很多已经为我们准备好的内置函数。它包含回调函数'本地位置回调','速度回调','状态回调'。
if __name__ == "__main__":parser = argparse.ArgumentParser()parser.add_argument('--port', type=int, default=5760, help='Port number')parser.add_argument('--host', type=str, default='127.0.0.1', help="host address, i.e. '127.0.0.1'")args = parser.parse_args()conn = MavlinkConnection('tcp:{0}:{1}'.format(args.host, args.port), timeout=60)drone = MotionPlanning(conn)time.sleep(1)drone.start()

什么是回调函数?回调函数只有在特定事件触发时才会被执行。例如,如果您查看代码行“self.register_callback(MsgID。LOCAL_POSITION,self.local_position_callback)'它所做的是注册 MsgID。python 字典中作为键值对的 LOCAL_POSITION 和 self.local_position_callback(在“self.register_callback”函数中实现)。现在每当 MsgID 中的值。' LOCAL_POSITION '变量发生变化,就会触发对' self.local_position_callback '函数的调用。因此它被称为回调函数。因为在正常的“顺序”程序流中不调用该函数,而是仅在特定事件发生时调用,该事件是“MsgID”值的变化。在这种特殊情况下为“LOCAL_POSITION”。

class MotionPlanning(Drone):def __init__(self, connection):super().__init__(connection) self.target_position = np.array([0.0, 0.0, 0.0])self.waypoints = []self.in_mission = Trueself.check_state = {} # initial stateself.flight_state = States.MANUAL # register all your callbacks hereself.register_callback(MsgID.LOCAL_POSITION, self.local_position_callback)self.register_callback(MsgID.LOCAL_VELOCITY, self.velocity_callback)self.register_callback(MsgID.STATE, self.state_callback)

这些回调函数构成了无人机飞行总体程序的核心结构。各种操作,如起飞,着陆,转换到航路点跟随状态,装备和解除无人机以及所需的回调功能都在这个起始代码中处理。你可以仔细阅读 motion_planning.py 文件并理解这个函数,但是由于本文的主要目的是解释“plan_path”函数的代码,所以我们不会过多地讨论起始代码。一旦无人机待命,它就成功起飞并转换到航路点跟随状态,我们需要开始一次发送一个航路点,这将由我们的“计划路径”功能在无人机起飞前生成。

一旦我们确保我们的无人机准备好了(基本上是一个系统检查,以确保所有的螺旋桨和其他系统都按照预期运行),我们在起飞前做的第一件事就是准备一条有效的路径。简单地说,我们计划在恒定高度飞行。我们也将与地图/世界中的障碍物保持“安全距离”。

目标高度= 5
安全距离= 5

  • Creat_Grid 为了创建一条路径,我们需要一张地图,这是在‘colliders . CSV’文件中提供给我们的。打开文件,我们可以看到第一行包含“lat0”和“lon0”值。这些是我们地图上的家的位置或 0,0,0。

下面几行读取 colliders.csv 第一行中提供的家乡纬度和经度,并将其设置为我们的家乡位置。

# TODO: read lat0, lon0 from colliders into floating point valueslat0_lon0 = pd.read_csv('colliders.csv', nrows = 1, header = None)lat0, lon0 = lat0_lon0.iloc[0,0], lat0_lon0.iloc[0,1]_, lat0 = lat0.split()_, lon0 = lon0.split()lat0 = np.float64(lat0)lon0 = np.float64(lon0)# TODO: set home position to (lat0, lon0, 0)self.set_home_position(lon0, lat0, 0)

然后检查我们当前的全球位置,并将其转换为本地位置,这将是相对于我们之前设置的本地位置。然后,我们打印当前的本地和全球位置以及全球主位置值。

# TODO: retrieve current global position 
# TODO: convert to current local position using global_to_local()
current_local_pos = global_to_local(self.global_position, self.global_home)# Me: checking current local position
print ('current local position {0} and {1}'.format(current_local_pos[0], current_local_pos[1]))print('global home {0}, position {1}, local position {2}'.format(self.global_home, self.global_position,self.local_position))

接下来,我们用网格格式定义我们的地图,我们在这个系列的第 1 部分中学习过。我们首先从 colliders.csv 中读取完整的数据,然后将该 numpy 数组传递给名为“create_grid”的函数。

# Read in obstacle map
data = np.loadtxt('colliders.csv', delimiter=',', dtype='Float64', skiprows=3)# Define a grid for a particular altitude and safety margin around obstacles
grid, north_offset, east_offset = create_grid(data, TARGET_ALTITUDE, SAFETY_DISTANCE)

在我们了解“create_grid”如何创建我们的网格图之前,我们需要了解 colliders.csv 中提供的数据格式。如果我们查看每列的标题(如图 2 的第 2 行所示),我们会看到给定了一个点的 3 个位置值—其 x、y 和 z 坐标,以及 3 个距离值。x、y 和 z 坐标是障碍物中心点的坐标,3 个距离是其宽度、长度和高度值。实际上它们是高度、宽度和长度的一半,因为它们是从中心点到障碍物一边的距离。下图解释了如何提供障碍物的中心点和尺寸值。

我们将创建类似于在第一部分中解释的 2.5D 结构的地图。事实上,我们将更进一步。我们已经用“目标高度”变量固定了无人机的飞行高度。因此,在创建地图时,如果障碍物的高度(PozZ + 2 * halfSizeZ)大于“TARGET_ALTITUDE”,我们将只在地图中包含该障碍物。如果障碍物的高度小于“目标高度”,我们将假设它是一个自由空间,因为我们的无人机可以飞越它。这种方法大大减少了我们的地图所需的空间和处理的复杂性。

随着高度参数的排序,我们需要确定我们需要创建的地图的大小。为此,我们首先确定 X 和 Y 方向上离原点最近和最远的点。假设 X 方向为北,Y 方向为东,我们可以得到两个方向上最近点和最远点的值,如下所示:

# minimum and maximum north coordinates
north_min = np.floor(np.min(data[:, 0] - data[:, 3]))
north_max = np.ceil(np.max(data[:, 0] + data[:, 3]))# minimum and maximum east coordinates
east_min = np.floor(np.min(data[:, 1] - data[:, 4]))
east_max = np.ceil(np.max(data[:, 1] + data[:, 4]))# given the minimum and maximum coordinates we can
# calculate the size of the grid.
north_size = int(np.ceil((north_max - north_min + 1)))
east_size = int(np.ceil((east_max - east_min + 1)))

最后,我们将网格图初始化为 numpy 个零数组

# Initialize an empty grid
grid = np.zeros((north_size, east_size))

接下来,我们将从 colliders.csv 数据中迭代每个障碍,我们已经在变量“数据”中捕获了这些数据。我们将首先比较障碍物的高度是否高于“目标高度”,如果是,那么我们将在我们的网格世界中将障碍物占据的区域+我们在变量“安全距离”中配置的安全距离标记为 1。最后,我们返回网格世界以及 north_min 和 east_min 值。

# Populate the grid with obstaclesfor i in range(data.shape[0]):north, east, alt, d_north, d_east, d_alt = data[i, :]if alt + d_alt + safety_distance > drone_altitude:obstacle = [int(np.clip(north - d_north - safety_distance - north_min, 0, north_size-1)),int(np.clip(north + d_north + safety_distance - north_min, 0, north_size-1)),int(np.clip(east - d_east - safety_distance - east_min, 0, east_size-1)),int(np.clip(east + d_east + safety_distance - east_min, 0, east_size-1)),]grid[obstacle[0]:obstacle[1]+1, obstacle[2]:obstacle[3]+1] = 1return grid, int(north_min), int(east_min)

我们需要理解的一个小警告是,碰撞器中的障碍物和我们当前的本地位置是相对于全局 home 的,这是我们在 lat0 和 lon0 变量的帮助下配置的。然而,我们在 create_grid 函数中创建的网格世界的原点在第一个障碍点。还记得我们是如何计算北部最小和最大值以及东部最小和最大值,然后计算北部和东部大小来创建网格的吗?因此,在碰撞器之间有一个偏移&我们无人机的位置值和我们网格世界中相应的相同位置。下图将帮助我们更好地理解它。

因此,每当我们试图将无人机位置传感器的值映射到网格世界时,我们需要分别减去北偏和东偏。这个偏移值就是 create_grid 函数返回的 north_min 和 east_min。我们将我们在 grid_world 中的当前位置设置为

# TODO: convert start position to current position rather than map center
grid_start = (int(current_local_pos[0] - north_offset), int(current_local_pos[1] - east_offset))

指定我们选择的目标位置

# Take GPS co-ordinates as Grid goal -Me
grid_goal = (-122.396582, 37.795714, 0)
grid_goal = global_to_local(grid_goal, self.global_home)
grid_goal = (int(grid_goal[0] - north_offset), int(grid_goal[1] - east_offset))

打印我们的起点和目标位置,然后开始我们成为 A*的旅程!!

print('Local Start and Goal: ', grid_start, grid_goal)
path, _ = a_star(grid, heuristic, grid_start, grid_goal)
  • A*在城市中 我们将刚刚在上面部分创建的网格、一个启发式函数以及我们的起点和目标位置作为参数传递给 a_star 函数。希望我们在本系列的第 1 部分中获得的概念能够帮助我们更好地理解这个函数的代码。事实上,让我们重温一下我们在理解广度优先算法时所经历的步骤列表。知道算法的哪一步是在哪一行中执行的,将有助于我们更好地理解下面的代码块。如第 1 部分所述,A*算法在 BFS 的基础上增加了“成本”和“启发式”功能。因此,随着代码实现以下步骤,它将包括添加和访问'成本'和'启发式'功能了。广度优先搜索的主干由这些基本步骤组成。将网格中的节点/顶点添加到要“访问”的节点队列中。
    2。访问队列中最顶端的节点,并将其标记为这样。
    3。如果该节点有任何邻居,检查它们是否被“访问过”。
    4。将仍然需要“访问”的任何相邻节点添加到队列中。
    5。从队列中删除我们访问过的当前节点。我们首先声明几个变量。我们将使用优先级队列来存储我们需要访问的节点。优先级队列中条目的典型模式是:(优先级编号,数据)形式的元组。首先检索最低值的条目,因为我们将使用“到达相应节点的成本”值作为“优先级 _ 编号”,所以每当我们从该优先级队列中“获取”(或弹出)元素时,我们将获取具有最小“成本”值的元素。我们从“开始”节点开始。
path = []path_cost = 0queue = PriorityQueue()queue.put((0, start))visited = set(start)branch = {}
found = False# Check till we have searched all nodes or have found our ‘goal’
while not queue.empty():item = queue.get() # Step2\. Visit the topmost node in the queuecurrent_cost = item[0]current_node = item[1] if current_node == goal:print('Found a path.')found = Truebreakelse:#Step3\. If that node has any neighbors, check to see if they have been “visited” or not.for a in valid_actions(grid, current_node):next_node = (current_node[0] + a.delta[0], current_node[1] + a.delta[1])new_cost = current_cost + a.cost + h(next_node, goal)#Step4\. Add any neighboring nodes that still need to be “visited” to the queue.if next_node not in visited:visited.add(next_node)queue.put((new_cost, next_node)) branch[next_node] = (new_cost, current_node, a)

正如我们在第 1 部分中看到的,无论何时我们到达 BFS 算法中的一个节点,它都保证是从我们的“开始”位置到那个节点的最短路径。因此,为了跟踪我们正在跟踪的路径,在 a_star 函数中,我们将维护一个字典,其中“key”将是我们接下来要访问的节点,它的值将是当前节点的元组、为了到达下一个节点要从当前节点采取的动作以及到达下一个节点的总成本。该元组(当前节点+到达下一个节点要采取的动作)将表示从“开始”位置到达下一个节点的最短路径。
现在,一旦我们找到“目标”位置,我们将在“分支”字典的帮助下追溯到“开始”位置的路线。我们首先复制到达“目标”位置的总成本值。接下来,由于我们知道字典的“值”中存在的节点位于最短路径上,我们将构建我们的“路径”列表为->[目标,分支的值中存在的节点[目标],…]。我们将继续追踪我们的路线,直到我们找到“开始”位置,将节点添加到“路径”列表中。

if found:# retrace stepsn = goalpath_cost = branch[n][0]path.append(goal)while branch[n][1] != start:path.append(branch[n][1])n = branch[n][1]path.append(branch[n][1])else:print('**********************')print('Failed to find a path!')print('**********************') return path[::-1], path_cost
  • 辅助函数 路径修剪:一旦我们想出了路径,我们将通过删除共线点来修剪它,如第 1 部分的共线性检查一节所述。我们从最终路径中取 3 个连续点,检查它们是否在同一条线上。我们通过计算选定的 3 个点所包围的面积来实现这一点。如果它非常接近 0,我们可以假设它们位于同一直线上。我们首先将一个 3 元素(x 坐标,y 坐标,1)中的点转换为 numpy 数组。我们添加最后一个元素“1 ”,这样我们可以将 3 个顶点排列成一个漂亮的 3×3 矩阵。在对“points()”函数中的点进行整形后,我们通过连接它们来创建一个矩阵,然后使用一个方便的 np.linalg.det()函数来计算该矩阵的行列式。
    有效动作:我们在 a_star 中使用的一个函数是 valid_actions (grid,current_node)。这用于执行 BFS 算法的步骤# 3,其中我们搜索当前节点的邻居。我们已经有了动作集(如第 1 部分的“搜索空间、动作集和成本”一节中所解释的)和当前节点的位置。该函数将返回动作集的子集。它将检查一个动作(即向上、向下、向左、向右或对角移动)是否会将我们带离网格或带至障碍物/禁飞区节点。如果是这种情况,它将从当前节点的有效可行动作列表中删除该动作。

回到 motion_planning.py,一旦我们得到了修剪过的路径,从其中取出每个点,将其转换为局部坐标系中的航路点(通过添加北向和东向偏移),并使用 self.send_waypoints()函数将其发送到自动驾驶仪。至此,我们完成了路径规划 A*算法的编码。所以事不宜迟,让我们启动 Udacity 的无人机模拟器,运行我们的 motion_planning.py python 文件。你可以在我的 github repo 这里找到所有的源代码。如果一切顺利,你应该能够看到你的无人机从用户配置的起点和目标位置飞行,如下图所示。

希望你喜欢阅读本系列的几篇文章,并且现在对 A*的基础有了很好的理解。

如果你觉得这篇文章有用,你知道下一步该怎么做😊直到下一次…干杯!!

让我们建立一个流数据管道

原文:https://towardsdatascience.com/lets-build-a-streaming-data-pipeline-e873d671fc57?source=collection_archive---------4-----------------------

用于实时数据管道的 Apache Beam 和数据流

今天的帖子是基于我最近在工作中做的一个项目。我真的很兴奋能实现它,并把它写成一篇博文,因为它给了我一个机会去做一些数据工程,也做了一些对我的团队非常有价值的事情。不久前,我发现我们的系统中存储了大量与我们的一个数据产品相关的用户日志数据。事实证明,没有人真正使用这些数据,所以我立即对我们开始定期分析这些数据能够学到什么产生了兴趣。然而,有几个问题。第一个问题是,数据存储在许多不同的文本文件中,不能立即用于分析。第二个问题是它存储在一个锁定的系统中,所以我不能使用任何我喜欢的工具来分析数据。

我考虑过如何让我们更容易获取这些数据,并通过将这些数据构建到我们的一些用户参与工作中来真正创造一些价值。思考了一会儿之后,我决定建立一个管道,将这些数据输入云数据库,这样我和更广泛的团队就可以访问这些数据,并开始产生一些见解。在最近完成了 Coursera 上的 GCP 数据工程专业之后,我热衷于使用课程中的一些工具开始一个项目。

对,所以将数据放入云数据库似乎是处理我的第一个问题的合理方式,但是我能对第二个问题做些什么呢?幸运的是,有一种方法可以将这些数据转移到我可以访问 Python 和谷歌云平台(GCP)等工具的环境中。然而,这将是一个漫长的过程,所以我需要做一些事情,让我在等待数据传输的同时进行开发。我想到的解决方案是使用 Python 中的 Faker 库创建一些假数据。我以前从未使用过这个图书馆,但很快意识到它是多么有用。采用这种方法允许我在没有实际数据的情况下开始编写代码和测试管道。

也就是说,在这篇文章中,我将介绍我是如何使用 GCP 的一些技术来构建上述管道的。特别是,我将使用 Apache Beam (python 版本)、Dataflow、Pub/Sub 和 Big Query 来收集用户日志、转换数据并将其输入数据库进行进一步分析。对于我的用例,我只需要 beam 的批处理功能,因为我的数据不是实时到达的,所以不需要发布/订阅。然而,我将把重点放在流版本上,因为这是您在实践中可能经常遇到的。

GCP 和阿帕奇波束简介

谷歌云平台为大数据处理提供了一堆真正有用的工具。我将使用的一些工具包括:

  • Pub/Sub 是一种使用发布者-订阅者模型的消息服务,允许我们实时获取数据。
  • data flow是一项简化创建数据管道并自动处理诸如扩展基础设施之类的事情的服务,这意味着我们可以专注于为我们的管道编写代码。
  • big query是云数据仓库。如果您熟悉其他 SQL 风格的数据库,那么 BigQuery 应该非常简单。****
  • 最后,我们将使用 Apache Beam ,特别是,我们将关注 Python 版本来创建我们的管道。这个工具将允许我们创建一个与 GCP 集成的流或批处理管道。它对并行处理特别有用,适合于提取、转换和加载(ETL) 类型的任务,因此如果我们需要在执行转换或计算时将数据从一个地方移动到另一个地方,Beam 是一个不错的选择。

GCP 上有各种各样的可用工具,因此很难掌握它们的全部以及它们的用途,但这里的是对它们的总结,以供参考。

可视化我们的管道

让我们使用图 1 来可视化管道的组件。在高层次上,我们想要做的是实时收集用户生成的数据,对其进行处理并将其输入 BigQuery。这些日志是在用户与产品交互时生成的,用户向服务器发送请求,然后被记录下来。这些数据对于理解用户如何使用我们的产品以及事情是否正常运行非常有用。一般来说,管道将有以下步骤:

  1. 我们的用户日志数据被发布到一个发布/订阅主题。
  2. 我们将连接到发布/订阅,并使用 Python 和 Beam 将数据转换成适当的格式(图 1 中的步骤 3 和 4)。
  3. 在转换数据之后,Beam 将连接到 BigQuery 并将数据追加到我们的表中(图 1 中的步骤 4 和 5)。
  4. 为了进行分析,我们可以使用各种工具(如 Tableau 和 Python)连接到 BigQuery。

Beam 使这个过程变得非常容易,无论我们有一个流数据源,还是我们有一个 CSV 文件并想进行批处理。稍后您将会看到,在这两者之间进行切换只需要对代码进行很小的修改。这是使用 Beam 的优点之一。

Figure 1: General Data Pipeline: Source:

使用 Faker 创建伪数据

正如我之前提到的,由于对数据的访问有限,我决定创建与实际数据格式相同的假数据。这是一个非常有用的练习,因为我可以在等待数据的同时开发代码和测试管道。如果你想知道图书馆还能提供什么,我建议你看一下 Faker 的文档。我们的用户数据通常类似于下面的例子。基于这种格式,我们可以逐行生成数据来模拟实时数据。这些日志为我们提供诸如日期、请求类型、服务器响应、IP 地址等信息。

**192.52.197.161 - - [30/Apr/2019:21:11:42] "PUT /tag/category/tag HTTP/1.1" [401] 155 "https://harris-lopez.com/categories/about/" "Mozilla/5.0 (Macintosh; PPC Mac OS X 10_11_2) AppleWebKit/5312 (KHTML, like Gecko) Chrome/34.0.855.0 Safari/5312"**

基于上面的行,我们想使用下面花括号中的 7 个变量创建我们的变量。稍后,我们也将在表模式中使用它们作为变量名。

**LINE = """\
{remote_addr} - - [{time_local}] "{request_type} {request_path} HTTP/1.1" [{status}] {body_bytes_sent} "{http_referer}" "{http_user_agent}"\
"""**

如果我们正在做一个批处理作业,代码会非常相似,尽管我们需要在某个时间范围内创建一堆样本。要使用 faker,我们只需创建一个对象并调用我们需要的方法。特别是,faker 对于生成 IP 地址和网站非常有用。我使用了以下方法:

**fake.ipv4()
fake.uri_path()
fake.uri()
fake.user_agent()**

stream_logs.py

设置谷歌云。

注意:为了运行管道和发布用户日志数据,我使用了 google cloud shell,因为我在使用 Python 3 运行管道时遇到了问题。Google cloud shell 使用 Python 2,它在 Apache Beam 上表现得更好。

为了能够运行管道,我们需要做一些设置。对于那些以前没有使用过 GCP 的人来说,你需要完成本页中概述的 6 个步骤。

在此之后,我们将需要上传我们的脚本到谷歌云存储,并复制到我们的谷歌云外壳。上传到云存储非常简单,这里有的解释。要复制我们的文件,我们可以通过点击下面图 2 中左边的第一个图标打开工具栏中的 Google Cloud shell。

Figure 2

下面列出了我们复制文件和安装必要的库所需的命令。

**# Copy file from cloud storage
gsutil cp gs://<YOUR-BUCKET>/ * .sudo pip install apache-beam[gcp] oauth2client==3.0.0 
sudo pip install -U pip
sudo pip install Faker==1.0.2# Environment variables
BUCKET=<YOUR-BUCKET>
PROJECT=<YOUR-PROJECT>**

创建我们的数据库和表

在我们完成了设置步骤之后,接下来我们需要做的是在 BigQuery 中创建一个数据集和一个表。有几种不同的方法可以做到这一点,但最简单的方法是使用谷歌云控制台,首先创建一个数据集。您可以按照下面的链接中的步骤来创建一个表和一个模式。我们的表将有 7 列 对应于每个用户日志的组件。为方便起见,除了 timelocal 变量之外,我们将所有列定义为字符串,并根据我们之前生成的变量来命名它们。我们的表模式应该如图 3 所示。

Figure 3 Table Schema

发布我们的用户日志数据

发布/订阅是我们管道的重要组成部分,因为它允许多个独立的应用程序相互交互。特别是,它充当了中间人的角色,允许我们在应用程序之间发送和接收消息。我们要做的第一件事是创建一个主题。这很简单,只需在控制台中点击“发布/订阅”并点击“创建主题”即可。

下面的代码调用我们的脚本来生成上面定义的日志数据,然后连接并发送日志到 Pub/Sub。我们需要做的唯一事情是创建一个 PublisherClient 对象,使用 topic_path 方法添加主题的路径,并在传递 topic_path 和数据的同时调用 publish 函数。注意,我们正在从我们的 stream_logs 脚本中导入 generate_log_line ,所以要确保这些文件在同一个文件夹中,否则会出现导入错误。然后,我们可以在 google 控制台中使用以下命令来运行它:

**python publish.py**

文件运行后,我们应该能够看到日志数据打印到控制台,如下图所示。这个脚本会一直运行,直到我们用 CTRL+C 杀死它。

Figure 4: publish_logs.py output

为我们的管道编码

现在我们已经完成了初始设置,我们可以开始有趣的事情,使用 Beam 和 Python 编写我们的管道。为了创建一个波束管道,我们需要创建一个管道对象( p ) 一旦我们创建了管道对象,我们可以使用 管道(|) 操作符一个接一个地应用多个函数。通常,工作流程如下图所示。

**[Final Output PCollection] **=** ([Initial Input PCollection] **|** [First Transform]**|** [Second Transform]**|** [Third Transform])**

在我们的代码中,我们创建了两个自定义函数。 regex_clean 函数,使用 re.search 函数搜索数据并根据模式列表提取适当的字符串。该函数返回逗号分隔的字符串。如果你不是正则表达式专家,我推荐你看看这个教程和笔记本来测试代码。之后,我们定义了一个名为 Split 的自定义 ParDo 函数,这是一种用于并行处理的波束变换。在 Python 中有一种特殊的方法,我们必须创建一个从 DoFn Beam 类继承的类。Split 函数从前面的函数中获取解析后的字符串,并返回一个字典列表,其中的键等于 BigQuery 表中的列名。关于这个函数,需要注意的一点是,我必须在函数中导入 datetime,它才能工作。我得到了一个错误,当我在文件的顶部导入时,这很奇怪。然后这个列表被传递给 WriteToBigQuery 函数,该函数只是将我们的数据追加到表中。下面提供了批处理数据流作业和流式数据流作业的代码。批处理代码和流代码之间的唯一区别是,在批处理作业中,我们使用 Beam 中的 ReadFromText 函数从 src_path 读取 CSV。

批处理数据流作业

main_pipeline_batch.py

流式数据流作业

main_pipeline_streaming.py

运行管道

我们可以用几种不同的方式来执行管道。如果我们愿意,我们可以从终端本地运行它,前提是我们已经远程登录到 GCP。

**python -m main_pipeline_stream.py \--input_topic "projects/user-logs-237110/topics/userlogs" \--streaming**

然而,我们将使用数据流来运行它。我们可以使用下面的命令做到这一点,同时还可以设置下面的强制选项。

  • **project** -你的 GCP 项目的 ID。
  • **runner** -管道运行器,它将解析你的程序并构建你的管道。对于云执行,这必须是DataflowRunner
  • **staging_location** -云数据流的云存储路径,用于存放执行工作的工人所需的代码包。
  • **temp_location** -云数据流的云存储路径,用于存放在管道执行期间创建的临时作业文件。
  • **streaming**
**python main_pipeline_stream.py \
--runner DataFlow \
--project $PROJECT \
--temp_location $BUCKET/tmp \
--staging_location $BUCKET/staging
--streaming**

当这个命令运行时,我们可以在 google 控制台的 DataFlow 选项卡上查看我们的管道。当我们点击管道时,我们应该看到如图 4 所示的内容。出于调试的目的,进入日志,然后使用 Stackdriver 查看详细的日志会很有帮助。这帮助我在很多情况下解决了管道的问题。

Figure 4: Beam Pipeline

在 BigQuery 中访问我们的数据

没错,我们应该建立管道,让数据流入表中。为了证实这一点,我们可以转到 BigQuery 并查看数据。使用下面的命令后,您应该会看到数据集的前几行。现在我们已经将数据存储在 BigQuery 中,我们可以做进一步的分析,与同事共享数据,并开始回答和解决业务问题。

**SELECT * FROM `user-logs-237110.userlogs.logdata` LIMIT 10;**

Figure 5: BigQuery

外卖食品

希望这提供了一个创建流数据管道的有用示例,也提供了一个找到使数据更易访问的方法的有用示例。拥有这种格式的数据对我们有很多好处。我们现在可以开始回答一些有用的问题,比如有多少人使用我们的产品?用户群是否会随着时间的推移而增长?人们与产品的哪些方面互动最多?还有有没有不该发生的错误发生?这些是组织感兴趣的问题类型,基于这些见解,我们可以推动产品的改进并提高用户参与度。

Beam 对于这种类型的练习非常有用,并且还有许多其他有趣的用例。例如,您可能希望实时分析股票报价单位数据,并根据分析进行交易;您可能有来自车辆的传感器数据,并希望计算出流量水平。例如,你也可以是一家游戏公司,收集用户数据,并利用这些数据创建跟踪关键指标的仪表板。好了,伙计们,这就是另一个帖子,感谢阅读,对于那些想看完整代码的人,下面是我的 GitHub 的链接。

**推荐课程:[【GCP】上的数据工程、大数据、机器学习](http://Data Engineering, Big Data, and Machine Learning on GCP)

**** [## d poly/用户日志管道

在 Google Cloud Platform 中为用户日志数据创建流管道-d poly/User _ log _ Pipeline

github.com](https://github.com/DFoly/User_log_pipeline)

注意,这篇文章中的一些链接是附属链接。****

使用 LDA 构建文章推荐器

原文:https://towardsdatascience.com/lets-build-an-article-recommender-using-lda-f22d71b7143e?source=collection_archive---------12-----------------------

Photo by Ian Schneider on Unsplash

由于对学习新主题的浓厚兴趣,我决定从事一个项目,其中一个潜在狄利克雷分配(LDA) 模型可以根据搜索短语推荐维基百科文章。

本文解释了我用 Python 构建项目的方法。请查看下面 GitHub 上的项目。

[## kb22/文章推荐者

使用 LDA,该项目基于搜索查询推荐维基百科文章。-kb22/文章推荐者

github.com](https://github.com/kb22/Article-Recommender)

结构

Photo by Ricardo Cruz on Unsplash

我使用类在 Python 中开发了完整的项目,并没有像我通常做的那样使用 Jupyter 笔记本来理解类以及如何开发一般的 Python 项目。模块、维基百科浏览器清理器内容被定义为Modules文件夹中的类。 config 文件包含了配置。收集数据生成器评估器用于开发和运行模型。

**Modules|- __init__.py|- WikipediaCrawler.py|- Cleaner.py|- Content.py****config.yml
collectData.py
generateDLA.py
evaluator.py****sample_images|- recommendations.png****.gitignore
LICENSE
Pipfile.lock
README.md
requirements.txt**

当您尝试运行项目时,您可以使用Pipfile.lockrequirements.txt来安装所有的依赖项。

配置

Photo by Tim Mossholder on Unsplash

将项目的任何配置包含在一个公共文件中总是一个好的做法。虽然这个项目中没有太多的信息,但是我定义了在config.yml文件中存储数据库、LDA 模型、字典和语料库的路径。我决定把这些都放在data文件夹里。

配置文件基于 YAML,这是业内常用的数据序列化方法,用于存储人类可读的配置。需要pyyaml包来读取 Python 中的 YAML 文件。

模块

Photo by Louis Reed on Unsplash

我开发和设计了三个模块(作为类),用于从维基百科抓取数据,并处理这些数据。

维基百科爬虫

WikipediaCrawler让我们根据某个类别抓取维基百科的文章。在初始化这个类时,它创建一个sqlite3连接,然后添加一个表wikiData,存储页面idcategoryurlcontentcollect_data方法使用wptools包提取页面并将它们存储在表中。wptools是一个 Python 包,允许我们根据给定的类别抓取维基百科的文章。

我添加了两个额外的方法,get_ids获取所有的页面 id,get_urls获取所有的 URL,如果需要的话。

清洁工

该模块接收文档文本并对其进行预处理。我只需要使用函数clean_text,因为它代表我们调用所有其他函数并返回最终结果。它执行以下操作:

  1. 删除不必要的新行字符\n
  2. 删除标点符号
  3. 删除数字
  4. 删除停用字词(过于常见且不适合作为搜索关键字的字词)
  5. 应用词条化(将每个单词转换为其词条单词,如 ran,running 转换为 run

内容

这个模块连接到sqlite3数据库,帮助我们迭代页面,并使用Cleaner模块清理它们的内容。我添加了其他方法来通过 id 获取页面url

应用

Photo by Jason Leung on Unsplash

一旦我设置好模块,我就开始搜集数据,训练 LDA 模型并推荐文章。

收集数据

首先,我运行文件collectData.py,它期望两个参数开始从 Wikipedia 中提取数据并将其存储在数据库中。

  1. 类别:我们要为其开发文章推荐系统的类别
  2. 深度:对于给定的类别,我们想要提取网页到什么深度。例如,当从深度 2 开始浏览一篇文章时,它将以深度 1 更深入一步(即其相关文章),但将在下一深度结束,因为它将是 0。

如果目录data不存在,它将创建该目录。使用WikipediaCrawler,它提取页面并存储到wikiData.db供其他文件使用。完成后,它输出消息:数据库已经生成

生成 LDA

下一步是使用我们创建的数据库,从它构建一个 ld a 模型,并将其存储在 data 文件夹中。

首先,我读取数据库并创建一个字典。我删除所有出现在少于 5 个文档中的单词和出现在超过 80%文档中的单词。我尝试了多个值,并通过反复试验得出了这些数字。然后,使用doc2bow,我创建一个单词包,作为关键字列表。最后,我生成了 LDA 模型,并保存了模型、词典和语料库。

求值程序

最后,一切准备就绪。我们调用evaluator.py并传入一个查询字符串,基于该字符串我们识别关键字并列出匹配搜索标准的前 10 篇文章。

我阅读查询并从中识别关键字。然后,通过调用get_similarity方法,我计算了相似度矩阵,并按照降序对它们进行排序,这样最大相似度的文档就在顶部。

接下来,我迭代这些结果,并呈现代表推荐文章的前 10 个 URL。

真实的例子

用例

我用深度 2 和类别机器学习创建了数据库。它生成了文件,wikiData.db。接下来,使用generateLDA.py,我创建了 LDA 模型。

使用

我使用搜索查询作为Machine learning applications,并被推荐了如下图所示的文章:

Recommended articles for ‘Machine learning applications’

结论

在本文中,我讲述了如何开发一个 LDA 模型,根据搜索查询向用户推荐文章。我使用 Python 类设计了一个完整的应用程序。

如果你喜欢这篇文章,看看我的其他文章:

[## 使用 Flask、Flask RESTPlus 和 Swagger UI 处理 API

Flask 和 Flask-RESTPlus 简介

towardsdatascience.com](/working-with-apis-using-flask-flask-restplus-and-swagger-ui-7cf447deda7f) [## 使用机器学习预测心脏病的存在

机器学习在医疗保健中的应用

towardsdatascience.com](/predicting-presence-of-heart-diseases-using-machine-learning-36f00f3edb2c) [## 使用 ROC 和 CAP 曲线的机器学习分类器评估

了解 ROC 和 CAP 曲线及其在 Python 中的实现

towardsdatascience.com](/machine-learning-classifier-evaluation-using-roc-and-cap-curves-7db60fe6b716)

一如既往,请随时分享您的想法和想法。如果你在一个项目或一个想法上需要帮助,在 LinkedIn 上 ping 我。你可以在这里找到我。

让我们计算一下纽约 Airbnb 价格的 Z 值

原文:https://towardsdatascience.com/lets-calculate-z-scores-for-airbnb-prices-in-new-york-8da9964c49b0?source=collection_archive---------22-----------------------

通过编码示例了解 z 分数

z 分数,也叫标准分数,根据维基百科的说法是

在统计中,标准分数是标准差的有符号分数,通过该分数,观察值或数据点的值高于被观察或测量的平均值。

翻译:衡量一个值与其总体平均值的差距。

我们来看看公式。

μ = mean, σ = std, x = value

这很简单。从被评估的值中减去数据集的平均值,然后除以标准差。

我们来玩一些数据。

首先,从 Kaggle 下载数据集,并将其保存在与您的 jupyter 笔记本相同的目录中(您的文件名可能与我的不同)。然后对前几条记录进行采样,看看数据看起来如何。

import pandas as pd
ny = pd.read_csv('airbnb-new-york/AB_NYC_2019.csv')
ny.head(3)

Scipy 有一个很好的方法来计算数据集中每个值的 z 值。见下文。

from scipy import stats
stats.zscore(ny.price)#=> array([-0.01549307,  0.30097355, -0.01132904, ..., -0.15707024,-0.4069123 , -0.2611711 ])

但是我们将编写自己的函数,因为我们只想检查几个值。

import numpy as npmean = np.mean(ny.price)
std = np.std(ny.price)def z_score(value, mean, std):return (value - mean) / std

现在从数据集中随机选择 5 个价格。

import randomvalues = []# randomly select 5 values from price
for i in list(range(0,5)):value = random.choice(ny.price)values.append(value)print(values)
#=> [78, 169, 53, 375, 80]

并计算这些值的 z 分数。

for val in values:z = z_score(val, mean, std)print(z)#=> -0.3111395124662796
#=> 0.06778761869937604
#=> -0.41524037267662456
#=> 0.9255787068326184
#=> -0.302811443649452

嘣。这到底意味着什么?

第一个示例比平均值低 0.31 个标准偏差。
第二个是平均值以上 0.07 个标准差。
3 号比平均值低 0.42 个标准差。你明白了。

所有的例子都在平均值的 1 个标准偏差内。这在任何服从正态分布的人群中都不是闻所未闻的(其中约 68%的值落在平均值的 1 个标准差之内)。

但是什么是正态分布呢?它有时被称为钟形曲线(尽管其他分布也遵循钟形)。

It’s the red line here. Thank you wikipedia.

是上面的红线。在自然科学和社会科学中,人口中的许多值都遵循这种分布。例如,大多数人的身高接近所有人的平均身高。而且很少有人超级高或者超级矮。这在直觉上是有道理的。

但并非一切都遵循正态分布。我怀疑我们的 Airbnb 价格。让我们建立一个直方图来找出答案。

import matplotlib.pyplot as plt
%matplotlib inlineplt.rcParams.update({'figure.figsize':(7,5), 'figure.dpi':100})plt.hist(ny.price, bins=100, range=(0, 1000))

差远了。

出于好奇,我们的均值和标准差是多少。

print(mean)
print(std)#=> 152.7206871868289
#=> 240.15171391941718

因此,虽然平均值是 153 美元,但标准差却高达 240 美元。这就是说价格变化很大。这就是为什么$78 的值和$375 的值都可以在平均值的 1 个标准偏差之内。

将我们的分布与标准偏差为 1 的正态分布进行对比!

为什么所有这些都很重要?在一个沉迷于快速统计数据和平均值的世界里。重要的是要记住,人口的平均值只是故事的一小部分。

让我们回到基础

原文:https://towardsdatascience.com/lets-get-back-to-basics-e0b19917aa91?source=collection_archive---------33-----------------------

数据偏好和数据成功之间的反比关系

Photo by Martin Adams on Unsplash

几年前,说每家公司都是科技公司很快就成了陈词滥调。当然,在某种程度上,每个公司都是如此。但是另一个趋势紧随其后,而且这个趋势更加适用:每个公司都在成为数据公司。见鬼,每个组织都在成为数据组织!成为数据驱动的好处是显而易见的;显然,如果你能根据数据做出决策,并衡量这些决策的影响,这是一种比过去推动业务发展的猜测或直觉更有效的方法。因此,市场上出现了数据驱动的强劲趋势也就不足为奇了,部分原因是云技术和 SaaS 的使用越来越多,使得数据比以往任何时候都更容易访问。

但没那么快。我还看到,尽管人们对数据驱动的兴趣比以往任何时候都大,但擅长数据驱动却比以往任何时候都难。事实上,我要说的是,围绕数据的基本要素(准确性、质量、可靠性、治理、访问、保护、安全性)实际上有一个相反的趋势—这些都非常难以正确处理,并且越来越难以管理。

但问题在于:这些趋势不仅同时存在,它们实际上还相互强化。也就是说,你越想成为数据驱动型(趋势上升),就越难把基本面搞对(趋势下降)。数据越不可靠,组织就越不重视他们的数据工作……这种恶性循环还在继续。

对此我们能做些什么?首先,我认为思考一下我们是如何走到这一步的是有帮助的。数据偏好和数据成功之间的这种反比关系有许多原因。首先,数据被视为蛋糕上的表面糖衣,而不是蛋糕本身,重点是人工智能、仪表盘和数据的 UI 方面,而不是从一开始就重新想象结构。此外,或许与此相关的是,数据在整个组织中往往是一个分散的目标。

这需要改变这两种现实,以确保我们不会因为使用不可靠的数据而分散自己的努力。从许多方面来说,这相当于通过思维方式的转变回归基础:

  • 没有数据总比有不可靠的数据好
  • 要信任数据,我们必须知道它来自哪里,它意味着什么,它基于什么样的假设
  • 我们必须从数据源到仪表板、报告或我们使用的机器学习模型,全程管理数据的可靠性

为什么我们在业务中所做的每一件事的可靠性标准都如此之高,这是最初鼓励这种数据驱动趋势的一部分!—但不知何故,我们已经接受了我们的数据不可靠的事实?我每天都被这个困扰着。如果你有同样的感觉——你看到了什么帮助组织扭转这一悖论的趋势?

让我们通过预测垃圾邮件来了解 ROC AUC 曲线

原文:https://towardsdatascience.com/lets-learn-about-the-roc-auc-curve-by-predicting-spam-d8007746a6f9?source=collection_archive---------24-----------------------

ROC AUC 曲线比较分类器不同分类阈值的 TPR 和 FPR。

ROC AUC 曲线通过评估模型区分不同类别的能力,帮助我们选择工作的最佳模型。

图例:
ROC =受试者操作曲线
AUC =曲线下面积
TPR =真阳性率
FPR =假阳性率

在深入了解这一切意味着什么之前,让我们为一个真实的例子绘制一条曲线。

举例:预测哪些短信是垃圾短信

首先,从 Kaggle 下载数据集。

在熊猫数据框中打开它。

import pandas as pddf = pd.read_csv('~/Downloads/spam.csv', encoding='ISO-8859-1')
df.head(3)

它看起来像是格式化不良的数据。数据通常就是这样——我们会解决它。

v1转换成你的标签y,将v2转换成你的特征X。标签需要是整数才能输入到模型中,所以if spam设置为1,而if ham设置为0。不知道的话,ham表示不是spam

import numpy as npy = np.array([(1 if i=='spam' else 0) for i in df.v1.tolist()])
X = np.array(df.v2.tolist())

X现在是字符串数组,y1's0's的数组。

将数据分成测试集和训练集。请注意,数据尚未矢量化。

from sklearn.model_selection import StratifiedShuffleSplitsplitter = StratifiedShuffleSplit(n_splits=1, test_size=0.3, random_state=0
)for train_index, test_index in splitter.split(X, y):X_train_pre_vectorize, X_test_pre_vectorize = X[train_index], X[test_index]y_train, y_test = y[train_index], y[test_index]

安装矢量器并转换测试和训练集。

from sklearn.feature_extraction.text import CountVectorizervectorizer = CountVectorizer()X_train = vectorizer.fit_transform(X_train_pre_vectorize)
X_test = vectorizer.transform(X_test_pre_vectorize)

选择一个分类器并将其安装在训练集上。我任意选择了LogisticRegression

from sklearn.linear_model import LogisticRegressionclassifier = LogisticRegression()
classifier.fit(X_train, y_train)

通常这是我们预测测试集的类的地方,但是因为我们只是对构建 ROC AUC 曲线感兴趣,跳过它。

让我们预测类的概率,并将结果转换成一个数组。

y_score = classifier.predict_proba(X_test)
y_score = np.array(y_score)
print(y_score)

The 1st index of each inner array is the probability the example’s class is 0. The 2nd index is the probability that example’s class is 1.

下面的代码可能有点混乱。对 3 个(或更多)类使用label_binarize()会将单个y[2]转换为[0 0 1],或者将[0]转换为[1 0 0],但是对仅有的 2 个类就不一样了。所以我们调用 numpy 的hstack来重新格式化输出。

from sklearn.preprocessing import label_binarizey_test_bin = label_binarize(y_test, neg_label=0, pos_label=1, classes=[0,1])y_test_bin = np.hstack((1 - y_test_bin, y_test_bin))
print(y_test_bin)

Our label binarized output.

生成曲线。

from sklearn.metrics import roc_curve, auc
import matplotlib.pyplot as pltfpr = dict()
tpr = dict()
roc_auc = dict()for i in [0,1]:# collect labels and scores for the current indexlabels = y_test_bin[:, i]scores = y_score[:, i]# calculates FPR and TPR for a number of thresholdsfpr[i], tpr[i], thresholds = roc_curve(labels, scores)# given points on a curve, this calculates the area under itroc_auc[i] = auc(fpr[i], tpr[i])

此时,我们可以分别计算 0 类和 1 类的 ROC 曲线。但是为了简单起见,我们将把它们结合起来,生成一条曲线。

免责声明:这在类平衡时更有意义,否则它可能会掩盖一个事实,即模型在一个类中表现很差,而在另一个类中表现很好。但是我们还是会在这里学习如何做。

我们将使用“微平均”并对两个类别的 TPR 进行拉平,对 FPR 也是如此。会为我们做这件事。例如,[[1,0],[0,1]]变成了[1,0,0,1]

fpr["micro"], tpr["micro"], _ = roc_curve(y_test_bin.ravel(), y_score.ravel())
roc_auc['micro'] = auc(fpr["micro"], tpr["micro"])

现在画出曲线。

plt.figure()
lw = 2
plt.plot(fpr[1], tpr[1], color='darkorange',lw=lw, label='ROC curve (area = %0.2f)' % roc_auc[1])
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic example')
plt.legend(loc="lower right")
plt.show()

My code for plotting was inspired by sklearn docs.

不错!这是一个非常棒的曲线。

橙色曲线下的面积越大,模型就能更好地区分类别。从另一个角度来看,曲线越靠近左上角越好。

我们所说的“不同的分类阈值”是什么意思?

如果你习惯使用现成的 sklearn 分类器,你会知道.predict输出预测的类。但是您可能不知道这是基于默认的 50%分类阈值。

大多数分类器,像LogisticRegression都有一个叫做predict_proba()的方法来预测一个例子落入每个类别的概率,而不是调用.predict()

使用这个你可以使用你指定的任何阈值重新计算输出的类。

高曲线好背后的直觉是什么?

一个正确分类大多数例子,并且输出接近0.0(不是这个类)或者1.0(是这个类)的预测概率的模型,会有一条类似上面的曲线。

它告诉我们,改变分类阈值不会对模型的分类输出产生太大影响,因为模型非常确信每个例子要么是一个1要么是一个0

例如,如果模型输出 SMS 消息是垃圾消息的预测概率为0.9,则将阈值从0.5改变为0.6对输出的类别没有影响。该模型对其输出的类非常有信心。

相反,如果模型在0.30.7范围内输出大多数预测概率,那么将阈值从0.5移动到0.6将改变输出的类别。你可以说像这样的模型对自己预测的分类不自信。

为什么是 ROC 和 AUC?

该曲线是“ROC 曲线”,其描绘了不同阈值下的 TPR 和 FPR。

AUC 只是曲线下面积的计算。这是一种不用看曲线就可以量化模型准确性的方法,或者是在目测曲线下的区域不能给出明确的赢家时,比较两个模型之间的曲线。

什么是 TPR?

真实阳性率。

TPR 是 TP 数除以 TP 和 FN 之和。

示例 1: 预测图像是否是狗的模型。
TP :正确预测了一个狗的形象就是狗。
FN: 错误预测一个狗的形象是猫。

例 2 :预测消息是否为垃圾邮件的模型。
TP :正确预测出一条垃圾短信是垃圾短信。
FN :错误预测垃圾短信是 HAM。

什么是 FPR?

假阳性率。

FPR 是 FP 的数除以 FP 和 TN 的和。

例 1: 一个预测图片是否是狗的模型。
FP :错误预测一只猫的形象是一只狗。
TN: 正确预测一个形象不是狗。

例 2: 预测消息是否为垃圾邮件的模型。
FP :错误地预测到一条 HAM 消息是垃圾消息。
TN :正确预测一条火腿消息是火腿。

ROC AUC 曲线做得不好的地方

ROC 曲线不是不平衡数据集的最佳选择。当两个阶层的人数持平时,他们是最好的。否则,模型在对特定类别进行分类时表现良好,可能会掩盖模型在预测其他类别时表现不佳的事实。

外卖

  • ROC AUC 曲线可以让我们深入了解模型在区分类别方面的预测能力。
  • AUC 较高的型号通常比 AUC 较低的型号性能更好。
  • ROC AUC 不是严重不平衡数据集的最佳选择。

让我们做个交易

原文:https://towardsdatascience.com/lets-make-a-deal-7eff0f5a7ef8?source=collection_archive---------19-----------------------

解决蒙蒂霍尔问题的三种方法

你的心脏跳得很厉害。你既兴奋又紧张,不知道接下来会发生什么。你以前从未上过电视,但你很了解这项运动。由老谋深算、魅力非凡的蒙蒂·霍尔领衔的《让我们做笔交易》是目前最受欢迎的电视节目之一。自 1965 年以来,你一直是一名普通观众,无数次看到蒙蒂与参赛者进行交易。有一次,你看到一个女人用 50 美元换取一个装有 1000 美元的信封。还有一次,你看到一个人拒绝了 800 美元,而是保留了一个盒子,结果发现里面只有纸巾!现在轮到你了。

蒙蒂·霍尔转向你。很快,就像广播员的剧本一样,“在这三个标有 1、2 和 3 的门后面,有一辆新的克尔维特;另外两个藏着不值钱的山羊。没错,绝对不值钱的山羊。现在那里,你会有哪扇门?”

你听到一个无声的“咩咩”声,但你不确定它来自哪里。

“我要 1 号门,”你自信地说。

“绝佳的选择!如你所见,3 号门后面是一只毫无价值的山羊。”3 号门打开了,一只黑白斑点的公山羊出现了。它几乎是可爱的,尽管它实际上一文不值。在你的城市公寓里养一只山羊的想法很滑稽,而且你也不知道如何卖掉一只山羊。

蒙蒂继续说道,“1 号门是你的最终选择吗?你可以转到 2 号门,但不能回头。我不希望在这里做出错误的决定。”

你考虑一下情况。你最初的选择有⅓概率是正确的,但是你被授予了新的信息,3 号门现在退出了。汽车一定在 1 号门或 2 号门后面,但是是哪一个呢?你考虑如果你从 1 号门换到 2 号门,却发现汽车一直在 1 号门后面,你会感到多么沮丧。也许坚持最初的选择是最好的…或者是吗?

蒙蒂·霍尔问题

蒙蒂霍尔问题是一个经典的脑筋急转弯,测试一个人用条件概率进行推理的能力。另外,问题的前提增加了一个心理边缘;许多人选择留在原来的车门,只是为了避免从汽车切换的失望。在这篇文章中,我将演示 3 种方法来确定最佳策略,留下或转换。

频率主义方法

相对来说,多次模拟 Monty Hall 游戏并记录游戏的胜败次数是比较容易的。从统计学的角度来说,我们可以将游戏中的每一次尝试视为伯努利试验(具有二元结果的随机实验),成功概率为 P。根据大数定律,如果实验次数 N 非常大,则预期胜率为 100 * P%。通过记录停留和转换策略的许多试验的结果,可以使用 z 检验来确定胜率是否存在统计上的显著差异。

下面的 python 代码定义了一个模拟游戏的函数monty_hall。关键字参数switch控制是采用停留还是切换策略。此外,设置关键字参数verbose = True允许一个人以互动的方式玩游戏,并当场选择是留下还是转换。

import numpy as npdef monty_hall(chosen_door, switch = False, verbose = False): '''Parameters----------chosen_door : Initial choice of door, must be either 1, 2, or 3.switch : False --> stay strategyTrue --> switch strategy.verbose: False --> no input requiredTrue --> player is asked if they'd like to switchdoors. overrides switch input.Returns------1 : if the game is won0 : if the game is lost'''# Correct indexing for chosen doorchosen_door += -1 # Randomly initialize array to represent the 3 doors# Array contains two 0s for goats and a single 1 for the cardoors = [0, 0, 0]doors[np.random.randint(0,3)] = 1# Reveal a door concealing a Goatrevealed_door = np.random.choice([i for i, x in enumerate(doors) if x == 0 and i != chosen_door])switch_door = list({0, 1, 2} - {chosen_door, revealed_door})[0]# If verbose == True ask the player if they'd like to switch.input_string = f"You've chosen door {chosen_door + 1}, an excellent choice! As you can see behind door {revealed_door + 1} is a worthless goat. Is door {chosen_door + 1} your final choice? You may switch to door {switch_door + 1} but there's no going back. Enter y if you'd like to switch."if verbose == True:choice = input(input_string)if choice == 'y':switch == Trueelse:switch == False# Return the result of the gameif switch == False:result = doors[chosen_door]else:result = doors[switch_door]if verbose == True:if result == 0:print("How unfortunate, you've chosen a worthless goat!")if result == 1:print("Congratulations, you've just won a new Corvette!")return result

让我们用这个函数对停留和转换策略进行 100,000 次游戏。结果将保存在停留和切换列表中,并将打印每个策略的胜率。

i = 0
stay = []
switch = []while i < 100000:stay.append(monty_hall(np.random.randint(1, 4)))switch.append(monty_hall(np.random.randint(1, 4), switch = True))i += 1print(f"Stay win rate: {round(100 * np.sum(stay) / 100000, 1)}%")
print(f"Switch win rate: {round(100 * np.sum(switch) / 100000, 1)}%")

入住率:33.3%

切换成功率:66.6%

显然,这两种策略之间有很大的区别。尽管在这里并不真的需要统计检验来检测差异,但我们还是要对数据进行双尾 z 检验。

from statsmodels.stats.weightstats import ztesttest_statistic, p_value = ztest(stay, switch)
print(f"Test Statistic: {round(test_statistic, 1)}")
print(f"P-Value: {round(p_value, 5)}")

测试统计:-157.5

p 值:0.0

z-test 返回的测试统计值为-157.5,p 值为 0(实际上是一个无穷小的数字,我们的计算机已将其四舍五入为 0)。因此,可以完全肯定地拒绝零假设,即逗留和转换策略的成功率是相同的。事实证明,转换显然是更好的策略!

但是为什么切换要好得多呢?为了更好地理解,让我们从贝叶斯的角度来看这个问题。

贝叶斯方法

与频率统计相比,贝叶斯统计为因果关系提供了另一种视角。频率主义统计学试图回答这个问题,“给定我的假设,我的数据有多大的可能性?”另一方面,贝叶斯统计试图回答这个问题,“给定我的数据,我的假设有多大的可能性?”这种差异是微妙而强大的。

Thomas Bayes, English minister, philosopher, and statistician known for deriving the rule that bears his name. However, the modern version used today was derived by the French mathematician Pierre-Simon Laplace.

贝叶斯统计的基石是贝叶斯规则,这是一个简单的恒等式,告知如何在给定新数据的情况下正确更新对假设的信念。

P(H|D) = P(D|H)*P(H) / P(D)

H =假设,D =新观察到的数据

P(H|D)是给定新的观察数据时我们假设的概率。P(D|H)是假设假设是正确的,观察到数据的概率。P(H)是我们在观察新数据之前对假设正确的概率的评估,也称为“贝叶斯先验”。P(D)是在任何情况下观察到数据的概率,无论假设是否成立。

对于 Monty Hall 问题,有两种可能的假设:H1)汽车在最初选择的门后面,以及 H2)汽车不在最初选择的门后面,并且切换将导致获胜。现在让我们考虑一下 H1,看看如何用贝耶法则来确定这个假设的概率。

首先,考虑假设 P(H1)的先验概率。请记住,最初的选择是从三个选项中做出的,这三个选项都同样可能是正确的。P(H1),做出最初正确选择的概率,简单来说就是 1/3。

接下来,考虑观察到新数据的概率,假设 H1 是正确的。如果汽车实际上在最初选择的门后面,那么山羊出现在其他门的概率是 1/2,因为蒙蒂会在他的两个选项中随机选择。H1 = 1/2。

Billy goat. Isn’t he cute?

最后,考虑在任何情况下观察到新数据的概率。因为可能只有两个互斥的假设,P(D)可以用下面的等式来确定,P(D) = P(D|H1)P(H1) + P(D|H2)P(H2)。我们已经知道 P(D|H1) = 1/2,P(H1) = 1/3。P(H2) = 2/3,是最初做出错误选择的概率。最后,P(D|H2) = 1/2,因为如果我们的第一扇门隐藏了一只山羊,剩下的两扇门都有相等的概率隐藏第二只山羊。总而言之,P(D) = 1/2 * 1/3 + 1/2 * 2/3 = 1/2。

我们总共有:P(H1) = 1/3,P(H2) = 2/3,P(H1)= 1/2,P(H2)= 1/2,P(D) = 1/2

现在可以将这些值插入到贝叶斯规则中,以确定汽车在我们最初选择的门后面的概率。

P(H1 | D)= P(D | H1)* P(H1)/P(D)=(1/2 * 1/3)/(1/2)= 1/3

看来新的信息并没有增加最初选择正确的可能性!

当我们这样做的时候,让我们也使用贝叶斯法则来确定 H2 的概率,即汽车不在我们最初选择的后面,以及转换将导致胜利。

P(H2 | D)= P(D | H2)* P(H2)/P(D)=(1/2 * 2/3)/(1/2)= 2/3

That billy goat sure is cute, but most people would rather have this awesome 70s Corvette.

我们现在使用贝叶斯推理来证实我们的频率主义者实验的结果。此外,为 H1 和 H2 确定的贝叶斯概率与观察到的胜率完全一致!到目前为止,为什么换工作比呆在公司好得多已经变得越来越清楚了,但是让我们以最后一种方式来看待这个问题,以便真正理解这一点。

博弈论方法

蒙蒂霍尔问题当然是欺骗性的,但它并不特别复杂。通过思考所有可能的结果,人们可以很快得出结论:转换是最优策略。

考虑转换策略会赢或输的情况。当初始门隐藏汽车时,切换将会失败。当初始门隐藏一只山羊时,蒙蒂将被迫露出第二只山羊,剩下的门将隐藏汽车,切换将总是获胜。由于最初的选择将仅在 3 场游戏中的 1 场游戏中隐藏汽车,所以转换策略将在 3 场游戏中输掉大约 1 场,并赢得另外 2 场。相反,留下来只会赢得最初选择恰好正确的三分之一的比赛。

蒙蒂拍摄一个不耐烦的样子,“现在任何一天伙计。我开始觉得我应该把那辆新的克尔维特给山羊!”

“咩咩”黑白相间的公山羊似乎同意蒙蒂的观点。

"我最后问一次,你愿意换到 2 号门吗?"

在突然的顿悟中,你想起了你读过的一篇关于这个主题的文章。虽然你不能确定,但你明白你的选择的可能性。抵制住坚持己见的诱惑,接受自己造成的不幸可能带来的尴尬,你平静地宣布“我要换到 2 号门。”

为了更深入地探究天魔堂问题,它的历史、心理学和许多变化,请查看杰森·罗森豪斯的《天魔堂问题

我们用机器学习做一些分子吧!⚛️

原文:https://towardsdatascience.com/lets-make-some-molecules-with-machine-learning-️-429b8838e3ef?source=collection_archive---------10-----------------------

米(meter 的缩写))医学和材料科学

一个新分子到达大众市场平均需要 10 年。

【1912 年 4 月, RMS 泰坦尼克号 在它的处女航中与大西洋上的一座冰山相撞,淹没了 1500 条生命,创造了历史。几十年后,沉船被发现,仍然充满了 20 世纪的历史。在打捞泰坦尼克号几个月后, 挑战者号航天飞机 将在全国数百万人热切的目光注视下发射。发射 73 秒后,航天飞机在半空中爆炸。

Historically relevant material failures

这两起灾难的根本问题不在于人为错误和设计。问题出在素材上。泰坦尼克号船体的失败程度不亚于挑战者号的右火箭助推器。我们记得这些悲剧事件,不是因为它们发生了,而是因为它们本来是可以避免的。泰坦尼克号和挑战者号建造时已知的更好的材料。但是仅仅知道存在更好的材料是不够的;它们必须是可用的和适用的。

问题是,一个分子从了解到应用需要大量的时间。今天,平均时间是 10 年。

According to Scientifist, the average time for a drug to complete this process is 12 years and 1.5B dollars (courtesy of Scientifist)

10 年足够花费数万亿美元,5 亿人死亡,数百万小时浪费在解决问题上,如果我们有合适的材料或药物,这些问题本来可以不那么严重。

这并不新鲜。从历史上看,科学进步是缓慢的。几个世纪以来,由石头制成的工具一直是标准的,定期开处方的药物治疗通常弊大于利。直到人类重视科学的进步,我们才开始创造更好的技术,从而开始了正反馈循环:

有一段时间,这种反馈循环导致了稳定的线性增长。但是随着我们对科学掌握的增长,我们的技术也在进步。随着人工智能等技术的出现,这种增长必然会呈指数级加速。

人工智能给了研究人员更多对分子空间的控制,从而在科学领域掀起了波澜。

在我的上一篇文章中, A.I 增强了分子发现和优化 ,用 A.I 在高水平上讨论了当前加速科学的方法。在这里,我将介绍我最近的一个项目,该项目遵循当前在科学领域的 ML 应用研究中使用的最常见的工作流/管道。

项目小说

这个项目的目标是用递归神经网络产生新的分子。这些分子可能没有用,甚至可能无效,但想法是训练模型学习微笑串中的模式,使得输出类似于有效分子。SMILES 是一个分子的字符串表示,基于给定分子的结构和组件。例如,环丙沙星看起来有点像这样:

Colors correspond to the character (Courtesy of Wikipedia)

神经网络的选择取决于我们要输入的数据类型。在这种情况下,我们将向它提供微笑字符串作为数据,因此递归神经网络(RNN)最适合这项工作。习惯于用相对更高效和有效的方式来增强 RNN 的内部结构;LSTM 牢房。我们将使用由 LSTMs 组成的几个层,在超过 200,000 个微笑字符串的数据集上进行训练。

步骤 1 —映射:

与大多数语言处理 rnn 一样,第一步是创建字符到整数的映射(允许神经网络处理数据),反之亦然(将结果翻译回字符)。

最简单的方法是创建一组独特的字符,并枚举每一项。在像英语这样的自然语言中,有 26 个字母(是大写字母的两倍),以及大量的语法符号和语法字符。在微笑字符串中,有两种类型的字符:

  1. 特殊字符:“/”、“(”、“”、“=”等。
  2. 元素符号:“C”、“O”、“Si”、“Co”等。

这个独特字符的列表被列举并方便地放入字典中。

值得注意的是字典不认为由两个字符组成的元素符号是一个元素。例如,硅元素符号的“S”和“I”算作两个独立的字符。这意味着模型必须了解“Si”和“S”之间的区别,这两者是完全不同的元素。将这两个字符的符号硬编码到字典中是完全可能的,但只是为了好玩,我将它们分开,以观察模型的表现如何。

第 2 步—数据预处理:

一旦有了惟一的字符映射,就可以着手将 SMILES 字符串数据集中的每个字符转换成整数。简单调用我们在第一步中构建的字典就可以了。

同时,您可以通过简单地将每个整数除以数据集中唯一字符的总数来规范化所有的整数。最后,将得到的整合和标准化数据集重新整形为适合神经网络模型的格式。

步骤 3 —模型架构

使用 Keras,构建模型非常简单。

Play around with the numbers! Try more layers, more neurons, more dropout, whatever you fancy!

我们的模型有多层,每一层都有数量递减的神经元;你可以随意摆弄这些数字。这是一个很大的概括,但经验法则是,神经网络中的层和神经元越多,计算量越大,但其性能也越好。

步骤 4—检查点:

我们都经历过。你已经在你一直在写的文章或报告上取得了很大进展,但突然你的电脑出了故障——你所有的工作都消失在深渊中。顺便提一下,训练神经网络也有同样的问题。谢天谢地,有一个解决方案。

还记得在新的马里奥游戏中,一旦你过了一半,游戏会保存你的进度吗?

For nostalgia, and to emphasize how important it is to SAVE!!! (courtesy of TrustedReviews)

检查点是 Keras 库中的一个内置功能,它允许我们将我们的训练进度(模型在任何给定时期的权重)保存在一个文件中,然后可以将其传输到另一个设备或保存起来供以后使用。检查点可能是最不受欢迎的,也是最有用的机器学习技术之一。

Don’t forget to call the callbacks parameter when fitting your model!

检查点对于将训练从预测、分类或生成步骤中分离出来特别有用。在将节省下来的重量加载到 CPU 上之前,通过在 GPU 或云服务上进行训练,你可以减少完成一个项目所需的时间。因此,检查点对于迁移学习或者简单地暂停和恢复训练是有用的。它们还可以用于对每个改进时期的模型输出进行采样,为网络模型增加一点透明度。

第 5 步—培训:

我使用分类交叉熵作为带有Adam优化器的损失函数(混合了RMS-propADAgrad以及内置动量)。为了利用尽可能多的数据集,该模型有 19 个 512 批次大小的时期可供学习。一般来说,更多的历元与更小的批量配对允许网络更好地从数据中学习,但代价是更长的训练时间。

第 6 步—生成:

发电相对简单。首先,我们导入从训练中保存的检查点(这样我们就不必在每次想要生成新分子时重新训练模型)。下一步是从数据集中随机选择一个 SMILES 字符串作为参考,最后生成指定数量的字符。

The exact code is used for generating any kind of text - only in this case, the text is a molecule.

根据数据集大小的选择、学习率和其他可以对模型进行的自定义调整,结果会有所不同,但理想情况下,您应该得到类似于有效分子的输出。如果你插入一个精确度较低的检查点文件,你实际上可以看到神经网络是如何学习并随着时间变得更好的。通常,它以一系列只有一次的字符开始:

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

但是随着时间的推移,包含交替字符会变得更好

C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1 C1

最终,随着它学习子结构,输出将更加多样化

C1 C1 C1 C1 C1 C1 C1((((((((((/////////ccccccchchchchchchchchc)))))))))

目标是尽可能接近

O1C = C[C @ H]([C @ H]1 O2)C3 C2 cc(OC)C4 c3oc(= O)C5 = C4 CCC(= O)5

尽可能。

可能的改进

这个项目可以用两种不同的方式来增强,一些以数据为中心,另一些以模型本身的架构为中心。

数据集

20 万个分子的数据集虽然令人印象深刻,但如果再大一些也不会有什么坏处。除了在互联网上搜寻更多的微笑字符串,一个可能实现的技术是数据扩充。

Data augmentation as explained using Andy Warhol paintings

数据增强实际上类似于安迪·沃霍尔的画;取一张图片,稍加修改,然后添加到数据集。从本质上说,这是数据扩充,尽管过于简单。对微笑字符串也可以这样做;获取字符串,找到它的排列,并将其添加到您的数据集中。

在这种情况下,项目的目标是生成尽可能接近有效的分子,而不是具有特定或期望属性的分子。这消除了偏向一种特定类型分子的结果的风险,因此增加我们现有的 200k 分子数据集是安全的。我们可以通过枚举超出其规范形式的微笑字符串来扩充数据,这基本上意味着以另一种方式编写相同的微笑字符串,所有这些字符串最终都表示相同的分子。这给了模型更多的字符串来学习,因为每个分子都有许多不同的微笑字符串,其数量随着分子大小和复杂性的增加而增加。

建筑

在这个项目中,LSTM 被用作各层的主节点。然而,还有许多其他强有力的选择。神经图灵机(NTM) 和它的兄弟例如,可微分神经计算机(DNCs) 都是由谷歌的研究人员创造的最先进的架构。两种架构都很强大。NTMs 和 DNCs 令人印象深刻,因为它们有一个外部组件,可以比 LSTMs 更好地“记住”事情。这个外部组件充当一种存储体。

The DNC architecture (courtesy of The Nature magazine)

你可以在这些博客文章(NTMs, DNCs )和关于它们的研究论文(NTMs,DNCs)中读到关于它的所有内容,或者在我的文章中获得关于 RNN 建筑家族所有成员的高层次概述。本质上,这两个强大的替代方案都有内置注意力机制的记忆库,这允许它们选择性地记忆数据的部分(在这种情况下是文本,但也可以是图像),这被认为是非常重要的。这在生成具有所需特性的分子方面可能非常有用,因为一些特性如毒性是由分子内的亚结构决定的,当翻译成微笑时,它是该串的特定部分。

还有其他因素需要考虑,比如其他可能的数据集和格式的丰富性。不同类型的分子表示代替微笑,例如 SMARTS)和架构改进(例如对抗性训练或强化学习的使用)。这两种改进已经有了一些值得注意的实现。

专用工具

有一些非常棒的工具可以用于大规模和高质量的制作,但是没有多少人知道。计算材料科学、生物学、化学和物理学项目将使用如下软件包:

  • Matminer —一个用于材料科学数据挖掘的Python
  • Magpie —基于Java的材料性能预测 ML 库
  • PyMKS——一个专门研究结构-属性关系的Python图书馆
  • deep chem(—Python一个让科学领域的 ML 民主化的图书馆
  • Openbabel —一个用于生物和化学信息学的PythonC++

这些专门的包与 Python 的内置和扩展库一致,这意味着它们可以与 numpy、scipy、matplotlib 等一起使用。对于项目。未来的工作将探索这些工具包能做什么!

下一步是什么+关键要点

Project Novel 是用基本的 M.L 工具和固体数据集生成分子的最基本方法的一个例子。大多数研究将结合其他架构的方面,如对抗训练,或强化学习,以提高生成分子的有效性,或使模型结果偏向具有所需属性的分子。

即使在最好的情况下,LSTMs 对生成的文本样本的说服力也是有限的。原因在于微笑字符串本身,这是不是计算表示分子的最佳方式。在不久的将来,可能会有更好的框架专门用于化学信息学和相关科学领域。然而,目前标准仍然停留在递归神经网络和分子串表示的动态组合上。

在我的下一篇文章中,我们将深入探究科学和人工智能的交汇点在哪里,以及随着人工智能加速科学的发展,会发生什么变化。

关键要点

  • 材料和药物的失败是研发速度缓慢的结果
  • 缓慢的研发速度可以通过像 M.L 这样的指数技术得到改善
  • 人工智能应用于科学最流行的方式是使用循环神经网络和分子串表示法
  • 递归神经网络和分子串表示法不是将 M.L .应用于科学的最佳方式
  • 人工智能和科学的交叉仅仅触及了表面;项目仍处于初级阶段,有很多东西值得期待!

需要看更多这样的内容吗?

跟我上LinkedIn 脸书 insta gram,当然还有

我所有的内容都在 我的网站 我所有的项目都在GitHub

**我总是希望结识新朋友、合作或学习新东西,所以请随时联系flawnsontong1@gmail.com

向上和向前,永远和唯一🚀

📝稍后在杂志上阅读这个故事。

🗞每周日早上醒来,你的收件箱里会有本周最值得关注的科技故事、观点和新闻:获取值得关注的时事通讯>

让我们开始吧——PUBG 一步一步教程

原文:https://towardsdatascience.com/lets-play-a-pubg-step-by-step-tutorial-1c0b38b322e8?source=collection_archive---------16-----------------------

大家好!这款笔记本是专门为想要进入 Kaggle 竞赛领域但不知道如何开始旅程的初学者准备的。

最有效的方法,就是去做!

嗯,我相信这个。对于初学者来说,这是一个很好的平台,可以让他们在正在进行的比赛中动手。我鼓励你们所有人在这个 PUBG 比赛中尝试并获得乐趣。

Photo by Kony Xyzx on Unsplash

从 Kaggle 页面

player unknown ' s BattleGrounds(PUBG)广受欢迎。销量超过 5000 万份,是有史以来第五大畅销游戏,每月有数百万活跃玩家。

你得到了大量匿名的 PUBG 比赛统计数据,格式化后每行包含一名球员的赛后统计数据。数据来自各种类型的比赛:单人赛、双人赛、团队赛和定制赛;不能保证每场比赛有 100 名玩家,也不能保证每组最多 4 名玩家。

你必须创建一个模型,根据玩家的最终统计数据预测他们的最终排名,范围从 1(第一名)到 0(最后一名)。

基本上,我们被要求在不玩游戏的情况下预测每个玩家的最终位置。多酷啊!这就像一个成功的公式,

哦,你有这么多大头照,你会进入前 5 名的。

太神奇了,不是吗?

在这个游戏中,有 n 个不同的人用不同的策略玩,知道什么能帮助你赢得游戏会很有趣。

和大多数 Kaggle 比赛一样,你会得到两个数据集:

  • 一个训练集,包含一组球员的结果(或目标变量)以及其他参数的集合,如他们的 groupId、matchId、助攻等。这是您必须在其上训练预测模型的数据集。
  • 一个测试集,你必须根据为两个数据集提供的其他玩家属性来预测现在未知的目标变量。

为了让事情运转起来,我们将从简单的方法开始,这些方法在逻辑上对所有人来说都是合理的。在我们前进的道路上逐渐转向深度学习方法。是的,你没听错。深度学习在 r .让我们不要忘乎所以。

让我们首先从加载这些库开始。

读取训练和测试文件

数据一瞥

只是我,还是你们也注意到了测试文件中有一个列不匹配(有一列丢失了)?
winPlacePerc 列是我们在测试中要预测的。如果在测试文件中有,这就不是一个挑战了,对吗?

让我们更深入地研究我们的目标变量。

好吧,这样更容易理解。0.4583 是训练集中的中值。这当然意味着大多数玩家都在完成游戏的区间(努力)的中间。你准备好做你的第一个预测了吗?既然大多数玩家都完成了中等级别的训练,也许假设测试组中的每个人都完成了是一个好的开始?一点玩快速脏,并发送一个预测。

您可能已经注意到,我们在目标值中有一个空值。除此之外,它是一个超级干净的数据集。(警告:这不是真实情况)。所以我们用 0 来估算。

现在在机器学习中,主要有两类变量。

  1. 分类变量,其值是有限的,通常基于特定的有限组。例如,分类变量可以是国家、年份、性别、职业。
  2. 然而,连续变量可以取任何值,从整数到小数。例如,我们可以得到收益,股票价格。

机器学习算法不支持字符。所以我们要把它们转换成因子(分类)。

我们的第一次预测出了什么问题?让我们分析一下。

我们看到了中间值(或最常出现的值)并将其应用于预测文件,希望其他所有玩家都在 try hards 类别中。我们是多么自信啊,啊!

欢迎来到超适合

  • 一个好的机器学习模型的目标是从训练数据很好地推广到来自问题域的任何数据。这使我们能够根据模型从未见过的数据对未来做出预测。
  • 过拟合指对训练数据建模过好的模型。
  • 过度拟合发生在模型学习训练数据中的细节和噪声,以至于对模型在新数据上的性能产生负面影响的时候。这意味着训练数据中的噪声或随机波动被模型拾取并学习为概念。问题是这些概念不适用于新数据,并对模型的概括能力产生负面影响。

在我们的例子中,通过查看中间值,我们认为它将适用于测试数据中的所有其他值。这是数据的过度拟合。

如何解决过度拟合?

  • 一个验证数据集仅仅是你的训练数据的一个子集,你把它从你的机器学习算法中保留下来,直到你的项目结束。在训练数据集上选择并调整了机器学习算法后,您可以在验证数据集上评估学习到的模型,以最终客观地了解模型在未知数据上的表现。

EDA 和特征工程

嗯,理论上讲步行距离应该是获胜的关键因素。由于跑步速度几乎是静止的,你对此无能为力。所以,如果你必须处于领先的位置,你就必须继续前进。步行距离与获胜几率成正比。

提升也应该是一个重要因素。如果你想多活些时间,很有可能你使用了一次或多次强化。

我们还看到了表示游戏模式(如小队、双人和单人模式)的预期分组数。小于 10 的值可能需要进一步调查,因为这些很可能是自定义游戏或断开错误。

相互关系

让我们看看变量之间的相关性。这可能会给我们一个良好的开端,以防从长远来看所有的变量都被认真考虑。

正相关——步行距离、武器获得、提升

负相关 —必杀之地

杀戮地点 —在比赛中杀死的敌方玩家数量排名。等级越低,赢得比赛的机会就越大。

1.NumGroups —我们在比赛中拥有数据的组的数量。

有趣的是,当 numGroups 为 1 时,只有的值为 0。让我们记住这一点,并在测试数据中进行更改。(一些后期处理)。

2.步行距离——步行的总距离,以米为单位。

似乎数据有很多离群值,这使得(或骗子)在训练数据。时速超过 20 公里是不切实际的。我们会认为这是一个欺骗代码,并继续前进。

3 —杀死

在这里,我为那些拥有超过 40 次杀戮的 id 创建了一个标志

4.头像率

爆头杀 可能有很多可以告诉你一个玩家有多好。我已经创建了一个变量 headshot_rate 来理解头部枪击致死率与总致死率的关系。

这里,我们创建了 test1 作为验证集,以便在真实测试数据集上进行测试之前进行进一步测试。

僵尸

问题陈述

主要有两种类型的机器学习问题

  • 分类 —输出变量采用类别标签。
  • 回归 —输出变量取连续值

这里,由于目标变量(winPlacePerc)是一个连续变量,该问题属于回归问题。

线性回归是回归的首选方法。

线性回归用于根据一个或多个输入预测变量 x 来预测结果变量 Y 的值。目的是在预测变量和响应变量之间建立线性关系(数学公式),这样,当只有预测变量(Xs)值已知时,我们可以使用该公式来估计响应变量 Y 的值。使用我们的 PUBG 数据,假设我们希望对资产、kills 和 winPlacePerc 之间的线性关系进行建模。

Y = β1 + β2X + ϵ

其中,β1 是截距,β2 是斜率。统称为回归系数。ϵ是误差项,y 的部分回归模型无法解释。

是线性的!

  • 在后台,代表“线性模型”的 lm 通过最小化最小二乘准则产生最佳拟合线性关系。
  • 对于我们模型的初始评估,我们可以使用 summary。这为我们提供了关于我们的模型的大量信息,我们将逐一介绍。

斯捷潘克

逐步回归中,选择程序由统计包自动执行。变量选择的标准包括调整的 R-square、Akaike 信息标准(AIC)、贝叶斯信息标准(BIC)、Mallows 的 Cp、PRESS 或错误发现率(1,2)。逐步选择的主要方法是向前选择、向后淘汰和两者的结合

平均绝对误差

平均绝对误差(MAE) 是另一个用于回归模型的损失函数。MAE 是我们的目标变量和预测变量之间的绝对差值的总和。因此,它测量的是一组预测中误差的平均大小,而不考虑它们的方向。(如果我们也考虑方向,这将被称为平均偏差误差(MBE),它是残差/误差的总和)。

H2O——图书馆

H2O 是一个开源、内存、分布式、快速、可扩展的机器学习和预测分析平台,允许您在大数据上构建机器学习模型,并在企业环境中轻松实现这些模型。

此外,它还使用内存压缩来处理大型数据集,即使是小型集群也是如此。它还包括实现并行分布式网络培训规定。

深度学习

希望你们学到了一些东西。建设性的反馈总是受欢迎的。

这里有完整的代码:https://github.com/Arjundasmarath/PUBG

跟着我上kaggle:https://www.kaggle.com/arjundas

让我们玩 21 点(用 Python)

原文:https://towardsdatascience.com/lets-play-blackjack-with-python-913ec66c732f?source=collection_archive---------2-----------------------

我们用 Python 实现了一个 21 点模拟器,以便更好地理解去拉斯维加斯的风险

这篇文章绝不是试图推广 21 点或赌博行为。任何时候你在赌场赌博,赔率都对你不利——随着时间的推移,你会输钱。不要拿你输不起的东西去冒险!

更正: 我意识到(感谢@DonBeham 的友好提示)在某些情况下,我的 total_up 函数错误地处理了多个 ace。我已经在我的 GitHub 上更新了下面的代码和 。我道歉!

我最近没有为博客写任何代码,所以我想写一篇与编程相关的文章。概率和统计的经典应用之一是对机会游戏(赌博)的研究。碰运气的游戏(纸牌游戏、骰子游戏等。)是统计学家的最爱,因为它们既展示了随机性,也展示了某种必然性:

  • 随机在那场你不知道会有什么结果的游戏中。
  • 必然在于你知道大量游戏的平均结果会是什么。

今天,我们将通过用 Python 编写一个 21 点模拟器来研究 21 点,模拟一系列游戏,然后研究我们的玩家做得如何。我将假定您对 21 点游戏有一些基本的了解,但这里有一个关于该游戏玩法的快速复习:

  1. 玩家下注。
  2. 玩家发 2 张牌。
  3. 庄家得到 2 张牌,第二张牌对玩家是隐藏的。
  4. 游戏的目标是获得比庄家更高的总点数(但不超过 21,任何超过 21 的点数都是自动损失,称为破产 ) —如果你以这种方式击败庄家,你将从赌场赢得你所赌的钱(如果庄家破产,你也将获胜)。ace 可以值 1 或 11;其他每张牌的面值都相同(正面牌的面值为 10)。
  5. 由一张 a 和一张脸牌组成的最初 2 手牌被称为 21 点,是最好的一手牌。
  6. 在第一轮发牌后,每个玩家都可以选择打(收到更多的牌)或留(没有更多的牌)。如果击中导致玩家失败(总数超过 21),那么他或她的赌注就输了。
  7. 在所有玩家都完成击球/停留后,庄家翻开他隐藏的牌。如果庄家的总数少于 17,那么他或她需要击中(收到一张新卡)。这个过程一直重复,直到庄家的手牌总数达到 17 或更多,或者破产(超过 21)。
  8. 庄家玩完之后,就决定了最后的结果——如果庄家破产,那么任何没有先破产的玩家就赢了他或她的赌注。如果庄家没有破产,那么庄家的总数将与每个玩家的总数进行比较。任何玩家的总点数大于庄家的,他或她就赢了钱(按下注的金额)。任何玩家的总点数少于庄家的,他或她就输钱。在平局的情况下不兑换货币。

如果你想了解更多关于 21 点规则的内容,请访问这个网站。开始编码的时间到了!

编写我们的模拟器

你可以在我的 GitHub 上找到完整的代码。

使用面向对象编程可能是个好主意。但是在这一点上,我还不习惯用那种方式写代码。我可能会在将来的某个时候修改我的代码,使之面向对象;但这是另一天的项目。

首先,让我们把输入语句放在一边:

import numpy as np
import pandas as pd
import random
import matplotlib.pyplot as plt
import seaborn as sns

现在让我们创建几个函数来帮助我们。首先,我们需要一个函数来创建一副新的纸牌供我们玩。 make_decks 函数就是这么做的——它为每种牌类型添加四张牌(ace、2、3、4 等等)。)到列表 new_deck ,洗牌 new_deck ,并返回新创建的列表(deck)供我们玩。还要注意,我们可以通过 num_decks 来指定我们希望该函数创建多少副牌。

# Make a deck
def make_decks(num_decks, card_types):new_deck = []for i in range(num_decks):for j in range(4):new_deck.extend(card_types)random.shuffle(new_deck)return new_deck

我们还需要一个函数,可以增加我们手中的卡的价值。它比简单的求和稍微复杂一些,因为 ace 可以值 1 或 11,这取决于哪一个对持有者最有利。因此,我们的函数首先计算手中每张非 a 牌的值(我用数字 10 表示所有的正面牌,因为它们在 21 点中的功能都是相同的)。然后它会计算 ace 的数量。最后,它决定了每张 a 值多少钱,这取决于你其余牌的价值。

修正:在我之前版本的代码下面,有一个错误。为了解决这个问题,我添加了助手函数 ace_values ,它将您手中的 ace 数作为整数输入,并输出您的 ace 值的唯一值列表。计算给定数量的 ace 的排列(和它们的和)比我想象的要多,我需要写下面两个助手函数来完成它(更多细节,请参考我在下面代码块中的注释):

# This function lists out all permutations of ace values in the
# array sum_array.
# For example, if you have 2 aces, there are 4 permutations:
#     [[1,1], [1,11], [11,1], [11,11]]
# These permutations lead to 3 unique sums: [2, 12, 22]
# Of these 3, only 2 are <=21 so they are returned: [2, 12]
def get_ace_values(temp_list):sum_array = np.zeros((2**len(temp_list), len(temp_list)))# This loop gets the permutationsfor i in range(len(temp_list)):n = len(temp_list) - ihalf_len = int(2**n * 0.5)for rep in range(int(sum_array.shape[0]/half_len/2)):sum_array[rep*2**n : rep*2**n+half_len, i]=1sum_array[rep*2**n+half_len : rep*2**n+half_len*2, i]=11# Only return values that are valid (<=21)return list(set([int(s) for s in np.sum(sum_array, axis=1)\if s<=21]))# Convert num_aces, an int to a list of lists
# For example if num_aces=2, the output should be [[1,11],[1,11]]
# I require this format for the get_ace_values function
def ace_values(num_aces):temp_list = []for i in range(num_aces):temp_list.append([1,11])return get_ace_values(temp_list)

以上两个函数现在可以由函数 total_up 使用,该函数像我上面提到的那样,计算我们手中牌的价值(包括正确处理任何 a):

# Total up value of hand
def total_up(hand):aces = 0total = 0for card in hand:if card != 'A':total += cardelse:aces += 1# Call function ace_values to produce list of possible values# for aces in handace_value_list = ace_values(aces)final_totals = [i+total for i in ace_value_list if i+total<=21]if final_totals == []:return min(ace_value_list) + totalelse:return max(final_totals)

既然我们的助手函数已经完成了,让我们进入主循环。首先,我定义了我的关键变量:

  • 牌堆是我们将模拟的牌堆数量(其中每个牌堆可以是一副或多副)。
  • 玩家是每个模拟游戏的玩家数量。
  • num_decks 是每叠牌中的牌数。
  • card_types 是所有 13 种卡类型的列表。
stacks = 50000
players = 1
num_decks = 1card_types = ['A',2,3,4,5,6,7,8,9,10,10,10,10]

现在开始我们模拟器的主循环。有两个:

  1. 一个 for 循环,遍历我们想要模拟的 50,000 叠牌。
  2. 一个 while 循环,对于每叠牌,玩 21 点,直到该叠牌中有 20 张或更少的牌。此时,它移动到下一个堆栈。

numpy 数组, curr_player_results,是一个重要的变量,其中存储了每个玩家的游戏结果——1 表示赢,0 表示平,1 表示输。这个数组中的每个元素对应于 21 点桌上的一个玩家。

在 while 循环中,我们给每个玩家发一张牌,然后给庄家发一张牌(Python 注释说“先发一张牌”),然后我们再发一次,这样每个人都有 2 张牌。为了发牌,我利用了输入为 0 的 pop 函数——它返回列表的第一个元素,同时将它从列表中删除(非常适合从一堆牌中发牌)。当庄家牌堆中剩余的牌数下降到 20 张或更少时,新的牌堆用于替换旧的牌堆(移动到 for 循环的下一次迭代)。

for stack in range(stacks):blackjack = set(['A',10])dealer_cards = make_decks(num_decks, card_types)while len(dealer_cards) > 20:curr_player_results = np.zeros((1,players))dealer_hand = []player_hands = [[] for player in range(players)] # Deal FIRST cardfor player, hand in enumerate(player_hands):player_hands[player].append(dealer_cards.pop(0))dealer_hand.append(dealer_cards.pop(0))# Deal SECOND cardfor player, hand in enumerate(player_hands):player_hands[player].append(dealer_cards.pop(0))dealer_hand.append(dealer_cards.pop(0))

接下来,庄家检查他或她是否有 21 点(a 和 10)。请注意,在前面的代码块中,我将 21 点定义为包含 a 和 10 的集合。

如果庄家有 21 点,那么玩家就输了(并在 curr_player_results 中得到-1),除非他们也有 21 点(在这种情况下是平局)。

 # Dealer checks for 21if set(dealer_hand) == blackjack:for player in range(players):if set(player_hands[player]) != blackjack:curr_player_results[0,player] = -1else:curr_player_results[0,player] = 0

如果庄家没有 21 点,游戏继续。玩家自己做 21 点检查——如果他们有,他们就赢(在一些赌场,21 点支付 1.5 比 1,换句话说,如果你的赌注是 100 美元,那么你就赢 150 美元)。我通过将数组 curr_player_results 中对应于该玩家的元素设置为 1 来记录一次胜利。

对于没有 21 点的玩家,他们现在可以选择击球、停留等。对于这个模拟,我的目标是捕捉所有类型的玩家决策——聪明的、幸运的和愚蠢的。所以我基于抛硬币来为玩家做决定(如果 random.random()产生的值高于玩家命中的 0.5,否则玩家留下)。

通过抛硬币来决定可能听起来很傻,但通过使击中/停留决定与游戏中实际发生的事情无关,我们可以观察所有类型的情况,并最终生成丰富的数据集进行分析。

在这个例子中,我并不试图找出最佳策略。相反,我想使用这个模拟器来生成训练数据,用这些数据我最终可以训练一个神经网络来最佳地玩 21 点(在未来的帖子中)。

对于 Python 来说,\字符表示行继续符,可以用来格式化超长的代码行,以获得更好的可读性——在下面的代码块中,你会看到我使用它。

 else:for player in range(players):# Players check for 21if set(player_hands[player]) == blackjack:curr_player_results[0,player] = 1else:# Hit randomly, check for bustswhile (random.random() >= 0.5) and \(total_up(player_hands[player]) <= 11):player_hands[player].append](dealer_cards.pop(0))if total_up(player_hands[player]) > 21:curr_player_results[0,player] = -1break

在我们循环的最后一段(快到了!),轮到庄家了。庄家必须打到他或她破产,或者有一手至少等于 17 的牌。因此,while 循环向庄家发牌,直到达到 17,然后我们检查我们的庄家是否破产。如果庄家破产,那么每个还没有输(通过破产)的玩家都会赢,我们会在 curr_player_results 中为他们记录 1。

 # Dealer hits based on the ruleswhile total_up(dealer_hand) < 17:dealer_hand.append(dealer_cards.pop(0))# Compare dealer hand to players hand # but first check if dealer bustedif total_up(dealer_hand) > 21:for player in range(players):if curr_player_results[0,player] != -1:curr_player_results[0,player] = 1

如果庄家没有破产,那么每个玩家都将自己的手牌与庄家的手牌进行比较,较高的手牌获胜。

 else:for player in range(players):if total_up(player_hands[player]) > \total_up(dealer_hand):if total_up(player_hands[player]) <= 21:curr_player_results[0,player] = 1elif total_up(player_hands[player]) == \total_up(dealer_hand):curr_player_results[0,player] = 0else:curr_player_results[0,player] = -1

最后,在每场 21 点游戏结束时,我们将游戏结果以及我们关心的其他变量添加到列表中,我们将使用这些列表来跟踪我们的整体模拟结果:

 # Track featuresdealer_card_feature.append(dealer_hand[0])player_card_feature.append(player_hands)player_results.append(list(curr_player_results[0]))

模拟结果

很好,我们现在可以检查一些结果了。我运行了 50,000 副牌的模拟器。由于使用了这么多副牌,最终出现了:

  • 玩了312,459 二十一点游戏。
  • 玩家在游戏的199403(当时的 64% )输了
  • 玩家在游戏 99,324 (当时 32% )中赢得
  • 玩家在游戏的13732(时间的 4% )中与打成平手。

我们可以看看赢/平概率(不把钱输给赌场的概率)是如何由于关键的可观察因素而变化的。例如,下面是所有可能的庄家牌的赢/平概率(回想一下,玩家在决定怎么做时只能看到其中一张庄家的牌):

Probability of Win or Tie vs. Dealer’s Shown Card

从 2 到 6,赢/平的概率增加。但是在 6 之后,这种可能性急剧下降。那很有趣。让我们思考一下为什么会出现这种情况:

  • 如果庄家亮出一张低牌,那么在其他条件相同的情况下,他的总牌价更低,这对玩家来说更容易被击败。这部分解释了为什么从 2 到 6 的概率平均高于从 7 到 ace 的概率。
  • 此外,记住庄家的规则——如果他的总数少于 17,他必须击中。如果他必须出手,他很有可能会破产。这解释了为什么概率从 2 增加到 6。这么想吧— 最常见的卡值是多少?它是 10,因为每副 52 张牌中有 16 张(4 张 10 张牌,j、q 和 k)。因此,如果庄家显示的是 6,(假设我们没有算牌),我们庄家最有可能的初步总数是 16。因为 16 小于 17,所以他必须击中。还有很多牌可能会让他破产——任何值 6 或以上的牌。同样的逻辑也适用于庄家出 5 的情况,只是少了一张会让他破产的牌(现在必须是 7 或更多)。
  • 现在让我们想一想,当庄家出 7 时会发生什么。在这种情况下,另一张隐藏的牌值 10。那么拥有 16 分或更少的玩家将会觉得必须去击球。如果他们不这样做,失败的概率是实质性的。但是如果他们真的击中了,那么他们很有可能会失败(由于所有的 10 分)。

简而言之,这就是赌场对 21 点玩家的优势——通过在玩家行动时隐藏庄家的一张牌(并迫使玩家在庄家之前行动),赌场迫使 21 点玩家做最坏的打算,并让自己面临被捕的风险(这很重要)。

因此,如果你在赌场,你拿到的牌总数在 12 到 16 之间,祝你好运,因为你已经成为赌场的标志,现在你的胜算很大。让我们来看看玩家的初始手牌值(他或她的初始两张牌的值)如何影响他或她的赢/平概率:

Probability of Win or Tie vs. Player’s Hand Value (21 not shown because the probability is 100%)

正如所料,初始玩家手牌值在 12 到 16 之间时,赢/平的概率最低。这些玩家经常被迫陷入“如果我打了我就破产,如果我留下我就输了”的双输局面。这也解释了为什么初始玩家手牌值为 4 和 5 的概率次低。假设你有一张 5,那么你需要打(没有理由不打)——但是如果你真的打了,那么最有可能的结果是你的手牌总数现在是 15。现在,你已经陷入了和那些初始手牌总数在 12 到 16 之间的玩家一样的困境(如果你击中了,你的下一张牌可能会让你破产)。

我未来帖子的预览

现在我们已经探索了 21 点的风险,接下来是什么?在即将发布的帖子中,我将使用上面生成的训练数据来训练神经网络玩 21 点。这样我就可以检查机器选择什么作为最优策略。

但是今天,让我们看看是否可以用一个简单的启发式方法来提高我们的胜算。回忆两件事:

  • 玩家面临的一个主要不利因素是他们被迫先行动(并面临在庄家之前被击败的风险)。因此,赌场的策略是迫使玩家在不确定的情况下行动,希望他们会一掷千金。
  • 在我们的模拟器中,玩家根据掷硬币来选择击中或停留,而不考虑他或她的手牌的价值(除非他或她 21 岁)。所以即使他或她 20 岁,仍然有 50%的机会击中。

因此,让我们看看,我们是否可以仅仅通过选择在我们知道没有失败机会的情况下才出手来提高我们的胜算。因此,我们的新决策规则不是抛硬币,而是只有当我们的总牌价等于或小于 11 时才继续击球。

这不是我所知道的最优策略,但很简单。因为它阻止了我们的破产,我们有效地将破产的风险从我们自己转移到了庄家/赌场。

下图比较了我们的新“智能”策略(蓝色)和我们的原始策略(红色的抛硬币策略):

Smart vs. Coin Flip Probability of Win or Tie (bucketed by Dealer’s Card)

哇,永不冒险的简单决定增加了我们全面获胜的几率。而旧的趋势还在,无论庄家亮出什么牌,我们不亏损的概率都增加了。

让我们来看看,当我们按初始手牌值下注时,我们新策略的赢/平概率是怎样的:

Smart vs. Coin Flip Probability of Win or Tie (bucketed by Player’s Initial Hand Value)

看这个情节就更清楚是怎么回事了。除了 12 到 16 之外,我们提高了所有初始牌价的胜算。这些手牌值相对不受影响,因为通过选择留下(为了消除破产的风险),我们使庄家更容易击败我们的手牌(因为庄家只有在手牌值达到 17 或更高时才能停止打击)。

但对于所有其他牌价,我们避免崩盘的策略似乎很有帮助。

我希望你喜欢阅读,并继续关注下一篇文章,我们将看到神经网络是否能够击败我们的天真策略。干杯并记住——永远不要赌你输不起的东西!

我最近的一些帖子,希望你看看:

你的公司真的是数据驱动的吗?

数据科学家面临自动化的风险吗

数据科学家挣多少钱?

数据科学家赚多少钱第二部

软件工程师挣多少钱?

技能提升的更好方法

让我们在新加坡地图上标出 Airbnb 的位置和价格

原文:https://towardsdatascience.com/lets-plot-airbnb-prices-on-a-map-of-singapore-ddbcae44fb69?source=collection_archive---------25-----------------------

使用 Matplotlib 以编程方式用 python 标注地图

在地图上绘制数据比你想象的要容易。

让我们通过在新加坡地图上绘制 Airbnb 房屋位置(用颜色和价格区分)来了解一下。为什么?嗯,我喜欢新加坡,但是我每次去都会花一大笔钱在航空旅馆上。

从 Kaggle 下载数据集,然后将其保存到与 jupyter 笔记本相同的目录中。你需要登录 Kaggle 来下载它。

数据集:https://www.kaggle.com/jojoker/singapore-airbnb

该文件是一个 CSV,我们可以很容易地预览熊猫。

import pandas as pd# you may have named it something different
df = pd.read_csv('data-sg-listings.csv')# take a look
df.head()

现在,让我们放弃所有价格超过 500 英镑的房屋,因为离群值会打乱我们的颜色编码。

df = df[df['price'] < 500]

完美。

困难的部分来了。得到新加坡的地图图像,我们最终将在上面绘图。我是这么做的。

我去了 http://www.copypastemap.com 的,输入了将形成一个包围新加坡的边界框的角点的纬度和经度(1.15N,103.5E & 1.50N,104E)。然后我拍了一个截图,用相同的点来表示我的 x 轴和 y 轴的最小值/最大值。

但是省点麻烦,把我的截图截图在下面就行了。然后保存在同一个目录下。

唷。现在是简单的部分。在地图上标出我们的位置。又名。以地图图像为背景,在散点图上绘制我们的点。

import matplotlib.pyplot as plt# import our image 
singapore_img = mpimg.imread('singapore-map-3.png')# plot the data
ax = df.plot(kind="scatter", x="longitude", y="latitude", figsize=(20,14),c="price", cmap=plt.get_cmap("jet"),colorbar=True, alpha=0.4,
)# use our map with it's bounding coordinates
plt.imshow(singapore_img, extent=[103.5,104,1.15, 1.50], alpha=0.5) # add axis labels
plt.ylabel("Latitude", fontsize=20)
plt.xlabel("Longitude", fontsize=20)# set the min/max axis values - these must be the same as above
plt.ylim(1.15, 1.50)
plt.xlim(103.5, 104)plt.legend(fontsize=20)
plt.show()

看看这个。

对我来说,最困难的实际上是获得一张包含我想要绘制的所有纬度/经度点的图像。多亏了 pandas 和 matplotlib,绘制这些点非常容易。

让我们在画面中弹出这些过滤器!

原文:https://towardsdatascience.com/lets-pop-those-filters-in-tableau-86d1e27a9a37?source=collection_archive---------14-----------------------

加快数据可视化

它是数据化的!— Tableau 剧本

Photo by Nicolas Picard on Unsplash

现在,我们又回到了学习有趣的数据可视化概念的旅程中,使用 Tableau、dash-boarding 最佳实践和一些方便的提示/技巧。

在此记录中,我们将经历以下活动:

  1. 使用细节层次(LOD)表达式来识别是否已经选择了某些过滤器。
  2. 使用计算字段隐藏/显示消息并突出显示哪些过滤器处于活动状态。
  3. 使用 Tableau 中的浮动容器来隐藏过滤器,并使它们在满足某些要求时弹出。

这些概念可以在您的 Tableau 旅程中的各种用例中使用。我将参考我创建并发布在我的 Tableau 公共配置文件中的示例仪表板,供您参考。

It’s Datafied! - Tableau Playbook

使用的数据集:样本超市

让我们从如何使用细节层次(LOD)表达式来识别某些过滤器是否被选中开始。

步骤 1:使用 LOD 表达式检查是否选择了地区、州、城市进行过滤

Hierarchical flow to be implemented

由于过滤器必须在我创建的参考仪表板中分层显示,让我们考虑我们必须检查的第一个条件,即是否选择了区域过滤器。将显示一条消息,要求首先选择区域,以便为状态应用过滤器。

一旦区域被选中,即弹出状态过滤器,状态过滤器将被显示。同样,当选择一个州时,会显示城市过滤器。

为了检查第一个条件是否选择了区域过滤器,我们将使用以下公式创建一个计算字段“未选择区域”

计算字段名称:“未选择 c#区域”

注意:如果您向自定义计算字段名称或 Tableau 中的参数名称添加类似 c#或 p#的前缀,以保持它们有组织并与您的其他维度/度量不同,这被认为是一个好的做法。

公式:

SUM([记录数])= SUM({ SUM([记录数])})

公式分解:

SUM([记录数]) 表示当前视图中记录数的总和,即应用区域过滤器时,该计数会相应变化。

SUM({ SUM([记录数])}) 代表固定 LOD,即它将计算数据集中的记录数,而不参考视图中的维度。这也被称为表作用域 LOD 。由于 tableau 不能在同一个表达式中混合聚合函数和非聚合函数,我们必须将其与 SUM([记录数])进行比较,即当前视图中记录数的总和。

除非选择了区域筛选器,并且在当前视图中筛选了记录数,否则这种比较是正确的。

接下来,只有选择了州过滤器,才会显示城市过滤器。因此,为了检查这种情况,我们创建了以下计算字段:

计算字段名称:“未选择 c#州”

公式:

SUM({固定[区域]:COUNTD([状态])})= COUNTD([状态])

公式分解:

SUM({固定[区域]:COUNTD([状态])})

在这里,我们对每个区域的不同状态进行计数,并使用固定的 LOD 对其进行汇总。因为不同的计数是跨每个区域计算的,所以它将不受除了区域之外的过滤器/维度的影响,因为它是固定的 LOD。

COUNTD([State]) 表示当前视图中不同状态的计数,即一旦应用了区域/州过滤器,该计数会相应改变。

同样,我们也将为 City 创建一个计算字段。

计算字段名称:“未选择 c#城市”

公式:

SUM({固定[州]:COUNTD([城市])})= COUNTD([城市])

步骤 2:使用计算字段根据适当的筛选器选择/取消选择来显示/隐藏消息

如您所见,我们有两个平铺窗口,上面显示一条消息,说明一旦选择了层次结构中较高的过滤器,就会显示相应的过滤器。让我们了解它们是如何工作的。

计算字段名称:“c#区域未选择文本”

公式:

如果[未选择区域],则“选择区域以查看状态过滤器”结束

公式分解:

如果没有选择区域,即如果我们在上述步骤中创建的'区域未选择' LOD 表达式为,则显示消息。因为我们没有 else 条件,所以在这种情况下不会显示任何消息。

以同样的方式,我们创建另一个计算字段,这一次是用于城市筛选器。

计算字段名称:' c#状态未选择文本'

公式:

如果[未选择州],则“选择州以查看城市过滤器”结束

步骤 3:创建工作表

所以现在我们到了第三步!太棒了。让我们继续前进,事情会越来越清楚。我们将使用在之前步骤中创建的字段,并创建 3 个工作表:

  1. 隐藏状态过滤器!
  2. 隐藏城市过滤器!
  3. 过滤警报!

隐藏状态过滤器!

所以现在我们将计算字段 ' c#区域未选择的文本 ' 添加到文本卡中,并进行适当的格式化。接下来,我们将 LOD 表达式'c # Region Not Selected'添加到 rows 工具架和 filters 工具架上。隐藏标题,如下所示:

我还在工作表中添加了区域过滤器,向您展示它是如何工作的。

确保在从过滤器中选择一个区域后,勾选“c # Region Not Selected”的编辑过滤器选项中的 True 值,并取消勾选 False 选项。

现在,如果我选择一个特定的区域,如下图所示:

  1. 我们视图中的记录数只针对中心区域进行了筛选,因此([记录数])SUM({ SUM([记录数])}) 因此我们的计算字段‘c #区域未选择’返回一个False值。**
  2. 这个值使文本消失,因为在‘c #区域未选择文本’计算字段中不满足我们的条件。
  3. 由于‘c #区域未被选择’被用于行货架,由于轴为*并被过滤,视觉的整个空间也被消除。这是重要的一步,你将在下一节中了解这一步有多重要。*

隐藏那个城市滤镜!

同样的,你可以创建'隐藏那个城市过滤器!'工作表如下所示:

过滤预警!

我希望现在您已经非常清楚 LOD,因此我们将继续使用它们来创建一个计算字段,该字段将显示一个警报,提示控制面板上哪些筛选器当前处于活动状态!是啊,那真的很酷,对吧?

计算字段名称:“应用了 c#筛选器的警报”

公式:

如果不是[未选择 c#地区]和[未选择 c#州]以及[未选择城市]

然后“使用中的过滤器:区域”

else if NOT[未选择 c#区域]和 NOT[未选择 c#州]和[未选择城市]

然后“使用中的过滤器:地区、州”

else if NOT[未选择 c#区域]和 NOT[未选择 c#州]和 NOT[未选择城市]

然后“正在使用的过滤器:地区、州、城市”

否则""

结束

创建一个新工作表,并将该字段添加到文本卡中。

该公式是不言自明的,我将把它留给您来试验,并理解在选择过滤器时计算字段如何返回 True /False。

步骤 4:使用浮动容器在仪表板中添加元素,使过滤器弹出!

唷!做完那些计算和工作表!现在我们开始仪表板开发。

因为在这种方法中我们必须重叠容器,所以我们将使用浮动容器。让我们直接进入流程吧!

Layout for our dashboard

我们将把我们创建的带有文本消息的工作表放在浮动容器中该字段的实际过滤器之上。然后,过滤器将隐藏在另一个浮动可视化后面。

一旦选择了层次结构中较高的过滤器,文本消息就会消失,从而显示出在容器中弹出的过滤器!

在本次演示中,我将使用两个图表 堆叠图例过滤器、双轴密度标志图。

你可以在 我之前的博文 中了解到他们,链接也在本文末尾分享了。

我已经将本次演示所需的所有浮动元素添加到仪表板上:

您可以通过对象部分将浮动垂直容器添加到空白仪表板:

状态筛选器是使用应用它的 visual 添加的:

现在,我们将通过按住 shift 键将带有文本消息和状态过滤器的工作表添加到浮动容器中。

确保未选中容器的“平均分配内容”选项。

提示:您可以通过双击宽灰色条来选择和移动容器,选择后该条显示在仪表板元素的顶部。

使用项目层次结构,我们可以将地图可视化拖动到项目层次结构的顶部,然后适当地放置它以隐藏它后面的状态过滤器:

现在,当我们通过启用过滤器动作将过滤器栈用作过滤器时,

瞧啊。状态过滤器从地图后面弹出!

我们已经介绍了一些有趣的新概念,这些概念在您的# DataRockstar Tableau 之旅中可能会非常有用。太棒了,对吧?!

注意:从我的 tableau 公共配置文件下载 Tableau 工作簿后,请务必检查仪表板操作,当取消选择该地区时,我使用了过滤器操作来重置州和城市过滤器,以避免任何歧义。那是让你作为一个活动进一步探索的!

总结

  1. 开发的组件——识别使用 LOD 表达式和计算字段选择的过滤器,显示活动过滤器的文本消息,组合浮动容器中的元素。
  2. 整合了最佳实践-遵循组织计算字段和参数的命名方案。
  3. 分享的提示和技巧——如何使用浮动容器隐藏元素,并根据层次结构中的过滤器选择显示它们。

请随意从我的 Tableau 个人资料中下载工作簿,并试用它以获得更好的理解。敬请期待进一步的帖子和快乐的餐桌!

*[## Tableau 公共

随意分享和玩耍

public.tableau.com](https://public.tableau.com/profile/pavneet.singh#!/vizhome/ProfitSalesAnalysisacrossCitiesinUSA/ProfitSalesAnalysisDashboard)* * [## 堆叠图例过滤器、双轴密度标记图和双轴散点图

它是数据化的!— Tableau 剧本系列

towardsdatascience.com](/stacked-legend-filter-dual-axis-density-marks-map-dual-axis-scatter-plot-in-tableau-3d2e35f0f62b)* *[## 概述:详细等级表达式-表格

本文解释了细节层次表达式是如何计算的,以及它们在 Tableau 中的作用。更多信息…

help.tableau.com](https://help.tableau.com/current/pro/desktop/en-us/calculations_calculatedfields_lod_overview.htm)* * [## 操作和仪表板

当源或目标是仪表板时,操作通常具有独特的行为。因为仪表板可以包含…

help.tableau.com](https://help.tableau.com/current/pro/desktop/en-us/actions_dashboards.htm) [## 调整仪表板的大小和布局

创建仪表板后,您可能需要调整其大小并重新组织,以便更好地为用户服务。固定大小…

help.tableau.com](https://help.tableau.com/current/pro/desktop/en-us/dashboards_organize_floatingandtiled.htm)*

让我们对机器学习模型进行欠适应和过适应

原文:https://towardsdatascience.com/lets-underfit-and-overfit-a-machine-learning-model-26e1aebca233?source=collection_archive---------23-----------------------

构建过度和不足的模型

一位同事最近开始使用术语“欠拟合”来指代命名实体识别(NER)模型,该模型遗漏了它应该标记的实体。

我必须澄清事实。这实际上并不是不合身,但我可以理解有人会有这种印象。

那么什么是适配不足,或者适配过度呢?

让我们训练一些低估和高估数据的模型!

我们先用 sklearn 的“make_classification”函数生成一个数据集。每个数据点将有 2 个特征(所以很容易绘制)和一个标签。

from sklearn.datasets import make_classification# We didn't need to display all params but I like to see defaults
# I've edited some of these
X,y = make_classification(n_samples=30, n_features=2, n_informative=2,n_redundant=0,n_repeated=0, n_classes=2, n_clusters_per_class=2, weights=None, flip_y=0.01, class_sep=1.0, hypercube=True, shift=0.0, scale=1.0, shuffle=True, random_state=None
)# Split examples by class (positive/negative) to give diff colors
pos_feat0 = []
pos_feat1 = []
neg_feat0 = []
neg_feat1 = []for idx,klass in enumerate(y):if klass == 1:pos_feat0.append(X[idx][0])pos_feat1.append(X[idx][1])else:neg_feat0.append(X[idx][0])neg_feat1.append(X[idx][1])# And plot them
import matplotlib.pyplot as plt
plt.scatter(pos_feat0,pos_feat1, c='blue')
plt.scatter(neg_feat0,neg_feat1, c='red')

嘣。我们有数据。

现在,我们将浏览欠拟合和过拟合的定义,然后有意识地选择将欠拟合和过拟合数据的算法。

欠拟合

根据[维基百科](http://Underfitting occurs when a statistical model cannot adequately capture the underlying structure of the data.)。

当统计模型无法充分捕捉数据的底层结构时,就会出现欠拟合。

翻译:模型在数据中找不到可靠的模式。这并不意味着没有模式。只是模特找不到。

from sklearn.linear_model import SGDClassifiermodel = SGDClassifier()
model.fit(X, y)# set min and max values for the x and y axes
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
a = np.arange(x_min, x_max, 0.1)
b = np.arange(y_min, y_max, 0.1)# build a grid of each unique combination of x and y
xx, yy = np.meshgrid(a, b)# make predictions for every combination of x and y on that grid
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)# draw the classification boundary
plt.contourf(xx, yy, Z, alpha=0.4)# adds the points from our training data
plt.scatter(X[:, 0], X[:, 1], c=y, s=20, edgecolor='k')plt.show()

完美。该模型在绘制决策边界方面做得很糟糕。它不能使用特征来确定一个例子的类别。吃不饱!

过度拟合

据维基百科。

产生的分析与一组特定的数据过于接近或精确,因此可能无法拟合额外的数据或可靠地预测未来的观察结果

翻译:模型学习输入的例子,但它不能推广到其他例子。

from sklearn.tree import DecisionTreeClassifier
model = DecisionTreeClassifier(max_depth=4)model.fit(X, y)# set min and max values for the x and y axes
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
a = np.arange(x_min, x_max, 0.1)
b = np.arange(y_min, y_max, 0.1)# build a grid of each unique combination of x and y
xx, yy = np.meshgrid(a, b)# make predictions for every combination of x and y on that grid
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)# draw the classification boundary
plt.contourf(xx, yy, Z, alpha=0.4)# adds the points in our training data
plt.scatter(X[:, 0], X[:, 1], c=y, s=20, edgecolor='k')plt.show()

太美了。又一个可怕的模型。它在应该出现的例子周围画出了界限,但是它发现的模式毫无意义,并且可能无法推断出新的例子。

让我们现在拟合数据,只是为了好玩

from sklearn.linear_model import LinearRegression,LogisticRegression
model = LogisticRegression()model.fit(X, y)# set min and max values for the x and y axes
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
a = np.arange(x_min, x_max, 0.1)
b = np.arange(y_min, y_max, 0.1)# build a grid of each unique combination of x and y
xx, yy = np.meshgrid(a, b)# make predictions for every combination of x and y on that grid
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)# draw the classification boundary
plt.contourf(xx, yy, Z, alpha=0.4)# adds the points in our training data
plt.scatter(X[:, 0], X[:, 1], c=y, s=20, edgecolor='k')plt.title('Underfitting')plt.show()

太好了。不完美。但是比之前的 2 好多了。

这就是了。欠拟合、过拟合和计划拟合。

我们有意选择了一个简单的 2 要素数据集,以便您可以在图表上看到决策边界。

具有数千个特征的真实例子需要一种更数值的方法来测量欠拟合和过拟合。但是我们会留到下一天。

让我们通过建模汽车来理解机器学习中的向量空间模型

原文:https://towardsdatascience.com/lets-understand-the-vector-space-model-in-machine-learning-by-modelling-cars-b60a8df6684f?source=collection_archive---------14-----------------------

带有代码示例

根据维基百科。

向量空间模型术语向量模型是一种代数模型,用于将文本文档(以及一般的任何对象)表示为标识符的向量,例如索引术语。

Translation :我们将数据集中的每个例子表示为一个特征列表。

wikipedia: the document is a vector of features weights

该模型用于表示 n 维空间中的文档。但是“文档”可以指您试图建模的任何对象。

无论你是否明确理解这一点,你已经在你的机器学习项目中使用了它。

什么是维度?

只是我们建模的对象的一个特征。比如说。

房屋可以有维度:房间数量、销售价格、建造日期、纬度和经度。

人物可以有维度:年龄、体重、身高、发色 _ 是蓝色、发色 _ 是其他。

句子对于每个可能的单词/单词可以有一个维度。

汽车可以有维度:最大速度、加速度、时间和价格。

最终,特性/尺寸是您在特性选择过程中决定的。

让我们在 n 维空间中建模汽车

我们的维度将是:
1。max_speed(最大速度单位为公里/小时)
2。加速 _ 时间(达到 100 公里/小时的秒数)
3。价格(美元)

我挑选了 3 辆车并收集了它们的信息(声明:我对车一无所知……)。

2020 款保时捷卡宴
max _ speed:304 kmph
acceleration _ time:4.4s
售价:9.92 万美元

2018 款特斯拉 Model S
max _ speed:250 kmph
acceleration _ time:3.8s
售价:79990 美元

2020 款宝马 i3s
max _ speed:160 kmph
acceleration _ time:7s
售价:6 万美元

那么向量看起来像什么呢?
T43【保时捷= (304,4.4,99200)
特斯拉= ( 250,3.8,79990 )
宝马= (
160,7,60000 )

让我们画出这些。

from matplotlib import pyplot
from mpl_toolkits.mplot3d import Axes3D
from numpy.random import rand
from pylab import figure# features
X = np.array([[304, 4.4, 99200],[250, 3.8, 79990],[160, 7, 60000]
])# labels
y = ['porsche', 'tesla', 'bmw']# setup our chart
fig = figure()
ax = Axes3D(fig)# iterate on the examples and plot them
for i in range(len(X)): ax.scatter(X[i,0],X[i,1],X[i,2],color='b') ax.text(X[i,0],X[i,1],X[i,2],'%s' % (str(y[i])), size=20, zorder=1,color='k')# label our chart
ax.set_xlabel('max_speed')
ax.set_ylabel('acceleration_time')
ax.set_zlabel('price')
pyplot.show()

酷毙了。

要看到汽车相互之间的方位有点困难,但是如果我们更有雄心的话,我们可以使用 matplotlib 的“动画”模块从不同的角度查看图表。

如果有 3 个以上的维度呢?

我选择了 3 个连续的特征,因为它很容易绘制。在现实中,我们可能有成千上万的功能,在我工作的 NLP 中,这是典型的情况。

但是有一些心理技巧可以用来想象 3 个以上的特征。就像想象每个人都有自己的酒吧秤。因此,如果我们有 5 个功能,而不是 3 个…

I like Tesla’s 😃

为什么使用向量空间模型?

它使得计算两个对象之间的相似性或者搜索查询和一个对象之间的相关性变得容易。

从上面看,我们的汽车有多相似?

这种相似性计算将忽略一些关键因素(即每个特征的重要性)。

首先我们将缩放我们的数据,然后计算余弦相似度,这是最流行的相似度算法之一。

from sklearn.metrics.pairwise import cosine_similarity
from sklearn.preprocessing import StandardScaler# scale unit variance
scaler = StandardScaler()
scaler.fit(X)
X_scaled = scaler.transform(X)
X_scaled# calculate cosine_similarity
similarities = cosine_similarity(X_scaled,X_scaled)
print(similarities)#=>
[[ 1\.          0.42538808 -0.9284599 ][ 0.42538808  1\.         -0.73110643][-0.9284599  -0.73110643  1\.        ]]

好吧!我们可以看到保时捷和特斯拉比宝马更相似。

就这样了,伙计们。

这是对向量空间模型及其用途的快速介绍。虽然你几乎会在任何机器学习项目中接触到这一点,但这不是你需要有意识地思考的事情。如果没有别的,这是一个观察世界的有趣的心智模式。

教育水平和贫困线:对美国最大城市的分析(包括交互式仪表盘)

原文:https://towardsdatascience.com/level-of-education-and-the-poverty-line-an-analysis-of-the-largest-us-cities-interactive-309e6c3e9f46?source=collection_archive---------15-----------------------

正如劳工统计局(【BLS】)所概述的,获得高中文凭的人比继续接受高等教育的人挣得少(获得学士学位的人多 66%,如果是硕士或以上学位,则多 102%),因此,受教育程度越高的人生活在贫困线以下的可能性就越小。虽然这一趋势已经确立了一段时间,但不同城市之间的教育水平差异很大。

在这项研究中,我使用了来自 2017 年美国社区调查的数据,查看了至少有 50 万居民的城市,以研究各城市的教育水平和贫困之间的关系。

为了更深入地挖掘和查看更多的可视化效果,转到这里使用我为今天的报告创建的仪表板。

%受过大学教育的人口生活在贫困线以下

密歇根州的底特律在美国大城市中位居前列,成为拥有大学学历的人群中贫困率最高的城市(10.5%)。紧随底特律之后的是亚利桑那州的图森(8.8%)和宾夕法尼亚州的费城(8.3%)。在光谱的另一端是北卡罗来纳州的夏洛特,那里只有 3.3%受过大学教育的人生活在贫困线以下。紧随其后的是加利福尼亚州的圣何塞和得克萨斯州的沃思堡,这两个城市的失业率与夏洛特相差不到 0 . 1%。

学士学位获得者与高中毕业生的比例

接下来,我们将看看受过大学教育(学士学位或更高)的人与高中文凭是他们接受的最高教育形式的人的比例。

图表图例:如何阅读以下报告的右侧

  • 颜色
  • o 红色——高于大城市的平均贫困水平(针对相应的教育水平)。

o 绿色——城市的教育贫困率低于中等贫困水平。

  • 形状

o‘X’—表示该市高中毕业生的贫困率。

o 钻石——城市大学毕业生贫困率(学士学位&以上)。

西雅图以 6.4 的比率领先,这意味着每 1 个拥有高中文凭的人,就有 6.4 个获得学士学位或更高学位的人。紧随西雅图之后的是旧金山(5.0 的比率)和华盛顿特区(3.4)。

在这份报告考虑的 32 个大城市中,只有 7 个城市拥有高中文凭的人比拥有学士学位或更高学位的人多。在底特律,每一个拥有高中文凭的人,只有 0.45 个学士学位获得者。底特律的这一比率远远领先于密尔沃基(0.74)和费城(0.8),这两个城市分别位居第二和第三。

生活在贫困线以下的高中毕业生与大学毕业生贫困率之间的差距

弗雷斯诺高中毕业生的贫困率领先所有主要城市(22.4%,以上;比大城市高中毕业生的贫困率中位数高出 27%),比受过大学教育的贫困率高出 388%(4.6%;比大城市大学毕业生贫困率中位数低 24%)。与其他四个加州城市不同,弗雷斯诺的高中毕业生和大学毕业生的比例接近 1:1。DC 华盛顿州以 382%的差距紧随其后,大学教育贫困率(5.7%)和高中教育贫困率(27.3%)之间的差距。排在第五位的是俄克拉荷马州的俄克拉荷马城;得克萨斯州埃尔帕索;和田纳西州的孟菲斯;这些城市的大学教育贫困率都比一般大城市高,但高中教育贫困率更低。

洛杉矶的教育水平差异最小,高中毕业生的贫困率仅比受过大学教育的贫困率高 131%。亚利桑那州图森(147%);科罗拉多州丹佛市(151%)位居第二和第三。

受过大学教育的人口比例高的城市对贫困水平的影响

在最后一张图片中,我比较了学士学位获得者与高中毕业生的比例(在之前的图片中使用),并将其与各自教育水平的贫困率进行了比较。获得学士学位者的比例越高,生活在贫困线以下的人口比例就越低(包括高中毕业生和大学毕业生)。

这是我今年计划写的关于贫困、收入不平等、住房和中产阶级化的一系列相关文章的第一篇。为了更深入地挖掘并查看更多的可视化效果, 转到这里使用我为今天的报告 创建的仪表板。

使用快速绘图提升数据可视化水平

原文:https://towardsdatascience.com/level-up-your-data-visualizations-with-quick-plot-f18eddb82468?source=collection_archive---------11-----------------------

K-Means plot for Spotify

数据可视化是数据科学家工作流程的重要组成部分。它允许我们直观地理解我们的问题,分析我们的模型,并允许我们为社区提供深刻的有意义的理解。

作为数据科学家,我们总是寻找新的方法来改进我们的数据科学工作流程。

我为什么要在 ggplot 上使用这个?他们有什么不同吗?有什么好处?

Qplot 允许更清晰、更简短和更简洁的语法来声明 ggplot 可视化。这是一把伟大的瑞士军刀,用于绘制快速简单的可视化图形,对于那些以前没有使用过 ggplot 或 R 的人来说,它非常容易阅读。

qplot 是quick plot的简写,是为 ggplot2 设计的一个快捷方式。

让我们看看它是如何工作的!

下面我将展示两种绘制相同可视化的方法。首先使用 ggplot2,然后使用 qplot。

Scatterplot

ggplot2

ggplot(mpg) + geom_point(aes(displ, hwy, color = factor(cyl), shape = factor(cyl)))

qplot

qplot(displ, hwy, data = mpg, colour = factor(cyl), shape = factor(cyl))

通过使用 quick plot,我们可以缩短语法,使其更加清晰简洁。如果您以前用 python 编程过,语法变得非常类似于seaborn库。

让我们再看几个例子!

条形图

Bar Chart using ggplot

ggplot2

ggplot(data = diamonds) + 
geom_bar(aes(color, weight = carat, fill = color, alpha = 0.5)) + scale_y_continuous("carat")

qplot

qplot(color, data = diamonds, geom = "bar", weight = carat, fill = color, alpha = 0.5) + scale_y_continuous("carat")

散点图和折线图

Scatter plot & line chart

首先,我们将从钻石数据集中抽取一个小样本。

dsmall <- diamonds[sample(nrow(diamonds), 100),]

ggplot

ggplot(dsmall, aes(carat, price)) + geom_point() + geom_smooth()

qplot

qplot(carat, price, data = dsmall, geom = c("point", "smooth"))

箱线图

Boxplot

ggplot

ggplot(data = mpg) + geom_boxplot(mapping = aes(x = drv, y = hwy, color = manufacturer))

qplot

qplot(drv, hwy, data = mpg, color = manufacturer, geom = 'boxplot' )

鳍状物

我希望这个故事教会你一些新的东西!ggplot 和 qplot 都可以用来达到同样的效果。但是,如果你曾经想决定是独立的,有一个快速,肮脏和简单的数据可视化探索性数据分析的 qplot 的尝试!

一如既往,我欢迎反馈和建设性的批评。你可以在推特@ chip asaur上找到我。

利用人工智能治愈癌症

原文:https://towardsdatascience.com/leveraging-ai-to-cure-cancer-c56189a9dbba?source=collection_archive---------7-----------------------

癌症是全球死亡的主要原因之一。这并不意外。

预计每两个加拿大人中就有一个会患上癌症,这是一个惊人的数字预计会有 1850 万人被诊断患有这种致命的疾病。更不用说四分之一的 T4 人预计会死于癌症,也就是 925 万人。

最近,人工智能等技术的许多进步正在帮助研究人员彻底改变医疗保健的未来,从识别医学图像中的模式到预测药物的新目标蛋白质!这项技术正显示出改变全世界数百万人生活的巨大能力。

我利用了人工智能的技术,并深入研究了称为生成模型的子部分。在生成模型中,我特别关注变型自动编码器,因为它能够:

a)学习数据的有意义的底层表示

b)从不同类别的数据中理清变异的来源

由于这些因素,我能够构建一个变分自动编码器来识别和提取一个包含 5000 个不同表达基因的数据集内的已知和未知生物信号。

数据集来源于癌症基因组图谱,该图谱描绘了超过 10,000 种肿瘤超过 33 种不同的癌症类型,揭示了不同的基因组特征,例如众多基因的表达水平。

基因表达水平是对样本中所有活性非活性基因的测量。如果基因是活跃的,这意味着它的过程,用它的信息(转录)编码 RNA ,并从编码蛋白质(翻译)的 RNA,被执行。基因表达水平捕获了关于肿瘤状态的大量信息。显然,不是所有的基因都一直表达,所以表达的基因有助于研究人员在治疗特定疾病时识别哪些特定的基因通路。基因表达的过程极其重要,因为基因表达的产物,一种蛋白质,决定了细胞的功能。识别在不同肿瘤中高度表达的基因,并识别其基因表达在患者中的生物影响,对于设计有助于治愈癌症等疾病的特定治疗方法来说极其重要。

我构建的变分自动编码器能够成功地压缩输入数据,并重新生成 5000 个基因及其表达水平的类似数据。它还能够理清数据中生物变异的来源,以及识别导致不同生物模式的特定基因的贡献,这可能导致肿瘤的癌变状态。

这篇文章将由两部分组成。

第 1 部分)部件——在 VAE 的引擎盖下

第 2 部分)解释——提取/识别数据中有意义的生物信号

第一部分

这是什么?

变分自动编码器是一个生成模型。这意味着它可以学习输入数据的底层分布,并基于它的学习生成数据的副本。

注意单词编码器是“可变自动编码器”的一部分这是因为 VAE 的一个功能是将输入数据(5000 个基因)压缩到一个低维(隐藏)空间,称为 潜在空间。 潜在空间中的数据是输入数据的分布,然后由解码器网络对其进行采样,以生成输入数据的类似版本。

VAE 由一个编码器解码器和一个损失函数组成。

Structure of a VAE

编码器是一个神经网络,它获取 5000 个基因的输入数据,并将其编码成仅仅一个 100 个特征

Snip-it of input data consisting of 5000 genes and their gene expression levels (this table goes on for a long time)

Compressing the input data

编码特征是仅代表输入数据的相关特征的概率分布。由于 VAE 是一个生成模型,它的目标是生成与输入数据相似的变量。为了使编码器压缩并以概率术语表示数据,以适合最小化的空间,编码器输出压缩的数据作为两个向量:平均向量标准偏差向量****。

直观地说,均值向量控制范围,即输入数据的编码应该围绕什么进行,而标准差控制“区域”,即编码可以偏离均值多少。

现在解码器网络从平均值和标准变化向量中采样,以获得向量格式的输入,并馈入解码器网络。采样的矢量称为隐藏层。解码器现在能够重建原始输入。

但是,我们如何确保解码器网络的输出与输入编码器网络的原始输入数据相匹配呢?

这就是损失函数发挥作用的地方!损失函数由两部分组成,一个生成损失和一个潜在损失。生成损失帮助解码器生成类似于输入的数据,这有助于它的准确性。它通过获取解码器的数据输出和编码器网络的输入之间的误差差来实现这一点。然后,误差通过两个网络反向传播,更新其权重和参数,以提高解码器网络的精度。潜在损失表明均值和标准差向量中的编码特征与原始输入数据的匹配程度。这在 VAE 中是一个非常重要的功能,因为最终编码的特征是解码器正在采样的,以从中学习并生成与输入类似的数据。

Output generated data from decoder network

第二部分

识别生物信号

我想看看 VAE 中的编码特征是否能够概括和保留基因数据中存在的生物差异,例如患者的性别。

为此,我提取了解码器网络第一层中的权重。解码器网络第一层中的权重对隐藏层进行解码,隐藏层由来自压缩输入数据的采样信息组成。

用于解码隐藏层中特征的权重实际上能够捕捉基因表达数据中重要且一致的生物模式。通过从解码器网络中提取权重,我能够识别出特征 82** 主要由与患者性别相关的基因组成。这意味着编码器网络能够输出 5000 个基因的压缩,这学习了数据集中的模式。**

通过从解码器提取权重,我们现在能够查看哪些基因对编码器网络创建的特定特征编码有贡献。你可以注意到特征 82 中的所有基因都位于性染色体上。****

genes in feature 82

我们可以通过观察阳性高权重基因来预测患者的性别,这些基因包括 x 失活基因,如 XIST 和 TSIX。

VAE 还能够构建两个特征,分别由原发性转移性** 皮肤黑色素瘤(SKCM)肿瘤组成。**

对于这两个特征中的基因,我们提取了权重较大的基因,来专门识别这些基因所执行的 GO (基因本体) terms 。我们提取高权重基因,因为这些基因被认为是表达最多的基因,这意味着它们对肿瘤的状态有更大的影响,因为它们的表达决定了细胞的功能。

Code to extract high weight genes from SKCM features

Output of high weight genes from metastatic tumour

Output of high weight genes for primary tumour

现在可以对来自特征 66** 和特征 53 的高权重基因实施过度表达途径分析,以识别每个特征中的 GO 术语。**

过度表达途径分析是一种用于解释特征中基因列表(也称为基因集)的 GO 术语/功能过程的技术。GO 术语分为 3 类 : 分子功能(描述基因的分子活性)生物过程(描述基因执行的更大的细胞作用,与其他基因协调)和细胞成分(描述基因产物(即蛋白质)在细胞中执行其功能的位置)。

每个基因都可以用多个术语来描述(注释)。过度表现途径分析与随机比较,识别集合中过度表现的 GO 术语(因此得名)。

被过度表示的项被输出为 P 值。P 值越接近零,特征(基因集合)中表示的 GO 项不是随机的并且具有生物学相关性的区别就越大。

根据对特征 66 中的高基因权重的分析,GO 术语在该基因集中过度出现,暗示了与胆固醇、乙醇和脂质代谢相关的功能。

GO terms

识别在特征的最高基因权重中过度表现的 GO 术语,可以指示由一组表达的基因执行的重要过程。

如果从癌性肿瘤中取样一组特定的基因,鉴定哪些基因具有最高的权重(最活跃)并鉴定它们的 GO 术语可以发出潜在的基因表达途径异常的信号,这有助于癌性肿瘤的起因。

例如,如果特征 66(转移性 SKCM 肿瘤)中的高权重基因暗示了与胆固醇相关的 GO 项的强相关性,这可能意味着由决定胆固醇水平变化的基因表达产生了特定的途径/过程功能障碍。这些变化将成为细胞功能中的一个巨大因素,而细胞功能可能导致癌症肿瘤的产生。

使用这种技术,研究人员可以识别特定导致癌性肿瘤产生的表达基因(蛋白质)的靶途径和产物。VAE 能够分离和构建 5000 个基因数据的编码特征,这些特征捕获了数据集中的模式,如患者性别和 SKCM 肿瘤。我们能够通过提取解码器网络中的权重来发现这一点,因为通过训练 VAE 模型,解码器权重学习数据内的模式。

关键要点

1.诸如变分自动编码器之类的生成模型能够在低维空间中有效地压缩数据,同时仍然保持帮助解码器网络重构输入数据的相关特征。

2.解码器网络中的权重能够捕获可以提取的数据中的重要生物模式。

3.使用过度表达分析来识别高基因权重中的 GO 项可以指示生物过程中的功能障碍。

利用区块链激励教育

原文:https://towardsdatascience.com/leveraging-blockchain-to-incentivize-education-5553e705324c?source=collection_archive---------15-----------------------

教育简介:赚钱的教育

Angkor Wat, Siem Reap, Cambodia

这里有一个小小的警钟:你做错了旅游。不相信我?我可以证明。

如果你是一个旅行者,你会知道在旅游景点的郊区看到小孩子卖纪念品是很常见的事情。有时小贩的孩子会变得好斗,即使他们不会说你的语言。它们都很可爱,以至于你很想让步买些东西……但你没有——可能是因为你并不真正需要那些纪念品,也可能是因为你的导游告诉你不要买。

很多人对此感到内疚。我承认我也是。回到 12 月,我去了趟柬埔寨,在那里我们参观了很多很多寺庙,看到很多可爱的小孩在卖小饰品,大部分是在吴哥窟。我不知道你怎么想,但是当我忽视他们的时候,我总是感觉很糟糕,但是那是我们的向导告诉我们要做的。于是我们这样做了,但我一点也不满意(今年的轻描淡写),因为我意识到我处于特权地位,却完全没有做任何事情来解决弥合机会不平等的问题,这真的很难。

当我真正开始思考到底发生了什么时,我意识到:柬埔寨的孩子们在卖纪念品,而不是去上学。比起孩子的长期教育,他们的家庭更看重短期的金钱激励。

贫困的循环就这样开始了,而没有人对此做任何事情。孩子们和父母在赚钱养家,游客可以买纪念品,所以很多人并不认为这是个问题。但事实是,他们无法摆脱贫困,因为他们的日常“工作”是街头小贩。

作为游客,我们会不假思索地走过,但实际上这个世界的运作方式有一个根本性的缺陷。

暹粒旅游业的大规模增长间接导致了入学率的下降,因为向游客销售比上学有更多的短期金钱收益。

我们如何打破这种循环?答案是教育。你可以看到,随着教育水平的提高,受教育率呈指数下降。对于小学来说,这是相当高的,因为他们没有语言/人际技能,一旦他们成熟和发展,他们就会辍学。

Facts and figures on Siem Reap’s school attendance.

区块链技术:你需要知道的

如果你不知道的话,区块链是一个去中心化的点对点网络,在这里数字信息(包括令牌)可以被分发和存储。它可以被认为是一个巨大的数据库,每个人都可以看到所有的活动,没有人可以控制其他人。可能最重要的方面是,他们在系统中没有中央权威,所以不可能有任何腐败,并且所有日志都是完全透明的,将被永久保存。

The face of every person who discovers a thing called ‘blockchain’

揭开系统的神秘面纱:区块和链条

等等…这是怎么回事?让我们打开这个。

这个系统实际上是如何工作的,谁参与,他们如何参与?

基本上,有 3 个主要参与者:挖掘者、节点和用户——没有他们,系统将无法工作。

当用户发送事务时,挖掘者会访问它们。矿工们竞相解决复杂的数学问题(解码哈希函数),以创造一个区块。这些散列函数需要很长时间才能解码,所以矿工们最终只能猜测和检查。这些块包含一系列事务,这些事务由挖掘器放在一起作为对解码散列的奖励

Credits: CBInsights

为什么矿工们想把所有的时间都花在解码哈希函数上?实际上,这是有动机的——除了用户支付的交易费之外,矿工还会因为创建区块而获得以太坊(ETH)的奖励(目前,以太坊大约为 2 ETH,约合 300 美元)。他们也可以创建空的区块,这样他们就可以得到第二个区块,但是拥有一个满的区块更经济。

当事务被添加到块中时,块被添加到链中,因此称为“块链”。节点接收一系列交易,并且更新数字分类帐的状态。瞧!

区块链的优势(或劣势……)

  • 去中心化:正如我们之前所说,这意味着没有系统故障的中心点。网络存在于每一个参与者的电脑上,不能由一个人或一个组织来控制。
  • 不变性:防止对任何帐户进行未经授权和未经授权的更改。你不能编辑过去的交易,或改变事件,所以所有的信息都是可信的,100%真实的。
  • 一致:由于需要所有节点之间的一致同意,防止可能的损坏。您可以随时查看分类帐的状态。
  • 透明性:这是一件既有利又有弊的事情。网络上的每个人都可以访问存储在区块链上的所有交易、记录和任何信息。不一定是侵犯隐私,看你怎么看待。

符合学生需求的系统

在我们的网站上了解更多关于我们项目的信息,链接这里。

区块链和柬埔寨儿童缺乏教育有什么关系?

TL;大卫:我们用加密货币来标记柬埔寨的教育系统,以激励教育。

我们的(加密)货币

柬埔寨:CCO

他们得到的东西(以 CamboCoin (CCO)代币的形式)的价值比他们作为商贩赚的钱更高。这种虚拟货币可以用来购买额外的营养,医疗保健福利和财政援助,以换取合作组织。学生上学越多,授予学生的 CCO 就越多。当交换时,它们就从流通中消失了。

他们获得上学代币,我们还自动化了一个系统来跟踪和记录学生在学校的参与情况——他们的出勤情况通过生物识别进行记录,在特定时间打卡上下班,但确保他们在申请奖励前停留最短时间。

知识硬币:KNO

CCO 是授予出勤学生的,而 KNC 是一种证书,为经济困难的青年提供了更多的机会来接受突破障碍的教育。

教育有两个主要目标:

  1. 让孩子上学:激励措施肯定会鼓励更高的入学率,尤其是当家庭需要非政府组织提供的奖励时。这一制度还能防止政府内部的腐败。
  2. 确保孩子们留在学校:由于小学的入学率为 90%,我们用乘数来激励教育(也就是说,小学生的收获不如中学生多,中学生的收获不如高中生多)

从每天最少 CCOs 到最多:

小学→中学→高中/中学

智能合同的作用

区块链最大的优势之一是它的权力下放。智能合同利用这种技术来有效地促进、验证和执行双方达成的协议。我们的系统由两个智能合约组成,每个智能合约对应一个令牌。

我们的第一份合同是管理 CamboCoin。这些代币是铸造的,分发给上学的学生。当这些代币被家庭认领时,它们会被从我们的总供给中烧掉,以调节它们的流通。

以下是 CCO 智能合约代码的摘录:

Minting various coin values according to the level of education.

另一个重要的方面是处理实际的事务。这需要交易费,以 ETH 支付。你也可以向账户捐款。用户可以申领他们的代币金额作为奖励。

完整的代码可以在这里找到。

这里有一个界面的预览,以及如何从他们的帐户中查看不变的信息。已有数据不可编辑,没有动作的反向功能。

*注意:为了预览,这是一个简化的界面,而不是实际看起来的样子!但它的目的只是让人们了解除了网站之外我们还在做什么。

重新想象未来

我整合和技术固然重要,但是如果你没有目标也没关系。基本上,你要知道你为什么。为创新而创新——她是谁?

个人经历和我的旅行明确地塑造了我的“为什么”。但更重要的是,我想在世界上做好事。做到这一点的最佳方式是通过联合国的可持续发展目标来构建整个理念。因此,我们专注于高质量的教育、经济增长、消除贫困和减少不平等。

显然不止于此。可扩展性是我们项目的一个重要组成部分,我们想评估如何将它扩展到柬埔寨更多的农村地区,甚至更远的地方。

我们项目的最终目标是教育——区块链恰好是促进这一进程的途径。作为一名学生,创造平等的机会对我来说非常重要,对我们团队的其他成员也是如此。教育有能力戏剧性地改变一个孩子的人生轨迹:从街头小贩变成导游。我们的一大重点是通过这个项目打破贫困循环,这个项目有可能影响数百万人的生活。

Siem Reap, Cambodia

这个项目是由马丁·索、威利斯·郭、玛希塔·拉希德、陈可辛和合作完成的。

非常感谢 Blockscale Solutions、Blockchain Learning Group、Adam、Erik、Zagabe 先生、Tarle 先生和 Mur 在整个过程中对我们的指导。

让我知道你的想法!

关注我关于 领英T22中 了解更多。

利用数据分析提高投资回报率

原文:https://towardsdatascience.com/leveraging-data-analytics-to-increase-roi-5df9250b26e7?source=collection_archive---------39-----------------------

普遍存在不愿意信任和依赖基于机器的决策。这是可以理解的;如何确保自动化决策系统考虑了所有应该考虑的因素?员工首先努力学习新技术,然后在取得巨大进步并生产出有前景的模型后,决策者仍然极不愿意冒险采用新方法,不管测试如何揭示其有效性。尽管如此,在当今竞争激烈的工作环境中,与机器保持积极的关系对于增加利润和提高投资回报率(ROI)至关重要。

建立基线

衡量投资回报率包括检查增加的收益与成本相比如何。为了增加 ROI,您需要建立一个基线来比较进展和一个良好的度量(价值标准。)还有,令人震惊的是,你现在的表现可能并不是你想象的那样。清楚地了解你的基线和度量,告诉你你在哪里;结合业务理解,你就知道自己要去哪里了。之后,你们可以就如何到达那里进行头脑风暴。

[## DDI 编辑推荐:5 本让你从新手变成专家的机器学习书籍|数据驱动…

机器学习行业的蓬勃发展重新引起了人们对人工智能的兴趣

www.datadriveninvestor.com](https://www.datadriveninvestor.com/2019/03/03/editors-pick-5-machine-learning-books/)

数据分析通过多种方式提高性能,其中主要有:

  • 提高利润、效率、准确性和满意度
  • 减少成本和延迟
  • 寻找新的更好的机会
  • 消除不合标准的做法

机器学习和数据科学可以帮助企业实现他们的目标——但只有在实际实施的情况下。为了提高数据科学的投资回报率,你必须掌握两种截然不同的技能:技术,以及说服他人信任和使用它的能力。

成为技术专家

学习数据科学方法的用途和优缺点对许多企业领导者来说是一个挑战。经验丰富的数据科学顾问可以帮助那些希望应用数据科学和机器学习最新发展的人确定好的项目及其所需的组件。在 Elder Research ,我们是许多大公司值得信赖的顾问,我们可以执行准备情况评估的第一步。Jeff Deal 和 Gerhard Pilcher 还写了一本书, 挖掘你自己的业务 ,以指导数据挖掘(数据科学)项目的经理。此外,Elder Research 还提供复杂的分析培训(短期和长期)和指导,以便客户的员工能够提高数据科学技能,并最终独立完成所有任务。

无人驾驶汽车的例子

目前,许多炒作都围绕着人工智能(AI)以及最近的突破——在驾驶汽车、玩围棋和扑克、写文章等方面。—令人印象深刻。但很少有人知道,最大的人工智能进步取决于数据科学。AI 通常使用自上而下的基于演绎逻辑的方法,而数据科学是归纳的;它自下而上地想出新的理论(逻辑和方程);也就是说,来自个别标记病例的例子。事实证明,数据科学是近来“人工智能”成就的原因。单独使用人工智能,你通常可以遵循逻辑,但使用数据科学,你可能无法准确地解释模型是如何工作的。在某种程度上,你必须对过程有信心,承认当严格的统计测试显示出样本外数据的良好准确性时,机器知道它在做什么。

自动驾驶汽车的能力正在稳步提高。2018 年 3 月,一则广泛报道的行人死亡事件让自动驾驶汽车的粉丝们暂停了脚步,但这项技术预防的事故很可能会远远超过曾经广泛使用的实际撞车事故。

到目前为止,成功的关键是“深度学习”,这是一种多层神经网络,可以创建令人费解的方程。例如,如果一辆自动驾驶汽车向左转,这是因为一个方程表明,在看到大量由实际驾驶和专家决策组成的训练数据后,这是最佳行动。成千上万个例子训练出来的方程,代替了,或者补充了,或者证实了,AI 的逻辑规则。

深度学习不同于经典的 AI。融合在一起,来自数据科学世界的归纳建模方法和来自人工智能世界的基于逻辑的方法变得非常强大。

方法的合并

在数据科学中,有许多不同的数据建模技术或方法来“连接”数据的点以形成答案。最受欢迎的是:

  • 回归
  • 决策树
  • 神经网络
  • 最近的邻居
  • 朴素贝叶斯

…但是有几十种有趣的算法。那么,哪个最好呢?在我和爱达荷大学的斯蒂芬·李一起做的一个实验中,我们发现在一个包含六个流行挑战问题的测试集上,我们发现神经网络赢得了比赛,但是所有五个被测试的算法在至少两个问题上获得了第一或第二名。因此,每种算法都是有用的,并且可能是最佳的,这取决于您试图解决的业务问题,神经网络值得一试。

但是我们也尝试了使用四种不同的集合技术的挑战,比如平均和投票。这是您使用所有竞争模型得出一致估计的地方。这四种综合方法甚至打败了最好的个人方法!因此,即使你在一种技术上取得了成功,你也应该尝试多种技术来提高性能。

图一。相对性能示例:6 个数据集上的 5 个算法(与爱达荷州斯蒂芬·李,1997; 来源)

图二。所有集成方法提高性能( 来源 )

此外,如果你比较标准偏差,或原始技术的传播,与任何集合技术,你会看到模型集合更可靠,更少的变化。

说服人们部署数据科学模型

长者研究已经进入第 25 个年头,所以我们有很多经验,在过去几十年里也学到了一些东西。在我们的第一个十年,我们有 90%的项目技术成功率,然而只有 65%的模型被实际使用!我们对此并不满意——尽管研究显示只有 33%的数据科学或机器学习项目在全国范围内实施。我们发现临界点是“碳基生命形式”;也就是人类。经理们将无法真正使用他们委托的努力工作,即使它满足了他们的所有要求。发生了什么事?

我们知道这是变化的问题。这项技术通常会导致人们行为方式的重大改变。在压力下,由于害怕鹤立鸡群,许多人回到了旧的做事方式,而不是信任这种模式。我们对此进行了研究,发现了许多改善信任环境的方法——包括技术和人际信任。它得到了回报;在我们的第二个十年,我们的技术成功率上升到 98%,我们的采用成功率飙升到 92%。

首都一中举例

在 90 年代末,当 Capital One 只有 100 名拥有硕士和博士学位的员工分析信用评分时(几年前我最后一次看到他们超过 300 人),他们雇佣了 Elder Research 来看看新的数据挖掘技术是否能增加什么。他们怀疑一个小的多面手公司能为他们的核心专业领域做出什么贡献。我注意到了预期的差异,并打了个赌:如果我们不能改进他们的模型,我们只会收取他们一半的费用——但如果我们做得更好,我们会收取双倍的费用。他们愉快地同意打赌。

使用专家建模和我们并不秘密的集成武器,我们能够提高性能。信用评分的杠杆作用——或利润的增加——如此之高,以至于 Capital One 的投资回报率飙升,他们很乐意支付我们两倍的价格。

这种情况我已经见过很多次了,直到今天,我喜欢给客户提供这样的交易,他们可以选择不预先支付任何费用,而只在交易实施后支付额外利润的一部分。我对技术和我们的专业知识充满信心。(如果您对此感兴趣,请告诉我们!)

说服的艺术

数据科学是一种理性的决策方法,但人类往往比我们愿意承认的更不理性。在他的《思考 、快与慢 一书中,丹尼尔·卡内曼描述了几个令人不安的例子,说明我们的判断是如何频繁地受到任意事物的影响,如饥饿、最近的积极事件或不合理的联想。我们认为,如果客户难以接受我们的结果,这是不合理的,但我们知道这是正常的,这种挑战值得尊重和关注。

稍后我将更多地谈论“软”问题,但我想简要地指出我开发的一个强大的技术工具,它可以揭示结果有多可靠:“目标改组”。目标洗牌量化了你的结果偶然发生的可能性。它解释了“巨大的搜索效应”,在这一效应中,数百万(比如说)可供选择的假设得到了检验;也被称为“黑客入侵”。通过目标洗牌,你可以从数据中提取真正的意义,而不会被巧合所迷惑。

石油和天然气勘探示例

我们已经在许多现实世界的挑战中使用了目标洗牌。一个令人难忘的例子向一家国际石油和天然气生产公司展示了它如何每年节省数百万美元。我们建立了预测分析模型,以确定某个地区的哪些气井面临停产风险(例如,由于地上管线冻结或地下管线堵塞)。他们希望提前 4-6 个月了解这一点,以便他们能够优先考虑预防性维护,并最好地利用他们宝贵的员工和维护资源。通过大量的辛勤工作和专业知识,我的同事们成功地预测了维护需求,比他们的基线方法好了 3 倍。因此,在不增加员工或机器支出的情况下,他们只需根据我们的模型安排员工路线,就可以回收数千万美元的天然气。目标洗牌显示这个结果是如此的可靠和重要,以至于只有 1/2500 的几率是由于运气。此外,如果他们能够将决策窗口缩短一两个月,由于准确性的提高,节省的成本将会大幅上升。

现实是,许多行业的公司可以通过从数据中提取有用的信息来获得巨大的收益。这需要信任和一些耐心,但老年人研究可以提供证明的结果,通常只需几个月。我们确定基线和业务指标,收集数据并将其转化为有价值的信息,以帮助您做出更好的决策,从而带来令人难以置信的投资回报并转变您的业务。

需要帮助开始分析吗?Elder Research 的现场半天分析高管战略会议提供了使用分析来改进组织决策的策略,以及如何提高您的分析能力的建议。 了解更多。

有关系的

数据分析真的能带来 1300%的投资回报率吗? 为什么高管层的数据素养很重要 炒作还是现实:机器学习的投资回报率

原载于https://www.elderresearch.com

利用数据造福社会——一个实例

原文:https://towardsdatascience.com/leveraging-data-for-social-good-a-practical-example-adac053bdeaa?source=collection_archive---------25-----------------------

一个五人小组如何利用经验数据为隐藏在印度北部农村角落的一个村庄做好事的故事

Using Data Science to make common lives better

注: 我们团队研究这个项目的支柱的所有术语和理论都归功于印度 Amrita Vishwa Vidyapeetham**的 Live in Labs 团队举办的预备研讨会。

2018 年夏天,我有机会成为一个团队的一员,该团队访问了印度北部一个高度落后的村庄。这次参观是我们学院课程的一部分— 实验室生活项目 ( 点击此处了解更多信息)我们在该项目中的任务如下:

确定村庄中需要立即关注的关键指标,验证我们的发现,并提出有助于改善其状况的解决方案。

Fig 1. Key Indicators of a village

通过这篇博文,我将提供我们在该村工作的要点,并阐明我是如何运用我对数据科学的热爱来做好社会公益的。

我为这个项目写的所有代码都可以在 https://github.com/ry05/Live-in-Labs-Analysis 找到。

村庄-基本信息

关于我们参观的村庄的一些初步信息如下:

  • 村庄的正式名称:新塔里亚尔
  • 地点:印度旁遮普省北部
  • 村里的房屋数量:58
  • 村里人数: 300+居住者
  • 人民的主要职业:非熟练工和季节工

资源地图

资源地图是村庄地理景观的草图,有两个主要目标:

  • 提供一份概述,介绍该村庄为实现自身可持续性而拥有的最重要的资源(例如:木柴)
  • 标出村内的主要地标和位置(例如:一所学校)

Fig 2. Resource Map of Dodeneer (CREDITS : Venkata Ramana)

最初的挑战

我们的主要目标是帮助村民解决他们面临的问题,但我们也意识到,这个问题的确定不会一蹴而就。这主要是由于以下两个原因:

  1. 不可否认的差距
    乡村和城市的生活方式有着巨大的差异。有不同的行话,不同的行为,不同的观点和更多的领域,城市和乡村的想法不能产生相同的频率。作为一个团队,我们需要尊重和理解这一点,如果我们要从人们身上提取任何实质性的东西来帮助他们的话。
  2. 对问题的接待
    如果一群大学生和一位导师来到我家,问我一些我不太好回答的问题,我不用花太多时间就能把他们引向门口。这同样适用于一个村庄。因此,我们必须格外小心,确保我们在村里的学习不会扰乱他们的日常生活,或者我们的问题不会让他们处于紧张的状态。

确定直接关注的领域

为了全面了解这个村庄,我们使用了一套特定的工具和技术。我将在下面对此做一个简短的介绍。

参与者观察法(POM)

顾名思义,该工具用于观察我们的参与者(即村民)并推断村庄的场景,而无需与村民就村庄中的问题进行直接对话。使用 POM 有几个优点:

  • 我们开始与考虑中的参与者建立关系
  • 我们成为了我们试图评估的社区的积极成员
  • 我们对主要痛点有了一个基本的概念,而无需过多干预参与者的日常生活

POM 可以通过使用 Senses 框架AEIOU 框架来执行。

  1. 感官框架
    利用视觉、听觉、嗅觉、触觉、味觉和直觉来感知环境(即我们这里的村庄)
  2. AEIOU 框架
    活动:目标导向的参与者采取的一组行动
    环境:活动发生的区域
    交互:可以是人-人或人-对象
    对象:用户使用的工具
    用户:被观察的人(参与者)

如果你想更多地了解 AEIOU 框架,下面的链接是一个很好的阅读材料。

[## AEIOU 框架

AEIOU 是一个启发,有助于解释观察收集的人种学实践在工业。它的两个主要…

help.ethnohub.com](https://help.ethnohub.com/guide/aeiou-framework)

该团队通过实地观察(在实地日志中记录的笔记)以及与村民、人物角色和场景的一对一随意交谈,收集了 POM 所需的数据和信息。

人物角色和场景

人物角色是基于所进行的研究而创建的虚构人物,以代表将从研究成果中受益的不同类型的用户。使用角色的一些优点是:

  • 帮助获得对最终用户体验的可靠、精确和相对的理解
  • 帮助几种类型的用户进行分类
  • 帮助洞察特定用户类型的关键特征,例如 a)他们的激励目标,b)他们的任务,c)他们的痛点

人物角色有助于确定研究关注的“谁”,而场景有助于确定人物角色作为一系列事件“如何”工作。

Fig 3. Persona vs Scenario (Image Source)

如图 3 所示。人物角色、场景和特定于用户的目标是三个主要组成部分,有助于确定特定个人的目标。一旦我们发现了一个人的目的,我们就能确定他对我们原型的期望。这正是人性化设计的基础。

参与式农村评估

PRA 的使用帮助我们深入了解了该村庄以及普遍存在的几个挑战。把 PRA 想象成这个框架,它执行的任务是将我们从村庄收集的原始数据组织成特定的 PRA 工具每个 PRA 工具执行其自己的特定任务并且揭示村庄的唯一维度

我们投入使用的 PRA 工具有:

  • 资源地图:该村主要资源和地标的基本地图
  • 横断面图:根据资源图和 AEIOU 框架将村庄划分为多个部分的地图
  • 季节/活动:帮助了解村庄的季节性活动和季节变化
  • 流入/流出:进村和出村的货物
  • 收入/支出矩阵:量化村庄的总体财务状况
  • 头脑风暴:与村里最有影响力的领导开会,听取他们的意见
  • 维恩图:用于描绘机构、自助组织、团体和个人对村庄的影响和相互依存关系
  • 问题树:描述村里几个问题的前因后果

Fig 4. The Transect Map

Fig 5. The Problem Tree

《概览》的必要性

在我们的观察方法和 PRA 的帮助下,我们能够确定该村的关键问题与水管理和分配有关(参见图 5。).但是,我们仍然心存疑虑,希望在把它带回家交给 LiLA 团队之前,能真正确定我们的发现。

就在那时,我们决定终于到了在村子里进行官方调查的时候了。我们可以使用这样收集的数据来检查 PRA 的结果是否与村庄的真实情况相符。

注意:我们为什么不首先进行调查呢?如果我们无论如何都要在最后进行调查,为什么我们必须使用所有的 PRA 和相关的方法? 这是一个非常相关的问题,我相信你现在一定会想到这个问题。我分几点来回答一下:

  • 调查是收集数据的好方法,但不是最人性化的方法
  • 与村民建立联系至关重要,粗略的调查无助于实现这一目标
  • 此外,我们的调查只集中在一个主要的重要研究问题上,“来自 Dodeneer 的人们正遭受严重的水资源短缺吗?”。如果我们没有进行 PRA 和观察性分析,我们永远也不能集中在这个主要问题上。
  • 因此,PRA 和其他框架有助于清楚地了解村庄,并帮助我们集中精力解决需要解决的主要问题。这项调查有助于证实我们的发现是否确实是居民想要的。

唤醒我心中的数据科学家!

现在,我们有两个主要的目的需要处理

  • 查一下村里的水分配不均是不是真的
  • 找出缺水的原因

我们有疑问,我们需要答案。那时,我就该戴上“数据科学的帽子”,从我们如何利用数据来帮助我们实现目标的角度来思考问题了。在这种情况下,我们如何利用数据做好社会公益?

我们肯定要进行调查,但是我们定义调查质量的方式将非常重要。我们都知道数据科学没有神奇的能力来读取我们的思想并给我们带来结果。因此,我们需要提供正确的数据来获得正确的结果。

Fig 6. Garbage In, Garbage Out

因此,为了确保我们将通过调查进行正确的数据收集,我们首先确定了我们将遵循的调查方法。我们花了几个小时思考理想的方法,最终集中在一个将帮助我们实现目标。

该调查

我们为我们的调查创造了自己的方法,构建了调查问卷,用当地语言将它们准备成对话,在纸上记下他们的回答,然后将数据数字化。

主要研究问题 多迪尼尔的人民是否正遭受严重的水资源短缺?

调查是如何进行的? 进行了如下调查:

  • 该调查以面对面访谈的方式进行,并使用预先准备好的问卷作为参考
  • 该小组首先在纸上收集数据,然后将其输入电子表格

Fig 7. Collecting Data through the Survey

问卷调查作为我们调查的一部分,我们向每个家庭询问了以下问题:

  • 房子储水的介质是什么?(水箱或污水坑或桶或罐)
  • 房子每天用水量的粗略估计是多少?
  • 这房子有地下马达(抽水)吗?
  • 家庭用水是来自 Thariyal 供水系统,还是村内的井眼水源,还是两者都有?
  • 如果一个家庭从两个来源获得水,哪一个来源提供的水量更大?
  • 房子里住了多少人?

Fig 8. A portion of the original survey response sheet

采访语言:这些问题是用当地语言(旁遮普语和印地语)问的。
额外帮助:团队还得到一名当地导游的帮助,帮助我们与村民互动

创建调查问卷时需要考虑的主要因素

  • 相关性 —这些问题与我们开展调查的目标相关吗?
  • 结构 —这些问题的结构是否可以被伪装成自然对话?考虑到这一点非常重要,因为正常的对话会比一系列明确的问题更能让人们开诚布公。
  • 长度——我们避免做一份冗长的问卷,这样我们就不会占用一个人太多的时间。
  • 安慰——在一个落后的印度村庄,并不是每个问题都会被以正确的态度对待。因此,我们决定避免询问诸如家庭收入等问题,因为不是每个家庭都愿意给出准确的答案。

最后,在进行调查后,我们获得了数据,并将其存储到 excel 表中,以便我们可以使用它来量化该村的水资源情况。

Fig 9. First 5 rows of our “Water Consumption in Dodeneer” data

执行数据分析

我们有数据。现在,是时候分析它了,看看我们是否能找到我们正在寻找的答案。如上所述,通过我们的分析,我们有两个主要目的要实现——

  • 查一下村里的水分配不均是不是真的
  • 找出缺水的原因

我使用 Python 作为数据分析语言,你可以在这里找到相关的 Jupyter 笔记本。

下面的工作流程图提供了分析我们的数据所涉及的步骤的高级描述。

Fig 10. The LiLA Survey Analysis Workflow

加载数据

我们的 excel 表中的数据被转换为。csv 格式(逗号分隔值)并作为熊猫数据帧加载。

Fig 11. Dataset loaded as a Dataframe

我们有 47 行数据,其中每一行对应于来自给定房屋的响应(该房屋使用房屋号特征来识别)。如图 11 所示,有 9 列(或特征)。

然而,我注意到数据中有两个主要问题—

  • “存储选择”中的某些值已被输入为“罐+桶”。这个值表示给定的房子使用罐子和桶来存放物品。但是,那个加号是令人讨厌的!
  • “容量…”特性的值不在同一范围内!当桶或罐是存储媒介时,单元具有桶或罐的计数。但是,当储存容器是一个水箱或一个污水坑时,它们的容积是 100 升.另外,在容量的第三行有一个奇怪的“-”值。

数据清理

为了使我们的数据比原始形式更适合我们的分析,我们执行数据清理。OMAR El gabry的这篇文章为数据清理提供了最好的深入解释。绝对值得一读(还有书签)!

[## 数据清理的终极指南

当数据是垃圾的时候

towardsdatascience.com](/the-ultimate-guide-to-data-cleaning-3969843991d4)

那么,我是如何清理我的数据的呢?

  1. “-”的异常值位于一个单元格中,该单元格指定了一所房屋的存储容量,该房屋对该村庄的水井的使用拥有第一手控制权。而且,如果我们说这所房子比村里的任何一户人家都能获得更多的水,这并不是一个太大胆的猜测。
    所以,我们给这个单元格一个 10000 的值。
  2. “容量…”功能的测量值范围不一致。(两个以及实体计数)。为了解决这个问题,我创建了一个名为“Amount”的新特性,它描述了一栋房子每天获得的总水量。贴完这个,我去掉了“容量……”功能。为了创建“金额”,我使用了调查中记录的以下几点。
  • 当存储=“罐”或“控制井”时,数量=容量
  • 当存储=“可以”时,金额=容量×50
  • 当存储=“桶”时,数量=容量 x 20
  • 当 Storage = "Cans + Buckets "时,容量以元组的形式输入(num_of_cans,num _ of _ buckets)。这里,数量=(罐数 x 50) +(桶数 x 20)

假设:村里使用的易拉罐统一容量为 50 升,而水桶可以装大约 20 升水。大多数村民谈论的是“满满的”桶或罐,因此我们假设所有的存储媒介都装满了它们各自的容量。

特征工程

警惕!特征工程是一个非常重要的主题,是机器学习算法工作的先决条件。我只对这个问题进行了基本的特征工程,因为我真的不需要做太多来回答我的数据问题。毕竟,为什么要拿起斧子去杀一只蚊子呢?

Emre ren beroglu 的这篇文章提供了一个真正技术性的、简单的对特征工程的理解,对深入细节非常有帮助。

[## 面向机器学习的特征工程基本技术

用熊猫例子进行综合数据预处理所需的所有方法。

towardsdatascience.com](/feature-engineering-for-machine-learning-3a5e293a5114)

同样,在这个数据集中,我沿着特征工程的路线做了什么?

还记得我是如何计算“数量”特性来消除“容量……”特性中的不一致吗?这种转换有一个潜在的缺陷。它是不完整的。因为,每栋房子里的人数是可变的。因此,每个家庭每天收到的水量远远不是一个好的衡量标准。如果我们要有效地量化村子里的水资源压力,我们真的需要了解村子里的每个人得到了多少水。

因此,我创建了一个新的功能,“每人每天的用水量”,制作如下:

dataset["Water_per_person_day"] <- dataset["Amount"] / dataset["No.    of people"]# dataset corresponds to exactly what you think it is

假设:为简单起见,我们假设给定家庭中的每个人每天获得的水量完全相同。这也适用于儿童。

现在,我的数据看起来更接近于帮助我识别多迪尼尔的水压力。

形象化

终于,我们到了!讨论数据如何帮助我们满足我们的目的的部分—

  • 查一下村里的水分配不均是不是真的
  • 找出缺水的原因

A)村里常见的储水介质有哪些?

Fig 12. Cans are the most common medium of storage

注: Misc 是控制钻井操作的一家公司

生活在多代尼尔的人们是如何分配水资源的?

Fig 13. A case of the haves and the have-nots

这是一个密度图(威尔·科尔森的这篇文章)描述了村子里每个人每天获得的水量分布。这证明了非常重要的一点,“虽然有许多家庭每人每天获得的水不到 50 升,但也有一些家庭每人每天获得的水超过 150 升!”。这在最纯粹的意义上是不平衡。

但是,跳到这种视觉化似乎是不对的。所以,我又提出了两个问题来帮助澄清这种不平衡—

  • 这种不平衡的严重性是什么?
  • 人们有足够的水用于日常活动和家务吗?

有多少房子符合联合国的用水要求?

根据联合国的数据,每人每天的最低需水量为 50-100 升,以确保基本需求得到满足,并且很少出现健康问题。我将阈值设定为 50 升(取最小值),并绘制了一个条形图,以查看 Dodeneer 有多少房子符合这一要求。

Fig 14. Almost 2/3 of the people in the village do not have their basic water requirements met

没有满足每人基本用水需求的家庭数量几乎是满足这些需求的家庭数量的两倍。

的确,水分失衡在十二尼尔非常普遍和严重!

D)使用地下马达会影响水的可用性吗?

在我们最初的观察中,我们发现 2 区(比 3 区离村口更近)有相当多的房子使用地下马达抽水。第 3 区的人还告诉我们,第 2 区的房屋使用马达是他们得不到水的主要原因。我们注意到了这一点。但是,最令人吃惊的发现是当我们拜访最近的城镇的市政办公室时。官员们通知说,“在那个地区(多迪尼尔和它的邻居)使用地下马达是非法的,会被罚款的!”。

所以,我也试着看看马达对接收的水有没有影响。我用了一个箱线图(关于它的更多信息可以从这篇文章由 Michael Galarnyk 撰写)来探究这个问题。

Fig 15. Outliers causing issues in viewing the graph

哎呀!进展不太顺利。上图看起来如此“无意义”的原因是因为那些额外的、单独的点。这些点不属于数据集中大多数其他点的一般行为。用数据术语来说,我们称这些为离群值。离群值有时会令人非常头疼,因为它们在大多数时候并不代表真实值。试图将它们包含在数据分析中可能会扭曲我们的发现或扭曲我们的图表(如图 15。).

塞尔吉奥·桑托约的这篇文章可能会帮助你了解离群值的本质细节。

[## 离群点检测技术概述

什么是离群值,如何处理?

towardsdatascience.com](/a-brief-overview-of-outlier-detection-techniques-1e0b2c19e561)

那么,在这种情况下,那些异常值是什么呢?

  • 位于 12000 升和 4000 升附近的值是那些具有地下水池作为其存储介质的房屋的存储量。
  • 值 10000 升是我们自己放入数据中的。还记得那栋通向水井的房子吗?

因此,这 3 个值与其他 44 户相距甚远,因此最好将其排除,以获得更真实的结果。所以,我把它们过滤掉,只取水量为 4000 升的那些值。

Fig 16. After removing outliers, the graph makes more sense

如果看起来有点太混乱,让我来揭穿这个方框图。有马达的房子比没有马达的房子获得的水量多得多;这可以通过比较两个框来查看。橙色框(使用电机)的高度明显高于蓝色框(未使用电机)。这可以解释为“使用电机的房屋通常比不使用电机的房屋用水量更大”。

结论

从上面的可视化和分析中,对团队来说显而易见的是,我们对 Dodeneer 的水问题的最初理解是正确的,并且我们能够证实我们的 PRA 的发现。此外,在这个过程中,我们还发现了一些额外的见解!

最终注释

这篇博文试图展示数据科学在促进社会公益和传播农村发展方面的一些非常重要的信息方面的应用。我真的要感谢 Paulina Zheng 这篇精彩的文章,她非常清楚地强调了利用我们的能力对社会产生积极影响的必要性。事实上,这篇文章是我最初写这篇文章的原因。

[## 利用数据科学造福社会

在混乱的代码和无情的技术浪潮中,人们很容易忽略更大的目标…

towardsdatascience.com](/using-data-science-for-social-good-c654a6580484)

我希望我能够清楚地阐明我的目的,如果有任何疑问,你可以随时在推特上联系我。

互联网上有大量的文章将数据带入人们的头脑和口袋。太好了,这很重要。但是,如果我们能试着把数据带进人们的心里呢?

绝对值得一想!!!

感谢您的阅读😃😃

利用代理数据集和快速失效技术优化卷积神经网络开发

原文:https://towardsdatascience.com/leveraging-proxy-datasets-and-fail-fast-techniques-to-optimize-convolutional-neural-network-6b67607738d8?source=collection_archive---------22-----------------------

当开发新的 CNN(卷积神经网络)时,为给定任务确定最佳超参数和架构的一个大的瓶颈就是花费在训练每个个体变量上的时间,以便为该任务确定最佳超参数和架构设置。

虽然理想的过程是运行每一个变化,直到完全收敛(即过拟合即将发生)并比较最终结果,但是计算时间和成本以及人力时间和成本排除了这种可能性。

因此,人们一直在努力寻找测试速度更快且结果与实际或完整数据集的结果关联更好的方法。这篇文章总结了 FastAI 和斯坦福大学的 Schliefer 和 Prokop 最近的论文-“使用小型代理数据集加速超参数搜索”中这些努力的最新结果。

在最近的 FastAI 高级开发课程中,杰瑞米·霍华德创建了两个代理数据集(ImageNette 和 ImageWoof ),其想法是使用这两个较小的数据集,以比在整个 ImageNet 数据集上测试更快的方式测试 CNN 变体。

Howard 的结果表明,与标准流程相比,这种代理流程能够实现更快的迭代和开发,代理的结果可以很好地映射到完整的 ImageNet 结果。从那时起,许多 FastAI 从业者开始利用它作为测试新架构的概念证明(例如,Google efficient net vs FastAI xres net)。值得注意的是,Howard 还警告说,使用 CIFAR 等数据集及其 32x32 图像,通常不会很好地映射到更自然的图像大小。

在最近的一篇论文中,(【https://arxiv.org/abs/1906.04887v1】)Schliefer 和 Prokop 通过测试产生代理数据集的最佳方式进一步发展了这一概念,并得出了一些有趣而有用的发现。他们测试了关于如何生成代理数据集的多种策略——随机采样 10%的完整数据集、10%最难的图像和 10%最容易的图像(通过默认设置运行的损失函数测量简单和困难),以及仅在完整数据集上运行 1 个历元。

具体来说,他们发现:

1 — 从 10%最简单的例子中构建和使用代理数据集是最有启发性的,并且为完整数据集的最终测试提供了最高的相关性! (r2 = .81%)。

具有讽刺意味的是,对 10%最难的例子进行测试,这些例子直观上可能被认为更好,但相关性却低得多(只有 0.36%)。

随机抽样(随机抽取 10%的数据集)和仅 1 个时期的整个数据集测试也表现不佳,仅 1 个时期显示仅 0.20%的相关性。

因此,信息是明确的——使用“简单”的例子建立一个“玩具”或代理数据集是加速你的 CNN 开发过程的最佳策略!

From the paper — a breakdown of proxy correlation results. The winner (easiest 10%) highlighted in purple.

本文还简要探讨了第二种策略,即在全数据集上运行时取消表现不佳的变化,以加快优化搜索。

当然,棘手的方面是收集了多少信息,相对于每种变化运行多远,以确定何时减少损失并投资于更好的设置或架构?

这张图表展示了他们的发现,并提供了一些有用的见解:

From the linked paper — after 2 epochs, 72% correlation!

他们的结果如上所示,并建议对转移评估资源的各种截止点进行一些考虑:

1-2 个时期后,与最终结果的相关性为 72%。

2 —从 5 到 15,相关性稳步增加。在 8 个时期之后,实现了大约 82%的相关性。

3-在 15 个时期,或完整运行的 75%,96%的相关性。

因此,根据您在测试方面所处的阶段,您可以考虑一个我称之为“快速失败”评估的策略,使用:

a-2 个时期(预期时期的 10%)作为广泛传播评估的快速过滤器(72%相关过滤器),然后移至

b —阶段 A 中胜出候选人的 8 个时期(或最终预期时期的 35%)。因此,这是一个 80/20 规则截止值,因为 82%的相关性显示为 8 个时期,最后

c-使用 15 个历元(或相当于 75%的历元)完成,提供 96%的相关滤波器,同时减少 25%的训练时间。

人们可能会采用上面的百分比(即 2 个时期=估计的最终运行长度的 10%,等等)来将其扩展到更大的预期时期。

上面当然有许多警告,因为最终结果是基于 20 个时期的,并且这些结果不一定适用于所有类型的 CNN 任务。然而,这种“快速失败”的策略应该是一个比随机起点更好的方法,当你工作在产生最佳 CNN 架构时,如何更好地明智地使用计算资源。

无论如何,这里的执行摘要非常清楚——该论文的结果有力地表明,使用基于 10%最简单示例的代理数据集是加速您开发最佳 CNN 的最佳策略!

论文链接:【https://arxiv.org/abs/1906.04887v1

使用深度学习利用劳动力分析

原文:https://towardsdatascience.com/leveraging-workforce-analytics-using-deep-learning-b13427f674bf?source=collection_archive---------27-----------------------

如今,几乎每个基于服务的企业都需要劳动力分析。它还被称为劳动力管理、人员分析和其他各种术语,但所有这些用例的最终工作和预期结果都是相同的,即预测日常管理业务所需的劳动力。劳动力分析的主要目标是在不影响工作质量的情况下削减劳动力成本。对每日劳动力需求的预测是基于组织中的几个内部和外部因素,如假期安排、病假和休假、天气条件以及所有其他直接或间接对业务产生影响的因素。我们主要关注基于我们已获得的历史数据的劳动力分析的预测方面,而不涉及预算、个人绩效分析、生产力检查等其他方面。

很简单,我们想知道每天需要多少劳动力才能无障碍地开展日常业务。由于我们正在处理每日数据,我们将考虑每日趋势,也就是说,业务可能在周末达到高峰,而在周中、周二和周三达到低谷。在更高的层面上,趋势也可以在每周数据中看到,劳动力需求可能在假期周飙升,在淡季周下降。月度趋势在这类数据中很少看到,即使看到也可以忽略,除非我们有一个庞大的历史数据库。

时间序列建模

这种数据是基于时间的——我们在数据中看到一些重要的趋势和模式,都与时间有关。数据具有时间依赖性;这意味着未来数据点的出现与过去数据点的出现相关。这种类型的数据不能用常规的机器学习模型来建模,而是需要一组专门的模型来处理这方面的数据。

这篇文章介绍了我在分析中应用的所有预测时间序列模型,以预测劳动力需求。本文不是关于我们可以对劳动力相关数据执行的各种不同的分析任务。仅仅是关于机器学习和深度学习模型,我已经应用来预测一段时间内的单变量数据,特别是针对我的用例和问题。市场上可能有更多的模型可以更好地处理不同类型的时间序列问题。这些是对我来说效果最好的几个。

目标:预测每天完成一项任务所需的工作小时数。(根据所需的总小时数,管理层计划完成任务所需的劳动力。)

数据:每日时间序列数据。感兴趣的变量是“每天工作的总小时数”。在我们的分析中,额外的变量被用作支持变量。

下面是我对这些数据运行的机器学习/深度学习模型的分类。

Predictive models used

使用的模型类别:

  • 经典方法
  • 机器学习模型
  • 深度学习模型
  • 集合模型

数据探索

就像任何其他数据一样,在我们应用任何方法进行预测之前,也需要很好地理解时间序列数据。我们需要进行一些数据探索,以确定潜在的趋势。

我使用带有 python 实现的 statsmodels 库来执行 EDA。Statsmodels 是一个为以下各项提供类和函数的模块:

  • 不同统计模型的估计
  • 进行统计测试
  • 进行统计数据探索

使用 statsmodels,我们可以识别数据中的季节性和周期性趋势。使用 Hodrick-Prescott 滤波器,我们可以分离趋势和周期分量。该滤波器使二次损失函数最小化,以确定各个分量。它使用一个平滑参数(λ),我们可以根据手头的数据进行调整。

将这些组件分别可视化,以检查它们在数据中的分布,并敏锐地观察它们所在的范围。与季节性和趋势成分相比,噪声应该可以忽略不计。

在上面的图表中,我们可以看到有一个略微上升的趋势,并且一定程度上存在季节性。整个数据集中存在噪声(残差)。

有关用于执行 EDA 的方法的详细信息,请参考我在时间序列建模中的描述性统计的文章:[ 链接

经典款

  1. ETS 模型(误差-趋势-季节性)

statsmodels 库中提供误差-趋势-季节性(ETS)模型。这些模型将采用这些项(误差、趋势、季节性)中的每一项进行平滑,即,将它们相加、相乘或省略其中一些。基于这些关键因素,我们可以创建一个最适合我们数据的模型。

ETS 分解是 ETS 模型的一个具体用例。statsmodels 的季节性分解()用于其实现。

在我们决定使用哪种 ETS 模型之前,需要检查数据的趋势成分。

  • 线性与指数
  • 向上与向下

还要检查数据中孤立的季节性成分和残差成分,看数据集结尾的噪声是否比开头的少。但是,主要看趋势组件应该有助于您做出选择模型的决定。

根据上面提到的单个组件,我们决定是选择加法模型还是乘法模型。

加性 ETS 模型:当趋势更加线性,季节性和剩余成分随着时间的推移更加稳定时,我们应用此模型。

乘法 ETS 模型:当趋势为指数时(趋势以非线性速率增加或减少)

在应用 ETS 分解之前,确保有效地处理缺失值,要么估算它们,要么从数据集中删除它们,因为 ETS 分解在它们存在时不起作用。

2。EWMA 模型(指数加权移动平均线)

上图显示了窗口大小为 7 天和 30 天(1 周,1 个月)的简单移动平均线。7 天平均线显示了一个详细的趋势,而 30 天平均线显示了一个更一般的趋势。你为你的窗口选择的时间框架给了你相应的趋势。

我们可以使用 SMA(简单移动平均线)来检查数据的总体趋势。在我们的分析中,它可以作为一个通用模型。但是,我们需要更复杂的模型来理解时间序列趋势。为此,我们可以使用 EWMA 模型。

EWMA 是 SMA 模型的扩展概念。SMA 的问题在于,它被限制为在整个数据中使用相同的窗口大小。另一方面,EWMA 允许我们使用不同大小的时间窗口,也就是说,更新的数据可以比旧的数据更重要。考虑到最近的数据在预测未来数据的建模中的重要性,给予其更多的权重。

EWMA 修复了 SMA 的其他问题,比如它减少了 SMA 的滞后效应,因为它将更多的权重放在了最近发生的值上。分配给这些值的权重取决于给定模型的实际参数和给定窗口大小的周期数。“衰减项”用于当我们从较新的值到较旧的值时,指数地减少分配给数据值的权重。

3。霍尔特-温特斯法

我们之前讨论过 EWMA,它是一种简单的指数平滑方法。我们应用了一个单一的平滑因子“阿尔法”。这没有考虑到趋势和季节性等因素。

霍尔特温特斯是一种双指数平滑方法。它包括一个预测方程和三个平滑方程。这里的三个平滑参数分别针对水平、趋势和季节性。(分别为α、β和γ)

同样,霍尔特温特斯模型可以用作加法和乘法模型。当季节变化在整个系列中保持不变时,使用加法模型。然而,当季节变化与系列水平成比例变化时,使用乘法霍尔特温特斯模型。

双指数平滑处理数据中的趋势部分,三指数平滑处理数据中的季节性部分。

4。ARIMA(自回归综合移动平均线)模型

基于 ARIMA 的模型通常是时间序列建模中最受欢迎的模型。这是一个非常广泛的主题,我已经写了一篇关于它的实现的单独文章— [ Link

深度学习模型

深度神经网络具有比传统机器学习模型先进得多的能力。它们具有强大的功能,为时间序列预测问题提供了很多希望,特别是在具有多步预测、多值输入和复杂非线性
依赖的问题上。它们还提供自动特性选择和对序列数据(如时间序列数据)的本地支持。

对具有时间相关性的数据建模,比如我们的时间序列数据,在拟合和评估模型时需要专门的处理。数据中的这种时间结构需要专门的模型来识别趋势和季节性模式。我们早先已经应用了像 ARIMA 这样的机器学习线性模型,因为它们对许多问题非常有效,并且很好理解。但是像这样的线性方法受到一些限制,例如:

-通常不支持缺失数据。
-线性方法假设数据中存在线性关系,但不包括更复杂的联合分布。
-大多数线性模型关注单变量数据。(除了少数情况)而大多数现实世界的问题都有多个输入/变量。
-我们需要更先进的模型,能够在很长的时间范围内预测结果。

但是神经网络通常是“黑箱”——很难超出它们的性能指标来解释它们。出于这个原因,每当你遇到与时间序列相关的问题时,首先尝试使用 ARIMA 模型,如果它们没有给你好的结果,那么就把神经网络作为最后的手段。接下来是我在深度学习中使用的所有模型的简要说明。同样,深度学习是一个庞大的主题,我在这篇文章中的尝试仅限于展示模型的基本效用,而不是详细解释这个概念。

5。多层感知器模型(MLP)

多层感知器模型是深度学习中最简单的前馈神经网络模型之一。在我们进入复杂的神经网络之前,让我们先了解一下简单的人工神经元是怎么回事。MLP 采用一组先前时间步长的观测值(滞后观测值)来预测一个或多个未来时间步长。

感知器或人工神经元:人工神经网络与我们身体中的生物神经元有很强的相似性。就像生物神经元如何从身体的各个部分接收输入信号并发出输出信号一样,人工神经网络也有类似的神经元概念,它接收各种输入,这些输入在通过激活函数之前进行加权,从而决定神经元的输出。

感知器将权重和偏差添加到输入中,激活函数决定是否激活该神经元。(要不要发射)常用的激活函数有 sigmoid 函数、双曲正切函数、校正线性单位(ReLu)。

z = wx + b

数学上,感知器可以用上面的等式表示,其中“w”是用偏差“b”加到“x”输入上的权重。

Simplest representation of an artificial neuron

正如你在下面看到的,上面的感知器(或神经元)是多层感知器网络中的单个 most 单元。黄色图层表示输入图层,红色图层表示输出图层,中间的所有蓝色图层表示网络中的隐藏图层。随着层越来越多,抽象层次也越来越高。并且,如果隐藏层是 3 层或更多,那么这样的网络被称为“深度网络”。

Example of a Multilayer Perceptron model [2]

6。递归神经网络

这类神经网络专门设计用于处理像我们的时间序列数据这样的序列数据。它们由循环神经元组成,与正常神经元略有不同。

递归神经元不同于普通神经元,它接收来自前一时间步和当前时间步的输入。下图显示了随时间滚动的递归神经网络。

Un-rolling the recurrent neuron over time [1]

例如,在第三时间步的循环神经元将是在 t,t-1,t-2 的输入的函数。这些神经元是来自先前时间步骤的输入的函数,因此被称为“记忆细胞”。通过这种方式,一个循环神经元在任何给定的时间步形成某种记忆状态,所有的历史数据都提供给它。

谈到输入和输出的格式,rnn 在这方面非常灵活。序列到序列、序列到向量、向量到序列是应用中广泛使用的几种格式。

在实现 RNNs 时,请确保缩放您的数据,因为神经元可能会对最小值和最大值之间存在巨大差异的数据表现不同。此外,将数据分批输入到模型中,因为小批量可以更好地训练。

并且 rnn 可能要求输入数据是某种格式。如果我们要向模型提供一个数据序列,请确保包含带有相应标签的序列,例如,[1,2,3,4]-->[5]。第 5 个时间步长的数据值成为前 4 个时间步长的标签。我们根据数据中的季节性来选择这个特性集。如果是年度季节性,那么输入序列(特征集)将包含 12 个输入(对于月度数据)。

您可以根据需要向网络添加图层。在添加这些层时,必须注意的超参数是:每层中的神经元数量、激活函数、输入形状。这些值中的每一个都可以首先通过反复试验来确定。如果模型不是最优的,那么可以使用网格搜索进行改进。在这方面花费大量的时间,因为确定适当的超参数值对模型性能起着至关重要的作用。

此外,定义损失函数及其优化器。还应该初始化对数据运行模型的时期数。

在所有这些实现之后,在测试/验证数据上测试它,一旦获得最佳性能,就预测数据的未来。

7 .。LSTM(长短期记忆单位)

rnn 会在一段时间后丢失信息,从最初的几个时间步骤开始。赋予相对较新的时间步长的权重会覆盖它们。我们的网络需要一种“长期记忆”。LSTMs 解决了这个问题。它解决了消失梯度的问题,并致力于跟踪序列数据中的长期依赖性。LSTM 是 RNN 的一种。

Un-rolling of an LSTM cell over time [3]

LSTM 的一个单位包含 4 个主要层:

第 1 层- 遗忘门层:由我们将要遗忘或从细胞状态中丢弃的信息组成。在使用特定权重和偏差项执行一些线性变换后,我们将 ht-1 和 Xt 作为输入传递给 sigmoid 函数。

第 2 层-第 1 部分: Sigmoid 层或输入门层:我们再次将两个输入 ht-1 和 Xt 传递到 Sigmoid 函数中,在这两个输入用权重和偏置项进行线性变换之后。这创建了新候选值的向量。

第 2 部分:双曲正切层:在这一层中,相同的输入经历线性变换,但是我们现在不是将它们传递到 sigmoid 函数中,而是将它们传递到双曲正切函数中。它们还创建了新候选值的向量。

第 3 层——在下一层,我们将从两层添加新的候选值,并将它们更新为单元格状态。注意,该单元状态总是具有当前单元状态值 Ct-1。

第 4 层-输出 ht 基于单元状态,但也是单元状态的过滤版本。同样在该层中,两个输入 ht-1 和 Xt 经历线性变换,并被传递到 sigmoid 函数。这又乘以 Ct 的双曲正切,得到输出 ht。

8。门控循环单元(GRU)

这是 LSTM 细胞的一个微小变化。

Structure of a Gated Recurrent Unit

与 LSTM 不同,GRU 使用复位门和更新门。重置门位于前一激活和下一候选激活之间以忘记前一状态,并且更新门决定在更新单元状态时使用多少候选激活。

就将小区状态暴露给网络中的其他单元而言,LSTMs 在一定程度上控制这种暴露,而 gru 将整个小区状态暴露给网络中的其他单元。LSTM 单元具有独立的输入和遗忘门,而 GRU 通过其复位门同时执行这两种操作。

参考文献

[1][3]https://colah.github.io/posts/2015-08-Understanding-LSTMs/

[2]https://www . neural designer . com/blog/perceptron-the-main-component-of-neural-networks

欧盟对人工智能的责任

原文:https://towardsdatascience.com/liability-for-artificial-intelligence-in-eu-d388c0bdff2b?source=collection_archive---------19-----------------------

Illustrations by Undraw

欧盟责任和新技术专家组 2019 年发布的报告摘要

本文是欧盟责任和新技术专家组报告的简要总结。简而言之,它概述了有关新兴技术的潜在法规,虽然以意见的形式陈述,但可能会影响有关未来法律框架的决策。

报告称,人工智能(AI)和物联网(IoT)有可能让我们的社会和经济变得更好。这些技术的操作可能会导致损坏。报告的结论是,“至少基本保护”的责任制度已经到位,但是新技术的具体特点可能会使索赔在所有情况下变得更加困难,而索赔似乎是合理的。

根据执行摘要,该报告最重要的发现如下[粗体斜体为新增]:

  1. 一个人操作一项允许的技术,但却增加了对他人造成伤害的风险,例如公共场所的人工智能机器人,应该为其操作造成的损害承担严格责任
  2. 在确保必要技术框架的服务提供商比配备人工智能的实际产品或服务的所有者或用户拥有更高程度的控制的情况下,在确定谁主要操作技术时应考虑这一点。
  3. 使用不会增加对他人造成伤害风险的技术的人仍应遵守适当选择、操作、监控和维护所用技术的职责,如果做不到这一点,则应为违反此类职责承担责任
  4. 一个人使用一种一定程度的自主 的技术对随之而来的伤害所负的责任 不应少于所述伤害是由人类辅助者造成的。
  5. 采用新兴数字技术的产品或数字内容 的制造商应对其产品中的缺陷造成的损害承担责任,即使该缺陷是在产品投放市场后,在制造商的控制下对产品进行的更改造成的。
  6. 对于将 第三方暴露于伤害风险增加的情形,强制责任保险可以让受害者更好地获得赔偿并保护潜在侵权人免受责任风险。
  7. 如果某项特定技术增加了证明存在超出合理预期的责任要素的难度,受害者应有权获得举证便利
  8. 新兴数字技术应具备记录功能在适当情况下,未能记录或提供对记录数据的合理访问应导致举证责任倒置,以免损害受害者
  9. 对受害者数据的破坏应被视为损害,在特定条件下可获得赔偿。
  10. 没有必要赋予设备或自主系统法律人格,因为这些设备或自主系统可能造成的伤害可以而且应该归咎于现有人员或机构。

报告随后附有主要调查结果。

数字化对责任法的影响会影响新兴技术的复杂性、不透明性、开放性、自主性、可预测性、数据驱动性和脆弱性。其中每一个都可能是渐进的,但综合效应会导致瓦解。有时很难分配损失,谁造成的,谁受益,谁在控制,谁避免了风险。

该报告发现,在涉及人类行为的功能相当的情况下,与受害者相比,数字索赔中的人获得的赔偿更少或没有。

因此,他们表示,重要的是要考虑对现有责任制度进行调整和修正,以确定哪些损失可以赔偿以及赔偿的程度。过错责任应该和产品的严格责任一样继续存在。

没有必要赋予自治系统法律人格。

一项重要声明如下:

“生产者应对新兴数字技术中的缺陷承担严格责任,即使所述缺陷是在产品投入流通之后出现的,只要生产者仍然控制着技术的更新或升级。开发风险抗辩不应适用。”

这意味着,在实践中,你需要确保你应用的人工智能在应用之前是有效的,并且没有开发风险防御适用,这是欧盟需要注意的重要一点。另一项重要声明如下:

如果证明新兴数字技术已经造成损害,如果在建立相关安全级别或证明未达到该安全级别方面存在不成比例的困难或成本,则证明缺陷的责任应该颠倒。

生产者还应该设计和销售产品,使经营者能够遵守,并在产品进入流通后对其进行监测。

如果自治系统造成损害,它应该:“……对应于此类辅助机构的委托人的替代责任制度。”

生产者有义务为技术配备记录技术运作信息的手段(设计记录)。但是,应该考虑测井的负面影响。必须根据适用法律,尤其是数据保护法进行记录。

如果损害是安全规则旨在避免的一种损害,不遵守这种安全规则,包括关于网络安全的规则,应导致举证责任倒置,即(a)因果关系,(b)过失,以及(c)缺陷的存在。

应该继续要求受害者证明造成伤害的原因。

鉴于新兴数字技术的挑战,如果平衡以下因素,证明因果关系的负担可能会减轻:

  • 技术造成伤害的可能性
  • 可能是由同一领域内的其他原因引起的
  • 已知缺陷的风险
  • 可追溯性和可理解性(如信息不对称)
  • 收集和生成的数据的可访问性和可理解性
  • 潜在或实际造成的损害的种类和程度

如果证明一项新兴技术造成了损害,则证明过失的责任应该倒置(如果很难确定注意标准和证明侵权)。情况可能更复杂,涉及多方:

“如果两个或两个以上的人在合同或类似的基础上合作提供一个商业和技术单位的不同要素,如果受害者能够证明至少有一个要素以触发责任的方式造成了损害,而不是哪一个要素,则所有潜在的侵权行为人应对受害者承担连带责任。”

在对数据造成损害的情况下,可能会因合同、产权、刑法和故意伤害而导致责任。随着伤害越来越频繁,强制性责任保险可能是必要的。

赔偿基金可用于保护根据适用的责任规则有权获得赔偿但其索赔无法得到满足的侵权行为受害者。

这些是总结的要点,但是,我建议你通读一遍,如果有机会的话,再深入一些。

人工智能责任 (2019,11 月)。

这里是#500daysofAI,您正在阅读的是第 208 条。500 天来,我每天都在写一篇关于或与人工智能相关的新文章。我目前 100 天 200-300 的重点是人工智能的国家和国际战略。

顺便说一句,以上都不能被视为法律建议,我也不是法律专业人士。

使用 OCR 技术和 CoreData 创建车牌读取 iOS 应用程序

原文:https://towardsdatascience.com/licence-plate-reader-ios-application-using-ocr-technologies-and-coredata-3cdee933c38b?source=collection_archive---------14-----------------------

使用不同库的完整教程—tesseracrios、SwiftOCR 和 Google MLVision |我们能打败 Google 吗?

Photo by Oleg Ivanov on Unsplash

当谈到字符识别技术时,看看我们已经走了多远是很有趣的。阅读和识别脚本文件的清晰图像中的文本变得很容易,但在现实生活中,如果光线不好,图像扭曲,该怎么办呢?

嗯,阅读和识别字符仍然令人惊讶地困难,这是因为视觉,一般来说,在计算方面是复杂和昂贵的。在试图从给定的图像中获取任何有用的信息之前,还有许多参数进入图像的预处理。

当你试图处理来自手机的图像时,由于你无法利用任何 GPU 加速来加速处理过程,这变得更加困难。

让我们深入 iOS 设备的视觉世界,在本教程中,我们将阅读车牌并识别其注册的城市。我们的应用程序将被称为 “你从哪里来?”

Final Result, Github

创建应用程序框架

基本设置

让我们首先创建一个带有单视图应用程序的 iOS 项目,确保选中使用核心数据😗*

Create a new project with core data

创建视图控制器

我们需要四个视图控制器:

  • 视图控制器:

在这里,我们将设置带有所有牌照(在本例中是摩洛哥牌照)和相应城市的 CollectionView。

  • OcrViewController:

在这个控制器中,我们将添加两个按钮:一个用于访问照片库,另一个用于访问相机。

  • WhatCityViewController:

这里我们将显示对应城市的实际图像。

  • MainTabViewController:

这是我们的主导航,我们将在这里为我们的应用程序创建完整的导航。

创建导航

iOS 中的导航非常简单,也很容易实现,我已经改变了一些东西,比如导航条的字体等等。所以看起来确实不错。这里是导航的完整源代码,你仍然可以在 Github 资源库中找到所有这些资料:

MainTabViewController.swift

确保相应地更改AppDelegate.swift,我们将此控制器用作我们的应用入口点:

AppDelegate.swift

设置 CoreData

如果您在创建项目时选择了“使用核心数据”,Xcode 会添加一个.xcdatamodeld文件,我们将使用它来创建我们的模型。

.xcdatamodeld file

您可以创建自己的模型,在这里我选择了一个非常简单的结构,因为我的objectif只是为了获取数据并更专注于 OCR,但您肯定可以根据您所在国家的车牌结构进行更改。

在这里,我将只使用City类作为存储我的车牌数据的主类,id代表后缀数字,name代表城市名。

添加模型

Core Date 将使用与类相关联的 CRUD 方法生成模型。你只需要创建一个NSManagedObject子类并按照步骤操作。这非常简单明了:

Create NSManagedObject Subclass

用数据助手填充模型

我用我的ViewController类的扩展创建了一个文件,这样我就可以用所有的车牌填充Database(如果你是摩洛哥人,你可以使用我创建的那个,否则创建一个并用必要的信息填充它)。

Example of how I instantiated my City class, I did this for 87 cities in the CreateCities.swift file

你只需要运行这个函数一次,否则,你会得到很多重复的结果。

设置上下文

我从 Xcode 最初放置它的AppDelegate.swift中移除了上下文,所以我创建了一个名为PersistenceManager的类。这是我的PersistenceManager类:

Persistence Manager Class

设置 UICollectionView—view controller . swift

创建和设置收藏的布局

首先,实例化一个UICollectionView对象和cellId对象:

Our Collection View

然后设置布局并添加代理:

我们还需要一个CollectionViewCell 我已经创建了一个自定义的,你可以在 Github 库中找到。

填充集合视图

我更喜欢在这里使用扩展名,所以我创建了一个单独的文件:

设置 UIImagePickerView—ocrviewcontroller . swift

从图像库中获取图像

我们需要一个按钮和一些逻辑来触发它:

启动摄像机

我们现在需要设定一些逻辑。更改Info.plist文件并添加一个向用户解释为什么我们需要访问摄像机和库的属性是非常重要的,添加一些文本到Privacy — Camera Usage Description:

设置代理人

现在我们可以从ImagePickerController访问图像:

Image Picker Delegate

测试三个 OCR 库

现在让我们进入有趣的部分,OCR!

说到图像处理,重要的是要找到一个易于处理的图像,更重要的是,要聚焦在主体上。让我们假设图像质量很好,并且已经裁剪到我们感兴趣的区域。

由于我们正在制作一个 iOS 应用程序,使用我的老朋友OpenCV 是没有意义的,因为它并不意味着要在 ARM 架构中使用,也不会被优化来处理复杂的卷积和转换系列(我确信,如果我们能够利用 OpenCV,结果会好得多)。

以下是我用来比较这三个库的图片:

Three images of Moroccan License Plates. Disclaimer: I found these images on google image engine and only used for testing purposes, I don’t know if they are real or not.

特瑟莱克里奥斯

这个库很有趣,因为它使用了遗留库 Tesseract,这是用 C++编写的,并包装成在 Swift 中工作。我相信这会给我一个不错的结果,但是我错了!

让我们开始吧,首先你需要设置你的pod文件,让你的工作空间启动并运行,我假设你知道如何使用 pods(YouTube 上有很多教程可以帮助你学习cocoapods)。

如果你想看的话,有一个 GitHub 库:tesseracrios

我创建了一个带有完成块的函数,它返回一个字符串:

Tesseract OCR for iOS

让我说清楚,这是三个中最差一个。我尝试了几乎所有的方法,甚至拍摄图像并在我的电脑上执行一些卷积来改善图像,但什么都没有!就是不好。

这个库只有在图片是纯黑色文本,字体非常简单,背景为白色的情况下才会运行良好。我还想指出的是,众所周知,Tesseract 不适合包含大量文本的图像。

SwiftOCR

SwiftOCR 是一个用 Swift 编写的快速简单的 OCR 库。它使用神经网络进行图像识别。截至目前,SwiftOCR 已针对识别短的一行长度的字母数字代码(例如 DI4C9CM)进行了优化。 来源:Github

这很有趣,因为这是一种不同于 Tesseract 的方法,在 tessera CT 中,你基本上利用分类和训练过的数据来进行识别。

SwiftOCR 使用神经网络,所以它应该更好,让我们试试吧!

因此,我创建了一个带有完成块的函数,它返回一个字符串:

没有比这更简单的了,只有四行代码。

我可以 100%确定它比宇宙魔方好得多,尤其是在一小块文本上。我会说它给了我 20%的字符,但并不一致,每次迭代之间有一个巨大的梯度。我不确定是我做错了还是只是不稳定。

因此,总结来说,对于这个用例,SwiftOCR 比 Tesseract 更好,但是它离预期的结果还差得很远。至此,我彻底郁闷了(开玩笑)。结果与我处理它并与我的数据库进行比较所需要的相差甚远。

SwiftOCR 更好,但仍然不够好!

Google MLVision — Firebase ML 套件

当你去谷歌,这意味着你已经达到了你的极限。

视觉很难,我在图像处理方面的一点点经验教会了我这一点。你需要大量的资源和非常专业的工艺来完成一些像样的东西。

您需要下载设备上的文本识别。显然,它没有基于云的强大,但我可以告诉你,它粉碎了其他库(就像真的粉碎了)。

因此,我创建了一个带有完成块的函数,它返回一个字符串:

我会非常直截了当地说,谷歌是伟大的时期:

95%的全文,98%的准确率。

决赛成绩

谷歌总是赢

你不能生其他图书馆的气,因为他们不可能做到谷歌能做到的。他们已经在游戏中呆了很长时间,并为此投入了大量的资金和资源。

每个人都知道视觉是人工智能最具挑战性的领域,谷歌正在尽自己的一份力量。

要是像脸书、微软和亚马逊这样的公司能够通过开源他们的一些工具来分享一小部分知识就好了。

无论如何,这是最后的结果:

Final result

如果你喜欢这个教程,请鼓掌并分享给你的朋友。如果你有任何问题,不要犹豫给我发电子邮件到 omarmhaimdat@gmail.com。

这个项目可以从我的 Github 帐户下载

下载项目

谎言,该死的谎言,和数据可视化

原文:https://towardsdatascience.com/lies-damn-lies-and-data-visualisation-39e20991e7da?source=collection_archive---------33-----------------------

或者,算术的意想不到的优点

The 3D stacked pie chart shows 8 statistics simultaneously, and none of them effectively

作为一名分析师或数据科学家,可能会觉得从百万行数据帧中创造洞察力是这个过程中最难的部分。

你花费数小时来清除空值、转换数据、测试假设、记录 R 值和仔细检查 p 值。在某些时候,你会得出一个结论。你坐下来,自鸣得意,因为你发现了一些真正突破性的见解。

现在你需要告诉全世界这一切。

如果数学、数据科学和统计学是同一种外语的方言,那么数据可视化可以被认为是一块罗塞塔石碑,允许数字分析者向某种人传达洞察力,这种人可能相当合理地认为“y-hat”是一个关于头饰的问题。

思考如何展示洞察力本身就是一门艺术。如果一个人不能恰当地可视化数据,那么,坦率地说,它将不会被理解。无论见解与谁分享,都是如此。在我之前的管理顾问生涯中,我看到过客户——甚至是首席执行官——拒绝完全合理的、基于证据的建议,因为这些证据的表述不恰当。人们很难指责首席执行官缺乏计算能力,或者普遍忽视合理的建议。

我还从痛苦的个人经历中了解到,一个令人困惑的格式图表甚至会让一位同事感到困惑,他曾在同一数据集上工作,而正是这种洞察力来自于该数据集。因此,每当我在这个问题上培训新员工时,我都会鼓励他们遵循一个简单的数据可视化规则的简短列表:

  • 保持简单。始终假设条形图就可以了,只有在洞察的本质真正需要时才偏离(例如,显示时间序列的折线图,或显示相关性的散点图)。
  • 图表应该是完全可以理解的,不需要附带文字。
  • 每个图表只显示一个洞察。
  • 使用 3D 图表显示任何数据,我将把它作为结束你职业生涯的个人目标。

实现上述目标的关键是有效利用前注意属性——任何图形的基本视觉属性。

How much longer did it take you to spot the odd one out in ‘Curvature’, compared to ‘Position’? How much longer would it take you if the dots were 3-dimensional?

前注意加工,即提取“明显的”视觉信息的行为,如上述例子所示,发生在感觉记忆中。它不需要观众有意识的努力,并且只需要不到 500 毫秒就可以完成。那么,有效的数据可视化不仅仅是让观众读出轴外的数字,而是要吸引他们的潜意识。

"总有一天,统计思维将像读写能力一样,成为高效公民的必要条件." —赫伯特·乔治·威尔斯

22 < 0, 34 < 14, and 2+2 = 5

当然,一个著名的数据科学家应该尽力确保可视化不会歪曲数据。他们还应该以一种读者能够从中获得明确、准确信息的方式展示他们的发现。

然而,如果数字不支持你所希望的那种信息,那么数据仍然可以以讲述理想故事的方式呈现。甚至在世界呈现出最近的后真理倾向之前,统计数据及其可视化就经常带着这种不可告人的动机被使用。

达雷尔·赫夫的畅销书《T2》、《T3》、《如何用统计数据撒谎》、《T4》、《T5》、《T6》、《T7》,并不是为了回应肖恩·斯派塞的另类事实《T9》或《T10》在 2016 年竞选巴士上的不实言论而写的。事实上,它出版于 1954 年,尽管其中的许多主题对现代读者来说是熟悉的(章节标题包括“具有内在偏差的样本”、“精心选择的平均值”和“Gee-Wizz 图”)。

He who controls the media, controls the y-axis

一些数据可视化的现代例子,如此明显是为了欺骗观众而设计的,即使放在最粗略的审查下,看起来也几乎是滑稽可笑的。但是,即使这些数字真的写在图表上,第一视觉印象(通常是残缺的 y 轴)也很重要。图表的前注意属性闪闪发光,要求观众的注意力。一个人的潜意识,经过一百万年的进化,是很难反驳的。

死后的生活——像鹦鹉一样

原文:https://towardsdatascience.com/life-after-death-as-a-parrot-92e1e731c61e?source=collection_archive---------22-----------------------

Photo by Roberto Nickson on Unsplash

交谈人格复制品:什么会使他们好,他们有什么好处?

2022 年 11 月 9 日更新:根据麻省理工科技评论的报道,新玩家已经出现在复制品领域。这一点以及大型语言模型的惊人崛起预示着真正有效的复制品可能会出现。然而,我没有看到当前的开发者处理我在 2019 年提出的更难的功能问题。他们似乎也没有意识到我所讨论的更广泛的用途。

我妈妈几乎比她那一代人和我这一代人都长寿。在她去世之前,我开始了一本图画书,以帮助保存对她的记忆。我翻出并扫描了旧的硬拷贝照片,制作了家谱,查阅了剪报、信件和剪贴簿。这些图像本身不会说话,所以这本书的一半是叙述,围绕着时代、祖先和其他重要人物组织起来。这是大量的工作,她的亲人珍惜它。

就在她去世后,我分发了这本书的副本,我得知她与她的雇主美国邮政服务公司发生了争执。这是关于她在 20 世纪 50 年代受到男同事的骚扰,以及对女员工的制度性歧视。她赢了(!)多年后光荣地从 USPS 管理层退休。

她的追悼会是她的朋友办的,她告诉我们她的精神成长,以及其他人如何依赖她来获得祷告的指导。

即使我的记忆之书被传到后代,而不是丢失在一个盒子里,它也太早了,无法包含那个歧视的故事或她的精神历程。虽然它展示了她的绘画,但并没有告诉我们她可以用华丽流畅的手写出精心制作的句子。它只会让我们对她的性格或了解和爱她的感觉有一点点的了解,因为任何关于一个人的单一叙述都是如此的有限。

我们自己的遗忘在我们死前很久就开始了;我们的身体痕迹和其他人对我们的记忆在死后继续衰退。当我们掌握信息的力量和持久性时,为什么个人生活的记忆会化为灰烬?

我们现在生活在一个科幻世界里。我们听说过它一厢情愿的概念,关于不死,或被上传到一个模拟,或被重新动画。这些还是有些牵强。然而,鉴于目前的技术发展,解决被遗忘问题的方法是可以预见的。

“哦,不!”你会说,“这不是又一场技术乌托邦式的长篇大论。”在这个技术反弹的时刻,听到任何“解决”生活中一些事实的计划可能看起来像是无用的、沉闷的书呆子幻想。但是,最近经历了一次损失,并经常审视自己的死亡,我想知道:在肮脏的午睡开始后,我们能更多地保留我们的个人身份吗?我们应该这样做吗?是必然的吗?

近年来出现的概念是一个人格复制品,它拥有关于焦点(已故)人的历史和人格的数据,并能够在对话中表达这些信息,就好像死者正在与你交谈一样。开发者们已经开始摆弄昂贵的机器人演示技术,比如一个人的长相和说话方式。2005 年有一个作家菲利普·K·蒂克的机器人头部复制品。第二年,它在一架飞机上丢失了,2011 年在汉森机器人公司被重新创造出来,该公司制造了被称为“角色机器人”的表情机器人,用于“人性化”人工智能的研究。《银翼杀手》、《西部世界》和其他许多科幻小说探索了人造人黑暗面的推断。

试图模仿一个真实的人的外表、行为和声音是昂贵的,并且很容易陷入“恐怖谷”——这种相似性是错误的,足以令人毛骨悚然。有了个人复制品,目前更可行的是强调对话,甚至使用文本,而不是外表。一项研究发现当没有视觉化身时,人们对聊天机器人的接受度和舒适度更高。我们已经将聊天机器人用于许多实际用途。它们也可能被滥用于钓鱼,这恰恰强调了文字本身确实有影响我们的力量。不需要昂贵的机器人外观的复制品也会让更多的人买得起。

第一步:生命盒。

让对话复制品工作良好的最重要的一步是让机器在理解和生成语言方面都有所提高。为了理解为什么,我们回到人格复制思想的预言家:数学家、计算机科学家、超现实主义者、赛博朋克投机小说作家鲁迪·拉克。他的书描述了许多像 DMT 之旅一样离奇的现实。但是,早在 1986 年,他创造了术语“生命盒”来表示一个非常可实现的想法。正如他解释的那样:

“…要创建一个虚拟的自我,我需要做的就是(1)以文章、书籍和博客帖子的形式在网上放置大量文本,(2)提供一个用于访问这个数据库的搜索框,以及(3)提供一个漂亮的用户界面。”

Rucker 感到惊讶的是,目前使用这一想法的机构从未承认是他发明的。他继续在小说和演讲中发展这个概念。他知道核心概念,如上所述,不会很聪明或吸引人。为了展示这一点,他使用谷歌创建了一个属于他自己的的.)原始生命盒。当你查询它的时候,你会得到一组指向博客和其他页面的谷歌链接。如果你想研究其他人的工作,这可能没问题,但是你可以和他讨论“好的用户界面”的实际概念。

我曾经和一家名为 Replika 的公司签约,该公司提议给你创造一个模仿个性的聊天机器人,只要让你和他们的软件进行文本交流。它应该了解你并模仿你的语言风格。该公司最初的项目是制作已故朋友的复制品,但他们的目标最终不同:“……为你提供持续的陪伴,让你感觉更好”。

如果一个聊天机器人一直想引起我的注意,我很难想象会有比这更好的感觉。它问我的问题既老套又烦人。它不知道任何我想知道的事情。当时,我对公司的隐私和安全政策缺乏信任。我不能停止怀疑,认为机器人有某种…我不知道是什么:代理?智力?意向性?可信度?

作为一名软件开发人员,我可能比大多数人更难推销,因为我能看到幕后。Replika 得到了聪明的风险投资人的支持,所以他们必须看到它有朝一日如何赚钱。当然,赚钱很难证明它是良性的或有用的。如果真人的人工对话模型变得更好,它们能做什么?

语言能力。

我们可以从拼图的对话部分开始。非营利组织 OpenAI 最近展示了他们的人工智能语言模型 GPT-2 的能力,引起了很大的轰动。每当它被一个人写的东西所引导时,它就能编出非常连贯的故事。给出两个声称发现说英语的独角兽的句子,它完全靠自己创造了一个九段的故事,讲述独角兽长什么样,发现它们的进化生物学家的假名,发现它们的感觉,以及他对动物起源的理论。所有这些都是流利的英语,包括引用生物学家的话。基本上,令人震惊的的东西。

GPT 2 号还令人印象深刻地回答了关于它刚刚读过的文章的问题。在对话中,复制品需要类似的东西来回答问题。

其他人工智能研究人员对 GPT-2 感到兴奋,因为尽管 OpenAI“由于(他们)对该技术恶意应用的担忧”而隐瞒了细节,但他们发布了足够多的信息,以便其他人最终能够复制他们的工作。一个邪恶的用途可能是创造更有说服力的巨魔机器人。基于像 GPT-2 这样的东西的超级创意机器人会因为喷出大量,如 OpenAI 所说的,“欺骗性的,有偏见的,或辱骂性的语言”,也就是巨魔使用的那种挑衅性和白痴的故事而变得难以置信。一个种子句子或段落可以产生无限数量的故事,这些故事都旨在验证巨魔想要传播的基本谎言。此外,这些故事本质上的圆滑将使它们更难被其人类目标受众或人类或人工智能专家发现为欺诈。

巨魔是更好的人工智能语言能力的一个明显的缺点。但是想想看,如果一个人格复制品能够用这个人特有的措辞说话,并谈论这个人特有的关注点,这两件事都由 Replika 这样的公司来解决,那么它会有多迷人。然后想象一下,如果它能够做到这一点,同时对之前对话中的内容保持敏感,并且看起来富有创造性和自发性,就像 GPT 2 号具有回答问题和创造故事的能力一样。因此,如果当前的人工智能进展保持不变,可能会出现有能力的复制品。

从 Rucker 开始,复制品的支持者强调,你可以使用许多数据源来训练一个复制品程序,使其行为像一个已知的人。如今,我们有音频和视频对话、博客、照片库、短信、电子邮件和其他社交媒体的数据记录。其中一些是私有的,或者在一段时间后可能无法访问。需要解决这些材料的储存和获取问题。至少有一个组织在处理个人数字档案。这些自动化将是一大进步。对于更多的历史人物,有他们的信件和其他作品,以及历史学家、传记作家、小说家和电影制作人对这个人的评论。

正如你所料,这种“训练”的想法忽略了一些关于制作一个令人信服的、能有效交谈的复制品的超级技巧。普遍的(也是大的)问题是如何组织材料,使其实际上像复制品一样。让我们看看一些没有得到太多关注的具体问题,然后讨论复制品如何融入我们的生活和文化。

复制品保真度与适应性

任何人工智能研究人员都会告诉你,像 GPT-2 这样有能力回答问题或阐述故事的人,只是一个非常能干的模仿者。它不懂单词和句子。相反,基于对真实语言实例的训练,它拥有大量关于单词和句子搭配的知识。有许多像 GPT-2 这样的程序,虽然功能不太强大,但我们每天都在搜索引擎等中使用。

我认为这样的程序就像一只超级聪明的鹦鹉,吉姆,它生活在一个繁忙的餐馆里。他会从许多顾客那里收集一些对话,并很快学会模仿人们说话的方式。吉姆不会学习任何特定的人的风格,但无论你对他说什么,他都会有一个似是而非的回答。吉姆记住的长对话越多,他就能越好地模仿真实的对话。

如果我们坚持使用能力基于模仿的复制品,它们的底层软件将不得不在许多真实的对话中接受训练。短信交流会有所帮助,但要获得更大范围的情感和细微差别,你可能需要训练一个文学对话的复制品。

这里有一个隐含的平衡行为,在一个复制品能够一般地交谈和它能够像一个特定的人一样交谈之间。再考虑一下吉姆。他听到并模仿许多人。现在我们把他交给一个叫梅的顾客。她是一个善于交际、健谈的女人,有许多朋友拜访她的客厅,在那里吉姆可以听到她的谈话,无论是面对面还是通过电话。吉姆会开始“鹦鹉学舌”梅吗?当然可以。他有时会说不像她的话吗?大概吧。

这是最初的训练问题。为了创造一个真人的模拟,仅仅从那个人那里可能没有足够的训练数据来产生真正的语言流利度。如果吉姆只和梅一起生活过,你问他一些梅从未提过的事情,他会不知道该说什么。有必要首先赋予一个复制品一般的语言能力,然后把它训练成像梅阿姨或亚瑟叔叔那样。但你不希望亚瑟叔叔的复制品有时说话像狄更斯小说中的人物或一些咆哮的博客。你不能在南方的酒馆里训练吉姆,却期望他在纽约的熟食店里能被理解。这种训练权衡对我来说似乎真的很难,但突破可能会发生。

社会影响力。

几十年的研究已经确立了人格的社会性。我们的个性很大程度上是由我们认识的人创造和表达的。我们还根据一系列普遍的社会规范和个人的好恶来与新人交往,例如:善待老人和年轻人;相信每个人,但总是切牌,不要忍受傻瓜,避免相信 x 的人。我们对一个新人的判断会随着时间的推移而演变,这取决于我们双方的所作所为以及我们和他们如何使用“心理理论”来了解对方可能在想什么。

我还没有看到任何关于人格复制品的讨论。使用社交效果的第一步,也是最起码的一步,是让一个复制品知道它在和谁互动,并记住之前和每个人的对话。如果没有这些功能,与复制品的对话将会令人沮丧,就像与一个患有痴呆症的真人对话一样。但是关于记忆有一个棘手的问题。如果一个复制品随着时间的推移被它与他人的对话所改变,那么它可能会失去一些与它所模仿的人的相似性。在某种程度上,允许的变化可能会成为一种设计选择。你想要一个抗变能力强还是弱的复制品?对于程序员来说,要做到这一点可能非常棘手。

新知识。

另一个问题是,当你想问“艺术叔叔”对他死后发生的事情有什么想法时。在问他是怎么想的之前,解释一些新闻和它的背景是很费力的。然而,如果我们让他直接访问当前的新闻提要,他将会与原来的不同。如果我们试着把他的新闻内容裁剪成原文会读到的内容,我们会知道该选什么吗?

心流。

真正对话的流程取决于说话者每时每刻的感受。著名计算机科学家 David Gelernter(在他的书中:机器中的缪斯思维的潮汐提醒我们,我们的思维也在流动,在现在发生的事情和记忆之间有着级联的联想。这些思想分支,连同身体事件,引发情绪变化和注意力跳跃。当与一个复制品对话时,我们将检测到这些的缺乏,并且当它不能适当地响应我们的变化时,我们将注意到。

现在回到鹦鹉吉姆,假设有时餐馆不是很忙,他会听到附近桌子上更长的对话。如果顾客是真实的,让他们的感觉在交谈中流动和出现,那么吉姆将学会模仿这种流动。但是,如果你试着和他交谈,他能学到足够的东西让你始终信服吗?可能不会,因为吉姆没有内在的精神状态去修改自己的发言。迟早他会做出不和谐的推论,提醒我们他只是一只鹦鹉。

我们能给一个人格复制品一些影响它如何交谈的感觉和内在联系吗?也许吧,但我们可能需要一个突破来模拟一个人的内部状态,并将它们与正确的模仿语言片段联系起来。这可能是最难解决的问题,因为它不仅试图近似语言行为,还试图近似行为背后的思想。

他们有什么好处?

我曾经告诉过我的女儿,在某人死后制作一个人格复制品来延续的想法。她对这个概念反应激烈,直言不讳地表示厌恶。她可能会不高兴我公开讨论这件事。我认为她的反应,尽管是发自内心的,可能是对焦点人物记忆的不尊重,也可能是对他们在未来如何使用复制品的问题上缺乏同意。也许她对计算机与真人有任何关系或相似之处的想法嗤之以鼻。其他人也提出了这些观点。

这些都是非常有效和令人信服的反对意见。反驳的理由如下。复制品也可以被视为超越悼词、坟墓纪念碑、画册、传记、网站、肖像、死后奖励、祖先崇拜和其他我们纪念死者的方式的一步。复制品是带有对话界面的压缩内存。它们应该让你想起你所爱的人,而不是被任何东西取代。一些人对他们失去的亲人产生幻觉,并以精神存在的形式保留他们的影响力。为什么我们这些感觉不到死者的人不能用一种不那么亲密的方式来帮助记住他们呢?

简单的复制品已经存在。更多的将会被制作出来,并且有更好的保真度和更有效的交互性。它们可能会变得流行,但可能不会便宜。很难想象没有人类的努力就能做出好的作品。如果社交媒体和当前的机器人是任何例子,可悲的是,复制品的流行将不取决于它们是做得更多还是更多。因此,像往常一样,我们将受益于深谋远虑和辩论。

当一些人接近生命的尽头时,他们会考虑写一个生活故事,一本回忆录,甚至一本自传。这可以是:传授经验教训;不仅仅是消失,而是成为除了墓碑和其他重要的人心中腐烂的记忆之外的东西;或者表达对重要的人永恒的爱。有些人可能会写他们的故事,因为他们认为这个世界离不开他们。这些也是为什么人们会创造或要求创造他们的个人复制品的原因。

个人或机构也可能创造名人或重要人物的复制品。他们的目的广泛,从宣传到教育或咨询。一些复制品可能会教授历史,比如博物馆里出现的有声录音。一个复制品在某些方面取得新成就或创新的机会似乎离我们所能期待的很遥远。但其他用途似乎是可能的。科幻小说长期以来一直想象祖先复制品指导后代的命运。这可能对更保守的社会组织有用。事实上,他们可能会跳过它。

如果你让著名复制品互相交流,那么介于教育和咨询价值之间的东西可能随之而来。作家以前经常使用这种对话方式。你可能会受益于组建一个个人顾问委员会,里面有睿智、成功或(如果你喜欢的话)名人的复制品。可能会有人工智能帮助解决或澄清董事会成员之间的分歧。

从一个复制品那里得到建议,比你去阅读和理解原始人在生活中说过的每一句话更容易获得一些深度的好处。这样的建议会不会很肤浅?不一定,如果复制品本身是基于对原物的深刻了解。

这种推测会引起一些读者的不安,甚至愤怒。是的,这种复制品的影响力可能是巨大的(就像今天的名人一样),可能会被它们的创造者或用户滥用。例如,我们可以期待复制品的观点只反映其创造者的议程,而不是其原作者的智慧或完整视角。挑选出美国受人尊敬的创始人,你可以提出一些令人厌恶的、不道德的建议。从宗教书籍中挑选出的建议也是如此(通常尤其如此)。我们已经被过去的不良偏见淹没了。

那有什么新鲜的?我们正处于人工智能影响我们文化的早期阶段。我们注意到使用机器人作为交互代理来传递各种影响的趋势。我们不妨把人为的历史神谕想象成一种方式,让这种影响变得更加良性、个人化和容易理解。他们可以解释他们的建议,并向我们推荐原始资料进行验证。他们可能是反巨魔,而不仅仅是更好的巨魔。这是书呆子的理想主义,还是我们可以做的事情?

当我们还在打开这个新的罐头蠕虫时,我们应该开始建立规则。有了复制品,关于人造人的法律的发展可能是一个起点。然而,这应该从管理我们最初的法人 s:有限责任公司的社会病态鼓励法中脱离出来。至少,应该有法律和技术手段来限制谁可以使用或复制复制品。例如,这将允许在一个人的遗嘱中规定保护他们未来的任何复制品。

复制品的话题不可避免地会引出科幻小说的比喻。一个足够复杂的复制品的创造者无法预测它会说什么。因此,它会有言论自由的权利吗?还是会独立于其创造者,为其不当行为负责?你能阻止一个复制的煽动者吗?这些纪念性的创作会被视为鹦鹉还是人,被关在笼子里还是自由的?

Hadoop 后的生活:让数据科学为您的企业服务

原文:https://towardsdatascience.com/life-after-hadoop-getting-data-science-to-work-for-your-business-c9ab6605733f?source=collection_archive---------16-----------------------

扩展数据科学的五个基本要素

由乔希·帕特森和吉姆·斯科特

数据科学可以对企业产生变革性的影响。但如果需要几个星期才能有结果,就不会了。

将数据科学付诸实践可以简化为三个步骤。首先,从业务流程中捕获数据。第二,将这些大数据与海量处理结合起来,创建机器学习模型。第三,验证模型的准确性并部署它们。

这听起来似乎很容易,但是到目前为止,却一点也不容易。像 Apache Hadoop 和基于 CPU 的基础设施这样的传统方法无法胜任这项任务——它们造成了太多的瓶颈,而且速度太慢。

NVIDIA 及其合作伙伴正在开发基于 GPU 的工具,让企业利用人工智能释放数据科学。以下是构建人工智能优化数据中心的五个关键要素,但首先让我们看看数据科学正处于哪个十字路口。

大数据的麻烦在于

实现机器学习的数据科学家需要三样东西:算法、大量数据和大量计算能力。它们需要万亿字节的数据、千万亿次的计算和数百次迭代学习循环来创建机器学习数据管道。

大数据最初构建于 Hadoop 之上,因为它易于扩展。这允许存储大量的数据。为了处理这些数据,在大型集群中 Hadoop 使用了 MapReduce 等软件框架。

然而,与机器学习相关的常见数据处理任务有许多步骤(数据管道),Hadoop 无法有效处理。 Apache Spark 通过将所有数据保存在系统内存中解决了这个问题,这允许更灵活和复杂的数据管道,但引入了新的瓶颈。

这些管道的许多步骤包括收集、清理、标准化和丰富数据。但是只使用 CPU 来处理这些复杂的工作流非常慢。

在具有数百个 CPU 节点的 Spark 集群上,即使分析几百千兆字节的数据也需要几个小时甚至几天。现在考虑处理以大数据著称的万亿字节数据,数据科学家认为该过程已经停止是情有可原的。

这甚至没有涉及到数据科学家想要完成的实际工作。虽然工作流的单次运行需要几个小时才能完成,但数据科学家同时希望修改变量、模型和模型参数,以选择最佳组合并重复他们的想法。

Workflows have many iterations of transforming Raw Data into Training Data, which gets fed into many algorithms combinations, which undergo hyperparameter tuning to find the right combinations of models, model parameters, and data features for optimal accuracy and performance.

数据科学的新时代

为了快速迭代,数据科学家需要更强的计算能力。事实上,他们需要的是超级计算能力,但要以企业可以轻松集成到现有基础设施中的方式。旧式数据中心无法完成这项工作。

GPU 可以加速其数据管道的许多步骤。虽然为数据中心添加 GPU 有好处,但这还不够。

为了挖掘数据科学的潜力,GPU 必须成为数据中心设计的核心。一般来说,GPU 上的数据科学工作流的端到端速度大约是 CPU 上的 10 倍。

我们一直在与合作伙伴合作,为数据科学创建解决数据中心瓶颈的基本构件。优化的人工智能数据中心有五个要素:

计算节点

凭借其巨大的计算性能,采用 NVIDIA GPUs 的系统是人工智能数据中心的核心计算构建模块。从英伟达 T4 到 V100,英伟达企业级 GPU 为众多应用的服务器提供超级性能。

我们已经看到,通过为每个节点添加一个 T4,流分析应用程序的性能提高了 10 倍以上。在其他地方,我们已经看到,在 DGX 系统中,V100 GPUs 与 NVSwitch 连接后,图形分析性能提高了 1000 倍。

NVIDIA DGX 系统提供了突破性的人工智能性能,并在 GPU 密度方面领先,在单个节点中拥有 8 个和 16 个 GPU。一台 DGX-1 平均可以取代 50 台双插槽 CPU 服务器。这是为数据科学家提供业内最强大的数据探索工具的第一步。

建立工作关系网

故事不止于从 CPU 扩展到 T4 和 DGX 系统。对于企业通常收集的海量数据,数据科学家也必须向外扩展。今天,大多数数据中心使用 10 或 25 GbE 网络,因为使用更快的网络几乎没有任何好处。在传统系统中,GPU 通过标准网络进行通信。一旦数据必须跨越节点,瓶颈就是 CPU 和网络。

远程直接内存访问(RDMA)解决了这一瓶颈,为深度学习和机器学习提供了顶级性能。在 Mellanox NICs、 NCCL2 (英伟达集体通信库)和 OpenUCX (一个开源的点对点通信框架)中,训练速度有了巨大的提升。由于 RDMA 允许 GPU 以高达 100Gb/s 的速度跨节点直接相互通信,它们可以跨越多个节点,就像在一台大型服务器上一样运行。

RDMA 的好处不仅限于训练。对于大型复杂的 ETL 工作负载来说,这也是至关重要的。在没有 RDMA 的系统上,与 PCIe GPU 相比,改进网络可为分布式连接提供高达 20 倍的优势。此外,以前仅限于 GPU 到 GPU 的通信,RDMA 通过 GPUDirect 存储在摄取静态数据方面提供了额外的 2 倍速度提升。

储存;储备

加速存储对企业来说并不是一个新概念,它只是没有为基于 Hadoop 构建的传统大数据集群提供显著的成本改善。考虑到 CPU 的性能,答案是使用较慢的磁盘并多次复制数据以提高局部性。

但是随着工作负载变得越来越复杂,复制将会增加。或者,CPU 将花费 70%的时间在 Spark 集群的数百个节点之间来回发送数据。虽然单个 GPU 最多有 48GB 的内存,但最终需要从存储中转移数据,传统存储成为最后的瓶颈。

GPUDirect 存储允许 NVMe 和 NVMe 通过光纤(NVMe-oF)直接向 GPU 读写数据,绕过 CPU 和系统内存。传统架构在存储和 GPU 计算之间的 CPU 系统内存中放置了一个“缓冲区”,其中的数据副本将用于保持 GPU 上的应用程序运行。

借助 GPUDirect 存储,一旦所有计算都在 GPU 上进行,GPU 不仅成为速度最快的计算元素,而且成为 I/O 带宽最高的元素。这释放了 CPU 和系统内存用于其他任务,同时让每个 GPU 以高达 50%的带宽访问更多数量级的数据。

NVSwitch 用一个系统统一了 GPU,RDMA 跨节点统一了 GPU,现在 GPUDirect Storage 统一了 GPU 和 NVMe 将其容量提升到 Pb 级。

Unifying GPUs intra-node with NVLink and NVSwitch, internode with RDMA networks, and with NVMe over Fabric Storage with GPUDirect Storage provides the highest throughput for GPU processing and training.

Kubernetes 和容器

部署软件是扩展数据科学的最后一个关键。企业通常依靠一些虚拟化或编排层来部署软件。在数据科学领域,Yarn 一直占据着至高无上的地位。它是 Hadoop、Spark 和其他传统大数据生态系统的支柱,允许企业在工作流中的库之间切换。

几乎所有的 Yarn 部署都是在 GPU 支持之前的版本上。这使得 Yarn 环境中的数据科学家很难将 GPU 机器作为工作负载的目标。这也是企业转向 Kubernetes 和 Docker 容器的原因之一。

通过容器打包和部署应用程序对于获得灵活性至关重要。将容器化的应用程序与 Kubernetes 相结合,使企业能够立即改变最重要任务的优先级,并为人工智能数据中心增加弹性、可靠性和可扩展性。Kubernetes 和集装箱在部署时间上也比传统包装和纱线更快。虽然在 Yarn 上构建一个数据科学集群可能需要几十分钟,但使用 Kubernetes 可以在几秒钟内完成。

能够快速改变任务减少了空闲周期,从而提高了集群的吞吐量和生产率。随着计算资源变得更加强大和密集,这对于最大化数据中心的价值至关重要。

英伟达意识到了 Docker 和 Kubernetes 的重要性,很早就投资了这个社区。这项投资使得 NVIDIA GPUs 成为 Kubernetes 的一流资源。软件可以访问数据中心的所有功能和硬件加速,从而最大限度地提高企业在数据科学方面的投资。

加速软件

RAPIDS 是一套完全在 GPU 上执行数据科学管道的开源软件库和 API,可以将培训时间从几天减少到几分钟。RAPIDS 基于 NVIDIA CUDA-X AI 构建,凝聚了图形、机器学习、深度学习、HPC 等领域多年的开发成果。

通过隐藏数据中心架构中使用 GPU 甚至幕后通信协议的复杂性,RAPIDS 创建了一种简单的方法来完成数据科学。随着越来越多的数据科学家使用 Python 和其他高级语言,在不改变代码的情况下提供加速对于快速缩短开发时间至关重要。

另一种加速开发的方式是集成到领先的数据科学框架,如 Apache Spark、 Dask 和 Numba ,以及众多深度学习框架,如 PyTorch 、 Chainer 和 Apache MxNet 。通过这样做,RAPIDS 为新的加速数据科学生态系统奠定了基础。

作为 Apache 2.0 开源软件,RAPIDS 不仅在 GPU 上整合了这个生态系统,还降低了新库的准入门槛。越来越多的产品建立在 RAPIDS 之上——例如, BlazingSQL ,一个 SQL 引擎(最近完全开源了)——为用户增加了更多加速功能。

RAPIDS 允许新一波应用程序具有本机集成、Kubernetes 支持、RDMA 功能和跨无数数据格式的 GPUDirect 存储,而无需投资多年的开发。更多的软件让数据科学家更容易做他们想做的事情:用数据解决具有挑战性的问题。将这些优势与人工智能数据中心的其他方面结合起来,可以让您不受性能限制地处理数据科学。

英伟达 GPU 在行动

无论行业或用例如何,当将机器学习付诸行动时,许多数据科学问题都可以分解为类似的步骤:迭代地预处理数据以构建特征,用不同的参数训练模型,并评估模型以确保性能转化为有价值的结果。

RAPIDS 有助于加速所有这些步骤,同时最大限度地提高用户的硬件投资。早期客户采用了需要几天甚至几周才能完成的完整数据管道,并在几分钟内完成。他们同时降低了成本并提高了模型的准确性,因为更多的迭代允许数据科学家探索更多的模型和参数组合,以及在更大的数据集上进行训练。

零售商正在改善他们的预测。金融公司能够更好地评估信用风险。广告技术公司正在提高预测点击率的能力。数据科学家通常能实现 1-2%的改进。这可能看起来微不足道,但它可以转化为数千万或数亿美元的收入和利润。

帮助塑造未来

NVIDIA 致力于简化、统一和加速数据科学社区。通过优化从硬件到软件的整个堆栈,以及消除瓶颈,NVIDIA 正在帮助各地的数据科学家以更少的资源做更多的事情。这转化为企业最宝贵资源的更多价值:他们的数据和数据科学家。

但是,我们并不是孤军奋战。搭建跨越数据科学社区的桥梁,加速每个人的发展。成为社区的一部分。开始使用加速库,让我们知道接下来会有什么特性,并且申请加入我们的顾问联盟。

NVIDIA 正在构建未来的数据科学平台,我们希望您成为其中的一员。

“数据科学生命周期”

原文:https://towardsdatascience.com/life-cycle-of-a-data-science-project-2973578b2f74?source=collection_archive---------16-----------------------

你好,朋友们,

希望你像往常一样做得很好,首先我祝你有美好的一天!

它的我 萨纳特 ,回到我的第二篇博客关于任何数据科学项目背后最基本和最重要的想法之一——数据科学生命周期

正如我们所知,在过去几年中,“数据科学”这个词引起了巨大的轰动,许多不同领域的工作人员开始转向这个不断发展的领域,因为我们可以看到有很多数据科学爱好者。因为我是他们中的一员,现在成功转型了,所以我敢保证,要成为一名更好的数据科学家,这真的是一个比你想象的更大、更具挑战性的旅程。与此同时,这将是充满乐趣的一个;) .这个博客对于有抱负的候选人来说是一个有用的工具,可以让他们按照公司的要求来培养自己。

拥有更强大的基础将是这个领域所需要的最好的品质,因为每天都有大量的新研究在进行,你需要睁大你的眼睛和耳朵来协同进化。网上有各种各样的资源可以提高成为数据科学家所需的编程和数学技能。除了这些技能, 如果你对数据科学项目将会如何以及数据科学家在项目的不同阶段会有哪些不同的职责有一个清晰的想法,那将会非常有益。 如果我让你足够好奇的话,是时候去看看下面的博客中“数据科学生命周期”的几个步骤了。

许多有抱负的数据科学家的问题是,他们认为机器学习和数据科学都是关于花哨的建模,但如果我说,虽然建模是一个重要的部分,但在将数据扔进你选择的算法之前,数据科学家需要参与许多肮脏的工作,会怎么样呢?坦率地说,你的工作中只有 15%到 20%会成为模特,你迟早需要像我一样接受这个事实

数据科学生命周期中的步骤

  1. 业务需求/理解。
  2. 数据收集。
  3. 数据清理。
  4. 探索性数据分析。
  5. 建模。
  6. 绩效评估。
  7. 与利益相关者沟通。
  8. 部署。
  9. 真实世界测试。
  10. 商业买入
  11. 运营和优化。

这并不是一个到处都要遵循的固定框架,但是上面阐述的步骤将适用于大多数数据科学项目。

业务需求/理解

第一步也是最重要的一步是对我们将要解决的数据科学用例以及我们将如何处理它有一个公平的业务理解。在此阶段,我们将决定我们想要解决的业务 KPI(关键绩效指标)到底是什么,并制定要优化的等效机器学习 KPI。在这个阶段,我们需要确保对领域知识有一个公平的领域理解。因为领域知识给了我们一个更好的想法,让我们在以后的阶段进行特性工程黑客攻击。当你在一个你不知道的新领域做一个项目时,建议在前进之前联系一些领域专家,至少获得一些基本的理解。这一阶段为数据科学项目中的其余步骤提供了启动,因此要清楚您将进一步工作的用例是什么,并且在每个阶段,问自己您正在做的工作是否为提议的用例增加了任何价值。

数据收集

这一阶段涉及数据工程知识,其中将使用多种工具从多个来源导入数据,从本地系统中的简单 CSV 文件到数据仓库中的大型 DB。公平/合理地理解 ETL 管道和查询语言将有助于管理这个过程。在某些情况下,数据集不容易获得,我们将使用基于 API 或基于 web 抓取的方法来获取数据。在 Python 中,我们有一个很棒的库,叫做 beautifulsoup,可以轻松地从网站上抓取数据,但是有些网站不允许你抓取他们的网站,在这种情况下,当你试图这样做时,你可能会遇到麻烦。总是研究网页,只有在法律允许的情况下才刮去它。

数据清理

这是 datascience 项目中最麻烦的部分(可能在少数情况下),需要大量的时间,也是最关键的部分,这时您的编码技能就发挥作用了。我们实时获得的数据并不容易通过模型,在前进之前可能需要采取许多预备步骤。这一阶段需要确保的几个常见步骤包括:处理缺失数据、处理异常值、处理分类数据、删除停用词、特征化少数 NLP 任务的文本数据以及特征化音频或图像等。我们在最初步骤中获得的领域知识可以指导我们估算缺失值和去除异常值等。有人说,模型不需要你拥有的所有数据,它只需要有用和必要的部分,它可以从中学习,这强调了不是用我们拥有的全部数据填充模型,而是清理它,并以适当的方式发送它,以最大化吞吐量。

探索性数据分析

探索数据的真正工作开始的部分,在这个阶段,我们将做一些统计测试和可视化技术,以了解关于底层数据的更多细节/模式。我们观察的细节可能像检查每个不同变量/特征的潜在分布,检查类不平衡(如果有的话),做一些假设检验等。你可能想知道为什么需要所有这些细节,但是这些细节给了我们关于哪些类型的算法可以工作,哪些不能工作的第一层次的洞察力。例如,在像 Log 这样的高维数据线性模型中。回归,SVM 往往工作良好,而在很少的维度,基于树的模型有更好的预测性,可以分析我们的数据中的复杂趋势。这一步有助于我们从手头的各种模型中排除不需要的模型。我们还可以看到像 PCA、tSNE 这样的降维是否能帮助我们提高性能,以及数据的可分性等。有时数据清理也会在 EDA 之后进行,这完全取决于手头的问题。

如果你想有一个关于数据可视化的详细指南,请参考我以前详尽的博客。-> 链接

以上 4 个步骤是最重要的,一些初学者往往会忽略这些步骤,而不知道这些步骤的重要性。

系统模型化

接下来是我们大多数人都非常热衷的部分。在这一部分,您将选择算法,并向它们提供从上述步骤中准备的数据。建模方法包括模型构建和超参数调整,这是使建模阶段富有成效的关键。标准方法是选择一个基准模型,并在基准模型的规模上比较不同模型的性能,以选择最佳模型。我们可以使用 H20 的 AutoML 特性,在非常短的初始运行时间间隔内选择我们的初始基线模型集。

在构建模型时,请始终牢记所有的业务约束,如延迟、模型的可解释性、使用校准(如果我们要使用概率输出或日志损失作为我们的度量标准)等。总是试图让模型尽可能简单。从工业角度来看,当我们可以使用逻辑回归以 90%的准确度对点进行分类时,如果像神经网络这样的复杂模型能够提供大约 91%的轻微性能改善,则没有必要使用它们。这在像 kaggle 这样的竞争环境中完全不同,在那里性能比复杂性和可解释性更重要。通常情况下,你需要等很长时间来训练模型,下面的迷因清楚地说明了这一点。

性能赋值

下一步是评估我们模型的优劣,在这里,我们将根据我们的 KPI 比较不同模型的性能,并确保我们的最终模型满足所有业务约束。我们将看到混淆矩阵,分类报告等,并决定我们是否可以继续下去,或者有任何更多的微调需要我们的最终模型。

对于竞争环境,循环在这里停止,有时步骤 5 和 6 可以迭代地完成,以提出一个健壮的模型。对于业务用例,我们还需要完成几个步骤。

与利益相关者沟通

在这个阶段之前,球会在数据科学家的球场上,从现在开始,是时候将它来回发送到业务部门进行验证了。最终模型和所有见解将与项目干系人进行沟通。他们将验证我们的模型在各种极限情况下的表现,并确认他们的检查。数据科学家的最佳品质不仅仅是完成上述步骤,而是让利益相关者相信新的模型将为他们提供优于现有方法的优势。

部署

一旦我们得到了利益相关者的许可,就该将我们的模型投入生产了。这可能需要几个团队的合作,比如数据科学家、数据工程、软件开发人员等等,这取决于架构的本质和我们要解决的问题。有时,由于延迟问题,我们获得的模型参数会用 C/C++之类的语言写回,这种语言的执行速度比 python 快。整个团队还需要确保与其他相互依赖的应用程序没有任何冲突。

真实世界测试

该模型现在将在真实的生产环境中进行测试,以查看其有效性。到目前为止,所有的努力都将在这个阶段被见证,如果值得的话。有像 A/B 测试、AAB 测试这样的技术,可以帮助我们在真实世界的数据上获得模型的 KPI。这将是我们模型的最终验证,如果 KPI 和所有其他业务约束都得到很好的控制,我们就很好。如果没有,我们需要回去找到哪里出了问题,并再次遍历循环。

业务买入

一旦所有这些步骤都完成了,我们就到达了这个阶段,那么是时候“拍拍自己的背”了,这个项目是成功的,作为一名数据科学家,你已经做出了一些最终可以帮助别人的东西。这是我们项目的最后一个检查点步骤,从这里核心开发工作结束,支持和维护在即将到来的阶段开始。

运营和优化

数据科学家的工作不仅止于此,他们还需要一个监控或仪表板设置来持续/定期监控 KPI。从数据的角度来看,在许多情况下,今天构建的模型现在可能是好的,但是性能可能会缓慢下降,或者性能可能会立即下降。原因可能是动态变化的数据,甚至是数据的底层分布发生了变化。那么是时候重新训练我们的模型了。当我们积累了更多的新数据时,我们也可以随时随地重新训练我们的模型,但是只有在性能下降时才重新训练是更好的选择。与初始部署相比,再培训阶段可能没有这种开销。

万岁!!!到此为止,现在你可能已经对数据科学家的工作方式以及他在整个项目过程中需要担当的不同角色有了大致的了解。您可能是其中任何一个步骤的专家,但要使数据科学周期平稳运行,需要对所有部分都有很好的了解。

谢谢你一直读到最后,我一如既往地欢迎你的所有评论/反馈。如果你一直读到这个阶段,我可以肯定地假设你非常渴望成为一名数据科学家,为什么我们不能专业地交流,因为我们都将同舟共济;)

联动于:【www.linkedin.com/in/sanatmpa

电子邮件 ID:smartersanat@gmail.com

特别感谢来自 AppliedAICourse.com 的导师 Srikanth Varma,他是我进入这一领域的关键人物,他教会了我从基础到行业广泛使用的一切。甚至这个博客的灵感也来自于他的一个视频。

所附的迷因归功于谷歌图片搜索。

数据科学项目的生命周期

原文:https://towardsdatascience.com/life-cycle-of-a-data-science-project-3962b9670e5b?source=collection_archive---------12-----------------------

解决现实世界数据科学问题的主要步骤

Photo by Estée Janssens on Unsplash

自数据科学这个术语在 90 年代被创造出来以来,它已经成熟了很多。该领域的专家在解决数据科学问题时遵循一种固定的结构。现在开展数据科学项目几乎就是一个算法。

太多时候都有一种绕过方法论直接解决问题的诱惑。然而,这样做,由于没有为整个努力打下坚实的基础,阻碍了我们最好的意图。然而,遵循这些步骤往往会让我们更接近我们试图解决的问题。

The Flow of a Data Science Project

1)问正确的问题,即业务理解

尽管在过去十年中,数据访问和计算能力都有了巨大的增长,但一个组织的成功在很大程度上仍然取决于他们对数据集提出的问题的质量。收集的数据量和分配的计算能力并不是一个区分因素。

IBM 数据科学家 John B. Rollins 将这一步称为业务理解。例如,谷歌在开始时会问“什么构成相关搜索结果”。随着谷歌作为搜索引擎业务的发展,它开始展示广告。那么正确的问题应该是“哪些广告与用户相关”。一些其他成功企业过去曾问过其数据科学团队的正确问题

  • 亚马逊—在不景气时期,他们可以出租多少计算(EC2)和存储(S3)空间?
  • 优步——司机实际开车的时间占多大比例?他们的收入有多稳定?
  • Oyo 酒店——普通酒店的平均入住率是多少?
  • 阿里巴巴——我们仓库的每平方英尺利润是多少?

在我们开始数据科学之旅之前,所有这些问题都是必要的第一步。问完正确的问题后,我们继续收集数据

2)数据收集

如果问正确的问题是的秘诀,那么数据就是你的要素。一旦你对业务有了清晰的理解,数据收集就变成了将问题分解成更小的部分。

数据科学家需要知道需要哪些成分,如何获取和收集这些成分,以及如何准备数据以达到预期的结果。

例如,对于亚马逊,所需的数据类型将是

  • 精简期间空闲的计算服务器数量
  • 在不景气时期闲置的存储服务器数量
  • 维护这些机器所花的钱
  • 鉴于上述数据,亚马逊可以很容易地理解他们可以利用多少。事实上,当亚马逊回答这些问题时,贝佐斯很高兴地知道这是一个非常迫切的需求。这导致了 AWS 的出现。

如何寻找和收集 亚马逊的工程师们负责维护服务器运行的日志。进行了市场调查,以了解有多少人将从按使用付费服务器中受益,只有这样他们才继续前进。

xkcd

3)数据准备

现在我们已经收集了一些数据。在这一步中,我们了解更多关于数据的信息,并且进一步分析做准备。数据科学方法论的数据理解部分回答了这个问题:您收集的数据是否代表了要解决的问题?

比方说,优步想了解人们是否会选择为他们开车。为此,比方说,他们收集了以下数据

  1. 他们目前的收入
  2. 出租车公司对他们收费的百分比降低了
  3. 他们乘坐的次数
  4. 他们闲置的时间
  5. 燃料成本

虽然 1-4 有助于他们更多地了解司机,但第 5 条并没有真正解释司机的任何事情。燃料成本确实影响了优步的整体模式,但并没有真正帮助他们回答他们最初的问题。

为了理解数据,很多人看数据统计,如平均值、中位数等。人们还绘制数据,并通过直方图、频谱分析、人口分布等图来查看其分布。

一旦我们对数据有了更好的理解,我们就为进一步的分析做准备。准备工作通常包括以下步骤。

  1. 处理缺失数据
  2. 修正无效值
  3. 删除重复
  4. 将数据结构化后送入算法
  5. 特征工程

数据准备类似于清洗蔬菜以去除表面化学物质。数据收集、数据理解和数据准备 占整个项目时间的 70%-90%

这也是如果你觉得数据不合适或不足以让你继续,你回到数据收集步骤。

一旦准备好并清理了数据,我们就进入任何数据科学项目的核心——建模

4)数据建模

建模是数据科学方法中的一个阶段,在这个阶段,数据科学家有机会品尝调味汁,并确定它是否正点或需要更多调料

建模用于发现数据中的模式或行为。这些模式或者以两种方式帮助我们——1)描述性建模例如推荐系统也就是说,如果一个人喜欢电影《黑客帝国》,他们也会喜欢电影《盗梦空间》;或者 2) 预测性建模,它涉及到对未来趋势的预测,例如线性回归,我们可能想要预测股票交易值

xkcd

在机器学习世界中,建模分为 3 个不同的阶段——训练、验证和测试。如果学习模式是无人监督的,这些阶段就会改变。

无论如何,一旦我们建立了数据模型,我们就可以从中获得洞见。这是我们最终可以开始评估我们完整的数据科学系统的阶段。

建模的结束是由模型评估来表征的

  1. 准确性—模型的表现如何,即它是否准确地描述了数据。
  2. 相关性——它是否回答了你想要回答的原始问题

5)部署和迭代

最后,所有数据科学项目都必须部署在现实世界中。部署可以通过 Android 或 iOS 应用程序,就像 cred 一样,也可以通过 web 应用程序,比如moneycontrol.com或者作为企业软件,比如 IBM Watson

无论您的数据模型以何种形式部署,它都必须向现实世界公开。一旦真正的人类使用它,你一定会得到反馈。对任何项目来说,获取这些反馈都直接关系到生死。您获得的反馈越准确,您对模型所做的更改就越有效,您的最终结果也就越准确。在这一点上,典型的组织记录这个流程,并雇佣工程师来不断迭代整个流程。

Real World Deployment

数据科学项目是一个迭代过程。您不断重复不同的步骤,直到您能够根据您的具体情况对方法进行微调。因此,您将同时进行上述大部分步骤。 PythonR 是数据科学使用最多的语言。数据科学是一个兔子洞。祝你玩得开心!

来自数据科学的生活经验

原文:https://towardsdatascience.com/life-lessons-from-data-science-a59119e130d6?source=collection_archive---------20-----------------------

过去的几个月对我来说是当头一棒。在搬到柏林之前,我已经想好了一切。我把这个学期的计划细化到每天几点起床,去哪所舞蹈学校,读什么书。(是的,其中涉及到一个 Excel 电子表格。)每件事都有预算和时间段;一切都说得通了。直到它没有。

入住两个月后,我发现自己迷失了方向,对日常生活完全不满意。夹在统计课、没完没了的作业和每天寻找意义和动力的努力之间,内心似乎打开了一个洞,提醒我,我以为我知道的“过最好的生活”的一切都不起作用。

然后,就像你注意时经常发生的那样,洞察力开始从似乎在折磨我的源头出现。当我在计算科学课程中导航时——最后一刻改变专业,这被证明不是一个玩笑——我突然意识到数据科学的原则对我们的日常生活是多么适用。我发现统计数据和个人成长都有三点是正确的:

  1. 你是你最丰富的数据集。
  2. 说到底,是系统的问题,不是细节的问题。
  3. 个人成长,就像数据科学一样,最好由好奇心驱动。

你是你最丰富的数据集。理解它并从中学习。

现实世界是一个巨大的反馈机制。最有才华的创新者和博学的未来学家是那些看到整体并理解人类历史的人,这是巧合吗?“了解你自己”是良好的数据科学和真正的个人成长的核心。我们过去的经历、情感模式、欲望和厌恶是一个不断被挖掘和更新的巨大数据仓库。随着我们的成长,我们开发了一个复杂的模型,将这些数据作为输入,并将信念、叙述和期望作为输出。但这种模式可能会崩溃,而且经常如此。预测与观察不符,所以我们对这个世界有一种挫败感。我们发现自己陷入了困境,因为我们的模型缺乏从自身错误中学习的能力。我们不断输入相同的数据,期待新的结果。不是有人说精神错乱的定义就是一遍又一遍的做着同样的事情,期待着不一样的结果吗?

在数据科学中,你知道你预测未来的能力取决于你对过去的解释。一个好的模型总是以敏锐的精确度整合历史数据。问题是并非所有的数据都是相关的。有点像这几天看新闻;知道发生了什么很重要,但十有八九,“发生”的是一种嘈杂的干扰,与真实的事态没有多大关系。

这个原则可能很难接受。人们可能会在生活中伤害自己,因为他们强化了很久以前建立在一些负面经验基础上的叙事。过度使用一个模型会产生一个强化的反馈循环,使得随着时间的推移更难改变。我从小就被告知(含蓄地)聪明的人获得科学学位,其他的都是肤浅的和浪费时间的。我花了一年时间学习痛苦的物理课程,只是为了取悦我内心的那个声音,那个声音说如果我不这样做,我就会是一个失败者。这种心态继续以微妙的方式限制着我,我知道我还有很多事情要做。

如果你的生活是一个统计模型,它会是什么样子?哪些变量比其他变量更重要,为什么?面对新信息时,模型表现如何?如果它不再为你服务,它还能适应吗?

归根结底,这是关于系统,而不是细节。

有一种东西叫做过度合身。过于完美地提炼每一课,同等关注地审视每一次经历,你的模型很快就会崩溃。我们不仅仅是我们各部分的总和,过度分析一个人自身存在的每一个方面——正如柏拉图所说,“在关节处雕刻自然”——并不会让我们更好地生活,并真正地享受那种存在。一个优秀的数据科学家知道,最好的模型总是为随机性、偶然性和同步性留有余地。在生活中,我们称之为神秘、美丽、奇迹。

前几天,一个朋友透露他的生活准则是“不要设定目标”。创建系统。”我们中的许多人从小就被教导要追求远大的目标,用一生去追逐里程碑,证明自己的价值,核对清单上的项目。这种努力的回报是认可、名誉和成功。但是,如果没有一种甜蜜、宁静的满足感,目标又是什么呢?这就是自我提升模式失去效力的地方,也是我朋友的方法如此吸引人的地方。

如果我们少关注细节,多关注大局会怎么样?如果我们的日常活动不是基于需要做什么,而是基于我们想要如何生活会怎样?任务将变得不那么受时间和成就的限制,而更倾向于它们给我们和他人带来的感受;他们挑战我们的部分和他们允许我们活出的价值。例如,我的朋友辞去了他朝九晚五的工作,以便有更多的时间陪伴他的儿子。他是一名自由职业的法律顾问,按照社会标准,他现在一天中的大部分时间都毫无建树。当其他人在写电子邮件和签署协议时,他可能正在擦拭刚刚滑下儿子脸颊的大块食物。当他工作时,他创造性地、精力充沛地工作,边喝咖啡边头脑风暴,举办法律研讨会,帮助企业家驾驭错综复杂的业务。他的套路很灵活。他是一个善于思考和与人交往的人,他已经找到了将自己的职业生活融入一个更大体系的方法,这个体系构成了他真正想要的生活。不是每天都是完美的。有时最后期限无法满足。但是每天,他都在调整系统,让他做他最擅长的事情,并变得更好。在他的模型中,做一个创新的法律顾问和做一个父亲一样重要。

数据科学和生活本质上都是经验性的,我们无法通过完善代码行或分分秒秒地分配时间来掌握它们。我们通过观察、参与和学习来掌握它们,然后创建一个反映我们最重视的东西的系统。

个人成长,就像数据科学一样,最好由好奇心驱动。

你可能听说过“p-hacking”这个术语。这是当研究人员有意或无意地操纵他们的方法来产生一个期望的 p 值时发生的事情——这个成败的统计数字告诉你在现实生活中获得与控制测试相同结果的概率。p 值显示了统计意义,这是数学家问“我应该多认真地对待这些结果?”

当数据科学家 p-hack 时,他们已经不再试图证明一个假设。相反,他们正在收集证据来支持他们已经相信或希望别人相信的东西。我们在自己的生活中一直是这种偏见的受害者。当我们的模型崩溃时,我们继续期待从相同的输入中得到不同的结果,我们告诉自己没关系。我们会想办法从积极的角度看待证据。我们不是问题所在,其他人才是。我们观察到的任何差异都是微不足道的。我们通过“证明”相同的旧假设来愚弄自己,不断收集有利于我们当前思维模式的证据,并拒绝任何表明有改进空间的东西。

这种想法很可怕,但如果对实验设计进行适当的调整,即使是最严谨的数据分析师也可以声称找到了不存在的模式,或者推翻了明显存在的模式。探索性数据分析的目标是发现和理解这些有趣的模式。但与 p-hacking 不同,它要求在数据发现过程中,我们不要在头脑中操纵我们看到的内容。方法纯粹是好奇。

我已经成为树立里程碑的牺牲品,这些里程碑不会挑战我的思维方式。追求个人成长和追求个人满足之间有很大的区别。我们不喜欢承认一个有时与另一个相矛盾。

那又怎么样呢?

数据科学教会了我少花时间制定计划,多花时间思考。系统的方法让我更容易更新我的信念,寻求和回应反馈,并确定我自己的模型中需要重新设计的部分。

我的结论是:没有“一刀切”。尝试完美之前先做实验。把自己当成一个优雅的统计模型,善于整合细微的反馈,消除噪音,适应复杂的环境。通过从你的错误中学习,并接受他人的意见,为你的基础建立弹性。把你的注意力从“什么时候?”以及“怎么做?”到“为什么?”,然后观察各个部分开始组合在一起。你的生活与其说是目标的线性结果,不如说是综合系统的一个突现属性。

作为一名数据科学家,最令人满意的事情之一是能够使用新开发的技能来揭示现实生活。我花了太长时间寻找“新的有趣的应用程序”,而最明显的一个却一直盯着我。

部署后模型的生命周期

原文:https://towardsdatascience.com/life-of-a-model-after-deployment-bae52eb83b75?source=collection_archive---------24-----------------------

Example dashboard used to monitor models — Stakion

应用程序监控是在生产中运行软件的关键部分。没有它,找到问题的唯一方法是通过运气或者因为客户报告了它。至少可以说这两者都不太理想!

你不会在没有监控的情况下部署应用程序,那么为什么要为机器学习模型部署呢?

为了尽量保持帖子的可管理长度,我们将只关注几个关键主题:

  • 监控所需的数据
  • 要跟踪和提醒的关键指标
  • 训练和推理分布之间的相似性度量

监控所需的数据

为了准确地监控机器学习模型,在进行预测时需要记录粒度数据。这些日志可用于调试为什么做出某个预测,一旦汇总,将使我们能够监控模型。

良好测井的关键部分:

  • 由调用 ML 模型的系统提供的每个请求的唯一 Id。这个唯一标识符将与每个日志一起存储,并允许我们在 ML 模型之前、期间和之后跟踪预测的路径。
  • 在特征工程之前输入特征
  • 输入特征工程后的特征
  • 输出概率
  • 预测值

虽然这看起来像是大量的日志记录,但是如果没有它,我们将看不到模型是如何处理某些输入的。

要跟踪的关键指标

在最好的情况下,我们会近乎实时地将地面实况标签与我们的预测进行比较。不幸的是,这通常是不可能的,因为对于大多数应用程序来说,基本事实标签直到做出预测后很长时间才可用。例如,当试图预测下一年的收入或预测交易是否欺诈时,就是这种情况。

如果无法实时追踪模型的准确性,请改为追踪输入和输出要素的分布。

监视模型功能背后的假设是,当要求模型对不属于定型集的新数据进行预测时,模型的性能将会改变。

我们可以通过跟踪一些指标来很好地了解模型的健康状况:

  • 预测次数
  • 预测延迟—进行预测需要多长时间
  • 输入和输出特征分布的变化

在特征级别,我们将想要跟踪在训练期间计算的分布(训练分布)和在推理期间计算的分布(推理分布)之间的相似性度量。

训练和推理分布之间的相似性度量

为了监控一个特性,我们需要计算一个度量来比较训练和推理分布。有许多不同的相似性分布可供选择,但很少能同时适用于分类变量和数值变量。

计算相似性度量

Wasserstein 距离[1]是一种相似性度量,可以针对数字和分类特征进行计算,其定义为:

Wasserstein distance with U as the training CDF and V the inference CDF

从图形上看,Wasserstein 距离是两个累积分布函数之间的面积。因此,如果训练和推理分布是相同的,那么它将是 0。当它们开始发散时,距离会增加,并且没有上限。

Graphical representation of the Wasserstein distance.

要计算分类变量的 Wasserstein 距离,您必须对每个类别的频率差异的绝对值求和。

存储分布

为了计算 Wasserstein 距离,我们需要存储连续分布和离散分布。

连续分布可以用 t-Digests 来表示[2]。不涉及细节,t-Digests 是一种新的数据结构,它存储 CDF 的稀疏版本,并具有许多属性(容易序列化、并行化等)。

离散分布更容易存储,我们只需要存储类别和它们各自的频率。如果类别总数很高,那么我们可以只存储前 1000 个。

可视化离散分布可能很棘手,我们可以做的一件事是将类别分组到桶中,每个桶至少包含 x %的数据(见下文)。鉴于这是在训练数据上完成的,我们预计每个桶的大小在推断过程中会略有波动。

Bucketing categories into buckets of frequency of 10%.

结论

通过一点规划,监控机器学习模型并不复杂。

监控模型归结为跟踪预测的数量以及训练和推理分布之间的相似性度量。如果你已经准备好了,你就可以高枕无忧了,如果出了问题,你会是第一个知道的人!

参考文献:

[1]瓦瑟斯坦米制,【https://en.wikipedia.org/wiki/Wasserstein_metric】T4

[2]使用 t-Digests 计算极其精确的分位数,https://arxiv.org/abs/1902.04023

生活方式、日常活动和网络虐待:有联系吗?

原文:https://towardsdatascience.com/lifestyles-activities-and-cyber-abuse-is-there-a-link-d757c835bb7a?source=collection_archive---------27-----------------------

使用 AutoStat 和贝叶斯变量选择对网络滥用的探索性分析。

Credit: Dragana Gordic / Freepik.com

介绍

互联网的出现带来了改进的通信、商业机会、科学和技术的进步。它也为犯罪创造了新的机会、新的犯罪方法和更多的潜在受害者。其中一种犯罪是网络虐待,这是一个总称,指的是利用技术进行的跟踪和骚扰。

虽然一些研究人员认为网络虐待只是旧的传统人际暴力形式(如跟踪和骚扰)的延伸,但很明显,技术影响着犯罪的实施、经历以及随后可以预防的方式。

对跟踪和骚扰机制的研究相当广泛,许多犯罪学理论被用来解释其原因。然而,新技术形式的滥用的因果机制尚未得到充分理解。同样不清楚的是,考虑到“地面”犯罪形式而发展起来的传统理论是否有助于解释这些新的犯罪形式。

在本文中,我们关注生活方式-日常活动理论,该理论解释了为什么一些人比其他人更容易经历犯罪(Cohen 等人,1981)。从这个角度来看,犯罪被视为在缺乏有能力的监护人的情况下,有动机的罪犯在时间和空间上与合适的目标汇合的产物(Cohen 和 Felson,1979 年)。

该理论认为,我们的生活方式和日常活动是犯罪受害风险的重要预测因素,因为它们决定了与罪犯接触的可能性。那些生活方式和日常活动更有可能导致与潜在罪犯接触的人更有可能成为受害者。

根据这一理论,犯罪受害的风险是概括的,可以通过衡量个人的以下方面来评估:a)风险暴露程度,b)与潜在罪犯的接近程度,c)目标吸引力(以经济或象征价值的形式,并被视为易受伤害),以及最后,个人周围环境中是否存在潜在监护人(如被动旁观者或积极干预者)。

在本文中,我们的目的是检验危险的生活方式和日常活动与网络虐待受害之间的关系的本质。

数据和方法

为了提高我们对网络虐待受害机制的理解,我们使用在线调查(N = 1463)调查了亚马逊的机械土耳其人的成年成员,然后使用在 AutoStat 中实现的随机搜索算法使用贝叶斯变量选择进行逻辑回归分析数据。

为了评估活动类型对成为网络虐待受害者的可能性的影响,我们测量了受访者参与潜在风险日常在线活动的程度,以及他们与各种社会联系人群体(如家人、朋友、在线游戏联系人等)的人际关系的强度。).在这里,我们测量了以前的研究中显示的影响一个人的风险暴露、与罪犯的接近程度、目标吸引力以及有能力的监护人的存在与否的活动,因此与个人受害风险的增加相关联 Vakhitova 等人(2019)。

表 1 显示了我们在此分析的样本的汇总统计数据。

将数据可视化

表 1 中的汇总统计数据似乎表明,我们关注的两个亚组(受害者和非受害者)在参与危险活动的程度上存在一些差异。为了帮助可视化这一趋势,我们使用箱线图和密度图比较了受害者和非受害者的在线生活方式和日常活动。图 1 展示了在线志愿服务(例如,作为在线论坛版主)和经历网络虐待受害者之间关系的密度和箱线图。这些数字表明,受害者(橙色分布)比非受害者(蓝色分布)更倾向于在线志愿服务。事实上,只有少数非受害者报告积极参与网上志愿服务。

Figure 1: Volunteering online and cyber abuse victimisation: Density plot on the left and boxplot on the right

然而,这种趋势并不一致,例如,对受害者和非受害者在线收入的比较表明,受害者和非受害者在线收入的可能性相似,这表明在线收入可能不是网络虐待受害的重要预测因素(见图 2)。

Figure 2: Earning income online and cyber abuse victimisation: density plot on the left and boxplot on the right.

要在 AutoStat 中生成分布图,选择选项卡可视化,选择您希望生成的图的类型,并将您希望绘制的变量移动到适当的框中(将您的分类变量移动到 子组 框中,将您的连续变量移动到 框中)(参见图 3)。

Figure 3: Generating density distribution plots in AutoStat®. Figure 6: Choice of plotting options in AutoStat®.

为什么在 AutoStat 中选择贝叶斯变量?

如前所述,双变量关系的汇总统计和可视化表明,受害者更有可能参与危险的在线活动,同时,不太可能与大多数人际关系积极交往(与前浪漫伙伴的关系和在线游戏连接除外)。

为了估计生活方式和日常活动相关变量以及社会人口统计控制的综合影响,我们现在将使用 AutoStat 中实施的贝叶斯变量选择逻辑回归对网络虐待受害进行建模。

在决定建模方法时,我们考虑了研究的探索性;在选择模型中包含的变量时,明显缺乏理论指导;以及先前研究中确定的社会科学研究背景下变量选择的统计方法的益处(Vakhitova 和 Alston-Knox,2018;Vakhitova 等人,2019 年)。在缺乏关于模型规范的明确理论指导的情况下,在建模过程时采用贝叶斯变量选择不仅允许考虑参数不确定性,还允许考虑模型不确定性,以及解决过拟合的问题。

我们使用 AutoStat 进行此分析,因为它提供了一个简单、用户友好的界面,以及一种进行类似分析的简单方法。在 R 编程环境中也有许多用于执行贝叶斯变量选择的统计包,例如,Raftery (1995)和 Raftery 等人(2016)或 Clyde 等人(2016)。虽然这些算法中的每一个都略有不同,但它们的意图是统一的,并且从模型中得出的推论也有类似的解释。

在这种分析中,随机搜索算法用于确定最可能的模型的解释能力。 AutoStat 允许使用多个不同的先验估计最可能的模型。在这项研究中,我们采用 G-先验尖峰厚片来实现变量选择。

如 G 先验尖峰厚片示意图所示,先验有两种状态(见图 4)。在系数被包括在模型中的 MCMC 迭代期间(如随机搜索算法所示),在该后验样本抽取中使用的先验将是 G 先验,表示为“slab”。类似地,对于当随机搜索不包括系数时的迭代,在后验抽取中使用的先验是零(0)处的点质量,由“尖峰”指示,导致系数的后验抽取正好是零(0):

Figure 4: Spike-Slab Algorithm Schema

我们的β参数的 g 先验(板坯)由: 给出

随着 g 的增加,先验变得更集中在零(0)附近,并在后验分布规范中扮演更活跃的角色。在本例中,我们将 g 设置为等于样本大小(AutoStat 中的默认值)。

有关变量选择的随机搜索算法和 g-prior 规范的更多信息,请参见 Marin 和 Robert (2014)。

AutoStat 模型生成器:操作指南

以下是如何使用 AutoStat 的模型构建器功能,通过随机搜索算法执行贝叶斯变量选择分析的操作指南。

在 AutoStat 中使用贝叶斯变量选择进行逻辑回归,选择 Model Builder 选项卡。选择您正在分析的数据集,并将其移动到训练数据框。然后选择因变量并将其移动到预测变量框,然后移动预测解释变量框。请注意,如果您有任何缺失值,您可以选择从分析中删除它们。

下一步是在屏幕的参数设置部分指定您的建模参数。您可以指定先验 g(在我们的例子中,等于删除所有缺失数据后的样本大小)、随机种子、迭代次数和 burnin(参见图 5)。

Figure 5: AutoStat® Model Builder. Drag and drop datasets; select model framework; specify variable(s) of interest, and select model parameters before analysing.

指定参数后,点击分析按钮,随机搜索的神奇就在你眼前发生了(图 6)!

Figure 6: AutoStat® Model Builder running the logistic regression model. On the right-hand side, Bayesian variable selection was specified with a G-prior spike slab estimator, with 10,000 iterations.

作为贝叶斯变量选择分析的一部分,AutoStat 生成许多不同的输出,包括五个最佳解释模型的摘要以及所有感兴趣系数的包含概率(图 7),所有感兴趣系数的均值、标准差和 HPD 区间的摘要(图 8),详细的变量重要性图(图 9)和许多诊断图(例如,参见图 10 和 11)。

Figure 7: Top five best models explaining cyber abuse victimisation as a function of routine activities.

Figure 8: Means, standard deviations and HPD intervals for all coefficients included in explanatory models.

Figure 9: Relative Variable Importances

Figure 10: Posterior distribution for participating in online gaming as an explanation of cyber abuse victimisation.

Figure 11: The visualisation of the spike-slab algorithm for participating in online gaming as an explanation of cyber abuse victimisation.

结果

表 2 总结了我们的分析结果。它显示使用我们的数据的最佳模型(模型 1)具有 0.23%的后验概率,包括 10 个预测值。第二个最好的模型(模型 2)有 9 个预测值,后验概率为 0.21%。请注意,模型的后验概率并没有告诉我们模型的预测能力。相反,它给了我们一个相对于所有其他可能模型的数字。因此,在我们的特定示例研究中,拥有许多潜在回归变量意味着大量潜在解释模型,这反过来意味着模型的相对后验概率较小。

Table 2: Logistic regression with variable selection predicting the risk of cyber abuse victimisation. Checkmarks denote coefficients included in the model.

最佳模型(模型 1)中包含的大多数变量也包含在所有五个最佳模型中,包含概率超过 50%。两个例外是与前浪漫伴侣的社交,包括在五分之四的最佳模式中,以及与体育联系人的社交,包括在五分之三的最佳模式中,入选概率约为 40%。

表 2 表明,使用我们的数据并控制社会人口特征、生活方式和日常活动似乎是网络虐待受害者的有用预测指标,其中一些指标比其他指标更有用。最佳解释模型(模型 1)表明,造成网络虐待受害风险的最重要因素包括参与在线志愿服务和与前浪漫伴侣交往形式的风险因素,以及可能积极干预网络虐待事件的人在场/不在场形式的保护因素,在线赚取收入,以及与家人、配偶和体育/社会联系人交往。

使用表 2 中的信息,我们估计那些生活中有监护人干预的人只有 17%可能遭受侵害,而那些在其直接环境中没有监护人干预的人有 83%可能遭受侵害;与家人、配偶和体育/社会委员会联系人的社交似乎也与减少经历网络虐待的可能性有关(分别为 27%、41%和 44%)。

然而,参与在线游戏、在线志愿活动和与前恋人交往会增加网络虐待受害者的风险(分别为 61%、66%和 65%)。网上赚钱似乎可以保护个人免受网络虐待(经历网络虐待的概率只有 38%)的发现令人困惑。那些在网上赚取收入的人的行为方式似乎与那些将互联网用于娱乐和交流目的的人不同,这只是为了保护他们免受伤害。

值得注意的是,在社会人口特征中,只有年龄是受害的有用预测因素(年轻人更有可能经历受害),而种族、就业和性别则不是。

讨论和结论

我们的发现表明,受害者的生活方式和日常活动可以为网络虐待受害机制提供有用的见解。话虽如此,一些生活方式和日常活动似乎比其他的影响更大。例如,我们发现,诸如在线志愿服务、在线收入、与前浪漫伴侣和体育/社交联系人进行社交等活动会增加网络虐待受害者的风险,而身边有人可以积极干预网络虐待事件,与家人和体育/社交联系人进行社交实际上会降低一个人成为网络虐待受害者的风险。

根据生活方式-日常活动理论,我们的最佳模型包括至少一个变量,该变量封装了来自所有四个风险方面的风险:暴露于风险、接近罪犯、目标吸引力和特别有能力的监护。

支持监护作为保护因素的证据特别有趣。我们的最佳模型包括四个衡量监护的变量——一个衡量在线监护(有人干预),三个衡量线下监护(积极与家人、配偶和体育/社会委员会联系)。看来监护就像网络空间本身一样没有边界;它的影响从地球世界到网络空间,然后再回来。

似乎也有一个主要由主要联系人(如家庭、配偶等)组成的活跃的社会网络。可以作为防止犯罪受害的保护因素。需要进一步的研究来更好地理解这种保护机制。

这项研究的另一个有趣的发现是,有人可以在网络虐待事件中代表你积极干预是网络虐待受害者的最佳解释(纳入概率为 100%),然而,有人目睹(被动)你被网络虐待并不是虐待的良好预测因素,纳入概率低于 40%。这一发现强调了监护在预防犯罪行动中的价值(Reynald,2010)。

传记

Zarina Vakhitova博士是莫纳什大学(澳洲墨尔本)社会科学学院的讲师,专门研究犯罪学和刑事司法。她的研究兴趣集中在应用环境犯罪学原理来理解和控制发生在网络空间的犯罪。Zarina 在谷歌学术的出版物清单在这里。

参考

克莱德,m .,利特曼,m .,王,q .,戈什,h. J .,,李,Y. (2016)。 BAS:贝叶斯模型平均的贝叶斯自适应采样。r 包版本 1.4.2。从 ftp://cran.r-project.org/pub/R/web/packages/BAS/BAS.pdf 取回

科恩,L. E .,&费尔森,M. (1979)。社会变化和犯罪率趋势:日常活动方法。《美国社会学评论》,第 44 期,588–608 页。

科恩,l .,克卢格尔,j .,,兰德,K. (1981)。社会不平等和掠夺性受害:一个正式理论的阐述和检验。《美国社会学评论》,46 期,505–524 页。

Marin 和 c . p . Robert(2014 年)。纽约 R . Bayesian essentials:Springer New York。

拉夫特里(1995 年)。社会研究中的贝叶斯模型选择。社会学方法论,25 ,111–163。

a .拉夫特里,Hoeting,j .沃林斯基,c .画家 I .,& Yeung,K. Y. (2016)。 BMA:贝叶斯模型平均。r 包版本 3.18.6。从 http://CRAN.R-project.org/package=BMA 取回

雷诺医学博士(2010 年)。监护人对监护:影响监护意愿、发现潜在犯罪者能力和干预意愿的因素。《犯罪和青少年犯罪研究杂志》,第 47 期,第 358-390 页。

Vakhitova,Z. I .,& Alston-Knox,C. L. (2018)。非显著 p 值?理解和更好地确定逻辑回归中效应和相互作用的重要性的策略。 PLoS ONE,13 (11)。DOI:https://DOI . org/10.1371/journal . pone . 0205076

瓦希托娃、Z. I .、阿尔斯通-诺克斯、C. L .、韦伯斯特、J. L .、雷诺德、D. M .、&汤斯利、M. K. (2019)。生活方式和日常活动:它们会导致不同类型的网络虐待吗?人类行为中的计算机,101 ,225–237 页。DOI:https://DOI . org/10.1016/j . CHB . 2019.07 .

神经类型转移的直观指南

原文:https://towardsdatascience.com/light-on-math-machine-learning-intuitive-guide-to-neural-style-transfer-ef88e46697ee?source=collection_archive---------5-----------------------

点亮数学机器学习

探索神经类型转移网络的设计选择和技术的直观指南

Courtesy of Pixabay.com

介绍

神经类型转移(NST)是一个非常好的想法。NST 建立在一个关键的理念上,

在计算机视觉任务(例如图像识别任务)期间学习的 CNN 中,可以分离风格表征和内容表征。

根据这一概念,NST 采用预训练的卷积神经网络(CNN)将风格从给定图像转移到另一个图像。这是通过定义试图最小化内容图像、风格图像和生成图像之间的差异的损失函数来实现的,这将在后面详细讨论。本教程结束时,你将能够创建非常酷的作品,如下所示。

本教程将在接下来的章节中介绍以下部分。

  • 为什么神经类型转移和高层架构
  • 加载 VGG 16 权重作为预训练的网络权重
  • 定义神经型传递网络的输入、输出、损耗和优化器
  • 定义将数据馈送到网络的输入管道
  • 训练网络并保存结果
  • 结论

本系列的其他文章可以在下面找到。

A BCD* E FG* H I JKL*** M N O P Q R S T U V******

*表示中等付费墙后面的文章

本文的目的

本文的目的是提供一个原则性的指南,而不是一个算法的预演,或者用一长串无聊的代码让读者窒息。特别是在这篇文章的结尾,我希望读者理解 NST 背后的概念,并知道为什么某些事情是这样的(例如损失函数)。作为一个额外的好处,读者可以浏览端到端的代码,并看到实际情况。

密码

请注意,我将只分享文章中最重要的代码片段。你可以在这里 获得 Jupyter 笔记本 的全部代码。该算法用 TensorFlow 实现。

为什么是 NST?

在物体识别和检测等任务中,深度神经网络已经超过了人类水平的性能。然而,直到最近,深度网络在产生具有高感知质量的艺术作品等任务上还远远落后。使用机器学习技术创造更高质量的艺术对于达到类似人类的能力是必不可少的,并开辟了一个新的可能性范围。随着计算机硬件的进步以及深度学习的普及,深度学习现在正被用于创作艺术。例如,一幅由人工智能生成的艺术作品不会在拍卖会上以高达 432,500 美元的价格出售。

高层建筑

如前所述,神经类型转移使用预训练的卷积神经网络。然后,为了定义将两个图像无缝混合以创建视觉上吸引人的艺术的损失函数,NST 定义了以下输入:

  • 内容图像( c ) —我们要将样式转移到的图像
  • 样式图像( s ) —我们要从中转移样式的图像
  • 输入(生成)图像( g ) —包含最终结果的图像(唯一可训练变量)

该模型的架构以及损耗的计算方法如下所示。您不需要深入理解下图中的内容,因为您将在接下来的几个部分中看到每个组件的细节。这样做的目的是对风格转换过程中的工作流程有一个高层次的理解。

High level architecture of NST model

下载和加载预训练的 VGG-16

你将从这个网页中借用 VGG-16 的重量。您需要下载 vgg16_weights.npz 文件,并将其放在您的项目主目录**中一个名为 **vgg** 的文件夹中(对不起,我应该自动完成这个任务,但是我太懒了)。你将只需要卷积和池层。具体来说,您将加载第一个7卷积层,用作 NST 网络。你可以使用笔记本中的load_weights(...)功能来完成。**

****注:欢迎你多尝试几层。但是要小心你的 CPU 和 GPU 的内存限制。

定义函数以构建风格传递网络

在这里,您定义了几个函数,这些函数将有助于您稍后全面定义给定输入的 CNN 的计算图。

创建张量流变量

在这里,您将加载的 numpy 数组加载到 TensorFlow 变量中。我们将创建以下变量:

  • 内容图片(tf.placeholder)
  • 风格形象(tf.placeholder)
  • 生成的图像(tf.Variabletrainable=True)
  • 预训练重量和偏差(tf.Variabletrainable=False)

确保生成的图像是可训练的,同时保持预训练的权重和偏差不变。下面我们展示两个函数来定义输入和神经网络权重。

计算 VGG 净产出

在这里,你通过卷积和汇集运算来计算 VGG 净产出。请注意,您正在用tf.nn.avg_pool操作替换tf.nn.max_pool,因为tf.nn.avg_pool在风格转换过程中会产生更好的视觉效果[1]。通过改变以下功能中的操作,随意试验tf.nn.max_pool

损失函数

在本节中,我们定义两个损失函数; 内容损失 功能和 风格损失 功能。内容损失函数确保更高层的激活在内容图像和生成的图像之间是相似的。风格损失函数确保在风格图像和生成的图像之间,所有层中激活的相关性是相似的。我们将在下面讨论细节。

内容成本函数

内容成本函数确保内容图像中存在的内容在生成的图像中被捕获。已经发现,CNN 在较高的级别中捕获关于内容的信息,其中较低的级别更关注单个像素值[1]。因此,我们使用最顶层的 CNN 层来定义内容损失函数。

【a^l_{ij}(i】为激活第 l 、第 i th 特征图和使用图像获得的第 j th 位置。那么内容损失被定义为,**

The content loss

基本上 L_{content} 捕获由生成的图像和内容图像产生的激活之间的均方根误差。但是为什么最小化更高层激活之间的差异确保了内容图像的内容被保留?

内容丢失背后的直觉

如果你想象一下神经网络所学到的东西,有证据表明,在不同物体的存在下,更高层的不同特征图被激活。因此,如果两幅图像具有相同的内容,它们在较高层中应该具有相似的激活。

我们可以将内容成本定义如下。

风格损失函数

定义风格损失函数需要更多的工作。为了从 VGG 网络中提取风格信息,我们使用了 CNN 的所有层。此外,风格信息被测量为给定层中特征图之间存在的相关量。接下来,损失被定义为由生成图像和风格图像计算的特征图之间存在的相关性的差异。数学上,风格损失定义为,**

(在本教程中选择均匀)是在损失计算期间给予每一层的权重,是取决于第 l 层的大小的超参数。如果您想查看确切的数值,请参考本文。然而,在此实施中,您没有使用 M^l ,因为在定义最终损耗时,它将被另一个参数吸收。**

风格丧失背后的直觉

虽然上面的方程式系统有点拗口,但这个想法相对简单。目标是为生成的图像和样式图像计算一个样式矩阵(如下图所示)。则风格损失被定义为两个风格矩阵之间的均方根差。

下面你可以看到一个如何计算样式矩阵的图解。样式矩阵本质上是 Gram 矩阵,其中样式矩阵的第 (i,j) 元素是通过计算第 i th 和第 j th 特征图的逐元素乘法并对宽度和高度求和来计算的。在该图中,红色叉号表示元素间的乘法,红色加号表示跨越特征图的两个宽度和高度的求和。

您可以按如下方式计算样式损失。

为什么在 Gram matrix 中可以捕捉到风格?

我们知道如何计算风格损失,这很好。但是您仍然没有看到“为什么使用 Gram 矩阵计算样式损失”。Gram 矩阵本质上捕捉了给定层中一组特征图的“特征分布”。通过尝试最小化两幅图像之间的风格损失,您实际上是在匹配两幅图像之间的特征分布[3,4]。

:个人认为上面的问题没有得到满意的回答。例如[4]解释了风格损失和域适应之间的相似性。但是这个关系并没有回答上面的问题。

所以让我试着更直观地解释一下。假设您有以下特征地图。为了简单起见,我假设只有三个特征图,其中两个完全不活动。您有一个特征地图集,其中第一个特征地图看起来像一只狗,而在第二个特征地图集中,第一个特征地图看起来像一只颠倒的狗。然后,如果您尝试手动计算内容和样式损失,您将获得这些值。这意味着我们没有丢失两个特征地图集之间的样式信息。但是,内容却大相径庭。

Understanding style loss

最终损失

最终损失定义为:

其中 αβ 为用户自定义超参数。这里 β 吸收了前面定义的 M^l 归一化因子。通过控制 αβ 可以控制注入生成图像的内容和样式的数量。您还可以在论文中看到不同 αβ 值的不同效果的可视化效果。

定义优化器

接下来,您使用 Adam 优化器来优化网络损耗。

定义输入管道

在这里,您可以定义完整的输入管道。[tf.data](https://www.tensorflow.org/guide/datasets)提供了一个非常易于使用和直观的接口来实现输入管道。对于大多数图像操作任务,你可以使用[tf.image](https://www.tensorflow.org/api_guides/python/image) API,然而tf.image处理动态大小图像的能力非常有限。例如,如果您想要动态裁剪和调整图像大小,最好使用生成器的形式,如下所示。

您已经定义了两条输入管道;一个是内容,一个是风格。内容输入管道寻找以单词content_开头的jpg图像,而样式管道寻找以style_开头的图像。

定义计算图形

现在你准备好摇滚了!在本节中,您将定义完整的计算图。

  • 定义提供输入的迭代器
  • 定义输入和 CNN 变量
  • 定义内容、风格和总损失
  • 定义优化操作

跑步风格转移

是时候运行计算图并生成一些艺术作品了。生成的作品将被保存到data/gen_0data/gen_1,...、data/gen_5等。文件夹。

当你运行上面的代码时,你应该得到一些整洁的图片保存到你的磁盘上,如下所示。

结论

在本教程中,您学习了神经类型转移。Neural style transfer 允许将两个图像(一个包含内容,一个包含样式)混合在一起,以创建新的艺术作品。您首先了解了为什么需要 neural style transfer,并概述了该方法的架构。然后,您用 TensorFlow 定义了神经类型传递网络的细节。具体来说,您定义了几个函数来定义变量/输入、计算 VGG 输出、计算损失和执行优化。接下来,你明白了让我们获得我们想要的东西的两个损失;详细讨论了内容损失和风格损失,并了解了它们是如何共同定义最终损失的。最后,您运行了模型并看到了模型生成的艺术品。

本教程的代码可在 这里 获得。

想在深度网络和 TensorFlow 上做得更好?

检查我在这个课题上的工作。

[1] (书)TensorFlow 2 在行动——曼宁

[2] (视频教程)Python 中的机器翻译 — DataCamp

[3] (书)TensorFlow 中的自然语言处理 1 — Packt

新的!加入我的新 YouTube 频道

如果你渴望看到我关于各种机器学习/深度学习主题的视频,请确保加入 DeepLearningHero 。

进一步阅读

【1】艺术风格的神经算法

【2】tensor flow 神经风格转移教程

【3】Quora 关于神经风格转移的文章

【4】揭秘神经风格转移

Keras 深层网络中的注意力

原文:https://towardsdatascience.com/light-on-math-ml-attention-with-keras-dc8dbc1fad39?source=collection_archive---------0-----------------------

点亮数学机器学习

将所有错综复杂的注意力转移到喀拉斯的一条优雅的线上

Courtesy of Pixabay

这个故事向您介绍了一个 Github 存储库,其中包含一个使用 Keras 后端操作实现的原子最新关注层。可在 关注 _keras 获得。

要访问本系列中我以前的文章,请使用以下信件。

ABCD* E F G H I JK**L*******M****

[ 🔈🔥最新文章🔥🔈:M—矩阵分解****

为什么是 Keras?

随着 TensorFlow 2.0 的推出,很难忽视引人注目的关注(没有双关语!)送给 Keras。有更多的重点是倡导 Keras 实施深度网络。TensorFlow 2.0 中的 Keras 将提供三个强大的 API 来实现深度网络。

  • 顺序 API——这是最简单的 API,首先调用model = Sequential()并不断添加层,例如model.add(Dense(...))
  • 功能 API —高级 API,您可以在其中创建具有任意输入/输出的自定义模型。定义一个模型需要非常小心,因为在用户端有很多事情要做。可以使用model = Model(inputs=[...], outputs=[...])定义模型。
  • 子类化 API——另一个高级 API,可以将模型定义为 Python 类。在这里,您可以在类中定义模型的向前传递,Keras 会自动计算向后传递。那么这个模型可以像使用任何 Keras 模型一样正常使用。

更多信息,从 TensorFlow 团队获得第一手信息。然而,请记住,虽然选择高级 API 为实现复杂模型提供了更多的“回旋空间”,但它们也增加了出现错误和各种兔子洞的机会。

为什么发这个帖子?

最近,我正在为我正在做的一个项目寻找一个基于 Keras 的注意力层实现或库。我处理了几个已经引起关注的回复。然而,我的努力是徒劳的,试图让他们与以后的 TF 版本。由于几个原因:

  • 实现注意力的方式缺乏模块化(对整个解码器而不是解码器的各个展开步骤实现注意力
  • 使用早期 TF 版本中不推荐使用的函数

他们做出了巨大的努力,我尊重所有做出贡献的人。但是我想我会介入并实现一个 AttentionLayer ,它适用于更多的原子级别,并随着新的 TF 版本而更新。这个库在这里可用。

:这是数学机器学习 A-Z 上 光系列的一篇文章。你可以在下面的信中找到以前的博客文章。

A BCD* E F G H I JKL*** MNO P Q R S T U V**********

介绍

在这篇文章中,首先你会探究什么是序列对序列模型,然后是为什么注意力对序列模型很重要?接下来,你将学习注意力机制的本质。这篇博文将以解释如何使用注意力层来结束。

序列到序列模型

Sequence to sequence 是一个强大的深度学习模型家族,旨在解决 ML 领域中最疯狂的问题。举个例子,

  • 机器翻译
  • 聊天机器人
  • 文本摘要

有着非常独特和独特的挑战。比如机器翻译要处理不同的语序拓扑(即主语-动词-宾语顺序)。因此它们是解决复杂 NLP 问题的必备武器。

让我们看看如何将序列对序列模型用于英法机器翻译任务。

序列对序列模型有两个组件,一个编码器和一个解码器。编码器将源句子编码成一个简洁的向量(称为上下文向量),解码器将上下文向量作为输入,并使用编码的表示来计算翻译。

Sequence to sequence model

这种方法有问题吗?

这种方法有一个巨大的瓶颈。上下文向量负责将给定源句子中的所有信息编码成一个包含几百个元素的向量。现在给出一点背景,这个向量需要保持:

  • 关于主语、宾语和动词的信息
  • 这些实体之间的相互作用

这可能是相当令人生畏的,尤其是对于长句。因此,需要一种更好的解决方案来突破极限。

输入关注!

如果解码器能够访问编码器的所有过去状态,而不是仅仅依赖于上下文向量,会怎么样?这正是注意力在做的事情。在每个解码步骤中,解码器都会查看编码器的任何特定状态。这里我们将讨论 Bahdanau 注意力。下图描绘了注意力的内部运作。

Sequence to sequence with attention

因此,如图所示,上下文向量已经成为所有过去编码器状态的加权和。

介绍 attention_keras

由于我前面解释的原因,让一些注意力层在那里工作可能会很麻烦。

使用注意力层

您可以将它用作任何其他层。举个例子,

**attn_layer = AttentionLayer(name='attention_layer')([encoder_out, decoder_out])**

我还提供了一个玩具神经机器翻译器(NMT)的例子,展示了如何在 NMT ( nmt/train.py )中使用注意力层。但是让我带你了解一些细节。

用心实施 NMT

在这里,我将简要介绍一下实现 NMT 的步骤。

首先定义编码器和解码器输入(源/目标字)。两者都是形状(batch_size,timesteps,vocabulary_size)。

**encoder_inputs = Input(batch_shape=(batch_size, en_timesteps, en_vsize), name='encoder_inputs')
decoder_inputs = Input(batch_shape=(batch_size, fr_timesteps - 1, fr_vsize), name='decoder_inputs')**

定义编码器(注意return_sequences=True)

**encoder_gru = GRU(hidden_size, return_sequences=True, return_state=True, name='encoder_gru')
encoder_out, encoder_state = encoder_gru(encoder_inputs)**

定义解码器(注意return_sequences=True

**decoder_gru = GRU(hidden_size, return_sequences=True, return_state=True, name='decoder_gru')
decoder_out, decoder_state = decoder_gru(decoder_inputs, initial_state=encoder_state)**

定义关注层。注意层的输入是encoder_out(编码器输出序列)和decoder_out(解码器输出序列)

**attn_layer = AttentionLayer(name='attention_layer')
attn_out, attn_states = attn_layer([encoder_out, decoder_out])**

连接attn_outdecoder_out作为 softmax 层的输入。

**decoder_concat_input = Concatenate(axis=-1, name='concat_layer')([decoder_out, attn_out])**

定义TimeDistributed Softmax 层并提供decoder_concat_input作为输入。

**dense = Dense(fr_vsize, activation='softmax', name='softmax_layer')
dense_time = TimeDistributed(dense, name='time_distributed_layer')
decoder_pred = dense_time(decoder_concat_input)**

定义完整模型。

**full_model = Model(inputs=[encoder_inputs, decoder_inputs], outputs=decoder_pred)
full_model.compile(optimizer='adam', loss='categorical_crossentropy')**

就是这样!

甚至支持注意力可视化…

这不仅实现了注意力,也给了你一个很容易窥视注意力机制的方法。这是可能的,因为这一层返回两者,

  • 注意上下文向量(用作解码器的 Softmax 层的额外输入)
  • 注意能量值(注意机制的 Softmax 输出)

对于每个解码步骤。因此,通过可视化注意力能量值,你可以完全了解注意力在训练/推理过程中在做什么。下面,我来说说这个过程的一些细节。

从 NMT 推断并获得关注权重

从 NMT 推断是繁琐的!因为你必须这么做,

  • 获取编码器输出
  • 定义一个执行解码器的单个步骤的解码器(因为我们需要提供该步骤的预测作为下一步的输入)
  • 使用编码器输出作为解码器的初始状态
  • 执行解码,直到我们得到一个无效字/ 作为输出/或固定步数

我不打算讨论模型定义。详情请参考examples/nmt/train.py。让我们来看看如何利用这一点来获得关注权重。

**for i in range(20):dec_out, attention, dec_state = decoder_model.predict([enc_outs, dec_state, test_fr_onehot_seq])dec_ind = np.argmax(dec_out, axis=-1)[0, 0]...attention_weights.append((dec_ind, attention))** 

如你所见,我们正在为每个解码步骤收集注意力权重。

然后,您只需将这个注意力权重列表传递给plot_attention_weights ( nmt/train.py ),以便获得带有其他参数的注意力热图。绘图后的输出可能如下所示。

2022 年 6 月更新

最近有一个关于 AttentionLayer 在 TensorFlow 2.4+版本上不工作的 bug 报告。这导致了如下的神秘错误,

**TypeError: Exception encountered when calling layer "tf.keras.backend.rnn" (type TFOpLambda).You are passing KerasTensor(type_spec=TensorSpec(shape=(None, 101), dtype=tf.float32, name=None), name='tf.compat.v1.nn.softmax_1/Softmax:0', description="created by layer 'tf.compat.v1.nn.softmax_1'"), an intermediate Keras symbolic input/output, to a TF API that does not allow registering custom dispatchers, such as `tf.cond`, `tf.function`, gradient tapes, or `tf.map_fn`. Keras Functional model construction only supports TF API calls that *do* support dispatching, such as `tf.math.add` or `tf.reshape`. Other APIs cannot be called directly on symbolic Kerasinputs/outputs. You can work around this limitation by putting the operation in a custom Keras layer `call` and calling that layer on this symbolic input/output.Call arguments received:• step_function=<function AttentionLayer.call.<locals>.energy_step at 0x7f1d5ff279e0>• inputs=tf.Tensor(shape=(None, None, 256), dtype=float32)• initial_states=['tf.Tensor(shape=(None, 101), dtype=float32)']• go_backwards=False• mask=None• constants=None• unroll=False• input_length=None• time_major=False• zero_output_for_mask=False**

该错误是由于基于图形的KerasTensor对象和渴望的tf.Tensor对象之间的混淆造成的。即将合并的 https://github.com/thushv89/attention_keras/tree/tf2-fix 分公司正在进行调整。

结论

在本文中,我向您介绍了 AttentionLayer 的一个实现。注意力对于序列模型甚至其他类型的模型都是非常重要的。然而,当前的实现要么不是最新的,要么不是非常模块化。所以我稍微挖了一下,用 Keras 后端操作实现了一个注意力层。所以我希望你能在这一层做得很好。如果您有任何问题/发现任何 bug,请随时在 Github 上提交问题。

欢迎贡献者

我将非常感谢有贡献者,修复任何错误/实施新的注意机制。所以欢迎投稿!

如果你喜欢我分享的关于数据科学和机器学习的故事,考虑成为会员吧!

**** [## 通过我的推荐链接加入媒体

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

thushv89.medium.com](https://thushv89.medium.com/membership)****

想在深度网络和 TensorFlow 上做得更好?

检查我在这个课题上的工作。

[1] (书)TensorFlow 2 在行动——曼宁

[2] (视频课程)Python 中的机器翻译 — DataCamp

[3] (书)TensorFlow 中的自然语言处理 1 — Packt

新的!加入我的新 YouTube 频道

如果你渴望看到我关于各种机器学习/深度学习主题的视频,请确保加入 DeepLearningHero 。

理解手套嵌入的直观指南

原文:https://towardsdatascience.com/light-on-math-ml-intuitive-guide-to-understanding-glove-embeddings-b13b4f19c010?source=collection_archive---------1-----------------------

点亮数学机器学习

理解 GloVe 和 Keras 实现背后的理论!

Photo by Jelleke Vanooteghem on Unsplash

;(太久没发工资了?不用担心,您仍然可以通过以下链接访问代码)

带 Keras 的手套实现:【此处为】

在本文中,您将了解 GloVe,这是一种非常强大的单词向量学习技术。本文将重点解释为什么 GloVe 更好,以及 GloVe 的成本函数背后的动机,这是算法中最关键的部分。。该代码将在后面的文章中详细讨论。

要访问本系列中我以前的文章,请使用以下信件。

ABCD E F G H I JK**L*******M*****

[ 🔈🔥最新文章🔥🔈**:M—矩阵分解**

GloVe 是一种词向量技术,它在短暂的沉寂之后驾驭了词向量的浪潮。只是为了刷新,单词向量将单词放入一个很好的向量空间,相似的单词聚集在一起,不同的单词相互排斥。GloVe 的优势在于,与 Word2vec 不同,GloVe 不仅仅依赖于局部统计(单词的局部上下文信息),而是融入了全局统计(单词共现)来获取单词向量。但是请记住,手套和 Word2vec 之间有相当多的协同作用。

听到使用全局统计数据来推导单词之间的语义关系的想法可以追溯到很久以前,不要感到惊讶。第一回,潜在语义分析 (LSA)。这只是一个有趣的事实。我们继续吧。

Word2vec 复习

Word2vec 背后的根本思想是什么?

从一个人交的朋友你就可以知道他说了什么——j·r·弗斯

单词向量就是建立在这个想法上的。基本上,你得到一个大型语料库,并制作一个元组数据集,其中每个元组包含(某个单词 x,x 的上下文中的一个单词)。然后你会使用你的老朋友,一个神经网络,学习预测 x 的上下文单词,给定单词 x。如果你想了解更多关于 Word2vec 的信息,请参考我的文章这里。

那么是什么在拉回呢?

鉴于 Word2vec 的显眼性能,为什么不坚持使用呢?原因不在于性能,而在于解决方案制定的根本。记住,Word2vec 只依赖于语言的 本地信息 。也就是说,对于一个给定的单词所学习的语义,只受周围单词的影响。

例如,以这个句子为例,

那只猫坐在垫子上

如果你使用 Word2vec,它不会捕捉这样的信息,

“the”是“cat”和“mat”这两个词的特殊语境吗?

或者

“the”只是一个停用词吗?

这可能是次优的,尤其是在理论家的眼中。

****回车,手套

GloVe 代表“全局向量”。如前所述,GloVe 捕获语料库的全局统计数据和局部统计数据,以便得出单词向量。但是,我们需要全球和地方统计数据吗?

两个比一个好吗?

事实证明,每种类型的统计都有自己的优势。例如,捕获局部统计数据的 Word2vec 在类比任务中表现非常好。然而,像 LSA 这样只使用全局统计的方法在类比任务中做得不好。然而,由于 Word2vec 方法由于仅使用局部统计而受到某些限制(如我们上面讨论的)。

手套介绍

手套方法建立在一个重要的理念上,

你可以从共现矩阵中推导出单词之间的语义关系。

给定一个含有 V 词语的语料库,共现矩阵 X 将是一个 V x V 矩阵,其中第行和第 j 列为 XX_ij 一个示例共现矩阵可能如下所示。

The co-occurrence matrix for the sentence “the cat sat on the mat” with a window size of 1. As you probably noticed it is a symmetric matrix.

我们如何从中获得一个度量词之间语义相似性的指标呢?为此,你需要一次说三个词。让我具体记下这句话。

The behavior of P_ik/P_jk for various words (Source [1])

考虑实体

P _ ik/P _ JK其中P _ ik = X _ ik/X _ I****

这里的 P_ik 表示同时看到单词 ik 的概率,通过除以同时出现 ik(X _ ik)的次数来计算**

你可以看到,给出两个词,即,如果第三个词(也叫“探针词”),******

  • 与冰很相似但与蒸汽无关(如k=固体) P_ik/P_jk 会很高(> 1),******
  • 与蒸汽很相似但与冰无关(如k=气体)P _ ik/P _ JK会很小(< 1),****
  • 与任一单词相关或不相关,那么P _ ik/P _ JK将接近 1****

因此,如果我们能够找到一种方法将P _ ik/P _ JK结合到计算单词向量中,我们将实现在学习单词向量时使用全局统计的目标。****

从度量到词向量

如果你喜欢到目前为止,系好安全带。就要变得粗暴了!我们如何能得到一个字向量算法并不是很明显,

  • 我们没有方程,例如 F(i,j,k) = P_ik/P_jk ,只是一个表达式。
  • 词向量是高维向量,然而 P_ik/P_jk 是标量。所以存在维度不匹配。
  • 涉及三个实体( i,j ,和 k )。但是用三个元素计算损失函数可能会很麻烦,需要减少到两个。

回答这三个问题是 GloVe 的主要贡献。现在让我们一步一步地浏览 GloVe,看看回答这三个问题如何给我们一个词向量算法。

我使用下面的符号,由于在介质上渲染乳胶的困难,它与论文略有不同。

  • wu —两个独立的嵌入层
  • *******w —w 的转置
  • X —共生矩阵
  • bwbu —分别为 w 和 u 的偏差

让我们假设一个等式

回答第一个问题很容易。假设一下。假设有一个函数 F,它接受字向量 ijk ,输出我们感兴趣的比率。

F(w _ I,w_j,u _ k)= P _ ik/P _ JK

现在你应该有点好奇了,因为我们看到两个嵌入层在播放( wu)。为什么是两个?该论文称,通常这两层的性能相当,只是随机初始化不同。然而,有两层有助于模型减少过度拟合****

现在回到函数。词向量是线性系统。例如,您可以在嵌入空间中执行算术运算,例如

w _ {国王}—w _ {男性}+w _ {女性} = w _ {女王}

因此,让我们将上面的等式改为下面的等式,

F(w_i — w_j,u_k) = P_ik/P_jk

为什么 w_i — w_j 适合这里?其实你可以在嵌入空间中推导出你观察到的关于 P_ik/P_jk 的美好性质。我来详细说明一下。

Behaviour of vector distances to a probe word w.r.t. w_i — w_j

所以你可以看到当考虑不同的单词时,距离(虚线)是如何变化的。以及两个给定词 ik 之间的距离,与 P_{ik} 的倒数相关。为什么会这样呢?因为我们总是计算距离 w.r.t 字向量 w_i — w_j (即红线)。所以从 w_i — w_j. 开始也未尝不可

向量到标量…

一个问题解决了,我们继续下一个问题。我们如何使 LHS 成为标量?对此有一个非常直接的答案。也就是用下面的方法在两个实体之间引入一个转置和一个点积。

*F((w_i — w_j)。u_k) = P_ik/P_jk 或者,

*如果假设一个字向量为一个 Dx1 矩阵, (w_i — w_j) 将被 1xD 整形,从而在与 u_k 相乘时给出一个标量。

F 能是什么?

接下来,如果我们假设 F 有某个性质(即 加法群和乘法群之间的同态 )给出

F(w _ I * u _ k—w _ j * u _ k)= F(w _ I * u _ k)/F(w _ j * u _ k)= P _ ik/P _ JK

换句话说,这种特殊的同态确保了减法【A-B】也可以表示为除法 F(A)/F(B) 并得到相同的结果。因此,****

F(w _ I * u _ k)/F(w _ j * u _ k)= P _ ik/P _ JK

F(w _ I * u _ k)= P _ ik

我对你耍了点小花招…

好吧,我是偷偷摸摸的。仅仅因为 F(A)/F(B) = G(A)/G(B)你不能说 F(A) = G(A)。因为 F(A)/F(B)=2F(A)/2F(B),不代表 F(A)=2F(A)。从最初的论文来看,并不清楚(至少对我来说)为什么这样假设。但是让我给你一些直觉,为什么这是一个安全的假设。如果我们要正确定义上述关系,它应该是,

F(w _ I * u _ k)= c P _ ik对于某些常数 c

但有了这个,你也得到了 F(w_j u_k) = c P_jk 对于任意的 j 。所以如果 ik 之间的相似度按 c 增长,那么 jk (对于任意一个jc之间的相似度也将按 增长。这意味着(在某种程度上)所有的单词向量将按系数 c 放大/缩小,这不会有任何损害,因为相对的拓扑被保留了。***

继续,如果我们假设 F=exp, 满足上述同态性质。那么让我们开始吧,

Exp(w _ I * u _ k)= P _ ik = X _ ik/X _ I

w _ I * u _ k = log(X _ ik)—log(X _ I)

接下来, X_i 独立于 k ,我们把 log(X_i) 移到 LHS,

w _ I * u _ k+log(X _ I)= log(X _ ik)

注意,如果没有项 log(X_i) ,即 ik 可以互换,则上述等式将具有对称性。我们可以添加一个 bias b_i 来吸收 log(X_i) 并添加另一个 b_k 来恢复对称性。所以,我们会有点创意,用神经网络的说法来表达 log(X_i)

w_i u_k + b_i +b_k= log(X_ik)*

或者,

w_i u_k + b_i +b_k — log(X_ik) = 0*

其中b _ Ib _ k是网络的偏差。**

定义成本

在一个理想的设置中,你有完美的词向量,上面的表达式将是零。换句话说,这就是我们的目标。所以我们将把 LHS 表达式作为我们的成本函数。

J(w_i,w _ J)=(w _ I * u _ J+b _ I+b _ J—log(X _ ij))

注意,平方使其成为均方成本函数。对最初的发现没有损害。k 也被 j 代替了。

最终成本函数

但是你的工作并没有到此为止,你还需要解决一个重要的理论问题。思考一下如果 X_ik = 0 会发生什么。如果你对上面的成本函数做一个小实验,你会看到一个 ML 从业者最讨厌的 3 个字母,即【NaN】。因为 log(0)未定义。简单的解决方法是使用被称为拉普拉斯平滑的 log(1+X_ik) 。但是手套纸背后的杰出人物提出了一种更时髦的方法。即引入一个加权函数。**

j = f(x_ij)(w_i^t u _ j+b _ I+b _ j—log(x _ ij))

其中f(x _ ij)=(x/x_{max})^aifx<x _ { max }else0******

结论

一切都结束了。GloVe 是一种利用语料库的全局和局部统计的词向量技术,以便提出使用这两者的原则性损失函数。GloVe 通过解决三个重要问题来做到这一点。

  • 我们没有方程,例如 F(i,j,k) = P_ik/P_jk ,只是一个表达式(即 P_ik/P_jk )。
  • 单词向量是高维向量,然而 P_ik/P_jk 是标量。所以存在维度不匹配。
  • 涉及三个实体( i,j ,和 k )。但是用三个元素计算损失函数可能会很麻烦,需要减少到两个。

提供了用 Keras 实现手套的代码【此处为】

如果你喜欢我分享的关于数据科学和机器学习的故事,考虑成为会员吧!

**** [## 通过我的推荐链接加入媒体

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

thushv89.medium.com](https://thushv89.medium.com/membership)****

想在深度网络和 TensorFlow 上做得更好?

检查我在这个课题上的工作。

[1] (书)TensorFlow 2 在行动——曼宁

[2] (视频教程)Python 中的机器翻译 — DataCamp

[3] (书)TensorFlow 中的自然语言处理 1 — Packt

新的!加入我的新 YouTube 频道

如果你渴望看到我关于各种机器学习/深度学习主题的视频,请确保加入 DeepLearningHero 。

参考:

[1] GloVe:单词表示的全局向量(原文

XGBOOST vs LightGBM:哪种算法赢得了比赛!!!

原文:https://towardsdatascience.com/lightgbm-vs-xgboost-which-algorithm-win-the-race-1ff7dd4917d?source=collection_archive---------3-----------------------

这篇文章是关于在人口普查收入数据集上对 LightGBM 和 XGBoost 进行基准测试。我注意到 XGBoost 的执行时间比 LightGBM 慢。下面我们来深挖更多细节,了解一下各种参数对比时哪个更胜一筹。

Photo by Tim Gouw on Unsplash

增压机的发展从 AdaBoost 开始,到今天被大肆炒作的 XGBOOST。XGBOOST 已经成为在 Kaggle 赢得比赛的事实上的算法,仅仅是因为它非常强大。但是考虑到大量的数据,即使 XGBOOST 也需要很长时间来训练。

来了…轻 GBM 入图。

Timeline

你们中的许多人可能对灯光渐变很熟悉,但是读完这篇文章后你会有一个坚实的理解。你会想到的最自然的问题是——为什么是另一个助推机器算法?比 XGBOOST 快吗?

嗯,你猜对了!!!在本文中,我们将通过一个例子来比较 Light GBM 和 XGBoost 及其性能。

本故事中要讨论的副主题:

  1. 什么是轻 GBM?
  2. 轻型 GBM 的优势
  3. 结构差异
  4. 了解参数
  5. 数据集上的实现
  6. 每种算法的性能
  7. 参数调整
  8. 结束注释

什么是轻 GBM?

Light GBM 是一个基于决策树算法的快速、分布式、高性能梯度提升框架,用于排序、分类和许多其他机器学习任务。

由于它是基于决策树算法的,所以它以最佳拟合的方式分裂树的叶子,而其他 boosting 算法以深度或级别方式分裂树,而不是以叶子方式。因此,当在轻量级 GBM 中生长在同一片叶子上时,逐叶算法可以比逐级算法减少更多的损失,从而导致更好的准确性,这是任何现有的 boosting 算法都很少能达到的。

之前是轻型 GBM 制造商的示意图,以清楚地解释差异。

轻型 GBM 的优势

  1. 更快的训练速度和更高的效率 : Light GBM 使用基于直方图的算法,即将连续的特征值放入离散的箱中,加快了训练过程。
  2. 更低的内存使用率:将连续值替换为离散值,从而降低内存使用率。
  3. 比任何其他 boosting 算法更高的准确性:它通过遵循逐叶分裂方法而不是逐层方法来生成更复杂的树,逐层方法是实现更高准确性的主要因素。但是,有时会导致过度拟合,这可以通过设置 max_depth 参数来避免。
  4. 与大型数据集的兼容性:与 XGBOOST 相比,它能够以显著减少的训练时间在大型数据集上表现得同样好。

LightGBM 和 XGBoost 的结构差异

LightGBM 使用一种新颖的基于梯度的单侧采样(GOSS)技术来过滤数据实例,以找到拆分值,而 XGBoost 使用预先排序的算法&基于直方图的算法来计算最佳拆分。这里的实例是观察/样本。

简而言之,基于直方图的算法将一个特征的所有数据点分割成离散的仓,并使用这些仓来找到直方图的分割值。虽然它在训练速度上比列举预排序特征值上所有可能的分裂点的预排序算法更有效,但是在速度上它仍然落后于 GOSS。

那么是什么让这种高斯方法变得高效呢?
GOSS(Gradient Based One Side Sampling)是一种基于梯度对实例进行下采样的新型采样方法。正如我们所知,梯度小的实例训练良好(训练误差小),梯度大的实例训练不足。一种简单的下采样方法是通过只关注具有大梯度的实例来丢弃具有小梯度的实例,但是这将改变数据分布。简而言之,GOSS 保留具有大梯度的实例,同时对具有小梯度的实例执行随机采样。

轻型 GBM 的重要参数:

*num_leaves*:要使用的叶节点数。拥有大量的叶片会提高精度,但也会导致过度拟合。

*min_child_samples*:分组到一个叶中的样本(数据)的最小数量。该参数可以大大有助于过度拟合:每片叶子较大的样本大小将减少过度拟合(但可能导致欠拟合)。

*max_depth*:明确控制树的深度。较浅的树减少过度拟合。

不平衡数据的调优

说明不平衡或偏斜数据的最简单方法是增加正面类别示例的权重:

*scale_pos_weight*:可以根据正反例的数量计算权重:*sample_pos_weight = number of negative samples / number of positive samples*

过拟合调谐

除了上述参数之外,以下参数可用于控制过度拟合:

*max_bin*:存放特征值的最大箱数。较小的*max_bin*减少了过度配合。

*min_child_weight*:一片叶子的最小和麻。结合*min_child_samples,*,较大的值可减少过度拟合。

*bagging_fraction**bagging_freq*:对训练数据进行打包(子采样)。这两个值都需要设置,以便装袋使用。频率控制使用(迭代)装袋的频率。较小的分数和频率减少了过度拟合。

*feature_fraction*:控制用于训练的特征的二次抽样(与装袋情况下对实际训练数据的二次抽样相反)。较小的分数减少了过度拟合。

*lambda_l1**lambda_l2*:控制 L1 和 L2 的正规化。

精确调谐

通过调整以下参数可以提高精度:

*max_bin*:较大的*max_bin*增加精度。

*learning_rate*:使用较小的学习率,增加迭代次数,可能会提高精度。

*num_leaves*:增加叶片数可以提高精度,但过度拟合的风险很高。

XGBoost 的重要参数:

XGBoost 作者将总体参数分为 3 类:

  1. 通用参数:引导整体运行
  2. 助推器参数:在每一步引导单个助推器(树/回归)
  3. 学习任务参数:指导优化执行

一般参数

这些定义了 XGBoost 的整体功能。

1。booster [default=gbtree]

选择每次迭代运行的模型类型。它有两个选项:

gbtree:基于树的模型

gblinear:线性模型

2。无声[默认值=0]:

静音模式激活设置为 1,即不打印任何运行消息。

通常最好保持为 0,因为这些消息可能有助于理解模型。

3。n thread[如果未设置,则默认为最大可用线程数]

这用于并行处理,应输入系统中的内核数量

如果您希望在所有内核上运行,则不应输入值,算法将自动检测。

助推器参数

虽然有两种类型的助推器,我在这里只考虑树助推器,因为它总是优于线性助推器,因此后者很少使用。

1。eta[默认值=0.3]

类似于 GBM 中的学习率

通过缩小每一步的权重,使模型更加健壮

要使用的典型最终值:0.01–0.2

2。最小 _ 子 _ 体重[默认值=1]

定义子代中所需的所有观察的最小权重和。

这类似于 GBM 中的 min_child_leaf ,但不完全相同。这是指观察值的最小“权重和”,而 GBM 具有最小“观察值数”。

用于控制过度拟合。较高的值会阻止模型学习可能高度特定于为树选择的特定样本的关系。

过高的值会导致拟合不足,因此应该使用 CV 进行调整。

3。max_depth [default=6]

树的最大深度,与 GBM 相同。

用于控制过度拟合,因为较高的深度将允许模型学习特定样本的特定关系。

应使用 CV 进行调整。

典型值:3–10

4。max_leaf_nodes

树中的最大终端节点或叶子数。

可以代替 max_depth 进行定义。由于二叉树被创建,深度“n”将产生最大的 2^n 叶。

如果这样定义,GBM 将忽略 max_depth。

5。伽玛[默认值=0]

只有当产生的分裂给出损失函数的正减少时,节点才被分裂。Gamma 指定进行分割所需的最小损失减少量。

使算法保守。这些值可能因损失函数而异,应该进行调整。

6。max _ delta _ step[默认值=0]

在最大增量步骤中,我们允许每棵树的重量估计为。如果该值设置为 0,则表示没有约束。如果将其设置为正值,则有助于使更新步骤更加保守。

通常,这个参数是不需要的,但是当类别极度不平衡时,它可能有助于逻辑回归。

这通常不被使用,但是如果你愿意,你可以进一步探索。

7。子样本[默认值=1]

同 GBM 子样本。表示每棵树随机抽样的观察分数。

较低的值使算法更加保守,并防止过度拟合,但太小的值可能会导致拟合不足。

典型值:0.5–1

8。λ[默认值=1]

关于权重的 L2 正则化项(类似于岭回归)

这用于处理 XGBoost 的正则化部分。虽然许多数据科学家不经常使用它,但应该探索它以减少过度拟合。

9。alpha[默认值=0]

权重上的 L1 正则化项(类似于套索回归)

可以在非常高的维数的情况下使用,使得算法在实现时运行得更快

10。scale _ pos _ weight[default = 1]

在高等级不平衡的情况下,应该使用大于 0 的值,因为它有助于更快收敛

学习任务参数

这些参数用于定义每一步要计算的指标的优化目标。

  1. 目标[default=reg:linear]

这定义了要最小化的损失函数。最常用的值有:

二进制:逻辑回归–二进制分类的逻辑回归,返回预测概率(非类别)

multi:softmax–使用 soft max 目标的多类分类,返回预测的类(不是概率)

multi:soft prob–与 softmax 相同,但返回属于每个类别的每个数据点的预测概率。

2。eval_metric [根据目标的默认值]

  • 用于验证数据的指标。
  • 对于回归,默认值为 rmse,对于分类,默认值为 error。
  • 典型值包括:

rmse —均方根误差

mae —平均绝对误差

对数损失 —负对数可能性

错误 —二值分类错误率(0.5 阈值)

误差 —多类分类误差率

mlogloss —多类 logloss

auc: 曲线下面积。

数据集上的实现:

现在让我们比较 LightGBM 和 XGBoost,将这两种算法应用于人口普查收入数据集,然后比较它们的性能。

Dataset Information

Loading the data

Data Description

在上面的数据集上运行 Light GBM 和 XGboost 之后。结果是:

Evaluation metrics: Accuracy, auc_score & execution time (Model 1)

Evaluation metrics: Accuracy, rsme_score & execution time (Model 2)

与 LightGBM 相比,XGBoost 在准确性、AUC 评分和 rsme 评分方面仅略有增加,但在训练程序的执行时间方面存在显著差异。与 XGBOOST 相比,Light GBM 非常快,并且在处理大型数据集时是一种更好的方法。

当你在有限时间的比赛中处理大型数据集时,这是一个巨大的优势。

参数调整:

对于 XGBOOST

这些是为模型 1 设置的参数:

Parameters for XGBoost — Model 1

模型 1 的精确度:

这些是模型 2 的参数:正在调整参数。

Parameters Tuning for XGBoost — Model 2

模型 2 的精确度:

正如我们可以看到的,随着参数的调整,我们的模型的准确性几乎没有增加。

对于 LightGBM:

这些是为模型 1 设置的参数:

Parameters for LightGBM — Model 1

模型 1 的精确度:

这些是模型 2 的参数:正在调整参数。

Parameters for LightGBM — Model 2

模型 2 的精确度:

正如我们可以看到的,随着参数的调整,我们的模型的准确性几乎没有增加。

结束注释

在本文中,我试图比较 Light GBM 和 XGBoost 的性能。使用这种 LightGBM 的一个缺点是用户基础狭窄——但这种情况正在迅速改变。这种算法除了比 XGBOOST 更精确、更省时之外,由于可用的文档较少,它的使用受到了限制。然而,该算法已经显示出好得多的结果,并且已经胜过现有的提升算法。

您可以在我的 GitHub 资源库中找到完整的代码。

[## nikhileshorg/light GBM-vs-XGBoost

在 GitHub 上创建一个帐户,为 Nikhileshorg/light GBM-vs-XGBoost 开发做出贡献。

github.com](https://github.com/Nikhileshorg/LightGBM-vs-XGBoost)

关于 LightGBM,XGBoost 或者与本帖相关的有什么问题吗?留下评论,提出你的问题,我会尽力回答。

感谢阅读!❤

不平衡数据集中焦点损失的 LightGBM

原文:https://towardsdatascience.com/lightgbm-with-the-focal-loss-for-imbalanced-datasets-9836a9ae00ca?source=collection_archive---------3-----------------------

焦损失(以下简称 FL)是由宗-林逸等人在他们 2018 年的论文“密集物体探测的焦损失” [1]中引入的。它被设计成解决具有极端不平衡类别的情况,例如前景和背景类别之间的不平衡可以是例如 1:1000 的一阶段对象检测。

在这篇文章中,我将展示如何为light GBM【2】(以下简称 LGB)编写 FL,并演示如何使用它。配套的 github repo 可以在这里找到。不幸的是,我找不到公开的真正具有挑战性的不平衡数据集。python 中的不平衡学习 [3]包附带的数据集相对容易,LGB 不需要任何技术来处理不平衡数据集就能产生良好的结果。另一个选择是 Kaggle 的信用卡欺诈检测数据集。然而,这也是一个非常容易的数据集,LGB 产生了非常好的结果“开箱即用”。

尽管如此,因为这篇文章的目标是展示 LGB 的 FL 代码以及如何使用它,所以我简单地挑选了两个众所周知的数据集,然后继续。这些是成人普查数据集和已经提到的信用卡欺诈检测数据集。

我们需要遵循这个代码中的代码的小数学是这个帖子可以写成如下。考虑二元分类问题,我们可以将 p_t 定义为:

Eq 1 (Eq 2 in Tsung-Yi Lin et al., 2018 paper)

其中,y ∈ { ∓ 1}指定地面实况类,p ∈ [0,1]是标注 y = 1 的类的模型估计概率。那么交叉熵可以写成:

Eq2. Binary Cross Entropy

根据该公式,焦点损失定义为:

Eq3 (Eq 5 in their paper)

让我们看看它的行为,如图 1 所示。

Figure 1 (Figure 1 in their paper). The figure shows the Focal Loss plotted against pt. Note that for γ=0 the FL is equal to the CE. We can see that the factor (1 − pt) γo the standard cross entropy criterion. Setting γ > 0 reduces the relative loss for well-classified examples (pt > .5).

正如我们在图中看到的,设置γ > 0 减少了分类良好的例子的相对损失(pt > .5),把更多的注意力放在困难的、错误分类的例子上。引用作者的话:“当γ = 2 时,与 CE 相比,pt = 0.9 的示例的损耗低 100 倍,pt ≈ 0.968 的示例的损耗低 1000 倍”。

这就是我们现在需要的所有数学知识。

光焦度损失

使用 LGB 时,为了编写您自己的损失函数,您需要损失数学表达式及其梯度和 hessian(即一阶和二阶导数)。光 GBM焦损可以简单编码为:

Focal Loss implementation to be used with LightGBM

如果只有一段代码可以从这篇文章中“拯救”出来,那就是上面的代码片段。

如果你要将 FL 和 LGB 一起使用,你可能需要编写相应的评估函数。在这种情况下,该函数需要返回名称、目标函数的值以及一个布尔值,该值指示值越高越好:

Evaluation Focal Loss function to be used with LightGBM

例如,如果不使用 F1 作为目标函数,您更喜欢 F1 分数这样的指标,您可以使用以下代码:

f1 score with custom loss (Focal Loss in this case)

注意第 2 行中的 sigmoid 函数。这是因为当使用您自己的损失函数时,直接来自算法的原始预测不会通过 sigmoid 来表示概率。

要将 FL 与 LGB 一起用于训练,只需:

How to use the Focal Loss for training with LightGBM

或者通过 F1 分数和交叉验证:

How to use the Focal Loss for LightGBM with cv and F1 as the evaluation metric

结果

如前所述,我使用了两个数据集,人口普查数据集和信用卡欺诈检测数据集。对于每个数据集,我运行两个实验:1)使用设置为Trueis_unbalance参数(如果少数类是正类,这相当于使用scale_pos_weight)和 2)使用 FL。我使用 Hyperopt 进行超参数优化,针对 F1 分数进行优化,每个实验运行 100 次迭代,每次迭代都进行交叉验证(3 次,即每个实验 300 次拟合)。我根本没有使用过/欠采样。本文引用的所有代码都可以在这里找到。

Table 1. Performance metrics for the experiments run in this post with and without Focal Loss

结果如表 1 所示。需要强调的是,正如本文前面提到的, 这两个数据集都不适合这里的 练习。事实上,成人人口普查数据甚至没有不平衡。因此,先验地,人们不会期望在有和没有 FL 的情况下获得的度量之间有大的变化。然而,表中的结果说明了 FL 的潜力。例如,两个数据集的 F1 分数都增加了 2%。此外,在信用卡欺诈检测数据集的情况下,所有的 F1、精度召回提高了 2%或更多。

对此,我可以补充一点,我已经在几个真实数据集和相关的改进中使用了 FL,在不平衡率为 2:100 的数据集上,所有性能指标都一致提高了约 5%。我的一些同事告诉我,他们看到了更大的改善。

为了结束这一部分,让我们来看看聚焦损耗中的α和γ参数:

Table 2. Focal loss α and γ parameters

较高的γ值将较大地减少分类良好的样本的相对损失,将更多的注意力放在难以分类的样本上。因此,这些结果可以解释如下。成人数据集虽然不是不平衡的,但对于算法来说,它比信用卡欺诈数据集【更具挑战性】。为了获得最好的 F1 分数,我们需要较大的γ值,将大量的“焦点放在硬的、错误分类的样本上。

**is_unbalance**参数****

到目前为止,当使用 FL 时,我已经将is_unbalance 参数设置为False. ,注意也可以同时使用 FL 和is_unbalance=True。为了理解使用两者的含义,让我们首先假设树集成方法的目标函数的一般形式:

Eq 4. This is actually Eq 3 in Tianqi Chen & Carlos Guestrin 2016 XGBoost paper [4].

其中 f _t 是树在第 t 次迭代时的函数, gh 分别是梯度和 Hessian。

如果我们看一下 c++代码的这里的,我们可以看到设置is_unbalance = True仅仅意味着,当计算损失时,少数类的标签权重将是两个类之间的比率(count _ majority/count _ minority)。如果我们再看这里的,在 sklearns API 中,我们看到在计算目标函数时,这些权重直接乘以梯度和 Hessian。

现在假设我们有一个不平衡比率为 1:9 的数据集,我们取两个样本,一个正(少数)样本和一个负(多数)样本,预测概率 p=0.9。现在假设α和γ分别为 1.0 和 2.0。如前所述,在这种情况下,FL 中的因子α(1-p)^γ会将这两个样本的相应损耗值减少 100 倍。换句话说,FL 试图把重点放在更难的、错误分类的样本上。

假设,为了计算目标,LGB 使用类似于等式 3 的表达式,并且我们设置is_unbalanced=True, 相应的梯度和焦点损失的 Hessian 将仅对于正(少数)样本乘以因子 9。换句话说,设置is_unbalanced=True将增加少数类样本对目标的贡献,而不管它们是否被很好地分类。

因此,在我看来,焦点损失和is_unbalance=True对于分类良好且属于少数类的样本是竞争效应。尽管如此,我已经使用 FL 和设置is_unbalance=True对 2 个数据集进行了实验,结果与表 1 中的几乎相同。

替代方法

在这篇文章中,我只是想展示如何为 LGB 编写 FL 并演示如何使用它。然而,让我简单地提一下我在这里没有探讨的一些替代技术。

使用 LGB 时,您可以直接传递与每个观察相关的权重。这也是一个值得你公司探索的好方法。也许你有一些启发,或使用一些无监督的技术,导致你的结论是,一些样本比其他的更重要。在这种情况下,您可以考虑为每个观察传递一个权重来反映这一先验知识。这可以通过简单地使用lightgbm.Dataset类中的参数weight 来实现。使用 FL 或使用weight参数都被称为成本敏感学习技术。

另一种技术是重新采样。正如我提到的,我没有使用任何欠采样/过采样。如果你想探索重采样技术,你可以在著名的 python 包 unbalanced-learn 中找到相当全面的资料。另一种我觉得特别有趣的更近期、更有前途的欠采样技术在 Ehsan Montahaei 等人 2018[5]中讨论过,如果你想更深入地了解重采样技术的话。

仅此而已。有什么想法,在这里评论或者发邮件给我:jrzaurin@gmail.com

参考资料:

[1]宗-林逸,普里亚·戈亚尔,罗斯·吉斯克等人,2018: 密集物体探测的焦损失arXiv:1708.02002 v2

[2]郭林·柯,,托马斯·芬利等,2017: LightGBM: 一种高效的梯度推进决策树

[3]纪尧姆·勒迈特,费尔南多·诺盖拉,克里斯特斯·k·阿里达斯 2017:不平衡学习:一个 Python 工具箱,解决机器学习中不平衡数据集的诅咒。

[4]陈天琦,Carlos Guestrin 2016: XGBoost:一个可扩展的树提升系统。arXiv:1603.02754 v3

[5] Ehsan Montahaei,Mahsa Ghorbani,Mahdieh Soleymani Baghshah,Hamid R. Rabiee 2018:不平衡问题的对抗性分类器。arXiv:1811.08812 v1

莱姆:解释机器学习模型的预测(1/2)

原文:https://towardsdatascience.com/lime-explaining-predictions-of-machine-learning-models-1-2-1802d56addf9?source=collection_archive---------17-----------------------

在我之前的博客中,我提到了以下理解模型预测的基本技术。

Photo by Alex Bertha on Unsplash

  1. 使用基尼指数的特征重要性
  2. 使用排列重要性的特征重要性
  3. 部分相关图

首先,我想问一个问题:“我们可以仅仅因为模型在测试数据上的表现令人信服地高,就相信模型的预测吗?”许多人可能会回答这个问题为【是的】。但这并不总是正确的。高模型性能不应被视为信任模型预测的指标,因为模型拾取的信号可能是随机的,可能没有商业意义。

在这篇博客中,我将谈论 LIME,一种在实例层面上帮助理解预测背后的原因的方法。这是一种与模型无关的技术,也就是说,你可以将它用于任何模型,无论是神经网络、基于树的模型、支持向量机等等。

LIME 代表LocalIn interpretableModel-AgnosticE解释。对许多人来说,本地这个词似乎是最令人困惑的。所以我先来解释一下为什么这个词本地

目标和自变量之间的关系在全局水平上可能变得非常复杂,例如参考下图。查看这个全局视图并不能提供太多关于独立特征和目标之间关系的洞察,所以 LIME 放大在非常非常局部的水平上进行。

让我们假设被解释的实例用绿色星号标记。LIME 背后的主要直觉是,在放大和局部分析目标和独立特征之间的关系之后,我们可以使用线性模型来近似这种关系。

现在,让我们了解石灰的工作步骤:

  • 对原始数据中靠近绿色星号的实例进行采样和 SMOTE 处理(正在解释实例)
  • 计算采样实例和被解释实例之间的距离
  • 对于这些合成生成的实例,使用原始全局模型进行预测
  • 对此数据集拟合一个简单的线性模型
  • 基于在步骤 2 中计算的相似性指数对该线性模型进行加权。这是为了确保最接近原始实例的实例上的错误比其他实例更有价值

现在让我们进入例子来解释石灰的结果。我已经使用了来自 Kaggle 的数据集。目标是确定拖欠信用卡付款的最强预测因素。我安装了一个 Scikit-learn 实现的梯度增强树。

Correctly classified *‘Non Default Payment’* instance:

橙色表示贡献给‘违约金’,蓝色表示贡献给‘非违约金’。全局模型对此实例的预测是 0.072,而局部模型的预测是 0.066。所以,对于这个特殊的例子,全局模型和局部模型的预测非常接近。

上面的例子表明,这个被标记为‘非违约付款’的特定实例的主要贡献者是上个月的还款状态( PAY_0 = 1 )。这意味着在前一个月付款是按时完成的。其他变量的解释也类似( PAY_2,PAY_3 等)。).这表明,如果前几个月的付款按时完成,那么这个人下个月不违约的可能性很高。

LIMIT_BAL 的高金额也促成了非违约付款。这也是有意义的,因为高 LIMIT_BAL 意味着剩余补充信用低。因此,下个月的账单有可能会很低,因此违约的几率会更小。现在,对于连续要素,LIME 的输出提供了更多详细信息,因为它指定了导致该要素产生影响的一系列特征值。例如'限额 _ 余额> 24 万'

我个人认为分析错误预测的实例是非常有见地的。这有助于理解哪些特征实际上导致了预测不正确。

Incorrectly classified *‘Non Default Payment’* instance (Actual: *‘Default Payment’*):

由于表示先前付款历史的特征( PAY_0PAY_2PAY_3 ),上述实例被错误地预测为非违约付款。在这种情况下,以前的付款是按时完成的。这可能使预测变得不正确。

根据上面的例子,石灰的一般概念听起来是合理的,但是石灰也有一些潜在的缺点。

**1\. Local linear behavior**

LIME 目前在本地实现线性模型来获得解释。而这种假设对于正在解释的实例周围的小区域是有效的。但是对于更复杂的数据集,随着我们增加局部区域的面积,这个假设可能不成立。因此,来自局部可解释模型的解释可能无法解释全局线性模型的行为。

**2\. Number of features**

需要优化选择用于解释的特征的数量。应该选择特征的数量,以便保持模型的复杂性和解释的简单性。在 LIME 的 python 实现中,它提供了以下选项:‘forward _ selection’,‘lasso _ path’,‘none’或‘auto’

**3\. Models without probability scores**

LIME 目前不支持没有概率分数的分类器模型。

**4\. No aggregated view**

LIME 实现不提供特性解释的聚合视图。用户必须依次分析各个实例。

**5\. Similarity score**

对于表格数据,LIME 通过单独扰动每个要素来创建新样本,从正态分布中提取该要素的平均值和标准差。对于连续特征,LIME 提供了一个选项,用于从以被解释的实例为中心的法线或从以特征数据集的平均值为中心的法线扰动样本。越靠近感兴趣的实例,样本的石灰权重越高。现在,在高维空间中,每个特征具有不同范围的值,计算相似性指数具有挑战性,并且可能不会产生清晰的结果。

**6\. Definition of the neighborhood**

定义一个正确的邻域来运行局部可解释模型是一个困难的问题。那么,为什么我们需要沿着被解释的实例定义一个局部邻域呢?解释模型对原始模型的准确性是通过在由局部核加权的简化输入空间中的一组样本上的损失函数来加强的。目前,LIME 使用指数平滑内核。这个内核的宽度决定了对正在解释的实例的局部模型的影响,同样,没有确定内核宽度的最佳方法。

**7\. Consistency of the model explanations**

由于采样偏差、相似性得分的计算和邻域的定义,石灰解释有时可能缺乏一致性。

结论:

LIME 提供了非常简单的可解释的解释,并且是分析每个特征的贡献的快速方法。LIME 也可以用于文本和图像数据,与其他可解释的技术(如 SHAP)相比,LIME 的执行时间更少。我喜欢 LIME 的另一个特性是,局部代理模型实际上可以使用独立的特性,而不是全局模型中使用的特性。

其他阅读资源:

  1. https://www . KDD . org/KDD 2016/papers/files/RFP 0573-ribeiroa . pdf
  2. 【https://github.com/marcotcr/lime
  3. https://christophm . github . io/interpretable-ml-book/lime . html

下一步是什么?

在下一篇博客中,我将解释另一种流行的技术:用于解释模型预测的 SHAP。

这个可解释的人工智能领域正在迅速发展,在工具和框架方面有很多新的发展。请在评论区写下你对博客的反馈,以及你在这个领域使用的最新工具。此外,如果你想让我写任何特定的主题,请发表评论。

这些内容最初发表在我的个人博客网站:http://datascienceninja.com/。点击此处查看并订阅即时接收最新博客更新。

Limericking 第 1 部分:背景和俳句。

原文:https://towardsdatascience.com/limericking-part-1-context-and-haikus-3eb057c8154f?source=collection_archive---------23-----------------------

石灰工程

使用自然语言处理产生诗歌

Watson: Jeopardy champ and future poet laureate?

机器学习和数据科学中最令人兴奋的领域之一是自然语言处理。让一台机器能够解析并生成听起来像人类的语言,这既有巨大的实用价值,也是众所周知的困难。人类的语言是混乱的,充满了计算机无法处理的那种不规则性。即使是相对简单的任务,比如标记一个给定单词的词性,也可能很难,并且依赖于上下文(permit 是名词还是动词?).

即使是最强大、最成功的 NLP 实现也会让人感觉有些不舒服。我仍然非常清楚地记得观看 IBM 的沃森与全明星肯·詹宁斯和布拉德·鲁特一起玩 Jeopardy。沃森的表现确实令人印象深刻,在两天的比赛中,沃森最终轻松获胜,但有时它感觉机器并没有真正执行它被设计来做的任务——正确解释自然语言——一点也不出色。在一场最后的危险游戏中,沃森在“美国城市”类别中找不到正确答案,他猜是多伦多:

如果沃森真的能够理解这项任务,它大概至少会猜对一个国家的城市,尽管我不完全相信它不是在故意开玩笑。我还记得在常规播放中的一个线索,询问了甲壳虫乐队的歌曲“挥舞银锤”的名字麦克斯韦尔,沃森回答了整个短语“麦克斯韦尔的银锤”。他们给沃森的回答加分,但也许他们不应该这样。沃森可以建立足够的联系来判断线索在问哪首歌,但不知道线索实际上在问什么。

这一切只是为了重申自然语言处理是辛苦的!将维基百科的全部内容输入一台最先进的超级计算机是很容易的。即使是最先进的超级计算机也能理解基本英语,这需要极大的创造力。

我对计算机生成文本的能力特别感兴趣。沃森相对容易,因为危险反应遵循严格的模式。让计算机生成更长更复杂的段落,尤其是那些需要恰当的变化和一致的段落,怎么样?在这篇文章中,也可能在未来的一系列文章中,我想探索如何生成这样的文本,着眼于创作热门打油诗。

这篇文章的灵感来自 twitter 账户 Limericking 。打油诗背后的匿名天才在新闻报道后写打油诗。出于我无法完全说清楚的原因,我认为利默瑞金的打油诗中最好的确实非常出色,是我所知道的最好的现代诗歌中的一些:

A brilliant limerick about rising tensions with Iran

我一直在考虑将 Limericking 的输出自动化的所有事情。你能输入一篇新闻文章,让计算机产生一首热门打油诗吗?其他尝试产生像这样的样式化文本的方法是使用递归神经网络,该网络在输入语料库上被训练,它们将试图模仿该输入语料库。例如,这位数据科学家用莎士比亚训练了一个 RNN,在超过 19 个小时的大约 35000 个训练步骤之后,计算机产生了这个文本片段:

泰特斯·安德洛尼克斯:

现在,我的安全和死亡是什么?

国王理查德二世:

你认为会有什么结果?

这是什么?

结果是非常令人印象深刻的,完全缺乏。这篇课文无疑是莎士比亚的,但毫无意义。这种不直接的方式擅长模仿风格,但不擅长产生“意义”。你可以想象用足够多的打油诗来训练 RNN,让它对格式有所了解,但是这个网络需要有多深才能创造出清晰的内容呢?或者让它把新闻文本处理成一首易读的摘要打油诗?

直觉上,更好的过程应该更程序化。您可以想象一个函数或一系列函数按顺序执行以下步骤:

  1. 分析新闻文本的含义,提取关键词或中心人物
  2. 用两三句话总结一下
  3. 搜索同义词库和押韵词典,找到符合押韵方案的备选单词
  4. 重新调整新的押韵句子,以正确扫描打油诗的形式。

问题是,每一个步骤本身都是一个棘手的数据科学问题。第一步:阅读文本,找到主题或中心人物。计算机如何知道如何将文本分配给特定主题?通常,这可以通过类似于朴素贝叶斯分类器的东西来完成,该分类器查看任何给定主题中特定单词的频率(例如,包含单词“gigabyte”的文本更可能来自关于技术的文章,而提到联合国的文章更可能是关于世界事务的)。这需要一个大的、标记良好的数据集来训练你的模型,这意味着,像许多大数据问题一样,这不仅仅是一个数据科学问题,也是一个数据生产问题。(也有无人监督的文本聚类方法,尽管让计算机决定分组方式会有风险)。

也许,你认为,有一个更简单的方法。你可能会稍微欺骗一下,认为一篇文章的主题会用一个在文章中相对频繁出现的名字或名词来表示。通过将文本中最常出现的专有名词集合起来,并猜测其中一个是主题,你会比随机选择做得更好。这本身也是一个复杂的分类问题,因为虽然计算机很容易计算实例,但计算机很难区分什么是专有名词。

幸运的是,如果你像我一样,突然对打油诗产生了热情,想要一头扎进去,那么大量的资源已经存在了。自然语言工具包( NLTK )是一个强大的 Python 文本操作和分析工具库,除了许多其他东西之外,它还包含一个已经相当不错的词性标记器(如果您认为自己可以做得更好,还可以使用其他工具来构建自己的标记器)。在一系列的文章中,我想探究解析和产生文本的每一项任务,看看我是否能慢慢地建立起类似自动缩词法的功能。

为此,我决定从简单开始。而不是从头开始构建必要的工具,而是开始使用 NLTK 自带的一些工具,并致力于产生一种更简单的文本类型。与其写一首带有韵律和语法要求的打油诗,不如写一首只需要韵律的俳句。鉴于俳句如此简短,当它们是印象式的时侯,似乎效果最好,所以没有必要太关注语法。正如比利·穆雷告诉我们的,如果俳句没有意义也没关系:

以下是我的入门俳句生成器的工作原理:

  1. 它接受一个来自 NPR 的新闻文章的 id 号。为什么是 NPR?因为他们有一个非常方便的纯文本版本的网站,这应该是一个练习语言处理而不是网络抓取
  2. 检索文本并对其进行“标记”——将其转换为机器可以逐段评估的单词列表
  3. 通过为每个文本标记词性并查看最常出现的专有名词,尝试确定文本的主题——这实际上非常有效。(我的函数还通过查看文本的二元模型来检查专有名词是否是名称的一部分,也就是说,作为一个集合紧挨着出现的一组单词,并将返回完整的名称。)
  4. 它通过从集合中移除“停用词”——像“a”、“the”、“is”等常见词——并收集形容词、名词和动名词(再次感谢 NLTK 词性标记器)来收集要使用的词
  5. 单词的语料库被“词条化”——像那些标记复数的屈折词尾被删除
  6. 然后它组合俳句:如果少于 5 个音节,它将主题放在第一行,如果有 6 或 7 个音节,它将主题放在第二行。然后,它用从语料库中随机抽取的词来填充俳句的其余部分,但倾向于在文本中出现频率更高的词。

这个简单的程序产生了一些令人惊讶的暗示性结果,这证明了语言的灵活性和人类思维的创造性暗示性。鉴于这篇文章关于亚马逊考虑使用送货无人机提供家庭监控,它正确地收集了这篇文章的主题是“亚马逊”,并创作了这首俳句:

亚马逊报告

计划监督部

无人机安全

这种方式触及了问题的核心,而且看起来像人类。事实上,我认为只要在“plan”这个词后面加上一个“s ”,结果看起来甚至会合乎语法。鉴于这篇关于埃尔多拉多度假村收购凯撒赌场名气的文章,结果不太令人信服,但也不可怕:

投机运动

凯撒娱乐新闻

品牌公司名称

当然,形体短小,印象深刻的时候很容易显得印象深刻。即使是一首不太好的打油诗,要写出更长、更符合语法的作品也要困难得多。

Limericking 第 2 部分:用 LDA 进行主题建模

原文:https://towardsdatascience.com/limericking-part-2-topic-modeling-with-lda-45476ab9af15?source=collection_archive---------27-----------------------

石灰工程

没有监督的情况下找话题

欢迎来到我构建自动打油诗生成器的第 2 部分。正如我在第 1 部分中详述的,我受到了令人难以置信的 twitter 账户 Limericking 的启发,该账户根据新闻事件制作热门打油诗。我发现我更喜欢阅读打油诗形式的新闻;这些天的新闻是如此沉闷,以至于我发现越来越难以任何其他方式阅读新闻。

Why contemplate concentration camps on the border without a poem at Mike Pence’s expense?

不幸的是,Limericking twitter 帐户背后的孤独天才只能产生这么多。毕竟,每首诗都必须根据节拍、韵律和喜剧性来精心制作,所以 Limericking 每周只创作几首诗也就不足为奇了。我赞扬该账户对质量的奉献,并拒绝出版任何不到一个辉煌的打油诗,但我哀叹内容的匮乏。有没有一种方法可以自动化主题五行打油诗的制作过程(从而让我在继续阅读轻松诗的同时也能合理地了解时事)?

也许有,但不幸的是,首先需要解决一系列棘手的数据科学问题。我们的打油诗生成器需要能够接收文本并解析其含义,得出一两个总结句子(或至少一个主题和关键词/数字),然后生成有意义的文本,这些文本经过调整以适应打油诗的形式,而不会失去其连贯性。我想最重要的是,你会希望打油诗是幽默的,尽管这可能超出了我的能力。

为了支持我的第一篇文章,我把这个任务分解了,最后得到了一系列基于新闻文章的俳句。我的程序试图通过查看文本中最常出现的专有名词来确定文本的主题(这种策略通常会产生合理的结果),但在其他情况下会半随机地将单词放入俳句中:选择单词的概率由该单词在文本中出现的频率来加权。改进该计划的第一步是什么?limerick 生成器需要采取的第一步是解析文本的含义,所以这篇文章的主题是主题建模,特别是一种叫做潜在 Dirichlet 分配的方法。

主题建模本质上是一个复杂的分类问题,它提出了两个挑战。首先,虽然计算机可以对文本做一些事情,比如计算字数,但文本信息对计算机来说并没有内在的意义。人类在文本中看到的意义既有单个单词的层面,也有来自句法和句子中单词之间关系的更高层次(“猫咬了狗”和“狗咬了猫”的意思非常不同,尽管都是相同的单词)。这些意义的形式对计算机来说是困难的;第一个原因是单词的意思从定义上来说是抽象的,是基于人类的语境,第二个原因是人类语言的语法结构复杂得令人难以置信。

有一些自然语言处理的方法完全避免了意义,但仍然可以获得强有力的结果。所谓的“单词袋”模型忽略了所有的语法或词序,只是将文本表示为单词的集合,然后可以进行概率比较。像朴素贝叶斯分类器这样的概率模型查看不同单词在不同上下文中出现的相对频率。在主题检测用例中,您可以想象特定领域的词汇在一些主题中比在其他主题中使用得更多:技术文章可能有技术词汇,如“处理器”或“千兆字节”,而政治文章可能有政治词汇,如“选举”或“勾结”。假设你有一个标记良好且足够大的数据集,这样的模型可能非常强大,即使是在相对微妙的问题上:一个训练有素的贝叶斯分类器可以以 98%的准确率区分合法的新闻故事和来自洋葱等来源的讽刺文章。

不幸的是,这给我们带来了第二个挑战,数据标注。为了训练一个分类器,你需要一个训练数据集,这个数据集已经被很好地标记,并被分成适当的组。对于讽刺分类器这样的东西来说,这不会是一个挑战——任何来自洋葱这样的来源的东西都将是讽刺,而任何来自路透社的东西都不是,所以数据几乎被默认标记。对于像主题这样的东西,就有点难了,特别是当文章被发布它们的新闻机构标记为不同的主题部分时,不同的组织可能使用不同的分类方案。例如,想象一下“政治”新闻和“国际”栏目中的英国退出欧盟新闻之间的区别。

手动标注一大堆新闻文章会非常麻烦。幸运的是,也有无监督的主题建模方法,包括潜在的狄利克雷分配,不需要良好标记的训练数据。LDA 和类似的方法可能更好地称为“主题聚类”,而不是主题建模。使用 LDA 的计算机不能准确地“命名”一个主题,它不能接受一篇文章并明确地说它来自报纸的艺术部分。毕竟,我们考虑使用 LDA 的全部原因是它不需要预先标记的数据,所以计算机无法知道它收到的文章来自艺术部分。

相反,LDA 和类似方法试图做的是将文章组合在一起,返回未命名的“主题”,代表它认为相似的文章簇。希望该模型将艺术部分的文章分组在一起,而不需要被告知哪些文章在艺术部分开始。这种方法的两个怪癖是:a)计算机不会,也不能直接返回它所找到的群体的可解释信息(这需要人工干预), b)没有真正的方法来验证它所识别的群体,因为它是以一种无人监督的方式找到这些群体的。

LDA 是一个“单词包”模型,因为它将每个文档或文本视为本质上只是一个没有任何语法或词序的单词集合。它基本上将“主题”概念化为单词的概率分布,将单个文档/文本概念化为主题的概率分布。在这个视图中,任何给定的文本本质上都是通过从某些主题中随机抽取单词来生成的。一个带有 LDA 功能的统计软件包(比如我使用的 scikit learn 的)试图在给定文本数据集和一些预期主题的情况下,找到主题中最合理的单词分组。

您可以想象 LDA 模型的工作方式,如下所示:该模型基于一组似乎有许多共同词汇的文章来识别主题。人类翻译可能会给这个话题贴上“政治”的标签:像“参议院”、“政党”和“投票”这样的词在这个话题中很常见,而像“薄饼”或“血红蛋白”这样的词不常出现。由模型识别的另一个主题可以与电影评论一致,并且对应于诸如“电影”、“动作”和“电影摄影”之类的词。当呈现一篇新文章时,比如说,一篇政治惊悚片的评论,该模型将有希望能够识别出它与这两个主题最强烈地对应。

LDA 实际上如何找到主题聚类的数学基础稍微复杂一些,尽管像许多数据科学工具一样,使用广泛可用的 python 库来实现它是很容易的。我决定尝试使用 LDA 来改进我的俳句生成器。第一步是建立一个文本训练语料库。我一直在与 NPR 的文章,因为 NPR 有一个方便,容易刮,纯文本版本的网站,其网址都是相同的保存一篇文章的 id 号。不幸的是,id 不是连续的,也没有一个容易访问的列表。比我有更多网络抓取技能的人会找到更好的方法来自动抓取 NPR 网站,我手工从最近的文章中编辑了大约 250 个文章 id 号。这是一个足够大的语料库,但远没有你想要的那么大。

下一步是对数据进行“矢量化”,将每篇文章从计算机无法真正处理的字符串转换成它可以处理的数学对象。我使用了一个简单的“计数矢量器”,它的功能和听起来差不多:整个文本语料库中的所有独特单词都被表示为一个大矩阵中的列。对应于任何给定文本的向量就像这个矩阵中的一行,每一列中的值对应于该列在文本中出现的单词的计数。因此,矩阵是“稀疏的”:因为大多数可能的单词不会出现在任何给定的文本中,所以有许多零。简单计数矢量化的一种替代方法可能是词频-逆文档频率(TF-IDF ),它实质上是与相应单词在整个语料库中出现的频率成反比地对文本向量中的条目进行加权。因此,在多个主题中常见的单词,如“good”或一周中各天的名称,将具有较低的权重,而相对罕见的单词则具有较高的权重。

最后,使用 scikit learn 运行 LDA 模型是一个简单的两行代码。我选择运行 10 个主题的模型,并打印出每个主题中最重要的单词,以直观地检查它们的连贯程度。

在某些情况下,该模型在将相关术语组合在一起方面做得非常好,特别是对于与当前事件相关的这些组,我认为不需要任何解释:

News articles from the border

News article about business as usual

其他主题表面上看不太清楚,不过,拥有较小数据集的一个意想不到的好处是,很容易找到一些联系。第七个话题起初看起来很奇怪,热门词汇大多与健康和医学有关,但也包含像“气候变化”这样的内容。这种联系是由一篇文章建立的,这篇文章讨论了炎热的夏天和其他与全球变暖相关的压力对健康造成的一些后果:你的医生和你谈过气候变化吗。因为这是一个相对较小的训练集,所以像这样的一篇文章可以在模型中不同的主题之间建立重要的联系。有了更大的文本集和更多的主题,LDA 模型可能会将医学和气候变化文章作为单独的主题进行分组,并认为链接这两个主题的文章是这两个主题的混合。

一旦模型被训练,它可以评估新文本,并根据它认为它属于哪个主题簇来对它们进行分类。例如,给定这篇关于飓风巴里在路易斯安那州登陆的文章,该模型认为它最有可能属于主题#4,这是一个具有大量政府和政治相关单词的主题。考虑到这篇文章讨论的是联邦政府对飓风的反应,这个猜测不错。为了更好地说明实际情况,我编写了一个函数来返回文本中在所选主题中权重最大的单词,因此这些单词对与该主题分组的文章贡献最大:

这个函数在我的测试文章中的输出有助于阐明为什么它被归入那个主题:

测试文章与其他新闻文章的分组是正确的,如果你仔细阅读与它所识别的主题群最相关的单词,你会看到“新闻演讲”的明显例子:“居民”、“报道”、“官员”等。不过,也有一些怪癖:一方面,它把“星期四”定为重要的一天。也许这真的有道理!也许新闻文章(而不是艺术部分的文章)更可能指定一周中的某一天。在我看来,有些词可能会出于“错误”的原因将模型指向某个特定的主题群。例如,“水”这个词。稍微了解一下进入这一模式的文章,我并不感到意外的是,水可能会聚集特朗普和其他与新闻相关的词:今年夏天,有许多关于南部边境拘留中心的文章,包括讨论被可耻地关押在那里的人是否能获得干净的水。然而,在本文的上下文中,它是一种不同的水,雨/洪水,被用来将本文链接到这个主题集群。

当然,整个练习的目的是提高我的打油诗写作能力。您如何将此用于该目的?两种方式。第一,这提供了一种从文章中过滤掉不太“有用”的单词的方法:您需要确定哪些单词是“内容”单词,并比所有主题的文章中常见的单词更频繁地使用它们。第二,这可能会释放文章文本中找不到的额外词汇。如果你正在创作一首打油诗,你可能需要寻找没有出现在文本中的单词,以便找到押韵或生成新的句子,并正确扫描。计算机怎么知道哪种词有意义呢?这可能是对单词进行分组的一种方式:“我看到本文属于这个主题组,与这个组相关的其他单词是……”

我试着调整我的俳句生成器,以便在组合俳句时使用输出的、高度加权的单词作为单词字典。在之前关于飓风巴里的文章中,我的新俳句生成器产生了这首诗:

路易斯安那

新应急水

中央报告日

鉴于这篇关于新任白宫新闻秘书斯蒂芬妮·格里沙姆的文章,它产生了以下内容:

Grisham 发言人

最大的政府

白色中等好

这个过程能提高我的俳句创作吗?不完全是。如果说有什么不同的话,那就是有几个原因让情况变得更糟。我以前的生成器按照单词在文本中的出现频率使用单词,除了停用词之外,没有丢弃任何单词。然而,现在,文本单词通过矢量器传递,该矢量器丢弃在语料库的所有文本中出现频率不够高的单词,并使用受模型/语料库整体影响的权重。因此,对于给定的文章来说相对特殊的单词可能不会出现在要使用的单词列表中,即使这些正是你想要出现在摘要俳句中的单词!从项目的长期来看,可能需要一个策略来打开一个更广泛的单词字典。然而,对我来说很明显,为了使用这种策略,你只需要更多:更多的文本,更多样化的文本,可以被分组到更多的主题群中。

Limericking 第 3 部分:文本摘要

原文:https://towardsdatascience.com/limericking-part-3-text-summarization-f715841a8765?source=collection_archive---------21-----------------------

石灰工程

从文本中识别关键的摘要句子

欢迎来到我正在进行的 Limericking 系列的第 3 部分,在这里我将探索自然语言处理在解析新闻文本和写诗方面的巨大潜力。正如我在系列文章的第一部分中解释的那样,我是 Twitter 账户 Limericking 的狂热粉丝,该账户能够消化新闻并创作出精彩的打油诗。

So much more pleasant that watching the Democratic primary debate

唯一的问题是 Limericking 只是一个帐户。到目前为止,其他主流媒体都无视我的要求,用押韵诗报道所有新闻,让我们的大部分新闻消费处于危险的非多样化状态。我希望通过创造一个自动计算程序,利用自动化的强大力量来解决这个问题,从而帮助弥合这一鸿沟。一个函数能接受一篇新闻文本,恰当地解释它的意思,并把它改写成一首打油诗吗?我相信答案是肯定的,尽管我可能需要更多的博客文章来解决所有的问题。然而,我已经自动生成了一些非常成功的俳句。

第一大任务是找到一种方法,让计算机“阅读”给定的新闻文本,并返回某种摘要或一组关键词。稍后,我们将不得不考虑如何让计算机生成自己的文本,该文本扫描正确且押韵(并有适当的喜剧性转折),但目前,简单地从文本中提取主题已被证明足够困难。我在这个系列中的最后一篇文章讨论了使用潜在的狄利克雷分配来尝试将文章分组到“主题”中,并识别与这些主题相关联的有意义的单词。结果不是很好。

不过,也许我对这部分挑战想得太多了。尽管主题建模是一个困难的问题,但我在第 1 部分中最初的俳句写作功能令人惊讶地做得很好的事情之一是识别新闻文章是关于什么的。我只是推断这篇文章可能是关于一个专有名词,比如一个人或一家公司,并且这个主题可能会在文章的正文中出现多次。简单地找到专有名词,并计算出哪些是最常出现的,对确定文章的内容大有帮助。像这样的策略的关键之一是它完全基于规则:它不需要在一组标记良好的文章样本上训练模型,也不需要计算机“理解”给定单词的意思,或者为什么它可能是文章的主题。更重要的是,该函数只是识别并返回原始文本的一个元素,所以您还不需要处理文本生成。

也许有一种方法可以做类似的事情,但它可以在更大的文本块上工作:比如说,一个函数可以根据一些容易计数的特征比较文本中的不同句子,然后返回一个似乎最重要的句子,就像最常重复的专有名词似乎“重要”一样。事实证明,有一种方法可以做到这一点,这种方法很容易实现,而且效果很好。关键的洞见是弄清楚如何衡量一个给定句子的“中心”或“主题”程度。寻找最常用的专有名词的句子长度是多少?

解决这个问题的一种方法是,根据文本中包含的单词来比较这些句子之间的相似程度。想象一下,例如,一个关于你所在城镇的市长的当地新闻故事。哪些单词最有可能出现在故事中,出现在最多的句子中?当然,你会期望城镇的名字和市长的名字会出现很多次,出现在很多不同的句子中。文章可能会有一个更具体的主题,比如某个特定的事件或市长工作的某个方面,这也会在文章中多次出现。其他事情可能在文本中出现得不太频繁,也许有一句话可能会提到市长的前任或邻镇正在发生的事情。

根据我们对这些单词分布的预期,你如何教计算机识别哪些句子看起来最重要?一种方法是简单地找出与文章中其他句子有最多共同点的句子。如果句子中有像市长的名字或城镇的名字这样的词,它看起来会和文章中包含这些词的许多其他句子相似。如果一个句子在谈论下一个城镇,而那个城镇的名字只被提到过一次,那么这个句子看起来就不像文章中的其他句子。举个具体的例子,考虑一篇关于纽约地铁糟糕状况的文章。像“纽约人指责白思豪造成地铁灾难”这样的句子可能会与文章中的其他句子相似,只是基于单词数:“纽约”、“地铁”等。像“彭博治下的情况没那么糟”这样的句子看起来不太相似,包含了像“彭博”这样的新词。

为了实现这个策略,首先我们需要将每个句子转换成计算机更容易处理的东西,比如一个向量,其中不同列中的值对应于给定单词在句子中出现的次数。然后计算机可以很容易地用余弦相似度这样的方法比较任意两个给定句子对应的向量。幸运的是,sklearn 很容易处理矢量化和相似性。考虑下面的实现,除了两个小问题之外,它非常简单:1)我使用优秀的 NLP 包 spaCy 将一大块文本分割成句子,但随后必须将句子转换回字符串对象(而不是 spaCy 标记), 2)我在第一个函数中有一个小循环,它将排除完全重复的句子。我之所以包括这个,是因为根据文本的来源,我发现我会重复使用类似“点击此处订阅”的短语,我想排除这些短语:

这在实践中是如何运作的?好吧。考虑到它的简单性,甚至可能出乎意料地好。例如,这篇关于农业对气候变化影响的文章有 23 个句子。我的函数将这些定义为最有用的 5:

The panel of scientists looked at the climate change effects of agriculture , deforestation and other land use , such as harvesting peat and managing grasslands and wetlands . The new report adds weight and detail to a warning put out by the same panel of scientists last fall , in which they sounded the alarm about the inadequacy of the pledges countries have made so far to reduce greenhouse gas emissions. At that time, the panel broadly suggested that farmland would need to shrink and forests would need to grow to keep Earth from getting more than 1.5 degrees Celsius hotter than it was in the preindustrial era. Scientists say the only way to achieve that reduction is to significantly increase the amount of land that ‘s covered in trees and other vegetation and significantly reduce the amount of methane and other greenhouse gases that come from raising livestock such as cows , sheep and goats. The U.N. panel is the latest group of experts to grapple with a global conundrum: how to reduce greenhouse gas emissions from agriculture , deforestation and other land use without creating food shortages or displacing people whose livelihoods rely on practices that are unsustainable globally.

一点都不差!整篇文章中有几个奇怪的遗留部分(比如以“当时”开头的句子没有明确的指代),但这篇文章的主旨很容易理解。

我想将实际的诗歌生成留到本系列的后续文章中,但我认为一个简单的系统将文本压缩成一个摘要有一些明显的好处。我们未来的五行打油诗生成器不必凭空创造文本,它会识别出重要的句子,只需要将它们恰当地塑造成五行打油诗的形式。它将能够借用整块的文本,而不需要担心词法或词序。

我的俳句生成器的含义也很清楚。这提供了一种非常有用的方法来识别要插入到俳句中的主题(所识别的句子之一的字面、语法主题),以及一种方法来识别应该选择的一组单词(从摘要句子中派生的词汇,而不是整个文本本身)。我将这些变化应用到我的俳句生成器中,它立即返回了这篇来自气候变化文章的精彩文章:

Sheep global need food,The panel of scientists,New effects countries.

从这个关于发现一只巨大史前鹦鹉的令人愉快的故事中,我们得到了这个相当贴切的金块:

Scientists small lint,Bird fauna island story,Ornithology.

但是,我想,当你的出发点是发现一只古老的儿童大小的鹦鹉的好消息时,结果一定会很有趣。

Artist’s rendering of the bird in question

协同推荐系统的局限性

原文:https://towardsdatascience.com/limitations-of-collaborative-recommender-systems-9801036941b3?source=collection_archive---------16-----------------------

从一个小杂志发行版的角度来看

Zines on display at the Stay Kind! table at Pioneer Valley Zine Fest in April 2018. (Source: Stay Kind! Instagram)

本文包括一些关于 Stay Kind 的背景!zine 发行版,构建基于购买的协作推荐系统的过程,对推荐的评估,对该系统的局限性的讨论,以及对未来发展的想法。

背景

我记不清的确切历史了,保持善良!锌发行版。它开始是一个非常非正式的附带项目,经历了几次迭代,从来没有严肃或重要到足以记录。也许这是杂志本质的恰当反映。作为“杂志”的简称,这些自行出版的作品本身就是一种文档——但也可能是有限的、短暂的,并且容易消失。

我没有开始记录任何事情,直到 2016 年年中发生了两个重大变化:

  1. 我开始拿别人的杂志。
  2. 我承诺将所有销售额的 20%捐赠给有益于我们社区的组织。

这两个改变意味着除了我自己之外,还要对其他人负责。这意味着要跟踪销售和交易情况,而不是随便就把东西送人。

决定建立一个推荐系统

制作一个简单推荐系统的最初动力来自几个地方:

  • 人们经常向我寻求建议,我不知道该怎么回答他们。
  • MovieLens data 很有趣,但我也想建立一个推荐器,为我提供新的信息和实际应用。
  • 我认为这将是超级快速和容易的,因为我已经有了所有的数据。(大部分都很快很容易——但是没有什么比你想象的更快更容易。)

该计划是建立一个推荐系统,使用基于购买的协同过滤。你可以在任何时候看到这样的系统,你可以看到“买这个的人也买了…”听这个的人也听…”等等。

构建协同推荐系统

数据收集

我计划从 Square 和 Stay Kind 上提取交易记录!网站。Square transactions 记录了活动期间面对面的销售和交易。该网站由 WooCommerce 提供支持,由于其报告选项,最终变得有点棘手。我最终从一个单独的电子表格中获取了网上销售信息,这个电子表格是我为跟踪交易而创建的。

Tabling at New Zineland in April 2018.

数据探索和预处理

在这两个数据集之间,我有从 2016 年春天到现在(可能)所有销售和交易的记录。有一次,一家图书馆购买了我当时库存的全部 48 本书的两本。我从最终数据中排除了这次销售。

正如所料,大部分事务来自事件,并在 Square 报告中捕获。这里的挑战是,这些购买大多是用现金进行的。虽然我可以对一起购买的物品进行分组,但我无法对同一个人在不同场合购买的物品进行分组,除非他们用一张卡支付,并且每次都使用同一张卡。一个人在三个不同的活动上用至少两张不同的卡从网站上购买杂志。我能够对这些购买进行分组,因为这个人的所有卡上都有相同的名字,但它们是规则的例外。

(在这个过程中,我还注意到有一个人的名片上有埃玛·戈尔德曼这个名字。虽然有可能这是这个人的真名,但我更倾向于相信这是对活动家的致敬,他经常被错误地引用说,“如果我不能跟着它跳舞,那就不是我的革命。”不管怎样,我都笑得很开心。)

总之,在组合、清理和匿名化数据集之后,我最终得到了类似这样的东西:

从这个片段中,我们可以看到客户#544 和#527 都购买了 2015 年 6 月和 7 月的 Ima Eat You!

协同推荐器

现在我们有了一个单一的数据框架,表明哪些客户拥有哪些商品,我们准备好根据购买情况构建推荐器了。我采取的步骤是:

  1. 添加一个名为Purchased的新列,所有值都设置为1
  2. index='Item', columns='Customer', values='Purchased'处创建一个数据透视表。
  3. 0填充缺失值,创建一个稀疏矩阵。
  4. 使用pairwise_distances计算余弦相似度。
  5. 将距离放入数据帧中,使其易于阅读。

以下是最终数据帧一部分:

(Scroll to the right to view more.)

一个值越接近0,这两件商品就是否被同一个人购买而言就越相似。因此与其自身交叉引用的项目将始终等于0

同时,1的值表示这两件商品从未被同一个人购买过。看上面的一个例子,这意味着已经买了 1 周半的人,没有一个还买了 9 的爱情药水

估价

让我们看几个例子来了解这个推荐器实际上做得有多好。

Ang Pangalawang Pagtatapat:第二部告白

Ang Pangalawang Pagtatapat(Source: Stay Kind!)

售出数量:23

以下是网站上的描述:

杂志系列的第二期《自白》讲述了不安全感、菲律宾政治的本质以及菲律宾人的心态。作者:苏迈.夏琳。

16 页,5.5 x 8.5 英寸

这些建议是基于购买了这个产品的人也买了什么:

People who got Ang Pangalawang Pagtatapat: The Second Confessions also got these zines by the same creator. (Source: Stay Kind!)

前两个推荐,自白Kulay Ng Balat ,实际上是提供种族反思的同一系列杂志的一部分。如果你讨厌一个人… 是同一作者的另一本杂志。《活着的南方人》是由另一位创作者制作的系列节目,他也专门谈论种族问题。总的来说,这一套建议还是不错的。

焦虑工具包

Anxiety Toolkit (Source: Stay Kind!)

售出数量:26

来自网站的描述:

焦虑工具包是我在 48 小时内专门为 2014 年布鲁克林杂志节制作的一次性杂志。这是一个可以用来缓解焦虑的 15 个工具的列表(以及这些工具如何/为什么对我有用的描述)。安妮·h。

28 页,4.25 x 5.5 英寸

这些建议是基于购买了这个产品的人也买了什么:

People who got Anxiety Toolkit also got these zines by other creators. (Source: Stay Kind!)

这个的结果有点复杂。虽然这本杂志的标题中有“工具包”,并包括降级策略,但作者以非常随意的语气写作,并分享个人故事。这样看来,其实类似于 Kulay Ng BalatFixer Eraser #2 这样的推荐书目。其他标题更明显。心理收缩如何爱我马上变得无忧无虑一切都会好起来这些都是关于心理健康、正念或自我保健的策略。

我要吃了你!2011 年 6 月

Ima Eat You! June 2011 (Source: Stay Kind!)

售出数量:5

来自网站的描述:

Dawn“Zilla”Graham 撰写的杂志,主要涵盖日常经历、观察和思考。2011 年 6 月包括寻找一个新的公寓,成为一个容易被说服的人,波士顿之旅,治疗,课程,寓言,食谱,去法院,性暴力,等等。

32 页,5.5 x 8.5 英寸

以及基于购买的推荐:

People who got Ima Eat You! June 2011 also got these other items created by me. (Source: Stay Kind!)

在这种情况下,根据人们的购买情况,只推荐五种商品。所有其他项目都有一个1的距离,这意味着——根据记录——没有人得到这个问题的我吃你!除了上面提到的物品,还有其他物品吗?五个项目中有三个也是我做的。

同样值得注意的是,售出的总数量是 5 台,远远少于前两个示例中售出的 20 多台。这一期的大部分份数我吃了你!早在我开始追踪这些东西之前,它们就已经被送走了。虽然Ang pangala Wang Pagtatapat焦虑工具包都被它们的创作者多次重新进货,但这一期的所有副本 Ima 吃了你!已被认领,绝不转载。

限制

最后一个例子暴露了这种推荐系统在应用于 zine 发行版时的一些局限性。让我们更深入地探讨一下:

杂志通常限量供应。有些用完了也不一定能补上。正因为如此,一份杂志上市的时间也是有限的。根据某本杂志第一次被添加到发行版的时间,或者它脱销的时间,它将与网站上列出的其他杂志中的一部分同时可用。这引发了两个问题。当第一次添加杂志时,存在“冷启动问题,这意味着没有以前的购买历史来通知推荐。人们不是从相同的总体选择中进行选择。

同样,由于有限的桌子空间,并非所有可用的杂志都会在活动中展示。因为人们从《保持友好》中获得了大部分杂志!在活动中而不是通过网站,这很重要。当杂志卖光后,我会用其他杂志取代它们在桌子上的位置。一天开始时的显示通常与一天结束时完全不同。焦虑工具包在之前的一次活动的第一个小时内就已经销售一空。如果那本杂志还能买到的话,很有可能那些随后过来并得到其他杂志的人也会对那本感兴趣。

另一方面,有些人在活动开始时收到几份杂志,后来又收到更多,因为他们看到新的杂志在展出。这将我们带回另一个限制。由于大多数销售是面对面进行的,使用现金,由同一个人进行的购买通常不能归在一起,即使是在同一天进行的。

最后,虽然这个推荐系统确实提供了关于一起购买的物品的准确信息,但它并不能很好地表明人们实际上喜欢什么。大多数面对面交易的好处在于,人们有机会先浏览一下。这意味着他们非常喜欢他们所看到的东西,并愿意去得到它。我带的大多数杂志都是文字内容丰富的。虽然有些人会站在那里阅读整本杂志,但大多数人直到后来才知道他们对新杂志的感觉。也有这样的情况,人们既给自己买了东西,也给别人买了礼物——所以一起购买的杂志不一定反映一个人的喜好。

(在列举了所有这些限制之后,我觉得有必要列举这个小项目的一个优点:基于购买的协作推荐器构建起来既快又容易。写这篇文章花费的时间比数据收集、预处理和创建推荐系统的时间加起来还要长。)

Zines on display at the Stay Kind! table at Not Another Punk Rock Flea Market in July 2018. (Source: Stay Kind! Instagram)

未来发展

有很多方法可以为发行版建立一个更好的推荐系统。一些想法包括:

  • 使用基于内容的过滤和协作过滤创建一个混合系统。这就意味着要包含各个项目的信息,包括主题、页面大小、彩色与黑白、创作者姓名、文字与图像的比例、成本等。
  • 该网站已经允许人们留下评分和评论。我可以更有意识地鼓励人们留下反馈,这样我就可以包括基于评级的协同过滤。
  • 如果我在网站上实现这个推荐系统,我会对它进行调整,这样登录的人就不会收到对他们已经拥有的商品的推荐。

感谢阅读!想法、问题和反馈总是很受欢迎。还可以查看本项目 GitHub 回购。

线检测:让自动驾驶汽车看到道路线

原文:https://towardsdatascience.com/line-detection-make-an-autonomous-car-see-road-lines-e3ed984952c?source=collection_archive---------10-----------------------

通过计算机视觉,你可以一步一步地将视频流转换成线状探测器

动机

全自动驾驶乘用车并非“指日可待”。埃隆·马斯克声称特斯拉将在 2020 年年底具备“完全自动驾驶”能力。特别是,他说特斯拉的硬件已经为自动驾驶做好了准备,剩下的只是对他们当前软件的更新,许多杰出的科学家正在为此努力。

我们人类作为司机的第一本能,很可能是看着前方,决定车该往哪里开;在哪个方向,在哪些线之间,等等。由于每辆自动驾驶汽车前面都有一个摄像头,因此一项非常重要的任务是决定汽车应该在其间移动的边界。对人类来说,我们在道路上画线。现在我们将教一辆自动驾驶汽车看到这些线。我保证会很好玩:)

鸣谢—参考文献

这些项目大部分是由麻省理工学院的 自动驾驶汽车深度学习 课程和 Udacity 的 自动驾驶汽车工程师 激发的。后者是学习和扩展你的领域技术知识的良好开端。

议程

我们将一步一步地设计孔管道,其中我们将激励我们为什么这样做。
灰度变换
高斯模糊
Canny 边缘检测
遮蔽感兴趣区域
霍夫线检测器
寻找道路线

完整的代码可以在这里找到。

在这里,我们将一步一步,提供整个代码的快照。然而,一些部分被省略了,因为这将使邮件非常沉重,并分散我们的目标。因此,如需更多信息,请参考上述知识库。

步骤 0:读取图像

matplotlib的帮助下,我们可以轻松地将 python 脚本中的任何图像加载为三维张量 C-H-W(颜色通道,图像的高度和宽度)

import matplotlib.image as mpimgimg_path = 'test_images/solidWhiteCurve'
img = mpimg.imread(img_path)
plt.imshow(img)
plt.show()

第一步:灰度

首先,我们要把图像变成灰度图像;只有一个颜色通道。这将有助于我们识别棱角。
我们可以通过opencv轻松做到这一点

import cv2gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
plt.imshow(gray_img, *cmap*='gray')
plt.show()

第二步:高斯模糊

将高斯噪声添加到图像中,这非常有用,因为它平滑了像素之间的插值,并且是一种超越噪声和伪梯度的方法。kernel越高,结果图像越模糊。

kernel_size = 5
gauss_img = cv2.GaussianBlur(gray_img,(kernel_size, kernel_size), 0)

第三步: Canny 边缘检测

Canny 边缘检测提供了一种检测图像边界的方法。这是通过图像的渐变来完成的。

后者只不过是一个函数,其中每个像素的亮度对应于梯度的强度。

我们将通过追踪沿着最强梯度的像素来找到边缘!一般来说,梯度显示函数变化有多快,像素之间强烈的密度变化将指示边缘。

low_threshold, high_threshold = [200, 300]
canny_img = cv2.Canny(gauss_img, low_threshold, high_threshold)

正如你所看到的,我们现在可以清楚地识别道路线!(我们甚至可以看到汽车的外形!)

步骤 4:遮蔽感兴趣的区域

上图中,有一些离群值;来自道路的其他部分、来自风景(山脉)等的一些边缘。由于我们的相机是固定的,我们可以在图像上加一个遮罩,只保留那些我们感兴趣的线条。因此,画一个梯形是非常自然的,目的是只保留一个区域,在那里我们应该期望道路线。cv2再次为我们而来;)

# Setting the corners of the trapezium
vertices = np.array([[(0, img_line.shape[0]), (img_line.shape[1], img_line.shape[0]), (400, 260), (600, 260)]])# make a blank/white image
mask = np.zeros_like(img)
mask_channels = (255,) * img.shape[2]# Fill the area of interest with 0 and 255 these
# which lie outside of it, thoughout all color channels
cv2.fillPoly(mask, vertices, mask_channels)# Keep only the pixels with 0 value of the canny_img
masked_img = cv2.bitwise_and(canny_img, mask)

Left: Selected Region Right: After applying the mask

第五步:霍夫线检测器

上面的图像只代表了边缘的点。剩下的就是把边缘连接起来。在这种情况下,我们正在寻找直线,我们将通过将图像传输到称为霍夫空间的参数空间来实现这一点。我们现在将处理极坐标 (rho 和 theta),其中我们将搜索相交线。

import mathlines = cv2.HoughLinesP(img, rho=1, theta=math.pi/180,threshold=15, np.array([]),        *minLineLength*=30,*maxLineGap*=40)line_img = np.zeros((img.shape[0], img.shape[1], 3), *dtype*=np.uint8)

以上将返回许多小车道(最小长度是一个超参数 minLineLength )。 line_img 将是一个列表,其中它的元素是一个列表,由图像空间{(x1,y1),(x2,y2)}中的两个点组成。众所周知,在 2D 空间中,只有一条直线经过两点。

这里自然会出现一个问题:我们如何连接这些线,并导致只有两条,他们将是道路吗?这可能是这篇文章中最具挑战性的部分。

第六步:找到道路线路

我们的策略如下:
。参照 x 轴将图像分成两半
。用线性回归模型拟合这些点,以找到一条平滑的线。
由于离群值,我们想要一个可以有效处理它们的回归模型。我们将使用HuberRegressor。然后,我们将图像限制在 y 轴的某个范围内,并在cv2.polylines的帮助下绘制直线。请记住,为了有一条平滑的线,我们将通过给定的回归量绘制给定的 **x****y** 的预测。

import mathdef draw_lines(line_img, lines):# CODE HEREpasslines = cv2.HoughLinesP(img, rho=1, theta=math.pi/180,threshold=15, np.array([]),        *minLineLength*=30,*maxLineGap*=40)line_img = np.zeros((img.shape[0], img.shape[1], 3), *dtype*=np.uint8)
draw_lines(line_img, lines)plt.imshow(line_img)
plt.show()

此时,鼓励读者编写上述函数。如果你卡住了或者只是想看看我的版本是什么样子,请在这里看。

我们的结果会是…

步骤 7:将线条与原始图像连接起来

通过对两幅图像进行加权,我们可以将它们相加。记住img_lines的黑色区域有值0,因此相加不会改变输出值。

out_img = cv2.addWeighted(img, 0.9, img_lines, 1.0, 0.0)
plt.imshow(out_img)
plt.show()

备注

瞧啊。我们已经成功探测到道路了!视频只是一个图像序列,因此,在moviepy的帮助下,我们为每一帧绘制上述管道!视频管道将看起来像:

from moviepy.editor import VideoFileClipin_video = 'test_videos_output/solidWhiteCurve.mp4'
output_video = 'test_videos_output/out.mp4'clip = VideoFileClip(in_video).subclip(0, 8)
empty_clip = clip.fl_image(YOUR PIPELINE AS A FUNCTION THAT RETURNS THE WEIGHTED IMAGE)out_clip.write_videofile(output_video, *audio*=False)

如前所述,完整的代码可以在这里找到。随意摆弄参数,想出新的方法来检测道路线。

下次再见,保重!

基于 CNN 的直线跟随机器人

原文:https://towardsdatascience.com/line-follower-robot-using-cnn-4bb4f297c672?source=collection_archive---------8-----------------------

Image by author

在本教程中,我们将学习如何制作一个线跟随机器人。虽然,有大量的线追随者教程,因为这个概念本身是相当古老的。然而,这里我们将学习如何使用卷积神经网络(CNN)来检测直线。基本上,我们将使用我们的 Raspberry Pi 相机以预定的间隔捕捉一系列图像,然后我们将使用预先训练的 CNN 来预测我们的机器人应该移动的方向,即向前、向右或向左。本教程需要以下内容:-

  1. 树莓 Pi 板,
  2. Pi 相机,
  3. 跳线
  4. 底盘、电机、轮胎
  5. 电机控制 IC (L293d)

我假设你已经知道如何使用你的 Raspberry Pi 的 GPIO 引脚来控制电机。如果你想提高你的技能,请浏览我之前的教程。此外,在继续下一步之前,请确保您的 Pi 上安装了 tensorflow 1.1 和 open CV。

我将把本教程分为三个部分

  1. 为 CNN 捕捉图像。
  2. 训练 CNN
  3. 在树莓派上部署 CNN

为 CNN 捕捉图像

我们需要三组图像用于三种条件中的每一种,即向前、向左和向右,来训练我们的 CNN。一旦我们训练了我们的 CNN,它将能够预测机器人在哪个方向移动,然后我们可以相应地采取纠正措施。例如,如果生产线左转,CNN 将预测机器人相对于生产线向右移动,因此,我们应该向左移动机器人。

Fig. depicting robot moving in various directions and the corresponding images captured by the camera

可以有各种方法来创建用于训练 CNN 的数据集。在我的例子中,我首先建造了一个轨道。然后,我使用下面提到的代码以 0.5 秒的间隔捕捉一系列图像。然后你把机器人放在轨道上的不同位置,捕捉一系列图像。例如,在第一个图像中,我放置了机器人,这样我希望 CNN 检测到机器人应该向左移动。同样,你在赛道的不同位置重复这个过程。一旦完成,你可以重复这个过程向前和向右。一旦你捕捉到三个方向的图像,将它们分别放入分别命名为向前、向左和向右的文件夹中。

# import the necessary packages
from picamera.array import PiRGBArray
from picamera import PiCamera
import time
import cv2# initialize the camera and grab a reference to the raw camera capture
camera = PiCamera()
camera.resolution = (640, 480) # set the resolution
camera.framerate = 32 # set the frame rate
rawCapture = PiRGBArray(camera, size=(640, 480))# allow the camera to warm up
time.sleep(0.1)# capture frames from the camera
start = 1for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):# grab the raw NumPy array representing the image, then initialize the timestamp and occupied/unoccupied textimage = frame.array# show the framecv2.imshow("Frame", image)key = cv2.waitKey(1) & 0xFFcv2.imwrite(str(start) + ".jpg", image)start = start + 1# clear the stream in preparation for the next framerawCapture.truncate(0)# if the `q` key was pressed, break from the loopif key == ord("q"):breaktime.sleep(.5)

训练 CNN

您可以在 raspberry PI 本身或不同的更强大的系统上训练 CNN,然后保存训练好的模型,PI 可以读取该模型。下面是训练 CNN 捕捉图像的代码。

首先,我们导入必要的库。

# import the necessary packages
from keras.models import Sequential
from keras.layers.convolutional import Conv2D, MaxPooling2D 
from keras.layers.core import Activation, Flatten, Dense
from keras import backend as K
from keras.preprocessing.image import ImageDataGenerator
from keras.preprocessing.image import img_to_array
from keras.optimizers import Adam
from sklearn.model_selection import train_test_split
from keras.utils import to_categorical
from imutils import paths
import numpy as np
import argparse
import random
import cv2
import os
import matplotlib

然后我们定义一个可以用来构建 CNN 的类LeNet。这里你可以看到这个类有一个函数build ,它接受参数widthheightdepthclasses。宽度和高度应该等于您将用作 CNN 输入的图像的宽度和高度。在我的例子中,我使用的是 28x28 的图像,因此宽度和高度分别是 28。深度定义输入图像中的通道数。单色的深度为 1,RGB 的深度为 3。类别定义了您希望 CNN 检测的不同类型图像的数量。在我们的例子中,我们想要区分 3 种类型的图像——前向、左向和右向。

class LeNet:[@staticmethod](http://twitter.com/staticmethod)def build(width, height, depth, classes):# initialize the modelmodel = Sequential()inputShape = (height, width, depth)# first set of CONV => RELU => POOL layersmodel.add(Conv2D(20, (5, 5), padding="same",input_shape=inputShape))model.add(Activation("relu"))model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))# second set of CONV => RELU => POOL layersmodel.add(Conv2D(50, (5, 5), padding="same"))model.add(Activation("relu"))model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))# first (and only) set of FC => RELU layersmodel.add(Flatten())model.add(Dense(500))model.add(Activation("relu"))# softmax classifiermodel.add(Dense(classes))model.add(Activation("softmax"))# return the constructed network architecturereturn model

当您调用build 函数时,它将定义一个具有两个卷积层和一个两个密集层的神经网络。人们可以试验这些层的参数,或者甚至添加额外的层来提高模型的准确性。接下来,提供培训图像文件夹所在的路径。您必须已经创建了三个文件夹向前、向左和向右,并将上面捕获的相应图像放在各自的文件夹中。

dataset = '/home/pi/Desktop/tutorials/raspberry/trainImages/' # please change this path
# initialize the data and labels
print("[INFO] loading images...")
data = []
labels = []# grab the image paths and randomly shuffle them
imagePaths = sorted(list(paths.list_images(dataset)))
random.seed(42)
random.shuffle(imagePaths)# loop over the input images
for imagePath in imagePaths:# load the image, pre-process it, and store it in the data listimage = cv2.imread(imagePath)image = cv2.resize(image, (28, 28))image = img_to_array(image)data.append(image)# extract the class label from the image path and update the# labels listlabel = imagePath.split(os.path.sep)[-2]print(label)if label == 'forward':label = 0elif label == 'right':label = 1else:label =2labels.append(label)

然后,上面的代码获取子文件夹中每个图像的路径,存储在列表imagePaths中,并对它们进行重排。在训练模型时,随机提供来自每个类的数据是必要的。此外,每个图像然后被读取、调整大小、转换成 numpy 数组并存储在data中。现在,我们还必须给每个图像分配一个标签。为此,我们从每个图像的图像路径中提取文件夹名称。然后,我们比较文件夹名称是否为“转发”,我们指定标签为 0。类似地,标签 1 和 2 被分配给文件夹“右”和“左”中的图像。这就是为什么需要创建子文件夹,并将相似的图像放在不同的文件夹中。

# scale the raw pixel intensities to the range [0, 1]
data = np.array(data, dtype="float") / 255.0
labels = np.array(labels)# partition the data into training and testing splits using 75% of
# the data for training and the remaining 25% for testing
(trainX, testX, trainY, testY) = train_test_split(data,labels, test_size=0.25, random_state=42)# convert the labels from integers to vectors
trainY = to_categorical(trainY, num_classes=3)
testY = to_categorical(testY, num_classes=3)

接下来,图像被归一化,使得每个像素的值在 0 和 1 之间。然后,将图像划分为训练集和测试集,以检查模型性能。在接下来的步骤中,我们使用 LeNet 类构建模型,根据训练数据训练模型,然后保存训练数据。

# initialize the number of epochs to train for, initial learning rate,
# and batch size
EPOCHS = 15
INIT_LR = 1e-3
BS = 32# initialize the model
print("[INFO] compiling model...")
model = LeNet.build(width=28, height=28, depth=3, classes=3)
opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS)
model.compile(loss="binary_crossentropy", optimizer=opt,metrics=["accuracy"])# train the network
print("[INFO] training network...")
H = model.fit(trainX, trainY, batch_size=BS,validation_data=(testX, testY),# steps_per_epoch=len(trainX) // BS,epochs=EPOCHS, verbose=1)# save the model to disk
print("[INFO] serializing network...")
model.save("model")

部署 CNN

一旦我们训练了我们的模型,我们就可以在我们的 Pi 上部署它。你可以使用下面提到的代码根据 CNN 的预测来控制机器人的方向。首先,我们从导入必要的库开始。这里我们也使用了motor_control.py文件,你可以在我之前的教程中找到。

# import the necessary packages
from keras.preprocessing.image import img_to_array
from keras.models import load_model
import numpy as np
import cv2, time, sys, imutils, argparse
import RPi.GPIO as GPIO
from picamera.array import PiRGBArray
from picamera import PiCamera
import motor_control as mc

接下来,定义您将用来控制电机的 raspberryPi 的引脚。

GPIO.setmode(GPIO.BCM)#choose the GPIO pins for mptor control
fwd1 = 23  # pin 16
bwd1 = 24 #pin 18
fwd2 = 16 # pin 36
bwd2 = 20 # pin 38# declare selected pin as output pin
GPIO.setup(fwd1, GPIO.OUT)
GPIO.setup(bwd1, GPIO.OUT)
GPIO.setup(fwd2, GPIO.OUT)
GPIO.setup(bwd2, GPIO.OUT)

接下来,我们定义一个函数control_robot,它将根据模型的预测控制机器人的方向。

#function to control direction of robot based on prediction from CNN
def control_robot(image):prediction = np.argmax(model.predict(image))if prediction == 0:print("forward")mc.forward()elif prediction == 2:print("left")mc.left()else:print("right")mc.right()

接下来,我们初始化相机,并开始在预定的时间间隔抓取图像。这些图像中的每一个都经过预处理,类似于我们对训练图像所做的那样。然后,该图像被传递给控制机器人方向的功能control_robot

model = load_model("model")if __name__ == "__main__":try:mc.stop()# initialize the camera and grab a reference to the raw camera capturecamera = PiCamera()camera.resolution = (640, 480)camera.framerate = 32rawCapture = PiRGBArray(camera, size=(640, 480))# allow the camera to warmuptime.sleep(0.1)# capture frames from the camerafor frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):# grab the raw NumPy array representing the image, then initialize the timestamp# and occupied/unoccupied textimage = frame.array# show the framekey = cv2.waitKey(1) & 0xFF image = cv2.resize(image, (28, 28))image = img_to_array(image)image = np.array(image, dtype="float") / 255.0image = image.reshape(-1, 28, 28, 3)#cv2.imshow("Frame", image[0]) control_robot(image) # clear the stream in preparation for the next framerawCapture.truncate(0) except KeyboardInterrupt:mc.stop()GPIO.cleanup()sys.exit()

如果一切顺利,当您在 Raspberry Pi 上运行这段代码时,您将能够看到类似的结果。

我希望你喜欢这个教程。请随时评论和询问或提出一些建议。非常感谢 Adrian Rosebrock 关于 RaspberryPi 的精彩教程,我在这里以此为基础。做检查他的网站。

ML 线性代数与概率论复习

原文:https://towardsdatascience.com/linear-algebra-and-probability-theory-review-for-ml-e3d2d70c5eb3?source=collection_archive---------30-----------------------

任何数据科学家都必须知道的矩阵、向量和概率论基础知识

Photo by Oleg Magni from Pexels

矩阵

  • 按行和列组织的一组元素。
  • 行是水平线,列是垂直线,它们通常都是零索引的。

Matrix Example

  • 矩阵维度: (行数)x(列数)
  • 矩阵加法和减法

Matrix summation/subtraction example

  • 矩阵乘法
    Mat A x Mat B
    (2,3) x (3,2)
    (Ai,Aj) x (Bi,Bj)内部尺寸(Aj & Bi)必须相等,以便能够执行具有外部尺寸(Ai,Bj)大小的输出矩阵的矩阵乘法

Matrix multiplication example

  • 矩阵转置
    一个(3x2)矩阵转置产生一个(2x3)矩阵

Matrix transpose example

  • 矩阵的逆矩阵
    I 被称为单位矩阵,它全是 0,对角线上的 1 与 a 的维数相同

向量

  • 向量是 n×1 矩阵
  • 表示 n 维空间中的直线

  • 向量幅度(范数):给出向量的长度

  • 单位向量:范数= 1 的向量
  • 对于 n 维向量

  • 向量平方的范数等于

  • 向量点积

  • 对于 n 维向量

  • 点积可以表示为

Dot product rule

The projection of the vector u on the vector v,

  • 如果 v 是一个单位向量,那么点积等于向量 u 在向量 v 上的投影
  • 如果两个向量都是单位向量,那么如果两个向量完全对齐,点积将最大
  • 如果两个向量正交,那么点积等于 0

概率论

概率论是我们处理世界不确定性的方式,它是一个数学框架,估计一个事件相对于其他可能事件发生的概率。概率是很多机器学习算法的非常深的层次。

我们来讨论一下解释概率论最著名的经验。掷两次公平硬币
在这个例子中,样本空间是所有可能结果的集合。
SS = { HH,TH,HT,TT }T 是反面, H 是正面。在大多数情况下,你会对所有可能结果的子集感兴趣,例如,你可能只对两次投掷都是正面的结果感兴趣 {HH} ,或者对两次投掷产生不同正面的事实感兴趣 {HT,TH}。
一个事件的概率是分配给一个事件的数 Pr(X)
>= 0
Pr(SS)= 1
(记住 SS 是样本空间)
Frequentists 统计:
Pr(X)= N(X)/N
—如果我们重复实验 X N 次。如果 n(X) 是我们观察 X. 的次数,那么 Pr(X) = n(X)/N

联合概率

对于两个事件 X 和 Y,联合概率是 X 和 Y 同时发生的概率,第一次掷是正面,第二次掷是反面的概率是多少。
Pr(1st 是 H,2nd 是 T) = Pr(1st 是 H) Pr(2nd 是 T) = 0.5 * 0.5 = 0.25。 如果 X{ HH }**B{HT,TH},联合概率 P(XY) 为 0,因为 XY 不可能同时发生。

独立性ˌ自立性

如果两个事件 X,Y 是独立的,那么

也就是说, X 发生,并没有说明 y 发生的概率。在硬币的例子中,如果第一次投掷产生了 H,这并不意味着第二次投掷也有可能是 H 和 T,仍然有 50%的机会。

High Blood Pressure test results

在上图中,是对 30 岁以下的人和 30 岁以上的人进行高血压测试的结果。该表显示了一个样本的结果。
如果 X 是{受试者不到 30 岁}, Y 是{受试者没有高血压}

Pr(XY) 是 1800/4000,
Pr(X) 是 2000/4000,
Pr(Y) 是 2000/4000
由于 Pr(XY) 不等于 Pr(X)PR(Y) ,这就意味着 X

调节

如果 XY 都是 Pr(X) > 0 的事件,则 Y 给定 X 的条件概率为

简单来说,这意味着如果我们知道 Y 发生了,那么 X 的概率是多少?

High Blood Pressure test results

再次回到上图中的例子,如果 X 是{受试者不到 30 岁}, Y 是{受试者没有高血压}

Pr(X|Y) =?
在我们知道受试者没有高血压的情况下,他/她不到 30 岁的概率是多少?
Pr(X | Y)= Pr(XY)/Pr(X)=(1800/4000)/(2000/4000)= 0.9
Pr(Y | X)= Pr(XY)/Pr(Y)=(1800/4000)/(2000/4000)= 0.9
两者相同只是

如果我们知道 XY 是独立的,那么 Pr(A|B) = Pr(A) ,请记住掷硬币的例子,如果我们知道没有一个输出对另一个输出有特殊影响,那么任何输出发生的概率既不影响任何先前条件,也不受任何先前条件的影响。

贝叶斯法则

给定 2 个事件 X 和 Y,并假设 Pr(X) > 0,则

Boxes example, a sketch made by skettchboard

如果我们有两个盒子,其中一个是红色的,另一个是蓝色的,蓝色的盒子包含 3 个平面和 1 颗星,红色的盒子包含 6 颗星和 2 个平面。
Pr(从蓝色盒子中挑选)为 60%, Pr(从红色盒子中挑选)为 40%。

形状是 S,盒子是 B
Pr(B = r)= 0.4
Pr(B = B)= 0.6

条件概率:
Pr(S = p | B = r)= 1/4
Pr(S = h | B = r)= 3/4
Pr(S = p | B = B)= 3/4
Pr(S = h | B = B)= 1/4

挑平面的概率:
这可以解释为我们选蓝框就从蓝框里挑平面的概率,选蓝框就从蓝框里挑平面的概率。
Pr(S = p)= Pr(S = p | B = r)p(B = r)+Pr(S = p | B = B)p(B = B)=1/4 * 4/10+3/4 * 6/10 = 11/20

这是你继续你的 ML 之旅所需要了解的基本知识,祝你好运!

Numpy 线性代数基础(第一部分)

原文:https://towardsdatascience.com/linear-algebra-essentials-with-numpy-part-1-af4a867ac5ca?source=collection_archive---------4-----------------------

啊,数学。你不可能永远回避它。你可以尝试,然后更努力地尝试,但迟早需要一些基本的直觉,前提是你认真努力推进你在数据科学领域的职业生涯。

Photo by Antoine Dautry on Unsplash

说到线性代数,我非常喜欢这句话:

如果数据科学是蝙蝠侠,线性代数就是罗宾。[1]

它以一种非技术性的方式巧妙地抓住了本质。

为什么要学习线性代数?

问得好。
简单来说,如果你理解了它,你将能够为机器学习和深度学习算法开发出更好的直觉,而不会把它们视为黑盒。此外,你还可以从头开始开发算法,并对它们进行自己的修改。

不仅如此,你还会被认为是一个很酷的孩子,就像这两个:

By GIPHY

太棒了。

我为什么要看这个帖子?

这篇文章当然不会教你关于这个话题的每一个细节,有太多的书涵盖了这些。这篇文章也不会深究证据,再说一遍,如果你对数学或科技感兴趣的话,就去读一本书吧。然而,这篇文章将为你提供 14 个不同领域的线性代数(和一些简单的计算)背后的基本直觉。

是的,你没看错。我计划在两篇文章中涵盖 14 个不同的主题。你会花一些时间去阅读(我也会花一些时间去写),但是如果你是新手,我强烈建议你每天最多阅读 2-3 个主题,然后在网上搜索更多的练习题。

文章结构如何?

因此,每个主题分为 3 个部分:

  1. 理论解释
  2. 示例(手工计算)
  3. 用 Python 实现(用 Numpy)

我不骗你,这将是一个很大的工作量。这第一部分将涵盖向量,以下是主题列表:

  1. 添加
  2. 纯量乘法
  3. 点积
  4. 标准
  5. 单位向量
  6. 向量之间的角度

现在介绍完了,就不要推迟必然了。喝杯咖啡(或者更烈的东西),和我一起去线性代数的神奇世界吧。

You after finishing this article. By GIPHY

什么是向量?

是啊,如果你不知道向量是什么,就没有必要从向量加法开始。首先,把向量想象成空间中的箭头。这里你需要记住两个量:

  • 方向
  • 重要

我说的方向是指箭头指向的空间位置,而大小告诉你在那个方向上你应该走多远。如果你只有大小,没有方向,那么你说的就是标量。一旦给标量一个方向,它就变成了矢量。

我说你应该试着把向量想象成箭头——这是一个完美的术语,因为箭头既有明确的方向,也有明确的大小(长度)。

向量通常用小写字母和上面指向右边的箭头表示:

简单,对吧?
现在让我们开始一些向量运算吧,我知道你一定很不耐烦(* *)。

1.向量加法

让我们开始第一个向量运算,这是向量加法(减法的工作方式是一样的,显然,只是你用减号代替了加号)。

这个基本操作真的没什么好说的,只说是通过添加相应的组件来执行的。如果你考虑向量会发生什么,而不仅仅是单纯的数字相加,这有助于理解这个观点。

看看这张来自维基共享的照片:

Vector Addition

简单来说,就是把矢量 b 加到矢量(得到 a+b ),从原点画出矢量 a ,再从矢量 a 的尖端画出矢量 b 。现在要得到 a+b ,只需要将原点连接到矢量 b 的尖端。

如果你第一次听到这个,可能会觉得有点夸张,但是只要拿起笔和纸画出来,你马上就会明白它的要点。

这是矢量加法的一般公式:

现在我将手工做一个简单的例子,稍后我将用 Python 实现这个例子。

再一次,拿一张纸来画这个——这非常直观。

Python 中的实现:

*v = np.array([3, 7])
u = np.array([2, 2])print(v + u)*

如您所见,Numpy 允许您使用加法运算符,非常简洁!

2.纯量乘法

让我引用我在本文前面说过的话:

如果你只有大小,没有方向,那么你说的就是标量。

这实质上意味着标量是一个单一的数字,它只能改变矢量的大小,而不能改变它的方向。这实际上意味着,乘以任何标量的矢量将保持在同一条“线上”,它将具有相同的方向,只是它的长度会改变。

太棒了,让我们看看标量乘法的公式:

以上, n 代表任意数字。让我们看一个例子。标量 n 将为 2,这意味着向量的每个分量都将乘以 2。

Python 中的实现:

*v = np.array([3, 7])print(2 * v)*

太棒了,我们进入下一个话题!

3.点积

要计算两个向量的点积,首先需要用乘以对应的元素 ( x1 乘以 y1x2 乘以 y2 等等),然后求和乘积项

当你看到通式时,这个概念实际上更容易理解,所以它是这样的:

现在我将写下一个二维空间中两个向量的基本例子:

Python 中的实现:

*v = np.array([3, 7])
u = np.array([2, 2])print(v.dot(u))*

是的,这就是关于点积的大部分内容——没什么可谈的。

4.向量范数

范数是向量长度或大小的另一个术语,用两边的双管(||)表示。它被定义为一个矢量的每个分量的平方和的平方根,你将在下面的公式中看到。

计算过程分为三步:

  1. 将每个组件平方
  2. 对所有平方求和
  3. 求平方根

你可以想象,这个公式简单得愚蠢:

这是一个二维空间中向量的实际例子:

Python 中的实现:

*v = np.array([3, 2, 7])print(np.linalg.norm(v))*

5.单位向量

计算单位向量的主要原因是,你只关心方向,而不关心大小。这个标准化过程包括去除幅度,这样就不会影响其他计算。[2]

单位矢量通常用帽子符号(^)表示,通过计算范数,然后用该范数除矢量的每个分量来计算。

事不宜迟,公式如下:

作为一个例子,我将从一个任意的三维向量计算单位向量:

你不必做最后一步——除以平方根——但它使最终结果更有吸引力。

Python 中的实现在这里会有点不同。Numpy 中没有内置函数用于计算单位向量(至少我不知道),但是因为你知道公式,所以计算过程比较繁琐。我已经声明了一个函数,它将一个向量作为输入,然后返回这个向量除以它的范数:

*def unit_vector(v):return v / np.linalg.norm(v)u = np.array([3, 6, 4])
print(unit_vector(u))*

6.向量之间的角度

这可能是线性代数中我最感兴趣的话题。原因是我在日常工作中到处用它来做一些很酷的事情。

向量之间的角度计算有很多实际应用。在 NLP ( 自然语言处理 )中寻找非常相似的字符串时广泛使用。例如,当对一些文本数据使用 TF-IDF 时,每个输入(试着把输入想象成一个单独的电子邮件文本)都被转换成一个向量。

通过这样做,您将确保所有向量都是相同的维数,如果输入在某个位置包含某个单词,则向量的相应分量的值将是 1,否则为 0。如果你计算向量之间的角度,角度最小的向量会更相似(在电子邮件的例子中,就像两封邮件是关于同一个主题的)。

希望你能看到你的项目中潜在的用例,如果没有,不要担心,你最终会看到的。

这是计算角度的公式。没什么特别的,你把两个向量的点积除以范数的积:

这是两个任意三维向量的简单例子:

与单位向量一样,Numpy 没有用于角度计算的内置函数。但是嘿,你知道这个公式,所以这能有多难呢?*
这里唯一的“窍门”是将弧度转换成度数,因为 Numpy 默认情况下将以弧度返回结果。其他的一切都和你想象的一样简单。*

代码如下:

*def angle_between(v1, v2):dot_pr = v1.dot(v2)norms = np.linalg.norm(v1) * np.linalg.norm(v2)return np.rad2deg(np.arccos(dot_pr / norms))v = np.array([1, 4, 5])
u = np.array([2, 1, 5])print(angle_between(v, u))*

这基本上结束了关于向量的讨论。没那么糟吧?

结论

这就是数据科学中线性代数的一些基本要素,至少对于向量来说是这样。下一篇文章将会隐藏矩阵,并且会比这篇文章长一点。

在你等待的时候,我强烈建议你去 YouTube 上看看这个精彩的频道,尤其是这个播放列表。它真正深入到线性代数的基本和高级概念背后建立直觉。如果你知道如何计算,但不知道为什么要计算,这个频道是我真诚的推荐。

3Blue1Brown — Essence of linear algebra playlist

感谢阅读。

第二部分:

* [## Numpy 线性代数基础(第二部分)

学习数据科学的基本线性代数技能—第 2/2 部分

towardsdatascience.com](/linear-algebra-essentials-with-numpy-part-2-d15717eebfd9)

By GIPHY*

喜欢这篇文章吗?成为 中等会员 继续无限制的学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

* [## 通过我的推荐链接加入 Medium-Dario rade ci

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@radecicdario/membership)*

参考

[1]https://www . analyticsvidhya . com/blog/2019/07/10-应用-线性代数-数据-科学/

[2]https://stack overflow . com/questions/2304634/why-do-we-need-a-unit-vector-in-other-words-why-do-we-need-normalize-vector

Numpy 线性代数基础(第二部分)

原文:https://towardsdatascience.com/linear-algebra-essentials-with-numpy-part-2-d15717eebfd9?source=collection_archive---------12-----------------------

Photo by Markus Spiske temporausch.com from Pexels

几天前,我发表了数据科学线性代数系列的第一部分。它涵盖了 6 个关键概念和术语,因此如果您还没有阅读,我强烈建议您先阅读该部分:

[## Numpy 线性代数基础(第一部分)

学习数据科学的基本线性代数技能—第 1/2 部分

towardsdatascience.com](/linear-algebra-essentials-with-numpy-part-1-af4a867ac5ca)

由于前一部分已经讲述了为什么和这个故事是什么(例如为什么线性代数),这一部分将直接切入正题。文章的结构是一样的。每个主题分为 3 个部分:

  1. 理论解释
  2. 示例(手工计算)
  3. 用 Python 实现(用 Numpy)

关于主题,我想说的是:

  1. 矩阵加法
  2. 纯量乘法
  3. 矩阵乘法
  4. 矩阵的转置
  5. 单位矩阵
  6. 决定因素
  7. 矩阵求逆

是的,我知道,这将是一个很大的工作量,再次。你对此无能为力——拿起一杯咖啡(或苏格兰),让我们开始吧!

By GIPHY

什么是矩阵?

据维基百科:

矩阵是数字或其他数学对象的矩形阵列,定义了加法和乘法等运算。[1]

作为一名数据科学家,你一直在使用矩阵,但你可能还不知道(只是还不知道)。您过去使用的任何数据集都可以被认为是一个矩阵——一个由数字组成的矩形阵列— 行和列更具体地说。

从数据科学家的角度来看,你可能想知道矩阵和向量有什么不同。简单来说,vector 是你数据集中的一个单列(属性),而 matrix 是所有列的集合。

矩阵通常用大写加粗字母表示,例如:

和向量一样,掌握关键概念并不困难。

让我们深入一些例子。

1.矩阵加法

矩阵加法(或减法)和你之前用向量做的很相似。唯一的区别是有多列而不是只有一列。

整个想法保持不变,你只需要把相应的组件加起来。在通式中,我使用了 ab 作为占位符,你可以看到每个部分是如何相加的:

虽然这很容易理解,但这里有一个简单的 2 矩阵加法的例子:

矩阵加法在 Numpy 中实现非常简单。同样,与向量一样,您可以使用加号:

A = np.matrix([[3, 5],[1, 0]
])
B = np.matrix([[2, -3],[1, 2]
])print(A + B)

2.纯量乘法

这些概念与向量或多或少是一样的。矩阵中的每一个数字都会乘以一些标量 n

公式也很相似:

对于这个例子,我选择使用一个任意的矩阵,并将标量 n 设置为 2:

Python 中的实现:

A = np.matrix([[3, 5],[1, 0]
])print(2 * A)

一切都和向量非常相似,对吗?

保持这种想法。

3.矩阵乘法

这里有一个话题,我想说的是,它比迄今为止遇到的其他话题要稍微复杂一些。这并不像一开始看起来那么难,但是你需要解决几个例子才能完全理解要点。

对于矩阵乘法部分的以下示例,声明了两个矩阵:

  1. 矩阵 A —尺寸为 mn ( m 行, n 列)
  2. 矩阵 B —尺寸为 np ( n 行, p 列)

AB 相乘将产生一个新矩阵,其尺寸为 m 乘以 p ( m 行乘以 p 列)。简单地说,得到的矩阵将具有矩阵 A 的行数和矩阵 B 的列数。

By GIPHY

在你完全理解最后一段之前,你可能需要读几遍,这没关系。为了帮助你,我现在所说的一切都是可视化的:

This helps, right?

如你所见,中间的两个 n 需要匹配。如果它们不相等,矩阵乘法不能被执行。大多数编程语言都会抛出一个关于尺寸不匹配的错误。

好了,现在当你理解了矩阵乘法的基本规则,你就为通式做好了准备:

用最普通的方式陈述(请把这个嵌入你的大脑):

通过计算矩阵 A 的相应行和矩阵 b 的相应列的点积来执行矩阵乘法

如果你理解了那句话,你就理解了矩阵乘法。如果没有,让我们用一个简单的例子来说明这一点:

与向量一样,您可以使用 函数来执行与 Numpy 的乘法:

A = np.matrix([[3, 4],[1, 0]
])
B = np.matrix([[2, 2],[1, 2]
])print(A.dot(B))

如果第一次阅读后很难理解,不要担心。矩阵乘法对我来说也是一个很难理解的概念,但是真正有帮助的是在纸上手工做。网上有很多例子。

不想找例子就自己编,然后用 Numpy 验证——像个 boss

4.矩阵转置

现在来点简单的,让你的大脑休息一分钟。但就一分钟。

矩阵转置是其中一个听起来非常奇特的话题,特别是如果你不是以英语为母语的人,你不知道转置是什么意思。

这个想法非常简单——你只需要交换矩阵的行和列。转置运算符在大多数情况下用大写字母 T 表示,符号可以放在矩阵前或作为指数。无论哪种方式,下面是一般公式:

正如你所看到的,对角线元素保持不变,而非对角线元素改变了位置。

下面是一个 2x2 矩阵的简单示例:

用 Python 实现真的不能再简单了:

A = np.matrix([[3, 4],[1, 0]
])print(A.T)

5.单位矩阵

正如转置一样,单位矩阵也很容易掌握。这是一个矩阵,其中:

  1. 每个对角元素都是 1
  2. 所有其他元素都是 0

就是这样!通常用大写字母 I 表示,下标中的数字代表它的大小。

以下是大小为 3 的单位矩阵的样子:

不会有任何单位矩阵的例子(目前),我将只向您展示如何用 Python 创建它们:

A = np.eye(3)print(A)

现在回到更难的事情上来。

6.决定因素

根据维基百科:

行列式是一个标量值,可以从方阵的元素中计算出来,并对矩阵所描述的线性变换的某些属性进行编码。
矩阵 A 的行列式表示为 det( A ),det A ,或| A |。从几何学上讲,它可以看作是矩阵所描述的线性变换的体积比例因子。[2]

为了更直观地了解行列式是什么,以及它的用途,请参考文章结论部分的视频播放列表。

对于 2x2 矩阵,计算过程很简单,对于 3x3 矩阵,get 有点困难,对于更大的矩阵,不应该手动计算。我是说如果你想的话你可以,但是为什么呢?这里的目标是发展直觉,计算机是用来做计算的。

下面是计算 2x2 矩阵行列式的一般公式:

为了说明问题,这里有一个最基本的手工计算的例子:

Python 中的实现:

A = np.matrix([[3, 2],[1, 6]
])print(np.linalg.det(A))

你做得很好。后面是最后一节,然后就大功告成了!

7.矩阵求逆

如果原矩阵与其逆矩阵相乘得到单位矩阵,则称方阵可逆(或非奇异)。

从这句话,你可以得出结论,不是所有的矩阵都有逆。对于可逆矩阵,它必须满足以下条件:

  • 必须是方形的
  • 行列式不能为 0

不可逆的矩阵称为奇异矩阵。从逻辑上讲,方阵要奇异,其行列式必须等于 0。让我们通过探索一般公式来看看为什么:

如你所见,矩阵的逆由上标中的这个 -1 项表示。这个公式你可能已经很熟悉了——之前见过ad——BCterm(行列式)。这里可以看出为什么行列式不能是 0 — 除以 0 是未定义的。**

这一项然后乘以稍微重新排列的原始矩阵。对角元素被交换,非对角元素被乘以负一(-1)。

下面是一个计算 2x2 矩阵逆矩阵的简单示例:

Python 中的实现:

**A = np.matrix([[4, 3],[5, 4]
])print(np.linalg.inv(A))**

现在让我们来验证一下先前的说法,即原始矩阵与其逆矩阵相乘产生单位矩阵:

这是一个手工计算的例子,这些陈述是正确的!

Python 中的实现:

**print(A.dot(np.linalg.inv(A)))**

结论

花点时间祝贺自己坚持到了最后。我希望你已经阅读了文章的第一部分,如果你已经阅读了,谢谢你。

By GIPHY

也许并非所有讨论的术语都直接适用于数据科学(从你的角度来看),但线性代数通常是值得了解的——这可能会在你即将到来的数据科学面试中被问到,所以了解基础知识是必须的。

现在放松一下,看部电影,喝几杯啤酒,让一切都沉淀下来。大约一周后,我建议你自己进一步探索线性代数,当然,一定要看这个播放列表:

我可以强调这对你发展线性代数的直觉方法有多大的帮助。

感谢阅读…

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

** [## 通过我的推荐链接加入 Medium-Dario rade ci

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@radecicdario/membership)**

参考

[1]https://en . Wikipedia . org/wiki/Matrix _(数学)

https://en.m.wikipedia.org/wiki/Determinant

线性分类器:综述

原文:https://towardsdatascience.com/linear-classifiers-an-overview-e121135bd3bb?source=collection_archive---------6-----------------------

本文讨论了四种流行的线性分类方法的数学属性和实际 Python 应用。

本文基于优秀的 Hastie,t .,Tibshirani,r .,& Friedman,J. H. (2009)的一章。统计学习的要素:数据挖掘、推理和预测。第二版。纽约:斯普林格。

用于解决分类任务的一类流行程序是基于线性模型的。这意味着,他们旨在将特征空间划分为根据目标可以采用的值标记的区域集合,其中这些区域之间的决策边界是线性的:它们是 2D 中的线、3D 中的平面和具有更多特征的超平面。
本文回顾了流行的线性分类模型,提供了对所讨论的方法以及 Python 实现的描述。我们将介绍以下方法:

  • 线性判别分析,
  • 二次判别分析,
  • 正则化判别分析,
  • 逻辑回归。

出于演示的目的,我们将把每个讨论的方法应用于垃圾邮件数据集,其中的任务是基于描述电子邮件中使用的词频的一组特征来将电子邮件分类为垃圾邮件或非垃圾邮件。数据集以及一些变量的描述可以在哈斯蒂等人的网站“统计学习的要素”教科书的数据部分找到。

让我们从导入本教程中使用的所有包并加载数据开始。

线性判别分析

要讨论的第一种方法是线性判别分析(LDA)。它假设所有特征的联合密度(取决于目标的类别)是一个多元高斯分布。这意味着,假设目标 y 在类别 k 中,特征 X 的密度 P 假定由下式给出

其中 d 是特征的数量,μ是平均向量,σ_k是类别 k 的高斯密度的协方差矩阵。

两个类之间的判定边界,比如说 kl ,是属于任一类的概率相同的超平面。这意味着,在这个超平面上,两个密度之间的差异(以及它们之间的对数优势比)应该为零。

LDA 中的一个重要假设是不同类别的高斯分布共享同一个协方差矩阵:上式中σ_k的下标 k 可以去掉。这个假设对于计算对数优势比很方便:它使标准化因子和指数中的一些二次部分相互抵消。这产生了在 kl 之间的判定边界,其在 X 中是线性的:

为了计算特征的密度,P(X|y=k),只需估计高斯参数:均值μ _k 作为样本均值,协方差矩阵σ作为经验样本协方差矩阵。计算后,目标属于类别 k 的概率可以从贝叶斯规则中获得:

其中P(y=k)是属于 k 类的先验概率,可以通过样本中 k 类观测值的比例来估计。

请注意,LDA 没有要优化的超参数。只需几行代码就可以将其应用于垃圾邮件数据。

二次判别分析

LDA 假设不同类的高斯分布共享相同的协方差矩阵,这很方便,但对于特定数据可能不正确。下图的左栏显示了 LDA 如何处理来自具有共同协方差矩阵的多元高斯分布的数据(上图),以及不同类别的数据具有不同协方差时的情况(下图)。

Source: https://scikit-learn.org/stable/modules/lda_qda.html

因此,人们可能希望放松公共协方差假设。在这种情况下,要估计的协方差矩阵不是一个,而是 k 个。如果有许多特征,这可能导致模型中的参数数量急剧增加。另一方面,高斯指数中的二次项不再相互抵消,决策边界在 X 中也是二次的,这给了模型更多的灵活性:见上图。这种方法被称为二次判别分析(QDA)。

多亏了 scikit-learn,QDA 的 Python 实现和 LDA 一样简单。

正则判别分析

正如用于回归的线性模型可以被正则化以提高准确性,线性分类器也可以。可以引入收缩参数α,其将 QDA 的独立协方差矩阵收缩到公共 LDA 矩阵:

收缩参数可以取从 0 (LDA)到 1 (QDA)的值,任何介于两者之间的值都是两种方法的折衷。α的最佳值可以基于交叉验证来选择。要在 Python 中做到这一点,我们需要将收缩参数传递给 LDA 函数,并将计算算法指定为最小二乘法,因为其他计算方法不支持收缩。

逻辑回归

线性分类的另一种方法是逻辑回归模型,尽管它的名字,它是一种分类而不是回归方法。逻辑回归通过线性函数对属于每个 K 类的观察值的概率进行建模,确保这些概率总和为 1,并保持在(0,1)范围内。根据 K -1 对数优势比指定模型,选择任意类别作为参考类别(在本例中是最后一个类别, K )。因此,属于给定类别和属于参考类别的对数概率之间的差异被线性建模为

其中 G 代表真实的、被观察的类。从这里,属于每个类别的观察值的概率可以计算如下

这清楚地表明所有类别的概率总和为 1。

逻辑回归模型通常由 scikit-learn 负责的最大似然估计。正如回归的线性模型可以被正则化以提高准确性,逻辑回归也是如此。事实上, L2 惩罚是 scikit-learn 中的默认设置。它还支持 L1弹性网惩罚(要了解更多信息,请查看上面的链接),但并非所有解算器都支持它们。 Scikit-learn 的逻辑回归文档有详细描述。

虽然逻辑回归主要用作任务中的推理工具,目标是理解输入变量在解释结果中的作用(它产生易于解释的系数,就像线性回归一样),但它也可以证明具有重要的预测能力,如下例所示。

总结和结论

本文讨论了几个线性分类器:

  • 线性判别分析(LDA) 假设给定目标类别的所有特征的联合密度是多元高斯分布,每个类别具有相同的协方差。公共协方差的假设是一个很强的假设,但如果正确,允许更有效的参数估计(较低的方差)。另一方面,该公共协方差矩阵是基于所有点来估计的,也包括那些远离决策边界的点。这使得 LDA 容易出现异常值。
  • 二次判别分析(QDA) 通过为每个类别估计单独的协方差矩阵,放松了 LDA 的公共协方差假设。这给了模型更多的灵活性,但是在许多特征的情况下会导致模型中参数数量的急剧增加。
  • 正则化判别分析是 LDA 和 QDA 之间的一种折衷:正则化参数可以调整为将协方差矩阵设置在所有类别的 1(LDA)和每个类别的完全分离(QDA)之间的任何位置。
  • 逻辑回归通过线性函数模拟属于每个类别的观察值的概率。一般认为它比判别分析方法更安全、更稳健,因为它依赖的假设更少。对于我们的示例垃圾邮件数据来说,这也是最准确的。

感谢阅读!我希望你已经学到了对你的项目有益的东西🚀

如果你喜欢这篇文章,试试我的另一篇文章。不能选择?从这些中选择一个:

[## 线性回归中收缩法和选择法的比较

详细介绍 7 种流行的收缩和选择方法。

towardsdatascience.com](/a-comparison-of-shrinkage-and-selection-methods-for-linear-regression-ee4dd3a71f16) [## 增强你对助推的把握

揭秘著名的竞赛获奖算法。

towardsdatascience.com](/boost-your-grasp-on-boosting-acf239694b1) [## 模型选择和评估

超越火车价值测试分裂

towardsdatascience.com](/model-selection-assessment-bb2d74229172)

来源

  1. Hastie,Tibshirani,r .,,j . h . Friedman(2009 年)。统计学习的要素:数据挖掘、推理和预测。第二版。纽约:斯普林格。
  2. https://scikit-learn.org/stable/modules/lda_qda.html
  3. https://sci kit-learn . org/stable/modules/generated/sk learn . linear _ model。LogisticRegression.html

Python 中的线性判别分析

原文:https://towardsdatascience.com/linear-discriminant-analysis-in-python-76b8b17817c2?source=collection_archive---------0-----------------------

https://www.pexels.com/photo/woman-in-red-long-sleeve-writing-on-chalk-board-3769714/

线性判别分析(LDA)是一种降维技术。顾名思义,降维技术减少了数据集中的维数(即变量),同时保留了尽可能多的信息。例如,假设我们绘制了两个变量之间的关系,其中每种颜色代表一个不同的类。

如果我们想把维数减少到 1,一种方法是把所有东西都投影到 x 轴上。

这很糟糕,因为它忽略了第二个特性提供的任何有用信息。另一方面,线性判别分析(LDA)使用来自两个特征的信息来创建新的轴,并将数据投影到新的轴上,从而最小化方差并最大化两个类的平均值之间的距离。

密码

让我们看看如何使用 Python 从头开始实现线性判别分析。首先,导入以下库。

from sklearn.datasets import load_wine
import pandas as pd
import numpy as np
np.set_printoptions(precision=4)
from matplotlib import pyplot as plt
import seaborn as sns
sns.set()
from sklearn.preprocessing import LabelEncoder
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix

在接下来的教程中,我们将使用可以从 UCI 机器学习知识库中获得的葡萄酒数据集。幸运的是,scitkit-learn库提供了一个包装器函数,用于下载和

wine = load_wine()X = pd.DataFrame(wine.data, columns=wine.feature_names)
y = pd.Categorical.from_codes(wine.target, wine.target_names)

数据集包含 178 行,每行 13 列。

X.shape

特征由各种特征组成,例如酒的镁和酒精含量。

X.head()

有三种不同的酒。

wine.target_names

我们创建一个包含特性和类的数据框架。

df = X.join(pd.Series(y, name='class'))

线性判别分析可以分解为以下步骤:

  1. 计算类内和类间散布矩阵
  2. 计算散布矩阵的特征向量和相应的特征值
  3. 对特征值排序,选择最上面的 k
  4. 创建一个包含映射到 k 特征值的特征向量的新矩阵
  5. 通过对步骤 4 中的数据和矩阵进行点积,获得新的特征(即 LDA 成分)

类内散布矩阵

我们使用以下公式计算类别散布矩阵中的

其中 c 是不同类的总数,并且

其中 x 为样本(即行) n 为给定类别的样本总数。

对于每个类,我们用每个特征的平均值创建一个向量。

class_feature_means = pd.DataFrame(columns=wine.target_names)for c, rows in df.groupby('class'):class_feature_means[c] = rows.mean()class_feature_means

然后,我们将均值向量( mi )代入之前的等式,以获得类内散布矩阵。

within_class_scatter_matrix = np.zeros((13,13))for c, rows in df.groupby('class'):rows = rows.drop(['class'], axis=1)s = np.zeros((13,13))for index, row in rows.iterrows():x, mc = row.values.reshape(13,1), class_feature_means[c].values.reshape(13,1)s += (x - mc).dot((x - mc).T)within_class_scatter_matrix += s

类间散布矩阵

接下来,我们使用下面的公式计算类间散布矩阵的

在哪里

feature_means = df.mean()between_class_scatter_matrix = np.zeros((13,13))for c in class_feature_means:    n = len(df.loc[df['class'] == c].index)mc, m = class_feature_means[c].values.reshape(13,1), feature_means.values.reshape(13,1)between_class_scatter_matrix += n * (mc - m).dot((mc - m).T)

然后,我们求解广义特征值问题

以获得线性判别式。

eigen_values, eigen_vectors = np.linalg.eig(np.linalg.inv(within_class_scatter_matrix).dot(between_class_scatter_matrix))

具有最高特征值的特征向量携带关于数据分布的最多信息。于是,我们将特征值从最高到最低排序,选择第一个 k 特征向量。为了保证排序后特征值映射到同一个特征向量,我们把它们放在一个临时数组中。

pairs = [(np.abs(eigen_values[i]), eigen_vectors[:,i]) for i in range(len(eigen_values))]pairs = sorted(pairs, key=lambda x: x[0], reverse=True)for pair in pairs:print(pair[0])

只看这些值,很难确定每个组件解释了多少差异。因此,我们用百分比来表示。

eigen_value_sums = sum(eigen_values)print('Explained Variance')
for i, pair in enumerate(pairs):print('Eigenvector {}: {}'.format(i, (pair[0]/eigen_value_sums).real))

首先,我们用前两个特征向量创建一个矩阵 W

w_matrix = np.hstack((pairs[0][1].reshape(13,1), pairs[1][1].reshape(13,1))).real

然后,我们把 XW 的点积保存成一个新的矩阵 Y

其中 X 是一个 n×d 矩阵,具有 n 样本和 d 维度, Y 是一个 n×k 矩阵,具有 n 样本和换句话说,是由 LDA 组件组成的,或者换一种说法,新的特征空间。

*X_lda = np.array(X.dot(w_matrix))*

matplotlib不能直接处理分类变量。因此,我们将每个类别编码为一个数字,这样我们就可以将类别标签合并到我们的绘图中。

*le = LabelEncoder()y = le.fit_transform(df['class'])*

然后,我们将数据绘制为两个 LDA 分量的函数,并为每个类别使用不同的颜色。

*plt.xlabel('LD1')
plt.ylabel('LD2')plt.scatter(X_lda[:,0],X_lda[:,1],c=y,cmap='rainbow',alpha=0.7,edgecolors='b'
)*

我们可以使用由scikit-learn库提供的预定义的LinearDiscriminantAnalysis 类,而不是每次都从头开始实现线性判别分析算法。

*from sklearn.discriminant_analysis import LinearDiscriminantAnalysislda = LinearDiscriminantAnalysis()X_lda = lda.fit_transform(X, y)*

我们可以访问下面的属性来获得每个组件解释的方差。

*lda.explained_variance_ratio_*

与之前一样,我们绘制了两个 LDA 组件。

*plt.xlabel('LD1')
plt.ylabel('LD2')plt.scatter(X_lda[:,0],X_lda[:,1],c=y,cmap='rainbow',alpha=0.7,edgecolors='b'
)*

接下来,我们来看看 LDA 与主成分分析或 PCA 相比如何。我们首先创建并装配一个PCA类的实例。

*from sklearn.decomposition import PCApca = PCA(n_components=2)X_pca = pca.fit_transform(X, y)*

我们可以访问explained_variance_ratio_属性来查看每个组件解释的方差的百分比。

*pca.explained_variance_ratio_*

正如我们所看到的,PCA 选择了导致最高分布(保留最多信息)的成分,而不一定是最大化类间分离的成分。

*plt.xlabel('PC1')
plt.ylabel('PC2')plt.scatter(X_pca[:,0],X_pca[:,1],c=y,cmap='rainbow',alpha=0.7,edgecolors='b'
)*

接下来,让我们看看是否可以创建一个模型,使用 LDA 组件作为特征对进行分类。首先,我们将数据分成训练集和测试集。

*X_train, X_test, y_train, y_test = train_test_split(X_lda, y, random_state=1)*

然后,我们建立并训练一个决策树。在预测了测试集中每个样本的类别后,我们创建一个混淆矩阵来评估模型的性能。

*dt = DecisionTreeClassifier()dt.fit(X_train, y_train)y_pred = dt.predict(X_test)confusion_matrix(y_test, y_pred)*

正如我们所看到的,决策树分类器正确地对测试集中的所有内容进行了分类。

线性判别分析(LDA) 101,使用 R

原文:https://towardsdatascience.com/linear-discriminant-analysis-lda-101-using-r-6a97217a55a6?source=collection_archive---------2-----------------------

决策边界、分离、分类等等。让我们潜入 LDA!

Marcin RyczekA man feeding swans in the snow (Aesthetically fitting to the subject)

这是我上一篇关于主成分分析的文章的后续文章,所以如果你喜欢的话可以看看:

[## 主成分分析(PCA) 101,使用 R

一次提高一个维度的可预测性和分类能力!使用 2D 图“可视化”30 个维度!

towardsdatascience.com](/principal-component-analysis-pca-101-using-r-361f4c53a9ff)

如果没有就继续读,我们先处理一个没有 PCA 的案例,然后用 LDA 跟进 PCA-‘转换’数据

在构建你的 LDA 模型之前,用 PCA 进行降维会得到(稍微)更好的结果。

如果你喜欢这篇文章并想看更多,请务必关注我的简介。

设置

对于本文,我们将使用来自 UCI 机器学习报告 的乳腺癌威斯康星州数据集作为我们的数据。如果您想继续学习,请继续为自己加载:

**wdbc** <- read.csv("wdbc.csv", header = F)**features** <- c("radius", "texture", "perimeter", "area", "smoothness", "compactness", "concavity", "concave_points", "symmetry", "fractal_dimension")names(**wdbc**) <- c("**id**", "**diagnosis**", paste0(**features**,"**_mean**"), paste0(**features**,"**_se**"), paste0(**features**,"**_worst**"))

上面的代码将简单地加载数据并命名所有 32 个变量。 ID诊断和十(30)个不同的特征。来自 UCI:

表示标准误差** 以及最差或者最大(三个最大值的平均值)的这些特征被计算用于每个图像,从而得到 30 个特征 。例如,字段 3 是平均半径,字段 13 是半径 SE,字段 23 是最差半径。”****

为什么是艾达?

让我们提醒自己,我们的数据的“点”是什么,我们试图描述肿瘤的什么性质 决定了它是否是恶性的。换句话说:“比如说,如果肿瘤有一定的大小、质地和凹陷,那么它很有可能是恶性的。”

这确实是‘分类’的基本概念,广泛应用于各种数据科学领域,尤其是机器学习

现在,即使你没有读过我关于主成分分析的文章,我相信你也能体会这个图的简单性:

2D PCA-plot showing clustering of “Benign” and “Malignant” tumors across 30 features.

我们在这里看到的是''和' 良性 '这两个类别之间的“清晰”分离,在一个 30 维数据集中只有 ~63%方差的图上。**

简单地使用上面图中的二维,我们可能会得到一些很好的估计,但更高维的数据很难掌握(但也说明了更多的差异),谢天谢地,这就是 LDA 的作用,它会试图找到我们在分类中最成功的“截止点或“决策界限,所以现在我们知道为什么,让我们更好地了解如何:【T21****

只考虑二维两个不同的集群。LDA 会将这些聚类投影到一维。想象它为每个类别/聚类创建单独的概率密度函数,然后我们尝试最大化这些之间的差异(有效地通过最小化它们之间的‘重叠’区域):

From Sebastian Raschka: https://sebastianraschka.com/Articles/2014_python_lda.html

在上面的例子中,我们有一个沿着 x 轴蓝色绿色集群的完美分离。这意味着,如果数据的未来点根据提出的概率密度函数表现,那么我们应该能够将它们完美地分类为蓝色绿色

好了,到此为止,让我们进入 R 并尝试一下!

原始数据的 LDA(所有 30 个维度)

好了,继续节目,让我们从定义数据开始:

****wdbc.data** <- as.matrix(wdbc[,c(3:32)])
row.names(wdbc.data) <- wdbc$id
**wdbc_raw** <- cbind(**wdbc.data**, as.numeric(**wdbc$diagnosis**)-1)
colnames(wdbc_raw)[31] <- "diagnosis"**

这只是简单地将 ID 作为变量移除,并将我们的数据定义为一个矩阵而不是数据框架,同时仍然保留 ID,但是在列名中。

现在我们需要定义一个训练/测试分割,这样我们就有一些数据可以测试我们的模型:

****smp_size_raw** <- floor(0.75 * nrow(**wdbc_raw**))
train_ind_raw <- sample(nrow(wdbc_raw), size = **smp_size_raw**)
**train_raw.df** <- as.data.frame(wdbc_raw[**train_ind_raw**, ])
**test_raw.df** <- as.data.frame(wdbc_raw[**-train_ind_raw**, ])**

这将使用 R 中的 sample() 函数对我们的数据进行 75/25 分割,这非常方便。然后我们将我们的矩阵转换成数据帧

现在我们的数据已经准备好了,我们可以使用【LDA()函数 i R 进行我们的分析,它在功能上与 lm()【glm()函数相同:****

****f** <- paste(names(**train_raw.df**)[31], "~", paste(names(**train_raw.df**)[-31], collapse=" + "))**wdbc_raw.lda** <- **lda**(as.formula(paste(**f**)), data = **train_raw.df**)**

这是一个小小的 lifehack 粘贴所有的变量名,而不是全部手动编写。如果你想看你的 FDA系数组意味着的话,你可以调用对象' wdbc_raw.lda ,但是它相当冗长,所以我不会在本文中发布输出。

现在让我们根据我们的测试数据做出一些预测:

****wdbc_raw.lda.predict** <- predict(**wdbc_raw.lda**, newdata = **test_raw.df**)**

如果你想检查预测,只需调用'wdbc _ raw . LDA . predict $ class'**

估价

这是令人兴奋的部分,现在我们可以看到我们的模型表现有多好

**### CONSTRUCTING ROC AUC PLOT:# Get the posteriors as a dataframe.
**wdbc_raw.lda.predict.posteriors** <- as.data.frame(**wdbc_raw.lda.predict$posterior**)# Evaluate the model
**pred** <- prediction(**wdbc_raw.lda.predict.posteriors**[,2], **test_raw.df$diagnosis**)
**roc.perf** = performance(**pred**, measure = "tpr", x.measure = "fpr")
**auc.train** <- performance(**pred**, measure = "auc")
**auc.train** <- **auc.train**@y.values# Plot
plot(**roc.perf**)
abline(a=0, b= 1)
text(x = .25, y = .65 ,paste("AUC = ", round(**auc.train**[[1]],3), sep = ""))**

我们开始了,一个美丽的大鹏图!在这里,我简单地画出了兴趣点,并添加了图例来解释它。现在,我绘制为“最佳”截止点的点就是我们曲线中具有最低欧几里德距离的点到点 (0,1) 的点,该点表示 100%真阳性率0%假阳性率,这意味着我们有一个完美分离 /预测。

那么这是什么意思?这意味着根据我们希望我们的模型如何“表现”,我们可以使用不同的截止值。我们想要 100%的真阳性率以得到一些假阳性为代价吗?或者,我们希望 0%的假阳性以一个爱真阳性率为代价?如果是良性肿瘤,被诊断为恶性肿瘤会更糟吗?如果是恶性肿瘤,被告知你很健康会更糟吗?

我们的点的 TRP 为 96.15%FPR 为 3.3% 这看起来不错,但我们真的想告诉 3.3%的健康人他们患有癌症3.85%的病人他们很健康吗?

请记住,您的结果肯定会与我的不同,因为进行训练/测试分割的样本方法是随机的。

让我们在 PCA 变换的数据上看一看 LDA,看看我们是否得到一些更好的结果。

基于降维数据(6 维)的 LDA

如果您想继续学习,请阅读我关于 PCA 的文章:

****** [## 主成分分析(PCA) 101,使用 R

一次提高一个维度的可预测性和分类能力!使用 2D 图“可视化”30 个维度!

towardsdatascience.com](/principal-component-analysis-pca-101-using-r-361f4c53a9ff)

好了,我们有了包含 6 个组件的 PCA,让我们创建一个由这些组件和我们的响应组成的新数据集:

**wdbc.pcst** <- **wdbc.pr$x[,1:6]**
**wdbc.pcst** <- cbind(**wdbc.pcst**, as.numeric(**wdbc$diagnosis**)-1)
colnames(wdbc.pcst)[7] <- "diagnosis"

我们将使用完全相同的方法来制作训练/测试分割,所以让我们跳到 LDA预测:

**wdbc.lda** <- **lda**(diagnosis ~ PC1 + PC2 + PC3 + PC4 + PC5 + PC6, data = **train.df**)**wdbc.lda.predict** <- predict(**wdbc.lda**, newdata = **test.df**)

现在,我们可以像以前一样简单地创建我们的 ROC 图,看看我们会得到什么样的结果:

很快,我们得到了一些更好的结果,但这可能仍然是纯粹的运气。

我们必须运行一些模拟并比较这两者!******

比较

现在看你的“运气”你可能会看到 PCA 转换的 LDAAUC 方面比原始 LDA 的 稍好 。然而,这可能只是随机发生的..那么让我们借助于 PCA 变换 LDA原始 LDA** 的 100.000 模拟来做一个快速T-检验😗*******

****t.test(as.numeric(**AUC_raw**),as.numeric(**AUC_pca**))****

AUC_rawAUC_pca 是简单的数组,带有我运行的每次迭代的结果 AUC 分数。

我不会用模拟部分来烦你,因为这是一大块丑陋的代码,所以请相信我!同时查看下面测试结果中的测向计数:

非常低的 p 值,这意味着两者之间存在统计学差异!因此,尽管他们的平均值仅相差 0.000137100.000尾这是一个统计上显著的差异。换句话说:

“在构建你的 LDA 模型之前,用 PCA 进行降维将会得到(稍微)更好的结果!”

因为每篇文章都需要一个花哨的情节:

结束语

如果你想多看多学,一定要 跟着我上 🔍推特 🐦

****** [## 彼得·尼斯特鲁普-中等

阅读彼得·尼斯特拉普在媒介上的作品。数据科学、统计和人工智能...推特:@PeterNistrup,LinkedIn…

medium.com](https://medium.com/@peter.nistrup)******

线性最小二乘法解释得好像你只有两岁

原文:https://towardsdatascience.com/linear-least-square-explained-like-youre-two-1b3eaca70120?source=collection_archive---------33-----------------------

线性最小二乘模型是一种机器学习和统计基础,因为它的可变性和多功能性,在你的武器库中拥有它是很棒的。只要深入研究线性最小二乘模型的表面,就会发现它作为一个模型的多功能性。线性最小二乘法有成百上千种不同的变体,其中最重要的一种从加权最小二乘法到线性最小二乘法回归。

正如我提到的,线性最小二乘模型有成百上千个不同的公式,但最值得注意的可能是你应该知道的。虽然这个列表可能会很不一样,但我还是选择了我认为最具可构建性的版本。此列表包括…

  • 普通最小二乘法
  • 线性最小二乘回归
  • 加权最小二乘法
  • 广义最小二乘

基础知识

定义一个如此多才多艺的模型的问题是,当它做了这么多事情时,很难描述它能做什么。然而,这个模型也有明显的缺点,如果你不是篡改方程的那种人,我当然只会建议偶尔把它用在手边的用例场景中。也就是说,您可以改进基本算法,编写一个非常有趣的算法,不管它是否是您的数据所独有的。

建立在线性最小二乘法基础上的模型的例子包括荣誉提名,如保序回归、迭代加权最小二乘法、工具变量、最佳工具、百分比最小二乘法和总体最小二乘法。

考虑到所有这些不同的模型,可以肯定的是,你应该知道的是线性最小二乘回归。今天有如此多的问题可以用基于回归的算法来解决,以至于这个模型一定会找到它偶尔的主流用途。

线性最小二乘回归示例

当谈到基于推理方程的机器学习模型时,开始伟大学习体验的最佳方式是断言方程。然而,这在教学中最不足的地方是缺乏对如何使用方程的解释。

像这样的等式可能看起来有点吓人,但是分解一下,它很简单,而且是基于斜率的。我们的斜率 m 等于群体大小(n)乘以 x 和 y 的点积之和减去 x 之和乘以 y 之和的乘积。

我没有忘记,我正试图像你们两个一样解释这一点,所以我首先要指出的是,求和(σ)只是将所有值相加的一种奇特方式,换句话说,就是使用 sum()方法。我想指出的另一点是,σxy 是 x 和 y 相加的点积,所以首先我们将两个数组的每个值相乘,然后将结果相加。最后但同样重要的是,当你大声说出σx 和(σx)时,它们听起来是一样的,但σx 是数组总和的点指数,而(σx)只是我们之前的σx,但我们对结果求平方。

这样一来,理解和复制这样一个方程最令人困惑的部分之一就是括号,所以我冒昧地把它写出来,所以希望如果你像我一样更有程序员头脑,这就更容易理解了。

在此基础上构建

我们对每个线性最小二乘公式的核心值了解得越多,我们就越能理解在处理不同数据时,操纵模型如何对我们有利。简而言之,有如此多的变体,你不可能全部学会,但是衍生出你自己的变体是 LLSQ 的真正优势,至少我是这么认为的。

用 Python 实现线性规划和离散优化

原文:https://towardsdatascience.com/linear-programming-and-discrete-optimization-with-python-using-pulp-449f3c5f6e99?source=collection_archive---------0-----------------------

线性和整数规划是离散优化问题的关键技术,它们在现代商业和技术领域几乎无处不在。我们将讨论如何使用 Python 库 PuLP 解决这类问题,并获得一个快速且健壮的解决方案。

介绍

离散优化是优化方法的一个分支,处理离散量,即非连续函数。它在各种各样的应用中无处不在,如金融投资、饮食规划、制造过程、以及职业运动的运动员或赛程选择。

线性和(混合)整数规划是解决问题的技术,这些问题可以在离散优化的框架内公式化。

这种优化技术的知识对数据科学家和机器学习(ML)从业者非常有用,因为离散和连续优化是现代 ML 和 AI 系统以及数据驱动的商业分析流程的核心。

有许多商业优化工具,但拥有以编程方式进行优化的实践经验是非常宝贵的。

针对优化问题的强大而高效的求解器的理论发展有着悠久而丰富的历史。然而,着眼于实际应用,我们将跳过这段历史,直接进入学习如何使用编程工具来制定和解决这种优化问题的部分。

Python 中有很多优秀的优化包。在本文中,我们将具体谈谈纸浆。但是在使用 Python 库之前,让我们先了解一下我们可以用它来解决什么样的问题。

一个(或两个)例题

假设你负责高中午餐的饮食计划。你的工作是确保学生从选择的食物中获得正确的营养平衡。

然而,在预算和食物种类方面有一些限制,需要在饮食中使其有趣。下表详细显示了每种食物的完整营养价值,以及它们的最大/最小日摄入量。

离散优化问题很简单:在给定这些约束条件(总热量以及每种营养成分,如胆固醇、维生素 A、钙等)的情况下,最小化午餐成本。

本质上,用一种随意的数学语言来说,问题是,

请注意,不等式关系本质上都是线性的,即变量 f 乘以常系数,所得项受常数极限的限制,这使得该问题可通过 LP 技术解决。

你可以想象这种问题在商业战略中可能会极其频繁地冒出来。取代营养价值的是利润和其他类型的商业收益,取代价格/服务的可能是数千美元的项目成本。作为一名经理,你的工作将是选择项目,在不超过项目资金总预算的情况下,获得最大的投资回报。

类似的优化问题也可能出现在工厂生产计划中,其中最大生产能力将是所用机器的函数,并且单个产品将具有不同的利润特征。作为一名生产工程师,你的工作可能是仔细分配机器和劳动力资源,以最大限度地提高利润,同时满足所有的能力限制。

从根本上说,来自不同领域的这些问题之间的共性在于,它们涉及最大化或最小化线性 目标函数 ,服从一组线性 不等式或等式约束

对于饮食问题,目标函数是我们试图最小化的总成本。不等式约束由每个营养成分的最小和最大界限给出。

PuLP——用于线性优化的 Python 库

Python 生态系统中有许多针对这类优化问题的库。纸浆是一个开源的 线性编程 (LP)包,它大量使用 Python 语法,并附带了许多行业标准的解算器。它还可以很好地与一系列开源和商业 LP 求解器集成。

您可以使用 pip(以及其他一些解算器)来安装它

$ sudo pip install pulp            *# PuLP* $ sudo apt-get install glpk-utils  *# GLPK* $ sudo apt-get install coinor-cbc  *# CoinOR*

关于安装和测试的详细说明在这里。然后,从库中导入所有内容。

from pulp import *

在这里看一个很好的解决线性规划的视频。

最优化问题如何公式化?

首先,我们用 PuLP 中的方法**LpProblem**创建一个 LP 问题。

prob = LpProblem("Simple Diet Problem",LpMinimize)

然后,我们需要用表中的信息创建一堆 Python 字典对象。代码如下所示,

为了简洁起见,我们没有在这里展示完整的代码。你可以把所有的营养成分都拿出来,为它们创建单独的字典。

然后,我们创建一个食品项目变量字典,其中下界=0类别连续,即优化解决方案可以采用任何大于零的实数。

注意下界的特殊重要性。

在我们的头脑中,我们不能认为食物的一部分是一个非负的有限的量,但是数学并不知道这一点。

没有这个界限的明确声明,解决方案可能是无意义的,因为求解者可能试图提出负的食物选择量来减少总成本,同时仍然满足营养需求!

food_vars = LpVariable.dicts("Food",food_items,**lowBound=0,cat='Continuous'**)

接下来,我们通过添加主目标函数开始构建 LP 问题。注意**lpSum**方法的使用。

prob += lpSum([costs[i]*food_vars[i] for i in food_items])

我们在此基础上进一步增加了热量限制,

prob += lpSum([calories[f] * food_vars[f] for f in food_items]) >= 800.0
prob += lpSum([calories[f] * food_vars[f] for f in food_items]) <= 1300.0

我们可以把所有的营养限制堆积起来。为了简单起见,我们只是增加了脂肪、碳水化合物、纤维和蛋白质的四个限制。代码如下所示,

我们已经解决了这个问题!

在任何优化场景中,困难的部分是以一种结构化的方式表述问题,这种方式可以呈现给求解者。

我们已经完成了最困难的部分。现在,这是运行求解器和检查解的相对容易的部分。

解决问题并打印解决方案

纸浆有相当多的求解器算法选择(如 COIN_MP,Gurobi,CPLEX 等。).对于这个问题,我们不指定任何选项,让程序根据问题结构默认自己的选择。

prob.solve()

我们可以打印溶液的状态。注意,尽管在这种情况下状态是最佳,但并不需要如此。如果问题是不适定的或者没有足够的信息,解决方案可能不可行或者无界

# The status of the solution is printed to the screen
print("Status:", LpStatus[prob.status])>> Status: Optimal

完整解包含所有变量,包括权重为零的变量。但是对我们来说,只有那些具有非零系数的变量才是感兴趣的,也就是说,那些变量应该包含在最佳饮食计划中。所以,我们可以扫描问题变量,只有变量数量为正数时才打印出来。

for v in prob.variables():if v.varValue>0:print(v.name, "=", v.varValue)>> Food_Frozen_Broccoli = **6.9242113**Food_Scrambled_Eggs = **6.060891**Food__Baked_Potatoes = **1.0806324**

所以,最佳方案是吃 6.923 份冷冻西兰花,6.06 份炒鸡蛋和 1.08 份烤土豆!

欢迎你下载整个笔记本,数据文件,用各种约束来实验改变你的饮食计划。代码在我的 Github 库里。

最后,我们可以打印出目标函数,即饮食成本

obj = value(prob.objective)
print("The total cost of this balanced diet is: $**{}**".format(round(obj,2)))>> The total cost of this balanced diet is: $5.52

如果我们想要一个整数解呢?

正如我们所看到的,最佳结果返回了一组食物的分数。这可能是不切实际的,我们可能希望解决方案强制只有整数数量的服务。

这就给我们带来了 整数规划 的技巧。用于先前优化的算法是简单的线性规划,其中允许变量采用任何实数值。整数编程强制某些或所有变量仅采用整数值。

事实上,整数规划是一个比线性规划更难的计算问题。整数变量使得优化问题非凸,因此更难解决。随着您添加更多的整数变量,内存和求解时间可能会呈指数增长。

幸运的是,纸浆也可以解决这种限制的优化问题。

代码和之前几乎一模一样,这里不再赘述。唯一的区别是变量被定义为属于**Integer**类别,而不是**Continuous**

food_integer = LpVariable.dicts("Food",food_items,0,cat='Integer')

对于这个问题,它稍微改变了最优解,在饮食中加入了卷心莴苣,成本增加了 0.06 美元。您还会注意到求解过程的计算时间明显增加。

Therefore, the optimal balanced diet with whole servings consists of
--------------------------------------------------------------------
Food_Frozen_Broccoli = **7.0**
Food_Raw_Lettuce_Iceberg = **1.0**
Food_Scrambled_Eggs = **6.0**
Food__Baked_Potatoes = **1.0**

整数规划的一个很酷的应用是解决一个 司机调度问题 ,这可能是一个 NP-hard 问题。见这篇文章(也请注意文章中,他们如何计算各种行动的成本,并在优化问题中使用它们),

[## 工程师整数编程导论:简化的总线调度

本文是 Remix 关于我们面临的软件工程问题的系列文章的一部分。在这一期中,重新混合…

blog.remix.com](https://blog.remix.com/an-intro-to-integer-programming-for-engineers-simplified-bus-scheduling-bd3d64895e92)

如何将二元决策合并到线性规划问题中?

通常,我们希望在优化问题中包含某种“如果-那么-否则”的决策逻辑。

如果我们不希望西兰花和卷心莴苣都包含在饮食中(但只有其中一种是好的)怎么办?

我们如何在这个框架中表示这样的决策逻辑?

事实证明,对于这种逻辑,您需要引入另一种类型的变量,称为指示变量。它们本质上是二元的,并且可以指示最优解中变量的存在或不存在。

[## 将指示函数作为约束包含在 LP 问题中

感谢为数学栈交换贡献一个答案!请务必回答问题。提供详细信息…

math.stackexchange.com](https://math.stackexchange.com/questions/2220355/involving-indicator-function-as-a-constraint-in-a-lp-problem)

但是对于这个特殊的问题,使用指示变量有一个明显的问题。理想情况下,如果指标变量为 1,您希望食品的成本/营养价值包含在约束等式中,如果为零,则忽略它。从数学上来说,将此写成原始术语(涉及食品项目)和指示变量的乘积是很直观的。但是当你这样做的时候,你就把两个变量相乘,使问题变成非线性的!在这种情况下,它属于 二次规划 (QP)的范畴(二次因为现在项是两个线性项的乘积)。

流行的机器学习技术支持向量机本质上解决了二次规划问题。

[## 什么是二次规划的直观解释,在 SVM 是怎么定义的?

答:二次规划包括最小化未知向量的分量为二次的形式…

www.quora.com](https://www.quora.com/What-is-an-intuitive-explanation-of-quadratic-programming-and-how-is-it-defined-in-SVM)

然而,在线性规划问题中使用指示符变量来表示二进制逻辑的一般概念也是非常有用的。在下一节中,我们给出了一个用 LP 解决数独难题的链接。

事实证明,有一个聪明的技巧可以将这样的二进制逻辑合并到这个 LP 中,而不会使它成为 QP 问题。

我们可以将二进制变量表示为food_chosen,并将它们实例化为Integer,上下界分别为 0 和 1。

food_chosen = LpVariable.dicts("Chosen",food_items,0,1,cat='Integer')

然后我们编写一个特殊的代码来链接通常的food_vars和二进制的food_chosen,并将这个约束添加到问题中。

**for** f **in** food_items:prob += food_vars[f]>= food_chosen[f]*0.1prob += food_vars[f]<= food_chosen[f]*1e5

如果你盯着代码足够长的时间,你会意识到这实际上意味着只有当相应的food_chosen指示变量为 1 时,我们才赋予food_vars重要性。但这样我们就避免了直接乘法,保持了问题结构的线性。

为了包含花椰菜和卷心莴苣的非此即彼条件,我们只需输入一个简单的代码,

prob += food_chosen['Frozen Broccoli']+food_chosen['Raw Iceberg Lettuce']<=1

这确保了这两个二元变量的和最多为 1,这意味着它们中只能有一个包含在最优解中,而不能两个都包含。

线性/整数规划的更多应用

在本文中,我们展示了用 Python 建立和解决一个简单的线性编程问题的基本流程。然而,如果你环顾四周,你会发现无数的工程和商业问题的例子可以转化为某种形式的线性规划,然后使用高效的解决方案来解决。下面是一些典型的例子,让你开始思考,

  • 解决数独的 LP 问题
  • 将长期投资回报最大化作为 LP 问题
  • LP 应用于生产计划
  • 使用 ILP 解决仓库选址问题

许多机器学习算法也使用线性规划为子集的优化的一般类别— 凸优化 。有关它的更多信息,请参阅下面的文章,

[## 下面是什么?机器学习的核心是优化

我们展示了最流行的机器学习/统计建模技术背后的核心优化框架。

towardsdatascience.com](/a-quick-overview-of-optimization-models-for-machine-learning-and-statistics-38e3a7d13138)

总结和结论

在本文中,我们展示了使用 Python package PuLP 通过线性和整数编程技术解决一个简单的饮食优化问题。值得注意的是,即使是广泛使用的 SciPy 也内置了线性优化方法。鼓励读者尝试各种其他 Python 库,并为自己选择一个好方法。

喜欢这篇文章吗?成为 中等成员 继续 无限制学习 。如果你使用下面的链接,我会收到你的一部分会员费, 而不增加你的额外费用

[## 通过我的推荐链接加入媒体

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@tirthajyoti/membership)

数据科学家的线性编程

原文:https://towardsdatascience.com/linear-programming-for-data-scientists-e9cf1ddf1331?source=collection_archive---------6-----------------------

作为数据科学家,我们在职业生涯的早期就熟悉了优化的概念。优化是每个机器学习模型的核心。但是我们与优化的关系可以追溯到很久以前;自从我们有记忆以来,我们就在不知不觉中解决最优化问题:

  • 去上班最快的方法
  • 组织我们的预算以获得最大收益
  • 规划训练,在最短的时间内获得最大的效果
  • 每个星期天都要做饭
  • 为漫长的假期打包行李

这些只是日常优化的几个例子。优化是生活方式。它可以像我刚才提到的例子一样简单,也可以像旅行推销员问题一样复杂。

数学优化 是在给定一些约束条件的情况下,从一组可用的备选方案中选择最佳备选方案的问题。一个优化问题有三个基本组成部分:(1)一个目标函数,我们要么最大化要么最小化它;(2)控制目标函数的一组变量;(3)一组约束,允许变量取某些值,同时排除其他值。

因此,优化问题是找到最大化或最小化目标函数的变量的值集,同时满足约束集。

线性规划是数学优化的主要分支之一。这也是解决优化问题的最简单的方法之一。

什么是线性规划?

我先说一下,这里的编程不是指计算机编程。 线性规划 —又名是一种在数学模型中寻找最佳结果的技术,其中目标函数约束线性关系表示。****

为了用公式表示一个线性程序,我们需要理解它的各部分的概念。

  1. 决策变量:我们想要确定的。未知数
  2. 目标函数:代表最大化或最小化数量的线性函数。
  3. 约束:代表决策变量限制的等式或不等式系统。
  4. 非负性限制:决策变量的值应该大于或等于零。

解决线性规划问题

根据上面的四个定义,我们可以一般地建立一个解决 LP 问题的过程:

  1. 识别决策变量
  2. 确定目标函数
  3. 指定约束
  4. 陈述非消极限制

解决一个线性规划问题有几种不同的方法:T2 图解法、傅立叶-莫茨金消元法、单纯形法、十字交叉算法、卡玛卡尔算法等等。也有一些商业和开源软件可供选择:Gurobi,CPLEX,MATLAB,SAS,GAMS,Mathematica, PuLP , Pyomo , SciPy ,是可用内容的一些例子。

通过实例学习——使用纸浆的实用教程

让我们看一个基于运输问题的例子,这是线性规划模型的最初应用之一。

以下摘自 Juraj Stacho 著 运筹学导论:

一家家具公司在纽约地区拥有三个仓库,需要在明天将椅子运送到该市的三家商店。这三家商店分别需要 4、2 和 3 个单位。三个仓库中椅子的当前库存水平分别为 8、6 和 3。由于距离不同,每个仓库到每个门店的配送成本也不同。寻找将椅子运送到商店的最便宜方式。

公式化线性问题:

  • 决策变量:从第仓库运送到第店铺的椅子数量****
  • 来源:三个仓库
  • 目的地:三家商店
  • 约束:来自第仓库的供应,来自第商店的需求****
  • 目标:最小化总运输成本

Information for the Transportation Problem

因为只有当supply = demand一个虚拟需求变量被创建时,解决方案才存在。下面是使用 PuLP 库解决这个 LP 问题的代码。

结论

优化对于调查复杂问题、识别和解决问题以及数据驱动的决策至关重要。此外,理解最优化理论对于数据科学这门手艺来说是必不可少的。许多实际问题可以用数学优化技术来建模和解决,其中输入和约束是从机器学习模型的预测中获得的-但这只是一个新手数据科学家的一个想法。

R 线性规划

原文:https://towardsdatascience.com/linear-programming-in-r-444e9c199280?source=collection_archive---------5-----------------------

r 代表工业工程师

探索“LP solve”R

Image by Arnold Francisca available at Unsplash

运筹学

运筹学是一种科学的决策方法,通常在需要分配稀缺资源的条件下,寻求系统的最佳设计和操作。制定决策的科学方法需要使用一个或多个数学/优化模型(即实际情况的表示)来做出最佳决策。

优化模型寻求在满足给定 约束 的决策变量的所有值的集合中找到优化(最大化或最小化) 目标函数决策变量 的值。它的三个主要组成部分是:

  • 目标函数:要优化的函数(最大化或最小化)
  • 决策变量:影响系统性能的可控变量
  • 约束:决策变量的一组限制(即线性不等式或等式)。非负约束限制决策变量取正值(例如,您不能产生负的项目数 x 1、 x 2 和 x 3)。

优化模型的解称为最优可行解

建模步骤

精确地模拟一个运筹学问题是最重要的——有时也是最困难的——任务。一个错误的模型将导致一个错误的解决方案,因此,不会解决原来的问题。以下步骤应该由具有不同专业领域的不同团队成员执行,以获得模型的准确和更好的视图:

  1. 问题定义:定义项目的范围,确定结果是三个要素的确定:决策变量的描述、目标的确定和限制条件(即约束条件)的确定。
  2. 模型构建:将问题定义转化为数学关系。
  3. 模型求解:使用标准优化算法。在获得解决方案后,应进行敏感性分析,以找出由于某些参数的变化而导致的解决方案的行为。
  4. 模型有效性:检查模型是否如预期的那样工作。
  5. 实施:将模型和结果转化为解决方案的建议。

线性规划

线性规划(也称为 LP)是一种运筹学技术,当所有目标和约束都是线性的(在变量中)并且所有决策变量都是连续的时使用。在层次结构中,线性规划可以被认为是最简单的运筹学技术。

来自 R 的 lpSolve 包包含了几个用于解决线性规划问题和获得重要统计分析的函数。对于下面的例子,让我们考虑下面要求解的数学模型:

我们来看看 R 代码!

Linear Programming R Code

解决方案:

在满足给定约束的情况下可以获得的最大 z 值(因此也是最优值)是 46,其中 x 1 = 5, x 2 = 3。敏感系数从 4.667 和 5.0 到 7.0 和 7.5。约束的影子/对偶价格分别为 0、2 和 1,而决策变量的影子/对偶价格分别为 0 和 0。约束条件的影子/双重价格下限分别为-1.0e+30、1.6e+01 和 6.3e+00,而决策变量分别为-1.0e+30 和-1.0e+30。最后,约束的影子/双重价格上限分别为 1.0e+30、2.4e+01 和 9.5e+00,而决策变量的上限分别为 1.0e+30 和 1.0e+30。

总结想法

线性规划代表了一个更好的决策制定的伟大的优化技术。 lpSolve R 包允许用几行代码解决线性规划问题并获得重要的统计信息(即敏感性分析)。虽然有其他免费的优化软件(如 GAMS、AMPL、TORA、LINDO),但在您的个人代码库中存储一个线性优化 R 代码可以节省您大量的时间,因为您不必从头开始编写公式,而只需更改相应矩阵的系数和符号。

确认

特别感谢édgar Granda博士在线性编程课程和我作为工业和系统工程师本科生的学术生涯中的所有教导。

— —

如果你觉得这篇文章有用,欢迎在 GitHub 上下载我的个人代码。也可以直接发邮件到rsalaza4@binghamton.edu找我,在LinkedIn找我。有兴趣了解工程领域的数据分析、数据科学和机器学习应用的更多信息吗?通过访问我的媒体 个人资料 来探索我以前的文章。感谢阅读。

——罗伯特

线性回归

原文:https://towardsdatascience.com/linear-regression-70cca59678ec?source=collection_archive---------30-----------------------

更简单直观的解释。

线性回归是一种著名的监督学习算法,用于预测实值输出。线性回归模型是输入示例特征的线性组合。

A note on the notation. *x_{i}* means x subscript i and *x_{^th}* means x superscript th.

数据的表示

如定义中所述,线性回归是一种监督学习算法,因此,有一组 N 标记的示例,表示为:

Data used to construct a linear regression model.

这里, x_{i} 表示对应于 i_{^th} 示例的一组属性。这些属性集合统称为特征向量。所有来自 i=1,2,3,…,n 的例子都有一个对应的实值 y,表示一个物理量,如成本、温度或任何其他连续值。

Here each feature vector is 3-dimensional consisting of the area of house in square metres, the number of rooms and the age of house in years. The target variable is the price of house in USD.

模型

现在,我们已经准备好了我们的例子,我们想要制作我们的模型 f(x) 来帮助我们预测未知的x的输出 y

Model of linear regression learning algorithm. Here, w is an R-dimensional parameter vector (x is an R-dimensional feature vector) and bis the bias.

模型的工作是预测特征向量 x. 的未知值的真实值 y ,但是,我们想要找到一个模型,使得它在预测 y 的值方面做得最好,因此,我们想要找到 wb 的值,使得预测尽可能接近实际答案。很明显, wb 的不同值会导致生产不同型号、不同能力的产品。因此,我们的工作是找到值 w* 和 b* 的最优集合,该集合将最小化模型 f(x) 所做的预测与训练集的实际结果 y 之间的误差。

最佳模特

如前所述,我们有 N 个示例和一个模型 f(x) ,我们需要找到 wb 的最佳值。让我们使用所有这些 N 示例来找到 wb 的最佳值,通常称为训练我们的模型我们需要找到 wb 的值,使得下面的表达式最小。

Cost function for linear regression.

这是我们的目标函数,因为我们要将其最小化。学习算法具有我们试图最小化或最大化的功能。这些函数被称为损失函数成本函数。这种特殊形式被称为均方误差损失函数。

如果你观察损失函数:

  • 就是简单的减去模型的输出, f(x_{i}) 和实际输出 y_{i}
  • 把它摆正,
  • 最后取其平均值。

为了更好地理解这一点,让我们假设约翰最近参加了一个有 10 道数学问题的考试,并且答案已经公布。现在约翰决定看看他的表现如何?于是,他将自己的答案 f(x)_{i} 与答案键上对应的答案 y_{i} 进行了比较。如果约翰的答案和实际答案 f(x){i}-y 之差是 0 他就答对了那个问题。如果他正确回答了所有问题,那么平均值也将是 0 ,这对应于最佳性能,意味着最佳型号。平方误差有助于强调模型的误差。我们也可以取一个立方或者更高的幂,但是这样导数就更难计算了。我们担心成本函数的导数,因为将它们设置为零给出了模型的最佳值 w* 和 b* 。

一般问题和示例

让我们讨论一下在学习线性回归时困扰我的几个问题。但是,在我们开始之前,让我们看看一个非常原始的线性回归的例子。

因此,约翰和他的朋友们决定从头开始研究线性回归,所以他们开始自己收集样本。他们收集的例子如下所示。

The tabular form of data. Here x is a single dimensional feature vector any y is a real-valued output corresponding to each feature vector.

收集完数据后,John 决定用线性回归模型来拟合数据。

The linear regression model of form f(x)=wx+b.

这是形式为 f(x)=wx+b 的模型,其中 w 是标量,因为 x,特征向量是一维的。更好地理解这个模型是将它与直线方程 y=mx+c 进行比较,其中 m 类似于 wcb。这是一个线性模型。

但是,我们能做得更好吗?我们能想出一个比现在的表现更好的模型吗?是的,我们可以。线性回归只包含直线模型,这是一种常见的混淆。然而,我们也可以通过转换数据来拟合曲线。让我们通过平方每个 x_{i} 值来转换我们的特征向量。

在转换了我们的特征向量之后,让我们尝试在新的特征向量 x 和输出 y 上拟合模型(原始特征向量 x 不被考虑用于训练模型,它的转换 x_{^ 2} 已经被用于训练模型)。

The model is a better fit than the previous linear model. Here the original feature vector x_{i} is transformed to it’s square and then the model is computed.

因此,现在我们通过将原始特征向量 x_{i} 变换为其平方,预测了一个比线性模型更好的多项式模型。新模型对应于f(x)= wx+b。

This is a plot of the polynomial regression model. Note that this plot is between X and Y with the polynomial model of degree two. The previous plot was between X² and Y, therefore, it was linear.

通过转换特征向量,模型预测更好结果的能力有所提高,但我们需要注意过度拟合。当模型在训练阶段预测得太好,但在预测看不见的示例时出错时,会发生过度拟合。过度拟合不能反映动态的真实情况。它不产生一般化的模型。

This is an example of overfitting where the model is too accurate on the training examples.

假设特征向量是 R 维的。我们已经看到了 R=1 的情况,也预测了线性和多项式模型。如果 R=2,则预测一个平面作为模型。通常,线性回归用 R 维特征向量 x 和 1 维输出 y 为数据集建模超平面。

超平面是一个比其周围空间的维度少一个维度的子空间。在 1 维线的情况下,是超平面,在 2 维区域的情况下,线是超平面,在 3 维空间的情况下,平面是超平面,依此类推。

偏差项

让我们讨论一下偏差项的效用。考虑直线的方程 y=mx 。在这种情况下, m 控制直线的斜率,可以在任何地方旋转直线,但只能围绕原点旋转。

假设您决定将这个模型用于一个简单的线性回归问题。然而,你产生的任何假设总是会通过原点,可能无法一般化。添加偏置项将导致假设 y=mx+c ,从而允许您在平面内的任何地方移动线。偏差项有助于概括假设。

线性回归

原文:https://towardsdatascience.com/linear-regression-91eeae7d6a2e?source=collection_archive---------9-----------------------

最大似然估计和最小平方和的统一。

介绍

我最近在我正在进行的机器学习基础系列中写了关于最大似然估计的文章:

[## 最大似然估计

机器学习基础(二)

towardsdatascience.com](/maximum-likelihood-estimation-984af2dcfcac)

在那篇文章中,我们学习了“建模”数据的含义,以及如何使用 MLE 来查找模型的参数。在这篇文章中,我们将深入线性回归,统计学中最重要的模型之一,并学习如何用最大似然法来构建它。解决方案是一个美丽的数学,像大多数 MLE 模型一样,充满了直觉。我假设您已经掌握了我在其他系列中涉及的词汇(概率密度、条件概率、似然函数、iid 数据等)。).如果你在这里看到一些让你不舒服的东西,看看那个系列的概率和最大似然的帖子就清楚了。

模型

当我们的数据在自变量(我们的特征)和因变量(我们的目标)之间有线性关系时,我们使用线性回归。在 MLE 的帖子中,我们看到了一些看起来类似的数据:

我们观察到 x 和 y 之间似乎有线性关系,但并不完美。我们认为这些缺陷来自一些错误或噪声过程。想象一下在点云上画一条直线。每个点的误差就是该点到我们直线的距离。我们希望在模型中明确包含这些错误。一种方法是假设误差服从均值为 0 且方差σ未知的高斯分布。高斯似乎是一个不错的选择,因为我们的误差看起来是对称的,而且小误差比大误差更有可能出现。我们用高斯噪声写出线性模型,如下所示:

Linear model with Gaussian noise term.

误差项从我们的高斯方程中提取,然后通过将误差加到线性方程的输出中,计算出我们观察到的 y。这个模型有三个参数:我们的线的斜率和截距以及噪声分布的方差。我们的主要目标是找到直线斜率和截距的最佳参数。

似然函数

为了应用最大似然,我们首先需要导出似然函数。首先,让我们将上面的模型重写为给定 x 的单个条件分布:

Given x, y is drawn from a Gaussian centered on our line.

这相当于将我们的 x 通过直线的方程,然后加入来自 0 均值高斯的噪声。

现在,我们可以用这个高斯函数写出给定 x 的 y 的条件分布。这只是高斯分布的概率密度函数的方程,用我们的线性方程代替平均值:

PDF of y given x and our linear model.

条件分布中的分号就像一个逗号,但它是一个有用的符号,用于将我们观察到的数据与参数分开。

每个点都是独立同分布的(iid ),因此我们可以将所有观察点的似然函数写成每个个体概率密度的乘积。由于σ对于每个数据点都是相同的,因此我们可以从乘积中剔除不包括 x 或 y 的高斯项:

Likelihood for our collection of data X.

(注:此处感谢同心抓错。乘积之前的项应该提高到数据点的数量,因为我从乘积中分解了它。)

对数可能性:

最大似然法的下一步是找到使该函数最大化的参数。为了使我们的等式更简单,让我们取可能性的对数。回想一下,最大化对数似然性与最大化似然性是相同的,因为对数是单调的。自然对数与指数相抵消,把乘积变成对数的和,把除法变成对数的减法;所以我们的对数似然看起来简单多了:

Derivation of log-likelihood for our model.

误差平方和:

为了更清楚起见,让我们将这一行的输出写成一个值:

Estimate of y from our line.

现在我们的对数似然可以写成:

Simplified log-likelihood equation.

为了去掉负号,让我们回忆一下,最大化一个数和最小化这个数的负数是一回事。因此,与其最大化可能性,不如最小化负对数可能性:

Minimize the negative log-likelihood.

我们的最终目标是找到我们生产线的参数。为了最小化线性参数(θs)的负对数似然,我们可以假设方差项是一个固定常数。

去掉任何不包括θ的常数都不会改变解。因此,我们可以抛开任何常数项,优雅地将我们试图最小化的内容写成:

Sum of squared error.

线性模型的最大似然估计是使误差平方和最小的那条线!这是一个漂亮的结果,你会看到最小化平方误差在机器学习和统计中随处可见。

求解参数

我们已经得出结论,斜率和截距的最大似然估计可以通过最小化误差平方和得到。让我们扩展我们的最小化目标,并使用 i 作为我们的 n 个数据点的索引:

SSE 公式中的平方使其成为具有单一最小值的二次型。可以通过对每个参数求导,将其设置为 0,并依次求解参数来找到最小值。

截距:

让我们从求解截距开始。对截距求偏导数,我们得到:

Derivative of SSE with respect to the intercept of our line.

变量上方的横条表示这些变量的平均值。我们利用了这样一个事实:变量值的和等于这些值的平均值乘以我们有多少个值。将导数设为 0 并求解截距,得到:

MLE for intercept.

这是一个非常好的结果。这是直线方程,用 x 和 y 的平均值代替了那些变量。截距仍然取决于斜率,所以我们接下来需要找到它。

坡度:

我们首先对 SSE 的斜率求偏导数。我们插入截距的解,并使用代数来分离斜率项:

Derivative of SSE with respect to the slope of our line.

将该值设为 0 并求解斜率,得到:

虽然我们在技术上已经完成了,但我们可以使用一些更好的代数来重写,而不必使用 n :

MLE estimate of the slope.

将所有这些放在一起:

我们可以使用这些推导出的方程,用 python 编写一个简单的函数,用于在给定至少两点的情况下求解任何线的参数:

def find_line(xs, ys):"""Calculates the slope and intercept"""# number of pointsn = len(xs) # calculate meansx_bar = sum(xs)/ny_bar = sum(ys)/n# calculate slopenum = 0denom = 0for i in range(n):num += (xs[i]-x_bar)*(ys[i]-y_bar)denom += (xs[i]-x_bar)**2slope = num/denom# calculate interceptintercept = y_bar - slope*x_barreturn slope, intercept

使用这个代码,我们可以拟合一条线到我们的原始数据(见下文)。这是我们数据的最大似然估计。该线使误差平方和最小,这就是为什么这种线性回归方法通常被称为普通最小二乘法。

MLE solution to our Linear Regression model.

最后的想法

我写这篇文章主要是为了强调最小化误差平方和与线性回归的最大似然估计方法之间的联系。大多数人首先学习通过最小化平方误差来解决线性回归,但人们通常不理解这是从带有假设的概率模型(如高斯分布误差)中得出的。

有一个更优雅的解决方案来寻找这个模型的参数,但它需要线性代数。在我的基础系列中介绍了线性代数之后,我打算再次讨论线性回归,并展示如何用它来拟合更复杂的曲线,如多项式和指数。

下次见!

线性回归和一瓶优质葡萄酒

原文:https://towardsdatascience.com/linear-regression-and-a-quality-bottle-of-wine-b053ab768a53?source=collection_archive---------9-----------------------

一个线性回归像品酒师一样预测一瓶酒的质量?请继续阅读,寻找答案。

Photo by Scott Warman on Unsplash

统计数据比我们想象的更能左右我们的生活。在一次糟糕的表现之后,你可能会表现得更好。这是弗朗西斯·高尔顿创造的一个术语,叫做“回归”。他比较了祖先和后代的身高,发现他们的身高更接近平均值。对于一个人在数学考试中的分数也可以做出同样的推论。如果你的数学考试成绩很差,那么根据回归分析,你应该在下一次数学考试中取得好成绩。

Bell curve

钟形曲线表示样本 n 的正态分布,其中 u 是平均值。回归表示 X 轴上的数据倾向于向平均值回归。

今天,回归算法被用来解决众多问题,这些问题涉及从统计学(这是其母领域)到股票市场前沿人工智能技术的各种应用。也许回归的最佳用途是在数据分析领域。

同样的模型也可以用来预测葡萄酒的质量。遵循以下方程的广义线性回归:

β0 是截距,β1…βn 是回归系数。现在,请记住,因为我们在这里使用多个变量,这意味着我们在多维超平面上解释数据。

广义线性回归假设因变量(本例中为 Y)与自变量(X1)具有线性关系..p)。因此,如果我们假设一个二维数据集(X1 和 Y),它会像下面的图像。

Linear regression for one dependent variable and independent variable

记住‘红线’是假设线,数据点是实际数据点。当模型拟合时,假设关系是线性的,这意味着假设数据拟合在红线附近。首先,我们需要从 UCI 存储库中收集数据集。先决条件是您已经安装了 python、spyder 和下面指定的其他软件包:

为了提取数据,我们使用 pandas 并将我们的特征(自变量)分配给 X,将因变量分配给 y。

Extracting variables using pandas

相关性 是一种统计技术,可以显示变量对的相关程度。我们使用这些变量来绘制一张热图,用来表示预测关系。我们发现每个特征是如何相互关联的。必须注意,特征之间的相关性并不意味着因果关系。例如,特征与其自身之间的相关系数(r) 等于 1。在所有其他情况下,相关性往往小于 1。相关系数也可以在特征之间具有相反的关系,在这种情况下,相关系数将等于-1。r 越接近+1 或-1,这两个变量的关系就越密切。

Heat-map of both dependent and independent variables

接下来,我们使用 seaborn 来绘制 x 中所有可用特性的特性与质量图。

Feature vs Quality plots for features of X

我们已经假设模型是线性的。现在数据集需要分成训练和测试数据,为此我们使用了 Scikitlearn 的 model_selection 模块。之后我们剩下要做的就是训练我们的线性回归模块。可以通过 x_train 使用 LinearRegression 类对其进行训练,也可以通过 x_test 对其进行测试。我们使用拟合方法来确定数据的中心,因为数据已经缩放,我们在这里不应用变换方法。

线性模型的估计是借助均方根误差或均方根偏差来完成的。

RMSE for sample n

线性回归技术的精度RMSE(均方根误差)RMSD (均方根偏差)用于决定算法的平滑程度。

所以 RMSE 是 0.4,老实说,也很糟糕,这个模型的精度只有 34.4%。这个模型突出了一些主要的瓶颈,这些瓶颈是在人工智能的早期科学家们无法根据质量对特征进行分类的时候研究人员遇到的。一些特征与因变量 Y 有很强的相关性,但这并不意味着该特征会导致 Y 的改善。也许,这就是我们在方法中所遗漏的。我们采用这些特征,并认为因为热图暗示了一种关系,所以该特征一定很强,但相关性并不暗示因果关系

酒的质量是一个**的定性变量,这也是算法没有做好的另一个原因。重要的是要注意,线性回归模型与定量方法相对比,与定性方法更好。当我们不能决定一个变量是否比另一个更好时,变量可以被归类为定性变量。比如:蓝色是否大于绿色?不。这意味着像决策树、随机森林这样的算法可以很好地用于葡萄酒质量的分类。让我们把它们留到下次吧。

干杯!

注意:作者不拥有 UCI 知识库提供的数据集。作者感谢数据集的所有者保持数据集开源。

线性回归和继承线

原文:https://towardsdatascience.com/linear-regression-and-lines-of-succession-451569c39016?source=collection_archive---------11-----------------------

计算机如何思考:第二部分

自从征服者威廉在 1066 年圣诞节加冕以来,英格兰和后来的大不列颠已经有近 50 位王位继承人,他们都试图在这个国家和她的人民的历史上留下自己的名字,并取得了不同程度的成功。其中,只有 36 位国王和 5 位王后被认为是具有任何合法性的君主。但是这些统治的时间长短不一。少年国王爱德华五世只统治了 86 天,直到他的突然消失为他的叔叔理查德登上王位扫清了道路。截至 2015 年 9 月,我们的现任女王在位 65 年(还在继续),是英国或英格兰君主中在位时间最长的。

Those are rookie numbers, Edward

想象一下,如果每个君主登上王位,我们可以凝视水晶球,了解他们将被授予多少年的统治。想象一下,如果我们能在他们登基的时候,猜测他们的统治何时结束。碰巧的是,有了正确的数据,在一定的精确度范围内,我们可以做到。

我们可以通过一种支撑现代人工智能的算法来做到这一点,这种算法可能为任何关注高中统计的人(不像我)所熟悉。该算法被称为线性回归。

这个世界充满了数字,而这些数字之间往往有关系。个子高的人通常更重。较大的房子通常卖更多的钱。静息心率较低的自行车运动员的圈速较快。有时候这些关系很简单,比如你有多少钱和你能买多少罐啤酒之间的联系。有时候它们很复杂很神秘,就像你喝了多少啤酒和第二天感觉有多糟糕之间的关系。线性回归是理解这些关系的工具。从一组先前的例子中,它推导出一个最符合观察到的数字的数字比率。如果你喝了一杯啤酒后感觉很好,第二天早上三杯后感觉有点不确定,六杯后头疼得厉害,那么你可以由此推断昨晚的 12 罐狂欢明天会有可怕的后果。

线性回归用于人工智能中任何时候对数值进行预测:一块房地产的可能价值,一名棒球运动员与另一名运动员相比可能得分多少,公司股价的前景-所有这些都可以通过线性回归进行预测。通过观察以前的例子,比如一组历史上的房屋销售,或者几十场比赛的分数,我们可以得出一些规则,如果这些规则成立,可以帮助我们预测未来的事情会如何发展。回归也用于研究,例如,了解吸烟和肺癌之间的关系,或估计药物治疗疾病的效果。多种因素的影响可以被衡量和区分,从而得出对世界的复杂理解。

我们还可以使用线性回归来(粗略)预测一位英国君主还会在位多久。但是首先我们需要选择一些变量——一些关于过去君主的已知事实——这可能有助于我们做出预测

除了少数例外,英国君主的职位是终身的。除了刽子手的斧头或战争的紧急情况(或亨利一世的命运,据报道他死于食用“过量的七鳃鳗”),君主剩余权力的主要预测者必须是他们登上王位时的年龄。因此,让我们选择“升天年龄”作为线性回归算法的第一个变量。让我们试着理解君主登基的年龄和他们在位时间的长短之间的关系。

The face of a man who is hungry for lampreys

为了理解和形象化这种关系,我们可以创建一个散点图。我们做了一个图表,横轴是“升天年龄”,纵轴是“在位时间长度”。对于每一位君主,从威廉一世到伊丽莎白二世,我们都在图表上做了标记。亨利六世在他父亲因痢疾自杀后九个月大的时候继承了王位,他位于图表的最左边。执政 39 年后,他的印记出现在 y 轴的三分之二处。他的标记在 y 轴的底部附近。

通过以这种方式绘制 40 多个帝王蝶,我们可以制作出下面的图表:

Fig. 1: Relationship between age at ascension and length of reign

在这张图表中,我们看到灵魂收割者咧着嘴笑的脸。尽管他们明智或愚蠢地统治,但没有一个君主能活到七十岁以上。一个统治可能会被可悲地终止——比如前面提到的爱德华五世,他 86 天的统治结束于他 12 岁时被限制在伦敦塔,然后(历史学家大多同意)被他背信弃义的叔叔理查德秘密谋杀。但是一个统治可能永远不会超过统治者的自然寿命。

Never trust a man with a pinkie ring

我们可以在图表中看到这一点。尽管我们看到一些君主(比如可怜的爱德华五世)落在了图表的左下象限——尽管他们还年轻,但他们的统治时间很短——但我们在右上角却没有看到——尽管年事已高,但仍享有长期统治的统治者。这就是线性回归非常适合发现的事实——这种关系。

升天时的年龄和君主统治时间的长短之间的关系可以用一个数字来表示,图表上的红线显示了这一点。这种关系是由线性回归算法导出的。该算法采用了一组例子——在这种情况下是我们的每个君主,并在我们展示的例子中找到最符合统治长度的升天年龄值。它在图表上画一条线,尽可能多的点靠近这条线。图表上的线条从亨利六世开始,他登基时只有 9 个月大,在苏格兰待了 40 年,还不算在苏格兰东躲西藏、被囚禁在伦敦塔、处于紧张性精神错乱状态的几年。这条线的终点非常接近威廉四世,他一直等到 64 岁才继承王位。威廉经历了他疯狂的父亲 59 年统治的大部分时间,然后是他哥哥掌权的 10 年,在他继承王位之前,他只在位 7 年。在这之间,这条线经过了许多不同年龄和任期的君主。它并没有经过所有这些地方,但是它的路线被计算为最可能符合观测数据。它的斜率与数据精确拟合,使得直线和每个数据点之间的距离最小。

I hope at 64 I still look this good in tights

这个斜率给了我们以下规则:一个君主可以期望统治 40 年多一点,即位时每多活一年少于六个月。

这里我们有一个非常简单的模型来预测君主的统治时间:

“Y = 1”或“在位时间= 40 年+(年龄 x 6 个月)”

简单!

但是这种数学精度可能会掩盖我们模型中的一些基本误解。首先,似乎很奇怪的是,每一年只占君主统治时期的六个月。在其他条件相同的情况下,登基前一年应该意味着登基后少一年。第二,当我们看图表时,我们看到大量的帝王蝶落在图表的左上方,远在红线之上,而另一组落在红线之下,在我们图表的底部中间。我们的线划得太浅了!所发生的是,我们几个英年早逝的年轻统治者已经把整条线拉向了左边。有没有可能,虽然一般来说年轻登基会导致更长的统治,但其他一些因素意味着那些太年轻的王位继承人注定会提前死亡?

碰巧的是,这是完全合理的!六个在十四岁或十四岁以下继承王位的君主中,有两个,亨利四世和六世,继承了在战争中被杀的父亲,还有三个,爱德华三世、五世和六世,是有点可疑的王位继承人。此外,年轻的统治者受制于反叛的摄政者和诡计多端的亲戚,他们可能会利用新统治者的年轻。如果我们能在分析中调整这种效应会怎样?

线性回归正好处理这种情况。对于每个君主,我们给算法两个值——升天时的年龄,然后另一个值被设置为 1,如果君主在他们登上王位时是 14 岁或更大,否则为零。该算法再次尝试找到最佳拟合线,但为了找到该线,它可以调整两个值——升天时一岁的值和升天当天小于 14 岁的值。我们制定了一个新的规则:君主将统治 50 年,如果他们登基时不满 14 岁,统治时间将减少 13 年,然后每增加一岁,统治时间将减少 9 个月。

我们可以用下面的图表来形象化这一规则:我们看到的值和以前一样,只是五位年轻统治者的统治时间已经根据他们的年轻程度进行了调整——我们给了他们额外的 13 年,红线——我们预测统治时间的指标——现在变得更加陡峭。

Fig. 2: Age and length of reign, adjusted for accession under age fourteen

现在,直线与数据点更加吻合。我们的模型更好地预测了君主统治的时间长度,但仍然相当糟糕。仍然有大量的帝王蝶在图表上的分数远离红线——我们对它们的预测非常差。举例来说,即使调整给他提供了额外的 14 年,这条线也比可怜的爱德华五世的分数高出了 20 年。他的继任者(也是被怀疑的杀手),理查德三世,也从模型中得到了过于慷慨的估计。这条线给他 25 年的刑期,而事实上,在他在博斯沃思战场上为自己的罪行付出生命代价之前,他只活了 3 年。与此同时,在光谱的另一端,乔治三世、维多利亚和伊丽莎白二世的分数都超过了 30 岁。

我们需要寻找更多的变量,幸运的是,有许多可能的候选者。我们的模型缺少任何关于君主统治结束的主要原因之一——战争的变迁和英国中世纪致命的政治——的数据。在英国历史的大部分时间里,君主更有可能通过敌人的阴谋而不是时间之父的无情之手来实现自己的目的。

但是如何预测战争的爆发呢?在一个君主开始统治的时候,我们如何猜测他们的统治是否会受到挑战?一种方法是观察他们夺取王位的方式——合法继承,还是篡夺。看起来,欺骗是不会成功的。那些避开通常的继承规则的统治者,平均统治时间不到那些无争议继承王位的统治者的一半。“血腥的”玛丽一世曾召集军队废黜她的表妹简·格雷夫人,她死前只享受了三年在火刑柱上烧死新教徒的生活。但是被称为“狮子心”的理查一世也许是这种“生于刀下,死于刀下”效应的最好例子。篡夺了他自己的兄弟,并与他的父亲开战,理查德在一次叛乱中赢得了王位,但十年后去世,在一次反对他自己统治的叛乱中捍卫了他的王位。我们应该为那些在有争议的情况下登上王位的统治者调整分数。

Richard: The line art

但是即使是合法的统治者也会陷入战争,或者伴随而来的疾病。中世纪的世界很危险,容易爆发战争、饥荒和疾病。尤其是在中世纪以农业经济为主的英国,有一个因素可以帮助预测这些疾病的爆发:天气。在这个时代,经济几乎完全依赖于农业,而农业几乎完全依赖于好天气。因此,如果天气比平均水平冷,我们可能会看到更多的疾病,更多的饥荒,更多的战争,因此,比预期更短的统治。

Fig. 3: Correlation between error in age/reign model and average temperature

上面的图表显示了每个君主的一个点(红色),根据他们登基的年份绘制,以及根据他们登基时的年龄,他们统治的年数比我们预期的多或少。红色阴影区域显示了该值的移动平均值。蓝线代表每 50 年平均温度的估计值。整个 11 世纪后期,气温都很高——“中世纪温暖期”,但从 13 世纪中期下降到 16 世纪后期到 18 世纪早期的低点——“小冰川期”,这与英国的不稳定和革命时期相吻合,包括推翻詹姆斯二世的“光荣革命”。图表显示,在我们的模型中,温度和误差之间存在一定程度的相关性——它们沿着相同的方向移动。

James II low-key repping Westside

我们的模型现在有五个输入要素:升天时的年龄、君主是否在 14 岁以下的调整、自 1066 年以来的年数、平均温度,以及最后,君主是否是王位的合法继承人的调整。

现在很容易继续搜索更多的特征,找到模型仍然预测不佳的君主,并找到一些输入特征来解释为什么他们的统治比预期的更短或更长。但是我们应该小心。以爱德华八世为例。爱德华八世在相对年轻的 42 岁登上王位,考虑到当时的政治稳定,我们的模型预测他的统治将持续到 60 多岁。但是爱德华的统治持续了不到一年。爱德华在某种程度上是个讨女人喜欢的人(也可能是纳粹的同情者),他在位不久就宣布打算与沃利斯·辛普森结婚,她是一个多次离婚的美国人,他与她已经有了几年的秘密恋情。这在宪法上被认为是不可接受的,于是爱德华放弃了王位。

What a dick

我们如何预测这一点?我们可能会在数据集中包含一些特征,比如“与一个美国人订婚”或“以前的婚外情次数”。这可能会让我们更好地预测爱德华统治的真实时间,但也会让我们面临风险。下一任君主在与已婚女性发生一连串婚外情后登上王位,或者打算与一个多次离婚的人结婚,可能会在一个更加开明的时代这样做,那时这些轻率的行为不会阻碍他们获得长期的王位。我们预测这位假想的风流君主的统治时间太短了。

只适用于一小部分帝王蝶的特征可能无法推广到更广泛的人群。我们为它们找到的关联在我们观察到的一组狭窄的数据中成立,但是那些观察在那组数据之外不成立。

因此,我们应该满足于我们拥有的五个特性。模型得出的最终规则如下:

38 年了

不满 14 岁的,16 岁

-一岁一年

自 1066 年以来每年+7 天

对于高于或低于平均值的每一度温度,为+/-15 年

合法统治者+10 年

我们最终得到的模型仍然很差,正如我们可以从这张绘制预测统治与实际统治的图表中看到的。在这张图表中,模型给出了所有帝王蝶的数据,除了随机选择的九只。然后对 9 个抵制者进行了预测。这样我们可以看到我们的模型概括得有多好。我们从一组君主身上学到的规则适用于另一组吗?我在 y 轴上画出了君主统治的预计时间长度,在 x 轴上画出了他们实际上在王位上待了多长时间。该图表上完全准确的预测看起来像一条由点组成的直对角线——预测与真实值完全匹配。实际的精确度要差得多。

Fig. 4: Predicted length of reign vs actual

该模型很好,因为它很少预测实际上统治了很长时间的君主的统治时间很短,但它经常预测实际上只在位很短时间的君主的长期统治。例如,它仍然让可怜的爱德华五世在位 25 年。此外,它还低估了大多数人的在位时间——伊丽莎白一世预计在位 27 年,而实际上她在位 45 年,乔治四世在位 11 年,而不是模型给他的 3 年。尽管对亨利来说这是一个强有力的模型。这让 24 岁的亨利七世一语中的,而亨利二世只统治了两年,超过了模型给他的 33 年。

What is he planning?

通过输入我们最有可能的下一个数据点查尔斯王子的数字,我们可以在实践中看到这一点。假设查尔斯明天登基(RIP Elizabeth),我们的模型预测他会在位多久?

在撰写本文时,查尔斯已经 68 岁了。气温比 1066 年以来的平均气温高了整整半度,这让查尔斯又多了七年的王位。自 1066 年以来,查尔斯在 2017 年登基将有 951 年的时间,我们的模型将其转化为额外的 18 年统治时间。查尔斯将(大概)合法继承王位,而不是篡夺可怜的伊丽莎白,再增加 10 年。把所有这些因素加在一起,我们得出查尔斯只在位五年,这可能有点保守。

我们的模型并不十分精确——它的预测通常与真实值相差不到十年。在君主统治时间长短差异巨大的背景下,这看起来似乎相当不错,但我怀疑十年的误差会给相关君主带来一些实质性的问题。

线性回归算法假设特征和结果之间存在线性关系。例如,它假设温度和统治时间的关系总是正的——越暖和,英国就越稳定,君主在王位上呆的时间就越长。模型看到的所有信息都证实了这种关系。但是,认为气温升高总会导致统治时间延长的假设是短视的。事实上,气候变化很可能在不久的将来导致严重的政治不稳定,这一全球剧变的悲惨后果将是我们模型的准确性大幅下降。

We’re all rooting for you, Charlie

也有可能英国的气候与其统治者在位时间的相关性完全是虚假的。这种联系似乎是可信的,表面上看,这些数据似乎是吻合的。但很可能有几十个其他指标在那个时期显示了类似的模式,这也可以被认为有一些似乎合理的因果联系。如果事实证明我们观察到的相关性是偶然的,那么我们的模型在未来将会严重出错。

这暴露了线性回归的一个弱点,事实上也暴露了许多此类算法的弱点:我们的模型基于一系列关于英国及其统治者的强有力假设——预期寿命将继续增长,气温上升将永远意味着更大的政治稳定性,不会出现对君主统治的新威胁,等等。如果这些假设中的任何一个被证明是错误的,我们的模型的准确性就会受到影响。随着新数据的出现,我们可以通过频繁检查和重新训练我们的模型来减轻这些风险,但即使在最复杂的算法中,这仍然是一个问题。例如,金融预测模型可能会嵌入一个假设,即房地产价格将永远上涨,或者无法解释商业模型的彻底中断。

虽然我们自己的模型有点不确定,但是回归模型可以非常准确,非常有用。只要支撑它们的假设成立,这些模型就能提供非常有用的指导。但是当我们依赖这些模型时,我们希望模型创建时存在的条件将持续到未来。我们了解到的是,尽管这些模型平均来说可能创造出最佳拟合,但是任何一个单独的例子都可能是一个实质性的异常值。当一个君主登上王位,并使用我们的模型来预测他们的未来时,他们可能会合理地从长期统治是他们最有可能的结果的预测中获得安慰。但是他们也应该注意自模型创建以来发生变化的环境。他们应该密切注意诡计多端的叔叔们。

本文使用的代码和数据可以在 我的 Github 页面 中找到。本系列之前的文章可以在这里 找到 。本系列的下一篇文章, 编织与建议 此处可用**

线性回归:自下而上的方法

原文:https://towardsdatascience.com/linear-regression-bottoms-up-approach-intro-to-spark-a-bonus-b923ae594323?source=collection_archive---------32-----------------------

额外收获:spark 简介

Photo by Carlos Muza on Unsplash

你有什么好处?

本文介绍了线性回归的细微差别,并将 spark 作为附件包括数据分析。这将作为经验丰富的数据科学家的复习资料,作为初学者的深度学习材料,以及作为新手的参考指南。

我们来谈谈数据

为了达到这个目标,我选择了一个 数据集 ,它不会太琐碎,同时也不会太吓人。我们将着重于确定水的盐度和温度之间的关系。这个数据集有大约 10 亿条记录,是 60 多年的海洋学数据。

免责声明!

帖子会很大。别担心,我不会用奇怪的数学来烦你,但我会专注于获得洞察力,我保证会很有趣。

如果您正在运行整个数据集,您可能希望使用 colab。取决于您的笔记本电脑容量。

使用 PySpark 进行数据分析

请随意跳到下一节课。如果你对 spark 和分布式计算入门感兴趣,一般来说,点我

这只是为了对 pyspark 的工作方式有所了解。

There is a negative correlation between salinity and temperature of the ocean water

Salinity is mostly distributed around 33–34.5

建模将意味着使用机器学习技术从数据中学习一组特征和我们希望预测的东西之间的关系。在建立模型之前,我们应该了解一下成本函数。这是一个非常重要的概念,有助于构建良好的模型。

成本/评估功能

我们该如何处理这个问题?开始一个人的推理的一个合适的地方是:假设我们创建了许多模型来预见我们的目标,我们怎么可能选择最好的一个呢?当我们决定这样做时,我们的目标是最小化/最大化该值。

如果您能够将您的问题简化为一个单一的评估度量标准,这将是非常有用的,因为这样可以非常容易地迭代模型开发。有时候你并不十分清楚你想要你的模型最大化/最小化什么。我们将更多地讨论这个挑战,但是现在,我们将坚持使用今天使用的非常标准的评估函数。

所以对于这个问题,我会提出以下评价指标:均方误差(MSE)。为了理解 MSE,让我们定义一些术语:

  • 𝑦hat——这是我们对第 I 个数据点的预测值
  • 𝑦 —这是第 I 个数据点的实际值
  • 𝑛 —数据点的数量

因此,MSE 为:

在英语中,对于每个点,我们从实际值中减去预测值。然后,因为我们不关心误差的方向,所以我们求差的平方。最后,我们取所有这些值的平均值。基本上,我们是说我们希望我们的预测和实际之间的平均距离小一些。

你可能会奇怪,为什么我们平方这个值,而不是取绝对值。事实证明,对于下面的一些数学运算来说,平方这个值效果很好。另外,它是 MSE 估计值。不过,这确实有在我们的平均值中增加大误差权重的效果,因为我们在平方所有的差异。

这取决于你的损失函数。在许多情况下,给予远离平均值的点更多的权重是有意义的——也就是说,偏离 10 比偏离 5 要糟糕两倍多。在这种情况下,RMSE 是一个更合适的误差度量。如果 10 点前的失误是 5 点前的两倍,那么 MAE 更合适。

我们的模型

现在我们有了成本函数,如何找到最小化它的方法呢?我们将回顾线性回归模型。该模型如下:

其中 j 是我们拥有的预测值的数量,β值是我们的系数,β0 是截距。基本上,我们的模型是预测值和截距的线性组合。

现在我们有了一个模型和一个成本函数,我们的挑战变成了为我们的模型找到最小化我们数据的 MSE 的β值。对于线性回归,实际上有一个封闭形式的解决方案,称为正规方程。不过,我们将使用一种在机器学习中更常见的不同技术——梯度下降。

梯度下降

梯度下降是我们从最优化中借用的一种技术。这是一个非常简单,但功能强大的算法,可用于寻找一个函数的最小值。

  1. 选择一个随机的起始值
  2. 在当前点采取与梯度负值成比例的步长
  3. 重复直到你收敛

如果一个函数是凸的,这种技术将找到全局最小值,如果不是,我们只能证明它将找到局部最小值。让我们来看一个的例子。

我们需要回答的第一个问题是:代价函数是凸的吗?让我们来看看:

我们在上面所做的是获取盐度的一系列系数值,并根据我们的数据(温度作为目标)计算每个系数值的 MSE。如果我们画出这些,我们会得到上面的曲线——看起来很凸!事实上,我们的线性回归模型的 MSE 函数总是凸的!这意味着我们可以使用梯度下降来找到我们的模型的最佳系数!

梯度下降比机器学习的正常方程更常见的一个原因是,随着我们增加特征的数量,它的规模更大。它也是一种普遍的优化技术,在机器学习中随处可见,因此了解它的工作原理是非常有价值的。

梯度

梯度就是关于系数的偏导数。对于每个系数,我们需要计算 MSE 对该系数的导数。我们开始吧!

记住我们的成本函数:

现在,让我们扩展一下这个简单的例子,它有一个截距和一个变量,Salnty:

现在,对于它对β0 的导数,我们得到:

对于β1:

实现可以在笔记本中找到。

学习率

学习率是一个超参数,用于确定我们离梯度方向有多远。你怎么知道选择什么值?通常,可以尝试许多值,这里有一些我认为是吴恩达建议的值:. 001,. 003,. 01,. 03,. 1,. 3,1,3

选择一个太小的值会导致收敛速度变慢。选择太大的值会导致超过最小值和发散。

也有其他梯度下降优化,更复杂,适应学习率超时为您服务。这也是你可以自己做的事情,随着时间的推移,你会慢慢降低学习速度。你可以在这里阅读更多关于不同优化器的信息。

什么时候停止迭代?

在我的代码中,我简单地选择运行我们的循环 10,000 次。为什么是一万。没有真正的原因,除了我很确定它足够长的时间来收敛。这通常不是最佳实践。一些更好的想法是:

  1. 在每一次循环后监控你的成本,当它的下降小于某个容差时——比如 0.001——停止。
  2. 使用一个验证集,并在其上跟踪损失,例如,MSE。当它停止减少时,停止。

标准化数据

使用梯度下降时,您希望所有数据都进行归一化。减去平均值,然后除以所有训练特征的标准差。如果您的成本函数不是凸的,这通常会使训练更快,并减少陷入局部最优的机会。

何时对数据进行规范化?

当您不知道数据的分布或您知道分布不是高斯型(钟形曲线)时,归一化是一种很好的方法。当您的数据具有不同的比例,并且您使用的算法不对数据的分布进行假设时,如 k-最近邻和人工神经网络,则规范化非常有用。最小-最大缩放器。它对异常值很敏感。

何时标准化数据?

标准化假设您的数据具有高斯(钟形曲线)分布。严格来说,这并不一定是真的,但是如果您的属性分布是高斯分布,这种技术会更有效。当您的数据具有不同的比例,并且您使用的算法假设您的数据具有高斯分布时,标准化非常有用,例如线性回归、逻辑回归和线性判别分析。

稳健标量(缩放至中位数和分位数) :

使用中位数和分位数进行缩放包括减去所有观测值的中位数,然后除以四分位差。它使用对异常值具有鲁棒性的统计数据来缩放要素。

X_scaled = (X-X.median) / IQR

其他类型的梯度下降

我在这里展示的梯度下降是一种普通形式,这意味着每次系数更新都使用所有数据来计算梯度。还有随机梯度下降只使用 1 行数据来更新每个循环中的系数。这更具可伸缩性,因为您一次只需查看一个数据行,但也更具随机性,因为您试图使用仅在单个数据点上计算的梯度进行导航。这也引入了一个新的术语:纪元,它是你想要循环数据的次数。

另一种类型的梯度下降是小批量梯度下降。这种形式是两者之间的一种折衷,您可以选择一个批处理大小,比如说 32(或者更好的是一个批处理时间表,从小的批处理开始,随着时间的增加而增加),并且梯度下降的每次迭代可以使用 32 个随机数据行来计算梯度。这提供了一些可伸缩性和一些随机性。这种随机性实际上对于非凸的成本函数(深度学习)是有用的,因为它可以帮助模型摆脱局部最小值。这是非凸成本函数最常用的方法。

我们模型的假设

每当你处理一个模型时,了解它所做的假设是有好处的。我本打算在这里写一篇关于这个的文章,但是杜克已经做得很好了。

使用 sklearn

现在我们已经了解了一些理论和实现,让我们转向一个软件库,对我们的数据进行线性回归。这对于学习从头开始编写模型非常有用,但是使用一个经过测试并被广泛使用的库通常会更好。

请记住扩展您的数据,这非常重要!

Sklearn 是一个很棒的包。它提供了许多模型,并且它们都具有拟合和预测功能。您可以对 X 和 y 数据调用 fit 来训练模型,并对新要素进行预测来获得预测值。Sklearn 还提供了很多你可以用来评估的指标,比如 MSE。这里我输出根 MSE (RMSE ),因为这让我们回到目标的原始比例,我觉得这更容易理解。

tol 告诉模型何时停止迭代,eta0 是我们的初始学习率。

多项式变量

如果你记得我们的 Salnty 对我们的目标(T_degC)的图,看起来有一点多项式关系(这可能也是因为图的比例)。线性回归适合线性关系,但是如果添加多项式要素,例如 Salnty,则可以适合更复杂的关系。Sklearn 让这变得简单:

多项式要素命令生成了一个新的要素矩阵,该矩阵由阶数小于或等于指定阶数的要素的所有多项式组合组成(在我们的示例 2 中)。然后,我们对这些数据进行缩放,并将其输入到我们的模型中。我们得到了稍微改进的 RMSE。太棒了。但是,请注意,这些结果并不十分有效,因为它们应用于我们的测试数据。在这篇文章的后面,我们将看看如何更好地评估我们的模型的可推广性。

分类变量

当您有分类数据时,线性回归是您需要小心使用的模型之一。如果某个要素的值为 1、2 和 3,实际上表示男性、女性,则无响应。即使它们是数字,你也不想这样给模型。如果你这样做了,模型会给这个特征分配一个系数——可能是 0.1。这就意味着,女性会将预测提高 0.1%,而无反应会提高 0.2%。但是也许女性应该把分数提高 1.2,而没有反应的分数只提高 0.001。考虑到这一点,您应该将这些值转换为虚拟变量,以便每个值都有自己的权重。除非您确信在您的数值顺序中有一个恒定的关系。

解释你的模型

线性回归是一个伟大的统计模型,已经存在很长时间了。有许多统计技术可以用来评估和解释它。我们不会涵盖所有这些,事实上,我们将主要关注非常简单的方法,这些方法在机器学习中可能比统计学更常见。

统计学习手册线性回归点介绍:

这只是一个介绍。请参考统计学习简介以便更好地理解。

潜在问题:

  • 响应-预测值关系的非线性——残差图帮助我们发现它。yhat — y 与 x 的关系图。如果残差图表明数据中存在非线性关联,那么一个简单的方法是使用预测值的非线性变换,如 logX、√X 和 X
  • 误差项的相关性——如果误差项是相关的,我们可能会对模型产生不必要的信心。为什么误差项之间会出现相关性?这种相关性经常出现在时间序列数据中。
  • 误差项的非恒定方差(异方差)——当你在残差图上发现漏斗形状时。面对这个问题,一个可能的解决方案是使用凹函数(如 logY 或√Y)来转换响应 Y。
  • 异常值-异常值在最小二乘拟合中没有太多 effect。它们会影响 r 和 RSE 值。
  • 高杠杆点-高/低这些点不是异常值,但它们与数据截然不同,靠近回归线,并将影响最小二乘拟合。
  • 共线性-共线性是指两个或多个预测变量彼此密切相关的情况。

首先,让我们看看我们的模型已经学习的系数:

这些系数是什么?它们表示在保持模型中其他特征不变的情况下,特征变化一个单位的平均温度变化(在我们的例子中,我们只有一个)。例如,盐度每增加一个单位,我们的目标(温度)就会降低 2.096。

这真是太好了!我们也许可以说,如果你想提高温度,降低盐度可能是一个开始。我说可能是因为线性回归着眼于相关性。在我们的数据中,情况确实如此,但这本身并不意味着这些特征有因果关系。不过,这可能是寻找因果关系的好地方,并且确实代表了数据中出现的关系。

置信区间

通常在机器学习中,在你的估计值周围有一个置信区间是非常有用的。有不同的方法可以做到这一点,但是一个相当通用的方法是使用 bootstrap。

Bootstrap 是替换我们数据的随机样本,该样本与原始数据大小相同。这是生成同一数据的多个视图的一种方式。让我们创建 1000 个数据引导。完成采样后,我们可以通过输入模型来获得每个数据集的系数。

这太好了!现在我们可以很有信心地说,萨恩蒂的实际系数是负的,几乎肯定在-2.2 和-2.1 之间

训练/测试分割和交叉验证

到目前为止,我们一直在根据现有的所有数据进行训练。这可能是有意义的,因为我们希望通过使用尽可能多的数据进行训练来最大化数据的效用。然而,另一方面,这使得我们很难评估我们的模型做得有多好。其原因是,如果我们只是使用模型训练的数据来计算我们的 MSE 分数,我们可能会发现我们引入的数据不是模型训练的数据,它的表现相当差。

这个想法叫做过拟合。基本上,当一个模型在它被训练的数据上比在新数据上表现得更好时,它已经过度适应了训练数据所特有的东西,而这些数据并不一般化。

这种情况的另一面叫做偏见。当一个模型不能很好地拟合数据时,它就有很大的偏差。在这种情况下,对于训练数据和在训练期间没有看到的数据,MSE 都将是高的。

在机器学习中,偏差和方差之间总是有一个权衡。随着模型变得越来越复杂,过度适应训练数据的风险也越来越大。

既然我们知道只看训练数据的 MSE 有问题,我们能做什么来更好地判断概化?以及诊断过度拟合和偏差?通常,我们将数据分成两组:训练集和测试集。

您可以利用 sklearn.model_selection 中的 train_test_split

太棒了。现在我们有了 RMSE 的训练和测试数据。两者都非常接近,这表明我们没有过度拟合的问题。不过,它们都很低吗?这表明有很大的偏见。

研究这个问题的一个方法是绘制学习曲线。学习曲线描绘了我们的误差函数(MSE ),以及用于训练的各种数据量。这是我们的情节:

你可以看到,在不到 2.5 亿个训练样本的情况下,训练 MSE 相当好,交叉验证相当差(我们还没有谈到交叉验证,所以暂时把它当作测试)。如果我们那时只有那么多数据,它看起来就像一个高方差问题。随着我们数据的增加,我们开始提高我们的分数,它们变得非常接近,这表明我们没有高方差问题。

这张图看起来更像是我们有一个高偏差问题,因为我们的两条曲线非常接近,并趋于平缓。不过,这很难说,因为我们可能刚刚达到了可能的最佳 MSE。在这种情况下,这不会是一个高偏差问题。如果我们的曲线变得平坦,并且 MSE 高于最优值,这将是一个问题。在现实生活中,你不知道最优的 MSE 是多少,所以你必须从理论上说明你是否认为减少偏差会提高你的分数——或者只是尝试一下!

修复高偏差/高方差问题

那么,现在你已经诊断出了你的偏差或方差问题,你如何解决它们呢?

对于高方差:

  • 获取更多培训数据
  • 尝试一组较小的功能
  • 尝试不太复杂的模型
  • 添加正则化

对于高偏置:

  • 尝试添加功能
  • 尝试更复杂的模型

交叉验证和调整超参数

之前我们提到过这个短语:交叉验证。让我们现在谈论那个。到目前为止,我们已经了解到,将数据分成训练集和测试集是一个好主意,这样可以更好地了解模型的实际运行情况。这很好,但是想象一下我们想要测试多个不同的模型或者测试我们模型的不同参数——例如,不同的学习率或者容忍度。我们如何决定哪个模型或哪个参数是最好的?我们会用训练数据训练一切,用测试数据测试一切吗?希望你能看到这是没有意义的,因为那样的话,我们将基本上处于以前的同一位置,没有办法测试我们对以前从未见过的数据做得有多好。所以——我们希望保持我们的测试集不受污染,也就是说,在一个完美的世界中,我们只会在完成所有实验并认为我们找到了最佳模型之后,才在它上面运行我们的测试。

听起来我们需要第三组数据——验证组。基本上,我们可以做的是将我们的训练数据分成两组:一组训练数据和一组验证数据。所有模型将在训练集上训练,然后在我们的验证集上测试。然后,我们选择验证效果最好的模型,看看它在测试中表现如何。我们的测试结果代表了我们认为我们的模型对看不见的数据有多好——然后我们就完成了。

注意:这里的假设是我们的测试和验证集是我们总体的代表性样本。通常,我们随机地将可用的数据分成三组,但是确认这些组是好的表示总是好的。否则,您会发现在验证和测试中运行良好的模型在生产中表现不佳。

在实践中,我们经常使用 k-fold 交叉验证,而不是创建一个单一的验证集。这里我们选择一个 k 值,比如说 3。然后,我们将训练数据分成三份。我们随机选择 2 个折叠进行训练,然后使用剩余的进行测试。然后,我们再重复 2 次,总共 3 次,这样所有的观察结果都用于训练和验证,并且每个观察结果只用于验证一次。然后,我们将所有三个分数(在我们的例子中是 MSE)进行平均,以获得特定模型的分数。然后,我们可以对多个模型重复这一过程,以找到最佳模型。这是一个很好的视频

使用 sklearn,这个过程非常简单:

这里我们实际上使用了随机搜索,这通常比搜索所有可能的值要好。通常,你想为许多不同的旋钮尝试许多不同的参数,网格搜索一切是没有效率的。通常,你会像我们上面做的那样使用随机搜索。但是,因为我们只有少量的值,所以我们通过将 n_iter_search 设置为我们想要尝试的值的数量来强制进行网格搜索。

我们还将 cv=3 设置为 3 倍,并使用负 MSE,因为 sklearn 中的 cv 函数试图最大化值。

你可以在这里了解更多关于随机搜索和网格搜索的信息:

此外,sklearn 还有许多其他 CV 函数,特别是如果您想要测试具有相同折叠的不同模型时,这些函数非常有用。这里有一些文件

正规化

作为解释高方差模型的一种方法,我提到了正则化。您可以将正则化视为一种用于惩罚学习复杂关系的模型的方法。对于线性回归,有三种流行的方法。所有这些方法都围绕着限制我们的特征的系数可以有多大的思想。这个想法是,如果我们高估了一个预测因子(一个大的系数)的影响,很可能我们是过度拟合了。注意:我们仍然可以有大的系数。正则化只是说,MSE 的减少必须证明系数幅度的增加是合理的。

  • L1 正则化(Lasso):将系数的绝对值之和添加到成本函数中。这种方法可以将系数强制为零,这可以作为特征选择的一种手段
  • L2 正则化(岭):你把系数的平方和加到成本函数中。
  • 弹性网:你将两者相加,并选择如何加权

这些方法中的每一种都采用了一个加权因子,该因子告诉您应该对成本函数中的正则化项进行多少加权。在 sklearn 中,它被称为 alpha。alpha 值为零不会增加任何损失,而高 alpha 值会因为模型系数大而对模型造成很大损失。您可以使用交叉验证来发现 alpha 的一个好值。

Sklearn 让这变得简单:

我希望你在文章中学到了一些东西。这是一个很好的起点。建议大家多读一些概念,巩固一下。大多数时候,人们倾向于在忙碌的时候学习新奇的东西。但是构建基础总是一个很好的起点。大量的业务应用程序只需要一个质量回归模型来进行点预测。

代号: Github

如果你需要任何帮助,你可以联系: LinkedIn

参考资料:

Geron Aurelien 的机器学习实践

线性回归推导

原文:https://towardsdatascience.com/linear-regression-derivation-d362ea3884c2?source=collection_archive---------1-----------------------

线性回归中的 2/3 部分

第 1/3 部分:线性回归直觉

第 3/3 部分:线性回归实现

经典的线性回归图像,但你知道吗,它背后的数学是甚至更性感。让我们揭开它。

在开始之前,您应该了解

偏导数

总和

准备好寻找最适合的线条了吗?

让我们从定义几件事情开始。

  1. 给定 N 个输入和输出…

2.我们将最佳拟合线定义为…

3.使得最佳拟合线看起来最小化我们命名为 S 的成本函数…

作为参考,我们将把最佳拟合线输入到分配减法的成本函数中,结果是…

为了最小化我们的成本函数 S,我们必须找到 S 相对于 aB 的一阶导数等于 0 的位置。aaB 越接近 0,每个点的总误差越小。先从 a 的偏导数说起。

找一个

使用链式法则,从指数开始,然后是括号中的等式。注意,对括号之间的方程求导可以简化为 -1

让我们从求和中取出-2,然后将两个方程除以-2。

让我们做一些半聪明的事情。让我们把总和分成 3 部分,把常数 B 从总和中抽出来

我们注意到 a 到 n 的和只是…

把这个代入并重新排列 B,给我们…

我们快到了!我们需要做的最后一件事是求解 a,所以我们将 na 加到两边,然后除以 n

看看这个。Y 和 x 的两个总和除以观察次数就是平均值:)。所以在所有这些工作之后,最小化相对于 aS 的成本函数是简单的…

调查结果 B

我们已经最小化了 S 相对于 a 的成本函数,让我们找到 S 相对于 b 的最后一部分。

我们把-2 剥掉,两边分。

为了便于查看,我们来分发 x。

现在,让我们做一些有创意的事情。还记得我们已经解决了。我们把 a (下面推导的公式)代入 S 关于上面 B 的偏导数。我们这样做是为了得到一个只有 x 和 y 的 a 和 B 的函数。

让我们分配负号和 x

这看起来很乱,但代数在这方面很厉害。让我们把总数分成两笔。

让我们把右边的求和项中的 -B 去掉,这样我们就可以分离出变量,并重新排列求和项中剩余的项。

通过减去第一个总和并除以第二个总和来隔离 B。

我们做到了!我们现在已经根据 x 和 y 分离出了 Ba 。这看起来像一个可怕的公式!不要担心,通过进一步操作公式,还有更简单的版本——你可以在这里查看这些。

总结一下:)

如果数据集只有一个独立变量,可以通过计算 B 找到最佳拟合线

然后将 B 代入 a

最后,将 Ba 代入最佳拟合线!

向前移动

那么…有多个自变量的数据集呢?我们能找到最适合这些的路线吗?你打赌!我们很快会讨论多元线性回归。同时,看看本系列的第 3 部分,我们将上面的方程与 Sklearn 的线性模型进行了比较。

线性回归:深入挖掘

原文:https://towardsdatascience.com/linear-regression-digging-deeper-b82672f168ce?source=collection_archive---------17-----------------------

如何发现和解决大多数与线性回归相关的问题

快速介绍

在我们关于线性回归的第一篇文章中,我们介绍了一种最简单但功能强大的机器学习形式的基础知识。在教程中,数据通常是精心选择的,以满足我们的需求,而不会带来很多困难。然而,在现实生活中,事情并不总是那么简单:我们经常遇到违反许多基本理论假设的数据,而这些假设是我们的线性模型有意义所必需的。当我们遇到这样的数据时,我们该怎么办?我们就这么放弃了吗?当然不是!根据出现的问题,我们可以使用许多技术来使我们的线性回归可行。在本文中,我们将讨论一些您应该注意的警告,以及如何解决它们。

重要的事情先来

我们现在将继续我们为预测房价建立的最后一个模型。如果你没有读过我们之前关于线性回归基础的文章,这是一个使用房屋面积、楼层数和建造年份来估计房价的模型。

首先,让我们看看当我们运行回归模型时,如何解释 R 生成的每个图,这样我们就可以发现其中的一些问题。当我们使用线性回归模型运行命令 plot() 时,它返回 4 个图,每个图有不同的解释:

**IN:**
path = 'insert you file path here'
data = read.csv(paste(path,'kc_house_data.csv', sep = ""))
model3 = lm(price ~ sqft_living + floors + yr_built, data = data)
plot(model3)

曲线 1:残差与拟合值的对比

在该图中,X 轴上是拟合值(由我们的模型估计的值),Y 轴上是残差(估计值和实际值之间的差值)。红线给出的图的形状表明我们的数据实际上是否是线性的(这是线性回归的一个基本条件)。在这种情况下,直线是一个很好的迹象,表明相对线性的形状。如果那条线是一条大曲线或抛物线,那将表明我们的数据遵循非线性模式。如果是这样的话,我们就需要另一种回归,这取决于曲线的形状,比如多项式回归。

图 2:正常 Q-Q

在这个图中,我们可以检查我们的残差是否正态分布,这是线性模型的另一个假设。在这种情况下,我们有一个问题:这些点应该遵循一条或多或少的直线,但在这里显然不是这样。从图中,我们还可以看到,我们有一些大的离群值,我们的分布是偏斜的,它有“重尾”。通常,这不是一个大问题:如果你的样本足够大,你可以忽略它,因为它不会对你的预测产生太大的影响。关于这个情节的更多细节,请查看这个链接。

剧情三:规模定位

在标度-位置图中,我们检查异方差/同方差:线性回归的假设之一是残差具有恒定方差(同方差)。当这个假设被违反时,我们说存在异方差问题。同方差是线性回归模型的一个关键假设,为了确保满足这个假设,我们希望图上的红线或多或少是直的和水平的,但这里显然不是这样。如果你不确定你有一条直线,你也可以运行一个 Breusch-Pagan 测试,包括在 lmtest 库中,为了更精确:

**IN**:
library(lmtest)
bptest(model3)**OUT**:studentized Breusch-Pagan testdata:  model3
BP = 2633.3, df = 3, p-value < 2.2e-16

简单来说,一个非常小的 p 值(例如小于 0.05)表示异方差(你可以在这里了解更多关于这个测试的信息)。

好的,那么我们如何调整我们的模型来考虑这种偏差呢?在进行回归分析时,我们必须考虑这些不同的标准偏差范围。有一些方法可以做到这一点,其中之一是稳健回归(这也有助于解决离群值)。幸运的是,在一个名为 robust 的包中有一个函数可以帮我们做到这一点:

**IN:**
library(robust)
model4 = lmRob(price ~ sqft_living + floors + yr_built, data = data)
summary(model4)**OUT:**
lmRob(formula = price ~ sqft_living + floors + yr_built, data = data)Residuals:Min      1Q  Median      3Q     Max 
-794793  -99349    6057  122207 5111794Coefficients:Estimate Std. Error t value Pr(>|t|)    
(Intercept)  4.033e+06  9.036e+04   44.64   <2e-16 ***
sqft_living  1.895e+02  1.556e+00  121.83   <2e-16 ***
floors       7.777e+04  2.548e+03   30.53   <2e-16 ***
yr_built    -2.054e+03  4.699e+01  -43.72   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1Residual standard error: 162500 on 21609 degrees of freedom
Multiple R-Squared: 0.317Test for Bias:statistic p-value
M-estimate      161.7       0
LS-estimate    4830.0       0

正如我们所看到的,我们的剩余标准误差降低了,我们的 R 平方提高了,这是一个好迹象。

图表 4:残差与杠杆

这是帮助我们发现异常值的图,这些异常值与其他观察值相差甚远,以至于扰乱了我们的回归。我们观察图的右角,发现红色虚线。过去的一切可能会使我们的模型产生偏差。通常,我们可以通过它们的行号(标绘的)来识别这些点,并在没有它们的情况下重新运行我们的回归。

等等,还有呢!

那么,除了非线性、非正态分布的残差、异方差、异常值,线性回归中实际上还有其他棘手的方面吗?的确,其中一些非常相关。

多重共线性

这违反了线性回归中一个非常重要的假设,这个假设经常被忽略:解释变量必须是独立的。如果不是,我们就说模型中存在多重共线性。检查的方法之一是计算模型的 VIF(方差膨胀因子)。粗略地说,它告诉我们,与没有多重共线性的假设情况相比,估计量的方差被夸大了多少。

**IN:**
vif(model3)**OUT:**
sqft_living      floors    yr_built 1.180454    1.395073    1.357629

没有硬性规定,但一般来说,我们可以说,如果 VIF 是 1,那么没有相关性,如果它在 1 和 5 之间,有中度相关性,如果它大于 5,有高度相关性(所以我们的模型应该是好的)。当存在高度相关性时,我们应该寻找高度相关的变量,并从模型中移除其中一个。

处理多重共线性的更好方法是进行岭回归、套索回归或弹性网回归。一般来说,他们会增加解释变量的权重,以确保不相关的变量获得较小的权重。另一种类型的回归称为逐步回归,它也有助于选择变量:它尝试不同的特征组合,然后根据一些标准选择最佳模型。

辛普森悖论

这是一个非常有趣的统计悖论,如下图所示。

If we only sample the red group or the blue group, we might have the wrong idea about our data

虽然当我们在不同的组中测试时,我们的数据可能呈现负相关,但总体的关系可能是相反的。当我们的模型中没有考虑第三个变量时(在图中,这是由颜色表示的变量),这个问题就出现了,这表明选择正确的特征是至关重要的。

型号选择标准

即使在尝试了几种不同的模型并确保它们都符合我们的假设之后,我们仍然可能最终得到几个运行良好的模型。那么,如何才能选出最好的呢?嗯,有一些比较线性回归模型的经典标准,主要的是赤池信息标准(AIC) ,它衡量每个模型丢失了多少信息。从定义上来说,模型是对现实的简化,因此它总是会丢失一些信息。AIC 所做的是比较这些模型,看看哪一个丢失的信息更少,因此,AIC 越小越好。

**IN:**
AIC(model1, model2, model3)**OUT:**df      AIC
model1  3 600540.6
model2  4 600540.4
model3  5 598739.3

在我们的例子中,模型 3 具有最小的 AIC,因此,根据这个标准,它是最好的模型。

结论

正如我们所见,尽管这是一个相对简单的过程,但做线性回归有许多微妙之处。这些是你在做这些事情时可能遇到的主要问题,以及一些可能的解决方案。显然,事情远不止如此,如果你想进一步研究,这里有一些有用的信息来源:

总体理解线性回归

https://en.wikipedia.org/wiki/Linear_regression

https://learningstatisticswithr.com/book/regression.html

了解线性回归图

【https://data.library.virginia.edu/diagnostic-plots/

线性回归陷阱

https://www . clock back ward . com/2009/06/18/普通-最小二乘-线性-回归-缺陷-问题-陷阱/

你可以访问完整的 R 脚本这里。

从头开始线性回归

原文:https://towardsdatascience.com/linear-regression-from-scratch-977cd3a1db16?source=collection_archive---------9-----------------------

在过去的几周里,我一直在快速学习 Goodfellow 和 Bengio 的深度学习。我从中学到了很多。这本书探索了广泛的机器学习+深度学习主题,并深入研究了这些技术背后的数学。这是一个很好的资源,可以让你对这个领域有一个基本的了解。

为了巩固我正在阅读的内容,我决定用 vanilla Python 和 numpy 对我正在研究的模型进行编码。如果可能的话,我还会创建一些正在发生的事情的基本可视化。

在这里,我将从本书的第一个也是最基本的模型开始:线性回归。事不宜迟,以下是我所做工作的概要。

动机

在我进入实现的肮脏细节之前,我想首先给出为什么要使用线性回归的一般概念。我们正在做的事情的动机是什么?

嗯,一般来说,线性回归是一个很好的预测连续变量的模型, y ,基于一个连续的(有时是离散的)输入, x 。线性回归模型将输入 x 组合在一起,对输出 y 进行良好的预测。例如,我们可以使用一个线性回归模型来预测房子的价格, y ,基于一些输入特征, x (例如,平方英尺、卧室数量等。).

需要注意的一点是,首先需要数据( x y 对)来训练线性回归模型,然后才能做出准确的预测。稍后我们将详细讨论这是如何实现的。

实现!

线性回归模型的实施有 5 个主要组成部分:模型、成本函数、参数、梯度和优化算法(如正常方程、梯度下降)。我们将在下面更深入地探讨每一个问题。

注意,这种实现推广到更高维度的空间。换句话说,它可以用( x y )数据做线性回归,用( x x y ) x x y)4 个维度的数据,以此类推。 通常,我们的模型将(n-1)维超平面拟合到 n 维空间中的数据。

模型

该模型由一个权重矩阵 W 与我们的数据 X 的基本线性组合来定义,其中添加了一个偏差项 b 以使我们的预测偏离原点。

这里注意@符号是矩阵乘法的。

成本函数

成本函数设定线性回归的目标。它定义了我们想要达到的目标。一般来说,清楚地定义你的成本函数是很重要的。你不能击中一个目标,直到你定义它是什么,对不对?这里,我们将成本函数定义为所有训练示例中我们对 y 的预测和 y 的实际值之间的平均平方距离。

参数

我们需要初始参数的值。参数不需要接近完美,只是一些开始预测的东西。这里,我们将初始化 W 为一个零向量,并将 b 初始化为 0。参数初始化有点像你刚出生时的知识。你真的不知道发生了什么,但这是一个开始!

坡度

我们使用梯度来学习我们的参数应该取什么值,以便最小化我们的成本函数。梯度公式是通过对我们的成本函数相对于 Wb 求导得到的。梯度为我们提供了移动 Wb 的方向,以便最小化我们的成本函数。请记住:通过最小化我们的成本函数,根据定义,减少我们的模型对我们的训练数据的 T84 预测 T85 和地面真实值y之间的平方距离。

优化算法

我将在这里介绍两种优化算法:梯度下降,和正常方程

梯度下降包括使用梯度在多次连续迭代中最小化成本函数,直到它收敛(即,达到它的最低点)。梯度下降有两个需要调整的主要参数:历元数(即迭代次数)和学习速率(一个调整我们的 Wb 值的速率的值)。如果历元数和学习率设置充分,梯度下降应收敛于 Wb 的值。

法线方程是求解 Wb 的替代技术。注意这个算法是 O (n)其中 n 是训练样本的数量。

把它放在一起

让我们把它们放在一起,运行模型!首先,我们将初始化参数, Wb 。然后,我们将使用这些参数、和我们的训练数据、 Xy 运行梯度下降,给出我们训练的 Wb 。由此,我们可以计算所有训练示例的平均成本。下面是我们的模型可以做什么的例子!

回顾这次演习

当我第一次从头开始编写线性回归代码时,我没有条理,老实说,我对这个问题没有很好的理解。我是说这能有多难?只是基本的线性回归。所以我开始写代码。

嗯,我肯定是搬起石头砸了自己的脚,以为这很容易。我没有制定一个很好的计划来保持我的数据和我的模型的兼容性,也没有真正计划好模型的每一部分如何组合在一起。

这导致了一些抛出错误的 bug,这些 bug 很容易修复,但是其他的 bug 就不那么容易了。例如,我在我的代码中发现的最后一个错误发生在 numpy 会在整个 W 矩阵中广播一个错误计算的 d W 值时。

因此,这里的经验教训是:(1)保持你的维度有组织,并有一个如何将你的模型和你的数据结合在一起的计划,(2)不要假设数据科学是容易的。

总的来说,实施线性回归确实有助于巩固和构建我对该主题的理论理解。我期待将来实现更复杂的模型!

使用 NumPy 直觉从零开始进行线性回归

原文:https://towardsdatascience.com/linear-regression-from-scratch-with-numpy-5485abc9f2e4?source=collection_archive---------14-----------------------

欢迎来到 NumPy 系列的线性回归的第一篇文章,在这篇文章中,我将尝试解释线性回归背后的直觉,这是一种流行的机器学习算法,并展示如何使用 Python 和numpy包来实现它。

自然,我们将使用其他有用的包,例如matplotlib,但是,它们的使用可能仅限于数据可视化、数据操作和/或加载数据集(例如sklearn.datasets),因此我们在为机器学习模型本身编写实际代码时不会走任何捷径。

总结一下,我们将从零开始实现一个机器学习算法!

这难道不令人兴奋,同时又有点让人不知所措吗?

我提到过它也非常有趣吗?

由于线性回归是机器学习宇宙中的" hello world "算法,所以用 NumPy 来实现它会非常容易。

如果你认为你对线性回归算法的底层原理了解的足够多,想马上跳到编码部分,请便,从这里开始阅读实现部分,否则继续阅读!

线性回归直觉

在我们编写实现线性回归的代码之前,首先我们需要了解什么是线性回归。有许多有用的资源可以让我们很容易理解回归,尤其是线性回归背后的概念,因此,我不会在这里讨论数学细节,而是尝试以更实用的方式解释算法背后的逻辑。

通过挖掘目标值和数据特征之间的关系,线性回归用于对我们手头的数据进行某种意义上的分析。当我们知道这个关系时,我们可以对我们以前没有见过的数据进行预测,换句话说,我们可以从特征值中推断出目标值。让我们举个例子:

假设我们想了解一家名为 X 的特定公司是如何决定向其员工支付薪酬的。

可能有很多因素会影响到这个决定,所以我们四处询问在那里工作的大多数员工。

经过大量的窥探和偷偷摸摸,结果是:

  • 他们中的一些人收入很高,因为他们已经在 X 公司工作了一段时间,
  • 他们中的一些人比大多数人挣得高,只是因为他们和老板相处得很好
  • 有些人因为他们的资历和才能而收入更高。

这三个指标似乎是主要指标,因此我们将在实施中使用它们。

现在,根据我们收集的信息,我们希望了解这些因素与当前支付给员工的工资之间的潜在关系。我们想出了这个过于简单的等式:

工资 =(?x 资历 ) +(?x工龄 T9)+(?x 与上司相处

从上面的等式中我们可以看出,工资受 3 个属性的影响。这些属性也被称为 特征 ,它们根据自己的权重影响工资,这些权重在等式中用问号表示,因为我们实际上并不知道这些权重是什么。

现在,让我们想象一下,如果我们确切地知道这些重量,会发生什么。然后,如果我们不知道某个员工的工资,我们可以使用这些特征(资格、服务年限等)。)来预测员工的工资,也就是说,我们会明白这些特性和目标值(工资)是如何相关的。

原来,线性回归就是用来做这件事的!它用于获得对这些权重的良好估计,以便它们可以用于预测未知数据的目标值。在机器学习领域,这些权重通常被称为参数,因此从现在开始,我们在这里也将采用这个术语。

梯度下降算法

既然我们已经掌握了什么是线性回归,我们可以进入如何的部分。这个算法是如何工作的?如何才能算出线性回归的这些参数呢?

在机器学习中,还有另一个著名的算法叫做梯度下降,它被广泛使用,不仅用于估计线性回归的参数,也用于其他优化问题。在梯度下降算法中,从参数的初始值开始,在每一步迭代地改变模型的参数。

再次提醒我们,参数(权重)是决定每个特性对目标值影响程度的数值。

我们想要确切地知道这些参数值,但是在现实生活中这是不可能的,因为可能有其他特征(因此,也有那些特征的参数)影响目标值。

但是,我们希望他们预测的目标值尽可能接近实际值。由于上式中的问号代表参数值,我们可以用如下值替换它们:

工资=(1000x资历)+(200x工龄)+(500x与上司相处 )

在这里,很明显,资格特征比其他特征对工资的影响更大,因为它的参数值高于其他特征。

请记住,我们已经直观地选择了这些参数值,我们将使用它们作为我们的初始参数值,然而这些初始值将在算法的每一步朝着它们的最优值变化。

按照我们的类比,假设我们对这些特性的参数有一个初步的估计,我们四处走访,向我们能找到的第一个员工问了这些问题:

  • 你在这里工作多久了?
  • 你有什么资格申请这个职位?
  • 你和你的老板相处得怎么样?(你的老板看起来是喜欢你还是不喜欢你?)

对于第一个问题,我们告诉该员工,我们将接受几年后的答案(1 年、2 年、5 年等)。).

对于第二个问题,我们告诉该员工,答案可以是 1 到 10 之间的任意数字(1 表示最不符合条件,10 表示最符合条件)。

对于最后一个问题,答案将是一个从-5 到 5 的数字。在这里,负号代表员工和老板之间关系的消极性。因此,-5 意味着老板很不喜欢这个员工,0 意味着老板甚至不认识这个员工和/或两人之间没有互动,而+5 意味着他们两个相处得很好。

当我们问员工这些问题时,我们得到的回答是:

  • 我已经在这里工作 10 年了。
  • 老实说,对于这份工作来说,我大材小用了。所以我给它打 9 分。
  • 我的老板似乎讨厌我。每当我在他身边,我都能看到他眼中的仇恨。所以我给它打 a -4。

请记住,我们希望根据我们选择的参数和我们从员工那里得到的答案来预测工资。在仅仅根据这些答案预测了工资后,我们问雇员她的实际工资是多少。

预测值和实际值之间的差异决定了我们对这些参数(权重)的估计有多成功。梯度下降算法的工作就是让这个差异(预测-实际)尽可能的小!。

让我们将这个差异称为 误差 ,因为它表示实际值与预测值的差异。现在,让我们将从第一名员工的回答中得到的数字代入我们的等式:

工资=(1000x10)+(200x9)+(500x-4)

因此,这表明我们对工资的预测是:

预测 薪资 = 12800

现在,在从雇员那里获得实际工资值后,我们计算实际工资值和预测工资值之间的误差:

实际 工资 = 9800

误差 = 预测 薪资- 实际 薪资 = 12800 - 9800 = 3000

我们看到我们的误差是 3000 ,我们想通过适当调整参数值使这个误差尽可能小。但是我们怎么做呢?

我们如何决定改变参数值的正确方法?

显然,我们可以直观地进行猜测,改变参数值(增大或减小),使误差足够小。然而,如果我们有一百个特性,而不是只有三个,这是不切实际的。一百个特征意味着一百个参数值,记得吗?

显然,我们必须找到比这更好的方法。

此外,还有一个问题需要考虑。这个错误不能只代表一个雇员,换句话说,我们不能只改变一个雇员的参数值,因为我们希望这个模型代表在 x 公司工作的所有雇员。

我们必须从每个员工那里得到答案,并将这些值代入等式,找出错误并相应地更改参数。

我们这里使用的误差函数(误差=预测-实际)是机器学习中最基本的函数之一,它有一定的局限性。因此,在实现线性回归时,我们将使用一个更复杂的版本,称为 误差平方和(SSE) ,它只是实际值和预测值之间的平方差之和。

现在,快速改变符号是为了。术语 成本 经常被用来代替 误差 我们在这里也会用到,因为成本会让我们与实际值相差一些。如果预测值等于实际值,成本将为零。

因此,成本函数用于衡量模型在估计要素值和目标值之间关系的能力方面有多差。

在确定使用哪个成本函数之后,我们现在可以继续。 梯度下降算法的整点就是最小化代价函数 当我们最小化成本函数时,我们实际上是在确保尽可能低的误差,同时提高我们模型的准确性。我们迭代地检查数据集,同时在每一步更新参数。

回到我们的类比,记得我们有三个参数(资历、服务年限、与老板相处)我们想要 朝最小化成本函数 的方向改变。因此,检查我们数据集中的每个数据点基本上意味着向在 X 公司工作的每个员工询问我们形成的 3 个问题,将我们从答案中提取的值插入成本函数,并决定下一步应该采取的方向,以便最小化成本函数。

现在,我们如何决定我们应该朝哪个方向前进以降低总成本呢?

微积分在这里对我们有帮助。当我们想最小化一个函数时,我们对一个变量求导,然后用这个导数来决定方向。

在我们的类比中,我们选择的参数实际上是我们的成本函数的变量,因为成本函数随着每个参数的变化而变化(因此,变量,咄!).

我们必须对每个参数求导,并用这些导数值更新参数。在下图中,我们可以看到一个参数(服务年限)的成本函数图。

现在,当我们计算成本函数仅关于这个参数的偏导数时,我们得到了我们需要为这个参数移动的方向,以便达到斜率等于 0 的局部最小值。

当我们对每个参数求导并找到我们需要前进的方向时,我们同时更新每个参数:

更新 工龄 = 工龄- (学习率 x 偏导数 w.r.t .工龄)

更新规则分别应用于所有使用偏导数的参数。

当我们应用更新规则一次时,意味着我们正在迭代数据集一次。

这里,学习率,也称为学习步长,是学习期间参数更新的量。学习率是一个可配置的超参数,通常在 0.0 和 1.0 之间选择,它定义了模型学习的速率或速度。

  • 如果学习率足够高,模型学习得很快。
  • 如果太高,我们可能会在学习过程中错过最佳值,因为我们可能已经迈出了一大步。
  • 如果太低,那么模型将花费大量时间来收敛到最低成本函数值。

显然,调优这个超参数在机器学习中是非常重要的!。

因此,一次迭代意味着只向每个雇员问一次这三个问题(或者检查一次数据集),并相应地更新参数值。

在多次迭代数据集之后,当我们到达一个点时,迭代停止,在这个点上,成本足够低,我们可以决定停止算法,并使用到目前为止更新的参数值。然后,我们可以使用那些优化的值来预测新特征值的新目标值。

这里我们所说的优化是什么意思?好了,在我们已经为我们的三个特征找到参数值之后,现在他们可以以最低的可能误差预测新的目标值。

因此,我们在模型中优化了这些参数。这就是机器学习真正发生的地方。我们学习最小化我们的成本函数的参数。

既然我们已经对线性回归模型有了相当深刻的理解,那么是时候用我们可爱的 Python 编程语言对它进行编码了。

你可以从这里阅读编码部分,也可以查看我的 GitHub 简介沿着 jupyter 笔记本阅读或者简单地使用代码来实现。

编码快乐!

有问题吗?评论?通过leventbas92@gmail.com或 GitHub 联系我。

使用 NumPy 从头开始线性回归—实现(最终!)

原文:https://towardsdatascience.com/linear-regression-from-scratch-with-numpy-implementation-finally-8e617d8e274c?source=collection_archive---------3-----------------------

欢迎使用 NumPy 系列从零开始学习线性回归的第二部分!在解释了线性回归背后的直觉之后,现在是时候深入研究实现线性回归的代码了。如果你想了解线性回归的直觉,你可以从这里阅读本系列的前一部分。现在,让我们把手弄脏吧!

首先,我们首先导入必要的库来帮助我们。正如我之前提到的,我们不会使用任何给我们已经实现的算法模型的包,比如sklearn.linear_model,因为它不会帮助我们掌握实现算法的基本原理,因为它是一个开箱即用的(因此是现成的)解决方案。我们想用强硬的方式,而不是简单的方式。

此外,请注意,我们可以使用sklearn包(或其他包)来利用它的有用功能,例如加载数据集,只要我们不使用它已经实现的算法模型。

我们将使用:

  • numpy(显然)在数据集上进行所有的矢量化数值计算,包括算法的实现,
  • matplotlib借助一些视觉辅助工具绘制图表,以便更好地理解手头的问题,
  • sklearn.datasets加载一个玩具数据集来玩我们写的代码。
Total samples in our dataset is: 506

现在,是时候加载我们将在本文中使用的数据集了。sklearn.datasets包提供了一些玩具数据集来说明一些算法的行为,我们将使用load_boston()函数返回一个回归数据集。这里,dataset.data代表特征样本,dataset.target返回目标值,也称为标签

值得注意的是,当我们加载目标值时,我们向数据添加了一个新的维度(dataset.target[:,np.newaxis]),这样我们就可以将数据用作列向量。记住,线性代数区分了行向量和列向量。

然而,在 NumPy 中,只有 n 维数组,本质上没有行列向量的概念。我们可以使用形状为(n, 1)的数组来模拟列向量,使用(1, n)来模拟行向量。因此,我们可以通过显式添加一个轴,将形状(n, )的目标值用作形状(n, 1)的列向量。幸运的是,我们可以用 NumPy 自己的newaxis函数来做到这一点,该函数用于在使用一次后将数组的维度增加一个维度。

我们已经选择了( 1/2) x 均方误差(MSE) 作为我们的成本函数,所以我们将在这里实现它。h表示我们的假设函数,它只是我们从输入(X)到输出(y)的映射的候选函数。

当我们用参数(X @ params)取我们的特征的内积时,我们明确地声明我们将从其他机器学习算法的广泛列表中为我们的假设使用线性回归,也就是说,我们已经决定特征和目标值之间的关系最好由线性回归来描述。

我们现在可以实现梯度下降算法。这里,n_iters表示梯度下降的迭代次数。我们希望保存每次迭代中由成本函数返回的成本历史,因此我们使用了一个 NumPy 数组J_history来实现这个目的。

关于更新规则,1/n_samples) * X.T @ (X @ params - y)对应于成本函数相对于参数的偏导数。因此,params根据更新规则保存更新的参数值。

在我们对数据集运行梯度下降算法之前,我们对数据进行标准化。标准化是一种技术,通常作为机器学习管道中数据准备的一部分,通常意味着将值重新调整到[0,1]的范围内,以提高我们的准确性,同时降低成本(误差)。另外,请注意,我们将参数(params)初始化为零。

Initial cost is:  296.0734584980237 Optimal parameters are: [[22.53279993][-0.83980839][ 0.92612237][-0.17541988][ 0.72676226][-1.82369448][ 2.78447498][-0.05650494][-2.96695543][ 1.80785186][-1.1802415 ][-1.99990382][ 0.85595908][-3.69524414]] Final cost is:  [11.00713381]

你有它!我们已经成功地运行了该算法,因为我们可以清楚地看到,成本从 296 急剧下降到 11。gradient_descent函数返回最佳参数值,因此,我们现在可以使用它们来预测新的目标值。

线性回归的类实现

最后,从零开始实现线性回归后,我们可以重新安排我们到目前为止编写的代码,添加更多的代码,进行一些修改,并将其转换为一个类实现,这样我们就有了自己的线性回归模块!给你:

请注意我们的实现和sklearn自己的线性回归实现之间的相似之处。

当然,我是故意这样做的,向您展示我们可以编写一个广泛使用的模块的简化版本,其工作方式类似于sklearn的实现。

不过,我这么做主要是为了好玩!

将我们的实现与 Sklearn 的线性回归进行比较

我们在实施方面做得很好,不是吗?我们的训练精度几乎和sklearn的精度一样。此外,与sklearn的测试精度相比,测试精度并不差。

毫无疑问,这很有趣。我鼓励你在读完这篇文章后自己编写代码。

你也可以查看我的 GitHub 简介,沿着 jupyter 笔记本阅读代码,或者简单地使用代码来实现。

将来我会带着更多的实现和博客文章回来。

编码快乐!

有问题吗?评论?通过leventbas92@gmail.com和 GitHub 联系我。

python 生态系统中的线性回归

原文:https://towardsdatascience.com/linear-regression-in-a-python-ecosystem-71db2bb1afc0?source=collection_archive---------22-----------------------

Photo by Steve Johnson on Unsplash

最受欢迎的监督机器学习算法之一是线性回归。线性回归在统计学领域根深蒂固,因此必须检查模型的拟合优度。

线性回归是预测定量反应的简单而有用的工具。回归的总体思想是检查两件事。首先,它检验一组独立变量(X)是否能很好地预测一个结果变量(Y)。其次,它决定了哪些变量是结果变量的重要预测因素,以及它们如何通过β估计值的大小和符号来表明结果变量的影响。这些线性回归估计用于解释一个因变量之间的关系。数学上,线性回归估计线性回归函数,定义为:

y = c + b*x+b

其中 y =估计的因变量得分,c =常数,b =回归系数,x =自变量得分。

回归技术有多种形式——线性、非线性、有毒、基于树的,但核心思想在整个范围内几乎是相似的,可以应用于各种数据驱动的分析问题,无论是在金融、医疗保健、服务、制造、农业等领域。线性回归是基本技术,,它深深植根于久经考验的统计学习和推理理论,并为现代数据科学管道中使用的所有基于回归的算法提供支持。

然而,线性回归模型的成功还取决于一些基本假设 : 它试图建模的基础数据的性质。

通过验证这些假设是否合理地满足来检查您的线性回归模型的质量是至关重要的(一般来说,视觉分析方法被用于检查假设,这取决于解释)。

问题在于,检查模型质量通常是数据科学管道中优先级较低的一个方面,其他优先级占主导地位,如预测、缩放、部署和模型调整。

我们经常使用 statsmodels 库通过运行拟合优度测试来检查模型?在基于 Python 的数据科学学习课程中,这样的情况很常见:

通常,有很多关于正则化、偏差/方差权衡或可扩展性(学习和复杂性曲线)图的讨论。但是,围绕以下情节和列表有足够的讨论吗?

  • 残差与预测变量图
  • 拟合与残差图
  • 归一化残差的直方图
  • 归一化残差的 Q-Q 图
  • 残差的夏皮罗-维尔克正态性检验
  • 残差的库克距离图
  • 预测特征的方差膨胀因子(VIF)

Scikit-learn 的问题

可以有把握地假设,大多数由统计学家转变为数据科学家的人定期对他们的回归模型进行拟合优度测试。

但是,对于数据驱动的建模,许多新手数据科学家严重依赖于像 Scikit-learn 这样的以 ML 为中心的包,尽管这些包是一个令人敬畏的库,并且实际上是机器学习和预测任务的银弹,但是它们不支持基于标准统计测试的简单快速的模型质量评估。

因此,除了使用 Scikit-learn 等以 ML 为中心的库之外,一个良好的数据科学管道还必须包括一些标准化的代码集,以使用统计测试来评估模型的质量。

这篇文章试图展示一个多元线性回归问题的标准评估集。我们将使用 statsmodels 库进行回归建模和统计测试。

线性回归假设概述

对于多元线性回归,从统计推断的角度来看,判断多重共线性(相关变量)也很关键。这种假设假设预测变量之间的线性相关性最小或没有线性相关性。

异常值也可能是一个影响模型质量的问题,因为它对估计的模型参数具有不成比例的影响。
以下是一段视频回顾:

有哪些地块可以查?所以,错误术语非常重要。

但是有一个坏消息。不管我们有多少数据,我们永远无法知道真正的错误。我们只能对产生数据的分布进行估计和推断。

因此,真实误差的代理是残差,残差就是观测值和拟合值之差。

底线-我们需要绘制残差图,检查它们的随机性质、方差和分布,以评估模型质量。这是线性模型拟合优度估计所需的视觉分析。

除此之外,多重共线性可以通过相关矩阵和热图进行检查,数据中的异常值(残差)可以通过所谓的库克距离图进行检查。

回归模型质量评估

我们使用来自 UCI ML 门户网站的混凝土抗压强度预测问题。混凝土抗压强度是龄期和成分的高度复杂的函数。我们能从这些参数的测量值预测强度吗?本帖的代码回购可以在作者的 Github 上查看。

检验线性的独立变量散点图
我们可以简单地通过目测线性假设来检验散点图。

成对散点图和相关热图用于检查多重共线性
我们可以使用 seaborn 库中的 pairplot 函数来绘制所有组合的成对散点图。

使用 Pandas,我们可以轻松计算关联矩阵,并将其传递到 statsmodels 的特殊绘图功能,将关联可视化为热图。

使用 statsmodel.ols()函数进行模型拟合
使用 statsmodels 进行主模型拟合。OLS 方法。这是一个线性模型拟合实用程序,感觉非常像 R 中强大的“lm”函数。最棒的是,它接受 R 风格的公式来构建完整或部分模型(即涉及所有或部分自变量)。

在大数据时代,为什么要费心创建一个局部模型,而不把所有数据都扔进去呢?这是因为数据中可能存在混杂或隐藏的偏差,这只能通过 控制某些因素 来解决。

简而言之,通过该模型拟合的模型已经提供了关于该模型的丰富的统计信息,例如对应于所有自变量的 t 统计量和 p 值、R 平方和调整的 R 平方、AIC 和 BIC 等。

残差与独立变量的关系图
接下来,我们可以绘制残差与每个独立变量的关系图,以寻找独立性假设。
如果残差围绕零个 x 轴均匀随机分布,并且不形成特定的集群*,则假设成立。在这个特殊的问题中,我们观察到一些集群。*

拟合与残差图检查同方差
当我们绘制拟合响应值(根据模型)与残差图时,我们清楚地观察到残差的
方差随着响应变量幅度*的增加而增加。因此,该问题不考虑同质性,可能需要某种变量变换来提高模型质量。*

归一化残差的直方图和 Q-Q 图
为了检查数据生成过程的正态性假设,我们可以简单地绘制归一化残差的直方图和 Q-Q 图。

此外,我们可以对残差进行夏皮罗-维尔克检验,以检查正态性。

使用库克距离图的异常值检测
库克距离本质上是测量删除给定观察的效果。需要仔细检查 Cook 距离较大的点是否为潜在的异常值。我们可以使用 statsmodels 中的特殊异常值影响类来绘制厨师的距离。

方差影响因素-VIF
此数据集的 OLS 模型摘要显示了多重共线性的警告。但是如何检查是哪些因素造成的呢?
我们可以计算每个自变量的方差影响因子。它是有多个项的模型的方差除以只有一个项的模型的方差的比率。同样,我们利用了 statsmodels 中的特殊异常值影响类。

其他残差诊断
Statsmodels 有多种其他诊断测试用于检查模型质量。
请随意查看这些资源:**

  • 剩余诊断测试
  • 拟合优度测试

结论

在本文中,我们介绍了如何在线性回归中添加用于模型质量评估的基本可视化分析——各种残差图、正态性测试和多重共线性检查。

目前,scikit-learn 没有用于模型质量评估的详细统计测试或绘图功能, Yellowbrick 是一个很有前途的 Python 库,它可以在 scikit-learn 对象上添加直观的可视化功能。我们希望在不久的将来,统计测试可以直接添加到 scikit-learn ML 估计量中。

感谢你阅读我的帖子。

Python 中的线性回归

原文:https://towardsdatascience.com/linear-regression-in-python-64679ab58fc7?source=collection_archive---------7-----------------------

https://www.pexels.com/photo/concentrated-black-kid-doing-sums-5905857/

所以你决定学习机器学习。无论你是出于职业原因还是纯粹出于好奇,你都来对地方了。在接下来的文章中,我们将了解机器学习的“Hello World”线性回归

算法

在机器学习的背景下,当人们谈到模型时,他们指的是在给定一组输入( x1,x2,x3… )的情况下用于预测因变量( y )的函数。在线性回归的情况下,模型采用 y = wx + b 的形式。

假设我们绘制了学习时间和期末考试成绩之间的关系。

接下来,假设我们为我们的模型任意选择了 y = 3x + 2 。如果我们画一条相应的线,它可能看起来像这样。

线性回归的目标是找到最佳拟合线,其中最佳拟合线由具有最小可能损失的线定义。最常用的损失函数之一是均方误差(MSE)。它的方程式写如下。

我们通过从一个数据点减去另一个数据点来计算从直线到给定数据点的距离。我们取误差的平方,因为我们不希望低于实际值的预测值被高于实际值的预测值抵消。换句话说,我们想消除负面影响。你还会看到人们使用平均绝对误差(MAE ),只要你在比较模型时坚持使用一个,使用一个比另一个没有任何优势。我们对距离求和,以获得整个数据集的总误差。然后我们将它除以样本总数,因为当你比较模型时,样本越多的数据集误差越大,因为它的样本越多。

在前面的图像中,从直线到每个点的距离被绘制为红色箭头。

梯度下降

如果我们画一个曲线图,描述斜率 w 和总损耗 T23 之间的关系,它看起来如下。

它呈现抛物线形状,因为当斜率 w 接近无穷大时,损耗趋于无穷大。

此外,随着斜率 w 接近负无穷大,损耗趋于无穷大。

当损失最小时,最佳拟合线的斜率将等于 w 的值。

我们可以利用梯度下降算法向全局最小值收敛,而不是以伪随机方式选择斜率值(即查看图表并进行有根据的猜测)。

梯度是微积分中一个众所周知的概念。梯度是偏导数的向量,它总是指向最陡上升的方向(在 f(x) 中最大增加的方向)。

然而,在我们的例子中,我们正在寻找使我们的损失函数最小化的方向,因此“ 【下降】【梯度下降】。

为了确定损失函数曲线上的下一个点,梯度下降算法将梯度大小的一部分添加到起始点,如下图所示。

梯度的大小乘以一个叫做学习率的东西。学习率决定了算法的步长。

例如,如果幅度梯度(偏导数)为 10,学习率为 0.01,那么梯度下降算法将选择距离前一个点 0.1 的下一个点。

如果我们有大量的数据,并且选择的学习率太小,那么训练我们的模型可能需要很长时间。从表面上看,这听起来没那么糟糕,但是一个需要花几天时间训练的模型很难进行调整和实验。

如果学习率太大,我们可能会错过全局最小值。

对于每个回归问题,都有一个既不太大也不太小的金发女孩学习率。数据科学家的部分工作是处理超参数(即学习率和迭代次数),否则学习过程可能会花费太长时间和/或最终结果不佳。

让我们看看梯度下降的数学基础。我保证没那么糟。首先,我们用直线方程代替回归线的 y 值。

然后我们计算斜率和 y 轴截距的偏导数。

为了确定每个变量的新值,我们在每次迭代中重复这个过程。正如我们之前提到的,我们将梯度乘以一个叫做学习率的常数。值得一提的是,方程是单独写的,但更多的时候你会看到它被写成一个向量。

在训练了我们的线性回归模型( y = wx + b )之后,我们获得了我们的数据集的最佳拟合线。

然后,我们可以使用我们的模型,根据学生学习的小时数来预测他们的成绩。

密码

让我们看看如何使用 Python 从头开始实现线性回归。首先,导入以下库。

from sklearn.datasets import make_regression
from matplotlib import pyplot as plt
from sklearn.linear_model import LinearRegression
import seaborn as sns
sns.set()

我们可以使用scikit-learn库来生成非常适合回归的样本数据。

x, y = make_regression(n_samples=50, n_features=1, n_informative=1, n_targets=1, noise=5)

很多时候,你需要某种基准来衡量你的模型的性能,通常对于回归问题,我们使用平均值。

starting_slope = 0
starting_intercept = float(sum(y)) / len(y)

我们利用matplotlib来绘制数据和平均值。

plt.scatter(x, y)
plt.plot(x, starting_slope * x + starting_intercept, c='red')

接下来,我们编写一个函数来计算均方差。

def mse(y_actual, y_pred):error = 0for y, y_prime in zip(y_actual, y_pred):error += (y - y_prime) ** 2return error

均方差越高,模型越差。想象一下从直线到每个数据点的箭头。

mse(y, starting_slope * x + starting_intercept)

接下来,让我们看看如何从头开始实现梯度下降。

我们创建一个函数来计算斜率和截距的偏导数。

def calculate_partial_derivatives(x, y, intercept, slope):partial_derivative_slope = 0partial_derivative_intercept = 0n = len(x) for i in range(n):xi = x[i]yi = y[i] partial_derivative_intercept += - (2/n) * (yi - ((slope * xi) +      intercept))partial_derivative_slope += - (2/n) * xi * (yi - ((slope * xi) + intercept))return partial_derivative_intercept, partial_derivative_slope

然后,我们定义一个函数,通过向解决方案迈出一小步来迭代改进我们的模型。

def train(x, y, learning_rate, iterations, intercept, slope):for i in range(iterations):partial_derivative_intercept, partial_derivative_slope = calculate_partial_derivatives(x, y, intercept, slope)intercept = intercept - (learning_rate * partial_derivative_intercept)slope = slope - (learning_rate * partial_derivative_slope)return intercept, slope

我们任意选择学习率和迭代次数。对于额外的练习,我建议您尝试替换一些其他值,并观察模型的行为。

learning_rate = 0.01
iterations = 300

接下来,我们训练模型并获得最佳拟合线的截距和斜率值。

intercept, slope = train(x, y, learning_rate, iterations, starting_intercept, starting_slope)

我们使用列表理解来获得沿着我们的线的每个 x 值对应的 y 值。

linear_regression_line = [slope * xi + intercept for xi in x]

我们绘制数据来看看我们做得如何。

plt.scatter(x, y)
plt.plot(x, linear_regression_line, c='red')

看起来比平均水平好多了。然而,在比较模型时,有时使用更具体的东西会有所帮助。

mse(y, linear_regression_line)

如我们所见,均方误差比平均值产生的误差低得多。

我们可以使用scikit-learn库提供的预定义类,而不是每次都从头开始实现梯度下降算法。首先,我们创建一个类LinearRegression的实例。

lr = LinearRegression()

然后,我们通过调用fit方法来训练模型。

lr.fit(x, y)

为了获得沿线的值,我们调用predict函数。

y_pred = lr.predict(x)

正如我们所看到的,我们得到或多或少相同的结果。

plt.scatter(x, y)
plt.plot(x, y_pred, c='red')

均方误差略好于我们的实现。我鼓励你检查源代码,找到我们的原因。

mse(y, y_pred)

线性回归模型

原文:https://towardsdatascience.com/linear-regression-models-4a3d14b8d368?source=collection_archive---------3-----------------------

使用 Python 和 SciKit 更好地理解线性回归模型的指南-学习

Photo by Benjamin Smith on Unsplash

可以说,回归任务的最佳起点是线性模型:它们可以快速训练并易于解释。

线性模型使用输入要素的线性函数进行预测。在这里,我们将探索 Scikit-Learn 中一些流行的线性模型。

完整的 Jupyter 笔记本可以在这里找到。

数据

这里我们将使用 SciKit-Learn 糖尿病数据集来回顾一些流行的线性回归算法。

该数据集包含 10 个特征(已经过均值居中和缩放)和一个目标值:基线后一年疾病进展的量度。

我们导入数据并为建模做准备:

from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split# load regression dataset
diabetes, target = load_diabetes(return_X_y=True)
diabetes = pd.DataFrame(diabetes)# Prepare data for modeling
# Separate input features and target
y = target
X = diabetes# setting up testing and training sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=27)

评估指标:R

r 平方,或决定系数,是我们的模型所解释的目标变量的变化量。

值的范围从 0 到 1。较高的值表示模型具有高度预测性。例如,R 值为 0.80 意味着模型解释了数据中 80%的可变性。

一般来说,R 值越高越好。低值表明我们的模型不太擅长预测目标。然而,需要注意的是,过高的 R 可能是过度拟合的迹象。

我们将使用以下函数来获取模型的交叉验证分数:

from sklearn.model_selection import cross_val_score# function to get cross validation scores
def get_cv_scores(model):scores = cross_val_score(model,X_train,y_train,cv=5,scoring='r2')print('CV Mean: ', np.mean(scores))print('STD: ', np.std(scores))print('\n')

线性回归(普通最小二乘法)

线性回归找出使预测值和目标值之间的均方误差或残差最小的参数。

均方误差定义为预测值和真实值之间的平方差之和除以样本总数。

为了生成线性回归,我们使用 Scikit-Learn 的LinearRegression类:

from sklearn.linear_model import LinearRegression# Train model
lr = LinearRegression().fit(X_train, y_train)# get cross val scores
get_cv_scores(lr)[out]
### CV Mean:  0.4758231204137221
### STD:  0.1412116836029729

我们得到 0.48 的 R 值和 0.14 的标准偏差。低 R 值表明我们的模型不是很精确。标准偏差值表明我们可能过度拟合了训练数据。

当模型对已知数据的预测比对未知数据的预测好得多时,就会发生过度拟合。该模型开始记忆训练数据,并且不能推广到看不见的测试数据。

克服过度拟合的一个选择是简化模型。我们将尝试通过引入正则化来简化我们的线性回归模型。

正则化可以定义为明确地限制模型以防止过度拟合。

由于线性回归没有参数,所以没有办法控制模型的复杂程度。我们将在下面探索一些增加正则化的变化。

岭回归(L2 正则化)

岭回归使用 L2 正则化来最小化系数的大小。它减少了系数的大小,有助于降低模型的复杂性。

我们用正则化参数⍺.来控制模型的复杂性

较高的⍺值迫使系数向零移动,并增加了对模型的限制。这降低了训练性能,但也增加了模型的可推广性。将⍺设置得太高可能会导致模型过于简单,数据不足。

Ridge Regression

⍺值越低,系数受到的限制就越少。当⍺很小时,模型变得更类似于上面的线性回归,我们有过度拟合的风险。

让我们看看是否可以使用 Scikit-Learn 的Ridge类来提高性能:

**from** sklearn.linear_model **import** Ridge*# Train model with default alpha=1* ridge **=** Ridge(alpha**=**1).fit(X_train, y_train)*# get cross val scores* get_cv_scores(ridge)[out]
### CV Mean:  0.3826248703036134
### STD:  0.09902564009167607

平均 R 值为 0.38 意味着我们只能用岭回归模型解释 38%的方差——与上面的线性回归相比,肯定没有改进。然而,我们的标准差降低了,这表明我们不太可能过度拟合。

我们在上面使用了 alpha 的默认值,这可能不会给出最好的性能。α的最佳值将随每个数据集而变化。

让我们看看是否可以通过调整 alpha 值来提高 R 值。我们将使用网格搜索来找到一个最佳的 alpha 值:

# find optimal alpha with grid search
alpha = [0.001, 0.01, 0.1, 1, 10, 100, 1000]
param_grid = dict(alpha=alpha)grid = GridSearchCV(estimator=ridge, param_grid=param_grid, scoring='r2', verbose=1, n_jobs=-1)
grid_result = grid.fit(X_train, y_train)print('Best Score: ', grid_result.best_score_)
print('Best Params: ', grid_result.best_params_)[out]
### Best Score:  0.4883436188936269
### Best Params:  {'alpha': 0.01}

我们的 R 分数通过为 alpha 优化而增加!但是 0.48 的 R 分还是不太好。让我们看看是否可以使用其他类型的正则化来进一步改善这一点。

拉索回归(L1 正则化)

Lasso 回归使用 L1 正则化来强制某些系数恰好为零。这意味着模型完全忽略了一些特征。这可以被认为是一种自动特征选择!

当我们有大量的特征,但期望只有少数特征是重要的时,Lasso 可以是一个很好的模型选择。这样可以让模型更容易解读,揭示最重要的特征!

较高的⍺值会迫使更多的系数为零,从而导致拟合不足。

Lasso Regression

alpha 值越低,非零特征越少,并可能导致过度拟合。非常低的 alpha 值将导致模型类似于线性回归。

让我们在糖尿病数据集上尝试 Lasso 回归:

from sklearn.linear_model import Lasso# Train model with default alpha=1
lasso = Lasso(alpha=1).fit(X_train, y_train)# get cross val scores
get_cv_scores(lasso)[out]
### CV Mean:  0.3510033961713952
### STD:  0.08727927390128883

我们在上面使用了 alpha 的默认值,这可能不会给出最好的性能。α的最佳值将随每个数据集而变化。

让我们看看可以通过调整阿尔法值来提高 R 值。我们将使用网格搜索来找到一个最佳的 alpha 值:

# find optimal alpha with grid search
alpha = [0.001, 0.01, 0.1, 1, 10, 100, 1000]
param_grid = dict(alpha=alpha)grid = GridSearchCV(estimator=lasso, param_grid=param_grid, scoring='r2', verbose=1, n_jobs=-1)
grid_result = grid.fit(X_train, y_train)print('Best Score: ', grid_result.best_score_)
print('Best Params: ', grid_result.best_params_)[out]
### Best Score:  0.48813139496070573
### Best Params:  {'alpha': 0.01}

通过优化 alpha,我们的分数提高了!

我们可以检查这些系数,看看是否有任何系数被设置为零:

# match column names to coefficients
for coef, col in enumerate(X_train.columns):print(f'{col}:  {lasso.coef_[coef]}')[out]
age:  20.499547879943435
sex:  -252.36006394772798
bmi:  592.1488111417586
average_bp:  289.434686266713
s1:  -195.9273869617746
s2:  0.0
s3:  -96.91157736328506
s4:  182.01914264519363
s5:  518.6445047270033
s6:  63.76955009503193

s2的系数为零。完全被模型忽略了!

我们将尝试最后一种类型的回归,看看我们是否可以进一步提高 R 分数。

弹性网回归

弹性网是一个线性回归模型,结合了套索和山脊的惩罚。

我们使用l1_ratio参数来控制 L1 和 L2 正则化的组合。当l1_ratio = 0我们有 L2 正则化(岭),当l1_ratio = 1我们有 L1 正则化(套索)。介于 0 和 1 之间的值给出了 L1 正则化和 L2 正则化的组合。

我们首先用默认参数拟合弹性网,然后使用网格搜索找到alphal1_ratio的最佳值:

from sklearn.linear_model import ElasticNet# Train model with default alpha=1 and l1_ratio=0.5
elastic_net = ElasticNet(alpha=1, l1_ratio=0.5).fit(X_train, y_train)# get cross val scores
get_cv_scores(elastic_net)[out]
### CV Mean:  -0.05139208284143739
### STD:  0.07297997198698156# find optimal alpha with grid search
alpha = [0.001, 0.01, 0.1, 1, 10, 100, 1000]
l1_ratio = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
param_grid = dict(alpha=alpha, l1_ratio=l1_ratio)grid = GridSearchCV(estimator=elastic_net, param_grid=param_grid, scoring='r2', verbose=1, n_jobs=-1)
grid_result = grid.fit(X_train, y_train)print('Best Score: ', grid_result.best_score_)
print('Best Params: ', grid_result.best_params_)[out]
### Best Score:  0.48993062619187755
### Best Params:  {'alpha': 0.001, 'l1_ratio': 0.8}

同样,在找到最佳超参数值后,我们的 R 值增加了。

结论

我们探索了四种不同的线性回归模型:

  • 线性回归
  • 山脉
  • 套索
  • 弹性网

我们通过正则化简化了我们的模型。不幸的是,我们的 R 分数仍然很低。

在以后的文章中,我们将探索线性回归的假设和更多提高模型性能的方法。

Python 中的线性回归

原文:https://towardsdatascience.com/linear-regression-on-housing-dataset-a57ef8bf2e60?source=collection_archive---------22-----------------------

线性回归可以说是数据科学中最重要和最常用的模型之一。在这篇博文中,我将带您浏览创建线性回归模型的过程,并向您展示一些很酷的数据可视化技巧。

我们将使用埃姆斯住房数据集,这是经常被引用的波士顿住房数据集的扩展版本。该数据集大约有 1,700 行和 81 列,目标是预测市场上的销售价格。

我们开始吧!

就像任何其他项目一样,第一步是导入所有的库。当您找到构建模型所需的所有工具时,您可以导入更多的库。

现在,在我们处理或更改数据之前,让我们先了解一下我们在处理什么。

数据集的简短描述向我们展示了它包含各种数据类型和空值。在我们处理数据和构建模型时,记住这一点很重要。

数据预处理

现实世界中的数据集从来都不是完美的。总会有遗漏值和异常值扭曲数据集,影响我们预测模型的准确性。这就是为什么在开始构建模型之前清理数据总是一个好主意。

之前,我提到过这个数据集有 1,700 行和 81 列。如果某一列中缺少某个值,删除整行是不明智的,因为我们还会在其他列中丢失一个数据点。有两种方法可以解决这个问题:

  1. 用特定列的中值替换给定列中的每个空值。(这仅适用于带有数值的列)
  2. 计算您的统计数据,同时忽略所有空值。(我将在博客的后面告诉你使用什么方法)。

我选择了第二种方法,所以我保留了数据集中的空值。

计算异常值

有多种方法可以计算异常值-z 值、四分位间距(IQR)和 Tukey 方法只是其中的几种方法。我选择使用 IQR。出于各种意图和目的,我假设您熟悉 IQR 的概念,所以我将只介绍如何用 Python 对其进行编码。如果你觉得你可以用一个简短的概述,这篇博文做了一个非常扎实的工作,解释了四分位数间距背后的关键思想。

为了计算第一个和第三个四分位数,我对数据集使用了 describe()函数。

summary = data_set.describe()

describe()函数生成一个简洁明了的数据框,其中包含来自原始数据集的每个数字列的重要统计数据。正如你在上面的图片中看到的,我现在只需要一行代码就可以访问平均值、标准差和百分位值了!

现在,我存储数据序列中每一列的统计数据。这允许我迭代地访问所有列中的百分比值。

现在让我们潜入深水区。在我将代码转储到这里之前,我将首先解释一下我是如何计算 IQR 的。

  1. 我创建了一个 for 循环来遍历每个数字列,因为我想计算所有列的 iqr 值。
  2. 在 for 循环中,我首先使用 summary _ 25%和 summary _ 75%系列来访问我的 q1 和 q3 值。
  3. 然后我计算了一下我的 iqr 范围(q3-q1)。
  4. 之后我计算了下界和上界。
  5. 接下来,我计算了给定列的第 98 和第 2 百分位值。我们将用这些值替换异常值。因为我们之前没有删除空值,所以我们将使用 nanpercentile()函数来计算百分位数,同时忽略空值。
  6. 最后,使用下限和上限来识别异常值,并用计算出的百分位值替换它们。

识别特征

现在我们已经处理了我们的数据,是时候创建我们的模型了,但是我们有 80 个潜在的独立变量。我们如何确定哪一个与目标变量 SalePrice 的相关性最强?

我为数据集中的每个变量和其他变量创建了一个关联矩阵。

相关矩阵太大了,无法在一张截图中捕捉到,所以这个缩小的模糊版本就足够了——尽管你已经明白了要点。从相关矩阵中,我发现变量“总体质量”和“GrLivArea”与销售价格的相关性最高。

为了再次确认,我绘制了两个变量的散点图。

在这两种情况下,显然存在线性关系,所以我们可以开始了!

创建模型

若要创建模型,请将 X 和 y 设置为各自的列。使用 train_test_split() 函数,将数据集拆分为模型的训练和测试数据集。函数中的参数 test_size 表示应该为测试保留多少百分比的数据集。标准是 30%

测绘

线性回归在视觉上最有意义——当你实际上可以看到最佳拟合线的时候。下面是我用来绘制下图的代码,在图的下面,你会发现一个包含所有重要统计数据的模型摘要。

结论

我希望这次演练对您有所帮助!如果您有任何问题或建议,请随时留下您的评论!

线性回归

原文:https://towardsdatascience.com/linear-regression-part-1-7f4b2f43ed11?source=collection_archive---------34-----------------------

通过实用的方法进行温和的介绍

Photo by Ryan Stone on Unsplash

线性回归是最古老但仍然非常强大的算法之一。在解决任何回归问题时,任何数据科学从业者想到的第一个想法都是创建线性回归模型。在本文中,我将借助一个简单的例子,通过使用一个样本数据集实现这个算法来解释这个强大的算法。其背后的详细数学原理将在另一篇文章中介绍。敬请关注。(我建议您在阅读本文时实现代码)

我们开始吧!

导入所有必需的库。

我们首先导入将用于解决这个问题的所有基本库。我将在本文中使用“波士顿房价”数据集。该数据集在 scikit learn 中作为样本数据集提供。

现在我们已经导入了库,让我们创建我们的数据框架。

boston = load_boston()

这将返回一个包含特定键和值的 python 字典。要查看字典中的关键字,您可以执行以下操作:

print(boston.keys())

这将产生以下结果:

dict_keys(['data', 'target', 'feature_names', 'DESCR', 'filename'])

要查看数据集描述,可以使用 boston。DESCR ,描述数据集中的每个特征。

**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 oxide 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 centers
**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)², where Bk is the proportion of [people of African American descent] by town
**LSTAT**: Percentage of lower status of the population
**MEDV**: Median value of owner-occupied homes in $1000s

花点时间,试着阅读并清楚地理解每个变量的描述。我们必须始终清楚地了解我们正在处理的数据。

在这里,MEDV 是我们的目标变量,我们需要预测,其余的是我们的特征。

现在我们知道了数据的描述,让我们快速准备数据框架,开始动手做吧!

df = pd.DataFrame(boston.data,columns=boston.feature_names)
df.head()

First five records of the Boston dataset

您可能已经注意到缺少目标 MEDV,所以让我们创建一个名为“MEDV”的新列,并将目标添加到其中。

df['MEDV'] = boston.target

探索性数据分析和数据预处理

加载数据后,第一步是执行 EDA(探索性数据分析)来探索数据(是的,EDA 这个术语是不言自明的!)并了解数据。这是一个至关重要的部分,通常会占用大部分时间。一个适当和广泛的 EDA 将揭示有趣的模式,并有助于以更好的方式准备数据!(我会写一个单独的帖子,介绍在执行 EDA 时要遵循的最佳实践,我保证!)

首先,让我们检查一下我们正在处理的数据集的大小。

Size of the dataset

我们可以看到总共有 506 行和 14 列或特性。

接下来,让我们检查数据集中是否有任何缺失值。

df.isna().sum()

Column-wise count of missing values

耶!没有缺失值!这意味着需要处理的麻烦更少了。确保我们的数据没有任何缺失值是很重要的,尤其是在线性回归的情况下,因为如果数据有缺失值,线性回归将不起作用。

现在,让我们继续做一些基本的 EDA 来理解我们的数据。我将在这篇文章中做一个基本的和最小的 EDA。请随意使用您的数据。执行深入的 EDA 总是明智的,这在特性工程阶段很有帮助。(更多信息请见 EDA 上的另一篇文章!)

Probability density function (PDF) of CRIM

从图中可以明显看出,卷曲是右偏正偏。从上面的图表中我们可以看到,CRIM 的大部分值位于 0.01 和 0.3 之间,并且具有较大的分布(std。偏差= 8.6),因为超过 20,就很少有值,它们可能被认为是异常值。(更多信息在另一篇文章中,让我们把这篇文章局限于线性回归)

PDF(概率密度函数)在一张图中给出了很多信息(是的,这是我的最爱!)而且最好先看一下 PDF。

继续,ZN 的 PDF 有点类似。

我鼓励你继续下去,多摆弄一下数据,检查数据是如何分布的,并试图理解图表所传达的信息。因为这篇文章是关于线性回归的,所以我不会偏离主题去详细讨论 EDA。

(提示:使用多个图表,如箱线图、PDF、散点图、条形图等。以获得更好的直觉)

PDF of ZN

相关性分析是构建任何机器学习模型的关键部分。让我们计算我们的特征之间的相关性,并在热图中绘制出来。

correlation = df.corr()
sns.heatmap(correlation)

对于那些不太熟悉统计术语相关性的人来说,它是两个变量之间线性相关性的度量。换句话说,它解释了一个特性如何受到另一个特性的影响。

下面我计算了数据中不同变量之间的相关性,并绘制了相关矩阵。(太多颜色了!!)

Correlation matrix

很漂亮,不是吗?!

在这里,我们可以观察到我们的目标 MEDV 与 LSTAT 高度负相关。这意味着 LSTAT 的减少导致 MEDV 的增加。我鼓励你仔细看看这个矩阵,找到其中的关系。

我们已经看到在卷曲特征中有许多异常值(还记得我们谈论的 PDF 吗?).消除这些极端观察值的最简单方法之一是对要素应用对数变换。这减少了离群值对我们模型的影响。

(如果你想让数据集完全吻合,你还有很多工作要做!)

完成必要的转换和数据清理后,您就可以部署您的第一个机器学习模型了!刚果!

但是等等!我的模型在哪里?

让我们导入 scikit 学习库中可用的线性回归模型。(是啊,scikit learn 太酷了!)

from sklearn.linear_model import LinearRegression

就这么简单!让我们初始化我们的模型并拟合数据。

model = LinearRegression()

我不会在本文中深入研究数学,但我会给你一个线性回归方程的基本直觉,我们将在后面的帖子中探讨它。

ɛ

这里 y 是我们的因变量。x 是我们的特征矩阵,是参数向量(也称为权重,如果你喜欢这样),ɛ 是误差向量。

我们的线性回归试图通过找到来拟合一条穿过数据的直线,使得误差最小。

Image source: Wikipedia

如果你没有得到上面的数学,没问题!你可以继续写这篇文章。我将单独写一篇更详细的帖子,特别是关于这个美丽算法背后的所有数学知识。

现在我们的模型已经准备好了,我们可以训练它了。但是在训练我们的模型之前,将数据分成训练和测试数据集,使用训练数据来训练和测试数据来验证我们的模型,这总是一个好的做法。那么,让我们继续分割数据集。谢天谢地,scikit learn 又来帮忙了。

from sklearn.model_selection import train_test_splitX = df.drop(['MEDV'],axis=1)
y = df['MEDV']X_train,X_test,y_train,y_test = train_test_split(X,y,test_size = 0.2)

这里 X 是我们的独立变量(特性)列表,y 是我们的目标变量。我已经从特性中去掉了 MEDV,也就是说,我使用除了目标变量之外的所有东西作为我的特性。

在 train_test_split 中,test_size 表示测试数据集的大小。这里我传递了一个值 0.2,这意味着我们的整个数据现在分为 80%的训练数据和 20%的测试数据。

现在是你期待已久的一步!训练模型。

使用极其强大的 scikit learn,训练一个模型就像编写一行代码一样简单!

model.fit(X_train,y_train)

我们现在已经成功地训练了我们的线性回归模型。但是我们如何检查它的性能呢?

还记得我们从数据集中分离出来的测试数据吗?我们将用它来评估我们模型的性能。

model.score(X_test,y_test)

Checking the accuracy of our model

model.score(X_test,y_test) 所做的是预测输入集“X”的“y”值,并将它们与真实的 y 值进行比较,即“y_test”

0.6546 ≈ 65%精度。这并不坏,考虑到我们已经保持我们的预处理和功能工程非常少。

Scatterplot of “LSTAT” vs “MEDV”

我们可以看到我们的回归线很好地拟合了数据:)

现在我们有了一些关于如何实现线性回归的实践经验。

你们中的一些人可能会对我在这里实现的一些机器学习概念感到困惑,比如 train_test_split,但是我们将在另一篇文章中讨论所有这些概念。

这篇文章只是模型构建的一个精华,还有很多东西在等着我们呢!我将涉及每个主题,一次一个,并附有易于理解的例子。

在那之前,继续练习,一切顺利😊

线性回归:基础

原文:https://towardsdatascience.com/linear-regression-the-basics-4daad1aeb845?source=collection_archive---------19-----------------------

了解线性回归技术的基础

回归技术帮助您测量变量的相关程度。例如,它们允许你说“房子每平方米要多花 6000 美元”(在这种情况下,这些变量是房子的面积和价格)。

线性回归是当关系是线性时我们所做的回归类型。在我们的例子中,情况可能是这样的:额外的平方米总会或多或少地增加房价。现在让我们考虑一下每间浴室的房价:虽然给你的房子增加第二间浴室会增加它的价格,但第 12 间浴室不太可能对一间已经有 11 间浴室的房子有多大影响。

在回归技术中,我们总是有我们的目标数值变量(Y)和我们的解释变量(X1,X2,…).在这种情况下,由于我们试图解释房价,这就是我们的 y。在第一个例子中,我们的 X 是房屋面积,在第二个例子中,它是浴室的数量。我们也可能有多个 X(例如,如果我们取面积、浴室数量和最近一次翻新的年份)。

现在让我们使用 r 进行第一次回归。我们将使用来自美国金县房屋销售数据的公共数据集,此处提供。然后我们可以加载它,看看变量:

**IN:**
path = 'insert you file path here'
data = read.csv(paste(path,'kc_house_data.csv', sep = ""))
colnames(data)**OUT:**[1] "id"            "date"          "price"         "bedrooms"      "bathrooms"     "sqft_living"  [7] "sqft_lot"      "floors"        "waterfront"    "view"          "condition"     "grade"        
[13] "sqft_above"    "sqft_basement" "yr_built"      "yr_renovated"  "zipcode"       "lat"          
[19] "long"          "sqft_living15" "sqft_lot15"

所以这里有价格平方英尺 _ 居住面积(居住面积平方英尺)。让我们来看看这两个变量的共同表现:

**IN:**
attach(data)
plot(sqft_living,price)

这里我们有一个散点图,每个点代表一栋房子,X 轴是它的面积,Y 轴是它的价格。不出所料,看起来房子越大越贵。此外,这种关系看起来或多或少是线性的。我们的第一个线性回归方程如下所示:

Y = a + bX*

其中 Y 是房价( price ), X 是其面积( sqft_living ), a 是基准值,是房子的最低价格,不管它有多小, b 是解释两个变量之间关系的系数(“f 或房子的每平方米,将多花美元

让我们建立第一个线性模型:

**IN:**
model1 = lm(price ~ sqft_living, data = data)
summary(model1)**OUT:**
Call:
lm(formula = price ~ sqft_living, data = data)Residuals:Min       1Q   Median       3Q      Max 
-1476062  -147486   -24043   106182  4362067Coefficients:Estimate Std. Error t value Pr(>|t|)    
(Intercept) -43580.743   4402.690  -9.899   <2e-16 ***
sqft_living    280.624      1.936 144.920   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1Residual standard error: 261500 on 21611 degrees of freedom
Multiple R-squared:  0.4929, Adjusted R-squared:  0.4928 
F-statistic: 2.1e+04 on 1 and 21611 DF,  p-value: < 2.2e-16

lm() 函数允许我们构建模型,而 summary() 函数允许我们查看模型的结果。现在让我们试着解释这些结果:

残差:显示残差的分布,残差是模型估计的价格与实际观察到的价格之间的差异。显然,我们希望我们的估计尽可能接近真实值,这意味着非常小的残差。理想情况下,它们将非常接近零,并且对称分布。

系数:“估计”字段从我们的模型中给出了 ab ,其中“截距”是 a 而“平方英尺生活”是 b (在我们的例子中,每平方英尺的居住面积意味着房价增加了 280 美元)。另一个相关字段是“Pr( > |t|)”,它给出了各自的 p 值。粗略地说,p 值意味着我们对估计的系数有多大的把握。p 值为 5%意味着我们对结果有 95%的信心。所以 p 值越小越好。通常情况下,如果小于 5%或 1%,这是令人满意的。在我们的例子中,p 值比这小得多,所以我们可以认为我们的系数是重要的。

R 平方:它告诉我们目标变量(价格)的变化有多少是由我们的模型解释的,从 0 到 1。显然,越多越好。然而,有一个警告:当我们考虑一个以上的解释变量时,我们应该看一下调整的 r 平方。在我们的例子中,它大约是 0.49,这意味着我们的模型解释了大约一半的房价变化。

让我们看看这个模型产生的线:

这条线显示,对于任何给定的房屋面积,根据我们的模型,它的估计价格。看起来没什么印象吧?现在我们知道如何阅读我们的模型摘要,让我们尝试改进它。我们可以尝试添加更多的变量,比如浴室的数量,例如:

**IN**:
model2 = lm(price ~ sqft_living + bathrooms, data = data)
summary(model2)**OUT**:
Call:
lm(formula = price ~ sqft_living + bathrooms, data = data)Residuals:Min       1Q   Median       3Q      Max 
-1483123  -147387   -24190   105951  4359876Coefficients:Estimate Std. Error t value Pr(>|t|)    
(Intercept) -39456.614   5223.129  -7.554 4.38e-14 ***
sqft_living    283.892      2.951  96.194  < 2e-16 ***
bathrooms    -5164.600   3519.452  -1.467    0.142    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1Residual standard error: 261400 on 21610 degrees of freedom
Multiple R-squared:  0.4929, Adjusted R-squared:  0.4929 
F-statistic: 1.05e+04 on 2 and 21610 DF,  p-value: < 2.2e-16

正如我们所见,调整后的 R 平方几乎保持不变,浴室系数的 p 值太大,这意味着这个变量似乎无法解释房价。然后,让我们尝试第三个模型,去掉浴室,并添加其他可能相关的变量:

**IN**:
model3 = lm(price ~ sqft_living + floors + yr_built, data = data)
summary(model3)**OUT**:
Call:
lm(formula = price ~ sqft_living + floors + yr_built, data = data)Residuals:Min       1Q   Median       3Q      Max 
-1669759  -134816   -16331   102089  4092350Coefficients:Estimate Std. Error t value Pr(>|t|)    
(Intercept)  5.595e+06  1.304e+05   42.92   <2e-16 ***
sqft_living  2.948e+02  2.018e+00  146.10   <2e-16 ***
floors       7.517e+04  3.731e+03   20.15   <2e-16 ***
yr_built    -2.933e+03  6.767e+01  -43.35   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1Residual standard error: 250800 on 21609 degrees of freedom
Multiple R-squared:  0.5335, Adjusted R-squared:  0.5334 
F-statistic:  8237 on 3 and 21609 DF,  p-value: < 2.2e-16

这一次,我们将调整后的 R 平方提高到 0.53,所有系数都是相关的。请注意, sqft_living 的系数已经改变:现在大约是 294。yr _ build 的系数也很有趣,因为它是负的。这意味着你建造的的价值越大,也就是说,房子越新,花费就越少。换句话说,旧房子往往更贵。

好吧,那下一步是什么?我们如何使用这个模型?嗯,我们可以用它来估计一栋新房子的销售价格,这不在我们的数据库中:

**IN**:
new_house = data.frame(sqft_living = 2080, floors = 1, yr_built = 1997)
predict(model3,newdata = new_house)**OUT**:
1 
426715.9

因此,对于一栋建于 1997 年的房子,有 2080 平方英尺的居住空间和一层楼,我们预计它的价格约为 426716 美元。

因此,我们已经了解了如何创建线性模型,如何评估和改进它,以及如何使用它进行预测。我们的模型仍然有许多改进的机会,我们将在下一个线性回归教程中解决,例如修复异方差(我发誓这仍然是英语)和多重共线性,但现在我们对这些模型如何工作以及如何使用它们有了基本的了解。

你可以在这里访问完整的 R 脚本。

线性回归:最后的前沿

原文:https://towardsdatascience.com/linear-regression-the-final-frontier-5a4dbda23317?source=collection_archive---------31-----------------------

先进的技术,让你的线性回归游戏更上一层楼

Photo by Jeremy Thomas on Unsplash

快速介绍

本文旨在介绍一些更高级的线性回归技术,它们可以极大地改善您的模型结果。如果你还没有掌握线性回归的基础知识,我建议另外两篇文章可以帮助你:第一篇介绍了一些理解线性回归的基本概念,而第二篇解释了如何发现并纠正线性回归中出现的一些常见问题。

多项式回归

顾名思义,线性回归意味着两个变量之间的线性关系,形式为 y = ax + b。但是,通常情况下,这两个变量之间的关系不是线性的,而是遵循某个其他函数,该函数采用 x 的平方(或某个其他幂)值。在这种情况下,一个简单的解决方案是向解释变量添加一个要检查的所有变换的列表(x 的平方,x 的三次方,等等)。这决定了你的多项式的次数(例如,如果你到 x 的五次方,你有一个五次多项式)。一旦你有了解释变量的完整列表,你就可以像往常一样进行线性回归了。这是一个简单的转换,但它可以产生一些非常好的结果。

固定过度配合

里脊回归

岭回归是一种特殊类型的线性回归,它试图通过对一些参数应用权重来减少过度拟合,从而减少实际上可能不重要的参数的影响。

为了在 R 中做到这一点,我们使用函数 glmnet(),并指定参数 alpha = 0,使其成为岭回归。我们还必须指定正则化参数 lambda,它将决定我们的回归对其给出的权重有多“严格”。使用交叉验证可以找到最佳值:

**IN:** library(glmnet)
library(tidyverse)y = data$price
x = data %>% select(sqft_living, floors, yr_built, yr_built_2) %>% data.matrix()model6 = glmnet(x, y, alpha = 0)lambdas = 10^seq(10, -10, by = -.2)
cv_fit = cv.glmnet(x, y, alpha = 0, lambda = lambdas)
plot(cv_fit)

This plot indicates us the lambda that minimises the error, but we can also fetch it directly.

**IN:**
opt_lambda = cv_fit$lambda.min
opt_lambda**OUT:**
6.309573e-07**IN:** model6 = cv_fit$glmnet.fitplot(model6, xvar = "lambda")
legend("left", lwd = 1, col = 1:6, legend = colnames(x), cex = .5)

This plot shows how the coefficients weights evolve for each variable, according to the value of lambda.

套索回归

套索回归的工作方式与岭回归类似,只是它不是对不重要的参数赋予小的权重,而是赋予它们 0 的权重,这意味着它将它们从回归中剔除。

在 R 中,我们还将使用 glmnet()函数,但这次将 alpha 设置为 1,以使其成为套索回归:

**IN:**
cv_fit = cv.glmnet(x, y, alpha = 1, lambda = lambdas)
opt_lambda = cv_fit$lambda.minmodel7 = cv_fit$glmnet.fit
plot(model7, xvar = "lambda")
legend("left", lwd = 1, col = 1:6, legend = colnames(x), cex = .5)

This is basically the same as the previous plot, but notice how the convergence of the weights to zero is more abrupt.

弹性网

弹性网络正则化本质上是岭回归和套索回归的两个正则化参数的线性组合。在实践中,这意味着将 alpha 值设置在 0 和 1 之间,这将把一些系数设置为 0,就像在 LASSO 回归中一样,并把一些系数设置为权重,就像在 Ridge 回归中一样。

**IN:**
library(caret)
set.seed(111)
model8 = train(price ~., data = data, method = "glmnet",trControl = trainControl("cv", number = 10),tuneLength = 10
)model8$bestTune**OUT:**alpha   lambda
94     1 1468.049

逐步回归

在前面的方法中,我们为每个参数分配权重以减少过度拟合。在逐步回归中,我们尝试参数的多种组合,并排除那些不重要的参数。一种方法是从所有变量开始,然后一个一个地去掉不太重要的变量。另一种方法是从一个变量开始,然后一个接一个地添加重要的变量。最后,我们可以将两种方法结合起来。这种选择可以通过在 stepAIC 函数中设置参数“方向”来实现,该参数可以取以下值:“向后“、“向前”、“都”。变量的重要性可以用许多不同的方法来衡量,所以这里我们将研究其中的一种方法,它是由 stepAIC()函数计算的,该函数研究 Akaike 信息标准。

**IN:**
library(MASS)
model8 = lm(price~., data = data)
model8 = stepAIC(model8, direction = "both", trace = FALSE)
summary(model8)**OUT:**
Call:
lm(formula = price ~ id + bedrooms + bathrooms + sqft_living + sqft_lot + floors + waterfront + view + condition + grade + sqft_above + yr_built + yr_renovated + zipcode + lat + long + sqft_living15 + sqft_lot15 + yr_built_2, data = data)Residuals:Min       1Q   Median       3Q      Max 
-1317688   -99197    -9464    76111  4340354Coefficients:Estimate Std. Error t value Pr(>|t|)    
(Intercept)    9.177e+07  7.674e+06  11.958  < 2e-16 ***
id            -1.485e-06  4.812e-07  -3.086 0.002032 ** 
bedrooms      -3.298e+04  1.900e+03 -17.358  < 2e-16 ***
bathrooms      3.554e+04  3.276e+03  10.846  < 2e-16 ***
sqft_living    1.510e+02  4.371e+00  34.537  < 2e-16 ***
sqft_lot       1.244e-01  4.783e-02   2.601 0.009307 ** 
floors        -1.376e+04  3.974e+03  -3.463 0.000536 ***
waterfront     5.860e+05  1.730e+04  33.868  < 2e-16 ***
view           5.474e+04  2.138e+03  25.599  < 2e-16 ***
condition      3.053e+04  2.371e+03  12.876  < 2e-16 ***
grade          9.579e+04  2.146e+03  44.640  < 2e-16 ***
sqft_above     3.033e+01  4.346e+00   6.979 3.05e-12 ***
yr_built      -8.830e+04  7.167e+03 -12.320  < 2e-16 ***
yr_renovated   2.263e+01  3.652e+00   6.196 5.89e-10 ***
zipcode       -6.053e+02  3.293e+01 -18.382  < 2e-16 ***
lat            6.099e+05  1.072e+04  56.908  < 2e-16 ***
long          -2.203e+05  1.312e+04 -16.785  < 2e-16 ***
sqft_living15  2.175e+01  3.436e+00   6.330 2.51e-10 ***
sqft_lot15    -3.518e-01  7.330e-02  -4.800 1.60e-06 ***
yr_built_2     2.189e+01  1.831e+00  11.955  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1Residual standard error: 200600 on 21593 degrees of freedom
Multiple R-squared:  0.7018, Adjusted R-squared:  0.7016 
F-statistic:  2675 on 19 and 21593 DF,  p-value: < 2.2e-16

我们只剩下一些初始变量,它们都是有意义的。

你可以在这里访问完整的脚本。

使用 TensorFlow 进行简单的线性回归

原文:https://towardsdatascience.com/linear-regression-using-tensorflow-fd732e1b690d?source=collection_archive---------22-----------------------

目标和重要概念

在本文结束时,您应该能够成功理解在 TensorFlow 中执行简单线性回归的过程,以获得并绘制由线性关系描述的某些数据集的最佳拟合线。此外,获得预测的解释将在最后给出,以阐明最佳拟合线的使用。

线性回归

线性回归是通过将线性方程拟合到数据点来描述两个变量之间关系的过程。这条线通常被称为“最佳拟合线”,是通过最小二乘回归方法获得的。

https://www.google.com/search?q=linear+regression+in+tensorflow&source=lnms&tbm=isch&sa=X&ved=0ahUKEwjx1IKJhNPiAhXSs1kKHQ6RBNMQ_AUIESgC&biw=1680&bih=939&dpr=2#imgrc=_xHshSPnhNG1oM:

最小二乘法

最小二乘回归线或方法是最小化回归线和数据集中每个数据点之间垂直距离的线。这条线最小化了数据中的方差,也就是所谓的损失。在 TensorFlow 甚至其他环境中,最小二乘回归线是通过两个过程确定的:代价函数和梯度下降法。

https://www.google.com/search?q=least+squares+regression&source=lnms&tbm=isch&sa=X&ved=0ahUKEwjZrNXGhNPiAhUOZN8KHc9FA_wQ_AUIESgC&biw=1680&bih=890&dpr=2#imgdii=Jr3voN86OP8v2M:&imgrc=y54-2EX4O_2KQM:

成本函数和梯度下降

TensorFlow 中线性回归的工作方式是选择一个占位符斜率和 y 截距来启动该过程。在迭代 n 的循环中,计算成本函数或误差平方和,如果没有最小化,则调整最佳拟合线的斜率和 y 截距,并再次计算成本函数,直到其最小。梯度下降或梯度下降算法是计算和调整成本函数、斜率和 y 截距值的整个过程。幸运的是,TensorFlow 有预先制作的函数来运行梯度下降过程,并在每次迭代时计算成本函数。

https://www.google.com/search?q=linreg1d&tbm=isch&source=iu&ictx=1&fir=zIsDdzISOI_EYM%253A%252Cm3PAo_HTKbKCsM%252C_&vet=1&usg=AI4_-kSxBE2bzXqM-Fx0jSGtMmW8VmRzZw&sa=X&ved=2ahUKEwic7J_UhdPiAhURWN8KHQuDDH8Q9QEwBHoECAMQBA#imgrc=zIsDdzISOI_EYM:

进入线性回归过程

数据

用于通过 TensorFlow 进行线性回归的数据集是研究生入学数据。该数据集有许多重要的参数,这些参数在申请硕士课程时非常重要。这些参数是:

  1. GRE 成绩(满分 340 分)
  2. 托福成绩(满分 120 分)
  3. 大学评级(满分 5 分)
  4. 目的陈述和推荐信强度(满分 5 分)
  5. 本科 GPA(满分 10 分)
  6. 研究经验(0 或 1)
  7. 录取机会(范围从 0 到 1)

就本文的目的而言,被认为可以得出线性回归线的两个因素是 GRE 分数和录取机会。

数据探索

在选择 GRE 分数作为线性回归的变量之前,我分析了数据集中提供的所有要素之间的关系和相关性。以下是数据集中所有要素的配对图:

Figure 1: The relationships between GRE_Score, TOEFL_Score, CGPA, and Chance_Of_Admit are all linear

为了进一步挖掘 GRE_Score、TOEFL_Score 和 Chance _ Of _ admission 之间的关系,我们使用了一个三维散点图来对此进行可视化:

Figure 2: This scatterplot shows that an increase in GRE_Scores and TOEFL_Scores lead to relatively linear increases in Chance_Of_Admit

最后,为了巩固我使用 GRE_Scores 作为线性回归独立变量的选择,我们创建了一个关联热图来可视化关联:

Figure 3: between GRE_Score and TOEFL_Score, GRE_Score has a higher correlation to Chance_Of_Admit

使用张量流的线性回归

线性回归的第一步是将数据集上传到文件中。其代码如下所示:

并非数据集中的所有列都具有相同的数据类型。GRE_Score、TOEFL_Score 和 University_Rating 都是字符串数据类型。尽管 TOEFL_Score 和 University_Rating 不会用于线性回归,但保持要素的数据类型不变是一种很好的做法。下面显示了数据类型转换代码:

最后,我们可以开始线性回归过程的核心。首先,自变量和因变量的列需要放入一个列表中。在这个例子中,我们将 GRE_Score 转换为 x 列表,将 Chance_Of_Admit 转换为 y 列表。这方面的代码如下所示:

接下来的几个步骤都被打包成一个函数,我称之为 linearregression()。在这个函数中,我们首先定义将被输入到模型中的两组数据。这些集合最初用随机的浮点数填充,但是当输入到模型中时,它们被上面声明的 x 和 y 数据占据。接下来,我们声明两个变量 W 和 b,并给它们分配随机数。w 用作最佳拟合线的斜率,而 b 用作最佳拟合线的 y 截距。最后,y_pred 和 loss 也在这个函数中定义。y_pred 的值是通过将 W 乘以 x1,然后加上 b 得到的,就像数学课上学过的等式一样。这个函数的代码如下所示。

最后的步骤包括在设计的 run()方法中运行梯度下降函数。GradientDescentOptimizer()函数用于创建步长为 0.000005 的优化器对象。然后,在优化器对象上使用 minimize()函数来返回成本函数的最小值。最后,将数据输入模型,并在散点图上绘制最佳拟合线。run()方法的代码如下所示:

结果

线性回归函数的最终结果给了我们一条最佳拟合线,它与 Seaborn 上的 regplot 生成的线极其相似。两者如下所示:

Figure 4: Loss value for this line of best fit is 0.0068259086

Figure 5: This is the regplot that was generated with the Seaborn package in python

结论

这篇文章是关于在 TensorFlow 中进行线性回归的。执行此操作的主要步骤是使用 TensorFlow 提供的梯度下降函数建立一个优化器,然后使用 minimize 函数确保返回最低成本函数值。要完全理解线性回归,必须了解梯度下降过程和成本函数。梯度下降是通过一个步长值调整函数的斜率和 y 截距,直到找到最小成本函数的渐进过程。成本函数本质上是绘制的每条最佳拟合线的最小平方和。有了这两个工具和上面的文章,你现在应该能够制作自己的线性回归函数了!

Numpy 中从零开始的梯度下降线性回归

原文:https://towardsdatascience.com/linear-regression-with-gradient-descent-from-scratch-in-numpy-d894a800a2ca?source=collection_archive---------15-----------------------

Image by Elias Sch. from Pixabay

几天前,我写了一篇介绍梯度下降的文章,介绍了一些基本的数学和逻辑知识,在文章的最后,我要求你尝试用一个简单的线性回归来实现它。

[## 梯度下降在 5 分钟内揭开神秘面纱

学习梯度下降是如何工作的,只需要一点点数学知识和很多常识。

towardsdatascience.com](/gradient-descent-demystified-in-5-minutes-f02966704e35)

我承认——这个要求有点过分,尤其是如果那篇文章是你第一次接触梯度下降的话。这就是为什么今天我想自己从头开始实现,先借助一些数学,再借助 Python。读完这篇文章后,你会完全理解梯度下降,并能够用它来解决任何线性回归问题。

手动梯度下降

我强烈建议你阅读上面链接的文章。它将为这个主题奠定基础,另外一些数学知识已经在这里讨论过了。

首先,我将定义我的数据集—只有三个呈线性关系的点。我选择这么少的点只是因为数学将会更短——不用说,对于更长的数据集,数学不会更复杂,它只会更长,我不想犯一些愚蠢的算术错误。

然后,我将系数β0β1设置为某个常数,并将成本函数定义为残差平方和(SSR/SSE) 。最后,我将把学习率设置为一个小值,比如 0.001:

通过使用线方程,很容易计算模型的预测值:

如前所述,成本函数将是残差平方和:

如果你懂一些微积分,你可以计算出成本函数相对于 beta 0beta 1偏导数。如果没有,就拿着这些方程,试着在网上搜索“多元微分”和“链式法则”:

接下来要做的是计算β0 和β1 的成本。这归结为基本的算术,很容易手工完成。

beta 0 的成本:

beta 1 的成本:

一旦获得这两个数字,就可以通过将计算出的成本乘以学习率来计算这两个系数的步长:

最后一步是通过从旧值中减去各自的步长来计算新的β0β1:

现在你可以使用这些新的系数值,重复整个过程大约 10000 次。出于明显的原因,你不应该手动操作——然而,知道算法是如何工作的是很好的。

差不多就是这样,现在你可以简单地重复同样的逻辑,不断更新你的系数。让我们看看如何在 Python 中实现梯度下降。

Python 中的梯度下降

从实现开始,让我们首先定义成本函数,并使用Sympy获取导数:

不知道怎么用 Sympy?查看这篇文章:

*** [## 在 Python 中取导数

学习如何处理机器学习中的微积分部分

towardsdatascience.com](/taking-derivatives-in-python-d6229ba72c64)

您可以看到计算出的导数与之前手动计算出的是一样的——Sympy 只做了乘法来去掉括号( ish )。

现在您可以将 xy 都定义为变量并绘制它们:

你拥有了所需的一切——这意味着接下来是梯度下降。因为我已经在数学部分解释了发生了什么,所以我不会在这里做太多的细节,我将只概述这个过程:

  1. β0β1系数初始化为某个值
  2. 初始化学习率和所需的周期数
  3. 制作一个循环的,它将运行 n 次,其中 n 是历元数
  4. 初始化保存当前时期误差的变量
  5. 使用直线方程进行预测
  6. 将平方差追加到误差数组
  7. 计算数据集中当前行的两个系数的偏导数
  8. 增加系数的成本
  9. 重新计算系数值

这听起来像是很多步骤,确实如此,但是如果你已经阅读了我以前的文章,并遵循了数学,你可以看到这里没有发生任何复杂的事情。下面是 Python 实现的代码:

Gradient Descent — https://gist.github.com/dradecic/cb1a3b0a68f8b8e0307dba754de08113

一旦代码单元执行完毕,你就可以检查你的系数的最终值,并用它们来做预测:

现在使用 y_preds 你可以添加一条回归线到先前绘制的图中:

还记得你是如何记录纪元误差的吗?

看起来 10000 个时期有点太多了,但是尽管如此,在大约 1000 个时期之后,误差被最小化,并且在剩余的运行中保持不变。

我在梯度下降的代码单元中添加了一串打印语句,所以每次迭代都被打印出来(我只运行了 1 个时期来验证数学工作),下面是我得到的结果:

这只是一次迭代,但它是数学如前所述起作用的决定性证据。你现在可以在更大的数据集上使用相同的逻辑,只是为了好玩。***

最后的话

梯度下降一开始可能看起来像一个令人生畏的算法,但它背后的逻辑相当简单,数学也没有你以前可能认为的那么复杂。

我希望你现在能从理论、数学和代码上看到清晰的画面。我如何实现梯度下降只是一个想法,肯定还有改进的空间-您可以将系数值保存在列表中-如果您的数据集中有多个要素,这将非常方便。现在,您已经拥有了自己进一步探索所需的所有工具。

请随意分享您的想法,如果有任何不清楚的地方,请随时联系我。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

*** [## 通过我的推荐链接加入 Medium-Dario rade ci

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@radecicdario/membership)***

PyTorch 线性回归

原文:https://towardsdatascience.com/linear-regression-with-pytorch-eb6dedead817?source=collection_archive---------2-----------------------

线性回归是一种方法,它试图通过最小化距离来找到因变量和自变量之间的线性关系,如下所示。

Taken from https://www.youtube.com/watch?v=zPG4NjIkCjc

在这篇文章中,我将展示如何使用 PyTorch 实现一个简单的线性回归模型

让我们考虑一个非常基本的线性方程,即 y=2x+1 。这里,‘x’是自变量,y 是因变量。我们将使用此等式创建一个虚拟数据集,用于训练此线性回归模型。下面是创建数据集的代码。

import numpy as np*# create dummy data for training* x_values = [i **for** i **in** range(11)]
x_train = np.array(x_values, dtype=np.float32)
x_train = x_train.reshape(-1, 1)y_values = [2*i + 1 **for** i **in** x_values]
y_train = np.array(y_values, dtype=np.float32)
y_train = y_train.reshape(-1, 1)

一旦我们创建了数据集,我们就可以开始为我们的模型编写代码。首先要定义模型架构。我们使用下面这段代码来实现。

import torch
from torch.autograd import Variable**class** linearRegression(torch.nn.Module):**def** __init__(self, inputSize, outputSize):super(linearRegression, self).__init__()self.linear = torch.nn.Linear(inputSize, outputSize)**def** forward(self, x):out = self.linear(x)**return** out

我们为线性回归定义了一个类,它继承了 torch.nn.Module ,后者是包含所有必需函数的基本神经网络模块。我们的线性回归模型只包含一个简单的线性函数。

接下来,我们使用下面的代码实例化这个模型。

inputDim = 1        *# takes variable 'x'* outputDim = 1       *# takes variable 'y'* learningRate = 0.01 
epochs = 100model = linearRegression(inputDim, outputDim)
*##### For GPU #######* **if** torch.cuda.is_available():model.cuda()

之后,我们初始化损失(均方误差)和优化(随机梯度下降)函数,我们将在该模型的训练中使用这些函数。

criterion = torch.nn.MSELoss() 
optimizer = torch.optim.SGD(model.parameters(), lr=learningRate)

完成所有初始化后,我们现在可以开始训练我们的模型。下面是训练模型的代码。

**for** epoch **in** range(epochs):*# Converting inputs and labels to Variable* **if** torch.cuda.is_available():inputs = Variable(torch.from_numpy(x_train).cuda())labels = Variable(torch.from_numpy(y_train).cuda())**else**:inputs = Variable(torch.from_numpy(x_train))labels = Variable(torch.from_numpy(y_train))*# Clear gradient buffers because we don't want any gradient from previous epoch to carry forward, dont want to cummulate gradients* optimizer.zero_grad()*# get output from the model, given the inputs* outputs = model(inputs)*# get loss for the predicted output* loss = criterion(outputs, labels)print(loss)*# get gradients w.r.t to parameters* loss.backward()*# update parameters* optimizer.step()print(**'epoch {}, loss {}'**.format(epoch, loss.item()))

现在我们的线性回归模型已经训练好了,让我们来测试一下。由于这是一个非常简单的模型,我们将在现有的数据集上进行测试,并绘制原始输出与预测输出的对比图。

**with** torch.no_grad(): *# we don't need gradients in the testing phase* **if** torch.cuda.is_available():predicted = model(Variable(torch.from_numpy(x_train).cuda())).cpu().data.numpy()**else**:predicted = model(Variable(torch.from_numpy(x_train))).data.numpy()print(predicted)plt.clf()
plt.plot(x_train, y_train, **'go'**, label=**'True data'**, alpha=0.5)
plt.plot(x_train, predicted, **'--'**, label=**'Predictions'**, alpha=0.5)
plt.legend(loc=**'best'**)
plt.show()

这绘制了下图。

看起来我们的模型已经正确地计算出了自变量和因变量之间的线性关系。

如果你已经理解了这一点,你应该试着为一个稍微复杂一点的有多个独立变量的线性方程训练一个线性回归模型。

利用 TensorFlow.js 进行线性回归的房价预测

原文:https://towardsdatascience.com/linear-regression-with-tensorflow-js-e7b39713572?source=collection_archive---------6-----------------------

使用 TensorFlow.js 构建线性回归模型,并用于预测房价

Photo by Geran de Klerk

TL;DR 在 TensorFlow.js 建立线性回归模型,预测房价。了解如何处理分类数据和进行要素缩放。

又下雨了。自从你最后一次见到太阳已经三个星期了。你已经厌倦了这种寒冷、不愉快的孤独和忧郁的感觉。

你脑子里的声音越来越大。

——“动”。

好了,你准备好了。去哪里?你记得你几乎破产了。

你的一个朋友告诉了你爱荷华州的埃姆斯这个地方,它深深地印在了你的脑海里。快速搜索后,你发现一年中天气宜人,也有一些雨水,但不多。兴奋!

幸运的是,你知道 Kaggle 上的这个数据集,它可能会帮助你找出你梦想中的房子可能要花多少钱。我们开始吧!

在浏览器中运行本教程的完整源代码:

房价数据

我们的数据来自 Kaggle 的房价:高级回归技术挑战。

有 79 个解释变量描述了(几乎)爱荷华州埃姆斯住宅的每个方面,这个比赛挑战你预测每个家庭的最终价格。

以下是我们将在模型中使用的数据子集:

  • OverallQual -对房屋的整体材料和装饰进行评级(0 - 10)
  • GrLivArea -地上(地面)以上居住面积平方英尺
  • GarageCars -车库容量大小
  • TotalBsmtSF -地下室总面积平方英尺
  • FullBath -地面以上的全浴室
  • YearBuilt -原始施工日期
  • SalePrice -以美元为单位的房产销售价格(我们正在尝试预测)

让我们使用 Papa Parse 来加载训练数据:

探测

让我们更好地理解我们的数据。首先—每栋房屋的质量得分:

大多数房子质量一般,但“好”的比“坏”的多。

让我们看看它们有多大(她是这么说的):

大多数房子的价格在 1,000-2,000 英镑之间,我们也有一些更大的。

让我们看看它们是哪一年建造的:

尽管有很多房子是最近建造的,但我们的分布范围要广得多。

年份和价格有多大关系?

似乎新房子更贵,没有人喜欢旧的和造得好的房子?

哦,好吧,但是高质量应该等于高价格,对吗?

一般可以,但是看质量 10。其中一些相对便宜。知道为什么会这样吗?

房子越大就等于价格越高吗?

似乎是这样,我们可以从居住区开始我们的价格预测模型!

线性回归

线性回归模型假设因变量Y和一个或多个解释变量X之间存在线性关系(可以用直线建模)。

在我们的例子中,我们将使用像living area (X)这样的特征来预测房子的sale price (Y)。

简单线性回归

简单线性回归是一种只有一个独立变量X的模型。它由下式给出:

其中 a 和 b 是在我们的模型训练期间学习的参数。 X 是我们将要用来训练我们的模型的数据, b 控制斜率, ay 轴的交点。

多元线性回归

多元线性回归模型是简单线性回归模型的自然延伸。它由下式给出:

其中,x1,x2,…,xn 是数据集的特征,w1,w2,…,wn 是学习参数。

损失函数

我们将使用均方根误差来衡量我们的预测与实际房价的差距。它由下式给出:

其中假设/预测 hw 由下式给出:

数据预处理

目前,我们的数据存放在一个 JS 对象数组中。我们需要把它变成张量,并用它来训练我们的模型。下面是代码:

我们将特征存储在X中,将标签存储在y中。然后,我们将数据转换为张量,并将其分成训练和测试数据集。

分类特征

我们数据集中的一些要素是分类的/可枚举的。例如,GarageCars可以在 0-5 的范围内。

在我们的数据集中用整数表示类别可能会引入隐含的排序依赖。不存在分类变量的事物。

我们将使用 TensorFlow 的一键编码为每个值创建一个整数向量,以打破排序。首先,让我们指定每个类别有多少不同的值:

我们将使用 tf.oneHot() 将单个值转换成一个 Hot 表示:

注意,createDataSets()函数接受一个名为categoricalFeatures的参数,它应该是一个集合。我们将使用它来检查我们是否应该将该特征作为分类来处理。

特征缩放

特征缩放用于将特征值转换到一个(相似的)范围内。特征缩放将帮助我们的模型学习得更快,因为我们使用梯度下降来训练它。

让我们使用一种最简单的特征缩放方法—最小-最大归一化:

此方法在[0,1]的范围内重新调整值的范围。

预测房价

既然我们知道了线性回归模型,我们就可以根据现有的数据来预测房价。让我们从简单的开始:

构建简单的线性回归模型

我们将把培训过程封装在一个函数中,以便在未来的模型中重用:

trainLinearModel接受我们模型的特性和标签。让我们使用 TensorFlow 定义一个线性回归模型:

由于 TensorFlow.js 不提供 RMSE 损失函数,我们将使用 MSE,并在稍后计算它的平方根。我们还将跟踪预测价格和实际价格之间的平均绝对误差(MAE ):

以下是培训过程:

我们针对 100 个时期进行训练,预先对数据进行洗牌,并使用其中的 10% 进行验证。RMSE 和梅在每一个时代之后都是可视化的。

培养

我们的简单线性回归模型使用了 GrLivArea 特性:

我们没有明确的特征,所以我们让这个集合为空。让我们来看看表演:

建立多元线性回归模型

我们还有很多没用过的数据。让我们看看这是否有助于改善预测:

我们使用数据集中的所有要素,并传递一组分类要素。我们做得更好吗?

总的来说,这两种型号的性能大致相同。这一次,增加模型的复杂性并没有给我们带来更好的准确性。

估价

评估我们模型的另一种方法是对照测试数据检查它们的预测。让我们从简单的线性回归开始:

添加更多的数据是如何改善预测的?

但事实并非如此。同样,用更多数据训练更复杂的模型并不能提供更好的性能。

结论

你做到了!您构建了两个线性回归模型,根据一组特征预测房价。你也做到了:

-特征缩放以加快模型训练

-将分类变量转换为一键表示

-实施 RMSE(基于 MSE)进行精度评估

在浏览器中运行本教程的完整源代码:

是时候学习神经网络了吗?

参考

处理机器学习模型中的分类数据

关于特征缩放和归一化

RMSE:均方根误差

最初发表于https://www.curiousily.com

建立机器学习模型(特别是深度神经网络),可以轻松地与现有或新的 web 应用程序集成。想想您的 ReactJs、Vue 或 Angular 应用程序通过机器学习模型的强大功能得到了增强:

[## JavaScript 黑客的深度学习

建立机器学习模型(特别是深度神经网络),您可以轻松地与现有或新的网络集成…

leanpub.com](https://leanpub.com/deep-learning-for-javascript-hackers)

简单线性回归与多项式回归

原文:https://towardsdatascience.com/linear-vs-polynomial-regression-walk-through-83ca4f2363a3?source=collection_archive---------5-----------------------

蓝鳃鱼:根据年龄预测长度

鱼越老越大。鱼的长度(厘米)与年龄(年)有多大的预测性?这种关系是否最适合简单的线性回归?

Source of image: Kelly Sikkema

目录

  1. 获取数据、可视化和初步分析
  2. 线性回归分析
  3. 二次和高次多项式回归分析
  4. 将数据分为训练和测试
  5. 每种回归类型的测试模型(线性、二次、六次)

第一部分:获取数据,可视化,和初步分析

首先,让我们引入数据和几个重要模块:

%matplotlib inline
import numpy as np
import pandas as pd
from sklearn.metrics import r2_score
import matplotlib.pyplot as plt
from scipy import stats
import seaborn as snsdata = pd.read_excel(r”C:\Users\...\fish polynomial.xlsx”)
df = data[[‘age’,’length’]]
df

数据集中有 77 个实例。下面是头部的原始数据:

现在让我们来想象散点图。我们将尝试根据年龄来预测长度,因此坐标轴位于各自的位置:

x = df['age']
y = df['length']
plt.xlabel('Age (yr)')
plt.ylabel('Length (cm)')
plt.title('Scatterplot of Length vs Age')
plt.scatter(x,y)
plt.show()

这似乎是一种趋势。随着鱼年龄的增长,似乎和长度有关系。为了获得更深入的视角,让我们将每个轴分解成它自己的单变量分布直方图。

Y——鱼的长度:

stdy = y.std()
meany = y.mean()
plt.hist(y)
plt.xlabel('Length (cm)')
plt.ylabel('Quantity')
plt.title('Length Distribution Histogram')
print ("The std of y is: " + str(stdy) + " The mean of y is: " + str(meany))

X——鱼的年龄:

stdx = x.std()
meanx = x.mean()
plt.hist(x)
plt.xlabel('Age (yr)')
plt.ylabel('Quantity')
plt.title('Age Distribution Histogram')
print ("The std of x is: " + str(stdx) + " The mean of x is: " + str(meanx))

我们可以看到,平均长度为 143.6 厘米,平均年龄为 3.6 岁。年龄的标准偏差成比例地高于长度的标准偏差,这意味着年龄分布的总体分布更大。这是尽管长度分布具有更高的范围。

第二部分:简单线性回归

简单线性回归是预测模型的基本类型之一。简而言之,它通过对数据拟合线性方程来衡量两个变量之间的关系。一个变量被认为是解释性的(年龄),另一个被认为是依赖性的(长度)。回归模型最小化直线和每个数据点之间的距离,以找到最佳拟合。

下面,我们使用 scipy stats 模块来计算我们产品线的关键指标。下面输出的分别是截距和斜率。

slope, intercept, r_value, p_value, std_err = stats.linregress(x,y)
intercept,slope

现在,我们将通过线性方程运行 x 的每个值,在原始散点图上绘制这条线: y = b0 + b1x

sns.set(color_codes=True)def linefitline(b):return intercept + slope * bline = linefitline(x)
plt.scatter(x,y)
plt.xlabel('Age (yr)')
plt.ylabel('Length (cm)')
plt.title('Scatterplot of Length vs Age - Linear Regression')
plt.plot(x,line, c = 'g')
plt.show()

r2_lin = r_value * r_valueprint('The rsquared value is: ' + str(r2_lin))

这条回归线的平方值显示年龄解释了 73%的长度变化。R-squared 计算回归线与其拟合的数据的相似程度。我写了另一篇关于 rsquared 的文章,你可以在这里参考。

其他可以解释剩余的 27%长度差异的独立变量可能是食物可用性、水质、阳光、鱼类遗传等。如果我们有所有这些属性的数据,我们可以运行多元回归,并有一个更好的模型。但是,唉,我们生活在一个数据有限的世界。

直观上,我们的简单线性模型并不经过 y 点的每个簇的中间点。对于第 1 年、第 2 年、第 5 年和第 6 年,它都高于该组的中间值。这很有可能是因为大多数样本是 3 岁和 4 岁的孩子,正如我们前面看到的。这将向上移动线条。

似乎最佳曲线需要弯曲以更准确地匹配数据。这就是多项式回归的用武之地。

第三部分:二次和高次多项式回归分析

简单来说,多项式回归模型可以弯曲。它们可以构造到 n 次,以最小化平方误差,最大化 rsquared。取决于 n 次,最佳拟合的线可以有更多或更少的曲线。指数越高,曲线越多。

下面我们有一些代码来创建新的线,并在我们的散点图上绘制它。这条线是一个二次函数,因为它只有二次幂。二次线只能弯曲一次。正如我们在下图中看到的,新的多项式模型更准确地匹配了数据。

x = df['age']
y = df['length']
plt.xlabel('Age (yr)')
plt.ylabel('Length (cm)')
plt.title('Scatterplot of Length vs Age')
p = np.poly1d(np.polyfit(x,y,2))
xp = np.linspace(1,6,100)
plt.plot(xp,p(xp),c = 'r')
plt.scatter(x,y)
plt.show()

r2 = r2_score(y, p(x))print('The rsquared value is: ' + str(r2))

与我们在简单线性模型中看到的 0.73 值相比,rsquared 值为 0.80。这意味着在这个新模型中,80%的长度是由它们的年龄来解释的。

我们现在可以尝试改变模型的第 n 个值,看看我们是否能找到一个更好的拟合线。然而,我们必须记住,我们走得越高,我们面临的风险就越大。

下面是一个提升到6 次的多项式的例子:

x = df['age']
y = df['length']
plt.xlabel('Age (yr)')
plt.ylabel('Length (cm)')
plt.title('Scatterplot of Length vs Age')
p = np.poly1d(np.polyfit(x,y,6))
xp = np.linspace(1,6,100)
plt.plot(xp,p(xp),c = 'b')
plt.scatter(x,y)
plt.show()

它对异常值的迎合有点过于极端,而且与数据过于接近。这个模型的平方值是 0.804,比二次模型高不了多少。

对于这个数据集,大多数人会同意二次函数最匹配。

第 4 部分:将数据分割成训练和测试

我们如何知道二次多项式回归直线可能是这个数据集的最佳拟合?这就是测试我们的数据的概念的来源!

首先,让我们打乱数据集。然后我们需要把它分成训练和测试部分。训练数据用于创建我们的模型;测试数据用于查看模型的匹配程度。有一个经验法则来划分 70%的培训和 30%的测试。因为这是一个相对较小的鱼样本量(n = 78),所以我决定在测试方面多做一点。我做了 50 次作为训练,最后 28 次作为测试。那是 65/35 的分成。

shuffled = df.sample(frac=1).reset_index(drop=True)
shuffx = shuffled['age']
shuffy = shuffled['length']
trainX = shuffx[:50]
testX = shuffx[50:]
trainY = shuffy[:50]
testY = shuffy[50:]
plt.scatter(trainX, trainY)
plt.xlabel('Age (yr)')
plt.ylabel('Length (cm)')
plt.title('Testing Data - Length vs Age')
axes = plt.axes()
axes.set_xlim([1,6])
axes.set_ylim([50, 200])
plt.show()
plt.scatter(testX, testY)
plt.xlabel('Age (yr)')
plt.ylabel('Length (cm)')
plt.title('Testing Data - Length vs Age')
axes = plt.axes()
axes.set_xlim([1,6])
axes.set_ylim([50, 200])
plt.show()

与测试相比,训练图中有更多的点,这是由于我们的 65/35 分割:

第 5 部分:每个回归类型的测试模型

线性模型测试:

现在,我们将根据训练数据创建一个线性模型:

p1 = np.poly1d(np.polyfit(trainx, trainy, 1))
xp = np.linspace(0, 6, 100)
axes = plt.axes()
axes.set_xlim([1,6])
axes.set_ylim([50, 200])
plt.scatter(trainx, trainy)
plt.xlabel('Age (yr)')
plt.ylabel('Length (cm)')
plt.title('Training Linear Regression')
plt.plot(xp, p1(xp), c='r')
plt.show()

这条线与训练集非常匹配。“0.75”的平方值相当不错:

r2_train = r2_score(trainy, p1(trainx))
print('The rsquared value is: ' + str(r2_train))

现在让我们看看这条线如何与我们保存的测试数据相匹配:

xp = np.linspace(0, 6, 100)
axes = plt.axes()
axes.set_xlim([1,6])
axes.set_ylim([50, 200])
plt.scatter(testx, testy)
plt.xlabel('Age (yr)')
plt.ylabel('Length (cm)')
plt.title('Testing Linear Regression')
plt.plot(xp, p1(xp), c='r')
plt.show()

这个模型看起来不错。它没有考虑 6 岁时的异常值,而且相对于每个年龄组的中值长度来说,它看起来也有点低。这些担心在较低的平方值中是合理的:

r2_test = r2_score(testy, p1(testx))
print('The rsquared value is: ' + str(r2_test))

二次模型测试:

让我们看看二次回归与简单线性回归的比较。这些计算的代码与上面的计算非常相似,在 numpy.polyfit 方法中定义回归时,只需将中的“1”更改为“2 ”:

p2= NP . poly 1d(NP . poly fit(trainx,trainy, 2 ))。

二次回归具有较高的训练方差。此外,与测试数据相比,它几乎没有下降多少。

性别(n6)回归检验:

最后,让我们看看高次多项式回归是如何执行的:

该模型以最高的训练平方值开始,但是当实际测试时,它直线下降。这是过度装配的症状。

结论:

二次回归最适合本例中的数据。然而,在训练/测试分割之前的混洗会影响这些结果。根据哪些行结束于哪个段,rsquared 结果可能会略有不同。对于像这样的小数据集来说尤其如此。

原始数据来源:宾夕法尼亚州立大学。

如果你觉得这有帮助,请订阅、鼓掌或评论。

感谢阅读!

我的其他文章,如果你想了解更多:

点击了解逻辑回归

点击了解有关 rsquared 的信息:

line flow:py torch 或任何框架的简单 NLP 数据集处理程序

原文:https://towardsdatascience.com/lineflow-introduction-1caf7851125e?source=collection_archive---------20-----------------------

代码越少,痛苦越少

Photo by Ferenc Horvath on Unsplash

对于 NLP 任务,您可能需要在预处理中标记文本或构建词汇表。而且你大概也体验过,预处理代码跟你的桌子一样乱。原谅我,如果你的桌子很干净:)我也有这样的经历。这就是为什么我创造了 LineFlow 来减轻你的痛苦!它会让你的“桌子”尽可能的干净。真正的代码是什么样的?看一下下图。预处理包括标记化、构建词汇表和索引。

I used Codeimg.io for this picture.

左边部分是来自 PyTorch 官方示例库的示例代码,它对文本数据进行常见的预处理。右边部分用 LineFlow 编写,实现完全相同的处理。你应该明白线条流是如何减轻你的疼痛的。你可以从这个链接查看完整代码。

在这篇文章中,我将详细解释右边部分的代码,并向您展示 LineFlow 的用法。让我们开始一个干净的“办公桌”生活吧!

1.加载您的文本数据

加载文本数据是通过上面代码的第 8 行完成的。稍后我会解释地图。lf.TextDataset将文本文件的路径作为参数并加载它。

dataset = lf.TextDataset(path, encoding='utf-8').map(...)

lf.TextDataset期望的数据格式是每行对应一个数据。如果您的文本数据满足这个条件,您可以加载任何类型的文本数据。

加载后,将文本数据转换为列表。列表中的项目对应于文本数据中的行。看下图。这是对lf.TextDataset的直观形象。图中的d代表代码中的dataset

LineFlow 已经提供了一些公开的数据集。所以你可以立即使用它。您可以在此查看提供的数据集。

2.标记化

第 8 行也完成了文本标记化。map将作为参数传递的处理应用于文本数据的每一行。

dataset = lf.TextDataset(...).map(lambda x: x.split() + ['<eos>'])

看下图。这是lf.TextDataset.map的直观形象。图中的d代表代码中的dataset

下面让我们深入实际的处理过程。

lambda x: x.split() + ['<eos>']

这里,我们用空格将文本数据中的每一行分割成标记,然后在这些标记的末尾添加<eos>。我们按照 WikiText 官方页面的处理方式。

此时,我们使用str.split进行标记化。我们可以使用其他标记化方法,如 spaCy 、 StanfordNLP 和 Bling Fire 等。例如,如果你想使用 Bling Fire,我们会得到下面的代码。

>>> from blingfire import text_to_words
>>> d = lf.TextDataset('/path/to/your/text')
>>> d.map(text_to_words).map(str.split)

此外,我们可以做任何我们想要的处理,只要我们的处理将每行文本数据作为参数。例如,我们可以计算令牌的数量。在下面的代码中,标记的数量在第二个元素中定义。

>>> d = lf.TextDataset('/path/to/text')
>>> d.map(tokenize).map(lambda x: (x, len(x)))

当我们想要制作注意力机制或 LSTM 的面具时,这种处理是很有用的。

3.索引

从第 9 行到第 12 行完成索引。这些线条如下图所示。在这个代码块中,我们构建了词汇表和索引。让我们按顺序来看这些。

for word in dataset.flat_map(lambda x: x):self.dictionary.add_word(word)
return torch.LongTensor(dataset.flat_map(...))

首先,我们将看到构建词汇的模块。在下面的代码块中,我们构建了词汇表。flat_map将作为参数传递的处理应用于数据中的每一行,然后将其展平。所以我们会在dataset.flat_map(lambda x: x)后得到个人令牌。

for word in dataset.flat_map(lambda x: x):self.dictionary.add_word(word)

看下图。这是对dataset.flat_map(lambda x: x)的直观形象。图中的d代表代码中的dataset

flat_map有点令人困惑,但它相当于下面的代码。

>>> from itertools import chain
>>> chain.from_iterable(map(lambda x: x, dataset))
>>>
>>> dataset.flat_map(lambda x: x) # same as above

在使用flat_map提取每个标记之后,我们将标记传递给self.dictionary.add_word,后者构建词汇表。我不解释它是如何工作的,因为它与这篇文章无关。但是如果你对它的内部实现感兴趣,请查看这个链接。

self.dictionary.add_word(word)

接下来,我们将看到索引的代码块。索引由下面的块完成。这里,我们还使用flat_map来索引每个令牌并将其展平。这是因为 PyTorch 的例子需要平坦记号的张量。所以我们跟着它。

dataset.flat_map([lambda x: self.dictionary.word2idx[token] for token in x)])

看下图。这是dataset.flat_map(indexer)的直观形象。图中的d代表代码中的dataset

这个代码等同于下面的代码。

>>> from itertools import chain
>>> chain.from_iterable(map(indexer, dataset))
>>>
>>> dataset.flat_map(indexer) # same as above

最后,我们用torch.LongTensor把它包裹起来,使之成为张量。我们完成了文本数据的加载。

return torch.LongTensor(dataset.flat_map(...))

我们可以在下面查看到的全部代码。

解释到此为止。LineFlow 通过对文本数据进行矢量化来完成较少的循环和较少的嵌套代码。我们可以通过使用 Python 的地图来做同样的事情。但是 LineFlow 为我们提供了可读和干净的代码,因为它像管道一样构建处理(流畅接口)。

如果你喜欢 LineFlow 并想了解更多,请访问下面的知识库。

[## tofunlp/lineflow

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/tofunlp/lineflow/tree/master/examples)

感谢您的阅读!

[NLP]基础:测量文本的语言复杂性

原文:https://towardsdatascience.com/linguistic-complexity-measures-for-text-nlp-e4bf664bd660?source=collection_archive---------6-----------------------

Photo by Nong Vang on Unsplash

确定文本的语言复杂性是您在自然语言处理中学习的第一个基本步骤。在本文中,我将带您了解什么是语言复杂性,以及如何度量它。

预处理步骤

首先,你需要对你的语料库进行标记化。换句话说,您需要将文本语料库中的句子分解成单独的单词(标记)。此外,你还应该删除标点符号,符号,数字,并将所有单词转换为小写。在下面的代码行中,我向您展示了如何使用 quanteda 包来实现这一点。

# Creating a corpus
mycorpus <- corpus(data, text_field = "text")# Tokenisation
tok <- tokens(mycorpus, what = "word",remove_punct = TRUE,remove_symbols = TRUE,remove_numbers = TRUE,remove_url = TRUE,remove_hyphens = FALSE,verbose = TRUE, include_docvars = TRUE)
tok <- tokens_tolower(tok)

然后,我在语料库的预处理中增加了一个步骤:删除停用词。这允许你在测量文本的词汇复杂度时得到更有意义的结果。为什么?因为停用词的词汇丰富性很小,只用于在句子中绑定单词。因此,为了不在分析中产生任何噪声,最好将它们移除。但是,请记住,这样做会大大减少字数。

tok <- tokens_select(tok, stopwords("english"), selection = "remove", padding = FALSE)

请注意,一些词汇复杂性的度量方法可能在您的语料库对象上工作得很好(正如您将在下面看到的),因此您不需要经历预处理步骤。

类型与标记

在自然语言处理中,您会经常听到“类型”或“标记”这样的词,理解它们所指的是很重要的。

令牌指的是你语料库中的字数。它指任何种类的词,甚至是停用词。下面的代码行向你展示了如何使用你的标记化对象找出你的语料库中的标记数量。

ntoken(tok)

类型指的是在你的语料库中找到的独特单词的数量。换句话说,虽然标记计算所有单词而不管它们是否重复,但是类型只显示唯一单词的频率。从逻辑上讲,类型的数量应该低于令牌的数量。

ntype(tok)

复杂性度量——它们是什么?

在语言学中,复杂性是一个文本的特征,但在实践中有多种度量,因此有多种隐含的定义。在自然语言处理中,这些度量对于描述性统计是有用的。我将向你展示评估文本复杂性的两种最流行的方法:文本的易读性(文本可读性)和丰富性(文本丰富性)。

词汇可读性

可读性测量试图量化文本的阅读难度。通常采用的基准是儿童书籍——被归类为“简单”类。使用 quanteda 包,一个有用的方法是从下面代码中显示的文本可读性的基本函数开始。

readability <- textstat_readability(mycorpus, c("meanSentenceLength","meanWordSyllables", "Flesch.Kincaid", "Flesch"), remove_hyphens = TRUE,min_sentence_length = 1, max_sentence_length = 10000,intermediate = FALSE)head(readability)

注意,这个函数允许您使用语料库对象,而不是标记化对象。在你的论点中,你必须指定你希望使用哪种词汇可读性的度量(点击这里找出所有你可以使用的)。可以包括非常简单直白的比如“meansentencelongth”计算平均句子长度、“meanwodsyllable”计算平均单词音节。

否则,您可以选择统计上更加稳健和复杂的度量。比较流行的是弗莱施-金凯德可读性评分或者弗莱施的阅读容易度评分。这两种测试使用相同的核心指标(单词长度和句子长度),但它们有不同的权重因子。这两个测试的结果大致成反比:在 Flesch 阅读难易程度测试中得分高的文本在 Flesch-Kincaid 测试中的得分应该较低。

弗莱施的阅读容易度测试中的高分表明材料更容易阅读;数字越小,段落越难阅读。作为一个基准:高分应该容易被一个平均 11 岁的孩子理解,而低分最好被大学毕业生理解。

词汇丰富度

与文本可读性类似, quanteda 包也有一个使用词汇多样性度量来评估文本丰富程度的功能。

最受欢迎的措施是类型令牌配额(TTR) 。这一措施背后的基本思想是,如果文本更复杂,作者使用更多样的词汇,因此有更多的类型(独特的单词)。这种逻辑在 TTR 的公式中是显而易见的,它计算类型的数量除以标记的数量。因此,TTR 越高,词汇复杂度越高。

dfm(tok) %>% textstat_lexdiv(measure = "TTR")

虽然 TTR 是一个有用的方法,但是你应该记住它可能会受到文本长度的影响。文本越长,引入小说词汇的可能性越小。因此,更长的文本可能更倾向于等式的标记侧:添加更多的单词(标记),但是越来越少的单词(类型)被表示。因此,如果你有一个大的语料库要分析,你可能想使用额外的词汇丰富度来验证你的 TTR 的结果。

你可以使用的另一个词汇丰富度的量度是 Hapax 丰富度,定义为只出现一次的单词数除以总单词数。要计算这个值,只需在文档特征矩阵上使用一个逻辑运算,为每个出现一次的术语返回一个逻辑值,然后对这些行求和得到一个计数。最后但同样重要的是,计算它占总字数(ntokens)的比例,以便在整个语料库中进行更好的解释。

ungd_corpus_dfm <- dfm(ungd_corpus)
rowSums(ungd_corpus_dfm == 1) %>% head()
hapax_proportion <- rowSums(ungd_corpus_dfm == 1)/ntoken(ungd_corpus_dfm)
hapax_proportion

最后,值得注意的是,复杂性度量在语言学和自然语言处理领域得到了广泛的讨论和辩论。许多学者试图对这些方法进行相互比较,或者回顾现有的方法以开发新的更好的方法。不用说,这是一个不断发展的领域。

我经常写关于数据科学和自然语言处理的文章。在 Twitter Medium上关注我,查看更多类似的文章或简单地更新下一篇文章。 感谢阅读!

为自然语言处理编写语言规则

原文:https://towardsdatascience.com/linguistic-rule-writing-for-nlp-ml-64d9af824ee8?source=collection_archive---------4-----------------------

用 spaCy 提取问题类型的指南

Source: This LA Times article

目录

  1. 一位语言学家的沉思
  2. 一种解决方案:基于规则的句法特征提取
  3. 一个例子:使用 spaCy 的问题类型抽取

🌳一位语言学家的沉思

当我在语言学博士项目接近尾声时开始探索数据科学时,我很高兴地发现了语言学的作用——具体来说,是语言学的特征——在 NLP 模型的开发中。与此同时,我有点困惑,为什么很少有人谈论利用句法特征(例如,从句嵌入的程度、并列的存在、言语行为的类型等等)。)相比于其他类型的特征,比如某个单词在文本中出现了多少次(词汇特征),单词相似度度量(语义特征),甚至单词或短语在文档中出现的位置(位置特征)。

例如,在情感分析任务中,我们可以使用实词列表(形容词、名词、动词和副词)作为特征来预测用户反馈的语义取向(即,积极或消极)。在另一个反馈分类任务中,我们可以管理特定领域的单词或短语列表,以训练可以将用户评论引导到适当的支持部门的模型,例如,计费、技术或客户服务。

这两项任务都需要预先构建的词典来进行特征提取,并且有许多这样的词典供公众使用,例如由媒体作者管理的 SocialSent 和这些。(也可以查看这篇研究文章,它讨论了建立情感词典的不同方法)。虽然词法特征在许多 NLP 应用程序的开发中发挥了重要作用,但是涉及句法特征使用的工作相对较少(一个大的例外可能是在语法错误检测领域)。

对我这样一个来自语言学传统的人来说,这很令人困惑(也有一点讨厌),因为在语法的总体架构中,语法比语义和音位学更“优越”。当然,这并不是说语言学家认为句法在某些方面比语言学的其他分支更重要——而是说它在许多语法模型中占据首要地位,这些模型假设句法形式是在语义或语音解释实现之前得到的。习惯了语言学理论中句法模块的这种“中心性”,我很难理解 NLP 中对句法结构的不冷不热的态度,这与 NLP 开发人员对词汇内容作为特征的巨大信心形成了鲜明的对比。

NLP 所想象的语言,有时让我想到一个支离破碎的土豆脑袋先生——散落在一本涂色书的一页上的二维身体部分,彼此没有关系的单词。

Source: https://www.pixar.com/feature-films/toy-story

当我了解到机器学习/深度学习的“魔力”时,我对这种明显过度简化的语言(在我最早的理解中,它是一个单词包)感到的一些不安最终消散了:即使没有显式编码,“它也能学习语法。”(具有讽刺意味的是,这也是一个孩子在没有明确指导的情况下习得语言的方式。)

但是,作为一名语言学家(特别是一名形态合成学家),老实说,我仍然有点担心句法特征在 NLP/ML 中没有获得像词汇特征那样多的关注,我倾向于将这种不对称归因于以下原因:

1。重复暴露于去强调结构的预处理流水线并对其进行规范化

作为 NLP 的学生,我们被反复介绍了 NLP 管道,其中包括预处理技术,如停用词移除、词汇化/词干化和词袋表示。这些技术在许多情况下是有价值的,但本质上是减法:它们去除了原文中存在的大量句法(和/或形态学)信息。停用词去除消除了编码关于成分/短语之间关系的信息的虚词,例如 into、from、to、等。词汇化和词干化删除了重要的屈折特征,如时态和一致以及派生词缀,这些词缀可能对确定单词的准确含义至关重要(例如,教师中的- er ,以及- 盗用中的- ment )。当然,单词袋表示法不考虑词序,对于像英语这样不使用形态格来表示词序的语言来说,这是一个重大损失。当这些步骤成为我们日常 NLP 管道中正常和重复出现的部分时,它有可能模糊或最小化句法结构在自然语言处理中实际发挥的作用,从而阻碍或阻止任何系统地测量其对 NLP 模型的影响的努力。

2。编写复杂语言规则的实际挑战

我还推测,句法特征的相对晦涩在很大程度上是由于编写足够复杂的规则的实际挑战。NLP 专家进入该领域时,对句法的了解程度各不相同,如果没有对每种语言的句法结构的基本原理和共性以及某种程度上对跨语言变化的限制的牢固掌握,可能很难知道什么样的句法特征与特定语言相关,更不用说编写试探法来提取它们了。与词汇特征不同,词汇特征在许多情况下相当于简单的字数统计,在句子(句法)级别上精心设计经过深思熟虑的语言规则是一项更具挑战性的任务,需要大量的领域知识。

3。人机交互中人类语言的简化性质

我还发现,我们一些最受欢迎和商业化的 NLP 产品不需要非常复杂的输入文本或语音的语法表示,这使得语法特征在支持它们的模型开发中变得不可或缺。我认为原因是:(1)人机交互中的人类语言往往过于简单(“嘿,谷歌,旧金山天气”与“嘿,约翰,你介意告诉我今天旧金山的天气吗?”)和(2)简单的解析比复杂的解析更适合于计算成本较低的系统,所以我们不得不处理这些约束。

👮一种解决方案:基于规则的句法特征抽取

明确地说,我上面概述的三件事是在特征工程中使用句法特征的挑战/障碍,而不是排除它们的理由。虽然我不确定与其他特征相比,句法特征对模型性能的贡献有多大,但我确实相信,随着我们寻求构建能够以更加微妙、自然和复杂的方式与人类交互的机器,句法输入和表示将在未来的自然语言处理中发挥越来越重要的作用。我认为,我们可以通过做以下三件事来应对,从而受益匪浅:

  1. 在我们日常的 ML 工作中更多地尝试语法特性,并投资于简化这个过程,使它成为流水线中重复的一部分。
  2. 为语言特征提取创建更多开源代码。
  3. 雇佣更多的语言学家——如果有必要的话,帮助他们提高专业技能。投资它们,因为它们会带来独特的回报。

在所有这三个任务中,我认为我们将通过开发,特别是一个规则驱动的系统来获得最大的收益。语法是一个需要关于特定语言的精确知识的领域,因此非常适合于基于规则的表示(在 NLP 中),也许比任何其他语法领域都更适合。采用基于规则的方法的提议与采用完全 ML 的方法来构建特性集相竞争。在后一种情况下,您训练一个模型来预测特定特性的值,并将其输入一个模型来预测某个目标变量的输出。然而,这个过程很可能非常耗时和昂贵,因为你正在训练一个模型训练一个模型。这就是为什么我会建议在几乎所有情况下将规则作为混合系统的一部分。混合方法将 ML 算法驱动的基础模型与作为一种后处理过滤器的基于规则的系统相结合,它们已经是旧闻了。它们已经有很多成功的应用,比如这个和我自己的工作。

规则用法

规则和基于规则的系统的另一个优势是,它们可以以多种方式灵活使用,因此为 ML 管道的几乎每个阶段带来价值和严谨性。除了在特征工程阶段使用它们提取特征外,它们还可用于:

  1. 预先标记大型数据集,以在数据准备期间创建有噪声的训练数据(一个标记功能
  2. 在数据预处理期间排除某些注释(一个预过滤器)
  3. 在模型评估之前/期间从分类器的输出中过滤掉假阳性(一个后置过滤器

因此,像有些人可能倾向于做的那样,用规则或基于规则的系统来对抗 ML 算法是不合适的。相反,我们必须承认,它们在一些非常引人注目的方面相互补充,为整体架构增添了重要的优势。

基于空间的⛹️‍♂️问句类型抽取

在这最后一部分,我将提供一个实用的指南来编写一些用于特征提取的语法规则。我将使用 spaCy 来做这件事,重点是提取题型。我选择了问题类型,因为这一类别可以很好地说明语言知识在构建部分规则驱动的 NLP 模型中的不可思议的价值。此外,可能有许多问题类型提取的用例(通过扩展,句子类型),所以希望有人能从下面的代码中受益。我能想到的一些应用有:问题的细粒度分类(句子是 wh-问句,是非问句,还是附加疑问句?)、言语行为检测(评论是问题、请求还是需求?)、一些对比言语分析(哪个个人或群体在言语中使用更多的礼貌策略?),等等。

Source: This review

在这最后一节,我最终希望能够让 NLP 开发人员理解语言学知识的相关性,以及 NLP/ML 任务中规则或基于规则的系统的相关性

语言规则编写:一个迭代过程

在编写语言规则时,我通常遵循以下六个步骤:

  1. 确定感兴趣的类别(例如,“疑问词”、“极性问题”、“不是问题”)。
  2. 对每个类别提出一两个大的语言概括。
  3. 想出一些概括的反例,并在必要时修改/扩展它们。
  4. 写出捕捉新概括的规则。
  5. 在一堆例子上测试规则。
  6. 通过解决任何误报和测试新示例来微调规则。

这些步骤通常不会完全按顺序进行。例如,确定你想要的目标类别(步骤 1)基本上相当于陈述一些关于它们的概括(步骤 2),所以你可以同时做这些步骤。在我说明这个流程如何指导我们的规则编写之前,让我们稍微深入一下 spaCy。

spaCy 入门

spaCy 是一个高性能的 Python 库,它拥有众多的特性和功能来帮助您构建您最喜欢的 NLP 应用程序,包括标记化、命名实体识别、词性标记、依存解析、预训练的单词向量和相似性以及内置的可视化工具。在这里查看它的全套功能,但是这里我们将只关注它的两个处理组件 tbat,这两个组件将使我们能够表示任何句子的句法结构,即taggerparser。使用 spaCy 的基本流程是这样的:首先,加载一个你选择的模型(例如"en_core_web_sm")。然后你可以通过调用nlp上的pipelinepipeline_name来检查管道组件。

接下来,通过传入一个字符串并将其转换成一个 spaCy Doc,一个令牌序列,来调用nlp(下面的第 2 行)。Doc的语法结构可以通过访问其组件标记的以下属性来构建:

  • **pos_**:粗粒度的词性标签。
  • **tag_**:细粒度的词性标签。
  • **dep_**:句法依存标签,即记号之间的关系。
  • **head**:句法调控器,或者直接支配的标记

我发现打印出这些属性的值以及元组中的标记名和索引很有帮助,如下所示:

如果你想可视化解析,把你的句子输入 spaCy 的内置可视化工具 displaCy :

spaCy’s visualizer displaCy lets you visualize dependency parses with POS annotations

箭头指示标记之间的头部相关关系,并且每个标记都标有粗略级别的 POS 标签(精细级别(tag_)在此未示出)。

步骤 1-2:确定你想写规则的类别,并为每个类别提出一两个语言概括

这两个步骤通常是齐头并进的。在提出问题类型提取的规则时,我们必须认识到任何语言中都有两种类型的问题:特殊疑问句和极性疑问句。仔细阅读这些概括:

Generalizations about question types:(1) **Wh-questions** (aka content questions): start with an interrogative word (a “wh-phrase”) like *who, what*, *where*, and *how,* and call for specific information.(2) **Polar questions** (aka yes or no questions): can be answered in the affirmative or the negative (with a yes or a no response), and begin with an auxiliary (*did, do*) or modal (*will, can*) verb.

您可能会发现使用 displaCy 可视化这些问题类型很有帮助。最后一个截图包含了一个疑问问句的解析,下面是一个极性问句的解析:

A dependency parse for a polar question

除了可视化解析之外,我喜欢能够看到每个标记的 pos-tag-dep 三元组,如下所示:

利用您对 Penn Treebank 注释约定的了解(因为这是 spaCy 所使用的),您可以尝试编写 v1 函数来捕捉上面的概括。我通常喜欢为不同的类别编写单独的函数,而不是编写一个包含复杂的 if/then 逻辑的函数。这里有一个快速的第一个版本,试图捕捉(1)-(2)中的概括。

v1 rules for extraction the two question types

第三步:想出反例,修改你的概括

为你最初的概括提出反例是必要的,因为它们会挑战你对所考虑的语言现象的基本假设(这里是问题形成),并迫使你找出不同例子之间的共同线索,以统一、概括的方式表达它们的行为和特征。最终,这将有助于您编写更简单、更健壮、更全面的规则。

上面给出的两个概括在这里复制,以节省您的滚动:

(1) **Wh-questions** (aka content questions): start with an interrogative word (a “wh-phrase”) like *who, what*, *where*, and *how,* and call for specific information.(2) **Polar questions** (aka yes or no questions): can be answered in the affirmative or the negative (with a yes or a no response), and begin with an auxiliary (*did, do*) or modal (*will, can*) verb.

这里是(1)中概括的第一对反例:

(3) What you sayis unbelievable.
(4) Who you're going to kill is not my problem.

我们看到(1)没有被这些句子证实,因为尽管以疑问词开头,它们不是疑问词!它们就是语言学家所说的 wh-clefts,或假撇子。假左通常被描述为强调或“聚焦”句子的一部分,并且具有(5)中的形式:

(5) free relative + "be" + focused constituent

自由关系是一个 wh-relative 从句,它(显然)缺少一个中心名词(所以是“你说的东西”而不是“你说的东西”)。这部分伪左引导一个主题(句子是关于什么的),并通过动词“be”链接到一个引入新信息(“不可思议”)的焦点成分。

以下是(1)的一些反例:

(5) In which article did they talk about spaCy?
(6) To whom did you read the article?

这些句子没有证实(1)的原因是不同的:虽然它们没有像概括所说的那样以疑问短语开始,但它们仍然是疑问问句,因为它们可以用具体的信息来回答(6)的问题(例如,对(6)的回答可以是“我给我妹妹读了这篇文章。”).这些句子是所谓的pied-pied结构,其特点是一个 wh-词与一个介词一起出现,就好像它将另一个“拖”到了句子的前面。(6)特别可以与另一个句子形成对比的是,“股”是介词:你读了谁的文章?”。

最后,这里有两个反例来概括(2)中陈述的关于极性的问题:

*(7) Is it going to rain tonight?
(8) Were you sad about her leaving?*

这些句子表明,除了助动词和情态动词之外,系词(“be”)作为动词(vs. an 助动词)应该被列入可以出现在极性问句开头的动词范畴。更简单地说,当动词是助动词、情态动词或充当主要动词的 be 形式时,动词和主语在极性问句中会发生倒置。这使我们得出以下经过修改的概括:

*(1') **Wh-questions** (aka content questions): **contain** an interrogative word (a “wh-phrase”) like *who, what*, *where*, and *how,* and call for more specific information.(2') **Polar questions** (aka yes or no questions): can be answered in the affirmative or the negative (with a yes or a no response), and display subject-verb inversion where the verb must be either an auxiliary (*did, do*), a modal (*will, can*), **or a form of the main verb *be.****

我认为这一步清楚地表明,语言知识对于编写复杂的特征提取规则是不可或缺的。了解英语使用各种策略来标记疑问句,如主语-动词倒装和 wh-移动,以及识别(并命名)有趣的语言现象,如 pied-piping 和 clefting,可以帮助你形成概括,进而帮助你编写不太具体的全面规则。

第四步:写规则

我们现在可以修改函数的早期版本is_wh_question_v1is_polar_question_v1,以符合新的一般化(1’)和(2’)。这一部分需要一些时间和练习,然后我们才能感到非常自信和舒适,所以要有耐心!下面,我将重点介绍 v2 功能的几个核心特征:

is_wh_question_v2:

  • 指空间标签(如"WDT""WP"等)。)使您的规则比引用单个 wh-words(第 3 行)更通用。
  • Pied-piping 可以通过 wh-word 和它的 head(语法父级,或标记的“governor ”)之间的prep依赖关系来捕获(第 8 行)。
  • 如果 wh 字与它的头部有csubjadvcl关系,则通过返回False来排除伪左(第 11-13 行)。

is_polar_question_v2中,我们需要考虑两种情况:

  1. 这个问题出现在一个非系词结构中,其中“is”(或“be”的另一种形式,如“were”)起着助词的作用,例如,“she正在使用空间吗?”(这里的主要动词是“利用”。)
  2. 这个问题出现在一个系动词结构中,其中“is”充当主动词,“IsIsthe mouse dead?”
  • 第 1 类出现在第 14-16 行,主语的倒置与助动词有关。(同样几行代码也可以占主语- 情态倒装句,像“你能看懂文章吗?”).
  • 类型 II 在第 20–22 行被捕获,主语的倒置是相对于根的,即依赖标签是文档中的"ROOT"的唯一标记。
  • 第 9-10 行体现了极性问题和特殊疑问句的互斥性。

步骤 5–6:在一堆例子上测试规则并迭代!

最后,为了将以上所有内容放在一起,我们可以编写一个测试函数,该函数获取一个例句列表,并打印每个句子的问题类型。

当我运行get_question_type(sentences)时,我得到以下输出:

*In [352]: get_question_type(sentences)
Is that for real? -- polar
Can you stop? -- polar
Do you love John? -- polar
Are you sad? -- polar
Was she singing? -- polar
Won't you come over for dinner? -- polar
Would you help me? -- polar
Who do you love? -- wh
**Whose child is that.** -- wh
How do you know him? -- wh
To whom did she read the book? -- wh
I'm hungry. -- not a question
Spacy is so fun! -- not a question
Tell me what you mean. -- not a question
Would love to help you. -- not a question
Don't be sad. -- not a question
**Whatever you want.** -- wh  # false positive 
What you say is impossible. -- not a question
Where you go, I will go. -- not a question*

除了倒数第三句“随便你。”。使用 v2 函数,我们已经实现了 18/19 = 94.7% 的准确度。还不错!请注意,这些规则对每个句子的潜在句法结构真正敏感,而不是对一些表面属性,如问号的存在(如“那是谁的孩子”示例的正确分类所示)。》。

此外:

*from sklearn.metrics import classification_reportcr = classification_report(true_values, rules_predictions)
print(cr) precision    recall  f1-score   supportnot a question       1.00      0.88      0.93         8polar       1.00      1.00      1.00         7wh       0.80      1.00      0.89         4*

最后一步,您将希望通过解决任何误报来微调您的规则,以提高精确度(例如,“无论您想要什么。”被错误地归类为 wh-问题),并用更多的例子(和更复杂的例子)进行测试以提高回忆。满意后,将规则应用于新数据,并在您认为合适的工作流程的任何阶段使用结果。例如,您可以选择在特征工程期间将它们作为特征合并,或者在数据管线中尽早使用它们来生成用于注记的噪声数据。

NLP/机器学习的语言规则编写是一个丰富的迭代过程,需要对语言有深刻的理解,并能够以编程语言的通用试探法的形式将这些知识编码。虽然规则可能不足以在 NLP 的大多数应用中独立存在,并且良好的规则编写几乎总是需要专业知识,但是它们具有许多优点,并且是 ML 算法的很好补充。如果我已经让你完全相信了它们的价值,请给 spaCy 一个尝试,并随时建议下面的 v3 功能,或者添加对其他功能的规则的请求。😃

美国白人的“抑郁死亡”与特朗普胜选之间的联系

原文:https://towardsdatascience.com/link-between-depression-deaths-in-white-america-trump-victory-4209a9d9957e?source=collection_archive---------30-----------------------

抑郁症死亡率高的地方如何在 2016 年特朗普的选举胜利中发挥关键作用?

“绝望之死”是一种报道不足的现象,它已经导致近 100,000 名美国中年白人因抑郁症相关原因而死亡。(自杀和成瘾)自 1999 年以来。(这次疫情在范围上堪比艾滋病)。我很好奇这是否与特朗普 2016 年的选举胜利有任何关联。所以我收集了从 1999 年到 2016 年每个县的 CDC 死亡率数据&然后我收集了最近三次选举的数据,即县级 2008 年、2012 年、2016 年。

这项分析是在县一级进行的,着眼于每个县在 2016 年选举中特朗普得票率的百分比波动&发现抑郁症死亡率上升最多的县;特朗普的支持率也显著上升。分析还显示,在 2008 年至 2016 年期间;白人死亡率上升高度集中在三个州,即密歇根州、威斯康星州&宾夕法尼亚州(这是特朗普成功的关键)以及他们从民主党的传统选民基础转向特朗普。它还发现了一个惊人的相关性,即“绝望死亡”率较高的县更有可能投票给特朗普,随着死亡率的增加,投票转向共和党的趋势也在增加。(见下文)

虽然“愤怒”长期以来一直被认为是解释川普赢得选举的隐藏变量,但这一分析可能是试图通过将愤怒与抑郁症(具体而言是绝望导致的死亡)联系起来,量化这种愤怒。选举被选民情绪所左右&如果他们被邻居绝望的死亡所包围,情绪受到影响是很自然的。

这种分析有助于帮助未来的选举模式;通过将绝望相关的区域死亡率作为影响投票者的关键特征向量之一。抑郁症的心理影响也可以解释特朗普的“非智力”简单化叙事对其核心基础的吸引力。

项目的技术细节

介绍

2015 年,一项突破性的研究声称,美国正在发生一些不寻常和令人不安的事情;几乎无人察觉。它的结论是,美国中年白人的死亡率突然上升;尽管美国其他种族和民族以及其他发达国家的白人的预期寿命都很长。作者称之为“绝望的死亡”,即美国中年白人通过自杀或与上瘾相关的死亡来自杀。这种流行病自 1999 年以来呈上升趋势,与教育、劳动力市场、家庭和宗教崩溃等因素的变化有关。[1]

另一方面,特朗普在 2016 年大选中出人意料的胜利仍然是一个谜,因为它与传统选举分析做出的大多数预测相矛盾。到目前为止,右翼政治和中年白人死亡率之间的联系已经被一些人假设,但没有被研究。这一数据挖掘案例研究着眼于 1999 年至 2015 年期间死亡率上升与倾向于共和党之间的相关性,以及与 2008 年和 2012 年的选举相比,最绝望的地点是否确实对应于选民从民主党转向共和党。

这项分析是在县一级进行的,研究每个县的中年白人美国人的死亡率以及该县在 2016 年选举中的投票情况。更具体地说,我们观察了每个县在 2016 年选举中共和党选票的百分比波动&发现死亡率增加最多的县;共和党的得票率也显著上升。这些地图还显示了 2008 年至 2016 年期间的情况;白人死亡率上升高度集中在三个州,即密歇根州、威斯康星州和宾夕法尼亚州(这是特朗普成功的关键)以及他们从民主党的传统选民基础转向共和党。它还发现了一个惊人的相关性,即“绝望死亡”率较高的县更有可能投票给共和党,这种投票转向共和党的趋势随着死亡率的增加而增加。

尽管“愤怒”长期以来一直被认为是解释特朗普选举胜利的隐藏变量,但这一分析可能是试图通过将愤怒与抑郁(具体而言是绝望导致的死亡)联系起来量化愤怒。选举被选民情绪所左右&如果他们被邻居绝望的死亡所包围,情绪受到影响是很自然的。这种分析有助于帮助未来的选举模式;将绝望相关的地区死亡率作为影响选民的因素之一。

1.问题背景

诺贝尔奖获得者安格斯·迪顿和安妮·凯斯在 2015 年发表了他们的开创性论文,题为“21 世纪非西班牙裔美国白人中年发病率和死亡率上升”,发现了美国以前未知的现象。1999 年至 2015 年间,美国非西班牙裔中年白人男性和女性的全因死亡率显著上升。死亡率上升的趋势是由于药物和酒精中毒、自杀、慢性肝病和肝硬化的死亡率上升;一起被称为“绝望的死亡”。这种死亡率上升的趋势在白人非西班牙裔美国人中是独一无二的,因为其他种族的死亡率持续下降。更重要的是,这种趋势也是美国独有的,因为在其他发达国家没有观察到。下面两张从论文中借用的图表,可以更好地展示得出的结论。[1]

第一个图表显示死亡率上升是美国独有的,第二个图表显示美国非西班牙裔白人的趋势是独一无二的。必须重申的是,从 1900 年到 1999 年,美国所有群体的死亡率都在稳步下降(由于总体预期寿命和生活质量的提高),但我们突然看到了这种趋势的逆转,不仅某个特定群体的死亡率下降停止了,而且他们突然死得更年轻、更快。

这篇论文强调了这种令人不安的趋势的严重性,称之为与艾滋病相当的流行病;但是没有引起注意。从报纸上引用。“如果 45-54 岁的白人死亡率保持在 1998 年的水平,1999 年至 2013 年将避免 96,000 例死亡,仅 2013 年就有 7,000 例。如果继续以之前(1979-1998 年)的速度下降,1999-2013 年期间将避免 50 万例死亡,相当于 2015 年中期美国艾滋病疫情中的死亡人数。”[1]

抑郁症会影响人们投票吗?

唐纳德·特朗普(Donald Trump)在 2016 年美国大选中意外获胜,迄今已有多种角度的解释。人们常说的一句话是,2016 年的选举触及了“美国的愤怒”。然而,到目前为止,还没有提出一个量化的定义来衡量愤怒。可想而知,绝望是愤怒的另一种变形。共和党的强大基础恰好是美国中年白人,这可能不是完全的巧合。把这两个方面放在一起,就是本研究的目的。

这一数据挖掘案例研究建立在上述论文的基础上,并试图发现,在美国绝望死亡人数上升和 2012 年至 2016 年选举中共和党选票摇摆之间是否存在某种模式。这个命题是要看看特朗普的选票增加是否与这些地区白人中年死亡率的百分比增加有关联。这项分析是在县一级进行的,包括投票率和死亡率。主张是检测共和党投票率上升的可变性可以部分地由统计上显著的死亡率变量来解释。

非常具体地说,这个案例研究计算了每个县中年白人美国人的死亡率,并试图确定它与该县特朗普选票的关系,以及在以前的选举中该县特朗普的支持率。

2.数据收集和分析

本项目的死亡率数据来自 CDC(疾病控制中心)。从 1999 年到 2015 年,每年都在逐步下载数据(由于 CDC 网站下载的大小限制)。该数据集包括这一时期美国各县的死亡人数和人口。[2][3]

2016 年的选举数据集是从《卫报》网站上搜集来的。数据()的抓取版本包括县级选票以及 2008 年选举结果和 2012 年选举结果的附加文件,以供比较。[5][6]

2.1 准备死亡率数据

以下是准备死亡率数据的步骤。

  1. CDC 提供了一本手册来理解数据集的列(4)。这些被用来解释数据。
  2. 限制中年人口的数据集,即。根据参考研究,年龄从 45-54 岁。
  3. 从 1999 年到 2015 年每年下载的全部数据文件包含有关{县、年份、种族、西班牙裔、性别、死亡和人口}的信息。有一些额外的列在这个阶段被丢弃。
  4. 每年死亡率数据的所有单个文件都被合并并加载到一个数据框中。
  5. 下一步是清除 population 为 NA 的行的数据。这样的行将被删除。
  6. 在此之后,我们按照每年、县和种族类型汇总数据。这是为了根据每个县每年的种族和死亡人数对数据集进行细分。
  7. 接下来我们计算每个县的种族死亡率。死亡率数据集现在准备用于导出特征向量。

2.2 准备投票数据集

  1. 收集 2008 年、2012 年和 2016 年县级选举结果的数据集。
  2. 合并县一级的数据集,创建一个综合文件。

3.特征工程

我们现在得到了可以用来定义特征向量的干净数据。准备数据以便将其用于模型是一项耗时的活动。它来回多次,有时只有在运行模型后才发现一些数据问题。为简单起见,下文仅提及最终数据准备方法,以及大量分析后发现的相关特征。

3.2 死亡率数据

  1. 使用比赛代码(对于每个比赛,即白色、黑色等。)和西班牙血统代码,我们对数据集进行分段,以导出白人-NH(非西班牙裔白人)和非白人(所有其他种族和西班牙裔)的人口标识符。我们继续进一步分析只有白人人口。
  2. 数据由这个新的种族描述符(白人与非白人)汇总,并得出每个县的死亡率。
  3. 接下来,我们处理缺失的值。一些间歇年份的数据可能会因县而缺失。总的来说,丢失数据的情况非常少。由于死亡率不会每年都发生剧烈变化,所以只要去年的死亡率缺失,就应该填入去年的死亡率。
  4. 我们现在得到一些额外的特征。我们首先计算每个县的平均死亡率。这是在不同的时间段计算的,与选举年相关联。所以我们得到了
  • 1999 年至 2007 年的平均死亡率
  • 2008 年至 2011 年间的平均死亡率
  • 2012 年至 2015 年间的平均死亡率
  1. 我们还计算了一些额外的跨期长期平均死亡率。
  2. 接下来,我们计算这两个时期死亡率的百分比变化。这些直接对应于上述时期。所以我们得到了
  • 1999 年至 2015 年死亡率的百分比上升
  • 2008-2011 年平均死亡率与 2012-2015 年平均死亡率之间的百分比上升
  • 1999-2007 年至 2008-2011 年平均死亡率的上升百分比

此外,我们还采用绝对死亡率的对数来处理数据中的偏差。

3.3 选举数据

  1. 我们在之前的实例中准备的选举数据集不包含 2008 数据集的投票份额百分比。因此,要导出的第一个特征是计算 2008 年选举的共和党和民主党的百分比份额。
  2. 接下来,我们得出从 2008 年到 2012 年某个县支持共和党的投票百分比;2012 年到 2016 年和 2008 年到 2016 年。
  3. 我们还派生了标识哪些县是民主党获胜,哪些县是共和党获胜的标志。
  4. 此外,我们还计算了标志,以识别 2008 年和 2012 年在 2016 年选举中为共和党填充的县。这意味着这些县最初由民主党赢得,但他们在 2016 年转向了共和党。

最后,我们在县代码(在笔记本中称为 FIPS 代码)上组合死亡率数据集和选举数据集。

4.建模

使用特征向量准备的数据将被导出到 csv 文件。我们首先检查变量之间的关系,检测异常值,如果需要,记录变量以处理数据中的非线性。然后,我们将构建一个最小二乘 linier 回归模型来验证特征是否具有统计显著性。

4.1 分析

  1. 我们首先使用散布矩阵来检查关系中的任何趋势以及多重共线性。然后我们开始深入挖掘两个变量之间的关系。
  2. 我们在死亡率和摆动之间的图中看到有一个偏斜,所以我们使用变量的对数
  3. 在这个过程中,我们看到了一些异常值。几乎没有会扭曲图表的异常值。为了获得清晰的相关性,去除那些异常值是很重要的,所以我们相应地去除它们。(详情见随附的笔记本)
  4. 看着上面的图表,我们可以说,与 2008 年和 2012 年选举相比,一个县的死亡率与该县在 2016 年选举中共和党选票的变化有着明显的关系。

4.2 回归模型

使用 OLS·林尼尔回归法建立了各种模型;回归 2016 年共和党的选票,并在 2016 年选举中从 2008 年和 2012 年转向支持共和党的选票。

从 2012 年到 2016 年以百分比计算的投票回归模型;发现保持其他一切不变。ln 每增加一个单位(2015 年死亡率);与 2012 年相比,2016 年选举中共和党的支持率上升了 6 个百分点。(请注意,结果是以对数标度表示的)。该模型的 f 统计值为 101,这意味着模型中肯定有一个或多个变量,并且这些变量具有较低的 p 值,表明它们在统计上是显著的。

下面的模型找到了 2016 年投票给共和党的摇摆和不同时期死亡率百分比增长之间的关系。在考虑所有因素后,可以说这种关系仍然是积极的,因为死亡率增加越多,2016 年与 2012 年相比,选票越倾向于共和党。

模型诊断正在模型上运行,没有发现异方差的证据,ggplot 看起来也符合相当线性的关系。

5.结果

5.1“绝望之死”在哪里盛行?

我们首先试图看到 2015 年美国中年白人的死亡率分布,然后是 1999 年至 2015 年间死亡率的长期平均值。然后我们还绘制了各县死亡率上升的百分比图。

正如我们从上面所看到的,有些县,尤其是中西部的县,集中在中西部北部(密歇根州)和南部的一些县,那里流行着“绝望之死”。上述两个图证实了中年美国白人自杀的传播有地区特色&一些地区比其他地区受到的负面影响更大。而且它在很长一段时间内是一致的。

自 2012 年以来,抑郁症死亡人数上升的 5.2 个县中,特朗普的支持率大幅上升

我们现在在地图上标出了自 1999 年至 2015 年以来,美国中年白人死亡率上升最快的县。请注意,所有其他种族的死亡率都在下降(其他发达国家也是如此);因此,看到如此持续增长的县确实令人担忧;几乎就像一个失败的反乌托邦国家。

然后,我们绘制了 2012 年至 2016 年大选中支持共和党的百分比变化图。这是可以说已经从民主党转移到共和党的百分比选票。

很明显,这两张地图有显著的相似之处。我们可以注意到中西部中部、中西部北部以及缅因州;共和党的选票份额上升了 10%以上,这是特朗普赢得选举的关键。这些县的美国白人死亡率和发病率显著上升。2016 年,传统上属于民主党的州(如密歇根州)出人意料的选举结果可以用这一新发现的相关性来解释。

5.3 个抑郁症死亡率高增长的县,自 2008 年以来一直支持特朗普

我们现在绘制了 2008 年至 2016 年选举中有利于共和党的百分比摇摆图(选票从民主党转向共和党),然后我们还绘制了同期(2007 年至 2015 年)白人死亡率的百分比上升。

可以说,县与县之间的相关性是显著而可怕的。重申一下,在仅仅 8 年的时间里,一些县的美国白人死亡率上升了 20 %;当其他国家的黑人、西班牙人和白人的死亡率都在下降时。

特朗普看到的对他有利的巨大转变再次来自密歇根、威斯康星和宾夕法尼亚(决定选举支持特朗普)以及其他中西部地区的完全相同的地区县。

还要注意的是,在东海岸地区(从波士顿到夏洛特)和西海岸的一些地区(仍然是民主党人),这种“绝望之死”的现象并不存在。最后,还要注意死亡率的上升&在这个国家的上西部缅因州这些没有被提及的地区,倾向于 Trump。这些地区可能会在未来的选举中出现混乱。

6.结论

主要发现

  • 根据特征图,可以得出这样的结论:某个县的死亡率解释了 2012 年和 2008 年选举中特朗普在 2016 年选举中的大量摇摆。正如在模型中发现的那样,这两者之间肯定存在统计上的显著相关性。该功能;从 2008 年到 2016 年,每个县的平均死亡率上升的百分比与共和党的选票有很大的相关性。因此,支持共和党的摇摆可以用同样的理由来解释。
  • 事实上,最被忽略和谈论的选举事件之一是民意测验专家忽略了密歇根、威斯康星和宾夕法尼亚的情绪。如果仔细看地图,密歇根、威斯康星和宾夕法尼亚肯定有问题,这可能是解释共和党摇摆的拼图中缺失的一块。这并不意味着完整的选举分析,而是一个引子。
  • 最后,相关性不是因果关系,所以这不能解释“绝望之死”现象的根本原因,而是它如何影响政治结果&不意识到这种影响会导致像 2016 年选举这样令人惊讶的结果。

后续步骤

预测选举结果或分析选举结果是一门需要读懂数百万人心思的艺术。在这个案例研究中,从来没有试图声称“绝望的死亡”是影响选举结果的唯一因素,因为还有成千上万的其他因素。

  • 在寻找相关性时,没有考虑教育因素。选民的教育水平在解释选民百分比波动的可变性方面起着至关重要的作用;包括这些也许能给出更精确的模型。对其他重要变量进行调整也可能是个好主意。然而,教育数据很难找到。
  • 只有回归模型被尝试过,在 OLS 也是如此。其他模型可能更适合这些数据,并且可能提供更强的洞察力和准确性。
  • 最后,在传统的选举模型中包括死亡率来预测选民的摇摆,可能是这项研究有效性的下一步。

引文

  1. http://wws . Princeton . edu/faculty-research/research/item/rising-发病率和死亡率-白人-非西班牙裔中年人
  2. https://wonder.cdc.gov/mortsql.html
  3. https://www.cdc.gov/nchs/data_access/VitalStatsOnline.html
  4. https://www.cdc.gov/nchs/nvss/mortality_public_use_data.htm
  5. https://github . com/tonmcg/County _ Level _ Election _ Results _ 12-16
  6. https://Simon Rogers . net/2016/11/16/us-election-2016-how-to-download-county-level-results-data/
  7. http://www . NBER . org/data/vital-statistics-death-data-multiple-cause-of-death . html
  8. http://data.library.virginia.edu/is-r-squared-useless/

使用 Neo4j 进行链接预测第 2 部分:使用 scikit-learn 预测合著者

原文:https://towardsdatascience.com/link-prediction-with-neo4j-part-2-predicting-co-authors-using-scikit-learn-78b42356b44c?source=collection_archive---------5-----------------------

这是最近添加到 Neo4j 图形算法库的链接预测函数系列文章的第二篇。

Link Predictions in the Neo4j Graph Algorithms Library

在第一篇帖子中,我们学习了链接预测度量,如何在 Neo4j 中应用它们,以及如何在机器学习分类器中用作特征。我们还了解了在处理图形时拆分训练和测试数据集的挑战。

在本帖中,我们将应用我们在引用数据集中学到的东西。我们将使用 scikit-learn 和链接预测算法来预测未来的合作关系

Amy Hodler 和我在上周的 Neo4j 在线会议上展示了如何应用本文中描述的方法,所以你也可以观看视频。

Link Prediction Online Meetup

如果你还在等待书面版本,那就让我们开始吧!

导入引用数据集

我们将使用来自 DBLP 引文网络的数据,其中包括来自各种学术来源的引文数据。我写了一篇博文解释了如何导入完整的数据集,但是在这篇博文中,我们将关注来自一些软件开发会议的数据。

Citation Networks

我们可以通过运行以下 Cypher 语句来导入该数据子集。只要在 Neo4j 浏览器中启用了多语句编辑器,就可以一次性运行所有语句:

// Create constraints
CREATE CONSTRAINT ON (a:Article) ASSERT a.index IS UNIQUE;
CREATE CONSTRAINT ON (a:Author) ASSERT a.name IS UNIQUE;
CREATE CONSTRAINT ON (v:Venue) ASSERT v.name IS UNIQUE;// Import data from JSON files using the APOC library
CALL apoc.periodic.iterate('UNWIND ["dblp-ref-0.json", "dblp-ref-1.json", "dblp-ref-2.json", "dblp-ref-3.json"] AS fileCALL apoc.load.json("[https://github.com/mneedham/link-prediction/raw/master/data/](https://github.com/mneedham/link-prediction/raw/master/data/)" + file)YIELD value WITH valueRETURN value','MERGE (a:Article {index:value.id})SET a += apoc.map.clean(value,["id","authors","references", "venue"],[0])WITH a, value.authors as authors, value.references AS citations, value.venue AS venueMERGE (v:Venue {name: venue})MERGE (a)-[:VENUE]->(v)FOREACH(author in authors | MERGE (b:Author{name:author})MERGE (a)-[:AUTHOR]->(b))FOREACH(citation in citations | MERGE (cited:Article {index:citation})MERGE (a)-[:CITED]->(cited))', {batchSize: 1000, iterateList: true});

下图显示了数据导入 Neo4j 后的样子:

Diagram showing Citation Network in Neo4j

构建合著者图表

数据集不包含描述他们合作的作者之间的关系,但我们可以根据找到的多人撰写的文章来推断它们。

下面的 Cypher 语句在至少合作过一篇文章的作者之间创建了一个CO_AUTHOR关系:

MATCH (a1)<-[:AUTHOR]-(paper)-[:AUTHOR]->(a2:Author)
WITH a1, a2, paper
ORDER BY a1, paper.year
WITH a1, a2, collect(paper)[0].year AS year, count(*) AS collaborations
MERGE (a1)-[coauthor:CO_AUTHOR {year: year}]-(a2)
SET coauthor.collaborations = collaborations;

我们在已经合作的作者之间只创建一个关系,即使他们已经合作了多篇文章。我们在这些关系上创建了几个属性:

  • 一个year属性,表示作者合作的第一篇文章的出版年份
  • 一个collaborations属性,指示作者合作了多少篇文章

Diagram showing co-authorsin Neo4j

现在我们已经有了合著者图表,我们需要弄清楚如何预测作者之间未来的合作。

为此,我们将构建一个二元分类器,因此我们的下一步是创建训练和测试图。

训练和测试数据集

正如在第一篇文章中提到的,我们不能随意将数据分成训练和测试数据集,因为这可能导致数据泄漏。

当您的训练数据之外的数据被无意中用于创建您的模型时,可能会发生数据泄漏。这在处理图形时很容易发生,因为我们的训练集中的节点对可能连接到测试集中的节点对。

相反,我们需要将我们的图分成训练和测试子图,幸运的是,我们的引用图包含我们可以分割的时间信息。我们将通过拆分特定年份的数据来创建训练和测试图。

但是我们应该在哪一年分手呢?我们来看看合著者合作的第一年的分布情况:

Chart showing distribution of year of collaboration

看起来 2006 年是拆分数据的好年份,因为它将为我们的每个子图提供合理数量的数据。我们将把 2005 年及更早的所有合作者作为我们的训练图,而从 2006 年开始的所有合作者作为测试图。

让我们基于该年在图表中创建明确的CO_AUTHOR_EARLYCO_AUTHOR_LATE关系。以下代码将为我们创建这些关系:

列车子图

MATCH (a)-[r:CO_AUTHOR]->(b) 
WHERE r.year < 2006
MERGE (a)-[:CO_AUTHOR_EARLY {year: r.year}]-(b);

测试子图

MATCH (a)-[r:CO_AUTHOR]->(b) 
WHERE r.year >= 2006
MERGE (a)-[:CO_AUTHOR_LATE {year: r.year}]-(b);

这种分裂在早期图表中留给我们 81,096 个关系,在后期图表中留给我们 74,128 个关系。这是 52 比 48 的比例。这比我们通常在测试图中看到的数值百分比要高,但是应该没问题。

这些子图中的关系将作为我们训练和测试集中的正例,但是我们也需要一些反例。需要反面的例子,这样我们的模型就可以学习区分应该有链接的节点和不应该有链接的节点。

正如在链接预测问题中经常出现的情况一样,负面例子比正面例子多得多。反例的最大数量等于:

# negative examples = (# nodes)² - (# relationships) - (# nodes)

即节点数的平方,减去图中的关系,减去自身关系。

我们不是使用几乎所有可能的节点对,而是使用彼此相距 2 到 3 跳的节点对。这将为我们提供更多可管理的数据。

我们可以通过运行以下查询来生成这些对:

MATCH (author:Author)
WHERE (author)-[:CO_AUTHOR_EARLY]-()
MATCH (author)-[:CO_AUTHOR_EARLY*2..3]-(other)
WHERE not((author)-[:CO_AUTHOR_EARLY]-(other))
RETURN id(author) AS node1, id(other) AS node2

这个查询返回了 4389478 个负面例子,而 81096 个正面例子,这意味着我们有 54 倍于的负面例子。

Imbalanced data

因此,我们仍然有很大的类别不平衡,这意味着预测每对节点都不会有链接的模型将非常准确。

为了解决这个问题,我们可以对正样本进行上采样,或者对负样本进行下采样。我们将采用下采样方法。

py2neo,熊猫,scikit-学习

在这篇文章的剩余部分,我们将用 Python 处理 py2neo 、 pandas 和 scikit-learn 库。

py2neo 驱动程序使数据科学家能够轻松地将 Neo4j 与 Python 数据科学生态系统中的工具集成。我们将使用这个库对 Neo4j 执行 Cypher 查询。

pandas 是一个开源的、BSD 许可的库,为 Python 编程语言提供了高性能、易于使用的数据结构和数据分析工具

scikit-learn 是一个流行的机器学习库。我们将使用这个库来构建我们的机器学习模型。

我们可以从 PyPi 安装这些库:

pip install py2neo==4.1.3 pandas sklearn

一旦我们安装了这些库,我们将导入所需的包,并创建一个数据库连接:

from py2neo import Graph
import pandas as pdgraph = Graph("bolt://localhost", auth=("neo4j", "neo4jPassword"))

构建我们的训练和测试集

我们现在可以编写以下代码来创建一个包含基于早期图的正面和反面例子的测试数据帧:

# Find positive examples
train_existing_links = graph.run("""
MATCH (author:Author)-[:CO_AUTHOR_EARLY]->(other:Author)
RETURN id(author) AS node1, id(other) AS node2, 1 AS label
""").to_data_frame()# Find negative examples
train_missing_links = graph.run("""
MATCH (author:Author)
WHERE (author)-[:CO_AUTHOR_EARLY]-()
MATCH (author)-[:CO_AUTHOR_EARLY*2..3]-(other)
WHERE not((author)-[:CO_AUTHOR_EARLY]-(other))
RETURN id(author) AS node1, id(other) AS node2, 0 AS label
""").to_data_frame()# Remove duplicates
train_missing_links = train_missing_links.drop_duplicates()# Down sample negative examples
train_missing_links = train_missing_links.sample(n=len(train_existing_links))# Create DataFrame from positive and negative examples
training_df = train_missing_links.append(train_existing_links, ignore_index=True)
training_df['label'] = training_df['label'].astype('category')

Sample of the training DataFrame

现在我们将做同样的事情来创建一个测试数据帧,但是这次我们只考虑后期图中的关系:

# Find positive examples
test_existing_links = graph.run("""
MATCH (author:Author)-[:CO_AUTHOR_LATE]->(other:Author)
RETURN id(author) AS node1, id(other) AS node2, 1 AS label
""").to_data_frame()# Find negative examples
test_missing_links = graph.run("""
MATCH (author:Author)
WHERE (author)-[:CO_AUTHOR_LATE]-()
MATCH (author)-[:CO_AUTHOR_LATE*2..3]-(other)
WHERE not((author)-[:CO_AUTHOR_LATE]-(other))
RETURN id(author) AS node1, id(other) AS node2, 0 AS label
""").to_data_frame()# Remove duplicates 
test_missing_links = test_missing_links.drop_duplicates()# Down sample negative examples
test_missing_links = test_missing_links.sample(n=len(test_existing_links))# Create DataFrame from positive and negative examples
test_df = test_missing_links.append(test_existing_links, ignore_index=True)
test_df['label'] = test_df['label'].astype('category')

现在是时候创建我们的机器学习模型了。

选择机器学习算法

我们将创建一个随机森林分类器。这种方法非常适合,因为我们的数据集将由强特征和弱特征混合组成。虽然弱特征有时会有所帮助,但随机森林方法将确保我们不会创建过度适合我们的训练数据的模型。

我们可以用下面的代码创建这个模型:

from sklearn.ensemble import RandomForestClassifierclassifier = RandomForestClassifier(n_estimators=30, max_depth=10, random_state=0)

现在是时候设计一些特征来训练我们的模型了。

特征提取是一种从大量数据和属性中提取出一组有代表性的数值,即特征的方法。然后将其用作输入数据,这样我们就可以区分学习任务的类别/值。

请记住,如果您想在这篇文章的下一部分试用代码示例,您需要确保您已经按照本系列文章的第篇文章中所述设置了 Neo4j 开发环境。

生成链接预测要素

我们将首先使用链接预测函数创建一些要素

def apply_graphy_features(data, rel_type):query = """UNWIND $pairs AS pairMATCH (p1) WHERE id(p1) = pair.node1MATCH (p2) WHERE id(p2) = pair.node2RETURN pair.node1 AS node1,pair.node2 AS node2,algo.linkprediction.commonNeighbors(p1, p2, {relationshipQuery: $relType}) AS cn,algo.linkprediction.preferentialAttachment(p1, p2, {relationshipQuery: $relType}) AS pa,algo.linkprediction.totalNeighbors(p1, p2, {relationshipQuery: $relType}) AS tn"""pairs = [{"node1": pair[0], "node2": pair[1]}  for pair in data[["node1", "node2"]].values.tolist()]params = {"pairs": pairs, "relType": rel_type}features = graph.run(query, params).to_data_frame()return pd.merge(data, features, on = ["node1", "node2"])

此函数执行一个查询,该查询从提供的数据帧中提取每对节点,并计算:

  • 共同邻居(cn)
  • 优先附件(pa),以及
  • 邻居总数(tn)

对于每一对。这些措施在第一篇文章中被定义为。

我们可以将它应用到我们的训练和测试数据帧中,如下所示:

training_df = apply_graphy_features(training_df, "CO_AUTHOR_EARLY")
test_df = apply_graphy_features(test_df, "CO_AUTHOR")

对于训练数据帧,我们仅基于早期的图表计算这些指标,而对于测试数据帧,我们将跨整个图表计算它们。

我们仍然可以使用整个图表来计算这些特征,因为图表的演变取决于它在整个时间内的样子,而不仅仅是基于 2006 年及以后发生的事情。

Sample of the training DataFrame

现在我们准备训练我们的模型。我们可以用下面的代码做到这一点:

columns = ["cn", "pa", "tn"]X = training_df[columns]
y = training_df["label"]
classifier.fit(X, y)

我们的模型现在已经训练好了,但是我们需要评估它。

评估我们的模型

我们要计算它的准确度、精确度和召回率。下图摘自奥莱利图算法书,解释了这些指标是如何计算的。

Accuracy measures

scikit-learn 内置了我们可以用于此的函数。我们还可以返回模型中使用的每个特性的重要性。

以下函数将对此有所帮助:

from sklearn.metrics import recall_score
from sklearn.metrics import precision_score
from sklearn.metrics import accuracy_scoredef evaluate_model(predictions, actual):accuracy = accuracy_score(actual, predictions)precision = precision_score(actual, predictions)recall = recall_score(actual, predictions)metrics = ["accuracy", "precision", "recall"]values = [accuracy, precision, recall]    return pd.DataFrame(data={'metric': metrics, 'value': values})def feature_importance(columns, classifier):        features = list(zip(columns, classifier.feature_importances_))sorted_features = sorted(features, key = lambda x: x[1]*-1)keys = [value[0] for value in sorted_features]values = [value[1] for value in sorted_features]return pd.DataFrame(data={'feature': keys, 'value': values})

我们可以通过运行以下代码来评估我们的模型:

predictions = classifier.predict(test_df[columns])
y_test = test_df["label"]evaluate_model(predictions, y_test)

Accuracy, Precision, Recall

我们在各方面都有很高的分数。现在,我们可以运行以下代码来查看哪个功能发挥了最重要的作用:

feature_importance(columns, classifier)

Feature Importance

我们可以在上面看到,公共邻居(cn)是我们模型中的主要特征。Common neighbors 向我们返回了一个作者拥有的未闭合合著三角形的数量,因此这可能并不令人惊讶。

现在,我们将添加一些由图形算法生成的新功能。

三角形和聚集系数

我们将从在测试和训练子图上运行三角形计数算法开始。该算法返回每个节点形成的三角形数量,以及每个节点的聚类系数。节点的聚类系数表示其邻居也是相连的可能性。

我们可以在 Neo4j 浏览器中运行以下 Cypher 查询,以在我们的列车图上运行该算法:

CALL algo.triangleCount('Author', 'CO_AUTHOR_EARLY', { write:true,writeProperty:'trianglesTrain', clusteringCoefficientProperty:'coefficientTrain'});

和下面的 Cypher 查询来在测试图上运行它:

CALL algo.triangleCount('Author', 'CO_AUTHOR', { write:true,writeProperty:'trianglesTest', clusteringCoefficientProperty:'coefficientTest'});

我们现在在节点上有 4 个新属性: trianglesTrain系数 TraintrianglesTest系数 Test 。现在,让我们在以下函数的帮助下,将这些添加到我们的训练和测试数据帧中:

def apply_triangles_features(data,triangles_prop,coefficient_prop):query = """UNWIND $pairs AS pairMATCH (p1) WHERE id(p1) = pair.node1MATCH (p2) WHERE id(p2) = pair.node2RETURN pair.node1 AS node1,pair.node2 AS node2,apoc.coll.min([p1[$triangles], p2[$triangles]]) AS minTriangles,apoc.coll.max([p1[$triangles], p2[$triangles]]) AS maxTriangles,apoc.coll.min([p1[$coefficient], p2[$coefficient]]) AS minCoeff,apoc.coll.max([p1[$coefficient], p2[$coefficient]]) AS maxCoeff"""pairs = [{"node1": pair[0], "node2": pair[1]}  for pair in data[["node1", "node2"]].values.tolist()] params = {"pairs": pairs,"triangles": triangles_prop,"coefficient": coefficient_prop}features = graph.run(query, params).to_data_frame()return pd.merge(data, features, on = ["node1", "node2"])

这些度量与我们迄今为止使用的不同,因为它们不是基于节点对计算的,而是特定于节点的度量。

我们不能简单地将这些值作为 node1Trianglesnode1Coeff 添加到我们的数据帧中,因为我们不能保证节点对中节点的顺序。我们需要想出一个不可知论的方法

我们可以通过取值的平均值、值的乘积,或者通过计算最小值和最大值来实现这一点,就像我们在这里所做的那样。

我们可以将该函数应用于数据帧,如下所示:

training_df = apply_triangles_features(training_df, "trianglesTrain", "coefficientTrain")
test_df = apply_triangles_features(test_df, "trianglesTest", "coefficientTest")

现在我们可以训练和评估:

columns = ["cn", "pa", "tn", "minTriangles", "maxTriangles", "minCoeff", "maxCoeff"
]X = training_df[columns]
y = training_df["label"]
classifier.fit(X, y)predictions = classifier.predict(test_df[columns])
y_test = test_df["label"]display(evaluate_model(predictions, y_test))

Accuracy, Precision, Recall

这些功能非常有用!我们的每项指标都比最初的模型提高了大约 4%。哪些功能最重要?

display(feature_importance(columns, classifier))

Feature Importance

公共邻域仍然是最有影响力的,但三角形功能也增加了一些价值。

概括起来

这篇文章已经比我预期的时间长了很多,所以我们就到此为止,但是肯定还有一些练习留给读者。

工程更多功能

你能想到我们可以添加的任何其他功能来帮助我们创建一个更高精度的模型吗?也许其他社区检测,甚至中心算法可能会有所帮助?

扩展对链接预测的支持

目前,图算法库中的链接预测算法仅适用于单部图。单部图是指两个节点的标号相同的图。这些算法基于节点的拓扑结构,如果我们试图将它们应用于具有不同标签的节点,这些节点将可能具有不同的拓扑结构,这意味着这些算法不会工作得很好。

我们正在考虑添加适用于其他图形的链接预测算法版本。如果你有什么特别想看的,请在 GitHub 问题上告诉我们。

接下来呢?

如果你觉得这篇博文很有趣,你可能会喜欢我和艾米·霍德勒在过去 9 个月里写的《奥莱利图算法》一书。我们正处于最后的审查阶段,它应该在未来几周内可用。

您可以注册从 Neo4j 网站获得免费的电子版,网址:neo4j.com/graph-algorithms-book

威尔·里昂和我还在与 Neo4j 一起开发一个新的关于数据科学的在线培训课程,请关注在线培训页面,了解详细信息。

使用 MQTT 将 Python 应用程序与您的 Android 设备链接起来

原文:https://towardsdatascience.com/link-python-applications-with-your-android-device-using-mqtt-c8e2c80f6a61?source=collection_archive---------18-----------------------

跨平台通信和 MQTT 协议

在计算机科学中,两个不同系统之间的数据共享或通信是很常见的事情。开发系统时,可以设计两个同构系统之间的通信。此外,完全不同的系统可能也需要共享信息。例如,一个由 Arduino 平台驱动的简单传感器可能需要向运行 Android 或苹果 iOS 的智能手机发送信息。为了实现跨平台通信,可以声明和使用一组通用的通信规则。这样的规则集被称为通信协议。在这篇文章中,让我们来看看一个简单的跨平台通信协议;MQTT。

MQTT 代表 MQ 遥测传输。它是一个简单的消息协议,是为低带宽设备设计的。本质上,MQTT 被设计成一个物联网消息传递协议。如果你有兴趣了解更多关于 MQTT 的信息,请随时访问他们的官方网站和 FAQ 页面。

可用的 MQTT 服务

正如开头提到的,MQTT 是一种通信协议。MQTT 协议由几个服务提供者作为服务来实现和提供。有免费的、付费的和有限的 MQTT 服务提供者。访问这个 DIY 项目页面,看看一些 MQTT 服务的本质。

在本文中,我们将使用一个名为 CloudMQTT 的 MQTT 服务提供者。CloudMQTT 中有不同的付费计划和一个免费计划。免费计划是一项非常受限制的服务。不过出于教育和兴趣目的,还是用 CloudMQTT 的免费计划‘可爱的猫’吧。

在 CloudMQTT 设置免费数据通道

首先,进入https://www.cloudmqtt.com/并登录。您可以使用您的 google 帐户或 GitHub 帐户进行身份验证。然后,您必须创建一个新的实例。实例是托管在云上的消息代理对象。

提供实例的名称。添加一些标签。现在,选择免费的“可爱的猫”计划。

选择数据中心。请注意,您可能需要更改数据中心,并检查它是否正常工作。这是地区原因。根据您所在的区域,您将拥有一个正常工作的数据中心。

选择数据中心后,将创建您的实例。将会看到以下用户界面。在那里,您可以访问实例、设置、web-socket UI、活动连接和一些其他功能和信息的一般详细信息。

web-socket UI 选项卡使您能够发送和接收关于主题的消息。主题是实例内部的消息传递通道。一个实例中可以有多个主题。注意,为了在 web-socket UI 上发送关于特定主题的消息,您不必预先创建主题。只需将主题和消息指定为字符串并发送。该消息将被接收并显示在已接收消息表中。下图显示了在“测试/测试”主题上发送字符串“这是一条消息”后的结果。

创建 Android 应用程序

让我们讨论一下在云上创建的 MQTT 实例如何服务于我们的跨平台通信需求。为了演示,让我们创建一个 Android 应用程序,它通过 CloudMQTT 实例与一个简单的 python 程序通信。

在本帖中,我们将使用 Android Studio 。Gradle 将被用作构建工具。

在 Android studio 中创建新的 Android 项目。然后将下面的依赖项添加到build.gradle(项目)文件中。该依赖项将添加一个 MQTT 客户端产品,它能够处理 MQTT 消息传递,同时您可以专注于您的应用程序及其业务模型。

repositories {maven {url "https://repo.eclipse.org/content/repositories/paho-snapshots/"}
}

另外,将以下依赖项添加到build.gradle (App)文件中。

dependencies {compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'compile 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
}

执行 Gradle Sync,您就可以在您的 android 项目中使用 MQTT 客户端了。

你的应用需要以下权限。您可以通过向AndroidManifest.xml文件添加以下权限来提供权限。确保在application标签开始之前添加以下代码行(在application标签之外)。

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>

另外,注册由导入的 MQTT 客户机提供的 MQTT 服务。在关闭application标签之前添加下面一行代码(在application标签内)。

<service android:name="org.eclipse.paho.android.service.MqttService" />

现在我们已经准备好编写代码来连接 MQTT 实例。让我们通过创建下面的MQTTHelper.java类来简化我们的生活。注意,我已经将这个类包含在包helpers中,你可以根据需要在另一个包中创建你的MQTTHelper类。

重要提示:将端口11111更改为实例详细信息中指定的端口号。此外,相应地更改用户名和密码。您可以设置任何客户端 ID 和主题。

题目已经定为sensor/+。这表示任何名称为“sensor/”后跟任何字符串的主题正在被监听。比如sensor/temperaturesensor/humidity、……..所有的都被监听了。

在您的一个活动中创建一个TextView元素。我在我的MainActivity中创建了dataReceived元素。那么活动:MainActivity的 java 代码如下。

每当一条消息到达指定的主题时,就会显示在指定的TextView元素上。让我们快速测试一下。转到 web-socket UI,在sensor/<something>下发送任何消息。你应该可以在手机应用程序上看到你刚刚发送的消息。请注意,您必须将消息发送到您的移动应用程序设置为要收听的主题之一。在这篇文章中,是以sensor/开头的任何话题。web-socket UI 将如下所示。

您可以通过访问 Connections UI 来验证您与 MQTT 实例的连接。下图显示了 MQTT 与移动应用程序的连接。

写一个简单的 Python 程序

现在,您的移动应用程序上有了一个工作的 MQTT 客户机,您希望监听由另一个平台发送的消息。在这篇文章中,让我们用一个简单的 python 程序来连接移动应用程序。即使我们说 python 程序要与移动应用程序对话,它也不是直接通信。消息将通过 CloudMQTT 消息代理发送。整体架构如下。

在编写我们的 python 程序之前,我们必须用 python 安装 paho MQTT 客户端库。注意,移动应用程序中使用了相同的 MQTT 客户端。使用 pip 安装相应的库。

pip install paho-mqtt

python 程序非常简单。我就把代码留在下面吧。

import paho.mqtt.client as mqttmqttc = mqtt.Client("client1", clean_session=False)
mqttc.username_pw_set("#User", "#password")
mqttc.connect("#Server", #port, 60)# Set a stopping condition or just press ctrl+C to quit.
while(True):inp = input()mqttc.publish("sensor/temp", payload=inp, qos=0)

确保在 python 脚本中指定所有 MQTT 实例细节。此外,可以在 python 程序中的任何地方随意使用这个简单的 MQTT 客户机publish方法调用。请注意,您发布的消息将在 web-socket UI 和移动应用程序上可见。

我还能连接什么?

消息代理并不局限于 Python 和 Android 之间。您可以用几个可用的 MQTT 客户端库连接其他平台。在文档中,点击您平台上偏好的语言,找到最合适最稳定的客户端。目前有 Ruby,Python,Node.js,Java,Go,。NET,NodeMCU 和 PHP 客户端正式可用。做一点研究,你可能会找到其他语言的客户。

希望你喜欢并利用了这篇文章。android 应用程序的代码可以在这个 GitHub 仓库中找到。

链表实现指南

原文:https://towardsdatascience.com/linked-list-implementation-guide-16ed67be18e4?source=collection_archive---------24-----------------------

介绍

在本指南中,我将解释如何实现一个链表。如果你不知道什么是链表,我推荐你阅读我的另一个博客,在这里找到,在那里我详细解释了什么是链表以及它是如何工作的。对于这个博客,我将重点讨论实现。

实施指南

下图演示了链表的实现。虽然该演示是用 C 语言编写的,但是所示的过程和步骤适用于使用任何编程语言实现链表。

必需的库和结构定义

下面的图 1 包括所需的库,定义了在整个演示过程中常用的两个函数,并详细说明了节点和链表的结构。节点被定义为包含一个整数(数据)和一个指向下一个节点的指针。同样,一个列表包含一个表示列表大小的整数和一个指向列表中第一个节点的指针(head)。函数 initList 将头指针初始化为空,并将列表的大小初始化为零,因为最初列表中没有节点。函数 isEmpty 确定一个列表是否为空。

Figure 1: Require libraries and structure/function definitions

将节点添加到列表中

insertFront 函数接受两个参数:一个链表和一个要插入到列表中的值。图 2 中的第 30 行为一个节点分配内存,并初始化一个指针指向分配的空间。如果成功分配了内存,该函数会将列表的大小增加 1,并在将新节点插入列表之前确定列表是否为空。如果列表为空,列表的头指针指向新节点,新节点的下一个指针指向 null。否则,新节点的 next 指针指向链表头所指向的节点,然后链表头指针更新指向新节点。

Figure 2: Function to insert node to the front of a linked list

将节点追加到列表

函数接受两个参数:一个链表和一个插入到列表末尾的值。图 3 中的第 49 行为一个节点分配内存,并初始化一个指针指向分配的空间。如果成功分配了内存,该函数会将列表的大小增加 1,并在将新节点插入列表之前确定列表是否为空。如果列表为空,则通过更新列表的头指针指向新节点,将新节点插入到列表中。否则,初始化指针以遍历列表。指针遍历列表,直到指向最后一个节点。一旦找到最后一个节点,该节点的 next 指针就会更新,指向新节点。

Figure 3: Function to insert node to the end of a linked list

从列表前面删除节点

函数 deleteFront 接受一个参数:一个链表。该函数首先确定列表是否为空。如果列表不为空,那么函数初始化一个指针指向列表中的第一个节点。然后更新列表的头指针,指向列表中的下一个节点,如果列表中没有其他节点,则为 null。然后,使用之前初始化的指针从内存中移除第一个节点。最后,列表的大小减一。

Figure 4: Function to remove first node from linked list

从列表末尾删除节点

deleteEnd 函数接受一个参数:一个链表。该函数首先确定列表是否为空。如果不为空,则初始化两个指针。一个指针(currentNode)指向第一个节点,而另一个指针(nextNode)指向下一个节点,或者如果列表中只有一个节点,则为 null。nextNode 指针用于遍历链表,直到指向最后一个节点,currentNode 指针指向倒数第二个节点。然后,currentNode 的 next 指针被更新为 null,nextNode 的指针用于从内存中删除最后一个节点。最后,列表的大小减一。

Figure 5: Function to remove last node from linked list

在所需位置插入节点的函数

insertNodeAtLocation 函数接受三个参数:一个链表、一个位置和值。该函数的目的是在所需位置插入一个节点。例如,如果所需位置是 3,数据值是 5(insertNodeAtLocation(list,3,5)),那么函数将创建一个数据值为 5 的节点,并将创建的节点作为列表中的第三个节点。为了满足函数的要求,第一步是通过检查输入位置的值是否等于或大于 1 但小于列表大小加 1 来确定输入位置是否有效。如果位置有效,该函数将检查所需位置的值是否为 1,然后调用图 2 所示的 insertFront 函数。否则,列表的大小增加 1,创建一个计数器来跟踪列表中的当前位置,为新节点分配内存,并初始化一个指针以遍历列表。一旦指针指向其位置正好在期望位置之前的节点(节点 A ),新节点的 next 指针被更新以指向当前跟随节点 A 的节点。然后,节点 A 的 next 指针被更新以指向新节点。

Figure 6: Function to insert a node at a desired location in the linked list

用于删除具有指定值的节点的函数

函数接受两个参数:一个列表和一个值。该函数首先确定列表是否为空。如果不为空,该函数将初始化两个指针(currentNode 和 prevNode)。最初,currentNode 指向列表的头部,而 prevNode 指向 null。然后 removeNode 函数检查当前节点的数据是否等于输入值。如果它们相等,则调用图 4 所示的 deleteFront 函数。否则,prevNode 指针更新为指向 currentNode,currentNode 更新为指向下一个节点。然后,指针遍历列表,直到 currentNode 等于 null。如果在迭代 currentNode 的数据的任何一点等于输入的值,列表的大小减少一,prevNode 的下一个指针更新为指向 currentNode 后面的节点,currentNode 用于在函数终止之前从内存中删除已删除的节点。如果输入的值在列表中找不到,该函数会向控制台输出“列表中找不到值”。

Figure 7: Function to remove first node in list containing specified value

打印链接列表

函数接受一个参数:一个链表。该函数首先初始化一个指针,该指针将用于遍历列表。如果列表为空,函数将向控制台输出“列表为空”。否则,这些函数输出列表中的节点数,以及列表中每个节点的数据值。

Figure 8: Function to print the value of each node in the list

主要功能

**主函数是执行 C 程序时运行的函数。如图 9 所示,使用上面定义的函数初始化链表,并从列表中插入/删除节点。

Figure 9: The main function

执行时,main 函数输出如下内容。

Figure 10: The output from the main function

结论

总之,链表是一种非常酷的结构化数据的方式。如前所述,如果你想了解链表如何工作或何时使用它们,请查看我的另一个博客这里

链表与数组

原文:https://towardsdatascience.com/linked-lists-vs-arrays-78746f983267?source=collection_archive---------5-----------------------

介绍

有许多不同类型的数据结构可以在计算机程序中实现,例如数组和链表。每种类型的数据结构都有其优点和缺点。由于这些原因,在设计、优化和扩展程序时,理解不同类型的数据结构的优缺点是很重要的。

数组

让我们从定义一个数组开始。简而言之,数组本质上是一种数据结构,类似于相同数据类型的值列表。数组的另一个特性是数组元素存储在连续的内存位置。此外,数组具有固定的大小,这是在初始化时定义的。根据这些属性,您能看出数组的优点和缺点吗?

阵列的优势

搜索时间:

如前所述,数组将元素存储在连续的内存位置。这意味着可以通过向数组的基值或第一个元素的位置添加偏移量来访问任何元素。下面的数字更详细地说明了我的意思。

Figure 1: Demo program to illustrate consecutive memory locations

Figure 2: Output of program in Figure 1

虽然图 2 中的内存地址看起来相隔四个,但实际上它们是连续的。这意味着,只要通过向第一个元素的地址添加偏移量来知道元素的索引,就可以定位数组中的任何元素。由于搜索数组中的第二个或最后一个元素没有时间差,所以数组具有恒定的搜索次数或大 O(O(1)),这非常快。基本上,最好的运行时间复杂度是 O(1)。

数组的缺点

浪费的内存:

数组的缺点之一是内存可能会被浪费。为了解释这一点,我将描述一个场景。作为一名程序员,你并不总是知道分配多少内存。例如,您正在构建一个应用程序,它将要求用户输入内容,然后将这些内容存储在一个数组中。因为您不知道用户将输入多少,所以您用一百万个索引初始化一个数组,因为您认为一百万个输入对任何用户来说都足够了。如果用户只向数组中输入十万个元素会怎样?然后,90%的分配空间被浪费。

缓慢的插入/删除时间:

数组的插入和删除时间很慢。让我们从关注插入开始。要将元素插入到数组的前面或中间,第一步是确保数组中有空间容纳新元素,否则需要调整数组的大小。下一步是通过将每个元素移动到所需的索引之后来为新元素留出空间。同样,对于删除,在删除一个元素后需要进行移位。这意味着数组的插入时间是 n 的大 O(O(n)),因为 n 个元素必须移位。然而,从数组末尾插入和删除是 O(1)。

链接列表

链表是收集类似数据的另一种方法。然而,与数组不同,链表中的元素不在连续的内存位置。链表由使用指针相互连接的节点组成。下面的图 3 展示了一个链表。

Figure 3: Diagram of singly linked list structure

如图 3 所示,单链表由一个头和一组节点组成。请注意,有许多类型的链表,如单向链表和双向链表,但现在我们将集中讨论单向链表。为了解释单链表是如何工作的,我必须首先定义一个指针。指针是保存另一个变量或结构地址的变量。在图 3 中,head 是一个指针,它包含链表上第一个节点的地址。head 变量允许计算机定位内存中的第一个节点并访问其数据。一旦定位了起始位置(第一个节点),就很容易遍历链表,因为每个节点都包含一个指向下一个节点的指针。

链表的优点

更好地利用内存:

从内存分配的角度来看,链表比数组更有效。与数组不同,链表的大小不是预先定义的,允许链表在程序运行时增加或减少大小。这是可能的,因为要插入或删除链表,指针需要相应地更新。

通常,在链表中插入一个节点需要在新节点初始化后更新指针。图 4-6 描述了如何在链表的开头、中间或结尾插入节点。

Figure 4: Diagram of inserting a node to the beginning of a linked list

Figure 5: Diagram of inserting a node in the middle of a linked list

Figure 6: Diagram of appending a node to a linked list

从链表中删除比插入更容易。唯一的步骤是更新指针。图 7-9 展示了删除链表开头、中间或结尾节点的过程。

Figure 7: Diagram of deleting first node from linked list

Figure 8: Diagram of deleting node from the middle of linked list

Figure 9: Diagram of deleting last node from linked list

如上图所示,在链表中插入和删除非常简单。此外,链表结构防止了内存浪费,因为节点是在初始化时插入到链表中的。

快速插入/删除时间:

如图 4 所示,在链表的开头或结尾插入一个新节点需要花费恒定的时间(O(1)),因为唯一的步骤是初始化一个新节点,然后更新指针。同样,如果有一个尾指针(类似于头指针),插入到链表的末尾也将是 O(1)。然而,插入到链表的中间需要线性时间(O(n)),因为在插入节点之前需要迭代 n 个元素才能到达正确的位置。类似地,删除链表开头和结尾的节点需要恒定的时间,而删除链表中间的节点需要线性时间。

链表的缺点

较慢的搜索时间:

链表的搜索时间比数组慢,因为不允许随机访问。与可以通过索引搜索元素的数组不同,链表需要迭代。这意味着,如果您想要获得第十个节点上的数据,可以使用 head 指针来获得第一个节点,可以使用第一个节点上的指针来获得第二个节点,依此类推,直到到达第十个节点。这意味着在搜索一个节点时必须迭代的节点越多,搜索时间就越长。这意味着链表的搜索时间是线性时间或 n 的大 O(O(n))。

结论

总之,有许多不同的数据结构。每种数据结构都有优缺点,根据任务的不同会影响性能。今天,我们探讨了两种数据结构:数组和链表。数组允许随机访问,每个元素需要的内存较少(不需要指针空间),但插入/删除操作和内存分配效率较低。相反,链表是动态的,具有更快的插入/删除时间复杂度。然而,链表具有较慢的搜索时间,并且指针需要列表中每个元素的额外内存。下面的图 10 总结了数组和链表的优缺点。

如果你有兴趣学习如何实现链表,可以看看我的链表指南 这里

Figure 10: Summary of strengths and weaknesses of arrays and linked list

Linode 可能是最好的部署解决方案

原文:https://towardsdatascience.com/linode-might-be-the-best-deployment-solution-ad8991282c32?source=collection_archive---------29-----------------------

Christopher Aker 创建的虚拟私有服务器托管服务是我使用过的最强大、可扩展的远程在线托管解决方案之一。对于我们这些在地下室没有数据中心的人来说,Linode 是一种高可靠性和高速度的网络主机的理想方式。对于 Flask、Node、React、Django 后端来说,Linode 绝对是一个很棒的选择。

可攀登的

有了 Linode,你可以随时调整你的私人服务器的大小。从每月 10 美元开始,到 960 美元结束,Linode 的计算能力相当强大。

Linode 还允许您获得更多 RAM 或专用 CPU,以及专用显卡。GPU 通常是非常高端的 RTX6000 系列卡。由于一个计划中有多达四个选项,很容易理解为什么从 Linode 开始会容易得多。

多才多艺的

像任何虚拟私人服务器一样,Linode 的优势在于它是一台成熟的计算机,而不是像共享主机那样的东西,它给你一个存储位置和一些共享内存。许多共享选项也很难修改,有时还会受到限制。

使用 Linode,您可以获得自己的远程无头 Linux 机器的能力,它有自己的转发端口和 IP。不用说,这使得它更加通用。通常,虚拟专用服务器用于更好的服务器管理,以及为基于 web 的应用程序运行后端计算。

不使用“全栈”服务、API 和语言的 Web 开发工作正在慢慢淡出,静态网站正在成为过去,特别是对于数据驱动的应用程序。

图像管理

Linode 带来的一个同样令人兴奋的概念是简单管理。服务器非常容易从映像中立即重建。等待 5-10 分钟来安装你的 RedHat 新版本,然后你就可以开始运行了!

想换成 Debian 服务器?这很好,只需从列表中选择图像并将其写入服务器。我最近在我的一个笔记本上重写了我的有问题的红帽系统,并被它的简单所吸引。

专有技术

虽然 Linode 确实很棒,但它肯定不适合所有人。如果你不擅长 Bash,不知道如何使用 nano 和 nsgiw,我不建议你使用 Linode 而不是更简单的东西。

奖励:纳米节点

另一个有趣的概念是“纳米电极”一个 nanode 是一个完整的 Linode 的较小版本,资源最少,每月 5 美元。但是考虑到这一点,对于 web 请求,我认为 Nanodes 肯定非常适合管道部署!

只要你知道如何建立你的新网站,并拥有一些基本的开发操作技能,利用 Linode 肯定可以让你的钱包里有更多的钱,更多的计算可以远程进行。虽然 AWS 和 Google Cloud 是很好的计算平台,但是说实话,它们很贵。如果你正在寻找一台服务器来托管你的作品集,我当然会选择 Linode。

数据科学内容的主要来源列表

原文:https://towardsdatascience.com/list-of-the-top-sources-of-data-science-content-dc805902d543?source=collection_archive---------28-----------------------

我最喜欢的数据科学内容来源的非详尽列表,请欣赏!

在本文中,我将源代码分为三个“不同”的类别:

  • 播客
  • 博客
  • 通用

请享用。希望你觉得有用。确保 跟随我的简介 🔍如果你喜欢这篇文章,并想看到更多!

播客

在通勤或放松时,播客是了解数据科学相关新闻和突破的好方法。播客的范围从高度事实和教育到更放松和假设。

我会在每个条目前面加上所有者自己的“关于”段落。

数据帧— 由 DataCamp 提供

数据科学是发展最快的行业之一,被称为 21 世纪最性感的工作。但是数据科学到底是什么?在 DataCamp 的播客中,Hugo Bowne-Anderson 从数据科学试图解决什么问题而不是什么定义最适合它的角度来处理这个问题。从自动医疗诊断和自动驾驶汽车到推荐系统和气候变化,与行业和学术专家一起探索将影响 21 世纪的行业内部工作方式。

[## 播客|数据营

播客

Podcastwww.datacamp.com 数据营](https://www.datacamp.com/community/podcast)

不那么标准偏差——罗杰·彭&希拉里·帕克

不那么标准差:数据科学播客 Roger Peng 和 Hilary Parker 谈论学术界和工业界的数据科学和数据分析的最新进展。共同主持人:约翰霍普金斯大学彭博公共卫生学院的 Roger Peng 和 Stitch Fix 的 Hilary Parker。

[## 不那么标准偏差

不那么标准差:数据科学播客罗杰·彭和希拉里·帕克谈论数据科学的最新进展…

nssdeviations.com](http://nssdeviations.com/)

数据怀疑论者——凯尔·波利奇

数据怀疑论者制作了这个网站和两个播客。该节目由凯尔·波利奇主持。Linh Da Tran 共同主持我们的迷你剧集。

我们的主要产出是每周播客,其中包括解释数据科学高级概念的小短片,以及对研究人员和从业人员的较长采访片段。

奖金饲料是额外的和扩展的材料,如果你只是不能得到足够的数据怀疑论者。

[## 数据怀疑论者

数据怀疑论者是你对统计学、机器学习、大…

dataskeptic.com](https://dataskeptic.com/)

博客

和播客一样,有些博客纯粹是教育和辅导性质的,有些则更像轶事。所有这些都是强烈推荐的!

简单统计——拉法·伊里扎里、罗杰·彭&杰夫·莱克

关于这个博客:我们将发布我们感兴趣的想法,为科学/流行写作的讨论做出贡献,链接到激励我们的文章,并与未来的统计学家分享建议。

为什么是“简单统计”:我们需要一个标题。此外,我们喜欢用简单的统计数据来解决真正重要的问题。我们不喜欢不必要的复杂——那只会导致谎言,该死的谎言和其他东西。

[## 简单统计

编者按:有一段时间,我们对统计学家和数据科学家进行了一系列采访,但事情变得…

simplystatistics.org](https://simplystatistics.org/)

统计建模——安德鲁·盖尔曼

关于这一点,没有官方的介绍,但它来自哥伦比亚大学的教授安德鲁·盖尔曼。

[## 统计建模、因果推理和社会科学

有一天,有人向我推荐了詹姆斯·考夫曼和弗拉德·格列弗努在一本心理学杂志上发表的一篇文章…

statmodeling.stat.columbia.edu](https://statmodeling.stat.columbia.edu/)

R 博客作者——由多位作者撰写

R-Bloggers 是关于授权 blogger 去授权其他 R 用户。

它是一个博客聚合器,内容由写 R(英文)的博客作者提供。该网站帮助 R 博客作者和用户联系并关注“R 博客圈”(你可以观看 useR2011 的 7 分钟演讲,了解更多关于 R 博客圈的信息)。

[## r 博客

在数据中发现一个有趣的模式总是令人兴奋的,它似乎指向一些重要的差异或…

www.r-bloggers.com](https://www.r-bloggers.com/)

机器学习大师——杰森·布朗利

没有具体的关于这一页,但贾森布朗利是一个绝对的传奇。他每天都写作,并在他的博客上产生了大量高质量的内容。

[## 从机器学习开始

我最常被问到的问题是:“我该如何开始?”我对获得…的最佳建议

machinelearningmastery.com](https://machinelearningmastery.com/start-here/)

流动数据 —作者 Nathan Yau

FlowingData 探索统计学家、设计师、数据科学家和其他人如何使用分析、可视化和探索来理解数据和我们自己。

[## 流动数据

人数上的优势

flowingdata.com](https://flowingdata.com/)

可能想多了——艾伦·唐尼

艾伦·唐尼是奥林学院的教授,也是《思考巨蟒》(Think Python)和《思考贝叶斯》(Think Bayes)的作者,其他书籍可从绿茶出版社(T21)获得。

[## 可能想多了

艾伦·唐尼的博客

www.allendowney.com](https://www.allendowney.com/blog/)

直观解释—由 Setosa 提供

直观解释(EV)是一个让难以理解的想法变得直观的实验,Bret Victor 的探索性解释启发了他的工作。

[## 直观解释

直观解释(EV)是一项实验,旨在让难以理解的想法变得直观

setosa.io](http://setosa.io/ev/)

一般

这最后几个在这里只是因为他们并不真正适合其他类别,虽然没有很多!

看见理论 —丹尼尔·库宁

丹尼尔·库宁在布朗大学读本科时创立了视觉理论。该网站的目标是通过交互式可视化使统计数据更容易获取。

[## 视觉理论

概率和统计的直观介绍。

seeing-theory.brown.edu](https://seeing-theory.brown.edu/)

走向数据科学 —数据科学及更多内容的出版商

我认为这个问题不需要太多解释😉

[## 走向数据科学

分享概念、想法和代码。

towardsdatascience.com](https://towardsdatascience.com)

结束语

我希望这篇短文对你有所帮助!

如果你想看和了解更多,一定要关注我的 中的 🔍和 推特 🐦

[## 彼得·尼斯特鲁普-中等

阅读彼得·尼斯特拉普在媒介上的作品。数据科学、统计和人工智能...推特:@PeterNistrup,LinkedIn…

medium.com](https://medium.com/@peter.nistrup)

听听我们的叙述文章

原文:https://towardsdatascience.com/listen-to-our-narrated-articles-779e436b4491?source=collection_archive---------31-----------------------

在您的时间表上方便地收听我们的一些最佳内容

我们的使命是为每个人提供最好的内容。我们热衷于以最适合你的方式让你接触到创新的概念和想法。从我们的播客到我们的时事通讯到我们的出版物本身,我们一直在努力以各种方式与你们分享前沿概念。

我们现在正致力于通过提供一些我们最好的文章的便捷音频解说来让您的生活更加美好。

我们选择的叙述性文章包括由我们的专业叙述者团队精心策划的内容。听听迈克尔·邦纳、杰纳·康纳利、埃里克·麦克法登和爱丽丝·伊里扎里在你度过每一天时为你带来的这些惊人的概念。

方便的时候听听,了解一些数据科学、机器学习、人工智能、编程等领域最不可思议的想法。

示例:

https://towardsdatascience.com/narrated/home

我们也让我们的作者提出他们自己的录音,就像丹尼尔在这里做的一样。将您的完整音频以 mp3 格式发送到 publication@towardsdatascience.com。

如果您对我们如何改进本部分有任何想法,请随时发送您的反馈。

谢谢!

Lit BERT: NLP 迁移学习的三个步骤

原文:https://towardsdatascience.com/lit-bert-nlp-transfer-learning-in-3-steps-272a866570db?source=collection_archive---------10-----------------------

BERT (Devlin 等人,2018)可能是最流行的迁移学习的 NLP 方法。由 Huggingface 实现的这个 API 提供了很多不错的特性,并抽象出了漂亮 API 背后的细节。

PyTorch Lightning 是一个轻量级框架(实际上更像是重构你的 PyTorch 代码),它允许任何使用 PyTorch 的人,如学生、研究人员和制作团队,轻松扩展深度学习代码,同时使其可复制。它还通过教练标志提供 42+高级研究功能。

Lightning 没有在 PyTorch 上添加抽象,这意味着它可以很好地与其他伟大的软件包一起使用,比如 Huggingface!在本教程中,我们将使用他们的 BERT 实现在 Lightning 中执行微调任务。

在本教程中,我们将分三步进行 NLP 的迁移学习:

  1. 我们将从 huggingface 库导入 BERT。
  2. 我们将创建一个照明模块,它使用 BERT 提取的特征进行微调
  3. 我们将使用灯光训练器训练 BertMNLIFinetuner。

现场演示

如果您更愿意在实际代码中看到这一点,复制这个 colab 笔记本!

微调(又名迁移学习)

如果你是一名试图改进 NYU 胶水基准的研究人员,或者是一名试图理解产品评论以推荐新内容的数据科学家,你正在寻找一种方法来提取一段文本的表示,以便可以解决不同的任务。

对于迁移学习,通常有两个步骤。您使用数据集 X 来预训练您的模型。然后,您使用该预训练模型将该知识带入求解数据集 b。在这种情况下,BERT 已经在图书语料库和英语维基百科上接受了预训练【1】。下游任务是你关心的解决胶合任务或分类产品评论。

预训练的好处是,我们在下游任务中不需要太多数据就能获得惊人的结果。

用 PyTorch 闪电微调

一般来说,我们可以使用以下抽象方法对 PyTorch Lightning 进行微调:

对于迁移学习,我们在 lightning 模块中定义了两个核心部分。

  1. 预训练模型(即:特征提取器)
  2. finetune 模型。

您可以将预训练模型视为特征提取器。这可以让您以一种比布尔或一些表格映射更好的方式来表示对象或输入。

例如,如果您有一个文档集合,您可以通过预先训练的模型运行每个文档,并使用输出向量来相互比较文档。

微调模型可以任意复杂。它可能是一个深度网络,也可能是一个简单的线性模型或 SVM。

用 BERT 微调

Huggingface

在这里,我们将使用一个预训练的 BERT 来微调一个名为 MNLI 的任务。这实际上只是试图将文本分为三类。这是照明模块:

在这种情况下,我们使用 huggingface 库中预先训练的 BERT,并添加我们自己的简单线性分类器,将给定的文本输入分类到三个类别之一。

然而,我们仍然需要定义验证循环来计算我们的验证准确性

以及计算我们测试精度的测试回路

最后,我们定义将要操作的优化器和数据集。该数据集应该是您试图求解的下游数据集。

完整的 lightning 模块看起来像这样。

摘要

在这里,我们学习了在 LightningModule 中使用 Huggingface BERT 作为特征提取器。这种方法意味着您可以利用一个真正强大的文本表示来做如下事情:

  1. 情感分析
  2. 对聊天机器人的建议回复
  3. 使用 NLP 构建推荐引擎
  4. 改进谷歌搜索算法
  5. 为文档创建嵌入以进行相似性搜索
  6. 任何你能创造性地想到的东西!

你也看到了 PyTorch Lightning 与包括 Huggingface 在内的其他库的配合有多好!

使用机器学习和谷歌地图实时预测交通事故风险

原文:https://towardsdatascience.com/live-prediction-of-traffic-accident-risks-using-machine-learning-and-google-maps-d2eeffb9389e?source=collection_archive---------3-----------------------

在这里,我描述了使用 scikit-learn、 Google Maps API、Dark Sky API、Flask 和 PythonAnywhere 创建和部署交互式交通事故预测器。

Source: unsplash

交通事故非常普遍。如果你像我一样生活在一个杂乱无章的大都市,你可能听说过、目睹过、甚至参与过其中。由于交通事故频繁发生,交通事故是全球死亡的主要原因,每年缩短数百万人的生命。因此,能够预测交通事故或事故易发区域的发生的系统能够潜在地挽救生命。

交通事故预测虽然困难,但并非不可能。事故不会以纯粹随机的方式出现;它们的发生受多种因素的影响,如驾驶员的身体状况、车型、驾驶速度、交通状况、道路结构和天气。研究历史事故记录将有助于我们理解这些因素和道路事故之间的(潜在因果)关系,这反过来将允许我们建立一个事故预测器。

幸运的是,有几个这样的事故记录是公开的!例如,英国政府公布了自 2002 年以来该国交通事故的详细记录。有了这个数据集,我和我的队友们已经创建并部署了一个 机器学习模型 ,它可以高精度地预测大伦敦地区何时何地可能发生事故。

在这篇文章中,我将带你完成这个项目的过程。完整的代码可以在我的 GitHub 库中找到,而实时模型可以在这个网站中访问。

[## 道路交通事故

在这个项目中,我们建立了一个机器学习模型,预测在不同地点的 RTAs 的概率…

kteo7.pythonanywhere.com](https://kteo7.pythonanywhere.com/)

目标

在开始这个项目之前,我们为自己设定了一个明确的目标:我们希望创建一个任何人都可以轻松访问的交互式交通事故预测器。我们认为实现这一目标的最佳方式是在网站上部署一个训练有素的预测器。这个预测网站应该能够做到以下几点:

  • 允许用户输入出发地和目的地(两者都必须在大伦敦),并找到连接两者的最佳驾驶路线。
  • 允许用户选择他们计划进行旅行的日期/时间,并确定在该时间窗口内沿线特别容易发生事故的区域。

下图描述了我们为实现这一目标而采取的步骤。我将在接下来的章节中详细阐述它们。

Steps in this project

数据收集

确定了目标后,我们开始寻找必要的数据。以下是我们最终选择的两个数据集:

卡格尔

我们在这个项目中使用的主要数据集是英国政府发布的详细事故记录,并在 Kaggle 上托管。他的数据集包含了 2000 年至 2014 年间发生在英国的 160 万起交通事故的细节。它由 33 列组成,记录了事故的地点、时间、严重程度以及各种气象和交通背景等细节。在这个项目中,我们仅限于分析 2012 年至 2014 年大伦敦地区的交通事故。

黑暗的天空

我们认为天气是道路事故中一个特别重要的因素。尽管前面提到的 Kaggle 数据集包含了气象信息,但我们认为这还不够。使用 Kaggle 数据集的weather_condition列有两个问题:

  • 它假设天气全天不变。如果你去过伦敦,你就会知道为什么这个假设是有问题的——那里的天气变化非常频繁!
  • 它只包含历史天气记录(显然!).为了使用weather_condition作为未来事故的预测器,我们需要一种方法来获得天气预报

由于这些原因,我们决定转而利用美国一家专门从事天气预报的公司 【黑暗天空】 提供的气象数据。黑暗天空每半小时提供一次过去的记录和未来的天气预报,这完全符合我们的目的。

数据处理

DBSCAN 聚类

在研究数据集时,我们发现伦敦几乎每条街道都曾是事故现场。这是有道理的——伦敦是一个繁忙的城市,交通事故(包括小事故)经常发生。下图是使用 Tableau 创建的,在伦敦地图上叠加了事故地点(红点)。注意整个城市是如何沐浴在红色之中!

The city of London. Each red spot indicates an accident between 2012 and 2014. As we can see, London is full of (historical) car accidents!

尽管全市都发生过事故,但有些地区比其他地区更容易发生事故。为了系统地识别这些事故热点,我们将上述事故地点分组。我们将一个聚类定义为一个横截面为 25 米的区域,其中在两年时间窗口内至少发生了 14 起事故。

我们使用 DBSCAN 算法来执行这种聚类。选择 DBSCAN 是因为它的速度、发现任意形状簇的能力以及对异常值的鲁棒性。落在聚类之外的事故点被视为异常值,并从我们随后的分析中排除。

A depiction of how DBSCAN works

DBSCAN 聚类步骤发现了 473 个事故热点。下面是使用地理分析软件 ArcGIS 对这些热点进行的可视化处理。我们可以看到热点集中在伦敦的主要道路上,如 A11 和 A13。

Accident hot spots in London

负采样

此时,我们有数百个事故热点。我应该澄清一件事——这些热点并非 100%的时候都容易发生事故。例如,伦敦主干道沿线的事故多发点在高峰时段可能很危险,但在安静时段相对安全。另一方面,急转弯中的热点在阳光明媚的日子里可能是相当无害的,但在下雪或下雨的日子里可能会变得致命。

因此,我们的下一个任务是找出这些热点在什么条件下被“激活”。通过这种方式,我们的项目现在变成了一个经典的二元分类问题:我们需要找出能够“激活”热点的因素组合(例如天气、时间等)。

然而,我们此时的数据还不足以创建一个分类模型!训练分类器需要正样本和负样本,但我们只有正样本(即目标标签为 1 的记录)。因此,我们需要一种生成阴性样本(即“非事故”记录)的方法

先前已经描述了使用阳性样品产生阴性样品。我们遵循袁等人 所描述的方法,实质上,该方法需要为聚类中的每个阳性样本随机生成三个阴性样本。例如,如果我们有一个位于 Abbey Road 的聚类,其中发生了 15 起事故,我们将随机合成该地点的 45 条非事故记录。除了它们的位置,这些阴性样本的其他预测特征,如非事故事件的日期和时间,是随机选择的。小心谨慎,以免这些随机合成的阴性样品与真正的阳性样品不一致。

探索和观察

在研究我们清理过的数据集时,我们发现了一些有趣的现象。一些更有趣的观察结果详述如下。

哪些月份最容易发生道路交通事故?

上面的热图显示了所有日历月中一周内每天发生的事故数量。我们可以看到,9 月至 12 月是事故发生频率相对较高的月份。这是伦敦秋季的几个月,其特点是低温、多雾和多雨。与直觉相反,寒冷的冬季一月和二月发生的事故较少。这可能表明人们更不愿意在这段时间开车。

一天中的什么时候最容易发生道路交通事故?

上面的热图显示了一周中每天每小时发生的交通事故数量。我们观察到,不出所料,大多数事故发生在早上 8 点到 9 点的早高峰时间和下午 3 点到 7 点的晚高峰时间(紫色块)。星期五尤其糟糕。

每起事故涉及多少辆车?

上面的条形图显示了基于涉及车辆数量的事故分布。它表明大多数事故涉及一辆或两辆汽车。这在直觉上是有意义的;大多数事故都是由于汽车偏离道路和/或两辆汽车相撞而发生的。

哪些区的交通事故发生率最高?

上面的条形图显示了伦敦不同行政区发生的事故数量。我们看到威斯敏斯特位居第一,泰晤士河畔的金斯敦交通事故最少,排在最后。下面的地图以不同的方式展示了同样的信息:它用较暗的紫色突出了容易发生事故的行政区。

监督学习

有了前面提到的预处理步骤,我们终于准备好进入建模阶段了!我们按照 70:30 的比例将数据集分为训练和测试数据集。

Python 的 scikit-learn 库用于模型训练和评估。我们尝试了常见的分类模型,如 SVM、逻辑回归和随机森林。使用准确度和受试者工作特征曲线下面积(AUC-ROC)来测量和比较模型的相对性能。下表总结了我们建模步骤的结果。

我们发现,在我们测试的模型中,表现最好的模型是仅根据数字特征训练的随机森林。这是我们为部署选择的模型,我将在下面描述这个过程。

部署

然后,我们使用 Python web 框架 Flask 将我们的 scikit-learn 模型打包成一个 web 应用程序。该网站的前端显示是基于一个取自网站 HTML5UP 的免费模板构建的。所有的 html、javascript 和 CSS 代码都集成到 Flask 应用程序中。

然后,PythonAnywhere(一个专注于 Python 的 web 托管服务)将该应用程序发布到网上。你可以在kteo7.pythonanywhere.com访问网站。以下是网站截图:

现在我想提供 Flask 应用程序工作的更多细节。

在前端,有字段,用户可以输入他们选择的起点和终点。这些文本字段配备了提供自动完成功能的 Google Places API。还有一个下拉菜单,用户可以选择日期/时间(可以是过去、现在或未来 48 小时内)。

一旦输入完成,一个POST请求就会被发送到后端框架。这里,这些输入充当函数call_google的参数。给定出发地和目的地,该函数将调用 Google Maps API,返回连接两地的最佳行驶路线。更具体地说,该函数返回路线的航路点的纬度和经度,这些航路点是沿路线有规律间隔的点。

纬度和经度作为另一个名为calc_distance. 的功能的输入。该功能从这些航路点“画”出半径为 50 米的假想圆,并检查是否有任何事故热点落在这些航路点内。

对于落入圆圈内的每个星团,另一个函数call_darksky向黑暗天空 API 发出请求。该函数将返回指定时间内该地点的天气预报。

利用天气数据以及日期/时间信息,最终预测功能将对感兴趣的热点在所选天气/时间下是否被“激活”进行二元预测。这些预测然后被发送到前端,前端将在屏幕上显示它们。

下面的 gif 展示了我们的交互模型。在这里,我选择了一个未来的日期和时间(10 月 12 日星期六下午 6 点),选择了一个起点(海德公园)和一个终点(国王十字车站)。我们可以看到,该模型选择了一条穿过 Gloucester Place 和 A501 的路线,并将这两条道路之间的繁忙交叉路口标记为潜在的事故地点。

同样,你可以在kteo7.pythonanywhere.com访问这个模型。我鼓励你在它仍然活跃的时候(它将一直活跃到 2020 年初)尝试一下。

注:除非另有说明,以上所有图片和动画均属本人所有。

如果你对这篇文章有任何意见或者想联系我,请随时通过 LinkedIn 给我发一个联系方式。另外,如果你能通过我的推荐链接成为一名中级会员来支持我,我将非常感激。作为一名会员,你可以阅读我所有关于数据科学和个人发展的文章,并可以完全访问所有媒体上的故事。

这个项目是“数据和可视化分析”课程的一部分,我在佐治亚理工学院攻读分析硕士学位时选修了该课程。特别感谢我在这个项目中的队友——katan nya,Roger,Siew Lee 和 Yeok!你们太棒了。

使用 Tweepy、Keras 和 Django 对 Twitter 数据进行实时情感分析

原文:https://towardsdatascience.com/live-sentiment-analysis-on-twitter-data-using-tweepy-keras-and-django-99c344e90488?source=collection_archive---------4-----------------------

Photo by Marten Bjork on Unsplash

欢迎来到这篇关于在推特上进行实时情绪分析的教程。我相信你一定遇到过复杂的仪表板,上面有大量的图表和数字正在被处理,看起来就像科幻电影一样,令人敬畏。这就是我们的目标。

Some Complex looking dashboard

虽然我们的最终结果不会像这样广泛,但是,它会教你如何进行必要的数据连接,这样你就可以使它像你想要的那样复杂。你可以继续把它作为一个 SaaS 业务或一个移动应用程序,赚一些钱。我们的结果会是这样的:

Our Result

它将对任何标签及其相关上下文进行实时分析,并在新推文出现时向您展示,同时附上一份情感。

够兴奋了吧?很好,我们开始吧。本文分为三个部分:

  1. 制作模型
  2. 制作 UI 界面(前端)
  3. 制作后端,获取实时数据,连接一切

1.模特的东西

虽然情感分析在自然语言处理中是一个非常常见的话题,但我现在只简要介绍一下模型架构,但稍后我会就此写一篇单独的帖子。

我使用了感知 140 数据集进行训练,它包含大约。160 万条推特。在通过规范化清理文本并删除以' @ '开头的用户标签后,我使用了gensim 包的 Word2Vec 函数在整个语料库上训练它。由于语料库相当庞大,我有足够的数据来训练相当准确的嵌入,否则,我会使用预训练的矢量器。

#Test word embeddings
w2v_model.most_similar("hate")[('suck', 0.5254894495010376),('stupid', 0.509635865688324),('hat', 0.479534387588501),('ugh', 0.4475134015083313),('dislike', 0.44565698504447937),('despise', 0.43604105710983276),('fuck', 0.4104633331298828),('annoy', 0.4004197418689728),('ughh', 0.3961945176124573),('fml', 0.39270931482315063)]

接下来,我使用了keras 标记器将输入数据转换成标记,并添加填充符以使所有输入长度相同。这是 NLP 中数据准备的标准过程。最后,我把准备好的数据传进了一个 LSTM 网络。

predict("@Nintendo I love your games!"){'score': 0.820274293422699}

最终的准确率竟然在 78.4% 左右,目前来看已经足够好了。整个实现是这里是

ACCURACY: 0.784396875
LOSS: 0.45383153524398806

最后,我保存了模型(作为一个. h5 文件)和经过训练的 Keras Tokenizer(作为一个. pkl 文件),以便以后在服务器脚本的推理过程中使用它们。您可以在此下载培训文件

注意:我实现了另一个模型,使用 1D 卷积代替 LSTM 网络进行比较,结果提供了几乎相似的结果。对于好奇的学习者,你可以在这里找到这个实现。

2.UI 前端的东西

我使用了 ReactJS 来构建接口。这是一个 Javascript 框架,通过创建组件并像乐高积木一样重用它们来促进模块化设计。每个组件都有其生命周期,因此如果某个组件的数据发生变化,只有该组件会刷新。这减轻了浏览器的负担,并减少了更新信息之间的延迟。

我不打算详述我是如何制作这个网站的,因为它只是基本的 CSS 和 Javascript,因此你可以直接研究库中的代码。然而,如果你有任何疑问,请在下面留下你的回复,我会很乐意为你解答。

你只需要知道

我们有一个名为**state** 的变量,它属于网站,这里的任何变化都会刷新组件。

this.state = {hashtag: "",options: {colors: ['#F7464A', '#46BFBD', '#FDB45C'],labels: ['Negative', 'Positive', 'Neutral'],plotOptions: {pie: {donut: {labels: {show: true}}}}},series: [44, 55, 41],tweets: [],hashtag_desc: ""}

**hashtag**包含输入字段的值,**options**值属于饼图的一些选项。我们只对一个功能感兴趣:

  • 该函数在被调用时会将一个 GET 请求连同**hashtag** 值一起发送到我们位于‘http://localhost:8000/analyzehashtag’的服务器。它需要以下形式的 JSON 响应:
{
...
data: {positive: 43,negative: 23,neutral: 12}
...
}
  • 该函数还向公共维基百科 API 发送一个 GET 请求,以及**hashtag** 值,以获取一些关于它的简短信息。
  • 最后,该函数将另一个 GET 请求连同**hashtag** 值一起发送到我们位于‘http://localhost:8000/gettweets’的服务器。它需要以下形式的 JSON 响应:
{"results": [{"text": "Is it possible to wirelessly project my laptop                   to my #Xbox? #XboxOne [https://t.co/KMuSoD2C5j](https://t.co/KMuSoD2C5j)","username": "Xbox_One_Reddit","label": "Neutral","score": 0.5679275393486023},{"text": "This year's #E3 had some big #XBOX news for the gaming industry. A glimpse at the future with Scarlet its Next Gen console, promising 4K &amp; 8K gaming, and of course the franchise that started it all... #Halo Infinite announced!\n\nWhich was you favorite?? #E32019 #XboxE3 #Gaming [https://t.co/tykdIYezmr](https://t.co/tykdIYezmr)","username": "NrdRnx","label": "Positive","score": 0.9130105972290039},{"text": "DOMED 💀 #apex #apexlegends #apexlegendsxbox #apexlegendsclips #apexlegendscommunity #apexlegendsplays #playapex #controllergang #xbox #mixer #twitch [https://t.co/itERG2vpaD](https://t.co/itERG2vpaD)","username": "gle_oh","label": "Negative","score": 0.26629960536956787},...]
}

这些数据用于填充处理实时 tweets 的组件。

3.后端的东西

最后,我们进入这篇文章的核心。对于后端,我们将使用 Django 来创建它。

注意:如果你没有后端开发经验,我推荐用 Flask 代替 Django。Flask 对用户非常友好,你可以在几分钟内创建和我在这里做的一样的东西。我使用 Django 是因为我发现部署更容易一些,而且它很容易扩展到更复杂的应用程序。

你可以谷歌如何创建 Django 项目,或者跟随他们文档中给出的教程。完成后,它应该具有以下文件夹结构:

│   .gitattributes
│   db.sqlite3
│   manage.py
│
├───main_app
│   │   admin.py
│   │   apps.py
│   │   config.py
│   │   models.py
│   │   Sentiment_LSTM_model.h5
│   │   tests.py
│   │   tokenizer.pickle
│   │   twitter_query.py
│   │   views.py
│   │   __init__.py
│   │
│   ├───migrations
│   │
│   └───__pycache__
│           admin.cpython-36.pyc
│           config.cpython-36.pyc
│           models.cpython-36.pyc
│           views.cpython-36.pyc
│           __init__.cpython-36.pyc
│
└───twitter_django│   settings.py│   urls.py│   wsgi.py│   __init__.py│└───__pycache__settings.cpython-36.pycurls.cpython-36.pycwsgi.cpython-36.pyc__init__.cpython-36.pyc

(而不是**main_app****twitter_django**,它们将是您选择的应用程序的名称)

Django 用“视图”的概念来封装负责处理用户请求和返回响应的逻辑。因此,我们收到的对服务器的任何请求都将在这里处理。我们使用**urls.py** : 来连接视图

当我们在一个特定的 URL 端点接收到一个请求时,比如说“/gettweets”,它触发指定的函数——在本例中是“views.gettweets”。功能的逻辑写在**views.py** 中。

注意这几行:

global graph
graph = tf.get_default_graph()
model = load_model('main_app/Sentiment_LSTM_model.h5')

如果没有图表,您就无法运行您的模型来获得预测(因为 Tensorflow 的工作方式)。如果你试着跑,' model.predict(..)'而没有指定图形,您将得到一个错误。因此,当你试图使用你的模型时,不要忘记加上:

with graph.as_default():            prediction = model.predict(...)

十二岁

如果你想从 Twitter 获取数据,Tweepy 就像是一个包。你可以使用pip.来安装它,你所需要的只是一些独特的密钥。这些密钥可以通过在 Twitter 开发者网站注册一个应用程序来获得。

一旦完成,我们可以将tweepy 初始化为:

# Twitter
auth = tweepy.OAuthHandler(consumer_key,consumer_secret)
auth.set_access_token(access_token, access_token_secret)
api = tweepy.API(auth,wait_on_rate_limit=True)

现在要获取 tweets,我们可以调用 Cursor 函数。我们使用了一个定制的搜索标签(从前端接收)并收集了相同的 tweets。

注意:我使用*“ -filter:retweets”*是为了只获得唯一的推文,否则,由于不同的转发频率,情感标签可能会有偏差。

tweepy.Cursor(api.search,q="#" + request.GET.get("text") + " -filter:retweets",rpp=5,lang="en", tweet_mode='extended').items(100)

制作一个 REST API

我们的服务器有两个重要的功能:

  1. **analyzehashtag()** —接受标签值,使用 tweepy 获得该标签的大量 tweets,并对每个 tweepy 执行情感分析。最后,通过简单地统计观察结果,计算积极、消极和中性推文在特定标签中的分布。
def analyzehashtag(request):    
positive = 0    
neutral = 0    
negative = 0    
for tweet in tweepy.Cursor(api.search,q="#" + request.GET.get("text") + " -filter:retweets",rpp=5,lang="en", tweet_mode='extended').items(100):        with graph.as_default():            prediction = predict(tweet.full_text) if(prediction["label"] == "Positive"):    positive += 1       if(prediction["label"] == "Neutral"):neutral += 1if(prediction["label"] == "Negative"):negative += 1return JsonResponse({"positive": positive, "neutral": neutral, "negative": negative});

2.**gettweets()**—这与第一个函数类似,但它不是计算分布,而是收集更少数量的推文并返回每个推文的结果。这样我们可以实时显示我们的模型的熟练程度,并检查它是否符合我们的常识。

def gettweets(request):tweets = []for tweet in tweepy.Cursor(api.search,q="#" + request.GET.get("text") + " -filter:retweets",rpp=5,lang="en", tweet_mode='extended').items(50):temp = {}temp["text"] = tweet.full_texttemp["username"] = tweet.user.screen_namewith graph.as_default():prediction = predict(tweet.full_text)temp["label"] = prediction["label"]temp["score"] = prediction["score"]tweets.append(temp)return JsonResponse({"results": tweets});

现在,为了让我们的前端能够访问这些函数,我们将把这些函数作为 API。使用 Django REST 框架可以很容易地做到这一点。

只需使用pip install djangorestframework安装,并在每个功能前添加[@api_view](http://twitter.com/api_view)([“GET”])。(因为我们在这里只使用了 2 个 GET 请求,所以我在这里只使用 GET)。

不要忘记在settings.py文件中添加以下内容。

INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','rest_framework','corsheaders','main_app'
]

结论

使用python manage.py runserver运行服务器,享受洞察“人们对新选举的反应”,或者“人们喜欢赛博朋克 2077 预告片中的基努·里维斯客串吗”。发疯吧!

我的 GitHub 上有完整的代码和安装说明。如果你愿意,可以去看看。再见

** [## agrawal-rohit —概述

拥有 3 年以上项目工作经验的初级数据科学家和软件开发人员。高度熟练的机器…

github.com](https://github.com/agrawal-rohit?tab=repositories)**

生活在机器人社会——一位世界领先的机器人专家的观点

原文:https://towardsdatascience.com/living-in-a-robot-society-a-perspective-of-a-world-leading-robotocist-51175fb455e3?source=collection_archive---------26-----------------------

与日本大阪大学智能机器人实验室主任石黑浩教授的 15 分钟。

我们谈到了他在制作机器人版本时学到的关键知识,与技术融合的意义,以及他对 HBO 著名剧集《西部世界》的看法。

你的愿景是什么?

我的动机是了解人类是什么。我对自己和人类社会非常感兴趣。我认为我们作为人类在这个世界上生存的目的就是思考人类。我们总是试图了解自己,这是在这个世界上生存的最重要的动力。

在我的案例中,通过使用计算机技术、机器人技术和机器人技术,我正在接近这些问题。

这是你建造人形或安卓机器人的原因,是为了在建造这些机器人的过程中了解我们自身的人性吗?

一旦我们创造了一个非常像人类的机器人,我们就可以把它附加到更重要的人性上,比如现在。我们在互相交谈,这是一次交谈,但交谈的真正意义是什么。

可能要进行一次谈话,我们需要思考一些事情,但是思考什么,对吗?有那么多模棱两可,不为人知的话。我想通过使用机器人来理解每一个对我们人类来说模糊但非常重要的概念。这就是我们实验室正在做的事情。

你说思维,就是说意识。你对意识有自己的定义吗?

意识是,思维,情感,欲望等等。这些概念是无法明确区分的。

我没有自己最初的定义,但是在研究中,我们基本上考虑三个层次,三层意识。首先是唤醒水平,然后是现象水平,最后是进入水平。

现象学的层次是感受性。例如,当我们看到日落时,我们被感动了。我们被日落的美景所感动。

在进入层面,我们可以考虑自己,我们可以感受自己。

这些层是紧密耦合的,我们不能分解它们。同时,这些意识水平与意图、欲望和情绪密切相关。

身体、大脑、思想之间有什么联系?

这对我们来说是非常重要的课题之一。本来我已经把 android 系统开发成了一个遥操作的 Android。这意味着如果我们通过互联网交谈,机器人可以像我一样行动。每个人都可以很容易地接受机器人身体作为他或她自己的身体。所以,我们实际上不需要身体和大脑之间的紧密联系。如果我们有一个机器人身体,我们的大脑可以接受机器人身体作为我们自己的身体,如果大脑可以控制身体的话。这是一个非常有趣的现象。

当我想到您构建的 Geminoid 时,您在这个过程中有哪些重要的见解?你学到了什么?

最重要的教训是,实际上,我不能接受我的第一个双子星座是我自己;但是其他人,学生和我的工作人员说这和我自己是一样的。

这意味着,我们不能对自己有客观的看法。我们不知道我们的脸、声音和行为。我发现人类基本上不可能有客观的观点。

这是我最感兴趣的发现。

因为我们有偏见,所以我们感知自己的世界和周围的人……

我们可以感知世界,但我们不能直接观察自己,我们需要使用镜子和录音机。一旦我们使用录音机,看着镜子,那就不同于我自己的辨认了。录制的声音听起来像另一个人。原则上,我们不能对自己有客观的看法和理解。

接下来,你可能想让 Geminoid 能够与人交流和互动,在这一点上,它变得更加复杂。

我们还没有研究人格,但是在研究人格之前,我们需要发展与他人对话的能力和功能。对话式自主机器人非常困难。现在,我们将重点放在对话功能上,我们采取了许多方法,如聊天机器人方法或更高级的非正式讨论。我们关注的是基于意图和欲望的更深层次的对话。

什么时候我会和 Geminoid 说话,而我不能确定我是在和你说话还是和你的机器人版本说话?

也许以后吧!我们正在越来越多地改进机器人。还没有!

你怎么看待从技术上拔掉插头?你认为这重要吗?你认为这在未来会变得不那么重要吗?

我认为思考人性是非常重要的,但从根本上说,我们人类有两种进化方式。

一个是基因;另一个是技术。因为科技,我们可以成为人类。如果我们不想使用技术,我们想成为猴子。我们不能把技术和我们人类分开。人类是使用技术和工具的动物。我们需要研究两个方面,人类的动物方面和人类的技术方面。但更重要的是,我们可以利用新技术开发更好的能力,这就是人类进化的方式。

需要克服的最大的坎是什么?

如果我们看看智能手机,一个国家无法用智能手机技术开发实用系统,iPhones 和其他智能手机是世界商业产品。他们需要有一个大市场来拥有一个更强大和更便宜的设备。对于机器人,我们需要有更多的技术。机器人需要在智能手机上添加执行器和传感器,然后我们才能拥有一个机器人。

在这种情况下,我们需要一个对社会产生更大影响的更大的市场。否则,我们就无法进行大规模生产,机器人也会非常昂贵。这是机器人社会最困难的一面。

让我们接触一下 乌托邦和反乌托邦的场景。你更积极还是更消极?

我不能说这是好是坏,因为未来就是未来。

我们总能在那里找到快乐。开心和不开心是相对的。

更重要的是扩展我们的能力和生存。如果我们开发更多的技术,我们将有更多的机会在这个世界和这个宇宙中生存。这对我们人类来说是最重要的事情。乌托邦和反乌托邦只是相对的尺度。如果你能享受与否,那取决于你。

一种观点是在我们的大脑中实现微芯片,以跟上机器人……

这是自然的。技术是进化中非常重要的一部分。看看我们现在在做什么,每个人都继续使用他们的智能手机,这几乎就像一个植入物。

你有什么个人的技巧或者日常做的套路来想出新点子吗?

我总是试着去想很多事情。这是一种内在的声音。所以总有人在我脑中说话。当我在浴室洗澡的时候,当我用吹风机的时候,总会有一些想法冒出来。如果我摸我的头,我可以进入我大脑中的中性状态,然后会有一些想法出现。

保持大脑的中立状态是非常重要的。也许这类似于心理化。对我来说很简单,我只需要用一个吹风机,然后我就可以精神化了。

想象一下,以你现在所拥有的知识和经验,2018 年你将年满 18 岁。你会怎么做?你会获得什么技能?

尽管如此,我还是会做同样的事情。我目前的动机是了解我自己、人类和社会。这是一个很根本的基本的东西。我也会这么做,但我可能会接受更多的挑战。我可能会开另一家公司。如果我年轻,我可以接受更多的挑战。

我认为我年轻的时候是一名优秀的程序员。如果我现在 18 岁,我会连接到软件世界,自己开发人工智能。

所以,技术技能与哲学、艺术、心理学等诸多领域的结合……

但是最有效的方法是建设性的方法。创造一个有意识的代理人。在那之后,我们可以谈论心理学、哲学等等,但是没有代理人,我们无法进行讨论。我称这种方法为“建设性方法”。

你知道西部世界系列吗?

是的。我不喜欢这个想法,它是完全错误的。如果我们杀死一个类似人类的机器人,那就是谋杀。我们没有那么疯狂,所以方法完全错误。

有什么可以推荐的电影?

两百周年纪念人,由罗宾·威廉姆斯扮演。我喜欢那部电影。活了两个世纪的人。

喜欢这篇文章吗?这是另一个

[## 我们需要去人性化的人工智能吗?

领先的人工智能专家乔安娜·布赖森就过度拟人化人工智能、偏见和安全人工智能的系统设计进行了采访。

medium.com](https://medium.com/omdena/do-we-need-to-dehumanize-artificial-intelligence-78d2f28c24fb)

关于作者:

迈克尔·布哈特是一位 AI 旅行企业家(40 多个国家)。他帮助 AI 爱好者通过真实世界的项目 获得动手技能。除了艾禾关于思维转变、冥想技巧和旅行者身体锻炼的博客。

LinkedIn insta gram

加载&%$*#检查点!

原文:https://towardsdatascience.com/load-that-checkpoint-51142d44fb5d?source=collection_archive---------23-----------------------

成功的 Udacity 项目检查点加载的提示和技巧

Photo by Vidar Nordli-Mathisen on Unsplash

加载那个检查点有问题吗?

我也是。

成为 Udacity 脸书 AI PyTorch 挑战赛的一员真是太棒了,一路上我学到了很多。完成最后的挑战后,我想分享一些技巧和诀窍,这些技巧和诀窍使我能够成功地将深度学习图像分类器项目的检查点提交到 Udacity 工作区。

最重要的是,遵循实验室的指示!我希望你知道这一点,但我把它放在这里以防万一…

保存您的检查点

如果您正在尝试在实验室中加载检查点,我假设您已经保存了检查点,但您确实需要保存检查点,因为这是您将在实验室中加载的内容!Torch.save 在这里非常方便。例如,这里有一个可能的检查点:

checkpoint = {'input_size': 2208,'output_size': 102,'epochs': epochs,'batch_size': 64,'model': models.densenet161(pretrained=True),'classifier': classifier,'scheduler': sched,'optimizer': optimizer.state_dict(),'state_dict': model.state_dict(),'class_to_idx': model.class_to_idx}torch.save(checkpoint, 'checkpoint.pth')

只装你需要的东西。你可能不需要我在这个检查点加载的所有信息,但是我把上面的一个作为例子,这样你可以看到一些选项。在实验室中加载检查点之前,应该完成检查点保存。

确保您知道您的检查点保存在哪里,以便您可以将该文件上传到 Udacity 工作区!

在 Colab 工作?

如果您正在使用 Google Colab,并且将您的 Google Drive 安装到您的笔记本上(这里有一篇很棒的文章,如果您刚刚开始使用 Colab 并且不知道我在说什么,您可以通过运行以下命令将您的检查点直接移动到您的 Google Drive 中:

model_save_name = 'classifier.pth'
path = F"/content/gdrive/My Drive/{model_save_name}" 
torch.save(model.state_dict(), path)

请确保文件路径正确无误!

*如果您决定将您的检查点保存到您的 Google Drive,您实际上可以将它从那里移动到 Udacity 的工作区,方法是转到您的 Google Drive,获取可共享的链接文件,并找到您的文件 ID。您只需要文件 ID:它将是“id=”后面的一长串字母和数字。然后转到 Udacity 实验室笔记本运行

!pip install gdown==3.6.0

安装 gdown。那就跑

ckpt_file_id = "YOUR-FILE-ID-GOES-HERE"

(确保用您的实际文件 ID 替换“YOUR-FILE-ID-GOES-HERE ”!)

最后

!gdown [https://drive.google.com/uc?id={](https://drive.google.com/uc?id={1kX4IwGUB88x9CTHAfhsAz7PljqnKZdEp)ckpt_file_id}

这将下载您的文件并将其放在 Udacity 实验室中。

在 Udacity 工作区中

如果您没有使用 Google Drive,那么当您到达实验室时,您需要点击“上传”按钮,上传您的检查点文件。确保它一直到 100%,否则你可能会得到一个损坏的文件。

以下是您提交项目所需的重要信息:

你需要加载你的参数。我从

ckpt = torch.load('checkpoint.pth')
ckpt.keys()

这样我就可以快速看一下我的钥匙。然后我运行我的进口。

from collections import OrderedDictimport torch
import torch.nn as nn
from torchvision import models
import os
from torchvision import datasets, transforms

这里有一个非常重要的细节:如果您还没有定义图像大小,请运行以下命令:

image_size = 224
# Values you used for normalizing the images. Default here are for
# pretrained models from torchvision.
norm_mean = [0.485, 0.456, 0.406]
norm_std = [0.229, 0.224, 0.225]

之后,您可以创建一个检查点加载函数,并使用它来加载模型。

def load_checkpoint(filepath):checkpoint = torch.load(filepath, map_location='cpu')model = checkpoint['model']model.classifier = checkpoint['classifier']model.load_state_dict(checkpoint['state_dict'], strict=False)model.class_to_idx = checkpoint['class_to_idx']optimizer = checkpoint['optimizer']epochs = checkpoint['epochs']for param in model.parameters():param.requires_grad = Falsereturn model, checkpoint['class_to_idx']model, class_to_idx = load_checkpoint('/home/workspace/checkpoint.pth')

你看到上面写着

map_location='cpu'

strict=False

?

你想包括那些!

不是开玩笑。Udacity 的工作空间没有连接 GPU,因此您需要确保指定了 CPU。您还希望使用“strict=False ”,以避免遇到任何不必要的版本兼容性问题。

仔细检查分类器的文件路径。正如你在上面看到的,我的是

model, class_to_idx = load_checkpoint('/home/workspace/checkpoint.pth')

你真的需要有正确的道路!如果你看一下测试单元上面的说明,几乎可以肯定你的文件路径应该是什么样子。Udacity 真的希望你成功,所以一定要认真看说明书!

最后

将所有内容放入一个单元格中!将每一行代码放入提供的测试单元中。许多学生在做了一个简单的改变后,最终成功提交了项目。去做吧!

现在测试代码并开始您的项目!这个项目是严格的通过/失败,所以如果你通过了,你就完成了!恭喜你!!!

现在去庆祝吧!

Photo by Jayson Hinrichsen on Unsplash

使用 AWS Lambda 和 CloudWatch 事件加载 Reddit 帖子

原文:https://towardsdatascience.com/loading-reddit-posts-using-aws-lambda-and-cloudwatch-events-9edb03ba4c14?source=collection_archive---------18-----------------------

上个月,我完成了 Reddit 分类项目,通过抓取 Reddit 网站收集数据,然后建立了一个二元分类器来识别给定帖子的来源。现在,当我有一些空闲时间时,我决定检查一下那个项目,并做一些改进。之前,我使用 cron 在 AWS EC2 实例上运行 python 脚本。但这次我决定探索更多的 AWS 服务,并将该脚本转换为由 CloudWatch 触发的 Lambda。

那么,我们开始吧。我们将创建一个 AWS lambda,它将使用 Reddit api 加载 Reddit 帖子,并将它们存储到 S3 桶中。

首先,我们定义一个 bucket 名称和一个要加载的主题列表。然后我们定义一个 lambda 的主方法——“lambda _ handler”,它接受两个参数——事件和上下文。这个方法是我们 lambda 的一个入口点,CloudWatch 会每隔 15 分钟触发一次。该方法将遍历主题列表,并为每个主题加载 reddit 帖子。如果出现异常,我们会捕获它,记录下来,然后继续下一个主题。

接下来,让我们看看加载 reddit 帖子的 main 方法。首先,我们检查一个 csv 文件与以前加载的职位已经存在于 S3。如果是这样,我们将这些帖子加载到一个列表中。我们从列表中提取最后保存的帖子的 id,使用“before”参数继续加载该 id 之后的所有新帖子。如果在 S3 没有现存的文件,这意味着我们还没有加载任何帖子。在这种情况下,我们将使用“after”参数通过 Reddit api 加载所有可用的帖子。你可以点击这个链接阅读更多关于如何使用 Reddit api 的内容:https://www.reddit.com/dev/api/它解释了如何使用“之前”/“之后”参数进行分页。最后,我们将所有帖子转换为 csv 字符串,并保存到 S3。

以下是我们如何从 S3 加载保存的帖子。我们使用 AWS boto3 客户端访问 S3。我们从 S3 读取一个文件,将它分割成单独的行,并将它们传递给 python csv 阅读器库。然后我们使用列表理解将每个解析的行转换成一个元组。

下面是使用 python 请求库加载帖子并从 json 响应中提取必填字段的方法。load_posts 方法使用 while 循环来持续加载 reddit 帖子。首先,它将 pagingId 作为 None 传递,以加载第一页。之后,它从加载的页面中提取下一个 pagingId,并将其与下一个请求一起传递。它一直这样做,直到 pagingId 变成 None。意味着 reddit api 没有剩下任何页面。

你可以在我的 Github 上找到完整的代码

现在,当我们准备好 lambda 代码后,我们需要创建一个 zip 文件来部署到 AWS。当我第一次尝试在 AWS 上运行这段代码时,它不起作用,因为 lambda 没有 requests python 库。结果是,在将 lambda 脚本部署到 AWS 之前,我们必须将所有必需的依赖项和 lambda 脚本一起添加到档案中。让我们在 cmd 中运行以下命令:

$ **mkdir lambda**
$ **cd lambda**
$ **pip install --target ./ requests .**  //install requests library
$ **zip -r ../reddit_lambda.zip .**   //archive the folder
$ **cd ..**
$ **zip -g reddit_lambda.zip reddit_lambda.py**  //add lambda script

这将创建一个名为 reddit_lambda.zip 的归档文件,其中包含请求依赖项和我们的 lambda 脚本。

现在我们将练习使用 AWS Cli 部署我们的 lambda 函数,并每隔 15 分钟触发一次。准备好在命令行中运行许多命令。

首先,我们必须为我们的 lambda 创建一个名为 reddit_lambda_role 的执行角色:

$ **cat lambda_assume_role_policy.json**
{"Version": "2012-10-17","Statement": [{"Effect": "Allow","Principal": {"Service": "lambda.amazonaws.com"},"Action": "sts:AssumeRole"}]
}
$ **aws iam create-role --role-name reddit_lambda_role --assume-role-policy-document file://lambda_assume_role_policy.json**

这个假设策略文档允许角色由我们帐户中的任何 lambda 假设。目前这个角色没有权限——这意味着即使 lambda 假设它没有权限做任何有用的事情,比如访问 S3 来保存对象。要解决这个问题,让我们创建一个策略:

**$ cat lambda_role_policy.json** {"Version": "2012-10-17","Statement": [{"Effect": "Allow","Action": ["s3:GetObject","s3:PutObject","s3:PutObjectAcl","s3:GetObjectAcl"],"Resource": "arn:aws:s3:::**your-bucket-name**/*"},{"Effect": "Allow","Action": ["logs:CreateLogStream","logs:PutLogEvents"],"Resource": "arn:aws:logs:eu-west-1:**your-account-id**:*"},{"Effect": "Allow","Action": "logs:CreateLogGroup","Resource": "*"}]
}$ **aws iam create-policy --policy-name reddit_lambda_policy --policy-document file://lambda_role_policy.json**

这个名为 reddit_lambda_policy 的策略授予访问 S3 的权限,以加载和保存文件,并将日志保存到 CloudWatch。现在,让我们将此策略附加到一个角色:

$ **aws iam attach-role-policy --role-name reddit_lambda_role --policy-arn arn:aws:iam::*your-account-id*:policy/reddit_lambda_policy**

现在让我们在 AWS 中创建一个名为 RedditLoader 的 lambda:

$ **aws lambda create-function --region us-east-1 --function-name RedditLoader --zip-file fileb://reddit_lambda.zip --role arn:aws:iam::*your-account-id*:role/reddit_lambda_role --handler reddit.lambda_handler --timeout 900 --runtime python3.7**

此时,您可以转到 AWS 控制台,打开 lambda 部分并手动运行这个 Lambda。它应该能够加载 reddit 帖子,并将其存储在 S3。但是我们的目标是使用 CloudWatch 事件每 15 分钟触发一次这个 lambda。

让我们创建一个名为 RedditLoadingRule 的预定事件规则:

$ **aws events put-rule --name RedditLoadingRule --schedule-expression 'rate(15 minutes)'**

现在,我们向 lambda 添加由规则中的事件触发的权限:

$ **aws lambda add-permission --function-name RedditLoader --statement-id RedditScheduleEvent --action 'lambda:InvokeFunction' --principal events.amazonaws.com --source-arn arn:aws:events:us-east-1:*your-account-id*:rule/RedditLoadingRule**

向我们的规则添加一个目标,以便它知道每 15 分钟触发什么:

$ **aws events put-targets --rule RedditLoadingRule --targets "Id": "1","Arn":"arn:aws:lambda:us-east-1:*your-account-id*:function:RedditLoader"**

仅此而已。现在,CloudWatch 将每隔 15 分钟发送一个事件,触发我们的 lambda。

所有的 AWS 命令可能看起来令人生畏,但是实际上一旦你学会了如何通过 AWS cli 使用基本命令,你将很快适应只使用 cli 与 AWS 交互。这是一项非常好的技能,可以打开强大自动化的大门。

在下一篇文章中,我们将看看如何使用 SageMaker 来训练和部署使用我们来自 S3 的 reddit 帖子的模型。

小企业银行贷款违约预测

原文:https://towardsdatascience.com/loan-default-prediction-for-small-industries-bank-21da431f7a28?source=collection_archive---------22-----------------------

Photo: https://thelendersnetwork.com/minimum-credit-score-needed-personal-loan/

银行贷款给公司,以换取还款承诺。有些人会拖欠贷款,因为某些原因无法偿还。银行维持保险以减少他们在违约时的损失风险。保险金额可以覆盖全部或部分贷款金额。

对于这项任务,银行希望根据公司的财务信息预测哪些公司会拖欠贷款。提供的数据集由贷款相关信息组成,如贷款金额、期限和州。此外,还有公司信息,如员工数量、运营部门等。

目标

为了预测一家公司是否会拖欠贷款,我尝试了两种不同的机器学习算法:逻辑回归和随机森林。这项作业的指示是使用准确性作为评估标准。然而,在这种情况下,精确性是至关重要的,因为我们希望将贷款违约的可能性降至最低。

见解/探索性数据分析

快速浏览一下数据就能发现一些真知灼见:
1 .贸易公司是最大的客户群
2。较小的公司更容易违约。贷款期限不影响违约的可能性。拖欠贷款的客户只有一半多

有了这些信息,我开始清理数据,并使用洞察力生成新的特征。目标是预测违约状态,0 表示没有违约,1 表示违约。

型号

为了确定哪些信息对于模型的良好运行是必不可少的,我查看了特征的重要性,并重复了特征工程的步骤。

逻辑回归是我的首选模型,因为它的时间复杂度低。该模型的准确率约为 70% 。这也意味着 13% (109/821)的客户没有进行任何还款,但预计不会违约,也就是假阳性。

随机森林是我的下一个模型。它的初始准确度分数是 99%,但是当引入看不见的数据时(验证是 90%),过度拟合将导致较差的预测。调整模型后,最终模型的精度为 94% ,不再过度拟合。维奥拉。我们设法将假阳性的数量从 13%降低到 3%。

结论

没有一种方法可以确定客户是否会停止还款。但是,贷款期限、行业、公司规模等因素都会影响他们的还款能力

这个项目的代码可以在我的 Github 上找到。如果你愿意联系,可以通过 LinkedIn 联系我。

本地数据应该由本地所有

原文:https://towardsdatascience.com/local-data-should-be-locally-owned-754c537c0a22?source=collection_archive---------28-----------------------

数据所有权的新模式意味着我们应该支持本地数据的本地所有权

Photo by Pawel Nolbert on Unsplash

有两个经济对话势头越来越大,看起来即将发生冲突。首先是本地财富创造:我们如何确保本地投资创造的财富留在当地社区并由当地社区控制?第二个是数据所有权:我们当前的自由放任数据所有权模式(将控制权和监督权交还给利益相关方)有哪些替代方案?

什么是本地数据?

本地数据是指主要在应用于产生价值的社区时产生价值的数据。在某种程度上,所有数据都是本地的。例如,当你的喜好和兴趣被用来更准确地为你投放广告时,它们是最有价值的。如果你的数据被用来针对其他人,这些数据可能是有用的,但它可能会变得不那么有价值。因此,本地数据的值不仅仅是与本地相关的,而是主要与本地相关的。**

建立联系

随着数据成为地球上最有价值的资源,这一价值的大部分将来自其在地方一级的应用,无论是在个人、城市还是国家一级。

地方财富的创造与数据所有权密切相关。例如,考虑运输数据。优步和谷歌地图等服务收集了城市内出行者的大量数据。例如,谷歌会让用户选择次优路线来标出他们不太了解的城市部分。这些数据随后被用于改善其服务。谷歌可以告诉你交通延误、公共交通路线、指路、估计行程时间。优步使用类似的数据来预测汽车需求,将客户的旅程与理想的司机联系起来,从而确保司机最终到达满足预测需求的最佳地点。

这里发生了很多事。首先,所有这些数据都是本地的。虽然了解伦敦的交通模式可能有助于测试以巴黎为模型的机器学习算法,但没有用户能够用伦敦地图在巴黎导航。

其次,所有这些数据都是在本地生成的。这在谷歌和次优方向的案例中很明显,但也有不太明显的来源。例如,如果每天有 1000 人在同一条街上开车,谷歌将能够构建一个旅行时间的正态分布,并预测这条街何时最繁忙。然后,通勤者正在生成关于他们的本地环境的数据,这些数据被非本地实体捕获。

第三,考虑数据访问。用户不直接访问这些数据,而是通过应用程序体验这些数据。这对普通人来说是好事,但人们应该想知道,为什么像优步这样遥远的公司比城市办公室的民选官员更了解和控制一个城市的交通网络。

提取,血统

这些数据的价值在本地产生,但流向拥有和控制这些数据的人。这些数据所有者(如谷歌和优步)可能不是本地人,也不太可能在城市的交通网络中有任何既得利益。例如,即使网络非常差,这些服务仍然可以具有竞争力,因为它们更了解差的网络。他们的优势不是来自投资,而是来自数据的提取和数据创造的价值机会。

地方政府没有理由不收集和分析这些数据,也没有任何东西阻止他们创建自己的应用程序来传递这些服务。通过让本地机构管理本地数据,这些数据被那些对其有既得利益的人使用,同时这些数据的价值仍然由本地持有。

然而,有人可能会争辩说,价值总是本地拥有的——它是用户从服务中体验到的便利。但是,是吗?例如,虽然谷歌可能不会对他们的服务收费,但他们确实会用他们的服务做广告。例如,在谷歌地图上,一家企业可以付费出现在地图上。如果本地数据归本地所有,广告可能会被取消,或者——更有可能的情况是——向谷歌付费让其出现在地图上的本地企业可能会向当地政府付费(可能会降低费率),从而将财富留在当地经济中。

我们还应该记住,地方政府不是一个盈利企业。随着利润从桌面上消失,本地数据可以得到不同的分析,释放出新的价值来源。例如,谷歌没有从利用当地数据规划更好的公交路线中获利,但当地政府肯定会从这些见解中发现价值。

数据所有权的新模式

目前,对数据所有权新模式的研究确实令人兴奋。不管是好是坏,我们当前的数据所有权自由放任模式正在受到挑战,像 T2 开放数据倡议这样的组织已经开始在替代方法方面做了出色的工作,比如数据信托。

数据信托只是一种模式,其中包括访问和应用在内的数据管理任务交给了一组专家受托人。我们可能会看到数据合作社的建立(个人汇集他们的数据,所有人分享它创造的价值)或数据共享(个人汇集他们的数据,任何人都可以访问)。我们甚至可能会看到更大的项目的建立,如集体透明(本质上,一个大规模的数据共享),可能通过区块链技术来促进。

这些模型表明,有可能以不同的方式想象数据所有权,而本地财富创造展示了本地数据的本地所有权可以带来的优势。尽管硅谷服务如此便利,但没有理由相信我们不能在地方层面实现同样的(如果不是更好的话)目标,创造财富和新的见解,造福当地经济和人民。

局部模型解释:介绍

原文:https://towardsdatascience.com/local-model-interpretation-an-introduction-90d039fbef8d?source=collection_archive---------17-----------------------

本文是我关于模型可解释性和可解释人工智能系列文章的延续。如果你还没有读过前两篇文章,我强烈推荐你去读一读。

本系列的第一篇文章,《机器学习模型解释入门》,涵盖了模型解释的基础知识。第二篇文章,‘动手全球模型解释’,详细介绍了全球模型解释,以及如何使用 Python 将其应用于现实世界的问题。

在本文中,我们将通过深入到本地模型解释来继续我们离开的地方。首先,我们将看看什么是局部模型解释,以及它可以用于什么。然后,我们将深入研究两种最流行的方法的理论,Lime(局部可解释模型不可知解释)和 Shapley 值,并应用它们来获得关于心脏病数据集上的个体预测的信息。

什么是局部模型解释?

局部模型解释是一套旨在回答以下问题的技术:

  • 模型为什么做出这个具体的预测?
  • 这个特定的特征值对预测有什么影响?

使用我们的领域专业知识,结合使用本地模型解释获得的知识,我们可以对我们的模型做出决定,比如它是否适合我们的问题,或者它是否没有按照预期发挥作用。

目前,使用本地模型解释变得越来越重要,因为公司(或个人)必须能够解释他们模型的决策。尤其是当它被用于需要大量信任的领域时,如医药或金融。

LIME(局部可解释的模型不可知解释)

尽管被广泛采用,机器学习模型仍然主要是黑箱。然而,理解预测背后的原因在评估信任时非常重要,如果一个人计划根据预测采取行动,或者在选择是否部署新模型时,信任是最基本的。— 里贝罗、马尔科·图利奥、萨梅尔·辛格和卡洛斯·盖斯特林。“我为什么要相信你?”。

Figure 2: Lime Example

概念和理论

Lime,局部可解释模型不可知,是一种局部模型解释技术,使用局部代理模型来近似底层黑盒模型的预测。

局部代理模型是可解释的模型,如线性回归或决策树,用于解释黑盒模型的单个预测。

Lime 通过从感兴趣的数据点生成新的数据集来训练代理模型。它生成数据集的方式因数据类型而异。目前 Lime 支持文本、图像和表格数据。

对于文本和图像数据,LIME 通过随机打开或关闭单个单词或像素来生成数据集。对于表格数据,LIME 通过单独置换每个要素来创建新样本。

LIME 学习的模型应该是黑盒模型的良好局部近似,但这并不意味着它是良好的全局近似。

优势

LIME 是分析预测的好选择,因为它可以用于任何黑盒模型,无论是深度神经网络还是 SVM。此外,LIME 是唯一适用于表格、文本和图像数据的解释技术之一。

不足之处

感兴趣的数据点的邻域的定义非常模糊,这是一个很大的问题,因为这意味着您必须为大多数应用程序尝试不同的内核设置。

此外,解释可能不稳定,这意味着对非常接近的数据点的解释可能变化很大。

关于 LIME 和可解释人工智能的更多信息,一般来说,请查看 Christoph Molnar 的优秀书籍 T2 的可解释机器学习。

示例和解释

Lime 可以在 Python 中与 Lime 和 Skater 包一起使用,这使得 LIME 与流行的机器学习库(如 Scikit Learn 或 XGBoost )的模型一起使用变得非常容易。在这篇文章中,我将研究心脏病数据集,一个简单的分类数据集。

为了分析像心脏病数据集这样的表格数据集的预测,我们需要创建一个 LimeTabularExplainer。

现在,我们可以使用 explain _ instace 方法来解释单个预测。

Figure 3: Lime Output

这里我们可以清楚地看到哪些特征值影响了预测。对于该数据点,cp 和 oldpeak 值对预测的负面影响最大。

有关如何使用 Lime 的更多示例,请查看自述文件中的“教程和 API”部分。

沙普利值

沙普利值是一种根据玩家对总支出的贡献将支出分配给玩家的方法。但是这和机器学习有什么关系呢?

概观

在机器学习的情况下,“游戏”是对数据点的预测任务。“增益”是预测减去所有实例的平均预测,而“玩家”是数据点的特征值。

Shapley 值是一个特性值在所有可能的联合中的平均边际贡献。这是一种解释单个预测的极好方法,因为它不仅给出了每个特征值的贡献,而且这些贡献的大小也是正确的,这与 LIME 等其他技术不同。

要获得更多关于 Shapley 值及其计算方法的信息,请务必查看 Christoph Molnar 的书“可解释的机器学习”的 Shapley 值部分。

优势

当使用 Shapley 值时,预测和平均预测在实例的特征值之间公平分布。这使得 Shapley 值非常适合需要精确解释的情况。此外,Shapley 值是唯一有坚实理论支持的局部解释方法。

不足之处

Shapley 值需要大量的计算时间。大多数情况下,只有近似解是可行的。另一个缺点是,您需要访问数据来计算 Shapley 值。这是因为您需要数据来替换感兴趣的部分实例。只有创建看起来像真实数据实例的数据实例,才能避免这个问题。

示例和解释

我们可以使用由 Scott Lundberg 创建的优秀的 shap (SHapley 附加解释)包在 Python 中使用 Shapley 值。

shap 包可用于多种模型,如树或深度神经网络,以及不同类型的数据,包括表格数据和图像数据。

要对心脏病数据集使用 shap,我们可以创建一个 TreeExplainer,它可以解释像随机森林一样的树模型的预测,然后使用 shap_values 和 force_plot 方法来分析预测。

在图像中,我们可以看到每个特征值如何影响预测。在这种情况下,预测值为 0,这意味着患者没有心脏病。最重要的特征值是 cp=0 和 ca=3。这由箭头的长度表示。

结论

局部模型解释是一套试图帮助我们理解机器学习模型的个体预测的技术。LIME 和 Shapley 值是理解个体预测的两种技术。

Lime 非常适合快速查看模型正在做什么,但是在一致性方面有问题。Shapley value 提供了一个完整的解释,这使得它比 Lime 更精确。

这就是这篇文章的全部内容。如果你有任何问题或者只是想和我聊天,请在下面留下评论或者在社交媒体上联系我。如果你想获得我博客的持续更新,请确保在 Medium 上关注我,并加入我的时事通讯。

具有深度学习的定位和物体检测

原文:https://towardsdatascience.com/localization-and-object-detection-with-deep-learning-67b5aca67f22?source=collection_archive---------22-----------------------

定位和目标检测是计算机视觉中的两个核心任务,因为它们被应用于许多现实世界的应用中,例如自主车辆和机器人。所以,如果你想在这些行业工作,成为一名计算机视觉专家,或者你想开发一个相关的产品,你最好能很好地掌握它们。但是它们是什么呢?物体检测和定位意味着什么?为什么我们把它们归为一类?

重要的事情先来。让我们快速回顾一下最常用的术语及其含义,以避免误解:

  • 分类/识别:给定一幅带有物体的图像,找出那个物体是什么。换句话说,从一组预定义的类别中将其分类。
  • 定位:找到物体所在的位置,并在它周围画一个边界框
  • 物体检测:对图像中的所有物体进行分类检测。给每个对象分配一个类,并围绕它画一个边界框。
  • 语义分割:将图像中的每一个像素按照其上下文分类,这样每一个像素都被分配到一个对象
  • 实例分割:将图像中的每一个像素归为一类,这样每一个像素都被分配给一个对象的不同实例

但是,请记住,这些术语在科学界没有明确的定义,因此您可能会遇到其中一个具有不同含义的术语。在我的理解中,这些是正确的解释。

当我们了解基本术语后,是时候做一些定位和物体检测了。我们怎么做呢?这些年来有许多方法,但自从深度学习到来后,卷积神经网络成为了行业标准。记住我们的目标是对物体进行分类和定位。但是我们确定只有一个物体吗?有没有可能有两个或者三个或者十五个物体?事实上,大多数时候是这样的。

这就是为什么我们可以把我们的问题分成两个不同的问题。在第一种情况下,我们知道对象的数量(我们将该问题称为分类+定位),而在第二种情况下,我们不知道(对象检测)。我将从第一个开始,因为它是最简单的。

斯坦福大学工程学院

分类+本地化

如果我们只有一个对象或者我们知道对象的数量,这实际上是微不足道的。我们可以使用一个卷积神经网络,并训练它不仅对图像进行分类,而且为边界框输出 4 个坐标。这样,我们将本地化视为简单的回归问题

例如,我们可以借用一个经过充分研究的模型,如 ResNet 或 Alexnet,它由一堆卷积、池化和其他层组成,并重新调整全连接层的用途,以产生与类别无关的边界框。它如此简单,以至于我们怀疑它是否会有结果。实际上它在实践中运行得很好。当然,您可以使用它并修改架构以服务于特定的问题或增强其准确性,但主要思想仍然存在。

请务必注意,为了使用这个模型,我们应该有一个训练集,其中包含为类和边界框注释的图像。而且做这样的标注也不是最好玩的。

但是如果我们事先不知道物体的数量呢?然后我们需要进入兔子洞,谈论一些核心的东西。你准备好了吗?之前要不要休息一下?当然,我明白,但是我警告你不要离开。这就是乐趣的开始。

目标检测

我开玩笑的。关于将要讨论的架构没有什么核心的东西。所有的是一些聪明的想法,使系统不能容忍输出的数量,并减少其计算成本。因此,我们不知道图像中对象的确切数量,我们希望对所有对象进行分类,并在它们周围绘制一个边界框。这意味着模型应该输出的坐标数量不是常数。如果图像有两个物体,我们需要 8 个坐标。如果它有 4 个对象,我们需要 16 个。那么我们如何建立这样一个模型呢?

传统计算机视觉的一个关键思想是区域提议。我们使用经典 CV 算法(如边缘和形状检测)生成一组可能包含对象的窗口,并且我们仅将这些窗口(或感兴趣的区域)应用于 CNN。要了解更多关于如何提议区域的信息,请务必查看此处的。

这是一篇基础的论文的基础,该论文介绍了一种叫做 RCNN 的新架构。

R-CNN

给定具有多个对象的图像,我们使用提议方法(在 RCNN 的情况下,这种方法称为选择性搜索)生成一些感兴趣的区域,并将这些区域弯曲成固定的大小。我们将每个区域转发到卷积神经网络(如 AlexNet),它将使用 SVM 为每个区域做出分类决定,并预测每个边界框的回归。该预测是对所提议的区域的校正,该区域可能处于正确的位置,但不是精确的大小和方向。

虽然这个模型产生了很好的结果,但是它有一个主要的问题。这是非常缓慢和计算昂贵的。想象一下,在一般情况下,我们产生 2000 个区域,我们需要将它们存储在磁盘中,我们将它们中的每一个都转发到 CNN 中多次传递,直到它被训练好。为了解决其中的一些问题,该模型的一个改进被称为“快速 RCNN”

快速 RCNN

这个想法很简单。我们将整个图像传递一次,并产生一个特征图,而不是将所有区域逐一传递到卷积层。然后,我们像以前一样(使用一些外部方法)将区域建议投影到特征图上。现在,我们在特征图中有了区域,而不是原始图像,我们可以在一些完全连接的层中转发它们,以输出分类决策和边界框校正。

请注意,区域投影建议是使用特殊层(ROI 层)实现的,它本质上是一种最大池,池大小取决于输入,因此输出总是具有相同的大小。有关 ROI 层的更多详细信息,请查看这篇伟大的文章。

更快的 RCNN

我们可以更进一步。使用从卷积层产生的特征图,我们使用区域提议网络而不是依赖于外部系统来推断区域提议。一旦我们有了这些建议,剩下的过程与 Fast-RCNN 相同(前进到 ROI 层,使用 SVM 分类并预测边界框)。棘手的部分是如何训练整个模型,因为我们有多个任务需要处理:

  1. 区域提议网络应该为每个区域决定它是否包含对象
  2. 并且它需要产生边界框坐标
  3. 整个模型应该对对象进行分类
  4. 并且再次预测边界框偏移

如果你想了解更多关于训练部分的内容,你应该检查一下最初的论文,但是为了给你一个概述,我们需要利用一个多任务损失来包括所有 4 个任务,并将这个损失反向传播到网络。

顾名思义,FasterRCNN 比以前的模型快得多,是大多数现实应用程序的首选。

定位和目标检测是一个非常活跃和有趣的研究领域,因为现实世界中的应用需要在计算机视觉任务(自动驾驶汽车、机器人)中具有出色的性能。公司和大学定期就如何提高准确性提出新的想法。

存在另一类用于定位和对象检测的模型,称为单次检测器,其在过去几年中变得非常流行,因为它们甚至更快并且通常需要更少的计算成本。当然,它们不太精确,但它们非常适合嵌入式系统和类似的耗电应用。

但是要了解更多,你必须等待第 2 部分…

如果您有任何想法、评论、问题或者您只想了解我的最新内容,请随时在LinkedinTwitterinsta gramGithub或在我的

原载于 2019 年 3 月 25 日sergioskar . github . io

使用自定义视觉人工智能中的对象检测来定位和识别蜂窝单元

原文:https://towardsdatascience.com/locating-and-identifying-honeycomb-cells-using-object-detection-in-custom-vision-ai-9b314532791b?source=collection_archive---------33-----------------------

由智商生物项目在 UPR-RP 举办的智商黑客马拉松参赛

Photo by Scott Hogan on Unsplash

从 7 月 31 日到 8 月 1 日,波多黎各有一场黑客马拉松,由跨学科定量生物学项目在波多黎各大学里约皮得拉斯校区 (UPRRP)主办。黑客马拉松在波多黎各 Bayamon 的一个合作空间 Engine 4 举行。

Hackathon Flyer

黑客马拉松的重点是寻找跨学科和定量(IQ)生物学问题的创造性解决方案。

我和Alejandro Armas(Alejandro Armas)Carlos Navea和 Giovanni Cortes 一起参加了这次黑客马拉松,他们都是 IQ 生物学暑期实习的聪明参与者。我们的团队名称是“蜂巢”。我们得到了 UPRRP 大学计算机科学系副教授雷米·梅里特教授的指导。

我们解决了两个问题:

  • 通过 webapp 简化研究人员的数据输入。
  • 使用对象检测自动蜂窝单元识别和计数。

本文主要讨论后者。

我们为黑客马拉松实现的代码可以在 https://github.com/alejandroarmas/PRhacks 的 GitHub 上找到。用于准备物体检测数据的代码在mlTool文件夹中。

问题陈述

波多黎各大学蜜蜂研究人员的一些职责是拍摄蜂窝并记录与蜂窝相关的各种变量,例如:蜂窝中有多少花蜜,有多少蜜蜂,有多少花粉,有多少幼虫,有多少密封的巢(容纳蜂蜜),有多少蛹。由于计算这些的任务过于繁重,研究人员记录了这些近似值(例如,5%的蜂巢有蜂蜜)。

Types of honeycomb cells. Glossy cells contain nectar. Sealed cells contain honey.

对于黑客马拉松,我们选择使用对象检测来解决计数问题。通过对象检测,我们可以自动识别不同类型的细胞并进行计数,以便研究人员可以记录这些细胞的准确数据。

对象检测是深度学习和计算机视觉的一个分支,涉及自动识别图像中感兴趣的项目,并确定围绕它们的矩形边界框(bbox)的坐标。然后可以使用坐标画出边界框。

Object detection example. (source)

数据注释

One of the images taken by the researchers. We did not annotate it completely due to time constraints.

在机器学习(ML)和深度学习(DL)中,对数据进行注释或标记意味着将其标记为属于某一类。当使用对象检测时,这意味着确定围绕图像中感兴趣区域的矩形的坐标(或者在使用注释工具时围绕感兴趣区域绘制矩形),并保存矩形的坐标和该区域所属的类。我们希望 ML 或 DL 模型从带注释/标签的数据中学习,并用这些注释/标签预测新数据。

One labeled cell.

我们在研究人员使用名为 labelImg 的开源标记工具拍摄的蜂窝图像中标记了花蜜和空细胞,该工具将注释保存到 XML 文件中。

LabelImg’s GUI.

我们只关注 nectar 和 empty 类,以便在实现解决方案之前不要花太多时间来注释数据,还因为它们是我们注释的蜂巢中最丰富的单元。最理想的情况是,我们应该标记所有的种类:密封的、空的、花蜜的、蜜蜂的、蛹的、幼虫的和花粉的。

Preview of one of the label XML files. Bounding box coordinates are within the

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/71392.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

.Net PdfiumViewer 打印时无法渲染电子签名问题的解决方法

需要修改源代码或直接反编译动态库修改 PdfPrintDocument.RenderPage 方法,本文仅介绍修改动态库。转载请标明原出处:https://www.cnblogs.com/crpfs/p/18463735 1. 先决条件 本文修改的动态库是从如下的 NuGet 包中获取的:如果使用的是 Visual Studio 中的 NuGet 包管理器获…

现代化 React UI 库:Material-UI 详解!

随着 React 在前端开发中的流行,越来越多的 UI 框架和库开始涌现,以帮助开发者更高效地构建现代化、响应式的用户界面。其中,Material-UI 是基于 Google Material Design 规范设计的一款开源 React UI 库,Github Star高达 94K,凭借其丰富的组件库、灵活的定制化选项以及无…

将html元素保存为图片

初始需求是echarts绘制的图表保存为图片, 后来发现,echarts图标之外,还有一个参数input/button也要放到图片中 于是,技术实现从简单的《echarts导出为图片》 变成了较为复杂的《html元素导出为图片》先放出已经实现的《echarts导出为图片》的代码,// 导出 图片generatePic…

第十期机器学习基础 02注意力机制和Transformer/Bert

一:注意力机制 (一)前提背景 1.人类的选择性视觉注意力 视觉注意力机制是人类视觉所特有的大脑信号处理机制。人类视觉通过快速扫描全局图像,获得需要重点关注的目标区域,也就是一般所说的注意力焦点,而后对这一区域投入更多注意力资源,以获取更多所需要关注目标的细节信…

查找大量时序遥感文件缺失、不连贯的成像日期:Python代码

本文介绍批量下载大量多时相的遥感影像文件后,基于Python语言与每一景遥感影像文件的文件名,对这些已下载的影像文件加以缺失情况的核对,并自动统计、列出未下载影像所对应的时相的方法~本文介绍批量下载大量多时相的遥感影像文件后,基于Python语言与每一景遥感影像文件的文…

AI智能照片放大软件--Topaz Gigapixel AI macOS苹果电脑安装包(含激活秘钥)

Topaz Gigapixel AI是一款功能强大的图像无损放大工具,具有以下功能特色:首先,它利用人工智能技术,能自动识别并增强图像中的细节,包括纹理、边缘等,同时减少噪声,使图像更加清晰细腻。其次,软件支持超高放大倍率,最高可达600%,且放大后的图像质量依然保持优秀。此外…

四、Spring Boot集成Spring Security之认证流程

Spring Security详细认证过程:包括登录时每个过滤器处理流程及业务处理和登出时每个过滤器处理流程及业务处理二、概要说明本文主要介绍登录登出业务流程,所以使用基于内存的用户名密码,暂不介绍授权相关内容,后续会详细介绍基于数据库的认证及授权 如何查看基于内存的默认…