問
我想加速一個 Pandas groupby,它也在兩列上應用求和并回傳結果資料幀。
代碼
df = df.groupby(['key','code','name','period','agg_metric'], sort=False, observed=True, dropna=False)[['metricA','metricB']]\
.sum().reset_index()
(該方法目前需要 2 分鐘來處理我最大用例的資料。)
資料
總體而言,最大大小的資料幀有大約 150 萬行,在這些行上應用了 groupby。Period 和 agg_metric 可以相互推斷,其中只有 2 個 period 值(因此有 2 個 agg_metric 值)。名稱值也可以從代碼中推斷出來。
在 groupby 之后,我剩下 70 萬條記錄。如果我理解正確,速度變慢是由于處理的結果組的數量。有沒有可能的方法來矢量化這個方法并將總和應用到每個組,而不是我假設當前正在迭代的。
筆記
我試過使用groupby().agg({...})and groupby().apply(lambda),兩者花費的時間大致相同。我還嘗試洗掉一些 groupby 列,然后稍后再將它們添加回來,但這并沒有加快計算速度,因此不能保證將它們從 groupby 中洗掉。該代碼段還具有 sort=False 和 Observed=True,但兩者都沒有改善處理時間。
我已經徹底瀏覽了盡可能多的資源(尤其是這個很好的參考:Python Pandas 中的 General Groupby:Fast way)。我對矢量化還很陌生,我正在這樣做,因為我正在從我們的資料庫中卸載幾個查詢。
uj5u.com熱心網友回復:
你有什么型別的資料?看起來列metricA/ metricB的型別為object,而 Pandas 對 Python 物件執行緩慢求和,而不是對 numpy 陣列執行快速求和。嘗試將度量列轉換為float64或integer型別。
您可以使用df.info()方法檢查資料型別。
證明:
from string import ascii_letters
from time import time
import numpy as np
import pandas as pd
from numpy.random import choice
N = 1_500_000
np.random.seed(123)
letters = list(ascii_letters)
words = ["".join(choice(letters, 5)) for i in range(30)]
df = pd.DataFrame(
{
"key": choice(words, N),
"code": choice(words, N),
"name": choice(words, N),
"period": np.random.randint(0, 10, N),
"agg_metric": choice(["mean", "sum", "count"], N),
"metricA": np.random.rand(N),
"metricB": np.random.rand(N),
}
)
def aggregate(df):
return (
df.groupby(
["key", "code", "name", "period", "agg_metric"],
sort=False,
observed=True,
dropna=False,
)[["metricA", "metricB"]]
.sum()
.reset_index()
)
start = time()
df2 = aggregate(df)
print(f"sum floats took {time() - start}")
start = time()
df3 = aggregate(df.astype({"metricA": object, "metricB": object}))
print(f"sum objects took {time() - start}")
assert df2.equals(df3)
輸出:
sum floats took 0.2983248233795166
sum objects took 81.04267287254333
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/352628.html
