【问题标题】:Python performance iterating through lists, numpy arrays遍历列表、numpy 数组的 Python 性能
【发布时间】:2018-03-18 14:37:39
【问题描述】:

我正在做一个项目,我必须遍历大型数组(列表),按索引访问每个项目。 通常这涉及根据条件检查每个元素,然后可能更新其值。

我注意到与例如在 C# 中执行类似操作相比,这非常慢。这是一个简单地遍历数组并重新分配每个值的示例:

C#:

var a = new double[10000000];
var watch = System.Diagnostics.Stopwatch.StartNew();

for (int i = 0; i < a.Length; i++)
{
     a[i] = 1.0;
}      
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;
//About 40ms

Python:

a = []
for i in range(0, 10000000):
    a.append(0.0)

t1 = time.clock()

for i in range(0, 10000000):
    a[i] = 1.0

t2 = time.clock()
totalTime = t2-t1
//About 900ms 

这里的 python 代码似乎慢了 20 倍以上。 我对python比较陌生,所以我无法判断这种性能是否“正常”, 或者如果我在这里做错了什么。我正在运行 Anaconda 作为我的 python 环境,PyCharm 是我的 IDE。

注意:我曾尝试在 numpy 数组上使用 nditer,但没有显着提高性能。

非常感谢任何提示!

更新: 我刚刚比较了以下两种方法:

#timeit: 43ms
a = np.random.randn(1000,1000)
a[a < 0] = 100.0

#timeit: 1650ms
a = np.random.randn(1000,1000)
for x in np.nditer(a, op_flags=['readwrite']):
    if (x < 0):
        x[...] = 100.0

看起来第一种(矢量化)方法是这里的方法......

【问题讨论】:

  • Python 循环比许多其他语言中的对应循环慢。使用 numpy 向量化您的操作(取决于您的操作)或使用 cythonnumba 加速循环(cython 也用于 scipy,甚至更多用于 scikit-learn;流行的科学库)。
  • stackoverflow.com/questions/10712002/… 这个问题可能会有所帮助。是否以某种方式创建带有“附加”的列表效率低下?
  • nditer 不承诺性能。
  • 这里你称之为 first-approach,a[a&lt;0] = 100.0 就是 numpy 中经常提到的 vectorization
  • 谢谢@sascha,我会研究一下向量化到底指的是什么

标签: python numpy anaconda


【解决方案1】:

如果您使用numpy,则应使用numpy 数组类型,然后利用numpy 函数和广播:

如果您的特定需求是将1.0 分配给所有元素,numpy 中有一个特定功能:

import numpy as np
a = np.ones(10_000_000)

对于更通用的方法,您首先定义数组,然后分配所有不同的元素:

import numpy as np
a = np.empty(10_000_000)
a[:] = 1.0 # This uses the broadcasting

默认情况下,np.array 的类型为 double,因此所有元素都是 doubles。

另外,作为旁注,使用time 进行性能测量并不是最佳选择,因为这将使用“挂钟时间”并且可能会受到计算机中运行的其他程序的严重影响。考虑查看timeit 模块。

【讨论】:

  • 感谢您的回复,尤其是关于timeit模块的评论!干杯
  • 为什么这个答案被否决了?它有什么问题?
【解决方案2】:

Python 有很多迭代结构的好方法。如果您发现自己使用我所说的C 样式循环,那么很有可能:

for i in range(0, 10000000):
    a = [1.0] * 10000000

...你可能做错了。

在我的快速测试中,这比上面的要快 40 倍:

a = [1.0] * 10000000

即使是基本的列表理解也快 3 倍:

a = [1.0 for i in range(0, 10000000)]

如 cmets 中所述,cythonnumbanumpy 都可用于为此类工作提供各种加速。

【讨论】:

  • 感谢您的回复。我刚刚尝试了 a[a
  • 我不明白你的比较。你在做两件不同的事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-26
  • 2023-03-20
  • 1970-01-01
  • 2019-01-25
  • 2017-08-12
  • 2018-02-16
  • 2015-07-29
相关资源
最近更新 更多