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

连续变量与二分类变量折线图:添加双Y轴及响应率展示方法

嘿,这个需求我刚好实操过,给你分享两种常用工具的实现方案——不管是做静态可视化还是交互式图表,都能完美满足你在直方图分箱中添加响应率的需求:

方法一:Matplotlib + Seaborn 实现静态双Y轴图表

这种方式适合生成静态报告或论文配图,步骤清晰易定制:

1. 准备数据(模拟或导入你的真实数据)

先构造一个包含连续变量和二分类响应变量的数据集,这里用模拟数据示例:

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

# 模拟数据:500个样本,连续变量服从正态分布,响应变量是二分类
np.random.seed(42)
df = pd.DataFrame({
    'continuous_var': np.random.normal(50, 15, 500),
    'response': np.random.binomial(1, 0.3, 500)
})

2. 分箱并统计关键指标

对连续变量分箱,然后计算每个分箱的样本量和响应率(正类占比):

# 把连续变量分成10个等宽分箱,也可以用pd.qcut做等频分箱
df['bin'] = pd.cut(df['continuous_var'], bins=10)

# 分组统计每个分箱的样本数和响应率
bin_stats = df.groupby('bin').agg(
    样本量=('response', 'size'),
    响应率=('response', 'mean')
).reset_index()

# 提取分箱中间值,方便后续绘图定位
bin_stats['分箱中间值'] = bin_stats['bin'].apply(lambda x: x.mid)

3. 绘制双Y轴图表并添加响应率标注

用双Y轴分别展示样本量(直方图)和响应率(折线),同时在每个直方图上方标注响应率:

fig, ax1 = plt.subplots(figsize=(10,6))

# 第一个Y轴:直方图展示分箱样本量
sns.barplot(data=bin_stats, x='分箱中间值', y='样本量', ax=ax1, color='lightblue', alpha=0.7)
ax1.set_xlabel('连续变量分箱中间值')
ax1.set_ylabel('样本数量', color='blue')
ax1.tick_params(axis='y', labelcolor='blue')

# 第二个Y轴:折线图展示响应率
ax2 = ax1.twinx()
sns.lineplot(data=bin_stats, x='分箱中间值', y='响应率', ax=ax2, marker='o', color='red', linewidth=2)
ax2.set_ylabel('响应率 (%)', color='red')
ax2.tick_params(axis='y', labelcolor='red')
ax2.set_ylim(0, 1)  # 响应率范围0-1,也可以乘以100转成百分比

# 在每个直方图上方标注响应率(保留1位小数的百分比格式)
for i, row in bin_stats.iterrows():
    ax1.text(row['分箱中间值'], row['样本量'] + 2, f"{row['响应率']:.1%}", 
             ha='center', va='bottom', color='darkred', fontweight='bold')

plt.title('连续变量分箱样本量与响应率分布')
plt.tight_layout()
plt.show()
方法二:Plotly 实现交互式双Y轴图表

如果需要做交互式分析(比如鼠标hover查看详细数据),Plotly是更好的选择:

import plotly.graph_objects as go

# 复用上面的bin_stats数据

fig = go.Figure()

# 添加直方图(样本量)
fig.add_trace(go.Bar(
    x=bin_stats['分箱中间值'],
    y=bin_stats['样本量'],
    name='样本数量',
    marker_color='lightblue',
    opacity=0.7
))

# 添加响应率折线(转成百分比格式)
fig.add_trace(go.Scatter(
    x=bin_stats['分箱中间值'],
    y=bin_stats['响应率'] * 100,
    name='响应率 (%)',
    yaxis='y2',
    marker=dict(color='red', size=8),
    line=dict(color='red', width=2)
))

# 配置双Y轴样式
fig.update_layout(
    title='连续变量分箱样本量与响应率分布',
    xaxis_title='连续变量分箱中间值',
    yaxis=dict(
        title='样本数量',
        titlefont=dict(color='blue'),
        tickfont=dict(color='blue')
    ),
    yaxis2=dict(
        title='响应率 (%)',
        titlefont=dict(color='red'),
        tickfont=dict(color='red'),
        overlaying='y',
        side='right',
        range=[0, 100]
    ),
    hovermode='x unified'  # 鼠标hover时同步显示同一分箱的所有数据
)

# 给每个直方图添加响应率标注
for i, row in bin_stats.iterrows():
    fig.add_annotation(
        x=row['分箱中间值'],
        y=row['样本量'] + 1,
        text=f"{row['响应率']:.1%}",
        showarrow=False,
        font=dict(color='darkred', size=10)
    )

fig.show()

一些实用小技巧

  • 分箱方式优化:如果连续变量分布不均匀,建议用pd.qcut做等频分箱,避免出现样本量极少的分箱
  • 标注位置调整:如果样本量差异大,可以把标注位置改成row['样本量'] * 1.02,避免标注重叠
  • 颜色选择:如果需要考虑色盲友好性,可把红蓝配色换成蓝橙配色(比如#1f77b4和#ff7f0e)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:32:34