对 numpy 数组进行加权计数的快速方法



我有两个形状相同的 2D numpy 数组:

idx = np.array([[1, 2, 5, 6],[1, 3, 5, 2]])
val = np.array([[0.1, 0.5, 0.3, 0.2], [0.1, 0., 0.8, 0.2]])

我知道我们可以使用np.bincount设置val作为权重:

np.bincount(idx.reshape(-1), weights=val.reshape(-1))

但这并不完全是我想要的。np.bincount索引不存在的地方放置零。在示例中,结果为:

array([0. , 0.2, 0.7, 0. , 0. , 1.1, 0.2])

但我不希望这些额外的零用于不存在的索引。我希望加权计数对应于np.unique(idx)

array([1, 2, 3, 5, 6])

我的预期结果是:

array([0.2, 0.7, 0., 1.1, 0.2])

有人有想法有效地做到这一点吗?我的idxval非常大,有超过 100 万个元素。

方法 1:

np.uniquereturn_inverse=True一起使用。

idx = np.array([[1, 2, 5, 6],[1, 3, 5, 2]])
val = np.array([[0.1, 0.5, 0.3, 0.2], [0.1, 0., 0.8, 0.2]])
unq,inv=np.unique(idx,return_inverse=True)
np.bincount(inv,val.reshape(-1))
# array([0.2, 0.7, 0. , 1.1, 0.2])

方法2:

使用二进制计数,然后删除(真正的(零。

np.bincount(idx.reshape(-1),val.reshape(-1))[np.bincount(idx.reshape(-1)).nonzero()]
# array([0.2, 0.7, 0. , 1.1, 0.2])

哪个更好将取决于idx的分布程度。

您可以有效地使用 numpy 库。

看看这个:

output = []
for i in np.unique(idx):
wt = (idx == i)
if i == 0:
zeros = wt*(idx+1)
l = np.sum(zeros*val)
else:
zeros = wt*idx
l = np.sum(zeros*val)/i
output.append(l)
print(output)

这是相当快的。我希望它有所帮助。

你可能知道,在python中使用for循环对于效率来说不是一个好主意:

您可以尝试使用 np.unique 方法索引 bincount 的输出:

>>> np.bincount(idx.reshape(-1), val.reshape(-1))[np.unique(idx)]
array([0.2, 0.7, 0. , 1.1, 0.2])

如果你只是想摆脱零,这可能是最快的方法。

成功的关键是:

  • 执行IDX到连续整数的唯一值的映射, 从0开始,
  • 根据上述映射的结果而不是IDX本身计算分箱计数。

执行此操作的代码(非常简洁且没有任何循环(是:

unq = np.unique(idx)
mapper = pd.Series(range(unq.size), index=unq)
np.bincount(mapper[idx.reshape(-1)], weights=val.reshape(-1))

对于示例数据,结果为:

array([0.2, 0.7, 0. , 1.1, 0.2])

最新更新