【问题标题】:How to optimise multi dimension numpy array calculation?如何优化多维numpy数组计算?
【发布时间】:2021-02-03 15:39:07
【问题描述】:

给定一个 5D 数组,目标是计算提取的两个数组之间的差异。为简单起见,假设测量第二个位置的差异,可以表示为btlf。这两个数组的值可以提取如下:

arr[ep, bt, mt, bd, :] - arr[ep, lf, mt, bd, :]

请注意,在上面,两个数组的第一个 (ep)、第三个 (mt) 和第四个 (bd) 轴的索引相同,只有第二个位置索引轴不同(btlf)。

基于这个需求,提出如下代码,并打包在nested_for_loop函数下:

import numpy as np
from joblib import Parallel, delayed
np.random.seed(0)

ub_lb_pair = np.tril_indices (5, -1)

arr = np.random.randn(3, 5, 4, 3, 2)
my_shape = arr.shape

def nested_for_loop():
    store_cval = np.full([my_shape[0], 10, my_shape[2], my_shape[3], my_shape[4]],
                         np.nan)  # preallocate
    for ep in range(0, my_shape[0]):
        for mt in range(0, my_shape[2]):
            for bd in range(0, my_shape[3]):
                for idx,(bt, lf) in enumerate(zip(ub_lb_pair[0], ub_lb_pair[1])):
                    store_cval[ep, idx, mt, bd, :] = arr[ep, bt, mt, bd, :] - \
                                                     arr[ep, lf, mt, bd, :]
    return store_cval


store_cval = nested_for_loop()

但是,如果可能的话,我想让代码更加紧凑和高效。

我能想到的一种方法是利用joblib parallel模块,可以如下实现,如multi_prop函数下所示。

def multi_prop(my_arr, ep):
    temp_ = np.full([10, my_shape[2], my_shape[3], my_shape[4]],
                    np.nan)
    for mt in range(0, my_shape[2]):
        for bd in range(0, my_shape[3]):
            for idx, (bt, lf) in enumerate(zip(ub_lb_pair[0], ub_lb_pair[1])):
                temp_[idx, mt, bd, :] = my_arr[ep, bt, mt, bd, :] - my_arr[ep, lf, mt, bd, :]
                x = 1
    return  temp_

dist_abs = Parallel(n_jobs=-1)(delayed(multi_prop)(arr, ep) for ep in range(0, my_shape[0]))

dist_abs = np.array(dist_abs)
bb = np.array_equal(store_cval, dist_abs)

但是,我想知道这是否是实现相同目标的更 numpythonic 方式。

【问题讨论】:

  • 为什么只对最后一个维度进行切片? arr[:,bt,:,:,:] and arr[:,lf,:,:,:] 甚至 arr[:,bt,...] and arr[:,lf,...]?
  • 假设最后一个维度的形状为 2 并且每个维度的值都为 [3,4][1,1] 。所以它们之间的差异是[2,3]。这对你有意义吗@hpaulj?

标签: python performance numpy coding-efficiency


【解决方案1】:

您根本不需要任何循环。想象一下这对花哨的索引:

bt, lf = np.tril_indices (5, -1)

你正在寻找

store_cval = arr[:, bt] - arr[:, lf]

请记住,store_cval[ep, idx, mt, bd, :] = arr[ep, bt, mt, bd, :] - arr[ep, lf, mt, bd, :] 是对最后一个索引的隐式循环。它们都是循环,你不需要它们中的任何一个。

更通用的解决方案:

def diffs(arr, axis):
    a, b = np.tril_indices(arr.shape[axis], -1)
    ind1 = [slice(None) for _ in range(arr.ndim)]
    ind2 = ind1.copy()
    ind1[axis] = a
    ind2[axis] = b
    return arr[tuple(ind1)] - arr[tuple(ind2)]

【讨论】:

  • 嗨@Mad,感谢您的详细解释。由于某种原因,我无法重现上述结果。例如,axis 的值是多少。另外,我的编译器在ind1 = [slice(None) for _ in range arr.ndim] 行上提供了警告End of statement expected。最后,你的意思是trilnp.tril_indices
  • @balandongiv。对错别字感到抱歉。现在修好了。在您的情况下,您想沿第二个轴使用组合,所以axis=1
猜你喜欢
  • 2019-11-14
  • 2021-03-03
  • 2019-05-17
  • 2019-06-16
  • 2017-09-19
  • 2012-06-26
  • 2014-05-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多