J'ai un pandas trame de données avec deux colonnes l'une est la température l'autre est le temps.
Je voudrais faire des troisième et quatrième colonnes appelées min et max. Chacune de ces colonnes serait remplie de nan sauf s'il y a un min ou un max local, alors elle aurait la valeur de cet extrema.
Voici un échantillon de ce à quoi ressemblent les données, essentiellement j'essaie d'identifier tous les pics et les points bas de la figure.
Existe-t-il des outils intégrés avec pandas qui peuvent accomplir cela?
En supposant que la colonne d'intérêt est étiquetée data
, une solution serait
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)]
Par exemple:
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()
La solution offerte par fuglede est génial mais si vos données sont très bruyantes (comme celle de l'image) vous vous retrouverez avec beaucoup d'exterminations locales trompeuses. Je vous suggère d'utiliser scipy.signal.argrelextrema
une fonction. argrelextrema
a ses propres limites mais il a une fonctionnalité intéressante où vous pouvez spécifier le nombre de points à comparer, un peu comme un algorithme de filtrage du bruit. par exemple:
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()
Quelques points:
n
pour filtrer les points bruyantsargrelextrema
renvoie un Tuple et le [0]
à la fin extrait un tableau numpy