![](/img/trans.png)
[英]Pandas Groupby apply function is very slow , Looping every group > applying function>adding results as new column
[英]Pandas dataframe groupby + apply + new column is slow
我有一個熊貓數據框。 我使用groupBy
(在1列上)+ apply
組合以將新列添加到數據框。 Apply調用帶有參數的自定義函數。 完整的調用如下所示:
df = df.groupby('id').apply(lambda x: customFunction(x,'searchString'))
自定義函數的工作方式如下:根據if
else
條件,新列將填充1
或0
。 然后返回該組。 有點概括,自定義函數如下所示:
def customFunction(group,searchString):
#print(group.iloc[[0]]['id'].values[0])
if len(group[(group['name'] == searchString)) > 0:
group['newColumn'] = 1
else:
group['newColumn'] = 0
return group
我的問題是,即使我不處理太多數據,該腳本也會運行相對較長的時間。 這些是我的數據的統計數據:數據框具有3130行和49列。 groupBy生成1499個單獨的組。
如果我在customFunction
輸出了一些調試文本, customFunction
觀察到通過每個組進行的實際迭代速度相當快,但是最后,要花費更長時間(比迭代本身更長的時間),直到groupBy
實際完成為止。 我認為這與從新列重新索引或重新分配新數據有關。
我的問題是:
groupBy
+ apply
需要這么長時間? 為什么實際迭代已經完成的部分要花這么長時間? 我應該避免讀返回組,因為它會花費很長時間,但是我認為這是必須的,因為我在我的customFunction
顯式生成了新數據,這就需要返回數據。
df.groupby(...).apply(...)
尚未完全向量化,因為在df.groupby(...).apply(...)
它是for .. loop
,它將對每個組應用指定的功能(在您的情況下,它將執行1499 + 1次)。
請參閱說明中為什么要應用熊貓的文檔中的注釋 ,將為第一組調用func兩次 :
在當前的實現中,在第一個組上兩次應用func調用,以確定它可以采用快速還是慢速代碼路徑。 如果func有副作用,這可能導致意外的行為,因為它們將對第一組生效兩次。
建議首先使用向量化函數,如果無法使用.apply()
作為最后的解決方案,則尋求解決方案。
IIUC可以使用以下矢量化方法:
In [43]: df
Out[43]:
id name
0 1 aaa
1 1 bbb
2 1 aaa
3 2 ccc
4 2 bbb
5 2 ccc
6 3 aaa
In [44]: searchString = 'aaa'
In [45]: df['newColumn'] = df.groupby('id')['name'] \
.transform(lambda x: x.eq(searchString).any().astype(int))
In [46]: df
Out[46]:
id name newColumn
0 1 aaa 1
1 1 bbb 1
2 1 aaa 1
3 2 ccc 0
4 2 bbb 0
5 2 ccc 0
6 3 aaa 1
70.000行DF的計時 :
In [56]: df = pd.concat([df] * 10**4, ignore_index=True)
In [57]: df.shape
Out[57]: (70000, 2)
In [58]: %timeit df.groupby('id').apply(lambda x: customFunction(x,searchString))
10 loops, best of 3: 92.4 ms per loop
In [59]: %timeit df.groupby('id')['name'].transform(lambda x: x.eq(searchString).any().astype(int))
10 loops, best of 3: 53.5 ms per loop
這是沒有groupby
另一種更有效的解決方案(針對此特定情況)
>> searchString = 'searchString'
>> df = pd.DataFrame({'id': np.random.choice(1000, 1000000)})
>> df['name'] = random_names # 1000000 random strings of len 10
>> df.loc[np.random.choice(1000000, 1000, replace=False), 'name'] = searchString
>>
>> def solution_0(x):
>> x = x.groupby('id').apply(lambda g: customFunction(g, searchString))
>>
>> def solution_1(x):
>> x['newColumn'] = x.groupby('id')['name'].transform(lambda g: g.eq(searchString).any().astype(int))
>>
>> def solution_2(x):
>> x['newColumn'] = 0
>> x.loc[x['id'].isin(x.loc[x['name'] == searchString, 'id']), 'newColumn'] = 1
>>
>> %timeit solution_0(df)
3.4 s ± 125 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>> %timeit solution_1(df)
1.47 s ± 56.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>> %timeit solution_2(df)
129 ms ± 4.33 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.