Esta es la contestación más correcta que te podemos aportar, pero mírala pausadamente y valora si se puede adaptar a tu proyecto.
Solución:
La solución que ofrece fuglede es excelente, pero si sus datos son muy ruidosos (como el de la imagen), terminará con muchos extremos locales engañosos. Te sugiero que uses scipy.signal.argrelextrema()
método. los .argrelextrema()
El método tiene sus propias limitaciones, pero tiene una característica útil en la que puede especificar el número de puntos que se compararán, algo así como un algoritmo de filtrado de ruido. por ejemplo:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from scipy.signal import argrelextrema
# Generate a noisy AR(1) sample
np.random.seed(0)
rs = np.random.randn(200)
xs = [0]
for r in rs:
xs.append(xs[-1] * 0.9 + r)
df = pd.DataFrame(xs, columns=['data'])
n = 5 # number of points to be checked before and after
# Find local peaks
df['min'] = df.iloc[argrelextrema(df.data.values, np.less_equal,
order=n)[0]]['data']
df['max'] = df.iloc[argrelextrema(df.data.values, np.greater_equal,
order=n)[0]]['data']
# Plot results
plt.scatter(df.index, df['min'], c='r')
plt.scatter(df.index, df['max'], c='g')
plt.plot(df.index, df['data'])
plt.show()
Algunos puntos:
- es posible que deba verificar los puntos después para asegurarse de que no haya puntos de hilo muy cerca uno del otro.
- puedes jugar con
n
para filtrar los puntos ruidosos argrelextrema
devuelve una tupla y la[0]
al final extrae unnumpy
array
Suponiendo que la columna de interés está etiquetada data
una solución sería
df['min'] = df.data[(df.data.shift(1) > df.data) & (df.data.shift(-1) > df.data)]
df['max'] = df.data[(df.data.shift(1) < df.data) & (df.data.shift(-1) < df.data)]
Por ejemplo:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# Generate a noisy AR(1) sample
np.random.seed(0)
rs = np.random.randn(200)
xs = [0]
for r in rs:
xs.append(xs[-1]*0.9 + r)
df = pd.DataFrame(xs, columns=['data'])
# Find local peaks
df['min'] = df.data[(df.data.shift(1) > df.data) & (df.data.shift(-1) > df.data)]
df['max'] = df.data[(df.data.shift(1) < df.data) & (df.data.shift(-1) < df.data)]
# Plot results
plt.scatter(df.index, df['min'], c='r')
plt.scatter(df.index, df['max'], c='g')
df.data.plot()
usando numpy
ser = np.random.randint(-40, 40, 100) # 100 points
peak = np.where(np.diff(ser) < 0)[0]
o
double_difference = np.diff(np.sign(np.diff(ser)))
peak = np.where(double_difference == -2)[0]
usando pandas
ser = pd.Series(np.random.randint(2, 5, 100))
peak_df = ser[(ser.shift(1) < ser) & (ser.shift(-1) < ser)]
peak = peak_df.index
Calificaciones y reseñas
Si conservas algún reparo y disposición de reaccionar nuestro escrito puedes añadir una nota y con deseo lo observaremos.