【技术实现】如何通过seasonal_decompose库挖掘数据长期趋势,赋能业务决策?

说明:代码基于Python,seasonal_decompose库。

文献:time-series-decomposition Tutorial。

一、写在前面

在上一篇  指标下降如何分析?分享一种“因子评分法”,帮你快速定位原因 文章中,我分享了一种基于细分和对比思维的分析小技巧,它是基于业务维度进行展开。

除此之外,我们在工作中,常会选择时间维度,对数据进行分析,即时间序列分析。其范围涵盖多个方面:

  • 通过趋势变化,找数据突变,分析原因;

  • 通过最小二乘拟合,选择合适的回归模型;

  • 通过移动平均,“平滑”数据,消除“抖动”;

  • 通过时间衰变关系,预测未来走势。

不同的分析方法,都指向同一个目的,即通过更好地挖掘数据信息,为业务提供洞见,应对未来。

本文同样秉持这个信念。相关的技术实现,是通过Python的seasonal_decompose库,来把整体数据一分为三:

  • 表征数据长期发展方向的趋势部分(Trend);

  • 反应数据固定规律波动的周期部分(Cyclical);

  • 剔除趋势和周期数据表现的噪声部分(Noise)。

即:

Total(整体) = Trend(趋势) + Cyclical(周期) + Noise(噪声)

Total(整体) = Trend(趋势) * Cyclical(周期) * Noise(噪声)

关于方包的计算细节,可见第四部分的【原理简述】。

二、业务背景

约定本文业务背景:

Excel文件为2022年3月至9月每天的某APP日活(DAU)数据。通过DAU表现,为未来策略制定方向。

如图1所示,为部分数据截图。其中,字段date表示日期,dau表示活跃用户数。

【技术实现】如何通过seasonal_decompose库挖掘数据长期趋势,赋能业务决策?_第1张图片 图1 DAU数据概览

三、技术细节

1、读取数据

首先加载方包:

import pandas as pd
import datetime
import matplotlib.pyplot as plt
from statsmodels.tsa.seasonal import seasonal_decompose

其中seasonal_decompose包,为本次时间序列分析的核心方包。

加载Excel,并调整时间字段格式,打印信息:

df=pd.read_excel(r'E:\文章资料\20221029-时间序列\daudata.xlsx',index_col='date')
df.index = pd.to_datetime(df.index) #转换索引格式为日期格式
df = df.sort_index() #对索引进行排序
print(df.head(10))
print(df.info())

如图2,为数据的前10行,和dataframe基本信息。可知,总共有214行有效非空数据。

【技术实现】如何通过seasonal_decompose库挖掘数据长期趋势,赋能业务决策?_第2张图片 图2 dataframe信息预览

2、整体表现

观察数据趋势,了解数据基本表现情况:

fig=plt.figure(figsize=(18,6))
labels=list(df.index)
plt.xlabel('Date',fontsize=14)
plt.ylabel('DAU',fontsize=14)
plt.title('DAU of 2022.03-2022.09',fontsize=14)
plt.plot(df.index,df['dau'],color='#22BABB')

如图3,为3至9月份DAU整体趋势。从图中可以看出:DAU整体趋势稳中向好,且存在较为显著的周期波动。

【技术实现】如何通过seasonal_decompose库挖掘数据长期趋势,赋能业务决策?_第3张图片 图3 DAU整体趋势

通过将数据周期限制为一个月,可以暂定DAU波动周期为7天(为后续分解数据做准备)。

3、数据细分

按照前面说的,选择 Total = Trend + Cyclical + Noise,将原始数据分为3个部分:

decomposition = seasonal_decompose(df['dau'],period=7) #(1)
trend = decomposition.trend #(2)
cyclical = decomposition.seasonal #(3)
noise = decomposition.resid #(4)

语句里,(1)中seasonal_decompose函数的period参数表示周期天数,常取7、30、7*4*3、365,约等于周、月、季、年。

(2)(3)(4)的目的是,分别将拆分后得到的趋势、周期、噪声数据,存入新的别名中。

4、细分表现

关注Trend部分:

fig_t=trend.plot(figsize=(9,3),color='#9EF8EE')
plt.xlabel('Date',fontsize=12)
plt.ylabel('DAU',fontsize=12)
plt.title('Trend Component of DAU',fontsize=12)

如图4,为DAU的趋势部分。可以看出,DAU从6月开始急速攀升,直到8月趋于稳定,9月后有所略微下滑。

【技术实现】如何通过seasonal_decompose库挖掘数据长期趋势,赋能业务决策?_第4张图片 图4 DAU趋势部分

