Pandas高效统计介于两日期列之间的分日分群组订阅用户数
最高效实现方案
核心采用事件差分累计法,完全避免展开每个用户的全量订阅周期,即使面对百万级用户、跨度数年的统计场景也能保持极高的运行效率和极低的内存占用。
实现逻辑
- 将订阅、退订分别作为两类事件,订阅对应+1,退订对应-1(退订从次日起不再计入订阅数)
- 合并所有事件后按日期+分组统计每日净变化值
- 补全所有日期+分组的组合,缺失的净变化值填0
- 按分组对净变化做累计求和,直接得到每日各分组的订阅用户数
完整可运行代码
接你提供的初始化代码继续执行即可:
# 1. 确定统计的日期范围,可根据需求自定义最大日期 min_date = users["sub_date"].min().date() max_date = users["unsub_date"].max().date() # 如需统计到当前可替换为 dt.date.today() # 2. 构造订阅、退订事件表 ## 订阅事件:订阅当日+1 sub_events = users[["sub_date", "group"]].rename(columns={"sub_date": "date"}) sub_events["delta"] = 1 ## 退订事件:退订次日-1,未退订(unsub_date为NaT)的用户无退订事件 unsub_events = users[["unsub_date", "group"]].dropna(subset=["unsub_date"]).rename(columns={"unsub_date": "date"}) unsub_events["date"] = unsub_events["date"] + pd.Timedelta(days=1) unsub_events["delta"] = -1 # 3. 合并事件并按日期+分组聚合每日净变化 events = pd.concat([sub_events, unsub_events], ignore_index=True) events["date"] = events["date"].dt.date daily_delta = events.groupby(["date", "group"], as_index=False)["delta"].sum() # 4. 生成完整的日期+分组笛卡尔积,补全缺失的日期分组 all_dates = pd.date_range(min_date, max_date, freq="D").date all_groups = users["group"].unique() full_index = pd.MultiIndex.from_product([all_dates, all_groups], names=["date", "group"]) full_df = daily_delta.set_index(["date", "group"]).reindex(full_index, fill_value=0).reset_index() # 5. 按分组累计求和得到最终每日订阅数 full_df["subbed"] = full_df.groupby("group")["delta"].cumsum() result = full_df.drop(columns=["delta"])
结果验证
输出的result完全符合你的需求:
- 2021-01-01 A组订阅数1、B组0
- 2021-02-03 A组订阅数2、B组2
- 2021-02-10 A组订阅数1、B组2
内容的提问来源于stack exchange,提问作者stfwn
相关产品推荐
相关产品推荐

