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

Python如何高效实现带不等值匹配条件的SAS SQL两表合并

Python高效实现滚动11个月累计收益计算方案

你原代码的性能瓶颈来自按id全量内连接生成的笛卡尔积临时数据,同id下如果有m条月度记录,单id就会生成m²条临时行,数据量稍大就会直接爆内存。该需求本质是按id分组的滑动窗口累计收益计算,无需走不等值join逻辑,用pandas原生rolling方法即可高效实现,性能与SAS实现接近。


适用场景:数据为严格月度频率,每个id每月仅对应1条收益记录

实现代码

import pandas as pd
import numpy as np

# 第一步:数据预处理,筛选范围+排序
indst = indst.loc[indst['DATE'].dt.year >= 1960, ['id', 'DATE', 'RET']].sort_values(by=['id', 'DATE'], ignore_index=True)
# 计算对数毛收益
indst['log_gross_ret'] = np.log(1 + indst['RET'])

# 第二步:按id分组计算滑动窗口累计收益
def calc_11month_ret(group):
    # shift(1)取当前行之前的记录,滚动窗口取近11条,要求满11条才计算
    group['sum_log'] = group['log_gross_ret'].shift(1).rolling(window=11, min_periods=11).sum()
    # 筛选1961年及以后的记录,对应原SAS中a表的过滤条件
    group = group.loc[group['DATE'].dt.year >= 1961, ['id', 'DATE', 'sum_log']].copy()
    # 转换为累计收益率
    group['ret11'] = np.exp(group['sum_log']) - 1
    return group.drop(columns='sum_log')

ret11 = indst.groupby('id', group_keys=False).apply(calc_11month_ret).sort_values(by=['DATE', 'id']).reset_index(drop=True)

该方案时间复杂度为O(n),空间复杂度为O(n),64GB内存可轻松处理千万级记录,不会出现内存不足问题。


补充:若数据存在月度缺失的预处理步骤

如果同一id下存在月份断档,需要先补全连续月度序列,保证窗口计算逻辑正确:

# 将日期转为月度周期
indst['month'] = indst['DATE'].dt.to_period('M')
# 按id分组后重索引,补全所有连续月份
indst = indst.set_index('month').groupby('id', group_keys=False).apply(
    lambda x: x.reindex(pd.period_range(x.index.min(), x.index.max(), freq='M'))
).drop(columns=['id']).reset_index()
# 补全DATE字段,可根据你原数据的日期规则选择月初/月末
indst['DATE'] = indst['month'].dt.to_timestamp(how='end')

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 04:39:02