假设检验——简介
假设是我们对数据的假设,这些数据可能是真的,也可能是假的。在本帖中,我们将讨论评估假设真实性的统计过程——这个过程被称为假设检验。
大多数统计分析起源于比较两种类型的分布:总体分布和样本分布。让我们通过一个例子来理解这些术语——假设我们想从统计上检验我们的假设,即平均而言,学生在标准能力倾向测试中的表现在过去十年中有所提高。我们得到了一个数据集,其中包含随机选择的 100 名学生在 2009 年和 2019 年考试中的分数(最高分数= 250)。根据这些信息,我们应该确定以下细节-
Q1。这个问题的总体和样本分布是什么?
Q2。我们应该如何从统计学上评估前述假设的正确性(或不正确性)?
第一个问题的答案在于我们可以收集多少数据来进行分析。理想情况下,我们应该有十年前和今年参加考试的所有学生(全国各地)的分数,以便进行公平的比较。但由于物理条件的限制,我们无法获得全国所有在 2009 年和 2019 年的能力倾向考试中出现的学生的数据(分数)。因此,我们使用每年的一些数据点(标记)来进行统计分析。因此,总体分布是指所有学生(2009 年和 20019 年合计)的分数分布,样本分布是总体分布的子集,包含较少(比如说 100 个)随机选择的学生的分数。通常情况下,我们无法获得总体分布,只能使用样本分布。
我们可以从总体分布中抽取多个样本,我们为我们的示例抽取了两个样本分布-第一个包含来自 2009 年数据的 100 名学生的分数,第二个包含来自 2019 年数据的 100 名学生的分数。让我们将未知总体分布正式表示为 P: μ,σ,n,已知样本分布如下:

Equation 1: Two sample distributions for our example
下标中的数字是样本分布中相应年份的最后两位数字。对于每个分布,μ、σ和 n 分别代表它们的均值、标准差和样本大小(样本数),这些参数的值可以从给定的数据中计算出来(总体分布除外)。第二个问题可以用如下三步假设检验程序来回答:
第一步:建立假设
从形式上来说,我们的假设*——平均而言,学生在标准能力倾向测试中的表现在过去十年中有所改善,可以写成——是这样的说法吗,>μ₀₉(比较平均值)*,在统计上显著正确?我们关于数据的假设被称为 研究假设 *。*我们知道在数字上μ₁₉ > μ₀₉,但我们也知道 2019 年有学生的分数低于μ₀₉,因为σ₁₉ > σ₀₉,因此有必要问一问——研究假设的统计意义是什么?为了解决这样的问题,我们总是从一个 无效假设 *,*开始,并且我们假设无效假设为真,直到被证明不是这样。对于我们的例子,零假设是学生在 2009 年和 2019 年的平均分数没有显著增加,也就是说,μ₁₉ = μ₀₉.根据给定的数据,我们可以计算出零假设正确的概率,如果这个概率非常低,那么我们应该拒绝零假设而支持研究假设,否则我们应该拒绝研究假设。我们将很快学习如何计算期望的概率,但现在我们应该对给定的数据建立如下假设:

Equation 2: Setting up the hypothesis
第二步:选择合适的检验统计量
为此,我们可以撤销中心极限定理(CLT ),该定理规定样本分布的平均值的分布是正态分布,具有平均值μ和标准偏差σ/⎷n,即 Z(μ,σ/⎷n).你可以从我之前的帖子中读到更多关于中心极限定理的内容。虽然,我们没有获得 P: μ,σ,n,但是我们从 CLT 中知道μ₀₉和μ₁₉属于一个参数未知的正态分布。假设检验最棘手的部分来了,就是把μ₀₉和μ₁₉的值从一个不确定的正态 distribution,Z(μ,σ/⎷n,转换(或映射)到标准的正态分布,也就是 Z(0,1)。实际上,我们希望将 Z(μ,σ/⎷n).的μ₀₉和μ₁₉这两个点的平均值设置为零,并将标准偏差调整为 1 对于我们的假设,可以这样做:

Equation 3: Mapping our hypothesis to a standard normal distribution, Z(0,1)
即使在将值(μ₀₉和μ₁₉)映射到 Z(0,1)之后,未知量μ、σ和 n 仍然出现在我们的假设中。通过重新排列假设中的各项,我们可以很容易地去掉μ,如下所示:

Equation 4: Rearranging the terms in our hypothesis to get rid of the unknown μ
在等式 4 中求解我们假设的左侧,我们得到:

Equation 5: Hypothesis without the unknown μ
要去掉σ,就要用样本标准差最高的来代替。在我们的例子中,σ₁₉ > σ₀₉,所以我们将σ替换为σ₁₉,并在假设的分母中使用相应的 n₁₉。因此,根据已知的样本分布参数,我们的最终假设可以写成:

Equation 6: Our hypothesis in terms of the known sample distribution parameters
现在,我们可以将等式 1 至等式 6 中各个参数的值代入,以获得假设的数值。

Equation 7: Numerical values of our hypothesis testing set up
注意: 大家都知道方程 7 中数值上 2.4 大于 0,但请注意,假设检验不是数值比较问题,而是统计问题。这意味着我们在问 2.4 是否在统计意义上大于 0(不仅仅是,2.4 是否大于 0?)?这里,z=2.4 是我们的测试统计量。
所谓统计显著,我们的意思是,如果我们选择多个独立的随机样本,每个样本 100 名学生,出现在我们 2019 年的能力倾向测试中,那么这些随机样本中的大多数随机样本具有 z > 2.4(隐含的意思是,μ₁₉ > μ₀₉).)的概率是多少我们的随机样本 S₁₉只包含一组 100 名学生,其平均值(μ₁₉)与μ₀₉的比较只给出一个检验统计量(z = 2.4)。但我们有兴趣测试一个普遍假设,即如果我们从 2019 年的数据中获得另一组 100 名学生(随机选择)的分数,那么新组的平均水平也高于μ₀₉.的可能性有多大这就是为什么我们测试 z > 2.4,而不是 z = 2.4。请注意,我强调了“大多数”,因为我们应该量化“大多数”在我们的统计假设检验问题中的含义,我们将在下一步中这样做。但是先来计算 z > 2.4 的概率,也就是 p(z > 2.4),从标准正态分布的表中,Z(0,1)。在 z = -2.4 处(钟形曲线是对称的,所以-2.4 和 2.4 处的值相等),我们得到 p(z > 2.4) = 0.0082 。
你也可以用这个计算器计算 p(z > 2.4)。
第三步:选择一个显著性水平(α)
这是我们用来决定假设检验的统计显著性的参数。要做到这一点,让我们首先来看看 Z(0,1)的概率分布,如图 1 所示。

Figure 1: A plot of standard normal distribution, Z(0,1)
从图 1 可以明显看出,在标准正态分布中,68%的数据位于 1 个标准偏差内,95%的数据位于 2 个标准偏差内,99%的数据位于平均值(=0)附近的 3 个标准偏差内。在假设检验中,我们选择至少有(1-α)%的随机样本支持我们的研究假设的那个点作为我们的显著性水平。让我们来理解这一点——还记得我在第 2 步的最后一段强调了“大多数”吗?“大多数”是根据显著性水平(α)量化的,如果我们随机选择多个组,每个组 100 名学生,他们出现在 2019 年的考试中,那么我们接受我们的研究假设(μ₁₉ > μ₀₉,等价于 z>2.4),只有当(1-α)%的这些组的均值大于μ₀₉.
通常,选择α = 0.05 来检验假设检验的统计显著性。这意味着我们想要(1-α)= 1–0.05 = 95%的随机样本来支持我们的研究假设。由于我们的假设检验问题通常有一个 z 统计量,所以我们只需要 p(z > z 统计量)< α to accept the research hypothesis, otherwise we reject it in the favor of the null hypothesis. For our example, if we select α = 0.05 then we should accept the research hypothesis only if p(z> 2.4) = 0.0082 < 0.05, which is indeed correct. By accepting the research hypothesis we mean — ,显著性水平为 0.05(α= 0.05),我们得出结论:μ₁₉在统计上显著大于μ₀₉.
总之,统计假设检验采用三步程序:
- ***设置假设:*用户制定一个研究假设(例如μ₁₉ > μ₀₉)并选择一个零假设(μ₁₉ = μ₀₉)进行比较。
- ***选择适当的检验统计量:*检验统计量是总结样本信息的单个数字。例如,我们在讨论中使用了 Z 统计量,因此,我们的示例假设检验通常被称为 Z 检验。然而,根据问题的性质,应该适当地选择不同的测试统计。例如,t 统计(根据学生的 t 分布计算)应用于小样本问题(n < 30 ),相应的假设检验称为 t 检验。
- 选择显著性水平(α): 为了建立假设检验的统计显著性,用户选择合适的显著性水平。由于显著性水平是一种概率度量,其值介于 0 和 1 之间。科学文献中使用的α典型值为 0.01、0.05 和 0.10,其中α=0.05 是最常用的值。
最后,根据研究假设的性质,假设检验有三种类型:
- ***上尾检验:*一种假设检验,其中研究假设表明参数值与原假设相比有所增加(例如,μ₁₉ > μ₀₉).
- ***低尾检验:*一种假设检验,其中研究假设表明参数值与原假设相比有所下降(例如,μ₁₉ < μ₀₉).
- ***双尾检验:*一种假设检验,其中研究假设表明参数值与原假设相比发生了变化(例如,μ₁₉ ≠ μ₀₉).值得注意的是,双尾检验是对不相等的检验,而不是对感兴趣的参数值的增加或减少的检验。
使用 Python 进行机器学习中的假设检验
可能所有初学机器学习或中级水平或统计学的学生都听说过这个时髦词假设检验。
今天我将简单介绍一下这个让我在学习时感到头疼的话题。我用 python 把所有这些概念和例子放在一起。
在我考虑更广泛的事情之前,脑子里有些问题-
什么是假设检验?我们为什么要用它?假设的基础是什么?假设检验的重要参数是什么?
让我们一个一个地开始:
1。什么是假设检验?
假设检验是一种统计方法,用于利用实验数据进行统计决策。假设检验基本上是我们对总体参数的一种假设。
你说班上学生的平均年龄是 40 岁,或者一个男孩比女孩高。
所有这些我们假设的例子都需要一些统计方法来证明。我们需要一些我们假设为真的数学结论。
2 。我们为什么要用它?
假设检验是统计学中必不可少的程序。假设检验评估关于总体的两个互斥陈述,以确定哪个陈述最受样本数据支持。当我们说一个发现具有统计学意义时,这要归功于假设检验。
3 。假设的基础是什么?

Normal Curve images with different mean and variance
假设的基础是归一化和标准归一化。我们所有的假设都是围绕这两个术语的基础。让我们看看这些。

Standardised Normal curve image and separation on data in percentage in each section.
你一定想知道这两个图像之间的区别,一个可能会说我没有发现,而另一个会看到一些平坦的图形相比陡峭。伙计,这不是我想要表现的,在第一张图中,你可以看到不同的正态曲线,所有这些正态曲线可以有不同的均值和方差,在第二张图中,如果你注意到图形是适当分布的,并且均值=0,方差=1,总是。当我们使用标准化的正常数据时,z 分数的概念就出现了。
正态分布-
如果一个变量的分布具有正态曲线的形状——一种特殊的钟形曲线,那么这个变量就被称为正态分布或者具有正态分布。…一个正态分布的图形被称为正态曲线,它具有以下所有属性 : 1 .平均值、中值和众数相等。

Normal distribution formula
标准化正态分布—
标准正态分布是平均值为 0、标准差为 1 的正态分布

Standard Normal Distribution
哪些是假设检验的重要参数?
零假设:- 在推断统计学中,零假设是一个一般性的陈述或默认立场,即两个测量的现象之间没有关系,或者组之间没有关联
换句话说,这是一个基本假设,或者是基于领域或问题知识做出的。
例如:一家公司的产量为每天 50 台等。
替代假设:-
备选假设是在假设测试中使用的与原假设相反的假设。人们通常认为这些观察结果是真实效应的结果(叠加了一些偶然变化)
例如:某公司生产的是!=50 单位/每天等。

Null and Alternate hypothesis.
**显著性水平:**指我们接受或拒绝零假设的显著程度。接受或拒绝一个假设不可能有 100%的准确性,因此我们选择一个通常为 5%的显著性水平。
这通常用 alpha(数学符号)表示,通常是 0.05 或 5%,这意味着您的输出应该有 95%的信心在每个样本中给出类似的结果。
**第一类错误:**当我们拒绝原假设,尽管那个假设是真的。第一类误差用α表示。在假设检验中,显示临界区域的正态曲线称为α区域
**第二类错误:**当我们接受零假设但它是假的。第二类错误用β表示。在假设检验中,显示接受区域的正态曲线称为贝塔区域。
单尾检验:- 统计假设的检验,其中拒绝区域仅在抽样分布的一侧,称为单** - 尾检验。**
例如:-一所大学有≥ 4000 名学生或数据科学≤ 80%的组织采用。
双尾检验:- 一个两个 - 尾检验是一种统计检验,其中一个分布的临界面积为两个 - 侧,并检验一个样本是否大于或小于某个范围的值。如果被测样品落入任何一个关键区域,则接受替代假设,而不是零假设。
举例:某学院!= 4000 学生或数据科学!= 80%的组织采用

one and two-tailed images
P 值:-****P 值或计算概率,是当研究问题的零假设(H 0)为真时,发现观察到的或更极端的结果的概率——极端的定义取决于假设是如何被检验的。
如果您的 P 值小于所选的显著性水平,那么您拒绝零假设,即接受您的样本提供了支持替代假设的合理证据。它并不意味着“有意义的”或“重要的”差异;这由您在考虑结果的现实相关性时决定。
例子:你有一枚硬币,你不知道这是公平的还是棘手的,所以让我们决定无效和交替假设
H0:一枚硬币是公平的。
H1:硬币是一种狡猾的硬币。和α=5%或 0.05
现在我们抛硬币,计算 p 值(概率值)。
第一次投掷硬币,结果是尾 - P 值= 50%(因为头和尾的概率相等)
第二次抛硬币,结果是尾,现在 p 值= 50/2 = 25%
同样,我们连续投掷 6 次,得到的结果是 P 值= 1.5% ,但我们将显著性水平设为 95%,意味着我们允许 5%的误差率,这里我们看到我们超出了该水平,即我们的零假设不成立,因此我们需要拒绝并提出这枚硬币是一枚棘手的硬币,实际上是一枚复杂的硬币。
:-现在想象你不戴帽子。你对数据分析感兴趣。您有一个包含 10 个值的数据集。如果你不估算任何东西,每个值可以取任意数,对吗?每个值都可以自由变化。但是,假设您想使用单样本 t 检验,用 10 个值的样本来检验总体均值。现在,您有了一个约束条件—平均值的估计。具体是什么约束?根据平均值的定义,以下关系必须成立:数据中所有值的总和必须等于 n x 平均值,其中 n 是数据集中值的数量。
因此,如果一个数据集有 10 个值,这 10 个值的总和必须等于平均值 x 10。如果 10 个值的平均值是 3.5(您可以选择任何数字),此约束要求 10 个值的总和必须等于 10 x 3.5 = 35。
有了这个约束,数据集中的第一个值可以自由变化。不管它是什么值,所有 10 个数的和仍然有可能是 35。第二个值也可以自由变化,因为无论您选择什么值,它仍然允许所有值的总和为 35 的可能性。
现在让我们来看看一些广泛使用的假设检验类型:-
- T 检验(学生 T 检验)
- z 检验
- 方差分析检验
- 卡方检验
****T-检验:-T-检验是一种推断统计,用于确定在某些特征上可能相关的两组的平均值之间是否存在显著差异。它主要用于数据集,如作为投掷硬币 a 100 次的结果而记录的数据集,将遵循正态分布,并且可能具有未知的方差。t 检验用作假设检验工具,允许检验适用于总体的假设。
t 检验有两种类型:1。一个样本 t 检验 2。双样本 t 检验。
单样本 t 检验:单样本 t 检验确定样本均值在统计上是否不同于已知或假设的总体均值。单样本 t 测试是一种参数测试。
例如:-你有 10 个年龄,你正在检查平均年龄是否为 30。(使用 python 检查下面的代码)
from scipy.stats import ttest_1samp
import numpy as npages = np.genfromtxt(“ages.csv”)print(ages)ages_mean = np.mean(ages)
print(ages_mean)
tset, pval = ttest_1samp(ages, 30)print(“p-values”,pval)if pval < 0.05: # alpha value is 0.05 or 5%
print(" we are rejecting null hypothesis")
else:
print("we are accepting null hypothesis")
上述代码的输出是:

one-sample t-test output
双样本 T 检验:- 独立样本 T 检验或双样本 T 检验比较两个独立组的平均值,以确定是否有统计证据表明相关总体平均值存在显著差异。独立的样本 t 检验是一个参数检验。这个测试也被称为:独立 t 测试。
示例:week1 和 week2 之间有任何关联吗(下面用 python 给出了代码)
from scipy.stats import ttest_ind
import numpy as npweek1 = np.genfromtxt("week1.csv", delimiter=",")
week2 = np.genfromtxt("week2.csv", delimiter=",")print(week1)
print("week2 data :-\n")
print(week2)
week1_mean = np.mean(week1)
week2_mean = np.mean(week2)print("week1 mean value:",week1_mean)
print("week2 mean value:",week2_mean)week1_std = np.std(week1)
week2_std = np.std(week2)print("week1 std value:",week1_std)
print("week2 std value:",week2_std)ttest,pval = ttest_ind(week1,week2)
print("p-value",pval)if pval <0.05:
print("we reject null hypothesis")
else:
print("we accept null hypothesis")

2-sampled t-test output
成对样本 t 检验:- 成对样本 t 检验也叫相依样本 t 检验。这是一个单变量测试,测试两个相关变量之间的显著差异。这方面的一个例子是,如果您在某个治疗、条件或时间点之前和之后收集个人的血压。
H0:——表示两个样本之间的差值为 0
H1:-两个样本之间的平均差异不为 0
检查下面的代码是否相同
import pandas as pd
from scipy import stats
df = pd.read_csv("blood_pressure.csv")df[['bp_before','bp_after']].describe()ttest,pval = stats.ttest_rel(df['bp_before'], df['bp_after'])
print(pval)if pval<0.05:
print("reject null hypothesis")
else:
print("accept null hypothesis")
当你可以进行 Z 测试的时候。
统计中使用了几种不同类型的检验(即 f 检验、卡方检验、 t 检验)。在以下情况下,可以使用 Z 检验:
- 您的样本量大于 30。否则,使用 t 测试。
- 数据点应该是相互独立的。换句话说,一个数据点不相关或者不影响另一个数据点。
- 您的数据应该是正态分布的。然而,对于大样本量(超过 30),这并不总是重要的。
- 您的数据应该从总体中随机选择,其中每一项都有平等的机会被选中。
- 样本大小应尽可能相等。
再举一个例子,我们使用 z-test 对血压进行一些均值测试,如 156 (python 代码如下所示)单样本 Z 测试。
import pandas as pd
from scipy import stats
from statsmodels.stats import weightstats as stestsztest ,pval = stests.ztest(df['bp_before'], x2=None, value=156)
print(float(pval))if pval<0.05:
print("reject null hypothesis")
else:
print("accept null hypothesis")
双样本 Z 检验- 在双样本 Z 检验中,类似于这里的 t 检验,我们检查两个独立的数据组,并决定两组的样本均值是否相等。
H0:两组平均值为 0
H1:两组的平均值不为 0
示例:我们在采血后和采血前检查采血数据。(下面是 python 代码)
ztest ,pval1 = stests.ztest(df['bp_before'], x2=df['bp_after'], value=0,alternative='two-sided')
print(float(pval1))if pval<0.05:
print("reject null hypothesis")
else:
print("accept null hypothesis")
****ANOVA(F-TEST):-t-TEST 在处理两组时效果很好,但有时我们希望同时比较两组以上的数据。例如,如果我们想测试选民年龄是否因种族等分类变量而不同,我们必须比较变量的每个级别或组的平均值。我们可以对每一组进行单独的 t 检验,但是当你进行多次检验时,就会增加假阳性的机会。方差分析或 ANOVA 是一种统计推断测试,允许您同时比较多个组。
F =组间变异性/组内变异性

