Python阈值检测程序运行过慢的性能优化咨询
嘿,我来帮你搞定这段代码的性能问题!你的思路完全没问题,但确实有几个关键细节拖慢了速度,我们一步步来优化:
1. 别再用np.where找索引——直接计算/用二分查找!
你的x是线性时间数组,这意味着它要么是均匀间隔的,要么是单调递增的,完全没必要每次遍历1200万元素找匹配值:
- 如果x是均匀间隔的(比如从x0开始,步长固定为dx),直接用公式计算索引,这是O(1)的操作,比
np.where的O(n)快几个数量级:dx = x[1] - x[0] start_x = ((i_start - x[0]) / dx).astype(int) stop_x = ((i_stop - x[0]) / dx).astype(int) - 如果x不是严格均匀,但单调递增,就用
np.searchsorted做二分查找,时间复杂度O(log n),同样远快于np.where:start_x = np.searchsorted(x, i_start, side='left') stop_x = np.searchsorted(x, i_stop, side='right')
2. 停止循环里的np.append——用列表先存再转数组
你代码里一开始用了列表,但后来又混用np.append,这会导致每次调用都重新分配内存、复制数组,非常低效。换成纯列表的append(amortized O(1)操作),最后再转numpy数组就好:
result_start = [] result_stop = [] # 循环内用列表append result_start.append(i_start) result_stop.append(i_stop) # 循环结束后统一转数组 result_start = np.array(result_start) result_stop = np.array(result_stop)
3. 向量化计算区间极值——彻底扔掉循环!
逐循环计算每个切片的nanmax/nanmin是另一个大瓶颈,我们可以用np.reduceat系列函数批量计算所有区间的极值,完全避免循环:
整合后的完整优化代码
import numpy as np def event_threshold(x, y, start, stop, threshold): # 第一步:快速计算所有区间的索引(根据x的类型选下面一种) # 情况1:x是均匀间隔的线性数组 dx = x[1] - x[0] starts_x = ((start - x[0]) / dx).astype(int) stops_x = ((stop - x[0]) / dx).astype(int) # 情况2:x是单调递增但非均匀的,注释掉上面三行,用下面两行 # starts_x = np.searchsorted(x, start, side='left') # stops_x = np.searchsorted(x, stop, side='right') # 第二步:构造分割点,批量计算所有区间的极值 split_points = np.concatenate([starts_x, stops_x]).reshape(-1, 2).flatten() if threshold >= 0: # 批量计算每个区间的nanmax interval_max = np.nanmax.reduceat(y, split_points, axis=0)[::2] # 生成筛选掩码:保留极值≥阈值的区间 mask = interval_max >= threshold else: # 批量计算每个区间的nanmin interval_min = np.nanmin.reduceat(y, split_points, axis=0)[::2] # 生成筛选掩码:保留极值≤阈值的区间 mask = interval_min <= threshold # 第三步:直接用掩码筛选结果 result_start = start[mask] result_stop = stop[mask] return result_start, result_stop
额外小提示
- 如果你的y数组里没有
nan,可以把np.nanmax.reduceat换成np.max.reduceat,速度还能再提一截; - 确保
start和stop本身就是numpy数组,如果是列表的话先转成数组,这样所有操作都是向量化的。
内容的提问来源于stack exchange,提问作者Gralhos
相关产品推荐
相关产品推荐

