探索性数据分析的广泛逐步指南
我对任何数据集执行 EDA 的个人指南
什么是探索性数据分析?
探索性数据分析(EDA) ,也称为数据探索,是数据分析过程中的一个步骤,其中使用了多种技术来更好地理解所使用的数据集。
“理解数据集”可以指许多事情,包括但不限于…
- 提取重要变量,留下无用变量
- 识别异常值、缺失值或人为错误
- 理解变量之间的关系或缺乏关系
- 最终,最大限度地提高您对数据集的洞察力,并最大限度地减少流程后期可能出现的潜在错误
这就是为什么这很重要。
你听说过“垃圾进,垃圾出”这句话吗?
对于 EDA,更像是“垃圾入,执行 EDA,可能是垃圾出。”
通过进行 EDA,你可以将一个几乎可用的数据集变成一个完全可用的数据集。我并不是说 EDA 可以神奇地使任何数据集变得干净——这不是真的。然而,许多 EDA 技术可以解决每个数据集中存在的一些常见问题。
探索性数据分析主要做两件事:
1.它有助于清理数据集。
2.它让你更好地理解变量和它们之间的关系。
EDA 的组件
对我来说,探索数据有几个主要部分:
- 了解您的变量
- 清理数据集
- 分析变量之间的关系
在本文中,我们将看看前两个组件。
1.了解您的变量
你不知道你不知道什么。如果你不知道自己不知道什么,那么你怎么知道你的见解是否有意义?你不会的。
举个例子,我正在研究 NFL 提供的数据(这里是数据这里是数据),看看我是否能发现任何关于增加受伤可能性的变量的见解。我得到的一个见解是,中后卫积累的伤病是后卫的八倍多。然而,我不知道后卫和后卫之间的区别是什么,正因为如此,我不知道我的见解是否有意义。当然,我可以谷歌一下这两者之间的区别,但是我不能总是依赖谷歌!现在您可以明白为什么理解您的数据如此重要了。让我们看看如何在实践中做到这一点。
作为一个例子,我使用了我用来创建我的第一个随机森林模型的相同数据集,二手车数据集这里。首先,我导入了我知道我的分析需要的所有库,并进行了一些初步的分析。
#Import Libraries
import numpy as np
import pandas as pd
import matplotlib.pylab as plt
import seaborn as sns#Understanding my variables
df.shape
df.head()
df.columns
。shape 返回我的数据集的行数乘以列数。我的输出是(525839,22),这意味着数据集有 525839 行和 22 列。
。head() 返回我的数据集的前 5 行。如果您想查看每个变量的一些示例值,这很有用。
。columns 返回数据集中所有列的名称。
df.columns 输出
一旦我知道了数据集中的所有变量,我想更好地理解每个变量的不同值。
df.nunique(axis=0)
df.describe().apply(lambda s: s.apply(lambda x: format(x, 'f')))
。nunique(axis=0) 返回每个变量的唯一值的数量。
。describe() 总结了数字变量的计数、平均值、标准差、最小值和最大值。接下来的代码只是将每一行格式化为常规格式,并取消科学符号(见此处)。
df.nunique(轴=0)输出
df.describe()。apply(lambda s:s . apply(lambda x:format(x,’ f '))输出
很快,我注意到了价格、年份和里程表的问题。例如,最低和最高价格分别为 0.00 美元和 3,048,344,231.00 美元。您将在下一节看到我是如何处理这个问题的。我仍然想更好地理解我的离散变量。
df.condition.unique()
使用**。unique()** ,我看了看我的离散变量,包括‘条件’。
df.condition.unique()
你可以看到彼此有很多同义词,比如‘优秀’和‘如新’。虽然这不是最好的例子,但在某些情况下,将不同的单词组合在一起是最理想的。例如,如果您正在分析天气模式,您可能希望将“多云”、“灰色”、“多云,有可能下雨”和“大部分多云”简单地重新分类为“多云”。
稍后您将看到,由于有太多的空值,我最终省略了这个列,但是如果您想要重新分类条件值,您可以使用下面的代码:
# Reclassify condition column
def clean_condition(row):
good = ['good','fair']
excellent = ['excellent','like new']
if row.condition in good:
return 'good'
if row.condition in excellent:
return 'excellent'
return row.condition# Clean dataframe
def clean_df(playlist):
df_cleaned = df.copy()
df_cleaned['condition'] = df_cleaned.apply(lambda row: clean_condition(row), axis=1)
return df_cleaned# Get df with reclassfied 'condition' column
df_cleaned = clean_df(df)print(df_cleaned.condition.unique())
你可以看到下面的值被重新分类了。
print(df _ cleaned . condition . unique())输出
2.清理数据集
现在,您已经知道了如何根据需要对离散数据进行重分类,但是还有许多事情需要注意。
a .删除冗余变量
首先我去掉了我认为多余的变量。这包括 url、图像 url 和城市 url。
df_cleaned = df_cleaned.copy().drop(['url','image_url','city_url'], axis=1)
b .变量选择
接下来,我想去掉任何有太多空值的列。多亏了我的朋友 Richie,我使用下面的代码删除了 40%或更多数据为空值的列。根据具体情况,我可能会提高或降低阈值。剩余的列如下所示。
NA_val = df_cleaned.isna().sum()def na_filter(na, threshold = .4): #only select variables that passees the threshold
col_pass = []
for i in na.keys():
if na[i]/df_cleaned.shape[0]<threshold:
col_pass.append(i)
return col_passdf_cleaned = df_cleaned[na_filter(NA_val)]
df_cleaned.columns
c .剔除异常值
回到前面提到的问题,我为价格、年份和里程表设置了参数,以删除设置边界之外的任何值。在这种情况下,我用我的直觉来确定参数——我肯定有确定最佳边界的方法,但我还没有深入研究过!
df_cleaned = df_cleaned[df_cleaned['price'].between(999.99, 99999.00)]
df_cleaned = df_cleaned[df_cleaned['year'] > 1990]
df_cleaned = df_cleaned[df_cleaned['odometer'] < 899999.00]df_cleaned.describe().apply(lambda s: s.apply(lambda x: format(x, 'f')))
您可以在下面的结果中看到最小值和最大值发生了变化。
d.删除空值行
最后,我用了**。dropna(axis=0)** 删除任何包含空值的行。在下面的代码之后,我从 371982 行增加到 208765 行。
df_cleaned = df_cleaned.dropna(axis=0)
df_cleaned.shape
3.分析变量之间的关系
相关矩阵
当分析我的变量时,我喜欢做的第一件事是通过相关矩阵将其可视化,因为这是对我的所有变量形成总体理解的最快方式。回顾一下,相关性是描述两个变量之间关系的度量——如果你想了解更多,你可以查看我的统计小抄这里。)因此,相关矩阵是显示许多变量之间的相关系数的表格。我使用 sns.heatmap() 来绘制二手车数据集中所有变量的相关矩阵。
# calculate correlation matrix
corr = df_cleaned.corr()# plot the heatmap
sns.heatmap(corr, xticklabels=corr.columns, yticklabels=corr.columns, annot=True, cmap=sns.diverging_palette(220, 20, as_cmap=True))
我们可以看到,价格与年份正相关,价格与里程表负相关。这是有道理的,因为新车通常更贵,里程数多的车相对更便宜。我们还可以看到年份和里程表之间存在负相关关系——越新的汽车行驶的里程数越少。
散点图
就数据可视化而言,很难击败关联热图,但就数据而言,散点图无疑是最有用的可视化之一。
散点图是一种沿着两个轴“绘制”两个变量值的图表,如年龄和身高。散点图非常有用,原因有很多:像相关矩阵一样,它允许您快速了解两个变量之间的关系,它对于识别异常值非常有用,并且在多项式多元回归模型中非常有用(我们将在下一篇文章中讨论)。我用了**。plot()** 并将图形的“种类”设置为**散点图。**我还将 x 轴设置为“里程表”, y 轴设置为“价格”,因为我们想看看不同级别的里程如何影响价格。
df_cleaned.plot(kind='scatter', x='odometer', y='price')
这和相关矩阵讲述了同样的故事——里程表和价格之间存在负相关。散点图的巧妙之处在于,它传达的信息不仅仅是这些。你可以假设的另一个观点是里程对价格的影响是递减的。换句话说,一辆车在生命早期积累的里程数对价格的影响要比它在生命后期的影响大得多。你可以看到这一点,因为这些图一开始显示了一个陡峭的下降,但随着里程数的增加,下降幅度变小了。这就是为什么人们说买一辆全新的汽车不是一个好的投资!
df_cleaned.plot(kind='scatter', x='year', y='price')
再举一个例子,上面的散点图显示了年份和价格之间的关系——车越新,可能就越贵。
另外, sns.pairplot() 是在所有变量之间创建散点图的好方法。
sns.pairplot(df_cleaned)
柱状图
相关矩阵和散点图有助于探索两个变量之间的关系。但是如果你只想探索一个单独的变量呢?这就是直方图发挥作用的时候了。直方图看起来像条形图,但它们显示了一组变量的值的分布。
df_cleaned['odometer'].plot(kind='hist', bins=50, figsize=(12,6), facecolor='grey',edgecolor='black')df_cleaned['year'].plot(kind='hist', bins=20, figsize=(12,6), facecolor='grey',edgecolor='black')
df_cleaned['year'].plot(kind='hist', bins=20, figsize=(12,6), facecolor='grey',edgecolor='black')
我们可以很快注意到,普通汽车的里程表从 0 到刚刚超过 200,000 公里,一年大约从 2000 年到 2020 年。这两个图的区别在于“里程表”的分布是正偏的,而“年份”的分布是负偏的。偏斜度很重要,尤其是在金融等领域,因为许多模型都假设所有变量都是正态分布的,而事实通常并非如此。
箱线图
另一种可视化变量分布的方法是箱线图。这次我们以“价格”为例。
df_cleaned.boxplot('price')
箱线图不像上面显示的其他图表那样直观,但它以自己的方式传达了很多信息。下图解释了如何读取箱线图。很快,您可以看到价格上限中有许多异常值,并且大多数价格都在 0 到 40,000 美元之间。
根据数据集的不同,您还可以使用其他几种类型的可视化效果,如堆积条形图、面积图、小提琴图,甚至地理空间图。
通过探索性数据分析的三个步骤,您将对您的数据有一个更好的理解,这将使您更容易选择您的模型、您的属性并对其进行整体优化。
感谢阅读!
如果您喜欢这篇文章,请务必点击 订阅此处 或至我的 独家快讯 千万不要错过另一篇关于数据科学指南、技巧和提示、生活经验等的文章!
人工神经网络图解指南
带插图的分步人工神经网络教程
在当前时代,关于人工智能的研究发展非常迅速。生活的方方面面开始和这个名词结合。从金融领域开始到汽车领域,当然不会脱离 AI。
随着人工智能的发展,一种快速发展的方法是人工神经网络(ANN) 。从 AI 发展之初,到今天深度学习的发展,ANN 在其中都有一份。所以这种方法是对人工智能发展最有影响的方法之一也就不足为奇了。
但为什么这种方法对 AI 的发展影响如此之大?为什么这个术语如此流行?而什么是人工神经网络?在本文中,我们将回答这个问题。
什么是人工神经网络?
人工神经网络是人工智能的一个分支,它采用人脑的工作方式将刺激组合处理成输出。
人工神经网络的一个重要组成部分是神经元。像人脑由许多脑细胞组成一样,ANN 也由相互连接的神经元集合组成。在神经元内部,有刺激接收器、刺激处理器和输出部分。输出产生的信息可以传递给其他神经元。
人工神经网络很受欢迎,因为它可以解决用其他方法难以解决的复杂问题。这种方法也成为了发展深度学习的先行者,深度学习是机器学习的子领域之一,专注于具有多个深层结构的人工神经网络。如果你没有看过我关于深度学习的文章,可以查看下面的链接。
人工智能、机器学习和深度学习的简单解释以及它们之间的区别
towardsdatascience.com](/artificial-intelligence-machine-learning-and-deep-learning-what-the-difference-8b6367dad790)
人工神经网络的组成
正如上一节所解释的,人工神经网络有一部分叫做神经元。通常,ANN 有三个神经元,即输入神经元、隐藏神经元和输出神经元。
神经元
在隐藏神经元和输出神经元中,有一个函数用于从前一个神经元生成输出。这个函数称为激活函数。神经元的输出可以被传递,稍后将成为更多神经元的输入。
激活功能
人工神经网络的输出是一个值,它代表了被寻找的变量的预测。ANN 的下一个重要部分是重量。权重被用作将进入神经元的输入乘数。每个相互连接的神经元都有自己的权重。每个神经元都可以加上偏置,这是加到神经元输入上的常数。
另外,还有一层。一层由一个或多个神经元组成。人工神经网络有三层,即输入层、隐藏层和输出层。如果该结构只有输入层和输出层,则称为单层感知器。
单层感知器
同时,如果它在输入层和输出层之间至少有一层(隐藏层),那么它被称为多层感知器。
多层感知器
如果多层感知器有许多隐藏层,则称为深度神经网络。在本文中,我们只关注多层感知器(1 个隐藏层)。
深度神经网络
它是如何工作的?
如前所述,ANN 可以通过研究已经提供的数据模式来进行预测和分类。提供的数据越多,通过这种方法可以学习的模式就越多。一般来说,神经网络中常用的主要有两个过程,即前馈和反向传播。
前馈是基于输入值计算输出值的算法,而反向传播是基于从输出值获得的误差训练神经网络(改变权重)的算法。
神经网络中的学习过程从初始化权重值、学习速率和时期开始。我们还必须确定输入神经元、隐藏神经元和输出神经元的数量。Epoch 是 ANN 中的一个迭代。我们可以确定学习过程中的迭代次数,如果达到一定的迭代次数,学习过程就会停止。我们还可以确定最小误差值来停止学习过程。
学习率是决定学习速度的一个值,学习率的值越大,机器学习的速度越快,但将很难得到最优结果,反之,学习率越小,机器学习的速度越慢,但得到最优结果的可能性越大。
前馈
前馈
前馈过程集中于寻找已经用预定参数建立的系统的输出。这些产出的结果将与预定的目标进行比较。让我们看看下面的插图。
单层感知器
上图是一个使用单层感知器的例子。x1
和x2
是我们使用的输入数据,而w1
和w2
是权重。通常,权重值是随机确定的[-1…1]。计算输出的过程如下。
- 将权重乘以神经元的输入,然后将它们相加。
- 将权重与输入相乘的结果输入到激活函数中
比如我们有x1
和x2
的值分别是 1 和 0,w1
和w2
的值分别是 0.25 和 0.75。然后计算是这样的x1 * w1 + x2 * w2 = 1 * 0.25 + 0 * 0.75 = 0.25
。然后,将该值输入激活函数。我们将在这里使用的激活函数是 sigmoid 函数。通过使用 sigmoid 函数,结果是 0.56。
Sigmoid 函数
那么,如果结构由 3 层组成,即输入层、隐藏层和输出层,会怎样呢?基本一样。上述激活函数的值将是隐藏层的值,该值将被转发到输出层。更多细节,让我们看看下面的插图。
多层感知器
在我们获得输出层的值之后,下一个过程是从输出层获得误差值。该误差值稍后将成为改变权重值的参数。计算误差也有许多方法,如 MSE(均方误差)、SSE(误差平方和)等。
误差计算
反向传播
反向传播
反向传播侧重于更新和评估前馈中使用的参数(权重)。重量值将根据获得的误差值而改变。从Target value — output value
获得的误差值。
权重更新通常使用优化算法。人工神经网络中使用的优化算法各不相同,如 Adam(自适应矩估计)、RMSProp、梯度下降等。
关于反向传播计算的更多细节,你可以看来自 3Blue1Brown 的视频。
在我们更新了之前的权重之后,我们已经完成了一次迭代。下一步是通过重复前馈过程进入第二次迭代。这个过程将继续重复,直到我们之前指定的停止条件。
反向传播动画
接下来呢?
在训练过程被认为是充分的之后,ANN 模型可以用于分类过程。进行分类的方法类似于前馈过程,在前馈过程中,输入的数据将在人工神经网络中的神经元上通过权重乘法进行处理。这里的权重乘法与前馈的区别在于,所使用的权重是在训练过程中获得的最佳权重。当该过程在输出层时,获得的输出是每个神经元的十进制数,该十进制数将被转换成来自系统的预测类标签。
在看到 ANN 的结构和学习过程后,可能会产生许多问题。ANN 获得良好性能的最合适的结构是什么?还有哪些参数可以用来提高系统性能?所用神经元的最佳数量是多少?等等。如果我们对案例和数据集的结构和参数进行试错实验,所有这些问题都会得到解答。每个数据集将具有不同的最佳参数和结构。
本文是与 Naufal Dzaky Anwari 合作的成果,如果您会说印尼语并想阅读印尼语版本,请访问此链接。
Langkah kerja 人工神经网络
medium.com](https://medium.com/milooproject/panduan-bergambar-artificial-neural-network-53d3648f0c58)
遗传算法图解指南
一步一步的遗传算法教程,并附有插图
遗传算法
在之前的帖子中,我们讨论了什么是一般的人工智能 (AI)。如果我们只知道来自外部的信息,那么信息就不那么丰富了。所以在这篇文章中,我将更详细地介绍人工智能领域中存在的一种方法。
人工智能、机器学习和深度学习的简单解释以及它们之间的区别
towardsdatascience.com](/artificial-intelligence-machine-learning-and-deep-learning-what-the-difference-8b6367dad790)
在这个场合,我将讨论一个包含在人工智能领域的算法,即遗传算法。遗传算法是受生物进化和自然选择过程启发的**进化计算****【EC】**的一部分。
遗传算法通常用于克服优化和搜索问题。该算法是一种通用算法,因此它可以容易地在各种问题中实现,并且可以为搜索解的每次迭代提供更好的结果。遗传算法可以从范围广泛且具有许多最佳点的候选集合中找到最佳解决方案,并且与类似的方法如爬山、深度优先搜索等相比,结果往往会趋向于全局最优。
由于以下优点,遗传算法可用于解决许多情况。
- 由许多同时提出的预期解决方案组成
- 每次迭代都为更好的解决方案提供了一个候选方案
- 大的解空间不是问题
- 一种快速有效的算法
遗传算法术语
在我们进一步讨论之前,我们必须首先了解遗传算法中常用的术语。
群体、染色体、基因型和表型
- 人口,收集可能的解决方案。
- 染色体,一个可能的解决方案
- 基因型,染色体中包含的元素
- 表现型,基因型值
此外,该算法中还经常使用其他术语。
- 适应度函数,决定每个染色体权重的函数
- 适应值,从适应函数的结果中获得的值
- 解码和编码,在某些情况下,表现型可以改变为其他形式。例如二进制、实数、置换和整数。解码和编码就是把它从一种形式变成另一种形式的过程。
- 遗传算法过程中的迭代次数。
关于它的使用的更多细节和例子,我将在下一节解释。
遗传算法的阶段
在我们学习了遗传算法的优点和术语之后,现在我们将描述遗传算法产生解决方案的各个阶段。
在这里,我将概括地解释这些阶段。具体情况,也许我会在下一篇文章中解释。一般来说,遗传算法包括以下步骤。
初始化群体
遗传算法的初始阶段是初始化种群。在这个阶段,我们必须确定要使用的染色体的数量和长度。对于确定人口数量本身,没有规定数量。人口数量越多,产生的解就越多样,从而增加了获得最优解的可能性。
染色体长度的确定通常根据所处理的情况进行调整。例如,如果在函数f(x,y) = 5 * x — 10 * y
最大化的情况下,那么染色体的长度是 2,因为有两个变量,即我们要寻找的 x 和 y。另一个例子是,如果情况是旅行推销员问题(TSP) ,那么染色体的长度被调整为要访问的地方的数量。
此外,我们还必须确定要使用的染色体的表示法。有一些常用的表示法,如二进制、整数、浮点和置换表示法。根据待解决的案例调整代表性的确定。
表现
我们还必须确定这个遗传算法过程何时停止。常用的方法有 2 种,第一种是确定适应值上的阈值,第二种是确定代数。
此外,我们还必须确定交叉概率和变异概率的值。由于这个原因,它将随着过程被进一步解释。
适合度计算
初始化群体后,下一步是计算每个染色体的适应值。适应度函数可以变化,这取决于要解决的问题。例如,如果我们想找到函数f(x,y) = 5 * x — 10 * y
的最大值,那么计算的方法就是在函数中包含x
和y
的值。
选择
在获得所有适应值之后,然后选择父母。确定要选择的父对的数量,然后按照以下方式进行选择。有几种方法可以选择亲代染色体。
- 随机选择,一种从亲本中随机选择染色体对的方法,不受适应值的影响。更简单地说,它只需要生成随机值来选择索引作为父染色体。
- 锦标赛选择,这种选择方法根据体能值进行选择。选择首先显示一些随机值作为索引来选择几个准父母,然后用最佳适应值进行选择。
- 轮盘赌选择,这种选择方法的使用是基于每个染色体的概率。轮盘赌中染色体比例的大小会根据适应值而变化。通过从所有适合度的范围中提高一个随机值来进行选择。
轮盘赌选择
交叉
选好亲本后,下一步我们要做的就是做一个杂交。交叉是产生新染色体的过程。交叉是在两条染色体之间进行的,交叉的结果是两条染色体。
有两种确定新染色体的方法,即世代法和稳态法。
- 世代相传。使用这种方法,新染色体的数量与旧染色体的数量相同,在迭代结束时,旧群体被新群体取代。
- 稳态。与世代法不同的是,在稳态下,新染色体的数量与旧染色体的数量不一样,而是只有一条或两条。新的染色体将取代旧的染色体。
世代与稳定状态
如果你还记得,在初始化过程中,我们必须确定交叉的概率。这是概率的函数。该概率用于确定是否发生交叉。一般来说,使用的交叉概率是 0.8,但您可以自由确定概率,因为没有最佳概率的确定性。
我们必须生成从 0 到 1 的随机值,如果随机值小于或等于概率,则执行交叉。可以进行的交叉类型如下。
- 一点交叉。这种交叉将基因从一个染色体交换到另一个染色体,通过一个交叉点产生新的染色体。
单点交叉
- 多点交叉。这种交叉将基因从一个染色体交换到另一个染色体,通过几个交叉点产生新的染色体。
多点交叉
- 均匀交叉。这种交叉通过基于概率的每个索引将基因从一个染色体交换到另一个染色体。每个基因都有一个概率,就像硬币一样,例如,如果头出现了,那么它就被交换,如果尾出现了,基因的位置就保持不变。
均匀交叉
所有的切割点都是随机获得的。
变化
几乎与交叉相同,由于突变的概率,突变并不总是发生。通常使用的突变概率是 0.1。与交叉概率一样,对于变异概率的值没有明确的规定。
在这个过程中,突变改变了基因的表型(改变了基因的价值)。突变可以用一个点完成,也可以用多个点完成,也可以交换点。
- 一点突变
一点突变
- 多点突变
多点突变
- 互换突变
互换突变
幸存者选择
下一步是为下一次迭代获得另一个群体。一些不重要的染色体将被丢弃,并被经过交叉和变异过程的新染色体所取代。
在遗传算法的应用中,最好使用精英主义的原则,在这个过程中总是存储最好的染色体,以便总是有适应度最高的染色体。如果新的染色体组合看起来更好,那么先前存储的一条染色体与新的染色体交换。
确定新种群后,接下来的过程就是计算新种群的适应度值。这将继续重复,直到满足终止条件。如前所述,通常使用的终止条件是使用阈值适应值或确定最大代数。
如果进程已经停止,那么这个遗传算法的解就是适应值最大的染色体。
零膨胀泊松回归模型图解指南
另外还有一个 Python 教程,介绍如何在有多余零的数据集上训练 ZIP 模型
在本文中,我们将学习如何为基于计数的数据集构建回归模型,其中因变量包含过量的零值数据。
计数数据集是因变量为事件的数据集,例如:
- 每小时通过十字路口的车辆数量。
- 每月急诊室就诊次数
- 每年提出的机动车辆保险索赔数量
- 在大量生产的印刷电路板中发现的缺陷数量。
包含许多零计数的数据集(图片由作者提供)
许多真实世界的现象产生的计数几乎总是零。例如:
- 机器每月发生故障的次数
- 每年发现的系外行星数量
- 生活在世界上每一个城市的亿万富翁的数量。
使用传统的计数数据模型,如二项式 或 负二项式 回归模型,很难处理这些数据。
这是因为此类数据集包含的零值计数数量比使用传统模型的概率分布预期观察到的数量多。
例如,如果您假设一个现象遵循以下泊松(5) 过程,您将期望看到零计数不超过 0.67%的时间:
泊松(5)过程将在大约 0.67%的观测值中产生零(图片由作者提供)
如果您观察到的零计数远远多于这个数,那么数据集包含了过多的零。
如果对这样的数据集使用标准的泊松或二项式或 NB 回归模型,它可能拟合得很差,并且会生成质量很差的预测,无论您对其参数做了多少调整。
那么,面对这种带有多余零的数据,建模者该怎么办呢?
零膨胀泊松回归模型
幸运的是,有一种方法可以修改标准计数模型,如泊松或负二项式模型,以解释额外零的存在。事实上,至少有两种方法可以做到这一点。一种技术被称为跨栏模式**,第二种技术被称为零充气模式。**
在本文中,我们将详细研究零膨胀回归模型。具体来说,我们将关注零膨胀泊松回归模型**,通常被称为 ZIP 模型。**
ZIP 模型的结构
在了解如何修改常规泊松模型的结构以处理过多的零计数之前,让我们先简要了解一下它的结构。
想象一个数据集,包含 n 个样本和 p 个样本的回归变量。因此,回归变量可以用一个大小为(n×p)的矩阵来表示, X 矩阵中的每一行 x_i 都是一个大小为(1×p)的向量,对应于因变量值 y_i :
矩阵符号中的数据集( y,X )(图片由作者提供)
如果我们假设 y 是一个泊松分布的随机变量,我们可以为这个数据集建立一个泊松回归模型。泊松模型由两部分组成:
- 泊松 P 概率 M ass F 函数(PMF)表示为 P(y_i=k) 用于计算在给定λ事件/单位时间的平均事件率的情况下,在任何单位间隔内观察到 k 事件的概率。
- 用于将平均速率λ 表示为回归变量 X 的函数的链接函数。
下图对此进行了说明:
标准泊松回归模型的概率质量函数(图片由作者提供)
通常,我们假设有一些潜在的过程按照泊松 PMF: P(y_i=k) 产生观察到的计数。
零膨胀泊松模型背后的直觉是 存在第二个潜在过程,该过程确定计数是零还是非零 。一旦计数被确定为非零,常规泊松过程就会根据泊松过程的 PMF 来确定其实际非零值。
因此, ZIP 回归模型由三部分组成:
- PMF P(y_i=0) 用于计算观察到零计数的概率。
- 第二个 PMF P(y_i=k) ,用于计算观察到 k 事件的概率,给定 k > 0 。
- 用于将平均速率λ 表示为回归变量 X 的函数的链接函数。
下图对此进行了说明:
ZIP 模型的概率质量函数(图片由作者提供)
如前所述, y_i 是随机变量,表示对应于回归变量行x _ I****=【x _ i1,x_i2,x_i3,…,x_ip】的观察计数。****
ϕ_i 是数据集中第 I 行(y _ I,x_i)*** 对应的多余零的比例的度量;。***
了解ϕ_i
理解 ϕ_i 的简单方法如下:
假设你取 y_i 的 1000 个观测值,每一个都与 相同 组合的回归变量值x _ I****=【x _ i1,x_i2,x_i3,…,x_ip】。由于 y_i 是一个遵循泊松分布的随机变量*,你可能会在 1000 次观察的每一次中看到不同的 y_i 值。***
假设在你观察到的 1000 个 y_i 值中,你观察到 874 个零值。您确定在这 874 个零值中,您为 y_i 假设的常规泊松分布将只能解释最多 7 个零值。所以剩下的 867 个零值是多余的零观测值。所以对于数据集中的第行和第行, ϕ_i =867/1000 = 0.867。**
当数据集在因变量中没有任何多余的零时,【ϕ】的值计算出为零,并且 ZIP 模型的 PMF 减少到标准泊松模型的 PMF(您可以通过将 ZIP 模型的 PMF 中的设置为 0 来轻松验证这一点)。**
如何估计 ϕ?
那么我们如何估算ϕ_i 的价值呢?
估算 ϕ_i 的一种简单而粗略的方法是将每个【ϕ】_ I设定为以下比率:**
一种简单但不准确的方法来估计_ I(图片由作者)**
也许计算 ϕ_i 的一种更现实的方法是将其作为回归变量 X 的函数进行估计。这通常是通过将 y 变量转换为二进制 0/1 随机变量y’(y _ prime)来完成的,如果底层的为 0,则取值为 0,在所有其他情况下取值为 1。然后我们在转换后的y’上拟合一个逻辑回归模型。然后,我们在数据集[ X,y’ ]上训练逻辑回归模型,并且它产生拟合概率的向量*_ 拟合的*** =[ _1,_2,_3,…,_n],(因为这就是逻辑回归模型所做的)。******
一旦我们得到了_ 拟合的* 矢量,我们就简单地把它设置为 矢量ϕ.*****
从而【ϕ_1= _1,ϕ_2= _2,ϕ_3= _3,…,ϕ_n= _ n】。
以上估算 ϕ 的过程如下图 :
估计多余零点参数 ϕ 的训练序列(图片由作者)
一旦估算出了向量,我们就将它插入到 ZIP 模型的概率函数中,并使用所谓的 M 最大值 L 似然性 E 估计( MLE )技术来训练具有超额计数的数据集上的 ZIP 模型。
****Please see my article on [**Poisson Regression Model**](/an-illustrated-guide-to-the-poisson-regression-model-50cccba15958) for an explanation of how **MLE** works.****
下图说明了 ZIP 模型的训练顺序:
ZIP 模型的训练序列(图片由作者提供)
令人欣慰的是,有许多统计软件包可以自动完成估算ϕ的整个过程,并使用估算的ϕ在数据集上使用 MLE 技术训练 ZIP 模型。****
在本文的其余部分,我们将使用 Python statsmodels 库在一行代码中构建和训练一个 ZIP 模型。
如何使用 Python 训练 ZIP 模型
在我们关于 ZIP 模型的 Python 教程中,我们将使用 250 组人进行的野营旅行的数据集:
野营旅行数据集(图片由作者提供)
数据集在这里可用。以下是该数据集的几个显著特征:
- 露营者在旅途中可能会也可能不会去钓鱼。
- 如果一群人去钓鱼,他们可能没有或没有钓到鱼。
- 我们不仅要估计捕获了多少鱼(如果野营小组进行了捕鱼),还要估计野营小组捕获任何鱼的概率。
因此,这里涉及两个不同的数据生成过程:
- 一个决定一个野营团体是否沉迷于一个成功的捕鱼活动的过程:ZIP 模型将在内部使用一个逻辑回归模型,该模型在前面已经解释过,用于模拟这个二元过程。
- 第二个过程是确定一个野营小组捕获了多少条鱼,假设该小组至少捕获了一条鱼:ZIP 模型将使用常规泊松模型来建模第二个过程。
数据集中的变量
野营旅行数据集包含以下变量:
被捕获的鱼的数量。这将是我们的因变量 y 。
LIVE_BAIT: 表示是否使用了活诱饵的二元变量。
****露营车:钓鱼团是否使用露营车。
****人数:钓鱼组总人数。注意,在一些群体中,他们可能都没有捕鱼。
****孩子:露营组的孩子数量。
以下是因变量 FISH_COUNT 的频率分布:
FISH_COUNT 的频率分布(图片由作者
正如我们所看到的,在这个数据集中可能有多余的零。我们将在这个数据集上训练一个 ZIP 模型来测试这个理论,并有望实现比常规泊松模型更好的拟合。
回归目标
我们对该数据集的回归目标如下:
根据 LIVE_BAIT、CAMPER、PERSONS 和 CHILDREN 变量的值,预测野营小组捕获的鱼的数量(FISH_COUNT)。
回归策略
我们的回归策略如下:
- FISH_COUNT 将是因变量 y ,【LIVE_BAIT,CAMPER,PERSONS,CHILDREN】将是解释变量 X 。
- 我们将使用 Python statsmodels 库 在( y,X )数据集上训练 ZIP 回归模型。
- 我们将使用 ZIP 模型对模型在其训练期间未见过的测试数据集进行一些预测。
让我们从导入所有需要的包开始:
*****import** pandas **as** pd
**from** patsy **import** dmatrices
**import** numpy **as** np
**import** statsmodels.api **as** sm
**import** matplotlib.pyplot **as** plt***
接下来,我们将把 fish 数据集加载到内存中。这里是数据集的链接:
***df = pd.read_csv(**'fish.csv'**, header=0)***
让我们打印数据集的前几行:
***print(df.**head**(10))***
数据集的前 10 行(图片由作者提供)
让我们也打印出 FISH_COUNT 值的频率分布:
***df.**groupby**('FISH_COUNT').**count**()***
鱼类数量的频率分布(图片由作者提供)
创建训练和测试数据集。请注意,目前我们没有进行分层随机分割:
***mask = np.random.**rand**(len(df)) < 0.8
df_train = df[mask]
df_test = df[~mask]
print(**'Training data set length='**+str(len(df_train)))
print(**'Testing data set length='**+str(len(df_test)))>> Training data set length=196
>> Testing data set length=54***
在Patsy符号中设置回归表达式。我们告诉 Patsy,FISH_COUNT 是我们的因变量 y ,它取决于回归变量 LIVE_BAIT、CAMPER、PERSONS 和 CHILDREN:
*****expr = **'FISH_COUNT ~ LIVE_BAIT + CAMPER + CHILDREN + PERSONS'*******
让我们使用 Patsy 为训练和测试数据集绘制出 X 和 y 矩阵。
*****y_train, X_train = **dmatrices**(expr, df_train, return_type=**'dataframe'**)y_test, X_test = **dmatrices**(expr, df_test, return_type=**'dataframe'**)*****
使用 statsmodels 的ZeroInflatedPoisson类,我们在训练数据集上构建并训练一个 ZIP 回归模型。
但是在我们这样做之前,让我解释一下如何使用类构造函数的两个参数:
- **膨胀:zeroinflatedpoisson模型类将在内部使用一个逻辑回归模型来估计参数 ϕ 。因此,我们将模型参数膨胀设置为‘logit’。我们还可以尝试将它设置为其他二项式链接函数,如“probit”。
- exog_infl: 我们还想请 ZIP 模型估计 ϕ 作为与母模型相同的一组回归变量的函数,即:LIVE_BAIT、CAMPER、PERSONS 和 CHILDREN。因此,我们将参数 exog_infl 设置为 X_train。如果您只想使用 X_train 的一个子集,您可以这样做,或者您可以将 exog_infl 设置为一组完全不同的回归变量。
下面一行代码在我们的训练数据集上构建和训练 ZIP 模型。
*****zip_training_results = **sm**.**ZeroInflatedPoisson**(***endog****=*y_train, ***exog****=*X_train, ***exog_infl****=*X_train, ***inflation****=*'logit').**fit**()*****
打印培训总结:
*****print(zip_training_results.**summary**())*****
以下是培训总结(我在输出中突出显示了重要元素):
ZIP 模型的训练总结(图片由作者提供)
解释培训输出
蓝框包含嵌套逻辑回归模型用来估计野营小组是否捕获任何鱼的概率【ϕ】的变量信息。
(图片由作者提供)
**注意,逻辑回归模型没有发现对估计ϕ有用的截距、LIVE_BAIT 和 CAMPER 变量。发现它们的回归系数在 95%的置信水平下不具有统计显著性,如各自的 p 值所示:
inflate _ Intercept =0.425,
inflate _ LIVE _ BAIT =0.680和
inflate _ CAMPER =0
观察结果 1
逻辑回归模型确定对估计是否有鱼被捕获的概率有用的唯一两个变量是儿童和人。
观察 2
人的回归系数为负(inflate _ PERSONS-1.2193),这意味着随着野营组人数的增加,该组没有鱼被捕获的概率降低。这符合我们的直觉。****
红框包含关于父泊松模型在 FISH_COUNT > 0 的条件下用于估计 FISH_COUNT 的变量的信息。
(图片由作者提供)
观察结果 3
我们可以看到,所有 5 个回归变量的系数在 99%的置信水平下具有统计显著性,正如它们的 p 值小于 0.01 所证明的那样。事实上,所有 5 个变量的 p 值都小于 0.001,因此显示为 0.000。
观察结果 4
儿童的系数为负(儿童-1.0810),这意味着随着野营组中儿童数量的增加,该组捕获的鱼的数量减少!
观察 5
该模型的最大对数似然为-566.43。这个值对于比较模型与其他模型的拟合优度很有用(见文末的趣味练习)。
观察 6
最后,请注意,ZIP 模型的训练算法无法收敛于训练数据集,如下所示:
(图片由作者提供)
如果它已经收敛,也许它会导致一个更好的拟合。
预测
我们将获得 ZIP 模型对测试数据集的预测,并计算均方根误差 w.r.t .实际值:
*****zip_predictions = zip_training_results.predict(X_test,exog_infl=X_test)predicted_counts=np.round(zip_predictions)actual_counts = y_test[dep_var]
print(**'ZIP RMSE='**+str(np.sqrt(np.sum(np.power(np.subtract(predicted_counts,actual_counts),2)))))>> **ZIP RMSE=**55.65069631190611*****
让我们绘制预测的和实际的鱼数量:
*****fig = plt.figure()fig.suptitle(**'Predicted versus actual counts using the ZIP model'**)predicted, = plt.plot(X_test.index, predicted_counts, **'go-'**, label=**'Predicted'**)actual, = plt.plot(X_test.index, actual_counts, **'ro-'**, label=**'Actual'**)plt.legend(handles=[predicted, actual])plt.show()*****
我们看到下面的情节:
预测与实际捕获的鱼(图片由作者提供)
这就完成了我们对零膨胀泊松回归模型的研究。
有趣的练习
- 阅读以下文章:泊松回归模型图解指南
- 使用 Python 和 statsmodels,在露营旅行数据集上训练标准泊松模型,并将该模型的性能与 ZIP 模型的性能进行比较。你可能会对你的发现感到惊讶。
- 使用 statsmodels 在两个模型的训练摘要中报告的最大对数似然值,比较两个模型在训练数据集上的拟合优度。最大 L1 越大,拟合优度越好。
- 在测试数据集上比较两个模型的 RMSE 分数。
快乐造型!
建议进一步阅读的主题
- 泊松过程:你需要知道的一切
- 泊松分布公式的直觉
- 泊松回归模型图解指南
- 真实世界数据集的广义泊松模型
- 负二项回归模型:逐步指南
- A. Colin Cameron 和 Pravin K. Trivedi,计数数据的回归分析
- Lambert,D. (1992),零膨胀泊松回归及其在制造缺陷中的应用,《技术计量学》,34,1–14。
感谢阅读!我写关于数据科学的主题,特别关注回归和时间序列分析。
如果您喜欢这篇文章,请关注我的Sachin Date以获得关于回归和时间序列分析主题的提示、操作方法和编程建议。
动态时间弯曲的说明性介绍
入门
+背后的数学
D 动态时间扭曲(DTW)是一种比较两个不完全同步的时间序列的方法。它是一种计算两个序列之间最佳匹配的方法。DTW 在许多领域都很有用,如语音识别、数据挖掘、金融市场等。测量两个时间序列之间的距离是数据挖掘中常用的方法。
在这篇文章中,我们将回顾 DTW 背后的数学。然后,提供两个说明性的例子来更好地理解这个概念。如果你对背后的数学不感兴趣,请跳到例子。
制定
假设我们有如下两个序列:
𝑋=𝑥[1],𝑥[2],…,x[i],…,x[n]
Y=y[1],y[2],…,y[j],…,y[m]
序列𝑋和𝑌可以被排列以形成𝑛-by-𝑚网格,其中每个点(𝑖,j)是𝑥[𝑖]和𝑦[𝑗].之间的比对
扭曲路径𝑊映射𝑋和𝑌的元素,以最小化它们之间的距离。𝑊是一系列网格点(𝑖,𝑗).稍后我们将看到一个弯曲路径的例子。
弯曲路径和 DTW 距离
到(𝑗_𝑘𝑖_𝑘)的最佳路径可以通过下式计算:
其中𝑑是欧几里德距离。然后,总路径开销可以计算如下
扭曲函数的限制
使用动态编程方法来比对两个序列,从而找到扭曲路径。遍历所有可能的路径是“组合爆炸”[1]。因此,为了提高效率,限制可能的扭曲路径的数量很重要,因此列出了以下约束条件:
- 边界条件:该约束确保弯曲路径从两个信号的起点开始,到它们的终点结束。
- 单调性条件:该约束保持了点的时间顺序(不及时返回)。
- 连续性(步长)条件:该约束将路径过渡限制到相邻的时间点(不是时间跳跃)。
除了上述三个约束条件之外,对于允许的翘曲路径,还有其他不太常见的条件:
- 扭曲窗口条件:允许的点可以被限制在宽度为𝜔(正整数)的给定扭曲窗口内。
- 坡度条件:可通过限制坡度来约束翘曲路径,从而避免在一个方向上的极端移动。
一个可接受的扭曲路径有以下棋王走法的组合:
- 水平移动:(𝑖,𝑗) → (𝑖,𝑗+1)
- 垂直移动:(𝑖,𝑗) → (𝑖+1,𝑗)
- 对角线移动:(𝑖,𝑗) → (𝑖+1,𝑗+1)
履行
让我们导入所有需要的 python 包。
import pandas as pd
import numpy as np# Plotting Packages
import matplotlib.pyplot as plt
import seaborn as sbn# Configuring Matplotlib
import matplotlib as mpl
mpl.rcParams['figure.dpi'] = 300
savefig_options = dict(format="png", dpi=300, bbox_inches="tight")# Computation packages
from scipy.spatial.distance import euclidean
from fastdtw import fastdtw
让我们定义一种方法来计算弯曲路径的累积成本矩阵 D 。成本矩阵使用欧几里德距离来计算每两点之间的距离。计算欧几里得距离矩阵和累积成本矩阵的方法定义如下:
示例 1
在这个例子中,我们有两个长度不同的序列 x 和 y 。
# Create two sequences
x = [3, 1, 2, 2, 1]
y = [2, 0, 0, 3, 3, 1, 0]
我们无法计算出 x 和 y 之间的欧几里德距离,因为它们的长度不相等。
例 1:x与 y 的欧氏距离(可能吗?🤔)(图片由作者提供)
计算 DTW 距离和扭曲路径
许多 Python 包仅通过提供序列和距离类型(通常为欧几里得距离)来计算 DTW。这里,我们使用 DTW 的一个流行的 Python 实现,即 FastDTW ,它是一个近似的 DTW 算法,具有更低的时间和内存复杂度[2]。
dtw_distance, warp_path = fastdtw(x, y, dist=euclidean)
注意,我们使用的是我们之前导入的 SciPy 的距离函数 Euclidean 。为了更好地理解扭曲路径,让我们首先计算累积成本矩阵,然后在网格上可视化路径。以下代码将绘制累计成本矩阵的热图。
cost_matrix = compute_accumulated_cost_matrix(x, y)
示例 1:绘制(并保存)累计成本矩阵热图的 Python 代码
示例 1:累积成本矩阵和扭曲路径(图片由作者提供)
颜色条显示网格中每个点的成本。可以看出,扭曲路径(蓝线)在网格上的成本最低。让我们通过打印这两个变量来看看 DTW 距离和弯曲路径。
>>> DTW distance: 6.0
>>> Warp path: [(0, 0), (1, 1), (1, 2), (2, 3), (3, 4), (4, 5), (4, 6)]
扭曲路径从点(0,0)开始,经过 6 次移动后在点(4,6)结束。让我们使用之前定义的函数来计算累积成本 most,并将这些值与热图进行比较。
cost_matrix = compute_accumulated_cost_matrix(x, y)
print(np.flipud(cost_matrix)) # Flipping the cost matrix for easier comparison with heatmap values!>>> [[32\. 12\. 10\. 10\. 6.]
[23\. 11\. 6\. 6\. 5.]
[19\. 11\. 5\. 5\. 9.]
[19\. 7\. 4\. 5\. 8.]
[19\. 3\. 6\. 10\. 4.]
[10\. 2\. 6\. 6\. 3.]
[ 1\. 2\. 2\. 2\. 3.]]
上面打印的成本矩阵具有与热图相似的值。
现在让我们绘制两个序列,并连接映射点。绘制 x 和 y 之间的 DTW 距离的代码如下所示。
示例 1:绘制(并保存)x 和 y 之间的 DTW 距离的 Python 代码
示例 1:x和 y 之间的 DTW 距离(图片由作者提供)
示例 2
在本例中,我们将使用两个正弦信号,并通过计算它们之间的 DTW 距离来了解它们是如何匹配的。
示例 2:生成两个不同长度的正弦信号(x1 和 x2)
与示例 1 一样,让我们使用 FastDTW 软件包计算 x1 和 x2 信号的 DTW 距离和弯曲路径。
distance, warp_path = fastdtw(x1, x2, dist=euclidean)
示例 2:绘制(并保存)x1 和 x2 之间的 DTW 距离的 Python 代码
示例 2:x1 和 x2 之间的 DTW 距离(图片由作者提供)
从上图可以看出,当两个信号具有相似的模式时,这两个信号之间的 DTW 距离特别大。两个信号之间的极值(最大和最小点)被正确映射。此外,与欧几里德距离不同,当使用 DTW 距离时,我们可以看到多对一映射,特别是如果两个信号具有不同的长度。
您可能会从上图中发现动态时间扭曲的问题。你能猜出它是什么吗?
问题在于时间序列的首尾不匹配。这是因为 DTW 算法不能承受端点处的翘曲不变性。简而言之,其效果是序列终点的微小差异将倾向于对估计的相似性做出不成比例的贡献[3]。
结论
DTW 是一种寻找两个序列之间最佳比对的算法,也是我们工具箱中有用的距离度量。当我们处理两个非线性序列时,这种技术很有用,特别是当一个序列是另一个序列的非线性拉伸/收缩版本时。扭曲路径是“棋王”移动的组合,从两个序列的头部开始,以它们的尾部结束。
你可以在这里找到这篇博文的笔记本。感谢阅读!
参考
[1] Donald J. Berndt 和 James Clifford,利用动态时间弯曲发现时间序列中的模式,第三届知识发现和数据挖掘国际会议
[2] Salvador,S. and P. Chan, FastDTW:走向线性时空中的精确动态时间弯曲 (2007),智能数据分析
[3]迭戈·费塔多·希尔瓦,等人,,关于端点对动态时间扭曲的影响 (2016),SIGKDD 关于时间序列挖掘和学习的研讨会
有用的链接
[1]https://nipunbatra.github.io/blog/ml/2014/05/01/dtw.html
[2]https://databricks . com/blog/2019/04/30/understanding-dynamic-time-warping . html
一个不可能的 AI 挑战?
弗朗索瓦·乔莱正在寻找一只独角兽
从 Adobe Stock 获得许可的图像
一场 抽象与推理挑战赛是由弗朗索瓦·乔莱主持的一场刚刚发布的卡格尔比赛的标题。副标题为“创造一个能够解决它从未见过的推理任务的人工智能”,这是为那些真正致力于推进人工智能的人准备的。简而言之,问题是这样的:
给你 3 到 5 个由彩色方块组成的输入网格,对于每个输入网格,都有一个相应的由彩色方块组成的“解决方案”网格。输入和输出格网的总面积可以是 1 到 30 平方。通过分析集合中的每个输入和输出,确定解决方案是如何导出的,然后将其应用于隐藏了“解决方案”的测试网格。
例如,下图左侧是三个大小不同的网格,其中红色方块的行为就像一个物体从左向右移动时在顶部和底部之间弹跳。在右边的“解决方案”网格中,看起来该过程是首先将左下方相邻的黑色方块改变为黄色,然后在红色方块与顶部或底部的“碰撞”之后,立即将每个相邻的黑色方块组改变为黄色,当这样的碰撞方块不与已经改变为黄色的方块相邻时。
通过 Jupyter 笔记本创建的图像此处
上面的例子有 3 对输入和输出,每个集合(输入和输出)在网格中有不同数量的方块,但是每个输入和输出对有相同数量的方块。
这是另一个例子,有 4 个输入/输出对:
通过 Jupyter 笔记本创建的图像此处
在本例中,左侧的每个输入网格有 9 个方块,而其对应的输出网格有 36 个方块。输入格网被复制 4 次以形成输出格网,但是在输入格网被放置在输出格网的 4 个角中的 3 个角之前,输入格网有一些“翻转”。以下是解决方案中发生的情况:
- 左上部分复制了输入网格
- 右上部分沿垂直轴反映输入网格
- 左下部分沿水平轴反映输入网格
- 右下角反映了水平轴和垂直轴(或对角线)上的输入网格。
从输入创建输出有几种方法,但是在每种情况下,都需要相同的转换步骤。
设计一个能够“理解”这些转变的人工智能模型,以这种方式将这种“智能”应用于一种新的、前所未见的转变,是非常困难的。
我期待着关注这场比赛,并看到世界各地的个人和团队如何试图创建能够取得某种程度成功的人工智能系统。
我乐观地认为,人工智能将越来越多地被用来让我们所有人的生活变得更好。您是否面临数据科学问题/挑战?我很乐意帮忙;我们连线吧!
感谢阅读!
对全球新冠肺炎疫情进行深入分析
使用这些工具掌握数据可视化
新冠肺炎疫情在全球范围内相比如何?
我最近发表了一篇文章,探讨了约翰·霍普斯金大学最近在新冠肺炎发布的数据;虽然我们能够做出一些有趣的发现,但收集数据提供更全面的情况似乎是恰当的。
亲自访问此页面获取数据:https://www.tableau.com/covid-19-coronavirus-data-resources
让我们立即开始一些基本的探索性数据分析。
数据熟悉
下载下来拉进来!
covid_tab <- read.csv('covid_tableau.csv')
让我们看看如何使用head
功能!
head(covid_tab)
我在这里的第一个要求是,这是在日期、国家、省、案例类型级别上构建的。类似于 JHU 的数据,但有一个关键的区别。这就是案件类型。如果我们能够了解在任何给定的地点和时间的活动、死亡和恢复的分类,这对我们评估情况及其进展有很大帮助。
您还会注意到,差异列表示每种案例类型每天的变化,而案例是当前的总数。
glimpse(covid_tab)
Glimpse 还提供了数据集维度、数据类型、样本等的一些上下文。
summary(covid_tab)
这根据数据类型给出了一些有趣的统计数据。数值的范畴、最小值、最大值、四分位数、平均值、中值的出现次数。
另一个快速注意事项是,我发现案例类型有以下值:
我想了解活动、死亡和恢复加起来是否等于确认,它们是否相互排斥,或者这些不同的值将如何被利用。
covid_tab %>% group_by(Country_Region, Case_Type ) %>% summarise(max(Cases))
按国家/地区和案例类型分组,因为我知道案例是累积的,所以我只取了最大值,并评估了它们是如何累加的。
看看这个样本!
以阿富汗和阿尔巴尼亚为例,您可以看到活动、死亡和康复加起来就是确诊。
睁大你的眼睛!
在我们继续之前,有一个小提示,您可能已经注意到,当我们运行glimpse
时,Date
列作为一个因素被调用。
为什么这是一个问题?
因为任何可视化都会把因子值当作字符串,并相应地排序。
看看下面的图表。我们所看到的中间的大幅下降实际上代表了这个月的前几天。
使用像这样的基本命令来清理它。注意你需要使用的格式。我不会在这里深究,但是让函数知道数据“来自”哪里是很重要的。
covid_tab$Date <- as.Date(covid_tab$Date, format = "%m/%d/%Y")
如果我们现在再次运行该命令,我们会得到以下结果
作为探索性数据分析的一部分,还可以经历许多其他步骤;与其在这里继续,我们将深入一些数据可视化。
可视化趋势、模式和关系!
一次一个开始
现在我们对数据有了一个很好的理解
跳进…我刚刚在上面展示了这个,但是我将展示我们如何到达那里。
在这里,我们希望看到所有累计确诊病例。
我采用数据框架,过滤“已确认”病例,按日期分组,按病例汇总,并创建一个条形图。
covid_tab %>% filter(Case_Type == 'Confirmed')%>%
group_by(Date) %>%
summarise(Cases = sum(Cases))%>%
ggplot(aes(x = Date, y = Cases))+ geom_bar(stat = 'identity')+
theme(axis.text.x = element_text(angle = 45))
然后,我们可以针对每种案例类型再次执行此操作。对于探索性的数据分析过程来说,这通常很有意义。
covid_tab %>%
filter(Case_Type == 'Deaths')%>%
group_by(Date)%>%
summarise(Deaths = sum(Cases))%>% ggplot(aes(x = Date, y =
Deaths))+
geom_bar(stat = 'identity')+ theme(axis.text.x = element_text(angle
= 45))
类似地,我们可以这样做来表示死亡的每日变化,只是通过按Difference
字段汇总死亡来代替。
covid_tab %>%
filter(Case_Type == 'Deaths')%>%
group_by(Date)%>%
summarise(Deaths = sum(Difference))%>%
ggplot(aes(x = Date, y = Deaths))+
geom_bar(stat = 'identity')+
theme(axis.text.x = element_text(angle = 45))
可视化多个变量
案例、国家和案例类型之间有什么关系?
类似于我们上面创建的,下面我们做同样的事情,现在按他们的Case_Type
分解总数。
正如你在我的代码中看到的,我已经从Case_Type
中删除了所有出现的‘确认’一词。我想我们可以包括它,它看起来就像一个求和条,紧挨着更多的粒度条。
covid_tab %>%
filter(!grepl('Confirmed', Case_Type)) %>%
group_by(Date, Case_Type) %>%
summarise(Cases = sum(Cases))%>%
ggplot(aes(x = Date, y = Cases, fill = Case_Type))+
geom_bar(stat = 'identity')+
theme(axis.text.x = element_text(angle = 45))
虽然这种观点是好的,但我实际上更喜欢包括位置参数“道奇”。那么这个图表在 case_type 的不同值之间看起来会更有可比性。
covid_tab %>%
filter(!grepl('Confirmed', Case_Type))%>%
group_by(Date, Case_Type)%>%
summarise(Cases = sum(Cases))%>%
ggplot(aes(x = Date, y = Cases, fill = Case_Type))+
geom_bar(stat = 'identity', position = 'dodge')+
theme(axis.text.x = element_text(angle = 45))
现在,我们对这些数字每天的变化有了更好的了解。我们看到 3 月初活跃案例大幅下降,上周左右又有所回升。
恢复的案例持续增长,甚至超过了总活跃案例,几周后再次领先。
每日差异情况
我们在这里看到的是,活跃病例的新发生率在 2 月底大幅下降,但随后在 3 月中旬大幅上升。
covid_tab %>%
filter(!grepl('Confirmed', Case_Type))%>%
group_by(Date, Case_Type)%>%
summarise(Difference = sum(Difference))%>%
ggplot(aes(x = Date, y = Difference, fill = Case_Type))+
geom_bar(stat = 'identity')+
theme(axis.text.x = element_text(angle = 45))
应该有助于更好地告知这是从哪里来的是通过地理变量打破这一点。我们将从国家级开始,然后再看看省级。
深入了解国家和案例类型
这段代码需要解释一些事情。RStudio 中的图例被夸大了,因为该数据集中包含了 100 多个国家。所以我创建了国家总数,在给定的时间内取最高的病例数。然后,我将它加入到我们一直使用的熟悉的命令中,并使用它来过滤出没有达到给定病例数的国家,这给了我们最高的 16 个左右的国家。
在那里,我们创建一个类似的可视化,这次用 country 替换 case type。我们可以将多个类别合并到我们的可视化中,但我们将把它留到以后。
country_totals <- covid_tab %>%
group_by(Country_Region)%>%
summarise(max_cases = max(Cases)) covid_tab %>%
left_join(country_totals, by = 'Country_Region')%>%
filter(grepl('Confirmed', Case_Type) & max_cases >= 1000)%>%
group_by(Date, Case_Type, Country_Region)%>%
summarise(Cases = sum(Cases))%>%
ggplot(aes(x = Date, y = Cases, fill = Country_Region))+
geom_bar(stat = 'identity')+
theme(axis.text.x = element_text(angle = 45))
正如你所猜测的,你可以看到中国在大部分疫情中占主导地位,意大利自 2 月下旬以来出现。
现在让我们用每日差异来检查一下。在这里,我们看到的是活动案例数量的每日变化。
covid_tab %>%
left_join(country_totals, by = 'Country_Region')%>%
filter(grepl('Active', Case_Type) & max_cases >= 1000 & Date >
'2 020-02-15')%>%
group_by(Date, Case_Type, Country_Region)%>%
summarise(Difference = sum(Difference))%>%
ggplot(aes(x = Date, y = Difference, fill = Country_Region))+
geom_bar(stat = 'identity', position = 'dodge')+
theme(axis.text.x = element_text(angle = 45))
这产生了一个有趣的一瞥,让我们了解在任一方向上给定时间的变化强度。
包含多个类别
刻面
这不是最漂亮的视觉效果,因为在下面的分面图中,国家有很多级别,每个窗格的体积也不一样。也就是说,打破这种多分类变量可以提供一个有趣的视角。
与前面的命令类似,这里我们在底部添加了 facet_wrap 命令,这使得我们将图表分成不同的窗格,以显示包含的分类变量的每个值。
covid_tab%>%
left_join(country_totals, by = 'Country_Region')%>%
filter(!grepl('Confirmed', Case_Type) & max_cases >= 1000 & Date >
'2020-02-15') %>% group_by(Date, Case_Type, Country_Region) %>%
summarise(Cases = sum(Cases))%>% ggplot(aes(x = Date, y = Cases,
fill = Country_Region))+ geom_bar(stat = 'identity', position =
'dodge')+ theme(axis.text.x = element_text(angle = 45))+
facet_wrap(~Case_Type)
在活跃窗格中,我们可以看到中国的活跃数量明显下降,而意大利在上周的大多数情况下迅速上升,超过了中国。
对于死亡,我们可以通过这个时间窗口看到中国保持静止,而意大利在增长。
由于明显滞后于中国的爆发,其他国家仍比其复苏曲线晚几天或几周。
没有中国
我们可以做同样的事情,只是排除中国,以更好地了解疫情更为流行的相对情况。
让我们仔细看看
这里有趣的是我们在第一个窗格中看到的。关注的不是数量,而是任何一个国家的曲线形状。
虽然我们看到一些指数增长,相反,韩国经历了这种对称分布;病例上升的速度几乎和病例下降的速度一样快。
让我们按国家分面
我们现在将把这张图表分成几个部分,以便更清楚地看到国与国之间的差异。
请记住,这种模式可能是由于测试斜坡。围绕大规模测试有传言称,韩国推出得非常快。我不知道不同国家的测试部署/斜坡有什么不同,所以我不能说,但这是要记住的事情。
covid_tab %>%
filter(!grepl('Confirmed', Case_Type) &
grepl('China|Korea|US|United Kingdom|Italy|Spain|Iran',
Country_Region) & Date > '2020-02-15')%>%
group_by(Date, Case_Type, Country_Region)%>%
summarise(Cases = sum(Cases))%>%
ggplot(aes(x = Date, y = Cases, fill = Case_Type))+
geom_bar(stat = 'identity', position = 'dodge')+
theme(axis.text.x = element_text(angle = 45))+
facet_wrap(~Country_Region)
下面,我将删除中国,以提高其他落后国家的可解释性。
与意大利的直接比较
谈到我们当前的发展轨迹,人们把美国比作意大利。已经说过很多次了,我们落后他们 10 天。我们来调查一下!
我想做的是确定某个国家的第一例冠状病毒,并从那里给出自爆发以来的每一天。然后我们将在 X 轴上画出这个,看看我们看起来比意大利落后多少天。这将有助于我们了解不同国家之间的相似或相异之处。
我做的第一件事是创建第一天的数据集。在这里,我们按国家分组,筛选出任何爆发前的日期,并取第一个日期。
然后,我们将其加入到我们的数据集中,并将 days_since_outbreak 指标作为我们的 x 轴。
first_day <- covid_tab%>%
filter(grepl('Active', Case_Type) & grepl('US|Italy', Country_Region) & Cases > 0)%>%
group_by(Country_Region)%>%
summarise(first_date = min(Date)) covid_tab %>%
filter(grepl('Active', Case_Type) & grepl('US|Italy', Country_Region))%>%
group_by(Date, Case_Type, Country_Region)%>%
summarise(Cases = sum(Cases))%>% left_join(first_day, by = 'Country_Region')%>%
mutate(days_since_outbreak = as.numeric(as.Date(Date) - as.Date(first_date)))%>%
ggplot(aes(x = days_since_outbreak, y = Cases, fill = Country_Region))+
geom_bar(stat = 'identity', position = 'dodge')
看一下自爆发以来的天数…
令人惊讶的是,美国的第一个病例实际上是在 2010 年 1 月 23 日确诊的。美国的增长在大约一个月的时间里没有真正开始。请记住,这在很大程度上取决于报告。
相反,意大利的第一天是在 8 天后的 1 月 31 日。有趣的是他们经历指数增长的速度有多快。
我又做了一次,但是我选择了“第一次约会”,是根据每个国家发展非常迅速的日期。这里我们可以看到,一旦美国达到类似的轨迹,我们实际上看到感染的速度更快。
人们可以立即推测说,也许美国已经更快地动员了测试能力——这可能是我们看到更快增长的原因,或者,这可能是由于缺乏早期干预。不言而喻,这可能是由于任何其他因素。
看看韩国
韩国是测试速度最快的国家。让我们来看看他们是如何比较一致的。
南韩驱车通过新冠肺炎测试站
正如我们所看到的,在韩国曲线开始变平之前,增长在几周内保持相似。这并不一定能告诉我们任何关于测试能力或测试速度的信息,但它确实提供了一幅有趣的图片,展示了每个国家的相对增长和下降;当然也回避了这样一个问题:韩国是如何如此迅速地拉平曲线的?
增长
最大的担忧之一是病毒的增长。病毒会以多快的速度席卷任何一个国家?
与我们所做的其他一些分析类似,我想观察各个国家的增长率。
我是这样计算增长率的:今天的总例数—昨天的例数/昨天的例数;从而得出与昨天总数相关的每日变化。
您将在下面的代码片段中看到,在按日期排序并按国家分组后,我使用了 lag 函数将前一天的总数提取到当天的记录中。
从那里,我简单地用先前定义的公式创建了一个字段。
我还重新考虑了将第 0 天定为病毒活跃的第一天的想法。
covid_growth <- covid_tab%>%
filter(grepl('Active', Case_Type) & grepl('China|Korea|US|United
Kingdom|Italy|Spain|Iran', Country_Region))%>%
group_by(Date, Case_Type, Country_Region)%>%
summarise(Difference = sum(Difference), Cases = sum(Cases))%>%
arrange(Date)%>% group_by(Country_Region)%>%
mutate(lag_cases = lag(Cases), growth = round((Cases - lag_cases) / lag_cases,2))%>%
ungroup()%>%
left_join(first_day, by = 'Country_Region')%>%
mutate(days_since_outbreak = as.numeric(as.Date(Date) -
as.Date(first_date)))covid_growth%>%
filter(days_since_outbreak > 0)%>%
ggplot(aes(x = days_since_outbreak, y = growth, col =
Country_Region))+
geom_line(stat = 'identity')
鉴于不祥的“翻倍率”,日增长率的下降令人欣慰。“倍增率”是一个在病毒背景下经常被提及的指标。它代表给定国家的病毒在一天内翻倍的天数。在 1 附近有一条一致的线,我们可以假设一个翻倍率持续保持强劲。
很明显,有些日子的增长率高达前一天的 4 倍,但好消息是,我们看到百分比增长率一天比一天持续下降。
结论
还有更多的东西可以投入进去!
我希望这已经被证明是有用的,因为你试图更好地了解世界上正在发生的事情,你的公司,或者你正在做的任何事情!
数据科学快乐!
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
原载于 2020 年 3 月 22 日 http://datasciencelessons.com**T21。
关于随机变量的深入速成课程
统计学和数据科学的基础
rawpixel.com 创建的商业向量—www.freepik.com
目录
- 随机变量
- 概率分布函数
- 你应该知道的著名 PMF
- 你应该知道的著名 pdf
- 均值和方差
- 常见分布的均值和方差
- 协方差和相关性
前言
令人惊讶的是,在线数据科学课程中并没有真正教授随机变量,这很可笑,因为它们是统计学的基础,而统计学是数据科学的基础!
因此,这旨在提供一个关于随机变量基础的综合速成课程。让我们开始吧!
随机变量
随机变量(RV) ,通常表示为 X,它的可能值是随机现象的数值结果。更简单地说,随机变量有一组值,它可以随机取这些值中的任何一个。随机变量是从样本空间到现实生活的函数。
有两种类型的随机变量,离散的和连续的。
离散随机变量
离散随机变量是其中可能值的数量是有限的或可数无限的。
离散 RVs 的示例包括某一天进入杂货店的人数、一个家庭中的儿童人数或一盒 24 个有缺陷电池的数量。
连续随机变量
连续随机变量是其中可能值的数量是不可数的无穷大。
连续 RVs 的例子包括人的身高和体重。
概率分布函数
每个随机变量都有一个相关的概率分布函数。概率分布函数本质上给出了与获得每个可能值或值的区间相关的概率。
有三种类型的概率分布函数:概率质量函数(pmf)、概率密度函数(pdf)和累积分布函数(cdf)。
概率质量函数(pmf) →对于离散 RVs
概率质量函数(pmf)是一个离散随机变量的概率分布,它是与每个可能值相关的概率列表。
用更专业的术语来说,如果 X 是一个分立的 RV,那么它的 pmf 是:
注:0 ≤ f(x) ≤ 1 且∑ f(x) = 1
概率密度函数(pdf) →连续 RVs
概率密度函数(pdf)是一个函数,其积分被计算以找到与连续随机变量相关的概率。
用更专业的术语来说,如果 X 是连续的 RV,那么 f(x) 是 X 的 pdf,如果它满足以下条件:
- ∫ f(x)dx = 1(曲线下的面积为 1)
- f(x) > 0 为所有 x(曲线没有负值)
单个点的概率等于零。所以,你得通过求定积分来求一个区间的概率:
累积分布函数
累积分布函数(cdfs)适用于离散和连续函数。cdf 是针对每个值 x 给出随机变量 X 小于或等于 X 的概率的函数。
用更专业的术语来说,对于任何 RV X ,cdf 定义如下:
对于离散 RVs,您只需简单地将小于或等于 x 的所有值的概率相加。
对于连续 RVs,你可以简单地找到 RV 从点 0 到 x 的定积分。
这里有一些你应该知道的关于 CDF 的定理:
- F(-∞) = 0
- F(x)是单调非减的(只能随着 x 的增加而增加或保持不变)。
- P(X>x) = 1 - F(x)
- P(a
- f(x) = F’(x) → the derivative of the cdf gives you the pdf
If this doesn’t make sense to you, don’t worry. Here’s an example…
Example of PMF and CDF
Suppose we flip two coins. Then let x =出现的人头数。
只有三种可能:头数= 0、1 或 2。我们可以将与每个可能结果相关的概率总结如下:
PMF 简单地用概率列表示,它显示了每个可能结果的概率。
类似地,CDF 简单地用累积概率列表示,它显示获得可能值或更少值的概率。
你应该知道的著名 PMF
离散均匀分布
X 具有离散均匀分布,如果其 pmf 为:
举例:抛一个骰子, x = 1,2,3,4,5,6。因此 n = 6,所有 x 的 pmf 等于 1/6。
二项分布
设 X 表示来自 n 次独立试验的成功次数,成功概率等于 p 。然后 X 具有参数 n 和 p 的二项分布。(符号:X∞Bin(n,p))
如果 X 具有二项式分布,那么在 n 试验中 k 成功的概率由 pmf 给出:
泊松分布
如果 x 的 pmf 如下所示,则 x 具有参数为λ的毒物分布:
你应该知道的著名 pdf
均匀分布
X 具有均匀分布(符号:X~Unif(a,b ),如果 X 同样可能在 a 和 b 之间的任何位置。它的 pdf 是:
指数分布
x 具有参数为λ的指数分布,如果它具有 pdf:
期望值和方差
期望值或平均值是平均值,是所有可能的 x 的加权平均值,其权重由 f(x)给出。如果 RV 的期望值或平均值为:
对于离散房车
对于连续房车
方差是对分布或离差的度量。X 的方差为:
常见分布的均值和方差
x~伯努利§
E[X] = p
Var(X) = pq
x~泊松(λ)
E[X] = λ
Var(X) = λ
x~统一(a,b)
E[X] = (a+b)/2
Var(X) = (a-b) /12
x ~法线(,σ)
E[X] =
Var(X) = σ
x ~指数(λ)
E[X] = 1/ λ
Var(X) = 1/λ
协方差和相关性
这两个度量都定义了 X 和 y 之间的关联程度。
协方差
X 和 Y 之间的协方差为:
同样,一种更简单的计算方法是:
注意协方差只考虑线性相关。如果 X 和 Y 以非线性方式相关,它们可能有协方差= 0。
如果 X 和 Y 是独立的,那么 X 和 Y 之间的协方差为零。请注意,协方差为 0 并不意味着它们是独立的。
相互关系
衡量两个变量之间的关系强度,范围从-1 到 1;协方差的标准化版本。
感谢阅读!
读完这篇文章后,希望你对随机变量、概率分布函数等有一个基本的了解。如果你觉得你需要更多地研究这些概念,我会查看我的免费数据科学资源,它涵盖了概率基础和概率分布。
特伦斯·申
- 每周查看我的免费数据科学资源的新资料!
- 如果你喜欢这个, 在 Medium 上关注我 了解更多
- 让我们连线上LinkedIn
深入了解谷歌分析 4:新功能、优势和劣势
来源:沉积照片
在本文中,我们将讨论什么是 Google Analytics 4,它与 Universal Analytics 有何不同,它给企业带来了什么价值,以及您可以用它解决什么问题。
大约一年前,谷歌团队推出了 App + Web 功能,它允许你将来自网站和移动应用的数据整合到一个谷歌分析资源中。从那以后,谷歌测试了这种新型资源,对其进行了修改,最终确定了它,并以不同的名称将其推出了测试版。认识一下谷歌分析 4 。
什么是谷歌分析 4?
谷歌分析 4 是谷歌分析中的一个新的资源类型。它看起来与通用分析(UA)资源略有不同,而且配置起来更容易、更快。在演示中,谷歌团队多次将这种新型资源称为分析的未来,引用了以下内容:
- 围绕事件构建的可扩展跨平台分析
- 所有谷歌分析用户都可以使用机器学习(ML)和自然语言处理(NLP)功能
- 维护隐私和避免设置 cookies 的需要是首要任务
- 与所有谷歌产品无缝集成
- 跨平台用户识别,因此您可以跨设备和平台查看用户的完整路径
让我们仔细看看这些好处。
可扩展的跨平台分析
基于事件的方法允许您跨多个设备和平台收集可靠且一致的数据。
在 Google Analytics 的标准 web 版本中,一切都是围绕用户会话构建的,而在 Firebase 中,一切都是围绕事件构建的。因此,很难分析用户在平台之间的转换,因为没有通用的用户行为衡量标准。即使有原始数据,你也需要花大力气建立高质量的用户流量。
谷歌分析 4 结合了所有围绕事件的分析。这使您可以为所有设备和平台收集相同的标准化数据,提高数据质量,并为您提供跨用户路径的单一报告。
机器学习
Google Analytics 4 的主要优势之一是其机器学习和自然语言处理(NLP)功能,您可以使用它来:
- 预测转换的概率,并基于该概率为谷歌广告创建受众预测
- 就数据中的重要趋势向您发出警告(例如,由于用户需求的变化而引起的产品需求)
- 在报告中查找异常
- 预测客户流失的可能性,这样你就可以有效地投资留住客户
图片由作者提供
谷歌团队计划继续朝着这个方向发展,并添加新的预测,如 ARPU,以便所有谷歌分析 4 用户可以调整他们的营销策略,并使用机器学习见解提高他们的投资回报率。
隐私是重中之重
- Google Analytics 4 以隐私为中心,使用 gtag。js 库,没有 cookies 也能工作。因此,我们可以预计,在不久的将来,谷歌将放弃客户端 ID ,而只依赖内部设备和浏览器标识符以及 CRM 中生成的跨平台用户 ID 标识符。
- Google Analytics 4 中的 IP 匿名化是默认配置的,不能更改。
与谷歌工具无缝集成
到目前为止,最先进的集成是与 YouTube 的集成。谷歌正在积极努力提高 YouTube 活动的评估质量(例如,允许您跟踪观看转换)。这将让你找到这些问题的答案:
- 我的 YouTube 广告活动如何影响特定的观众参与指标?
- 我的 YouTube 活动如何影响跳出率、我网站上的事件(不一定是转换)等?
通过更深入的 Google Ads 集成,您可以创建受众并开展活动,以相关和有用的产品吸引新客户,无论他们使用什么设备。
此外,在 Universal Analytics 中, BigQuery 导出功能仅对付费版本的用户开放,而在 Google Analytics 4 中,该功能对所有人都是免费的。您可以在 Google Analytics 4 资源设置中激活 BigQuery 云存储中的数据收集。
跨平台用户识别
谷歌分析 4 考虑的是与你的公司互动的个人用户,而不是他们使用的设备和浏览器。
它使用三个级别的身份识别来实现这一点:
- 用户标识
- 谷歌信号
- 设备 id
图片由作者提供
通过实施基于事件的分析,Google Analytics 4 使您能够更好地跟踪用户从首次接触到转化和重新订购的路径。此外,如果用户使用不同的设备多次完成同一事件,则该事件的数据将被合并到单个触摸点。例如,如果客户将一件商品放入智能手机上的购物车,然后放入笔记本电脑,“添加到购物车”事件将只计算一次。
谷歌分析 4 和通用分析的区别
让我们比较一下通用分析和谷歌分析 4 中的关键跟踪概念:
谷歌分析 4
- 分析是围绕事件而不是会话构建的。由于会话是一个人造的概念,谷歌建议放弃它们。如果需要会话数据,可以通过在 Google BigQuery 中处理原始数据来自己构建。
- 有针对整个网站的高级数据收集设置和随每个事件而变化的设置。
- 借助内置的端到端 user_id 报告,您不需要创建单独的视图来使用 user_id。
在 Google Analytics 4 中,有三种类型的事件及其参数,就像 Firebase 中一样。
谷歌分析 4 中的三种事件和设置
- 自动收集 —例如:page_view、session_start、view_search_results、scroll、file_download ( 查看文档中完整的事件列表。)
- 推荐活动分为商业领域:零售和电子商务、旅游、游戏(见完整列表)。)
- 自定义 —您想要实施和监控的所有其他事件(受 Google Analytics 4 限制。)
推荐事件和自定义事件是独立实现的。
每个事件可以有额外的定义
图片由作者提供
自定义定义是对大多数报告端到端的维度和指标,并帮助您保持在 Google Analytics 4 限制内。
没有类别、动作或事件快捷方式
Google Analytics 4 没有类别、动作和事件快捷方式这样的概念。
对于现有设置和收集的数据,这些属性映射到事件设置。如果你想在 Google Analytics 4 报告中看到属性,你需要注册它们。
页面视图已成为 page_view 事件
如果您实现了“config”gtag . js 片段,这些事件会被自动收集。
page_view 事件具有以下预设参数:
- 页面位置
- 页面路径
- 页面标题
- 页面 _ 推荐人
谷歌分析 4 中的会话和会话计数
Google Analytics 4 报表有会话,但它们与通用分析中的会话有所不同:
- 会话由自动收集的 session_start 事件触发。
- 会话持续时间是第一个和最后一个事件之间的间隔。
- 交互被自动识别(不需要调度交互事件)。
- 延迟案例处理超时为 72 小时(UA Properties 中为 4 小时)。如果您比较 Google Analytics 4 和 Universal Analytics 报告中的会话数量,您可能会发现前者的会话数量较少,因为在会话完成后发送的点击可以在 72 小时内分配到正确的会话。因此,会议报告的印发时间更长。
- 目前无法在 Google Analytics 4 中配置会话持续时间。
自定义维度和指标
为了在 Google Analytics 4 报告中包含自定义维度和指标,必须根据 Google 的规则将它们转移到新的资源。尽管点击级别和用户级别的参数在 Google Analytics 4 中有相似之处,但会话级别的参数却没有对等物。或者,您可以在点击级别定义它们。
要使用自定义产品级定义,您必须单独添加它们。目前还不清楚这将如何工作,因为该功能仍在开发中,没有包含自定义产品级别定义的电子商务报告。
用户属性(新)
谷歌分析 4 引入了一个新的用户属性功能。
用户属性是对应于特定受众/用户的定义:性别、城市、新客户或老客户、永久客户等。
影响特定用户的属性扩展到他们的所有行为。基于用户属性,谷歌分析 4 为个性化广告形成受众。
现在谁将从过渡到 Google Analytics 4 中受益?
在以下情况下,您应该已经实施了 Google Analytics 4:
- 你通过数据层和谷歌标签管理器在你的网站上收集数据
- 您使用很少的标签(意味着最小的调整)
- 你积极使用 YouTube 广告和基于用户 ID 的再营销
- 您正在积极地使用 Firebase,并且您的团队熟悉 Firebase 数据收集逻辑以及 BigQuery 中用于导出表的 App + Web (Firebase)数据模式
越快迁移到 Google Analytics 4,就能越快开始收集历史数据,获得越多的决策信息,也能越快从机器学习洞察中获得价值。正如我们已经看到的,Google Analytics 4 和 Universal Analytics 有明显不同的数据结构和数据收集逻辑。因此,组合来自这两种资源的数据将会有问题。
为什么不加快转变呢
在以下情况下,您可能会遇到实施 Google Analytics 4 的问题:
- 代码是你网站的主要追踪方法
- 您使用 Google Tags Manager 作为您的主要跟踪方法,并且在容器中有许多标签(尤其是当标签绑定到自动事件时)
- 你有一个包含许多子域名的大型网站,每个子域名你都单独跟踪
- 对于事件及其参数,您没有一个度量系统(统一的名称和值),也没有统一的事件层次结构方法(在这种情况下,不清楚哪些事件首先添加到 GA 界面更重要,哪些最好推迟。)
- 您有一个没有通用事件层次结构的网站和应用程序
- 你的团队还没有在 BigQuery 中处理过原始数据,也不熟悉 Firebase Analytics / App + Web 的原理和上传方案
如果这些陈述适用于您,我们建议首先构建通用数据收集逻辑,然后再实施 Google Analytics 4。否则,您会很快发现自己没有用户参数的空闲插槽。
如果您没有内置的数据收集方案,除了付费存储对任何人都没有用的垃圾数据(例如,关于滚动事件和横幅视图的数据)之外,您还可以在 BigQuery 中收集无用的事件并面临导出限制。
在我们看来,Google Analytics 4 的主要缺点是将数据导出到 Google BigQuery 的方案,其中事件和用户的关键参数存储在嵌套字段中。这意味着,为了从 Google Analytics 4 表中获取必要的信息,与标准 Google Analytics 360 中的 OWOX BI 数据流或 BigQuery 导出相比,您需要处理更多的数据。
Google Analytics 4 还有哪些不适合的情况?
谷歌分析 4 可能不适合你,如果:
- 多个命令必须同时使用新的资源,因为 Google Analytics 4 中目前没有视图,并且访问管理还没有实现
- 您想要分析非 Google 活动的费用和 roa,因为新资源还不允许您导入数据
- 您希望将转换结果导出到搜索广告 360 和显示与视频 360,因为与其他谷歌产品的集成还没有完全发挥作用
如何转移到谷歌分析 4
到目前为止,谷歌和 OWOX 的分析师都推荐使用这两个版本的谷歌分析资源。为此,您需要:
- 创建和配置新的 Google Analytics 4 资源
- 手动添加跟踪代码或通过 GTM 添加**(我们建议使用标签管理器,因为它更快更方便。)**
- 考虑要收集到新资源类型中的事件和设置
- 同时使用两种资源类型来比较数据的收集方式
- 请注意:
- 一个 Google Analytics 4 资源只能添加一个 Firebase 项目
- 但是,您可以将来自不同应用程序的多个数据流配置到一个 Google Analytics 4 资源中
摘要
- 谷歌分析 4 是有史以来对谷歌分析逻辑最深刻的更新。现在,一切都是围绕事件、事件参数和用户构建的,而不是像以前那样围绕会话。
- 您的网站和开箱即用的应用程序之间的跨平台分析是 Google Analytics 4 的关键功能和驱动因素之一。
- 你可以通过 gtag 使用已经配置好的谷歌分析资源。js 或 GTM 来配置新的 Google Analytics 4 资源。
- 当你设置 Google Analytics 4 时,它会自动创建一个新的 WP 资源,并且只有在你设置它时才会收集数据。不会从较旧的 WPs 中迁移任何数据。
- 谷歌团队并不敦促每个人都放弃旧的谷歌分析,改用新的。他们建议与谷歌分析并行运行新的谷歌分析 4,并开始收集数据。历史数据的来源仍然是标准的谷歌分析。
- 虽然新的 Google Analytics 4 有缺陷,而且并非所有功能都可用,但开发者正在逐步推出它们。
- 没有办法将非谷歌来源的成本导入谷歌分析 4。数据导入在路线图中,但细节尚不清楚。
- 您可以设置从 Google Analytics 4 向 Google BigQuery 免费上传数据。导出方案与 Firebase 相同。
- 您已经可以配置 Google Analytics 4 资源并开始收集数据。配置资源越快,收集的历史数据就越多。
对执行基础数据分析的深入了解
通过威尔士就业形势了解基本数据分析
威尔士是一个美丽的国家,是英国的一部分。你可以在 https://en.wikipedia.org/wiki/Wales 了解更多。
可在https://stats Wales . gov . Wales/Catalogue/Business-Economy-and-Labour-Market/People-and-Work/Employment/Jobs/Whole-Labour/Work place Employment-by-industry-area查阅按行业分列的威尔士工作场所就业情况。这就是我们将从中抓取数据集的地方。为了理解数据分析的基本原理,让我们考虑 10 年的就业数据,即 2009 年至 2018 年期间。
收集了 10 个行业的数据。这些行业是 农业、生产、建筑、零售、信息和通信技术、金融、房地产、专业服务、公共管理 ,所有其他部门和服务都归入 其他 _ 服务 。
我们将使用 Python 来完成任务和以下包:
- 熊猫
- Matplotlib
- Sklearn
- 海生的
- Plotly
图 1:就业数据在网站上看起来是这样的(图片:截图https://stats Wales . gov . Wales/Catalogue/Business-Economy-and-Labour-Market/People-and-Work/Employment/Jobs/Whole-Work force/Work place 就业-行业-领域
第一步
第一步是下载数据集。打开网页,点击左上方下拉框中的 2009 年,点击导出为 CSV 文件。在 2018 年之前的所有年份重复同样的操作。这样,我们将在同一个文件夹中存储 10 个 CSV 文件。
第二步
下一步是用 python 创建一个数据框,我们可以用它做进一步的工作。
*def data_extraction():
list_values=[]
for year in range(start_year,end_year):
file_name_part1="export_"
file_name_part2=year
file_name_part2=str(file_name_part2)
file_name=file_name_part1+file_name_part2+".csv"
with open(file_name) as csv_file:
csv_reader = csv.reader(csv_file, delimiter=',')
line_count = 0
for row in csv_reader:
if(line_count<=2):
line_count=line_count+1
elif(line_count<=12):
list_values.append(row[5])
line_count=line_count+1
print("Extracted the data for year: "+file_name_part2)
flag=0
for check_null in list_values:
if(check_null==""):
flag=1
if(flag==0):
print("No Null Value Found for the year: "+str(year))
else:
print("!!!NULL FOUND!!!")
all_years[file_name_part2]=list_values
list_values=[]*
函数 data_extraction() 将是我们要编写的第一个函数,它将从每个 CSV 文件中提取所需的数据,并将其存储在一个 list "list _ values"中,然后将其存储在一个 dictionary "all _ years"中。这是我们将从中创建数据框架的字典。该函数还检查数据中的任何空值。在运行代码时,我们可以发现没有空值,因此此时我们不必担心处理空值。(附言那是自己的话题)
*def create_dataframe():
df=pd.DataFrame(all_years,index=['Agriculture','Production','Construction','Retail','ICT','Finance','Real_Estate','Professional_Service','Public_Administration','Other_Service'])
return df*
函数 create_dataframe() 应使用字典**“all _ years”并创建数据帧“df”**。
第三步
现在让我们考虑一个特定的年份,比如说 2009 年,然后通过绘制简单的折线图来看看每个行业的雇员人数。然后,我们将对其进行循环,以获得 2009 年至 2018 年期间每年的类似图表。
*def data_analysis_1(df):
for year in range(start_year,end_year): #start year is 2009 and end year is 2019
plt.figure(figsize=(10,7))
df.reset_index()
plt.plot(df[str(year)])
plt.xlabel('Industry',fontsize=10)
plt.ylabel('Number of Employess')
plt.title("Industry and its Employees in Year: "+str(year))
plt.show()*
图 2:2009 年的地图(图片由作者提供)
这种图表的优点是,我们可以直观地识别哪个行业在就业人数方面表现最好和最差。
例如,当我们查看 2009 年的图表时(检查"图 2 "),一个非常容易的推断是"公共管理"行业在 2009 年雇用了最多的人,而"房地产"在 2009 年雇用了最少的人。
另一个推论是,“信息和通信技术、金融和房地产”的雇员人数接近相等,“公共行政和零售部门”的雇员人数接近相等。
第四步
现在,让我们来看看在 2009 年至 2018 年期间,哪些行业的总体增长率 最高和最低 。
*def data_analysis_3(df):
indsutry_list=['Agriculture','Production','Construction','Retail','ICT','Finance','Real_Estate','Professional_Service','Public_Administration','Other_Service']
for industry_name in indsutry_list:
ind=df.loc[str(industry_name)]
year_2009 = ind[0]
year_2018 = ind[9]
percentage = ((year_2018 - year_2009) / year_2009)*100
print("Percentage Overall Growth of "+industry_name+" is: "+str(percentage))*
这个函数的输出告诉我们,就就业人数而言,房地产部门的总体增长是惊人的 86.67%。另一方面,总体增长最低的是零售业,就就业人数而言,10 年间仅增长 0.6%。
到目前为止,我们已经了解了如何提取数据、创建数据框、查找是否有空值、绘制几个折线图以查找每年表现最佳和最差的行业,以及我们发现哪些行业在 2009 年至 2018 年期间的总体增长率最高和最低。
现在,我们将向前迈进一步,尝试对威尔士的就业形势有更深入的了解。
第五步
我们现在将使用【Plotly】创建动态散点图,以显示一段时间内劳动力数量的变化。让我们看看实际的情节来更好地理解这一点。
*def data_visualise_plotly(df):
indsutry_list=['Agriculture','Production','Construction','Retail','ICT','Finance','Real_Estate','Professional_Service','Public_Administration','Other_Service']
#Function to plot using plotly for analysing employee change in each sector over the time period
for industry_name in indsutry_list:
agriculture=df.loc[industry_name]
year_list=[]
value_list=[]
for year in range(start_year,end_year):
year_list.append(year)
value_list.append(agriculture[str(year)])
print(year_list)
print(value_list)
new_df=pd.DataFrame(list(zip(year_list,value_list)),columns=["Year","Employees"])
print(new_df)
fig=px.scatter(new_df, x="Year", y="Employees", marginal_y="violin", trendline="ols")
title_for_plot = "Industry: "+industry_name
fig.update_layout(title=title_for_plot)
fig.show()
value_change_list=[]
prev=0.0
current=0.0
for v in value_list:
current=v
value_change_list.append(current-prev)
prev=current
value_change_list[0]=0.0
print(value_change_list)
new_df=pd.DataFrame(list(zip(year_list,value_change_list)),columns=["Year","Employees_Change"])
print(new_df)
fig=px.scatter(new_df, x="Year", y="Employees_Change", marginal_y="violin", trendline="ols")
title_for_plot = "Industry: "+industry_name+" Change from Previous Year"
fig.update_layout(title=title_for_plot)
fig.show()*
上述函数产生所需的图。这些图将在带有本地 IP 的默认浏览器中打开。
图 3:左边的图是“生产”行业每年的就业人数。右边的图表显示了与前一年相比,每年的数字变化。(图片由作者提供)
在图 3 的第一个图中,我们绘制了*【生产】*行业每年的就业人数。在第二张图中,我们看到了这些数字相对于各自前一年数字的变化。让我们更好地理解这一点。
参见图 3 的第二个图。2009 年的值始终为 0,因为它是考虑时间范围的开始。从那以后,当前 x 轴值的 y 轴上的每个值都表示相对于其先前 x 轴的 y 轴值的数字变化。
我们可以注意到一条穿过图表的线。这条线就是 OLS(普通最小二乘法)回归线 。你可以在这里了解更多关于普通最小二乘的知识。这基本上是一条线性回归线,对我们了解数据趋势非常有帮助。例如,在图 3 的第一个图中,回归线显示出增长的趋势,这意味着 2019 年、2020 年等更有可能…在 2009-2018 年将有更多的就业机会。
但这是一个十亿美元的问题。如果第一个图显示增长趋势,那么为什么图 3 的第二个图显示中性趋势(水平直线)(即变化保持不变)。
啊啊啊………耐人寻味吧。
图 3 的第二个图类似于第一个图的衍生物。中性趋势表明,在 2009 年至 2018 年期间,这一变化平均保持不变。为了得到这个十亿美元问题的答案,考虑一个每年有+2000 名员工变动的行业“X”。即每年就业人数增加 2000 人。这意味着图 3 的第一个图必须显示增加的趋势。但是由于变化在我们想象的场景中保持不变,第二个图将有一条中性趋势线。即中性趋势线表示变化是恒定的。
假设,行业“Y”在 2009-2010 年间的变化为+2000,在 2010-2011 年间的变化为+3000,在 2011-2012 年间的变化为+4000,依此类推…那么第二个图中的趋势线将是线性增长趋势。
在图 3 中,每个图的右侧还有 violin 图。这些图给了我们最大-最小值,也显示了(用一个凸起)在哪个范围内找到了最大数量的数据点。凸起区域表示更多数量的数据点位于该区域。
第六步
该进行主成分分析了。第一个问题是为什么?让我们把每一年看作一个维度。这意味着我们的数据现在是“10 维”的。但是你真的认为我们可以想象和理解一个 10 维的图形吗?普通人能够想象和理解的最大维度是“三维”。为了简单起见,我们使用主成分分析将我们的 10 维数据集减少到 2 或 3 维数据集,这样我们就很容易可视化和理解数据。这就是统计中的降维。
*def pca(df):
print(df)
indsutry_list=['Agriculture','Production','Construction','Retail','ICT','Finance','Real_Estate','Professional_Service','Public_Administration','Other_Service']
df['Industry']=indsutry_list
print(df)
features_for_pca=['2009','2010','2011','2012','2013','2014','2015','2016','2017','2018']
x = df.loc[:,features_for_pca].values
y = df.loc[:,['Industry']].values
x = StandardScaler().fit_transform(x)
print("Scaling of Values done")
print(x)
pca = PCA(n_components=2)
principalComponents = pca.fit_transform(x)
principalDf = pd.DataFrame(data = principalComponents, columns = ['principal component 1', 'principal component 2'],index=indsutry_list)
print("The Principal Components are as follows")
#print(principalDf)
finalDf = pd.concat([principalDf, df[['Industry']]], axis = 1)
print(finalDf)
print("Trying a 2D Plot")
fig = plt.figure(figsize = (8,8))
ax = fig.add_subplot(1,1,1)
ax.set_xlabel('Principal Component 1', fontsize = 15)
ax.set_ylabel('Principal Component 2', fontsize = 15)
ax.set_title('2 component PCA', fontsize = 20)
indsutry_list = ['Agriculture','Production','Construction','Retail','ICT','Finance','Real_Estate','Professional_Service','Public_Administration','Other_Service']
colors = ['r','g','b','c','m','y','k','0.75','0.5','0.3']
for industry,color in zip(indsutry_list,colors):
indicesToKeep = finalDf['Industry'] == industry
ax.scatter(finalDf.loc[indicesToKeep, 'principal component 1']
, finalDf.loc[indicesToKeep, 'principal component 2']
, c = color
, s = 50)
ax.legend(indsutry_list)
ax.grid()
plt.show()*
通过这段代码,我们将 10 维数据集缩减为 2 维数据集。
图 4:双组分五氯苯甲醚(图片由作者提供)
当我们绘制新创建的二维数据集时(图 4),我们可以发现有几个行业自然地聚集在一起。例如,一个非常明显的群集是图左下方的红色、黄色、蓝色和黑色点,分别对应于农业、金融、建筑和房地产行业。
聚类表明,在 2009 年至 2018 年期间,它们之间的相关性更强。这意味着,一个集群内各行业就业人数的变化趋势几乎是相似的。我们可以自然地观察到,四个集群正在出现,有趣的是,专业服务行业是集群中唯一的行业。
但是它们真的相关吗?
到目前为止,我们使用 Plotly 创建动态图,并使用主成分分析技术来减少数据集中的维数。我们最后问了一个问题", PCA 图中发现的集群内的行业是否真的相关?”。让我们回到这个问题上来。
第七步
我们现在要做的是找出 2009 年至 2018 年期间各行业之间的相关性。任何两个实体之间的相关性可以在-1 和 1 之间变化,其中-1 是可能的最小值,表示行业高度“不相关/负相关”,最大值+1 表示行业高度“相关”。它可以取-1 到+1 之间的任何值。好吧,在我们的语境中,两个行业相关/负相关到底意味着什么?让我们不要忘记,我们正在处理这里的就业数字。这意味着如果两个行业高度相关,那么就业人数的变化趋势是相似的。也就是说,为了理解这一点,让我们再次假设两个行业 X 和 Y 的假想场景,并假设它们的相关值为+1。这意味着如果 X 中的雇员数量增加了 M 个百分点,那么 Y 中的雇员数量也很有可能增加 M 个百分点(理论上是 100%)。
既然我们已经理解了相关性的真正含义,那么让我们来看看数据集中每一对行业之间的相关性。
*def correlation_complete(df):
print(df)
print(df.transpose())
corrMatrix = df.transpose().corr()
print(corrMatrix)
sn.heatmap(corrMatrix,annot=True)
plt.show()*
这几行代码给了我们所谓的相关矩阵的热图。
图 5:关联热图(图片由作者提供)
我们可以从图 5 中推断出相关性*(除了值“1”,因为与自身的相关性,永远等于 1)* 的最大值是 0.8。这意味着专业服务和其他服务 80%相关。也就是说,专业服务部门就业人数的 M %的变化可能(80%的可能性)导致其他服务类别中所有子部门的 M %的变化。
这里有一个问题,如果您还记得我们在文章的前一部分中说过,在 PCA 图中有 4 个自然发生的聚类,在其中一个聚类中,专业服务是唯一的成员。这意味着,根据我们在 PCA 图中所做的分析,专业服务和其他服务是不相关的(换句话说,它们不属于同一个集群)。但是在相关矩阵中,我们发现它们是 80%相关的,并且在任意两个行业之间具有最高的相关值。讽刺?我们哪里出错了?暂停阅读这篇文章,思考几分钟,看看我们的分析可能出了什么问题。
得到答案了吗?没问题,我是来帮你的。在主成分分析中,我们进行了降维。主成分 1 和 2 是 10 个维度的代表。但是这两个主要组成部分对我们来说并不具有同等的价值。为了理解这一点,考虑一个公司 X,其中有两个股东 A 和 B(这两个股东是主成分 1 和 2)。假设 A 持有 X 公司 75%的股份,而 B 只持有 25%的股份。现在告诉我,如果 A 必须在公司做出决定,B 的意见真的重要吗?没有权利。a 有完全的权力为公司做决定。同样,我们需要找出两个主成分 1 和 2 的价值是多少。
*print(pca.explained_variance_ratio_)*
通过这一行代码,我们可以得到主成分的变化。瞧啊。输出是
[0.99808273 0.00102919]
看见了吗?这表明第一主成分 PC1 占变异的 99.8%,而第二主成分 PC2 仅占~0.1%。如果我们将主成分的数量增加到 3(即,如果我们想要我们的数据集中的三维),第三个主成分,PC3 将具有比 PC2 更小的值。
现在事情似乎已经水落石出了。我们可以看到,PC1 提供了 99.8%的行业信息,而 PC2 仅提供了 0.1%的信息。我们实际需要绘制的只是 PC1,而不是 PC2。
向上滚动到 PCA 图,想象折叠 y 轴。也就是说,假设所有东西的“y 值”都只有 0。(换句话说,将所有点投影到 x 轴上)。现在将只出现两个集群,一个在右边有两个点,一个在左边有所有其他的点。这告诉我们,我们现在需要从 PCA 图向前迈进,因为它们没有给我们提供太多关于行业之间关系的信息。
第八步
我们现在来看看 K-Means 聚类技术,看看它是否能提供比简单 PCA 图更好的结果。
但是有个问题。我们无法处理 10 个维度。但是主成分分析的降维技术在这个基本分析中并不那么有效。还有其他几种降维技术可用,但为了简单起见,我们要做的是找出每个行业表现最好和最差的年份,并创建一个类似这样的数据框架。
best worst0 2016 2011
1 2014 2010
2 2016 2013
3 2016 2017
4 2017 2015
5 2018 2010
6 2018 2009
7 2018 2012
8 2018 2009
9 2017 2009
这样,我就把它变成了一个二维数据集。假设 k 值为 2。即要求簇的数量为 2。
*def best_worst_df(df):
indsutry_list=['Agriculture','Production','Construction','Retail','ICT','Finance','Real_Estate','Professional_Service','Public_Administration','Other_Service']
for industry_name in indsutry_list:
empl=df.loc[str(industry_name)]
print(type(empl))
test = list(empl)
#print(test)
empl_max_position = test.index(max(test))
empl_min_position = test.index(min(test))
print("Best Year for "+str(industry_name)+" is "+str(2009+empl_max_position))
best_year.append(2009+empl_max_position)
print("Worst Year for "+str(industry_name)+" is "+str(2009+empl_min_position))
worst_year.append(2009+empl_min_position)
Data = { 'best':best_year, 'worst':worst_year }
kmeans_df = pd.DataFrame(Data,columns=['best','worst'])
print(kmeans_df)
#Creating the Kmeans graph
kmeans =* ***KMeans(n_clusters=2)****.fit(kmeans_df)
centroids = kmeans.cluster_centers_
print(centroids)
plt.scatter(kmeans_df['best'], kmeans_df['worst'], c= kmeans.labels_.astype(float), s=50, alpha=0.5)
plt.scatter(centroids[:, 0], centroids[:, 1], c='red', s=50)
ind = 0
for i in indsutry_list:
plt.text(best_year[ind],worst_year[ind],str(i))
ind = ind + 1
plt.xlabel('Best Year')
plt.ylabel('Worst Year')
plt.title('KMeans on Best-Worst Year Data')
plt.show() #KMeans 2 and 3 clusters*
这给了我们以下情节。
图 6:双均值聚类技术(图片由作者提供)
在图 6 中,我们可以看到我们的问题在一定程度上得到了解决。专业服务和其他服务现在位于一个集群中(紫色集群)。但是我们不会就此停止,而是将集群的数量增加到 3 个,然后再增加到 4 个。
图 7: 3 均值聚类(图片由作者提供)
图 8: 4 均值聚类(图片由作者提供)
我们可以看到,4-均值似乎有点过拟合数据,2-均值似乎有点欠拟合数据。3-Means 似乎是最优的。也就是说,这些行业可以分为 3 个集群。
是的,我们已经接近了解威尔士就业形势的基本数据分析这篇文章的结尾。最后,我们必须明白我们为什么要做这一切?这种数据分析的目的是什么?
任何数据分析的主要目的都是情报。它可以是商业智能或环境智能(来自环境数据)或任何其他智能。这有助于决策者做出更好的决策。让我们通过一个简单的场景来理解。想象一下这样一种情况,在威尔士,建筑业突然大量裁员。现在,由于数字很大,政府开始注意到这一点,并开始在这个严重的问题上采取行动。但是,政府现在也掌握了额外的信息,也就是说,在我们的数据分析的帮助下,他们现在知道,建筑行业的就业人数趋势与农业部门有 73%的关联。因此,政府现在可以对建筑行业的裁员采取行动,并采取预防措施,以防止农业部门发生任何此类不幸事件。这种预防性措施可以通过防止任何严重的经济影响,对一个国家的经济产生巨大影响。这只是理解数据力量的一个简单场景。
到目前为止,我们所做的分析只是沧海一粟。数据中隐藏着如此多的信息,如果使用得当,它们是这个时代最强大的资产之一。
感谢您的宝贵时间!如果你喜欢这个故事,一定要和你的朋友分享。
你可以关注我的LinkedIn。再次感谢您!
积分速成班
理解概率分布的基本构件
由 freepik 创建的背景向量—www.freepik.com
目录
- 为什么你应该知道积分
- 用黎曼和逼近曲线下的面积
- 定积分作为黎曼和的极限
- 微积分基本定理
- 定积分的性质
为什么你应该知道积分
“数据科学”是一个非常宽泛的术语。它包括数据可视化、数据分析、数据工程、数据建模等等。在你更关注数据可视化和数据分析的情况下,积分可能是不必要的。
然而,对于那些想进入预测建模和假设测试的人来说,积分是成为数据科学家的基础。如果你打算更详细地学习统计和概率分布,了解积分的基础知识将会非常有用。
在这篇文章结束时,你将理解积分的基本概念,积分的基本性质,以及知道一些有用的反导数。
用黎曼和逼近曲线下的面积
想象一下,我们想要找到两点 a 和 b 之间的曲线下的面积。我们可以做的一个方法是使用矩形近似曲线下的面积。
注意,我们用越多的矩形来近似曲线下的面积,近似就越精确。如果我们取右边四个矩形的面积,它将比左边两个矩形更接近曲线下的面积。
有 4 种主要方法可以使用黎曼和,但我们将专注于左黎曼和、右黎曼和以及中点黎曼和。这三者之间的区别在于,它们只是确定每个矩形的高度(y 值)。
因为中点黎曼和是最精确的,所以它比左或右黎曼和更受青睐。你需要知道两个等式:
Delta x 告诉我们每个矩形的宽度应该是多少。然后,我们使用下一个等式来合计每个矩形的面积。简单!
定积分作为黎曼和的极限
正如我之前提到的,注意当你用更多的矩形来逼近曲线下的区域时,面积的逼近会变得更好。理论上,如果你使用无限数量的矩形,你可以找到曲线下的精确面积。当 n(矩形的数量)接近无穷大时,我们可以把它写成一个极限。
这个极限等价于定积分的方程,其写法如下:
既然你已经理解了定积分的含义,我们就来看看积分的基本原理。别担心,它们非常简单易懂,所以不要害怕。首先,我们将看看微积分的两个基本定理(这是积分有用的地方),然后我们将看看积分的几个性质。
微积分基本定理
微积分第一基本定理
这基本上告诉我们,一旦找到方程的积分,如何计算曲线下的面积。
微积分第二基本定理
这个定理本质上意味着积分是反导数的,也就是说它与求导是相反的。它告诉我们积分和导数之间有联系。
定积分的性质
负定积分
曲线上方到 x 轴的面积为负。例如,如果你想得到上面函数在点 a 和 b 之间的积分,那么面积将等于负十而不是十。
单点上的定积分
单点 c 的积分等于零。这是有道理的,因为如果你仔细想想,一条线的面积是零!
函数的比例形式的定积分
常数乘以函数的积分等于常数乘以函数的积分。
交换边界的定积分
交换边界(a 和 b)的积分等于负积分。
函数和的定积分
f(x)加 g(x)的积分等于 f(x)加 g(x)的积分。
相邻区间上的定积分
a 点到 c 点的定积分等于 a 点到 b 点的积分和 b 点到 c 点的积分之和。
常见函数的积分
与您了解到 x 的导数是 2x,sin(x)的导数是 cos(x)类似,下面是在计算概率分布曲线下的面积时经常用到的常用函数的积分。
多项式的不定积分(逆幂法则)
以上是求多项式积分的概括。你可以通过事后求积分的导数来确认这一点!
根的不定积分
与上一点类似,上面的等式是根式积分的推广。
指数函数的不定积分
触发函数的不定积分
感谢阅读!
通过阅读,你应该知道积分背后的基本概念,以及基本积分需要的主要规则。同样,这对于那些想更好地理解概率分布的人来说非常有用。