你花哨的专有人工智能模型对我没有价值
…除非您分享其目标、设计、测试和指标的细节
图片由皮克斯拜的 Gerd Altmann 提供
各地的厂商,请不要告诉我你的机器学习(或者更好的是‘AI’)模型有 99%的准确率。不要告诉我,我们所需要做的就是‘插入你的数据’,然后一些闪亮的魔法就发生了。我不是唯一的一个。最近,31 名科学家对谷歌健康的一项研究提出质疑,因为没有足够的公开证据来确定所提出的人工智能模型的可信度。我们都需要尽自己的一份力量来构建值得信赖的模型,为我们新的先进应用提供动力。被告知是减轻模型风险的第一步。
给我提供背景
当检查内部创建的模型或现成的供应商产品时,我会遵循一些必要的步骤。还有许多其他伟大的问题。请在评论区分享它们。
首先我们要明白,你在幕后做的是不是机器学习。如果你不能告诉我什么类型的模型产生的结果,让你的工程师打电话。
没有上下文,准确性度量是没有价值的。如果你正在为一个儿童动物学应用程序标记鱼的种类,百分之九点九的准确率是非常好的,但如果你正在识别来袭导弹,就没那么好了。
在私下讨论任何指标之前,需要检查以下三个问题。
目标是什么?
- 你是在促进什么还是阻止什么?
事件发生的频率或罕见程度如何?
- 给我数据。“非常罕见”不是一个好的回答。
最坏的情况是什么?
- 如果模型是错的会发生什么,包括假阳性和假阴性。
- 如果你不知道,你就不了解用例。你有工作要做。
给我提供证据和细节
一旦我理解了这些基础知识,我们就可以进入细节了。
你从哪里得到的训练数据?
- 如果购买,供应商是谁?
- 您是否在建模数据的基础上构建模型?
- 数据是如何收集和准备的?
- 交易、电话调查、网络应用、电话应用
训练的模型类型:
- 什么样的模型?
- 你是如何得到这些特别的模型的?
- 在做决定时,您是否依赖于特定的平台或架构?
指标:
- 准确是好的,但不仅仅是准确。请给我看看混淆矩阵。模型哪里做得好,哪里做得不好?
- 你能告诉我最好的预测吗?我需要验证它们是否“有意义”关联值是多少?有没有可能数据泄露?
偏置:
- 你认为你的训练数据中存在哪些偏见(人口统计、地区、收集方法(iPhone 与 Android)、种族、健康和福利)?如果偏见是不可避免的,你做了什么来减轻它?
- 您是否通过分析模型实施的结果评估了可能的偏差影响?一个模型可以有绝对“干净”的数据,但仍然会产生意想不到的后果。性别、种族、民族和社会经济地位很容易泄露到数据库中,即使这些列没有被使用。如需详细示例,请阅读 Obermeyer 等人的“剖析用于管理人口健康的算法中的种族偏见”SCIENCE2019 年 10 月 25 日:447–453。它很好地详细说明了选择一个看似合理的优化目标(降低慢性病患者的医疗保健成本)如何导致黑人社区中有价值的健康计划候选人服务不足。
结论
随着机器学习和人工智能工作的快速发展,我们对模型设计和验证透明度的期望也应该快速发展。如果没有能力彻底理解模型及其产生的结果,对所有模型的不信任可能会出现,从而抑制增长和创造力。如果你还没有提问,请开始提问。我们所有的成功都有赖于此。
参考文献
上个月,《自然》杂志发表了一篇由 31 名科学家撰写的对谷歌健康的一项研究的谴责性回应,该研究似乎…
www.technologyreview.com](https://www.technologyreview.com/2020/11/12/1011944/artificial-intelligence-replication-crisis-science-big-tech-google-deepmind-facebook-openai/?itm_source=parsely-api) [## 人工智能中的透明性和再现性
订阅期刊获得为期 1 年的完整期刊访问权限 199.00 美元,每期仅 3.90 美元所有价格均为净价。增值税…
www.nature.com](https://www.nature.com/articles/s41586-020-2766-y.epdf?sharing_token=esGu0AMNcdnJWDaAaBr3BtRgN0jAjWel9jnR3ZoTv0M3qEeZVaYZS89U0ri_i4YI_lJ0an-lE15Ncv2e1v5F7I2jYVuc7_mR1WrnlDjpWJ6ANzSjO0KJiERmpzE097VzbFgywD7RRHVOYg305JycIUX7UQDWkLlgHtsoU72ppNzneeIGzsSR4Cr5dVRyVtV2UMxm2gs9pA22vydPt_RRBmPUqh6R2UPn-oziFm82hKA%3D&tracking_referrer=www.technologyreview.com) [## 你如何用自己的小方法防止系统性的种族歧视
这里有两种方法可以解决技术和数据科学中的偏见
towardsdatascience.com](/how-you-can-prevent-systemic-racism-in-your-own-small-way-fc33cb57fdde)
“剖析用于管理人口健康的算法中的种族偏见”,作者 Obermeyer 等人SCIENCE2019 年 10 月 25 日:447–453
从不同的角度看你最喜欢的游戏
使用数据找出赢得神奇宝贝战斗的最可取的特点和特征——并通过这些见解建立最好的团队
完整的 python 代码和探索性数据分析笔记本可以在我的 github 个人资料中找到;
图片来源:【https://i.ytimg.com/vi/QWGGtKgalDo/maxresdefault.jpg
《神奇宝贝》是日本媒体的一个特许经营权,最初名为神奇宝贝红色和神奇宝贝绿色,是任天堂最初的游戏男孩的一对视频游戏,由 Game Freak 开发,由任天堂于 1996 年 2 月发布。神奇宝贝自此成为有史以来票房最高的媒体特许经营,特许经营总收入达到 900 亿美元。
神奇宝贝游戏,特别是第一代和第二代的游戏:神奇宝贝红色、蓝色、黄色、金色、银色和水晶对于出生于 90 年代的整代人来说,真的很了不起——包括我自己。这些天,我在 Kaggle 网站上寻找一些数据集,最后我发现了这个帖子,作者给出了包含神奇宝贝和游戏中神奇宝贝战斗数据的数据集,并提出了一个挑战:建立一个模型,能够根据给定的数据预测两个神奇宝贝之间的战斗结果。
把我童年的爱好和现在的爱好融合在一起?听起来不错,所以我同意!
数据集
Kaggle 的 Weedle 洞穴哨所提供了以下数据集:
神奇宝贝数据集 | 800 个输入,12 个特征
该数据集包含了所有发布到第 6 代的神奇宝贝的数据;
# —口袋妖怪指数(与最初的特许经营列表中使用的不同,因为大型进化列在普通形态的口袋妖怪之后);
名字 —口袋妖怪的名字;
类型 1 —口袋妖怪的初级类型;
类型 2 —口袋妖怪的副类型*(所有口袋妖怪都有主类型,但不一定有副类型);*
HP —生命值基础统计;
攻击 —物理攻击基础统计;
防御 —物理防御基础统计;
Sp。Atk —特攻基础统计;
Sp。Def —特殊防御基础统计;
速度 —速度基础统计;
一代 —这款神奇宝贝属于哪一代的特许经营游戏;
传奇 —表示神奇宝贝是否属于传奇团体;
神奇宝贝数据集的头部
战斗数据集 | 50000 个输入,3 个输入
该数据集包含神奇宝贝战斗的数据,列出了它们的索引( # )所涉及的两个神奇宝贝,以及哪一个以胜利者的身份结束了战斗:
First_Pokemon —训练师 A 的神奇宝贝 # (索引)——(先攻击过的神奇宝贝会一直列为“First _ Pokemon”);
秒 _ 神奇宝贝 —训练师 B 的神奇宝贝 # (索引);
赢得战斗的神奇宝贝的 — # (指数);
战斗数据集的头部
神奇宝贝的战斗是如何进行的?
在进入探索性数据分析(EDA)之前,理解单个神奇宝贝战斗是如何工作的很重要(也有双重战斗,但数据集上记录的战斗不是这种情况)。
神奇宝贝战斗遵循通常的 RPG 游戏模式:战斗轮流进行,每个参与者每回合可以采取一次行动(不是同时进行),第一个将对手的生命值减少到零的人就是赢家。在特许经营游戏中,行动由神奇宝贝训练师采取,他们可以选择攻击敌人的神奇宝贝,使用一件物品,甚至将自己的神奇宝贝换成团队中的另一个(训练师最多可以携带 6 个神奇宝贝)。
如上所述,衡量谁是赢家的标准是生命值,简称为 HP 。每个神奇宝贝拥有的 HP 的数量由以下等式给出:
来源:https://bulbapedia.bulbagarden.net/wiki/Statistic
给定的数据集仅提供了 HP 基本统计数据(在等式中突出显示)。所有其他变量(个人值: IV ,努力值: EV 和等级)都是游戏中开发的机制和引擎,不会在分析中考虑,因为没有办法找到数据集中记录的战斗的这些值。然而,如等式所示,总的 HP 与基础统计 HP 成正比。换句话说,基础属性越高,一只神奇宝贝在完全训练后获得的生命值就越高。
为了将对手的生命降至零并赢得战斗,神奇宝贝能够使用*战斗招式、这是一种特殊的移动,用于造成伤害、增强属性或对对手甚至环境造成一些影响。在攻击性战斗移动的情况下,*会造成一些伤害并降低敌人的生命值,所造成的伤害使用以下等式计算:
资料来源:https://bulbapedia.bulbagarden.net/wiki/Damage
其中:
来源:https://bulbapedia.bulbagarden.net/wiki/Damage
A/D是攻击方神奇宝贝的有效攻击属性与目标神奇宝贝的有效防御属性的比值。“有效”来源于这样一个事实,即有两种类型的伤害:物理的和特殊的(用一个简单的比喻,让我们说它会是类似“魔法”的东西)。对于其中的每一个,特定的统计数据被用于模数因子的计算:
物理移动使用攻击神奇宝贝的攻击统计数据,以及目标的防御统计数据。另一方面,特殊招式考虑攻击 Sp。攻击状态,目标 Sp。防御属性。
与**血量类似,**这些统计数据由一个等式给出,最终值与各自的基础统计值成正比,这是神奇宝贝数据集中所有神奇宝贝的唯一信息。**
来源:https://bulbapedia.bulbagarden.net/wiki/Statistic
我们用来构建分析的另一条信息是类型因素。长话短说:所有的神奇宝贝都有一个类型,,这是它身体组成的一个基本元素。事实上,每只神奇宝贝都至少有一种类型*,但它们也可能有多达两种类型:初级和次级。*
每一种类型都与他人有特定的互动,有强的、弱的、中性的或免疫的。同样,每一个战斗招式都关联一个类型,所以这个类型因子显示在伤害等式上就是攻击招式类型* x 目标类型伤害乘数。(不要慌,我们马上就到了)。*
因此,在本次分析中,我们将考虑损伤与模数因子和类型损伤乘数因子的乘积成正比,而模数因子和类型损伤乘数因子是数据集中可用的信息。
听起来不错,对吧?尽管事实上没有所有必要的信息来计算一个完整和完全准确的计算,知道如何计算类型的伤害乘数,至少有足够的信息来建立一些关于神奇宝贝战斗背后的数学好主意。然后,这是下一步!
如何计算类型伤害乘数因子?
现在我们知道了什么是神奇宝贝类型,并且它们对伤害计算非常重要,是时候知道在神奇宝贝世界里有哪些类型了:
图片来源:https://pokemon.fandom.com/wiki/Types
这些类型中的每一种都与所有其他类型有着进攻和防守的关系,这一信息是由 Game Freak 在每一个新一代发布后提供的。我已经在球形图上取了最新的类型图,并创建了一个新的数据框,包含与下图所示完全相同的信息:
神奇宝贝的类型图
这张图表给出了所有类型之间的直接关系,包括进攻型(横向参考)和防守型(纵向参考)。
举个例子: 电型在攻击一个水型时有一个伤害乘数等于 2,攻击一个草型时有 0.5,攻击一个火型时等于 1,最后,攻击一个地型敌人时等于 0。那么,我们可以说,电运动:
- 对抗水类型是否超有效*;*
- 对对抗草种类不是很有效;
- 都是中立对抗火力类型;
- 不影响地面类型;
给定这四种可能的类型之间的相互作用,以及类型图表,现在可以计算所有神奇宝贝战斗的类型伤害乘数因子,对吗?
还没有!
正如我之前提到的,神奇宝贝有可能有第二类型。事实上,直到日本特许发行的第六代游戏,这是神奇宝贝数据集中包含的数据,只有 48.25%的神奇宝贝只有初级类型。
由于大多数神奇宝贝有两种类型,并且交互因素是累积的,我们需要一种方法来计算多种类型的交互结果。由于战斗数据集没有提供任何关于战斗中采取了哪些行动的信息,我采用一些假设来简化分析:我们将考虑:
- 神奇宝贝在战斗中只能使用自己类型的战斗招式——例如,一个火* / 飞如 Charizard 只能使用火招或飞招(战斗招式只有一种类型与之相关);*
- 神奇宝贝训练师总是会为他们的神奇宝贝选择最好的战斗移动选项(如果适用的话),以便对敌人的神奇宝贝造成尽可能多的伤害。
***作者注:*神奇宝贝从其他类型而不是自己的类型中了解战斗招式是完全可能和正常的,更有经验的玩家总是选择从可能为他们的弱点提供一些覆盖的类型中教授他们的神奇宝贝招式(神奇宝贝可以同时了解多达 4 个招式)。然而,由于缺乏战斗数据集的信息,该分析不会考虑这一事实;
为了理解如何计算型伤害乘数因子,一个简单的例子可能会有用。
想象一下,两个神奇宝贝训练师相遇并决定通过一场战斗来测试谁是最好的。1 号教练有一把小火龙、,2 号教练有一把舒克尔。假设小火龙有更高的速度统计,训练师#1 将首先采取行动。
*注:速度统计用于决定战斗中哪个神奇宝贝先移动。标准规则很简单:最快的先走。除了 **HP,*之外的其他属性的速度属性由之前显示的相同等式给出,但是使用速度基础属性代替。为了记录在案,在游戏机制中有超越标准速度规则来选择先移动哪些神奇宝贝的规则,例如优先移动或持有物品——然而,这再次不包括在这个分析范围内,因为没有关于这些战斗细节的数据。
计算小火龙对舒克尔攻击的型伤害乘数因子、最佳 A/D 因子和比例伤害因子
- 由于小火龙只有一种招式火,这里没有关于使用哪种招式的选项。它肯定会使用火招;
- 另一方面, Shuckle 有两种类型: Bug 和 Rock 。所以有必要考虑火招式如何与这两种类型相互作用,并将这些相互作用融合在一起成为一个最终的数字;
- 使用特殊移动是最好的选择,因为它最终会成为一个更好的模数转换因子;
- 已知型损伤乘数和最佳模数因子,从本文前面给出的完整损伤方程可知输出损伤与这两个数的乘积成正比。
计算舒克尔对小火龙攻击的型伤害乘数因子、最佳 A/D 因子和比例伤害因子
- 从攻击者的角度来看舒克尔,有一个本质的区别:舒克尔有两种类型*、,所以它的训练者必须决定哪种移动类型是对敌人的小火龙造成尽可能多伤害的最佳选择;***
- 对于舒克,物理攻击是最好的选择——因为物理模数因子高于特殊模数因子;
考虑到两种魔法的相互作用,型伤害乘数因子有六个可能的值:
类型优势
- 4 :两种目标类型对攻击类型都很弱;
- 2:一个目标的类型是弱的,另一个是中性的攻击;
中性交互
- 1 :要么两个目标类型对进攻方都是中性,要么一个目标类型对进攻方是强一个弱;
类型缺点
- 0.5 :一个目标的类型是强,另一个对攻击的类型是中性;
- 0.25 :两种目标类型对进攻的都很强;
- 至少有一个目标的类型是攻击性的;
尽管如此,我们现在有了一个好主意,可以分析哪些特征,以便更好地了解哪些是神奇宝贝在战斗中获胜的最重要因素。
然而,没有一个关于战斗的有价值的信息被直接给出,因为神奇宝贝数据集只有个别神奇宝贝的特征,而战斗数据集只告知哪个神奇宝贝在哪里战斗以及哪个是赢家。然后,有必要建立一个 ETL 管道——从所有三个数据集中提取所有必要的信息,通过计算所有有价值的特征来转换数据,以了解战斗胜利者的特征(基于建立在神奇宝贝战斗如何工作的基础上的知识),以及将所有东西加载到一个新的数据集中,我将其命名为神奇宝贝战斗数据集。**
应用于原始数据的 ETL 管道
除了 ETL 管道的完整代码和完整的数据分析,生成的神奇宝贝战斗数据集可在我的 github 个人资料的项目回购中获得。
该新数据集由 35 个特征组成:
First_Pokemon —训练师 A 的神奇宝贝 # (索引)——(先攻击过的神奇宝贝会一直列为“First _ Pokemon”);
秒 _ 神奇宝贝 —训练师 B 的神奇宝贝 # (索引);
赢得战斗的神奇宝贝的赢家 — # (指数);
基础统计差异 —两个神奇宝贝基础统计的差异( 6 个特性,每个特性一个:HP,攻击,防御,Sp。攻击,Sp。防守,速度);
有效属性差异 —两个神奇宝贝( 8 特性 s)用于伤害计算的有效属性差异,差异:攻击与 HP,攻击与防御,Sp。攻击和 HP,Sp。攻击和 Sp。防守,针对进攻者/目标的两种组合);
A/D 因子 —毁伤方程中使用的有效 A/D 因子( 4 特征),针对攻击者/目标的两种可能性的两种可能的 A/D 因子(物理的和特殊的);
类型伤害乘数 —类型伤害乘数因子( 2 特性,每种攻击方/目标的可能性一个);
比例伤害因子 —最高 A/D 因子和类型伤害乘数因子的乘积( 2 个特性,每个攻击方/目标的可能性一个);
伤害/生命值系数 —比例伤害系数与目标生命值基础值的比率( 2 个特性,攻击者/目标的每种可能性一个);
神奇宝贝类型 —每个神奇宝贝的初级和次级(如果有的话)类型( 4 特性);
传奇神奇宝贝 —表示战斗中任何一只神奇宝贝都是传奇的旗帜( 2 特征);
优先级 —表示基础状态速度最低的神奇宝贝先移动的标志;
神奇宝贝 1 赢了——表示首先出击的神奇宝贝最终赢得战斗的标志(这将用作预测模型的目标变量);
现在,基于这个新数据集,结合来自神奇宝贝数据集的单个神奇宝贝数据,可以执行探索性数据分析,以便更好地了解导致赢得神奇宝贝战斗的最相关因素。
探索性数据分析
这里快速回顾一下:
*-我们知道,通过对敌人的生命值造成伤害直到生命值减为零,战斗就胜利了;
- 伤害是许多变量的函数,然而与两个因子的乘积成正比: A/D 因子和型伤害乘数;
- 模数因子由神奇宝贝有效统计的划分给出,另一方面,它与各自的基础统计直接成比例,这在数据集上对我们是可用的;
- 型伤害乘数可以用本文前面所示的程序计算;*
因此,给定神奇宝贝的战斗动态和可用的数据,为了赢得战斗,分析了解神奇宝贝最有价值的特征将基于构成伤害的两个因素:基础统计(以及所有可能从中得出的比例因素)和类型互动。
基本统计
赢得战斗最重要的属性是什么?一般来说,在你的旅程中使用具有防御特性的神奇宝贝是值得的,还是进攻更有效?
回答这些问题的最好方法,是看看在战斗中获胜的神奇宝贝和被击败的神奇宝贝之间基础统计数据的差异:
赢家和输家之间的基础统计差异分布
这些分布图给了我们一些有价值的信息:
- 一般来说,这可能是一般的直觉,与对手相比,基础属性更高的神奇宝贝最终会赢得战斗;
- 更高的进攻基础统计(攻击和 Sp。攻击似乎比更高的防御属性( HP 、防御和 Sp)更相关。防御);
- 虽然所有其他属性的分布几乎是对称的,只是稍微偏移和向右倾斜,但是速度基础属性是严重向右倾斜的——显示它自己是迄今为止与赢得战斗最相关的基础属性;
这个结果真的很有趣,因为速度统计基本上只用于定义哪个神奇宝贝在回合中先移动。从本文开头的数据解释中,我们可能还记得战斗数据集将最先攻击的放在神奇宝贝#1 中。
然而,神奇宝贝#1 总是比神奇宝贝#2 有更高的速度基础属性是不真实的——这有很多原因:
——我们看的是基础属性,而不是属性本身;
-游戏中有机制可能会覆盖先发制人的标准速度规则(如优先移动、持有物品、物品使用、神奇宝贝开关和环境效果)——但在数据集中没有关于这些机制使用的细节;**
然后,在 ETL 管道期间,一个名为 Prio 的功能被创建,以指示速度较低的神奇宝贝首先出击的战斗。
赢家和松散神奇宝贝之间的速度基础统计差异——常规速度规则覆盖分析
再次查看胜利者和失败者神奇宝贝之间的基础属性减法,人们能够看到,除了微小的差异,更高的速度属性仍然更有价值,即使是在基础属性较低的神奇宝贝先移动的战斗中(优先级=真)。**
请注意,在战斗的第一个回合首先出击,并不意味着神奇宝贝#1 已经在所有其他回合首先出击。事实上,数据显示在标准速度规则 下拥有每回合先动的优势是神奇宝贝赢得战斗的最有价值的特征。
因此,数据显示快速和进攻神奇宝贝是你在真实的神奇宝贝游戏中进行冒险时团队组成的最佳选择。
这涵盖了我们之前看到的损害等式的一个方面。另一个比例因子型相互作用怎么样?它们如何影响战斗结果?
比例损伤因子和类型相互作用
从基础数据本身来看,进攻特征通常比防守特征更有影响力。但它总是正确的吗?类型交互如何影响它?
正如我们在《神奇宝贝战斗动态》介绍中看到的,无论是从进攻角度还是防守角度来看,共有三种类型的型互动*类别:
- 型优势-进攻乘数: 4x 或 2x |防守乘数: 0x 、 0.25x 或0.5 x;
- 中立互动-攻防倍增:1x;
- 型劣势-(进攻乘数:0 x,0.25x 或 0.5x |防守乘数: 2x ,4x;*
这些互动对战斗的影响有多大?此外,最有价值的统计特征在不同类型的互动场景中会发生变化吗,或者进攻永远是最好的选择?
成功率 x 类型互动
*上图显示,类型优势,无论是进攻还是防守,都与更高的胜率直接相关,因为进攻伤害乘数越高,**胜率越高,*防御胜率越高,反之亦然。
它证实了直觉的想法,即类型交互对战斗的胜利有很强的相关性,因为它们与伤害成正比。然而,在不同类型的互动场景中,它没有说太多关于最有价值的神奇宝贝的特征。
*为了更好地理解有利或不利类型比赛中神奇宝贝特征之间的关系,下面的方框图可能更有用。分别代表胜者神奇宝贝的 A/D 因子、比例伤害因子 ( A/D 型伤害乘数)、比例伤害因子与敌人的 HP 基础统计值之比 ( 乘以 50,更贴合剧情);
不同类型匹配时的模数系数
不同类型匹配时的伤害系数和伤害/血量比
这些特征中的大多数都有巨大的异常值,因此有必要应用IQR(IenterQuartileR安歌】方法来消除它们并进行分析。完整的代码和数据预处理方法可在原始项目笔记本上找到。
这些方框图揭示了一些非常有趣的事情:
- 进攻特点 对于一个神奇宝贝在类型优势* 场景(无论是进攻还是防守)上赢得战斗的**来说,相对于一般情况(整套分析);*
- 然而,对于型劣势的情况,这是不成立的。事实上,恰恰相反的情况发生了:在这种类型的比赛中,防守特性成为最受欢迎的特性;
- 另一方面,中性相互作用与一般情况非常相似*;*
综合我们目前掌握的所有信息,我们有:
-型优势显著提高了赢得战斗的概率;
-进攻特点在中性和有利型比赛中最有价值;
将这些信息与来自基本统计分析的信息相结合,可以得出以下结论:
最佳的团队组合必须不仅基于快速和进攻魔法,还基于具有更高有利数量的魔法类型,或者至少是中立的配对。
但是,在这个指标上,哪些类型是最好的呢?
类型匹配
哪种类型提供更多的有利匹配?
开始研究这个问题的最好方法是直接从类型数据集中统计有利和不利类型匹配的数量。
每种类型的类型匹配计数—按进攻和防守交互进行划分
上面的柱状图表明,对所有 18 种神奇宝贝来说,有利的和不利的配对数量甚至都没有接近平衡。
如果每种类型的魔法数量平均分布的话,这可能是这个分析需要的唯一的图。但是,这是真的吗?
这是要检查的下一点:
每种类型的神奇宝贝数量
很明显,人们不能直接使用类型匹配计数图作为参考来了解哪些类型可以提供更高的覆盖率,因为每种类型的神奇宝贝数量严重不平衡。
因此,与其直接使用有利或不利类型配对的计数,不如使用这些配对所代表的神奇宝贝百分比:
每种比赛类型覆盖的神奇宝贝的百分比——按进攻和防守互动划分
进攻型优势
格斗和地面*,是进攻优势配对数最好的类型,各有 5 个有利配对。然而,看看神奇宝贝在有利的进攻比赛中的最高百分比, Ice 是最好的一个,对这个数据集的神奇宝贝的 39.2% 超级有效;*
由于普通类型没有优势,覆盖率也为零( 0% ),是两个度量中最差的类型;
防守型优势
钢铁在两个指标上都是最好的类型,从神奇宝贝的百分比来看 11 防守有利匹配类型匹配 ups 和67.38%*;*
寒冰和普通类型只对 1 类型有抗性,然而寒冰*就百分比而言单独在列表中垫底,onlt 4.75% ,因为它只对自己有抗性,而且它是神奇宝贝世界中最稀有的类型(考虑到这些数据集);*
进攻型劣势
草在这两个指标上都是最差的类型, 7 不利进攻配合,对神奇宝贝 61.62% 进攻乏力;
龙、鬼、仙配合数最好,分别对 2 种、、进攻较弱,而龙在百分比上独占鳌头,对魔人只有 11.85%* 进攻较弱;*
防御型劣势
摇滚只是不利防守配合计数最差的类型,有 5 的弱点。在看神奇宝贝防御弱点百分比时最底层的类型是草*:47.5%;*
电动和普通型各只有 1 个弱点。然而,电动在百分比指标上保持最佳位置,仅弱于所有神奇宝贝的6.25%*;*
正如我们已经看到的那样,有利的类型匹配增强了赢得神奇宝贝战斗的概率,当查看每种类型的胜率时,人们期望看到具有最佳匹配百分比的类型作为具有最高胜率的类型,只要战斗数据集是真正随机的,并且在记录的战斗中神奇宝贝类型的频率遵循每种类型神奇宝贝的相同分布。
在战斗数据集中输入频率
上面的柱状图表明,在 50.000 次记录的战斗中涉及的神奇宝贝类型遵循每种类型的神奇宝贝的相同分布,这证实了战斗确实是随机选择的,因此人们可能确实直觉地认为上面提到的类型是胜率最高的类型。
每种类型的成功率
在比赛中表现最好的类型,真的是胜率最高的类型吗?
为了验证这一点,我们来看一个柱状图,显示每种类型的成功率。
由于神奇宝贝有初级和次级类型,观察这些特征如何影响胜率也是很有趣的。此外,了解是否有一些类型本身更强大,而其他类型作为补充可能会更好,这可能是有用的。
每种类型的胜率—常规、主要类型和次要类型
每种类型的最佳和最差一般胜率
结果相当令人惊讶:更高的胜率与更高的有利类型匹配百分比并没有很强的相关性。那么,对于一个类型来说,哪一个因素与更高的胜率最相关?
根据此分析的初始想法,如果类型交互不是胜率的影响因素,则应检查基本统计数据。因此,下一步是调查每种类型的平均基础统计,并找出类型是否有一些嵌入的统计特征。
每种类型的平均基础状态
神奇宝贝的类型有一些特定的基础统计特征吗?是否有一些类型更侧重于进攻,而其他类型更侧重于防守?
我们将开始调查每种类型的统计特征,找出每个统计中最好的类型(就平均基础统计而言),并通过柱状图直观地比较它们:
每种类型的平均 HP 基础统计
每种类型的平均攻击基础统计
每种类型的平均防御基础统计
平均 Sp。每种类型的攻击基础统计
平均 Sp。每种防御基础统计
每种类型的平均速度基础统计
每种类型的总平均基础统计
上面这七个柱状图显示了每种类型的平均基础统计值,包括所有的六种统计值 ( 生命值、攻击值、防御值、Sp 值。攻击,Sp。防御和速度,以及总基础统计,这是所有基础统计的总和。
通过视觉检查这些图,找出每种类型的一些基础统计特征或模式并不容易,但是有可能注意到一些真正有趣的事情:具有最高胜率的类型 是具有最高平均速度基础统计的类型,和就胜率而言最差的是平均最慢的类型。它们并不遵循完全相同的顺序,但这是一条重要的线索,有助于确定某个类型具有更高胜率的最重要因素。
胜率 x 每种类型的平均速度基础统计
为了弄清楚每种类型的平均基础统计数据的一些模式,人们可能想要查看不同类型的图,其中可以同时可视化所有六种统计数据的数值。雷达图可能非常适合这个角色。
每种类型的平均基础统计数据—图 1/2
每种类型的平均基础统计数据—图 2/2
上面的雷达图清楚地表明,每种神奇宝贝都有一些统计特征:
- 例如战斗类型倾向于专注于物理攻击(高平均攻击基础属性,而其他属性较低);
- 通灵型另一方面有平均高 Sp。攻击和 Sp。防御基础属性,而其他人则没有那么高;
这些图也更好地说明了一些类型的平均基础统计数据之间的差异。给出的例子:通过比较虫和龙的雷达图,可以注意到龙的魔法在每一个属性上都比虫的魔法有巨大的优势。
如上所述,很容易注意到更高的平均速度基础统计与更高的胜率高度相关,然而,除了这两个等级的顶端和底端由相同的神奇宝贝类型填充这一事实之外,它们出现的顺序也不相同——因此,对于一个类型来说,在战斗中具有高胜率还有一些其他相关因素。
基本数据和类型匹配百分比与胜率的相关性
与战斗胜率最相关的类型特征是:
- 平均速度基础统计 —相关性:0.96;
- 平均速度。攻击基础统计 —相关度:0.53;
- 平均总统计数据 —相关度:0.51;
- 平均 HP 基础统计 —相关性:0.41;
- 平均攻击基础统计 —关联度:0.35;
- 进攻型优势(百分比) —相关性:0.30;
如前所述,最佳团队组合必须不仅基于快速和进攻魔法,还必须拥有更高有利数量的魔法类型,或者至少是中立的配对。
不过现在已经知道有利的基础统计(特别是速度, Sp。攻击、 HP 和攻击)和高总基础属性比类型优势更有价值,如果你想在战斗中建立一个高效的神奇宝贝团队。虽然进攻有利型配合也通过数据显示了它的重要性,所以在组队的时候也要注重进攻有利型覆盖。
利用从数据中获得的知识建立一个神奇宝贝团队
现在,我们将使用数据分析过程中收集的所有信息来建立一个神奇宝贝团队,寻找赢得战斗的最高效率。
作为第一代神奇宝贝(它带来了CharizardBlastoise和venus aur)可能是大多数人,特别是 90 年代出生的人最值得注意的一个,我将范围仅限于神奇宝贝传说中的神奇宝贝和超级进化都不会被包括在内,因为它们通常比“普通”的神奇宝贝有更高的基础属性。**
基于使用本文提及的所有数据集的探索性数据分析**,选择团队成员的标准按优先顺序列出如下:**
- #1 —高速基础统计的神奇宝贝;
- #2 —具有攻击性特征的神奇宝贝(要么攻击,要么 Sp。攻击);
- # 3—团队中所有神奇宝贝的类型组合应具有广泛的有利进攻类型搭配(应尽量避免重复类型);
和所有神奇宝贝游戏一样,我们的团队将由六只神奇宝贝组成。
在神奇宝贝数据集上运行一个简单的查询,我们得到:
我们神奇宝贝团队的最佳候选人
严格遵循既定的标准,一个人最终拥有以下神奇宝贝团队:
化石翼龙-基本统计和类型
胡地-基本统计和类型
奥术——基本属性和类型
耿鬼-基本统计和类型
雷伊布-基本统计和类型
宝石海星-基本统计和类型
该队对 18 种神奇宝贝中的 13 种有有利的进攻配合
你会在下一次游戏中尝试这支神奇宝贝队伍吗?
所有列入这份名单的神奇宝贝都有稳固的速度基础统计** ( 奥术最差,数值 95 ),也有稳固的进攻基础统计(物理、特殊甚至两者兼而有之——比如奥术),而且没有重叠类型(除了宝石海星的二级类型,它与胡地的重叠),达到了**的标记听起来很有希望,对吧?****
后续步骤
预测神奇宝贝战斗赢家的机器学习模型
由于 Kaggle 帖子的最初的挑战是建立一个机器学习模型,该模型能够预测哪只神奇宝贝将赢得战斗,考虑到两个战斗神奇宝贝,这将是下一步!
我们将使用从这里描述的 ETL 管道中导出的新数据集,以及关于神奇宝贝战斗的所有知识来建模和训练机器学习模型,所有细节将在下一篇文章中全面描述。
此外,一旦模型被完全训练,也将有可能使用数据分析来检查这个神奇宝贝团队的效率**!**
****作者注:对于那边的所有神奇宝贝粉丝来说——重要的是要记住,用于建立这一分析的所有战斗可能都是在游戏战斗中,在一次跑步中记录的,与野生神奇宝贝和 NPC 的战斗(没有关于战斗的起源和来源的信息)。竞技神奇宝贝场景完全不同,不是这里的重点。
你的第一个 Apache Spark ML 模型
如何用 Apache Spark 和 Python 构建一个基本的机器学习模型?
Héizel Vázquez 插图
我爱阿帕奇火花。这是我用于机器学习和数据科学的首批框架之一。在过去的几年里,它一直在稳步增长,我们已经接近它的第三个版本。我们预期的变化主要是在查询和流程的优化方面,所以 API 不会有太大的变化。这意味着你在这篇文章中学到的东西会在一段时间内起作用(我们不知道会持续多久,因为生活很微妙)。
这篇文章分为三个部分:
- Apache Spark 的基础知识
- 安装和使用 Apache Spark
- 创建您的第一个 Apache Spark 机器学习模型
前两节中您将看到的许多内容来自我以前写的两篇关于 Apache Spark 的文章:
[## 使用 Apache Spark 进行深度学习—第 1 部分
第一部分全面讨论了如何使用 Apache Spark 进行分布式深度学习。这一部分:什么是火花…
towardsdatascience.com](/deep-learning-with-apache-spark-part-1-6d397c16abd) [## 如何在你的电脑上使用 PySpark
我发现在您的本地上开始使用 Apache Spark(这里将重点介绍 PySpark)有点困难…
towardsdatascience.com](/how-to-use-pyspark-on-your-computer-9c7180075617)
但是是时候更新了:)
Apache Spark 的基础知识
几年前,Apache Spark 被其创建者定义为:
大规模数据处理的快速通用引擎。
“**快速”**部分意味着它比以前的方法更快地处理大数据,如经典的 MapReduce。更快的秘密是 Spark 在内存(RAM)上运行,这使得处理速度比在磁盘上快得多。
“**通用”**部分意味着它可以用于多种用途,比如运行分布式 SQL、创建数据管道、将数据摄取到数据库中、运行机器学习算法、处理图形、数据流等等。
现在他们把定义改成了:
Apache Spark 是一个用于大规模数据处理的统一分析引擎。
我们仍然有通用部分,但现在它的范围更广了,有了单词“ unified,”,这是为了解释它可以在数据科学或机器学习工作流中做几乎所有的事情。对于端到端的项目,可以单独使用 Spark 框架。
**“大规模”**部分意味着这是一个可以完美处理大量数据的框架,我们过去称之为“大数据”(有趣的是事物变化的速度)。
RDD
杰弗里·汤普森的 PySpark 图片。
Apache Spark 的核心抽象和开端是弹性分布式数据集(RDD)。
RDD 是可以并行操作的容错元素集合。您可以在驱动程序中并行化现有集合,或者引用外部存储系统中的数据集来创建它们,例如共享文件系统、HDFS、HBase 或任何提供 Hadoop InputFormat 的数据源。
关于 Spark,有一点非常重要,那就是所有的转换都是惰性的,这意味着它们不会马上计算出结果。相反,Spark 会记住应用于某个基本数据集(如文件)的转换。只有当一个动作需要将结果返回给驱动程序时,才会计算转换。
默认情况下,每次对变换后的 RDD 执行操作时,都会对其进行重新计算。然而,您也可以使用持久化(或缓存)方法在内存中持久化一个 RDD,在这种情况下,Spark 会将元素保留在集群上,以便下次查询时可以更快地访问。还支持在磁盘上持久化 rdd 或跨多个节点复制 rdd。
数据框架
杰弗里·汤普森的 PySpark 图片。
从 Spark 2.0.0 开始,数据帧就是一个被组织成命名列的数据集。它在概念上相当于关系数据库中的一个表或 R/Python 中的一个数据帧,但是在底层有更丰富的优化。
数据帧可以由各种各样的源构建,例如:结构化数据文件、Hive 中的表、外部数据库或现有的 rdd。
https://aspgems . com/blog/big-data/migrando-de-pandas-spark-data frames
简而言之,Dataframes API 是 Spark 创造者简化框架中数据处理的方法。它们非常类似于 Pandas 数据帧或 R 数据帧,但有几个优点。首先,它们可以分布在一个集群中,因此可以处理大量数据;其次,它们经过了优化。
这是社区迈出的非常重要的一步。到了 2014 年,用 Spark 搭配 Scala 或者 Java,速度快了很多,整个 Spark 世界都因为性能变成了 Scala。但是有了 DF API,这不再是一个问题,现在您可以在 R、Python、Scala 或 Java 中使用它获得相同的性能。
负责这种优化的是催化剂。你可以把它想象成一个向导,它会接受你的查询(哦,是的!,您可以在 Spark 中运行类似 SQL 的查询,在 DF 上运行它们,它们也会被并行化)和您的操作,并创建一个优化的计划来分配计算。
过程没那么简单,但是作为程序员的你根本不会注意到。现在它一直在那里帮助你。
在 Spark 3.0 中,我们将获得一种称为“自适应查询执行”(AQE)的东西,它将根据查询执行过程中收集的运行时统计数据来重新优化和调整查询计划。这将对性能产生巨大影响,例如的例子假设我们正在运行查询
SELECT max(i) FROM table GROUP BY column
没有 AQE,Spark 将启动五个任务进行最终聚合:
但是有了 AQE,Spark 将把这三个小分区合并成一个,因此,最终的聚合现在只需要执行三个任务,而不是五个:
在这个新版本中,Spark 将解决一个大问题:基于成本的优化。如果你想了解更多,请查看上面两张图片中的链接。
在接下来的会议中,我们将看到更多关于 Spark 及其机器学习(ML)库的内容。
安装和使用 Apache Spark
备注:
- “$”符号将表示在 shell 中运行(但不要复制该符号)。
- >>>符号表示 Python 外壳(不要复制符号)。
我们将在本地安装 PySpark,然后使用 Jupyter 来处理它。使用 Spark 还有更多方法,如果你想了解更多,请查看这篇文章。
安装 PySpark
PySpark,可以想象,就是 Apache Spark 的 Python API。这是我们使用 Python 与框架交互的方式。安装非常简单。这些是步骤:
- 在计算机上安装 Java 8 或更高版本。
- 安装 Python(我推荐>来自 Anaconda 的 Python 3.6)
- 安装 PySpark:
$ pip3 install pyspark
目前的默认版本是 3.0.0,这是实验性的,但是它应该适用于我们的实验。
要测试您的安装,请转到您的终端,然后打开 Python。然后写:
>>> import pyspark
如果你没有得到一个错误,你就在正确的道路上。要检查 Spark write 的安装版本:
pyspark.__version__
你应该得到‘3 . 0 . 0’。
- 在 Python 笔记本中测试 Spark:创建一个新的 Jupyter 笔记本,编写和以前一样的内容。如果出现错误,直接从笔记本上安装 PySpark。下面是一款笔记本电脑实现这一功能的要点:
创建您的第一个 Apache Spark ML 模型
Spark 的机器学习库叫做 MLlib(机器学习库)。它在很大程度上基于 Scikit-learn 关于管道的想法。在本库中,创建 ML 模型的基本概念是:
- DataFrame:这个 ML API 使用 Spark SQL 中的 DataFrame 作为 ML 数据集,可以保存各种数据类型。例如,数据帧可以具有存储文本、特征向量、真实标签和预测的不同列。
- 转换器:转换器是一种可以将一个数据帧转换成另一个数据帧的算法。例如,ML 模型是将具有特征的数据帧转换成具有预测的数据帧的转换器。
- 估计器:估计器是一种算法,它可以适合一个数据帧来产生一个转换器。例如,学习算法是在数据帧上训练并产生模型的估计器
- 管道:管道将多个转换器和评估器链接在一起,以指定 ML 工作流
- 参数:所有的转换器和估算器现在共享一个公共的 API 来指定参数。
如果你想知道更多关于 API 和它们如何工作的信息,请查看官方文档。
对于这个例子,我们将使用一个非常基本的数据集。泰坦尼克号数据集,希望你们都熟悉这个案例和数据。首先,我们必须下载数据,为此我们使用 Kaggle:
从这里开始!预测泰坦尼克号上的生存并熟悉 ML 基础知识
www.kaggle.com](https://www.kaggle.com/c/titanic/data)
只需下载“train.csv”文件就可以了:)。
我们将根据乘客的特征来预测其是否幸存。
启动前:确保关闭并停止所有其他 Spark 笔记本。当使用多个 Spark 实例时,Java 有时会报错。
将数据加载到 Spark
为了加载数据,我们使用 Spark DataFrames。它比熊猫稍微复杂一点。不能只做“导入-> read_csv()”。您首先需要启动一个 Spark 会话,来完成该写操作:
from pyspark.sql import SparkSessionspark = SparkSession \
.builder \
.appName('Titanic Data') \
.getOrCreate()
现在如果你写:
spark
在您的笔记本上,您应该会看到:
这意味着您在所有内核(即*)上本地使用 Spark,版本为 3.0.0,会话名称为“Titanic Data”。认为“Spark UI”在你使用 Spark 时会很有用,如果你点击它,你会看到:
我没有时间详细解释 UI,但如果你想了解更多,请告诉我:)。
酷!现在我们已经准备好读取数据了。为此,请编写:
df = (spark.read
.format("csv")
.option('header', 'true')
.load("train.csv"))
就是这样!您已经创建了您的第一个 Spark 数据框架。要查看数据帧的内部,请编写:
df.show(5)
你会得到一些不漂亮但至少有用的东西:
+-----------+--------+------+--------------------+------+---+-----+-----+----------------+-------+-----+--------+
|PassengerId|Survived|Pclass| Name| Sex|Age|SibSp|Parch| Ticket| Fare|Cabin|Embarked|
+-----------+--------+------+--------------------+------+---+-----+-----+----------------+-------+-----+--------+
| 1| 0| 3|Braund, Mr. Owen ...| male| 22| 1| 0| A/5 21171| 7.25| null| S|
| 2| 1| 1|Cumings, Mrs. Joh...|female| 38| 1| 0| PC 17599|71.2833| C85| C|
| 3| 1| 3|Heikkinen, Miss. ...|female| 26| 0| 0|STON/O2\. 3101282| 7.925| null| S|
| 4| 1| 1|Futrelle, Mrs. Ja...|female| 35| 1| 0| 113803| 53.1| C123| S|
| 5| 0| 3|Allen, Mr. Willia...| male| 35| 0| 0| 373450| 8.05| null| S|
+-----------+--------+------+--------------------+------+---+-----+-----+----------------+-------+-----+--------+
only showing top 5 rows
是的,我知道,没那么漂亮。使用 Python 的一个好处是,你可以很容易地与熊猫互动。为了以更漂亮的格式显示我们的数据,您可以写:
df.toPandas()
您将获得:
但是小心我的朋友们!!!只有当您处理的数据足够小时,您才能这样做,因为当您执行“toPandas()”时,您将一次获得所有数据,并且数据不会分布在该单元格中。所以它必须适合内存。
检查关于您的数据的信息
有一些基本函数可以从数据集中获取更多信息。在下一段代码中,我加入了基本的代码( - >表示计算的结果):
# How many rows we have
df.count()
-> 891# The names of our columns
df.columns
-> ['PassengerId',
'Survived',
'Pclass',
'Name',
'Sex',
'Age',
'SibSp',
'Parch',
'Ticket',
'Fare',
'Cabin',
'Embarked']# Types of our columns
df.dtypes
-> [('PassengerId', 'string'),
('Survived', 'string'),
('Pclass', 'string'),
('Name', 'string'),
('Sex', 'string'),
('Age', 'string'),
('SibSp', 'string'),
('Parch', 'string'),
('Ticket', 'string'),
('Fare', 'string'),
('Cabin', 'string'),
('Embarked', 'string')]
最后是一些关于我们数据的统计数据:
# Basics stats from our columns
df.describe().toPandas()
数据准备和特征工程
我们从上面的数据探索中注意到的一件事是,所有的列都是字符串类型。但这似乎不对。其中一些应该是数字。所以我们打算让他们出演。此外,由于时间关系,我只选择了几个变量进行建模,因此我们不必处理整个数据集:
from pyspark.sql.functions import coldataset = df.select(col('Survived').cast('float'),
col('Pclass').cast('float'),
col('Sex'),
col('Age').cast('float'),
col('Fare').cast('float'),
col('Embarked')
)dataset.show()
最后,你会得到这个数据集:
+--------+------+------+----+-------+--------+
|Survived|Pclass| Sex| Age| Fare|Embarked|
+--------+------+------+----+-------+--------+
| 0.0| 3.0| male|22.0| 7.25| S|
| 1.0| 1.0|female|38.0|71.2833| C|
| 1.0| 3.0|female|26.0| 7.925| S|
| 1.0| 1.0|female|35.0| 53.1| S|
| 0.0| 3.0| male|35.0| 8.05| S|
| 0.0| 3.0| male|null| 8.4583| Q|
| 0.0| 1.0| male|54.0|51.8625| S|
| 0.0| 3.0| male| 2.0| 21.075| S|
| 1.0| 3.0|female|27.0|11.1333| S|
| 1.0| 2.0|female|14.0|30.0708| C|
| 1.0| 3.0|female| 4.0| 16.7| S|
| 1.0| 1.0|female|58.0| 26.55| S|
| 0.0| 3.0| male|20.0| 8.05| S|
| 0.0| 3.0| male|39.0| 31.275| S|
| 0.0| 3.0|female|14.0| 7.8542| S|
| 1.0| 2.0|female|55.0| 16.0| S|
| 0.0| 3.0| male| 2.0| 29.125| Q|
| 1.0| 2.0| male|null| 13.0| S|
| 0.0| 3.0|female|31.0| 18.0| S|
| 1.0| 3.0|female|null| 7.225| C|
+--------+------+------+----+-------+--------+
如果我们运行这个:
from pyspark.sql.functions import isnull, when, count, coldataset.select([count(when(isnull(c), c)).alias(c) for c in dataset.columns]).show()
我们得到:
+--------+------+---+---+----+--------+
|Survived|Pclass|Sex|Age|Fare|Embarked|
+--------+------+---+---+----+--------+
| 0| 0| 0|177| 0| 2|
+--------+------+---+---+----+--------+
我们看到在一些列中也有空值,所以我们只消除它们:
dataset = dataset.replace('?', None)\
.dropna(how='any')
现在,Spark ML 库只处理数字数据。但我们还是想用《性》和《登船》专栏。为此,我们需要对它们进行编码。为此,让我们使用一个叫做 StringIndexer 的东西:
from pyspark.ml.feature import StringIndexerdataset = StringIndexer(
inputCol='Sex',
outputCol='Gender',
handleInvalid='keep').fit(dataset).transform(dataset)dataset = StringIndexer(
inputCol='Embarked',
outputCol='Boarded',
handleInvalid='keep').fit(dataset).transform(dataset)dataset.show()
如果你这样做,你会得到:
+--------+------+------+----+-------+--------+------+-------+
|Survived|Pclass| Sex| Age| Fare|Embarked|Gender|Boarded|
+--------+------+------+----+-------+--------+------+-------+
| 0.0| 3.0| male|22.0| 7.25| S| 0.0| 0.0|
| 1.0| 1.0|female|38.0|71.2833| C| 1.0| 1.0|
| 1.0| 3.0|female|26.0| 7.925| S| 1.0| 0.0|
| 1.0| 1.0|female|35.0| 53.1| S| 1.0| 0.0|
| 0.0| 3.0| male|35.0| 8.05| S| 0.0| 0.0|
| 0.0| 3.0| male|null| 8.4583| Q| 0.0| 2.0|
| 0.0| 1.0| male|54.0|51.8625| S| 0.0| 0.0|
| 0.0| 3.0| male| 2.0| 21.075| S| 0.0| 0.0|
| 1.0| 3.0|female|27.0|11.1333| S| 1.0| 0.0|
| 1.0| 2.0|female|14.0|30.0708| C| 1.0| 1.0|
| 1.0| 3.0|female| 4.0| 16.7| S| 1.0| 0.0|
| 1.0| 1.0|female|58.0| 26.55| S| 1.0| 0.0|
| 0.0| 3.0| male|20.0| 8.05| S| 0.0| 0.0|
| 0.0| 3.0| male|39.0| 31.275| S| 0.0| 0.0|
| 0.0| 3.0|female|14.0| 7.8542| S| 1.0| 0.0|
| 1.0| 2.0|female|55.0| 16.0| S| 1.0| 0.0|
| 0.0| 3.0| male| 2.0| 29.125| Q| 0.0| 2.0|
| 1.0| 2.0| male|null| 13.0| S| 0.0| 0.0|
| 0.0| 3.0|female|31.0| 18.0| S| 1.0| 0.0|
| 1.0| 3.0|female|null| 7.225| C| 1.0| 1.0|
+--------+------+------+----+-------+--------+------+-------+
only showing top 20 rows
如您所见,我们创建了两个新列“性别”和“登船”,包含与“性别”和“登船”相同的信息,但现在它们是数字。让我们对数据类型做最后一次检查:
dataset.dtypes-> [('Survived', 'float'),
('Pclass', 'float'),
('Sex', 'string'),
('Age', 'float'),
('Fare', 'float'),
('Embarked', 'string'),
('Gender', 'double'),
('Boarded', 'double')]
所以我们想要的所有列都是数字。我们现在必须删除旧列“Sex”和“apolloed ”,因为我们不会使用它们:
# Drop unnecessary columns
dataset = dataset.drop('Sex')
dataset = dataset.drop('Embarked')dataset.show()
您将获得:
+--------+------+----+-------+------+-------+
|Survived|Pclass| Age| Fare|Gender|Boarded|
+--------+------+----+-------+------+-------+
| 0.0| 3.0|22.0| 7.25| 0.0| 0.0|
| 1.0| 1.0|38.0|71.2833| 1.0| 1.0|
| 1.0| 3.0|26.0| 7.925| 1.0| 0.0|
| 1.0| 1.0|35.0| 53.1| 1.0| 0.0|
| 0.0| 3.0|35.0| 8.05| 0.0| 0.0|
| 0.0| 1.0|54.0|51.8625| 0.0| 0.0|
| 0.0| 3.0| 2.0| 21.075| 0.0| 0.0|
| 1.0| 3.0|27.0|11.1333| 1.0| 0.0|
| 1.0| 2.0|14.0|30.0708| 1.0| 1.0|
| 1.0| 3.0| 4.0| 16.7| 1.0| 0.0|
| 1.0| 1.0|58.0| 26.55| 1.0| 0.0|
| 0.0| 3.0|20.0| 8.05| 0.0| 0.0|
| 0.0| 3.0|39.0| 31.275| 0.0| 0.0|
| 0.0| 3.0|14.0| 7.8542| 1.0| 0.0|
| 1.0| 2.0|55.0| 16.0| 1.0| 0.0|
| 0.0| 3.0| 2.0| 29.125| 0.0| 2.0|
| 0.0| 3.0|31.0| 18.0| 1.0| 0.0|
| 0.0| 2.0|35.0| 26.0| 0.0| 0.0|
| 1.0| 2.0|34.0| 13.0| 0.0| 0.0|
| 1.0| 3.0|15.0| 8.0292| 1.0| 2.0|
+--------+------+----+-------+------+-------+
在进入机器学习部分之前,只剩下一步了。Spark 实际上是用一个列来进行预测的,这个列将所有的特性组合成一个类似列表的结构。例如,如果您具有以下功能:
+--------+------+----+-------+------+-------+
|Survived|Pclass| Age| Fare|Gender|Boarded|
+--------+------+----+-------+------+-------+
| 0.0| 3.0|22.0| 7.25| 0.0| 0.0|
+--------+------+----+-------+------+-------+
而你要预测“幸存”,就需要把“Pclass”、“年龄”、“票价”、“性别”、“登车”这几列信息组合成一列。我们通常称之为列特性,它应该是这样的:
+--------+------+----+-------+------+-------+----------------------+
|Survived|Pclass| Age| Fare|Gender|Boarded| features |
+--------+------+----+-------+------+-------+----------------------+
| 0.0| 3.0|22.0| 7.25| 0.0| 0.0|[3.0, 22.0, 7.25, 0, 0] |
+--------+------+----+-------+------+-------+----------------------+
正如您所看到的,新的列功能包含了我们所有功能的相同信息,但是是在一个类似列表的对象中。为了在 Spark 中做到这一点,我们使用了 VectorAssembler :
# Assemble all the features with VectorAssemblerrequired_features = ['Pclass',
'Age',
'Fare',
'Gender',
'Boarded'
]from pyspark.ml.feature import VectorAssemblerassembler = VectorAssembler(inputCols=required_features, outputCol='features')transformed_data = assembler.transform(dataset)
现在,如果我们检查我们的数据,我们有:
+--------+------+----+-------+------+-------+--------------------+
|Survived|Pclass| Age| Fare|Gender|Boarded| features|
+--------+------+----+-------+------+-------+--------------------+
| 0.0| 3.0|22.0| 7.25| 0.0| 0.0|[3.0,22.0,7.25,0....|
| 1.0| 1.0|38.0|71.2833| 1.0| 1.0|[1.0,38.0,71.2833...|
| 1.0| 3.0|26.0| 7.925| 1.0| 0.0|[3.0,26.0,7.92500...|
| 1.0| 1.0|35.0| 53.1| 1.0| 0.0|[1.0,35.0,53.0999...|
| 0.0| 3.0|35.0| 8.05| 0.0| 0.0|[3.0,35.0,8.05000...|
| 0.0| 1.0|54.0|51.8625| 0.0| 0.0|[1.0,54.0,51.8624...|
| 0.0| 3.0| 2.0| 21.075| 0.0| 0.0|[3.0,2.0,21.07500...|
| 1.0| 3.0|27.0|11.1333| 1.0| 0.0|[3.0,27.0,11.1332...|
| 1.0| 2.0|14.0|30.0708| 1.0| 1.0|[2.0,14.0,30.0708...|
| 1.0| 3.0| 4.0| 16.7| 1.0| 0.0|[3.0,4.0,16.70000...|
| 1.0| 1.0|58.0| 26.55| 1.0| 0.0|[1.0,58.0,26.5499...|
| 0.0| 3.0|20.0| 8.05| 0.0| 0.0|[3.0,20.0,8.05000...|
| 0.0| 3.0|39.0| 31.275| 0.0| 0.0|[3.0,39.0,31.2749...|
| 0.0| 3.0|14.0| 7.8542| 1.0| 0.0|[3.0,14.0,7.85419...|
| 1.0| 2.0|55.0| 16.0| 1.0| 0.0|[2.0,55.0,16.0,1....|
| 0.0| 3.0| 2.0| 29.125| 0.0| 2.0|[3.0,2.0,29.125,0...|
| 0.0| 3.0|31.0| 18.0| 1.0| 0.0|[3.0,31.0,18.0,1....|
| 0.0| 2.0|35.0| 26.0| 0.0| 0.0|[2.0,35.0,26.0,0....|
| 1.0| 2.0|34.0| 13.0| 0.0| 0.0|[2.0,34.0,13.0,0....|
| 1.0| 3.0|15.0| 8.0292| 1.0| 2.0|[3.0,15.0,8.02919...|
+--------+------+----+-------+------+-------+--------------------+
only showing top 20 rows
这正是我们想要的。
建模
现在是有趣的部分,对吗?不要!哈哈。建模很重要,但是如果没有前面的步骤,这是不可能的。所以在所有的步骤中享受乐趣:)
在建模之前,让我们按照惯例将训练和测试分开:
(training_data, test_data) = transformed_data.randomSplit([0.8,0.2])
好的。建模。这意味着,在这种情况下,为我们的数据集构建并拟合一个 ML 模型,以预测“幸存”的列和所有其他列。我们将使用一个随机森林分类器。这实际上是一个我们必须适应的估计器。
这实际上是最简单的部分:
from pyspark.ml.classification import RandomForestClassifierrf = RandomForestClassifier(labelCol='Survived',
featuresCol='features',
maxDepth=5)
现在我们符合这个模型:
model = rf.fit(training_data)
这将给我们一个叫做变压器的东西。最后,我们使用测试数据集预测:
predictions = model.transform(test_data)
就是这样!你做到了。恭喜:)。你的第一个火花 ML 模型。现在让我们看看我们做得有多好。为此,我们将使用一个称为准确度的基本指标:
# Evaluate our model
from pyspark.ml.evaluation import MulticlassClassificationEvaluatorevaluator = MulticlassClassificationEvaluator(
labelCol='Survived',
predictionCol='prediction',
metricName='accuracy')
我们要获得我们所做的准确性:
accuracy = evaluator.evaluate(predictions)
print('Test Accuracy = ', accuracy) -> 0.843
我们的基本模型给出了 0.843 的精度。一点也不差:)。
应该注意的是,我们必须做更多的事情来实际构建一个数据科学项目和一个好的 ML 模型,比如交叉验证、特征选择,我们还必须测试更多的模型,等等。
我在 GitHub 中创建了一个 repo,包含了本文的所有代码。您可以在这里找到它:
[## 法维奥巴斯克斯/first_spark_model
你的第一个 Apache Spark 模型:)。通过在…上创建帐户,为 FavioVazquez/first_spark_model 开发做出贡献
github.com](https://github.com/FavioVazquez/first_spark_model)
希望您能从这篇文章中学到一些新东西。我将在这个主题上创造更多,我也将很快与我的公司 Closter 一起推出关于 Spark、Python 和数据科学的课程。你可以通过以下方式联系我:favio [at] closer [dot] net
下期文章再见:)
构建数据科学项目
为什么、何时以及如何开始你的第一个数据科学/机器学习项目
我应该什么时候开始我的第一个项目?
每个数据科学/机器学习的有志者至少会遇到一次的问题是,尽管他们对这个领域相对较新
现在开始我自己的项目是不是太早了?在我开始自己的项目之前,我还需要学习什么?
这个问题的答案因人而异,但一般的经验法则是,一旦你对机器学习的一些基本子主题感到满意,你就可以开始了!永远不会太早。与看别人做同样的事情或阅读相关书籍相比,我们在做一件事情时学得更快,记得更多。
应该选择哪个项目?
选择任何一个你想研究的主题(回归、分类、计算机视觉、自然语言处理等)。),试着为题目想出现实生活中的应用,并制作一个地图,一个粗略的草图,列出你需要采取的所有步骤,让这个想法走出大脑,进入现实世界。
在数据科学职业生涯的早期,您不需要担心您的项目是否有任何现实意义或可能的业务成果。这样做的根本目的是测试你自己的技能,并找到你缺乏知识的领域。
从现在开始,我将带你完成我的第一个数据科学项目,汽车转售价格预测。看一下这个项目的部署版本,以了解您的项目在完成后应该是什么样子。
本文中使用的代码片段摘自我的 GitHub 上的代码。 RESALECARS
开始使用:
以下是您在进行任何数据科学项目时需要遵循的步骤:
- 数据收集
- 数据预处理
- 探索性数据分析
- 特征工程
- 模型结构
- 部署
在本文中,我们将停留在模型构建上。使用 Heroku 和 streamlit 查看 PART-2 进行部署。我将通过上述每一个步骤来预测前面提到的汽车转售价格。
数据收集:
恭喜你!你已经走到这一步了。你有一个你愿意付诸实践的想法。这是你的第一个数据科学创意!现在你必须弄清楚你需要什么数据来建立一个模型。您可以通过两条途径收集数据:
- 流行的数据仓库( Kaggle , UCI 机器学习仓库等。)
- Web 报废
我使用 python 库 Selenium 从网站 CarsDirect 收集数据。然而,在这篇文章中,我不会深入探讨 web 报废技术和框架。
数据预处理:
大多数真实世界的数据集都有空值和其他类型的值(我们将在后面讨论),在进一步研究之前,您需要注意这些值。
让我们看看我们的数据集是什么样的,以及在这个数据集中有多少空值
现在我们已经知道哪些列有缺失值,我们可以继续使用各种统计技术(平均值、中值、众数)或其他方法估算这些缺失值,例如创建一个列来指示缺失值,用不同的类别替换缺失值等。
幸运的是,我处理的数据没有丢失值!
探索性数据分析:
统计学在数据科学中的应用被大大低估了。在将数据输入模型之前,我们首先需要了解哪种数据适用于所选的模型。
-连续数据:
我们可以使用 seaborn 和 matplotlib 等可视化工具,这些工具提供了各种各样的绘图,我们可以用它们来可视化我们数据的各个方面。在处理连续数据时,我们可以先绘制直方图、核密度图、散点图,最后是相关矩阵。
-分类数据:
我们可以使用条形图、饼图来显示分类列中每个类/类别的出现频率,从而使分类列可视化。Seaborn 和 matplotlib 都为此提供了漂亮的可视化工具。然而,最简单的方法是直接使用 pandas(它反过来使用 matplotlib)
特征工程:
我们已经获得了我们的数据。我们已经清理了数据。我们知道我们的数据是如何分布的。因此,让我们开始构建一个模型来预先停止在那里!我们还没有到那一步。我们的数据还没有准备好用于模型训练。
固定偏斜度:
并非所有的数据分布都适用于每个模型。打个比方,如果我(一个印度人)去另一个国家(比如中国),我将无法适应他们的食物,也无法以最佳状态工作,因为我习惯了传统的印度餐。线性模型适用于高斯数据,基于树的模型不需要标准化数据,其他不同的模型需要不同种类的数据。最佳做法是从修正偏斜度并将数据转换为高斯分布开始。
该代码片段允许您可视化所有数字数据的分布,并找出数据的偏差程度。
数据的这种偏斜可以通过各种变换来解决,例如:
- 对数变换
- 博克斯-考克斯变换
- 指数变换
- 相互转化
创建新列:
这一步没有标准程序。这完全取决于您拥有的数据类型。我将通过举例来详细说明你会在哪里使用它。
- 实例 1 :假设您有一列分类数据,其中 10%-15%的数据丢失。您不能删除该实例,因为这将大大减少您的数据大小。你是做什么的??创建一个新列,该列的值为 1,其中给定的列不为空,0 表示空,然后使用-1 或“N.A”作为新的类别来估算空值。
- 实例 2: 假设您有一列连续的数据,比如年龄。您可以进一步使用此列创建一个新列(假设为“成人”),如果年龄为 18 岁,则值为 0,如果年龄≥ 18 岁,则值为 1…
在执行特征工程时,有许多其他方法可以采用,但这是我坚持的主要方法。
在我们开始建模之前,将数据分成测试集和训练集
模型建筑:
我们终于到了。唷!太久了。我们的数据现在可以用于建模了。
对于这个特殊的实例(转售汽车价格回归),我们正在执行的任务是回归。因此,我们将尝试各种回归模型,找出哪种模型能给我们最好的精度/ RMSE,然后构建堆叠模型。
这里我常用的模型有:线性回归、随机森林回归器、梯度推进树、SVM、Lasso、ElasticNet、BayesianRidge、Ridge、LassoLarsIC、Kernel Ridge、XGBoost、LightGBM。很长的名单,不是吗?
为每个模型创建一个参数网格,然后使用随机搜索找到给定模型的理想参数。
下面给出的是梯度推进回归器的代码。这个过程在列表中的每个模型上用不同的参数网格执行。
一旦你知道哪个模型给你最好的准确性,选择所有或/和少数这些,并创建多个集合,以获得最好的输出。
我们现在有了一个好的预测器,好得不能再好了!我们已经从一个想法走了很长的路。我们终于完成了我们的第一个项目!…哦,等等。我们还没有部署模型!
[## 使用 Streamlit 和 Heroku 进行部署
sandeepram3103.medium.com](https://sandeepram3103.medium.com/end-to-end-deployed-project-machine-learning-part-2-43ddb1bc43d0)
谢谢你留下来。我希望这对你有所帮助,如果你觉得这很有用,请鼓掌,如果你有任何与数据科学相关的疑问,请随时联系我。
你在 PyTorch 的第一个神经网络
让我们把电脑预热一下。
随着深度学习领域日益升温,网络上有太多的高级文章,很容易认为深度学习是只为数学博士保留的高级领域——但让我们证明你错了。
照片由 Aziz Acharki 在 Unsplash 上拍摄
深度学习领域,至少是实践部分,从未像现在这样容易起步——因为资源的数量在增长,图书馆也在变得更好。
这篇文章的目标读者是那些知道人工神经网络的基础理论但不知道如何编码的人。相信我,事情会比你想象的简单。
这篇文章的结构如下:
- 导入和数据集
- 训练/测试分割
- 定义神经网络模型
- 模特培训
- 模型评估
- 结论
这看起来很多,但是我保证——如果你安装了必要的库,你最多可以在 10 分钟内读完,如果你决定跟随代码,15 分钟就可以了。
读完这篇文章后,你将对如何在 PyTorch 库中实现一个人工神经网络算法来对以前看不见的数据进行预测有一个基本的想法。
请记住,这篇文章并没有涵盖高级的内容,因为这些内容将会出现在后面的文章中。所以事不宜迟,我们开始吧。
导入和数据集
对于这个简单的例子,我们将只使用几个库:
Pandas
:用于数据加载和操作Scikit-learn
:用于列车测试分割Matplotlib
:用于数据可视化PyTorch
:用于模型训练
如果您只想复制/粘贴,以下是导入内容:
import torch
import torch.nn as nn
import torch.nn.functional as F
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
至于数据集,虹膜数据集,可以在这个 URL 上找到。下面介绍如何在熊猫中直接导入:
iris = pd.read_csv('[https://raw.githubusercontent.com/pandas-dev/pandas/master/pandas/tests/data/iris.csv](https://raw.githubusercontent.com/pandas-dev/pandas/master/pandas/tests/data/iris.csv')')
iris.head()
前几行看起来像这样:
我们现在要做的是将Name
列中的值更改或重新映射为数字——比如说0, 1, 2
。下面是如何做到这一点:
mappings = {
'Iris-setosa': 0,
'Iris-versicolor': 1,
'Iris-virginica': 2
}iris['Name'] = iris['Name'].apply(lambda x: mappings[x])
执行上面的代码会产生以下数据帧:
也就是说我们可以继续了。
训练/测试分割
在本节中,我们将使用Scikit-Learn
库来进行训练/测试分割。之后,我们将把分割数据从Numpy arrays
转换到PyTorch tensors
。
让我们看看怎么做。
首先,我们需要将虹膜数据集分为特征和目标 —或者 X 和 y。列Name
将是目标变量,其他所有内容都将是特征(或预测值)。
我也将使用一个随机的种子,所以你能够复制我的结果。代码如下:
X = iris.drop('Name', axis=1).values
y = iris['Name'].valuesX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)X_train = torch.FloatTensor(X_train)
X_test = torch.FloatTensor(X_test)
y_train = torch.LongTensor(y_train)
y_test = torch.LongTensor(y_test)
如果您现在检查从X_train
开始的前 3 行,您会得到这样的结果:
同样适用于y_train
:
我们现在已经具备了创建神经网络所需的一切——让我们在下一节开始吧。
定义神经网络模型
至于模型的架构,会很简单。让我们看看网络将如何构建:
- 全连通层 ( 4 输入特征(X 中的特征数), 16 输出特征(任意))
- 全连通层 ( 16 输入特征(来自上一层的输出特征数), 12 输出特征(任意))
- 输出层 ( 12 输入特征(来自前一层的输出特征的数量), 3 输出特征(不同类的数量))
差不多就是这样。除此之外,我们将使用 ReLU 作为我们的激活函数。让我们看看如何用代码实现这一点:
class ANN(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(in_features=4, out_features=16)
self.fc2 = nn.Linear(in_features=16, out_features=12)
self.output = nn.Linear(in_features=12, out_features=3)
def forward(self, x):
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.output(x)
return x
PyTorch 使用这种面向对象的方式来声明模型,并且非常直观。在构造函数中,您将定义所有的层及其架构,在forward()
方法中,您将定义一个向前传递。
就这么简单。
现在,让我们创建一个模型实例,并验证其架构是否与我们上面指定的架构相匹配:
model = ANN()
model
太好了。在我们训练模型之前,我们还需要声明几件事情:
- 标准:基本上我们如何衡量损失,我们将使用
CrossEntropyLoss
- 优化器:优化算法,我们将使用学习率为
0.01
的Adam
下面是如何用代码实现它:
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
现在是我们期待已久的部分——模特培训!
模特培训
这部分也会极其简单。我们将训练模型 100 个纪元,记录时间和损失。每隔 10 个时期,我们将向控制台输出当前状态——指示我们所处的时期以及当前的损失。
代码如下:
%%timeepochs = 100
loss_arr = []for i in range(epochs):
y_hat = model.forward(X_train)
loss = criterion(y_hat, y_train)
loss_arr.append(loss)
if i % 10 == 0:
print(f'Epoch: {i} Loss: {loss}')
optimizer.zero_grad()
loss.backward()
optimizer.step()
如果你想知道最后 3 行在做什么,答案很简单— 反向传播 —因此更新权重和偏差,这样模型就可以真正“学习”。
下面是上面代码的结果:
太快了——请不要习惯这种感觉。
如果简单的数字对你来说毫无意义,这里有一个我们损失的可视化(x 轴上的纪元编号和 y 轴上的损失):
我们已经训练了模型,但是现在呢?我们需要以某种方式在以前看不见的数据上评估。在这里多呆一分钟,你就会知道怎么做了。
模型评估
在评估过程中,我们希望以某种方式跟踪模型做出的预测。我们需要迭代X_test
并做出预测,然后将它与实际值进行比较。
这里我们将使用torch.no_grad()
,因为我们只是在评估——没有必要更新权重和偏差。
总之,代码如下:
preds = []with torch.no_grad():
for val in X_test:
y_hat = model.forward(val)
preds.append(y_hat.argmax().item())
预测现在存储在preds
数组中。我们现在可以用以下 3 个属性制作一个熊猫数据帧:
Y
:实际值YHat
:预测值Correct
:标志,1 表示Y
和YHat
匹配,否则为 0
代码如下:
df = pd.DataFrame({'Y': y_test, 'YHat': preds})df['Correct'] = [1 if corr == pred else 0 for corr, pred in zip(df['Y'], df['YHat'])]
df
的前 5 行将如下所示:
这很好,但是实际上如何计算精确度呢?
这很简单——我们只需要对Correct
列求和,然后除以df
的长度:
df['Correct'].sum() / len(df)**>>> 1.0**
我们的模型对以前未见过的数据的准确率是 100%。请记住,这只是因为虹膜数据集非常容易分类,这绝不是说神经网络是该数据集的最佳算法。我会说 NN 对于这种类型的问题来说太过了,但是这是另一个时间的讨论。
结论
这就是你所要写的最简单的神经网络,有一个完美干净的数据集,没有丢失的值,最少的层和神经元,承认吧,这很容易。
下一次就不会了——因为更多的先进概念将会被引入。
感谢阅读。再见。
喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。
[## 通过我的推荐链接加入 Medium-Dario rade ci
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
medium.com](https://medium.com/@radecicdario/membership)
你迈向 AI 的第一步——标签数据!
成功的机器学习项目需要良好的数据——但在许多项目中,这可能已经是第一个主要障碍。例如,来自照相机的图像数据可能已经可用,但是到目前为止还没有记录计算机可读的数据,这些数据在将来应该会被自动识别。特别是如果你想从 AI 开始,前面的数据准备工作可能会令人不知所措。当然,在您只想从一个已定义领域的概念证明开始第一次尝试的情况下,这尤其令人沮丧。
因此,您需要一个解决方案来快速、轻松地标记您自己的原始数据。我们看了看工具丛林,收集了市场所能提供的和需要注意的东西。让我们来看看在开始贴标签之前,你应该问自己哪些重要的问题,以及你可以使用的工具。
谁应该给数据贴标签?
标注是一项非常繁琐的任务——尤其是如果你想为深度学习算法提供足够多的数据。如果你不相信这一点,你应该想象一下,以像素级的精度在数百张图像上画出组件的缺陷是什么样的。不幸的是,一定数量的标记数据是绝对必要的。那么你从哪里得到这些数据呢?基本上,有以下几种情况:
- *领域专家对数据的标注:*当涉及到你自己的数据时,作为一名专家你自然最清楚应该如何标注。在开始时,您应该决定什么是存储标签的好格式,并使用合适的工具建立一个工作流,以便可以对数据集尽可能快地完成这项工作。
- *由人工智能服务提供商标记:*在适当的指导和解释之后,您的人工智能伙伴当然也能够执行标记。这样做的好处是可以直接传达对基本数据及其类的良好理解。同时,这种方法在大多数情况下成本太高,因为贴标签本身并不复杂。
- *第三方贴标:*也可以将工作完全外包。谷歌等云服务提供商也为此提供自己的服务(【https://cloud.google.com/ai-platform/data-labeling/docs】T2)。但是,仅支持某些格式(图像、视频和文本),并且必须制定非常具体的指令才能获得正确的结果。文档建议进行几次测试,直到它工作为止。数据本身当然也必须转移到云中。
在下文中,我们将更多地关注前两种情况,因为根据我们的经验,它们发生得最为频繁。
什么样的数据可以被标注?
虽然当考虑带标签的数据和图像中的人工智能对象识别是首先想到的事情,但来自不同应用程序的各种各样的数据类型都可以用标签来丰富。标签本身也可以应用在不同的层次上。例如,您可以标记整个图像,在其中绘制框并标记它们(边界框分割),甚至分配具有像素精度的类(语义分割)。
不同种类的标记级别(从左至右):标记、边界框、语义分割、安德里亚·苏克罗改编自的图片 https://www . pexels . com/photo/grey-and-white-long-coated-cat-in-middle-of-book-son-shelf-156321/
除了图像,当然还有其他非常适合处理的数据格式,其中最相关的有:
- 时间序列:例如,这包括机器控制系统的记录或生产过程中保存的传感器值。
- 音频:来自音频区的数据可用于识别语音或分析麦克风在任何过程中拾取的录音。
- Text :对自然语言处理领域的所有用例都感兴趣,比如聊天机器人或智能文档管理系统。
- 图像:通常来自照相机或光学传感器的数据,其应该支持例如生产过程结束时的质量控制。
- 视频:视频记录可来自监控摄像头,例如可用于提高机器操作的安全性。
- 3D 数据:也可以想象,例如制造模型的部件需要提供标签。
正如我们将在后面看到的,工具在不同程度上支持不同的数据区域。但是,除了功能性要求之外,还有其他一些一般条件需要考虑。
一个好的标签工具还有哪些进一步的要求?
如果你正在与一家人工智能服务提供商合作,并且拥有敏感的公司数据,那么还有更进一步的考虑。
- 许可合规:当使用外部工具时,如果客户想要自己贴标,必须允许在有限的时间内将其传递给客户。另一方面,如果人工智能服务提供商支持贴标签过程,这种情况也可能发生在客户身上。
- 数据安全性:如果可能的话,我们希望避免基于云的解决方案,因为我们经常处理敏感数据,不希望这些数据不必要地出现在标签供应商的服务器上。
- 舒适性:该工具还应能被缺乏技术经验的员工直观地操作。这方面也包括时间投入。使用选择的工具总是比“手动”更快。该工具还必须在技术上易于设置,并且可以在尽可能多的环境中使用。
- 用例覆盖:最理想的是,一个工具而不是五个工具。这应该是一个程序,支持图像分割,但也可以处理时间序列分类。
- 成本:使用的工具不应超出财务和时间框架。在大多数情况下,这种考虑可以反映在免费工具和付费解决方案节省的时间的比较中。
鉴于这些标准,我们准备看看提供的解决方案!
有哪些工具?
我们环顾四周,试图了解市场上现有的解决方案。我们研究了商业软件和免费软件,试图理解它们涵盖了哪些用例。商业解决方案大多基于云支持,除了标签之外,还提供额外的功能,如人工智能算法的同步培训或外部劳动力的支持。大多数免费的替代方案通常需要命令行安装,并且不能作为现成的解决方案使用(如果您想自己托管它们)。
我们对不同标签工具的比较概述,图片作者 Andrea Suckro (slashwhy)
该表迄今为止还不完整,而是旨在给出当前解决方案的概述。我们注意到,对于 3D 数据的标记,没有真正规范的解决方案(除了 KNOSSOS,它是一种用于组织数据的专用工具)。因此,对于您的技术 3D 数据,您必须使用自己选择的工具(例如,AutoCAD、Blender 等)进行标注,并将其导出到相应的文件中。
最后的想法
所有的开始都是困难的——就像为一个最初的人工智能项目准备带有标签的原始数据一样。然而,我们可以依靠不断增加的支持和工具。对于这个领域的第一步,Label-Studio 最让我们信服,因为它安装迅速,易于使用。如果需要,它还对不同的数据类型和高级工作流提供了非常广泛的支持。我们希望这篇文章可以让你对标签世界有一点了解,并使你能够在你的个人人工智能之旅中迈出下一步。所以不要害羞,让我们开始吧——从收集数据到贴标签!
以下是我们介绍的工具的链接集合:
- 仓促https://hasty.ai/solution.html
- https://www.datagym.ai/数据体育馆
- https://labelbox.com/标签盒
- 谷歌云 AI 标签https://cloud.google.com/ai-platform/data-labeling/docs
- 云工厂https://www.cloudfactory.com/data-labeling
- 最终标记https://github.com/alexandre01/UltimateLabeling
- 拉贝尔梅https://github.com/wkentaro/labelme
- https://github.com/tzutalin/labelImg
- 标签工作室https://github.com/heartexlabs/label-studio
- 曲线https://github.com/baidu/Curve
- https://archive.mpi.nl/tla/elan 的锐气
线性回归模型指南
用 Python 解释和编程线性回归模型
可解释性是机器学习中最大的挑战之一。如果一个模型的决策更容易被人理解,那么这个模型就比另一个模型更具有可解释性。有些模型非常复杂,内部结构如此复杂,以至于几乎不可能理解它们是如何得出最终结果的。这些黑盒似乎打破了原始数据和最终输出之间的关联,因为在这之间发生了几个过程。
但是在机器学习算法的宇宙中,有些模型比其他模型更透明。决策树肯定是其中之一,线性回归模型又是另外一个。它们的简单和直接的方法使它们成为解决不同问题的理想工具。让我们看看怎么做。
您可以使用线性回归模型来分析给定地方的工资如何依赖于经验、教育水平、角色、工作城市等特征。同样,您可以分析房地产价格是否取决于诸如面积、卧室数量或到市中心的距离等因素。
在这篇文章中,我将重点关注线性回归模型,这些模型检查一个因变量和一个(简单线性回归)或多个(多元线性回归)自变量之间的线性关系。
简单线性回归
当输出变量(目标)只有一个输入变量(预测值)时,使用的是最简单的线性回归形式:
- 输入或预测变量是帮助预测输出变量值的变量。俗称 X 。
- 输出或目标变量是我们想要预测的变量。就是俗称的 y 。
β0 的值,也叫截距,表示估计回归线与 y 轴相交的点,而 β1 的值决定了估计回归线的斜率。随机误差描述的是因变量和自变量之间线性关系的随机成分(模型的扰动, y 中 X 无法解释的部分)。真正的回归模型通常是未知的(因为我们无法捕捉影响因变量的所有效应),因此对应于观察数据点的随机误差项的值仍然未知。然而,回归模型可以通过计算观察数据集的模型参数来估计。
回归背后的想法是从样本中估计参数 β0 和 β1 。如果我们能够确定这两个参数的最佳值,那么我们将有最佳拟合的线,我们可以用它来预测的值,给定 X 的值。换句话说,我们试图拟合一条线来观察输入和输出变量之间的关系,然后进一步用它来预测看不见的输入的输出。
我们如何估算 β0 和 β1 ?我们可以使用一种叫做普通最小二乘法(OLS) 的方法。其背后的目标是将黑点到红线的距离尽可能地减小到接近零,这是通过最小化实际结果和预测结果之间的平方差来实现的。
实际值和预测值之间的差异称为残差(e) ,可以是负数,也可以是正数,这取决于模型是否高估或低估了结果。因此,为了计算净误差,将所有残差直接相加会导致项的消除和净效应的减小。为了避免这种情况,我们取这些误差项的平方和,称为 残差平方和(RSS)。
普通最小二乘法(OLS)将残差平方和最小化,其目的是拟合一条回归线,使观测值与预测值(回归线)之间的距离(以二次值测量)最小化。
多元线性回归
有两个或两个以上预测值或输入变量时,线性回归的形式。与之前描述的 SLR 模型相似,它包括额外的预测因子:
请注意,该方程只是简单线性回归方程的扩展,其中每个输入/预测值都有其对应的斜率系数 (β ) 。第一个 β
随着要素数量的增长,我们的模型的复杂性也在增加,并且变得更加难以可视化,甚至难以理解我们的数据。因为与单反相机相比,这些模型中的参数更多,所以在使用它们时需要更加小心。添加更多的术语将从本质上提高数据的拟合度,但新术语可能没有任何实际意义。这是危险的,因为它可能会导致一个模型符合这些数据,但实际上并不意味着任何有用的东西。
一个例子
广告数据集包括一种产品在 200 个不同市场的销售额,以及三种不同媒体的广告预算:电视、广播和报纸。我们将根据电视、广播和报纸广告预算(自变量),使用数据集来预测销售额(因变量)。
数学上,我们将尝试求解的公式是:
找到这些常数的值 (β) 就是回归模型通过最小化误差函数和拟合最佳直线或超平面(取决于输入变量的数量)所做的事情。我们编码吧。
加载数据并描述数据集
你可以在这个链接下下载数据集。在加载数据之前,我们将导入必要的库:
*import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn import metrics
from sklearn.metrics import r2_score
import statsmodels.api as sm*
现在我们加载数据集:
*df = pd.read_csv(“Advertising.csv”)*
让我们了解数据集并对其进行描述:
*df.head()*
我们将删除第一列(“未命名”),因为我们不需要它:
*df = df.drop([‘Unnamed: 0’], axis=1)
df.info()*
我们的数据集现在包含 4 列(包括目标变量“sales”)、200 个寄存器,没有缺失值。让我们想象一下自变量和目标变量之间的关系。
*sns.pairplot(df)*
电视和销售之间的关系似乎相当紧密,虽然广播和销售之间似乎有某种趋势,但报纸和销售之间的关系似乎并不存在。我们也可以通过相关图进行数字验证:
*mask = np.tril(df.corr())
sns.heatmap(df.corr(), fmt=’.1g’, annot=True, cmap= ‘cool’, mask=mask)*
正如我们所料,最强的正相关发生在销售和电视之间,而销售和报纸之间的关系接近于 0。
选择特征和目标变量
接下来,我们将变量分成两组:因变量(或目标变量“y”)和自变量(或特征变量“X”)
*X = df.drop([‘sales’], axis=1)
y = df[‘sales’]*
分割数据集
要了解模型性能,将数据集分为定型集和测试集是一个好策略。通过将数据集分成两个独立的集合,我们可以使用一个集合进行训练,并使用另一个集合中的未知数据来测试模型性能。
*X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)*
我们将数据集分成 70%训练和 30%测试。random_state 参数用于初始化内部随机数生成器,它将决定在您的情况下将数据分为训练和测试索引。我设置 random state = 0,这样您就可以使用相同的参数比较多次运行代码的输出。
*print(X_train.shape,y_train.shape,X_test.shape,y_test.shape)*
通过打印分割集合的形状,我们看到我们创建了:
- 2 个各有 140 个寄存器的数据集(占总寄存器的 70%),一个有 3 个自变量,一个只有目标变量,将用于训练和生成线性回归模型。
- 2 个数据集,每个包含 60 个寄存器(占总寄存器的 30%),一个包含 3 个自变量,一个仅包含目标变量,将用于测试线性回归模型的性能。
建立模型
构建模型非常简单:
*mlr = LinearRegression()*
火车模型
将模型拟合到训练数据代表了建模过程的训练部分。在模型定型后,可以使用预测方法调用来进行预测:
*mlr.fit(X_train, y_train)*
我们来看看模型训练后的输出,看看 β0 (截距)的值:
*mlr.intercept_*
我们还可以打印系数的值 (β) :
*coeff_df = pd.DataFrame(mlr.coef_, X.columns, columns =[‘Coefficient’])
coeff_df*
通过这种方式,我们现在可以根据电视、广播和报纸的不同预算值来估算“销售”值:
例如,如果我们确定电视预算值为 50,广播预算值为 30,报纸预算值为 10,则“销售额”的估计值为:
*example = [50, 30, 10]
output = mlr.intercept_ + sum(example*mlr.coef_)
output*
试验模型
测试数据集是独立于训练数据集的数据集。该测试数据集是您的模型的未知数据集,它将帮助您更好地了解其归纳能力:
*y_pred = mlr.predict(X_test)*
评估绩效
模型的质量与其预测与测试数据集的实际值的匹配程度有关:
*print(‘Mean Absolute Error:’, metrics.mean_absolute_error(y_test, y_pred))
print(‘Mean Squared Error:’, metrics.mean_squared_error(y_test, y_pred))
print(‘Root Mean Squared Error:’, np.sqrt(metrics.mean_squared_error(y_test, y_pred)))
print(‘R Squared Score is:’, r2_score(y_test, y_pred))*
在根据测试集验证了我们的模型之后,我们得到了 0.86 的 R,这似乎是一个相当不错的性能分数。但是,尽管较高的 R 表明模型更适合,但高度量并不总是一件好事。我们将在下面看到一些解释和改进回归模型的方法。
如何解读和改进你的模型?
好了,我们创建了模型,现在做什么?让我们看看训练数据的模型统计数据,以获得一些答案:
*X2 = sm.add_constant(X_train)
model_stats = sm.OLS(y_train.values.reshape(-1,1), X2).fit()
model_stats.summary()*
下面我们来看看这些数字是什么意思。
假设检验
运行 MLR 模型时,您应该回答的一个基本问题是,是否至少有一个预测因子对预测输出有用。如果自变量和目标之间的关系只是偶然的,并且没有任何预测因素对销售产生实际影响,那该怎么办?
我们需要进行假设检验来回答这个问题,并检查我们的假设。这一切都是从形成一个零假设(H0) 开始的,该假设声明所有系数都等于零,并且预测值和目标值之间没有关系(这意味着没有独立变量的模型既适合数据,也适合您的模型):
多元线性回归。来源:走向数据科学
另一方面,我们需要定义一个替代假设(Ha) ,该假设声明至少有一个系数不为零,并且预测值和目标值之间存在关系(意味着您的模型比仅截距模型更好地拟合数据):
多元线性回归。来源:走向数据科学
如果我们想要拒绝零假设并对我们的回归模型有信心,我们需要找到强有力的统计证据。为此,我们进行假设检验,为此我们使用了 F 统计量。
如果 F-statistic 的值等于或非常接近 1,则结果有利于零假设,我们无法拒绝它。
正如我们在上表中看到的(用黄色标记),F-统计量是 439.9,从而提供了反对零假设(所有系数都是零)的有力证据。接下来,我们还需要在假设零假设为真的情况下,检查 F 统计量(也用黄色标记)出现的概率,即 8.76e-70,一个极小的低于 1%的数字。这意味着在有效的零假设假设下,F 统计值 439.9 偶然出现的概率远低于 1%。
话虽如此,我们可以拒绝零假设,并确信至少有一个预测因子在预测输出时是有用的。
生成模型
运行包含许多变量(包括不相关的变量)的线性回归模型会导致不必要的复杂模型。哪些预测因素是重要的?它们对我们的模型都有意义吗?为了找出答案,我们需要执行一个叫做特征选择的过程。特征选择的两种主要方法是:
- ***正向选择:*从与因变量相关性最高的预测值开始,一次添加一个预测值。然后,更大的理论重要性的变量被顺序地结合到模型中,直到达到停止规则。
- ***逆向淘汰:*从模型中的所有变量开始,去掉统计意义最小(p 值较大)的变量,直到达到停止规则。
虽然这两种方法都可以使用,除非预测值的数量大于样本大小(或事件数量),否则通常最好使用向后排除法。
你可以在链接中找到这些方法的完整示例和实现。
对比车型
每当你在一个模型中加入一个独立变量,R 就会增加,即使这个独立变量微不足道。在我们的模型中,所有预测因素都有助于销售增长吗?如果是的话,他们做的程度一样吗?
与 R 相反,调整后的 R 是一个仅在自变量显著并影响因变量时增加的度量。因此,如果随着您向模型中添加变量,您的 R 值增加了,但调整后的 R 值减少了,那么您就知道有些特性是没有用的,您应该删除它们。
上表中一个有趣的发现是,报纸的 p 值超高(0.789,红色标注)。找到每个系数的 p 值将会知道该变量对于预测目标是否具有统计显著性。
根据一般经验,如果给定变量的 p 值小于 0.05,则该变量和目标之间有很强的关系。
这种方式,包括变量报纸似乎不适合达到一个稳健的模型,删除它可能会提高模型的性能和泛化能力。
除了调整后的 R 分数,您还可以使用其他标准来比较不同的回归模型:
- 赤池信息准则(AIC): 是一种用于估计模型的似然性以预测/估计未来值的技术。它奖励达到高拟合度分数的模型,如果它们变得过于复杂,则惩罚它们。一个好的模型是所有其他模型中 AIC 最小的模型。
- 贝叶斯信息标准(BIC): 是模型选择的另一个标准,衡量模型拟合度和复杂性之间的权衡,对过于复杂的模型的惩罚甚至超过 AIC。
假设
因为线性回归模型是任何事件的长期序列的近似值,所以它们需要对它们所代表的数据做出一些假设,以便保持适当。大多数统计测试依赖于对分析中使用的变量的某些假设,当这些假设不满足时,结果可能不可信(例如,导致 I 型或 II 型错误)。
从输出是输入变量的线性组合的意义上来说,线性回归模型是线性的,并且只适合于对可线性分离的数据进行建模。线性回归模型在各种假设下工作,这些假设必须存在,以便产生正确的估计,而不仅仅依赖于准确性分数:
- 线性:特征和目标之间的关系必须是线性的。检查线性关系的一种方法是目视检查散点图的线性。如果散点图中显示的关系不是线性的,那么我们需要运行非线性回归或转换数据。
- 同方差:对于 x 的任何值,残差的方差必须相同。多元线性回归假设残差中的误差量在线性模型的每个点都是相似的。这种情况称为同质性。散点图是检查数据是否同质的好方法,也有几种测试可以从数字上验证假设(如 Goldfeld-Quandt、Breusch-Pagan、White)
线性回归算法的假设。来源:走向数据科学
- ***无多重共线性:*数据不应显示多重共线性,当独立变量(解释变量)彼此高度相关时会出现多重共线性。如果发生这种情况,在计算出造成因变量/目标变量差异的具体变量时就会出现问题。这种假设可以用方差膨胀因子(VIF)法或通过相关矩阵来检验。解决这个问题的替代方法可能是将数据居中(扣除平均分数),或者进行因子分析并旋转因子以确保线性回归分析中因子的独立性。
- 无自相关:残差的值应该彼此独立。残差中相关性的存在大大降低了模型的准确性。如果误差项相关,估计的标准误差往往会低估真实的标准误差。为了检验这个假设,你可以使用 Durbin-Watson 统计。
- 残差的正态性:残差必须是正态分布的。正态性可以用拟合优度检验(如科尔莫戈罗夫-斯米尔诺夫或夏皮罗-维尔克检验)来检查,如果数据不是正态分布,非线性变换(如对数变换)可能会解决这个问题。
线性回归算法的假设。来源:走向数据科学
假设是至关重要的,因为如果假设无效,那么分析过程就会被认为是不可靠的、不可预测的和失控的。无法满足假设可能导致得出无效或没有数据科学支持的结论。
你可以在链接中找到对假设的全面测试。
最后的想法
虽然 MLR 模型扩展了 SLR 模型的范围,但它们仍然是线性模型,这意味着模型中包含的术语不能显示彼此之间的任何非线性关系,也不能代表任何种类的非线性趋势。预测要素观测范围之外的点时也应小心,因为当您移出观测范围时,变量之间的关系可能会发生变化(由于没有数据,您无法知道这一事实)。
观察到的关系可能是局部线性的,但在数据范围之外可能存在未观察到的非线性关系。
线性模型还可以通过包含非线性变量(如多项式)和转换指数函数来模拟曲率。线性回归方程在 参数 中为线性,意思是你可以将自变量提升一个指数来拟合一条曲线,仍然保持在“线性世界”中。线性回归模型可以包含对数项和反项,以遵循不同类型的曲线,但仍然保持参数的线性。**
当自变量被平方时,模型在参数上仍然是线性的
像 多项式回归 这样的回归可以模拟非线性关系*,虽然线性方程有一种基本形式,但非线性方程可以采取许多不同的形式。您可能考虑使用 非线性回归模型 的原因是,虽然线性回归可以模拟曲线,但它可能无法模拟数据中存在的特定曲线。*
您还应该知道,OLS 并不是拟合您的线性回归模型的唯一方法,其他优化方法,如 梯度下降 更适合大型数据集。将 OLS 应用于复杂的非线性算法可能不可扩展,梯度下降法在计算上可以更便宜(更快)地找到解决方案。梯度下降是一种最小化函数的算法,给定一个由一组参数定义的函数,该算法从一组初始参数值开始,迭代地向一组最小化该函数的参数值移动。这个迭代最小化是使用导数实现的,在函数梯度的负方向上采取步骤。
使用梯度下降的线性回归。来源:走向数据科学
另一个需要考虑的关键问题是异常值会对回归线和相关系数产生巨大影响。为了识别它们,有必要执行探索性数据分析(EDA) ,检查数据以检测异常观察,因为它们会以激烈的方式影响我们的分析和统计建模的结果。如果您发现任何异常值,可以对其进行估算(例如,使用平均值/中值/众数)、封顶(替换某些限制之外的值)或替换缺失值并进行预测。
最后,线性回归模型的一些限制是:
- 省略变量。需要有一个好的理论模型来建议解释因变量的变量。在简单的双变量回归的情况下,人们必须考虑其他因素来解释因变量,因为可能有其他“未观察到的”变量来解释输出。
- 反向因果关系。许多理论模型预测双向因果关系——也就是说,因变量可以引起一个或多个解释变量的变化。例如,更高的收入可以让人们在自己的教育上投入更多,这反过来会提高他们的收入。这使得回归估计的方式变得复杂,需要特殊的技术。
- 测量错误。因子可能测量不正确。例如,天资很难衡量,智商测试也存在众所周知的问题。因此,使用智商的回归可能无法正确控制资质,导致教育和收入等变量之间的不准确或有偏差的相关性。
- 太局限了一个焦点。回归系数仅提供一个变量的小变化(而非大变化)与另一个变量的变化之间的关系。它将显示教育中的一个小变化是如何影响收入的,但它不会让研究者概括大变化的影响。如果每个人同时接受大学教育,一个刚毕业的大学生不太可能挣得更多,因为大学毕业生的总供给会急剧增加。
对这些话题感兴趣?在 Linkedin或 Twitter 上关注我
你的网刮 Quora 问答指南
数据科学
只需几行代码,你就能抓取 Quora 的数据
来源:由 Flickr 中的托马斯·霍克(CC By-NC 2.0)
在本教程中,我将向您展示如何使用 Anaconda Jupyter 笔记本和 BeautifulSoup 库来执行 web 抓取。
我们将从 Quora 搜集问题和答案,然后我们将它们导出到Pandaslibrary data frame,然后导出到一个. CSV 文件。
让我们直接进入正题,然而,如果你正在寻找一个指南来理解网络抓取,我建议你阅读来自 Dataquest 的这篇文章。
1-使用一个 URL
让我们导入我们的库
import urllib
import requests
from bs4 import BeautifulSoup
import pandas as pd
插入你的 Quora 网址,一个例子显示。
url = ‘[https://www.quora.com/Should-I-move-to-London'](https://www.quora.com/Should-I-move-to-London')
然后让我们向 web 服务器发出一个GET
请求,它将为我们下载给定网页的 HTML 内容。
page = requests.get(url)
现在,我们可以使用 BeautifulSoup 库来解析这个页面,并从中提取文本。我们首先必须创建一个BeautifulSoup
类的实例来解析我们的文档:
soup = BeautifulSoup(page.content, ‘html.parser’)
然后,我们将创建熊猫数据框架来包含我们想要的问答。
df = pd.DataFrame({‘question’: [],’answers’:[]})
现在是从网页中选择问答类的时候了,类在抓取时被用来指定我们想要抓取的特定元素。
question = soup.find(‘span’, {‘class’: ‘ui_qtext_rendered_qtext’})
answers = soup.find_all(‘div’, attrs={‘class’: ‘ui_qtext_expanded’})
然后,我们可以通过将结果添加到之前创建的数据框架中来得出结论。
for answer in answers:
df = df.append({‘question’: question.text,
‘answers’: answer.text
}, ignore_index=True)
df
将结果导出到 CSV 文件的时间。
df.to_csv(‘One_URLs.csv’)
2-使用多个 URL
这一次我们将一起努力在同一时间内刮出不止一页。这一过程几乎与相对变化相同。
从导入库开始
import urllib
import requests
from bs4 import BeautifulSoup
import pandas as pd
添加所有你需要的网址,我们现在有 2 个
url = [‘[https://www.quora.com/What-are-best-places-to-relocate-and-settle-in-UK'](https://www.quora.com/What-are-best-places-to-relocate-and-settle-in-UK'), ‘[https://www.quora.com/Should-I-relocate-to-the-UK'](https://www.quora.com/Should-I-relocate-to-the-UK')]
创建我们的数据框架
df = pd.DataFrame({‘question’: [],’answers’:[]})
现在,我们将执行一个 for 循环,该循环将迭代两个 URL 来执行相同的过程,然后它可以将结果保存到 DataFrame 中。
for i in url:
page = requests.get(i)
soup = BeautifulSoup(page.content, “html.parser”)
question = soup.find(‘span’,
{‘class’: ‘ui_qtext_rendered_qtext’})
answers = soup.find_all(‘div’,
attrs={‘class’: ‘ui_qtext_expanded’})
for answer in answers:
df = df.append({‘question’: question.text,
‘answers’: answer.text
}, ignore_index=True)
df
现在,让我们将数据帧导出到 CSV 文件。
df.to_csv(‘Two_URLs.csv’)
您现在应该对如何从 Quora 中抓取和提取数据有了很好的理解。一个很好的下一步,如果你对网络抓取有点熟悉,你可以选择一个网站,自己尝试一些网络抓取。
快乐编码:)
你想象中作为数据分析师的第一天
在你先前在线课程知识的帮助下完成你的第一个项目
你有没有问过自己,作为一名数据分析师,成功的第一天是怎样的?为了获得我的数据科学纳米学位,我将向您展示一个简单的场景。
你会学到:
- 什么是交叉销售?
- 如何分析你的客户?
- 如何使用机器学习进行交叉销售预测?
塞纳里奥
我从 Kaggle 获得了一个名为“健康保险”交叉销售预测的数据集🏠 🏥。请想象一下,你是一家大型保险公司的数据分析师。作为你的第一份工作,你的老板让你分析一个特定的客户数据集。他给了您一个 customer-info.csv 文件和以下三个问题:
- 我们公司的典型客户是什么?
- 什么因素决定了客户是否愿意接受我们的保险?
- 哪些客户会对我们的营销活动做出回应?
不幸的是,作为一名初露头角的数据科学家,你不知道什么是交叉销售,所以你马上去谷歌一下:
“交叉销售是向现有客户销售额外产品或服务的行为或实践”——维基百科 2020
现在你知道了。你在一家提供全面健康保障的大型保险公司工作。这家保险公司现在希望扩大其产品组合。因此,你的工作是找出哪些客户可能对汽车保险感兴趣。
我们公司的典型客户是什么?
现在您想使用您的 Python 知识来分析数据。为了可视化和分析数据,您使用了 Seaborn 和 Pandas 库。完成后,您定义了两个客户角色。
安24 岁,住在州,拥有**【28】的优秀称号。她有驾照**,她的车是两年前的并且已经损坏。到目前为止,她对汽车保险没有兴趣。
凯文今年 28 岁,也住在州,有着优秀的头衔**【28】。他也有驾驶执照。因为他真的很喜欢汽车,他的车是几个月前的**,它的一点损坏都没有。到目前为止,他对汽车保险没有兴趣。
当你向你的同事展示人物角色时,他们会印象深刻。但是,他们建议您再添加一些图表。否则,老板会怀疑这一切是不是你编造的。你想,这一点问题都没有。毕竟,人物角色不是你想出来的。恰恰相反,数据分析是你假设的人物角色的基础。首先,您创建了一个性别分布图。
性别分布只相差几个百分点。所以,你决定要一男一女。下一步是观察年龄分布。你还确保每个年龄组的男性人数大致相同。因此,你用两种颜色描绘了年龄分布。您可以从图表中看到,大多数客户都在 25 岁到 30 岁出头之间。
所以,你决定选择 24 岁和 28 岁的两个人。所以你选择了 24 岁和 28 岁的两个人。即使你对此没有任何更精确的信息,你也要相信你的直觉。在关于该地区的图表中,您可以看到大多数人来自第 28 州,并且每个人都有驾驶执照。
最后,您决定仔细看看客户的汽车。您已经注意到,大多数客户的车龄在 1 到 2 年之间,甚至不到 1 年。你认为这是重要的信息,当然,你想把它包含在你的人物角色中。
客户是否会对我们的交叉销售方法做出反应,这取决于什么?
你的老板对你的分析印象深刻。但是他也有需要批评的地方。你的两个角色都对我们的产品不感兴趣。他想知道是什么因素影响了安和凯文,使他们更有可能从他的公司购买汽车保险。
所以,你回去工作,你决定在反应特征和其他特征之间找到一些关联。
您将从热图中获得的新信息添加到角色中:
如果凯文的车受到更严重的损坏,他会改变主意的。这是基于响应标准和车辆损坏标准之间的小相关性(0.35)。你认为向你的老板建议我们可以损坏凯文的车很有趣,但你决定反对。讽刺很可能第一天就没好结果。
如果 Ann 年纪大了,她可能会改变主意(相关系数仅为 0.11)。老年人对保险更感兴趣,这意味着我们的营销活动可以专注于长期客户,但我们还没有要求他们购买车辆保险。
哪些客户会对我们的营销活动做出回应?
当把你的最终结果展示给你的老板时,他留下了深刻的印象,他现在要求你使用一些奇特的机器学习来完成你的任务。因为您已经准备好了数据,所以这没什么大不了的,因为您知道预处理已经完成了 80%的工作。
然而,在快速研究了 ScitKit-Learn 文档之后,您现在也知道该怎么做了。你的问题是一个二元分类(会或不会响应我们的交叉销售方法)你可以使用一些分类器。你决定采用一些最先进的方法,如 LBM 或 XGBoost。
同时,您希望使用一个旧的但众所周知的模型,这样您就可以展示新的高级分类器的优势。对于评估指标,你又谷歌了一遍。研究表明,一个平衡的分类器(精确度和召回率之间的平衡)会非常好。所以你确保了这一点。
从结果中可以看出,与其他分类器相比,LBM 分类器工作得相当好,并且也是平衡的。您将使用它来预测哪些客户最有可能对我们的营销活动做出回应。
在你把最终结果发给你的老板后,你会感到无比的快乐。你在网上课程中投入的所有工作和努力确保了你能在你的第一个任务和新职位上取得成功!用你最喜欢的机器学习和统计蔻驰的话说。
三次爆炸。三次爆炸。作为一名潜在的数据分析师,我们在第一天就站稳了脚跟。明天我们将获得一份真正的工作,这样我们就可以在准确的数据上测试跨行业的数据挖掘标准流程。我们很好奇。
你可以在我的 GitHub 库找到这篇文章的代码💻。感谢阅读!如果你喜欢它,请一定要鼓掌,看看我的网站🌎不要犹豫,给我发电子邮件询问反馈📩。
您的实时新冠肺炎跟踪与气流和 GitHub 网页
加载数据,使用散景制作出色的可视化效果,将它们托管在 GitHub Pages 网站上,并随着新数据的到来,让气流自动完成这一过程!
在 Unsplash 上由 Fabrizio Verrecchia 拍摄的照片
随着新冠肺炎病的爆发,我们——数据科学爱好者——可以使用一系列令人惊叹的数据集来制作我们自己的可视化工具,获得有用的见解,并为有用和智能信息的传播做出贡献。
这些数据通常每天更新,因为新闻中报道了新的病例。因此,想象一下,您加载数据并花大量时间清理它,进行探索性的数据分析,并创建令人印象深刻的可视化;然后你决定保存你的图表并分享它们。到目前为止还不错,但是第二天呢?数据更新后,您是否每天都手动运行脚本?还有,你的朋友怎么能不用问你就能查看图表呢?
幸运的是,有一些工具可以让这项任务变得非常简单。首先, GitHub Pages 允许你创建自己的网站,在那里你可以托管你令人惊叹的新情节(并与世界分享它们)。)其次, Apache Airflow 允许您调度和自动化流程并执行任务。它是基于 Python 的,但是它处理不同种类的任务(比如运行 C++或 Bash 脚本。)
我们开始吧!
加载、清理和转换数据
让我们以约翰·霍普金斯大学系统科学与工程中心提供的广泛使用的CSSE·新冠肺炎数据集为例,来进行我们的可视化。我们旅程的第一步是加载数据集并(像往常一样)对它们进行一些清理:我们只需更改 State 和 Country 列名,按国家对州进行分组并对值求和。
这很容易,主要归功于组织良好的原始数据集。
现在我们必须选择我们想要显示的内容。为了这篇文章,我决定在金融时报上复制这张漂亮的图表。该图根据每个国家首次通过 x 平均死亡人数的天数显示了每个国家的新冠肺炎死亡人数趋势。为此,我们需要计算相关时间序列的滚动平均值。下面的代码完成了这个任务:
原始数据集提供每天的病例总数,因此我们需要首先通过调用.diff()
来计算每天的病例数(还要注意,我们将只显示前 10 个国家;)然后,我们计算每列的滚动平均值。通过重置索引并连接滚动的列,我们能够将索引称为从我们第一次计算n_since
值开始的 x 天的数量。当调用rolling(n_since=3)[1].head()
(死亡)时,您应该会看到这样的内容:
散景可视化
熊猫.plot()
将很快显示图表,但这种类型的情节值得更多的风格。在这些选项中,散景是最简单和最有特色的选择之一。我不打算进一步解释这个库的功能,因为有许多资源,而只是简单地为您提供一个我创建的定制功能(它遵循上面的代码,因此它以滚动数据帧作为输入):
这就是了!
托管到 GitHub
现在是时候让世界看到它了。创建一个 Github 网站非常简单,按照这里的说明就可以完成。基本上,您需要创建一个名为 structure*username . github . io .*的新公共存储库
然后你提交新的散景图,命名为index.html并推它。最后在http://. github . io就能看到了。你可以在这里找到我的:https://hectoramirez . github . io/covid/Daily _ deaths _ Europe . html。
那么,明天 CSSE 数据集更新时会发生什么呢?一种选择是手动运行您的脚本,并将您的情节提交/推送到 GitHub。每天。试着在早上早点做——你的朋友可能想在早餐时检查一下。或者…
借助气流实现 it 自动化
如前所述,Apache Airflow 允许您调度和自动化流程——比如在特定时间运行脚本。更准确地说,
气流用于创建代码管道,我们可以在其中调度和监控我们的工作流。工作流可以是要像流程图一样执行的任务的集合。
设置
有很多学习使用 Airflow 的资源,包括 Airflow 自己的文档,所以我会引导你走向我们的具体目标。让我们从安装 Airflow 开始,这可以通过 pip 工具轻松完成:
$ pip install apache-airflow
如果一切都是正确的,通过运行$ airflow version
,您应该会看到类似这样的内容:
____________ _________________ |__( )_________ __/__ /________ ______ /| |_ /__ ___/_ /_ __ /_ __ \_ | /| / /___ ___ | / _ / _ __/ _ / / /_/ /_ |/ |/ /_/_/ |_/_/ /_/ /_/ /_/ \____/____/|__/ v1.10.9
Airflow 应该已经创建了一个 AIRFLOW_HOME 文件夹,并在其中创建了一个dags
文件夹(如果没有,自己创建。)在主文件夹中,我们调用
$ airflow initdb
以便初始化与工作流相关的数据库。完成后,你会发现包含初始设置的airflow.db
数据库文件和airflow.cfg
文件。最后,我们呼吁
$ airflow webserver
启动气流图形用户界面。转到 https://localhost:8080 ,您应该会看到类似这样的内容:
你现在看到的是一组默认的气流例子(要隐藏它们,去airflow.cfg
文件并设置load_examples=False
)。)注意这些被称为 DAG s:
在 Airflow 中,一个
DAG
——或者一个有向无环图——是你想要运行的所有任务的集合,以一种反映它们的关系和依赖的方式组织。DAG 是在 Python 脚本中定义的,它将 DAG 结构(任务及其依赖项)表示为代码。
也就是说,我们需要编写 Python 脚本,其中包含一系列按照指定顺序执行的任务。它们按照时间表运行,使用 Cron 的语法。
新冠肺炎的例子
回到我们的新冠肺炎追踪器。(这也提供了 DAG 的简单示例;对于更复杂的任务,请参考文档。)
我们需要创建一个 DAG,包含我们想要执行的任务,以保持我们的跟踪器更新:在一个 Python 文件dags/covid_dag.py
中,我们导入基本模块并定义default_args
,如下所示:
from airflow import DAG
from airflow.operators.bash_operator import BashOperator
from airflow.operators.python_operator import PythonOperator
import datetime as dtdefault_args = {
'owner': 'airflow',
'start_date': dt.datetime(2020, 4, 1, 1, 00, 00),
'retries': 1
}
气流操作员允许执行特定类型的任务。例如,我们可以在 DAG 文件中复制/粘贴bokeh_plot
函数,并让PythonOperator
调用它。类似地,您可以在外部脚本中拥有该函数,导入它并用相同的操作符调用它。另一个选择是拥有一个包含所有函数的外部 python 脚本,并让一个BashOperator
为您运行它。这就是我们将要做的。
start_date
设置工作流程执行的时间。可以是过去的某个日期。retries
参数告诉 DAG 应该运行多少次,以防执行不成功。
接下来,我们定义 DAG 参数:
dag = DAG('covid',
default_args=default_args,
schedule_interval='0 1 * * *',
catchup=False
)
第一个参数是 DAG 的名称。schedule_interval
告知执行频率—对于我们的案例,每天在凌晨 1 点执行。为了避免常见的陷阱,需要注意以下几点:
- 正如您在 GUI 的右上角看到的,Airflow 使用 UTC 时间。
- 设置计划时,将开始日期与计划对齐。如果计划在世界协调时凌晨 2 点运行,开始日期也应该在世界协调时凌晨 2 点。
请花些时间阅读这些条目,为你未来的努力节省能量:
- https://CWI ki . Apache . org/confluence/display/air flow/Common+陷阱
- https://airflow.apache.org/docs/stable/scheduler.html
根据schedule_interval
,从开始日期到当前日期,可能有多次执行。catchup
告知当我们打开 DAG 时是否应该执行这些执行。
现在,我们将完整的 load-clean-bokehplot 代码打包到一个covid_func.py
脚本中——当运行时,它应该在脚本所在的同一文件夹中输出散景图;但是,由于我们希望将它托管在您的 GitHub 网站中,您可以通过将输出目录设置为
save(p, ‘YourGithubPageDirectoryPath/index.html’.format(cat))
如上所述,我们只想运行脚本,所以我们可以调用BashOperator
来执行任务。它应该是这样的:
# replace PathToYourFile for the directory pathcommand_t1 = 'python PathToYourFile/covid_func.py 't1 = BashOperator(
task_id = 'covidPlots',
bash_command = command_t1
dag = dag
)
接下来,我们需要提交和推送文件。从终端提交和推送文件需要几个步骤,实际上,多亏了[GitPython](https://gitpython.readthedocs.io/en/stable/)
,它们也可以用 Python 来完成。因此,我决定写一个提交和推送的小脚本,然后用另一个BashOperator
调用它:
from git import Repo
import os
os.chdir(YourGithubPageDirectoryPath)
PATH_OF_GIT_REPO = YourGithubPageDirectoryPath/.git'COMMIT_MESSAGE = 'Daily update'
def git_push():
repo = Repo(PATH_OF_GIT_REPO)
repo.git.add('--all')
repo.index.commit(COMMIT_MESSAGE)
origin = repo.remote(name='origin')
origin.push()
git_push()
这要求git
被正确配置,并且你被允许连接到 GitHub 而不需要在每次访问时提供你的用户名或密码。这是通过 SSH 完成的,详情请查看此链接。
侧注:气流提供了一堆不同的 运算符 。其中之一就是 [*GitOperator*](https://airflow-plugins.readthedocs.io/en/latest/plugins/operators/git.html)
。如果你愿意,你可以自己尝试。
我们现在准备给你的covid_dag.py
添加下一个任务:
command_t2 = 'python PathToYourFile/git_push.py 't2 = BashOperator(
task_id = 'gitPush',
bash_command = command_t2,
dag = dag
)
t3 = BashOperator(
task_id = 'gitPush_repit',
bash_command = command_t2,
dag = dag)
t1 >> t2 >> t3
正如你所看到的,我决定重复这个任务,只是为了确保推的发生——没有危险。
最后,我们用>>
操作符指定任务的顺序。
你的狗现在准备好了!让我们再次调用$ airflow initdb
来设置它并打开气流 GUI——您的新 covid DAG 应该在那里。如果您单击它并转到树形视图,您应该能够看到工作流程:
回到主页,打开它!
这个旅程的最后一步是返回命令行并调用
$ airflow scheduler
你的死刑应该在明天凌晨 1 点执行。
最后一点,您可以随时点击链接栏中的 Trigger Dag,手动执行它并检查它是否工作正常。如果出现任何问题,您应该能够在日志中跟踪错误。
摘要
在这篇文章中,我们采用了广泛使用的 used 新冠肺炎数据集,并为前 10 个国家(死亡人数较多的国家)的每日死亡人数创建了一个高度互动的散景图。然后我们将它提交到 GitHub 页面。
由于数据每天都在更新,所以绘图也应该如此。为此,我们设置了 Apache Airflow,创建了一个新的 DAG,其中包含每天更新数据所需的任务集,并启动了 Airflow 调度程序。
我又创建了几个图表,都放在我的 GitHub 网站上。你可以在这里查看:
欢迎在评论中留下任何想法或问题!
更新(2021): 网页不再维护。完整的代码可以在这个库中找到。
参考
** [## 我喜欢用 Python 进行数据探索的 6 个理由
散景已经存在很多年了,但我只是最近才真正发现它,没多久它就成了我的最爱…
towardsdatascience.com](/6-reasons-i-love-bokeh-for-data-exploration-with-python-a778a2086a95) [## Apache Airflow 入门
在这篇文章中,我将讨论由 Airbnb 开发的工作流管理系统 Apache Airflow。
towardsdatascience.com](/getting-started-with-apache-airflow-df1aa77d7b1b) [## 气流初学者指南
Airflow 用于创建简单和复杂的代码管道,我们可以在其中调度和监控我们的工作流。一个…
medium.com](https://medium.com/zenofai/a-beginners-guide-to-airflow-3572ddd14731) [## 冠状病毒追踪:疫情传播的最新数据|免费阅读
冠状病毒爆发的人类成本持续上升,全球确诊病例超过 207 万例,而…
www.ft.com](https://www.ft.com/coronavirus-latest?fbclid=IwAR2Pi_sryd7x2ZvOt_y0J0_00N5mDQeYLvBc4DfMr6bpninqV75dcxRtEsA)**
你的机器学习工程师不需要博士或硕士学位
要求机器学习/人工智能雇员拥有花哨的学位已经过时了。原因如下。
你的机器学习雇员应该有博士学位吗?在 ML 工作需要博士学位吗?
我总是看到博士和硕士学位被列为 ML 职位描述的要求。我为“机器学习工程师”打开的第一个谷歌工作结果要求:
数据科学、机器学习、统计学、运筹学或相关领域的博士
相关领域理学硕士,拥有 5 年以上将数据科学技术应用于实际商业问题的经验。
对于软件工程师来说,拥有博士甚至硕士学位是一个不寻常的要求。我们不指望从事网络、安全、系统架构或应用开发的开发人员会这样。那么是什么让机器学习如此特别呢?
有些人可能会说 ML 非常复杂和数学化,是科学家的领域,而不是软件开发人员的领域(哎哟!).
我不相信。ML 可能很棘手,但密码学、分布式系统、图形学以及计算机科学中的许多其他主题也是如此。然而,我们并不要求开发人员拥有博士学位来从事这些工作。我认为是别的原因:
我们经常忘记机器学习对我们大多数技术人员来说是很新的东西。就在五年前,我的同事们还在谈论深度学习是一个可疑的赌注。工具很难使用。为 ML 设计的结实的硬件很难得到。模型质量与今天相差甚远。
结果我们大部分人在学校都没学过 ML。五年前,我的母校普林斯顿大学只提供大约 3 毫升/人工智能课程。机器学习绝对不是你典型的计算机科学课程的“标准”部分,你可能不用学习太多就能轻松毕业。网上资源匮乏。然后,当人工智能突然成为新的热点时,许多人冲回硕士课程,以填补他们教育中新的相关空白。
在 ML 人才短缺的情况下,难怪如果你想雇佣一个在这个领域有经验的人,这个人很可能是一个学者。
与此同时,工程师们开始在工作中学习 ML。即使在世界上最大的人工智能博士研究人员雇主之一的谷歌,大量从事人工智能产品的工程师也只有有限的技术经验。他们通过在线资源、内部课程(如谷歌的机器学习速成课程)或通过承担小块项目并边做边学来学习。
五年对于技术来说是漫长的一年,数据科学领域已经发生了变化。如今,在课堂之外学习机器学习比过去容易得多,我们的工具集也变得更加用户友好(参见 PyTorch、TensorFlow 2.0、Keras)。再加上庞大且不断增长的在线资源生态系统,这位有决心的开发人员无需花费一毛钱,就能给自己提供一个丰厚的 ML 教育。
合格的数据科学家/机器学习工程师招聘库也发生了变化。2019 年,数据科学竞赛网站 Kaggle 调查了~4000 名数据科学家。他们发现,虽然 52%的受访者拥有硕士学位,但只有 19%拥有博士学位。与此同时,大多数受访者只有 3-5 年的工作经验,而且年龄偏年轻(25-29 岁)。一大批雄心勃勃、自学成才的数据科学家刚刚进入就业市场。
我们理所当然地认为,自学成才的软件工程师可能非常有才华(谷歌的一名招聘人员最近告诉我,她采访了一名高中生)。科技招聘人员很久以前就知道,如果他们只雇佣麻省理工的毕业生,他们根本不会雇佣任何人。因此,现在我们需要在雇佣数据科学家的方式上进行类似的视角转变。
这也意味着我们需要开始像评估软件工程师一样评估 ML 工作申请人。我们需要花更多的时间来建立有效的面试,让候选人展示他们的技能,而不是专注于证书,无论他们是如何或在哪里学到的。建立雇佣 ML 工程师的新标准不是一件容易的事情,但是对于雇主来说,回报是值得的。
我们来连线一下 Twitter 或者insta gram*!*
原载于 2020 年 8 月 26 日 https://daleonai.comT21*。*