Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/349.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
索引numpy数组与python append一样慢_Python_Arrays_Performance_Numpy - Fatal编程技术网

索引numpy数组与python append一样慢

索引numpy数组与python append一样慢,python,arrays,performance,numpy,Python,Arrays,Performance,Numpy,我一直被告知python的本机append是一个缓慢的函数,应该避免使用for循环。但是,经过几次小测试后,我发现当使用for循环对其进行迭代时,它的性能比numpy数组差: 第一个测试-数组/列表构造 python本机列表附加 Numpy分配数组,然后访问 结果: Python时间:179毫秒 Numpy时间:189毫秒 第二次测试-接入元件 结果 python-顺序:175毫秒 numpy-顺序:198毫秒 python-shuffled访问:2.08秒 numpy-随机存取:2.15秒

我一直被告知python的本机append是一个缓慢的函数,应该避免使用for循环。但是,经过几次小测试后,我发现当使用for循环对其进行迭代时,它的性能比numpy数组差:


第一个测试-数组/列表构造 python本机列表附加 Numpy分配数组,然后访问 结果: Python时间:179毫秒

Numpy时间:189毫秒


第二次测试-接入元件 结果 python-顺序:175毫秒

numpy-顺序:198毫秒

python-shuffled访问:2.08秒

numpy-随机存取:2.15秒

numpy-矢量化访问:1.92ms




这些结果对我来说是相当令人惊讶的,因为我认为至少由于python是链表,访问元素会比numpy慢,因为必须遵循一系列指针。还是我误解了python列表实现?还有,为什么python列表的性能要比numpy等价物稍好一些?我想大部分的低效来自于使用python for循环,但是python的append仍然比numpy的访问和分配更具竞争力。

python列表不是链表。列表对象的数据缓冲区包含指向对象(内存中其他位置)的链接/指针。因此,获取第i个
元素很容易。缓冲区也有增长空间,因此
append
只需插入新元素的链接即可。缓冲区必须周期性地重新分配,但Python可以无缝地进行管理

numpy数组也有一个1d数据缓冲区,但它包含数值(通常是
dtype
所需的字节)。获取很容易,但它必须创建一个新的python对象来“包含”值(“取消装箱”)。赋值还需要将python对象转换为将要存储的字节

一般来说,我们发现通过添加到列表(末尾有一个
np.array
call)来创建一个新数组与分配到预分配的数组具有竞争性

通过numpy数组的迭代通常比通过列表的迭代慢

我们强烈反对使用
np.append
(或某种变体)迭代地增长数组。这样每次都会生成一个新数组,并具有完整副本


在编译代码中完成迭代时,numpy数组速度很快。通常,整个数组方法都是这样。
c
代码可以迭代数据缓冲区,直接对值进行操作,而不是在每个步骤调用python对象方法。

python列表不是链表。列表对象的数据缓冲区包含指向对象(内存中其他位置)的链接/指针。因此,获取第i个
元素很容易。缓冲区也有增长空间,因此
append
只需插入新元素的链接即可。缓冲区必须周期性地重新分配,但Python可以无缝地进行管理

numpy数组也有一个1d数据缓冲区,但它包含数值(通常是
dtype
所需的字节)。获取很容易,但它必须创建一个新的python对象来“包含”值(“取消装箱”)。赋值还需要将python对象转换为将要存储的字节

一般来说,我们发现通过添加到列表(末尾有一个
np.array
call)来创建一个新数组与分配到预分配的数组具有竞争性

通过numpy数组的迭代通常比通过列表的迭代慢

我们强烈反对使用
np.append
(或某种变体)迭代地增长数组。这样每次都会生成一个新数组,并具有完整副本


在编译代码中完成迭代时,numpy数组速度很快。通常,整个数组方法都是这样。
c
代码可以在数据缓冲区上迭代,直接对值进行操作,而不是在每一步调用python对象方法。

我猜当您在循环中松开numpy时,您将失去所有性能优势。但是如果你能把它写成一个向量函数,它会比用干净的python循环更快?因此,访问它们的元素(特别是以随机顺序)会更快,因为CPU可以直接抓取内存块,而不必遵循指向元素的一系列指针?python列表不是链表。我猜,如果在循环中松开numpy,就会失去所有性能优势。但是如果你能把它写成一个向量函数,它会比用干净的python循环更快?因此,访问它们的元素(特别是以随机顺序)会更快,因为CPU可以直接获取内存块,而不必遵循指向元素的一系列指针。python列表不是链表。
def pythonAppend(n):
      x = []
      for i in range(n):
          x.append(i)
      return x

%timeit pythonAppend(1000000)
 def  numpyConstruct(n):
     x = np.zeros(n)
     for i in range(n):
         x[i] = i
     return x

%timeit numpyConstruct(1000000)
n = 1000000
x = pythonAppend(n)
arr = numpyConstruct(n)
order = arr[:]; np.random.shuffle(order); order = list(order.astype(int))

def listAccess(x):
     for i in range(len(x)):
             x[i] = i/3.
     return x

def listAccessOrder(x, order):
     for i in order:
             x[i] = i/3.
     return x

%timeit listAccess(x)
%timeit listAccess(arr)
%timeit listAccessOrder(x, order)
%timeit listAccessOrder(arr, order)
%timeit arr / 3.