如何找到满足条件(Python)的向量的最后“K”索引? (Matlab的“发现”类似物)

时间:2018-04-02 13:16:48

标签: python numpy

考虑一些载体:

import numpy as np
v = np.arange(10)

假设我们需要找到满足某些条件的最后2个索引。 例如,在Matlab中,它将被写成例如。

find(v <5 , 2,'last')
answer =    [ 3 ,    4 ]  (Note: Matlab indexing from 1)

问题:在Python中最明智的方法是什么?

“Nice”解决方案应该在找到2个所需结果时停止搜索,它不应搜索向量的所有元素。 所以np.where在这个意义上似乎并不“好”。

我们可以使用“for”轻松编写,但有没有其他方法? 我害怕使用“for”因为它可能很慢(至少在Matlab中是如此)。

3 个答案:

答案 0 :(得分:1)

即使循环被隐藏,您找到的任何解决方案都会遍历列表。在一个函数内部。 您的问题的解决方案取决于您可以做出的假设,例如列表是排序的? 对于一般情况,我从最后开始迭代循环:

def find(condition, k, v):
    indices = []
    for i, var in enumerate(reversed(v)):
        if condition(var):
            indices.append(len(v) - i - 1)
            if len(indices) >= k:
                break
    return indices

然后该条件应作为函数传递,因此您可以使用lambda:

v = range(10)
find(lambda x: x < 5, 3, v)

将输出

  

[4,3,2]

答案 1 :(得分:1)

此尝试不使用numpy,并且可能不是非常惯用。

尽管如此,如果我理解正确,zipfilterreversed都是惰性迭代器,它们只接受它们真正需要的元素。因此,你可以试试这个:

x = list(range(10))

from itertools import islice

res = reversed(list(map(
  lambda xi: xi[1], 
  islice(
    filter(
      lambda xi: xi[0] < 5, 
      zip(reversed(x), reversed(range(len(x))))
    ), 
    2
  )
)))

print(list(res))

输出:

[3, 4]

它的作用(从内到外):

  • 创建索引范围
  • 反转数组和索引
  • 使用索引
  • 压缩反转数组
  • 过滤所需的两个(value, index) - 对,按islice
  • 提取
  • 丢弃值,仅保留map
  • 的索引
  • 再次反向

即使它看起来有点怪异,但它应该都是懒惰的,并在它找到你要找的前两个元素后停止。我没有将它与一个简单的循环进行比较,也许只是使用循环会更简单,更快。

答案 2 :(得分:1)

我不知道&#34;好&#34;短暂的短路解决方案。

最有原则的方法是使用类似Cython的东西来粗暴地过度简化它为Python添加快速循环。一旦你设置了它就很容易。

如果你不想这样做,你必须雇用一些体操,如:

import numpy as np

def find_last_k(vector, condition, k, minchunk=32):
    if k > minchunk:
        minchunk = k
    l, r = vector.size - minchunk, vector.size
    found = []
    n_found = 0
    while r > 0:
        if l <= 0:
            l = 0
        found.append(l + np.where(condition(vector[l:r]))[0])
        n_found += len(found[-1])
        if n_found >= k:
            break
        l, r = 3 * l - 2 * r, l
    return np.concatenate(found[::-1])[-k:]

这会尝试平衡循环开销和numpy&#34;不灵活性&#34;通过搜索块,我们以指数方式成长,直到找到足够的命中。

不过很不错。