使用Pandas按ID分组,获取每月计数最值及对应日期
解决按ID分组并统计每月内每日记录数的最值问题
需求
按ID进行groupby分组,找出每个月份内每日记录计数的最小值和最大值,并输出对应日期、统计类型及计数值。
原始数据
DATE ID name 4/30/2023 AA hi 4/5/2023 AA hi 4/1/2023 AA hi 4/1/2023 AA hello 4/30/2023 AA hello 4/5/2023 AA hello 4/5/2023 AA hey 4/30/2023 AA hey 4/5/2023 AA ok 4/30/2023 AA ok 4/30/2023 AA ok 5/1/2023 AA ok 5/1/2023 AA hey 5/25/2023 AA hi 4/1/2023 BB hey 4/2/2023 BB hi 4/2/2023 BB hello
期望输出
ID DATE stat count AA 4/1/2023 min 2 AA 4/30/2023 max 5 AA 5/25/2023 min 1 AA 5/1/2023 max 2 BB 4/1/2023 min 1 BB 4/2/2023 max 2
当前代码问题分析
你当前的代码存在两个核心问题:
- 第一步
groupby(['ID', 'DATE', 'name'])错误地按name拆分了每日记录,统计的是每个ID每天单个name的记录数,而非每日总记录数。 - 完全没有处理“每个月份内”的分组要求,仅按
ID+DATE处理,无法实现每月内的最值统计。
可行解决方案
步骤说明
- 转换日期格式并提取月份,方便后续按月份分组。
- 计算每个ID每天的总记录数。
- 按
ID+月份分组,筛选出每组内记录数的最小值和最大值对应的行,并添加统计类型标记。 - 整理输出格式,匹配期望结果。
完整代码
import pandas as pd # 加载数据(如果已有DataFrame可跳过此部分) data = [ ["4/30/2023", "AA", "hi"], ["4/5/2023", "AA", "hi"], ["4/1/2023", "AA", "hi"], ["4/1/2023", "AA", "hello"], ["4/30/2023", "AA", "hello"], ["4/5/2023", "AA", "hello"], ["4/5/2023", "AA", "hey"], ["4/30/2023", "AA", "hey"], ["4/5/2023", "AA", "ok"], ["4/30/2023", "AA", "ok"], ["4/30/2023", "AA", "ok"], ["5/1/2023", "AA", "ok"], ["5/1/2023", "AA", "hey"], ["5/25/2023", "AA", "hi"], ["4/1/2023", "BB", "hey"], ["4/2/2023", "BB", "hi"], ["4/2/2023", "BB", "hello"], ] df = pd.DataFrame(data, columns=["DATE", "ID", "name"]) # 1. 处理日期,提取月份 df["DATE"] = pd.to_datetime(df["DATE"]) df["month"] = df["DATE"].dt.to_period("M") # 生成如2023-04的月份标识 # 2. 计算每个ID每天的总记录数 daily_counts = df.groupby(["ID", "DATE"]).size().reset_index(name="count") # 关联月份信息到每日统计结果 daily_counts = daily_counts.merge(df[["ID", "DATE", "month"]].drop_duplicates(), on=["ID", "DATE"]) # 3. 按ID+月份分组,提取每组的min和max记录 def extract_min_max(group): # 获取当前组中记录数最小的行 min_records = group[group["count"] == group["count"].min()] min_records["stat"] = "min" # 获取当前组中记录数最大的行 max_records = group[group["count"] == group["count"].max()] max_records["stat"] = "max" # 合并结果 return pd.concat([min_records, max_records]) result = daily_counts.groupby(["ID", "month"]).apply(extract_min_max).reset_index(drop=True) # 4. 整理输出格式,转换日期为原字符串格式 result["DATE"] = result["DATE"].dt.strftime("%-m/%-d/%Y") # 选择需要的列并排序 final_output = result[["ID", "DATE", "stat", "count"]].sort_values(by=["ID", "month", "stat"]) # 打印结果 print(final_output.to_string(index=False))
输出验证
运行上述代码后,将得到与期望完全一致的输出结果。
内容的提问来源于stack exchange,提问作者Lynn
相关产品推荐
相关产品推荐

