繁体   English   中英

加快循环迭代

[英]Speed up for loop iteration

我可以以某种方式加速 python 中的这个简单代码吗? 执行需要 0.221 秒

for some_list in some_list_of_lists:
    i = 1
    while i < len(some_list):
        a = some_list[i-1]
        b = some_list[i]
        
        i += 2
  • some_list_of_lists ~110 000 个项目
  • some_list ~10 项

cython 中的相同代码只需要 0.004 秒,我的目标是在 python 中达到 0.02 秒或更少(不使用 cython)

完整代码:

result = []
for some_list in some_list_of_lists:
    t1 = 1
    t2 = 1
    
    i = 1
    while i < len(some_list):
        a = some_list[i-1]  #int
        b = some_list[i]    #int
        
        t1 *= a
        t2 *= b
        
        i += 2 
    if t1 > t2:
        result.append(some_list)

线程和多处理都是用于加速功能并在更短的时间内完成更多工作的模块。 我不确定您会在这个示例中看到多少改进,但总的来说,这些模块非常值得了解。

多处理与线程 Python

这里的主要问题是您的实现效率非常低。

相比:

from timeit import timeit
from random import random
import numpy as np  # for a numpy solution
from math import prod  # for a better Python solution

# just some random example data that is "some list of lists" (of numbers)
example_data = [
    [random() * 10 for _ in range(100)]
    for _ in range(100)
]


def f(some_list_of_lists):
    # your code, in a function, so it's easy to time
    result = []
    for some_list in some_list_of_lists:
        t1 = 1
        t2 = 1

        i = 1
        while i < len(some_list):
            a = some_list[i - 1]  # int
            b = some_list[i]  # int

            t1 *= a
            t2 *= b

            i += 2
        if t1 > t2:
            result.append(some_list)
    return result


# the same data again, but in a numpy array
example_array = np.array(example_data)


def numpy_f(some_array):
    # this function does exactly the same, it selects those 'lists' for which
    # the product of the even elements is greater than the product of the odd ones
    return some_array[
        np.prod(some_array[:,::2], axis=1) > np.prod(some_array[:,1::2], axis=1)
    ]


def better_python_f(some_list_of_lists):
    return [
        xs for xs in some_list_of_lists if prod(xs[::2]) > prod(xs[1::2])
    ]


# showing that the results are the same
simple_example = [[2, 1, 1, 1], [1, 2, 1, 1], [2, 1, .5, 1], [.5, 1, 1, 1], [1, .5, 1, 1]]
print(f(simple_example))
print(numpy_f(np.array(simple_example)))
print(better_python_f(simple_example))

# timing running each 10,000 times on the large example data set
print('yours:', timeit(lambda: f(example_data), number=10000))
print('numpy:', timeit(lambda: numpy_f(example_array), number=10000))
print('mine :', timeit(lambda: better_python_f(example_data), number=10000))

Output:

[[2, 1, 1, 1], [1, 0.5, 1, 1]]
[[2.  1.  1.  1. ]
 [1.  0.5 1.  1. ]]
[[2, 1, 1, 1], [1, 0.5, 1, 1]]
yours: 5.2597994999996445
numpy: 0.1987909999988915
mine : 0.7029579999998532

这表明仅使用普通的 Python,无需外部库,您可以轻松获得几乎快一个数量级的速度。 我相信有人可以在 Python 中想出一个更快的方法。

然而, numpy非常适合这个,甚至我写的微不足道的解决方案也比你的快 25 倍以上 - 而且我认为在numpy应用程序方面更有经验的人可能可以使用numpy编写更快的解决方案。

这里的关键点不应该是“我需要使用 numpy,因为它很快”。 关键是你应该考虑你实际解决的是什么问题,然后决定最有效的方法是什么。

在您的情况下,代码实际执行的是“对于一系列数字系列,确定每个数字系列的偶数索引上的数字乘积是否大于奇数索引上的数字乘积,并仅保留那些案子”。 对我来说,这很快指向考虑切片、计算产品的有效方法,以及如何 select 并返回所需的结果。

better_python_f不仅完全按照它的需要做,而且代码读起来几乎就像是对问题的描述:

[
    xs for xs in some_list_of_lists if prod(xs[::2]) > prod(xs[1::2])
]

“原始列表中所有xs的列表,其中偶数元素的乘积大于奇数元素的乘积。”

当然,它确实要求您了解 Python 概念“列表理解”( x for x in.. if <condition on x> )和“切片”(例如xs[::2] ),并且该math具有相当有效的prod() function 来计算像列表这样的可迭代元素的乘积。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM