Pandas: Paralelisasi untuk tugas paralel yang memalukan

Dibuat pada 19 Des 2013  ·  64Komentar  ·  Sumber: pandas-dev/pandas

Saya ingin mempromosikan gagasan penerapan multiprocessing.Pool() eksekusi tugas paralel yang memalukan, misalnya penerapan fungsi ke sejumlah besar kolom.
Jelas, ada beberapa overhead untuk mengaturnya, jadi akan ada batas jumlah kolom yang lebih rendah dari yang ini saja bisa lebih cepat daripada pendekatan cython yang sudah cepat. Saya akan menambahkan tes kinerja saya nanti untuk masalah ini.
Saya mengirim email ke @jreback tentang ini dan dia menambahkan komentar/komplikasi berikut:

  • mentransfer data numpy tidak begitu efisien - tetapi masih mungkin cukup baik
  • anda dapat mentransfer (acar) fungsi tipe lambda jadi mungkin perlu melihat menggunakan perpustakaan yang disebut dill (yang memecahkan masalah ini) - mungkin dapat sedikit memodifikasi msgpack untuk melakukan ini (dan sudah cukup efisien dalam mentransfer jenis objek lain)
  • juga dapat menyelidiki joblib - Saya pikir statsmodels menggunakannya [ed: Sepertinya itu benar, saya membaca di grup mereka tentang joblib]
  • Saya akan membuat dir core/paralel tingkat atas baru untuk jenis barang ini
  • strategi di tautan ini bisa menjadi cara yang baik untuk diikuti: http://stackoverflow.com/questions/17785275/share-large-read-only-numpy-array-between-multiprocessing-processes

tautan:
http://stackoverflow.com/questions/13065172/multiprocess-python-numpy-code-for-processing-data-faster
http://docs.cython.org/src/userguide/parallelism.html
http://distarray.readthedocs.org/en/v0.5.0/

Docs Groupby IO HDF5 Performance

Komentar yang paling membantu

Saya telah memuat bingkai data dengan sekitar 170 juta baris dalam memori (python menggunakan ~ 35GB RAM) dan mengatur waktu operasi yang sama dengan 3 metode dan menjalankannya semalaman. Mesin ini memiliki 32 core fisik atau 64 hypervised dan RAM bebas yang cukup. Sementara konversi tanggal adalah operasi yang sangat murah, ini menunjukkan overhead dari metode ini.

Sementara cara ulir tunggal adalah yang tercepat, cukup membosankan untuk melihat satu inti terus berjalan pada 100% sementara 63 sedang diam. Idealnya saya ingin operasi paralel semacam batching untuk mengurangi overhead, misalnya selalu 100000 baris atau sesuatu seperti batchsize=100000.

<strong i="7">@interactive</strong>
def to_date(strdate) :
    return datetime.fromtimestamp(int(strdate)/1000)

%time res['milisecondsdtnormal']=res['miliseconds'].map(to_date)
#CPU times: user 14min 52s, sys: 2h 1min 30s, total: 2h 16min 22s
#Wall time: 2h 17min 5s

pool = Pool(processes=64)
%time res['milisecondsdtpool']=pool.map(to_date, res['miliseconds'])
#CPU times: user 21min 37s, sys: 2min 30s, total: 24min 8s
#Wall time: 5h 40min 50s

from IPython.parallel import Client
rc = Client() #local 64 engines
rc[:].execute("from datetime import datetime")
%time res['milisecondsipython'] = rc[:].map_sync(to_date, res['miliseconds'])
#CPU times: user 5h 27min 4s, sys: 1h 23min 50s, total: 6h 50min 54s
#Wall time: 10h 56min 18s

Semua 64 komentar

Mungkin ini akan menjadi sesuatu yang lebih baik dilakukan di folder sandbox/parallel
sampai kita memutuskan apa yang layak dilakukan? Ini juga akan baik untuk memiliki
seseorang untuk menguji kinerja di Windows juga, saya pernah mendengar bahwa ada sangat
karakteristik kinerja yang berbeda untuk Windows vs. Linux/OSX.

untuk windows vs linux/osx threading/multiprocessing itu.

Saya pikir ini bisa dimulai dengan kata kunci/opsi opsional untuk mengaktifkan perhitungan paralel jika berguna. ini memecahkan masalah windows/Linux karena default untuk melakukan paralel dapat berbeda (atau memiliki ambang batas yang berbeda, seperti yang kami lakukan untuk numexpr)

