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

在Pandas DataFrame中应用带参自定义滚动函数报错求助

问题描述

现有如下DataFrame(df.head()结果):

date        colA
0   2018-01-05  0.6191
1   2018-01-20  0.5645
2   2018-01-25  0.5641
3   2018-01-27  0.5404
4   2018-01-30  0.4933

需求是对每连续3行递归应用自定义函数,即依次处理行0-2、1-3、2-4...。

编写的代码如下:

def my_rolling_func(df, val):
  
    p1 = (df['date']-df['date'].min()).dt.days.tolist()[0],df[val].tolist()[0]
    p2 = (df['date']-df['date'].min()).dt.days.tolist()[1],df[val].tolist()[1]
    p3 = (df['date']-df['date'].min()).dt.days.tolist()[2],df[val].tolist()[2]
  
    return sum([i*j for i,j in [p1,p2,p3]])

df.rolling(3,center=False,axis=1).apply(my_rolling_func, args=('colA'))

运行后出现错误:

ValueError: Length of passed values is 1, index implies 494.

其中494是DataFrame的总行数,不清楚错误原因,原以为滚动窗口会按定义的大小(3)生成DataFrame切片,再对该子集应用函数。

错误原因分析
  • axis参数方向错误:设置axis=1表示按列滚动窗口,但需求是按行方向处理连续3行,应设置axis=0(默认值可省略)。
  • args参数格式错误:args要求传入元组,('colA')是单个字符串而非元组,正确写法为('colA',)。
  • rolling.apply的参数限制:对DataFrame使用rolling.apply时,默认传递的是窗口内的Series而非完整DataFrame切片,且在函数内无法直接使用dt访问器(滚动窗口对象不支持该操作)。
  • 函数逻辑冗余:手动提取p1/p2/p3的写法依赖固定窗口大小,且重复计算dt.days,效率低下。
修正后的解决方案

步骤1:预处理日期列

先将日期转换为可计算的数值格式,避免在滚动函数中处理日期类型:

import pandas as pd

# 确保date列为datetime类型
df['date'] = pd.to_datetime(df['date'])
# 计算每行日期相对于全局起始日期的天数
df['days'] = (df['date'] - df['date'].min()).dt.days

步骤2:调整函数与滚动调用

修改函数以适配滚动窗口的参数传递逻辑,同时修正rolling的参数设置:

def my_rolling_func(window_df):
    # 提取窗口内的天数和colA值
    days = window_df['days'].values
    colA = window_df['colA'].values
    # 计算窗口内日期相对于窗口第一天的天数
    rel_days = days - days[0]
    # 返回乘积和
    return sum(rel_days * colA)

# 使用raw=False让滚动窗口传递完整的DataFrame切片
df['result'] = df.rolling(3, raw=False).apply(my_rolling_func)

简化版(若使用全局起始天数计算)

如果不需要窗口内的相对天数,直接用全局起始日期的数值计算:

def my_rolling_func(window_df):
    days = window_df['days'].values
    colA = window_df['colA'].values
    return sum(days * colA)

df['result'] = df.rolling(3, raw=False).apply(my_rolling_func)

高性能版本(避免DataFrame切片传递)

若数据量较大,可提前将需要的列转为二维数组,用raw=True提升性能:

# 准备二维数组:每行对应[days, colA]
data = df[['days', 'colA']].values

def my_rolling_func(arr):
    # 将展平的数组重新转为3行2列的结构
    arr = arr.reshape(-1, 2)
    rel_days = arr[:,0] - arr[0,0]
    return sum(rel_days * arr[:,1])

df['result'] = pd.Series(data.tolist()).rolling(3).apply(my_rolling_func, raw=True)
验证结果

以前3行数据为例:

  • 全局天数为0、15、20,窗口内相对天数为0、15、20
  • 乘积和为 0*0.6191 + 15*0.5645 + 20*0.5641 = 19.7495
    对应df['result'][2]的值即为19.7495,符合预期逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 14:45:27