我有两个形状相同的 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])
有人有想法有效地做到这一点吗?我的idx
和val
非常大,有超过 100 万个元素。
方法 1:
将np.unique
与return_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])