根据上一篇文章对时序数据概念做了统一的描述,本文通过对国内汽车销量数据为例进行时序数据的季节成分分离。从结果看,此问题不能采用书本中的移动平均趋势剔除法。
01 数据读取
读取数据
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/camash/test_data_repository/master/carsales.csv')
season_series = df['日期']
conventional_series = df['传统汽车销量']
nev_series = df['新能源销量(万辆)x5']
total_series= conventional_series+nev_series
绘制时序数据的折线图
from matplotlib import rcParams
import matplotlib.pyplot as plt
rcParams['axes.unicode_minus']=False
rcParams['font.sans-serif']='SimHei' # 在mac上正常显示中文
plt.figure(figsize=(50,5))
plt.xlabel('时间')
plt.ylabel('万辆')
plt.xticks(rotation=70) # 将横坐标值旋转70度
plt.plot(season_series,conventional_series,'o-',color = 'r',label='传统汽车销量')
plt.plot(season_series,nev_series,'*-',color = 'g',label='新能源汽车销量')
plt.plot(season_series,total_series,'D-',color = 'b',label='所有汽车销量')
plt.legend(loc='best')
plt.show()

从上图可以得出以下几点直观理解:
首先整体趋势随之时间增长的; 在总体趋势下呈现出每年季节波动的影响; 从2013起新能源加入战场,份额逐渐增加; 近几年有销售直降的趋势,单次线性方程不能实现很好的拟合。
02 数据处理
02.01 总体销量中分离季节成分
这里采用移动平均趋势剔除法,对季节指数(seasonal index)进行调整。
计算移动平均值
# 计算4个季度的移动平均
for i in range(0,df.shape[0]-2):
df.loc[df.index[i],'TOTAL_MA_4'] = (df.iloc[i,5]+df.iloc[i+1,5]+df.iloc[i+2,5]+df.iloc[i+3,5])/4
# 再对移动平均做中心化处理,移动一位使首尾都空出两个空值
df['TOTAL_CMA']=df.iloc[:,11].rolling(window=2).mean().shift(1)
df['TOTAL_CMA']
0 NaN
1 NaN
2 115.37500
3 121.91250
4 125.93750
...
60 761.96000
61 721.90125
62 690.04500
63 NaN
64 NaN
Name: TOTAL_CMA, Length: 65, dtype: float64
计算移动平均的比值,即将每个季度的观察值除以相应的CMA
df['TOTAL_RATIO'] = total_series/df['TOTAL_CMA']
季度指数调整,使移动平均比值的平均值等于1
# 首先对季节分组,求比值的平均值
df['season']=df['日期'].str.slice(start=5,stop=7)
df_season_total = df[['season','TOTAL_RATIO']].groupby('season').mean()
df_season_total
TOTAL_RATIO
season
Q1 1.041809
Q2 1.019756
Q3 0.932039
Q4 1.003256
df_season_total.mean()
TOTAL_RATIO 0.999215
dtype: float64
# 将平均比值的平均值除以总的平均值,得到季节指数,其平均值为1
df_season_total['TOTAL_SEASON_INDEX']= df_season_total['TOTAL_RATIO']/0.999215
销售量除以季节指数
# 原始数据增加季节指数
for idx in df_season_total.index:
df.loc[df['season'] == idx,'TOTAL_SEASON_INDEX'] = df_season_total.loc[idx,]['TOTAL_SEASON_INDEX']
# 分离总销量中的季节成分
df['TOTAL_SALE'] = total_series/df['TOTAL_SEASON_INDEX']
# 绘制销量折现图
rcParams['axes.unicode_minus']=False
rcParams['font.sans-serif']='SimHei' # 在mac上正常显示中文
plt.figure(figsize=(50,5))
plt.xlabel('时间')
plt.ylabel('万辆')
plt.xticks(rotation=70) # 将横坐标值旋转70度
plt.plot(season_series,total_series,'D-',color = 'b',label='所有汽车销量')
plt.plot(season_series,df['TOTAL_SALE'],'o-',color = 'r',label='分离季节成分的汽车销量')
plt.legend(loc='best')
plt.show()

从图形上看,即使使用了季节成分分离,由于销量本身的涨跌幅度过大,可以判断为非平稳时间序列。因此,另写一篇文章使用ARIMA对时间序列进行拟合和预测。
文章转载自FishData,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




