82 votes

Recherche de maxima et minima locaux

Je cherche un moyen efficace de trouver les maxima/minima locaux pour une grande liste de nombres dans R. J'espère qu'il n'y aura pas de for boucles...

Par exemple, si j'ai un fichier de données comme 1 2 3 2 1 1 2 1 Je veux que la fonction renvoie 3 et 7, qui sont les positions des maxima locaux.

1voto

lokxs Points 69

Dans le cadre de la pracma utiliser le paquet

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

Cela renvoie une matrice à 4 colonnes. La première colonne indique les valeurs absolues des pics locaux. La deuxième colonne indique les indices Les 3ème et 4ème colonnes sont le début et la fin des pics (avec un chevauchement potentiel).

Voir https://www.rdocumentation.org/packages/pracma/versions/1.9.9/topics/findpeaks pour plus de détails.

Une mise en garde : je l'ai utilisé dans une série de nombres non entiers, et le pic était en retard d'un indice (pour tous les pics) et je ne sais pas pourquoi. J'ai donc dû supprimer manuellement "1" de mon vecteur d'index (ce n'est pas grave).

1voto

GKi Points 6744

Recherche maxima et minima locaux pour une séquence moins facile, par exemple 1 0 1 1 2 0 1 1 0 1 1 1 0 1 Je donnerais leurs positions à (1), 5, 7,5, 11 et (14) pour les maxima et à 2, 6, 9, 13 pour les minima.

#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

1voto

Seily Points 371

Nous voyons ici de nombreuses fonctions et idées intéressantes avec différentes caractéristiques. L'un des problèmes rencontrés dans presque tous les exemples est l'efficacité. Nous voyons souvent l'utilisation de fonctions complexes telles que diff() o for() -qui deviennent lentes lorsqu'il s'agit de grands ensembles de données. Permettez-moi de vous présenter une fonction efficace que j'utilise tous les jours, avec un minimum de fonctionnalités, mais très rapide :

Fonction de maxima locaux amax()

L'objectif est de détecter tous les maxima locaux dans un vecteur à valeur réelle. Si le premier élément x[1] est le maximum global, il est ignoré, car il n'y a pas d'information sur l'élément précédent. S'il y a plateau, le premier bord est détecté.

@param x numeric vector

@return renvoie les indices des maxima locaux. Si x[1] = max alors il est ignoré.

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

0voto

user1362215 Points 636

J'ai déjà posté cette question ailleurs, mais je pense qu'il s'agit d'une façon intéressante de procéder.

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

3 votes

Concis mais obscurci n'est généralement pas aussi utile, à moins qu'il ne s'agisse d'une grande entreprise qui a besoin d'une efficacité extrême ou d'un concours où vous devez être aussi peu clair que possible :) Vous pouvez expliquer le code ou l'essentiel ? Le fait de nous balancer ce code bizarre (et illisible - pourquoi ne pas ajouter des espaces ?) comme ça n'incitera pas les gens à l'utiliser

1 votes

Cette méthode est plus inefficace que les autres, mais elle fonctionne quand même. Je pense qu'il s'agit là d'une question qui doit être clarifiée. L'idée générale est de convertir les différences de code en texte et de prendre le premier caractère de celui-ci, qui est soit un espace s'il est positif, soit un - s'il est négatif. Si vous voyez un - - (ou un espace à l'une des extrémités), vous avez trouvé un maximum. J'ai essayé cela sous Linux, et j'ai utilisé substr(...,2,2) au lieu de substr(...,1,1) puisqu'il y a un espace avant le texte. Les expressions régulières ne sont pas idéales pour ce problème, mais c'est une solution amusante.

0voto

Une amélioration (méthode simple et rapide) de la formule proposée par @BEN et concernant les cas proposés par @TOMMY :

la formule récursive suivante s'applique dans tous les cas :

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

Maintenant, la formule fournie par @Ben Bolker peut être utilisée avec un petit changement :

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.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X