如何检查numpy矩阵列中的所有值是否相同?

48 投票
4 回答
77078 浏览
提问于 2025-04-17 15:46

我想检查一个numpy数组或矩阵的所有列里的值是否都一样。我试着用reduceufunc里的equal,但是在某些情况下好像不太管用:

In [55]: a = np.array([[1,1,0],[1,-1,0],[1,0,0],[1,1,0]])

In [56]: a
Out[56]: 
array([[ 1,  1,  0],
       [ 1, -1,  0],
       [ 1,  0,  0],
       [ 1,  1,  0]])

In [57]: np.equal.reduce(a)
Out[57]: array([ True, False,  True], dtype=bool)

In [58]: a = np.array([[1,1,0],[1,0,0],[1,0,0],[1,1,0]])

In [59]: a
Out[59]: 
array([[1, 1, 0],
       [1, 0, 0],
       [1, 0, 0],
       [1, 1, 0]])

In [60]: np.equal.reduce(a)
Out[60]: array([ True,  True,  True], dtype=bool)

为什么在第二种情况下,中间那一列的结果也显示为True,而它应该是False呢?

谢谢大家的帮助!

4 个回答

3

虽然不太优雅,但在上面的例子中也可能有效。

a = np.array([[1,1,0],[1,-1,0],[1,0,0],[1,1,0]])

计算每一行和它上面那一行的差值。

np.diff(a,axis=0)==0 

array([[ True, False,  True],
       [ True, False,  True],
       [ True, False,  True]])    
11

根据ubuntu的精彩解释,你可以用reduce来解决你的问题,但要把它应用在bitwise_andbitwise_or上,而不是equal。所以,这个方法不适用于浮点数数组:

In [60]: np.bitwise_and.reduce(a) == a[0]
Out[60]: array([ True, False,  True], dtype=bool)

In [61]: np.bitwise_and.reduce(b) == b[0]
Out[61]: array([ True, False,  True], dtype=bool)

基本上,你是在比较每一列中每个元素的二进制位。相同的位保持不变,不同的位会被设置为零。这样,任何一个在某个位上是零而不是一的数字都会改变最终的值。bitwise_and无法处理那些引入新位而不是移除位的情况:

In [62]: c = np.array([[1,0,0],[1,0,0],[1,0,0],[1,1,0]])

In [63]: c
Out[63]: 
array([[1, 0, 0],
       [1, 0, 0],
       [1, 0, 0],
       [1, 1, 0]])

In [64]: np.bitwise_and.reduce(c) == c[0]
Out[64]: array([ True,  True,  True], dtype=bool)

第二列明显是错的。我们需要用bitwise_or来捕捉新位:

In [66]: np.bitwise_or.reduce(c) == c[0]
Out[66]: array([ True, False,  True], dtype=bool)

最终答案

In [69]: np.logical_and(np.bitwise_or.reduce(a) == a[0], np.bitwise_and.reduce(a) == a[0])
Out[69]: array([ True, False,  True], dtype=bool)

In [70]: np.logical_and(np.bitwise_or.reduce(b) == b[0], np.bitwise_and.reduce(b) == b[0])
Out[70]: array([ True, False,  True], dtype=boo

In [71]: np.logical_and(np.bitwise_or.reduce(c) == c[0], np.bitwise_and.reduce(c) == c[0])
Out[71]: array([ True, False,  True], dtype=bool)

这个方法比ubuntu建议的用all的方法更严格,也不那么优雅,但它的好处是如果你的输入数据很大,就不会产生巨大的临时数组。临时数组的大小应该只和你矩阵的第一行一样。

编辑

根据这个问答和我在numpy上提交的bug,这个解决方案之所以有效,是因为你的数组只包含零和一。实际上,bitwise_and.reduce()操作只能返回零或一,因为bitwise_and.identity1,而不是-1。我保留这个答案,希望numpy能修复这个问题,让答案变得有效。

编辑

看起来numpy很快会有变化。肯定会改变bitwise_and.identity,也可能会增加一个可选参数给reduce。

编辑

好消息,大家。np.bitwise_and的身份值已经在版本1.12.0中设置为-1

79
In [45]: a
Out[45]: 
array([[1, 1, 0],
       [1, 0, 0],
       [1, 0, 0],
       [1, 1, 0]])

将每个值与第一行对应的值进行比较:

In [46]: a == a[0,:]
Out[46]: 
array([[ True,  True,  True],
       [ True, False,  True],
       [ True, False,  True],
       [ True,  True,  True]], dtype=bool)

如果一列中的所有值都是 True,那么这一列就有一个共同的值:

In [47]: np.all(a == a[0,:], axis = 0)
Out[47]: array([ True, False,  True], dtype=bool)

我们可以通过仔细分析 np.equal.reduce 在处理 [1, 0, 0, 1] 时发生了什么,来看到它的问题:

In [49]: np.equal.reduce([1, 0, 0, 1])
Out[50]: True

首先比较前两个数字,10,结果是 False

In [51]: np.equal.reduce([False, 0, 1])
Out[51]: True

接着将 False0 进行比较,结果是 True

In [52]: np.equal.reduce([True, 1])
Out[52]: True

但是 True1 是相等的,所以最终结果是 True,这并不是我们想要的结果。

问题在于 reduce 尝试“局部”地累积结果,而我们想要的是像 np.all 这样的“全局”测试。

撰写回答