You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将分组柱状图的计数值转换为分组占比百分比

需求:将分组柱状图从计数值改为分组占比百分比

我目前用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 17:44:59