如何修复Python代码使散点簇与核密度概率等高线匹配?
解决核密度图与散点簇不匹配的问题
你的问题核心是phi2是环形变量(取值范围-180°~180°,对应圆周),但默认的高斯KDE是为线性变量设计的,没有考虑环形空间的连续性——-180°和180°在环形空间里是相邻的,但线性KDE会把它们当成距离360°的远隔点,导致原本的两个环形簇被合并成一个峰值,和散点的三个簇不匹配。
以下是修改方案:
1. 适配环形变量的核密度估计
通过复制环形数据并平移,让KDE识别到-180°和180°的连续性;同时调整带宽让峰值更贴合数据簇。
2. 修改后的完整代码
import numpy as np from scipy.stats import circvar, circmean import scipy.stats as st import matplotlib.pyplot as plt # 原始数据 phi2 = np.array([ 73.62324995, 122.64334345, 72.67064757, -175.63713227, -176.42631705, 111.97090782, 112.43262405, 113.1094183 , 111.53501099, 110.69594668, -75.46326239, -67.76160179, -95.94455459, -64.01216275, -93.67976318, 12.22483834, 11.24380368, 7.12787335, 8.57004673, 9.57479941]) theta = np.array([161.96978904, 174.70995924, 159.42606079, 174.98472276, 174.94378114, 167.49406671, 167.38426198, 164.57103987, 164.51372335, 164.46138757, 22.65628947, 13.59729108, 27.54987277, 16.46934502, 28.45572831, 4.02895771, 3.79725376, 3.9735054 , 3.62785328, 3.48080227]) N = len(phi2) # -------------------------- 适配环形变量的KDE -------------------------- # 复制phi2的环形数据:将原phi2加360,模拟环形连续性 values = np.vstack([phi2, theta]) values_ring = np.hstack([values, np.array([values[0] + 360, values[1]])]) # 创建KDE,手动设置带宽(bw_method越小,峰值越尖锐,越贴合簇) kernel = st.gaussian_kde(values_ring, bw_method=0.2) # 生成包含环形扩展的网格:-180~540(覆盖原区间+平移后的区间) xx_full, yy_full = np.mgrid[-180:540:((N+2)*1j), 0:180:((N+2)*1j)] positions_full = np.vstack([xx_full.ravel(), yy_full.ravel()]) f_full = np.reshape(kernel(positions_full).T, xx_full.shape) # 将平移后的区间(180~540)映射回原区间(-180~180),合并密度值 f = f_full[:(N+2), :] + f_full[(N+2):, :] xx = xx_full[:(N+2), :] # 取原区间的x网格 # -------------------------- 绘图 -------------------------- fig, ax = plt.subplots(figsize=(8,6)) # 等高线图 levels = np.linspace(f.min(), f.max(), 20) cfset = ax.contourf(xx, yy_full, f, levels=levels, cmap='viridis', zorder=0) plt.colorbar(cfset, ax=ax, label='Kernel Density') # 散点图 scatter = ax.scatter(phi2, theta, color="red", linewidth=1, edgecolor="black", s=60, marker='x') ax.set_xlim([-180, 180]) ax.set_ylim([0, 180]) ax.set_xlabel('phi2 (°)') ax.set_ylabel('theta (°)') plt.show()
关键修改说明
- 环形数据处理:将phi2数据复制并平移360°,让KDE识别到-180°和180°的连续性,避免环形簇被合并。
- 带宽调整:通过
bw_method=0.2缩小带宽,让KDE的峰值更尖锐,精准匹配散点的三个簇(可根据实际效果调整该值,越大越平滑,越小越尖锐)。 - 网格扩展与合并:生成覆盖原区间和平移后区间的网格,计算密度后将平移部分映射回原区间,得到正确的环形密度分布。
内容的提问来源于stack exchange,提问作者Laz
相关产品推荐
相关产品推荐

