Đối với bất cứ ai đang tìm cách áp dụng tqdm trên mã áp dụng gấu trúc song song tùy chỉnh của họ.
(Tôi đã thử một số thư viện để song song hóa trong nhiều năm, nhưng tôi chưa bao giờ tìm thấy giải pháp song song hóa 100%, chủ yếu cho chức năng áp dụng và tôi luôn phải quay lại mã "thủ công" của mình.)
df_multi_core - đây là người bạn gọi. Nó chấp nhận:
- Đối tượng df của bạn
- Tên hàm bạn muốn gọi
- Tập hợp con của cột có thể được thực hiện theo (giúp giảm thời gian / bộ nhớ)
- Số lượng công việc để chạy song song (-1 hoặc bỏ qua cho tất cả các lõi)
- Bất kỳ kwarg nào khác chức năng của df đều chấp nhận (như "trục")
_df_split - đây là chức năng của trình trợ giúp nội bộ phải được định vị toàn cầu cho mô-đun đang chạy (Pool.map là "phụ thuộc vị trí"), nếu không tôi sẽ xác định vị trí bên trong ..
đây là mã từ ý chính của tôi (Tôi sẽ thêm nhiều bài kiểm tra chức năng gấu trúc ở đó):
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
Bellow là một mã kiểm tra cho một ứng dụng song song với 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))
Trong đầu ra, bạn có thể thấy 1 thanh tiến trình để chạy mà không cần song song và các thanh tiến trình trên mỗi lõi khi chạy song song. Có một chút khó khăn và đôi khi các lõi còn lại xuất hiện cùng một lúc, nhưng ngay cả khi đó tôi nghĩ nó hữu ích vì bạn có được số liệu thống kê tiến độ trên mỗi lõi (ví dụ: nó / giây và tổng số hồ sơ)
Cảm ơn bạn @abcdaa vì thư viện tuyệt vời này!