首页 文章

Python中的MATLAB风格的find()函数

提问于
浏览
52

在MATLAB中,很容易找到满足特定条件的值的索引:

>> a = [1,2,3,1,2,3,1,2,3];
>> find(a > 2)     % find the indecies where this condition is true
[3, 6, 9]          % (MATLAB uses 1-based indexing)
>> a(find(a > 2))  % get the values at those locations
[3, 3, 3]

在Python中执行此操作的最佳方法是什么?

到目前为止,我已经提出以下建议 . 要获得值:

>>> a = [1,2,3,1,2,3,1,2,3]
>>> [val for val in a if val > 2]
[3, 3, 3]

但是,如果我想要每个值的索引,它会更复杂一些:

>>> a = [1,2,3,1,2,3,1,2,3]
>>> inds = [i for (i, val) in enumerate(a) if val > 2]
>>> inds
[2, 5, 8]
>>> [val for (i, val) in enumerate(a) if i in inds]
[3, 3, 3]

有没有更好的方法在Python中执行此操作,尤其是对于任意条件(不仅仅是'val> 2')?

我在NumPy中找到了与MATLAB“find”相同的函数,但我目前无法访问这些库 .

9 回答

  • 3

    您可以创建一个带有可调用参数的函数,该参数将在列表推导的条件部分中使用 . 然后你可以使用lambda或其他函数对象来传递你的任意条件:

    def indices(a, func):
        return [i for (i, val) in enumerate(a) if func(val)]
    
    a = [1, 2, 3, 1, 2, 3, 1, 2, 3]
    
    inds = indices(a, lambda x: x > 2)
    
    >>> inds
    [2, 5, 8]
    

    它更接近你的Matlab示例,而不必加载所有numpy .

  • 5

    在numpy你有 where

    >> import numpy as np
    >> x = np.random.randint(0, 20, 10)
    >> x
    array([14, 13,  1, 15,  8,  0, 17, 11, 19, 13])
    >> np.where(x > 10)
    (array([0, 1, 3, 6, 7, 8, 9], dtype=int64),)
    
  • 74

    或者使用numpy的非零函数:

    import numpy as np
    a    = np.array([1,2,3,4,5])
    inds = np.nonzero(a>2)
    a[inds] 
    array([3, 4, 5])
    
  • 27

    为什么不使用这个:

    [i for i in range(len(a)) if a[i] > 2]
    

    或者对于任意条件,为您的条件定义函数 f 并执行:

    [i for i in range(len(a)) if f(a[i])]
    
  • 7

    要获取具有任意条件的值,可以将 filter() 与lambda函数一起使用:

    >>> a = [1,2,3,1,2,3,1,2,3]
    >>> filter(lambda x: x > 2, a)
    [3, 3, 3]
    

    获取索引的一种可能方法是使用 enumerate() 构建包含索引和值的元组,然后过滤:

    >>> a = [1,2,3,1,2,3,1,2,3]
    >>> aind = tuple(enumerate(a))
    >>> print aind
    ((0, 1), (1, 2), (2, 3), (3, 1), (4, 2), (5, 3), (6, 1), (7, 2), (8, 3))
    >>> filter(lambda x: x[1] > 2, aind)
    ((2, 3), (5, 3), (8, 3))
    
  • 0

    我一直试图想出一个快速的方法来做这件事,这是我偶然发现的(使用numpy进行快速矢量比较):

    a_bool = numpy.array(a) > 2
    inds = [i for (i, val) in enumerate(a_bool) if val]
    

    事实证明,这比以下快得多:

    inds = [i for (i, val) in enumerate(a) if val > 2]
    

    似乎Python在numpy数组中完成比较时速度更快,而且/或者在检查事实而不是比较时更快地执行列表推导 .

    Edit:

    我正在重新审视我的代码,我遇到了一个可能更少的内存密集,更快,更简洁的方式在一行中执行此操作:

    inds = np.arange( len(a) )[ a < 2 ]
    
  • 2

    更常用于此应用程序的 numpy 例程是numpy.where();不过,我相信它与numpy.nonzero()一样 .

    import numpy
    a    = numpy.array([1,2,3,4,5])
    inds = numpy.where(a>2)
    

    要获取值,您可以存储索引并切片:

    a[inds]
    

    或者您可以将数组作为可选参数传递:

    numpy.where(a>2, a)
    

    或多个数组:

    b = numpy.array([11,22,33,44,55])
    numpy.where(a>2, a, b)
    
  • 3

    我想我可能找到了一个快速而简单的替代品 . BTW我觉得np.where()函数不是很令人满意,从某种意义上说它包含一个烦人的零元素行 .

    import matplotlib.mlab as mlab
    a = np.random.randn(1,5)
    print a
    
    >> [[ 1.36406736  1.45217257 -0.06896245  0.98429727 -0.59281957]]
    
    idx = mlab.find(a<0)
    print idx
    type(idx)
    
    >> [2 4]
    >> np.ndarray
    

    最好,达

  • 3

    Matlab的查找代码有两个参数 . 约翰的代码解释了第一个参数但不是第二个参数 . 例如,如果您想知道索引在满足条件的位置:Mtlab的函数将是:

    find(x>2,1)
    

    使用John的代码,您所要做的就是在indices函数的末尾添加一个[x],其中x是您要查找的索引号 .

    def indices(a, func):
        return [i for (i, val) in enumerate(a) if func(val)]
    
    a = [1, 2, 3, 1, 2, 3, 1, 2, 3]
    
    inds = indices(a, lambda x: x > 2)[0] #[0] being the 2nd matlab argument
    

    返回>>> 2,第一个索引超过2 .

相关问题