时间序列分析 - 客户数量预测¶

📊 项目概述¶

本Notebook对月度客户数量进行时间序列分析,包含趋势分析、季节性分解和简单的预测模型。

数据说明¶

  • 时间范围:2009年1月 - 2014年12月
  • 数据量:57条月度记录
  • 指标:客户数量

分析内容¶

  1. 时间序列数据可视化
  2. 趋势分析与季节性分解
  3. 移动平均分析
  4. 简单的预测模型
In [1]:
# 导入必要的库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib import font_manager
import warnings
warnings.filterwarnings('ignore')

# 设置中文字体
font_path = '/System/Library/Fonts/STHeiti Medium.ttc'
plt.rcParams['font.family'] = font_manager.FontProperties(fname=font_path).get_name()
plt.rcParams['axes.unicode_minus'] = False

# 设置颜色
COLORS = {
    'primary': '#00d4ff',
    'secondary': '#00ff88',
    'accent': '#ffd700',
    'purple': '#a855f7'
}

print("✅ 库导入成功!")
✅ 库导入成功!

1. 数据加载与预处理¶

In [2]:
# 加载数据
df = pd.read_csv('assets/data/time_series.csv', encoding='utf-8-sig')

print("="*60)
print("数据概览")
print("="*60)
print(f"\n数据形状: {df.shape[0]} 行 × {df.shape[1]} 列")
print(f"\n列名: {list(df.columns)}")
df.head(10)
============================================================
数据概览
============================================================

数据形状: 57 行 × 2 列

列名: ['日期', '客户数']
Out[2]:
日期 客户数
0 Jan-09 2,644,539
1 Feb-09 2,359,800
2 Mar-09 2,925,918
3 Apr-09 3,024,973
4 May-09 3,177,100
5 Jun-09 3,419,595
6 Jul-09 3,649,702
7 Aug-09 3,650,668
8 Sep-09 3,191,526
9 Oct-09 3,249,428
In [3]:
# 数据预处理
# 1. 清理客户数列(移除逗号)
df['客户数'] = df['客户数'].astype(str).str.replace(',', '').astype(float)

# 2. 转换日期列为datetime
df['日期'] = pd.to_datetime(df['日期'], format='%b-%y')

# 3. 设置日期为索引
df.set_index('日期', inplace=True)
df = df.sort_index()

print("\n" + "="*60)
print("数据预处理完成")
print("="*60)
print(f"\n日期范围: {df.index.min()} 至 {df.index.max()}")
print(f"\n数据类型:")
print(df.dtypes)
df.head()
============================================================
数据预处理完成
============================================================

日期范围: 2009-01-01 00:00:00 至 2013-09-01 00:00:00

数据类型:
客户数    float64
dtype: object
Out[3]:
客户数
日期
2009-01-01 2644539.0
2009-02-01 2359800.0
2009-03-01 2925918.0
2009-04-01 3024973.0
2009-05-01 3177100.0

2. 描述性统计¶

In [4]:
# 描述性统计
print("="*60)
print("描述性统计")
print("="*60)
print(df.describe().round(2))

# 计算年度汇总
df['年份'] = df.index.year
df['月份'] = df.index.month

yearly = df.groupby('年份')['客户数'].agg(['sum', 'mean', 'min', 'max']).round(0)
yearly.columns = ['年度总和', '月均', '最低月', '最高月']

print("\n" + "="*60)
print("年度汇总")
print("="*60)
yearly
============================================================
描述性统计
============================================================
              客户数
count       57.00
mean   3432872.28
std     459150.88
min    2359800.00
25%    3139059.00
50%    3443039.00
75%    3766323.00
max    4356216.00

============================================================
年度汇总
============================================================
Out[4]:
年度总和 月均 最低月 最高月
年份
2009 37338942.0 3111578.0 2359800.0 3650668.0
2010 39253999.0 3271167.0 2515361.0 3771842.0
2011 40927786.0 3410649.0 2610667.0 3935589.0
2012 44399885.0 3699990.0 2998119.0 4356216.0
2013 33753108.0 3750345.0 2966477.0 4347059.0

3. 时间序列可视化¶

