Aquí está mi experimento:
Estoy usando la findPeaks
función en el paquete quantmod :
Quiero detectar picos "locales" dentro de una tolerancia 5, es decir, las primeras ubicaciones después de que la serie temporal caiga de los picos locales en 5:
aa=100:1
bb=sin(aa/3)
cc=aa*bb
plot(cc, type="l")
p=findPeaks(cc, 5)
points(p, cc[p])
p
La salida es
[1] 3 22 41
Parece incorrecto, ya que espero más "picos locales" que 3 ...
¿Alguna idea?
r
time-series
Luna
fuente
fuente
findPeaks
aparece en mi respuesta, @Adam. Por cierto, el paquete es "quantmod" .Respuestas:
La fuente de este código se obtiene escribiendo su nombre en el indicador R. La salida es
La prueba
x[pks - 1] - x[pks] > thresh
compara cada valor máximo con el valor que le sucede inmediatamente en la serie (no con el siguiente canal de la serie). Utiliza una estimación (cruda) del tamaño de la pendiente de la función inmediatamente después del pico y selecciona solo aquellos picos donde esa pendiente excede elthresh
tamaño. En su caso, solo los primeros tres picos son lo suficientemente afilados para pasar la prueba. Detectará todos los picos utilizando el valor predeterminado:fuente
Estoy de acuerdo con la respuesta de Whuber, pero solo quería agregar que la porción "+2" del código, que intenta cambiar el índice para que coincida con el pico recientemente encontrado, en realidad 'se sobrepasa' y debería ser "+1". por ejemplo en el ejemplo en cuestión obtenemos:
cuando resaltamos estos picos encontrados en un gráfico (rojo negrita):
vemos que están consistentemente a 1 punto del pico real.
consecuentemente
debería ser
pks[x[pks] - x[pks + 1] > thresh]
opks[x[pks] - x[pks - 1] > thresh]
GRAN ACTUALIZACIÓN
siguiendo mi propia búsqueda para encontrar una función adecuada de búsqueda de picos escribí esto:
un "pico" se define como un máximo local con
m
puntos a cada lado de él más pequeños que él. por lo tanto, cuanto más grande es el parámetrom
, más estricto es el procedimiento de financiamiento máximo. entonces:la función también se puede usar para encontrar mínimos locales de cualquier vector secuencial a
x
través defind_peaks(-x)
.Nota: ahora he puesto la función en gitHub si alguien lo necesita: https://github.com/stas-g/findPeaks
fuente
Eek: actualización menor. Tuve que cambiar dos líneas de código, los límites, (agregar un -1 y +1) para alcanzar la equivalencia con la función de Stas_G (estaba encontrando demasiados 'picos adicionales' en conjuntos de datos reales). Las disculpas por cualquier persona conducen muy mal por mi publicación original.
He estado usando el algoritmo de búsqueda de picos de Stas_g desde hace bastante tiempo. Fue beneficioso para uno de mis proyectos posteriores debido a su simplicidad. Sin embargo, necesitaba usarlo millones de veces para un cálculo, así que lo reescribí en Rcpp (Ver paquete Rcpp). Es aproximadamente 6 veces más rápido que la versión R en pruebas simples. Si alguien está interesado, he agregado el código a continuación. Espero ayudar a alguien, ¡salud!
Algunas advertencias menores. Esta función devuelve índices de pico en orden inverso al código R. Requiere una función de signo C ++ interna, que incluí. No se ha optimizado por completo, pero no se esperan más ganancias de rendimiento.
fuente
for(q = lb; q < rb; ++q){ if(vY(q) > vY(i+1)){ isGreatest = false; } }
como la última carrera a través de los "gana" bucle, haciendo el equivalente a:isGreatest = vY(rb-1) <= vY(rb)
. Para lograr lo que dice el comentario justo por encima de esa línea, el ciclo for debería cambiarse a:for(q = lb; isGreatest && (q < rb); ++q){ isGreatest = (vY(q) <= vY(i+1)) }
En primer lugar: el algoritmo también llama falsamente una caída a la derecha de una meseta plana, ya
sign(diff(x, na.pad = FALSE))
que será 0 y -1, por lo que su diferencia también será -1. Una solución simple es garantizar que el signo-diff que precede a la entrada negativa no sea cero sino positivo:Segundo: el algoritmo da resultados muy locales, por ejemplo, un 'arriba' seguido de un 'abajo' en cualquier ejecución de tres términos consecutivos en la secuencia. Si uno está interesado en los máximos locales de una función continua con ruido, entonces, probablemente haya otras cosas mejores, pero esta es mi solución económica e inmediata.
suavizar los datos muy ligeramente. Emplee también el control mencionado anteriormente contra el plano y luego la caída.
filtre estos candidatos comparando, para una versión suavizada de loess, el promedio dentro de una ventana centrada en cada pico con el promedio de los términos locales afuera.
fuente
Es cierto que la función también identifica el final de las mesetas, pero creo que hay otra solución más fácil: dado que la primera diferencia de un pico real dará como resultado '1' y luego '-1', la segunda diferencia sería '-2', y podemos verificar directamente
fuente
usando Numpy
o
usando pandas
fuente