Python 有效地将列表分配给变量或变量片

Python 有效地将列表分配给变量或变量片,python,arrays,numpy,slice,Python,Arrays,Numpy,Slice,如何加快元素列表的分配?对于标量数据,答案是预先分配一个数组: import numpy as np maxTime=1000; A=np.zeros(maxTime) for t in range(maxTime): data=get_fancy_data() A[t]=data 但是,如果您的fancy_数据是一个每个时间段大小不同的列表,那么如何有效地完成这项工作 python -m timeit -s "import numpy as np; N=10**4; r=np.ran

如何加快元素列表的分配?对于标量数据,答案是预先分配一个数组:

import numpy as np
maxTime=1000; A=np.zeros(maxTime)
for t in range(maxTime): 
 data=get_fancy_data() 
 A[t]=data
但是,如果您的
fancy_数据
是一个每个时间段大小不同的列表,那么如何有效地完成这项工作

python -m timeit -s "import numpy as np; N=10**4; r=np.random.random(N); A=np.zeros(N);" \
"for i in range(N): A[:i+1] = r[:i+1]"
# 100 loops, best of 3: 14.9 msec per loop

python -m timeit -s "import numpy as np; N=10**4; r=np.random.random(N); A=np.zeros(N);" \
"for i in range(N): A = r[:i+1]"
# 1000 loops, best of 3: 1.68 msec per loop
不预先分配
A=np。第二个示例中的零(N)
不会显著改变所用的时间

我不确定为什么第二个例子更快。我怀疑
A[:I+1]
在分配之前创建了该部分的副本

我有一些代码在这样的操作中遇到了瓶颈,但找不到更快的方法

*


我注意到这与相关,因为它涉及
A[0:2]
的含义-这是修改原始数组
A
,而不是创建新数组并丢弃旧数组。然而,这个问题涉及到一种修改数组
a
的方法,这种方法比重复创建新数组
a
要快得多。我无法解开为什么我尝试预分配的纯pythonic方法没有更快的谜团,所以我决定降低级别。我决定使用Cython,所以我不必研究如何在不复制numpy数组的情况下将它们传递给纯C代码

我的解决方案是这样的:

修改数组.pyx

import numpy as np
cimport numpy as np
cimport cython
ctypedef np.float64_t DTYPE_t
@cython.boundscheck(False) # turn off bounds-checking for entire function
@cython.wraparound(False)  # turn off negative index wrapping for entire function

cpdef foo(unsigned int T, unsigned int S, np.ndarray[DTYPE_t,ndim=2] A):
 cdef size_t t,s;
 for t in range(T): 
  for s in range(S): A[t,s]=data[t,S-s];
 return 0;
def baz(unsigned int T, unsigned int S, np.ndarray[DTYPE_t,ndim=2] A):
 cdef size_t t,s;
 for t in range(T): 
  for s in range(S): A[t,s]=data[t,S-s]; 
   #n.b. Do not be tempted to try a more pythonic approach like A=data[:,::-1]:
   #it will require calls to the python interpreter and gut your speed boost.
return 0;
数组似乎是通过引用传递的,除非我弄错了(因为纯Python中不存在这个概念)。在任何情况下,对
foo
所做的任何更改都会反映在调用Python代码中。也可以使用numpy阵列执行此操作:

修改数组\u np.pyx

import numpy as np
cimport numpy as np
cimport cython
ctypedef np.float64_t DTYPE_t
@cython.boundscheck(False) # turn off bounds-checking for entire function
@cython.wraparound(False)  # turn off negative index wrapping for entire function

cpdef foo(unsigned int T, unsigned int S, np.ndarray[DTYPE_t,ndim=2] A):
 cdef size_t t,s;
 for t in range(T): 
  for s in range(S): A[t,s]=data[t,S-s];
 return 0;
def baz(unsigned int T, unsigned int S, np.ndarray[DTYPE_t,ndim=2] A):
 cdef size_t t,s;
 for t in range(T): 
  for s in range(S): A[t,s]=data[t,S-s]; 
   #n.b. Do not be tempted to try a more pythonic approach like A=data[:,::-1]:
   #it will require calls to the python interpreter and gut your speed boost.
return 0;
应该避免使用任何numpy或python函数——也就是说,应该显式循环索引,而不是使用np.sum,以确保算法可以正确地转换为C代码。
modify\u array\u np.pyx
比我在问题中给出的等效解决方案快两倍
modify_array.pyx
又快了几十个百分点。这没有我希望的那么多,但更好。如果有人有任何更快的建议,我很乐意听到

使用Python中的函数

