Ich habe Zeitreihendaten. Daten generieren
date_rng = pd.date_range('2019-01-01', freq='s', periods=400)
df = pd.DataFrame(np.random.lognormal(.005, .5,size=(len(date_rng), 3)),
columns=['data1', 'data2', 'data3'],
index= date_rng)
s = df['data1']
Ich möchte eine Zick-Zack-Linie zwischen den lokalen Maxima und den lokalen Minima erstellen, die die Bedingung erfüllt, dass auf der y-Achse |highest - lowest value|
jeder Zick-Zack-Linie einen Prozentsatz (z. B. 20%) des Abstands der vorherigen überschreiten muss Zick-Zack-Linie UND ein vorgegebener Wert k (sagen wir 1,2)
Ich kann die lokalen Extrema mit diesem Code finden:
# Find peaks(max).
peak_indexes = signal.argrelextrema(s.values, np.greater)
peak_indexes = peak_indexes[0]
# Find valleys(min).
valley_indexes = signal.argrelextrema(s.values, np.less)
valley_indexes = valley_indexes[0]
# Merge peaks and valleys data points using pandas.
df_peaks = pd.DataFrame({'date': s.index[peak_indexes], 'zigzag_y': s[peak_indexes]})
df_valleys = pd.DataFrame({'date': s.index[valley_indexes], 'zigzag_y': s[valley_indexes]})
df_peaks_valleys = pd.concat([df_peaks, df_valleys], axis=0, ignore_index=True, sort=True)
# Sort peak and valley datapoints by date.
df_peaks_valleys = df_peaks_valleys.sort_values(by=['date'])
aber ich weiß nicht, wie ich die Schwellenbedingung darauf anwenden soll. Bitte teilen Sie mir mit, wie diese Bedingung anzuwenden ist.
Da die Daten Millionen Zeitstempel enthalten können, wird eine effiziente Berechnung dringend empfohlen
Für eine klarere Beschreibung:
Beispielausgabe meiner Daten:
# Instantiate axes.
(fig, ax) = plt.subplots()
# Plot zigzag trendline.
ax.plot(df_peaks_valleys['date'].values, df_peaks_valleys['zigzag_y'].values,
color='red', label="Zigzag")
# Plot original line.
ax.plot(s.index, s, linestyle='dashed', color='black', label="Org. line", linewidth=1)
# Format time.
ax.xaxis_date()
ax.xaxis.set_major_formatter(mdates.DateFormatter("%Y-%m-%d"))
plt.gcf().autofmt_xdate() # Beautify the x-labels
plt.autoscale(tight=True)
plt.legend(loc='best')
plt.grid(True, linestyle='dashed')
Meine gewünschte Ausgabe (etwas Ähnliches, der Zickzack verbindet nur die signifikanten Segmente)
quelle
Sie können die Rollfunktion von Pandas verwenden, um die lokalen Extrema zu erstellen. Das vereinfacht den Code ein wenig im Vergleich zu Ihrem Scipy-Ansatz.
Funktionen zum Auffinden der Extrema:
Die Funktion zum Erstellen des Zickzacks kann sofort (über jede Spalte) auf den Datenrahmen angewendet werden. Dadurch werden jedoch NaNs eingeführt, da die zurückgegebenen Zeitstempel für jede Spalte unterschiedlich sind. Sie können diese später einfach löschen, wie im folgenden Beispiel gezeigt, oder die Funktion einfach auf eine einzelne Spalte in Ihrem Datenrahmen anwenden.
Beachten Sie, dass ich den Test anhand eines Schwellenwerts auskommentiert habe
k
. Ich bin mir nicht sicher, ob ich diesen Teil richtig verstanden habe. Sie können es einschließen, wenn der absolute Unterschied zwischen dem vorherigen und dem aktuellen Extrem größer sein muss alsk
:& (ext_val.diff().abs() > k)
Ich bin mir auch nicht sicher, ob der endgültige Zickzack immer von einem ursprünglichen Hoch zu einem Tief oder umgekehrt wechseln soll. Ich habe es angenommen, sonst können Sie die zweite Suche nach Extrem am Ende der Funktion entfernen.
Generieren Sie einige Beispieldaten:
Wenden Sie die Funktion an und extrahieren Sie das Ergebnis für die Spalte 'data1':
Visualisieren Sie das Ergebnis:
quelle
(ext_val.diff().abs() > (ext_val.shift(-1).abs() * p))
ich weiß, vergleichen Sie den Abstand zwischen zwei Punkten mitp%
dem letzten Punkt. Stimmt das? Weil ich jedes Zickzack-Segment mit dem vorherigen Segment vergleichen und wiederholen möchte, bis die Bedingung erfüllt ist.