前几天在跑 GaoFen-3 卫星的数据反演,需要结合 AIEM 和水云模型,对 27 个自动观测站的历史土壤水分时间序列做一个未来趋势的预测。熟悉我平时工作流的朋友大概知道,我在处理这批 SONTE-China 站点网络数据时,一直坚持一个很轴的底层逻辑:一个站点对应一个独立的地表粗糙度,绝不能把所有站点混在一起一锅炖。
这种坚持在物理反演上是很严谨的,但一落到写时间序列预测代码的时候,简直就是一场噩梦。
按照传统的写法,你要为这 27 个站点分别构建滞后特征(Lag),自己手写 for 循环去做滚动窗口预测,还要小心翼翼地把上一天的预测结果塞回今天的特征里去。代码写完,满屏的各种索引对齐逻辑,不仅难看,后期稍微改下预测步长,牵一发而动全身。
直到我最近在开源社区挖到了一个刚发布不久的黑魔法级别的 Python 库——Tsururu。今天就来好好聊聊这个能够让你彻底告别手写时间序列底层逻辑的神器。
为什么 Tsururu 如此与众不同?
目前市面上的时序库大多把精力放在“算法模型”上,给你丢一堆眼花缭乱的神经网络。但 Tsururu 的哲学非常务实,它不造模型的轮子(底层完全兼容 CatBoost、PyTorch 等现有模型),而是专注于解决时间序列工程中最繁琐的两件事:多序列建模策略(Multi-series) 和 多步预测推理机制(Multi-step-ahead)。
在看具体的代码之前,我们可以先在脑子里建构一下它极其清晰的数据流转流水线:
[原始多站点时序数据 DataFrame] │ ▼ (TSDataset 数据集封装) │ ▼ [预处理与特征工程管道] (如 LagTransformer 自动生成时间滞后项) │ ▼ [多序列策略分配层 (Multi-series Strategy)] ├─> Global (所有站点共享同一套权重参数) ├─> Local (为每个站点独立实例化模型,互不干扰) <-- 我们今天用这个! └─> Multivariate (考虑站点间的空间并发约束影响) │ ▼ [多步预测推理层 (Multi-step Strategy)] ├─> Recursive (单步迭代,将预测值作为下一步的输入) ├─> MIMO (多输入多输出,一波流直接输出未来 N 天) └─> Direct (为未来的每一天单独训练一个专属模型) │ ▼ [底层集成模型 (如 CatBoost) 进行计算并输出结果]
极简实战:多站点独立预测管道搭建
光说理论太空洞,我们直接拿我手头正在处理的这 27 个站点的数据来写一段实操代码。
首先我们需要引入数据并做一层非常薄的封装,告诉 Tsururu 哪一列是时间、哪一列是站点 ID、哪一列是我们需要预测的土壤水分目标值。
import pandas as pdfrom tsururu.dataset import TSDataset# 假设我们在处理 27 个观测站的历史土壤水分与雷达后向散射数据# CSV 文件中包含了 date, station_id, soil_moisture, surface_roughness 等列dataset_params = { "target": {"columns": ["soil_moisture"]}, # 我们要预测的目标 "date": {"columns": ["date"]}, # 时间轴 "id": {"columns": ["station_id"]}, # 区分不同时间序列的唯一标识}# 载入数据,Tsururu 会自动帮我们做好底层的索引隔离ts_dataset = TSDataset( data=pd.read_csv("sonte_china_27_stations_cleaned.csv"), columns_params=dataset_params,)
接下来是最震撼的部分。如果我们要实现文章开头说的“针对每一个站点独立的物理参数(粗糙度等)分别建模,并用过去 7 天的数据去迭代预测未来”,在 Tsururu 里只需要一个极其优雅的声明式 Pipeline:
from tsururu.pipeline import Pipelinefrom tsururu.strategies import LocalModelling, RecursiveStrategyfrom tsururu.transformers import LagTransformerfrom catboost import CatBoostRegressor# 把繁琐的循环和特征工程全部交给 Pipelinepipeline = Pipeline( # 第一步:特征工程,自动为所有站点生成过去 7 天的历史观测值作为输入特征 transformers=[LagTransformer(lags=7)], # 第二步:核心策略编排 # 因为每个站点的地表粗糙度等先验知识完全不同,我们坚决使用 LocalModelling # 这意味着框架会在底层自动为 27 个站点实例化 27 个互不干扰的独立模型 strategy=LocalModelling( # 具体的预测手段我们采用 RecursiveStrategy(递归预测) # 即:预测出明天的水分后,立刻把它作为已知条件,去预测后天的水分 base_strategy=RecursiveStrategy( # 底层算力引擎,这里我们随便挑一个大家都爱的 CatBoost model=CatBoostRegressor(iterations=500, silent=True) ) ))
你看,没有任何脏乱的 for 循环,也没有手动的 df.groupby('station_id').shift()。你的代码逻辑和你的学术思考逻辑做到了完美的统一。
一键训练与未来推演
策略配置好之后,剩下的工作就是喝口咖啡,让机器自己去跑。
print("开始在后台并行处理 27 个站点的独立特征并训练模型...")# 一行代码搞定所有站点的训练,Tsururu 底层会接管所有的数据路由pipeline.fit(ts_dataset)# 假设我们要推演未来 15 天的土壤水分变化print("正在生成未来 15 步的预测结果...")forecast_dataset = pipeline.predict(ts_dataset, horizon=15)# 将框架内部的数据格式无缝转回我们最熟悉的 Pandas DataFramepredictions_df = forecast_dataset.to_pandas()# 抽查特定站点的预测趋势station_05_preds = predictions_df[predictions_df["station_id"] == "Station_05"]print("\nStation_05 站点的未来水分走势预测:")print(station_05_preds[["date", "soil_moisture_pred"]].head())
为什么我强烈推荐你在项目中引入它?
这几天把论文里原本两三百行臃肿的数据处理脚本用 Tsururu 重构之后,那种如释重负的清爽感真的很难用语言形容。
做数据分析或者科研开发,我们最宝贵的精力应该花在对业务逻辑和物理参数的思考上(比如思考是该用 MIMO 策略还是 Recursive 策略更符合地表水分的挥发规律),而不是整天跟在各种索引越界、缺失值对齐的 Bug 后面疯狂打补丁。
如果你平时的工作也涉及批量的多主体时间序列预测,不管是传感器监测站、还是电商平台上不同品类商品的销量预估,强烈建议你 pip install 一下这个新晋的宝藏库。相信我,只要体会过这种“像搭积木一样设计预测策略”的快感,你就再也回不去手撕基础循环的日子了。
编辑:余文彬
审校:余雨馨