Saya punya data deret waktu. Menghasilkan data
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']
Saya ingin membuat garis zig-zag yang menghubungkan antara maxima lokal dan minimum lokal, yang memenuhi syarat bahwa pada sumbu y, |highest - lowest value|
setiap garis zig-zag harus melebihi persentase (katakanlah 20%) dari jarak sebelumnya garis zig-zag, DAN nilai yang dinyatakan sebelumnya k (katakanlah 1.2)
Saya dapat menemukan ekstrema lokal menggunakan kode ini:
# 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'])
tapi saya tidak tahu bagaimana menerapkan kondisi ambang itu. Tolong beri tahu saya bagaimana menerapkan kondisi seperti itu.
Karena data dapat berisi jutaan cap waktu, perhitungan yang efisien sangat disarankan
Untuk deskripsi yang lebih jelas:
Contoh output, dari data saya:
# 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')
Output yang saya inginkan (sesuatu yang mirip dengan ini, zigzag hanya menghubungkan segmen signifikan)
sumber
Anda dapat menggunakan fungsi rolling panda untuk membuat ekstrema lokal. Itu menyederhanakan kode sedikit dibandingkan dengan pendekatan Scipy Anda.
Fungsi untuk menemukan ekstrema:
Fungsi untuk membuat zigzag, dapat diterapkan pada Dataframe sekaligus (di atas setiap kolom), tetapi ini akan memperkenalkan NaN's karena cap waktu yang dikembalikan akan berbeda untuk setiap kolom. Anda dapat dengan mudah menjatuhkan ini nanti seperti yang ditunjukkan pada contoh di bawah ini, atau cukup menerapkan fungsi pada satu kolom di Dataframe Anda.
Perhatikan bahwa saya membatalkan pengujian terhadap ambang batas
k
, saya tidak yakin apakah sepenuhnya memahami bagian itu dengan benar. Anda dapat memasukkannya jika perbedaan absolut antara ekstrim sebelumnya dan saat ini harus lebih besar darik
:& (ext_val.diff().abs() > k)
Saya juga tidak yakin apakah zigzag akhir harus selalu bergerak dari tinggi asli ke rendah atau sebaliknya. Saya berasumsi itu seharusnya, jika tidak, Anda dapat menghapus pencarian kedua untuk ekstrim di akhir fungsi.
Hasilkan beberapa data sampel:
Terapkan fungsi dan ekstrak hasilnya untuk kolom 'data1':
Visualisasikan hasilnya:
sumber
(ext_val.diff().abs() > (ext_val.shift(-1).abs() * p))
, seperti yang saya mengerti, Anda membandingkan jarak antara dua titik denganp%
titik terakhir, apakah saya benar? Karena saya ingin membandingkan setiap segmen zigzag dengan segmen sebelumnya, dan ulangi sampai kondisinya terpenuhi.