我有几个numpy数组;我想构建一个groupby方法,它将为这些数组提供组ID。然后,它将允许我根据组ID对这些数组进行索引,以对组执行操作。
例如:
import numpy as np
import pandas as pd
a = np.array([1,1,1,2,2,3])
b = np.array([1,2,2,2,3,3])
def group_np(groupcols):
groupby = np.array([''.join([str(b) for b in bs]) for bs in zip(*[c for c in groupcols])])
_, groupby = np.unique(groupby, return_invesrse=True)
return groupby
def group_pd(groupcols):
df = pd.DataFrame(groupcols[0])
for i in range(1, len(groupcols)):
df[i] = groupcols[i]
for i in range(len(groupcols)):
df[i] = df[i].fillna(-1)
return df.groupby(list(range(len(groupcols)))).grouper.group_info[0]
输出:
group_np([a,b]) -> [0, 1, 1, 2, 3, 4]
group_pd([a,b]) -> [0, 1, 1, 2, 3, 4]
有没有更有效的方法来实现它,理想情况下是纯numpy?目前的瓶颈似乎是构建一个对每个组都有唯一值的向量-目前我正在通过将每个向量的值连接为字符串来实现这一点。
我希望这适用于任何数量的输入向量,它可以有数百万个元素。
编辑:这里是另一个测试用例:
a = np.array([1,2,1,1,1,2,3,1])
b = np.array([1,2,2,2,2,3,3,2])
这里,组元素2、3、4、7应该都是相同的。
编辑2:添加一些基准。
a = np.random.randint(1, 1000, 30000000)
b = np.random.randint(1, 1000, 30000000)
c = np.random.randint(1, 1000, 30000000)
def group_np2(groupcols):
_, groupby = np.unique(np.stack(groupcols), return_inverse=True, axis=1)
return groupby
%timeit group_np2([a,b,c])
# 25.1 s +/- 1.06 s per loop (mean +/- std. dev. of 7 runs, 1 loop each)
%timeit group_pd([a,b,c])
# 21.7 s +/- 646 ms per loop (mean +/- std. dev. of 7 runs, 1 loop each)
3条答案
按热度按时间cngwdvgl1#
在数组
a
和b
上使用np.stack
之后,如果在np.unique
中将参数return_inverse
设置为True
,那么它就是您要查找的输出:你可以把
np.stack
中的[a,b]
替换为所有向量的列表。编辑:一个更快的解决方案是在
sum
的数组上使用np.unique
乘以max
加上groupcols
中所有先前数组的1的累积乘积(np.cumprod
)。例如:检查:
注意:与每个组相关联的数字可能不相同(这里我将
a
的第一个元素更改为3)但群体本身是一样的。
现在检查一下时间:
w6mmgewl2#
numpy_indexed包(dsiclaimer:我是它的作者)涵盖了这些类型的用例:
像这样传递一个索引数组的元组可以避免创建一个副本;但如果你不介意复制,你也可以使用堆叠:
wh6knrhe3#
我写了一个
group_by
函数(here)来解决另一个问题。该功能非常灵活,可以解决您要求的问题:我想指出的是,公认的答案并没有回答你关于列举这些群体的问题。它在计算逆指数。但它确实突出了
np.unique
的参数axis
,这是最关键的一点。