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

时间:2018-10-03 05:12:40

标签: python numpy numpy-broadcasting

这是我想用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循环中有一个错字。

2 个答案:

答案 0 :(得分:0)

方法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的孩子,有两个(一个是发布的问题的修改版本,另一个是本文中较早版本的问题的修改版本)-

应用#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)])

答案 1 :(得分:0)

创建numpy_indexed软件包(免责声明:我是它的作者)是为了高效,简洁地解决诸如此类的问题:

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