Mereka semua dapat dikelompokkan dalam atribut par seperti metode str . Apa semua yang ada dalam pikiran di sini selain berlaku? Apakah jumlah, prod, dll mungkin menguntungkan?

@michaelaye dapatkah Anda memberikan contoh sederhana yang bagus untuk pembandingan?

Berikut implementasi menggunakan joblib:

https://github.com/jreback/pandas/tree/parallel

dan beberapa pengaturan waktu ..... Saya harus menggunakan fungsi yang cukup dibuat-buat sebenarnya ....
Anda perlu menimbang waktu acar untuk sub-bingkai vs waktu fungsi
waktu acar yang tercantum di bawah ini adalah ke disk yang tidak terjadi saat mengirim ke sub-proses
(tapi masih menjadi faktor pembatas menurut saya). FYI jika frame sudah ada di disk (misalnya HDF), maka ini bisa memiliki manfaat yang cukup besar menurut saya.

In [1]: df1  = DataFrame(np.random.randn(20000, 1000))

In [2]: def f1(x):
   ...:         result = [ np.sqrt(x) for i in range(10) ]
   ...:         return result[-1]
   ...: 
In [8]: %timeit df1.to_pickle('test.p')
1 loops, best of 3: 1.77 s per loop
# reg apply
In [3]: %timeit df1.apply(f1)
1 loops, best of 3: 6.28 s per loop

# using 12 cores (6 real x 2 hyperthread)
In [4]: %timeit df1.apply(f1,engine='joblib')
1 loops, best of 3: 2.06 s per loop

# 1 core pass thru
In [5]: %timeit df1.apply(f1,engine=pd.create_parallel_engine(name='joblib',force=True,max_cpu=1))
1 loops, best of 3: 6.28 s per loop

In [6]: %timeit df1.apply(f1,engine=pd.create_parallel_engine(name='joblib',force=True,max_cpu=4))
1 loops, best of 3: 2.68 s per loop

In [7]: %timeit df1.apply(f1,engine=pd.create_parallel_engine(name='joblib',force=True,max_cpu=2))
1 loops, best of 3: 3.87 s per loop

waktu acar melebihi keuntungan perf, fungsinya terlalu cepat sehingga tidak ada manfaat di sini

In [6]: %timeit df1.apply(f2)
1 loops, best of 3: 981 ms per loop

In [7]: %timeit df1.apply(f2,engine='joblib')
1 loops, best of 3: 1.8 s per loop

In [8]: def f2(x):
    return np.sqrt(x)
   ...: 

Jadi, Anda memerlukan fungsi yang cukup lambat pada satu kolom agar ini bermanfaat
(akan sangat mudah untuk melakukan sampel waktu dari satu kolom, katakan dan putuskan apakah akan paralel atau tidak)
sekarang hanya menggunakannya sesuai permintaan (pengguna/opsi) yang ditentukan

In [9]: %timeit f1(df1.icol(0))
100 loops, best of 3: 5.89 ms per loop

In [10]: %timeit f2(df1.icol(0))
1000 loops, best of 3: 639 ᄉs per loop

Bagus menulis Jeff. Saya pikir waktu acar adalah faktor besar tetapi juga waktu untuk menelurkan proses baru.

Saya membayangkan ini bekerja dengan serangkaian proses komputasi yang diluncurkan sebelumnya saat startup dan menunggu untuk bekerja. Untuk pekerjaan paralel saya di masa depan, saya mungkin akan menggunakan paralel iPython di seluruh data hdf5 terdistribusi. Masalah yang sering saya alami adalah konsumsi memori yang perlahan bertambah untuk proses python yang hidup terlalu lama.

Pada disk akses paralel potongan baris HDF5 untuk mempercepat komputasi terdengar hebat.

@dragoljub

ya...Saya tidak berpikir menambahkan IPython paralel back end akan terlalu sulit (atau jenis backend terdistribusi lainnya). Hanya mewarisi dan pasang.

HDF5 dan penerapan groupby terlihat seperti kasus yang sangat bagus untuk peningkatan dengan ini.

Tolong mainkan dan beri saya umpan balik tentang API (dan bahkan coba backend!)

http://docs.cython.org/src/userguide/parallelism.html

