对于我的项目使用,我需要在二维数组中存储一定数量(~100x100)的 float 。在函数计算期间,我需要读取和写入数组,并且由于该函数确实是瓶颈(消耗 98% 的时间),所以我确实需要它很快。
我用 numpy 和 cython 做了一些实验:
import numpy
import time
cimport numpy
cimport cython
cdef int col, row
DTYPE = numpy.int
ctypedef numpy.int_t DTYPE_t
cdef numpy.ndarray[DTYPE_t, ndim=2] matrix_c = numpy.zeros([100 + 1, 100 + 1], dtype=DTYPE)
time_ = time.time()
for l in xrange(5000):
for col in xrange(100):
for row in xrange(100):
matrix_c[<unsigned int>row + 1][<unsigned int>col + 1] = matrix_c[<unsigned int>row][<unsigned int>col]
print "Numpy + cython time: {0}".format(time.time() - time_)
但我发现,尽管我进行了所有尝试,使用 python 列表的版本仍然明显更快。
使用列表的代码:
matrix = []
for i in xrange(100 + 1):
matrix.append([])
for j in xrange(100 + 1):
matrix[i].append(0)
time_ = time.time()
for l in xrange(5000):
for col in xrange(100):
for row in xrange(100):
matrix[row + 1][col + 1] = matrix[row][col]
print "list time: {0}".format(time.time() - time_)
结果:
list time: 0.0141758918762
Numpy + cython time: 0.484772920609
我是不是做错了什么?如果没有,有什么可以帮助我改善结果吗?
最佳答案
这是我的代码版本。 共有三个函数,分别处理整数数组、32位 float 组和 double float 组。
from numpy cimport ndarray as ar
cimport numpy as np
import numpy as np
cimport cython
import time
@cython.boundscheck(False)
@cython.wraparound(False)
def access_write_int(ar[int,ndim=2] c, int n):
cdef int l, col, row, h=c.shape[0], w=c.shape[1]
time_ = time.time()
for l in range(n):
for row in range(h-1):
for col in range(w-1):
c[row+1,col+1] = c[row,col]
print "Numpy + cython time: {0}".format(time.time() - time_)
@cython.boundscheck(False)
@cython.wraparound(False)
def access_write_float(ar[np.float32_t,ndim=2] c, int n):
cdef int l, col, row, h=c.shape[0], w=c.shape[1]
time_ = time.time()
for l in range(n):
for row in range(h-1):
for col in range(w-1):
c[row+1,col+1] = c[row,col]
print "Numpy + cython time: {0}".format(time.time() - time_)
@cython.boundscheck(False)
@cython.wraparound(False)
def access_write_double(ar[double,ndim=2] c, int n):
cdef int l, col, row, h=c.shape[0], w=c.shape[1]
time_ = time.time()
for l in range(n):
for row in range(h-1):
for col in range(w-1):
c[row+1,col+1] = c[row,col]
print "Numpy + cython time: {0}".format(time.time() - time_)
为了从 Python 调用这些函数,我运行这个
import numpy as np
from numpy.random import rand, randint
print "integers"
c = randint(0, high=20, size=(101,101))
access_write_int(c, 5000)
print "32 bit float"
c = rand(101, 101).astype(np.float32)
access_write_float(c, 5000)
print "double precision"
c = rand(101, 101)
access_write_double(c, 5000)
以下更改很重要:
通过使用
[i,j]
形式的索引访问数组来避免对数组进行切片。而不是[i][j]
定义变量
l
,col
,和row
,作为整数,以便 for 循环在 C 中运行。使用函数装饰器
@cython.boundscheck(False)
和 '@cython.wraparound(False)` 关闭程序关键部分的边界检查和环绕索引。这允许越界内存访问,因此您应该仅当您确定索引正确时才执行此操作。交换最里面的两个
for
循环,以便您根据数组在内存中的排列方式访问数组。对于较大的阵列来说,这会产生更大的差异。np.zeros
给出的数组np.random.rand
等通常是 C 连续的,因此行存储在连续的 block 中,并且沿着外部for
中的行改变索引会更快。循环而不是内部循环。如果您想保持 for 循环不变,请考虑在对其运行函数之前对数组进行转置,以便各列位于连续的 block 中。
关于python - python的快速二维 float 组(访问/写入),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17515630/