【发布时间】:2021-02-08 12:19:43
【问题描述】:
我有以下DataFrame,
import random
import pandas as pd
random.seed(2)
n_observations_per_user = 3
n_users = 3
n_dimensions = 2
ids = []
for i in range(n_users):
ids += [i]*n_observations_per_user
data = {"id": ids}
for idim in range(n_dimensions):
data[f"dim{idim}"] = [random.uniform(-10, 10) for i in range(n_observations_per_user*n_users)]
df = pd.DataFrame(data)
df
id dim0 dim1
0 0 9.120685 2.136035
1 0 8.956550 1.624080
2 0 -8.868973 -6.832343
3 1 -8.302560 -1.386607
4 1 6.709978 -2.129364
5 1 4.719400 4.460242
6 2 3.394608 9.896391
7 2 -3.837271 8.987909
8 2 2.118883 0.883541
我需要计算每个维度(列)的最大绝对值,按id 分组。为此,我使用.agg():
abs_max_fun = lambda x: x[x.abs().idxmax()]
agg_dict_absmax = {"id": "first"}
for idim in range(n_dimensions):
agg_dict_absmax[f"dim{idim}"] = abs_max_fun
df.groupby("id").agg(agg_dict_absmax)
id dim0 dim1
id
0 0 9.120685 -6.832343
1 1 -8.302560 4.460242
2 2 -3.837271 9.896391
这是正确的。但是,当n_observations_per_user、n_users 和n_dimensions 变大时,这种聚合方法会变慢,与例如max(没有abs)相比,可以看出:
# Create new, large df, with the following:
n_observations_per_user = 100
n_users = 1000
n_dimensions = 100
# Measure time for max-abs
import time
abs_max_fun = lambda x: x[x.abs().idxmax()]
agg_dict_absmax = {"id": "first"}
for idim in range(n_dimensions):
agg_dict_absmax[f"dim{idim}"] = abs_max_fun
start = time.time()
df.groupby("id").agg(agg_dict_absmax)
end = time.time()
print(end - start)
输出:27.204503297805786
与max相比:
import time
agg_dict_max = {"id": "first"}
for idim in range(n_dimensions):
agg_dict_max[f"dim{idim}"] = "max"
start = time.time()
df.groupby("id").agg(agg_dict_max)
end = time.time()
print(end - start)
输出:0.10446596145629883
我的用例有一个更大的DataFrame(更多用户),所以我正在寻找一种解决方案,使max-abs-aggregation 可以变得更快,理想情况下与max 一样快。除非找到最大 abs 值的理论时间复杂度不允许这样做,否则这样的解决方案将是理想的。
有什么想法可以做到这一点吗?
【问题讨论】:
-
一种选择可能是找到每列的最大值和最小值。
np.where(df.max() > df.min().abs(), df.max(), df.min())之类的计算时间应该是max的几倍。 -
@Swier 我喜欢这个想法,但我不确定如何应用此方法,因为在进行聚合之前我需要将
df按id分组。有什么想法吗? -
如果我执行
.groupby('tmp_id).apply(lambda x: (np.where(x.max() > x.min().abs(), x.max(), x.min()))),它会遍历列并且与我的建议一样慢。
标签: python python-3.x pandas numpy pandas-groupby