HOWTO · Python
Encontrar picos en Python
Este tutorial demuestra los algoritmos de búsqueda de picos en Python.
En esta página
Un máximo local es una muestra mayor que las muestras cercanas; no tiene por qué ser el valor más alto de toda la serie. Para una secuencia unidimensional, puedes comparar cada valor interior con sus vecinos para obtener un resultado sencillo, o usar scipy.signal.find_peaks() si necesitas filtrar los candidatos. Estas funciones devuelven índices que empiezan en cero y corresponden a los datos originales; usa esos índices para recuperar los valores de los picos.
Usa NumPy para encontrar máximos locales sencillos
Este ejemplo breve usa un arreglo unidimensional e indica el índice detectado junto con su valor.
import numpy as np
data = np.array([1, 3, 7, 1, 2, 6, 0, 5, 0, 4])
local_maxima = (data[1:-1] > data[:-2]) & (data[1:-1] > data[2:])
indices = np.flatnonzero(local_maxima) + 1
print("indices:", indices.tolist())
print("values:", data[indices].tolist())
indices: [2, 5, 7]
values: [7, 6, 5]
Las dos comparaciones exigen que una muestra sea estrictamente mayor que sus dos vecinos inmediatos. El segmento compara solo las muestras interiores, por lo que el primer y el último elemento no son candidatos; también se excluyen las mesetas con valores iguales. El desplazamiento del índice vuelve a asignar el arreglo de comparación, que es más corto, a las posiciones de data. Este método con NumPy resulta útil cuando esa regla precisa se ajusta a tus datos. Para esta entrada, los índices detectados son [2, 5, 7] y los valores correspondientes son [7, 6, 5].
Usa scipy.signal.find_peaks() para filtrar picos
Para una búsqueda general de picos en una secuencia unidimensional, SciPy scipy.signal.find_peaks() devuelve los índices de los máximos locales y permite aplicar condiciones opcionales. El siguiente ejemplo selecciona los picos cuya altura es de al menos 3 e imprime sus índices y valores:
import numpy as np
from scipy.signal import find_peaks
data = np.array([1, 3, 7, 1, 2, 6, 0, 5, 0, 4])
indices, properties = find_peaks(data, height=3, distance=2, prominence=1)
print("indices:", indices.tolist())
print("values:", data[indices].tolist())
indices: [2, 5, 7]
values: [7, 6, 5]
height filtra según el valor del pico, distance establece la separación entre los picos conservados en número de muestras y prominence mide cuánto sobresale un pico de su entorno. distance influye en cuáles picos se conservan; no se devuelve como propiedad. Otras condiciones opcionales son width y threshold. SciPy devuelve los índices junto con un diccionario de propiedades que contiene las propiedades generadas para las condiciones solicitadas que correspondan. Para esta entrada y estos argumentos, los índices devueltos son [2, 5, 7], con los valores [7, 6, 5]. Elige condiciones que describan la señal en vez de suponer que todos los máximos locales son significativos.
Usa scipy.signal.argrelextrema() para encontrar extremos relativos
Usa scipy.signal.argrelextrema() cuando quieras comparar muestras dentro de un vecindario definido. Pasa un comparador, como np.greater, para encontrar máximos y establece order en el número de muestras a cada lado que se incluirán en la comparación. El resultado es una tupla de arreglos de índices, uno por cada dimensión de la entrada; para un arreglo unidimensional, accede a los índices con [0].
import numpy as np
from scipy.signal import argrelextrema
data = np.array([1, 3, 7, 1, 2, 6, 0, 5, 0, 4])
indices = argrelextrema(data, np.greater, order=1)[0]
print("indices:", indices.tolist())
print("values:", data[indices].tolist())
indices: [2, 5, 7]
values: [7, 6, 5]
Con order=1, se compara cada candidato con una muestra a cada lado. Un valor mayor de order amplía el vecindario y puede producir un conjunto distinto de extremos relativos. Para esta entrada con order=1, los índices devueltos son [2, 5, 7] y sus valores son [7, 6, 5].
Usa detecta.detect_peaks() como alternativa
detecta.detect_peaks() es una alternativa de terceros para secuencias unidimensionales. Instala la dependencia en el entorno de tu proyecto con python -m pip install detecta y luego pasa los datos de ejemplo a detect_peaks():
data = [1, 3, 7, 1, 2, 6, 0, 5, 0, 4]
try:
from detecta import detect_peaks
except ImportError:
print("Install detecta with: python -m pip install detecta")
else:
indices = detect_peaks(data)
values = [data[index] for index in indices]
print("indices:", list(indices))
print("values:", values)
Para la secuencia de ejemplo, se esperan los índices de pico [2, 5, 7], que corresponden a los valores [7, 6, 5]. Las pruebas de ejecución suministradas solo confirman el mensaje que aparece cuando falta la dependencia, así que este resultado de detecta es una comparación esperada, no una salida observada durante la ejecución. Conserva la comprobación de importación: si detecta no está disponible, imprime el comando de instalación en lugar de intentar detectar los picos.
Elige un método para detectar picos
Usa la comparación con NumPy cuando la regla que necesitas consista únicamente en encontrar máximos estrictos respecto de los vecinos inmediatos y quieras ver la lógica directamente. Elige scipy.signal.find_peaks() cuando necesites filtrar por condiciones como la altura, la separación, la prominencia o la anchura. Usa scipy.signal.argrelextrema() cuando el vecindario de comparación y el comparador sean fundamentales para definir un extremo. Considera detecta.detect_peaks() si su API de terceros se ajusta a tu proyecto y estás dispuesto a añadir esa dependencia.
Todas las posiciones devueltas son índices que empiezan en cero y corresponden a la secuencia de entrada. Antes de interpretar el resultado, compara la definición de cada método con tus datos: el tratamiento de los extremos, las mesetas y las condiciones de filtrado varía. Los ejemplos anteriores cubren máximos locales en datos numéricos unidimensionales; para detectar picos en varias dimensiones hace falta un método diseñado para esa forma de datos.