You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

咨询解决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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 21:38:12