Si j'ai un ensemble de données qui produit un graphique tel que celui-ci, comment pourrais-je déterminer par un algorithme les valeurs x des pics affichés (dans ce cas, trois d'entre elles):
Si j'ai un ensemble de données qui produit un graphique tel que celui-ci, comment pourrais-je déterminer par un algorithme les valeurs x des pics affichés (dans ce cas, trois d'entre elles):
Réponses:
Une approche générale consiste à lisser les données , puis à rechercher les pics en comparant un filtre maximum local au filtre lisse . Dans R
:
argmax <- function(x, y, w=1, ...) {
require(zoo)
n <- length(y)
y.smooth <- loess(y ~ x, ...)$fitted
y.max <- rollapply(zoo(y.smooth), 2*w+1, max, align="center")
delta <- y.max - y.smooth[-c(1:w, n+1-1:w)]
i.max <- which(delta <= 0) + w
list(x=x[i.max], i=i.max, y.hat=y.smooth)
}
Sa valeur de retour inclut les arguments des maxima locaux ( x
) - qui répondent à la question - et les index dans les tableaux x et y où ces maxima locaux se produisent ( i
).
Deux paramètres doivent être adaptés aux circonstances: w
la demi-largeur de la fenêtre utilisée pour calculer le maximum local. (Sa valeur doit être sensiblement inférieure à la moitié de la longueur du tableau de données.) De petites valeurs captureront de petites bosses locales alors que des valeurs plus grandes les transmettront directement. Un autre - non explicite dans ce code - est l’ span
argument du loess
plus lisse. (Elle est généralement comprise entre zéro et un; elle reflète la largeur de la fenêtre sous forme de proportion de la plage de valeurs x). Des valeurs plus grandes lisseront les données de manière plus agressive, faisant disparaître complètement les bosses locales.
Pour voir cet accord effectif, créons une petite fonction de test pour tracer les résultats:
test <- function(w, span) {
peaks <- argmax(x, y, w=w, span=span)
plot(x, y, cex=0.75, col="Gray", main=paste("w = ", w, ", span = ", span, sep=""))
lines(x, peaks$y.hat, lwd=2) #$
y.min <- min(y)
sapply(peaks$i, function(i) lines(c(x[i],x[i]), c(y.min, peaks$y.hat[i]),
col="Red", lty=2))
points(x[peaks$i], peaks$y.hat[peaks$i], col="Red", pch=19, cex=1.25)
}
Voici quelques expériences appliquées à des données synthétiques légèrement bruitées.
x <- 1:1000 / 100 - 5
y <- exp(abs(x)/20) * sin(2 * x + (x/5)^2) + cos(10*x) / 5 + rnorm(length(x), sd=0.05)
par(mfrow=c(3,1))
test(2, 0.05)
test(30, 0.05)
test(2, 0.2)
Une fenêtre large (tracé du milieu) ou plus agressive (tracé du bas) éliminent les maxima locaux détectés dans le tracé du haut. La meilleure combinaison est probablement une fenêtre large et un lissage doux uniquement, car un lissage agressif semble déplacer ces pics (voir les points au centre et à droite du graphique du bas et comparer leurs emplacements aux pics apparents des données brutes). Dans cet exemple, w=50
et span=0.05
fait un excellent travail (non illustré).
Notez que les maxima locaux aux points finaux ne sont pas détectés. Ceux-ci peuvent être inspectés séparément. (Pour supporter ceci, argmax
retourne les valeurs y lissées.)
Cette approche présente plusieurs avantages par rapport à la modélisation plus formelle pour les travaux généraux:
Il n’adopte aucun modèle préconçu des données.
Il peut être adapté aux caractéristiques des données.
Il peut être adapté pour détecter les types de pics auxquels on s'intéresse.
w
et span
, mais aussi pour découvrir que des valeurs plus élevées de span
décalaient les pics. On a l'impression que même ces étapes pourraient être automatisées. Par exemple, pour le premier numéro, si nous pouvions évaluer la qualité des pics découverts, nous pourrions utiliser optimize
les paramètres! Pour le deuxième problème, par exemple, choisissez une fenêtre de part et d'autre du pic découvert et recherchez des valeurs plus élevées.
Comme je l'ai mentionné dans un commentaire, si la série temporelle semble être une adaptation périodique, un modèle de régression harmonique permet de lisser la fonction et d'identifier le pic en appliquant les tests de la première et de la seconde dérivées. Huber a souligné un test non paramétrique qui présente des avantages lorsqu'il existe plusieurs pics et que la fonction n'est pas nécessairement périodique. Mais il n'y a pas de repas gratuit. Bien que sa méthode présente certains avantages, il mentionne qu'il peut y avoir des inconvénients si un modèle paramétrique convient. C'est toujours le revers de l'utilisation de techniques non paramétriques. Bien qu'elle évite les hypothèses paramétriques, l'approche paramétrique est préférable lorsque les hypothèses paramétriques sont appropriées. Sa procédure ne tire pas non plus pleinement parti de la structure des séries chronologiques dans les données.
Je pense que s'il convient de souligner les avantages d'une procédure suggérée, il est également important de souligner les inconvénients potentiels. Mon approche et celle de Huber trouvent les pics de manière efficace. Cependant, je pense que sa procédure demande un peu plus de travail lorsqu'un maximum local est inférieur au pic le plus haut déterminé précédemment.
Une approche classique de détection de pic dans le traitement du signal est la suivante:
Une autre approche qui fonctionne consiste à comparer un signal filtré nettement passe-haut à un signal fortement lissé (filtre passe-bas ou médian) et à appliquer l'étape 3.
J'espère que cela t'aides.