首页 > 解决方案 > 使用 Cython 循环?或更好的方法来删除落入给定范围内的元素

问题描述

我基本上是在寻找一种更快/更好/有效的方式来执行我的一段 python 代码。

这是我的部分代码的更简单版本。

import numpy as np

A = np.random.choice(100,80) # randomly select integers
A = np.sort(A) # sort it
B = np.unique(A) # drop the duplicate values

我想用这个向量 B 做的是从前一个值中删除它在给定范围内的元素。例如,如果我有一个排序的向量B = [1,2,5,7,8,11,20,25,30]并且我想分配的范围值为 10,那么我的代码应该输出C = [1,11,25]. (2,5,7,8 被删除,因为它与元素 1 的距离小于 10。下一个元素是 11。20 被删除,因为 20 与元素 11 的距离小于 10。下一个是 25,所以 30 是删除)。你明白了。

我写的代码如下:

def RemoveViolations(vec, L):
    S = []
    P = 0 # pointer
    C = 0 # counter
    while C < vec.size:
        S.append(vec[C])
        preC = np.where(vec>S[P]+L)[0]
        if preC.size:
            C = preC[0]
        else:
            C = vec.size+1
        P = P+1

    return np.asarray(S)

所以,现在,我可以做到这一点C = RemoveViolations(B,10),这就像一个魅力。

现在,问题是这是 python 中非常慢的代码。我喜欢一个大小为 100 万的排序向量,完成这段代码需要一些时间。有没有更好的方法来完成这项任务?

如果我需要实现 Cython,我将如何更改代码以在 C++ 环境中工作?我听说这并不复杂,但快速搜索效果不佳。

谢谢!

标签: pythonwhile-loopcython

解决方案


0.15s您的算法的复杂性是问题所在:这是在我 8 岁的笔记本电脑上执行的纯 Python 解决方案(您的实现需要 200 秒;对于 n=1000000,i/ea 提高了 1300 倍):

import random


def get_filtered_values(dist, seq):

    prev_val = seq[0]
    compare_to = prev_val + dist
    filtered = [prev_val]

    for elt in seq[1:]:
        if elt <= compare_to:           # <-- change to `<` to match desired results; 
                                        # this matches the results of your implementation 
            continue
        else:
            compare_to = elt + dist
            filtered.append(elt)
    return filtered


B = [1,2,5,7,8,11,20,25,30]
print(get_filtered_values(10, B))

n = 1000000
C = sorted(list(set([random.randint(0, n) for _ in range(n)])))
get_filtered_values(10, C)

您可以对这段代码进行cythonize,或者根据需要对其进行numpyize,但这可能不是必需的。


推荐阅读