如何在Seaborn/Matplotlib中指定特定概率密度的Contour Level
如何在Seaborn/Matplotlib中指定特定概率密度的Contour Level
我懂你需求了——你想要的不是Seaborn默认那种等间隔的密度等高线,而是能精准对应数据占比的等高线(比如刚好圈住50%的样本)对吧?找这个方法确实有点绕,我给你一个直接可行的方案,用Scipy的KDE工具配合Seaborn就能实现:
核心思路是:先手动计算联合概率密度的分布,找到对应目标概率的密度阈值,再把这个阈值传给Seaborn的kdeplot作为levels参数,这样画出来的等高线就刚好包含你指定比例的数据。
下面是修改后的完整代码,直接替换你原来的代码就行:
import seaborn as sns import pandas as pd import numpy as np import matplotlib.pyplot as plt from scipy.stats import gaussian_kde # 你的数据(这里保留你的示例数据,实际用真实数据替换即可) np.random.seed(0) x = np.random.randn(100) y = np.random.randn(100) # -------------------------- # 关键步骤:计算目标概率对应的密度阈值 # -------------------------- # 创建联合概率密度估计器 kde = gaussian_kde(np.vstack([x, y])) # 生成和你坐标轴范围匹配的网格点(100j是网格分辨率,数字越大越精准) xmin, xmax = 0, 20 ymin, ymax = 0, 17.5 xi, yi = np.mgrid[xmin:xmax:100j, ymin:ymax:100j] positions = np.vstack([xi.ravel(), yi.ravel()]) # 计算每个网格点的密度值 density = kde(positions).reshape(xi.shape) # 把密度值扁平化,按从高到低排序 density_flat = density.ravel() sorted_density = np.sort(density_flat)[::-1] # 计算累积概率:密度高的区域对应数据更集中,累加后除以总密度(即1)得到占比 cumulative_prob = np.cumsum(sorted_density) / np.sum(sorted_density) # 设定你想要的目标概率,比如50% target_prob = 0.5 # 找到第一个累积概率达标时对应的密度阈值 threshold = sorted_density[np.argmax(cumulative_prob >= target_prob)] # -------------------------- # 画图部分,和你原来的逻辑一致,只是levels参数用我们计算的阈值 # -------------------------- sns.jointplot(x=x, y=y, kind="scatter", color='b') # 传入阈值作为levels,如果你要多个概率(比如50%和90%),就传[threshold1, threshold2] sns.kdeplot(x=x, y=y, color="r", levels=[threshold]) # 你的坐标轴范围设置 plt.ylim(0, 17.5) plt.xlim(0, 20) plt.show()
额外说明
- 如果你需要同时画多个概率的等高线,比如50%和90%,只需要重复计算对应的threshold,把它们放进
levels列表里就行。 - 网格的分辨率(代码里的
100j)可以根据需求调整,数值越大,计算出的阈值越精准,但计算速度会稍慢。 - 这个方法的核心是直接基于你的数据分布计算,完全贴合你想要的“指定概率占比的等高线”需求,不是用默认的等间隔分割。
备注:内容来源于stack exchange,提问作者Apinorr
相关产品推荐
相关产品推荐

