Python numpy 按条件过滤二维数组

Posted

技术标签:

【中文标题】Python numpy 按条件过滤二维数组【英文标题】:Python numpy filter two-dimensional array by condition 【发布时间】:2016-12-19 00:18:44 【问题描述】:

这里是 Python 新手,我已经阅读了 Filter rows of a numpy array? 和文档,但仍然无法弄清楚如何以 Python 方式对其进行编码。

我有的示例数组:(实际数据为 50000 x 10)

a = numpy.asarray([[2,'a'],[3,'b'],[4,'c'],[5,'d']])
filter = ['a','c']

我需要找到aa[:, 1] in filter 中的所有行。预期结果:

[[2,'a'],[4,'c']]

我当前的代码是这样的:

numpy.asarray([x for x in a if x[1] in filter ])

它工作正常,但我在某处读到它效率不高。什么是正确的 numpy 方法?

编辑:

感谢所有正确答案!不幸的是,我只能将一个标记为已接受的答案。我很惊讶numpy.in1d 没有出现在谷歌搜索numpy filter 2d array 中。

【问题讨论】:

【参考方案1】:

您可以使用可以使用np.in1d 生成的bool 索引数组。

您可以使用bools 的数组来指示是否应包含某个元素,从而沿着您想要的任何axis 索引np.ndarray。由于您要沿axis=0 进行索引,这意味着您要从最外的索引中进行选择,因此您需要具有长度为行数的一维np.array。它的每个元素都将指示是否应包含该行。

一个快速的方法是在a 的第二列使用np.in1d。您可以通过a[:, 1] 获得该列的所有元素。现在您有一个 1D np.array 其元素应根据您的过滤器进行检查。这就是np.in1d 的用途。

所以完整的代码如下所示:

import numpy as np

a = np.asarray([[2,'a'],[3,'b'],[4,'c'],[5,'d']])
filter = np.asarray(['a','c'])
a[np.in1d(a[:, 1], filter)]

或更长的形式:

import numpy as np

a = np.asarray([[2,'a'],[3,'b'],[4,'c'],[5,'d']])
filter = np.asarray(['a','c'])
mask = np.in1d(a[:, 1], filter)
a[mask]

【讨论】:

【参考方案2】:

有点复杂的纯numpy矢量化解决方案:

>>> import numpy
>>> a = numpy.asarray([[2,'a'],[3,'b'],[4,'c'],[5,'d']])
>>> filter = numpy.array(['a','c'])
>>> a[(a[:,1,None] == filter[None,:]).any(axis=1)]
array([['2', 'a'],
       ['4', 'c']], 
      dtype='|S21')

索引中的None创建了一个单例维度,因此我们可以比较a的列和filter的行,然后减少得到的布尔数组

>>> a[:,1,None] == filter[None,:]
array([[ True, False],
       [False, False],
       [False,  True],
       [False, False]], dtype=bool)

在第二个维度上使用any

【讨论】:

虽然in1d 解决方案更简单(至少在函数调用中),但理解和使用这个解决方案也很好。这是一种适用于许多其他情况的解决方案。 是的,我自己同意in1d 的解决方案更好。我不知道它的存在;甚至在回答之前尝试用谷歌搜索“矢量化输入”,但由于某种原因,找不到任何东西。 我查看了in1d 代码。我认为在这种情况下,它正在构建相同的掩码,只是在 filter 上迭代。【参考方案3】:

试试这个:

>>> a[numpy.in1d(a[:,1], filter)]
array([['2', 'a'],
       ['4', 'c']], 
      dtype='|S21')

也可以通过http://docs.scipy.org/doc/numpy/reference/generated/numpy.in1d.html

【讨论】:

【参考方案4】:

在这种情况下,len(filter)a[:,1] 足够小,np.in1d 执行迭代版本

mask = (a[:,1,None] == filter[None,:]).any(axis=1)
a[mask,:]

确实如此(改编 in1d 代码):

In [1301]: arr1=a[:,1];arr2=np.array(filter)
In [1302]: mask=np.zeros(len(arr1),dtype=np.bool)
In [1303]: for i in arr2:
      ...:     mask |= (arr1==i)
In [1304]: mask
Out[1304]: array([ True, False,  True, False], dtype=bool)

如果filter 中有更多项目,它将围绕uniqueconcatenateargsort 构建搜索,寻找重复项。

所以它的方便隐藏了相当多的复杂性。

【讨论】:

以上是关于Python numpy 按条件过滤二维数组的主要内容,如果未能解决你的问题,请参考以下文章

python 按二维数组的某行或列排序 (numpy lexsort)

Python numpy 保留已排序二维数组的索引列表

Python使用numpy函数vsplit垂直(行角度)拆分numpy数组(返回拆分后的numpy数组列表)实战:垂直拆分二维numpy数组split函数垂直拆分二维numpy数组

Python使用numpy函数hsplit水平(按列)拆分numpy数组(返回拆分后的numpy数组列表)实战:水平(按列)拆分二维numpy数组split函数水平(按列)拆分二维numpy数组

numpy如何沿维度拆分数组?

将二维 C 数组传递给 python numpy