如何根据第一项是否与第三项相同来有效地使用Python过滤元组列表?
假设我有old_data,我想要new_data:
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]]
这个数据是数百万行,我需要以相同的格式返回元组列表。
答案 0 :(得分:2)
我不确定你是如何使用你的数据的(这很重要!)但是更改为生成器可能会提升性能。
您需要做的就是将[
更改为(
。
new_data_too_slow = (x for x in old_data if x[0] != x[2])
同样,这取决于你如何使用它,但这种方法很容易胜过大多数IO操作。另外,因为它是一个生成器,你可以使用它 - 但你会使用更少的内存。
答案 1 :(得分:0)
这可以使用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