F-Test or Anova concept image
与 z 分布和 t 分布不同,F 分布没有任何负值,因为组间和组内的变异性由于每个偏差的平方而总是正的。
单向 F-检验(Anova) :- 它根据两组或更多组平均相似性和 F-分数来判断它们是否相似。
示例:有 3 种不同类别植物及其重量,需要检查所有 3 组是否相似(下面的 python 代码)
df_anova = pd.read_csv('PlantGrowth.csv')
df_anova = df_anova[['weight','group']]grps = pd.unique(df_anova.group.values)
d_data = {grp:df_anova['weight'][df_anova.group == grp] for grp in grps}
F, p = stats.f_oneway(d_data['ctrl'], d_data['trt1'], d_data['trt2'])print("p-value for significance is: ", p)if p<0.05:
print("reject null hypothesis")
else:
print("accept null hypothesis")
双向 f 检验:- 双向 f 检验是单向 f 检验的扩展,当我们有 2 个自变量和 2+组时使用。双向 f 检验不能说明哪个变量是主导变量。如果我们需要检查个体显著性,则需要执行事后测试。
现在让我们来看看总的平均作物产量(不按任何分组的平均作物产量),以及按每个因素和按组合在一起的因素的平均作物产量
import statsmodels.api as sm
from statsmodels.formula.api import olsdf_anova2 = pd.read_csv("[https://raw.githubusercontent.com/Opensourcefordatascience/Data-sets/master/crop_yield.csv](https://raw.githubusercontent.com/Opensourcefordatascience/Data-sets/master/crop_yield.csv)")model = ols('Yield ~ C(Fert)*C(Water)', df_anova2).fit()
print(f"Overall model F({model.df_model: .0f},{model.df_resid: .0f}) = {model.fvalue: .3f}, p = {model.f_pvalue: .4f}")res = sm.stats.anova_lm(model, typ= 2)
res
卡方检验- 当一个总体中有两个分类变量时,应用该检验。它用于确定两个变量之间是否有显著的关联。
例如,在选举调查中,选民可以按性别(男性或女性)和投票偏好(民主党、共和党或无党派)分类。我们可以使用卡方检验来确定性别是否与投票偏好有关
查看下面的 python 示例
df_chi = pd.read_csv('chi-test.csv')
contingency_table=pd.crosstab(df_chi["Gender"],df_chi["Shopping?"])
print('contingency_table :-\n',contingency_table)#Observed Values
Observed_Values = contingency_table.values
print("Observed Values :-\n",Observed_Values)b=stats.chi2_contingency(contingency_table)
Expected_Values = b[3]
print("Expected Values :-\n",Expected_Values)no_of_rows=len(contingency_table.iloc[0:2,0])
no_of_columns=len(contingency_table.iloc[0,0:2])
ddof=(no_of_rows-1)*(no_of_columns-1)
print("Degree of Freedom:-",ddof)
alpha = 0.05from scipy.stats import chi2
chi_square=sum([(o-e)**2./e for o,e in zip(Observed_Values,Expected_Values)])
chi_square_statistic=chi_square[0]+chi_square[1]
print("chi-square statistic:-",chi_square_statistic)critical_value=chi2.ppf(q=1-alpha,df=ddof)
print('critical_value:',critical_value)#p-value
p_value=1-chi2.cdf(x=chi_square_statistic,df=ddof)
print('p-value:',p_value)print('Significance level: ',alpha)
print('Degree of Freedom: ',ddof)
print('chi-square statistic:',chi_square_statistic)
print('critical_value:',critical_value)
print('p-value:',p_value)if chi_square_statistic>=critical_value:
print("Reject H0,There is a relationship between 2 categorical variables")
else:
print("Retain H0,There is no relationship between 2 categorical variables")
if p_value<=alpha:
print("Reject H0,There is a relationship between 2 categorical variables")
else:
print("Retain H0,There is no relationship between 2 categorical variables")
您可以在我的 git 存储库中获得所有代码。
啊,我们终于结束了这篇文章。我希望这篇文章会有所帮助。任何反馈都会受到欢迎。
更多更新请查看我的 git 并在媒体上关注 we。
使用方差分析进行假设检验:一项核心数据科学技能
使用假设检验确定最有利可图的客户的例子
项目目标
作为 Northwind 数据库项目的一部分,我需要对数据提出一些问题,以便为公司获得有价值的商业见解。Northwind 数据库是 Microsoft 为一家名为 Northwind Traders 的虚构公司提供的示例数据库,该公司从世界各地进口和出口消费品。该数据库包含公司活动的一系列信息,包括客户、客户订单、产品及其供应商。我感兴趣的是更好地了解他们的客户,并找出哪些客户群体对 Northwind 的利润贡献最大。所以我决定问的一个问题是:
不同地区的客户每份订单的平均收入是否不同?
陈述假设
为了回答这个问题,我首先创建了一个无效替代假设:
零假设:每个订单的平均花费金额在不同的客户区域之间是相同的
另一个假设:在不同的客户区域,每个订单的平均消费金额是不同的(或高或低)
阿尔法水平(即,当假设为真时拒绝零假设的概率)设置为 0.05。
获取和清理数据
第一步是使用这个(只有轻微的标签错误)模式提取正确的数据:

Northwind database schema
为了回答正在调查的问题,我需要提取客户区域、订购的每种产品的总量、单价以及每份订单的折扣级别。为此,我使用 Order 表连接了 Customer 和 OrderDetail 表:
# Importing the required libraries
from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker
import pandas as pd
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
import statsmodels.api as sm
from statsmodels.formula.api import ols# Creating an engine and connecting to a database with SQLAlchemy
engine = create_engine('sqlite:///Northwind_small.sqlite', echo=True)
Session = sessionmaker(bind=engine)
session = Session()
con = engine.connect()# Extracting the data required as a pandas dataframe using a SQL query
df3 = pd.read_sql_query('''
SELECT c.Region, od.OrderId, od.Quantity, od.UnitPrice, od.Discount
FROM Customer c
JOIN [Order] o ON c.Id = o.CustomerId
JOIN OrderDetail od ON od.OrderId = o.Id
''', engine)
产生的数据框架现在显示了每个订单中每个产品的订单 ID、数量、单价和折扣:

The first five rows of the dataset
但我真正想要的是每份订单的总收入。这是使用下面单元格中的代码计算的,该代码将折扣应用于单价和单位数量的乘积,然后对每个订单求和,并删除不再需要的列:
# Calculating the revenue per sub-order
df3['price_per_order'] = df3.Quantity * df3.UnitPrice * (1 - df3.Discount)# Dropping the columns for quantity, unit price and discount now that we have the total revenue
df3.drop(['Quantity', 'UnitPrice', 'Discount'], axis=1, inplace=True)# Grouping the data by order and summing the revenue for each order
df3 = df3.groupby(['Region', 'OrderId'])['price_per_order'].sum().reset_index()# Dropping the OrderId as we no longer need this
df3.drop('OrderId', axis=1, inplace=True)
这给我留下了一个只包含我需要的数据的数据框架:

The first five rows of the new dataset
但是,对每个地区的订单数量进行快速统计后发现,一些地区的客户仅下了少量订单:

因为方差分析将用于检验假设,所以最好确保相对相等的样本量,特别是满足方差相等的假设。因此,较小的群体与其他具有地理意义的群体结合在一起,并采用了 30 人的最小群体规模。
# Combining Eastern and Southern Europe
df3.loc[(df3.Region == 'Eastern Europe') | (df3.Region == 'Southern Europe'),'Region'] = 'Southern and Eastern Europe'# Combining Scandinavia and Northern Europe
df3.loc[(df3.Region == 'Scandinavia') | (df3.Region == 'Northern Europe'),'Region'] = 'Northern Europe and Scandinavia'# Combining Central and South America
df3.loc[(df3.Region == 'Central America') | (df3.Region == 'South America'),'Region'] = 'South and Central America'

探索数据
既然数据已经有了正确的格式和分组,就可以开始研究它了。以下代码块生成了下图,该图绘制了每个地区的订单数、每份订单的总收入和每份订单的平均收入:
# Plotting the number of orders, total revenue per order and average revenue per order for each region
fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(8,8))
df3.groupby(['Region'])['Region'].count().plot(kind='barh', ax=ax1)
df3.groupby(['Region'])['price_per_order'].sum().plot(kind='barh', ax=ax2)
df3.groupby(['Region'])['price_per_order'].mean().plot(kind='barh', ax=ax3)
ax1.set_title('Total number of orders')
ax1.set_ylabel('')
ax2.set_title('Total revenue ($)')
ax2.set_ylabel('')
ax3.set_title('Average revenue per order ($)')
ax3.set_ylabel('')
fig.subplots_adjust(hspace=0.4);

图表显示,西欧是订单数量最多的地区,总收入也最高。然而,北美的平均订单最贵(其次是西欧)。南欧和东欧的订单数量最少,总收入最低,平均订单最便宜。第三张图支持了另一个假设,即各地区之间的平均订单收入存在显著差异。这通过使用统计假设检验被进一步研究。
假设检验和结果
为了回答来自不同地区的顾客每份订单的平均花费是否不同的问题,使用了 ANOVA。这评估了多个样本之间的变化程度,在这种情况下,每个样本是不同的区域。
方差分析假设数据是正态分布的,样本具有相似的方差。分布图是使用 seaborn 绘制的,这表明数据非常严重地正偏,具有长尾。对数据进行对数变换会产生具有更相似分布的更正态分布的数据。对数转换数据的分布(如下所示)由以下代码生成:
# Copying the dataset and log-transforming price_per_order
df3_log = df3.copy()
df3_log['price_per_order'] = np.log(df3['price_per_order'])# Plotting the distributions for the log-transformed data
plt.figure(figsize=(8,5))
for region in set(df3_log.Region):
region_group = df3_log.loc[df3_log['Region'] == region]
sns.distplot(region_group['price_per_order'], hist_kws=dict(alpha=0.2), label=region)
plt.legend()
plt.xlabel('Revenue per order (log-transformed)')

数据现在更加正态分布,均值的方差也更加相似。现在可以进行方差分析测试了:
# Fitting a model of price_per_order on Region categories, and using statsmodels to compute an ANOVA table
lm = ols('price_per_order ~ C(Region)', df3_log).fit()
sm.stats.anova_lm(lm, typ=2)

上面的 ANOVA 表显示 p 值低于 alpha 值 0.05。因此,我能够拒绝零假设,接受替代假设。不同地区之间的平均订单价值存在统计上的显著差异,即平均而言,来自世界不同地区的客户在订单上花费的金额不同。
结论
商业洞察:
- 不同地区客户的平均每单收入存在显著的统计差异。
- 西欧客户下的订单最多,是 Northwind 盈利的最大贡献者。然而,尽管北美客户的订单数量大约是西欧客户的一半,但他们平均每份订单的花费更多。
- 订单平均最贵的地区(北美,1,945.93 美元)和订单最便宜的地区(南欧和东欧,686.73 美元)之间的差额为 1,259.20 美元,是北美订单的 2.8 倍。
- 南欧和东欧的订单数量最少,总收入最低,每笔订单的平均收入也最低。
- 北美客户的订单数量与南美和中美客户相似,但他们每份订单的平均支出是南美和中美客户的 1.8 倍。
未来工作的潜在业务行动和方向:
- 如果 Northwind 希望专注于利润更高的客户,一个潜在的行动将是停止为南欧和东欧的客户提供服务,而更多地关注西欧和北美的客户。
- 然而,还需要进一步的分析来证实这些发现。例如,一些更贵的产品可能只在某些地区有售。
假设检验——什么、为什么和如何

理解假设检验背后的直觉。它到底是什么,我们为什么要这样做,以及如何执行它。让我们开始吧!
直觉
我们先来了解一下假设检验背后的直觉。假设你在一家电子商务公司工作,你设计了一个新的网站来吸引更多的顾客。你的老板想知道你的新网站设计是否值得投资,或者只是一个噱头。你是做什么的?你不能只是把网站推广给你所有的客户,然后全力以赴。几天后,你会想通过引导流量到新网站来确认你的新设计是否真的有效。如果结果出来惊人的好,那意味着你的新网站设计确实很棒。否则,这可能只是一个一次性的运动。
你的新网站就是你想要测试的假设。但是你想让它和别的东西比较,对吗?为此,你做了一个“零假设”。你的无效假设说你的网站是垃圾。没有任何实际影响。然后你提出一个‘替代假设’。你的另一个假设是你的新网站真的很棒,它真的增加了你的客户。我们首先假设我们的零假设是正确的。所以如果你成功地证明了你的零假设是错误的,你实际上证明了你的替代假设是正确的!
太好了!所以你现在对我们在做什么,为什么我们在做什么*,以及我们如何我们在做什么有一个直觉。现在让我们进入细节。*
显著性水平和置信区间
继续我们的示例,假设贵公司每天的平均客户数量约为 5430 人。如果你为一年中的每一天的顾客画一张图,你将得到下面的正态分布图,平均值为 5430。

The normal distribution curve with mean μ and standard deviation σ
在你开始测试你的新想法之前,你设置一个显著性水平——一个阈值概率。这也被称为临界值— α。
曲线下超过临界值的区域就是临界区。临界值定义了我们的样本统计量(我们的实验值)与零假设值(原始平均值)之间的距离,在此之前,我们可以说它是异常的,足以拒绝零假设。
然后你把流量导向你的新网站几天,看看结果。假设平均有 5723 个客户。现在这个数字的增加可能是由于你的新设计(你的替代假设提出的)或者仅仅是运气。然后,我们计算这个实验的 测试统计量——这是 Z 测试的 Z 得分(下面将详细介绍)。这意味着,我们需要检查 5723 的实验值离我们的原始分布均值有多远或多少标准差。这可以使用下面的表达式来计算:

X = Sample mean, μ=Population mean, σ=Standard deviation
临界值可以是 0 到 1 之间的任何值。通常选择为 0.05。这意味着只有当达到 5723 的 Z 值的 P 值小于 0.05 时,你才能拒绝零假设。否则,你无法拒绝。现在,你可能知道曲线下的面积表示总概率,超过临界值的面积将是 5%。或者我们可以说我们有 95%的置信区间。如果将临界值降低到 0.01,假设检验会变得更加严格,因为如果要拒绝零假设,您现在希望新的 p 值更低(小于 0.01)。这意味着你的置信区间将是 99%。
p 值
达到 5723 或更大极限值的概率是假设我们的零假设为真的 P 值。请注意,这不是实现点估计 5723 的概率,这将是非常低的。它是实现一个如此罕见甚至更罕见的价值的总概率。它是正常曲线下超过 P 值标记的区域。这个 P 值是用我们刚刚找到的 Z 值计算出来的。每个 Z 得分都有一个对应的 P 值。这可以使用任何统计软件如 R 或甚至从Z-表中找到。

现在,如果这个 P 值小于临界值——意味着达到这个客户数量的可能性非常小,这确实不是运气,我们可以拒绝我们的零假设。现在,我们不能说我们接受我们的替代假设,因为统计学是一个推理游戏,我们永远不可能 100%确定。但是,正如我们已经设定了我们的置信区间,我们可以有 95%甚至 99%的把握。这就是错误出现的地方!
第一类和第二类错误
就像我说的,我们永远不能百分百确定。你的结论总是有可能是错误的,而事实真相是完全相反的。
如果你的显著性水平是 0.05,这意味着你有 5%的几率是错的!意思是,你拒绝了你的无效假设,当它在现实中是正确的时候。这是第 1 类错误。因此,犯类型 1 错误的概率是 α 。
反过来,你也可以断定你的零假设是真的,或者用统计学的话说,你没有拒绝你的零假设,而实际上它是假的。这是第二类错误的一个例子。犯第二类错误的概率用β来解释— β 。

[source](https://bmjopen.bmj.com/content/7/8/e015397)
功效是当零假设为假时,拒绝零假设的概率。所以犯第二类错误的概率是 1-(幂)或 1-β。
现在我们如何减少这些误差?我们可以简单地增加我们的信心水平,或者换句话说,减少我们的α。这样做减少了α下的面积,从而减少了犯类型 1 错误的概率。但是减少α 会增加犯第二类错误的概率,因为你将会更多地拒绝你的零假设!所以有一个取舍。
你也可以增加你的样本大小,n,这将使你的分布曲线更窄,从而降低犯错误的概率。
单尾与双尾检验
统计测试也可以是方向性的。这意味着你提出的另一个假设是结果增加或者减少或者减少*。在我们的例子中,我们想测试客户是否增加了。所以这是一个单尾检验的例子。因此,对于 95%的置信区间,5%的概率分布是在我们测试的方向上(在我们的例子中是向右)。*
相反,我们也可以从另一个方向进行测试。例如,测试对软件进行某些更改是否会显著减少处理时间。在这种情况下,我们将考虑正常曲线的左侧部分。

对于两个尾检验的情况,没有具体的方向。我们的替代假设只是检查新的统计数据是否发生了显著变化,即它是显著大于还是小于原始统计数据。因此,对于 95%的置信区间,我们的 5%概率分布将被分成两部分,两个方向各 2.5%。因此α 将是 0.025。
统计测试的类型
z 检验
当要计算两个分布之间的均值差异时,通常使用 z 检验。总体的标准差应该是已知的,样本数应该大于 30。z-检验的一个最重要的假设是所有的样本观测值都是相互独立的。
t 检验
当总体的标准偏差未知且必须从样本中近似得出时,使用 t 检验。它通常用于比较两个不同的群体。t 检验有三种主要类型:
卡方检验
卡方检验通常用于与分类变量相关的检验。卡方检验主要有两种类型——拟合优度检验和关联检验。对于一个分类变量,拟合优度测试用于测试观察值是否与分布相匹配。另一方面,关联测试用于比较列联表中的两个变量,看它们是否独立。
卡方检验通常用于 特征选择 过程。我们使用关联测试来检查所有特征与目标变量的相关性。然后选择相关性最高的顶部特征来训练模型。
这些是主要使用的统计测试。还有更多的测试,如 F 检验、方差分析。
如果您想更深入地挖掘并理解背后的实际数学,我建议您参考以下优秀资源:
- https://www . uda city . com/course/intro-to-推论-统计- ud201
- https://www.khanacademy.org/math/ap-statistics
本文到此为止。请在下面评论你的想法!
假设检验可视化
从字面上看统计测试是如何工作的
在本文中,我们将对假设检验有一个直观的视觉感受。虽然网上有很多用文字解释的文章,但主要依靠视觉的文章还远远不够;这是令人惊讶的,因为这个主题非常适合通过图片和电影来阐述。
但是在我们走得太远之前,让我们简单描述一下它到底是什么。
什么是…
在进行一般性描述之前,最好从假设检验的例子开始。我们首先需要的是一个假设。例如,我们可以假设男性的平均身高大于女性的平均身高。本着‘矛盾求证’的精神,我们首先假设两性的平均身高没有差别。这成为我们的默认假设,或者无效假设。如果我们收集两组人的身高数据,并发现如果零假设为真,那么观察到该数据的可能性极小(例如,“如果零假设为真,为什么我在样本中看到男性和女性的平均身高有如此大的差异?”),我们可以拒绝它,得出确实有区别的结论。
对于一般的假设检验问题,我们需要以下内容:
- 我们关心的一个指标(上面例子中的平均身高)。
- 两个(或更多)以某种已知方式彼此不同的群体(在上面的例子中是雄性和雌性)。
- 一个无效的假设,即我们的组之间的度量是相同的,因此我们在收集的数据中观察到的任何差异都只能是统计噪声和另一个假设,即确实存在一些差异。
然后,我们可以继续收集两组的数据,估计他们感兴趣的度量,并查看我们的数据与我们的无效假设和替代假设的兼容性如何。最后一部分是假设检验理论的来源。我们将在前面的章节中看到它是如何工作的。
如何拒绝
现在我们已经形成了我们的假设并收集了我们的数据,我们如何用它来拒绝我们的零?总体框架如下:
- 定义一个统计量,用于测量两组之间我们关心的指标的偏差。在我们的平均身高示例中,这样的度量可以是男性和女性平均身高之间的差异(零假设是零)。另一个可能是男性和女性平均身高的比率(零假设是 1)。
- 由于我们从假设零假设开始,我们已经知道了检验统计分布的平均值(在上面的例子中,零表示差异,一表示比率)。关于分布的其他一切(如方差和其他矩),我们从收集的数据中获得。
- 现在,从收集的数据中获得统计的点估计值(对于平均高度的差异,平均您看到的两组的高度并取其差异)。如果零假设是真的,那么看到比我们观察到的估计值更极端的东西的概率是多少?如果这个概率(称为 p 值)低于某个阈值,我们得出结论,零假设不可能产生它。这个概率成为我们测试的假阳性率的估计值(因为我们将拒绝 null,即使它在这个概率下是真的)。
关于方差的一个注记
需要强调的是,关注点的分布是测试统计中估计值的分布,而不是总体中度量值的分布。例如,在我们比较男性和女性平均身高的例子中,男性的身高会有一些差异。然而,这不是我们感兴趣的方差。如果我们取 n 个男性的平均身高,我们就得到了男性人口平均身高的估计值。除非我们集合地球上所有男性成员,测量他们的身高并取平均值,否则这个估计值会有偏差*。如果我们再进行一次实验,我们可能会得到一组不同身高的男性。所以,这次我们得到的平均值会略有不同。重复实验之间的这种差异(如果我们进行了多次)是我们有兴趣估计的。*
当我们增加任何一组的样本量时,该组估计值的方差就会减小。如果你刚好过敏或者只是没心情数学,只想跳到图片,可以跳过下面一节跳到下一节,我不会难受的:)
方差:数学
我们的检验统计量的方差(例如,男性和女性平均身高估计值的差异)取决于两组的度量估计值的方差。为了具体说明这一点,假设我们对 n1 名男性进行了采样,并计算了他们身高的方差 s1。男性平均身高估计值的方差变成:s1 /n1。这是因为男性的平均身高估计为:

