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

将含valid_from/valid_to的用户收入数据按月末重采样为逐行数据集

高效生成用户月末时点收入数据集的Pandas方案

你当前通过遍历月末日期索引来填充数据的方法虽然逻辑直观,但当数据量变大(比如用户数上千、时间跨度几年)时,效率会很低。我来分享一个基于Pandas矢量化操作的更优方案,避免循环遍历,大幅提升处理速度。

核心思路

  1. 先生成所有需要覆盖的月末日期范围
  2. 生成用户-月末日期的笛卡尔积,得到每个用户每个月末的基础行
  3. 通过区间匹配,将原收入数据与基础行关联,找到每个时点对应的有效收入记录

具体实现代码

首先我们构造测试数据来模拟你的场景:

import pandas as pd

# 模拟用户收入数据:单个用户可能有多条生效区间不同的记录
raw_data = {
    'user_id': ['A', 'A', 'B', 'B'],
    'income': [5000, 6000, 8000, 9000],
    'valid_from': ['2022-01-15', '2022-06-01', '2022-03-01', '2022-10-01'],
    'valid_to': ['2022-05-31', '2022-12-31', '2022-09-30', '2022-12-31']
}
df = pd.DataFrame(raw_data)
# 转换日期格式为datetime类型
df['valid_from'] = pd.to_datetime(df['valid_from'])
df['valid_to'] = pd.to_datetime(df['valid_to'])

步骤1:生成所有需要的月末日期

我们从原数据的生效起止日期中,自动确定需要覆盖的月份范围:

# 计算日期范围:从最早生效日所在月份的月末,到最晚终止日所在月份的月末
start_month = df['valid_from'].min().to_period('M').to_timestamp('M')
end_month = df['valid_to'].max().to_period('M').to_timestamp('M')
# 生成该区间内的所有月末日期
month_ends = pd.date_range(start=start_month, end=end_month, freq='M')

步骤2:生成用户-月末的基础数据集

通过笛卡尔积,创建每个用户对应每个月末日期的空行:

# 获取唯一用户列表
unique_users = df['user_id'].unique()
# 生成用户与月末日期的笛卡尔积
user_month_base = pd.MultiIndex.from_product(
    [unique_users, month_ends],
    names=['user_id', 'month_end']
).to_frame(index=False)

步骤3:关联原数据,匹配有效收入记录

这里我们用merge_asof来高效完成区间匹配(比交叉连接后过滤更高效):

# 先对原数据和基础表按用户ID、日期排序(merge_asof要求输入已排序)
df_sorted = df.sort_values(['user_id', 'valid_from'])
user_month_sorted = user_month_base.sort_values(['user_id', 'month_end'])

# 使用merge_asof匹配每个月末对应的有效收入记录
# direction='backward'表示找到小于等于当前月末日期的最晚生效记录
matched_result = pd.merge_asof(
    user_month_sorted,
    df_sorted,
    left_on='month_end',
    right_on='valid_from',
    by='user_id',
    direction='backward',
    allow_exact_matches=True
)

# 过滤掉月末日期超过记录终止日的无效匹配
final_result = matched_result[
    matched_result['month_end'] <= matched_result['valid_to']
][['user_id', 'month_end', 'income']].sort_values(['user_id', 'month_end']).reset_index(drop=True)

处理边界情况

如果某个用户在某个月末没有生效的收入记录(比如还未开始生效或已过期),可以按需填充默认值(比如0):

# 将结果转成宽表后填充0,再转回长表
final_result_filled = final_result.pivot(
    index='month_end',
    columns='user_id',
    values='income'
).fillna(0).stack().reset_index(name='income')

方案优势

  • 效率更高:完全利用Pandas的矢量化操作,避免Python循环,处理大数据量时速度提升明显
  • 代码更简洁:逻辑清晰,易于维护和扩展
  • 自动适配范围:无需手动指定日期范围,自动从原数据中推导

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:45:23