Pouvez-vous suggérer une fonction de module de numpy / scipy qui peut trouver des maxima / minima locaux dans un tableau numpy 1D? De toute évidence, l'approche la plus simple qui soit consiste à jeter un coup d'œil aux voisins les plus proches, mais j'aimerais avoir une solution acceptée qui fasse partie de la distribution numpy.
116
Réponses:
Si vous recherchez toutes les entrées du tableau 1d
a
plus petites que leurs voisins, vous pouvez essayerVous pouvez également lisser votre tableau avant cette étape en utilisant
numpy.convolve()
.Je ne pense pas qu'il y ait une fonction dédiée à cela.
la source
<
par>
vous donnera les maxima locaux au lieu des minima[False False]
Quel pourrait être le problème ici?Dans SciPy> = 0,11
Produit
Notez que ce sont les indices de x qui sont locaux max / min. Pour obtenir les valeurs, essayez:
scipy.signal
fournit égalementargrelmax
etargrelmin
pour trouver respectivement des maxima et des minima.la source
np.random.random(12)
génère 12 valeurs aléatoires, elles sont utilisées pour démontrer la fonctionargrelextrema
.test02=np.array([10,4,4,4,5,6,7,6])
, cela ne fonctionne pas. Il ne reconnaît pas les valeurs consécutives comme des minima locaux.Pour les courbes sans trop de bruit, je recommande le petit extrait de code suivant:
Le
+1
est important, cardiff
réduit le numéro d'index d'origine.la source
[1, 2, 2, 3, 3, 3, 2, 2, 1]
, les maxima locaux sont évidemment quelque part entre les 3 au milieu. Mais si vous exécutez les fonctions que vous avez fournies, vous obtenez des maximas aux indices 2,6 et des minimas aux indices 1,3,5,7, ce qui pour moi n'a pas beaucoup de sens.+1
au lieu de l'np.diff()
utilisernp.gradient()
.Une autre approche (plus de mots, moins de code) qui peut aider:
Les emplacements des maxima et minima locaux sont également les emplacements des passages par zéro de la première dérivée. Il est généralement beaucoup plus facile de trouver des passages à zéro que de trouver directement les maxima et minima locaux.
Malheureusement, la première dérivée a tendance à "amplifier" le bruit, de sorte que lorsqu'un bruit significatif est présent dans les données d'origine, la première dérivée n'est mieux utilisée qu'après que les données d'origine ont subi un certain degré de lissage.
Étant donné que le lissage est, dans le sens le plus simple, un filtre passe-bas, le lissage est souvent mieux (enfin, le plus facilement) effectué en utilisant un noyau de convolution, et "façonner" ce noyau peut fournir une quantité surprenante de capacités de préservation / amélioration des fonctionnalités . Le processus de recherche d'un noyau optimal peut être automatisé en utilisant une variété de moyens, mais le meilleur peut être une simple force brute (très rapide pour trouver de petits noyaux). Un bon noyau déformera (comme prévu) massivement les données originales, mais n'affectera PAS l'emplacement des pics / vallées d'intérêt.
Heureusement, assez souvent, un noyau approprié peut être créé via un simple SWAG ("supposé instruit"). La largeur du noyau de lissage doit être un peu plus large que le pic "intéressant" le plus large attendu dans les données d'origine, et sa forme ressemblera à ce pic (une ondelette à échelle unique). Pour les noyaux préservant la moyenne (ce que tout bon filtre de lissage devrait être), la somme des éléments du noyau doit être exactement égale à 1,00, et le noyau doit être symétrique par rapport à son centre (ce qui signifie qu'il aura un nombre impair d'éléments.
Étant donné un noyau de lissage optimal (ou un petit nombre de noyaux optimisés pour différents contenus de données), le degré de lissage devient un facteur d'échelle pour (le «gain») du noyau de convolution.
La détermination du degré "correct" (optimal) de lissage (gain du noyau de convolution) peut même être automatisée: Comparez l'écart type des premières données dérivées avec l'écart type des données lissées. Comment le rapport des deux écarts types change avec les changements du degré de came de lissage être utilisé pour prédire les valeurs de lissage efficaces. Quelques exécutions manuelles de données (qui sont vraiment représentatives) devraient suffire.
Toutes les solutions précédentes publiées ci-dessus calculent la première dérivée, mais elles ne la traitent pas comme une mesure statistique, et les solutions ci-dessus n'essaient pas non plus d'effectuer un lissage préservant / améliorant la fonctionnalité (pour aider les pics subtils à "sauter au-dessus" du bruit).
Enfin, la mauvaise nouvelle: trouver de "vrais" pics devient une douleur royale lorsque le bruit a également des caractéristiques qui ressemblent à de vrais pics (bande passante qui se chevauchent). La solution suivante plus complexe consiste généralement à utiliser un noyau de convolution plus long (une «ouverture de noyau plus large») qui prend en compte la relation entre les pics «réels» adjacents (tels que les taux minimum ou maximum d'occurrence de pic), ou d'utiliser plusieurs la convolution passe en utilisant des noyaux de largeurs différentes (mais seulement si elle est plus rapide: c'est une vérité mathématique fondamentale que les convolutions linéaires exécutées en séquence peuvent toujours être convolutionnées ensemble en une seule convolution). Mais il est souvent beaucoup plus facile de trouver d'abord une séquence de noyaux utiles (de largeurs variables) et de les convoluer ensemble que de trouver directement le noyau final en une seule étape.
Espérons que cela fournisse suffisamment d'informations pour permettre à Google (et peut-être un bon texte de statistiques) de combler les lacunes. J'aurais vraiment aimé avoir le temps de fournir un exemple travaillé, ou un lien vers un. Si quelqu'un en trouve un en ligne, veuillez le poster ici!
la source
Depuis la version 1.1 de SciPy, vous pouvez également utiliser find_peaks . Voici deux exemples tirés de la documentation elle-même.
En utilisant l'
height
argument, on peut sélectionner tous les maxima au-dessus d'un certain seuil (dans cet exemple, tous les maxima non négatifs; cela peut être très utile si l'on doit traiter une ligne de base bruyante; si vous voulez trouver des minima, multipliez simplement votre entrée par-1
):Un autre argument extrêmement utile est
distance
, qui définit la distance minimale entre deux pics:la source
Pourquoi ne pas utiliser la fonction intégrée signal.find_peaks_cwt de Scipy pour faire le travail?
résultats:
Cordialement
la source
Mise à jour: je n'étais pas satisfait du dégradé, donc je l'ai trouvé plus fiable à utiliser
numpy.diff
. S'il vous plaît laissez-moi savoir s'il fait ce que vous voulez.En ce qui concerne la question du bruit, le problème mathématique est de localiser les maxima / minima si nous voulons regarder le bruit, nous pouvons utiliser quelque chose comme convolve qui a été mentionné précédemment.
la source
Alors que cette question est vraiment ancienne. Je pense qu'il existe une approche beaucoup plus simple dans numpy (une ligne unique).
Pour trouver un max ou un min local, nous voulons essentiellement savoir quand la différence entre les valeurs de la liste (3-1, 9-3 ...) passe de positive à négative (max) ou négative à positive (min). Par conséquent, nous trouvons d'abord la différence. Ensuite, nous trouvons le signe, puis nous trouvons les changements de signe en reprenant la différence. (Un peu comme une première et une deuxième dérivée dans le calcul, seulement nous avons des données discrètes et n'avons pas de fonction continue.)
La sortie dans mon exemple ne contient pas les extrema (les première et dernière valeurs de la liste). De plus, tout comme le calcul, si la deuxième dérivée est négative, vous avez max, et si elle est positive, vous avez un min.
Ainsi, nous avons le match suivant:
la source
Aucune de ces solutions n'a fonctionné pour moi car je voulais également trouver des pics au centre des valeurs répétitives. par exemple, dans
ar = np.array([0,1,2,2,2,1,3,3,3,2,5,0])
la réponse devrait être
Je l'ai fait en utilisant une boucle. Je sais que ce n'est pas super propre, mais ça fait le travail.
la source
minm
etmaxm
contiennent des indices de minima et de maxima, respectivement. Pour un énorme ensemble de données, cela donnera beaucoup de maximas / minimas, donc dans ce cas, lissez d'abord la courbe, puis appliquez cet algorithme.la source
Une autre solution utilisant essentiellement un opérateur dilaté:
et pour les minima:
De plus,
scipy.ndimage
vous pouvez remplacerrank_filter(x, -1, size=3)
pargrey_dilation
etrank_filter(x, 0, size=3)
pargrey_erosion
. Cela ne nécessitera pas de tri local, donc c'est légèrement plus rapide.la source
Un autre:
la source