【问题标题】:Efficient way of finding the maximum absolute value, for many columns对于许多列,找到最大绝对值的有效方法
【发布时间】: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_usern_usersn_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 我喜欢这个想法,但我不确定如何应用此方法,因为在进行聚合之前我需要将 dfid 分组。有什么想法吗?
  • 如果我执行.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


【解决方案1】:

您可以使用优化的内置操作获得每组的最大值和最小值,而不是在 groupby 期间为每个组进行(低效的)绝对最大值计算,然后才能确定哪个绝对值更高。

import pandas as pd
import numpy as np

n_rows = 1_000_000
n_cols = 1_000
df = pd.DataFrame(np.random.random((n_rows, n_cols)) - 0.5)
df["group"] = np.random.randint(0, 400, (n_rows))

df_max = df.groupby("group").max()
df_min = df.groupby("group").min()
df_absmax = pd.DataFrame(
    np.where(df_max > -df_min, df_max, df_min),
    index=df_max.index,
    columns=df_max.columns
)

上述示例的运行时间是df.groupby("group").max() 的两倍多。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-30
    • 2015-08-11
    • 1970-01-01
    • 2018-01-10
    • 2011-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多