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

Python中基于DTW的大规模时间序列距离矩阵计算效率优化

你的代码跑一年是正常的——109489个样本的全量两两DTW配对总共有近60亿次计算,哪怕单次DTW计算只花0.1毫秒,全量跑完也要近70天,更别说你现在的代码还有大量无效开销。下面按收益从高到低给可行的优化方案,入门也能直接落地。

1 零逻辑改造成本的基础提效(先做,直接提效2-3倍)

先把代码里的纯浪费部分砍掉:

  • 提前把所有时间序列从pandas里抽出来存成numpy数组列表:你现在每次循环都用cycles.iloc[i]取数,pandas行索引的额外开销很高,提前一次性把cycle_info_scaled列转成纯列表存好,不要在循环里碰pandas接口
  • 利用DTW的对称性减少一半计算:DTW满足d(i,j)=d(j,i),且d(i,i)=0,你现在每一行都算所有j从0到总长度,等于每对距离算两遍,对角线的0值也在重复计算,只需要算j>i的部分,最后对称补全矩阵即可
  • 修正矩阵数据类型:DTW返回的是浮点数,你现在把矩阵dtype设为object,内存占用是float32的2倍以上,且连续读写性能差,直接改成dtype=np.float32即可
  • 换原生支持并行的DTW实现:你现在自己写joblib并行的方式有很大的进程通信开销,CPU根本跑不满,直接用dtaidistance库的dtw.distance_matrix_fast接口,它是C实现,内置多进程并行,自动只算对称矩阵的一半,比你手写的并行版本快5-10倍。
2 算法层面减计算量(核心优化,提效100-1000倍)

哪怕你把代码优化到极致,60亿次DTW计算的总量摆在那,普通消费级硬件不可能在几天内跑完。你的最终目标是聚类,根本不需要算全量距离矩阵,这是最核心的优化点:

  • 优先用时间序列嵌入替代原始DTW计算:用MiniRocket/ROCKET工具把每个时间序列转换成几千维的特征向量,10万条序列的转换只需要几分钟,转完之后用欧氏距离就能得到和DTW接近的聚类效果,距离计算速度比DTW快3个数量级
  • 如果必须用精确DTW,不要算全量矩阵:聚类用HDBSCAN这类基于近邻图的算法即可,只需要计算每个样本最近的10-30个邻居的DTW距离,总计算量从60亿次降到200-300万次,普通机器几个小时就能跑完
  • 数据量大的时候先做预聚类:先随机抽5%-10%的样本做聚类得到类中心,剩下的样本只需要计算和类中心的DTW距离归到最近类,再在类内做细聚类,总计算量可以降到原来的1%以下
3 可直接运行的参考实现

3.1 小样本测试用(1000条以内,验证DTW计算逻辑)

import numpy as np
from dtaidistance import dtw
import joblib

# 加载数据,提前抽成numpy数组列表,脱离pandas
cycles = joblib.load('new_cycles.pkl')
series_list = [np.array(x, dtype=np.float32) for x in cycles['cycle_info_scaled'].values]

# 自动并行计算对称DTW矩阵,warp窗口和你原来设的0.05一致
dist_matrix = dtw.distance_matrix_fast(
    series_list,
    window=0.05,
    parallel=True,
    use_mp=True,
    only_triu=True  # 只算上三角,减少一半计算
)

3.2 全量10万样本聚类方案(普通机器半天内跑完,效果和DTW聚类接近)

如果序列长度不一致,先统一补零到相同长度即可:

import numpy as np
import joblib
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from minirocket import MiniRocket
from hdbscan import HDBSCAN

# 加载并预处理数据
cycles = joblib.load('new_cycles.pkl')
series_list = [np.array(x, dtype=np.float32) for x in cycles['cycle_info_scaled'].values]
max_len = max(len(s) for s in series_list)
# 补零到统一长度,适配MiniRocket输入要求
X = np.stack([
    np.pad(s, (0, max_len - len(s)), constant_values=0) 
    for s in series_list
], axis=0)

# 时间序列转特征向量
embed_pipe = make_pipeline(
    MiniRocket(num_kernels=10000, random_state=42),
    StandardScaler()
)
X_embedded = embed_pipe.fit_transform(X)

# 无监督聚类,不需要全量距离矩阵
clusterer = HDBSCAN(min_cluster_size=10, n_jobs=-1)
cluster_labels = clusterer.fit_predict(X_embedded)
4 原代码的具体问题汇总
  • 重复计算对称位置的距离,浪费50%算力
  • 循环内反复调用pandas的iloc接口取数,产生大量不必要的开销
  • 距离矩阵用object类型存储,内存占用高、读写慢
  • 手写joblib并行的粒度过粗,进程间数据传输开销大,CPU利用率低
  • 最核心的问题:10万级样本计算全量两两DTW本身就不具备工程可行性,必须从算法层面压缩计算量,否则无论怎么优化代码逻辑都不可能在可接受时间内跑完

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 17:39:18