【问题标题】:R get and restrain number of local maxima position and valueR获取并约束局部最大值位置和值的数量
【发布时间】:2019-07-17 12:37:14
【问题描述】:

我正在使用 R 分析一些光谱,并试图获得局部最大值,即它们的位置和值。

例如,使用向量:

spectrum <- c(1,1,2,3,5,3,3,2,1,1,5,6,9,5,1,1)

我想要以下结果:

pos.peaks = c(5,13)
val.peaks = c(5,9)

我已经使用了此处提供的解决方案:Finding local maxima and minima 用于峰的位置,但是之后如何提取相应的值?知道我不只有一个向量,我在一个列表的几个数据帧中有几列,我想将该函数应用于列表中所有数据帧的每一列。例如,对于我所做的所有职位:

example <- lapply(mylist, function (x) lapply(x, function(y) which(diff(sign(diff(y)))==-2)+1))

我没有设法让它与切片或过滤器一起使用,因为我不需要同一数据帧中的相同行...

此外,我想知道如何减少我得到的局部最大值的数量,因为我的数据非常嘈杂。

如果您能给我任何帮助,我将不胜感激。

谢谢!

纳特

【问题讨论】:

  • 只需使用位置对数据进行子集化以获取值
  • 你可以使用spectrum[which(diff(sign(diff(spectrum))) == - 2) + 1]

标签: r position max


【解决方案1】:
peakPosition <- function(x, inclBorders=TRUE) {
  if(inclBorders) {y <- c(min(x), x, min(x))
  } else {y <- c(x[1], x)}
  y <- data.frame(x=sign(diff(y)), i=1:(length(y)-1))
  y <- y[y$x!=0,]
  idx <- diff(y$x)<0
  (y$i[c(idx,F)] + y$i[c(F,idx)] - 1)/2
}

(pos.peaks  <- peakPosition(spectrum))
#[1]  5 13

(val.peaks  <- spectrum[pos.peaks])
#[1] 5 9

对于循环来获取类似的值:

example <- lapply(mylist, function(x) {x[peakPosition(x)]})

对于职位:

lapply(mylist, peakPosition)

在评论中,您说您的数据非常嘈杂,并且您达到了许多局部最大值,因此您可以先尝试如下平滑您的数据:

d <- predict(loess(spectrum ~ seq_along(spectrum)))
pos.peaksS  <- peakPosition(d)
(i <- pos.peaks[apply(abs(outer(pos.peaks, pos.peaksS, "-")), 1, FUN=which.min)])
#[1]  5 13
spectrum[i]
#[1] 5 9

或者您对索引进行一些聚合,例如:

set.seed(42)
x <- rnorm(1e3)

y <- peakPosition(x)
(pos.peaks <- sort(aggregate(y, list(k=kmeans(y, 7)$cluster), FUN = function(i) i[which.max(x[i])])[,2]))
#[1] 118 287 459 525 613 820 988

(val.peaks  <- x[pos.peaks])
#[1] 2.701891 2.459594 2.965865 3.229069 2.223534 3.211199 3.495304

【讨论】:

  • 感谢您一路循环,我将尝试两种解决方案,看看哪种方案最适合我的数据(它非常嘈杂,所以我得到了许多局部最大值)跨度>
  • @nathkpa 我已经更新了答案,但也许你提出了一个新问题,主题是减少局部最大值。
  • 再次感谢,我已经修改了标题和文字,“克制”一词是否适合标题?
  • @nathkpa 我不知道“克制”是否合适——没有母语人士。
【解决方案2】:

如果向量的长度至少为 3:

find_peaks <- function(x, max = TRUE) {
  if (max == FALSE) x <- x * (-1)
  res <- rep(FALSE, length(x))
  if (x[1] > x[2]) res[1] <- TRUE
  if (x[length(x)-1] < x[length(x)]) res[length(res)] <- TRUE
  for (i in (2:(length(x)-1))) {
    if ((x[i-1] < x[i]) & (x[i+1] < x[i])) res[i] <- TRUE
  }
  res
}
spectrum[find_peaks(spectrum)]
# [1] 5 9
which(find_peaks(spectrum))
# [1]  5 13

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    • 2020-05-15
    • 2016-03-16
    • 1970-01-01
    • 2022-11-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多