【问题标题】:Improve performance python matrix提高性能python矩阵
【发布时间】:2017-07-05 04:43:00
【问题描述】:

我有一个包含地球物理数据的大型矩阵(形状: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++(我知道它更快)。有什么建议吗?

【问题讨论】:

  • 不是where 很慢,而是你做了很多次。您正在迭代 3 个级别。你在用var1,var2,var3做什么?
  • 我使用这些变量来计算每个 LAT/LON 点的深度积分。
  • @Johngoldenboy 看起来这里有一个XY problem:您在尝试解决更大的问题时要求优化算法的特定部分(查找)。我建议打开一个单独的问题(可能在CS 网站上)要求更快的积分计算算法。我认为你所做的非常不理想,但很难推理,因为我不知道你到底想做什么。
  • numpy 中,我们尽量避免循环,尤其是多个级别。我们将迭代推送到快速编译的函数上,并且仅在不可能的情况下进行迭代。
  • 可能是@numba (numba.pydata.org/numba-doc/0.17.0/user/jit.html) 使用 jit 编译的方法之一。它可以为此类问题提供加速。

标签: python performance numpy matrix


【解决方案1】:

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

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_maskednditer(复杂)或

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

【讨论】:

    【解决方案2】:

    考虑到数字,仅lexsort 您的数据数组应该是相当有效的。这是在开始删除所有 where 语句时投入的 2 秒。

    代码 sn-p 假定 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
    

    【讨论】:

      【解决方案3】:

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

      我认为你应该优化你的算法。目前还不清楚您要做什么,但我的猜测是您正在尝试在矩阵中找到任何位置,该位置在您的 LATS 列表中具有纬度,在您的 LONS 列表中具有经度并且深度介于 1 和400.交换循环的位置:沿着外循环中的矩阵运行,然后检查所有三个条件是否成立。之后,您就可以用set of latitudes 替换纬度列表,set 查找比列表查找快得多。

      【讨论】:

      • 我需要使用 var1 到 var3 计算深度上的积分。 LAT 和 LON 的大小都约为 100,两者都已经是列表(set(matrix [;,1]))。您重新组织我的 for 循环可能是对的。
      • 如果两个数组都是 100 长,那么操作量是巨大的:100*100*400*1e6*3 ~ 1e13。根据硬件和优化情况,需要数小时甚至数天。
      • 没错。这就是为什么我需要优化它。
      猜你喜欢
      • 2017-11-06
      • 2018-08-19
      • 2013-09-06
      • 2022-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-09
      相关资源
      最近更新 更多