用 Python 实现金融中的大数定律
大数定律:
你有没有想过赌场是怎么赚钱的?大数定律从统计学的早期阶段开始就是一个众所周知的概念。但是,我们不仅仅在统计学中发现它的用途。它的重要性体现在生活的各个领域,从赌博到汽车保险定价,甚至是猜测谁会赢得选举。
鸣谢:图片来自 Unsplash
大数定律指出,随着试验或观察次数的增加,观察到的或实际的概率接近预期的均值或理论值。这意味着随着样本量的增加,样本的平均值越来越接近总人口的平均值。
大数定律在从金融到商业到统计的各种分析领域都有应用。例如,在商业环境中,增长率往往是大数法则的代表。这表现为增长率或多或少地与经济增长率趋同。类似的情况也出现在金融领域,市值巨大的公司或多或少变得停滞不前,看不到之前观察到的增长。
理解这个概念的一个非常有力且被广泛引用的例子是观察硬币的翻转。最初的几次投掷不一定有一半的机会是正面或反面。对于一个结果可能有更高的累积概率。因此,相对频率可能与预期的 50%相差很远,比如说 10、20、50、100 次翻转。但另一方面,假设我们像掷硬币 a 一样掷 1000 次或 100000 次,那么得到正面的累积概率就更接近 50%的期望值。
我试图通过用 python 写代码来模拟这种情况。
在观察不同翻转次数的累积概率时,我们看到当整体翻转随着分布接近正态分布而开始变高时,概率收敛到期望值 50.0%。
仅仅 10 次翻转,我们就能看到以下内容:
抛 10 次硬币正面朝上的概率
对于 1000 次翻转,我们会看到以下内容:
投掷硬币 1000 次,正面集中到 50%的概率
因此,大数定律有助于我们理解为什么不能只相信一个结果。这就是为什么我们需要对从样本人群中得到的观察结果持怀疑态度,尤其是那些低数量的人群。
平均法则:
有时人们倾向于把大数定律和平均数定律互换。他们不一样。大数定律是一个数学定理,随着试验次数的增加(大型试验),理论上结果必然会收敛到预期的平均值,而平均定律或多或少是一个门外汉术语,认为试验的结果会在一个小样本内达到平衡。这不是数学原理,而是一厢情愿的想法。而这个非常糟糕的统计数据导致了‘赌徒谬误’的概念。
赌徒的谬误:
这种谬误是一种信念,认为某个结果可能会发生,因为错误地理解了平均法则的基本原理。这导致“赌徒”相信,由于特定的结果最近没有发生,所以它现在有可能发生,从而达到平均。人们需要理解,各种结果的发生之间没有关系,它们是相互独立的。
虽然大数定律将有助于赌场在大量旋转中获得收益,即使它在轮盘赌的单次或几次旋转中失败,但是平均定律将不会帮助赌徒,因为假设轮盘现在将落在黑色上,就像它以前几次落在红色上一样。因此它纯粹是随机的,没有真正的平均律概念。
大数定律在交易和金融中的应用:
大数定律在贸易和金融领域也有应用。它表明,大量具有较高夏普比率(回报风险比)的交易往往比少量交易更有效。
正如乔治索罗斯(George Soros)所言,重要的不是你是对是错,而是正确时你会赚多少,错误时你会亏多少,这让你的策略更有针对性。这归结为有效风险管理的原因。在这种情况下,根据大数定律,一个交易者可能大部分时间都是错的,但仍然是盈利的。
在很多这样的场景中,最大的挑战是理解一段时间实际上有多长。经验告诉我们,尽可能长时间的回溯测试会让我们更接近平均年化回报。让我们以低频交易策略为例。让我们试着去理解实现一个更真实的夏普战略和它的方差需要多长时间。
让我们假设一个经过回溯测试的策略的真实夏普比率为 2(假设这是低频交易的平均值)。让我们在大约 2 个月的 40 天交易期内试着认识到这一点。假设正态分布的平均回报率为 0.1%,让我们模拟一下,看看夏普比率随着交易(或试验)次数的增加而变化。
它的 python 代码如下。
只做了 15 笔交易,我们看到以下夏普比率:
进行了 15 次交易
上面的直方图告诉我们,只要有几笔交易,就会得到比回溯测试更低的夏普比率。
通过 500 笔交易,我们观察到以下情况:
500 笔交易
在 2500 笔交易中,我们看到了以下情况:
2500 笔交易
从上面的图表中,我们可以清楚地看到,随着轨迹的减少,我们可能会观察到更多的损失。但是最终,随着试验的不断增加,夏普比率趋向于回溯测试的数字(通过趋向于正态分布)。这里的诀窍是尽可能多地参与大量的试验。
行为心理学对 LLN 的入侵:
大数定律的关键在于,首先,一次又一次地交易,其次,不要因为一次又一次地改变潜在的假设而中断交易。交易者确实倾向于改变策略,希望战胜市场,因此很难保持自我控制。在不气馁的情况下尽可能多的交易是一个非常困难的任务。因此,“耐心和财务”这个概念变得比以往任何时候都重要。这个信息超载的时代是一把双刃剑。它一方面帮助长期投资者做出明智的选择,但同时也干扰了另一个不耐烦的投资者对策略进行定期评估。这使投资者倾向于选择正确的股票,但在错误的时机退出交易策略,甚至在很早的时候退出交易游戏。
离别的思念:
无论从回溯测试中得出的交易策略听起来有多好,它都取决于你无数次的执行和实践。交易是一份需要正确的技术和技能,经验和更重要的不断尝试的工作。
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
走向一个特定法律领域的伯特?
法律行业的特定领域 BERT
来源:大英图书馆
谷歌来自变形金刚的双向编码器表示(BERT)是 2018 年开发的大规模预训练自动编码语言模型。它的发展被描述为 NLP 社区的“ImageNet 时刻”,主要是因为 BERT 在执行下游 NLP 语言理解任务时非常熟练,只需要很少的反向传播和微调(通常只有 2-4 个时期)。
对于上下文,传统的单词嵌入(例如 word2vec 和 GloVe)是非上下文的。they用单个静态向量表示每个单词令牌,通过单词共现而不是单词的顺序上下文来学习。当一词多义时(即同一个词有多个不同的意思),这可能会有问题,这在法律中是很常见的。
来源:谷歌开发者
例如,单个静态上下文无关向量将用于表示句子“柠檬是酸的”和“那辆车是柠檬”中的单词“柠檬”(即,对柠檬法则的有趣引用,该法则在新车被证明有缺陷时保护消费者)。
相比之下,BERT 是一个上下文模型,它基于每个单词周围的单词生成特定于上下文的表示。有趣的是,Ethayarajh (2019)表明,BERT 不会为每个词义创建一个“柠檬”的表示(左选项),而是会创建无限多个“柠檬”的表示,每个表示都高度特定于其上下文(右选项)。这意味着不是生成单个密集向量来表示令牌“lemon”,而是将令牌动态地表示为“______ 是酸的”和“那辆车是 _____”。
伯特捕捉语言多义性的能力尤其适用于多义性大量存在的法律领域。例如,法律中的“对价”一词代表契约关系中的互惠理念,与该词通常的含义“考虑周到”有着不同的含义。此外,同一术语在成文法和判例法中可以有多种定义。例如,“工人”一词在欧盟法律中有四种不同的定义,甚至在同一份文件中也可以用来指不同种类的工人。因此,语境语言模型的发展对法律人工智能领域具有重要意义。
BERT 体系结构的技术细节超出了本文的范围(已经有大量文章讨论过)。然而,值得注意的是,BERT 的关键创新之一是它的双向性,即它克服了顺序文本解析的传统问题。值得注意的是,这个上下文中的双向并不意味着在顺序意义上的双向(即同时从左到右和从右到左进行解析),而是在同时意义上的双向(即它同时从所有层中的令牌的左右上下文中学习信息)。这是通过使用像掩蔽 LMs (MLMs)和下一句预测(NSP)这样的方法来实现的,以获得更好的上下文单词嵌入结果。
特定领域的优势
来源:大英百科全书
虽然 BERT 在执行一般语言表示任务方面非常有效,但问题是——在未标记的通用维基百科和开源文章上接受训练——它缺乏特定领域的知识。这是一个重要的警告,因为语言模型只能和它的语料库一样好。打个比方,将一个普通的伯特模型应用于特定法律领域的问题,可能相当于让一个文科生去解决一个法律问题,而不是让一个学了多年法律知识的法律学生去解决。这是有问题的,因为在一般开源语料库(例如维基百科和新闻文章)中发现的语言和法律语言之间有很多脱节,这些语言可能是深奥的和基于拉丁语的。
虽然在撰写本文时尚未开发出法律领域特定的 BERT 模型,但已经开发的其他领域特定的 BERT 的示例包括 BioBERT(生物医学科学)、SciBERT(科学出版物)、FinBERT(金融通讯)和 ClinicalBERT(临床笔记)。尽管它们都具有特定于领域的 BERTs 的相似性,但是它们的体系结构表现出许多关键的不同。
培训特定法律领域的专家
我将探索一些培训特定领域业务技术人员的方法:
完全预先训练伯特
这包括用大规模未标记的法律语料库(例如,法令、判例)完全重做 BERT 的预训练过程。从这个意义上说,特定领域的知识将在预培训过程中注入。这是 SCIVOCAB SciBERT 采用的方法。
虽然这确实大大提高了 BERT 在特定领域任务上的性能,但关键问题是完成重新训练所需的时间、成本和数据量可能太大而不可行。BERT-Base 本身是一个具有 12 个堆叠层和大约 1.1 亿个权重/参数的神经网络,其预训练语料库需要 33 亿个令牌。重新训练特定领域的 BERT 将需要类似数量的训练数据(例如,SciBERT 使用了 31.7 亿个令牌)。训练该模型需要一周或更长时间(例如,SCIVOCAB SciBERTs 在 v3 TPU 上训练需要一周时间),并且成本极高,这对于一般企业来说根本不可行。
进一步预培训 BERT
因此,一种折衷方案可能是不完全重新训练 BERT,而是从 BERT 初始化权重,并用合法的特定领域数据进一步对其进行预训练。这已被证明可以提高 BERT 的性能,Sun (2019)表明,经过进一步预训练的模型在所有七个数据集上的表现都优于原始的 BERT-Base 模型。
这似乎是最受欢迎的方法,用于 BioBERT、BASEVOCAB SciBERT 和 FinBERT。研究人员没有完全从头开始重新训练,而是用从 BERT-Base 学习到的权重初始化新的 BERT 模型,然后在特定领域的文本上训练它(例如 PubMed abstracts 和 BioBERT 的 PMC 全文文章)。Lee 等人(2020)报告说,BioBERT 在所有数据集上取得了比 BERT 更高的 F1、精度和召回分数。同样,Beltagy 等人(2019)报告称,SciBert 在生物医学、计算机科学和多领域任务上表现出色。
来源:李等人(2019)
微调伯特
另一个更简单的选择是使用预先训练的 BERT,但在下游 NLP 任务中使用特定于法律领域的语料库对其进行微调。微调的概念来自迁移学习的领域,简单地说,这意味着采用一个旨在解决任务 x 的模型,并将其重新用于解决任务 y 。在实践中,它通常意味着采用预训练的 BERT 模型,并在最后添加一个未训练神经元的额外输出层,然后使用带标签的法律语料库进行训练(微调通常是一项监督任务)。在对特定于领域的数据进行微调之后,得到的模型将具有更新的权重,更接近于目标领域的特征和词汇
这种方法的优点是,它需要的数据少得多,而且训练起来明显更快、更便宜。鉴于 BERT-Base 的预训练已经编码了一般领域中大多数单词的知识,它只需要一些调整就可以适应法律上下文的功能。微调通常只需要 2-4 个时期(几分钟的事情),而不是几周的时间跨度。这种方法还需要更少的数据(尽管它通常需要带标签的数据),这使它更可行。
此外,如果需要,微调可以结合特定领域的预训练来完成,即它们不是互斥的方法。例如,BioBERT 首先接受生物医学领域特定语料库的预训练,然后在生物医学文本挖掘任务上进行微调,如命名实体识别、关系提取和 QA。
结论
随着最近对像 OpenAI 的 GPT-3 这样的超大规模模型的大肆宣传,最初围绕 BERT 的兴奋似乎有些消退。然而,值得记住的是,BERT 仍然是一个非常强大和敏捷的模型,可以说它有更多的实际应用。从特定领域的 BERT(如 SciBERT 和 BioBERT)的经验来看,在特定领域的语料库上微调和/或预训练 BERT 可能会提高法律 NLP 任务的性能。为此,根据研究人员的时间和金钱资源,有各种方法来改善和调整伯特的表现。
分层标签传播算法
一种社区发现算法
在运行分层标签传播算法之后,具有可变混合参数(μ)和固定节点数以及平均节点度的 lanchi netti-Fortunato-radic chi 基准合成网络。
分层标签传播算法(LLP) [1]的发展强烈地基于旧的标签传播(LP) [2]。后者从给网络中的每个节点分配不同的社区开始。然后,在每一轮的开始,节点的顺序被随机化。在每一轮中,每个节点将被分配在直接邻居中更有代表性的社区。只要社区没有发生变化,或者达到给定的迭代次数,LP 就结束。它不依赖于任何目标函数的优化,并且不需要关于网络中存在的社区的先验信息(无监督的)。虽然,可以用近似集输入(半监督)。根据定义,该算法本质上是局部的,在边的数量上是(近似)线性的,并且在图中需要很少的通道。这些是允许对真实网络进行分析的基本特征。寻找最优划分的问题已经被证明等价于寻找动力学 Potts 模型[1]的哈密顿量的局部最小值。虽然这个问题有一个平凡的全局最优解,将整个网络视为一个集群,但这不是我们感兴趣的。LP 避免了这样的解决方案,因为本地搜索的固有动态性。虽然这通常被认为是一个缺点,但在这种情况下,它是 LP 算法工作的一个基本特征。
尽管使用了类似的方法,LLP 不仅考虑了邻居中的节点,还考虑了剩余网络中的节点。迭代过程是一样的,区别在于它优化的值。在这种情况下,分配的社区将最大化:
𝑘𝑖是在给定节点的邻域中带有标签𝜆𝑖的节点的数量,而𝑣𝑖是整个图中以相同方式标记的总数。𝛾是分辨率参数,通过其在整个网络中的通常存在来缓冲属于邻域中给定社区的节点的数量。每当接近 0 时,LLP 就减少到 LP。预计对于较低的𝛾值,该算法将突出显示较少、较大和稀疏的聚类。对于更高的值,簇变得更小、更密集并增加它们的数量。可以说,没有一个先验的度量来说明哪个值对被分析的网络更好。算法 1 中 LLP 的伪代码。
与 LLP 类似,已经提出了其他算法,它们执行相同的步骤序列,但最大化不同的值,如模块化。
利用多个处理器的并行实现可以显著地加速该算法在我们的机器上的执行。
参考
[1] P. Boldi,M. Rosa,M. Santini 和 S. Vigna,“分层标签传播:用于压缩社交网络的多分辨率无坐标排序”,载于 WWW '11 第 20 届国际万维网会议论文集,2011 年;
[2] N. Raghavan,R. Albert 和 s .鸠摩罗王,“检测大规模网络中社区结构的近线性时间算法”,*物理评论 E 25 周年里程碑,*第 76 卷第 3 期,2007 年。
数据层:背景如何帮助做出更好的决策
2012 年,《哈佛商业评论》宣布数据科学家的角色是“21 世纪最性感的工作”。Glassdoor 在 2016 年将数据科学家列为他们年度最佳工作名单的第一位,这更是火上浇油。他们 2019 年的头号工作?你猜对了:数据科学家。那么,这些“受过培训、有好奇心在大数据世界中做出发现的高级专业人员”到底有什么特别性感的地方呢?首先,现在的数据比以往任何时候都多,而且大多数数据都是最近才创建的。2017 年,数据管理平台 Domo 估计,所有数据中有 90%是在前两年内创建的——每天有 2.5 万亿字节的数据*。难怪公司对如何最好地利用这些前所未有的数据感兴趣。然而,大量的数据不一定是相关的数据。这种不一致导致公司在过去十年中争相实施程序来解释这些数据并产生可操作的见解。正如杜克大学经济学家丹·艾瑞里在 2013 年所说:*
“大数据就像青少年性行为:每个人都在谈论它,没有人真正知道如何去做,每个人都认为其他人都在做,所以每个人都声称自己在做……”
因此,数据科学家对这些海量信息的理解能力变得非常有价值。通过绘制不同数据点之间的联系,并评估这些数据为何重要的更大图景,数据科学家能够帮助公司获得有意义的见解,从而做出更好的决策。
为什么没有上下文数据毫无意义
从表面上看,数据只是数字、单词等的集合。只有当数据与上下文一起呈现时,它才变得有意义。以谷歌趋势图为例:
没有任何语境,完全没有意义。这个频率肯定有周期性的东西,但是还不完全清楚这个频率是什么或者为什么会发生,或者它为什么重要。现在,如果我告诉你趋势图是关于搜索词“馅饼”的,你可以开始对数据得出有意义的结论:也就是说,每年都有一些东西导致搜索词“馅饼”的搜索量激增。如果我继续提供上下文线索,数据会变得越来越相关。例如,请允许我进一步澄清,搜索仅限于美国,峰值似乎集中在一个主要峰值和一个次要峰值上:
知道了在美国对“馅饼”的搜索在每年的 11 月达到高峰,我们就可以开始推断这些数据意味着什么。在这一点上,你可能会对自己说“很明显,在感恩节前后搜索馅饼的次数会激增。”然而,这正是上下文变得至关重要的地方。如果你在美国出生和长大,你很可能知道感恩节在 11 月,而且馅饼经常在感恩节供应,因此馅饼搜索的激增与人们计划感恩节庆祝活动直接相关。然而,如果你不是在美国长大的,你可能缺乏上下文参考来理解为什么馅饼搜索在美国的 11 月达到高峰。
那么三月份的小高峰是怎么回事呢?在这一点上,你可能已经猜到了,3 月份的峰值很可能是每年 3 月 14 日(3.14…明白吗?).同样,这些数据只对那些拥有提供相关性的适当上下文的人有洞察力。如果你从未听说过圆周率日,3 月份的数据峰值可能不会给你提供太多的见解。
有了适当的上下文,可以根据数据做出决策,也可以根据数据的含义做出决策。在我们的 pie 示例中,假设的 pie 制造商的 CMO 将配备有关于流量习惯的信息(数据),以及与这些习惯相关的热门话题(上下文)。总之,这可以支持广告活动,其中数据通知何时以及如何到达消费者,并且上下文通知他们可能发现相关和有趣的内容。
值得一提的是,这个例子过于简化,可能需要通过定量和定性手段获得额外的数据和背景。无论如何,希望这些性感的数据科学家能够通过研究趋势和背景线索来帮助改善决策,这一点变得越来越清楚。可能不太清楚的是,他们如何可能开始用 2.5 万亿字节的日常数据做到这一点。这就是技术进入等式的地方。
计算机如何帮助导航上下文线索
在我们进入芯片和算法之前,让我们花点时间想想是什么让数据科学家能够如此出色地完成他们的工作。广义地说,他们都可以使用现存的最强大的计算机:人脑。神经科学家 Bobby Kasthuri 博士致力于“以前所未有的规模绘制大脑地图”,他估计一个人的大脑有大约 1000 亿个连接连接超过 1000 亿个神经元。正是这种极端的复杂性导致了意识和认知。实际上,这种复杂性和力量是人类之所以为人的原因。生物过程和它们影响的高级行为特征之间的这种分离最终是神经科学和认知科学之间的差异。这一切都回避了一个问题:如果我们能制造一台像人脑一样复杂的计算机,它能“思考”吗?
截至这篇论文发表时,人类大脑的复杂程度比我们可用的最强大的计算机还要高几个数量级,因此,真正的计算机认知距离现实还有很长的路要走。如果我们看看神经科学/认知科学的关系,电气工程和计算机科学之间有明显的相似之处。计算机行为背后的理论(计算机科学)受限于硬件的实际约束(电子工程)。因此,计算机需要人类的输入和指令才能以某种方式运行。换句话说,它们需要数据(输入)和上下文(指令)来生成一些有价值的输出。数据科学家可以利用他们的经验、洞察力、研究和批判性思维来帮助计算机“学习”与给定数据集相关的上下文。反过来,计算机可以在给定的上下文中快速独立地处理这些数据。这就是机器学习的有效工作方式。一旦经过训练,计算机可以接受新的输入,并确定该输入是否与已建立的上下文匹配,并相应地采取行动,提供根据已建立的上下文理解进行判断的新输出。这个循环本质上就是我们所说的人工智能。
尽管有了这些基本的工具,计算机离思考还有很长的路要走。正如柳文欢·埃齐奥尼在《T4》中所说的,如何知道人工智能是否会毁灭文明:
机器只拥有人类丰富多样的学习能力的一小部分。说机器学习就像说小企鹅知道如何捕鱼。事实是,成年企鹅会游泳,捕捉鱼,消化鱼,吐出到它们的嘴里,然后把食物放进它们孩子的嘴里。人工智能同样被人类科学家和工程师填鸭式喂养。
与机器学习相反,人类学习将个人动机(“我想独立于父母开车”)映射到战略学习计划(“参加驾驶培训,周末练习”)。一个人制定具体的学习目标(“在平行停车方面变得更好”),收集并标记数据(“这次角度错了”),并融入外部反馈和背景知识(“讲师解释了如何使用侧镜”)。人类识别、框定和塑造学习问题。这些人类的能力没有一项是机器可以远程复制的。机器可以执行超人的统计计算,但这仅仅是学习的最后一英里。"
我们如何利用人工智能做出更好的决策
显然,技术“思考”的能力与我们自己的能力还相差甚远。然而,当我们将人工智能视为改善我们决策方式的几个可用工具之一时,它仍然提供了显著的好处。
如果计算机缺乏真正“思考”和生成战略决策的能力,我们还应该使用人工“智能”这个术语吗?如果我们按照以下定义来考虑人工智能,我会说是的:人工智能是一个依赖人类输入的计算机系统,以便在给定的数据环境下处理可能的输出。没有人类的智能,人工智能是没有意义的。
想想人工智能的这个定义,很明显,任何输出的价值都将受到数据准确性和上下文相关性的限制。此外,上下文的范围将是“影响”任何结果的最大驱动因素。如果我们要接受人工智能的功能至少类似于人类智能,尽管功能远不如人类智能,那么我们应该首先考虑如何利用我们自己的智能来为决策提供信息,这是有道理的。考虑一下机器学习公司 OnCorps 的创始人兼首席执行官、埃森哲前首席技术策略师 Bob Suh 的话:
情商高的人优势明显。他们学习其他人的模式,知道如何传达同理心,并根据他们对他人反应的预期,仔细权衡回应,选择最佳回应。情商帮助领导者做出更好的决策,产生更好的结果。
考虑到情商的这一定义,模式是从经过仔细权衡(上下文)的响应(数据)中得出的。所有这些都符合我们之前对机器学习的定义。主要的补充是在 Suh 的描述中,高情商的人知道“如何传达同理心”这是人类的理解和人工智能的输出可以一起行动,以更好地做出决策的地方。
最普遍接受的同理心定义(也是 Suh 提到的与高情商个体相关的定义)是“对他人态度的心理认同或替代体验。”较少讨论的是移情的第二个定义,它是“赋予一个物体,如一个自然物体或艺术品,自身存在的情感或态度的想象力。”如果我们认为“要做的决定”是一个我们可以归因于自己的感觉或态度的对象,那么我们就可以看到决策是一系列的行动,在这些行动中,我们将自己的情感背景用于最终结果。这就是人脑的复杂性取代计算机能力的地方,并允许我们做出比计算机本身更复杂的决定。
避免语境偏见的危险
在我们上面提到的例子中,正是个人情绪和经历的可变性最终允许了复杂的决策。每个人都会对输入指导和输出评估做出不同的、略有细微差别的解释。因此,考虑用于训练 AI 的上下文如何导致有偏见的结果是至关重要的。虽然个人可能会对如何解释和使用任何人工智能输出产生明显的偏见,但本节将特别关注输入偏见如何导致重大但往往隐藏的问题。为什么?因为如果你的任务是仅仅基于输出做出决策,你可能会缺乏任何关于是什么形成了输入的背景,这可能会导致你对数据的完全不正确的解释。
历史偏见是有偏见的最明显的例子之一。当由于文化、法律和/或系统原因,数据集被限制在一个小的上下文子集内,可能不再有效时,就会出现这种情况。举个例子,广泛报道的问题与亚马逊试图创建一个人工智能算法来审查新员工并为公司的发展职位找到最佳候选人有关。一旦实施,结果明显倾向于推荐男性候选人而不是女性候选人。原因?亚马逊使用十年的应用程序作为成功/失败的背景来建立这个系统。问题是绝大多数技术职位的候选人和雇员都是男性。虽然众所周知,历史上(以及现在)技术行业的工作都是由男性主导的,但任何数据模型都必须考虑这一历史背景,以防止有偏见的招聘决策。
偏置结果的另一个例子涉及先前关于人类经验和视角的讨论,用于向数据集提供上下文。有一种现象与人类所说的他们的感受/想法和他们的大脑实际反应之间的差异有关。正如我们之前讨论的,我们可以将处理(神经科学)与输出(认知)分开。在许多情况下,我们的生活经历导致我们(通常是下意识地)改变我们的输出,以满足我们认为可以接受的东西(社会的、情境的或其他的)。情感本质上是主观的。这当然会影响我们训练数据模型的方式,这会给任何人工智能输出增加偏见。
如果我们认识到背景主观性会固有地偏向数据训练,那么我们必须检查这对基于这些主观模型的现实世界决策有什么潜在影响。2016 年 5 月,ProPublica 对语境偏见的影响进行了最早和最彻底的调查。他们对美国各地法庭使用的“风险评估”算法进行了彻底的分析,以确定通过司法系统的个人再犯的风险。最终,他们发现这些算法明显更有可能将黑人被告识别为比白人被告具有更高的再犯风险,这导致这些人的刑期明显更高。问题是这与实际的再犯率没有关联。白人被告与其实际比率相比长期得分较低,而黑人被告与其实际比率相比长期得分较高。事实上,种族间的再犯率比分数显示的要接近得多。虽然正在讨论的算法的具体设计是专有的,因此我们无法最终确定其失败的确切原因,但它揭示了当我们“出错”时可能发生的可怕后果。人们失去了多年的生命,因为没有考虑到背景偏见可能会不正确地扭曲输出。
如果有空间对影响人工智能输出的背景偏见产生如此重大的、潜在的改变生活的后果,它回避了问题:我们到底应该使用人工智能吗?与人类大脑相比,它是否仍然过于初级,无法为我们提供任何有意义的东西?简而言之,不,我们不应该放弃人工智能带来的潜在好处。然而,我们必须时刻注意技术如何将上下文应用于数据,上下文如何增加偏差,以及这对未来的任何输出意味着什么。如果我们认识到人工智能对有什么好处:也就是说,它只是我们可以用来补充决策过程的许多工具之一,那么我们就可以开始利用我们个人和商业生活中的潜在重大利益。
如何通过自动化变得更棒并节省时间
我写 Python 字数统计脚本时的一个实际用例
和很多开发者一样,我很懒。我珍惜自己的时间,也珍惜亲人的时间。
当我看到一个朋友一遍又一遍地重复一项乏味的任务时,我感到沮丧,就好像这是我的负担一样。因为我讨厌重复的任务,所以我想找到一种自动化它们的方法。
拥抱懒惰
自动化包括给机器一套指令,让它替你做所有的重活。都是关于效率。我跟你说实话:我是一名专门从事移动开发的程序员。我对脚本语言没有特别的了解。
不久前,我看到一篇文章,这篇文章启发了我如何以及为什么我们可以让生活变得更轻松。
“编程最好的部分是看到机器做一些有用的事情的胜利。用…自动化枯燥的工作
automatetheboringstuff.com](https://automatetheboringstuff.com/)
这值得痛苦吗?
记住,大多数开发人员都很懒。写剧本对我来说听起来很痛苦。对你来说也一样。问自己这些问题:你介意重复同样的任务吗?你觉得手工做有价值吗?如果你在这些问题上犹豫不决,考虑投资一些时间在自动化上。
我想和你分享一个故事,这个故事让我为我的朋友写了一个小剧本。我决定选择 Python,因为这是一个发现这种语言的绝佳机会。
字数问题
有一天,女朋友带着任务来找我。她是一名专业内容作家。有时,她碰巧做翻译工作。有一次,一家公司给她发了一个剧本来翻译。以下是一个示例:
Joey and Phoebe meets in a bar
Joey(smiling): [<How're you doing?>]
Phoebe welcomes him with open arms
Phoebe(cheerful): [<Oh! I'm feeling great!>]
注意到文本中的分隔符了吗?该公司突出显示了要翻译的区域。其余的作为额外的信息——对从上下文中选择正确的语气至关重要。工作完成后,她需要将发票寄给公司。因为我的朋友是按单词收费的,她需要计算她翻译了多少单词。
任何文字处理软件都可以帮你统计字数。然而,她不能对整篇文章收费——并不是说她不介意账单。她必须首先排除括号外的内容。可惜公司没有给她提供这样的工具。
当她开始用手数单词时——我们谈论的是 50000 个单词!——我必须在她失去理智之前进行干预。
分析需求
任务很明确:在一个定义的分隔符内计算所有单词。我开始把它分解成更小的步骤:
- 对于所有输入行,提取
[<
和>]
之间的文本。 - 将所有带格式的行合并成一个文本块。
- 把这个模块分成一个单词列表
- 计算列表的长度
考虑到这一点,我准备开始下一阶段。
用脚本自动化
我最终写了这个剧本:
word_counter.py
仅此而已!我承认我花了两个小时才把它放下。但这两个小时花得很值。我很自豪地看到几行代码可以为我的朋友节省这么多时间!她的理智也是!
她只需要将文本插入到inputString
变量中,然后运行脚本来获得字数。
$ python word_counter.py
7 // there are seven words in the example above
对于没有入门的 Python 开发人员,我们来分解一下这段代码。
提取分隔符中的文本
第一步要求我使用正则表达式(Regex)。它们允许我提取符合特定模式的所有行。我以这个结尾:
import relist = re.findall(r'\[\<(.+?)\>\]', inputString)
// ['How're you doing?', 'Oh! I'm feeling great!']
首先,我们必须导入 Regex 库。然后,我们通过从inputString
中找到所有以[<
开头、以>]
结尾的句子来创建一个list
。最后,括号声明我们想要排除分隔符。作为注释,我展示了从本文开头的示例中获得的结果。
从提取的文本创建一个句子
我们要把list
展平成一句话。我们需要将前面的列表加入到一个空字符串中。
subString = " ".join(list).replace('\xc2\xa0', ' ')
// "How're you doing?, Oh! I'm feeling great!"
注意到replace
方法了吗?由于 UTF-8 编码,当复制粘贴你的文本时,一些不间断空格会出现。我们可以用一个规则的空格代替它们来计算两个单词而不是一个。当我的朋友要开发票时,省略单词不会让她高兴!
将句子拆分成单词
对于这一步,一个简单的split
就可以了。
words = subString.split()
// ['How're', 'you', 'doing?', 'Oh!', 'I'm', 'feeling', 'great!']
在继续之前,我必须检查结果是否正确。例如,你可能会惊讶于“怎么样”也算一个单词。我也很好奇。然而,任何在线工具都会证实这一点。
计数和打印
最后,计算并打印我们的words
列表的大小。
count = len(subStr.split())
print count
// 7
如何理解它?
我知道这个剧本一点也不特别。有改进的余地。例如,我可以提取分隔符或输入文本等参数。
但它完成了任务。这就是我所关心的!
痛苦吗?不完全是。在不了解 Python 的情况下,我设法在几个小时内编写了一个小脚本。我甚至觉得写它很有趣!
值得吗?问我女朋友。到目前为止,她似乎很感谢有这个工具。
高血压药物综述的 LDA 主题建模
图片由作者“联合国新冠肺炎对策”提供
主题建模是一种利用无监督机器学习算法的文本分析技术。主题建模的最终目标是在大量文本文档中发现主题,并发现隐藏的主题。语料库中的每个文档将由至少一个主题组成,如果不是多个主题的话。主题建模对于文档聚类和非结构化文本的信息检索非常有用。
潜在狄利克雷分配 (LDA)是一种用于主题建模的算法,用于将文档中的文本聚类成主题列表。
这里我们将把 LDA 应用于一组高血压药物综述文档,并把它们分成主题。
动机
目标是通过对这些分组主题的分析,从这些评论中获得深刻见解:
- 从综述中探索所有高血压药物共有的潜在主题。
- 预测给定评论文本的评分。
我们开始吧!
数据集
该分析中使用的数据集是从 WebMD 药物评论数据集(可从 Kaggle 下载)中提取的约 18,000 份患者对用于治疗高血压的药物的评论列表。数据提供者通过抓取 WebMD 站点获取数据集。原始数据集中约有 36 万行独特的评论,更新到 2020 年 3 月。
import pandas as pd# Read data into papers
drug_df = pd.read_csv('C:/Users/Johnny Phua/Metis/Project4/Drug Review/webmd.csv')hbp_drug_df = drug_df[drug_df["Condition"] == 'High Blood Pressure']
看一眼数据。
print(len(hbp_drug_df))
hbp_drug_df.head()
图 1:药品评论数据集的前 5 行。
数据预处理
执行了以下步骤:
- 小写单词并删除非字母字符。
- 字 <三字被去掉。
- 分词:将文本拆分成单词。
- 所有停用字都被移除。
- 单词被词条化:第三人称的单词被改为第一人称,过去时态和将来时态的动词被改为现在时态。
- 单词被词干化:单词被还原成它们的词根形式。
以下功能用于小写单词、删除非字母字符以及删除少于 3 个字符的单词:
import redef clean_non_alpha(text):
return re.sub('[^a-zA-Z]',' ', str(text))def remove_short_word(text):
return re.sub(r'\b\w{1,3}\b', '', str(text))def convert_to_lower(text):
return re.sub(r'([A-Z])', lambda m: m.group(1).lower(),
str(text))
标记化
标记化就是将一个字符串拆分成一系列标记的过程**。标记是整体的一部分,所以在我们的上下文中,单词是句子中的标记。**
from nltk.tokenize import RegexpTokenizerdef get_tokenize(text):
"""
function to tokenize text to list of words.
"""
tokenizer = RegexpTokenizer(r'\w+')
return tokenizer.tokenize(str(text))
图 2:标记化后列表中的单词
删除停用词、词汇化、词干
下面的函数做的工作是去除停止字,词汇化和词干化。
from nltk.stem import WordNetLemmatizer
lemma = WordNetLemmatizer()
from nltk.stem import PorterStemmer
stemmer = PorterStemmer()
from nltk.corpus import stopwords
stop_words = stopwords.words('english')def remove_stopwords(token):
"""
function to remove stopwords
"""
return [item for item in token if item not in stop_words]def clean_lemmatization(token):
#from nltk.stem import WordNetLemmatizer
#lemma = WordNetLemmatizer()
return [lemma.lemmatize(word=w,pos='v') for w in token]def clean_stem(token):
#from nltk.stem import PorterStemmer
#stemmer = PorterStemmer()
return [stemmer.stem(i) for i in token]
图 3:去除停用词、词汇化和词干后的标记。
数据集现在是干净的,并且格式正确。它现在可以用于 LDA 建模。
然而,在我们开始训练模型之前,我们将如何决定使主题可解释性的最佳主题数量。
1)主题建模中主题数(k)的确定方法是什么?
确定主题模型的最佳主题数(k)的方法之一是通过比较 C_V 一致性分数。最佳的话题数量会产生最高的 C_V 连贯分数。Coherence 查看每个生成的主题中最频繁出现的单词,对它们之间的语义相似性进行评级(使用 UCI 或 Umass 进行成对计算),然后找到模型中所有主题的平均一致性分数。(http://qp ple . com/topic-coherence-to-evaluate-topic-models/)
我们如何评估和提高模型结果的可解释性?
一旦我们选择了主题的最佳数量,接下来要问的问题是如何最好地评估和提高这些主题的可解释性。一种方法是可视化我们的主题模型的结果,以确保它们对我们的场景有意义。我们可以使用 pyLDAvis 工具来可视化您的 LDA 模型对主题及其热门词的拟合。
一袋单词
从“reviews_docs”创建一个字典,包含一个单词在训练集中出现的次数。
from gensim import corpora
dictionary = corpora.Dictionary(reviews)
使用 Gensim.filter_extremes 内置函数过滤出出现在,
- 少于 15 份文件(绝对数量)或
- 超过 0.5 个文档(总语料库大小的一部分,而不是绝对数量)。
- 在上述两个步骤之后,只保留那些出现次数为 11 及以上的标记,换句话说,只保留前 2130 个最频繁的标记。
通过检查整个单词字典的频率分布(按频率降序排列),我们可以知道前 2130 个单词/记号对于每个记号具有 11 个及以上的出现次数。
# first get a list of all words
all_words = [word for item in list(hbp_drug_df['reviews_text_processed']) for word in item]# use nltk FreqDist to get a frequency distribution of all words
fdist = FreqDist(all_words) # choose k and visually inspect the bottom 10 words of the top k
k = 2130
top_k_words = fdist.most_common(k)
top_k_words[-10:]
图 5:语料库的词频分布。
将上述过滤器应用于 gensim 字典:
dictionary.filter_extremes(no_below=15, no_above=0.5, keep_n=2130)
然后,我们为每个文档创建一个文档单词矩阵,报告有多少单词以及这些单词出现了多少次。将此保存到‘doc _ term _ matrix’。
from gensim import corpora
doc_term_matrix = [dictionary.doc2bow(rev) for rev in reviews]
使用单词包运行 LDA
准备好字典和 doc_term_matrix 后,现在我们可以使用gensim . models . LDA model . LDA model来训练 LDA 模型。
然而,此时,我们需要问的下一个问题是,我们应该使用多少个主题(k)来训练我们的模型?我们可以利用 c_v coherence score 和 pyLDAvis 可视化工具来决定我们的模型的最佳主题数量。
计算 c_v 一致性分数:
#Calculate the c_v Coherence Score for different k from 1 to 10.
from tqdm import tqdm
from gensim.models import LdaModel
coherenceList_cv = []
num_topics_list = np.arange(1,10)for num_topics in tqdm(num_topics_list):
lda_model = LdaModel(corpus=doc_term_matrix,id2word=dictionary,num_topics=num_topics,random_state=100, update_every=1, chunksize=1000, passes=50, alpha='auto', per_word_topics=True)
cm_cv = CoherenceModel(model=lda_model, corpus=doc_term_matrix, texts=reviews, dictionary=dictionary, coherence='c_v')
coherenceList_cv.append(cm_cv.get_coherence())
绘制 pyLDAvis:
# Plotting tools
import pyLDAvis
import pyLDAvis.gensim# Visualize the topics
pyLDAvis.enable_notebook()
vis = pyLDAvis.gensim.prepare(lda_model, doc_term_matrix, dictionary)
vis
什么是话题连贯?
连贯性测量在每个生成的主题中最频繁出现的单词,评定它们之间的语义相似性;利用 UCI 或 Umass 来执行成对计算;然后为该模型计算所有主题的平均一致性分数。
从下面我们的模型中不同 k 个主题的 c_v 一致性分数分布可以看出,主题数 k=3 和 k=5 给出了同样高的分数。
图 6:k 个主题的 c_v 连贯分数
然而,如果我们绘制 pyLDAvis 图,很明显,k=3 将比 k=5 给出更有希望的结果。可以注意到,对于 k=5,主题 1、2 和 3 彼此高度重叠。而对于 k=3,主题在不同的象限中被很好地分开。
图 7:k 从 1 到 10 的 pyLDAvis 图
t-SNE 图也清楚地表明,k=3 比 k=5 好得多,因为可以注意到,当 k=5 时,有 3 个主题相互重叠。
图 8:k = 3 和 k=5 时的 t-SNE 图
现在,我们可以使用 k=3 来生成 LDA 模型。让α和β超参数自动生成。
import gensim# Creating the object for LDA model using gensim library
LDA = gensim.models.ldamodel.LdaModel# Build LDA model
lda_model = LDA(corpus=doc_term_matrix, id2word=dictionary, num_topics=3, random_state=100, chunksize=1000, passes=50, update_every=1, alpha='auto', eta='auto', per_word_topics=True)
您可以使用 lda_model.show_topic(): 查看每个主题的前 10 个关键词以及每个关键词的权重(重要性)
0 [(‘天’,0.043550313),(‘感觉’,0.03116778),(‘时间’,0.030068435),(‘得到’,0.0252915),(‘喜欢’,0.020811914),(‘迪子’,0.017624224),(‘使’,0.017559748),(‘胎’,0.01706512
1 [(‘压’,0.046297483),(‘效’,0.045646794),(‘血’,0.044705234),(‘方’,0.041772064),(‘功’,0.027191896),(‘年’,0.026943726),(‘医’,0.024851086),(‘下’,0.0203996)。
2 [(‘咳嗽’,0.038522985),(‘疼痛’,0.021691399),(‘药物’,0.02127608),(’ caus ‘,0.017660549),(’ sever ',0.01583576),(‘走’,0.01558094),(‘医生’,0.01529741),(‘停’,0.015242598
词云
我们来看看模型的词云分布。
图 9:单词云
通过参考高血压药物的一些常见副作用的列表,可以注意到主题 0 和主题 2 显示了下面提到的列表中的一些副作用。
高血压药物的一些常见副作用包括:
咳嗽
腹泻或便秘
头晕或头晕
剧烈而突然的脚部疼痛
感到紧张
感觉疲倦、虚弱、困倦或缺乏能量
头痛
恶心或呕吐
皮疹
无需尝试就能减肥或增重
- 腿肿
获得洞察力
通过从数据集中随机读取耐心的评论,可以注意到,主题 0 和主题 2 的评论显示耐心对于这两个主题经历了不同类型的副作用。而专题 2 的综述表明,这类患者的耐心比专题 0 经历了更严重的副作用,因为专题 2 的患者采取了诸如停止服用该药物并改用另一种药物的行动。然而,对于以主题 1 为主导主题的耐心的评论显示,该药物对他们有效,并且仅经历轻微的副作用症状。
现在我们可以给这个主题贴上如下标签:
主题 0:副作用类型 I —“头晕”、“疲倦”、“头痛”
话题 1:药物有效
主题 2:第二类副作用——“咳嗽”、“肿胀”、“疼痛”
图 10:各主题满意率统计
从上述三幅图中可以看出,在主题 1 中聚集了评论的患者对等级为 3 及以上的药物最满意。而主题 0 和主题 2 的患者对 2 级及以下的评分大多不满意。
图 11:每个主题的文档数。
从上面的图表可以看出,大约 55%服用高血压药物的患者会出现某种副作用症状。
基于 Tweets 的 LDA 主题建模
理解非结构化文本
问题和目的
有了一些为文本分类构建 NLP 模型的经验,我一直在进一步思考如何处理完全非结构化的文本数据。每天大约有 5 亿条推文在 Twitter 上发布,Twitter 是文本数据的巨大来源。人们在推特上谈论什么?这些推文可以通过编程组织成主题吗?人们对你的产品或公司有什么看法?可以发现对进一步分析/建模有用的模式吗?嗯——我想我们会找到答案的。
对于这个项目,我决定使用 GetOldTweets3 python 库从 twitters API 中提取的 tweets。用于这个项目的任何笔记本都可以在我的 GitHub 上找到。
GetOldTweets3
import GetOldTweets3 as got
- 使用“got”别名导入 GetOldTweets3 库,以便于使用
- 有很多参数可以玩,即用户名,位置,日期。我选择使用“通过查询搜索获取 tweets ”,这样我就可以指定一个特定的主题。
tweetCriteria = got.manager.TweetCriteria().setQuerySearch('anxiety')\
.setSince("2018-06-30")\
.setUntil("2020-06-30")\
.setNear('New York')\
.setMaxTweets(10000)tweet_object = got.manager.TweetManager.getTweets(tweetCriteria)
我选择查看纽约地区两年时间内包含“焦虑”一词的推文,希望了解人们可能在推文中表达他们的焦虑。是什么引起的?人有自残的风险吗?我们能找到任何有价值的特定主题来潜在地执行进一步的建模吗?
在进行 API 调用后,我用下面的代码片段构建了一个数据帧:
这里感兴趣的主要值只是文本。我不会对用户名、日期等感兴趣。此刻。
预处理文本
在我真正对文本数据做任何有用的事情之前,它必须被预处理成机器可读的数字输入。我已经在之前的博客中介绍了下面的步骤,但是我将在这里列出一般的步骤。
- 删除 URL
- 标记每条推文
- 删除停用词、标点符号和小写所有单词
- 删除任何剩余的特殊字符
- 将文本词条化
一旦文本被处理,它应该像这样:
[‘feel’, ‘like’, ‘cheer’, ‘slowly’, ‘morphed’, ‘scream’]
我可以检查我的推特语料库的全部词汇:
共 99716 字,词汇量为 13633
最大推文长度为 32
电子设计自动化(Electronic Design Automation)
然后,我可以使用 seaborn 和 matplotlib 的 countplot 检查每条 tweet 的长度:
语料库中推文的长度
考虑到这种分布是右偏的,每条包含少于 5 个单词(令牌)的 tweets(文档)高度集中,我将删除少于 4 个单词的额外文档,假设这些文档不会提供任何有意义的上下文。
让我们来看看排名前 30 的单词。有了 nltk.probability 的 FreqDist 类和 WordCloud 库,实际上相当容易。
首先,我从每条 tweet 创建了一个包含所有令牌的平面列表。然后将所有标记的列表传递给 FreqDist(),它将计算每个标记的出现次数,并为每个标记创建一个包含(单词,频率)的元组。
输出:
[('time', 854), ('people', 774), ('depression', 608), ('much', 548), ('know', 501), ('stress', 469), ('really', 449), ('thing', 438), ('need', 437), ('attack', 428), ('make', 407), ('social', 396), ('today', 389), ('work', 354), ...]
一旦我有了词频,我就可以构建一个字典来创建单词云。
然后,该字典可以与。WordCloud 的 generate _ from _ frequencies 方法。
单词云:
人、时间、压力、抑郁是出现频率最高的 10 个词。考虑到被查询的推文都包含“焦虑”一词,这并不奇怪。
创造一个单词包
我将使用 Gensim 的字典构造器给 tweet 语料库中的每个单词一个唯一的整数标识符。
构造的字典应该包含 13633 个标记(语料库 vocab 的大小)。
{'applies': 0, 'exist': 1, 'go': 2, 'japanese': 3, 'learning': 4, 'list': 5, 'mean': 6, 'okay': 7, 'open': 8, 'people': 9, ....}
袋字 什么是袋字?简单的解释是,它是一个单词 token(或 term) 在一个文档中出现的次数的计数(在这个例子中是一条 tweet )。下面的代码利用了 gensim 的 doc2bow 方法,将上面的字典作为输入。
输出将包含每个 tweet 的向量,形式为**(单词 id,单词在文档中出现的频率)。**
[[(0, 1),
(1, 1),
(2, 1),
(3, 1),
(4, 1),
(5, 1),
(6, 1),
(7, 1),
(8, 1),
(9, 1),
(10, 1),
(11, 1),
(12, 1),
(13, 1),
(14, 1)],
...]
考虑到 tweet 通常非常短,平均大约 33 个字符,我们可以看到这条 tweet 包含 14 个独特的单词,每个单词只出现一次。有了这袋单词,建模就可以开始了!
拟合 LDA 模型
那么,LDA 到底是什么?
LDA,或潜在目录分配,是围绕最流行的主题建模算法之一。 LDA 是一个生成统计模型,它允许观察值由未观察到的组来解释,从而解释为什么部分数据是相似的。LDA 将文档集作为输入,假设每个文档是少量主题的混合,并且每个单词可归属于文档主题之一。如果想深入了解,可以去看看戴夫·布雷的讲座,以及这个博客。
根西姆
在 Gensim 中拟合 LDA 模型非常简单。作为起点,我已经建立了一个包含 5 个主题和 10 个通道的模型。这在这个阶段有些武断。我想看看是否会出现一些关于人们为什么在推特上谈论焦虑的一般性话题,并发现一个可观察到的模式。
以下是输出结果:
[(0,
'0.019*"work" + 0.015*"take" + 0.014*"stress" + 0.014*"need" + 0.014*"time" + 0.013*"much" + 0.011*"today" + 0.010*"sleep" + 0.009*"next" + 0.009*"watch"'),
(1,
'0.034*"know" + 0.027*"people" + 0.025*"depression" + 0.017*"nice" + 0.016*"social" + 0.016*"family" + 0.015*"please" + 0.015*"really" + 0.015*"fucking" + 0.015*"think"'),
(2,
'0.022*"attack" + 0.019*"much" + 0.018*"give" + 0.017*"really" + 0.014*"make" + 0.014*"know" + 0.014*"never" + 0.013*"would" + 0.013*"something" + 0.013*"people"'),
(3,
'0.018*"news" + 0.014*"respond" + 0.013*"good" + 0.013*"disorder" + 0.012*"fear" + 0.012*"hard" + 0.011*"trying" + 0.011*"still" + 0.010*"love" + 0.010*"literally"'),
(4,
'0.030*"people" + 0.020*"real" + 0.019*"body" + 0.019*"social" + 0.018*"find" + 0.018*"good" + 0.018*"depression" + 0.018*"want" + 0.016*"next" + 0.016*"actually"')]
估价
在我寻求评估的过程中,我发现了一些有用的资源,这才刚刚开始。特别是 Matti Lyra 在 PyData Berlin 2017 关于评估主题模型的演讲。我不打算在这篇博客中深入讨论评估或优化,因为这会变得太长。但是这里有一些可视化主题模型的基本策略。
目测
输出代表 5 个主题,包括热门关键词和对主题的相关权重贡献。
虽然我可以从每个主题中推断出一定程度的情感,但主题分配并没有明确的划分或可识别的模式。和常用词也有不少交叉。
- 主题 0 似乎是关于在家工作的挣扎。虽然如果是这样的话,我很惊讶“covid”、“新冠肺炎”、“冠状病毒”等。不包括在这里。
- 话题 1 可能是关于社会孤立?
- 话题二?
- 主题 3 似乎是关于媒体,以及对媒体的反应
- 主题 4 与主题 1 没有太大的不同
皮尔戴维斯
PyLDAvis 库是可视化主题模型中的主题的好方法。我不打算详细解释它,但这里有图书馆的文件以及原创研究论文,该论文于 2014 年 6 月 27 日在巴尔的摩的 2014 年关于交互式语言学习、可视化和界面的 ACL 研讨会上发表。
用 PyLDAvis 可视化主题模型非常简单。传入模型、单词包和 id2word 映射,就完成了。
输出:
在左边,主题被绘制在表示每个主题之间的距离的二维平面上。而右边的水平条形图代表与每个主题最相关的单词。该图表是交互式的,允许您选择特定的主题,并查看每个主题的相关单词,希望从每个主题中推断出含义。
结论和未来步骤
虽然我目前对这个 tweet 主题模型的迭代没有明确地以一种我认为对外部任务有价值的方式分离或聚集 tweet,但我将继续研究一些优化策略。
- 使用 n-grams 连接通常一起出现的单词,如“精神”和“健康”。一个双字母组合将保留“心理健康”,这样模型就可以把它作为一个标记来读取。
- 对不提供任何有意义上下文的常见单词进行额外过滤。
- 计算一致性分数,并找到 k 个主题、通过次数等的最佳参数。
- 收集更大的推特语料库,并尝试更多样化的数据集。
祝贺你坚持到了最后。如果你想联系@https://www.linkedin.com/in/rob-zifchak-82a551197/,请随时在 LinkedIn 上联系我
用愿景而不是指标来领导:OKR 如何成为一个危险的工具
照片由 iStock Photo 编舞提供
如果使用得当,数据是任何组织成功的关键。没有帮助我们理解性能和设定基线的度量标准,就不可能改进。大多数组织一开始都有良好的意图——使用数据来提高效率、推动问责制和改进关键指标——但很快就陷入了官僚主义、“给自己的作业打分”的偏差状态。这导致利用数据来转移人们对美国真实状况的注意力,或者更糟糕的是,直接撒谎并掩盖真相。
20 世纪 90 年代,NYPD 实施了 CompStat,这是一个全市范围的数据库系统,使用比较统计数据来更有效地跟踪和减少犯罪。该法案要求警察对其管辖区域内的犯罪负责,并因将犯罪率降低了 75%而受到称赞。然而,在过去的几十年里,这实际上导致了官员们不太关心履行他们的职责,而更关心在被跟踪的指标上显示改进。在极端情况下,有报道称警察降低了举报犯罪的严重程度只是为了提高指标。
按指标管理:用良好的意图铺路
科技行业多年来一直使用 OKR(目标和关键结果)来跟踪业绩,但我们都看到它们随着时间的推移变得越来越没有意义。经过几个季度甚至几年的时间,人们不可避免地将 OKR 氏症作为获得晋升的一种方法,而不是一种跟踪什么是对的,以及——可能更重要的是——什么是错的方法。这意味着,被跟踪的关键结果最终成为相同的顶级指标,只是稍作调整,以显示对组织其余部分的微小改进:比如“我们的数据将扩展 10%”或“我们将增加 5 个新客户”
这种类型的问题在一个行业中并不孤立,但当我们为成功设定错误的标准时,这种问题就会经常发生。例如,学校通常是根据学生的毕业率来评判的。作为回应,老师们感到有压力让可能没有取得学业成功的学生通过考试。这种做法非但没有让学生为未来做好准备,反而危及学生接受的教育质量。
设定只跟踪顶级指标的目标是糟糕领导的表现。我可以在没有外界知识的情况下进入任何一家公司,并通过说“我们的组织需要多销售 X%的产品”或“增加 Y%的利润”来负责一个好的船长不仅会规定船需要到达哪里,还会提供一个愿景,让船员们能够沿途做出自己的航行决定。
哪里出问题了?
CompStat,沿着我们在教育和技术领域看到的路线,开始得很好。作为一个集中跟踪数据库的所有逮捕,传票,以及整个地区的其他犯罪活动,它有巨大的能力,揭示主要趋势。如果使用得当,它可以帮助领导者更有效地打击犯罪,例如,通过了解犯罪是如何联系在一起的,或者在什么时间哪个区域需要更多的警察关注。
然而,任何像这样的系统被滥用的两个因素是:
- 给自己的作业评分
- 与晋升和降级的相关性
不幸的是,这两个概念是相互矛盾的。我们都希望在报告自己的成功时能够做到客观,但当业绩与个人职业发展或成就相关时,即使是道德狂热分子也会有意或无意地将衡量标准偏向那些对他们更有利的方面。
如何对抗度量的阴暗面
无论你怎么分析,这都是一个极其困难的问题。很难激励你的组织去创建和恰当地度量那些不可游戏的客观指标。也很难确保员工对愿景有足够清晰和简明的理解,以便他们在任何时候都能为组织做出正确的决定。
有几个因素可能有助于组织实现这些目标。
1——作为领导者,为公司设定正确的愿景。
一个组织的愿景不应该由顶级的业务成果组成。相反,愿景应该是员工在决策过程中使用的工具,以理解和直观地了解他们应该做出的决策类型。亚马逊取得了令人难以置信的成功,部分原因是杰夫·贝索斯让非常清楚顶级指标并不是亚马逊努力的方向。他正在建设“世界上最大的商店”,员工们知道他们可以牺牲短期收入来实现这个目标。
2 —创建与个人绩效无关的组织绩效客观指标。
有一个清晰定义的愿景会让一切变得更容易,并有助于确保员工跟踪真正重要的指标。出于客观性,指标不应与个人晋升相关联,以确保对公司的成功有一个清晰的看法,不受政治的影响。
3——推动个人绩效评估中的问责制。
给自己的作业评分是决定成绩的良好基础,但任何好的制度都有制衡机制。个人需要责任感,这可以通过管理层、同事和最终消费者来实现。
它在实践中是如何工作的?
让我们试着把这个过程应用到 NYPD。
1——NYPD 运用杰夫·贝索斯原则的新愿景。
我们不应该设定像“连续 20 年降低犯罪率”这样的最高目标,而是应该思考警察为什么存在,并以此来定义我们的愿景。
寻找愿景应该很简单:“在执法的同时确保公民的安全、健康和财产。”
最终,这意味着警察是公务员,其任务是帮助公民更加安全。不应优先考虑不符合这一愿景的指标。
2 —定义客观的绩效指标。
虽然客观性通常很难实现,但我们的工作变得容易多了,因为我们都设定了一个愿景,并将衡量与推广脱钩。因此,在报告犯罪时,我们不应该担心坏数据。犯罪将是我们的第一个衡量标准,因为它达到了理解我们公民的安全、健康和财产的最高水平。
犯罪显然是衡量愿景的一个标准,因为犯罪是衡量违反法律的频率的外在标准,但它并不能严格衡量公民的安全和健康。我们可以从外部数据中添加这方面的直接测量,并将其与犯罪联系起来,以确保它们得到准确报告。我们也可以通过这种方法来衡量警察自己是否造成了伤害。
3 —推动对个人绩效的问责。
个人绩效报告是一个良好的开端,但让官员承担责任也意味着从同事、经理和外部信息中收集信息。
为了确保警察对公民的安全和健康起到促进作用,我们必须衡量警察本身的行为。警队的不良行为记录需要像保存给市民一样保存给警察。
最后,我们应该增加从我们的公民中提取警方表现数据的方法,如民意测验或匿名举报热线。从多个来源和角度收集反馈对于推动绩效评估的问责制至关重要。
底线
自从引入 CompStat 以来,已经过去了将近 30 年。虽然指标可能在改善,但公民和警察之间的关系比以往任何时候都紧张。当然,在讨论美国的治安状况时,有一个更大的社会背景需要考虑。然而,由于专注于错误的指标,他们不再致力于确保公民安全和健康的目标。
我们能从中学到什么?虽然大多数人本质上是好的,并希望在他们的组织中做到最好,但很少有领导层能够将他们公司的愿景提炼为一套指导原则。员工非常擅长对他们获得的成功指标进行局部优化,并且倾向于推动短期指标而不是长期愿景,除非组织明确规定了优先事项。
在许多组织中,缺乏领导远见会导致对员工的误导。OKR 的是一个危险的目标设定框架,没有一个明确定义的愿景和客观跟踪和分级表现的结构。不用说,我们都应该努力确保愿景和目标跟踪在我们的组织中被视为一等公民,否则我们将面临与警察机构相同的挑战。
领导软件开发团队
5+5 关于如何成为伟大的技术领导者的独特视角
软件开发是团队的努力,但是一群没有技术带头人的工程师就像一群没有牧羊人的羊。技术领导的角色不仅仅是设计和编写代码,还是软件质量的守护者;它还包括指导和代表技术团队,并需要采用一套新的非技术技能。在我的职业生涯中,我发现下面列出的原则为成为一名有效的领导者提供了一个坚实的基础——一个不断取得巨大成就的领导者!
因此在本文中,我们将深入探讨这个问题:
什么是伟大的技术领先?
向技术领导过渡
新任命的技术主管(TL)可能会很快陷入许多陷阱,这些陷阱通常是由他们作为开发人员时养成的习惯造成的。为了克服这些缺陷,他们必须找到在技术和领导责任之间取得平衡的方法。
让我们来探究其中的一些错误:
➊:反思生产力
作为一名开发人员,你可能至少花了 80%的时间写代码。每天结束时,你可以回顾并看到进展:无论是代码、设计规范、同行评审还是修复 bug,你都可以说:这是我今天做的事情。
但是,作为一个领导角色,量化你的日常成就变得非常困难,因为你是通过你的团队的生产力和效率来衡量的。准确地说,困难来自内部;虽然别人可以清楚地看到你的成就,但你内心的声音一直在想:我今天到底做了什么?在无数的会议、计划会议、整理积压工作、状态报告、技术讨论和各种各样的干扰之后,你带着一种交付不足的感觉结束了一天。
这当然不是真的。作为一名 TL,你应该使用关注团队成果的方法,而不是你个人的产出。
➋:在编码方面找到了正确的平衡
当我第一次担任 TL 角色时,我犯的最明显的错误是继续像以前一样编写代码。在不停地编码几年后,我的自然倾向是以同样的方式操作,没有意识到尽管我作为一个个体贡献者最大化了我的生产力,但我这样做是以我团队的生产力为代价的(抱歉伙计们)。当你认为自己的技术能力是成为一名技术人员的首要原因时,停止把自己视为一名制作人是非常棘手的。
新 TLs 经常犯的另一个错误是不再做足够的编码。当你不动手时,你将逐渐变得不太能够设计正确的架构,评估你的团队建议的解决方案,或者帮助调试在生产中不断出现的讨厌的多线程错误。冒援引“象牙塔领导”反模式的风险,即领导技术决策而不理解其真正含义,会给团队带来可怕的后果,他们最终会对你这个领导者失去信心。
根据我的经验,这个问题没有正确的答案。最佳状态是将 30%-40%的时间用于编码,剩下的时间留给剩下的工作。
➌:关注大局
新 TLs 发现的角色挑战的另一个方面是如何调整他们的“关注水平”。作为一名开发人员,你曾经一次专注于一项任务。显然,了解你的特性/模块/服务如何与整个系统相适应是很重要的,你可能会迷失在实现的细节中。但是作为一个 TL,这种情况会改变:你需要对软件生态系统有一个鸟瞰图,并且对代码设计有一个更广泛的理解。
想象一下相机上的变焦镜头:它允许操作者向后拉并看到大画面,但也允许他们放大细节。类似地,一个有效的目标语可以不断地从大局转移到细节,转换视角和语境。
➍:忍住了微观管理的冲动
新成立的团队有着积极管理团队的冲动,因为他们相信领导力包括做出所有决定的谬论,无论这些决定是大是小。他们成为看门人:他们在发布之前审查所有的代码变更,他们是唯一可以访问关键服务的人,他们处理所有的任务管理和评估,他们代表团队与业务部门进行对话,等等。这些情况中的每一种都会导致团队感到无能为力,并对他们的士气、动机和表现产生不良影响。
一个有能力的领导者和一个微观管理者之间的界限可能很窄,虽然这条界限对你来说似乎很模糊,但你的团队很可能很容易就能识别出来。一定要放手!相信你的团队,尽量不要支配一切,在早上的讨论中获得你的每日更新,不要做一个令人窒息的老板!
➎:代表
在希腊神话中,阿特拉斯是掌管大地和天空的神。在更小的范围内,作为一名 TL,你可以尝试扮演这个角色,独自完成所有的关键工作。显然,有些任务需要你的经验和知识,但你不想成为解决问题的瓶颈,所以你需要找到一种方法来委派任务,并且仍然参与其中。
只有当领导者认为某人有足够的技能和动力来完成一项任务时,授权才是可能的,这不仅鼓励解决问题的创造力,也是赋予团队权力并看到他们成长的机会。一个从来没有被要求拥有他们的工作,转换环境,或者解决他们舒适区之外的事情的团队将永远不会前进。
试图为阿特拉斯这个角色服务,从长远来看,是一种不值得承受的负荷。和团队分享会好很多。
作为技术领导者的卓越表现
虽然扎实的技术知识对 TLs 至关重要,但一个有效的领导者最重要的技能是社交技能。但坏消息是:
非技术能力没有明显的“你好世界”!
这些技能是在你的领导之旅中逐渐形成的。你的最终目标不应该是擅长你的新角色,而是要出彩!成就卓越就是对出色完成的工作有一种成就感——这是本文的主旨!
正如亚里士多德所说:“我们就是我们反复做的事情。因此,优秀不是一种行为,而是一种习惯。
让我们看看成为一名优秀的 TL 需要什么!
➊:是一个仆人式的领导者
服务型领导颠覆了传统的等级领导方式。它通过关注他人的支持和成长来采取利他主义的领导方式。
保持服务第一的心态意味着你专注于授权和提升那些为你工作的人。你是在服务而不是命令,表现谦逊而不是展示权威,倾听理解而不是决定你的反应,并且总是希望以释放潜力和提高绩效的方式促进团队成员的发展。
当你认为你比你的团队成员更优秀的时候,你是不可能去服务的——对你来说,从来没有一份工作是太小的!仆人式领导不是让人在你下面;它是关于携带人和你,去建立比你自己更好的东西!这本身就是一种很棒的感觉!
➋:放弃胜利和自己的失败
每当有成功的时候,人们都想得到荣誉(有时他们甚至想为他们没有做过的事情得到荣誉)。如果你想出类拔萃,把你团队的任何成功故事的功劳都给别人,因为它会给你十倍的回报:表扬,不仅会给团队更大的主人翁感,还会给他们工作的成功(以及后来的失败)带来更大的责任感!
在失败中,当大多数人开始指指点点时,那就是承担责任的时候了!即使你可能不相信这是你的错,你也必须拥有你的团队生产的一切。如果他们觉得你会把责任推给他们,他们会怨恨你的领导。向他们反馈他们的缺点,但总是向高级管理层掩盖你的团队。
➌:培养信任文化
强大的团队文化是完成使命的基础。
你应该努力营造一种信任的氛围,即营造一种敢于冒险的环境,在这种环境中,你周围的人感到安全并有动力发挥他们的创造力,交流想法并毫不犹豫地为重大决策提供意见。给予信任是激励回报的强烈信号。
信任和谦逊是相辅相成的。不知道是谁创造了这句话:“当我和经理们交谈时,我觉得他们很重要。当我与领导交谈时,我感觉自己很重要,但这是谦逊领导的最佳例子。团队中的每个人都应该在与你交谈后感到被授权、被重视和被欣赏,然后离开。
当一个好的领导者的工作完成了,他的目标实现了,人们都会说,“这是我们自己做的。”——老子
强化团队精神的一个同样重要的方面是问他们“我做得怎么样?“—提出这样的问题需要谦虚,考虑答案更需要谦虚!
在我的领导风格中,将团队放在首位极大地影响了我的职业道路和我的个人品牌。我希望你在职业生涯的早期就认识到团队导向的重要性!
➍:从过去中吸取教训
你的领导哲学应该由你早期作为开发人员的经历来定义。我记得年轻时的自己在会议上发言时感到不自在。现在我通过询问那些安静的人是否有什么要补充的来确保每个人的声音都被听到。解决您作为开发人员遇到的一些问题,包括技术和社会问题,是一个很好的起点。你的团队会喜欢你的!
同样,我也曾为令人沮丧的 TLs 和绝对英雄工作过。我试图避免成为我真正不喜欢的 TL,并注意到那些我钦佩的人的强烈特征,并将它们融入到我的管理风格中。
➎:打造新领袖
寻求取代你自己,除非你想在你的职业生涯中继续做同样的工作!你需要通过承担更多的责任,偶尔让他们领导团队,给你的团队发光的机会。在指导他们并帮助他们发现自己的优点和缺点后,请他们在你度假时扮演你的角色。然后,您可以评估他们可能需要额外培训和发展的地方。逐渐地将更多的任务委派给他们,直到你尝试新领域的时候!
考虑你的继任计划意味着你需要培养你周围的人。当他们知道下一个角色在等着他们时,他们的自尊和自尊会得到提升,这增强了他们作为团队成员的效能和价值。这是双赢的局面!
推荐资源
这里有几个资源对我以前的 TL 角色影响最大。
- 调试团队,布莱恩·菲茨帕特里克&本·柯林斯-苏斯曼
- 开发人员的技术领导技能,Patrick Kua
结论
技术领导将无与伦比的技术专长与社交技能相结合。如果你做到了这一步,你可能足够关心做好 TL 这个角色,并且你有成为 TL 的天赋。
成为最好的是关于不断改善你是谁,并保持进化…这是你的旅程。拿着!
感谢阅读!
我经常在媒体上写关于领导力、技术&的数据——如果你想阅读我未来的帖子,请‘关注’我 !
英雄联盟获胜条件
用 Python 编码来理解赢得英雄联盟游戏的最重要因素
Mateo Vrbnjak 在 Unsplash 上拍摄的照片
介绍
在过去的几年里,电子竞技社区一直在快速发展,曾经是一种休闲娱乐的东西已经演变成一个产业,预计到 2022 年将产生 18 亿美元的收入。虽然这个生态系统中有许多视频游戏,但很少有像英雄联盟这样成为社区的主要内容,该游戏在 2019 年世界锦标赛期间聚集了超过 1 亿名独立观众。
《英雄联盟》于 2009 年底发布,是一款免费的 MOBA(多人在线对战竞技场)视频游戏,由 Riot Games 创建,早期曾产生广泛的竞争场景,2011 年的第一届世界锦标赛产生了约 160 万观众。从那以后,这款游戏在受欢迎程度和游戏性方面都有所增长,因为 Riot 开始明白如何改变才能使游戏更具竞争性和趣味性。
游戏目前的状态相当复杂,如果你是一个完全的新手,你应该看看这个视频。总的来说,一场英雄联盟比赛由两队五名球员组成,每队控制一个独特的角色或“冠军”,当一队位于该队基地深处的 Nexus 被摧毁时,比赛结束。一路上,一个团队可以实现许多目标,例如摧毁炮塔,杀死中立的怪物,如龙和男爵,为整个团队的爱好者,等等。一些目标,比如摧毁至少五个炮塔和一个抑制剂,是赢得游戏的必要条件,而其他的,比如获得第一滴血,是有帮助的,但不是必要的。通过这个项目,我想更好地了解这些目标中哪些是赢得一场英雄联盟比赛最重要的。就此而言,我提出的问题如下:
《英雄联盟》一款游戏最重要的胜利条件是什么目标?
收集数据
跳进来,我首先用 Riot 开发者门户申请了一个应用,在我的应用被接受后,我浏览了一下API 标签以了解我可以请求的数据类型。不幸的是,没有直接的方法让我从一个区域中找出最后 X 个排名匹配,所以我必须找到一种方法来解决这个问题。
我的解决方案是使用一个召唤师名字(用户名)列表来为每个玩家生成一个最近比赛的列表。通过使用 Python 包 Riot-Watcher 对 Riot API 的一系列调用,我在一个略低于 10,000 行的 Pandas 数据帧中填充了最近排名的英雄联盟游戏,这些游戏是由五个地区的前 100 名玩家玩的,这五个地区构成了最大数量的英雄联盟玩家群。乍看之下,数据帧如下所示:
匹配数据帧的前十行
在前七列中,0 表示“假”,1 表示“真”,而在后面的列中,单元中编码的数据表示该事件发生的次数。每一行都包含了英雄联盟排名赛中一支球队的数据。例如,在第一行中,没有首先获得任何目标的队输掉了整场比赛。
利用热图和主成分分析进行探索性数据分析
我首先发现,大约 91%的获胜团队摧毁了第一个抑制剂,80%杀死了第一个男爵,70%摧毁了第一个塔,63%杀死了第一条龙,59%的获胜团队以第一滴血开始游戏。看起来最重要的胜利条件是摧毁第一个抑制剂,这是有道理的,因为摧毁一个团队的抑制剂会给他们的基地带来压力,并让对手有更多的地图控制权。
接下来,我可视化了数据集中各列之间的相关性:
数据间的热图关联
我还为我的数据中代表的每个区域绘制了相同的相关性热图,以比较不同区域之间的相关性,希望注意到游戏风格的一些差异。不过一般来说,相关矩阵看起来非常相似。一个可能的原因是,我的数据包括了每个地区最好的球员参加的比赛,其中许多人都是职业水平的。因此,由于良好的游戏实践在竞争社区中是一致的,所以我的数据中所表示的比赛涉及到的玩家相对于每个地区排名较低的玩家来说,在每个游戏中的导航是相似的。
我现在很好奇,想看看用比我用来预测游戏结果的 10 个特征更少的特征能在多大程度上解释数据中的差异。在这种情况下,我进行了主成分分析,以了解我可以将数据简化成多少个特征,并仍然保留大部分差异:
每个新组成部分解释的差异比率
十个预测值列中超过 80%的方差可以用一半的特征量来解释。这肯定很有趣,通过将每个组件与原始数据集的列相关联,我希望了解哪些特性在解释数据的方差方面最重要,这可以帮助我找出哪些列对团队是否会获胜最关键。
数据集的列和主成分之间的关系
用于生成上述热图的组件来自一个包含六个组件的 PCA 对象,因为我希望这些组件能够解释数据中 90%以上的差异。看起来,杀死塔的数量、杀死抑制剂的数量以及团队是否摧毁了第一个抑制剂是决定数据方差的最重要的特征,因为第一个成分解释了方差的 40%,并且前面提到的三列在该成分中权重最大。
重申我在这一点上收集的见解:
- 从我的关联热图来看,一个团队是否摧毁了第一个抑制剂,一个团队有多少塔杀,一个团队摧毁了多少抑制剂,都与获胜有最高的关联。
- 根据我的 PCA 分析,一个团队是否摧毁了第一个抑制剂,一个团队有多少塔杀,以及一个团队摧毁了多少抑制剂在解释数据的差异方面起了最大的作用。
使用逻辑回归的数据建模
我用了一个逻辑回归模型来理解一场《英雄联盟》排名赛的获胜条件。我的过程是首先将我的数据分成一组特征和一组目标,其中我的特征是除“win”和“region”列之外的所有列,我的目标是“win”列。然后,我将我的数据分为训练集和测试集,通过逻辑回归模型运行它们,并检查分类报告和混淆矩阵,以确保相对较强的预测能力。当逻辑回归模型在整个数据集上运行时,模型的精度和召回率分别为. 86 和. 85。
在这里,我对只包含一个地区的数据子集进行了逻辑回归,比如只在北美、北美等地进行的比赛。,并将模型的系数记录在熊猫数据框中。然后这个数据框架被可视化,这样我就可以比较不同的区域:
跨区域和整体的对数回归系数
回归系数描述了预测变量和目标变量之间的关系。例如,当观察上面的第一滴血预测变量时,获得第一滴血的团队是游戏结果的中度预测者,因为获得第一滴血的团队更有可能获胜。另一方面,裂缝传令官杀死实际上是反方向相关的(除了 EUNE),获得更多裂缝传令官杀死的团队更有可能失败。
使用这个分析过程,我了解了哪些列更能预测胜利,帮助我回答了关于英雄联盟游戏中胜利条件的问题。
结论
作为我项目的结果,以下是我得出的结论:
- 根据我的逻辑回归模型,按照从大到小的顺序,第一个抑制剂,第一个塔,和塔杀是整个数据集中最重要的获胜条件。
- 根据我的关联热图,按照从大到小的顺序,塔击杀、第一个抑制剂和抑制剂击杀是整个数据集中最重要的获胜条件。
- 虽然拿了第一个男爵的北美和 EUW 队更有可能获胜,但是随着杀死男爵数量的增加,这些地区的队更有可能失败。
- 与其他地区相比,北美地区的团队更有可能赢得第一条龙,这一事实可能表明北美地区的游戏更容易受到龙迷的影响,并围绕龙展开战斗。
- KR 游戏受一个特性的影响并不均衡。这可能表明 KR 球员比其他地区的球员更了解如何在背后比赛,这促使一支球队比其他地区更经常地赢得目标的组合。
如果你认为我错过了任何其他有趣的观察,请在评论中告诉我们!
包含我的代码的 GitHub 存储库和我为这次分析整理的数据集可以在这里找到。
在 Web 应用程序中泄露秘密
环境变量失控:数据泄露结果
利用错误配置的中间件中的漏洞
“秘密应该是安全的”——授权给杰森·奥斯特罗姆
信息泄露是一种漏洞,在这种漏洞中,系统会无意中暴露机密信息。这篇文章通过观察环境变量在 web 应用程序中如何被误解和误用,展示了这个缺陷的一个例子。这篇文章将重新审视最佳实践,并以对开发者的可行建议作为结束。
L eaking Secrets 描述了一种信息泄露缺陷,在这种缺陷中,应用程序将敏感凭证或 API 密钥暴露给对手。OWASP 2017 十大漏洞将此漏洞归类为“ 敏感数据曝光 ”。这篇文章将讨论如何通过一个在 rails 应用程序上运行的易受攻击和错误配置的中间件 gem 的案例研究来利用这一点。这些类型的问题可能会导致企业的数据泄露,从而导致重大的财务和声誉损失。这些问题是经常观察到的,因为基础设施即代码(IaC)和云速度使 DevOps 人员能够快速启动新的 web 应用程序和环境而不受检查。如果您是使用 Rails 的开发人员,您需要了解这些问题。如果你是一个使用 web 应用程序的初学者,你会发现这些信息很有用,并且(我希望)能够更好地保护你的客户。
在你的 web 应用程序中通过公共互联网暴露秘密正是你 永远 不想做的事情。对于阅读本文的 Rails 开发人员来说,这是对 Rack-mini-profiler 的致敬。
机架式迷你剖面仪:好的,坏的,丑陋的
Rack-mini-profiler是一个中间件 gem,被 Rack 开发人员用作性能工具,以提高基于 Rack 的 web 应用程序的可见性和速度。该工具对开发者社区有价值,并受到高度重视,正如这位爱好者所展示的:
*rack-mini-profiler*
是一个用于机架应用的性能工具,由天才的 @samsaffron 维护。 rack-mini-profiler 提供了一整套工具来测量支持 rack 的 web 应用程序的性能,包括详细的 SQL 查询、服务器响应时间(对每个模板和部分模板都有细分),令人难以置信的详细的毫秒级执行时间细分(具有不可思议的*flamegraph*
功能),甚至可以通过其出色的垃圾收集功能帮助您跟踪内存泄漏。我会毫不犹豫地说***rack-mini-profiler***
是我最喜欢也是最重要的开发快速 Ruby webapps 的工具。
我最近在野外发现了一个使用 Rack-mini-profiler 的 Rails 应用程序的部署,看到其中的安全问题令人大开眼界。我想澄清的是,我并不是说创业板有内在的脆弱性;相反,如果没有适当的安全保护,如何使用或配置中间件 gem 是一个问题。所以我开始更好地理解这是如何发生的,以及观察到的实际漏洞。这一努力的高潮是一个开源项目,“锤子”。Hammer 是一个易受攻击的 Rails 应用程序部署的例子,它使用 Rack-mini-profiler 来泄漏 API 密钥和敏感信息。它与在野外观察到的真实世界的应用程序一样容易受到攻击。这也是一个骨架应用程序,可以用来以安全的方式分叉和试验敏感变量。在构建这个工具的过程中,我学到了一些东西,希望与开发人员和 InfoSec 社区分享这些经验。
锤子图像,归杰森·奥斯特罗姆所有
锤子 Github 站点这里是这里是。
这里的是的一个轻锤介绍。
让我们快速浏览一下中间件的功能,它为开发人员提供了如此多的好处,但同时也使它成为一个有吸引力的攻击目标。你可以跟随锤子的演示应用:https://preprod.rtcfingroup.com。
在左上角,通过安装这个性能中间件 gem 呈现了一个“HTML 速度徽章”。安装该工具后,HTML speed badge 可用于分析 Rails 应用程序提供的任何给定页面。
HTML 速度徽章
【https://preprod.rtcfingroup.com/users/.】T2 让我们浏览敏感用户可以公开访问的 URL—注意,这些不是真正的用户。它们是从模拟用户的工具中包含的脚本中随机生成的。看一下左上角的 HTML 速度标记,看看它是如何渲染页面渲染时间的。
用户页面
Ex 在 /users/ 展开速度徽章,显示渲染每个页面所花费的时间,以毫秒为单位。请注意用于呈现 用户/索引 的有趣的 SQL 查询。Rack-mini-profiler 创建了一个链接,您可以单击该链接获取更多信息。让我们来看看。
用户的 SQL 查询
B 下面,您可以看到 Rack-mini profiler 显示了详细的调用堆栈查询信息。您可以看到呈现给用户的 SQL 查询、文件和精确行。对于试图提高性能和识别应用程序瓶颈的开发人员来说,这是非常好的信息。但是从攻击者的角度来看,这收集了诸如 SQL 查询之类的有价值的信息,这些信息可能使其他漏洞被利用。从不公开 SQL 查询客户端被认为是一种标准的安全实践。当我第一次在野外看到这个的时候,我简直不敢相信我所看到的。Rack-mini-profiler 的网站声明,该工具可用于分析开发和生产中的应用程序。这就是为什么确保公开 SQL 调用堆栈查询与应用程序开发的组织安全策略保持一致如此重要。当我第一次看到这个的时候,我不知道会有更有趣的东西。阅读下文。
调用堆栈查询
R ack-mini-profiler gem 使用了“Pretty Print”Ruby 类( pp ),可以通过追加 在默认 URL 找到?pp =求助 。对于开发者来说,它有很多不错的特性,比如内存分析和垃圾收集。从安全角度来看最有趣的是漂亮的印花 env 。
精美的印刷(pp)菜单
№1:转储“环境”
T 他的 env pretty print 特性转储所有传递给 Rails 应用程序的环境变量。这包括如下所示的 机架环境 。
env 的漂亮印刷
T 看一下profiler . Rb的 Rack-mini profiler 源代码,代码显示它首先通过迭代并打印存储在 env 中的局部变量来转储 env 。 这与上面以“ 机架环境 ”开头的输出相关
№2:转储“环境”
其次,它通过迭代并打印这个散列的内容来转储 ENV 常量。
用于转储环境和环境的 RackMiniProfiler 源
T 下面的截图显示了从易受攻击的示例应用程序开始转储 ENV 常量哈希,与从ENV.each do
开始的第二部分代码相关。
转储环境
在这个例子中,亚马逊 S3 API 密钥被存储在 ENV 中,并向公众公开。这显示了在存储于 ENV 常量散列中的环境变量中存储 API 秘密和其他敏感凭证是多么危险。我们将在下面详细讨论这是如何发生的。
转储更敏感的环境
更进一步,示例应用程序泄露了各种不同的云 API 和秘密,包括脸书、Twitter、LinkedIn 和 Google。
转储 API 密钥
Ruby 中的 env 和 ENV 是什么?
NV 是一个类似哈希的类,Ruby 用它向我们的应用程序公开环境变量。例如,我们的 rails 应用程序可以使用 PATH 或 HOME。Rack-mini-profiler 不需要做太多的事情来转储 ENV,因为该常量在应用程序启动时公开。开发人员有责任正确地存储、加载和保护 ENV。传统上,ENV 与环境变量相关,并且比 env 更加全局。这些变量中的每一个都被列为键/值对,它们通常用于共享配置。
像 Rails 这样的 ll Rack 应用程序只接受一个参数,这个参数是一个名为 env 的散列。env 被传递给 Rails 应用程序,并存储诸如 HTTP 头、请求和服务器配置等信息。与 ENV 相比, env 更适合 Rails。
漏洞
环境变量不应该用来存储敏感的配置信息,比如凭证和 API 密钥。如果必须使用它们,您的安全程序应该接受这种风险,将其记录在您的风险登记簿中,并提供适当的安全控制来降低风险。
关于环境变量及其正确使用已经说了很多。十二因素应用宣言声明环境变量应该被用来存储配置元素,比如亚马逊 S3 或 Twitter 等外部服务的凭证。
十二要素应用宣言
我不同意这个。遵循这种做法会增加您公司的商业风险。
这个示例应用程序展示了开发人员犯错误和无意中暴露敏感的 API 键(如 AWS)是多么容易,这些 API 键会导致数据泄露。创建此应用程序是为了模拟在列举上述问题后得到保护的野外生产环境。Rails 开发人员可以使用不同的环境,比如生产、QA 或开发。Rack-mini profiler 设计用于这些环境中的任何一种。暴露的环境变量,如果包含在开发环境中运行的敏感机密,会给攻击者提供凭证,允许未经授权的数据访问、信息泄漏和特权升级到生产。环境变量有一个存储配置元素的好地方。它们不应该被用于敏感的秘密。
T 这个示例应用程序使用 Dotenv rails gem 从.env
加载环境变量。这个示例应用程序使用.env.local
将文件中包含的所有填充的环境变量加载到由 Rack-mini-profiler 转储的 env 常量中。看看锤子的 Github 回购中也能看到的配置:
Hammer 附带的“. env.local”
除了通过中间件暴露敏感环境变量的风险之外,还有其他一些充分的理由说明为什么开发人员应该意识到这种实践中固有的风险。下面的列表总结了来自迪奥戈莫尼卡的一些风险:
- 由于没有正确使用 而将未加密的环境变量文件如
.env.local
复制到中央 Git 存储库中的风险。gitignore 文件。部落知识的风险,当没有设置系统的新开发人员没有适当注意保护这些包含环境变量的文件时。秘密被复制到不同的系统并被暴露。 - 应用程序可以获取整个环境,并打印出来用于调试或错误报告。如果在离开您的环境之前没有进行适当的清理,机密可能会泄露。
- 环境变量被传递给子进程,这可能导致意外的访问(例如,第三方工具可以访问您的环境)。
- 当应用程序崩溃时,通常将环境变量存储在日志文件中以供调试。这增加了磁盘上明文秘密的风险。
试验 ENV 和 Bash 环境
在我们开始玩一些 ENV 和环境变量的例子之前,让我们回顾一下 Ruby 环境变量的一些规律。 Honeybadger.io 就此给出了一个精彩的教程,我来总结一下:
- 每个进程都有自己的一组环境变量。
- 环境变量随着它们的过程而消亡。
- 一个进程从它的父进程继承它的环境变量。
- 对环境的更改不会在进程间同步。
- 您的 shell 只是环境变量系统的一个 UI。
这个例子遍历了 Rails 应用程序主目录中的 Hammer 环境。
转到 Rails Hammer 应用程序的工作主目录:
$ cd /home/<username>/hammer
Grep for SECRET 中的 .env.local 来看一些我们想玩的环境变量。
$ grep SECRET .env.local
你会看到几个皇冠宝石的 API 键。现在用env
打印 Bash shell 环境变量。您将看到所有的标准环境变量,比如
H
O
M
E
和
HOME 和
HOME和PATH。用env | grep SECRET
验证那些敏感变量当前没有加载到您的 Bash 环境中。
验证“env”命令不显示机密
运行交互式 Ruby 工具( irb ),我们看看会发生什么。默认情况下, irb 不会看到 ENV 公开的任何敏感环境变量。这是因为我们需要使用 Rails ‘dotenv’ gem 从.env
文件中加载变量。这表明,默认情况下,当实例化 Ruby 应用程序时,Rails 应用程序会将父进程(Bash shell)的环境变量继承到 ENV 常量中。但是我们需要以特殊的方式将额外的环境变量加载到 ENV hash constant 中,因为这些变量在默认情况下是不可用的。您将能够看到
P
A
T
H
∗
∗
∗
和
∗
∗
∗
PATH*** 和 ***
PATH∗∗∗和∗∗∗HOME ,但看不到其他任何内容。
$ irb
> ENV
> ENV['PATH']
> ENV['S3_SECRET_ACCESS_KEY']
启动 irb
获取一些环境变量
指示 irb 使用 dotenv gem 从 .env.local 文件中加载环境变量。这个命令将把环境变量加载到 ENV 中,使它们对我们的 irb ruby 环境可用。
> require 'dotenv';Dotenv.load('.env.local')
注意,所有漂亮的东西现在都有了,敏感的皇冠宝石 API 键!
使用 dotenv 加载. env.local 文件
验证您可以在 irb 终端中访问这些漂亮、敏感的 ENV 程序!
> ENV['S3_ACCESS_KEY_ID']
> ENV['S3_SECRET_ACCESS_KEY']
验证敏感的环境变量
接下来,打开一个新的外壳。启动 irb 并尝试列出 ENV 中存储的敏感环境变量。
默认情况下,ENV 不会在单独的进程之间共享或同步
注意,在第二个 shell 的 irb 会话中,没有列出敏感的环境变量。这是因为环境变量的工作方式。每个进程都有自己的一组环境变量,这些变量不会在进程之间自动同步。
现在尝试导出这些变量。如果你把export
放在.env.local
中命名的变量的语法前面,并源文件, 神奇地发生了 。这将本地 shell 变量转换为 ENV 可用的环境变量。然后任何从 bash shell 实例化的 Rails 子进程都可以使用它。锤子应用程序包括一个导出的变量文件样本,目的是以安全的方式处理敏感变量- .env.local.exported
。让我们试一试。
在第二个 shell 中,退出 irb 会话并键入 source 命令。然后运行 env 列出 bash shell 中的环境变量:
$ source .env.local.exported
$ env | grep SECRET
获取. env.local.exported 文件
现在在第二个 shell 中,重新启动 irb 并获取敏感的 ENV 变量。
$ irb
> ENV['S3_ACCESS_KEY_ID']
> ENV['S3_SECRET_ACCESS_KEY']
显示秘密被加载到 ENV 中
太神奇了!你不必调用 Dotenv gem 来自动加载到 env 中。这向您展示了 Dotenv gem 正在做什么——本质上是从 中获取变量。env 文件当环境被引导并加载到 env。然后通过 Rack-mini-profiler Pretty Printer(PP)ruby 类转储 ENV。
在本例中,我们最终将导出的变量提供给了 bash shell。一旦我们退出 shell,环境变量对于下一个启动的 bash shell 就不可用了。如果开发人员将命令添加到 shell init 脚本,如 。bashrc 这是应该避免这种做法的另一个原因。
存储机密的方法概述
- **明文存储秘密:**使用 Rails gem 方法如 Dotenv 或 Figaro 在环境中存储秘密,通过加载 env 访问。其他方法包括 rbenv-vars 插件和 direnv 。这些是流行的方法,但是开发者应该考虑更好的安全性。
- SaaS 秘密管理服务:使用诸如金库、 AWS 秘密管理器和许多其他服务在你的应用程序内同步和管理秘密。这是一种比明文存储秘密更好的方法,但是请记住,您必须保护一个超级机密的 SaaS API 密钥,它会保护您的所有秘密。
- **Rails 加密的秘密:**从 Rails 5.1 开始,您可以使用加密的秘密来为您的应用凭证提供更好的保护。可以使用除 ENV 键/值散列之外的特殊变量来访问它们。这里有一个很好的概述,从 Rails 6 开始,可以做多环境凭证管理。这是比第一种方法更安全的方法,与第二种方法相似。这应该将主加密密钥保存在您的 Rails 系统上,而不是与云 SaaS 同步。
推荐
以下是一些降低风险的建议。这些旨在提供想法,并应与您的开发运维流程保持一致。
- 卸下连接到公共互联网的所有系统上的 rack-mini-profiler gem。
- 在需要可访问公共互联网的 Rack-mini profiler 系统上:通过白名单/防火墙 IP 地址实施强访问控制,仅允许开发人员工作站访问 web 应用程序。
- 使用 RackMiniProfiler 访问控制来授权请求并将其列入白名单。RackMiniProfiler 有一个authorization _ mode在生产中加入白名单。参考自述文件中 非开发环境下的访问控制 章节。
- 使用加密的机密并避免使用 ENV 的环境变量来存储敏感的凭证。在本地执行此操作的最佳方法是 Rails 加密机密。这将避免将敏感变量加载到 ENV 中,因为这会增加它们被无意中暴露的风险。
结论
像 Rack-mini-profiler 这样的中间件为开发人员提高 Rails 应用程序的速度提供了优秀的特性;但是,必须应用安全控制来确保机密在您的应用程序中得到适当的保护,不会泄露给对手。
一位睿智的网络安全专家发表了这个简单而有力的声明:
我们都需要一起努力。任何弱点都是需要修正的弱点,让我们一起来修正它。
参考
https://github.com/MiniProfiler/rack-mini-profiler
https://www . speed shop . co/2015/08/05/rack-mini-profiler-the-secret-weapon . html
https://stack ify . com/rack-mini-profiler-a-complete-guide-on-rails-performance/
https://www . honey badger . io/blog/ruby-guide-environment-variables/
https://www . honey badger . io/blog/securing-environment-variables/
https://www . ruby guides . com/2019/01/ruby-environment-variables/
https://diogomonica . com/2017/03/27/why-you-should-use-env-variables-for-secret-data/
https://stack overflow . com/questions/61821207/rails-environment-variables-with-rack-mini-profiler
https://medium . com/craft-academy/encrypted-credentials-in-ruby-on-rails-9db 1 f 36d 8570
https://medium . com/poka-tech blog/the-best-way-to-store-secrets-in-your-app-308 a 6807 D3 ed
今日学习人工智能 Pytorch 入门
今天学 AI
定义和训练 Pytorch 模型并动态可视化结果
Jukan Tateisi 在 Unsplash 上拍摄的照片。
这是今天我创作的 学艾 系列中的第一个故事!这些故事,或者至少是前几个,是基于我在研究/学习 PyTorch 和深度学习时创作的一系列 Jupyter 笔记本。我希望你和我一样觉得它们很有用!
你将从这个故事中学到什么
- 如何创建 PyTorch 模型
- 如何训练你的模型
- 动态可视化培训进度
- 学习速度如何影响训练
1.PyTorch 中的线性回归
线性回归是一个你可能很熟悉的问题。最基本的形式就是用一条线来拟合一组点。
1.1 介绍概念
考虑一条线的数学表达式:
w
和b
是该线性模型的两个参数或权重。在机器学习中,通常使用w
指重量和b
指偏差参数。
在机器学习中,当我们训练一个模型时,我们基本上是在为一组给定的输入/目标(x,y)
对寻找最佳参数 w
和b
。在模型被训练之后,我们可以计算模型估计。该表达式现在将看起来
这里我把y
的名字改成ye
(y 估计),因为这个解不精确。
均方差(MSE) 就是mean((ye-y)²)
——目标值和估计值之间的均方差。对于一个回归问题,你确实可以最小化 MSE 以便找到最好的w
和b
。
线性回归的思想可以用代数矩阵符号来概括,以允许多个输入和目标。如果你想了解更多关于回归问题的数学精确解,你可以搜索正规方程。
1.2 定义模型
PyTorch nn.Linear
类是定义具有任意数量输入和输出的线性模型所需要的全部。对于将直线拟合到一组点的基本示例,考虑以下模型:
注: 我使用的 Module
来自fastai库,因为它使代码更干净。如果你想使用纯 PyTorch,你应该使用 nn.Module
来代替,你需要在 __init__
方法中添加 super().__init__()
。fastai Module
为你做到了。
如果你熟悉 Python 类,代码是不言自明的。如果没有,考虑在深入 PyTorch 之前做一些研究。有许多在线教程和课程涵盖了这一主题。
回到代码。在__init__
方法中,您定义了模型的层。在这种情况下,它只是一个线性层。然后,forward
方法就是当你调用模型时被调用的方法。类似于普通 Python 类中的__call__
方法。
现在,您可以将 LinearRegression 模型的一个实例定义为model = LinearRegression(1, 1)
,表示输入和输出的数量。
也许你现在在问为什么我不简单地做model = nn.Linear(1, 1)
你是绝对正确的。我在定义LinearRegression
类时遇到这么多麻烦的原因只是为了给以后的改进提供一个模板,稍后你会发现。
1.3 如何训练你的模型
训练过程基于一系列 4 个步骤,反复重复:
- **正向传递:**将输入数据提供给模型,并获得模型输出—
outputs = model(inputs)
- **计算损失函数:**对于线性回归问题,我们使用的损失函数是均方误差(MSE)。我们经常把这个函数称为标准—
loss = criterion(outputs, targets)
- **反向传递:**计算损失函数相对于每个可学习参数的梯度。记住,我们要减少损失函数,使输出接近目标。梯度告诉我们,如果你增加或减少每个参数,损耗会如何变化—
loss.backwards()
- 更新参数:在减少损失的方向少量更新参数值。更新参数的方法可以简单到减去乘以一个小数值的梯度值。这个数字被称为学习率,我刚刚描述的优化器是随机梯度下降(SGD) —
optimizer.step()
我还没有确切地定义criterion
和optimizer
,但我会在一分钟。这只是给你一个训练迭代步骤的总体概述和理解,或者通常称为训练时期。
让我们定义我们的fit
函数,它将完成所有需要的步骤。
请注意,在 — optimizer.zero_grad()
之前,还有一个额外的步骤我没有提到。这是因为默认情况下,在 PyTorch 中,当您调用loss.backwards()
时,优化器会将梯度值相加。如果你不在每个时期将它们设置为零,那么它们将会一直累加,这是不可取的。除非你在做梯度积累——但那是一个更高级的话题。除此之外,正如你在上面的代码中看到的,我保存了每个时期的损失值。我们应该预计它会稳步下降——这意味着该模型在预测目标方面变得越来越好。
正如我上面提到的,对于线性回归,通常使用的标准是 MSE 。至于优化器,现在我总是把 Adam 作为首选。它速度很快,应该可以很好地解决大多数问题。我不会详细说明 Adam 现在是如何工作的,但我们的想法总是在最短的时间内找到最佳解决方案。
现在让我们继续创建我们的线性回归模型的实例,定义我们的标准和我们的优化器:
model.parameters()
是向优化器提供可训练参数列表的方式,而lr
是学习率。
现在让我们创建一些数据并训练模型!
数据只是一组遵循模型y = 2x + 1 + noise
的点。为了让它更有趣一点,我让 x 的值越大噪声越大。第 4 行和第 5 行中的unsqueeze(-1)
只是在末尾给张量增加了一个额外的维度(从[10000]
到[10000,1]
)。数据是相同的,但张量需要有这样的形状,这意味着我们有 10000 个样本,每个样本有一个特征。
绘制数据,结果就是下图,可以看到真实的模型和输入数据+噪声。
线性回归模型的输入数据。图片由作者提供。
现在为了训练模型我们只需运行我们的 **fit**
函数!
经过训练后,我们可以绘制 100 个时期内损失的演变。正如您在下图中看到的,最初的损失约为 2.0,然后急剧下降到接近零。这是意料之中的,因为当我们开始时,模型参数是随机初始化的,并且随着训练的进行,它们收敛到解决方案。
100 个训练时期的损失演变(MSE)。图片由作者提供。
**注:**试试玩学习率值,看看对训练有什么影响!
要检查训练好的模型的参数,可以在训练完模型后运行list(model.parameters())
。您将会看到,在这个示例中,它们非常接近 2.0 和 1.0,因为真正的模型是y = 2x + 1
。
您现在可以计算模型估计值— ye = model(x_train)
。(请注意,在计算评估之前,您应该始终运行model.eval()
来将模型设置为评估模式。这对于这个简单的模型来说不会有什么不同,但是当我们开始使用批处理规范化和删除时,就会有所不同。)
绘制预测图,您可以看到它几乎完美地匹配了真实数据,尽管事实上模型只能看到有噪声的数据。
可视化模型评估。图片由作者提供。
2.逐步走向多项式回归
既然我们已经使它适用于简单的情况,那么转移到更复杂的线性模型就非常简单了。第一步当然是生成这样的输入数据。对于这个例子,我认为模型y = 3x² + 2x + 1 + noise
如下:
多项式模型的输入数据。图片由作者提供。
请注意,这次输入形状是[1000, 2]
,因为我们有两个对应于x
和x²
的特征。这就是使用线性回归拟合多项式的方法!
与前面的例子相比,现在唯一的区别是模型需要两个输入— model = LinearRegression(2,1)
。就是这样!现在,您可以按照完全相同的步骤来训练模型。
然而,让我们用一些动态的可视化来让事情变得更有趣一点吧!
2.1 动态可视化培训进度
为了动画化训练的发展,我们需要更新拟合函数,以便也存储每一步的模型估计值。
你可能注意到了一个‘新词’——detach()
(代码第 17 行)。这是告诉 PyTorch 从梯度计算图中分离变量(它将不再计算分离变量的梯度)。如果在分离之前尝试将张量转换为 NumPy,将会出现错误。
继续,您可以像以前一样重复相同的过程来训练模型。唯一的区别是fit2
函数也将返回每个训练时期的模型估计值。
要创建培训的视频/gif,请看下面的代码:
%%capture
告诉 Jupyter 抑制单元格的输出,因为我们将在下一个单元格中显示视频。然后,从第 3 行到第 10 行,我照常设置情节。不同之处在于模型预测。我将其初始化为空,然后使用matplotlib.animation
迭代更新图形以生成动画。最后,可以使用来自IPython.display
的HTML
渲染视频。看看下面的结果!
在训练期间可视化模型预测。作者的动画。
有趣的是,蓝线最初非常快地弯曲成正确的形状,然后为了最终的解决方案收敛得更慢!
注:尝试使用学习率、不同的优化器以及任何您能想到的东西,看看对优化的影响。这是一个直观了解优化工作原理的好方法!
3.神经网络模型
上面的例子对于学习和实验来说很有趣。然而,在实践中,你的数据通常不是由多项式生成的,或者至少你不知道多项式的项是什么。关于神经网络的一个好处是你不需要担心它!
让我们从定义我命名为GeneralFit
的模型开始:
在这个模型中有一些新的方面需要考虑。有 3 个线性层,正如你在正向方法中看到的,在前两个线性层之后,使用了一个 ReLU 激活函数 — F.relu()
—。 ReLU 代表整流线性单元,简单来说就是将所有负值归零。然而,这个看似琐碎的操作足以使模型非线性。
**注意,线性层只是矩阵乘法。**如果你有一个接一个的 100 个线性图层,线性代数会告诉你有一个线性图层执行相同的操作。这个线性层是 100 个矩阵的简单乘积。然而,当你引入非线性激活函数时,这就完全改变了。现在,您可以继续添加更多的线性层与非线性激活交错,如 ReLU(在最近的模型中最常见)。
一个深度神经网络只不过是一个具有几个“隐藏”层的神经网络。回头看看上面的代码,例如,你可以尝试添加更多的“隐藏”层并训练模型。事实上,你可以称之为深度学习。(请注意,隐藏层只是输入层和输出层之间任何层的传统名称。)
使用上述模型和一组新生成的数据,我获得了以下训练动画:
以 0.01 的学习率在训练期间可视化 GeneralFit 模型的模型预测。作者的动画。
对于这个例子,我训练了 200 个纪元,学习率为 0.01。让我们试着将学习率设置为 1。
在学习率为 1 的训练期间可视化 GeneralFit 模型的模型预测。作者的动画。
显然这样不好!当学习率过高时,模型可能无法正确收敛到一个好的解,甚至可能发散。如果你把学习率设定为 10 或 100,它不会有任何进展。
家庭作业
我可以给你看一千个例子,但如果你能自己做一两个实验,你会学到更多!我给你们展示的这些实验的完整代码可以在这个笔记本上找到。
- 试着玩一下学习率,历元数,隐藏层数,隐藏层数的大小;
- 也试试 SGD optimizer,玩玩学习率,也许还玩玩动量(我在这个故事中没有涉及到,但现在你知道了,你可以做一些研究);
如果你通过实验创造了有趣的动画笔记本,那就在 GitHub、Kaggle 上分享吧,或者写一个关于它的故事!
结束语
今日学 AI系列第一个故事到此结束!
- 请考虑 在此链接加入我的邮件列表 获取更新,以便您不会错过以下任何故事或重要更新!
- 我还会在 learn-ai-today.com列出新的故事,这是我为这次学习之旅创建的页面!
- 如果你以前错过了,这是 Kaggle 笔记本的链接,上面有这个故事的代码!
欢迎在评论中给我一些反馈。你觉得什么最有用,或者什么可以解释得更好?让我知道!
本系列的下一个故事:
** [## 今日学习人工智能:02 —使用 PyTorch 解决分类问题简介
用神经网络对花卉进行分类,可视化决策边界和理解过度拟合。
towardsdatascience.com](/learn-ai-today-02-introduction-to-classification-problems-using-pytorch-b710918cba63)
你可以在下面的故事中了解更多关于我的旅程!
[## 我的 3 年历程:从零 Python 到深度学习竞赛高手
自从 2017 年开始学习 Python 以来,我一直遵循的道路是成为一名独自参加 Kaggle 比赛的大师…
towardsdatascience.com](/my-3-year-journey-from-zero-python-to-deep-learning-competition-master-6605c188eec7) [## 我在 Kaggle 上的两年旅程:我如何成为竞赛大师
描述我的旅程和策略,我遵循成为一个竞赛大师与个人金牌
towardsdatascience.com](/my-2-year-journey-on-kaggle-how-i-became-a-competition-master-ef0f0955c35d)
感谢阅读!祝您愉快!**
今天学习人工智能 02:使用 PyTorch 的分类问题介绍
今天学 AI
用神经网络对花卉进行分类,可视化决策边界和理解过度拟合。
这是我创作的 今日 AI系列的第二个故事!这些故事,或者至少是前几个,是基于我在研究/学习 PyTorch 和深度学习时创作的一系列 Jupyter 笔记本。我希望你和我一样觉得它们很有用!
如果你还没有,一定要检查以前的故事!
定义和训练 Pytorch 模型并动态可视化结果
towardsdatascience.com](/learn-ai-today-01-getting-started-with-pytorch-2e3ba25a518)
你将从这个故事中学到什么:
- 验证的重要性
- 如何为分类问题训练模型
- 动态可视化决策边界
- 如何避免过度拟合**
1.鸢尾花数据集
让我们从介绍数据集开始。我将使用非常著名的 鸢尾花数据集 ,它包含以下 3 种花的 4 种不同测量值(萼片长度、萼片宽度、花瓣长度、花瓣宽度)。
图片改编自维基百科。
****目标是使用每朵花的 4 个测量值准确识别物种。注意,现在使用直接从图像中学习的模型(卷积神经网络)相对容易,但我将把这个话题留到下一课。如下面的代码所示,鸢尾花数据集可以很容易地从 sklearn 数据集中下载。
为了快速显示数据,我们绘制每对要素的散点图和每个要素的直方图。为了实现这个表示,我使用了pandas . plotting . scatter _ matrix函数(和往常一样,你可以在最后找到完整代码的链接)。
鸢尾花数据的可视化(蓝点——鸢尾;蓝绿色的点——杂色鸢尾;黄点——海滨鸢尾)。图片由作者提供。
正如你在上面的散点图中看到的,对于大多数样品来说,区分物种应该很容易。例如,在大多数地块中,刚毛鸢尾点与其他两个物种非常接近。对于这样一个简单的例子,你可以通过画几条线来创建一个基于规则的算法。然而,为了简单起见,也是一个用神经网络介绍分类的好例子!****
2.验证集
在直接进入模型和训练之前,创建一个验证集非常重要。为了避免一次引入太多概念,我在第一课中跳过了这一步。
验证集的想法很简单。不是用你所有的数据训练一个模型,而是把一小部分数据(通常是 20% — 30%)储存起来,你将使用这些数据来评估训练好的模型是否能很好地推广到看不见的数据。这对于确保您的模型可以安全地投入生产以准确评估新数据非常重要。
在上面的代码中,我使用了train_test_split
函数来随机分割数据,我选择了一个test_size=0.5
。设置random_state
总是一个好主意,以确保当您重新运行代码时,将使用相同的分割。
请注意,这是一个常见且良好的实践,两个不是 2 个而是 3 个数据分割:训练、验证和测试。在这种情况下,当你尝试几个模型、想法和超参数(如学习率)时,你使用验证集来检查进度,当你对结果满意时,才在最后使用测试集。这就是在卡格尔比赛中发生的事情,那里通常有一个隐藏测试装置**。**
3.为分类训练模型
我将在这个例子中使用的模型与我在上一课中用于回归问题的模型完全相同!
那么有什么区别呢?不同之处在于损失函数。对于多类分类问题,通常的选择是交叉熵损失 (nn。PyTorch 中的 CrossEntropyLoss)。对于二元分类的问题,你通常会用二元交叉熵 损失 (nn。BCEWithLogitsLoss)。因此,用于定义模型、标准和优化器的代码与我在上一课中用于回归的代码非常相似!
要考虑的另一个区别是最后一个激活函数。对于回归问题,模型的输出是一个数字,可以是任何实数值。对于二进制分类**,您需要使用一个 Sigmoid 激活函数将输出映射到 0–1 范围。对于多级分类,您需要 Softmax 激活功能(除非您想要允许多项选择,在这种情况下使用 Sigmoid 激活)。Softmax 输出可以解释为分配给每个类的概率。**
现在不要太担心激活函数。我只是在这里提一下,让你意识到他们的存在。目前,值得一提的是。CrossEntropyLoss 包括为您激活的 Softmax 和 nn。BCEWithLogitsLoss 为您提供乙状结肠。这样你就不需要在模型的末尾添加任何激活函数。PyTorch 会帮你搞定的!
在训练模型之前,我还修改了上一课的fit
函数(你可以在 Kaggle 笔记本上查看,最后有完整的代码),以考虑到train
和test/validation
数据。(当只处理两个数据集时,术语验证和测试经常互换使用。)
绘制 1000 次训练中的训练和测试损失图,你可以看到有些奇怪的事情正在发生**。**
训练和测试损失。图片由作者提供。
虽然列车损失随着时间的推移不断改善,但测试损失最初稳步改善,但随后开始增加**。也许最重要的是,你可以通过绘制模型在 1000 个时期的精确度来看到同样的效果。**
训练和测试准确性。图片由作者提供。
你现在看到的是我们所说的过拟合**——在的某个点,模型开始“记忆”训练数据,而的泛化性能(用测试集评估)下降。这就是为什么你需要一个验证/测试集。在这种情况下,你可以看到,如果你在 200 个时期停止训练,结果可能会更好。这种方法称为提前停止,是一种减少过拟合的简单方法。然而,还有其他的方法,比如使用重量衰减,我马上会谈到。让我们首先做一些有趣的可视化来更好地理解正在发生的事情。**
4.可视化决策边界并减少过度拟合
为了可视化训练边界并更好地理解过度拟合,我仅使用 2 个(而不是 4 个)特征来重新训练模型,以便容易地在 2D 图形中绘制结果。在下面的动画中,您可以看到在 1000 个训练时期中,训练(左)和测试(右)的决策界限不断演变。
在 1000 个训练时期可视化模型决策边界。作者的动画。
看看最初模型如何快速学习划分区域的 2 条直线边界**。然后,红黄边界开始向上弯曲,更好地适应列车组。然而,观察测试集,这导致了性能的轻微下降,因为更多的黄色点移动到中间区域,而蓝绿色点移动到顶部区域。而这正是过度拟合的样子**。对于更复杂的问题,你可以在多维度中想象这一点——当你有很多维度时,更容易过度拟合。****
如果你很难想象任何超过 3 维的东西,只要遵循 Geoffrey Hinton 的建议:“要处理 14 维空间中的超平面,想象一个 3 维空间,并大声对自己说‘14’。大家都这么干。”****
为了减少这个例子中的过度拟合,可以使用两个简单的“技巧”:
- ****提前停止:用更少的时期训练模型
- ****权重衰减:通过在每次迭代中少量减少模型权重,使其变小
4.1 提前停止
提前停止的想法非常简单,正如我之前提到的,如果模型在大约 200 个历元时具有最佳验证精度,那么如果你只训练 200 个历元,你将得到一个概括得更好的模型——根据验证精度。问题是,您可能会在视觉上过度适应验证集——特别是当您根据验证分数调整许多超参数时。这就是为什么在完成所有实验后,获得一组额外的数据来评估模型是非常重要的。
4.2 重量衰减
****体重衰减的思路也很简单。当拟合一个神经网络时,一般来说,不存在最优解,而是存在多个可能的相似解。权重衰减,通过迫使权重保持较小,将迫使优化过程达到更简单的解决方案。
让我们给我们的模型添加一个weight_decay=0.01
,并像以前一样在训练 1000 个时期后可视化结果。在 PyTorch 中,您只需要将这个参数作为optimizer = optim.Adam(model.parameters, lr=0.001, weight_decay=0.01)
添加到优化器中。生成的动画如下。
在权重衰减为 0.01 的 1000 个训练时期期间可视化模型决策边界。作者的动画。
如您所见,现在红黄边界不会像以前那样向上弯曲,因为这需要大幅增加权重,而且精度不会有太大变化。
用具有重量衰减的 4 个输入特征来训练模型,得到了下面的训练和测试损失图。看,现在测试损失没有像以前一样开始增加!****
用重量衰减训练的模型的训练和测试损失。图片由作者提供。
同样重要的是要提到当你开始一个新项目时,过度适应是你应该瞄准的目标**。从一个可以过度拟合数据的模型开始,这样你就知道你的模型有足够的“灵活性”来学习数据中的模式。然后增加正则化,像权重衰减,避免过拟合!**
家庭作业
我可以给你看一千个例子,但如果你能自己做一两个实验,你会学到更多!这些实验的完整代码可以在 这本笔记本 上找到。
- 和上一课一样,试着玩学习率、时期数、重量衰减和模型大小。
- 做些实验,看看结果是否如你所愿,如果不是,看看视觉效果,试着理解为什么。
和往常一样,如果你通过实验创作出了有趣的动画笔记本,那就在 GitHub、Kaggle 上分享吧,或者写一个中型故事!
结束语
Learn AI Today 系列第二个故事到此结束!
- 请考虑将 加入我的邮件列表,点击此链接 获取更新,这样你就不会错过下面的任何故事或重要更新了!
- 我还会在 learn-ai-today.com列出新的故事,这是我为这次学习之旅创建的页面!
- 如果你以前错过了, 这是 Kaggle 笔记本的链接,上面有这个故事的代码!
欢迎在评论中给我一些反馈。你觉得什么最有用,或者什么可以解释得更好?让我知道!
你可以在下面的故事中了解更多关于我的旅程!
**** [## 我的 3 年历程:从零 Python 到深度学习竞赛高手
自从 2017 年开始学习 Python 以来,我一直遵循的道路是成为一名独自参加 Kaggle 比赛的大师…
towardsdatascience.com](/my-3-year-journey-from-zero-python-to-deep-learning-competition-master-6605c188eec7) [## 我在 Kaggle 上的两年旅程:我如何成为竞赛大师
描述我的旅程和策略,我遵循成为一个竞赛大师与个人金牌
towardsdatascience.com](/my-2-year-journey-on-kaggle-how-i-became-a-competition-master-ef0f0955c35d)
感谢阅读!祝您愉快!****
学习人工智能今天 03:马铃薯分类使用卷积神经网络
今天学 AI
在 PyTorch 中创建一个 CNN 模型,并使用 fastai2 训练它识别土豆的类型,以简化代码
这是 学艾今日 系列的第 3 个故事!这些故事,或者至少是前几个,是基于我在研究/学习 PyTorch 和深度学习时创作的一系列 Jupyter 笔记本。我希望你和我一样觉得它们很有用!
如果你还没有,一定要检查以前的故事!
[## 今日学习人工智能:02 —使用 PyTorch 解决分类问题简介
用神经网络对花卉进行分类,可视化决策边界和理解过度拟合。
towardsdatascience.com](/learn-ai-today-02-introduction-to-classification-problems-using-pytorch-b710918cba63)
你将从这个故事中学到什么:
- 土豆并不都一样
- 使用 Kaggle 数据集
- 卷积神经网络如何工作
- 使用 fastai2 让您的生活更轻松
1.Kaggle 数据集
如果你想找到一个公共数据集,Kaggle 数据集页面是一个很好的起点。Kaggle 上有近 5 万个数据集,随着用户创建和上传新的数据集与世界分享,这个数字每天都在增长。
有了为这节课创建一个土豆分类器的想法后,我很快找到了这个数据集,它包含了 4 类土豆以及许多其他水果和蔬菜。
来自水果 360 数据集的图像样本。
2.卷积神经网络
计算机视觉的构建模块是卷积神经网络。这些网络通常结合了几层核卷积运算和缩减。
下面的动画是对内核卷积操作的可视化展示。内核是一个小矩阵,通常是 3x3,在整个图像上移动。让我们称它为输入特征图,而不是图像,这样更通用。
来自 Theano 文档的卷积示例。
在每一步中,内核 3x3 矩阵的值按元素乘以输入特征映射的相应值(上面动画中的蓝色矩阵),这 9 个乘积之和就是输出值,从而得到动画中的绿色矩阵。内核中的数字是待学习模型的参数。通过这种方式,模型可以学习识别作为计算机视觉基础的空间模式。通过拥有多层并逐渐缩小图像,每个卷积层学习到的模式越来越复杂。为了更深入地了解 CNN,我推荐 Irhum Shafkat 的这个故事。
CNN 的想法从 80 年代就有了,但它在 2012 年开始获得动力,当时 ImageNet 竞赛的获胜者使用了这种方法并“击败”了竞争对手。他们的论文描述了解决方案,摘要如下:
“我们训练了一个大型深度卷积神经网络,将 ImageNet LSVRC-2010 大赛中的 120 万幅高分辨率图像分类为 1000 个不同的类别。在测试数据上,我们实现了 37.5%和 17.0%的前 1 名和前 5 名错误率,这大大优于以前的最先进水平。具有 6000 万个参数和 650,000 个神经元的神经网络由五个卷积层组成,其中一些卷积层后面是 max-pooling 层,以及三个完全连接的层,最后是 1000 路 softmax。为了加快训练速度,我们使用了非饱和神经元和卷积运算的高效 GPU 实现。为了减少全连接层中的过拟合,我们采用了最近开发的正则化方法“dropout ”,该方法被证明非常有效。我们还在 ILSVRC-2012 竞赛中加入了该模型的一个变体,并获得了 15.3%的前五名测试错误率,而第二名的错误率为 26.2%。”
前五名的错误率为 15.3%,而第二名的错误率为 26.2%,这是一个巨大的突破。快进到今天, 当前前 5 名结果 准确率为 98.7%(错误率 1.3%)。
现在让我们用两个卷积层编码一个非常简单的 CNN,并用它来创建一个土豆分类器!
- 第一卷积层
nn.Conv2d
具有 3 个输入通道和 32 个输出通道,其内核大小为 3×3。输入通道的数量 3 对应于 RGB 图像通道。输出通道数只是一个选择。 - 第二卷积层具有 32 个输入通道和 64 个输出通道,以匹配前一层的输出通道数量。
- 注意第 9 行和第 10 行,在卷积层之后,我应用了一个
F.max_pool2d
和一个F.relu
。 max-pooling 操作将通过选择每个 2x2 像素的最大值来缩小图像。这样得到的图像只有一半大小。 ReLU 是一个非线性激活函数,正如我在本系列的第 1 课中提到的。 - 在大小为 2 的两次卷积和最大池化之后,得到的特征图的大小是原始图像的 1/4。我将使用 64x64 的图像,因此这将产生一个 16x16 的特征地图。我可以添加更多的卷积层,但在某些情况下,当特征图已经很小时,通常,下一步是使用平均池,通过计算平均值将特征图减少到 1x1。注意,因为我们有 64 个通道,结果张量将有一个
(batch-size, 64, 1, 1)
的形状,然后在应用最后的线性层之前,它将被整形为(batch-size, 64)
。 - 最终线性层的输入大小为 64,输出大小等于要预测的类别数**。在这种情况下,将是 4 种类型的土豆。**
**注意:**理解一切工作原理的一个好方法是使用 Python 调试器。您可以将import pdb
和pdb.set_trace()
包含在 forward 方法中。然后你可以一步一步地移动,检查每一层的形状,给你一个更好的直觉或者帮助调试问题。
3.使用 fastai2 让您的生活更轻松
当有工具可以让你的生活更轻松时,不值得浪费时间为深度学习管道的每一步编码。这就是为什么在这个故事中我将使用 fastai2 库 来完成大部分工作。然而,我将使用前一节中定义的基本 CNN 模型。请注意,fastai2 使用 PyTorch,并使每个步骤的定制变得容易,这使它对初学者和高级深度学习实践者和研究人员都有用。
下面 12 行代码就是 fastai2 中的整个深度学习流水线,使用的是上一节定义的 BasicCNN !你可以在这里找到本课所有代码的笔记本。
- 第 1-6 行:定义了 fastai 数据块。我在这个和这个故事中谈到了 fastai 数据块的话题。图像块和类别块表示数据加载器将有一个图像类型的输入和一个类别类型的目标。
- 第 2 行和第 3 行:
get_x
和get_y
是给出处理输入和目标的函数的参数。在这种情况下,我将从 pandas dataframe 中读取列“file”(每个图像文件的路径)和“id”(马铃薯的类型)。 - 第 4 行:
splitter
是一个参数,可以告诉你如何将数据分成训练集和验证集。这里我使用了RandomSplitter
,默认情况下随机选择 20%的数据来创建验证集。 - **第 5 行:**添加了一个变换,将图像的大小调整为 64x64。
- **第 6 行:**包括标准化和图像放大。请注意,我使用的是默认的扩充。fastai 的一个优点是,大多数情况下,您可以使用默认设置,而且它很有效。这对学习非常有好处,因为在开始做有趣的工作之前,你不需要了解所有的细节。
- **第 8 行:**data loaders 对象被创建。(
train_df
是带有file
和id
列的数据帧,查看完整代码此处)。 - **第 9 行:**创建一个类数为 4 的 BasicCNN 模型的实例(注意
dls.c
自动指示类数)。 - **第 10 行:**定义了 fastai Learner 对象。这是您指出模型、损失函数、优化器和验证指标的地方。我将使用的损失函数是
nn.CrossEntropyLoss
,正如在上一课中所述,它是超过两个类别的分类问题的首选。 - **第 12 行:**使用一次循环学习率时间表(学习率快速增加到
lr_max
,然后逐渐减少)和 0.01 的权重衰减来训练模型 30 个时期。
经过 30 个时期的训练,我用这个简单的 CNN 模型获得了 100%的验证准确率!这是训练和验证损失看起来像一个训练过程:
培训和验证损失在培训过程中的演变。图片由作者提供。
就是这样!如果你按照代码操作,你现在可以非常准确地识别 4 种土豆。最重要的是,这个例子中没有任何东西是关于土豆的!您可以对几乎任何想要分类的东西应用类似的方法!
家庭作业
我可以给你看一千个例子,但如果你能自己做一两个实验,你会学到最多!这个故事的完整代码可以在这个笔记本上找到。
- 和上一课一样,试着玩学习率、时期数、重量衰减和模型大小。
- 不使用 BasicCNN 模型,尝试使用在 ImageNet 上预训练的 Resnet34(看看 fastai
cnn_learner
)结果如何比较?可以尝试更大的图像尺寸,激活 Kaggle 内核上的 GPU,让训练更快!(Kaggle 免费为您提供 30h/周的 GPU 使用量) - 现在,使用数据集中的所有水果和蔬菜训练模型,并查看结果。该数据集还包括一个测试集,您可以使用它来进一步测试训练好的模型!
和往常一样,如果你通过实验创作出了有趣的动画笔记本,那就在 GitHub、Kaggle 上分享吧,或者写一个中型故事!
结束语
Learn AI Today 系列第三个故事到此结束!
- 请考虑 在这个链接中加入我的邮件列表 ,这样你就不会错过我即将发布的任何故事了!
- 我还会在 、learn-ai-today.com、我为这次学习之旅创建的页面以及GitHub 资源库 列出新故事!
- 如果你以前错过了, 这是 Kaggle 笔记本的链接,上面有这个故事的代码!
欢迎在评论中给我一些反馈。你觉得什么最有用,或者什么可以解释得更好?让我知道!
你可以在下面的故事中了解更多关于我的深度学习之旅!
[## 我的 3 年历程:从零 Python 到深度学习竞赛高手
自从 2017 年开始学习 Python 以来,我一直遵循的道路是成为一名独自参加 Kaggle 比赛的大师…
towardsdatascience.com](/my-3-year-journey-from-zero-python-to-deep-learning-competition-master-6605c188eec7) [## 我在 Kaggle 上的两年旅程:我如何成为竞赛大师
描述我的旅程和策略,我遵循成为一个竞赛大师与个人金牌
towardsdatascience.com](/my-2-year-journey-on-kaggle-how-i-became-a-competition-master-ef0f0955c35d)
感谢阅读!祝您愉快!
今日学习人工智能 04:时间序列多步预测
今天学 AI
创建和训练 1D 卷积神经网络,以预测用 Mackey-Glass 方程生成的混沌时间序列的多个未来时间步长
这是 学艾今日 系列的第 4 个故事!如果你还没有,一定要检查以前的故事。
[## 今天学习人工智能:03 —使用卷积神经网络的马铃薯分类
在 PyTorch 中创建一个 CNN 模型,并使用 fastai2 训练它识别土豆的类型,以简化代码
towardsdatascience.com](/learn-ai-today-03-potato-classification-using-convolutional-neural-networks-4481222f2806)
你将从这个故事中学到什么:
- 创建一个混乱的时间序列
- 按顺序拆分系列以提供给模型
- 定义和训练用于时间序列预测的 1d 卷积神经网络
- 使用 fastai2 数据集和学习器
1.创建一个混乱的时间序列
在一个混沌系统中,初始条件的一个非常小的变化就可能导致完全不同的结果。在这样的系统中,即使你知道描述未来的确定性方程,你也无法准确预测未来。为什么?因为你需要一台无限精确的计算机和无限精确的初始条件。事实上,这根本不可能。这就是为什么天气预报只在短期内准确。随着时间的推移,随着动态和统计模型的改进以及计算能力的提高,它们也在不断改进。然而,不可能长期准确地预测每天的天气,因为它是一个混沌系统。
为了生成一个混沌时间序列,我将使用 Mackey-Glass 方程,参数在这里描述。Python 代码如下所示:
前 500 个样本的结果如下:
麦基-格拉斯时间序列。图片由作者提供。
请注意,时间序列中有一个模式,但有很多变化,无法在很长一段时间内可靠地预测。
2.按顺序拆分系列以提供给模型
用上面的代码生成的数据是一个很长的序列。为了训练一个模型,我将把数据分成 500 个元素的较小序列。输入数据将是前 100 个元素,而目标数据(未来预测)将是剩余的 400 个元素。此外,数据的前 2/3 将用作训练数据,而后 1/3 用作验证数据。
**注意:**处理时间序列时,选择序列的最后一部分进行验证通常是个好主意,特别是当您想要预测未来时。否则,该模型可能会学习自相关,并产生误导性的好结果,这将在应用于未来时“打破”实践。
上面的代码简单地运行长序列,并创建如上所述的输入和目标序列,按照模型所需的格式重新整形。对于图像数据和通常的 2D 卷积神经网络,张量以形状[批量大小,通道,行,列]组织。这里对于 **1D 卷积神经网络,**也是一样的,但是去掉了最后一个维度。并且实际上有可能具有多个时间序列的输入(表示为几个通道)。
3。定义和训练模型
我为这个实验定义的模型是一个 1D 卷积神经网络,它有 3 个卷积层,然后是 ReLU 激活和批量归一化,最后是平均池和两个线性层。基本原理类似于 2D 卷积层。每个连续的层都可以捕获越来越复杂的数据模式。批量标准化有助于使训练更快、更稳定,即使在非常深的神经网络中。你可以看这个 10 分钟的视频,吴恩达解释了为什么 Batch Norm 有效。
还注意到,在最后一个线性层之前,我使用了一个下降(第 26 行)。漏失(在第 10 行中定义,概率为 0.5)通常是一种成功的正则化方法。它只是随机删除特征图中的一些元素,使数据每次都略有不同。以一幅图像为例。丢弃就像删除图像的一些像素。最有可能的是,您仍然可以识别图像中的对象,因此模型必须学习它,从而产生更健壮的模型。
**注意:**在推断时间内,辍学是不活跃的。这也是你需要在运行推理之前调用model.eval()
的原因之一,否则会应用 dropout。
使用 fastai Datasets
类很容易创建数据加载器,然后使用 fastai Learner
将数据加载器与模型结合起来。学习者类处理训练和预测。
- 在上面的代码中,数据集是通过给出一个项目列表和一个函数来定义输入和其他目标而创建的(第 1 行)。我之前将序列和目标定义为张量
x
和y
(这里是完整代码),因此我只需要从这些张量中选择元素。你可以在文档中阅读更多关于 fastaiDatasets
的信息。 - 如您所见,在第 5 行中,我使用一个周期学习率时间表训练模型 20 个时期(学习率上升,直到达到
max_lr
,然后逐渐衰减)。fastai 提供的又一个好特性!
在训练过程中,下表打印了结果,您可以看到随着训练的进行,训练和验证损失逐渐下降。
训练进展表。图片由作者提供。
如上表所示,列车损失高于验证损失有几个原因。在这种情况下,一个可能的原因是仅用于培训的辍学本身的使用。你可以试着运行没有脱落的代码,检查一下是不是这样!
现在模型已经定型,让我们计算验证的预测。Learner
的get_preds
方法可以如下使用:ye_valid, y_valid = learn.get_preds().
注意,我不需要调用model.eval()
,因为 fastai get_preds
已经处理了这些细节。然而有一点需要记住。
有了结果,是时候可视化预测了!这是最好玩的部分。下面的代码创建了一个包含 12 个验证序列的可视化图像。
结果的可视化。绿线代表真实数据,红线代表预测。输入数据显示在垂直黑条上。图片由作者提供。
如上图所示,模型预测(红色)从紧跟目标(绿色)开始,但随着时间的推移,性能开始下降。事实上,如果我沿着时间轴绘制均方差(MSE ),结果如下:
MSE 超过 400 的预测序列。图片由作者提供。
由于数据的混乱性质,这是意料之中的。这个结果还能进一步提高吗?可能是的,我在准备这个故事时尝试了几种不同的选择,真正的学习是查看代码并进行自己的观察和实验。
家庭作业
我可以给你看一千个例子,但如果你能自己做一两个实验,你会学到最多!这个故事的完整代码可以在 这个笔记本 上找到。
- 尝试改变模型、超参数、优化函数、输入和输出序列的大小,看看它如何影响结果。
- 将该模型应用于你可能感兴趣的某个问题的另一个时间序列。成绩如何?
和往常一样,如果你通过实验创作出了有趣的动画笔记本,那就在 GitHub、Kaggle 上分享吧,或者写一个中型故事!
结束语
今日学 AI系列第四个故事到此结束!
- 请考虑 在这个链接中加入我的邮件列表 ,这样你就不会错过我即将发布的任何故事了!
- 我还会在learn-ai-today.com**—**我为这次学习之旅创建的页面上列出新的故事,并在GitHub 知识库 列出新的故事!
- 如果你以前错过了, 这是 Kaggle 笔记本的链接,上面有这个故事的代码 !
欢迎在评论中给我一些反馈。你觉得什么最有用,或者什么可以解释得更好?让我知道!
你可以在下面的故事中了解更多关于我的深度学习之旅!
[## 我的 3 年历程:从零 Python 到深度学习竞赛高手
自从 2017 年开始学习 Python 以来,我一直遵循的道路是成为一名独自参加 Kaggle 比赛的大师…
towardsdatascience.com](/my-3-year-journey-from-zero-python-to-deep-learning-competition-master-6605c188eec7) [## 我在 Kaggle 上的两年旅程:我如何成为竞赛大师
描述我的旅程和策略,我遵循成为一个竞赛大师与个人金牌
towardsdatascience.com](/my-2-year-journey-on-kaggle-how-i-became-a-competition-master-ef0f0955c35d)
感谢阅读!祝您愉快!
Git 和 GitHub 入门:初学者完全教程
动手教程
关于如何在 15 分钟内使用 GitHub 的完整教程
Git 作为一个版本控制系统
G 它是全球开发者普遍使用的开源版本控制系统。版本控制系统帮助开发人员对开源项目做出贡献,并检查代码的版本。git 是由 Linux 创始人 Linus Torvald 开发的,作为帮助 Linux 开发人员开发和维护代码的工具。所以,git 是 Linus Torvald 支持主项目 Linux 的第二个项目。
git 作为版本控制工具的图示(图片由作者提供)
上图清楚地向我们解释了 git 作为版本控制工具的功能。它让我们可以处理单个文件,而不是有各自版本的多个文件。使用基本版本(许多文件)往往是不可跟踪和非结构化的。我们也无法跟踪我们的修订。但是,使用 git,任何修订或更改都将被记录在 git 系统上,作为用户,我们可以根据需要返回到文件的某个版本。从 git 日志中,我们可以从头开始跟踪我们工作中的修订。
作为协作工具,git 将电子邮件、短信、聊天等基本协作方式移植到协作系统中。对于一个有很多人参与的大项目来说,基本的协作往往是不完整的、误解的、糟糕的日志,并且效率低下。
Git 是为基于文本的数据设计的,例如代码、书籍、论文、文章等
许多公司和开源项目都在使用版本控制系统来管理他们的项目,比如谷歌、脸书、微软、推特、LinkedIn 等等。所以,这就是为什么我们需要学习基本的 git 命令,为我们未来在科技公司的工作和职业生涯服务。
如何安装 Git
在你的电脑上安装 git 似乎很容易。但是这也取决于你的操作系统。对于 Windows 用户,你可能需要去 git 官方网站下载它。幸运的是,对于 Linux 用户,只需打开我们最喜欢的终端并运行如下脚本:
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git
安装完成后,一切都会好的。用下面的命令检查我们的 git 版本。
**# Check our git version**
git --version
Git 版本 2.17.1(图片由作者提供)
配置
第一步,在深入讨论 git 及其环境之前,我们需要配置我们的 git。我们向它提供一个用户名和电子邮件**。**
**# Setup the git configuration**
git config --global user.name "your-username"
git config --global user.email "your-email"
设置 git 配置(图片由作者提供)
查看我们的 git 全局配置(图片由作者提供)
Git 作为版本控制工具
对于我们第一次接触 git,让我们创建一个目录,例如,在我的例子中是 git-stk ,然后移动到那个目录中。然后,从**git init**
开始我们的练习。重要的是注意到**git status**
将打印我们的作品的状态,如目录或文件有任何变化。只要我们没有做任何修改,命令**git status**
将 打印出来还没有提交 。
git 的初始化(图片由作者提供)
那么,**git init**
是什么意思呢?简单来说,这个命令将创建一个包含几个文件夹和文件的**.git**
文件夹,比如**hooks**
、**info**
、**objects**
、**refs**
、**config**
、**description**
和**HEAD**
,以便跟踪我们的工作。我们的更改日志将被记录在那里。
中的目录。git 初始化后的 git 文件夹(图片由作者提供)
为了与 git 命令进行交互,让我们创建一个新的 markdown 文件,即 README.md ,其中填充了句子*“readme . MD 文件的第一行”*。
创建一个新文件与 git 交互(图片由作者提供)
让我们用**git status**
命令检查当前状态。它打印出红色标记,表明我们对 git-stk 中的文件夹或文件做了任何更改。这也意味着我们的改变还没有被标记出来。我们处于 git 生命周期中的修改状态。
README.md 在修改状态下的状态(图片由作者提供)
要在文件 README.md 中标记我们的更改,请运行**git add**
命令。要查找修改状态和暂存状态之间的状态差异,只需再次运行**git status**
。绿色标记表示我们的更改已被标记,现在我们处于暂存状态。
README.md 运行**git add**
命令后的状态(图片由作者提供)
我们的 README.md 文件已被标记,但尚未录制。记录我们的更改,就像我们在使用 Microsoft Word 或其他带有**git commit**
的工具时一样,然后是提交消息。
README.md 已提交(图片由作者提供)
Git 生命周期
到目前为止,我们已经在 git 环境中进行了实验,并分配了 git 命令。但是现在,我们将深入探讨 git 的生命周期。我们之前所做的就是我们在 git 生命周期中看到的。git 生命周期分为四个状态,即:
- 已修改:尚未标记任何更改。我们可以在这里做任何事情,操作文件,创建或删除一个新的文件夹,以及其他事情
- Staged :我们的变更已经被标记但还没有被记录的状态
- 提交:成功的文件夹或文件被记录到我们的中。git 文件夹
Git 生命周期(图片由作者提供)
继续追踪我们的日志
你能想象如果我们在文件夹中犯了一些错误吗?我们可以倒退回上一次提交或两次提交吗?答案是我们当然可以。Git 保存我们的更改(提交),如果我们的工作需要,我们可以去任何地方。好了,下面是你必须知道的新 git 命令:**git log**
。我们将记录我们的整个提交,所以我们可以很容易地跟踪我们的工作或提交。
在之前的提交中,我们创建了一个名为 README.md 的文件。现在,我们将使用 git logs 命令修改该文件并检查其日志。首先用句子*“readme . MD 文件第二行”*添加我们的 README.md 文件然后提交。只需遵循并运行基于下图的脚本。
修改我们的 README.md 文件并提交它(图片由作者提供)
检查状态,直到它打印出*“Nothing to commit”*。这意味着我们已经提交了所有的更改。好了,为了跟踪我们的工作(提交),我们只需运行**git log**
,它将打印作者(用户名和电子邮件)、修改的日期和时间、消息和 SHA。
**git log --oneline**
:打印一行日志**git log --graph**
:用作者的线漂亮的展示日志**git log --author=<username>**
:显示某个作者的日志(如果我们和很多用户一起工作)**git log <filename>**
:显示某个文件的日志
我们必须尽可能清晰简单地添加提交消息,因为这将有助于我们跟踪我们的工作
在 git 中提交日志(图片由作者提供)
git 上必须知道的命令之一是**git diff**
。它帮助我们比较分支、特定文件或整个目录上的提交。例如,我们将比较两次提交。
图案是**git diff <SHA-before> <SHA-after>**
。用我们提交的 SHA 输入**<SHA-before>**
和**<SHA-after>**
。
使用**git diff**
比较 git 中的两个条件(图片由作者提供)
根据输出,我们在 README.md 文件中获得了关于第一次提交和第二次提交之间差异的信息。有用吧?
向后移动到以前的状态
作为人类,我们并不完美,对吗?有时我们会犯一些影响其他事情的错误。这也适用于科技公司,例如作为一个数据科学团队,我们正在为我们的机器学习流程开发新功能。但是发现了一个 bug。我们必须从作品的开始追溯,逐行检查代码。Git 通过向后移动特性简化了我们的工作。我们可以根据发现 bug 之前的提交来跟踪,而不是从作品的开头开始。
在 git 上有三个命令可以向后移动。它是用来满足我们的需要的。
**git checkout**
:它就像一台时光机,我们可以将项目文件的状态还原到指定的时间。然而,这是暂时的。这些不存储在 git 数据库中**git reset**
:这个命令让我们无法回到未来。我们将丢失我们的提交。重置 git 日志后,我们需要编写一个新的提交**git revert**
:将采用过去已有的文件条件,然后将它们与上次提交合并
我们可以调用 git checkout 命令在每次提交时检查文件条件。使用命令
***git checkout master***
从过去返回
git 中**git reset**
命令的实现(图片由作者提供)
当我们决定使用 git reset 时,有三个选项可供选择。这取决于我们的问题和我们想去的州。让我们来看看它们,并在您的计算机上试用它们!
**git reset --soft**
:将文件恢复到暂存状态**git reset --mixed**
:将文件恢复到修改状态**git reset --hard**
:将文件恢复到提交状态
Git 重置命令(图片由作者提供)
**git reflog**
用于恢复项目历史。我们可能熟悉显示提交列表的**git log**
命令。**git reflog**
与此类似,但显示的是**HEAD**
改变的时间列表。
执行**git reflog**
来恢复项目历史(图片由作者提供)
让我们再次修改我们的 README.md 文件来显示**git checkout**
命令。我们只是用*“readme . MD 文件的第三行”*添加一个新行。之后,像上一步一样,将其添加到提交状态。
在 git 中提交日志(图片由作者提供)
请记住,我们已经用**git reset**
恢复了我们的文件,它删除了我们的最后一次提交。然后,使用 git checkout,我们将在每次提交时检查文件条件。
**记住:**直到这一步,我们只有三次提交
在 git 中提交日志(图片由作者提供)
为了检查我们的第一次提交,我们使用了头指针。按照说明理解**git checkout HEAD**
是什么意思。它帮助我们跟踪 README.md 文件中的内容,每次提交时,是否有任何更改?什么样的变化?
使用**git checkout**
命令检查提交(图片由作者提供)
要了解标题上 波浪号(~) 和 脱字符(^) 的功能,请看下图。它让我们可以执行工作中每个分支上的每个提交。
标题上的代字号和插入符号(图片由作者提供)
Git 作为协作工具—分支
当谈到 git 作为一个版本控制工具时,我们只是谈论 git 如何帮助我们保持文件的版本。但是,现在我们将 git 作为一个协作工具来讨论。
Git 中默认的分支名称为
**master**
在我们的代码上开发新特性时,建议创建一个新的分支。让主分支作为我们的主要代码。如果我们的功能已经完成,并且没有发现错误,就与主分支合并。
在这种情况下,我们将创建一个名为 new_branch 的新分支,向 README.md 文件添加两行新行。
***git checkout***
命令也用于移动和创建分支
在 README.md 文件中新建一个分支并添加一行(图片由作者提供)
在 new_branch 分支上添加对提交状态的修改,并返回到主分支。查看 README.md 文件。我们在 new_branch 上的修改没有应用到主文件,因为我们在不同的分支上工作。它保持我们的主要代码干净和安全。
签出到主文件,并在 README.md 文件中添加新的一行(图片由作者提供)
查看 git 日志,现在您会在红色标记处发现一个新分支。是的,这表明在另一个分支上有任何提交。
使用 git 中的新分支提交日志(图片由作者提供)
我们刚刚创建了一个新的分支并提交给它。现在,我们必须将该分支合并到主分支,并清除所有冲突。
Git 作为协作工具—合并
当我们和一个团队一起工作时,我们必须有许多分支和它的特性。我们的下一个任务是合并这些分支,并管理其中的冲突。它是由**git merge**
指挥的。当主文件上的文件被选为主文件或代码时,我们必须将另一个分支合并到主文件中。所以我们要去找师父!如果我们的代码冲突,作为主要开发人员或项目负责人,我们的任务是选择是删除代码还是添加到主代码中。
两个分支代码由
**======**
分开
将 new_branch 合并到主服务器并管理冲突(图片由作者提供)
在我们的合并正确完成后,只需查看 git 日志。瞧啊。我们已经将 new_branch 合并到 master。我们的主人现在干净了!这是在 git 上合并的简单任务。
在 git 中提交日志(图片由作者提供)
显示文件的每一行是什么版本和作者最后修改的,我们可以使用**git blame**
命令。
**git blame L <start><end>**
README.md 文件中的最后修改版本和作者(图片由作者提供)
Git 作为协作工具—远程存储库
在谈论了很多关于 git 作为版本控制工具之后,接下来我们讨论 git 作为通过远程存储库的协作工具。有许多平台提供服务,让我们的脚本与人们或我们的团队协作,例如 GitHub、GitLab、Bitbucket 等。对于本教程,我们使用 GitHub。因此,您可能需要注册您的帐户,并按照说明操作!
请登录 GitHub 页面并创建一个新的存储库。选择您自己的回购名称,然后单击 创建存储库 创建新的存储库。
在 GitHub 中创建一个新的资源库(图片由作者提供)
我们的目标是将本地存储库上传到 GitHub 上的远程存储库。因此,在创建了新的存储库之后,我们可以将我们的远程存储库链接(通过 SSH 或 HTTPS )复制到终端并运行**git remote add**
命令。它将创建一个到远程存储库的新连接。
运行**git push**
将我们的本地存储库上传到远程存储库。这个命令需要两个参数***<remote-name>******<branch-name>***
。
***<remote-name>***
: 一个远程名字,比如,**origin**
***<brach-name>***
:分支名称,例如**master**
(默认)
管理远程存储库并上传到其中(图片由作者提供)
摘要
我们现在就在这里,编码员!总结一下我们的教程,友好的开发者只是创建了一个简单的备忘单来帮助我们理解我们已经学过的基本 git 命令。了解更多关于 git 备忘单的信息!
笔记
你可能想要得到这个基础 git 教程的简历,只需访问我的 GitHub 页面https://audhiaprilliant . GitHub . io/git-version-control-system/。如果能和世界各地的人一起分享和学习,那该多好啊!谢谢!
参考
[1]阿诺姆,吉特 (2020),https://docs.github.com/。
通过检测垃圾邮件学习贝叶斯定理
应用贝叶斯定理预测 SMS 消息是垃圾消息的概率的教程。
本教程有 2 个部分:
1。从条件概率推导贝叶斯定理
2。预测短信是否是垃圾短信
第一部分:从条件概率推导贝叶斯定理
条件概率
我在这里更深入地讨论了条件概率。
条件概率告诉我们,给定另一个事件,一个事件发生的概率。
P(A|B) = P(A ∩ B) / P(B)
是发生A
的概率,在我们知道B
发生的情况下。计算方法是A
和B
都发生的概率除以B
发生的概率。
但是如果我们想找到相反的情况,在发生A
的情况下B
的概率,会怎么样呢?
有时条件概率在这方面很有用。但是有时候用贝叶斯定理更简单。
贝叶斯定理
维基百科说,
推导贝叶斯定理
我们从条件概率的公式开始,它可以写成“A 给定 B”或“B 给定 A”。
注意,直观上,P(A∩B)
和P(B∩A)
是一样的(见下文)。这意味着我们可以互换使用它们。以后请记住这一点。
我们从第一个公式开始,P(A|B)= P(A∩B) / P(B)
。
多两边乘P(B)
。这将抵消右边的P(B)
分母,留给我们下面的。
我们现在能看到的(如果我们交换左右两边,会更容易)是P(A∩B)= P(A|B) * P(B)
。我们将把它插回到我们的第二个原始配方中(原始配方如下)。
得到这个公式(修改如下)。
也就是贝叶斯定理。
我们现在将使用贝叶斯定理来尝试和预测 SMS 消息中的垃圾邮件。
第 2 部分:预测 SMS 消息是否是垃圾消息
贝叶斯推理在垃圾邮件检测中有着悠久的历史。我们将在这里用一些真实的数据进入基础。
在我们的例子中,probability an SMS is spam, given some word
,等于probability of the word, given it is in a spam SMS
,乘以probability of spam
,再除以probability of the word
。
从 Kaggle 下载数据集,并在数据帧中检查。
import pandas as pd
df = pd.read_csv('sms-spam.csv', encoding='ISO-8859-1')
df.head(3)
原始 CSV 中的列没有意义。因此,我们将把有用的信息移到两个新列中,其中一列是布尔值,表示该短信是否是垃圾短信。
仅供参考,“火腿”的意思是“不是垃圾邮件”。
import numpy as npdf['sms'] = df['v2']
df['spam'] = np.where(df['v1'] == 'spam', 1, 0)df.head(3)
现在删除旧列。
df = df[['sms','spam']]
df.head()
好多了。
检查记录的数量。
len(df)
#=> 5572
那太多了。让我们使用 25%的原始数据样本。
sample_df = df.sample(frac=0.25)
len(sample_df)
#=> 1393
那更好。
现在将数据分成两个独立的数据帧,一个是垃圾邮件数据帧,一个是火腿数据帧。
spam_df = sample_df.loc[df['spam'] == 1]
ham_df = sample_df.loc[df['spam'] == 0]print(len(spam_df))
print(len(ham_df))#=> 180
#=> 1213
我们将使用 sklearn 的 TFIDF 矢量器来观察垃圾邮件中的一些重要单词,并选择一个插入我们的公式中。
from sklearn.feature_extraction.text import TfidfVectorizervectorizer_spam = TfidfVectorizer(stop_words='english', max_features=30)vectorizer_spam.fit(spam_df['sms'])
vectorizer_spam.vocabulary_
我们需要在公式中选择一个单词,所以我将选择单词“win ”,尽管尝试使用其他单词也很有趣。
现在我们需要计算公式的不同部分。
P(W|S)
=单词“win”出现在垃圾消息中的概率
P(S)
=垃圾消息整体的概率
P(W)
=单词“win”出现在消息整体中的概率
说出我们的话。
word = 'win'
计算P(W|S)
。
word = 'win'spam_count = 0
spam_with_word_count = 0for idx,row in spam_df.iterrows():
spam_count += 1
if word in row.sms:
spam_with_word_count += 1probability_of_word_given_spam = spam_count / spam_with_word_count
print(probability_of_word_given_spam)#=> 10.0
计算P(S)
。
probability_of_spam = len(spam_df) / (len(sample_df))
print(probability_of_spam)#=> 0.12921751615218952
计算P(W)
。
sms_count = 0
word_in_sms_count = 0for idx,row in sample_df.iterrows():
sms_count += 1
if word in row.sms:
word_in_sms_count += 1probability_of_word = word_in_sms_count / sms_count
print(probability_of_word)#=> 0.022254127781765973
现在把所有这些放在一起。
(probability_of_word_given_spam * probability_of_spam) / probability_of_word#=> 58.064516129032256
嘣。这告诉我们,如果一条短信包含“赢”这个词,那么这条短信有 58%的概率是垃圾短信。
结论和下一步措施
在生产垃圾邮件检测系统中,我们需要对语料库中的每个单词进行上述计算,然后组合概率。
我们可能还想包括其他功能,如单词组合,消息长度,标点符号等。
这会让这篇文章变得很长。
如果你感兴趣,这里有一篇 PDF 文章,解释了组合多个单词结果的几种方法。
我希望这给了你一些使用贝叶斯定理的洞察力和实践经验,即使我们只是触及了表面。