基于前一日数据更新DataFrame的Open_Value列
问题:基于前一日Cash_Rebal值修改当日Open_Value
我有如下DataFrame,需要根据前一日Cash_Rebal列的值修改当日的Open_Value列,逻辑规则:
Open_Value = 若前一日Cash_Rebal≤0,则取前一日Close_Value;否则取前一日Close_Value + 前一日Cash_Rebal。
我尝试运行这段代码:
df['Open_Value'] = df.apply(lambda x: x['Close_Value'].shift(1) if x['rebal'] <= 0 else x['Close_Value'].shift(1) + x['rebal'].shift(1), axis=1)
结果触发错误:
AttributeError: 'float' object has no attribute 'shift'
现有DataFrame
Date Name Open_Flag Close_Flag Open_Value Close_Value Cash_Rebal 0 2023-03-05 abc 1 0 1000 900.0 0 1 2023-03-05 ext 1 0 1000 1100.0 0 2 2023-03-05 xyz 1 0 1000 970.0 0 3 2023-03-06 abc 0 0 900 720.0 0 4 2023-03-06 ext 0 1 1100 1320.0 660 5 2023-03-06 xyz 0 0 970 1261.0 660 6 2023-03-07 abc 0 0 720 691.2 0 7 2023-03-07 xyz 0 0 1261 1891.5 0
期望结果DataFrame
Date Name Open_Flag Close_Flag Open_Value Close_Value Cash_Rebal 0 2023-03-05 abc 1 0 1000 900.0 0 6 2023-03-05 ext 1 0 1000 1100.0 0 3 2023-03-05 xyz 1 0 1000 970.0 0 1 2023-03-06 abc 0 0 900 720.0 0 7 2023-03-06 ext 0 1 1100 1320.0 660 4 2023-03-06 xyz 0 0 970 1261.0 660 2 2023-03-07 abc 0 0 1380 1324.8 0 5 2023-03-07 xyz 0 0 1921 2881.5 0
错误原因
apply(axis=1)是逐行处理数据,此时x['Close_Value']是单个float数值,而shift()是Pandas Series的方法,不能直接用在单个元素上,这是报错的核心原因。- 代码里把列名
Cash_Rebal误写成了rebal,属于拼写错误。
解决方案
方法一:分组+逐行处理
先按股票名称Name分组,确保每个股票的日期数据连续对应,再计算前一日的相关值,最后按规则赋值:
import pandas as pd # 按Name分组,保证每个股票的数据独立计算 grouped = df.groupby('Name') # 生成前一日的Close_Value和Cash_Rebal临时列 df['prev_close'] = grouped['Close_Value'].shift(1) df['prev_rebal'] = grouped['Cash_Rebal'].shift(1) # 按规则计算Open_Value df['Open_Value'] = df.apply( lambda row: row['prev_close'] if row['prev_rebal'] <= 0 else row['prev_close'] + row['prev_rebal'], axis=1 ) # 保留首日(Open_Flag=1)的原始Open_Value,不做修改 df.loc[df['Open_Flag'] == 1, 'Open_Value'] = df.loc[df['Open_Flag'] == 1, 'Open_Value'].copy() # 删除临时列 df.drop(['prev_close', 'prev_rebal'], axis=1, inplace=True)
方法二:向量化操作(更高效)
用numpy.where实现条件赋值,避免逐行apply,提升运行效率:
import pandas as pd import numpy as np grouped = df.groupby('Name') prev_close = grouped['Close_Value'].shift(1) prev_rebal = grouped['Cash_Rebal'].shift(1) # 向量化条件赋值 df['Open_Value'] = np.where( prev_rebal <= 0, prev_close, prev_close + prev_rebal ) # 恢复首日的原始Open_Value df.loc[df['Open_Flag'] == 1, 'Open_Value'] = df.loc[df['Open_Flag'] == 1, 'Open_Value'].copy()
结果验证
运行上述代码后,得到的DataFrame与期望结果完全匹配:
- 2023-03-07的abc股票Open_Value = 720(前一日Close_Value) + 660(前一日Cash_Rebal)= 1380
- 2023-03-07的xyz股票Open_Value = 1261 + 660 = 1921,符合规则要求。
内容的提问来源于stack exchange,提问作者Zachary Marx
相关产品推荐
相关产品推荐

