如何检查numpy矩阵的列中的所有值是不是相同?
Posted
技术标签:
【中文标题】如何检查numpy矩阵的列中的所有值是不是相同?【英文标题】:How to check if all values in the columns of a numpy matrix are the same?如何检查numpy矩阵的列中的所有值是否相同? 【发布时间】:2013-01-29 08:20:44 【问题描述】:我想检查 numpy 数组/矩阵的列中的所有值是否相同。
我尝试使用ufunc equal
中的reduce
,但似乎并非在所有情况下都有效:
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
?
感谢您的帮助!
【问题讨论】:
这个问题困扰了我一段时间。虽然@Ubuntu 的解决方案足够优雅,但尝试在 4096**3 双数组上运行它只是为了得到一个布尔数组来占用你剩下的任何内存,这并不是很愉快。我正在玩弄一个使用np.equal(a, a[:, 0, None])
的纯Python 实现,但结果是同样的问题。因此,我正在为 numpy 添加一个新函数 np.same
来处理这种情况。
【参考方案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
这样的“全局”测试。
【讨论】:
很好的答案。有没有办法在不创建掩码数组的情况下为大型数组做这样的事情?这一定是 OP 对使用reduce
的最初诉求。
我不知道有任何 NumPy 方法可以在没有临时(布尔)数组的情况下生成结果。如果您正在使用一个非常大的数组并且内存很紧,您可以将数组“分块”成多个片段(例如由 N 行组成的数组)并分别测试每个片段。然后组合并测试各个部分,汇总结果。
您可能还想查看numpy.memmap、Pytables 或h5py,以便将大型阵列存储在磁盘上,这样您就可以一次提取和处理阵列的一大块,而无需要求整个数组存储在内存中。这样你可能有更多空间用于 NumPy(通常)需要的临时数组。
嘿。感谢您对 reduce 工作原理的演练,我能够找到一种使用 reduce 的方法。即将发布。【参考方案2】:
鉴于 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)
这种方法比 ubunut 使用all
的建议限制性更强,也没有那么优雅,但如果你的输入很大,它的优点是不会创建巨大的临时数组。临时数组应该只和矩阵的第一行一样大。
编辑
基于此Q/A 和the bug I filed with numpy,提供的解决方案仅适用于您的数组包含零和一。碰巧的是,显示的bitwise_and.reduce()
操作只能返回零或一,因为bitwise_and.identity
是1
,而不是-1
。我保留这个答案,希望numpy
得到修复并且答案变得有效。
编辑
看起来实际上很快就会对 numpy 进行更改。当然是bitwise_and.identity
,也可能是reduce的可选参数。
编辑
大家好消息。 np.bitwise_and
的标识自版本 1.12.0
起已设置为 -1
。
【讨论】:
【参考方案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]])
【讨论】:
以上是关于如何检查numpy矩阵的列中的所有值是不是相同?的主要内容,如果未能解决你的问题,请参考以下文章
如何编写 R 脚本来检查直线;即,对于任何给定的行,一组列中的所有值是不是具有相同的值
如何将 numpy 数组存储在 Pandas 数据框的列中?