Python Pandas绘制百分比图表:三类占比可视化无新增列实现方案
需求与解决方案
背景与原实现
已有包含State(州)和Class(类别)的数据集,原计数条形图实现代码如下:
import pandas as pd import matplotlib.pyplot as plt data = [['FL', 2], ['AR', 0], ['CA', 0], ['CA', 1], ['AR', 1], ['FL', 0], ['CA', 0], ['CA', 1], ['AR', 2], ['FL', 1], ['AR', 0], ['FL', 2], ['CA', 1], ['FL', 1], ['AR', 1], ['AR', 2], ['AR', 1], ['FL', 2], ['CA', 2], ['FL', 0], ['FL', 2], ['AR', 2], ['AR', 1], ['FL', 0], ['AR', 1], ['CA', 0], ['CA', 0], ['CA', 2]] columns = ['State', 'Class'] df = pd.DataFrame(data=data, columns=columns) # 原计数绘图代码 df.groupby(['State', 'Class']).size().to_frame('Size').unstack(level=-1).sort_values([('Size', 0)], ascending=False).plot(kind='bar', rot=45, figsize=(8,8), fontsize=10) plt.legend(['Class 0', 'Class 1', 'Class 2'], prop={'size':15}) plt.show()
需求
需实现三类百分比图表,禁止在原DataFrame中新增列(实际数据包含大量其他列):
- 图表1:X轴为州,Y轴为州内各类别的占比,每州对应3个类别条形;
- 图表2:X轴为类别,Y轴为各类别内各州的占比,每类别对应各州条形;
- 图表3:同图表1,但Y轴为全局占比。
图表1:州内类别占比
通过分组后用transform计算州级总计数,直接得到占比后绘图:
# 计算州内各类别占比(无新增列) state_class_counts = df.groupby(['State', 'Class']).size() state_totals = state_class_counts.groupby('State').transform('sum') state_class_pct = (state_class_counts / state_totals).unstack(level=-1) # 绘图 state_class_pct.sort_values(0, ascending=False).plot(kind='bar', rot=45, figsize=(8,8), fontsize=10) plt.title('州内各类别占比') plt.ylabel('占比') plt.legend(['Class 0', 'Class 1', 'Class 2'], prop={'size':15}) plt.show()
transform('sum')会保留原分组结构,无需修改原DataFrame即可完成占比计算。
图表2:类别内各州占比
调整分组层级,用相同逻辑计算类别内各州占比:
# 计算类别内各州占比(无新增列) class_state_counts = df.groupby(['Class', 'State']).size() class_totals = class_state_counts.groupby('Class').transform('sum') class_state_pct = (class_state_counts / class_totals).unstack(level=-1) # 绘图 class_state_pct.plot(kind='bar', rot=45, figsize=(8,8), fontsize=10) plt.title('类别内各州占比') plt.ylabel('占比') plt.legend(['AR', 'CA', 'FL'], prop={'size':15}) plt.show()
图表3:类别全局占比
直接用分组计数除以全局总样本数得到全局占比:
# 计算全局占比(无新增列) global_total = len(df) state_class_global_pct = (df.groupby(['State', 'Class']).size() / global_total).unstack(level=-1) # 绘图 state_class_global_pct.sort_values(0, ascending=False).plot(kind='bar', rot=45, figsize=(8,8), fontsize=10) plt.title('类别全局占比(按州分组)') plt.ylabel('全局占比') plt.legend(['Class 0', 'Class 1', 'Class 2'], prop={'size':15}) plt.show()
内容的提问来源于stack exchange,提问作者Geeths
相关产品推荐
相关产品推荐

