我一直在尝试加速创建和操作非常大的数据矩阵的一段代码(大约 15,000 x 15,000;双精度类型)。目前,我认为矩阵的大小并不那么重要,因为即使对于小的 10 x 10 矩阵,我也看不到加速(事实上,对于小矩阵,编译的 cython 代码比纯 python 慢,而时间对于大型矩阵,cython 和 python 几乎相同)。请耐心等待,因为我只编写了一周的 Python 代码(新从 Matlab 转换而来),而且我只是一个不起眼的化学工程师。
代码的目标是将一维数组(长度 L)作为输入,例如:
[ 16.66 16.85 16.93 16.98 17.08 17.03 17.09 16.76 16.67 16.72]
并产生一个矩阵(高 L,宽 L-1)作为输出:
[[ 16.66 16.85 16.93 16.98 17.08 17.03 17.09 16.76 16.67]
[ 16.85 16.93 16.98 17.08 17.03 17.09 16.76 16.67 16.72]
[ 16.93 16.98 17.08 17.03 17.09 16.76 16.67 16.72 0. ]
[ 16.98 17.08 17.03 17.09 16.76 16.67 16.72 0. 0. ]
[ 17.08 17.03 17.09 16.76 16.67 16.72 0. 0. 0. ]
[ 17.03 17.09 16.76 16.67 16.72 0. 0. 0. 0. ]
[ 17.09 16.76 16.67 16.72 0. 0. 0. 0. 0. ]
[ 16.76 16.67 16.72 0. 0. 0. 0. 0. 0. ]
[ 16.67 16.72 0. 0. 0. 0. 0. 0. 0. ]
[ 16.72 0. 0. 0. 0. 0. 0. 0. 0. ]]
我希望从上面的示例和下面的代码中可以清楚地了解我想要实现的目标。该算法需要扩展到非常大的矩阵,它目前没有错误,只是很慢!
这是我的cython代码:
from scipy.sparse import spdiags
import numpy as np
cimport numpy as np
cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
def sfmat(np.ndarray[double, ndim=1] data):
cdef int h = data.shape[0]
cdef np.ndarray[double, ndim=2] m = np.zeros([h, h-1])
m = np.flipud(spdiags(np.tril(np.tile(data,[h-1,1]).T,0),range(1-h,1), h, h-1).todense())
return m
我还尝试了更详细的代码,这可能更容易阅读:
from scipy.sparse import spdiags
import numpy as np
cimport numpy as np
cimport cython
DTYPE = np.float
ctypedef np.float_t DTYPE_t
@cython.boundscheck(False)
@cython.wraparound(False)
def sfmat(np.ndarray[DTYPE_t, ndim=1] data):
assert data.dtype == DTYPE
cdef int h = data.shape[0]
cdef np.ndarray[DTYPE_t, ndim=2] m = np.zeros([h, h-1], dtype=DTYPE)
cdef np.ndarray[DTYPE_t, ndim=2] s1 = np.zeros([h, h-1], dtype=DTYPE)
cdef np.ndarray[DTYPE_t, ndim=2] s2 = np.zeros([h, h-1], dtype=DTYPE)
cdef np.ndarray[DTYPE_t, ndim=2] s3 = np.zeros([h, h-1], dtype=DTYPE)
s1 = np.tile(data,[h-1,1]).T
s2 = np.tril(s1,0)
s3 = spdiags(s2,range(1-h,1), h, h-1).todense()
m = np.flipud(s3)
return m
任何有关 cython 实施的帮助将不胜感激。如果有任何其他方法可以加速这个算法,那也会有所帮助。感谢您的任何帮助!
因为我是新手,所以这里有更多细节,这可能会或可能不会阻止我加快速度。我正在运行 64 位 Windows 7 Pro,并使用 Windows SDK C/C++ 编译器成功编译了 cython 代码。(我在这里成功地遵循了 github 上的指示)。简单的“hello world”cython 示例在 64 位模式下编译和运行良好,上面的代码也编译和运行没有错误。对于整个 15,000 x 15,000 矩阵的操作,需要 64 位架构,或者至少我相信是这样,因为在编译为 32 位后运行代码会导致内存错误。对于这个问题,请假设将矩阵分解成更小的块是不可能的。请让我知道是否需要任何其他信息来回答此问题。
干杯,科学家R
更新
我认为避免 for 循环是最好的方法,但是 spdiags 是主要瓶颈。因此,一种新算法效果更好(在我的计算机上提高了 4 倍):
import numpy as np
cimport numpy as np
cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
def sfmat(np.ndarray[double, ndim=1] data):
cdef int i
cdef np.ndarray[double, ndim=2] m = np.zeros([data.shape[0], data.shape[0]-1])
for i in range(data.shape[0]-1):
m[:,i] = np.roll(data,-i);
return m
但是 Cython 并没有对纯 Python 提供任何改进。请帮忙。正如评论员所指出的那样,除了更优化的算法之外,可能没有办法改进这一点,但我充满希望。谢谢!另外,是否有更快的算法,cython 或 python?