从numPy数组列表中删除重复项

时间:2015-01-03 02:12:27

标签: python arrays list numpy duplicate-removal

我有一个普通的Python列表,其中包含(多维)numPy数组,它们具有相同的形状和相同数量的值。列表中的某些数组与早期的数组重复。

我遇到的问题是我要删除所有重复项,但数据类型为numPy数组的事实使这一点复杂化......

•我无法使用set(),因为numPy数组不可清除 •我无法在插入过程中检查重复项,因为数组是由函数批量生成的,并使用.extend()添加到列表中。
•numPy数组不能直接比较,而不需要使用numPy自己的函数之一,所以我不能只使用&#34;如果列表中的x&#34; ... <登记/> •列表的内容需要在流程结束时保留numPy数组;我可以比较转换为嵌套列表的数组的副本,但我不能永久地将数组转换为直接的python列表。

有关如何有效删除重复项的任何建议吗?

3 个答案:

答案 0 :(得分:3)

根据数据结构的不同,直接比较所有数组可能会更快,而不是找到一些散列数组的方法。该算法是O(n ^ 2),但每个单独的比较将比创建数组的字符串或python列表快得多。所以它取决于您需要检查的阵列数量。

例如

uniques = []
for arr in possible_duplicates:
    if not any(numpy.array_equal(arr, unique_arr) for unique_arr in uniques):
        uniques.append(arr)

答案 1 :(得分:2)

使用这里的解决方案:Most efficient property to hash for numpy array如果a是一个numpy数组,我们看到散列最适合a.tostring()。所以:

import numpy as np
arraylist = [np.array([1,2,3,4]), np.array([1,2,3,4]), np.array([1,3,2,4])]
L = {array.tostring(): array for array in arraylist}
L.values() # [array([1, 3, 2, 4]), array([1, 2, 3, 4])]

答案 2 :(得分:2)

以下是使用tuple的一种方式:

>>> import numpy as np
>>> t = [np.asarray([1, 2, 3, 4]), 
         np.asarray([1, 2, 3, 4]), 
         np.asarray([1, 1, 3, 4])]

>>> map(np.asarray, set(map(tuple, t)))
[array([1, 1, 3, 4]), array([1, 2, 3, 4])]

如果您的数组是多维的,那么首先将它们展平为1-by-whatever数组,然后使用相同的想法,并在最后重塑它们:

def to_tuple(arr):
    return tuple(arr.reshape((arr.size,)))

def from_tuple(tup, original_shape):
    np.asarray(tup).reshape(original_shape)

示例:

In [64]: t = np.asarray([[[1,2,3],[4,5,6]],
                         [[1,1,3],[4,5,6]],
                         [[1,2,3],[4,5,6]]])

In [65]: map(lambda x: from_tuple(x, t[0].shape), set(map(to_tuple, t)))
Out[65]: 
[array([[1, 2, 3],
        [4, 5, 6]]), 
 array([[1, 1, 3],
        [4, 5, 6]])]

另一种选择是在pandas.DataFrame中创建一个ndarrays(如果需要,通过重新整形将它们视为行),并使用pandas内置函数来统一行。

In [34]: t
Out[34]: [array([1, 2, 3, 4]), array([1, 2, 3, 4]), array([1, 1, 3, 4])]

In [35]: pandas.DataFrame(t).drop_duplicates().values
Out[35]: 
array([[1, 2, 3, 4],
       [1, 1, 3, 4]])

总的来说,我认为尝试使用tostring()作为准哈希函数是一个坏主意,因为你需要更多的样板代码而不是我的方法,以防止某些内容的可能性在某些dict中被分配了“哈希”键后,它们会发生变异。

如果考虑到数据的大小,重新整形和转换为tuple的速度太慢,我的感觉是,这揭示了一个更基本的问题:应用程序的设计并不能满足需求(如重复数据删除)并试图将它们塞进一些在内存中运行的Python进程可能不是正确的方法。那时,我会停下来考虑像Cassandra这样的东西,它可以在浮点(或其他)数据的大型列(或多维数组)之上轻松构建数据库索引,这不是更合理的方法。