Eq 1: Estimate of mean height of males
因此,这个估计值的方差(如果我们对 n_1 个雄性样本进行多次采样,估计值 h_m 会变化多少)变为:

Eq 2: Variance in estimate of average height of males given we sample n_1 of them.
在等式(2)中,V(h_i)的最佳估计,即单个样本的方差是 S1,即根据我们的样本计算的方差。你可以看到,随着我们收集的样本越来越多,这个估计量的方差越来越小。
类似地,如果抽样 n_2 名女性,女性身高方差的估计为:s_2 /n2。
如果我们选择均值差异作为我们的检验统计量,它可以表示为:

并且该统计中的方差变成(因为来自两组的样本之间没有相关性):


Eq 3: Variance of test statistic
要使它变小,n_1 和 n_2 都必须变大。这里,我们举了手段不同的例子。然而,一般结论也适用于我们可能构建的其他检验统计量(如均值比)。
给我看看照片
好吧,我答应给你照片,但你到目前为止只看到文字和符号。让我们想象一下假设检验是什么样子的。下面的图 0 显示了 t 的概率密度函数(均值差异的检验统计量)。
假设我们选择了一个假阳性率(FPR),α为 15%(我们不希望有超过 15%的几率在没有差异的情况下错误地得出有差异的结论)。
粉色垂直线是右边区域变为 15%的点。所以这成为我们拒绝零的门槛。如果观察到的统计值大于粉红线,我们拒绝零(推断高度之间存在显著差异),如果小于粉红线,我们不拒绝它(数据无法推断高度存在显著差异)。

Fig 0: Distribution of the difference of means. The pink area is 15%, so the pink vertical line is our current threshold. If the difference we observe from the data is greater than it, we reject the null.
注意,对于我们拒绝零假设的标准,我们不是基于检验统计量本身,而是基于从零假设下的分布计算的概率来构造阈值。为什么要用这种复杂的方式呢?因为在给定足够的数据的情况下,它确保我们的测试能够捕捉到两组指标之间的最小差异,因为统计估计的方差将变为零。
假设男性的身高总是比女性高 5 厘米。上面图 1 中的绿点代表了这 5 厘米的差异。然而,由于它位于粉红色阈值的左侧,我们无法识别它,并得出结论,没有发现差异。
让我们看看当我们开始增加其中一组的数据量时会发生什么(假设是雄性——在图中这些组被标记为治疗组和对照组;假设治疗是指雄性,控制是指雌性)。根据等式(3),测试统计的方差开始下降。结果,粉红色的线(右边的区域是 15%)开始向左朝着绿点移动。同样根据图 1,我们可以看到,在另一组的贡献开始占主导地位之前,增加男性组的样本量只能减少这么多的方差。所以,粉色的线不能到达绿色的点。

Fig 1: As we increase the sample size of the one of the groups, the variance of the test statistic under the null reduces. This causes the point at which the FPR is 15% to shift to the left. Eventually however, the variance stops reducing since the second group becomes the blocker. Created using: https://github.com/ryu577/pyray
然而,当我们增加第二组(女性)的样本量时,方差再次开始显著减小,并且我们的阈值粉色线再次向左移动,直到它最终到达绿点。有了这么多数据,我们就能捕捉到平均高度的差异,小到蓝线上的绿点。这个故事的寓意是,给定足够的数据(在两个组中),即使是最小的效应大小也可以被捕捉到。

Fig 2: Beyond a point, increasing the sample size for the first group started giving us diminishing returns. So, we had to start increasing the sample size of the other group to get a further reduction in the variance of the distribution of the test statistic under the null hypothesis.
现在,我们刚刚表明,如果我们对假阳性率有 15%的容差,我们会得到上面图 1 和图 2 中的粉红色线。但这是我们设定的。如果假阳性率是我们唯一关心的,为什么不把它设置得尽可能低(0)?这将涉及到将粉红色线移动到无穷大,我们永远不会拒绝零。不会有假阳性,因为根本不会有阳性。这个测试的明显缺点是当另一个假设事实上是真的时(这里是高度之间的差异)。现在,因为我们从不拒绝零,我们会错误地总是拒绝它,即使存在差异。这将使我们的假阴性率(即使有显著差异,概率测试也返回阴性)达到 100%。在统计学术语中,假阳性率被称为第一类错误,用α表示,而假阴性率被称为第二类错误,用β表示。现在,α来自零假设,其中我们知道检验统计量的平均值(对于我们一直在进行的等均值检验,均值差的平均值为零)。为了得到β,我们假设交替假设为真(确实存在高度差异)。所以,我们需要得到它下面的统计分布。这个备择假设的方差和其他方面应该与零假设相同。但是,我们应该把意思定为什么呢?对于空值,它是零(对于均值差异检验统计量)。另一种方法是,我们挥挥手,从帽子里抽出一个数字。这就是我们希望测试关注的“效果大小”。基本上,我们假设平均值的差异正好是 5 cm(比方说),然后看看我们的测试在捕捉这种差异方面有多好(拒绝零)。
在下图 3 所示的两个图表中,黄色曲线是零假设,紫色曲线是替代假设。它们峰值的差距就是效应大小。图 3 清楚地显示了α(用黄色区域表示)和β(用紫色区域表示)之间的权衡。当我们减小α时,我们将粉色阈值向右移动。但这会导致紫色区域β增加。还要注意,当α=0 时,我们总是预测为负。因此,当交替假设为真时,假阴性率变为β=1。类似地,当α=1 时,β=0。因为它们之间有明显的权衡,我们会得到一个连接这两个极端的递减函数。这种α-β权衡图如下图 3 左下方所示。当粉色阈值来回移动时,我们沿着递减函数移动。

Fig 3: Tradeoff between FPR and FNR. Image created using https://github.com/ryu577/pyray
最糟糕的测试
现在我们知道,假阳性率α由我们来设定,但它与假阴性率β之间存在权衡。对于给定的样本量(在两组中),任何基于我们构建的统计数据的测试都将具有如图 3 左下方所示的α-β曲线。我们希望α和β都低,所以如果一个给定的假设检验的曲线保持在另一个的曲线之下,我们会更喜欢它。在统计学术语中,更可取的检验被称为“更有效的检验”,因为 1-β被称为检验的功效。既然我们有了一种称测试为“更有效”的方法,那么对于“最有效”测试的自然探索就产生了,给定我们感兴趣的度量以及该度量在治疗组和对照组中的分布。这是一个一致最有效测试的概念,在统计学中有相当多的努力来寻找这些测试。然而,我们将在这一节中反其道而行之,寻找最坏的可能,最没有力量的测试。因为如果我们知道最糟糕的交易是什么,我们就永远不会以最糟糕的方式受骗。
假设汤姆的任务是确定男性和女性的身高在统计学上是否有显著差异。他没有出去从一些男性和女性那里收集一些数据,而是呆在家里简单地扔硬币。硬币正面朝上的概率为α。如果他确实得到了“正面”,他只是简单地得出结论:零假设是正确的,平均身高没有差异(用统计学的行话来说,他“未能拒绝零”)。如果他得到了反面(概率 1-α),他得出结论,另一个假设是正确的。假设零假设为真,他将有错误拒绝它的概率α(根据定义)。而如果备选项为真,他将有而不是拒绝空的概率β=1-α。所以在这种情况下,α和β的关系就是β=1-α。这显示在下面图 4 的红线中。对于一个更合理的测试,它实际上收集了一些样本数据并构建了一个合理的测试统计量(如差异或均值比),对应的关系可能看起来像下面的白色曲线。

Fig 4: The α-β curve for the worst possible hypothesis test is given by the red line, β=1-α. A more reasonable hypothesis test where we actually look at some data might be given by the white curve. You can see for a given α, the β we get for the red line is much higher (worse).
样本量
假设检验中的另一个重要问题涉及到我们的实验需要多少样本量。要回答这个问题,我们需要目标假阳性率(α)、假阴性率(β)和我们感兴趣的效应大小。假设我们想要 16%的假阳性率和 10%的假阴性率。这在下面图 5 左下方的图中用绿点表示。您可以看到,最初,α-β曲线没有触及绿点(对于目标α,β比我们期望的要高得多)。然而,随着我们开始增加对照组和治疗组的样本量,整个曲线开始向下移动,直到最终绿点位于其上(注意,黄色区域α保持不变,但紫色区域β显著减少)。这是因为粉色线向左移动,紫色曲线变细。这基本上是我们如何预先知道,在给定假阳性和假阴性率的情况下,我们需要两组样本的大小,以及我们希望获得的效应大小。

Fig 5: Increasing sample size allows us to get any FNR for a given FPR. Image created using https://github.com/ryu577/pyray
这涵盖了假设检验的大部分重要方面。让我知道你的想法,我错过了什么,如果有任何其他方面的假设检验有利于这样的可视化。
假设检验:大学城的房价受经济衰退的影响小吗?
衰退是经济活动普遍下降时的商业周期收缩。经济衰退发生在支出普遍下降的时候,这可能是由于各种事件,如金融危机、外部贸易冲击或经济泡沫破裂。在衰退期间,我们发现国内生产总值、收入、就业、销售和工业生产稳步下降。衰退于 2007 年 12 月袭击了美国,持续了大约 18 个月(2009 年 6 月)
在这篇博文中,让我们看看大学城(例如,锡拉丘兹是一个大学城,因为它的学生人口比传统的非学生人口多)的平均房价受经济衰退的影响是否比其他城镇小。
我们使用假设检验的方法来找出大学城的平均房价在经济衰退期间是否受影响较小。你可以在这里阅读更多关于假设检验的内容
问题:大学城的平均房价受经济衰退的影响比其他城镇小吗?
零假设:大学城的平均房价同样受到了经济衰退的影响。
数据:
1.从 Zillow.com 的 T4 传来了美国的房屋数据。特别是城市级别的所有房屋的数据文件,该文件具有细粒度级别的房屋销售价格中值。
2.维基百科上关于大学城的页面上有一个美国大学城的列表,它已经被复制并粘贴到文件 university towns 中。
3.来自美国商务部经济分析局,在 GDP 文件中,以现值美元表示的美国季度 GDP 超时值
数据角力:
数据分析中最被低估的任务是清理、操作数据,并准备好对数据应用机器学习算法。我们将使用 3 个不同的数据文件来测试我们的假设。我们开始吧!
大学城:

该文档是文本文件,其格式为州[编辑] —城镇名称—大学名称[编号] —城镇名称—大学名称[编号]。因此,第一个任务是获取一个包含州名和该州大学城的数据框。
**def** get_list_of_university_towns():
**with** open('university_towns.txt') **as** file:
data = []
**for** line **in** file:
data.append(line[:-1])
state_town = []
**for** line **in** data:
**if** line[-6:] == '[edit]':
state = line[:-6]
**elif** '(' **in** line:
town = line[:line.index('(')-1]
state_town.append([state,town])
**else**:
town = line
state_town.append([state,town])
state_college_df = pd.DataFrame(state_town,columns = ['State','TownName'])
**return** state_college_dfget_list_of_university_towns()
给你。,我们创建了一个函数,该函数将返回一个包含州和相应大学城的数据框。我们去掉了[编辑]、数字、大学和括号。

Data Frame- Univerity Towns
GDP

我们可以看到,前 6 行是由标题,所以我们将摆脱它。我们不需要所有的数据,因为我们正在努力寻找 2009 年某个地方发生的经济衰退的影响。我们去掉了 1929 年至 1999 年的所有数据,我们的数据集现在应该有 2000 年至 2016 年的季度 GDP。即从行 212 开始的列 E 和列 F。我们采用季度 GDP,因为这将有助于我们从微观层面理解衰退的影响。
x = pd.ExcelFile('gdplev.xls')
gdp = x.parse(skiprows=7)
gdp = gdp[['Unnamed: 4', 'Unnamed: 5']]
gdp = gdp.loc[212:]
gdp.columns = ['Quarter','GDP']
gdp['GDP'] = pd.to_numeric(gdp['GDP'])
gdp

Data Frame — gdp
Zillow 房产数据

在这个数据集中,我们有很多列,我们感兴趣的是从 2000 年开始的州、城镇名称和年份。我们希望我们的年份采用年-季度的形式(2000 年第一季度、2000 年第二季度、2000 年第三季度……),但是我们的数据采用年-月的形式(2000-01 年)。2000–02…)因此,我们编写一个函数来获取所需形式的数据。
*# Use this dictionary to map state names to two letter acronyms*
states = {'OH': 'Ohio', 'KY': 'Kentucky', 'AS': 'American Samoa', 'NV': 'Nevada', 'WY': 'Wyoming',
'NA': 'National', 'AL': 'Alabama', 'MD': 'Maryland', 'AK': 'Alaska', 'UT': 'Utah', 'OR': 'Oregon',
'MT': 'Montana', 'IL': 'Illinois', 'TN': 'Tennessee', 'DC': 'District of Columbia', 'VT': 'Vermont',
'ID': 'Idaho', 'AR': 'Arkansas', 'ME': 'Maine', 'WA': 'Washington', 'HI': 'Hawaii', 'WI': 'Wisconsin',
'MI': 'Michigan', 'IN': 'Indiana', 'NJ': 'New Jersey', 'AZ': 'Arizona', 'GU': 'Guam', 'MS': 'Mississippi',
'PR': 'Puerto Rico', 'NC': 'North Carolina', 'TX': 'Texas', 'SD': 'South Dakota', 'MP': 'Northern Mariana Islands',
'IA': 'Iowa', 'MO': 'Missouri', 'CT': 'Connecticut', 'WV': 'West Virginia', 'SC': 'South Carolina', 'LA': 'Louisiana',
'KS': 'Kansas', 'NY': 'New York', 'NE': 'Nebraska', 'OK': 'Oklahoma','FL': 'Florida', 'CA': 'California',
'CO': 'Colorado', 'PA': 'Pennsylvania', 'DE': 'Delaware', 'NM': 'New Mexico', 'RI': 'Rhode Island',
'MN': 'Minnesota', 'VI': 'Virgin Islands', 'NH': 'New Hampshire', 'MA': 'Massachusetts', 'GA': 'Georgia',
'ND': 'North Dakota', 'VA': 'Virginia'}
**def** convert_housing_data_to_quarters():
df = pd.read_csv('City_Zhvi_AllHomes.csv')
df = df.drop(df.columns[[0] + list(range(3,51))], axis=1)
df2 = pd.DataFrame(df[['State', 'RegionName']])
df2.rename(columns={'RegionName':'TownName'},inplace=**True**)
**for** year **in** range(2000, 2016):
df2[str(year) + 'q1'] = df[[str(year) + '-01', str(year) + '-02', str(year) + '-03']].mean(axis = 1)
df2[str(year) + 'q2'] = df[[str(year) + '-04', str(year) + '-05', str(year) + '-06']].mean(axis = 1)
df2[str(year) + 'q3'] = df[[str(year) + '-07', str(year) + '-08', str(year) + '-09']].mean(axis = 1)
df2[str(year) + 'q4'] = df[[str(year) + '-10', str(year) + '-11', str(year) + '-12']].mean(axis = 1)
year = 2016
df2[str(year) + 'q1'] = df[[str(year) + '-01', str(year) + '-02', str(year) + '-03']].mean(axis = 1)
df2[str(year) + 'q2'] = df[[str(year) + '-04', str(year) + '-05', str(year) + '-06']].mean(axis = 1)
df2[str(year) + 'q3'] = df[[str(year) + '-07', str(year) + '-08']].mean(axis = 1)
df2['State'] = [states[state] **for** state **in** df2['State']]
df2 = df2.set_index(['State', 'TownName'])
ans = pd.DataFrame(df2)
**return** ans
convert_housing_data_to_quarters()
为了将年-月转换为年-季度,我们创建了一个新列 Year-Quarter (2000q1,2000 Q2…)取第一季度前三个月(1 月-3 月)和第二季度前三个月(4 月-6 月)的房价平均值,我们对 2000 年到 2015 年的每一年都这样做。对于 2016 年,我们有截至 8 月的数据,即截至第三季度的数据。此外,我们注意到我们的州名有缩写(NY,IL…)但是我们想要一个全名,因为我们包含大学城的数据框有完整的州名。在字典(states)的帮助下,我们将缩写转化为全名。让我们看看我们的数据现在是什么样子。