mesin Cynthon juga mudah (meskipun perlu sedikit perubahan dalam pengaturan untuk dikompilasi dengan Dukungan OpenMP)
tapi sepertinya langsung

Saya telah memuat bingkai data dengan sekitar 170 juta baris dalam memori (python menggunakan ~ 35GB RAM) dan mengatur waktu operasi yang sama dengan 3 metode dan menjalankannya semalaman. Mesin ini memiliki 32 core fisik atau 64 hypervised dan RAM bebas yang cukup. Sementara konversi tanggal adalah operasi yang sangat murah, ini menunjukkan overhead dari metode ini.

Sementara cara ulir tunggal adalah yang tercepat, cukup membosankan untuk melihat satu inti terus berjalan pada 100% sementara 63 sedang diam. Idealnya saya ingin operasi paralel semacam batching untuk mengurangi overhead, misalnya selalu 100000 baris atau sesuatu seperti batchsize=100000.

<strong i="7">@interactive</strong>
def to_date(strdate) :
    return datetime.fromtimestamp(int(strdate)/1000)

%time res['milisecondsdtnormal']=res['miliseconds'].map(to_date)
#CPU times: user 14min 52s, sys: 2h 1min 30s, total: 2h 16min 22s
#Wall time: 2h 17min 5s

pool = Pool(processes=64)
%time res['milisecondsdtpool']=pool.map(to_date, res['miliseconds'])
#CPU times: user 21min 37s, sys: 2min 30s, total: 24min 8s
#Wall time: 5h 40min 50s

from IPython.parallel import Client
rc = Client() #local 64 engines
rc[:].execute("from datetime import datetime")
%time res['milisecondsipython'] = rc[:].map_sync(to_date, res['miliseconds'])
#CPU times: user 5h 27min 4s, sys: 1h 23min 50s, total: 6h 50min 54s
#Wall time: 10h 56min 18s

sama sekali tidak jelas waktu yang Anda tentukan di sini; cara pool dan ipython split ini sangat buruk; mereka mengubah jenis tugas ini menjadi banyak evaluasi skalar di mana biaya transportasi JAUH lebih tinggi daripada waktu evaluasi.

pr melakukan jenis batching ini dengan tepat

Anda harus meminta setiap prosesor mengeksekusi sepotong dan mengerjakannya dalam satu tugas (untuk setiap prosesor), tidak merusak kumpulan seperti yang Anda tunjukkan.

@michaelaye apakah Anda sudah melihat cabang ini? https://github.com/jreback/pandas/tree/parallel

Oh, ini mengasyikkan. Saya telah menunggu fungsi penerapan scatter/gather paralel menggunakan IPython.parallel. Harap beri tahu kami tentang kemajuan apa pun di sini.

Memang! Ini akan menjadi fitur yang bagus. Saya telah menggunakan konkuren.futures dan itu membuat segalanya cukup mudah, namun biaya untuk mengumpulkan proses baru masih membutuhkan banyak waktu. Jika kita memiliki kernel paralel IPython yang menunggu untuk bekerja dengan semua impor yang tepat, meneruskan pointer data ke kernel tersebut dan menggabungkan hasil akan menjadi fantastis.

@dragoljub Anda telah memukul paku di kepala. joblib baik-baik saja, tetapi Anda sering kali tidak perlu memunculkan proses seperti itu; biasanya Anda memiliki mesin nongkrong mereka.

Apakah Anda memiliki beberapa kode yang saya bisa membajak?

Saya tidak berpikir akan sangat sulit untuk menambahkan ini menggunakan IPython.parallel ; Saya hanya belum pernah menggunakannya (untuk apa yang saya lakukan, saya sering menelurkan proses yang relatif berumur panjang)

Ini mungkin berlebihan tetapi saya memiliki buku catatan tentang penggunaan IPython.parallel di sini. Ada beberapa contoh cepat.

https://github.com/jseabold/zorro

Dokumen mereka juga cukup bagus

http://ipython.org/ipython-doc/dev/parallel/

terima kasih nakhoda....ok selanjutnya....kalian punya contoh non-sepele untuk tujuan vbenching? misalnya hal-hal yang benar-benar berfungsi (dan membutuhkan waktu yang tidak sepele) yang dapat digunakan untuk pembandingan? (harus relatif mandiri .... meskipun jelas bisa menggunakan say statsmodels :)

Saya kebetulan menjalankan satu masalah seperti itu sekarang. :) Saya melewatkan melamar demi peta joblib.Parallel. Biarkan saya melihat apakah saya bisa membuatnya mandiri.