为了便于参考,请使用以下命令行编译上述Cython代码:

cython modify\u array.pyx

它将生成一个C文件,然后您应该使用C编译器编译该文件(有关必需的includes/flags,请参阅)。然后,在python文件中:

import modify_array
import numpy as np
T=100; A=np.zeros((T,T))

for t in range(T):
 data=get_fancy_data()
 returnValue=modify_array.foo(t,data,A) #The function modifies A directly
 #Do more stuff

我无法解开为什么我尝试预分配的纯pythonic方法没有更快的谜团,所以我决定降低级别。我决定使用Cython,所以我不必研究如何在不复制numpy数组的情况下将它们传递给纯C代码

我的解决方案是这样的:

修改数组.pyx

import numpy as np
cimport numpy as np
cimport cython
ctypedef np.float64_t DTYPE_t
@cython.boundscheck(False) # turn off bounds-checking for entire function
@cython.wraparound(False)  # turn off negative index wrapping for entire function

cpdef foo(unsigned int T, unsigned int S, np.ndarray[DTYPE_t,ndim=2] A):
 cdef size_t t,s;
 for t in range(T): 
  for s in range(S): A[t,s]=data[t,S-s];
 return 0;
def baz(unsigned int T, unsigned int S, np.ndarray[DTYPE_t,ndim=2] A):
 cdef size_t t,s;
 for t in range(T): 
  for s in range(S): A[t,s]=data[t,S-s]; 
   #n.b. Do not be tempted to try a more pythonic approach like A=data[:,::-1]:
   #it will require calls to the python interpreter and gut your speed boost.
return 0;
数组似乎是通过引用传递的,除非我弄错了(因为纯Python中不存在这个概念)。在任何情况下,对
foo
所做的任何更改都会反映在调用Python代码中。也可以使用numpy阵列执行此操作:

修改数组\u np.pyx

import numpy as np
cimport numpy as np
cimport cython
ctypedef np.float64_t DTYPE_t
@cython.boundscheck(False) # turn off bounds-checking for entire function
@cython.wraparound(False)  # turn off negative index wrapping for entire function

cpdef foo(unsigned int T, unsigned int S, np.ndarray[DTYPE_t,ndim=2] A):
 cdef size_t t,s;
 for t in range(T): 
  for s in range(S): A[t,s]=data[t,S-s];
 return 0;
def baz(unsigned int T, unsigned int S, np.ndarray[DTYPE_t,ndim=2] A):
 cdef size_t t,s;
 for t in range(T): 
  for s in range(S): A[t,s]=data[t,S-s]; 
   #n.b. Do not be tempted to try a more pythonic approach like A=data[:,::-1]:
   #it will require calls to the python interpreter and gut your speed boost.
return 0;
应该避免使用任何numpy或python函数——也就是说,应该显式循环索引,而不是使用np.sum,以确保算法可以正确地转换为C代码。
modify\u array\u np.pyx
比我在问题中给出的等效解决方案快两倍
modify_array.pyx
又快了几十个百分点。这没有我希望的那么多,但更好。如果有人有任何更快的建议,我很乐意听到

使用Python中的函数

为了便于参考,请使用以下命令行编译上述Cython代码:

cython modify\u array.pyx

它将生成一个C文件,然后您应该使用C编译器编译该文件(有关必需的includes/flags,请参阅)。然后,在python文件中:

import modify_array
import numpy as np
T=100; A=np.zeros((T,T))

for t in range(T):
 data=get_fancy_data()
 returnValue=modify_array.foo(t,data,A) #The function modifies A directly
 #Do more stuff

这里没有列表。列表和NumPy数组表面上可能很相似,但它们的操作语义和性能特征非常不同。第一个修改原始数组,第二个从不修改原始数组,相反,它将原始
A
的片段重新分配给名称
A
,指定原始数组进行垃圾收集。在这种情况下,@user2357112可能会重复,我认为它们不会以任何有意义的方式重复。在这两种情况下,都有切片作为视图和切片分配。@pvg:List切片不生成视图。(一维)切片分配语义相似,但切片检索完全不同。此处没有列表。列表和NumPy数组表面上可能很相似,但它们的操作语义和性能特征非常不同。第一个修改原始数组,第二个从不修改原始数组,相反,它将原始
A
的片段重新分配给名称
A
,指定原始数组进行垃圾收集。在这种情况下,@user2357112可能会重复,我认为它们不会以任何有意义的方式重复。在这两种情况下,都有切片作为视图和切片分配。@pvg:List切片不生成视图。(1维)切片分配语义相似,但切片检索完全不同。