pandas 空表生成多期 lag,列名和列数却没变
DataFrame 没有数据行时,多 periods 的 shift 可能提前返回原列结构。按各期分别 shift 后拼接,保留预定列顺序,并把空输入的 schema 纳入检查。
用 df.shift(periods=[0, 1], suffix="_lag") 生成两期特征,正常批次有四列,筛选后为空的批次却只剩原来的两列。调用没有抛异常,错误要到下游检查列名或预测特征时才出现。
pandas 3.1.0 的正式实现中,self.empty 且 freq is None 时会先返回副本,随后才处理多个 periods。因此,空表绕过了各期移动、加后缀与拼接的部分,不能用“没有数据行”推断输出列结构无关紧要。
对各期分别移动,再统一拼接
下面的示例只处理按行位置移动,不传 freq,列名是普通单层字符串:
import pandas as pd
df = pd.DataFrame({
"price": pd.Series(dtype="int64"),
"volume": pd.Series(dtype="float64"),
})
periods = [0, 1]
features = pd.concat(
[df.shift(p).add_suffix(f"_lag_{p}") for p in periods],
axis=1,
)
每次传给 shift() 的 p 是单个整数,即使空表提前返回,也仍会执行外面的 add_suffix()。对于这个示例,预期列名依次是 price_lag_0、volume_lag_0、price_lag_1、volume_lag_1,形状为 (0, 4)。
保留 periods 的顺序,它决定拼接后的列顺序。配置为空列表时,应在应用配置边界明确拒绝或定义空输出;不能直接把空列表交给 pd.concat(),再把新的异常误当成同一问题。重复的期数或已有重复列名,也可能生成重复的特征名,需要按模型输入要求处理。
不要临时填一行数据只为建立列名
插入假数据后再删除,可能触发 dtype 推断、缺失值填充和业务聚合。特征列数对了,也可能已经改变类型或统计过程。为了保存 schema,直接从各期结果建立输出更容易核对,也不必让虚构行进入流水线。
如果原调用使用了 fill_value、日期 freq、axis=1 或多层列索引,不能原样套用这个简化示例。多个期数的内置接口对 axis 有限制,日期频率又会改变索引含义;需要按原调用逐项保留这些约定。单独的 shift(0) 与非零移动在非空整数列上也可能得到不同 dtype,不应靠强制全表转浮点来隐藏这种差异。
验收同一套特征函数时,保留空表、一行和多行输入,检查列名、列顺序、dtype 及行索引。非空输入还要核对每一期值来自哪一行。保存旧的输出契约,确认下游读取没有再按位置错配列;不能只看异常消失,就认为所有 lag 特征都计算正确。


