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

Pandas中替代.apply()方法的高效数据处理方案问询

如何优化Pandas DataFrame处理速度(从小时级到分钟级)

这问题我太熟了——你现在的核心瓶颈就是逐行apply(axis=1) + 逐个循环600个合同的组合,这俩加起来相当于在Python层面做了近8000万次函数调用,速度慢是必然的。咱们直接用Pandas的向量化能力重构核心逻辑,把时间从小时级压到分钟甚至秒级,具体步骤如下:

一、先解决数据加载的低效问题

你现在用xlwings读取大文件,这会和Excel交互,速度非常慢。换成pd.read_excel直接解析文件,能大幅提升加载速度:

替换fx_rates读取方式

# 用pd.read_excel直接读取Lookups表的汇率数据,header=3对应原数据的H4行作为表头
fx_rates_df = pd.read_excel(claims_data_path, sheet_name="Lookups", header=3, usecols="H:I", nrows=177)
fx_rates = fx_rates_df.set_index(fx_rates_df.columns[0])[fx_rates_df.columns[1]].to_dict()

替换claims_data读取方式

# 直接读取Reserving Policy Detail表,header=2对应原数据的A3行作为表头
claims_data = pd.read_excel(claims_data_path, sheet_name="Reserving Policy Detail", header=2, usecols="A:BA")

向量化处理列符号转换

原来的for循环逐个列乘-1,换成Pandas批量操作:

col_list = ["Gross_Paid_Losses", "Gross_Outstanding_Losses", "Gross_Incurred_Losses", "Net_Paid_Losses", "Net_Outstanding_Losses", "Net_Incurred_Losses"]
# 批量修改列符号,比for循环快数倍
claims_data[col_list] = claims_data[col_list] * -1

二、核心优化:用向量化替代自定义对象+循环+apply

你现在创建600个XOL对象,然后逐个循环调用calculate_recovery并逐行apply,这是效率最低的做法。咱们把合同数据保持为DataFrame,用Pandas的批量匹配和计算来替代:

1. 整理合同数据为结构化DataFrame

放弃自定义对象列表,直接用contract_data_shaped整理成匹配条件和参数的DataFrame:

contract_df = contract_data_shaped.rename(columns={
    "Attachment": "attachment",
    "Limit": "limit",
    "Placed": "placed",
    "Class": "classes_covered",
    "Treaty Year": "uwy_covered",
    "Currency": "currency_covered"
}).reset_index().rename(columns={"index": "name"})
# 确保数值列类型正确,避免计算时的类型转换开销
contract_df[["attachment", "limit", "placed", "uwy_covered"]] = contract_df[["attachment", "limit", "placed", "uwy_covered"]].astype(float)

2. 准备索赔数据的关键匹配列

把索赔数据中用于匹配合同的列提取并重命名,方便后续合并:

claims_key = claims_data[["Underwriting_Year", "Currency", "Adjusted Class", "Gross_Incurred_Losses"]].rename(columns={
    "Underwriting_Year": "uwy_covered",
    "Currency": "currency_covered",
    "Adjusted Class": "classes_covered",
    "Gross_Incurred_Losses": "gross_loss"
})
# 转换为float类型,避免计算报错
claims_key["gross_loss"] = claims_key["gross_loss"].astype(float)

3. 批量计算所有合同的Recovery

通过merge匹配合同和索赔的条件,然后用向量化运算计算recovery,最后pivot回原来的列格式:

# 左合并索赔数据和合同数据,只保留匹配条件(承保年度、币种、险种)的行
merged = pd.merge(claims_key, contract_df, on=["uwy_covered", "currency_covered", "classes_covered"], how="left")

# 初始化recovery列为0
merged["recovery"] = 0.0

# 用布尔掩码筛选符合条件的行:gross_loss >= attachment
mask = merged["gross_loss"] >= merged["attachment"]

# 向量化计算recovery:(min(gross_loss, limit) - attachment) * placed
merged.loc[mask, "recovery"] = (
    merged.loc[mask, "gross_loss"].clip(upper=merged.loc[mask, "limit"])  # 取gross_loss和limit的较小值
    - merged.loc[mask, "attachment"]
) * merged.loc[mask, "placed"]

# 将结果转置为:每一行是索赔,每一列是对应合同的recovery值
recovery_df = merged.pivot(index=merged.index, columns="name", values="recovery").fillna(0)

# 重命名列名,和原来的格式保持一致
recovery_df.columns = [f"Contract_ID_{col}" for col in recovery_df.columns]

# 把计算好的recovery列合并回原claims_data
claims_data = pd.concat([claims_data, recovery_df], axis=1)

三、为什么这样快?

  • 避免Python层面的循环开销:所有核心计算都是Pandas的向量化操作(基于C语言实现),比逐行调用Python函数快100~1000倍。
  • 批量处理所有合同:一次合并+计算就完成了600个合同的recovery计算,不用逐个循环合同。
  • 减少类型转换开销:提前统一数据类型,避免计算中重复做类型转换。

按照这个方案优化后,你的运行时间应该能从1小时降到5~10分钟左右(具体取决于你的机器性能)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 16:52:34