在R中遍历多财年每日数据,生成分客户类型活跃客户统计
解决方案:多财年每日活跃客户统计
核心思路
不用手动遍历每个财年,而是通过生成完整日期序列 + 事件流统计法来高效计算,避免循环带来的冗余和内存问题。以下是具体实现步骤:
1. 数据预处理
先统一日期格式,处理缺失的释放日期(活跃中客户用目标结束日期填充):
import pandas as pd import datetime as dt # 假设原始数据集为df df['entrance_date'] = pd.to_datetime(df['entrance_date']) df['release_date'] = pd.to_datetime(df['release_date']) # 定义统计截止日期:可选当前日期或最近财年结束日 end_date = dt.date.today() # 示例:用当前日期 # end_date = pd.to_datetime('2024-03-31') # 若财年为4月至次年3月,用最近财年结束日 # 填充活跃中客户的release_date df['release_date'] = df['release_date'].fillna(end_date)
2. 生成跨财年的完整日期序列
根据数据中最早财年的起始日期,生成到截止日期的所有日期:
# 自定义财年起始日期计算函数(支持自然年/4月起始财年,可扩展) def get_fy_start(fy_year, fy_type="calendar"): if fy_type == "calendar": return pd.to_datetime(f"{fy_year}-01-01") elif fy_type == "april": # 财年:当年4月至次年3月 return pd.to_datetime(f"{fy_year-1}-04-01") # 获取最早财年的起始日期 min_fy = df['fy_year'].min() start_date = get_fy_start(min_fy, fy_type="calendar") # 根据实际财年类型调整 # 生成完整日期序列 date_df = pd.DataFrame({"date": pd.date_range(start=start_date, end=end_date, freq="D")})
3. 事件流法统计每日活跃数
通过记录客户的「准入(+1)」和「释放次日(-1)」事件,再累计计算每日活跃数,效率远高于遍历每个客户的活跃区间:
# 生成所有客户的流入/流出事件 events = [] for _, row in df.iterrows(): # 准入日:该客户计入活跃 events.append({"date": row['entrance_date'], "cus_gr": row['cus_gr'], "change": 1}) # 释放次日:该客户不再计入活跃(释放当日仍算活跃) events.append({"date": row['release_date'] + pd.Timedelta(days=1), "cus_gr": row['cus_gr'], "change": -1}) events_df = pd.DataFrame(events) # 按日期+客户类型聚合事件变化量 events_agg = events_df.groupby(['date', 'cus_gr'])['change'].sum().reset_index() # 合并完整日期序列,填充无事件日期的变化量为0 merged = pd.merge(date_df, events_agg, on="date", how="left") merged['change'] = merged['change'].fillna(0) # 按客户类型计算累计活跃数(即每日活跃客户量) daily_active = merged.groupby('cus_gr').apply( lambda x: x.set_index('date')['change'].cumsum() ).unstack(level=0).fillna(0).astype(int).reset_index() # 重命名列名(可选) daily_active.columns = ['date'] + [f"active_{gr}" for gr in daily_active.columns[1:]]
4. (可选)按财年拆分结果
如果需要按财年区分统计结果,可添加财年标识列:
def get_fy(date, fy_type="calendar"): if fy_type == "calendar": return date.year elif fy_type == "april": return date.year if date.month >=4 else date.year -1 daily_active['fy_year'] = daily_active['date'].apply(get_fy)
最终的daily_active就是按日期、客户类型统计的每日活跃客户数DataFrame,自动覆盖从最早财年到截止日期的所有日期,无需手动循环单个财年。
内容的提问来源于stack exchange,提问作者Morrigan
相关产品推荐
相关产品推荐

