为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Qyouu 2022-08-02 17:09:26
我有一个2D数组,其中我需要独立处理每个“列”(axis= 1)。对于每列(1D 数组),我需要一个应用于 1D 数组的每个长度尾部的函数,以提供长度为 N 的数组,如下所示。如何让它更快?也许通过删除 for 循环。我用map/lambda/hstack来做这件事,直到我命中了除以零的错误,这需要if/elif/else条件来消除行进到无穷大。import numpy as npx = 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 0result = np.apply_along_axis(get_updown_array, 0, x)if/else 条件逻辑似乎消除了同时在一个 numpy 维度中跨多个值应用函数的能力。我研究了如何使用veyize,尽管这似乎仍然需要第一个函数中的for循环。我看了 pandas.apply,虽然它看起来更慢,之后仍然需要一个连接或 vstack/hstack?Cython被考虑过,尽管这仍然让不雅的循环咯吱咯吱咯吱地溜走了。我尝试了np.where,尽管这仍然需要一个for循环。有没有办法在没有for循环的情况下将数学/逻辑应用于每个长度的尾部?最快的方法是什么?堆栈溢出社区。
查看完整描述

1 回答

?
噜噜哒

TA贡献1784条经验 获得超7个赞

我会做这样的事情:


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.divide


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)

        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 倍):x


In []: %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倍。


查看完整回答
反对 回复 2022-08-02
  • 1 回答
  • 0 关注
  • 119 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信