当前位置:首页>python>用Python做科研级画图——KDE密度

用Python做科研级画图——KDE密度

  • 2026-09-02 19:04:21
用Python做科研级画图——KDE密度

大家好,我是你们的小帅学长。

在上一篇里,我们讲了直方图(Histogram),也讲了一个关键问题:bin 怎么选?但你可能已经发现一个现象:同一组数据,只要改变分箱数,直方图的形状就可能明显变化。

有时候,bin 少了 → 结构被抹平;bin 多了 → 噪声变结构。这时候很多人就会问,有没有一种方法,不需要分箱,也能看分布?

答案就是今天的主角:KDE(Kernel Density Estimation)核密度估计。简单理解为,KDE 就是一条“平滑版的直方图”。

01.KDE 到底在做什么?

直方图的逻辑是,把数据切成很多小箱子,然后统计每个箱子的数量。

而 KDE 的逻辑是,在每个数据点上放一个小“平滑曲线”,再把它们加起来。最终得到一条连续的概率密度曲线。

所以 KDE 的核心特点是 没有分箱边界、曲线连续、更容易看出整体趋势。

很多论文里的“分布曲线图”,其实就是 KDE。

02. 什么时候 KDE 比直方图更好?

1)当你关心的是“整体形态”

例如,是否单峰 / 多峰?是否偏态?分布是否平滑?这时候,KDE 会比直方图更直观。

特别是在数据量较大的情况下(n > 200),KDE 往往能更好地呈现真实结构。

2)当你需要比较多组分布

如果你想比较:模型 A vs 模型 B、男 vs 女、城市 vs 农村,这时候,直方图叠加往往会很乱。

而 KDE 可以这样画:两条平滑曲线叠在一起,趋势差异一眼可见。

3)当你不希望 bin 影响结果

直方图的一个问题是:分箱边界会影响形状。

KDE 不存在这个问题,因为它没有 bin。

03. KDE 的关键参数:bandwidth(带宽)

如果说直方图的核心是 bin,那 KDE 的核心就是 bandwidth。

带宽控制的是 曲线有多“平滑”。

带宽太小:曲线会非常锯齿、就像把噪声当结构

带宽太大:曲线会过度平滑、多个峰可能被合并

所以,KDE 的艺术,其实是带宽选择。

好消息是 大多数软件已经有不错的自动选择规则。

例如:

Scott rule

Silverman rule

通常已经足够。

04. KDE 的常见误区

1)KDE 一定比直方图好

不是。如果样本量很小(n < 50),KDE 可能会画出“看起来很平滑但不真实”的曲线。这时候直方图反而更可靠。

2)KDE 是概率

很多人误以为曲线高度就是概率。

实际上,KDE 表示的是概率密度。曲线下面积才是概率。

3)KDE 可以解释每个细节

KDE 是一种估计方法。曲线形状会受带宽影响,所以不要过度解读细节。

05. Python 示例代码(直方图 + KDE)

import osimport numpy as npimport matplotlib as mplimport matplotlib.pyplot as pltimport seaborn as snsfrom matplotlib import font_manager as fmfrom matplotlib.ticker import MaxNLocatorwin_fonts = r"C:\Windows\Fonts"for p in [          os.path.join(win_fonts, "times.ttf"),          os.path.join(win_fonts, "timesbd.ttf"),          os.path.join(win_fonts, "timesi.ttf"),          os.path.join(win_fonts, "simsun.ttc"),]:         if os.path.exists(p):                    try:                             fm.fontManager.addfont(p)                     except Exception:                             passmpl.rcParams["font.family"] = ["Times New Roman", "SimSun"]mpl.rcParams["axes.unicode_minus"] = FalseOUT_DIR = r"D:\py_figs"os.makedirs(OUT_DIR, exist_ok=True)np.random.seed(42)data_A = np.concatenate([        np.random.normal(0, 1, 400),         np.random.normal(4, 1.2, 400)])data_B = np.random.normal(2, 1.5, 800)mean_A = np.mean(data_A)median_A = np.median(data_A)mean_B = np.mean(data_B)median_B = np.median(data_B)fig, ax = plt.subplots(figsize=(8,5))# 直方图sns.histplot(         data_A,         bins="fd",         stat="density",         alpha=0.35,        ax=ax)# KDE曲线sns.kdeplot(         data_A,         linewidth=2.5,         label="Distribution A")sns.kdeplot(         data_B,         linewidth=2.5,         linestyle="--",        label="Distribution B")# 均值线ax.axvline(mean_A, linestyle="--", linewidth=1.5)ax.axvline(mean_B, linestyle="--", linewidth=1.5)# 中位数线ax.axvline(median_A, linestyle="-.", linewidth=1.5)ax.axvline(median_B, linestyle="-.", linewidth=1.5)ax.set_title("Histogram + KDE Density Comparison / 直方图与KDE密度对比", fontsize=14)ax.set_xlabel("Value / 数值", fontsize=12)ax.set_ylabel("Density / 密度", fontsize=12)ax.xaxis.set_major_locator(MaxNLocator(nbins=6))ax.yaxis.set_major_locator(MaxNLocator(nbins=6))ax.legend(frameon=False)out_path = os.path.join(OUT_DIR, "kde_density_demo.jpg")fig.savefig(         out_path,         dpi=300,         bbox_inches="tight",         pad_inches=0.05)plt.close()print("Saved:", out_path)

在这张图中,直方图展示的是样本频率分布,而 KDE 曲线展示的是平滑的概率密度。虚线表示均值(mean),点线表示中位数(median),通过这些辅助信息可以更清楚地理解分布结构。

06. 什么时候该用 KDE?

你可以记住一个简单原则:

场景
推荐
想看分布结构
KDE
样本量较小
直方图
对比多个分布
KDE
需要统计解释
直方图

看完分布之后,我们接下来要讲一个统计含义非常强的图:《箱线图(解释统计含义 + 别误读)》。箱线图不仅能看分布,还能直接读出中位数、四分位距、异常值,但很多人其实一直在误读箱线图。下一篇,我会把箱线图背后的统计逻辑讲清楚。

——期待你的关注—— 

往期内容:

用Python做科研级画图——哑铃图

用Python做科研级画图——直方图

用Python做科研级画图——点图替代柱状

用Python做科研级画图——分组对比

用Python做科研级画图——柱状图基础

最新文章

随机文章