【问题标题】:Speed up python loop加快python循环
【发布时间】:2013-04-01 00:30:46
【问题描述】:

我正在尝试加速以下 python 代码:

for j in range(4,len(var_s),3):
    mag_list.append(float(var_s[j]))
mag_list = [value for value in mag_list if value != 99.]
med_mag = np.median(mag_list)

有没有一种将两个 for 循环合并为一个的好方法?这种方式,真的很慢。我需要的是从 var_s 列表中提取每三个条目,从五分之一开始,如果该条目的值不等于 99。在结果列表中,我需要中位数。 谢谢!

【问题讨论】:

  • med_mag = np.median([v for v in map(float, var_s[4::3]) if v != 99])。不确定这是否更快,但它更短。
  • 各种var_s 是什么数据类型?你真的需要从每一个中构造一个浮点数吗?
  • 你有一个样本数据集来做一些基准测试吗?你有我的好奇心 =)
  • 我同意@TomasLycken——如果我有一些样本数据,我会做一些基准测试/测试:)

标签: python performance for-loop


【解决方案1】:
for j in range(4,len(var_s),3):
    value = float(var_s[j])
    if value != 99:
        mag_list.append(value)
med_mag = np.median(mag_list)

【讨论】:

    【解决方案2】:

    你可以试试:

    mag_list = [value for value in var_s[4::3] if value != 99.]
    

    根据var_s,您可能会使用itertools.islice(var_s,4,None,3) 做得更好,但这肯定需要定时知道。

    如果你一直坚持使用 numpy,也许你会做得更好:

    vs = np.array(var_s[4::3],dtype=np.float64)  #could slice after array conversion too ...
    med_mag = np.median(vs[vs!=99.])
    

    同样,这需要定时查看它相对于其他的表现如何。

    【讨论】:

    • 您可能还想将其转换为浮点数? float(value) for value in var_s[4::3] if value != 99.另外,如果他只需要中位数,就不需要存储中间列表。
    • 当我尝试获取 mag_list 的中位数时,使用它会出现以下错误。任何想法如何解决这个问题? med_mag = np.median(mag_list) File "/usr/lib64/python2.6/site-packages/numpy/lib/function_base.py", line 2995, in median return mean(sorted[indexer], axis=axis, out=out) File "/usr/lib64/python2.6/site-packages/numpy/core/fromnumeric.py", line 2488, in mean out=out, keepdims=keepdims) File "/usr/lib64/python2.6/site-packages/numpy/core/_methods.py", line 51, in _mean out=out, keepdims=keepdims) TypeError: cannot perform reduce with flexible type
    • @frixhax -- 我认为这与我的comment on your question 有关。您是否尝试过我发布的唯一 numpy 版本?
    • 一直使用迭代器而不是列表不是更快吗(即在适当的情况下将[] 切换到())?
    • @TomasLycken -- 我很确定 numpy 大部分时间都会在迭代器上阻塞。
    【解决方案3】:
    mag_list = filter(lambda x: x != 99, var_s[4::3])
    

    好的,这里有一些timeit 试验,全部在 Python 2.7.2 中:

    设置:

    >>> from random import seed, random
    >>> from timeit import Timer
    >>> from itertools import islice, ifilter, imap
    >>> seed(1234); var_s = [random() for _ in range(100)]
    

    使用 for 循环:

    >>> def using_for_loop():
    ...     mag_list = []
    ...     for j in xrange(4, len(var_s), 3):
    ...             value = float(var_s[j])
    ...             if value != 99: mag_list.append(value)
    ... 
    >>> Timer(using_for_loop).timeit()
    11.596584796905518
    

    使用地图和过滤器:

    >>> def using_map_filter():
    ...     map(float, filter(lambda x: x != 99, var_s[4::3]))
    ... 
    >>> Timer(using_map_filter).timeit()
    8.643505096435547
    

    使用 islice、imap、ifilter:

    >>> def using_itertools():
    ...     list(imap(float, ifilter(lambda x: x != 99, islice(var_s, 4, None, 3)))) 
    ... 
    >>> Timer(using_itertools).timeit()
    11.311019897460938
    

    使用列表推导和 islice:

    >>> def using_list_comp():
    ...     [float(v) for v in islice(var_s, 4, None, 3) if v != 99]
    ... 
    >>> Timer(using_list_comp).timeit()
    8.52650499343872
    >>> 
    

    总之,使用带有 islice 的列表推导式是最快的,其次是使用 map 和 filter 的速度稍慢。

    【讨论】:

    • 这可能比列表理解更慢,因为重复调用 lambda 函数 - Python 函数调用相对昂贵。此外,要让演员漂浮在那里,您需要使用类似map(float, filter(...)) 的东西,循环两次而不是一次,这使得这更少可能更快。
    • map 返回一个生成器(至少在 Python 3 中),所以不用担心“循环两次”。
    猜你喜欢
    • 2014-07-27
    • 1970-01-01
    • 1970-01-01
    • 2022-01-08
    • 1970-01-01
    • 2019-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多