按索引拆分 numpy 值,导致形状不规则

Split numpy values by indices resulting in irregular shape

这是我想用 numpy 实现的,但不知道如何实现。明确地说,我想尽可能简洁地做到这一点。

# shape (5, 2)
data = np.array([
    [10, 20]
    [30, 50]
    [10, 10]
    [5, 13]
    [7, 7]
])

# shape (5,)
target = np.array([0, 2, 1, 0, 2])

# how to achieve this in a more numpy way
# shape(3, 2)
result = np.zeros((target.max() + 1, data.shape[1]))
for i in range(result.shape[0])):
    result[i] = data[np.where(target == i)].mean(axis=0)

我知道它可以是一条线:

result = np.array([data[np.where(target == i)].mean(axis=0)
                   for i in range(target.max() + 1)])

谢谢

编辑:for 循环中有错字。

方法#1:我们可以使用np.add.at-

def binmean_addat(data, target):
    result = np.zeros((target.max() + 1, data.shape[1]))
    np.add.at(result, target,data)
    grouped_count = np.bincount(target)
    out = result/np.bincount(target)[:,None]
    out[grouped_count==0] = 0
    return out

方法 #2: 我们还可以利用 matrix-multiplication -

def binmean_dot(data, target):
    grouped_sum = (target == np.arange(target.max() + 1)[:,None]).dot(data)
    grouped_count = np.bincount(target)
    out = np.true_divide(grouped_sum,grouped_count[:,None])
    out[grouped_count==0] = 0
    return out

方法 #3:np.add.reduceat -

def binmean_reduceat(data, target):
    sidx = target.argsort()
    grouped_count = np.bincount(target)
    grouped_sum = np.add.reduceat(data[sidx],np.r_[0,grouped_count[:-1].cumsum()])
    out = np.true_divide(grouped_sum,grouped_count[:,None])
    out[grouped_count==0] = 0
    return out

样本运行-

In [45]: data
Out[45]: 
array([[10, 20],
       [30, 50],
       [10, 10],
       [ 5, 13],
       [ 7,  7]])

In [46]: target
Out[46]: array([0, 2, 1, 0, 2])

In [47]: binmean_addat(data, target)
Out[47]: 
array([[ 7.5, 16.5],
       [10. , 10. ],
       [18.5, 28.5]])

对于玩 code-golf 的孩子,这里有两个(一个是 posted 问题的修改版本,另一个是 post 中较早的问题之一)-

应用 #1 -

(data.T.dot(target[:,None]==range(target.max()+1))/(np.bincount(target)+0.0)).T

应用 #2 -

np.array([data[target==t].mean(0) for t in range(target.max()+1)])

创建 numpy_indexed 软件包(免责声明:我是其作者)是为了高效简洁地解决以下问题:

import numpy_indexed as npi
unique, result = npi.group_by(target).mean(data)