从股票价格波动,到司机气温变化,从大桥沉降预测,到城市用电预警,时间序列数据广泛存在于量化交易、回归预测等机器学习应用,是最常见的数据类型。
接下来使用Python对一个经典的时间序列数据集:墨尔本十年气温变化数据集,进行以下工作:
- 探索性数据挖掘和数据可视化:绘制折线图、热力图、箱型图、小提琴图、滞后图、自相关图,让枯燥的时间序列颜值爆表!
- 对时间做特征工程:拓展时间数据纬度,这个代码模板也可以作为时间序列数据的通用预处理模板。
- 使用三种机器学习模型建立回归拟合模型:岭回归、随机森林、神经网络,并可视化展示三种模型的回归拟合效果。
导入墨尔本1980-1990十年气温数据集
下载数据集
导入数据集
# 导入Python的数据处理库Pandas,相当于Python里的Excel
import pandas as pd
#导入Python绘图matplotlib
import matplotlib.pyplot as plt
# 使用ipython的魔法方法,将绘制出的图像直接嵌入在notebook单元格中
%matplotlib inline
#设置绘图大小
plt.style.use({'figure.figsize':(25,20)})
plt.rcParams['font.sans-serif']=['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False # 用来正常显示负号
#调用pandas的read_csv函数读取数据集文件
df = pd.read_csv('daily-minimum-temperature.csv')
探索数据集
# 查看df这张二维表格
df
第一列Date为日期,也就是时间序列,我们将第一列的数据类型转换为pandas中的datetime日期类型,并将这一列作为数据的索引,便于后续处理
df['Date'] = pd.to_datetime(df['Date'])
df = df.set_index('Date')
#查看各列的信息
df.info()
探索性数据分析
#查看前五行
df.head()
df.shape
共有3650行数据,每一行数据都表示一天,总共表示了1980年1月1日到1990年12月31十年间墨尔本每天的最低气温
#查看df中割裂数据的统计特征
df.describe()
绘制折线图
df['Temp'].plot(figsize=(30,15))
#设置坐标字体大小
plt.tick_params(labelsize=30)
#生成刻度线网格
plt.grid()
折线图容易产生毛刺,可以换成散点图。
df['Temp'].plot(style='k.',figsize=(30,15))
#设置坐标字体大小
plt.tick_params(labelsize=30)
#生成刻度线网格
plt.grid()
直方图
hist表示在一定范围内的数的个数的统计,与bar不相同,bar表示的是每个数的数据,hist表示在一定范围内的数的个数。binas参数表示横轴多少等分。
# 设置绘图大小
plt.style.use({'figure.figsize':(5,5)})
df['Temp'].plot(kind='hist',bins=20)
df['Temp'].hist(bins=50)
堆积面积图
#seaborn是基于matplotlib的Python可视化库,将matplotlib库进行了进一步封装,使用更加简单,而且绘制出的图标更加高大上
#导入Python可视化库seaborn
import seaborn as sns
df.plot.area(stacked=False)
核密度估计图(KDE)
df['Temp'].plot(kind='kde')
热力图
将1982年每一个月的平均气温用热力图展示出来。
resample(‘M’)是按月份重采样
plt.style.use({'figure.figsize':(20,8)})
sns.heatmap(df['1982'].resample('M').mean().T)
为什么6月和7月气温最低呢?因为墨尔本在澳大利亚,属于南半球,6月和7月是冬天
筛选指定日期的数据
我们刚刚将日期列转换为了pandas中的datetime类型,我们可以直接通过年份和日期索引选择指定时间的数据。
df['1984']
#将每年和每天的温度筛选出来
groups = df.groupby(pd.Grouper(freq='1Y'))['Temp']
from pandas import DataFrame
years = DataFrame()
for name,group in groups:
years[name.year] = group.values
years
# 设置绘图大小
plt.style.use({'figure.figsize':(30,15)})
years.plot()
#设置图例文字大小和图示大小
plt.legend(fontsize=15,markerscale=15)
#设置坐标文字大小
plt.tick_params(labelsize=15)
绘制每年的变化折线图、箱型图、热力图、小提琴图
绘制每年的变化折线图、箱型图、热力图、小提琴图
years.boxplot(figsize=(20,10))
#设置绘图大小
plt.style.use({'figure.figsize':(30,10)})
sns.heatmap(years.T)
# 矩阵可视化
plt.matshow(years.T,interpolation=None,aspect='auto')
#设置绘图大小
plt.style.use({'figure.figsize':(30,22)})
years.hist(bins=15)
#选取1985年12个月每天的气温数据
groups_month = df['1985'].groupby(pd.Grouper(freq='1M'))['Temp']
months = pd.concat([DataFrame(x[1].values) for x in groups_month], axis=1)
months = DataFrame(months)
months.columns = range(1,13)
months.boxplot(figsize=(20,15))
plt.title('墨尔本1982年每个月最低温度分布箱型图')
months
# 设置图像大小
plt.style.use({'figure.figsize':(15,10)})
sns.violinplot(data=months)
plt.title('墨尔本1982年每个月最低气温分布小提琴图')
# linewidth参数可以控制线宽
sns.violinplot(data=months,linewidth=3)
plt.title('墨尔本1982年每个月最低气温分布小提琴图')
# 设置图像大小
plt.style.use({'figure.figsize':(5,8)})
sns.heatmap(months)
plt.title('墨尔本1982年每天最低气温分布热力图')
plt.matshow(months, interpolation=None, aspect='auto',cmap='rainbow')
滞后散点图
时间序列分析假定一个观测值与前面的观测值之间存在一定的关系。 相对于某观察值之前的观测值被称为滞后值,在一个时间步长前的观测值称为滞后一期,在两个时间步长前的观测值为滞后二期,依此类推。 比如,对于1982年8月15日的气温数据,8月14日的气温为滞后一期,8月13日的气温为滞后二期。 每个观察值之间和其滞后值之间的关系可以用滞后散点图表示。
#设置图片大小
plt.style.use({'figure.figsize':(10,10)})
from pandas.plotting import lag_plot
lag_plot(df['Temp'])
plt.title('墨尔本1980-1990年最低气温滞后一期散点图')
散点图聚在左下角到右上角,表示与滞后值正相关。 散点图聚在左上角到右下角,表示与滞后值负相关。 离对角线越紧密,表明相关关系越强。 分散的球状散点图表明相关关系微弱。
lag_list = [1,2,3,5,10,20,50,100,150,180]
plt.style.use({'figure.figsize':(15,35)})
for i in range(len(lag_list)):
ax = plt.subplot(5,2,i+1)
ax.set_title('t vs t+' + str(lag_list[i]))
lag_plot(df['Temp'],lag=lag_list[i])
plt.title('墨尔本1980-1990年最低气温滞后{}期散点图'.format(lag_list[i]))
自相关图
高中数学就讲过的,两个随机变量之间的pearson相关性系数
但是对于我们的时间序列来说, 需要比较的两个随机变量分别是: 一段时间的温度值,以及这段时间之前某段时间的温度值序列。
相关性系数的公式稍微有一些改变。
比如我们有一个星期的温度数据,即T=7 当我们选择滞后值为3,也就是比较每段序列和它之前三天的序列, 带入公式,分子的第一个括号是周四到周日的温度与一周平均温度的差值 分子的第二个括号是周一到周三的温度与一周平均温度的差值 分母的括号为一周每天的温度与一周平均温度的差值
# 设置图像大小
plt.style.use({'figure.figsize':(15,10)})
import numpy as np
from pandas.plotting import autocorrelation_plot
autocorrelation_plot(df['Temp'])
plt.title('墨尔本1980-1990年最低气温自相关图')
# 设置坐标文字大小
plt.tick_params(labelsize=10)
# plt.xticks(np.linspace(0, 3650, 7))
plt.yticks(np.linspace(-1, 1, 20))
# 设置图像大小
plt.style.use({'figure.figsize':(10,5)})
import numpy as np
a = np.random.randn(100)
a = pd.Series(a)
lag_plot(a)
plt.title('随机数列的1期滞后散点图')
autocorrelation_plot(a)
plt.title('随机数列的自相关图')