连续变量与二分类变量折线图:添加双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
相关产品推荐
相关产品推荐