关注Cyclical部分,由于7天为1个周期,所以分析2个月的数据足矣。此处选择3至5月的数据:

fig_c=cyclical.loc[[datetime.date(2022,3,1) <= i < datetime.date(2022,5,1) for i in df.index]].plot(figsize=(9,3),color='#FA7F08',marker='o')
plt.xlabel('Date',fontsize=12)
plt.ylabel('DAU',fontsize=12)
plt.title('Cyclical Component of DAU',fontsize=12)

如图5,为DAU的周期部分。从图中看出,周期内第6天和第7天DAU为低值,说明该APP的用户,周日和周一最不活跃(3月1日是周日,3月2日是周一)。这是什么行业才具有的特征呢?

【技术实现】如何通过seasonal_decompose库挖掘数据长期趋势,赋能业务决策?_第5张图片 图5 DAU周期部分

关注Noise部分,简单起见,以8至9月份数据为例:

fig_n=noise.loc[[datetime.date(2022,8,1) <= i for i in df.index]].plot(figsize=(9,3),marker='o',color='#F24405')
plt.xlabel('Date',fontsize=12)
plt.ylabel('DAU',fontsize=12)
plt.title('Noise Component of DAU',fontsize=12)

如图6,为DAU的噪声部分。可以看出,绝大部分噪声数据均落在[-1000,1000]范围内。

【技术实现】如何通过seasonal_decompose库挖掘数据长期趋势,赋能业务决策?_第6张图片 图6 DAU噪声部分

但是8月26、27和29日这3天的数据,很不听话地游离在范围之外,显得比较另类。这种异常,往往就是需要我们重点关注的对象。

5、细分整合

整合3个细分部分数据,绘制在同一个图中:

fig_total=plt.figure(figsize=(18,16))
plt.figure(1)
plt.subplots_adjust(hspace=0.35)
ax1 = plt.subplot(411)
ax1.plot(df.index,df['dau'],color='#22BABB')
ax1.set_title('DAU of 2022.03-2022.09',fontsize=14,fontweight="bold")
ax2 = plt.subplot(412)
ax2.plot(trend,color='#9EF8EE')
ax2.set_title('Trend Component',fontsize=12)
ax3 = plt.subplot(413)
ax3.plot(cyclical,color='#FA7F08')
ax3.set_title('Cyclical Component',fontsize=12)
ax4 = plt.subplot(414)
ax4.plot(noise,color='#F24405')
ax4.set_title('Noise Component',fontsize=12)

如图7,为整体趋势和细分趋势的对比总览图。

【技术实现】如何通过seasonal_decompose库挖掘数据长期趋势,赋能业务决策?_第7张图片 图7 DAU整体和细分总览图

如果不是像我这样的“精致boy”,事实上只需要2条命令,就可以实现图7的大体效果:

fig = decomposition.plot()
fig.set_size_inches(18,8)

四、原理简述

上述操作的核心,是通过seasonal_decompose库将数据分成3部分,语法不难。那么,整个过程到底是肿么实现的呢?

实际的计算的过程,与上述代码步骤很类似,这里长话短说:

  1. 确定周期长度。根据数据表现,确定周期天数,比如本文将7天作为数据周期;

  2. 分解趋势数据。通过移动平均法,计算整体趋势,平均的数据范围就是第1步选择的周期;

  3. 分解周期和噪声数据。需要确定3个组成部分,是应该相乘还是相加。可以根据周期波动的幅度,随时间变化的规律来确定。比如时间越长波动幅度越大时,3者应该相乘,否则相加;

  4. 分解周期数据。以7天为周期举例:周期第1天的数据,为所有周期内第1天的数据求平均。以此类推;

  5. 分解噪声数据。根据第3和第4步,求解出噪声数据。

这5步看起来简单,实则坑相当多。比如:

  • 周期的判断,并不是一直那么显然;

  • 周期奇偶不同,移动平均法计算方式不同;

  • 相乘还是相加?有时不是那么明显……

考虑到篇幅不宜过长,不要指望本文去做详细的计算。

有兴趣的同学,可以按照上述步骤,搭配Tutorial,用Excel去踩踩坑。

五、写在最后

数据分解只是第一步,接下来,可以做的方向包括但不限于:

  • 数据预测;

  • 异常预警;

  • 根据Cyclical,动态调整投放策略;

  • 根据Trend,评判平台发展健康度;

  • ……

数据分析方法层出不穷,可套用的模型千千万万。但是一定要在业务能理解、数据可解释的范畴之内,做出最优的选择。

正所谓是,

分析千万条,能用好用第一条;

模型高大上,业务数据四行泪。

你可能感兴趣的:(曾哥数据分析,python,开发语言)