基于季节性时序数据的Python聚类模型选型求助
解决方案:基于季节性趋势的时序聚类方案
一、核心问题定位
之前使用TimeSeriesKMeans仅得到数值高低的聚类结果,本质是没有把ID自身的季节性相对波动作为聚类依据,而是用了原始时序或全局标准化后的绝对数值,忽略了"相对自身升降"的核心需求。
二、数据预处理:提取季节性特征(关键步骤)
先将数据转换为能体现每个ID月度相对波动的特征向量,这是实现趋势聚类的基础:
补全缺失月份并填充0
为每个ID生成完整的1-12月序列,缺失月份的X1设为0:import pandas as pd # 读取原始数据 df = pd.read_csv("your_data.csv", sep=" ") # 解析月份和年份 df['month'] = pd.to_datetime(df['YR-MONTH']).dt.month df['year'] = pd.to_datetime(df['YR-MONTH']).dt.year # 生成每个ID的完整年月网格 ids = df['ID'].unique() years = df['year'].unique() full_index = pd.MultiIndex.from_product([ids, years, range(1,13)], names=['ID', 'year', 'month']) full_df = df.set_index(['ID', 'year', 'month']).reindex(full_index, fill_value=0).reset_index()计算月度相对波动特征
对每个ID,计算每个月份X1相对于自身全年平均值的比值,突出"相对自身的升降趋势":# 计算每个ID每年的X1平均值 full_df['annual_avg'] = full_df.groupby(['ID', 'year'])['X1'].transform('mean') # 避免除以0,添加极小值epsilon epsilon = 1e-8 full_df['seasonal_ratio'] = full_df['X1'] / (full_df['annual_avg'] + epsilon) # 提取每个ID的12维季节性特征向量(1-12月的平均相对比值) seasonal_features = full_df.groupby(['ID', 'month'])['seasonal_ratio'].mean().unstack()
三、聚类模型选择与实现
基于提取的季节性特征,可选择以下方案:
1. 改进版K-Means(推荐)
直接用12维季节性特征做聚类,聚焦趋势模式而非绝对数值:
from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler # 标准化特征(让每个月份的波动权重一致) scaler = StandardScaler() scaled_features = scaler.fit_transform(seasonal_features) # 训练K-Means,k为自定义聚类数 k = 3 kmeans = KMeans(n_clusters=k, random_state=42) seasonal_features['cluster'] = kmeans.fit_predict(scaled_features)
2. 层次聚类
适合需要观察聚类层级关系的场景:
from sklearn.cluster import AgglomerativeClustering import scipy.cluster.hierarchy as sch import matplotlib.pyplot as plt hc = AgglomerativeClustering(n_clusters=k, linkage='ward') seasonal_features['cluster_hc'] = hc.fit_predict(scaled_features) # 绘制树状图查看聚类层级 plt.figure(figsize=(10,6)) sch.dendrogram(sch.linkage(scaled_features, method='ward')) plt.title('Dendrogram of Seasonal Trends') plt.show()
3. 基于形状的时序聚类(tslearn改进)
若坚持用时序聚类,需对每个ID的时序单独做归一化,突出形状而非数值:
from tslearn.clustering import TimeSeriesKMeans from tslearn.preprocessing import TimeSeriesScalerMinMax # 整理每个ID的12月时序序列 time_series = [] for idx in seasonal_features.index: ts = full_df[full_df['ID'] == idx].sort_values('month')['X1'].values time_series.append(ts) # 对每个时序单独做MinMax归一化 scaler = TimeSeriesScalerMinMax() scaled_ts = scaler.fit_transform(time_series) # 用DTW距离训练TimeSeriesKMeans(更适配时序形状匹配) ts_kmeans = TimeSeriesKMeans(n_clusters=k, metric="dtw", random_state=42) clusters = ts_kmeans.fit_predict(scaled_ts)
四、聚类效果验证
通过可视化每个聚类的平均季节性趋势,验证是否符合预期:
import seaborn as sns # 计算每个聚类的月度平均相对比值 cluster_avg = seasonal_features.groupby('cluster').mean().T.reset_index() cluster_avg = cluster_avg.melt(id_vars='month', var_name='cluster', value_name='avg_ratio') # 绘制趋势对比图 sns.lineplot(data=cluster_avg, x='month', y='avg_ratio', hue='cluster') plt.title('Average Seasonal Trend by Cluster') plt.show()
内容的提问来源于stack exchange,提问作者RRAIN
相关产品推荐
相关产品推荐

