Хорошо, я думаю, что вы ищете ответ - мы этого не делаем из-за векторизации в python
Рассмотрим приведенный ниже код.
Теперь по существу - python часто оптимизируется для выполнения определенных математических операций векторизованным способом (например, numpy
или pandas
), что означает - применять его ко всему вектору быстрее, чем разбивать его на куски и выполнять это тогда.
Так, например, df["A"].mul(df["B"])
будет быстрее, чем: df.apply(lambda X: X["A"]*X["B"], axis=0)
. То же самое относится и к группировке - это просто гораздо более масштабируемый способ.
Попробуйте приведенный ниже код - по сути, это то, на что вы ссылались - так что выполняйте операцию до Vs после groupby(...)
. Векторизованное решение довольно быстро масштабируется, даже если вы материализуете дополнительный столбец - чем больше строк вы обрабатываете, тем большую разницу вы увидите.
Edit
Я добавил векторизованное решение на сгруппированных данных, поэтому мы имеем:
(1) мы группируем, мы лениво оцениваем строку за строкой
(2) мы обрабатываем full df векторизованным способом, мы группируем, мы применяем встроенные в агрегирующей функции
(3) мы группируем, мы обрабатываем векторизованным способом, группа, по группе, мы делаем агрегирующую функцию
по сути - из результата, который мы видим, разбивка на куски замедляется обработка, независимо от того, идет ли речь о группах или записях, - таким образом, векторизованное решение масштабируется лучше, чем любое другое пользовательское решение, которое мы можем применить поверх.
import pandas as pd
import numpy as np
import time
x=np.random.randint(1,9,(3000,5))
df=pd.DataFrame(x, columns=[f"column{l}" for l in list("ABCDE")])
df["cat"]=np.random.choice([f"key{l}" for l in list("ABCDEFG")], size=3000)
df2=df3=df
#print(df)
s=time.time()
df.groupby("cat").apply(lambda z: np.prod(z.values, axis=1).mean()).pipe(print)
e=time.time()-s
print(f"method 1: {e} s")
s=time.time()
df2["prod"]=np.prod(df[[f"column{l}" for l in list("ABCDE")]], axis=1)
df2.groupby("cat")["prod"].mean().pipe(print)
e=time.time()-s
print(f"method 2: {e} s")
s=time.time()
df3=list(map(lambda x: (x[0], np.prod(x[1][[f"column{l}" for l in list("ABCDE")]], axis=1).mean()), df3.groupby("cat")))
print(df3)
e=time.time()-s
print(f"method 3: {e} s")