Data Frame - Housing Prices
提问:
1.衰退的开始日期是什么时候?
在这里,我们用 GDP 数据来回答这个问题。例如,如果我们有数字 1,2,5,3,2,7,8,我们可以看到 5>3 和 3>2,所以我们的衰退开始日期将在数字 5。使用同样的逻辑,我们得到一个衰退的开始日期。
**def** get_recession_start():
x = pd.ExcelFile('gdplev.xls')
gdp = x.parse(skiprows=7)*#skiprows=17,skip_footer=(38))*
gdp = gdp[['Unnamed: 4', 'Unnamed: 5']]
gdp = gdp.loc[212:]
gdp.columns = ['Quarter','GDP']
gdp['GDP'] = pd.to_numeric(gdp['GDP'])
quarters = []
**for** i **in** range(len(gdp) - 2):
**if** (gdp.iloc[i][1] > gdp.iloc[i+1][1]) & (gdp.iloc[i+1][1] > gdp.iloc[i+2][1]):
quarters.append(gdp.iloc[i][0])
**return** quarters[0]
get_recession_start()
我们的开始日期是 2008 年第三季度。
2.经济衰退何时触底?
这里的衰退底部是指 GDP 最低的点。
**def** get_recession_bottom():
*'''Returns the year and quarter of the recession end time as a*
*string value in a format such as 2005q3'''*
df = pd.read_excel('gdplev.xls', skiprows = 7)
df = df[['Unnamed: 4','Unnamed: 6']]
df.columns = ['Quarter','GDP']
df = df.iloc[212:]
df = df.reset_index()
df = df[['Quarter','GDP']]
recession_end = []
**for** i **in** range(len(df) - 4):
**if** ((df.iloc[i][1] > df.iloc[i+1][1]) & (df.iloc[i+1][1] > df.iloc[i+2][1]) & (df.iloc[i+2][1] < df.iloc[i+3][1]) & (df.iloc[i+3][1] < df.iloc[i+4][1])):
recession_end.append([df.iloc[i][0],df.iloc[i+1][0],df.iloc[i+2][0],df.iloc[i+3][0],df.iloc[i+4][0]])
ans = recession_end[0][2]
**return** ans
get_recession_bottom()
2009 年 Q2 出现了经济衰退的谷底
数据可视化:
如果我们以年季度为轴,GDP 为 y 轴绘制时间序列图,我们应该可以更准确地理解上面回答的问题。
gdp1=gdp.loc[245:252]
plt.figure(figsize=(12,7))
ax = sns.lineplot(x="Quarter", y="GDP", data=gdp1)

Start-2008q3, bottom-2009q2, end-2009q4
为了方便使用,让我们将函数返回的所有值放入一个变量中。
nitowns = get_list_of_university_towns()
bottom = get_recession_bottom()
start = get_recession_start()
hdata = convert_housing_data_to_quarters()
bstart = hdata.columns[hdata.columns.get_loc(start) - 1]
现在,如果我们想知道大学城的房价是否受影响较小,我们就取一个比率,(衰退开始时的 Gdp-衰退底部的 Gdp)/衰退开始时的 Gdp。该比率是从衰退开始日期到衰退底部房价的下降。
hdata['ratio'] = (hdata[bstart] - hdata[bottom])/ hdata[bstart]
hdata['ratio']

下一步是合并数据框。我们创建一个包含州、城镇名称、衰退底部、衰退开始和比率的新数据框架 hdata,并将该数据框架与大学城数据框架合并。
hdata = hdata[[bottom, bstart, 'ratio']]
hdata = hdata.reset_index()
unitowns_hdata = pd.merge(hdata,unitowns,how='inner',on=['State','TownName'])
unitowns_hdata.head()
现在,让我们看看我们的数据框是什么样子的:

我们需要在数据框中将大学城与其他城镇分开。因此,我们创建一个列“uni ”,如果是大学城,则用 True 填充,否则用 False 填充,然后创建一个数据框 ut,其中包含所有大学城的 True 值和非大学城的 nut 值。
unitowns_hdata['uni'] = **True**
hdata2 = pd.merge(hdata, unitowns_hdata, how='outer', on=['State','TownName',bottom, bstart, 'ratio'])
hdata2['uni'] = hdata2['uni'].fillna(**False**)
ut = hdata2[hdata2['uni'] == **True**]
nut = hdata2[hdata2['uni'] == **False**]


T 检验:
t 检验用于确定大学城的平均房价与非大学城相比是否具有统计学意义。
我们对 ut 和 n ut 数据框架进行 T 检验,检查大学城的房价是否受经济衰退影响较小。我们采用 99%的置信区间来检验我们的假设。
**def** hypo():
**from** **scipy.stats** **import** ttest_ind
t,p = ttest_ind(ut['ratio'].dropna(), nut['ratio'].dropna())
different = **True** **if** p<0.01 **else** **False**
better = "university town" **if** ut['ratio'].mean() < nut['ratio'].mean() **else** "non-university town"
**return** (p,different,better)
hypo()
输出:

p, different, better
结论:
在 99%的置信区间,我们拒绝假设大学城的平均房价同样受到(而不是更少)经济衰退的影响,因为 p 值(0.00336292287685515)小于 0.01。我们可以得出结论,美国大学城的平均房价受经济衰退的影响较小

用 Numpy 进行假设检验

各位数据科学爱好者,我们都做假设检验来从一个更大的流行样本数据中推断结果。这个测试帮助我们发现我们的零假设是对还是错。
首先,让我们明白当我们做假设检验时。当我们既不能从图形化 EDA 中得出结论,也不能通过比较汇总统计数据得出结论时,我们就这样做。在这种情况下,我们从现有的数据集模拟一个假设。做到这一点的一个方法是置换我们拥有的数据集。在继续之前,让我们看看如何做置换
def permutation_sample(data1, data2):
#Generate a permutation sample from two data sets.
# Concatenate the data sets: data
data = np.concatenate((data1, data2)) # Permute the concatenated array: permuted_data
permuted_data = np.random.permutation(data) # Split the permuted array into two: perm_sample_1, perm_sample_2
perm_sample_1 = permuted_data[:len(data1)]
perm_sample_2 = permuted_data[len(data1):] return perm_sample_1, perm_sample_2
您可以在“for 循环”中使用该函数来产生许多您需要的样本集。注意,这里我写了这个函数,从两个数据集推断样本。根据需要调整函数。
现在,既然我们知道如何使用排列来模拟假设,让我们来测试它。记住,假设假设是真的,测试假设是对观察到的数据的合理程度的评估。理解我们正在评估的数据是什么以及我们如何量化它是很重要的。这个问题的答案是测试统计。
检验统计量是一个单一的数字,可以从观察到的数据和我们从零假设模拟的数据中计算出来。这将有助于我们比较假设预测的结果和我们从数据中实际观察到的结果。我们可以选择能够帮助我们回答我们试图用假设来解决的问题的检验统计量。如果假设为真,样本的检验统计量和原始数据的检验统计量将是相同的,或者它们之间的差异太小。现在让我们看看如何使用 python 来计算这个测试统计复制。
def draw_perm_reps(data_1, data_2, func, size=1):
"""Generate multiple permutation replicates.""" # Initialize array of replicates: perm_replicates
perm_replicates = np.empty(size) for i in range(size):
# Generate permutation sample
perm_sample_1, perm_sample_2 = permutation_sample(data_1, data_2) # Compute the test statistic
perm_replicates[i] = func(perm_sample_1, perm_sample_2) return perm_replicates
在上面的函数中,您可以调整要传递的数据集的数量。在 for 循环中,对于每次迭代,它将使用我们之前编写的函数计算置换样本,然后计算测试统计量。您可以传递任何函数(如 np.mean()、np.var()或您自己的函数)来计算您的测试统计数据。
然后我们将这些值绘制成柱状图。然后,我们在直方图上标记来自原始数据的测试统计值。如果我们对原始数据的测试统计量的面积进行合计,就会得到 p 值。这可以用 python 实现,

P-Value, Red line represents the original data’s test statistics.
# Compute p-value: p
p = np.sum(perm_replicates >= test_statistic_of_original_data)/ len(perm_replicates)
例如,如果我们得到 p 值 0.05,我们可以说我们有 95%的信心我们的假设是正确的。即(100-(0.05×100))。
p 值是在零假设的假设下,获得测试统计值的概率,该值至少与观察到的值一样极端。注意,p 值不是假设为真的概率。
综上,让我们写下假设检验的流水线。
- 显然,陈述零假设
- 定义您的测试统计
- 假设零假设为真,生成多组模拟数据
- 计算每个模拟数据的测试统计
- p 值是测试统计至少与真实数据一样极端的集合的分数
在这里,我分享了一些关于如何进行假设检验的解释和 python 片段。希望对你有帮助。让我知道你的反馈。
假设检验和 p 值:一个温和的介绍

每当统计学家被要求对一些无法观察到的人口参数作出推断时,他们需要从人口中有代表性的样本开始。然而,一旦获得了该参数的估计值(称为统计量),他们如何能够说明它是否对应于真实的参数,因为后者是未知的?
因为不可能比较两个结果(同样,一个是不可观察的),所以有必要做出一些假设并进行所谓的假设检验。
这些测试旨在评估估计值与真实参数相等的可能性。这个想法是,它总是存在一种可以被认为是默认的情况:这是一种保守的情况,如果你对自己的假设没有足够的把握,你最好保持这种情况。这种情况将是我们的零假设,或 H0。另一方面,还有另一种情况,如果被接受,将会改变现状。这是另一种假设,或 H1。
这些假设有一个有意义的解释,而做出错误决定的惩罚是不均衡的。事实上,如果你因为你的发现而决定拒绝零,而事实证明这是真的,你就陷入了你可能面临的最糟糕的情况:事实上,你拒绝了保守状态,也就是说,你的“舒适区”。另一方面,当选择为真时,不拒绝空值也没那么糟糕。为了更简单,让我们考虑下面的例子。
假设你是一名医生,你必须决定是否让一名病人住院。你非常谨慎,如果有疑问,你通常更愿意让你的病人住院至少一个晚上,但是这对你的组织来说是非常昂贵的。因此你决定设定这两个假设:
- H0:‘病人需要住院’
- H1:‘病人不需要住院’
想象一下,病人实际上需要住院治疗,但你确信情况正好相反:你将把一个病情严重的人送回家,这可能会带来可怕的后果。另一方面,如果你决定让病人留院观察一晚,但事实证明他完全正常,你肯定会损失一些钱,但这种情况并不像让某人因疏忽而死亡那么糟糕。
话虽如此,我们如何具体地进行假设检验呢?要做到这一点,了解数据的分布是至关重要的。这里,我们将使用标准正态分布,它具有众所周知的钟形,平均值=0,标准差=1。
要标准化一个样本的正态分布,步骤如下:

z 值称为 z 得分,它表示位于总体平均值和数据点值之间的标准偏差数。
也就是说,假设你在考试中得了 30 分,平均分是 25,标准差是 3。您的 z 分数将等于:

这意味着你的分数比平均值高 1.67 个标准差*。让我们想象一下:*

请注意,当您有多个样本并且想要描述这些样本平均值的标准偏差时,您可以使用以下 z 得分公式:

其中 n =样本大小。
很好,但是这和假设检验有什么关系呢?这个想法是,你需要 z-score 来计算你的假设的概率,从而决定,在给定的置信水平下,是否拒绝零。让我们看看下面的例子。
想象一下,上面例子中测试的总体平均值是 25。然而,在选择了 30 名学生的样本后,发现他们的平均分数更高,比如说 28 分。可能出现的问题是,这一证据是否足够有力地表明人口的平均值高于 25。你的假设是:
- H0:“平均数等于 25”
- H1:“平均值大于 25”
然后,你必须设置所谓的显著性水平,这是你愿意拒绝零假设的误差幅度。因此,用α表示的显著性水平是当零假设为真时做出错误决策的概率。它通常采用 1%、5%和 10%这样的值,当假设为真时,它对应于拒绝零假设的区域。
即,α=5%,由于分布是对称的,我们将有两个 z 得分的临界值,表示为 Zα/2 和-Zα/2,它们是接受区域(绿色区域)的边界,而红色区域表示拒绝区域:

知道概率分布的重要性来了。事实上,由于我们已知的标准正态分布,我们可以使用包含与每个 z 分数相关的概率的表格。

也就是说,如果我们想在α=5%的情况下解决上述问题,我们必须找到那些决定 95%接受区域的临界 z 分数。因此,他们将在尾部为每一边留下 2.5%的概率,我们可以很容易地在表上看到这些值分别是-1.96 和 1.96。
现在,我们可以计算问题的 z 值:

由于 z 值超出了接受范围,我们可以拒绝总体均值等于 25 的零假设:我们有足够的证据(显著性为 5%)来拒绝该假设。

这个问题也可以用不同的方法来解决。假设您想要计算实际样本均值(或其更极端的值)出现的概率,而不是您的 z 得分。换句话说,事前获得样本均值等于或大于 28 的可能性有多大?

因为 z 分数大于 3.89(或小于-3.89)产生的概率为 0,所以我们的结果将为零(大约)。这意味着获得样本均值的可能性非常低(几乎不可能),以至于出现的事实表明人口的真实分布均值不等于 25。该概率的值称为 p 值。
一般来说,如果 p 值小于显著性水平,我们可以拒绝零假设。

假设检验是可以在各种情况下运行的强大工具。在本文中,我们看到了参数假设检验的例子,但是它们也可以指概率分布、数据间缺乏相关性、区间估计等。
我买了一台新电脑只是为了试用 CUDA,值得吗?

我一直对统计计算中图形处理的潜力很感兴趣。我最近一直在使用许多 OpenCL 包,而不是基于 CPU 的股票包,因为我的显卡是由 AMD 制造的,openCL 是他们对希望利用 GPU 的数学能力而不仅仅是图形的程序员做出的唯一足够的贡献。
当然,我最感兴趣的是 CUDA,这是一个 Nvidia 专有的并行计算平台。然而,我拥有的最后一个 Nvidia GPU 是 8800GT,我周围所有的卡都是 team red 的,大多数都是旧卡(我是一个硬件迷。)
因此,在过去的几周里,我不是在搜索,而是在 Letgo、脸书和 Craigslist 上查看了几次我感兴趣的硬件,只有一个要求:
它需要一个 Nvidia 显卡。
在我搜索的最后一刻,我偶然发现了一个令人震惊的发现。

这台电脑在 Letgo 上的售价只有区区 140 美元,但还是有一些问题。显然,我想知道处理器,但我可以告诉插座是 AM3+,这是一个好消息,无论处理器是什么,都值得用安装在机箱前面的 240 毫米大散热器来冷却。
此外,显卡是蓝宝石和蓝色 PCB,蓝色 PCB 很重要,因为蓝宝石不再使用它们,至少据我所知,它们通常与镭龙 HD 系列相关。显然,镭龙高清是没有骰子的 CUDA,是你能从 Nvidia 卡最远。
然而,不管怎样,这笔交易肯定是诱人的,因为这是一个 140 美元的相当不错的系统!我交叉手指,希望主板会配备 AMD FX 八核处理器或类似的东西(piledriver,而不是推土机。)结果是 AMD FX 830e 八核处理器的主频达到了 3.5 GHz。
但还是;显卡。我给卖电脑的人发信息问了几个问题,让他启动 bios 帮我检查一些规格。该系统添加了高达 8gb 的双通道内存、750w 模块化电源、240mm 散热器/AIO、128 GB SSD(不确定读写速度)、一些 Aura 主板和这张 Saphire 卡。
但为了让交易更甜蜜,他透露,除了他卖给我的规格,另加 20 美元,他会卖给我一个 GTX 1060 ROG strix 图形卡!
把它带回家后,我把它组装在一起,换了一个装有操作系统的固态硬盘(砰!Os),引导到 EFI 和一切工作完美。我添加了一些升级,一个 570 Evo SSD,8g 额外的内存和一个 R9 290 来驱动任何额外的显示器,结果看起来有点像这样:

太美了。
现在我们有了硬件,我们需要为软件做同样的事情!
让 CUDA 工作起来
CUDA 的设置实际上是相当广泛的,因为它不像设置你的驱动那么简单。首先,您必须进入您的终端并安装依赖项:
sudo apt-get install freeglut3 freeglut3-dev libxi-dev libxmu-dev
然后你必须去“Cuda 专区”给自己找一些二进制文件…或者如果你在 Debian 上,你可以得到回购:
wget http://developer.download.nvidia.com/compute/cuda/10.1/Prod/local_installers/cuda_10.1.243_418.87.00_linux.run
然后我们从 repo 中运行 sh 文件(作为 root 用户):
sudo sh ./cuda_10.1.243_418.87.00_linux.run
还有一种方法可以在 DPKG 上安装 CUDA 环境,但我选择了 SH 版本,因为这通常是我对 Nvidia 等可靠来源的首选途径。当你通过 SH 安装时,你会被问一些问题,我添加了#注释来解释我的回答,这样你就可以决定你是否认为说是合适的。
You are attempting to install on an unsupported configuration. Do you wish to continue?
(y)es/(n)o [ default is no ]: y# Obviously, we have to do this to proceed with the CUDA installation. Install NVIDIA Accelerated Graphics Driver for Linux-x86_64 396.26?
(y)es/(n)o/(q)uit: n# I said no to this, as I use the POP! OS Nvida DriverInstall the CUDA 9.2 Toolkit?
(y)es/(n)o/(q)uit: y# Of course, the whole reason we're here is for the toolkitEnter Toolkit Location
[ default is /usr/local/cuda-9.2 ]:# That location suited me fine.Do you want to install a symbolic link at /usr/local/cuda?
(y)es/(n)o/(q)uit: y# There's no reason not to, so it's global and usable with everything.Install the CUDA 9.2 Samples?
(y)es/(n)o/(q)uit: y# I figured why not so I can see the usage in Python, and C as I do a lot of writing there, as well.Enter CUDA Samples Location
[ default is /home/kinghorn ]: /usr/local/cuda-9.2
安装 cuBLAS 修补程序:
sudo sh cuda_9.2.88.1_linux.run
最后但同样重要的是,我们必须将回显路径添加到我们的系统中,我们首先在以下位置创建一个 sh 文件:
/etc/profile.d/cuda.sh
并将以下内容放入其中:
export PATH=$PATH:/usr/local/cuda/bin
export CUDADIR=/usr/local/cuda
另一个 sh 文件位于:
/etc/ld.so.conf.d/cuda.conf
包含:
/usr/local/cuda/lib64
当然,我们必须以超级用户的身份编辑它们。然后我们终于可以跑了
sudo ldconfig
现在我们有了 CUDA 设置!我越来越兴奋了!现在让我们进入 Julia 并设置我们的软件包!这应该很容易,但在这里我们将发现如果流行!驱动程序将会兼容。我们需要以下包:
CuArrays
CUDAnative
CUDAdrv
为了确保一切正常,我将推进这些路径,然后构建每个包:
ENV["LD_LIBRARY_PATH"] = "/usr/lib/cuda/lib64"
ENV["CUDA_PATH"] = "/usr/lib/cuda"
**using** Pkg; Pkg.build("CuArrays")
Pkg.build("CUDAnative")
Pkg.build("CUDAdrv")
现在只需启动 Jupyter 并进行测试!
ERROR: LoadError: Available CUDA toolchain does not provide libcudadevrt
小崽子,真不幸。看起来我们可能要安装 Nvidia 的驱动程序,我真的希望 POP 的驱动程序可能是驱动程序上的一个分叉工作,但似乎不是这样,或者如果是,它有点太修改了。
终于开始工作了
在 CUDA 控制面板中做了一些调整,并在我的部分做了一些 bashrc 编辑之后,我的 CUDA 驱动终于可以工作了。那么,在我的 CPU 上,Julia 和修改过的线性回归函数之间的时间比较如何呢?我着手做美国数据科学家最擅长的事情,进行了 20 次测试,得到了两个特征的平均值:
CPU:
0.2208722 seconds
CUDA:
0.052839374 seconds
哇!
有了这样的收获,我决定单独使用 OpenCL 进行第三次独立测试,结果令人震惊:
0.10083948593 seconds
结论
使用 CUDA 时,深度学习和简单预测建模的性能明显提高。将来,我也想使用一张有张量核的卡片,因为它的速度肯定是无可挑剔的。不管怎样,我对这一切的结果很满意!那么为了使用 CUDA 而购买一台全新的机器值得吗?
不值得。
我使用自然语言处理和分类模型构建了一个假新闻检测器

