通过在numpy 1D数组中应用数学/逻辑更快地获得每个尾巴 - 消除无穷大

我有一个2D数组,其中我需要独立处理每个“列”(axis= 1)。对于每列(1D 数组),我需要一个应用于 1D 数组的每个长度尾部的函数,以提供长度为 N 的数组,如下所示。如何让它更快?也许通过删除 for 循环。我用map/lambda/hstack来做这件事,直到我命中了除以零的错误,这需要if/elif/else条件来消除行进到无穷大。


import numpy as np

x = np.random.rand(20,5)


def get_updown_array(loc_array):

    return np.array([updown(loc_array[x:]) for x in list(range(loc_array.shape[0]))])


def updown(local_array):

    sub_length = ((local_array.shape[0]) + 1) // 2 # to get the middle value when length is uneven

    a = local_array[:sub_length].mean() # first half mean

    b = local_array[-sub_length:].mean() # second half mean

    if not a == 0:

        return ( b - a ) / abs(a)

    elif not b == 0:

        return ( b - a ) / abs(( a + b ) / 2)

    else:

        return 0


result = np.apply_along_axis(get_updown_array, 0, x)

if/else 条件逻辑似乎消除了同时在一个 numpy 维度中跨多个值应用函数的能力。

  1. 我研究了如何使用veyize,尽管这似乎仍然需要第一个函数中的for循环。

  2. 我看了 pandas.apply,虽然它看起来更慢,之后仍然需要一个连接或 vstack/hstack?

  3. Cython被考虑过,尽管这仍然让不雅的循环咯吱咯吱咯吱地溜走了。

  4. 我尝试了np.where,尽管这仍然需要一个for循环。

有没有办法在没有for循环的情况下将数学/逻辑应用于每个长度的尾部?最快的方法是什么?堆栈溢出社区。


Qyouu
浏览 120回答 1
1回答

噜噜哒

我会做这样的事情:def updown(x):    result = np.zeros_like(x)    for i in range(len(x)):        mid = (len(x)+1)//2        a = x[:mid].mean(axis=0)        b = x[-mid:].mean(axis=0)        mask_a = a != 0        mask_b = (a == 0) & (b != 0)        result[i, mask_a] = (b[mask_a] - a[mask_a]) / abs(a[mask_a])        result[i, mask_b] = (b[mask_b] - a[mask_b]) / abs((a[mask_b] + b[mask_b])/2)        x = x[1:]    return result在循环相当不可避免的情况下,最好预先分配结果数组(如果事先知道维度)并填充循环中的值。这还具有允许预先填充默认值零的优点。无需在 列上应用任何内容,因为其他运算(和算术)可以很容易地应用于所选轴。xmean条件逻辑是通过屏蔽实现的。您还可以使用 和 关键字参数:outwherenp.dividedef updown(x):    result = np.zeros_like(x)    for i in range(len(x)):        mid = (len(x)+1)//2        a = x[:mid].mean(axis=0)        b = x[-mid:].mean(axis=0)        np.divide(b - a, abs(a), out=result[i], where=(a != 0))        np.divide(b - a, abs((a + b)/2), out=result[i], where=(a == 0) & (b != 0))        x = x[1:]    return result让我们看看一些性能比较(我已经将整个原始代码包装在一个名为updown_orig)对于维度,我们只看到 2 倍的改进:(20, 5)In []: %timeit updown_orig(np.random.rand(20, 5))1 ms ± 13.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)In []: %timeit updown(np.random.rand(20, 5))508 µs ± 10.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)让我们将两个维度缩放 10(将 大小增加 100 倍):xIn []: %timeit updown_orig(np.random.rand(200, 50))                                                                 96.4 ms ± 1.91 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)In []: %timeit updown(np.random.rand(200, 50))                                                                      5.84 ms ± 64 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)现在,差异约为16.5倍。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python