如何程序化识别钟形曲线的首个最小值、峰值与第二个最小值
识别钟形分布的三个关键点位
问题描述
我正在处理一组类正态钟形分布的数据集,需要识别三个特定点:
- 曲线上升前的首个最小值点
- 曲线的峰值(最大值点)
- 峰值后曲线下降过程中的第二个最小值点
难点在于曲线尾部趋于平坦,最小值定义模糊,考虑用一阶导数符号变化判断:首个最小值对应导数由负变正的位置,第二个最小值对应峰值后导数由正变负的位置。
数据集信息
分布曲线

Pandas数据结构
# ... (数据加载代码) ... print(df.head())
y轴数值
0 0.000006775275118 1 0.000002841071152 2 0.000002331050869 3 0.000002098089639 4 0.000001958793763 5 0.000001882957831 6 0.000001817511261 7 0.000001778793930 8 0.000001747600657 9 0.000001726581760 10 0.000001736836910 11 0.000001725393807 12 0.000001735801905 13 0.000001722637070 14 0.000001749210289 15 0.000001743336865 16 0.000001773540895 17 0.000001758737558 18 0.000001792945553 19 0.000001789850672 20 0.000001779160328 21 0.000001807576901 22 0.000001808267621 23 0.000001818196607 24 0.000001811775275 25 0.000001818907290 26 0.000001807848091 27 0.000001836718285 28 0.000001808366208 29 0.000001808187769 30 0.000001782767490 31 0.000001769246699 32 0.000001775707035 33 0.000001759920903 34 0.000001737253676 35 0.000001722037872 36 0.000001727249139 37 0.000001693093662 38 0.000001701267438 39 0.000001692311112 40 0.000001678170239 41 0.000001661488536 42 0.000001668086770 43 0.000001667761220 44 0.000001662043200 45 0.000001667680139 46 0.000001659051206 47 0.000001708371198 48 0.000001732222077 49 0.000001774399919 50 0.000001876523600 51 0.000002025685347 52 0.000002259535699 53 0.000002560415994 54 0.000003055340098 55 0.000003727916538 56 0.000004705124476 57 0.000005971950809 58 0.000007664882924 59 0.000009665827809 60 0.000012083860418 61 0.000014769510653 62 0.000017550004674 63 0.000020119588986 64 0.000022386885842 65 0.000024171012583 66 0.000025206126640 67 0.000025491871789 68 0.000024878712706 69 0.000023424992853 70 0.000021276252458 71 0.000018607410922 72 0.000015824313725 73 0.000012923828210 74 0.000010311275904 75 0.000008025889954 76 0.000006292151302 77 0.000004904108668 78 0.000003974381668 79 0.000003333372577 80 0.000002833383398 81 0.000002537387898 82 0.000002308652989 83 0.000002216008051 84 0.000002145439742 85 0.000002146526344 86 0.000002167240574 87 0.000002248661389 88 0.000002323548464 89 0.000002430060014 90 0.000002537689493 91 0.000002347846822 Name: diff_current, dtype: float64
解决方案
核心逻辑
- 计算一阶导数:用差分法计算y值的一阶导数,反映曲线的增减趋势
- 定位峰值:直接找y值最大值点,或用
scipy.find_peaks精准定位主峰 - 首个最小值:在峰值前,寻找导数由负变正的第一个位置(曲线从下降转上升的拐点)
- 第二个最小值:在峰值后,寻找导数由正变负的第一个位置(曲线从上升转下降的拐点)
- 过滤干扰:设置导数阈值,忽略尾部平坦区域的微小波动
代码实现
import pandas as pd import numpy as np from scipy.signal import find_peaks # 假设数据已加载到df中,y列名为'diff_current' y = df['diff_current'].values x = np.arange(len(y)) # 1. 计算一阶导数(差分) dy = np.diff(y) # 2. 定位主峰,prominence参数根据数据量级调整 peak_idx, _ = find_peaks(y, prominence=0.000005) peak_pos = peak_idx[0] # 3. 定位首个最小值:峰值前导数由负变正的第一个拐点 first_min_pos = None pre_peak_dy = dy[:peak_pos] for i in range(1, len(pre_peak_dy)): # 忽略极小波动,设置导数绝对值阈值 if abs(pre_peak_dy[i-1]) > 1e-8 and abs(pre_peak_dy[i]) > 1e-8: if pre_peak_dy[i-1] < 0 and pre_peak_dy[i] > 0: first_min_pos = i break # 4. 定位第二个最小值:峰值后导数由正变负的第一个拐点 second_min_pos = None post_peak_dy = dy[peak_pos:] for i in range(1, len(post_peak_dy)): if abs(post_peak_dy[i-1]) > 1e-8 and abs(post_peak_dy[i]) > 1e-8: if post_peak_dy[i-1] > 0 and post_peak_dy[i] < 0: second_min_pos = peak_pos + i break # 输出结果 print(f"首个最小值点索引: {first_min_pos}, 值: {y[first_min_pos]}") print(f"峰值点索引: {peak_pos}, 值: {y[peak_pos]}") print(f"第二个最小值点索引: {second_min_pos}, 值: {y[second_min_pos]}")
代码说明
- 差分计算:
np.diff(y)替代连续导数,适合离散数据集 - 主峰过滤:
find_peaks的prominence参数可排除小峰值干扰 - 阈值过滤:通过导数绝对值阈值
1e-8,忽略尾部无意义的微小波动 - 拐点判断:严格依据导数符号反转定位,确保精准捕捉趋势变化
内容的提问来源于stack exchange,提问作者joe
相关产品推荐
相关产品推荐