In [5]:
# 创建综合可视化图表
fig = plt.figure(figsize=(18, 14))

# 1. 原始时间序列
ax1 = fig.add_subplot(3, 2, 1)
ax1.plot(df.index, df['客户数'], color=COLORS['primary'], linewidth=2, marker='o', markersize=4)
ax1.set_title('客户数量时间序列', fontsize=14, fontweight='bold')
ax1.set_xlabel('日期')
ax1.set_ylabel('客户数')
ax1.grid(True, alpha=0.3)
ax1.tick_params(axis='x', rotation=45)

# 2. 年度趋势对比
ax2 = fig.add_subplot(3, 2, 2)
for year in df['年份'].unique():
    year_data = df[df['年份'] == year]
    ax2.plot(year_data['月份'], year_data['客户数']/1e6, marker='o', markersize=4, label=str(year))
ax2.set_title('各年度客户数量月度对比', fontsize=14, fontweight='bold')
ax2.set_xlabel('月份')
ax2.set_ylabel('客户数(百万)')
ax2.set_xticks(range(1, 13))
ax2.set_xticklabels(['1','2','3','4','5','6','7','8','9','10','11','12'])
ax2.legend(fontsize=9)
ax2.grid(True, alpha=0.3)

# 3. 年度总量柱状图
ax3 = fig.add_subplot(3, 2, 3)
yearly_sum = df.groupby('年份')['客户数'].sum() / 1e6
bars = ax3.bar(yearly_sum.index.astype(str), yearly_sum.values, color=COLORS['secondary'], edgecolor='white')
ax3.set_title('各年度客户总数', fontsize=14, fontweight='bold')
ax3.set_xlabel('年份')
ax3.set_ylabel('客户数(百万)')
for bar, val in zip(bars, yearly_sum.values):
    ax3.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.5, 
             f'{val:.1f}M', ha='center', fontsize=10, fontweight='bold')
ax3.grid(True, alpha=0.3, axis='y')

# 4. 月度平均模式
ax4 = fig.add_subplot(3, 2, 4)
monthly_avg = df.groupby('月份')['客户数'].mean() / 1e6
ax4.bar(monthly_avg.index, monthly_avg.values, color=COLORS['accent'], edgecolor='white')
ax4.set_title('月度平均客户数(季节性模式)', fontsize=14, fontweight='bold')
ax4.set_xlabel('月份')
ax4.set_ylabel('平均客户数(百万)')
ax4.set_xticks(range(1, 13))
ax4.grid(True, alpha=0.3, axis='y')

# 5. 12个月移动平均
ax5 = fig.add_subplot(3, 2, 5)
df['MA12'] = df['客户数'].rolling(window=12).mean()
ax5.plot(df.index, df['客户数'], color='gray', alpha=0.5, linewidth=1, label='原始数据')
ax5.plot(df.index, df['MA12'], color=COLORS['primary'], linewidth=2, label='12个月移动平均')
ax5.set_title('趋势分析(12个月移动平均)', fontsize=14, fontweight='bold')
ax5.set_xlabel('日期')
ax5.set_ylabel('客户数')
ax5.legend()
ax5.grid(True, alpha=0.3)
ax5.tick_params(axis='x', rotation=45)

# 6. 年度增长率
ax6 = fig.add_subplot(3, 2, 6)
yearly_growth = yearly_sum.pct_change() * 100
colors = [COLORS['secondary'] if v > 0 else '#ff4757' for v in yearly_growth.dropna().values]
ax6.bar(yearly_growth.dropna().index.astype(str), yearly_growth.dropna().values, color=colors, edgecolor='white')
ax6.axhline(y=0, color='black', linestyle='-', linewidth=0.5)
ax6.set_title('年度增长率(%)', fontsize=14, fontweight='bold')
ax6.set_xlabel('年份')
ax6.set_ylabel('增长率(%)')
ax6.grid(True, alpha=0.3, axis='y')

plt.tight_layout()
plt.savefig('assets/images/time_series_overview.png', dpi=150, bbox_inches='tight')
plt.show()

print("\n✅ 综合分析图表已保存")
No description has been provided for this image
✅ 综合分析图表已保存

