gpt4 book ai didi

python - 列表理解、映射和 numpy.vectorize 性能

转载 作者:太空狗 更新时间:2023-10-29 17:52:42 25 4
gpt4 key购买 nike

我有一个函数 foo(i) 需要一个整数并需要大量时间来执行。以下任何一种初始化a的方式之间是否会有显着的性能差异:

a = [foo(i) for i in xrange(100)]

a = map(foo, range(100))

vfoo = numpy.vectorize(foo)
a = vfoo(range(100))

(我不在乎输出是列表还是 numpy 数组。)

有没有更好的办法?

最佳答案

  • 你为什么要优化这个?您是否编写了有效的、经过测试的代码,然后检查了您的算法 profiled你的代码,发现优化这个会有效果吗?你是否在一个深层的内部循环中这样做,你发现你正在花时间?如果没有,请不要打扰。
  • 只有通过计时,您才能知道哪个最适合您。为了以有用的方式计时,您必须将其专门用于您的实际用例。例如,您可以在列表推导式中的函数调用与内联表达式之间获得明显的性能差异;目前尚不清楚您是否真的想要前者,或者您是否将其简化为使您的案例相似。
  • 你说你最终得到的是一个 numpy 数组还是一个 list 都没有关系。 ,但如果您正在进行这种微优化,那确实很重要,因为在您之后使用它们时,它们的表现会有所不同。把你的手指放在上面可能会很棘手,所以希望它会证明整个问题还为时过早。
  • 通常最好使用正确的工具来实现清晰性、可读性等。我很少在这些事情之间做出决定。
  • 如果我需要 numpy 数组,我会使用它们。我会用它们来存储大型同构数组或多维数据。我经常使用它们,但很少在我想使用列表的地方使用。
  • 如果我使用这些,我会尽力编写已经矢量化的函数,这样我就不必使用 numpy.vectorize .例如,times_five下面可以在没有装饰的 numpy 数组上使用。
  • 如果我没有理由使用 numpy,也就是说,如果我没有解决数值数学问题或使用特殊的 numpy 功能或存储多维数组或其他任何...
  • 如果我有一个已经存在的函数,我会使用 map .这就是它的用途。
  • 如果我有一个适合小表达式的操作并且我不需要函数,我会使用列表理解。
  • 如果我只想对所有情况进行操作但实际上并不需要存储结果,我会使用普通的 for 循环。
  • 在许多情况下,我实际上会使用 map并列出推导式的惰性等效项:itertools.imap和生成器表达式。这些可以将内存使用量减少 n 倍在某些情况下,有时可以避免执行不必要的操作。


  • 如果事实证明这是性能问题所在,那么正确处理此类事情就很棘手。人们为他们的实际问题选择错误的玩具箱时间是很常见的。更糟糕的是,极其普通的人会根据它制定愚蠢的通用规则。

    考虑以下情况(timeme.py 在下面发布)
    python -m timeit "from timeme import x, times_five; from numpy import vectorize" "vectorize(times_five)(x)"
    1000 loops, best of 3: 924 usec per loop

    python -m timeit "from timeme import x, times_five" "[times_five(item) for item in x]"
    1000 loops, best of 3: 510 usec per loop

    python -m timeit "from timeme import x, times_five" "map(times_five, x)"
    1000 loops, best of 3: 484 usec per loop

    一个天真的观察者会得出结论,map 是这些选项中表现最好的,但答案仍然是“视情况而定”。考虑使用您正在使用的工具的好处的力量:列表推导式让您避免定义简单的函数;如果您在做正确的事情,numpy 可以让您在 C 中对事物进行矢量化。
    python -m timeit "from timeme import x, times_five" "[item + item + item + item + item for item in x]"
    1000 loops, best of 3: 285 usec per loop

    python -m timeit "import numpy; x = numpy.arange(1000)" "x + x + x + x + x"
    10000 loops, best of 3: 39.5 usec per loop

    但这还不是全部——还有更多。考虑算法更改的威力。它甚至可以更具戏剧性。
    python -m timeit "from timeme import x, times_five" "[5 * item for item in x]"
    10000 loops, best of 3: 147 usec per loop

    python -m timeit "import numpy; x = numpy.arange(1000)" "5 * x"
    100000 loops, best of 3: 16.6 usec per loop

    有时,算法更改可能会更有效。随着数字越来越大,这将越来越有效。
    python -m timeit "from timeme import square, x" "map(square, x)"
    10 loops, best of 3: 41.8 msec per loop

    python -m timeit "from timeme import good_square, x" "map(good_square, x)"
    1000 loops, best of 3: 370 usec per loop

    即使是现在,这一切可能与您的实际问题没有多大关系。如果你能正确使用它,看起来 numpy 非常棒,但它有它的局限性:这些 numpy 示例都没有在数组中使用实际的 Python 对象。这使必须做的事情变得复杂;甚至很多。如果我们确实可以使用 C 数据类型呢?它们不如 Python 对象健壮。它们不可为空。整数溢出。您必须做一些额外的工作来检索它们。它们是静态类型的。有时这些事情被证明是问题,甚至是出乎意料的问题。

    所以你去了:一个明确的答案。 “这取决于。”
    # timeme.py

    x = xrange(1000)

    def times_five(a):
    return a + a + a + a + a

    def square(a):
    if a == 0:
    return 0

    value = a
    for i in xrange(a - 1):
    value += a
    return value

    def good_square(a):
    return a ** 2

    关于python - 列表理解、映射和 numpy.vectorize 性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2703310/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com