寻找局部最大值和最小值
Posted
技术标签:
【中文标题】寻找局部最大值和最小值【英文标题】:Finding local maxima and minima 【发布时间】:2021-09-12 01:20:11 【问题描述】:我正在寻找一种计算有效的方法来查找 R 中大量数字的局部最大值/最小值。
希望没有for
循环......
例如,如果我有一个像1 2 3 2 1 1 2 1
这样的数据文件,我希望函数返回 3 和 7,它们是局部最大值的位置。
【问题讨论】:
【参考方案1】:diff(diff(x))
(或diff(x,differences=2)
:感谢@ZheyuanLi)本质上计算二阶导数的离散模拟,因此在局部最大值处应该是负数。下面的+1
处理了diff
的结果比输入向量短这一事实。
编辑:添加了@Tommy 对 delta-x 不是 1 的情况的更正...
tt <- c(1,2,3,2,1, 1, 2, 1)
which(diff(sign(diff(tt)))==-2)+1
我上面的建议 (http://statweb.stanford.edu/~tibs/PPC/Rdist/) 适用于数据噪声较大的情况。
【讨论】:
你比我少了几秒钟 - 并且有更好的解决方案 :) 但如果值不总是改变一个,它应该是which(diff(sign(diff(x)))==-2)+1
。
正如 Tommy 所指出的,当输入列表按递增顺序排列时,Ben 的解决方案也不起作用。例如tt
链接...ppc.peaks.html不起作用,请改用statweb.stanford.edu/~tibs/PPC/Rdist。【参考方案2】:
@Ben 的解决方案非常棒。但它不处理以下情况:
# all these return numeric(0):
x <- c(1,2,9,9,2,1,1,5,5,1) # duplicated points at maxima
which(diff(sign(diff(x)))==-2)+1
x <- c(2,2,9,9,2,1,1,5,5,1) # duplicated points at start
which(diff(sign(diff(x)))==-2)+1
x <- c(3,2,9,9,2,1,1,5,5,1) # start is maxima
which(diff(sign(diff(x)))==-2)+1
这是一个更健壮(但更慢、更丑)的版本:
localMaxima <- function(x)
# Use -Inf instead if x is numeric (non-integer)
y <- diff(c(-.Machine$integer.max, x)) > 0L
rle(y)$lengths
y <- cumsum(rle(y)$lengths)
y <- y[seq.int(1L, length(y), 2L)]
if (x[[1]] == x[[2]])
y <- y[-1]
y
x <- c(1,2,9,9,2,1,1,5,5,1)
localMaxima(x) # 3, 8
x <- c(2,2,9,9,2,1,1,5,5,1)
localMaxima(x) # 3, 8
x <- c(3,2,9,9,2,1,1,5,5,1)
localMaxima(x) # 1, 3, 8
【讨论】:
感谢我尝试了这段代码,它可以工作!如何在不更改输入的情况下为局部最小值修改它? 嗨,Tommy,我想在一个包中使用您的 localMinima 功能,请您联系我以便我能够正确地确认您吗? @VahidMir 基本上这个函数是一种(聪明的!)方法来获取向量的一阶导数从正到负切换的位置。因此,局部最小值将在它从负数变为正数的地方给出:只需将第一行替换为y <- diff(c(.Machine$integer.max, x)) < 0L
(这样可以保留检测初始最小值的可能性)
很好,但是 localMaxima()
会在拐点 localMaxima(c(1, 2, 2, 3, 2, 1))
上触发错误,返回 2 4
而不仅仅是 4
为什么 rle(y)$lengths 被调用了两次?我的意思是我了解y <- cumsum(rle(y)$lengths)
,但不了解前面的独立rle(y)$lengths
【参考方案3】:
使用动物园库函数rollapply:
x <- c(1, 2, 3, 2, 1, 1, 2, 1)
library(zoo)
xz <- as.zoo(x)
rollapply(xz, 3, function(x) which.min(x)==2)
# 2 3 4 5 6 7
#FALSE FALSE FALSE TRUE FALSE FALSE
rollapply(xz, 3, function(x) which.max(x)==2)
# 2 3 4 5 6 7
#FALSE TRUE FALSE FALSE FALSE TRUE
然后使用“coredata”为那些“which.max”是表示局部最大值的“中心值”的值提取索引。您显然可以使用 which.min
而不是 which.max
对局部最小值执行相同的操作。
rxz <- rollapply(xz, 3, function(x) which.max(x)==2)
index(rxz)[coredata(rxz)]
#[1] 3 7
我假设您不需要起始值或结束值,但如果您这样做,您可以在处理之前填充向量的末端,就像染色体上的端粒一样。
(我注意到 ppc 包(“Peak Probability Contrasts”)用于进行质谱分析,只是因为在阅读上面@BenBolker 的评论之前我不知道它的可用性,我认为添加这几个词会增加对质谱感兴趣的人会在搜索中看到这个。)
【讨论】:
这比其他的有一个非常显着的优势。通过将间隔增加到大于 3 的值,我们可以忽略一个点恰好比它的两个最近邻点略高的情况,即使附近还有其他点更大。这对于具有小的随机变化的测量数据很有用。 感谢您的评论,感谢 dbaupp,感谢@GGrothendieck 和 Achim Zeileis 将zoo
写得如此干净,以至于我能够干净地应用它。
这是一个绝妙的解决方案,但请注意:明确定义 align
参数是个好主意。 zoo:::rollapply.zoo
默认使用align = "center"
,但xts:::rollapply.xts
使用align = "right"
。
@dleal,你在数组xz
上滚动一个宽度为 3 的窗口。这个窗口的内容是返回最大值索引的函数的参数x
。如果这个索引指向窗口的中心,那么你就停留在局部最大值上!在这种特殊情况中,窗口宽度为 3,因此中间元素的索引为 2。基本上,您正在为宽度等于 2*m–1
的窗口寻找条件 which.max(x) == m
。
虽然有趣的是,@42- 的建议在重复值多于宽度(例如 3)的情况下会失败。换句话说,鞍点会被误认为是一个极端。一个简单的例子是:x <- c(3, 2, 2, 2, 2, 1, 3)
,然后是rx <- rollapply(as.zoo(x), 3, function(x) which.min(x)==2)
,然后index(rx)[coredata(rx)]
错误地给出[1] 2 6
(应该是[1] 6
)。【参考方案4】:
提供了一些不错的解决方案,但这取决于您的需要。
只需 diff(tt)
返回差异。
您想检测何时从递增值变为递减值。 @Ben 提供了一种方法:
diff(sign(diff(tt)))==-2
这里的问题是,这只会检测立即从严格递增到严格递减的变化。
轻微的变化将允许在峰值处重复值(返回 TRUE
以表示最后一次出现的峰值):
diff(diff(x)>=0)<0
然后,如果您想在开头或结尾检测最大值,您只需正确填充前后
以下是包含在函数中的所有内容(包括寻找山谷):
which.peaks <- function(x,partial=TRUE,decreasing=FALSE)
if (decreasing)
if (partial)
which(diff(c(FALSE,diff(x)>0,TRUE))>0)
else
which(diff(diff(x)>0)>0)+1
else
if (partial)
which(diff(c(TRUE,diff(x)>=0,FALSE))<0)
else
which(diff(diff(x)>=0)<0)+1
【讨论】:
粮农组织未来的访客,我在这里尝试了一些建议的解决方案,这对我来说效果最好。【参考方案5】:我在其他地方发布了这个,但我认为这是一种有趣的方式。我不确定它的计算效率如何,但它是一种非常简洁的解决问题的方法。
vals=rbinom(1000,20,0.5)
text=paste0(substr(format(diff(vals),scientific=TRUE),1,1),collapse="")
sort(na.omit(c(gregexpr('[ ]-',text)[[1]]+1,ifelse(grepl('^-',text),1,NA),
ifelse(grepl('[^-]$',text),length(vals),NA))))
【讨论】:
简洁但经过混淆通常没有那么有用,除非它是一个需要极高效率的大公司,或者你需要尽可能不清楚的竞赛:) 愿意解释代码或主要要点吗?只是把这个奇怪的(而且不可读 - 为什么不添加一些间距?)代码扔给我们不会导致人们尝试使用它 这比其他方法效率低,但仍然有效。我认为这将属于需要不清楚的竞争。一般的想法是您将代码中的差异转换为文本并获取它的第一个字符,如果它是正数则为空格,如果为负数则为-
。如果您看到 - -
模式(或任一端点处的空格),您已找到最大值。我在 Linux 上试过这个,我使用 substr(...,2,2)
而不是 substr(...,1,1)
,因为文本有一个前导空格。正则表达式对于这个问题并不理想,但它是一个有趣的解决方案。【参考方案6】:
这是最小值的解决方案:
@Ben 的解决方案
x <- c(1,2,3,2,1,2,1)
which(diff(sign(diff(x)))==+2)+1 # 5
请注意汤米帖子中的案例!
@Tommy 的解决方案:
localMinima <- function(x)
# Use -Inf instead if x is numeric (non-integer)
y <- diff(c(.Machine$integer.max, x)) > 0L
rle(y)$lengths
y <- cumsum(rle(y)$lengths)
y <- y[seq.int(1L, length(y), 2L)]
if (x[[1]] == x[[2]])
y <- y[-1]
y
x <- c(1,2,9,9,2,1,1,5,5,1)
localMinima(x) # 1, 7, 10
x <- c(2,2,9,9,2,1,1,5,5,1)
localMinima(x) # 7, 10
x <- c(3,2,9,9,2,1,1,5,5,1)
localMinima(x) # 2, 7, 10
请注意:localMaxima
和 localMinima
都不能在开始时处理重复的最大值/最小值!
【讨论】:
不确定您的答案真正带来了什么,因为其他答案包括相同的算法。 是的,但它给出了最小值的解决方案,如最初要求的那样。另外,还没有提到开始时重复最大值/最小值的情况。 好吧......即使答案基本相同,我也无法反驳。所以我不会投反对票,但也不会投赞成票。您应该尝试回答尚未回答的问题(即使这个问题没有正式回答,前 2 个答案有 18 票和 20 票这一事实使其相同)。 顺便说一句,我可能需要帮助找到一种方法来适应具有更大间隔的最大值/最小值的函数,因此'delta x > 1'。有人有想法吗? @Sebastian 如果还没有看到,请查看我的答案以获得更大的间隔。【参考方案7】:在以前的解决方案中让位置工作时遇到了一些麻烦,我想出了一种直接获取最小值和最大值的方法。下面的代码将执行此操作并绘制它,将最小值标记为绿色,最大值标记为红色。与which.max()
函数不同,这会将最小值/最大值的所有索引拉出数据帧。零值被添加到第一个 diff()
函数中,以说明在您使用该函数时出现的结果长度缺失的缩短。将它插入到最里面的diff()
函数调用中可以避免在逻辑表达式之外添加偏移量。没关系,但我觉得这是一种更清洁的方式。
# create example data called stockData
stockData = data.frame(x = 1:30, y=rnorm(30,7))
# get the location of the minima/maxima. note the added zero offsets
# the location to get the correct indices
min_indexes = which(diff( sign(diff( c(0,stockData$y)))) == 2)
max_indexes = which(diff( sign(diff( c(0,stockData$y)))) == -2)
# get the actual values where the minima/maxima are located
min_locs = stockData[min_indexes,]
max_locs = stockData[max_indexes,]
# plot the data and mark minima with red and maxima with green
plot(stockData$y, type="l")
points( min_locs, col="red", pch=19, cex=1 )
points( max_locs, col="green", pch=19, cex=1 )
【讨论】:
几乎非常好 - 最后似乎没有最大值> histData$counts [1] 18000 0 0 0 0 0 0 0 0 0 0 0 [217] 0 0 0 0 0 0 0 0 5992max_indexes = sign(diff( c(0,histData$counts,0))))
虽然有效,但我不知道它是否会破坏其他任何东西。
@idontgetoutmuch... 该方法本质上使用数据的一阶导数计算,并且不会在被评估的系列的端点处找到相对最大值或最小值。如果这是一个相对的最大值/最小值,它将适用于该系列的倒数第二个值,因为可以在那里近似导数。如果您正在寻找系列中的最大值,则 max() 函数应该可以正常工作。将它与上面的代码结合起来应该可以得到你需要的 max/mins 信息。
我应该对我上面评论的第一句话更清楚......该方法基本上使用数据的一阶导数近似值,并且不会在端点找到相对最大值或最小值正在评估系列,因为无法知道端点是否是相对的最大/分钟。【参考方案8】:
我今天对此进行了尝试。我知道你说希望没有 for 循环,但我坚持使用 apply 函数。有点紧凑和快速,并允许阈值规范,因此您可以大于 1。
功能:
inflect <- function(x, threshold = 1)
up <- sapply(1:threshold, function(n) c(x[-(seq(n))], rep(NA, n)))
down <- sapply(-1:-threshold, function(n) c(rep(NA,abs(n)), x[-seq(length(x), length(x) - abs(n) + 1)]))
a <- cbind(x,up,down)
list(minima = which(apply(a, 1, min) == a[,1]), maxima = which(apply(a, 1, max) == a[,1]))
要使用阈值进行可视化/播放,您可以运行以下代码:
# Pick a desired threshold # to plot up to
n <- 2
# Generate Data
randomwalk <- 100 + cumsum(rnorm(50, 0.2, 1)) # climbs upwards most of the time
bottoms <- lapply(1:n, function(x) inflect(randomwalk, threshold = x)$minima)
tops <- lapply(1:n, function(x) inflect(randomwalk, threshold = x)$maxima)
# Color functions
cf.1 <- grDevices::colorRampPalette(c("pink","red"))
cf.2 <- grDevices::colorRampPalette(c("cyan","blue"))
plot(randomwalk, type = 'l', main = "Minima & Maxima\nVariable Thresholds")
for(i in 1:n)
points(bottoms[[i]], randomwalk[bottoms[[i]]], pch = 16, col = cf.1(n)[i], cex = i/1.5)
for(i in 1:n)
points(tops[[i]], randomwalk[tops[[i]]], pch = 16, col = cf.2(n)[i], cex = i/1.5)
legend("topleft", legend = c("Minima",1:n,"Maxima",1:n),
pch = rep(c(NA, rep(16,n)), 2), col = c(1, cf.1(n),1, cf.2(n)),
pt.cex = c(rep(c(1, c(1:n) / 1.5), 2)), cex = .75, ncol = 2)
【讨论】:
我喜欢threshold
似乎只会改变绘图上的点大小,但不能解决这个问题。有什么建议吗?
您好,当值绑定时,您到底期望发生什么?该功能将它们视为同一点 - 被忽略。在一座平坦的山顶上,走到哪里都是峰顶,即使中间有一道缝隙。您正在使用哪些具有相同值的数据?顺便说一句,如果相邻的高度不相同,点的变化也会不同。在阈值 = 3 处查看向量 c(0,0,0,1,0.7,3,2,3,3,2,1,1,2,3,0.7, 0.5,0,0,0)
【参考方案9】:
@42- 的回答很好,但我有一个用例我不想使用zoo
。使用dplyr
和lag
和lead
很容易实现这一点:
library(dplyr)
test = data_frame(x = sample(1:10, 20, replace = TRUE))
mutate(test, local.minima = if_else(lag(x) > x & lead(x) > x, TRUE, FALSE)
与rollapply
解决方案一样,您可以分别通过lag
/lead
参数n
和default
控制窗口大小和边缘情况。
【讨论】:
【参考方案10】:在pracma
包中,使用
tt <- c(1,2,3,2,1, 1, 2, 1)
tt_peaks <- findpeaks(tt, zero = "0", peakpat = NULL,
minpeakheight = -Inf, minpeakdistance = 1, threshold = 0, npeaks = 0, sortstr = FALSE)
[,1] [,2] [,3] [,4]
[1,] 3 3 1 5
[2,] 2 7 6 8
返回一个有 4 列的矩阵。 第一列显示局部峰值的绝对值。 第二列是索引 第 3 列和第 4 列是峰的起点和终点(可能有重叠)。
详情请见https://www.rdocumentation.org/packages/pracma/versions/1.9.9/topics/findpeaks。
一个警告:我在一系列非整数中使用了它,峰值是一个索引为时已晚(对于所有峰值),我不知道为什么。所以我不得不从我的索引向量中手动删除“1”(没什么大不了的)。
【讨论】:
【参考方案11】:聚会迟到了,但这可能会引起其他人的兴趣。您现在可以使用ggpmisc
包中的(内部)函数find_peaks
。您可以使用threshold
、span
和strict
参数对其进行参数化。由于ggpmisc
包旨在与ggplot2
一起使用,您可以使用stat_peaks
和stat_valleys
函数直接绘制minima 和maxima:
set.seed(1)
x <- 1:10
y <- runif(10)
# Maxima
x[ggpmisc:::find_peaks(y)]
[1] 4 7
y[ggpmisc:::find_peaks(y)]
[1] 0.9082078 0.9446753
# Minima
x[ggpmisc:::find_peaks(-y)]
[1] 5
y[ggpmisc:::find_peaks(-y)]
[1] 0.2016819
# Plot
ggplot(data = data.frame(x, y), aes(x = x, y = y)) + geom_line() + stat_peaks(col = "red") + stat_valleys(col = "green")
【讨论】:
【参考方案12】:找到局部最大值和最小值以获得不太容易的序列,例如1 0 1 1 2 0 1 1 0 1 1 1 0 1
我会在 (1), 5, 7.5, 11 和 (14) 给出他们的位置,最大值和最小值 2, 6, 9, 13。
#Position 1 1 1 1 1
# 1 2 3 4 5 6 7 8 9 0 1 2 3 4
x <- c(1,0,1,1,2,0,1,1,0,1,1,1,0,1) #Frequency
# p v p v p v p v p p..Peak, v..Valey
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
#Find Peaks
peakPosition(x)
#1.0 5.0 7.5 11.0 14.0
#Find Valeys
peakPosition(-x)
#2 6 9 13
peakPosition(c(1,2,3,2,1,1,2,1)) #3 7
【讨论】:
【参考方案13】:在我正在处理的情况下,重复经常发生。所以我实现了一个函数,可以找到第一个或最后一个极值(最小值或最大值):
locate_xtrem <- function (x, last = FALSE)
# use rle to deal with duplicates
x_rle <- rle(x)
# force the first value to be identified as an extrema
first_value <- x_rle$values[1] - x_rle$values[2]
# differentiate the series, keep only the sign, and use 'rle' function to
# locate increase or decrease concerning multiple successive values.
# The result values is a series of (only) -1 and 1.
#
# ! NOTE: with this method, last value will be considered as an extrema
diff_sign_rle <- c(first_value, diff(x_rle$values)) %>% sign() %>% rle()
# this vector will be used to get the initial positions
diff_idx <- cumsum(diff_sign_rle$lengths)
# find min and max
diff_min <- diff_idx[diff_sign_rle$values < 0]
diff_max <- diff_idx[diff_sign_rle$values > 0]
# get the min and max indexes in the original series
x_idx <- cumsum(x_rle$lengths)
if (last)
min <- x_idx[diff_min]
max <- x_idx[diff_max]
else
min <- x_idx[diff_min] - x_rle$lengths[diff_min] + 1
max <- x_idx[diff_max] - x_rle$lengths[diff_max] + 1
# just get number of occurences
min_nb <- x_rle$lengths[diff_min]
max_nb <- x_rle$lengths[diff_max]
# format the result as a tibble
bind_rows(
tibble(Idx = min, Values = x[min], NB = min_nb, Status = "min"),
tibble(Idx = max, Values = x[max], NB = max_nb, Status = "max")) %>%
arrange(.data$Idx) %>%
mutate(Last = last) %>%
mutate_at(vars(.data$Idx, .data$NB), as.integer)
原问题的答案是:
> x <- c(1, 2, 3, 2, 1, 1, 2, 1)
> locate_xtrem(x)
# A tibble: 5 x 5
Idx Values NB Status Last
<int> <dbl> <int> <chr> <lgl>
1 1 1 1 min FALSE
2 3 3 1 max FALSE
3 5 1 2 min FALSE
4 7 2 1 max FALSE
5 8 1 1 min FALSE
结果表明第二个最小值等于 1,并且该值从索引 5 开始重复两次。因此,通过将这个时间指示给函数以查找最后一次出现的局部极值,可以获得不同的结果:
> locate_xtrem(x, last = TRUE)
# A tibble: 5 x 5
Idx Values NB Status Last
<int> <dbl> <int> <chr> <lgl>
1 1 1 1 min TRUE
2 3 3 1 max TRUE
3 6 1 2 min TRUE
4 7 2 1 max TRUE
5 8 1 1 min TRUE
根据目标,可以在局部极值的第一个值和最后一个值之间切换。 last = TRUE
的第二个结果也可以通过列“Idx”和“NB”之间的操作获得...
最后,为了处理数据中的噪声,可以实现一个函数来消除低于给定阈值的波动。代码没有公开,因为它超出了最初的问题。我已经将它包装在一个包中(主要是为了自动化测试过程),并在下面给出一个结果示例:
x_series %>% xtrem::locate_xtrem()
x_series %>% xtrem::locate_xtrem() %>% remove_noise()
【讨论】:
不错!我有一个累积值图,因此有平坦的范围。您的解决方案是这里唯一有效的解决方案。也可以包含绘图代码。 这是一个很棒的功能!能够在重复序列中控制第一个和最后一个非常方便。【参考方案14】:Timothée Poisot 的这个函数对于嘈杂的系列很方便:
2009 年 5 月 3 日在向量中查找局部极值的算法 Filed under: Algorithm — Tags: Extrema, Time series — Timothée Poisot @ 6:46pm
我花了一些时间寻找一种算法来找到局部极值 一个向量(时间序列)。我使用的解决方案是“步行”通过 向量逐级大于1,为了甚至只保留一个值 当值非常嘈杂时(参见末尾的图片 发布)。
事情是这样的:
findpeaks <- function(vec,bw=1,x.coo=c(1:length(vec)))
pos.x.max <- NULL
pos.y.max <- NULL
pos.x.min <- NULL
pos.y.min <- NULL for(i in 1:(length(vec)-1)) if((i+1+bw)>length(vec))
sup.stop <- length(vec)elsesup.stop <- i+1+bw
if((i-bw)<1)inf.stop <- 1elseinf.stop <- i-bw
subset.sup <- vec[(i+1):sup.stop]
subset.inf <- vec[inf.stop:(i-1)]
is.max <- sum(subset.inf > vec[i]) == 0
is.nomin <- sum(subset.sup > vec[i]) == 0
no.max <- sum(subset.inf > vec[i]) == length(subset.inf)
no.nomin <- sum(subset.sup > vec[i]) == length(subset.sup)
if(is.max & is.nomin)
pos.x.max <- c(pos.x.max,x.coo[i])
pos.y.max <- c(pos.y.max,vec[i])
if(no.max & no.nomin)
pos.x.min <- c(pos.x.min,x.coo[i])
pos.y.min <- c(pos.y.min,vec[i])
return(list(pos.x.max,pos.y.max,pos.x.min,pos.y.min))
Link to original blog post
【讨论】:
我喜欢这个功能。它提供了一种确定信封的好方法。【参考方案15】:我们在这里看到了许多具有不同功能的不错的功能和想法。几乎所有示例的一个问题是效率。很多时候,我们看到使用像diff()
或for()
-loops 这样的复杂函数,当涉及到大型数据集时,它们会变得很慢。让我介绍一个我每天都在使用的高效功能,功能最少,但速度非常快:
局部最大值函数amax()
目的是检测实值向量中的所有局部最大值。
如果第一个元素x[1]
是全局最大值,则忽略它,
因为没有关于前一个元素的信息。如果有
是一个平台,第一个边缘被检测到。
@param x 数值向量
@return 返回局部最大值的指标。如果x[1] = max
,那么
它被忽略了。
amax <- function(x)
a1 <- c(0,x,0)
a2 <- c(x,0,0)
a3 <- c(0,0,x)
e <- which((a1 >= a2 & a1 > a3)[2:(length(x))])
if(!is.na(e[1] == 1))
if(e[1]==1)
e <- e[-1]
if(length(e) == 0) e <- NaN
return (e)
a <- c(1,2,3,2,1,5,5,4)
amax(a) # 3, 6
【讨论】:
【参考方案16】:@BEN 提出的公式和@TOMMY 提出的案例的增强(快速而简单的方法):
以下递归公式可以处理任何情况:
dx=c(0,sign(diff(x)))
numberofzeros= length(dx) - sum(abs(dx)) -1 # to find the number of zeros
# in the dx minus the first one
# which is added intentionally.
#running recursive formula to clear middle zeros
# iterate for the number of zeros
for (i in 1:numberofzeros)
dx = sign(2*dx + c(0,rev(sign(diff(rev(dx))))))
现在,只需稍加改动即可使用@Ben Bolker 提供的公式:
plot(x)
points(which(diff(dx)==2),x[which(diff(dx)==2)],col = 'blue')#Local MIN.
points(which(diff(dx)==-2),x[which(diff(dx)==-2)],col = 'red')#Local MAX.
【讨论】:
以上是关于寻找局部最大值和最小值的主要内容,如果未能解决你的问题,请参考以下文章
Python/Pandas- 在趋势变化时应用标签(识别数据集中的局部最大值和最小值)