求助:为交易DataFrame匹配对应日期的账户策略列
解决交易数据匹配对应账户策略的问题
我来帮你搞定这个问题!你现在需要给交易数据df2新增一列,匹配对应账户在交易日期时生效的策略,之前的两种apply方法报错是因为语法和逻辑上的小问题,我来拆解一下原因并给出可行方案:
先明确前提:转换日期类型
首先要注意的是,你的原始数据里日期是字符串格式,虽然看起来能比较,但为了避免潜在的格式问题,第一步先把所有日期列转成datetime类型:
import pandas as pd # 原始数据 strategy_data = [['001', '2018-03-02', '2018-03-04', 'strat1'],['001', '2018-03-05', '2018-03-10', 'strat2'],['002', '2018-02-01', '2018-03-02', 'strat2']] df = pd.DataFrame(strategy_data, columns = ['acc', 'd1', 'd2', 'strat']) transaction_data = [['001', '2018-03-02', 234], ['001', '2018-03-03', 432], ['001', '2018-03-07', 543], ['002', '2018-02-20', 543]] df2 = pd.DataFrame(transaction_data, columns = ['acc', 'd', 'am']) # 转换日期为datetime类型 df[['d1', 'd2']] = df[['d1', 'd2']].apply(pd.to_datetime) df2['d'] = pd.to_datetime(df2['d'])
分析你的报错原因
方案1的问题
df.loc(lambda df: df['acc'] == acc)这种写法不符合loc的用法,loc接受的是布尔掩码或者标签,不是lambda函数;return df3['strat'].value这里应该用.values[0]来取具体的策略值,.value是pandas的一个属性,不是用来取值的;apply里的参数写错了,应该是axis=1(表示逐行处理),而不是index=1。
方案2的问题
df.d1 <= row['d'] <= df.d2这种链式比较会生成一个布尔Series,直接放到loc里会触发"truth value ambiguous"的错误,因为pandas无法判断整个Series的真假,你需要把它拆成两个条件,用&连接,并且给每个条件加上括号(因为运算符优先级的问题);- 没有提取具体的策略值,直接返回了Series,导致赋值失败。
修正后的apply方案
方案1修正版
先写一个清晰的匹配函数,再用apply调用:
def return_strat(acc, date): # 生成布尔掩码:匹配账户 + 交易日期在策略区间内 mask = (df['acc'] == acc) & (df['d1'] <= date) & (df['d2'] >= date) # 返回对应的策略值(假设每个日期对应唯一策略,取第一个结果) return df.loc[mask, 'strat'].values[0] # 给df2新增strat列 df2['strat'] = df2.apply(lambda row: return_strat(row['acc'], row['d']), axis=1)
方案2修正版
把逻辑直接写到lambda里,注意条件的写法:
df2['strat'] = df2.apply( lambda row: df.loc[ (df['acc'] == row['acc']) & (df['d1'] <= row['d']) & (df['d2'] >= row['d']), 'strat' ].values[0], axis=1 )
更高效的非apply方案(推荐)
apply是逐行处理,数据量大的时候效率很低,推荐用merge加布尔筛选的向量化方法:
# 先按账户合并两个DataFrame merged_df = pd.merge(df2, df, on='acc', how='left') # 筛选交易日期在策略区间内的行 valid_rows = merged_df[(merged_df['d'] >= merged_df['d1']) & (merged_df['d'] <= merged_df['d2'])] # 整理成最终结果(保留交易数据的列+策略列) final_df = valid_rows.drop(columns=['d1', 'd2']).reset_index(drop=True)
验证结果
不管用哪种方法,最终得到的df2(或final_df)都会是:
acc d am strat 0 001 2018-03-02 234 strat1 1 001 2018-03-03 432 strat1 2 001 2018-03-07 543 strat2 3 002 2018-02-20 543 strat2
内容的提问来源于stack exchange,提问作者Karin Hahn
相关产品推荐
相关产品推荐

