Bagi siapa saja yang ingin menerapkan tqdm pada kode panda-berlaku paralel kustom mereka.
(Saya mencoba beberapa perpustakaan untuk paralelisasi selama bertahun-tahun, tetapi saya tidak pernah menemukan solusi paralelisasi 100%, terutama untuk fungsi yang berlaku, dan saya selalu harus kembali untuk kode "manual" saya.)
df_multi_core - ini adalah yang Anda panggil. Ia menerima:
- Objek df Anda
- Nama fungsi yang ingin Anda panggil
- Subset kolom fungsi dapat dilakukan pada (membantu mengurangi waktu / memori)
- Jumlah pekerjaan yang harus dijalankan secara paralel (-1 atau menghilangkan semua inti)
- Semua kwarg lain yang diterima fungsi df (seperti "sumbu")
_df_split - ini adalah fungsi pembantu internal yang harus diposisikan secara global ke modul yang sedang berjalan (Pool.map adalah "penempatan bergantung"), kalau tidak saya akan menemukannya secara internal ..
inilah kode dari intisari (saya akan menambahkan lebih banyak tes fungsi panda di sana):
import pandas as pd
import numpy as np
import multiprocessing
from functools import partial
def _df_split(tup_arg, **kwargs):
split_ind, df_split, df_f_name = tup_arg
return (split_ind, getattr(df_split, df_f_name)(**kwargs))
def df_multi_core(df, df_f_name, subset=None, njobs=-1, **kwargs):
if njobs == -1:
njobs = multiprocessing.cpu_count()
pool = multiprocessing.Pool(processes=njobs)
try:
splits = np.array_split(df[subset], njobs)
except ValueError:
splits = np.array_split(df, njobs)
pool_data = [(split_ind, df_split, df_f_name) for split_ind, df_split in enumerate(splits)]
results = pool.map(partial(_df_split, **kwargs), pool_data)
pool.close()
pool.join()
results = sorted(results, key=lambda x:x[0])
results = pd.concat([split[1] for split in results])
return results
Di bawah adalah kode uji untuk penerapan paralel dengan tqdm "progress_apply".
from time import time
from tqdm import tqdm
tqdm.pandas()
if __name__ == '__main__':
sep = '-' * 50
# tqdm progress_apply test
def apply_f(row):
return row['c1'] + 0.1
N = 1000000
np.random.seed(0)
df = pd.DataFrame({'c1': np.arange(N), 'c2': np.arange(N)})
print('testing pandas apply on {}\n{}'.format(df.shape, sep))
t1 = time()
res = df.progress_apply(apply_f, axis=1)
t2 = time()
print('result random sample\n{}'.format(res.sample(n=3, random_state=0)))
print('time for native implementation {}\n{}'.format(round(t2 - t1, 2), sep))
t3 = time()
# res = df_multi_core(df=df, df_f_name='apply', subset=['c1'], njobs=-1, func=apply_f, axis=1)
res = df_multi_core(df=df, df_f_name='progress_apply', subset=['c1'], njobs=-1, func=apply_f, axis=1)
t4 = time()
print('result random sample\n{}'.format(res.sample(n=3, random_state=0)))
print('time for multi core implementation {}\n{}'.format(round(t4 - t3, 2), sep))
Dalam output Anda dapat melihat 1 progress bar untuk berjalan tanpa paralelisasi, dan progress bar per-core saat berjalan dengan paralelisasi. Ada sedikit hickup dan kadang-kadang sisa core muncul sekaligus, tetapi meskipun begitu saya pikir itu berguna karena Anda mendapatkan statistik kemajuan per inti (itu / detik dan total catatan, misalnya)
Terima kasih @abcdaa untuk perpustakaan yang luar biasa ini!