Hmm, mungkin terlalu sepele. Kasus penggunaan saya yang sebenarnya membutuhkan waktu lebih lama 20 obs ~ 1s dan datanya cukup besar. Temukan kemunculan pertama sebuah kata dalam beberapa teks. Anda dapat meningkatkan n , membuat "judul" lebih panjang, menyertakan unicode, dll. dan dengan cepat menjadi memakan waktu.

n = 100

random_strings = pd.util.testing.makeStringIndex().tolist()
X = pd.DataFrame({'title' : random_strings * n,
                                'year' : np.random.randint(1400, 1800, size=10*n)})

def min_date(x): # can't be a lambda for joblib/pickling
    # watch out for global
    return X.ix[X.title.str.contains('\\b{}\\b'.format(x))].year.min()

X.title.apply(min_date) 

Mungkin ada beberapa contoh yang lebih baik di ipython/examples/parallel . Ada juga beberapa di buku catatan saya. Misalnya, optimasi paralel, tapi saya tidak yakin ini adalah kasus penggunaan nyata dari penerapan scatter-gather yang saya pikirkan. Sesuatu seperti

def crazy_optimization_func(...):
    ....

df = pd.DataFrame(random_start_values)
df.apply(crazy_optimization_func, ...)

Di mana DataFrame berisi baris nilai awal acak dan Anda mengulangi sumbu nol untuk melakukan pengoptimalan global orang miskin.

Beberapa inspirasi API. Lihat aaply, adply, dll.

http://cran.r-project.org/web/packages/plyr/index.html

Saya lupa bahwa Hadley dengan baik hati melisensikan ulang semua kodenya agar kompatibel dengan BSD, sehingga Anda dapat mengambil lebih dari sekadar inspirasi API jika karena alasan tertentu Anda penasaran.

sebenarnya apinya sangat mudah:

df.apply(my_cool_function, engine='ipython')

from IPython.parallel import Client
df.apply(my_cool_function,engine=pd.create_parallel_engine(client=Client(profile='mpi')))

misalnya Anda baru saja melewati mesin (prob akan memungkinkan Anda untuk melewati Klien secara langsung sebagai mesin)

Besar.

Anda mungkin juga hanya mengizinkan 'ipython' dan menggunakan panggilan default Client() . Jika Anda memulai sesi/notebook IPython Anda dengan profil yang benar maka itu harus menghormati ini dan mencari di direktori itu untuk kode pengaturan yang dibutuhkan. Ada bug di sini di beberapa IPython 1.x tetapi harus diperbaiki sekarang.

https://github.com/ipython/ipython/issues/4238

melewati engine='ipython' akan membuat Klien default
juga dapat diatur melalui opsi, parallel.default_engine

dan hanya akan lulus dengan jumlah baris ambang (bisa memiliki fungsi melakukannya juga)

Kedengarannya mengagumkan. Tidak sabar untuk ini. Akan menjadi fitur besar.

Apa statusnya ini? Tampaknya mengagumkan. Apakah Anda hanya memerlukan beberapa fungsi untuk benchmark? Saya dapat menemukan sesuatu jika itu membantu/semua yang diperlukan.

berapa banyak yang harus diambil oleh fungsi target (per baris, katakanlah; itulah yang selalu saya terapkan)? 0,1 detik? 1 detik? 10 detik? keterbatasan RAM?

Baik itu bekerja untuk joblib, semacam dengan IPython.parallel. membutuhkan lebih banyak pekerjaan/waktu. Saya juga yakin bahwa Anda memerlukan tugas yang cukup intensif agar ini benar-benar berguna. misalnya waktu pembuatan/komunikasi tidak sepele.

Saya tidak akan punya waktu untuk ini untuk sementara waktu, tetapi kode saya ada di luar sana.

