Apakah ada fungsi SciPy atau fungsi NumPy atau modul untuk Python yang menghitung rata-rata berjalan dari array 1D yang diberikan jendela tertentu?
python
numpy
scipy
moving-average
Shejo284
sumber
sumber
UPD: solusi yang lebih efisien telah diusulkan oleh Alleo dan jasaarim .
Anda dapat menggunakannya
np.convolve
untuk itu:Penjelasan
Mean berjalan adalah kasus operasi matematika konvolusi . Untuk mean yang sedang berjalan, Anda menggeser jendela di sepanjang input dan menghitung rata-rata dari isi jendela. Untuk sinyal 1D diskrit, konvolusi adalah hal yang sama, kecuali alih-alih berarti Anda menghitung kombinasi linear sewenang-wenang, yaitu mengalikan setiap elemen dengan koefisien yang sesuai dan menjumlahkan hasilnya. Koefisien-koefisien tersebut, satu untuk setiap posisi di jendela, kadang-kadang disebut kernel konvolusi . Sekarang, rata-rata aritmatika dari nilai-nilai N adalah
(x_1 + x_2 + ... + x_N) / N
, jadi kernel yang sesuai adalah(1/N, 1/N, ..., 1/N)
, dan itulah yang kita dapatkan dengan menggunakannp.ones((N,))/N
.Tepi
The
mode
argumennp.convolve
menspesifikasikan bagaimana menangani tepi. Saya memilihvalid
mode di sini karena saya pikir itulah cara kebanyakan orang berharap menjalankan berarti bekerja, tetapi Anda mungkin memiliki prioritas lain. Berikut adalah plot yang menggambarkan perbedaan antara mode:sumber
numpy.cumsum
memiliki kompleksitas yang lebih baik.Solusi yang efisien
Konvolusi jauh lebih baik daripada pendekatan langsung, tetapi (saya kira) menggunakan FFT dan karenanya sangat lambat. Namun khusus untuk komputasi yang sedang berjalan berarti pendekatan berikut berfungsi dengan baik
Kode untuk diperiksa
Perhatikan bahwa
numpy.allclose(result1, result2)
adalahTrue
, dua metode yang setara. Semakin besar N, semakin besar pula perbedaan waktu.peringatan: meskipun cumsum lebih cepat akan ada peningkatan kesalahan floating point yang dapat menyebabkan hasil Anda tidak valid / salah / tidak dapat diterima
komentar menunjukkan masalah kesalahan floating point di sini tapi saya membuatnya lebih jelas di sini di jawabannya. .
np.longdouble
tetapi kesalahan floating point Anda akan tetap signifikan untuk jumlah poin yang relatif besar (sekitar> 1e5 tetapi tergantung pada data Anda)sumber
numpy.convolve
adalah O (mn); yang docs menyebutkan bahwascipy.signal.fftconvolve
penggunaan FFT.running_mean([1,2,3], 2)
givearray([1, 2])
. Menggantix
dengan[float(value) for value in x]
melakukan trik.x
mengandung pelampung. Contoh:running_mean(np.arange(int(1e7))[::-1] + 0.2, 1)[-1] - 0.2
kembali0.003125
sementara yang diharapkan0.0
. Informasi lebih lanjut: en.wikipedia.org/wiki/Loss_of_significancePembaruan: Contoh di bawah ini menunjukkan
pandas.rolling_mean
fungsi lama yang telah dihapus dalam versi panda terbaru. Setara modern dengan panggilan fungsi di bawah ini adalahpanda lebih cocok untuk ini daripada NumPy atau SciPy. Fungsinya rolling_mean melakukan pekerjaan dengan nyaman. Itu juga mengembalikan array NumPy ketika input adalah sebuah array.
Sulit untuk mengalahkan
rolling_mean
dalam kinerja dengan implementasi Python murni khusus. Berikut adalah contoh kinerja terhadap dua solusi yang diusulkan:Ada juga opsi bagus untuk bagaimana menangani nilai-nilai tepi.
sumber
df.rolling(windowsize).mean()
sekarang berfungsi sebagai gantinya (sangat cepat saya dapat menambahkan). untuk seri 6.000 baris%timeit test1.rolling(20).mean()
menghasilkan 1000 loop, terbaik 3: 1,16 ms per loopdf.rolling()
berfungsi dengan cukup baik, masalahnya adalah bahkan formulir ini tidak akan mendukung ndarrays di masa mendatang. Untuk menggunakannya, kita harus memuat data kita ke dalam Bingkai Data Pandas terlebih dahulu. Saya ingin melihat fungsi ini ditambahkan ke salah satunumpy
atauscipy.signal
.%timeit bottleneck.move_mean(x, N)
3 sampai 15 kali lebih cepat daripada metode cumsum dan panda di komputer saya. Lihatlah benchmark mereka di README repo .Anda dapat menghitung rata-rata berjalan dengan:
Tapi lambat.
Untungnya, numpy menyertakan fungsi belok yang dapat kita gunakan untuk mempercepat. Mean berjalan setara dengan berbelit
x
- belit dengan vektor yangN
panjang, dengan semua anggota sama dengan1/N
. Implementasi convolve yang numpy termasuk transien awal, jadi Anda harus menghapus poin N-1 pertama:Di komputer saya, versi cepat adalah 20-30 kali lebih cepat, tergantung pada panjang vektor input dan ukuran jendela rata-rata.
Perhatikan bahwa convolve memang menyertakan
'same'
mode yang sepertinya harus mengatasi masalah transien awal, tetapi membelahnya antara awal dan akhir.sumber
mode='valid'
diconvolve
mana tidak memerlukan post-processing.mode='valid'
menghapus transien dari kedua ujungnya, kan? Jikalen(x)=10
danN=4
, untuk rata-rata berlari, saya ingin 10 hasil tetapivalid
mengembalikan 7.modes = ('full', 'same', 'valid'); [plot(convolve(ones((200,)), ones((50,))/50, mode=m)) for m in modes]; axis([-10, 251, -.1, 1.1]); legend(modes, loc='lower center')
(dengan pyplot dan numpy diimpor).runningMean
Apakah saya memiliki efek samping rata-rata dengan nol, ketika Anda keluar dari array denganx[ctr:(ctr+N)]
untuk sisi kanan array.runningMeanFast
juga memiliki masalah efek perbatasan ini.dalam pengujian saya di Tradewave.net TA-lib selalu menang:
hasil:
sumber
NameError: name 'info' is not defined
. Saya mendapatkan kesalahan ini, Pak.Untuk solusi yang siap digunakan, lihat https://scipy-cookbook.readthedocs.io/items/SignalSmooth.html . Ini memberikan rata-rata berjalan dengan
flat
jenis jendela. Perhatikan bahwa ini sedikit lebih canggih daripada metode konvolusi do-it-yourself yang sederhana, karena metode ini mencoba menangani masalah di awal dan akhir data dengan merefleksikannya (yang mungkin atau mungkin tidak berfungsi dalam kasus Anda. ..)Untuk memulainya, Anda dapat mencoba:
sumber
numpy.convolve
, bedanya hanya dalam mengubah urutan.w
ukuran jendela, dans
data?Anda dapat menggunakan scipy.ndimage.filters.uniform_filter1d :
uniform_filter1d
:'reflect'
default, tetapi dalam kasus saya, saya lebih suka'nearest'
Ini juga agak cepat (hampir 50 kali lebih cepat dari
np.convolve
dan 2-5 kali lebih cepat daripada pendekatan cumsum yang diberikan di atas ):inilah 3 fungsi yang memungkinkan Anda membandingkan kesalahan / kecepatan implementasi yang berbeda:
sumber
uniform_filter1d
,np.convolve
dengan persegi panjang, dannp.cumsum
diikuti olehnp.subtract
. hasil saya: (1.) convolve adalah yang paling lambat. (2.) cumsum / kurangi sekitar 20-30x lebih cepat. (3.) uniform_filter1d sekitar 2-3x lebih cepat dari cumsum / kurangi. pemenang pasti uniform_filter1d.uniform_filter1d
adalah lebih cepat daricumsum
solusi (sekitar 2-5x). danuniform_filter1d
tidak mendapatkan kesalahan floating point besar seperticumsum
solusinya.Saya tahu ini adalah pertanyaan lama, tetapi di sini ada solusi yang tidak menggunakan struktur data atau pustaka tambahan. Itu linier dalam jumlah elemen daftar input dan saya tidak bisa memikirkan cara lain untuk membuatnya lebih efisien (sebenarnya jika ada yang tahu cara yang lebih baik untuk mengalokasikan hasilnya, tolong beri tahu saya).
CATATAN: ini akan jauh lebih cepat menggunakan array numpy daripada daftar, tapi saya ingin menghilangkan semua dependensi. Mungkin juga untuk meningkatkan kinerja dengan eksekusi multi-threaded
Fungsi ini mengasumsikan bahwa daftar input adalah satu dimensi, jadi berhati-hatilah.
Contoh
Asumsikan bahwa kita memiliki daftar
data = [ 1, 2, 3, 4, 5, 6 ]
yang ingin kita hitung rata-rata bergulir dengan periode 3, dan bahwa Anda juga menginginkan daftar keluaran dengan ukuran yang sama dengan input (yang paling sering terjadi).Elemen pertama memiliki indeks 0, sehingga rata-rata bergulir harus dihitung pada elemen indeks -2, -1 dan 0. Jelas kami tidak memiliki data [-2] dan data [-1] (kecuali jika Anda ingin menggunakan khusus syarat batas), jadi kami mengasumsikan bahwa elemen-elemen tersebut adalah 0. Ini setara dengan nol-padding daftar, kecuali kami tidak benar-benar pad itu, hanya melacak indeks yang membutuhkan padding (dari 0 hingga N-1).
Jadi, untuk elemen N pertama kami terus menambahkan elemen dalam akumulator.
Dari elemen N + 1 ke depan akumulasi sederhana tidak berfungsi. kami harapkan
result[3] = (2 + 3 + 4)/3 = 3
tetapi ini berbeda dari(sum + 4)/3 = 3.333
.Cara untuk menghitung nilai yang benar adalah untuk mengurangi
data[0] = 1
darisum+4
, sehingga memberikansum + 4 - 1 = 9
.Ini terjadi karena saat ini
sum = data[0] + data[1] + data[2]
, tetapi itu juga berlaku untuk setiapi >= N
sebab, sebelum pengurangan,sum
adalahdata[i-N] + ... + data[i-2] + data[i-1]
.sumber
Saya merasa ini bisa diselesaikan dengan elegan menggunakan bottleneck
Lihat contoh dasar di bawah ini:
"mm" adalah rata-rata bergerak untuk "a".
"window" adalah jumlah maksimum entri yang perlu dipertimbangkan untuk moving average.
"min_count" adalah min jumlah entri yang perlu dipertimbangkan untuk memindahkan rata-rata (misalnya untuk beberapa elemen pertama atau jika array memiliki nilai nan).
Bagian baiknya adalah Bottleneck membantu menangani nilai-nilai nan dan juga sangat efisien.
sumber
Saya belum memeriksa seberapa cepat ini, tetapi Anda dapat mencoba:
sumber
Jawaban ini berisi solusi menggunakan pustaka standar Python untuk tiga skenario yang berbeda.
Rata-rata berjalan dengan
itertools.accumulate
Ini adalah solusi Python 3.2+ yang efisien memori, menghitung rata-rata yang berjalan di atas nilai yang dapat diubah dengan memanfaatkannya
itertools.accumulate
.Catatan yang
values
bisa berupa iterable, termasuk generator atau objek lain yang menghasilkan nilai dengan cepat.Pertama, malas membangun jumlah kumulatif dari nilai-nilai.
Selanjutnya,
enumerate
jumlah kumulatif (mulai dari 1) dan membangun generator yang menghasilkan sebagian kecil dari nilai akumulasi dan indeks enumerasi saat ini.Anda dapat mengeluarkan
means = list(rolling_avg)
jika Anda membutuhkan semua nilai dalam memori sekaligus atau meneleponnext
secara bertahap.(Tentu saja, Anda juga dapat beralih
rolling_avg
denganfor
loop, yang akan memanggilnext
secara implisit.)Solusi ini dapat ditulis sebagai fungsi sebagai berikut.
Sebuah coroutine yang Anda dapat mengirim nilai-nilai setiap saat
Coroutine ini mengkonsumsi nilai yang Anda kirim dan menjaga rata-rata berjalan dari nilai yang terlihat sejauh ini.
Ini berguna ketika Anda tidak memiliki iterable nilai tetapi meminta nilai untuk dirata-rata satu per satu pada waktu yang berbeda sepanjang hidup program Anda.
Coroutine bekerja seperti ini:
Menghitung rata-rata di atas ukuran jendela geser
N
Fungsi generator ini mengambil iterable dan ukuran jendela
N
dan menghasilkan rata-rata di atas nilai saat ini di dalam jendela. Ini menggunakandeque
, yang merupakan struktur data yang mirip dengan daftar, tetapi dioptimalkan untuk modifikasi cepat (pop
,append
) di kedua titik akhir .Berikut ini fungsinya:
sumber
Agak terlambat ke pesta, tapi saya sudah membuat fungsi kecil saya sendiri yang TIDAK membungkus ujung atau bantalan dengan nol yang kemudian digunakan untuk menemukan rata-rata juga. Sebagai perlakuan lebih lanjut adalah, bahwa itu juga sampel ulang sinyal pada titik-titik spasi linear. Kustomisasi kode sesuka hati untuk mendapatkan fitur lainnya.
Metode ini adalah perkalian matriks sederhana dengan kernel Gaussian yang dinormalisasi.
Penggunaan sederhana pada sinyal sinusoidal dengan tambahan noise terdistribusi normal:
sumber
sum
, menggunakannp.sum
bukannya 2 The@
operator (tidak tahu apa itu) melempar kesalahan. Saya mungkin memeriksanya nanti tetapi saya kekurangan waktu sekarang@
adalah operator perkalian matriks yang mengimplementasikan np.matmul . Periksa apakahy_in
array Anda adalah array numpy, itu mungkin masalahnya.Alih-alih numpy atau scipy, saya akan merekomendasikan panda untuk melakukan ini lebih cepat:
Ini mengambil rata-rata bergerak (MA) dari 3 periode kolom "data". Anda juga dapat menghitung versi bergeser, misalnya yang mengecualikan sel saat ini (bergeser satu kembali) dapat dihitung dengan mudah sebagai:
sumber
pandas.rolling_mean
saat menggunakan tambangpandas.DataFrame.rolling
. Anda juga dapat menghitung bergerakmin(), max(), sum()
dll. Sertamean()
dengan metode ini dengan mudah.pandas.rolling_min, pandas.rolling_max
dll. Mereka serupa namun berbeda.Ada komentar oleh mab yang dimakamkan di salah satu jawaban di atas yang memiliki metode ini.
bottleneck
memilikimove_mean
yang merupakan rata-rata bergerak sederhana:min_count
adalah parameter praktis yang pada dasarnya akan membawa rata-rata bergerak ke titik itu dalam array Anda. Jika Anda tidak menyetelmin_count
, itu akan samawindow
, dan semuanya akan mencapaiwindow
poinnan
.sumber
Pendekatan lain untuk menemukan moving average tanpa menggunakan nanda, panda
akan mencetak [2.0, 4.0, 6.0, 6.5, 7.4, 7.8333333333333]
sumber
Pertanyaan ini sekarang bahkan lebih tua daripada ketika NeXuS menulis tentang hal itu bulan lalu, TETAPI saya suka bagaimana kodenya berurusan dengan kasus tepi. Namun, karena ini adalah "rata-rata bergerak sederhana," hasilnya tertinggal di belakang data yang mereka terapkan. Saya berpikir bahwa berurusan dengan kasus tepi dengan cara yang lebih memuaskan daripada mode NumPy ini
valid
,same
danfull
dapat dicapai dengan menerapkan pendekatan yang sama denganconvolution()
metode berbasis.Kontribusi saya menggunakan rata-rata berjalan tengah untuk menyelaraskan hasilnya dengan data mereka. Ketika ada terlalu sedikit titik yang tersedia untuk jendela ukuran penuh untuk digunakan, rata-rata berjalan dihitung dari jendela yang lebih kecil berturut-turut di tepi array. [Sebenarnya, dari jendela yang lebih besar berturut-turut, tapi itu detail implementasi.]
Ini relatif lambat karena menggunakan
convolve()
, dan mungkin bisa dirapikan cukup banyak oleh Pythonista yang sebenarnya, namun, saya percaya bahwa ide itu berlaku.sumber
Ada banyak jawaban di atas tentang penghitungan rata-rata berjalan. Jawaban saya menambahkan dua fitur tambahan:
Fitur kedua ini sangat berguna untuk menentukan nilai mana yang berbeda dari tren umum dengan jumlah tertentu.
Saya menggunakan numpy.cumsum karena ini adalah metode yang paling efisien waktu ( lihat jawaban Alleo di atas ).
Kode ini hanya berfungsi untuk Ns saja. Itu dapat disesuaikan untuk angka ganjil dengan mengubah np.insert dari padded_x dan n_nan.
Contoh output (mentah dalam warna hitam, movavg dengan warna biru):
Kode ini dapat dengan mudah diadaptasi untuk menghapus semua nilai rata-rata bergerak yang dihitung dari kurang dari cutoff = 3 nilai non-nan.
sumber
Gunakan Hanya Pustaka Standar Python (Hemat Memori)
Berikan saja versi lain menggunakan perpustakaan standar
deque
saja. Cukup mengejutkan bagi saya bahwa sebagian besar jawaban menggunakanpandas
ataunumpy
.Sebenarnya saya menemukan implementasi lain dalam python docs
Namun implementasinya menurut saya sedikit lebih kompleks dari yang seharusnya. Tetapi harus dalam dokumen python standar karena suatu alasan, dapatkah seseorang mengomentari implementasi tambang dan dokumen standar?
sumber
O(n*d)
perhitungan (d
menjadi ukuran jendela,n
ukuran iterable) dan mereka melakukanO(n)
Dengan variabel @ Aikude, saya menulis satu baris.
sumber
Meskipun ada solusi untuk pertanyaan ini di sini, silakan lihat solusi saya. Ini sangat sederhana dan bekerja dengan baik.
sumber
Dari membaca jawaban-jawaban lain, saya kira ini bukan pertanyaan yang ditanyakan, tetapi saya tiba di sini dengan kebutuhan menjaga rata-rata daftar nilai yang terus bertambah.
Jadi, jika Anda ingin menyimpan daftar nilai yang Anda peroleh dari suatu tempat (situs, alat pengukur, dll.) Dan rata-rata dari nilai terakhir yang
n
diperbarui, Anda dapat menggunakan kode di bawah ini, yang meminimalkan upaya penambahan baru elemen:Dan Anda dapat mengujinya dengan, misalnya:
Pemberian yang mana:
sumber
Solusi lain hanya menggunakan perpustakaan dan deque standar:
sumber
Untuk tujuan pendidikan, izinkan saya menambahkan dua solusi Numpy (yang lebih lambat daripada solusi cumsum):
Fungsi yang digunakan: as_strided , add.reduceat
sumber
Semua solusi tersebut buruk karena tidak ada
numpy.cumsum
, atauO(len(x) * w)
implementasi sebagai konvolusi.Diberikan
Perhatikan bahwa
x_[:w].sum()
sama denganx[:w-1].sum()
. Jadi untuk rata-rata pertamanumpy.cumsum(...)
tambahx[w] / w
(viax_[w+1] / w
), dan kurangi0
(darix_[0] / w
). Ini menghasilkanx[0:w].mean()
Melalui cumsum, Anda akan memperbarui rata-rata kedua dengan menambah
x[w+1] / w
dan mengurangi tambahanx[0] / w
, menghasilkanx[1:w+1].mean()
.Ini berlangsung sampai
x[-w:].mean()
tercapai.Solusi ini adalah vektor
O(m)
,, dapat dibaca dan stabil secara numerik.sumber
Bagaimana dengan filter rata-rata bergerak ? Ini juga satu-liner dan memiliki keuntungan, bahwa Anda dapat dengan mudah memanipulasi jenis jendela jika Anda memerlukan sesuatu selain persegi panjang, yaitu. rata-rata bergerak N-long sederhana dari sebuah:
Dan dengan jendela triangular diterapkan:
Catatan: Saya biasanya membuang sampel N pertama sebagai palsu karena itu
[N:]
pada akhirnya, tetapi itu tidak perlu dan masalah pilihan pribadi saja.sumber
Jika Anda memang memilih untuk roll sendiri, daripada menggunakan perpustakaan yang ada, harap menyadari kesalahan floating point dan mencoba untuk meminimalkan efeknya:
Jika semua nilai Anda kira-kira sama dengan besarnya, maka ini akan membantu menjaga presisi dengan selalu menambahkan nilai dengan besaran yang hampir sama.
sumber