我不会说这是重复的,但您提到的相关问题是一个很好的起点。您的链接的大多数答案需要对数组进行排序,提取组开始的索引,然后在其上调用np.split。这里不是这种情况,因为它会返回大小不平衡的组列表。
相反,您可以使用np.bincount 方法。它计算每个加权值的出现次数,这实际上与 groupby sum 相同,只是输出中不存在组键。
def group_by_sum(x):
u, idx = np.unique(x[:,0], return_inverse=True)
s = np.bincount(idx, weights = x[:,1])
return np.c_[u, s]
奖金。它实际上是numpy_indexed 包中的单行器:
np.transpose(npi.group_by(x[:, 0]).sum(x[:, 1]))
基准测试
import numpy as np
import perfplot
import matplotlib.pyplot as plt
def bincount(x):
u, idx = np.unique(x[:,0], return_inverse=True)
s = np.bincount(idx, weights = x[:,1])
return np.c_[u, s]
def reduceat(x):
x = x[np.argsort(x[:, 0])]
i = np.flatnonzero(np.diff(x[:, 0]))
i = np.r_[0, i + 1]
s = np.add.reduceat(x[:, 1], i)
return np.stack((x[i, 0], s), axis=-1)
def setup(N, s):
x = np.linspace(0,1,N+1)[np.random.randint(N, size = s)]
return np.c_[x, (x**2)%1]
def build_args(k):
return {'setup': lambda x: setup(k, x),
'kernels': [bincount, reduceat],
'n_range': [2**k for k in range(1, 20)],
'title': f'Testing for x samples in [0, 1] with no more than {k} groups',
'show_progress': True,
'equality_check': False}
outs = [perfplot.bench(**build_args(n)) for n in (10, 100, 1000, 10000)]
fig = plt.figure(figsize=(20, 20))
for i in range(len(outs)):
ax = fig.add_subplot(2, 2, i + 1)
ax.grid(True, which="both")
outs[i].plot()
plt.show()