Credit: Unsplash
分析来自子编辑 r/TheOnion & r/nottheonion 的开源数据。
当 WhatsApp 宣布每月删除 200 万个账户以防止假新闻传播时,我被激起了兴趣。在数百万被标记为删除的账户中,有多少被误归类为假新闻?WhatsApp 甚至是如何创造出删除数百万假新闻账号的自动化流程的?为了回答这些问题,我使用 Reddit 的开源数据构建了自己的假新闻检测器。以下是我是如何做到的,以及我一路走来学到的东西。
在 Pushshift.io API 包装器 *的帮助下,我从子编辑 r/TheOnion 和 r/nottheonion 中搜集了大约 3 万篇帖子。我选择了这些小标题,看看我能在多大程度上区分假新闻和荒谬新闻。r/TheOnion 上的帖子以来自 www.theonion.com 或其他类似恶搞网站的讽刺新闻为特色。r/nottheonion 上的帖子以可信新闻机构报道的荒谬时事为特色。

r/TheOnion has 95.2k subscribers while r/nottheonion has 15 million subscribers. Image credit: Reddit.
为了保持我的数据简洁明了,我选择将我的预测变量(X)设为文章的标题,将我的目标变量(y)设为 1 来表示 r/TheOnion,设为 0 来表示 r/nottheonion。为了清理数据,我创建了一个数据清理函数,删除数据帧中的重复行,删除所有文本中的标点和数字,删除多余的空格,并将所有文本转换为小写。
# Data cleaning function
def clean_data(dataframe):# Drop duplicate rows
dataframe.drop_duplicates(subset='title', inplace=True)
# Remove punctation
dataframe['title'] = dataframe['title'].str.replace('[^\w\s]',' ')# Remove numbers
dataframe['title'] = dataframe['title'].str.replace('[^A-Za-z]',' ')# Make sure any double-spaces are single
dataframe['title'] = dataframe['title'].str.replace(' ',' ')
dataframe['title'] = dataframe['title'].str.replace(' ',' ')# Transform all text to lowercase
dataframe['title'] = dataframe['title'].str.lower()
print("New shape:", dataframe.shape)
return dataframe.head()
既然我的 Subreddit 数据集已经很好很干净了,我就可以进行探索性数据分析(EDA)了。即使我决定给我的预测变量(X)分配帖子标题,在我的数据搜集过程中,我也获得了帖子的其他特征,以揭示数据中隐藏的故事。总的来说,我从每篇文章中总结了以下特征:
title:子编辑帖子的标题subreddit:这个帖子属于哪个子编辑num_comments:一篇帖子的评论数author:文章作者的用户名subreddit_subcribers:该子编辑的用户数量score:Reddit 上收到的分数domain:帖子中引用的域名created_utc:帖子创建的日期和时间
当我观察到一个作者分享的帖子数量时,一些奇怪的事情引起了我的注意。在拥有 1500 万订阅者的 r/n 联盟中,只有三位作者分享了超过 100 篇帖子,而拥有 95000 订阅者的 r/n 联盟有 14 位作者分享了超过 100 篇帖子,最多的是 4113 篇帖子。在做出这个观察之后,我确认了我做出了一个很好的决定,将 r/TheOnion 作为一个案例来了解 WhatsApp 的假新闻问题。在 WhatsApp 的“帮助防止谣言和假新闻传播的提示”中,七个提示中有三个侧重于防止假新闻传播。假新闻的最大问题之一不一定是它被写出来,而是它被传播。r/TheOnion 作者的活动模仿了假新闻现象的核心特征。

Most Active Authors in r/nottheonion & and r/TheOnion. Image credit: Jasmine Vasandani
数据科学中的第一个最大错误是将每个业务挑战都视为预测方法。记住 70%的低挂问题可以通过做 EDA 来解决。
Sundar Ramamurthy
在对数据进行 EDA 的过程中,我发现了另一件有趣的事情,那就是每个子编辑中引用最多的域。当然,r/TheOnion 中提到的大多数域名来自theonion.com和其他恶搞新闻网站。然而,r/nottheonion 中引用最多的域给了我一脚。r/nottheonion 上被引用次数最多的五个域名分别是foxnews.com、theguardian.com、google.com、bbc.com和newsweek.com。

Top 5 Most Referenced Domains in r/TheOnion & r/nottheonion. Image credit: Jasmine Vasandani
我对我的数据集进行了更多的 EDA,并通过对数据应用CountVectorizer(ngram_range = (1,1))来分析最常用的词。我还通过对数据应用CountVectorizer(ngram_range = (2,2))分析了最常用的二元模型。在这两个子编辑之间,我记下了常见的常用词,并将它们添加到一个自定义的stop_words列表中,稍后我将在数据建模中使用该列表。
我本可以早点开始建模过程,但是我决定先进行 EDA,以便更好地了解我的数据。在数据与我分享了他们的故事后,我开始创建和完善我的预测模型。我设置了我的预测器(标题)和目标(子编辑)变量,进行了训练/测试分割,并通过管道和 GridSearchCV 找到了我的模型的最佳参数。我使用了矢量器和分类模型的组合来寻找能给我最高准确度分数的最佳参数。我对准确性进行了优化,以确保所有假新闻都被归类为假新闻,而所有真实新闻都不会被归类为假新闻。
我结合使用计数矢量器和tfid 矢量器与逻辑回归和多项式实现了四个模型。我实现最高测试准确度分数的最佳模型是 CountVectorizer 和 MultinomialNB。下面是我如何找到这个模型的最佳参数的代码。
# Assign vectorizer and model to pipeline
pipe = Pipeline([('cvec', CountVectorizer()),
('nb', MultinomialNB())])# Tune GridSearchCV
pipe_params = {'cvec__ngram_range': [(1,1),(1,3)],
'nb__alpha': [.36, .6]}gs = GridSearchCV(pipe, param_grid=pipe_params, cv=3)
gs.fit(X_train, y_train);
print("Best score:", gs.best_score_)
print("Train score", gs.score(X_train, y_train))
print("Test score", gs.score(X_test, y_test))gs.best_params_
我解释系数的最佳模型实现了 CountVectorizer 和 LogisticRegression。下面是我如何找到这个模型的最佳参数的代码。
pipe = Pipeline([('cvec', CountVectorizer()),
('lr', LogisticRegression(solver='liblinear'))])# Tune GridSearchCV
pipe_params = {'cvec__stop_words': [None, 'english', custom],
'cvec__ngram_range': [(1,1), (2,2), (1,3)],
'lr__C': [0.01, 1]}gs = GridSearchCV(pipe, param_grid=pipe_params, cv=3)
gs.fit(X_train, y_train);
print("Best score:", gs.best_score_)
print("Train score", gs.score(X_train, y_train))
print("Test score", gs.score(X_test, y_test))gs.best_params_
为了评估我的 CountVectorizer 和 MultinomialNB 模型,我实现了一个混淆矩阵。虽然 90%的准确率测试分数很高,但这仍然意味着 10%的帖子被错误地分类为假新闻或真实新闻。如果这是 WhatsApp 对其假新闻检测器的评分,每月将有 10%的假新闻账户被错误分类。好在我先在一个较小的数据集上创建了一个假新闻检测器。

Confusion Matrix. Image credit: Jasmine Vasandani
最后,尽管我的 CountVectorizer 和 LogisticRegression 模型的性能不如上面的模型,但我仍然决定解释它的系数,以更好地了解每个单词如何影响预测。在我的逻辑回归系数的下图中,对来自 r/TheOnion 贡献最大的词是“kavanaugh”,其次是“incredible”和“ftw”。对“来自 r/not theon”贡献最大的词是“佛罗里达”,其次是“警察”和“被捕”。在指数化我的系数之后,我发现当“kavanaugh”在标题中的出现次数增加 1 时,该标题被归类为 r/TheOnion 的可能性是 7.7 倍。并且随着标题中“florida”的出现增加 1,该标题被分类为 r/nottheonion 的可能性是 14.9 倍。

Logistic Regression Coefficients. Image credit: Jasmine Vasandani
回顾我的过程,我会在我的数据上测试更多的 NLP 矢量器和分类模型。展望未来,我很好奇如何通过机器学习来解析图像、视频和其他形式的媒体,因为新闻文章并不总是以文本格式编写的。我也对 WhatsApp 可能如何创建一个检测假新闻账户的模型有了更好的理解。至于 WhatsApp 删除账号的准确率得分,那是我至今还在想的问题。
要查看我在这个过程中的所有代码,请查看我的 GitHub repo 。
*帽子提示大卫·五车二与我分享 API 包装器!
Jasmine Vasandani 是一名数据科学家、战略家和研究员。她热衷于建立包容性的数据社区。了解她更多:www.jasminev.co/
我做了一个乐谱转录器——以下是我的操作方法
从音符到 ABC 符号的翻译从未如此简单!
过去几年,机器学习和深度学习领域经历了巨大的变革,并在许多领域带来了许多有用的应用。一个感兴趣的领域是光学音乐识别(OMR)。根据维基百科,OMR 是一个研究领域,调查如何通过计算读取文档中的音乐符号。OMR 的目标是教会计算机阅读和解释乐谱,并生成机器可读版本的书面乐谱。让我们就这么做吧!

The end product — an annotated music sheet with notes translated in ABC notation
音乐速成班
在我开始写代码之前,我先简单介绍一下乐谱。我们中的许多人都是通过学习如何阅读音符的缓慢而痛苦的过程开始学习音乐的。事实上,许多人通过在乐谱上写下每个音符对应的字母来将音符转换成 ABC 符号。

Converting between notes and ABC notation
我自己经历过这个过程,我决定如果我能建立一个 web 应用程序,可以自动将音符翻译成 ABC 符号,并在乐谱上标注 ABC 字母,那将是非常棒的!
深度学习模型
因此,我开始寻找能够执行这项任务的合适的深度学习架构。在此之前,我没有太多的光学识别模型的经验,所以我不确定是否会有任何关于这个主题的现有工作。让我惊讶的是,我在《应用科学杂志》上发现了一篇由 Calvo-Zaragoza 等人在 2018 年发表的非常精彩的研究论文,题目是端到端的神经光学音乐识别单音乐谱。他们甚至策划了一个数据集:乐谱的印刷图像(PrIMuS ),包含超过 80,000 个西方常用记谱法的真实乐谱!
Calvo-Zaragoza 等人提出的模型由一个卷积神经网络(CNN)组成,用于从输入图像中提取特征,随后是一个双向长短期记忆(BLSTM)网络,用于处理序列,单个五线谱被视为一个序列。CNN 最后一层的输出连接到 BLSTM 第一层的输入,形成卷积递归神经网络(CRNN)。研究人员使用了一种特殊的损失函数,连接主义者时间分类(CTC)损失函数,它提供了一种优化 CRNN 参数的方法,以便在给定输入 x 的情况下,它可能会给出正确的序列 y。这里,输入 x 代表单个五线谱图像,y 是其相应的音乐符号序列。

Graphical scheme of the CRNN taken from the paper.
但是请注意,该模型不输出关于每个音符的确切位置的信息,而只输出音符出现的顺序。然而,这并不重要,因为尽管音乐读者可能不知道哪个音符对应于哪个字母,但他们可以根据输出的字母数量来理解。
有关 CRNN 架构和实验细节的更多信息,请查看他们的论文这里了解更多信息。
在 Web 上部署
如果你只是想得到代码,点击这里。
好了,现在我们已经简单地了解了模型架构,现在是实现的时候了!研究人员已经上传了他们在 Tensorflow 中实现的模型,并将代码上传到 Github 上。在此基础上,我能够快速建立模型,并准备在 web 上部署它。首先,确保您安装了 tensorflow v1、flask 和 OpenCV。然后,下载研究人员训练的语义模型以及语义词汇。还要下载字体 Aaargh.ttf ,因为需要用 ABC 符号对图像进行注释。(如果您想自己训练模型,请前往 tensorflow 模型 Github 存储库获取说明,并下载 PrIMuS 数据集)。语义词汇表基本上是一个将整数表示映射到实际音符的字典,比如 index 348 如何给你 note-A2_quarter 。但是,由于模型的词汇表包含的信息比需要的要多得多(如拍号、竖线等),而且由于演奏者无需任何音乐背景知识就可以在乐谱上看到,所以不需要对这些信息进行注释,因此我对模型的输出进行了后处理,仅包含 ABC 字母,代码如下:
notes=[]
for i in array_of_notes: // array_of_notes contains the full output
if i[0:5]==”note-”:
if not i[6].isdigit():
notes.append(i[5:7])
else:
notes.append(i[5])
幸运的是,所有的笔记都标有“note-”作为前 5 个字符,所以很容易只抓住那些与 ABC 字母相关的。
Web 应用程序是做什么的?
获得包含相关注释的数组后,我使用 PIL ( Python 图像库)库将注释添加到图片本身。这包括创建一个新的完全白色的图像,其宽度和高度是原始图像的 1.5 倍,以扩展原始图像。然后,我使用 Image.paste()函数将原始图像复制到白色图像上。在下面用空白扩展了原始图像后,我可以在五线谱下面打印 ABC 字母。

Original Image

Annotated Image
如前所述,该模型不包含每个音符的确切位置信息,而是只打印出一系列字母,所以我必须做一些计算,使 ABC 字母在五线谱下方排列非常。它没有完全对齐,这肯定是未来改进的一个领域,但这不是一个大问题,因为音乐播放器可以根据出现的顺序知道哪个字母对应哪个音符。
在研究人员提供的 tensorflow predict.py 代码的基础上,我用 Flask 实现了我的 web 应用。Flask 是一个非常方便的 web 应用程序框架,它可以让每个人在尽可能短的时间内将自己的 python 代码移植到 web 应用程序上。所有 Flask 需要的是您的主要 python 代码、html 文件和 css 模板,您就可以开始了!
仔细看看弗拉斯克
Flask python 文件只需要对当前的机器学习 python 文件做一些小的补充。首先,你必须添加行
app = Flask(__name__)
导入 Flask 后,在您的机器学习代码上方创建 web 应用程序的 Flask 类的实例。然后,在后面添加下面一行:
if __name__==”__main__”:
app.run()
当 python 运行该文件时,它会将名称"__main__"分配给脚本。因此,__name == "__main__"得到满足,app.run()执行。在此之后,您必须定义一些函数,并将它们映射到一些路由,例如定义用户上传音乐表后,如何重定向到/预测包含注释音乐表的内容。查看烧瓶文档和我的代码了解更多信息。
最后的润色
现在 python 文件已经设置好了,剩下的就是 html 文件和 css 文件了。文件夹结构通常如下:
app.py
├── templates
| ├── html files here
├── static
| ├── css
| └── css files here
在这个项目中,该网站是风格化的布尔玛,一个伟大的开源 CSS 框架,我强烈推荐给大家!它使用简单,不需要太多的 Javascript,看起来非常好。
这个项目还需要一些额外的文件——深度学习模型、语义词汇文件、字体和任何你想要测试的图像。所以如果你已经下载了所有的文件,你应该这样组织你的文件夹:
app.py
vocabulary_semantic.txt
Aaargh.ttf
├── Semantic-Model
| ├── semantic_model.meta
| └── semantic_model.index
| └── semantic_model.data-00000-of-00001
├── templates
| ├── index.html
| └── result.html
├── static
| ├── css
| └── bulma.min.css
就是这样!一旦如上所述设置好了一切,就进入你的终端/命令提示符。将目录更改为包含您的app.py文件的目录,并运行python app.py。等待几秒钟,您应该会收到一条消息,显示您应该访问的链接,以便查看 web 应用程序。转到网址,上传您的音乐表,并获得结果!带注释的工作表将被保存到与您的app.py文件相同的目录中。
请注意,目前该模型只能处理单音乐谱(由一条旋律线组成的乐谱)。所以不要给它太复杂的分数!
试试这个!我希望你能从中得到乐趣,并告诉我进展如何!如果你有任何关于如何使用这个模型的好主意,请在评论区分享!
这篇文章也发表在我的博客里。
使用可视化交流数据

Communicating data using visualizations
我下载了我的脸书数据,这些数据分析了我的在线行为,并更新了过去十年的上网频率和总体参与度。
这篇博客文章以分析我在脸书的更新开始了社交媒体分析系列博客。第一次分析的目的是了解:I)我在 2009 年至 2018 年期间在我的脸书账户上发布帖子的频率,并根据更新的类型打破这些更新,即发布状态更新、帖子(这是指分享图片、新闻文章或转发附有一些个人评论的脸书帖子),在朋友的时间线上分享一些东西,分享一篇文章和发布一篇文章的链接,ii。)按年份和 iii 发布特定类型更新的年度百分比可能性。)我按工作日、小时和月份发帖的倾向,通过过去 10 年发帖频率的加权平均值来衡量。这将作为对我在过去十年中发布的内容类型进行更详细分析的后续,忽略年轻的我可能已经发布的明显令人生厌的帖子。
import pandas as pd
import datetime
import matplotlib.pyplot as plt
import numpy as np
from google.colab import drive
drive.mount('/content/gdrive')
fb_posts = pd.read_csv(‘/***/myposts.csv’)
我把脸书的数据保存在我的谷歌硬盘上;为了在 Google Colab 上与这些数据进行交互,我必须使用 google.colab 包来挂载 GDrive 并打开与我的分析相关的文件夹和 csv。
阅读文件
#I need to convert this into a readable datetime
#iterate through timestamps and convert individual rows
fb_posts[‘timestamp’] = fb_posts[‘timestamp’].apply(lambda x: datetime.datetime.fromtimestamp(int(x)))
#create month, day, year and time columns
fb_posts[‘year’] = fb_posts.timestamp.dt.year
fb_posts[‘month’] = fb_posts.timestamp.dt.month
fb_posts[‘day’] = fb_posts.timestamp.dt.day
fb_posts[‘time’] = fb_posts.timestamp.dt.time#making the assumption that if 95% of the rows are NaN values, the column doesn’t contain valuable info for the purposes of our analysis
#use dropna and specify threshhold of na values
fb_posts = fb_posts.dropna(thresh=len(fb_posts)*0.05, axis=1)#use list(fb_posts) to id the remaining columns
fb_posts = fb_posts.drop(fb_posts.iloc[:,[1,4]], axis=1)
关于从 facebook 导入的数据,您注意到的第一件事是,您的更新的时间戳是以 unix 时间戳格式(一个表示自 1970 年 1 月 1 日以来发生的秒数的数字)导入的,因为它同时表示所有时区。为了将这个时间戳转换成可读时间,我在时间戳列的每一行上应用了一个 lambda 函数。所以我遍历每一行,并应用一个 lambda 函数将时间戳转换成日期时间格式。
然后,我继续使用。年份,。月,。天还有。时间分别。我需要这些专栏来回答我在开篇段落中提出的问题。
目前,dataframe 大约有 126 列,其中大部分对我们的分析没有用。为了过滤掉不重要的列,我删除了 NaN 值占行中值的 95%或更多的列。我这样做是为了减少列的数量,这样我就可以专注于我真正想要用于分析的列(并可能找到其他包含有趣信息的列)。
一旦我有了更少的列,我就根据与我们的分析最相关的列来限制列。
数据清理
#rename column
fb_posts.rename(columns = {'data/0/post':'posts', 'attachments/0/data/0/external_context/url':'links'}, inplace=True)
fb_posts['title'] = fb_posts['title'].astype(str)
for x in ['link', 'post', 'status', 'timeline','recommend','books','reviewed','playlist','feeling','event','likes','listened','played','published','shared','was','followed','commented','song','responded','wants','invested','photo']:
fb_posts.loc[fb_posts['title'].str.contains(x), 'title'] = x
#remove chart junk
removal = ['recommend','books','photo','reviewed','playlist','nan','feeling','event','likes','listened','played','published','was','followed','commented','song','responded','wants','invested']
fb_posts2= fb_posts[~fb_posts['title'].isin(removal)]
现在有趣的部分来了:清理。我首先将列重命名为更容易引用的名称:然后将 title 列中的所有项目转换为 string 格式。我这样做是为了帮助我们使用一个单词的引用(例如,状态=状态更新)来分类每行所代表的文章类型。
通过将 title 列中的所有项目转换为 string,我可以遍历 title 列中的每个字符串,并检查它是否包含在上面代码块中定义为“x”列表的单词列表中出现的任何单词。如果是这样,我就将该行的值更改为“x”列表中的相关引用文本。
然后,我遍历这个列表,删除引用删除列表中指定的引用词的值。我这样做是因为我只想处理状态、帖子、链接、分享和时间线更新。基于对我在脸书历史上发布的内容的理解,我认为这些是我在脸书活动的主要内容。
按年份和类型绘制更新频率图
fb_posts2.groupby([‘year’,’title’]).size().unstack().plot.bar(stacked=True)

