Pandas encontrando local max y min

Tengo un dataframe de pandas con dos columnas, una es la temperatura y la otra es el tiempo.

Me gustaría hacer las columnas tercera y cuarta llamadas min y max. Cada una de estas columnas se rellenaría con la de nan, excepto cuando hay un mínimo local o máximo, entonces tendría el valor de ese extremo.

Aquí hay una muestra de cómo se ven los datos, esencialmente estoy tratando de identificar todos los picos y puntos bajos en la figura.

introduzca la descripción de la imagen aquí

¿Hay alguna herramienta integrada con pandas que pueda lograr esto?

Suponiendo que la columna de interés esté etiquetada como 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() 

introduzca la descripción de la imagen aquí

La solución ofrecida por fuglede es excelente, pero si sus datos son muy ruidosos (como el que se muestra en la imagen), terminará con muchos exterminios locales engañosos. Le sugiero que use la función scipy.signal.argrelextrema . argrelextrema tiene sus propias limitaciones, pero tiene una característica interesante 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() 

introduzca la descripción de la imagen aquí

Algunos puntos:

  • Es posible que deba verificar los puntos luego para asegurarse de que no haya puntos muy cerca uno del otro.
  • Puedes jugar con n para filtrar los puntos ruidosos.
  • argrelextrema devuelve una tupla y el [0] al final extrae una matriz numpy