假设我有一个pandas数据帧和一个我想要应用于每一行的函数。我可以拨打df.apply(apply_fn, axis=1)
,这应该花费df
大小的线性时间。或者我可以拆分df
并使用pool.map
在每个部分上调用我的函数,然后连接结果。
我期望加速因子使用pool.map
大致等于池中的进程数(new_execution_time = original_execution_time / N,如果使用N个处理器 - 并且假设零开销)。
相反,在这个玩具示例中,使用4个处理器时,时间下降到2%左右(0.005272 / 0.230757)。我最多只期望25%。发生了什么,我不理解什么?
import numpy as np
from multiprocessing import Pool
import pandas as pd
import pdb
import time
n = 1000
variables = {"hello":np.arange(n), "there":np.random.randn(n)}
df = pd.DataFrame(variables)
def apply_fn(series):
return pd.Series({"col_5":5, "col_88":88,
"sum_hello_there":series["hello"] + series["there"]})
def call_apply_fn(df):
return df.apply(apply_fn, axis=1)
n_processes = 4 # My machine has 4 CPUs
pool = Pool(processes=n_processes)
t0 = time.process_time()
new_df = df.apply(apply_fn, axis=1)
t1 = time.process_time()
df_split = np.array_split(df, n_processes)
pool_results = pool.map(call_apply_fn, df_split)
new_df2 = pd.concat(pool_results)
t2 = time.process_time()
new_df3 = df.apply(apply_fn, axis=1) # Try df.apply a second time
t3 = time.process_time()
print("identical results: %s" % np.all(np.isclose(new_df, new_df2))) # True
print("t1 - t0 = %f" % (t1 - t0)) # I got 0.230757
print("t2 - t1 = %f" % (t2 - t1)) # I got 0.005272
print("t3 - t2 = %f" % (t3 - t2)) # I got 0.229413
我保存了上面的代码并使用python3 my_filename.py
运行它。
PS我意识到在这个玩具示例中new_df
可以以更直接的方式创建,而不使用apply。我有兴趣将类似的代码应用于更复杂的apply_fn
,而不只是添加列。
答案 0 :(得分:1)
修改(我之前的回答实际上是错误的。)
time.process_time()
(doc)仅在当前流程中测量时间(并且不包括休眠时间)。因此,不考虑在子进程中花费的时间。
我使用time.time()
运行您的代码,该代码测量实际时间(根本不显示加速)并且使用更可靠的timeit.timeit
(约50%加速)。我有4个核心。