Frequency of Facebook updates
为了形象化我们的图表,我按年份分组,并计算每种更新(标题)的出现次数。有趣的是,频率有点像高斯分布,频率峰值在 2012 年和 2015 年之间的中间,总更新数最低的是在 2009 年和 2018 年的尾部。这不一定表明我在社交媒体上不太活跃,而是我越来越多地从脸书转向 Twitter。这主要是因为该平台潜在的学习价值,以及它如何让自己成为比人们在脸书上分享猫图片和其他随机事情有趣得多的对话。
按百分比更新
我想想象的下一个趋势是了解 2009 年至 2018 年间任何一年的更新类型,按百分比计算。
#we want to find the count of posts, status updates and link shares by year
nine = fb_posts2[fb_posts2['year']==2009].groupby('title').size()
ten = fb_posts2[fb_posts2['year']==2010].groupby('title').size()
eleven = fb_posts2[fb_posts2['year']==2011].groupby('title').size()
twelve = fb_posts2[fb_posts2['year']==2012].groupby('title').size()
thirteen = fb_posts2[fb_posts2['year']==2013].groupby('title').size()
fourteen = fb_posts2[fb_posts2['year']==2014].groupby('title').size()
fifteen = fb_posts2[fb_posts2['year']==2015].groupby('title').size()
sixteen = fb_posts2[fb_posts2['year']==2016].groupby('title').size()
seventeen = fb_posts2[fb_posts2['year']==2017].groupby('title').size()
eighteen = fb_posts2[fb_posts2['year']==2018].groupby('title').size()
a = [x/sum(x)*100 for x in [nine,ten,eleven,twelve,thirteen,fourteen,fifteen,sixteen,seventeen,eighteen]]
df = pd.DataFrame(a, index= my_names)
#remove all NaN values and replace with 0
df['post'].fillna(0, inplace=True)
df['shared'].fillna(0, inplace=True)
df['timeline'].fillna(0, inplace=True)
在这段代码中,我获得了每种类型的更新占该特定年份总更新的百分比。然后,我继续删除由某些年份未发生的某些类型的更新导致的任何 NaN 值,并用 0 替换该 NaN 值。
df.plot(kind='bar', stacked=True, width=0.98)

Update type by percentage
从这个视觉化中,有一个明显的趋势表明状态更新在减少,我的更新越来越倾向于链接和帖子更新。我对社交媒体的使用案例已经从与老朋友保持联系转变为讨论热门话题或让我的业务和职业抱负感兴趣的问题。这清楚地反映在我的更新趋势中。
脸书按天更新
这个分析的问题集中在找出我在工作日更新脸书的倾向。
#convert dates to week days
fb_posts2[‘weekday’] = fb_posts2.timestamp.dt.weekday_name#find average tweets per day grouped by year
weighted = fb_posts2.groupby(‘year’).weekday.value_counts(normalize=True).unstack().sum().sort_values().plot(kind=’bar’)
在将我的时间戳上的工作日转换为单词 weekday 之后,我寻找一种解决方案来计算我的数据中每年按工作日更新的加权平均值,从最小到最大对条形进行排序,并对数据帧进行拆分以对其进行整形,并返回整个定义期间每天的加权平均值之和。

Most frequent posts by week day
最终结果不言自明:我的脸书更新频率在周末和本周初达到峰值。从最近的角度来看,我更有可能在一周结束和开始时分享脸书的链接,因为这是我最有可能积极检查我的脸书和阅读我更有可能分享的外部内容的时候。我相信我在周五通常更活跃,因为我的注意力往往会在一天结束时下降,因为我会期待周末,而在周一,我通常会在早上早些时候慢慢开始使用社交媒体,并放松进入我的工作。
在过去的两年里,这种情况越来越多地出现在 Twitter 上,而不是脸书,这解释了过去几年脸书帖子数量下降的原因。
脸书每小时更新
#facebook posts by hour, I need to split the first 2 digits from time
fb_posts2['hour'] = fb_posts['time'].apply(lambda x: x.hour)
time_weight = fb_posts2.groupby('year').hour.value_counts(normalize=True).unstack()
time_weight.sum().sort_index().plot(kind='bar')
为了显示过去 10 年中每小时的平均更新,与前面的分析非常相似,我计算了每小时更新的加权平均值,并通过将 groupby 函数与 value_counts (计算小时的唯一值总数)结合起来对这些平均值求和。“normalize”参数只允许我计算并返回我计算的小时数的唯一值的相对频率。

Most frequent posts by hour
平均每小时的帖子数从早上 5 点开始持续增加,在下午 6-9 点达到高峰。我会推测,这是我更可能坐在家里拿着手机的时候(取决于讲座或工作后的一年)。此外,我注意到我最容易分心的时间是上午 10-11 点和下午 6-8 点。虽然我通常是一个夜猫子,大多数日子熬夜到凌晨 1 点,周末甚至更久,而且通常在深夜更活跃。我倾向于在晚上 9 点左右不活跃在社交媒体上。
脸书每月更新
month_weight = fb_posts2.groupby('year').month.value_counts(normalize=True).unstack()
labels = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sept','Oct','Nov','Dec']
fig, ax = plt.subplots()
month_weight.sum().sort_index().plot(kind='bar')
plt.title('Most frequent post months')
plt.ylabel('Weighted Average')
plt.xlabel('Months')
ax.set_xticklabels(labels)
为了按月对条形图进行排序,我在 groupby 函数中以整数格式保存了月份。因为我知道按索引排序这些月份将返回从 1 到 12 排序的月份,所以我可以使用 set_xticklabels 将月份转换为由它们各自的缩写表示的月份

Most frequent posts by month
从每月发帖的频率来看,我在脸书的活跃程度似乎在冬季有所下降,在夏季有所上升,尤其是在接近年底的时候。如果不对我每月发布的帖子类型和主题进行进一步的分析,很难对这种趋势的原因进行理论化。
这篇文章不是我一个人写的
AI 在这里,越来越容易使用和理解。
使用 Python 在几分钟内用 GPT-2 生成文本。

Credit to my amazing sister Heizel Vázquez
不久前,我写了一篇关于数据科学的文章:
数据科学家不是知道如何使用 Python 或 R 的人,他们是可以通过理解他们拥有的数据来改进和优化业务工作方式的人,并创建模型来解释现实的复杂性,同时创建可以推动行动的解决方案,即与业务相关的特定行动。
我想看看我能想到的与这个思路相关的其他东西。这是系统产生的结果:
数据科学家是那些了解业务、了解业务需求、了解客户需求、了解业务模式并使用这些知识来更好地了解业务和客户的人。
在处理应用程序或业务时,您需要一名数据科学家来了解应用程序或业务需要什么类型的数据。当要做出明智的决策时,你需要一个懂得如何编写优秀的数据可视化(或分析)应用程序的人。这个人也可以理解即将到来的数据,并确定使用这些数据的最佳方式。

GPT-2 基础

