咨询解决peak函数无法识别数据集首个局部最大值的技术方案
如何识别序列首元素作为局部峰值?
我有两组时间序列数据(Max_Val列为核心分析列):
第一组数据
[,1] [,2] [,3] statSignal Time Max_Val Min_Val 5001.000 172 -179 8334.333 162 -188 11667.667 1205 -674 15001.000 1205 -1649 18334.333 1205 -1649 21667.667 703 -1649 25001.000 632 -669 28334.333 881 -872 31667.667 1640 -872 35001.000 1640 -872 38334.333 1640 -552 41667.667 215 -444 45001.000 1408 -652 48334.333 1408 -1711 51667.667 1408 -1711 55001.000 772 -1711 58334.333 540 -205 61667.667 268 -205 65001.000 268 -205
针对这组数据,Max_Val列的局部峰值为{1205, 1640, 1408},我用peak函数可以成功识别这些峰值。
第二组数据
[,1] [,2] [,3] statSignal Time Max_Val Min_Val 5001.000 1298 -2176 8334.333 1048 -2176 11667.667 1048 -222 15001.000 294 -222 18334.333 132 -221 21667.667 1959 -925 25001.000 1959 -2064 28334.333 1959 -2064 31667.667 1326 -2064 35001.000 1326 -344 38334.333 402 -1237 41667.667 1754 -2861 45001.000 4369 -2861 48334.333 4369 -2861 51667.667 4369 -2020 55001.000 851 -2020
但在这组数据中,当局部最大值为首个数值(1298)时,peak函数无法识别它。
现寻求解决该问题的方案,比如修改peak函数、使用其他函数或编写自定义代码,望得到技术支持。
解决方案
1. 自定义峰值检测函数(兼容边界)
大部分默认峰值函数只识别内部峰值(要求左右都有元素且当前值大于两侧),首元素因无左侧元素被忽略。以下是兼容边界的自定义函数:
detect_peaks <- function(x) { peaks <- c() # 处理首元素:只要大于等于右侧相邻元素即判定为峰值 if (length(x) >= 1 && (length(x) == 1 || x[1] >= x[2])) { peaks <- c(peaks, x[1]) } # 处理中间元素:当前值大于等于左右两侧 for (i in 2:(length(x)-1)) { if (x[i] >= x[i-1] && x[i] >= x[i+1]) { peaks <- c(peaks, x[i]) } } # 处理尾元素:只要大于等于左侧相邻元素即判定为峰值 if (length(x) >= 2 && x[length(x)] >= x[length(x)-1]) { peaks <- c(peaks, x[length(x)]) } # 去重连续重复的峰值 unique(peaks) } # 调用示例 max_vals <- c(1298, 1048, 1048, 294, 132, 1959, 1959, 1959, 1326, 1326, 402, 1754, 4369, 4369, 4369, 851) detect_peaks(max_vals) # 输出:[1] 1298 1959 4369
2. 用滑动窗口工具实现(以zoo包为例)
通过滑动窗口判断每个位置是否为峰值,单独处理边界:
library(zoo) max_vals <- c(1298, 1048, 1048, 294, 132, 1959, 1959, 1959, 1326, 1326, 402, 1754, 4369, 4369, 4369, 851) # 窗口函数:判断窗口中间值是否为最大值 peak_fun <- function(window) { mid <- length(window) %/% 2 + 1 window[mid] == max(window) } # 分别检测首元素、中间元素、尾元素的峰值 first_peak <- max_vals[1] >= max_vals[2] mid_peaks <- rollapply(max_vals, width=3, FUN=peak_fun, align="center") last_peak <- max_vals[length(max_vals)] >= max_vals[length(max_vals)-1] # 合并结果并去重 all_peaks <- c( if (first_peak) max_vals[1], max_vals[which(mid_peaks)+1], if (last_peak) max_vals[length(max_vals)] ) unique(all_peaks) # 输出:[1] 1298 1959 4369
3. 调整现有峰值函数的边界处理(以pracma::findpeaks为例)
给序列前后添加极小值,让首/尾元素变成"内部"元素,再用原函数检测:
library(pracma) max_vals <- c(1298, 1048, 1048, 294, 132, 1959, 1959, 1959, 1326, 1326, 402, 1754, 4369, 4369, 4369, 851) # 前后填充负无穷,让边界元素处于窗口内 padded_vals <- c(-Inf, max_vals, -Inf) peaks <- findpeaks(padded_vals, threshold=0) # 提取峰值并去重 unique(peaks[,1]) # 输出:[1] 1298 1959 4369
内容的提问来源于stack exchange,提问作者user341191
相关产品推荐
相关产品推荐

