TowardsDataScience-博客中文翻译-2020-四十六-
TowardsDataScience 博客中文翻译 2020(四十六)
浓缩咖啡测量:溶解度
用数据看到更大的图景,第 3 部分
咖啡溶解度被证明是使用定性方法区分镜头的最简单和最好的指标。幸运的是,一些团体,如苏格拉底咖啡和复合咖啡已经比较了折光率仪,考虑到它们的成本,这同样重要。这是从苏格拉底咖啡,复合咖啡收集的数据,和我讨论折射仪的数据。这是系列的第三部分,第一部分关注预浸、压力和水温,第二部分关注研磨、分配和捣实。

为了测量溶解度,人们使用折射仪。这可以测量总溶解固体(TDS),如果你有饮料的重量,它可以确定你杯子里有多少咖啡。一旦你知道你的杯子里有多少咖啡,你就可以通过除以输入的咖啡重量来计算提取率(EY)。EY 是你提取的咖啡的百分比。一般来说,30%的咖啡能够被提取出来,而好的浓缩咖啡的提取率大概在 18%到 22%之间。
标准的 VST 数字折射仪价格约为 700 美元,即使是价格更低的也要 300 美元(Atago)。最终,我买了一个 20 美元的白利糖度计,后来,我终于决定买一个更贵的(Atago)。我还收集数据来帮助理解 Atago 的工作情况,以及它与更便宜的工具白利糖度计的比较。
零水
任何折光仪都需要校准,通常使用蒸馏水。 Socratic Coffee 调查了VST 和 Atago 仪表使用蒸馏水和冲泡水的不同之处。
他们发现了与咖啡温度有关的下降趋势,但当比较两米时,似乎没有太大的趋势。

过滤样本
如果我们观察样品是否使用注射器过滤器过滤,未过滤的样品最终具有更高的 TDS。苏格拉底咖啡做了一个很好的调查,在我自己的一个小样本上,我能够看到一个与粗注射器过滤器相似的趋势。

关于滤波的更多数据显示,每个样本中,滤波后的样本具有较低的 TDS。考虑到过滤器的作用,这是有意义的(它过滤掉影响折光仪的较大颗粒)。

当他们又一次观察过滤和未过滤样本之间的差异时,对 ey 也有明显的影响。然而,我不相信一个过滤器是值得的成本或努力。

VST 二/三对阿塔戈
苏格拉底咖啡比较了 VST 折光仪和 Atago ,结果很有趣。首先,VST 二世相对于 VST 三世偏移了一个常数。

他们又看了两个,我们能做的一件事就是把所有的数据结合起来。这样做,有一个明显的趋势之间的阿塔戈和 VST 的意思是,他们在测量能力相当。这两个分布相当大,使用双尾 t 检验,它们的 p 值为 0.9842,这意味着它们是同一个分布。

比较 EY 和 TDS
Socratic Coffee 将他们的大部分数据显示为 TDS,而不是提取产量(EY),值得注意的是,EY 的产量重量略有差异。因此,我根据每次拍摄的预期产量和他们对分发工具的影响所做的一项研究的实际产量来计算 EY。
最明显的区别是,使用 40g 输出的 EY 是对实际 EY 的低估。

我也对 VSTII/III 和 Atago 进行了分析。有一些细微的差别,足以让我停留在 EY 的领域,而不是 TDS。最终,我不认为它对潜在的结论有影响。

白利糖度与数字
复合咖啡对比廉价的白利糖度计看糖分。他们可能不知道白利糖度和 TDS 之间存在直接的转换关系(通常 TDS = 0.85 *白利糖度或白利糖度= 1.176 * TDS)。他们的数据不仅表明了这一点,还表明使用白利糖度计相当于使用 TDS 计。对于他们的数据,方程略有不同(Brix = 1.1367 * TDS + 0.6102),但仍然非常接近。

我做了一项有趣的研究拍摄了大量照片,我用 Atago 测量仪测量了 TDS,用廉价的折射计测量了白利糖度。我发现两者有相似的分布,具有统计学意义,因为我在 1:1,拍摄的后半部分收集,然后计算 3:1 比率标记的最终 TDS。

这些折光仪的数据非常令人兴奋,因为这有助于证明为家庭咖啡师购买廉价折光仪的合理性。目前,折光仪是量化和区分一杯浓缩咖啡的主要工具,通常只由专业咖啡师使用。
我希望考虑使用白利糖度计的人可以买一个便宜的白利糖度计,看看这个信息是否对他们的日常生活有帮助,然后再花几百美元。
如果你愿意,请在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。
我的进一步阅读:
浓缩咖啡参数:预浸、压力和水温
用其他数据看到更大的画面,第 1 部分
在收集了一年多浓缩咖啡的数据后,我感觉自己像一座孤岛。很少有人像我一样在 espresso 上收集数据,espresso 社区几乎没有数据分析。如果它确实存在,它隐藏在付费墙后面,对外界没有太多的指示。总的来说,实验都是单一样本或者忽略了对某些参数的控制,这就是为什么我印象深刻地发现了复合咖啡、苏格拉底咖啡和五感咖啡。当然,学术研究是有的,但它通常不涵盖像压力和温度这样的基本问题,而这些问题在研究领域之外是可以获得的。


关键数据,以防你想跳过其他的。
复合咖啡有过各种各样的实验,但我从未听说过。我很惊讶他们没有更出名或被更多引用,但我怀疑这是因为他们收集的数据都放在表格中,人们很难看到清晰的图片(他们没有用图表显示他们的发现)。Fives Senses Coffee 只有一个我感兴趣的研究,Socratic Coffee 有表格和图表(他们的数据包含在第 2 和第 3 部分中)用于各种实验。
在这项工作中,我将检查与预浸、水温和压力相关的数据,因为它们会影响提取。假设是更高的提取与更好的味道相关,我的数据表明,假设相同的输出量。
我的理解是,大多数人认为最好的办法是在水温为 94 摄氏度、压力为 9 巴的情况下,几乎不预注入水。很好奇数据是怎么说的。
复合咖啡
我挖掘了他们的数据,并写了一些分析,以帮助向世界展示他们的结果。他们的实验得到了很好的控制和很好的记录,但是他们的分析有两个错误:
- 没有图形表示。
- 统计学意义的 p 值误用。
我可以用一些有趣的情节来解决第一个问题,但第二个问题可以让任何人陷入统计上的困境。
统计显著性可以表示为使用 t 检验拒绝零假设。零假设是数据的两个分布样本来自同一个总体分布。如果您有超过 30 个样本,您可以进行 t 检验,以确定分布是否在统计上不同,这意味着检验的 p 值小于 0.05。一个更强的测试是配对 t 测试,其中有成对的数据点。
Compound Coffee 将 t-test 应用于他们的数据,他们所有的测试都只有不到 30 个样本。通常,他们有 10 个样本,他们使用 p 值来确定一种技术是否优于另一种技术。这并不意味着一种技术不是,但他们不能用 p 值来看。我喜欢看数据,我的经验是,通过找到合适的情节,结论(如果有的话)对不熟悉的人来说应该是显而易见的。
在看他们的数据时,我看过未排序和排序的。我对数据进行分类是因为每个样本不应该与前一个相关,所以公平的比较是最好的与最好的比较,第二好的与第二好的比较,…以及最差的与最差的比较。
9 巴提取前的预注入
他们在 9 巴提取压力前查看了预注入,发现预注入无助于提取产量(数据见附录 A)。然而,从他们的表格中很难看出这一点。我绘制原始数据,然后进行排序,在第一组数据中,我使用了与基线样本的直接比较。

这是所有排序后的样本。9 巴是明显的赢家,但有趣的是,30 秒的预输注具有更一致的结果(各次注射之间的差异更小)。似乎提取的可变性随着预灌输的增加而降低。

同样,这些结果不可能有统计学意义,因为它们是欠采样的,但它们仍然是有趣的。
注射压力
复合咖啡研究了在提取过程中改变机器压力的,他们发现 7 到 8 巴是最佳的(数据在附录 B 中)而不是 9 巴。然而,当他们没有足够的样本时,他们声称有统计学意义。

所有样本都已分类排列好。

数据排序后,我看到的情况是,7 巴的提取略好于 8 巴。从这个图表中可以清楚地看出,9 巴不是更高萃取的最佳压力。
所以我们只比较 8 小节和 7 小节:

图上的一个点看起来像异常值,但除此之外,7 根棒线看起来稍微好一点。尽管如此,我们不知道它是否有统计学意义,因为我们没有足够的样本值。
7 巴提取前的预注入
Compound Coffee 随后对预浸进行了测试,使用 7 根萃取棒而不是 9 根萃取棒,考虑到基于之前的结果,7 根萃取棒似乎比 9 根萃取棒产生更高的萃取率。下面是排序值和控制样本之间的比较。

较高的预浸渍产生高得多的提取,即使对于较低的分布也是如此。对于较高的预输注时间,注射之间的可变性比在 9 巴提取时稍高,这给较高的预输注与较低的提取可变性相关的概念带来不确定性。
另一方面,这个结论看起来很清楚,但是同样,这些结果应该放在可行性的背景下,而不是统计证明的确定性。这些结果符合我对更长时间预输注的经验,但我还没有足够控制我的变量来表明更长时间的预输注总是更好。

水温
复合咖啡查看了冲泡时的水温,他们想知道它是如何影响提取的(附录 D)。他们扫描了 91C 到 95C,数据显示 95C 比 91C 好。下面是与 91C 的比较,更高的温度似乎做得更好。

以下是所有经过分类的样本,再次显示 95C 的提取率更高,但这一趋势并不总是成立。方差有点高,无法得出可靠的结论。较高的温度只是提供了更一致的提取,因为它的范围比其他温度小得多。一个可靠的结论是,91C 不能保证提供最高的提取率。

五感咖啡研究了水温,温度高一些,样本少一些。他们没有足够的数据来证明统计意义,但似乎高于 92 摄氏度的温度是更可取的。

我很想看到这些实验在不同的烘烤中进行更深入的研究,收集更多的样本。这些数据表明了以下结论,但需要更多的数据:
- 对于提取来说,7 巴比 9 巴好。
- 15 秒或更长时间的预浸,然后是 7 巴萃取,提供了更高的咖啡萃取率。
- 水温在 95C 左右或更高更好。
浓缩咖啡领域已经爆炸了,但它仍然缺乏一种数据驱动的方法,这种方法在其他研究领域非常有用。我希望重新审视这些数据能帮助人们踏上自己的旅程,发现这些群体的亮点,并激励其他人使用数据来推动创新。
第 2 部分将涵盖研磨、分配和夯实。第 3 部分将介绍咖啡提取工具。
如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。
我的进一步阅读:
被盗浓缩咖啡机的故事
附录 A

附录 B

附录 C

附录 D

浓缩咖啡的制备:研磨、分配和捣实
用其他数据看到更大的画面第 2 部分
之前,我们通过几个数据源查看了预注入、压力和温度,以了解什么提供了最佳提取。现在,让我们看看研磨、分配和捣固。
使用的主要指标是提取率(EY)或总溶解固体(TDS)。使用 TDS、输出重量和输入重量计算 EY。它们与口味关系不大,能够达到更高的 ey 或 TDS,因此目标是更高的 TDS 或 EY。
研磨机刀片锋利度
Socratic Coffee 研究了毛刺锐度与保水性的关系,分类后的数据在提取方面没有显示出太大的差异。我很好奇,如果使用多个研磨设置或豆会提供一个更清晰的图片。

他们继续研究提取率,分类成对比较的数据和线形图显示,刀片越锋利,提取率越高。更锋利的刀片最有可能影响研磨分布,但他们没有进一步深入这些实验。

研磨速度
苏格拉底式咖啡还研究了研磨机的速度以及它如何影响咖啡渣的分布。然而,在最初的图表中,他们没有显示每次烘烤的所有速度,只有一个图表。我拆分了他们的数据,你可以看到中间部分受 500 RPM 的影响最大,所以我放大了那部分数据。很难在看不到味道或 TDS 效果的情况下显示分布,但拍摄一致性的关键是保持 RPM 一致。

圆盘准备中的顶部空间
苏格拉底咖啡在顶空做了一个小研究用 20g 的篮子和 22g 的篮子。他们在最初的演示文稿中使用了方框图,但由于样本数量较少,我认为最好绘制出排序后的样本。箱形图非常适合汇总数据,但是当分布不是高斯分布时,很难理解箱形图。非高斯分布的最佳提示是中值偏离平均值。理想情况下,它们应该居中,如果不居中,不均匀的分布可能表明采样规模太小。
所以我用他们的箱线图估算了他们的原始数据,给出了最小值、最大值、中值、25%和 75%的界限。对于十个样本,该信息立即给出样本 1、3、7 和 10。其余的是点之间的插值,考虑到中值是样本 5 和 6 的平均值。
结果没有显示出明显的差异,苏格拉底咖啡或其他人也没有做过进一步的实验。

过滤篮
苏格拉底式咖啡看了几次过滤篮。首先,他们查看了仿制药与 VST & IMS ,然后是仿制药与 IMS ,然后是一个跨越四个篮子的更大样本:仿制药、佩萨多、铂尔曼和 VST。Pesado 属于 IMS 类别。所有这些数据最初都是箱线图格式的,我根据箱线图参数估计了原始样本。

最左边的奇数样本是由于 IMS 数据中的低 EY 异常值和一般数据中的高 EY 异常值。
总的来说,似乎使用任何精确的篮子都比通用的要好。但是如果我们把所有这些数据结合起来会怎么样呢?对比一下怎么样?对 VST 来说,结果显示它们导致更高的提取率。对于普尔曼过滤器,就不那么清楚了。对于佩萨多,似乎有所增加,但不清楚它是否比 VST 更好。

与 VST 相比,铂尔曼和佩萨多的表现稍差,但统计意义尚不明确。一个更大范围的烘烤对比肯定会很有趣,因为即使是一次烘烤也不能保证讲述整个故事。我想知道是否有些过滤器对某些研磨分布或烘焙水平更好,而对其他的则不是。我再次注意到数据的缺乏,能有这样的数据真是太好了。

咖啡分销
多年来,许多人试图使用不同的技术或工具来改善咖啡的分配。在复合咖啡和苏格拉底咖啡之间,有一些有趣的数据表明大多数经销商弊大于利。
强迫症工具
强迫症工具似乎是高质量咖啡师的必备工具,但数据显示并非如此。我甚至买了一个,但是我已经改用一个弯曲的回形针了。苏格拉底咖啡研究了 OCD 工具与在三台研磨机上敲击 portafilter 的对比。研磨机显然不那么重要,但拍摄时间似乎变化很大。

如果我们取所有的样本,我们实际上每个样本有 30 个样本,现在直接进行有意义结果的两两配对 t 检验,我们得到 p = 8.1384e-11,这意味着两者之间的差异在统计上有意义(p < 0.05 is statistically significant).

OCD2 & BT Tool
They then went to look at two more: the BT and OCD2 distribution tools. Both of which don’t perform well against the control sample.

Bonus Data: Grinder Comparison
Inside this data for OCD tools, they used three different grinders. So we could also do a grinder comparison. I looked at the data with and without sorting. Either way, the K30 looks like a better grinder in this experiment, but there was not an analysis on the grind distribution for this grind setting. It is not clear that each grinder was best dialed in; I would like to assume so, but I can’t be certain. This points to the difficulty of running espresso experiments and controlling all the variables.

Tapping, NSEW, Stockfleth, and OCD
Compound Coffee 比较了四种分布方法,但他们将数据转储到一个没有图表的表格中。我在这里用两种方式想象它们。两者都表明答案不明确,但 Stockfleth 方法似乎更好一点。强迫症工具并不是一个明显的赢家,但它不像在苏格拉底咖啡实验中那样糟糕。

手指、1–8–0 浅、1–8–0 深和捻线分布技术
复合咖啡做了第二批分销商,但他们都没能做得比好的奥莱手指分销更好。

总体印象
分发工具似乎没什么帮助,但不清楚为什么。我只是怀疑,因为大多数只影响冰球的上半部分。我本以为 Twister 工具会做得更好,但事实并非如此。
篡改者!
夯实压力
苏格拉底式咖啡研究了萃取时的夯实压力,结果与许多人声称的正确夯实压力背道而驰。这一数据只表明没有一个明确的趋势。唯一有意思的是,10 磅夯锤的提取时间比其他夯锤略低,但只要提取正常,这并不重要。否则,似乎需要稍大于夯锤重量的低夯压。

篡改类型
苏格拉底咖啡看了很多捣棒,LM、Easy、Pullman(Pullman 的简称)看起来都很相似。有人可能会说 Perg 和 Pull 捣棒更好,但没有足够的证据来证明这一点。

复合咖啡也看了 LM,Pergtamp,和 Levy 。他们的结果似乎有一个更大的不同,那就是 T4 和征税。

因此, Compound Coffee 进一步测试了两者之间的正面交锋,Pergtamp 显然是赢家。我甚至将两个数据集结合起来,进行了 t 检验。抽样只有 25 个样本,并且它具有 0.0178 的低 p 值,这表明对于这些样本,存在统计上显著的差异。

体积与手动
咖啡师 Hustle 做了一个比较,一个咖啡师(Jamie)根据体重停止一杯咖啡,另一个让机器在特定的音量停止一杯咖啡。这是一场机器对人类的测试,虽然一系列结果显示机器赢了,但仍然有太多的混合。这台机器肯定更加稳定,但这并不意味着一个熟练的咖啡师不能拍出令人惊叹的照片。

这些都是有趣的实验来绘制和分析。我真的很喜欢查看数据集,特别是考虑到这些数据集很小,而且不知道咖啡烘焙或咖啡豆如何影响结果。然而,我们可以从这些数据中得出一些有趣的想法:
- 保持你的刀刃锋利。
- OCD 分发工具并没有真正的帮助。
- Stockfleth 方法非常有用。
- 不需要用力夯实。
- 并非所有的篡改者都是生来平等的;Pergtamp 或类似产品将优于其他篡改工具。
- 如果您希望能够像自动机器一样拍摄出相似一致性的照片,请使用标尺。
我希望这些数据的收集能够帮助人们了解或者更好地激励人们收集数据。本系列的下一篇文章将讨论 TDS 测量工具。
如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。
我的进一步阅读:
克鲁夫筛:一项分析
熊猫数据准备的基本命令

熊猫“小抄”争夺数据
如果你喜欢烹饪,你会非常了解这一点。打开炉子烹饪食物是整个烹饪过程中很小的一部分。你的大部分汗水和泪水实际上都花在了准备正确的配料上。
老生常谈,但值得再说一遍——数据准备是任何数据科学项目中 80%的工作。无论是制作仪表板、简单的统计分析,还是拟合高级机器学习模型,都是从找到数据并将其转换为正确的格式开始,这样算法就可以处理其余的事情。
如果你是 Python 爱好者,那么pandas就是你数据科学之旅中最好的朋友。配备了所有的工具,它可以帮助您完成项目中最困难的部分。
也就是说,像任何新工具一样,你首先需要了解它的功能以及如何使用它们。许多数据科学的初学者仍然很难充分利用 Pandas,而是将大量时间花在堆栈溢出上。我认为,这主要是因为无法将 Pandas 的功能与其分析需求相匹配。
只要列出典型的数据准备问题清单,并为它们配备合适的 Pandas 工具,就可以解决大部分问题。下面,我将介绍一个典型的数据准备和探索性分析工作流程,以及必要的 Pandas 功能。我并不是要记录下世界上所有关于熊猫的事情,而是演示创建你自己的数据争论备忘单的过程。
建立
启动您最喜欢的 Python IDE 后,您可能想马上开始并导入必要的库。这很好,但是您仍然需要设置您的环境来设置工作目录、定位数据和其他文件等。
# find out your current directory
import os
os.getcwd()# if you want to set a different working directory
os.chdir("folder-path")# to get a list of all files in the directory
os.listdir()
数据导入
接下来是数据导入,这是你第一次使用熊猫。
您的数据可能位于世界上的任何地方—您的本地机器、SQL 数据库、云中甚至在线数据库中。数据可以保存为各种格式— csv、txt、excel、sav 等。
根据数据的来源和文件扩展名,您需要不同的 Pandas 命令。下面是几个例子。
# import pandas and numpy libraries
import pandas as pd
import numpy as np# import a csv file from local machine
df = pd.read_csv("file_path")# import a csv file from an online database
df = pd.read_csv("[https://raw.githubusercontent.com/uiuc-cse/data-fa14/gh-pages/data/iris.csv](https://raw.githubusercontent.com/uiuc-cse/data-fa14/gh-pages/data/iris.csv)")
数据检查
在导入数据后,您想要检查一些东西,如列和行的数量,列名等。
# description of index, entries, columns, data types, memory info
df.info() # check out first few rows
df.head(5) # head# number of columns & rows
df.shape # column names
df.columns # number of unique values of a column
df["sepal_length"].nunique()# show unique values of a column
df["sepal_length"].unique()# number of unique values alltogether
df.columns.nunique()# value counts
df['species'].value_counts()
处理 NA 值
接下来,检查 NA、NaN 或缺失值。一些算法可以处理缺失值,但其他算法要求在将数据投入使用之前处理缺失值。无论如何,检查缺失值并理解如何处理它们是“了解”数据的重要部分。
# show null/NA values per column
df.isnull().sum()# show NA values as % of total observations per column
df.isnull().sum()*100/len(df)# drop all rows containing null
df.dropna()# drop all columns containing null
df.dropna(axis=1)# drop columns with less than 5 NA values
df.dropna(axis=1, thresh=5)# replace all na values with -9999
df.fillna(-9999)# fill na values with NaN
df.fillna(np.NaN)# fill na values with strings
df.fillna("data missing")# fill missing values with mean column values
df.fillna(df.mean())# replace na values of specific columns with mean value
df["columnName"] = df["columnName"].fillna(df["columnName"].mean())# interpolation of missing values (useful in time-series)
df["columnName"].interpolate()
列操作
通常情况下,您可能需要执行各种列操作,例如重命名或删除列、对列值进行排序、创建新的计算列等。
# select a column
df["sepal_length"]# select multiple columns and create a new dataframe X
X = df[["sepal_length", "sepal_width", "species"]]# select a column by column number
df.iloc[:, [1,3,4]]# drop a column from dataframe X
X = X.drop("sepalL", axis=1)# save all columns to a list
df.columns.tolist()# Rename columns
df.rename(columns={"old colum1": "new column1", "old column2": "new column2"})# sorting values by column "sepalW" in ascending order
df.sort_values(by = "sepal_width", ascending = True)# add new calculated column
df['newcol'] = df["sepal_length"]*2# create a conditional calculated column
df['newcol'] = ["short" if i<3 else "long" for i in df["sepal_width"]]
行操作(排序、过滤、切片)
到上一节为止,您已经清理了大部分数据,但数据准备的另一个重要部分是切片和过滤数据,以进入下一轮分析管道。
# select rows 3 to 10
df.iloc[3:10,]# select rows 3 to 49 and columns 1 to 3
df.iloc[3:50, 1:4]# randomly select 10 rows
df.sample(10)# find rows with specific strings
df[df["species"].isin(["Iris-setosa"])]# conditional filtering
df[df.sepal_length >= 5]# filtering rows with multiple values e.g. 0.2, 0.3
df[df["petal_width"].isin([0.2, 0.3])]# multi-conditional filtering
df[(df.petal_length > 1) & (df.species=="Iris-setosa") | (df.sepal_width < 3)]# drop rows
df.drop(df.index[1]) # 1 is row index to be deleted
分组
最后但同样重要的是,您通常需要按不同的类别对数据进行分组——这在探索性数据分析和深入了解分类变量时尤其有用。
# data grouped by column "species"
X = df.groupby("species")# return mean values of a column ("sepal_length" ) grouped by "species" column
df.groupby("spp")["sepal_length"].mean()# return mean values of ALL columns grouped by "species" category
df.groupby("species").mean()# get counts in different categories
df.groupby("spp").nunique()
摘要
这篇文章的目的是展示一些必要的 Pandas 函数,这些函数用于数据分析。在这次演示中,我遵循了一个典型的分析过程,而不是以随机的方式显示代码,这将允许数据科学家在项目中以正确的顺序找到正确的工具。当然,我不打算展示处理数据准备中的每个问题所需的每个代码,而是展示如何创建一个基本的 Pandas cheatsheet。
希望这有用。如果你喜欢这篇文章,请在 Twitter 上关注我。
无人谈论的基本数据科学技能。
老式的工程技能是你促进数据科学事业所需要的
谷歌“一个数据科学家的必备技能”。顶部结果是一长串技术术语,命名为硬技能。Python、代数、统计和 SQL 是最受欢迎的一些。后来,出现了软技能——沟通、商业头脑、团队合作精神等。
让我们假设你是一个拥有以上所有能力的超人。你从五岁开始编码,你是一个围棋大师,你的会议论文肯定会获得最佳论文奖。你知道吗?您的项目仍有很大的机会努力达到成熟,并成为成熟的商业产品。
最近的研究估计,超过 85%的数据科学项目无法进入生产阶段。这些研究为失败提供了许多原因。而且我也没有看到所谓的必备技能作为潜在原因被提及过一次。
我是不是在说上面的技巧不重要?当然,我不是。软硬技能都至关重要。关键是它们是必要的,但还不够。此外,它们很受欢迎,出现在每次谷歌搜索中。所以机会是你已经知道你是否需要提高你的数学水平或者团队合作。
我想说的是和流行的软硬技能互补的技能。我称之为工程技能。它们对于用真实的客户构建真实的产品特别有用。遗憾的是,数据科学家很少学习工程技能。它们伴随着经验而来。大多数初级数据科学家缺乏这些。
工程技能与数据工程领域无关。我用工程技能这个术语来区分它们和纯粹的科学或研究技能。根据剑桥词典, 工程 是运用科学原理设计和建造机器、结构和其他物品。在本文中,工程是将科学转化为产品的促成因素。如果没有适当的工程,模型将继续在预定义的数据集上运行。但是他们永远不会接触到真正的顾客。
外卖:
重要但经常被忽视的技能是:
- 简单。确保你的代码和模型简单,但不要过于简单化。
- 鲁棒性。你的假设是错误的。喘口气,继续编码。
- 模块化。分而治之。深入挖掘最小的问题,然后找到一个开源解决它。
- 水果采摘。不要只关注那些唾手可得的果实。但是要确保你总是有东西可以挑选。
简单

图片来源:shutterstock
"没有必要,实体不应相乘 " —奥卡姆的威廉。“简单是最高级的复杂”—莱昂纳多·达芬奇。一切都应该尽可能简单,但不要简单到极点。“这是我的座右铭之一——专注和简单”——史蒂夫·乔布斯。
我本可以用一整页的篇幅来引用关于简洁的内容。研究人员、设计师、工程师、哲学家和作家都称赞简约,并表示简约有其自身的价值。他们的理由变了,但结论是一样的。你达到完美不是因为没有什么可以添加,而是因为没有什么可以去除。
软件工程师绝对意识到简单的价值。关于如何让软件变得更简单,有很多书籍和文章。我记得接吻原则——保持简单,笨蛋——甚至在我的一门本科课程中也教过。简单的软件维护起来更便宜,更容易修改,也不容易出现 bug。对此有广泛的共识。
在数据科学中,情况非常不同。有很多文章,例如,Kristian Bondo Hansen 的《简单的优点:算法交易中的 ML 模型》或者 Alfredo Gemma 的《简单在数据科学革命中的作用》。但它们是例外,而不是规律。数据科学家的主流往好里说不在乎,往坏里说更喜欢复杂的解决方案。
在继续解释为什么数据科学家通常不关心,为什么他们应该关心,以及如何处理之前,让我们看看简单意味着什么。根据剑桥词典的解释,是容易理解或做的品质,是朴素的品质,没有不必要或多余的东西或装饰。
我发现定义简单最直观的方式是通过否定,作为复杂的反义词。根据同一字典,复杂性是由许多相互连接的部分或元素组成的;错综复杂。虽然我们不能总是说某事简单,但我们通常可以说某事复杂。我们可以力求不复杂,不创造复杂的解决方案。
在数据科学中寻求简单的原因与在所有工程学科中的原因是一样的。更简单的解决方案要便宜得多。现实生活中的产品不是 Kaggle 比赛。需求是不断修改的。当一个复杂的解决方案需要适应新的条件时,它很快就变成了维护的噩梦。
很容易理解为什么数据科学家,尤其是应届毕业生,更喜欢复杂的解决方案。他们刚从学院回来。他们已经完成了论文,甚至可能发表了论文。一个学术出版物是由准确性、数学优雅性、新颖性、方法论来评判的,但很少由实用性和简单性来评判。
一个复杂的想法,提高 0.5%的准确率,对任何一个学生来说都是巨大的成功。对于数据科学家来说,同样的想法是失败的。即使它的理论是合理的,它也可能隐藏着被证明是错误的潜在假设。在任何情况下,增量改进几乎不值得复杂性的代价。
那么,如果你、你的老板、你的同事或你的下属喜欢复杂和“最优”的解决方案,该怎么办呢?如果是你的老板,你很可能在劫难逃,你最好开始找份新工作。在其他情况下,保持简单,愚蠢。
稳健性

图片来源:shutterstock
俄罗斯文化中有一个概念叫做“avos”。维基百科将其描述为“盲目相信天意,指望纯粹的运气”。“Avos”是卡车司机超载决定的幕后黑手。它隐藏在任何不可靠的解决方案后面。
什么是稳健性?或者具体来说,数据科学中的鲁棒性是什么?与我们的讨论最相关的定义是“算法的健壮性是它对假设模型和现实之间的差异的敏感性”,来自 Mariano Scain 论文。对现实不正确的假设是数据科学家问题的主要来源。他们也是上面卡车司机的问题来源。
细心的读者可能会说,鲁棒性也是算法在执行过程中处理错误的能力。他们可能是对的。但它与我们的讨论不太相关。这是一个技术问题,有明确的解决方案。
在前大数据时代和前深度时代,构建强大系统的必要性显而易见。功能和算法设计是手动的。测试通常在成百上千个例子上进行。即使是最聪明的算法创造者也从未假设他们能想到所有可能的用例。
大数据时代是否改变了鲁棒性的本质?我们为什么要关心我们是否可以使用代表所有可想象场景的数百万数据样本来设计、训练和测试我们的模型呢?
它指出,鲁棒性仍然是一个重要的和未解决的问题。每年顶级期刊都会通过发表关于算法鲁棒性的论文来证明这一点,例如,“提高深度神经网络的鲁棒性”和“基于模型的鲁棒深度学习”。数据的数量并没有转化为质量。用于培训的大量信息并不意味着我们可以涵盖所有用例。
而如果人参与其中,现实总是出乎意料,难以想象的。我们大多数人都不知道午餐吃什么,更不用说明天了。数据很难帮助预测人类行为。
那么,怎样做才能使你的模型更健壮呢?第一种选择是阅读适当的论文并实施他们的想法。这很好。但是这些论文并不总是通用的。通常,你不能把一个想法从一个领域复制到另一个领域。
我想介绍三种常规做法。遵循实践并不能保证健壮的模型,但是它显著地减少了脆弱解决方案的机会。
性能安全裕度。安全裕度是任何工程的基础。为了安全起见,通常的做法是获取需求并增加 20–30%。一个能装 1000kg 的电梯,会轻松装 1300kg。而且测试的是能装 1300kg 而不是 1000kg。工程师为意外情况做准备。
数据科学中的安全边际相当于什么?我认为是 KPI 或成功标准。即使发生了意想不到的事情,你依然会在门槛之上。
这种实践的重要结果是你将停止追逐增量改进。如果你的模型增加了 1%的 KPI,你就不可能稳健。在所有的统计显著性测试中,环境的任何微小变化都会扼杀你的努力。
过度测试。忘记单一测试/培训/验证部门。你必须在所有可能的组合中交叉验证你的模型。你有不同的用户吗?按照用户 ID 划分,做几十遍。您的数据会随着时间的推移而改变吗?根据时间戳划分,并确保每天在验证组中出现一次。用随机值或在数据点之间交换某些特征的值来“垃圾”您的数据。然后对脏数据进行测试。
我发现假设我的模型有错误是非常有用的,直到被证明不是这样。
关于数据科学和 ML 测试的两个有趣来源——Alex Gude 的博客和“用 Python 进行机器学习,一种测试驱动的方法”。
不要把城堡建在沙滩上。减少对其他未测试组件的依赖。永远不要在另一个高风险和未经验证的组件之上构建您的模型。哪怕那个组件的开发者信誓旦旦说什么都不会发生。
模块性

图片来源:快门股票
模块化设计是所有现代科学的基本原则。这是分析方法的直接结果。分析方法是一个将大问题分解成小问题的过程。分析方法是科学革命的基石。
你的问题越小越好。这里的“更好”并不意味着拥有它是件好事。这是必须的。这会节省大量的时间、精力和金钱。当一个问题很小,定义明确,并且没有大量假设时,解决方案是准确的,并且易于测试。
大多数数据科学家都熟悉软件设计环境中的模块化。但是,即使是最好的程序员,他们的 python 代码非常清晰,也常常无法将模块化应用于数据科学本身。
失败是很容易证明的。模块化设计需要一种方法将几个较小的模型组合成一个大模型。不存在这样的机器学习方法。
但是有一些实用的指导方针我觉得很有用:
- 迁移学习。迁移学习简化了现有解决方案的使用。你可以把它想成把你的问题分成两部分。第一部分创建低维特征表示。第二部分直接优化相关 KPI。
- 开源。尽可能使用现成的开源解决方案。根据定义,它使您的代码模块化。
- 忘了被优化。从头开始构建一个针对您的需求而优化的系统,而不是修改现有的解决方案,这是很有诱惑力的。但是只有当你能证明你的系统明显优于现有系统时,它才是合理的。
- 模型组合。不要害怕采取几种不同的方法,把它们扔进一个锅里。这是因为大多数卡格尔比赛都赢了。
- 划分你的数据。不要试图创造“一个伟大的模式”,虽然从理论上讲,这是可能的。例如,如果你处理预测客户行为,不要为一个全新的客户和已经使用你的服务一年的人建立相同的模型。
查看组合深度学习了解更多关于深度学习构建模块的细节。阅读修剪过的神经网络惊人地模块化以获得科学证明。
采果

图片来源:shutterstock
产品经理和数据科学家之间的关系一直很紧张。产品经理希望数据科学家专注于唾手可得的成果。他们的逻辑很清楚。他们说企业只关心水果的数量和它们生长的地方。水果越多,我们做得越好。他们加入了各种流行词汇——帕累托、MVP、最好是最好的敌人等等。
另一方面,数据科学家指出,挂在低处的水果容易腐烂,味道也不好。换句话说,解决简单的问题影响有限,而且治标不治本。通常,这是学习新技术的借口,但通常他们是对的。
就我个人而言,我在两种观点之间徘徊。在阅读了 P. Thiel 的《零比一》之后,我确信那些低挂的果实是在浪费时间。在初创企业呆了近 7 年后,我确信创造一个容易实现的 MVP 是正确的第一步。
最近,我开发了自己的方法,将这两个极端统一起来。数据科学家的典型环境是一个动态而怪异的世界,树木向四面八方生长。这些树一直在变换方向。它们可以倒着或横着生长。
最好的果实确实在顶端。但是如果我们花太多时间搭丨梯丨子,树就会移动。因此,最好的办法是瞄准顶部,但要不断监控顶部在哪里。
从隐喻到实践,在漫长的发展过程中,事情总有可能会发生变化。原来的问题将变得无关紧要,新的数据源将出现,原来的假设将被证明是错误的,KPI 将被取代,等等。
瞄准顶端是很好的,但是记住在每隔几个月推出一个工作产品的时候也要这么做。该产品可能不会带来最好的水果,但你会更好地了解水果是如何生长的。
Python 和 R 之间翻译的基本指南
使用 Python 或 R 知识有效学习另一种语言的简单方法。

作为一个以英语为母语的人,当我小时候开始学习西班牙语时,三个关键的练习帮助我从笨拙地试图将我的英语单词翻译成西班牙语,到直接用西班牙语思考和回应(偶尔甚至做梦)。
- 把新的西班牙语单词和我已经知道的英语单词联系起来。对比西班牙语和英语单词使我能很快理解新单词的意思。
- 多次重复这个词,并在许多不同的场景中使用它,让这些词在我脑海中反复出现。
- 利用上下文的线索让我更好地理解了这个词是如何以及为什么要用在它的同义词上。
当你第一次学习编码时,重复和语境化是必不可少的。通过不断的重复,你开始记忆词汇和语法。当您开始看到在不同的上下文环境中使用的代码时,通常通过项目开发,您能够理解不同的功能和技术是如何以及为什么被使用的。但是,不一定有一种简单的方法可以将新的思维方式与您所说的语言联系起来,这意味着您不仅仅是记住一个单词,而是必须对每个编程概念形成新的理解。甚至你写的第一行代码,打印(“Hello World!”)需要你学习 print 函数的工作原理,编辑器如何返回 print 语句,以及何时使用引号。当你学习第二种编程语言时,你可以将概念从你所知道的语言翻译到新的语言中,从而更有效、更快速地学习。
数据科学领域分为 Python 拥护者和 R 爱好者。但是,任何已经学习了其中一种语言的人都应该利用他们的优势,一头扎进另一种语言中,而不是宣布支持哪一方。Python 和 R 之间有无限的相似之处,有了这两种语言,您可以用最好的方式解决挑战,而不是把自己限制在工具棚的一半。下面是连接 R 和 Python 的简单指南,便于两者之间的转换。通过建立这些联系,反复与新语言交互,并与项目联系起来,任何懂 Python 或 R 的人都可以很快开始用另一种语言编程。
基础知识
将 Python 和 R 放在一起看,你会发现它们的功能和外观非常相似,只有语法上的细微差别。
数据类型
# Python # R
type() class()
type(5) #int class(5) #numeric
type(5.5) #float class(5.5) #numeric
type('Hello') #string class('Hello') #character
type(True) #bool class(True) #logical
分配变量
# Python # R
a = 5 a <- 5
导入包
# Python # R
pip install packagename install.packages(packagename)import packagename library(packagename)
数学:是一样的——数学在所有语言中都是一样的!
# Python # R
+ - / * + - / *# The same goes for logical operators
< #less than < #less than
> #greater than > #greater than
<= #less than or equal to <= #less than or equal to
== #is equal to == #is equal to
!= #is not equal to != #is not equal to
& #and & #and
| #or | #or
调用函数
# Python # R
functionname(args, kwargs) functionname(args, kwargs)print("Hello World!") print("Hello World!")
If / Else 语句
# Python # R
if True: if (TRUE) {
print('Hello World!') print('Go to sleep!')
else: } else {
print('Not true!') print('Not true!')
}
列表和向量:这个有点夸张,但是我发现这个联系很有帮助。
- 在 python 中,列表是任何数据类型的有序项目的可变集合。在 Python 中索引列表从 0 开始,并且不包含。
- 在 R 中,向量是同一类型有序项目的可变集合。索引 R 中的向量从 1 开始,包括 1 和 1。
# Python # R
ls = [1, 'a', 3, False] vc <- c(1, 2, 3, 4)# Python indexing starts at 0, R indexing starts at 1
b = ls[0] b = vc[1]
print(b) #returns 1 print(b) #returns 1c = ls[0:1] c = vc[1:2]
print(c) #returns 1 print(c) #returns 1, 2
对于循环
# Python # R
for i in range(2, 5): for(i in 1:10) {
a = i a <- i }
数据操作
python 和 R 都提供了简单而流畅的数据操作,使它们成为数据科学家的必备工具。这两种语言都配备了能够加载、清理和处理数据帧的包。
- 在 python 中,pandas 是使用 DataFrame 对象加载和操作数据框最常用的库。
- 在 R 中,tidyverse 是一个类似的库,它使用 data.frame 对象实现简单的数据帧操作。
此外,为了简化代码,两种语言都允许多个操作通过管道连接在一起。在 python 中。在 r 中使用%>%管道时,可以用来组合不同的操作。
读取、写入和查看数据
# Python # R
import pandas as pd library(tidyverse) # load and view data
df = pd.read_csv('path.csv') df <- read_csv('path.csv')df.head() head(df)df.sample(100) sample(df, 100)df.describe() summary(df) # write to csv
df.to_csv('exp_path.csv') write_csv(df, 'exp_path.csv')
重命名和添加列
# Python # R
df = df.rename({'a': 'b'}, axis=1) df %>% rename(a = b)df.newcol = [1, 2, 3] df$newcol <- c(1, 2, 3)df['newcol'] = [1, 2, 3] df %>%
mutate(newcol = c(1, 2, 3))
选择和过滤列
# Python # R
df['col1', 'col2'] df %<% select(col1,col2)df.drop('col1') df %<% select(-col1)
筛选行
# Python # R
df.drop_duplicates() df %<% distinct()df[df.col > 3] df %<% filter(col > 3)
排序值
# Python # R
df.sort_values(by='column') arrange(df, column)
汇总数据
# Python
df.groupby('col1')['agg_col').agg(['mean()']).reset_index()# R
df %>%
group_by(col1) %>%
summarize(mean = mean(agg_col, na.rm=TRUE)) %>%
ungroup() #if resetting index
使用过滤器聚合
# Python
df.groupby('col1').filter(lambda x: x.col2.mean() > 10)# R
df %>%
group_by(col1) %>%
filter(mean(col2) >10)
合并数据框
# Python
pd.merge(df1, df2, left_on="df1_col", right_on="df2_col")# R
merge(df1, df2, by.df1="df1_col", by.df2="df2_col")
上面的例子是在 Python 和 r 之间建立思维上的相似性的起点。虽然大多数数据科学家倾向于使用这两种语言中的一种,但是精通这两种语言使您能够利用最适合您需求的工具。
请在下面留下您认为有用的任何相似之处和附加评论。
基于股票市场数据构建机器学习模型的基本准则
在股票市场数据上建立机器学习模型时需要考虑的三件重要事情

图片:Pixabay.com
注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
为股票市场投资建立一个机器学习模型似乎是一个很好的主意。如果这个模式成功了,它会让你变得富有。如果没有,你至少会知道建立一个机器学习模型需要什么。股票市场如此欢迎机器学习的另一个原因是历史数据的可用性。
但是,仅仅因为数据是广泛可用的,并不意味着你可以不加考虑地使用它。事实上,在基于历史基本面股票数据建立机器学习模型时,有三个基本问题需要考虑。忽略它们会使你的模型对现实世界的应用毫无用处。下面,我将讨论在为机器学习处理股市数据时需要遵循的三个基本准则。
在对 2020 年 1 月 1 日的模型进行训练和回溯测试时,我可以使用网飞第四季度的基本面数据吗?不,你不应该——当然,除非你想作弊。
1.不要使用未来的数据进行回溯测试
想象一下,你正在建立一个机器学习模型,它将在每个季度初预测股票的季度表现。这种模型应该为投资者提供准确的指导,例如在 2020 年 1 月 1 日,一只股票在 2020 年 3 月 30 日之前是上涨、下跌还是横盘整理。当建立这样一个模型时,你需要确保你没有使用未来的数据。在我们的例子中,这意味着你的训练集不能包含 2020 年 1 月 1 日及以后的数据。
要使历史股票市场数据变得复杂一点,您还需要考虑数据何时可用。让我们回到我们的例子,看看网飞截至 2020 年 12 月 31 日的第四季度业绩。在对 2020 年 1 月 1 日的模型进行训练和回溯测试时,我可以使用网飞第四季度的基本面数据吗?不,你不应该——当然,除非你想作弊。原因是 2020 年 1 月 21 日公布了 Q4 业绩。这是测试和训练你的模型的截止日期之后的 20 天。因此,在你的模型中使用第四季度的结果意味着你要么有内部消息,要么有一个神奇的水晶球。下面是说明市场数据可用性问题的时间表。

网飞第四季度业绩的公布和归档
对此我能做些什么?如何确保我的模型中没有使用未来的数据?
有三种方法可以解决这个问题。第一个解决方案是使用所谓的即时市场数据。时间点数据会考虑数据何时公开。这确保了当您查看网飞在 2020 年 1 月 1 日的最新收入时,您将获得第三季度的数据,而不是第四季度的数据,因为那时还没有这些数据。大多数主要的付费市场数据提供商都允许您访问这些即时数据。例如,彭博允许您使用他们的 BQL API 检索时间点数据。
如果你无法获得即时市场数据,那么你可以使用滞后市场数据。美国证券交易委员会(SEC)规定,公司必须在前三个季度结束后 35 天内、最后一个季度结束后 60 天内提交收益报告。在我们的示例中,我们可以强制模型使用 2019 年 10 月 16 日发布的第三季度结果。
第三种选择是在 SEC 的 EDGAR 网站【https://www.sec.gov/edgar/searchedgar/companysearch.html的帮助下创建自己的即时市场数据库。EDGAR 网站包括每份年度和季度报告的归档日期信息。多亏了几个很棒的免费 Python 包,可以相对容易地搜集这些信息。

SEC EDGAR 网站上的网飞 10-K 年度报告提交日期信息
然而,使用滞后的市场数据或通过抓取 SEC 的 EDGAR 网站建立自己的时间点数据库,都无法击败专门的时间点数据提供商的准确性。它不考虑重述,滞后数据可能“过于滞后”。即使您精心构建时间点数据库也会包含不准确性。例如,网飞在 2020 年 1 月 21 日发布了第四季度的业绩,但在 8 天后的 2020 年 1 月 29 日提交了报告。但是,如果你没有时间点市场数据提供商,使用滞后数据或建立自己的时间点数据库是下一个最好的选择。
使用静态股票列表进行回溯测试意味着你忽略了所有破产或因其他原因退市的公司。
2.当心不断变化的股票市场,避免生存偏差
每当你为股市投资建立机器学习模型时,你都必须决定要考虑哪些股票。这可以是一个指数,如标准普尔 500 或美国所有公开交易的股票。无论你选择什么样的股票,你都需要意识到它的构成在不断变化。让我们把标准普尔 500 指数作为我们的股票宇宙,我们将使用它作为我们的机器学习模型。标准普尔 500 指数目前包括 505 家公司。2015 年,目前构成标准普尔 500 指数的公司中只有 75%是该指数的一部分。剩下的 25%是因为业绩不佳而被摘牌或者干脆从标准普尔 500 指数中剔除的公司。2010 年,这个数字是 65%,而在 2000 年,只有 45%的标准普尔 500 成份股构成了该指数。

标准普尔 500 指数构成变化
忽视不断变化的股票市场会把你的模型引入所谓的生存偏差。使用静态股票列表进行回溯测试意味着你忽略了所有破产或因其他原因退市的公司。此外,在他们真正成为“赢家”之前,你就在考虑“赢家”。再来看 AMD。2016 年 AMD 股价从 2.10 到 11.30。然后在 2017 年 3 月,AMD 取代 Urban Outfitters 加入了标准普尔 500 指数。因此,在 2016 年你的标准普尔 500 宇宙中有 AMD 会被认为是作弊。
解决这个问题的方法很简单。不要在你的股票市场中使用静态的股票列表。确保你对每个时期进行调整,以反映任何给定时间点的真实成分。
3.使用调整后的价格
在为机器学习处理股市数据时,要考虑的最后一件重要事情很简单。使用调整后的股票价格。对于有经验的甚至是新手的股票交易者来说,这似乎是显而易见的。但对于没有股市经验的数据科学家来说,调整后的价格可能是一个新概念。这里有一个简短的解释为什么我们使用调整后的股票价格。
例如,公司可能会决定进行二对一的股票分割。这意味着,如果你拥有 100 股,在股票分割后,你将拥有 200 股。这样的股票分割会如何影响股价?自然,价格会减半,因为公司的价值没有变化。调整后的股票价格考虑了影响价格但不影响基础价值的股票分割和其他类似事件,并对其进行调整以反映更准确的股票价值。
幸运的是,大多数主要的股市数据提供商默认使用调整后的价格,因此使用非调整后价格的可能性很低。只要仔细检查你是否真的在使用调整后的价格,你不应该在事后担心它。
这是你在股市数据上建立机器学习模型时应该考虑的三个基本准则。遵循它们能确保成功的机器学习模型吗?肯定不是!建立一个模型有无数种可能性。知道哪个可行哪个不可行,几乎是不可能的。但是,遵循这些准则将确保您的模型建立在坚实的基础上。
ROC 曲线下面积和积分
数据科学的基本数学
使用 ROC 曲线下的面积了解积分和模型性能比较

( 图片作者 )
积分和曲线下的面积
微积分是数学的一个分支,它通过两个主要领域提供研究函数变化率的工具:导数和积分。在机器学习和数据科学的背景下,您可能会使用积分来计算曲线下的面积(例如,评估具有 ROC 曲线的模型的性能,或者根据密度来计算概率。
在本文中,您将学习积分和曲线下面积,使用 ROC 曲线下面积的实际数据科学示例来比较两种机器学习模型的性能。从这个例子开始,你会从数学的角度看到曲线下面积和积分的概念(来自我的书《数据科学基础数学》)。
实际项目
比方说,你想从葡萄酒的各种化学特性来预测葡萄酒的质量。你想做一个质量的二元分类(区分非常好的葡萄酒和不太好的葡萄酒)。您将开发一些方法,允许您在考虑受试者操作特征(ROC)曲线下面积不平衡数据的情况下评估您的模型。
资料组
为此,我们将使用一个数据集来显示红葡萄酒的各种化学特性及其质量评级。数据集来自这里:https://archive.ics.uci.edu/ml/datasets/wine+quality。相关论文是 Cortez,Paulo 等人的“通过物理化学性质的数据挖掘对葡萄酒偏好建模”决策支持系统 47.4(2009):547–553。

图 1:葡萄酒质量建模示意图。(图片作者 )
如图 1 所示,数据集代表了葡萄酒的化学分析(特性)和质量评级。这个评级是目标:这是你要尝试评估的。
首先,让我们加载数据,看看特性:
Index([‘fixed acidity’, ‘volatile acidity’, ‘citric acid’, ‘residual sugar’,
‘chlorides’, ‘free sulfur dioxide’, ‘total sulfur dioxide’, ‘density’,
‘pH’, ‘sulphates’, ‘alcohol’, ‘quality’],
dtype=’object’)
最后一列quality很重要,因为您将使用它作为您分类的目标。质量由从 3 到 8 的等级来描述:
array([5, 6, 7, 4, 8, 3])
既然目标是对非常好质量的红酒进行分类,那么让我们决定当评级为 7 或 8 时红酒是非常好的,否则就不是非常好。
让我们创建一个数据集,其中y是质量(因变量,0 表示评分小于 7,1 表示评分大于或等于 7),而X包含所有其他特征。
在查看数据之前,要做的第一件事是将数据分成一部分用于训练算法(训练集)和一部分用于测试算法(测试集)。这将使您能够评估模型在培训期间不可见的数据上的性能。
预处理
作为第一步,让我们标准化数据,以帮助算法的收敛。你可以使用 Sklearn 的类StandardScaler。
请注意,您不希望考虑来自测试集的数据来进行标准化。方法fit_transform()计算标准化所需的参数并同时应用。然后,您可以对测试集应用相同的标准化,而无需再次拟合。
第一个模型
作为第一个模型,让我们在训练集上训练逻辑回归,并在测试集上计算分类准确度(正确分类的百分比):
0.8729166666666667
准确度约为 0.87,这意味着 87%的测试示例已被正确分类。你应该对这个结果感到高兴吗?
不平衡数据集的度量
不平衡数据集
由于我们将数据分为非常好的葡萄酒和不太好的葡萄酒,因此数据集是不平衡的:每个目标类别对应的数据量不同。
让我们看看你在消极类(不是很好的葡萄酒)和积极类(很好的葡萄酒)中有多少观察结果:
0.8650580875781948
0.13494191242180517
它表明大约有 86.5%的例子对应于 0 类,13.5%对应于 1 类。
简单模型
为了说明关于准确性和不平衡数据集的这一点,让我们创建一个模型作为基线,并查看其性能。这将有助于您了解使用准确性之外的其他指标的优势。
利用数据集不平衡这一事实的非常简单的模型将总是估计具有最大数量观察值的类。在你的例子中,这样一个模型将总是估计所有的葡萄酒都是坏的,并得到相当的准确性。
让我们通过创建低于 0.5 的随机概率来模拟这个模型(例如,0.15 的概率意味着该类有 15%的可能性是正的)。我们需要这些概率来计算准确性和其他指标。
array([2.08511002e-01, 3.60162247e-01, 5.71874087e-05, …,
4.45509477e-01, 1.36436118e-02, 2.61025624e-01])
假设如果概率高于 0.5,则该类被估计为正:
array([0, 0, 0, …, 0, 0, 0])
变量y_pred_random只包含零。让我们评估一下这个随机模型的准确性:
0.8625
这说明,即使是随机模型,精度一点都不差:不代表模型好。
总的来说,每一类都有不同数量的观察值,你不能依靠精确度来评估你的模型的性能。在我们的例子中,模型可以只输出零,你会得到大约 86%的准确性。
您需要其他指标来评估具有不平衡数据集的模型的性能。
ROC 曲线
精度的一个很好的替代方法是接收机工作特性(ROC)曲线。你可以在 Géron,Aurélien 查看 Aurélien Géron 关于 ROC 曲线的非常好的解释。使用 Scikit-Learn、Keras 和 TensorFlow 进行机器学习:构建智能系统的概念、工具和技术。奥莱利媒体,2019。
主要思想是将模型中的估计分为四类:
- 真阳性(TP):预测值为 1,真实类别为 1。
- 误报(FP):预测是 1,但真实类别是 0。
- 真负值(TN):预测值为 0,真实类别为 0。
- 假阴性(FN):预测值为 0,但真实类别为 1。
让我们为您的第一个逻辑回归模型计算这些值。可以使用 Sklearn 的函数confusion_matrix。它提供了一个组织如下的表格:

图 2:混淆矩阵的图示。(图片作者 )
array([[414, 0],
[ 66, 0]])
你可以看到,没有一个积极的观察已被正确分类(TP)与随机模型。
决定阈值
在分类任务中,您希望估计数据样本的类别。对于像逻辑回归这样输出 0 到 1 之间概率的模型,您需要使用决策阈值或仅使用阈值将该分数转换为 0 或 1 类。高于阈值的概率被认为是正类。例如,使用决策阈值的默认选择 0.5,当模型输出高于 0.5 的分数时,您认为估计的类是 1。
但是,您可以选择其他阈值,用于评估模型性能的指标将取决于此阈值。
使用 ROC 曲线,您可以考虑 0 到 1 之间的多个阈值,并根据每个阈值的假阳性率来计算真阳性率。
可以使用 Sklearn 的函数roc_curve来计算假阳性率(fpr)和真阳性率(tpr)。该函数还输出相应的阈值。让我们用我们模拟的随机模型来试试吧,在这个模型中,输出只有低于 0.5 的值(y_pred_random_proba)。
让我们来看看输出结果:
array([0\. , 0\. , 0.07246377, …, 0.96859903, 0.96859903,
1\. ])
array([0\. , 0.01515152, 0.01515152, …, 0.98484848, 1\. ,
1\. ])
array([1.49866143e+00, 4.98661425e-01, 4.69443239e-01, …,
9.68347894e-03, 9.32364469e-03, 5.71874087e-05])
现在,您可以根据这些值绘制 ROC 曲线:

图 3:随机模型对应的 ROC 曲线。(图片作者 )
图 3 显示了对应于随机模型的 ROC 曲线。它给出了真阳性率,作为每个阈值的假阳性率的函数。
但是,要小心,阈值是从 1 到 0。例如,左下方的点对应于阈值 1:有 0 个真阳性和 0 个假阳性,因为不可能有大于 1 的概率,所以阈值为 1 时,没有观察结果可以归类为阳性。在右上方,阈值是 0,因此所有的观察都被分类为阳性,导致 100%的真阳性和 100%的假阳性。
对角线周围的 ROC 曲线意味着模型不比随机模型好,这里就是这种情况。对于所有假阳性率值,完美的模型将与真阳性率为 1 的 ROC 曲线相关联。
现在让我们来看看与您之前训练的逻辑回归模型相对应的 ROC 曲线。你将需要来自模型的概率,你可以使用predict_proba()而不是predict得到:
array([[0.50649705, 0.49350295],
[0.94461852, 0.05538148],
[0.97427601, 0.02572399],
…,
[0.82742897, 0.17257103],
[0.48688505, 0.51311495],
[0.8809794 , 0.1190206 ]])
第一列是类 0 的分数,第二列是分数 1(因此,每行的总和是 1),所以您可以只保留第二列。

图 logistic 模型对应的 ROC 曲线。(图片作者 )
您可以在图 4 中看到,您的模型实际上比随机模型更好,这是您无法从模型精度中得知的(它们是等价的:随机模型大约为 0.86,而您的模型为 0.87)。
目视检查是好的,但是用一个单一的数字指标来比较你的模型也是至关重要的。这通常由 ROC 曲线下的面积提供。在接下来的章节中,你会看到曲线下的面积是多少,以及如何计算。
积分
积分是微分的逆运算。取一个函数 f(x)并计算它的导数 f'(x),f'(x)的不定积分(也称为反导数)返回 f(x)(直到一个常数,你很快就会看到)。
您可以使用积分来计算曲线下的面积,这是由函数界定的形状的面积,如图 5 所示。

图 5:曲线下的区域。(图片作者 )
定积分是特定区间上的积分。它对应于这个区间内曲线下的面积。
例子
通过这个例子你会看到如何理解函数的积分和曲线下面积的关系。为了说明这个过程,您将使用曲线下面积的离散化来近似函数 g(x) = 2x 的积分。
示例描述
让我们再以行驶中的火车为例。你看到速度是时间的函数,距离是时间的导数。这些功能如图 6 所示。

图 6:左图显示 f(x ),它是距离与时间的函数,右图显示它的导数 g(x ),它是速度与时间的函数。(图片作者 )
图 6 左图所示的函数定义为 f(x) = x。其导数定义为 g(x)=2x。
在这个例子中,你将学习如何找到 g(x)曲线下面积的近似值。
分割函数
要估算一个形状的面积,可以使用切片法:用简单的形状(如矩形)将形状切割成小切片,计算每个切片的面积,然后求和。
你要做的就是找到 g(x)曲线下面积的近似值。

图 7:通过将速度曲线下的面积离散化为时间的函数,得到曲线下面积的近似值。(图片作者 )
图 7 显示了 f'(x)的曲线下的区域,该区域被切成一秒钟的矩形(我们称之为差值δx)。请注意,我们低估了面积(查看丢失的三角形),但我们稍后会解决这个问题。
让我们试着理解切片的含义。拿第一个来说:它的面积被定义为 2 ⋅ 1。切片的高度是一秒钟的速度(值为 2)。所以第一个切片有两个单位的速度乘以一个单位的时间。面积相当于速度和时间的乘积:这是一个距离。
例如,如果你以每小时 50 英里的速度行驶了两个小时,你行驶了 50 ⋅ 2 = 100 英里的距离。这是因为速度的单位对应于距离和时间的比率(比如英里每小时)。你得到:(距离/时间)⋅时间=距离。
总结一下,距离对时间函数的导数就是速度对时间的函数,速度对时间函数的曲线下面积(它的积分)给你一个距离。这就是导数和积分的关系。
履行
让我们用切片来近似函数 g(x)=2x 的积分。首先,让我们定义函数 g(x):
如图 7 所示,您将认为该函数是离散的,并以δx = 1 为步长。您可以创建一个值从 0 到 6 的 x 轴,并对每个值应用函数g_2x()。您可以使用 Numpy 方法arange(start, stop, step)创建一个数组,用从start到stop的值填充(不包括):
array([0, 1, 2, 3, 4, 5, 6])
array([ 0, 2, 4, 6, 8, 10, 12])
然后,您可以通过迭代并将宽度(δx)乘以高度(此时的 y 值)来计算切片的面积。切片的。正如您所看到的,这个区域(下面代码中的delta_x * y[i-1])对应于一个距离(移动的火车在第 I 个片段中行驶的距离)。最后,您可以将结果追加到一个数组中(下面代码中的slice_area_all)。
注意y的索引是i-1,因为矩形在我们估计的 x 值的左边。例如,对于 x=0 和 x=1,面积为零。
array([ 0., 0., 2., 4., 6., 8., 10.])
这些值是切片的面积。
要计算从起点到相应时间点(不对应每个切片)的距离,可以用 Numpy 函数cumsum()计算slice_area_all的累计和:
array([ 0., 0., 2., 6., 12., 20., 30.])
这是 g(x)的曲线下面积作为 x 的函数的估计值,我们知道函数 g(x)是 f(x)=x 的导数,所以我们要通过对 g(x)的积分把 f(x)取回来。
让我们画出我们的估计和 f(x),我们称之为“真实函数”,来比较它们:

图 8:估算函数和原始函数的比较。(图片作者 )
图 8 中表示的估计表明该估计并不差,但是可以改进。这是因为我们错过了图 9 中用红色表示的所有三角形。

图 9:速度函数切片中的缺失部分(红色)。δx 越小误差越小 ( 图片作者 )
让我们估计δx = 0.1 的积分函数:

图 10:切片宽度越小,对原始函数的估计越好。(图片作者 )
如图 10 所示,我们恢复了(至少,直到一个附加常数)我们对其导数进行积分的原始函数。
延长
在我们之前的例子中,您对函数 2x 进行了积分,这是一个线性函数,但是对于任何连续函数,原理都是相同的(例如,参见图 11)。

图 11:切片方法可用于许多线性或非线性函数,包括所有连续函数。(图片作者 )
黎曼和
使用这种切片方法近似积分被称为黎曼和。黎曼和可以用不同的方法计算,如图 12 所示。

图 12:积分逼近的四种黎曼和。(图片作者 )
如图 12 所示,使用左黎曼和,曲线与矩形的左角对齐。使用右黎曼和,曲线与矩形的右角对齐。使用中点规则,曲线与矩形的中心对齐。对于梯形法则,使用梯形形状而不是矩形。曲线穿过梯形的两个顶角。
数学定义
在上一节中,您看到了曲线下面积和积分之间的关系(您从导数中恢复了原始函数)。现在让我们看看积分的数学定义。
函数 f(x)关于 x 的积分表示如下:

符号 dx 被称为 x 的微分,指的是 x 的无穷小变化的想法,它是 x 中接近 0 的差。积分的主要思想是对无限个宽度无限小的切片求和。
符号∫是整数符号,表示无限个切片的总和。
每个切片的高度是值 f(x)。f(x)的乘法
因此 dx 是每个切片的面积。最后,∫ f(x) dx 是无限个切片的切片面积之和(切片的宽度趋于零)。这是曲线下的区域。
你在上一节看到了如何近似函数积分。但是如果你知道一个函数的导数,你就可以在知道它是逆运算的情况下检索积分。例如,如果您知道:

可以得出 2x 的积分是 x,但是,有一个问题。如果你给我们的函数加一个常数,导数是一样的,因为常数的导数是零。举个例子,

不可能知道常数的值。因此,您需要在表达式中添加一个未知常数,如下所示:

其中 c 是常数。
定积分
在定积分的情况下,用整数符号上下的数字表示积分区间,如下所示:

它对应于 x=a 和 x=b 之间函数 f(x)曲线下的面积,如图 13 所示。

图 13:x = a 和 x=b 之间曲线下的面积 ( 图片作者 )
ROC 曲线下面积
现在你知道了曲线下的面积与积分的关系,让我们来看看如何计算它来比较你的模型。
请记住,您的 ROC 曲线如图 14 所示:

图 14:随机模型(蓝色)和逻辑回归模型(绿色)的 ROC 曲线。(图片作者 )
先说随机模型。您希望将每个真阳性率值乘以 x 轴上的宽度(即相应的假阳性率值与前一个值之差)进行求和。您可以通过以下方式获得这些差异:
array([0.00241546, 0.01207729, 0\. , …, 0.01207729, 0\. ,
0.06038647])
所以随机模型的 ROC 曲线下的面积是:
0.5743302591128678
或者您可以简单地使用 Sklearn 的函数roc_auc_score(),将真实目标值和概率作为输入:
0.5743302591128678
ROC 曲线下 0.5 的面积对应于不比随机更好的模型,面积 1 对应于完美的预测。
现在,让我们将该值与您的模型的 ROC 曲线下的面积进行比较:
0.8752378861074513
这表明你的模型实际上并不差,你对葡萄酒质量的预测也不是随机的。
在机器学习中,你可以用几行代码来训练复杂的算法。然而,正如你在这里看到的,一点数学知识可以帮助你充分利用它,加快你的工作。它会让你在学科的各个方面更加轻松,甚至,例如,理解像 Sklearn 这样的机器学习库的文档。
原载于 2020 年 11 月 6 日https://hadrienj . github . io。
这篇文章是我的书数据科学基础数学的样本!
帮助您开始学习计算机视觉的基本 OpenCV 函数
计算机视觉
了解常见的 OpenCV 函数及其应用

作者图片
计算机视觉是人工智能的一个领域,它训练计算机解释和理解视觉世界。因此,许多项目涉及使用相机和视频中的图像,以及使用多种技术,如图像处理和深度学习模型。
OpenCV 是一个旨在解决常见计算机视觉问题的库,它在该领域非常受欢迎,非常适合在生产中学习和使用。这个库有多种语言的接口,包括 Python、Java 和 C++。
在整篇文章中,我们将介绍 OpenCV 中不同的(常见的)函数,它们的应用,以及如何开始使用每一个函数。尽管我将提供 Python 中的例子,但是对于不同的支持语言,概念和函数是相同的。
我们今天到底要学什么?
- 读取、写入和显示图像
- 更改色彩空间
- 调整图像大小
- 图像旋转
- 边缘检测
读取、写入和显示图像
在我们可以用计算机视觉做任何事情之前,我们需要能够阅读和理解计算机是如何处理图像的。计算机唯一能处理的信息是二进制信息(0 和 1),包括文本、图像和视频。
计算机是如何处理图像的
为了理解计算机是如何“理解”一幅图像的,你可以画出一个图像大小的矩阵,在这个矩阵中,你在每个单元格上指定一个值,代表该位置图像的颜色。
让我们以灰度图像为例:

对于这种特殊情况,我们可以为图像中的每个块(或像素)分配一个数值(可以解释为二进制)。这个数值可以是任何范围的,尽管习惯上用 0 代表黑色,255 代表白色,中间的所有整数代表强度。
当我们处理彩色图像时,根据库和我们选择的表示颜色的方式,情况会有所不同。我们将在后面的文章中详细讨论,然而,它们都或多或少地分享相同的想法,即使用不同的通道来表示颜色,RGB(红色、绿色和蓝色)是最受欢迎的选项之一。对于 RGB,我们需要 3 个通道来构建每个像素,因此我们的 2d 矩阵现在是深度为 3 的 3d 矩阵,其中每个通道都是特定颜色的强度,当混合时,我们得到像素的最终颜色。
使用 OpenCV 处理图像
现在让我们进入代码来执行处理图像时最重要的三个功能,读取,显示,保存。
import cv2
import matplotlib.pyplot as plt# Reading the image
image = cv2.imread('sample1.jpg')# Showing the image
plt.imshow(image)
plt.show()# Saving the image
cv2.imwrite('sample1_output.jpg', image)
如果您运行我们的代码,现在您将得到一个保存到磁盘的图像,以及另一个作为绘图结果的图像。

作者图片,来自 Berkay Gumustekin 在 Unsplash 发布的原始图片
左边的图像是我们绘制的,而右边的是保存到磁盘的图像。除了尺寸上的差异(由于剧情原因),左边的图像看起来很奇怪,看起来是蓝色的,但为什么会不同呢?(对了,右图没错)。
左边的图像看起来颜色奇怪的原因与 OpenCV 默认读取图像的方式有关。OpenCV imread()函数将使用 BGR 通道读取图像,假定为 RGB ,由绘图函数使用。这对于 OpenCV 来说是正常的,我们接下来会讨论修复它的方法。
更改色彩空间
什么是色彩空间?在我们之前的例子中,我们看到了计算机是如何处理图像的,我们看到,为了表示颜色,我们需要使用通道,当组合时,我们得到图像的最终颜色。设置这些通道的配置是色彩空间。不知不觉中,我们已经在之前的代码片段中涵盖了 2 种不同的色彩空间,我们使用了 RGB 和 BGR ,但是还有更多具有非常特殊和有趣的属性。其他一些流行的颜色空间包括 LAB 、 YCrCb 、 HLS、和 HSV 。由于每个颜色空间都有自己的属性,一些算法或技术在一个空间中可能比其他空间中工作得更好,因此在这些颜色空间之间改变图像是很重要的,谢天谢地,OpenCV 为我们提供了一个非常容易使用的函数来实现这一目的。
满足 cvtColor ,让我们看看如何用它来修复我们上面的情节
import cv2
import matplotlib.pyplot as plt# Reading the image
image = cv2.imread('sample1.jpg')# Change color space
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)# Showing the image
plt.imshow(image)
plt.show()
我们现在有了一只漂亮的棕色狗:

让我们探索一些其他的色彩空间:
import cv2
import matplotlib.pyplot as plt# Reading the image
original = cv2.imread('sample1.jpg')fig = plt.figure(figsize=(8, 2))
axarr = fig.subplots(1, 3)# Change color space
image = cv2.cvtColor(original, cv2.COLOR_BGR2RGB)
axarr[0].imshow(image)image = cv2.cvtColor(original, cv2.COLOR_BGR2GRAY)
axarr[1].imshow(image)image = cv2.cvtColor(original, cv2.COLOR_BGR2LAB)
axarr[2].imshow(image) plt.show()

调整图像大小
既然我们能够加载、显示和更改图像的颜色空间,接下来我们需要关注的是调整大小。在计算机视觉中调整图像的大小很重要,因为 ML 中的学习模型使用固定大小的输入。大小将取决于模型,但为了确保我们的图像将在模型上工作,我们需要相应地调整它们的大小。
OpenCV 提供了一个名为 resize 的实用方法,让我们看一个如何使用它的例子。
import cv2# Reading the image
original = cv2.imread('sample1.jpg')# Resize
resized = cv2.resize(original, (200, 200))print(original.shape)
print(resized.shape)
哪些输出
(1100, 1650, 3)
(200, 200, 3)
图像旋转
训练模型的一个关键部分是我们将用来训练它的数据集。如果数据集没有足够的样本和分布良好的样本,训练好的模型很可能会失败。但有时我们没有足够大的数据集,或者我们没有我们想要训练模型的所有情况,所以我们运行改变图像的过程来生成新的图像。在很多情况下,将图像旋转到不同的角度可以帮助我们提高模型的效率,但我们不会在这里一一介绍。相反,我想向您展示如何使用 OpenCV 来旋转图像。
让我们看一个 OpenCV 中的旋转函数的例子
import cv2
import matplotlib.pyplot as plt# Reading the image
image = cv2.imread('sample1.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)image = cv2.rotate(image, cv2.ROTATE_90_CLOCKWISE)plt.imshow(image)
plt.show()

尽管这种方法非常容易使用,但它也限制了我们的选择,我们不能以任何角度旋转。为了更好地控制旋转,我们可以使用 getRotationMatrix2D 和 warpAffine 来代替。
import cv2
import matplotlib.pyplot as plt# Reading the image
image = cv2.imread('sample1.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)rows, cols = image.shape[:2]
deg = 45
# (col/2,rows/2) is the center of rotation for the image
# M is the coordinates of the center
M = cv2.getRotationMatrix2D((cols/2, rows/2), deg, 1)
image = cv2.warpAffine(image, M, (cols, rows))plt.imshow(image)
plt.show()

边缘检测
边缘是图像中图像亮度急剧变化或不连续的点。这种不连续性通常对应于:
- 深度的不连续性
- 表面方向的不连续性
- 材料特性的变化
- 场景照明的变化
边缘是图像的一个非常有用的特征,可以用作 ML 管道的一部分,我们已经看到了一些边缘如何帮助我们检测道路上的形状或线条的例子。
[## 使用 Hough 变换和 OpenCV & Python 理解和实现形状检测
用几行 Python 代码在图像中找到车道和眼睛
medium.com](https://medium.com/@bajcmartinez/understanding-implementing-shape-detection-using-hough-transform-with-opencv-python-cd04346115c0) [## 不用深度学习就能找到车道
今天我们将在一个项目中合作,使用 python 在图像和视频中寻找车道。对于该项目,我们…
medium.com](https://medium.com/@bajcmartinez/finding-lanes-without-deep-learning-5407053560cb)
CV2 为我们提供了这个任务的 Canny 函数,下面是它的使用方法:
import cv2
import matplotlib.pyplot as plt# Reading the image
original = cv2.imread('sample2.jpg')fig = plt.figure(figsize=(6, 2))
axarr = fig.subplots(1, 2)axarr[0].imshow(cv2.cvtColor(original, cv2.COLOR_BGR2RGB))threshold1 = 50
threshold2 = 200
grey = cv2.cvtColor(original, cv2.COLOR_BGR2GRAY)
image = cv2.Canny(original, threshold1, threshold2)
axarr[1].imshow(image, cmap='gray') plt.show()

摘要
OpenCV 是一个非常棒的处理图像和视频的库,它提供了大量有用的工具和函数,可以处理从最简单到更复杂的场景。我们今天讨论的函数只是图库中的几个。如果你有兴趣探索库文档,看看样本,有很多,从简单的图像处理,如转置,到更高级的功能,如轮廓检测,特征检测,甚至人脸检测。
我希望你喜欢阅读这篇文章,并且请加入到关于你最喜欢的 OpenCV 函数的讨论中来。
感谢阅读!
基本编程|控制结构
节目的骨干

如果你想开始编程,我必须承认前景并不好:不同的操作系统,如此多的编程语言,以及达到相同结果的无尽方式。这些情况要么让你逃跑(尽可能快、尽可能远,希望你再也不会碰到编程),要么让你面对野兽。如果你决定面对它,那么你将不知道从哪里开始,或者如何处理它。你只会有问题,甚至可能没有一个答案,但你知道吗?这是一个很好的开始方式。实际上,我就是这样开始编程的。我相信,如果我想理解程序,我必须回答这个问题:
程序是如何工作的,你如何构建它们?
当然不是一个简单的问题,但是拜托,更难的问题已经有答案了,对吧?看一看马文·明斯基。被认为是人工智能之父之一的明斯基写了 【心灵的社会】 来回答我们这个时代最困难的问题之一:什么是人类的心灵,它是如何工作的?从一个革命性的角度来看,明斯基认为我们的思维是由小思维(或更基本的成分)的集合组成的,这些思维已经进化成执行高度特定的任务。根据他的说法,这些微小心灵中的大多数缺乏我们认为的智力属性,并且受到严重限制,只能通过与其他组件的相互作用来达到感觉,想法或有目的的行动。
这个想法包含了一个强有力的概念:复杂的事情可以被认为是一组简单的主题,也可以被分割成更基本的东西,直到你达到一个正确的理解。如果你这样想的话,任何有效的系统都可以被解释为一组更简单的功能,当这些功能组合在一起时,与它们各自的性能相比,可以达到更好的效果。
出于这个原因,如果我想理解计算机程序(并学习如何制作它们),我需要理解它们的构建模块。你看,当一个程序运行时,代码被计算机逐行(从上到下,从左到右)读取,就像你读一本书一样。在某个时候,程序可能会遇到需要做出决定的情况,例如跳转到程序的不同部分或再次运行某个片段。这些影响程序代码流程的决策被称为控制结构。
控制结构可以被认为是计算机程序的构建模块。它们是使程序能够“做出决定”的命令,遵循这样或那样的路径。一个程序通常不局限于线性的指令序列,因为在它的处理过程中,它可能会分叉、重复代码或绕过某些部分。控制结构是分析变量并根据给定的参数选择前进方向的模块。
编程语言中的基本控制结构是:
- 条件句(或选择):,用于在满足条件的情况下执行一条或多条语句。
- 循环(或迭代):其目的是将一个语句重复一定的次数或在满足一个条件的时候。
现在,让我们来看看这些概念中的每一个。下面我们将深入使用 R 编程语言(数据科学中最常用的语言之一),但是同样的思想和解释适用于任何其他编程语言。
条件式
“条件”是编程的核心。它们背后的思想是,它们允许你控制基于程序中不同条件执行的代码流(例如,来自用户的输入,或者运行程序的机器的内部状态)。在本文中,我们将探讨“If 语句”和“If-Else 语句”的条件控制结构。
1) If 语句
“If 语句”在满足条件时执行一条或多条语句。如果该条件的测试为真,则执行该语句。但是如果它是假的(条件不满足),那么什么都不会发生。让我们想象一下:

如果语句
“If 语句”的语法是:

示例
举个简单的例子,假设您想要验证变量(x)的值是否为正:

在本例中,首先我们将值 4 赋给变量(x ),并使用“If 语句”来验证该值是否等于或大于 0。如果测试结果为真(如本例),该函数将打印句子:“变量 x 是一个正数”。
输出
[1] "variable x is a positive number"
但是由于“If 语句”只在测试条件为真时执行语句,如果变量值为负会发生什么呢?要在测试条件下执行一个结果为假的语句,我们需要使用“If-Else 语句”。
2) If-Else 语句
这种控制结构允许程序遵循可选的执行路径,无论条件是否满足。

If-Else 语句
“If-Else 语句”的语法是:

指令的“else 部分”是可选的,仅当条件测试为假时才进行评估。
例 1
按照我们的示例,我们通过添加“else 部分”来扩展前面的条件“If 语句”,以测试变量的值是正还是负,并在测试结果为真还是假时执行操作。

在本例中,我们将值-4 赋给变量(x ),并使用“If 语句”来验证该值是否等于或大于 0。如果测试结果为真,函数将打印句子:“变量 x 是一个正数”。但是在测试结果为假的情况下(就像在这种情况下),函数继续执行替代表达式并打印句子:“变量 x 是负数”。
输出
[1] "variable x is a negative number"
例 2
比方说,你需要定义两个以上的条件,就像给考试评分一样。在这种情况下,你可以评分 A,B,C,D 或 F (5 个选项),那么,你会怎么做呢?
“If-Else 语句”可以有多个可选语句。在下面的例子中,我们定义了一个初始分数,以及一个包含 5 个评级类别的“If-Else 语句”。这段代码将遍历每一个条件,直到得到一个真实的测试结果。

输出
[1] “C”
环
“循环语句”只不过是通过组织动作序列和对需要重复的部分进行分组来实现多步骤过程的自动化。作为编程的核心部分,迭代(或循环)赋予了计算机强大的能力。他们可以根据需要经常重复一系列步骤,简单步骤的适当重复可以解决复杂的问题。
一般来说,有两种类型的“循环技术”:
- “For Loops”:是在计数器或索引的控制下,执行规定次数的程序。
- “While 循环”和“重复循环”:基于逻辑条件的开始和验证。在循环构造的开始或结束时测试条件。
让我们来看看它们:
1)对于循环
在这种控制结构中,语句以连续的顺序在一系列值上一个接一个地执行,这些值只有在“For 循环”启动时才被求值(从不重新求值)。在这种情况下,迭代次数是固定的,并且是预先知道的。

For 循环
如果对变量(可以采用指定序列中的值)的条件评估结果为真,将对该值字符串顺序执行一个或多个语句。一旦第一个条件测试完成(结果为真),就执行语句并再次评估条件,经历一个迭代过程。“序列中的变量”部分对序列中的每个值执行这个测试,直到它覆盖了最后一个元素。
如果不满足条件,并且结果为假(例如,“序列中的变量”部分已经完成了序列的所有元素),则循环结束。如果条件测试在第一次迭代中的结果为假,则“For 循环”永远不会执行。
“For 循环”的语法是:

例 1
为了展示“For 循环”是如何工作的,首先我们将创建一个序列,通过连接不同的水果名称来创建一个列表(称为“fruit_list”):

我们将使用这个水果列表作为“For 循环”中的“序列”,并让“For 循环”为序列中提供的每个值(水果列表中的不同水果)运行一次语句(打印每个值的名称):

这样,“For 循环”的结果如下:
## [1] "Apple"
## [1] "Kiwi"
## [1] "Orange"
## [1] "Banana"
好了,我们打印了列表中每个值的名字。没什么大不了的,对吧?好的一面是“For 循环”可以用来产生更有趣的结果。看看下面的例子。
例二
如果我们想修改值,或者按顺序执行计算,该怎么办?您可以使用“For Loops”对向量的每个值(相同类型的元素,在本例中为数字元素)依次执行数学运算。
在本例中,我们将创建一个数字序列(从 1 到 10),并设置一个“For 循环”来计算和打印该序列中每个值的平方根:

在这种情况下,“For 循环”的结果是:
[1] 1
[1] 1.414214
[1] 1.732051
[1] 2
[1] 2.236068
[1] 2.449490
[1] 2.645751
[1] 2.828427
[1] 3
[1] 3.162278
您可以在一个数字序列上使用任何类型的数学运算符,正如我们将在本文后面看到的,在不同的控制结构之间进行各种组合,以获得更复杂的结果。
2) While 循环
在“While Loops”中,首先评估一个条件,如果测试该条件的结果为真,则重复执行一个或多个语句,直到该条件变为假。

While 循环
与“If 语句”不同,在“If 语句”中,测试为真的条件只执行一次表达式就结束了,“While 循环”是反复执行某个表达式直到条件变为假的迭代语句。如果条件永远不会为假,那么“While 循环”将永远继续下去,程序将会崩溃。反之,如果循环开始时条件测试结果为假,表达式将永远不会执行。
“While 循环”的语法是:

例 1
让我们看一个例子。首先,我们将创建一个变量(x ),并给它赋值 1。然后,我们设置一个“While 循环”来迭代测试该变量上的条件,直到条件测试结果为假:

它是这样工作的:变量(x)的初始值是 1,所以当我们测试条件“变量(x)小于 10 吗?”,结果计算为 TRUE,执行表达式,打印变量(x)的结果,在第一种情况下是 1。但随后发生了一些事情:变量(x)在函数结束前增加 1,在下一次迭代中,x 的值将为 2。
这种变量的重新分配是很重要的,因为它最终会达到假条件,循环退出(x = 10)。未能改变“While 循环”中的初始条件将导致无限循环和程序崩溃。
输出
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
例二
你听说过斐波那契数列吗?这是一系列数字,其特点是序列中的下一个数字是通过将它前面的两个数字相加得到的:0、1、1、2、3、5、8、13、21……这个序列可以在几个自然现象中找到,在金融、音乐、建筑等学科中有不同的应用。
让我们使用“While 循环”来计算它。

在这种情况下,我们将序列中的最大值设置为停止条件,这样循环只打印小于 100 的斐波纳契数列。当一个序列元素(不管它是什么)变得大于 100 时,循环周期结束。
[1] 0
[1] 1
[1] 1
[1] 2
[1] 3
[1] 5
[1] 8
[1] 13
[1] 21
[1] 34
[1] 55
[1] 89
例 3
用“While 循环”生成斐波纳契数列的另一种方法是,不将数列的最大值设置为停止条件,而是设置您想要生成的数列元素的数量。

这个“While 循环”将序列中的下一个元素追加到前一个元素的末尾,直到达到停止条件。在这种情况下,当序列达到 10 个元素时(无论是哪个值),循环结束。
输出
[1] 0 1 1 2 3 5 8 13 21 34
3)重复循环
与“While Loops”紧密相连,“Repeat Loops”迭代执行语句,但直到满足停止条件。这样,不管条件的结果是什么,语句都至少执行一次,并且只有当某个条件为真时才退出循环:

重复循环
“重复循环”的语法是:

“重复循环”使用“中断语句”作为停止条件。“中断语句”与中断循环内循环的条件测试相结合,因为当程序遇到中断时,它会在循环结束后立即将控制传递给指令(如果有)。
如果不满足中断条件,“重复循环”将永远运行。请看这两个例子
例 1
首先我们创建一个变量(x)并给它赋值 5。然后,我们设置一个“重复循环”来迭代地打印变量的值,修改变量的值(增加 1),并在该变量上测试一个条件(如果它等于 10),直到条件测试结果为真。

当变量(x)达到 10 时,触发“中断条件”,循环结束。
输出
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
例二
现在让我们假设我们产生一个随机数列表,我们不知道它的生成顺序。
在这个例子中,我们将使用一个“重复循环”来生成一个正态分布的随机数序列(您可以使用任何其他分布来生成 random,我们只选择这一个),并在其中一个数大于 1 时破坏该序列。因为我们不知道哪些数字会先出现,所以我们不知道序列会有多长:我们只知道破缺条件。

首先,我们使用“set.seed”指令来固定随机数(总是生成相同的随机数),并使这个例子可再现。
然后,我们通过生成一个正态分布的随机数,打印它,并检查该数是否大于 1 来启动“重复循环”。只有当这个条件为真时(可能是第一个生成的数字,也可能不是),循环才会传递到 break 语句并结束。
输出
[1] -0.9619334
[1] -0.2925257
[1] 0.2587882
[1] -1.152132
[1] 0.1957828
[1] 0.03012394
[1] 0.08541773
[1] 1.11661
这再一次表明了设定一个合适的破裂条件的重要性。否则将导致无限循环。
最后的想法
我们已经看到并解释了孤立的概念,但是“控制结构”可以按照你想要的任何方式组合:循环可能包含几个内部循环;条件句可能包含循环和条件句,选项是无穷无尽的。(事实上,在回顾“重复循环”时,我们发现示例中包含嵌套的“If 语句”)。
您可以通过组合我们在本文中解释的“控制结构”来开发高级解决方案。正如明斯基所说,我们可以通过简单成分的相互作用达到复杂的结果。控制结构构成了计算中决策过程的基本模块。它们改变了程序的流程,使我们能够从简单的构件中构造出复杂的指令集。
我的建议是: 了解一下他们。
它会让你更容易编码和理解程序,并帮助你找到解决问题的新方法。
基本编程|排序算法
基本编程工具指南

埃菲社在 Unsplash 上拍摄的照片
你日历中的下一个任务,你最喜欢的运动队在联盟中的排名位置,你手机中的联系人列表,所有这些都是有顺序的。当我们处理信息时,顺序很重要。我们用秩序来理解我们的生活,优化我们的决定。想象一下,在一个混合字母顺序的字典中查找一个单词,或者试图在一个无序的定价列表中找到最便宜的产品。我们订购东西是为了做出更合理的决定(这实际上是一种错觉),这让我们对结果更有信心。
但有一个问题:这个世界是混乱的,是天生无序的(至少从我们人类的感知来看)。今天的数据又乱又多,真是糟糕的组合。我们怎样才能以一种对我们有意义的方式来整理这个海量的信息漩涡?这就是计算机排序算法发挥关键作用的地方。
排序算法的世界
简单来说,算法就是解决问题的一步一步的方法。算法的基础是接受一个输入并执行一系列特定的动作以达到一个结果。它们被广泛应用于计算机编程、数学,甚至我们的日常生活中(例如,一个烹饪食谱就是一个算法)。
算法远在计算机发明之前就存在了,但是自从现代技术的爆炸以来,计算机算法已经扩展并到处复制。现在,从计算机算法的巨大宇宙中,我认为排序算法值得一个特殊的章节。
排序算法是计算机科学的基础。它们将无序的数据转化为按照某种标准排序的数据,例如字母顺序、最高到最低值或最短到最长距离。
它们基本上以项目列表作为输入,对这些列表执行特定的操作,并以有序的方式交付这些项目作为输出。排序算法的许多应用包括在零售网站上按价格组织商品,以及确定网站在搜索引擎结果页面上的顺序
有许多不同的排序算法,但它们有一个共同点,那就是可视化后更容易理解。在下面的例子中,我们取一个无序列表,用 5 种不同的算法进行排序:选择排序、插入排序、冒泡排序、合并排序和快速排序。让我们来看看。
选择排序
选择排序算法基于这样的思想:在未排序的列表中找到最小或最大元素,然后以排序的方式将其放在正确的位置。在升序排序的情况下,最小的元素将在第一个,在降序排序的情况下,最大的元素将在开始。
因此,当按升序排序时,选择排序的工作方式是反复从列表的未排序部分中找到最小元素,并将其放在开头。在每次迭代中,从列表的未排序部分选取最小元素,并将其移动到列表的排序部分。为了做到这一点,该算法在进行传递时寻找最小值(在升序的情况下),并在完成传递后,将其放置在适当的位置。

选择排序算法(升序)
看上面的例子。需要升序排序的列表分为两部分,左端排序的部分和右端未排序的部分。最初,已排序的部分是空的,未排序的部分是整个列表。从未排序列表中选择最小的元素(本例中为 2)(用洋红色标记),并与最左边的元素交换,该元素成为排序数组的一部分(现在为橙色)。这个过程通过将未排序的元素从未排序的列表一个接一个地移动到已排序的列表来继续,直到没有元素剩下为止。
选择排序非常直观,但由于它需要扫描整个列表来查找下一个小值,所以在处理大量数据时会非常慢。
插入排序
你在游戏中整理过扑克牌吗?如果答案是肯定的,那么这就是插入排序。
与选择排序类似,插入排序将元素分为排序列表和未排序列表。在该算法中,按顺序搜索元素,将未排序的项目移动并插入到排序列表中,直到覆盖所有未排序的值。

插入排序算法(升序)
在我们的示例中,从左边开始,算法将第一个元素(29)标记为已排序。然后,它选取位于未排序列表中的第二个元素(10),并将其与位于排序列表中的前一个元素进行比较。因为 10 小于 29,所以它将较高的元素向右移动,并将较小的元素插入第一个位置。现在,元素 10 和 29 表示排序后的列表。该算法通过从右侧的未排序列表中提取元素并将其与左侧的排序列表中的元素进行比较来顺序执行这一练习,以确定将它们插入到哪个位置。
插入排序是自适应的,这意味着如果提供部分排序的数组作为输入,它会减少总的步骤数,从而提高效率。像选择排序一样,插入排序不适合大数据量,因为它不适合其他排序算法。
冒泡排序
冒泡排序基于这样一种思想,即反复比较相邻元素对,然后如果它们以错误的顺序存在,就交换它们的位置。
如果一个元素列表必须按升序排序,那么冒泡排序将从比较列表的第一个元素和第二个元素开始。如果第一个元素大于第二个元素,它将交换两个元素,并继续比较第二个和第三个元素,依此类推。

冒泡排序算法(升序)
在我们的例子中,算法从比较第一个元素(29)和第二个元素(10)开始。因为 29 比 10 大,所以它交换它们并将 29 作为列表中的第二个元素。然后,它对第二个元素(29)和第三个元素(14)执行相同的操作,并对所有列表元素重复该操作。因此,在第一遍中,列表中最高的元素(41)将被放置在列表的末尾(右侧)。该算法将多次遍历所有元素,直到它们都被排序,“冒泡”每个元素到它所属的位置。
冒泡排序通常被认为是一种低效的排序工具,因为它必须在知道元素的最终位置之前交换项目。然而,如果在一次传递中没有交换,那么我们知道列表必须被排序。如果冒泡排序发现一个列表已经被排序,它可以被修改为提前停止,这为它提供了识别排序列表的能力。
合并排序
合并排序是一种非常有效的算法,它将元素列表分成相等的两半,然后以排序的方式组合它们。
该算法从重复地将一个列表分解成几个子列表开始,直到每个子列表由一个元素组成并且不能再被分割(创建一个元素的分区)。每个子列表的第一个元素在它们之间进行比较,并且如果以升序排序,则两者中较小的元素成为新的合并排序列表的新元素。重复该过程,直到所有子列表都为空,并且一个新合并的列表覆盖了所有子列表的所有元素,从而得到一个排序列表。
这里的秘密是一个只有一个元素的列表已经被排序了,所以一旦我们把原始列表分解成只有一个元素的子列表,我们就成功地把问题分解成了基本问题。这种方法被称为【分而治之】,其基本思想是将一个单一的大问题分解成更小的子问题,解决更小的子问题,并组合它们的解决方案,以找到原始大问题的解决方案。

合并排序算法(升序)
在我们的例子中,算法首先将元素列表分成 1 个分区。然后,它合并第一个(29)和第二个(10)元素,对它们进行排序(在本例中是按升序),并将它们放回列表中。然后,它合并第一个(现在是 10 个)、第二个(现在是 29 个)和第三个(14 个)元素,对它们进行排序,并将它们放回列表中。它对所有子列表执行这个过程,合并子结果,直到得到一个唯一的排序列表。
由于合并排序将输入分成多个块,因此可以同时并行地对每个块进行排序,从而产生极快的结果。
快速排序
快速排序是最有效的排序算法之一,它基于将数据集划分为子组,然后再将子组递归划分为更小的组,以优化排序过程。该算法的工作原理是在数据集中找到一个“pivot element”,并将其作为排序的基础。
快速排序还使用了“分而治之”的方法来划分和组织 pivot 周围的元素,这样:pivot 的左侧包含所有小于 pivot 元素的元素,右侧包含所有大于 pivot 的元素(这称为“分区”)。这样,pivot 值从将整个元素分成两部分开始,通过为每个子部分找到一个 pivot 递归工作,直到所有部分只包含一个元素。

快速排序算法
在上面的例子中,未排序分区的第一个元素被选作 pivot 元素(用黄色突出显示)。比它小的元素用绿色标记并排序在左边,比它大的元素用紫色突出显示并排序在右边。
我们来看看顺序。开始时,选择 29(左边的第一个元素)作为支点。当枢轴被放置在适当的位置时,所有比它小的元素被放置在左边(一个子组),比它高的元素被放置在右边(另一个子组)。然后选取 5(左侧未排序列表的第一个元素)作为新的 pivot 元素,整个过程不断迭代,直到这一侧排序完毕。
一旦左侧组被排序,算法就移动到右侧未排序的组,并挑选 41(左侧的第一个元素)作为中枢,并在这一侧执行相同的过程,直到整个数据集从最低到最高排序。
在快速排序中,可以选择数据集中的任何元素作为轴心:第一个元素、最后一个元素或任何其他随机元素。那么最好的办法是什么呢?和往常一样,没有一个直接的解决方案,这取决于你试图解决的问题。您可以:
- 总是选择第一个元素作为轴心
- 总是选择最后一个元素作为轴心
- 选择一个随机元素作为轴心
- 选择中线作为轴心
如果分区后产生的子划分是不平衡的(也就是说,在轴心的一侧得到的元素很少,而在另一侧得到的元素很多),那么快速排序将需要更多的时间来完成。为了避免这种情况,您可以选择随机枢纽元素并分散获得不平衡分区的风险。
选哪个?
自然,计算机科学家不断发明额外的排序算法,它们各有利弊,所以要谨慎选择你的排序算法。选择正确的排序算法,你的程序就能快速运行。选择错误的排序算法,你的程序对用户来说可能会慢得让人无法忍受。一般来说,插入排序最适合小列表,冒泡排序最适合已经排序的列表,快速排序通常是日常使用中最快的。
你明白了:一些算法在管理相对少量的项目时速度很快,但是如果你强迫它们管理大量的项目,速度就会很慢。另一方面,其他算法在对最初几乎正确排序的项目进行排序时非常快速和有效,但如果对列表中随机分散的项目进行排序时则非常慢。
但是如果你能从每一个中取其精华呢?混合算法是我们要走的路。
混合算法结合了解决同一问题的两种或多种其他算法,或者选择一种,或者在处理过程中在它们之间切换。
这样做是为了组合每个组件的所需功能,以便整体性能优于单个组件的性能。例如 Tim Sort 是一种混合排序算法,源自合并排序和插入排序,旨在实现真实世界数据的高性能。该算法查找已经排序的数据的子序列(称为“自然运行”),并使用它们更有效地对剩余部分进行排序。
对这些话题感兴趣?在 Linkedin或 Twitter 上关注我
基本编程|时间复杂性
如何衡量算法的效率

在计算机编程中,就像在生活的其他方面一样,解决一个问题有不同的方法。这些不同的方法可能意味着不同的时间、计算能力或您选择的任何其他指标,因此我们需要比较不同方法的效率,以选择正确的方法。
现在,你可能知道,计算机能够根据算法解决问题。
算法是告诉计算机做什么和如何做的程序或指令(一组步骤)。
如今,它们进化得如此之快,以至于即使完成同样的任务,它们也可能有很大的不同。在最极端的情况下(顺便说一下,这很常见),用不同编程语言编写的不同算法可能会告诉不同硬件和操作系统的不同计算机以完全不同的方式执行相同的任务。太疯狂了,不是吗?
事情是这样的,一种算法需要几秒钟才能完成,而另一种算法即使是很小的数据集也需要几分钟。我们如何比较不同的性能并选择最佳算法来解决特定的问题?
幸运的是,有很多方法可以做到这一点,我们不需要等到算法工作时才知道它是否能快速完成工作,或者它是否会在输入的压力下崩溃。当我们考虑一个算法的复杂性时,我们不应该真的关心所执行的操作的确切数量;相反,我们应该关心运算的数量如何与问题大小相关。想一想:如果问题规模翻倍,运算次数保持不变吗?他们会加倍吗?它们会以其他方式增加吗?为了回答这些问题,我们需要测量算法的时间复杂度。
时间复杂度代表一条语句被执行的次数。算法的时间复杂度不是执行特定代码所需的实际时间,因为它取决于其他因素,如编程语言、操作软件、处理能力等。时间复杂性背后的思想是,它只能以一种仅依赖于算法本身及其输入的方式来度量算法的执行时间。
为了表达算法的时间复杂度,我们使用了一种叫做“大 O 符号”的东西。大 O 符号是我们用来描述算法时间复杂度的语言。这是我们比较解决问题的不同方法的效率的方式,有助于我们做出决策。
大 O 符号根据算法相对于输入(该输入称为“n”)的增长速度来表示算法的运行时间。这样,举例来说,如果我们说一个算法的运行时间“按照输入大小的数量级”增长,我们可以用“O(n)”来表示。如果我们说一个算法的运行时间“与输入大小的平方成正比”,我们可以用“O(n)”来表示。但是这到底是什么意思呢?
理解时间复杂性的关键是理解事物增长的速率。这里讨论的速率是每个输入大小所用的时间。有不同类型的时间复杂性,所以让我们检查最基本的。
恒定时间复杂度:O(1)
当时间复杂度恒定时(记为“O(1)”),输入(n)的大小无关紧要。时间复杂度恒定的算法运行时间恒定,与 n 的大小无关。它们不会根据输入数据改变运行时间,这使它们成为最快的算法。

恒定时间复杂度
例如,如果您想知道一个数字是奇数还是偶数,您可以使用具有恒定时间复杂度的算法。不管这个数字是 1 亿还是 90 亿(输入“n”),算法都只会执行一次相同的操作,然后给你结果。
此外,如果您想一次性打印出一个短语,如经典的“Hello World ”,那么您也应该以恒定的时间复杂度运行,因为无论您使用哪种操作系统或哪种机器配置,这个短语或任何其他短语的操作量(在本例中为 1)都将保持不变。
为了保持恒定,这些算法不应该包含循环、递归或对任何其他非恒定时间函数的调用。对于常数时间算法,运行时间不会增加:数量级始终为 1。
线性时间复杂度:O(n)
当时间复杂度与输入的大小成正比时,您将面临线性时间复杂度,即 O(n)。具有这种时间复杂度的算法将在“n”次运算中处理输入(n)。这意味着随着输入的增加,算法完成的时间也相应增加。

线性时间复杂度
在这种情况下,您必须查看列表中的每一项才能完成任务(例如,找到最大值或最小值)。或者你也可以思考一些日常任务,比如读一本书或者找一张 CD(还记得吗?)在 CD 堆栈中:如果必须检查所有数据,输入大小越大,操作次数就越多。
线性运行时间算法非常常见,它们与算法从输入中访问每个元素的事实有关。
对数时间复杂度:O(log n)
具有这种复杂性的算法使得计算速度惊人。如果一个算法的执行时间与输入大小的对数成正比,则称该算法在对数时间内运行。这意味着不是增加执行每个后续步骤的时间,而是以与输入“n”成反比的幅度减少时间。

对数时间复杂度
它的秘密是什么?这些类型的算法从来不需要检查所有的输入,因为它们通常在每一步都丢弃大量未经检查的输入。这个时间复杂度一般与每次将问题分成两半的算法有关,这是一个被称为“分而治之”的概念。分治算法使用以下步骤解决问题:
1.他们将给定的问题分成相同类型的子问题。
2。他们递归地解决这些子问题。
3。他们恰当地组合子答案来回答给定的问题。
考虑这个例子:假设你想在一个所有单词都按字母顺序排序的字典中查找一个单词。至少有两种算法可以做到这一点:
算法 A:
- 从书的开头开始,按顺序进行,直到找到您要查找的联系人。
算法 B:
- 从中间打开书,检查上面的第一个单词。
- 如果你要找的单词按字母顺序排列比较大,那么它会出现在右半部分。否则,它看起来在左半部。
两者哪一个更快?算法 A 一个字一个字地进行 O(n),而算法 B 在每次迭代 O(log n)时将问题分成两半,以更有效的方式获得相同的结果。
对数时间算法(O(log n))是仅次于常数时间算法(O(1))的最快算法。
二次时间复杂度:O(n)
在这种类型的算法中,运行时间与输入大小的平方成正比(类似于线性,但为平方)。
在大多数情况下,特别是对于大型数据集,具有二次时间复杂度的算法需要大量时间来执行,应该避免使用。

二次时间复杂度
嵌套的 For 循环在二次时间上运行,因为您正在另一个线性操作中运行一个线性操作,或者 nn* 等于 n .
如果你面对这些类型的算法,你要么需要大量的资源和时间,要么你需要想出一个更好的算法。
指数时间复杂度:O(2^n)
在指数时间算法中,输入(n)每增加一次,增长率就增加一倍,通常会遍历输入元素的所有子集。每当一个输入单位增加 1,就会导致您执行的操作数量加倍。这听起来不太妙,对吧?
具有这种时间复杂度的算法通常用在你对最佳解决方案了解不多的情况下,你必须对数据尝试每一种可能的组合或排列。

指数时间复杂度
指数时间复杂度通常见于蛮力算法。这些算法盲目地迭代整个可能解的域,以搜索一个或多个满足条件的解。他们试图通过尝试每一种可能的解决方案来找到正确的解决方案,直到碰巧找到正确的方案。这显然不是执行任务的最佳方式,因为它会影响时间复杂度。在密码术中,暴力算法被用作攻击方法,通过尝试随机字符串直到找到解锁系统的正确密码来破解密码保护。
与二次时间复杂度一样,您应该避免运行时间为指数的算法,因为它们不能很好地伸缩。
如何度量时间复杂度?
一般来说,我们已经看到算法的运算越少,速度就越快。这看起来是一个很好的原则,但我们如何将它应用到现实中呢?
如果我们有一个算法(不管它是什么),我们如何知道它的时间复杂度?
在某些情况下,这可能相对容易。假设您有一个循环的外部,它遍历输入列表中的所有项,然后有一个嵌套的循环的内部,它再次遍历输入列表中的所有项。执行的总步骤数是 n * n,其中 n 是输入数组中的项数。
但是怎么求复杂函数的时间复杂度呢?
为了找到答案,我们需要将算法代码分解成几个部分,并尝试找出各个部分的复杂性。是的,很抱歉告诉你,但是没有一个按钮可以告诉你一个算法的时间复杂度。你必须自己去做。

主要时间复杂性
作为一条经验法则,最好是尝试让你的函数运行在线性时间复杂度之下或之内,但显然这并不总是可能的。
有不同的大 O 符号,像【最佳情况】**一般情况】和【最坏情况】,但真正重要的是最坏情况;这些会严重破坏一切。它们直击为什么时间复杂性很重要的核心,并指出为什么一些算法不花几十亿年就不能解决一个问题。
最坏情况分析给出了算法执行期间必须执行的基本操作的最大数量。它假设输入处于最糟糕的状态,必须做最大的努力来纠正错误。例如,对于旨在以升序对数组进行排序的排序算法,当输入数组以降序排序时,会出现最坏的情况。在这种情况下,必须执行最大数量的基本操作(比较和赋值)来以升序设置数组。请这样想:如果您必须在目录中通过阅读每个名字来搜索一个名字,直到找到正确的名字,最坏的情况是您想要的名字是目录中的最后一个条目。
综上所述,一个算法的时间复杂度越好,算法在实际中执行工作的速度就越快。你在设计或管理算法的时候应该考虑到这一点,考虑到这对于一个算法是实用还是完全无用有很大的影响。
任何认真的程序员都需要知道的基本 Python 概念和结构,解释

来源: Pixabay
生成器、面向对象编程、闭包、装饰器等等
本文将概述一些重要的 Python 概念,任何认真的程序员都应该知道并理解这些概念才能实现。这些概念形成了高级 Python 编程的框架,以智能地处理和实现问题。
发电机
用 Python 构建一个迭代器,一个可以迭代的对象,需要做大量的工作。一个类(面向对象的编程)必须用一个__iter__()和__next__()方法构建,内部状态必须被存储和更新,当没有值要返回时,必须产生一个StopIteration错误。

Python 中的迭代。作者创建的图像。
为了避免这个冗长的过程,Python 生成可以自动创建迭代器。上面描述的创建迭代器的所有过程都是由 Python 和生成器自动完成的。生成器是一个函数,它返回一个可以迭代的对象(迭代器)(一次覆盖一个值)。
生成器函数被定义为一个函数,但是使用了关键字yield而不是传统的return。如果函数体包含yield,那么它将自动成为一个生成器函数。
def simple_generator():
yield 1
yield 2
yield 3for value in simple_generator():
print(value)
前四行代码定义了生成器,它将迭代返回1、2和3。最后两行通过迭代打印输出值来演示迭代,输出:
1
2
3
一个生成器对象仍然需要一个函数来描述对象,但是需要设置为等于一个变量,在本例中为x。
x = simple_generator()
print(next(x))
print(next(x))
print(next(x))
例如,下面的代码创建一个斐波那契数列生成器,其中每一项都是前面两项(0、1、1、2、3、5、8、13、…)的和。
def fibonacci(limit):
a, b = 0, 1
while a < limit:
yield a
a, b = b, a+b
用于跟踪序列的两个数字是a和b,它们分别被初始化为 0 和 1。当a低于限值(函数中指定为参数的数字)时,程序产生(返回)a 的值。然后,a和b同时更新,其中a设置为b,而b设置为自身加上a。这将序列 1 向右移动,同时保留用于生成下一个序列值(前两个数字)的相关信息。

斐波那契序列发生器逻辑。作者创建的图像。
然后可以迭代生成器,在这种情况下使用 for 循环:
for i in fibonacci(8):
print(i)
因此,输出将遍历 Fibonacci 序列中值为 8 的所有元素:
0
1
1
2
3
5
面向对象编程
面向对象编程是 Python 的一个特性,它允许对方法和变量进行干净和有组织的存储。Python 中的面向对象编程(OOP)由class对象组成,其中包含关于该对象的信息。
例如,假设我们想用 Python 创建一只虚拟狗。一个类的个人属性存储在一个__init__函数中。必须包括self参数,以及创建时需要定义的该对象的任何其他属性,例如狗的species和age。
class dog:
def __init__(self, species, age):
self.species = species
self.age = age
可以用.在class对象内部调用对象的变量和函数,前面的元素引用对象,句号后面的项目引用被调用的对象。self.species = species将内部变量设置为输入参数species的值。
我们还可以在类中创建函数:
class dog:
def __init__(self, species, age):
self.species = species
self.age = age def bark(self, call='Woof!'):
print(call) def reveal_information(self):
print('I am a', self.species)
print('I am', self.age, 'years old')
这两个内部函数bark和reveal_information是由类执行和附加的方法。然后,我们可以为 dog 类设置一个变量pepper。我们必须指定初始化参数,species和age。
pepper = dog(species='German Shepard', age=3)
然后,我们可以调用pepper的属性:
pepper.reveal_information()
这将输出:
I am a German Shepard
I am 3 years old

面向对象的可视化类。作者创建的图像。
Python 中的面向对象编程适用于许多目的。尽管它可能需要更多的输入来设置,但它允许更多的可读代码。
关闭
闭包可以避免使用全局值,并提供了一种数据隐藏形式,为问题提供了一种面向对象的解决方案。当一个类中要实现的方法很少时,闭包可以提供一种替代的、更优雅的解决方案。当属性和方法的数量增加时,一个类就更合适了。以下标准演示了当嵌套函数引用其封闭范围内的值时 Python 中的闭包:
- 存在嵌套函数(函数中的函数)
- 嵌套函数引用封闭函数中声明的值
- 封闭函数返回嵌套函数

闭合图。作者创建的图像。
让我们用一个示例函数make_multiplier来演示闭包,它接受一个参数*n*并返回一个带有该参数的函数。
def make_multiplier(n):
def multiplier(x):
return x * n
return multiplier
创建一个将某物乘以 3 的函数的过程如下:
times3 = make_multiplier(3)
因为函数make_multiplier返回一个函数,times3是一个函数。
print(times3(9))
…返回…
27
…因为 3 乘以 9 等于 27。闭包可能是用 Python 完成这项任务的最佳方式。
内置枚举
Python 内置枚举牛逼。也许开发人员面临的最常见的任务是在跟踪索引的同时遍历列表中的一项。在许多没有枚举的其他语言中,程序员需要手动完成这项工作,例如在 Python 中:
counter = 0
for item in a_list:
do_something_with(item)
do_something_else_with(counter)
counter += 1
然而,Python 的enumerate()函数通过返回一个不可打包的元组来自动跟踪每次迭代的计数器:
for index, item in enumerate(a_list):
do_something_with(item)
do_something_with(index)
作为演示,下面的代码…
for index, item in enumerate(['a','b','c']):
print(index,item)
…会输出…
0 a
1 b
2 c
装修工
装饰者接受一个函数,向该函数添加一些功能,然后返回它。这在需要父函数的小变化的情况下非常有用,因为可以用装饰器来改变函数,而不是为需要的函数的每个变化重写函数。
假设我们有一个函数ordinary(),它的唯一目的是打印出一个字符串“I am an ordinary function.”
def ordinary():
print("I am an ordinary function.")
假设我们还想添加另一条消息,“I was decorated!”我们可以创建一个函数decorate(),它接收一个函数,打印添加的消息,然后调用原始函数,其对象作为参数输入到函数decorate()中。添加额外字符串和调用原始函数的过程可以存储在一个内部函数中,其对象用decorate()返回。
def decorate(function):
def inner_function():
print("I was decorated!")
function()
return inner_function
为了修饰原始函数ordinary(),我们将在原始函数上调用函数decorate()。我们存储decorate()输出到decorated的变量是一个函数(函数decorate()中的inner_function)。
decorated = decorate(ordinary)
decorated()
调用decorated()产生输出…
I was decorated!
I am an ordinary function.
装饰者使用@符号来自动装饰一个功能。
@decorate
def ordinary():
print("I am an ordinary function.")
在函数定义前使用@符号会自动修饰函数。它的计算方式与前面概述的修饰函数的方法相同。
通过在一个函数前添加几行@decorate,多个 decorators 可以相互链接。
感谢阅读!
如果您对代码示例或概念有任何疑问,请在下面的回复中提问。
数据科学项目的基本软件工具
Python,Matplotlib 样式,Git,Git 自述文件,Git 页面,VSCode,概念,语法

如有疑问,请始终选择“黑暗模式”选项!由克莱门特 Photo】在 Unsplash 拍摄的照片
在本文中,我们将研究如何设置一些工具,以实现更具可重复性和协作性的工作流。本指南将有助于人们开始他们的第一个 ML 项目,或者数据科学领域的资深人士在☕️意外洒出咖啡后重新设置他们的 MacBook🤦♂️.然而,鉴于这篇文章是在周五起草的,啤酒溢出的可能性要大得多。
免责声明:这里将描述的“基本软件”是基于作者的个人偏好和必然存在的一套更好的工具—请在评论中添加您的建议。本文绝不试图宣传或推广任何特定的软件,所有程序都可以免费获得。
需求:这里的指令将基于 MAC OS(v 10.15);然而,安装 Linux 或 Windows 也是可行的。
大纲:
这里的部分基本上是独立的,请随意跳过!
- Git:版本控制和代码备份是必须的。GitHub 允许你为你的项目创建一个吸引人的自述文件,甚至可以免费托管你的网站。
- Python:设置一个虚拟环境,用于包安装和分配一个默认的漂亮的绘图风格宏。
- VSCode:使用 Python 笔记本的一种更高级的方式。
- 理念:创建并分享关于你的项目的漂亮笔记。
- 语法上:提高你的写作技巧。
1.饭桶
这里,我们将假设对git和 GitHub 有一些熟悉。如果你真的想学习更多关于版本控制的知识,或者需要复习,去看看 Anne Bonner 的这篇令人惊叹的文章。与 GitHub 存储库交互的最有效方式是通过 iTerm2 这样的终端应用程序,它提供了惊人的 git 集成、自动建议和语法高亮显示,正如这里描述的。此外,它允许直接在终端中打开图像(和 gif)。

带有自动建议和语法高亮显示的 iterm 2(图片由作者提供)
你的项目不应该只有一个平淡无奇的自述页面,所以像这里描述的一样写一个吸引人的项目描述,并附上一些徽章(盾牌),如下所示。

https://github.com/badges/shields资源库的自述页面。(图片作者)
最后,如果你需要一个网站来托管你的项目,或者需要一个在线作品集来展示多个项目,GitHub 提供了工具来轻松做到这一点,正如埃米尔·吉尔在这里描述的。学习 HTML 和 CSS 技能的一个好方法是从 HTML5 UP 下载一个免费的网站模板,然后开始修补。

一个免费的 HTML5 模板,Strata,来自https://html5up.net/strata(作者提供图片)
2.计算机编程语言
这里我们将继续用pip和virtualenv进行 Python 包的 本地 安装。
如果你需要获得最新版本的 Python 使用 *brew install python* ( 看这里 如果你的笔记本电脑上没有 *brew* )。这将安装最新版本的 *python* 和 *pip* 。如果您已经安装了旧版本的 Python(例如 v2)并且 *python* 命令链接到它(检查 *python --version* ),brew 会使 *python3* 和 *pip3* 可用。
首先,安装环境管理器(如果 *python --version* 为 v2,则使用 *pip3* )
接下来,创建一个新目录,并在该目录中实例化一个新的 Python 环境
这将允许我们在那个环境中直接安装 Python 包,而不是“全局”安装。该环境需要用以下命令激活(每次登录)
您应该会在终端中看到(my_project_env)。如果您有许多要安装的软件包,只需将它们列在一个文件中——您也可以在其中指定版本— requirements.txt
然后让pip在my_project_env中一次性安装好
默认 Python Matplotlib 样式
如果希望您的绘图看起来比使用默认 Matplotlib 选项的绘图更有吸引力,可以设置自定义 Matplotlib 样式。这里有一个例子:

资料来自 奥雷连·杰龙的《动手机器学习》一书 。 ( 作者图片)
为了实现这种风格,下载这个宏文件 ml_style.mplstyle (随意修改/分发该文件),并将这些行添加到您的 Python/Jupyter 代码中
3.虚拟代码
Jupyter 在大笔记本之间切换标签时反应迟钝,令人有些沮丧。自从过渡到 VSCode 之后,Jupyter 就没有什么可错过的了:Python 笔记本的所有功能都在。此外,VSCode 是 Python、C、LaTeX 和其他文件的快速而强大的编辑器。此外,可以将 VSCode 设置为与其他更熟悉的编辑器(如 Sublime 或 Atom)具有相同的快捷方式和行为——答对了!
Bikash Sundaray 写了一篇关于为 Python 笔记本设置 VSCode 的伟大文章。此外,你可以连接到一个远程 Jupyter 会话上运行,例如,你的 GPU Ubuntu 服务器(更多关于这个在这里)用于神经网络训练。

VSCode Python 笔记本中的内联绘图和代码自动建议。(图片作者)
4.概念
一个强大的平台来做笔记和创建文档是必须的。它有两个目的:1)让你自己有条理,2)让你可以轻松地与他人分享你的笔记。概念允许你组织你的文档,并使任务、模板、会议、代码嵌入变得轻而易举。 Sergio Ruiz 写了一份综合指南,介绍如何利用这个概念的许多特性。

注意语法突出显示。(图片作者)
一封学术风格的电子邮件(即以。edu、英国等。)会免费授予你一个 Pro 版本。如果你以前使用过 Evernote,那么它提供了一个迁移工具,对我来说,它的效果和预期的一样。
注意:截至 2020 年 8 月,仅支持美国英语和韩语,英国英语(拼写检查)以及其他语言。
5.语法上
在你的模型上获得高准确度的分数是很棒的;然而,一个成功的数据科学项目需要有效地交流你的发现和方法。Grammarly——一个人工智能支持的语法、语气和风格助手——让你提高写作技能。

语法在行动!(图片作者)
请注意,ideal 将很快实现语法集成(与独立应用程序),希望如此。同时,只有通过浏览器打开概念时,Grammarly 才起作用。
编后记
我希望这篇文章有助于您开始数据科学项目。如果您有任何意见或建议,请告诉我。即将到来的后续文章将描述其他健壮的工具和方法(DevOps)来改进您的工作流。
推荐引擎的本质:基于内容和协同过滤

来源: altkom 软件&咨询
两种推荐引擎的描述和比较
你有没有想过为什么脸书上的广告与你感兴趣的东西如此相关,或者网飞上的“电影匹配”是如何工作的?是魔法吗?不会。在这两种情况下,推荐引擎或系统都会根据你的历史行为做出预测。
如果你是科幻电影迷,看过《星球大战》,推荐引擎可能会建议你看《阿凡达》。这种方法被称为基于内容的过滤,因为它分析每个项目的内容并找到相似的项目。虽然非常有用,但它需要对每个项目有透彻的了解,以便找到相似的项目。
我们还可以想到另一种情况,你的一个和你有很多相似之处的朋友告诉你“昨天,我去电影院看了乔治·卢卡斯的新电影,太棒了!你真应该去看看”。与其他用户有共同点也可以是推荐电影的好方法。下面是第二种推荐引擎:协同过滤。
在本文中,我将回顾基于内容的过滤和协作过滤背后的原理,然后对它们进行比较。
基于内容的过滤

这里的想法是推荐与你之前喜欢的物品相似的物品。该系统首先找到所有文章对之间的相似性,然后使用与用户已经评估的文章最相似的文章来生成推荐列表。
但是一个新的问题出现了:如何才能找到物品之间的相似之处?
为了比较两个项目,我们需要将它们转换为向量等数学对象,在此基础上,我们可以计算度量标准,如欧几里德距离、皮尔逊系数或余弦相似度。
以下是上述不同指标的公式:

一种常用的技术是 TF-IDF (频率术语—倒置文档频率)。它是一种统计度量,用于评估一个单词与一组文档中的一个文档的相关性。这是通过将两个度量相乘来实现的:单词在文档中出现的次数(术语频率)和该单词出现在文档中的次数的倒数(逆文档频率)。如果一部电影是像《星球大战》is 那样的科幻片,科幻这个词可能会在电影描述中出现很多,所以词条频率会高,如果电影语料库中科幻片不多,词条频率的倒数也会高。最后归一化后,TF-IDF 的值会接近 1。
如果我们将这种技术应用于一组胶片,在归一化之后,我们可以获得下表。此表中的数字是随机的似是而非的值。

现在我们有了描述电影的向量,我们可以计算这些向量中的两个向量之间的欧几里德距离、皮尔逊系数或余弦相似度。比如《星球大战》和《阿凡达》向量之间的欧氏距离是 0.05,而《星球大战》和《泰坦尼克号》之间的距离是 1.5。结果越接近 0,元素越相似。这样,我们就可以根据自己选择的特点(科幻、动作、言情)清楚地看到《星球大战》和《阿凡达》有多接近,《星球大战》和《泰坦尼克号》有多远。
正如您所看到的,对于这个方法,了解每个元素的内容是非常重要的。在下一部分中,我们将深入研究协作方法,它是一种同时基于用户和对象之间相似性的方法。
协同过滤
协同过滤不需要任何东西,只需要用户对一组项目的历史偏好。

协同过滤的标准方法被称为 最近邻 算法。我们有一个 n × m 的评级矩阵,我们称之为 r,用户矩阵表示为 u,项目矩阵表示为 p。用户 I 由向量 uᵢ表示,他们是 n 个用户,所以 i = 1,…n。项目由向量 pⱼ表示,他们是 m 个项目,所以 j=1, …m .现在,如果目标用户 I 没有观看/评价项目 j,我们想要预测评价 rᵢⱼ。该过程是计算目标用户 I 和所有其他用户之间的相似性,选择前 x 个相似用户,并且取这些具有相似性的 x 个用户的评价的加权平均值作为权重。 评级 rᵢⱼ的定义是:

然而,人们有不同的评分标准,有些人往往比其他人给出更高的分数。这种偏差可以通过在计算加权平均值时减去每个用户在所有项目上的平均分,再加上目标用户的平均分来避免,如下所示。

然后,我们使用皮尔逊相关、余弦相似度或欧几里德距离来计算相似度。
但是这种方法有一些限制。它没有很好地处理稀疏性,例如,当邻居中没有人对你试图为目标用户预测的项目进行评级时。
由于稀疏性和可伸缩性是标准 CF 方法的两个最大挑战,这里出现了一种更先进的方法,将原始稀疏矩阵分解为具有潜在因子/特征和更少稀疏性的低维矩阵。这种方法被称为矩阵分解。回想一下,R 是矩阵评级,我们想把 R 写成两个矩阵的乘积:U 是用户矩阵,P 是项目矩阵。由于分解不可能完全相等(R 与 U 和 P 的乘积稍有不同),我们引入了另一个称为 R '的矩阵,它表示预测的等级。它被定义为 p 与 U 乘积的结果。
矩阵 U 的行数等于用户数。矩阵 P 的列数等于项目数。矩阵 U 的列数等于矩阵 P 的行数,矩阵 P 等于潜在向量的数量。
在下面的例子中,我选择的潜在向量的数量等于 2。为了理解这种选择,我们需要查看 SVD 分解,其中潜在向量的数量是确保 r '能够捕捉原始矩阵 r 内的大部分方差的向量的数量,因此 r '是 r 的近似值,R' ≈ R。我们注意到 rᵢⱼ'是用户 I 对项目 j 的近似评级。因此,我们有:

这个想法是为了尽量缩小 rᵢⱼ和 rᵢⱼ'.之间的差异问题暴露如下:

但是,我们如何找到最优向量 uᵢ和 pⱼ呢?
回想一下,这些向量代表用户 I 和物品 j。如果您熟悉机器学习,为了进行预测,我们总是使用我们希望最小化的损失函数:

优化过程的目的是找到使损失函数最小的最佳 U 和 P。此外, L2 正则化已被添加,以防止用户和项目向量的过度拟合。
两种技术的比较
尽管在基于内容的过滤中,该模型不需要其他用户的数据,因为推荐是特定于该用户的,但它是协同过滤算法的核心。然而,对元素的透彻了解对于基于内容的算法是必不可少的,而在协同过滤方法中只需要元素评估。
与这一点密切相关的是引入新元素的问题,也称为“冷启动问题”。如果在训练期间没有看到某个元素,则系统不能为其创建嵌入,也不能使用该元素查询模型。虽然一些技术作为 WALS 中的投影或试探法存在,以生成新的嵌入,但是添加新的功能将增强基于内容的过滤方法。
PS:我现在是柏克莱大学的工程硕士,如果你想讨论这个话题,请随时联系我。 这里的 是我的邮箱。
你的模型的对数损失比随机猜测的对数损失好吗?
在二元或多类分类问题中,如何获得考虑类不平衡的随机猜测对数损失基线得分

介绍
你做了一个分类模型。
您在某处读到过关于对数损失作为一种评估模型性能的方法。关于对数损失幻数。
但与准确性不同,使用它并衡量你的模型得到的对数损失是好是坏并不是很直观,对吗?尤其是当你的班级不平衡的时候。
如果是,那么你点击了正确的链接!
在这篇文章中,我试图回答这些问题:
- 为什么是日志丢失?
- 什么是日志丢失?
- 与随机猜测相比,如何衡量模型性能?
- 班级不平衡怎么办?
- 当目标是多类时该怎么办?
- 你能给我适用于所有这些情况的代码吗?(当然,我可以!)
为什么是日志丢失?
建立一个模型只是完成了一半的工作。需要有一个评估指标来衡量模型的性能。在行业中,不同种类的度量标准被用来评估模型。度量标准的选择是模型类型和目标的函数。对于分类任务,混淆矩阵提供了几个度量标准可供选择,如准确度、精确度和召回率。
虽然分类准确性是最广泛使用的度量标准,但它可能是最容易误导的。准确度被定义为正确预测与总预测的比率。事实上,准确性并不能给出错误预测的信息。
具体来说,在两种情况下,准确性度量失败。第一,两个班以上的时候。模型可能会忽略一个或多个类。在这种情况下,该指标不会给出关于每个类别的个体准确性的信息。第二,当数据存在不平衡类时。例如,如果二进制分类数据集具有 90:10 的类别不平衡比率,那么具有 90%分类准确度的模型是不提供信息的模型。
为了解决这些限制,F1 分数是另一个度量,它被定义为精确度和召回率的调和平均值。精度是被正确识别的阳性病例的比例,而召回是被正确识别的实际阳性病例的比例。提高 F1 分数有助于同时提高准确率和召回率。取调和平均值是有意义的,因为与算术平均值相比,调和平均值对极值的惩罚更大。

作者图片
尽管作为一种度量,F1 分数比准确性好,但在分类模型中仍然存在缺点,其中类别预测是基于类别概率的。
考虑两个模型,其中对于特定观察,第一个模型预测概率为 0.6 的类别,而另一个模型预测概率为 0.9 的类别。F1 分数将对这些模型一视同仁,因为这两个模型都预测了此次观察的相同类别。它没有考虑预测的确定性。如果实际值为 1,那么两个模型都是正确的。但是第二种模式显然更好,不是吗?

比较精确度和 F1 与对数损失(图片由作者提供)
为了考虑分类概率,可以使用对数损失。Log-loss 是每个实例的校正预测概率对数的负平均值。
什么是日志丢失?
Log-loss 是每个实例的校正预测概率对数的负平均值。
对于具有真实标签 y ∈ {0,1}和概率估计 p=Pr(y=1)的二元分类,每个样本的对数损失是给定真实标签的分类器的负对数似然性:

作者图片
这延伸到如下的多类情况。假设一组样本的真实标签被编码为 1-of-K 二进制指示矩阵 y,即如果样本 I 具有取自一组 k 个标签的标签 k,则 yᵢ,ₖ = 1。设 p 是概率估计的矩阵,pᵢ,ₖ = Pr(tᵢ,ₖ=1).那么整个集合的对数损失为

作者图片
好了,理论到此为止。让我们直接讨论眼前的问题,好吗??
与随机猜测相比,如何衡量模型性能?
想象一下。我有一盒巧克力。它有 5 块黑巧克力和 5 块白巧克力。如果我让你不偷看盒子里的巧克力并猜它是哪一种,你会说有 50%的机会是黑色的,对吗?换句话说,你的随机猜测准确率是 50%。
也就是说,准确度分数在 50%以上的模型比随机猜测要好。在这里,你直观的知道 100%的准确率是最好的,0%是最差的。
对于日志丢失,事情不那么明显,也不那么直观。你需要把你的猜测代入上面给出的公式。
考虑一个有 10 个观察值的数据集。目标 y 有五个 1 代表黑巧克力,五个 0 代表白巧克力。如果你随机猜测,得到一个黑巧克力的概率,p = Pr(y =黑)=0.5。用 1 代替黑巧克力,用 0 代替白巧克力,上面的公式给出了下面的计算。

平衡二元分类的随机猜测对数损失(图片由作者提供)
取最后一列的平均值,瞧!你有你的随机猜测日志损失。因此,如果你的模型的对数损失小于(损失是负的,记住!?)0.693,肯定比乱猜强!
这就引出了我们的下一个问题,如果机会不是 50-50 呢?
班级不平衡怎么办?
还记得我那盒著名的巧克力吗?如果现在我告诉你它有三块黑巧克力和七块白巧克力,你不会说取出黑巧克力的机会是 50-50,对吗?
这里选一个黑巧克力的概率就变成了,p = Pr(y =黑)=3/10=0.3。现在,用 1 代替黑巧克力,用 0 代替白巧克力,看看下面的计算。

不平衡二元分类的随机猜测对数损失(图片由作者提供)
看看随机猜测 log-loss 是怎么从 0.693 降到 0.611 的?这意味着酒吧被设置了更严格的条件,嗯?该模型的性能需要优于 0.611。
最后,让我们看看当你的盒子里有更多种类的巧克力时会发生什么!美味,不是吗!?
当目标是多类时该怎么办?
这次我在盒子里放了 10 块牛奶巧克力。现在计算更加不直观了,但是请耐心听我说。这次我们有三种标签——黑巧克力、白巧克力和牛奶巧克力。
注意 y 代表拿起一种巧克力的事件。之前我们取 y=1 代表黑巧克力。于是 1-y 自动变成了白巧克力。然而,这一次,我们明确地说出了巧克力的类型。我们取 y1 =拿起一块黑巧克力的事件,y2 =拿起一块白巧克力的事件,y3 =拿起一块牛奶巧克力的事件。然后,根据随机猜测,
选择黑巧克力的概率=3/20=0.15
选择白巧克力的概率=7/20=0.35
选牛奶巧克力的概率=10/20=0.5
现在这些计算就有意义了。

不平衡多类分类的随机猜测对数损失(图片由作者提供)
这就对了。这个不平衡多类问题的随机猜测对数损失为 0.999。
请注意,每行的最后一个单元格表示上一节中给出的公式的内部求和。当将列相加时,在计算平均值时,表示外部求和。
好的,你明白了,但是当你遇到一个具有不同类别和患病率的新数据集时,该怎么办呢?你接着读下一部分,傻瓜。
你能给我适用于所有这些情况的代码吗?
这是一个 python 函数,它将类的比率列表作为输入,并输出一个随机猜测的对数损失。如果你的模型的对数损失小于这个数字,你的工作就完成了!
看到那个论点“多”了吗?我用它来按照输入的比率创建随机的观察样本。如果您给 multi=1000,代码将按照提供的比率创建 1000 个观察值。然后使用 sklearn 的 log-loss 函数得到你的基线。整洁,是吧!?
结论
在本文中,我解释了为什么 log-loss 是评估分类模型性能的好选择。我解释了它是什么,并展示了如何针对三种场景计算它——平衡二进制、不平衡二进制和不平衡多类分类。最后提供的 python 函数可以帮助您获得分类问题的基线。
参考
https://sci kit-learn . org/stable/modules/model _ evaluation . html # log-loss
在 LinkedIn 上和我联系!
在 GitHub 上看看我的一些很酷的项目!
估计人工智能项目成本和时间表:4 条经验法则
规划人工智能项目的实用指南
对于人工智能项目的“正确”方法还没有达成共识。你也不会找到专门针对人工智能项目成本和持续时间的公认的、经过验证的估算模型或基准。
关于常规 IT 开发需要多长时间有很多指导,但是大部分都倾向于关注从用户那里引出需求的活动,或者构建技术设计和编写代码。对于处于人工智能工作核心的更非结构化的工作来说,帮助要少得多——例如处理数据、评估算法和处理训练数据。
目前,估计人工智能工作的非传统部分往往更多地依赖于个人经验和预期,而不是更客观的东西。
这里有四条经验法则,可以帮助你决定为人工智能项目投入多少时间和精力,或者评估提交给你的评估。他们强调的是避免可能导致最令人不快的意外的陷阱。他们特别适用于那些在人工智能项目方面经验不足的人。

但是,首先提醒一下 IT 项目评估的一些基础知识。估计人工智能项目的成本是一种进化和适应。
可靠的 IT 项目评估的基础
IT 工作有一个当之无愧的名声,那就是大规模超支,尤其是大型的多年项目。然而,在过去的几十年里,现实发生了变化。IT 项目仍然会延迟,但是巨大的、引人注目的失败已经不那么常见了。
这种变化有几个原因。一个是更灵活的开发过程和更短的项目周期的流行。另一个是采用项目质量度量和持续改进。卡内基·梅隆大学的 CMM 著作在第二部中发挥了重要作用,对于 IT 新手来说仍然是无价的读物。
关于 IT 流程和项目管理方法仍然存在激烈的争论。然而,在给定相同信息的情况下,对 IT 项目报价的请求会产生来自大多数供应商的大致可比的估计。这将包括如何将整个工作分解成阶段或活动的类似分解,例如要求等。
这与人工智能项目相关,因为我们目前处于许多年前一般 IT 评估的位置:不一致,通常不可靠。一个很大的原因是人工智能开发过程各不相同,就像关于质量对人工智能交付品意味着什么的观点一样。因此,关于评估的讨论通常是由个人经验或项目约束驱动的,而不是更客观的东西。
在你如何构建人工智能方面创造一致性将会为评估未来的人工智能项目带来更客观的基础。这也将允许你改善和优化你的人工智能工作,并在与供应商的讨论中保持自己的优势。
评估人工智能项目:经验法则 1
没有可信的基准,最好是你自己的基准,不要计划大项目
不管你得到了什么样的承诺或数字表明了什么,你都应该明智地着手大型人工智能项目。如果你有人工智能工作的经验,你可能对所涉及的内容有一些基准。这些是验证大型预测人工智能项目成本的最佳方式。即便如此,要求其他客观数据来支持评估是值得的,最好是你可以验证的数据。客户推荐尤其有用。
如果你第一次体验人工智能,从大型项目开始的风险会更大。我总是建议从一个短时间的、相对低成本的练习开始。
这样,你的团队和合作伙伴将在你的组织中体验人工智能。这将是开发使用你的数据并连接到你的 IT 系统的人工智能解决方案的真实体验。对于人工智能项目成本和时间尺度的未来估计,这是一个比一般或行业数字更现实的基础。在第二个或第三个小项目之后,你将有一个更可靠的起点来评估更雄心勃勃的人工智能工作。
当开始使用人工智能时,有用的小项目可以短至 2-3 个月,而不是几个季度或几年。用几万或非常小的几十万英镑/美元/欧元就可能得到现实的结果;数十万或数百万的成本对结果造成了更大的压力。一个个位数规模的核心团队可能比几十个人中的一个更有效率和生产力。
如果建议你的人不这么认为,那么你可能要重新考虑选择范围或目标。当然,可能会有组织或商业因素影响观点。
评估人工智能项目:经验法则 2
接受某些阶段在本质上是“实验性的”,但是要控制住它们
人工智能工作的一个有时被误解的特点是,几天或几周的工作被“浪费”是正常的。这不一定是团队缺乏经验或缺乏能力的标志——尽管生产力当然会随着实践而提高。这是基础人工智能技术的反映,需要实验和一定程度的试错。
估算人工智能项目成本和时间表的一个挑战是,它们可能会成为——也许是无意的——“空白支票”,尤其是对人工智能供应商而言。诀窍是在有效结果的足够空间和允许“漂移”的工作之间找到正确的平衡。
大部分的 AI 课程,包括非技术类的,都参考了 EDA(或者某种等同物)的概念。这是探索性数据分析,大多数人工智能项目的关键早期部分。
处理“实验性”工作评估的技巧
一种常见的方法是将人工智能项目成本和时间表的估计分成两部分。对于 EDA,可能会有一个确定的估计,而对于项目的其余部分,可能会有一个更加试探性的估计。第二个估计只有在 EDA 结束时才被确认。到那时,对数据、业务问题和更广泛的 IT 环境会有更好的理解。
另一个选择是使用 IT 开发技术,比如时间盒来限制实验工作的持续时间。这反过来又将项目的其余部分限制在时间盒中发现的内容。这涉及到对像敏捷这样的开发方法的讨论。除了指出敏捷不是糟糕的评估的借口之外,在这里讨论细节是不合适的。
你如何处理一个人工智能项目的“实验”方面,不如认识到它们的特征重要。对于一个好的人工智能项目,评估的诀窍是限制实验阶段的持续时间,而不过度损害它们的有用性。
理想情况下,通过很好地使用这些阶段,您的团队可以在几天或几周后发现不可避免的错误或死胡同,而不是几个月。
评估人工智能项目:经验法则 3
决定如何平衡“好”和“足够好”之间的矛盾
数据科学家的一个关键角色是探索解决业务问题的不同方法,评估备选方案以确定最佳方案。而人工智能团队的业务成员是保持专注于人工智能工作的业务结果。从这个角度来看,人工智能是达到目的的一种手段,要尽可能快速、经济地达到目的。
这可能导致两种观点,即什么使一项任务“完成”,或者需要更多的努力。例如,如果一个算法达到 95%的“准确率”,数据科学家可能会认为这很差,但业务用户可能会不这么认为。
当然,正确的答案取决于算法的用途。这包括理解获得 95%正确答案的价值,以及 5%错误的成本/风险。这就是像精度、召回和 F1 分数这样的术语变得相关的地方,并导致诸如假阳性与假阴性的相对重要性的讨论。
这种平衡在实践中是什么样的?
为了更好地理解这一点,我们来看一个医学诊断的例子,比如癌症检测。“5%的误差”的含义是模糊的。一种可能性是,5%接受筛查的患者认为他们没有癌症,但实际上患有癌症。相反,这可能意味着 5%被标记为患有癌症的患者实际上都是健康的。
决定追求更精确的算法还是停留在 95%的精确度需要理解这样的差异。理想情况下,还要意识到相关的商业价值。
- 为了获得更高的精确度,可能需要进一步调整模型;
- 如果 95%接近算法性能的极限,则可能需要其他算法;
- 第三种选择可能是重新审视各种选择,以获取或准备更好的数据;
- 正确的答案可能是接受 95%的准确率,即使可能更好。
这只是一个例子。在人工智能工作期间,在“正确”答案上可能会有几个这样的潜在冲突。每个都会影响人工智能项目的评估。
人工智能项目领导的角色就是平衡这两种心态。项目期间已经够棘手的了。即使有事实,两种观点都可能有令人信服的论据。
很难——可以说是不可能——在这种可能性出现之前准确地考虑到它们。因此,在一开始估计人工智能项目的成本和持续时间时,需要考虑到这一点。这包括在团队内部就如何处理此类决策达成一致。
评估人工智能项目:经验法则 4
对数据“运作”有现实的预期和意外情况
第四条经验法则的出现是因为人工智能的结果通常需要大量的数据准备工作。在项目评估中,这项工作经常被忽视。
获得足够的适当数据来“喂”一个人工智能解决方案可能是人工智能工作中的一个黑洞,尤其是对粗心的人来说。数据准备可能会耗费过多的精力,有时甚至可能不是供应商报价的一部分。
一个挑战是知道你的环境真正需要多少数据。另一个是确保它被适当地包含在估算中。
请特别仔细地查看供应商对此处问题的评估。数据准备有时会完全从报价中消失,被埋没在提案假设中。另一种方法是允许一个象征性的几天,知道它会立即扩大。
估计数据准备工作
为了涵盖这些可能性,你的团队需要了解哪些相关数据是可用的。这包括它有多完整、准确和可靠,以及可以和不可以用它做什么(例如法律、监管、道德)。
没有这种理解,任何人都不可能可靠地预测准备数据的工作量和成本。这种理解包括真正的数据是什么,数据处于什么状态(完整性、准确性等),以及准备和清理数据的工作。这是估计人工智能项目成本和时间表的另一个棘手的部分。
如果你的组织已经在你考虑的领域做了人工智能或分析工作,这些信息可能是可用的。它可能不会出现在正式的文档中,但是希望有具备相关知识的人来帮助确定数据准备工作的规模。
如果您没有理解数据准备的知识,您将需要一个范围界定练习,称为探索性数据分析(ed a)。如果供应商这样做,您应该期望数据准备活动和评估作为可交付成果是清晰的。
估算人工智能项目成本&时间表:总结
人工智能流程和基准是长期评估准确性的关键
估计人工智能项目的成本和时间比常规的 IT 工作更难。这在一定程度上是由于缺乏 AI 行业流程和基准。结果是更多地依赖于你的人工智能专家和供应商的经验、判断和意见。
如果人工智能是你经常做的事情,考虑在你的前几个项目中创造你自己的人工智能工作方法。您将为自己的组织获取人工智能项目成本和工作数据。对你来说,这将比行业数据更可靠,并为持续改进提供基准。这不一定是一个困难的练习,也不会增加太多的开销。事实上,它应该通过未来工作中的储蓄迅速收回成本。
评估较小的项目更容易,尤其是在早期
与此同时,在开始人工智能项目时,从小处着手通常是必经之路。
不管项目大小如何,有一些明显的领域的估计可能是过度的或过于乐观的。如果你依靠供应商来交付你的工作,尤其如此。
考虑在进行过程中评估每个阶段
有效地使用 EDA,以及良好的项目管理实践会非常有帮助——尤其是像敏捷这样的迭代方法。你还需要平衡不同团队角色的本能和优先级,尤其是在工作的“实验”阶段。
这篇文章最初发表于www.aiprescience.com。
用机器学习估算建筑物的反事实能耗
我们可以制作 ML 模型来预测建筑的能源使用吗?绝对的!

目录表
- 摘要
- 背景
- 材料和方法
- 结果和结论
- 参考
1.摘要
美国供暖、制冷和空调工程师协会(ASHRAE)是世界上最大的能源效率研究协会之一。它们成立于 1894 年,拥有 54 000 多名成员,服务于 132 个国家。自 1993 年以来,他们已经举办了 3 次大型数据竞赛,旨在预测建筑能耗。最近的一次是 2019 年 10 月在 Kaggle 上举办的。在这次比赛中,前 5 名选手分享了总计 25,000 美元的奖金。第一名团队获得 10,000 美元奖金。比赛于 2019 年 12 月 19 日结束。我参加比赛较晚,但由于我的机械工程背景(ME)和对机器学习的热情(ML),我对比赛非常感兴趣。因此,我决定在到期日之后解决这个问题,以便更好地理解 ML 以及它如何应用于我的领域,即我。因此,本文试图根据最近 2019 年 10 月 Kaggle 的数据,调查一座建筑将消耗多少能源。为什么?因为正如竞赛状态:
评估能效改进的价值可能具有挑战性,因为没有办法真正知道一座建筑在没有改进的情况下会使用多少能源。我们能做的最好的事情就是建立反事实模型。建筑物大修后,新的(较低的)能耗将与原始建筑物的模拟值进行比较,以计算改造后的节约量。更准确的模型可以支持更好的市场激励,并实现更低成本的融资。

图 0.0 来自 IPMVP 的节能干预预测模型的使用。此图说明了预测模型的使用,并与长期建筑性能模型的节能进行了比较。⁴
2.背景
为了进行这种分析,使用来自 ASHRAE 及其贡献者的数据,用 Python 构建了四个 Jupyter 笔记本。⁴ ⁵ ⁶ ⁷
原始输入数据来自 6 个不同的文件,其中有 17 个独特的特征。
如上图,有16独特的site ids,托管1448独特的建筑。建筑的主要用途(primary_use)属于16的独特类别(即办公、教育等)。除此之外,还有4独特的仪表来测量能源使用情况(1.chilled water、2.electric、3\. hot water、4\. steam)。
此外,由于时间范围在 2015 年和 2018 年之间,因此有超过6100 万个唯一时间戳!这是大量的数据。事实上,那些用于训练和测试的文件的大小分别为 ~0.7 和 1.4 GBs ,需要一种不简单的数据处理方法!
快速免责声明:出于教育目的,允许在比赛之外使用数据:
数据访问和使用。您可以出于任何商业或非商业目的访问和使用竞赛数据,包括参加竞赛和 Kaggle.com 论坛,以及学术研究和教育。
这些模型的准确性基于均方根对数误差(RMSLE)进行评估:

方程式 0。用于模型评估的均方根对数误差(RMSLE)。
其中:
ϵ是 RMSLE 值(分数)n是(公共/私有)数据集中的观测值总数,pi是你预测的目标,而ai是i的实际目标。log(x)是x的自然对数。
3.材料和方法

图 0.1 所用 Jupyter 笔记本的整体流程图。
有一件事变得很明显,那就是这个问题的“泄露”数据的来源。⁹:我不想使用“泄露”的数据,因为我想对我的模型如何在未知的未来数据上工作进行公平的评估。在我看来,这是一个更有价值的方法,尤其是因为我不是为了比赛而这样做。在比赛中,这很常见,而且似乎是获胜的唯一途径。
我的方法的独特之处在于,我用Site_ID分解了问题。因此,我的方法将数据分成 16 个模型,因为有 16 个唯一的Site_ID数字。这大大减少了一次训练的数据量。这也让我能够专注于每个Site_ID的独特差异。无论我在Site_ID中注意到什么趋势,我都能够更好地为其建模。基本的总聚集方法不会出现这种情况。
大多数人似乎聚集了所有的数据来形成预测,产生一个 ML 模型来预测未来的能源使用。一些人尝试按仪表类型分割数据,因此有 4 种不同的型号。⁸的一些人试图根据一年中训练的时间将数据一分为二。获胜的⁰团队对“泄露”的数据以及Site_ID、Meter和Building & Meter的组合进行了混合和堆叠。
在网上做了一些挖掘后,我找到了威廉·海登·⁵最近的一篇论文,其中描述了一些与获胜团队有相似之处的方法。他的论文不是专门针对这个问题,而是针对 187 种家庭能源使用。
“首先,每个家庭被独立地建模,产生总共 187 个模型,这些模型的预测被聚合以形成总预测。第二,将家庭汇总,开发一个单一模型,将客户群视为一个单一单元。第三种选择是根据每个家庭的平均日负荷情况对类似的家庭进行分组⁵
我们的问题有 1448 个独特的建筑,这意味着理论上我们可以制作 1448 个独特的模型,就像威廉的第一种方法一样。然而,这种方法在威廉的论文中并不是最优的。最佳方法是根据每个家庭的平均日负荷概况对数据进行聚类(选项 3)。
因此,我的方法是对每个Site ID使用类似于最优方法的东西,因为它们通过单向 ANOVA ( p 值~0 )似乎具有统计上不同的平均值meter readings。这意味着我们可以拒绝零假设(每个站点都有相同的平均值meter reading),假设异常值和杂乱的数据没有掩盖真实的平均值。
import pingouin as pgaov = pg.anova(data=data_train, dv=’meter_reading’, between=[‘site_id’], detailed=True)

图 0.2 原始训练数据的箱线图,通过将 y 轴限制为 2000 千瓦时排除异常值。请注意,站点 13 的平均值甚至不在此范围内。

图 1.0Part-1-divide . ipynb .流程图
第一部分。按唯一的站点 ID 划分数据
Part-1-Divide.ipynb 是一个很短的笔记本,但是非常有效。
制作输出文件的目录。这是我制作 16 个独特的输出文件夹的地方,如图 1 所示。为每个站点 ID 创建唯一模型时,这些文件夹是导入和导出文件的占位符。
Splits =['Site_ID_0',
'Site_ID_1',
'Site_ID_2',
'Site_ID_3',
'Site_ID_4',
'Site_ID_5',
'Site_ID_6',
'Site_ID_7',
'Site_ID_8',
'Site_ID_9',
'Site_ID_10',
'Site_ID_11',
'Site_ID_12',
'Site_ID_13',
'Site_ID_14',
'Site_ID_15']
导入和查看数据。在用 unique Site ID分割数据之前,我只是确保数据如上所述在那里。我确保Site ID没有空值,并且我还确保我可以捕获每个时间戳的索引或引用。这对于在过程结束时将所有东西粘在一起是至关重要的。
building = **file_loader**(building)
weather_train_data = **file_loader**(weather_train_data)
data_train = **file_loader**(data_train)
weather_test_data = **file_loader**(weather_test_data)
data_test = **file_loader**(data_test)







图 1.1。部分数据来自 Part-1-Divide.ipynb Jupyter 笔记本。
减少数据内存。这些文件非常大!光是 T2 的文件就超过了 1 GB。因此,我需要找到一种方法来减少这些文件的内存,而不丢失有用的信息。我在 Kaggle 讨论板上发现了一些非常有用的数据缩小策略,我认为它们不仅对这个项目,而且对未来的项目都非常有用。本质上,您可以通过搜索数据类型并分别对其进行更改,将数据减少到最少的信息量。当您试图一次运行所有数据来训练 ML 模型时,为了保持脚本运行并且不使您的计算机崩溃,这是绝对必要的。我在余下的工作流程中使用了这个策略。
building = **reduce_mem_usage**(building)
weather_train_data = **reduce_mem_usage**(weather_train_data)
weather_test_data = **reduce_mem_usage**(weather_test_data)
data_train = **reduce_mem_usage**(data_train)
data_test = **reduce_mem_usage**(data_test)
合并数据。在我把主要文件简化成最小的有用形式后,我把它们合并在一起。
data_train**.merge**(building, on=’building_id’, how=’left’)
data_train**.merge**(weather_train_data,
on=[‘site_id’,‘timestamp’], how=’left’)data_test**.merge**(building, on=’building_id’, how=’left’)
data_test**.merge**(weather_test_data,
on=[‘site_id’,‘timestamp’], how=’left’)
划分&导出数据。pickle功能是在这些文件合并和分离后导出它们的一个很好的工具。
count=0
for Split_Number in list(Splits):
dummy = data_train[(data_train[‘site_id’]==count)]
# OUTPUTS: Folder for storing OUTPUTS
print(Split_Number)
dummy.to_pickle(os.path.join(OUTPUT_split_path[count],
‘site_id-{}-train.pkl’.format(count)))
count+=1

图 2.0Part-2-and . ipynb .流程图
第二部分。探索性数据分析和清理
我开始盲目地研究这个问题,没有看讨论板。这让我走上了一条痛苦的道路,寻找并试图理解如何处理缺失和零值数据。然而,这并没有走多远,因为原始数据是如此的杂乱和庞大。
于是,我开始阅读人们对大量杂乱数据所做的工作,并发现了几种解决方法。人们很快指出他们发现的异常值:
- 建造前显示电表读数的建筑物。⁰
- 长时间的持续读数。
- 大正负尖峰。
- 具有在相同频率下出现仪表读数异常的建筑物的站点。
- 一般来说,建筑物缺少数据或值为零(这是我马上注意到的一个明显的问题)。
对于缺失的数据,我做了这个小函数,missing_table,为了捕捉和总结。
missing_table()
**def** **missing_table(**data_name**):**
non_null_counts = data_name.count()
null_counts = data_name.isnull().sum()
total_counts = non_null_counts+null_counts
percent_missing= round(100*null_counts/total_counts,1)
min_non_null = data_name.min()
median_non_null = data_name.quantile(q=0.5)
max_non_null = data_name.max()
missing_data=pd.concat([total_counts,non_null_counts,
null_counts,percent_missing,
min_non_null,median_non_null,
max_non_null],axis=1,keys=
['Total Counts','Non-Null Counts',
'Null Counts','Percent Missing(%)',
'Non-Null Minimum','Non-Null Median',
'Non-Null Maximum'])
**return** missing_data

图 2.1。站点 ID 15 中缺失数据表摘要的示例。有很多数据缺失!
我是如何处理这些混乱的?良好的..我首先对数据进行了每小时一次的向上采样,因为这是数据以原始形式出现的最频繁的时间。但是这样做会增加更多的空值,因为它会为未记录的小时数创建时间戳。因此,我做了以下工作,通过一系列的删除、填充空值、插值、向前填充、向后填充以及最后再次填充空值来填充这些空白和之前缺失的大量内容。
重采样(“H”)。均值()
我对数据进行了向上采样,取平均值,然后按其独特的building_id、meter、site_id、primary_use和square feet进行分组。这为其他项目如air_temperature、dew_temperature、wind_speed等留出了一些空间。不过这不是问题。插值将处理大部分这些差距。
pd.to_datetime(data_train["timestamp"],format='%Y-%m-%d %H')
data_train=data_train.set_index('timestamp')
pd.to_datetime(data_test["timestamp"],format='%Y-%m-%d %H')
data_test=data_test.set_index('timestamp') grouplist=['building_id','meter','site_id',
'primary_use','square_feet']
data_train.groupby(grouplist)**.resample('H').mean()**
data_train.drop(grouplist,axis=1)
data_test.groupby(grouplist)**.resample('H').mean()**
data_test.drop(grouplist,axis=1)
dropna()
如果一个列有我认为太多丢失的数据,我会将其删除。因此,对于一个站点中丢失数据超过 40%的列,我执行了以下操作:
thresh = len(data_train)*.6
data_train**.dropna**(thresh = thresh, axis = 1, inplace = True)
thresh = len(data_test)*.6
data_test**.dropna**(thresh = thresh, axis = 1, inplace = True)
菲尔娜()
当对数据进行上采样时,我不想失去对索引的跟踪,因此,我通过将新值设置为-1 来跟踪原始索引以供参考。
data_train['index']**.fillna**(-1, inplace = True)
data_test['index']**.fillna**(-1, inplace = True)
内插()
以下连续参数因缺失值而被插值。
data_train['meter_reading']**.interpolate()**
data_train['air_temperature']**.interpolate()**
data_train['dew_temperature']**.interpolate()**
data_train['cloud_coverage']**.interpolate()**
data_train['precip_depth_1_hr']**.interpolate()**
data_train['sea_level_pressure']**.interpolate()** data_train['wind_direction']**.interpolate()**data_test['air_temperature']**.interpolate()**
data_test['dew_temperature']**.interpolate()**
data_test['cloud_coverage']**.interpolate()**
data_test['precip_depth_1_hr']**.interpolate()**
data_test['sea_level_pressure']**.interpolate()** data_test['wind_direction']**.interpolate()**
pad()
通常在这一点上不会丢失太多数据。这个前向填充函数, pad() ,通常得到最后一位。它使用最后一个已知的值,如果缺少该值,则将其向前移动到下一个值。
grouplist=['building_id','meter','site_id',
'primary_use','square_feet']data_train=data_train.groupby(grouplist)**.pad()**
data_test=data_test.groupby(grouplist)**.pad()**
isnull()
此时,我将使用 isnull() 函数来检查我是否遗漏了什么。如果是,我就用之前的 fillna() 带中值或者完全丢弃。此外,我还在 Jupyter 笔记本上记下了每个站点的 ID,以备不时之需。
data_train.isnull().sum()
data_test.isnull().sum()
好了,现在数据至少是完整的了。离群值呢?
我主要做了两件事:
- 降低了超出正常值的仪表读数(峰值)。
我认为它们会使我们很难做出一个精确的 ML 模型,因为还有很多其他的假设。
data_train.drop((data_train.loc[data_train['meter_reading']> 1.5e+04])['meter_reading'].index)
2.降低了零值仪表读数。
我认为这些应该是数据,或者它们是在前面的步骤中填充的,因为那里实际上什么也没有。这在后来可能有点多余,但至少是包容性的。
data_train.drop((data_train.loc[data_train['meter_reading']== 0])['meter_reading'].index)
现在我们可以看到一些东西了!
很难查看混乱且缺少大量值的数据。既然数据已经清理完毕,我只想验证一下。这里有几幅图显示了几个站点的air_temperature分布。你可以看到这些地方有他们自己的季节,可能在地理上有不同的气候。请注意,位置 13 为左偏斜,位置 12 为正常,位置 14 为双峰分布。



图 2.1。一些不同地点的气温数据显示了它们独特的分布。

图 3.0Part-3-convert . ipynb流程图。
第三部分。特征工程、特征提取和机器学习。
特征工程()
**def** **feature_engineering(**data**)**:
data[**"hour"**] = data["timestamp"].dt.hour
data[**"week"**] = data["timestamp"].dt.week
data[**"month"**] = data["timestamp"].dt.month
data[**"weekday"**] = data["timestamp"].dt.weekday data[**'Sensible_Heat'**] = 0.5274*(10.**
(-4.))*data['square_feet']*(75.-data['air_temperature'])
data[**'log_square_feet'**] = np.log(data['square_feet'])
data[**'log_floor_count'**] = np.log(data['floor_count'])
data[**'square_dew_temperature'**]
=np.square(data['dew_temperature'])
*# Holidays*
holidays = ["2016-01-01", "2016-01-18", "2016-02-15", "2016-05-30", "2016-07-04",
"2016-09-05", "2016-10-10", "2016-11-11", "2016-11-24", "2016-12-26",
"2017-01-01", "2017-01-16", "2017-02-20", "2017-05-29", "2017-07-04",
"2017-09-04", "2017-10-09", "2017-11-10", "2017-11-23", "2017-12-25",
"2018-01-01", "2018-01-15", "2018-02-19", "2018-05-28", "2018-07-04",
"2018-09-03", "2018-10-08", "2018-11-12", "2018-11-22", "2018-12-25",
"2019-01-01"]
data["**is_holiday"**] =(data.timestamp.dt.date.astype("str").isin(holidays)).astype(int)
**return** data
大多数人似乎把工程师的使用时间放在他们一边。例如,一年中的星期是与目标能量使用有很强相关性的常见特征。这是有意义的,因为一年有冬天和夏天之类的季节,而周数(即 52 周中的 51 周,冬季周)会告知你处于哪个季节。我使用了其中的一些时间策略,但是在问题的机械工程方面更深入了一些。我将所有这些基本特征视为我在日常工程生活中使用和处理的方程的输入。我想我可以设计一些可能与目标结果有关系的新功能。
因此,我钻研了热力学和暖通空调的定律。
我们希望根据建筑使用数据和环境天气数据,预测给定电表的能源使用量。了解所涉及的因素以及它们之间的关系非常重要。
大图观点来自热力学第一定律:

等式 1。热力学第一定律。
其中:
- 问:系统是否增加了热量
- w 是系统做的功
- δU 是内能的变化。
因此,这些建筑根据环境条件(即air temperature、dew temperature、wind_speed、wind_direction和cloud_coverage)改变它们添加或移除的热量,需要能量形式的工作(电、蒸汽等)。
每栋建筑与热力学第一定律之间的一个重要联系是建筑的供暖、通风和空调(HVAC) 单元。
影响这些 HVAC 装置添加或移除热量的效率的因素可能与建筑物的年龄有关(year_built)。由于过时的 HVAC 设备,旧建筑在添加或移除热量方面可能效率较低(除非它们被翻新!).如果暖通空调系统多年来没有得到适当的维护,那么它可能会由于制冷剂或气流问题而产生不像正常情况下那么多的冷空气。 ⁷
基于房间居住者显热的排热通风率可表示为:

等式 2a。排热的房间通风率。
其中:
q_dot是房间的显热去除率。rho是房间的平均空气密度。cp是室内空气的恒定比热。Vroom是房间的体积。Tid是房间的室内设计温度(通常为 75 华氏度)。Tin是进入室内空气的温度。
因此,由于更多的人和更大的空气量,更大的建筑可能需要更多的能源或 HVAC 容量。建筑物内的空气体积与房间的数量及其各自的体积成正比。因此,建筑的平方英尺(square_feet)与建筑空气量成正比,而建筑空气量与通风所需的显热移除量成正比。然而,所需的最小通风率取决于建筑类型和各个房间的独特要求,如 ASHRAE 标准 62.1 中所述。对于粗略的比例关系,我们可以在此基础上设计一个新变量qs,即每栋建筑的显热去除率,如下所示:

等式 2b。显热去除的特征工程步骤概要。
尽管有标准! ASHRAE 标准 62.1 ,规定了所需的呼吸区室外空气(即呼吸区的室外通风空气)Vbz,作为区域占用量Pz和区域占地面积Az的函数。⁶第一项(RpAz)说明了占用产生的污染物,而第二项(RaAz)说明了建筑产生的污染物。ASHRAE 标准 62.1 要求在所有负载条件下运行期间保持以下速率:

等式 3。ASHRAE 标准 62.1 最低要求呼吸区室外空气流速。⁶
其中:
Vbz是呼吸区所需的最小室外空气流量Rp是人室外空气流速Pz是区域占用Ra是该区域的室外空气流速Az为分区建筑面积。
因此,每栋建筑(building_id)可能都有其自己独特的设计要求,这是基于通用的 ASHRAE 62.1 标准。进入该标准的输入是基于占据该房间的设计人数和被占据的建筑或房间的类型。例如,一个Educational区域可能需要一个10 cfm/person,而一个Office Building区域可能需要该房间中的5 cfm/person。⁶:这意味着我们可以根据建筑类型来预测不同的能源使用组合(primary_use或site_id)。















图 3.1。最终运行中不同站点 ID 结果的特征重要性图。
拆分数据
我对数据进行了分割,以便在每个季节捕捉一部分数据,用机器学习(ML)算法进行训练和验证。所以冬天是 1 月(1)攻陷,春天是 4 月(4)攻陷,夏天是 7 月(7)攻陷,秋天是 10 月(10)攻陷。因为我们有如此多的数据,我进一步把它分成两半。因此,其中一半的测试月被用于培训。根据Site_ID的不同,这在 75%到 90%的训练范围内,这在 80%的经验法则范围内。这是一个时间序列回归问题,因此重要的是不要在一个月内获得所有数据,也不要因为过度拟合而过于频繁。我相信我分割它的方式是一个公平的方法,因为只有全年的训练数据。它大致等间隔地预测未来两年。
final_test = test
test = train[(train['timestamp'].dt.month.isin([1,4,7,10]))]
train_w, test = train_test_split(test,test_size=.50,random_state=42)
train = train[(train['timestamp'].dt.month.isin([2,3,5,6,8,9,11,12]))]
train=pd.concat([train,train_w],axis=0)
缩放数据
我使用了minmax scaler()为 ML 算法获取 0 到 1 之间的值。我意识到使用standard scaler()可能会更好,因为可能会有异常值。
*#Scale Data*
scalerTrain = MinMaxScaler(feature_range=(0,1))
X_train=scalerTrain.fit_transform(X_train)
X_test=scalerTrain.transform(X_test)
X_final_test=scalerTrain.transform(X_final_test)
****机器学习用light GBM
在最终决定使用 LightGBM 回归器之前,我尝试使用随机森林回归和 XGBoost 回归器。从我的初步运行来看,随机森林的准确性要差得多,训练的时间也要长得多。XGBoost 不如 LightGBM 精确,而且耗时更长。针对这些问题的培训可能需要几个小时,这取决于如何设置。
最初,当我把所有的数据都扔给算法时,需要一夜的时间,通常我的内核会崩溃。我甚至上了谷歌云平台,开始从云端运行模型。连那些内核都崩溃了…哈哈。这是另一个原因,我决定去与 16 个不同的模型更小。这些数据对我来说是可以管理的。我可以看到我在做什么,并且在需要的时候可以修理东西。我还可以完成工作,而不会让我的计算机从所有的 RAM 分配到本地运行中变慢到停止。
所以我最终微调了一些超参数,但可能还不够好。主要是因为做这些事花了这么长时间。但是在我写这篇文章的时候,我看到了我的跑垒和上一次跑垒之间的巨大进步。基本上,我的基本跑的均方根对数误差(RMSLE)是 1.566,我的最终跑是 1.292(好了大约 20%)。我知道这些分数不是最大的,但这不是整件事的重点,因为这是后期比赛。这是一次学习经历。
我对 LightGBM 的最佳超参数是:
best_params = {
"objective": "regression",
"boosting": "gbdt",
"num_leaves": 1500,
"learning_rate": 0.05,
"feature_fraction": ([0.8]),
"reg_lambda": 2,
"num_boost_round": 300,
"metric": {"rmse"},
}
我将已经像前面提到的那样分割的训练数据分割成 3 个 K 倍,用于训练/验证,如下所示:
kf = KFold(n_splits=3,shuffle=**False**)
count =0
models = []
**for** params **in** list(params_total):
print('Parms: ',count )
**for** train_index,test_index **in** kf.split(features_for_train):
train_features = features_for_train.loc[train_index]
train_target = target.loc[train_index]
test_features = features_for_train.loc[test_index]
test_target = target.loc[test_index]
d_training = lgb.Dataset(train_features,
label=train_target,
free_raw_data=**False**)
d_test = lgb.Dataset(test_features,
label=test_target,
free_raw_data=**False**)
model = lgb.train(params,
train_set=d_training,
valid_sets=[d_training,d_test],
verbose_eval=100,
early_stopping_rounds=50)
models.append(model)
count += 1
然后我在测试集上预测(不是最终测试集!),该模型的性能如何,如下所示。注意,因为有 3 个折叠,所以产生了 3 个优化的最佳模型(best_iteration)。因此,对我来说,最后的结果是基于这三个的平均值。
我在最后的测试中使用了相同的方法,这意味着在训练/验证之后,我没有改变我使用的模型。我只是看了看下面显示的数字,看看模型在我可以与之比较的数据上的表现如何,然后再扔向我无法与之比较的数据(看不见的未来测试数据,2017 年至 2019 年)。他们看起来表现很好!RMSLE 小于 1,对于大多数 all (>0.9),相关系数很强。
results = []
**for** model **in** models:
**if** results == []:
results = np.expm1(model.predict(features_for_test, num_iteration=model.best_iteration)) / len(models)
**else**:
results += np.expm1(model.predict(features_for_test, num_iteration=model.best_iteration)) / len(models)















图 3.2。用 LightGBM 对实际目标测试数据与预测值进行线性回归比较。

图 4.0Part-4-all siteids . ipynb 流程图
4.结果和结论
第四部分。一起评估所有模型。
所以…现在是时候总结所有 16 个site_id预测的所有结果了。
count=0
**for** Split_Number **in** list(Splits):
dummy= os.path.join(OUTPUT_split_path[count],
"test_Combined_Site_ID_**{}**.csv".format(count)) dummy2 = pd.DataFrame(file_loader(dummy))
**if** count == 0:
test_Combined = dummy2
**else**:
test_Combined =
pd.concat([test_Combined,dummy2],axis=0)
count+=1

图 4.1。显示出比跑垒有进步。
就像前面提到的,RMSLE 有了很大的提高,公开分数和私人分数都提高了近 20%。显然,进一步调整 ML 超参数和数据清理可能有助于获得更好的分数。我觉得印象比较深刻的是下图!
那么…这些数字到底是什么样子的呢?!














****
图 4.2 每个站点 ID 上所有建筑物的所有仪表读数的平均每小时消耗量(kWh)。
嗷。我认为那看起来令人印象深刻!这是我们在训练模型时不知道的未来两年(红线),从直觉上看,这非常合理。蓝色的线显示了我们对数据的预测,这看起来也是合理的。我认为我们可以有把握地说,我们可以制作机器学习(ML)模型来预测建筑物未来的能源使用。多么有趣又刺激的项目啊!在这次旅行中,我学到了很多东西,也学到了很多我不知道的东西。感谢您的阅读!
5.参考
- ASHRAE。关于 ASHRAE。从 https://www.ashrae.org/about检索到 2020 年 1 月
- 卡格尔。ASHRAE-大能量预测三(2019)。从https://www.kaggle.com/c/ashrae-energy-prediction/overview检索到 2020 年 1 月
- ASHRAE。ASHRAE 技术委员会 4.7 数据驱动建模(DDM)分委员会:能量计算
- 辛伯贝斯特。新加坡伯克利建筑在热带地区的效率和可持续性
- 巴德实验室。建筑和城市数据科学
- 德克萨斯 A&M 大学工程实验站
- ASHRAE 竞赛管理小组成员 Chris Balbach 先生
- 杰夫·哈伯博士,ASHRAE 竞赛管理团队成员
- Krishnan Gowri 博士,ASHRAE 竞赛管理团队成员
- 沃帕尼,卡格尔笔记本,“ASHRAE:一半一半。”从https://www.kaggle.com/rohanrao/ashrae-half-and-half检索到 2020 年 1 月
- 凯撒勒普姆,卡格尔笔记本,“ASHRAE——从这里开始:一个温和的介绍。”2020 年 1 月检索自https://www . ka ggle . com/caesarlupum/ASHRAE-start-here-a-gentle-introduction
- CeasarLupum,Kaggle 笔记本,“ASHRAE—lightgbm simple Fe。”2020 年 1 月检索自https://www . ka ggle . com/caesarlupum/ASHRAE-ligthgbm-simple-Fe
- 罗曼,卡格尔笔记本,“埃达为 ASHRAE。”从https://www.kaggle.com/nroman/eda-for-ashrae#meter检索到 2020 年 1 月
- Sandeep Kumar,“ASHRAE-KFold light GBM-无泄漏(1.08)”2020 年 1 月检索自https://www . ka ggle . com/ai tude/ASHRAE-kfold-light GBM-without-leak-1-08
- SciPy。保利·维尔塔宁、拉尔夫·戈默斯、特拉维斯·奥列芬特、马特·哈伯兰、泰勒·雷迪、戴维·库尔纳波、叶夫根尼·布罗夫斯基、皮鲁·彼得森、沃伦·韦克塞、乔纳森·布赖特、斯蒂芬·范德沃特、马修·布雷特、约书亚·威尔逊、贾罗德·米尔曼、尼古拉·马约罗夫、安德鲁·纳尔逊、埃里克·琼斯、罗伯特·克恩、埃里克·拉森、希杰·凯里、i̇lhan·波拉特、余峰、埃里克·摩尔、杰克·范德普拉斯、丹尼斯·拉克萨尔德、约瑟夫·佩尔(2019)SciPy 1.0-Python 中科学计算的基本算法。预印本 arXiv:1907.10121
- Python。特拉维斯·奥列芬特。用于科学计算的 Python,《科学与工程中的计算》, 9,10–20(2007 年 b) K. Jarrod Millman 和 Michael Aivazis。面向科学家和工程师的 Python,科学与工程中的计算,13,9–12(2011)
- NumPy。特拉维斯·奥列芬特。美国 NumPy 指南:特雷戈尔出版公司(2006 年)。(b)斯蒂芬·范德沃特、克里斯·科尔伯特和盖尔·瓦洛夸。NumPy 数组:高效数值计算的结构,科学与工程中的计算,13,22–30(2011)
- IPython。费尔南多·佩雷斯和布莱恩·格兰杰。IPython:用于交互式科学计算的系统,科学与工程中的计算,9,21–29(2007)
- Matplotlib。亨特,“Matplotlib:2D 图形环境”,《科学与工程中的计算》,第 9 卷,第 3 期,第 90–95 页,2007 年。
- 熊猫。韦斯·麦金尼。Python 中统计计算的数据结构,第 9 届科学中的 Python 会议录,51–56(2010)
- sci kit-学习。法比安·佩德雷戈萨、加尔·瓦洛夸、亚历山大·格拉姆福特、文森特·米歇尔、贝特朗·蒂里翁、奥利维尔·格里塞尔、马蒂厄·布隆德尔、彼得·普雷登霍弗、罗恩·韦斯、文森特·杜伯格、杰克·范德普拉斯、亚历山大·帕索斯、戴维·库尔纳波、马蒂厄·布鲁彻、马蒂厄·佩罗特、爱德华·杜谢斯奈。sci kit-learn:Python 中的机器学习,机器学习研究杂志,12,2825–2830(2011)
- sci kit-图像。斯蒂芬·范德沃特、约翰内斯·l·舍恩伯格、胡安·努涅斯-伊格莱西亚斯、弗朗索瓦·布洛涅、约书亚·d·华纳、尼尔·雅戈、伊曼纽尔·古亚尔特、托尼·于和 scikit-image 供稿者。sci kit-Image:Python 中的图像处理,PeerJ 2:e453 (2014)
- 作者:Plotly Technologies Inc .书名:协作数据科学出版社:Plotly Technologies Inc .出版地点:马萨诸塞州蒙特利尔出版日期:2015 URL: https://plot.ly
- 越来越多的建筑产生越来越通用的模型——基于开放电表数据的基准预测方法。马赫。学习。知道了。Extr。2019, 1, 974–993.
- W.Hedén,“使用随机森林和支持向量回归预测每小时住宅能耗:分析家庭聚类对性能准确性的影响”,学位论文,2016 年。
- 林德堡,迈克尔 R. 机械工程参考手册。第十三版。,专业出版物,2013。
- ASHRAE。技术资源,“消费者应该知道的关于空调的十大事情。”2020 年 1 月检索自https://www . ASHRAE . org/technical-resources/free-resources/十大空调消费者须知
- NZ,“按仪表类型对齐时间戳-LGBM”2020 年 1 月检索自https://www . ka ggle . com/NZ 0722/aligned-timestamp-lgbm-by-meter-type
- 卡格尔。ASHRAE-大能量预测三(2019)-讨论板。“对于数据泄露将采取什么措施?”检索 2020 年 1 月[https://www . ka ggle . com/c/ASHRAE-energy-prediction/discussion/116739](http://ASHRAE-Great Energy Predictor III (2019). Retrieved January, 2020)
- 卡格尔。ASHRAE-大能量预测三(2019)-讨论板。"在建成之前消耗能源的建筑."检索到 2020 年 1 月。https://www . ka ggle . com/c/ASHRAE-energy-prediction/discussion/113254
- 卡格尔。ASHRAE-大能量预测三(2019)-讨论板。“第一名解决方案团队 Isamu & Matt。”检索到 2020 年 1 月。https://www . ka ggle . com/c/ASHRAE-energy-prediction/discussion/124709
- 康斯坦丁·雅科夫列夫。卡格尔笔记本,“ASHRAE——数据缩小”检索到 2020 年 1 月。https://www.kaggle.com/kyakovlev/ashrae-data-minification
- 效率评估组织。国际性能测量和验证协议。可在线查询:https://Evo-world . org/en/products-services-main menu-en/protocols/IP MVP(2020 年 1 月 26 日访问)。
使用 GARCH 估计货币波动
GARCH 如何用于资产价格波动建模
免责声明:本文是在“原样”的基础上编写的,没有任何担保。它旨在提供数据科学概念的概述,不应被解释为投资建议或任何其他类型的专业建议。
资产价格在时间序列中具有高度的随机趋势。换句话说,价格波动受很大程度的随机性影响,因此很难使用传统的时间序列模型(如 ARIMA 模型)来预测资产价格。
此外,由于今天的大部分交易都是在算法的基础上进行的——价格会在这种预测的基础上不断调整——因此很难在市场中占据优势。
例如,假设我构建了一个时间序列模型来预测一个城市未来三个月的降雨量。我的时间序列模型可能有很高的精确度,因为预测不会影响未来的降雨量。然而,如果每个人都使用 ARIMA 模型来预测未来三个月的资产价格波动——那么基于这些预测的后续交易将直接影响之前的预测——从而在许多情况下使它们无效。
背景
因此,通常对金融市场中资产价格的预期波动率建模——而不是直接预测预期价格。
让我们看看如何使用 Python 来实现这一点。GARCH 模型用于预测欧元/美元和英镑/美元货币对的波动性,使用 2017 年 1 月至 2018 年 1 月的数据。
数据来源于 FRED 使用的 Quandl 库:
eurusd = quandl.get("FRED/DEXUSEU", start_date='2017-01-01', end_date='2018-01-01', api_key='enter_api_key')gbpusd = quandl.get("FRED/DEXUSUK", start_date='2017-01-01', end_date='2018-01-01', api_key='enter_api_key')
序列被转换为对数格式以平滑时间序列:
欧元/美元

资料来源:Quandl
英镑/美元

资料来源:Quandl
然后对数据进行一阶差分,以近似高斯分布。
Dickey-Fuller 检验显示两个序列的 p 值均为 0,表明我们拒绝了单位根存在于 5%显著性水平的零假设,即模型中存在平稳性或趋势平稳性。
欧元/美元:迪基-富勒测试结果
>>> result = ts.adfuller(data, 1)
>>> result(-16.26123019770431,
3.564065405943774e-29,
0,
247,
{'1%': -3.457105309726321,
'5%': -2.873313676101283,
'10%': -2.5730443824681606},
-1959.704886024891)
英镑/美元:迪基-富勒测试结果
>>> result = ts.adfuller(data, 1)
>>> result(-12.380335699861567,
5.045829408723097e-23,
1,
246,
{'1%': -3.457215237265747,
'5%': -2.873361841566324,
'10%': -2.5730700760129555},
-1892.8308007824835)
此外,对 QQ 图的视觉筛选显示,该系列现在基本上遵循正态分布:
欧元/美元:QQ 图

来源:Jupyter 笔记本输出
英镑/美元:QQ 图

来源:Jupyter 笔记本输出
GARCH 建模
构建 GARCH(1,1)模型来预测两种货币对的过去 30 天交易数据的波动性。以前的数据用作 GARCH 模型的训练集。
# split into train/test
n_test = 30
train, test = data[:-n_test], data[-n_test:]
# define model
model = arch_model(train, mean='Zero', vol='GARCH', p=1, q=1)
预测生成如下:
# fit model
model_fit = model.fit()
# forecast the test set
yhat = model_fit.forecast(horizon=n_test)
现在,让我们跨测试集比较预测的方差和实际的 5 天滚动方差。
欧元/美元
预测方差
test.rolling(window=5).var().plot(style='g')
pyplot.title("5-day Rolling Variance")

来源:Jupyter 笔记本输出
5 天滚动差异
pyplot.plot(yhat.variance.values[-1, :])
pyplot.title("Predicted Variance")
pyplot.show()

来源:Jupyter 笔记本输出
我们看到,GARCH 模型预测了过去 30 天的波动性下降(以方差衡量)——这通过实际 5 天滚动方差的视觉检查得到了证实。
让我们来看看英镑/美元的对比。
英镑/美元
预测方差

来源:Jupyter 笔记本输出
5 天滚动差异

来源:Jupyter 笔记本输出
我们可以看到,虽然预测的方差比实际的 5 天滚动方差小得多,但两个实例都预测在 30 天的测试期间方差会减少。
这与我们实际观察到的情况相符-相对于交易年度的其他月份,2017 年 12 月欧元/美元和英镑/美元货币对的波动很小。
结论
这是 GARCH 如何用于时间序列波动建模的一个例子。
希望你觉得这篇文章有用,任何问题或反馈都非常感谢。
参考
从观测数据估计房室模型的参数
非线性最小二乘最小化估计 SEIR 和塞德模型的参数
在本文中,我们将定义 SEIR 和塞德模型,并最小化非线性最小二乘法,以从冠状病毒病例的观察数据中估计它们的参数。为了表现良好,非线性优化技术,如leven Berg–Marquardt(LM)算法需要良好的初始猜测来解决非线性最小二乘优化。我们将使用 SEIR 和塞德模型模拟来猜测参数估计值,并在优化中使用这些值。
请注意,这纯粹是一个编程和数据科学练习,因此不要根据模拟或参数估计得出结论。这最好留给流行病学和医学专家去做。
在我们深入研究之前,让我们先熟悉一下 SEIR 和塞德所属的模型类型。
但是,如果您想直接进入代码,在 SEIR 模型的仿真&参数估计和塞德模型的仿真&参数估计中可以获得带有完整代码的 Jupyter 笔记本。
机械模型
机械模型用于模拟和预测疾病和感染的传播,如流感、埃博拉甚至冠状病毒。与机器学习模型相比,机械模型的一个显著特征是它们能够对疾病传播的假设因果性质进行编码。这通常涉及构建因果机制的数学公式,并使用分析工具用观测数据验证这些假设[R. Baker 等人,2018]。
简而言之,机械模型是可以解释的,而机器学习模型通常是不可以解释的。正因为如此,一个能够很好地解释这一现象的机械模型可以提供关于疾病如何传播以及可能如何应对的深刻信息。下面的表 1 列出了这两种模型提供的数据和信息类型的差异。

表 1: Baker RE,pea J-M,Jayamohan J 和 Jérusalem A,2018 机械论模型对机器学习,一场值得为生物界而战的战斗?生物。信件。18866 . 688686868617
分室模型
房室模型是一种机械模型,它将种群分成称为房室的组。它们基于一个常微分方程系统,该系统表达了一个群体的不同流行病学状态之间的动态。它们有助于对一种现象(如疾病)的传播进行短期和长期预测,也可用于研究不同干预措施的效果[Chowell,2017]。
SEIRD 塞德公司
下面的图 1 和图 2 显示了 SEIR 和塞德模型中流行病学状态之间的间隔和进展。

图 1: SEIR 模型

图 2: SEIRD 模型
要查看这些模型的动力系统以及如何用 python 模拟它们的更多细节,请参考使用 Python 模拟流行病学中的房室模型& Jupyter Widgets 。
估计参数
在这一节中,我们将讨论数据,模型和最小化非线性最小二乘参数估计。
数据
我们将使用印度新冠肺炎 REST API提供的印度冠状病毒病例数据。从 API 返回的 JSON 的结构如下,
{
'success': boolean,
'data': [
{'day': 'YYYY-MM-DD',
'summary': {
'total': int,
'confirmedCasesIndian': int,
'confirmedCasesForeign': int,
'discharged': int,
'deaths': int,
'confirmedButLocationUnidentified': int
},
'regional': [
{
'loc': string,
'confirmedCasesIndian': int,
'discharged': int,
'deaths': int,
'confirmedCasesForeign': int,
'totalConfirmed': int
}
]
}
],
'lastRefreshed': timestamp,
'lastOriginUpdate': timestamp
}
数据示例如下所示,
{
'success': True,
'data': [
{'day': '2020-03-10',
'summary': {
'total': 47,
'confirmedCasesIndian': 31,
'confirmedCasesForeign': 16,
'discharged': 0,
'deaths': 0,
'confirmedButLocationUnidentified': 0
},
'regional': [
{
'loc': 'Delhi',
'confirmedCasesIndian': 4,
'confirmedCasesForeign': 0,
'discharged': 0,
'deaths': 0,
'totalConfirmed': 4},
{
'loc': 'Haryana',
'confirmedCasesIndian': 0,
'confirmedCasesForeign': 14,
'discharged': 0,
...
}
...
]
}
...
],
'lastRefreshed': '2020-04-27T04:30:02.090Z',
'lastOriginUpdate': '2020-04-27T02:30:00.000Z'
}
这些数据可以很容易地转换成 pandas 数据框,我们熟悉使用下面这段代码
让我们看看下面表 2 中熊猫数据帧的前 5 行,

表 2:印度有新冠肺炎病例的数据帧样本
由于每天都有新的非零阳性病例,印度冠状病毒阳性病例总数仍在上升。案件趋势如下图 3 所示。

图 3:印度的新冠肺炎病例
现在,让我们用 python 来定义模型。
定义 SEIR 和塞德模型
SEIR 和塞德模型是由一个常微分方程系统定义的。让我们看看这些 ode 是什么,以及如何用 python 编码和求解它们,
SEIR
数学模型

图 4: SEIR 动力系统
Python 代码
塞德
数学模型

图 5: SEIRD 动力系统
Python 代码
我们将使用 scipy 中的 odeint 模块来求解这些方程组。像 ODE 的系统一样,求解 ODE 的函数也非常相似。让我们看看如何用 Python 为 SEIRD 模型编码。
要解一个常微分方程系统,你需要初始条件和描述你的方程的参数。您可以在上面的 python 代码中观察到这些。
接下来,我们使用非线性最小二乘最小化来优化 ODE 的参数。
非线性最小二乘最小化
什么是非线性最小二乘法?
非线性模型是指输出和输入之间的关系在模型参数中不是线性的。例如

图 6:米氏–门滕酶动力学模型
Michaelis–Menten 模型不能表示为两个β的线性组合。
现在,非线性最小二乘可以定义为,“非线性最小二乘是最小二乘分析的一种形式,用于将一组 m 个观测值与一个在 n 个未知参数(m ≥ n)中为非线性的模型进行拟合。”—维基百科
最小化非线性最小二乘的算法(例如 LM)需要更接近最优值的良好的初始参数估计。接下来,我们将使用模型的模拟来达到一个良好的初始估计。
模拟
我们将使用后中构建的 SEIR 和塞德模型的模拟器,使用 Python & Jupyter Widgets 模拟流行病学中的房室模型,并为此进行一些修改。
在尝试了各种参数组合后,beta(感染率)= 1.14,sigma(孵化率)= 0.02,gamma(恢复率)= 0.02,mu(死亡率)= 0.01,似乎是 SEIRD 模型的合理初始估计。模拟器设置可以在下面的图 7 中看到。

图 7:使用 SEIRD 模拟器直观拟合初始参数估计数据
类似的方法可以用于 SEIR 模型。现在,让我们使用初始猜测,使用 LM 算法进一步优化参数。
优化
在不涉及太多细节的情况下,在 leven Berg-Marquardt 算法(也称为阻尼最小二乘法(DLS ))中,连续时段中的权重变化由下式给出:

图 8:LM 算法中历元 m 的所有权重的权重变化的通用公式。应用科学与工程的神经网络。
我们将使用 python 中 lmfit 库中的 minimize 模块,使用 LM 算法实现非线性最小二乘的最小化。最小化需要残差以及模型的其他参数作为优化输入。让我们对残差进行编码,并将其传递给最小化,如下所示。
现在,用 LM 算法( leastsq )最小化非线性最小二乘非常简单,如下面的代码所示。
优化完成后,您可以打印优化的模型参数并可视化拟合。

表 3:优化的模型参数

图 9:观察图与拟合图
指标
我们还可以通过使用优化的参数并调用上面定义的 ode_solver 来计算像 MAE 和 RMSE 这样的指标。在写这篇文章的时候,我发现这些价值观是,
Fitted MAE
Infected: 587.5587793520101
Recovered: 216.5347633701369
Dead: 21.532532235433454
Fitted RMSE
Infected: 702.1643902204037
Recovered: 284.9841911847741
Dead: 26.4463792416788
您还可以在模拟器中输入优化的参数值,以查看流行病学状态曲线,如图 9 所示。

图 10:具有优化参数的 SEIRD 模型模拟
完全码
在 SEIR 模型的仿真&参数估计和赛德模型的仿真&参数估计中可以找到完整代码的 jupyter 笔记本。
结论
在这篇文章中,我们了解到,
- 机械模型、分室模型、SEIR 模型和塞德模型
- 用 Python 写颂歌并解决它们
- 非线性模型和非线性最小二乘法
- 利用 SEIRD 塞德模拟器和 lmfit 库中的最小化模块优化 ODE 参数
- 在模拟器中使用优化的参数来可视化流行病学状态曲线
*注意,同样的方法也可以用于编码和优化任何 ode 系统。
我们没有学到的东西(有意识的选择)
- 如何解读这些流行病学模型的结果?
- 曲线什么时候会变平?有多少人会感染、康复、死亡等?我们什么时候能重新启动经济?
让我们把这些重要的问题留给专家来回答。
参考
- Baker RE,pea J-M,Jayamohan J 和 Jérusalem A,2018,机械模型对机器学习,一场值得为生物界而战的战斗?生物。http://doi.org/10.1098/rsbl.2017.0660
- Chowell G,《用量化的不确定性拟合流行病爆发的动态模型:参数不确定性、可识别性和预测的初级读本》( 2017 年),《传染病建模》第 2 卷第 3 期,2017 年 8 月,第 379-398 页
- 非线性最小二乘法(维基百科)
- 非线性回归(维基百科)
- 萨马拉辛哈,2007,应用科学与工程的神经网络
估计可能未被发现的新冠肺炎感染病例
全国范围内未检出新冠肺炎病例的估计和加强检测设施的建议。
为什么估计未被发现的新冠肺炎病例至关重要?
对未被发现的新冠肺炎病例的估计对于当局规划经济政策、围绕封锁的不同阶段作出决策以及致力于生产重症监护病房是重要的。
由Nikhel Gupta与参与 Omdena 冠状病毒 AI 挑战赛的人员合作完成的工作。

新冠肺炎考试中心离你家有多远?(鸣谢:链接)
随着我们在全球范围内跨越了 100 万新冠肺炎患者的心理关口,关于我们的卫生保健系统遏制病毒的能力出现了更多的问题。最大的担忧之一是感染该病毒的公民数量的系统性不确定性。对这种不确定性的主要贡献可能是由于正在进行的新冠肺炎试验的一小部分。
确认某人是否患有新冠肺炎病毒的主要测试是从其鼻子或喉咙的拭子中寻找病毒遗传物质的迹象。这对于大多数人来说还不具备。医务工作者在道德上被限制为医院里的重病患者保留测试仪器。
在本文中,我将展示一个简单的贝叶斯方法来估计未被发现的新冠肺炎病例。贝叶斯定理可以写成:
P(A | B)=P(B | A)×P(A)/P(B)
其中 P (A)为事件 A 的概率, P (B)为事件 B 的概率, P (A|B)为 B 为真时观测到事件 A 的概率, P (B|A)为 A 为真时观测到事件 B 的概率。
我们感兴趣的数量是 P (已感染|未测试),即未测试的感染概率。这相当于感染新冠肺炎病毒但未检测的人口百分比,我们可以写成:
P (已感染|未检测)= P (未检测|已感染)× P (已感染)/ P (未检测)
这里的其他概率是:
- (未检测|已感染):未对已感染人群进行检测的概率或未检测但已感染人群的百分比。
- P (感染):感染的先验概率或感染人群的已知百分比。
- P (未测试):未被测试的人的概率或百分比。
下图显示了几个国家每百万人的新冠肺炎检测总数和每百万人的确诊病例总数。这表明新冠肺炎试验和确认的阳性检测之间有明显的联系。

图 1:截至 2020 年 3 月 20 日每百万人检测数与每百万人新冠肺炎阳性病例数的对比(数据来源)。
假设所有国家都遵循新冠肺炎检测和确诊病例之间的这种关系,我们可以粗略估计每个国家未检出病例的数量(我将在本文稍后回到这一假设)。
让我们以澳大利亚为例:
例如,该图显示了感染病例的先验知识
P (被感染)= 27.8/1⁰⁶,和
P (notTested) = (1⁰⁶ — 473)/1⁰⁶.)
为了估计 P(未检测|感染),我使用了新冠肺炎检测和确诊病例之间的关系,如上图 1 所示。这是通过拟合以下形式的幂律来实现的:y = a * x**b,其中 a 是归一化,b 是该幂律的斜率。下图显示了与上图数据点的拟合,其中最佳拟合 a = 0.060±0.008,b = 0.966±0.014。

图 2:新冠肺炎测试和确诊病例之间的关系以及幂律最佳拟合。
*使用最佳拟合参数, P (未检测|已感染)=(1⁰⁶—4473)/1⁰⁶/(a (1⁰⁶—4473)**b)/1⁰⁶.
对于概率 1、2 和 3,我发现 P = 0.00073%的澳大利亚人口。将这个数字乘以澳大利亚的人口表明,澳大利亚有大约 18600 例未被发现的新冠肺炎病例的可能性。下图显示了截至 2020 年 3 月 20 日不同国家可能未检出的新冠肺炎病例与每百万检测数的函数关系。

图 3:未检出新冠肺炎病例的估计(见文中假设)。
请注意,为了估计这些未检测到的情况,我们做了一些假设和考虑。例如:
- 我假设所有国家都遵循相同的幂律关系来估计 P。然而,这不是一个非常好的假设,因为不同国家之间的这种关系有很大的差异。
- 我们之前对感染人数的了解可能会有偏差,因为 T21 感染人数取决于截至 2020 年 3 月 20 日的检测数量。
- 我还没有考虑一个国家的人口对新冠肺炎的易感性,以及发病率,即发病率的生物统计学测量值,新冠肺炎的发病率估计在 50-80%左右( Verity 等人,2020 )。
- 这些国家的政府政策在 3 月 20 日之前 14 天和之后 14 天的影响未被考虑。
- 我还没有考虑接下来几天在不同国家检测的对象是怎样的易感人群。
下图 4 显示了几个国家截至 2020 年 4 月 5 日的确诊病例总数与每百万检测数的对比(数据来源)。
在 4 月 5 日的 16 天后,乌克兰、印度和菲律宾等国家的确诊阳性病例与图 3 中的预测一致。截至 3 月 20 日,这些国家每百万人中进行了≤ 10 次检测。
请注意,截至 3 月 20 日和 4 月 5 日的估计数之间的一致性并不一定意味着截至 3 月 20 日所有未发现的病例现在都得到确认。由于 3 月 20 日至 4 月 5 日之间的传播(即使存在封锁),截至 4 月 5 日的几例确诊病例预计将是新病例。
与截至 4 月 5 日的确诊病例总数(即两国均为约 1,500 例)相比,哥伦比亚和南非等国家的估计未检出病例约为两倍(图 3)。这两个国家每百万人进行了大约 100 次检测。
另一方面,与图 3 中的估计数字相比,台湾、澳大利亚和冰岛等国家显示了数量级的少量确诊病例。
这表明,尚未将其检测效率提高到每百万人 1,000 次以上的国家,其目前确诊病例数的不确定性要大得多。

图 4:截至 2020 年 4 月 5 日,每百万人中确诊病例总数与检测数的对比。
根据图 4 中 2020 年 4 月 5 日的数据,我再次重复了整个过程,以估计这些国家、城市和州未被发现的新冠肺炎病例。下图显示了与图 2 相似的最佳拟合幂律和数据点,但数据截止日期为 2020 年 4 月 5 日。

图 5:截至 2020 年 4 月 5 日的数据的最佳拟合幂律。
图 5 中幂律关系的最佳拟合斜率(b = 1.281±0.009)与图 2 中 2- σ 置信水平下的斜率一致。这有助于我们从最佳拟合幂律关系(斜率不变)估计 P (未测试|感染)的假设,然而,其他警告与之前相同。
最后,下图显示了截至 2020 年 4 月 5 日不同国家未检测到的新冠肺炎病例的估计值。

图 6:截至 2020 年 4 月 5 日估计未检出的新冠肺炎病例(见文中假设)。
由于截至 3 月 20 日的未检出估计数(图 3)与截至 4 月 5 日的确诊病例数(图 4)之间的比较表明,每百万人需要更多的检测才能发现可能的未检出病例,因此现在是当局提高检测效率以减少未检出新冠肺炎病例的系统性的时候了。这似乎是降低新冠肺炎患者死亡率的唯一好方法,德国和南韩的大量新冠肺炎检测表明了这一点。
要做到这一点,所有国家都需要至少一个半径 20 公里内的检测中心,并尽快安排更多的驱车通过检测设施。
这项工作是与致力于 Omdena 冠状病毒 AI 挑战的人员合作完成的。
估计真实的新冠肺炎死亡人数
为什么病毒杀死的人数可能比官方数据显示的要多

毫无疑问:官方数据是错误的。无论是阳性病例、官方死亡人数、康复人数,大多数关于新冠肺炎的可用数据都具有误导性。众所周知,这只是一个数字相差多少的问题。
特别是,新冠肺炎死亡的官方数字通常来自医院。死在家中的人可能不会被计算在内,因为他们从未接受过冠状病毒检测。因此,死亡人数 可能被 低估了。然而,这种差异通常很难量化,因为政府数据往往是唯一可用的信息来源。
鉴于意大利有大量关于新冠肺炎疫情的一手和二手数据,我将研究重点放在意大利的情况上。跟踪任何流行病的演变并量化其进展是一项极具挑战性的工作,因此其他国家很可能面临同样的问题,导致巨大的低估。

就在两天前,5 月 4 日,意大利国家统计局(ISTAT) 发布了一个大型数据集报告了发生在该国的每一起死亡事件,死因各异,但不一定与新冠肺炎有关。死亡按日期、城市、性别和年龄组报告,包含 6,866 个城市的数据(覆盖范围为 7,904 - 87%)。数据集集中于 1 月 1 日至 3 月 31 日期间,并与最近 5 年的历史数据相关联。
本文的主要目的是比较正常时期的平均死亡率与新冠肺炎疫情期间登记的死亡人数。死亡人数超过无疫情年份的原因可以用新冠肺炎的直接和间接影响来解释。
我们将充分利用 Python 数据科学库的潜力来分析数据,识别死亡率的异常,将它们与新冠肺炎官方死亡人数进行比较,并最终绘制结果图。
主要发现
- 意大利(很可能是世界各地)受新冠肺炎影响的人数远远高于政府官方数字。
- 数据显示,与过去 5 年相比,2020 年 3 月总死亡人数出现异常增长:全国范围内 + 49.4% 。
- 在同一时期,一些地区(意大利的第一个行政级别)的死亡率急剧上升:仅举几个例子,如伦巴第+186%,艾米利亚-罗马涅**+70%, + 65 %特伦蒂诺上阿迪杰 。
- 在地方一级,一些特定省份(第二行政级别)的疫情极为严重:例如,3 月份,佛手省死亡人数增加了 567.6 %,克雷莫纳省增加了 391.8 %,罗提省增加了 370.6 %。****
- 官方数据只能解释 2020 年 3 月发生的异常死亡中的 50.2 %。其余的数字很可能是由于“隐藏的”新冠肺炎病例,或由于疫情的间接影响(医院饱和、卫生服务水平较低、难以或不愿及时进入医院……)
- ISTAT 提供的数据仅占 87%的城市。尽管这是一个统计上有代表性的样本,但我们可以假设现实情况更为戏剧性。事实上,第 5 点中提供的百分比是一个保守估计,它代表总死亡数的下限。**
- 该国一些省份受到了病毒的严重打击,而另一些省份在整个危机期间相对未受影响。这可能是因为地区和国家当局实施了及时有效的封锁措施。**
导入和清理数据
这项工作是在 macOS 上用 Python-3.7.1 开发的,主要利用了开源数据科学库,如Pandas、Geopandas、Matplotlib。
让我们开始导入必要的库。
现在,我们导入 ISTAT 出版的大表,报告按城市、年龄、性别和日期记录的死亡(大约 100 万个记录)。当缺少 2020 年 3 月的数据时(大约 13%的行),我们将字段名翻译成英文,并删除城市。然后,我们只保留二月和三月的数据。
下一步是计算在没有疫情的一年中每个城市登记的死亡人数。我们将这个变量命名为 baseline_deaths,,它是通过计算 2015 年至 2019 年间登记的死亡人数的平均值而创建的。基线 _ 死亡数与 2020 年 3 月的死亡数之差被称为超额 _ 死亡数,它存在于可归因于新冠肺炎疫情的异常。
国家级分析
我们现在可以直观的看到这三个关键变量在时间上的演变:基线 _ 死亡人数(最近 5 年的平均死亡人数),死亡人数 _2020 和超额 _ 死亡人数。下面的代码生成一个图表,显示国家层面的趋势。

图表清楚地告诉我们,2020 年 3 月发生了不寻常的戏剧性事件,在 3 月 21 日到 28 日之间的几天里,意大利每天的死亡人数几乎翻了一番。现在,想象一下 2020 年死亡人数相对于平均水平的百分比增长会很有趣。
****
在这张图表中,峰值更加明显。事实上,2019-20 年的冬天异常温和,流感疫情导致的死亡人数低于往年的平均水平。然后,大约在 3 月 4 日,新冠肺炎疫情开始在全国范围内杀死第一批人。考虑到整个三月,意大利的死亡率上升了 49.36 %** 。**
现实 VS 官方数据
我们现在有了所有我们需要的来比较 2020 年 3 月登记的异常死亡人数和意大利公民保护局发布的官方新冠肺炎死亡人数。
下面的代码下载了平民保护 GitHub 账号的官方死亡人数,并与 2020 年登记的超额死亡人数进行对比。
****
意大利民防组织提供的官方新冠肺炎死亡人数并不能完全解释三月份记录的峰值。2020 年 3 月 ISTAT 报告的死亡人数比非疫情年平均水平增加了 24668 人。同期,民防部门报告的新冠肺炎官方死亡人数仅为 12399 人,仅为超额死亡人数的 50.26 %。剩下的数字最有可能是由于“隐藏”的新冠肺炎病例(没有进行病毒检测就在家中死亡的人)或疫情的间接影响(医院饱和、医疗服务水平较低、难以或不愿及时进入医院……)。此外,我们知道 ISTAT 只报告了 87%的城市的数字。因此,现实可能比我们保守估计的还要糟糕。****
区域层面分析
我们知道病毒并没有以同样的强度袭击整个国家。这场流行病使意大利北部陷入困境,而南部地区相对来说没有受到危机的影响。ISTAT 发布的数据集提供了与非常高的空间分辨率相关的信息,也有可能在区域和省一级检查死亡异常情况。
首先,让我们关注 6 个受影响最严重的地区,将它们的基线 _ 死亡与 2020 年登记的死亡人数进行比较。

同样,我们注意到 2020 年死亡的常规趋势,直到三月初。但是伦巴第地区比其他地区受到的影响要大得多。现在让我们想象一下超额死亡的趋势以及与五年平均值相比的百分比增长。

上图显示,2020 年 3 月 23 日左右,皮埃蒙特、利古里亚、马尔凯和艾米利亚-罗马涅的日均死亡人数是过去 5 年的两倍。但是同样,最严重的情况发生在伦巴第,在 3 月 18 日和 28 日之间登记的死亡人数是平均每天死亡人数的 3 倍。
绘制地区超额死亡人数图
现在可以按地区绘制 2020 年 3 月整个月份登记的死亡增加地图。意大利地区的边界可以从意大利国家统计局网站下载 shapefile 。

该地图清楚地显示了该国相对两侧的不同情况:虽然意大利北部的死亡率急剧上升,但有趣的是,与过去五年的平均水平相比,南部一些地区的死亡率有所下降。这可能是由于严格的封锁措施(道路和工作事故减少,季节性流感疫情减少……)和异常温和的冬季的影响,但这一假设应通过专门的分析进一步验证。
省级分析
ISTAT 数据集让我们可以更深入地分析,并在省级基础上比较基线 _ 死亡人数和死亡人数 _2020* 。在下面的图表中,我们将重点关注六个受影响最严重的省份。*

在 6 个受影响最严重的省份中,4 个在伦巴第区,2 个在艾米利亚-罗马涅区。特别是,图表显示了贝加莫省的一个极端峰值:三月份报告的死亡人数甚至比米兰多,米兰的总人口是它的三倍。现在让我们检查各省的超额死亡人数和死亡增加的百分比。

发生在贝加莫省的灾难程度现在更加清楚了。在本月的某些日子里(16 日至 26 日),该省的平均死亡人数是非流行年份的 10 倍。其他省份(皮亚琴察、布雷西亚、克雷莫纳)也受到了严重影响,一些高峰达到了正常死亡率的 600%。
绘制各省超额死亡人数图
这项分析的最后一步是创建 2020 年 3 月死亡增长的省级地图。意大利各省的边界在 ISTAT 网站上以 shapefile 的形式提供。

下表总结了受影响最严重省份的分析结果。
上表所载信息可以被视为对意大利总体死亡率的流行病影响的最准确分析。
结论
- 在这篇文章中,我提供了意大利官方每天公布的死亡人数比实际数字低得多的证据。
- 在全国范围内,真实的死亡人数可能被低估了 12000 人,大约是官方总数的两倍。
- 上述估计包括了新冠肺炎病毒直接和间接导致的死亡:其中一些死亡人数的增加可能与卫生系统没有适当治疗的其他疾病有关,或者是因为危机导致他们找不到医院床位。
- 在一些南部地区和省份,死亡率与平均水平相比已经大幅下降。部分原因是由于意大利的封锁,道路死亡人数和工作事故减少,以及异常温和的冬季。
致谢
本文中进行的一些分析受到了费德里科·里奇-特尔森吉教授发表的工作的启发,他设法量化了新冠肺炎对额外死亡的直接和间接影响之间的比率。我还要感谢格雷格·奥卡拉汉、罗希尼·斯瓦米纳森和弗吉尼亚·埃特诺审阅了本文的草稿,并提出了编辑和改进的建议。
我为本文中显示的分析和地图开发的所有代码都可以在我的 GitHub 库中找到。
感谢您的阅读!如果你喜欢这篇文章,不要犹豫,评论或分享它。
我每天都在学习,如果你发现任何错误,请随时纠正我,并在评论区写下你的建议。
作者注:我不是流行病学家,本文中的分析仅基于应用于公开数据的纯数学。
编者注: 迈向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
使用 Python 通过统计和模拟来评估任务
用 PERT 和蒙特卡罗模拟模拟任务估算
几个月前,当世界还是一个非常不同的地方时,我写了关于待办事项列表任务的战略。我想知道,给定你的待办事项列表中的一堆任务,你应该使用什么策略来选择首先处理的任务?根据我实际想要达到的目标,我的做法可能会大不相同。
我的假设是,任务的复杂性是固定的,也就是说,完成任务所需的时间是预先确定的。这通常是不正确的(统计笑话提醒!).即使在疫情带来不确定性之前,大多数任务的复杂性和持续时间也很难准确预测。
如果我们关注待办事项清单之外的任务,例如项目任务,情况会变得更糟。项目任务的复杂性不仅影响持续时间,还影响工作和成本,因此能够确定复杂性是非常重要的。

然而,众所周知,项目任务很难估计,这可能意味着延迟和成本上升。
柏林的新勃兰登堡机场在 2006 年开工前规划了 15 年,预计于 2011 年 10 月开放。然而,该项目仍在进行中,也面临着预算暴涨。最近的开放日期是 2020 年 11 月,但鉴于目前的形势,它似乎有可能再次移动。
美国宇航局的太空发射系统(SLS)是一种发射火箭,将为载人月球飞行和人类火星任务提供基础,始于 2010 年,截至 2020 年已耗资 186 亿美元。2020 年初宣布成本将超支 20 亿美元,并至少推迟 2 年。
这不是什么新鲜事,NASA 因过分乐观和低估项目而臭名昭著。詹姆斯·韦伯太空望远镜(JWST)原本应该在 2007 年发射,耗资 5 亿美元,但截至今天,已经推迟到 2021 年,预计耗资 100 亿美元。它的前身哈勃太空望远镜原本应该在 1983 年发射,但最终在 1990 年发射,成本从最初的 4 亿美元下滑到最终的 47 亿美元。然而,国际空间站是最棒的——它以 367.5 亿美元的预算开始,推迟了 6 年才完工,最终耗资 1050 亿美元。
建筑项目并不是唯一被延迟的项目类型,软件开发项目通常也是罪魁祸首。在一个相当臭名昭著的开发昆士兰州健康工资系统的案例中,该项目于 2007 年 12 月被 IBM 招标并以 9800 万美元中标,本应于 2008 年 7 月推出。最终于 2010 年交付,有 bug,耗资 12 亿美元。
估计项目任务
当然,项目失败的原因有很多。由于各种无法预测的原因,完全正确估计的项目可能遭受灾难性的结果。你可以肯定的是,无论项目任务估计得有多好,都不会增加我们现在面临的疫情,也不会增加它的后果。尽管如此,良好的评估对于保持项目顺利进行是至关重要的。

由著名的西班牙/加泰罗尼亚建筑师安东尼·高迪设计的圣家族大教堂于 1882 年动工,预计在高迪于 1926 年去世 100 年后的今天于 2026 年完工
有多种方法可以进行评估。在敏捷方法中(大部分是软件开发项目),我们有计划 pokers,affinity groups,t-shirt sizing,bucketing 等等。在估算单位方面,有 t 恤尺寸(S,M,L,XL 等),斐波那契故事点,点投票和许多其他非常有创意的方式来表示工作的大小。
对于更传统的项目管理方法,评估技术包括自下而上、自上而下、参数化、类比、三分法等等。有许多其他类型的评估技术,尤其是在软件开发中,包括 COCOMO、SEER-SEM、Putnam、PERT 和许多其他技术。我们绝对不缺乏评估技术。
无论我们使用哪种技术和单位,项目最终关心的是按时交付(时间),在成本范围内交付(预算),以及做它应该做的事情(质量),无论是太空望远镜还是医疗工资系统。

任务估计很难。它主要是基于判断,利用评估者(通常是做任务的人)的经验。此外,大多数估计往往过于乐观。事实上,有一个由心理学家丹尼尔·卡内曼和阿莫斯·特沃斯基在 1979 年创造的术语,叫做计划谬误,准确地描述了这个。卡尼曼和特沃斯基发现,我们倾向于忽视过去在类似任务中所学到的东西,并且对潜在问题甚至我们自己完成任务的能力过于乐观(乐观偏见)。这个主题非常吸引人,如果你想了解更多,你可以多读读他们的书,《思考的、、快与慢的、。
三点估计
其中一个方法是使用三点估算法。诀窍是为每个估计产生 3 个数据点(因此得名):
a—最佳情况估计b—最有可能的估计c—最坏的情况估计
这迫使评估者每次都要考虑最好、最坏和最有可能的情况。虽然这不是克服规划谬误的灵丹妙药,但它给了我们一些有趣的数据。
活泼性感的
项目评估和评审技术(PERT) 是项目管理中用来分析和表示项目任务的工具。它是在 1957 年为美国海军开发的,用于管理美国海军北极星核潜艇导弹项目,但它也有许多其他用途,包括早期用于规划 1968 年格勒诺布尔冬季奥运会。

潜艇首次发射北极星(部分视频片段)(公共领域来自https://commons . wikimedia . org/wiki/File:1960-07-21 _ First _ Polaris _ fireing _ By _ Submerged _ U-boat . ogv)
PERT 是一种大规模、一次性计划和安排的工具,关注事件和时间。PERT 本身产生了相关的工具和概念,如工作分解结构、关键路径和关键路径分析(CPA)。
PERT 也引起了做三点估计,事实上它给了一个连续概率分布族的名字,叫做 PERT 分布。
PERT 分布
PERT 分布是由最小值(a)、最大可能值(b)和最大值(c)定义的连续概率分布,其平均值(或期望值)为:

PERT 分布实际上是一个转换的四参数贝塔分布。贝塔分布有两个定义在区间[0,1]上的参数 α 和 β ,这使得它对概率和随机变量建模很有用。贝塔分布的四参数版本使区间为[a,c],其中 a 是最小值,c 是最大值。
你可以看到这是怎么回事。通过使用 PERT 分布来绘制估计值,我们可以近似估计值本身的概率!
也就是说,当我们要求评估者提供乐观、悲观和最有可能的评估值时,实际的期望值可能与最有可能的值不同,我们可以计算出任务在持续时间或预算内完成的可能性有多大。
然而,这实际上只是一个单一的任务。当然,在一个项目中,我们有很多很多任务,每个任务可能有不同的分布参数 a、b 和 c。如果你是项目经理,你如何计算出总体估计值和概率?
嗯,我们也可以尝试做数学,但我们是程序员,不是数学家(我这么说是出于好意),所以我们寄希望于我们的老朋友蒙特卡洛。
蒙特卡洛
当然,我说的蒙特卡洛指的是蒙特卡洛模拟,而不是赌场。蒙特卡罗是一种流行的模拟技术,它使用许多重复的随机抽样来产生数字数据。这就像进行大量的实验,并从所有的数据中找出真知灼见。

摩纳哥蒙特卡洛赌场(图片来自https://Commons . wikimedia . org/wiki/File % 3a casin % C3 % B2 - panoramio . jpg)
1947 年,斯坦尼斯劳·乌拉姆(Stanislaw Ulam)在疾病康复期间想出了这个主意。当时他正在洛斯阿拉莫斯国家实验室从事一个核武器项目,并把这个想法告诉了约翰·冯·诺依曼,他看到了这个想法的重要性,并编写了第一个蒙特卡罗模拟程序。由于他们工作的秘密性,他们必须想出一个代号。他们的一个同事建议,蒙特卡洛,摩纳哥著名的赌场乌兰的叔叔曾经在那里向亲戚借钱赌博,剩下的就是历史了。(你可能会从我之前写的一篇**)中认出乌兰和冯·诺依曼,他们都是才华横溢的数学家、科学家,也是计算机科学的早期先驱。
蒙特卡罗模拟可以用来解决任何概率问题。使用大数定律,我们可以通过自己创造的经验数据来近似计算结果。当然,没有计算机我们无法理智地做到这一点,因为这项技术需要运行大量的重复实验。蒙特卡洛字面蛮力的结果!
那么,我们究竟如何使用蒙特卡罗来计算出许多项目任务的总体估计呢?其实很简单。对于每个任务,我们使用给定的a(悲观)、b(最有可能)和c(乐观)值创建一个 PERT 分布,并从该分布中提取一个值。我们得到的是对每项任务的模拟评估。当我们把这些评估加在一起时,我们得到了整个项目的模拟评估。
冲洗,重复。
我们最终会得到很多很多的项目评估,这也是某种概率分布。实际上,我们将会以另一个 PERT 分布结束,但是让我们稍后看看如何证明它。一旦我们有了数据,我们就可以计算出我们估计的各种概率。
让我们试一试!为此,我将在 Jupyter Notebook 上使用 Python3,使用常见的怀疑对象——numpy、pandas、scipy 和 matplotlib。
估计单个任务
我们从一个单一的任务开始,对它进行 1000 万次实验。这并不像听起来那么疯狂,运行这个脚本只需要 2 秒钟。
让我们看一下剧本。no_of_experiments和num_bins是我们想要运行的实验的数量,以及我们用于直方图的箱的数量。
tasks是一个只有 1 个键值对的字典。我用这个是因为很自然地我们以后会有更多的任务,所以提前做好准备。关键是任务的名称,而值是 3 个元素的列表,第一个是乐观值a,第二个是最可能值b,最后一个是悲观值c。
还记得我之前说过的 PERT 分布是一种变形的四参数 beta 分布吗?我这么说是因为numpy和scipy都没有 PERT 分布,相反它们有 beta 分布。因此,要使用 PERT 分布,我们需要将 a、b 和 c 转换为 α 和 β。转换公式非常简单,如果你不想自己算,你可以从维基百科关于 PERT 分布的条目中找到。

和

一旦我们有了 α 和 β ,我们就可以使用numpy(或者scipy,随便你选,但我在这里使用了numpy)从分布中随机抽取一些随机变量。这里我们画了 1000 万个随机变量。
接下来我们需要将随机变量转换回我们想要的实际值,它在a和c之间。最后,我们有一个额外的步骤,将它添加到一个全 0 的points列表中,这对于一个单一的任务来说并不真正有用,但是当我们有更多的任务时,就需要它了。points列表现在是从 PERT 分布中随机抽取的 1000 万个数字的列表。
现在我们有了数据,我们将使用matplotlib的hist函数来绘制它。我们稍微改变一下 x 轴,从 0 开始,也改变点来表示一个概率。
运行它,这就是我们得到的。

任务[4,7,12]的概率分布
这是一个很好的曲线,但它意味着什么呢?让我们使用scipy.stats对其进行一些统计分析。
我们做的第一件事是简单地显示任务,如果我们有一个以上的任务,我们把乐观的,最有可能的和悲观的值加起来。
然后使用stats.describe函数,我们得到最小值、最大值、平均值、方差、偏度、峰度以及标准偏差值。仅仅几行代码就包含了大量内容!
最后,我们打印出标准差为 0.5、1、2 和 3 的概率。
现在让我们来看看结果。
*Tasks
-----
optimistic likely pessimistic
Task 1 4 7 12
Total 4 7 12
Statistics
----------
minimum: 4.0 maximum: 12.0
mean: 7.3
standard deviation: 1.5
skewness: 0.22
kurtosis: -0.60
Probabilities
-------------
* between 7.0 and 7.7 : 36.0% (within 0.5σ)
* between 6.6 and 8.1 : 64.7% (within 1σ)
* between 5.8 and 8.8 : 97.3% (within 2σ)
* between 5.1 and 9.6 : 100.0% (within 3σ)*
这些任务非常简单明了,包括最小值和最大值。平均值很有意思,如果我们用前面的等式计算 PERT 分布的平均值,我们得到 7.333,这证明了我们的答案。使用 PERT 分布的方差,即:

我们将得到方差 2.222,标准差,即方差的平方根,将是 1.49,这再次验证了我们的答案。
对于概率,我们简单地取均值和均值两侧标准差σ的倍数之间的曲线下面积,这就是概率(因为曲线下面积的总和为 1.0 或 100%)。
我们说这项任务在 5.1 到 9.6 之间结束的概率是 100%,这似乎令人吃惊,也是错误的,但这是因为我将结果截断到了小数点后 1 位。如果我们允许更多的小数点,它将是 99.9994%。尽管如此,让我们看看几个有趣的点。
期望值或平均值和最可能值(由估计器提供)接近但不相同。
偏斜度 为 0.22,这意味着估计倾向于更乐观。如果它是一个负数,这意味着它倾向于更加悲观。对称分布的偏斜度为 0。
峰度 为-0.6 表示峰值有点平坦,更分散。一般来说,数字越低(正态分布的峰度为 0),曲线越平坦,数字越高,曲线越多峰。较平坦的曲线意味着乐观值和悲观值彼此远离,而峰值曲线意味着乐观值和悲观值彼此靠近。
这个任务有 99.9994%的可能性在 5.1 到 9.6 之间。现在比较一下乐观值 4 和悲观值 12。如果你乐观地认为任务是 4,悲观地认为是 12,然后被统计数据告知这两个值的概率只有 0.0006%,这似乎是错误的!
从数字上看,这似乎违反直觉,但你可以从不同的角度来解释它。如果悲观值的概率只有 0.0006%,那么悲观值估计可能是错误的,应该更大。您可以快速尝试一下,并将任务更改为:
*tasks = {
"Task 1": [4,7, 24],
}*
再次运行它将得到以下结果:

任务[4,7,24]的概率分布
*Tasks
-----
optimistic likely pessimistic
Task 1 4 7 24
Total 4 7 24
Statistics
----------
minimum: 4.0 maximum: 23.5
mean: 9.3
standard deviation: 3.3
skewness: 0.70
kurtosis: -0.02
Probabilities
-------------
* between 8.5 and 10.2 : 33.7% (within 0.5σ)
* between 7.7 and 11.0 : 65.0% (within 1σ)
* between 6.0 and 12.7 : 96.3% (within 2σ)
* between 4.3 and 14.3 : 99.6% (within 3σ)*
您可以立即看到,对于值 12,它落在 2σ范围内。你可能会想——这是不对的,统计数据告诉你现在它是一个更大的值,但是它是怎么知道的呢?
答案是没有。作为估计者,你更清楚值 12 的可能性。如果你认为这是极不可能的,并且有非常非常小的可能是正确的,那么值 12 可能是正确的。如果你认为它不太可能是 12,但它很可能会大于 0.0006%,那么你应该选择一个更大的值。
换句话说,数字就是数字,但是对乐观值、最可能值和悲观值的判断取决于估计者。
评估多项任务
我们之前做的只是热身。我们真正想要的是估计多个任务。虽然我们可以根据 PERT 分布或多或少地计算出单个任务的值,但是如果你有 100 个任务,那么这样做就很麻烦了。
几乎所有的代码都是一样的,除了我们有更多的任务,所以我不会在这里重复。
*tasks = {
"Task 1": [4,7, 12],
"Task 2": [2, 3, 9],
"Task 3": [3, 5, 16],
"Task 4": [6, 7, 23],
"Task 5": [10, 12, 28],
}*
有了这个任务列表,让我们再次运行脚本。

5 项任务的概率分布
现在我们再做一次统计分析。
*Tasks
-----
optimistic likely pessimistic
Task 1 4 7 12
Task 2 2 3 9
Task 3 3 5 16
Task 4 6 7 23
Task 5 10 12 28
Total 25 34 88
Statistics
----------
minimum: 26.3 maximum: 69.7
mean: 41.5
standard deviation: 4.8
skewness: 0.40
kurtosis: 0.06
Probabilities
-------------
* between 40.3 and 42.7 : 32.2% (within 0.5σ)
* between 39.1 and 43.9 : 67.6% (within 1σ)
* between 36.6 and 46.3 : 96.1% (within 2σ)
* between 34.2 and 48.8 : 99.7% (within 3σ)*
因为我们现在有多个任务,所以不能看单个任务的乐观、最有可能、悲观值。我们还需要考虑任务是否相互依赖。简单来说,任务都是相互依赖的,也就是说任务 5 依赖于任务 4,任务 4 依赖于任务 3,如此循环直到任务 1。
所以从逻辑上来说,对于项目来说,任务估计应该是乐观、可能和悲观三栏的总和。作为一个项目,我们看到乐观的总数是 25,最可能的总数是 34,悲观的总数是 88。但是有多准确呢?让我们深入了解一下。
从数字中,我们看到平均值 41.5 与最可能的值相差甚远,而平均值实际上是该分布的最可能值!这意味着通过把最有可能的值加起来,我们最终会有一个更乐观的观点,正如数字所显示的那样。
最小值仅略高于乐观值,而最大值比悲观值小很多。这再次意味着,通过累加悲观值,我们确实太悲观了,而我们只是比数字显示的稍微乐观一些。
分布的偏斜度非常正,因此 over 项目往往更乐观,而峰度稍微为正(实际上非常接近 0),因此该项目在乐观值和悲观值之间的范围内相当平衡。
现在让我们看看概率。您会注意到一些有趣的事情——大约有 67%的可能性项目值在平均值的 1σ以内,96%的可能性在 2σ以内,99.7%的可能性在 3σ以内。这些数字看起来熟悉吗?
如果是的话,那么恭喜你,你在统计学课上没有睡觉,至少在你的讲师给你讲正态分布的时候没有。经验法则指出,对于正态分布,68%的值在平均值的 1σ以内,95%在 2σ以内,99%在 3σ以内。虽然经验法则适用于正态分布,但大多数钟形分布(就像我们得到的这个)多少都遵循这个法则,尽管数字略有不同(这也被称为三西格马法则)。这也是为什么单个任务的早期运行也遵循大致相同的数字的原因。
现在再来看一看概率。数字显示,项目价值有 99.7%的可能性在 34.2 到 48.8 之间。请记住,如果我们将各个列中的所有值相加,乐观值是 25,该项目的最可能值是 34,悲观值是 88!乐观和悲观的价值都不是真实的,最有可能的价值也可能是错误的。
把这些列加起来终究不能说明真实的情况。如果你思考它的含义,它实际上应该是这样的。对于悲观值或乐观值相加,这意味着每个任务都需要全部悲观或全部乐观,这是极不可能的。
那么统计数字实际上意味着什么呢?我们在这里得出的统计数据基本上意味着,如果我们所有的估计都是准确的,那么项目值将有 99.7%可能在 34.2 和 48.8 之间。
理解评估
项目任务的评估是困难的,所有之前显示的统计分析并没有减少对专家判断的需求。最终,无论技术多么强大,如果评估数据完全错误,没有什么能够使它正确。
然而,通过这样的技术分析数据允许我们检测任务估计的潜在问题。它还将帮助我们理解评估,不仅从个人的基础上(正如你从上面看到的,这是有帮助的),而且从项目或其他方面的群体上。

米卡·鲍梅斯特在 Unsplash 上的照片
我们之前所做的练习中,一个任务与前一个任务之间存在简单的依赖关系,但是在更现实的场景中,我们会有多个依赖关系的任务,相互依赖甚至交叉依赖的任务组。
一旦复杂性增加,将项目作为一个整体来看就变得更加困难,并且它的评估很容易出错。使用统计工具可以帮助我们发现潜在的问题,并指导我们做出更好的估计。
这种统计分析还有助于我们更好地指导成本和及时性的预测。随着任务的完成,我们还可以使用分析来与实际值进行比较,然后更新和修改未来任务的估计,以获得更高的准确性。
度量单位
在前面的练习中,我讨论了任务价值和项目价值,但是我对度量单位本身并不清楚。我指的是持续时间吗?我指的是完成任务和项目所需的时间吗?是几天、几周还是几个月?或者我看的是工作量,以人工日或人工周或人工月计算?成本如何,以美元和美分计算?还是复杂?
实际上,我们可以用这个来衡量上面的任何一个,只要我们想要衡量的东西有数值。如前所述,在一些敏捷方法中,团队提出了他们自己的任务度量单位(有人提出了坚果或模糊的时间单位,scrum 甚至完全取消了单位),这很好。
然而,我们也应该明白,在一天结束时,项目成功通常是根据它是否按时、在成本范围内和高质量来衡量的。
用微软 Excel?
我在这里用 Python 和 Jupyter Notebook 做了所有的工作。对于许多项目经理来说,这不是一个自然的使用工具——大多数人更喜欢用 Microsoft Excel 来做所有这些计算。
好消息是,Excel 是一个优秀的工具,拥有所有必要的统计计算功能。坏消息是 Excel 每张工作表最多有 1,048,576 行和 16,384 列。所以,如果你想做 1000 万次蒙特卡洛模拟,你可能无法做到每行一次模拟。
事实上,我们每个任务做了 1000 万次模拟,如果你有大量的任务,你就要倒霉了。此外,即使这不是问题,处理 100 万行对于 Excel 来说也需要相当长的时间,而我们在 Jupyter Notebook 中运行的 Python 脚本对于单个任务只需要 2 秒,对于 5 个任务大约需要 7 秒。
一些最后的想法
Ulam 和 von Neumann 在曼哈顿项目工作时,他们提出了蒙特卡罗模拟的想法,PERT 是为了支持美国海军的潜艇核导弹项目北极星而创建的。具有讽刺意味的是,这两种技术都是出于军事需要而发明的,都与核武器研究有关。
战争和军事野心一直是历史上创新的最强驱动力之一。虽然这些野心给数百万人带来了痛苦,但令人欣慰的是,从这种恐惧中诞生了如此出色的工具,也可以帮助我们的生活变得更加轻松。
估计社会距离的影响
估计疫情动力学参数的贝叶斯方法
在我的上一篇帖子中,我创建了一个 GUI,使用确定性 SIR 模型来模拟新冠肺炎疫情的动态。然后我提到了一些关于创建一个奇特的方法来估计模型中随着时间推移的感染率β**。今天我将 β,作为一种状态添加到 SIR 模型中,将其建模为随机过程,从而创建了一个随机 SIR 模型。然后,我使用了一种名为无迹卡尔曼滤波的奇特方法,以及一种更为奇特的叫做无迹 Rauch-Tung-Striebel 平滑法的方法,来估计整个过程的状态,特别是 β 来看看数据中是否有任何证据表明社交距离确实有效。
那些对数学不感兴趣的人可以跳过技术细节,看看漂亮的图片。如果你对数学感兴趣,尤其是贝叶斯估计,请原谅我所做的任何愚蠢的近似。每次我假装某个东西是高斯的或者近似线性的,那只是我想应付过去。但是如果你有更好的近似或方法,请在这里加入进来。

在我的上一篇文章中,我使用了报告的病例数,因为当时瑞典的死亡人数并不多。现在看一下数据,报告的病例似乎不是一个非常可靠的指标,因为它会受到政策和行为变化的影响。不幸的是,现在每天都有相当多的死亡人数,而这些数据并不受制于相同的时间环境,因此我选择使用这些数据进行这项研究。
上次我还忽略了 SIR 模型背后的实际数学运算,这实际上非常简单。三个组 S 可接收、 I 感染和 R 不可接收按照下面的微分方程描述进行耦合:

另外值得一提的是,N ≡ S + I + R 是常数。因此,目前我们有一个确定性模型,其中感染率β 和回收率γ 是常数。我也将坚持我的可疑主张,γ=0.2,但现在我们将β放入模型状态,并添加两个方程:

所以我们说,我们不能确定性地模拟β,但我们说,它随着某个速度而变化,该速度的时间导数是白色和通常分布在零附近,有一些标准偏差 q 。与我们所说的β及其时间导数 马尔可夫 相反,术语“白色”在此上下文中意味着过程 v(t) 没有记忆,意味着在预测任何未来状态时,关于某一时刻状态的任何知识都不会添加任何信息。这意味着该过程具有记忆,并且当前状态足以描述前进的过程,关于该过程的任何先前信息都是多余的。
好了,现在我们有了一个随机 SIR 模型,非常酷。但是我们该拿它怎么办呢?嗯,这个模型为我们提供了一些关于疫情动态的信息,现在我们想要融合这些数据来估计疫情当前的状态。也就是说,人群中目前有多少易感者、感染者和耐药者,以及感染率是多少。最终,我们也希望回到过去,回顾疫情爆发的情况。
事实证明,假设您有一个带有白高斯过程噪声的线性过程模型,并且我们可以用一个带有白高斯测量误差的线性模型来描述测量结果,那么就有一种使用测量数据来估计过程状态的经典方法。高斯意味着正态分布,正态分布的白色过程噪声我们有-检查。我们的模型并不完全是线性的,但是我们将不得不在以后解决它。首先,我们必须提出一个测量模型。现在有一个:

所以第 k 天的死亡人数是泊松分布,其比率与感染人数成比例,乘以λ,即死亡率。如果死亡人数足够多,比如说> 30,那么正态分布就是一个相当好的近似值。对于死亡人数为 < 30 的情况,我们只需假设近似值是可以的。虽然这个模型中的测量误差是白色的,但如果你使用任何随时间聚合的数字,这是开始玩卡尔曼滤波器时常见的错误。
现在,如果我们的模型是线性的,我们基本上已经使用了卡尔曼滤波器,但情况并非如此,所以我们必须做些什么。如果模型是相当线性的,可以选择每次使用估计值将其线性化(这被称为扩展卡尔曼滤波器),但这个模型并不那么好,事实证明。对于所有好奇想知道我是怎么知道的数学书呆子来说,这是因为时间导数的雅可比不是幂零的。🤓
因此,我们使用一种叫做无迹变换的东西,这实质上意味着将分布离散化成许多点。这些点然后可以使用非线性模型传播,然后可以用于计算预测的分布和称为卡尔曼增益的非常重要的矩阵。这个版本的卡尔曼滤波器被称为 无迹卡尔曼滤波器 ,由于许多其他原因,它非常好。它不需要大量的分析计算,该模型的工作原理非常简单。它通常还具有比扩展卡尔曼滤波器更好的数值稳定性。
现在,我们所要做的就是为我们的零日爆发参数制定一个无信息先验分布。这意味着我们将状态参数的知识描述为多元正态分布,其中一些初始猜测为平均值,一些非常夸张的方差反映出我们在这一点上对系统了解不多。然后,我们可以预测第一天的先验分布,使用卡尔曼增益更新数据,预测第二天的先验分布,等等。在某一点上,我们到了我们拥有数据的最后一天 N ,在这一点上,我们将有一个那天的无偏最优估计…假设我们不记得我们在这一过程中所做的任何欺骗和近似。🤔
现在的问题是,所有早期的估计都已经过时,但是我们希望利用所有信息来估计由于政府法规和建议的增加而发生的β变化。幸运的是,洛克希德导弹公司的三名聪明的德裔美国火箭科学家想出了卡尔曼滤波器的扩展,可以回到过去,并解释“来自未来”的信息。这些家伙被称为 Rauch,Tung 和 Striebel,因此这种方法被称为 Rauch-Tung-Striebel 平滑 。
然而,另一个问题是,这种方法并不适用于无迹卡尔曼滤波器。但是不到十年前,一位名叫 Simo srkk 的芬兰研究人员提出了一个解决方案。现在我们有了模型,有了数据,我们可以断言一些初始猜测,使用无迹卡尔曼滤波器估计每天的状态,当我们到达终点时,我们使用无迹 Rauch-Tung-Striebel 平滑器返回。👌
在得出结果之前,我还应该提到,我对数据做了一些预平滑处理,原因有两个。主要是为了缓解由于卫生保健当局报告死亡日期的方式存在缺陷,一些工作日的死亡人数一直较低或较高,以及总体而言较高的可变性。还因为高斯假设对低死亡率数字并不完全适用。有更好的方法来处理这个问题,但现在必须这样做。
我还应该提到,我实际上通过在 SIR 模型中添加另一组感染者,使事情变得有点复杂。被感染的个体被转移到第一组,在那里他们可以影响其他人,之后他们转移到第二组,在那里他们为死亡预测做出贡献。我做了这个选择,因为在报告的病例和死亡之间似乎存在延迟,这在标准 SIR 模型中没有反映出来。此外,我工作了一段时间,将报告的病例和死亡的数据结合起来,在这种情况下,这是必要的,然后碰巧我没有从模型中删除它。这些组之间的转换率与示例中的回收率γ相同。
此外,死亡率λ未知,也没有可靠的估计值,因此我将提供死亡率为 0.5%、0.2%和 1%的例子。死亡率λ可以从总死亡率和假定的恢复率γ计算出来。这些示例包含β随时间变化的标准偏差估计值,以及从 4 月 10 日开始的预测值,其中最佳猜测显示为实线和虚线,代表β估计值的一个标准偏差。

死亡率= 0.5%

死亡率= 0.2%

死亡率= 1%
这些结果至少表明,社会距离政策对感染率β产生了影响,在一个月的时间里,感染率β似乎从 0.5 下降到 0.27±0.03。鉴于实际死亡率约为 0.2% ,感染率保持在接近0.2%,在这种情况下,只有大约 8.000 瑞典人将失去生命,死亡高峰似乎将在 4 月末到来。
另一方面,如果实际死亡率接近 1%,高峰将出现在从 5 月到 6 月的转折时期和30.000 到 60.000之间,瑞典人将失去他们的生命,这取决于社会距离的持续成功。
这是一个微妙的平衡之举,当局必须用有限的数据和生硬的工具进行干预。而且赌注显然很高。
估计美国未来冠状病毒病例的数量
更新 3/14/2020 :本文底部的模型预测在 3/11 到 3/14 之间的平均绝对误差(MAE)为 86。这意味着到目前为止,本文中概述的 AR-X(1)模型在平均 86 个冠状病毒确认中是准确的。 2020 年 3 月 18 日 :更新统计数据见 后续文章 。 2020 年 4 月 10 日更新 : 最近的数据表明 美国正走在一条悲惨的道路上,比地球上任何其他发达国家都要经历更多的冠状病毒感染和死亡。
仍然大部分是坏消息,但是隧道的尽头有一线光明。
随着疾病预防控制中心和美国当局争先恐后地为公众准备足够多的冠状病毒测试,如果我们能够每天估计美国未来的新冠肺炎病例数量,将会有所帮助。我们可以通过评估该疾病在其他国家的传播速度来做到这一点。虽然这篇文章的标题指定美国为目标受众,但下面概述的模型可能适用于大多数确诊冠状病毒感染超过 500 例的国家。
这项工作建立在我上一篇文章的背景之上,在这篇文章中,我评估了冠状病毒的全球死亡率的可变性,研究了滞后死亡率,并使用一些简单的数学方法估计了当时美国未确认的新冠肺炎病例总数。
约翰·霍普斯金大学系统科学与工程中心最近发布了一个非常有用的仪表板…
link.medium.com](https://link.medium.com/aPNhU635C4)
和以前一样——如果你在寻找关于新型冠状病毒的最新指导和新闻,请参考疾病控制中心或你的国家公共卫生研究所。以下是对约翰·霍普斯金·CSSE 截至 2020 年 3 月 10 日收集的冠状病毒数据的分析,并严格出于教育和研究目的向公众提供。

这种疾病传播有多快?
上图显示了自约翰·霍普斯金数据的第一个追踪日期以来,各个国家的新冠肺炎确诊病例数是如何增长的。初始追踪日期要么是第一个输入的可用数据点,如中国的情况,要么是该国记录的第一个感染病例。在图表中,我们看到新型冠状病毒在对数尺度上以大体一致的方式传播。
在国家达到 500 例确诊病例后评估数据,我们看到这一趋势持续到数千例。这些数据描绘了一幅相当黯淡的画面。这表明,美国正在经历与那些报告称医院不堪重负的国家相同的感染水平,例如意大利、T2、南韩和 T4。



上面的皮尔森相关矩阵和时间序列图表明,在 500 例确诊病例后,疾病在世界各地的传播惊人地相似。几乎在所有情况下,我们都看到感染人数开始缓慢增长,然后迅速呈指数增长。根据我们目前掌握的数据,很明显,这个问题的估算方法既不复杂也不复杂。
新冠肺炎汇总统计
我们可以利用上述数据的四分位数范围来创建一个参考表,该表概述了一个国家出现 500 例确诊感染病例后几天内预计的新增病例数。这可能是最简单但也是最天真的方法,我们可以用它来估算感染人数如何在各国间增长。然而,由于它不是特定于任何一个国家,这也意味着任何阅读本文的人都可以将其应用于自己的国家,以模拟该疾病在自己国家内的传播。

从 3 月 8 日到 3 月 10 日,我们看到美国确诊病例数量的增长与其他国家超过 500 例确诊感染病例的数据一致。如果这种疾病继续以类似的方式在美国传播,那么到 3 月 20 日,可能会有 6975 至 14270 例确诊冠状病毒病例,到 3 月 25 日,可能会有 8125 至 33463 例确诊病例。也就是说,应该注意的是,随着时间的推移,观测值会减少-中国、日本、意大利和韩国是数据中仅有的拥有超过 15 天数据的国家-因此,预期误差会随着未来的推移而增加。
还有一个额外的缺点——上表假设了测试中的等价性,我们知道这不是真的。鉴于缺乏测试,美国的官方统计数据可能会长期漏报,因此我们需要更具体的东西来模拟美国确诊的冠状病毒感染。
参数估计
用技术术语来说,我们建立了一个自回归外生模型(AR-X(1)),其中我们根据前一天的值以及来自外生但统计上相关的趋势的输入来估计每一天新增病例的平均值。在这种情况下,我们的外生变量是该组中其他国家确诊病例数的中位数。我通过以下方式计算模型:( 1)选取所有至少有 100 例确诊感染的国家,( 2)使用样本中每天的病例数中位数,( 3)估计美国到目前为止的预期病例数。该模型符合 Python 的 statsmodels 包(|AIC|: 3.70,|BIC|: 3.66,RSS: 0.43),看起来如下:

上述自回归模型目前预测未来 7 天美国确诊病例数如下:

鉴于美国缺乏测试,目前的模型有可能是向下偏的。一旦测试增加,我们可能会看到案例数量的显著变化,这将需要我们重新训练模型。
美国的结果会有什么不同呢?据推测,美国人民可以通过在局势失控之前主动采取措施来实践社交距离来改变他们的未来。
取消一切。
估计任意选择地区的人口
仅使用 OpenStreetMap (OSM)功能

使用本帖中描述的模型进行人口估计的例子
介绍
自古以来,人们就一直在寻找关于一个特定地方或国家人口数量的信息。旧帝国和国家会不遗余力地粗略估计其领域的居民人数,以确定可以招募的军事力量或可以征税的人数。
在近代,估计人口的方法有了很大的改进,变得更加精确,现在大多数政府都定期进行人口普查,并辅以出生、死亡和移民记录,以及上学人数、税收清单、选民登记册等。尽管如此,许多国家和地区仍然缺乏关于其人口的准确信息,即使在这些信息已知的地方,也缺乏细粒度的公开可用信息,通常只有相对较大的行政级别(如村庄、议会等)的数据是已知的或可访问的。
记住这一点,在这篇文章中,我们将研究一种通用的方法来估计世界上任何给定地区的人口,只使用世界上最大和最容易访问的公共数据集之一的要素:OpenStreetMap【OSM】。
OSM 是一个主要由志愿者构建和维护的大规模协作世界地图,它拥有关于各种事物的丰富信息,如道路(高速公路、小学、住宅等)建筑(住宿、商业、宗教等)便利设施(餐馆、酒吧、娱乐、交通等)商店****休闲区、运动场所, 以及大量的其他特性,这些特性可以通过使用 API(例如overAPI)提取,或者像本项目中的情况一样,通过使用工具(例如 PyOsmium )直接从 OSM 文件中提取。
我们在该项目中使用的人口训练数据(间接)来自脸书的高分辨率定居层,它使用卫星图像估计给定区域的人口。虽然也许所述模型可以实现更高的精度,但是对新的用户定义的区域执行预测可能意味着能够使用首先使用的图像处理算法,这很可能不是公开可用的,更不用说该任务所需的可能很高的计算资源了。
因此,拥有一个仅基于公开可用数据、使用相对较少的特征集进行同类预测的模型有明显的优势(OSM)。这个项目的主要目标是提供这样一个模型作为最终结果。
方法学
这个项目由三个不同但密切相关的主要步骤组成:数据收集、数据分析和模型训练。
注意:正如您将看到的,执行了两个有些独立的工作流,一个使用一组更基本的 OSM 要素(是原始源数据集的一部分),另一个使用一组扩展的 OSM 要素(添加到原始数据中)。后者将是本次分析的主要焦点,但我们也将讨论前者。
数据收集
我们从一个现有的数据集【1】开始,它由多个六边形组成,边长 400 米,横跨整个地球(减去一些阴影区域)。其中包含来自脸书高分辨率定居图层的关于人口数据的聚合数据,并结合了一些 OSM 要素,如 OSM 对象的数量、建筑物的数量、绘制该区域地图的 OSM 用户的数量、道路的总长度等。
从这个庞大的数据集中,选择了包含大不列颠(英格兰、苏格兰和威尔士)的一个较小的子集区域,并对该模型进行了过滤,结果得到了一个由大约 300k 个六边形组成的数据集。选择该地区是因为其在高密度城市地区和低密度农村地区之间相对较大的分布,以及相对较好的地图绘制。生成的数据集的快照如下所示。

红色区域表示人口较多的区域
由于该数据中存在的 OSM 要素不足以解释足够的差异(正如我们将在结果部分中看到的),我们投入了大量精力来构建一个应用程序,该应用程序在给定一个基本 OSM 文件和一个定义研究区域的 GeoJSON 多边形的情况下,可以自动检索多个要素并将这些要素映射到所提供的多边形。
OSM 数据模型是这样的,有节点、路和区。节点是所有其他更复杂结构的基本构建块,当它们具有相关联的标签时,它们被包括在计数中。路代表表示线的节点的集合,例如用于绘制道路。因此,它们被映射为一个长度。最后,区域是在相同位置开始和结束的节点的集合,用于绘制建筑物或任何其他结构,因此,被绘制为区域。
因此,最终这相当于大约 120 个提取的特征,这基本上对应于可以从 OSM 地图中提取的大部分信息。例如,在下图中,所有紫色标签对应于商店,然后按类别划分(如食品、服装、美容等),而暗黄色标签对应于娱乐设施,再按类别划分(食物、娱乐、交通等)。
要深入了解特性集合背后的基本原理,请访问相应的 项目 和 OSM 维基 。

OSM 标签示例
收集完数据后,执行了一些数据清理,包括删除只有一个值的列和离群值。因为没有分类变量,所以不需要一次性编码。在此之后,数据就可以进行分析并构建模型了。
数据分析
在数据收集和准备步骤之后,进行探索性分析,以便了解数据以及目标变量群体和其他独立变量之间的关系。因为我们在构建回归模型,所以数据最重要的特征之一是因变量(目标变量)和自变量(特征变量)之间的相关性。也许不出所料,发现变量highway_residential_length 、 landuse_residential_area和highway_bus_stop_count具有最高的相关性,因为这些变量与住宅区相关联,因此与人口密集的地方相关联。相反,负相关性最高的变量是natural_area和landuse_agricultural_area,这也是意料之中的,因为这些类型的特征与低人口密度相关。下图显示了完整的关联结果。

所有特征和总体之间的相关性
仔细看看这些变量之间的关系,,highway_residential_length,,,,,,之间的相关性很强,但,building_accommodation_count,,population,之间的相关性较弱。对于负相关的变量,我们可以观察到关系不是线性的,而是抛物线的,这已经给了我们一个指示,或许变量的多项式项将提供更好的数据拟合。**

对数据进行空间可视化也带来了一个有趣的视角,证实了我们在散点图中看到的相关性。不出所料,城市中心的住宅道路、铁路和建筑较为集中,而农业用地较多的地区或标记为自然的地区在远离城市中心的地方较为集中。

所选要素的空间分布。较红的区域表示较高的值
模特培训
在分析数据后,将机器学习管道放在一起,以便对数据执行一些预处理和转换,然后将训练数据拟合到模型中,测试-训练分为 20-80%。
管道中的一个转换是通过与每个训练示例相对应的区域来标准化所有特征和目标变量,因为这被证明是使结果对更大的区域更通用的更好的解决方案。下面简要描述流水线的步骤:
- 计算面积:该步骤计算输入数据的面积,如果还没有计算的话。
- 特征选择器:该步骤选择模型特征+区域,后者将在下一步使用。
- **面积归一化器:该步骤通过对应于该训练示例的面积来归一化每个特征。
- 删除列:该步骤删除不需要的列;在本例中为区域。
- **特征映射:该步骤将输入特征的多项式项添加到指定次数(如果为 1,则不添加多项式项)。可以选择只包含指数项,也可以包含变量之间的相互作用项。
- **特性缩放:该步骤通过减去平均值并除以标准偏差,使特性值都处于同一比例。
- **回归器:这一步是实际应用回归算法,将数据拟合到模型中。
结果
如前所述,构建了两种不同的模型:第一种方法使用包含少量 OSM 要素的源数据集,第二种方法使用通过定制的应用增加了更多要素的数据集。为了测试模型的性能,选择了两个不同的指标:rr得分,它为我们提供了模型所解释的数据中方差比率的度量,以及平均绝对误差,它为我们提供了模型在可测量的数量上表现如何的指示,在我们的情况下是居民/公里。**
对于建立模型的第一种方法,尝试了线性(套索和山脊和集合(随机 森林和梯度 推进)回归器的组合。在执行超参数调整后,可以看到使用高达三次多项式项和梯度 提升回归量的组合获得了最佳结果,相应的 r 得分约为 0.67,而平均绝对误差约为 158 居民/ km。为了了解我们在偏差-方差方面的表现,我们分析了学习曲线,正如我们所怀疑的那样,我们可以观察到,即使使用多项式来构建变量之间更复杂的关系,模型也存在高偏差,其中训练和交叉验证误差都收敛于相对较高的值。因此,为了建立一个性能更好的模型,我们不需要添加更多的训练数据,但要包括一个更大的特征集,一个可以解释目标变量中更多变化的特征集。

因此,在这些学习的激励下,获得了更多的数据(详见数据收集),使我们准备好将机器学习管道应用于这个丰富的数据集。与前面的方法一样,再次尝试了线性(套索和山脊)和集合(随机 森林和梯度 推进)回归元的组合。在超参数优化之后,高达二次多项式项和梯度 提升回归量的组合再次获得了最佳结果,其 r 得分约为 0.9,而平均绝对误差*约为 91.8 居民/公里。与第一种方法相比,这是一个巨大的进步!这证明了获取更多功能的努力是值得的。再看一下学习曲线,我们看到训练和交叉验证误差仍在收敛(表明模型中存在一定的偏差),但其值要小得多。*

不过,在这种情况下,对一些地方/城市的实际人口值和估计人口值进行了比较。完成后,可以看到使用正则化值为 1 的套索回归变量获得了最佳结果(实际和预测之间的平均误差较低),这表明当使用梯度推进回归变量时,我们可能在某种程度上过度拟合了数据。*
** 为了计算自定义地点的人口,首先需要使用osm-feature-extractor*并绘制所提供区域的 osm 特征。然后,可以将这个中间步骤输入模型,该模型将输出人口密度(居民/公里)。最后,将结果乘以面积,就得到总人口。**

Lasso(左)和梯度增强(右)模型在几个地方的模型结果比较
进一步检查模型,该模型的特征重要性表明,实际上迄今为止最重要的特征是highway_residential_length,而不是 Lasso 回归的更为分散的系数值。这表明了这样一个事实,即 Lasso 回归模型可能更善于概括未知的情况,因为它考虑了更多的特征,因此不容易过度拟合。

Lasso(左)和梯度增强(右)模型之间的系数/特征重要性比较
结论
在这个项目中,我们着手建立一个模型,仅基于从 OSM 数据中提取的特征,该模型可以准确预测给定区域的人口。为此,我们首先从取自【1】的数据集开始,该数据集的特点是特征很少,因此产生了高偏差模型。基于此,我们使用定制的应用程序从 OSM 文件中提取特征来扩展基础数据。
我们看到,添加更多的特征,尽管有给模型增加一些噪声的风险,但提供了更好的预测能力,并使我们能够大大降低平均绝对误差。此外,通过这种方法,我们可以从 OSM 文件中确定性地提取所有需要的模型输入特征,而不是仅使用初始数据,我们没有现成的方法来确定新区域的特征,而不必执行某种逆向工程。
我们看到,尽管梯度推进回归器模型在测试数据上表现更好,但拉索回归器在几个地方/城市的实际人口估计上表现更好,实现了 26%的最大差异。
在这个模型中,我们使用了遍布英国的数据点,这些数据点跨越了人口密度非常高的地区(如伦敦),以及人口密度较低的地区和农田。这应该使模型能够很好地扩展到大多数情况,虽然如果我们在人口密度非常高的地区使用它,可能不是那么好。此外,该模型还取决于研究中该区域的地图绘制程度。在西方世界的大部分地区,OSM 提取的地图绘制得相当好,但在欠发达地区就不那么好了——尽管总的来说,主要的人口中心往往都绘制得很好。
尽管存在这些事实,但我们看到该模型对实际地点和城市人口的估计误差相对较低,并且我们现在有了一个模型,可以仅根据 OSM 特征对任何给定区域的人口进行粗略估计。
参考
****【1】-Kontur 人口:全球人口密度为 4 亿 H3 六边形
****【2】-巴斯特,汉娜,2015。精细的人口估计
用有限混合模型和 EM 算法估计经济状态

有限混合模型假设存在一个潜在的、不可观察的变量,该变量会影响生成数据的分布。这个想法有许多实际应用:例如,股票价格可能根据一些假设的模型而变化,但是这个模型的参数在牛市和熊市期间可能是不同的。在这种情况下,潜在变量是经济状况,这是一个有点不确定的术语,但却非常有影响力。
将有限混合物拟合到数据包括估计数据可能来自的分布的参数,以及来自每个分布的概率。这使我们能够量化和估计重要但未定义和不可观察的变量,例如已经提到的经济状况!然而,使用标准的最大似然法并不容易。幸运的是,聪明的期望最大化(EM)算法拯救了我们。
本文分为三个部分,讨论以下主题:
- EM 算法是什么,它是如何工作的,以及如何用 Python 实现它。
- 如何在实践中应用它来估计经济状况。
- 附录:为好奇的读者提供 EM 算法背后的数学知识。
让我们直入主题吧!

期望值最大化算法
我们将首先使用一些随机生成的数据来讨论 EM 算法。让我们从数据生成过程开始。假设我们的数据可能来自两个不同的正态分布。一个用平均值-4 和标准差 2 来描述。对于另一个,参数分别是 11 和 3。

我们实际观察到的数据是上述两者的混合,定义为

其中δ∑{ 0,1},概率𝑝为 1。在我们的例子中,让我们设置𝑝为 0.65。因此,如果对于给定的数据点δ= 1,它来自分布𝑑𝑎𝑡𝑎1,如果δ= 0,它来自𝑑𝑎𝑡𝑎2.这里,δ是我们在现实中不会观察到的影响数据生成过程的潜在变量。让我们根据这个过程生成一些数据,并绘制它们的直方图。

快速浏览该图表明,数据可能是在两条法线混合的情况下产生的。因此,两个高斯函数的有限混合似乎是这些数据的合适模型。请记住:我们观察的只是数据,我们需要估计的是参数:𝜇1、𝜎1、𝜇2、𝜎2 和𝑝,称为混合概率,是数据来自其中一个分布的概率——比如第一个。
这种数据的可能性很难通过分析最大化。如果你想知道为什么会这样,向下滚动到数学附录。但是还有另一种方法——EM 算法。这是一种使用迭代两步程序提供对数似然函数最大值(可能是局部最大值)的方法:
- 期望(E)步骤,
- 最大化(M)步骤。
在 E 步骤中,我们基于数据和潜在变量δ的联合密度计算所谓的完全数据似然函数。在 M 步中,我们最大化这个函数的期望值。我们迭代地重复这两个步骤,直到参数估计不再改变。所有的数学推导都归入下面的附录中;现在,让我给你提供现成的公式。
在我们的两个高斯混合的情况下,e 步骤包括计算𝑝=1 给出其他参数的概率,表示为𝑝𝑝1:

𝜙(𝑑𝑎𝑡𝑎在哪里;𝜇1,𝜎1)是第一个分布下数据的概率密度,一个具有均值𝜇1 和标准差𝜎1.的高斯分布让我们把它编码下来:
M 步骤中应用的最大化公式如下(滚动到底部查看推导过程):

𝜇2 和𝜎2 的公式是相同的,只是它们用(1−𝑝𝑝1)代替了𝑝𝑝1.让我们把它翻译成 Python:
如您所见,E-step 对参数𝜇1、𝜎1、𝜇2、𝜎2 和𝑝进行条件化,M-step 对其进行更新。为了开始,我们需要在运行第一个 E-step 迭代之前初始化这些参数。一个普遍的选择是将均值𝜇设置为从数据中抽取的任意随机数据点,将标准差𝜎设置为数据的标准差,将𝑝设置为 0.5:
我们现在已经编码了整个 EM 算法!让我们将所有这些代码放入一个名为TwoGaussiansMixture()的类中,使用一个fit()方法,该方法将data和num_iter作为参数,初始化参数,并通过 E 和 M 步骤迭代num_iter迭代。该类还将有其他三个实用程序方法:
predict(),它获取一些数据x,并为这些数据生成我们拟合的高斯混合的预测 PDF,get_mixing_probability(),它获取一些数据x,并返回每个数据点来自其中一个分布的概率,plot_predictions_on_data(),将predict()生成的 PDF 绘制在原始数据直方图的顶部。
现在,让我们用 100 次迭代来拟合我们的模型,并绘制预测的 PDF。

蓝色直方图和上面的一模一样,描绘的是原始数据。橙色线是我们拟合的高斯混合的概率密度,或 PDF。它非常符合数据!我们也可以在上面的图上画出混合概率。

在图的左侧,混合概率接近于零,这意味着模型确定 x 轴上的值来自左侧分布。我们越向右走,模型就越确定数据来自另一个模型。
最后,我们来看参数。他们正确估计了。
print(model.mu_1, model.mu_2, model.sigma_1, model.sigma_2, p)11.263067573735341 -3.893589091692746 2.5184757384087786 2.162510874493102 0.2999296508820708
回想一下,真实均值是-4 和 11,标准差是 2 和 3,𝑝是 0.65(因此 1−𝑝是 0.35,该模型不关心哪个分布是哪个)。参数估计值似乎接近真实值!

评估经济状况
现在我们已经看到了 EM 算法如何处理一些随机生成的数据,让我们将这些知识付诸实践吧!下图显示了美国从 1967 年到 2019 年的季度 GDP 增长率。红色条纹是美联储宣布为衰退的时间段。我们可以看到,衰退与 GDP 增长率的大幅下降相关联。

数据来源:弗雷德
让我们比较一下衰退时期和非衰退时期的 GDP 增长率直方图。

看起来像两个高斯人?这是我们TwoGaussiansMixture()模型的一个很好的用例!在这种情况下,我们假设 GPD 增长率具有正态分布,参数取决于潜在变量δ,δ要么为 1,要么为 0:衰退或不衰退。在这种情况下,参数𝑝可以被解读为衰退的概率,对经济状况的一个很好的估计。
我们将重用我们的TwoGaussiansMixture()类,并使用get_mixing_probability()方法来计算每个原始数据点的𝑝。由于原始概率𝑝非常嘈杂,我们将使用滚动平均来平滑它们。
现在,让我们画出我们估计的衰退概率和美联储宣布的衰退概率。

在过去的三次衰退中:2007 年的房地产泡沫、21 世纪初的互联网泡沫和 1990 年的油价冲击,我们的估计都达到了峰值,表明衰退的概率很高,而事实也确实发生了。一些早期的衰退也被很好地捕捉到了,尽管模型显示 1983 年有 90%的可能性出现衰退,但实际上并没有出现。
也许这个模型并不完美,但请记住,它能看到的唯一数据是 GPD 增长率,并且它输出了对经济状况的概率估计——可能是 1983 年预测的峰值捕捉到了经济几乎崩溃的危险吗?

感谢阅读!如果你对 EM 方程的来源感到好奇,请随意阅读下面的数学附录。不然就自己抓点数据建个有限混合模型!所有的代码,包括产生情节的代码,都可以在这里找到。
如果你喜欢这篇文章,试试我的其他文章。不能选择?从这些中选择一个:
揭秘著名的竞赛获奖算法。
towardsdatascience.com](/boost-your-grasp-on-boosting-acf239694b1) [## 线性回归中收缩法和选择法的比较
详细介绍 7 种流行的收缩和选择方法。
towardsdatascience.com](/a-comparison-of-shrinkage-and-selection-methods-for-linear-regression-ee4dd3a71f16) [## 模型选择和评估
超越火车价值测试分裂
towardsdatascience.com](/model-selection-assessment-bb2d74229172) 
附录:EM 算法的数学
在这个可选部分,我们将展示为什么我们必须使用 EM 算法来估计混合模型。我们还将推导出之前应用过的公式。
回想一下数据生成过程如下:

让我们将所有的模型参数共同表示为𝜃={𝜇1,𝜎1,𝜇2,𝜎2,𝑝}.
由于数据是两个高斯混合,并且数据点是独立的,因此数据的似然函数是每个数据点的高斯混合的乘积:

其中𝜙表示高斯分布的 PDF。如果我们取似然性的对数,以便更容易地最大化它,请注意,高斯 pdf 上的和将出现在对数内,这一点也不容易。我们可以尝试数值方法,但这对于更多的高斯混合来说很难。最后,我们还想知道在给定参数(即概率𝑃(δ=1|𝜃).)的情况下,哪个分布与每个数据点相关
可能性
这是电磁魔法的切入点!即使δ未被观察到,我们也可以认为它是数据集的一部分。这被称为数据增强(不要与这个术语的机器学习含义混淆,它表示基于真实的观察人为地创建更多的数据)。然后我们考虑所谓的完全数据似然函数,基于数据和δ的联合密度。
根据条件概率定律,我们可以推导出数据和δ的联合密度:

其中,𝐼是指示函数,如果其自变量为真,则为 1,否则为 0。完全数据似然函数是上述跨观察的产物:

当我们对其取对数时,乘积的对数变成对数的和,我们得到下面的对数完全数据似然函数:

电子步骤
上面的对数似然是需要最大化的。然而,我们没有观察到它的𝐼(δ𝑛=1 部分。因此,我们简单地取δ的期望值。这需要我们计算期望𝐸[𝐼(δ𝑛=1],这就是𝑃(δ=1|𝜃).在上面的代码中,这个量被表示为𝑝𝑝1,可以计算如下:

完成后,我们可以将上述内容代入𝑙𝑜𝑔𝐿的公式,计算出预期对数似然:

m 步
艰苦的工作完成了!最大化上述内容实际上很简单,因为有三个独立的相加部分,它们中的每一个都可以单独最大化。第一部分提供了𝑝作为𝑝𝑝1.平均值的新估计第二个可以使用普通的 PDF 公式重写为:

其在将一阶导数设置为零并求解最大值后,提供了用于更新𝜇1 和𝜎1:的公式

可以相应地推导出更新𝜇2 和𝜎2 的公式。这些是我们在前面的代码中使用的精确公式。
新冠肺炎在个别年份的特定年龄风险
据报道,10-20 岁年龄段人群中存在新冠肺炎的年龄风险因素。我们可以做得更好。很容易估计特定年龄的个体年风险,这使得人们能够更准确地评估他们的个人风险水平。
TL;速度三角形定位法(dead reckoning)
我们现在已经有了相当好的关于新冠肺炎相关风险的数据,但这些数据并没有以让人们容易理解或使用的方式呈现出来。这一系列的目的是帮助人们更清楚地评估新冠肺炎对他们自己和他们所关心的人的风险。
查看文章底部的图 8,了解特定年龄的风险水平。

裘德·贝克在 Unsplash 上的照片
谁会以 10 年为一个年龄段来描述自己的年龄?
你可能见过许多类似图 1 所示的图表,它显示了年龄如何影响新冠肺炎风险。

图 1-新冠肺炎基于年龄的死亡率。具体数字摘自本系列第二部。
这些图表有助于传达风险随年龄增长的一般概念。但是他们不太擅长传达任何特定年龄的风险水平。如图 2 所示,我 70 岁那天会发生什么?我的风险是否在一天内从 0.9%增加到 2.4%?

图 2——像这样的图表不能精确地传达特定年龄的风险。
你的风险当然不会在一天内增加。在你 60 多岁的时候,它一直在增加,在你 70 多岁的时候,它还会继续增加。图 1 和图 2 中的图表实际上是稳步增长的风险水平的粗略近似值,如图 3 所示。

图 3——显示风险的条形图实际上显示了年龄段中点的风险水平。
条形图上的每一条实际上显示了每个年龄段的平均风险水平。或者,换句话说,它显示了每个年龄段中点的风险。
在每个年龄段的低端,你的风险比显示的要低,在每个年龄段的高端,你的风险比显示的要高。61 岁时,你的风险低于 0.9%。69 岁时,你的风险高于 0.9%。只有当你接近年龄段的中间值,也就是接近 65 岁时,你的风险才是 0.9%。
使用内插法估计年龄风险因素
据我所知,没有政府机构或研究人员发表过新冠肺炎的年龄特异性风险。然而,使用插值的数学技术,更具体的风险水平很容易从可用数据中估算出来。
让我们看一个例子。假设我们想估计 69 岁老人的死亡率。我们从我们知道的开始。如图 4 所示,我们知道 65 岁时的死亡率为 0.9%,75 岁时的死亡率为 2.4%。我们想知道的是 69 岁时的死亡率是多少。

图 4
我们知道另外一个可能不太明显的事实,那就是 69 是 65 到 75 的 40%。
插值是这样的假设,如果你有两个相关的标度,并且其中一个标度上的一个因子是从一端到另一端的 40%,那么相关标度上的相关因子也必须是从一端到另一端的 40%。这种假设不一定 100%正确,但除非我们相信一个人的风险因素确实在他们的生日那天突然增加,否则这是一个合理的近似值。
如图 5 所示,当我们计算时,这意味着 69 岁的人的死亡率为 1.6%。

图 5
一个小问题
图 3-5 中使用的中点是年龄组的直接算术中点。例如,我显示 65 岁是 60-69 岁年龄段的中点,因为它是 60-69.999 的中点。(真正的年龄段不是 60–69,是 60–69.999。)
每个年龄段更准确的中点应该使用每个年龄段实际人数的加权平均值来计算。直到 60 岁,这种人口加权中点和算术中点之间的差异是最小的,但对于 60-69 岁年龄段,这种差异是一年的四分之一,而对于 70-79 岁年龄段,这种差异是一年的三分之二。
每个年龄段的具体差异如图 6 所示。

图 6-每个年龄段的算术和人口中点。80 岁以上年龄段的中间点是以不同的方式确定的,将在本文后面解释。
现在我们有了更准确的年龄组中点,我们应该修改图 5 所示的插值,以使用更准确的中点。该修订如图 7 所示。

图 7
从图 7 中可以看出,在这种特殊情况下,69 岁的风险系数 1.6%保持不变。然而,其他年龄段的风险因素确实会发生变化。
真正的特定年龄风险因素
我们可以对所有其他年龄进行与图 7 中相同的过程,使用年龄组的人口加权中点,并为每隔一个年龄创建一个特定年龄的风险因素表。这些计算的结果如图 8 所示。

图 8
限制和注意事项
以这种方式插值是一种近似的练习。图 8 中的数字并非基于死亡数据本身;它们相当于可以从粗略数据中近似推断出的额外精度。
这种方法还有一些额外的限制。
第一个限制是,我们不能插值超过最年轻和最年长年龄带的中点。
在低年龄方面,我们知道年龄范围的中点是 10.15,我们知道风险系数是 0.0012%。但是由于我们没有 10.15 岁以下人群的风险数据,我们没有在更年轻的年龄插入风险因素的基础。这意味着 10.15 岁以下的所有因素都是一样的。由于四舍五入,11 岁和 12 岁的附加因素看起来是一样的。
在高年龄方面,死亡率数据停留在 80+。我们知道下面年龄段的中点是 74.35,我们知道它的风险系数是 2.4%。我们知道下一个年龄段的风险系数是 4.4%,但我们不知道它的中点,因为它被描述为“80+”。对于这个最高范围,我将中点定义为 85 岁。美国人口普查数据显示,80-84 岁的人口有 610 万,85 岁以上的人口有 650 万。根据这些数据,真正的中点一定在 85 岁以内。
由于我们没有 85 岁以上人群的死亡率数据,我们无法对 85 岁以上人群进行插值,因此每个更大的年龄都有相同的风险因素。
为什么特定年龄的危险因素很重要?
图 8 中的风险因素允许一个人比 10 年年龄段的人更准确地评估他们的个人风险。如果你快 50 岁了,感觉非常好,因为从 50 岁到 59 岁的平均风险系数只有 0.30%,查一下表格。58 岁时,你的风险系数是 0.50%,当你 59 岁时,它攀升至 0.56%,这几乎是你年龄段中点风险系数的两倍。
在文章的开始,我指出一个 70 岁的人在他们 70 岁的那天死亡风险不会从 0.9%增加到 2.4%。事实上,从表中可以看出,他们的风险从 1.6%增加到 1.7%,当然这也不是一天之内发生的。
尽管这篇文章比其他地方更准确地介绍了新冠肺炎风险,但仍然缺少一点,即有无共病。我将在本系列的下一篇文章中展示共病是如何影响个人风险的。
这是关于新冠肺炎死亡率的 5 集系列报道的第 4 集:
- 第一部分 :为美国建立一个总体基础 IFR
- 第二部分 :基于年龄的 IFRs
- 第 3 部分 :基于人口统计的各州和各国 IFRs 的变化
- 第 4 部分:按个别年份分列的 IFRs
- 第 5 部分:有无共病的 IFRs】
更多详情请访问新冠肺炎信息网站
更多美国和州级数据,请查看我的新冠肺炎信息网站。
我的背景
20 年来,我一直专注于理解软件开发的数据分析,包括质量、生产率和评估。我从处理噪音数据、坏数据、不确定性和预测中学到的技术都适用于新冠肺炎。
估计、预测和预报
估计与预测。预测对预测。请跟着读,以便快速区分

马库斯·温克勒在 Unsplash 上的照片
估计意味着使用历史数据找到最佳的参数,而预测使用这些数据来计算未知数据的随机值。
在我们继续下一步之前,上面陈述中突出显示的单词需要一些上下文设置:
我们需要大量的历史数据来学习机器学习和建模的依赖性。数据通常涉及多个观察值,其中每个观察值由多个变量组成。这个多变量观察值 X 属于随机变量 X,其分布位于被称为‘自然状态’的可能分布的有限集合的范围内。
估算是优化自然界真实状态的过程。粗略地说,估计与模型构建有关,即找到最合适的参数,该参数最好地描述了历史数据的多元分布,例如,如果我们有五个独立变量,X1、X2……X5 和 Y 作为目标变量。然后,估计包括寻找 f(x)的过程,f(x)是由 g(θ)表示的自然的真实状态的最接近的近似值。

训练数据的参数估计
然而,预测利用已经建立的模型来计算样本外的值。它是计算另一个随机变量 Z 的值的过程,这个随机变量的分布与自然界的真实状态有关(这个性质在任何机器学习算法中都起着举足轻重的作用)。平均而言,当所有可能的 Z 值都一致时,预测被认为是好的。

对未知数据的预测
有多种方法可以解释这两者的区别,让我们也来探索一下贝叶斯直觉:
估计是在事件发生之后,即后验概率。预测是事件发生前的一种估计,即先验概率。
让我们总结一下我们对估计和预测的理解:为了对看不见的数据进行预测,我们在训练数据集上拟合一个模型,该模型学习估计器 f(x),该估计器用于对新数据进行预测。
现在,我们了解了预测是什么,让我们看看它与预测有什么不同。
预测问题是预测问题的子集,其中两者都使用历史数据并谈论未来事件。预测和预报的唯一区别是在预报中明确增加了时间维度。
预测是基于时间的预测,即在处理时间序列数据时更合适。另一方面,预测不需要仅仅基于时间,它可以基于影响目标变量的多个因果因素。
我偶然发现了一个非常新鲜的视角,用单词本身的起源来解释预测和预报之间的差异。
我将在本帖中简要介绍这个创新的插图,但是你可以在原帖这里阅读更多关于它的内容。
预测更多的是面向过程,遵循一定的做事方法论。在某种程度上,它假设过去的行为是未来将要发生的事情的足够好的指示器。
预测考虑所有的历史过程,影响变量和相互作用来揭示未来。
总之,所有预测都是预测,但并非所有预测都是预测。
希望你现在已经清楚了估计和预测之间的区别。这篇文章还强调了预测和预报之间的区别。
快乐阅读!!!
对抗带有种族偏见的警察算法的伦理障碍
调整用于刑事司法的算法的变量权重可能是有希望的,也可能是有问题的。

辛辛那提市议员杰夫·帕斯托尔(摄影:卡里姆·埃尔加扎/The Enquirer,原载于 cincinnati.com)
在 2019 年日历年结束时,俄亥俄州辛辛那提市议员杰夫·帕斯托尔(Jeff Pastor)呼吁对该市警务工作中的种族差异进行全面审查。斯坦福开放警务项目进行了一次广泛宣传的报告后,帕斯特恳求纽约市进行评估。该报告发现了该市交通拦截的显著差异,包括一项发现“辛辛那提警察在黑人占主导地位的社区比白人多拦截了 120%的居民。”
要求进行审查的呼吁重新激起了警察问责活动家和公共政策界的辩论。随着预测性警务和其他数据驱动策略变得越来越普遍,一个持续发展的主要问题是潜在的有偏见的警察数据会变成什么样?如果警方的互动有偏差,这些数据一旦输入预测模型,就可能导致有偏差的输出,引导警方采取有偏差的行为,即使在警官不知情或不服从的情况下。正如现在的老话所说,“垃圾进来,垃圾出去”。
修复并不简单
学者、活动家和爱好者已经在将算法公平性问题带到主流关注的前沿方面取得了长足的进步。面部识别扩散已经在多个地方被停止,直到可以开发出合理的安全措施。这发生在种族差异被公开之后,部分原因是人工智能在同质数据集上接受训练,该数据集不包括肤色较深的人。
但是,创建包容性数据集作为一种解决方案并不总是适用的,特别是当涉及到基于历史警方数据的预测性警务时。创建一个道德框架是困难的。有了预测性政策,就不是数据科学家创建数据集了。这不仅仅是一个过于同质的集合的问题,而是可用的历史数据在被输入任何预测模型之前可能被污染。一个统计模型可以遵循科学审查的最高标准,但当地面上的个人可以引入有偏见的数据时,这可能无关紧要。
内建预期
这就产生了一个问题:可以说,科学家应该用多少数据来进行“先发制人的防御”。
几个月前,公共政策中的有色人种学生研讨会在加州大学伯克利分校高盛公共政策学院举行,人工智能中的种族问题是其中一个主题。该小组由政策专家组成,调查算法不公平的潜在危害,以及活动人士为使政府系统更加透明而正在进行的努力。
该小组讨论了 2017 年斯坦福大学关于奥克兰警官使用语言的种族差异的研究。这项研究中的研究人员使用计算语言学模型来识别语音模式。关键的一点是,该模型可以相当准确地检测出一名官员是否在与一名黑人或白人居民交谈,完全基于对话的文字记录。
小组中的一位数据科学家表示,这样的研究是乐观的理由。她的论点是,如果我们能够确定种族偏见的比率,就像这项研究似乎做的那样,那么你就可以使用调整函数来降低受歧视人口统计数据的得分。
有个缺点,但是统计奇偶性、真阳性率比较和其他“公平指标”中的流行技术在识别偏倚方面显示出希望。然而在实践中,这是有问题的。
引入体重是种族主义的借口吗?
想象一下,警察正在使用一个给定的“热点”软件,该软件使用犯罪的时间、位置和历史报告作为变量来预测未来犯罪的风险。一个可能的策略是首先确定有偏见的政策倾向。假设确定了某个城市的特定网格具有相对高密度的少数种族,并且被过度政策化。因此,人们可能会低估与城市网格相关的变量,这表明数据集中的这些观察结果“不太可信”。
在使用许多预测变量的场景中,类似于当代风险地形预测(与“什么?在哪里?什么时候?”热点模型),可以给变量分配不同的权重。虽然目前没有犯罪前预测性警务的例子旨在为特定人口统计的成员建立预测,但像调整可变权重这样的想法似乎在解决累犯分数的偏见方面受到欢迎。
多年来,美国越来越多的司法管辖区采用“风险评估分数”来帮助确定再次犯罪的可能性。主要用于假释或保释听证会,2016 年 ProPublica 调查发现:
在预测谁会再次犯罪时,[风险评估]算法对黑人和白人被告犯错误的几率大致相同,但方式非常不同。
这个公式很可能错误地将黑人被告标记为未来的罪犯,错误地将他们标记为白人被告的比例几乎是白人被告的两倍。
白人被告比黑人被告更容易被误贴上低风险的标签。
当看到这一点时,从上述小组成员的证词中可以推断出一个巨大的诱惑:“如果人口统计 X以已知的偏差率 Y受到歧视,并且我们有一个包括人口统计信息的预测模型,我们可以调整 T10 人口统计 X 的变量权重,以补偿已知的 T12 偏差率 Y。”
尽管初衷是好的,但这种改革很有可能隐含着接受一定程度的种族主义。在这两种情况下,城市网格的权重或特定人口统计数据的权重都有所降低,一定程度的偏差被接受并纳入模型中。
这可能会造成偏见问题已经“解决”的错觉。这可能会导致不太重视偏见训练。执法部门或州政府可能觉得有必要纠正模型中的问题。如果参与司法系统的个人认为,最终,该模型会纠正他们的行为,他们可能会感到不那么负责。
此外,这带来了新的伦理问题。在犯罪前预测警务的情况下,如果执法中的情绪变化超过了预测算法的能力,该怎么办?预测模型可能不擅长解释剧烈的新变化。假设在一个特定的例子中,执法比分配的权重更有偏向性。在这种情况下,趋势是不是会因为不符合规范而低估这种程度的偏差?假设执法比体重偏差小。在这种情况下,对偏见的内在补偿会成为特定人群的不道德特权吗?
简单地说,偏差率也可能是错误的。这些算法使用历史数据,在某些情况下可以追溯到十年前。偏差率在时间和地点上是静态的吗?这似乎令人怀疑。这是否要求每个在司法事务中使用算法的司法管辖区也量化他们的数据有多大的偏差?如果是,应该多久审计一次这个数字?
我们应该还是不应该包括人口统计信息?
作为对延续种族偏见指控的回应,PredPol,预测警务软件的最大供应商之一,强调他们不使用某些人口统计信息,如种族(尽管这并不能满足因其他原因潜在种族差异的投诉)。这可能是更好的,但陪审团仍然没有出来。
用数据来识别种族差异已经被证明是有用的。但是,正如许多活动家和学者所争论的那样,福柯关于政府统治工作传统的那些人其中最重要的是,人口统计数据也有将个人放入历史盒子并将他们归入官僚类别的风险。例如,人口普查数据在美国被用于拘留日本人,在纳粹德国,它被用于追踪犹太人口。即使没有明显的恶意目的,人口统计数据仍然可以加强分离。它巩固了“他者”的存在。
接下来的问题是,如果偏见持续存在,即使没有人口统计数据,通过消除这些数据,我们已经不可挽回地损害了我们识别偏见的集体能力,该怎么办?
结论
在执法中使用算法似乎不是一种衰落的时尚。随着犯罪前和风险评估中的预测性警务持续增长,数据科学和社会科学领域必须保持警惕。不能忘记,模型的另一边也有人类。应该查询数据,遵循最佳做法,分享对话。
从道德角度收集与认知障碍患者的对话
提高语音助手的可访问性:正确做事
这是我与 T2 的论文的精简节略,发表在 2020 年人类语言技术的法律和伦理问题研讨会上。如果您在研究中使用了本指南的任何内容,请务必引用我们题为“道德地收集与认知障碍患者的多模态自发对话”的论文:
**Harvard:**
Addlesee, A. and Albert, P., 2020\. Ethically Collecting Multi-Modal Spontaneous Conversations with People that have Cognitive Impairments. LREC Workshop on Legal and Ethical Issues in Human Language Technologies.**BibTeX:**
@inproceedings{addlesee2020ethically,
title={Ethically Collecting Multi-Modal Spontaneous Conversations with People that have Cognitive Impairments},
author={Addlesee, Angus and Albert, Pierre},
journal={LREC Workshop on Legal and Ethical Issues in Human Language Technologies},
year={2020}
}
我花了一年多的时间才获得伦理上的批准来收集重要的语料。这是一个相对新鲜的领域,但我希望其他研究人员能够致力于为各种认知障碍患者提供语音助手。这本实用指南旨在帮助像我一样的未来研究人员快速收集这些有价值的数据集,而不损害任何伦理考虑或数据安全。
介绍
一年多前,我决定致力于让痴呆症患者更容易使用语音助手(Siri、Alexa 等)。为了开始这个项目,我(和我的两名主管)首先详细列出了一些关键挑战,如果我们要朝着这个目标前进的话。一个巨大的障碍是缺乏合适的数据…所以让我们收集它?
我首先决定需要哪些数据,并着手组织这项任务、录制地点、录制设备等。我计划录制与痴呆症患者的友好、即兴对话的音频和视频。作为一名数学家/计算机科学家,有一项重要的工作我没有足够的经验在没有帮助的情况下无法完成——伦理审批。

我花了一年多的时间与来自英国国民医疗服务体系、慈善机构、痴呆症研究中心、心理学部门、伦理委员会(名单还在继续)的专家交谈,以确保数据收集既符合伦理又安全。
这篇文章包括我从这些专家那里学到的实用指南和 Pierre Albert 开发的设备“T2”CUSCO 的细节,以尽可能安全地捕获和存储这些数据。
数据
我之前已经讨论了 为什么这些数据很重要,但是在本指南的上下文中,我将在简要描述我们正在收集的哪些数据之前对此进行扩展。
自然语言
虽然我们和其他人有自然的日常对话,但我们说话并不干净,因为我们的言语中充斥着美丽的对话现象:
- 犹豫&停顿——“我去了那家很棒的咖啡店 … Peppers!”
- 充满停顿——“我去了那家很棒的咖啡店……嗯……辣椒!”
- 修——”然后向左走……不不,向右!
- 重复-“这是如此如此好!”
- 背道而驰——(电话中有人)是的……嗯……嗯……
然而,当我们对语音助手说话时,我们从我们的语音中消除了所有这些现象,称为 计算机对话 。为了说明这一点,你会对一个语音助手(叫做 Jacob)说什么:
- “雅各布,我的手是湿的,所以你能设置一个计时器吗……嗯……我不知道……请给我几分钟。”
- “雅各布,设置两分钟的计时器”
我们都知道是哪一个,因为…
我们适应系统的能力!我们了解哪些功能是可用的,以及如何最好地使用这些功能。对于老年人(缺乏使用语音助手的经验)和有认知障碍的人来说,这些“智能设备”可能会非常令人沮丧。这是因为语音助手不懂自然交流,有以上所有现象(还有更多),这正是人们一直以来的交流方式。
自然视觉传达
我们也不仅仅用语言交流,我们在每一次面对面的谈话中都使用视觉线索。例如:
- “那是什么?”-没有观点或眼神,不可能回答。
- “哈”——他们可能看起来困惑或惊讶(“哈,有意思!”)
- 沉默——点头表示同意或摇头表示不同意。
你很有希望想到更多的例子,并意识到我们在视觉上呈现了多少精彩纷呈的有价值的信息。大多数语音助手完全忽略了这种材料(公平地说,他们没有摄像头),但它可能对解释某些用户群极其有益。
例如,痴呆症患者在想一个单词时停顿的时间可能比预期的要长。如果语音助手可以看到这个用户显然在想一个词,它可以耐心等待。或者,就像我和一群理科硕士学生一起工作一样,它可以给出最有可能的答案。

胡椒- 来源
利用视觉反馈的语音助手变得越来越常见,因为它们适用于盲人用户(就像我对另一组理学硕士学生所做的那样)和嵌入辅助机器人的语音助手。如果这些视觉提示被证明对老年人和有认知障碍的人有益,那么我们必须探索如何做到这一点。
进入细节
为了研究有认知障碍的人如何自然互动,我们需要分析与有相关认知障碍的人的自然对话。
以痴呆症为例,有两个常用的数据集:
- 皮特文集 :-参与者描述一幅图片,因此没有对话,这只是一段独白。也没有视频。
- 卡罗莱纳对话集——该集合非常大,但在搜索痴呆症患者时却很有限(鲁兹等人报告 21)。对话是基于记忆的问题的采访,所以不完全是自然的对话。最后,音频质量不是很高,痴呆症的例子没有视频。
因此,我们希望捕捉一个参与者患有痴呆症的自然、无计划对话的高质量音频和视频记录。这些对话不是采访,也不会询问任何个人信息。只是一个有趣的聊天!
为了做到这一点,我们正在与一个任务的创建者一起工作。 Sofia de la Fuente Garcia 创造了一种地图任务的变体来引发与痴呆症患者的自发对话。
使用这项任务,一个健康的参与者将坐在一个痴呆症患者的对面进行随意的交谈。两个参与者都有一张位置相同的地图,但是只有患有痴呆症的人才能看到穿过虚拟土地的可能路线:

显示路线的地图- de la Fuente Garcia 等人,2019
健康的参与者是唯一知道两人需要去哪些地方的人。因此,他们需要通过对话合作,一起踏上旅程
这种对话是我们想要捕捉的,但是我们如何道德安全地做到这一点呢?
道德考量
现在我们进入了这篇文章的核心部分——如何从伦理的角度实际收集有认知障碍的人的这些有价值的数据。
在这一节中,我将介绍:同意、参与者舒适(确保参与者不会感到不安)、参与者招募和可选的认知评估。然后,我将在最后一节讨论数据安全性(包括新设备)。
同意
有认知障碍的人被视为弱势参与者,因此需要一名证人监督同意过程。见证人应该是家庭成员或看护人,并且必须在弱势参与者同意参与研究后签署“见证人同意书”。
在数据收集前至少一周,每位参与者都会收到一份“参与者信息表(PIS)”,其中包含有关研究的所有信息(将涉及的内容、参与的益处、将存储的数据等)。提前提供 PIS 给每个参与者阅读、消化、提问、、和理解信息的机会。你应该强调欢迎所有问题,参与完全是自愿的。这里需要注意的是,除了研究团队成员之外,还可以向家庭成员、护理人员或全科医生提问。
在我看来,尽早提供 PIS 是这一过程中最关键的步骤之一。如果你不愿意提前提供 PIS,为什么?你的程序中有什么让你不舒服,为什么你不希望人们注意到它?这一步本质上是最后的检查,你会知道什么时候你乐意回答问题并认为你的研究是“道德的”。

所需文件的分发
在收集当天,参与者和同意见证人都会收到各自的同意书(如上图所示)。参与者同意书总结了 PIS 的要点,并确认参与者已经阅读并理解。然后,证人签署他们的“同意书证人”,确认认知障碍参与者理解 PIS,回答了他们的所有问题,并自愿同意参加研究。
不道德的研究人员可能试图欺骗一个有认知障碍的人(例如,在他们“签署一份快速表格”后主动给他们一杯茶)或获取个人信息(例如,询问他们以前的病史)。为了确保这种情况不会发生,证人还签字确认研究人员没有试图获取个人信息、误导或欺骗参与者。
参与者舒适度
参与者将宝贵的时间花在帮助研究上,但可能会对参与感到压力,尤其是那些有认知障碍的人。因此,确保人们拥有舒适的体验至关重要。
甚至在参与之前,PIS 应该包含尽可能多的信息,以防止不必要的压力。例如,它可以突出显示任务的以下内容:
- 它不需要准备。
- 这不是医学检查。
- 我们想录制一段自然的对话,所以它是为了好玩。
- 可以随时停止(或暂停)录制,而无需给出原因。
- 答案没有对错之分。
- 没有时间限制。
有些人可能会对停止研究感到不舒服,即使他们感到苦恼。因此,家庭成员或护理人员应见证该任务(通常是见证同意阶段的同一名证人)。证人也可以在任何时候停止或暂停录音,而无需给出理由。作为一个研究者,理解这个证人的重要性是至关重要的。不同的认知障碍,甚至同一认知障碍的不同人,都有截然不同的信号来表示苦恼。家庭成员和护理人员在确定某个人是否不舒服方面比任何研究人员都更有经验,因为他们了解那个人。
在参与者舒适度方面,位置是另一个需要考虑的非常重要的因素。

资源中心的一家老年痴呆症苏格兰咖啡馆,旨在成为一个无障碍的社区中心。这是我住过的最迷人的房间之一。它看起来和感觉上都像一个时尚的现代咖啡馆,但是每一个单品都是经过深思熟虑的,并且被设计成容易接近的!包容性设计的完美范例。
一个合适的地点相对容易找到,因为自发的对话几乎可以在任何地方进行。然而,为了参与者的舒适和证人的可用性,最好与关注认知障碍的企业或慈善机构合作。为了参与他们的社区,这些组织通常都有活动中心,人们可以去那里参加社交活动、获得支持和上课(例如,上图)。
这些中心是运行任务的完美地点,因为人们在里面非常舒适。工作人员也认识潜在的参与者,因此可以成为证人并帮助招聘工作(下文讨论)。
大多数可到达的地点都是合适的,但如果可能的话,与慈善机构合作,在他们的中心之一进行研究,是参与者舒适的最佳选择。
参与者招募
在招募弱势参与者时,与相关组织合作至关重要,这是对参与者舒适度的补充。这些组织可以接触他们的社区,并以安全友好的方式协助招募合适的参与者。然而,协作耗费了组织宝贵的时间,因此解释数据收集背后的动机以及它如何使人们受益是很重要的。
健康的参与者也需要以正确的方式招募。向研究参与者提供小额奖励(如礼品卡)很常见,但在这种情况下不建议这样做。有认知障碍的人将利用他们的时间通过参与这项任务来为研究做出贡献。健康的参与者的理想动机是对社会的贡献,而不是某种最终的回报。
一些不关心研究背后动机的人可能会为了一张礼品卡而匆忙完成任务,使脆弱的参与者的时间贬值。如果没有金钱奖励,这个例子就不会发生。
可选认知评估
收集这些对话的多模态录音极其耗时。因此,分享这些数据是值得的(我们将在数据安全一节中详细介绍)。
对于某些领域的其他研究人员来说,如心理学,认知评估结果有巨大的好处。执行相同认知评估的另一个语料库(例如,基于空间导航或记忆的研究)可以被合并以揭示未知的联系。
然而,在包含这样的任务之前,也有一些担心需要考虑。例如,一个适合我们收集数据的任务是 Addenbrooke 的认知检查 (ACE-III),因为它是常用的、低技术含量的、快速执行的。下面是一个问题示例:

ACE-III 中的一个示例问题
在英国,需要通过 NHS 培训才能进行这项测试,与其他测试类似,所有培训必须在收集前完成。这一部分不能以视听方式记录,只应记录对话任务。
需要强调的一个缺点是,ACE-III 被全科医生用于在诊断痴呆症时筛查人群。因此,参与者可能会回忆起做过这项任务,并被提醒他们诊断时的紧张时期。这可能会让参与者感到不安,此外,重新进行测试可能会突显出他们自首次完成测试以来认知能力的下降。
每种认知障碍都有一系列的测试来检查,包括认知评估是非常有价值的。然而,一个人的健康应该是优先考虑的,所以只有在仔细考虑和相关培训后才进行测试。
数据安全
选择任务,招募参与者并了解研究,设置舒适的位置,准备好证人,完成同意程序,可选的认知评估结束,现在终于是按下记录的时候了。
安全地记录对话
一般来说,涉及弱势人群或医务人员的谈话充满了敏感数据。人们经常在交谈中透露个人身份信息(例如,提及他们孩子的名字或病史)。对于有认知障碍的人来说,这种担忧更加强烈,他们更不容易控制自己透露的信息。
标准记录系统(如录音机和摄像机)不是安全设备,它们不能用于捕捉敏感数据。此外,记录的数据可以在标准系统上轻松访问,因此它们不能用于存储敏感数据。如果标准设备丢失或被盗,必须考虑数据泄露的道德和法律后果,这凸显了对安全方法的需求。
Pierre Albert 开发了一个新系统——“CUSCO”,以满足有关敏感材料数据收集的道德评估要求。
该设备通过实时加密记录的数据流来确保记录数据的安全性,并允许收集一系列模态,包括音频和视频。数据使用 Veracrypt 加密,Veracrypt 是一种经过安全审计的专用开源软件,保证加密算法的正确实施。收集的数据只能使用为每个项目生成的密钥进行访问,确保语料库在其生命周期的所有阶段的安全性:收集、运输、交换和存储。
CUSCO 设备的开发具有更广泛的用途,捕捉任何敏感的原位对话(例如全科医生会诊)。
因此,风险预防和缓解至关重要,因此,即使设备在记录过程中遭到破坏或被盗,之前记录的对话和任何正在进行的记录的整个数据集也是安全的。
设备本身的软件是围绕模块化设计组织的:

CUSCO 设备的主要组件。
对应于一种模态(视频、音频、3D)或一种功能(语音活动检测)的每个流都由一个专用模块控制,该模块负责设置配置、检查所需元素的状态(适当设备的存在)以及管理记录。
对于我们的用例,分析多模态对话,我们使用两个深度摄像头、一个高质量的桌面麦克风和一个麦克风阵列来促进后处理中的说话者日记化(音频分段和每个说话者的归属)。
这是我们设置的早期试运行:

我和 Arash Eshghi 用 CUSCO 设备测试这个任务(由 Pierre Albert 友好地强调)。
我们使用桌面麦克风,因为需要将翻领麦克风连接到参与者身上,这可能会造成伤害,并有可能导致痛苦。
该设备的硬件使用常见的现成元件,而软件是开源的(这里是设计方案和软件)。对这种设备的需求超出了我们在本文中详述的对话,延伸到了任何应该实时加密的敏感记录。这样的用例包括记录:全科医生咨询,与儿童的互动,以及与私营公司的讨论。在更严格的数据收集中,即使是研究人员也不允许访问原始数据,该设备提供了收集匿名音频和视觉特征的功能。因此,研究人员只能获得不能用于重建原始信号的交互作用的抽象间接描述。
安全处理和共享数据
一旦对话被安全地记录下来,它们在 CUSCO 上保持加密状态(如上所述),因此可以被传输。
然后,研究团队需要删除谈话过程中可能泄露的任何个人信息。为了做到这一点,每当说出敏感信息时,音频被静音,视频被模糊(嘴周围)。模糊视频降低了视觉行为注释的准确性,但是隐私优先以避免可能的参与者识别。因此,转录不能包含任何敏感信息(并且不应从原始记录转录以确保这一点)。不会共享个人信息,请务必在参与者信息表中强调这一点(PIS)。这些经过处理的记录现在被认为是匿名的,因为参与者只能通过个人联系来识别(因此,未知的研究人员无法识别参与者)。
研究团队成员的详细联系信息应包含在 PIS 中,以便请求删除和随后移除参与者的数据。匿名记录和相关转录可以通过集中的档案与其他相关研究人员共享,以控制其使用,如果在 PIS 中声明,结果将发表在研究论文中。
例如,我们已经决定将我们的语料库存储在痴呆症数据库中,因为它是一个多媒体交互的共享数据库,用于研究痴呆症中的交流。对 DementiaBank 中数据的访问受密码保护,仅限于 DementiaBank 财团成员。将从访问这些数据中受益的研究人员可以请求加入这个组(在审查过程之后),从而从语料库中受益。
结论
从有认知障碍的人那里收集这些对话是创造更易接近和自然的语音助手的重要一步。为了确保这是合乎伦理的,有许多因素需要考虑,我希望这份实用的伦理指南可以帮助那些想要应对许多伦理挑战的研究人员,以便收集和发布类似的数据集。CUSCO 还可用于在需要时安全地捕获、传输和交换这些数据。
我花了一年多的时间才到达收集点(然后被冠状病毒延迟),但我希望这个指南能帮助下一个研究人员更快地捕捉到类似的对话,而不会牺牲道德考虑或数据安全。对话式人工智能中的可访问性将有望流行起来,我真的希望这有所帮助!
承认
感谢苏格兰阿尔茨海默氏症花时间陪我,支持这个项目,总的来说棒极了!尽管因 Covid 而延期,但我会在安全的时候来完成这项研究,不会浪费您的时间。
再次衷心感谢过去一年里我就这个项目与所有人交谈过的人。有无数(象征性的)你!我记下了你对本指南的每一条建议,我相信如果这能帮助到另外一个人,我们都会很高兴:)
道德和大数据
确定大数据的使用是否符合道德

在结论“目的限制和大数据的原则”中,作者写道:
应该指出的是,包括目的限制原则在内的数据保护法规寻求实现的隐私可能不仅被视为经济和科学的阻碍因素……相关利益攸关方应共同努力应对挑战,并强调隐私是大数据的核心价值和必要性(Forgó 40)
换句话说,我们不应该将隐私问题视为阻碍我们如何使用数据的创新的东西,但隐私和人们对它的权利应该是我们如何使用大数据的核心问题。事实上,Paganoni 在《构建大数据》中写道:
企业责任应被指定为企业运营中的一种内在道德立场,例如,通过启用从一开始就保护隐私的技术(数据保护“设计”)来实施,而不是追溯性的(Paganoni 95)
这两句话传达的重要信息是,隐私不应该是事后才想到的,而是我们如何开发获取和使用数据的技术的核心价值。然而,如果你读了我最近的帖子关于我们对死亡的恐惧如何被操纵成让组织侵犯我们的隐私,或者观察了几年前发生的剑桥分析公司丑闻,你会看到这是一个如何有待完全实现的价值观。
构建大数据的最后一章是“大数据辩论中的道德问题和法律框架”,并讨论了欧盟通用数据保护法规(GDPR)中使用的语言。如果你看到任何关于个人数据在互联网上被使用的报道,你可能会看到这个首字母缩略词到处流传。Paganoni 用了整整一章来研究这组法律中的语言,而你几乎肯定会看到 GDPR 的某种提及的原因是因为它标志着解决大数据使用问题的新时代,并决定什么是大数据的道德使用,什么不是。
GDPR 是对 1995 年制定的数据保护指令的替代,当时互联网是一个非常不同的地方。正如 z solt zdi 所说,“大数据根本不是一个问题,或者至少在最近的叙述框架中不是”(第。76).相比之下,GDPR 非常重视大数据的收集和使用带来的问题,因为它“沉浸在大数据生态系统中”(Paganoni 84)。
围绕 GDPR 的一个主要担忧是,它正在导致互联网的“巴尔干化”。正如奥斯曼帝国分裂成许多不同的国家一样,人们担心互联网也会分裂成自己的国家。从本质上讲,一个人对互联网的体验会随着地理位置的不同而改变。这种变化,尤其是欧洲 GDPR 带来的变化,在诸如这种的文章中被框定为负面。然而,我相信这是一句相对能说明问题的话:
然而,欧洲正在建立自己的壁垒,新的数据保护和隐私规则可能会阻碍机器学习的应用。
在这篇文章的开始,我引用了两句关于隐私和大数据的话。这些引用的核心是,保护用户隐私不应该被视为一种障碍或事后想法,但它应该是任何类型的机器学习技术开发的核心。GDPR 是一套相对复杂的法规,但它们实际上可以归结为两个概念:隐私和透明。支持这两项权利的法规被视为进步的障碍,这一事实表明作者关心什么样的进步,不关心什么样的进步。
此外,许多将网络巴尔干化视为负面因素的人特别指出,人们对互联网的体验会因所处位置的不同而不同。他们担心这会导致一些国家变得像中国一样,很多网站都被屏蔽了。然而,这篇文章指出,那种情况已经发生了:
换句话说,网络的一点点割据可能是民主权力和多元化的健康行使。问题是决定在哪里停下来。在不久的将来,居住在蓝色州的美国人会有一个互联网,而居住在红色州的美国人会有另一个互联网吗?(唉,鉴于脸书和 Twitter 等网站如何创造所谓的“过滤泡沫”,提供我们已经同意的新闻和观点,这在许多方面已经是这样的情况了)。
你甚至可以在网飞看到这一点,不同的国家有不同的电影选择。事实上,你可以上这个网站看看哪些电影在哪些国家上映。因此,这种不同互联网体验的特殊问题是我们在其他地区已经经历过的,这些地区收到的投诉比 GDPR 少得多。
没有 GDPR 和类似的法规,真的没有什么可以阻止大公司不道德的数据使用。如前所述,隐私并没有被视为机器学习中数据收集和使用的核心支柱,公司关心的是底线,而不是道德。尽管 Paganoni 在她关于 GDPR 的那一章的结尾说它远非完美,但它无疑是向在一个相对新的、快速发展的领域引入具体的伦理规则迈出的一步。
[1]福尔戈、尼古拉、斯蒂芬妮·诺尔德和本杰明·舒茨。目的限制和大数据原则。”载于新技术、大数据与法律,第 17–42 页。2017 年,新加坡施普林格。
[2]玛丽亚·克里斯蒂娜·帕戈诺尼。构建大数据:语言和话语方法。斯普林格,2019。
[3]佐迪,佐尔特。“大数据时代的法律和法律科学。”路口。东欧社会与政治杂志 3,第 2 期(2017):69–87。
[4]斯宾塞,迈克尔。“防止互联网的巴尔干化。”外交关系委员会。外交关系委员会,2018 年 3 月 28 日。https://www.cfr.org/blog/preventing-balkanization-internet.
[5]罗伯特,杰夫·约翰。" GDPR 和我们分裂的互联网:我们失去了什么."财富。财富 2018 年 5 月 29 日。https://fortune.com/2018/05/26/gdpr-internet/.
伦理和(可解释的)人工智能
基于 AI 的系统必须负责任。直到现在,它们中的许多都是黑匣子。道德和无偏见的训练数据比以往任何时候都更重要。

马库斯·温克勒在 Unsplash 上的照片
大多数人更信任计算机算法,而不是其他人。不幸的是,与算法相比,当专家做出有充分根据的陈述时,情况也是如此。大多数人不知道计算机做出决定的依据是什么。许多人认为他们是无条件的。但这只是部分真实。算法是人类开发的。有些人可能会说,有了机器学习,人类开发人员的偏见被消除了。让我们简单看一下机器学习和深度神经网络。
好的机器学习模型需要好的数据。在监督学习中,你需要一组好的分类训练数据。如果你的训练集有偏差,模型也会有偏差。那是什么意思?让我们来看看一些有偏差的训练数据的案例以及使用它们的后果。
你会得到这份工作吗?
如果在招聘过程中消除人类的偏见,那不是很好吗?如果某人来自外国,种族背景和性别并不重要。只有技能很重要。算法的完美工作,不是吗?这是亚马逊在 2014 年的想法。使用了一种算法来预筛选空缺职位的候选人。2015 年,他们意识到他们的算法偏好男性。即使女性候选人有更好的资格,系统也不会推荐她们。原因:训练集有偏差!在一个男性主导的领域,该模型得出的结论是,女性相当不适合。2015 年,亚马逊停止使用其算法。
我知道你会做什么,你会再做一次!
一个名为 COMPAS 的 AI 承诺预测犯罪的累犯率。美国的许多州都在使用 COMPAS。通过一组约 137 个问题,这些算法计算出某人是否会再次犯罪。基于此,人们将面临更高的刑期。后果是,法官不看犯罪记录。他们正在使用 COMPAS 返回的分数。这导致了一个危险的反馈循环,因为 COMPAS 没有得到关于错误指控的反馈。训练集可能会有偏差,因为它是基于过去的案例。准确性值得怀疑。你可以从 Pro Publica 获得更深刻的见解,包括一个 GitHub 知识库和一个漂亮的 Jupyter 笔记本。
拉屎进去,拉屎出来。

由来源(WP:NFCC#4),合理使用,https://en.wikipedia.org/w/index.php?curid=49953711
这是泰。微软在 2016 年创建的聊天机器人。这个想法是创造一个机器人,从 Twitter 上与其他用户的互动中学习。Tay 学得很快。不到 24 小时(确切地说是 16 小时), Tay 变成了一个种族主义者、法西斯主义者和歧视者。微软试图修复他们的机器人,但没有成功:Tay 离线了。问题是:用户已经明确地将与 Tay 的对话引向这个方向。拉屎进去——拉屎出来。
上面的每个故事都有一个共同点:有偏见的数据被用来训练模型。在模型中,一个黑盒决定如何对一些输入做出反应。想想亚马逊的雇佣人工智能。没有一个申请者知道什么参数是重要的。我怀疑人力资源部的员工不知道他们是如何被评估的。这同样适用于 COMPAS 和 Tay。为了理解黑盒,我们对深度神经网络进行一点小小的探索。
简而言之,深度神经网络
免责声明:这是一个高层的解释。整个话题比较复杂,但是你会明白的。
让我们从一个简单的感知器开始:

简单的感知器。(图片由卡斯滕·桑德特纳提供)
一些输入被加权,放入一个函数,一个激活函数决定感知器是否激活。你的任务是调整权重并定义一个偏差(当输入为 0 时会发生什么?)对训练集中的每个输入数据进行处理,直到它最适合为止。
机器学习的意思是:使用训练数据来确定最适合所有数据的权重。对于简单的感知器,它可以是一个如下的等式
y = mx + b
在大多数情况下,输入更复杂,我们得到某种线性回归。

一个简单的神经元—(图片由卡斯滕·桑德纳提供)
同样,我们必须找出我们的线性回归最适合所有训练数据的最佳参数。
今天,我们已经有足够的计算能力来毫不费力地训练一个拥有数百万个数据点的模型。而且这么简单的模型,人类还是可以理解的。
现在让我们来看看一个神经网络。

一个简单神经网络的结构(图片由 Carsten Sandtner 提供)
神经网络有一个输入层、几个隐藏层和一个输出层。如你所见,神经元的每一个输出都可以成为下一层中每一个神经元的输入。为每个神经元确定权重和偏差。它变得越来越复杂,人类将有更多的问题来解释这个网络中发生的事情。深度神经网络可以有两个以上的隐藏层。想象一个有 50-100 个输入和 5 个隐藏层的神经网络。经过训练的模型正在成为人类的黑匣子。
想想 COMPAS 案例:没有人知道使用了什么参数,模型是如何被训练的?训练集来自哪里?这同样适用于亚马逊案例。神经网络变得越来越复杂。
可解释的 AI 解决这些问题?
这就是为什么可解释 AI 被要求和鼓励的原因。想法:它描述了神经网络做什么,它如何被训练等。2017 年 DARPA 资助了几项可解释人工智能的努力。埃森哲正在宣传负责任的人工智能,可解释的人工智能是其中的一个主要部分。
但是这不仅仅是神经网络可以解释的。基于人工智能的系统不能产生负反馈循环。一个基于数据的算法需要更多的数据才能更好。如果像 COMPAS 这样的系统预测累犯率很高,有人因此被判处更长的刑期,重新融入社会就变得更加困难。这里开始了负反馈循环。找工作的机会更差,绝望并可能为了生存而再次犯罪。人工智能系统知道!还是体制造成的?很难回答。
即使不是罪犯,人工智能也能让你深陷困境。例如,斯蒂夫·泰利被错误地指控为罪犯,并被残酷逮捕。他的错?图像识别错误地将他与犯罪联系在一起。
使用的训练数据集必须对所有人开放。如果一个训练集有偏差,人们应该知道。大多数系统,无论是招聘人员还是维持治安,都是作为黑箱工作的。他们也没有一个好的反馈回路。人们仍然更相信计算机算法而不是专家。我们都必须对基于人工智能的系统负责。数据科学家负责负责。由于种族和性别偏见的批评,IBM 最近退出了面部识别业务。这是朝着负责任行动的正确方向迈出的一步。亚马逊和微软也采取了类似的举措。
AI 很棒。我喜欢这项技术的可能性。有很多很好的例子。但是我们需要负责任地使用它。并不是每个问题都可以用人工智能来解决。我们需要时刻牢记这一点。
cs 和机器人专家的伦理
抽象&尺度&伦理系统。
成为机器人专家意味着什么?这个标题有点老生常谈的性质,体现在许多初创公司高管的副标题为“机器人博士”的员工身上,这导致了一个更具挑战性的问题,即如何定义道德指南。我有责任为人们应该从广义上考虑的事情制定有序的指导方针,并在其中接受教育。应用这些原则的实际问题本质上是灵活的,因此这些原则应该重新排序。在这篇文章中,我希望定义一个向量,它可以成为未来发展的指导原则,随着时间的推移,随着问题空间的变得更加清晰,它将被修改。
最终,自主代理影响每个人的生活,并且在未来几十年中,这种影响的幅度将继续增加。我的主要目标是找出如何最好地设计系统,a)不伤害个人,b)不引起下游多系统相互作用的任何社会重组。
数据导致的个人错误
由人工智能系统造成的个人困难的想法主要属于“公平机器学习”的范畴,这个领域在新闻中获得了很多关注,如自动警察对人进行分析,搜索结果伤害少数群体,或雇佣算法出于不公平的原因过滤人们(这里是跟踪此类失败的流行列表,或参见 FAccT 会议并从那里开始)。构建自主系统将包括这种类型的风险,但它也将扩展得更广。就我个人而言,我希望在机器人真正完成每一项人际任务之前,这些问题将远离我们(如果 ML 在十年内不公平,我们有更大的鱼要炸)。
简而言之:机器人伦理需要利用人工智能伦理作为基础,并在其上建立更具体的东西。在完成了与人工智能伦理相关的不同研究领域的比较研究的初稿后,这里是我们提出的框架。最终,这三个子领域是试图触及社会技术系统(STS)主题的研究孤岛:
- AI 安全:值对齐和证明灭绝概率去 0。
- 公平 ML:最小化伤害个人用户或个人群体的决策算法的误用。
- 人在回路中的自主性(人-机器人交互 HRI /信息物理系统 CPS):避免事故,并找出如何在物理自主系统中最好地模拟人的意图(从这些领域可以得出一个有趣的论点,一个主要来自 CS 端— HRI,一个来自 EE 端— CPS,其中目标采取弹性的形式,如何在意外事件后恢复正常操作,以及鲁棒性,处理意外事件的能力)。
我们论文的关键是找出如何避免阻碍 CS 研究与 STS 主题有益结合的陷阱,以及研究生如何成为潜在的干预点。这个争论的其余部分留待以后,我可能会在以后的文章中包括人工智能伦理学这些子领域的历史片段,它们相当有启发性。我把我们写的关于人在回路中的自主性的几个段落包括进来,因为它在这里看起来非常相关,并且很好地过渡到下一节的思想:
由于许多最早的机器人系统是由技术人员远程操作的,机器人领域的核心一直是人机交互(HRI)问题。早期的工作与人的因素的研究密切相关,这是一种跨学科的努力,借鉴了工程心理学、人类工程学和事故分析。随着机器人能力的提高和自主性的增加,交互范例从仅仅远程操作发展到监督控制。随着 IEEE 机器人与人类互动交流国际研讨会的成立,HRI 在 20 世纪 90 年代成为一个独特的多学科领域。这一领域的现代工作包括从自主代理(即机器人)的角度建模交互,而不仅仅是人类监督者的角度。通过结合社会科学和认知心理学的原理,HRI 使用人类行为的预测和模型来优化和规划。这项工作通过使模型对其条件具有鲁棒性,减轻了事故的社会技术风险,事故具体定义为物理困难或灾难发生的状态。
数字技术已经发展到许多系统被赋予了超越机器人代理传统概念的自主性,包括电网的交通信号网络。因此,我们认为 HIL 自主的子领域是将人类行为纳入机器人和信息物理系统的前沿研究。这个子领域有两个方向:1)通过感知和行为预测的物理交互的创新;2)为复杂或不稳定环境中的系统弹性进行设计。面对越来越多的计算方法和新技术的潜在市场渗透,这些界限正在变得模糊。例如,自动车辆(AVs)的设计在许多方面都提出了挑战。对于更流畅和适应性更强的行为,如合并,算法 HRI 试图形式化一对一交互的模型。与此同时,反车辆地雷造成了身体伤害的风险,因此进一步的工作将整合这些人体模型,以确保安全,尽管可能会出现难以预测的行动。最后,人口层面的影响(如 AV 路由对交通吞吐量和诱导需求的影响)需要更深入地调查与社会层面的互动。
回到机器人。如果某个东西在物理上被搞乱了,它可能会更容易被注意到,但也可能会出现代理交互数量呈指数增长的现象(如果每个代理都与其他代理交互,5 个代理有 20 个成对的交互,100 个代理有近 10,000 个交互)。自治系统之间的这些交互可能会更难建模、预测和预防(就像我在谈论推荐系统时所得到的)。
社会重组
随着自主性的采用加速,机器人平台的影响从个人影响扩大到社会影响。例如,如今,对于大多数行人来说,一辆自动驾驶汽车代表着一件危险的现代艺术品,但当这一比例达到更可观的水平时,比如说 10%,自动驾驶汽车的车队及其相互作用可能会定义作为行人意味着什么——人类不再是什么时候穿过道路的驾驶座。我所遇到的最常见的车队互动模式是更有效的交通流量,但真的没有什么可以防止有害的突发现象。
自动驾驶汽车是的第一个孩子从现代自动驾驶的角度来看,它们是每个人都在关注的应用程序,并且有巨大的支持来实现它,但这并不意味着它会产生巨大的影响。
规模伦理
在现代数字(即将具体化)系统中,有许多伦理因素在起作用:有相互竞争的政治和经济利益,自动化取代工作的问题,人与人之间伦理的抽象效应,等等。我认为制定伦理指南的关键是关于尺度的推理。计算机科学家以他们在抽象中工作的能力而闻名,但我担心很多人抽象出道德决策——一旦它超出了你的边界框,那就是别人的问题了。老实说,道德应该从第一个用户开始就发挥作用,但大多数初创企业可能不会考虑它,直到他们需要这样做(谁能责怪他们)。
机器人的物理性质和自主性可能会引发对技术中不良道德判断的更直接、更进化的反应。我认为这是我的安慰,也是为什么它值得追求——总的来说,我对我的人类同胞更有信心,能很好地应对屏幕外的挑战事件。
工程涉及低层次的设计决策,机器学习也是如此:在不确定的假设下做出具体的决策。由于设计原则没有考虑复杂的系统交互,我不认为自治工程师应该遵循陈词滥调的管理原则。我认为这是关于在创造产品时,能够转换抽象框架,博览群书,并在植入堆栈中垂直地进行讨论。
特定的、建立的指导方针是自治伦理的实施方式。从业者有责任更早地做出更好的决定,这样他们就可以对系统如何运行有发言权,而不是全国范围内相对无知的决策者。

照片由塞尔吉奥索萨从 Pexels
特别指导方针制定
我被迫在我的博士项目之外辅修了一门课,在这个过程中,我学到了很多关于治疗学发展过程和 FDA 的知识(课程是这个的早期版本)。最终,美国食品药品监督管理局(FDA)的简史是:人们搞砸了,我们用创可贴来防止未来发生这种情况。为了避免深刻的经济和哲学争论,我认为这种方法是自由市场的先决条件——修补所有令人担忧的领域可能会扼杀创新。这就是技术政策是如何产生的,并且很可能会继续下去。
计算机科学正处于一个转折点,监管机构并不完全存在他们的问题空间,但人们开始提出问题。延迟的全面监管的替代方案:造就更好的演员。这就是我试图为自己和那些与我一起解决机器人问题的人所做的——让世界变得更好。我们将看到每个人的决定在 10 年或 20 年的时间滞后后会如何。
当前课程
为了比较起见,我想说明大多数专业领域是如何在培训和实践中包含一些道德成分的。
- 医学:医学院的课程中有伦理内容,资格考试中有问题,还有对每个医院的监督。
- 法律:律师通过了律师考试中粗略的道德部分。
- 金融:在众多内幕交易和其他避光法律中,约 10%的特许金融分析师课程是道德培训(金融管理机构非常常见的认证项目)。
- 心理学:他们有自己定义的道德准则基于四个原则:有益与无害、忠诚与责任、正直与公正。
显然,计算领域落后了。当你做研究时,每个其他领域都有道德准则,计算正在成为每个领域的幕后玩家(可悲的是,当你把你的才华带到不同的应用空间时,没有道德准则的继承)。加州大学伯克利分校的数据科学项目开设了首批必修的道德课程之一https://data.berkeley.edu/hce(加油熊)。

照片由 Pexels 的 Sebastian Voortman 拍摄
因此,通读这些,你可能会想“怎么能指望任何人跟上所有这些,并且仍然创造突破性的创新?”我同意,这是很多。我希望继续找出需要解决的核心挑战和问题。这是一个更大的项目的一部分,我想把这个草图设计成一个课程,继续关注这个方向的更多工作,如果你想参与进来,就联系我们。面对日益增多的计算方法和新技术的潜在市场渗透,这些界限正在变得模糊。
你认为从事自动化工作的人的道德指南应该增加哪些内容?
这是我一期关于机器人学的免费时事通讯的巅峰之作&自动化, 民主化自动化。
一个关于机器人和人工智能的博客,让它们对每个人都有益,以及即将到来的自动化浪潮…
robotic.substack.com](https://robotic.substack.com/)
欧洲金融监管数据
关于如何访问与欧盟金融市场相关的公共数据源的指南

芬恩·普罗茨曼在 Unsplash 上的照片
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
简介
在欧盟,金融市场的参与者——包括银行、保险公司、投资基金、贸易公司和证券化特殊目的载体(SPV)——都受到广泛的规则和监管。许多法规要求市场参与者向监管者提供关于他们自己及其活动的数据,如欧洲中央银行或欧洲证券和市场管理局(ESMA)。监管机构主要使用这些数据来监控金融系统,并(有希望)检测和应对可能导致问题的事态发展。然而,这些数据的一个子集也向公众开放,可能会引起希望更清晰地描绘欧洲金融市场图景的数据侦探的兴趣。
在本文中,我将概述一些公共数据源,解释它们是什么以及如何访问和使用它们。我将使用 Python 编程语言提供几个说明性的代码示例来获取和解析数据,但除此之外,不需要了解任何编程语言。对 API 和 XML,当然还有金融市场本身有一个基本的了解会很有帮助。所有示例代码都可以在下面的 GitHub 资源库中找到:
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/bunburya/eu_finreg_data)
我将在本文中引用(并链接)各种法规,但值得注意的是,这些法规中的许多(如果不是全部的话)自最初发布以来已经过修改。我在这里提到的大多数法规都由欧盟和国家监管机构的各种监管技术标准、实施标准和指南进行补充,在许多情况下,这些标准和指南将规定主要法规所规定义务的实施细节。最后,当然,你在这里读到的任何东西都不应该被认为是法律建议!
金融工具参考数据
根据金融工具市场条例 (MiFIR)和市场滥用条例 (MAR),交易场所(如证券交易所)和系统内部机构(如在内部结算客户提交的交易,而不是在交易所结算这些交易的投资公司)必须向 ESMA 提交有关相关金融工具(股票、债券等)的参考数据。然后,ESMA 在其网站上公布这些数据。该数据库被称为金融工具参考数据系统(FIRDS),可通过 ESMA 注册网站访问。
FIRDS 数据集的大小和它包含的信息使它可能非常有趣,因此值得花一些时间讨论如何使用它。数据可以通过用户界面访问,但对我们的目的来说更重要的是,它也可以通过 API 批量下载。
ESMA 发布的下载说明中规定了下载 FIRDS 文件的流程。首先,您需要查询给定的 URL,指定您想要的数据的日期(以 ISO 8601 格式)。然后,您将获得一个 XML 对象(或者一个 JSON 对象,如果您在请求中指定了该格式的话),其中包含相关文件的下载链接。例如,以下 URL 查询将返回一个 XML 对象,其中包含 2020 年 9 月 11 日到 2020 年 9 月 18 日之间发布的所有文件的链接:
[https://registers.esma.europa.eu/solr/esma_registers_firds_files/select?q=*&fq=publication_date:%5B2020-09-11T00:00:00Z+TO+2020-09-18T23:59:59Z%5D&wt=xml&indent=true&start=0&rows=100](https://registers.esma.europa.eu/solr/esma_registers_firds_files/select?q=*&fq=publication_date:%5B2017-08-25T00:00:00Z+TO+2017-08-25T23:59:59Z%5D&wt=xml&indent=true&start=0&rows=100)
上面链接的下载说明告诉你如何根据日期和数据类型找出你要找的文件的名称。例如,文件FULINS_D_20200912_02of03.zip包含与 2020 年 9 月 12 日发布的债务证券相关的数据(并且是三个此类文件中的第二个)。每个download_link元素指定了下载相关文件(作为 zip 存档文件)所需查询的 URL。
zip 存档应包含一个 XML 文件,其内容在 ESMA 出版的报告说明中有描述。简而言之,XML 树的根元素是一个BizData元素,它应该有两个直接子元素;报头(Hdr)元素和有效载荷(Pyld)元素。Pyld元素有一个名为Document的子元素,它又有一个名为FinInstrmRptgRefDataRpt的子元素。FinInstrmRptgRefDataRpt的第一个子节点是表头RptHdr;其余的子元素是RefData元素,每个描述一种安全。RefData元素的各个子元素包含您正在寻找的信息。
到底存在什么样的子元素将取决于您正在查看的安全性类型,为了完全理解您正在查看的内容,您应该结合上面链接的报告说明自己探索 XML。举例来说,下面是 RefData 元素的一些子元素,它们包含一些关于债务证券的有用信息:
- Issr :债务证券发行人的 LEI 代码(见下文“法人实体标识符”一节)。
- DebtInstrmAttrbts->TtlIssdNmnlAmt:债务证券的总发行票面金额。
- DebtInstrmAttrbts->MtrtyDt:债务证券的到期日(格式为 YYYYMMDD)。
- DebtInstrmAttrbts->-intrstrade:适用于债务证券的利率(如果证券支付浮动利率,此元素将有描述相关基准利率和利差的子元素)。
- FinInstrmGnlAttrbts->-Id:债务证券的 ISIN。
- FinInstrmGnlAttrbts->NtnlCcy:证券名义金额所用的货币。
- TradgVnRltdAttrbts->Id:该证券上市或交易的交易场所的市场识别码。
这只是一个小例子;FIRDS 的数据包含了更多关于债务证券的信息。当然,关于其他类型证券(股票、衍生品等)的第一批数据将包含与这些类型证券相关的不同数据。
使用 FIRDS 数据时,有几件事需要记住:
- 它相当大——例如,
FULINS_D_20200912_02of03.xml未经压缩大约有 417MB,只是那天发布的许多 FIRDS 文件中的一个。根据您的系统,一次将多个这样的文件加载到内存中会很快耗尽您所有的 RAM。如果您使用 Python 来解析 XML,那么您可以考虑使用 iterparse 函数,该函数允许您在遇到元素时进行处理,而不是等待整个树被读入内存。 - FIRDS 数据似乎包含每个报告交易场所的每个证券的一个
RefData元素。也就是说,如果同一种证券在三个不同的场所交易(例如),它将在数据中出现三次。如果想避免重复数据,应该跟踪已经处理过的 isin,并跳过引用相同 isin 的RefData元素。 - 数据并不总是以完全一致的方式记录。例如,如果您试图寻找基于 EURIBOR 支付浮动利率的证券,您会发现基准利率可能被描述为“EURIBOR”、“EURI”、“欧元银行同业拆放利率”或许多其他变体之一。其中一些变体可能是拼写错误——例如,我在数据中看到过“EUROBOR”和“EURIOBOR”。或者,基准利率可以用 ISIN 来描述,而不是用名称来描述。
在这里您将看到一个脚本,其中包含许多函数,用于下载特定日期和证券类型的 FIRDS 数据,并使用该数据创建一个基本的 SQLite 表,将证券 ISINs 映射到发行人 lei。
法人主体标识符
受欧盟(和其他地方)监管的公司和其他法律实体通常需要获得唯一的法律实体标识符 (LEI)并将其提供给相关监管机构。LEI 的授予和管理由全球法律实体标识符基金会 (GLEIF)监督,该基金会还维护着全球 LEI 指数,这是一个关于 LEI 及其持有者的综合数据来源。除了在 GLEIF 网站上手动搜索,还有两种方法可以访问关于 lei 的数据:
- 下载串接文件。GLEIF 每天发布一个包含所有 lei 数据的链接文件。截至 2020 年 10 月 26 日,连接的 LEI 文件中有 170 多万个条目,解压缩后的大小约为 3.6GB(压缩后约为 224MB)。数据是 XML(具体来说, LEI-Common Data File )格式。GLEIF 还发布带有其他辅助信息的连接文件,如“关系记录”,描述了实体与 LEI 的直接和间接所有权,以及关于 ISIN 与 LEI 关系的信息。
- 访问 API,此处记录了该 API。这里还有一个演示应用程序可以让你探索 API。该 API 允许您通过实体名称或 LEI 进行搜索,并以 JSON 对象的形式提供结果。举例来说,这个就是你搜索 LEI 7 zw8 qjwvpr 4 P1 j 1k QY 45(Google LLC)会找到的。
您可以从全球 LEI 索引中获得的信息包括相关法律实体的名称、地址、国家和(在某些情况下)所有者。这非常有帮助,因为您从其他来源获得的数据(例如,FIRDS 或 STS 数据)通常是指公司的 lei,而不是全称。请注意,虽然您可以使用 GLEIF 数据找到证券发行人的详细信息,但根据我的经验,并不是所有的 using 雷关系都出现在 GLEIF 数据中,我在使用上述 FIRDS 数据时运气更好。
举例来说,这里的是一个基本函数,用于查询 API 并返回每个提供的 LEI 的发行者名称和权限。
总交易量和成交笔数
根据 MiFID II,当投资公司在“有组织的、频繁的、系统的和实质性的基础上”通过柜台执行客户指令时,自营交易受某些附加规则的约束。每个投资公司,为了确定其是否满足特定证券的测试,需要将其执行的交易数量和交易量与市场上该证券的交易总数和交易量进行比较。为了帮助企业进行比较,ESMA 每季度计算并公布在欧盟执行的交易总量和数量,并按证券进行细分。当前和历史数据可以在 ESMA 的网站上找到。
当前和历史数据都可用。数据可以 Excel 格式下载。xlsx)文件,股票、债券和其他非股票证券(主要是衍生品)有单独的文件。股票和债券档案是指证券的 ISIN,而非股票档案是由“子类识别”来细分的。每个 Excel 文件都有一个“解释性说明”作为单独的工作表,非股票文件的解释性说明解释了如何解释衍生产品的“子类识别”。
例如,这里的是一些代码,用于解析一个 Excel 文件并生成一个描述欧盟中交易最多的股票的条形图,以便调用具有以下参数的脚本(来自与股票 Excel 文件相同的目录):
$ python si_calcs.py equity_si_calculations_-_publication_file_august_2020.xlsx most_traded_stocks.png
…将生成下图:

本文件是使用从 ESMA 网站下载的材料起草的。ESMA 不认可本出版物,也不对本出版物侵犯版权或其他知识产权或对第三方造成的任何损害承担任何责任。
简单、透明和标准化的证券化
欧洲的证券化受证券化法规监管。《证券化条例》规定,如果某些证券化符合该条例规定的要求和标准,则这些证券化可以被指定为“简单、透明和标准化”(STS)证券化。这一想法是确定和促进(通过优惠监管资本待遇)被认为对投资者风险特别低的证券化。
希望获得 STS 称号的证券的详细信息必须通知 ESMA,ESMA 在其网站上公布了某些详细信息。目前,它们以定期更新的电子表格的形式发布,尽管计划是它们最终将作为一个单独的登记册发布在 ESMA 注册局的网站上。
STS 证券化分为公共证券化(根据招股说明书条例就其起草招股说明书)和私人证券化。只有非常有限的私人证券化细节是公开的,例如被证券化的基础资产的资产类别,以及证券化是否是资产支持商业票据(ABCP)交易。对于公开证券化,可以获得更多详细信息,例如基础资产的发起人和票据的 ISINs 的详细信息(可以对照 FIRDS 数据进行交叉引用,以找到有关票据和发行 SPV 的更多信息)。
关于可以用这些数据做什么的基本示例,请参见本网页,该网页也利用了上面讨论的 FIRDS 和 LEI 数据。
欧元区金融机构
欧洲中央银行(ECB)保存着欧元区各类金融机构的名单。金融机构的类型如下:
- 货币金融机构(MFI),包括中央银行、信贷机构、其他存款公司和货币市场基金(MMF)。
- 投资基金 (IF),不包括养老基金和 MMF。
- 金融工具公司(FVC),广义而言,是参与证券化的特殊目的公司。
- 支付统计相关机构 (PSRIs),即支付服务提供商和支付系统运营商。
- 保险公司。
您可以按如下方式下载列表:
- psri 和 ICs : 点击上面的链接,点击相关类型的金融机构,将出现附加文本(包括多个链接)。下载金融机构名单的链接将采用“关于[psri/ICs]名单的已公布详细信息,包括历史数据”的形式。该链接指向一个 zip 文件,其中包含一个 Excel(.xlsx)表示有数据的每一年。
- IFs 和 FVC:点击上面的链接,点击相关类型的金融机构。下载金融机构列表的链接将采用“[IFs/FVCs]概述[时间段]”的形式(例如,“FVCs 概述 2019–2020”)。该链接指向一个 zip 文件,其中包含相关时间段内每个季度的可用数据的 Excel 文件。
- MFIs :转到该页面将允许您搜索或下载数据集。数据集是 CSV 格式的(注意,值由制表符而不是逗号分隔)。
当您下载某个季度或某年的列表时,请注意该列表将包含该季度末相关类型的所有注册机构,而不仅仅是该季度注册的机构。例如,文件 FVC_2020_Q1.xlsx 是 Q1 2020 年的 FVC 列表,将包含 Q1 2020 年底仍注册为 FVC 的所有实体的完整列表。
一般来说,金融机构的名单将包括(除其他外)每个机构的列伊、法定名称和地址以及注册国。每类金融机构的列表还将包括与该类金融机构相关的一些附加数据。例如,FVC 数据将包括负责每个的管理公司的详细信息(包括 LEI、名称和国家),以及每个发行的债务证券的 ISINs。
与金融机构相关的其他数据,如资产负债表总额,可以在欧洲央行的统计数据仓库网站上找到(以及许多其他有趣的统计数据和数据集)。
应该注意的是,尽管欧洲央行收集的数据主要与 T2 欧元区国家相关,但一些非欧元区国家的中央银行也选择收集数据并发送给欧洲央行。例如,Q2 2020 年的 FVC 数据包括了来自保加利亚、瑞典和丹麦的数据。
这段代码使用 FVC 的数据生成一个“choropleth”地图,向您展示欧元区哪些国家拥有最多的金融工具公司。如下调用脚本(假设所有数据文件都在同一个目录中):
$ python fvc.py CNTR_RG_20M_2020_3857.shp FVC_2020_Q2.xlsx fvcs_in_euro_area.png
…将生成这样的图像:

行政边界的欧洲地理
衍生品—埃米尔报告
欧盟的衍生产品受欧洲市场基础设施法规 (EMIR)监管,该法规要求欧盟交易对手签订的所有衍生产品的详细信息必须报告给交易库。贸易报告本身并不公开。然而,交易存储库有义务向公众提供按衍生产品类别细分的某些汇总衍生产品数据,具体来说,就是汇总未平仓头寸、汇总交易量和汇总价值。汇总的数据必须公布在公众易于访问的网站或在线门户上,并且必须至少每周更新一次。
不幸的是,据我所知,没有一个中央来源(如 ESMA 网站)可以访问这些数据;每个交易库都在其网站上发布自己的数据。因此,似乎获得完整集合数据的唯一方法是检查 ESMA 的贸易库列表,进入每个注册贸易库的网站,导航到适当的部分(它可能被称为类似“埃米尔公共数据”)并访问和下载相关日期的数据。例如,这里的是 DTCC 访问数据的页面。
更重要的是,尽管大多数交易存储库似乎允许你以文件的形式下载数据,但是格式之间并不一致;有些以逗号分隔值的形式提供数据,有些以 Excel 电子表格的形式提供数据,有些以 XML 的形式提供数据。因此,不仅需要一些手动工作来访问所有数据,还需要根据需要整合数据。
证券融资交易— SFTR 报告
证券融资交易法规 (SFTR)要求将“证券融资交易”(sft)的详细信息报告给交易存储库。sft 包括回购交易、证券借贷交易和融资融券交易等。
SFTR 报告义务与埃米尔报告义务非常相似,公开数据(以及获取数据的方式)也很相似。这里的是 DTCC 的 SFTR 数据页面。SFTR 报告义务相当新,仍在逐步实施中,因此并非所有市场参与者都需要报告。
简介
根据招股说明书条例,向公众发行证券(如债券或股票)的公司,或者将被允许在受监管市场交易的公司,必须为这些证券起草招股说明书,招股说明书必须符合招股说明书条例的要求,并且必须得到有关主管当局的批准。ESMA 在其网站上维护着一份当前已获批准的招股说明书的注册记录,并通过 API 提供机器对机器的访问。关于如何使用 API 的详细说明可以在这里找到(特别参见第 1、2 和 5 节)。
处理数据
在使用我上面讨论的任何数据集时,下面是一些你应该记住的事情。
了解数据的范围
在处理任何这些数据集之前,准确了解谁需要提供相关数据、他们需要提供什么以及何时需要提供这些数据非常重要。否则,你可能会发现你的数据并不像你想象的那样准确或全面。上面讨论的 SFTR 数据就是一个例子,它现在还不能给出欧盟 SFT 市场的全貌,因为并非所有的市场参与者都需要报告他们的 sft。
理解这些数据集的精确范围不可避免地涉及到对基本规则及其应用的一些理解。这并不容易,而且(远远)超出了本文的范围。ESMA 和其他监管机构发布了各种问答和其他形式的指导,旨在帮助市场参与者了解适用于他们的报告要求的范围,这可能有助于您了解您可以获得的数据中包含和不包含的内容。
了解英国退出欧盟将如何影响这些数据集也很重要。英国的大多数市场参与者将继续遵守金融行为监管局(FCA)制定的同等或类似的报告要求。然而,在后英国退出欧盟时代,大多数情况下,英国实体报告的数据将与 EU-实体提供的数据分开发布。英国的新规定在某些方面也可能不同于欧盟的规定。FCA 的网站有更多关于英国退出欧盟过渡的信息——特别参见“市场”标签下的“市场政策”标题。
了解数据的局限性
所有数据集都容易出现错误、漏洞和不一致,我们在这里讨论的数据集也不例外。您可能会在需要清理的数据中遇到错误。
除了错误导致数据不正确的可能性之外,您还应该意识到数据报告方式不一致的可能性。例如,正如我们在上面看到的,有许多不同的方法来描述基准利率,如 EURIBOR。还有许多不同的方式来书写公司的名称,例如,取决于什么是资本以及公司的法律形式(如“公共有限公司”)是如何显示或缩写的。这就是为什么,如果可能的话,最好用雷或而不是公司名称来搜索和排序数据。
遵守我们讨论的法规并不总是完美的,这可能会影响数据的质量。一个例子是 2012 年首次引入的埃米尔报告义务。在引入该义务后的最初几年,行业遵守该义务的水平相当低,结果是当时的数据并没有描绘出欧盟衍生品市场的一幅非常全面的画面。随着时间的推移,合规性有所改善,但仍远非完美。
您还应该知道使用我所讨论的各种数据集所附带的法律限制和条件。对于欧盟监管机构直接发布的数据,通常允许免费使用。然而,通常需要包括某种形式的归属或通知。各种数据发布实体(ESMA、欧洲央行、GLEIF、贸易资料库等)的网站将规定具体的限制和条件。
补充数据来源
下面是一些其他的数据来源,当你试图分析或可视化我在这篇文章中讨论的数据集时,你可能会觉得有帮助。例如,在下面的链接中,你可以找到每个欧盟成员国的人口规模、经济规模和债务水平的数据。
- 世界银行数据:世界银行的数据库包含了世界上大多数国家的广泛数据,包括人口、GDP、债务等等。
- 欧盟统计局数据:欧盟统计局是欧盟的统计机构,其数据库包含了许多与欧盟及其成员国相关的有趣数据集。您还可以找到描述国家和其他行政区域的位置和边界的地理数据。这有助于创建基于地图的可视化。
- 欧洲晴雨表数据:欧洲晴雨表是代表欧盟定期进行的一系列调查,旨在评估欧洲人对广泛话题的看法。“标准欧洲晴雨表”调查是定期进行的,每次都倾向于问大致相似的问题,而“特别欧洲晴雨表”和“快速欧洲晴雨表”调查的频率较低(有时是一次性的),侧重于特定的主题。欧盟根据欧洲晴雨表调查的回复发布报告,但也可以下载原始数据(SPSS 或 STATA 格式)进行分析。
结论
这是对一小部分公开的监管数据的简要概述。还有很多其他的数据来源,我们没有时间去研究——例如,可以在 ESMA 注册网站上找到的其他注册。然而,希望这篇文章为您指明了正确的方向,您会发现一些解释和示例对您自己的项目有所帮助。如果你用我们在这里讨论的数据创造了什么,请在评论中分享!
使用 Python 中的统计假设检验评估 ML 分类器性能
有一个强有力的论据,为什么选择一个分类算法,而不是基于性能的重要性水平

Alexis Fauvet 在 Unsplash 上拍摄的照片
介绍
选择正确的机器学习算法是决定性的,它决定了模型的性能。选择模型时最主要的因素是性能,它采用 KFold-cross-validation 技术来实现独立性。
所选择的模型通常具有较高的平均性能。然而,有时它起源于统计上的侥幸。有许多统计假设检验方法来评估交叉验证产生的平均性能差异,以解决这一问题。如果差异高于显著性水平“ p 值”,我们可以拒绝两个算法相同且差异不显著的零假设。
在开发新的分类模型或参加 Kaggle 的比赛时,我通常会在我的管道中包含这样一个步骤。
教程目标
- 理解统计假设检验之间的区别。
- 基于平均性能分数的模型选择可能会产生误导。
- 为什么使用配对学生的 t 检验而不是原始学生的 t 检验。
- 利用 MLxtend 库应用 5X2 折叠的高级技术来比较基于 p 值的算法
目录
- 统计显著性检验是什么意思?
- 常用统计假设检验的类型
- 根据性能提取最佳的两个模型。
- 对最好的两个进行假设检验的步骤
- 应用 5X2 折叠的步骤
- 比较分类器算法
- 摘要
- 参考
统计假设检验是什么意思?
考虑到两个数据样本具有相同的分布,统计假设检验量化了它们的似是而非程度。描述了无效假设。我们可以通过应用一些统计计算来检验这个无效假设。
- 如果测试结果推断没有足够的证据来拒绝零假设,那么任何观察到的模型分数差异都是偶然发生的。
- 如果测试结果推断有足够的证据拒绝零假设,那么任何观察到的模型分数差异都是真实的。
统计假设检验的类型
通过统计显著性测试检查机器学习模型需要一些预期,这些预期将影响所使用的统计测试。这种比较最稳健的方式被称为 [成对设计](http://paired design of experiments) ,它在相同的数据上比较两种模型(或算法)的性能。这样,两种模型(或算法)都必须处理相同的困难。
在下文中,每个测试都有一些优点和缺点,您应该在选择时加以考虑。
还有其他用于比较分类器的统计测试,但这是最值得推荐的一种。
- 独立数据样本:有无限数据集时使用。您为训练收集 n 个 样本,并测试数据集。然后为每种方法计算十个独立的模型分数。最后,应用 t 检验来比较模型。然而,这种方法并不实际,因为现实中没有无限的数据。
2。十重交叉验证:使用普通配对 t 检验。相对于其他方法,该方法具有良好的可重复性,以及体面的类型 II 误差。但是,它有很高的I 型误差;这就是不推荐的原因。
通过交叉验证比较训练算法比比较特定(完全训练)模型的预测性能做出更强的假设。其中重采样验证(交叉验证属于)不能完全估计算法比较的方差不确定性。
3。麦克内马测试:
在统计学中,麦克内马检验是一种用于成对名义数据的统计检验。它应用于具有二分特征的 2 × 2 列联表,具有匹配的受试者对,以确定行和列的边际频率是否相等(即是否存在“边际同质性”)。— 维基百科
这是最近二十年推荐的。然而,这种方法的挑战在于,您要么需要构建自己的函数来实现它,要么使用第三方库,在您使用的工具中通常不会为您打包它。
4。非参数配对检验:这种方法包括做一些假设。例如,假设模型精度的分布具有正态分布(高斯)。
Wilcoxon 符号秩检验是配对学生 t 检验的非参数版本。尽管检验是非参数的,但它仍然假设每个样本内部的观察值是独立的。尽管使用 k 倍交叉验证会打破这个假设。
5。估计统计:一种数据分析框架,使用效应大小、置信区间、精度规划和元分析的组合来规划实验、分析数据和解释结果— 维基百科。然而,当使用重采样方法评估模型时,独立性假设被打破。作为替代,其他统计重采样方法,如自举。Bootstrapping 可以估计稳健的非参数置信区间。因此,我们可以解释结果并比较分类器。
5X2 折叠方法背后的直觉
一种在数据的相同 k 倍交叉验证分割上评估每个模型并计算每个分割分数的方法。这将为十倍交叉验证提供十个分数的样本。然后,我们可以使用配对统计检验来比较这些分数。
由于多次使用相同的数据行来训练模型,因此违反了独立性假设;因此,测试会有偏差。
这种统计测试可以调整,以克服缺乏独立性。此外,可以配置该方法的折叠和重复次数,以实现模型性能的更好采样。
Thomas Dietterich 在“用于比较监督分类学习算法的近似统计测试”中提出了这种方法 — 1998 年
正在加载数据集
对于本教程,我将使用sklearn库中的load_iris数据集。然而,对于任何 ML 问题,步骤都是相同的。

窥视虹膜数据集
提取最佳两个模型的步骤
在这一步中,我将根据性能准确度分数对四种不同的算法进行比较。然后将选择得分最高的两个模型在它们之间进行假设检验。
# Spot-Check Algorithms
models = []
models.append(('LR', LogisticRegression(max_iter=1000)))
models.append(('LDA', LinearDiscriminantAnalysis()))
models.append(('KNN', KNeighborsClassifier()))
models.append(('DSC', DecisionTreeClassifier(random_state = 1, max_depth=2)))
models.append(('SVM', SVC()))
# evaluate each model in turn
results = []
names = []
for name, model in models:
kfold = RepeatedStratifiedKFold(n_splits=10, n_repeats = 3, random_state=1)
cv_results = cross_val_score(model, X, y, cv=kfold, scoring='accuracy')
results.append(cv_results)
names.append(name)
msg = "%s: %.2f (%.3f)" % (name, cv_results.mean(), cv_results.std())
print(msg)
结果:
LR: 0.96 (0.041)
LDA: 0.98 (0.031)
KNN: 0.96 (0.037)
DSC: 0.94 (0.051)
SVM: 0.96 (0.045)
看来LR, KNN和SVM的均值相同,标准差略有不同。然而,LDA表现出较高的性能,而DTC表现出最低的性能。让我们在KNN、DTC,和LDA之间建立一个箱线图,作为更多解释的可视化。
import matplotlib.pyplot as pltplt.figure(figsize = (15, 10))
plt.grid(False)
plt.title("Mean accuracies between the best two selected algorithms", fontsize = 25, fontweight = 'bold')

算法间的平均精确度
好像 LDA 和 DTC 表现差不多,就挑那两个吧。
对于这个分类问题,您可以实现逻辑回归。然而,我选择了更复杂的分类算法来展示假设检验的思想。
假设检验的步骤
第一步是陈述零假设。
H0:两个模型在数据集上都有相同的表现。
H1:两个模型在数据集上的表现不尽相同。
显著性水平为 0.05
假设显著性阈值为 α=0.05 ,用于拒绝两种算法在数据集上表现相同的零假设,并进行 5x2_cv _t_test。
# evaluate model 1
model1 = LinearDiscriminantAnalysis()
cv1 = RepeatedStratifiedKFold(n_splits = 10, n_repeats = 3, random_state = 1)
scores1 = cross_val_score(model1, X, y, scoring = 'accuracy', cv = cv1, n_jobs = -1)
print('LDA Mean Accuracy: %.1f%% +/-(%.3f)' % (mean(scores1*100), std(scores1)))# evaluate model 2
model3 = DecisionTreeClassifier(random_state = 1, max_depth=2)
cv2 = RepeatedStratifiedKFold(n_splits = 10, n_repeats = 3, random_state = 1)
scores3 = cross_val_score(model2, X, y, scoring = 'accuracy', cv = cv2, n_jobs = -1)
print('DecisionTreeClassifier Mean Accuracy: %.1f%% +/-(%.3f)' % (mean(scores3*100), std(scores3)))# plot the results
plt.boxplot([scores1, scores2], labels=['LDA', 'DTC'], showmeans=True)
plt.show()
结果
LDA Mean Accuracy: 98.0% +/-(0.031)
DecisionTreeClassifier Mean Accuracy: 96.4% +/-(0.037)
看来LDA比DTC有更好的性能,而LDA的精度更高。
使用 MLxtend 封装的 5 乘 2 CV
您可以从头开始实现 5X2 CV 折叠;但是,有一个很好的软件包可以节省您很多时间,它叫做 MLxtend。我将使用评估模块中的 paired_ttest_5x2cv 函数来计算两个模型的 t 和 p 值。
from mlxtend.evaluate import paired_ttest_5x2cv
# check if difference between algorithms is real
t, p = paired_ttest_5x2cv(estimator1=model1,
estimator2=model2,
X=X,
y=y,
scoring='accuracy',
random_seed=1)
# summarize
print(f'The P-value is = {p:.3f}')
print(f'The t-statistics is = {t:.3f}')
# interpret the result
if p <= 0.05:
print('Since p<0.05, We can reject the null-hypothesis that both models perform equally well on this dataset. We may conclude that the two algorithms are significantly different.')
else:
print('Since p>0.05, we cannot reject the null hypothesis and may conclude that the performance of the two algorithms is not significantly different.')
结果:
The P-value is = 0.027
The t-statistics is = 3.101
Since p<0.05, We can reject the null-hypothesis that both models perform equally well on this dataset. We may conclude that the two algorithms are significantly different
现在你有一个强有力的理由来解释为什么选择 LDA 而不是 DTC。
摘要
最后,我希望这篇教程很好地说明了如何使用假设检验来开发一个更有意义的模型。我的建议是在你的分类管道中加入算法比较。尝试迭代以及尝试不同的算法性能比较。
感谢阅读!
参考
- 赛车比赛
- MLxtend 库
- 比较监督分类学习算法的近似统计检验 — Thomas Dietterich,1998
- MLxtend.evaluate.5X2cv 配对 t 测试 API
- Sklearn 通用数据集 API
- 可执行 kaggle 笔记本
如何使用累积增益、提升曲线和 Python 评估分类模型性能

马修·奇里科在 Unsplash 上的照片
累积增益和提升曲线是两个密切相关的视觉辅助工具,用于测量预测分类模型的有效性。当您需要向业务涉众解释模型,并展示使用模型如何影响业务决策和策略时,与其他评估模型性能的方法相比,它们有几个很大的好处。
为了了解如何从中受益,让我们看看人们通常会遇到的第一个模型评估工具。在二元分类模型上评估预测模型性能的一种流行且有效的方法是使用受试者操作特征曲线(ROC)。ROC 曲线在纵轴上绘制了模型的灵敏度,也称为真阳性率,在 x 轴上绘制了 1 减特异性或假阳性率。最靠近左上角的曲线性能更好。比较曲线是一条对角线,它表示在不使用模型的情况下,通过使用简单规则对不同的情况进行分类,所有的预测信息都被忽略,每个记录都被简单地标记为多数类的成员。希望使用预测信息可以帮助创建一个比这个基准更好的模型。通常用来总结 ROC 的指标是曲线下面积(AUC ),它提供了一种综合的方法来评估所有可能的分类阈值的模型性能。

理解你的目标
如果您的唯一目标是预测您想要评估的每个新记录的类成员,并且您想要比较不同模型在这方面的性能,ROC 和 AUC 将是一个很大的帮助。但是,很多时候情况并非如此。业务问题通常会涉及检查一组新记录的预测目标,以检测哪些记录最有可能属于您感兴趣的特定类别,因此开始评估分类模型对新记录进行排序的效率不是很好吗?有许多业务问题可以归结为计算出一个模型在多大程度上帮助我们选择相对较少的记录,这些记录包含了问题上下文中相对较大比例的重要内容。也许这就是找出哪些客户最有可能流失,或者对营销提议作出回应,或者实施欺诈,或者点燃他们租赁的汽车。与坐在二楼休息厅咖啡桌上的神奇八号球相比,你的模型在帮助利益相关者定位这些案例方面会有多好?那就是心态的转变。从所考虑的下一个新观察值被分类的准确程度,到该模型创建分级观察值的层次结构的能力。
如果你带着 ROC AUC 数字参加会议来解释工作,你可能会让每个人坐半个小时的幻灯片来解释敏感性、特异性、AUC 代表什么,如何解释它,以及 ROC 曲线带来的所有警告。最后,你还是给他们一个数字,这个数字对他们来说一点也不直观,也不可行。AUC 不会帮助任何试图弄清楚他们是否想使用你的模型的人决定如何或在哪里应用你的工作。这就是累积收益和提升的来源。
让我们想象一下,你在大公司工作,监管营销的残酷上司通过设定预算来扼杀他们的活动推广,预算只允许他们从 25,000 名有新线索的客户中锁定 5,000 名客户。他们要求您建立一个模型,预测哪些客户最有可能对营销活动报价做出响应。他们不想浪费宝贵的资源去寻找几乎没有成功机会的线索。完成后,他们希望您参加一个会议,在会上您将解释为什么您的模型优于仅使用会计部经过战斗考验的 magic eight ball 随机选择线索,如果您还可以估计在预算限制允许的 5,000 个联系人中有多少个响应线索,那就太好了。
您决定建立一个分类模型,使用例如逻辑回归来输出潜在客户对营销促销的反应倾向。累积收益和提升不依赖于任何一个模型,它们可以像这样用于任何能够输出记录属于感兴趣类别的预测概率的模型。需要注意的是,它们不能很好地与多类分类器一起工作,除非您将一个类定义为最重要的类来识别,并将其他所有的类合并到一个组合其他所有类的类中。二元分类就是你要找的。但在这种情况下,你只对回应者和非回应者感兴趣,你就可以走了。因此,您需要在记录的选择或子集上训练模型参数,在验证集上测试性能,检查 ROC 曲线和 AUC 值等性能指标以帮助优化模型,并检查它是否过度拟合或拟合不足,直到得到您满意的模型。
具体细节
累积增益和升力图都是使用相同的输入构建的。您需要模型输出的每条记录属于目标类的预测概率,以及该记录属于验证数据集中的实际类。如果你要绘制这个图而不使用某个包中的函数,那么所有的观察值都需要根据模型的输出按降序排列。然后,对于每一行,添加到当前行为止(包括当前行)的实际感兴趣的类成员的累积数量。这个结果累积列是根据记录数绘制的。它看起来会像这样。

累积增益和提升图的 x 轴左侧将从根据模型属于感兴趣类别的概率最高的观察值开始。这些概率沿着轴向右方向递减。x 轴告诉我们被考虑的观察值的百分比。y 轴表示作为感兴趣类别的所有潜在观察值的累积量,占当前正在考虑的观察值的百分比。现在,您可以通过该图提出和回答的问题是,当模型应用于数据时,选择了最有可能的 X %的记录,您希望找到的实际记录的百分比是多少?
我们怎么知道自己什么时候很牛逼?
为了了解这个模型有多好,需要与我们已经有的东西进行比较,而我们已经没有什么东西了。一个很好的比较基准是由某个人随机分配每个观察结果的倾向所产生的结果。平均而言,使用该方法的累积列将增加,增加量为感兴趣的类的总数除以每行中的观察总数。例如,如果您的数据集有 26 个观察值,其中 13 个实际上是您感兴趣的类,那么您会期望随机选择属于感兴趣的类的单个记录的概率为 13/26 = 0.5。如果随机选择 10 条记录,则预期 10 X 0.5 = 5 条记录属于该类别。基线累积总量图将是一条从点(0,0)到点(总观测值,感兴趣类别的数量)的对角线。在这个例子中,从(0,0)到(26,13)。
scikitplot 模块使构建累积增益曲线变得相对容易,而不必手动排序和计算累积总量,然后绘制曲线。您可以使用名为 plot_cumulative_gain 的方法,它有两个参数。第一个是包含目标的真实值的数组。第二个是对模型观测结果的预测。预测应该包括类或目标的输出。以下代码使用虚拟数据构建了一个快速逻辑回归模型,无需任何预处理、验证或优化,以尝试确定最有可能响应营销活动的销售线索。我不打算做任何验证或调整,只要足以让我们可以开始解释结果图。predict_log_proba 的输出返回两个类的估计值,这两个类在一个 numpy 数组中成对出现,该数组可以传递到绘图函数中,无需进一步处理。

现在可以与业务利益相关者分享一些有意义的陈述,这些陈述直观地揭示了这种模型为什么有用以及如何有用。业务限制是新营销活动只能瞄准 5,000 个新销售线索,这是 25,000 个可用销售线索的 20%。我们可以从标记为 1 级的兴趣类别的累积收益曲线中看到,选择最有可能响应营销要约的前 20%的销售线索将只包含大约 45%的实际响应者。您可以使用类似于df[“target"].value_counts() 的东西来查看训练数据中有 1187 个实际响应者,因此在营销给模型排序为最有可能响应的 5,000 个销售线索后,可以预期有 1187 X 0.45 = 534.15 个响应。在不使用该模型的情况下,预期的基线数字将仅为 1187 名实际回应者的 20%,或者 1187 X 0.2 = 237.4 名针对这 5,000 名销售线索的营销回应者。当应用于新数据时,使用该模型可能会产生比随机选择好 534.15 / 237.4 = 2.25 倍的结果。反之亦然。如果业务目标是达到 60%的最有可能响应的销售线索,那么您可以在 y 轴上找到该数量,并确定大约只需要使用大约 30%的最有可能的销售线索来实现这一目标。
提升图提供了一种简单的方法,可以直观地显示应用模型比随机选择任何百分比的排名记录好多少倍。它只是自动执行我们之前所做的计算,得出结论:当选择 x 轴所有可能值中的前 20%时,使用该模型会产生 2.25 倍的更好结果。scikitplot 包还提供了一个升力曲线的实现。相同的y和X变量可以作为plot_lift_curve函数的输入循环使用。

让我们检查一下我们早期的工作。等级 1 在 20%时的升力曲线在 y 轴上的值大约为 2.25,这与之前计算的模型在完全没有模型的情况下的有效性一致。用于比较的基线是 1.0 处的水平虚线。随着要添加的实际上是感兴趣的类的记录越来越少,曲线逐渐减小,并且模型提供优势的机会也越来越少。
一个真正工作良好的分类器将为相对小百分比的排序数据的选择产生高“提升”。现在,当你展示你的模型时,你有了一个优雅的指标来分享,它不需要任何人在对它有一个直观的理解之前经历三个不同的 Coursera 课程。现在,您可以像这样提供输入:该模型的性能应该是随机选择销售线索的两倍多,我们可以估计,我们营销的 5000 个销售线索中,大约有 535 个会对该提议做出响应。这是一个可操作的声明。采取行动,修改决策,或为追求商业目标部署更多或更少的资源,多少提升才算足够,没有任何正确的答案。将一个模型作为比随机决策更好的选择,无疑会增加它被使用和欣赏的机会。当可以估计分类成功和错误的成本和收益时,提升图甚至可以更加强大和提供更多信息。我将在下一篇文章中讨论这个问题!
正确评估你的模型
这不全是统计数据
我们在机器学习方面看到的进步是不可否认的,在任何一周,我们都看到新的算法被研究和理论化,新的库被发布到开源社区,新的准确性基准被超越。毫无疑问,数据科学社区正在开发越来越擅长优化目标的工具。但这不是我今天想谈的。当我们越来越擅长达到目标时,我想问这个目标是否一直是正确的。随着模型拟合变得越来越复杂,模型评估似乎保持不变。这似乎是有道理的,因为只有这么多的指标可以用来评估模型的预测,但实际上,模型评估不仅仅是统计误差和偏差。
让我们看一个真实的例子。当我们观看比赛时,我们通过单圈时间来衡量赛车性能,这是速度和操控性以及其他更详细指标的函数。当我们买车时,它能跑多快可能不是我们评价标准中最重要的。当我们考虑投资一家汽车公司时,他们的车能跑多快几乎无关紧要。在定义明确的比赛环境中,简单的速度指标至关重要,但随着我们进入更广泛的背景,它的重要性逐渐减弱。这个简单的例子告诉我们,我们的评估标准会根据我们所处的环境发生显著变化,我们以前都经历过。然而,当涉及到机器学习模型和数据科学项目的评估时,这个简单的逻辑似乎被层层的技术概念所掩盖。

威廉·沃比在 Unsplash 上的照片
我经常看到的当前方法是试图向一位企业高管解释,为什么将均方根误差提高几个百分点很重要。这类似于我们试图决定是否应该投资一家汽车制造商,因为如果我们继续前面的例子,他们的新车在最高速度上有轻微的改善。难怪关于技术度量改进的对话从未真正传达给高级涉众。我认为值得注意的是,我并不是说技术指标不重要,它们绝对重要,但是当我们从技术解决方案转移到业务解决方案时,我们需要相应地度量正确的指标。
衡量什么是重要的
到目前为止,我们应该已经知道,在高效地进行数据科学研究时,提出正确的问题并找到正确的问题来解决是非常重要的。但是,在评价的时候,我们往往不会在另一边跟进。例如,如果我们想要评估客户流失预测模型是否有助于留住客户以增加经常性收入。了解客户流失的可能性只是等式的一部分。我们还需要考虑其他因素,比如我们能在多大程度上说服客户不要流失,这样做要花多少钱,我们有什么资源等。最终,我们应该根据保留的预测收入来评估我们的模型,因为这是我们所关心的。使用正确的指标将确保我们不会浪费时间优化无关紧要的事情。
这一点经常被忽视,因为不像建模算法,我们可以安装一个库并使用,没有标准的度量标准可以完全适用于我们的具体情况。作为分析专业人员,这是我们需要花时间思考什么是正确的评估标准的地方,因为我们有责任确保我们的解决方案在付诸实践时是有效的。
开始的时候要有目的
我经常看到的另一个常见的陷阱是,我们在没有确定如何评估输出的情况下就开始分析。毫无疑问,直接进入项目是令人兴奋的,但如果我们不预先定义评估标准,我们可能会偏向于我们已经建立的解决方案,因为我们致力于它。在我们开始构建解决方案之前设计评估流程并标准化评估流程,可以确保我们客观地评估不同的想法。
选择的悖论
有多少次,当涉及到模型诊断时,我们发现自己迷失在度量的海洋中。以一个简单的分类问题为例,我们可以使用混淆矩阵、ROC 曲线和 F1 分数等来评估模型。正如我们之前所讨论的,这些指标都不应该是我们用来评估模型的最终指标,因为它们不能反映全部情况,但是这并不意味着它们没有帮助。这些诊断度量使我们能够理解模型正在做什么,并且它们帮助我们识别我们可以迭代的改进区域。理解什么样的指标对什么样的场景有用,以及理解它们之间的关系是很重要的。
找到正确的业务指标
数据科学是使用数据解决业务问题的过程。我们了解将业务问题转化为可以用数据解决的技术问题的重要性,我们还需要了解我们需要将结果转化为更广泛的公司能够理解的业务问题。这是一个建立业务模型、理解不同业务部门之间的关系以及什么指标对他们来说是重要的过程。虽然这看起来不像是一个“技术性”的练习,但这是将一个表现良好的模型转化为有用的解决方案的关键部分。这也是领域专业知识发挥作用的地方,因为这将有助于将技术指标转化为业务指标。
回归基础
与算法开发不同,模型评估与复杂性和寻找更好的优化方法无关。模型评估是关于简单性和找到性能的正确表示。如果一个好的机器学习模型是一辆快车,那么一个好的模型评估就是一个好的导航系统。如果我们想到达正确的目的地,我们需要同时关注这两个方面。所以下一次,当你构建一个解决方案的时候,回到基础,想想什么样的指标是重要的,以及你如何用它来评估你的方法。
如果你喜欢我的内容并分享我对这个话题的看法,请在 https://jchoi.solutions/subscribe注册
使用 NDCG 评估你的推荐引擎
如何最好地评价一个推荐系统是一个有争议的话题。让我们看看如何使用 NDCG 度量来评估推荐引擎。
对此类机器学习主题感兴趣或需要一些帮助?
我们处在一个个性化的时代。用户想要个性化的内容,企业也在利用这一点。通常使用机器学习技术构建的推荐引擎已经成为满足这种需求的重要工具之一。然而,开发一个推荐引擎有其挑战性。

演职员表:蓝钻画廊的尼克·扬森
开发或增强推荐引擎的关键挑战之一是评估其影响。虽然我们对积极影响有把握,但有必要对其进行量化。 这种量化不仅有助于利益相关方的沟通,还可以作为未来改进的基准。
在探索了一些方法后,我决定采用归一化贴现累计收益或简称为 NDCG 。
NDCG 是衡量排名质量的一个标准。
在信息检索中,这些措施评估文档检索算法。
在本文中,我们将涵盖以下内容:
- 使用质量排名方法评估推荐引擎的理由。
- 潜在的假设。
- 累积增益
- 贴现累计收益(DCG)
- 标准化贴现累积收益(NDCG)
是不是一个有效的措施!?
读完这篇文章后,我想到的第一个问题是如何衡量排名质量适合评估推荐引擎?
推荐引擎从该引擎发现与用户最相关的超集中推荐一组文档。从这个意义上说,推荐引擎只是执行文档检索的任务。因此,我们可以使用 NDCG 来评估推荐引擎。
让我们看看 NDCG 的理论,以及我们如何使用它来评估一个推荐引擎。
要了解 NDCG,我们需要了解它的前辈:累积收益(CG) 和贴现累积收益(DCG)。同样,我们需要记住以下假设:
高度相关的文档比中度相关的文档更有用,中度相关的文档又比不相关的文档更有用。
累积增益
每个推荐都有一个关联的相关性分数。累积增益是推荐集中所有相关性分数的总和。

因此,具有文档相关性分数的有序推荐集 A 的 CG 将是:

贴现累计收益(DCG)
累积增益有一个缺点。考虑下面两个具有各个文档的相关性分数的有序推荐集。

我们知道集合 B 比集合 A 更好,因为它是按照相关性递减的顺序推荐的,但是根据累积收益,两个集合都同样好。真正缺乏的是位置和相关性分数的使用。DCG 填补了这一空白。该计算包括通过将相关性分数除以相应位置的对数来贴现相关性分数。

或者,也可以使用下面的表达式来计算。

如果具有较高相关性的文档排名较低,则与第一个表达式相比,第二个表达式的惩罚较重。根据应用,您可以选择任一表达式来计算 DCG 和 NDCG。
如果相关性分数是二进制的,即 0 或 1,那么两个表达式产生相同的结果。
让我们使用第一个表达式计算两个有序集的 DCG。

上述例子的 DCG 结果与我们的直觉一致。B 组比 a 组好。
标准化贴现累积收益(NDCG)
DCG 似乎是一个很好的衡量标准,因为它考虑了职位的重要性。然而,它仍然不完整。根据各种因素,为每个用户提供的推荐数量可能有所不同。因此,DCG 会相应地变化。我们需要一个有适当上限和下限的分数,这样我们就可以取所有推荐分数的平均值来报告一个最终分数。NDCG 带来了这种正常化。
对于每个建议集,为了计算 NDCG,我们需要计算:
- 推荐订单的 DCG
- 理想秩序的 DCG(iDCG)。
那么 NDCG 就是推荐阶的 DCG 与理想阶的 DCG 之比。

该比率将始终在[0,1]范围内。
考虑以下提供给其中一个用户的有序推荐集。

此建议集的理想顺序是:

相应的 DCG 分数使用第一个表达式:

因此,此建议集的 NDCG 将为:

为了评估推荐引擎,计算提供给用户测试集的推荐的 NDCG 平均值。
结论
在本文中,我们介绍了 NDCG 理论及其作为推荐引擎评估指标的用途。
还有其他度量,如平均精度等。然而,对于我建立的推荐引擎类型,我发现 NDCG 是一个更好的衡量标准。
NDCG 可能不是评估所有推荐引擎的最佳指标,但它对许多推荐引擎都适用。
对此类话题感兴趣或需要一些帮助?
评估贝叶斯混合模型

Andrew DesLauriers 在 Unsplash 上拍摄的照片
在 R/Python 中评估贝叶斯混合模型
由爱德华多·科罗纳多·斯罗卡 — 17 分钟阅读
在本文中,我的目标是引导您通过一些有用的模型检查和评估可视化方法来检查 R 和 Python 中的贝叶斯模型(不是典型的 RMSE)。

不溅
多通道神经网络
通过 Eugenio Zuccarelli — 7 分钟阅读
神经网络可以而且应该在多种类型的特征上进行训练。本教程将介绍如何使用 Keras Functional API 来扩展您的网络

疾控中心在 Unsplash 上的照片
通过文化维度理解 word 2 vec
由卡梅隆·雷蒙德 — 7 分钟阅读
Word2Vec 是一个工具,用于以保持关系的方式将对象作为向量嵌入。它是通过直觉做到这一点的,即在相似的上下文中使用的单词可能有相似的意思。

图片来自美国地球物理联盟
如何从外太空理解全球贫困
由 Asmi Kumar — 8 分钟读取
经济生计难以估计。即使在当今世界,也缺乏明确的数据来确定贫困地区,这导致资源分配不足——金钱、食物、药物和受教育机会。我们生产了大量的资源,为多达 100 亿人提供食物、衣服和住房,但仍有数亿人生活在贫困之中。

由 Unsplash 上的电影人拍摄的照片
用数据分析理解网球比赛中一发的重要性
由安德里亚·卡扎罗 — 9 分钟阅读
网球是一项动态复杂的运动。单个点涉及的击球有好几个,但只有一个是在不受对手影响的情况下进行的:发球。事实上,发球让球员有机会以具体的优势开始得分。良好的发球对每个职业选手来说都是很重要的,但是我们能把良好的第一发球和出色的表现联系起来吗?如果你是一名网球运动员,你可能听过这样一句话“你的第一次发球有多好,你就有多好”。这是真的吗?
在 R/Python 中评估贝叶斯混合模型
了解“后验预测检查”的含义以及如何直观地评估模型性能
我能说什么呢,模型检查和评估只是你在模型开发过程中不能(也不应该)避免的事情之一(好像这还不够明显)。然而,我认为在很多情况下,我们最终会追逐性能指标,比如RMSE、错误分类等。—而不是理解我们的模型对数据的表现有多好。这可能会导致接下来的问题。
因此,无论您使用什么样的框架和指标,我都建议您记住以下问题:
- 我的模型没有捕捉到我们的数据和对问题的理解的哪些方面?
- 哪种模式表现最好,它能在多大程度上推广(即在未来的工作中)?
避免追逐性能指标(例如 RMSE、错误分类等)。).理解我们的模型如何很好地代表数据和我们的知识也是至关重要的。
在本文中,我的目标是引导您通过一些有用的模型检查和评估可视化方法来检查 R 和 Python 中的贝叶斯模型(不是典型的 RMSE)。我将基于我上一篇文章中提到的一个例子和一组模型,所以我建议你在继续之前快速浏览一下。
[## R/Python 中线性混合模型(LMM)的贝叶斯方法
实现这些比你想象的要简单
towardsdatascience.com](/a-bayesian-approach-to-linear-mixed-models-lmm-in-r-python-b2f1378c3ac8)
一眼
以下是我将介绍的内容:
- 如何通过后验预测检查 (PPCs)检查模型拟合
- 如何通过交叉验证评估绩效(LOOCV,贝叶斯设置)
- 使用这两个概念的应用模型选择示例
事不宜迟,让我们穿越不确定性的沙丘,来到贝叶斯的土地上。(抱歉不是抱歉这个俗气的比喻。😉)

Andrew DesLauriers 在 Unsplash 上拍摄的照片
从我们离开的地方继续
在我之前的帖子中,我们的 EDA 建议我们探索三种贝叶斯模型——简单线性回归(基础模型)、随机截距模型和随机截距、随机斜率模型——模拟网站反弹时间,总体目标是确定各地年轻人在网站上花费的时间是否比老年人多。同样,我们运行了一些 MCMC 视觉诊断,以检查我们是否可以信任从brms和pymc3中的采样方法生成的样本。
因此,我们的模型开发流程的下一步应该是评估每个模型与给定上下文的数据的拟合度,以及衡量它们的预测性能,最终目标是选择最佳模型。
注意:之前的帖子只包含代码片段。所有模型拟合和 MCMC 诊断代码都是在 Github 上找到的。
步骤 3.b 后验预测检查(PPP)
后验预测检验只是贝叶斯术语中模型检验的一种花哨说法。该名称源自用于评估拟合优度的方法(解释如下)。一旦你拟合了一个模型,并且 MCMC 诊断显示没有危险信号,你可能想要直观地探索模型与数据的拟合程度。在非贝叶斯设置中,你可能会看残差或正态 Q-Q 图(你仍然可以对贝叶斯模型这样做)。但是,请注意,贝叶斯残差图不会捕捉我们推论的不确定性,因为它们是基于单参数绘制的。
贝叶斯模型是可生成的,因此我们可以模拟模型下的值,并检查这些值是否与原始数据中的值相似。
贝叶斯模型本质上是可生成的,它允许我们在模型下模拟数据集,并将这些数据集与观察到的数据集进行比较。如果模型拟合得很好,我们希望模拟值看起来与我们观察到的数据相似。相反,如果我们的模拟数据与观察到的数据不相似,那么我们就错误地指定了模型,应该警惕我们的参数推断。
如果模拟值与观测值不相似,那么我们可以说“不合适”或“模型设定错误”。
因此,检查模型拟合的最常见技术是模拟来自后验预测分布的数据集— 因此术语后验预测检查— 定义如下

我们基本上是对我们的后验推断进行边缘化(整合)以获得给定我们的观察数据 y 的预测值ỹ。您可以将此过程视为首先模拟来自您的联合后验(例如均值和方差)的一些参数值,然后使用这些参数值作为似然函数(例如正态分布)的输入来生成预测样本。
因此,我们后验推断的质量将影响后验预测样本代表观察数据的能力。
让我们来看一些编码的例子。
比较后验密度
首先,让我们探索一下模拟数据集的密度与观测数据的密度相比有多好。
In R bayesplot提供了很好的内置函数ppc_dense_overlay来生成这些可视化效果。
在 Python 中, PyMC3 也有通过arviz生成的内置函数plot_ppc。
下面我们看到,随机截距模型生成的模拟数据与观察到的数据非常吻合(即具有相似的模式)。


R(左)和 Python(右)中模拟数据(浅色)与观测数据(深色)的密度对比
比较后验检验统计
好的,我们的模拟数据在视觉上似乎类似于观察到的密度,但是我们可能也想知道模拟汇总统计数据与观察到的数据有多大的可比性。从你良好的 101 天统计中,你可能会想起典型的测试统计是均值、方差等。你可能会想使用它们。让我们看看当我们对基本线性回归的样本使用平均值时会发生什么。

太好了!后验样本的平均值似乎也符合数据——所以我们应该继续,对吗?嗯,等一下。再来看另一个汇总统计:偏斜度。

嗯,什么?发生了什么事?!嗯,这是一个警示故事,它说明了检查不仅仅是后验预测样本的均值和方差的重要性。如果我们只是这样做,我们可能会错误地得出结论,我们的模型不缺乏拟合,它正确地表示了数据,但它显然没有捕捉到它的偏斜度。
事实上,建议查看与您正在更新的任何参数无关(也称为正交)的汇总统计数据。
与我们的模型参数相关的测试统计可能无法捕捉数据和我们的模型之间的潜在问题。
在我们的案例中,我们的模型假设为高斯分布,我们正在更新均值和方差参数。因此,我们可以探索的不相关的度量标准是偏斜度和中值——前者在群体层面,后者在群体层面。
在 R 中,我们可以使用两个bayesplot函数来生成这些图:ppc_stat和ppc_stat_grouped。
在 Python 中,这并不简单,但是可以通过使用pandas、matplotlib和plotly的一些定制代码来实现,如下所示。
现在,我们可以看到随机截距模型捕获了观察数据的行为。首先,基于偏斜度


R(左)和 Python(右)中模拟的(直方图)与观察到的(黑线)偏斜度统计
其次基于县级中值。


步骤 3.c 边缘(逐点)后验预测检查
在上一节中,我们介绍了使用联合后验预测密度(即考虑所有数据)的模型检查。然而,如果我们也对检测异常的观察值感兴趣,比如异常值和有影响的点,或者检查我们的模型在观察值之间指定得有多好呢?使用联合分布使这一点变得非常困难。相反,我们可以基于边际(即单变量)后验预测分布,将我们的模型检查提升到更细粒度的水平。获得这些边缘样本的一种方法是通过留一交叉验证(LOO CV)预测密度。

“等等,但那太没效率了!”我知道,我知道。计算这些需要我们改装模型 n 次(!!),但不要担心亲爱的读者,有办法不用所有的改装就能接近这些密度。聪明的人想出了一个优雅的近似方法,叫做帕累托平滑重要性抽样 (PSIS),我称之为洛-PSIS。
边际预测检查对于检测异常值和影响点,或检查整体模型校准(即模型的指定程度)特别有用。
模型校准—识别模型规格错误
在贝叶斯设置中,我们使用一些概率论来测试这一点——具体来说,一个称为概率积分变换 (PIT)的概念,它基本上使用 CDF 属性来将连续随机变量转换为均匀分布的变量。然而,只有当用于生成连续随机变量的分布是真实分布时,才是正确的。
这对我们意味着什么?在我们的例子中,拟合模型是产生连续随机变量的原因,因此,如果它是真实反弹时间生成分布、的良好近似,那么我们为每个 LOO 边缘密度计算的一组经验 CDF 值将近似一致。也就是说,对于一个遗漏点的每个单变量密度 p( ỹ_i | y_-i ) ,我们将计算一个 CDF 值[p _ I =pr(ỹ_i≤y _ I | y _-I),然后绘制这些***p_i***以查看它们看起来是否均匀分布。
如果我们的拟合模型是真实数据生成分布的良好近似,那么矿坑转换值将近似遵循均匀分布。
对一些人来说,这听起来像是“巫毒魔法”,所以我写了一个不错的附带教程,你可以回顾一下,以获得更多关于为什么这是真的直觉。您可以随意摆弄代码和数据。
[## 高级贝叶斯模型检查:校准
关于如何使用 LOO-CV 概率积分变换(PIT)获得如何修改模型以提高拟合度的提示的直观示例
htmlpreview.github.io](https://htmlpreview.github.io/?https://github.com/ecoronado92/towards_data_science/blob/master/hierarchical_models/bayes_lmm/loo_pit_example/loo_pit.html)
耶!如果你还在这里,这意味着我要么没有完全失去你的解释,要么我已经重新获得了你的信任(希望)与该教程。好了,让我们深入一个例子,看看如何使用这个诊断。作为提醒,我将把经验 CDF 值称为 LOO-PIT。
在 R,中,我们可以使用loo包生成 LOO-PSIS 样本,并使用 bayesplot ppc_loo_pit_overlay函数将 PIT 应用于这些值,并将它们与来自 Uniform[0,1]的样本进行比较。
在 Python 中,可以如下使用 PyMC3 内置函数plot_loo_pit
下面我们可以看到,我们的模型中的 LOO-PIT 值(粗曲线)是根据标准制服的随机样本(细曲线)绘制的。无需深入细节,以下是解读这些情节的一般方法:
- 集中在 0 或 1 附近的 LOO-PIT 值暗示模型分散不足(即我们的逐点预测密度太窄,预期变化小于数据中发现的变化)
- 集中在 0.5 附近的 LOO-PIT 值暗示模型过度分散(即,我们的逐点预测密度过于宽泛,预期变化大于数据中发现的变化)
查看我们的模型,没有任何明显的不适合,因为 LOO-PIT 值遵循看似合理的统一样本。然而,在 0.6 附近似乎有一个粘滞点,这暗示了轻微的过度分散(即,一些边缘密度与数据相比太宽),并在教程中讨论,该教程链接在上方。相反,如果厕所线不在统一样本附近,那么您应该将此解释为不合适,并探索进一步的建模。


R(左)和 Python(右)中随机截距模型的 LOO-PIT 示例。
(要了解更多信息,我建议你阅读《贝叶斯数据分析 3 的第152–153 页)。
使用 Pareto-k 诊断识别异常值和影响点
在任何建模场景中,我们感兴趣的是潜在的有影响的数据点或异常值可能对我们的模型产生的影响——即,如果我们忽略有影响的点,它们会极大地改变我们的后验预测密度吗?查看与这些点相关的观察提供了关于我们是否以及如何想要修改我们的建模策略的提示。传统上,我们比较全部数据后验预测密度和每个 100 CV 预测密度来识别这些点,但是这可能在计算上是昂贵的。
幸运的是,LOO-PSIS 方法已经计算了这种比较的经验估计:采样器中使用的广义帕累托分布的尾部形状参数( k̂ ) 。直观地说,如果一个被忽略点的边际预测密度有一个大的 k̂,那么它表明这个点有很大的影响。实际上,具有 k̂ 值的观测值:
- 小于 0.7 被认为是对 LOO 预测密度具有可靠 PSIS 估计的非影响点
- 介于 0.7 和 1 之间的被认为是有影响的和不太可靠的
- 大于 1 被认为是高度有影响的,并且模型估计不可靠
Pareto-k 诊断有助于识别模型中的问题点(甚至跨模型!).
让我们通过一个例子来获得一些关于如何使用这个 k̂ 来识别这些不寻常点的直觉。
在 R 中,您可以使用loo函数来计算和提取帕累托形状估计值 k̂ ,并使用ggplot可视化这些估计值。
在 Python 中,你可以使用 PyMC3 内置函数loo来生成逐点样本,使用plot_khat函数来可视化这些形状估计。
由于所有的观察值都有一个 0.5 的 k̂ < ,那么没有一个被认为对后验有影响,因为我们的模型能够正确地描述它们。换句话说,我们模型的卢-PSIS 估计是可靠的。


R(左)和 Python(右)中的 Pareto-k 诊断图
步骤 4:模型评估和比较
像往常一样,我们希望知道给定一些样本外(未知)数据时我们的模型的预测准确性。估计这种误差的一种常见方法是使用某种类型的交叉验证。除了典型的 RMSE 度量,线性贝叶斯模型的性能可以用一些额外的度量进行评估。例如,预期测井预测密度 (ELPD) 或Watanabe–Akaike 信息标准(WAIC)哪个 ELPD 更快且计算成本更低。在这里,我将重点介绍 ELPD 标准。
直观地说, ELPD 指的是模型在未知数据 分布上的平均预测性能(如上所述,我们可以用交叉验证来近似)。不管我们选择的交叉验证方式是 K-fold 还是 LOO,我们都可以为每个样本外数据点 获得一个预期 测井预测密度(ELPD)值 (参见此处的直观示例)。一般来说,ELPD 值越高,模型性能越好。
虽然这听起来可能违反直觉,但在贝叶斯设置中,计算 K 倍 CV 可能比 LOO CV 效率更低、更复杂。
现在,与 LOO 相比,使用 K-fold 似乎是显而易见的,因为它通常会导致更低的方差(尤其是当数据相关时),并且计算成本更低。然而,在贝叶斯设置中,我们有办法近似 100 值,而不必多次重新调整模型(例如,上面讨论的 PSIS 方法)。
此外,LOO ELPD 估计值比 K 倍 ELDP 值更有优势。它们允许我们识别难以预测的点,甚至可以用于模型比较,以识别哪个模型最好地捕捉每个样本外观察。
让我们通过一个示例来了解如何使用整体 LOO ELPD 值和点态 LOO ELPD 值来比较预测性能模型。
在 R 中,我们可以使用loo和loo_compare函数来比较多个模型的整体性能,以及一对模型之间的逐点差异。(注: *loo* 还提供了 *kfold* 功能。)**
在 Python 中,我们可以使用 PyMC compare和loo函数来获得相同的整体和逐点模型比较。
下面是上面代码的输出。总体性能最佳的型号通常列在最前面,有最小的(d_loo)和最大的(elpd_loo)。在我们的例子中,随机截距模型具有最好的整体性能。
****
R(左)和 Python(右)中整体模型性能输出的比较
现在,正如我上面提到的,我们可以获得逐点 ELPD 估计,而不管我们选择的 CV 方法,这允许我们更精细地比较模型。下面标绘的值是来自随机截距模型的 ELPD 值减去线性回归的 ELPD 值之间的差。在这里,我们看到随机截距模型具有更好的整体性能(即大多数值> 0)** ,但是,请注意在**某些点上,线性回归的性能更好。****
****
R(左)和 Python(右)中的逐点模型比较
ELPD 逐点图与上述 Pareto-k 诊断图配对有助于识别异常点。
把所有的放在一起
既然我们已经讨论了评估贝叶斯模型的所有细节,让我们将这些技术应用到我上一篇文章中的三个模型中。
模型检查
首先,我们比较模型的后验预测密度。在这里,我们观察到线性混合模型倾向于更好地拟合观察到的数据。

类似地,我们想要查看一些后验检验统计数据,记住与我们的模型参数相关的统计数据可能对检测模型的错误设定没有用处。下面,观察均值如何未能捕捉到线性回归的拟合缺失,而偏度系数清楚地显示了一个错误设定。

我们还可以查看特定于县的测试统计数据,以确定潜在的不适合性。下面我们观察到,混合模型比线性回归模型更容易捕捉到县的中位数(粗线)。

接下来,查看 LOO-PIT 诊断我们发现,在所有 PIT 值(粗线)遵循可能的随机均匀样本(细线)的情况下,我们的任何模型都不存在拟合不足。然而,如上所述,似乎所有模型都有一些棘手的问题。

线性回归似乎呈现出分散不足(即值集中于 1),而混合模型呈现出一些过度分散(即值集中于 0.5)。这提示进一步的建模工作可以集中在缩小混合模型中的单变量后验预测分布,以更好地捕捉不确定性。
模型比较
现在,查看使用 ELPD 信息标准的模型之间的预测性能,我们看到随机截距模型似乎是最好的模型(即elpd_diff = 0.0)。
## elpd_diff se_diff
## bayes_rintercept 0.0 0.0
## bayes_rslope -1.3 0.3
## lin_reg -347.8 18.8
我们可以看看随机截距模型和其他两个模型之间的逐点差异,看看它在哪里表现得更好(即ELPD_rand_int_i — ELDP_other_model_i)。顶部图表显示,对于大多数点来说,随机截距模型比线性回归(ELPD Pointwise Diff > 0)表现更好,因此模型性能存在较大差异。混合模型之间的类似比较证明了它们的类似性能,但是我们也可以使用这种分析来识别更难预测的观察结果(例如多塞特郡的观察结果)。

最后,查看帕累托-k 诊断中那些难以预测的观察值的指数,我们可以看到随机截距模型能够更好地解析这些观察值(即,更小的 k̂ 值)。

最终模型
恭喜你,你已经到达贝叶斯土地!在这一点上你应该为自己感到骄傲。浏览所有这些材料可能会令人望而生畏,但希望你已经对如何评估贝叶斯模型有了更好的理解和一些直觉。
从上面的分析中,我们看到这个数据的最佳模型是随机截距模型。它不仅显示了良好的预测性能,还显示了与我们数据的良好拟合。所以作为最后一步,让我们看看我们的推论,回答我们最初的问题:“年龄如何影响弹跳时间?”
下表总结了一些固定效应和组内/组间方差估计值,其可信区间为95。这里需要注意两件重要的事情:
- 假设 95%的区间不包含 0,我们确信所有这些估计都是非零的
- 和我们原来的问题相关,年龄对弹跳时间的影响在 1.8 左右。由于我们对我们的变量进行了中心缩放,因此相对于我们是否考虑高于或低于平均年龄的偏差,效果将是积极的或消极的。****
你可以使用 R 中的
tidybayes或者 Python 中 PyMC3 的pm.summary()函数来实现这样的汇总表。

理解群体间估计差异的一个非常有用的方法是可视化随机效应。下面我们看到cheshire, cumbria, essex, and kent的平均反弹时间更长,而london and norfolk的平均反弹时间更短。我们不能对dorset和devon这样说,因为他们 95%的区间包含零,因此我们不能确定这些县的跳出率偏离了人口平均水平。需要注意的一点是,我们的贝叶斯框架即使在样本规模较小的县(即kent和essex)也能够捕捉不确定性。
使用 R 中的
*tidybayes*或 Python 中 PyMC3 的*pm.foresplot()*函数,你可以实现这些非常漂亮的视觉效果

我们观察到,样本量较大的县拟合区间较窄(如cheshire),而样本量较小的县拟合区间较宽(如kent)。最后,我们可以根据数据检查拟合度。
在 R 中使用
*tidybayes*你可以很容易地实现这些非常漂亮的视觉效果,在 Python 中使用seaborn和pandas可能会更加繁琐,但仍然是可能的。

结论
评估贝叶斯模型遵循许多与您遇到的任何其他模型相同的拟合优度测试和性能比较步骤。然而,有一些工具和概念对于评估贝叶斯模型特别有用。有些非常复杂,如果你不熟悉它们的输出意味着什么,使用它们会让人感到畏惧。(没有什么比看不懂一个模型的输出汇总更让人苦恼的了。)
幸运的是,有可视化的方法来诊断模型的适合度,评估性能,甚至解释贝叶斯模型的结果。
我希望关于贝叶斯混合模型的第 2 部分能够继续增强您对贝叶斯建模的直觉,从而使它成为您工具集中的一种强大方法。
** [## R/Python 中线性混合模型(LMM)的贝叶斯方法
实现这些比你想象的要简单
towardsdatascience.com](/a-bayesian-approach-to-linear-mixed-models-lmm-in-r-python-b2f1378c3ac8) [## 当混合效应(分层)模型失败时:汇集和不确定性
一个直观和可视化的指南,其中部分池变得麻烦,贝叶斯方法可以帮助量化…
towardsdatascience.com](/when-mixed-effects-hierarchical-models-fail-pooling-and-uncertainty-77e667823ae8)
参考
- Gelman,a .,Carlin,J. B .,Stern,H. S .,Dunson,D. B .,Vehtari,a .,和 Rubin,D. B. (2013 年)。贝叶斯数据分析。CRC 出版社。
- 盖布里、乔纳等人,《贝叶斯工作流程中的可视化》《英国皇家统计学会杂志:A 辑(社会中的统计学)182.2(2019):389–402。
- 吉尔曼,安德鲁,杰西卡黄,和阿基维塔里。"理解贝叶斯模型的预测信息标准."统计与计算24.6(2014):997–1016。
- 维塔里,阿基,安德鲁·盖尔曼和乔纳·盖布里。“使用留一交叉验证和 WAIC 的实用贝叶斯模型评估。”统计与计算27.5(2017):1413–1432。
如果你喜欢这篇文章,请随意分享!如果您有任何问题,或者您看到任何不正确/有问题的内容,请发表评论或发推文( @ecoronado92 )。
所有的 R 代码都可以在这里找到
所有 Python 代码都可以在这里找到
报告包含的材料和例子实施贝叶斯线性混合效应(层次模型)模拟…
github.com](https://github.com/ecoronado92/towards_data_science/tree/master/hierarchical_models/bayes_lmm)**
评估分类器模型性能
精确度、召回率、AUC 等——去神秘化

由 Unsplash 上的absolute vision拍摄
现在是凌晨 4 点,你正在喝第七杯咖啡。你已经在论坛里搜寻了你能找到的最复杂的模型。您已经设置了预处理管道,并选择了超参数。现在,是时候评估你的模型的性能了。
你兴奋得发抖(也可能是咖啡因过量)。这是你在卡格尔世界舞台上的首次亮相。当你的预测被提交时,你的想法会转向你将如何处理奖金。兰博基尼还是法拉利?什么颜色的?红色最适合奶油色的室内装潢,但同时…
屏幕上弹出排行榜,好像在宣布什么。
你的模特表现变差了。你静静地坐着,似乎过了很久。
最终,你叹了口气,合上笔记本电脑的盖子,上床睡觉。
如果你以前尝试过建立一个模型,你会知道这是一个迭代的过程。进步不是线性的——可能会有很长一段时间,你看起来没有更接近你的目标,甚至在倒退——直到出现突破,你向前冲……并进入下一个问题。
在验证集上监控模型性能是一种很好的方式,可以获得关于您所做的工作是否有效的反馈。它也是比较两种不同模型的一个很好的工具——最终,我们的目标是建立更好、更准确的模型,帮助我们在实际应用中做出更好的决策。当我们试图向特定情况下的利益相关者传达一个模型的价值时,他们会想知道为什么他们应该关心:对他们有什么好处?这将如何让他们的生活变得更轻松?我们需要能够将我们已经建立的系统与已经存在的系统进行比较。
评估模型性能可以告诉我们我们的方法是否有效——这被证明是有帮助的。我们可以继续探索,看看我们能把我们正在研究的问题的现有概念推进到什么程度。它还可以告诉我们我们的方法是否不起作用——这被证明甚至更有帮助,因为如果我们的调整使模型在它应该做的事情上变得更糟,那么它表明我们可能误解了我们的数据或正在建模的情况。
所以模型性能的评估是有用的——但是具体怎么做呢?
通过示例的方式进行探索
目前,我们将专注于一类特殊的模型——分类器。这些模型用于将看不见的数据实例归入特定的类别——例如,我们可以建立一个二元分类器(两个类别)来区分给定图像是狗还是猫。更实际地,可以使用二元分类器来决定传入的电子邮件是否应该被分类为垃圾邮件,特定的金融交易是否是欺诈性的,或者是否应该基于在线商店的特定客户的购物历史来向他们发送促销电子邮件。
用于评估分类器性能的技术和指标将不同于用于回归器的技术和指标,后者是一种试图从连续范围预测值的模型。这两种类型的模型都很常见,但是现在,让我们将分析局限于分类器。
为了说明一些重要的概念,我们将建立一个简单的分类器来预测特定图像的图像是否是 7。让我们使用著名的 NMIST 数据集来训练和测试我们的模型。
(如果你想看完整的 Python 代码或者在家跟着看,可以在 GitHub 上查看制作这部作品的笔记本!)
下面,我们使用 Scikit-Learn 下载我们的数据并构建我们的分类器。首先,为数学导入 NumPy,为绘图导入 Matplotlib:
# Import modules for maths and plotting
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.style as style
style.use(‘seaborn’)
然后,使用 scikit-learn 内置的 helper 函数下载数据。数据以字典的形式出现——我们可以使用“数据”键来访问训练和测试数据的实例(数字的图像),使用“目标”键来访问标签(数字被手工标记为什么)。
# Fetch and load data
from sklearn.datasets import fetch_openmlmnist = fetch_openml(“mnist_784”, version=1)
mnist.keys()# dict_keys(['data', 'target', 'frame', 'categories', 'feature_names', 'target_names', 'DESCR', 'details', 'url'])
完整的数据集包含多达 70,000 张图像,让我们选取 10%的数据子集,以便更容易地快速训练和测试我们的模型。
# Extract features and labels
data, labels = mnist[“data”], mnist[“target”].astype(np.uint8)# Split into train and test datasets
train_data, test_data, train_labels, test_labels = data[:6000], data[60000:61000], labels[:6000], labels[60000:61000]
现在,让我们简单检查一下我们训练数据中的前几个数字。每个数字实际上由从 0 到 255 的 784 个值表示,这些值表示 28 乘 28 网格中每个像素应该有多暗。我们可以轻松地将数据重新形成网格,并使用 matplotlib 的 imshow()函数绘制数据:
# Plot a selection of digits from the dataset
example_digits = train_data[9:18]# Set up plotting area
fig = plt.figure(figsize=(6,6))# Set up subplots for each digit — we’ll plot each one side by side to illustrate the variation
ax1, ax2, ax3 = fig.add_subplot(331), fig.add_subplot(332), fig.add_subplot(333)
ax4, ax5, ax6 = fig.add_subplot(334), fig.add_subplot(335), fig.add_subplot(336)
ax7, ax8, ax9 = fig.add_subplot(337), fig.add_subplot(338), fig.add_subplot(339)
axs = [ax1, ax2, ax3, ax4, ax5, ax6, ax7, ax8, ax9]# Plot the digits
for i in range(9):
ax = axs[i]
ax.imshow(example_digits[i].reshape(28, 28), cmap=”binary”)
ax.set_xticks([], [])
ax.set_yticks([], [])

我们数据集中的九个数字样本
现在,让我们创建一组新的标签——我们目前只对是否是 7 感兴趣。一旦完成,我们就可以训练一个模型,希望它能挑选出构成数字“7-y”的特征:
# Create new labels based on whether a digit is a 7 or not
train_labels_7 = (train_labels == 7)
test_labels_7 = (test_labels == 7)# Import, instantiate and fit model
from sklearn.linear_model import SGDClassifiersgd_clf_7 = SGDClassifier(random_state=0)
sgd_clf_7.fit(train_data, train_labels_7)# Make predictions using our model for the nine digits shown above
sgd_clf_7.predict(example_digits)# array([False, False, False, False, False, False, True, False, False])
对于我们的模型,我们使用了一个 SGD (或随机梯度下降)分类器。对于我们的九个示例数字阵列,看起来我们的模型正在做正确的事情——它已经正确地从其他八个非七中识别出一个七。让我们使用三重交叉验证对我们的数据进行预测:
from sklearn.model_selection import cross_val_predict# Use 3-fold cross-validation to make “clean” predictions on our training data
train_data_predictions = cross_val_predict(sgd_clf_7, train_data, train_labels_7, cv=3)train_data_predictions# array([False, False, False, ..., False, False, False])
好了,现在我们对训练集中的每个实例都有了一组预测。听起来可能很奇怪,我们正在对我们的训练数据进行预测,但是我们通过使用交叉验证来避免对模型已经训练过的数据进行预测——请点击链接了解更多信息。
真/假阳性/阴性
在这一点上,让我们后退一步,想想对于给定的模型预测,我们可能会发现自己处于不同的情况。
- 模型可能预测的是 7,图像实际上是 7(真正);
- 模型可能预测的是 7,图像实际上不是 7(假阳性);
- 模型可能预测的不是 7,图像实际上是 7(假阴性);和
- 模型可能预测不是 7,而图像实际上不是 7(真阴性)。
我们使用真/假阳性(TP/FP)和真/假阴性(TN/FN)来描述上面列出的四种可能的结果。对/错部分指的是模型是否正确。肯定/否定部分是指被分类的实例实际上是否是我们想要识别的实例。
一个好的模型将会有高水平的真阳性和真阴性,因为这些结果表明模型在哪里得到了正确的答案。一个好的模型也会有低水平的假阳性和假阴性,这表明模型在哪里犯了错误。
这四个数字可以告诉我们很多关于模型做得如何以及我们可以做些什么来帮助的信息。通常,将它们表示为一个混淆矩阵是有帮助的。
混淆矩阵
我们可以使用 sklearn 轻松提取混淆矩阵:
from sklearn.metrics import confusion_matrix# Show confusion matrix for our SGD classifier’s predictions
confusion_matrix(train_labels_7, train_data_predictions)# array([[5232, 117],
[ 72, 579]], dtype=int64)
这个矩阵的列代表了我们的模型所预测的,而不是左边的-7 和右边的 7。这些行表示模型预测的每个实例的实际情况,而不是顶部的-7 和底部的 7。当比较我们的预测和实际结果时,每个位置的数字告诉我们观察到的每个情况的数量。
总之,在 6,000 个测试案例中,我们观察到(将“正面”结果视为 7,将“负面”结果视为其他数字):
- 579 个预测的 7 实际上是 7(TPs);
- 72 个预测的非 7 实际上是 7(fn);
- 117 个预测的 7 实际上不是-7(FPs);和
- 5232 个预测的非 7 实际上不是 7(TN)。
你可能已经注意到,理想情况下,我们的混淆矩阵应该是对角线— 也就是说,只包含真阳性和真阴性。事实上,我们的分类器似乎更多地与假阳性而不是假阴性作斗争,这给我们提供了有用的信息,以决定我们应该如何进一步改进我们的模型。
精确度和召回率

我们可以使用混淆矩阵中编码的信息来计算一些更有用的量。精度定义为真阳性的数量占所有(真和假)阳性的比例。实际上,这个数字代表了有多少模型的正面预测实际上是正确的。
对于我们上面的模型,精度是 579 / (579 + 117) = 83.2%。这意味着在我们的数据集中,所有我们预测为 7 的数字中,只有 83.2%实际上是 7。
但是,精确度也必须与召回一起考虑。召回被定义为真阳性的数量占真阳性和假阴性的比例。记住,真阳性和假阴性都与被考虑的数字实际上是7 的情况有关。所以总而言之,回忆代表了这个模型在正确识别正面事例方面有多好。
对于我们上面的模型,召回率是 579 / (579 + 72) = 88.9%。换句话说,我们的模型只捕捉到了实际上是 7 的数字的 88.9%。
我们还可以直接从我们的模型中获取这些量,从而避免手动计算这些量:
from sklearn.metrics import precision_score, recall_score# Calculate and print precision and recall as percentages
print(“Precision: “ + str(round(precision_score(train_labels_7, train_data_predictions)*100,1))+”%”)print(“Recall: “ + str(round(recall_score(train_labels_7, train_data_predictions)*100,1))+”%”)# Precision: 83.2%
# Recall: 88.9%
我们可以通过调整模型的阈值来设置期望的精度水平或回忆。在后台,我们的 SGD 分类器已经为数据中的每个数字得出了一个决策分数,它对应于一个数字的“七-y”程度。看起来非常像 7-y 的数字会有较高的分数。模型认为看起来根本不像 7 的数字会有较低的分数。模棱两可的情况(可能是画得很差的七,看起来有点像七)会在中间。决策分数高于模型阈值的所有数字将被预测为 7,而分数低于阈值的所有数字将被预测为非-7。因此,如果我们想提高我们的回忆(并增加我们成功识别的 7 的数量),我们可以降低阈值。通过这样做,我们实际上是在对模型说,“降低你识别 7 的标准一点”。然后我们会捕捉到更多的模糊的 7,我们正确识别的数据中实际的 7 的比例会增加,我们的回忆会增加。除了增加 TP 的数量,我们还将减少 fn 的数量——之前被错误识别为非 7 的 7 将开始被正确识别。
但是,您可能已经注意到,在降低阈值的过程中,我们现在很可能会将更多的非 7 人错误分类。画得有点像 7 的那个现在可能被错误地预测为 7。因此,我们将开始得到越来越多的假阳性结果,并且随着召回率的增加,我们的精确度将呈下降趋势。这是精确-召回的权衡。鱼与熊掌不可兼得。最好的模型将能够在两者之间取得良好的平衡,从而使精确度和召回率都处于可接受的水平。
什么样的精确度和召回率才算“可接受”?这取决于该模型将如何应用。如果未能识别出阳性实例的后果很严重,例如,如果你是一名旨在检测威胁生命的疾病的医生,你可能愿意承受更多的假阳性(并让一些没有患病的人做一些不必要的进一步检查)以减少假阴性(在这种情况下,有人不会接受他们需要的救命治疗)。同样,如果你有一种情况,在这种情况下,你有必要对你的积极预测非常有信心,例如,如果你正在选择一个要购买的财产或选择一个新油井的位置,如果这意味着你不太可能因为一个假阳性而投入时间和金钱,你可能会很高兴放弃一些机会(即让你的模型预测更多的假阴性)。
将精确度可视化——回忆权衡
我们可以观察精度和召回率如何随着决策阈值而变化(对于上面我们的指标的计算,scikit-learn 使用了零阈值):
# Use cross_val_predict to get our model’s decision scores for each digit it has predicted
train_data_decision_scores = cross_val_predict(sgd_clf_7, train_data, train_labels_7, cv=3,
method=”decision_function”)from sklearn.metrics import precision_recall_curve# Obtain possible combinations of precisions, recalls, and thresholds
precisions, recalls, thresholds = precision_recall_curve(train_labels_7, train_data_decision_scores)# Set up plotting area
fig, ax = plt.subplots(figsize=(12,9))# Plot decision and recall curves
ax.plot(thresholds, precisions[:-1], label=”Precision”)
ax.plot(thresholds, recalls[:-1], label=”Recall”)[...] # Plot formatting

正如你所看到的,精确和召回是一个硬币的两面。一般来说(也就是说,如果没有特定的理由以牺牲另一个为代价来寻找更多的一个),我们会希望调整我们的模型,以便我们的决策阈值设置在精确度和召回率都很高的区域。
随着决策阈值的变化,我们还可以绘制精确度和召回率之间的直接对比图:
# Set up plotting area
fig, ax = plt.subplots(figsize=(12,9))# Plot pairs of precision and recall for differing thresholds
ax.plot(recalls, precisions, linewidth=2)[...] # Plot formatting

我们还包括了曲线上当前模型(决策阈值为零)所在的点。在理想情况下,我们应该有一个既能达到 100%准确率又能达到 100%召回率的模型,也就是说,我们应该有一条通过上图右上角的准确率-召回率曲线。因此,我们对模型所做的任何调整,将我们的曲线向外推向右上方,都可以被视为改进。
F1 分数
对于精确度和召回率同样重要的应用,将它们组合成一个称为 F1 分数的量通常是方便的。F1 分数被定义为精确度和召回分数的调和平均值。直观地解释 F1 分数比分别解释精确度和回忆要困难一些,但是将这两个量总结成一个易于比较的指标可能是可取的。
为了获得高 F1 分数,模型需要同时具有高精度和高召回率。这是因为当取调和平均值时,如果精确度或召回率中的一个较低,F1 分数会被显著拉低。
from sklearn.metrics import f1_score# Obtain and print F1 score as a percentage
print(“F1 score: “ + str(round(f1_score(train_labels_7, train_data_predictions)*100,1))+”%”)# F1 score: 86.0%
ROC(受试者操作特征)和 AUC(曲线下面积)
评估(和可视化)模型性能的另一种常用方法是使用 ROC 曲线。从历史上看,它起源于信号检测理论,并在第二次世界大战中首次用于探测敌机,其中雷达接收机操作员根据输入信号进行检测和决策的能力被称为接收机工作特性。尽管今天人们使用它的准确语境已经发生了变化,但这个名字却一直沿用下来。

ROC 曲线描绘了真阳性率和假阳性率如何随着模型阈值的变化而变化。真正的阳性率只是被正确识别的阳性实例的百分比(即我们正确预测的 7 的数量)。相应地,假阳性率是被错误地识别为阳性的阴性实例的数量(即被错误地预测为 7 的非 7 的数量)。你可能已经注意到,真实肯定率的定义等同于回忆。您可能是对的——这些只是相同指标的不同名称。
为了对好的和坏的 ROC 曲线有一点直觉(因为思考这些更抽象的量实际上意味着什么通常有点棘手),让我们考虑一下极端情况——我们可能拥有的最好和最差的分类器。
最坏可能分类器基本上是随机的,50/50 猜测一个给定的数字是 7 还是不是 7——它没有尝试去了解这两个类别的区别。每个实例的决策分数基本上是随机分布的。假设我们最初将决策阈值设置为一个非常高的值,这样所有的实例都被分类为否定的。我们将不会识别出任何阳性实例——真或假——因此真阳性和假阳性率都为零。随着我们降低决策阈值,我们将逐渐开始将相同数量的阳性和阴性实例分类为阳性,以便真阳性率和假阳性率以相同的速度增加。这种情况一直持续到我们的阈值处于某个非常低的值,此时我们遇到了与开始时相反的情况——正确地分类了所有阳性实例(因此真实阳性率等于 1 ),但也错误地分类了所有阴性实例(假阳性率也是 1)。因此,随机的 50/50 分类器的 ROC 曲线是从(0,0)到(1,1)的对角线。
(你可能认为有可能有比这更糟糕的分类器——也许是一个每次都预测相反的数字而把每个数字都弄错的分类器。但在这种情况下,分类器本质上将是一个完美的分类器——如果错了,模型将需要完美地学习分类,然后在做出预测之前切换输出!)
最佳可能分类器将能够以 100%的准确度正确预测每个给定的实例是正面的还是负面的。所有正面实例的决策得分将是某个高值,以表示该模型对其预测具有极高的信心,并且对其给出的每个数字也是如此。所有否定的实例都有一些低的决策分数,因为模型再次非常有把握地认为所有这些实例都是否定的。如果我们以非常高的值开始决策阈值,使得所有实例都被分类为阴性,我们会遇到与 50/50 分类器所描述的相同的情况——真阳性率和假阳性率都为零,因为我们没有预测到任何阳性实例。同样,当决策阈值非常低时,我们将预测所有实例都是阳性的,因此真阳性率和假阳性率的值都是 1。因此,对于 50/50 分类器,ROC 曲线将从(0,0)开始,到(1,1)结束。然而,当决策阈值被设置在识别阳性和阴性实例的高和低决策分数之间的任何水平时,分类器将以 100%的真阳性率和 0%的假阳性率完美地操作。太神奇了!上面的结果是,我们的完美分类器的 ROC 曲线是连接(0,0),(0,1)和(1,1)的曲线——一条包围图的左上角的曲线。
大多数真实世界的分类器将介于这两个极端之间。理想情况下,我们希望我们的分类器的 ROC 曲线看起来更像一个完美的分类器,而不是随机猜测的——因此ROC 曲线越靠近图的左上角(越接近完美分类器的行为)就代表着一个更好的模型。
有了这些新知识,让我们画一些 ROC 曲线。
from sklearn.metrics import roc_curve# Set up plotting area
fig, ax = plt.subplots(figsize=(9,9))# Obtain possible combinations of true/false positive rates and thresholds
fpr, tpr, thresholds = roc_curve(train_labels_7, train_data_decision_scores)# Plot random guess, 50/50 classifier
ax.plot([0,1], [0,1], “k — “, alpha=0.5, label=”Randomly guessing”)# Plot perfect, omniscient classifier
ax.plot([0.002,0.002], [0,0.998], “slateblue”, label=”Perfect classifier”)
ax.plot([0.001,1], [0.998,0.998], “slateblue”)# Plot our SGD classifier with threshold of zero
ax.plot(fpr, tpr, label=”Our SGD classifier”)[...] # Plot formatting

很明显,我们的 SGD 分类器比随机猜测的要好!毕竟所有的工作都是值得的。我们可以通过计算模型的 ROC 曲线下的面积(称为 AUC)来量化模型性能,而不是依赖于“越靠近左上角越好”这种模糊的说法。
如果您还记得计算三角形面积的公式,您应该能够看到随机分类器的 AUC 是 0.5。您还应该能够看到完美分类器的 AUC 是 1。因此,AUC 越高越好,我们希望 AUC 尽可能接近 1。我们的 SGD 分类器的 AUC 可以如下获得:
from sklearn.metrics import roc_auc_score# Obtain and print AUC
print(“Area Under Curve (AUC): “ + str(round(roc_auc_score(train_labels_7, train_data_predictions),3)))# Area Under Curve (AUC): 0.934
孤立来看,很难准确说出我们的 AUC 0.934 意味着什么。正如之前看到的基于精度和召回的指标一样,这些是标准的比较工具。我们应该有目的地使用它们来开发和调整我们当前的模型,并将我们的模型与其他算法进行比较,以在我们的特定任务中寻求最佳性能。
结论
我们今天走了很多路,所以如果你一路过关斩将,恭喜你!当第一次处理一个问题时,人们很容易被大量的算法、方法和参数所淹没,这些算法、方法和参数可以作为解决问题的方法的一部分。模型性能度量可以作为指引我们穿越这片荒野的指南针——只要我们分解一个问题,决定一个初始方法(如果需要,我们可以在以后改变),并使用像上面解释的那些明智的工具来评估我们是否正在取得进展,我们将朝着我们需要去的地方前进。尽管看不到某个特定绩效指标的改善反映了数小时的研究和模型修补令人心碎,但知道我们是在前进还是后退总是更好。
所以坚持下去——如果数据显示某个方法不起作用,不要太投入。冷静地回顾和比较模型和方法。如果你能做到这一点,你马上就能坐上那辆配有奶油色内饰的法拉利。
学分和更多信息
Andrew Hetherington 是英国伦敦的一名见习精算师和数据爱好者。
本文中的代码块改编自 A. Géron 的 2019 年著作、使用 Scikit-Learn、Keras 和 TensorFlow 进行机器学习的实践第二版,作者为 Aurélien Géron (O'Reilly)。版权所有 2019 凯维软件有限公司,978–1–492–03264–9。
由absolute vision、 Markus Spiske 和 Marat Gilyadzinov 拍摄的照片。
评估聚类结果
用于评估聚类结果的标准

作者图片
聚类方法的主要目标是获得高的类内相似性和低的类间相似性(同一类中的对象比不同类中的对象更相似)。在我关于宏基因组学宁滨分析的工作中,我一直在使用不同的聚类方法,在这篇文章中,我想分享一些我的想法和我使用的技术。
聚类分析(聚类)
根据维基百科,
聚类分析或聚类是对一组对象进行分组的任务,使同一组中的对象(称为聚类)比其他组(聚类)中的对象彼此更加相似(在某种意义上)。
我希望你熟悉分类中使用的术语,如 TP、TN、FP、FN、准确度、精确度、召回率和 F1 分数。我不会深入这些条款的细节。如果你想回顾一下,我发现下面的文章非常有用。
评估聚类结果时遇到的问题
在我分析的一些案例中,聚类方法无法找到黄金标准中的正确聚类数。一些方法高估了聚类的数量,而另一些方法低估了聚类的数量。在这种情况下,我们不能使用用于分析分类结果的标准标准,因为分类结果的数量与黄金标准中的分类数量相同。
在浏览了我所在领域的相关文献后,我发现了一些标准,这些标准适用于我之前讨论过的情况。让我们看看如何继续我们的评估。
评定标准

图一。K x S 矩阵(图片由作者提供)
聚类结果表示为一个K x S矩阵,如图 1 所示,其中K是聚类方法预测的聚类数,S是黄金标准中存在的类数。
这里,元素 aₖₛ 表示聚集到 kᵗʰ 集群的对象总数,并且属于黄金标准中的 sᵗʰ 类。
在理想情况下,K = S其中通过聚类方法预测的类的数量与黄金标准中存在的类的数量相同。但是,在某些情况下,K < S或K > S聚类方法预测的聚类数不等于黄金标准中存在的类别数。
使用这个矩阵,我们可以找到以下标准。
- 精确
- 回忆
- f1-分数
- 调整后的兰德指数
精确
对于每个集群,我们都获得了分配了最大数量对象的黄金标准类。然后,我们对每个集群的最大对象数求和,并除以集群对象的总数。得到的值是 精度 并使用K x S矩阵,其计算如图 2 所示。

图二。精度方程(图片由作者提供)
回忆
对于每个黄金标准类,我们获得分配了最大数量对象的聚类。然后,我们对每个黄金标准类的最大对象数求和,并除以集群对象和非集群对象的总数。得到的值就是(也叫)并利用K x S矩阵,计算出来如图 3 所示。**

图 3。回忆方程式(图片由作者提供)
这里U表示未聚类对象的数量。
f1-分数
-得分 是 精度召回 的调和平均值,计算方法如图 4 所示。

图 4。F1 分数等式(图片由作者提供)
调整后的兰德指数
调整后的兰德指数(ARI) 是 兰德指数(RI) 的机会修正版。这是对聚类结果与其黄金标准分组相似程度的度量。使用K x S矩阵,ARI 的计算如图 5 所示。

图 5。ARI 方程(图片由作者提供)
这里N表示聚类对象的总数,并且(N 2)(二项式系数)被计算为N(N-1)/2。
示例演练
让我们看一个例子,我们将为给定的聚类结果计算不同的评估标准。假设金本位中有 257 个对象,我们知道每个对象的类别。
情况 1: K=S
让我们假设一个理想的情况,其中我们在黄金标准中有 5 个类别,并且通过聚类方法预测了 5 个聚类。我们可以得到一个如下图所示的K x S矩阵。
**64, 4, 1, 5, 0
2, 37, 1, 6, 0
0, 0, 44, 0, 0
1, 1, 0, 72, 0
0, 0, 0, 0, 9**
如果我们参照图 1,行代表集群,列代表类。聚类到第一个聚类并属于黄金标准中的第一类(第一行和第一列的交叉点)的对象的数量是 64。类似地,聚类到第一聚类并属于黄金标准中的第二类(第一行和第二列的交叉点)的对象的数量是 4。
请注意,每行和每列(64、37、44、72 和 9)的最大值可以在对角线中找到,这告诉我们第一个聚类对应于黄金标准中的第一类,第二个聚类对应于黄金标准中的第二类,依此类推。
聚集的对象总数将是 247 。
**Total number of objects clustered
=64+4+1+5+2+37+1+6+44+1+1+72+9
=247**
未聚类对象的数量将为 10 。
**Total number of unclustered objects
=257-247
=10**
现在,让我们使用这个矩阵来计算精确度、召回率和 F1 值。
**Precision
=(64+37+44+72+9)/(64+4+1+5+2+37+1+6+44+1+1+72+9)
=91.50%Recall
=(64+37+44+72+9)/(64+4+1+5+2+37+1+6+44+1+1+72+9+10)
=87.94%F1-score
=2*(91.50*87.94)/(91.50+87.94)
=89.68%**
案例 2: K
Let us assume a case where we have 5 classes in the gold standard and 4 clusters are predicted by the clustering method. We can see that two clusters have been combined (the third row with 44 and 9).
**~~64, 4, 1, 5, 0
2, 37, 1, 6, 0
0, 0, 44, 0, 9
1, 1, 0, 72, 0Total number clustered = 64+4+1+5+2+37+1+6+44+9+1+1+72 = 247
Total number unclustered = 257-247 = 10~~**
Now, let us calculate the precision, recall and F1-score using this matrix.
**~~Precision
=(64+37+44+72)/(64+4+1+5+2+37+1+6+44+9+1+1+72)
=87.85%Recall
=(64+37+44+72+9)/(64+4+1+5+2+37+1+6+44+9+1+1+72+10)
=87.94%F1-score
=2*(87.85*87.94)/(87.85+87.94)
=87.89%~~**
Case 3: K> S
让我们假设一种情况,其中我们在黄金标准中有 5 个类别,并且通过聚类方法预测了 6 个聚类。我们可以看到一个集群被拆分(第三行和第四行分别为 24 和 20)。
**~~64, 4, 1, 5, 0
2, 37, 1, 6, 0
0, 0, 24, 0, 0
0, 0, 20, 0, 0
1, 1, 0, 72, 0
0, 0, 0, 0, 9Total number clustered = 64+4+1+5+2+37+1+6+24+20+1+1+72+9 = 247
Total number unclustered = 257-247 = 10~~**
现在,让我们使用这个矩阵来计算精确度、召回率和 F1 值。
**~~Precision
=(64+37+24+20+72+9)/(64+4+1+5+2+37+1+6+24+20+1+1+72+9)
=91.50%Recall
=(64+37+24+72+9)/(64+4+1+5+2+37+1+6+24+20+1+1+72+9+10)
=80.16%F1-score
=2*(91.50*80.16)/(91.50+80.16)
=85.46%~~**
分析
让我们仔细检查一下从每个示例案例中获得的值,如图 6 所示。

图 6。精确度、召回率和 F1 分数值(图片由作者提供)
我们可以看到,如果聚类方法低估了聚类的数量(情况K<S),即将聚类组合在一起,并且这些聚类将包含多个黄金标准类,则精度会降低,但召回率仍与理想情况相同。这是因为,对于组合仓,在行(44)中将只考虑最大值。
类似地,如果聚类方法高估了聚类的数量(案例K>S),即分割实际聚类,黄金标准类由多个聚类表示,则召回率会降低,但精度仍与理想情况相同。这是因为,对于分离的箱,在列(24)中将只考虑最大值。
在K<S和K>S两种情况下,F1 分数随着精确度或召回率的降低而降低。
总的来说,我们可以看到,随着聚类方法预测的聚类数的增加,精确度增加,而召回率减少。
结束想法
我希望这篇文章对你的学习或研究工作有用。
我在下面附上了一个简单的脚本,你可以输入聚类结果和黄金标准,并获得精度,召回,F1 分数和 ARI 值。这个脚本接收 2 个.csv文件;一个用于聚类结果,另一个用于金标准。
您可以使用命令运行这个脚本,
**~~python evaluate.py --clustered clustering_result.csv --goldstandard gold_standard.csv~~**
这里 clustering_result.csv 和 gold_standard.csv 应该是object_id,cluster_id的格式。将打印精确度、召回率、F1 分数和 ARI 值。
感谢您的阅读!
干杯!
参考
[1] MetaCluster 5.0:一种用于噪声样本中低丰度物种的宏基因组数据的两轮宁滨方法。王等人。al 。生物信息学,第 28 卷,第 18 期,2012 年 9 月 15 日,i356–i362 页,DOI:https://doi.org/10.1093/bioinformatics/bts397
[2]宁滨宏基因组重叠群的覆盖范围和组成。阿尔内贝格 et。艾尔。《自然方法》2014 年第 11 卷,第 1144-1146 页,土井:https://doi.org/10.1038/nmeth.3103
[3]使用 dS2 寡核苷酸频率相异度改善宏基因组数据的重叠群宁滨。王等人。艾尔。 BMC 生物信息学 18(425),2017,DOI:https://doi.org/10.1186/s12859-017-1835-1
[4] GraphBin:使用组装图的宏基因组重叠群的精细宁滨。Mallawaarachchi 等人。艾尔。生物信息学,第 36 卷,第 11 期,2020 年 6 月,第 3307-3313 页,DOI:https://doi.org/10.1093/bioinformatics/btaa180
评估图像分割模型
不同评价方法的比较和对比

克里斯托夫·高尔在 Unsplash 上拍摄的照片
什么是图像分割?
图像分割是将数字图像划分成不同图像类别或对象的过程。这是自动驾驶汽车非常重要的一部分,因为正确检测汽车前方的物体以及它们的位置是自动驾驶算法的关键输入。

图像分割程序的输出示例。
图像分割模型是通过一个接受给定事实的神经网络创建的。基础事实是正确标记的图像,它告诉神经网络预期的输出是什么。

地面真实 vs .人物形象类的预测[ 站点
在图像分割被训练并输出预测之后,我们需要评估该模型执行得有多好。这通常是通过两种方式完成的,像素精度和交集超过并集 (或 IoU) 。
像素精度
这是评估图像分割模型性能的最简单方法。为此,我们必须首先计算真正值、真负值、假正值和假负值。要了解这些术语的更多含义,你可以阅读这篇文章。
在这种情况下,对于给定的类 X:
- 真阳性(TP): 像素被正确分类为 X
- 假阳性(FP): 像素被错误分类为 X
- 真阴性(TN): 像素被正确分类为非 X
- 假阴性(FN): 像素被错误分类为非 X
计算像素精度的公式为:

像素精度公式。
假设我们正在尝试计算以下 3x3 图像的像素精度。

在这种情况下, R 表示对应于道路等级的像素,而 S 对应于人行道等级。根据地面实况,我们在地面实况中有 3 个道路像素,所以 TP = 3 。没有任何人行道像素被标记为道路,因此 FP = 0 。对于顶部的两个角,模型将像素标记为人行道,而它应该是道路,因此 FN = 2 。最后,地面真相底部的 4 个人行道像素都被正确标记,因此 TN = 4 。

这种方法也可以在评估每一类的像素精度时全局使用。
出现了一个问题
像素精度存在问题,下图可以说明这一点:

照片由 Rowan Heuvel 在 Unsplash 上拍摄
如果我们想要计算鸟类的像素精度,即使我们完全错误地预测了鸟类的像素,因为我们图像中的大多数像素是天空,我们的 TN 值会非常高,从而使我们的像素精度非常高。

并集上的交集
这是评估来自图像分割模型的预测的另一种方法。该方法通过计算基础事实和预测之间的交集和并集来计算性能。
例如,让我们使用之前的图像:

事实与预测[ 地点
因此,现在我们要确定基本事实和预测之间的交集和联合,如下所示:

交叉点对联合[ 站点
然后,我们可以通过以下公式计算 IoU 值:

在实践中,如果我们想找到一个特定类的 IoU,我们必须首先计算所有正在验证的图像的#TP、#FP、#FN 的总和,然后用总和计算 IoU。
平均欠条(百万)
这也是一个度量标准,它采用所有类别的 IoU,并取其平均值。这是图像分割模型在该模型想要检测的所有类别上表现如何的良好指标。
结论
像素精度和 mIoU 是用于评估图像分割模型性能的最常见的两种方法。虽然像素精度是一种非常简单的编码方法,但它也会受到占用大部分图像的类的严重影响。mIoU 解决了这个问题,但在某些情况下,mIoU 的运行成本更高,或者编码更复杂。
评估机器学习模型
入门
如何理解一个 ML 模型是否真的在做你想要它做的事情

当构建模型的艰苦工作完成后,必须有人做出是否按下“go”并将模型放归自然的最终决定。对于数据科学家来说,这是一个至关重要的时刻,当他们发现他们是否会看到他们的工作起飞,或者是否会回到绘图板。对于决策者来说,这也是一个重要的过程,因为如果关键错误在事后才被发现,或者更糟的是根本没有被发现,错误地批准一个算法可能会导致中断和成本。
因此,理解做出该决定的关键因素对于开发算法的数据科学家和依赖这些算法的人都很重要。在这篇博客中,我们将讨论这个决定的一些关键组成部分,使用一个基于开源 IMDB 数据的模型。
设置场景
当理解一个模型时,上下文是最重要的,所以让我们花一些时间来勾画一下。比方说,我们的模型是应一位电影制片厂高管的要求建立的,这位高管对一系列缺乏光泽的电影评论感到失望。该模型背后的想法是,它将用于预测电影在推介时的评论分数,从而为电影委托团队提供更多关于批准或拒绝推介的信息。

Jakob Owens 在 Unsplash 上拍摄的照片
我们将使用 IMDB 用户评级作为我们模型的质量指南。这是一个由网站用户分配的评级,任何人都可以留下评级(暂且不考虑这是否是一个好的质量衡量标准!).经过几周的数据处理,我们的数据科学家使用随机森林回归模型向电影高管展示了一个模型。好到可以被团队使用吗?请继续阅读…
理解“准确性”
最自然的问题是这个模型有多精确。这个看似简单的问题可以通过多种方式来解决,很容易抛出大量的准确性度量标准,但仍然让涉众一无所知。这里有一些提示,可以帮助你和你的利益相关者理解你的模型的真正能力:
- 选择正确的准确性指标
- 可视化误差指标
- 选择一个相关的精度基准
- 开发直接针对模型环境的定制指标
- 调查数据集中的相关亚人群
1.选择正确的准确性指标
选择正确的度量标准是一个理解如何使用模型的问题。在我们的案例中:
- 是否所有的电影推介都将根据预测得分进行排名,前 X 名将获得批准?如果是这样,我们应该探索专门评估排名准确性的准确性指标
- 是不是所有超过某个预测分数的电影都会被批?当我们在处理一个更加二元的是/否批准阈值时,我们可能想把它看作是一个像科恩的 Kappa 或 F1 这样的 metics 的分类问题
- 让一些电影“正确”比其他电影更重要吗,比如根据预算规模?在这里,我们需要对模型进行加权,以对某些电影进行优先级排序,并且我们还需要报告准确性指标
- 这将有助于理解个人电影和各种电影投资组合的预测评论分数吗?在这种情况下,我们最感兴趣的是每部电影的点估计精度。
现在让我们假设最后一个选项最接近模型的使用方式。出于这个原因,我们将选择 R2,因为它能很好地反映个人预测与真实结果的接近程度。
2.可视化误差指标
现在我们已经选择了我们的误差度量,我们可以自信地告诉我们的涉众,我们模型的 R2 是 0.3(当然是在验证集上)。仅仅引用这些很难说到底发生了什么,所以可视化的度量可以给涉众一个更准确的触觉。对 R2 来说,最合理的可视化可能是散点图,如下图所示。
模型预测评级与验证集上的实际评级(2020 部电影)

模型预测评分对比验证集上的实际评分(2020 部电影)。“numVotes”表示构成平均评级的投票数,这让人们感受到投票数较少的电影的准确性如何变化
这告诉我们的不仅仅是简单的 R2 度量。首先,我们可以看到,虽然预测和实际结果之间肯定有关系,但任何给定的预测都有很多不确定性。
此外,我们还看到,在平均 5-7 分的评分附近,有一个预测“群聚”,这在实际结果中我们很少看到。这反映了模型缺乏预测能力:它没有足够的信息来区分高低,因此它在平均分数附近“猜测”结果,因为这将使它具有最小的 R2。这也意味着它通常会低估电影投资组合之间的平均评论评级差异,因为它会将好电影和坏电影的投资组合拉向平均值。
3.选择一个相关的精度基准
测试你的算法的最好方法是将它与如果你的算法没有被使用时的决策进行比较。在我们的案例中,与其向我们的电影委托团队推出一个复杂的模型,不如想出一个简单的启发,比如说:“电影评级将与该导演最近五部电影的评级平均值相似”。这很容易理解,任何有网络连接的人都可以快速评估。那么我们的算法表现如何呢?
在这种情况下,启发式算法给出的 R2 为 0.14,因此大约是我们模型的一半准确。这是个好消息,给了我们一些信心,我们的模型比更简单的方法更有价值。
4.开发直接针对模型上下文的定制指标
像 R2 和 RMSE 这样的标准模型准确性度量标准可能非常抽象,因此创建更具触觉性且与模型使用方式密切相关的度量标准通常很有价值。在这种情况下,一个好的指标是预测评级最高的前 100 部电影的平均实际评级,为 8.92。这更好,因为它给出了模型将实现的清晰的真实世界视图。
同样,我们可以将其与我们的基准试探法进行比较,后者给出了类似的值 8.13,因此我们的算法比这个指标好 0.79。这足以证明算法的推出是正确的吗?这可能取决于,但现在我们的电影专员可以在“如果我花必要的时间/精力让我的电影委托团队采用这一点,我的电影平均会获得 0.79 的高评级”之间进行权衡。
5.调查相关亚人群

照片由 Pexels 的 Caleb Oquendo 拍摄
在许多情况下,不仅需要评估总体准确性,还需要评估不同数据组或子部分的准确性。在我们的案例中,我们可能希望检查模型是否对男性或女性导演区别对待,这是一个常见的问题,我们的电影专员热衷于避免。看一下 R2,我们看到女性董事为 0.29,男性董事为 0.3,所以这个模型对这些人群来说似乎非常准确,这是个好消息。当然,这并不是偏见的全部,我们将在后面详细讨论。
现在我们已经很好地掌握了模型的精确度,让我们来了解一下它是如何更好地“思考”的。
模型如何做出决策
人们在这个阶段关闭是很常见的,特别是考虑到数据科学有点书呆子气的形象和许多算法被大肆宣传的“黑箱”性质。尽管很复杂,但是可以做很多事情来给非技术观众一个模型如何做决策的感觉。
首先,有一个特性重要性图。大多数 ML 包都提供了这种形式,这表明模型使用了多少变量来进行决策(在随机森林的情况下,当分割该特征时,该特征减少了多少杂质)。

模型使用 70 多项功能,因此仅限于前 20 项功能
在这里,我们看到一些预期的行为,和一些怪异。许多重要的功能与导演、作家或演员以前的电影评级有关,这是有意义的。然而,电影的长度似乎是模型中最重要的因素,这听起来不太对。让我们用一个部分依赖图来理解发生了什么:

在这里,我们可以看到问题可能是什么:似乎有两个“水平”的评论评分,一个是“短片”,即 10-30 分钟的迷你电影,另一个是更正常长度的功能。看起来,平均来说,短片比长篇故事片得到的评价更高。这很可能是一个真实的现象,短片吸引了不同的评论观众,人们喜欢更短的电影,或者一些看不见的功能在“短”电影类别中更普遍。虽然从表面上看,电影长度并没有直观地感觉到它应该会影响质量,所以我们可能会决定删除这个功能,前提是它不会严重影响准确性,这个决定可以与我们的电影专员讨论。
我们还可以检查一些其他的高影响特性,看看模型是否以合理的方式对待它们。让我们来看看下一个最重要的变量,导演最近 5 部电影的平均评级,以及演员最近 5 部电影的平均评级(根据演员在电影账单中的排名进行加权)。


这两者都给出了相当合理和直观的结果,演员和导演过去的评级越高,他们未来的电影就越有可能获得高评级。然而,仔细观察确实揭示了一些有趣的行为:可变影响呈 S 形,这意味着超过一定水平后,以前的良好评级就无关紧要了。对于导演最近的电影,这种影响的 S 曲线下降大多发生在数据很少的地方,但对于平均演员评级,我们看到相当多的电影发生在变量停止产生显著影响之后,这意味着超过 6.5-7 左右,它不会显著影响平均评级。糟糕的演员可以搞垮一部电影,但伟大的演员无法让一部平庸的电影变得伟大。
总之,我们的模型与我们之前计算的试探法没有什么不同,只是它考虑了更广泛的类似试探法,考虑了电影的长度(除非我们删除这个特征)。当然,人们可以在这里进入更多的细节,但这给了我们的电影专员一个很好的概述。
亲身展示例子
对于所有聪明的可视化和解释技术,除了通过一些例子展示模型的运行,让人们感受到它是如何工作的,通常没有什么可以替代的。
一个人在选择例子时应该小心,可能很容易想到“哦,这是一个奇怪的结果,让我们隐藏它”,但这是一个坏习惯。首先,在模型的实际表现上误导了涉众,但是也让自己暴露在以后的批评中:如果你预先展示了一些不好的结果,而模型仍然被批准,涉众不能说他们没有被警告。然而,如果您隐藏了不方便的结果,涉众可能会合理地问为什么他们只在同意部署模型后才看到奇怪的输出。
虽然在挑选例子时总是有一定的随机性,但如果只展示几个例子,使用完全盲目的随机选择可能不是最好的方法,因为它们不具有代表性的几率很高。相反,有更多值得讨论的引导方法。
首先,你可以挑选利益相关者可能熟悉的众所周知的例子,比如下面我从 2020 年最受欢迎的 50 部电影中随机挑选的。这有一个好处,利益相关者可以参与进来并发表意见,这意味着你更有可能获得有意义的反馈和你无法获得的背景知识。
或者,如果没有明显的例子,人们可以在某些类别中选择最有代表性的,例如“典型的”动作片或爱情片。如果类别不明显,可以使用聚类算法来识别数据中的子群体进行采样。这样做的好处是可以识别质心,从而使你能够从给定的聚类中选择最具数学代表性的例子。

从 2020 年 IMDB 上排名前 30 的电影中随机抽取,以投票数计。请注意,2020 年的所有电影都被作为模型的验证集
现在我们有了我们的例子,我们看到一些好的预测(“Da 5 血液”)和一些不太好的(“提取”)。虽然人们不能从这些图表中得出一般性的结论,但它们可以使之前图表中显示的一般性结论更加真实。
请注意,我已经把我们之前讨论过的启发式方法也放进去了,所以你可以看到它的预测性。这是有用的,因为我们看到,尽管模型在总体上优于启发式算法,但它并不总是优于启发式算法(例如,“Gretel & Hansel”、“Sonic”和“Extraction”)。虽然统计学家反复向他们灌输平均绩效改进并不能保证绩效改进,但几个例子可以帮助那些没有…呃…幸运的人明白这一点?…足以进行这种培训。
这个模型将如何影响周围的世界
利益相关者最关心的事情之一是模型会以何种方式改变他们的团队、系统或过程的运作。当一个模型进行优化时,它通常不会以中立的方式进行。更确切地说,模型旨在通过支持某些群体和不支持其他群体来改善特定的结果。因此,理解并向利益相关者传达可能的影响是很重要的。
例如,我们在特征重要性图中看到,该模型特别关注恐怖电影。这是否意味着他们可能会被算法所排斥?这可能是我们的电影专员理解的一个关键点,因为这可能意味着在使用这种模式时,较少的恐怖电影被制作出来。让我们更详细地了解一下导演的性别,以及我们之前提到的短片/完整版电影的区别:

在这里,我们看到这个模型并没有惩罚女性董事,尽管这些女性董事在数据中仍然代表不足。此外,在我们的模型中,恐怖电影表现得更好,而不是更差,所以这一点不用担心。
然而,在“短片”上,我们看到了更明显的影响,该模型已经确定短片通常比完整长度的电影获得更高的分数,因此实际上推动了这些类型的电影,甚至超过了我们在实际结果中看到的。这可能不是电影专员想要的,因此将是部署模型的关键考虑因素。一种选择可能是对短片和常规电影有单独的阈值或配额,一直到在输出中对短片和完整长度电影强制类似的分数分布。
人们可以用任何一组指标或特性来做到这一点。这里的技巧是确定哪些输出特征与模型上下文相关,以及涉众可能对什么感兴趣。
摘要

决定决定(照片由TAHA·AJMI在 Unsplash 上拍摄)
希望你现在已经很好的理解了这个模型是如何运作的,以及你是否想在野外使用它。这里没有正确的答案,这是一个收益有多大价值以及如何权衡推出这种模型的复杂性和后果的问题(作者倾向于启发式方法,因为它更简单,性能也不会差太多)。
这里最重要的一点不是关于电影或这个特定的模型,而是关于向非技术利益相关者解释模型的步骤和方法,以及当 ML 模型呈现给你时,作为利益相关者应该问的正确问题。概括一下:
- 选择正确的误差指标,将它们可视化,不要害怕在测量准确性的方式上有所创新
- 使用可变重要性和部分相关图等技术来感受模型是如何“思考”的
- 使用例子,在选择这些例子时要小心公平
- 仔细思考并举例说明该模型将如何影响它所部署到的系统
随着人工智能越来越多地融入到我们的生活和职业环境中,人们必须学会对这些算法提出正确的问题,以确保它们真正增加价值,而不是在表面下造成意想不到的伤害。伟大的数据科学经常使用黑盒算法,但永远不应该是黑盒。
进一步阅读
如果你有兴趣进一步探索这些想法,我强烈推荐下面的一些论文和博客,因为它们是作者写这篇博客时从中获得灵感的文献样本。
模型卡(Timnit Gebru et。艾尔。)https://arxiv.org/abs/1810.03993和https://modelcards.withgoogle.com/about
卡西·科济尔科夫谈 AI 为什么会犯错:【https://towardsdatascience.com/dont-trust-ai-10a7df520925
TWIML 人工智能博客上关于人工智能可解释性的大讨论:https://open.spotify.com/episode/2n7PVTEcoQMish70AYoHY4?si=k6PwmW7USSOkx2HtYjQVQg
可解释机器学习综合指南(Christoph Molnar)https://christophm.github.io/interpretable-ml-book/
评估对象检测模型的性能
什么是地图?如何评价一个物体检测模型的性能?
在本文中,您将了解如何使用 mAP 来评估对象检测模型的性能。什么是地图?如何用 11 点插值计算 mAP?

对象检测和实例分割
我们使用机器学习和深度学习来解决回归或分类问题。
我们使用均方根(RMS)或平均百分比误差(MAPE)等。评估回归模型的性能。
使用准确度、精确度、召回率或 F1 分数来评估分类模型。
是物体检测、分类还是回归问题?
存在多种深度学习算法用于对象检测,如 RCNN:快速 RCNN、更快 RCNN、YOLO、掩模 RCNN 等。
目标物体检测模型是为了
- 分类:识别图像中是否存在物体以及物体的类别
- 定位:当图像中存在物体时,预测物体周围边界框的坐标。这里我们比较地面真实和预测边界框的坐标
我们需要评估在图像中使用包围盒的分类和定位的性能
我们如何衡量物体检测模型的性能?
对于对象检测,我们使用并集上的交集(IoU)的概念。IoU 计算两个边界框的并集上的交集;地面真实的边界框和预测的边界框

红色是真实边界框,绿色是预测边界框
IoU 为 1 意味着预测边界框和实际边界框完全重叠。
您可以为 IoU 设置一个阈值,以确定对象检测是否有效。
假设您将 IoU 设置为 0.5,在这种情况下
- 如果 IoU ≥0.5,将物体检测分类为真阳性(TP)
- 如果 Iou <为 0.5 ,那么这是一次错误检测,将其归类为假阳性(FP)
- 当图像中存在地面真实且模型未能检测到物体时,将其归类为假阴性(FN)。
- 真阴性(TN ): TN 是图像中我们没有预测到物体的每个部分。这个度量对于对象检测没有用,因此我们忽略 TN。
将 IoU 阈值设置为 0.5 或更大。可以设置为 0.5,0.75。0.9 或 0.95 等。
使用精确度和召回率作为评估性能的指标。使用真阳性(TP)、假阳性(FP)和假阴性(FN)来计算精确度和召回率。

计算图像中所有对象的精度和召回率。
您还需要考虑图像中模型检测到的每个对象的置信度得分。考虑置信度得分高于某个阈值的所有预测边界框。高于阈值的边界框被认为是正边界框,低于阈值的所有预测边界框被认为是负边界框。
使用 11 点插值平均精度计算平均平均精度(mAP)
如何使用 11 点插值计算地图?
第一步:绘图精度和召回
在精确度召回(PR)图上绘制精确度和召回值。PR 图是单调递减的,在精确度和召回率之间总是有一个权衡。增加一个会减少另一个。有时,由于某些例外和/或缺乏数据,PR 图并不总是单调递减的。

第二步:计算平均精度(mAP),使用 11 点插值技术。
如上图所示,插值精度是在 0.0、0.1、0.2、0.3…0.9、1.0 等 11 个等距召回级别上测得的平均精度。
PR 图有时可能不是单调递减的,为了解决这个问题,我们为 recall 值设置了最大精度。从图形上看,在每个召回级别,我们用该召回级别右侧的最大精度值替换每个精度值,即:我们取所有未来点的最大值
基本原理是,如果精度和召回率都变得更好,人们愿意考虑更高的精度值。
最后计算测试集中每个信息在每个召回级别的插值精度的算术平均值。
mAP 总是在整个数据集上进行计算。
让我们以如下所示的例子来理解,召回值被排序,以便我们绘制 PR 图

样本精度和召回值
11 点插值将使用召回值精度的最高值。
我们创造了 11 个等间隔的回忆水平,分别是 0.0,0.1,0.2,0.3…0.9,1.0。
0.2 的召回具有最高精度值 1.00。0.4 的召回值具有不同的精度值 0.4、0.67、0.5。在这种情况下,我们使用最高精度值 0.67。当精度值为 0.6 时,我们的精度值为 0.5,但是对于 0.8 的召回,我们看到更高的精度值 0.57。基于 11 点插值的基本原理,我们取所有未来点的最大值,因此我们需要考虑的精度是 0.57,而不是 0.5。最后,对于 1.0 的召回,我们取最大精度 0.5。

现在绘制精度召回和插值精度。

我们最后应用平均精度公式

AP = 1/11(4 * 1.0+2 * 0.67+4 * 0.57+1 * 0.5)= 0.74
这给出了使用 11 点插值的平均精度
用于计算 Pascal VOC 数据格式地图的 Python 代码
Pascal VOC 边界框由(x-左上,y-左上,x-右下,y-右下 ) 定义
#GT Boxes
gt_boxes= {"img_00285.png": [[480, 457, 515, 529], [637, 435, 676, 536]]}#Pred Boxes
pred_boxs={"img_00285.png": {"boxes": [[330, 463, 387, 505], [356, 456, 391, 521], [420, 433, 451, 498], [328, 465, 403, 540], [480, 477, 508, 522], [357, 460, 417, 537], [344, 459, 389, 493], [485, 459, 503, 511], [336, 463, 362, 496], [468, 435, 520, 521], [357, 458, 382, 485], [649, 479, 670, 531], [484, 455, 514, 519], [641, 439, 670, 532]], "scores": [0.0739, 0.0843, 0.091, 0.1008, 0.1012, 0.1058, 0.1243, 0.1266, 0.1342, 0.1618, 0.2452, 0.8505, 0.9113, 0.972]}}
导入所需的库
import numpy as np
from copy import deepcopy
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
创建图像 id 和置信度得分的字典
**def get_model_scores(pred_boxes):**
"""Creates a dictionary of from model_scores to image ids.
Args:
pred_boxes (dict): dict of dicts of 'boxes' and 'scores'
Returns:
dict: keys are model_scores and values are image ids (usually filenames)
"""
model_score={}
for img_id, val in pred_boxes.items():
for score in val['scores']:
if score not in model_score.keys():
model_score[score]=[img_id]
else:
model_score[score].append(img_id)
return model_score
计算 Pascal VOC 格式边界框的 IoU

Pascal VOC 边界框
**def calc_iou( gt_bbox, pred_bbox)**:
'''
This function takes the predicted bounding box and ground truth bounding box and
return the IoU ratio
'''
**x_topleft_gt, y_topleft_gt, x_bottomright_gt, y_bottomright_gt= gt_bbox**
**x_topleft_p, y_topleft_p, x_bottomright_p, y_bottomright_p= pred_bbox**
if (x_topleft_gt > x_bottomright_gt) or (y_topleft_gt> y_bottomright_gt):
raise AssertionError("Ground Truth Bounding Box is not correct")
if (x_topleft_p > x_bottomright_p) or (y_topleft_p> y_bottomright_p):
raise AssertionError("Predicted Bounding Box is not correct",x_topleft_p, x_bottomright_p,y_topleft_p,y_bottomright_gt)
#if the GT bbox and predcited BBox do not overlap then iou=0
if(x_bottomright_gt< x_topleft_p):
# If bottom right of x-coordinate GT bbox is less than or above the top left of x coordinate of the predicted BBox
return 0.0
if(y_bottomright_gt< y_topleft_p): # If bottom right of y-coordinate GT bbox is less than or above the top left of y coordinate of the predicted BBox
return 0.0
if(x_topleft_gt> x_bottomright_p): # If bottom right of x-coordinate GT bbox is greater than or below the bottom right of x coordinate of the predcited BBox
return 0.0
if(y_topleft_gt> y_bottomright_p): # If bottom right of y-coordinate GT bbox is greater than or below the bottom right of y coordinate of the predcited BBox
return 0.0
**GT_bbox_area = (x_bottomright_gt - x_topleft_gt + 1) * ( y_bottomright_gt -y_topleft_gt + 1)**
** Pred_bbox_area =(x_bottomright_p - x_topleft_p + 1 ) * ( y_bottomright_p -y_topleft_p + 1)**
**x_top_left =np.max([x_topleft_gt, x_topleft_p])
y_top_left = np.max([y_topleft_gt, y_topleft_p])
x_bottom_right = np.min([x_bottomright_gt, x_bottomright_p])
y_bottom_right = np.min([y_bottomright_gt, y_bottomright_p])**
**intersection_area = (x_bottom_right- x_top_left + 1) * (y_bottom_right-y_top_left + 1)**
**union_area = (GT_bbox_area + Pred_bbox_area - intersection_area)**
**return intersection_area/union_area**
计算精度和召回
**def calc_precision_recall(image_results):**
"""Calculates precision and recall from the set of images
Args:
img_results (dict): dictionary formatted like:
{
'img_id1': {'true_pos': int, 'false_pos': int, 'false_neg': int},
'img_id2': ...
...
}
Returns:
tuple: of floats of (precision, recall)
"""
true_positive=0
false_positive=0
false_negative=0
**for img_id, res in image_results.items():**
**true_positive +=res['true_positive']
false_positive += res['false_positive']
false_negative += res['false_negative']**
try:
**precision = true_positive/(true_positive+ false_positive)**
except ZeroDivisionError:
precision=0.0
try:
**recall = true_positive/(true_positive + false_negative)**
except ZeroDivisionError:
recall=0.0
return (precision, recall)
返回单个图像的一批边界框的真阳性、假阳性和假阴性。
**def get_single_image_results(gt_boxes, pred_boxes, iou_thr):**
"""Calculates number of true_pos, false_pos, false_neg from single batch of boxes.
Args:
gt_boxes (list of list of floats): list of locations of ground truth
objects as [xmin, ymin, xmax, ymax]
pred_boxes (dict): dict of dicts of 'boxes' (formatted like `gt_boxes`)
and 'scores'
iou_thr (float): value of IoU to consider as threshold for a
true prediction.
Returns:
dict: true positives (int), false positives (int), false negatives (int)
"""
all_pred_indices= range(len(pred_boxes))
all_gt_indices=range(len(gt_boxes))
if len(all_pred_indices)==0:
tp=0
fp=0
fn=0
return {'true_positive':tp, 'false_positive':fp, 'false_negative':fn}
if len(all_gt_indices)==0:
tp=0
fp=0
fn=0
return {'true_positive':tp, 'false_positive':fp, 'false_negative':fn}
gt_idx_thr=[]
pred_idx_thr=[]
ious=[]
**for ipb, pred_box in enumerate(pred_boxes):
for igb, gt_box in enumerate(gt_boxes):
iou= calc_iou(gt_box, pred_box)**
** if iou >iou_thr**:
gt_idx_thr.append(igb)
pred_idx_thr.append(ipb)
ious.append(iou)
**iou_sort = np.argsort(ious)[::1]**
if len(iou_sort)==0:
tp=0
fp=0
fn=0
return {'true_positive':tp, 'false_positive':fp, 'false_negative':fn}
else:
gt_match_idx=[]
pred_match_idx=[]
**for idx in iou_sort:
gt_idx=gt_idx_thr[idx]
pr_idx= pred_idx_thr[idx]**
# If the boxes are unmatched, add them to matches
**if(gt_idx not in gt_match_idx) and (pr_idx not in pred_match_idx)**:
**gt_match_idx.append(gt_idx)
pred_match_idx.append(pr_idx)**
**tp= len(gt_match_idx)
fp= len(pred_boxes) - len(pred_match_idx)
fn = len(gt_boxes) - len(gt_match_idx)**
**return {'true_positive': tp, 'false_positive': fp, 'false_negative': fn}**
最后使用 11 点插值技术计算地图。您可以在此指定 IoU 阈值,否则将使用默认值 0.5
**def get_avg_precision_at_iou(gt_boxes, pred_bb, iou_thr=0.5):**
** model_scores = get_model_scores(pred_bb)**
sorted_model_scores= sorted(model_scores.keys())# Sort the predicted boxes in descending order (lowest scoring boxes first):
for img_id in pred_bb.keys():
arg_sort = np.argsort(pred_bb[img_id]['scores'])
pred_bb[img_id]['scores'] = np.array(pred_bb[img_id]['scores'])[arg_sort].tolist()
pred_bb[img_id]['boxes'] = np.array(pred_bb[img_id]['boxes'])[arg_sort].tolist()pred_boxes_pruned = deepcopy(pred_bb)
precisions = []
recalls = []
model_thrs = []
img_results = {}# Loop over model score thresholds and calculate precision, recall
for ithr, model_score_thr in enumerate(sorted_model_scores[:-1]):
# On first iteration, define img_results for the first time:
print("Mode score : ", model_score_thr)
img_ids = gt_boxes.keys() if ithr == 0 else model_scores[model_score_thr]for img_id in img_ids:
gt_boxes_img = gt_boxes[img_id]
box_scores = pred_boxes_pruned[img_id]['scores']
start_idx = 0
for score in box_scores:
if score <= model_score_thr:
pred_boxes_pruned[img_id]
start_idx += 1
else:
break
# Remove boxes, scores of lower than threshold scores:
pred_boxes_pruned[img_id]['scores']= pred_boxes_pruned[img_id]['scores'][start_idx:]
pred_boxes_pruned[img_id]['boxes']= pred_boxes_pruned[img_id]['boxes'][start_idx:]# Recalculate image results for this image
print(img_id)
img_results[img_id] = get_single_image_results(gt_boxes_img, pred_boxes_pruned[img_id]['boxes'], iou_thr=0.5)# calculate precision and recall
prec, rec = calc_precision_recall(img_results)
precisions.append(prec)
recalls.append(rec)
model_thrs.append(model_score_thr)precisions = np.array(precisions)
recalls = np.array(recalls)
prec_at_rec = []
for recall_level in np.linspace(0.0, 1.0, 11):
try:
args= np.argwhere(recalls>recall_level).flatten()
prec= max(precisions[args])
print(recalls,"Recall")
print( recall_level,"Recall Level")
print( args, "Args")
print( prec, "precision")
except ValueError:
prec=0.0
prec_at_rec.append(prec)
avg_prec = np.mean(prec_at_rec)
return {
'avg_prec': avg_prec,
'precisions': precisions,
'recalls': recalls,
'model_thrs': model_thrs}
参考文献:
下一节:评估相关性上一节:信息检索中的评估上一节:未分级检索内容的评估…
nlp.stanford.edu](https://nlp.stanford.edu/IR-book/html/htmledition/evaluation-of-ranked-retrieval-results-1.html#tab:11-point)
https://www . cl . cam . AC . uk/teaching/1415/infor trv/lecture 5 . pdf
评估模型的性能
你的逻辑回归或分类模型有多有效?

在完成了一些逻辑回归和二元分类的数据科学项目后,我决定写更多关于评估我们的模型和采取步骤以确保它们高效准确地运行的内容。你可能有“好”的数据并且知道如何建立模型,但是如果你能够解释你的模型的效率,你就能够解释你的结果并且提供最终的商业决策!

图片来源:【giphy.com
使用回归,我们预测连续变量,因此将误差作为我们的估计有多远的距离来讨论是有意义的。对于分类问题,我们正在处理二元变量,所以我们的模型不是对就是错。因此,当评估分类算法的性能时,我们检查一些特定的测量。
评估指标
- 精度 —衡量预测的精度。
- 回忆 — 表示我们感兴趣的类中有多少百分比被模型实际捕获。
- 准确度 大概是最直观的度量。我们用它来衡量一个模型正确预测的总数,包括真正的正面和真正的负面。
- F1 分数是一个度量,它同时考虑了精确度和召回率来计算分数。它可以被解释为精度和召回值的加权平均值,并且在精度和召回值都不高的情况下不可能高。当一个模特的 F1 分数很高时,你知道你的模特在各方面都做得很好。
示例:预测某个员工是否被聘用(活动)。在这个项目中,我们理想地预测候选人是否适合公司。
Precision: “在模型显示有人被雇佣的所有次数中,有多少次被讨论的雇员实际上在“牙科魔术”工作?"
回想一下:“在我们看到的所有实际被雇佣的员工中,我们的模型正确识别出他们中有多少人是在职的?”
精确度和召回率成反比关系。一个上升,另一个就会下降。
精确比回忆好吗?
这是一个经典的数据科学问题。什么是更好的假阳性或假阴性?答案是“视问题而定”,可以测试你的批判性思维能力。让我们来看一个新的例子。
检测信用卡欺诈,假阳性将是当我们的模型将交易标记为欺诈,但它不是。这导致了一个稍微恼火的顾客。假阴性可能是一种欺诈性交易,一家公司错误地将其视为正常的消费者行为。在这种情况下,信用卡公司可能会因为错过交易欺诈的迹象而向客户偿还数千美元而陷入困境!尽管错误从来都不是理想的,但信用卡公司倾向于将他们的模型构建得有点过于敏感是有道理的,因为高召回率比高精度分数能为他们节省更多的钱。
让我们来分析一下我们的 HR 例子。我们的模型想要预测一个人是否适合“受雇与未受雇”的公司。在这种情况下,我们希望两者都很低:假阴性和假阳性。作为一名人力资源员工,我们希望误报率高于漏报率,原因如下。由于误报率较高,我们的模型预测我们的候选人非常适合,而实际上他们并不适合…这只是候选人的第一轮面试扫描,我们宁愿浏览更多的简历,也不愿错过一个潜在的优秀候选人。最终的雇佣决定来自一个人的最终决定。
受试者工作特征曲线
在评估模型时,我们希望可视化 ROC 曲线。说明了我们的分类器的真阳性率与假阳性率。真实阳性率是回忆的另一个名称,它是真实阳性预测与所有实际阳性值的比率。
- TPR = TP/(TP+FN)
假阳性率是假阳性预测与实际为阴性的所有值的比率。
- FPR = FP/(FP+TN)
如果 TPR 是我们的 y 轴,FPR 是我们的 x 轴,我们希望我们的 ROC 曲线紧靠图表的左侧,这意味着 TPR 越高,FPR 越低。

图片来源:测量性能参考
判别边界
逻辑回归模型产生每个观察的特定类的概率。想象它如下图所示:

图片来源:统计学习入门。加雷思·詹姆斯 特雷弗·哈斯蒂 罗伯特·蒂布拉尼 丹妮拉·威滕
如果我们改变截止点,将会牺牲精度,增加 FPR 以增加 TPR,反之亦然。将判定边界从 0.5 向左移动将导致捕获更多的正类(1)情况。它还会拾取一些假阳性(在阴性(0)病例分布的最右边的红色病例)。
ROC 较差的模型在两个类别的概率估计中可能有很大的重叠。这将表明我们的模型很难将这两个类分开。
让我们看一个例子:
*#Import roc_curve, auc*
from sklearn.metrics import roc_curve, auc*#Calculate the probability scores of each point in the training set*
**y_train_score** = model_log.decision_function(X_train)*# Calculate the fpr, tpr, and thresholds for the training set*
**train_fpr, train_tpr, thresholds** = roc_curve(y_train, y_train_score)*#Calculate the probability scores of each point in the test set*
**y_test_score** = model_log.decision_function(X_test)*#Calculate the fpr, tpr, and thresholds for the test set*
**test_fpr, test_tpr, test_thresholds** = roc_curve(y_test, y_test_score)
使用 Matplotlib,我们希望可视化我们的 ROC 曲线:
plt.plot(test_fpr, test_tpr, color='darkorange', lw=lw, label='ROC curve')

图片来源:米歇尔维纳布尔斯— Github/HR_Project
如左图所示,您可以看到我们的分类模型 TPR vs FPR。想一想这个模型的场景:预测员工在公司内的适合度。如果您将当前模型调整为具有 76%的真阳性率(您仍然错过了 29%的合适者),那么假阳性率是多少?
当 TPR = 75%时,FPR 为 22%。真实阳性率决定了被正确识别为合适的在职员工的百分比。同时,这有一个接近 0.25 的 FPR,这意味着大约有四分之一的情况下,我们错误地警告一个员工是一个很好的人选,而他们实际上表现不佳。
测试 AUC : 0.8041
分类器的总体准确性可以通过 AUC(曲线下的面积)来量化。完美的分类器将具有 1.0 的 AUC 分数,而 0.5 的 AUC 毫无价值。这里我们有 0.80 的 AUC,这似乎是准确的。
参考资料:
评估推荐引擎
解释来自混淆矩阵的度量
我最近被要求为一个数字活动过滤邮件列表。邮件列表有 40k+强,如果邮件发送到整个列表,那么退订的机会将会很高,因为电子邮件被发送给那些可能对产品不感兴趣的人。
此外,打开率和点击率也不是一个好的销售指标,因为电子邮件会被“错误的”人阅读和点击。举个例子,如果我收到一封关于最新法拉利的电子邮件,我很可能会打开邮件,阅读它,甚至点击“立即购买”链接,但只是为了查看价格,而不是实际购买。在这种情况下,打开率和点击率会因为我的动作而增加,但这是一个嘈杂的指标。因此,过滤掉邮件列表,只向目标少数群体发送广告的重要性就显现出来了。
方法学
为了推荐活动的最终电子邮件 id 列表,我获得了每个客户对公司销售的所有产品的购买历史记录,将其划分为特定的产品类别,并用阈值将数据二进制化,即创建一个客户与产品的矩阵,1 表示客户之前购买了超过一定金额的产品,否则为 0。这种方法背后的直觉是,有类似需求的客户很可能已经购买了类似的产品。基于这些数据构建了不同的模型,并为每个客户提供了 5、10、15 和 20 个建议。然后根据给定产品推荐给谁来编辑邮件列表。
推荐引擎
数据集以 80:20 的比例分为训练和测试;以下模型使用 80%的数据进行训练,并使用剩余的 20%进行测试。
- 随机模型:一组随机建议,目的是测试其他机器学习算法的性能。
- 基于项目的协同过滤(IBCF):根据购买过类似产品的人推荐产品
- 基于用户的协同过滤(UBCF):根据客户的相似性推荐产品。即计算客户之间的“距离”,并根据类似客户购买的产品为给定客户提供推荐。
- 关联规则使用市场篮分析来寻找最可能的产品组合。在此基础上,根据每位顾客已经购买的商品向其推荐产品。
- 流行模型推荐是基于一个项目在数据集中的“流行”程度。购买产品的客户越多,向没有购买该产品的客户推荐该产品的可能性就越大。
混淆矩阵
如果客户购买了模型推荐的产品,则它被标记为真阳性。如果客户没有购买模型推荐的产品,那么它将被标记为误报,以此类推。生成了混淆矩阵,并计算了各种度量来评估模型。

回忆 (TPR = TP / AP)以测量模型从整个列表中正确推荐的电子邮件 id 的比例,即模型正确识别的实际阳性类别的比例。
精度 (PPV = TP / PP)检查推荐的精度,即。推荐邮件列表中正确的电子邮件 id 的比例,即在所有将收到该电子邮件的人中,有多少人会真正发现它有用。
掉出 (FPR = FP / AN)来衡量模型错误推荐的邮件 id 比例。随着这一指标的增加,取消订阅的机会也将增加,因为电子邮件将被发送到大量不应接收该电子邮件的电子邮件 id。
特异性 (TNR = TN / AN)衡量模型从邮件列表中正确忽略的电子邮件 id 的比例,从而降低退订风险。它还表明有多少“噪音”已经从推荐中去除,这将对如何解释电子邮件的点击率和打开率产生影响。
阴性预测值 (NPV = TN / PN)用于衡量被正确排除的电子邮件 id 的比例,但这里的分母是预测的阴性类别(与特异性不同,在特异性中,分母是实际的阴性)。换句话说,这是模型归类为负面的电子邮件 id 的比例。
遗漏率 (FNR = FN / AP)或模型遗漏推荐的邮件 id 比例。这些是应该包括在内的电子邮件 id,但模型错误地排除在最终的建议列表之外,即模型错过了多大的机会。
错误发现 (FDR = FP / PP)或模型错误推荐的比例。这类似于 Fall Out -指标越大,退订的几率越高,因为电子邮件是发给那些可能对产品不感兴趣的人的。
假遗漏率 (FOR = FN / PN)衡量所有被遗漏但本应包含在邮件列表中的人的比例。这和漏失率差不多;指标越大,模型错过的机会就越多。然而,这里的分母是预测的负类,不像漏失率,分母是实际的负类。
准确率 (TP + TN / n)或者模型正确做出的推荐和遗漏的比例。这是最常用的指标,但是在某些情况下,优化上面提到的其他指标可能会更好。
平衡准确度 (TPR + TNR / 2)或者召回率和特异性的平均值,或者正确包含和正确省略的平均比例。度量标准的选择通常取决于练习的目的。在大多数情况下,需要考虑不止一个指标,通常不超过 2 或 3 个。
模型评估
模型的性能如下所示。我在红绿标度上使用了条件格式来表示每个度量中哪些是性能更好的模型。(为了保护公司数据,所有数字都统一减少了,即实际数字都高于下面显示的数字)

以下是一些观察结果:
- 很明显,所有模型的性能都优于随机推荐模型,并且在构建这些模型上花费的时间是合理的。
- 虽然流行的模型有最多的绿色单元,但它可能是也可能不是最适合当前目标的。答案将取决于所提建议的质量。稍后将详细介绍。
- 基于项目的协同过滤仅在落点和特异性测量中表现良好,因此其在准确性测量上的性能也有所提高。因此,除非必须发送电子邮件营销活动*,并且没有行动号召,否则这种模式可能不是最合适的。在这种情况下,该模型将确保退订率得到控制。如果每个产品的更多属性被考虑到模型中,基于项目的 CF 可能会有所改进。
模型的选择归结为基于用户的 CF、关联规则和流行。为了选择模型,我们查看了每个模型提出的建议,如下表所示。

- 受欢迎的型号已经向过去没有购买过该产品的人推荐了该产品。这可能不是推荐产品的最合适的方法。
- Associative Rules 已经向之前购买并退回该产品的人推荐了该产品。这些客户被基于用户的 CF 和流行模型正确地忽略了。因此,除非活动的目标是向上销售产品,否则关联规则可以放在一边。
这给我们留下了基于用户的协同过滤,它给出了大约一万个客户的邮件列表。
活动评估
邮件将于本月晚些时候发出,并由测试和控制小组进行评估。将考虑的主要指标是电子邮件的打开和点击,以及模型推荐的客户与收到电子邮件但模型不推荐的客户相比的退订率。
如果该模式成立,那么这种方法也将用于其他数字活动,我们希望看到对网站参与度(包括网站访问量和 PDF 下载量)和销售额的积极影响。
如果您有任何意见或反馈,或其他评估推荐引擎的方法,请使用下面的评论部分。

约翰·戈迪内斯在 Unsplash 上拍摄的照片
使用 NLP 评估 2020 年 NFL 选秀课程
自然语言处理(NLP)用于识别运动员身上最突出的品质,并确定每个运动员被谈论的程度。

摄影:SNIllustration/Getty Images
在 3 周的时间里,全美橄榄球联盟的球队将决定谁将是未来的球队。为了这一夜,我们投入了数小时的工作,以确保球队能选出所需的合适球员。NFL 选秀是非常不可预测的,球队选秀时没有人看到球员来到球队进行交易,试图在选秀中获得一名运动员,他将成为选秀的抢手货。2017 年,芝加哥熊队抓住了这个机会,给了旧金山 49 人队 4 个选秀权,以提升到第二顺位,他们选中了米切尔·特鲁比斯基(他们认为会是抢断的球员)。几个选秀权之后,一个叫帕特里克·马霍斯的四分卫被拿下了。回到今天,Patrick Mahomes 是 MVP,超级碗冠军四分卫,而 Trubisky 正在芝加哥争夺首发位置。征兵有时会非常残酷。
模拟草稿和 NLP
选秀中的大学生球员被放在显微镜下观察,并被球探部门一路分析,直到选秀之夜。因为这是足球界最重要的夜晚之一,许多足球分析家写下他们对这些球员的评论,并制作模拟草稿来模拟他们认为选秀会如何进行。分析师的观点往往是相互矛盾的,那么你信任哪一个来评价某个球员呢?全部都用怎么样。使用自然语言处理(NLP),我们将使用所有可以找到的分析评论和模拟草稿来评估顶级草稿前景。
评估#1:是什么让运动员脱颖而出
选秀中的每个运动员都有独特的品质。这些品质在战场上展示出来时,常常被分析家们所称赞。因此,结合使用分析师评论和模拟草案,我们将找到使每个运动员脱颖而出的品质。为了做到这一点,NLP 将被用来找到在评论中出现最多的品质。

让蔡斯·杨脱颖而出的一点是,与他位置上的其他球员相比,他的力量
出于数据科学的目的,自然语言处理通常用于语音和文本。它变得越来越受欢迎,最明显的形式是 Siri、谷歌家园和亚马逊回声。这导致了许多库的创建,我们可以用它们来使 NLP 更容易编码。一个非常重要的库是 NLTK 库。这个库有能力阅读一个句子,并确定哪些单词是名词、形容词、动词等。这对我们来说很重要,因为我们不想要任何词语,我们想要描述每个运动员和他们比赛风格的词语。这就是为什么评论中只保留形容词和动词的原因。
为了找出这些单词中哪一个出现得最多,每个运动员都使用一个简单的字典。字典中的关键值是所有评论中的唯一单词,这些值是这些单词出现的频率。单词云将用于可视化这些品质,单词越大,出现的频率越高。
单词云
1.追逐年轻,边缘

蔡斯·杨无疑是选秀中最好的防守球员。只是在云这个词里看到了一些让他成为最优秀的品质。年轻是一个强大的冲锋派。他控球出色,是一名出色的组合型球员,擅长跑位和传球。分析师们也看到了这一点,因为在他们的分析中,这些关键词经常被用来描述杨,导致这些关键词成为他的一些顶级品质,使他脱颖而出。
2.QB 乔·伯罗

也许是大学橄榄球历史上最伟大的四分卫赛季。乔·伯罗被一致认为是选秀中的第一顺位。他所拥有的使他成为一名优秀传球手的品质包括他高超的准确性,出色的口袋表现,以及他在比赛中面对艰难情况下的压力的能力。这在之前的全国冠军赛中出现过,当时伯罗将带领路易斯安那州立大学赢得全国冠军。
通过发现球员分析中最常见的特征,你甚至不用看就能对球员的实力有一个很好的了解。例如,下面列出了在选秀中用来描述一些顶级潜在客户的最常用词。仅仅通过观察描述每个球员的一两个词,你就能了解那个球员是什么样的。

评估#2:利大于弊吗
对大学生运动员的每一项分析都包括他们的优势和劣势。这很好地评估了运动员在赛场上是资产还是负债,这也是我们进一步评估这些运动员的方法。
情感分析是指使用自然语言处理和文本分析来识别主观信息。一个广泛使用的情感分析的例子是垃圾邮件检测。当您收到带有与垃圾邮件相关的关键字的电子邮件时,垃圾邮件检测会将该电子邮件归类为垃圾邮件,并将其放入垃圾邮件文件夹。对情绪分析的基本理解就是我们如何评估这些运动员。鉴于他们的评论,我们将创建一个模型,输出对运动员的评论是积极的而不是消极的概率。概率越高,运动员被谈论的话题就越多。
模型
该模型将是用于分类的逻辑回归模型。这个模型的输入是每个运动员的所有评论。为了确定评论的积极程度或消极程度,该模型将在足球的多个利弊评论上进行训练。实际上,所有的肯定句都用 1 表示,否定句用 0 表示。然后,该模型将评估哪些词对正面评论的反应最大,哪些词对负面评论的反应最大。下面的单词列表是正面/负面评论的最大单词指示器。数字越高,这个词的影响力越大。

在模型被训练之后,我们现在可以将我们的运动员和他们的评论输入到模型中,以真实地查看他们的优点是否超过他们的缺点。

模型的输出
分析
计划参加第一轮选秀的 20 名运动员被输入到模型中。输出是他们各自的正面评论比负面评论多的概率。这些结果是我们从一些最好的大学生运动员那里得到的。大多数可能性非常高,因为这些运动员是他们级别中的佼佼者,他们的优势远远超过他们的劣势。然而,在这个列表中有一些惊喜。首先,概率排名最高的运动员不是蔡斯·杨或乔·伯罗,而是特里斯坦·沃夫斯,他是爱荷华大学的一名进攻型铲球手。回顾他的一些评论,他得到了很高的评价,很少有人批评他的进攻铲球。其次,也许是最令人惊讶的是,乔·伯罗甚至不是这份名单上评价最高的四分卫。阿拉巴马州的四分卫图阿·塔戈瓦洛亚。图阿已经为 NFL 做好准备有一段时间了,作为阿拉巴马州的领导者,是他被积极谈论的一个主要原因。另一方面,陋居度过了不可思议的一年,而不是几年。由于他是预计的第一顺位,人们自然会谈论他缺乏什么,导致他的概率低于图阿。在我看来,陋居比图阿更好,但也许差距比人们想象的要小得多,正如通过模型看到的证据。
偷和半身像的草案
抢断:肯尼斯·默里,LB

马修·埃蒙斯摄于美国今日体育
肯尼斯·默里是俄克拉荷马捷足者队的后卫。他是一个充满活力的闪击手,有着在第二场比赛中表现出来的运动能力。在许多模拟选秀中,穆雷被预测为第三后卫。许多人认为他在第一轮的得分在 20 以上。我相信他会成为选秀的抢手货。当我们的模型运行时,穆雷是最高评级的后卫,这意味着与他的缺点相比,他有最高的上升空间。分析家们谈论的主要品质是他的运动能力。今天的后卫被要求做得越来越多,尤其是在报道 NFL 如何转变为一个主要传球联盟方面。我相信这是穆雷将会发光的地方,成为像卢克·库切利一样的统治性内线后卫。
半身像:克里斯蒂安·富尔顿,CB

运动员的布罗迪·米勒的照片
克里斯蒂安·富尔顿是路易斯安那州立大学的角卫。富尔顿预计将在第一轮被选中,但我相信他会成为选秀的焦点。当模型为富尔顿运行时,输出仅为 0.68,是所有被测试运动员中最低的。这表明他被正面谈论,但他的缺点经常出现在他的分析中。这些缺陷表明他不是一个强硬/身体素质好的球员。我相信,由于他是国家队的首发队员,这可能会提高他的股票。自从路易斯安那州立大学击败了他们所有的竞争对手后,他可能表现得很好。但当克莱姆森之间的全国冠军赛(一场非常激烈的比赛)到来时,富尔顿在覆盖顶级竞争对手方面苦苦挣扎。
结论
花在评估这些运动员身上的时间可能有 100 多个小时。在任何团队中,找到合适的运动员来填补合适的空缺都需要付出很多努力。有这么多关于运动员应该是谁的意见,自然语言处理给了我们一个解决方案来听取每个人的意见。这只是我们可以做的又一个评估,以进一步分析这些运动员,希望找到谁将是 NFL 的下一个明星。
参考
[1] D. Jeremiah,丹尼尔-Jeremiah 排名前 50: 2020 NFL 选秀前景排名 2.0 (2020),http://www.nfl.com/news/story/0ap3000001102767/article/丹尼尔-Jeremiah-Top-50-2020-NFL-Draft-prospect-rankings-20
[2] K. Hanson, 2020 年 NFL 选秀前景排名:大板 100 强 (2020),https://www . si . com/NFL/2020/03/19/Draft-Big-Board-Top-100-prospects
[3] V. Iyer,NFL Draft prospects 2020:Big board of the top 100 players total&按位置排名 (2020),https://www.sportingnews.com/ca/nfl/news/ NFL-Draft-prospects-2020-Big-board-top-100-players/rpx Sao 3p 9 a 0 z 16 JK 9 e 80 julb 8
[4] D .凯利, 2020 NFL 指导线 (2020),https://nfldraft.theringer.com/
[5]阵容,阵容 2020 NFL 选秀指南 (2020),https://www.lineups.com/articles/NFL-Draft-Guide-2020-profiling-the-top-50-NFL-prospects/
[6]今日美国,NFL 2020 年选秀:竞争者如何解决顶级前景的突出需求 (2020),https://www.usatoday.com/story/sports/nfl/2020/04/01/NFL-draft-2020-团队需求-老鹰-牛仔-爱国者/5092924002/
[7] B .米勒,LSU CB 克里斯蒂安富尔顿 (2020)漫长、奇特、几乎不为人知的旅程,https://theahlettic . com/1488680/2019/12/26/LSU-football-cornerback-克里斯蒂安-富尔顿-journey/
评估我的视频搜索引擎的准确性
我训练了一个 ResNet-50 模型,让它在一个视频帧中找到一个乒乓球。我的模型好吗,或者我只是训练了一个“白色斑点”检测器?
在我在“视频搜索引擎”上的帖子之后的几个星期里,我兴奋地向任何愿意听的人展示我的进步。

当 ML 社区的朋友们认为这很棒时,一个问题困扰着我,
我的模型好吗?
我刚刚训练了一个白色斑点探测器吗?
有时我的模特会发现一个乒乓球,我会高兴地大叫。但其他时候,模型是在推断球员短裤上的乒乓球,光头,等等。没什么了不起的。

我旅程的下一步是测量模型的准确性。
使用平均精度(mAP)的变量来测量对象检测精度。有无数的帖子描述了这一指标的变体,所以我不会在这里赘述。但是有必要总结一下将在下面的代码示例中出现的要点。
背景和方法
Mean average Precision(mAP)是每个类的平均精度 (AP)的平均值,其被测量为每个类的精度-召回曲线下的面积:

假设一个物体检测器可以识别 20 个不同的类别。地图计算每个类的平均精度,然后对结果进行平均。
因此,我们需要为给定的召回值计算精度:

然后测量精确-召回对的曲线下的面积。为了简单起见,精确召回曲线的之字形被平滑了,就像这样:

因此,我们需要计算精度和召回率。这些公式信息丰富:

其中精度指的是准确度(所有预测中正确的预测的百分比),而召回指的是真阳性率(真阳性与所有真实阳性的比率)。
在 PASCAL VOC challenge (包括基准对象检测模型的评估指标)中,如果 IoU 大于或等于 0.5 ,则预测为真。小于 0.5 的 IoU 是“误报”(就像重复的边界框)。
IoU 是一种评估指标,用于计算地面实况边界框和预测边界框之间的重叠。来自 Jonathan Hui 的这张图是一个精彩的总结:

IoU 相当容易计算:
- 在分子中,我们计算预测边界框和真实边界框之间的重叠区域。
- 分母是联合区域,由预测边界框和实际边界框包围。
- 将重叠面积除以并集面积得到分数“交集超过并集”。
现在我们有了计算我的模型准确性所需的一切。以下部分显示了实现上述步骤的代码片段。
我的视频搜索引擎的平均精度
我们从导入本例所需的包开始:
# import the necessary packages
import json
import os
import boto3
from collections import namedtuple
import cv2
import matplotlib.image as mpimg
import pandas as pd
# set Pandas table options for viewing data on screen
pd.set_option(‘display.max_columns’, 500)
pd.set_option(‘display.width’, 1000)
遵循 Adrian Rosebrock 的示例,我们定义一个将存储三个属性的检测对象:
image_path:驻留在磁盘上的输入图像的路径。gt:地面实况包围盒。pred:来自我们模型的预测包围盒。
然后我们创建一个函数来计算并集上的交集:
# Define the `Detection` object
Detection = namedtuple("Detection", ["image_path", "gt", "pred"])def bb_intersection_over_union(boxA, boxB):
# determine the (x, y)-coordinates of the intersection rectangle
xA = max(boxA[0], boxB[0])
yA = max(boxA[1], boxB[1])
xB = min(boxA[2], boxB[2])
yB = min(boxA[3], boxB[3])
# compute the area of intersection rectangle
interArea = max(0, xB - xA + 1) * max(0, yB - yA + 1)
# compute the area of both the prediction and ground-truth
# rectangles
boxAArea = (boxA[2] - boxA[0] + 1) * (boxA[3] - boxA[1] + 1)
boxBArea = (boxB[2] - boxB[0] + 1) * (boxB[3] - boxB[1] + 1)
# compute the intersection over union by taking the intersection
# area and dividing it by the sum of prediction + ground-truth
# areas - the interesection area
iou = interArea / float(boxAArea + boxBArea - interArea)
# return the intersection over union value
return ioudef bb_intersection_over_union(boxA, boxB):
# determine the (x, y)-coordinates of the intersection rectangle
xA = max(boxA[0], boxB[0])
yA = max(boxA[1], boxB[1])
xB = min(boxA[2], boxB[2])
yB = min(boxA[3], boxB[3])
# compute the area of intersection rectangle
interArea = max(0, xB - xA + 1) * max(0, yB - yA + 1)
# compute the area of both the prediction and ground-truth
# rectangles
boxAArea = (boxA[2] - boxA[0] + 1) * (boxA[3] - boxA[1] + 1)
boxBArea = (boxB[2] - boxB[0] + 1) * (boxB[3] - boxB[1] + 1)
# compute the intersection over union by taking the intersection
# area and dividing it by the sum of prediction + ground-truth
# areas - the interesection area
iou = interArea / float(boxAArea + boxBArea - interArea)
# return the intersection over union value
return iou
理想情况下,我们对验证集中的每个图像重复这种计算。因此,让我们通过(1)遍历每个验证图像来构建检测元组的数组;(2)调用对象检测端点;以及(3)存储预测边界框、地面实况边界框和图像路径的结果。这就完成了工作:
for filename in os.listdir(directory):
if filename.endswith(".png"):
file_with_path = (os.path.join(directory, filename))
img = mpimg.imread(file_with_path)
height = img.shape[0]
width = img.shape[1]
with open(file_with_path, 'rb') as image:
f = image.read()
b = bytearray(f)
ne = open('n.txt', 'wb')
ne.write(b)response = runtime_client.invoke_endpoint(EndpointName=endpoint_name, ContentType='image/png', Body=b)
result = response['Body'].read().decode('ascii')
detections = json.loads(result)
best_detection = detections['prediction'][0] # ordered by max confidence; take the first one b/c only one ping pong ball in play ever
print(best_detection)(klass, score, x0, y0, x1, y1) = best_detection
xmin = int(x0 * width)
ymin = int(y0 * height)
xmax = int(x1 * width)
ymax = int(y1 * height)
pred_pixels = [xmin, ymin, xmax, ymax]
gt_pixels = find_gt_bbox_for_image(annotation_filename, filename)
det = Detection(filename, gt_pixels, pred_pixels)
det_array.append(det)
mAP_df.loc[filename, 'Confidences'] = score
continue
else:
continue
请注意,上面的代码片段通过使用图像文件名作为关键字引用 annotations.json 文件来获取基本事实边界框,使用如下方式:
def find_gt_bbox_for_image(annotation_filename, image_filename):
with open(annotation_filename) as f:
js = json.load(f)
images = js['images']
categories = js['categories']
annotations = js['annotations']
for i in images:
if i['file_name'] == image_filename:
line = {}
line['file'] = i['file_name']
line['image_size'] = [{
'width': int(i['width']),
'height': int(i['height']),
'depth': 3
}]
line['annotations'] = []
line['categories'] = []
for j in annotations:
if j['image_id'] == i['id'] and len(j['bbox']) > 0:
line['annotations'].append({
'class_id': int(j['category_id']),
'top': int(j['bbox'][1]),
'left': int(j['bbox'][0]),
'width': int(j['bbox'][2]),
'height': int(j['bbox'][3])
})
class_name = ''
for k in categories:
if int(j['category_id']) == k['id']:
class_name = str(k['name'])
assert class_name is not ''
line['categories'].append({
'class_id': int(j['category_id']),
'name': class_name
})
if line['annotations']:
x0 = line['annotations'][0]['left']
y0 = line['annotations'][0]['top']
x1 = int(line['annotations'][0]['left'] + line['annotations'][0]['width'])
y1 = int(line['annotations'][0]['top'] + line['annotations'][0]['height'])
gt = [x0, y0, x1, y1]
return gt
现在让我们取检测数组det_array中的每个Detection元组,并计算它的 IoU,此外还输出一个图像供我们检查:
for detection in det_array:
# load the image
image_with_path = (os.path.join(directory, detection.image_path))
image = cv2.imread(image_with_path)
# draw the ground-truth bounding box and predicted bounding box
cv2.rectangle(image, tuple(detection.gt[:2]),
tuple(detection.gt[2:]), (0, 255, 0), 1)
cv2.rectangle(image, tuple(detection.pred[:2]),
tuple(detection.pred[2:]), (0, 0, 255), 1)
# compute the intersection over union and display it
iou = bb_intersection_over_union(detection.gt, detection.pred)
mAP_df.loc[detection.image_path, 'IoU'] = iou # add to df for PR-curve calc.
cv2.putText(image, "IoU: {:.4f}".format(iou), (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
print("{}: {:.4f}".format(detection.image_path, iou))
if not cv2.imwrite('./IoU/{}'.format(detection.image_path), image):
raise Exception("Could not write image")
下面是上面脚本中的一个示例图像:

但是我们的工作还没有完成。我们仍然需要计算精确回忆曲线,并测量曲线下的面积。根据谭的这个例子,我做了一个熊猫表,按照各自的推理得分排序。我承认熊猫对于这个简单的任务来说火力太大了,但是我想在这篇文章中利用熊猫的表格布局和可视化:

让我们通过在上面的det_array中的每次迭代期间将 IoU 结果存储在具有 image_path 索引的数据帧中来计算精度召回表:
mAP_df.loc[detection.image_path, 'IoU']
然后,我们可以根据置信度对数据帧进行排序:
mAP_df = mAP_df.sort_values(by='Confidences', ascending=False)
并计算数据帧中每一行的真阳性、假阳性、精度和召回值:
def calc_TP(row):
iou = row['IoU']
if iou >= 0.5:
result = 1
else:
result = 0
return resultdef calc_FP(row):
iou = row['IoU']
if iou < 0.5:
result = 1
else:
result = 0
return resultmAP_df['TP'] = mAP_df.apply(calc_TP, axis=1)
mAP_df['FP'] = mAP_df.apply(calc_FP, axis=1)
mAP_df['Acc TP'] = mAP_df['TP'].cumsum(axis=0)
mAP_df['Acc FP'] = mAP_df['FP'].cumsum(axis=0)def calc_Acc_Precision(row):
precision = row['Acc TP'] / (row['Acc TP'] + row['Acc FP'])
return precisiondef calc_Acc_Recall(row):
recall = row['Acc TP'] / (mAP_df.count()[0])
return recallmAP_df['Precision'] = mAP_df.apply(calc_Acc_Precision, axis=1)
mAP_df['Recall'] = mAP_df.apply(calc_Acc_Recall, axis=1)
这个方便的绘图函数揭示了 PR 曲线,考虑到我有限的验证示例数量,它看起来相当不足:
import matplotlib.pyplot as plt
mAP_df.plot(kind='line',x='Recall',y='Precision',color='red')
plt.show()

剩下的就是计算曲线下的面积了。该函数在给定一系列(x,y)坐标的情况下执行数值积分:
def calc_PR_AUC(x, y):
sm = 0
for i in range(1, len(x)):
h = x[i] - x[i-1]
sm += h * (y[i-1] + y[i]) / 2return smcalc_PR_AUC(mAP_df['Recall'], mAP_df['Precision'])
那么我的模型的平均精度是多少呢?
请敲鼓…

> > > 0.57
万岁…?没有上下文,很难对这个数字感到兴奋。让我们将我的平均精度与其他模型进行比较。
将我的平均精确度联系起来
“自 2006 年以来,Pascal 视觉对象类(VOC)挑战赛一直是一项年度活动。挑战由两部分组成:(一)从 Flickr 网站(2013 年)获得的公开图像数据集,以及地面实况注释和标准化评估软件;(二)年度竞赛和研讨会。”(Everingham,m .,Eslami,S.M.A .,Van Gool,l .等人,《帕斯卡视觉对象类挑战:回顾》 (2015)。)如这里,该论文中的一个任务是对象检测,它询问“图像中特定对象类的实例(如果有的话)在哪里?”( Id。)
看看 2012 年 PASCAL VOC 挑战赛,我们得到了来自几个世界级团队的结果表:

在那里,每个团队都在 VOC2012 数据上训练了一个对象检测器,该表报告了每个对象类别和提交的 AP 分数。每列中的金色条目表示相应类别的最大 AP,银色条目表示排名第二的结果( Id。)我们看到最高 AP 是 65。该论文还显示了通过任何方法获得的最佳 AP(最大值)和所有方法的中值 AP(中值):

放在这样的背景下,我 57 的 AP 看起来还不错!
但如果你像我一样,你会想,
等等,这太好了,不可能是真的…
将我的结果与 2012 年的 OC 挑战进行比较是善意的,但有严重的局限性。各种因素使我的模型看起来比实际要好:
- 我的模型只预测了一个类。要求模型预测许多类肯定会降低我的整体地图。
- 给定我的领域特定的任务,假设在任何时候都只有“一个球在玩”,所以我的计算采用了每帧的最高得分检测,这排除了重复的边界框。查看所有的预测都会降低我的地图质量。
- 我的模型利用了一种新颖的深度学习架构 ResNet-50(一种具有 50 层的卷积神经网络,在 ILSVRC 和 COCO 2015 比赛中获得了第一名),相对于 PASCAL VOC challenge 中提供的技术,这代表了最先进技术的一次重大飞跃。
- 我的模型使用了“迁移学习”,利用 ImageNet 数据库中的 100 多万张图像对模型进行预训练,然后为它提供更多针对我的任务的数据
- PASCAL VOC 的方法并不是计算目标探测任务平均精度的最新方法。Jonathan Hui 很好地总结了这一点:“最新的研究论文往往只给出 COCO 数据集的结果。。。。对于 COCO 来说,AP 是多个 IoU 的平均值。。。。AP@[.5:.95]对应于 0.5 至 0.95 范围内 IoU 的平均 AP,步长为 0.05。 YOLOv3 (一个来自 2018 年的最先进的深度学习神经网络),在 COCO test-dev 数据集上以每秒 30 帧的速度运行,在 80 个类上获得了 57.9%的 mAP,而我的模型预测一个类每秒约 0.3 帧!
也就是说,我对在环境中学习和校准我对这一指标的理解的 AP 计算感到满意。我谦卑地补充一点,上面的比较并不意味着我的模型很棒,或者它的表现与世界级研究人员的模型相似。
未来方向
鉴于模型的平均精度,我开始梦想组装整个系统:
- 给定一个乒乓球视频,
- 通过在每一帧上调用我的模型来识别球何时在运动
- 当球在比赛时存储时间戳
- 向用户提供 web UI 界面,以及
- 允许用户查看球在比赛时的精彩镜头。
但我想知道我的模型将如何推广到不同的乒乓球比赛。不同的拍摄角度会放大我的模型吗?不同的桌面颜色或球员的服装会影响表现吗?我惊喜地看到这样的结果:

计算各种匹配帧的 IoU。
满怀希望,我潦草地画了这张图,以指引我旅程的下一步:

请继续关注这方面的更多内容!
虽然上面的帖子解释了各种代码片段,但最好有完整的要点,这样您就可以自己探索代码了:
对象检测的计算平均精度. py
评价 NBA 球队板凳的有效性
看看 2019–2020 NBA 赛季,哪些 NBA 球队的板凳球员表现不佳,而超出了预期。

马库斯·斯皮斯克在 Unsplash 上的照片
对于每一场比赛,每个 NBA 球队的名册都有多达 15 名球员被正式列入名单。然而,即使在这 15 名球员中,他们每个人都是世界上最好的篮球运动员,当谈到对球队的贡献时,他们每个人都有不同程度的责任也就不足为奇了。定义球员在球队中的角色的一个非常基本的启发是看“先发球员”和“替补球员”在职业篮球赛中,一个队可以同时有五名队员在场。“先发球员”(或“首发阵容”)是一场比赛开始时在场的五名球员。通常情况下,这些是球队在五个位置的每一个位置上最好的五名球员,有时,首发阵容可以由球队整体最好的五名球员组成。首发球员也往往是在一场比赛中上场时间最多的球员。每场比赛的首发阵容会有所不同,但在大多数情况下,球队喜欢保持他们相当一致,这就是为什么我们可以区分首发和“替补”(不是首发的球员)。即使在替补球员中,一些球员也有更多的责任和更多的上场时间(例如“第六人”),而其他人在一场场比赛中的阵容中并不重要。当谈到我的分析时,我想看看 NBA 的哪些板凳球员表现不佳,而超出了预期,以及与其他球队的板凳球员相比,哪些板凳球员对球队的贡献更大(根据球队的成功进行了调整)。
数据
为了进行这种分析,我需要一种方法来衡量团队的成功和球员的贡献。为了衡量团队的成功,我会查看团队在常规赛中的获胜次数,为了衡量球员的贡献,我会查看一个名为“获胜份额”的高级统计数据
团队获胜
这基本上就是一支球队在常规赛中赢球的场次。除非出现特殊情况(就像我们在 2020 年看到的 COVID 关闭),NBA 球队通常会在常规赛中打 82 场比赛,比赛可能会导致胜利或失败。以下是 2019-2020 赛季按胜场数排名的前 10 名 NBA 球队。

(图片由作者提供)
赢得份额(WS)
根据 basketball-reference.com 的说法,“‘赢得份额’是一种玩家统计,它试图将团队成功的功劳分配给团队中的个人。”从现在开始,我将“赢股”简称为 WS。在这个分析中,我收集了 basketball-reference.com 的数据,所以我将使用他们对 WS 的定义,这意味着一场团队胜利可以转化为大约一场 WS(这在篮球参考定义中并不完全是一场,所以 WS 也可以因为在失败中的出色表现而获得奖励)。这意味着一个赛季 50 胜的球队将会有大约 50 胜。球员在一个赛季的 WS 之和等于球队在那个赛季的 WS。WS 是一项统计数据,基于个人和团队的表现与其他团队和球员的表现进行比较。WS 的完整定义在这里给出。值得注意的是,WS 是一个累积的统计数据,因此在两个在类似球队打球并对这些球队有类似贡献的球员之间,上场时间更长的球员可能会有更多的 WS。
为了粗略地比较这些玩家,我们使用“每 48 赢股”(我此后将把它称为 WS/48)。这是不言而喻的:你把一个玩家积累的总 WS 数,除以这个玩家玩的分钟数,然后乘以 48。假设一场 NBA 比赛持续 48 分钟,这试图估计一名球员在一场比赛中会贡献多少 WS。下面,我列出了一些历史和 2019–20 WS 和 WS/48 排行榜,以帮助让概念更清晰一些。

空前的 NBA WS 领袖(图片由作者通过 basketball-reference.com 提供)

空前的 NBA WS/48 领袖(图片由作者通过 basketball-reference.com 提供)

2019-20 NBA WS 领袖(图片由作者 via basketball-reference.com 提供)
必须注意的是,WS 和 WS/48 不应该被认为是比较 NBA 球员的综合指标。例如,没有不尊重伟大的尼尔·约翰斯顿,但我没有办法选择他超过勒布朗詹姆斯,即使他有更高的历史最高 WS/48。肯定有其他指标可以用来比较球员,包括“球员效率评级”(PER)和“方块加减”(BPM),有时甚至简单的方块得分比较就足够了。此外,篮球比赛的许多方面并没有被基本和高级统计所捕捉。然而,当比较一组球员或整个球队时,这些偏差肯定会得到平衡,这就是为什么我们可以使用这种分析来比较不同球队的替补阵容。例如,下面我展示了 2019-2020 NBA 赛季球队胜利与球队胜利的散点图。

(图片由作者提供)
方法学
现在我们有了胜败的概念,我们需要一种方法来定义谁是我们的“板凳球员”,特别是考虑到每场比赛的阵容都可能不同。以下是我用来筛选“首发”和替补球员的标准。这些肯定有些武断,但我认为它们很好地区分了经常首发的球员和替补球员。
- 首先,我根据开始游戏的百分比筛选出每支球队的前五名球员,这就是一名球员开始的游戏数除以该球员参加的游戏总数。
- 之后,我会过滤掉所有首发次数超过 70%的球员。
- 然后我会过滤掉那些至少打了赛季 85%的比赛,并且在超过一半(50%)的比赛中首发的球员。
- 然后,我会筛选出至少打了半个赛季(50%)并且首发次数超过 60%的球员。
- 团队的其他成员被定义为该团队的“替补队员”。
例如,这里是 2019-20 NBA 赛季的一些名单,以及应用这些过滤器后的名单。

2019–20 洛杉矶快船队(图片由作者提供)

2019–20 洛杉矶快船替补席(图片由作者提供)

2019–20 多伦多猛龙队(图片由作者提供)

2019–20 多伦多猛龙替补席(图片由作者提供)

2019-20 亚特兰大老鹰队(图片由作者提供)

2019-20 亚特兰大老鹰队替补席(图片由作者提供)
分析
利用我掌握的数据,我进行了两种不同的分析。第一个是 wins 对 WS 的普通最小二乘法 (OLS)线性回归,其中 wins 是自变量(x),WS 是因变量(y)。用通俗的话说,这就是所谓的最佳拟合线。第二个分析是 wins 对 WS/48 的 OLS 回归。第一个回归没有考虑上场时间,而是给出了一个总体的概念,即哪支球队比其他球队更多地使用板凳。第二个分析提供了洞察,哪些长凳超过他们的整体团队绩效调整后的期望。为了确定“表现优于”和“表现差于”的概念,我查看了残差,它只是该团队赢得的比赛数量的观察值和期望值之间的差异(期望值位于回归线上)。
结果
这两项分析都给出了一些非常有趣的结果,这些结果大多符合我对最近 NBA 赛季球队的直觉。以下是 2019-20 NBA 赛季的表格和回归结果。

(图片由作者提供)

(图片由作者提供)

(图片由作者提供)
第一个表基于 WS 的残差按降序排序。具有最高正残差的团队比预期更多地利用他们的板凳,这些板凳比其他团队的板凳对团队的成功更重要。回顾 2019-20 NBA 赛季,这是有意义的。例如,洛杉矶快船队有两个年度第六人决赛选手(NBA 最佳“第六人”奖的决赛选手),所以就板凳重要性而言,他们接近榜首是有道理的。然而,快船板凳球员被一些快船板凳球员打了很多分钟的事实夸大了,所以这肯定夸大了他们似乎比 NBA 板凳球员表现得更好。这表现在 WS/48 回归中,快船板凳只有很小的正残差。此外,一些我认为真正头重脚轻的球队,包括开拓者队,其中像达米恩·利拉德和 CJ 麦科勒姆这样的首发球员产生了大部分的进攻,以及休斯顿火箭队,其中整个进攻都是以首发阵容中的詹姆斯·哈登为中心,也在名单的底部。此外,我只想对我最喜欢的芝加哥人之一,德里克·罗斯大喊一声,他去年在底特律活塞队替补出场。
值得注意的是,这不是一个关于板凳阵容有多强大或有多有效的排名,而是他们对球队的成功做出了多少贡献。我宁愿要纽约尼克斯队的板凳球员名单,而不是洛杉矶湖人队的:当然不是。但是尼克斯的板凳对球队的成功相对来说比湖人更重要(尽管很少),至少在常规赛中是这样。
结论
我的方法肯定有一些可以改进的地方。首先,如果我看看每场比赛的实际阵容,分析会更准确。例如,如果一个常规的先发球员受伤了,一些替补球员将不得不替补上场,直到先发球员完全康复。在这种情况下,他们在这些比赛中获得的 WS 应该流向首发 WS 而不是替补 WS。此外,团队只是喜欢在很多时候尝试不同的阵容。不幸的是,为每场比赛的每个球员请求网页,然后计算 WS,这可能是非常计算密集型的,但是我的过滤器提供了整个赛季板凳球员的粗略估计。
当谈到推广这些结果时,我想到了它们是否有任何预测能力。显然,我们不应该根据板凳有多重要来预测一支球队在接下来的赛季中的成功。然而,这种分析在休赛期肯定是重要的,那时总经理和 NBA 特许经营的篮球运营团队正在评估应该做出什么样的名册变化。这对于训练人员和教练来说也是很有用的,可以帮助他们了解球员发展的重点。总的来说,我只是认为这是一种很酷的方式来感受不同 NBA 球队的动态,并验证你对球场上发生的事情的直觉。
杂项
我也开始将我的研究项目的 Python 脚本推送到 Github 上的一个公共存储库中,链接这里!这些脚本在。ipynb 文件,所以你必须使用 Jupyter Notebook 或 Google Colab 之类的工具打开它们。此外,如果你想讨论我的任何项目和其他研究想法,或者如果你想让我运行不同 NBA 赛季的结果,请随时通过脸书或 LinkedIn 与我联系。我也喜欢谈论篮球。下次再见!
分类的评估标准
精确度、召回率、ROC 曲线和 F1 分数概述

简介
了解模型的准确性是必要的,但仅仅了解模型的性能水平是不够的。因此,有其他的评估标准可以帮助我们更好地理解模型的执行程度。这些指标包括精确度、召回率、ROC 曲线和 F1 分数。
显然,当我们选择一个指标时,我们必须知道机器学习应用程序的最终目标。因此,我们需要了解整个决策过程,以便建立一个好的模型。
在本文中,我们将看到所有这些主题以及 python 的应用。
所以,让我们开始吧!
第一部分:精确度和召回率
在谈论精度和召回率之前,让我简单介绍一下什么是混淆矩阵。
混淆矩阵是表示评估二元分类结果的最全面的方式。下面是一个混淆矩阵的例子。

作者图片
正如你在上面看到的,一个值可以分为 TN(真阴性)、TP(真阳性)或 FN(假阴性)、FP(假阳性)。
- TP :预测为正,实际值也为正
- FP :预测为正,实际为负
- TN :预测为负,实际值也为负
- FN :预测为负,实际为正
综上所述,你可以制度化地理解,当一个值被错误地分类到一个特定的类中时,结果将是 FN 或 FP。相反,当分类正确时,我们将得到 TN 或 TP。
从这个角度来看,我们可以很容易地计算出我们的精度,由以下比率给出:
(TP+TN) / (TN+FN+TP+FP)
所以,我们可以说,准确度是考虑所有不同结果的真实结果的比例。
关于精度,我们想知道预测值被正确归类为正值的比例。所以:
TP / (TP + FP)
当我们想要确定我们的预测时,精度非常有用,因为它告诉我们有多少预测为正的值实际上是正的。
回忆是另一个非常有用的指标,例如,它允许我们知道被正确分类为阳性的值的数量占实际为阳性的总值的比例。
TP / (TP + FN)
第二部分:接收机工作特性(ROC)
现在假设您想要比较假阳性率(FPR)和真阳性率(TPR)。
TPR 是我们以前见过的召回。所以公式将会是:
TPR(recall) = TP/(TP+FN)
相反,FPR 由以下比率给出:
FPR = FP/(FP+TN)
因此,为了比较 FRP 和 TPR,我们可以简单地使用 ROC 曲线。
对于 ROC 曲线,理想曲线接近左上方。目标是获得一个产生高 TPR(召回)和低 FPR 的模型。
然而,如果我们想用一个数字来概括 ROC 曲线,我们可以计算曲线下面积(AUC)。下图表示 ROC 曲线及其面积。

作者图片
第三部分:F1-得分
一个全面了解精确度和召回率的好方法是使用 F1 分数。F1 分数给出了精确度和召回率的调和平均值。下面我们可以看到公式。
F = 2*(precision-recall)/(precision+recall)
当我们处理不平衡的二进制分类数据集时,F1 值是一个比精确度更好的度量,知道这一点很重要。
无论如何,从 sklean metrics 中,我们可以导入分类报告,该报告为我们提供 F1 分数和所有指标,如精度和召回率。

结论
在分类问题中,这些是最常用于评估模型性能的指标。因此,每当您必须构建分类模型时,使用我们在本文中看到的度量标准来评估您的模型的性能是一个好主意。
感谢你阅读这篇文章。您还可以通过其他方式与我保持联系并关注我的工作:
- 订阅我的时事通讯。
- 也可以通过我的电报群 数据科学初学者 联系。
分类的评估标准已解释
为 Python 中的多类和二类分类问题选择合适的评估度量

艾萨克·史密斯在 Unsplash 上拍摄的照片
评估指标是指我们用来评估不同模型的度量。选择一个合适的评估指标是一个决策问题,需要对项目的目标有一个透彻的理解,并且是所有建模过程之前的一个基本步骤。那么为什么它如此重要,我们应该如何选择呢?
为什么重要?
假设你住在一个一年大约 300 天都是晴天的城市。在另外的 65 天里,大雨或大雪会让天气变得很不舒服。在这个想象的世界里,只有两个天气 app。一个应用程序预测天气的准确率为 80%,而另一个应用程序的准确率为 70%。你会选择哪个 app?

如果一个应用程序总是预测这个城市是晴天,这个应用程序将有 80%的正确率,即使它从来没有准确预测坏天气。这样的话,这个 app 就没用了!另一方面,另一个应用程序可能在 30%的时间里无法预测晴天,但它会在 80%的时间里准确地告诉你坏天气。在这种情况下,这个 70%正确预测天气的 app 比 80%的 app 有用多了。

App 1 在 80%的情况下是正确的,但是错过了所有的坏天气。App 2 在 70%的情况下是正确的,但不会错过任何坏天气。
正如我们在这里看到的,我们如何选择评估我们的模型可以告诉我们的数据非常不同的信息。它必须由项目的目标和数据集的属性决定。任何数据都不会没有方差,任何模型都无法完美地解释这个世界。所以我们必须知道我们宁愿让这样的预测错误发生在哪里。
真或假,积极或消极

当模型进行二元预测时,有 4 种可能的结果。一个模型可以预测是(正)或否(负),也可以是正确的(真)或错误的(假)。当模型进行多类预测时,同样的逻辑也适用。这个模型预测一个单独的类是或不是,它可能是对的,也可能是错的,我们决定如何组合这些单独的结果。
正确预测的概率

正确的案例
精确度和召回率
但是我们如何解释一个模型超出了这四个结果。首先,真阳性(TP)涉及两个事件:模型预测和实际状态。我们的解释可以根据我们对这两个事件的优先顺序而改变。我们可以看到当实际值为正时模型是否预测为正,或者当模型预测为正时我们可以看到实际值是否为正。
比方说,当天气晴朗时,应用程序有 80%的可能性预测天气晴朗。但是这并没有告诉我们任何有用的信息。相反,我们应该看到应用程序显示天气晴朗的频率。这将告诉我们该应用程序在预测晴天时的预测有多精确。这是精度指标,代表模型在所有情况下都正确的概率。
**from** sklearn.metrics **import** precision_score
precision_score(actual_y, predicted_y)
# scoring parameter: ‘precision’

但有时知道所有阳性病例中阳性预测的概率可能更重要。想象一下,我们正在预测一种食物是否有毒。一个模型的精度(预测食物有毒时食物有毒的可能性)没有预测食物有毒时食物有毒重要。因为如果模型说它有毒,我们可以干脆不吃,但如果它不能告诉我们,我们就冒着吃有毒食物的风险。所以我们想要一个当食物有毒时有很高概率预测阳性的模型。这是针对召回或灵敏度指标的情况。也叫真阳性率。它代表了我们的模型在检测阳性病例时的灵敏度。
**from** sklearn.metrics **import** recall_score
recall_score(actual_y, predicted_y)
# scoring parameter: ‘recall’
F1 分数
但是如果这两个都很重要呢?换句话说,在不遗漏正面案例和不遗漏负面案例同等重要的情况下,我们该怎么办?想象一下,你正在预测一种可以通过某种治疗方法治愈的疾病。但是这种治疗对没有患病的人是有害的。在这种情况下,我们需要一个对检测阳性病例敏感且检测同样精确的模型。这时 F1 分数开始发挥作用。 F1 得分是精确率和召回率的调和平均值,是精确率和召回率的平均值。
**from** sklearn.metrics **import** f1_score
f1_score(actual_y, predicted_y)
# scoring parameter: ‘f1’
准确(性)
精确度和召回率指标侧重于预测正面案例:对问题'这是 __?’。但正如我们之前看到的,模型有两种不同的正确方式:它可以在应该说是时说是,也可以在应该说不是时说不是。准确性是在这两种情况下正确的概率。当等级相等时,我们可以使用精确度。比如说我们想预测一张图片是不是狗。我们只想让模特在它是狗的时候说是,在它不是狗的时候说不是。当它是一只猫的时候说它是一只狗和当它是一只狗的时候说它不是一只狗没有任何不同的结果。在这种情况下,我们可以使用精度。
**from** sklearn.metrics **import** accuracy_score
accuracy_score(actual_y, predicted_y)
# scoring parameter: ‘accuracy’

这是一只狗吗?由 Karsten Winegeart 在 Unsplash 上拍摄
特征
最后,特异性是预测阴性病例的灵敏度(在所有阴性病例中预测阴性的概率)。换句话说,当不遗漏负面案例比犯错更重要时,我们可以使用特异性。假设你想知道井里的水是否可以饮用。你宁愿把可饮用的水标为不可饮用,也不愿错误地标为不可饮用。如果我们交换正反两面,问一个问题'这水有传染性吗?',我们将使用灵敏度而不是特异性。
特异性在 Sci-kit 学习包中没有内置功能。相反,您可以使用灵敏度并交换正反例,或者使用混淆矩阵通过自定义函数来计算。
# custom function to calculate specificity for binary classification**from** sklearn.metrics **import** confusion_matrixdef **specificity_score**(y_true, y_predicted):
cm = **confusion_matrix**(y_true, y_predicted)
**return** cm[0, 0] / (cm[0, 0] + cm[0, 1])**print**(**specificity_score**(y_true, y_predicted))
多类问题

马库斯·斯皮斯克在 Unsplash 上拍摄的照片
微观平均值
我们回顾了如何为我们的二元分类数据选择评估指标。但是,当我们的目标不是“是”或“否”,而是由多个类别组成时,我们该怎么办呢?一种方法是对每个结果进行全局计数,而不考虑类内分布,并计算指标。我们可以通过使用微平均值来实现这一点。
让我们想想使用全局计数意味着什么。如果我们只看全局结果,我们没有之前的四个结果(TP,TN,FP,FN)。相反,我们有真(预测=实际类)或假(预测!=实际类)。因此,微精度、微召回、准确度都代表准确预测的概率,并且相等。此外,由于 F1 得分是精度和召回的调和平均值,因此微 F1 得分与其他指标相同。
# these are all the same **recall_score**(actual_y, predicted_y, average = **'micro'**)
**precision_score**(actual_y, predicted_y, average = **'micro'**)
**accuracy_score**(actual_y, predicted_y)
**f1_score**(actual_y, predicted_y, average = **'micro'**)# scoring parameter: 'f1_micro', 'recall_micro', 'precision_micro'
计算全局结果不考虑每一类预测的分布(只计算有多少预测正确)。当数据集包含高度不平衡的类,并且我们不关心控制任何特定类中的预测误差时,这可能会很有帮助。但是正如我们上面讨论的,我们的许多问题确实涉及到对预测误差来源的特定控制。
宏观平均值
另一种处理多类的方法是简单地计算每个类的二元测度。例如,如果我们的目标变量可以是猫、狗或鸟,那么我们对每个预测都会得到一个二元的是或否的答案。这是一只猫吗?这是一只狗吗?这是一只鸟吗?这将导致与我们的目标职业一样多的分数。然后,我们可以汇总这些分数,并使用宏观平均值或加权平均值将它们转化为一个单一指标。
宏平均值计算单个类的指标,然后计算它们的平均值。这意味着它对每个类返回的结果给予相同的权重,而不管它们的总体大小。所以它对每个班级的规模不敏感,但它更重视单个班级的表现,即使它是少数。因此,如果很好地预测少数类与整体准确性一样重要,并且我们也相信少数类中有可靠的信息量来准确地表示基本事实模式,则宏观平均值是一个很好的度量。
宏观平均召回分数与多类问题中的平衡准确率相同。
print(**f1_score**(actual_y, predicted_y, average = **'macro'**))
print(**precision_score**(actual_y, predicted_y, average = **'macro'**))# below two are the same measures**from** sklearn.metrics **import** balanced_accuracy_score, recall_score
print(**recall_score**(actual_y, predicted_y, average = **'macro'**))
print(**balanced_accuracy_score**(actual_y, predicted_y))# scoring parameter: 'f1_macro', 'recall_macro', ...etc.

加权平均值
概括地说,微观平均给予单个观察值同等的权重,宏观平均给予单个类别同等的权重。根据定义,宏平均值并不关心每个类有多少数据。因此,即使少数群体没有足够的数据来显示可靠的模式,它仍然会平等地衡量少数群体。如果是这种情况,我们可能希望通过使用加权平均值来考虑每个类的总体大小。
# we can also compute precision, recall, and f1 at the same time**from** sklearn.metrics **import** precision_recall_fscore_support
**precision_recall_fscore_support**(actual_y, predicted_y, average = '**weighted**')# scoring parameter: 'f1_weighted', 'recall_weighted', ...etc.
科恩的卡帕
到目前为止,我们讨论的每个指标都讲述了一个故事的一部分,这就是为什么我们希望确保我们的目标是明确的,并与我们选择的指标保持一致。但是,如果我们只是想要一个度量,可以全面地告诉我们,相对于随机机会,我们的模型分类做得如何呢?科恩的 Kappa 将分类器的性能与随机分类器的性能进行了比较。自然地,它考虑了类别不平衡,因为随机分类器将依赖于每个类别的分布。与其他衡量概率的指标不同,科恩的卡帕值从-1 到 1 不等。
**from** sklearn.metrics **import** cohen_kappa_scoreprint(**cohen_kappa_score**(actual_y, predicted_y))
我们研究了二元和多类分类的每个评估指标如何唯一地用于个体问题,以及为什么关注我们选择的指标很重要。我试图用简单的英语复习最基本的小节。但我仍然忽略了另一个非常重要的指标,ROC/AUC 得分,我将在另一篇文章中讨论。

只是一只小狗。照片由克里斯·莱佩尔特在 Unsplash 上拍摄
机器学习中分类问题的评价指标

在 Unsplash 上由 Helloquence 拍摄的照片
知道如何创建机器学习模型是成为成功的数据科学家的一大步,但第一个模型很少是“最好”的模型。评估我们的机器学习模型的质量对于继续改进我们的模型至关重要,直到它尽可能地发挥最佳性能。对于 分类 问题, 评估度量 将预期类别标签与预测类别标签进行比较,或者解释类别标签的预测概率。分类问题是常见的,并且具有许多现实世界的应用,例如检测垃圾邮件、定向营销、欺诈检测或评估患者是否处于发展特定疾病诊断的高风险中。在这篇博文中,我们将回顾针对这些类型问题的一些不同类型的分类评估标准。
1.混淆矩阵
2.精确
3.回忆
4.准确(性)
5.f1-分数
6.AUC ROC
混淆矩阵
混淆矩阵是一个包含预测值和实际值的四种不同组合的表格。这是一个很好的方式来可视化不同的输出,并计算精度、召回、 精度、F-1 评分为以及 AUC-ROC。我们将在本博客后面更详细地讨论每一个问题。首先,让我们将 TP、FP、FN 和 TN 分解成一个混淆矩阵。

混淆矩阵
- 真阳性(TP) :我们的模型预测的次数是肯定的,实际输出也是肯定的。
- 真阴性(TN) :我们的模型预测为 NO 而实际输出为 NO 的次数。
- 假阳性(FP) :我们的模型预测为是而实际输出为否的次数,这就是所谓的 1 类错误。
- 漏报****【FN】:我们的模型预测为否,实际输出为是的次数。这就是所谓的第二类错误。
——
精度可以描述为相关实例在检索实例中所占的比例。这回答了“多大比例的积极认同是正确的?”公式如下:

根据我们的混淆矩阵,等式可以表示为:

精度表示我们的模型所说的相关数据点的比例实际上是相关的。
回忆 —
回忆,又称敏感性。这回答了“有多少比例的实际阳性被正确分类?”这可以用下面的等式来表示:

在我们的混淆矩阵中,它可以表示为:

召回表示数据集中哪些实例是相关的。在评估模型时,检查精确度和召回率是很重要的,因为它们通常有相反的关系。当精确度增加时,回忆倾向于减少,反之亦然。
准确度 —
准确性决定了在所有的分类中,我们正确分类了多少?这在数学上可以表示为:

使用我们的混淆矩阵术语,该等式可写成:

我们希望准确度分数尽可能 高。值得注意的是,准确性可能不总是使用的最佳指标,尤其是在 类不平衡数据集 的情况下。这是指数据在所有类别中的分布不相等。
例如,假设我们正在寻求建立一个模型来帮助诊断脑癌患者。如果我们的模型只是将每个人归类为没有患脑癌,我们在绝大多数情况下都是正确的,但事实上,当某人患有脑癌而没有被诊断出来的代价是毁灭性的。根据行业的不同,这些成本可能会超过模型的准确性。在这种不平衡的情况下,最好使用 F1-Score 来代替。
F1-得分 —
F1 分数是精确度和召回率的函数。它用于在两个指标之间找到正确的平衡。它决定了在不遗漏大量实例的情况下,模型正确分类的实例数量。这个分数可以用下面的等式来表示:

精确度和召回率之间的不平衡,例如高精确度和低召回率,可以给你一个非常精确的模型,但是不能正确地分类困难的数据。我们希望 F1 分数尽可能高,以实现我们车型的最佳性能。
AUC(曲线下面积)ROC(受试者操作特征)曲线
AUC ROC 曲线是显示分类模型在所有阈值的性能的图表。ROC 是概率曲线,AUC 代表可分离度。ROC 绘制了以下参数:
- 真阳性率(TPR) ,也称回忆或敏感度,在上一节有解释。

- 假阳性率(FPR) ,也称为漏失,假阳性预测与所有实际为阴性的值的比率。

RPR 和 FPR 都在范围[0,1]内。该曲线是在范围[0,1]中不同点的 FPR 对 TPR。表现最好的分类模型会有一条类似于下图中绿线的曲线。绿线在曲线下的面积最大。AUC 越高,你的模型表现越好。只有 50-50 准确度的分类器实际上并不比随机猜测好多少,这使得模型毫无价值(红线)。

我希望这篇博客有助于澄清用于评估机器学习中分类模型性能的不同度量标准!
如果这篇博文有什么启示,请务必记住,没有适用于所有问题的评估标准。这取决于行业和你要处理什么样的数据集。
感谢阅读!
参考资料:
- https://developers . Google . com/machine-learning/速成课程/分类/真-假-正-负
- https://towards data science . com/understanding-mission-matrix-a9ad 42 dcfd 62
- http://gim.unmc.edu/dxtests/ROC3.htm
- https://towards data science . com/beyond-accuracy-precision-and-recall-3da 06 bea 9 f6c
- https://towards data science . com/accuracy-precision-recall-or-f1-331 FB 37 C5 CB 9
线性回归中的评价指标和模型选择
数据科学
揭开最常见的度量和模型选择方法的神秘面纱

克里斯·利维拉尼在 Unsplash 上的照片
在本文中,我们将回顾线性回归中最常见的评估指标以及模型选择策略。
残差图-评估模型之前
我们知道,线性回归试图拟合一条线,使预测值和实际值之间的差异最小,这些差异也是无偏的。这种差异或误差也被称为残差。( 无偏是指预测值没有系统的分布模式)
残差=实际值—预测值
e=y—ŷ
值得注意的是,在使用 R 平方等评估指标评估或评价我们的模型之前,我们必须利用残差图。
残差图暴露了一个比其他任何评价指标都有偏差的模型。如果你的残差图看起来正常,继续,用各种度量评估你的模型。
残差图在 y 轴上显示残差值,在 x 轴上显示预测值。如果你的模型有偏差,你就不能相信结果。
显示对应于预测值的误差的残差图必须是随机分布的。然而,如果有任何系统模式的迹象,那么你的模型是有偏见的。
但是随机分布的误差意味着什么呢?
线性回归模型的假设之一是误差必须是正态分布的。这意味着,对于整个预测值范围,确保残差分布在零附近。因此,如果残差是均匀分布的,那么您的模型可能表现良好。
线性回归模型的评估指标
评估指标是衡量模型表现的好坏以及它与关系的近似程度。让我们看看 MSE、MAE、R 平方、调整 R 平方和 RMSE。
均方误差
回归任务最常见的度量是 MSE。它有一个凸起的形状。它是预测值和实际值之差的平均值。因为它是可微分的,并且具有凸形,所以更容易优化。

均方差。图片由作者提供。
MSE 惩罚大的错误。
平均绝对误差
这只是目标值和模型预测值之间的绝对差值的平均值。在异常值突出的情况下,不推荐使用。

平均绝对误差。图片由作者提供。
MAE 不惩罚大的错误。
r 平方或决定系数
此指标表示由模型的自变量解释的因变量方差部分。它衡量模型和因变量之间的关系强度。
为了理解 R-square 真正代表什么,让我们考虑下面的情况,在有和没有独立变量的知识的情况下,我们测量模型的误差。
计算回归误差 当我们知道自变量的值时,我们可以计算回归误差。
我们知道残差是实际值和预测值之间的差值。因此,RSS(残差平方和)可以计算如下。

剩余平方和。图片由作者提供。
计算平方残差 考虑我们不知道自变量的值的情况。我们只有 y 的值。这样,我们就可以计算出 y 值的平均值。这个点可以表示为一条水平线。现在我们计算平均y 值和每隔一个yy值之间的误差平方和。
Y 中的总变化可以被给出为每个点之间的距离的平方差和 Y 值的算术平均值。这可以被称为 TSS (总平方和)。

y 或 TSS 的总变化。图片由作者提供。
用 RSS & TSS 计算决定系数,因此我们想找出 Y 的总变化的百分比,由独立变量 x 描述。如果我们知道 Y 的总变化的百分比,即回归线描述的而不是,我们可以从 1 中减去相同的值以获得决定系数或 R 平方。

图片由作者提供。

决定系数。图片由作者提供。
如果数据点非常接近回归线,则该模型说明了大量的方差,从而导致高 R 值。
然而,不要让 R 值欺骗了你。一个好的模型可以具有低的 R 值,而一个有偏差的模型也可以具有高的 R 值。这就是你应该利用剩余地块的原因。
总之,残差(RSS)与总误差(TSS)的比率告诉您回归模型中还有多少总误差。从 1 中减去该比率,就可以得出使用回归分析消除了多少误差。这就是 R 平方误差。
如果 R 很高(比如说 1),那么模型代表因变量的方差。
如果 R 非常低,那么模型不代表因变量的方差,回归并不比取平均值好,也就是说,你没有使用来自其他变量的任何信息。
负 R 表示你做的比平均值差。如果预测值根本不能解释因变量,那么 RSS ~ TSS 可能为负值。
因此,R 评估回归线周围的分散数据点。
不可能看到 R 为 1 的模型。在这种情况下,所有预测值都与实际值相同,这实质上意味着所有值都落在回归线上。
均方根误差(RMSE)
这是预测值和实际值的平方差的平均值的平方根。
r 平方误差优于 RMSE。这是因为 R 平方是相对测量值,而 RMSE 是拟合的绝对测量值(高度依赖于变量,而不是归一化测量值)。
基本上,RMSE 只是残差平方平均值的根。我们知道残差是一个度量点离回归线有多远的指标。因此,RMSE 测量这些残差的分散。

均方根误差。图片由作者提供。
RMSE 惩罚大错误。
模型选择和子集回归
让我澄清一下,当你开发任何考虑到所有预测或回归变量的模型时,它被称为完整模型。 如果你丢弃一个或多个回归变量或预测变量,那么这个模型就是一个子集模型。
子集回归背后的一般思想是找出哪个做得更好。子集模型或完整模型。
我们选择在所有可用候选预测值中表现最好的预测值子集,这样我们就有最大的 R 值、最大的调整 R 或最小的 MSE 。
然而,R 从不用于比较模型,因为 R 的值随着预测因子数量的增加而增加(即使这些预测因子没有给模型增加任何值)。
选择模型的原因 我们着手选择能很好解释数据的预测因子的最佳子集。由于降低了复杂性,充分解释关系的更简单模型总是更好的选择。增加不必要的回归变量会增加噪声。
我们现在来看看比较和选择最佳模型的最常见标准和策略。
调整的 R 平方—选择标准
调整后的 R 平方与 R 平方的主要区别在于, R 平方描述的是每个独立变量所代表的因变量的方差,而调整后的 R 平方测量的是仅由实际影响因变量的独立变量所解释的方差。

调整后的 R 平方。图片由作者提供。
在上面的等式中,n 是数据点的数量,而 k 是模型中变量的数量,不包括常数。
r 往往随着自变量数量的增加而增加。这可能会产生误导。因此,调整后的 R 平方由于增加了不符合模型的独立变量(方程中的 k)而对模型不利。
马洛的 Cp —选择标准
Mallow 的 Cp 衡量模型的有用性。它试图计算均方预测误差。

马洛的 Cp 统计。作者图片。
这里的 p 是回归数,是模型的 RSS 为给定的 p 回归数,是总 MSE 为 k 总预测数,而 n 是 这在 n>>k>时很有用**
Mallow 的 Cp 将完整模型与子集模型进行了比较。如果 Cp 几乎等于 p (越小越好),那么子集模型就是一个合适的选择。
可以为每个子集模型绘制 Cp 对 p 以找出候选模型。
穷举和最佳子集搜索
穷举搜索**查看所有模型。如果有 k 个回归量,就有个可能的模型。这是一个非常缓慢的过程。
最佳子集策略通过为每个 P 值 寻找最小化 RSS 的模型来简化搜索。
逐步回归
逐步回归比穷举和最佳子集搜索更快。选择最佳模型是一个反复的过程。
逐步回归分为向后选择和向前选择。
逆向选择从一个完整的模型开始,然后我们一步一步减少回归变量,找到 RSS 最小、R 最大或者 MSE 最小的模型。要删除的变量是那些具有高 p 值的变量。然而,重要的是要注意,你不能删除一个分类变量的一个层次。这样做会导致一个有偏见的模型。要么删除分类变量的所有级别,要么不删除。
前向选择从一个空模型开始,然后我们逐步增加回归变量,直到我们无法再提高模型的误差性能。我们通常选择调整后 R 最高的模型。
** [## 机器学习中模型评估和选择的终极指南- neptune.ai
在高层次上,机器学习是统计和计算的结合。机器学习的关键在于…
bit.ly](https://bit.ly/3lSfQM2)**
结论
我们讨论了线性回归中最常用的评估指标。我们看到了在多元线性回归和模型选择过程中使用的指标。在浏览了最常见的评估指标和选择策略的用例之后,我希望您理解了它们的潜在含义。下一场见。干杯。
谢谢你
NLP 模型的评估—最新基准
以及为什么它很重要

在 Unsplash 上由 Carlos Muza 拍摄的照片
需要评估指标
其他领域的损失计算
在大多数深度学习任务中——分类、回归或图像生成——评估模型的性能是非常容易和直接的,因为解决方案空间是有限的/不是很大。
在大多数分类问题中,标签的数量是固定的,这使得有可能计算每一类的分数,并因此使得有可能计算从基础事实的损失/偏移。
在图像生成的情况下,输出和地面实况的分辨率是固定的。因此,我们可以计算一个像素的地面真实值的损失/偏移。水平。
在回归的情况下,输出中值的数量是固定的,因此可以为每个值计算损失,即使每个值的可能性是无限的。
注意:我在这篇文章中交替使用了问题和任务,因为每个问题都是围绕着一个模型需要执行的任务来定义的,所以请不要混淆。
自然语言处理中的损失计算问题
在 NLP 的情况下,即使输出格式是预先确定的,尺寸也不能是固定的。如果我们希望我们的模型输出单个句子,那么限制该句子的字数将是违反直觉的,因为我们知道有多种方式来表达相同的信息。
一个例子

如果我要求您从以下选项中为上图选择不正确的标题:
- 房子前面的一辆汽车。
- 一辆汽车停在房子前面的路上。
- 一辆灰色汽车停在一所房子前面的路上。
- 一辆灰色跑车停在一栋房子前。
你可以选择其中任何一个,仍然是正确的,没有一个是不正确的,只是细节有所不同。如果我们的数据集中该图像的真实情况是“一辆灰色汽车在路上”。你将如何教一个模型使用地面真相标签,所有 4 个输出都是正确的?不太容易,是吗?
为什么拥有良好的评估指标很重要?
在我们深入到各种度量的细节和细微差别之前,我想在这里不仅谈谈为什么有一个好的度量很重要,而且还谈谈什么是一个好的度量——在我看来——以防你在文章结束之前没有做到。
开发这些 AI 解决方案的主要目的是将它们应用到现实世界的问题中,让我们的生活变得更轻松、更美好。但是我们的现实世界并不简单。那么,我们如何决定使用哪个模型来解决特定的问题呢?这就是这些指标派上用场的时候了。
如果我们试图用一个模型解决两个问题,我们会想知道模型在这两个任务上的表现,做出明智的决定,意识到我们正在做的权衡。这也是衡量标准的“优点”所在。现实世界充满了偏见,我们不希望我们的解决方案有偏见,因为这可能会产生不可想象的后果。
举个简单的例子,如果我们把一篇文章从 X 语言翻译成英语。对于一个特定的句子,如果我们谈论的是 A 组,它被翻译成“他们做了一个 好的 工作。”相比之下,对于 B 组,它被翻译成“他们做了一件 伟大的 工作。”,这是一个非常明显的迹象,表明我们的模型偏向于 b 组。这种偏见应该在它部署到现实世界之前就知道,度量标准应该有助于我们发现这些偏见。
尽管学习偏差与训练数据的关系更大,而与模型架构的关系更小,但我觉得,拥有一个捕捉偏差的指标或偏差的标准将是一个适应的好做法。
BLEU 评分-双语评估替补演员
顾名思义,它最初用于评估从一种语言到另一种语言的翻译。
如何计算 BLEU 分数?
计算单字精度:
步骤 1: 查看输出句子中的每个单词,如果它出现在任何参考句子中,则给它打分,如果没有出现,则给 0 分。
第二步:通过将一个参考译文中出现的单词数除以输出句子中的总单词数,使计数标准化,使其始终介于 0 和 1 之间。
继续上面的例子:
地面真相:一辆灰色的车在路上
S1:《一辆车在路上》会得到 5/6 的分数,
S2:《一辆灰色的车在路上》会得到 6/6 的分数,
S3:《一辆灰色的车在路上》也会得到 6/6 的分数!
事实上 S4:“车车车车车车”也将获得 6/6 的分数!!
这似乎是不正确的;我们不应该给 S3 和 S4 打这么高的分。为了惩罚最后两种情况,我们使用一元、二元、三元和 n 元的组合,将它们相乘。使用 n-grams 在某种程度上帮助我们捕捉句子的顺序——S3 情景。我们还根据每个单词在任何参考句子中出现的最高次数来限制计数每个单词的次数,这有助于我们避免不必要的重复单词——S4 情景。
最后,为了避免因为标题太短而错过细节,我们使用了简短惩罚。我们通过将它与长度最接近的参考句子的长度进行比较来做到这一点。
if (length(output) > length(shortest_References))
brevity_Penalty = 1;
else { // output caption is shorter.
brevity_Penalty = exponent(length(output)/length(shortest_Reference)-1);
}BLEU Score = unigram_precision * bigram_precision *...* ngram_precision * brevity_Penalty;
BLEU 的问题是:
- 不考虑意义:现实中,句子中的单词对句子意义的贡献是不平等的。但是 BLEU 方法对所有单词的评估都是平等的。
地面真相:我有一辆栗色车。S1:我有一辆蓝色的汽车。S2:我有一辆红色的汽车。S3:我有一艘栗色的船。所有人都会得到相同的分数,尽管 S1 和 S3 在这里传达了错误的信息。 - 不直接考虑句子结构:无法捕捉句法。词序对一句话的得分贡献不大。或者在翻译的情况下,句子的顺序。
例如,如果我试图评估一部小说中某一章的翻译,我交换了翻译的前半部分和后半部分,这只会对 BLEU 分数产生一点点影响。同时,翻译的故事情节会被完全扭曲,这只有在诺兰电影中才能接受。 - 它 不处理形态丰富的语言。如果你想用法语说“我很高”,“我很高”和“我很高”都是正确的翻译。唯一的区别是“grand(e)”这个词的性别。但是对于一个布鲁来说,这些词可能会像白天和黑夜一样不同。如果一个模型预测了其中一个,而期望另一个,BLEU 只会认为这是一个不匹配。
SQuAD —斯坦福问答数据集
在这种类型的度量测试中,给定一个问题和一个文本,模型需要从给定的文本中预测答案。
【以防你不熟悉《奇幻参考》,这里是你需要知道的一切,以便理解我的类比:
哈利波特是 JK 罗琳的系列丛书;《波西·杰克森》&《奥运选手》是雷克·莱尔顿制作的一个完全不同且毫无关联的系列;在《哈利·波特》系列中,主角——哈利·波特,在 90%的时间里,要么处于困境,要么正在陷入困境;
波西·杰克森是我提到的另一个书系列的主角,也和哈利有同样的惹上麻烦的倾向;《哈利·波特》系列中有一个角色叫珀西,虽然不是很重要。是的,这就是你所需要知道的。😄]
如果我给你一篇哈利波特系列的课文,问你“为什么波西·杰克森和他的朋友会有麻烦”?人类能够分辨出问题和文本没有上下文关系,因此问题是不可回答的;一个陶工脑袋会和我断绝关系。但当被问及 NLP 模型时,它可能只是试图预测最有可能的答案,这可能是关于某个陷入困境的其他角色——暗示哈利·波特或某个名叫珀西或杰克逊的角色所做的事情。
为了解决这些弱点,SQuAD 2.0 将现有的小队数据与超过 50,000 个无法回答的问题相结合,这些问题由人群工作者以敌对的方式编写,看起来与可回答的问题相似。为了在 SQuAD 2.0 上做得好,系统不仅必须在可能的情况下回答问题,还必须确定何时没有答案被段落支持并放弃回答。
你可以在这里查看班长板。
MS MACRO —机器阅读理解数据集
这是一个大规模的机器阅读理解数据集。它由以下任务组成:
- 问题回答——根据问题和段落上下文所能理解的上下文段落,生成一个结构良好的答案(如果可能的话)。
- 段落排名 —对给定问题的一组检索到的段落进行排名。
- 关键短语提取 —在给定一组上下文段落的情况下,预测问题是否可回答,并像人类一样提取和合成答案。
该数据集开始关注 QnA,但后来发展到关注任何与搜索相关的问题。
该数据集由 1,010,916 个匿名问题组成——从 Bing 的搜索查询日志中取样——每个问题都有一个人为生成的答案和 182,669 个完全由人重写的生成答案。此外,该数据集包含 8,841,823 个段落,这些段落是从 Bing 检索的 3,563,535 个 web 文档中提取的,为管理自然语言答案提供了必要的信息。
胶水和强力胶——通用语言理解评估
GLUE 和 SuperGLUE 评估模型在一组任务上的性能,而不是单个任务,以获得性能的整体视图。它们由单句任务、相似性和释义任务以及推理任务组成。
我浏览了他们的论文,并收集了他们各自任务的简要概述。为了更快更好地理解,我将它们组织成这些表格。如果你想详细了解每项任务,请浏览文章末尾参考资料部分的链接。

胶水中的任务。

强力胶中的任务。

超级胶水纸上给出的每个任务的例子。来源。
了解这些指标无论如何都不会帮助您提高模型的性能。然而,它肯定会帮助你理解更大的画面,我们目前在这个领域试图解决的问题!希望你觉得有用。
参考资料和其他好读物:
我很高兴你坚持到了这篇文章的结尾。🎉我希望你的阅读体验和我写这篇文章时一样丰富。💖**
请点击这里查看我的其他文章。
如果你想联系我,我会选择推特。
情感分析的评价:反思自然语言处理的过去和未来
我们能不能发现一些仍然缺失的元素的线索,从而使 NLP 更加有效?我们应该在哪里寻找下一件大事?

Javier Allegue Barros 在 Unsplash 上拍摄的照片
我最近收到一篇新论文,题为“金融中的情绪分析评估:从词典到变形金刚”,发表于 2020 年 7 月 16 日的 IEEE。作者 KostadinMishev、Ana Gjorgjevikj、Irena Vodenska、Lubomir T. Chitkushev 和 DimitarTrajanov 比较了应用于两个已知金融情绪数据集的一百多种情绪算法,并评估了它们的有效性。虽然这项研究的目的是测试不同自然语言处理(NLP)模型的有效性,但论文中的研究结果可以告诉我们更多关于 NLP 在过去十年中的进展,特别是更好地了解哪些因素对情绪预测任务贡献最大。
所以让我们从情绪预测任务的定义开始。给定一组段落,该模型将每个段落分为三个可能的类别:正面情绪、负面情绪或中性情绪。然后,基于混淆矩阵(3X3)来评估该模型,该混淆矩阵是根据预测情感与基本事实(每个段落的真实标签)的计数来构建的。
作者实施的评估指标被称为马修斯相关系数(MCC),并作为二元(两类)分类质量的衡量标准(马修斯,1975)。尽管 MCC 度量仅适用于二元情况,但是作者没有提及他们如何在多类别情况(3 个情感类别)中应用 MCC 函数。他们是使用了微平均法,还是对多类情况应用了广义方程?
作者根据文本表示将 NLP 模型分为五大类:(1)基于词汇的知识,(2)统计方法,(3)单词编码器,(4)句子编码器,(5)转换器。每个类别应用了几个不同的模型,其性能记录在表中。
上表展示了这些年来在文本表示方法的推动下情感分析的进展。作者证实,与其他评估方法相比,transformers 表现出更好的性能,并且文本表示扮演了主要角色,因为它将单词和句子的语义输入到模型中。
但是等等!关于 NLP 的未来,也许可以从这个实验中得出更多的结论。我们能发现仍然缺失的元素的线索,使 NLP 在更复杂的任务中更有效吗?为了用语言模型更好地表现人类语言,下一个重大突破可能是什么?
为了解决这个问题,我开始进一步挖掘模型的结果,寻找文本表示、模型大小和模型性能之间的联系,试图提取模型大小和文本表示对最终性能的影响。基于作者的分析,我创建了下图。下图显示了每个模型的 MCC 分数,作为模型数值参数的函数。颜色代表模型主类别。

图 1:作为模型中参数数量(对数标度)的函数的情感分类(MCC 分数)的改进
从我的分析中可以看出,情绪预测任务的进展包括两个阶段。第一阶段主要归功于更好的文本表示,而第二阶段是由于引入了转换器,该转换器可以通过增加网络规模和管理数百万个参数来处理巨大的语料库。
从上图中可以看出,从 80 年代初开始,文本表示发生了三次重大变革。第一次是从词汇表征到嵌入向量表征。嵌入向量的主要优点是其无监督的性质,因为它不需要任何标记,同时仍然捕获单词之间有意义的语义关系,并受益于模型的泛化能力。重要的是要记住这些嵌入模型,比如 word2vec 和 GloVe,是上下文无关的。它们将同一个相关向量分配给同一个单词,而不管该单词周围的上下文。因此,它们不能处理自然语言中的多义性或复杂语义。
然后,面向 2016 年推出了与上下文相关的单词表示法,如埃尔莫和 GPT。这些模型具有依赖于其上下文的单词的向量表示。埃尔莫双向编码上下文,而 GPT 从左到右编码上下文。它们的主要贡献是处理多义词和更复杂的语义的能力。
NLP 中最近的革命是 BERT(来自转换器的双向编码器表示),它结合了双向上下文编码,并且对于广泛的自然语言处理任务只需要最小的架构改变。BERT 输入序列的嵌入是记号嵌入、段嵌入和位置嵌入的总和。BERT 和以下模型的独特之处在于,它们可以处理一批序列,从 1M 的参数到达到 500M 以上的最新模型。从图中可以看出,模型中的参数数量是过去 4 年中性能持续改善的主要原因。
尽管 NLP 模型在最近几年取得了长足的进步,但仍有很大的改进空间。根据多项研究,1,2 仅仅增加网络规模是不够的,即使在今天该模型也处于过度参数化的状态。下一个突破可能来自文本表示的进一步发展,届时 NLP 模型将能够更好地捕捉语言的组成性(通过组成其组成部分的含义来学习一大段文本的含义的能力)。语法推理领域是寻找新的文本表示方法的好地方。通过学习受控形式语法,我们可以更深入地了解应该在测试方面综合处理(Solan et al,2005)的元素,如系统性、替代性、生产率、本地化等。(Hupkes 等人,2019;Onnis & Edelman,2019)。
传记
(1) Hupkes,d .,Dankers,v .,Mul,m .,& Bruni,E. (2019)。神经网络的组合性:整合符号主义和连接主义。 arXiv 预印本 arXiv:1908.08351 。
(2)科瓦列娃、罗马诺夫、罗杰斯和拉姆斯斯基(2019)。揭露伯特的黑暗秘密。 arXiv 预印本 arXiv:1908.08593 。
(3) Onnis,l .,& Edelman,S. (2019)。本地与全球语言统计学习。
(4) Solan,z .,Horn,d .,Ruppin,e .,和 Edelman,S. (2005 年)。自然语言的无监督学习。美国国家科学院院刊, 102 (33),11629–11634。
(5)米舍夫,k .,Gjorgjevikj,a .,沃登斯卡,I .,奇库舍夫,L. T .,和特拉亚诺夫,D. (2020)。金融中情感分析的评价:从词典到变形金刚。 IEEE 访问, 8 ,131662–131682。
FlinkSQL 和 Zeppelin 危机事件驱动供应链
开源流媒体技术如何帮助改善新冠肺炎供应链
原载于https://www . data crafts . fr
技术正在帮助世界度过由 Covid19 病毒引起的卫生、经济和社会危机。人工智能帮助科学家了解病毒,以找到治疗方法/疫苗。移动应用程序让远方的家人和朋友保持联系。物联网用于管理通过蓝牙点对点交互传播的病毒。更多关于技术如何帮助的例子在许多博客文章中列出。在这篇博文中,我将重点讨论流媒体技术如何在危机期间帮助供应链。
供应链如何受到挑战?
一张图胜过千言万语。下面是我在宣布封锁前几天在巴黎一家商店拍的照片。吓人吧?焦虑之下,人们开始囤积食物,尽管 CPG 行业已经宣布不会出现短缺。这种行为造成了暂时的短缺,使人们感到恐惧,阻碍了他们对官方信息的信任。他们开始囤积货物,使情况变得更糟。恶性循环。

宣布社会距离后,在巴黎的意大利面货架上肆虐
零售只是大众熟知的一个例子。医院供应链面临的挑战要大得多。Covid19 病例的指数级增长对检测试剂盒、个人防护设备、药物、ICU 病床、呼吸机和工作人员造成了持续的压力。在法国,病人通过医疗列车和航班在城市间转移。他们中的一些人在德国受到照顾。航空公司正在帮助货运活动从中国运送数百万个口罩。每个决定都需要在许多未知的情况下快速做出,并且会影响人们的生活。
但是巨大的挑战伴随着巨大的机遇。
借助物联网和流媒体平台,我们可以实时了解整个供应商、国家甚至行业的库存和需求。当库存因意外需求而更快耗尽时,我们可以立即触发警报。可以对行动进行优先排序,决策得到数据的支持,可以快速做出决策以适应不断变化的模式。此外,该平台有助于收集更多数据,从而使预测更加准确。
开源事件驱动的零售供应链
为了实际起见,让我们看看如何利用 Cloudera 数据平台和 Cloudera 数据流中的开源软件来实现这一愿景。该架构使用:
- MiNiFi :在每个销售点(POS)部署小型数据收集代理,收集销售交易,并实时发送到数据中心或云端。
- 阿帕奇尼菲:收集来自代理商的销售事件,并发送给阿帕奇卡夫卡经纪人。NiFi 还将来自几个数据库的商店和产品数据实时导入 Kafka。
- Apache Flink :处理来自不同 Kafka 主题的数据,以丰富 POS 事件,在时间窗口上聚合它们,检测阈值违反等。Apache Flink 有一个 SQL API,使得编写管道更加容易。
- Apache Zeppelin :是一款交互式笔记本,支持 Apache Flink 和 Flink SQL,用于探索数据、构建实时仪表盘以及与不同团队交流信息。
- Kafka Connect: 收集不同主题的事件,并将其存储到类似 S3 或 ADLS 的云存储中。数据保存在更便宜的存储设备上,用于长期归档或其他批量使用情况。
- Cloudera 机器学习:处理数据,训练机器学习模型,提取特征,根据各种数据集预测未来模式。

面向零售的事件驱动架构的高级架构。商店图标来自 by 视频整形, CC-BY-SA 4.0
在接下来的部分中,我们将关注事件流管道。
数据模型和摄取
我在几篇博客中讨论过 NiFi 和 MiNiFi 功能。我们可以在商店中部署数千个小型代理,并从一个中心位置控制它们。每个代理可以在本地从商店的数据源(数据库、文件或类似 MQTT 的轻量级代理)收集数据,并将其发送到中央 NiFi。关于这部分的更多信息,可以参考我写的关于如何建立一个工业物联网系统,然后用商店代替工厂的详细博文。
[## 如何使用 Apache NiFi、MiNiFi、C2 服务器、MQTT 和 Raspberry Pi 构建 IIoT 系统
您认为构建一个先进的工业物联网原型需要多长时间,它可以:
medium.com](https://medium.com/free-code-camp/building-an-iiot-system-using-apache-nifi-mqtt-and-raspberry-pi-ce1d6ed565bc)
一旦在 NiFi 中接收到数据,我们就可以通过一个简单的流程将事件发布到 Kafka。下面的流程为每个事件附加一个模式名(pos ),并将其推送到 pos Kafka 主题。

NiFi 使用模式注册表向 Kafka 发送 POS 事件
来自商店的事件具有以下属性。
{
"tstx" : "1586615062225", //transaction timestamp
"idtx" : "1871134",// transaction identifier
"idstore" : 5, // store identifier
"idproduct" : 8, // product identifier
"quantity" : 3 // quantity at which the product was sold
}
此事件意味着商店“5”售出了 3 件产品“8”
类似地,NiFi 可以监视几个表,并把新的或更新的行增量地接收到 Kafka 中。在我们的用例中,我们从一个商店表中获取数据,该表中有每个商店的详细信息,比如用户名和位置。
{
"idstore":1,
"namestore":"supermarket",
"city":"paris"
}
我们还从一个产品表中获取数据,该表包含每个产品的详细信息,比如产品名称和在给定频率下观察到的平均销售量。
{
"idproduct":8,
"nameproduct":"hand-sanitiser",
"avgsales":2
}
数据摄取的结果可以在下面的视频中看到,我使用 Streams Messaging Manager 来探索三个 Kafka 主题的内容: pos 、 stores 和 products 。这些主题被划分,事件根据 id 字段进行分配,以便在以后对处理进行负载平衡。我们还准备了第四个主题, alerts ,稍后当我们检测到某个产品的销售速度比平时快时,我们将使用它来发送警报。从视频中,你还可以看到生产者和消费者对每个话题的看法。
卡夫卡主题、事件、生产者和消费者概述
使用 Flink SQL 和 Zeppelin 进行数据探索
Apache Flink 是一个现代的、开源的流引擎,我们将使用它来构建我们的数据管道。Flink 可用于实时 ETL,其中事件被实时转换。它还可以用于计算基于不同时间操作(事件时间和处理时间、窗口、全状态处理等)的高级 KPI。Apache Flink 拥有强大的 API,如 DataStream 和 ProcessFunction APIs,可用于构建现代事件驱动的应用程序。它还具有易于使用的表格和 SQL API,使分析用户可以使用这项技术。我们将利用 SQL API 使这个博客能够被更广泛的社区访问。要使用 Flink SQL,现成的选项是 SQL 客户端 CLI。让我们先用它来探究 POS 主题的内容:
使用 FlinkSQL CLI 客户端实时读取事件
Flink SQL CLI 非常适合简单的分析。但是,对于想要测试和修改几个查询的数据探索来说,这并不方便。幸运的是,数据科学笔记本 Apache Zeppelin 支持运行 Flink 和 Flink SQL 代码。我们将在接下来的章节中使用它。我们开始吧!
我们手里有什么?
为了在 FlinkSQL 中处理我们的流,我们需要创建表。一个表定义了 Kafka 主题中的事件模式,并提供了对 SQL API 的访问。例如,要创建我们的 POS 流的表,我们可以使用:
CREATE TABLE pos (
tstx BIGINT,
idtx BIGINT,
idstore INT,
idproduct INT,
quantity INT,
timetx AS CAST(from_unixtime(floor(tstx/1000)) AS TIMESTAMP(3)),
WATERMARK FOR timetx AS timetx - INTERVAL '10' SECOND
) WITH (
'connector.type' = 'kafka',
'connector.version' = 'universal',
'connector.topic' = 'pos',
'connector.startup-mode' = 'latest-offset',
'connector.properties.bootstrap.servers' = 'kafka-url:9092',
'connector.properties.group.id' = 'FlinkSQLPOS',
'format.type' = 'json'
);
这创建了一个名为 pos 的表,指向 pos Kafka 主题中的事件。这些事件采用 JSON 格式,拥有我们之前介绍的五个属性。除了这些属性之外,它还定义了一个事件时间字段,该字段是根据事务时间戳(tstx)计算的,并定义了一个 10 秒的水印。该表使用 Flink Kafka 连接器连接到 edge2ai-1.dim.local:9092 中运行的集群。类似地,在 Flink SQL 中使用商店和产品表之前,我们需要创建它们。
CREATE TABLE stores (
idstore INT,
namestore STRING,
city STRING
) WITH (
'connector.type' = 'kafka',
'connector.version' = 'universal',
'connector.topic' = 'stores',
'connector.startup-mode' = 'earliest-offset',
'connector.properties.bootstrap.servers' = 'kafka-url:9092',
'connector.properties.group.id' = 'FlinkSQLStore',
'format.type' = 'json'
);CREATE TABLE products (
idproduct INT,
nameproduct STRING,
avgsales INT
) WITH (
'connector.type' = 'kafka',
'connector.version' = 'universal',
'connector.topic' = 'products',
'connector.startup-mode' = 'earliest-offset',
'connector.properties.bootstrap.servers' = 'kafka-url:9092',
'connector.properties.group.id' = 'FlinkSQLProducts',
'format.type' = 'json'
);
我们准备好查询我们的表: SELECT * FROM pos 。这就像在 SQL 数据库中查询数据一样简单。这是它在齐柏林飞艇中的样子。事件不断地从 Kafka 中被消费并打印在 UI 中。FlinkSQL 作业在 Flink 仪表板和 Yarn UI 上可见。
在 Zeppelin 中创建 FlinkSQL 表
Zeppelin 有一个嵌入在笔记本中的简单数据可视化的好特性。我们可以用它来绘制按产品和商店分组的事件。这对于快速浏览非常有用,仅适用于结果集,而不是所有数据或时间窗口。真正的分组应该以后在 FlinkSQL 里做。

按商店组织的售出产品数量图表
流到流的连接和丰富
在上图中,我们可以看到按产品和商店分组的事件。但是,我们只有产品和店铺 id。对理解正在发生的事情没什么用。我们可以通过将产品和商店流加入 POS 流来丰富交易。使用 idproduct 和 idstore ,我们可以获得其他元数据,比如产品名称和城市。
请记住,POS 流是一个高速的仅附加流,在数据仓库世界(DWH)中也称为事实表。商店和产品是缓慢变化的流,在 DWH 世界被称为维度表。它们也是只附加的流,其中更新是具有现有 ID 的新事件。即使流连接看起来类似于表连接,但还是有根本的区别。例如,如果我有几个关于产品 x 的事件,我将加入哪一个 POS 事件?最新的那个?时间戳最近的那个?为了保持这篇博客的简洁,我将暂时忽略这些方面,我将在未来几天发表一篇关于 streams joins 的深度博客。
转到 FlinkSQL,这里是我们如何加入我们的三个流:
SELECT tstx,idtx, namestore, city, nameproduct, quantity
FROM
pos AS po,
stores AS s,
products AS pr
WHERE po.idstore = s.idstore AND po.idproduct = pr.idproduct;
使用 Zeppelin 图表,我们可以看到我们的产品在每个城市的销售速度。下面的视频展示了查询的执行。
使用 SQL 连接丰富数据流
快速检测用完的产品
现在我们对数据有了更好的理解,我们可以寻找产品销售模式,并将它们与历史数据进行比较。我们不能让某人一直监控仪表板,我们希望生成警报。
请记住,在我们的 products 表中,我们有一个列 avgsales,它告诉我们在给定的时间范围(例如 4 小时)内,我们通常在每个商店销售的每个产品的平均数量。出于演示的目的,我们将考虑一个非常短的时间尺度(15 秒)来加速。那么如何才能检测出一个产品卖的快呢?
首先,我们需要在 15 秒的时间窗口内聚合我们的 POS 事件。对于每个窗口,我们将计算售出数量的总和。我们希望每个商店也这样做,因此也按商店分组。该查询如下所示。请注意,该查询引入了两个新列,starttime 和 endtime,分别表示时间窗口的开始和结束。
SELECT TUMBLE_START(timetx, INTERVAL '15' SECOND) as starttime, TUMBLE_END(timetx, INTERVAL '15' SECOND) as endtime, idstore, idproduct, SUM(quantity) as aggregate
FROM pos
GROUP BY idproduct,idstore, TUMBLE(timetx, INTERVAL '15' SECOND)
一旦我们有了聚合流,我们希望将它与商店和产品流结合起来,以获得其他字段,如 avgsales。我们希望将计算出的总量 aggregate 与 hostorical avgsales 进行比较。这给了我们完整的查询:
SELECT starttime, endtime, nameproduct, aggregate, avgsales, namestore, city
FROM
(
SELECT TUMBLE_START(timetx, INTERVAL '30' SECOND) as starttime,
TUMBLE_END(timetx, INTERVAL '30' SECOND) as endtime, idstore,
idproduct, SUM(quantity) as aggregate
FROM pos
GROUP BY idproduct,idstore, TUMBLE(timetx, INTERVAL '30' SECOND)
) AS a,
products as p,
stores as s
WHERE aggregate > avgsales AND a.idproduct = p.idproduct AND a.idstore = s.idstore;
下面的视频展示了 Zeppelin 中查询的执行和 Flink 仪表板中生成的查询计划。我们可以观察到,在所有城市,洗手液的购买速度都比平时快。
当产品销售速度比平时快时发出警报
创建新的通知流
既然我们对我们的数据处理和探索感到满意,我们需要创建一个新的警报流。该流可用于通过移动应用程序向商店经理发送推送通知。收到此通知后,商店经理可以要求员工优先重新装满特定产品的货架。这在员工数量可能减少的危机时期非常重要。这将有助于主动管理当地活动,以避免空货架,从而减少焦虑和购买可能无法获得的产品的冲动。
FlinkSQL 也可以用来创建新的 Kafka 流。我们必须像以前一样创建一个新表。
CREATE TABLE alerts (
starttime TIMESTAMP(3),
endtime TIMESTAMP(3),
nameproduct STRING,
aggregate INT,
avgsales INT,
namestore STRING,
city STRING
) WITH (
'connector.type' = 'kafka',
'connector.version' = 'universal',
'connector.topic' = 'alerts',
'connector.startup-mode' = 'latest-offset',
'connector.properties.bootstrap.servers' = 'kafka-url:9092',
'connector.properties.group.id' = 'FlinkSQLAlerting',
'format.type' = 'json'
);
然后,我们可以将之前的聚合和警报查询嵌入到 insert into 语句中。
INSERT INTO alerts
SELECT starttime, endtime, nameproduct, aggregate, avgsales,
namestore, city
FROM
(
SELECT TUMBLE_START(timetx, INTERVAL '15' SECOND) as
starttime, TUMBLE_END(timetx, INTERVAL '15' SECOND) as
endtime, idstore, idproduct, SUM(quantity) as aggregate
FROM pos
GROUP BY idproduct,idstore, TUMBLE(timetx, INTERVAL '15'
SECOND) ) AS a,
products as p,
stores as s
WHERE aggregate > avgsales AND a.idproduct = p.idproduct AND
a.idstore = s.idstore;
这样,所有生成的警报都被发送到 alerts Kafka 主题中,就像我们在 SMM 看到的那样。从 Kafka,我们可以让 NiFi、KStreams 或 Java 应用程序订阅这些警报事件,并将它们推送到我们的商店管理器中。
在 Kafka 中存储警报以支持下游应用程序
结论
在这篇博客中,我们解释了流媒体平台如何让任何供应链获得实时洞察。在需求巨大、不确定性不断增加的危机形势下,这些见解将改变游戏规则。这正是我们今天面临的危机。
我们还展示了如何使用 Apache NiFi、Apache Flink 和 Apache Zeppelin 等工具构建一个高级的事件驱动警报系统,而无需任何代码。Flink 通过一个简单的 SQL API 提供高级流操作,如流连接和窗口。建立一个先进的实时供应链系统变得人人可及。CDF 等事件流平台将所有这些工具打包成一个统一的堆栈,易于部署和使用。
在以后的博客中,我将介绍 Flink 和 Flink SQL 中的流连接类型。如果你对这些话题有兴趣,过几天再来看看这个博客。
谢谢你读到这里。一如既往,欢迎反馈和建议。
想要 Jupyter 的进度条吗?
对你的长时间循环进行健全性检查(和一点视觉风格)

如何使用循环可以告诉你很多编程技巧。
介绍
循环可能非常有效,但有时运行时间太长。特别是,随着您更多地使用大数据,您将不得不处理大量数据集,并使用循环来执行每个观察的计算。
当你不得不花几分钟甚至几个小时在笔记本上寻找星号时,循环一点也不好玩。最糟糕的是,当循环有数千次迭代时,您不知道循环是否正常工作,或者只是因为数据中的一些愚蠢错误而停留在某次迭代上。
好消息是你可以用tqdm库为 Jupyter 笔记本创建进度条。这个库非常容易使用,而且它也给难看的黑白笔记本带来了某种风格。此外,在进行过程中,您还可以让条形图显示循环正在进行的迭代。不错吧。在这里,观看它的行动:
[## 通过我的推荐链接加入 Medium-BEXGBoost
获得独家访问我的所有⚡premium⚡内容和所有媒体没有限制。支持我的工作,给我买一个…
ibexorigin.medium.com](https://ibexorigin.medium.com/membership)
获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:
留在循环中,不用花无数时间浏览下一个突破;我们的算法识别…
alphasignal.ai](https://alphasignal.ai/?referrer=Bex)
如果你想知道
tqdm到底是什么意思,这个词是一个类似的阿拉伯词的缩写,意思是进步。这就对了,上下文关系。
可点击的目录(仅限网络)
∘ 简介
∘ 安装
∘ 自动进度条
∘ 嵌套进度条
∘ 手动控制进度条
∘ 总结
装置
安装tqdm对于脚本来说非常简单。对于 Jupyter 笔记本或 Jupyter 实验室,还需要一些额外的步骤(感谢用户, Sam Wilkinson 展示了这些方法):
- 安装
tqdm(这一步对于脚本来说足够了):
pip install tqdm # pip
conda install -c conda-forge tqdm # conda
2.Jupyter 笔记本(经典款)的后续产品:
pip install ipywidgets
jupyter nbextension enable --py widgetsnbextension
3.继续 Jupyter 实验室(加上所有上述步骤):
jupyter labextension install @jupyter-widgets/jupyterlab-manager
如果你想知道更多关于经典 Jupyter 和 JupyterLab 的区别,请阅读这个 StackOverflow 线程。
自动进度条
安装后,库的基本用法非常简单。对于笔记本电脑,您可以像这样导入主模块:
tqdm子模块提供模块的所有灵活性和大部分功能。trange是一个使用range()功能创建进度条的快捷功能。让我们从这个开始:
trange只提供单一功能。对于除了range objects之外的其他类型的迭代,我们将使用tqdm。让我们使用tqdm来看看同样的进度条:
一般的语法就是这样。在您的循环中,只需将 iterable 包装在tqdm()中。
Iterables 基本上是任何可以循环的对象,比如列表、生成器对象等。
带有进度条的嵌套 for 循环
进度条的另一个很好的用例是在循环中使用嵌套的。所有循环级别的语法都是相同的。为了区分进度条,我们可以使用tqdm()的另一个参数叫做desc。它将允许我们命名酒吧:
输出中进度条的数量取决于外部的 iterable 级别。所以当你对外层有一个很长的描述时,要注意这一点。内部水平条的数量与可迭代的长度一样多。
手动控制进度条
有时,你会处理一个很长的循环,并且很难观察到循环在哪个成员上工作。tqdm为此提供了一个非常有用的替代方案:
这比使用挤出输出单元格的print语句要好得多。在上面的代码中,我们首先在循环之外创建了这个条。接下来,我们使用in后的 bar,编写循环体。为了指示循环的成员,我们使用进度条的set_description()方法并传递所需的字符串。
包裹
在这篇文章中,我只展示了简单循环中进度条的例子。当您处理更复杂的问题时,如对数千个文件执行操作或迭代百万行长的数据帧时,您会看到它们的好处。还有一些东西我没有包括在这篇文章中,所以一定要查看库的文档来了解更多!
如果你喜欢这篇文章,请分享并留下反馈。作为一名作家,你的支持对我来说意味着一切!
阅读更多文章:
[## 来自 Kagglers:DS 和 ML 的最佳项目设置
来自顶级 Kagglers 的项目成功最佳实践的集合
towardsdatascience.com](/from-kagglers-best-project-setup-for-ds-and-ml-ffb253485f98) [## 熊猫合并/连接数据终极指南
从半连接/反连接到验证数据合并
towardsdatascience.com](/ultimate-guide-to-merging-joining-data-in-pandas-c99e482a73b9) [## 掌握 Seaborn 中的 catplot():分类数据可视化指南。
如果你能在锡伯恩做到,那就在锡伯恩做吧,#2
towardsdatascience.com](/mastering-catplot-in-seaborn-categorical-data-visualization-guide-abab7b2067af) [## 我的情节糟透了。以下是我如何修复它们。
你的,在某种意义上,可能也是。
towardsdatascience.com](/deep-guide-into-styling-plots-delivering-effective-visuals-12e40107b380) [## 掌握 plt.annotate()让您的情节更上一层楼
上帝保佑所有阅读 Matplotlib 文档的人
towardsdatascience.com](/finally-learn-to-annotate-place-text-in-any-part-of-the-plot-d9bcc93c153f)
每个数据科学家都需要一些火花魔法
如何借助 Spark Magic 改进您的数据探索和高级分析

CC BY-SA 3.0,肯尼斯·詹森
虽然数据科学被吹捧为 21 世纪最性感的工作,但它也不能幸免于臭名昭著的帕累托法则或 80/20 法则。商业数据科学家 80%的时间花在寻找、清理和准备数据上。这是数据科学家工作中效率最低也是最可怕的部分。
互联网为如何打破数据科学的 80/20 法则提供了无尽的意见,但好的建议却很难得到。低生产率的一个主要原因在于数据准备的双重性:
- 快速访问、连接和聚合存储在企业数据湖中的大数据
- 探索和可视化笔记本中的数据和统计数据,这些数据和统计数据对 Python 包具有复杂的依赖性
大数据大部分是非结构化的,存储在生产环境中,存在企业治理和安全限制。快速访问数据需要昂贵的分布式系统,这些系统由 IT 部门集中管理,并且必须与其他数据科学家和分析师共享。
Spark 是数据行业在分布式数据湖中处理数据的黄金标准。但是,要经济高效地使用 Spark 集群,甚至允许多租户,很难适应单独的需求和依赖性。分布式数据基础设施的行业趋势是朝着短暂集群发展,这使得数据科学家更难部署和管理他们的 Jupyter 笔记本环境。
毫不奇怪,许多数据科学家在本地使用高规格笔记本电脑工作,在那里他们可以更容易地安装和维护他们的 Jupyter 笔记本环境。到目前为止还可以理解。那么,许多数据科学家如何将他们的本地开发环境与生产数据湖中的数据联系起来呢?他们用 Spark 将 csv 文件具体化,并从云存储控制台下载它们。
从云存储控制台手动下载 csv 文件既不高效,也不是特别健壮。以终端用户友好和透明的方式将本地 Jupyter 笔记本与远程集群无缝连接不是更好吗?认识一下 SparkMagic!
Jupyter 笔记本的 SparkMagic

麻省理工学院 Sandro Pereira 授权的合理使用和公共领域图标和 svg
Sparkmagic 是一个通过 Livy REST API 与 Jupyter 笔记本中的远程 Spark 集群交互工作的项目。它提供了一套 Jupyter 笔记本单元魔法和内核,将 Jupyter 转变为远程集群的集成 Spark 环境。
SparkMagic 允许我们
- 运行多种语言的 Spark 代码和
- 针对任何远程火花簇,使用 SparkContext 和 HiveContext 自动创建 SparkSession
- 提供 SQL 查询的自动可视化
- 轻松访问 Spark 应用程序日志和信息
- 将 Spark 查询的输出捕获为一个本地 Pandas 数据帧,以便与其他 Python 库(例如 matplotlib)轻松交互
- 将本地文件或 Pandas 数据帧发送到远程集群(例如,将预先训练的本地 ML 模型直接发送到 Spark 集群)
您可以使用以下 Dockerfile 文件构建一个支持 SparkMagic 的 Jupyter 笔记本:
FROM jupyter/all-spark-notebook:7a0c7325e470USER $NB_USER
RUN pip install --upgrade pip
RUN pip install --upgrade --ignore-installed setuptools
RUN pip install pandas --upgrade
RUN pip install sparkmagic
RUN mkdir /home/$NB_USER/.sparkmagic
RUN wget [https://raw.githubusercontent.com/jupyter-incubator/sparkmagic/master/sparkmagic/example_config.json](https://raw.githubusercontent.com/jupyter-incubator/sparkmagic/master/sparkmagic/example_config.json)
RUN mv example_config.json /home/$NB_USER/.sparkmagic/config.json
RUN sed -i 's/localhost:8998/host.docker.internal:9999/g' /home/$NB_USER/.sparkmagic/config.json
RUN jupyter nbextension enable --py --sys-prefix widgetsnbextension
RUN jupyter-kernelspec install --user --name SparkMagic $(pip show sparkmagic | grep Location | cut -d" " -f2)/sparkmagic/kernels/sparkkernel
RUN jupyter-kernelspec install --user --name PySparkMagic $(pip show sparkmagic | grep Location | cut -d" " -f2)/sparkmagic/kernels/pysparkkernel
RUN jupyter serverextension enable --py sparkmagic
USER root
RUN chown $NB_USER /home/$NB_USER/.sparkmagic/config.json
CMD ["start-notebook.sh", "--NotebookApp.iopub_data_rate_limit=1000000000"]
USER $NB_USER
构建图像,并用以下内容进行标记:
docker build -t sparkmagic
在 Spark Magic 的支持下启动一个本地 Jupyter 容器,挂载当前的工作目录:
docker run -ti --name \"${PWD##*/}-pyspark\" -p 8888:8888 --rm -m 4GB --mount type=bind,source=\"${PWD}\",target=/home/jovyan/work sparkmagic
为了能够连接到远程 Spark 集群上的 Livy REST API,您必须在本地计算机上使用 ssh 端口转发。获取远程集群的 IP 地址并运行:
ssh -L 0.0.0.0:9999:localhost:8998 REMOTE_CLUSTER_IP
首先,使用启用了 SparkMagic 的 PySpark 内核创建一个新的笔记本,如下所示:

[OC]
在启用 SparkMagic 的笔记本中,您有一系列单元 Magic 可用于本地笔记本以及作为集成环境的远程 Spark 集群。% %帮助魔术打印出所有可用的魔术命令:

[OC]
您可以使用 %%configure 魔法配置您的远程 Spark 应用程序:

正如您在上面的截图中所看到的,SparkMagic 自动启动了一个远程 PySpark 会话,并提供了一些有用的链接来连接到 Spark UI 和日志。
该笔记本集成了两种环境:
- %%local 它在您的笔记本电脑和由 jupyter docker 映像提供的 anaconda 环境上本地执行单元
- %%spark 它通过远程 spark 集群上的 PySpark REPL 经由 Livy REST API 远程执行单元
下面的代码单元格首先远程导入 SparkSql 类型。其次,它使用远程 SparkSession 将英格玛-JHU-新冠肺炎数据集加载到我们的远程 Spark 集群中。我们可以看到遥控器的输出。在笔记本中显示()命令:

[OC]
但这只是魔法的开始。我们可以将 dataframe 注册为一个 Hive 表,并使用 %%sql 魔法对远程集群上的数据执行 Hive 查询,并在本地笔记本中创建结果的自动化可视化。虽然这不是火箭科学,但对于数据分析师和数据科学项目早期阶段的快速数据探索来说,这是非常方便的。

SparkMagic 真正有用的特性是在本地笔记本和远程集群之间无缝传递数据。数据科学家的日常挑战是创建和持久化他们的 Python 环境,同时使用短暂的集群与他们公司的数据湖进行交互。
在以下示例中,您可以看到我们如何将 seaborn 作为本地库导入,并使用它来绘制 covid_data pandas 数据框。但是这些数据来自哪里呢?它是由远程火花簇创建和发送的。神奇的 %%spark -o 允许我们定义一个远程变量,在单元执行时传递给本地笔记本上下文。我们的变量 covid_data 是
- 远程集群上的 SparkSQL 数据帧和
- 当地 Jupyter 笔记本中的熊猫数据框

使用 Pandas 将远程集群中的大数据聚合到本地的 Jupyter 笔记本中的能力对数据探索非常有帮助。例如,使用 Spark 将直方图的数据预聚合到按箱的计数中,以使用预聚合的计数和简单的条形图在 Jupyter 中绘制直方图。另一个有用的特性是能够使用神奇的% % Spark-o covid _ data-m sample-r 0.5对远程 Spark 数据帧进行采样
集成环境还允许您使用神奇的 %%send_to_spark 将本地数据发送到远程 Spark 集群
支持的两种数据类型是 Pandas DataFrames 和string。要向远程 Spark 集群发送更多或更复杂的内容,例如用于评分的经过训练的 scikit 模型,您可以使用序列化来创建用于传输的字符串表示:
import pickle
import gzip
import base64serialised_model = base64.b64encode(
gzip.compress(
pickle.dumps(trained_scikit_model)
)
).decode()
将 PySpark 工作负载部署到生产中?
如您所见,这种短暂的 PySpark 集群模式有一个很大的痛点:用 Python 包引导 EMR 集群。当您部署生产工作负载时,这个问题不会消失。您可以在我之前的博客文章中阅读如何使用 PEX 加速 PySpark 应用程序在短暂的 AWS EMR 集群上的部署:
[## PEX——AWS EMR 工作负载完美 PySpark 部署的秘方
如何使用 PEX 加速 PySpark 应用程序在临时 AWS EMR 集群上的部署
towardsdatascience.com](/pex-the-secret-sauce-for-the-perfect-pyspark-deployment-of-aws-emr-workloads-9aef0d8fa3a5) 
Jan 是公司数据转型方面的成功思想领袖和顾问,拥有将数据科学大规模应用于商业生产的记录。他最近被 dataIQ 评为英国 100 位最具影响力的数据和分析从业者之一。
在 LinkedIn 上连接:【https://www.linkedin.com/in/janteichmann/】
阅读其他文章:https://medium.com/@jan.teichmann
每一个复杂的数据帧操作,直观地解释和可视化

图片作者。
熔化、旋转、连接、爆炸等
Pandas 提供了各种各样的数据帧操作,但其中许多都很复杂,可能看起来不容易实现。本文将介绍 8 种基本的数据帧操作方法,几乎涵盖了数据科学家需要了解的所有操作功能。每种方法都包括解释、可视化、代码和记住它的技巧。
所有图片由作者提供。
在枢轴上转动
透视一个表会创建一个新的“透视表”,它将数据中的现有列作为新表的元素进行投影,即索引、列和值。将成为索引的初始数据帧中的列和列显示为唯一值,这两个列的组合将显示为值。这意味着透视不能处理重复值。

透视名为df的数据帧的代码如下:
df.pivot(index='foo', columns='bar', values='baz')
记住:轴心是——在数据处理领域之外——围绕某种对象的旋转。在运动中,一个人可以绕着他们的脚“旋转”:熊猫的枢轴是类似的。原始数据帧的状态围绕一个数据帧的中心元素旋转成一个新的数据帧。有些元素确实是旋转或变换的(如列'bar')。
熔化
熔化可以被认为是一种“逆透视”,因为它将基于矩阵的数据(有两个维度)转换为基于列表的数据(列表示值,行表示唯一的数据点),而透视则相反。考虑一个二维矩阵,其中一个维度为“B”和“C”(列名),另一个维度为“a”、“b”和“c”(行索引)。
我们选择一个 ID、一个维度和一列或多列来包含值。包含值的列被转换为两列:一列用于变量(值列的名称),另一列用于值(其中包含的数字)。

结果是 ID 列的值(a、b、c)和值列(B、C)的每个组合,以及相应的值,以列表格式组织。
熔化操作可以在数据框df中这样执行:
df.melt(id_vars=['A'], value_vars=['B','C'])
记忆:熔化像蜡烛一样的东西,就是把一个固化的、复合的物体变成几个小得多的、单独的元素(蜡滴)。熔化一个二维数据帧解包它的固化结构,并将它的片段作为单个条目记录在一个列表中。
激增
分解是去除数据中列表的有用方法。当一列展开时,其中的所有列表都作为新行列在同一个索引下(为了避免这种情况,只需随后调用.reset_index())。字符串或数字之类的非列表项不受影响,空列表是 NaN 值(您可以使用.dropna()清除这些值)。

在 DataFrame df中分解一列‘A’非常简单:
df.explode(‘A’)
记住:分解一个东西会释放它所有的内部内容——分解一个列表会分离它的元素。
堆
堆叠采用任意大小的数据帧,并将列“堆叠”为现有索引的子索引。因此,得到的数据帧只有一列和两级索引。

堆叠一个名为 df 的表就像df.stack()一样简单。
为了访问比如狗的身高,只需调用两次基于索引的检索,比如df.loc[‘dog’].loc[‘height’]。
要记住:从视觉上来说,stack 取一个表的二维度,可以将列堆叠成多级索引。
出栈
拆分采用多索引数据帧并将其拆分,将指定级别中的索引转换为新数据帧的列及其相应的值。在一个表上调用一个 stack 后跟一个 unstack 不会改变它(原谅一个'【T6]'的存在)。

拆分中的一个参数是它的级别。在列表索引中,索引为-1 将返回最后一个元素;关卡也是如此。级别-1 表示最后一个索引级别(最右边的一个)将被拆分。作为另一个例子,当级别被设置为 0(第一索引级别)时,其中的值变成列,并且随后的索引级别(第二索引级别)变成转换的数据帧的索引。

拆垛可以和堆垛一样进行,但是使用水平参数:df.unstack(level=-1)。
记住 : Unstack 的意思是“撤销一个堆栈”。
合并
合并两个数据帧就是在一个共享的“键”中按列(水平)组合它们。这个键允许表的组合,即使它们的顺序不同。默认情况下,完成的合并数据帧会将后缀_x和_y添加到值列。

为了合并两个数据帧df1和df2(其中df1包含leftkey,df2包含rightkey),调用:
df1.merge(df2, left_on='leftkey', right_on='rightkey')
合并不是 pandas 的功能,而是附属于数据帧。通常假设合并所附加到的数据帧是“左表”,而在函数中作为参数调用的数据帧是“右表”,并带有相应的键。
默认情况下,merge 函数执行所谓的内部连接:如果每个数据帧都有一个键没有在另一个数据帧中列出,则它不会包含在合并的数据帧中。另一方面,如果一个键在同一个数据帧中列出两次,则相同键的值的每个组合都会在合并的表中列出。例如,如果键foo的df1有 3 个值,而同一个键的df2有 2 个值,那么在最终的数据帧中将有 6 个带有leftkey=foo和rightkey=foo的条目。

记住:你合并数据帧就像你横向驾驶时合并车道一样。想象每根柱子都是高速公路上的一条车道;为了合并,它们必须水平合并。
加入
联接通常优于合并,因为它在水平联接两个数据帧时具有更清晰的语法和更广泛的可能性。联接的语法如下:
df1.join(other=df2, on='common_key', how='join_method')
使用联接时,公共键列(类似于 merge 中的right_on和left_on)必须命名为相同的名称。how参数是引用四种方法之一的字符串join可以组合两个数据帧:
‘left’:包含df1的所有元素,只有当df2的元素的键是df1的键时,才会伴随df2的元素。否则,df2的合并数据帧的缺失部分将被标记为 NaN。‘right’:‘left’,但是在另一个数据框架上。包含df2的所有元素,只有当df1的元素的键是df2的键时,才会伴随df1的元素。‘outer’:包含两个数据帧中的所有元素,即使一个键在另一个数据帧中不存在——缺少的元素标记为 NaN。‘inner’:仅包括其键同时出现在两个数据帧键中的元素(交集)。默认为合并。
记住:如果你使用过 SQL,单词‘join’应该立即与列相加联系起来。如果没有,“加入”和“合并”在定义上有非常相似的含义。
串联
尽管合并和连接是水平工作的,但串联或简称为串联,是按行方式(垂直)附加数据帧。例如,考虑两个具有相同列名的数据帧df1和df2,用pandas.concat([df1, df2])连接起来:

虽然您可以通过将 axis 参数设置为1来使用 concat 进行列连接,但是使用 join 会更简单。
请注意,concat 是一个 pandas 函数,而不是 DataFrame 中的一个。因此,它接受一个要连接的数据帧列表。
如果一个 DataFrame 有一个列没有包含在另一个 data frame 中,默认情况下它将被包含在内,缺少的值列为 NaN。为了防止这种情况,添加一个额外的参数join=’inner’,它将只连接两个数据帧共有的列。

记住:在列表和字符串中,额外的条目可以连接起来。串联是对现有主体的附加元素,而不是新信息的添加(就像按列连接一样)。因为每个索引/行都是一个单独的项,所以串联会向数据帧添加额外的项,数据帧可以看作是一个行列表。
Append 是组合两个数据帧的另一种方法,但它执行的功能与 concat 相同,但效率较低且通用性较差。
有时候内置函数是不够的。
尽管这些函数涵盖了您可能需要操作数据的广泛内容,但有时所需的数据操作对于一个甚至一系列函数来说过于复杂。探索复杂的数据操作方法,如解析器函数、迭代投影、高效解析等,请点击此处:
[## 将您的数据辩论技能提升到一个新水平的提示、技巧和技术
带有图表、代码和示例
感谢阅读!
如果你对最新的文章感兴趣,可以考虑订阅。如果你想支持我的写作,通过我的推荐链接加入 Medium 是一个很好的方式。干杯!
每个机器学习算法都可以表示为一个神经网络

算法中的算法
似乎机器学习的所有工作——从 20 世纪 50 年代的早期研究开始——都是随着神经网络的创建而累积起来的。从逻辑回归到支持向量机,相继提出了一个又一个新的算法,但神经网络是算法中的算法,是机器学习的巅峰。这是对机器学习的普遍概括,而不是一次尝试。
从这个意义上说,它更像是一个框架和概念,而不仅仅是一个算法,这一点很明显,因为在构建神经网络时有很大的自由度——隐藏层和节点数、激活函数、优化器、损失函数、网络类型(卷积、递归等)。),以及专业层(批次定额、退学等)。),不一而足。
从神经网络是一个概念而不是一个严格的算法的角度来看,可以得出一个非常有趣的推论:任何机器学习算法,无论是决策树还是 k 近邻算法,都可以用神经网络来表示。虽然直觉上可以用几个例子来理解这一点,但这种说法可以用数学来证明。
让我们首先定义什么是神经网络:它是由输入层、隐藏层和输出层组成的体系结构,每层的节点之间有连接。信息通过线性变换(权重和偏差)以及非线性变换(激活函数)从输入层转换到输出层。有一些方法来更新模型的可训练参数,以便…
逻辑回归简单地定义为标准回归,每个输入都有乘法系数,并添加了一个额外的截距,所有这些都通过一个 sigmoid 函数。这可以通过没有隐藏层的神经网络来建模;结果是通过一个 sigmoid 输出神经元的多重回归。

通过用线性激活函数替换输出神经元激活函数,可以对线性回归进行同样的建模(它只是映射输出 f ( x ) = x,换句话说,它不做任何事情)。
支持向量机(SVM)算法试图利用所谓的“核技巧”将数据投影到新的空间中,从而优化数据的线性可分性。在数据被转换后,该算法绘制出沿着类边界最好地分离数据的超平面。超平面被简单地定义为现有维度的线性组合,很像二维中的一条线和三维中的一个平面。从这个意义上说,人们可以把 SVM 算法看作是把数据投影到一个新的空间,然后进行多元回归。神经网络的输出可以通过某种有界输出函数来实现概率输出。

当然,可能需要实施一些限制,例如限制节点之间的连接和固定某些参数——当然,这些变化不会损害“神经网络”标签的完整性。也许需要添加更多的层来确保支持向量机的这种表示能够像真实交易一样执行。
像决策树算法这样的基于树的算法要稍微复杂一些。如何构建这种神经网络的答案在于分析它如何划分其特征空间。当一个训练点遍历一系列分裂节点时,特征空间被分裂成若干超立方体;在二维示例中,垂直线和水平线创建了正方形。

来源:DataCamp 社区。图片免费分享。
因此,沿着这些线分割特征空间的类似方式可以用更严格的激活来模拟,如阶跃函数,其中输入是一个值或另一个值,本质上是分隔线。权重和偏差可能需要实现值限制,因此仅用于通过拉伸、收缩和定位来定向分割线。为了获得概率结果,结果可以通过激活函数传递。

虽然算法的神经网络表示和实际算法之间存在许多技术差异,但关键是网络表达了相同的思想,并且可以用与实际算法相同的策略和性能来处理问题。
但是,也许您不满足于将算法粗略地转换成神经网络形式,或者希望看到对 k-最近邻或朴素贝叶斯等更复杂的算法的普遍应用,而不是基于具体情况。答案在于通用逼近定理——这是神经网络取得巨大成功背后的数学解释——本质上是说,足够大的神经网络可以以任意精度模拟任何函数。说有某个函数 f ( x )表示数据;对于每个数据点( x , y ), f ( x )总是返回一个等于或非常接近于 y 的值。

建模的目标是找到这个代表性的或基本事实函数 f ( x ),我们将它表示为 p ( x )用于预测。所有机器学习算法处理这项任务的方式都非常不同,将不同的假设视为有效,并给出它们的最佳结果, p ( x )作为结果。如果有人要写出算法接近创建 p ( x )的方式,你可能会得到从条件列表到纯数学运算的任何东西。描述函数如何将目标映射到输入的函数实际上可以采用任何形式。

有时,这些功能会起作用。其他时候,它们没有——它们有固定数量的参数,使用它们是一个要么接受要么放弃的问题。不过,神经网络在寻找 f ( x )的方式上略有不同。
任何函数都可以用许多类似台阶的部分来合理地近似,台阶越多,近似就越精确。

这些步骤中的每一个都在神经网络中表示为具有 sigmoid 激活函数的隐藏层中的节点,sigmoid 激活函数本质上是概率阶跃函数。本质上,每个节点被“分配”给功能的一部分, f ( x )。然后,通过权重和偏置系统,网络可以确定节点的存在,如果神经元应该为特定输入激活,则将 sigmoid 函数的输入吹向无穷大(输出为 1),否则吹向负无穷大。这种委派节点来寻找数据函数的特定部分的模式不仅在数字数据中观察到,而且在图像中也观察到。
虽然通用近似定理已经扩展到适用于其他激活函数,如 ReLU 和神经网络类型,但该原理仍然成立:神经网络是为了完美而创建的。神经网络不再依赖于复杂的数学方程和关系系统,而是将自己的一部分委托给数据函数的一部分,并在指定的区域内强力记忆概括。当这些节点聚合成一个巨大的神经网络时,结果是一个看似智能的模型,而实际上它们是巧妙设计的近似器。
鉴于神经网络至少在理论上可以构建一个基本上和你想要的一样精确的函数(节点越多,逼近就越精确,当然不考虑过拟合的技术细节),具有正确结构的神经网络可以模拟任何其他算法的预测函数p(x)。这一点对于其他任何机器学习算法都不能说。
神经网络使用的方法不是优化现有模型中的几个参数,如多项式曲线或节点系统。神经网络是数据建模的一个特定视角,它不寻求充分利用任何独立系统,而是直接逼近数据函数;我们如此熟悉的神经网络架构仅仅是一个想法的模型表现。
随着神经网络的力量和对深度学习这一无底洞领域的不断研究,数据——无论是视频、声音、流行病学数据还是二者之间的任何数据——都将能够以前所未有的程度进行建模。神经网络确实是算法中的算法。
除非另有说明,所有图片均由作者创作。
神经网络可解释性基础

作者创建的图像
激活最大化、灵敏度分析等
神经网络是机器学习的巅峰:它们可以通过将极其复杂的功能与同样复杂的结构进行匹配来建模。充满了非线性和信息传播流,数据科学家的思维模式通常是“我们牺牲可解释性来获得能力。”的确——算法的黑盒性质已经被大多数人接受,但它不应该如此。
理解算法如何做出决策对于使用它们的应用程序来说至关重要。在世界各地的组织中,神经网络被用来决定某人是否应该获得贷款,他们是否有资格获得一份工作,甚至是否有人犯了罪——以“它在训练集上表现良好”的态度离开无法解释的算法来解决这些重要问题是危险和不道德的。
学习如何解释神经网络是每个深度学习工程师都应该学习的东西,但可悲的是大多数人都没有。通过能够解释这个强大的建模器,您将能够在数据中反映的严重问题变成更大的问题之前阻止它们,并获得人类可以理解的知识,比如肺癌的症状,这对于无法访问先进技术的应用程序和位置来说非常有价值。
神经网络的解释将人的因素带入了这种人工构造中。
本文将涵盖解释神经网络过程的三种方法和评估解释质量的一种方法。
激活最大化
激活最大化是一种可视化神经网络的方法,旨在最大化某些神经元的激活。在正常训练期间,人们将迭代地调整网络的权重和偏差,使得神经网络的误差或损失在数据集中的训练示例之间最小化。另一方面,激活最大化颠倒了这一点:在分类器被训练之后,我们想要迭代地找到模型认为属于一个类的数据部分。
例如,考虑识别从 0 到 9 的手写数字(MNIST 数据集)的神经网络的可视化:我们想要看到神经网络认为图像的哪些部分对于它决定哪个数字是重要的;也许是 8 的底圈或者 0 的洞。
网络的激活函数输出表示一个训练样本属于一个特定类的置信度,因此激活最大化构建了一个图像,该图像检查神经网络正在寻找的每一个框,从而产生最大的激活函数。这是通过梯度上升完成的,它试图最大化输出神经元。激活最大化的思想实际上就是找到返回最高置信度输出的输入。

各种 ImageNet 类别的 AlexNet、VGG M 和 VGG VD 模型的激活最大化图像。来源:马亨德兰等人图片免费使用。
这些结果对于模型如何决策是一个非常有启发性的观点;较暗的区域表示“惩罚”,因为该区域中的较高值使得模型不太确定输入是那个数字,而较亮的值表示“奖励”,因为这些区域中的较高值增加了输出神经元的置信度。激活最大化也可以以一维非图像数据的分布或另一种分布表示的形式被可视化。
敏感性分析
敏感性分析是一种分析模型预测梯度的方法。如果神经网络由函数 f ( x )建模,其中 x 是表示输入值的变量( x [ 1 ] ,x [ 2 ] ,…,x [ n ), 然后灵敏度定义为 f ( x )相对于 x [ i ]的导数,其中 x [ i 是我们要建模的特征。 通俗地说,敏感性分析衡量一个特征的变化如何在模型对某个目标的置信度中产生相应的机会,或者模型对某个特征的敏感程度。
这项技术不仅适用于深度神经网络的解释——它在金融和医学领域有着强大的根基。
那么,问题是“是什么让这幅图像或多或少像一艘船?”而不是“是什么让这幅图像成为一辆车?”这可以通过例如激活最大化来回答。它可以被认为是特性重要性的度量,但更重要的是它向展示了改变特性的值如何影响输出置信度,而不是告诉我们这是真的。

由作者创建
层相关性传播
尽管先前讨论的测量仅利用神经网络模型的输入/输出流,并且因此可以被应用于分析任何算法的决策,但是相关性传播被明确地设计用于深度神经网络的前馈图结构。
假设我们有一张狗的图像,神经网络正在对它进行分类,但我们不确定它是否正确地识别了狗,或者使用水碗作为上下文线索。因此,我们可以将图像分成两部分,并分别通过神经网络进行处理;如果其中一只狗被归类为狗,而水盘不是,那么我们知道这个模型可以推广到其他狗的图像。

由作者创建
另一方面,如果两个图像都被分类为狗,则很少获得关于模型在完整图像的两个部分上放置的权重的信息。线索 LRP:分层相关性传播。
LRP 的目标是为输入向量 d 的每个元素定义相关性度量 R [ d ],使得神经网络的输出是 R 的值的总和。换句话说,LRP 试图将神经网络发现的复杂关系压缩成加法问题;在戏剧性的信息浓缩中,每个输入元素(特征)的 R 的值既可解释又有价值。
为了执行这种分解,总相关性分数(相当于输出)开始集中在输出中。然后,本着反向传播的精神,相关性分数被分解并分布在各个节点中,穿过神经网络的每一层,直到它到达输入层。

来源:蒙塔冯等人图片免费分享
输入层的相关性分数然后可以用热图或一些其他介质来可视化;当这些分数相加时,产生与结果相同的结果,但是在对结果的贡献中,告诉了很多关于一个输入节点的值如何在神经网络结构中传播的信息。
这类似于一个电路,某人在一个端点注入一定量的电流,并在其他端点评估随后的电流;电流较高的端点在电力如何在整个系统中分配方面具有更大的优先权和“重要性”。
这种独特的神经网络解释方法依赖于局部相关性守恒原理,该原理认为这种分解是可能的,因为网络中的信息可以保持固定,就像适用于电流的基尔霍夫守恒定律一样。
解释连续性
有多种方法可以解释神经网络的黑盒性质,每种方法都依赖于自己的直觉和展开结构的方法,但量化解释的质量也很重要。如果不能给出准确的解释,一个花哨的解释技巧是没有价值的。
解释连续性植根于公平性度量,并指出如果两个数据点几乎相等,那么对它们预测的解释也应该几乎相等。
虽然这似乎是显而易见的,但解释连续性是一个比人们想象的更棘手的问题。例如,考虑对函数max(x1, x2)的解释,该函数简单地基于较大的值设置坐标标签。三种解释方法:敏感性分析、简单泰勒分解(另一种寻找相关性分数的方法)和相关性传播都对函数有不同的解释。

来源:蒙塔冯等人。图片免费分享。
只有相关性传播解释在x1 = x2处是连续的,并且产生平滑的、基于循环的解释过渡,这与灵敏度和简单的泰勒分解结果相反,在泰勒分解结果中,在x1 = x2线上移动点 0.001 会产生完全不同的解释。
如果一个解释是高质量的,稍微改变输入,比如移动框架,旋转它,或者添加一些噪声,不应该改变结果的解释。否则,解释技术可能无法正确理解输入产生输出的原因。
感谢阅读!
如果你对最新的文章感兴趣,可以考虑订阅。如果你想支持我的写作,通过我的推荐链接加入 Medium 是一个很好的方式。干杯!
除非另有说明,否则图片由作者创作。
算法中的算法
towardsdatascience.com](/every-machine-learning-algorithm-can-be-represented-as-a-neural-network-82dcdfb627e3) [## 机器学习算法比你想象的要脆弱得多
为什么恶意输入会起作用以及如何防止它们
towardsdatascience.com](/machine-learning-algorithms-are-much-more-fragile-than-you-think-25fdb3939fee)
每一种蛋白质都是一首歌

将蛋白质转化成音乐可能是一种创造新药和抗体的新方法
利用音乐设计药物和抗体的全新方法。
虽然不明显,但音乐和蛋白质之间有许多相似之处。
音乐是由一组音符组成的——通常不超过七个。蛋白质是由二十种氨基酸组成的。
像音乐一样,这些分子从有限的词汇中讲述深刻而令人印象深刻的故事。
我们现在知道,蛋白质中的氨基酸序列不是随机打乱或混乱的。更确切地说,它们似乎是由许多长弦组成的,这些长弦相互重复、相互扭打——就像交响乐的乐章一样。
不仅仅是蛋白质——DNA、RNA 和自然界中的许多其他分子都与音乐有着有趣的结构相似性。
事实上,原子和分子尺度的生物学似乎是由一位音乐家写的。
也许正是这种洞察力驱使像麻省理工学院的 T2·马库斯·布勒教授这样的科学家用蛋白质创作音乐。
虽然这看起来像是把一个比喻延伸得太远了,但他的工作是一种革命性的设计药物和抗体的新方法,同时揭示了自然界的蛋白质奥秘。
结构就是意义

胰岛素分子的结构。1951 年,它成为第一个被完全测序的蛋白质。来自欧洲的蛋白质数据库。
大多数生物是由蛋白质构成的。
头发是一种蛋白质。指甲、蚕丝、牛奶、蜘蛛网、皮肤、蛋清、荷尔蒙、眼球也是。
肌肉是蛋白质。这就是为什么有抱负的健美运动员消耗大量的乳清蛋白粉。事实上,我们知道的最大的蛋白质之一——肌红蛋白——是一种肌肉蛋白质。27000 个氨基酸组成一个肌联蛋白分子。移动一根肌肉纤维需要数百万个肌联蛋白分子。
身体的每一部分——无论是结构性的(指甲、头发、皮肤)还是功能性的(荷尔蒙、酶)——都有一些蛋白质在创造奇迹。
因此,蛋白质化学非常复杂。我们仍在学习它们是如何工作的。
我们所知道的是,所有的蛋白质都是由一些被称为氨基酸的精选分子组装而成的。
它们有相当好听的名字,如胱氨酸、甘氨酸、亮氨酸、丝氨酸、脯氨酸等。它们的共同点是一个“胺基”——一个简单的三个氮原子和两个氢原子(-NH2)——从它们的骨架结构中伸出来。试着看看你是否能找出下面分子中的胺基。

一些氨基酸的化学结构。请注意它们中的氨基。
为了制造蛋白质,氨基酸按照特定的顺序排列和连接。
例如, 5xdi 是一种小的抗真菌蛋白,发现于一种名为牛罗勒的开花杂草中。
5xdi 只有 40 个氨基酸:
fqcgrgaggarcsnglccsqfgycgstpycgacqgqsqc
每个字母代表一种氨基酸。该序列定义了 5xdi。改变一个氨基酸——用 A 代替中间的 C——它就不再是 5xdi 了。
如你所见,蛋白质对拼写的准确性要求非常严格。
但是,这个序列只是 5xdi 的起点。
原来氨基酸并不总是合得来。这些分子中有些相互吸引,有些相互排斥。这些力使分子卷曲扭曲,直到它变得像下面的东西一样复杂。

蛋白质 5xdi 的三维结构。来自欧洲蛋白质数据库
在蛋白质的世界里,结构就是意义。
分子中的一个弯曲可以决定一种蛋白质是否会结合到某种细胞上,或者它是否会成为一种有效的抗病毒抗体。
许多蛋白质是螺旋状的。一些形成长片。

蛋白质的二级结构。许多蛋白质形成螺旋或折叠
这不是魔法——事实证明,这些形状很好地平衡了吸引力和排斥力,足以让整个分子陷入微妙的稳定状态。
因此,蛋白质符合不同的结构层次。
底部是氨基酸序列。这就是所谓的初级结构 。
这一系列的扭曲和盘绕——也许会变成螺旋状或片状。这是 的二级结构 。
螺旋或薄片可以进一步卷曲和折叠。这是 三级结构 。
许多蛋白质显示出更高水平的组织。但是你明白了:蛋白质被严重扭曲了!
一个真正复杂的蛋白质分子可以被认为是一堆杂乱的绳子——如果这些绳子是由氨基酸连接起来并通过量子化学扭曲而成的。
如果你认为这很复杂,它就是!
即使在今天,蛋白质结构的确定也是一项艰巨的任务。我们可能已经掌握了某一特定蛋白质的完整氨基酸序列,但仍然无法知道它的实际三维形状。
将蛋白质转化成音乐

蛋白质的三维结构通过一个叫做发音的过程被编码成音乐
正是蛋白质的分层结构让我们想起了音乐。
氨基酸就是音符。
二级结构——螺旋的线圈或平面——让我们想起节奏和音高。
挑战在于开发一个将蛋白质结构转化为声音的正式过程。
Markus Buehler 尝试了几种不同的方法将氨基酸转化为声音。
一种方法是捕捉分子振动的基本模式。
根据量子力学,分子可以被认为是一个有许多缠绕弦的仪器。就像任何弦乐器一样,它们往往有特定的振动频率。通过将这些转换成音频,我们可以真正听到氨基酸。
然而,第二种方法要简单得多。
有二十种氨基酸。为什么我们不把这些映射到一个确定的音阶中,比如多里安音阶?
关键是将每个氨基酸与音阶中的特定音符联系起来。你可以根据分子的大小或基本振动来排列分子,并将其带到天平上。
结果是每种氨基酸都有独特的音符。蛋白质的基本氨基酸序列现在已经成为一组随时间随意流动的音符。
下一步是捕捉二级结构。我们能让这些音符听起来像是螺旋盘绕的吗?或者可以把它们做成类似于一张纸的平面吗?
如果一种氨基酸位于曲线上,它们产生的音符会变得更短和更响。结合邻近氨基酸的影响,这给了声音一种紧迫感,让人想起掉进隧道或冲过过山车的感觉。
同样,所有复杂的结构成分都被映射成独特的声音。
把这些加在一起,你会发现——整个蛋白质都被翻译成了音乐!
选择演奏这些音符的乐器确实是一种艺术选择。马库斯倾向于在他的作品中经常使用吉他、大提琴、古筝、贝斯、打击乐器和长笛。
这个过程——将蛋白质结构忠实地翻译成音乐——被称为发音。
其中我最喜欢的是一种叫做 4osd 的病毒蛋白的发音。它由包括古筝、小提琴、大提琴、长笛和低音提琴在内的乐器合奏而成。音乐长 43 分钟(是大蛋白)。
虽然我不太确定这种蛋白质有什么作用,但我向你保证,这听起来很棒:
病毒蛋白 4osd 的超声处理。麻省理工学院马库斯·J·布勒
最奇怪的也许是他最近对冠状病毒刺突蛋白的研究。

冠状病毒的数字表示,显示其尖峰(红色)。从疾控中心/科学数据库。
冠状病毒得名于其外壳中伸出的刺突状蛋白质。这种病毒是致命的,但它的尖刺能奏出优雅的古典音乐:
由冠状病毒的刺突蛋白制成的音乐。麻省理工学院马库斯·J·布勒
氨基酸音符在日本古筝上演奏。许多其他工具提供公司和更高层次的结构信息。
这个上个月在网上疯传。据 SoundCloud 统计,至今已有 88.8 万人播放过这首音乐。
最后,听听这个:
你在这首曲子中听到的是一种新的蛋白质设计的音乐实现,这是来自不同病毒的蛋白质通过机器学习挤在一起,并自我组装成新形式的结果。这是一次进入新世界的旅程,在那里不同物种的蛋白质相互作用和重组,每一个都贡献出来自他们各自生命语言的模式和思想。
用人工智能创造音乐(和蛋白质)

使用复合神经网络,蛋白质结构可以转换成音乐。麻省理工学院马库斯·伯勒
马库斯最近更进一步。
首先,他教会了一个神经网络如何制作蛋白质音乐。
这些网络是人脑的数学抽象。他们从提供给他们的例子中学习做事——没有任何具体的指示。
这些方法可以将蛋白质结构快速转化为音乐,Markus 已经建立了一个超过 10,000 首蛋白质歌曲的数据库。
他已经听了很多遍,以至于他说他可以通过它的旋律来识别一种蛋白质。他可以通过声音辨别蛋白质是螺旋还是折叠。
第二,他使神经网络能够对音乐进行微小的改变。
神经网络现在可以在这里或那里改变一个音符。当翻译回氨基酸序列时,这就产生了一种略有变化的蛋白质。
网络能够在有约束的情况下工作。例如,他可以坚持认为蛋白质是螺旋。这种新蛋白质是它原来的突变体,但它将符合螺旋结构。
他成功地创造了新的蛋白质——以前从未在自然界发现过。
下一步是将这些蛋白质与其特性相匹配。例如,神经网络能否预测一种螺旋蛋白,它将像头发一样强壮,但颜色是绿色的?
它能合成一种对抗病毒感染的新药吗?
他指出,这种方法可能使我们能够找到冠状病毒刺突上另一种蛋白质容易附着的地方。我们或许还能让另一种蛋白质与音乐相匹配,这种蛋白质会像钥匙上的锁一样粘在这些尖峰上。
如果是这样的话,这将是使病毒变得无能的第一步。
最近,一家年轻的初创公司开始提供将个人基因信息转换成音乐的服务——只收取少量费用。 GenM 软件( Music about you )将获取任何生物信息,并将其调整为音乐。
你可以选择歌词和音调。想听鲍勃·马利或果阿·特兰斯的生活密码吗?搞定了。
但从根本上说,这是两种看似不相关的语言的结合——一种用氨基酸的语言书写,另一种用音符拼写。
它强调了自然界万物的终极统一。
与此同时,世界等待着来自蛋白质之歌的发现。
每个人都被邀请免费参加 GitHub 卫星 2020

图片来源: Github 卫星
关于 GitHub 卫星 2020 你需要知道的
GitHub 是什么?
Github 是一个帮助世界各地的开发者相互合作的平台,也是开源项目的最大来源…
查看此视频了解更多信息
GitHub 卫星是什么?
GitHub Satellite 是一年一度的国际活动——实际上,这是美国以外最大的开发者活动,它为开发者,特别是团队和研讨会带来了伟大的想法、免费的产品讲座和保护。
我需要注册吗?
不需要行动加入活动,只需保存日期:5 月 6 日。如果你想让参加 5 月 7 日的** 研讨会,你必须注册**。
为什么每个人都被邀请到 GitHub 卫星 2020
作为例外,今年每个人都可以免费参加 GitHub 卫星大会,因为冠状病毒的传播和为了保证每个人的安全,所以今年的活动将是虚拟的。所以,享受这一切,不用离开你的房子,换下睡衣,或支付一毛钱。想看就去卫星站点加入直播吧。你可以在这里查看的日程安排。
为什么你应该在那里?
有很多理由加入我们的虚拟卫星活动。以下是几个例子:
- 了解下一步:在首席执行官 Nat Friedman 的主题演讲中,率先了解安全、DevOps、GitHub Enterprise 等领域的一些激动人心的公告。(演讲者和表演者名单)
- 从代码驱动的音乐表演中获得灵感:(由代码构建的 DJ 设备)。
- 加入对话:提问并分享你对活动环节的想法。
车间的价格是多少?
因为工作室的空间有限,你需要支付 50 美元来预订一个位置,100%的钱将被捐赠给治愈新冠肺炎。保住你的位置。
如果你错过了研讨会怎么办?
每一次会议将被记录,并在结束后立即提供。
你可以在 YouTube 上观看 GitHub 卫星 2019 主题演讲
关于此次活动的更多信息,请访问 Github 卫星网站。
感谢阅读!😄
查看我的其他文章,关注我的 中型
PyTorch 关于 Fasterrcnn 的一切
了解如何在 PyTorch 中实现 Fasterrcnn 并提取每幅图像的特征图

介绍
目标检测是计算机视觉中的一项任务,我们试图对图像中存在的目标进行分类,而不是对图像进行分类。它有各种各样的应用,如检测空闲的停车位,跟踪闭路电视镜头中的物体,以及监控作物,这就是我们将要讨论的内容。
有许多方法来执行对象检测;Fasterrcnn 只是其中之一。许多其他技术,如 YOLO 和 SSD,同样工作良好。你应该了解 Fasterrcnn 的原因是,它在许多比赛中给出了最先进的结果,并在 Pinterest 应用程序等实际应用中使用。
本文简要介绍了 Fasterrcnn、与之相关的概念及其在 PyTorch 中的实现。
建筑:
Fasterrcnn 的架构如下所示:

来源:https://arxiv.org/abs/1506.01497
该网络首先从图像中提取特征。体系结构的这一部分被称为网络的主干。可以使用任何标准的图像分类架构。我们将使用带有特征金字塔网络的 ResNet50 作为我们的主干。
在第二步中, 区域提议网络 用于生成可能包含对象的区域。与过去的方法相比,这个网络是一个真正的提升,比如在整个图像上滑动一个窗口来寻找潜在的区域,正如你可以想象的那样,这是一个非常缓慢和计算昂贵的过程。
在这个网络中,相对于过去的方法的另一个改进是使用锚盒来检测各种比例和纵横比的图像。

来源:https://arxiv.org/abs/1506.01497
最后,从体系结构中可以看出,相同的特征图用于检测区域和分类。重用特征地图的想法非常聪明,你会看到很多架构都在这么做。采取的功能图,并附上多个头部,它的多项任务。
现在让我们用 PyTorch 实现一个 Fasterrcnn,并在此过程中理解更多的术语。
在 PyTorch 中实现 Fasterrcnn
Kaggle 最近举办了一场识别麦穗的比赛。我用这次比赛的数据训练了一个模型。
数据以 csv 及其相应图像的形式提供。我们有左下角的坐标,也有每个盒子的宽度和高度。

如果我们打印边界框的类型,我们会看到它们是字符串类型,而不是我们所期望的列表。这个错误很常见,可以使用来解决。为了方便使用,我们还将边界框分成了四列。

我们现在创建一个定制的小麦数据集。faster CNN 期望我们的数据以图像和与之对应的字典的形式出现。字典至少应该包括边界框和标签。

我们用数据框和存放图像的文件夹初始化数据集。我们在 getitem()函数中完成剩余的计算。

我们将盒子从(x0,y0,w,h)格式转换为(x0,y0,x1,y1)格式。我们把我们的标签分配给所有的 1,因为在这个问题中我们只有一个类(我们用 1 作为我们的标签,因为在 PyTorch 中,0 代表背景。).最后,我们把所有东西都转换成 PyTorch 张量。
我们还定义了 len()函数,因为 PyTorch 数据加载器使用它来迭代我们的数据集。
Pro 提示:如果你的数据在云上,不用下载到本地,可以直接拉图进行训练(考虑到这个过程不是超级慢)。这样,当您在线更新数据集(添加更多条目或对现有条目进行更改)时,您就不必更新本地副本。您只需要运行一个训练脚本,您的模型将根据新数据进行训练。
现在,我们可以从数据加载器中检索一个批处理,并可视化其中一个输入图像。

接下来,让我们定义我们的模型。我们正在为我们的 Fasterrcnn 使用带有功能金字塔网络的 ResNet50 主干网。主干很容易定制。我们需要传递的唯一参数是数据集中的类的数量。

在训练模式中,该模型将图像和目标字典作为输入,并产生 loss_dict 作为输出。

我们为 5 个时期训练我们的模型。然后,我们通过传递我们的图像来评估它,并获得一个边界框、标签及其各自分数的字典。然而,这不是最终的结果。如果我们看其中一个输出,

我们看到我们的模型为同一个对象生成了许多盒子。过滤掉不需要的盒子是我们的责任。这样做的一种技术叫做非最大抑制。
非最大抑制(NMS)
要在 PyTorch 中使用 NMS,我们可以简单地做

这一行代码给出了我们应该保留的所有边界框的索引。让我们来看看应用 NMS 后的相同图像。

看起来好多了,对吧?那么 NMS 是如何运作的呢?
要理解 NMS,我们首先需要理解 IoU(并集上的交集)。IoU 是衡量两个盒子相似程度的指标。IoU 越接近 1,方框越相似。记住这一点,让我们来看看 NMS 算法:
- 根据分数(置信度)对所有边界框进行排序。
- 选择可信度最高的框。该框将是输出的一部分。
- 和其他箱子一起算欠条。
- 将 IoU 超过阈值(本例中为 0.3)的框与所选框一起移除。这将删除包含相同对象或仅包含其一部分的所有重叠框。
- 从左边的框中,选择下一个框(第二高的分数)并重复该过程。
这样做给了我们一个非常好的输出。我们可以尝试各种阈值,但 0.3 效果很好。
如果你也想提取特征图,你可以使用钩子来完成。查看内核中的相同内容。
这就是本文的全部内容。如果你想了解更多关于深度学习的知识,可以看看我在这方面的系列文章。
我所有关于深度学习的文章的系统列表
medium.com](https://medium.com/@dipam44/deep-learning-series-30ad108fbe2b)
参考资料:
关于用 Python 绘图的一切
📚实践中的 Python
从 matplotlib 到 pandas.plot()

照片由 h heyerlein 在 Unsplash 上拍摄
2020 年 11 月 4 日更新: Seaborn 补充。
atplotlib 是数据科学和许多科学绘图领域可视化的基石。然而,*plt* 函数看似简单,参数却让人应接不暇。根据底部显示的教程,我总结了一份 python 绘图格式:
import matplotlib as mpl
import matplotlib.pyplot as pltplt.style.use('seaborn')
mpl.rcParams['font.family'] = 'serif'
%matplotlib inline #1\. create a figure,like canvas
fig = plt.figure() #2\. add plots inside that figure you just created
ax = fig.add_subplot(111)
#3\. set all the parameters for the plot inside that ax
ax.set(xlim=[0.5, 4.5], ylim=[-2, 8], title='An Example Axes',
ylabel='Y-Axis', xlabel='X-Axis')#4\. do the plotting
ax.plot(x,y)
plt.show()
您可以使用以下方法节省一行代码:
fig, axes = plt.subplots(ncols=2, figsize=plt.figaspect(1./2))
使用 轴 代替***plt***的好处不仅是使整个过程更像“客观绘图”,每个***ax***代表一个图形,而且使每个ax/图形的迭代更容易,如:
fig, axes = plt.subplots(nrows=2, ncols=2)
axes[0,0].set(title='Upper Left')
axes[0,1].set(title='Upper Right')
axes[1,0].set(title='Lower Left')
axes[1,1].set(title='Lower Right')
*# To iterate over all items in a multidimensional numpy array, use the `flat` attribute*
**for** ax **in** axes.flat:
*# Remove all xticks and yticks...*
ax.set(xticks=[], yticks=[])
plt.show()
Figure是这个层次结构中的顶级容器。它是整个窗口/页面,所有的东西都画在上面。您可以有多个独立的图形,并且Figure s 可以包含多个Axes。
大多数绘图发生在Axes上。轴实际上是我们绘制数据的区域,以及与之相关的任何记号/标签等。通常,我们将通过调用subplot来设置一个轴(它将轴放置在一个规则的网格上),所以在大多数情况下,Axes和Subplot是同义的。
每个Axes都有一个XAxis和一个YAxis。这些包括ticks、刻度位置、标签等。在本教程中,我们将主要通过其他机制来控制分笔成交点、分笔成交点标签和数据限制,因此我们不会过多地触及事物的单个Axis部分。不过这里值得一提的是解释一下Axes这个术语的来源。

我最喜欢的 python 导师科里·斯查费的 Matplotlib 最佳视频教程之一。
熊猫情节
至于熊猫的剧情功能,一切都打包在一个功能里:
pandas.DataFrame.plot()
该函数中有几个非常有用的参数,例如:
pd.DataFrame.plot(
ax = ax,
secondary_y="some_col",
subplots=True
)
***ax***允许您将绘图添加到当前绘图中;***secondary_y***在你的图的右边给你一个额外的轴,并设置***subplots***为真,就像plt.subplots()一样,这将给你每一列一个单独的图。
海生的
一旦你开始使用 Matplotlib 一段时间,很快你就会意识到 Matplotlib 有太多的参数和函数。我经常搞不清哪个参数属于哪个函数。另一次,我不记得参数的名称。
Seaborn 是 Matplotlib 之上的一个很好的包装器。除了美学优化,seaborn 还提供了一个解决方案,帮助用户以更简单的方式探索数据。
你可以直接使用 Seaborn
import seaborn as sns
默认设置对于日常数据可视化来说已经足够好了。如果你想对你的情节的风格和大小有一点额外的控制。最简单的方法就是一开始就设定好风格和语境。
sns.set(style="ticks", context='talk')
有五个预设的 seaborn 主题:darkgrid、whitegrid、dark、white和ticks。它们分别适合不同的应用和个人偏好。默认主题是darkgrid。四个预设上下文按照相对大小的顺序分别是paper、notebook、talk和poster。默认为notebook样式。顺便说一下,所有的参数都可以通过一个set()功能来设置。
sns.set({"xtick.major.size": 8, "ytick.major.size": 8}, style="ticks")
现在问题来了,我怎么知道那些参数是什么?
Seaborn 将所有复杂的参数归结为 2 组,只有 2 个函数需要记住。要控制风格,使用[**axes_style()**](https://seaborn.pydata.org/generated/seaborn.axes_style.html#seaborn.axes_style)和[**set_style()**](https://seaborn.pydata.org/generated/seaborn.set_style.html#seaborn.set_style)功能。要缩放图形,使用[**plotting_context()**](https://seaborn.pydata.org/generated/seaborn.plotting_context.html#seaborn.plotting_context)和[**set_context()**](https://seaborn.pydata.org/generated/seaborn.set_context.html#seaborn.set_context)功能。在这两种情况下,第一个函数返回一个参数字典,第二个函数设置 matplotlib 默认值。
sns.axes_style()

sns.plotting_context()

要设置任何参数,您只需简单地调用set()即可。例如,您可以一次性设置所有内容。
sns.set({'font.size': 60.0,
'axes.labelsize': 'medium',
'axes.titlesize': 'large',
'xtick.labelsize': 'medium',
'ytick.labelsize': 'medium',
'legend.fontsize': 'medium',
'axes.linewidth': 0.8,
'grid.linewidth': 0.8,
'lines.linewidth': 1.5,
'lines.markersize': 6.0,
'patch.linewidth': 1.0,
'xtick.major.width': 0.8,
'ytick.major.width': 0.8,
'xtick.minor.width': 0.6,
'ytick.minor.width': 0.6,
'xtick.major.size': 8.0,
'ytick.major.size': 8.0,
'xtick.minor.size': 2.0,
'ytick.minor.size': 2.0,
'legend.title_fontsize': None})
基本上,大多数时候,你只需要改变预设的主题和背景。一旦完成数据探索,您可以使用sns.set()微调任何参数以满足您的要求。
这些就是你所需要了解的关于 Seaborn 的一切。我注意到一件事,它不在参数之内,是图形大小设置。简单的方法是在代码的开头声明一个图形画布,就像使用 matplotlib 一样。
fig, ax = plt.subplots(figsize=(18,9))
ax=sns.lineplot(data=data)
ax.set(title='title', ylabel='ylabel')
当然,强大的 set()函数可以接受所有订单:
sns.set(rc={'figure.figsize':(11,4)})
#or like this
sns.set({'figure.figsize':(20,8)})
请注意,如果你的数据是一个熊猫数据帧,Seaborn 将自动模仿你的数据帧结构,换句话说,你不需要担心标签和标题等。。
总之,你需要记住的只是 4 行代码
import seaborn as sns
sns.set(context='poster', style='ticks')
sns.axes_style()
sns.plotting_context()
我忘了说的一件事是颜色。默认调色板是
sns.color_palette()

对于离散变量,‘Paired’是一个很好的选项(记住大写 p),
sns.color_palette('Paired')

至于连续数据,‘rocket’还不错。
sns.color_palette('rocket')

一会儿
警告:除非 ticklabels 已经被设置为一个字符串(通常是在中的情况,例如一个 boxplot),否则这将不能用于任何比1.1.0新的 matplotlib 版本。
通常,您可以按照以下方式操作刻度标签:
import matplotlib.pyplot as pltfig, ax = plt.subplots()# We need to draw the canvas, otherwise the labels won't be positioned and
# won't have values yet.
fig.canvas.draw()labels = [item.get_text() for item in ax.get_xticklabels()]
labels[1] = 'Testing'ax.set_xticklabels(labels)plt.show();

要理解为什么您需要经历这么多困难,您需要对 matplotlib 的结构有更多的了解。
Matplotlib 有意避免对记号等进行“静态”定位,除非明确要求这样做。假设您想要与图进行交互,因此图的边界、刻度、刻度标签等将动态变化。
因此,不能只设置给定刻度标签的文本。默认情况下,每次绘图时,axis 的定位器和格式化程序都会重置它。
然而,如果定位器和格式化器被设置为静态的(分别为FixedLocator和FixedFormatter,那么刻度标签保持不变。
这就是set_*ticklabels或ax.*axis.set_ticklabels所做的。
很多时候,你其实想做的只是注释某个位置。既然如此,那就去调查annotate吧。
我将介绍在 Matplotlib 中设置刻度标签字体大小的不同方法。它包括,
plt.xticks(fontsize= )ax.set_xticklabels(xlabels, fontsize= )plt.setp(ax.get_xticklabels(), fontsize=)ax.tick_params(axis='x', labelsize= )
下面的代码示例将使用相同的数据集。

创建上图的代码是,
from matplotlib import pyplot as plt
xvalues = range(10)
yvalues = xvaluesfig,ax = plt.subplots()
plt.plot(xvalues, yvalues)
plt.grid(True)plt.show();
plt.xticks(fontsize=)设置 Matplotlib 刻度标签的字体大小
from matplotlib import pyplot as plt
xvalues = range(10)
yvalues = xvaluesfig,ax = plt.subplots()
plt.plot(xvalues, yvalues)
plt.xticks(fontsize=16)
plt.grid(True)plt.show();
plt.xticks获取或设置 x 轴刻度位置和标签的属性。
[fontsize](https://matplotlib.org/3.1.1/api/text_api.html#matplotlib.text.Text.set_fontsize) 或 [size](https://matplotlib.org/3.1.1/api/text_api.html#matplotlib.text.Text.set_fontsize)是Text实例的属性,可以用来设置刻度标签的字体大小。

ax.set_xticklabels(xlabels,Fontsize=)设置 Matplotlib 刻度标签的字体大小
set_xticklabels用字符串标签列表设置 x 刻度标签,用Text属性作为关键字参数。在这里,fontsize设置刻度标签的字体大小。
from matplotlib import pyplot as plt
import numpy as npxvalues = np.arange(10)
yvalues = xvaluesfig,ax = plt.subplots()
plt.plot(xvalues, yvalues)
plt.xticks(xvalues)
ax.set_xticklabels(xvalues, fontsize=16)
plt.grid(True)plt.show()

plt.setp(ax.get_xticklabels(),Fontsize=)设置 Matplotlib 刻度标签的字体大小
matplotlib.pyplot.setp设置一个艺术家对象的属性。plt.setp(ax.get_xticklabels(), fontsize=)设置 xtick labels 对象的fontsize属性。
from matplotlib import pyplot as plt
xvalues = np.arange(10)
yvalues = xvaluesfig,ax = plt.subplots()
plt.plot(xvalues, yvalues)
plt.setp(ax.get_xticklabels(), fontsize=16)plt.grid(True)plt.show()

ax.tick_params(axis='x ',Labelsize=)设置 Matplotlib 刻度标签的字体大小
tick_params设置记号、记号标签和网格线的参数。
ax.tick_params(axis='x', labelsize= )设置x轴,也就是 X 轴的刻度标签的labelsize属性。
from matplotlib import pyplot as plt
xvalues = range(10)
yvalues = xvaluesfig,ax = plt.subplots()
plt.plot(xvalues, yvalues)
ax.tick_params(axis='x', labelsize=16)
plt.grid(True)plt.show()

颜色名称
- 蓝色
- g:绿色
- 红色
- c:青色
- 男:洋红色
- y:黄色
- 凯西:黑色
- w:白色的
但是,如何给 pandas/matplotlib 条形图自定义颜色呢?
我发现最简单的方法是使用.plot()中的colormap参数和一个预设的颜色渐变:
df.plot(kind='bar', stacked=True, colormap='Paired')

您可以在此找到一个大型预设色彩映射表列表。

标记

线型

绘图属性

孵出
面片对象可以有为其定义的图案填充。
- / —对角线阴影线
- \ —后对角线
- | —垂直
-
- —水平
-
- —交叉
- x-交叉对角线
- o-小圆圈
- o-大圆(大写字母“o”)
- 。—圆点
-
- —星星
字母可以组合。
参考
- 解剖 Matplotlib 最好的 Matplotlib 教程之一
- 定制剧情图例摘自杰克·范德普拉斯的 Python 数据科学手册
请查看我最近发表的文章:
📈Python For Finance 系列
关于 Python 列表数据结构的一切:初学者指南
在本文中,我们将重点介绍 Python 列表数据结构的完整过程。

https://unsplash.com/photos/eygpU6KfOBk
目录:
- 什么是 Python 列表?
- 如何创建 Python 列表
- 如何从 Python 列表中访问元素
- 如何分割 Python 列表
- 如何对 Python 列表进行排序
- 如何向 Python 列表添加项目
- 如何从 Python 列表中移除项目
- 如何更改 Python 列表中的项目
- 结论
什么是 Python 列表
Python 列表是一种序列数据类型,它允许我们在一个逗号分隔的数据实例中组合几个项目。列表可以包含相同或不同类型的数据,并且是可变的。这意味着我们可以在 Python 中改变列表对象的大小和内容。
如何创建 Python 列表
用 Python 创建列表非常简单。你需要把所有用逗号分隔的条目放入方括号中。请记住,您可以将不同的数据类型放在一起,例如整数、浮点、布尔甚至其他列表。这里有几个例子:
带有字符串元素的列表
我们应该得到:
['Apple', 'Banana', 'Orange', 'Pineapple']
带有整数元素的列表
我们应该得到:
[1, 2, 3, 4]
具有混合类型元素的列表
我们应该得到:
['Apple', 1, True, 2.4]
具有嵌套元素的列表
在上面的例子中,列表中的每一项只包含一个值。如果我们希望每个项目存储两个值呢?Python 列表也允许我们这样做!例如,您希望列出产品及其价格。您的数据如下:一个苹果的价格是 1 美元,一个香蕉的价格是 0.70 美元。为了给列表中的每个项目添加两个或更多的值,我们需要将它们放在方括号中,并用逗号分隔。它看起来像是一个嵌套的列表。
我们应该得到:
[['Apple', 1], ['Banana', 0.7]]
如何从 Python 列表中访问元素
Python 列表的一个重要且非常有用的属性是它是一个索引序列,这意味着对于一个有 n 个元素的列表,第一个元素的索引= 0,第二个元素的索引= 1,一直到 n -1。
使用索引访问列表中的元素
索引也可以反过来,这意味着第一个元素的索引= — n ,第二个元素的索引= — n +1,一直到-1。
为了便于展示,请看下面的视觉效果:

我们可以看到列表中的' Apple '元素有两个索引:0 和-4。
让我们用 Python 重新创建这个列表:
现在,我们想打印出列表中的第一个元素。从前面我们知道,它有两个索引:0 和-4,所以我们可以两个都尝试,看看输出是否相同。
我们应该得到:
AppleApple
在这两种情况下,输出是相同的。
在列表中查找元素
假设我们有以下字符串元素列表:
我们应该得到:
['Apple', 'Banana', 'Orange', 'Pineapple']
并且您想要查找“香蕉”元素的索引。
这可以通过使用简单地找到。index() 将某个值作为参数并在 Python 列表中查找其索引的方法:
我们应该得到:
1
我们很快发现“Banana”元素位于列表的索引 1。
如何分割 Python 列表
在前一节中,我们展示了如何使用精确的索引从 Python 列表中访问一个条目。在本节中,我们将展示当您想要访问某个范围内的项目时,例如,前两个或后两个项目,该如何操作。
回想一下,为了使用索引从列表中检索条目,我们将它放在方括号 [] 中。切片使用相同的方法,但是我们不是传递单个索引值,而是传递一个范围。Python 中的一个范围使用以下语法传递 [ 从 : 到。
不指定 from 和 to 的切片
如果从到到你不放任何索引到,默认情况下 python 会取整个列表。下面两行代码产生了相同的输出:
我们应该得到:
['Apple', 'Banana', 'Orange', 'Pineapple']['Apple', 'Banana', 'Orange', 'Pineapple']
通过指定 from 进行切片
你可以通过从中指定来分割一个列表,它将从你指定的索引中取出条目,直到列表结束。例如,您希望打印列表中的最后两项。请记住,您可以同时使用索引和反向索引。下面两行代码产生了相同的输出:
我们应该得到:
['Orange', 'Pineapple']['Orange', 'Pineapple']
指定为的切片
你可以通过指定到来分割一个列表,它将从列表的开始直到你指定的索引项-1。例如,您希望打印列表中的前两项。请记住,您可以同时使用索引和反向索引。以下代码将产生所需的输出:
我们应该得到:
['Apple', 'Banana']
请注意,我们将指定为 index = 2,需要记住的是,index = 3 实际上是第三个项目的位置。Python 中列表切片的工作方式是遍历条目,直到指定的到索引(在我们的例子中是 2)为止,并包括到该索引为止的所有条目,但不包括到索引下的条目。
如何对 Python 列表进行排序
Python 中的列表有一个方法。sort()** 它允许我们对列表中的项目进行排序。如果你的列表包含字符串,这个方法将按字母升序排序。如果你的列表包含数值(整数或浮点数),它将按升序排序。请注意,如果你有一个列表会有多个数据类型,。sort() 方法不起作用,会产生错误。让我们来看几个例子:**
用字符串对列表进行排序
我们应该得到:
['Apple', 'Banana', 'Orange', 'Pineapples']
用数值对列表进行排序
我们应该得到:
[1, 2, 3, 4]
在这两种情况下,我们都创建了无序列表,并在应用了之后。sort()** 方法,当打印出列表时,它被排序。**
如何向 Python 列表添加项目
在本节中,我们将介绍如何向现有列表中添加新项目。有两个列表方法可以帮助我们:。append()** 和。插入()。它们都可以向列表中添加新的条目,但是有一个主要的区别:。append() 通过“追加”的方式将项目添加到列表的末尾,而。insert() 允许我们在列表中选择一个特定的“位置”(索引),新项目将被添加到这个位置。**
让我们看一些例子:
向列表追加项目
我们应该得到:
['Apple', 'Banana', 'Orange', 'Pineapple', 'Mango']
我们从我们的旧清单开始,有 4 个项目(水果)。现在我们想把“芒果”加入我们的清单。我们创建了一个变量 new_item 并为其赋值‘Mango’。然后我们把它添加到我们的主列表中,当我们把它打印出来时,我们会看到列表中的所有 5 个条目。
将项目插入列表
与上述方法的根本区别在于,在这种情况下,我们能够在列表中选择我们想要插入新项目的确切位置。此列表方法具有以下语法:。插入(** 索引 , 条目 ) 。**
例如,我们的新项目是“芒果”,我们希望将其添加到列表中的“苹果”之后。知道“苹果”项目的索引(位置)是 0,我们应该使用 index = 1 在它后面添加一个项目。
下面是将产生我们所期望的输出的代码:
我们应该得到:
['Apple', 'Mango', 'Banana', 'Orange', 'Pineapple']
完美!使用正确的索引将“芒果”添加/插入到“苹果”之后。
如何从 Python 列表中移除项目
在本节中,我们将介绍如何从现有列表中删除新项目。有两个列表方法可以帮助我们做到这一点:。拆下()和。pop()** 。它们都可以从列表中删除项目,但是有一个主要的区别:。remove() 删除您指定的项目(必须完全匹配),而。pop() 允许我们在列表中选择一个特定的“位置”(索引)来删除你想要的项目。**
让我们看一些例子:
使用值从列表中移除项目
我们应该得到:
['Apple', 'Orange', 'Pineapple']
我们从我们的旧清单开始,有 4 个项目(水果)。现在我们想从列表中删除“香蕉”。我们创建一个变量来移除,并给它赋值“Banana”。然后我们将它从主列表中移除,当我们打印出来时,我们会看到剩余的 3 个项目。
使用索引从列表中移除项目
与上述方法的不同之处在于,我们可以选择要从列表中删除的项目的确切位置,而不是指定项目的值。此列表方法具有以下语法:。流行(** 指数 ) 。例如,您想从列表中删除“香蕉”。知道‘Banana’项的索引(位置)是 1,我们应该使用 index = 1 将其从列表中删除。**
索引的默认值是-1,这意味着如果你不指定索引而只应用。pop()** ,它将删除列表中的最后一项。**
下面是将产生我们所期望的输出的代码:
我们应该得到:
'Banana'
['Apple', 'Orange', 'Pineapple']
如何更改 Python 列表中的项目
在这一节中,我们将展示如何更改列表中的项目。例如,您有一个现有的项目列表,您想用一个新项目替换其中一个项目。我们怎么做呢?
在 Python 中,这真的很简单。我们所要做的就是在列表中指定一个我们想要改变的条目的索引,然后给它赋一个新的值。
回想一下我们的清单:苹果、香蕉、橘子、菠萝。现在,你想用甜瓜代替橘子(指数= 2)。下面是如何做到这一点:
我们应该得到:
['Apple', 'Banana', 'Melon', 'Pineapple']
结论
这一项是对 Python 中 list 方法的介绍性演练,学习这些方法很重要,因为它们在编程的许多领域和机器学习中使用。
如果你有任何问题或者对编辑有任何建议,请在下面留下你的评论。
原载于 2020 年 4 月 6 日 https://pyshark.com。****
任何东西都有它的价格——如何给单词和短语定价,在线广告竞价等等
这篇文章概述了自然语言单词或短语定价的 NLP 方法。它创造性地利用了(1)模型 word2vec,它从给定的语料库中学习上下文和单词之间的关联;(Mondovo 数据集,它为我们进一步引导我们的应用程序提供了基本的构建块。该解决方案将在诸如在线广告竞价、在线营销、搜索引擎优化等领域具有有趣的应用。这篇文章是定价问题的初始基线解决方案的一个示例,渴望了解更多关于我在实践中是如何做的以及对该主题更深入的处理的读者欢迎收听我的后续出版物。

人们正在量化一切。当我们无法做到这一点时,我们称之为无价值的或神秘的,或熟练地将其视为幻觉;爱情、忠诚、诚实等等就是如此。
在线广告竞价行业绝对不是例外,他们最大的问题之一是如何为他们选择的广告关键词或短语提供准确的竞价价格,以确保出版商网站上的一些热点广告。困境是这样的:如果出价太高,你可能肯定会得到广告位,但你也将不得不支付你出价的高昂价格;如果你把出价定得太低,你可能很难得到那个广告位。显然,这种微妙的权衡需要创造性地解决将单词/短语量化为价格的问题。
幸运的是,我们可以放心一个响亮的好消息:单词也可以定价!对于这个问题,我们可能没有像 Black-Scholes 期权定价模型那样精心制作的处方,但我们有多种方法可以解决这个问题。
在本文中,我将为关键词定价问题草拟一个简单的解决方案,它基本上使用了一种叫做 word2vec 的自然语言处理技术。接下来的部分将展示如何处理数据,在哪里使用 word2vec,如何将我们的问题转化为一个回归任务,最后展示整个管道的性能。
让我们开始吧。

word2vec 简介
追溯统计语言模型的演变可能是有帮助的。首先,我们有简单的词袋模型,在这个模型中,我们离散地对待语料库中的每个词;没有上下文,没有依赖,只有独立的词。对于这样一个模型,你能做的最好的事情就是想出一个词频图表。
接下来是 n 元模型。单字,即单个单词,没有那么强大,但我们可以扩展到双字、三字、四字等,其中每 N (2、3、4 或更多)个连续的单词被视为一个整体(作为单个单词)。可以说,这样的模型将能够捕捉大小为 N 的单词上下文,并使我们能够进行更复杂的预测和推理。例如,我们可以轻松地构建更强大的概率状态转移模型,如马尔可夫链,它支持日常应用,如单词自动暗示或自动完成。
相比之下, word embedding 是一个语言模型家族,其中使用向量来描述/表示词汇表中的单词或短语,而 word2vec 是最流行的技术之一。一般来说,它使用神经网络从给定的语料库中学习单词关联/关系,并使用给定长度的向量来表示每个单词,使得单词之间的语义相似性将与它们的向量表示之间的向量相似性相关。维基百科页面将提供一个很好的初始指针,对于这个主题的更深入的处理,请继续关注我未来的帖子。
数据处理
这是极其重要的一步。为了让我们提出任何模型,我们首先需要数据。此外,为了让我们的模型学习数据之间任何有意义的关系,我们希望数据包含从自然语言单词到价格的示例映射。不幸的是,互联网上有许多这样的数据集,我能找到的一个来自 Mondovo 。这个特定的数据集包含了 Google 上最常问的 1000 个问题及其相关的全球每次点击成本,尽管数据集相当小,但它提供了我们需要的基本成分:单词及其价格。
将这 1000 行数据打包成一个包含两列的 pandas dataframe 是相当容易的:关键字和价格,从现在开始我们称这个 dataframe 为 df 。
然后,让我们执行以下步骤,以确保数据的顺序确实是随机的:
df = df.sample(frac=1).reset_index(drop=True)
这就是我们的数据预处理。
模型导入
现在让我们稍微关心一下 word2vec。在这项任务中,我们将依赖于一些现成的向量表示,而不是从我们自己的语料库(即 1000 个短语)中学习单词向量表示。以下代码片段将介绍 Google 的开箱即用解决方案:
import gensim.downloader as apiwv = api.load('word2vec-google-news-300')
据这位消息人士称,该模型建立在‘预先训练好的谷歌新闻语料库(30 亿个运行词),(并包含)词向量模型(300 万个 300 维英文词向量)’。
从单词到句子
这里有一个问题:模型 word2vec 只包含单个单词的向量表示,但是我们需要像我们数据集中的那些短句/短语的向量表示。
至少有三种方法可以解决这个问题:
(1)取短句中所有单词的向量的平均值;
(2)类似地,取平均值,但是使用单词的 idf(逆文档频率)分数对每个向量进行加权;
(3)使用 doc2vec,而不是 word2vec。
在这里,我很想看看基线模型的表现如何,所以让我们暂时使用(1 ),将其他选项留给将来的探索。
以下代码片段将提供一个简单的示例来实现平均函数:
def get_avg(phrase, wv):
vec_result = []
tokens = phrase.split(' ') for t in tokens:
if t in wv:
vec_result.append(wv[t].tolist())
else:
#300 is the dimension of the Google wv model
vec_result.append([0.0]*300) return np.average(vec_result, axis=0)
请注意如果条件在某个“停用词”(给定语言中极其常见且通常无信息的词)中是必要的。在英语中,认为“the”、“it”、“which”等已被排除在谷歌模式之外。在上面的片段中,我留了一些余地,跳过了详细处理缺少单词或停用词的主题。在我以后的文章中,将会有更深入的讨论。请继续收看!

回归问题设置
请记住,从根本上讲,几乎所有的机器学习算法都期望数字输入:例如,在图像处理问题中,黑白图片作为 0–1 的矩阵提供给算法,彩色图片作为 RGB 张量。我们的问题也不例外,这就是为什么我们不厌其烦地介绍 word2vec。
考虑到这一点,让我们看看机器学习算法中使用的特征矩阵和目标向量:
X = np.array([get_avg(phrase, wv) for phrase in df['keyword']])y = df['price']
由于我们预测的是一些数值,这是一个回归问题。让我们为此任务选择一些简便的回归算法:
from sklearn.ensemble import RandomForestRegressor#leaving out all params tuning to show absolute baseline performance
reg = RandomForestRegressor(random_state=0)
表演
现在我们终于能够看到我们的绝对基线模型的表现了。让我们建立如下 10 重交叉验证方案:
from sklearn.model_selection import KFoldfrom sklearn.metrics import mean_absolute_error#set up 10-fold Cross Validation:
kf = KFold(n_splits=10)#loop over each fold and retrieve result
for train_index, test_index in kf.split(X):
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index] reg.fit(X_train, y_train)
print(mean_absolute_error(y_test, reg.predict(X_test)))
在我的实验中,运行上面的代码给出了 MAE 分数 1.53、0.98、1.06、1.23、1.02、1.01、1.06、1.19、0.96 和 0.96,导致平均 MAE 为 1.1,这意味着我们的估计价格平均可能会偏离真实价值 1.1 美元。
考虑到可用的数据稀少,训练数据中缺乏单词冗余,样本内数据点稀疏,以及我们在没有任何参数优化的情况下的绝对基线假设,我对我们目前的方法能够推进的程度印象深刻。不难想象,一些热心的读者自己做实验一定会取得更好的结果。
一切都是回归
寻找统计学的统一范例

序幕
我的记忆力很差。
在大学里,我的第一爱好是生物,但最终我对这些课程不感兴趣,因为它们强调记忆。我被数学作为一门学问所吸引,因为我不需要记忆任何东西。在数学中,要点是我们如何知道某事。如果你自己都不能证明一个结果,那你就是不懂。
出于某种原因,统计学仍然经常通过列出在各种情况下适用的测试来教授。复杂的流程图和更加具体的统计测试。

检验均值假设的统计流程图。
这导致了统计测试的混乱和误用。不过没关系,因为我有一些好消息。基本统计数据可以分为三个部分进行解释:
对于有数据科学和/或机器学习背景的人来说,这是一个好消息。由于回归是大多数机器学习研究的起点,这意味着你已经在做统计假设检验了——也许你并不知道。在这篇文章中,我将通过给出一些如何从回归的角度考虑普通统计检验的例子来关注这一点的最后一步。
线性回归快速回顾
在线性回归中,我们为我们的特征 x 和我们的响应变量 y. 之间的关系建立一个线性模型

该模型是统计的,因为假设ε是随机的。

噪声项,假设正态分布在普通最小二乘法(OLS)中
这是一个数学模型。这是我们精确地指定我们对数据集的假设的一种方式。每当我们构建模型时,记住这句名言是很有用的:
所有的模型都是错的,但有些是有用的。—乔治·博克斯
模型是对现实世界复杂性的抽象和简化。因为它们是一种简化,所以它们总是错误的,但它们可能捕捉到一些重要的想法。
作为一个例子,让我们考虑一个从 1991 年到 2018 年的 NBA 选秀数据集(你可以从我的网站下载这个数据集)。我们可以看看选秀权和职业生涯场均得分之间的关系。这显示在下面的散点图中,以及数据的最佳拟合回归线。

对 1991 年至 2018 年的 737 名 NBA 选秀权和他们的职业生涯 PPG 平均水平进行线性回归。请注意,这些点是随机抖动的,以避免散点图上的重叠
这里的最佳拟合回归线由下式给出:

最佳拟合线性回归模型
线性回归的最佳拟合通常通过最小化残差平方项来找到。

N 个数据点的 LS 成本函数。
在这里,我不会深入探讨成本函数的实际最小化是如何工作的。可以说,使用线性代数中的一些技巧,我们可以很快找到这个成本函数的全局最小值。这给了我们一些最适合斜率和截距的参数。
分类变量回归
我们还可以对本质上是分类的特征进行回归。这里的诀窍是做一个所谓的 一个热编码 的分类变量。想法是将分类水平转换成指示变量(δ)。如果输入属于其指定电平,这些δ将为 1,否则为零。
例如,对于 NBA 选秀数据,让我们将选号列分为彩票选号(≤14)和非彩票选号(NL)。

然后我们可以寻找这两组球员平均每场得分的差异。

编码回归模型。如果不是彩票选号,δ为 0,否则为 1。
这是一张显示回归线的数据图。

现在,斜率项β给出了非彩票选号(x=0)和彩票选号(x=1)之间每场游戏的平均点数的差异。这里的轻微上升趋势表明,我们有一些证据表明,彩票选秀权往往在他们的职业生涯中平均得分更多。
当然,这种趋势是基于对玩家的随机抽样,所以如果我们收集新的样本,这种上升趋势可能会消失。为了说明随机采样引起的变化,我们可以为斜率形成一个置信区间。
对于上面的彩票选号示例,我们发现参数的 95%置信区间如下:
β ∈ (3.48, 4.78)
α ∈ (6.65,7.57)
这告诉我们,彩票选秀权减去非彩票选秀权的职业生涯 PPG 的平均差异可能在 3.48 到 4.78 之间。这让我们了解了影响方向(正面)和影响程度(3.5-4.8 分)。
我们可以看到这个斜率区间不包含零。这告诉我们,如果我们重新采样数据,我们不太可能看到这一趋势的逆转。如果我们将置信水平从 95%提高到 99%,我们将看到区间宽度会增加。为了减少错误,我们需要更大范围的值。
我们现在可以玩增大(100-p)%置信区间的游戏,直到区间在左侧刚好达到 0。这个值称为 p 值。

斜率为零的零假设的 p 值可以通过稳定地增加 CI 的宽度直到它接触零假设区域来找到。
p 值给出 P(D|H₀)在假设零假设为真(即 H₀ : β=0)的情况下观察到数据的概率。
双样本 t 检验
在某些情况下,我们可能只关心效果的方向,而不关心效果的大小。这属于被称为双样本 t 检验的统计检验的范畴。在基础统计学课上,我们被教导使用双样本 t 检验来评估在两种条件下收集的数据,以寻找均值差异的证据。这是典型的控制组对实验组。

为了在 R 中执行这个测试,我首先要从我们相当大的草案数据集制作一个较小的数据集。下面的命令只是产生一个随机的 100 名玩家的子集,供我们比较。为了更好地衡量,我还在数据集中创建了一个彩票列。

为两个样本的 t 检验建立两组。使用种子,这样你就可以得到和我一样的值。
现在我们准备在 r 中运行 t 测试。

我们运行了一个双样本 t 检验来寻找 NBA 中彩票和非彩票选秀权之间的平均职业生涯得分的差异。
现在请注意我们结果中的 p 值。此处相对较小的值表明数据不太可能给出零假设。
现在让我们用一个分类特征来做线性回归。

在这里,我将展示我们简单的线性回归的 R 中的一个摘要命令的结果。

我已经强调了重要的一行。将此结果与我们使用双样本 t 检验发现的结果进行比较。t 值(直到符号)和 p 值是相同的!
此外,当我们查看 R 中的回归汇总时,请注意相同的 p 值在汇总的最后一行中重复出现。这是对我们整个回归模型进行的 F 检验 的结果。
这个测试告诉我们模型中的任何特征是否以统计上显著的方式偏离零。我们的课程,在这个简单的例子中,我们只有一个特征,因此模型的 f 检验和彩票特征的 t 检验是完全相同的。在多元回归(不止一个特征)中,这些将是不同的。
方差分析和多元回归
假设我们想评估球员的位置对他们职业生涯平均得分的影响。首先,我们应该清理数据集中 position 列的级别。

使用 R 中的 forcats 包来清理 Position(Pos)列的级别。这里我们将一些类别合并在一起,得到 C,F,G 作为位置。
然后,我们可以按职位绘制职位职业得分图:

nba 球员样本中位置对职业得分影响的箱线图。
我们可能想知道这些组的平均值是否真的不同,或者观察到的差异是否也可以用抽样误差来解释。在经典统计学中,我们会说我们想要进行单向 ANOVA (方差分析)。这可以在 R:

R 中的 ANOVA,注意 p 值在最右边给出 p=0.0813。
现在我们也可以把它看作回归。我们的回归模型具有以下形式:

alpha 截距值现在告诉我们中心的平均值,两个斜率告诉我们相对于中心值的点。
这些都是在 r 中完成的,输出如下:

将回归输出中的最后一行(f 检验)与 ANOVA 输出进行比较。我们再次看到相同的结果!
这告诉我们,单向方差分析只是一个具有分类特征的线性回归模型——具有两个以上的水平。使用的测试有一个无效假设,即所有的斜率都为零。
双向方差分析
在双向方差分析中,我们使用两个分类特征来预测一个连续的响应变量。
让我们使用 Tm(起草团队)和 Pos(职位)列对我们的草案数据集进行此操作。双向方差分析需要更多的数据来拟合模型,所以我们将使用完整的数据集,而不是我们的精简数据集。首先,我运行下面的两个命令来清理两个分类特征级别。

清理整个草稿数据集的团队和职位列。这些人使用了 forcats 软件包
在这种情况下,我们的线性模型采用以下形式:

第一个总和是虚拟编码团队变量,第二个总和是职位类别。所有这些都在 r 中很好地完成了。为了执行我们的分析,我们可以使用以下公式构建线性模型:

建立双向方差分析线性模型
这里唯一的变化是我们应该在我们的模型上使用 anova() 命令,而不是通常的 summary() 。这将显示以下结果:

这两条线告诉我们,我们有证据表明职位对职业积分很重要,但我们没有足够的证据得出团队很重要的结论。现在,您大概可以看到如何使用多元回归进行 N 向方差分析。
协方差分析
如果我们在回归中加入一个连续的特征,这就有了另一个名字(ANCOVA=协方差分析)。这里的动机可能是我们已经看到位置对 NBA 球员的 PPG 很重要,然而这可能只是因为一些位置比其他位置打更多的时间。
我们可以通过在我们的模型中包含这个特性来控制播放时间的效果。首先,我将重新调整上场时间列(MP ),使平均值为零,标准差设为 1。这样做的动机是,否则我们在线性模型中的截距是真的没用的——因为这会给一个场均 0 分钟的中锋带来职业生涯的 PPG。现在,截击将有一个平均每场比赛出场时间的中锋的平均 PPG 的解释。也许有点拗口,但更有意义。

缩放播放分钟数栏
这是一张每场比赛上场时间和得分之间的关系图,位置用颜色表示。

现在我们来建立线性模型:

这会产生以下结果:

第一行告诉我们,即使在控制上场时间后,这个位置对职业生涯 PPG 也有统计学上的显著影响。
比例和 GLMs
我们也可以把其他基本的统计程序表述为回归。然而,我们将需要利用所谓的广义线性模型(GLM) 走得更远。
首先,我将生成一个假数据集供我们使用。下面的命令创建了一个 R 数据帧,它存储了一场假想比赛的罚球结果和球员姓名,在这场比赛中,球员 A 和 B 各罚 100 次球。

玩家 B 只有 77%的命中率,玩家 A 只有 80%的命中率,虽然这是有抽样误差的。我们可以在 R:

在这里,我们可能要执行一个双样本比例测试,以检验两个玩家之间的百分比不同的假设。

这可以在 R 中使用 prop.test 命令来完成。

在 r 中运行双尾 prop 测试的结果。这里我们简单地使用两个比例相等的零假设进行测试。这也可以用相同的 p 值进行χ检验。
现在是回归方法。如上所述,由于我们的响应变量不再连续,我们需要调整我们的回归来处理二元输出。实际上,我们希望我们的模型能产生一个概率 pᵢ
这可以使用 逻辑回归 来完成。我们通常的回归采用以下形式:

在逻辑回归中,我们的输出 Yᵢ应该给出在给定 Xⱼ特征的情况下,Yᵢ取值 1 的概率。如前所述,我们有一个问题,上面模型的右边将产生ℝ=(-∞的值,∞),而左边的应该存在于[0,1]中。
因此,要使用这样的模型,我们需要将我们的输出从[0,1]转换到整个实际ℝ.线 logit 函数对此很有用,因为它映射 logit: [0,1] → ℝ.

因此,如果将我们的输出视为由 logit 函数 Yᵢ=logit(pᵢ).产生,我们可以使用我们的多元回归技术这是逻辑回归的基本思想:

最后,我们可以反转 logit 函数来获得实际概率:

其中 logit⁻ : ℝ → [0,1]由下式给出:

逻辑回归是被称为广义线性模型(GLM) 的一系列技术中的一个例子。GLMs 包括线性预测函数α+ ∑ βⱼ Xᵢⱼ和将线性预测函数映射到响应变量的链接函数 g()。

这在 r 中很容易做到。我们只需将 lm()函数改为 glm(),并指定我们想要使用的链接函数。

使用逻辑回归和模型比较进行双样本比例检验。请注意,p 值与上面的结果一致。
在上述情况下,我们实际上符合两个逻辑回归。第一个是我们实际想要建立的模型,第二个是两个样本比例检验的零假设的等价物。通过仅拟合截距(上面的~1),我们说两个球员罚球的百分比必须相同。
然后,我们使用 anova()函数将我们的模型与零假设模型进行比较。我还指定方差分析应该使用 l 似然比检验(LRT) 。当然,像往常一样,请注意 p 值与上面的比例测试相同。
此外,这个例子向我们展示了如何使用回归模型和 anova 命令来进行模型选择。实际上,我们一直在这么做,因为零假设一直是一个模型——我们只是以前没有在 anova 命令中指定它。这也向我们展示了如何开始将我们的模型与更复杂的空模型进行比较。
模型选择允许我们比较模型并超越琐碎的空模型。
为什么这很重要
一个数学模型的自然进程的超级奇妙的图表如下所示:

RIP 模型。让这成为你深度学习的一个警告!
当我们被迫承认统计测试是数学模型时,这就把假设推到了前沿。希望这能让我们在模型生命周期的前两个阶段停留得更久一点。同样,这意味着我们可以停止试图记忆一堆统计测试。
停止记忆,开始建立模型
如果你想继续了解这个话题,我强烈推荐你去看看乔纳斯·林德洛夫的网站。对于这方面的教科书,我推荐《统计学再思考》。对于基本的统计阅读,我喜欢所有的统计。对于一些更高级的回归分析,我推荐看一看 Gelman 和 Hill 。
掌握数据科学的 SQL 技能所需的一切
如果你谷歌“如何学习 SQL?”,你得到很多结果,这是压倒性的。让我们来看看一些最好的资源。

我写这篇文章是通过分析业内一些最好的数据科学家写的各种 LinkedIn 帖子以及我在学习 SQL 时经历的事情。我认为这是 SQL 的一些好资源的列表。我用过其中的一些,但不是全部。
本文包括 SQL 的重要性、必须涵盖的重要主题、课程、实践平台、面试准备资源,以及 SQL 注释。
SQL 的重要性?
在脸书最近发布的 25 个数据科学家职位中,每个职位都列出了 SQL 技能。在 2020 年 LinkedIn 印度十大创业公司名单中,有 7 家将 SQL 作为他们最常用的技能之一。这种经常被低估的语言不仅在印度,而且在全世界都是需要的顶级技能之一。只要数据科学中有‘数据’,SQL 就仍然是它的重要组成部分。虽然 SQL 已经有 40 多年的历史,但它在 21 世纪仍然适用,这是因为它提供了许多优于替代产品的关键优势。
SQL 在什么情况下出现?
数据科学是对数据的研究和分析。为了分析数据,我们需要从数据库中提取数据。这就是 SQL 的用武之地。
许多数据库平台都是模仿 SQL 的。这是因为它已经成为许多数据库系统的标准。事实上,像 Hadoop、Spark 这样的现代大数据系统利用 SQL 来维护关系数据库系统和处理结构化数据。
识别正确的数据源、获取数据和预处理数据是任何描述性或预测性分析工作的基本步骤。由于这些数据主要存储在关系数据库中,因此,为了查询这些数据库,数据科学家必须具备良好的 SQL 知识。而 SQL 在这些步骤中扮演着最关键的角色。
为了通过创建测试环境来试验数据,数据科学家使用 SQL 作为他们的标准工具,并使用存储在 Oracle、Microsoft SQL、MySQL 等关系数据库中的数据进行数据分析,我们需要 SQL。
数据科学 SQL 中的重要主题
在进入参考资料之前,让我们看看哪些是重要的主题。确保你涵盖了以下话题,但不限于这些。
1】Group By 子句:SQL Group By 子句与 SELECT 语句配合使用,将相同的数据分组。大多数情况下,我们将聚合函数与 group by 子句一起使用,也使用 Having 子句和 group by 子句来应用条件。
2】聚合函数:聚合函数对一组值执行计算,并返回单个值。《出埃及记》计数、平均值、最小值、最大值等。
3】字符串函数和操作:为了执行各种操作如将字符串转换成大写,匹配一个正则表达式等。
《出埃及记》1]查找名称以“A”开头的学生 id。2]从地址栏中获取 pin 码。
4】日期&时间操作:当值包含唯一的日期时,很容易处理,但是当还包含时间部分时,事情就有点复杂了。所以一定要多练习。
5】输出控制语句:按要求得到结果。例如:order by 子句,limit 函数获取有限的行。
6】各种运算符:主要有三种运算符,分别是算术运算符、逻辑运算符和比较运算符。
7]联接:这是一个重要的主题,用于联接多个表以获得期望的输出。确保您了解所有的概念,如连接类型、主键、外键、组合键等。
8】嵌套查询:子查询/嵌套用于返回数据,当该数据将在主查询中用作条件以进一步限制要检索的数据时。
(嵌套查询可用于返回标量(单个)值或行集;然而,联接用于返回行。如果您可以用两种方式执行操作,那么优化的方式是使用连接。)
9】视图&索引:索引是数据库搜索引擎可以用来加速数据检索的特殊查找表。简单地说,数据库中的索引类似于一本书的索引。
临时表:这是一个很棒的特性,它允许您使用相同的选择、更新和连接功能来存储和处理中间结果。
11】窗口函数:窗口函数对一组行进行操作,并为基础查询中的每一行返回一个值。它们降低了分析数据集分区(窗口)的查询的复杂性。
12】查询优化:当我们处理较大的数据集时,使用最有效的方法让 SQL 语句访问所请求的数据是很重要的。
最后是 13】常用表表达式。
如果您在以下课程中没有找到【CTE】,那么这里有 5 个有用的资源: 资源 1 , 资源 2 , 资源 3资源 4
学习和实践的资源:
课程:
1】uda city 用于数据分析的 SQL:
在本课程中,您将学习使用结构化查询语言(SQL)来提取和分析存储在数据库中的数据…
www.udacity.com](https://www.udacity.com/course/sql-for-data-analysis--ud198)
这是最好的 免费 课程之一,涵盖上述所有主题,每个主题后都有清晰的解释和练习测验。实践测验的质量使本课程非常有效。总的来说,这是一门很棒的课程。
2】Excel 用户 SQL 编程入门:
如果你是一个 Excel 用户,并想学习 SQL,那么这将是一个很好的 YouTube 播放列表。这涵盖了以上列表中的主要主题。
3】Udemy 的数据科学主 SQL:
本课程将使您成为 SQL 查询向导。你将学到从…中提取关键洞察力所需的技能
www.udemy.com](https://www.udemy.com/course/master-sql-for-data-science/)
在本课程中,您将学习从数据库中的数据中提取关键洞察力所需的技能。有超过 100 个谜题散布在整个课程中,有深入的解决方案为你提供大量练习的机会。
4】可汗学院:
了解如何使用 SQL 来存储、查询和操作数据。SQL 是一种专用编程语言,专为…
www.khanacademy.org](https://www.khanacademy.org/computing/computer-programming/sql)
这是一个非营利教育组织,目标是创建一套帮助教育学生的在线工具。这是一个很棒的平台,提供免费的优质课程,并有详细的解释。你也可以尝试其他课程这里。尤其是我爱统计一。
整个课程包含 5 个部分,从基础开始,一直到更高级的课程。在本课程中,每个主题的末尾都有挑战,然后是视频教程和一个小项目。
5】200+SQL 面试问题:
[## 面向开发人员的 200 多个 SQL 面试问题和答案
您准备好参加 SQL Developer 面试了吗?我在数据库领域有大约 15 年以上的经验,并且…
如果你正在为面试做准备,本课程将通过解决复杂的问题来帮助你。在本课程中,您将找到 200 多个真实世界的 SQL 问题和实用答案。
6】LinkedIn Master SQL for Data Science:
[## SQL 在线培训课程| LinkedIn Learning,原名 Lynda.com
从选择编程语言到理解存储过程,通过观看我们的…
www.linkedin.com](https://www.linkedin.com/learning/topics/sql)
数据科学主 LinkedIn
这总共包含 6 个项目。这套课程涵盖了数据科学所需的各个方面。
如果你对 SQL 的历史感兴趣,那就去看看 这段视频 (仅第 1 部分)。
如果你是一名 初学者 ,选修以上任何一门课程或你认为好的任何其他课程,并完成以上列表中的所有主题。
如果你 知道了基础知识 那么对复习所有题目 这段视频 会很有帮助。
实践是成功的关键。
一旦你知道了所有的主题,就该练习了。没有实践,你无法掌握任何技能。所以让我们来看看一些好的练习平台……
SQL 查询实践平台:
1】leet code:
提高你的编码技能,迅速找到工作。这是扩展你的知识和做好准备的最好地方…
leetcode.com](https://leetcode.com/problemset/database/)
这是一个最好的实践平台,有各种各样的问题。下面是一些好问题有第二高工资问题、重复邮件、班级 5 人以上、升温、班级 5 人以上。
2】SQL 动物园:
[## SQLZOO
跳转到导航跳转到搜索新教程:新冠肺炎国际数据。这个服务器是由爱丁堡纳皮尔托管的…
sqlzoo.net](https://sqlzoo.net/wiki/SQL_Tutorial)
SQLZoo 是一个完善的在线平台(自 1999 年以来),用于编写和运行针对实时数据库的 SQL 查询。您可以看到查询的实际结果,而不必仔细检查您的查询是否与解决方案匹配,因为解决一个问题可能有多种方法。评估部分包含更多复杂的示例,允许您以不同的难度深入数据库
3】黑客排名:
加入超过 1100 万名开发人员的行列,在 HackerRank 上解决代码挑战,这是为…
www.hackerrank.com](https://www.hackerrank.com/domains/sql)
这是一个很好的练习平台。这里的问题分为三个部分,容易,中等,困难。
4】SQL Bolt:
[## SQLBolt -学习 SQL-SQL 介绍
欢迎使用 SQLBolt,这是一系列交互式课程和练习,旨在帮助您在工作中快速学习 SQL
sqlbolt.com](https://sqlbolt.com/lesson/introduction)
本质上,它是一系列互动的课程和练习,旨在帮助用户轻松学习 SQL(T21)。本网站上的课程和主题非常全面,涵盖了使用 SQL 的所有重要细节。
5]选择 SQL:*
[## 选择星形 SQL
这是一本交互式的书,旨在成为互联网上学习 SQL 的最佳场所。这是免费的…
selectstarsql.com](https://selectstarsql.com/)
这是一本交互式书籍,旨在成为互联网上学习 SQL 的最佳场所。它是免费的,没有广告,不需要注册或下载。它通过对现实世界的数据集运行查询来帮助您完成重要的项目。
6】模式:
学会用 SQL 用数据回答问题。不需要编码经验。
mode.com](https://mode.com/sql-tutorial/)
在这里,您可以按主题练习和,有四个主要部分,分别是基础、中级、高级和 SQL 分析培训。在这里,您可以阅读理论并练习 SQL 查询。
7】斯坦福大学:
斯坦福在 2013 年 6 月发布了 edX 平台的第一个开源版本 Open edX。我们将我们的实例命名为…
online.stanford.edu](https://online.stanford.edu/lagunita-learning-platform)
在这里你可以练习题型智慧题。用户界面不是很好,但你会得到高质量的材料。在这里,您可以解决主题式查询。涵盖的主要主题是基础知识、连接、子查询、修改数据、聚合、日期、字符串,最后是递归。
面试准备资源
如果你正在准备面试,下面的资源可以帮助你,
1】Zachary Thomas 的数据分析师 SQL 面试问题:
[## 最佳中硬数据分析师 SQL 面试问题
扎克里·托马斯·(zthomas.nc@gmail.com,推特,LinkedIn)
quip.com](https://quip.com/2gwZArKuWk7W)
SQL 的前 70%相当简单,剩下的 30%可能相当复杂。科技公司数据分析师和数据科学家的面试问题通常来自这 30%。在这里,他专注于那些中等难度的问题。如果你练习了以上任何一个平台的所有重要话题(我会更喜欢 Leetcode。)那么这就足够面试准备了。
2】数据和尚:
SQL 数据科学面试问题这里我们有 150 多个 SQL 面试问题,大部分数据都会问这些问题…
thedatamonk.com](http://thedatamonk.com/sql-data-science-interview-questions/)
在这里你可以找到公司的所有主题(SQL、python、统计学、案例研究等。)面试问题破解数据科学与数据分析师面试。
笔记
1]如果你想在短时间内复习所有概念,那么 这里是 GoalKicer 提供的 SQL 100+ pages 笔记。
2】这是 stack overflow 投稿人创作的电子书。 这本书涵盖了所有的概念。
注:很可能还有其他资源。太好了。我只是还没有全部做完!
如果你发现任何可以帮助别人的东西,请写在评论里,我会把这些资源添加到博客里。
结论
在本文中,我们回顾了所有有助于规划您自己的 SQL 跟踪的资源。本文涵盖了从基础知识到面试准备的所有资源。如果你还在困惑“如何开始?”,只需使用每个标题下的第一个资源。
您可能想阅读的其他文章
这篇文章是关于用统计术语理解线性回归的。
towardsdatascience.com](/the-complete-guide-to-linear-regression-analysis-38a421a89dc2)*
通过 TigerGraph 认证测试的所有知识

Jon Herke 拍摄的照片
为什么每个数据科学家都应该获得认证,以及如何获得认证
什么是 TigerGraph,我为什么要获得认证?
被列为 Gartner 2019 年十大数据和分析趋势之一的图形技术是未来,允许用户对复杂的数据提出复杂的问题,TigerGraph 就是其中的一个例子。在这里,我们将介绍使用 TigerGraph 和学习图形技术所需的所有内容。如果你获得认证,你的可信度会增加,因此我强烈建议你试一试。此外,TigerGraph 是“企业唯一可扩展的图形数据库。”通过参加认证考试,你不仅会增加你的可信度,而且你还会学到一些几乎在任何地方都能帮到你的新东西。此外,参加考试是完全免费的,所以所需要的只是时间和愿意学习通过你的测试!
第一步:理论
你将看到的前四个模块由理论组成。什么是图形技术?你能说出一些流行版本之间的区别和它们不同的应用吗?
图形数据库和分析
一个图由通过边连接的个顶点(也称为节点)组成。所有的顶点和边组成一个模式。图表技术的强大之处在于数据是相互关联的,允许用户跨复杂的数据提出复杂的问题,而使用 SQL 有时是不可能的。节点和边可以有属性或属性,如年龄、位置、时间等。,它提供关于每个节点和边的细节;带有节点、顶点和属性的图称为属性图。


照片由 Shreya Chaudhary 拍摄。上面显示了一个基本的属性图和一个例子。每个顶点都与有向边或无向边(分别是一个箭头或一条线)相连,并且具有唯一的 primary_id。
通过搜索不同的实体,图可以被用作一个参考网络,这些实体具有多个共同的顶点,并且相距几个跳(或边)。你可以在日常生活中找到推荐网络,比如你推荐的 LinkedIn 联系人或推荐的医生。
属性图与资源描述框架(RDF)图形成对比,因为 RDF 上的每个节点都是唯一资源标识符(URI) ,它不能携带任何属性。它们有主语和宾语(节点),用谓词(边)连接,但它们可能会变得冗长。


照片由 Shreya Chaudhary 拍摄。这是一个 RDF。请注意,属性是独立的节点,而不是节点的属性。

考试的时候一定要记住上面图表中的信息!
管理关系
接下来,我们将了解不同数据库存储关系的方法以及 graph 如何进行比较。关系数据库将每个实体存储在单独的表中,然后需要表连接来连接,这一操作可能需要几个小时,并且计算量很大。它可以用于索引和搜索一种类型的数据,并执行基本分析。关系数据库针对交易进行了优化,而不是深度分析。

照片由 Shreya Chaudhary 拍摄。这是一个在不同实体之间使用表连接的关系数据库的例子。
图形数据库,相比之下,是一个,单一的,预先连接的表。它们是为存储和分析关系而构建的自然存储模型。因为它的所有关系都是一级实体,针对深度分析优化的图形数据库往往比关系数据库快得多。
与 NoSQL 相比,图形数据库更适合深度分析。一个这样的例子是键值数据库,它将所有数据存储在一个表中。键值数据库允许数据灵活性和快速键查找,但它是低级的。列族是大规模的高效处理,但是对于事务和更新来说很慢。文档可以处理像 XML 和 JSON 这样的结构,但是它通常非常专业。所有这些都需要遍历和分析关系,对表进行多次扫描,这使得它不适合分析深层关系。最后,图有利于处理关系,是上述结构中唯一能很好管理关系的,但并不是所有的图都能提供大规模的实时速度。总的来说,虽然 NoSQL 图可以存储各种各样的数据,但图是处理关系和实体的最佳选择。

照片由 Shreya Chaudhary 拍摄。这显示了一个键值数据库,这是一个巨大的数据库,需要花费很多时间来迭代。
图的演变
目前有三种类型的图表:图表 1.0、图表 2.0 和图表 3.0。 Graph 1.0 使用单服务器和非并行架构的原生图形存储。 Graph 2.0 使用 NoSQL 基础进行存储扩展,并且可以支持两跳查询,但是它们不是为实时更新而设计的。然而,Graph 3.0 既是原生的又是并行的,支持超过十跳,运行跳和加载数据花费的时间更少。
由 TigerGraph 提供的图形 3.0(T1)支持 HTAP(混合事务和分析)。它还支持 OLTP 和 OLAP,具有实时性能,是一个事务图形,具有针对大规模数据集的可扩展性,可以使用深度链接多希望分析,易于开发和部署,并提供企业级安全性。TigerGraph 是世界上第一个本地并行和分布式图形,具有互操作性,与 MPP 并行,库中有许多图形算法,支持多重图形,使用 GSQL(类似于 SQL,便于转换)。图形工作室,一个图形用户界面,允许快速简单地创建图形和易于可视化。
数据科学能力
图形支持许多机器学习和数据科学算法。这是其中一些的演练。
深度链接分析支持查看三跳以上的数据。这可能会呈指数级增长。深度链接分析的一个例子是试图找到一个用户的欺诈历史。它不仅会查看浅层连接,还会查看深层连接,以检测用户的历史记录是否清晰。
多维实体和模式匹配将在图形中寻找模式。
关系共性寻找两个顶点的共同点,比如两个供应商的共同客户。
中枢社区检测搜索图中最有影响力的顶点,即边最多的顶点。这有助于发现社区中某个事物的相关性。
地理空间图形分析使用纬度和经度显示两个事物之间的距离。
时态图分析类似,但它着眼于实体和关系如何随时间变化。
机器学习和可解释的 AI 可以通过提取特征和使用 graph studio(GUI)为图表提供视觉帮助,供 graph 使用。
第二步:TigerGraph 云
要使用 TigerGraph Cloud,请前往https://tgcloud.io/。登录,然后确保您对使用该资源感到满意。能够使用 GraphStudio 创建解决方案、上传数据、创建查询和构建图表。已经有几个很棒的关于这个的博客了,所以我在这里把它们链接起来。
这里有一个我推荐:https://www . tiger graph . com/2020/01/20/taking-your-first-steps-in-learning-tiger graph-cloud/
第 3 步:选择语句
挑选
使用 Select 语句,可以从一组顶点遍历到另一组顶点。这是一般语法(必需的参数以粗体显示):
resultSet = **SELECT vSet FROM (edgeSet | vertexSet)** [whereClause] [accumClause] [havingClause] [orderClause] [limitClause] **;**
当运行这个命令时,算法从 FROM 开始,遍历所有其他子句来“过滤”或操作它们,然后 SELECT 返回所有合适的顶点。
以下是一个查询示例:
CREATE QUERY GetFriends(vertex<Users> inputUser) FOR GRAPH Social {
Start = (inputUser);
Friends = SELECT t FROM Start:s- (IsFriend:e)-User:t;
PRINT Friends;
}
在示例中,s 是起始节点,e 是边,t 是目标或最终节点。
哪里和和
其中过滤掉不符合特定条件的顶点。可以使用 AND 语句连接这些条件。
CREATE QUERY GetFriends(vertex<Users> inputUser) FOR GRAPH Social {
Start = (inputUser);
Friends = SELECT t FROM Start:s- (IsFriend:e)-User:t
WHERE e.connectDt BETWEEN to_datetime("2019-01-01")
AND to_datetime("2020-01-01")
AND t.gender == "F";
PRINT Friends;
}
在本例中,它使用 connectDt 过滤 2019–01–01 和 2020–01–01 之间的所有边。接下来,它过滤掉所有性别属性为“F”的目标节点。最终,Friends 打印出 2019 年所有连接的女性朋友。
累加器
累加器可以是本地(用一个@表示)或全局(用两个@@表示)。局部累加器专用于每个顶点,全局累加器用于整个图形。
其次,累加器有更具体的类型:
- suma ccum
存储所有通过的数字的累计。 - MaxAccum
存储通过的最大数。 - MinAccum < int > 存储通过的最小数。
- AvgAccum < int > 存储所有传递的数字的移动平均值。
- SetAccum < int > 要求所有元素都是唯一的。
- ListAccum < int > 有一个按传入顺序排列的元素列表。
- MapAccum < int,SumAccum < int > > 使用键值对像映射一样存储数据。
- HeapAccum
将数据按升序或降序存储在元组中。还可以设置容量限制;当达到限制时,它将删除最高值或最低值。
这里有两个例子。第一个具有一跳全局 MinAccum:
CREATE QUERY GetFriends(vertex<Users> inputUser) FOR GRAPH Social {
MinAccum<uint> @@youngFriend;
Start = (inputUser);
Friends = SELECT t FROM Start:s- (IsFriend:e)-User:t
WHERE e.connectDt BETWEEN to_datetime("2019-01-01")
AND to_datetime("2020-01-01")
AND t.gender == "F";
ACCUM @@youngFriend += t.age;
PRINT Friends;
}
第二个具有两跳本地 AvgAccums:
CREATE QUERY GetFriends(vertex<Users> inputUser) FOR GRAPH Social {
AvgAccum @avgAge;
Start = (inputUser);
Friends1Hop = SELECT t FROM Start:s- (IsFriend:e)-:t;
Friends2Hop = SELECT t
FROM Friends1Hop:s- (IsFriend:e)-:t
ACCUM t.@avgAge += s.age;
PRINT Friends2Hop;
}
累积后
POST-ACCUM 独立于 ACCUM 子句。他们可以访问起始顶点或目标顶点(s 或 t 别名)。如果是全局累加器,工作会排队,在离开 POST-ACCUM 子句后生效。
查看使用全局最大累加器和求和累加器进行规格化的示例:
CREATE QUERY GetFriends(vertex<Users> inputUser) FOR GRAPH Social {
SumAccum<uint> @sumAge;
SumAccum<float> @normCNum;
MaxAccum<float> @@maxCNum;
Start = (inputUser);
Friends1Hop = SELECT t FROM Start:s- (IsFriend:e)-:t;
Friends2Hop = SELECT t
FROM Friends1Hop:s- (IsFriend:e)-:t
ACCUM t.@cNum += 1
POST-ACCUM @@maxCNum += t.@cNum;
Friends2Hop = select s FROM Freinds2Hop:s
POST-ACCUM s.@normCNum += s.@cNum/@@maxCNum;
PRINT Friends2Hop;
}
拥有
HAVING 子句是过滤数据的另一种方式。它类似于 WHERE 子句,但是 HAVING 子句只能访问选定的顶点和属性,而 WHERE 子句可以访问起始顶点和目标顶点。
CREATE QUERY GetFriends(vertex<Users> inputUser) FOR GRAPH Social {
AvgAccum @avgAge;
Start = (inputUser);
Friends1Hop = SELECT t FROM Start:s- (IsFriend:e)-:t;
Friends2Hop = SELECT t
FROM Friends1Hop:s- (IsFriend:e)-:t
ACCUM t.@avgAge += s.age
HAVING t.@avgAge > 30;
PRINT Friends2Hop;
}
排序依据和限制
最后,ORDER BY 可以对结果进行升序或降序排序。限制设置累加器中值的最大数量。
CREATE QUERY GetFriends(vertex<Users> inputUser) FOR GRAPH Social {
AvgAccum @avgAge;
Start = (inputUser);
Friends1Hop = SELECT t FROM Start:s- (IsFriend:e)-:t;
Friends2Hop = SELECT t
FROM Friends1Hop:s- (IsFriend:e)-:t
ACCUM t.@avgAge += s.age
ORDER BY t.@avgAge ASC
LIMIT 2;
PRINT Friends2Hop;
}
上面的例子将结果排序为升序,然后获取前两个,也就是最小的两个。
步骤 4: GSQL 演示
图表模式
对于模式中的每个顶点,您需要有一个主 ID。另外,对于每个顶点,你需要指定一个 FROM 和 to。请遵循以下语法:
CREATE VERTEX Test(PRIMARY_ID test_id STRING)
CREATE VERTEX Test2(PRIMARY_ID test2_id STRING)
CREATE DIRECTED EDGE TEST_TO_TEST2(FROM Test, To Test2)
CREATE UNDIRECTED EDGE TEST2_TO_TEST(FROM Test2, To Test)
加载数据
要加载数据,您需要定义一个加载作业。为此,您需要创建文件名变量并使用加载语句:
DEFINE FILENAME f1 = “/path”
LOAD f1 TO VERTEX person($”name”)
图形检查
对于本模块,您需要熟悉如何使用终端或控制台来检查图表。您可以使用以下选项选择要使用的图表:
use graph social
然后,您可以使用各种其他命令。列出的命令包括 from、to、directed、to、attributes、e_type。这里有一个例子:
SELECT * FROM person WHERE var=”Val”
基本 GSQL
您将创建的查询将返回 JSON。你也可以使用 curl 来运行这个图表。知道如何创建查询和结果。
CREATE QUERY name(VERTEX=person p) FOR GRAPH social;
Start = ()
Result = SELECT tgt from Start:src -{friendship x} -person-tgt
高级 GSQL
本模块回顾了累加器,如 OrAccum 和 AvgAccum 以及本地和全局累加器。这些是累积变量的不同方法。请记住,要创建全局变量,请使用两个@@,否则只需使用一个@符号。
GSQL 中的深度查询
对于深度查询,模块检查了khop和run query name(parameters)。
其他来源
在本文中,我回顾了每个视频系列,并对每个视频系列进行了总结或描述。此外,考试中还有一些杂七杂八的题目,比如如何使用 gadmin。如果您有时间,我建议您也查看一下 TigerGraph 的文档。
gad min:https://www . tiger graph . com/managing-tiger graph-servers-with-gad min/
TigerGraph 文档:https://www.tigergraph.com/tigergraph-docs-gsql-101/
视频系列原文链接:https://community . tiger graph . com/t/tiger graph-getting-started-guide/11
你现在准备好了
这是 TigerGraph 认证考试的文本版本。现在,去这里获得认证并了解本文之外的更多内容。祝好运,学习愉快!
你不想知道的关于 CSV 的一切
揭开 CSV 的神秘面纱,介绍使用 CSV 文件的工具和策略

CSV 是用于存储数据的更常见的文件格式之一,但是,它也充满了许多问题,这些问题会使使用它变得很痛苦。不像其他格式,如 JSON ,CSV 不是形式化或标准化的。这意味着有些东西可能被称为 CSV,但不一定能被您正在使用的 CSV 解析器正确读取。
我希望这篇文章能让你更好地理解使用 CSV 文件的挑战,以及一些转换和分析 CSV 格式数据的方法。我假设你有一定程度的技术经验,但不一定是你写代码。
什么是 CSV?
维基百科条目的第一句话提供了一个简单的(但已经有问题的)CSV 定义:
逗号分隔值(CSV)文件是使用逗号分隔值的分隔文本文件。CSV 文件以纯文本格式存储表格数据(数字和文本)。文件的每一行都是一条数据记录。每个记录由一个或多个字段组成,用逗号分隔。
根据这个定义,CSV 文件看起来应该是这样的(本例中的第一行代表列标题):
id,name,title
1,Alex Wennerberg,Cloud Data Engineer
这看起来相对简单,但是很快,问题就出现了。比如一个值里面有逗号怎么办?您可以将该值封装在双引号中,但是如果引号字符也包含在该值中呢?如果用于描述记录的字符(即换行符)出现在数据中会怎样?如果您的文件使用逗号以外的字符来描述值,该怎么办?诸如此类。这些问题的答案通常是特定的,并且依赖于系统,因此,根据您正在处理的 CSV 数据的来源,您需要应用一组不同的规则来正确解释该数据。如果幸运的话,您的源代码系统会提供完整的文档。如果不是,那么您必须猜测和/或逆向工程您的 CSV 文件遵循的任何规则集。
CSV 从 20 世纪 70 年代就开始使用了,但是没有标准化。最接近 CSV 标准的是 2005 年发布的 RFC 4180 。虽然这可能是一个有用的参考,但不能保证您正在使用的系统称为“CSV”文件的文件遵循这个 RFC。比如微软 Excel 明确没有。RFC 本身声明如下:
它没有规定任何类型的互联网标准。
美国国会图书馆提供了一个更加“真实”的 CSV 定义,并描述了许多常见的偏差:
在使用逗号字符代替数字中的小数点的语言环境中,字段/列之间的分隔符通常是分号。
换行符可以是 CR 或 LF,不一定是 CRLF。
一些基于 Unix 的应用程序可能使用不同的转义机制来指示某个分隔符出现在文本值中。单个字符前面有一个反斜杠字符,而不是用双引号将整个字符串括起来。单引号可能被视为等同于转义的双引号(也称为“文本限定”)。其他几个警告值得注意:
文件中的最后一条记录可能以换行符结尾,也可能不以换行符结尾。
通过使用几种 c 样式字符转义序列中的一种,不可打印的字符可以包含在文本字段中:###或\ o # # # Octal\x##十六进制;\d###十进制;和\u#### Unicode。
对字段和记录分隔符附近空白的处理因应用程序而异。如果文本字段值开头和结尾的空格很重要,则文本字符串应该是文本限定的,即用引号括起来。
在某些应用中,存在强数据类型的假设,未加引号的字段被认为是数字,加引号的字段被认为是文本数据。
我在实践中见过大部分或所有这些偏差。在某些情况下,工具会通过在记录之间拼接一个逗号来导出“CSV”,这很容易被打断(例如 SQL Server 的“CSV”格式)。
如果您有兴趣进一步阅读,LOC 页面有很多其他的细节,但是我不建议您假设任何 CSV 数据都符合 RFC 4180,或者您正在与之交互的任何解析器都实现了 RFC 4180。您可能想要查看您正在使用的特定 CSV 编写器或解析器的文档,如果它存在的话,以了解那个单独的系统如何处理 CSV。一些系统将相对较好地处理 CSV,而其他系统可能会以不可预测的方式失败。
CSV 工具
如果您正在处理 CSV 格式的数据,您可能希望转换您的 CSV 数据并将其加载到对 CSV 格式有不同期望的不同系统中。您可能还想从 CSV 加载数据,并对其执行转换和分析。这里有一些我觉得在处理 CSV 文件时有用的工具。这些工具中的大多数都假设您有一些使用命令行和从二进制或软件包仓库安装软件的经验。
这个命令行工具是我执行大多数与 CSV 相关的任务的首选工具——它可靠且速度极快,如果您正在处理大文件(> 1GB ),它没有太大的竞争力。它可以做许多简单的操作,包括切片数据、排序数据、执行基本分析、重新格式化 CSV 数据、修复不匹配的行等。查看文档以获取更多信息。如果您正在对数据进行更复杂的分析或转换,xsv 可能不合适,您可能想看看下面的一些其他工具。
另一个命令行工具,我在发现 XSV 之前使用 CSVkit。它起着类似的作用,但速度远不及前者。CSVkit 还有很多附加功能,例如在 CSV 和其他格式之间转换。如果你需要做一些 XSV 做不到的事情,或者如果你处理的文件比较小,性能不是很重要,那么这是一个很好的库。
大多数关系数据库都能够从 CSV 导入或导出。对于在大型数据集上进行复杂分析,这是一个非常好的策略,性能相对较好。如果您已经熟悉 SQL,这也很容易。我推荐 SQLite 来做这样的分析,因为它不需要服务器,可以直接写到磁盘,甚至可以在内存中运行,但是您也可以使用您更熟悉的另一个关系数据库。
一个相对较新的工具是 DuckDB ,一个嵌入式列数据库,它也可以读取 CSV。我还没有使用过这个,但如果您正在为分析工作流寻找一个更高性能的嵌入式数据库,这可能是一个很好的选择!
如果您熟悉 Pandas(Python 数据操作和分析库),它可能是处理 CSV 数据的一种有用方式,但在大型(几 GB)数据集上可能会遇到性能问题,具体取决于您的计算机规格。数据科学家经常结合使用 Pandas 和 Jupyter 进行数据分析,这两种工具都有一个广泛的社区。Pandas 非常适合在从 CSV 加载数据后对其进行更复杂的转换和分析。你也可以将数据从 Pandas 导出为多种不同的格式。
big query,** 红移 ,或者其他托管的柱状数据库**
如果您正在处理非常大量的数据(数十或数百 GB),您的计算机可能无法通过 SQLite 或 Pandas 处理本地运行的分析。您可能想要将您的 CSV 文件移动到列数据库中,这些托管工具让您不必担心设置数据库服务器。
用你选择的编程语言编写代码
如果你喜欢写代码,你的编程语言可能有一个 CSV 解析库。例如,我经常使用标准 Python 库的一部分 Python CSV 库。如果您正在处理大量数据并且对性能非常敏感,或者如果您想要执行上述工具无法处理的任务,这是一个有用的策略。在某些情况下,使用 Unix 工具如 awk 或 sed 可能对处理 CSV 有意义,但我通常会使用专门编写的命令行工具来处理 CSV。编写自己的代码对于修复格式错误的 CSV 可能特别有帮助,这样它就可以被不同的解析器读取。
提示和技巧
我确信这一点是显而易见的,但是在几乎所有情况下,您都不希望通过简单地用逗号分割文件或用逗号连接一系列值来编写自己的 CSV 解析器。如果您正在编写代码,几乎可以肯定存在一个 CSV 解析库,它可以处理尽可能多的我们已经讨论过的问题。但是,在某些情况下,您可能希望查看您的语言的 CSV 解析器的细节,以便更彻底地理解“CSV”的确切含义。
如果您的 CSV 文件来自机器导出,请查看该系统的文档以了解它是如何导出 CSV 的。例如,Excel、MySQL、PostgreSQL 等都在如何格式化 CSV 文件方面做出不同的决定。您正在使用的另一个专有或遗留系统可能会做出不同的决策。看看你正在使用的系统是否记录了它的 CSV 格式。在某些情况下,可能不会。
注意数据类型。CSV 是非类型化的,不同的系统可能有不同的方式来区分整数(1)和字符串(例如,邮政编码,01234)。确保您的系统不会将字符串 id(可以从零开始)转换成整数。请注意不同系统处理 NULL 值的方式之间的差异,以及 NULL 和空字符串之间的差异,空字符串在 CSV 文件中可能是相同的值,也可能不是相同的值。
如果您决定使用除 CSV 之外的任何其他开放格式,您可能希望考虑使用该格式而不是 CSV。
有时问题可以通过使用像 XSV 这样的工具来解决,使 CSV 中的所有字段都被引用,或者改变分隔符以便系统可以正确解析它。
如果您继续努力将您的 CSV 加载到某个系统中,而该系统可以加载另一种格式,如 JSON,那么可以尝试在加载之前将您的 CSV 转换为 JSON。JSON 是正式指定的,可能会导致较少的问题。
最终注释
在命令行查看Data Science以更全面地了解如何通过命令行处理数据,而不仅仅是 CSV 文件。
CSV 可能会令人沮丧,但请注意,你并不孤单,其他人可能也遇到了类似的问题。如果遇到问题,可以自由使用 Google 和 StackOverflow。CSV 的存在是有充分理由的——它简单、轻量级、可读,但是它表面上的简单隐藏了许多常见问题。当这些问题发生时,做好处理它们的准备。
链接和参考
- RFC 4180 —逗号分隔值(CSV)文件的通用格式和 MIME 类型
- CSV,逗号分隔值(国会图书馆)
- CSV 不是标准的
- 为什么(Ruby) CSV 标准库被破坏
- PEP 305 —用 Python 描述 CSV
原载于https://www.cloudbakers.com。**
深入 Python 编程所需的一切
你很可能已经被覆盖了

A 你准备好用 Python 编程了吗?对于一个初学者来说,跳入水中可能会很害怕,但是相信我,你只需要一条游泳裤就可以了。而我说的泳裤,是指一些基本的硬件和软件。
一个常见的问题是“Python 编程应该买哪台笔记本电脑?”好消息是 Python 不需要太多。在本文中,我将介绍一些基本知识来帮助您进行设置。
穿上裤子,让我们开始您的 Python 之旅。
- 硬件 —您的需求以及台式机和笔记本电脑的区别
- 软件 —选择适合您的操作系统
- 在手机上编程? —是啊,毕竟是 2020 年了
- 文本编辑器和 IDE s
- 在线 —使用在线编码环境
免责声明:本文中没有附属链接。
五金器具
我很想说任何机器都可以。如果你买了一个不到 5-10 年的带有现代操作系统的,它很可能会运行。我不是说这将是一个平稳的经历,但它会工作。您需要什么样的硬件取决于您打算编写什么样的代码。
说到硬件,你要么看台式电脑,要么看笔记本电脑。(除非你想在手机上开发。稍后将详细介绍)您的选择基于多种需求。这往往归结于功率与便携性。
桌面
Python 代码只是文本,所以代码本身非常简单。在决定购买什么样的硬件时,您还需要考虑其他因素。由于 CPU、RAM 和 GPU 不是那么重要,我将从您将与之交互的其他部分开始。

屏幕:
你的主要工具之一是你的屏幕。屏幕分辨率越高,可以显示的代码就越多。在高分辨率屏幕上,文本可能会显得很小,会让您的眼睛感到紧张,因此,请调整设置,以获得您可以使用几个小时的最佳设置。
对于您的桌面,您希望找到一个可以旋转 90 度的屏幕,这样您就可以显示更多行代码。4k 分辨率的屏幕现在越来越便宜,所以如果你负担得起,我建议你看看 27 英寸及以上支持 4k 的屏幕。如果你正在寻找一个预算屏幕,跳过 4k 选项,选择一个适合你桌子的。你可以在更小的屏幕上编码,但是我会在我的预算范围内得到最大的屏幕。
如果你发现自己经常在软件之间切换,你应该考虑超宽选项。有了这些显示器,您可以让您的应用程序并排排列。在 38 英寸超宽屏幕上工作了几年后,我发现很难回到双显示器设置。
键盘
你在键盘上打字的时间和看屏幕的时间差不多。毕竟你是写代码。对你有用的键盘,对另一个人来说可能是最糟糕的。选择合适的键盘是个人的事,只要记住你会用上几个小时,所以使用起来舒服很重要。
我过去用过各种键盘,最近扔掉了我定制的 WASD 键盘,换上了一个苹果魔法键盘。

上图:WASD 键盘,下图:苹果魔法键盘。两种截然不同的体验。作者图片
WASD 键盘有机械键(这是许多程序员的首选),移动距离很好。这是一个沉重的设备,使它显得坚实。对我来说,高度让我分心,因为长时间打字会让我的手腕疼痛。你可以通过获得手腕支撑来避免这一点,但超扁平的苹果 Magic keyboard 对我来说更舒适。苹果魔键的行程更短,但键盘的手感非常舒适,我可以输入几天。
在你下定决心之前,你应该试着弹奏几次键盘。如果每天工作 10 个小时后感觉良好,你可能已经找到了你的打字伴侣。如果你住的地方有很好的退货选择,试一试,如果不适合你的手指,就把它送回去。
如果一个普通的平面键盘会疼,你可以寻找键盘分离和倾斜的选项。我姐夫最近向我介绍了 ergo DOX EZ T1 键盘,这看起来是一个非常有趣的选择。
我建议你买一个美式布局的键盘。这种布局非常适合编写代码。我是挪威人,但是因为这个原因,我所有的键盘都是美式布局。如果你需要你的母语字母,你可以在软件中切换语言。我看着你“啊,啊,啊”。
你可能不会经常使用数字小键盘。在这种情况下,你可以看看紧凑型键盘。一些制造商创造了他们键盘的紧凑版本。确保他们没有把箭头键放在奇怪的位置。
老鼠
很容易说你用什么鼠标都没关系,因为毕竟你不会经常用你的鼠标。即使打字是你的主要活动,你也会浏览网页(主要是 StackOverflow)和用鼠标做很多其他的操作。当谈到偏好时,这就像键盘一样个人化,但是要确保你得到的鼠标不会伤到你的手。你的手是你的工具,好好保管它!
虽然我很喜欢苹果的神奇键盘,但神奇鼠标并没有那么棒。在我看来,苹果从来就不擅长鼠标,而苹果神奇鼠标的人机工程学外形非常糟糕。我最近使用它的唯一原因是因为它上面集成了触控板。它非常适合浏览,但当我需要做一些更繁重的工作时,我旁边有一个 Steelseries Kana,因为握起来更舒服。

苹果魔术鼠标与支持钢系列假名。作者图片
购买鼠标时,您应该考虑外形因素。使用普通键盘已经让你的手腕扭曲到不自然的位置。你可以考虑用一个稍微垂直的鼠标来减轻你手腕的压力。罗技 MX Master 3 目前是一个受欢迎的选择,并略有倾斜。我目前有这个订单,并希望它像所有评论说的那样好。如果效果更好的话,你可以得到全垂直布局或操纵杆布局的鼠标。
CPU 和内存
关于 CPU 就不多说了,因为大多数 CPU 都会运行 Python。一个更强的 CPU 总是比一个弱的更快,所以购买你能负担得起的 CPU。Python 已经是慢语言了。没有必要用一个糟糕的 CPU 使它更慢。
注意 Python 也是单线程的。
来自 Python 文档:
在 CPython 中,由于全局解释器锁,一次只有一个线程可以执行 Python 代码(尽管某些面向性能的库可能会克服这个限制)。如果你想让你的应用更好的利用多核机器的计算资源,建议你使用
[multiprocessing](https://docs.python.org/3.8/library/multiprocessing.html#module-multiprocessing)或者[concurrent.futures.ProcessPoolExecutor](https://docs.python.org/3.8/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor)。但是,如果您想要同时运行多个 I/O 绑定的任务,线程仍然是一个合适的模型。
如果你发现自己在进行繁重的计算,你可能需要更多的内存,但是对于大多数任务,你不需要太多。有些任务需要在处理时将结果存储在内存中,但是对于大多数任务来说,使用少量 RAM 应该没问题。
请记住,像浏览器和 IDE 这样的应用程序将会使用大量的 RAM,所以如果您的预算不紧张,一般来说就使用更多的 RAM。4GB 可能可以,但这是最低端的容量,您会看到大部分容量可能会在一天中使用。今天,大多数桌面都配备了 8GB-64GB 的 RAM——这对于 Python 来说当然没有问题。
国家政治保卫局。参见 OGPU
你可能已经猜到了,Python 也不是 GPU 的重地。几乎任何显卡都可以。你可以考虑的一件事是,你可以使用 GPU 进行机器学习,所以如果你打算走这条路,你可以投资一个更好的显卡,只是为了做好准备。
硬盘驱动器
Python 代码只是文本,如果你看看你的 python 程序,你会发现我们谈论的是 kB 而不是 MB。这意味着代码本身不需要太多的硬盘空间。另一方面,您用代码创建的数据可能需要空间,所以这是您必须添加到等式中的内容。另一个会消耗硬盘空间的是你的操作系统和其他安装的软件。
有两种硬盘:固态硬盘 SSD 和硬盘 HDD。固态硬盘比硬盘快得多,所以一般来说,你会喜欢使用固态硬盘。与硬盘相比,它们的价格很高,所以还是要看预算。您可以考虑将 SSD 用于您的操作系统,将 HDD 用作第二个硬盘,以最大化大小。
我们在云中存储越来越多的内容,大多数情况下你的代码会被上传到 Github。这意味着对硬盘的需求不像 10-20 年前那么重要了。我用 iCloud 储存大部分工作文件。它既可以作为备份,也很容易在设备之间同步文件。
网络摄像机
我猜你没想到会这样。当你购买一台笔记本电脑时,一个网络摄像头几乎总是包含在屏幕框中。当你买台式机时,你必须单独购买(除非你买 iMac 或类似的产品)。如果你从初级爱好者变成初级开发人员,你很可能会看到自己与团队进行数字会议。你不想成为那个没有相机的人。作为奖励,它迫使你保持房间整洁。
笔记本电脑
好了,说到便携小兄弟。
你总是可以带额外的设备,比如键盘和鼠标,但是让我们来关注是什么让笔记本电脑成为笔记本电脑。我们在这里看到的例子有点贵,但请记住,你可以用二手笔记本电脑,我也会告诉你一个秘密。你可以带着你能找到的最便宜的笔记本电脑离开。关键是在线编码环境。

屏幕
你将整天看着你的屏幕。11 英寸或 13 英寸会给你带来很大的便携性,但 15 英寸- 17 英寸会给你更多的空间。配备 retina 显示屏(3072×1920)的 Macbook Pro 16 英寸 2019 型号的尺寸与旧的 15 英寸相同。戴尔 XPS、联想 X1 Carbon 和 Razer Blade 都拥有 3840 x 2160 的出色分辨率。使用更大的屏幕,你可以获得更好的分辨率,但是你放弃了一些便携性。在我看来,它们是如此轻,无论如何,这是一个明显的优势去有点大。
根据 Just Josh 的说法,与他的 Surface Book 2 15 英寸和 Aero 17 英寸笔记本电脑相比,他可以在 Macbook Pro 16 英寸上查看多 30%的代码行。它们都具有相同的 8.5 英寸垂直屏幕高度。
键盘
如果你想买 MacBook Pro,你必须知道在 2015 年至 2019 年期间,苹果公司为它们配备了蝴蝶键盘。这种键盘因故障而臭名昭著,键程几乎不存在。2019 年,他们开始发运配备新苹果魔法键盘的型号,这些是打字的乐趣。它们不是机械的,但感觉就像独立版的魔法键盘。如果你买了一台蝴蝶键盘的 MacBook,苹果有一个保修计划,如果你有问题,你可以换一台。
不管你喜不喜欢,苹果的产品都有触控条而不是 F 键。我喜欢这一点,因为它提供了很大的灵活性,但也有很多人讨厌它们。如果您依赖功能键,请确保尝试 touch bar 来下定决心。
一些游戏笔记本电脑已经开始包括机械键盘,所以如果你正在寻找那种触感,你也可以在旅途中得到它。
当心!拿到笔记本电脑需要注意的一点是,厂商需要做一些妥协,让这些机器变得轻薄小巧。你必须检查键盘的布局。在 MacBook Pros 的最新阵容中,ESC 键以其物理形式回归。对程序员来说是个好消息。Razer Blade 有一个荒谬的箭头键位置,但看起来他们在最新的阵容中改变了这一点。确保你做了一些研究,这样你就不会讨厌每一次按键。
轨迹板
一些制造商还不如不包括触控板。以我的经验来看,没有人能与 MacBook 触控板相媲美。也许是 Razer,但我自己没有试过,只听同事说它很棒。如果你不想带鼠标,确保你对触控板满意。
如果触控板很糟糕,你可能会更好地使用键盘导航。至少不是完全的损失。
软件
希望你现在已经拿到了一台机器。但是软件呢。你需要软件来运行代码,对吗?根据您正在编程的内容,您可以对您的编程机器进行最小的设置。
我们首先要看的是操作系统。
操作系统
要开始编程,你需要一个操作系统(OS)。Python 是跨平台的,可以在 Windows、macOS 和 Linux 上工作。选择操作系统主要是个人喜好的问题。
根据 Stack Overflow 的 2020 年调查,45.8%使用 Windows 开发,27.5%在 macOS 上工作,26.6%在 Linux 上工作。
Windows 操作系统
你可能对视窗很熟悉,因为它们在全世界被广泛使用。Windows 的最新版本是 Windows 10。一般来说,你应该使用最新版本的操作系统,但如果你有一台旧机器或其他软件需要它,你可能会被困在 Windows 7 或更旧的版本。这两个你都应该没问题,但是要注意如果你想用 Python 3.5 或者更高版本的话, Windows XP 是不支持的。
如果您使用 Windows,有一些 shell 选项适合您。Windows 自带命令行,也有 Powershell。Powershell 感觉更像是一个普通的终端,你可以从 Linux 或者 Mac 世界中了解到。
更好的新来者是 Windows 终端。这款高度可定制的终端非常好用。

运行中的新 Windows 终端。作者图片
在过去,人们对某些库在 Windows 上不被支持有疑问。您可能不知道将来会使用什么库,但是如果您最终在安装任何库时遇到问题,这可能就是原因。
Windows 许可证通常与您购买的机器捆绑在一起。如果不是,你看到的费用在 139-309 美元之间。
马科斯
Mac 和 Linux 都属于 UNIX 家族。你可以把它们看作两个不同的分支。这两种操作系统的开发感觉是相似的。
Mac 有一个开箱即用的内置终端。如果您喜欢更大的灵活性,您可以安装各种版本,比如 iTerm,但是原始版本可以完美地完成它的工作。Python 预装在 macOS 中,但请确保检查版本,以便保持最新。
大多数文本编辑器和 ide 都在 macOS 上工作。
macOS 和 Windows 一样,不是开源的,但它是机器自带的。macOS 只能在 Mac 上运行(官方),所以你只能依赖苹果的硬件。
Linux 操作系统
Linux 并不是真正的操作系统,它是一个内核。你所认为的操作系统是发行版。使用 Linux 的一个好处是这些发行版是轻量级的,并且是高度可定制的。你可以货比三家,找到最适合你的。一些流行的发行版有 Ubuntu、Mint、Fedora 和 CentOS。
Linux 非常适合开发。它还带有一个终端,许多文本编辑器和 ide 都在 Linux 上工作。Linux 是开源的,所以它是一个预算友好的选择。
计算机编程语言
当然,你需要 Python。前往 python.org,下载安装程序,并运行它。如果您在终端中编写“python3”(如果您下载了 python3 版本),您应该看到它执行并打印您运行的 python 版本。
文本编辑器和 ide
有很多文本编辑器,但是请不要成为那个说你可以在记事本中写代码的人。至少知道如何通过说“哦,我指的是 Notepad++”来拯救自己,以防你受到邪恶的盯视…
你在文本编辑器中寻找的一些东西是:
- 语法突出显示。Python 是一种流行的语言,所以大多数文本编辑器都将它作为标准或可下载的扩展。
- 代码预测。如果你已经创建了一个名为
ninja_turtles的变量,在你开始输入 ninj 之后,编辑器会预测你的变量名,这很好……让软件在你输入的时候寻找模块可以用于快速编码和学习。 - 制表符缩进。大多数编辑器允许你选择你想要在一个标签中有多少空格。Python 的 PEP8(圣经)指出你应该使用 4 个空格。Python 3 甚至不允许混合制表符和空格。
我们只看精选的几个。确保你浏览网页寻找你最喜欢的。
原子
Atom 是一个轻量级的文本编辑器,可以在所有操作系统上运行。它是高度可定制的,有主题和 CSS/Less 定制。包管理器、文件系统浏览器、git 集成,以及最后但同样重要的“Teletype ”,它让您可以实时地对同一代码进行协作,这是文本编辑器的最佳选择。

感觉大胆运行一个轻的主题。左边是浏览器,中间是代码,右边是设置。使用安装的社区制作的脚本在底层执行代码。作者图片
托尼
Thonny 是一个极简的 IDE,非常适合初学者。借助强大的调试器,您可以确保理解您的代码。我过去从未使用过 Thonny,但很快就喜欢上了这个工具。

Thonny 及其出色的调试器。作者图片
崇高
崇高出现在游戏中已经有一段时间了,被很多人使用。它有一些漂亮的特性,比如允许你一次重命名多个变量的“多重选择”和定制。
朱皮特
Jupyter 是一个开源的 web 应用程序,允许你创建和共享包含实时代码、等式、可视化和叙述性文本的文档。用途包括:数据清理和转换、数值模拟、统计建模、数据可视化、机器学习等等。
你可能以前见过使用 Jupyter的漂亮的图形数据展示。可以安装 Jupyter 笔记本,也可以使用浏览器版本。如果你想处理数据,Jupyter 是你的工具。

Jupyter 进行中。作者图片
Visual Studio IDE
由微软开发,受到许多人的喜爱。这个广泛的工具允许你写代码,调试,安装库,使用 Git 进行源代码控制和单元测试你的代码。
要找到适合你的版本,去他们的比较页面看看,并确保你看了他们的 python 特定页面。
在手机上编程
给你一个小惊喜。你可能没有意识到,你信任的旧手机可以用来实现伟大的事情。我必须承认,我从来没有在我的手机上做过任何适当的编码(只有当我在度假时迫切需要时),但从我在网上看到的情况来看,有几个应用程序可以完成这项工作。
ios
Pythonista 是一款流行的软件,是一款面向手机开发的完整 IDE。
Koder 是另一种选择。这是一个代码编辑器,不是一个完整的 IDE,但它有语法高亮显示和对 Dropbox 等云服务的支持。
Buffer Editor 看起来圆滑简约。它支持 Git 和 Dropbox。
机器人
Pydroid 遍布脸书的 Python 团体,有了 pip 支持、GUI 支持,比如 PyQT、离线解释器、语法高亮和代码预测,它成为流行的选择并不奇怪。
在线编程
如果你喜欢最大的可移植性,你可以考虑使用在线编辑器。你可能会在安装库或类似的东西时遇到一些困难,但是你也可以在网上完成很多工作。去年,我在大学为我们的 python 课程使用了 6 个月的在线编辑器。用浏览器登录任何一台电脑的好处都是很大的。
这里是一些你可以尝试的概述。记住,总有比我发现的更多的选择,所以一定要做一些研究。也许你会找到另一个你喜欢的服务。
回复它
它拥有多种语言,其中包括 python。您可以与其他程序员合作,连接到您的 Git 存储库,并且它有插件支持。免费版将带你走得更远,还有团队定价选项。

repl.it 运行“生命的游戏”。作者图片
Pythonanywhere
顾名思义, pythonanywhere 让你无论身在何处都可以编码。这项服务是 python 独有的,在免费版本中你可以同时运行两个控制台。

pythonanywhere 玩 Yahtzee。作者图片
编程
Programiz 有一个简单易用的在线编辑器。据我所知,它只是一个供你测试代码的编辑器,而不是你存储文件的环境。如果我错了,请纠正我。

运行非常著名的“Hello World”程序。作者图片
最后
我希望 Python 入门看起来不再可怕,如果它更早的话。如你所见,开始学习 Python 并不需要太多。如果你有浏览器,你可以开始学习。当你对 Python 有了更多的了解,并意识到这是你喜欢做的事情时,你可以考虑升级。当你这样做的时候,你仍然不需要太多的继续。这就是这种轻量级编程语言的美妙之处。
当然,买你买得起的。你必须时刻考虑你采购的东西是否需要,但是硬件永远不可能太好。
我希望你会喜欢这个奇妙的旅程,现在我们已经讨论了各种替代方案,有些选择是明确的。
M
关于相关性你需要知道的一切

上海崇明岛上的一群白鹭
皮尔森、斯皮尔曼、肯德尔、B iserial、Tetrachoric 等等
相关性是几乎所有部门都使用的最基本的统计概念之一。
例如,在投资组合管理中,相关性经常被用来衡量投资组合中包含的资产的多样化程度。选择彼此相关性低或负相关的资产有助于降低投资组合的风险。此外,在营销研究中,相关性提供了关于营销策略和业务成果的见解,这进一步帮助营销人员做出可操作的决策,并最终发展业务。
简而言之,当一组变量中的测量值与另一组变量中的测量值以一种并非偶然的方式相关时,我们使用相关性来以定量的方式陈述两组变量之间关系的强度和方向。
或许,你可能和我有相似的经历,纠结于许多不同类型的相关性(例如皮尔森、斯皮尔曼、肯德尔、比瑟里尔、四分位数等等)。有什么区别?我们应该使用哪一个?我们如何在 Python 中计算它们?****
在本帖中,我将与你分享我回答这些问题的笔记。像往常一样,我提供一个笔记本给你练习,可以从 my Github 访问。
几个关键术语
在我们深入研究相关性之前,如果能列出一些关键术语并放在手边就更好了。
1。标准差**:它是一组值的变化量或离差的度量(它只是方差σ 的平方根)。
- ****总体标准差: N 为总体大小,为总体均值。

- ****样本标准差: n 为样本大小, x̄ 为样本均值。

****2。协方差:它是两个变量从它们的平均值前后变化的程度的度量。
- ****人口协方差: N 为人口规模,为人口均值。

- ****样本协方差: n 为样本大小, x̅/y̅ 为样本均值。

****3。参数检验:它假设数据中潜在的统计分布。必须满足有效性条件,以便参数测试的结果是可靠的。
****4。非参数检验:它不依赖于任何分布,因此可以在有效性的参数条件不满足时应用。
****5。效应大小/强度:相关系数在. 10 到. 29 之间代表小关联,系数在. 30 到. 49 之间代表中等关联,系数在. 50 及以上代表大关联或关系。
6。分类变量:又称离散变量或定性变量。分类变量可进一步分为名义变量,二分变量或序数变量。****
- 名义变量是指有两个或两个以上类别,但没有内在顺序的变量。例如,财产类型(房屋、单元和公寓)、公司名称、宗教、颜色偏好和邮政编码。
- 二分变量是名义变量,但只有两个类别或级别。比如性别(男女),是/否问题,电信流失数据(流失或停留)。
- 序数变量是和名义变量一样有两个或两个以上类别的变量,但也可以排序或排名。例如,汽车尺寸(超小型、紧凑型、中型、豪华型)、经济地位(下层、中层或上层)、排名 5 种啤酒、满意度(非常不满意、有些不满意、有些不满意、不满意)。
7。连续变量:又称数量变量。这种类型的数据具有相邻单元之间的有序和等间隔的性质。连续变量可进一步分类为区间或比率变量。****
- 区间变量:可以沿连续统测量的,有数值的数据。例如,温度、出生年份、满意度(分值单位,1-10)和鞋码。
- 比率变量:它们是区间变量,但是有明确的定义 0,表示没有该变量。比如收入,价格,距离,一个家庭的孩子数,开车时间,剂量等等。
“比率”这个名称反映了这样一个事实,即可以对比率变量的值执行乘法和除法运算。因此,我们可以说 15 美元的价格比 5 美元的价格贵三倍。然而,10°C 的温度不应被视为 5°C 的两倍。它仅高出 5°C(即,只能对区间变量的值应用加法和减法运算)。
这里有一个取自 GraphPad 的图表(图 1)可以帮助你理解这些不同的变量

图 1 | 可变刻度
8。单调关系:在单调关系中,两个变量趋向于以下之一:(1)随着一个变量的值增加,另一个变量的值也增加;或者(2)随着一个变量值的增加,另一个变量值减少。,但不一定以恒定的速率(图 2)。
9。线性关系:线性关系中,两个变量的作用与单调关系相同,但速率不变。趋势可以用直线来模拟。线性关系都是单调的,但不是所有的单调关系都是线性的。

图 2 |单调关系的图示
10。并列等级:在计算 Spearman 相关系数时,这是一列中具有相同等级的两个项目。
11。一致/不一致:描述两个样本的排序是否相同(图 3)。

图 3 |和谐与不和谐的定义
理解c或关系的强度、方向和意义
两个变量之间的相关性用一个数字相关系数来量化,通常在 1 到+1 之间变化。零表示没有相关性,1 表示完全或完美的相关性。相关强度从 0 增加到+1,从 0 增加到 1。符号表示相关的方向。负相关意味着这两个变量是反向相关的。
一般来说,除了相关性的强弱,我们还需要报告其统计显著性,即 p 值。p 值表示这种相关强度可能偶然出现的概率。统计上显著的相关性不一定意味着相关性的强度很强。
比如两个相关系数 0.32 ( p < 0.01 )和 0.93 ( p < 0.05 )。即使 0.32 的相关性具有更显著的水平( p < 0.01 ),与 0.93 的相关性相比,它仍然是较弱的相关性。 p < 0.01 仅确保 99%的时间相关性为 0.32。
皮尔逊相关(参数检验)
皮尔逊相关系数(皮尔逊积差相关系数)是线性相关变量之间关系程度的最广泛使用的统计度量。用字母 r 表示。**
Pearson 的 r 是通过将这两个变量的协方差除以它们的标准差的乘积来计算的。

其计算要求以下数据假设有效:
- 区间或比率变量****
- 线性相关
在实践中,第二个假设是通过用测试的两个变量制作散点图来直观检查的(图 4)。

图 4 |用于目视检查的散点图
“皮尔逊 r 并没有假设正态性。许多人认为,为了证明 r 的计算是正确的,这两个变量必须是正态分布的。但许多人也认为,他们在喝酒后可以更好地驾驶。”
艾伯特·库尔茨和塞缪尔·梅奥
皮尔森 r 本身并不假设正态性!实际上,我们仍然需要检查二元正态性的原因是为了满足显著性统计检验的假设。
Python 中有几种不同的检验正态性的方法,包括直方图(**pyplot.hist**()),正态 Q-Q 图 ( [**statsmodels.qqplot**()](https://www.statsmodels.org/stable/generated/statsmodels.graphics.gofplots.qqplot.html)),夏皮罗-维尔克检验(**scipy.stats.shapiro**()),达戈斯蒂诺检验(**scipy.stats.normaltest**(),安德森-达令检验(**scipy.stats.anderson**())。
我们需要注意的另一件事是,正如其公式中的标准差所表明的那样,皮尔逊相关系数自然对偏斜分布和异常值敏感。
如果我们的数据满足上述假设和先决条件,我们可以通过调用**scipy.stats.pearsonr**(*x***,** *y*)在 Python 中轻松计算 Pearson 的 r,这将返回 Pearson 相关系数和p-值。或者我们可以使用**pandas.dataframe.corr**(method=’pearson’)来寻找数据帧中所有列的成对相关性。**
斯皮尔曼相关(非参数检验)
在大多数情况下,如果我们的数据满足所有要求,Pearson 的 r 是关系的最佳度量,应该使用。然而,并不是一切都能如人所愿。幸运的是,当我们得到不理想的数据时,仍然有几个选项使我们能够得到相关系数。
Spearman 秩相关系数通常表示为 ρ (rho)或 r s ,是 Pearson 相关系数的非参数版本。对于单调关系,可以处理序数、区间或比率变量。
顾名思义,斯皮尔曼的 ρ 依赖于给定的两个变量的秩而不是它们的值。其简单形式公式如下:

其中 n 为样本大小, di 为 与 样本的秩差。请看图 5 中的一个例子,计算距离机场的距离和瓶装水的价格之间的相关性,我相信这将有助于你立即理解公式。

图 5 | Spearman 等级相关系数的计算
正如我们从图 5 中看到的,Spearman 相关性对强异常值的敏感度低于 Pearson 相关性,因为 Spearman 的 ρ 将异常值限制在其等级值内。
另一件应该注意的事情是并列的等级(图 5 中的商店#2 和#4)。当这种情况发生时,我们可以取他们本来会占据的等级的平均值。当联系数相对于 n 较小(1 或 2)时,仍然可以使用简单形式的公式。
否则,我们需要使用 Spearman 公式的完整版本,它将处理并列的等级:

其中 ui 是第一个样本中第个观测值的秩,第 vi 是第二个样本中第个观测值的秩。****
在 Python 中,我们可以调用**scipy.stats.spearmanr**(),它返回我们两个值 ρ 和 p- 。或者我们可以使用**pandas.dataframe.corr**(method=’spearman’)来查找数据帧中所有列的成对相关性。
肯德尔相关性(非参数检验)
一般来说,当样本量很小且有很多并列秩时,肯德尔相关常表示为τ(Tau)(Tau 有三个版本,即 Tau-a、Tau-b、Tau-c ,是 Spearman 相关的最佳替代。******
肯德尔相关性要求与斯皮尔曼相关性相同的数据假设,即 1)序数、区间或比率变量和 2) 两个变量之间的单调关系。
这里只介绍 Tau-b(这是**scipy.stats.kendalltau**(x, y)中使用的方法),定义为:

其中𝑁𝑐和𝑁𝑑分别表示样本中一致对的数量和不一致对的数量。𝑇𝑥表示仅与第一个响应变量相关的配对数量,𝑇𝑦表示仅与第二个变量相关的配对数量。如果同一对在 x 和 y 中出现平局,则不会添加到𝑇𝑥或𝑇𝑦.****
在 Python 中,我们可以调用**scipy.stats.kendalltau**(x, y),它返回给我们 Tau 和 p- 值。或者我们可以使用**pandas.dataframe.corr**(method=’kendall’)来查找数据帧中所有列的成对相关性。
总的来说,关于数据中异常值和差异的容忍度,Kendall 相关性是最稳健的度量,其次是 Spearman 相关性,而 Pearson 相关性是最敏感的。
点双列相关
当我们需要将一个连续变量与另一个二分变量相关时,我们可以使用点双列相关。****
点双列的相关性通常用符号 rpb 表示,计算如下:

其中 𝑀1 是变量 y 的第 1 组中所有数据点在连续变量 x 上的平均值, 𝑀0 是变量 y 的第 2 组中所有数据点在连续变量 x 上的平均值, 𝑛1 是第 1 组中的数据点数, 𝑛0 是第 2 组中的数据点数,𝑛是总样本量。
在 Python 中,这可以通过调用**scipy.stats.pointbiserialr(***x***,** *y***)**来计算,它再次返回给我们一个点双列相关系数和它的p-值。**
我们应该注意到有一个 双列的相关 ,它也是一个连续变量与另一个二分变量的相关系数。但是,这里的二分变量应该是基本连续且正态分布的。****
换句话说,这种类型的二分变量,在现实中是连续的,正态分布的,但只记录了两类。因此可称为连续二分法。****
与分类二分法相比,连续二分法可以被认为是一个正态分布的连续变量,它被人为地分为两类。例如,通过使用某个阈值,测试分数可以分为通过和失败。销售可以分为不好的和好的等等。****
然而,你可能会问,为什么我要通过把连续变量转换成二分变量来丢失信息呢?说实话,我也不知道。也许统计学家只是喜欢发明公式。无论如何,在这种情况下,我只是使用皮尔逊相关性。****
四分相关
当我们希望将两个二分变量相互关联时,Tetrachoric 相关性旨在估计 Pearson r 。实际上,这些变量中的每一个都可能是连续的和正态分布的,但只记录在两个类别中。
正如它的定义所显示的,Tetrachoric 关联的适用性并不十分普遍。本质上,它根本不适用于分类变量。对于这样的情况,我们要用φ的关联 ( φ, AKA。马修斯相关系数(MCC)) 改为。
在 python 中,我们可以使用**sklearn.metrics.matthews_corrcoef()**得到 φ 。
最后,我们应该注意到,还有更多用于相关性计算的技术,本文没有涉及。我们一定要根据我们的数据和目的来选择合适的方法。我希望你能从这篇文章中学到一些有用的东西。
感谢阅读!
以下是一些有用的链接:
- 名词性、序数、区间&比率变量+【例题】
- 什么是区间数据?+【例题、变量&分析】
- 名义变量、序数变量、区间变量和比率变量的测量标度
- 肯德尔τ(肯德尔等级相关系数)
- 点-双列和双列相关性
- phi、Matthews 和 Pearson 相关系数之间的关系
和往常一样,我欢迎反馈、建设性的批评以及听到关于您的数据科学项目的信息。可以通过 Linkedin 和我的网站找到我。
在 3 分钟内你需要知道的关于日期格式的一切
每个分析师都知道。你必须合并十个文件,每个文件都有不同的日期格式。我将向您展示如何转换日期以便进一步处理。

假设您收到了十个不同的文件,您的工作是匹配这些数据以获得新的见解。不管您是通过 csv 还是 api 获得数据,您至少会收到五种不同的日期格式。这可能具有挑战性。Python 的 datetime 提供了一些非常有趣的函数来处理这类问题。
[In]
import datetime
now = datetime.datetime.now()
now
[Out]
datetime.datetime(2020, 1, 30, 21, 4, 11, 887948)
变量现在包含年、月、日和当前时间。在许多情况下,获得年、月和日就足够了。日期时间对象的每一部分都可以单独访问。
[In]
print(now.year)
print(now.month)
print(now.day)
[Out]
2020
1
30
但是它如何帮助转换数据呢? Datetime 对象提供了函数 strftime ,使得在 Python 中处理日期变得如此简单。
[In]
now.strftime('%Y-%m-%d')
[Out]
'2020-01-30'
表达式 %Y 是一个已定义的指令,它从日期时间对象中提取年份。这同样适用于其他对象。有趣的是,您可以以任何想要的方式格式化结果字符串。在本例中,我们在年、月和日之间添加了“ - ”。我们还可以添加任何其他字符:
[In]
now.strftime('%Y/%m/%d')
[Out]
'2020/01/30'
通常,您会收到一个需要首先转换的字符串:
delivered_date = 'Sep, 26 2019'
您可以使用 strptime 将我们的变量 delivered_date 转换为 datetime 对象:
[In]
datetime.datetime.strptime(delivered_date, '%b, %d %Y')
[Out]
datetime.datetime(2019, 9, 26, 0, 0)
strptime 需要两个参数。第一个是字符串,第二个是给定表达式的结构。在这种情况下,我们有一个月的短版本,带有一个逗号 %b,,后面是日期 %x 和年份 %Y 。
让我们看一下标题图片中的例子。我们总是希望格式 YYYY-MM-DD 最后:
我们从 2020 年 1 月 1 日开始
[In]
date_1 = 'Jan, 01 2020'
datetime.datetime.strptime(date_1, '%b, %d %Y').strftime('%Y-%m-%d')[Out]
'2020-01-01'
2020 年 1 月 1 日
[In]
date_2 = '2020 Jan 01'
datetime.datetime.strptime(date_3, '%Y %b %d').strftime('%Y-%m-%d)[Out]
'2020-01-20'
20/01/20
[In]
date_3 = '20/01/20'
datetime.datetime.strptime(date_4, '%y/%m/%d').strftime('%Y-%m-%d')[Out]
'2020-01-20'
2020 年 1 月 20 日
[In]
date_4 = '20.01.2020'
datetime.datetime.strptime(date_4, '%d.%m.%Y').strftime('%Y-%m-%d')
[Out]
'2020-01-20'
- 2020 年 1 月
[In]
date_5 = '1\. January 2020'
datetime.datetime.strptime(date_6, '%d. %B %Y').strftime('%Y-%m-%d')
[Out]
'2020-01-20'
结论
Python 的 datetime 提供了一个非常简单的框架来处理日期格式。格式化数据以便进一步处理也非常有用。例如,无论是 Excel 还是 CSV 文件都没关系。所有格式都可以转换。我希望你喜欢阅读,并且可以带走一些有用的东西。
如果您喜欢中级数据科学,并且还没有注册,请随时使用我的推荐链接加入社区。
关于熊猫的“loc”和“iloc”你需要知道的一切
明确区分 loc 和 iloc

Javier Allegue Barros 在 Unsplash 上拍摄的照片
Pandas 是使用最广泛的数据分析和操作库,它提供了许多灵活方便的功能,可以简化和加快数据分析过程。在这篇文章中,我将介绍两个重要的工具,它们用于根据指定的行和列从数据帧中选择数据。让我们先介绍它们,并通过不同种类的例子来建立一个全面的理解。
- 位置:按行和列的标签选择
- iloc:按行和列的位置选择
随着我们对例子的研究,这种区别变得很明显。一如既往,我们从进口熊猫开始。
import pandas as pd
import numpy as np
我们将在 kaggle 上的电信客户流失数据集上做例子。让我们将数据集读入熊猫数据帧。
df = pd.read_csv("Projects/churn_prediction/Telco-Customer-Churn.csv")

数据集包括 21 列,但我们只能看到适合屏幕的列。
loc 用于通过标签选择数据。列的标签是列名。例如,customerID、gender、SeniorCitizen 是前三个列名(即标签)。我们需要小心行标签。由于我们没有分配任何特定的索引,pandas 默认创建整数索引。因此,行标签是从 0 开始向上的整数。与 iloc 一起使用的行位置也是从 0 开始的整数。我们将通过例子来看熊猫如何用 loc 和 iloc 不同地处理行。
- 选择行“2”和列“性别”

它返回行“2”的“性别”列中的值
- 选择最多“5”的行标签以及“性别”和“伴侣”列

- 选择行标签“2”、“4”、“5”和“InternetService”列

我们还可以过滤数据帧,然后应用 loc 或 iloc
- 选择带有合作伙伴的客户的行标签“10”、“InternetService”和“PhoneService”列(Partner == 'Yes ')

我们过滤数据帧,但不改变索引。因此,所得数据帧的索引仅包含未被省略的行的标签。因此,当使用 loc[:10]时,我们可以选择标签达到“10”的行。o 另一方面,如果我们在应用过滤器后使用 iloc[:10],我们会得到 10 行,因为 iloc 按位置选择,而不考虑标签。

正如您所注意到的,我们还需要改变选择列的方式。我们还需要将列的位置传递给 iloc。
- 选择前 5 行和前 5 列

- 选择最后 5 行和最后 5 列。
这些位置从 0 开始。如果我们从末尾开始定位,我们从-1 开始,所以我们使用“-5:”来选择最后五个。

我们也可以应用 lambda 函数。
- 选择第三行到第 15 行,仅显示“合作伙伴”和“互联网服务”列。

我们可以在两者之间选择位置或标签。
- 选择 20 到 25 之间的行位置,4 到 6 之间的列位置。

如果您试图将标签传递给 iloc,Pandas 会友好地返回如下信息反馈:
**ValueError**: Location based indexing can only have [integer, integer slice (START point is INCLUDED, END point is EXCLUDED), listlike of integers, boolean array] types
当我们将位置传递给 loc 时,会返回类似的错误。
我希望 loc 和 iloc 之间的区别现在已经非常清楚了。要掌握知识,真正“学”,我建议大量练习。只是尝试不同的例子,你会在很短的时间内习惯它们。
感谢您的阅读。如果您有任何反馈,请告诉我。
关于最小-最大归一化,您需要知道的一切:Python 教程
在这篇文章中,我解释了什么是最小-最大缩放,何时使用它,以及如何使用 scikit-learn 在 Python 中实现它,但也可以从scratch手动实现。

作者用 Python 创建的图。
介绍
这是我关于在机器学习(ML)模型拟合之前经常使用的标准化技术的第二篇文章。在我的第一篇文章中,我使用 scikit-learn 的StandardScaler函数介绍了标准化技术。如果您不熟悉标准化技术,只需点击这里即可在 3 分钟内学会要领。
在现在的帖子中,我将使用 scikit-learn(函数名:[MinMaxScaler](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.MinMaxScaler.html))解释第二个最著名的归一化方法,即 最小-最大缩放 。
方法的核心
另一种标准化输入特征/变量的方法是最小-最大缩放器(除了标准化缩放特征使其具有μ=0和σ=1)。通过这样做,所有特征将被转换到范围****【0,1】中,这意味着特征 / 变量的最小值和最大值将分别为 0 和 1 。
如果你想在交互式路线图和活跃的学习社区的支持下自学数据科学,看看这个资源:【https://aigents.co/learn
为什么要在模型拟合之前进行归一化?
规范化/标准化背后的主要思想总是相同的。在不同的尺度下测量的变量对模型拟合 &模型学习函数的贡献不相等,可能最终产生偏差。因此,为了处理这个潜在的问题,通常在模型拟合之前使用特征标准化,例如最小最大缩放。****
这个可以 非常有用 对于一些 ML 模型像多层感知器(【MLP】),其中可以更甚至 更快**
注 :基于树的模型通常不依赖于缩放,但非树模型模型如 SVM、LDA 等。往往非常依赖它。
数学公式

最小-最大缩放的数学公式。作者创造的形象。这里,x 表示单个特征/变量向量。
Python 工作示例
这里我们将使用通过 scikit-learn 获得的著名的iris数据集。
提醒 : scikit-learn 函数期望输入一个 numpy 数组X,其维数为[samples, features/variables]。
**from sklearn.datasets import load_iris
from sklearn.preprocessing import MinMaxScaler
import numpy as np# use the iris dataset
X, y = load_iris(return_X_y=True)
print(X.shape)
# (150, 4) # 150 samples (rows) with 4 features/variables (columns)# build the scaler model
scaler = MinMaxScaler()# fit using the train set
scaler.fit(X)# transform the test test
X_scaled = scaler.transform(X)# Verify minimum value of all features
X_scaled.min(axis=0)
# array([0., 0., 0., 0.])# Verify maximum value of all features
X_scaled.max(axis=0)
# array([1., 1., 1., 1.])# Manually normalise without using scikit-learn
X_manual_scaled = (X — X.min(axis=0)) / (X.max(axis=0) — X.min(axis=0))# Verify manually VS scikit-learn estimation
print(np.allclose(X_scaled, X_manual_scaled))
#True**
视觉示例中的变换效果
**import matplotlib.pyplot as pltfig, axes = plt.subplots(1,2)axes[0].scatter(X[:,0], X[:,1], c=y)
axes[0].set_title("Original data")axes[1].scatter(X_scaled[:,0], X_scaled[:,1], c=y)
axes[1].set_title("MinMax scaled data")plt.show()**

Iris 数据集前两个特征的最小最大缩放效果。图由作者用 Python 制作。
很明显,在最小-最大缩放(右图)之后,特性值在和范围【0,1】内。****
scikit-learn 网站的另一个可视化示例

最小最大缩放效果。图摘自 scikit-learn 文档:https://scikit-learn . org/stable/auto _ examples/preprocessing/plot _ all _ scaling . html
摘要
- 使用最小最大值缩放时要记住的一件重要事情是,它受到我们数据中最大值和最小值的高度影响,因此如果我们的数据包含异常值,它就会有偏差。
MinMaxScaler重新调整数据集,使所有特征值都在范围[0,1]内。这是以独立的方式按功能完成的。MinMaxScaler缩放可能在一个窄的范围内压缩所有内联者。
如何处理异常值
- 手动方式(不推荐):目视检查数据,并使用异常值剔除统计方法剔除异常值。
- 推荐方法:使用
[RobustScaler](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.RobustScaler.html)来缩放特征,但在这种情况下,使用对异常值稳健的统计。该缩放器根据分位数范围范围(默认为 IQR :四分位间距)移除中值和缩放数据。*IQR 是第一个四分位数(第 25 个四分位数)和第三个四分位数(第 75 个四分位数)之间的范围。*****
今天就到这里吧!希望你喜欢这第一个帖子!下一个故事下周开始。敬请关注&注意安全。
——我的邮件列表只需 5 秒:https://seralouk.medium.com/subscribe
最新帖子
** [## 用新冠肺炎假设的例子解释 ROC 曲线:二分类和多分类…
在这篇文章中,我清楚地解释了什么是 ROC 曲线以及如何阅读它。我用一个新冠肺炎的例子来说明我的观点,我…
towardsdatascience.com](/roc-curve-explained-using-a-covid-19-hypothetical-example-binary-multi-class-classification-bab188ea869c) [## 支持向量机(SVM)解释清楚:分类问题的 python 教程…
在这篇文章中,我解释了支持向量机的核心,为什么以及如何使用它们。此外,我还展示了如何绘制支持…
towardsdatascience.com](/support-vector-machines-svm-clearly-explained-a-python-tutorial-for-classification-problems-29c539f3ad8) [## PCA 清楚地解释了——如何、何时、为什么使用它以及特性的重要性:Python 指南
在这篇文章中,我解释了什么是 PCA,何时以及为什么使用它,以及如何使用 scikit-learn 在 Python 中实现它。还有…
towardsdatascience.com](/pca-clearly-explained-how-when-why-to-use-it-and-feature-importance-a-guide-in-python-7c274582c37e) [## Scikit-Learn 的标准定标器如何工作
在这篇文章中,我将解释为什么以及如何使用 scikit-learn 应用标准化
towardsdatascience.com](/how-and-why-to-standardize-your-data-996926c2c832)
请继续关注并支持我
如果你喜欢这篇文章并且觉得它有用,请关注我和为我的故事鼓掌支持我!
资源
在这里并排查看所有 scikit-learn 规范化方法:https://sci kit-learn . org/stable/auto _ examples/preprocessing/plot _ all _ scaling . html
参考
[1]https://sci kit-learn . org/stable/modules/generated/sk learn . preprocessing . minmax scaler . html
[2]https://sci kit-learn . org/stable/auto _ examples/preprocessing/plot _ all _ scaling . html
[3]https://sci kit-learn . org/stable/modules/generated/sk learn . preprocessing . robust scaler . html
和我联系
- 领英:https://www.linkedin.com/in/serafeim-loukas/
- 研究之门:https://www.researchgate.net/profile/Serafeim_Loukas
- EPFL简介:https://people.epfl.ch/serafeim.loukas
- 堆栈溢出:https://stackoverflow.com/users/5025009/seralouk**
关于 MVC 架构你需要知道的一切
MVC 如何工作的一般解释。
MVC 被认为是一种架构模式,它包含三个部分模型、视图和控制器,或者更准确地说,它将应用程序分成三个逻辑部分:模型部分、视图和控制器。它曾用于桌面图形用户界面,但现在用于设计移动应用和网络应用。
历史
Trygve Reenskaug 发明了 MVC。关于 MVC 的第一份报告是他在 1978/79 年拜访施乐帕洛阿尔托研究实验室(PARC)的一位科学家时写的。起初,MVC 被称为“事物模型视图编辑器”,但很快就变成了“模型视图控制器”。
Tygrve 的目标是解决用户控制大型复杂数据集的问题。多年来,MVC 的实践已经发生了变化。由于 MVC 模式是在 web 浏览器之前发明的,最初被用作图形用户界面(GUI)的架构模式。

最初的 MVC
目前,MVC 被用于设计 web 应用程序。一些使用 MVC 概念的 web 框架:Ruby on Rails、Laravel、Zend framework、CherryPy、Symphony 等
MVC 架构
MVC 是一种架构模式,这意味着它控制着应用程序的整个架构。即使它通常被称为设计模式,但如果我们只将其称为设计模式,我们可能是错误的,因为设计模式用于解决特定的技术问题,而架构模式用于解决架构问题,所以它影响我们应用程序的整个架构。
它有三个主要组件:
-模型
-视图
-控制器
,每个组件都有特定的职责

MVC 架构
使用 MVC 的主要原因是:首先,它不允许我们重复自己,其次,它有助于创建我们的 web 应用程序的坚实结构。
模型
它被称为最低级别,这意味着它负责维护数据。逻辑地处理数据,所以它基本上是处理数据。模型实际上是与数据库相连的,所以你对数据做的任何事情。添加或检索数据是在模型组件中完成的。它响应控制器的请求,因为控制器从不自己与数据库对话。该模型与数据库来回对话,然后将所需的数据提供给控制器。注意:模型从不与视图直接交流。
视角
数据表示由视图组件完成。它实际上为用户生成 UI 或用户界面。因此,在 web 应用程序中,当您想到视图组件时,只需想到 Html/CSS 部分。视图是由模型组件收集的数据创建的,但这些数据不是直接获取的,而是通过控制器获取的,因此视图只与控制器对话。
控制器
它被称为主要人员,因为控制器是实现视图和模型之间的互连的组件,所以它充当中介。控制器不必担心处理数据逻辑,它只是告诉模型做什么。从模型接收数据后,它对数据进行处理,然后将所有信息发送给视图,并向用户解释如何表示。注意:视图和模型不能直接对话。
MVC 的优势
- MVC 架构将用户界面从业务逻辑和业务逻辑中分离出来
-组件是可重用的。
-易于维护。
-MVC 中应用程序的不同组件可以独立部署和维护。
-这种架构有助于独立测试组件。
MVC 的缺点
——复杂度高。
-不适合小型应用。
-针对数据访问的低效率。
结论
所以 MVC 不是那么容易理解,实际上它真的很难,但不是不可能学会,每个开发人员在开发应用程序时都需要记住它。请记住,MVC 是一种将你的软件分成更小的组件的架构。模型处理数据和系统的逻辑。视图只显示数据,控制器维护模型和视图之间的连接。这种“划分”使可读性和模块化,以及它更容易测试部分。
只要记住这些要点:
-MVC 是一种架构模式,由三部分组成:模型、视图、控制器。模型:处理数据逻辑。
视图:向用户显示来自模型的信息。
控制器:控制数据流向模型对象,并在数据变化时更新视图。
——是 Trygve Reenskau 发明的。
-尽管它非常受欢迎,也确实有一些缺点,但主要的缺点是复杂。
关于时间序列你需要知道的一切
你能找到的最完整的时间序列分析介绍

很明显,我们拥有的最宝贵的资源是时间。—史蒂夫·乔布斯
介绍
收集的大多数数据都有时间结构。有时,这种结构是隐藏的,或者我们可以忽略它,但是,有一些方法可以使用这种时间结构从可用数据中提取相关信息。
知道如何对时间序列建模是数据科学中的一项基本技能,因为这种类型的数据有特定的结构,可以在所有情况下进行探索。
我放在本指南中的所有内容都可以在任何时间尺度上使用。请记住:每当我说天、周、小时或任何时间单位,你都可以理解为“周期”。那么,我们开始吧。
时间序列的结构
你如何知道你正在处理一个时间序列?一个时间序列是一系列按时间顺序索引的数据点。最简单的时间序列是这样的:

简单时间序列
其中的元素是:
- 时间戳:事件被注册时的时间标记。其准确性将取决于测量的事件。
- 价值:这种现象在那一刻的价值是什么?
可以只是一个或多个值。当每个时间戳有多个值时,我们有一个多变量时间序列。
时间序列的类型
此外,知道时间序列有两种类型也很重要:
- 有规律的时间序列:在每个统一的时间段内都有记录的时间序列。一个每日的温度序列可以被认为是一个常规序列,因为我们期望每天一个记录,每单位时间一个记录。
- 不规则时间序列:没有规定频率的时间序列。一个例子是网站的访问日志。人们不是每隔 N 分钟就统一访问一次。在这种情况下,我们将拥有不同时间间隔的记录。
时间序列数据准备
特征工程
为了创建机器学习模型,我们需要输入变量(特征— X)和一个或多个输出变量(目标— y)。有四个基本特征,应该在任何时间序列问题上进行测试:
- 滞后:滞后特性就是简单地使用以前的目标值作为预测当前目标值的特性。例如,如果你想预测明天苹果股票的价格,今天的价格是一个非常强大的功能,这个案例是一个 lag 1 功能。或者,如果您的问题具有每周季节性,滞后七功能可能会非常有用。
- 差异:这个特性和 Lag 很相似。只是这里不用具体的数值,而是用上一期和上一期的差。例如,计算昨天售出的商品数量和上周同一天售出的商品数量之间的差异。最常见的运算是差(减),但我们也可以使用和、比和乘法。
- 统计特性:除了对特定的值和算术运算,我们还可以计算平均值、标准差、最大值、最小值、分位数等统计量。在我们的销售示例中,我们可以计算在过去的七天中,该产品在一天中的最大销售量。这个想法很简单,取一个时间段的窗口,对各自的值应用一个函数。通常,这个函数应该为每个时间戳只返回一个数字。
- 时间戳分解:我们也可以提取时间戳的相关部分,通常是与它的季节性相关的东西。一些时期有特定于那个时刻的不同模式。一些经典的例子是圣诞节,黑色星期五,母亲节,父母,情人节。在这些日期之前的日子里,贸易中的销售有显著的增加。换句话说,在一年中的这个时候,总会有销售增长,模型需要知道这一点。我们可以创建诸如星期几、一个月中的某一天、一年中的某个月、一天中的某个时间等特征。
系统模型化
传统上,统计时间序列模型一次应用于一个序列。也就是说,您只有一系列的值,并应用期望的方法来建模生成它的过程。在 Data Science,我们也可以一次对一个序列建模,只需创建仅依赖于我们试图预测的序列值的特征。但是,我们也可以将时间序列堆叠起来,制作一个堆叠模型。这样,我们可以有单独的模型和堆叠的模型,因为单独的模型是传统的方法,我将详细解释堆叠方法。
堆叠建模
在这种情况下,我们不是为每个系列创建一个模型,而是将它们“堆叠”在一起,创建一个全局模型。我说的堆叠是什么意思?
假设我们有一系列 10 家公司一年的股票价格,每天一个记录。让我们把所有这些系列连接成一个。那么我们将有 10 家公司 x 365 天= 3650 行。“新系列”的每一行都有时间戳、公司标识和当时的销售额。
我们为什么要这样做?
- 更多数据:机器学习模型往往在数据量较大的情况下工作得更好。我们不是基于一些记录(在我们的例子中是 365 行)来建立模型,而是建立更多的行,让模型更健壮地捕捉模式。
- 复杂性:对于生产、监控模型、保持模型运行来说,维护一个模型比维护 10 个模型要简单得多。这降低了我们解决方案的复杂性,并避免了实现错误。
- 全球效应:同时使用几个系列,模型有机会捕捉它们之间的共同事件。全球效应,发生在几个系列,将更清楚,更容易捕捉。
确认
当我们处理时间序列模型时,我们不能进行错误的验证,而严重错误的验证是很常见的。如果你只是简单地随机划分你的数据,就像我们在很多课程中学到的那样,你会得到一个看起来非常好的结果,但它实际上不会在生产中重现。这是因为你将混合过去和未来的线,让你的模型知道未来的信息来预测过去!这样,在生产中,就没有办法得到时间机器,得到这些信息。
另外,整个过程受时间影响。有些更快,有些更慢,因此我们需要了解我们的模型将如何应对将要发生的变化。
你可能想知道:整个过程真的会随着时间而改变吗?
即使是图像分类器也会受到影响,因为用于拍照的设备总是在变化。
通常,与人类行为直接或间接相关的模型往往变化更快,需要以一定的频率更新(重新训练)。正确的频率取决于具体情况。一般来说,时间序列打破了线独立性的假设。也就是说,来自邻近线的信息倾向于给出关于我们选择的线的目标的提示。
因此,在训练和测试之间划分时间数据的最简单但已经相当健壮的方法是按日期划分。你可以选择一个特定的日期或一部分数据,通常前 70%用于训练,30%用于验证。甚至,我们可以做一个时间序列交叉验证吗?
时间序列交叉验证
不要只使用一个分割来验证我们的模型,最好使用至少三个交叉验证折叠来这样做,总是按照时间戳来分割数据。
通常,越新的数据对模型越重要。我们可以使用两种类型的“窗口”来验证我们的模型:
- 可扩展窗口:这意味着久而久之,我们的训练数据将会增加。下图可以很好的说明这个过程。

- 滑动窗口:在这个格式中,以及在特征的计算中,我们将滑动一个固定的窗口,由数据预先定义。滑动窗口让您对将要使用的数据有更多的控制,使您的管道在重新训练时更加健壮。即使你有很多年的数据,也不代表你需要用所有的东西来训练模型。
简单交叉验证的一个缺点是,我们正在验证未来的“某个版本”,那些真正发生过的版本,在一个小时间的变化后迭代每个版本。但在某些情况下,未来可能会有所不同。
在金融市场建模的案例中,这种情况经常发生。总的来说,你需要寻找不同金融体系(高、低和停滞)的时间段来验证你的模型。
越来越受欢迎的一种方法是跨块验证。一般而言,在验证中重复使用数据样本的重采样方法往往更加稳健。
在时间序列的情况下,由于我们希望保留结构,但模拟不同的场景,我们需要在不进行随机混合的情况下获取数据块,并且这些数据块在交叉验证折叠之间不能有交集。最重要的是,随着时间的推移,一起生成的线保持在一起。这些可以在下图中看到:

模型
一些机器学习模型似乎更适合时间序列数据。
树形系综
这里我们讨论的是任何结合几个决策树进行预测的模型。最流行的是随机森林和梯度提升决策树。
在竞赛和行业项目中,我们看到这些模型很容易发现时间序列中的模式,对噪声具有鲁棒性,并且由于其捕捉非线性模式的高能力,能够提取与目标几乎不相关的特征值。
神经网络
多层感知器(MLP)神经网络是最传统的,可以用来创建基本上任何性质的模型。但是有一些类型可以直接处理字符串。
卷积神经网络
最初是为了处理图像而创建的,但是它们在时间序列案例中的使用越来越普遍。基本上,他们最终会学习在卷积窗口内乘以原始特征的滤波器。这意味着我们可以使用学习表示的能力来建模时间序列。
与递归网络相比,它们训练速度更快,需要调整的参数(权重)更少。尽管如此,在大多数神经网络的情况下,随着数据量的增长,它们往往会工作得更好。小样本值得一试,但不要指望它能创造奇迹。
递归神经网络(RNN)
今天最流行的是长-短时记忆(LSTM ),是专门针对顺序数据的,时间序列也是如此。这个想法是,不仅当前的例子可以影响结果,过去例子的“记忆”也可以帮助预测。
这些网络往往相当复杂,有大量的参数需要调整,这使得它们需要大量的样本才能达到良好的效果。同时,它们非常灵活,允许在进入和退出期间的数量之间有多种架构组合。
衰减时间
每个时间序列预测都试图理解人类的相互作用。如果建模的系统改变了任何逻辑,则训练的模型将随着时间的推移而出现性能衰减。有些模型会衰减很快,有些则很慢。
要测量您的模型随着时间的推移表现如何,请尝试监控其性能,并在性能下降到阈值以下时重新训练它。
衰减的速度会因您处理的问题类型而异,例如,金融模型可能需要在短时间内重新训练,而预测天气的模型可以在较长时间后重新训练。
有一些更可靠的方法来判断何时重新训练时间序列模型,然而,这篇文章已经足够长了。总有一天我会在这里写一篇关于它的文章。
结论
最常见的数据之一与时间有关。对于数据科学家来说,它们是理解如何正确探索、准备、提取好的特征、验证和建模这类数据的基础。
有了这里提出的想法,你一定能够使用时间序列的机器学习来创建高性能和稳健的模型。
我希望这个概述可以帮助一些人,因为现在我只会留下一本书的推荐和一个好的报价。
读时间系列的书很好:
时间序列预测(Francesca Lazzeri):【https://amzn.to/2R7qGko T2
Python 速成班(Eric Matthes):【https://amzn.to/38gJtPI
用于数据分析的 Python(韦斯·麦金尼):https://amzn.to/2tpgevz
很明显,我们拥有的最宝贵的资源是时间。—史蒂夫·乔布斯
参考资料:
时间序列 CV 数字来自:https://hub . packtpub . com/cross-validation-strategies-for-time-Series-forecasting-tutorial/
关于网络抓取,你需要知道的一切

如今,无论你走到哪里,都有机器在为人类做事。随着技术和生产的发展,许多事情很容易实现自动化。我们现在正需要这些,为什么你不能让自己也轻松一点呢?
这正是网页抓取的目的。这是一个用来从网上网页获取数据的术语。
一旦你得到了你想要的数据,你可以用它做很多事情,这取决于你,但在这篇文章中,我想回顾一下网络抓取的一些最佳用法,并回答一些关于这个话题的一般性问题。
什么是网页抓取?
Web 抓取是一种从网站上获取大量数据的方法,这些数据可以用于任何类型的数据处理和操作。
对于这项技术,我们使用 web 浏览器。您通常没有获得所需数据的内置选项。这就是为什么我们使用 Web 抓取来自动获取数据,而不必手动操作。网络抓取是一种自动化这一过程的技术,这样就不用手动从网站上复制数据。

网络搜集的好处和用途
如前所述,用这种方法你可以一次获得大量数据,但这不是它的唯一用途。
如果你能从网站上获得数据,想象一下你能做什么。数据操作是这里的关键。
以下是一些例子:
分析:收集数据,做一个分析工具,跟踪你的数据。你可以用这个方法进行研究。甚至可能用机器学习或更复杂的想法来预测行为(如何用 Python 制作分析工具 ) 价格比较:从不同的网站获取价格并进行比较,以了解市场概况,这样您就可以省钱!(如何用 Python 省钱 )
邮件列表:收集邮件地址,用于营销和促销目的。你每天都会收到很多来自你从未听说过的公司的电子邮件,这就是原因。
工作:找工作真的很难,因为招聘信息分散在不同的网站上,令人困惑
社交媒体:从脸书、Instagram 或 Twitter 等网站搜集数据。为了获得关注者/不关注者的数量或当时的趋势。
这些是网络抓取的一些最常见的用法,这些是我的想法,但是根据你的工作和网站的使用情况,你可能会有一些关于如何实现它的其他想法!关键是你的工作流程中自动化程度越多(T2),对你就越好。

网页抓取的最佳编程语言
显然巨蟒。你可以使用很多不同的库来抓取网页。其中一些是:
Selenium :这个库使用 Web Driver for Chrome 来测试命令和处理网页以获得你需要的数据。(使用示例:如何使用 Python 制作分析工具如果您想了解更多信息25 个 Selenium 函数,让您成为 Web 抓取专家)
beautiful soup:用于从 HTML 和 XML 文件中提取数据的 Python 库。它创建了数据解析树以便于获取数据。(用法举例:如何用 Python 省钱 )
熊猫:用于数据提取和操纵。通常,对于数据库,它将数据保存为某种格式。
这不仅仅是因为 Python 有库,而且 Python 是最容易使用的语言之一,也是最强大的语言之一。

法律问题
有些网站允许刮痧,有些不允许。
为了检查网站是否支持网页抓取,您应该在目标网站的 URL 末尾添加“/robots.txt”。
它会告诉你关于网站的所有细节,包括关于刮擦的信息,这里有一个例子:

在这种情况下,你必须查看专门的网页抓取网站。
始终注意版权并仔细阅读 合理使用 。

简单的例子
现在我们已经基本上涵盖了网络抓取的所有要点,让我们创建一个简单的网络抓取使用示例。
如果你想要一些具体的东西,可以看看这方面的高级例子:如何用 Python 制作分析工具和如何用 Python 省钱。
相反,我们将制作一个简单的脚本来从一个网站获取一些数据!类似于这篇文章,我们会从网站上得到价格和标题。
让我们直接开始吧!
编码
规划流程
首先,我们必须找到我们想要跟踪的项目。我发现这台笔记本电脑很贵。
我的代销商产品链接
为此,我们需要几个库,所以让我们来设置环境。
设置环境
一旦我们完成了一个项目搜索,我们打开编辑器。我个人选择的是 Visual Studio 代码。它简单易用,可定制,并且对你的计算机来说很轻。
打开一个新的项目,创建一个新文件。这是一个我的看起来能帮助你的例子:

在 VS 代码中,有一个“Terminal”选项卡,您可以使用它打开 VS 代码中的内部终端,这对于将所有内容放在一个地方非常有用。
在终端中,您应该安装库:
*pip3 install requests*
可以使用请求,这样您就可以通过简单的 Python 库添加内容,如标题、表单数据、多部分文件和参数。它还允许您以同样的方式访问 Python 的响应数据。
sudo pip3 install beautifulsoup4
Beautiful Soup 是一个 Python 库,用于从 HTML、XML 和其他标记语言中获取数据。
pip3 install smtplib
smtplib 模块定义了一个 SMTP 客户端会话对象,该对象可用于向任何带有 SMTP 或 ESMTP 监听器守护进程的互联网机器发送邮件。
创建工具
我们已经设置好了一切,现在我们要编码了!
首先,如前所述,我们必须导入已安装的库。
*import* requests*from* bs4 *import* BeautifulSoup*import* smtplib
在这种情况下,我们需要使用两个变量,即 URL 和标题。
URL 将是我们产品的链接,标题将是用户代理,我们将使用它来访问正确版本的浏览器和机器。要找出你的浏览器用户代理,你可以在这里做。只需替换“用户代理”部分之后的链接,并像我一样用单引号括起来。
URL = '[https://www.amazon.de/dp/B07XVWXW1Q/ref=sr_1_10?keywords=laptop&qid=1581888312&sr=8-10](https://www.amazon.de/dp/B07XVWXW1Q/ref=sr_1_10?keywords=laptop&qid=1581888312&sr=8-10)'In order to fix that we are going to do some text permutations or parsing.For title we are going to use .split() function:print(title.strip())
And for our price:sep = ','
con_price = price.split(sep, 1)[0]
converted_price = int(con_price.replace('.', ''))
We use sep as the separator in our string for price and convert it to integer (whole number).headers = {"User-agent": 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36'}
接下来,我们将使用 URL 和请求库的标题来定义页面。
page = requests.get(URL, headers=headers)soup = BeautifulSoup(page.content, 'html.parser')
这将得到我们想要的链接,现在我们只需找到页面上的元素,以便将它们与希望的价格进行比较。
title = soup.find(id="productTitle").get_text()price = soup.find(id="priceblock_ourprice").get_text()
为了找到页面上的元素,我们使用 soup。找到()函数,用。get_text()。
标题和价格我们要为程序的输出进行节省,让它看起来很好看。
现在,元素看起来很奇怪,因为在我们需要的文本前后有太多的空格。
为了解决这个问题,我们将进行一些文本置换或解析。
对于标题我们将使用。拆分()功能:
print(title.strip())
而对于我们的价格:
sep = ','con_price = price.split(sep, 1)[0]converted_price = int(con_price.replace('.', ''))
我们使用 sep 作为价格字符串中的分隔符,并将其转换为整数。

下面是完整的代码:
我们完了!

如果你想了解更多关于硒功能的知识,试试这里的!
我希望你喜欢这个小教程,并关注我更多!
感谢阅读!
跟着我上媒
在推特上关注我
在 20 分钟内成为一名数据科学家需要了解的基础知识
关于成为数据科学家所需了解的广泛速成课程

图片由皮克斯拜的 Gerd Altmann 提供
这篇文章是一个广泛的速成班,我认为这是成为一名数据科学家需要知道的一些最基本和最有用的概念。我已经把它分成了不同的部分,这样你就可以一点一点地看了。
好吧,这并没有涵盖与数据科学相关的一切(那是不可能的),不,这应该是而不是你用来发展知识和技能的唯一资源…
然而,如果你一无所知,那么这将有助于你很好地理解数据科学的基础知识。如果您对数据科学有所了解,这可以作为一门紧凑的速成课程,用于复习、磨练您的知识和/或找出您知识中的差距。
一如既往,我希望这能对您有所帮助,并祝您在数据科学事业中好运!
目录
1.机器学习模型

机器学习模型的基本分段
所有的机器学习模型被分类为监督的或非监督的。如果模型是监督模型,那么它被细分为回归或分类模型。我们将讨论这些术语的含义以及下面每个类别中对应的模型。
监督学习
监督学习涉及学习基于示例输入-输出对将输入映射到输出的函数。
例如,如果我有一个包含两个变量的数据集,年龄(输入)和身高(输出),我可以实现一个监督学习模型,根据年龄预测一个人的身高。

监督学习的例子
重复一下,在监督学习中,有两个子类别:回归和分类。
回归
在回归模型中,输出是连续的。下面是一些最常见的回归模型。
线性回归

线性回归的例子
线性回归的概念就是找到一条最符合数据的直线。线性回归的扩展包括多元线性回归(例如,找到最佳拟合的平面)和多项式回归(例如,找到最佳拟合的曲线)。你可以在我的上一篇文章中了解更多关于线性回归的知识。
决策图表

图片来自 Kaggle
决策树是一种流行的模型,用于运筹学、战略规划和机器学习。上面的每个方块被称为一个节点,节点越多,你的决策树就越精确(一般来说)。决策树中做出决策的最后节点称为树的叶。决策树直观且易于构建,但在准确性方面有所欠缺。
随机森林
随机森林是一种基于决策树的集成学习技术。随机森林包括使用原始数据的自举数据集创建多个决策树,并在决策树的每一步随机选择一个变量子集。然后,该模型选择每个决策树的所有预测的模式。这有什么意义?依靠“多数获胜”模型,它降低了单个树出错的风险。

例如,如果我们创建一个决策树,第三个,它会预测 0。但是如果我们依赖所有 4 个决策树的模式,预测值将是 1。这就是随机森林的力量。
StatQuest 做了一项了不起的工作,更详细地说明了这一点。见此处。
神经网络

神经网络的可视化表示
一个神经网络是一个受人脑启发的多层模型。就像我们大脑中的神经元一样,上面的圆圈代表一个节点。蓝色圆圈代表输入层,黑色圆圈代表隐藏层,绿色圆圈代表输出层。隐藏层中的每个节点代表一个输入经过的函数,最终导致绿色圆圈中的输出。
神经网络实际上是非常复杂和非常数学化的,所以我不会进入它的细节,但…
饶彤彤的文章对神经网络背后的过程给出了直观的解释(见此处)。
如果你想更进一步,理解神经网络背后的数学,请点击这里查看这本免费的在线书籍。
如果你是一名视觉/音频学习者,3Blue1Brown 在 YouTube 上有一个关于神经网络和深度学习的惊人系列这里。
分类
在分类模型中,输出是离散的。下面是一些最常见的分类模型。
逻辑回归
逻辑回归类似于线性回归,但用于模拟有限数量结果的概率,通常为两个。在对结果的概率建模时,逻辑回归比线性回归更常用,原因有很多(见此处)。实质上,逻辑方程是以这样一种方式创建的,即输出值只能在 0 和 1 之间(见下文)。

支持向量机
一个支持向量机是一种监督分类技术,它实际上可以变得非常复杂,但在最基本的层面上是非常直观的。
让我们假设有两类数据。支持向量机将找到一个超平面或两类数据之间的边界,该边界使两类数据之间的间隔最大化(见下文)。有许多平面可以分隔这两个类别,但只有一个平面可以最大化类别之间的边距或距离。

如果你想了解更多细节,Savan 在这里写了一篇关于支持向量机的文章。
朴素贝叶斯
朴素贝叶斯是数据科学中使用的另一种流行的分类器。背后的想法是由贝叶斯定理驱动的:

虽然有许多关于朴素贝叶斯的不切实际的假设(这就是为什么它被称为‘朴素’),但它已经被证明在大多数情况下都是有效的,而且构建起来也相对较快。
如果你想了解更多,请点击这里。
决策树,随机森林,神经网络
这些模型遵循与前面解释的相同的逻辑。唯一区别是输出是离散的而不是连续的。
无监督学习

与监督学习不同,非监督学习用于从输入数据中进行推断和发现模式,而不参考标记的结果。无监督学习中使用的两种主要方法包括聚类和降维。
使聚集

摘自 GeeksforGeeks
聚类是一种无监督的技术,涉及数据点的分组,或聚类。它经常用于客户细分、欺诈检测和文档分类。
常见的聚类技术有 k-means 聚类、分层聚类、均值漂移聚类、基于密度的聚类。虽然每种技术在寻找聚类时有不同的方法,但它们的目标都是一样的。
降维
降维是通过获得一组主变量来减少所考虑的随机变量的数量的过程。简单来说,就是减少特性集的维数的过程(更简单来说,就是减少特性的数量)。大多数降维技术可以分为特征消除或特征提取。
一种流行的降维方法叫做主成分分析。
主成分分析
从最简单的意义上来说, PCA 涉及到将高维数据(如 3 维)投影到更小的空间(如 2 维)。这导致数据的维度降低(2 维而不是 3 维),同时保持模型中的所有原始变量。
这涉及到相当多的数学问题。如果你想了解更多…
点击查看这篇关于 PCA 的精彩文章。
如果你宁愿看视频,StatQuest 在 5 分钟内解释 PCA这里。
2.统计数字
数据类型
数值:用数字表示的数据;是可以衡量的。既可以是离散也可以是连续。
分类:定性数据分类成类别。可以是名义(未排序)或序数(排序数据)。
集中趋势测量
均值:一个数据集的平均值。
中位数:有序数据集的中间;不易受离群值的影响。
模式:一个数据集中最常见的值;仅与离散数据相关。

差异量数
范围:数据集中最高值和最低值之差。
方差(σ2): 测量一组数据相对于平均值的分布程度。

标准差(σ): 数据集中数字分布的另一种度量;它是方差的平方根。
Z 值:确定数据点偏离平均值的标准偏差数。

R 平方:拟合的统计度量,表明自变量解释了因变量的多少变化;仅对简单线性回归有用。

调整后的 R 平方:已针对模型中预测器的数量进行调整的 R 平方的修改版本;如果新项对模型的改进超过偶然的预期,那么它就会增加,反之亦然。
变量之间关系的度量
协方差:测量两个(或更多)变量之间的方差。如果是正的,那么它们倾向于向同一个方向移动,如果是负的,那么它们倾向于向相反的方向移动,如果它们是零,那么它们彼此没有关系。

样本的分母变为(n-1)
相关性:衡量两个变量之间的关系强度,范围从-1 到 1;协方差的标准化版本。一般来说,+/- 0.7 的相关性代表两个变量之间的密切关系。另一方面,介于-0.3 和 0.3 之间的相关性表明变量之间几乎没有关系。

概率分布函数
概率密度函数(PDF): 连续数据的函数,其中任意点的值可以被解释为提供随机变量的值等于该样本的相对可能性。(维基)
概率质量函数(PMF): 离散数据的函数,给出给定值出现的概率。
累积密度函数(CDF): 告诉我们一个随机变量小于某个值的概率的函数;PDF 的积分。
连续数据分布
均匀分布:所有结果可能性相等的概率分布。
正态/高斯分布:通常称为钟形曲线,与 中心极限定理 有关;平均值为 0,标准偏差为 1。

T-分布:在样本量较小和/或总体方差未知时用于估计总体参数的概率分布(参见更多 此处 )。
卡方分布:卡方分布统计量(见 此处 )。
离散数据分布
泊松分布:概率分布,表示给定数量的事件在固定时间段内发生的概率。
二项式分布:一系列 n 次独立经历中成功次数的概率分布,每次经历都有自己的布尔值结果(p,1-p)。
朋友圈
矩描述了分布的性质和形状的不同方面。一阶矩是均值,二阶矩是方差,三阶矩是偏度,四阶矩是峰度。********
准确(性)
真阳性:检测条件出现时的条件。
真否定:不检测条件不存在时的条件。
假阳性:检测条件不存在时的条件。
假阴性:在条件存在时不检测条件。
灵敏度:又称召回;当条件存在时,测量测试检测条件的能力;灵敏度= TP/(TP+FN)
特异性:测量当条件不存在时,测试正确排除条件的能力;特异性= TN/(TN+FP)

预测值正:又称精度;对应于条件存在的阳性比例;PVP = TP/(TP+FP)
预测值阴性:对应于条件不存在的阴性比例;PVN = TN/(TN+FN)

假设检验和统计显著性
查看我的文章《尽可能简单地解释假设检验》获得更深入的解释 这里 。
零假设:样本观察值纯属偶然的假设。
备选假设:样本观测值受某种非随机原因影响的假设。
P 值:假设零假设正确,获得某个检验的观测结果的概率;较小的 p 值意味着有更强的证据支持替代假设。
α:显著性水平;当零假设为真时拒绝零假设的概率—也称为1 型错误。
贝塔:2 型错误;未能拒绝虚假的零假设。
假设检验的步骤:
1。陈述无效假设和替代假设。确定测试规模;是单尾还是双尾检验?
3。计算测试统计和概率值
4。分析结果,拒绝或不拒绝零假设(如果 p 值大于α,不拒绝零假设!)
3.可能性
概率是事件发生的可能性。
条件概率【P(A | B)】是一个事件发生的可能性,基于前一个事件的发生。
独立事件是其结果不影响另一事件结果概率的事件;P(A|B) = P(A)。
互斥事件是不能同时发生的事件;P(A|B) = 0。
贝叶斯定理:确定条件概率的数学公式。“给定 B 的概率等于给定 A 的 B 的概率乘以 A 的概率超过 B 的概率”。

概率的八大法则
- 规则#1:对于任何事件 A,0≤P(A)≤1;换句话说,一个事件发生的概率范围可以从 0 到 1。
- 规则 2:所有可能结果的概率总和总是等于 1。
- 规则#3: P(非 A)= 1—P(A);这个规则解释了一个事件的概率和它的补事件之间的关系。补充事件是指包含 a 中没有的所有可能结果的事件。
- 规则#4:如果 A 和 B 是不相交事件(互斥),那么 P(A 或 B)= P(A)+P(B);这被称为不相交事件的加法规则
- 规则#5: P(A 或 B) = P(A) + P(B) — P(A 和 B);这就是所谓的一般加法法则。
- 规则#6:如果 A 和 B 是两个独立事件,那么 P(A 和 B)= P(A) P(B)*;这叫做独立事件的乘法法则。
- 规则#7:给定事件 A,事件 B 的条件概率为 P(B|A) = P(A 和 B) / P(A)
- 规则#8:对于任意两个事件 A 和 B, P(A 和 B)= P(A) P(B | A)*;这被称为通用乘法法则
计数方法

阶乘公式:n!= n x(n-1)x(n-2)x…x 2 x 1 当项目数等于可用的位置数时使用。找出 5 个人可以坐在 5 个空座位上的总数。
= 5×4×3×2×1 = 120
基本计数原理(乘法) 当允许重复且填充空位的方式数不受之前填充的影响时,应使用此方法。早餐有 3 种,午餐有 4 种,甜点有 5 种。组合总数= 5 x 4 x 3 = 60
排列:P(n,r)= n!/(n r)! 此方法用于不允许替换且项目排序重要的情况。 例如,一个代码有 4 个数字,按特定顺序排列,数字范围从 0 到 9。如果一个数字只能用一次,有多少种排列?
P(n,r) = 10!/(10–4)!=(10 x 9 x 8 x 7 x 6 x 5 x 4 x 3 x2 x 1)/(6x 5 x 4 x 3 x2 x 1)= 5040
组合公式:C(n,r)=(n!)/[(n r)!r!] 当不允许替换并且项目的排列顺序不重要时使用。要赢得彩票,你必须以从 1 到 52 的任何顺序选择 5 个正确的数字。有多少种可能的组合?
C(n,r) = 52!/ (52–5)!5!= 2598960
4.熊猫
Pandas 是 Python 中的一个软件库,用于数据操作和分析。这在数据科学领域是普遍现象,必须了解!下面是学习熊猫基本功能的指南。
设置
导入熊猫库
import pandas as pd
创建和读取数据
创建数据框架
数据帧只是一个由多个数组组成的表。在下面的示例中,代码将创建一个包含 ABC 和 DEF 两列的表。
pd**.DataFrame**({'ABC':[1,2,3],'DEF':[4,5,6]},index=[1,2,3])
创建一个系列
系列是一系列值,也称为列表。从视觉角度来看,想象它是表格中的一列。
pd**.Series**([1,2,3],index=[], name ='ABC')
将 CSV 文件读入数据帧
获取数据的最常见方式。这将 CSV 文件转换为数据帧。
# example
df = pd**.read_csv**("filename.csv", index_col=0)
将数据帧转换为 CSV 文件
反之亦然,如果您想将 DataFrame 转换成 CSV,可以使用下面的代码:
# example
df**.to_csv**("filename.csv", index_col=0)
确定数据帧的形状
这将告诉您数据帧有多大,格式是什么(行,列)。
df**.shape()**
查看数据帧的前 5 行
如果你想直观地了解数据帧的样子。head() 返回给定数据帧的前 5 行。
df**.head()**
查看一列或多列的数据类型
# For one column
df.variable**.dtype**# For all columns
df**.dtypes**
将列转换为另一种数据类型
如果您想将整数转换成浮点数(反之亦然),这是很有用的。
df.variable**.astype()**
操作数据帧
从数据帧中选择系列
# a) Method 1
df.property_name# b) Method 2
df['property_name']
索引系列
# if you want to get the first value in a series
df['property_name'][0]
基于索引的选择
基于索引的选择根据数据在数据帧中的数字位置检索数据。它遵循行优先,列第二的格式。Iloc 的索引方案是这样的:的第一个数字是包含性的,而的最后一个数字是排他性的。
df**.iloc[]**
基于标签的选择
基于标签的选择是索引数据帧的另一种方式,但它基于实际数据值而不是数字位置来检索数据。Loc 的索引方案使得的第一个和最后一个值都包含在内。
df**.loc[]**
使用现有列设置索引
因为基于标签的选择依赖于数据帧的索引,所以可以使用。set_index() 将一列分配给索引。
df.**set_index**("variable")
基于条件标签的选择
我们也可以使用基于标签的选择来过滤出数据帧。
# a) Single Condition
df.loc[df.property_name == 'ABC']# b) Multiple conditions using AND
df.loc[df.property_name == 'ABC' & df.property_name == 'DEF']# c) Multiple conditions using OR
df.loc[df.property_name == 'ABC' | df.property_name == 'DEF']
选择值在值列表中的位置
我们也可以使用 isin() 来过滤数据帧。如果你懂 SQL,它类似于 WHERE ___ IN()语句。
df.loc[df.property_name **isin**(['ABC','DEF'])
选择值为空/不为空的位置
第一行代码将过滤 DataFrame,只显示属性名为 null 的行。
反之亦然,第二行代码用 filter it 使属性名不为空。
df.loc[df.property_name**.isnull**()]df.loc[df.property_name**.notnull()**]
添加新列
df['new_column'] = 'ABC'
重命名列
您通常会希望将列重命名为更容易引用的名称。使用下面的代码,列 ABC 将被重命名为 DEF。
df.**rename**(columns={'ABC': 'DEF'})
汇总函数
。描述()
这给出了数据帧或变量的高级摘要。它是类型敏感的,这意味着与字符串变量相比,数字变量的输出是不同的。
df**.describe()**
df.variable**.describe()**
。平均值()
这将返回变量的平均值。
df.variable**.mean()**
。唯一()
这将返回变量的所有唯一值。
df.variable**.unique()**
。值计数()
这显示了唯一值的列表以及数据帧中出现的频率。
df.variable.**value_counts()**
映射函数
。地图()
映射用于通过函数将一组初始值转换为另一组值。例如,我们可以使用映射将列的值从米转换为厘米,或者我们可以将这些值标准化。
。map()用于转换一个序列。
df.numerical_variable**.map()**
。应用()
。apply()类似于。map(),只是它转换整个数据帧。
df.numerical_variable**.apply()**
分组和排序
。groupby()
获取变量的每个值的计数(与 value_counts 相同)
df**.groupby**('variable').variable**.count()**
获取变量的每个值的最小值
df**.groupby**('variable').variable**.min()**
获取变量的每个值的汇总(长度、最小值、最大值)
df**.groupby**(['variable']).variable.**agg([len, min, max])**
多重索引
df.groupby(['variable_one', 'variable_two'])
对数据帧排序
按一个变量排序
df.**sort_values**(by='variable', ascending=False)
多变量排序
df.sort_values(by=['variable_one', 'variable_two'])
按索引排序
df**.sort_index()**
处理缺失数据
处理缺失数据是 EDA 中最重要的步骤之一。下面是一些处理缺失数据的方法。
删除包含空值的行
如果您有一个包含大量行的数据帧,并且您能够完全删除包含空值的行,那么。dropna()是一个有用的工具。
df.**dropna()**
删除包含空值的列
这与上面类似,除了它删除任何具有空值的列而不是行。
df.**dropna(axis=1)**
填充缺失值
如果您希望填充缺少的值,而不是完全删除行或列,可以使用下面的代码:
df.variable**.fillna**("n/a")
替换值
假设有一个数据帧,其中有人已经用“n/a”填充了缺失值,但是您希望用“unknown”填充缺失值。那么您可以使用下面的代码:
df.variable**.replace**("n/a", "unknown")
组合数据
。concat()
当您想要合并具有相同列的两个数据帧时,这很有用。例如,如果我们想将一月份的销售额和二月份的销售额结合起来分析长期趋势,您可以使用以下代码:
Jan_sales = pd.read_csv("jan_sales.csv")
Feb_sales = pd.read_csv("feb_sales.csv")**pd.concat**([Jan_sales, Feb_sales])
。加入()
如果您想要合并具有公共索引的两个列(例如 customer_id),那么您可以使用。加入()。
使用上的参数确定要连接的列。
要确定它是左连接、右连接、内连接还是外连接,可以使用参数 how 。
# example
table_1.**join**(table_2, on='customer_id', *how='left')*
如果你不了解 SQL joins,在这里阅读。本质上是一样的想法。
5.SQL 和查询
定义
行,也称为记录,*是代表单个实体的属性(变量)的集合。例如,一行可能代表一个住院病人,可能有年龄、体重、身高等属性/变量…*

表是具有相同属性(相同变量)的行的集合。对我帮助最大的是把一个表格想象成一个 Excel 表格。

表格示例
查询是从数据库表或表的组合中请求数据。使用上面的表格,如果我想找到所有年龄大于 23 岁的患者,我将编写一个查询*。*
如何编写 SQL
因为这是一个初学者的教程,所以如果你想从一个表中提取数据,我将向你展示如何编写一个查询。
一个基本查询有五个组成部分:
- 选择(必填)
- 从(必填)
- 其中(可选)
- 分组依据(可选)
- 排序依据(可选)
其结构如下:
***SELECT**
[column_name_1],
[column_name_2],
[column_name_n]
**FROM**
[table_name]
**WHERE**
[condition 1]
**GROUP BY** [column_name]
**ORDER BY** [column_name]*
让我们带回我的例子作为参考:

1.选择(必填)
SELECT 决定了要从给定的表中提取哪些列。例如,如果我想提取名字,那么我的代码应该是这样的:
*SELECT Name*
一个巧妙的技巧是,如果你想提取所有的列,你可以使用星号——如下所示:
*SELECT **
2.从(必填)

FROM 确定要从哪个表中提取信息。例如,如果您想要提取患者的姓名,您可能想要从名为 patient_info 的表中提取数据(见上文)。代码看起来会像这样:
*SELECT
Name
FROM
patient_info*
这是您的第一个函数查询!让我们来完成另外 3 个可选步骤。
3.其中(可选)
如果您想选择年龄超过 23 岁的患者的姓名,该怎么办?这就是我们的用武之地。 WHERE 是用来过滤您的表的语句,就像您在 Excel 中使用过滤工具一样!
获取 23 岁以上患者姓名的代码在左边。右侧显示了一个可视化表示:

如果您想要满足两个子句的患者姓名,您可以使用和。例如,查找年龄超过 23 岁且体重超过 130 磅的患者的姓名。
*SELECT
Name
FROM
patient_info
WHERE
Age > 23
AND
Weight_lbs > 130*
如果您想要满足两个子句之一的患者姓名,您可以使用或。找出小于 22 岁或大于 23 岁的病人的名字。
*SELECT
Name
FROM
patient_info
WHERE
Age < 22
OR
Age > 23*
4.分组依据(可选)
GROUP BY 正如它所说的那样— 它将具有相同值的行分组到汇总行中。它通常与计数、最小值、最大值、总和、AVG 等聚合函数一起使用。
让我们用下面的例子:

如果我们想得到每个病人去医院的次数,我们可以使用下面的代码并得到下面的结果:

5.排序依据(可选)
ORDER BY 允许您根据特定属性或多个属性按升序或降序对结果进行排序。我们来举个例子。

*SELECT
*
FROM
patient_info
ORDER BY
Age asc*
“ORDER BY Age asc”意味着您的结果集将按年龄以升序对行进行排序(参见上图中的左表)。如果你想按降序排列(上图的右边表格),你可以用 desc 代替 asc 。
现在你已经学习了基本结构,下一步是学习 SQL 连接,你可以在这里阅读。
6.额外内容
如果你读到了最后,恭喜你!我希望这能激励你继续你的数据科学之旅。事实是,关于我写的每个主题,还有很多东西需要学习,但幸运的是,有成千上万的资源可供您使用!
下面是一些额外的资源和教程,您可以用它们来继续学习:
- 建立你的第一个机器学习模型并开始你的数据科学生涯的指南 : 如果你从未创建过机器学习模型并且不知道从哪里开始,请参考这个。
- 探索性数据分析的详尽逐步指南 :探索您的数据对于您使用的每个数据集都至关重要。通读这篇文章,了解什么是 EDA 以及如何进行 EDA。
- 如何用 Python 代码评价你的机器学习模型! :创建你的机器学习模型是一回事。创造一个好的机器学习模型是另一件事。这篇文章教你如何评估你是否建立了一个好的机器学习模型。
- 超过 100 个数据科学家面试问答! :一旦你建立了一个强大的数据科学组合,你觉得已经准备好找工作了,利用这个资源来帮助你准备找工作。
感谢阅读!
如果你喜欢我的工作,想支持我…
- 支持我的最好方式就是在媒体上这里关注我。
- 在 Twitter 这里成为第一批关注我的人之一。我会在这里发布很多更新和有趣的东西!
- 此外,成为第一批订阅我的新 YouTube 频道 这里!
- 在 LinkedIn 这里关注我。
- 在我的邮箱列表 这里注册。
- 看看我的网站,terenceshin.com。
从零到英雄学习 Python 所需的一切
计算机编程语言
分享我用来学习 Python 的资源,从书籍、课程、播客到编码网站和文档

维克多·加西亚在 Unsplash 上拍摄的照片
在这个编程技能非常有利可图的时代,每个人都在利用互联网上的大量资源来学习编程。你不仅可以开发供你个人使用的程序,或者仅仅是为了构建一些东西,而且你还可以通过大量的实践和正确的关系不断增强你的技能,从而在知名公司如谷歌、特斯拉、亚马逊等赢得一席之地。
史蒂夫·乔布斯曾说过一句名言:
“我认为每个人都应该学习如何给计算机编程(学习一种计算机语言),因为它教你如何思考。”—史蒂夫·乔布斯
也就是说,我自己正在开发我的编程技能,更具体地说是 Python,这是目前最流行的编程语言之一。这就是为什么我搜遍了互联网,收集了这个动物园或个人收藏的资源,我将用它们来真正全面地掌握 Python。我不建议任何人从这个列表中学习每一个资源,因为一个人的时间是有限的,所以一定要选择几个你想使用的和你认为可以获得最大收益的资源。
有些书和在线课程是免费的,有些不是,所以在决定付费之前,一定要确保它们是你学习和发展的好投资。我希望这篇文章对任何想学习 Python 的人来说都是有用的资源。
目录
- 书
- 在线课程
- 油管(国外视频网站)
- 编码挑战
- 博客和网站
- 播客
- 时事通讯
- IDEs 与环境
书
书籍是信息的驱动力,为一个更伟大、更有知识的社会提供动力。从书本中学习技能总是很棒的,因为它们是可靠和紧凑的。我发现编程和编码的书最好是电子书,这样更容易参考和使用。这里有几个我觉得对学习 Python 很有帮助的例子。
初学者
这构成了 python 的基础,从安装和设置 Python 到用类和函数(OOP)编写成熟的程序
- 用 Python 自动化枯燥的东西(第二版) —这是一本免费的两部分书籍,涵盖了自动化计算机上单调任务的基础知识和项目,帮助初学者直接应用他们的知识。
- Python 速成教程(第二版) — PCC 对概念有更详细的解释,也是一本分为两部分的书,第一部分是基础知识,从打印 hello world 到 OOP,从头开始编写类和函数,第二部分是 3 个有趣的小项目—创建游戏、可视化数据和 web 应用程序。
- Think Python 2e——Think Python 是前两本书的后续免费书籍,主要是因为它教你计算机科学的基础知识,并使用 Python 来实现这一目标。
- 艰难地学习 Python 3——这是编程初学者钻研 Python 的另一个选择。这并不困难,因为你不会理解任何东西,这是一种不同的学习方法,作者将其解释为“指导”,通过重复来培养技能。
中级/高级
这些包括更高级的概念,并教你如何编写 pythonic 代码以及项目和应用程序。
- 学习 Python(第五版) —这是一本厚重的书(1600 页),比你从头到尾通读一遍的书更适合作为参考。当你想深入某个特定主题并了解它的全部内容时,这是一本很棒的书。
- 有效的 Python —写更好的 Python 的 90 种方法合集是本书的副标题,不言自明。这些技巧来自 Python 语言的老手,肯定会对您的开发有用。
- Python 食谱 —这本书包含了无数应用程序的食谱(因此得名食谱)。这种食谱的合并是为那些想要测试最新工具的有经验的程序员准备的,因为每个主题都给你一个现成的代码块,以及解释
- 流畅的 Python —这本书帮助你对 Python 有一个很深的理解,并教你表现抽象和具体。它告诉你如何和为什么。它更加高级,并且期望您事先能够熟练地在可变项目中使用 Python。
数据科学
- 从零开始的数据科学 —如果你刚刚接触数据科学,从零开始的 DS 是一个很好的资源。要了解更多,请查看我的文章。
- python like you mean it—PLYMI 是一个免费资源,用于学习 Python 和 NumPy 的基础知识,因此它非常适合那些学习 Python 进行数据分析和机器学习的人。
- Python 数据科学手册——这是一本免费手册,面向那些希望使用 Python 处理数据操作、转换、清理、可视化和机器学习模型的人,这些都是数据科学家的日常任务。Python 中科学计算的必备。
- 用于数据分析的 Python—以数据科学的数据分析部分为中心,介绍了解决大量数据分析问题的库。由熊猫图书馆的作者撰写,这本书解决了许多实际研究,是有抱负的分析师的理想选择。
机器学习
- 机器学习 w Python 简介 —这本书教你如何用 Python 和 scikit-learn 构建 ML 应用。它在光谱的实践方面,帮助你获得对 ML 的直观理解。
- 使用 Scikit 动手操作 ML-学习& Tensorflow,第二版。 —动手 ML 是一本学习和应用都很棒的书。读者可以应用他们的知识,接触 ML 世界中两个流行的框架。
- 机器学习 w Python Cookbook —从名字就能看出来,里面包含了很多让你在日常生活中应用 ML 的食谱。它让你超越理论和概念,并为你提供在实际应用中使用 ML 的工具。
算法
- Grokking Algorithms —这是一本很棒的书,用直观的方式教你关于算法的知识,给出的代码例子都是用 python 写的。对于程序员来说,学习算法是至关重要的,因为它允许你考虑不同类型的算法在不同时间复杂度(大 O 符号)下的权衡。另外,它在 manning.com 是免费的
- 使用 Python 的算法和数据结构解决问题——这是一本学习算法和数据结构解决问题的免费电子书,是计算机科学的基础。
更简洁详细的列表,请看这篇文章。
在线课程
在线课程就像大学教育一样,但是完全免费。MOOCs 的兴起对经济能力较差的社区非常有利,并提供了无数新的机会,这些机会曾经因贫困而不可能实现。网上学习是一种祝福和礼物,我们不应该把它视为理所当然。这里有一些我知道的很棒的 Python 课程。
介绍
- 面向所有人的 Python——可能是最受欢迎的 Python 入门课程。在 Coursera 和 YouTube 上,由 Charles Severance 教授。查看免费电子书。
- 计算机科学和 Python 编程简介 —麻省理工学院的《计算机科学导论》是编程初学者学习 Python 计算和问题解决的绝佳课程。
- 谷歌的 Python —谷歌的 Python 课程是掌握 Python 基础或复习概念的一种快速而有趣的方式,它配有讲座视频、交互式代码和练习。
- FreeCodeCamp——以免费课程和令人惊叹的 YouTube 教程闻名,FCC 最近发布了 Python 课程,供所有人免费学习。
- 实用 Python 编程 Github 上的一门免费课程,向您传授 Python 的实用知识,如处理数据、测试和调试,以及高级主题,如函数装饰器、静态和类方法。
数据科学和人工智能
- Python UMich应用数据系统专业——该专业也非常受所有有抱负的数据科学家的欢迎,以 Python 授课,从基础到顶点项目,确保您做好充分准备并具备应用数据科学方法和技术的技能。
- 计算思维和数据科学简介——这是用 python 讲授 cs 简介的延续,更侧重于计算思维和数据科学,也用 Python 讲授。
- CS50 用 Python 介绍 AI—CS50 是最著名的 CS 课程之一,它专注于使用 Python 中的机器学习,向您介绍算法和模型,这些算法和模型揭示了自动驾驶汽车、推荐系统等背后的隐藏机制。
- 构建人工智能(Building AI)——这门课程面向任何想要提高人工智能相关词汇和技能的人,包括非程序员和可以用 Python 编程的人。
深度学习
- fast.ai — fast.ai 是一门非常受欢迎的免费学习深度学习的课程,大部分课程都是用 Python 和 PyTorch 教授的。如果你对自己的 python 能力以及对机器学习的良好理解有信心,fast.ai 是你迈向精通的下一步。
其他网站,如 Dataquest.io 、 Codeacademy 、 Educative.io 、 pluralsight 和 Udemy 都是很好的课程,有简明的路径让初学者轻松完成,但它们相当昂贵,所以这真的取决于偏好。
油管(国外视频网站)
YouTube 是互联网诞生以来最伟大的平台之一,尽管它有大量的错误信息、点击诱饵和成堆的广告。这仍然是学习新技能的最好方法之一,这里有一些 YouTube 频道,里面有令人惊叹的 Python 教程。
- 科里·斯查费——一个伟大的编程渠道,涵盖不同技能水平的主题,包括 Python、Git、开发环境、终端、SQL、JS、cs 等等。他的 Python 播放列表有超过 140 个视频,并且还在增加,这对初学者来说是惊人的,非常实用。
- Sentdex——除了 python 教程,sent dex 还有涵盖机器学习、数据分析、web 开发、游戏开发等等的视频。他的 Python 教程范围很广,涵盖了机器学习的非常基础的到从头构建神经网络。
- TechWithTim —资源丰富多样的 Tim 拥有大量关于多种语言的教程,他的 python 教程涵盖了许多主题,包括构建机器人、机器学习、聊天机器人、神经网络,以及许多信息视频。
- FreeCodeCamp——它以许多长且内容丰富的视频而闻名,这些视频帮助初学者从头开始创作。他们在这个播放列表中有很棒的 python 视频。
- 德里克·巴纳斯——一个伟大的 Youtuber 用户,他涵盖了大量编程主题,有一个关于 ML 和数据科学的惊人系列
编码挑战
编码挑战就像轻推,帮助你巩固你的知识,同时学会新的技巧来提高你的编码能力。虽然它在编码面试中使用并不是一个程序员能力的真实表现(通过足够的练习,一个人最终可以记住挑战的答案),但它对培养编程的习惯很有帮助,并帮助你衡量你当前的能力。
- 伟大的用户界面和设计,我个人使用它,我认为它有一个伟大的概念,用它学习编程很有趣。
- 被许多公司用于工作面试的 HackerRank,一天一个问题会增加你到时候解决编码问题的机会。
- exercisem—一种在命令行界面中应对编码挑战的有趣方式。有一个 python Track,你可以选择实践模式或导师模式(导师对你的解决方案给出评论)
- Python 挑战赛——初学者学习 Python 的一种有趣方式,当你被讲座视频和书籍搞得精疲力尽时很有用
- CheckIO —面向初学者和高级程序员的编码游戏,在这里你可以通过使用 Python 和 TypeScript 解决引人入胜的挑战和有趣的任务来提高你的编码技能
更多的编码挑战网站,请查看我的文章20 大编码挑战网站。
博客和网站
博客和网站是互联网上的信息口袋,就像图书馆里的书一样。有大量的程序员和资深人士对编程给出了惊人的解释和启发性的见解,还有教程和文档。在 StackOverflow、Reddit 和 Discord 这样的网站上,你可以与成千上万的其他初学者一起努力解决一个问题,或者完全被一位 10 年经验丰富的程序员的惊人的一行解决方案难倒。这里有一组在线 python 资源
在线指南/教程
- Python 的搭便车指南 —这是一本手工制作的指南,为 Python 开发新手和专家提供日常安装、配置和使用 Python 的最佳实践手册。
- 全栈 Python —全栈是一个术语,基本上是关于构建和部署应用程序的能力,包括后端和前端。这本在线书籍可以帮助你将你的 Python 知识从小程序和代码片段变成一个成熟的 web 应用程序。现在你终于可以向你的朋友和家人展示你的技能了。
- PythonProgramming.net——一系列视频教程,指导你构建项目,从机器学习和游戏开发到量子计算机编程。
备忘单
- Python 的一个有趣的小备忘单。
- 全面的 Python 备忘单
博客
Python 官方网站
Github repos
- r/learn python—python 资源和子编辑的惊人列表在这里。
StackOverflow
不和谐服务器
- 查看我的文章,为 Python 和其他人加入服务器。
播客
播客是收听专家对话和讨论的免费门票,尽管其间偶尔会有赞助广告。堵车了?散步吗?每天从家坐一小时火车去上班?每天坚持听一些播客,如果你把它变成一种习惯,你会惊讶地发现你会学到多少东西,谢谢你的复利。
时事通讯
除了垃圾邮件和订阅,你已经好几个星期没联系了,高质量的时事通讯,像詹姆斯·克利尔的,可以非常足智多谋,帮助你保持知情。如果你已经每天都在查看你的电子邮件,为什么不在里面放些有用的信息呢?这里有一些建议。
- 牛逼的 Python 简讯
- Pycoder 周刊
- Python 的把戏
- Python 周刊
- 真正的 Python 简讯
- 丹的 Python 简讯
- 高级 Python 简讯
- 咬人的蟒蛇
- Python 拼图
IDEs 与环境
要编程,你需要 ide 和对什么是虚拟环境的理解(基本上是用于不同类型项目的虚拟机,这样兼容性和版本控制就不会全乱了)。
- SublimeText3 —非常适合学习和编写小程序和代码,因为它快速且易于使用
- Atom —另一个轻量级且设计精美的 IDE,非常适合小程序和代码。
- py charm——python 程序员构建东西的伟大工具,它与 anaconda 无缝协作。PyCharm + Anaconda 是数据科学相关项目的实际组合,但是您也可以将它用于 python 项目。如果你想获得 Pycharm Professional,可以通过 GitHub 学生开发者包免费获得。
- Anaconda——一个令人惊叹的免费应用程序,它可以帮助你在一个地方管理成千上万的库和包,并消除编程和版本控制的大部分痛苦。
- Visual Studio 代码 —有些更喜欢 PyCharm,有些喜欢 VScode。这取决于你用它做什么。虽然 VScode 更轻量级,耗电更少。
- repl . it——当你只想在浏览器上快速运行或测试几行代码时,它是完美之选。
- Kaggle 笔记本——伟大的数据科学相关的 python 代码。
摘要

如果你一直对脸书、Twitter、Instagram 等价值数十亿美元的应用程序是如何构建的感到好奇,那么开始学习永远不会太晚,学习编程不仅能启发你了解应用程序运行背后的隐藏层,还能赋予你创造自己喜欢的东西的能力。
互联网上有大量的资源可以学习你感兴趣和好奇的东西,尤其是在经济不景气和失业率上升的不确定时期。掌握一项新技能可以为你带来更多的工作机会。
在线学习最重要的是专注和注意力,这两者都被社交媒体、流媒体服务和人们经常跳舞的应用程序高度利用。是时候用提高生产力和时间管理的应用程序来收回你的注意力了, Google Calendar 用于规划你一天的时间块, Todoist 用于创建你的 todolist,concept用于写日志和笔记,以及定时器应用程序 Forest 用于激励你专注并在工作中获得流动。
我希望你觉得我的文章很有资源,并在下面的评论中留下你认为对学习 python 有帮助的任何其他资源。在我的下一篇文章中再见,注意安全!
欲了解更多资源,请访问:
[## Stephen h67/python-resources-2019
9/6/20 更新了 Python 3 资源、书籍、网站、教程、代码挑战的精选列表。如果你有…
github.com](https://github.com/stephenh67/python-resources-2019) [## 常规 Python 资源
Python 速成班的指导原则是,“为了……你至少需要知道什么
ehmatthes.github.io](https://ehmatthes.github.io/pcc_2e/recommended_reading/general_python/)
如果您对学习数据科学感兴趣,就从这两个系列开始吧!
这是一个简短的指南,基于《超学习》一书,应用于数据科学
medium.com](https://medium.com/better-programming/how-to-ultralearn-data-science-part-1-92e143b7257b) [## 数据科学简介
关于什么是数据科学、大数据、数据和数据科学过程及其应用。
towardsdatascience.com](/the-data-scientists-toolbox-part-1-c214adcc859f)
查看这些关于数据科学资源的文章。
[## 2020 年你应该订阅的 25 大数据科学 YouTube 频道
以下是你应该关注的学习编程、机器学习和人工智能、数学和数据的最佳 YouTubers
towardsdatascience.com](/top-20-youtube-channels-for-data-science-in-2020-2ef4fb0d3d5) [## 互联网上 20 大免费数据科学、ML 和 AI MOOCs
以下是关于数据科学、机器学习、深度学习和人工智能的最佳在线课程列表
towardsdatascience.com](/top-20-free-data-science-ml-and-ai-moocs-on-the-internet-4036bd0aac12) [## 机器学习和数据科学的 20 大网站
这里是我列出的最好的 ML 和数据科学网站,可以提供有价值的资源和新闻。
medium.com](https://medium.com/swlh/top-20-websites-for-machine-learning-and-data-science-d0b113130068) [## 开始数据科学之旅的最佳书籍
这是你从头开始学习数据科学应该读的书。
towardsdatascience.com](/the-best-book-to-start-your-data-science-journey-f457b0994160) [## 数据科学 20 大播客
面向数据爱好者的最佳数据科学播客列表。
towardsdatascience.com](/top-20-podcasts-for-data-science-83dc9e07448e)
联系人
如果你想了解我的最新文章,请通过媒体关注我。
也关注我的其他社交资料!
请关注我的下一篇文章,记得保持安全!
关于梯度下降你应该知道的一切

丹尼尔·里昂在 Unsplash 上的照片
这是数据科学中最流行的优化算法之一。你知道它是如何工作的吗?
我为什么要看这个?
大多数机器学习模型使用某种优化算法来寻找产生最小误差的参数,梯度下降可能是这些算法中最受欢迎的一种。
如果你是一名数据科学家或从事机器学习工作,你肯定会使用某种使用梯度下降的算法。即使您可能永远不会自己硬编码它,理解它是如何工作的可以帮助您理解为什么您的模型没有给出好的结果,甚至根本没有收敛。
它是如何工作的?
梯度下降寻找导致函数局部最小值的参数。在最大似然算法中,该函数通常是某种代价函数,与模型输出和实际观测值之间的差异有关。
直觉
梯度下降在函数中选择一个随机点,并开始向周围的最低点“行走”,直到它达到局部最小值。起点是产生一定成本(误差)的参数的随机组合。接下来的步骤就是在附近找一个这个成本更低的点,移动到这个点上。
想象你在黑暗中走在一座山上,试图找到可能的最低点。你慢慢摸索着路,试图一直走下去。斜坡越平缓,你走得越慢,因为你越期待它到达终点。
Gif 来自 Gfycat 。
使其正式化
但是,在函数中搜索时,如何控制速度呢?利用函数在特定点的导数。

然后,您将使用成本函数 j(θ)在您现在所在点上的导数,按顺序更新您的函数参数θ,由⍺.进行调整
⍺是学习率(当算法“行走”时,你调整“步”的大小)。如果⍺太小,算法就会太慢。如果⍺太大,算法可能无法收敛甚至发散。
:=是一个赋值操作符,意味着我们把这样的值赋给变量。
所以,理想情况下,你希望自己的学习率尽可能高(这样你的算法运行得越快越好),而不至于高到发散。下次你的模型不收敛的时候,试着用一个小一点的学习率。
替代版本
对于非常大的数据集,梯度下降在计算上非常昂贵,因为它必须在每次迭代中计算整个数据集的 J。因此,让我们来看看一些更适合大量数据的替代方法。
随机梯度下降
随机梯度下降从随机洗牌开始。这很重要,因为它将一步一步地阅读观察结果,所以它们不应该有任何特定的顺序。然后,它将只为第一次观察计算成本函数,并只基于该观察向最小值迈出第一步。对于第二次迭代,它将做同样的事情,仅仅基于第二次观察。依此类推,直到它到达训练集中的最后一个观察值。如果您有很多数据,这仍然应该在合理的时间内产生令人满意的结果。
小批量梯度下降
小批量版本介于随机版本和经典版本之间。这里,它不是在每次迭代中只使用一个训练示例,而是使用一个用户定义的参数,大小为 b 的小批量。这意味着,例如,如果我们设置 b = 10,我们将在每次迭代中使用 10 个观测值进行梯度下降。这有时实际上比随机版本更快。如果你仔细想想,你会发现随机版本实际上是迷你批量的特例,当 b = 1 时。
结论
现在你知道了梯度下降是如何工作的,你知道了当梯度下降不收敛时,如何通过改变学习速率来修复它,以及如何通过实现它的替代版本来使它更快。
如果你喜欢这篇文章,你可能也会喜欢其中的一篇:
回归技术帮助您测量变量的相关程度。他们允许你说,例如…
towardsdatascience.com](/linear-regression-the-basics-4daad1aeb845) [## XGBoost:理论与实践
了解最流行的算法之一是如何工作的,以及如何使用它
towardsdatascience.com](/xgboost-theory-and-practice-fb8912930ad6)
如果你想进一步讨论,请随时在 LinkedIn 上联系我,这将是我的荣幸(老实说)。
邪恶的约翰内斯·古腾堡
技术进步的另一个视角。

由 Merzmensch 的art breader制作
J 奥汉斯·古腾堡是个邪恶的纨绔子弟。他扼杀了书籍的人文因素。在他的时代之前,人们汗流浃背地一个字母接一个字母地写文章,他们把一生都献给了写作和阅读这种独特的人类体验。
古腾堡发明了冷机,印刷了一本又一本的书。废话连篇,一旦写出来。他制造假新闻。在他的时代之前,恶作剧制造者必须手写他们的煽动性文章——这需要时间,并在一段时间内拯救了社会。现在,有了这个邪恶的机器,每个人都可以在最短的时间内印刷和传播假新闻。
毕竟,《我的奋斗》也是一本书,它没有在 20 世纪 30 年代纳粹阴谋者之间的手写手稿中流通,而是自豪地出现在纳粹德国的中央书店里。
邪恶的书…
…邪恶的 AI。
在过去,宣传需要人手来写。[……]只需很少的努力,GPT-3 就可以被引导以一系列风格写作:在最近的一项研究中,米德尔伯里国际研究学院的研究人员克里斯·麦古菲和亚历克斯·纽豪斯发现,它可以被提示生成可信的亲纳粹帖子,再现大规模射击宣言的写作风格,并像卡农信徒一样回答问题。GPT-3 的开发者明白滥用的可能性,并限制了访问的人数,尽管敌对国家可能很快就会开发出模仿版本。(《大西洋月刊》,2020 年 9 月 20 日)
在关于新技术及其对社会的影响的讨论中,人工智能滥用的愿景一直是一个大话题。现在,随着 GPT-3 成为全球作家,世界发现了一个新的妖怪,可以在信息启示录的情况下解决。
这种 topos——一种将人类与受害者并列的敌对技术——可能是现在前所未有的我们媒体中最受欢迎的主题之一(无论这种媒体代表的是什么颜色、政治运动还是国家)。
然而主要的话题仍然没有被提及:人类。
我们已经看到错误的标签和不准确的数据集准备可以通过人工智能的完美表现带来可怕的结果。事实上,人工智能开发者对机器学习模型负有责任:数据集应该尽可能基于最高的多样性,人工智能模型必须无故障地运行。
但是他们做到了。即使不是那么明显和容易。
对于图片深度造假:
StyleGAN 实现了潜在空间投影,识别出一张疑似伪造的图像。(这并不总是完美的,但是给出了方法)。
对于视频 deepfakes:
AI 研究人员利用心跳检测在运动画面中寻找 deepfake。
对于自然语言处理生成的文本:
据我所知,OpenAI 正在为 GPT-3 生成的内容开发检测工具。它们还实现了各种语义标记功能,以在文本可能存在特定风险时发出信号。
独立于此,有一个 Chrome 插件 GPTrue of False ,它可以显示文本是 transformer 生成的还是人类编写的概率。
…仅提及人工智能社区为提供人工智能滥用的预防性保护所做的一些多方面的努力。
不幸的是,这些努力并没有真正接触到公众,或者对主流观众来说并没有真正的吸引力(与《黑镜》的恐怖故事相比)。
这不是对我们文明中普通成员数字能力不足的咆哮。我们的任务是提高对它的认识,为教育做贡献,开设人工智能,提供课程,写书和文章,走上数字街道。
即使技术焦虑的趋势现在似乎很流行,即使人们请求技术进步后退一步:
你不能通过破坏技术来修复社会。
EvoFlow:为什么我们更喜欢自己的气流解决方案

商业科学
通用的流量检查流程
EvoFlow 简介
EvoFlow 是由 Evo 的数据工程师和 devOps 团队开发的多功能平台,用于创建、调度和监控工作流。
编码工作流允许开发团队创建和共享他们产品的版本。这种协作过程可以在保持产品结构的同时进行,或者更好的是,在改进这些结构的同时进行。
EvoFlow 的创建是为了增强 ETL、Scraper 和其他数据管道检查的流程,但是它的功能远远超出了这些用途。
EVO 之路
那么我们为什么要创建自己的平台呢?毕竟,广泛采用的气流(【https://airflow.apache.org/】)可以做 EvoFlow 做的所有事情;早已成为标配。虽然气流的用处是没有争议的,但这个工具可能有点笨拙。有了这么多的功能,它实际上可以减慢简单的检查。我们需要一个工具来简化 ETL 和 Scraper 流程,而不是使流程进一步复杂化。
EVO 数据工程师和 DevOps 团队决定构建一个简化的平台,以便更快地实现我们的目标。我们将它命名为 EvoFlow,因为它是作为流检查的流而诞生的。
与气流相比,EvoFlow 的创建给了该团队一些显著的优势。使用 EvoFlow,我们可以受益于:
- 由于平台的功能减少,结构更简单;
- 由于对整个平台的了解而具有更高的控制能力;
- 由于在使用的基础设施上构建了 EvoFlow 代码,因此具有更高的适应性;
- 由于平台需求减少,基础设施成本降低;
- 由于与广泛采用的警报管理器(https://prometheus.io/docs/alerting/latest/alertmanager/)的结合,警报管理具有更高的灵活性。
结构
EvoFlow 有五个关键组件,所有这些组件都可以在图 1 中看到:
- 来源包括 JSON、R、SQL、txt、Python、CSV 文件,加载所需任务中使用的数据;
- 规则指定了平台执行任务和进来所需的所有信息。yml 文件;
- Python 中定义的函数详细描述了要执行的操作;
- 日志在执行时打印出来,并存储在 SQL 数据库中;
- 警报由 Alertmanager 管理;
- 报告构建为元数据库(https://www.metabase.com/)仪表板。

图 EvoFlow 平台的方案(图片由作者提供)。
成分
源文件包括几个扩展名,通常用于将数据加载到 EvoFlow 平台中。对数据源的唯一要求是它们不能在加载过程中改变数据。例如,SQL 查询应该只包含 select 语句:
SELECT'dates/weeks' AS items_type,'sql execute' AS check_message,MIN(date) AS start_date,MAX(date) AS end_date,MIN(CONVERT(int, week)) AS min_week_diffFROMclient_calendar
规则是。定义 EvoFlow 要求(数据)、数据源路径(源)、检查要求(接受)、错误消息(error_message)、描述(check_descriptions)和严重性(severity)的 yml 文件:
# Check etl executionParameters:# Define the parameters required by the projectsql_string: 'TRUE'sql_connection: 'TRUE'sql_logs: 'TRUE'is_check: 'TRUE'email_alert: 'TRUE'Checks:
# Check files importfiles_check:type: sqlpath: '/functions/check_last_import_file_amount.sql'check_description: 'Check amount of files imported'error_message: 'The imported files amount is wrong'severity: Criticalacceptances:- compare_to_acceptance(comparison="(abs(data['last_import'] - data['previous_import']) / data['previous_import']) < 0.1")package_check:
# Check ETL package executiontype: sqlpath: '/functions/check_package_error.sql'check_description: 'Check errors in the ETL package'error_message: 'Errors in the ETL packages execution'severity: Erroracceptances:- compare_to_acceptance(comparison="data['count_value'] == 0")
函数指定规则接受所需的所有动作和检查。它们通常用 Python 编写:
def compare_to_acceptance(comparison):"""Compare a given field to a provided acceptanceParameters:comparison (string): the comparison to executeReturns:0 if the results are within the acceptance, 1 otherwise"""# Initialise the list of resultsresults = list()# Iterate for each element and get the results of the checkfor i in range(0, len(self.data)):result = 0 if eval(comparison) else 1results.append(result)return(results)
日志通常存储在 SQL 数据库中,由 Alertmanager 管理,并报告为元数据库仪表板。
功能
EvoFlow 主要处理 ETL 和 scraper 自动化的检查。也就是说,它的功能还可以执行任何可能的脚本并管理相应的警报。
EvoFlow 目前用于:
- 检查客户端 ETL 输出的质量;
- 检查自动刮刀产生的数据质量;
- 分析工具文件夹并识别自动化的问题;
- 将每日汇率导入 SQL 数据库。
如果我们将来需要扩展 EvoFlow 的使用,该平台也具有完成这些任务所需的灵活性。
结论
EvoFlow 平台的开发改变了 EVO 组织的游戏规则。有了这个新的基础设施,我们能够:
- 识别和纠正自动化中的问题和错误的速度至少快四倍;
- 创建对数据和流程的新检查,并使用仪表板对其进行监控;
- 提醒所有参与使用工具的人,而不仅仅是开发人员;
- 创建独立的流动,可以存在于最常用的管道之外;
- 在运行代码流之前,自动评估代码的质量。
为了评估 EvoFlow 的性能,我们希望量化其影响。我们主要测量了在一项任务上花费的时间和警报的数量。根据任务的不同,花在这些任务上的时间减少了 2 到 4 倍。警报数量每周下降约 10%。
主要由于 EvoFlow 与 Alertmanager 的集成,警报数量持续下降。这个联合允许我们根据关联项目的名称和警报的严重级别(错误、警告、严重)来管理警报。此外,该集成还会自动创建与触发的警报相关的 Gitlab 问题,以确保每个警报都有适当的优先级,并确保解决该问题的任务被委派给正确的团队成员。
我们的早期结果显示了年轻的 EvoFlow 平台的前景。它已经带来了显著的投资回报,我们乐观地认为不久会有更好的表现。虽然我们不能建议像 EvoFlow 这样的简化平台是每个团队的正确解决方案,但我们对它迄今为止的成功感到高兴。
将整体架构迁移到微服务架构
微服务、框架和设计的原则
我们为什么需要微服务?
微服务是这几天的热门话题。但是为什么大家都在说微服务呢?什么是单片架构,什么是微服务架构?我将通过从整体架构到微服务架构的迁移过程来解释这一点。我还将介绍微服务架构的特点、优势,以及它面临的一些挑战。

什么是整体架构?
整体架构意味着我们将应用程序的所有功能放在一个归档包中进行部署和运行。例如,如果你使用 Java,你所有的函数都打包到一个 Jar 包或 War 包中。这种风格的架构可以称为单一应用程序风格架构,也称为整体架构。
单片架构的优势
这种架构有什么优势?它有很多优点,包括相对简单,大家都熟悉。此外,它是 IDE 友好的。ide 通常被设计成可以轻松地开发、部署、调试和分析单个应用程序。它非常容易部署,例如,由于只有一个 war 包或 jar 包,或者一个可执行程序,您可以很容易地将其部署在一个目录或多个目录中。
整体架构的缺点
当然,这种整体架构也有其缺点。缺点主要在于系统的复杂性,尤其是网上商城、网上银行等复杂系统。这些单个应用程序的代码库将会庞大而难以维护,这也很难理解。

单片软件的代码很难理解。照片由 Tim Gouw 在 Unsplash 上拍摄
况且由于代码基数特别大,启动要花很多时间。以前做单申请的时候,要半个小时才能开始,所以我们都有足够的时间去打乒乓球。
它缺乏可扩展性。由于所有的功能都放在同一个应用程序中,而如果我想改变一个微小的功能,比如我稍微修改了一下用户注册功能,但是后勤模块没有改变,甚至连后勤模块都没有改变,我不得不能够再次重新部署它,这是痛苦和低效的。
还有很多其他的缺点因为是单代码库,所以我们只能用一个技术栈,全 Java,全 C++,全 Python 等。,会有很多限制。这些都是单片架构的缺点。
如何解决单片架构的不足?
现在有这些不足,怎么解决呢?软件世界中的解决方案的方法论与通常的世界是一样的。当我们面对生活中复杂的问题时,我们的方法是分而治之,这和这个软件世界是一样的。整体架构简单来说就是 all in one,即将所有东西放在一起。如果我想解决这些问题,我必须通过一些划分。
首先,垂直划分会划分出完全不相关的应用。例如,用户注册模块和图片显示模块完全互不干扰。我们可以把它分成多个独立的模块,使它们耦合性更小。

分而治之是微服务之道。照片由 Alex 在 Unsplash 上拍摄
当系统慢慢变得越来越复杂,单个模块可能更复杂的时候,我们可能会考虑再次分而治之,也就是横分。什么是水平分割?例如,物流模块可能需要访问用户信息,信贷模块可能也需要访问用户信息,等等。如果所有模块都访问同一个用户数据库,数据库负载将会非常高。因此,我们将它们横向划分,我们将所有与用户相关的放在一个较低级别的用户管理模块中,将与订单相关的放在一个订单管理模块中。这是解决单一架构缺陷的第二步。如果经过这两步划分,模块仍然非常复杂,我们将在系统中引入微服务模型。

整体架构与微服务架构
微服务模型
微服务模式目前没有一个严格的定义,但大致可以分为以下几个特征。整个系统按照业务场景来划分,比如刚才说的用户管理模块可能包括用户注册、用户登录等。我们根据业务场景来划分,这样它的扩展性可以更好。同时,服务通过几种语言无关的机制进行通信,包括 HTTP 的 RESTful 风格,这是常用的一种。
另外,每个服务都是自主的。简单来说,我的数据归我。仅作为示例,用户数据由用户管理模块管理。要让其他人访问用户数据,您需要其他人通过您的用户管理模块获取数据,而不是直接访问您的数据库。
还有一个特性,因为在它被分成越来越多的小服务之后,到最后,它的部署可能会比较困难,所以微服务模型需要一个自动化部署的特性。

划分服务,直到它们变得非常微小。Jo Szczepanska 在 Unsplash 上拍摄的照片
当然,当你开发越来越多的微服务时,你可能需要考虑一种方法来管理它们。比如一个城市以前只有一个企业,你可以很容易的联系上。但是当以后几千家或者几百家企业发展起来了,你不可能一个一个找出来处理。也许会有工商局。当我寻找这项服务时,我首先寻找公共局,寻找提供这项服务的公司,我会找到联系地址。然后我再找一家公司和他沟通。这是集中管理的一个特点。
接下来,微服务在不同机器上的分布当然是自然的,多个服务、多个机器、多个实例被部署形成一个分布式系统。基于这些特点,微服务是有优势的,而这正是单片架构所缺乏的。
另一个优势包括对代码的更好理解。以前所有的代码都放在一起,大家可能看不懂,很复杂。但是一个服务模块可能只有一个简单的功能,如用户注册、用户登录、信用查询等。如此简单的功能模块,代码简单,易于维护,开发效率高。还具有良好的扩展能力。例如,我想在注册过程中添加一个电子邮件通知。是的,不需要编辑用户注册码。

代码简单且易于维护。由克里斯多佛·高尔在 Unsplash 拍摄的照片
技术堆栈的选择更加灵活,因为我们通过与语言无关的协议相互通信。比如商城推荐系统可以用流行的 Python 实现,商品管理系统还是用 Java。这没关系,因为通信协议是语言不可知的,这是它的优势之一。
另外,版本更新更加敏捷,因为每个模块都是单独维护的。
最重要的是它更健壮,这意味着如果单个模块挂起,不是所有模块都挂起。比如物流系统暂停了一个小时,但是我还可以进货,注册,登录。这对微服务来说是一个巨大的优势。
微服务的挑战
当然,世界上没有十全十美的事情。这些优势会带来一些其他的困难。微服务带来的困难有哪些?首先,它的复杂度会更高,因为它的服务众多,你管理起来会有困难。
此外,因为服务分布在不同的机器和不同的进程上,它们的事务很难控制。考虑像银行账户之间的现金转移这样的用例,用户从一个微服务中扣除了钱,然后调用另一个服务来转移现金。利用以前的整体架构,它可以确保通过数据库进行事务处理的即时性。那么如果是分布式的,就需要通过复杂的机制来保证交易的即时性。我会在后面的文章里继续说。

上千个微服务之间的连接会很麻烦。约翰·巴克利在 Unsplash 上拍摄的照片
另一个挑战是服务分工。现在我们还没有一个如何划分的标准。不同的公司甚至一个公司内的不同部门都会有各自的分工策略。
最后一个是部署。我刚刚提到,因为有更多的服务,比单一架构更难部署。过去,软件可能只有一个应用程序和一个服务,部署很容易。现在一个应用可能有上百甚至上千个服务,部署会有很大的挑战。
摘要
首先,我们简单介绍一下什么是单片架构,它的优点和缺点,我们必须继续通过分而治之的方法来解决它的缺点,然后逐渐演变为微服务架构,它的特点和优点为软件设计提供了巨大的改进。同时,我们还介绍了微服务架构实现这些优势将面临的一些挑战。
极限学习机的进化
理解 ML
这些年来榆树是如何进化的,现在它们的地位如何?

多层结构。来源: 用榆树进行大数据的具象学习
注意!这只是榆树进化的一个主要概述。它并没有包括所有可能的版本和这些年来对 ELMs 所做的调整。
榆树是什么?
ELM(极限学习机)是前馈神经网络。于 2006 年由 G. Huang 发明,它基于逆矩阵近似的思想。
如果你不熟悉 ELMs,请先看看我的文章“极限学习机简介”。
进化是什么时候开始的?
我-ELM (2006 年)

工字形榆树结构。来源: 增量式极限学习机的一种改进算法
在 2006 年的原始论文发表后,黄和他的同事们发表了另一篇关于不同类型的 ELM 的论文,称为 I-ELM (增量 ELM)。顾名思义,I-ELM 是标准 ELM 网络的增量版本。I-ELM 的想法很简单:
从 l=0 开始定义最大隐节点数 l 和期望训练精度ϵ(l 为当前隐节点数):
- 增量 l_t = l_{t-1} + 1
- 随机初始化新添加的隐藏神经元的权重 w_l 和偏置 b_l(不要重新初始化已经存在的神经元)
- 计算输出向量 H
- 计算权重向量 β ^
- 添加节点后计算错误
- 检查 E < ϵ
- 如果没有,则增加隐藏节点的数量,并重复该过程。
有一种可能是,l > L 在过程中的某一点和 E > ϵ 。此时,我们应该重复训练和初始化的整个过程。
增加网络大小的想法并不新鲜,通常比“手动”设置网络大小产生更好的结果。就 ELMs 而言,有一个缺点特别重要,那就是计算时间。如果你的网络碰巧很大(假设有 1000 个隐藏节点),在更糟糕的情况下,我们必须进行 1000 次矩阵求逆。
如果您对 I-ELM 感兴趣,您应该知道它有许多变体:
- II-ELM(改进的 I-ELM)
- CI-ELM(凸 I-ELM)
- EI-ELM(增强型 I-ELM)
我不打算一一解释,因为这篇文章应该只是一个快速总结和一个起点,而不是关于榆树所有变种的整本书。除此之外,可能每个阅读这篇文章的人都在这里,如果他/她知道要找什么,他/她知道如何找到关于一个有趣主题的更多信息:P
P-ELM (2008 年)
在引入 ELM 的增量版本之后,另一个改进是使用修剪来实现网络的最佳结构。P-ELM(修剪榆树)于 2008 年由荣海军引进。该算法从一个非常大的网络开始,并删除与预测无关的节点。“不相关”是指节点不参与预测输出值(即输出值接近 0)。这个想法能够产生更小的分类器,并且最适合模式分类。
埃姆-埃尔姆(2009 年)
这个版本的 ELM 不是一个独立的版本,而是对 I-ELM 的改进。EM 代表误差最小化,允许添加一组节点而不是一个节点。这些节点被随机插入网络,直到误差不低于 ϵ 。
规则化榆树(2009)
从 2009 年开始,郑研究了 ELM 的稳定性和推广性能。他和他的团队想出了在计算 β ^的原始公式中加入正则化的想法。
现在看起来像是:

TS-ELM (2010 年)
两级 ELM (TS-ELM)是一个再次最小化网络结构的建议。顾名思义,它包括两个阶段:
- 应用前向递归算法从每一步随机产生的候选节点中选择隐节点。添加隐藏节点,直到满足停止标准。
- 对现有结构的审查。即使我们用最少数量的节点创建了一个网络来满足我们的标准,其中一些节点可能不再有用。在这一阶段,我们将删除不重要的节点。
凯尔姆(2010)
引入了基于内核的 ELM (KELM ),它使用内核函数来代替 H^T H 。这个想法是受 SVM 的启发,ELMs 使用的主要核函数是 RBF ( 径向基函数)。凯尔姆被用来设计深榆树。
V-ELM (2012)
基于投票的 ELM (V-ELM)是在 2012 年提出的,旨在提高分类任务的性能。问题是 ELM 的标准训练过程可能无法达到分类的最佳边界,然后随机添加节点。因此,靠近该边界的一些样本可能会被错误分类。在 V-ELM 中,我们不是只训练一个网络,而是训练许多网络,然后基于多数投票法,选择最佳网络。
ELM-AE (2013)
当 2013 年像 RBM 和自动编码器这样的想法开始流行时,卡斯努发表了一篇关于 ELM-AE (ELM 自动编码器)的论文。主要目标是能够再现输入向量,就像标准的自动编码器一样。ELM-AE 的结构看起来与标准 ELM 相同

榆树-AE 结构。来源: 大数据用 ELMs 的具象学习
有三种类型的 ELM-AE:
- 压缩。高维输入空间到低维隐藏层(比输入少的隐藏节点)。
- 平等代表权。数据维度保持不变(隐藏和输入中的节点数量相同)
- 稀疏化。高维隐藏层的低维输入空间(比输入更多的隐藏节点)
标准 ELMs 和 ELM-AE 有两个主要区别。第一个是 ELM-AE 是无人监管的。作为输出,我们使用与输入相同的向量。第二件事是 ELM-AE 中的权重是正交的,隐藏层中的偏差也是如此。这很重要,因为 ELM-AE 用于创建 ELMs 的深度版本。
MLELM (2013)
在同一篇论文(使用 ELMs 进行大数据的表征学习)中,Kasnu 提出了一种称为多层 ELM 的 ELM 版本。这个想法基于堆叠式自动编码器,由多个 ELM-AE 组成。

多层结构。来源: 用榆树进行大数据的具象学习
你可能会问“为什么还要用 ELMs 创建类似于堆栈式自动编码器的东西呢?”。如果我们看看 MLELM 是如何工作的,我们会发现它不需要微调。这使得它比标准的自动编码器网络构建起来要快得多。就像我说过的,MLELM 使用 ELM-AE 来训练每个层中的参数,并删除输出层,因此我们只剩下 ELM-AEs 的输入层和隐藏层。
DELM (2015)
Deep ELM 是最新的(也是在撰写本文时 ELM 发展的最后一次主要迭代)之一。delm 基于 MLELMs 的思想,使用 KELM 作为输出层。

DELM 结构。来源: 深度极限学习机及其在脑电分类中的应用。
结论
这些年来,ELMs 一直在进化,并且肯定抄袭了机器学习领域的一些主要思想。其中一些想法真的很棒,在设计现实生活中的模型时会很有用。你应该记得那只是对榆树领域所发生的事情的一个简短的总结,而不是一个完整的回顾(甚至不接近)。如果您在 ELM 之前键入某个前缀,很可能已经有一个版本的 ELM 带有该前缀:)
参考资料:
- 光-黄斌,秦-朱钰,徐志敬。《极限学习机:理论与应用》,2006 年出版
- 光、雷震、萧启庆。“使用带有随机隐藏节点的增量构造前馈网络的通用逼近”,2006 年出版物
- 荣,王海俊,姚谭,阿惠,朱,泽轩。(2008).一种用于分类问题的快速剪枝极端学习机。神经计算。出版
- 冯、、黄、林广斌、庆平、盖伊、罗伯特。(2009).隐节点增长和增量学习的误差最小化极限学习机。出版
- 、邓、郑、清华、陈、林。(2009).正则化极限学习机。出版
- 蓝,苏,黄广彬(2010)。用于回归的两阶段极限学习机。出版
- 萧、和。2016.一种用于回归的极限学习机优化方法。出版
- 曹,九文,林,志平,黄,刘广斌,南。(2012).基于投票的极限学习机。出版
- 卡森,李亚娜阿拉奇&周,洪明&黄,光斌&冯,智民。(2013).面向大数据的 ELMs 表示学习。出版
- 丁、、张、南、徐、新郑、郭、丽丽、张、简。(2015).深度极限学习机及其在脑电分类中的应用。出版
最初发布于https://erdem . pl。
语言模型的演变:N-gram、单词嵌入、注意力和变形金刚

约翰尼斯·普莱尼奥在 Unsplash 拍摄的图片
在这篇文章中,我认为整理一些关于自然语言处理(NLP)这些年来的进步的研究是很好的。
你会惊讶于这个领域有多年轻。
我知道我是。
但是首先,让我们为什么是语言模型打下基础。
语言模型只是简单地将概率分配给单词序列的模型。
对于神经语言模型来说,它可能是像 N-Grams 一样简单的东西。
甚至预训练的单词嵌入也是从语言建模中导出的,即 Word2Vec、Glove、SVD、LSA
我倾向于把语言模型看作是一把更大的伞,其中包含了一大堆东西。
说完了,让我们从头开始。😃
注意:请容忍我到 2000 年。从那以后变得更有趣了。
1948-1980 年之前——N-gram 和规则系统的诞生

总的来说,这一时期的大多数 NLP 系统是基于规则的,最初的一些语言模型是以 N-gram 的形式出现的。
根据我的研究,不清楚是谁创造了这个术语。
然而,N-Grams 的第一次引用来自克劳德·香农在 1948 年发表的论文“通信的数学理论”。
Shannon 在本文中总共引用了 N 元语法 3 次。
这意味着 N-Grams 的概念可能是在 1948 年之前由其他人制定的。
1980-1990 年——计算能力的崛起和 RNN 的诞生

一个单位递归神经网络的示意图(RNN),2017 年 6 月 19 日,作者 fdeloche ( 来源)
在这十年中,大多数 NLP 研究集中在能够做出概率决策的统计模型上。
1982 年,John Hopfield 引入了递归神经网络(RNN ),用于对序列数据(即文本或语音)的操作
到 1986 年,第一个将单词表示为向量的想法出现了。这些研究是由现代人工智能研究的教父之一杰弗里·辛顿进行的。(辛顿等人 1986;鲁梅尔哈特等人 1986 年
1990-2000—自然语言处理研究的兴起和 LSTM 的诞生

一个单位的长短期记忆图(LSTM),2017 年 6 月 20 日由 fdeloche ( 来源)
在 20 世纪 90 年代,NLP 分析开始流行起来。
n 元语法在理解文本数据方面变得非常有用。
到 1997 年,长短期记忆网络 (LSTM)的概念由 Hochreiter 等人(1997)提出。
然而,在这个时期仍然缺乏计算能力来充分利用神经语言模型的最大潜力。
2003 年——第一个神经语言模型
2003 年,Bengio 等人(2003)提出了第一个前馈神经网络语言模型。
Bengio 等人(2003)的模型由一个单独的隐藏层前馈网络组成,用于预测序列的下一个单词。

本吉奥等人于 2003 年提出的第一个神经语言模型(来源)
虽然特征向量在这个时候已经存在,但是 Bengio 等人(2003)将这个概念带给了大众。
今天,我们称它们为 Worder 嵌入。😃
注意:还有很多其他的研究,比如用神经网络进行多任务学习 (Collobert & Weston,2008)以及在这十年中研究的更多。
2013 年——广泛的预训练单词嵌入的诞生(Google 的 Word2Vec)
2013 年,谷歌推出了 Word2Vec 。(米科洛夫等人,2013 年)
Mikolov 等人(2013)的目标是引入新技术,以便能够从可跨 NLP 应用程序转移的庞大语料库中学习高质量的单词嵌入。
这些技术是:
- 连续词袋(CBOW)
- 跳跃图

Word2Vec 型号。CBOW 架构基于上下文预测当前单词,而 Skip-gram 在给定当前单词的情况下预测周围的单词。作者 Mikolov 等人,2013 年(来源)
Mikolov 等人(2013)的预训练单词嵌入的结果为未来几年的大量 NLP 应用铺平了道路。
直到今天,人们仍然在各种自然语言处理应用中使用预训练的单词嵌入。
正是在这个时期,LSTMs、RNNs 和门控循环单元(GRU)也开始被广泛用于许多不同的 NLP 应用。
2014 年—斯坦福:全球向量(Glove)
Word2Vec 推出一年后,斯坦福大学的 Pennington 等人(2014)推出了手套。
Glove 是一组预训练的单词嵌入,使用不同的技术在不同的语料库上训练。
Pennington 等人(2014)发现,单词嵌入可以通过共现矩阵来学习,并证明他们的方法在单词相似性任务和命名实体识别(NER)方面优于 Word2Vec。

Pennington 等人 2014 年对单词类比任务 Glove vs CBOW vs Skip-Gram 的总体准确性(来源)
作为轶事,我相信更多的应用程序使用 Glove 而不是 Word2Vec。
2015 —回归:奇异值分解和 LSA 词嵌入&注意力模型的诞生

神经网络模型的最新趋势是似乎在单词相似性和类比检测任务方面优于传统模型。
正是在这里,研究人员 Levy 等人(2015 年)对这些趋势方法进行了一项研究,以了解它们如何与传统的统计方法相比较。
Levy 等人(2015)发现,通过适当的调整,SVD 和 LSA 等经典矩阵分解方法获得了与 Word2Vec 或 Glove 类似的结果。
他们的结论是,新旧方法之间的性能差异不明显,没有证据表明任何一种方法比其他方法有优势。
我想这里的教训是,新的闪亮的玩具并不总是比旧的(不那么闪亮的)玩具好。
注意力模型的诞生
在以前的研究中,使用 RNNs 的神经机器翻译(NMT)的问题是,如果句子太长,它们往往会“忘记”所学的内容。
这被称为“长期依赖”问题。
因此,Bahdanau 等人(2015)提出了注意机制来解决这个问题。
注意力机制复制了人类如何进行翻译任务,而不是让模型在翻译前记住整个输入序列。
该机制允许模型只关注最有助于模型正确翻译单词的单词。
精神食粮。
在开始翻译整段文字之前,你会完整地阅读整段文字吗?
当然不是。
到那时,你可能已经忘记你读过的东西了。
那么,为什么我们应该期望一个模型在开始翻译任务之前记住所有的事情?
这是创造注意力机制背后的直觉。
2016 —从神经机器翻译到注意力集中的图像字幕
在注意力机制被提出后不久,其他研究人员如徐等人(2016)开始研究如何在其他自然语言处理应用中使用注意力,如图像字幕。

注意正确对象的例子(白色表示注意的区域,下划线表示相应的单词)徐等 2016 ( 来源)
请注意模型是如何“关注”图像的正确区域来为文字添加标题的。
2017 —变形金刚的诞生

鉴于注意力机制在 NLP 应用中的成功,谷歌提出了一种新的简单网络架构,称为转换器。(瓦斯瓦尼等人,2017 年)
这是一个范式的转变,与 NLP 应用的标准构建方式不同。即使用用字嵌入初始化的 rnn、LSTMs 或 gru。
Vaswani 等人(2017 年)将变压器完全建立在注意力机制的基础上,完全摒弃了 RNNs。

瓦斯瓦尼等人于 2017 年制作的变压器模型架构(来源
Vaswani 等人(2017 年)的工作很快催生了第二年变形金刚的改变游戏规则的双向编码器表示。(德夫林等人,2018 年)
有趣的事实:BERT 目前被 Google 搜索引擎使用。这里有一个到谷歌博客的链接。
2018-今天-预训练语言模型的时代

《芝麻街》GIF”,2016 年 3 月 23 日(来源)
如前所述,在过去的两年中,NLP 模型的构建方式发生了转变。
预训练的单词嵌入已经进化为预训练的语言模型。
这里的直觉是用预训练的权重来初始化整个模型架构,而不仅仅是用预训练的单词嵌入来初始化模型的输入层。
人们发现,预先训练的语言模型只需要微调就可以在各种 NLP 任务中表现得相对较高。
这些预训练架构的一些例子是,伯特,阿尔伯特,罗伯塔,ELMO,厄尼,XLNET,GTP-2,T5 等。
到今天为止,这些模型中的一些实际上超过了 BERT。
2020 年—期末注释
看起来我们终于到达了时间线的尽头!😃

GIPHY Studios Originals 制作的快乐无比激动 GIF,2016 年 11 月 18 日(来源)
我发现这个关于 NLP 研究进展的时间表非常有趣,希望你也一样!
想象一下…
从引入预训练单词嵌入到转向预训练语言模型只用了 5 年时间。
令人惊讶的是,几十年来我们做事的方式在这个时期发生了巨大的转变。

《天堂单身汉》第六季 GIF,2019 年 8 月 7 日(来源)
似乎 NLP 上的领域还是一个相当年轻的领域。
我们还远远不能将世界知识编码到机器中,以真正理解人类的语言。
所以这绝对是一个激动人心的时代!
让我们拭目以待,看看未来会怎样!
就这样,我会在下一篇文章中看到你!
阿迪欧。
声明:这绝不是一个详尽的研究。我只是研究了我个人认为 NLP 中的关键进步。😃
LinkedIn 简介:蒂莫西·谭
自然语言处理的发展
入门
对过去十年自然语言处理的直观视觉解释

在 Unsplash 上 Thyla Jane 拍摄的照片
你所需要的只是一个关心。这是 2017 年一篇论文的名称,该论文将注意力作为一种独立的学习模型进行了介绍——这是我们现在在自然语言处理(NLP)领域占据主导地位的先驱。
变形金刚是自然语言处理领域的新锐,它们可能看起来有些抽象——但是当我们回顾自然语言处理领域过去十年的发展时,它们开始变得有意义了。
我们将讨论这些发展,看看它们是如何导致今天使用的变压器的。本文并不假设您已经理解了这些概念——我们将建立一个直观的理解,而不会过于专业。
我们将涵盖:
**Natural Language Neural Nets**
- Recurrence
- Vanishing Gradients
- Long-Short Term Memory
- Attention**Attention is All You Need**
- Self-Attention
- Multi-Head Attention
- Positional Encoding
- Transformers
自然语言神经网络
随着 Mikolov 等人在 2013 年发表的介绍 word2vec 的论文[2],NLP 真正爆发了。这引入了一种通过使用单词向量来表示单词之间的相似性和关系的方法。

这些初始单词向量包含 50-100 个值的维度。这些向量的编码机制意味着相似的单词将被分组在一起(周一、周二等),向量空间上的计算可以产生真正深刻的关系。

一个众所周知的例子是,取国王的向量,减去向量男人,加上向量女人,导致最近的数据点是王后。
重现
在 NLP 的繁荣时期,递归神经网络(RNN)迅速成为大多数语言应用程序的最爱。rnn 非常适合语言,这要感谢它们的重现。

递归神经网络单元将消耗第一个时间步,将其输出状态传递给下一个时间步【快速】——该递归过程持续特定长度的时间步(序列长度)。
这种循环允许神经网络考虑单词的顺序及其对前后单词的影响,从而更好地表达人类语言的细微差别。
虽然我们直到 2013 年才看到它们的普遍使用,但 RNNs 的概念和方法在 20 世纪 80 年代的几篇论文中都有讨论[2],[3]。
消失渐变
rnn 带来了他们的问题,主要是消失梯度问题。这些网络的循环意味着它们本质上是非常深的网络,具有许多包含输入数据和神经元权重之间的运算的点。
当计算网络的误差并使用它来更新网络权重时,我们一个接一个地通过网络更新权重。
如果更新梯度是一个小数字,我们乘以一个越来越小的数字——这意味着整个网络要么需要很长时间来训练,要么根本不起作用。
另一方面,如果我们的权重循环值太高,我们就会遭遇爆炸梯度问题。这里,网络权重将振荡,而不学习任何有意义的表示。
长短期记忆
随着长短期记忆(LSTM)单元的引入,消失梯度问题得到了解决。

LSTM 单位引入了一种更稳定的信息通道——细胞状态,如上图黑色所示。
LSTMs 引入了一个额外的信息流,沿着时间状态链,通过“门”控制最少数量的转换。

单元状态允许信息以较少的转换从早期状态传递到后期状态。
这允许通过允许来自序列中更早的信息被保留并应用于序列中更晚的状态来学习长期依赖性。
注意力
很快,循环的编码器-解码器模型被附加的隐藏状态和神经网络层所补充——这些产生了注意力机制。

注意编解码器 LSTMs。
添加编码器-解码器网络允许模型的输出层不仅接收 RNN 单元的最终状态,而且还接收来自输入层的每个状态的信息,从而创建一种“注意”机制。

英法翻译任务中编码和解码神经元间的注意。图像源[3]。
使用这种方法,我们发现编码器和解码器状态之间的相似性将导致更高的权重,产生类似于上面法语翻译图像的结果。
对于这种编码器-解码器实现,在关注操作中使用了三个张量,即查询、关键字和值。在每个时间步长,从解码器的隐藏状态中提取查询,评估该查询和键值张量之间的对齐,以产生上下文向量。

然后,上下文向量被传回解码器,用于产生该时间步长的预测。对于解码器空间中的每个时间步长,重复该过程。
你需要的只是关注
正如我们在简介中所说,这一切都始于 2017 年的“你只需要关注”论文[5]。你可能已经猜到了,这篇论文介绍了我们不需要在注意力旁边使用这些复杂的卷积或递归神经网络的想法——事实上,注意力就是你所需要的全部。
自我关注
自我关注是实现这一功能的关键因素。这意味着之前的查询来自输出解码器,而现在是直接从输入值以及 T2 K ey 和 T4 V T5 值产生。

用两个略有不同的短语自我关注。通过将累(左)改为宽(右),注意力从动物转移到街道。来源[3]。
因为 Q uery、 K ey 和Vvalue 都是由输入产生的,所以我们能够对同一输入序列的不同部分之间的对齐进行编码。如果我们取上面的图像,我们可以看到,将最后一个词从累改为宽将注意力焦点从动物转移到街道。
这允许注意力机制对输入数据中所有单词之间的关系进行编码。
多头注意力
注意力机制的下一个重大变化是增加了多个注意力头——本质上是并行执行的许多自我注意力操作,并用不同的权重进行初始化。

多头注意是指并行处理多个注意‘头’。这些多个头的输出被连接在一起。
在没有多头关注的情况下,A. Vaswani 等人的 transformer 模型实际上比它的许多前辈表现得更差[5]。
并行机制允许模型表示相同序列的几个子空间。这些不同程度的注意力然后被一个线性单元连接和处理。
位置编码
变压器模型的输入不像 RNNs 那样是顺序的。在过去,正是这种顺序操作允许我们考虑单词的位置和顺序。
为了保持单词的位置信息,在进入注意机制之前,向单词嵌入添加位置编码。
《注意力就是你所需要的》一文中采用的方法是为嵌入维中的每一维生成不同的正弦函数。
还记得我们之前说过 word2vec 引入了用 50 到 100 维的向量来表示单词的概念吗?这里,在 Vaswani 等人的论文中,他们使用了相同的概念,但是表示了单词的位置。

交替位置编码值。使用字位置 pos ,嵌入尺寸 i ,嵌入尺寸数量 d_model 。
但是,这次不是使用 ML 模型计算矢量值,而是使用修改后的正弦函数计算矢量值。

正弦后接余弦函数。这种正弦-余弦-正弦的交替模式对于嵌入索引中的每个增量持续。
向量的每个索引被分配一个交替的正弦-余弦-正弦函数(索引 0 是正弦,索引 1 是余弦)。接下来,随着索引值从零向 d(嵌入维数)增加,正弦函数的频率降低。

使用总嵌入维数为 20 的前五个嵌入指数的正弦函数。嵌入索引位置显示在图例中。
我们可以从上面得到同样难以控制的正弦曲线,加上在 A. Vaswani 等人的研究中使用的 512 嵌入维数。用纸将这些绘制到更容易理解的热图上:

我们可以在较低的嵌入维度中看到较高的频率(左图),它随着嵌入维度的增加而降低。在第 24 维附近,频率降低了很多,以至于我们在剩余的(交替的)正弦余弦波中不再看到任何变化。
这些位置编码然后被添加到单词嵌入中。
顺便提一下,这意味着单词嵌入维度和位置编码维度必须匹配。
变形金刚

A. Vaswani 等人的变压器架构。改编自同一篇论文。
注意力模型的这些变化产生了世界上第一个变压器。
除了已经讨论过的单词嵌入、位置编码和多头自我关注操作,这个模型相当容易理解。
我们有加法和归一化层,我们简单地将两个矩阵相加,然后归一化它们。还有普通的前馈神经网络。
最后,我们将张量输出到线性层。这是一个完全连接的神经网络,它映射到一个 logits 向量——一个大向量,其中每个索引映射到一个特定的单词,其中包含的值是每个相应单词的概率。
然后,softmax 函数输出最高概率索引,该索引映射到我们的最高概率单词。
这就是全部(我承认,这是很多)。
NLP 中目前最先进的技术仍然使用变压器,尽管有一些奇怪而奇妙的修改和添加。尽管如此,核心概念仍然是相同的,即使像 GPT-3 和伯特模型。
我相信,NLP 的未来将和过去一样多样化,我们将在未来几年看到一些真正迷人的、坦率地说是改变世界的进步——这是一个非常令人兴奋的领域。
我希望这篇文章能够帮助您更好地理解 transformer 模型的基础知识,以及它们为什么如此强大。如果你想了解更多,我在 YouTube 上发布了编程/ML 视频!
如果您有任何问题、想法或建议,请通过 Twitter 或在下面的评论中联系我们。
感谢阅读!
参考
[1] T. Mikolov 等人,向量空间中单词表示的有效估计 (2013),ICLR
[2] D. Rumelhart 等人,通过错误传播学习内部表征 (1985),ICS 8504
[3] M. Jordan,串行顺序:并行分布式处理方法 (1986),ICS 8604
[4] D. Bahdanau 等人,通过联合学习对齐和翻译的神经机器翻译 (2015),ICLR
[5] A. Vaswani 等人,注意力是你所需要的全部 (2017),NeurIPS
*所有图片均由作者提供,除非另有说明
YOLO-YOLO 版本 1 的演变
YOLO 的起源——“你只看一次”物体探测

来源: 你只看一次:Joseph Redmon 等人的统一实时物体检测
YOLO(YouOonlyLookOnce)是最流行的对象检测卷积神经网络(CNN)之一。Joseph Redmon 等人在 2015 年发表了他们的第一篇 YOLO 论文之后,随后的版本分别由他们在 2016 、 2017 和 Alexey Bochkovskiy 在 2020 发表。本文是一系列文章中的第一篇,概述了 YOLO CNN 是如何从第一个版本发展到最新版本的。
1.YOLO v1 —动机:
在 YOLO 发明之前,诸如 R-CNN 的对象检测器 CNN 首先使用区域提议网络(RPNs)来在输入图像上生成边界框提议,然后在边界框上运行分类器,最后应用后处理来消除重复检测以及细化边界框。R-CNN 网络的各个阶段必须单独训练。R-CNN 网络很难优化,而且速度很慢。
YOLO 的创造者被激励去设计一个单级 CNN,它可以被端到端地训练,易于优化并且是实时的。
2.YOLO v1 —概念设计:

图 1: YOLO 版本 1 概念设计(来源: 你只看一次:Joseph Redmon 等人的统一实时物体检测)
如图 1 左图所示,YOLO 将输入图像分成 S×S 网格单元。如图 1 中上图所示,每个网格单元预测 B 个边界框和一个“对象性”得分 P(Object ),表示网格单元是否包含对象。如图 1 中下部图像所示,每个网格单元还预测网格单元包含的对象所属类的条件概率 P(Class | Object)。
对于每个边界框,YOLO 预测了五个参数——x,y,w,h 和一个置信度得分。边界框相对于网格单元的中心由坐标 (x,y) 表示。 x 和 y 的值介于 0 和 1 之间。边界框的宽度 w 和高度 h 被预测为整个图像的宽度和高度的一部分。所以它们的值在 0 和 1 之间。置信度得分指示边界框是否具有对象以及边界框有多精确。如果边界框没有对象,则置信度得分为零。如果边界框具有对象,则置信度得分等于预测边界框和基础真值的并集上的交集(IoU)。因此,对于每个网格单元,YOLO 预测了 B×5 个参数。
对于每个网格单元,YOLO 预测 C 类概率。这些类别概率是基于网格单元中存在的对象的条件。即使格网单元具有 B 边界框,YOLO 也只预测每个格网单元的一组 C 类概率。因此,对于每个网格单元,YOLO 预测 C+B×5 个参数。
图像的总预测张量= S x S x (C + B x 5)。对于 PASCAL VOC 数据集,YOLO 使用 S = 7、B = 2 和 C = 20。因此,帕斯卡 VOC 的最终 YOLO 预测是 7×7 ×( 20+5×2)= 7×7×30 张量。
最后,YOLO 版本 1 应用非最大值抑制(NMS)和阈值来报告最终预测,如图 1 右图所示。
3.YOLO v1 — CNN 设计:

图 2: YOLO 第一版 CNN ( 来源: 你只看一次:Joseph Redmon 等人的统一实时物体检测)
YOLO 版本 1 的 CNN 如图 2 所示。它有 24 个卷积层,作为特征提取器。接着是两个完全连接的层,负责对象的分类和边界框的回归。最终输出是一个 7 x 7 x 30 的张量。YOLO CNN 是一个简单的单路 CNN,类似于 VGG19 。YOLO 使用 1x1 卷积,然后是 3x3 卷积,灵感来自谷歌的盗梦空间版本 1 CNN。泄漏 ReLU 激活用于除最后一层之外的所有层。最后一层使用线性激活函数。
4.YOLO v1 —损失设计:
平方和误差是 YOLO 损失设计的基础。因为多个网格单元不包含任何对象,并且它们的置信度得分为零。它们压倒了包含对象的几个单元的梯度。为了避免这种导致训练发散和模型不稳定的过度控制,YOLO 增加了来自包含对象的边界框的预测的权重( λ coord = 5),并减少了权重( λ noobj = 0。 5)用于不包含任何对象的边界框的预测。

图 3: YOLO v1 丢失部分 1 —包围盒中心坐标(来源: 你只看一次:Joseph Redmon 等人的统一实时物体检测)
图 3 示出了 YOLO 损失的第一部分,其计算边界框中心坐标预测中的误差。损失函数仅惩罚边界框中心坐标的误差,如果该预测器负责地面真实框的话。

图 4: YOLO v1 丢失部分 2——包围盒宽度和高度(来源: 你只看一次:Joseph Redmon 等人的统一实时物体检测)
图 4 示出了 YOLO 损失的第二部分,其计算边界框宽度和高度的预测误差。如果小边界框与大边界框的预测误差大小相同,则它们会产生相同的损失。但是相同大小的误差对于小边界框比大边界框更“错误”。因此,这些值的平方根用于计算损失。因为宽度和高度都在 0 和 1 之间,所以它们的平方根对于较小的值比较大的值增加更多的差异。损失函数仅惩罚边界框的宽度和高度误差,如果该预测值负责地面真实框的话。

图 5: YOLO v1 损失部分 3-物体置信度得分(来源: 你只看一次:约瑟夫·雷德蒙等人的统一实时物体检测)
图 5 示出了 YOLO 损失的第三部分,其计算具有对象的边界框的对象置信度得分的预测误差。损失函数仅惩罚对象置信度误差,如果该预测器负责基本事实框的话。

图 6: YOLO v1 损失第 4 部分——无对象置信度得分。(来源: 你只看一次:Joseph Redmon 等人的统一实时物体检测)
图 6 示出了 YOLO 损失的第四部分,其计算没有对象的边界框的对象置信度得分的预测误差。损失函数仅惩罚对象置信度误差,如果该预测器负责基本事实框的话。

图 7: YOLO v1 丢失部分 5 类概率(来源: 你只看一次:Joseph Redmon 等人的统一实时物体检测)
图 7 示出了 YOLO 损失的第五部分,其计算具有对象的网格单元的类概率预测中的误差。如果网格单元中存在对象,损失函数只惩罚类概率错误。
5.YOLO 第一版—结果:

图 8: YOLO v1 —结果(来源: 你只看一次:Joseph Redmon 等人的统一实时对象检测)
YOLO v1 在 PASCAL VOC 2007 数据集上的结果如图 8 所示。YOLO 实现了 45 FPS 和 63.4 %的 mAP,与另一种实时对象检测器 DPM 相比显著提高。尽管速度更快的 R-CNN VGG-16 的 mAP 更高,为 73.2%,但其速度相当慢,为 7 FPS。
6.YOLO 第一版—限制:
- YOLO 很难发现成群出现的小物体。
- YOLO 在探测具有不寻常长宽比的物体时有困难。
- 与快速的 R-CNN 相比,YOLO 犯了更多的定位错误。
7.参考资料:
[1] J. Redmon,S. Divvala,R. Girshick 和 a .法尔哈迪,你只看一次:统一的实时对象检测 (2015),arxiv.org
[2] R. Girshick,J. Donahue,T.Darrell 和 J. Malik,用于精确对象检测和语义分割的丰富特征层次 (2013),arxiv.org
[3] K. Simnoyan 和 A. Zisserman,用于大规模图像识别的甚深卷积网络 (2014),arxiv.org
[4] C .塞格迪,w .刘,y .贾,p .塞尔马内,s .里德,d .安盖洛夫,d .埃汉,v .万霍克和 a .拉宾诺维奇,用卷积深化 (2014)
强化学习的进化策略
只用蛮力就解决了著名的倒立摆问题。

丹尼尔·佩莱斯·杜克在 Unsplash 上拍摄的照片
在上一篇文章中,我们给自己设定的目标是通过优先化的经验回放来优化深度 Q-Learning,换句话说,为算法提供一点帮助来判断什么是重要的,什么是不应该记住的。在大多数全球范围内,根据当前的技术成就,在人工干预的帮助下,算法往往表现更好。以图像识别为例,假设你要对苹果和香蕉进行分类。有了香蕉是黄色的先验知识,你的算法肯定会比它自己学习更准确。这也可以通过过度设计一组超参数来解释,这些超参数只会优化非常具体的任务。至于强化学习,证明算法可以通用化的一个方法就是用多种环境来测试,来求解。这正是为什么 OpenAI 环境被制造出来,允许研究人员通过提供一个简单的接口来测试他们的算法,使我们能够非常容易地在环境之间转换。
现在,关于优先体验重放,该出版物表明,它可以在大多数环境中很好地推广,但这一点点人工干预帮助在我们的情况下没有好处。毕竟,也许这个环境确实需要更多的随机性才能被解决。在深度 Q 学习的情况下,随机性是通过使用一个ε贪婪策略来创建的,该策略是“我们不不时地采取最优化的行动,看看会发生什么,怎么样”。这也叫探索。但是这实际上是一种非常苍白的随机行为,因为它是基于随机(概率)策略的。呃。在这种情况下,如何使它完全随机?

强化学习随机性烹饪食谱:
- 第一步:用一个有一组权重的神经网络,我们用它来把一个输入状态转化成一个相应的动作。通过在这个神经网络的指导下采取连续的行动,我们收集并累加每个连续的奖励,直到体验完成。
- 步骤 2:现在添加随机性:从这组权重中,通过将随机噪声添加到原始权重参数中来生成另一组权重,也就是说,使用采样分布(例如高斯分布)对它们进行一点修改。尝试新的体验并收集总奖励。
- 第三步:重复随机抽样的权重参数,直到你达到理想的分数。
这是你能做的最随意的事情。拉出一个随机权重的随机神经网络,看看是否可行,如果不行就再试一次。事实是,这不太可能行得通。(或者至少在合理的时间内工作)。然而,最近几年发表的一些非常有前途的论文,在让类人机器人学习如何走路等任务中提供了非常有竞争力的结果,离应用这一非常基本的烹饪食谱不远了。
我们开始吧。现在想象一下,不是围绕相同的初始权重集进行采样,而是在每次采样迭代中,将您的奖励与前一个权重集的奖励进行比较。如果回报更好,这意味着你的神经网络对什么是最优策略有更好的想法。现在,您可以从这里开始,对另一组砝码进行采样。这个过程叫做爬山。
这个类比非常简单,你试图优化你的总回报(位于山顶),你正在采取连续的步骤。如果你的一步让你更接近顶峰,那么你就非常自信地从那里开始下一步。否则,你回到上一步,尝试另一个方向。它实际上看起来非常像梯度上升,通过“攀爬”您试图优化的函数来优化函数。区别在于神经网络更新。在爬山中,不使用反向传播来更新权重,而只使用随机采样。
爬山实际上属于一组叫做黑盒优化算法的算法。

我们不知道我们试图优化的函数到底是什么,我们只能给它输入并观察一个结果。基于输出,我们能够修改我们的输入,以尝试达到最佳结果值。实际上,呃,这听起来很熟悉!事实上,强化学习算法也依赖于一个黑盒,因为它们基于一个环境,该环境为代理人采取的每一步(输入)提供奖励(输出)。例如,当你试图教一个人形机器人如何行走时,你对你试图行动的模型的运动学和动力学完全没有先验知识,甚至不知道重力意味着什么!这是一个相当黑的盒子,不是吗?如下图所示,我们试图优化的是我们自己对环境的近似函数。

在深度 Q 网络的情况下,当我们执行反向传播时,我们有我们试图优化的函数的概念,所以在某种意义上,只有环境被认为是黑盒。至于爬山,我们盲目地修改一组权重,而不知道如何使用这些权重,这可以被认为是一个黑盒。
现在,让我们爬上一些山,看看这将如何实现。我们从另一个叫做 Cart Pole 的环境开始,它基本上是一个倒立摆。这通常是一个非常好的测试算法和想法的环境,因为它很容易解决,没有特别的局部最小值。Cart pole 也很受欢迎,因为它也用于经典控制理论(提供解析解)。
让我们先看看现实生活中的倒立摆是什么样子,这里由 Naver Labs 的一个令人印象深刻的机器人来平衡:
现在让我们试着从我们的健身房环境中平衡车杆。在这个实现中,我们假设提供了一个代理(github 上的代码),它可以评估完整剧集的报酬。
很简单不是吗?我们实际上做了一个小小的改进,而不是使用所有的奖励来计算新的权重,我们只使用其中的一小部分,称为“精英”权重,即提供最佳奖励的权重。我们也可以更加贪婪,只取回报最高的权重,但这样会不够健壮,也不能很好地处理局部最小值。另一方面,用所有结果计算新的权重更健壮,但是也更慢。使用结果的一部分代表了鲁棒性和快速收敛之间的某种平衡。

爬山结果
该算法可以用大约 470 秒的处理时间在 104 次迭代中求解 cart 极点环境。让我们享受观看训练有素的代理人执行他的任务。肯定没有人形机械手臂平衡重量好看,但这已经很了不起了!

现在爬山是一种可能的黑盒算法实现。在这篇论文中,open ai 团队(也是 OpenAI gym 的制造商)推出了另一个版本,他们说这个版本可以解决复杂的 RL 问题,例如 Mujoco 运动任务或 Atari 游戏集合。他们还声称,他们可以比最有效的 RL 算法更快地解决这些任务,至少快 10 倍。让我们看看这种成功背后的算法是什么:

进化策略
抛开数学符号不谈,这里的内容与爬山算法非常相似。首先通过高斯分布随机抽样生成权重集,评估每组权重的回报,并使用所有结果更新新的权重。主要区别在于更新,而爬山只是平均最好的权重,进化策略将使用一个更新率缓慢地向最佳方向移动。与所有 RL 算法一样,这确实意味着避免直接陷入局部最小值并增加鲁棒性。除此之外,这很像爬山。而认为能够比最复杂的 RL 算法执行得更好?呃。关键词其实就在快照的标题里:并行化。
并行化是将处理任务分开,并同时执行它们。比方说,当您想要评估每组权重的奖励时,您可以同时评估所有权重,然后在所有权重完成后收集结果。如果只使用一台计算机,当然这将要求它具有难以置信的强大功能,但这里的技巧是,计算不仅限于一台机器。并行化可以通过与其他计算机共享计算任务来完成。例如,OpenAI 团队表示,为了教会人形机器人行走,他们在 80 台机器上使用了1440 个 CPU。
如果你想获得不错的结果,那么现在让任务并行化来解决 RL 问题是必须的。例如,相对著名的 A3C 算法的目标是利用并行计算,这是作者所谓的深度 RL 异步方法的一部分。进化策略(es)的不同之处在于,ES 完全利用了并行化,尽管它是一段简单得多的代码,但堆叠越来越多的计算机将会产生更好的结果。
即便如此,我(可能还有你)手头没有 80 台计算机,尝试运行这种带有异步计算的算法仍然很有趣,以便更好地了解它实际上是如何工作的,并看看我们是否能超越爬山性能。
为了尝试并行化进化策略算法,我们需要深入研究 Python 中的并行计算以及执行多线程的不同方式。幸运的是,我们可以依靠一些非常好的文章,这些文章详细介绍了我们正在寻找的东西,目前是关于哪个库最适合我们的指南,其中有一些代码片段教我们如何使用它。(实际上这应该是本文的一部分,但是嘘)。
在这里插入 Python 中的多线程分析 < < < < <
使用新获得的知识,我们可以尝试并行化进化策略算法。
我们实现的基础层与前面介绍的相同,它依赖于一个代理,该代理可以评估给定的一组权重的总回报。代理只需对用指定权重构建的神经网络执行正向传递,以找出每一步要采取的行动,并总结健身房环境提供的奖励。
我们现在想通过为我们的案例选择正确的库来利用我们的线程知识。我们希望通过并行化繁重的计算来优化进化策略的收敛时间。最重要的是,我们希望将来能够使用多个独立计算机的内核。选择是显而易见的,我们想用多处理库。
可以看到,使用多处理时,一些数据类型无法成功序列化,代理就是这种情况,可能是由于 pytorch 数据类型的存在。为了解决这个问题,代理被定义为全局变量,以便它们仍然可以从线程访问,这不是一个好的设计,并且不能用于在多台计算机之间共享计算的情况。至于测试,这是目前测量并行计算效率的主要方法。该算法的基础如下:在每次迭代中,为您想要使用的每个并行代理启动一个线程。然后在每个线程中采样一组权重并调用 evaluate 函数。收集每个线程产生的所有奖励,并更新权重。请注意,更新需要奖励和采样权重,但线程只返回奖励。这是使用种子技巧:np.random 实际上并没有那么随机,如果多次调用 np.random.randn,然后重置种子并重复,它将提供完全相同的结果。利用这一点,我们可以只返回种子,然后在需要时重新创建权重,而不是返回权重集(这对复杂的神经网络来说可能是巨大的)。对于一些应用来说,不串行化/解串行化权重的时间增益是必然的。下面是这个实现的样子:
运行这段代码有一个问题。多处理 apply_async 在第二次迭代开始时被阻塞。似乎某些适合多重处理的内部锁正在阻塞计算。由于第一次迭代是成功的,我们可以猜测第一次迭代的一些残余会阻碍下一次迭代的开始。可能是当 mp 的对象超出范围时。无法正确销毁池()句柄。
一种可能的解释是,多重处理在内部使用“fork”方法创建线程,该方法复制线程环境,而不是“繁殖”重新评估“所有变量”。可能不是所有的数据类型(和底层数据类型)都有一个定义良好的复制构造函数,这会导致死锁。那用“产卵”法怎么样?由于多处理重新评估所有变量,健身房环境以及代理本身确实受到相同的处理,这非常耗时(至少比调用 sample_reward 函数本身多得多)。即使这种方法仍然可行,但它肯定不能让我们达到固定的目标,提高进化策略算法的计算效率。
那现在怎么办?多处理似乎不是一个可行的替代方案,唯一的其他解决方案是使用线程池库,它受到全局解释器锁(GIL)的限制。我们仍然可以使用该库来验证性能水平,看看与基本的顺序方法相比是否有所提高。在这两种情况下,我们使用 50 个代理,它们能够为随机抽样的一组重量生成总报酬:

该算法一直运行到平均奖励达到 195。在这两种情况下,行为看起来相似,并且环境通过等量的情节得到解决。在此之前,一切看起来都很好。算法是相同的,唯一的区别是计算的并行化。然而,计算时间是不同的,在使用线程池执行器库的情况下,计算时间实际上更长。这与不同线程方法的基准测试结果相呼应。我们只是确认了预期的结果。
我们现在发现自己陷入了一个僵局,我们首选的线程库没有像预期的那样工作,其他方法实际上比顺序方法要慢。我们处理线程的方式需要有所不同。如果我们能在体育馆环境中直接并行化计算,事情会简单得多…
你猜怎么着?这个接口有..算是存在的。有一个名为 VecEnv 的接口,它实际上是 openai 健身房环境的数组。实际上,这听起来与我们之前采用的方法非常相似。除了这个 VecEnv 充当传统 gym 环境的包装器,并允许您执行“step”操作的并行计算。在下面的 evaluate 函数实现示例中,“step”函数现在接受一组动作,并返回一组奖励和新状态:
在我们将一集的奖励累积过程并行化之前,我们在这里称每个“步骤”为多线程。好处是我们在已经执行了神经网络前向传递之后调用了一个线程。这意味着应该避免前一节中遇到的与 pytorch 数据类型和多重处理相关的问题。让我们检查一下性能结果:

当我们期待计算时间有巨大的改进时,实际上却发生了相反的情况。尽管与之前的 400 次迭代相比,该算法使用了大约 500 次迭代就收敛了,但它需要多花大约三倍的时间来计算。
现在,让我们试着拆开“步进”函数,从算法的其余部分分别测量性能。
我们创建了两个代理,一个实现通常的“步进”功能,将一个动作作为参数并返回新的状态和获得的奖励,而另一个使用 VecEnv(环境向量)并实现“步进”功能,将一组动作作为参数并输出一组状态和奖励。我们重复调用“步骤”的过程固定次数,并比较结果:

我们知道,VecEnv 通过实现多处理来执行线程,这是一种正确的方法,应该可以提供显著的计算改进。然而,我们观察到,即使在线程数量等于 PC 内核数量(本例中为 4 个)的最有利情况下,性能仍然落后于简单的顺序情况。
这种性能缺乏的一个原因可能是环境太简单,无法解决:“step”函数只需要很少的时间就可以返回,而多处理确实需要序列化和反序列化(我们不知道数量,因为它隐藏在 VecEnv 实现中)。很可能在更复杂的环境中,当仿人机器人学习行走时,“步进”功能将需要更多的计算能力,从而充分利用线程实现。
结论:
- 虽然我们最初计划改进我们的月球着陆器,但我们选择先解决倒立摆问题,作为测试实施效率的简单方法。
- 我们可以观察到,由于 Pytorch 的原因,将体验奖励的完整评估分离到不同线程中的简单线程实现无法工作。
- 我们改用线程池执行器,并证明这种方法仍然受到 GIL(全局解释器锁)的限制。
- 最后,我们尝试了 gym 环境的 VecEnv 包装器,它提供了一个使用多线程执行“步骤”的接口。然而,这种方法似乎并不成功,可能是因为我们的环境过于简单,无法利用多线程方法。
待完成:
- 在更复杂的环境中尝试该算法(例如 Mujoco 环境)。
Github 回购:https://github.com/Guillaume-Cr/evolution_strategies
进化决策树:当机器学习从生物学中汲取灵感时

发现进化决策树
随着时间的推移,我们在生物学或生命科学方面的知识大幅增加,它已经成为许多寻求解决挑战性问题和开发创造性创新的工程师的巨大灵感来源。
以日本高速列车 新干线 为例,它是世界上最快的列车之一,时速超过 300 公里。在构思过程中,工程师们遇到了严重的困难,因为列车前方空气置换产生的大量噪音,甚至会对几个隧道造成结构性破坏。
为了解决这个问题,他们求助于一个不太可能的来源,翠鸟!这种鸟有一个细长的喙,这使他能够潜入水中以最小的水花猎食。
因此,通过以鸟的形象重新设计火车,工程师们不仅能够解决最初的问题,还能将火车的电力消耗降低 15%,并将速度提高 10%。


图 1 —日本高速列车新干线、 来源
利用生物学中的知识作为灵感来源,在机器学习中也是可能的。
内容
在本文中,我将重点介绍一个例子: 进化决策树。
这些分类器使用进化算法,该算法依赖于受生物进化启发的机制来构建更健壮、更高效的决策树。
阅读本文后,您将了解到:
- 什么是决策树?
- 如何使用进化算法构建决策树?
- 与其他分类器相比,进化决策树表现如何?
资料组
为了说明整篇文章中将要讨论的概念,我将依赖一个数据集,该数据集收集了航空公司乘客满意度调查的结果。关于数据集的更多信息可在这里找到。
目标是预测客户对航空公司服务满意的可能性。从公司决策的角度来看,这样的研究是至关重要的。它允许任何提供商品或服务的公司不仅定义其产品的哪些方面需要改进,而且定义改进的程度和迫切程度。
事不宜迟,让我们从回顾决策树的基础开始。
1。什么是决策树?
决策树 指一种依靠流程图的树状结构的分类器。底层模型通过学习从数据特征中推断出的简单决策规则来对观察结果进行分类。
下图提供了一个决策树的例子。已经使用 Scikit Learn 决策树模块对其进行了航空公司乘客满意度调查培训。

图 2—决策树示例
决策树显示,对于商务旅行,客户满意度的主要因素是在线登机:简单高效的在线登机增加了客户满意的可能性。这也凸显了机上服务 wifi 质量的重要性。
它们已经被广泛用于分类任务,因为它们提供了许多优点:
- 类似人类推理的可理解和可解释的性质;
- 处理数字和分类数据的能力;
- 分层分解允许更好地使用可用变量。
大多数用于诱导决策树的算法依赖于贪婪的自顶向下递归划分策略来增长树。
代表树的根节点的源集合根据特定的规则被分成子集(子节点)。对每个派生的子集重复该过程,直到节点处的子集具有目标变量的所有相同值,或者分裂不会给预测增加任何值。
用于确定在节点和分割中生成测试的最佳方式的度量因算法而异。最常见的有 信息增益 (或 熵 )和 基尼杂质 。它们是杂质度量,意味着当一个节点的所有样本属于同一类别时,它们等于 0,并且当我们具有均匀的类别分布时(即,当该节点的所有类别具有相等的概率时),它们达到最大值。更多信息,可以阅读这篇文章。
然而,这种策略有两个主要缺点:
- 它可能导致次优解决方案;
- 它会生成过于复杂的树,这些树不能很好地从训练数据中概括出来,从而导致过度拟合的问题。
已经提出了几种技术来克服这些问题:
- 剪枝技术:首先,完全构建决策树,即直到一个叶子中的所有实例属于同一类。然后,通过移除“无关紧要的”节点或子树来减小树的大小。
- 集合树:不同的树被构建,最终的分类通过特定的规则给出,在大多数情况下是投票方案。请注意,这导致决策树的可理解性方面的损失。
因此,有必要探索生成模型树的其他方法。在这种背景下,进化算法(EAs) 最近获得了强烈的兴趣。
它们在候选解的空间中执行稳健的全局搜索,而不是局部搜索。因此,与贪婪方法相比,进化算法能够更好地处理属性交互。
让我们来看看它们是如何工作的。
2.如何用进化算法构建决策树?
进化算法是搜索试探法,使用受自然生物进化过程启发的机制。
在这个范例中,群体中的每个“个体”代表一个给定问题的候选解决方案。每个个体由一个适应值评估,该适应值测量他作为解决方案的质量。因此,第一种群通常被随机初始化,并向搜索空间的更好区域进化。
在每一代,选择过程确保具有低适应值的最佳个体具有更高的繁殖概率。
此外,通过受遗传学启发的操作,群体经历特异性,例如:
- 交叉和突变,或重组机制:来自两个个体的信息被混合并传递给它们的后代;
- 突变:微小的随机变化适用于个体。
该过程反复重复,直到满足停止标准为止。选择最合适的个体代表作为解决方案。

基于 EA 的决策树为普通技术带来了一个有趣的替代方案,原因如下:
- 作为随机搜索技术,它们有助于避免贪婪的、自上而下的递归划分策略可能导致的局部极小值;
- 决策树的可理解性与集成方法相反。
- 它不仅可以优化一个指标,还可以将不同的目标整合到适应值中。

2.1.原始群体
在进化决策树,中,个体是树。第一种群由随机生成的树组成。
随机树可以按如下方式生成:
从一个根节点和两个孩子开始,该算法以预定义的概率 p. 决定孩子是分裂还是该节点成为终端节点(叶子)
- 如果子节点被拆分,算法会随机选择属性并拆分值。
- 如果该节点成为终端节点(叶),则分配一个随机的类标签。
2.2.健康
分类器的目标是为新的未标记数据获得最佳预测准确性。决策树分类器还必须控制最终树的大小,因为小树会导致欠拟合问题,而复杂树会导致过拟合问题。
因此,可以定义一个适应度函数来平衡这两个标准:
适应度= α1 f1 + α2 f2
其中:
- f1 是训练集上的准确度;
- f2 根据树的深度惩罚个体的大小;
- α1 和α2 是要选择的参数。
2.3.选择
在选择将被用来创造下一代的双亲时,有几种选择。
最常见的有以下几种:
- 适应度比例选择,或轮盘赌选择:每个个体相对于群体的适应度用于分配选择的概率。
- 锦标赛选择:通过从群体中随机选择的一组个体中选择具有最高适应性的个体来选择父母。
- 精英主义:具有最高适应值的个体被直接带入下一代,这确保了保留最成功的个体。
请注意,一个个体可以被选择多次,这使他能够将其基因传播给更多的孩子。
2.4.交叉
交叉子代是通过组合当前父代的父代对获得的。
首先,选择两个个体成为父母。然后,在两棵树中随机选择一个节点。因此,通过用来自第二个亲本的子树替换来自第一个亲本的子树来形成新的个体(后代)。

图 3—交叉
2.5.变化
突变是指在一个群体的个体中做出的小的随机选择。这对于确保遗传多样性和使遗传算法能够搜索更广阔的空间是至关重要的。
在决策树的上下文中,可以通过随机改变一个属性,拆分随机选择的一个节点的值来实现。

图 4 —突变
2.6.停止标准
如果群体中最佳个体的适应度在固定数量的代期间没有提高,则认为该算法已经收敛。
如果收敛缓慢,为了限制计算时间,预先设置最大代数。
3。与其他分类器相比,进化决策树的表现如何?
进化决策树看起来很吸引人,但是与通常的机器学习算法相比,它的性能如何呢?
3.1.一个简单的实验
为了了解它的效率,我实现了它,并在包含航空公司乘客满意度调查的数据集上进行了训练。
目标是了解哪些因素会带来高水平的客户满意度。在这种情况下,有一个简单但可靠的模型来解释客户满意或不满意的途径是至关重要的。

Ross Parmly 在 Unsplash 上拍摄的照片
关于数据集
数据集很大,超过 100k 行。
- 它包含关于客户及其旅行的事实信息:客户性别、年龄、客户类型(忠诚或不忠诚的客户)、旅行类型(个人或商务旅行)、航班等级(商务、经济、经济加)和飞行距离。
- 它还包含以下服务的客户满意度:机上 wifi 服务、出发/到达时间便利性、在线预订便利性、登机口位置、食品和饮料、在线登机、座位舒适度、机上娱乐、机上服务、腿部空间服务、行李搬运、值机服务、机上服务、清洁度。
因此,目标变量是客户满意度,可以是“满意”或“中性或不满意”。
方法论
下面是我遵循的步骤的快速总结:
- 数据预处理:将分类变量转换为指标变量。将数据集分成随机的训练和测试子集。
- 建模和测试:在训练子集上考虑每个模型的训练,并在验证子集上测量。
- 车型性能对比。
我选择将进化决策树(EDT) 方法与仅基于树的模型、决策树 (DT)、和随机森林(RF)、进行比较,以有限的树深度 3 作为约束。我还将 EDT 的总体规模值和 RF 的估计数设置为 10,以便能够在合理的计算时间内以一致的方式比较它们。
结果
这是结果

图 5—满意的客户数量和不满意的客户数量

表 1—DT 模型的分类报告

表 2 —射频模型的分类报告

表 EDT 模型的分类报告

图 6-三个模型的 ROC 曲线和 AUC
在这种设置下, EDT 的性能与另外两种机器学习算法非常相似。
然而, EDT 模型因其提供单一决策树的能力而脱颖而出:
- 这可以可视化,与 RF 模型相反,在该模型中,多个决策树被聚合,
- 与简单的 DT 模型相反,这是健壮的,因为它是种群中最好的树。
下面是在最大深度设置为 2 的情况下训练算法时,在 EDT 群体中的最佳决策树的表示。

图 EDT 最佳决策树的表示
3.2.EDT 方法的更一般的实验验证
与其他机器学习算法相比,上面进行的实验当然不足以评估进化决策树的性能和可靠性。
因为它仅使用一个数据集,所以它没有探索所有的可能性,例如目标的类的数量的影响、特征和观察的数量的影响等。
在[ 2 ]中,作者使用真实的 UCI 数据集,比较了 EDT 方法与其他机器学习方法的性能。
让我们来探究这篇文章的发现。
关于数据集
下表简要描述了所使用的数据集:

表 4—数据集的特征
如您所见,数据集在观测值、要素和目标类的数量方面有很大差异。
最困难的数据集当然是第一个数据集,因为它提供了大量的类和有限的观察值。
方法论
以下是作者用来评估 EDT 模型与更“经典”机器学习算法相比的性能的方法的主要信息:
- EDT 模型已经用以下超参数进行了训练:500 代的数量,400 的种群规模,0.6/0.4 的 ac 交叉/变异概率,具有精英主义的随机均匀选择方法。
- 使用 5x2 交叉验证测量了模型的性能。
结果

表 5-依赖于数据集的模型精度
正如作者所指出的,从上表中可以得出 2 个想法:
- 基于树的算法往往在几乎所有情况下都优于其他机器学习算法。这可以用决策树自然更能选择最重要的特征这一事实来解释。此外,基于规则的模型更适合特定的数据集,尤其是当目标和特征之间的关系难以建模时。
- 数据集鲍鱼上的结果特别差:这是因为目标有 28 个类,而观察值非常少(只有 210)。然而, EDT 模型以最高的精度脱颖而出。这显示了它处理困难数据集和有效避免过拟合的能力。
注意美国东部时间的结果是用默认参数获得的。调整参数会带来更好的性能。
参考文献
[1] R. Barros 等, 决策树归纳进化算法综述 , 2011
[2] D .扬科夫斯基等, 决策树归纳的进化算法 ,2016
[3] S. Cha, 利用遗传算法构造二元决策树 ,2008
[4] D. Carvalho 等, 一种混合决策树/遗传算法的数据挖掘方法 ,2003
[5]维基百科, 旅行推销员问题
[6]维基百科,遗传算法
数据科学的发展:下一步是什么?
游戏变了吗?
2010 年,希拉里·梅森和克里斯·维金斯发表了一篇关于数据科学进程的文章。那时候,获取、筛选、探索、建模和解释是游戏的名字。然而,这并不是第一次将数据科学视为一个过程。让我们来探索基本面是如何随着时间的推移而变化的。

我最近读了一本来自迈克尔·苏立文的令人惊叹的教科书讨论统计过程。在书中,他提出了一个六步程序。但是这款和 2010 款有什么不同呢?我用一个新冠肺炎的例子来解释:
- 提问:是什么导致了一个国家的高新冠肺炎传染率?
- 数据收集:收集病例、人口密度、气候、口罩使用等数据。
- 汇总数据:绘制每个指标。检查平均值、分组依据、方差。
- 建模:使用协变量或回归拟合 SIR 模型或空间模型。选择你的毒药。
- 推论:定义假设。在人口密度更高的国家,传染速度更快。使用 A/B 测试或模拟。
- 结果交流:制作几个漂亮的图来展示你的分析结果。

注意,Sullivan 没有提到任何软件或 API 来提供结果。重点是分析的值。
我们可以回到过去。我最近在罗恩·科哈维的精彩演讲中了解到,第一个受控实验可以追溯到《T4》旧约。这意味着我们做数据科学已经有一段时间了!然而,在过去的 2000 年中出现了新的挑战。如今,数据就是产品,的价值在于对它的持续推断。
我们还需要几个步骤来烤蛋糕。让我们来谈谈这些新的步骤以及团队是如何考虑的。
首先,让我们讨论一下在数据科学社区中越来越流行的两个数据科学过程框架。然后再讲还需要更多发展的步骤。我个人看到两个需要进一步探索的新领域:机器学习工程和机器学习项目规划。
ML 项目框架的生命周期
我最近看到的关于数据科学作为一个过程的最有用的观点是由全栈深度学习课程提出的。

乔希·托宾、谢尔盖·卡拉耶夫和彼得·阿贝耳(2019)通过课程
本课程在我们之前学习的迈克尔·苏立文统计过程的基础上增加了几个步骤。Sullivan 忽略的主要步骤在计划&项目设置和部署&测试矩形内部。
计划&项目设置步骤属于项目管理(PM)和数据科学的交集。这些是我找到的关于项目管理和数据科学挑战的最佳资源:如何建立你的项目、如何定义成功和价值评估。然而,我们把部署&测试放在哪个学科?
这就是机器学习工程的用武之地。
机器学习工程这个术语越来越受欢迎。我不确定它的起源,但在 NIPS 2016 Martin Zinkevich 做了一个关于可靠的机器学习的演讲。他为机器学习工程发布了一份规则清单。有趣的是,他们提到“ML 系统的可靠性工程”应该是一个新的学科。我想说 Zinkevich 的演讲是 ML 工程术语的起源,但是如果我错了,请在评论中告诉我。关于该主题的另一篇极具影响力的论文是数据科学的隐藏技术债务。
机器学习工程是关于部署,监控,以及基础设施,全栈框架上的最后一个矩形。如果你想深入了解这个框架的细节,你可以学习全栈深度学习课程。他们也讨论测试和标签。

ML 项目的最后一英里:Josh Tobin、Sergey Karayev 和 Pieter Abbeel(2019)通过课程
机器学习框架的持续交付
因此,我们了解到规划和部署是任何数据科学项目的关键部分。现在让我们深入第二个数据科学流程框架。由 Danilo Sato 持续交付机器学习框架(CD4ML)。

该行业已经意识到,在生产中使用机器学习模型与使用 if-else 启发式方法非常不同。我们需要具体的类型的测试,具体的类型的监控,甚至部署策略。许多人和行业都在参与讨论。CD4ML 侧重于数据科学项目的数据、模型和代码组件。传统的软件开发项目不像 ML 项目那样依赖数据。模型对象也是进入拼图的新棋子。有关 CD4ML 的更多信息,请查看 Danilo Sato 的帖子。
工程推动是用 Mlflow 、 Metaflow 和 F lyte 等产品加速。这些平台的目标是简化部署和测试。但是,规划&项目设置方面的资源并不多。我们可以得到正确的工程,但我认为我们需要投入更多的时间来定义项目目标。

项目设置:乔希·托宾、谢尔盖·卡拉耶夫和彼得·阿贝耳(2019)通过课程
- 话虽如此,如何确定数据科学努力的优先级?
- 我们与其他计划相比如何?
- 我们是否由于不确定性而未能沟通项目的影响?
- 我们如何评估项目的风险?
- 我们如何在简单启发式和 ML 之间做出选择?
所有这些都是我们应该开始问自己的问题。金融也有助于对话。毕竟,我们只需要估计未来的回报,并计算它们的净现值。
我见过几个如何做到这一点的例子。评估经济价值很难。这就是为什么我们有专门评估价值的金融市场和学科。这里有一个很好的 ML 例子来解释我所说的:
您需要从您的反欺诈解决方案中每年节省大约 140 万美元才能在市场上生存。假设您每月有 4,000 个采购订单,平均订单价值为 83 美元,那么您的平均收入为 332,000 美元。
在机器学习之前,你必须为 40%的订单支付退款(1600 英镑)。那你每个月要花 132,800 美元。对于准确率为 95%的解决方案,您只需支付 4,000 起欺诈交易的 5%(200),即 16,600 美元。你的收益是退款的费用减少,总计 116,200 美元。这相当于每年节省 1,394,400 美元。
因此,您需要一个解决方案来检测 100 个可疑交易中的 95 个(准确性)。能够达到该阈值的工具将获得绿灯。【来源
欺诈是一个特别容易评估价值的领域。然而,我认为这是一个不完整的分析。我们需要评估项目的风险,并考虑未来的付款。
除此之外,在生产中使用该工具的反馈循环又如何呢?准确性会随着时间降低吗?这对它的价值有什么影响?是否存在任何伦理问题或意想不到的后果?
在分类类型项目(欺诈/无欺诈)中,评估价值可能很简单。但是回归、预测和聚类呢?视觉处理、自然语言和优化怎么样?我们如何评估像苹果 Siri 这样的项目的现值?Veronika Megler 的《管理机器学习项目》是一个很好的资源。
想想谷歌是如何以及为什么决定雇佣这个星球上最好的软件工程师来开发 Tensorflow vs 谷歌广告。两个项目之间的预算是如何决定的?我怀疑他们在 Tensorflow 上投入了更多资金,因为他们期望在人工智能上获得比这个星球上任何其他公司都高的投资回报。我正在探索的关于这个主题的两个资源是:如何测量任何东西和我经济学。
结论
总之,数据科学过程每周都在发展和改进。谷歌、微软、亚马逊、百度和 Salesforce 等巨头的投资正在加速这一演变。在机器学习工程方面需要进一步分析,但在机器学习规划方面可能更迫切。毕竟,计划是真正的 AI-complete 😃

现在就进化你的神经网络!具有从零开始的正则化演化的 AutoML
你是否厌倦了手工创建所有的神经网络架构?你是否在平凡而迭代的过程中浪费了宝贵的时间?一个正则化的进化算法等着你来帮助你

Johannes Plenio 在 Unsplash 上拍摄的照片
简介
AutoML 是一个概念,其中机器学习算法不是由人开发的,而是由计算机开发的。因此,对于给定的问题,例如预测照片上的猫/狗或预测股票价格,AutoML 算法会创建几个具有不同参数的架构,并评估其验证准确性/验证。一个机器学习研究人员也在做类似的事情,但需要一些先验知识和直觉。通常这样的过程是乏味的,并且需要几次构建和测试的迭代来找出好的架构。因此需要研究者花费大量的时间和雇佣他的公司/机构的资金。此外,仍然存在改进这种架构的空间,如过去几年中关于 CNN(卷积神经网络)架构的几个出版物所示(例如 Resnet50、Imagenet 等。).
现在的大多数算法都非常复杂,通常使用某种强化学习[1],贝叶斯优化过程[2],或者某种树搜索和进化搜索[3]。没有广泛的解释、研究和编码,任何一个都不容易尝试。然而,2019 年 Google Brain 发表了一篇关于“正则化进化”的论文[4],我将在这里解释它,甚至让它在 Jupyter 笔记本上尝试,你可以在 Google Colab 上运行。这是一个非常简单的进化算法,主要需要编写一个循环。
正则化进化,它是如何工作的?
在我们转向正则化进化之前,让我先介绍一下进化算法的概念。
进化算法
一般来说,EAs 是一组优化算法,它们受到生物进化过程的启发。其中或多或少基于突变和繁殖来选择最适合环境的。这些算法能够以一个噪声度量 ,遍历巨大的搜索空间*** (星号表示文章末尾的解释)。与进化过程类似,很难衡量一个比另一个更好,繁殖也有随机因素,但有机体仍然进化,能够适应给定的环境。该算法涉及到一些术语,你应该在继续之前理解,你可以在下面学习。
该算法在一组个体上工作,称为群体(例如机器学习模型),其中群体的大小是固定的(例如 100)。每个个体都是由一组基因定义的,你可以把它想象成一个个体属性的列表或向量(例如层的类型、数学运算、数字),这组基因被称为染色体。这些个体通过交叉和自身突变进行繁殖。突变是改变一个基因(例如,改变一种类型的层、参数或其他东西),其中交叉你可以认为是组合两组基因(例如,来自一个个体的层列表的一半与来自另一个模型的层列表的另一半,但它不必是一半,它可以是例如 5/100)。接受繁殖的个体是根据适合度分数、选择的,适合度分数告诉你一个个体有多好(例如 ML 模型的验证准确性)。体能分数越高,我们的个体越好。

描绘了交换和突变。不同颜色的方块代表不同的基因。
该算法通过在繁殖和适应性分数计算之间迭代来工作,其中最适合的和被选择用于繁殖的以及最不适合的被从种群中移除。这样的一次迭代称为一个循环,在一个循环中产生新的一代——通过突变和繁殖产生新的个体。该算法通过循环迭代,直到我们得到足够好的个体,或者当大多数群体共享相同的基因时(因此群体收敛)。该算法很少收敛到全局最优解,但很容易找到一个好的最优解。

进化算法的一个例子。这里没有显示交叉,但是需要使用锦标赛选择来选择两个人。根据托马西尼,马可。一篇评论。(1999).
选择过程可以通过各种算法进行,最流行的是 锦标赛选择 ,它从群体中随机抽取 k 个个体(其中 k 小于群体大小)并输出其中最好的。这确保了不总是选择最适合的,并给较弱的个体一个机会。这是因为最适合的个体并不总是繁殖的最佳候选人,也许其他个体在几代之后会更好。这确保了在搜索空间中遍历时更大的多样性。此外,你可能会认为这是为了防止陷入局部最大值的健康得分,即使一个人有一套非常好的基因,仍然可以有一个更好的组合。

描述了锦标赛选择。
另一种是 轮盘 根据适应度选择个体,适应度越高,概率越高。虽然文章中没有用到,这里也没有描述。
有规律的进化——有什么不同?
有规律的进化也被称为老化进化——随着算法的进步,我们的种群会老化。因此,从群体中移除最老的,而不是最不适合的。这确保了种群的多样性,因为最适者不能确保存活,即使表现良好,也会因老化而死亡。它的工作方式与锦标赛选择一节中描述的方式类似——简而言之,就是增加多样性,防止陷入局部最小值。该算法的模式稍后在下面描述。
利用正则化进化实现架构搜索
使用 regularized revolution 的架构搜索是在一个为本文准备的 Jupyter 笔记本中实现的,您可以在 Google Colab 环境(或任何其他地方,但需要一个像样的 GPU!).Jupyter 笔记本您可以在下面的我的资源库中找到:
进化 AutoML 教程。在 GitHub 上创建一个帐户,为 DanielWicz/AutoMLEvol 的发展做出贡献。
github.com](https://github.com/DanielWicz/AutoMLEvol)
这里有一个到 Google Colab 的直接链接,你可以直接与代码交互:
colab.research.google.com 的正则化进化教程](https://colab.research.google.com/github/DanielWicz/AutoMLEvol/blob/master/regul_evolution_tut.ipynb)
请记住,计算是为了执行架构搜索,因此参数设置得尽可能低,以加快计算和训练时间。在你发现一些有趣的架构后,你可以扩大它的规模(通过增加过滤器的数量)并充分利用它。然后你可以把它和一个排名(例如https://benchmarks.ai/cifar-10)进行比较,并且很高兴拥有一个表现良好的小模型。此外,如果我们在卷积层中使用不同数量的填充符,例如 16、32、64,那么算法将总是选择具有大量滤波器的卷积层的模型。事实说明,对于少量的时段和参数,这里可以忽略过拟合,并选择较大的参数空间。
必需的软件包:
在继续之前,您必须确保已经安装了以下软件包:
- Tensorflow 2.0 或以上
- Numpy 1.18 或以上
- Matplotlib 3.0.0 或以上版本
- Seaborn 0.9.0 或以上
在继续之前做一点解释
有几个算法的关键部分,你应该知道。但是如果你先打开它,在你进入文本之前,在代码中浮现你自己,那将是最好的。
算法中的关键是你在算法中使用的一组基因。
基因被定义为五种类型的层,其中第一层是身份函数,因此输出与输入相同。身份函数服务于缺少层的目的,实现一个空层比从基因集中删除一个层更容易。
然后,这些基因为模型产生随机层,正如在random_element()方法中定义的那样。该方法返回元组,将图层类型与其参数相关联。所有层只有一个参数,包括卷积层,其中滤波器的数量固定为一个小值。小尺寸的填充物用于加速计算(见本节开头)。
接下来是使用random_element()函数的random_architecture()函数,创建一个作为元组列表的架构。例如,这可能是一个架构:[(3, (2, 2)), (0, 16.0), (1, None), (1, None), (1, None), (3, (2, 2)), (1, None), (0, 16.0)]。您可以解密从左到右(从第一层到最后一层)读取的架构,并比较定义的基因中第一个元组的元素中的数字,这些基因在available_genes字典中。如果你试着在 Jupyter 笔记本中生成一些架构来了解它将会是什么样子,这是最好的。
事实上,你现在可以得出结论,群体中的一个个体(即一个架构)由一系列元组表示,这些元组表示不同的基因(即我们的架构搜索问题中的层)。您也可以尝试使用init_train_and_eval()方法通过传递一个带有架构的列表来训练一个架构。该函数返回验证精度,如果模型编译失败,则精度为零。
进入进化算法之前的最后一个重要功能是mutate_arch(),它负责你群体中每个个体的基因突变。该函数只是在你的模型列表中选择一个随机索引,并使用random_element()函数用一个随机元素替换它。
算法是如何工作的?
正则化进化算法在regularized_evolution()函数中实现。如何使用该函数以及相应的参数在做什么在它的 docstring 中有解释。
算法一般通过重复三个步骤来工作,其中的步骤称为循环。在每一个循环中,通过锦标赛选择来选择一个个体,然后对其进行变异,并从群体中移除最老的个体。最后一步是通过定义 FIFO 队列数据结构中的填充来执行的,因此那些较早添加的也较早被移除。下图更精确地描述了这一过程:

作为图表的正则化进化。相对于之前的 EA 图的差异用半透明的洋红色正方形标记。基于 Real E .等人在《aaai 人工智能会议论文集》(第 33 卷,第 4780–4789 页)。
运行算法
当算法运行时,您应该监控一些事情,这表明它的行为有多好。

正则化进化优化过程中的日志
这里的分数表示在给定数据集(这里是 cifar-10 )的给定架构评估期间获得的验证准确性。有几个值,像平均值、标准差和种群中最适合的个体。此外,由于在老化进化中,最适合的个体可能会死亡,因此也存在优化期间遇到的最佳模型的指示符。
随着算法的进展,你应该会看到或多或少,平均值增加,标准差减少。其背后的原因是群体中越来越多的个体共享相似的基因,从而具有相似的适合度(或验证准确性)。通常,该过程不是单调的,均值上升而标准差保持不变,然后保持不变,标准差下降。
算法的结果
经过指定数量的循环后,您将获得优化过程中遇到的最佳模型以及每个循环中的所有模型。您可以使用运行正则化进化的单元格下方的单元格,将其绘制为每个周期的分数分布。你应该得到如下图:

你可以发现它收敛于某一点。
您可以看到,验证准确性在开始时迅速提高,然后来回波动。通常,这是一个很好的趋同指标,表明大多数群体共享一组最佳基因。然而,有时这也表明你陷入了局部最小值,因此你可以减少锦标赛选择中的样本数。
我在 600 次循环后获得的最佳模型如下所示:
([(1, None),
(0, 16),
(0, 16),
(-1, <function __main__.random_element.<locals>.<lambda>>),
(1, None),
(0, 16),
(2, ('renorm', True)),
(0, 16),
(-1, <function __main__.random_element.<locals>.<lambda>>),
(1, None)],
0.6743999719619751)
这转化为具有以下层的架构:

事实上,我可以删除身份层,因为他们什么也不做。但是为了清楚起见我把它们留下了。
之后,您可以获得模型,并通过增加每个卷积层(如前一层的 2 倍,如 16、32、64、128)将其放大一点。然后,使用之前使用的数据集(cifar-10)训练模型。例如上面的例子,我在验证集上获得了大约 71%的准确率。如果我在此基础上使用图像增强,那么模型会给我多一点,大约是 77%。
然而,如果你想在真实案例中使用它,应该使用一组单独的图像(一个测试集)。这是因为您正在针对验证集优化您的架构,所以您的架构可能会过度适应验证集。但是那是另一个故事的主题,不是这个,但是要小心。
总结
进化算法是搜索复杂搜索空间的有效方法。他们研究群体,群体是一组个体,每个个体都有一组基因。基因是个体的特征,并且可以通过例如用其他值随机替换来突变。然后,进化算法迭代地选择那些在给定问题中表现良好的(那些最适合的),并对它们进行变异。由于群体大小是固定的,所以那些表现不好的群体不会更早或更早地被排除在群体之外。有规律的进化(也称为老化进化)为种群中的个体引入了年龄,因此每个人都随着时间而消亡,只有年轻的个体通过从最适合的个体中选择的基因存活下来。它增加了种群的多样性,因此可以找到更好的解决方案。
进化算法可用于机器学习中的架构搜索,例如卷积神经网络。他们在大量可能的模型(搜索空间)中有效地搜索,并以相对较少的迭代次数找到最优解。
解释:
- *搜索空间是某个问题中所有可能的结果或结果的集合。试着把它想象成所有的模型,你可以用给定类型的层来创建。
- **连续训练几个机器学习模型通常会给出不同的结果,每次训练时,即使使用相同的数据和迭代次数。你可以在 Jupyter 的笔记本上找到它,连续几次训练同一个模型,仍然给出不同的结果。
- ***您可以注意到没有交叉,这是因为没有交叉会使算法更简单,因此可以轻松地针对群集中的几个节点进行并行化。
参考资料:
[1] Kotthoff,l .,Thornton,c .,Hoos,H. H .,Hutter,f .,和 Leyton-Brown,K. (2017 年)。auto-WEKA 2.0:WEKA 中的自动模型选择和超参数优化。机器学习研究杂志, 18 (1),826–830。
[2]福雷尔,m .,克莱因,a .,艾根伯格,k .,斯普林根伯格,j .,布卢姆,m .,&胡特,F. (2015)。高效和健壮的自动化机器学习。在神经信息处理系统的进展(第 2962-2970 页)。
[3]乐,傅伟文,穆尔,陈建华(2020)。使用特征集选择器将基于树的自动机器学习扩展到生物医学大数据。生物信息学, 36 (1),250–256。
[4] Real,e .,Aggarwal,a .,Huang,y .,& Le,Q. V. (2019,7 月)。图像分类器结构搜索的正则化进化。aaai 人工智能会议论文集(第 33 卷,第 4780-4789 页)。
[5]托马西尼(1999 年)。并行和分布式进化算法:综述。
进入量子计算领域你需要知道什么
不要说“我不够聪明,做不了量子”

照片由energepic.com从派克斯拍摄
尽管量子计算是一项相对古老的技术,但它最近已经获得了业界和媒体的大量关注。量子计算最早出现在 20 世纪 80 年代。然而,目前围绕这项技术的吸引力正在上升,这有多种原因。
近年来,量子计算已经从纯理论走向实用。现在,有真正的量子计算机,你可以在上面运行简单的程序。
此外,不同的公司都在努力增加感兴趣的人的量子知识。
今天,我们生活在一个科技的时代;它就在我们周围。作为数据科学家,我们每天都要面对越来越多的数据。要处理、分析和清理的数据的增加,打开了量子技术如何帮助转变数据科学领域和许多其他领域的大门。
现在的问题是,每当一个从事量子计算的人问另一个人为什么他们不考虑加入这个领域时,答案通常是两种情况之一:
- 我没有聪明到可以加入量子。
- 或者,它太复杂了,需要很多我不知道/不喜欢的数学知识。
在这篇文章中,我想作为一个两年多前才加入这个领域的人和你谈谈。我想告诉你,大多数让你不要涉足量子计算领域的担忧都是不准确的。
我想向你们展示进入量子计算需要什么。我想向你们建议,进入量子计算并不比进入数据科学或任何其他技术领域更难。
那么,从量子计算开始,你真的需要知道什么?
量子计算入门知识
我会尽量布局一下你进入量子计算可能需要/不需要的知识。你愿不愿意将取决于你到底想在这个领域做什么。
例如,如果你已经是一名程序员或数据科学家,你想探索量子技术如何改变你的工作,你可能不需要知道太多的物理或力学知识就可以到达你不会去的地方。
另一方面,如果你想进入量子位的构造和它们如何工作,你将需要比编程和数学知识更多的物理/力学知识。
编程;编排
要开始使用 quantum,您可能需要了解一些编程基础知识。虽然目前有一些编程语言完全是为了给量子计算机编程而设计的,但是当你进入这个领域的时候,你并不需要学习这样的语言。
今天用于编程实际量子机器的最常用的编程语言之一是 Python 。
所以,如果你想尝试给量子机器编程,我建议你从 IBM 的开源工具包 Qiskit 开始。
使用 Qiskit 不仅可以让你编写一个真正的 IBM 量子机器,还可以帮助你轻松地学习许多量子概念。一旦你熟悉了量子概念,你就可以尝试学习一门量子编程语言。
数学
数学,可能是第一个让人们远离量子计算的东西。好吧,我不骗你;量子计算涉及到一些数学知识。
我还认为数学涉及所有其他技术领域,如机器学习、人工智能和自然语言处理。
事实上,其中一些数据科学领域包含比量子计算更复杂的数学!我知道这听起来不真实,但事实如此。
让量子计算发挥其魔力的基础数学是 线性代数 。量子计算中的一切,从量子位和门的表示到电路的功能,都可以用各种形式的线性代数来描述。
另一个真正涉及到量子计算的数学领域是 概率论 的基础知识。
就是这样。线性代数和概率论。两个领域涉及数据科学的所有子领域和当前大部分技术领域。
这并不是说随着你在这个领域的发展,事情不会变得复杂,但是所有的领域不都是这样吗?
物理/力学
量子计算的内在功能,比如纠缠和量子叠加,都是纯物理现象。它们有一些物理定律来控制和解释它们为什么会发生。
然而,经典计算机的内部功能是一样的。你不需要确切地知道你的电脑硬件是如何工作的,就可以用它来创造伟大的东西。你只需要知道如何使用它。
同样的逻辑也适用于量子计算。要成为一名量子软件开发人员,你只需要知道量子计算机是如何工作的,然后用它来构建你自己的应用程序。
如果你打算从事或参与建造量子计算硬件,你将需要真正了解量子计算机如何工作的物理和力学。
如果你想构建一个经典的处理器或 GPU 也是如此。您需要深入了解允许该硬件在这两种情况下正确运行的物理原理。
好奇心
在我看来,好奇心是进入量子计算领域最重要的心态。我知道好奇心不是一种知识,但是为了这篇文章而提到它是至关重要的。
我进入量子计算是因为我很好奇量子计算如何让我们目前的技术变得更好。它怎么能把非常先进的东西变得更先进呢?
我很想了解更多关于量子计算的知识,因为起初,这听起来像科幻小说,而不是实际可以开发的东西。
我的大多数同事在进入这个领域时都有同样的心态。作为人类,我们总是被吸引到让我们的思想漫游和自由想象的地方。当事情以不同于我们所习惯的方式运作时,这引起了我们的兴趣。
这种好奇心导致了我们今天所有的科学和技术进步,也将导致许多进步的产生。
最后的想法
量子计算机与其他任何技术领域没有什么不同。它只是有一个坏名声,因为在某个时间点,这个词 【量子】 与 复合体 联系在一起。所以,现在每当有人提到量子,你脑海中浮现的第一件事——直到最近,我的第一件事——是“哦,那一定非常复杂!”。
我想留下两件事。首先,如果你曾经决定接近量子计算,以同样的心态去做,你做任何其他领域。所有领域都有复杂的主题;他们都有一个学习曲线,有些比其他人更陡。然而,他们都这样做。
第二个,释放你的好奇心;让它带领你去探索和尝试新的领域和方面。我可以向你保证,如果你有进入量子计算的好奇心,你有这样做的智慧。
你足够聪明,可以进入任何你想进入的领域,而不仅仅是量子。所以,不要让量子这个词吓倒你,或者阻止你跳入这个神秘的领域。我在这里告诉你,现在是开始这样做的最佳时机。
一个非常欢迎新来者的全新领域
medium.com](https://medium.com/better-programming/4-reasons-why-now-is-the-best-time-to-start-with-quantum-computing-753437487ef4) [## 向量子领域迈出第一步
量子门和量子电路导论
towardsdatascience.com](/take-your-first-step-into-the-quantum-realm-a13e99fab886)
考察霍瓦特钟及其背后的统计方法
如何从 DNA 甲基化数据中找到生物年龄

来源: Unsplash 本人编辑
想象一下,你是一名研究人员,在实验室里研制一种抗衰老药丸。经过几个月对不同历史群体使用的不同抗衰老补充剂的研究,你找到了合适的干预方法。现在的问题变成了你如何证明干预确实抑制了衰老?
在临床试验中,你不能等到病人的整个生命周期来验证抗衰老补充剂实际上在哪里起作用。那会浪费时间。
相反,我们需要一个能够在短时间内测量评估不同干预的有效性的指标。这是对衰老生物标志物需求的主要原因。
在我们研究不同的衰老生物标志物之前,定义几个概念是很重要的。第一个是,什么是衰老?
字典对衰老的定义是变老的过程。够简单吧?
嗯,研究人员通常将衰老分为两个不同的类别:实足年龄、和生物年龄。实足年龄是通常理解的术语中的衰老;你多大了。从你出生到现在的时间。
生物年龄是一个新概念。生物年龄是你的细胞随着时间的推移而发生变化的方式,并且会受到许多不同生活方式因素的影响。为了给你一个直观的例子,让我们以一对双胞胎为例,一个吸烟,一个不吸烟。吸烟者的 生物年龄 会高于不吸烟者。因为他做了一个糟糕的生活方式选择,加速了他的衰老。双胞胎的 实足年龄 应该是一样的。

相同实足年龄的人,由于生活方式的差异,可以有不同的生物年龄。来源: Unsplash 本人编辑
通过测量你的生理年龄与实际年龄的比例,它可以给你一个很好的衰老速度的概念。如果你的某个组织按时间顺序是 50 岁,但生物学上是 30 岁,那就很好了。如果你在时间上是 50 岁,但在生理上是 70 岁,那就糟了。
这篇文章中展示的许多研究的关键是确定一个可以显示生物年龄的生物标志物。有几个可能的候选人:
- 端粒长度(染色体末端的帽)
- 基因表达水平
- 蛋白质表达水平
但是最准确、最广泛使用的生物标记叫做 DNA 甲基化。研究人员发现,DNA 甲基化是唯一符合被认为是生物年龄标志的标准的生物标志物。
那么有哪些标准呢?
- 与实际年龄有很强的相关性
- 预测年龄相关的表型
- 对不同的干预/生活方式的改变做出反应
甲基化时钟符合这些标准,这使它成为一个非常好的候选物,也是迄今为止研究最多的衰老生物标志物。
dna 甲基化
DNA 甲基化是被称为表观遗传学的更大研究的一部分。表观遗传学是调节基因组的不同生物过程的集合。这是导致细胞分化的原因,或者说是使你的神经细胞不同于肌肉细胞的原因。

CH3(甲基)附着在 CpG 位点的胞嘧啶上来源:维基共享
DNA 甲基化通过在 CpG 位点添加甲基基团(CH3)来改变表达。CpG 位点是基因组中胞嘧啶核苷酸后接鸟嘌呤核苷酸的位置。甲基可以与胞嘧啶核苷酸结合,生成5-甲基胞嘧啶。基因组中 CpG 位点出现频率高的地方被称为 CpG 岛 。人类基因组上大约有2800 万个 CpG 位点和27000 个 CpG 岛。

5-甲基胞嘧啶有一个额外的甲基。来源:[研究之门](http://‘From Death, Lead Me to Immortality’ – Mantra of Ageing Skeletal Muscle - Scientific Figure on ResearchGate. Available from: https://www.researchgate.net/figure/Methylation-of-cytosine-to-5-methylcytosine_fig4_259111694 [accessed 13 Mar, 2020])
CpG 岛通常位于启动子所在的位置或 DNA 中转录开始的区域。约 70%的人类启动子 CpG 含量高。推测基因启动子中 CpG 位点的甲基化可能抑制基因表达。
随着年龄的增长,我们的甲基化模式会发生变化。当我们的细胞分裂时“表观遗传噪音”被加入并改变甲基化模式。这个想法是找到以可预测的方式变化的 CpG,以便开发生物学年龄估计。
开发生物年龄的预测器
现在,我们如何从 DNA 甲基化中获取信息,并将其转化为功能性衰老生物标志物?这就是加州大学洛杉矶分校的史蒂夫·霍瓦特博士发挥作用的地方。霍瓦特被认为创造了最常用的甲基化钟之一,称为“霍瓦特钟”。霍瓦特钟提供了一种可以用于多种细胞类型的生物年龄测量方法。我将概述甲基化数据转化为年龄的过程。
霍瓦特收集了从 Illumina 甲基化检测 27k 和 450k 测得的甲基化数据集。27k 看起来大约。27,000 个 CpG 站点,而 450k 查看 450,000 个 CpG 站点,因此得名。

这个截图显示了数据输入后的样子。我的电脑来源截图
甲基化是的类似物。它要么在 CpG 网站上,要么不在。然而,这种分析的工作方式是,它观察给定组织中成千上万个细胞的甲基化,然后找到那些甲基化细胞的比例。这就是为什么当输入到他的时钟统计模型中时,CpG 位点的值在 0 和 1 之间。1 在所有细胞中都是甲基化的,0 在所有细胞中都不是甲基化的。
跳过数据标准化步骤,为了从大约 21,000 个将被输入的位点中找到 CpG 位点,霍瓦特使用了一个根据实际年龄训练的弹性网络回归模型。这是一个使用线性回归的统计模型,但是使用了正则化技术来消除和缩减大量参数。查看这个视频系列了解更多。
该模型有 21,000 个参数,其中许多参数对创建时钟并不重要。通过使用这种弹性网络回归,它可以让你摆脱许多无用的参数,霍瓦特缩小到 353 。

霍瓦特时钟年龄和真实年龄的相关性来源:维基共享资源
该模型是根据实际年龄训练的,因为最重要的标准之一是它与实际年龄有很强的相关性,因为实际年龄毕竟是生物年龄的良好代表。霍瓦特时钟年龄实际上与实足年龄的皮尔逊相关系数为 0.98,这是前所未有的。
霍瓦特在 82 个数据集和许多不同类型的组织和细胞类型上训练和测试了他的模型。最终结果是一个以 353 个 CpG 位点作为输入的公式,其权重(系数)显示了与生物年龄的正或负关系。
在创建这篇文章的过程中,我遵循了霍瓦特博士布置的一个教程,该教程采用了一个数据集,并展示了如何用 r 编写模型。这是一个非常酷的教程,GitHub 链接在这里。
后续步骤
霍瓦特钟创建于 2013 年。从那以后,随着耶鲁大学的摩根·莱文博士开发的表生时钟和加州大学洛杉矶分校的阿克·卢创造的表生时钟,表观遗传学时钟领域有了很大的进展。
新的表观遗传学时钟对预测专门的疾病特异性时钟感兴趣。创造一种可以预测细胞衰老水平的时钟。随着前沿研究人员不断取得突破,有许多挑战和问题需要解决。
这篇文章是为了帮助我掌握对表观遗传时钟的第一原理的理解,这让我着迷了一段时间。关于表观遗传时钟和生物学年龄,我还有许多问题,最深刻的是甲基化变化背后的生物学机制是什么?我仍然不清楚这是如何工作的,尽管我已经读到这是由于“表观遗传维持系统”。这可能与大卫·辛克莱的衰老传播信息理论有关,我正在读他的书《寿命》。
下次见。
嘿大家好!👋我是亚伦,一个 15 岁的孩子,对人工智能和人类长寿之间的交叉有着超级的热情。请随时在Linkedin上与我联系,或者查看我的完整 作品集
在流行数据集上检验 RCNs 的性能
皇家护理学院
大脑启发的计算机视觉模型有多好?
递归皮层网络基于与我们在深度学习中习惯的想法有很大不同的想法。那么,那些受神经科学启发的想法有多好呢?在这篇文章中,我们检查了 rcn 在不同任务上的表现,并对作者引入的想法进行了消融研究。除非另有说明,本文全部基于 RCNs 的论文[1]及其补充文件。
注:本文所有图表均取自【1】。
RCNs 的第一个测试是基于文本的验证码,它可以灵活地处理。500 个 reCAPTCHA 图像用于设置一些超参数的值,包括 RCN 将要被训练的字体。是的,RCN 实际上不是直接在 reCAPTCHA 图像上训练的,而是在对其进行了 10 次变换的单个字母上训练的,如图 1 所示,产生了总共 260 个图像的训练数据集。请记住,中间层仍在 SHREC 3D 数据集上进行训练,不包括在这些数字中。

图 1:为验证码图片构建的 RCN 的训练数据集。
这产生了一个模型,该模型以 84.2%的成功率为 reCAPTCHA 提供答案,而人类工人达到了 87.4%的准确率。然而,需要注意的是,如果答案产生的字符串长度与实际长度相似,并且有 0 或 1 个错误字符,则接受答案。这个成功率在逻辑上打破了基于文本的验证码,例如,你不希望一个机器人以这个成功率在你的网站上创建假账户。破解基于文本的验证码是否是一个壮举是另一个讨论,但这里明确的壮举是数据效率和推广到看不见的条件的能力,这将在剩余的实验中变得更加清楚。
为了了解它与 ConvNet 的对比,作者建立了一个 reCAPTCHA 控制集,并基于谷歌街景和 reCAPTCHA 团队 2013 年的一篇论文建立了一个 conv net 模型[2]。该论文声称,在困难的例子上达到 99.8%的准确率,但训练集“在数百万的数量级”。RCN 的作者在 79,000 张图像上训练了 ConvNet,并添加了残余连接,因为论文是旧的。前一段的 ConvNet 和 RCN 得分相当。然而,在增加测试集中字符之间的水平间距时(该间距不在训练集中,但应该使字母更清晰、更容易识别),ConvNet 的性能急剧下降,而 RCN 的性能则有所增加,如表 1 所示。

表 1:reCAPTCHA 控制集上 RCN 和 ConvNet 的性能比较。“间距”是水平间距。
为了展示 rcn 的高数据效率,他们在一次性学习 Omniglot 挑战赛上进行了测试。数据集由 20 个符号组成,每个符号有一个训练图像和一个测试图像。从 Omniglot 挑战的 3 年进度报告中,您可以看到他们的成果仍然令人印象深刻,如摘自该报告的表 2 所示[3]。在您的评估中,您应该考虑到 rcn 与 ConvNets 不同,几十年来没有经过不同研究人员的改进。需要注意的是,BPL 并不是像 RCNs 那样的通用架构,这也是它表现如此出色的原因。

表 2:不同型号在单镜头 Omniglot 挑战赛上的表现。
RCN 论文中的另一个重要实验是对 MNIST 噪声变体的测试。实验如下进行。他们在 MNIST 数据集的干净图像上训练了 3 个模型:1000 幅图像上的 RCN,1000 幅图像上的 CNN,以及 60000 幅图像上的 CNN。然后,他们在 MNIST 测试图像上测试了每个模型的性能,但添加了 6 种不同强度的不同类型的噪声,如表 3 所示。RCN 在这项测试中的优势从数字中显而易见,因为它始终胜过 ConvNets。但是,我仍然希望您记住,rcn 是在 SHREC 3D 数据集的 10K 图像上预先训练的。

表 3:一个 RCN 和两个 ConvNets 在噪声 MNIST 上的性能。报告的数字是测试精度,括号中的数字是标准偏差。
此外,作者进行了一项消融研究,以观察横向连接和反向传递是否有用。在这项研究中,他们测试了具有不同配置的 RCN 在噪声小于 MNIST 方面的性能,如表 4 所示。这个测试表明,对于高数据效率,RCNs 中的所有思想都非常有用。

表 4:消融研究结果。报告的数字是分类精度。FP 指的是向前传递,BP 指的是向后传递,Lats 指的是横向连接。扰动因子是横向连接的超参数。
作者做了更多的实验,包括在 ICDAR 挑战上测试 rcn,在不同的 CAPTCHA 数据集上测试,在从有噪声的 MNIST 图像重建上测试,以及在 3D 对象的分类上测试。然而,它们不会在本文中讨论,但是我可能会将它们包含在后续文章中,该后续文章将对 rcn 进行更具批判性的分析,以及我们可以从中学到什么。
您可能会有一个迫切的问题,如果 rcn 是数据有效的,为什么不在现实生活中应用。这有多种原因,但即使是作者也承认的两个主要原因是,它不适用于大规模数据集,并且它假设背景是单一的东西,不包含信息。用作者自己的话说,这是两个原因:
“…因为 RCN 将每个训练样本的原型存储在其倒数第二层(用于分类),所以扩展到非常大的数据集,如 ImageNet 和其他对象识别基准,其中 CNN(如 AlexNet)是最先进的,可能会很困难…”
在真实图像中,背景上下文提供了关于场景中可能存在的对象的无价信息。这个信息目前被 RCN 忽略,RCN 只对前景对象建模,忽略上下文。另一个极端是,CNN 不加区分地汇总前景和背景信息(这样就有可能通过显示脱离上下文的对象来欺骗 CNN)”
那为什么要写各种各样的文章呢?因为这两个缺点并不存在于所有的数据集中(想想资源不足的语言的 OCR ),因为想法在开始时有很多限制是正常的,就像胶囊网络一样。
本文到此为止。如果你想了解更多关于 RCNs 的知识,你可以查看它的论文[1]和补充材料文档,或者你可以阅读我的关于 RCNs 结构的文章。
参考资料:
[1] D. George,W. Lehrach,K. Kansky 等,一种以高数据效率进行训练并打破基于文本的验证码的生成视觉模型(2017),科学杂志(第 358 卷—第 6368 期)。
[2] I. Goodfellow,Y. Bulatov,J. Ibraz 等,利用深度卷积神经网络从街景图像中识别多位数号码(2013),Arxiv。
[3] B. Lake,R. Salakhutdinov,& J. Tenenbaum,《Omniglot 挑战:三年进度报告》(2019 年),Arxiv。
使用 Python 检查 Postgres 目录

Postgres 目录中的大量信息
充分利用数据库元数据
像 Postgres 这样的关系数据库包括一组描述数据库中的表的表。这组元数据表被称为目录,它包含了关于数据库的大量细节。我最近需要编写一个程序来从数据库目录中自动提取见解,这使我编写了一个简单的 Python 模块来连接到 Postgres 数据库,从目录中获取信息,并将该信息加载到 Pandas 数据帧中,以便用 Python 进行进一步处理。这篇文章描述了我遵循的过程。
介绍
关于 Postgres 的一个关键事实是,它有两个目录,而不是一个:
- ANSI (information_schema):这个目录包含为 ANSI 标准定义的公共关系数据库信息。如果您将目录的使用限制在 information_schema,那么您的代码应该与实现 ANSI 标准的其他关系数据库一起工作。
- PostgreSQL (pg_catalog):这个目录包含特定于 Postgres 的元数据。如果您的代码依赖于这个目录,那么在它可以与其他关系数据库一起使用之前,需要对它进行更新。
当您使用 Postgres UI 管理工具 pgAdmin 检查与数据库相关的对象时,您可以看到数据库 dvdrental 有以下两个目录:

出于本文的目的,我将重点放在 ANSI 目录上,因为它有我需要的信息,并且我编写的用于 Postgres ANSI 目录的代码应该可以用于其他关系数据库的目录。
设置 Postgres 目录的探索
为了从 Python 程序中探索 Postgres ANSI 目录,我遵循了以下步骤:
- 下载了并安装了 Postgres,还有 pgAdmin 。出于本练习的目的,pgAdmin 提供了快速检查目录和复查 Python 代码结果的完美方法。
- 设置 dvdrental 数据库。这个示例数据库很容易设置,并且有丰富的数据库对象,包括触发器、视图、函数和序列,所以在它的 ANSI 目录中有很多需要研究的内容。
- 创建了一个 Python 模块来连接数据库,运行一个查询来从一个目录表中提取信息,并将结果保存为一个 pickled 数据帧
以下部分描述了我为实现步骤 3 而编写的 Python 代码。
探索 Postgres 目录的 Python 模块
你可以在这里找到探索 Postgres 目录的 Python 模块。以下是该守则的要点:
- 使用 psycopg2 库创建到 Postgres 数据库的连接。使用从配置文件scrape _ db _ catalog _ config . yml读取的参数和用户交互提供的 Postgres 密码建立连接:
2.使用配置文件中的参数构建查询来检查目录中的一个表,运行查询,并将结果复制到 Python 变量 record_col_details 中。
3.将查询结果写入熊猫数据帧:
配置文件包含连接参数(在 general 部分)和查询参数(在 query_scope 部分)。
通过更新配置文件中的参数,您可以轻松地更改查询,以检查不同的目录表(通过更新 from_table)或目录表中不同的列集(通过更新 cols)。这意味着您可以重复地重新运行 Python 模块来从目录中获得您需要的细节,而不必接触 Python 代码。
例如,如果我想在查询的输出中包含 ordinal_position 列,我只需将它添加到配置文件的 cols 列表中:
请注意,Postgres 连接的密码不包含在配置文件中。相反,代码会直接提示用户输入密码:
以下是 Python 模块的输出示例,显示了从 ANSI 目录的列表(information_schema.columns)中选择的列。我可以使用列的数据类型信息来帮助自动创建简单的深度学习模型,以对这些表中的数据进行预测。
column_name data_type table_name
0 last_name character varying actor
1 actor_id integer actor
2 first_name character varying actor
3 last_update timestamp without time zone actor
4 first_name character varying actor_info
5 actor_id integer actor_info
6 last_name character varying actor_info
7 film_info text actor_info
结论
Postgres ANSI 目录包含关于 Postgres 数据库的有用元数据。通过使用 psycopg2 库连接到数据库并在配置文件中维护连接和查询参数,您可以从 Python 模块中有效地检查目录。
相关资源
- 包含本文所述代码的回购:【https://github.com/ryanmark1867/dl_auto_catalog
- Python PostgreSQL 教程使用 psycopg 2:https://pynative.com/python-postgresql-tutorial/
- 结构化数据深度学习主 repo:https://github . com/ryanmark 1867/Deep _ Learning _ for _ Structured _ Data
- 结构化数据深度学习书籍:https://www . manning . com/books/deep-Learning-with-Structured-Data
检查美国林务局数据以了解标准化燃烧率

2019 年 4 月,加利福尼亚州马里布夏至峡谷,燃烧的灌木在春天生长
我的生命从一开始就是由火形成的。我第一次大快朵颐是在 70 年代,当时我去加州的克里尔湖看望我的祖父母;我们发现自己被火包围了。大火包围了我们的湖,侵占了湖港,导致我的家人和其他几十人在湖边寻找避难所,因为野火切断了所有出口。对这个年轻人来说,这些事件既可怕又刺激。
我看过几次马里布大火,在高速公路被火焰包围的时候在盖蒂开 405,把博物馆藏起来。我的家人半夜从着火的房子里逃了出来。困惑地看着我们半裸的邻居在街上互相庇护,消防员耐心地控制着我们被摧毁的家园。

我一直对火很感兴趣。1992 年洛杉矶暴乱后,我沿着拉谢内加大街向北走,探索暴乱带来的暴力和流离失所的边缘。在我的记忆中,我仍然可以看到有一天我遇到的一个被烧毁的购物中心。唯一没有倒塌的是三面墙,在被熏黑的墙上,学生们用人行道上的粉笔画了巨大的彩色花朵。我哭了,在这样的破坏中看到这美丽的景色。
在我的一生中,我经常去以前被烧毁的地方,浸泡在茂盛的再生植物中,这些植物是在那之后再生的。迄今为止,我所完成的大部分工作都围绕着如何从破坏中获得增长这一核心兴趣。
什么是 LANDSAT 和归一化燃烧比?

美国宇航局戈达德太空飞行中心提供的地球资源卫星图片
1972 年 7 月 23 日,美国发射了地球资源技术卫星。这个计划,以前被称为“地球资源技术卫星计划”,是世界上所有国家中运行时间最长的卫星成像项目。该项目最初由美国国家航空航天局开发,后更名为 LANDSAT,并于 1975 年移交给 NOAA。
这颗卫星和相关的计划已经重复了八次。下一个预定版本的陆地卫星将于 2020 年 12 月发射。1992 年 10 月,美国国会已经认识到这些卫星和这个项目的价值,并通过了土地遥感政策法案。该法案授权进一步采购卫星,并确保以最低成本向传统(科学家)和新用户持续提供大地卫星数字数据和图像。

瓦莱丽·托马斯,美国宇航局数据科学家
Valerie Thomas 是美国国家航空航天局的数据分析师和科学家,他为卫星操作控制中心开发了计算机数据系统(1964-1970 年),然后监督了陆地卫星计划的创建(1970-1981 年),成为陆地卫星数据产品的国际专家。在 1974 年 LANDSAT 发射后,Thomas 领导了一个团队进行大面积作物库存实验(LACIE),这是与 NASA 的约翰逊航天中心、国家海洋和大气管理局(NOAA)和美国农业部共同努力的结果。LACIE 展示了空间技术如何使预测小麦产量的过程自动化。
这一概念由一位女性色彩科学家首创,利用土地图像预测作物产量,很快扩展到其他探索领域。除了不同的方式之外,LANDSAT 还被用于发现新物种、跟踪渔业健康状况、观察冰川消退、测量雨林的生物量、测量地震对地表的影响、分析水体的漂移以及记录野火对我们的公共和私人土地的影响。
标准化燃烧比
野火会根据有机物的类型和体积产生不同的强度,有机物是燃烧过程的燃料。强烈的火燃烧起来很热,并释放出巨大的先前包含的能量。
烧伤的严重程度描述了火灾的强度如何影响发生烧伤的土地和生态系统。局限在有限区域内的强烈火灾可能比更广泛和多样化区域内的不太强烈的火灾严重得多。在不同的生态系统或小气候中,火的影响程度是不同的。
归一化燃烧比(NBR)是一种工具,旨在显示大型火灾区域燃烧面积的信息。该公式结合了电磁波谱的近红外(NIR)和短波红外(SWIR)波长的信息。基本上,生物质和其他材料反射近红外区的光,SWIR 范围不同。健康的、未燃烧的植被在 NIR 范围内显示出高反射率,而在光谱的 SWIR 部分显示出低反射率。而最近烧伤的区域在 NIR 中表现出低反射率,在 SWIR 中表现出高反射率。
LANDSAT 通过将 NIR 和 SWIR 传感器放置在大气层上方,使这些类型的测量成为可能,因此我们作为一个物种,可以使用这些卫星测量全球的 NBR。这些测量是从 705 公里(438 英里)的近极地轨道上的一颗卫星在地面上以 30 米(98+英尺)的分辨率进行的,这颗卫星每 99 分钟绕地球一周。如果你想了解这是如何工作的,我发现这个来自联合国外层空间事务办公室的资源很有帮助。
分析美国林务局的实地研究
联合火灾科学项目 (JFSP)是一个跨部门项目,由美国内政部和美国林务局执行。它的任务是资助涉及野地火灾的科学研究,并向火灾管理和预防方面的利益相关者分发研究结果。它有几个合作伙伴,如印第安事务局、土地管理局、美国鱼类野生动物保护局等。由于 JFSP,有大量的野火研究可供公众使用,这些研究的数据和分析可供公众使用。
我决定检查来自的一组数据,在美国西部的五个生态系统中,过去火灾中的植被恢复和燃料条件如何影响燃料和未来的火灾管理。
从实地研究看几起火灾
虽然我检查的数据集(覆盖 47,010 平方米的土地)包含美国各地 19 起不同火灾的信息(覆盖超过 200 万英亩的土地),但我将触及其中的一个子集,以讨论我认为进一步研究和提问应该引向何处。
我对这个项目有很多疑问。什么是标准化燃烧比?森林管理是如何运作的?有什么工具可以用来了解野火?除了这些问题和许多其他问题,我想对美国野火的更大背景有所了解,因为它们在我们南加州的当地媒体环境中扮演着如此重要的角色。我的研究似乎揭示了更多的问题,而不是答案。这里有一些来自实地研究的图表,后面是一些关于全国野火的数字。
里科火灾
在 2005 年 7 月 11 日和 7 月 15 日之间,南达科他州黑山国家森林的 Ricco 大火吞噬了大约 4000 英亩土地,并威胁到了拉皮德城。NBR 的数据显示这场大火很快燃烧了大量的生物质。NBR 的下降幅度如此之低,表明受影响的土地受到了相当大的破坏。但它也显示了相对较快的复苏。与加州西米谷火灾的数据相比,这种差异是非常明显的。
里科大火发生在拉皮德城外一个崎岖的高海拔地区,除了纯粹关注自然的活动外,几乎没有任何人类参与。在这些地区发现的世界级的捕鱼和徒步旅行使它成为当地人对再生有既得利益的地方。周围地区的居民既能获得这些资源,又能从这些资源中获得收入。因此,NBR 数据显示,火灾区域的生物量非常高,随后生物量相对快速地重建,这在很大程度上是由于周围社区支持生物量的再生长。

2005 年 Ricco 火灾的归一化燃烧比
西米火
2003 年 10 月 25 日至 11 月 5 日,洛杉矶县西部和文图拉县东部西米山的西米大火吞噬了大约 108,204 英亩土地。它还摧毁了山谷上下数百座建筑。西米大火发生在荒地和城市交界处。与数据集中的其他地区相比,西米山谷包含数百英亩的混凝土,数千个结构,并建造了许多基础设施。燃烧前的这些 NBR 值相对较低,表明生物质的量相对较少。在火灾后,在这项研究中,数据显示生物量永远不会恢复。在人们居住的城市地区,数据缺乏恢复并不奇怪。火灾通常涉及重建(更多的结构,更多的混凝土),这很少看到生物量的增加。

2003 年西米火灾的归一化燃烧比
席卷美国的野火
我通过国家海洋和大气管理局的年度野火报告收集了美国各地火灾数量和烧毁面积的数据。这些数字跨越了 1984 年至 2018 年。正如你所看到的,尽管图表中有波动,但这些年来实际发生的野火数量似乎大致一致。

然而,当比较火灾数量和实际烧毁的英亩数时,情况就大不相同了。这些数字呈现出明显的上升趋势。媒体和消防专业人士似乎有充分的理由声称美国的野地火灾状况正在恶化。

进一步研究
标准化燃烧比只是了解公共土地、森林和野生动物区火灾的一种工具。还有很多其他的,当然,火有不同的种类。一些燃烧强烈而迅速,而另一些闷烧,燃烧数月或数年。比如澳大利亚的“火烧山”大火,已经燃烧了 6000 年。
这些地区的火灾通常是由雷击引起的(例如,阿拉斯加在任何 24 小时内都可以看到 8000 多次闪电)。尽管如此,纵火也是引发全国大量火灾的原因之一。
燃料负荷,以及燃烧后会产生何种类型的火,由许多因素决定。例如,许多火灾肆虐的地区,当地大部分树木因虫害而死亡,如华盛顿北部的 Okanogan-Wenatchee 国家森林中被甲虫杀死的 lodgepole 松林。这场由闪电引发的大火烧毁了大约 175,184 英亩土地,成为华盛顿历史上最大的野火之一。
燃料负载中的干旱和相对湿度在确定任何给定火灾的强度方面也起着重要作用。在这些研究期间,美国大部分地区经历了长期干旱。
我甚至比开始这个项目时对这个课题更感兴趣了。这项工作的一个重大成果是,在一定程度上了解了 NBR 的工作原理,使用它来测量当地生物量的相对健康状况,以及它对火灾研究的影响。在未来,我将对这个数据集和其他数据集做更多的工作,我将探索这些问题的更多方面。
深度学习中偏差方差权衡的例子

西蒙·艾布拉姆斯在 Unsplash 上拍摄的照片
介绍
啊…偏差-方差权衡…
到目前为止,你可能已经在互联网上看到了大量关于这方面的文章。
这不像他们中的一个。
似乎缺乏关于深度学习(高/低)偏差和方差实际上是什么样子的例子。
希望这篇文章能填补这个空白。
以下是我将要报道的内容:
- 对偏差和方差的简要概念理解
- 不同情况下拟合损失曲线可能的样子
- 如何缓解
- 如何优先考虑先减轻什么——你应该先降低偏差还是方差?
机器学习中的偏差和方差
术语“偏差”和“方差”实际上在不同的行业有不同的含义。
在心理学中,“偏见”可以指所有的认知偏见!例如信息偏差、确认偏差、注意偏差等。
有趣的事实:我花了 4 年时间获得心理学学位。然而,我在这里写的是一个与此无关的帖子。生活的结局很有趣。
在数学中,术语“方差”指的是平均值的平方偏差。
然而,在机器学习的背景下,它只是指你训练的模型要么学习得太少(偏差),要么学习得太多(方差)。
简单来说,
偏差=一个简单的模型,它不符合数据
相反地…
方差=过度拟合数据的复杂模型
那么这在概念上看起来如何呢?
下面是不同场景的样子。
原谅看起来凌乱的曲线..这些是我用 powerpoint 画的哈哈。

高偏差和低方差与低偏差和高方差的对比示例

高偏差和高方差与低偏差和低方差的对比示例
我认为最难理解的概念是高偏差和高方差的情况。
我已经对图表进行了注释,指出了高偏差和差异的区域,这样您就可以直观地理解它在概念上的样子。
到目前为止还不错,是吗?
如果你正在寻找数学和推导,有大量的其他职位涵盖这一点。我不会报道这些。
现在你已经对机器学习中的偏差和方差有了一个简单的理解,让我们来看看它们实际上是什么样子的。
偏差方差权衡的例子
这里是一些实际的屏幕截图,展示了不同的偏差与方差的情况。
这些是运行多个深度学习模型以找到每个模型的好例子的结果。😃
低偏差和低方差

低偏差和低方差示例
低偏差和高方差

低偏差和高方差示例
高偏差和低方差

高偏差和低方差示例
高偏差和高方差

高偏差和高方差的例子
您已经看到了四个例子,展示了每种组合可能的样子。
你能说出哪些有高偏差或高方差吗?你在看什么来得出你的结论?
这是我用来确定偏差和方差的东西。
我首先关注的是拟合误差统计。
在上面的结果中,这是曲线上标注的两个数字。这些数字代表跨时代的最小训练/验证误差。
如果训练误差很高,比如说 15.39%,那么你可以说你的模型不合适或者偏差很大。
我会在后面解释为什么“可能”是斜体。这里有一个潜在的假设。
如果验证误差很高,比如说 17.77%,并且验证误差和训练误差之间的差异相对较大(看行间的空白),那么你可以说你的模型是过拟合 或者方差很大。
综合来看,如果训练和验证误差较大,且两个统计量之间的差异相对较大,则存在高偏倚和高方差。
请随意向上滚动,再次查看结果,以确认您的理解。
你如何减轻偏差和差异的问题?
这里有一个解决机器学习中偏差/差异的通用框架。
在这种情况下,对于你的深度学习项目。

深度学习项目中如何解决偏差和差异的流程图
这里有一个具体的例子来说明正规化是如何帮助的。

正则化对深度学习模型的影响的示例
可悲的是,在正规化时,有时你可能会以上述场景结束。
该模型从低偏差、高方差变为高偏差、低方差。
换句话说,通过将 L2 正则化设置为 0.001,我对权重进行了过多的惩罚,导致模型欠拟合。
确定缓解工作的优先顺序
正如你已经看到上面的流程图,你应该几乎总是优先减少偏差。
然而,回想一下,我在上面用斜体提到了“可能”,并暗示了一个潜在的假设。
精神食粮。
你的偏见是根据什么来衡量的?
想一想。
如果你没有注意到,方差的基础是你的偏见。
那么偏见的底线是什么呢?15.39%的训练误差真的很糟糕吗?
看情况。
它肯定会坏!或者……也许不是。
偏倚比较的基础是对特定任务的人类水平表现的假设。
如果我告诉你,我正在训练的任务是一个困难的名称实体识别(NER)任务,人类往往有 15%的时间弄错标签。
然后…
15% vs 15.33%还不算太差!
我甚至会说这个模型非常合适!
这个模型的表现相当于人类的表现。
现在问题来了。
你如何衡量人的水平表现?
一个好的方法是对训练集进行分层采样,并覆盖标签。然后让一个人或一群人煞费苦心地给样品贴上标签。
这个人工标记任务的结果就是你的人类水平的表现。
现在只是为了形式和技术…
你的训练错误和人类水平的错误之间的区别就是所谓的“可避免的偏差”。
注意:在做研究时,你可能会遇到术语“贝叶斯错误”。人为误差是贝叶斯误差的近似值。在统计学中,贝叶斯误差是随机结果的任何分类器的最低可能****误差。它类似于数学中的渐近线;你的目标是尽可能地接近它,但是你知道你永远也不会达到它。
现在这个问题已经解决了,让我们回到最初关于优先级的问题。
什么时候应该关注减少偏差还是减少方差?
机器学习错误分析
为了了解你应该把时间和精力放在哪里,你需要做一个错误分析。
下面是机器学习错误分析的例子。
理解起来相当简单。

优先化偏见的一个例子
在这个例子中,可避免的偏差高于方差;4%对 1%。
因此,您的首要任务应该是减少模型中的偏差。
现在假设我们稍微改变一下。
你现在应该优先考虑哪个?

区分差异优先级的示例
在这种情况下,方差高于可避免的偏差;5%对 1.5%。
如果是这种情况,那么把你的时间集中在减少差异上。
到目前为止,我已经介绍了我想介绍的内容。
但是既然我们谈到了错误分析这个话题,让我们更进一步。
如果发生这种情况,你该怎么办?

高测试误差示例
我不知道测试和验证错误之间的区别的名称,所以我把它标为“?”。
但是请注意,该模型在训练集和验证集上都做得很好。
但是,它在测试集上没有表现出来。
这是为什么呢?
如果这种情况发生在你身上,你可以参考以下几点:
- 你的测试集和你的验证集来自同一个发行版吗?如果你训练一个猫分类器,你的测试集是老虎的图片吗?
- 您是否过度使用了验证集?增加验证集的大小。记住也要打乱你的数据。
- 您在培训/验证期间使用的评估标准不是一个好的指标。您可能需要改变度量标准。
可能有更多的原因,但这是我会做的几件事。
结尾注释
以下是到目前为止你所读内容的快速总结:
- 我开始给你一个概念上的理解,在机器学习的背景下什么是偏差和方差。
- 接下来,我展示了四个真实的例子,展示了每种情况下拟合误差曲线的样子。这是为了确保你自己能够更好地识别它们。
- 我还通过一个典型的流程图讲述了如何减轻偏差-方差问题。
- 最后,我介绍了像人的水平的性能这样的概念,并介绍了如何执行错误分析。
良好的..就是这样!
我真诚地希望你从中有所收获!
直到下一个帖子,再见!!
剧透:下一篇文章会很长。我已经就深度学习网络的变化如何影响预测结果进行了大量实验,并一直在记录我的结果。期待下一个帖子!😃
LinkedIn 简介:蒂莫西·谭
使用 Python 将 Apache Spark 与 PySpark 结合使用的示例
Apache Spark 是技术领域最热门的新趋势之一。这可能是最有可能实现大数据和机器学习联姻成果的框架。
它运行速度很快(由于内存操作,比传统的 Hadoop MapReduce 快 100 倍),提供健壮的、分布式的、容错的数据对象(称为),并通过补充包(如 Mlib 和 GraphX )与机器学习和图形分析的世界完美集成。

Spark 在 Hadoop/HDFS 上实现,大部分用 Scala 编写,一种类似 Java 的函数式编程语言。事实上,Scala 需要在您的系统上安装最新的 Java,并在 JVM 上运行。然而,对于大多数初学者来说,Scala 并不是他们进入数据科学世界首先要学习的语言。幸运的是,Spark 提供了一个奇妙的 Python 集成,称为 PySpark ,它允许 Python 程序员与 Spark 框架进行交互,并学习如何大规模操作数据,以及如何在分布式文件系统上处理对象和算法。
在本文中,我们将学习 PySpark 的基础知识。有很多概念(不断发展和引入),因此,我们只关注一些简单例子的基本原理。我们鼓励读者在这些基础上,自己探索更多。
Apache Spark 的短暂历史
Apache Spark 于 2009 年作为加州大学伯克利分校 AMPLab 的一个研究项目启动,并于 2010 年初开源。这是加州大学伯克利分校的一个班级项目。想法是建立一个集群管理框架,它可以支持不同类型的集群计算系统。该系统背后的许多想法在多年来的各种研究论文中都有介绍。发布后,Spark 成长为一个广泛的开发人员社区,并于 2013 年转移到 Apache Software Foundation。今天,该项目是由来自数百个组织的数百名开发人员组成的社区合作开发的。
Spark 不是一种编程语言
需要记住的一点是,Spark 不是像 Python 或 Java 那样的编程语言。它是一个通用的分布式数据处理引擎,适用于各种环境。它对于大规模和高速的大数据处理特别有用。
应用程序开发人员和数据科学家通常将 Spark 集成到他们的应用程序中,以快速查询、分析和转换大规模数据。一些最常与 Spark 相关联的任务包括:跨大型数据集(通常为万亿字节大小)的 ETL 和 SQL 批处理作业;处理来自物联网设备和节点的流数据、来自各种传感器、各种金融和交易系统的数据;以及电子商务或 IT 应用程序的机器学习任务。
在其核心,Spark 建立在 Hadoop/HDFS 框架之上,用于处理分布式文件。它主要是用 Scala 实现的,Scala 是 Java 的一种函数式语言变体。有一个核心的 Spark 数据处理引擎,但在此之上,还有许多为 SQL 类型的查询分析、分布式机器学习、大规模图形计算和流数据处理而开发的库。Spark 以简单接口库的形式支持多种编程语言:Java、Python、Scala 和 r。
Spark 使用 MapReduce 范式进行分布式处理
分布式处理的基本思想是将数据块分成可管理的小块(包括一些过滤和排序),使计算接近数据,即使用大型集群的小节点来完成特定的任务,然后将它们重新组合起来。分割部分被称为“映射”动作,重组被称为“缩减”动作。他们共同创造了著名的“MapReduce”范式,这是谷歌在 2004 年左右推出的(见原文)。
例如,如果一个文件有 100 条记录要处理,那么 100 个映射器可以一起运行,每个映射器处理一条记录。或者也许 50 个映射器可以一起运行,每个处理两个记录。在所有的映射器完成处理之后,框架在将结果传递给 reducers 之前对它们进行洗牌和排序。映射器仍在运行时,缩减器无法启动。具有相同键的所有地图输出值都被分配给一个 reducer,然后该 reducer 聚合该键的值。
如何设置 PySpark
如果您已经熟悉 Python 和库(如 Pandas 和 Numpy ),那么 PySpark 是一个很好的扩展/框架,可以通过在后台利用 Spark 的能力来创建更具可伸缩性、数据密集型的分析和管道。
安装和设置 PySpark 环境(在一台独立的机器上)的确切过程有些复杂,可能会因您的系统和环境而略有不同。目标是使用 PySpark 包让您的常规 Jupyter 数据科学环境在后台与 Spark 一起工作。
这篇关于 Medium 的文章 提供了关于逐步设置过程的更多细节。

或者,您可以使用 Databricks 设置来练习 Spark。这家公司是由 Spark 的最初创建者创建的,拥有一个优秀的现成环境,可以使用 Spark 进行分布式分析。
但想法总是一样的。您在许多节点上以固定的小块分发(和复制)大型数据集。然后,您将计算引擎靠近它们,以便整个操作是并行的、容错的和可扩展的。
通过使用 PySpark 和 Jupyter notebook,您可以学习所有这些概念,而无需在 AWS 或 Databricks 平台上花费任何东西。您还可以轻松地与 SparkSQL 和 MLlib 进行接口,以进行数据库操作和机器学习。如果您事先已经理解了这些概念,那么开始处理现实生活中的大型集群将会容易得多!
弹性分布式数据集(RDD)和 SparkContext
许多 Spark 程序都围绕着弹性分布式数据集(RDD)的概念,这是一个可以并行操作的容错元素集合。SparkContext 驻留在驱动程序中,通过集群管理器管理工作节点上的分布式数据。使用 PySpark 的好处是,所有这些复杂的数据分区和任务管理都在后台自动处理,程序员可以专注于特定的分析或机器学习工作本身。

rdd-1
创建 rdd 有两种方法——在驱动程序中并行化现有集合,或者引用外部存储系统中的数据集,例如共享文件系统、HDFS、HBase 或任何提供 Hadoop InputFormat 的数据源。
from pyspark import SparkContext import numpy as np sc=SparkContext(master="local[4]") lst=np.random.randint(0,10,20) A=sc.parallelize(lst)
注意参数中的‘4’。它表示 4 个计算核心(在您的本地机器中)将用于这个 SparkContext 对象。如果我们检查 RDD 对象的类型,我们得到如下结果,
type(A) >> pyspark.rdd.RDDA.collect() >> [4, 8, 2, 2, 4, 7, 0, 3, 3, 9, 2, 6, 0, 0, 1, 7, 5, 1, 9, 7]
但是 A 不再是简单的 Numpy 数组。我们可以使用 glom()方法来检查分区是如何创建的。
A.glom().collect() >> [[4, 8, 2, 2, 4], [7, 0, 3, 3, 9], [2, 6, 0, 0, 1], [7, 5, 1, 9, 7]]
现在停止 SC,用 2 个内核重新初始化它,看看重复这个过程会发生什么。
sc.stop() sc=SparkContext(master="local[2]") A = sc.parallelize(lst) A.glom().collect() >> [[4, 8, 2, 2, 4, 7, 0, 3, 3, 9], [2, 6, 0, 0, 1, 7, 5, 1, 9, 7]]
RDD 现在分布在两个块上,而不是四个!您已经了解了分布式数据分析的第一步,即控制如何将您的数据划分为更小的块以供进一步处理
RDD &派斯帕克基本操作的一些例子
数数元素
>> 20A.first() >> 4 A.take(3) >> [4, 8, 2]
使用 distinct 删除重复项
注意:这个操作需要一个洗牌来检测跨分区的复制。所以,这是一个缓慢的操作。不要过度。
A_distinct=A.distinct() A_distinct.collect() >> [4, 8, 0, 9, 1, 5, 2, 6, 7, 3]
使用 reduce 方法对所有元素求和
注意这里使用了 lambda 函数,
A.reduce(lambda x,y:x+y) >> 80A.sum() >> 80
通过归约寻找最大元素
A.reduce(lambda x,y: x if x > y else y) >> 9
在文本块中查找最长的单词
words = 'These are some of the best Macintosh computers ever'.split(' ') wordRDD = sc.parallelize(words) wordRDD.reduce(lambda w,v: w if len(w)>len(v) else v) >> 'computers'
使用过滤器进行基于逻辑的过滤
# Return RDD with elements (greater than zero) divisible by 3 A.filter(lambda x:x%3==0 and x!=0).collect() >> [3, 3, 9, 6, 9]
编写与 reduce()一起使用的常规 Python 函数
def largerThan(x,y): """ Returns the last word among the longest words in a list """ if len(x)> len(y): return x elif len(y) > len(x): return y else: if x < y: return x else: return y wordRDD.reduce(largerThan) >> 'Macintosh'
注意这里的 x < y does a lexicographic comparison and determines that Macintosh is larger than computers !
Mapping operation with a lambda function with PySpark
B=A.map(lambda x:x*x) B.collect() >> [16, 64, 4, 4, 16, 49, 0, 9, 9, 81, 4, 36, 0, 0, 1, 49, 25, 1, 81, 49]
Mapping with a regular Python function in PySpark
def square_if_odd(x): """ Squares if odd, otherwise keeps the argument unchanged """ if x%2==1: return x*x else: return x A.map(square_if_odd).collect() >> [4, 8, 2, 2, 4, 49, 0, 9, 9, 81, 2, 6, 0, 0, 1, 49, 25, 1, 81, 49]
groupby returns a RDD of grouped elements (iterable) as per a given group operation
result=A.groupBy(lambda x:x%2).collect() sorted([(x, sorted(y)) for (x, y) in result]) >> [(0, [0, 0, 0, 2, 2, 2, 4, 4, 6, 8]), (1, [1, 1, 3, 3, 5, 7, 7, 7, 9, 9])]B.histogram([x for x in range(0,100,10)]) >> ([0, 10, 20, 30, 40, 50, 60, 70, 80, 90], [10, 2, 1, 1, 3, 0, 1, 0, 2])
Set operations
Check out 这个 Jupyter 笔记本 有更多的例子。
惰性评估是一种评估/计算策略,它为计算任务准备了执行流水线的详细的逐步内部图,但是将最终执行延迟到绝对需要的时候。这一策略是 Spark 加速许多并行化大数据操作的核心。
让我们在这个例子中使用两个 CPU 内核,
sc = SparkContext(master="local[2]")
用一百万个元素做一个 RDD
%%time rdd1 = sc.parallelize(range(1000000)) >> CPU times: user 316 µs, sys: 5.13 ms, total: 5.45 ms, Wall time: 24.6 ms
一些计算功能—需要时间
from math import cos def taketime(x): [cos(j) for j in range(100)] return cos(x)
检查 taketime 函数花费了多少时间
%%time taketime(2) >> CPU times: user 21 µs, sys: 7 µs, total: 28 µs, Wall time: 31.5 µs >> -0.4161468365471424
现在对函数进行映射操作
%%time interim = rdd1.map(lambda x: taketime(x)) >> CPU times: user 23 µs, sys: 8 µs, total: 31 µs, Wall time: 34.8 µs
为什么每个函数需要 45.8 us,但一百万元素 RDD 的地图操作也需要类似的时间?
由于懒惰评估,即在之前的步骤中没有进行任何计算,只制定了一个执行计划。变量 interim 不指向数据结构,而是指向一个执行计划,用依赖图表示。依赖图定义了 rdd 如何相互计算。
reduce 方法的实际执行
%%time print('output =',interim.reduce(lambda x,y:x+y)) >> output = -0.28870546796843666 >> CPU times: user 11.6 ms, sys: 5.56 ms, total: 17.2 ms, Wall time: 15.6 s
现在,我们还没有保存(具体化)任何中间结果,所以另一个简单的操作(例如,计数元素> 0)将花费几乎相同的时间。
%%time print(interim.filter(lambda x:x>0).count()) >> 500000 >> CPU times: user 10.6 ms, sys: 8.55 ms, total: 19.2 ms, Wall time: 12.1 s
缓存以减少类似操作的计算时间(消耗内存)
还记得我们在上一步中构建的依赖图吗?我们可以像以前一样使用 cache 方法运行相同的计算,告诉依赖图规划缓存。
%%time interim = rdd1.map(lambda x: taketime(x)).cache()
第一次计算不会改进,但是它缓存了中间结果,
%%time print('output =',interim.reduce(lambda x,y:x+y)) >> output = -0.28870546796843666 >> CPU times: user 16.4 ms, sys: 2.24 ms, total: 18.7 ms, Wall time: 15.3 s
现在在缓存结果的帮助下运行相同的过滤方法,
%%time print(interim.filter(lambda x:x>0).count()) >> 500000 >> CPU times: user 14.2 ms, sys: 3.27 ms, total: 17.4 ms, Wall time: 811 ms
哇!计算时间从之前的 12 秒下降到不到 1 秒!这样,延迟执行的缓存和并行化就是 Spark 编程的核心特性。
Dataframe 和 SparkSQL
除了 RDD,Spark 框架中的第二个关键数据结构是。如果您使用过 Python Pandas 或 R DataFrame,这个概念可能会很熟悉。
数据帧是指定列下的行的分布式集合。它在概念上相当于关系数据库中的一个表、一个带有列标题的 Excel 表或 R/Python 中的一个数据框,但是在底层有更丰富的优化。数据帧可以从各种来源构建,例如:结构化数据文件、Hive 中的表、外部数据库或现有的 rdd。它还与 RDD 有一些共同的特征:

- 本质上是不可变的:我们可以创建一次数据框架/ RDD,但不能改变它。并且我们可以在应用变换之后变换数据帧/ RDD。
- 惰性评估:这意味着直到一个动作被执行,一个任务才被执行。分布式:RDD 和 DataFrame 都分布在自然界。
数据框架的优势
- 数据帧是为处理大量结构化或半结构化数据而设计的。
- Spark 数据帧中的观察结果组织在命名列下,这有助于 Apache Spark 理解数据帧的模式。这有助于优化这些查询的执行计划。
- Apache Spark 中的 DataFrame 能够处理数 Pb 的数据。
- DataFrame 支持多种数据格式和数据源。
- 它有对不同语言的 API 支持,比如 Python,R,Scala,Java。
数据框架基础示例
有关数据帧的基础知识和典型使用示例,请参见以下 Jupyter 笔记本,
SparkSQL 有助于弥补 PySpark 的不足
关系数据存储易于构建和查询。用户和开发人员通常更喜欢用类似人类的可读语言(如 SQL)编写易于解释的声明性查询。然而,随着数据的数量和种类开始增加,关系方法无法很好地扩展以构建大数据应用程序和分析系统。
借助 Hadoop 和 MapReduce 范式,我们在大数据分析领域取得了成功。这很强大,但是通常很慢,并且给用户提供了一个低级的、过程化的编程接口,要求人们为非常简单的数据转换编写大量代码。然而,一旦 Spark 发布,它就真正彻底改变了大数据分析的方式,专注于内存计算、容错、高级抽象和易用性。

Spark SQL 本质上试图在我们之前提到的两种模型——关系模型和过程模型——之间架起一座桥梁。Spark SQL 通过 DataFrame API 工作,可以对外部数据源和 Spark 内置的分布式集合执行关系操作——大规模!
为什么 Spark SQL 这么快,这么优化?原因是因为一个新的可扩展优化器, Catalyst ,它基于 Scala 中的函数式编程结构。Catalyst 支持基于规则和基于成本的优化。虽然在过去已经提出了可扩展的优化器,但是它们通常需要复杂的特定于领域的语言来指定规则。通常,这导致了很长的学习曲线和维护负担。相比之下,Catalyst 使用 Scala 编程语言的标准特性,例如模式匹配,让开发人员可以使用完整的编程语言,同时仍然可以轻松地指定规则。
关于 SparkSQL 数据库操作的介绍,可以参考下面的 Jupyter 笔记本:
你将如何在你的项目中使用 PySpark?
我们讲述了 Apache Spark 生态系统的基础知识,以及它是如何工作的,并给出了一些使用 Python 接口 PySpark 的核心数据结构 RDD 的基本例子。此外,还讨论了 DataFrame 和 SparkSQL 以及代码笔记示例的参考链接。
将 Apache Spark 与 Python 结合使用,还有很多东西需要学习和尝试。PySpark 网站是一个很好的参考网站,他们会定期更新和增强——所以请关注它。
此外,如果您对使用 Apache Spark 进行大规模分布式机器学习感兴趣,请查看 PySpark 生态系统的 MLLib 部分。
原载于 2020 年 4 月 7 日【https://blog.exxactcorp.com】。
3 个中级 Excel 函数以及如何用 Python 来做!
不仅仅是在熊猫身上试水!

让我们和熊猫一起出发吧!资料来源:Nik Piepenbreier
你想尝试一下蟒蛇和熊猫的有趣世界吗?
Python 通常被认为比 Excel 更难掌握,但却有无限的潜力。本教程将带您逐步了解您已经在 Excel 中使用的函数。
Pandas 中的文本转列
当您得到由奇怪结构的数据组成的大型数据集时,Text to columns 是这些基本功能之一。
例如,可能会给你一列人名。但是不是一列表示姓,另一列表示名,而是一列表示姓,名。

Excel 中的文本到列。资料来源:Nik Piepenbreier
Excel 的“文本到列”功能让您可以轻松地将这些数据拆分到单独的列中。
您只需选择列,单击数据→文本到列,并用逗号分隔。
瞧啊。
现在在熊猫身上做同样简单!
让我们来看看这段代码:
Pandas 中的文本到列。资料来源:Nik Piepenbreier
要创建包含姓氏和名字的两个新列,只需编写以下代码:
Pandas 中的文本到列-代码。资料来源:Nik Piepenbreier
让我们来看看拆分功能:
- 我们指定要在逗号(,)上进行拆分。
- 我们还指出 expand=True,这意味着数据被拆分到新的列中。如果该值为 False,将创建一个字符串列表。
- 还可以使用 n=来指定想要拆分字符串的次数。默认值为-1,表示所有实例。
用熊猫代替文本函数(如 RIGHT()、PROPER())
Excel 也塞满了不同的文本函数。您可以使用 LEFT()和 RIGHT()等函数来提取字符,使用 PROPER()和 LOWER()来修改单元格内的文本。
让我们加载另一个数据帧,看看如何用 Pandas 实现这些:
加载更多数据。资料来源:Nik Piepenbreier
现在,让我们应用一些文本函数:
应用字符串函数。资料来源:Nik Piepenbreier
LEFT()和 RIGHT()函数通过索引每一列中的字符串来工作。由于字符串是 Python 中的可迭代对象,所以可以对它们进行索引。
通过编写[:3],您要求 Python 返回第三个字符之前的字符(但不包括第三个字符)。

Excel 和 Pandas 中的一些常用文本函数。资料来源:Nik Piepenbreier
跨列应用计算
Excel 使得对列的操作非常直观。由于每个单元格都有一个特定的引用,您可以使用该单元格引用轻松地将其乘以一个值,将两个单元格相加,等等。
现在还不清楚你是否能在熊猫身上做到这一点。
让我们加载一个包含两列重量的样本数据帧,我们假设重量单位为千克:
加载第三个数据帧。资料来源:Nik Piepenbreier
如果我们想要创建一个包含 weight1 和 weight2 之和的新列,我们可以简单地将它们相加:
添加两列。资料来源:Nik Piepenbreier
最后,如果我们想将 sum 列转换为磅(通过乘以 2.2),您可以直接应用该乘法:
在熊猫中乘一列。资料来源:Nik Piepenbreier
结论

感谢阅读!资料来源:Nik Piepenbreier
感谢阅读这篇文章!我希望你学到了一些东西,并且对尝试 Python 和熊猫的有趣世界感到更舒服了!
如果你想更深入地了解这一点,可以看看我的其他文章或我的电子书,带你从完全初学者到中级熊猫!你可以在这里找到:https://gumroad.com/l/introtopythonfordatascience
Excel,Tableau,Power BI…应该用什么?
找出你需要什么数据分析或可视化。

杰森·斯特鲁尔在 Unsplash 上的照片
在发表了我的上一篇关于 Power BI 的数据可视化的文章之后,我收到了很多关于 Power BI 相对于 Tableau 或 Excel 的能力的问题。如果使用得当,数据可以变成数字黄金。那么,作为个人或组织,您必须使用什么来分析和可视化您的数据呢?请继续阅读,寻找答案。
在本文中,我们将了解所有这三个系统,并比较它们的各种特性。
微软 Excel 发布于 1985 年,本质上是一个具有计算、绘图工具、数据透视表和宏编程语言等功能的工具。可以在 Windows、Mac、Android、iOS 等多种操作系统上使用。
接下来是 的画面。Tableau 成立于 2003 年,是一款交互式数据可视化软件。它被认为是发展最快的数据可视化工具,主要是因为它能够帮助用户查看和理解数据。它只是将原始数据转换成易于理解的视觉效果,从而改变人们使用数据解决问题和做出决策的方式。
动力 BI 发布于 2014 年。它是微软基于云的分析和商业智能服务。它旨在为 It 用户提供交互式可视化和商业智能功能,以及简单的数据共享、数据评估和可扩展的仪表板。
下面列出几个参数,对三款软件进行对比。

作者图片
1。数据来源
Excel 是一种灵活、易用的电子表格,通常用于创建数据集。借助数据连接功能,它可以将数据从外部数据源拉入您的电子表格。它还可以从 Web、Microsoft Query、SharePoint List、OData Feed、Hadoop Files (HDFS)等来源获取数据。因此,Excel 文件经常被用作 Power BI 和 Tableau 的数据源。
Tableau 支持数百种数据连接器,包括在线分析处理(OLAP)和大数据选项(如 NoSQL、Hadoop)以及云选项。

作者图片
Power BI 非常能够连接到用户的外部资源,包括 SAP HANA、JSON、MySQL 等等。它使用户能够连接到微软 Azure 数据库、第三方数据库、文件和在线服务,如 Salesforce 和谷歌分析。
当用户从多个来源添加数据时,Tableau 和 Power BI 会自动确定关系。然而,Power BI 连接有限的数据源,同时在每月更新中增加其数据源连接器。
2。数据发现
数据发现是通过可视化导航数据或应用引导式高级分析来检测数据中的模式和异常的过程。
使用 Excel 时,您需要知道数据需要将您引向何处,以便找到关键的见解。Excel 中的股票和地理位置等选项有助于快速获取数据细节。
Tableau 和 Power BI 允许您自由探索数据,而无需提前知道您想要的答案。使用这个软件,你能够发现相关性和趋势,然后深入了解是什么导致了它们的发生,而不是相反。这些系统让你一目了然地了解你的数据。
3。数据模型和适用性
Excel 侧重于创建具有广泛功能的结构化和简单的数据模型,最适合于结构化数据的统计分析。
Tableau 允许您创建一个简单的数据模型,比如单个表,也可以是更复杂的模型,包含使用不同关系、连接和联合组合的多个表。它最适合快速简单地表示大数据,有助于解决大数据问题。
Power BI 的数据模型专注于数据摄取,并轻松构建潜在的复杂数据模型。
4.形象化
可视化是突出不可或缺的数据的好方法。
在使用 excel 进行数据可视化时,我们首先处理显示的数据,然后手动创建不同的图表。为了使可视化容易理解,您应该很好地理解 excel 的功能。
用户可以选择许多可视化作为蓝图,然后使用 Power BI 将侧栏中的数据插入到可视化中。此外,它允许用户通过用自然语言进行查询来创建可视化效果。在深入数据集进行分析时,Power BI 确实设置了 3,500 个数据点的限制。但是,此数据点限制也有一些例外:R 视觉效果的最大数据点数量限制为 1,50,000,Power BI 视觉效果的最大数据点数量限制为 30,000,散点图的最大数据点数量限制为 10,000。
Tableau 允许用户创建不同类型的基线可视化,包括热图、折线图和散点图。此外,用户能够提出数据的“假设”问题,并可以在其分析中自由使用任意数量的数据点。
此外,Power BI 和 Tableau 允许用户集成 Python、R 等编程语言来创建可视化。
由 giphy 上的 Paloma Health
此外,一个好的 API 通过提供所有的构建模块,使开发可视化变得更加容易,然后由程序员将这些模块组合在一起。API 由一组子程序定义、通信协议和构建软件的工具组成。实质上,它是各种组件之间的一组明确定义的通信方法。 Excel 、 Tableau 和 Power BI 允许用户合并 API 并利用数据创建引人注目的可视化效果。
5.仪表板
Excel 为创建仪表板提供了有限的功能,刷新仪表板是一个繁琐的过程。Tableau 和 Power BI 允许您创建由不同类型的图表、地图和图示组成的定制仪表板。使用 Tableau 和 Power BI 很容易刷新您的仪表板,它们使用户能够创建美观的仪表板。当谈到嵌入数据时,这可以在所有三个系统上轻松完成,但是与 Power BI 相比,在 Tableau 中这样做是一个实时挑战。
6.用户界面
为了充分发挥 excel 的潜力,需要具备宏和 visual basic 脚本知识。
Tableau 和 Power BI 拥有不需要编码知识就能开发复杂的可视化界面。
Tableau 有一个智能用户界面,能够轻松创建仪表板。和力量 BI 相比,画面有点难。
Power BI 界面非常简单易学。由于其简单性,Power BI 经常受到用户的青睐。
7。语言依赖性
VBA (Visual Basic for Applications)是 Excel 和其他 Microsoft Office 程序的编程语言。此外,当您从数据透视表字段列表中选择项目时,Excel 使用 MDX 来检索字段和数据值。从 Analysis Services 多维数据集中导入数据时,也可以手动生成 MDX 查询。
但是什么是 MDX 呢?MDX 代表多维表达式,是一种用于 OLAP 数据库的查询语言。
Tableau 的软件工程师使用几种编程语言,但构成 Tableau 桌面绝大部分的代码是 C++。
DAX 和 M 是在 Power BI 中使用的语言,用于构建 Power BI 模型时有所不同,它们并不相互依赖。m 是一种查询公式语言。在将数据加载到 Power BI 模型之前,可以使用 m 语言在 Power Query 编辑器中查看、编辑和准备数据。M 中的表达式是在转换完成时自动生成的。DAX 是一种分析数据计算语言。您可以使用 DAX 为计算列和度量(也称为计算字段)定义自定义计算,所有这些都可以在数据视图阶段进一步用于深入的数据分析。DAX 包括 Excel 公式中使用的一些函数,以及用于处理关系数据和执行动态聚合的附加函数。
8。性能
Excel 以中等速度运行,没有加速选项。Tableau 和 Power BI 也以中等速度运行,具有优化和增强操作进度的选项。Power BI 是为普通利益相关者而构建的,不一定是数据分析师。为了帮助团队建立他们的可视化,Power BI 的界面更多地依赖于拖放和直观的特性。总的来说,在数据可视化方面,Power BI 在易用性方面胜出,但 Tableau 在速度和功能方面胜出。
9。数据可用性
Excel 是用户特定的。但是,您可以使用 Power BI 与同事共享您的 Excel 工作簿。
在 Tableau 上创建的可视化可以存储在 Tableau 服务器上,并与其他 Tableau 用户共享。
Power BI 专注于报告和分析建模,它允许您通过将仪表板发布到工作区来存储和共享仪表板,以便每个人都可以在其上进行协作。存储容量限制取决于您的工作区类型(共享或高级)。
更多关于这方面的信息可以在这里找到。
10。产品和定价
Excel 与 MS Office 工具捆绑,可以单独购买。
Tableau 拥有众多产品,如 Tableau Server、Tableau Online、Tableau Public Server、Tableau Desktop、Tableau Public Desktop、Tableau Reader、Tableau Mobile 和 Tableau Prep Builder,它们都有不同的用途。这些产品及其详细信息可在这里找到。
使用 Tableau Public,这是一个免费软件,任何人都可以将电子表格或文件连接到它,并为 web 创建交互式数据可视化。接下来,我们有 Tableau Reader,它也是免费的,允许你打开并与 Tableau 桌面中的可视化交互。
你可以访问 Tableau 的网站了解他们产品和价格的更多详情。
Power BI 也有一些产品,如 Power BI 桌面,Power BI 移动,Power BI 报表服务器等。他们所有的产品都可以在他们的网站上找到。
有关产品及其定价的更多信息,请参见下表:

作者图片
就价格而言,Power BI 通常是更实惠的选择。对于优先考虑免费试用功能的用户,Power BI 提供了强大的 60 天专业试用,而 Tableau 的免费试用为 14 天,Excel 应用程序不提供免费试用,除非付费。此外,Power BI 的起价为每个用户每月 9.99 美元,而 Tableau Explorer 的起价为 35 美元。
最后的裁决是什么?
在阅读了上述所有三个系统的比较之后,是时候通过问自己以下问题来决定您或您的组织需要什么了:
- 你的重点是数据处理还是数据可视化?
- 您或您的组织需要什么样的报告?
- 您多久创建一次报告?
- 你的预算怎么样?
Excel 非常适合创建快速、一次性的报告。虽然 Excel 是一个使用起来很强大的工具,但是创建和维护重复的报表、创建可视化和演示文稿以及深入查看数据的粒度视图都需要一些关于其功能的高级知识。
但是,选择哪一个取决于用户的业务规模和需求。
财力和人力资源有限的小型企业,如果正在寻求更经济实惠的商业智能解决方案,应该从 Power BI 开始。然而,优先考虑数据分析并拥有人力资本支持数据分析的中型和企业公司使用 Tableau 会更好。
牢记企业高管,Tableau 创建。其数据可视化和自助服务功能允许决策者调出报告或仪表板,并自由深入到信息的粒度级别。这种解决方案可能很昂贵,但是如果您正在创建许多必须快速更新的重复性报告,那么它是值得的。如果您的企业创建了更多的一次性报表,而不是更新定期报表,您可能需要考虑学习 Excel 的更多高级功能。Tableau 允许用户在其分析中集成无限数量的数据点,并提供全面的支持选项。
Power BI、Tableau 和 Excel 基于不同的意识形态和原则。因此,对我们来说,决定哪一个是最好的是具有挑战性的。根据我们的需求,我们可以选择我们需要的系统。
我希望这篇文章,以及上面提到的众多参数的比较,有助于你决定你需要在哪些方面投入时间和金钱。
谢谢你阅读它。
参考
[1] Excel 帮助和学习:https://support.microsoft.com/en-us/excel
[2]入门—Tableau:https://help . Tableau . com/current/pro/desktop/en-us/getting Started _ overview . htm
[3] Power BI 文档:https://docs . Microsoft . com/en-us/Power-BI/#:~:text = Power % 20BI % 20 amplifies % 20 your % 20 insights,how%20you%20use%20Power%20BI。
Excel 到 Python
为 Python 工具构建前端 Excel 工作簿

D 在 Build 2016 大会上,微软宣布全球有 12 亿人在使用 Excel [1]。同年,地球人口估计为 74 亿[2]。
那就是地球上所有人的 16.2%。
根据 2019 年的一份报告[3],Python 相比之下只有 820 万活跃开发者——占地球人口的 0.001%。
考虑到这些数字,鼓励 Excel 和 Python 之间更多的交互可能对我们有好处——为大量新用户打开 Python 构建的工具的闸门。
面向 Python 的 Excel 前端的机会是巨大的。在本文中,我们将看看如何做到这一点,并实现一个“典型的”财务 Excel 设置表。
先有工具,后有 Excel
在我能想到的几乎所有场景中,首先构建工具的 Python 部分会更方便。但是,我们必须保持工具“输入”格式的灵活性。

更改输入数据集格式不应破坏代码。
我的意思是,如果我们使用 Pandas 读取一个或两个 CSV/Excel 表——对于第一个原型,我们可能依赖于一组给定的列名。
但是,如果成千上万行代码,我们依赖于相同的硬编码值,当我们试图用 Excel 使这些输入列名动态化时,就会遇到问题。
因此,在初始原型阶段,如果还没有 Excel 表,使用代码的初始部分将列标签重命名为它们的内部(希望更具描述性)标签名称:
稍后,这将被我们的 Excel 表映射所取代。
Excel 前端
一旦 Python 工具被构建成一个更实际的原型,我们就该开始构建 Excel 前端了。首先,我们必须决定哪些变量可以从 Excel 工作表中进行调整。
总是在假设输入数据的格式会改变的情况下构建这些类型的工具。
根据您的工作地点和您正在开发的工具,这要么非常重要,要么不重要。一些过程只是被很好地定义,数据格式不太可能改变。
但是,我总是谨慎行事,通过 Excel 前端包含更多而不是更少的灵活性。别太复杂了。

使用 Excel 将内部 Python 列标签映射到外部 CSV/Excel 列标签。
使用内部命名系统并允许 Excel 用户指定列映射是保持灵活性的一个很好的例子。现在,Excel 用户可以调整这些映射,而不必依赖于硬编码的列名,甚至不用接触 Python。
映射
集成的核心是mappings字典。这将需要一个包含工具“设置”的 Excel 选项卡(我通常称之为映射)。
为了填充映射字典,我们需要读取 Excel mapping 选项卡的函数。为此,我们使用 openpyxl 。
我们可以从 Excel 的给定单元格中读取一个值,如下所示:
使用这个方法,我们现在可以开始填充我们的mappings字典。我们将调整上面的代码,将本地路径添加到“tool _ setup”Excel 工作簿。
我们还假设最初活动的工作表可能不是映射工作表,在添加、删除或移动选项卡的情况下,我们使用列表理解来查找“映射”选项卡索引:
现在我们可以添加一些映射:
mappings = {}
mappings['Amount'] = ws["E4"].value
mappings['Term'] = ws["E5"].value

保持灵活性
在从我们的 Excel mapping 选项卡中添加或删除行的情况下,这种方法将构建一个不正确的mapping字典。为了避免这种情况,我们使用了search_col功能。这将迭代地搜索一列中的每个单元格,直到找到包含我们想要的值的单元格(或者超出行limit)。
此时,search_col 返回包含我们想要查找的数据的列和行。


如果设置不正确,仅仅在一行中添加一个小的注释就可能破坏这个工具。左边 B12 单元格包含 Internal 字样,表示我们列映射表的表头行,右边是 B14 。
这允许我们通过在列 B 中搜索‘内部’来搜索列映射表,如下所示:
search_col(ws, 'B', 'Internal')
[Out]: ('B', 12)
从这里,我们可以创建一个循环,将从列 C 到列 E 的映射添加到我们的mappings字典中。一旦看到两个或更多的空白单元格,我们可以确信映射表已经结束,因此我们可以从循环中断开:
一旦运行这段代码,我们将得到一个类似于下面这样的 Python 字典mappings :
{
'Loan ID': 'loan identifier',
'Product': 'product type',
...
'Initial Fees': 'init fees'
}
如果我们还想引入其他变量,例如 filepath,它在映射表截图中显示为data/loanbook.csv。我们只需找到包含 ' 文件路径'的行,并提取列 D 中的相应值:
row, _ = search_col(ws, 'C', 'Filepath')
mappings['filepath'] = ws[f'D{row}].value

综合
最后一步也是最简单的,将这些新的列名集成到我们的 Python 脚本中。
让我们使用上面的映射表来读入数据,并将输入列标签转换为它们的内部标签。
data = pd.read_csv(mappings['Filepath'])
在将输入列标签转换为它们的内部标签之前,我们必须将键-值对交换为值-键对。
# invert the dictionary
inv_mappings = {mappings[key]: key for key in mappings}
尽管对于这个简单的例子来说,在构建mappings字典时这样做似乎更方便。对于更复杂的工具,我总是发现保持我们在这里使用的内部:外部映射格式更好。尽管如此,这个细节还是由你来决定。
最后,将输入标签转换为内部标签:
data.rename(inv_mappings, axis=1, inplace=True)
我们可以在这里增加更多的灵活性。为了避免前导/尾随空格或小写/大写输入错误,我们重写了这部分代码:
我想加入的另一个可选部分。当我们在 Excel 表中显示内部列标签时,它们是大写的,并且包含正常间距。然而,作为个人偏好,我在内部维护了 snake_case 格式,转换为:
"Loan ID" -> "loan_id"
"Initial Rate" -> "initial_rate"

我见过无数大量使用 Excel 的办公室,这些办公室可以节省数百个小时来检查复选框、键入值或等待 Excel 模型处理哪怕是最小的数据集。
虽然自动化和机器学习的时代正在迅速自动化许多 Excel 繁重的领域,但 Excel 不会很快走向任何地方。
目前,许多行业可以通过世界上发展最快的编程语言和世界上使用最多的软件之间的更紧密集成获得巨大的利益。
感谢阅读!
参考
[1] J. Osborne, Build 2016:来自第 1 天和第 2 天的最大新闻 (2016),techradar
[2]世界银行,总人口 (2019),世界银行公开数据
[3] M. Carraz,J. Stichbury,S. Schuermans,P. Crocker,K. Korakitis,C. Voskoglou,Developer Economis:the State of the Developer Nation(2019),SlashData
说到弥合不同技术之间的差距,我写过一篇关于用 Python 为 SQL 增压的文章。请点击这里查看:
[## 用 Python 为 MS SQL Server 增压
如何使用 Python 来自动化 SQL 的一切
towardsdatascience.com](/supercharging-ms-sql-server-with-python-e3335d11fa17)
Excel 的限制导致了 16,000 个阳性 COVID 病例的丢失
追踪人员漏掉了 50,000 名潜在的感染者,却没有告诉他们进行自我隔离

米卡·鲍梅斯特在 Unsplash 上的照片
缺失数据
如果你打开一个 Excel 文件,滚动到底部(提示: CTRL +南箭头),你会发现它的结尾是 1,048,576。一行也不能多。
据《卫报》报道,英国公共卫生部将 15841 例阳性 COVID 测试结果的丢失归咎于这一限制。反过来,根据每个非复杂病例有 3 名密切接触者的估计,这导致至少 47,000 名潜在感染者未被告知并被要求自我隔离,并可能被追踪。这一数字可能超过 50,000,因为据报道,15,841 例失踪阳性病例中有少数是复杂的,即来自医院、监狱、无家可归者收容所等环境,这些环境平均有 7 名密切接触者。
它是如何发生的
英国公共卫生(PHE)组织收集公共和私人实验室的结果。正如《卫报》所报道的,一个实验室已经把它的日常测试报告作为 CSV 文件发送给了 PHE。然后,PHE 将实验室的结果与从其他实验室获得的结果合并到 Excel 中。然后,本组织将报告官方数字,并对追踪和通报个人阳性病例采取后续行动。
然而,似乎手边的实验室已经在 PHE 数据表的 100 多万行中了。添加另一个每日批次导致一些结果被截断,因此没有报告和采取行动。
如何预防
Excel 是一个非常受欢迎的工具。它可以用于多种任务,而这些任务与它的初衷相去甚远:一个电子表格。它的易用性也意味着它是可访问的,因此许多用户远不是超级用户,不知道也不遵循好的实践。我会想到一些建议:
- 实施检查和平衡,例如在导入之前和之后验证记录的数量,将很容易消除这种事件,
- 关于 Excel 局限性的提醒或信息会议,针对在关键部门工作的用户,
- 或者,使用另一个工具,一个可以绕过一百万行限制的工具。使用 SQL Server 可以快速处理这项工作。但是,在时间和资源短缺的疫情,向报告和跟踪案件的团队引入新软件的前景是不可取的。这种介绍也可能通过电话会议而不是面对面进行,这是另一个缺点。
以前发生过
2012 年,一个 Excel 错误导致摩根大通亏损 60 亿美元。他们在报告中描述了这个错误:
在审查过程中,更多的业务问题变得很明显。例如,该模型通过一系列 Excel 电子表格运行,这些表格必须通过从一个电子表格向另一个电子表格复制和粘贴数据的过程手动完成。
此外,据 Business Insider 当时报道:
有证据表明,由于这种压力,模型审查小组加快了审查,这样做可能更愿意忽略批准过程中明显的操作缺陷。
其他昂贵的活动 were⁴:
- TransAlta 因复制粘贴错误损失了 2400 万美元,
- 柯达因遣散费打印错误损失 1100 万美元,
- 伦敦奥运会花样游泳比赛超售了 2 万张门票,比赛还有 1 万个剩余座位,
在每种情况下,手动操作都是错误的原因。

迈克尔·斯科特在办公室——Gif 发自男高音
我爱你,但你有缺点
Excel 是一个伟大的工具,但也有难以忽视的缺陷。首先想到的自然是它的 100 万行的限制,尽管它的主要目的不是作为一个接近大数据的工具。
- 它也缺乏一个可审计的概述。任何人都可以有意或无意地调整未锁定的文件。即使上锁,也缺乏控制和安全性,容易受到欺诈或腐败。
- 很难排除故障或进行测试,
- 难以整合并且不是为协作工作而设计的,尽管近年来在这方面有所改进,
- 缺乏权威来源。许多员工可能正在使用同一文件的不同快照,但是具有不同的值,
这只是列举了几个例子。
后果
Excel 首先承担了责任,PHE 组织引用了一个 IT 问题。软件本身对它的能力是直截了当的,无论谁想知道,列和行的数目都会显示出来。后来发现人为错误也是原因之一。PHE 组织将于明年 3 月解散,这一宣布发生在 cases⁵.失守之前
如果这个故事提醒了我们一个重要的因素,那就是需要为手头的工作使用正确的工具,保持对细节的高度关注,以及经理或领导者确保关键用户得到适当的装备来完成他们的工作。
希望每一个相关的案件都会有好的结果。
快乐的数据争论!
感谢阅读!喜欢这个故事吗? 加入媒介 获取完整的我的所有故事。
参考
[1] Alex Hern (2020),"Excel 如何可能导致英格兰 16000 次 COVID 测试的丢失",https://www . the guardian . com/politics/2020/oct/05/How-Excel-may-have-induced-loss-of-16000-COVID-tests-in-England
[2]乔希·哈利迪,丹尼斯·坎贝尔,彼得·沃克和伊恩·萨姆特(2020),“英格兰 COVID 病例错误意味着 5 万个接触者可能没有被追踪到”,https://www . the guardian . com/world/2020/oct/05/England-COVID-cases-error-unknown-how-many-contacts-not-tracted-says-minister
[3] Linette Lopez (2013),“伦敦鲸的崩溃如何部分是使用 Excel 的错误的结果”,https://www . business insider . com/Excel-部分归咎于交易损失-2013-2?IR=T
[4] Teampay (2018),"有史以来最大的 7 个 Excel 错误"https://www . Teampay . co/insights/maximum-Excel-errors-of-All-Time/
[5]丹尼斯·坎贝尔(2020),“废除公共卫生英格兰只是‘转嫁冠状病毒错误的责任’”,https://www . the guardian . com/world/2020/aug/19/废除公共卫生英格兰只是转嫁冠状病毒错误的责任
Python 中的异常处理
Python 中异常处理的介绍

异常处理是以编程方式响应需要特殊处理的异常情况的方法。在 python 中,为各种各样的错误类型实现异常处理是非常简单的。在本帖中,我们将讨论如何在 python 中实现异常处理。
我们开始吧!
首先,让我们考虑下面的整数列表:
my_list1 = [1, 2, 3, 4, 5]
我们可以遍历列表并使用“for-loop”打印元素:
for value in my_list1:
print(value)

在“for-loop”中,我们还可以执行操作并打印结果。让我们计算每个元素的平方并打印结果;
for value in my_lis1t:
square = value**2
print(value, square)

假设我们的列表也包含字符串值“6”:
my_list2 = [1, 2, 3, 4, 5, '6']
让我们试着计算这个新列表中每个元素的平方。这将返回一个“类型错误”:
for value in my_list2:
square = value**2
print(value, square)

该错误指定了有问题的代码行:
square = value**2
引发了“TypeError”,因为“”幂运算符不支持操作数“str”。假设我们希望我们的代码能够处理字符串值的整数而不抛出错误。这就是异常处理发挥作用的地方。我们可以使用 python 关键字 try 和 except 来处理“类型错误”。首先,让我们尝试**平方并打印每个值:
for value in my_list2:
try:
square = value**2
print(value, square)
当我们得到一个“类型错误”时,我们使用 except 关键字来处理“类型错误”。由于字符串包含数值,我们可以使用' int()'方法将字符串转换为整数,并计算异常内的平方:
for value in my_list2:
try:
square = value**2
print(value, square)
except(TypeError):
square = int(value)**2
print(value, square)

值得注意的是,我们处理错误的方式很大程度上取决于错误类型和我们正在处理的数据类型。
接下来,假设我们的列表包含一个单词或类似列表的另一种类型。我们希望能够处理这些错误,而不让我们的代码产生任何输出。让我们考虑以下包含字符串' ## '的列表:
my_list3 = [1, 2, 3, 4, 5, '##']
如果我们尝试循环这个新列表并计算其平方,我们会得到一个“ValueError”:
for value in my_list3:
try:
square = value**2
print(value, square)
except(TypeError):
square = int(value)**2
print(value, square)

这个错误是说我们不能将字符串“##”转换成整数。我们需要为这种错误类型编写额外的处理。例如,我们可以用一些填充值替换字符串,如 0 或“NaN”:
import numpy as np
for value in my_list3:
try:
square = value**2
print(value, square)
except(TypeError):
square = np.nan
print(value, square)

让我们考虑另一个异常处理的例子。假设我们有以下包含编程语言的字符串列表:
my_list4 = ['python c++ java', 'SQL R scala', 'pandas keras sklearn']
我们可以使用“split()”方法来拆分字符串,并使用“+”运算符添加文本“is awesome ”:
for value in my_list4:
print([i +' is awesome' for i in value.split()])

由于“split()”方法是一个字符串对象方法,如果我们的列表中有非字符串值,将会引发“AttributeError”。让我们在列表中添加一个字典,然后再次运行我们的代码:
my_list4 = ['python c++ java', 'SQL R scala', 'pandas keras sklearn', {'language': ''golang'}]
for value in my_list4:
print([i +' is awesome' for i in value.split()])

该错误指出“dict()”对象没有属性“split()”。让我们编写一些 try/except 逻辑来处理这个错误:
my_list4 = ['python c++ java', 'SQL R scala', 'pandas keras sklearn', {'language': 'golang ruby julia'}]
for value in my_list4:
try:
print([i +' is awesome' for i in value.split()])
except(AttributeError):
print([i +' is awesome' for i in value['language'].split()])

我就讲到这里,但是我鼓励你自己去研究代码。
结论
总之,在这篇文章中,我们讨论了 python 中的异常处理。我们展示了如何使用 try/except 关键字和错误类型来处理数据中的错误值。我们看看处理“类型错误”和“属性错误”的例子。我鼓励您研究其他错误类型以及如何处理它们。附加的错误类型包括“SyntaxError”、“ZeroDivisionError”、“FileNotFoundError”等等。我希望你觉得这篇文章有用/有趣。这篇文章中的代码可以在 GitHub 上找到。感谢您的阅读!
Python 异常和异常处理初学者指南
Python 中的异常处理是通过使用 try except 子句来完成的

照片由 Hitesh Choudhary 在 Unsplash 上拍摄
介绍
在本教程中,我们将学习如何使用 try except 子句在 Python 中处理异常。
但是首先,什么是例外?🤔
异常是当代码的执行导致意外结果时,由我们的代码引发的错误。通常,异常会有一个错误类型和一条错误消息。一些例子如下。
ZeroDivisionError: division by zero
TypeError: must be str, not int
ZeroDivisionError和TypeError是错误类型,冒号后的文本是错误消息。错误消息通常描述错误类型。
每一个好的代码和应用程序都会处理异常,以保持用户体验的流畅和无缝。那么,让我们来学习如何做到这一点,好吗?🙂
内置异常
在 Python 中,所有内置的异常都是从BaseException类中派生出来的。直接继承BaseException类的异常类有:Exception、GeneratorExit、KeyboardInterrupt和SystemExit。在本教程中,我们将重点关注Exception类。
在许多情况下,我们希望定义自己的自定义异常类。这样做的好处是,我们可以通过用甚至非程序员也能理解的简单英语来指出程序中出现的错误。
要定义一个定制的异常类,我们需要从Exception类继承,而不是像官方 Python 3 文档中建议的那样从BaseException类继承。
酷毙了。现在我们对异常有了一些基本的了解,让我们来看一些例子。
常见例外
现在,我们将看看在学习 Python 编程时可能遇到的一些最基本和最常见的异常。
值错误
当我们传入一个正确类型的值,但该值是错误的时,就会引发这个异常。举个例子,假设我们想把一个字符串转换成一个整数。
int("5") // 5
这很好,对吧?现在,看看当我们传递一个不能转换成整数的字符串时会发生什么。
int("five")Traceback (most recent call last):
File "<input>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'five'
现在说得通了吧?在第二个例子中,尽管参数的类型是好的,但是值是不正确的。
索引错误
这个异常告诉我们,我们正试图通过超出范围的索引来访问集合中的项目或元素(例如,字符串或列表对象)。
some_list = [1, 2, 3, 4]
some_list[5]Traceback (most recent call last):
File "<input>", line 1, in <module>
IndexError: list index out of range
在这个例子中,some_list的最大索引是 3,我们要求程序访问索引为[5]的元素。因为该索引不存在(或者超出范围),所以抛出IndexError异常。
类型错误
与ValueError不同,当我们传递给函数或表达式的参数或对象的类型是错误的类型时,就会引发这个异常。
100 + "two hundred"Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
这里的错误信息非常清楚。它告诉我们+操作符不能用于类型为int和str的对象。
名称错误
每当我们试图使用一个不存在或尚未定义的变量时,就会抛出这个异常。
a = "defined"print(b)Traceback (most recent call last):
File "<input>", line 1, in <module>
NameError: name 'b' is not defined
同样,错误信息非常清楚。这个不用多解释了。🙂
还有许多更常见的异常,但我希望这已经是足够的例子了。
现在,你可能会问,写着Traceback (most recent call last)的前几行是什么?好吧,让我们在下一节讨论一下。

回溯(或堆栈跟踪)
在上一节的所有示例异常中,有一点值得一提,那就是异常类型和消息之前的部分。这部分被称为回溯或堆栈跟踪。
Traceback (most recent call last):
File "<input>", line 1, in <module>
当我们的代码比上面的例子复杂得多时,这是很有用的,我敢打赌一定会如此,尤其是我们的应用程序代码。回溯或堆栈跟踪本质上告诉我们代码执行的顺序,从最新的(顶部)到最早的(底部)。
让我们看一些来自 Python 官方文档的例子。
Traceback (most recent call last):
File "<doctest...>", line 10, **in** <module>
lumberjack()
File "<doctest...>", line 4, **in** lumberjack
bright_side_of_death()
IndexError: tuple index out of range
这里,回溯告诉我们导致IndexError异常的最后一次代码执行位于第 10 行,特别是在调用lumberjack()函数时。
它还告诉我们,在调用lumberjack()函数之前,我们的程序从第 4 行开始执行bright_side_of_death()函数。
在真实世界的应用程序中,我们的代码由许多模块组成,回溯将有助于调试。因为它指导我们哪里出了问题,在哪里以及执行的顺序。
用户定义的异常
如前所述,Python 允许我们定义自己的定制异常。为此,我们需要定义一个继承了Exception类的类。
class MyCustomException(Exception):
def __init__(self, code, message):
self.code = code
self.message = message
在讨论这个问题的同时,让我们看看如何在代码中引发一个异常。我们现在将定义一个抛出MyCustomException的函数。
def process_card(card_type):
if card_type == "amex":
raise MyCustomException("UNSUPPORTED_CARD_TYPE", "The card type used is not currently supported.")
else:
return "OK"
现在,让我们通过传递"amex"作为参数来调用process_card,这样它将抛出MyCustomException。
process_card("amex")Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 3, in process_card
MyCustomException: ('UNSUPPORTED_CARD_TYPE', 'The card type used is not currently supported.')
完美!因此,为了从我们的代码中抛出一个异常,要使用的关键字是raise关键字。
好了,我希望现在你已经很好地理解了什么是异常,尤其是在 Python 中。接下来,我们要学习如何处理它。

Andrés Canchón 在 Unsplash 拍摄的照片
用 Try Except 子句处理异常
Python 为我们提供了 try except 子句来处理代码可能引发的异常。try except 子句的基本结构如下。
try:
// some codes
except:
// what to do when the codes in try raise an exception
简单地说,try except 子句基本上是在说,“尝试这样做,除非有错误,然后改为这样做”。
对于如何处理从try块抛出的异常,有几个选项。我们来讨论一下。
重新引发异常
让我们看看如何编写 try except 语句,通过重新引发异常来处理异常。
首先,让我们定义一个函数,它接受两个输入参数并返回它们的和。
def myfunction(a, b):
return a + b
接下来,让我们将它包装在一个 try except 子句中,并传递错误类型的输入参数,这样函数将引发TypeError异常。
try:
myfunction(100, "one hundred")
except:
raiseTraceback (most recent call last):
File "<input>", line 2, in <module>
File "<input>", line 2, in myfunction
TypeError: unsupported operand type(s) for +: 'int' and 'str'
这与我们不在 try except 子句中包装函数的情况非常相似。
捕捉某些类型的异常
另一个选择是定义我们想要具体捕捉哪些异常类型。为此,我们需要将异常类型添加到except块中。
try:
myfunction(100, "one hundred")
except TypeError:
print("Cannot sum the variables. Please pass numbers only.")Cannot sum the variables. Please pass numbers only.
酷毙了。它开始变得更好看了,不是吗?
现在,为了更好,我们实际上可以记录或打印异常本身。
try:
myfunction(100, "one hundred")
except TypeError as e:
print(f"Cannot sum the variables. The exception was: {e}")Cannot sum the variables. The exception was: unsupported operand type(s) for +: 'int' and 'str'
很好。🙂
此外,如果我们想以同样的方式处理这些异常类型,我们可以在一个except子句中捕获多个异常类型。
让我们将一个未定义的变量传递给我们的函数,这样它将引发NameError。我们还将修改我们的except块来捕获TypeError和NameError,并以同样的方式处理任一异常类型。
try:
myfunction(100, a)
except (TypeError, NameError) as e:
print(f"Cannot sum the variables. The exception was {e}")Cannot sum the variables. The exception was name 'a' is not defined
注意,我们可以添加任意多的异常类型。基本上,我们只需要传递一个包含类似(ExceptionType1, ExceptionType2, ExceptionType3, ..., ExceptionTypeN)的异常类型的tuple。
通常,我们会有另一个没有特定异常类型的except块。这样做的目的是捕捉未处理的异常类型。一个用例是当向第三方 API 发出 Http 请求时,我们可能不知道所有可能的异常类型,但是,我们仍然希望捕捉并处理它们。
让我们修改我们的 try except 块,以包含另一个 except 块,该块将捕获其余的异常类型。
try:
myfunction(100, a)
except (TypeError, NameError) as e:
print(f"Cannot sum the variables. The exception was {e}")
except Exception as e:
print(f"Unhandled exception: {e}")
如果我们的函数引发了除TypeError和NameError之外的任何异常,它将转到最后一个except块并打印Unhandled exception: <unhandled exception here>。

包裹
哇!大家学习 Python 中的异常和异常处理做得很好。我希望那不是太糟糕😆
如您所知,我们仍然可以通过添加else和finally块来扩展我们的 try except 子句。在未来的教程中会有更多的介绍。或者你想自己看,可以去看看这个教程。
一如既往,请随意发表任何评论或提出任何问题。🙂
汇率预测:具有 5 个回归模型的机器学习
在数据清理和可视化之后,这一部分使用机器学习来寻找适合所有数据点的最佳直线,为最终部分的预测做准备。

来源:https://unsplash.com/photos/7JoXNRbx6Qg
如果你错过了我的第一部分关于汇率预测的端到端项目,请随时查看这里的。
概括地说,该项目旨在分析不同国家货币对美元汇率的历史模式,从而预测 2020 年的汇率值。为了得到最好的模型,我把这个项目分成了三个部分,我希望这三个部分能够涵盖预测所需的内容:
- ****第 1 部分:解释性数据分析(EDA) &数据可视化(奖励:假设检验)
- 第二部分:具有 4 个回归模型的机器学习
- 第三部分:机器学习(续)与 ARIMA
今天,我将带你看第二部分,它部署了机器学习,目的是找到最适合多年来汇率模式的线。也就是说,线性回归似乎是正确的模型,或者至少是我们分析的基础。除此之外,在决定使用哪个模型进行预测之前,我还测试了其他线性回归模型(第 3 部分):
- 线性回归
- 多元线性回归
- 多项式回归
- 岭回归(L2 正则化)
- 拉索回归(L1 正则化)
我们开始吧!
根据 Investopedia,有 3 种预测汇率的常用方法:购买力平价(PPP)、相对经济实力和计量经济模型。在这三种方法中,我决定选择第三种,因为它涉及到影响汇率变动的众多因素。
使用货币汇率预测可以帮助经纪人和企业做出明智的决策,以帮助最小化风险…
www.investopedia.com](https://www.investopedia.com/articles/forex/11/4-ways-to-forecast-exchange-rates.asp)
“计量经济模型中使用的因素通常基于经济理论,但任何变量****都可以加上,如果认为它会显著影响汇率。”——Investopedia,作者 Joseph Nguyen。
这种方法与使用“任何独立变量”对因变量产生影响的方向——线性回归非常一致。因此,我想测试的因素是利率差、 GDP 增长率和收入增长率**,顺序但累积。对于这个项目,我使用澳元/美元的汇率进行分析。****
1.线性回归
让我们以一个独立变量开始我们的线性回归模型:利率差。如果你热衷于探索,可以参考这个数据来源。
**ir_df = pd.read_csv("aud usd interest carry trade.csv")
ir_df.head()**

以上是 2017-2019 年澳元/美元利率差表。如果你想更多地了解什么是“多头套利”和“空头套利”,可以查看 Investopedia 上关于套利交易的这篇文章,以及 FXCM 上关于利率套利交易的另一篇文章。简言之,
利率套利交易是一种套利形式,其中有人利用两个市场之间的差异来获利。
因此,让我们转换这些数据进行分析(在这种情况下,我使用长期套利利率):
**x_ir = ir_df['Long Carry'].astype(str)
x_ir = x_ir.replace({'%':''}, regex = True)
x_ir = x_ir.astype(float)
x_ir = np.array(x_ir).reshape(-1,1)aud_usd_fx = df_groupby_aud[(df_groupby_aud['month_year'] >= '2017-01') & (df_groupby_aud['month_year'] <='2019-12')].reset_index(drop=True)
aud_usd = aud_usd_fx['AUD_USD']y_fx = aud_usd**
这里, x_ir 是指影响我们汇率的自变量。为了更容易使用,我用 regex 替换去掉了数字中的“%”,并将它们转换为 float。由于回归模型中需要 2D 阵列数据,我们需要使用将我们的 1D x_ir 转换为 2D。整形(-1,1)。如果您还记得第一部分,我们已经清理了整个数据集,因此现在我们可以更容易地选择澳元/美元数据(y_fx)作为因变量。
请注意,为了简单起见,我在这个项目中只用了很短的一段时间(从 2017 年到 2019 年,36 个月)。
好了,让我们通过从 Scikit-learn 库中导入相关函数来运行我们的第一个机器学习模型!
**from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression**
您可能已经知道,为了测试我们模型的准确性,我们被建议将数据集分成训练集和测试集。本质上,我们在训练集上训练模型,然后用测试集预测值。
**x_train, x_test, y_train, y_test = train_test_split(x_ir, y_fx, train_size=0.8, test_size=0.2, random_state=1)model = LinearRegression()
model.fit(x_train, y_train)
y_predict = model.predict(x_test)print(model.score(x_train, y_train))
print(model.score(x_test, y_test))**
这里我把数据拆分成 80%的训练和 20%的测试,意思是模型会通过 80%的训练数据学习模式,然后用 20%的测试数据预测 y 值。。score() 告诉我们因变量(汇率)被自变量(利率差)或我们所知的 R 平方解释的百分比。

如您所见,训练和测试数据之间的百分比非常接近,这意味着模型的准确性相对较好。
然而,根据我的观察,数据集的大小相对较小(n=36,因为我们只覆盖 2017 年到 2019 年),为了简单起见,我想看看我是否能够不将数据分成训练集和测试集。
**model = LinearRegression()
model.fit(x_ir, y_fx)
y_fx_predict = model.predict(x_ir)print(model.score(x_ir, y_fx))**

分割和不分割之间的 R 平方差异极小,这可能是由于数据集较小。因此,我将而不是分割数据并使用整个数据集。
让我们看看我们的模型在创建“最佳拟合”线方面表现如何:
**month_year = aud_usd_fx['month_year']
month_year = month_year.astype(str)plt.figure(figsize=(12,6))
plt.scatter(month_year, y_fx, alpha=0.4)
plt.plot(month_year, y_fx_predict)
plt.title("Linear Regression: AUD/USD Exchange Rate (1 var: Interest Rate)")
plt.xlabel("Month-Year")
plt.ylabel("Exchange Rate")
plt.xticks(fontsize=4)
plt.show()**

结合 R 平方,该线似乎可以在一定程度上刻画汇率(R 平方为 72%)。让我们添加另一个变量,用多元线性回归来看看我们的 R 平方提高了多少。
2.多元线性回归
正如本文开头所分享的,我们能够向模型中添加额外的变量,只要它们对因变量有影响。这就引出了第二个线性回归模型,它包含多于 1 个自变量。
我们把 GDP 增长率加到我们的数据集中,可以从这个域找到。
**aus_gdp = pd.read_csv("AUS GDP.csv")
usa_gdp = pd.read_csv("USA GDP.csv")aus_gdp = aus_gdp.rename(columns={'GDP': 'AUS_GDP'})
aus_usa_gdp = pd.merge(aus_gdp, usa_gdp, on="month_year", how="inner")
aus_usa_gdp = aus_usa_gdp.rename(columns={'GDP': 'USA_GDP'})
aus_usa_gdp['GDP_diff'] = aus_usa_gdp['AUS_GDP'] - aus_usa_gdp['USA_GDP']aus_usa_gdp_20172019 = aus_usa_gdp[(aus_usa_gdp['month_year'] >= '2017-01') & (aus_usa_gdp['month_year'] <='2019-12')].reset_index(drop=True)gdp_diff = ["%.4f" %num for num in aus_usa_gdp_20172019['GDP_diff']]**
加载完数据后,我应用 EDA 进行清理,将数据帧中的 gdp_diff 提取到一个列表中,以便与 x_ir 变量结合起来进行多元线性回归。
**x_ir_gdp = np.array(list(zip(x_ir, gdp_diff)))
x_ir_gdp = x_ir_gdp.astype(np.float)model.fit(x_ir_gdp, y_fx)
y_fx_predict_2 = model.predict(x_ir_gdp)print(model.score(x_ir_gdp, y_fx))**
在模型中加入另一个变量后,R 平方有了相当显著的提高,从 72%提高到 87.2%。让我们直观地将其与我们创建的第一行进行比较:

看起来不错,对!好吧,让我们尝试向我们的模型添加另一个独立变量,消费者价格指数(CPI)。同样,数据集可以从这个域中找到。
**cpi = pd.read_csv("aus usa cpi difference.csv")cpi_diff = cpi['CPI_diff']x_ir_gdp_cpi = np.array(list(zip(x_ir, gdp_diff, cpi_diff)))
x_ir_gdp_cpi = x_ir_gdp_cpi.astype(np.float)model.fit(x_ir_gdp_cpi, y_fx)
y_fx_predict_4 = model.predict(x_ir_gdp_cpi)print(model.score(x_ir_gdp_cpi, y_fx))**
这一次,R 平方确实略有增加,从 87.2%增加到 87.3%。这意味着 CPI 不会显著影响汇率的变动,也不会有助于改进我们的模型。视觉上,也没什么区别。

让我们用另一个变量——失业率(UER)代替 CPI 变量,看看这是否能改进我们的模型。
**unemployment_rate = pd.read_csv("aus usa unemployment rate.csv")unemployment_rate['uer_diff'] = unemployment_rate['aus_unemployment rate'] - unemployment_rate['usa_unemployment rate']
uer_diff_all = unemployment_rate['uer_diff']uer_diff = ["%.4f" % num for num in uer_diff_all]x_ir_gdp_uer = np.array(list(zip(x_ir, gdp_diff, uer_diff)))
x_ir_gdp_uer = x_ir_gdp_uer.astype(np.float)model.fit(x_ir_gdp_uer, y_fx)
y_fx_predict_3 = model.predict(x_ir_gdp_uer)print(model.score(x_ir_gdp_uer, y_fx))**
好的,R 平方提高了一点,从 87.2%提高到 88.9%。从统计和视觉上看,还不错。您可以继续向模型中添加更多的变量,但要小心过度拟合!

对我来说,我没有添加更多的自变量,而是决定测试另一个回归模型来找到更好的拟合线:多项式回归。
3.多项式回归
什么是多项式回归?它仍然是一种线性回归,但是是一个更“适应”的版本。
传统上,线性回归旨在找到适合所有数据点的最佳线性线,但情况可能并不总是如此。因此,多项式回归充当从坐标(x,y)绘制直线的另一种形式,将 y 建模为 n 次多项式 。
让我们从 Sciki-learn 库中导入函数并构建我们的模型:
**from sklearn.preprocessing import PolynomialFeaturespoly = PolynomialFeatures(degree=4)x_poly = poly.fit_transform(x_ir_gdp_uer)model_poly = LinearRegression()
model_poly.fit(x_poly, y_fx)
y_pred = model_poly.predict(x_poly)print(model_poly.score(x_poly, y_fx))**
线性回归和多项式回归在函数上的唯一区别是次数参数。在得出结果之前,我先简单说明一下:。fit_transform() 就是把你的自变量从线性转换成多项式。函数的其余部分保持不变。
在这里,我随机选择了 4 和 R 的平方接近完美的程度:99.9%!你可能想直观地看到它?

黑线表示多项式回归找到的拟合度为 4。有多神奇?但问题是:“哪个程度是最好的,既不会过拟合也不会欠拟合数据?”
我们知道我们的目标是找到尽可能高的 R 平方,因为它很好地解释了因变量(汇率)受自变量影响的事实。除此之外,还有另一个指标能够评估我们模型的准确性:均方误差(MSE)。
为了找到最佳的度数,我决定在我们的模型上分别用 a for loop 测试一个度数范围,从 1 到 10,并将其可视化:
**from sklearn.metrics import mean_squared_errorr_squared_list = []
mse_list = []
a = range(1,10,1)for i in a:
poly = PolynomialFeatures(degree=i)
x_poly = poly.fit_transform(x_ir_gdp_uer)
model_poly = LinearRegression()
model_poly.fit(x_poly, y_fx)
y_pred = model_poly.predict(x_poly)
r_squared = model_poly.score(x_poly, y_fx)
mse = mean_squared_error(y_pred, y_fx)
r_squared_list.append(r_squared)
mse_list.append(mse)**

正如您在两个图表中看到的,随着直线从 1 度增加到 4 度,R 平方和 MSE 显著提高(R 平方越高越好,MSE 越低越好)。然而,它在 4 度时达到峰值,并且从 5 度开始没有看到进一步的改善。这意味着 4 度为我们的模型带来了最好的准确度分数!所以我们还是坚持用 4 吧!
耶!多亏了多项式回归,我们终于得到了最符合历年汇率的直线!
4.& 5.岭回归和套索回归
这最后两个是我在线性回归模型的“生态系统”中的最新实验,我以前在某个地方听说过。哦,是的,它关系到 L1 和 L2 的正规化!因此,我想在我的项目中测试这两个模型,看看它们与上述模型相比表现如何。
然而,在进入它们之前,让我们快速指出这些模型的起源,正则化,以及它们在我们通常所知的线性回归中扮演的角色。
这一切都是从超配开始的。简而言之,当机器学习模型过于适合某个数据集(特别是有太多独立变量/特征)并因此无法推广到其他数据集时,就会发生过度拟合。因此,引入了规则来防止这种现象。本质上,规范化的作用是:
- 降低模型的复杂性,同时保持独立变量/特征的数量
- 从技术上讲,减少系数的大小作为损失函数的惩罚项
如果你想深入了解它是如何工作的,从数学上来说,查看这篇关于走向数据科学的文章,了解更多细节。
岭回归和套索回归就是从这种正则化概念发展而来的。两者的唯一区别是:
- 岭回归使用 L2 正则化技术,将系数缩小到零,但不是绝对零****
- 套索回归使用 L1 正则化技术,将系数缩小到绝对零****
这是因为 Ridge 保留了所有变量/特征 ,而 Lasso 只保留了重要的变量/特征,因此当我们的数据集有太多变量/特征时,它被选为变量/特征选择技术。
好了,回到我们的数据集!
尽管我们的模型没有太多的变量(在本例中是 3),我仍然想看看岭和套索回归在我的数据集上的表现。
**from sklearn.linear_model import Ridge, Lassoridge = Ridge(alpha=0.001)
ridge.fit(x_ir_gdp_uer, y_fx)y_fx_ridge = ridge.predict(x_ir_gdp_uer)
print(ridge.score(x_ir_gdp_uer, y_fx))lasso = Lasso(alpha=0.001)
lasso.fit(x_ir_gdp_uer, y_fx)y_fx_lasso = lasso.predict(x_ir_gdp_uer)
print(lasso.score(x_ir_gdp_uer, y_fx))**

山脊的 r 平方是 88%,而套索是 87%。当我们将这些数字与我们的多元线性回归(88.9%)进行比较时,还不算太坏。这证明我们的模型没有出现过拟合!
哇!这是这个项目第二部分的总结!吸收太多了,不是吗?但是我真的希望你已经发现这篇文章的信息和可操作性。
简而言之,我们已经找到了最符合我们的数据集的直线,极大地解释了多年来的汇率模式!下一步是什么?
再次提醒,请注意我项目的最后一部分,它将涵盖我如何使用我们刚刚发现的回归线预测 2020 年的汇率。与此同时,如果您觉得这有帮助,请给我一个掌声,并在这里随意查看我的 Github 以获得完整的资源库:
github:https://github.com/andrewnguyen07LinkedIn:www.linkedin.com/in/andrewnguyen07
谢谢!
汇率预测:用 ARIMA 进行时间序列预测
利用之前的回归工作,这最后一部分旨在使用 ARIMA 预测未来汇率,这是一种“从过去预测未来”的机器学习算法。

来源:https://unsplash.com/photos/6EnTPvPPL6I
我的数据科学端到端项目的最后部分来了。如果您遵循或阅读了前两部分,您可能已经知道本文中会出现什么。但是如果你还没有,不要犹豫去看看它们: 第一部分 和 第二部分 。
以下是这个项目整体结构的总结:
- 第 1 部分:解释性数据分析(EDA) &数据可视化(奖励:假设检验)
- 第二部分:4 个回归模型的机器学习
- 第三部分:机器学习(续。)与 ARIMA
第一部分通过数据清理和可视化为分析奠定基础,第二部分采用回归模型拟合所有数据点,最后一部分将利用它们来预测未来(在这种情况下,是 2020 年的澳元/美元汇率)。为了做到这一点,应考虑先决条件和流程:
- 静态测试(ADF 和 KPSS)
- 自相关(ACF)和部分自相关(PACF)
- ARIMA 天气预报
我们开始吧!
在开始之前,您可能想知道为什么在使用 ARIMA 之前我们需要遵循上面提到的结构。如果是,让我们简单了解一下 ARIMA 是什么,需要什么优先!
0.简而言之 ARIMA
ARIMA 代表什么?
在预测时间序列时,我们可以选择:
- 单变量:如果我们相信时间序列的先前值能够预测其未来值
- 多变量:如果我们使用预测器而不是序列本身来预测未来值
在这种情况下,ARIMA 代表‘自回归综合移动平均’,这种算法源于这样一种信念,即时间序列的 过去值可以单独用于预测未来值 。
要使用 ARIMA,我们需要确定它的参数值:p,d,q
- p:AR 项的阶数(AR:自回归)
- d:差异的数量
- 问:移动平均线的顺序
这几乎是你熟悉下面将要发生的事情所需要的全部信息。
1.静态测试
什么是静态测试,我们为什么需要它?
ARIMA 要求数据集是“稳定的,这样模型才能产生准确的预测。简而言之,从技术上讲,平稳序列不会随时间而变化。特别是,均值、方差、协方差等参数随时间保持不变。
为了更直观地展示它,我们来看看下面的图表,看看平稳数据和非平稳数据之间的区别:

来源:https://en.wikipedia.org/wiki/Stationary_process
如您所见,这并不意味着数据集在任何特定时间点都是“冻结”的。它确实发生了变化,但随着时间的推移,其均值和方差保持不变(图 1)。与相反,如果看到这种不寻常的峰值或谷值(没有清晰的模式),这意味着数据集及其统计属性会随着时间而变化(图 2)。众所周知,这是由于趋势或季节性对数据集的影响。
如果你想探究这两者在数学上的区别,可以看看这篇关于数据科学的文章:
平稳性的概念和类型综述
towardsdatascience.com](/stationarity-in-time-series-analysis-90c94f27322)
静态数据很重要,因为模型更容易学习模式,我们也更容易分析和预测模式,这已经成为大多数时间序列分析中的一个常见假设。
话虽如此,我们如何知道数据集是否是静态的呢?首先,我们可以依靠统计测试来检查平稳性,如果不是,我们需要将数据从非平稳转换为平稳。
ADF (增广的迪基-富勒)和 KPSS (科维亚特科夫斯基-菲利普斯-施密特-申)是两种常见的平稳性统计测试。这两个测试的目的在技术上是相同的,只是后面使用的技术不同。ADF 使用差分来转换数据集, KPSS 移除趋势使数据稳定。因此,建议使用这两种测试来确保预期的结果。
然而,需要注意的一点是,H0(零假设)和 H1(替代假设)的两个检验是彼此相反的:
- ADF: H0 声称数据集是而不是静止的,而 H1 说它是静止的。
- KPSS : H0 声称数据集是静止的,而 H1 却说它是而不是。
from statsmodels.tsa.stattools import adfulleradf_test = adfuller(y_pred)
print('stat=%.3f, p=%.3f' % adf_test[0:2])
if adf_test[1] > 0.05:
print('Probably not Stationary')
else:
print('Probably Stationary')
ADF 测试结果: stat=-0.434,p = 0.904—‘可能不稳定’
from statsmodels.tsa.stattools import kpsskpss_test = kpss(y_pred, nlags='auto')print('stat=%.3f, p=%.3f' % kpss_test[0:2])
if kpss_test[1] > 0.05:
print('Probably Stationary')
else:
print('Probably not Stationary')
KPSS 检验结果: stat=0.692,p = 0.014——“可能不平稳”
原来数据集根本不是静止的!让我们直观地看一下:
from statsmodels.tsa.seasonal import seasonal_decomposey_pred_list = y_pred.tolist()
result = seasonal_decompose(y_pred_list, model='additive', period=1)result.plot()

Seasonal_decompose 告诉我们数据集在趋势、季节性和残差方面的表现。如您所见,观察值和趋势值之间的模式非常相似,这意味着趋势已经作为非平稳数据的原因介入其中。
让我们再一次让它静止!!
date = list(range(1,37))
date_fx = pd.DataFrame(zip(date, y_pred_list), columns=['Date', 'FX'])date_fx_log = np.log(date_fx)date_fx_log_diff = date_fx_log - date_fx_log.shift(1)
date_fx_log_diff.dropna(inplace=True)y_stationary = date_fx_log_diff.iloc[:,1]
首先,为了简单起见,我将实际日期替换为从 1 到 36 的数字范围(在我们的数据中代表 36 个月)。然后,为了稳定数据集,我用 np.log 对原始数据进行了变换(这可以通过不同的方法完成:幂变换、平方根或对数变换)。最后,我用差分让数据与平稳。shift(1),将数据集中的每个点减去其前面的点。
好了,我们已经将非平稳的预测汇率(y_pred_list,如前一部分)转换为平稳的预测汇率(y_stationary)!
让我们再次与 ADF 和 KPSS 确认一下!
#a. ADF Test
adf_test_2 = adfuller(y_stationary)
print('stat=%.3f, p=%.3f' % adf_test_2[0:2])
if adf_test_2[1] > 0.05:
print('Probably not Stationary')
else:
print('Probably Stationary')#b. KPSS Test
kpss_test_2 = kpss(y_stationary, nlags='auto')print('stat=%.3f, p=%.3f' % kpss_test_2[0:2])
if kpss_test_2[1] > 0.05:
print('Probably Stationary')
else:
print('Probably not Stationary')
结果是:
- ADF: stat=-5.316,p=0.000,可能是平稳的
- KPSS : stat=0.192,p=0.100,可能是静止的
耶!
2.自相关(ACF)和部分自相关(PACF)
什么是 ACF 和 PACF,它们与 ARIMA 有什么关系?
在使数据集稳定后,我们继续该过程的第二步:为 ARIMA 模型确定 p,d,q 。这可以通过观察 ACF 和 PACF 图来实现!
根据机器学习掌握度,
这些图以图形方式总结了一个时间序列中的观察值与之前时间步长中的观察值之间的关系强度。
这与我们之前完成的步骤之一完全一致:区别于。转变①!如果您还记得的话,我们已经采用了 shift 作为将当前值减去前一个值的方法,以使数据保持稳定。事实上,ACF 和 PACF 能做的不仅仅是差异化!
让我们把它们画出来:
from statsmodels.graphics.tsaplots import plot_acf, plot_pacfdate_fx_log_diff = date_fx_log_diff.values.reshape(-1)plot_acf(date_fx_log_diff, lags=50)
plot_pacf(date_fx_log_diff, lags=50)plt.show()

基于 ACF 和 PACF 的形状和图案,我们可以确定 ARIMA 模型的 p (AR 项)和 q (MA 项)。如果你想深入研究,可以看看这些文章这里和这里。本质上,图表中显著滞后的数量“传递了信息”,在这种情况下是 p & q 的值。
正如您在 ACF 图中看到的,在滞后 1 中看到一个大尖峰,随后是 2 或 3 个滞后,所有滞后都被认为是显著的,因为它们位于“极限阈值”或“显著性线”(蓝色区域)之上。同样地,在 PACF 的图中,在第一个时间出现一个大的峰值,然后在第三个时间出现另一个峰值。那么这一切意味着什么呢?
对我来说,这一发现是测试哪种(p,d,q)组合对我们的 ARIMA 模型产生最佳结果的关键,其中 p 可以在 ACF 中找到,而 q 在 PACF。那么具体是什么 结果 呢?是 AIC。
赤池信息标准(AIC)是一种广泛使用的统计模型的措施。它基本上将模型的 1)拟合优度和 2)简单性/简约性量化为单个统计数据。—阿巴斯·凯什瓦尼,酷派博客
一般来说,AIC 越低越好。让我们转到第 3 部分,看看哪种组合的 AIC 最低!
3.ARIMA 预测
让我们将 p、d、q 的值代入我们的 ARIMA 模型!
正如我前面解释的,ACF 和 PACF 图中的显著滞后的数量可以转化为相应的 p & q。让我们看看 ARIMA 在下列值下的情况:
- p = 3,因为 ACF 中有 3 个显著滞后
- 根据中的计算,d = 1。移位(1)
- q =2 为 PACF 的 2 个显著滞后
from statsmodels.tsa.arima_model import ARIMAy = date_fx_log.iloc[:, 1]model_arima = ARIMA(y, (3,1,2))
model_arima_fit = model_arima.fit()
print(model_arima_fit.summary())
首先,我们从 Statsmodels 库中导入 ARIMA,并从转换后的数据集中提取 y。然后,我们用(p,d,q)的上述值拟合 ARIMA 模型,称为。概要():

尽管看起来很复杂,但我们只需关注表中的两个指标:AIC 和 P 值(P>|z|)。
- AIC = -183.227,我们将对 p,d,q 的另一个组合进行测试,看它是否是最低值。
- p = 3 时,模型为不同行中的每个 AR 返回 3 个不同的 p 值。虽然前两个的 p 值为< 0.05 (这是理想的推荐值),但 AR。L3 的高于 0.05。这意味着在 ACF 图中实际上可能有 2 个明显的滞后。
基于这个发现,让我们测试(p,d,q) = (2,1,2)的另一个组合:

在这种情况下,AIC (-183.096)与第一个模型的 AIC (-183.227)相比没有改善。此外,AR 的 p 值。、马。L1(第一个 q)大于 0.05,这表明我们可能只需要 p=1 和 q=1。让我们用(p,d,q) = (1,1,1)来测试一下:

答对了。AIC 已经改进了很多,因为它是三次试验(最低 AIC 和所有 p 值<0.05).
Okay, this process has been a bit too manual and time-consuming. How about we use 与 for 循环的迭代,看看哪个组合(p,d,q)产生最低 AIC)后的最佳值。
import itertoolsp = range(1, 4)
d = range(1, 2)
q = range(1, 3)pdq = list(itertools.product(p, d, q))aics = []
params = []for param in pdq:
model = ARIMA(y, order=param)
model_fit = model.fit()
aic = model_fit.aic
aics.append(aic)
params.append(param)combo = list(zip(aics, params))
combo.sort()combo_array = np.array(combo)
print(combo_array)
如上所述,我根据 ACF 和 PACF 图创建了 p、d 和 q 的不同范围:
- p = range(1,4):因为在 ACF 中看到 3 个滞后
- d = range(1,2):因为我们至少需要 1 次差分来使数据稳定
- q = range(1,3):因为在 PACF 看到两个滞后
然后,我使用 itertools.product() 从给定的值生成不同的组合。最后,我为循环应用了一个,并用生成的每个组合来拟合 ARIMA 模型。

所以你看,从(1,1,1)的(p,d,q)来看,最低的 AIC 是-185.892,与上面的最新试验相同!

最后,也是最后一步,预测:
pred = model_arima_fit.forecast(12, alpha=0.05)[0]
print(pred)model_arima_fit.plot_predict(1,42)
简单说一下,。forecast() 包括我们需要预测的值的数量(在本例中,数据集周期之后的 2020 年的 12 个月)和 alpha=0.05 作为 95%置信区间。plot_predict(1,42)作为整个预测数据集的(start,end )(在本例中,1 表示第一个月 2017 年 1 月,2 表示最后一个月 2020 年 12 月)。

关于我们 y 值(橙色)和预测(蓝色)的匹配度,看起来还不错!事实上,如果你回想一下多项式回归的图表,预测(蓝色)与我们发现的曲线完全吻合!
塔达!我们已经预测了 2020 年的汇率,这个项目快结束了。如果打印预测值,您可能会觉得奇怪:

这是因为预测值来源于数据集,该数据集在运行该模型之前已经过的对数变换!借助于指数函数简单地恢复数值,这是对数的倒数。
pred = np.exp(pred)
forecast = pred.tolist()fx_2020 = np.array(list(zip(month_year_future, forecast)))
print(fx_2020)

完美!我们整体来形象化一下,2017 年到 2020 年!
x_merge = ['2019-12', '2020-01']
y_merge = [y_pred[-1], forecast[0]]plt.figure(figsize=(14,6))
plt.scatter(month_year, y_fx, alpha=0.4)
plt.plot(month_year, y_fx_predict, color='b')
plt.plot(month_year, y_fx_predict_2, color='r')
plt.plot(month_year, y_fx_predict_3, color='g')
plt.plot(month_year, y_pred, color='black')
plt.plot(x_merge, y_merge, color='y')
plt.plot(month_year_future, forecast, color='y')
plt.legend(['1var', '2var', '3var', '3var with Poly', 'Forecast'])
plt.title("Linear Regression: AUD/USD Exchange Rate (3 var: Interest Rate, GDP & UER)")
plt.xlabel("Month-Year")
plt.ylabel("Exchange Rate")
plt.xticks(fontsize=5)
plt.show()

瞧啊。!!
这个项目到此结束——汇率预测!尽管有很多信息要吸收,我还是希望你能发现整个系列( 第一部分 、 第二部分 ,以及这里的最后一部分)是有帮助的和信息丰富的!
在不久的将来,一定要关注我的即将到来的数据科学和机器学习项目!与此同时,如果您觉得这有帮助,请给我一个掌声,并在这里随意查看我的 Github 以获得完整的资源库:
github:https://github.com/andrewnguyen07LinkedIn:www.linkedin.com/in/andrewnguyen07
谢谢!
如何部署你的第一个机器学习模型——第一部分
从描述业务问题到部署,开发定制的 ML 管道。这份内容广泛的指南包括 Docker 和包装配置。

机器学习模型只有在交付给最终用户时才会有巨大的价值。最终用户可能是房地产平台上的推荐系统,它向租房者或投资者推荐房产——例如 Zillow 。
然而,机器学习项目只有在一个模型被部署,并且它的预测被服务的时候才能成功。
我很惊讶机器学习部署不寻常地在网上讨论——这是你需要在实践工作流中学习的特殊技能。
我试图谷歌这个特定的主题,但我发现了许多关于为机器学习模型设置 Flask APIs 的博客帖子。然而,这些教程都没有深入细节,开发唯一的端点。
因此,我决定在一个关于如何将 ML 模型部署到产品中的综合教程系列中写一篇关于这个主题的博客。我将首先使用 Jupyter 笔记本进行初步的统计分析,然后构建一个定制的机器学习框架——包。之后我会用 FLASK APP 开发一个端点 API。最后,我将使用 CI/CD 管道将机器学习模型部署到 Paas 平台。
我们会使用的一些技术有 Docker、Gemfury、Flask-API、CircleCI、Kaggle API 和 Sklearn。太激动了,让我们开始旅程吧。
免责声明,教程更侧重于事物如何工作,而不是代码逐行教程。在任何时候,您都可以使用Github repo提交历史来引用您的代码,当然,询问您是否需要帮助。
这是一个两部分的教程,这是第一部分,包括构建和发布一个机器学习 python 包。第二部分包括构建一个 Flask API 端点并部署到 Heroku。
请注意,这是一个中级教程,你需要满足一定的要求才能赶上。然而,我通过添加评论和附上资源以供进一步学习和阅读,尽可能地让自己清楚。
在第一部分中,我将带您完成开发您自己的机器学习框架所需的步骤,以自动化从获取数据集到发布到云的构建步骤,以便您可以下载和使用。
先决条件:
本教程假设您对以下方面有一些经验
- python OOP——面向对象编程。
- 拥有 Kaggle 帐户。
- 作为文本编辑器的 VScode。
- 具备 shell 脚本的基础知识—可选。
- 了解终端命令的基本知识。
- 拥有 CircleCI 账户。
- 拥有 Github 帐户。
目录:
- 使用 jupyter 笔记本浏览数据集。
- 从笔记本迁移到 python 脚本
- 为您的应用程序设置虚拟环境
- 设置包的体系结构
- 包装管理器简介—毒性
- 包装要求
- 构建包框架
- CircleCI 简介
- 公共与私有软件包 Gemfury 简介
用于此项目的数据集
在本教程中,我将使用 Kaggle 的房价数据集,它是免费的。我将使用它只是为了演示的目的;我会做一些原始数据处理。可以做更精密的分析;然而,我更喜欢保持简单,因为主要话题已经够复杂了。你可以在 Github repo 中查看完整的项目。
第一步:使用笔记本调查数据集
在此步骤中,我们将执行以下操作:
- 探索数据集—汇总统计数据和 EDA
- 建立回归模型并预测输出。
- 使用 RMSE、梅度量标准评估模型性能。
我将全部细节附在 Kaggle 笔记本上,并关联了如下链接:
第二步:设置包结构
有很多好的搭建 CLI 包可以搭建一个标准的结构,比如 pyscaffold 和许多其他的来设置包结构。然而,我发现对于非软件开发背景的人来说,这并不是很令人欣慰。所以我构建了一个脚手架模板,让你不用那么担心调试后端代码。可以参考 Github 上的源代码。你需要做的就是克隆或下载回购,然后按照说明开始。
第三步:设置脚本文件
包树结构如下所示:

软件包主要模块的快照
让您的软件包正常运行是非常重要的。我们需要设置文件,以便包可以预测没有任何问题。在此步骤中,我们将进行以下操作:
- 设置 config.py 文件→包含训练阶段使用的模型常数。
- 遵循 OOP 最佳实践,将 Jupyter 笔记本转换成 python 脚本。
- 利用 python 中的日志记录→将代码从打印语句升级到日志记录——这在调试会话期间非常有用。
- 在 config.py 文件中,我试图依靠注释来帮助你跟进。在这个文件中,我们设置了在包中使用的常量变量,比如包路径、数据集路径、模型中使用的变量等。所以应该直截了当。
- 下载数据集并将其存储到包文件夹中指定的数据集文件夹中。
- data _ management . py负责加载数据,保存管道,将模型保存为 pickle 文件,最后删除之前持久化的旧模型。
- errors.py 负责在调试会话期间引发自定义错误消息,帮助研究问题。
- features.py 包含数据转换逻辑——如果需要,可以随意添加更多转换
- preprocessor . py实现缺失值插补、分类变量编码等数据角力步骤。
- validation . py确认数据有效——输入数据没有 Nulls 或 NAs。
- pipeline.py 设置管道——构建模型所需执行的步骤。
- train _ pipeline . py从根文件夹加载数据,将数据拆分成 train 和 test,在训练集上拟合模型,最后保存管道是必不可少的。
请注意,我们保留了与版本相关联的文件,这使得工作具有可追溯性和专业性。
- predict.py 根据建立的模型获得预测。如终端中所示,保存的模型是有版本的,因此您可以跟踪要选择哪个模型——日志记录非常棒。
预测. py

日志消息的终端输出
第四步:包构建
对于包构建,我将使用设置工具和滚轮依赖项。这些允许您有效地构建和分发 Python 包,尤其是依赖于其他包的包。他们可以生成一个 dist 源分布文件,该文件包含 .tar.gz 和。 whl 也是扩展名文件。
您需要做的就是更新 setup.py 文件来设置包元数据。此外,您需要更新 tox.ini 文件以包含包构建命令。在构建模型之后执行包构建命令是有意义的。一旦完成,这个包就可以在本地构建和安装了。在终端中运行以下命令:
tox -e install_locally
现在它将选择一个已经在 tox.ini 文件中定义的特定 tox 环境。它将在内创建一个新的虚拟环境。托克斯目录。这个命令在第一次执行时会花费较长的时间,所以不要担心!
现在,如图所示,输出与之前运行 tox 的日志非常不同。这是因为它指定了所有由 设置工具 命令完成的设置。

运行 tox 命令后的终端提示符

构建包后文件夹结构的快照
第五步:在本地安装软件包
在终端中,运行以下命令在本地安装软件包:
pip install -e .
标签是在本地安装包,而。是指定包的根目录。
如果您不在包目录中,您需要指定包的路径而不是点。
安装完成后,我们可以通过使用 python 启动 python 命令行来测试它。

在本地测试包
该软件包现已成功安装在您的计算机上,可以使用了。
可选步骤:设置脚本从 Kaggle 获取数据集
专注于构建高效模型的一种方法是从已知的 API 中自动获取数据集。这是一个有效的方法来确保你没有忘记下载数据或把它放在错误的目录中。我将利用 Kaggle API 来自动下载数据集。他们有一个友好的 CLI 工具,它很容易使用,会节省你大量的时间下载数据。
- 你应该有一个 Kaggle 账户,如果没有,你可以在这里注册。
- 导航到我的帐户→ API →创建新的 API 令牌→将 JSON 文件保存在您的本地机器中。
- 将下面的代码片段放到脚本目录下的fetch _ ka ggle _ dataset . sh中。
如果您试图运行该文件,它会抛出一个错误,因为我们还没有设置 API 键。我们应该在接下来的步骤中设置 CircleCI/CD 管道时这样做。
第六步:建立 CI/CD 管道
自动化包开发的各个阶段是非常必要的。同时,确保如果添加了更新的代码或新的功能,不会出现任何问题。这就是使用持续集成/部署和交付平台(CI/CD 管道)的意义所在。根据下图,管道确保流程中的一切正常工作:
构建→测试→合并→自动发布到公共回购→自动部署
有许多托管平台使用 CI/CD 管道,仅举几个例子:
我以前用过 Travis 和 Jenkins,所以我很好奇想在这个项目中尝试一下 CircleCI。如果您曾经参与过任何开发-运营管道开发,它会有相同的操作和几乎相同的命令。尽管 CircleCI 集成了 GitHub,但它只提供了一个免费的项目,用于在部署到 Paas 的过程中构建和禁用其他一些关于速度和缓存的特性。然而,其他主机平台的配置几乎相同。
首先,我们需要使用以下步骤在 circleci 中设置 Kaggle 环境变量:
打开为 kaggle API 令牌下载的文件。
进入 CircleCI 仪表板→项目名称→项目设置(在右上角)→环境变量→添加变量→
将名称设置为
KAGGLE_USERNAME,并将 值保存到你的 kaggle 用户名的 JSON 文件 中。
重复这个过程,将名为
KAGGLE_KEY的新变量添加到您的密钥值中。
根据文档,将这些环境变量命名为与上面相同的名称很重要,这样才能成功构建。
我使用了 Circleci 文档提供的入门指南;这很容易理解。这个脚本的作用是:
- 创建虚拟
- 激活它
- 升级 pip 命令
- 在包的根目录下安装 requirements.txt 文件
- 授予执行外壳文件的权限
- 获取数据集
- 运行测试
我在特定的 github commit 链接了基本的 config.yml 文件供你参考。
每当一个新的 git commit 被推送到 master,CircleCi 就会运行测试,如果它有一个成功的构建,一个绿色的小勾就会出现在 GitHub 相应的 commit 附近。

CircleCi 仪表板

Github 接口
https://media.giphy.com/media/Zc1sReLPQDN6Cxsezw/giphy.gif
第七步:发布到 web
发布包有两个选项:
- 将包公开-任何人都可以使用。你可以很容易地在pypi.org上发布这个关于 pypi 文档的指南。
- 将包设为私有-仅对特定用户可用。
在本教程中,我将使包成为私有的,因为这将是你在现实生活中面临的情况。然而,公开软件包的步骤几乎是相同的。所以让我们开始吧。
以下是您需要开始的步骤:
- Gemfury 帐户—如果您还没有在此处注册。Gemfury 是一个托管库,可以托管私有包。
- 登录并导航至令牌→完全访问令牌→复制
- 然后导航到
CircleCI 仪表盘→项目名称→项目设置(右上角)→环境变量→添加变量→
- 将名称设置为
PIP_EXTRA_INDEX_URL, - 和价值
https://${Full access token}@pypi.fury.io/${gemfury_username}
将完全访问令牌和 gemfury 用户名替换为您自己的之后,您就可以开始下一步了— 您也可以按照文档进行操作。
4.在这一步,你需要一个 shell 脚本来发布这个包——publish _ model . sh,我按照这个代码做了一点调试和大量的读取从这里,这里这里。
现在是时候通过添加发布包的新命令来更新 Circleci config.yml 了。
如果您登录到您的 gemfury 帐户,您将会看到在 packages 选项卡下发布的包。唷!!!


结论和要点
这个项目是比较中级的水平。我们探讨了许多需要包含在您的技能组合中的概念。我们探索的一些技能:
- 坚持练习写 python 脚本而不是笔记本是最精华的。当处理可伸缩的应用程序时,它将节省大量的时间。
- Python 代码的最佳实践。
- 了解根据您的需求定制软件包的基础知识— 构建您的项目指南。
- 分离关注点是保持你的代码有条理和可读性的一个很好的实践— 搭便车的指南代码风格。
- 自动化流水线减少了错误和 bug 的机会— sklearn 文档。
- 将日志记录添加到源代码中,使调试变得更加容易— 您的参考资料,了解关于日志记录和格式化程序以及日志记录指南的更多信息。
- 花足够的时间规划工作流和架构对于质量非常重要— 可选参考。
- 了解业务问题并将其分解成小块使其易于管理— 可选参考 _1 和参考 _2 。
免责声明:如果您导航到Github repo,您会注意到我禁用了 pytest 包——单元测试被禁用。这是因为我想专注于部署,忽略单元测试中出现的任何问题。
最后,我完成了如何从头开始开发机器学习 python 包的第 1 部分。对我来说,这是一个令人愉快又富有挑战性的项目。在第 2 部分中,我将利用这个包构建以下内容:
- 使用 Flask app 构建 REST API 端点
- 为完整的工作流程构建 docker 映像
- 使用 Circleci 将应用程序部署到 Heroku
- 使用 streamlit 构建前端接口。
敬请关注!
我希望这篇教程让你对机器学习模型的完整生命周期有所了解。有问题就问吧;我很乐意帮忙!快乐学习!
适应熊猫套餐——课程、练习和修改

学习熊猫
熊猫和数据框
因为你用的是熊猫,你必须在(几乎)所有笔记本上写的第一行是
import pandas as pd
在熊猫中,数据帧是一个表格。你可以在一个数据框架上做很多事情:对一列求和,绘制直方图,做一个数据透视表…
作为一个好的开始,简单地写“pd”在一个空的单元格中,使用键盘快捷键 Tab 来查看 pandas 中所有可用的功能。你会的
创建数据框架
要创建数据帧,请使用:
pd.DataFrame({
'age':[10, 45, 13]
})
函数' pd。DataFrame()'使用字典:
{
'age':[10, 45, 13]
}
其中“年龄”是列的名称,[10,45,13]是行的值。
注意您可以有多列:
{
'age':[10, 45, 13],
'name': ['George', 'Damien', 'Ingrid'],
'gender': ['male', 'male', 'female']
}
你可以看到这有点不直观,因为我们习惯于把表格想象成由行组成的列表。更确切地说,熊猫数据框架使用了一系列列。这是要掌握的第一个概念。创建数据帧还有其他方法,但这是最常用的一种。其他的包括读取文件:
pd.read_excel('myExcelFile.xlsx')
(打开文件前不要忘记关闭,否则会出错)
或者
pd.read_csv('myFile.csv')
组合数据帧
组合数据帧非常简单:使用任意一种。join(),。append()、pd.concat()或。合并()。
见下文(很丑但很管用)
同。join():
pd.DataFrame({
'age':[10, 45, 13]
}).**join(**
pd.DataFrame({
'name': ['George', 'Damien', 'Ingrid']
})
**)**.**join(**
pd.DataFrame({
'gender': ['male', 'male', 'female']
})
**)**
返回

同。append():
pd.DataFrame({
'age':[10, 45, 13]
}).**append(**
pd.DataFrame({
'age': ['George', 'Damien', 'Ingrid']
})
**)**.**append(**
pd.DataFrame({
'age': ['male', 'male', 'female']
})
**)**
返回

(见丑索引:0,1,2,0,1,2,0,1,2)
注意 append 不能连接列上的数据帧,它必须通过行连接(一行在另一行之上,而不是一行挨着一行)。数据帧之间必须有相同的列名,否则会得到警告。
With pd.concat():
**pd.concat([**
pd.DataFrame({
'age':[10, 45, 13]
}),
pd.DataFrame({
'name': ['George', 'Damien', 'Ingrid']
}),
pd.DataFrame({
'gender': ['male', 'male', 'female']
})
**], axis=1)**
返回

请注意,pd.concat()将用于数据帧列表,而不是数据帧。使用 pd.concat([df1,df2,…])。注意在熊猫中很常见的轴=1。基本上,轴=0 是列,轴=1 是行。
同。merge():
pd.DataFrame({
'age':[10, 45, 13],
'name': ['George', 'Damien', 'Ingrid']
})**.merge(**
pd.DataFrame({
'name': ['George', 'Damien', 'Ingrid'],
'gender': ['male', 'male', 'female']
})**, on=['name']**
**)**
返回

。“merge()”是 SQL“JOIN”。您至少需要一列来匹配它们。
在数据帧上运行操作
总和、最大值、最小值、平均值、中值
pd.DataFrame({
'age':[10, 45, 13],
'name': ['George', 'Damien', 'Ingrid'],
'gender': ['male', 'male', 'female']
})**.mean()**
返回

请注意,它仅对数值列进行平均。
pd.DataFrame({
'age':[10, 45, 13],
'name': ['George', 'Damien', 'Ingrid'],
'gender': ['male', 'male', 'female']
})**.sum()**
返回

看到它适用于所有列了吗?!!它将文本连接在一起,并对“年龄”列求和。这是因为你可以用 Python 对文本求和:
'Damien' + 'George'
这里我们不关心文本的总和,但在某些情况下,它可能是有趣的。
pd.DataFrame({
'age':[10, 45, 13],
'name': ['George', 'Damien', 'Ingrid'],
'gender': ['male', 'male', 'female']
})**.min()**
返回

。min()返回数值的最小值,同时也返回按字母顺序排列的字符串的最小值!这是因为您可以在 Python 中比较文本:
'Damien' > 'George'
透视表 _ 表格
如果你是一个 Excel 用户,不需要介绍这个。数据透视表只是以一种易于阅读的方式将数据聚集在一起。
pd.DataFrame({
'age':[10, 45, 13],
'name': ['George', 'Damien', 'Ingrid'],
'gender': ['male', 'male', 'female']
})**.pivot_table(**index='gender', aggfunc='min'**)**
返回

和以前一样,“min”操作符对数字列和字符串列都有效。
自定义功能

要在 0 和 1 之间缩放数据集的列,可以编写以下代码:
for column in df.columns:
df[column] = \
(df[column] — df[column].min()) / \
(df[column].max() — df[column].min())
记住反斜杠是换行符。
更高级的写法是使用。应用()方法。顾名思义,它将一个函数同时应用于所有列或所有行。
df = df.apply(
lambda column: (column-column.min()) / (column.max()-column.min())
)
要对 1 个特定列执行自定义功能,请使用。地图()【方法】。
df['column_1_squared'] = df['column_1'].map(
lambda x: x * x
)
结论
尽可能多地练习这些。它们会变得非常有用。

练习
创建数据框架
创建如下图所示的数据帧。哦,找到一个聪明的方法来创建它们,不要只是在字典中硬编码这些值:

数据框#1:从 3 到 10 的正方形

数据帧#2:多列

数据帧#3:平方数
组合数据帧
customers1 = pd.DataFrame({
'age':[10, 45, 13],
'name': ['George', 'Damien', 'Ingrid'],
'gender': ['male', 'male', 'female']
})customers2 = pd.DataFrame({
'age':[12, 23, 25],
'name': ['Albert', 'Jane', 'Angela'],
'gender': ['male', 'female', 'female']
})
如何在一行中编写连接两个客户表的表?
- 难
假设您的硬盘上有一些名为 cust_transactions 的文件夹中的文件。每个文件都包含一些客户交易的以下信息:
file_482.csv 包含以下 4 列:

如何将所有文件读入一个名为“transactions”的数据帧?
最后一个
非常困难;)
你有一个名为 model_1,model_2,…,model_5 的 5 sklearn 二元分类模型。您希望在名为 X_train 和 X_test 的训练集和测试集上测量所有这 5 个模型的 AUC、对数损失、准确性和 f1 得分。目标的实际值分别是 y_train 和 y_test。
每行代表一个模型的性能。
你能写一个干净的代码来创建下面的表吗?

提醒:
这是衡量准确性的 4 个标准:
**from** sklearn.metrics **import** log_loss, roc_auc_score, accuracy_score, f1_score
log_loss 和 roc_auc_score 以预测的概率为输入, accuracy_score 和 f1_score 以预测的类为输入。
例如,如果 m 是模型的名称:
log_loss(y_true=y_train, **y_pred**=m.**predict_proba**(X_train)**[:,1]**)
roc_auc_score(y_true=y_train, **y_score**=m.**predict_proba**(X_train)**[:,1]**)
注意一个用 y_pred,另一个用 y_score。

修改
创建数据框架
pd.DataFrame({
'n': range(3,11),
'n_squared': [n*n for n in range(3,11)]
})
pd.DataFrame({'number_'+str(n):[n] for n in range(10)})
别忘了 n 旁边的 [] 。
pd.DataFrame({'column_'+str(n):[n*m for m in range(10)] for n in range(10)})
两个列表理解交织在一起。
组合数据帧
customers1.append(customers2, ignore_index=True)
注意 ignore_index=True 不是必须的,获得一个干净的新索引是很好的。
import ostransactions = pd.concat([
pd.read_csv(f)
for f in os.listdir('cust_transactions')
if f.endswith('.csv')
])
“导入操作系统”是调用“os.listdir('cust_transactions ')”所必需的,它列出了“cust_transactions”文件夹中的所有文件。我加了 if f.endswith(。csv),以防文件夹中有其他类型的文件。
使用多个。这里的 append()看起来也是一个不错的选择。但是在一起读几千或者几百万个文件的时候,会很慢。将 pd.concat([])与 pd.read_csv()一起使用将是最快的选择。
最后一个
models = [model_1, model_2, model_3, model_4, model_5]pd.concat(
[
pd.DataFrame({
sample+'_log_loss': [log_loss(y_true=y, y_pred=m.predict_proba(X)[:,1]) for m in models],
sample+'_AUC': [roc_auc_score(y_true=y, y_score=m.predict_proba(X)[:,1]) for m in models],
sample+'_accuracy': [accuracy_score(y_true=y, y_pred=m.predict(X)) for m in models],
sample+'_f1score': [f1_score(y_true=y, y_pred=m.predict(X)) for m in models]
})
for (sample,X,y) in zip(['train', 'test'], [X_train, X_test], [y_train, y_test])
],
axis=1
)
系外行星,我们在哪里?
带有少量 Wolfram 语言的计算思维

由 Unsplash 上 Greg Rakozy 拍摄的照片
太阳系外的第一颗行星——系外行星——被确认至今不过 30 年左右。系外行星发现的时间表相当复杂,因为事实上早期的观察,其中一次早在 1917 年,最初并没有被认为是系外行星的证据。
在一段时间的基于地球和哈勃望远镜的发现之后,一架名为开普勒的太空望远镜于 2009 年发射,致力于寻找系外行星的任务。它一直指向夜空的一小部分,几年来耐心地记录了来自 50 多万颗恒星的光。

在大约 10 年的任务中,它探测到了超过 2600 颗新的系外行星。加上其他发现,已知的系外行星总数超过 4000 颗。许多系外行星都有轨道周期、质量、半径等等的估计值。在这篇文章中,我将关注它们的质量和半径,并将它们与我们太阳系中的行星进行比较。
获取系外行星数据
在 Wolfram 语言中,这些系外行星可以从 Wolfram 知识库的编程接口直接访问。在笔记本界面中,你可以通过漂亮的用户界面访问任何实体,而不仅仅是系外行星:

(图片由作者提供)
上面的最终结果也可以以纯文本代码的形式表示。它们是完全一样的东西:
EntityClass["Exoplanet", All]
我们可以通过一个简单的查询获得每个行星的质量和半径:
data = ExoplanetData[
EntityClass["Exoplanet", All], {
EntityProperty["Exoplanet", "Mass", {"Uncertainty" -> "Around"}],
EntityProperty["Exoplanet", "Radius", {"Uncertainty" -> "Around"}]
}, "EntityAssociation"]
许多系外行星没有对它们的质量和/或半径的估计,而那些有估计的行星通常有很大的不确定性。十行数据的随机样本显示了典型的情况:

(图片由作者提供)
在过滤掉质量或半径缺失的情况后,我们得到了一个干净的数据集(显示了另一个 10 行的随机样本):

(图片由作者提供)
绘制数据
现在很容易画出每个系外行星的质量与半径的关系。极细的垂直线和水平线表明了每个系外行星的不确定性:

(图片由作者提供)
看到大量更大的系外行星并不奇怪。更大的行星更容易被发现,因此更多的行星被探测到。
为了将这些系外行星与我们太阳系中的行星进行比较,我们首先需要获得它们以及它们的质量和半径:
EntityValue[
EntityClass["Planet", All],
{"Mass", "Radius"},
"EntityAssociation"
]
使用额外的数据,我们现在可以重复相同的绘图,但包括太阳系行星:

(图片由作者提供)
这个挺有意思的。它表明有相当多的系外行星甚至比木星还要大。当然有一个上限,因为在某个尺寸下,一颗非常大的行星会变成一颗非常小的恒星。
在系外行星光谱的另一端,很明显我们没有发现很多非常小的行星。甚至火星也位于被探测到的主要系外行星群之外。希望有一天我们也会发现很多这样的东西!

鸣谢: NASA (公共领域)
带代码的完整 Wolfram 笔记本可在网上这里获得。
通过规范化扩展您的回归曲目
使用通过 tsfresh 生成的大量特征,通过逻辑回归对桶样品进行分类
你也可以在 GitHub 上阅读这篇文章。这个 GitHub 存储库包含了您自己运行分析所需的一切。
介绍
对于许多数据科学家来说,基本的主力模型是多元线性回归。它是许多分析的第一站,也是更复杂模型的基准。它的优势之一是所得系数的易解释性,这是神经网络特别难以解决的问题。然而,线性回归并非没有挑战。在本文中,我们关注一个特殊的挑战:处理大量的特性。大型数据集的具体问题是如何为我们的模型选择相关特征,如何克服过度拟合以及如何处理相关特征。
正规化是一种非常有效的技术,有助于解决上述问题。正则化通过用限制系数大小的项来扩展正常的最小二乘目标或损失函数来做到这一点。这篇文章的主要目的是让你熟悉正规化及其带来的好处。
在本文中,您将了解以下主题:
- 什么是更详细的正则化,为什么值得使用
- 有哪些不同类型的正规化,以及术语 L1-和 L2-规范在这种情况下的含义
- 如何实际运用正规化
- 如何使用 tsfresh 为我们的正则化回归生成特征
- 如何解释和可视化正则化回归的系数
- 如何使用交叉验证优化正则化强度
- 如何可视化交叉验证的结果
我们将从更理论化的规范化介绍开始这篇文章,并以一个实际的例子结束。
为什么使用规范化,什么是规范?
下图显示了一个绿色和一个蓝色函数与红色观测值相匹配(属性)。两个函数都完全符合红色观测值,我们真的没有好办法使用损失函数来选择其中一个函数。

不能选择这些函数意味着我们的问题是欠定的。在回归中,两个因素增加了欠定的程度:多重共线性(相关特征)和特征的数量。在具有少量手工特征的情况下,这通常可以手动控制。然而,在更多的数据驱动的方法中,我们经常使用许多(相关的)特征,我们事先不知道哪些会工作得很好。为了克服不确定性,我们需要在问题中加入信息。给我们的问题添加信息的数学术语是规则化。
回归中执行正则化的一个非常常见的方法是用附加项扩展损失函数。 Tibshirani (1997) 提出用一种叫做 Lasso 的方法将系数的总大小加到损失函数中。.)表示系数总大小的数学方法是使用所谓的范数:

其中 p 值决定了我们使用什么样的范数。p 值为 1 称为 L1 范数,p 值为 2 称为 L2 范数,以此类推。既然我们已经有了范数的数学表达式,我们可以扩展我们通常在回归中使用的最小二乘损失函数:

请注意,我们在这里使用 L2 范数,并且我们也使用 L2 范数表示损失函数的平方差部分。此外,λ是正则化强度。正则化强度决定了对限制系数大小与损失函数的平方差部分的关注程度。请注意,范数项在回归中引入了偏差,主要优点是减少了模型中的方差。
包含 L2 范数的回归称为岭回归 ( sklearn )。岭回归减少了预测中的方差,使其更加稳定,不容易过度拟合。此外,方差的减少也对抗多重共线性引入的方差。
当我们在损失函数中加入一个 L1 范数时,这被称为 Lasso ( sklearn )。Lasso 在减小系数大小方面比岭回归更进一步,一直减小到零。这实际上意味着变量会脱离模型,因此 lasso 会执行特征选择。这在处理高度相关的要素(多重共线性)时影响很大。Lasso 倾向于选择一个相关变量,而岭回归平衡所有特征。Lasso 的要素选择属性在您有许多输入要素,而您事先不知道哪些输入要素将对模型有益时特别有用。
如果您想混合套索和岭回归,您可以将 L1 和 L2 范数添加到损失函数中。这就是所谓的弹性网正规化。撇开理论部分不谈,让我们进入正规化的实际应用。
正则化的使用示例
使用案例
人类非常善于识别声音。仅基于音频,我们就能够区分汽车、声音和枪支等事物。如果有人特别有经验,他们甚至可以告诉你这种声音属于哪种车。在本例中,我们将构建一个正则化的逻辑回归模型来识别鼓声。
数据集
我们模型的基础是一组 75 个鼓样品,每种鼓 25 个:底鼓、小军鼓和 tom 。每个鼓样本都储存在一个 wav 文件中,例如:


wav 文件是立体声的,包含两个声道:左声道和右声道。该文件包含一个随时间变化的波形,x 轴为时间,y 轴为振幅。振幅实际上列出了扬声器的圆锥应该如何振动,以便复制存储在文件中的声音。
以下代码用所有 75 个鼓样本构造了一个DataFrame:

额外的函数audio_to_dataframe可以在文章的 github repo 中的helper_functions.py文件中找到。
使用 tsfresh 生成要素
为了适应监督模型,sklearn 需要两个数据集:一个带有我们特征的samples x features矩阵(或数据帧)和一个带有标签的samples向量。因为我们已经有了标签(all_labels),所以我们把精力集中在特征矩阵上。因为我们希望我们的模型对每个声音文件进行预测,所以特征矩阵中的每一行都应该包含一个声音文件的所有特征。下一个挑战是想出我们想要使用的特性。例如,低音鼓的声音可能有更多的低音频率。因此,我们可以对所有样本运行 FFT,并将低音频率分离为一个特征。
采用这种手动特征工程方法可能非常耗费人力,并且有排除重要特征的很大风险。tsfresh ( docs )是一个 Python 包,它极大地加快了这个过程。该软件包基于时间序列数据生成数百个潜在特征,还包括预选相关特征的方法。拥有数百个特征强调了在这种情况下使用某种正则化的重要性。
为了熟悉 tsfresh,我们首先使用MinimalFCParameters设置生成少量特征:

留给我们 11 个特征。我们使用extract_relevant_features函数来允许 tsfresh 预先选择给定标签和生成的潜在特征有意义的特征。在这种最小的情况下,tsfresh 查看由file_id列标识的每个声音文件,并生成诸如幅度的标准偏差、平均幅度等特征。
但是当我们生成更多的特性时,tsfresh 的优势就显现出来了。这里,我们使用高效设置来节省一些时间,而不是完全设置。注意,我从保存的 pickled 数据帧中读取结果,该数据帧是使用 github repo 中可用的generate_drum_model.py脚本生成的。我这样做是为了节省时间,因为在我的 12 线程机器上计算有效特性大约需要 10 分钟。

这大大扩展了特性的数量,从 11 个增加到 327 个。现在,特征包括跨越几个可能滞后的自相关、FFT 分量以及线性和非线性趋势等。这些特征为我们的正则化回归模型提供了一个非常广阔的学习空间。
拟合正则化回归模型
现在我们有了一组输入要素和所需的标签,我们可以继续拟合我们的正则化回归模型。我们使用来自 sklearn 的逻辑回归模型:
并使用以下设置:
- 我们将惩罚设为
l1,也就是说,我们使用 L1 规范进行正则化。 - 我们设置
multi_class等于one-versus-rest(ovr)。这意味着我们的模型由三个子模型组成,每个子模型对应一种可能的鼓。当使用整体模型进行预测时,我们只需选择表现最佳的模型。 - 我们使用
saga解算器来拟合我们的损失函数。还有很多可用的,但佐贺有一套完整的功能。 C暂时设为 1,其中 C 等于1/regularisation strength。注意,sklearn 套索实现使用了𝛼,它等于1/2C。因为我发现𝛼是一个更直观的度量,所以我们将在本文的剩余部分使用它。tol和max_iter设置为可接受的默认值。
基于这些设置,我们进行了大量的实验。首先,我们将比较基于少量和大量 tsfresh 特性的模型的性能。之后,我们将重点关注使用交叉验证来拟合正则化强度,并以拟合模型的性能的更一般的讨论来结束。
最小 t 新鲜与高效
我们的第一个分析测试了假设,即使用更多生成的 tsfresh 特征会导致更好的模型。为了测试这一点,我们使用最小和有效的 tsfresh 特征来拟合模型。我们通过模型在测试集上的准确性来判断模型的性能。我们重复这个过程 20 次,以了解由于选择训练集和测试集的随机性而导致的准确性差异:

得到的箱线图清楚地表明,与基于最小特征的模型的 0.4 相比,有效的 tsfresh 变量显示出 0.75 的高得多的平均准确度。这证实了我们的假设,我们将在本文的其余部分使用高效的特性。
通过交叉验证选择正则化强度
使用正则化时,我们必须做出的一个主要选择是正则化强度。这里我们使用 crossvalidation 来测试 c 的一系列潜在值的准确性。方便的是,sklearn 包括一个函数来执行逻辑回归分析:[LogisticRegressionCV](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegressionCV.html)。它本质上具有与LogisticRegression相同的接口,但是您可以传递一个潜在的 C 值列表来进行测试。关于代码的细节,我参考了 github 上的generate_drum_model.py脚本,为了节省时间,我们将结果从磁盘加载到这里:
注意,我们使用[l1_min_c](https://scikit-learn.org/stable/modules/generated/sklearn.svm.l1_min_c.html)来获得最小 C 值,对于该值,模型将仍然包含非零系数。然后,我们在此基础上添加一个介于 0 和 7 之间的对数标度,最终得到 16 个潜在的 C 值。我对这些数字没有很好的理由,我只是在l1_min_c链接的教程中重复使用了它们。转化为𝛼α正则化强度,取 log10 值(为了可读性),我们最终得到:

正如我们将在结果的解释中看到的,这跨越了一个很好的正则化强度范围。
交叉验证选择了以下𝛼值:

请注意,我们有三个值,每个子模型一个值(踢模型、鼓模型、响弦模型)。这里我们看到,大约 6 的正则化强度被认为是最佳的(C = 4.5e-07)。
基于 CV 结果的模型的进一步解释
cv_result对象包含比拟合正则化强度更多的关于交叉验证的数据。在这里,我们首先看看交叉验证模型中的系数,以及它们在不断变化的正则化强度下遵循的路径。注意我们使用 github 上的helper_functions.py文件中的plot_coef_paths函数:

注意,我们在图中看到 5 条线,因为默认情况下我们执行 5 重交叉验证。此外,我们关注kick子模型。在该图中,以下观察结果很有趣:
- 增加正则化强度会减小系数的大小。这正是正规化应该做的,但结果支持这一点是件好事。
- 增加正则化强度会减少褶皱的拟合系数之间的差异(线条更接近)。这与规范化的目标是一致的:减少模型中的方差,并与不确定性作斗争。然而,褶皱之间的变化仍然是相当引人注目的。
- 对于后面的系数,总的系数大小下降。因此,早期系数在模型中最为重要。
- 对于交叉验证的正则化强度(6),相当多的系数脱离了模型。在 tsfresh 生成的 327 个潜在特征中,只有大约 10 个被选择用于最终模型。
- 许多有影响的变量是 fft 分量。这在直觉上是有意义的,因为鼓样本之间的差异集中在某些频率附近(低音鼓->低频,小军鼓->高频)。
这些观察描绘了正则化回归按预期工作的画面,但肯定还有改进的空间。在这种情况下,我怀疑每种类型的鼓有 25 个样本是主要的限制因素。
除了查看系数和它们如何变化,我们还可以查看子模型的整体准确性与正则化强度。注意,我们使用了来自helper_functions.py的plot_reg_strength_vs_score图,你可以在 github 上找到。

请注意,精确度涵盖的不是一条线,而是一个区域,因为我们在交叉验证中有每个折叠的精确度分数。该图中的观察结果:
- kick 模型在拟合的正则化强度(6 -> 0.95)下以非常低的最小精度整体表现最佳。
- tom 模型表现最差,其最小和最大精度低得多。
- 正则化强度在 5-6 之间达到性能峰值,这与所选值一致。在强度较小的情况下,我怀疑模型中剩余的多余变量带来了太多噪音,之后正则化提取了太多相关信息。
结论:我们的正则化回归模型的性能
基于交叉验证的准确度分数,我得出结论,我们在生成鼓声音识别模型方面相当成功。特别是底鼓很容易与其他两种鼓区分开来。正则化回归也为模型增加了很多价值,并减少了模型的总体方差。最后,tsfresh 在从这类基于时间序列的数据集生成特征方面显示了很大的潜力。
改进模型的潜在途径有:
- 使用 tsfresh 生成更多潜在的输入要素。对于这个分析,我使用了高效设置,但是也可以使用更复杂的设置。
- 使用更多的鼓样本作为模型的输入。
由于人工智能,你可以在 4K 观看童年时代的电视节目
这是一个人工智能如何将 1984 年的原版《变形金刚 G1》转换成《4K》的例子

你是否在和你的孩子一起重温你最喜欢的童年电视连续剧,并问自己——如果我能在美丽的 4K 看他们,那不是很好吗?这是一个非常合理的问题,因为你正在观看的旧电视节目大多是标清质量的。这意味着分辨率最好为 720x576 像素,仅为 4K 屏幕像素的 5%。实际上,这意味着您的电视会将每个画面放大 20 倍,以填满整个 4K 屏幕。难怪照片看起来模糊不清。

标清与全高清以及 4K UHD 的对比
传统灌制
许多老的电视节目和电影,如《星际迷航》King》、《阿拉丁》或《狮子王》,已经被重新录制成更高的清晰度,可以在流行的流媒体平台上观看。然而,你最喜欢的童年电视节目或电影至少有全高清版本的可能性相当小。其原因在于,重新灌制更高清晰度的图像通常是一项乏味且昂贵的工作。首先,你需要拿到原始的 16 毫米或 8 毫米胶片,并希望它仍然完好无损。然后,胶片必须一帧一帧地进行数字扫描。一旦胶片被扫描,就执行手动颜色和图像校正。这都需要大量的时间和金钱,从商业角度来看,这是不合理的。你可以在这里和阅读更多关于电影修复的内容。
人工智能拯救世界
人工智能、人工神经网络和机器学习都是过去几年的热门词汇。虽然经常被夸大,但人工神经网络(ann)给语音和图像识别或机器翻译等领域带来的进步不容忽视。原则上,它们是强大的模式识别算法,可以自动学习如何基于现有的数据集将输入转换为所需的输出。例如,你可以给人工神经网络输入 10 万张猫的图片和另外 10 万张狗的图片,它会自动学习如何区分这两张图片。编写一个传统的程序来区分图片中的猫和狗需要几个月的编码时间,而且可能不如简单的人工神经网络好,后者只需几天就可以建立起来。
既然人工神经网络可以在各种各样的任务上被训练,为什么不把它们用于 4K 改造呢?给人工神经网络足够多的相同图像或视频的 SD 和 4K 版本的例子,它将学习如何将低质量的 SD 输入重新制作成详细的 4K 视频。记住,当把一张 SD 图像转换成 4K 时,从技术上讲,你是把一个像素变成了 20 个像素。当你在 4K 电视上观看标清内容时,每个像素基本上都被放大 20 倍并进行模糊处理,以减少锯齿边缘。另一方面,人工神经网络将为原始视频的每个像素向 19 个新生成的像素人工添加逼真的细节。最终的 4K 结果应该是清晰的,有很多 SD 视频中没有的细节。
由于所有主要的神经网络框架都是开源的,因此您可以为 4K 升级构建和训练自己的 ANN 模型,但幸运的是,这方面的解决方案已经存在。一个这样的工具是托帕斯实验室的托帕斯视频增强人工智能。这个工具可以让你利用预训练的人工神经网络,通过几次点击,将低质量的视频升级到 4K 甚至 8K。
使用人工智能测试 4K 向上扩展
黄玉视频增强人工智能在 1984 年发行的原版变形金刚 G1 动画系列的 DVD 上进行了测试。这部动画系列从未以高清形式重拍,更不用说《4K》了,这使它成为一个完美的测试对象(除了它是一部伟大的剧集这一事实)。一个中档英伟达 GTX 1060 显卡花了大约 14 个小时将一集 22 分钟的内容从标清升级到 4K,但这种等待是值得的。以下是第一季介绍主题的一些对比镜头:

左—原始 SD 版本升级到没有人工智能的 4K |右—使用人工智能的 4K 版本(原生 4K 部分)

左—原始 SD 版本升级到没有人工智能的 4K |右—使用人工智能的 4K 版本(原生 4K 部分)

左—原始 SD 版本升级到没有人工智能的 4K |右—使用人工智能的 4K 版本(4K 本地部分)

左—原始 SD 版本升级到没有人工智能的 4K |右—使用人工智能的 4K 版本(4K 本地部分)
原版和 4K 版的《变形金刚》之间的差异是很难被忽略的。图像更加清晰,干净——这是普通的升级版无法做到的。你仍然会看到偶尔的电影噪音和 AI 模型无法提高动画帧率,但它无疑给了 36 岁的变形金刚一个急需的打磨。
期待什么
使用人工神经网络提升 4K 的结果令人印象深刻。和传统重制版一样好吗?不,但考虑到它使用起来如此简单,这是一个不可思议的成就。目前,使用人工神经网络的 4K 升级主要由爱好者和业余爱好者使用。典型的消费者不会看到或使用这样的工具,因为它们相对较慢。除了 2019 年的 Nvidia Shield,根本没有一款消费产品能够使用复杂的人工神经网络将视频实时升级到 4K。因此,问题是,我们什么时候能看到这样的人工智能成为主流?有两种可能的解决方案:
1.高端专用消费产品
我们可以期待在未来几年看到利用人工神经网络进行实时 4K 和 8K 升级的高端专用消费产品。这些可能采取机顶盒或控制台的形式,必须插入电视。其中一个已经存在的产品是 2019 年的 Nvidia Shield。后来,我们可以期待人工智能升级硬件直接内置到电视中。这将特别有助于销售 8K 电视,因为它实际上抵消了可用 8K 内容的缺乏。
2.流媒体平台开始利用人工神经网络
人工神经网络升级成为主流的另一种可能性是流媒体平台开始利用这项技术。流媒体平台必须使用人工神经网络将其标清和高清内容升级到 4K 甚至 8K,就像使用现有工具一样。一旦完成,升级后的 4K 或 8K 内容将可供每个人观看。这个过程可能需要电影工作室的一些许可澄清,但从技术的角度来看,现在没有什么会阻碍流媒体平台使用这项技术。
谁也说不准 4K 什么时候会用复杂的人工神经网络来做主持人。但是,这种技术所能达到的结果使我们希望这一天早日到来。
免责声明:《变形金刚》及其所有相关角色是孩之宝的商标,我不主张任何权利。我和 Topaz 实验室或其任何员工都没有关系。版权免责根据 1976 年版权法 107 节,允许出于批评、评论、新闻报道、教学、学术、教育和研究等目的的“合理使用”。合理使用是版权法允许的使用,否则可能侵权。
期望值最大化算法,已解释
入门
EM 算法的综合指南,包含直觉、示例、Python 实现和数学

登上富士山与 EM 寻找最大似然估计值的方式惊人地相似。请继续阅读,找出原因。由吉勒·德贾尔丁在 Unsplash 上拍摄的照片
是啊!先说期望最大化算法(简称 EM)。如果您处于数据科学“泡沫”中,您可能在某个时间点遇到过 EM,并且想知道:什么是 EM,我需要知道它吗?
它是解决高斯混合模型的算法,这是一种流行的聚类方法。对于隐马尔可夫模型至关重要的 Baum-Welch 算法是 EM 的一种特殊类型。
它适用于大数据和小数据;当其他技术失败时,当信息缺失时,它会蓬勃发展。
这是一种非常经典、强大和通用的统计学习技术,几乎在所有的计算统计学课程中都有教授。阅读完本文后,您可以对 EM 算法有一个很深的理解,并知道何时以及如何使用它。
我们从两个激励性的例子开始(无监督学习和进化)。接下来,我们看看什么是 EM 的一般形式。我们跳回现实,用 EM 来解决这两个例子。然后,我们从直觉和数学两方面解释为什么 EM 像魔咒一样起作用。最后,对本文进行了总结,并提出了一些进一步的课题。
这篇文章改编自我的博文,省略了推导、证明和 Python 代码。如果你更喜欢 LaTex 格式的数学,或者想获得这里所有问题的 Python 代码,你可以在我的博客上阅读这篇文章。
激励的例子:我们为什么关心?
可能你已经知道为什么要用 EM,也可能你不知道。不管怎样,让我用两个激励人心的例子来为新兴市场做准备。我知道这些很长,但它们完美地突出了 EM 最擅长解决的问题的共同特征:缺失信息的存在。
无监督学习:求解用于聚类的高斯混合模型
假设您有一个包含 n 个数据点的数据集。它可以是一群访问你的网站的客户(客户档案)或一个有不同对象的图像(图像分割)。聚类是在您不知道(或不指定)真正的分组时,为您的数据找出 k 个自然组的任务。这是一个无监督的学习问题,因为没有使用基本事实标签。
这种聚类问题可以通过几种类型的算法来解决,例如,诸如 k-means 的组合类型或诸如 Ward 的分层聚类的分层类型。但是,如果您认为您的数据可以更好地建模为正态分布的混合,您会选择高斯混合模型(GMM)。
GMM 的基本思想是,你假设在你的数据背后有一个数据生成机制。该机制首先选择 k 个正态分布中的一个(具有一定的概率),然后从该分布中传递一个样本。因此,一旦您估计了每个分布的参数,您就可以通过选择可能性最高的数据点来轻松地对每个数据点进行聚类。

图一。 安 例 混合高斯数据,使用 k-means 和 GMM 进行聚类(EM 求解)。注意 EM 发现的组看起来像正态分布。
然而,估计参数并不是一项简单的任务,因为我们不知道哪个分布产生了哪些点(缺失信息)。EM 是一种算法,可以帮助我们解决这个问题。这就是为什么 EM 是 scikit-learn 的 GMM 实现中的底层求解器。
群体遗传学:估计蛾的等位基因频率以观察自然选择
你以前听过“工业黑变病”这个说法吗?生物学家在 19 世纪创造了这个术语来描述动物如何由于城市的大规模工业化而改变它们的肤色。他们观察到,以前罕见的深色胡椒蛾开始主宰以煤为燃料的工业化城镇的人口。当时的科学家对此观察感到惊讶和着迷。随后的研究表明,工业化城市的树皮颜色更深,比浅色的更能掩饰深色的蛾子。你可以玩这个胡椒飞蛾游戏来更好的理解这个现象。

图二。 深色(上)和浅色(下)的胡椒蛾。图片由 Jerzy Strzelecki 通过维基共享资源提供
结果,暗蛾在捕食中存活得更好,并把它们的基因传递下去,从而形成了一个以暗斑蛾为主的种群。为了证明他们的自然选择理论,科学家们首先需要估计蛾类种群中产生黑色和产生光亮的基因/等位基因的百分比。负责蛾的颜色的基因有 C、I、T 三种类型的等位基因,基因型 C C、 C I、 C T 产生深色的胡椒蛾(Carbonaria);产生轻微的胡椒蛾。 I I 和 I T 产生中间色的蛾( Insularia )。
这里有一个手绘的图表,显示了观察到的和缺失的信息。

图三。 花椒螟等位基因、基因型和表型之间的关系。我们观察了表型,但希望估计人群中等位基因的百分比。作者图片
我们想知道 C、I 和 T 在人口中所占的百分比。然而,我们只能通过捕捉来观察到炭螟、典型和岛螟的数量,而不能观察到基因型(缺失信息)。事实上,我们没有观察到基因型和多个基因型产生相同的亚种,这使得计算等位基因频率变得困难。这就是 EM 发挥作用的地方。利用 EM,我们可以很容易地估计等位基因频率,并为由于环境污染而在人类时间尺度上发生的微进化提供具体证据。
在信息缺失的情况下,EM 如何处理 GMM 问题和胡椒蛾问题?我们将在后面的部分说明这些。但是首先,让我们看看 EM 到底是什么。
一般框架:什么是 EM?
此时,你一定在想(我希望):所有这些例子都很精彩,但真正的 EM 是什么?让我们深入研究一下。
EM 算法是一种迭代优化方法,可在存在隐藏/缺失/潜在变量的问题中找到参数的最大似然估计(MLE)。
Dempster、Laird 和 Rubin (1977)在其著名的论文(目前引用 62k)中首次全面介绍了这一概念。它因其易于实现、数值稳定和稳健的经验性能而被广泛使用。
让我们为一个一般问题建立 EM,并引入一些符号。假设 Y 是我们的观察变量,X 是隐藏变量,我们说对(X,Y)是完全数据。我们还将任何感兴趣的未知参数表示为θ∈θ。大多数参数估计问题的目标是在给定模型和数据的情况下找到最可能的θ,即,

其中被最大化的项是不完全数据可能性。使用总概率定律,我们也可以将不完全数据的可能性表示为

其中被积分的项称为完全数据似然。
所有这些完整和不完整数据的可能性是怎么回事?
在许多问题中,由于信息缺失,不完全数据似然的最大化是困难的。另一方面,使用完全数据可能性通常更容易。
EM 算法就是为了利用这种观察而设计的。它在一个期望步骤 (E 步骤)和一个最大化步骤 (M 步骤)之间迭代,以找到 MLE。
假设上标为(n)的θ是在第 n 次次迭代中获得的估计值,该算法在两个步骤之间迭代如下:
- E 步:定义 Q(θ |θ^(n))为完全数据对数似然的条件期望 w.r.t .隐变量,给定观测数据和当前参数估计,即,

- M 步:找到一个使上述期望最大化的新θ,设为θ^(n+1),即,

乍一看,上述定义似乎很难理解。一些直观的解释可能会有所帮助:
- E-step :这一步是问,给定我们的观测数据 y 和当前参数估计θ^(n),不同 X 的概率是多少?还有,在这些可能的 X,下,对应的对数似然是什么?
- M 步:这里我们问,在这些可能的 X 下,给我们最大期望对数似然的θ值是多少?
该算法在这两个步骤之间迭代,直到达到停止标准,例如,当 Q 函数或参数估计已经收敛时。整个过程可以用下面的流程图来说明。

图 4。EM 算法在 E 步和 M 步之间迭代,以获得最大似然估计,并在估计值收敛时停止。作者图片
就是这样!有了两个方程和一堆迭代,你刚刚解开了一个最优雅的统计推断技术!
EM 在行动:真的有用吗?
上面我们看到的是 EM 的一般框架,而不是它的实际实现。在这一节中,我们将一步一步地看到 EM 是如何被实现来解决前面提到的两个例子的。在验证了 EM 确实可以解决这些问题之后,我们将在下一节中直观地从数学上理解它为什么可以解决这些问题。
求解聚类的 GMM
假设我们有一些数据,并想模拟它们的密度。

图 5。 400 个点生成为四种不同正态分布的混合物。作者图片
你能看到不同的底层分布吗?显然,这些数据来自不止一个发行版。因此,单一的正态分布是不合适的,我们使用混合方法。一般来说,基于 GMM 的聚类是将(y1,…,yn)个数据点聚类成 k 组的任务。我们让

因此,x_i 是数据 y_i 的一位热码,例如,如果 k = 3 并且 y_i 来自组 3,则 x_i = [0,0,1]。在这种情况下,数据点集合 y 为不完整数据,( x , y )为扩充后的完整数据。我们进一步假设每个组遵循正态分布,即,

在通常的混合高斯模型建立之后,以概率 w_k,从第 k 个组生成新点,并且所有组的概率总和为 1。假设我们只处理不完整的数据 y 。GMM 下一个数据点的可能性为

其中φ(;μ,σ)是具有均值μ和协方差σ的正态分布的 PDF。n 个点的总对数似然为

在我们的问题中,我们试图估计三组参数:组混合概率( w )和每个分布的均值和协方差矩阵( μ ,σ)。参数估计的通常方法是最大化上述总对数似然函数与每个参数的比值(MLE)。然而,由于对数项内的求和,这很难做到。
期望步骤
让我们使用 EM 方法来代替!记住,我们首先需要在 E-step 中定义 Q 函数,它是完整数据对数似然的条件期望。由于( x , y )是完整数据,一个数据点对应的可能性为

并且只有 x_{ij} = 1 的项是有效的,因为它是一次性编码。因此,我们的总完全数据对数似然是

将θ表示为未知参数的集合( w , μ ,σ)。按照(2)中的 E 步公式,我们获得 Q 函数如下

在哪里

上面的 z 项是数据 y_i 在当前参数估计的类别 j 中的概率。这种概率在某些文本中也被称为责任。意味着每个类对这个数据点的责任。给定观测数据和当前参数估计,它也是一个常数。
最大化步骤
回想一下,EM 算法是通过在 E 步和 M 步之间迭代来进行的。我们已经在上面的 E 步骤中获得了最新迭代的 Q 函数。接下来,我们继续进行 M 步,找到一个新的θ,使(6)中的 Q 函数最大化,即我们找到

仔细观察得到的 Q 函数,会发现它实际上是一个加权正态分布 MLE 问题。这意味着,新的θ具有封闭形式的公式,可以使用微分法轻松验证:

对于 j = 1,…, k 。
表现如何?
我们在这一节回到开头的问题。我用四种不同的正态分布模拟了 400 个点。如果我们不知道底层的真实分组,我们会看到图 5。我们运行上面导出的 EM 程序,并设置算法在对数似然不再变化时停止。
最后,我们找到了混合概率和所有四组的平均和协方差矩阵。下面的图 6 显示了 EM 发现的叠加在数据上的每个分布的密度等值线,这些数据现在通过其地面实况分组进行了颜色编码。四个基本正态分布的位置(均值)和尺度(协方差)都被正确识别。与 k-means 不同,EM 为我们提供了数据的聚类和它们背后的生成模型(GMM)。

图六。 叠加在四个不同正态分布样本上的密度等值线。作者图片
估计等位基因频率
我们回到前面提到的群体遗传学问题。假设我们捕获了 n 只蛾,其中有三种不同的类型:炭蛾、典型蛾和岛蛾。然而,除了典型蛾外,我们不知道每种蛾的基因型,见上图 3。我们希望估计群体等位基因频率。让我们用 EM 术语来说。以下是我们所知道的:
- 观察到:

2.未观察到的:不同基因型的数量

3.但是我们知道它们之间的关系:

4.感兴趣的参数:等位基因频率

我们需要使用另一个重要的建模原则:Hardy-Weinberg 原则,该原则认为基因型频率是相应等位基因频率的乘积,或者是两个等位基因不同时的两倍。也就是说,我们可以预期基因型频率为

很好!现在我们准备插入 EM 框架。第一步是什么?
期望步骤
就像 GMM 的情况一样,我们首先需要计算出完整数据的可能性。注意,这实际上是一个多项式分布问题。我们有一群飞蛾,捕捉到 CC 基因型飞蛾的机会是 p_{C},其他基因型也是如此。因此,完全数据似然就是多项式分布 PDF :

并且完整数据对数似然可以写成以下分解形式:

请记住,在给定最新迭代的参数估计值的情况下,E-step 根据未观测数据 Y 对上述可能性进行有条件的期望。发现 Q 函数是

其中 n_{CC}^(n)是给定当前等位基因频率估计值的 CC 型蛾的预期数量,对于其他类型也类似。k()是一个不涉及θ的函数。
最大化步骤
由于我们获得了每种表型的预期数量,估计等位基因频率就很容易了。直观地,等位基因 C 的频率计算为群体中存在的等位基因 C 的数量与等位基因总数之间的比率。这也适用于其他等位基因。因此,在 M 步骤中,我们获得

事实上,我们可以通过对 Q 函数求微分并将它们设置为零(通常的优化程序)来获得相同的 M 步公式。
表现如何?
让我们试着用上面推导出的 em 过程来解决胡椒蛾问题。假设我们捕获了 622 只胡椒蛾。其中 85 种是卡波尼亚,196 种是海岛,341 种是典型。我们运行 EM 迭代 10 步,图 7 显示我们在不到 5 步的时间内获得了收敛的结果。

图 7。 EM 算法收敛不到五步,找到等位基因频率。作者图片
我们从例子中学到了什么?
由于缺少表型信息,估计等位基因频率是困难的。EM 帮助我们解决这个问题,它用丢失的信息来补充这个过程。如果我们回头看看 E-step 和 M-step,我们会看到 E-step 在给出最新频率估计的情况下计算最可能的表型计数;M-step 然后计算给定最新表型计数估计的最可能频率。这个过程在 GMM 问题中也很明显:在给定当前类参数估计的情况下,E-step 计算每个数据的类责任;然后,M-step 使用这些责任作为数据权重来估计新的类参数。
解释:为什么有效?
通过前面的两个例子,我们清楚地看到 EM 的本质在于用缺失的信息增加观察到的信息的 E 步/M 步迭代过程。我们看到它确实有效地找到了最大似然估计。但是为什么这个迭代过程会起作用呢?EM 只是一个聪明的黑客,还是有很好的理论支撑?让我们找出答案。
直观的解释
我们首先对 EM 的工作原理有一个直观的理解。
EM 通过在一些小步骤中将最大化不完全数据似然(困难)的任务转移到最大化完全数据似然(容易)来解决参数估计问题。
想象你正在富士山徒步旅行🗻第一次。在到达顶峰之前有九个站要到达,但是你不知道路线。幸运的是,有徒步旅行者从山顶下来,他们可以给你一个到下一站的大致方向。因此,下面是你可以达到顶端的方法:从基站开始,向人们询问到第二站的方向;去第二个车站,向那里的人打听去第三个车站的路,以此类推。在一天结束的时候(或者一天开始的时候,如果你在看日出的话🌄),你很有可能到达顶峰。
这就是 EM 为我们有缺失数据的问题寻找最大似然估计所做的事情。EM 不是最大化 ln p( x )(找到登顶的路线),而是最大化 Q 函数,找到下一个同样增加 ln p( x )(问下一站方向)的θ。下面的图 8 通过两次迭代说明了这个过程。请注意,G 函数只是 Q 函数和其他几项常数 w.r.t. θ的组合。最大化 G 函数 w.r.t. θ相当于最大化 Q 函数。

图 8。EM 的迭代过程分两步说明。当我们从当前参数估计建立并最大化 G 函数(等价地,Q 函数)时,我们获得下一个参数估计。在这个过程中,不完全数据对数似然也会增加。作者图片
摘要
在本文中,我们看到 EM 通过优化转移框架将一个有缺失信息的难题转化为一个简单的问题。我们还通过用 Python 实现一步一步地解决两个问题(高斯混合聚类和胡椒蛾种群遗传学)来看 EM 的作用。更重要的是,我们看到 EM 不仅仅是一个聪明的黑客,而且有坚实的数学基础来解释它为什么会起作用。
我希望这篇介绍性文章对您了解 EM 算法有所帮助。从这里开始,如果您感兴趣,可以考虑探索以下主题。
更多主题
深入挖掘,你可能会问的第一个问题是:那么,EM 完美吗?当然不是。有时,Q 函数很难用解析方法获得。我们可以使用蒙特卡洛技术来估计 Q 函数,例如,检查蒙特卡洛 EM 。有时,即使有完整的数据信息,Q 函数仍然很难最大化。我们可以考虑替代的最大化技术,例如,参见期望条件最大化( ECM )。EM 的另一个缺点是它只提供给我们点估计。如果我们想知道这些估计中的不确定性,我们将需要通过其他技术进行方差估计,例如 Louis 的方法、补充 EM 或 bootstrapping。
感谢阅读!请考虑在下面给我留下反馈。如果你对更多的统计学习感兴趣,可以看看我的其他文章:
直觉、插图和数学:它如何不仅仅是一个降维工具,为什么它在现实世界中如此强大…
towardsdatascience.com](/linear-discriminant-analysis-explained-f88be6c1e00b) [## 卷积神经网络:它与其他网络有何不同?
CNN 有什么独特之处,卷积到底是做什么的?这是一个无数学介绍的奇迹…
towardsdatascience.com](/a-math-free-introduction-to-convolutional-neural-network-ff38fbc4fc76)
参考
- 登普斯特,A. P .,莱尔德,N. M .,,鲁宾,D. B. (1977)。通过 EM 算法不完全数据的最大似然。英国皇家统计学会杂志:B 辑(方法论), 39 (1),1–22。








浙公网安备 33010602011771号