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

如何对Pandas面板数据进行连续3个月周期的Bootstrap抽样?

Pandas面板数据的连续3个月Bootstrap抽样实现

第一步:先把日期格式理清楚

不管你的月份是Nov21这种字符串还是其他格式,先转成Pandas的datetime类型,这是处理跨年度连续月份(比如Nov21-Dec21-Jan22)的核心前提:

import pandas as pd
import numpy as np

# 假设数据包含customer_id(客户ID)和month(月份列)两个核心字段
df['month'] = pd.to_datetime(df['month'], format='%b%y')

如果你的月份格式是2021-11这类,把format参数改成'%Y-%m'即可。

第二步:给每个客户筛选有效连续3个月的起始点

先按客户+月份排序,再给每个客户的月份编连续序号,这样不管客户数据有没有缺失月份,都能准确找到可抽取的连续3个月区间:

# 按客户和月份排序,确保时间顺序正确
df_sorted = df.sort_values(['customer_id', 'month']).reset_index(drop=True)

# 给每个客户的月份从1开始编序号
df_sorted['month_rank'] = df_sorted.groupby('customer_id')['month'].rank(method='first').astype(int)

# 筛选有效起始序号:序号必须满足后面还有至少2个月份(凑够连续3个月)
valid_starts = df_sorted.groupby('customer_id').apply(
    lambda x: x['month_rank'].unique()[x['month_rank'].unique() <= x['month_rank'].max() - 2]
).reset_index(name='start_rank')

如果你的数据中每个客户的月份都是连续无缺失的,这一步可以简化,直接取每个客户前n-2个月份作为起始点:

# 简化版(仅适用于客户月份完全连续的场景)
valid_starts = df_sorted.groupby('customer_id')['month'].apply(
    lambda x: x.iloc[:-2]
).reset_index(name='start_month')

第三步:编写抽样函数,执行90次抽样

每次随机挑选一个有有效区间的客户,再随机选他的一个起始点,抽取对应连续3个月的数据:

def bootstrap_sample(df_sorted, valid_starts):
    # 随机选一个符合条件的客户
    sampled_customer = np.random.choice(valid_starts['customer_id'].unique())
    # 选该客户的一个有效起始序号
    customer_starts = valid_starts[valid_starts['customer_id'] == sampled_customer]['start_rank'].values
    sampled_start = np.random.choice(customer_starts)
    # 抽取连续3个月的数据
    sample = df_sorted[
        (df_sorted['customer_id'] == sampled_customer) &
        (df_sorted['month_rank'].between(sampled_start, sampled_start + 2))
    ]
    return sample

# 重复90次抽样,合并结果
bootstrap_results = pd.concat([bootstrap_sample(df_sorted, valid_starts) for _ in range(90)], ignore_index=True)

如果用的是简化版的valid_starts,抽样函数可以改成这样:

def bootstrap_sample_simple(df_sorted, valid_starts):
    sampled_customer = np.random.choice(valid_starts['customer_id'].unique())
    sampled_start = np.random.choice(valid_starts[valid_starts['customer_id'] == sampled_customer]['start_month'].values)
    # 计算结束月份:起始月+2个月
    sampled_end = sampled_start + pd.DateOffset(months=2)
    sample = df_sorted[
        (df_sorted['customer_id'] == sampled_customer) &
        (df_sorted['month'] >= sampled_start) &
        (df_sorted['month'] <= sampled_end)
    ]
    return sample

额外实用提示

  • 提前过滤数据不足3个月的客户,避免抽样时选到无效客户:
df = df.groupby('customer_id').filter(lambda x: len(x) >= 3)
  • 如果需要给每次抽样打标记方便后续分析,可以在抽样函数中添加sample_id列:
def bootstrap_sample_with_id(df_sorted, valid_starts, sample_id):
    sample = bootstrap_sample(df_sorted, valid_starts)
    sample['sample_id'] = sample_id
    return sample

# 循环时传入抽样编号
bootstrap_results = pd.concat(
    [bootstrap_sample_with_id(df_sorted, valid_starts, i+1) for i in range(90)], 
    ignore_index=True
)

内容的提问来源于stack exchange,提问作者Katharina Böhm

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 13:46:30