如何用Pandas计算指定月份过去3个月的唯一员工ID数量?
解决方案:计算当月及过去3个月的唯一员工ID数量
问题分析
你已经实现了当月唯一员工ID数量的计算,但直接使用滚动窗口(rolling)无法正确计算过去3个月的唯一员工数——因为rolling.nunique()会对窗口内的"当月唯一数"做去重,而我们需要的是过去3个月所有员工ID的并集的数量。
数据预处理
首先确保日期列是datetime类型,并生成月份周期列DateM:
import pandas as pd # 加载并预处理数据 df = pd.read_csv("你的数据文件路径.csv") df['Date'] = pd.to_datetime(df['Date']) df['DateM'] = df['Date'].dt.to_period('M')
方法一:直观的区间筛选法(适合中小数据量)
该方法通过为每个月份筛选过去3个月的所有员工ID,再计算去重数量:
- 提取员工与月份的唯一对应关系:避免同一个员工当月多次出现影响结果
emp_month_pairs = df[['EmpId', 'DateM']].drop_duplicates()
- 生成连续的月份序列:确保没有缺失月份导致计算断档
all_months = pd.period_range( start=emp_month_pairs['DateM'].min(), end=emp_month_pairs['DateM'].max(), freq='M' )
- 定义函数计算单月对应的过去3个月唯一员工数
def calc_3month_unique(month): # 计算窗口起始月份(当前月往前推2个月,共3个月) start_month = month - 2 # 筛选窗口内的所有员工ID并去重计数 window_emps = emp_month_pairs[emp_month_pairs['DateM'].between(start_month, month)]['EmpId'] return window_emps.nunique()
- 合并当月与过去3个月的结果
# 计算当月唯一员工数 monthly_unique = df.groupby("DateM")["EmpId"].nunique().reset_index() monthly_unique.rename(columns={"EmpId": "One Month Unique EMP count"}, inplace=True) # 计算过去3个月唯一员工数 three_month_unique = pd.DataFrame({ 'DateM': all_months, '3 Month Unique EMP count': all_months.map(calc_3month_unique) }) # 合并并排序结果 final_result = pd.merge(monthly_unique, three_month_unique, on='DateM', how='left') final_result = final_result.sort_values("DateM", ascending=False).reset_index(drop=True)
方法二:滚动窗口合并法(适合大数据量)
利用rolling窗口合并每月的员工列表,再计算并集大小:
- 生成包含所有连续月份的基础表
monthly_groups = df.groupby("DateM").agg( One_Month_Unique=("EmpId", "nunique"), Emp_List=("EmpId", "unique") ).reset_index() # 补全缺失月份,避免窗口计算错误 all_months = pd.period_range( start=monthly_groups['DateM'].min(), end=monthly_groups['DateM'].max(), freq='M' ) all_months_df = pd.DataFrame({'DateM': all_months}) monthly_full = pd.merge(all_months_df, monthly_groups, on='DateM', how='left').fillna({ 'One_Month_Unique': 0, 'Emp_List': [] })
- 用滚动窗口合并员工列表并计算唯一数
# 滚动窗口大小为3(当前月+前2个月),合并窗口内的所有员工ID并去重计数 monthly_full['3_Month_Unique'] = monthly_full['Emp_List'].rolling(window=3).apply( lambda window: len(set().union(*window)), raw=False ) # 整理最终结果 final_result = monthly_full[['DateM', 'One_Month_Unique', '3_Month_Unique']].rename(columns={ 'One_Month_Unique': 'One Month Unique EMP count', '3_Month_Unique': '3 Month Unique EMP count' }).sort_values("DateM", ascending=False).reset_index(drop=True)
注意事项
- 如果存在缺失月份,必须先补全连续月份,否则滚动窗口会计算错误(比如跳过缺失的月份,窗口实际包含的月份不足3个)
- 两种方法的核心都是获取窗口内所有员工ID的并集,而不是对"当月唯一数"做二次去重
内容的提问来源于stack exchange,提问作者Vishal Mahajan
相关产品推荐
相关产品推荐

