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

Pandas:日期范围求和与重复uID的用户活跃订阅统计问题

高效处理用户活跃频次统计的方案

嘿,你的问题我太懂了——处理大数据集的时候,循环和重复ID确实是坑!原代码的问题主要是效率低(iterrows循环在大数据下慢到离谱),而且没法正确处理同一个uID的多条订阅记录,我给你两个高效的解决方案,都是用pandas的向量化操作,比循环快得多,还能完美处理重复ID的情况:

方案一:用apply+explode快速展开日期范围(易读性高)

这个方法代码简洁,容易理解,适合中等规模的数据集:

步骤1:先统一日期格式

首先把输入的字符串日期转成pandas的datetime类型,方便后续处理:

import pandas as pd

# 假设input_df是你的原始输入DataFrame
input_df['startdate'] = pd.to_datetime(input_df['startdate'], format='%d-%m-%Y')
input_df['stopdate'] = pd.to_datetime(input_df['stopdate'], format='%d-%m-%Y')

步骤2:展开每条订阅的日期范围

为每条订阅记录生成它覆盖的所有日期,然后把日期序列展开成单独的行:

# 为每条订阅生成对应的日期序列
input_df['date_range'] = input_df.apply(
    lambda row: pd.date_range(row['startdate'], row['stopdate'], freq='D'), axis=1
)

# 把日期序列展开,每条日期对应一条订阅记录
expanded_df = input_df.explode('date_range')

步骤3:统计并转成目标格式

统计每个日期、每个uID的活跃订阅数,再转成你需要的宽表格式:

# 按日期和uID分组统计活跃数
count_df = expanded_df.groupby(['date_range', 'uID']).size().reset_index(name='count')

# 转成宽表,列是uID,行是日期,缺失值填充0
result_df = count_df.pivot(index='date_range', columns='uID', values='count').fillna(0).astype(int)

# 把列名改成你要的"uID:X"格式
result_df.columns = [f'uID:{col}' for col in result_df.columns]

# 重置索引,把日期转成字符串格式
result_df = result_df.reset_index().rename(columns={'date_range': 'Date'})
result_df['Date'] = result_df['Date'].dt.strftime('%d-%m-%Y')

方案二:用numpy广播优化(超大数据集首选)

如果你的数据集特别大(百万级以上),apply可能还是有点慢,用numpy的向量化操作可以进一步提升效率:

import pandas as pd
import numpy as np

# 先统一日期格式(和方案一一样)
input_df['startdate'] = pd.to_datetime(input_df['startdate'], format='%d-%m-%Y')
input_df['stopdate'] = pd.to_datetime(input_df['stopdate'], format='%d-%m-%Y')

# 计算每条订阅覆盖的天数
start_dates = input_df['startdate'].values
stop_dates = input_df['stopdate'].values
days = (stop_dates - start_dates).astype('timedelta64[D]').astype(int) + 1

# 生成所有订阅对应的日期和uID
dates = np.concatenate([pd.date_range(s, e, freq='D') for s, e in zip(start_dates, stop_dates)])
uids = np.repeat(input_df['uID'].values, days)

# 构建展开后的DataFrame
expanded_df = pd.DataFrame({'Date': dates, 'uID': uids})

# 统计并转成目标格式(和方案一后续步骤一致)
count_df = expanded_df.groupby(['Date', 'uID']).size().reset_index(name='count')
result_df = count_df.pivot(index='Date', columns='uID', values='count').fillna(0).astype(int)
result_df.columns = [f'uID:{col}' for col in result_df.columns]
result_df = result_df.reset_index()
result_df['Date'] = result_df['Date'].dt.strftime('%d-%m-%Y')

为什么这两个方案比原代码好?

  • 效率高:完全避免了iterrows循环,用pandas/numpy的向量化操作,处理大数据集的速度能提升几十甚至上百倍
  • 自动处理重复uID:不管同一个uID有多少条订阅记录,分组统计都会自动累加当日的活跃数(比如uID:1在15-01-2019的两条订阅会被统计为2)
  • 格式完全匹配需求:最终输出的DataFrame和你期望的结构完全一致,日期格式也符合要求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 16:37:37