web-dev-qa-db-fra.com

Pandas recherche locale max et min

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.

enter image description here

Existe-t-il des outils intégrés avec pandas qui peuvent accomplir cela?

12
Mustard Tiger

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()

enter image description here

15
fuglede

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()

enter image description here

Quelques points:

  • vous devrez peut-être vérifier les points par la suite pour vous assurer qu'il n'y a pas de points très proches les uns des autres.
  • vous pouvez jouer avec n pour filtrer les points bruyants
  • argrelextrema renvoie un Tuple et le [0] à la fin extrait un tableau numpy
24
Foad