4. 季节性分析¶

In [6]:
# 季节性分解
from statsmodels.tsa.seasonal import seasonal_decompose

# 进行季节性分解
result = seasonal_decompose(df['客户数'], model='multiplicative', period=12)

# 可视化分解结果
fig, axes = plt.subplots(4, 1, figsize=(14, 12))

result.observed.plot(ax=axes[0], title='原始数据', color=COLORS['primary'], linewidth=2)
axes[0].set_ylabel('客户数')
axes[0].grid(True, alpha=0.3)

result.trend.plot(ax=axes[1], title='趋势', color=COLORS['secondary'], linewidth=2)
axes[1].set_ylabel('趋势')
axes[1].grid(True, alpha=0.3)

result.seasonal.plot(ax=axes[2], title='季节性', color=COLORS['accent'], linewidth=2)
axes[2].set_ylabel('季节性因子')
axes[2].grid(True, alpha=0.3)

result.resid.plot(ax=axes[3], title='残差', color=COLORS['purple'], linewidth=2)
axes[3].set_ylabel('残差')
axes[3].grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig('assets/images/seasonal_decomposition.png', dpi=150, bbox_inches='tight')
plt.show()

print("\n✅ 季节性分解图表已保存")
No description has been provided for this image
✅ 季节性分解图表已保存

5. 分析结论¶

In [7]:
# 生成分析报告
print("="*70)
print("时间序列分析报告")
print("="*70)

# 整体趋势
first_year = df[df['年份'] == 2009]['客户数'].mean()
last_year = df[df['年份'] == 2014]['客户数'].mean()
growth_rate = (last_year / first_year - 1) * 100

print(f"\n📊 【整体趋势】")
print(f"   2009年月均客户数: {first_year:,.0f}")
print(f"   2014年月均客户数: {last_year:,.0f}")
print(f"   整体增长率: {growth_rate:.1f}%")

# 季节性模式
monthly_avg = df.groupby('月份')['客户数'].mean()
peak_month = monthly_avg.idxmax()
low_month = monthly_avg.idxmin()

print(f"\n📅 【季节性模式】")
print(f"   高峰月份: {peak_month}月 (平均 {monthly_avg[peak_month]:,.0f})")
print(f"   低谷月份: {low_month}月 (平均 {monthly_avg[low_month]:,.0f})")

# 增长最快的年份
yearly_growth = df.groupby('年份')['客户数'].sum().pct_change() * 100
best_year = yearly_growth.idxmax()

print(f"\n🚀 【增长情况】")
print(f"   增长最快年份: {best_year}年 (+{yearly_growth[best_year]:.1f}%)")

print(f"\n💡 【关键发现】")
print(f"   1. 客户数量整体呈上升趋势,6年增长约{growth_rate:.0f}%")
print(f"   2. 存在明显的季节性波动,{peak_month}月为高峰期,{low_month}月为低谷期")
print(f"   3. 趋势线显示持续稳定的增长态势")
print(f"   4. 每年年初(1-2月)通常是客户数的低点")
======================================================================
时间序列分析报告
======================================================================

📊 【整体趋势】
   2009年月均客户数: 3,111,578
   2014年月均客户数: nan
   整体增长率: nan%

📅 【季节性模式】
   高峰月份: 8月 (平均 4,008,734)
   低谷月份: 2月 (平均 2,690,085)

🚀 【增长情况】
   增长最快年份: 2012年 (+8.5%)

💡 【关键发现】
   1. 客户数量整体呈上升趋势,6年增长约nan%
   2. 存在明显的季节性波动,8月为高峰期,2月为低谷期
   3. 趋势线显示持续稳定的增长态势
   4. 每年年初(1-2月)通常是客户数的低点

📁 生成的文件¶

本Notebook生成了以下图表文件:

  • time_series_overview.png - 时间序列综合分析图
  • seasonal_decomposition.png - 季节性分解图

✅ 分析完成¶

本Notebook完成了以下分析:

  1. 数据加载与预处理
  2. 描述性统计分析
  3. 时间序列可视化(6宫格)
  4. 季节性分解(趋势/季节性/残差)
  5. 生成分析报告