R语言 如何在我的数据中找到一个峰值和两个谷值?

uoifb46i  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(142)

x1c 0d1x的数据
嗨,我有一个数据集(和相对图),看起来有点像这样(它是一系列随时间变化的测量值)。正如你所看到的,它充满了噪音(实际上这已经用滚动平均值进行了“平滑”)。
我想做两件事:
1.找到第一个(也是最高的)峰和它周围的两个谷。只找到这一个峰,而不是曲线中的所有峰。
1.拟合一条从第一个谷到峰的线,从峰到第二个谷,见下面的例子(我想我有一个想法如何做到这一点,所以它不太重要)

我试过一些网上找到的方法(比如ggpmisc的find_peaks),但我只能找到所有的峰和谷,而我只需要这个特定的一个(这是唯一正确的一个)。
你们有什么建议吗?

编辑

如果有人感兴趣,我可以使用pracma::findpeaks(它也可以通过在感兴趣的变量前放置一个-符号来查找谷值)来完成它。我添加了TRUE/TRUE列来跟踪峰和谷的位置,以便稍后更容易地绘制这些点。

#Find peak
peaks <- findpeaks(data$L.MEAN, npeaks = 1, minpeakdistance = 100, sortstr = TRUE)
is_peak <- vector("logical" , length(data$Time))
data$is_peak = is_peak
for (Time in peaks[,2]) {
  data$is_peak[Time] = TRUE
}

#Find valleys
valleys <- findpeaks(-data$L.MEAN, npeaks = 2, minpeakdistance = 100)
is_valley <- vector("logical" , length(data$Time))
data$is_valley = is_valley
for (Time in valleys[,2]) {
  data$is_valley[Time] = TRUE
}

字符串

zf9nrax1

zf9nrax11#

我将导出一些数据进行分析:

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()

字符串
x1c 0d1x的数据
使用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")

找到前面/后面的山谷是一个skosh更多的工作

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::rollapplydata.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个点的正梯度。

相关问题