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