Saya sangat bersemangat tentang ini! Saya menulis fungsi saya sendiri untuk membagi - memetakan - concat tetapi mengalami beberapa masalah dengan multiprocessing ( http://stackoverflow.com/questions/26665809/multiprocessing-on-pandas-dataframe-confusing-behavior-based-on-input-size ).

Adakah pemikiran kapan ini bisa keluar?

+1 untuk mesin penerapan paralel!

Sudah setahun sejak @jreback menyediakan panda versi paralel dan tidak jelas apa yang dimaksud dengan penangguhan yang tidak memungkinkan untuk menjadikannya fitur panda biasa (bahkan dalam bentuk "pengujian").

Meskipun telah terbukti berhasil, tampaknya ada pemahaman bahwa pengujian lebih lanjut mungkin diperlukan. Bukankah membuat fitur ini tersedia/dapat diakses (bahkan jika untuk tujuan pengujian) di panda biasa memfasilitasi lebih banyak pengujian dan pelaporan bug?

@wikiped
Saya tidak bisa menjalankan ini dari perspektif pengujian untuk UDF generik (fungsi yang ditentukan pengguna). dan kehabisan waktu.

Sebenarnya jauh lebih mudah/lebih baik untuk digunakan: http://blaze.pydata.org/docs/latest/index.
untuk jenis paralelisasi ini karena didukung dengan cukup baik saat ini.

Ini akan menjadi fitur tambahan yang sebenarnya membutuhkan sedikit kerja/pengujian/pembandingan untuk membuat bagian dari inti pandas.

Anda dipersilakan untuk melakukan ini jika Anda mau.

@jreback
Terima kasih telah berbagi perspektif Anda tentang ini. Saya berharap saya dapat membantu dalam hal kode dengan ini, tetapi sayangnya itu di atas tingkat keahlian saya.

Dan terima kasih telah menautkan blaze - perlu melihat lebih dalam - dari pandangan pertama terlihat menarik, tetapi membuat saya merasa tersesat dengan semua konsep baru dan belum (belum) mencapai dokumen/contoh.

Menghubungkan ini dengan #3202.

Apakah ada kemajuan dalam hal ini? Saya ingin membantu jika kami membutuhkan pengembang untuk mengerjakan ini! Datatable paralel akan _sangat berguna_ mengingat saya memiliki mesin 36 inti hanya menggunakan 1 utas :( Pyspark memiliki implementasi paralel tetapi sangat lambat pada satu mesin.

Ada banyak alat baru yang menarik di ruang ini: dask, Ibis, SFrame. Saya akan merekomendasikan untuk melihat beberapa di antaranya. Memperluas panda untuk mendukung secara asli dari komputasi inti akan sangat bagus tetapi itu akan menjadi pekerjaan yang cukup banyak dan itu tidak ada dalam agenda langsung siapa pun. Sejujurnya itu mungkin lebih baik diserahkan ke proyek lain.

Pada Jumat, 24 Juli 2015 jam 08:59, abell25 [email protected] menulis:

Apakah ada kemajuan dalam hal ini? Saya ingin membantu jika kami membutuhkan pengembang untuk mengerjakan ini! Datatable paralel akan _sangat berguna_ mengingat saya memiliki mesin 36 inti hanya menggunakan 1 utas :( Pyspark memiliki implementasi paralel tetapi sangat lambat pada satu mesin.

Balas email ini secara langsung atau lihat di GitHub:
https://github.com/pydata/pandas/issues/5751#issuecomment -124566446

menggunakan panda secara paralel membutuhkan cukup banyak pekerjaan pada implementasinya. Untungnya dask telah melakukan ini, dan ini bekerja dengan baik dengan panda (sebenarnya, kami merilis gil dan membuat CategoricalIndex untuk memfasilitasi ini. Jadi saya akan merekomendasikan ini untuk paralel yang memalukan (dan sebenarnya komputasi paralel umum) .

Saya akan mengubah masalah ini ke salah satu dokumen, karena saya pikir kita harus menambahkan bagian ke enhancingperf.rst untuk menunjukkan cara untuk memulai.

cc @mrocklin

Lebih lanjut, mungkin diinginkan untuk menyediakan antarmuka dari sisi panda ke dask (dan mungkin beberapa perpustakaan komputasi out-of-core / paralel), misalnya sesuatu di sepanjang baris

df.apply(f, engine='dask') . Yang dapat mengirimkan perhitungan. Namun, ini tidak akan menjadi mekanisme umum karena sering kali Anda benar-benar ingin melakukan serangkaian perhitungan. Jadi tidak yakin apa / jika ada yang harus kita lakukan di sini.

Saya akan sangat senang bekerja dengan orang-orang yang tertarik untuk memparalelkan komputasi seperti panda dengan dask. Saya menduga bahwa ini akan melibatkan sedikit pekerjaan baik untuk memastikan bahwa dask.dataframe mencakup semua Pandas API yang diperlukan dan dalam memastikan bahwa Pandas merilis GIL di lokasi yang sesuai.

Membuat ini bekerja dengan sangat baik mungkin memerlukan tindakan dari beberapa pihak, pengguna dengan aplikasi penggerak, pengembang inti panda, dan pengembang inti dask. Jeff dan saya memiliki interaksi yang baik tentang hal ini di masa lalu; akan lebih baik untuk menambahkan beberapa orang dengan kasus penggunaan yang konkret.

Apakah harapan bahwa df.apply(f, engine='dask') (atau mesin lainnya) _must_ mengembalikan hasil yang sama dengan df.apply(f) ? Atau bisakah dask mengembalikan grafik dask? Saya tertarik untuk melihat pengembalian grafik apa yang memungkinkan Anda melakukannya, dan seberapa sulit penerapannya? Ingin sekali membicarakan ini hari ini @mrocklin

@TomAugspurger

JIKA kami melakukan ini, maka saya pikir ini hanya akan melakukan perhitungan (secara paralel) dan mengembalikan hasilnya. Agak hei, gunakan saja jenis multi-core. Sudut pandang saya adalah bahwa ini memberi rata-rata pengguna panda palu besar, jadi alih-alih membuat vektor (atau menggunakan cython/numba), mereka SEGERA menuju paralel ketika tidak diperlukan.

Jadi itulah keraguan saya di sini. (yang lain berpendapat bahwa Anda hanya mendokumentasikan/mendidik dan menyediakan alat). Argumen saya adalah bahwa mungkin kita TIDAK boleh melakukan ini di panda SAMA SEKALI, dan jika Anda cukup canggih untuk menggunakan eksekusi paralel, maka menggunakan dask mainline (atau ibis et al.) adalah cara yang benar untuk melakukan ini.

Pandangan saya selaras dengan @jreback di sini. Saya pikir jika data Anda sudah ada di pandas DataFrame maka eksekusi paralel yang bersemangat mungkin memberikan sebagian besar manfaat yang Anda harapkan tanpa sesuatu yang tidak terduga.

Sangat masuk akal.

Di sisi lain, untuk pengguna panda pemula yang menggunakan numba atau bahkan dask (dan terkadang bahkan membuat vektor) tidak begitu mudah sambil mendapatkan peningkatan kinerja tanpa perlu melakukan apa pun (alias opsi konfigurasi "gunakan paralel di mana saja" disetel ke True ) adalah manfaat yang sangat bagus untuk semua orang, bahkan pengguna listrik.

Saya pikir kita bisa menambahkan engine= argument

dan izinkan say: numba, dask (jika diinstal)

yang mendapatkan sebagian besar jalan ke sana

Setuju dengan komentar di atas:

Saya pikir jika data Anda sudah ada di pandas DataFrame maka eksekusi paralel yang bersemangat mungkin memberikan sebagian besar manfaat yang Anda harapkan tanpa sesuatu yang tidak terduga.

Itu mati.

Juga, saya sangat menyukai ide mesin = opsi argumen. Ini akan menjadi manfaat besar bagi sebagian besar pengguna akhir, terutama mereka yang menggunakan panda sebagai dependensi inti dalam aplikasi mereka sendiri—paralelisme langsung di seluruh .map dan .apply dengan penyertaan dependensi (ala dask) dan / atau JIT (ala numba) dan opsi konfigurasi sederhana.

Bersemangat tentang ini, dan luar biasa, semua pekerjaan di sini. Salut untuk kalian semua.

Apakah mungkin untuk mengintegrasikan panda dengan dekorator @parallel di ipyparallel, seperti contoh yang mereka miliki dengan numpy?

http://ipyparallel.readthedocs.org/en/latest/multiengine.html#remote -function-decorators

Saya pikir secara teoritis, bahkan panda tidak mendukung komputasi paralel secara default, pengguna masih dapat merujuk ke mpi4py untuk komputasi paralel. Ini hanya beberapa waktu pengkodean lagi jika seseorang sudah tahu tentang MPI.

ayo doc ini langsung ke dask

Saya mencoba groupby dan menerapkan dengan pandas 0.17.1, dan terkejut melihat fungsi tersebut diterapkan secara paralel. Saya bingung, apakah fitur ini sudah ditambahkan dan diaktifkan secara default? Saya tidak menggunakan dask.

@heroxbd yah GIL IS dirilis selama operasi groupby. Namun tidak ada paralelisme secara native/inheren dalam groupby. Mengapa menurut Anda itu paralel?

Buktinya adalah bahwa semua beban CPU saya tumbuh hingga 100% ketika saya memanggil groupby apply.
sph = tt.groupby('ev').apply(sphericity)

jadi jika Anda melakukan operasi aritmatika di dalam sphericity (misalnya df + df ) atau sejenisnya. Ini tunduk pada numexpr , yang menggunakan multi-core secara default. Bisakah Anda memberikan sketsa fungsi ini?

Ini adalah hal-hal kinerja yang dilakukan panda tanpa disadari secara khusus oleh pengguna.

@jreback Ah-ha. Ini dia:
pmtl, ql = event['pmt'].values, event['q'].values
pl = pdir[pmtl] * ql[:,np.newaxis]
s = np.sum(pl[:,:,np.newaxis] * pl[:,np.newaxis,:], axis=0)
qs = np.sum(ql _2)eig = np.sort(np.linalg.eigvals(s/qs))return pd.Series({'S': (eig[0] + eig[1])_1.5, 'A': eig[0] 1.5}) # sphericity, aplanarity

Maaf untuk kebisingan. Eksekusi paralel berasal dari OpenMP yang digunakan oleh OpenBLAS, yang pada gilirannya digunakan oleh NumPy.

menutup ini sebagai dask adalah yang paling tepat untuk ini. Tentu saja dapat menambahkan beberapa penggunaan dalam panda untuk benar-benar menggunakan dask, tetapi itu adalah masalah yang terpisah (misalnya pada grup yang cukup besar dengan (jumlah grup) menunda ke dask adalah hal yang baik)

Apakah ada alasan ketika merilis GIL dalam grup pandas dengan operasi untuk hanya mengizinkan grup terpisah oleh dan menerapkan operasi terjadi secara bersamaan daripada komputasi agregasi tingkat grup independen secara paralel?

Setelah Anda memiliki operasi grup pelepasan GIL, maka pengembang lain dapat menggunakan Pandas secara paralel. Sebenarnya cukup sulit untuk secara cerdas menuliskan algoritme untuk menangani semua grup. Saya pikir jika seseorang ingin melakukan ini untuk Panda, itu bagus. Ini adalah usaha yang cukup serius sekalipun.

Untuk melakukan ini dengan dask.dataframe

$ conda install dask
or 
$ pip install dask[dataframe]
import pandas as pd
df = ... your pandas code ...

import dask.dataframe as dd
df = dd.from_pandas(df, npartitions=20)
dd_result = df.groupby(df.A).B.mean()  # or whatever
pd_result = dd_result.compute()  # uses as many threads as you have logical cores

Tentu saja, ini tidak bekerja pada semua groupbys (seperti yang disebutkan sebelumnya, ini sangat sulit untuk dilakukan secara umum) tetapi berhasil dalam banyak kasus umum.

@mrocklin terima kasih atas tipnya. Berapa lama df = dd.from_pandas(df, npartitions=20) mengambil kerangka data dengan katakanlah 10M-100M baris? Apakah ada salinan yang terlibat? Apakah dask mendukung kolom kategoris?

Ada satu salinan yang terlibat (hanya untuk kerangka data panda lainnya). Kami secara efektif hanya melakukan dfs = df.iloc[i: i + blocksize] for i in range(0, len(df), blocksize)] . Kami juga melakukan pengurutan pada indeks sebelumnya yang, jika algoritme Anda tidak memerlukannya, Anda dapat mematikannya dengan sort=False (meskipun beberapa groupbys, terutama groupby.applys pasti akan menghargai indeks yang diurutkan .)

Umumnya panggilan from_pandas relatif murah dibandingkan dengan panggilan grup. Menyalin data dalam memori umumnya berjalan cukup cepat.

@dragoljub

Khususnya YMMV tergantung pada hal-hal seperti jumlah grup yang Anda tangani dan bagaimana Anda mempartisi

Sejumlah kecil kelompok

In [7]: N = 10000000

In [8]: ngroups = 100

In [9]: df = pd.DataFrame({'A' : np.random.randn(N), 'B' : np.random.randint(0,ngroups,size=N)})

In [10]: %timeit df.groupby('B').A.mean()
10 loops, best of 3: 161 ms per loop
In [15]: ddf = dd.from_pandas(df, npartitions=8)

In [16]: %timeit ddf.groupby(ddf.B).mean().compute()
1 loop, best of 3: 223 ms per loop

Jumlah grup yang lebih besar

In [17]: ngroups = 10000

In [18]: df = pd.DataFrame({'A' : np.random.randn(N), 'B' : np.random.randint(0,ngroups,size=N)})

In [19]: %timeit df.groupby('B').A.mean()
1 loop, best of 3: 591 ms per loop

In [21]: %timeit ddf.groupby(ddf.B).mean().compute()
1 loop, best of 3: 323 ms per loop

Dapat melakukan lebih baik jika benar-benar menggunakan indeks kami

In [32]: ddf = dd.from_pandas(df.set_index('B'), npartitions=8)

In [33]: %timeit ddf.groupby(ddf.index).mean().compute()
1 loop, best of 3: 215 ms per loop

Perhatikan bahwa ini adalah pengaturan waktu yang cukup naif. Ini adalah perhitungan _single_ yang dibagi menjadi tugas paralel yang memalukan. Umumnya Anda akan menggunakan dask untuk beberapa langkah dalam perhitungan. Jika data Anda _tidak_ muat di memori, dask itu sering dapat membantu lebih banyak.

Dalam perhitungan paralel yang memalukan, saya membuat banyak kerangka data yang harus dibuang ke disk (Ini adalah output yang diinginkan dari program). Saya mencoba melakukan perhitungan dan dumping (ke hdf5) secara paralel menggunakan joblib. Dan saya mengalami masalah HDFWrite. Perhatikan, bahwa pada titik ini, saya tidak terlalu khawatir tentang kinerja penulisan paralel.

Contoh yang menunjukkan masalahnya ada di https://github.com/rbiswas4/ParallelHDFWriteProblem

Program demo_problem.py menyertakan fungsi yang disebut pekerja(i) yang membuat kerangka data yang sangat sederhana berdasarkan input i dan menambahkannya ke file hdf. Saya melakukan ini dua kali sekali secara serial, dan sekali secara paralel menggunakan joblib.

Apa yang saya temukan adalah bahwa kasus serial selalu bekerja. Tetapi kasus paralel tidak dapat direproduksi: Terkadang berfungsi tanpa masalah dan terkadang macet. Dua file log https://github.com/rbiswas4/ParallelHDFWriteProblem/blob/master/demo.log.worked
dan
https://github.com/rbiswas4/ParallelHDFWriteProblem/blob/master/demo.log_problem
adalah dua kasus ketika bekerja dan tidak bekerja masing-masing.

Apakah ada cara yang lebih baik untuk menulis ke file hdf secara paralel dari panda yang harus saya gunakan? Apakah ini pertanyaan untuk forum lain seperti joblib dan pyTables?

@rbiswas4 Jika Anda ingin membuang banyak data ke disk secara paralel, hal termudah untuk dilakukan adalah membuat file HDF5 terpisah untuk setiap proses. Pendekatan Anda pasti akan menghasilkan data yang rusak -- lihat FAQ pytables untuk detail lebih lanjut (http://www.pytables.org/FAQ.html#can-pytables-be-used-in-concurrent-access-scenarios) . Anda mungkin juga tertarik dengan dask.

Menulis ke file terpisah adalah sesuatu yang harus saya hindari karena saya mungkin akan membuat terlalu banyak file (batas inode). Saya kira ini berarti salah satu dari yang berikut:

  • Saya seharusnya tidak melihat hdf5 sebagai format keluaran yang mungkin, tetapi menggunakan database.
  • Gunakan jumlah partisi yang lebih sedikit dan karenanya file dibuat. Ini masih sangat tidak elegan
  • pertimbangkan beberapa metodologi yang dengannya saya dapat menulis kerangka data melalui proses terpisah (saya tidak yakin bagaimana membaginya)

Tampaknya yang pertama adalah taruhan terbaik. Dan, ya saya bermaksud untuk melihat apakah saya harus menggunakan dask !

Terima kasih @shoyer

@rbiswas4 , jika Anda dapat menulis hdf5 mentah (melalui h5py) alih-alih pytables, silakan lihat di SWMR,

https://www.hdfgroup.org/HDF5/docNewFeatures/NewFeaturesSwmrDocs.html

tersedia dalam hdf5-1.10.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat