如何用Python基于频率表计算各城市的年龄中位数
频率表格式DataFrame计算分组年龄中位数实现方案
方法1:纯Pandas实现(无额外依赖)
核心逻辑是通过累积频率定位中位数所在区间,再线性插值得到精确中位数,适配区间型频率表、单岁频率表两种场景。
首先假设你的频率表结构如下(和附图结构对齐):
| 城市 | 年龄下限 | 年龄上限 | 频数 |
|---|---|---|---|
| 北京 | 0 | 5 | 120 |
| 北京 | 5 | 10 | 156 |
| ... | ... | ... | ... |
示例代码:
import pandas as pd # 构造示例数据,可替换为你自己的DataFrame df = pd.DataFrame({ "城市": ["北京", "北京", "北京", "上海", "上海", "上海"], "年龄下限": [0, 5, 10, 0, 5, 10], "年龄上限": [5, 10, 15, 5, 10, 15], "频数": [120, 156, 180, 110, 160, 170] }) def calc_median(group): # 计算总频数 total = group["频数"].sum() # 计算累积频数并按年龄排序 group = group.sort_values("年龄下限").assign(累积频数=lambda x: x["频数"].cumsum()) # 找到第一个累积频数≥总频数一半的行 median_row = group[group["累积频数"] >= total/2].iloc[0] # 取中位数区间之前的累积频数 prev_cum = group[group["累积频数"] < total/2]["累积频数"].max() if (group["累积频数"] < total/2).any() else 0 # 插值计算中位数 median = median_row["年龄下限"] + (total/2 - prev_cum) / median_row["频数"] * (median_row["年龄上限"] - median_row["年龄下限"]) return median # 按城市分组计算中位数 result = df.groupby("城市").apply(calc_median).reset_index(name="年龄中位数") print(result)
方法2:使用scipy简化计算
如果允许引入第三方库,可以直接调用scipy.stats.weighted_median加权中位数函数,用年龄区间中点作为数值、频数作为权重计算,代码更简洁:
import pandas as pd from scipy.stats import weighted_median # 同上述示例df df["年龄中点"] = (df["年龄下限"] + df["年龄上限"]) / 2 result = df.groupby("城市").apply( lambda x: weighted_median(x["年龄中点"], weights=x["频数"]) ).reset_index(name="年龄中位数")
注意事项
- 如果你的频率表是单岁统计(年龄下限=年龄上限),直接去掉插值逻辑、取对应年龄即可,无需调整其他代码
- 区间如果是闭区间/开区间的差异,仅需调整年龄中点或插值的边界取值,核心逻辑不变
内容的提问来源于stack exchange,提问作者Julemb95
相关产品推荐
相关产品推荐

