如何获取划分双峰分布为三组的X分界值?代码结果不符预期求解
问题描述
需要将双峰分布划分为三组,预期分界值为x<5、5<x<90、x>90,但运行下方代码后未得到预期结果。
原代码
import numpy as np from scipy.stats import gaussian_kde from scipy.signal import find_peaks # Generate bimodal data dist1 = np.random.normal(loc=0, scale=1, size=100) dist2 = np.random.normal(loc=90, scale=1, size=100) bimodal = np.concatenate((dist1, dist2)) # Fit KDE kde = gaussian_kde(bimodal) xgrid = np.linspace(0,100) pdf = kde.evaluate(xgrid) plt.hist(bimodal, bins=100, density=True) plt.title("Bimodal distribution") # Find peaks peaks, _ = find_peaks(pdf) peak1, peak2 = xgrid[peaks] # Find valley pdf_min = np.min(pdf[(xgrid > peak1) & (xgrid < peak2)]) valley = xgrid[(pdf == pdf_min) & (xgrid > peak1) & (xgrid < peak2)] # Create group labels groups = np.ones(len(bimodal), dtype=int) groups[bimodal < valley] = 0 groups[(bimodal >= valley) & (bimodal <= peak1)] = 1 groups[bimodal > peak1] = 2 # Plot plt.hist(bimodal) plt.vlines([valley, peak1], 0, 100, colors='r') plt.title("Bimodal distribution clustered into 3 groups") plt.show() print(groups)
问题分析与修正
原代码核心问题
- 缺失依赖导入:代码使用
plt但未导入matplotlib.pyplot,会直接触发报错。 - 峰识别失效:
find_peaks默认参数无法识别边缘峰(示例数据左峰在x=0附近,属于xgrid起始位置),导致无法正确获取两个峰的位置。 - 分组逻辑完全偏离预期:误将左峰位置作为右侧分界,且KDE谷值位于两个峰中间(约45左右),和预期的
5、90分界完全不符。
修正方案
方案1:严格按预期阈值分组
如果直接使用你指定的5和90作为分界,无需依赖KDE计算峰谷,直接做阈值判断即可:
import numpy as np import matplotlib.pyplot as plt # 生成双峰数据 dist1 = np.random.normal(loc=0, scale=1, size=100) dist2 = np.random.normal(loc=90, scale=1, size=100) bimodal = np.concatenate((dist1, dist2)) # 按预期阈值分组 groups = np.zeros(len(bimodal), dtype=int) groups[(bimodal >= 5) & (bimodal <= 90)] = 1 groups[bimodal > 90] = 2 # 可视化结果 plt.hist(bimodal, bins=100, density=True) plt.vlines([5, 90], 0, plt.ylim()[1], colors='r', linestyles='--') plt.title("双峰分布分组结果(分界值:5、90)") plt.show() print(groups)
方案2:通过KDE自动适配数据分布分组
如果希望基于数据分布自动寻找类似分界(适配实际数据的峰谷特征),修正峰谷识别逻辑:
import numpy as np from scipy.stats import gaussian_kde import matplotlib.pyplot as plt # 生成双峰数据 dist1 = np.random.normal(loc=0, scale=1, size=100) dist2 = np.random.normal(loc=90, scale=1, size=100) bimodal = np.concatenate((dist1, dist2)) # 拟合KDE,扩展xgrid范围避免边缘峰被忽略 kde = gaussian_kde(bimodal) xgrid = np.linspace(np.min(bimodal)-5, np.max(bimodal)+5, 500) pdf = kde.evaluate(xgrid) # 稳定获取两个峰的位置:取PDF的两个最大值点 peak_indices = np.argsort(pdf)[-2:] peak_indices.sort() peak_left, peak_right = xgrid[peak_indices] # 查找两个峰之间的谷值 mask_between_peaks = (xgrid > peak_left) & (xgrid < peak_right) valley_index = np.argmin(pdf[mask_between_peaks]) valley = xgrid[mask_between_peaks][valley_index] # 自定义分界:左分界用预期的5,右分界用右峰位置 left_threshold = 5 right_threshold = peak_right # 分组 groups = np.zeros(len(bimodal), dtype=int) groups[(bimodal >= left_threshold) & (bimodal <= right_threshold)] = 1 groups[bimodal > right_threshold] = 2 # 可视化结果 plt.hist(bimodal, bins=100, density=True) plt.vlines([left_threshold, right_threshold], 0, plt.ylim()[1], colors='r', linestyles='--') plt.scatter([peak_left, peak_right], [pdf[peak_indices[0]], pdf[peak_indices[1]]], c='blue', label='峰') plt.scatter(valley, pdf[mask_between_peaks][valley_index], c='green', label='谷') plt.title("双峰分布自动分组结果") plt.legend() plt.show() print(groups)
内容的提问来源于stack exchange,提问作者Smith
相关产品推荐
相关产品推荐

