使用numpy数组和单个值进行比较

3
我有一个包含多个值的numpy数组"target_tokens"。我尝试接收一个与之形状相同的numpy数组,在目标令牌数组中,当我有一个特定值(即九或二)时,在该位置放置1.0。 下面是针对九的代码示例:
i_factor        = (target_tokens == 9).astype(np.float32)

结果:

[[ 0.  0.  0.  0.]
 [ 0.  0.  0.  0.]
 [ 0.  0.  1.  0.]
 [ 0.  0.  0.  0.]
 [ 0.  0.  0.  0.]...

这个不起作用:

group           = [2, 9]
i_factor        = (target_tokens in group).astype(np.float32)

结果是:

i_factor        = (target_tokens in group).astype(np.float32) 
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

为什么会这样,我如何在没有大循环的情况下仍然可以实现我的目标(实际上,该组比两个值更大)。
谢谢

1
不确定是否理解正确,那么这个怎么样:np.asarray(target_tokens)[:,None] == range(9) - Divakar
3个回答

2

您可以使用位运算符

让我们首先通过更基本的数组来简化您正在尝试实现的内容:

a = np.array([1, 2, 7, 3, 9, 6])

"以及您想要与之核对的数字:"
g = [2, 9]

获取一个由1和0组成的数组,表示每个元素是否等于g中的任一元素,我们可以使用按位或运算符'|':
((a == g[0]) | (a == g[1])).astype(np.float32)

这句话的意思是:“这给了:”
array([ 0.,  1.,  0.,  0.,  1.,  0.], dtype=float32)

这也适用于更高维的数组。
例如:
a = np.array([[1, 5, 7], [9, 3, 2], [5, 8, 9]])

这将产生具有相同 g 的结果:
array([[ 0.,  0.,  0.],
       [ 1.,  0.,  1.],
       [ 0.,  0.,  1.]], dtype=float32)

请注意,您也可以使用 np.bitwise_or() 来实现相同的效果,如果您希望 g list 的大小为任意值,则需要使用它。
如果您想让 g 可以是任何大小,除非您编写一个 for-loop 来执行它,否则不能再使用按位或运算符 '|'。因此,为了避免使用 for-loop,我们可以在 arrays 上使用 np.bitwise_or.reduce
所以对于原始的 array
a = np.array([1, 2, 7, 3, 9, 6])

但是现在使用更长的 g:
g = [1, 7, 9, 4]

我们可以使用np.bitwise_or.reduce
np.bitwise_or.reduce([a == e for e in g]).astype(np.float32)

这句话的意思是:“给出了:”。
array([ 1.,  0.,  1.,  0.,  1.,  0.], dtype=float32)

学到了很多,也喜欢它,尽管更简单的解决方案np.isin()是我在这里实现的。还是谢谢1 - Phillip Bock

2
除了@JoeIddon方案中描述的按位或运算符之外,还有几个选项。
其中一个解决方案基于@Divakar的评论:
group = [1, 9]
a = np.array([1, 1, 2, 3, 4, 1, 9, 9, 2])
(np.asarray(group)[:,None] == a).sum(axis=0)

如果您需要np.float32类型:

(np.asarray(group)[:,None] == a).sum(axis=0, dtype=np.float32)    

另一种方法是使用列表推导式,在组中对每个测试值进行相等性测试,并添加解决方案:
group = [1, 9]
a = np.array([1, 1, 2, 3, 4, 1, 9, 9, 2])
np.sum(a == g for g in group)

或者,如果你需要 np.float32 类型:

np.sum((a == g for g in group), dtype=np.float32)

无论哪种情况,答案都将是:
array([1, 1, 0, 0, 0, 1, 1, 1, 0]) # or float32

我的解决方案使用了“按位或”!不过很好地利用了“sum”,加一分。 - Joe Iddon

2

andor 一样,in 不允许广播。Python 语言要求 in 总是返回一个布尔值。此外,只有右操作数可以定义 in 的含义,并且您使用了列表,而不是数组。你正在获得 Python 列表的 in 行为。

NumPy 的 in 运算符 相当奇怪,对你来说没有用处。对于列表来说,in 更有意义,但仍然不是你所需要的。你需要 numpy.isin,它的行为类似于在其左操作数上广播的 in 测试(但不是右操作数):

numpy.isin(target_tokens, group).astype(np.float32)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接