如何在我的数据中找到一个峰值和 2 个谷值?

问题描述 投票:0回答:1

曲线

嗨,我有一个数据集(和相对图),看起来有点像这样(它是随着时间的推移进行的一系列测量)。正如您所看到的,它充满了噪音(实际上这已经用滚动平均值“平滑”了)。

我正在努力实现两件事:

  1. 找到第一个(也是最高的)山峰及其周围的 2 个山谷。仅此一个峰值,而不是曲线中的所有峰值。

  2. 拟合一条从第一个谷到峰、从峰到第二个谷的线,请参见下面的示例(我想我知道如何做到这一点,所以它不太重要)

示例

我尝试了一些在网上找到的方法(例如来自ggpmisc的

find_peaks
),但我只能找到所有峰和谷,而我只需要这个特定的(这是唯一真实的)。

我的情节的基本代码是这样的(我已经删除了所有样式):

model_data %>% ggplot() +
  geom_line(aes(x = Time, y = L.MEAN, color = "red"), linewidth = 1)

大家有什么建议吗?

r plot curve-fitting smoothing curve
1个回答
0
投票

我将导出一些数据来分析:

dat <- data.frame(x = seq(-1, 6*pi, by=0.01))
dat$y <- sin(dat$x) / ifelse(abs(dat$x) < 1e-9, 1, sqrt(abs(dat$x)))
library(ggplot2)
ggplot(dat, aes(x, y)) + geom_line()

使用

which.max
可以轻松找到最大值:

ymaxi <- which.max(dat$y)
ymaxi
# [1] 432
dat$y[ymaxi + -1:1]
# [1] 0.8512233 0.8512383 0.8511839

ggplot(dat, aes(x, y)) +
geom_line() +
geom_point(data = ~ .[ymaxi,], color = "red")

找到前面/后面的山谷是一项艰巨的工作

ymini1 <- ymaxi + 1L - which(diff(rev(dat$y[1:ymaxi])) > 0)[1]
dat$y[ymini1 + -2:2]
# [1] -0.8511520 -0.8512284 -0.8512356 -0.8511732 -0.8510408
ymini2 <- which(diff(dat$y[-(1:ymaxi)]) > 0)[1] + ymaxi
dat$y[ymini2 + -1:1]
# [1] -0.4633072 -0.4633109 -0.4632688

ggplot(dat, aes(x, y)) + geom_line() + geom_point(data = ~ .[c(ymini1, ymaxi, ymini2),], color = "red")

我将“谷”定义为梯度 (

diff(.)
) 从负值变为正值的点。您可能需要对此进行一些容忍,以便对如此多的点进行更改,以便跳过假谷...在这种情况下,有很多不同的启发式方法,主要取决于上下文的上下文数据和您的意图。例如,您可以找到大多数正值高于某个值的值,例如将
> 0
更改为
> 0.01
或类似的值,但如果它是正值(向上倾斜)但非常接近平坦,则可能会失败。或者你可以说寻找 n 个连续的正数,这是一个滚动窗口问题,并且通过使用
zoo::rollapply
data.table::frollapply
或许多其他窗口函数来了解情况;你也可以使用游程编码(R 的
rle
函数),也许像:

diffs <- diff(dat$y[-(1:ymaxi)])
r <- rle(diffs > 0)
r
# Run Length Encoding
#   lengths: int [1:6] 343 318 316 315 315 160
#   values : logi [1:6] FALSE TRUE FALSE TRUE FALSE TRUE
r$values[r$lengths < 3 & r$values] <- FALSE
which(inverse.rle(r))[1] + ymaxi
# [1] 776

这恰好与上面相同,但会“忽略”在再次变为负值之前仅 1 或 2 点的正梯度。

© www.soinside.com 2019 - 2024. All rights reserved.