改进性能python矩阵

时间:2017-02-16 07:40:41

标签: python performance numpy matrix

我有一个包含地球物理数据的大矩阵(形状:2e6,6)。在搜索矩阵中的值以分配变量之前,我有3个for循环。

我的第一个解决方案是np.where。这太慢了!我阅读it would be better以使用另一个for循环来提高性能。但是,我提出的代码甚至略慢。

有人知道如何提高性能吗?

第一个解决方案(np.where

for lat in LATS:
    for lon in LONS:
        for depth in range(1,401,1):

            node_point_line = matrix[np.where( (matrix[:,0]==lat) * (matrix[:,1]==lon) * (matrix[:,2]==depth) )][0]

            var1 = node_point_line[3]
            var2 = node_point_line[4]
            var3 = node_point_line[5]
            ...

第二个解决方案(额外for循环)

for lat in LATS:
    for lon in LONS:
        for depth in range(1,401,1):

            matrix_flat = matrix.flatten()
            for i in range( len( matrix_flat )):
                if matrix_flat[i]==lat and matrix_flat[i+1]==lon and matrix_flat[i+2]==depth:
                    var1 = matrix_flat[i+3]
                    var2 = matrix_flat[i+4]
                    var3 = matrix_flat[i+5]
                    ...

同样,两种解决方案都太慢了。我避免使用Fortran或C ++(我知道它更快)。有什么建议吗?

3 个答案:

答案 0 :(得分:0)

您的LATSLONS数组有多大?即使它们是一个元素长,那么你的程序必须执行大约1*1*400*1e6*3 ~ 1.2e9个操作,这太过分了。即使在C ++中正确实现,也可能需要一秒或更长时间。

我认为你应该优化你的算法。目前还不是很清楚你要做什么,但我的猜测是你试图找到一个矩阵中的任何位置,该矩阵在LATS列表中有纬度,经度在LONS列表中深度在1到400之间。循环的交换位置:沿外循环中的矩阵运行,然后检查所有三个条件是否成立。之后,您将能够用set纬度替换纬度列表,set查找比列表查找快得多。

答案 1 :(得分:0)

考虑到数字,只需lexsort数据阵列就可以合理有效。在开头删除所有where语句时投入了2秒。

代码段假定LATSLONS已排序:

order = np.lexsort([matrix.T][2::-1] # takes < 2 sec
sorted = matrix[order, :]

data_per_lat = np.split(sorted, sorted[:, 0].searchsorted(LATS[1:], axis=0)
for lat, dpla in zip(LATS, data_per_lat):
    data_per_lon = np.split(dpla, dpla[:, 1].searchsorted[LONS[1:], axis=0)
    for lon, dplo in zip(LONS, data_per_lon):
        depth, var1, var2, var3 = dplo.T[2:]
        # the variables are now vectors, containing all data matching lon and lat sorted by depth

答案 2 :(得分:0)

您可以使用矢量化过程压缩起始矩阵,这将使您的循环更快。

DPTH=np.arange(1,401,1)
mask=np.in1d(matrix[:,0],LATS) * np.in1d(matrix[:,1],LONS) * np.in1d(matrix[:,2],DPTH)
matrix_masked=matrix[mask]

然后只需for通过matrix_masked(复杂)或

循环nditer
for i in range(matrix_masked.shape[0]):
    var1 = matrix_masked[i,3]
   . . .