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

如何基于月度活跃/逾期统计DataFrame生成无小数占比的100%堆叠条形图?

轻松实现100%堆叠条形图的简便方法

嘿,这事儿用Python的pandas+可视化工具就能快速搞定,分两步走就行,完全不用复杂操作!我给你捋捋具体步骤:

第一步:生成每月活跃/逾期统计DataFrame

首先得把原始数据按月份聚合出活跃数和逾期数。假设你的原始数据集有日期列(比如date)、活跃标记(比如is_active,1代表活跃,0代表不活跃)、逾期标记(比如is_overdue,1代表逾期)。用pandas的resample或者groupby就能一键统计:

import pandas as pd

# 先把日期列转成datetime格式(如果还没转的话)
df['date'] = pd.to_datetime(df['date'])

# 按月份分组,统计每月活跃数和逾期数
monthly_stats = df.resample('M', on='date').agg(
    每月活跃数=('is_active', 'sum'),  # sum就是统计活跃用户的数量
    每月逾期数=('is_overdue', 'sum')
).reset_index()

# 把日期转成「年-月」格式,x轴显示更友好
monthly_stats['月份'] = monthly_stats['date'].dt.strftime('%Y-%m')

要是你的活跃/逾期判断逻辑不一样(比如是从状态字段判断),只需要调整agg里的函数就行,比如用lambda x: (x['user_status'] == 'active').sum()这种,灵活得很。

第二步:生成带整数标注的100%堆叠条形图

这里给你两种方案,选你顺手的来:

方案1:用Matplotlib(基础通用)

手动计算占比,然后堆叠绘图,还能精准控制标注显示整数:

import matplotlib.pyplot as plt

# 提取需要的数据
months = monthly_stats['月份']
active_counts = monthly_stats['每月活跃数']
overdue_counts = monthly_stats['每月逾期数']
total_counts = active_counts + overdue_counts  # 每月总用户数

# 转成整数百分比(避免小数)
active_pct = (active_counts / total_counts * 100).astype(int)
overdue_pct = (overdue_counts / total_counts * 100).astype(int)

# 开始画图
plt.figure(figsize=(10, 6))

# 先画活跃用户占比,再画逾期的叠在上面
bar_active = plt.bar(months, active_pct, label='活跃用户占比')
bar_overdue = plt.bar(months, overdue_pct, bottom=active_pct, label='逾期用户占比')

# 给每个条形加整数标注(占比)
for rect in bar_active:
    height = rect.get_height()
    plt.text(rect.get_x() + rect.get_width()/2., height/2,
             f'{height}%', ha='center', va='center', fontsize=10)
for rect in bar_overdue:
    height = rect.get_height()
    bottom_pos = rect.get_y()
    plt.text(rect.get_x() + rect.get_width()/2., bottom_pos + height/2,
             f'{height}%', ha='center', va='center', fontsize=10)

# 要是你想标注数量而不是占比,换成这段代码就行:
# for idx, (a, o) in enumerate(zip(active_counts, overdue_counts)):
#     plt.text(idx, a/2, f'{a}', ha='center', va='center', fontsize=10)
#     plt.text(idx, a + o/2, f'{o}', ha='center', va='center', fontsize=10)

plt.title('每月活跃/逾期用户100%堆叠占比图', fontsize=12)
plt.xlabel('月份', fontsize=10)
plt.ylabel('占比(%)', fontsize=10)
plt.legend()
plt.xticks(rotation=45)
plt.tight_layout()  # 自动调整布局,避免标签被截断
plt.show()

方案2:用Plotly Express(更快捷,带交互)

不想手动算占比?用Plotly一键生成,还能自动加标注,交互性拉满:

import plotly.express as px

# 把宽表转成长表(Plotly更适合这种格式)
monthly_long = monthly_stats.melt(
    id_vars='月份', 
    value_vars=['每月活跃数', '每月逾期数'], 
    var_name='用户类型', 
    value_name='数量'
)

# 生成100%堆叠条形图,直接显示整数数量
fig = px.bar(
    monthly_long, 
    x='月份', 
    y='数量', 
    color='用户类型', 
    text='数量',  # 显示数量,精准整数
    barmode='relative'  # 这个参数就是开启100%堆叠
)

# 要是想显示占比,先提前计算整数占比列:
# monthly_long['占比(%)'] = (
#     monthly_long['数量'] / monthly_long.groupby('月份')['数量'].transform('sum') * 100
# ).astype(int)
# fig = px.bar(monthly_long, x='月份', y='占比(%)', color='用户类型', text='占比(%)', barmode='relative')

# 调整样式,让标注在条形内部
fig.update_layout(
    title='每月活跃/逾期用户100%堆叠图',
    xaxis_title='月份',
    yaxis_title='统计数量'
)
fig.update_traces(textposition='inside')
fig.show()

小提醒

  • 如果活跃和逾期不是互斥的(比如有些用户既活跃又逾期),那得调整统计逻辑,比如统计「活跃且未逾期」「活跃且逾期」的数量,这样堆叠起来才是100%的总用户数。
  • 所有标注都是整数的关键:用astype(int)把占比转成整数,或者直接用原始的整数统计数量,完全不会出现小数~

内容的提问来源于stack exchange,提问作者Agustina

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 19:27:40