如何检查numpy矩阵列中的所有值是否相同?
我想检查一个numpy数组或矩阵的所有列里的值是否都一样。我试着用reduce
和ufunc里的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 个回答
虽然不太优雅,但在上面的例子中也可能有效。
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]])
根据ubuntu的精彩解释,你可以用reduce
来解决你的问题,但要把它应用在bitwise_and
和bitwise_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.identity
是1
,而不是-1
。我保留这个答案,希望numpy
能修复这个问题,让答案变得有效。
编辑
看起来numpy很快会有变化。肯定会改变bitwise_and.identity
,也可能会增加一个可选参数给reduce。
编辑
好消息,大家。np.bitwise_and
的身份值已经在版本1.12.0
中设置为-1
。
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
首先比较前两个数字,1
和 0
,结果是 False
:
In [51]: np.equal.reduce([False, 0, 1])
Out[51]: True
接着将 False
和 0
进行比较,结果是 True
:
In [52]: np.equal.reduce([True, 1])
Out[52]: True
但是 True
和 1
是相等的,所以最终结果是 True
,这并不是我们想要的结果。
问题在于 reduce
尝试“局部”地累积结果,而我们想要的是像 np.all
这样的“全局”测试。