You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python实现多时间序列聚类?含Sklearn与Tslearn方案

问题描述

需求

将10家门店(实际场景为150+门店、20年数据)基于2021-2022年的points、assists、rebounds多维数据分为6个聚类。

尝试情况

使用sklearn.cluster.KMeans仅能处理单周期数据,接触到tslearn的TimeSeriesKMeans结合动态时间规整(DTW),但对数据重构和预处理步骤存在疑问。

具体问题

  1. 如何使用sklearn.cluster.KMeans实现时间序列聚类?
  2. 使用tslearn.clustering.TimeSeriesKMeans前,正确的数据结构是什么?

测试数据代码

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from tslearn.clustering import TimeSeriesKMeans

df_full =  pd.DataFrame({'year':[2021,2021,2021,2021,2021,2021,2021,2021,2021,2021,
                            2022,2022,2022,2022,2022,2022,2022,2022,2022,2022],
                     'store':['store1','store2','store3','store4','store5','store6','store7','store8','store9','store10',
                    'store1','store2','store3','store4','store5','store6','store7','store8','store9','store10'],
                'points': [18, 33, 19, 14, 14, 11, 20, 28, 30, 31,
                          35, 33, 29, 25, 25, 27, 29, 30, 19, 23],
               'assists': [3, 3, 4, 5, 4, 7, 8, 7, 6, 9, 12, 14,
                           5, 9, 4, 3, 4, 12, 15, 11],
               'rebounds': [15, 14, 14, 10, 8, 14, 13, 9, 5, 4,
                            11, 6, 5, 5, 3, 8, 12, 7, 6, 5]})

单周期Sklearn KMeans尝试代码

# For a single year
df = df_full[df_full['year']==2021].copy()

# Make year and store as index before applying cluster
df.set_index(['year','store'], inplace=True)

scaled_df = StandardScaler().fit_transform(df)

kmeans_kwargs = {
"init": "random",
"n_init": 1,
"random_state": 1}

#create list to hold SSE values for each k
sse = []
for k in range(2, 8):
kmeans = KMeans(n_clusters=k, **kmeans_kwargs)
kmeans.fit(scaled_df)
sse.append(kmeans.inertia_)

#instantiate the k-means class, using optimal number of clusters
kmeans = KMeans(init="random", n_clusters=6 ,n_init=1, random_state=1)

#fit k-means algorithm to data
kmeans.fit(scaled_df)

#view cluster assignments for each observation
kmeans.labels_

df['cluster'] = kmeans.labels_
print(df) 

Tslearn TimeSeriesKMeans尝试代码

df_dtw = df_full.set_index(['year','store'])
model = TimeSeriesKMeans(n_clusters=6, metric="dtw",
                     max_iter=10, random_state=1)
model.fit(df_dtw)
df_dtw['cluster'] = model.labels_
print(df_dtw)

解决方案

1. 用Sklearn KMeans实现时间序列聚类的方法

Sklearn的KMeans本身不直接支持时间序列,需通过特征工程将时间序列转化为静态特征向量,再执行聚类。针对门店多维时间序列数据,步骤如下:

步骤1:重构数据结构

将每个门店的多周期、多指标数据转化为扁平特征向量。比如每个门店2年数据、3个指标,对应2*3=6个特征(2021_points、2021_assists、2021_rebounds、2022_points、2022_assists、2022_rebounds)。

# 透视重构:每个门店一行,年度指标转为列
df_pivot = df_full.pivot(index='store', columns='year', values=['points', 'assists', 'rebounds'])
# 扁平化列名
df_pivot.columns = [f'{col[0]}_{col[1]}' for col in df_pivot.columns]
df_pivot.reset_index(inplace=True)

步骤2:数据标准化

时间序列指标量级差异大,需做标准化处理:

# 提取特征列(排除门店标识)
features = df_pivot.drop('store', axis=1)
scaler = StandardScaler()
scaled_features = scaler.fit_transform(features)

步骤3:KMeans聚类

kmeans_kwargs = {
    "init": "random",
    "n_init": 10,  # 调高n_init保证聚类稳定性
    "random_state": 1
}
# 执行聚类
kmeans = KMeans(n_clusters=6, **kmeans_kwargs)
df_pivot['cluster'] = kmeans.fit_predict(scaled_features)
# 查看聚类结果
print(df_pivot[['store', 'cluster']])

注意:若为20年数据,特征维度会膨胀至60维,可结合PCA降维避免维度灾难。

2. TimeSeriesKMeans要求的正确数据结构

tslearn.TimeSeriesKMeans要求输入三维数组,形状为(n_samples, n_timesteps, n_features):

  • n_samples:样本数量(此处为10家门店)
  • n_timesteps:时间步长(此处为2个年度)
  • n_features:单时间点的特征数(此处为3个指标)

数据重构步骤

# 按门店分组,提取每个门店的时间序列数据
grouped = df_full.groupby('store')
# 初始化三维数组
n_samples = len(grouped)
n_timesteps = df_full['year'].nunique()
n_features = 3  # points、assists、rebounds
X = np.zeros((n_samples, n_timesteps, n_features))

# 填充数据(需保证时间顺序正确)
for i, (store, data) in enumerate(grouped):
    data_sorted = data.sort_values('year')
    X[i, :, 0] = data_sorted['points'].values
    X[i, :, 1] = data_sorted['assists'].values
    X[i, :, 2] = data_sorted['rebounds'].values

标准化与聚类

时间序列聚类前建议对每个特征维度做标准化:

# 对每个特征维度标准化(沿时间步长维度)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X.reshape(-1, n_features)).reshape(X.shape)

# 执行DTW聚类
model = TimeSeriesKMeans(
    n_clusters=6,
    metric="dtw",  # 用DTW衡量时间序列相似性
    max_iter=50,  # 调高迭代次数保证收敛
    n_init=10,
    random_state=1
)
cluster_labels = model.fit_predict(X_scaled)

# 合并聚类结果到原数据
store_list = [store for store, _ in grouped]
cluster_df = pd.DataFrame({'store': store_list, 'cluster': cluster_labels})
df_full_with_cluster = df_full.merge(cluster_df, on='store')
print(df_full_with_cluster)

注意:需保证所有样本的时间步长一致(无缺失数据,缺失需先填充);150+门店+20年数据场景下,DTW计算成本较高,可改用metric="softdtw"或先对时间序列降维。


内容的提问来源于stack exchange,提问作者user032020

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 14:41:27