这项工作在很大程度上基于 greycode 和 huggingface 的工作,你可以在这里看到他们的回复:
带有 OpenAI gpt-2 Pytorch 实现的简单文本生成器— graykode/gpt-2-Pytorch
github.com](https://github.com/graykode/gpt-2-Pytorch) [## 拥抱脸/py torch-预训练-BERT
📖变形金刚的大扩展库:为谷歌的 BERT,OpenAI GPT 和 GPT-2 预训练 PyTorch 模型…
github.com](https://github.com/huggingface/pytorch-pretrained-BERT)
但是在运行代码之前,我们需要一些关于这个模型如何工作的基础知识(如果您只是想使用这个模型,请转到下一节)。
GPT-2 是一个大型的基于转换器的语言模型,具有 15 亿个参数,在 800 万个网页的数据集上进行训练。GPT-2 训练有一个简单的目标:预测下一个单词,给定一些文本中的所有以前的单词。对我们来说很遗憾,但也许对世界更好的是,他们没有发布整个模型,而是发布了一个较小的模型。您可以在这里看到最初的实现:
“语言模型是无监督的多任务学习者”论文的代码——open ai/GPT-2
github.com](https://github.com/openai/gpt-2)
现在我们有一个(117 米参数)和中等(345 米参数)版本的 GPT-2 测试。该模型如下所示:

Improving Language Understanding by Generative Pre-Training, Radford et al.
这些是型号规格:
我们的模型很大程度上遵循了最初的变压器工作。我们训练了一个只有 12 层解码器的变压器,它有掩蔽的自我注意头(768 维状态和 12 个注意头)。对于位置式前馈网络,我们使用 3072 维内部状态。我们使用了 Adam 优化方案,最大学习速率为 2.5e-4。在前 2000 次更新中,学习率从零线性增加,并使用余弦时间表退火至 0。我们在 64 个随机采样的小批次上训练 100 个时期,512 个标记的连续序列。由于 layernorm 在整个模型中广泛使用,简单的权重初始化 N(0,0.02)就足够了。我们使用了一个字节对编码(BPE)词汇,有 40,000 个合并和残差,嵌入,以及 0.1 的注意丢失率用于正则化。我们还采用了在中提出的 L2 正则化的修改版本,在所有非偏置或增益权重上 w = 0.01。对于激活函数,我们使用高斯误差线性单位(GELU)。我们使用学习位置嵌入,而不是原来的工作中提出的正弦版本。
他们在这里提到的“原创作品”是谷歌的一篇论文,名为“注意力是你所需要的”(2017)。这里他们提出了一个看起来像这样的变压器:

Attention Is All You Need (2017)
Transformer 是一种避免重复出现的模型架构,而是完全依赖于一种注意机制来绘制输入和输出之间的全局依赖关系。
变压器依靠一个编码器和一个解码器。这里,编码器将符号表示的输入序列 (x1,…,xn) 映射到连续表示的序列 z = (z1,…,zn) 。给定 z,解码器然后一次一个元素地生成符号的输出序列 (y1,…,ym) 。在每一步,模型都是自回归的,在生成下一步时,消耗先前生成的符号作为附加输入。
它们通过警示机构连接。它可以被描述为将查询和一组键-值对映射到输出,其中查询、键、值和输出都是向量。输出被计算为值的加权和,其中分配给每个值的权重由查询与相应键的兼容性函数来计算。
关于注意力机制和它的工作方式还有很多要讨论,请阅读詹姆斯·蒙泰斯的文章:
[## 检查变压器架构—第 1 部分:开放 GPT 2 争议
“回收对世界没有好处。它对环境有害,对我们的健康有害,对我们的…
towardsdatascience.com](/examining-the-transformer-architecture-part-1-the-openai-gpt-2-controversy-feceda4363bb) 
如何使用 GPT 新协议模型

到目前为止,我们一直是技术性的,但在使用模型之前,最好有一个我们正在做什么的想法。但是现在,我们如何使用它呢?
让我们从旋转 JupyterLab 会话和克隆一些 repos 开始。为此,我使用了一个用于数据科学的云托管系统。
项目在那里(用叉车测试):
[## MatrixDS |数据项目工作台
MatrixDS 是一个构建、共享和管理任何规模的数据项目的地方。
community.platform.matrixds.com](https://community.platform.matrixds.com/community/project/5d653ca4d3af3918c87bc0c7/files) 
这是 GitHub 回购协议:
[## FavioVazquez/gpt2-matrixds
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/FavioVazquez/gpt2-matrixds)
注意:如果你铲车回购你会有一切已经测试代码,如果没有遵循以下说明。
在 JupyterLab(我在本教程中使用的那个)中,打开终端并开始克隆 greycode repo:
git clone [https://github.com/graykode/gpt-2-Pytorch](https://github.com/graykode/gpt-2-Pytorch)
然后转到刚才创建的文件夹,下载 hugginface 的预训练模型:
curl --output gpt2-pytorch_model.bin [https://s3.amazonaws.com/models.huggingface.co/bert/gpt2-pytorch_model.bin](https://s3.amazonaws.com/models.huggingface.co/bert/gpt2-pytorch_model.bin)
并安装要求:
pip install -r --user requirements.txt
我还需要安装 PyTorch 和 tqdm,对于 pip,只需输入:
pip install --user torch torchvision
pip install --user tqdm
之后,你就可以走了!您有一个运行实验的命令行工具,可以通过以下方式使用:
python main.py --text "This is a text"
或者,如果您在笔记本电脑中:
!python main.py --text "This is a text"
如果您转到 main.py 文件,您将看到模型是如何被使用的,但是没有太多关于模型本身的描述。我们可以改变的论点是:
:seed=None : Integer seed for random number generators, fix seed to reproduce results
:nsamples=1 : Number of samples to return total
:batch_size=1 : Number of batches (only affects speed/memory). Must divide nsamples.
:length=None : Number of tokens in generated text, if None (default), is determined by model hyperparameters
:temperature=0.7 : Float value controlling randomness in boltzmann distribution. Lower temperature results in less random completions. As the temperature approaches zero, the model will become deterministic and repetitive. Higher temperature results in more random completions.
:top_k=40 : Integer value controlling diversity. 1 means only 1 word is considered for each step (token), resulting in deterministic completions, while 40 means 40 words are considered at each step.
:unconditional=False: If true, unconditional generation.
最难的概念是温度和 top_k ,阅读原文可以更好的理解:

例子
注意:我在这里展示的例子可能与你在 repo 或 notebook 中看到的不一样,它们是经过几次代码迭代后我能找到的最好的引用。
我们来试几个例子,看看这个东西有多好。
第一个文本将是:
“人工智能是新的电力”
!python main.py --text "AI is the new electricity" --top_k=10
样品:
在过去的两年里,它一直在开发世界上最先进和最具成本效益的发电系统,并提供世界上最高效的电力。它还致力于让世界上最贫穷的人用得起电,并投资于新能源技术以应对这些挑战。
我不认为算法在这个例子中有足够的信息,它只是谈论电力和功率。让我们尝试一些不同的东西。
让我们试试我的文章“学习数据科学的 3 个最大错误”中的一些内容:
数据科学需要实践。你所学的一切,即使教授没有告诉你,也要实践和尝试。这是真正理解事物的基础,当你在这个领域工作时,你会做许多不同的实际工作。
!python main.py --text "Data science needs practice. Everything you learn, even though if the professor doesn't tell you, practice and try it. This is fundamental to really comprehend things and when you are working in the field you will be doing a lot of different practical stuff." --top_k=20
下一次你在一个领域,你将会工作或者做很多对你来说不同的事情。你将在现实世界中做这些事情。你可以做不同的事情。你会在不同的领域发现不同的东西。你会在不同的工作中发现不同的东西。你会发现不同的东西。所以这不是你在现实世界中会做的事。你觉得更有趣的工作。你觉得更有趣的工作。你觉得更有趣的工作。你觉得更有趣的工作。有很多在现场的人实际上并不在现场。
!python main.py --text "Data science needs practice. Everything you learn, even though if the professor doesn't tell you, practice and try it. This is fundamental to really comprehend things and when you are working in the field you will be doing a lot of different practical stuff." --top_k=10 --temperature=0.8
如果你看着这个世界,这个世界对你来说是有意义的,不仅仅是这个世界或这个世界,而是整个世界,是这个世界给了人们希望和幸福。你需要了解的是这个世界。
看起来好多了,不是吗?
最后,让我们回到文章的第一句话:
数据科学家不是知道如何使用 Python 或 R 的人,而是可以通过理解他们拥有的数据来改进和优化业务工作方式的人,并创建模型来解释现实的复杂性,同时创建可以推动行动的解决方案,即与业务相关的特定行动。
!python main.py --text "A data scientist is not someone who knows how to use Python or R, is the person that can improve and optimize how a business work by understanding the data they have and create models that explain the complexity of reality while creating solutions that can drive actions, specific actions related to the business." --top_k=40 --temperature=0.9
在分析数据时,您需要有人了解您正在查看什么类型的数据,以及您将如何在业务案例中使用这些类型的数据。该人员还可以理解即将到来的数据,并确定在该业务案例中使用何种类型数据的最佳方式。
数据科学家是一个可以帮助你开发更好的商业解决方案的人。此人还可以帮助您制定更好的业务决策,以便更好地向客户解释数据。那个人也可以帮助你使用数据分析软件,学习如何更好地分析你的数据。
太棒了。这与我正在考虑的数据科学很接近,但系统帮助我创造了这些句子。您可以尝试一下,但是我建议您测试不同的配置,并阅读产生的文本,看看它是否有意义。

结论

我们正在达到人工智能世界的新水平,测试、尝试和扩展世界上最优秀的人的工作和研究变得越来越容易。在本文中,我展示了如何在 MatrixDS 平台中使用 GPT-2 模型,只需要最少的配置和该模型的一些基础知识。
你可以尝试非常不同的场景来测试这个模型,并开始用数据科学和人工智能改变世界。

感谢您的阅读,如果您想了解更多信息,请关注我这里,以及 LinkedIn 和 Twitter:
[## 法维奥·瓦兹奎——science y Datos | LinkedIn 创始人/首席数据科学家
加入 LinkedIn ‼️‼️重要提示:由于 LinkedIn 技术限制,我现在只能接受连接请求…
www.linkedin.com](https://www.linkedin.com/in/faviovazquez/) [## 法维奥·巴斯克斯(@法维奥·巴斯克斯)|推特
Favio Vázquez 的最新推文(@FavioVaz)。数据科学家。物理学家和计算工程师。我有一个…
twitter.com](https://twitter.com/faviovaz)
“我不喜欢板球…我爱它”
网络刮痧遇上潮流
介绍
板球是一种球棒和球的游戏,双方各有 11 名队员,比赛场地的中心是一个 20 米(22 码)的球场,两端各有一个小门,每个小门由两个球组成,平衡在三个树桩上。击球方通过用球棒击打在三柱门投球得分,而保龄球和防守方试图阻止这一点,并解雇每个球员(所以他们是“出局”)(维基百科)。

动机
板球的四年一度的展览,国际刑事法院板球世界杯 2019 年本月早些时候在板球的“主场”英格兰开始。甚至在世界杯开始之前,就有很多关于最新一届世界杯的炒作。ESPNcricinfo 已经成为板球爱好者访问所有板球比赛和球员数据的热门网站。这篇博客背后的动机是如何从网站上收集有用的信息,并在 r 的帮助下从中产生一些基本的见解。在这第一篇博客中,我对“1971 年至 2019 年的国际板球结果”数据集进行了广泛的探索。该数据集列出了从 1971 年到 2019 年初的所有国际板球比赛(如比赛中的对手国家或民族)。
更具体地说,本博客将涵盖以下内容:
- 我们将首先学习如何收集 ESPNCricinfo.com 迄今为止不同团队的记录
- 然后,我们将看到一些从一个页面中提取信息的基本技术:我们将按年份提取所有 once day international (ODI)团队记录的比赛团队、获胜者、保证金、场地、比赛日期和记分牌
- 以及所有 ODI 在一个子页面上按年份显示的所有比赛的个人团队得分
- 有了这些工具,你就可以开始你的游戏,并比较不同板球队的比赛(我们自己选择的):我们将看到你如何利用
tidyverse包,如绘图和dplyr,结合stringr,来进一步检查数据,并根据tidyverse的哲学为进一步的调查和统计推断制定假设。
网页抓取 ESPNCricinfo.com:rvest
步骤 1: 准备工作
步骤 2: 废弃团队记录
步骤 3: 提取记分卡 URL
步骤 4: 废弃记分卡
第一步:准备
首先,我做了一个我想废弃的年份的向量。
第二步:删除团队记录
在下一步中,我将这个函数应用于我之前生成的 URL 列表。为此,我使用了purrr包中的map()函数和 year-url 数据框中的‘rvest’函数。
步骤 3:提取记分卡 URL
从href属性中提取记分卡的 URL。然后获取 URL 列表并抓取我正在寻找的数据,然后在一些预处理后将其粘贴到数据框中。
第四步:废弃记分卡
Imap``rvest对记分卡 URL 起作用。因为这是大量的网址。我用的是进度条progress包。
数据清理和与 Tidyverse 的争论
在任何环境中处理数据的一个大问题是数据清理和数据集合并的问题,因为我经常从ESPNCricinfo.com收集数据。有无数种方法可以将 R 用于数据争论,但是我非常依赖 tidyverse。我用tidyr dplyr来处理不同的数据争论和重塑任务。最后,我编写了一个方便的函数,它从记分牌数据帧中获取输入。它提取所有游戏的分数绑定到一个 tibble。然后应用map函数来获取包含团队记录所需信息的数据帧。经过一些处理后,将得到的数据帧连接起来。
使用 Tidyverse 进行可视化数据探索
数据可视化是数据分析过程中的一个重要工具。可视化任务的范围可以从生成基本分布图到理解机器学习算法中复杂的因果变量的相互作用。随着数据集的创建,我将可视化 ODI 比赛的分布情况。我将ggplot2 创建主要图形,以及一些看起来松散的趋势,为排名靠前的板球队获胜的情节。
每年的比赛次数
国际板球理事会(ICC)根据所有球队在不同比赛和双边系列赛中的表现给他们打分。这些分数随后被用于球队的排名。这一排名有助于保持各国之间的良性竞争,以不断争取胜利。基于这个排名,我只进入了前 10 名的团队进行探索和分析。

顶级球队的比赛次数

2019 年世界杯参赛球队
大英帝国在将板球运动传播到海外方面发挥了重要作用,到 19 世纪中叶,它已经在澳大利亚、加勒比海、印度、新西兰、北美和南非站稳了脚跟。然而,我将只关注有资格参加 2019 年世界杯的球队;包括阿富汗、澳大利亚、孟加拉、英国、印度、新西兰、巴基斯坦、南非、斯里兰卡、西印度群岛。

ICC Cricket World Cup 2019 Teams Final List (https://dailysportsupdates.com)
哪个世界杯球队的胜率最高
奥迪斯,印度是领头的。西印度群岛、南非、英格兰和孟加拉国在这种形式中取得了胜利,并在榜单上排名前 5。现在每支球队都至少踢过一次球,根据我们目前看到的表现来预测哪个国家会赢仍然是不切实际的。然而,印度和英格兰似乎都是冠军的有力争夺者,只要他们能保持目前的比赛状态。

结论:
我们确定了如何将网页抓取分成不同的阶段,每个阶段都有自己需要应对的挑战:网站分析阶段、数据分析和设计阶段以及生产阶段。在每个阶段中,我们都提到了在进入下一阶段之前要开展的一些活动和要回答的一些问题。在这篇博客中,我们已经看到了用于网络抓取的 R 包是如何应用于统计领域的。我们已经展示了网络抓取如何用于探索背景变量和检索元数据等情况,以及它如何与 r 的tidyverse包完美结合。我们在 ICC 拥有最好的 ODI 板球队,它们是胜率最高的球队。我们提供了 plausibe isnight 来预测 2019 年 ICC 板球世界杯,我将在下一篇博客中发表。敬请关注。
参考资料:
“我不喜欢板球……我爱它!”:10cc — Dreadlock Holiday
《蟋蟀》。维基百科、国际板球理事会(ICC)
“统计与记录”:ESPNcricinfo.com
“gg plot 2】:H Wickham——数据分析的优雅图形
“Rvest】:H Wickham——轻松收获(刮)网页
“The tidy verse】:H Wickham——R 包
“gist-syntax-themes”:https://github.com/lonekorean/gist-syntax-主题
我喂了一个机器人八百个汉堡,这就是它吐出来的东西
似乎没有什么是人类能做的,除非有一个聪明的电脑傻瓜出现并做得更好。首先是简单的计算,然后是工厂。1996 年,计算机在国际象棋上打败了我们,1915 年,它们掌握了围棋,现在,它们也来争夺我们的视频游戏。这开始变得有点烦人了。但有一个领域我们永远比我们的数字对手有优势:创造力。
对吗?计算机不能产生创造性的作品。可以吗?它能想象吗?让我们找出答案。还有什么比人类智慧的顶峰,文明的最高荣耀,汉堡包更好的考验呢?
在我的家乡,每年都有一个美食节,来自城市各处的餐馆竞相做出最好、最有创意、最美味的汉堡。在过去的六年里,我一直在努力收集关于这些汉堡的数据。除了统计汉堡中使用的小圆面包、肉饼和其他配料的种类,我还记录了每个汉堡的名称和描述——总共超过 800 个。

1815 Cafe and Bar’s “Sweet Baby Cheesus”: Crumbed mozzarella with smoked cheddar, parmesan cream, jalapeno relish on a herbed milk bun, with straw fries. Matched with Garage Project White Mischief — Salted White Peach Sour.
汉堡的描述证明了人类的创造力。几乎所有能夹在小圆面包里的东西都出现在了菜单上,而且,在很大程度上,它们显示了对口味组合的深思熟虑。这是一个非凡的创造力壮举——想象并制作出新颖、令人兴奋、但味道也不错的配料组合。
这是我们可以教计算机做的事情吗?我们至少可以试试!让我们建立一个算法,可以产生一个从未见过的汉堡的描述。
我们需要一个可以生成文本的算法。这些技术同样支持聊天机器人和预测文本功能,如预先生成的电子邮件回复和自动完成句子。他们都有一个共同的方法:给定一个单词或短语,最有可能跟随的单词是什么?以“昨天我去了……”开头的句子可能以“……去了图书馆”结尾,但同样也可能以“……完全疯了”结尾给定上下文,这些算法试图计算哪一个是更好的选择。
让我们探索其中的一些算法,看看它们是如何工作的,并希望在此过程中制作出一些美味的汉堡。
实现这一点的最简单的方法被称为“马尔可夫链”。这就像游戏“多米诺骨牌”一样,在游戏中,通过匹配的数字将瓷砖连接起来。然而,我们的瓷砖上写的不是数字,而是单词。

Does anyone actually use Dominos for this?
想象一下,我们把我们集合中的每一个汉堡描述,分解成一对单词。威灵顿牛肉汉堡的“碳烤牛肉馅饼配野蘑菇”变成了“碳烤牛肉”、“牛肉馅饼”、“馅饼配”、“配野蘑菇”,等等。我们以同样的方式分解每一个汉堡的描述,就像多米诺骨牌一样,我们把它们混杂在一个袋子里。
现在,我们一次从袋子里拿出一片瓷砖。就像多米诺骨牌一样,我们可以把它们排列出来,把匹配的单词连接在一起。写有“配肉饼”的磁贴可能会连接到写有“配薯条”的磁贴,就像惠灵顿牛肉汉堡一样,但它也可能会连接到写有“配薯条”的磁贴。通过这种方式,我们把有时几乎有意义的汉堡描述放在一起。这里有几个用这种方法制作的汉堡:
奶酪红烧牛肉馅饼配熏牛肉、瑞士奶酪凝块、火柴杆薯条、gorgonzola 馅饼、纯素面包配烧过的甜菜根番茄酱。
手工制作的全熏甜菜根小面包,配以印度香料 taki 鳄梨色拉酱硬山羊奶酪酱,烤红辣椒肉饼,填充手切薯条,搭配 w Garage Project 啤酒,阿斯托里亚小面包配以卷心菜沙拉…
五香和牛淋薯条(五)
这些汉堡有些问题!第一个汉堡几乎是可信的,抛开你如何“奶酪炖”牛肉,或者“gorgonzola 肉饼”尝起来如何的问题。
第二个汉堡有更大的问题——它有两个小圆面包,配料太多。这个描述几乎没有意义。
最后,第三个汉堡根本不是汉堡!只是一些淋了牛肉的薯条,不知何故做成素食。
这些汉堡描述暴露了马尔可夫链方法的一些弱点。对于这样一个简单的算法,它在这种情况下产生了令人惊讶的一致结果,但它忽略了汉堡构造的几个重要规则:一个汉堡应该只有一个小面包,一个肉饼(通常),最多两三种其他配料。如果配上薯条或者其他的伴奏,这些都要在描述的最后介绍。马尔可夫链方法无法解释这些规则。
我们需要更复杂的东西。它能够理解它所使用的单词的含义,更重要的是,理解这些单词的顺序的含义。
我们试图解决的问题是,给定一个或多个前面的单词,如何预测句子中的下一个单词。如果一个汉堡的描述以“猪肉配……”开头,那么下一个词更有可能是“泡菜”、“棉花糖”或“老鼠药”之类的东西。为了生成我们的汉堡描述,我们从一个词开始,从我们收集的真实汉堡描述中随机选择。然后我们试着预测,给定第一个单词,最有可能的第二个单词是什么。
如果我们的第一个词是“熏”,那么第二个词很可能是“鹿肉”或“培根”之类的东西,很可能不是“生菜”。给定第二个单词,我们将这对单词反馈到模型中。给定这两个词,最有可能的第三个词是什么?例如,“熏鹿肉馅饼”比“熏鹿肉小圆面包”更有可能。
我们将使用的模型被称为“LSTM”,代表“长期短期记忆”。就像我们在以前的文章中用来分类图像的算法一样,这个模型是一个“神经网络”。这采用了两层或更多层的算法,首先将汉堡描述中的原始单词提取为有意义的数据,然后根据这种提取的“嵌入”进行预测。
LTSM 采用了两项非常重要的创新。首先,它是一个“递归”神经网络。这意味着它不仅知道描述中单词的意思,还知道这些单词的顺序中存在的意思。第二个创新是,该模型可以考虑句子中单词的不同重要性——该模型识别出汉堡的一些细节——如小面包和肉饼——应该只出现一次。该模型可以选择“保留”在汉堡描述中早期出现的单词,并使用这些重要的单词来通知它在文本中稍后选择的单词。
像其他神经网络模型一样,LTSM 是迭代训练的。它开始做出非常天真的选择,随着每一次迭代(或“时代”)的训练,它变得更加复杂。这是我们的模型在一个时期后的输出:
牛肉和和和和和和和和和和和和和和和和和和和和
这不是一个鼓舞人心的开始。从我们提供给模型的“种子”单词“beef”中,模型选择了它认为最有可能的下一个单词:“and”。并非没有道理——总体而言,“和”是描述中最常见的词。但是这个模型一次又一次地做出同样的猜测,随着句子越来越长,从不更新它的预测。让我们看看它在另一轮训练后表现如何:
牛肉馅饼加牛肉和牛肉和牛肉和牛肉和牛肉和牛肉馅饼加牛肉和牛肉
仍然不太好,尽管它已经在之前的尝试中取得了实质性的进展。据悉,“patty”通常跟在“beef”后面,“with”是另一个常用词。我们继续训练吧。
熏肉牛肉馅饼,烟熏牛肉馅饼,自制奶酪和蛋黄酱,夹在小面包里,还有手切薯条
现在我们有进展了!这个模型已经学会了一些重要的东西:它正在向汉堡中添加更多的配料,并且学会了按照可信的顺序摆放这些配料:肉饼、其他配料、小圆面包,最后是薯条。仍然有太多的“和”和“与”,但我们正在取得进展。让我们再来一次:
牛肉馅饼配烟熏培根和烟熏奶酪,夹在潘多罗面包里,配以手工切制的薯条
这简直太完美了!四个时代的训练(在我的笔记本电脑上大约四十分钟)给了我们非常好的结果。这是一个非常糟糕的汉堡,但至少它是有意义的。
从这里开始,对模型的改进要慢得多。需要十个以上的时间(和几个小时)才能可靠地做出真正可信的汉堡:
牛肉馅饼配烟熏切达番茄和 kāpiti 蓝奶酪,配以潘多罗牛奶面包和薯条
这个模型几乎已经确定了汉堡描述的格式。它学会了像“烟熏切达干酪”这样的短语。据悉,每种配料只应出现一次,尽管在这种情况下,它既有切达奶酪又有蓝奶酪,这是一个奇怪的烹饪选择。除了缺少逗号和大写字母(这些已从训练数据中删除),这种汉堡不会在餐厅菜单上引起任何关注。
下面是通过向同一个模型提供不同的“种子”单词而创建的几个汉堡:
木薯粉加香料的羊肉馅饼,夹有烟熏奶酪、蛤蜊调料和泡菜,放在潘多罗面包里,还有薯条
陈年牛肉馅饼配烟熏培根和培根果酱、西红柿酱和火箭酱,夹在 zaidas 面包房的牛奶小面包里,还配有薯条
猪肉馅饼配烟熏切达干酪和烟熏切达干酪沙拉,配以潘多罗牛奶面包和薯条
炸鸡配泡菜和红卷心菜沙拉,面包配薯条
饼干碎乡村肉猪肉馅饼配烟熏切达干酪贸易厨房金斯米德卡斯尔波因特羊乳酪和 kāpiti bay 屠夫培根配克莱尔维尔面包店面包配手工切薯条
相当好吃!我不知道饼干碎猪肉或木薯五香羊肉,但在大多数情况下,这些看起来像很好的汉堡。该模型已经学习了许多复杂的汉堡构造规则,这使它能够可靠地制作出令人信服的餐馆汉堡描述的复制品。
但是上面选择的汉堡掩盖了我们模型的一个弱点。再看更广泛的选择,它生产的汉堡几乎都极其相似。该模型有反复重复的模式:“烟熏培根和培根果酱番茄调味品和火箭”经常出现,每个汉堡都配有薯条,偶尔手工切割。此外,产生的汉堡范围相当狭窄。大部分是牛肉汉堡。很少有人偏离传统的汉堡标准。我们的模特是一个非常缺乏想象力的厨师。
事情是这样的。该模型学习预测句子中的每个单词,如果猜测错误,它将受到惩罚。这有助于模型学习汉堡描述的结构和模式,但当给定相对较小的数据集时,它会鼓励模型做出非常保守的选择。它学会在每个关键时刻做出最有可能的选择。它不是试图有创造性,而是试图成为正确的 T2。
这是所有人工智能算法的一个基本约束。从本质上讲,它们的运作原则是尽量减少误差。我们的汉堡生成器简单地学习了定义普通汉堡的原则,并试图尽可能做出最不令人惊讶的选择。它永远不会包含任何它没有见过的成分。它永远不会想出新的烹饪技术。在模仿汉堡描述的模式方面,它可能比马尔可夫链算法更熟练,但它本质上仍然只是重新排列它所训练的描述的片段。这有点令人失望。我们能做得更好吗?
结果是肯定的!虽然我们无法绕过核心约束——这些算法在内心渴望最小化惊喜,而不是最大化愉悦——但我们能做的是大幅扩大生成器必须利用的信息范围,并增加其计算的复杂性。我们需要深入艰苦的前沿研究——这种研究需要巨大的超级计算机和拥有难以发音领域学位的团队。我无法理解的东西。为了使用这项技术,我们将使用一种更古老、更简单的技术。我们要抄袭别人的作品。
2019 年 4 月,开放人工智能项目发布了他们的“GPT2”模型。这是一个“通用语言模型”。它对于我们的汉堡发电机就像核电站对于野营炉一样。我们的汉堡生成器有大约 20 万个参数——它可以学习数据的单个特征。GPT2 有超过 10 亿。虽然我们的汉堡生成器是在 800 个汉堡描述上训练的——大约 25,000 个单词或 140 千字节——但 GPT2 是在 800 万个网页上训练的——40 千兆字节的数据。你可以在开放人工智能网站上阅读更多关于这个模型的信息,但你可能会更喜欢实时实验它的反应。
这个非常强大的模型运行的基本原理与我们之前的汉堡生成器相似,只是规模扩大了。经过大量文本的训练,它不仅知道如何制作汉堡,还知道如何生成任何类型的文本*。给它一个种子词“牛肉”,它会自信地快速说出一串关于这个主题的句子:*
清迈路边餐馆的炖牛肉会让人瞬间怀旧。这是因为该镇长期以来最受欢迎的菜肴——炖牛肉来自这个村庄,它在那里已经存在了 1000 多年
这很有趣,但不是做汉堡。为了实现这一点,我在与之前相同的汉堡数据集上重新训练了该模型,尽管作为额外的挑战,我还包括了汉堡名称。该模型保留了它所看到的文本的复杂性和知识深度,但它学会了将训练集中在制作汉堡上。起初,它的努力相当奇怪:
…一个大家庭的终结,这很可能是个好主意。这是世界上“最疯狂”的人对最近的研究说的话,这项研究仍然是相关的;更重要的是…
但是很快它就学会了喜欢类似汉堡的单词:
…是一道非常好的纯素食甜点和辣味炸鸡,配有芝麻、番茄酱、芥末、薄荷和大虾的泡菜薯条,还有烤土豆
最爱的烤土豆,配培根…
有趣的是,随着它的学习,它保留了一些它被训练过的数据的怪癖。这里它给了一个摄影师一个不存在的插图。
蘑菇,带一点自制的红色奶酪馅饼,生菜,红洋葱和刺山柑。装在一个拉链袋里。(图片:克里布拉扎基)
它似乎对发现的汉堡很兴奋:
哦,天哪,一份炸鸡面包是一部 B 级电影,有薯条和香脆的洋葱面包。
然而,没过多久,这种“发电机”就开始生产各种各样新颖的、有时令人倒胃口、但绝对原汁原味的汉堡:
中城宿醉:牛肉馅饼配炸洋葱、碎马苏里拉奶酪、鳄梨、红甘蓝味噌、生菜、生菜泡菜和滑稽的宙斯荷兰酸辣酱。
帕特里克·斯图尔特爵士:牛肉馅饼来自多塞特郡,配有金斯米德香料茴香、pecorino、rojo 奶酪、猕猴桃沙拉、香草马沙拉胡椒蛋黄酱和甜菜根面包蘸 johnbé酱,还有小玉米爆米花-盐 tahini 凉拌卷心菜。
我把它们都毁了:牛肉配肋眼肉、土豆和黄瓜酸辣酱、烟熏椒盐卷饼、肉桂土豆、甜菜根酸辣酱和芒果酸辣酱夹在黑麦面包里,还有红色猕猴桃块和 confit 鸭籽沙拉。
小鸡夫人:香脆的油炸鹰嘴豆配奶酪、大蒜黄油、烧烤猪肉酱和星鳀鱼酸辣酱,放在 Arobake 牛奶面包中,配有水煮 piccalilli 和香脆的荷包蛋。
肥鸡汉堡:油炸的甜辣鸡腿,配以厚厚的巧克力和墨西哥辣酱,软壳上涂有辣酱。
海哲明牛肉汉堡:牛肉馅饼,干草卡哈羊乳酪,啤酒花屠夫蓝奶酪,奶油肉汁,松脆的绿色蔬菜和马槟榔豌豆油炸饼夹在芝麻软米饭团中。
臭名昭著的救赎者去年春天滑块所有春夏:玉米饼汉堡;霍夫曼汉堡;罗马牛肉饼配巨嘴鸟乳清干酪肉汁;鹿肉沙拉配脆迷迭香和自制菠萝,配软奶酪酱和手切苹果沙拉。
可疑的猪猪扒白宫肉配炸洋葱、炸甜菜根沙拉和大量绿叶菜,配 kū mara 薯条。
那么,计算机又一次胜利了吗?世界上的厨师们能放下帽子,相信算法能发明出比他们想象的更有创意的食物吗?我们教会了一台机器有创造力吗?

This one’s going on the refrigerator
不完全是。正如我们所了解的,我们的模型,即使是最复杂的模型,也根本没有试图去创造。他们只是试图正确地猜测句子中的下一个单词。在我们看来,他们的创造性程度是他们失败和不成功的函数。最终的模型已经很好地学习了英语句子的结构,甚至一些关于动词和形容词如何用于修饰食物的语义:“荷包蛋”、“松脆青菜”、“碎马苏里拉奶酪。但是它还没有完全学会构成“正常”汉堡的规则,因此它做出了不寻常的、令人惊讶的选择。我们可以将这些选择解读为“创造性的”,但它们绝不是小说创作中刻意努力的产物。
为了创造一个真正有创造性的算法,我们需要奖励“创造性”的选择,惩罚不那么有创造性的选择。我们需要能够衡量创造力。这暴露了我们努力的徒劳。到底什么是创造力?当厨师发明新的食谱时,他在做什么?当艺术家把颜料放到画布上时,他们在想什么?在某种程度上,它们在做和我们的算法一样的事情——它们在它们所选择的媒介的限制下工作;但是他们也在推动对抗那些约束。他们试图表达某种东西。
这重要吗?也许不是。如果有人坐下来点一个“海哲明牛肉汉堡”或“中城宿醉”却不能分辨出他们的汉堡是由计算机而不是人类厨师制作的,他们会知道其中的区别吗?海哲明奶牛的“腌豌豆油炸饼”会因为不是人类构思出来的而变得更难吃吗?会不会显得没创意了?如果“创造力”不在于厨师如何想出他们的食谱,或者艺术家如何选择他们的颜料。如果它只存在于吃汉堡的人的头脑(和胃)中呢?我们无法制造一台有创造力的机器,因为我们无法衡量创造力。也许那是因为没有可衡量——创造力不存在于创造的行为中,而是存在于感知的行为中。
这些问题超越了机器学习和汉堡。但在另一种意义上,它们是它的核心问题:像人一样思考意味着什么?这是精神食粮。
感谢阅读!本系列的上一篇文章——关于图像识别——可以在 这里 找到。下一篇文章将于下月发表。
我不知道如何建立一个机器学习管道。但我是这么想的。
学习从零开始构建机器学习管道

当事情变得困难时,困难就开始了。
作为一名学习人工智能(AI)的研究生,我对机器学习(ML)的接触很大程度上是学术性的。然而,当给我的任务是为时间序列预测模型创建一个简单的 ML 管道时,我意识到我是多么的无知。此外,我几乎找不到任何关于这个主题的具体信息或代码,因此我决定写这个主题。
本文将介绍如何创建一个简单的 ML 管道的基本结构(随着时间的推移,可能会补充更多的信息)。
什么是机器学习管道*,为什么它们是相关的?*
正如“管道”一词所暗示的,它是 ML 循环中一系列链接在一起的步骤,通常涉及获得数据、处理数据、对各种 ML 算法进行训练/测试,以及最终获得一些输出(以预测等形式)。与传统的“管道”不同,新的现实输入及其输出通常会反馈到更新模型的管道。微软 Azure 的这篇文章很好地描述了 ML 管道。

Typical ML Pipeline (source: https://docs.microsoft.com/en-us/azure/machine-learning/service/concept-ml-pipelines)
简而言之,ML 变得如此广泛如此迅速,以至于模型的准确性变得与访问、缩放和存储这些模型的能力同等重要。ML 管道本质上是一个自动化 ML 工作流程。
(管道现在已经可以在平台上使用,比如 Azure 机器学习管道和亚马逊 SageMaker。虽然它们代表了数据团队构建和部署的一种快速有效的方式,但是本文并没有解决上述这些服务。)
动机
在构建和部署 ML 模型时,效率是关键。然而,理解其中的细微差别和困难将有助于我们理解为什么自动化工作流是非常受欢迎的,尤其是当我们谈到可伸缩性和跟踪变更的简易性时。
除了拥有适当的结构和隔离 ML 堆栈不同部分的方法(数据处理、特性选择等),值得一提的是日志记录更改也是 ML 模型部署的重要部分。以下是一些原因:
- 如果输入要素发生变化,其余要素的权重也可能发生变化。我们希望始终能够跟踪一个模型相对于另一个模型的增量,以便我们能够始终评估是否有任何改进。
- 当我们不断迭代有细微变化的模型时,在保持清晰和灵活性的同时跟踪配置文件的更新变得很困难。
- 数据输入可能会随着时间而改变。将这些作为日志的一部分进行跟踪也很重要。
- 随着额外的数据反馈,更新测试和验证集是很重要的,因为我们需要保证模型之间的可比性。
ML 管道的组件
- README.md
大多数人应该对这个很熟悉。这只是一个降价文件,指导用户如何运行具有任何特性的管道。这方面的例子可以在任何 Github 存储库中找到。 - requirements.txt
这是一个文本 文件保存了所有的库版本需求。它由所有用于在管道中执行代码的外部(非预安装的 Python 库)库组成。创建这样一个文件的目的是为了让管道可以很容易地移植到另一个平台上,比如 Docker 容器或虚拟机。安装这些需求可以作为 run.sh 文件的一部分。 requirements.txt 文件的例子如下:
scikit-learn==0.20.0
numpy==1.16.3
pandas==0.24.2
statsmodels==0.9.0
scipy==1.3.1
Keras==2.2.4
seaborn==0.8.1
- run.sh
这本质上是一个 bash 脚本来完成以下任务(非穷举):
- 下载可能存储在云上的数据
- 在 requirements.txt 中安装库需求
- 创建任何文件夹/子文件夹来存储输出(日志、图表等)。)
- 运行任何属于 ML 管道的 python 模块/类/脚本
# Download dataset stored on cloud
curl -o dataset.csv [https://insert_cloud_storage_url/dataset.csv](https://insert_cloud_storage_url/dataset.csv)# Install libraries in requirements.txt
pip install -r requirements.txt# Make a charts directory if it doesn't exist; This is to store model chart outputs for example
[ -d charts ] || mkdir charts# Execute main script
python mlp/main.py -f experiments/config.yaml
- main.py
这应该是执行大部分代码的主文件。这应该包括解析配置文件的代码(在步骤 5 中)。一个例子可能是这样的(这个例子来自马丁·托马斯——大声喊出来帮忙!):
def load_cfg(yaml_filepath):
"""
Load a YAML configuration file. Parameters
----------
yaml_filepath : str Returns
-------
cfg : dict
"""
# Read YAML experiment definition file
with open(yaml_filepath, 'r') as stream:
cfg = yaml.load(stream)
cfg = make_paths_absolute(os.path.dirname(yaml_filepath), cfg)
return cfgdef make_paths_absolute(dir_, cfg):
"""
Make all values for keys ending with `_path` absolute to dir_. Parameters
----------
dir_ : str
cfg : dict Returns
-------
cfg : dict
"""
for key in cfg.keys():
if key.endswith("_path"):
cfg[key] = os.path.join(dir_, cfg[key])
cfg[key] = os.path.abspath(cfg[key])
if not os.path.isfile(cfg[key]):
logging.error("%s does not exist.", cfg[key])
if type(cfg[key]) is dict:
cfg[key] = make_paths_absolute(dir_, cfg[key])
return cfg
之后,该文件可用于运行其他脚本中的代码,这些脚本可用于数据预处理、特性选择、参数调整等。这个文件构成了其他文件的主干。
5.配置文件
通常,模型配置(调整超参数等)总是写在代码块本身中。但是,在单独的配置文件中维护这些配置已经成为一种惯例,因为它们可以更容易地处理,并且不需要在实际的代码块中进行修改。这些都是典型的 。yaml 文件。以下内容应该可以通过配置文件进行配置:
- 数据集加载
- 预处理
- 特征抽出
- 参数选择
- 模型创建
- 模型评估
一个的例子。yaml 文件应该是这样的:
dataset:
script_path: ../datasets/cifar10_keras.py
model:
script_path: ../models/optimized.py
optimizer:
script_path: ../optimizers/adam_keras.py
initial_lr: 0.0001
train:
script_path: ../train/train_keras.py
artifacts_path: ../artifacts/cifar10_opt/
batch_size: 64
epochs: 1000
data_augmentation:
samplewise_center: False
samplewise_std_normalization: False
rotation_range: 0
width_shift_range: 0.1
height_shift_range: 0.1
horizontal_flip: True
vertical_flip: False
zoom_range: 0
shear_range: 0
channel_shift_range: 0
featurewise_center: False
zca_whitening: False
6.创建的任何其他 python 模块/类/脚本
这可以包括从数据预处理、特征选择到处理数据所需的任何事情。
7.正确的项目文件夹结构
有一个合适的文件夹结构是很重要的,因为对于任何试图理解项目如何工作的人来说,这变得更加整洁和清晰。
├── artifacts
│ ├── train : Logfiles, trained models
│ └── test : Logfiles
├── datasets : Data loading scripts
├── experiments : Configuration files
├── models : Scripts defining how the model looks like
├── optimizers : Scripts defining the optimizeres
└── train : Script to run the training
估价
每个机器学习模型都有一个评估指标,通常以交叉熵(又称对数损失)、均方误差/绝对误差或简单的准确度(或精确度/召回率)的形式存在。这些指标可以输出到控制台,以帮助用户确定模型是否在改进,或者可以记录到文本文件中。
结束语
希望这能帮助那些试图理解为什么机器学习管道很重要以及如何创建一个管道的人!
支持我! —如果你喜欢我的内容并且没有订阅 Medium,请考虑支持我并通过我在这里的推荐链接订阅 ( 注意:你的一部分会员费将作为推荐费分摊给我)。
两年前我不知道如何写代码。现在我是一名 AI 工程师。

Photo by Jakub Kriz on Unsplash
正如艾尔莎所说,职业转换是一次“走向未知”的旅程
我最原始的旅程
两年前,我从大学毕业,在那里我学习经济和金融。我已经做好了从事金融业的准备。投资银行和全球市场——这些都是梦寐以求的工作。毕业前 9 个月,我在一家投资银行找到了一份工作,感到很自豪,因为如果没有在那家银行实习过,通常很难找到工作。
工作几个月后,我学会了一些 Excel VBA ,学会了如何使用 Tableau 、 Power BI 和 UiPath (一个机器人流程自动化软件)。我意识到我更感兴趣的是拿起这些工具,学习编码,而不是学习银行产品。银行产品一度因其复杂性而引起我的兴趣,但现在只被视为银行从客户身上获利的一种方式。
银行业环境极大地挑战了我的个人价值观,但这是改天的话题。
与此同时,我的一位同事让我看到了‘机器学习’的世界。一个人可以从特定的输入“预测”特定的结果,这个事实引起了我的兴趣。
我立刻就被吸引住了。
但是有一个问题——我的编码技能很初级。在我的字典里,蟒蛇是蛇的一种,而猪是好的…一头猪。
快进两年后,在这里我即将进入 AI 行业,成为一名 AI 工程师。旅程不容易,也不短。对我来说,转向人工智能行业仅仅是一个开始——一个我学习和成长的新开始。我的旅程是这样的。
放弃
每个人的数据科学之旅都不一样。这篇文章不是关于“如何进入人工智能”,也不应该被看作是一步一步的指南。这是一则个人轶事,我希望能激励人们鼓起勇气去做他们想做的事情,因为生命太短暂了,不能过着没有意义的生活。
我的旅程
跳上 MOOC 炒作列车
我有经济和金融背景,不知道如何编码。 Excel VBA 非常接近编码,但仅此而已。作为一名优等生,并希望赶上数据科学的潮流,我报名参加了一些大型开放式在线课程(MOOCs)。不是一个,而是少数。这是我报名参加的课程清单:
- Python BootCamp:在 Python 3 中从零到英雄[ Udemy ]
- Python for Data Science and Machine Learning boot camp[Udemy]
- 用 MySQL 管理大数据[ Coursera ]
- Java 初学者教程[ Udemy ]
- Web 开发人员训练营[ Udemy ]
- 机器学习 A-Z:数据科学中的实践 Python & R[Udemy
- 用 Docker [ Udemy ]部署机器学习和自然语言处理模型
不用说,大部分都不是我完成的(只有粗体的)。我陷入了我称之为的 MOOC 自我延续周期。获取知识的便利性使得从一门课程到下一门课程变得很自然,由于所涵盖的主题过于简短,我的兴趣稍纵即逝,所以通常无法完成之前的课程。
对我来说,这是 MOOCs 最大的缺点——覆盖的内容过于简短。或者,也许我最初对 MOOCs 能够推动我从事数据科学职业的期望太天真了。
从长远来看,教授传统机器学习(ML)方法的典型 MOOC 通常会忽略模型实际做的事情。随机森林被教导为决策树的集合,但是决策树如何决定在哪个分支选择哪个特征(即熵的概念和数学)将不被涵盖。支持向量机只是简单的作为一种分类方法来讲授,但是超平面是如何确定的就不涉及了。
当我们考察深度学习等更高级的人工智能领域时,我们可以看到“我所知道的与“我需要知道的”之间的这种差异。教授深度学习的 MOOCs 通常会在像 MNIST 这样的数据集上向你抛出一堆代码,并得出结论说你现在是深度学习专家(我有点夸张,但你已经明白要点了)。这显然与现实相去甚远,因为研究论文通常包括复杂的架构,涉及对深度神经网络模型中特征提取的理解,以及其他更复杂的功能,如变压器和双向编码。除了迁移学习和元学习等概念之外,理解为什么一些最先进的模型比其他模型更好也很重要。
在我看来,教授 ML 的 MOOCs 经常给人一种错误的印象,即任何人都可以成为 ML 从业者。对于天真的人来说,ML 只是包含的几行代码。契合()和。predict() ,这是因为 MOOCs 以这样一种方式呈现它,人们可以相对容易地开始学习 ML(也许由于 ML 的大量宣传,这些课程的货币化是如此有利可图)。
不要误解我——mooc 很棒。它们为人们获取知识和开始某个主题提供了一种快速简单的方法。他们会让你成为专家吗?不。完成课程后你做什么将决定你是否成为专家。
弄脏我的手
在完成了几门 MOOCs 课程后,我知道自己将一事无成。当然,我在 Python 中有一些基本技能,并且知道如何在中使用 sci-kit learn 。fit() 和*。predict()* 感,但仅此而已。
为了提高我的编码技能,我在hacker rank上练习,并完成了与 SQL 和 Python 相关的问题。同时,我想有一个现实生活中的项目,在那里我可以利用 Python 。这是我开始开发一个可以帮我预订羽毛球场的机器人的时候。这主要涉及使用 Selenium 与浏览器进行交互,以浏览网页,并最终推出并支付羽毛球场的费用(这类似于运动鞋机器人)。这样做的动机是,新加坡的羽毛球场通常在两周前就被预订一空,许多人经常在发布时间每天都在预订网站上扎营(他们通常在一两秒钟内就被预订了)。
尽管我对用 Python 写代码更有信心,但我对代码效率一无所知。时间和空间的复杂性对我来说完全陌生。面向对象编程是我头脑中的一个概念,从未有过闪光的时刻(更不用说最终被遗忘)。
在 ML 方面,我是一个 Jupyter 笔记本专家。我可以把我的 Jupyter 笔记本的主题改成“黑暗模式”,并使用所有的快捷键。显然,我已经准备好担当数据科学家的角色。
现实检查——我面试失败得很惨。涉及代码的技术测试比我说“数据科学”还快。我申请的一个技术分析师的职位让我被转到了另一个部门,因为他们觉得我更适合做业务分析师。
我离我该去的地方很远。
脏但还不够脏
为了获得 ML 的深度并磨练我的 Python 技能,我决定在新加坡管理大学攻读商业 IT 硕士学位(专攻 AI)。
我了解了传统 ML 模型背后的数学,并在自我管理的数据集上应用了最先进的深度学习架构。我了解了人工智能的重要概念,包括常见的搜索算法、Q 学习和深度 Q 学习。我学习了算法设计,包括图形算法、时间和空间复杂性、名称匹配算法和许多其他算法,这些算法几乎真的把我非计算机科学的大脑撕裂了。本质上,这门课程给了我 MOOCs 所缺乏的学术严谨性。
在这个时间点上,我有几个硕士项目。它们不是完全成熟的项目,因为数据集通常是从 Kaggle 提供或获得的,并且它们通常以 Jupyter 笔记本告终。为了一致性,深度学习模型在 Docker 上运行,但从未考虑过部署的某个方面。毕竟,它们是学校的项目。
在我看来,硕士学位提供了人工智能专业人员所必需的学术严谨性,但缺乏现实世界应用的方面。硕士课程不会告诉你在数据科学领域找到工作需要什么——你必须自己去发现。软件工程和 DevOps 技能通常是数据科学家工作范围的一部分(尽管不广泛)。代码协作在大型组织中也很重要。因此,知道如何设置 Docker 环境、启动 AWS EC2 实例、在 Azure blob 存储上托管数据集、高效地组织代码以及使用 GitHub 或 GitLab 进行版本控制是一些需要的关键技能,但在课堂上没有教授。
尝试,即使你认为自己不够好
我继续面试,在技术面试和非技术面试中积累了大量的经验(尽管大多数都失败了)。这也让我知道我不知道的事情,并花时间去学习那些技能。更重要的是,它让我了解了公司为同一角色提供的不同类型的职位描述,以及这如何与公司在人工智能采用方面的成熟度相对应。
两年后,我得到了一个角色,作为一名人工智能工程师接受培训。对我来说,这是一个在我热爱的领域学习和成长的好机会。更重要的是,这证明了任何人都可以完成他们设定的目标,尽管有些人可能比其他人需要更长的时间。
归根结底,职业生涯是一场马拉松,而不是短跑。做你喜欢做的事情,因为你将会花大量的时间在工作上。
如果你感到失落,记住艾尔莎说的话,“做下一件正确的事”。
结束语
很高兴收到任何评论:)
支持我! —如果你喜欢我的内容并且没有订阅 Medium,请考虑支持我并通过我在这里的推荐链接订阅 ( 注意:你的一部分会员费将作为推荐费分摊给我)。
898

被折叠的 条评论
为什么被折叠?



