本文概述
介绍
移动平均值(也称为滚动平均值或移动平均值)用于通过计算完整数据集不同子集的平均值来分析时间序列数据。由于它涉及对一段时间内的数据集取平均值, 因此也称为移动平均值(MM)或滚动平均值。
滚动平均的计算方法有很多种, 但一种方法是从完整的数字序列中提取固定的子集。通过对数字的第一个固定子集求平均值来计算第一个移动平均值, 然后通过向前移动到下一个固定子集(包括子组中的将来值, 同时从序列中排除前一个数字)来更改子集。
移动平均数通常与时间序列数据一起使用, 以捕获短期波动, 同时关注较长的趋势。
时间序列数据的一些例子可以是股票价格, 天气预报, 空气质量, 国内生产总值, 就业等。
通常, 移动平均线使数据平滑。
移动平均值是许多算法的基础, 其中一种算法是自回归综合移动平均值模型(ARIMA), 它使用移动平均值进行时间序列数据预测。
有多种类型的移动平均线:
简单移动平均线(SMA):简单移动平均线(SMA)使用滑动窗口来获取设定时间段内的平均值。它是先前n个数据的均等加权平均值。
为了进一步理解SMA, 让我们举一个n值的序列为例:
那么n个数据点的平均加权滚动平均值实质上就是前M个数据点的平均值, 其中M是滑动窗口的大小:
同样, 为了计算后续的滚动平均值, 会将新值添加到总和中, 并且将删除先前的时间段值, 因为你具有先前时间段的平均值, 因此不需要每次都进行完全求和:
- 累积移动平均线(CMA):与简单移动平均线不同, 简单移动平均线会随着添加新的移动平均线而丢弃最旧的观测值, 累积移动平均线会考虑所有先前的观测值。 CMA不是一种很好的分析趋势和平滑数据的技术。原因是, 它将对所有之前的数据进行平均, 直到当前数据点为止, 因此对n个值的序列进行了加权平均:
- 指数移动平均线(EMA):与SMA和CMA不同, 指数移动平均线对近期价格具有更大的权重, 因此, 它可以是更好的模型, 也可以更快地捕获趋势的移动。 EMA的反应与数据模式成正比。
由于EMA对最新数据的权重高于对旧数据的权重, 因此与SMA相比, 它们对最新价格变化的反应更快, 这使EMA的结果更及时, 因此EMA比其他技术更受青睐。
理论够了吧?让我们跳到移动平均线的实际实现。
在时间序列数据上实现移动平均
简单移动平均线(SMA)
首先, 让我们创建虚拟时间序列数据, 然后尝试仅使用Python实施SMA。
假设存在对某种产品的需求, 并且该需求被观察了12个月(1年), 那么你需要找到3个月和4个月窗口期的移动平均值。
导入模块
import pandas as pd
import numpy as np
product = {'month' : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 'demand':[290, 260, 288, 300, 310, 303, 329, 340, 316, 330, 308, 310]}
df = pd.DataFrame(product)
df.head()
月 | 需求 | |
---|---|---|
0 | 1 | 290 |
1 | 2 | 260 |
2 | 3 | 288 |
3 | 4 | 300 |
4 | 5 | 310 |
让我们为窗口大小3计算SMA, 这意味着你将每次考虑三个值来计算移动平均值, 对于每个新值, 最旧的值将被忽略。
为了实现这一点, 你将使用pandas iloc函数, 因为需求列是你所需要的, 因此你将固定它在iloc函数中的位置, 而该行将是一个变量i, 你将不断对其进行迭代, 直到到达末尾为止。数据框。
for i in range(0, df.shape[0]-2):
df.loc[df.index[i+2], 'SMA_3'] = np.round(((df.iloc[i, 1]+ df.iloc[i+1, 1] +df.iloc[i+2, 1])/3), 1)
df.head()
月 | 需求 | SMA_3 | |
---|---|---|---|
0 | 1 | 290 | NaN |
1 | 2 | 260 | NaN |
2 | 3 | 288 | 279.3 |
3 | 4 | 300 | 282.7 |
4 | 5 | 310 | 299.3 |
为了进行健全性检查, 我们还使用Pandas内置的滚动功能, 看看它是否与我们基于自定义python的简单移动平均值相匹配。
df['pandas_SMA_3'] = df.iloc[:, 1].rolling(window=3).mean()
df.head()
月 | 需求 | SMA_3 | Pandas_SMA_3 | |
---|---|---|---|---|
0 | 1 | 290 | NaN | NaN |
1 | 2 | 260 | NaN | NaN |
2 | 3 | 288 | 279.3 | 279.333333 |
3 | 4 | 300 | 282.7 | 282.666667 |
4 | 5 | 310 | 299.3 | 299.333333 |
很酷, 如你所见, 自定义平均值和Pandas移动平均值完全匹配, 这意味着你实施的SMA是正确的。
让我们还快速计算window_size为4的简单移动平均值。
for i in range(0, df.shape[0]-3):
df.loc[df.index[i+3], 'SMA_4'] = np.round(((df.iloc[i, 1]+ df.iloc[i+1, 1] +df.iloc[i+2, 1]+df.iloc[i+3, 1])/4), 1)
df.head()
月 | 需求 | SMA_3 | Pandas_SMA_3 | SMA_4 | |
---|---|---|---|---|---|
0 | 1 | 290 | NaN | NaN | NaN |
1 | 2 | 260 | NaN | NaN | NaN |
2 | 3 | 288 | 279.3 | 279.333333 | NaN |
3 | 4 | 300 | 282.7 | 282.666667 | 284.5 |
4 | 5 | 310 | 299.3 | 299.333333 | 289.5 |
df['pandas_SMA_4'] = df.iloc[:, 1].rolling(window=4).mean()
df.head()
月 | 需求 | SMA_3 | Pandas_SMA_3 | SMA_4 | Pandas_SMA_4 | |
---|---|---|---|---|---|---|
0 | 1 | 290 | NaN | NaN | NaN | NaN |
1 | 2 | 260 | NaN | NaN | NaN | NaN |
2 | 3 | 288 | 279.3 | 279.333333 | NaN | NaN |
3 | 4 | 300 | 282.7 | 282.666667 | 284.5 | 284.5 |
4 | 5 | 310 | 299.3 | 299.333333 | 289.5 | 289.5 |
现在, 你将绘制计算出的移动平均线的数据。
import matplotlib.pyplot as plt
%matplotlib inline
plt.figure(figsize=[15, 10])
plt.grid(True)
plt.plot(df['demand'], label='data')
plt.plot(df['SMA_3'], label='SMA 3 Months')
plt.plot(df['SMA_4'], label='SMA 4 Months')
plt.legend(loc=2)
<matplotlib.legend.Legend at 0x11fe15080>
累积移动平均线
我认为我们现在准备移至真实数据集。
对于累积移动平均值, 让我们使用可从此链接下载的空气质量数据集。
df = pd.read_csv("AirQualityUCI/AirQualityUCI.csv", sep = ";", decimal = ", ")
df = df.iloc[ : , 0:14]
df.head()
日期 | 时间 | 二氧化碳(GT) | PT08.S1(CO) | NMHC(GT) | C6H6(GT) | PT08.S2(NMHC) | 氮氧化物(GT) | PT08.S3(NOx) | 二氧化硫 | PT08.S4(NO2) | PT08.S5(O3) | Ť | 相对湿度 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 10/03/2004 | 18.00.00 | 2.6 | 1360.0 | 150.0 | 11.9 | 1046.0 | 166.0 | 1056.0 | 113.0 | 1692.0 | 1268.0 | 13.6 | 48.9 |
1 | 10/03/2004 | 19.00.00 | 2.0 | 1292.0 | 112.0 | 9.4 | 955.0 | 103.0 | 1174.0 | 92.0 | 1559.0 | 972.0 | 13.3 | 47.7 |
2 | 10/03/2004 | 20.00.00 | 2.2 | 1402.0 | 88.0 | 9.0 | 939.0 | 131.0 | 1140.0 | 114.0 | 1555.0 | 1074.0 | 11.9 | 54.0 |
3 | 10/03/2004 | 21.00.00 | 2.2 | 1376.0 | 80.0 | 9.2 | 948.0 | 172.0 | 1092.0 | 122.0 | 1584.0 | 1203.0 | 11.0 | 60.0 |
4 | 10/03/2004 | 22.00.00 | 1.6 | 1272.0 | 51.0 | 6.5 | 836.0 | 131.0 | 1205.0 | 116.0 | 1490.0 | 1110.0 | 11.2 | 59.6 |
每当处理数据时, 预处理都是必不可少的步骤。对于数字数据, 最常见的预处理步骤之一是检查NaN(Null)值。如果有任何NaN值, 则可以将其替换为0或平均值或之前或之后的值, 甚至丢弃它们。尽管替换通常比删除它们是更好的选择, 因为此数据集具有很少的NULL值, 但是删除它们不会影响系列的连续性。
df.isna().sum()
Date 114
Time 114
CO(GT) 114
PT08.S1(CO) 114
NMHC(GT) 114
C6H6(GT) 114
PT08.S2(NMHC) 114
NOx(GT) 114
PT08.S3(NOx) 114
NO2(GT) 114
PT08.S4(NO2) 114
PT08.S5(O3) 114
T 114
RH 114
dtype: int64
从上面的输出中, 你可以观察到所有列中大约有114个NaN值, 但是你会发现它们都位于时间序列的末尾, 因此让我们快速删除它们。
df.dropna(inplace=True)
df.isna().sum()
Date 0
Time 0
CO(GT) 0
PT08.S1(CO) 0
NMHC(GT) 0
C6H6(GT) 0
PT08.S2(NMHC) 0
NOx(GT) 0
PT08.S3(NOx) 0
NO2(GT) 0
PT08.S4(NO2) 0
PT08.S5(O3) 0
T 0
RH 0
dtype: int64
你将在”温度”列(T)上应用累积移动平均值, 因此让我们快速将该列与完整数据分开。
df_T = pd.DataFrame(df.iloc[:, -2])
df_T.head()
Ť | |
---|---|
0 | 13.6 |
1 | 13.3 |
2 | 11.9 |
3 | 11.0 |
4 | 11.2 |
现在, 你将使用Pandas扩展方法来找到上述数据的累积平均值。如果你从介绍中回想起, 则与简单移动平均值不同, 累积移动平均值在计算平均值时会考虑所有先前的值。
df_T['CMA_4'] = df_T.expanding(min_periods=4).mean()
df_T.head(10)
Ť | CMA_4 | |
---|---|---|
0 | 13.6 | NaN |
1 | 13.3 | NaN |
2 | 11.9 | NaN |
3 | 11.0 | 12.450000 |
4 | 11.2 | 12.200000 |
5 | 11.2 | 12.033333 |
6 | 11.3 | 11.928571 |
7 | 10.7 | 11.775000 |
8 | 10.7 | 11.655556 |
9 | 10.3 | 11.520000 |
时间序列数据是相对于时间绘制的, 因此让我们结合日期和时间列并将其转换为datetime对象。为此, 你将使用python中的datetime模块(来源:时间序列教程)。
import datetime
df['DateTime'] = (df.Date) + ' ' + (df.Time)
df.DateTime = df.DateTime.apply(lambda x: datetime.datetime.strptime(x, '%d/%m/%Y %H.%M.%S'))
让我们用datetime更改温度数据帧的索引。
df_T.index = df.DateTime
现在让我们绘制实际温度和累积移动平均线。时间。
plt.figure(figsize=[15, 10])
plt.grid(True)
plt.plot(df_T['T'], label='temperature')
plt.plot(df_T['CMA_4'], label='CMA_4')
plt.legend(loc=2)
<matplotlib.legend.Legend at 0x1210a2d30>
指数移动平均线
df_T['EMA'] = df_T.iloc[:, 0].ewm(span=40, adjust=False).mean()
df_T.head()
Ť | CMA_4 | Ma | |
---|---|---|---|
DateTime | |||
2004-03-10 18:00:00 | 13.6 | NaN | 13.600000 |
2004-03-10 19:00:00 | 13.3 | NaN | 13.585366 |
2004-03-10 20:00:00 | 11.9 | NaN | 13.503153 |
2004-03-10 21:00:00 | 11.0 | 12.45 | 13.381048 |
2004-03-10 22:00:00 | 11.2 | 12.20 | 13.274655 |
plt.figure(figsize=[15, 10])
plt.grid(True)
plt.plot(df_T['T'], label='temperature')
plt.plot(df_T['CMA_4'], label='CMA_4')
plt.plot(df_T['EMA'], label='EMA')
plt.legend(loc=2)
<matplotlib.legend.Legend at 0x14b2a41d0>
哇!因此, 从上图可以看出, 指数移动平均线(EMA)在捕获数据模式方面做得非常出色, 而累积移动平均线(CMA)则有相当大的差距。
总结
恭喜你完成了本教程。
本教程是你如何计算数据的移动平均值并加以理解的一个很好的起点。
尝试在不使用pandas库的情况下编写累积和指数移动平均python代码。这将使你更加深入地了解它们的计算方式以及它们之间的区别。
还有很多实验。尝试计算输入数据和移动平均值之间的局部自相关, 并尝试找到两者之间的某种关系。
如果你想了解有关pandas中的DataFrames的更多信息, 请参加srcmini的pandas Foundations交互式课程。
参考文献:
- 时间序列教程
请随时在下面的评论部分中提出与本教程相关的任何问题。
评论前必须登录!
注册