for循环列表在python中的理解或映射

时间:2014-06-11 04:14:24

标签: python list-comprehension

我试图提高一些python代码的速度,因此尝试将标准for循环移动到列表理解或地图调用:

    buf = [0 for i in range(self.numLEDs * 3)]
    temp = [0,0,0]
    for x in range(self.numLEDs):
        r = data[x*3]
        g = data[x*3+1]
        b = data[x*3+2]
        temp[self.c_order[0]] = self.gamma[r]
        temp[self.c_order[1]] = self.gamma[g]
        temp[self.c_order[2]] = self.gamma[b]

        buf[x * 3:x * 3 + 3] = temp

c_order只是另一个列表,在本例中为[1,2,0]。它控制某些RGB像素的通道顺序。 gamma是256个元素长的列表,用于保存每个8位通道值的伽马校正值。

我想要做的是以某种方式从这段代码中完全删除任何标准for循环的使用。我设法在没有频道交换的情况下完成了这项工作,但是通过伽马校正,它的速度提高了两倍。像这样:

corrected = [gamma[i] for i in data]
buf[0:len(corrected)] = corrected

我如何在没有for循环的情况下交换列表元素的顺序?

3 个答案:

答案 0 :(得分:3)

您可以在numpy中完成所有内容,只需几行,但速度要快一些:

In [69]:

gamma=list(np.random.rand(256))
numLEDs=10
data=list(np.random.randint(0,256,30))
c_order=[0,1,2]
In [70]:

%%timeit 
buf = [0 for i in range(numLEDs * 3)]
temp = [0,0,0]
for x in range(numLEDs):
    r = data[x*3]
    g = data[x*3+1]
    b = data[x*3+2]
    temp[c_order[0]] = gamma[r]
    temp[c_order[1]] = gamma[g]
    temp[c_order[2]] = gamma[b]
    buf[x * 3:x * 3 + 3] = temp
10000 loops, best of 3: 47.3 µs per loop
In [85]:

gamma=np.array(gamma)
data=np.array(data)

In [86]:

%%timeit
data_array=data.reshape(3, -1, order='F')
np.take(gamma[data_array], c_order, axis=0).ravel(order='F')
10000 loops, best of 3: 38.3 µs per loop

当你有很多LED时,numpy版本会比loop版本快得多:

In [98]:

gamma=list(np.random.rand(256))
numLEDs=1000
data=list(np.random.randint(0,256,3000))
c_order=[0,1,2]
In [99]:

%%timeit 
buf = [0 for i in range(numLEDs * 3)]
temp = [0,0,0]
for x in range(numLEDs):
    r = data[x*3]
    g = data[x*3+1]
    b = data[x*3+2]
    temp[c_order[0]] = gamma[r]
    temp[c_order[1]] = gamma[g]
    temp[c_order[2]] = gamma[b]
    buf[x * 3:x * 3 + 3] = temp
100 loops, best of 3: 4.08 ms per loop
In [100]:

gamma=np.array(gamma)
data=np.array(data)

In [101]:

%%timeit
data_array=data.reshape(3, -1, order='F')
np.take(gamma[data_array], c_order, axis=0).ravel(order='F')
1000 loops, best of 3: 244 µs per loop

答案 1 :(得分:1)

所以你需要没有任何扩展库的纯python代码。

加速代码:

  1. 在循环中使用局部变量。
  2. 将循环更改为列表理解。
  3. 以下是代码:

    class Test(object):
    
        def __init__(self, n):
            self.numLEDs =  n
            self.c_order = [1, 2, 0]
            self.gamma = [i // 2 for i in range(256)]
    
        def do1(self, data):
            buf = [0 for i in range(self.numLEDs * 3)]
            temp = [0,0,0]
            for x in range(self.numLEDs):
                r = data[x*3]
                g = data[x*3+1]
                b = data[x*3+2]
                temp[self.c_order[0]] = self.gamma[r]
                temp[self.c_order[1]] = self.gamma[g]
                temp[self.c_order[2]] = self.gamma[b]
    
                buf[x * 3:x * 3 + 3] = temp
            return buf
    
        def do2(self, data):
            buf = [0] * (self.numLEDs * 3)
            gamma = self.gamma
            for idx, idx2 in enumerate(self.c_order):
                buf[idx2::3] = [gamma[v] for v in data[idx::3]]
            return buf
    
    import random
    random.seed(0)
    N = 1000
    t = Test(N)
    data = [random.randint(0, 255) for i in range(3*N)]
    r1 = t.do1(data)
    r2 = t.do2(data)
    print r1 == r2  # check the result
    
    %timeit t.do1(data)
    %timeit t.do2(data)
    

    输出,它快了6倍:

    True
    1000 loops, best of 3: 1.1 ms per loop
    10000 loops, best of 3: 176 µs per loop
    

答案 2 :(得分:0)

与普遍看法相反,调用map函数不会给你带来显着的加速。实际上你可能会看到更差的表现。

根据您在此部分代码中花费的时间长短,这可能是将此循环简单地移植到C的完美情况。 See here

确保您在此for循环中花费了大量时间,否则调用C代码的开销将超过任何潜在的性能提升。

如果您决定使用此代码将此代码移植到C:

,请在此处阅读一些可能的替代方案
  1. ctypes vs C extension
  2. Wrapping a C library in Python: C, Cython or ctypes?