给定python中的阈值,有效地删除彼此接近的数组

时间:2017-03-26 22:50:21

标签: python numpy duplicates distance

我正在使用python来完成这项工作并且在这里非常客观,我想找到一个' pythonic'从数组数组中删除"复制"从阈值开始彼此接近。例如,给这个数组:

[[ 5.024,  1.559,  0.281], [ 6.198,  4.827,  1.653], [ 6.199,  4.828,  1.653]]

观察到[ 6.198, 4.827, 1.653][ 6.199, 4.828, 1.653]彼此非常接近,他们的欧几里德距离为0.0014,所以他们差不多重复#34;我想要我的最终输出只是:

[[ 5.024,  1.559,  0.281], [ 6.198,  4.827,  1.653]]

我现在的算法是:

to_delete = [];
for i in unique_cluster_centers:
    for ii in unique_cluster_centers:
        if i == ii:
            pass;
        elif np.linalg.norm(np.array(i) - np.array(ii)) <= self.tolerance:
            to_delete.append(ii);
            break;

for i in to_delete:
    try:
        uniques.remove(i);
    except:
        pass;

但它真的很慢,我想知道一些更快和&#39; pythonic&#39;解决这个问题的方法。我的容忍度是0.0001。

2 个答案:

答案 0 :(得分:2)

通用方法可能是:

def filter_quadratic(data,condition):
    result = []
    for element in data:
        if all(condition(element,other) for other in result):
            result.append(element)
    return result

这是具有条件的通用高阶filter。只有当条件满足 所有元素已经在列表*中时,才会添加该元素。

现在我们仍然需要定义条件

def the_condition(xs,ys):
    # working with squares, 2.5e-05 is 0.005*0.005 
    return sum((x-y)*(x-y) for x,y in zip(xs,ys)) > 2.5e-05

这给出了:

>>> filter_quadratic([[ 5.024,  1.559,  0.281], [ 6.198,  4.827,  1.653], [ 6.199,  4.828,  1.653]],the_condition)
[[5.024, 1.559, 0.281], [6.198, 4.827, 1.653]]

算法在 O(n 2 中运行,其中 n 是您为函数提供的元素数。但是,您可以使用 k -d树使其更高效,但这需要一些更高级的数据结构。

答案 1 :(得分:1)

如果你可以避免必须将每个列表元素与嵌套循环中的每个列表元素进行比较(这不可避免地是一个O(n ^ 2)操作),那么效率会更高。

一种方法是生成一个密钥,使得两个“几乎重复”将产生相同的密钥。然后,您只需迭代一次数据,只插入结果集中尚未存在的值。

result = {}
for row in unique_cluster_centers:
    # round each value to 2 decimal places: 
    # [5.024,  1.559,  0.281] => (5.02,  1.56,  0.28)
    # you can be inventive and, say, multiply each value by 3 before rounding
    # if you want precision other than a whole decimal point.
    key = tuple([round(v, 2) for v in row])  # tuples can be keys of a dict
    if key not in result:
        result[key] = row
return result.values()  # I suppose the order of the items is not important, you can use OrderedDict otherwise