如何将此函数矢量化



我有一个NumPy数组,具有以下属性:

  • 形状:(9986080,2(
  • 数据类型:np.float32

我有一个方法,它在数组的范围内循环,执行一个操作,然后将结果输入到新数组:

def foo(arr):
new_arr = np.empty(arr.size, dtype=np.uint64)
for i in range(arr.size):
x, y = arr[i]
e, n = ''
if x < 0:
e = '1'
else:
w = '2'
if y > 0:
n = '3'
else:
s = '4'
new_arr[i] = int(f'{abs(x)}{e}{abs(y){n}'.replace('.', ''))

我同意Iguananaut的评论,即这种数据结构看起来有点奇怪。我最大的问题是,尝试将整数放在字符串中进行矢量化,然后将其重新转换为整数,这真的很棘手。尽管如此,这肯定有助于加快功能:

def foo(arr):
x_values = arr[:,0]
y_values = arr[:,1]
ones = np.ones(arr.shape[0], dtype=np.uint64)
e = np.char.array(np.where(x_values < 0, ones, ones * 2))
n = np.char.array(np.where(y_values < 0, ones * 3, ones * 4))
x_values = np.char.array(np.absolute(x_values))
y_values = np.char.array(np.absolute(y_values))
x_values = np.char.replace(x_values, '.', '')
y_values = np.char.replace(y_values, '.', '')
new_arr = np.char.add(np.char.add(x_values, e), np.char.add(y_values, n))
return new_arr.astype(np.uint64)

这里,首先对输入数组的x和y值进行拆分。然后,我们使用矢量化计算来确定en应该是1或2、3或4。最后一行使用标准的列表理解来执行字符串合并位,这对于超大数组来说仍然非常慢,但比常规的for循环更快。此外,对之前的计算进行矢量化应该会大大加快函数的速度。

编辑:我以前弄错了。Numpy使用np.char.add((方法确实有一种很好的处理字符串连接的方法。这需要使用np.char.array()x_valuesy_values转换为Numpy字符数组。同样由于某些原因,np.char.add()方法只取两个数组作为输入,因此有必要首先连接x_valuese以及y_valuesn,然后连接这些结果。尽管如此,这将使计算矢量化,并且应该非常快。由于您要执行的操作相当奇怪,代码仍然有点笨拙,但我认为这将大大帮助您加快函数的速度。

您可以使用np.apply_along_axis。当您为该函数提供另一个以行(或列(为参数的函数时,它会执行您想要执行的操作。

对于您的情况,您可以将函数重写如下:

def foo(row):
x, y = row
e, n = ''
if x < 0:
e = '1'
else:
w = '2'
if y > 0:
n = '3'
else:
s = '4'
return int(f'{abs(x)}{e}{abs(y){n}'.replace('.', ''))

# Where you want to you use it.
new_arr = np.apply_along_axis(foo, 1, n)

最新更新