Python与R绘制同数据集密度函数图结果存在差异的原因问询
R与Python绘制分组密度图差异原因说明
核心原因1:密度归一化规则默认值不同
这是导致图形差异的最主要原因:
- R的
ggplot2::geom_density默认按分组单独归一化:每个组的密度曲线下面积都为1,完全不考虑组内样本量差异。你的样本中TARGET=1仅占1/25,但归一化后它的密度峰值会和占绝大多数的TARGET=0差不多高,会放大少数类的分布表现。 - Python的
seaborn.displot(kind='kde')默认common_norm=True:所有分组的密度总和的积分是1,密度值会按各组样本量加权。样本占比极低的TARGET=1的密度峰值会远低于TARGET=0,更符合类别不平衡的真实分布情况,这也是你觉得Python结果更符合预期的原因。
次要原因2:核带宽默认计算规则不同
分组密度的平滑程度由核函数带宽决定,两个工具的默认带宽规则不一致:
- ggplot2默认使用
nrd0(Silverman经验法则)计算带宽 - seaborn默认使用
scott规则计算带宽
对于TARGET=1这种只有3个样本的极小样本组,带宽的微小差异都会导致曲线形状出现明显变化。
代码对齐方案
如果希望两种工具输出结果一致,可以调整参数抹平默认差异:
让R的绘图结果匹配Python默认效果
修改ggplot的密度映射,使用加权密度,同时对齐核参数即可:
# ggplot2 3.3.0及以上版本 ggplot(df,aes(x=varA))+ geom_density(aes(fill=as.factor(TARGET), y = after_stat(density * n / sum(n))), alpha=0.8, position="identity", bw = "scott", kernel = "gaussian") # 旧版本ggplot2替换y映射为y = ..density.. * ..n.. / sum(..n..)即可
让Python的绘图结果匹配R默认效果
修改seaborn的common_norm参数为False,每组单独归一化,同时对齐核参数:
sns.displot(data=df, x="varA", kind="kde", hue='TARGET', fill=True, alpha=0.3, common_norm=False, bw_method='silverman') plt.show()
内容的提问来源于stack exchange,提问作者NopeToday
相关产品推荐
相关产品推荐

