如何在Python Pandas中按条件计算资产合格后天数差?
问题:计算资产合格后天数(TSE)
需要为Pandas DataFrame创建新字段time since eligibility(合格后天数),用于计算资产从eligible字段由0转为1后的天数差。已手动生成目标字段TSE作为参考,此前尝试嵌套循环实现但未成功,需解决该问题。
相关数据与代码
初始化数据
import pandas as pd df1 = pd.DataFrame(columns=['asset', 'eligible', "date"]) df1['asset'] = ['003', '003', '003', '003', '003', '003', '002', '002', '002', '002', '002', '002', '002', '003', '003', '003'] df1['eligible'] = [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1] df1['date'] = ['1.1.2016', '2.1.2016', '3.1.2016', '4.1.2016', '5.1.2016', '6.1.2016', '1.1.2016', '2.1.2016', '3.1.2016', '4.1.2016', '5.1.2016', '6.1.2016', '7.1.2016', '1.1.2016', '2.1.2016', '3.1.2016'] df1["TSE"] = [0, 0, 1, 2, 3, 4, 0, 0, 0, 0, 1, 2, 3, 1, 2,3 ]
目标DataFrame展示
asset eligible date TSE 0 003 0 1.1.2016 0 1 003 0 2.1.2016 0 2 003 1 3.1.2016 1 3 003 1 4.1.2016 2 4 003 1 5.1.2016 3 5 003 1 6.1.2016 4 6 002 0 1.1.2016 0 7 002 0 2.1.2016 0 8 002 0 3.1.2016 0 9 002 0 4.1.2016 0 10 002 1 5.1.2016 1 11 002 1 6.1.2016 2 12 002 1 7.1.2016 3 13 003 1 1.1.2016 1 14 003 1 2.1.2016 2 15 003 1 3.1.2016 3
尝试过的无效循环代码
for i in range(len(df1)-1): for j in range(len(df1)-1): row1, row2 = df1.iloc[i], df1.iloc[i+j] if row1["eligible"] - row2["eligible"] != 0: df1.iloc[i] = df1['date'].diff()
解决方案
步骤1:转换日期格式
先将date字段转为datetime类型,才能进行天数差计算:
df1['date'] = pd.to_datetime(df1['date'], format='%d.%m.%Y')
步骤2:按资产分组获取合格起始日期
对每个资产,找到首次eligible变为1的日期;对于一开始就全为1的资产,取该组最早日期作为合格起始日:
def get_eligibility_start(group): # 定位eligible从0转1的首个日期 eligible_shifts = group['eligible'].diff() == 1 if eligible_shifts.any(): return group.loc[eligible_shifts, 'date'].iloc[0] else: # 全为1的资产取最早日期,全为0则返回None if (group['eligible'] == 1).all(): return group['date'].min() else: return None # 生成资产与合格起始日的映射字典 eligibility_start = df1.groupby('asset').apply(get_eligibility_start).to_dict()
步骤3:计算TSE字段
根据合格起始日期计算天数差,合格前的记录设为0:
# 为每条数据映射对应资产的合格起始日 df1['eligibility_start_date'] = df1['asset'].map(eligibility_start) # 计算合格后天数:合格起始日当天为1,之后依次递增;未合格时为0 df1['calculated_TSE'] = df1.apply( lambda row: (row['date'] - row['eligibility_start_date']).days + 1 if row['eligible'] == 1 else 0, axis=1 )
验证结果
运行后calculated_TSE字段将与手动生成的TSE完全一致,可通过以下代码查看:
print(df1[['asset', 'eligible', 'date', 'TSE', 'calculated_TSE']])
说明
- 放弃嵌套循环:Pandas的分组、向量化操作比循环高效得多,数据量越大优势越明显
- 覆盖边界场景:处理了资产从0转1、初始全为1、初始全为0三种情况
- 日期转换是前提:必须将字符串日期转为datetime类型才能进行天数计算
内容的提问来源于stack exchange,提问作者Lisa
相关产品推荐
相关产品推荐

