【问题标题】:Is there a way to do for loops faster有没有办法更快地执行循环
【发布时间】:2020-05-23 18:02:13
【问题描述】:

我希望能够进行迭代检查列表的值的条件,该列表将只有数字作为条目。如果它通过了条件测试,那么我想将它添加到一个新列表中。不幸的是,由于并非所有值都将添加到同一个列表中,因此我认为我无法进行列表理解。

我希望能够做到这一点:

def sort(values: []):
    sum_0 = sum(values)
    len_0 = len(values)
    average_0 = sum_0 / len_0
    lesser_list_0 = []
    greater_list_0 = []
    for value in values:
        if value >= average_0:
            greater_list_0.append(value)
        else:
            lesser_list_0.append(value)

但是没有被 for 循环减慢的烦恼。另外,有没有比使用 append 方法更快的方法将值添加到任一列表的末尾?

【问题讨论】:

  • 您好,您能分享一些示例输入和预期输出吗?然后,我们可以使用它并使用timeit监控性能。
  • 我知道列表推导比执行常规 for 循环更快,但因为并非所有值都进入同一个列表,(除非所有值都相同)我不能做一个列表理解。所以我想知道是否有另一种方法可以更快地执行 for 循环。
  • 之后您打算如何使用greater_listlesser_list?即你会访问元素还是只迭代它们?视情况而定,您可以选择发电机。另外,这里是 numpy 的选择吗?如果是这样,您可能想查看numpy.partition
  • 我需要访问原始列表的值,因为我需要比较值。

标签: python performance loops


【解决方案1】:

由于您需要读取所有值来执行此计算,因此您将需要“某种循环”。你不想做的是在你关心速度的数值计算中使用 Python 循环。

我建议你看看一些专门的数值计算库。特别是,看看numpy。您可以轻松计算平均值,并且 numpy 具有非常强大的索引功能,您可以使用单个值、整数数组、布尔数组等索引数组。

检查下面的代码,我们将数组与单个标量(平均值)进行比较以获取布尔数组。然后我们可以使用这个布尔数组来仅获取原始数组中对应的布尔值为 True 的值。这将为您提供您想要的。

import numpy as np


def separate_values(values: np.ndarray):
    average = np.mean(values)

    # This will gives an array of Boolean with the same dimension of `values`
    # and True only in places where the value is lower than the average
    mask1 = values < average
    mask2 = np.logical_not(mask1)  # We could also just write `values >= average`

    # We can use the boolean mask to index the original array.
    # This will gives us an array with the elements lower than the average
    lesser = values[mask1]
    # This will gives us an array with elements greater than or equal to the average
    greater = values[mask2]

    # Returns a tuple with both arrays
    return lesser, greater


if __name__ == '__main__':
    # A random array with 5 integers in the interval (0, 10]
    values = np.random.randint(0, 10, 5)

    lesser, greater = separate_values(values)

    print("Average:", np.mean(values))
    print("Values:", values)
    print("Values < average:", lesser)
    print("Values >= average:", greater)

您需要安装 numpy 才能正常工作。可以通过pip、conda等轻松安装。

【讨论】:

  • numpy 可能很快,但这完全取决于您以后如何使用数据。如果您稍后将这些值单独处理为 python 整数,则将 numpy 整数逐个单元格转换为 python int 将失去任何性能增益。如果您只为这个特定任务将数据与 numpy 相互转换,您实际上可能会减慢速度。
【解决方案2】:

列表推导也是循环,您真正节省的只是在每一轮中查找greater_list_0.appendlesser_list_0.append。当您创建两个列表时,for 循环会更快。您可以通过预先安排您想要的两种附加方法来节省少量时间。对于下面显示的 3 个场景,我的机器上的时间是

for loop 1.0464496612548828
comprehensions 1.1907751560211182
less lookup 0.9023218154907227

而测试代码是

import random
import time

def sort(values: []):
    sum_0 = sum(values)
    len_0 = len(values)
    average_0 = sum_0 / len_0
    greater_list_0 = []
    lesser_list_0 = []
    for value in values:
        if value >= average_0:
            greater_list_0.append(value)
        else:
            lesser_list_0.append(value)

def sort2(values: []):
    sum_0 = sum(values)
    len_0 = len(values)
    average_0 = sum_0 / len_0
    greater_list_0 = [val for val in values if val >= average_0]
    lesser_list_0 = [val for val in values if val < average_0]

def sort_less_lookup(values: []):
    sum_0 = sum(values)
    len_0 = len(values)
    average_0 = sum_0 / len_0
    greater_list_0 = []
    lesser_list_0 = []
    g_append = greater_list_0.append
    l_append = lesser_list_0.append
    for value in values:
        if value >= average_0:
            g_append(value)
        else:
            l_append(value)

values = list(range(100000))
random.shuffle(values)

tries = 100
start = time.time()
for _ in range(tries):
    sort(values)
delta = time.time() - start
print('for loop', delta)

start = time.time()
for _ in range(tries):
    sort2(values)
delta = time.time() - start
print('comprehensions', delta)

start = time.time()
for _ in range(tries):
    sort_less_lookup(values)
delta = time.time() - start
print('less lookup', delta)

【讨论】:

    【解决方案3】:

    是的,您可以使用 pandas 和 numpy 库进行这些操作。 这些库针对这些操作进行了优化。 他们使用 c 数据类型和并发性以及多处理和...。

    https://pandas.pydata.org/pandas-docs/stable/10min.html

    您必须使用切片和子集。它的工作原理是这样的,但您必须参考文档: specific_value = values_mean my_dataframe[my_dataframe['values'] >= specific_value]

    您可以通过以下方式计算均值非常有效: https://www.geeksforgeeks.org/python-pandas-dataframe-mean/

    【讨论】:

    • 在我的情况下,这是加快 for 循环的唯一方法吗?
    • 您能否指出要在这些库中使用的函数名称?
    • 我编辑了答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-16
    相关资源
    最近更新 更多