Python 中的时间序列处理
第一部分:使用熊猫的基本分析
Ales Krivec 在 Unsplash 上拍摄的照片
时间序列是一段时间内的一系列值。旧金山过去 30 天的日平均气温就是一个例子。
时间序列出现在各行各业,从天气到经济到产品销售到健康指标。
为什么要分析时间序列?因为这可以揭示趋势和其他模式。从中可以预测未来的价值。
这篇文章通过一个简单的运行和发展的例子,介绍了 Python 中 Pandas 库中处理时间序列的各种特性。
熊猫时间序列特征可以分为两类:时间序列中的值的特征和这些值后面的时间指数的特征。本帖涵盖前者。后者本身就是一个完整的主题,将在后续的帖子中讨论。
示例设置:温度
要开始使用熊猫,只需
import pandas as pd
接下来,让我们创建我们的第一个时间序列。
temps = pd.Series([70,75,65,70,75,70,30, 100, 80,72,76,79,85,76,81,69, 78])
把temps
想象成存储旧金山连续几天的日平均温度。日期隐含在索引中 t = 0,1,2,…
Pandas 支持更精细的时间指数。例如,我们可以存储 temps 封面的实际日期。我们不会在这里讨论这些。因此,我们可以将重点放在值的操作上,这些值有很大的变化。
温度最小值、最大值、平均值、可变性
temps
的平均(或最低或最高)温度是多少?简单:只需做temps.mean()
、temps.min()
或temps.max()
。气温波动有多大?Do: temps.std()
获得数量感。它会给出标准差。
让我们从数据中感受一下。temps.mean()
返回约 73.58。这接近于人们仅仅通过观察数据所猜测的。temps.min()
和temps.max()
分别是 30 和 100。范围很广。
temps.std()
返回约 13.74。因此,大多数温度徘徊在平均值的 13 度以内——正负。我们一眼就能看出这一点。
另一种方法是通过计算第 5 和第 95 个百分点,这可以被认为是 min 和 max 的软化。temps.quantile(0.05)
为 58.0,temps.quantile(0.95)
约为 88。所以这也给了我们一个相似的范围。
接下来,让我们给temps
添加一个异常值,看看它如何影响我们的分析。这种异常值可能是由数据输入错误引起的。
temps_with_outlier = pd.Series([70,75,65,70,75,70,30, 100, 80,72,76,79,**10000**,85,76,81,69, 78])
我们看到temps_with_outlier.mean()
是一个巨大的 625.055!而temps_with_outlier.std()
安,更是高达 2339.715!由此得出的教训是,无论是均值还是标准差,对异常值都不稳健。
统计学家建议,在这种情况下,我们应该使用中位数和平均绝对偏差(mad)来代替。它们是对异常值稳健的均值和标准差版本。temps_with_outlier.**median**()
是 75.5。哇!temps_with_outlier.**mad**()
是 1041.66。有点帮助。不够。经验教训:一定要用中位数。
从华氏温度转换到摄氏温度
你可能已经猜到我们的温度目前是华氏温度。怎样才能让这些进入摄氏温度?不多。
temps_celcius = (temps-32)*5/9
相当多的事情发生在幕后。首先,从temps
中的每个值中减去 32,得到一个新的时间序列。接下来,结果时间序列中的每个值都乘以 5/9。
关联邻近城市的温度
接下来,让我们根据旧金山的估计温度虚构一个圣何塞的估计温度时间序列(尽管是真实的)。
temps_sj = temps + 10
这里的想法是,圣何塞往往比旧金山暖和几度,因为它远离海洋,在一个避风的山谷里。
我们注意到temps
和temps_sj
是相关的,即它们一起移动。在任何一天,temps_sj
中的值总是比 temps 中的值高 10 度。
这让我们不禁要问:如何度量同一时间点上的两个时间序列是相关的?在探讨这个之前,我们先设置一个“控制”。这将与温度无关。所以我们可以衡量我们的措施有多有效。通过比较temps
和temps_sj
相对于temps
和控制的公式相关性。
import random
temps_random = pd.Series(random.sample(range(58,88),len(temps)))
这里发生了很多事。我们来解释一下。
random.sample(range(58,88),len(temps))
从 58 到 88 的范围内独立均匀地采样len(temps)
值。我们试图近似我们在temps
中看到的数值范围,同时平均分配这些数值。这就是为什么temps
和temps_random
有相似的值,只是它们不相关。
提出相关性度量的第一个合理尝试是将这两个时间序列的各个部分相乘,以产生一个新的时间序列。然后对这个时间序列中的所有值求和。让我们来看看实际情况。先应用到temps
和temps_sj
上吧。
m = temps*temps_sj
m.sum()
m
中的前两个值是 5600 和 6375。5600 等于temps[0]*temps_sj[0]
,6375 等于temps[1]*temps_sj[1]
。
*
操作也称为点积。
m.sum()
等于 107593。价值大。我们不知道这是怎么回事。这就是控制权的来源。如果我们的相关性度量很好,如果我们用temps_random
代替temps_sj
,那么m.sum()
的值应该会低得多。
(temps*temps_random).sum()
等于 88480。所以确实低了,意料之中!也就是说,它应该更低,对不对?
嗯,让我们试试不同的东西。在进行点积之前,让我们先将temps
和temps_random
分别居中。随着代码变得越来越复杂,让我们把它封装成一个函数。
def centered_dot_product(time_series_1,time_series_2):
ts1_centered = time_series_1- time_series_1.mean()
ts2_centered = time_series_2- time_series_2.mean()
return (ts1_centered*ts2_centered).sum()
centered_dot_product(temps,temps_sj)
返回 3024.11,而centered_dot_product(temps,temps_random)
返回-414.58。那好多了。区别更加明显。
为什么前者效果不好?因为在所有的时间序列中,大部分温度都在 58 到 88 度之间。点积发现了这种相似性。先定中心“减去”这种相似性,这样得到的测量结果可以不关注时间序列中的值,而是关注它们如何共变。
我们可以在这个指标上进一步改进,但我们不会。我们希望涵盖其他功能。
发现温度异常值
考虑一下temps_with_outlier
。以前我们用它来说明处理异常值的统计数据。在这里,我们研究如何找到离群值。
我们已经将发现异常值封装到一个函数中。它的代码有点复杂。我们建议先读一遍,然后看看我们接下来的解释,如果你还有点不清楚的话,可能还会再读一遍。
def outliers(time_series,lowp,highp):
low = time_series.quantile(lowp)
high = time_series.quantile(highp)
in_range = time_series.between(low,high)
outliers = []
for t,v in in_range.items():
if not v:
outliers.append([t,time_series[t]])
return outliers
在解释幕后发生的事情之前,让我们打个电话给它,看看它会有什么回报。此外,这也给了我们一个解释参数lowp
和highp
的机会。
outliers(temps_with_outlier,0.01,0.99)
返回[[6,30],[12,10000]]。这表明温度 30 和 10000 被视为异常值,分别出现在时间点 6 和 12。有道理!
我们在决定什么是离群值时有多严格?这是由分位数的下限和上限指定的,我们在此图中选择的值是 0.01 和 0.99。提高下限和降低上限将放宽离群值标准。让我们看看这是如何运作的。
outliers(temps_with_outlier,0.1,0.9)
返回[[2,65],[6,30],[7,100],[12,10000]]。在我们之前的异常值列表中又增加了两个:65 度和 100 度。新发现的可能被合理地解释为分别是“异常冷”和“异常热”。
不错。
气温上升了吗?
考虑temps
的以下变体:
temps = pd.Series([60,65,62,68,65,67,70,67,73,67,75,66,77,69,77,69,79])
你看到了什么?气温呈上升趋势。通过适当区分时间序列,可以使这种趋势更加生动。让我们看看这个效果如何。
首先尝试temps.diff(1)
。这导致了temps
中一步差的时间序列。即:NaN,temps[1]-temps[0],temps[2]-temps[1],…第一个值是 NaN,因为temps[-1]
未定义。
nan 5.0 -3.0 6.0 -3.0 2.0 3.0 -3.0 6.0 -6.0 8.0 -9.0 11.0 -8.0 8.0 -8.0 10.0
嗯,还没那么生动。让我们试试temps.diff(**4**)
。这导致了temps
中 4 步差的时间序列。结果中的第个条目是temps[i]-temps[i-4]
。
nan nan nan nan 5.0 2.0 8.0 -1.0 8.0 0.0 5.0 -1.0 4.0 2.0 2.0 3.0 2.0
好多了!趋势暴露了。
让我们做temps.diff(4).mean()
,这导致了 3.0。这可以被解释为平均每 4 天气温升高 3 度。
让我们看看通过不同的计算得到了什么:temps.diff(10).mean()
给出了 7.85。请注意,3.0/4 大致等于 7.85/10。换句话说,两者都表明平均气温每天上升约 0.75 度。不错。
温度上升的百分比是多少?
假设我们想知道temps
每天的平均百分比增长。熊猫里的shift
操作员会在这里帮忙。
我们将逐步构建我们的解决方案,因为它有点复杂。让我们从temps.shift(4)
开始。这产生了一个版本的temps
,其中时间移动了 4 步。下面是原始版本和转换后的版本
**Original**: 60 65 62 68 65 67 70 67 73 67 75 66 77 69 77 69 79
**Shifted**: nan nan nan nan 60.0 65.0 62.0 68.0 65.0 67.0 70.0 67.0 73.0 67.0 75.0 66.0 77.0
我们选择移动 4 步,因为这 4 步的差异在之前对相同的数据进行了很好的计算。
另外,注意temps — temps.shift(4)
相当于temps.diff(4)
。
我们最后的表达是
100.0*(temps-temps.shift(4))/temps.shift(4)
将时间序列temps-temps.shift(4)
除以时间序列temps.shift(4)
得到分数变化的时间序列。(请注意,这种划分是针对组件的。)乘以 100.0 以百分比表示。
消除温度波动
均线是对时间序列的一种重要操作。它产生一个新的时间序列,其值是前一个时间序列中相邻值的平均值。这具有消除瞬时波动的效果。
认为
temps = pd.Series([60,65,62,68,65,67,70,67,73,67,75,66,77,69,77,69,79])
temps_smoothed = temps.rolling(2).mean()
我们先来看结果,在temps_smoothed
。
nan 62.5 63.5 65.0 66.5 66.0 68.5 68.5 70.0 70.0 71.0 70.5 71.5 73.0 73.0 73.0 74.0
哇——这些绝对是平滑的!它们更生动地揭示了上升趋势。
现在让我们来解释一下幕后发生了什么。告诉熊猫建造宽度为 2 的滚动窗户。mean()
然后计算窗口中的平均值。这个滚动过程产生平滑的时间序列。
默认情况下,窗口在右边,不居中。我们可以通过检查结果来推测这一点。注意temps_smoothed[1]
是 62.5,是temps[0]
的平均值,是 60,temps[1]
是 65。
时间序列、信号和傅立叶变换
未来文章的介绍和入门
在我接下来的三篇文章中,我将介绍和讨论傅立叶和小波变换,它们提取了一个量如何随时间振荡的信息。这些方法几乎有无数的应用,我在这里描述了其中的一些。
示例代码 链接可以在下面的“参考资料”部分找到。
时间序列
毫无疑问,每个人都熟悉时间序列,即使你没有听说过这个术语。一个时间序列仅仅是一组按时间排序的值。例如,股票指数价格,在你最喜欢的新闻网上通常被描绘成价格与时间的关系图。另一个例子是 7 天预报,显示几天内的高温。时间序列是表示数据的一种自然方式。
纳斯达克指数价格随时间变化是一个熟悉的时间序列。图片来自谷歌搜索“纳斯达克”。
7 天预报中的最高和最低温度形成一个时间序列。图片来自谷歌搜索“天气”。
信号
信号是一种时间序列。更具体地说,信号是代表物理事件的时变量。信号的两个基本属性是:振幅和频率。信号的幅度是其大小,例如音频信号的响度。信号的频率表征了它在时间上的振荡,例如吉他发出的音调。
音乐的音频信号波形。信号是立体声混音的左半部分。图片作者。
不言而喻,当从连续信号(数量的无限集合)到离散信号(数量的有限集合)时,信息会丢失。因此,离散信号通常是连续信号的近似。例如,考虑捕捉办公室中的温度波动来运行 HVAC 系统。在任何时候,办公室都会有一些平均环境温度。假设每小时用一套温度计测量这个温度。这种测量会产生一个离散的信号,近似于办公室中真实的温度波动。有理由怀疑这些每小时的温度记录会导致空调不良,因为温度可能会在比一小时小得多的时间尺度上变化。如果是,应该多久测量一次温度?使用奈奎斯特定理正式回答了这个问题。为了可靠地捕获连续信号,记录信息的速率(称为采样速率)必须是目标信号频率的两倍。这就是为什么音频通常以 44,100 Hz 采样,因为人类听觉的上限约为 20,000 Hz。
实际上,从环境中获取有意义的信息可能并不那么简单。真实世界的信号通常是非周期性的、有噪声的,并且受多种来源的影响。从这些信号中提取有用的信息是信号处理的基本目标。
傅立叶变换
傅立叶变换的定义。还存在其他一些因前置因子而不同的约定。图片作者。
信号处理的核心是傅立叶变换。FT 将函数分解成正弦和余弦即波。理论上,任何函数都可以用这种方式表示,即表示为不同振幅和频率的(可能是无限的)正弦和余弦函数之和。下面给出一个玩具例子。代码可以在随附的 GitHub repo 找到。
**玩具示例信号。**图片作者。
**玩具的构成频率举例:**换句话说,玩具信号可以表示为频率为 1 和 2 Hz 的 2 个正弦函数之和。图片作者。
**玩具信号的单侧功率谱:**对应于信号分解成两个正弦函数,在 f=1 和 2 Hz 处出现两个幅值相等的显著峰值。图片作者。
应用程序
傅立叶变换在频谱分析、解微分方程和 A/V 制作中有无数的应用。
音频制作
均衡(EQ)是音频制作的重要组成部分。特定频率范围的音量可以调高或调低,从而改变音频的声音。EQ 的一个基本用途是从音频文件中去除背景噪音。
顶部面板显示音频信号。底部面板显示均衡器,它增加或减少频率范围的增益。图片作者。
脑电图
脑电图是一种记录大脑电活动的技术。EEG 的频谱分析被广泛使用,即通过成分频率能量检查信号。EEG 中广泛使用的频带约定如下。
脑电图中常用的频带。图片作者。
结论
时间序列和信号是组织数据的自然方式。傅立叶变换提取嵌入在数据中的频率信息。这种方法在音频工程、物理和数据科学等领域有无数的用例。对于实际应用,傅立叶变换通过快速傅立叶变换(FFT) 算法进行离散化并提高计算效率。FFT 将在我的下一篇文章中讨论。
资源
⭐️成为会员使用我的推荐链接,并获得充分的媒体上的每一篇文章。您的会员费直接…
shawhin.medium.com](https://shawhin.medium.com/membership)
时间序列平滑以实现更好的聚类
机器学习的金融序列处理
莱蒂·施密在 Unsplash 上拍摄的照片
在时间序列分析中,脏的和杂乱的数据会改变我们的推理和结论。这是真的,尤其是在这个领域,因为时间依赖在处理时间序列时起着至关重要的作用。
噪声或异常值必须按照特定的解决方案小心处理。在这种情况下, tsmoothie 软件包可以帮助我们在准备时间序列进行分析时节省大量时间。 Tsmoothie 是一个用于时间序列平滑和异常值检测的 python 库,可以以矢量化的方式处理多个序列。它很有用,因为它可以提供我们需要的预处理步骤,如去噪或剔除异常值,保留原始数据中的时间模式。
在本帖中,我们使用这些小玩意来改进聚类任务。更准确地说,我们试图通过一种无监督的方法来识别财务数据中的一些变化。最后,我们将期望指出收盘价中的清晰模式,这些模式可用于检查市场的隐藏行为。
数据
如前所述,我们操作金融时间序列。有许多工具或预制数据集可以提供和存储金融数据。对于我们的目标,我们使用从 Kaggle 收集的数据集。2000–2018 年的股票数据是从 2000 年到 2018 年大约 39 只不同股票的股票价格的清理集合。它每天报告成交量、开盘价、最高价、最低价和收盘价。我们关注接近的价格。
出于演示的目的,我们考虑亚马逊的股票价格,但同样的发现也出现在其他股票信号中。
亚马逊收盘价历史和分布
时间序列平滑
我们工作流程的第一步包括时间序列预处理。我们的策略非常直观有效。给定收盘价的时间序列,我们把它分成小的滑动块。然后对每个片段进行平滑处理,以去除异常值。平滑过程对于减少我们系列中出现的噪声和指出可能随时间推移出现的真实模式是必不可少的。
Tsmoothie 为我们的目的提供了不同的平滑技术。它还具有内置的实用程序来运行滑动平滑方法。原始时间序列被分割成相等的窗口片段,然后被独立地平滑。我们选择局部加权散点图平滑(洛斯)作为平滑过程。
LOWESS 是一种强大的非参数技术,通过单变量或多变量平滑来拟合给定数据的平滑线。它对移动范围内的点集合进行回归,并根据横坐标值周围的距离进行加权,以计算序数值。平滑参数(α)的选择通常完全基于“重复试验”的基础。没有特定的技术来选择它的精确值。特定值的选择可能导致“过平滑”或“欠平滑”。
下面是应用上述程序的结果,滑动窗口长度为 20 天,且α等于 0.6。换句话说,我们正在为每个生成的窗口计算一个 LOWESS。
AMZN 股票价格的第一个平滑窗口
时间序列聚类
第二步包括使用聚类算法来识别我们的时间序列中的行为。创建等长窗口旨在轻松解决这一任务。
一般来说,将不同的时间序列聚类到相似的组中是具有挑战性的,因为每个数据点都遵循一个时间结构,为了获得满意的结果,我们必须遵守这个时间结构。标准聚类算法中使用的距离度量,如欧几里德距离,通常不适用于时间序列。一个更强的方法是用比较时间序列的度量代替默认的距离度量,例如动态时间扭曲。
使用 K-均值和动态时间弯曲度量搜索 4 个聚类产生以下结果:
带平滑的缩放聚类中心和相关样本
正如我们所看到的,很明显产生了 4 个不同的集群,代表了 4 种不同的市场运动:上升趋势(集群 0 )、下降趋势(集群 1 )、下降转折点(集群 2 )、上升转折点(集群 3 )。我们可以在不计算平滑度的情况下对原始时间窗口做同样的事情,并进行比较。
缩放的聚类中心和相关样本没有平滑****
现在这四组之间的差异并不明显。对生成的集群进行解释更加困难。从聚类算法中生成有意义的组的能力是任何无监督方法的更重要的先决条件。如果我们不能做出解释,结果就不能用来做决定。在这个意义上,采用平滑预处理可以帮助分析。
AMZN 收盘价和相应的窗口簇。通过平滑获得聚类
摘要
在金融领域,波动性的概念是决策的基础。它衡量市场中存在的不确定性,即风险。在这里,我们更深入地扩展了短期市场机制的概念。我们确定了四个明确的市场条件,平滑我们的时间序列块,以更好地理解数据的真实动态。在本文中,我们利用了金融聚类应用程序中的时间序列平滑,但这种方法在其他一些涉及时间序列分析的竞赛中也是有效和有用的。
保持联系: Linkedin
时间序列平滑用于更好的预测
降低传感器中的噪声,以更好地预测太阳能电池板的发电量
亚历山大·埃里明在 Unsplash 上的照片
在时间序列预测中,脏的和杂乱的数据的存在会损害最终的预测。这是真的,尤其是在这个领域,因为时间依赖在处理时间序列时起着至关重要的作用。
噪声或异常值必须按照特定的解决方案小心处理。在这种情况下, tsmoothie 软件包可以帮助我们在准备时间序列进行分析时节省大量时间。 Tsmoothie 是一个用于时间序列平滑和异常值检测的 python 库,可以以矢量化的方式处理多个序列。它很有用,因为它可以提供我们需要的预处理步骤,如去噪或剔除异常值,保留原始数据中的时间模式。
在本帖中,我们用这些小玩意来改进预测任务。更准确地说,我们试图预测太阳能电池板的日发电量。最后,我们将期望从我们的去噪过程中受益,并产生比没有预处理的情况更好的预测。
数据
在 Kaggle 上有一个用于我们目的的真实数据集。该数据存储了安装在私人住宅屋顶上的太阳能电池板的日发电量。数据自 2011 年开始记录,以时间序列格式呈现 3 个不同的来源:
- 房子每天的煤气消耗量。
- 房子的日常用电量。其中负值表示太阳能超过了当地的电力消耗。
- DC 到交流转换器上功率计的每日值。这是目前累积的太阳能电力。我们不需要累计值,而是需要每日的绝对值,因此,我们进行简单的微分运算。这是我们的预测目标。
正如我们从 raw 系列的图中可以注意到的,存在大量噪声。这对于传感器记录的数据来说是正常的。如果我们的数据源受到外部气象条件的影响,或者如果传感器质量不好,并且位于非最佳位置,情况会更糟。
幸运的是,我们有知识和工具来实现我们预测任务的良好结果。
时间序列平滑
我们工作流程的第一步包括时间序列预处理。我们的策略非常直观有效。我们获取目标时间序列(发电量),并用一个神奇的工具对其进行平滑:每个数据科学家都必须知道的卡尔曼滤波器、、。
一般来说,在时间序列任务中使用卡尔曼滤波器的最大优点是可以使用状态空间形式来表示未观察到的组件模型。以状态空间形式表示时间序列模型的范围是一组通用算法(包括卡尔曼滤波器)的可用性,用于高斯似然的计算,其可以在数值上最大化以获得模型参数的最大似然估计。著名的软件使用这种表示来拟合像 ARIMA 这样的模型并不是偶然的。在我们的特殊情况下,我们使用卡尔曼滤波器和状态空间表示来建立一个未观察到的组件模型。
到目前为止,所有这些解释听起来都很棘手,但我想向您保证…Tsmoothie可以轻松地构建未观察到的组件模型,以非常简单有效的方式操作自定义卡尔曼平滑。在这个阶段,我们可以释放我们的想象力,从水平、趋势、季节性、长期季节性中检测哪些成分有助于创建我们正在观察的时间序列。365 天的水平和长季节性对我们来说听起来不错。我们只需为每个组件假设添加一个“置信度”,就完成了。
对所有系列进行卡尔曼平滑(仅用于视觉目的)。我们只使用平滑的目标
得到的平滑时间序列保持原始数据中存在的相同时间模式,但是具有一致且合理的噪声降低。
****专业提示:如果我们的系列出现 NaNs,这不是问题,这个过程非常有效,它是一个非常强大的工具,可以填补我们数据中缺失的空白…这就是卡尔曼平滑的魅力。
时间数列预测法
第二步是建立一个神经网络结构来预测未来几天的发电量。首先,我们在原始数据上拟合一个模型,其次,我们尝试在平滑的序列上拟合。平滑数据仅用作目标变量,所有输入序列保持原始格式。平滑标签的使用旨在帮助模型更好地捕捉真实模式并丢弃噪声。
我们选择 LSTM 自动编码器来预测未来 5 天的发电量。使用keras-hype tune执行训练程序。该框架以非常直观的方式提供了神经网络结构的超参数优化。我们对一些参数组合进行网格搜索。所有涉及的两项培训都是如此。
基线只是现值的重复
我们可以想象,预测误差是时间范围的函数。第二天的预测比未来五天的预测更准确。重要的一点是,就所有时间预测范围的预测精度而言,平滑过程提供了很大的好处。
对未知测试数据的预测
摘要
在这篇文章中,我们利用了预测场景中的时间序列平滑。我们应用卡尔曼滤波器来平滑我们的原始数据并减少噪音的存在。这一选择被证明在预测准确性方面是有利的。我还想指出卡尔曼滤波器在这一应用中的强大功能,以及它在构建未观察到的组件模型时成为一种良好工具的能力。
保持联系: Linkedin
是时候改变了(数据)—使用 Pivot 和 Python,借助 Power BI 跟踪您的个人财务状况。
采用微软 POWER BI 的数据科学
一种使用 python 在 Power BI 中实现完全动态透视的方法,同时还可以享受跟踪个人财务的乐趣
在 Power BI 中学习一些关于 pivot 和 python 的新知识,同时构建一种更好的方法来跟踪您的个人财务状况,这不是很好吗?
如果你想要这个仪表盘👇那么这个故事是给你的!
个人财务仪表板
除了有趣的部分,我们还学到了以下内容:
- 如何在 Power BI 中进行透视,同时保持所有列完全动态,使添加新数据变得容易,而无需接触我们的模型。
- 动态检测 Power BI 中的数据类型,并使用自定义函数转换列。
- 在 Power BI 中使用 Python 清理和转换数据。
数据
从我的 Github 库下载样本数据。
github.com](https://github.com/sebastianzolg/dynamic-pivot-in-powerbi)
让我们快速浏览一下我们的数据。
在 Excel 中打开 personal-spendings.xlsx 文件,注意它的简单结构。这样做的目的是让你从不同的地方添加数据变得容易,比如你的银行账户或者你正在做的任何项目。
您可以随意添加任意多的细节,但是输入数据要简单,这样跟踪数据就不会太难。我们让权力 BI 为我们做繁重的工作。
在枢轴上转动
Pivot 是将我们的数据维度转换为新形式的过程。在我们的例子中,我们希望初始的类别作为一个特征矩阵,以数量作为值。
将左侧数据集透视到右侧数据集
Power BI 中的 pivot 面临的挑战是在初始建模之后引入新标签(列)所需的工作。
这是因为 Power BI 通过名称静态引用列和其他元素*。这迫使我们每次推出新品类时都要接触我们的模型。我们需要一个解决方案!*
构建我们的模型
在 Power BI 中,点击**获取数据,选择 Excel ,点击连接。**从我的 Github 存储库中打开样本数据,或者选择您自己的数据集。
选择财务电子表格,查看数据并点击转换。
第一步,我们将列月和年转换成一个单独的日期列。
选择两列并点击合并列。
选择自定义作为分隔符类型,并使用斜线( / )作为分隔符。将列命名为日期并点击确定按钮。搞定了。
现在是时候将我们的数据转换到目标结构中,其中类别成为我们的列,数量成为我们的值。
确保您已经选择了类别列,然后单击透视列。
从数值下拉字段中选择金额。如果我们在同一个月有多个条目,我们希望 Power BI 使用 Sum 作为聚合函数。
点击确定。
结果应该如下面的屏幕所示。
请注意以下三点:
- 我们有很多无效数据,因为不是每个类别都有收益和支出。
- 我们对支出类型的值有负数,这可能很难想象。
- 我们没有每个日期(月)的总计栏。
为了满足我们的需求,我们在 Power BI 中使用了一个 Python 脚本。
点击运行 Python 脚本并插入下面的脚本。
让我们分解一下,看看这个 python 脚本为我们做了什么。
首先,我们动态选择数据类型为编号为的所有列。这样我们就不用硬引用任何列,并且可以很容易地添加新列。
numeric_cols = dataset.select_dtypes(include=np.number).columns
接下来,我们用数字 0 替换所有的空值 。
dataset.fillna(0, inplace=True)
现在我们已经选择了所有的数字列,我们只需在所有的行上调用abs()
函数,将所有的负数转换成它的绝对等效值。
dataset[numeric_cols] = dataset[numeric_cols].abs()
最后,我们对所有行及其数字列进行求和。我们将结果存储在名为 GrandTotal 的新列中。
dataset['GrandTotal'] = dataset[numeric_cols].sum(axis=1)
为了使用结果,我们单击表来扩展数据集。
在运行 Python 片段后,Power BI 试图自动检测数据类型,但在这里没有做好。
此外,这一步添加了对命名列的硬引用。
因为我们希望它是完全动态的,我们通过点击 X 图标从应用步骤面板中移除了变更类型步骤。
**等一下!**当我们不能使用 Power BI 类型检测时,我们如何动态地输入数据?我们需要一个函数!
右键点击查询面板,选择新建查询>空白查询。
首先,我们给新的查询函数起一个好听的名字,比如AutoDetectAndTransformTypes
。
接下来,我们通过点击高级编辑器图标调出编辑器。插入下面的脚本,点击完成。
这是怎么回事? 这个剧本的灵感来源于 这里的 。向作者致敬。这篇文章很好地解释了脚本的作用。然而,我介绍了一些简化和另一种类型检测方法。
简而言之,脚本检查每一列,并通过检查每个值来推断正确的数据类型。然后,它构建列和数据类型的映射,并将其传递回 Power BI。
现在我们通过点击公式栏中的 fx 图标来调用此功能。
没看到公式栏? 转到 查看 并勾选 公式 栏 旁边的方框。
要调用数据集上的函数,请输入下面的公式并点击 enter。
= AutoDetectAndTransformTypes(dataset)
**搞定!**如您所见,我们的函数运行得非常好,将所有数值转换为类型十进制数并将日期字段转换为类型日期。
要开始可视化您的数据,点击关闭&应用。
构建仪表板
现在我们有了如此简单的数据,我们可以轻松地构建一个漂亮的报告。我让你自己去做。
如果您不想自己动手,我会将 Power BI 模板放在我的 Github 存储库中的数据文件旁边。只需克隆整个存储库并从同一个目录中打开dynamic-pivot-in-power bi . pbit文件。
由于我们的旋转模型,这都是视觉上的拖放。不需要代码或公式。
添加新类别
让我们来看看这一解决方案的强大功能。在 Excel 中打开原始数据,在列表底部引入任何新的类别和。别忘了救它。
回到 Power BI,您唯一需要做的就是刷新数据。
点击刷新,选择仪表板上的任何视觉效果,看到新添加的类别自动出现在字段列表中。勾选旁边的方框就大功告成了。
当然,这个字段也是总计计算的一部分。一切都充满活力。
**就是这样!**你做得很好。
就这样吧。
—塞巴斯蒂安
是时候将敏捷编程和敏捷数据科学结合起来了
数据科学家来自火星,软件工程师来自金星(第五部分)
敏捷软件 2.0 宣言和过程
在本系列的第 1 部分中,我们研究了软件和模型之间的主要区别;在 Part 2 中,我们探讨了将模型与软件混为一谈的十二个陷阱;在第 3 部分中,我们看了模型的进化;在第 4 部分中,我们经历了模型生命周期。现在,在本系列的最后一部分,我们将讨论模型生命周期和敏捷软件开发方法应该如何结合在一起。
基于我们之前的讨论,我们主要关心的是模型生命周期过程——及其迭代的价值发现、价值交付和价值管理——如何能够与传统的敏捷软件开发方法相结合。本文的重点是这两种方法的结合;关于使数据科学或模型生命周期敏捷,这是 而不是 。模型生命周期过程本身是迭代的和敏捷的。
敏捷的历史
敏捷的根源可以追溯到 20 世纪 30 年代的敏捷制造。在他们关于“敏捷创新的秘史”的文章中,作者——达雷尔·里格比、杰夫·萨瑟兰和竹内广孝——注意到了这一历史背景。
一些人将敏捷方法追溯到弗朗西斯·培根在 1620 年对科学方法的阐述。更合理的起点可能是 20 世纪 30 年代,当时贝尔实验室的物理学家和统计学家沃尔特·休哈特(Walter Shewhart)开始将计划-实践-研究-行动(PDSA)循环应用于产品和流程的改进。休哈特将这种迭代和增量开发方法教给了他的学生 W. Edwards Deming,后者在二战后的几年里在日本广泛使用了这种方法。
软件中敏捷性概念的早期应用之一(例如,它的持续和迭代性质)可以追溯到 20 世纪 50 年代。根据专家 Craig Larman 和 Victor Basili 的说法,早在 1957 年,IBM 服务局公司的 Gerald Weinberg 和 Bernie Dimsdale 就在洛杉矶进行增量软件开发。然而,敏捷的诞生通常归功于 2001 年犹他州雪鸟的一次会议。以下引自《大西洋月刊》的一篇文章抓住了这一诞生的精神:
但正是在这里,一群软件反叛者聚集在一个滑雪胜地的白雪皑皑的群山中,于 2001 年起草并签署了该行业历史上最重要的文件之一,这是编码集的一种独立宣言。这个为期三天的小型务虚会将有助于塑造大部分软件的想象、创建和交付方式——或许还有世界的运行方式。
正是在这个地方,敏捷宣言和敏捷十二原则诞生了。详细研究敏捷宣言是值得的,这样我们就可以为敏捷数据科学开发另一个宣言。
敏捷软件开发宣言
敏捷软件开发宣言由四个关键陈述组成:
- 过程和工具之上的个人和交互
- 综合文档之上的工作软件
- 合同谈判中的客户协作
- 响应变化而不是遵循计划
该文档继续指出虽然右边的项目有价值,但我们更重视左边的项目*。因此,敏捷思维是对当时现有最佳实践的补充,而不是替代。有时候,敏捷被用作不提供全面的文档或没有架构设计或开发计划的借口。讽刺的是,敏捷本身已经变得更像一个过程和方法,而不是关注个人和他们的互动。*
敏捷数据科学宣言
在他 2013 年关于敏捷数据科学的第一本书和 2017 年名为敏捷数据科学 2.0 的修订版中,Russell Jurney 展示了如何构建一个数据平台来构建、部署和完善分析应用。他将敏捷数据科学的目标定义如下:
敏捷数据科学流程的目标是记录、促进和指导探索性数据分析,以发现并遵循关键路径获得引人注目的分析产品。
然后,他根据以下七条原则组织了他的敏捷数据科学宣言*。*
1.迭代,迭代,迭代:表格,图表,报告,预测。
2.船舶中间输出。即使失败的实验也有产出。
3.执行任务的原型实验。
4.在产品管理中整合数据的专制观点。
5.当我们工作时,在数据价值金字塔上爬上爬下。
6.发现并追求通向杀手级产品的关键路径。
7.获取 meta。描述过程,而不仅仅是结束状态。
这些原则针对的是我们在之前的文章中概述的软件和模型之间的一些关键差异——主要是以实验为中心的开发过程和基于使用数据的归纳的推理机制。
在我们看来,这份敏捷数据科学宣言遗漏了一些关键发展:
- ***数据产品与模型:*重点是以敏捷的方式用 web 前端构建(大)数据产品。宣言中缺少持续和迭代的价值发现、价值交付和价值管理的丰富内容。
- ***数据科学家 vs 跨学科团队:*正如我们之前讨论过的,模型生命周期管理正在从预测即服务转向模型工厂,这导致了新角色的出现,如 ML 工程师、模型操作和数据操作专家。这需要更多地关注跨学科团队。
- ***应对变化与颠覆:*敏捷数据科学宣言更关注应对变化,而不是用创新产品颠覆市场。
现在,我们来看看如何将敏捷软件开发和数据科学宣言结合到我们所谓的敏捷软件 2.0 宣言中。
敏捷软件 2.0 宣言
特斯拉人工智能高级总监安德烈·卡帕西(Andrej Karpathy)介绍了术语软件 2.0 ,并将其与传统编程进行了对比,他称之为软件 1.0。具体来说,他说:
软件 1.0 的“经典栈”是我们都很熟悉的——它是用 Python、C++等语言编写的。它由程序员写给计算机的明确指令组成。通过编写每一行代码,程序员用一些期望的行为来识别程序空间中的特定点。
相比之下,软件 2.0 可以用更抽象、对人类不友好的语言编写,比如神经网络的权重。没有人参与编写这段代码,因为有很多权重(典型的网络可能有几百万),直接用权重编码有点困难(我试过)。
虽然 Karpathy 仅将软件 2.0 一词用于使用机器学习和深度学习开发的系统,但很明显,在可预见的未来,我们将需要软件开发的 1.0 和 2.0 版本共存。因此,我们应该将敏捷软件开发的关键价值与敏捷模型开发结合起来。我们认为这一联合宣言的目标如下:
通过促进(数据、软件和模型的)持续集成、交付和(机器)学习,我们正在发现开发由(AI/ML)模型驱动的软件的更好方法。
将敏捷软件开发宣言扩展为敏捷软件 2.0 宣言,我们有以下四个基本价值观:
- ***多学科团队和个人&互动:*当我们将传统软件 1.0(例如,传统编程)与软件 2.0(例如,机器学习或更一般的模型构建)相结合时,我们正在将数据、软件和模型生命周期相结合。这要求我们关注来自数据、软件和数据科学的多学科团队,包括业务分析师、数据分析师、架构师、软件开发人员、数据科学家、ML 工程师、DevSecOps、MLOps 或 ModelOps 以及 AI ethicists 没有一个人能够拥有所有这些能力,而且这些人也不仅仅来自一个学科;它们需要是由生命周期中的阶段决定的多学科。
- ***有洞察力的行动和决策以及工作软件:*传统的敏捷软件开发加速了有用的工作软件的时间线,通常被称为最小可行产品(MVP)。然而,在这个敏捷软件周期中强制进行数据探索和模型构建通常会导致简单的描述性分析,而没有洞察力或预测性或规范性模型。模型构建或数据科学敏捷周期需要从软件敏捷周期中分离出来(如下所述),以便产生同样有洞察力的工作软件。
- ***数据&模型探索和客户协作:*敏捷软件开发强调客户协作,因为传统的瀑布方法过度索引了从客户收集需求、设计软件、构建和测试。软件 2.0 带来了数据和模型,为这个等式增加了一个维度。客户可能无法总是清楚地表达他们的偏好或原因,或者他们为什么做出某些决定。拥有“数据讲述故事”和“模型展现数据本质”的能力对于软件 2.0 至关重要。
- ***创新&颠覆性和响应变化:*敏捷软件开发非常善于响应变化——尤其是客户要求的变化。根据我们的经验,软件开发的短迭代周期(即 sprints)通常会导致功能的增量改进,但不会通过使用可用的数据和从模型中获得的洞察力来为创新和破坏提供足够的机会。
图 1:敏捷软件开发宣言(来源:Agilemanifesto.org)和敏捷软件 2.0 宣言
在讨论了敏捷软件 2.0 宣言之后,我将详细讨论如何将敏捷软件开发生命周期与模型开发生命周期结合起来,这在我之前的文章中已经讨论过了。
集成的敏捷软件 2.0 流程
考虑到软件和模型之间的根本差异——以及上面敏捷软件 2.0 宣言中提到的原因——我们需要在时间方面将传统的敏捷软件冲刺与模型生命周期分开。同时,我们不希望将它们作为两个独立且不同的敏捷周期来运行,因为这将阻止我们实现传统软件和模型的全部好处。那么,解决办法是什么呢?
一个解决方案包括交错 sprint 周期,并为软件 sprint 和模型 sprint 提供单独的时钟。在这个交错的过程中,有几个关键的交互点值得详细说明:
- ***产品启动/积压:*在产品的启动阶段,尤其是结合了传统软件和模型的产品,软件、数据和建模团队需要一起决定客户想要的关键功能、可用的数据、需要产生的潜在见解或需要测试的假设,以及产品的关键差异化因素。一旦完成了这些,软件和建模团队就可以独立地执行他们的冲刺了。软件团队可以通过他们的标准 sprint 过程,而建模团队使用数据和模型进行探索和实验,正如我们在模型生命周期中的 价值交付循环 所描述的那样。
- Sprint Backlog: 当建模团队已经验证了假设并生成了洞察之后,被测试的模型和数据管道被放入 Sprint Backlog 中。当软件团队完成了它的标准冲刺后,它会将测试过的模型合并到软件的当前版本中。在这一步,软件开发人员、数据工程师、ML 工程师和数据科学家必须合作调整模型并大规模部署它们。
- ***完成的工作和价值交付:*这个软件和模型集成 sprint 然后产生一个软件,它有一个准备好部署的嵌入式模型。在这个集成冲刺的最后,模型被部署到生产环境中,价值交付过程开始了。与传统软件不同,在传统软件中,软件可以进入操作阶段,对于具有嵌入式模型的软件,我们需要经历价值交付阶段,以确认模型仍然按照生产环境中的要求执行。一旦完成,集成模型就可以进入价值管理流程。
图 2:敏捷软件 2.0 过程
总之,敏捷软件 2.0 需要整合来自敏捷软件开发和敏捷数据科学的领先敏捷方法,以帮助希望部署嵌入 AI/ML 模型的软件的客户获得投资回报。
数据、软件和 AI/ML 模型的融合才刚刚开始。广泛的软件工程、软件开发和维护方法对于 AI/ML 模型来说是不存在的。最佳实践刚刚出现,未来十年将会看到该领域更多的学术和行业进步。我们以声称数据科学家来自火星,软件开发人员来自金星开始这个系列。在过去的几年里,这些学科逐渐融合在一起。这个由五部分组成的系列只是软件开发人员和 AI/ML 建模人员关注的主要领域的开始。
是时候做出改变了
将 MacOS 默认值从 Python 2 升级到 Python 3
2020 年正在如火如荼地进行中,如果你还没有这样做的话,是时候更换你的默认 python 了。自 1 月 1 日起,Python 2.7 的维护已经停止。这意味着您当前版本的 python 现在是遗留代码!虽然在您的系统上保留一个版本的 Python 2 对于旧的脚本来说仍然很方便,但是现在是时候更新您的系统了。在本简报中,我们将下载 Python 3,将其设为默认,并将 Python 2 存储为别名。现在开始,让我们探索一下当前的 Python 环境。
来源 XKCD
要找到我们的默认 Python 在系统中的位置,只需输入:
which python
这将向您显示默认 Python 的路径。如果您像我一样在/usr/local/bin 系统之外有一个默认的 Python,这可能会提供一些信息。我的默认 Python 是 Anaconda 发行版的一部分。要查看如何更改 Anaconda 发行版中的默认 Python,请向下滚动一点,越过默认方法。
默认 MacOS 系统
要查看 Python 的当前版本,只需输入:
python --version
我现在的版本是 2.7.15。要改变 MacOS 上的默认版本,我们可以从【https://www.python.org/downloads/mac-osx/】Python 下载页面()下载最新的安装程序开始。下载安装程序会将新版本插入/usr/local/bin。在更改默认 Python 之前,让我们将旧的 python2 版本链接到 Python 2 命令。
echo "alias python2=/usr/local/bin/python2.7" >> ~/.bashrc
别名“python2”意味着当我们键入命令时,默认的 python 版本将是我们的 Python 2 发行版。现在让我们为新的 Python 3 创建一个别名。
echo "alias python=/usr/local/bin/python3.8" >> ~/.bashrc
应该可以了。这种方法的局限性在于,如果您想要更新 Python 版本,则必须手动重置别名。这意味着对于 Python 3.9,您必须重新执行之前的命令。
使用 Anaconda Base 升级
我的系统使用除 Anaconda 之外的默认 Python 发行版。要更改默认 Python 版本,只需输入:
conda install python=3.8.1
这将安装 Python 3.8.1。要在 Anaconda 上查看所有可用的 Python 版本,只需输入:
conda search python
安装较新版本的 Python 可能需要几分钟时间,并且额外的冲突解决方案是您之前下载的包可能与较新版本的 Python 不兼容。
你有它!一个简单的更新 Python 默认值的步骤,这样你就可以为这十年做好准备了!我叫科迪·格利克曼,你可以在 LinkedIn 上找到我。
利用数据科学了解气候变化:大气 CO2 水平(基林曲线)——模型拟合和时间序列分析
TL;博士:
也称为“执行摘要”
欢迎光临!本文是数据科学的一个完整项目。本文涵盖了 1)数据准备 2)建模、和 3)模型评估的领域。这个项目着眼于一个时间驱动的季节性数据集,我们将与熊猫库合作。对于建模和拟合,我们使用 Numpy 的 polyfit 和 Scipy 的 optimize 库。我将带你经历提出和构建模型的思维过程,以及如何验证它们。
对于更高级的读者,我将在另一篇文章中讨论如何通过 PyStan (斯坦的Python 实现)使用蒙特卡罗方法对同一数据集执行预测分析**。**
你可以在这里找到完整的代码。
背景
斯克里普斯二氧化碳项目
该项目基于自 1958 年以来在夏威夷莫纳罗亚天文台收集的二氧化碳浓度数据。该数据集由斯克里普斯海洋研究所编制,因此被称为 斯克里普斯二氧化碳数据集 。这是迄今为止最全面和最一致的科学测量之一,自 20 世纪 70 年代以来,美国国家海洋和大气管理局(NOAA)的 GMD 计划一直在努力扩大这一测量。
从 1980 年到 2010 年的月平均大气 CO2 浓度(来源)
龙骨曲线
数据集的结果曲线被命名为 基林曲线 ,以纪念启动监测程序的科学家查理斯·大卫·基林。基林曲线显示了二氧化碳浓度的平均增长(~ 2 ppmv/年),并且是温室气体如何导致气候变化的最权威的证据之一。基林曲线有助于识别二氧化碳的季节变化、自然和人类活动之间的相互作用以及现代工业时代二氧化碳浓度的加速。
数据准备
数据下载
您可以直接从 Scripps 程序主页下载数据。csv 格式:https://Scripps CO2 . ucsd . edu/data/atmospheric _ CO2/primary _ mlo _ CO2 _ record . html。在我们的调查中,我们将使用文件名为“weekly _ in-situ _ co2 _ mlo . CSV”的每周原位 CO2 数据集。请注意,默认的原位 CO2 数据是每月——因此请确保您下载的是正确的文件。
数据的前 44 行是关于文件的信息,应该在导入 Python 之前丢弃。第一列表示记录的日期,格式为“yyyy/mm/dd”。第二列表示大气 CO2 浓度,单位为百万分率(ppm)。
数据导入
我们将使用熊猫图书馆来存放我们的数据。对于那些不熟悉熊猫的人来说,这是一个让你用一堆有用的特性创建数据框架的库。如果你正在进入数据科学领域,你会经常用到它!
df = pd.read_csv('weekly_in_situ_co2_mlo.csv',names=['date','CO2 ppm'])
print('Dataframe has **%d** data points of **%d** features'
%(df.shape[0],df.shape[1]))df.head()
数据的输出(。csv 文件)导入。
将日期列转换为“日期时间”格式
当前日期采用字符串格式。我们将其更改为 datetime 对象,这样 Python 就可以识别出时间线上的数据点。熊猫对此有一个函数叫做“到 _datetime ”
df['date'] = pd.to_datetime(df['date'],format='%Y/%m/**%d**')
df.head()
将“日期”列更改为日期时间后的输出
创建“天”列
虽然 date 列用于将数据绘制成时间序列,但它对我们的建模步骤用处不大。为对应于第一天之后 N 天的的数据创建一个新参数会提供更多信息。至少,它使我们的模型参数易于解释**。**
*# take the first row as the start date* epoch = df['date'][0]*# take integer values of the days from epoch* df['days'] = (df['date']-epoch).dt.daysdf.head()
添加要在我们的模型中使用的“days”列的输出。请注意,“天数”列将用于查找模型的参数,而“日期”列将用于绘图。
数据观察
数据科学的第一步是调查数据的一般形式(如果可能的话)。这将使我们能够确定用于建模的宏观趋势。
未经编辑的原始数据
在宏观的一瞥之后,对数据进行一些细微的观察也是值得的。对于这个数据集,我将始终查看数据集的第一年、前三年、最后三年和最后一年。
数据集两侧的 1 年和 3 年数据图。
从这两个观察中,我们看到有一个增加的基数趋势和一个波动的季节性趋势。这两种趋势是您将在时间驱动的数据集中看到的典型趋势,尤其是关于自然观测的数据集。
建模和评估
建模
对数据建模是一种尝试,旨在识别生成数据的不同力量。建模可以通过科学调查或从数据中推断来完成。
如果你意识到一些创造数据的基本力量,通过科学调查建模是可能的。有限资源环境中的人口增长,例如病毒在有限人口中的传播,是一个已经在数学中广泛建模的问题。虽然这些数学模型无法解释数据中的所有变化,但它们可以提供塑造模型的关键方向,并且更适用于类似的场景(例如,具有不同初始点的类似环境)。
推断建模是针对数据中的变化进行的,当你不知道这些变化是如何产生的时候。推理建模仅限于指数或正弦曲线的基本集合,因为复杂的多项式函数往往会过度拟合数据,并且具有有限的可推广性。
估价
可以通过视觉和数字两种方式进行评估。目视评估可通过目视检查模型生成数据与实际数据来进行。当差异较大或数据中有未说明的趋势时,目视检查非常有用。重要的是从建模数据中创建相关图表,以查看剩余数据是否显示其他趋势。然后,可以通过添加额外的数学模型来解释这些数据。
数值评估通常采用 R 平方值的形式。r 平方值显示预测(或回归)解释的原始数据方差的百分比。接近 1.00 的 R 平方值更好(有可能过度拟合数据),而接近 0 的值更差。(负的 R 平方值也是可能的,但是我们在这里不考虑这个概念。)R 平方值本身并不能揭示无法解释的方差在哪里。噪声引起的方差是不可分辨的,而缺少建模引起的方差是可以改善的。
模型# I——线性基本趋势
线性基本趋势建模
最明显的基本趋势是线性趋势。由于我们还没有考虑季节变化,所以整个模型是一个带有两个参数的多项式——零阶和一阶系数。
Numpy (np)的 Polyfit 库允许我们对数据进行多项式拟合。然后,我们可以使用输出系数值为我们拥有的每个数据点创建合成数据(即,为我们拥有的每个 x 点绘制相应的 y 点)。
coeffs = np.polyfit(df['days'],df['CO2 ppm'],deg=1)
print('Data has a linear trend**\n\**
1st deg coeff: **%.3e** (slope)**\n\**
0th deg coeff: **%.3e** (intercept)'
%(coeffs[0],coeffs[1]))
df['linear trend'] = df['days']*coeffs[0]+coeffs[1]
df['relative ppm (lin)'] = df['CO2 ppm']-df['linear trend']
线性基本趋势的拟合参数值。
线性基本趋势评估
我们首先从模型的外观检查开始。将建模数据叠加到原始数据上显示,我们的线性模型确定了多年来的持续增长。
我们拟合的线性趋势叠加在原始数据之上
现在,我们观察在解释了线性趋势的变化后,数据看起来是什么样的。这是通过简单地从原始数据中减去模型数据来实现的。在代码中,这存储在一个名为**‘相对 ppm(Lin)’的新列中。**
线性趋势无法解释的其余变化。
从这个相对图中我们可以观察到两件事。首先,在剩余的数据中有明显的减少和增加(月牙形)。这表明数据的增长率平均先降低后升高,与线性趋势假设的恒定增长率相反。其次,数据有明显的季节性。这是显而易见的,因为我们还没有在我们的模型中实现季节性趋势,因此季节性仍然无法解释。请注意,当考虑到宏观水平的增长时,可以更好地观察到季节性趋势的幅度。
使用数值分析使用 r 平方,我们发现数据中 97.7%的变化可以用简单的线性趋势来解释。
模型#2 —二次基本趋势
二次基趋势建模
虽然使用高次多项式通常会因其过度拟合和缺乏可推广性而受到反对,但二次多项式,也称为二次函数,被广泛认为是合理的基本趋势。
像线性基本趋势一样,我们使用 Numpy 的 polyfit 库来拟合我们的数据的三个参数。
coeffs = np.polyfit(df['days'],df['CO2 ppm'],deg=2)
print('Data has a quadratic trend**\n\**
2nd deg coeff: **%.3e** (quad term)**\n\**
1st deg coeff: **%.3e** (slope)**\n\**
0th deg coeff: **%.3e** (intercept)'
%(coeffs[0],coeffs[1],coeffs[2]))
df['quad trend'] = df['days']**2*coeffs[0]+df['days']*coeffs[1]+coeffs[2]
df['relative ppm (quad)'] = df['CO2 ppm']-df['quad trend']
二次基本趋势的拟合参数值。
二次基本趋势评估
同样,我们试图通过将趋势叠加到我们的数据上来进行视觉评估。
拟合的二次趋势叠加在原始数据之上。
我们立即看到,二次基趋势是一个比线性趋势好得多的宏观趋势。我们再次将剩余变化绘制到基本趋势上,以识别任何未解释的变化。
二次趋势无法解释的其余变化。
我们看到,以前的(线性)模型的新月形变化现在在新的(二次)模型下得到解释。似乎还有一些更高层次的变异,但现阶段很难直观观察到。
看一下的 r 平方值,我们现在看到 99.4%的变化现在被模型解释了——比以前的模型增加了 1.7 个百分点。
模型# 3——二次基数和正弦季节趋势
二次+正弦趋势建模
既然我们对的基本趋势有些满意,我们可以开始处理的季节性趋势。对于这个模型,我们实现了一个正弦曲线作为我们的季节因素。
基本趋势的参数仍然是二阶多项式函数的三个系数。一条一般正弦曲线也有三个系数** : (1)振幅,(2)频率,和 (3)相位。**
这就是我们可以利用我们的科学调查的地方。我们可以预测每年的季节性变化**。虽然这可能不准确,但我们仍然可以测试假设并观察性能。当我们能够减少拟合参数的数量时,它也为我们节省了大量的计算能力并增加了末端拟合的精度。因为我们的时间是以天为单位的,所以我们可以将频率参数取为 1/365.25,因为每年有 365.25 天。(如果你不知道. 25 的出处,查“闰年”)**
由于我们的模型不再是一个多项式**,我们不能使用 Numpy 的 Polyfit 库。相反,我们使用 Scipy 的优化模块来找到五个(之前是六个)参数的拟合值。**
**def** test_func(t,c0,c1,c2,c3,c4):
**return** c0+c1*t+c2*t**2+c3*np.cos(2*math.pi*f_year*t+c4)
coeffs, coeffs_covariance = optimize.curve_fit(test_func,df['days'],df['CO2 ppm'])
print('optimized coefficient values:')
**for** i **in** range(5):
print('c**%d**: **%.3e**'%(i,coeffs[i]))
df['quad+sin trend'] = coeffs[0] + coeffs[1]*df['days'] +\
coeffs[2]*df['days']**2 +\
coeffs[3]*np.cos(2*math.pi*f_year*df['days']+coeffs[4])
df['relative ppm (quad+sin)'] = df['CO2 ppm']-df['quad+sin trend']
拟合的参数值。请注意,与 Numpy 的 polyfit 库不同,scipy.optimize 要求您显式声明一个函数来拟合数据。
二次+正弦趋势评估
我们的模型在整个数据期间以及第一年和最后五年的原始数据集上的叠加。
****目视检查显示我们的组合模型与我们的数据非常吻合。 r 平方值告诉我们,我们现在已经解释了来自五个参数的数据变化的 99.9% (具体地说,99.8783%)。我们看到,正弦模型的增加使我们的模型的解释能力提高了 0.5 个百分点。
我们应该满足于这 99.9%的解释吗?这就是我们需要警惕过度拟合的地方。任何数据集,只要加入足够多的参数,都可以 100%“解释”。(从技术上来说,任何大小为 N 的数据集都可以通过使用具有 N 个参数的多项式进行 100%匹配)仅使用 5 个参数,现在就对一个3000+数据点数据集进行过度拟合还为时过早。决定归结为剩余的方差是来自噪声**,我们不应该过度拟合,还是来自模式,我们希望将其合并到模型中。这就是为什么我们总是需要查看剩余变化并观察是否存在我们可以建模的模式。**
二次+正弦模型预测后的剩余变化。
观察整个时标的剩余变化,我们首先看到变化的幅度已经显著降低。在线性基础模型中,最大变化(数据最高点和最低点之间的差异)约为 17 ppm,在二次基础模型中为 11 ppm。现在,考虑到正弦季节性,最大变化仅为 6 ppm。我们还看到两个 30 年长的新月形,但是它们的偏斜度很难识别。
第一年和最后一年绘制的剩余变化。
在多年时间尺度上,我们看到仍然有一些周期变化大约 6 个月长度。放大到年尺度**,我们看到低谷出现在每年的 4 月和 10 月左右,高峰出现在 1 月和 7 月。这些半年波动的振幅约为 2.5 ppm ,其中心在宏观尺度上移动。**
奖金——研究正弦不对称
虽然我们的基本趋势是一年(365.25 天),但我们无法解释的变化的周期是 6 个月,即我们正弦周期的一半。这似乎表明我们的年度正弦季节性周期性地抵消我们的数据。
我们可以调查这种偏移是如何发生的,方法是将我们的所有数据逐月叠加,并查看它与我们模型中使用的正弦季节性相比如何。****
为了实现这一点,我们首先将年度差异移至我们的“日期”栏。这确保了我们所有的数据将绘制在 x 轴的同一线段上。在我的代码中,我通过将年份部分重置为 1904 来实现这一点。这与完全删除年份部分略有不同,默认情况下,这将使用 1900 年的“datetime”类纪元年份。这不适用于我们的情况,因为我们的一个数据点有闰日(2 月 29 日),1900 年不是闰年(1904 年是)。
其次,我们需要根据我们在线性和二次基本趋势中看到的每年的平均值增长进行调整。这确保了我们所有的数据将被绘制在 y 轴的同一范围内。在我的代码中,我通过从每年的数据值中减去每年的平均数据值来实现这一点。这意味着我的绘图将以 y=0 线为中心。
*# the list of years represented in the dataset*
dfYears = range(df.iloc[0]['date'].year,df.iloc[-1]['date'].year+1)
**for** year **in** dfYears:
dfYear = df[df['date'].dt.year == year]
*## there's 1992-02-29 in the dataset*
*## and the "epoch" year in the datetime module (1900)*
*## is NOT a leap year*
monthDays = [datetime.strptime('1904-'+str(date.month)+'-'+str(date.day), '%Y-%m-**%d**')
**for** date **in** dfYear['date']]
plt.plot(monthDays,dfYear['CO2 ppm']-np.mean(dfYear['CO2 ppm']),
color='b',alpha=0.1)
最后,我们在聚合图上绘制正弦曲线,以验证我们的假设。为了比较,我在黄色虚线中加入了一个非相移正弦图(从 0 开始到结束)。我用眼睛标记了一个相移,它的图形用橙色虚线表示。
每年绘制的大气 CO2 汇总数据图,并以绝对高度归一化(蓝色,不透明度=0.1)
在此,我们确定数据的季节性实际上是与正弦曲线略有出入**。数据值从谷到峰的增加是非常缓慢的——总计耗时 8 个月。另一方面,数据值的下降,只需要 4 个月。这解释了当数据的增长速度比我们的模型慢并且的下降速度比我们的模型快时 6 个月与模型的差异。**
如果你真的去查阅斯克里普斯项目网站上的文件和出版物,你会发现一个解释,解释了大气 CO2 的增减循环中的这种不对称性。简而言之,大气 CO2 的减少来自夏季植被的生长,因为植物消耗 CO2 并排出 O2。由于大部分地块集中在北半球,本次夏季从5 月持续至9 月,为期 4 个月。CO2 水平变化在大气中的反映延迟约 1 个月,实际下降周期为6 月(高峰)至 10 月(低谷)。****
下一步是什么?
首先,祝贺你走到这一步!现在,您已经了解了为时间序列数据建立模型的基本思维过程。在数据科学方面,你也使用了三个 Python 包——熊猫(数据结构)、Numpy 和 Scipy。Numpy 和 Scipy 都广泛用于数学计算**,Scipy 为线性代数函数提供了更全面的能力。如果你是一个刚进入数据科学领域的学生,你会看到这些软件包更多!**
具体来说,关于这个项目,你可以关闭这一章满意地解决了 99.9%的变化在一个数据集重要的人类;或者尝试对该变化进行甚至更大的定址(诸如微调该正弦曲线以更好地拟合该增大-减小不对称性);或者尝试数据外测试(即投影),以查看模型在数据集中的时间序列中的表现。关于最后一点,我写了一篇单独的文章,使用蒙特卡罗方法来确定模型的投影边界,并通过 PyStan 库实现。
用 Pandas 和 Python 进行时间序列数据分析的时间戳解析
入门
TL;Pandas 为解析时间戳格式提供了很大的灵活性。但是灵活性是以性能为代价的**。在处理标准格式的时间戳时,这仍然是一个很好的解决方案。然而,当时间戳格式不标准时,像记忆和带有预建查找表的映射这样的技术可以比 Pandas 快**几个数量级。跳至总结部分了解不同条件下使用方法的建议。****
我们今天生成的许多数据都是时间序列数据的形式。并且对该数据的分析通常依赖于在一种结构中表示数据的时间戳,该结构服从于基于时间的切片和切割。在标准 Python 和流行的数据分析库中,如 Numpy 和 Pandas,有专门的数据类型来存储基于时间的信息。但是,传入的时间戳通常是不同格式的字符串。并且将这些字符串解析成基于时间的数据类型是一个耗时且有时乏味的过程。
Pandas 中时间相关数据的数据类型。图片来自 pandas.pydata.org。
在标准 Python 中,解析具有已知格式的时间戳字符串的常见方式是 time 模块的 strptime 方法(类似于 C 的 strptime 的接口)。
然而,由于大多数数据科学家不得不在数据集上做比解析时间戳字符串更多的事情,像 Pandas 这样强大的库变得非常受欢迎。在 Pandas 中,解析时间戳字符串最常见的方式是 to_datetime 方法。这种方法提供了很大的灵活性,甚至可以自动推断格式。所以很多人几乎是盲目的使用。
在本文中,我们将研究不同时间戳解析方法在不同类型数据集上的性能和适用性。我们就看什么时候盲目用熊猫,什么时候用别的了。
常用方法
在这个分析中,我们将比较六种解析时间戳字符串集合的常用方法。
1.time.strptime
对于具有已知格式的时间戳字符串,Python 的时间模块提供了这个方法来将字符串转换为 Python Datetime 对象。
示例:
2.Pandas.to_datetime 无需推断
Pandas 库中的这个方法可以转换时间戳字符串的集合,即使没有预先知道的格式。
示例:
请注意时间戳字符串列表 ts_str_list 如何具有不同格式的时间戳。Pandas 自动推断出每个时间戳字符串的格式,然后进行转换。
3.带推断的 Pandas.to_datetime
同样的 to_datetime 方法在 Pandas 中有几个可选的参数。其中一个参数是推断日期时间格式。默认设置为假。然而,通过将其设置为 True ,该方法推断集合中第一个时间戳字符串的格式,然后尝试使用该格式解析其余的字符串。如果推断出的格式与集合中的任何后续字符串都不匹配,则该方法会采用 infer_datetime_format = False 的行为。
这种方法的优点是在解析具有一致格式的字符串集合时节省了大量时间。
示例:
4.具有指定格式参数的 Pandas.to_datetime
to_datetime 方法接受的另一个参数是格式。类似于 time.strptime,这让我们可以显式地定义一种格式来解析时间戳字符串的集合。正如我们将在后面看到的,这种方法的优点是它比让 Pandas 自己推断日期时间要快得多。然而,先决条件是时间戳字符串的集合具有一致且预先知道的格式。
示例:
5.time.strptime 带记忆
记忆是一种存储操作结果的技术,这样就不需要重复操作。使用 memos for the time.strptime 方法可以确保在具有重复时间戳的数据集中,我们不会浪费时间多次解析同一个字符串。当然,在没有任何重复的数据集中,这种方法不会比 plain time.strptime 方法有优势。
示例:
6.预建的查找映射
另一种解析已知格式和已知时间范围的长时间戳列表的方法是创建字符串到日期时间对象的映射。然后,我们可以使用 Python 的 map 方法来获得对应于每个时间戳字符串的 Datetime 对象的列表。
示例:
具有唯一时间戳的实验
1.标准格式的时间戳列表
ISO-8601 是一个被广泛接受的时间相关信息交换国际标准。除了遵循 ISO-8601 标准的时间戳之外,就 Pandas 而言,其他一些时间戳也是一种“标准”格式。这意味着熊猫可以非常有效地解析一些时间戳格式。没有一个详尽的列表(据我所知),但是一般来说,包含日期所有部分的时间戳格式和以年份开始的格式似乎都属于这一类。
现在,让我们看看当给定已知标准格式的时间戳时,这些方法是如何执行的。时间戳的格式在每个数据集中是一致的。我们用不同大小的数据集测试了适用方法的性能。
时间戳为标准格式时比较不同的方法|作者图片
结果显示,在这种情况下, Pandas.to_datetime 明显优于 time.strptime。预构建的查找方法也略微优于 time.strptime 方法。然而,它仍然远远达不到熊猫提供的性能。
2.非标准格式的时间戳列表
现在,如果我们对具有非标准时间戳格式(例如 13–11–2000 04:50:32)的数据集运行相同的测试,我们会看到一些差异。
时间戳为非标准格式时比较不同的方法|作者图片
我们在这里注意到,具有指定格式的 Pandas.to_datetime 执行得最好,而普通的 time.strptime 循环排在第二位。预构建的查找方法花费太多时间来构建地图,因此其性能受到影响。没有 infer 选项的 Pandas.to_datetime 也需要很长时间,因为每个时间戳字符串都需要重复的格式推断。
在 Pandas.to_datetime with infer 的结果中,我们也看到了一些奇怪的行为。我们看到,在数据集规模接近 20000 之前,它的表现异常出色。然后它以与 Pandas.to_datetime 相同的方式执行,而不使用 infer。这是怎么回事?!
这种行为恰好是这些实验中使用的数据集的副作用,但它说明了一个重要的问题。这些实验中使用的数据集是一个时间戳列表,从 2000 年 1 月 1 日上午 12:00 开始,以 1 秒的间隔持续进行。使用的时间戳格式为 dd-mm-yyyy hh:MM:ss 。因此,当 Pandas 试图推断列表中的第一个时间戳时,格式存在模糊性。这是因为时间戳字符串 01–01–2000 00:01:00 的格式可以是 dd-mm-yyyy hh:MM:ss 或 mm-dd-yyyy hh:MM:ss !
因此,当我们有一个以模糊时间戳开始但在列表末尾有明确时间戳的数据集时,Pandas 可能会在到达列表末尾时意识到其推断是不正确的。然后,它会退回到为每个时间戳字符串单独推断日期时间格式的行为。这将导致操作的性能类似于 infer_datetime_format = False 时的情况。
重复数据集上的实验
迄今为止使用的数据集没有重复的。然而,在现实世界中,我们经常处理具有重复时间戳的数据集或来自同一时间段的多个数据集。在工业智能领域(我目前在其中工作),同时处理来自同一时间范围的大量数据集并不少见,因此,在所有这些数据集之间存在大量重复的时间戳字符串。
在下面的实验中,我们将看到我们对时间戳解析的选择会如何根据我们的数据集中有多少重复而改变。
在接下来的实验中,所有数据集都包含一百万个时间戳字符串。在测试过程中,不同数量的副本被注入每个数据集,同时保持数据集大小固定。注入的最低重复数是 0(都是唯一的),最高重复数是 100(数据集中的每个时间戳有 99 个其他副本)。
尝试使用标准格式的时间戳字符串(并且在整个数据集中保持一致)
当时间戳格式为标准|图片由作者提供时,无论有无重复,熊猫都表现良好
我们在这里看到,在处理标准格式时,Pandas.to_datetime 是一个简单的选择。正如所料,随着数据集中重复项数量的增加,内存化和预构建的查找映射会得到改善。
尝试使用非标准格式的时间戳字符串(并且在整个数据集中保持一致)
当时间戳格式不标准时,记忆和预建查找的性能优于 Pandas 图片由作者提供
但是当时间戳的格式不标准并且数据集中有一些重复时,记忆和预建的查找映射都表现得更好。事实上,我最近使用了预先构建的查找映射方法来解析大量时间戳字符串,这为我节省了 8 个多小时!
摘要
对于没有太多重复的数据:
- 已知格式一致的时间戳 使用熊猫并指定格式。
- 具有一致但未知格式的时间戳
使用熊猫 infer_datetime_format = True。 - 没有一致格式的时间戳 使用 Pandas with infer _ datetime _ format = False。
对于有大量重复的数据:
对于有重复的数据,时间戳的格式很重要。因此,这里有一个方便的表格来帮助你选择。
在不同条件下解析时间戳字符串的推荐方法|作者图片
时间戳与时间增量与时间段
了解熊猫时间序列数据结构
数据!不仅仅是数据科学,软件行业的所有其他领域都在处理数据。从系统软件到应用软件,以高效的方式处理和存储数据始终是一项挑战。一种常见且最有效的战斗策略是利用 数据结构。
正如计算机科学家弗雷德·布鲁克斯所说,
在与缓慢的系统进行的永无止境的战斗中,程序员的主要武器是改变内部模块结构。我们的第一反应应该是重组模块的数据结构。
无论怎样强调数据结构都不为过——您可以拥有完美的代码、完美的逻辑、零错误,但是以笨拙的方式存储数据可能会导致应用程序的崩溃。
Pandas 本质上是为分析金融时间序列数据的目的而开发的。它包含了大量的工具来处理日期和时间相关的数据。在本文中,我将解释基本的 pandas 时间序列数据结构、它们可以接受的输入类型以及它们的功能。
处理时序数据的一些基本数据结构是:
- 工时戳记
- 时间差
- 时间段
1)时间戳:
Python 在包含三种不同类型的[datetime](https://docs.python.org/3/library/datetime.html)
模块中提供了日期和时间功能,
- 日期—日、月、年
- 时间—小时、分钟、秒、微秒
- 日期时间—日期和时间的组成部分
python 中的datetime
由日期和时间组成,pandas 的替代方案是将日期和时间封装在一起的Timestamp
对象。它是 python 的datetime
的对等物,但基于更有效的 numpy.datetime64 数据类型。
时间戳插图
熊猫 时间戳 引用具有纳秒精度(十亿分之一秒)的特定时刻。
这是最基本的时间序列数据类型,它将值与特定时刻相关联。时间戳构造函数非常灵活,可以处理各种输入,比如字符串、浮点、整型。下面是它可以接受的不同类型的输入的例子。
用各种输入创建时间戳对象
在上面的示例中,[7]和[8]包含一个标量值。诸如整数或浮点数之类的单个值也可以传递给时间戳构造函数,它返回的日期和时间相当于 UNIX 纪元(1970 年 1 月 1 日)之后的秒数。此外,它允许人类可理解的日期对象与 UNIX 纪元相互转换,以便于计算。当一个 nan 值像[9]中那样被传递时,它返回一个 NaT(不是时间)值,这是 pandas 对于时间戳数据的 null 值。
时间戳构造函数理解时区转换。默认情况下,它不知道时区,但是可以通过在创建对象时将时区传递给参数tz
来使知道时区。这个对象在内部存储了一个 UTC 时间戳值,使得时区之间的转换变得简单。
注意 :如果您的列/索引/对象不支持时区,您将会得到如下错误
时区转换错误
您可以通过本地化(使其具有时区意识)然后转换来克服这个问题。
除此之外,时间戳可以存储频率信息,具有大量对数据操作有用的属性和方法。时间戳的索引结构是 DatetimeIndex ,其类型为 datetime64,包含时间序列特定方法,便于处理。
2)时间差:
delta 的定义之一是它是两个事物或值之间的差异。Timedelta
只不过是时间上的差异,可以指两个间隔之间的时间量或确切的时间长度,并且基于 numpy.timedelta64。
与时间戳构造函数类似,Timedelta 也倾向于接受可变数量的输入。有趣的是,它既可以取正值,也可以取负值。下面是一些例子,让你一窥究竟。
Timedeltas 是 python 和 pandas 的一部分。他们可以
-
彼此相加或相减
-
彼此相除以返回浮点值
-
添加到
timestamp
-
添加到
datetime
-
添加到
date
-
无法添加到
time
与Timestamp
类似,Timedelta
也有大量用于操作数据的属性和方法,相关的索引结构是类型为 int64 的 TimedeltaIndex 。
3)时间段:
时间周期指开始和结束时间戳之间的特定时间长度,该时间长度不变且不重叠。Period
类采用Period
类型,该类型采用一个字符串或整数,并基于 numpy.datetime64 对固定频率进行编码。
通常,一个值和一个频率参数被传递给Period()
构造函数,被指定为freq
的频率参数接受一组预定义的字符串。考虑下面的例子,
时间段示例
在[1] freq='A-OCT'
中,表示频率为每年一次,固定在十月底,而在[3] freq='M'
中,表示频率为每月一次。您还可以指定每季度、每周的频率。要了解更多信息,请点击查看。
时间周期图示
可以使用带有start
、end
和频率参数的period_range()
函数生成一系列Period
对象。
生成一系列期间
频率之间的转换是一项经常需要处理的任务。这可以通过[asfreq](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.asfreq.html)
方法完成。让我们考虑一个将月频率转换为周频率的例子,
频率之间的转换
除此之外,Periods
可以转换成Timestamps
,反之亦然。与Period
对象相关联的索引结构是PeriodIndex
。
感谢你一路阅读到这里。如果你有任何问题、反馈或批评,请在评论区告诉我。祝你今天开心!玩的开心!
时间和数量
一个用 Jupyter notebook 在 Python 中计时代码的例子。
作者: Edward Krueger 数据科学家兼讲师和 Douglas Franklin 助教兼技术作家。
在本文中,我们将点积计算作为基准测试运行时的模型,我们将可视化一些生成点积的方法,看看哪种方法最快。此外,我们还将介绍一些计时代码行和 ipython 单元的方法。
链接到 GitHub 库:https://github.com/edkrueger/dot-product-timing
程序员通过可读性、模块化和运行时间来判断代码质量。本文主要关注 Python 和 Jupyter 中的运行时和计时方法。随着函数处理更多的数据,运行时间可能会急剧增加。在所有条件相同的情况下,越快的函数越好。在本文中,我们将点积计算作为基准测试运行时的模型,我们将可视化几种生成点积的方法,看看哪种方法最快。点积是两个或多个向量相乘的结果。向量是大多数科学算法的基础,也是机器学习和梯度下降的基础。因此,对于数据科学家、机器学习研究人员,甚至是寻找技巧的新程序员来说,这些方法可能会提供洞察力。
Jupyter 方法
属国
# import packagesimport numpy as np
from timeit import timeit
import matplotlib.pyplot as plt
我们将在 Jupyter 笔记本中展示三种不同的时间编码方法。我们计时方法的输出有时被分成“墙时间”和“CPU 时间”两个子类别墙上时间是我们熟悉的时间概念,就像墙上的时钟或秒表的时间一样。墙壁时间记录从过程开始到结束的时间。CPU 时间是 CPU 专用于一个进程的总执行时间或运行时间。CPU 时间将是墙时间的一小部分。这是因为其他不直接涉及 CPU 的操作都包含在 wall time 中。我们将关注“墙时间”,因为它提供了直接和直观的时间。
在开始计时之前,我们需要计时的代码和作为参数传递的数组。为了创建函数计时的数组,我们使用 NumPy 生成两个大小为 1,000 的随机向量作为 NumPy 数组
# create the vectors# create the vectors as numpy arrays
A_arr = np.random.randn(10**3)
B_arr = np.random.randn(10**3)# copy the vectors as lists
A_list = list(A_arr)
B_list = list(B_arr)
现在我们将讨论 Jupyter 笔记本中的三种计时方法;Jupyter 内置的 time 'magic '和 timeit 'magic '方法以及一个名为 timeit 的外部包。
魔术是 Ipython(或 Jupyter)内核特有的,由 Ipython 内核提供。magics 的一个优点是你不必导入一个包。为了正常工作,Magics 使用了在底层语言中无效的语法元素。例如,Jupyter 内核对 Magics 使用“%”语法元素,因为“%”在 Python 中不是有效的一元运算符。然而,`% '在其他语言中可能有含义。
- Jupyter 的内置魔术时间
Jupyter 的内置时间魔术返回单次执行一个单元格或一行的时间。通过在要计时的代码行上插入“%time ”,可以将时间魔法应用于一行代码。时间魔法也可以通过在单元格的开头放置%%time 来应用于单元格。这个“%%”告诉 Jupyter 使用魔法来计时整个细胞。
示例:时间线魔术
# time one execution of numpy’s function%time np.dot(A_arr, B_arr)[out] Wall time: 4.99 ms
例子:时间单元魔法
%%time# timing numpy’s built in functionnp.dot(A_arr, B_arr)[out] Wall time: 4.99 ms
- Jupyter 的内置魔术 timeit
Jupyter 的内置魔术 timeit 会返回同一单元格或行的多次执行的平均值。当对每个单元格或行的单次执行进行计时时,结果可能会有所不同。这种差异可能是由后台运行的计算机进程造成的。因此,使用 timeit 将通过返回一组执行次数的平均值和标准偏差来产生更有价值的结果。这个方法也可以用作单元格或行魔术,但是为了比较,我们只把它实现为行魔术。
例如:朱庇特的时间
# find average of 10 runs of numpy’s dot product%timeit -n 10 np.dot(A_arr, B_arr)[out] 5.14 ± 2.93 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
3)time it 外部包
timeit 包还可以对一个函数的多次执行进行计时。这个包创建了一个函数计时的环境。默认情况下,这种环境关闭垃圾收集和缓存。垃圾收集是通过删除不再需要或不再使用的数据来释放计算机内存空间的自动过程。缓存是由用于在计算环境中临时存储数据的硬件或软件来完成的。这种方法的优点是它使独立的计时更具可比性。缺点是垃圾收集和/或缓存可能是被测函数性能的重要组成部分。
要使用 timeit,我们需要创建一个没有参数的函数。一个简单的方法是传递一个 lambda 函数,不带参数,作为计时的参数。
示例:Timeit 包
# find average of 10 runs of numpy’s functiontime = timeit(
lambda: np.dot(A_arr, B_arr),
number=10
)print(f”{time} ms”.format(time * 1000/ 10))[out] 0.0018839795529856929 ms
以上三种计时方法收敛到相同的结果。NumPy 数组上基于循环的函数最慢,列表上基于循环的函数次之,而 NumPy 的函数是目前最快的。
使用 timeit 的更彻底的方法
另一种方法是编写一个计时器函数,接受要计时的函数及其参数。然后它定义一个等价的(lambda)函数,没有参数,并计时。
def time_function(func, *args, reps=10):
“””
Passes *args into a function, func, and times it reps
times, returns the average time in milliseconds (ms).
“””
avg_time = timeit(lambda:func(*args),number=reps) / reps
return avg_time * 1000
由此,我们得到了与直接使用 timeit 大致相同的结果。
现在,我们可能想看看随着向量长度的增长,时间是如何变化的。我建立了一个函数来计算不同长度的点积函数。使用同一个向量多次计时可能会产生不准确的结果,因为对于某些向量来说,计算点积可能会更快。我将重复不同的向量,以确保公平的测试。
def time_dot_product(func,
vector_length,
input_type = “array”,
data_reps = 10,
reps = 10
):
“””
Takes func, a function that perfroms a calculation on
two vectors (array-lines) and returns the times (in ms)
the function takes to run on std. normal generated
vectors.Arguments:
— — — — —
func (function): a function that performs a calculation
on two vectors (array-lines)
vector_length (int): the length that the random
vectors should be
input_type (str): Controls the data type of the random vector.
Takes values \”list\” or \”array\”
data_reps (int): the number of times to generate
the data
reps (int): the number of time to run the timer
for each data set
“””total_time = 0
for i in range(0, data_reps):
A = np.random.standard_normal(vector_length)
B = np.random.standard_normal(vector_length)
if input_type == “list”:
A = list(A)
B = list(B)
inst_time = time_function(func, A, B, reps=reps)
total_time += inst_time
avg_time = total_time / data_repsreturn avg_time
为了可视化这些函数的行为,我们将使用 Matplotlib 绘制它们的图形。为此,我们对长度为 1 到 1,000,000 的向量的每个点积函数进行计时。对于较慢的计算机,应选择较低的数量级。如果有一台更快的计算机,看看这些函数在更长的向量上的表现可能会很有趣。
# create an array of increasing timesord_mag = 6
lengths = [10 ** n for n in range(0, ord_mag + 1)]
随着向量长度的增加,运行时间的增加几乎是完全线性的。这种线性符合理论:假设算术运算具有恒定的时间复杂度,点积运算具有线性时间复杂度,即 O(n)。基于循环的点积在 NumPy 数组上较慢,因为循环函数必须将 NumPy 数组转换为 python 列表数据类型。这种转换意味着遍历一个 NumPy 数组比遍历一个 list 需要更多的时间。NumPy 函数可能看起来不会增加执行时间。然而,如果我们放大,我们可以看到与其他时间复杂性相似的行为;O(n)。
总之,应该使用 NumPy 进行点积计算。对于其他向量运算也是如此。但是,如果必须编写循环,使用列表比 NumPy 数组作为输入更有效。我们所有的计时方法都返回了相似的结果,尽管格式不同。尽管根据我们的结果,NumPy 点积具有最短的运行时间,但是我们可以说所有的测试都具有相同的渐近复杂度或顺序;O(n)。在实际情况下,算法的运行时间取决于它必须完成的操作数量。记住,所有的事情都是一样的,更快的功能是更好的功能。当编写在大型数据集上运行的代码或编写模块化代码时,我们应该记住这一点。向量对于机器学习应用至关重要。因此,对于任何机器学习计算,NumPy 数组都是可行的。更快意味着更少的计算资源、时间和能量。在计算中,更快的解决方案是更好的解决方案!
我希望这是信息丰富和发人深省的!请随意浏览标题中链接的 Jupyter 笔记本,并亲自尝试一些计时。你的电脑比我的快吗?
我的电脑
|组件|规格|规格
|型号| iMac Retina 5k,27 英寸,2015 年末|
|CPU | 3.2 GHz 英特尔酷睿 i5 |
| RAM | 8GB 1867 MHz DDR 3 |
| GPU | AMD 镭龙 r9 m390 2gb |
| OS | Mojave v 10 . 14 . 5 |
对新冠肺炎实施制裁的时机很重要
越早采取的措施控制得越好
图片来源:freepik
作者:吉塔达斯&凯瑟琳洛佩斯
从第一个新冠肺炎病例出现在一个国家开始,这种病毒已经以不同的速度在不同的国家渗透到不同的社区。在某一时刻,政府通常会实施某种措施和政策,以拯救生命和生计。这些措施包括检测、追踪、增加卫生系统的容量、封锁和旅行限制等等。在这篇文章中,我们研究了一组国家,以了解他们在控制病毒传播方面的表现,以及他们使用的各种措施的时机。
本研究数据&国家
从我们在之前的工作继续,我们在这项研究中纳入了比澳大利亚确诊病例更多的国家。截至 2020 年 6 月 12 日,有 64 个国家出现了更多的确诊病例,并提供了它们的措施数据。因此,本研究将对这 64 个国家进行调查,其截至 6 月 12 日的确诊病例如下图 1 所示。
图一。截至 2020 年 6 月 12 日,世界各国的病例数超过澳大利亚
我们使用了来自人道主义数据交换(HDE)的 2 组数据。
- 数据集追踪全球受新冠肺炎影响的人数,包括确诊、康复和死亡病例。
- 获取强制措施“acaps _ covid 19 _ government _ measures _ Dataset . xlsx”的数据集。
强制措施之间的相互关系
这项研究列出了 33 个国家的措施,从“加强公共卫生系统”到“部分封锁”等等。根据一个国家使用的每个具体措施的时间,每个措施都被缩放到[0,1]。从一个国家报告第一例病例的那一天起,如果没有使用某项措施,则该措施记录为 0。一个国家越早采取一项措施,该具体措施记录的数值就越高(越接近 1)。下图 2 显示了基于皮尔逊相关系数的热图。
图二。包含 33 个测量值的关联热图
上面的热图显示,“加强公共卫生系统”和“经济措施”之间有很强的相关性,“一般建议”和“测试政策”之间也有很强的相关性。它还表明了“部分封锁”和“国内旅行限制”之间的相关性。我们可以理解为这些措施经常一起使用。在所有这些被研究的国家中,“检测政策”是完全独立的,与“边境检查”无关。
实施措施和时机的聚类分析
在研究了 33 个测度之间的相关性后,通过降维得到了一组 28 个主成分。我们使用 K-means 聚类和剪影分数从 64 个国家的数据中得出一组 6 个聚类。
在每个国家出现第一例病例后,在不同的时间采取了不同的措施。所有这 64 个国家都根据其采取措施的时间特点被分配了一个类别号。如下面图 3 中的热图所示,如果度量值引入较早,则度量值更暗,在[0,1]的范围内更接近 1。一组国家使用的指标越晚,热图中显示的颜色越浅。
例如,“有限聚集是在新冠肺炎病例在这些国家开始后的早期阶段在所有国家使用的措施。相反,这项研究中包括的这些国家最近采取的措施是“封锁难民”和“大规模人口测试”。
图三。6 个集群中每个度量的时间平均值的热图
第 1 组(第 1 组)包括澳大利亚—“早起鸟”风格:
这 14 个国家包括澳大利亚、奥地利、比利时、丹麦、法国、德国、意大利、挪威、葡萄牙、西班牙、瑞士、哈萨克斯坦、菲律宾和南非。这些国家采用的措施的特点是:
- 过早或相当早地推出 政府可能推出的大量跨选项措施。这些措施包括“经济措施”、“关闭商业和公共服务”和“加强公共系统”。
- 杰出早期简介**【心理援助与医务社会工作】和【测试政策】相比其他团体。**
这组国家每日确诊病例的 7 天滚动平均值如图 4 所示。在这 14 个国家中,包括澳大利亚在内的 11 个国家已经(或几乎已经)使曲线变平。这些国家中的大多数也经历了病例从高峰到最新状态的大幅减少。澳大利亚政府在早期阶段采取了多项措施,成功地走上了这条曲线。
图 4。包括澳大利亚在内的第一组国家
第 2 组(第 2 类、第 5 类和第 6 类)——“早或晚”风格:
在下图 5 中,这一组包括 18 个国家。参照图 3,这些国家在实施措施方面有两个共同点。
- 很早 一些措施的介绍:与其他国家相比,第 2 组国家很早就采用了"监视和监测"、“关闭学校"和"关闭边境”,第 6 组国家很早就采用了"提高认识运动"、“加强公共卫生系统"和"机场健康检查”。
- 很晚才出台“军事部署”和“乱人口测试”等措施,与其他团体的“测试政策”相比。
从下图 5 所示的案件数量的 7 天移动平均数来看,除了爱尔兰、以色列和厄瓜多尔这些奉承曲线的国家之外,大多数国家还没有用“或早或晚”模式实施的措施使曲线变平。
图五。第 2 类、第 5 类和第 6 类国家
第 3 组(第 3 组和第 4 组)——“中晚期”风格
这一组包括 33 个国家。关于这些国家采用所有这 33 项措施的时间,我们可以看到,与其他国家相比,大多数措施是在相当晚或相当晚的阶段引入这些国家的,只有“学校关闭”是一个例外。从下图 6 所示病例数的 7 天移动平均数来看,大多数国家的阳性病例数仍在上升。然而,中国、韩国、加拿大、荷兰、英国都包括在成功控制第一波疫情的国家之内,这表明除了引入的时机之外,我们还需要考虑更多的因素。
图六。第 3 类和第 4 类国家
见解和开放式问题
不同的国家在不同的时间采取不同的措施来控制传染病的传播。根据采取这些措施的时间,我们对国家进行了分组,以确定这 64 个国家的具体模式。很明显,越早采取措施,对控制疾病传播的影响就越大:
“时机很重要!越早越好”
然而,这项研究也强调指出,产生足够影响的时机非常有限。我们需要研究每项措施在控制 COVID19 传播方面的有效性,以便各国能够通过了解更多信息来调整更有效的短期和长期管理策略:
“在减少传播方面,各种措施有不同的效果!”
欢迎随时访问 GitHubrepo,欢迎您的反馈和意见。**
高效 Python 代码的计时
如何比较列表、集合和其他方法的性能
乔恩·泰森在 Unsplash 上的照片
动机
让我们看看这些常用的创建列表的方法:
串联:
l = []
for i in range(10000):
l = l + [i]
追加:
l = []
for i in range(10000):
l.append(i)
理解:
l = [i for i in range(10000)]
列表范围:
l = list(range(10000))
这些方法应该给你同样的数组。但是你有没有想过不同方法的效率?如果您正在处理一个小数据集,您可能不需要选择一种方法而不是另一种方法,但是当数据集变大时,选择一种有效的方法会对性能产生很大的影响。
惊讶于concat
和其他方法在性能上的巨大差异?等到你看到比例:
1019.0323133454616!
您可能会意识到理解不同方法和 Python 对象之间的性能差异是多么重要。但是你能用什么方法来选择一个有效的方法呢?
计时来追踪它
你追踪的一个方法是用时间来追踪创建某个对象需要多长时间,比较时间差。timeit
方法允许你这么做。
import timeitimport numpy as npfrom timeit import Timer
让我们看看如何跟踪方法的时间来创建我之前展示的列表。要使用Timer
,我们需要:
- 将您想要计时的函数作为字符串和位置传递,以将该函数放入
Timer
- 设置实验次数以找到该功能的平均时间
结果:
concat 25.208993583999998 milliseconds
append 0.13781585199999924 milliseconds
comprehension 0.08480268199999941 milliseconds
list range 0.024738168999999033 milliseconds
Worse vs. best ratio 1019.0323133454616
比较其他 Python 方法
酷!现在我们知道如何比较不同方法之间的时间。让我们用它来跟踪我们在 Python 中经常使用的其他方法
Pop-front 与 Pop-end
您可能会猜测弹出数组前面的元素比弹出数组末尾的元素花费更多的时间(因为在弹出第一个元素后,您必须重新分配数组中其他元素的位置)。但是随着数组大小的增加,先弹出多长时间呢?
我们使用范围从 10000 到 1000000 的数组进行测试,步长为 20000。让我们一起来观察我们的结果
import numpy as npmatrixDat = np.array( result )import matplotlib.pyplot as pltplt.plot(matrixDat[:,0], matrixDat[:,1], 'o', color='red',label='pop_zero');
plt.plot(matrixDat[:,0], matrixDat[:,2], '+', color='blue',label='pop_end');leg = plt.legend(numpoints=1)
.pop(0)
的持续时间随着阵列尺寸的增加而增加,而.pop()
的持续时间几乎保持不变。如果不追踪时间,我们不会注意到差异。
列表与集合
在我们找到 list 和 set 在性能上的区别之前,你愿意猜猜哪个性能更好吗?保持你的猜测,向下滚动找到答案。
使用前面的代码行来绘制结果。女士们先生们,让我来宣布结果:
如果你最初的猜测成立,你是对的。随着大小的增加,创建列表的持续时间增加,而集合的持续时间保持不变。
结论
了解 Python 方法之间的性能差异有助于您为自己的目标选择最有效的方法或对象。由于您将在数据科学项目中使用大型数据集,因此关注不同方法的性能以节省时间至关重要。
在 this Github repo 中,您可以随意使用本文的代码。
我喜欢写一些基本的数据科学概念,并尝试不同的算法和数据科学工具。你可以通过 LinkedIn 和 Twitter 与我联系。
如果你想查看我写的所有文章的代码,请点击这里。在 Medium 上关注我,了解我的最新数据科学文章,例如:
你创建了一个待办事项清单来提高效率,但最终却把时间浪费在了不重要的任务上。如果你能创造…
towardsdatascience.com](/maximize-your-productivity-with-python-6110004b45f7) [## cy thon——Python 函数的加速工具
当调整你的算法得到小的改进时,你可能想用 Cython 获得额外的速度,一个…
towardsdatascience.com](/cython-a-speed-up-tool-for-your-python-function-9bab64364bfd) [## 用 Python 选择要投资的股票
您计划在未来 3 年投资几只股票,每只股票的每一美元都有不同的预期回报…
towardsdatascience.com](/choose-stocks-to-invest-with-python-584892e3ad22) [## 为您的数据科学项目提供 Numpy 技巧
创建数组、矩阵、执行矩阵运算、解决线性代数问题和常见数据科学的技巧…
medium.com](https://medium.com/@khuyentran1476/comprehensive-numpy-tutorials-for-beginners-8b88696bd3a2)
如果火绒可以直接刷到你身上会怎么样?
字节/大小
随着视频聊天功能即将推出,这个约会平台可以使用人工智能来检测令人不快的图像
亚历山大·辛恩在 Unsplash 上的照片
18 岁是每个人生命中的一大步,一两个月前我迈出了这一步。它通常伴随着一系列的通过仪式:买你的第一张彩票,喝你的第一杯酒,签订令人心碎的债务协议。
另一个是加入 Tinder。我们可能相距遥远,但与他人联系的需求比以往任何时候都更强烈。我想,离别使心更亲?
那是谎言,你的高中恋情不会持续到大学两个星期,杰西卡。
Tinder 最近宣布计划为该平台引入视频聊天功能,他们已经明确表示,在我所谓的“性感垂直缩放会议”期间,将利用某种人工智能 + 物体检测来防止骚扰并确保安全。
什么是物体识别?
一些定义:
- **AI(人工智能)😗*泛指机器(计算机)系统,执行人类可以完成的任务。
- **CV(计算机视觉)😗*专门理解图像或视频内容的一类 AI。
- **物体检测:**与 CV 相邻,它在寻找一个特定的物体。
在人类的术语中,‘大脑’有点像人工智能的整体概念,你的’眼睛执行计算机视觉,当你寻找特定的东西(你的钥匙、零食、真爱)时,你正在执行物体探测任务。
大多数 CV 程序使用CNN(卷积神经网络):
CNN 的每一个“层”都着眼于图像的某些特征(通过像素值),从简单的边缘开始,逐渐变得更加复杂。
这些特征被映射以给出每个特征的概率位置。来自每个部分的最高概率被汇集到一个更小的图像中,其中负像素值被变成 0。
然后过程重复。最终,所有这些连接的层可以被编译,使得它们匹配某个标签/结果。基于这些结果的概率,CNN 给出了它对图像中内容的最佳猜测。
这很巧妙,但也很耗时。如果查丁顿·伍兹沃斯在 Tinder 视频聊天上开始变得太……舒服,20 秒的处理时间会感觉像过了一辈子。
幸运的是,一些 CNN 可以在实时运行。 YOLO 是一种物体检测算法,在自动驾驶汽车方面显示出了前景,在自动驾驶汽车中,实时检测是一个生死攸关的问题。
唯一一次说 YOLO 在 2020 年是可以接受的
YOLO 将图像分解成一个网格,每个网格方块负责预测其边界内物体的大小、类别和位置。
它还给出一个置信度得分——有多确定这是一个对象?然后,它试图找出对象的类(在它实际上是对象的情况下)。这返回一个条件概率:例如 P(Car | Object)。
这些置信度得分与正在讨论的对象周围的边界框相关联,最终产生许多不同权重的边界框。该算法然后寻找有许多 重叠的盒子——这意味着那里很可能有一个物体。
来源 |较重的边界框线对应较大的置信度得分。
那些高度重叠的预测被输出,如果它们满足某个阈值概率分数,它们将被保留。YOLO 可以在视频的每一帧/每一秒都这样做,如果 Tinder 想监控视频聊天的安全,这是一个完美的工具。
这对 Tinder 的发展意味着什么
Tinder 表示,当涉及到安全和隐私之间的平衡时,他们向安全学习。在他们即将推出的视频聊天功能中使用 YOLO 实时物体检测可以让许多人感到更安全使用它+阻止任何小动作。
Tinder 的下一波用户是 Z 世代——我们的整个生活都在互联网上,所以我想我们会对 Tinder 观看我们的视频聊天感到满意。
这项功能如何工作是一个不同的问题。如果 Tinder 看到一个不受欢迎/不合适的对象,他们会结束通话,举报用户,还是给你一个警告?
技术上来说,这完全是另一回事。在整个关系中,从用户到用户、和的不适当变化的分类。即使算法是为每个用户定制的,这也将是一个计算上具有挑战性的问题。
幸运的是,我 18 岁
在 3 英里外
,我喜欢解决问题和在沙滩上漫步。
A **byte-sized deep dive** into **tech** and **business**.
大家好,我是 Murto,是加拿大多伦多的一名 18 岁的企业家和学生。如果你想聊天,请在 LinkedIn 上联系我!
微型机器学习:下一次人工智能革命
更大的模型并不总是更好的模型
由 NASA 推动开始的电子产品小型化成为了一个完整的消费产品产业。现在我们把贝多芬的全部作品别在翻领上,戴着耳机听。— 尼尔·德格拉斯·泰森,天体物理学家兼科学评论员
[……]超低功耗嵌入式设备的普及,加上面向微控制器的 TensorFlow Lite 等嵌入式机器学习框架的推出,将使人工智能支持的物联网设备大规模扩散。— 哈佛大学副教授维杰·贾纳帕·雷迪
嵌入式设备微型机器学习(TinyML)概述。
这是微型机器学习系列文章的第一篇。本文的目标是向读者介绍微型机器学习的概念及其未来的潜力。在本系列的后续文章中,将深入讨论具体的应用程序、实现和教程。
简介
在过去的十年里,由于处理器速度的提高和大数据的出现,我们目睹了机器学习算法的规模呈指数级增长。最初,模型足够小,可以使用中央处理器(CPU)中的一个或多个内核在本地机器上运行。
不久之后,使用图形处理单元(GPU)的计算变得有必要处理更大的数据集,并且由于引入了基于云的服务,如 SaaS 平台(如谷歌联合实验室)和 IaaS(如亚马逊 EC2 实例),变得更加容易获得。此时,算法仍然可以在单台机器上运行。
最近,我们已经看到了专用集成电路(ASICs)和张量处理单元(TPU)的发展,它们可以打包大约 8 个 GPU 的能力。这些设备已经增加了跨多个系统分布学习的能力,以试图发展越来越大的模型。
最近,随着 GPT-3 算法(2020 年 5 月发布)的发布,这一点达到了顶峰,该算法拥有包含惊人的 1750 亿神经元的网络架构,是人脑中现有数量的两倍多(约 850 亿)。这比有史以来第二大神经网络图灵-NLG(2020 年 2 月发布,包含约 175 亿个参数)的神经元数量多 10 倍。一些估计称,该模型的培训成本约为 1000 万美元,并使用约 3 GWh 的电力(约为三个核电厂一小时的发电量)。
虽然 GPT-3 和图灵-NLG 的成就值得称赞,但自然地,这导致了一些业内人士批评人工智能行业越来越大的碳足迹。然而,它也有助于激发人工智能社区对更节能计算的兴趣。这些想法,像更有效的算法、数据表示和计算,多年来一直是一个看似不相关的领域的焦点:微型机器学习。
微型机器学习(tinyML)是机器学习和嵌入式物联网(IoT)设备的交集。该领域是一个新兴的工程学科,有可能彻底改变许多行业。
tinyML 的主要行业受益者是边缘计算和节能计算。TinyML 源于物联网(IoT)的概念。物联网的传统理念是,数据将从本地设备发送到云端进行处理。一些人对这一概念提出了某些担忧:隐私、延迟、存储和能效等等。
**能源效率。**传输数据(通过有线或无线)非常耗能,大约比机载计算(具体来说,乘累加单元)耗能多一个数量级。开发能够自行执行数据处理的物联网系统是最节能的方法。人工智能的先驱们已经讨论了“以数据为中心”的计算(相对于云模型的“以计算为中心”)有一段时间了,我们现在开始看到它的表演。
**隐私。**传输数据可能会侵犯隐私。此类数据可能会被恶意行为者截获,并且当存储在单一位置(例如云)时,其安全性会变得更低。通过将数据主要保存在设备上并最大限度地减少通信,这提高了安全性和隐私性。
储存。对于许多物联网设备来说,它们正在获取的数据毫无价值。想象一下,一个安全摄像头一天 24 小时记录着一栋大楼的入口。在一天的大部分时间里,摄像机镜头没有任何用处,因为什么都没发生。通过拥有一个仅在必要时激活的更智能的系统,需要更低的存储容量,并且传输到云的必要数据量也减少了。
**潜伏期。**对于标准的物联网设备,如亚马逊 Alexa,这些设备将数据传输到云端进行处理,然后根据算法的输出返回响应。从这个意义上来说,这个设备只是一个通向云模型的便捷通道,就像你和亚马逊的服务器之间的信鸽。这个设备相当笨,完全依赖于互联网的速度来产生结果。如果你网速慢,亚马逊 Alexa 也会变慢。对于具有板载自动语音识别功能的智能物联网设备,延迟会减少,因为对外部通信的依赖会减少(如果不是没有的话)。
这些问题导致了边缘计算的发展,即在边缘设备(位于云“边缘”的设备)上执行处理活动的想法。这些设备在内存、计算和功率方面受到高度的资源限制,导致了更高效的算法、数据结构和计算方法的开发。
这种改进也适用于更大的模型,这可能导致机器学习模型的效率提高几个数量级,而不会影响模型的准确性。例如,由微软开发的 Bonsai 算法可以小到 2 KB,但甚至可以比典型的 40 MB kNN 算法或 4 MB 神经网络有更好的性能。这个结果听起来可能不重要,但在 1/10,000 大小的模型上同样的精度是非常令人印象深刻的。这么小的模型可以在 Arduino Uno 上运行,Arduino Uno 有 2 KB 的 RAM 可用——简而言之,你现在可以在 5 美元的微控制器上建立这样的机器学习模型。
我们正处于一个有趣的十字路口,机器学习正在两种计算范式之间分叉:以计算为中心的计算和以数据为中心的计算。在以计算为中心的范式中,数据由数据中心中的实例存储和分析,而在以数据为中心的范式中,处理在数据的源位置本地完成。虽然我们似乎正在快速迈向以计算为中心的范式的天花板,但以数据为中心的范式的工作才刚刚开始。
物联网设备和嵌入式机器学习模型在现代世界中越来越普遍(预计到 2020 年底将有超过 200 亿台活跃设备)。其中很多你可能都没有注意到。智能门铃,智能恒温器,当你说两句话,或者甚至只是拿起电话,智能手机就会“醒来”。本文的剩余部分将更深入地关注 tinyML 是如何工作的,以及当前和未来的应用程序。
云的层次结构。(来源: eBizSolutions )
TinyML 的示例
以前,设备需要复杂的电路来执行各种操作。现在,机器学习越来越有可能将这种硬件“智能”抽象为软件,使嵌入式设备变得越来越简单、轻便和灵活。
嵌入式设备的机器学习带来的挑战是相当大的,但在这一领域已经取得了很大的进展。在微控制器上部署神经网络的关键挑战是低内存占用、有限的功率和有限的计算。
也许 TinyML 最明显的例子是在智能手机中。这些设备会持续主动地监听唤醒词,比如安卓智能手机上的“嘿谷歌”,或者 iPhones 上的“嘿 Siri”。通过智能手机的主中央处理器(CPU)运行这些活动,现代 iPhone 的 CPU 为 1.85 GHz,仅在几个小时内就会耗尽电池。对于大多数人一天最多使用几次的东西来说,这种程度的退化是不可接受的。
为了解决这个问题,开发人员创造了专门的低功耗硬件,能够由小型电池供电(如圆形 CR2032“硬币”电池)。这使得电路即使在 CPU 不运行时也能保持活动,基本上是在屏幕不亮的时候。
这些电路的功耗低至 1 mW,使用标准 CR2032 电池可供电长达一年。
可能看起来不像,但这是一件大事。对于许多电子设备来说,能量是一个限制因素。任何需要市电的设备都被限制在有布线的位置,当十几个设备出现在同一个位置时,布线会很快变得难以承受。干线电力也是低效和昂贵的。将电源电压(在美国约为 120 V)转换为典型的电路电压范围(通常约为 5 V)会浪费大量能源。任何有笔记本充电器的人在拔掉充电器的时候可能都会知道这一点。充电器内变压器产生的热量是电压转换过程中浪费的能量。
即使是带电池的设备,电池寿命也有限,需要频繁对接。许多消费类设备的设计都是为了让电池能够持续工作一个工作日。依靠硬币大小的电池可以持续工作一年的 TinyML 设备意味着它们可以被放置在偏远的环境中,只在必要时进行通信以节省能源。
唤醒词并不是我们看到的唯一无缝嵌入智能手机的 TinyML。加速度计数据用于确定是否有人刚刚拿起手机,这将唤醒 CPU 并打开屏幕。
显然,这些不是 TinyML 唯一可能的应用。事实上,TinyML 为企业和爱好者提供了许多令人兴奋的机会,来生产更智能的物联网设备。在一个数据变得越来越重要的世界中,将机器学习资源分发到远程位置的内存受限设备的能力可能会对农业、天气预报或地震学等数据密集型行业产生巨大的好处。
毫无疑问,赋予边缘设备执行数据驱动处理的能力将为工业过程带来范式转变。例如,能够监测作物并在检测到土壤湿度、特定气体(例如,苹果成熟时会释放乙烷)或特定大气条件(例如,大风、低温或高湿度)等特征时发送“帮助”消息的设备将极大地促进作物生长,从而提高作物产量。
另一个例子是,智能门铃可能装有摄像头,可以使用面部识别来确定谁在场。这可以用于安全目的,或者甚至仅仅是当有人在场时,门铃的摄像机信号被传送到房子里的电视,以便居民知道谁在门口。
tinyML 目前的两个主要关注领域是:
关键词看点 **。**大多数人已经熟悉了这个应用程序。“嘿 Siri”和“嘿 Google”是关键词的例子(通常与 hotword 或 wake word 同义)。这种设备持续收听来自麦克风的音频输入,并被训练成只对与所学习的关键词相对应的特定声音序列做出响应。这些设备比自动语音识别(ASR)应用程序简单,并且相应地使用较少的资源。一些设备,如谷歌智能手机,利用级联架构来提供安全的说话人验证。
视觉唤醒词 **。**有一种基于图像的模拟唤醒词,称为视觉唤醒词。把这些想象成一个图像的二进制分类,来表示某样东西是存在还是不存在。例如,智能照明系统可以被设计成当它检测到人的存在时激活,当他们离开时关闭。类似地,野生动物摄影师可以在特定动物出现时使用这个来拍照,或者在他们检测到有人出现时使用安全摄像头。
下面显示了 TinyML 的当前机器学习用例的更广泛的概述。
tiny ml 的机器学习用例(来源图片:NXP)。
TinyML 如何工作
TinyML 算法的工作方式与传统的机器学习模型非常相似。通常,模型像往常一样在用户的计算机上或云中被训练。后期培训是 tinyML 真正工作的开始,这个过程通常被称为深度压缩。
深度压缩过程示意图。来源: ArXiv 。
模型蒸馏
在训练之后,模型然后以这样的方式被改变,以创建具有更紧凑表示的模型。剪枝和知识 提炼就是这样两种技术。
知识提炼的基本思想是,较大的网络中有一些稀疏或冗余。虽然大型网络具有高的表示能力,但是如果网络能力不饱和,它可以在具有较低表示能力(即,较少神经元)的较小网络中表示。Hinton et al. (2015)将教师模型中的嵌入信息转移到学生模型中称为“暗知识”。
下图说明了知识提炼的过程。
深度压缩过程图。在这个图中,“老师”是一个经过训练的卷积神经网络模型。教师的任务是将其“知识”转移到一个参数更少的更小的卷积网络模型,即“学生”。这一过程被称为知识提炼,用于将相同的知识保存在一个较小的网络中,提供了一种压缩网络的方法,以便它们可以在更多内存受限的设备上使用。来源:ArXiv。
在这个图中,“教师”是一个经过训练的神经网络模型。教师的任务是将其“知识”转移到一个参数更少的更小的网络模型“学生”中。该过程用于将相同的知识保存在较小的网络中,提供了一种压缩知识表示的方式,从而压缩神经网络的大小,使得它们可以用于更多内存受限的设备。
同样,修剪有助于使模型的表示更加紧凑。广义地说,修剪试图去除对输出预测几乎没有用处的神经元。这通常与较小的神经权重有关,而较大的权重由于在推理过程中更重要而被保留。然后,在修剪后的架构上重新训练网络,以微调输出。
提取模型知识表示的剪枝图解。
量化
在提炼之后,该模型在训练后被量化成与嵌入式设备的架构兼容的格式。
为什么量子化是必要的?想象一个使用 ATmega328P 微控制器的 Arduino Uno,该微控制器使用 8 位算法。要在 Uno 上运行一个模型,模型权重理想情况下必须存储为 8 位整数值(而许多台式计算机和笔记本电脑使用 32 位或 64 位浮点表示)。通过量化模型,权重的存储大小减少了四分之一(对于从 32 位到 8 位值的量化),并且精度通常受到可忽略的影响(通常在 1–3%左右)。
8 位编码期间的量化误差图(然后用于重构 32 位浮点)。(来源: TinyML 书)
由于量化误差,一些信息可能在量化过程中丢失(例如,在基于浮点表示的 3.42 的值可能在基于整数的平台上被截断为 3)。为了解决这个问题,量化感知(QA)训练也被提出作为一种替代方案。QA 训练本质上在训练期间约束网络仅使用量化设备上可用的值(参见张量流示例)。
霍夫曼编码
编码是一个可选的步骤,有时通过以最有效的方式存储数据来进一步减少模型大小:通常通过著名的霍夫曼编码。
汇编
一旦模型被量化和编码,它就被转换成某种形式的光神经网络解释器可以解释的格式,其中最流行的可能是 TF Lite (大小约 500 KB)和 TF Lite Micro (大小约 20 KB)。然后,该模型被编译成 C 或 C++代码(大多数微控制器为了有效利用内存而使用的语言),并由设备上的解释器运行。
TInyML 应用的工作流程(来源:Pete Warden 和 Daniel Situnayake 所著的 TinyML 一书)
tinyML 的大部分技能来自于处理复杂的微控制器世界。TF Lite 和 TF Lite Micro 之所以这么小,是因为去掉了任何不必要的功能。不幸的是,这包括调试和可视化等有用的能力。这意味着,如果在部署过程中出现错误,很难辨别出发生了什么。
此外,虽然模型必须存储在设备上,但是模型还必须能够执行推理。这意味着微控制器必须具有足够大的存储器,以便能够运行(1)其操作系统和库,(2)神经网络解释器,如 TF Lite,(3)存储的神经权重和神经架构,以及(4)推理期间的中间结果。因此,tinyML 研究论文中经常引用量化算法的峰值内存使用量,以及内存使用量、乘累加单元(MAC)的数量、精度等。
为什么不在设备上训练?
设备上的训练带来了额外的复杂性。由于数值精度降低,保证足够训练网络所需的精度水平变得极其困难。标准台式计算机上的自动微分方法近似精确到机器精度。计算 10^-16 精度的导数是不可思议的,但是利用 8 位值的自动微分将导致糟糕的结果。在反向传播过程中,这些导数被合成并最终用于更新神经参数。在如此低的数值精度下,这种模型的精度可能很差。
也就是说,神经网络已经使用 16 位和 8 位浮点数进行了训练。
第一篇研究降低深度学习中数值精度的论文是 Suyog Gupta 和他的同事在 2015 年发表的论文*有限数值精度的深度学习*。这篇论文的结果很有趣,表明 32 位浮点表示可以简化为 16 位定点表示,而精度基本上没有下降。然而,这是使用 随机舍入 的唯一情况,因为平均而言,它产生一个无偏的结果。**
2018 年,王乃刚及其同事在他们的论文用 8 位浮点数 训练深度神经网络中,训练了一个使用 8 位浮点数的神经网络。使用 8 位数字而不是推理来训练神经网络,实现起来明显更具挑战性,因为需要在反向传播期间保持梯度计算的保真度(当使用自动微分时,它能够实现机器精度)。
计算效率如何?
还可以定制模型,使其计算效率更高。广泛部署在移动设备上的模型架构,如 MobileNetV1 和 MobileNetV2 就是很好的例子。这些基本上是卷积神经网络,它们重新设计了卷积运算,使其计算效率更高。这种更有效的卷积形式被称为深度方向可分离卷积**。还可以使用 基于硬件的评测 和 神经架构搜索 来优化架构的延迟,本文对此不做介绍。**
下一场人工智能革命
在资源受限的设备上运行机器学习模型的能力为许多新的可能性打开了大门。发展可能有助于使标准机器学习更加节能,这将有助于平息对数据科学对环境影响的担忧。此外,tinyML 允许嵌入式设备基于数据驱动的算法被赋予新的智能,这可以用于从预防性维护到探测森林中的鸟声的任何事情。
尽管一些机器学习从业者无疑将继续扩大模型的规模,但一个新的趋势正在朝着更具内存、计算和能源效率的机器学习算法发展。TinyML 仍处于萌芽阶段,这方面的专家很少。我推荐感兴趣的读者查看参考资料中的一些论文,它们是 tinyML 领域中的一些重要论文。这个领域正在快速发展,并将在未来几年内成为人工智能在工业中的一个新的重要应用。注意这个空间。
参考
[1]辛顿,杰弗里&维尼亚尔斯,奥里奥尔&迪恩,杰夫。(2015).在神经网络中提取知识。
[2] D. Bankman,L. Yang,B. Moons,M. Verhelst 和 B. Murmann,“一款始终在线的 3.8μJ/86% CIFAR-10 混合信号二进制 CNN 处理器,所有片内存储器均采用 28nm CMOS ,” 2018 年 IEEE 国际固态电路会议——(ISSCC),加利福尼亚州三藩市,2018 年,第 222–224 页,doi: 10.1109
[3]沃登,P. (2018)。机器学习的未来为何微小。皮特·沃顿的博客。
[4]沃德-福克斯顿,S. (2020 年)。皮层上的 AI 声音识别——M0:数据为王。EE 时代。
[5]利维,M. (2020)。MCU 上的深度学习是边缘计算的未来。EE 时代。
[6]格鲁恩斯坦、亚历山大&阿尔瓦雷斯、拉结尔&桑顿、克里斯&戈德拉特、穆罕默德阿里。(2017).移动设备上关键字定位的级联架构。
[7] Kumar,a .,Saurabh Goyal 和 M. Varma。(2017).物联网用 2 KB RAM 的资源高效机器学习。
[8]张,运东&须田,纳文&赖,梁真&钱德拉,维卡斯。(2017). Hello Edge:微控制器上的关键词识别。
[9]费多罗夫、伊戈尔&斯塔梅诺维奇、马尔科&延森、卡尔&杨、李奇亚&曼德尔、阿里&甘、&马蒂娜、马修&沃特穆格、保罗。(2020). TinyLSTMs:助听器的高效神经语音增强。
[10]林,季&陈,魏明&林,&科恩,约翰&甘,庄&韩,宋.(2020). MCUNet:物联网设备上的微小深度学习。
【11】陈、田琦&莫罗、蒂埃里。(2020). TVM:面向深度学习的自动化端到端优化编译器。
[12]韦伯、洛根和安德鲁·雷乌施(2020)。Tiny ml——TVM 如何驯服 Tiny 。
【13】克利须那摩提,Raghuraman。(2018).量化深度卷积网络实现高效推理:白皮书。
[14]约辛斯基,贾森&克伦尼,杰夫&本吉奥,Y. &利普森,霍德。(2014).深度神经网络中的特征有多大的可转移性?。
[15]赖,良真&须田,纳文&钱德拉,维卡斯。(2018).cMSIS-神经网络:Arm Cortex-M CPU 的高效神经网络内核。
[16]乔德里,阿坎克沙&沃顿,皮特&施伦斯,黄邦贤&霍华德,安德鲁&罗德斯,洛奇。(2019).视觉唤醒词数据集。
[17]监狱长,皮特。(2018).语音命令:用于有限词汇语音识别的数据集。
[18]泽姆利亚尼金,马克西姆&斯莫卡洛夫,亚历山大&哈诺瓦,塔蒂亚娜&彼得罗维奇娃,安娜&谢列布里雅科夫,格里戈里。(2019). 512KiB RAM 就够了!单片机上的现场摄像头人脸识别 DNN。2493–2500.10.1109/ICCVW.2019.00305
用于搜索的 TinyBERT:比 BERT 快 10 倍,小 20 倍
加速谷歌用来回答你的问题的算法,这样它就可以在标准的 CPU 上运行
合著 科尔梯恩梯
最近,谷歌推出了一种理解搜索并决定你看到哪些结果的新方法。这种方法基于流行的开源转换器 BERT,使用语言理解来理解搜索背后的含义,这是传统的关键字方法无法做到的。
我们构建了 NBoost 来让非 Google 用户也能轻松使用高级搜索排名模型,并在此过程中开发了 TinyBERT for search,我将在本文中介绍它。
特别是对于更长、更具对话性的查询,或者像“for”和“to”这样的介词对意义非常重要的搜索, **Search 将能够理解您查询中单词的上下文。**你可以用自己觉得自然的方式搜索。
- Pandu Nayak,谷歌搜索副总裁
让伯特变得更小更快
BERT 已经被证明可以改善搜索结果,但是有一个问题:运行这些查询理解模型需要大量的计算机。当速度很重要并且需要处理数百万次搜索时,这一点尤为重要。这一挑战如此艰巨,以至于谷歌甚至建立了自己的硬件来运行这些模型。而且他们用来在生产中运行这些 TPU 的代码是私有的,所以其他任何想运行它的人都要倒霉了。
为了在标准硬件上运行这些模型,我们使用 知识提炼 ,一个更大的教师网络被用来训练一个更小的学生网络的过程,该网络保持了大部分的准确性,但使用了更少、通常更小的层,使其更小和更快。
https://nerv anasystems . github . io/distiller/knowledge _ distillation . html
TinyBERT 建筑
我们使用来自这个报告的代码进行知识提炼,并对其进行修改,用于在女士马可数据集上进行训练和评估。我们最初用 MS Marco 训练三元组在 PyTorch 中训练了一个教师 bert-base-uncased 网络。然后我们用它作为老师训练一个更小的学生 BERT 网络,只有 4 个隐含层而不是标准的 12 个。此外,这些层中的每一层都只有 312 的尺寸,而不是 768 的尺寸,使得模型更加轻便。我们在 BERT 的末尾使用前馈二进制分类层来产生搜索排名的分数。
BERT 用于对(问题、答案)或(搜索、搜索结果)对进行搜索评分,然后根据这些评分对结果进行排名
以下是我们使用的 tinyBERT 架构的示例 bert_config.json ,与标准 bert_config 的显著差异以粗体显示。
{
“attention_probs_dropout_prob”: 0.1,
“cell”: {},
**“emb_size”: 312,**
“hidden_act”: “gelu”,
“hidden_dropout_prob”: 0.1,
“hidden_size”: 312,
“initializer_range”: 0.02,
**“intermediate_size”: 1200,**
“max_position_embeddings”: 512,
“num_attention_heads”: 12,
**“num_hidden_layers”: 4,**
“pre_trained”: “”,
“structure”: [],
“type_vocab_size”: 2,
“vocab_size”: 30522
}
评估模型
[1] MRR 对 BM25 排名前 50 的结果。宾查询指的是马尔科女士。K80 GPU 上的速度。
Marco 女士是真实世界搜索引擎使用数据的最大公开来源,使其成为评估搜索和问答模型的理想选择。它显示真实世界的必应搜索结果,以及用户最终点击了什么的信息。当伯特基地第一次在 MSMarco 上使用的时候,它以 0.05 MRR 的成绩击败了最先进水平(很多)。基于 BERT 的解决方案仍然位居排行榜首位。我们的目标是找到一种方法,从一个在现实世界中使用足够快的模型中实现这种提升。
进来吧,TinyBERT。虽然在重新排名方面不如 BERT Base 有效,但我们的实验表明,它保留了 BERT Base 的 90%的 MRR 分数(0.26 比 0.29,从 BM25 重新排名前 50),同时使模型 ~快 10 倍, ~小 20 倍。然而,基于马尔科女士等学术基准的结果往往缺乏现实世界的普遍性,因此应该持保留态度。
将机器学习添加到你的小应用程序中
使用机器学习构建嵌入式系统项目指南
美国宇航局在 Unsplash 拍摄的照片
您可能已经使用 NVIDIA 的 Jetson 板或 Raspberry Pi 设计了 ML 项目。对于构建汽车和机器人应用来说,这些都是非常强大的设备。例如,Jetson 使用强大的 GPU,满负荷运行时功率为几十瓦。
但你有没有想过在你的微型微控制器或 Arduino 项目中利用深度学习?嗯,你可能最终会想‘哦,这几乎不可能’。这些微型微控制器仅仅运行在几十或几百千字节的内存上。它们主要用于低功耗和低成本的应用程序,并且计算效率低下,无法运行深度学习功能。
你可能会惊讶地发现,你的 Android 手机使用什么机制来不断监听“Ok Google”呼叫词。我告诉你,它没有使用 Android 强大的处理器和千兆字节的 RAM 来运行强大的神经网络。相反,它只是使用运行在数字信号处理器(DSP)上的 14KB 神经网络来完成这项任务。这些 DSP 只有几十千字节的内存,功耗只有几毫瓦。
简而言之,为了将机器学习引入到运行在几千字节内存、低处理能力和寿命为几个月的硬币电池(能源成本低于 1 mW)上的设备中,TinyML 的这一想法被引入。结合深度学习和嵌入式系统,您现在可以通过集成简单的语音识别、通过运动传感器进行的手势检测以及通过摄像头传感器检测人员来构建令人惊叹的应用。
我需要什么硬件?
最初,从许多现成的板开始是一个好习惯。 SparkFun 的 Edge 、 Arduino Nano 33 BLE Sense 和 Mbed STM32F746G 探索套件是一些受欢迎的选项。如果你想建立一些现实的原型项目,你还需要一个麦克风,加速度计或摄像头。
我需要什么软件?
大多数开发者更喜欢 TensorFlow 和 Keras 来构建和训练深度学习网络。张量流模型基本上是一组指令,告诉解释器如何转换数据以产生输出。当我们想要使用这个训练好的模型时,我们将它加载到内存中,并使用解释器执行它。幸运的是,TensorFlow 提供了一个解释器来在这些微小的低功耗设备上运行模型。这套工具叫做 TensorFlow Lite 。 TensorFlow Lite 转换器用于将我们的模型转换为 TensorFlow Lite 格式。
TensorFlow Lite 有一个变种叫做tensor flow Lite for micro controllers,这是一个专门为运行在只有几十千字节可用内存的嵌入式设备上而设计的框架。
模型被转换后,就可以部署了。我们使用 tensor flow Lite for micro controller 的 C++库将模型加载到设备并进行预测。由于这是我们的模型满足我们的应用程序代码的一部分,我们需要编写一些代码,从传感器获取原始输入数据,并将其转换为与我们的模型被训练时相同的格式。然后,将转换后的数据传递到模型中,用于进行预测。
作者图片
包扎
TinyML 使我们能够将机器学习模型集成到 C++程序中,以创建用于在低内存和低功耗设备上部署的强大应用程序。微控制器无处不在,我们周围的不同设备中大约有 2500 亿个微控制器。想象一下,如果由这种微小的人类般的智能为它们提供动力,它们会给我们带来什么样的力量?
Python 中快速数据分析的技巧和诀窍
尼古拉斯·霍伊泽在 Unsplash 拍摄的照片
用 python 快速总结和描述数据集
python 编程语言有大量用于数据分析的内置函数和库。结合这些库可以产生非常强大的方法来总结、描述和过滤大量数据。
在本文中,我想分享一些关于如何结合 pandas 、 matplotlib 和一些内置 python 功能来快速分析数据集的技巧。
本文中的所有库都可以通过软件包管理器安装。
数据
在本文中,我将使用一个被称为成人收入数据集的数据集,它可以从 UCI 机器学习库下载。该数据集包含关于每个成年人的许多特征和一个目标变量,该变量告诉我们他们的收入是否超过 50,000 pa。
这里是我正在使用的库的所有导入。
import pandas as pd
import numpy as np
from sklearn import preprocessingimport matplotlib.pyplot as plt
%matplotlib inline
我使用 pandas 读取数据集并返回前几行。
data = pd.read_csv('adults_data.csv')
data.head()
该数据集通常用于建立机器学习模型,该模型根据特征预测收入阶层。然而,在进入模型构建阶段之前,先进行一些数据分析是有用的。
形容
describe 函数允许我们快速查看数据集中数字要素的一些基本描述性统计数据。运行data.describe()
我们可以看到我们的数据集有 32,561 行,我们可以看到每个数字特征的平均值,并了解每个特征的值分布情况。
值计数
在这个数据集中,我们还有分类变量,对这些变量的分布有一个基本的了解也是很有用的。value_counts()
函数提供了一种非常简单的方法来实现这一点。让我们用这个来检查一下marital-status
的特性。
data['marital-status'].value_counts()
为了使其更容易可视化,我们可以通过添加少量额外代码来快速创建该值的条形图。标题是可选的,您可以使用通常的 matplotlib 功能自定义轴标签、颜色和图表的其他方面。
plt.title('Marital Status')
data['marital-status'].value_counts().plot.bar()
当我们有一个具有高基数(大量唯一值)的要素时,使用值计数绘图就不那么有效了。
plt.title('Native Country')
data['native-country'].value_counts().plot.bar()
对于像 native-country 这样的要素,只绘制前 n 个值会更有用,因为这为我们提供了有用的洞察力。我们可以通过增加一点代码来实现。
plt.title('Native Country')
data['native-country'].value_counts().nlargest(10).plot.bar()
熊猫小组
当我们有数据要进行分段比较时,pandas groupby 函数非常有用。在该数据集中,我们希望执行分析以了解两个收入类别之间的差异以及要素差异的大小。pandas 的 groupby 函数提供了一种非常快速的方法来实现这一点。
如果我们运行下面的代码,我们可以分析两个收入组之间所有数值的均值差异。
round(data.groupby(['income']).mean(),2)
比较差异的更好方法是查看两组的分布差异。箱线图是一种很有用的方法。这可以通过与 groupby 一起使用绘图功能来实现。可视化如下所示。
data.groupby('income').boxplot(fontsize=20,rot=90,figsize=(20,10),patch_artist=True)
你会注意到,由于数值在不同的尺度上,很难比较这两种分布。为了克服这一点,我们可以缩放这些值。为此,我使用了scikit-learnminmax scaler 函数。这会缩放这些值,使它们都位于 0 和 1 之间。我们现在可以清楚地看到一些特征之间的实质性差异,例如年龄和每周工作时间。
numeric_features = data.select_dtypes(include=['int64', 'float64']).columns
categorical_features = data.select_dtypes(include=['object']).columnsnumeric_data = data[numeric_features]
categorical_data = data[categorical_features]x = numeric_data.values
min_max_scaler = preprocessing.MinMaxScaler()
x_scaled = min_max_scaler.fit_transform(x)
numeric_data = pd.DataFrame(x_scaled, columns=numeric_data.columns)
data_transformed = pd.concat([numeric_data, categorical_data], axis=1)
data_transformed.groupby('income').boxplot(fontsize=20,rot=90,figsize=(20,10),patch_artist=True)
我们还可以使用 groupby 函数来比较分类特征。在下图中,我们可以很快发现,在高收入阶层中,男性人数多于女性。
data.groupby('income').gender.value_counts().unstack(0).plot.barh()
数据透视表
Pandas 的功能使您能够用 python 创建电子表格风格的数据透视表。数据透视表允许您快速汇总、分组和过滤数据,以执行更复杂的分析。
我们可以使用数据透视表来探索更复杂的关系。让我们更深入地研究一下性别和收入阶层之间的关系。女性挣得少是因为她们每周工作时间少吗?
pivot_workclass = pd.pivot_table(data, values=['hours-per-week'],
index = 'gender',
columns = 'income', aggfunc=np.mean, fill_value=0)
我们可以添加绘图功能,使这更容易可视化。
pivot_workclass = pd.pivot_table(data, values=['hours-per-week'],
index = 'gender',
columns = 'income', aggfunc=np.mean, fill_value=0).plot.bar()
上面描述的所有方法都可以扩展,以创建更丰富、更复杂的分析。更多关于熊猫图书馆的信息,请看我之前的指南,可以在这里找到。
感谢阅读!
RStudio 和 R Markdown 中的提示和技巧
或者如何更快更有效地写 R 代码
照片由胡安·戈麦斯拍摄
如果你有机会和一位经验丰富的程序员一起工作,你可能会惊讶于她写代码的速度。在本文中,我分享了一些技巧和快捷方式,您可以在 RStudio 和 R Markdown 中使用它们来加速代码的编写。
运行代码
你很可能已经知道这个快捷方式,但是我仍然为新的 R 用户提到它。从您的脚本中,您可以运行一段代码:
command + Enter on Mac
Ctrl + Enter on Windows
在 R and R 减价中插入评论
要插入注释:
command + Shift + C on Mac
Ctrl + Shift + C on Windows
此快捷方式可用于:
- 当你想注释你的代码时。它会在行首添加一个
#
- 对于 R Markdown 中的文本。它会在文本周围添加
<!--
和-->
请注意,如果您想要注释多行,请选择您想要注释的所有行,然后使用快捷键。如果您想要取消注释,请应用相同的快捷键。
编织一个 R 减价文件
您可以使用此快捷方式来编织 R Markdown 文档:
command + Shift + K on Mac
Ctrl + Shift + K on Windows
代码片段
代码段通常只有几个字符长,用作插入一段普通代码的快捷方式。你只需输入几个字符,然后按下Tab
,它会用一个更大的代码来完成你的代码。然后再次使用Tab
在需要定制的代码中导航。例如,如果您键入fun
,然后按下Tab
,它将自动使用所需代码完成代码,以创建一个函数:
name <- function(variables) {
}
再次按下Tab
将在占位符间跳转,以便您进行编辑。所以你可以先编辑函数的名字,然后是变量,最后是函数内部的代码(自己试试!).
RStudio 中默认有很多代码片段。以下是我最常用的代码片段:
lib
呼叫library()
library(package)
mat
创建一个矩阵
matrix(data, nrow = rows, ncol = cols)
if
、el
、ei
创建if() {}
、else {}
、else if () {}
等条件表达式
if (condition) {
}else {
}else if (condition) {
}
fun
创建一个函数
name <- function(variables) {
}
for
创建 for 循环
for (variable in vector) {
}
ts
插入带有当前日期和时间的注释(如果你有很长的代码并与他人分享,以便他们能看到它何时被编辑,这很有用)
# Tue Jan 21 20:20:14 2020 ------------------------------
shinyapp
每次我创建一个新的闪亮的应用
library(shiny)ui <- fluidPage(
)server <- function(input, output, session) {
}shinyApp(ui, server)
你可以看到所有默认的代码片段,并通过点击工具>全局选项…>代码(左侧栏) >编辑代码片段…
R 降价中的有序列表
在 R Markdown 中,当创建这样的有序列表时:
- 项目 1
- 项目 2
- 项目 3
而不是纠结于数字和打字
1\. Item 1
2\. Item 2
3\. Item 3
你可以简单地输入
1\. Item 1
1\. Item 2
1\. Item 3
获得完全相同的结果(自己尝试一下或者查看本文的代码!).这样,在创建新项目时,您就不必担心下一个号码是什么了。
更进一步,只要第一项是您想要开始的数字,任何数字实际上都将呈现相同的结果。例如,您可以键入:
1\. Item 1
7\. Item 2
3\. Item 3
这使得
- 项目 1
- 项目 2
- 项目 3
然而,我建议总是使用你想要的数字来开始所有的条目,因为如果你移动了顶部的一个条目,列表将从这个新的数字开始。例如,如果我们将7\. Item 2
从前面的列表中移到顶部,列表将变成:
7\. Item 2
1\. Item 1
3\. Item 3
这不正确地呈现了
- 项目 2
- 项目 1
- 项目 3
R Markdown 中的新代码块
当编辑 R Markdown 文档时,您将需要多次插入新的 R 代码块。以下快捷方式将使您的生活更轻松:
command + option + I on Mac (or command + alt + I depending on your keyboard)
Ctrl + ALT + I on Windows
R Markdown 中的新 R 代码块
重新格式化代码
一个清晰可读的代码总是更容易和更快地阅读(并且在分享给合作者时看起来更专业)。自动应用最常见的编码准则,如空白、缩进等。,使用:
cmd + Shift + A on Mac
Ctrl + Shift + A on Windows
例如,下面的代码不符合指导原则(并且不容易阅读):
1+1
for(i in 1:10){if(!i%%2){next}
print(i)
}
变得更加简洁易读:
1 + 1
for (i in 1:10) {
if (!i %% 2) {
next
}
print(i)
}
RStudio addins
RStudio 插件是一些扩展,它们为从 RStudio 中执行高级 R 函数提供了一种简单的机制。更简单地说,当执行一个插件(通过单击插件菜单中的一个按钮)时,相应的代码被执行,而您不必编写代码。RStudio 插件的优势在于,与您自己编写代码相比,它们允许您更轻松地执行复杂和高级的代码。
我最常用的 addin 可能是[{esquisse}](https://www.statsandr.com/blog/rstudio-addins-or-how-to-make-your-coding-life-easier/#esquisse)
addin ,它允许用[{ggplot2}](https://www.statsandr.com/blog/graphics-in-r-with-ggplot2/)
包以用户友好和交互的方式绘制图形,而不必自己编写代码。
RStudio 插件种类繁多,需要更详细的解释,所以我写了一篇文章专门讨论这些插件。见文章此处。
{pander}
和{report}
为美学
{pander}
包中的pander()
功能对于 R Markdown 文档和报告非常有用。这实际上不是一条捷径,但它极大地提高了 R 输出的美观性。
例如,参见下面独立性卡方测试的默认输出与使用pander()
函数(使用[{ggplot2}](https://statsandr.com/blog/graphics-in-r-with-ggplot2/)
包中的diamonds
数据集)的相同测试的输出之间的差异:
library(ggplot2)
dat <- diamondstest <- chisq.test(table(dat$cut, dat$color))
test##
## Pearson's Chi-squared test
##
## data: table(dat$cut, dat$color)
## X-squared = 310.32, df = 24, p-value < 2.2e-16library(pander)
pander(test)
你需要的所有信息都显示在一个雅致的表格中。pander()
函数适用于许多统计测试(不是所有测试,但我没有在 R 中的所有可用测试中尝试过)和回归模型:
# Linear model with lm()
model <- lm(price ~ carat + x + y + z,
data = dat)
model##
## Call:
## lm(formula = price ~ carat + x + y + z, data = dat)
##
## Coefficients:
## (Intercept) carat x y z
## 1921.2 10233.9 -884.2 166.0 -576.2pander(model)
pander 函数还制作数据集、表格、向量等。在 R Markdown 输出中可读性更好。例如,请参见下面的差异:
head(dat) # first 6 observations of a dataset## # A tibble: 6 x 10
## carat cut color clarity depth table price x y z
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl>
## 1 0.23 Ideal E SI2 61.5 55 326 3.95 3.98 2.43
## 2 0.21 Premium E SI1 59.8 61 326 3.89 3.84 2.31
## 3 0.23 Good E VS1 56.9 65 327 4.05 4.07 2.31
## 4 0.290 Premium I VS2 62.4 58 334 4.2 4.23 2.63
## 5 0.31 Good J SI2 63.3 58 335 4.34 4.35 2.75
## 6 0.24 Very Good J VVS2 62.8 57 336 3.94 3.96 2.48pander(head(dat))
summary(dat) # main descriptive statistics## carat cut color clarity depth
## Min. :0.2000 Fair : 1610 D: 6775 SI1 :13065 Min. :43.00
## 1st Qu.:0.4000 Good : 4906 E: 9797 VS2 :12258 1st Qu.:61.00
## Median :0.7000 Very Good:12082 F: 9542 SI2 : 9194 Median :61.80
## Mean :0.7979 Premium :13791 G:11292 VS1 : 8171 Mean :61.75
## 3rd Qu.:1.0400 Ideal :21551 H: 8304 VVS2 : 5066 3rd Qu.:62.50
## Max. :5.0100 I: 5422 VVS1 : 3655 Max. :79.00
## J: 2808 (Other): 2531
## table price x y
## Min. :43.00 Min. : 326 Min. : 0.000 Min. : 0.000
## 1st Qu.:56.00 1st Qu.: 950 1st Qu.: 4.710 1st Qu.: 4.720
## Median :57.00 Median : 2401 Median : 5.700 Median : 5.710
## Mean :57.46 Mean : 3933 Mean : 5.731 Mean : 5.735
## 3rd Qu.:59.00 3rd Qu.: 5324 3rd Qu.: 6.540 3rd Qu.: 6.540
## Max. :95.00 Max. :18823 Max. :10.740 Max. :58.900
##
## z
## Min. : 0.000
## 1st Qu.: 2.910
## Median : 3.530
## Mean : 3.539
## 3rd Qu.: 4.040
## Max. :31.800
##pander(summary(dat))
table(dat$cut, dat$color) # contingency table##
## D E F G H I J
## Fair 163 224 312 314 303 175 119
## Good 662 933 909 871 702 522 307
## Very Good 1513 2400 2164 2299 1824 1204 678
## Premium 1603 2337 2331 2924 2360 1428 808
## Ideal 2834 3903 3826 4884 3115 2093 896pander(table(dat$cut, dat$color))
names(dat) # variable names## [1] "carat" "cut" "color" "clarity" "depth" "table" "price"
## [8] "x" "y" "z"pander(names(dat))
克拉,切工,颜色,净度,深度,表,价格, x , y 和 z
rnorm(4) # generates 4 observations from a standard normal distribution## [1] -1.8170575 0.2089859 1.0480589 0.1609936pander(rnorm(4))
1.291 、 0.1842 、 -0.1146 和 -1.006
这个技巧在编写 R Markdown 时特别有用,因为生成的文档看起来会更好。
另一个美观的技巧是{report}
包中的report()
函数。
与pander()
类似,report()
函数允许以更易读的方式报告测试结果——但它也为您解释结果。例如,参见相关性测试:
# install.packages("remotes")
# remotes::install_github("easystats/report") # You only need to do that once
library("report") # Load the package every time you start Rreport(cor.test(dat$price, dat$carat))## Effect sizes were labelled following Funder's (2019) recommendations.
##
## The Pearson's product-moment correlation between dat$price and dat$carat is positive, significant and very large (r = 0.92, 95% CI [0.92, 0.92], t(53938) = 551.41, p < .001)
测试结果与 p 值和相关系数一起显示并解释给您。
注意,report()
功能可用于其他分析。在软件包的文档中查看更多示例。
用{equatiomatic}
提取方程模型
如果您经常需要在 R Markdown 报告中编写与统计模型相对应的方程,[{equatiomatic}](https://cran.r-project.org/package=equatiomatic)
将帮助您节省时间。
下面是一个多元线性回归的基本示例,使用与上述相同的数据集(即diamonds
来自{ggplot2}
):
# install.packages("equatiomatic")
library(equatiomatic)# fit a basic multiple linear regression model
model <- lm(price ~ carat + depth,
data = dat)extract_eq(model,
use_coefs = TRUE)
价格= 4045.33 + 7765.14 克拉-102.17 克拉(深)+ ϵ
如果方程很长,您可以通过添加参数wrap = TRUE
在多行中显示它:
model <- lm(price ~ carat + x + y + z + depth,
data = dat)extract_eq(model,
use_coefs = TRUE,
wrap = TRUE)
价格= 12196.69 + 10615.5 克拉-1369.67 克拉+ 97.6 克拉+ 64.2 克拉-156.62 克拉(深)+ ϵ
请注意:
- 如果您在 R Markdown 中使用它,您需要为该特定代码块添加
results = 'asis'
,否则该方程将被呈现为 LaTeX 方程 - 在撰写本文时,它仅适用于 PDF 和 HTML 输出,不适用于 Word
- 每行的默认术语数是 4。您可以使用
terms_per_line
参数来更改它:
extract_eq(model,
use_coefs = TRUE,
wrap = TRUE,
terms_per_line = 2)
{equatiomatic}
也支持逻辑回归的输出。在插图中查看所有支持的型号- 如果您需要没有实际参数估计的理论模型,请删除
use_coefs
参数:
extract_eq(model,
wrap = TRUE)
在这种情况下,我更喜欢用β0 作为截距,而不是α。你可以用intercept = "beta"
论点来改变这一点:
extract_eq(model,
wrap = TRUE,
intercept = "beta")
管道操作员%>%
如果您经常使用{dplyr}
、{tidyverse}
或{magrittr}
软件包,以下是管道操作员%>%
的快捷方式:
command + Shift + M on Mac
Ctrl + Shift + M on Windows
其他人
与许多其他程序类似,您也可以使用:
- Mac 上的
command + Shift + N
和 Windows 上的Ctrl + Shift + N
打开一个新的 R 脚本 - Mac 上的
command + S
和 Windows 上的Ctrl + S
保存您当前的脚本或 R Markdown 文档
感谢阅读。我希望这些提示和技巧对你有用。如果你正在使用其他的,请在评论区分享。
和往常一样,如果您有与本文主题相关的问题或建议,请将其添加为评论,以便其他读者可以从讨论中受益。
相关文章:
- 安装和加载 R 包的有效方法
- 我的数据符合正态分布吗?关于最广泛使用的分布以及如何检验 R 中的正态性的注释
- R 中的费雪精确检验:小样本的独立性检验
- R 中独立性的卡方检验
- 如何在简历中创建简历时间线