如何将分组柱状图的计数值转换为分组占比百分比
需求:将分组柱状图从计数值改为分组占比百分比
我目前用Seaborn的countplot绘制DataFrame中多列的分组柱状图,当前图表展示的是绝对计数值,但我需要把每个x轴分组(比如性别列里的女性、男性)下的子项数值,转换成占该分组总数的百分比。举个例子:性别列统计出530名女性、470名男性,我希望女性组的每个子项数值除以530,男性组的除以470,最终以百分比形式呈现。
我的原始代码如下:
import pandas as pd import matplotlib.pyplot as plt import seaborn as sns # Define the columns to consider columns = [ "1 : A quale sesso appartieni? ", "age range", "6 : Come è composto il tuo nucleo familiare? ", "7 : Unicamente ai fini statistici ti chiediamo di indicare in quale delle seguenti fasce rientra il reddito familiare mensile netto (per rispondere considera tutte le fonti di reddito tue o del tuo coniuge o delle persone con le quali vivi: stipendio, pe...", "8 : Quale tra le seguenti categorie meglio descrive la tua professione attuale? " ] # Set a custom color palette for the charts colors = sns.color_palette("Set3") # Create individual bar charts for each column for i, column in enumerate(columns): plt.figure(figsize=(12, 6)) ax = sns.countplot(x=column, hue="Sportivo/Non Sportivo", data=df, palette=colors) # Set the axis labels ax.set_xlabel(column) ax.set_ylabel("Count") # Set the title from the list ax.set_title(lista_titoli_graph[i]) # Set the legend ax.legend(title="Sportivo/Non Sportivo") # Rotate x-axis labels if necessary plt.xticks(rotation=90) # Remove spines sns.despine() # Add value labels to the bars (without decimal points) for p in ax.patches: ax.annotate(f"{int(p.get_height())}", (p.get_x() + p.get_width() / 2., p.get_height()), ha="center", va="center", xytext=(0, 5), textcoords="offset points") # Show the plot plt.tight_layout() plt.show()
修改后的代码(实现百分比展示)
import pandas as pd import matplotlib.pyplot as plt import seaborn as sns # 定义要分析的列 columns = [ "1 : A quale sesso appartieni? ", "age range", "6 : Come è composto il tuo nucleo familiare? ", "7 : Unicamente ai fini statistici ti chiediamo di indicare in quale delle seguenti fasce rientra il reddito familiare mensile netto (per rispondere considera tutte le fonti di reddito tue o del tuo coniuge o delle persone con le quali vivi: stipendio, pe...", "8 : Quale tra le seguenti categorie meglio descrive la tua professione attuale? " ] # 自定义颜色 palette colors = sns.color_palette("Set3") # 为每一列绘制分组占比柱状图 for i, column in enumerate(columns): plt.figure(figsize=(12, 6)) ax = sns.countplot(x=column, hue="Sportivo/Non Sportivo", data=df, palette=colors) # 计算每个x分组的总样本数 group_totals = df.groupby(column).size() # 修改坐标轴标签为百分比 ax.set_xlabel(column) ax.set_ylabel("Percentage (%)") # 设置图表标题 ax.set_title(lista_titoli_graph[i]) # 设置图例 ax.legend(title="Sportivo/Non Sportivo") # 旋转x轴标签避免重叠 plt.xticks(rotation=90) # 移除多余边框 sns.despine() # 为每个柱状添加百分比标注 for p in ax.patches: # 通过bar的x坐标映射到对应的分组类别 x_group_idx = int(p.get_x() // p.get_width()) x_group = ax.get_xticklabels()[x_group_idx].get_text() # 获取该分组的总样本数 total = group_totals[x_group] # 计算百分比并保留1位小数 percentage = (p.get_height() / total) * 100 # 添加标注文本 ax.annotate(f"{percentage:.1f}%", (p.get_x() + p.get_width() / 2., p.get_height()), ha="center", va="center", xytext=(0, 5), textcoords="offset points") # 调整布局并展示图表 plt.tight_layout() plt.show()
关键修改说明
- 新增
group_totals = df.groupby(column).size():计算每个x轴分组的总样本数(比如女性530、男性470) - 修改y轴标签为
Percentage (%),明确图表展示内容 - 重构标注逻辑:通过bar的位置映射到对应分组,计算当前bar数值占该分组总数的百分比,替换原有的计数值标注
- 百分比保留1位小数,保证展示的可读性
内容的提问来源于stack exchange,提问作者coelidonum
相关产品推荐
相关产品推荐

