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

如何让手动实现的KDE与sns.kdeplot输出的可视化结果一致?

两种KDE绘图结果差异的核心原因
  • 等高线层级计算逻辑完全不同:这是最主要的差异来源。sns.kdeplot默认的层级是基于密度的分位数设置,每个层级对应可覆盖指定比例样本的密度阈值,默认10个层级对应0~0.9的分位数区间,等高线是按数据分布的覆盖比例划分的。而你调用plt.contourf(levels=10)是把计算得到的密度值的绝对数值范围等分成10份,两者划分逻辑完全不同,最终呈现的色块分布自然差异很大。
  • 带宽计算存在潜在差异:scipy.stats.gaussian_kde和Seaborn内部的KDE实现虽然默认都采用Scott带宽规则,但Seaborn会对两个维度分别做标准化后计算带宽,和scipy直接基于原始二维数据协方差矩阵计算带宽的逻辑存在细微差别,会导致密度分布的平滑程度有差异。
  • 色阶映射适配逻辑不同:sns.kdeplot默认会将最低密度值对应色阶的最浅端、最高密度对应最深端,而plt.contourf会根据传入的层级自动适配色阶,因为层级划分逻辑不同,最终的明暗呈现也会有区别。

修正方案

你可以调整contourf的层级计算逻辑,对齐Seaborn的分位数规则,就能得到和sns.kdeplot几乎一致的结果,修正后的代码如下:

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats # 原代码缺了该导入,直接运行会报错

geyser = sns.load_dataset("geyser")

dur = np.array(geyser["duration"])
wait = np.array(geyser["waiting"])

# 自定义KDE实现
def make_kde(x, y):
    kde = stats.gaussian_kde([x, y])
    xx, yy = np.mgrid[min(x):max(x):(max(x)-min(x))/200,
                      min(y):max(y):(max(y)-min(y))/200]
    density = kde(np.c_[xx.flat, yy.flat].T).reshape(xx.shape)
    return xx, yy, density

xgrid, ygrid, density = make_kde(dur, wait)

fig, ax = plt.subplots()
# 核心修改:用密度的分位数作为层级,对齐Seaborn逻辑
levels = np.quantile(density, np.linspace(0, 0.9, 10))
ax.contourf(xgrid, ygrid, density, cmap="binary", levels=levels)
plt.show()

原代码对应效果参考

  • sns.kdeplot生成效果:sns.kdeplot效果图
  • 原plt.contourf生成效果:自定义contourf效果图

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 09:48:03