Python 快速筛选元组列表

Python 快速筛选元组列表,python,list,Python,List,如何使用Python根据第一项与第三项是否相同高效地过滤元组列表 假设我有旧的_数据,我想要新的_数据: old_data = [(2,3,2), (3,4,4), (7,6,7), (2,1,2), (5,7,2)] new_data = [(3,4,4), (5,7,2)] 我当前的解决方案(列表理解)太慢: new_data_too_slow = [x for x in old_data if x[0] != x[2]] 这些数据有数百万行,我确实需要返回相同格式的元组列表。我不确定

如何使用Python根据第一项与第三项是否相同高效地过滤元组列表

假设我有旧的_数据,我想要新的_数据:

old_data = [(2,3,2), (3,4,4), (7,6,7), (2,1,2), (5,7,2)]

new_data = [(3,4,4), (5,7,2)]
我当前的解决方案(列表理解)太慢:

new_data_too_slow = [x for x in old_data if x[0] != x[2]]

这些数据有数百万行,我确实需要返回相同格式的元组列表。

我不确定您是如何使用数据的(这很重要!),但更改为生成器可能会提高性能

您所要做的就是将
[
s更改为
s)


同样,这取决于您如何使用它,但此方法的性能很容易超过大多数IO操作。此外,由于它是一个生成器,您只需使用一次,但使用的内存将大大减少。

使用
numpy
可以有效地完成此操作,因为它的操作是用C编写的

In [16]: import numpy as np

In [17]: old_data = [(2,3,2), (3,4,4), (7,6,7), (2,1,2), (5,7,2)]

In [18]: np_data = np.asarray(old_data)

In [19]: new_data = np_data[ np_data[:,0] != np_data[:,2 ] ]

In [20]: new_data
Out[20]: array([[3, 4, 4],
                [5, 7, 2]])
通过这种方式,第一项和第三项的比较会快得多。到
numpy
的转换不一定昂贵,因为
np.asarray
(而不仅仅是
np.array
)不复制原始数据,除非它必须复制,它只是包装原始数据

此时,
new_data
是一个
numpy
数组,如果足够的话,您可以像遍历元组列表一样对其进行迭代,但您可以轻松地将其转换为列表列表

In [22]: new_data.tolist()
Out[22]: [[3, 4, 4], [5, 7, 2]]
…然后放入具有列表理解的元组列表中(如果出于您的目的确实需要)

下面是比较部分对生成的数据的一些计时,这些数据有一百万行,所有元素为0或1

In [58]: test_data = np.random.randint( 0, 2, size=(1000000,3) )

In [59]: test_data
Out[59]: 
array([[1, 1, 0],
       [1, 0, 0],
       [0, 1, 0],
       ..., 
       [0, 0, 1],
       [0, 1, 0],
       [0, 1, 1]])

In [60]: %%timeit                                              
new_data = test_data[test_data[:,0] != test_data[:,2]]
   ....: 
10 loops, best of 3: 26.2 ms per loop

In [61]: test_data = test_data.tolist()                   

In [62]: %%timeit                                               
new_data = [ x for x in test_data if x[0] != x[2] ]
   ....: 
1 loop, best of 3: 345 ms per loop

对于纯Python,这无法更快完成。看看像numpy这样的外部库。这大约是您使用Python所能达到的最快速度。您调用“太慢”的速度有多慢?这与Python中的速度一样快。可能可以使用numy来过滤,但之后它将“缓慢地将数据转换为numpy”首先,我想知道
过滤器
是否会更快:
过滤器(lambda x:x[0]!=x[2],旧数据)
@Robᵩ 可能不会,除非映射内置函数,否则理解通常更快。在任何情况下,映射/筛选和等效列表理解之间的差异通常是微不足道的。但是,这确实有一些限制:如果您需要前面的长度,您就不走运了。@Shadow,这将占用更少的内存,但是这实际上是一个更快的操作?如前所述-这取决于。我们需要了解更多关于用例的信息,然后才能知道它是否会更快。当然可以。如果OP需要另一个物化列表,那么它最终会变得更慢,但是,如果每个过滤的元组不必保存在新的数据结构中,它可能会更快。
new_data=[…]
似乎暗示它们确实如此…@StefanPochmann在上面添加了一些计时-本来应该包括在内。谢谢。同时我也尝试了,得到了因子7左右(使用
old_data*10**7
作为测试数据)。
In [58]: test_data = np.random.randint( 0, 2, size=(1000000,3) )

In [59]: test_data
Out[59]: 
array([[1, 1, 0],
       [1, 0, 0],
       [0, 1, 0],
       ..., 
       [0, 0, 1],
       [0, 1, 0],
       [0, 1, 1]])

In [60]: %%timeit                                              
new_data = test_data[test_data[:,0] != test_data[:,2]]
   ....: 
10 loops, best of 3: 26.2 ms per loop

In [61]: test_data = test_data.tolist()                   

In [62]: %%timeit                                               
new_data = [ x for x in test_data if x[0] != x[2] ]
   ....: 
1 loop, best of 3: 345 ms per loop