如何在Pandas中计算ID组内年度环比与组间整体同比变化
问题分析与解决方案
你遇到全NaN的原因大概率是以下两个之一:
- 计算百分比变化时错误地按
ID+year分组,每个分组仅1条数据,pct_change()无法计算相邻行变化,直接返回NaN; year列是字符串类型且未按时间顺序排序,导致分组内的行顺序混乱,若后续操作逻辑依赖时序则会出现异常(但不会全NaN,除非分组只有一行)。
以下是针对两个需求的正确实现步骤:
第一步:预处理数据
先将year转为整数并按ID+year排序,确保每个ID内的年份是时序递增的,这是计算时间序列变化的前提:
import pandas as pd # 你的原始数据 data = [ [123456, "2017", 8.0, 150.235], [123456, "2018", 8.0, 202.5], [123456, "2019", 7.0, 168.526], [123456, "2020", 6.0, 175.559], [123456, "2021", 8.0, 206.667], [789101, "2017", 8.0, 228.9], [789101, "2018", 5.0, 208] ] df = pd.DataFrame(data, columns=["ID", "year", "count", "mean"]) # 转换year为整数并排序 df["year"] = df["year"].astype(int) df = df.sort_values(["ID", "year"]).reset_index(drop=True)
第二步:计算年度间百分比变化
仅按ID分组,对count和mean列应用pct_change(),计算组内相邻年份的百分比变化(乘以100转为百分比格式):
# 生成年度间百分比变化列 df["count_yearly_pct"] = df.groupby("ID")["count"].pct_change() * 100 df["mean_yearly_pct"] = df.groupby("ID")["mean"].pct_change() * 100
执行后,每个ID的第一行对应列会是NaN(因为没有前一年数据),其余行是正常的年度变化值。
第三步:计算首个年份到最新年份的整体百分比变化
可以生成单独的汇总表,或者将结果合并到原DataFrame的每一行:
方式1:生成单独的汇总表
# 按ID聚合首末年份的数值,计算整体变化率 overall_pct = df.groupby("ID").agg( first_count=("count", "first"), last_count=("count", "last"), first_mean=("mean", "first"), last_mean=("mean", "last") ).assign( count_overall_pct=lambda x: ((x["last_count"] - x["first_count"]) / x["first_count"]) * 100, mean_overall_pct=lambda x: ((x["last_mean"] - x["first_mean"]) / x["first_mean"]) * 100 ).drop(columns=["first_count", "last_count", "first_mean", "last_mean"])
方式2:合并到原DataFrame
# 将整体变化率合并到原表,每个ID的所有行都显示该值 df = df.merge(overall_pct, on="ID", how="left")
最终效果示例
处理后的df部分数据如下:
| ID | year | count | mean | count_yearly_pct | mean_yearly_pct | count_overall_pct | mean_overall_pct |
|---|---|---|---|---|---|---|---|
| 123456 | 2017 | 8.0 | 150.235 | NaN | NaN | 0 | 37.564 |
| 123456 | 2018 | 8.0 | 202.50 | 0.0 | 34.783 | 0 | 37.564 |
| 123456 | 2019 | 7.0 | 168.526 | -12.50 | -16.777 | 0 | 37.564 |
内容的提问来源于stack exchange,提问作者user
相关产品推荐
相关产品推荐

