作者 | Selva Prabhakaran
译者 | Tianyu
责编 | Jane
出品 | AI科技大本营(ID: rgznai100)
【导语】时间序列是指以固定时间为间隔的序列值。本篇教程将教大家用 Python 对时间序列进行特征分析。
1、什么是时间序列?
时间序列是指以固定时间为间隔的、由所观察的值组成的序列。根据观测值的不同频率,可将时间序列分成小时、天、星期、月份、季度和年等时间形式的序列。有时候,你也可以将秒钟和分钟作为时间序列的间隔,如每分钟的点击次数和访客数等等。
为什么我们要对时间序列进行分析呢?
因为当你想对一个序列进行预测时,首先要完成分析这个步骤。除此之外,时间序列的预测也具有极大商业价值,如企业的供求量、网站的访客量以及股票价格等,都是极其重要的时间序列数据。
那么,时间序列分析都包括哪些内容呢?
要做好时间序列分析,必须要理解序列的内在属性,这样才能做出更有意义且精准的预测。
2、如何在 Python 中引入时间序列?
关于时间序列的数据大都存储在 csv 文件或其他形式的表格文件里,且都包含两个列:日期和观测值。
首先我们来看 panda 包里面的 read_csv() 函数,它可以将时间序列数据集(关于澳大利亚药物销售的 csv 文件)读取为 pandas 数据框。增加一个 parse_dates=['date'] 字段,可以把包含日期的数据列解析为日期字段。from dateutil.parser import parseimport matplotlib as mplimport matplotlib.pyplot as pltimport seaborn as snsimport numpy as npimport pandas as pdplt.rcParams.update({'figure.figsize': (10, 7), 'figure.dpi': 120})# Import as Dataframedf = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/a10.csv', parse_dates=['date'])df.head()
时间序列数据框
此外,你也可以将文件读取为 pandas 序列,把日期作为索引列,只需在 pd.read_csv() 中指定 index_col 参数。ser = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/a10.csv', parse_dates=['date'], index_col='date')ser.head()
pandas 序列
注意,在 pandas 序列中,'value' 列的位置高于 'date' 列,这表明它是一个 pandas 序列而非数据框。
3、什么是面板数据?
面板数据同样是基于时间的数据集。
不同之处是,除了时间序列,面板数据还包括一个或多个相关变量,这些变量也是在同个时间段内测得的。
面板数据中的列包括有助于预测 y 值的解释变量,这些特征列可用于之后的预测。以下是关于面板数据的例子:# dataset source: https://github.com/rouseguydf = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/MarketArrivals.csv')df = df.loc[df.market=='MUMBAI', :]df.head()
面板数据
4、时间序列可视化
接下来,我们用 matplotlib 对序列进行可视化。# Time series data source: fpp pacakge in R.import matplotlib.pyplot as pltdf = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/a10.csv', parse_dates=['date'], index_col='date')# Draw Plotdef plot_df(df, x, y, title="", xlabel='Date', ylabel='Value', dpi=100):plt.figure(figsize=(16,5), dpi=dpi)plt.plot(x, y, color='tab:red')plt.gca().set(title=title, xlabel=xlabel, ylabel=ylabel)plt.show()plot_df(df, x=df.index, y=df.value, title='Monthly anti-diabetic drug sales in Australia from 1992 to 2008.')
时间序列可视化
由于所有的值都为正数,无论使用 y 轴的哪一侧都可以看到增长的趋势。# Import datadf = pd.read_csv('datasets/AirPassengers.csv', parse_dates=['date'])x = df['date'].valuesy1 = df['value'].values# Plotfig, ax = plt.subplots(1, 1, figsize=(16,5), dpi= 120)plt.fill_between(x, y1=y1, y2=-y1, alpha=0.5, linewidth=2, color='seagreen')plt.ylim(-800, 800)plt.title('Air Passengers (Two Side View)', fontsize=16)plt.hlines(y=0, xmin=np.min(df.date), xmax=np.max(df.date), linewidth=.5)plt.show()
飞机乘客数据 - 双边序列
由于这是一个月份的时间序列,每年的走势都遵循着特定重复的模式,你可以在同一个图中画出单独每年的折线。这样有助于对这几年的趋势走向进行平行对比。
季节性时间序列的可视化:# Import Datadf = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/a10.csv', parse_dates=['date'], index_col='date')df.reset_index(inplace=True)# Prepare datadf['year'] = [d.year for d in df.date]df['month'] = [d.strftime('%b') for d in df.date]years = df['year'].unique()# Prep Colorsnp.random.seed(100)mycolors = np.random.choice(list(mpl.colors.XKCD_COLORS.keys()), len(years), replace=False)# Draw Plotplt.figure(figsize=(16,12), dpi= 80)for i, y in enumerate(years):if i > 0:plt.plot('month', 'value', data=df.loc[df.year==y, :], color=mycolors[i], label=y)plt.text(df.loc[df.year==y, :].shape[0]-.9, df.loc[df.year==y, 'value'][-1:].values[0], y, fontsize=12, color=mycolors[i])# Decorationplt.gca().set(xlim=(-0.3, 11), ylim=(2, 30), ylabel='$Drug Sales$', xlabel='$Month$')plt.yticks(fontsize=12, alpha=.7)plt.title("Seasonal Plot of Drug Sales Time Series", fontsize=20)plt.sho
药品销售的季节性时间序列图
每年的二月份,药品销售会有一次大幅度下跌,三月份会回涨,四月份再次下跌,以此规律循环。很明显,该模式以年为单位,每年循环往复。
不过,随着年份的变化,药品销售总体呈上升趋势。你可以选择使用箱型图将这一趋势进行可视化,可以方便看出每一年的变化。同样地,你也可以按月份绘制箱型图,来观察每个月的变化。
按月份(季节)和年份绘制箱型图:你可以将数据处理成以季节为时间间隔,然后观察特定年份内值的分布,也可以将全部时间的数据进行对比。# Import Datadf = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/a10.csv', parse_dates=['date'], index_col='date')df.reset_index(inplace=True)# Prepare datadf['year'] = [d.year for d in df.date]df['month'] = [d.strftime('%b') for d in df.date]years = df['year'].unique()# Draw Plotfig, axes = plt.subplots(1, 2, figsize=(20,7), dpi= 80)sns.boxplot(x='year', y='value', data=df, ax=axes[0])sns.boxplot(x='month', y='value', data=df.loc[~df.year.isin([1991, 2008]), :])# Set Titleaxes[0].set_title('Year-wise Box Plo