如何基于带计数列的分组数据绘制Seaborn箱线图?
带权重计数的Seaborn箱线图实现方案
方案原理
Seaborn原生boxplot接口不直接支持权重参数,因此我们可以提前按分组计算加权统计量,再传入绘图接口实现需求,完全避免行重复带来的内存浪费。
具体实现步骤
- 第一步:计算每个region分组的加权箱线图统计量
可以用statsmodels提供的加权描述性统计工具快速计算加权分位数,也可以自定义加权分位数函数避免额外依赖。
示例代码:import seaborn as sns import matplotlib.pyplot as plt import pandas as pd import numpy as np from statsmodels.stats.weightstats import DescrStatsW # 按region分组计算加权统计量 def calc_weighted_box_stats(sub_df): w_stats = DescrStatsW(sub_df['age'], weights=sub_df['total']) q1, med, q3 = w_stats.quantile([0.25, 0.5, 0.75]) iqr = q3 - q1 # 计算1.5倍IQR范围的上下须 lower_whisker = q1 - 1.5 * iqr upper_whisker = q3 + 1.5 * iqr # 须的边界不能超过实际数据的极值 actual_min = sub_df['age'].min() actual_max = sub_df['age'].max() return pd.Series({ 'med': med, 'q1': q1, 'q3': q3, 'whislo': max(lower_whisker, actual_min), 'whishi': min(upper_whisker, actual_max) }) weighted_box_stats = df.groupby('region').apply(calc_weighted_box_stats).reset_index() # 转换为matplotlib bxp接口支持的格式 stats_list = weighted_box_stats.rename(columns={'region':'label'}).to_dict('records') # 绘图 fig, ax = plt.subplots(figsize=(12, 6)) ax.bxp(stats_list, patch_artist=True, showfliers=False) sns.despine() plt.xlabel('Region') plt.ylabel('Age') plt.xticks(rotation=45) plt.show() - 第二步(可选):自定义加权分位数函数
如果不想引入statsmodels依赖,可以用以下函数替代加权分位数计算逻辑:
调用时把def weighted_quantile(values, weights, quantiles): values = np.array(values) weights = np.array(weights) # 按值排序 sorter = np.argsort(values) values = values[sorter] weights = weights[sorter] # 计算累积权重 cum_weights = np.cumsum(weights) cum_weights = cum_weights / cum_weights[-1] # 插值得到分位数 return np.interp(quantiles, cum_weights, values)DescrStatsW部分替换为该函数即可。
方案优势
- 完全不需要按total值重复行,避免了数据膨胀,大样本下内存效率提升非常明显
- 统计逻辑完全可控,可以灵活调整箱线图须、分位数的计算规则
内容的提问来源于stack exchange,提问作者Adam Grünwald
相关产品推荐
相关产品推荐

