Seaborn kdeplot与直方图拟合偏差问题求助(数值差10倍)
Seaborn kdeplot与直方图数值差异过大的解决方法
问题描述
使用Seaborn绘制加权KDE曲线时,蓝色KDE曲线数值比橙色直方图大10倍,导致可视化结果失真。代码如下:
import seaborn as sns import matplotlib.pyplot as plt import numpy as np BH = np.array([141.19618068420274, 191.2406412961248, 346.01168490938585, 230.14257295050672, 185.01589850153252, 245.67488131757796, 175.6108949133985, 325.03739349020094, 379.41413332517686, 105.59295515652147 ]) MT = np.array([0.015004641668689452, 0.011144290004860507, 0.007974195145875648, 0.019437031417186952, 0.0036642005992589023, 0.0036642005992589023, 0.0036642005992589023,0.0036642005992589023, 0.0023554322266426775,0.0023554322266426775 ]) sns.kdeplot(x=BH, weights=MT, bw_adjust=0.2, log_scale=True, common_grid=True, bw_method='silverman') plt.hist(BH, weights=MT, bins=np.logspace(2, 7.5, num=50), log=True, histtype='step', density=True) plt.show()
问题原因
sns.kdeplot设置log_scale=True时,在原始数据空间计算概率密度,再将x轴转为对数刻度;plt.hist使用对数间距bins并设置density=True时,计算的是对数数据空间的概率密度;- 两者密度值存在转换关系:
对数空间密度 = 原始值 × 原始空间密度,因此出现10倍左右的数值差异。
解决方法
方法一:在对数空间计算KDE(推荐)
先对原始数据取对数,在对数空间计算KDE后,再将x轴转换为对数刻度(显示原始数值),与直方图的密度逻辑完全匹配:
import seaborn as sns import matplotlib.pyplot as plt import numpy as np BH = np.array([141.19618068420274, 191.2406412961248, 346.01168490938585, 230.14257295050672, 185.01589850153252, 245.67488131757796, 175.6108949133985, 325.03739349020094, 379.41413332517686, 105.59295515652147 ]) MT = np.array([0.015004641668689452, 0.011144290004860507, 0.007974195145875648, 0.019437031417186952, 0.0036642005992589023, 0.0036642005992589023, 0.0036642005992589023,0.0036642005992589023, 0.0023554322266426775,0.0023554322266426775 ]) # 对BH取对数,在对数空间计算KDE log_BH = np.log(BH) sns.kdeplot(x=log_BH, weights=MT, bw_adjust=0.2, bw_method='silverman') # 将x轴转为对数刻度,显示原始数值 plt.xscale('log') # 保持原直方图参数,此时密度与KDE完全匹配 plt.hist(BH, weights=MT, bins=np.logspace(2, 7.5, num=50), log=True, histtype='step', density=True) plt.show()
方法二:手动归一化直方图到原始空间密度
去掉直方图的density=True,手动计算原始空间的概率密度,与kdeplot的密度逻辑匹配:
import seaborn as sns import matplotlib.pyplot as plt import numpy as np BH = np.array([141.19618068420274, 191.2406412961248, 346.01168490938585, 230.14257295050672, 185.01589850153252, 245.67488131757796, 175.6108949133985, 325.03739349020094, 379.41413332517686, 105.59295515652147 ]) MT = np.array([0.015004641668689452, 0.011144290004860507, 0.007974195145875648, 0.019437031417186952, 0.0036642005992589023, 0.0036642005992589023, 0.0036642005992589023,0.0036642005992589023, 0.0023554322266426775,0.0023554322266426775 ]) # 绘制原始空间密度的KDE sns.kdeplot(x=BH, weights=MT, bw_adjust=0.2, log_scale=True, common_grid=True, bw_method='silverman') # 手动计算原始空间的直方图密度 total_weight = MT.sum() bins = np.logspace(2, 7.5, num=50) bin_widths = np.diff(bins) # 计算每个bin的权重和 bin_weights, _ = np.histogram(BH, weights=MT, bins=bins) # 原始空间密度 = bin权重和 / (总权重 × bin宽度) density = bin_weights / (total_weight * bin_widths) # 绘制直方图 plt.step(bins[:-1], density, where='post', color='orange', linestyle='--') plt.yscale('log') plt.show()
内容的提问来源于stack exchange,提问作者Matías Liempi
相关产品推荐
相关产品推荐

