如何在sklearn时间序列预测中创建滞后特征且不额外占用内存?
用内存共享视图解决滞后项内存爆炸问题
核心思路是利用numpy的内存视图机制,不复制原始数据,通过重新定义数组的步长(stride)来生成滞后项,这样所有滞后特征都共享原始数据的内存,不会额外占用大量空间。下面是一个兼容sklearn的自定义转换器实现:
自定义滞后特征转换器
import numpy as np from sklearn.base import BaseEstimator, TransformerMixin class LagFeatureView(BaseEstimator, TransformerMixin): def __init__(self, lag_size=180): self.lag_size = lag_size def fit(self, X, y=None): # 无需拟合逻辑,直接返回自身 return self def transform(self, X): # 确保输入是连续的numpy数组,避免步长异常 X = np.ascontiguousarray(X) n_samples, n_features = X.shape out_samples = n_samples - self.lag_size if out_samples <= 0: raise ValueError(f"样本数({n_samples})小于滞后长度({self.lag_size}),无法生成有效滞后项") # 使用stride_tricks创建内存共享的滞后视图 # 形状变为:(有效样本数, 滞后步数, 特征数) lagged_array = np.lib.stride_tricks.as_strided( X, shape=(out_samples, self.lag_size, n_features), strides=(X.strides[0], X.strides[0], X.strides[1]) ) # 将特征维度与滞后维度合并,输出形状为(有效样本数, 特征数*滞后步数) return lagged_array.transpose(0, 2, 1).reshape(out_samples, -1)
原理说明
np.lib.stride_tricks.as_strided不会复制原始数据,只是重新定义了数组的读取规则:通过调整步长,让新数组的不同位置指向原始数据的不同切片(比如第i个样本的第k个滞后项,指向原始数据的第i+k个样本的对应特征)。- 后续的
transpose和reshape操作也不会触发深拷贝,最终返回的数组完全共享原始数据的内存,内存占用和原始数据几乎一致。
使用注意事项
- 原始数据不可随意修改:因为滞后视图直接引用原始数据,修改原始数据会同步改变视图中的值,建议在生成视图前完成所有数据预处理。
- 输入需为连续数组:如果输入的numpy数组是不连续的(比如经过多次切片、转置),先通过
np.ascontiguousarray转为连续数组,避免步长计算错误。 - 兼容sklearn流水线:这个转换器继承了
BaseEstimator和TransformerMixin,可以直接加入sklearn的Pipeline中,和其他组件无缝配合。
内容的提问来源于stack exchange,提问作者cjm2671
相关产品推荐
相关产品推荐

