为什么在转置矩阵中列出理解节拍拉链

Wei*_*Liu 1 python performance zip list-comprehension

最近我使用python来处理一些百万大小的列表.

这里我有一个列表E,它有1,470,000个元素,每个元素是一个包含2个整数的列表.

E看起来像:[[1,3],[2,4],[4,7] ...]

我想分别得到第一列和第二列的最大数量.

我可以通过使用列表理解来获得它

m1 = max([e[0] for e in E])
m2 = max([e[1] for e in E])
return (m1, m2)
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用zip:

list(map(max, zip(*E)))
Run Code Online (Sandbox Code Playgroud)

首先我认为第二种方式应该更快,因为列表理解将建立一个大的列表(更多,2次).但事实证明列表理解速度非常快,使用zip的方法速度慢了10~20倍(使用cProfile).

我认为拉链不应该那么慢,(更重要的是,列表理解怎么能那么快?)任何人都可以告诉我原因吗?

我正在使用python 3.2

PS通过使用Windows任务管理器,我甚至看不到任何内存跟踪显示python曾创建过新的列表.必须有一个黑魔法.

NPE*_*NPE 6

我已经使用Python 2.7.3和3.3.0测试了各种方法,但我无法重现您的结果.

以下时间来自Python 2.7.3(3.3.0的结果类似):

In [31]: E = [(random.randrange(0,1000),random.randrange(0,1000)) for _ in range(1470000)]

In [32]: %timeit max([e[0] for e in E]), max([e[1] for e in E])
1 loops, best of 3: 319 ms per loop

In [33]: %timeit max(e[0] for e in E), max(e[1] for e in E)
1 loops, best of 3: 343 ms per loop

In [36]: %timeit max(E, key=operator.itemgetter(0)), max(E, key=operator.itemgetter(1))
1 loops, best of 3: 314 ms per loop

In [38]: %timeit list(map(max, zip(*E)))
1 loops, best of 3: 307 ms per loop
Run Code Online (Sandbox Code Playgroud)

我测试的所有方法都具有相同的性能.

如果你关心性能,你应该考虑使用NumPy:

In [39]: import numpy as np

In [40]: EE = np.array(E)

In [46]: %timeit EE.max(axis=0)
100 loops, best of 3: 3.21 ms per loop
Run Code Online (Sandbox Code Playgroud)

如您所见,此数据集numpy.max()比我尝试过的任何纯Python方法快约100倍.