【问题标题】:Mean of the last two entries of non-zero elements in a 3D array3D 数组中最后两个非零元素的平均值
【发布时间】:2021-03-07 07:17:18
【问题描述】:

我有一个 (n × i × j) - 3D numpy 数组:a_3d_array (2 × 5 × 3)

array([[[1, 2, 3],
    [1, 1, 1],
    [2, 2, 2],
    [0, 3, 3],
    [0, 0, 4]],

   [[1, 2, 3],
    [2, 2, 2],
    [3, 3, 3],
    [0, 4, 4],
    [0, 0, 5]]]).

对于 n 中的每一列 j,我想提取最后 2 个非零元素并计算平均值,然后将结果放入 (n by j) 数组中。我目前所做的是使用 for 循环

import numpy as np

a_3d_array = np.array([[[1, 2, 3],
                        [1, 1, 1],
                        [2, 2, 2],
                        [0, 3, 3],
                        [0, 0, 4]],
                       [[1, 2, 3],
                        [2, 2, 2],
                        [3, 3, 3],
                        [0, 4, 4],
                        [0, 0, 5]]])

aveCol = np.zeros([2,3])
for n in range(2):
    for j in range(3):
        temp = a_3d_array[n,:,j]
        nonzero_array = temp[np.nonzero(temp)]
        aveCol[n, j] = np.mean(nonzero_array[-2:])

得到想要的结果

print(aveCol)
[[1.5 2.5 3.5] [2.5 3.5 4.5]]

效果很好。但我想知道是否有更好的 Pythonic 方式来做同样的事情?

我发现与我的问题最相似的是here。但我不太明白在稍微不同的上下文中解释的答案。

【问题讨论】:

  • 因为这是完全工作的代码;这可能会更好地放在codereview.stackexchange.com 上(如果您决定在那里发帖,请删除此问题)
  • 谢谢 JeffUK,我不知道还有另一个合适的网站可以询问工作代码。由于我已经收到了 2 个对这篇文章的回答,所以这次我将把我的帖子留在这里。但是下次我会去其他网站!
  • 好电话!他们是真正的代码审查专家,你会在那里得到很多很好的指导。

标签: python numpy multidimensional-array mean


【解决方案1】:

TL;DR 据我所知,Ann's answer 是最快的


每个m 是一个n×i 2D 数组,接下来我们取其转置的row,即执行计算的“列”——在这个“列”我们丢弃所有的零,我们将最后两个非零元素相加并取平均值

In [17]: np.array([[sum(r[r!=0][-2:])/2 for r in m.T] for m in a])
Out[17]: 
array([[1.5, 2.5, 3.5],
       [2.5, 3.5, 4.5]])

编辑1

看起来它比你的循环更快

In [19]: %%timeit
    ...: avg = np.zeros([2,3])
    ...: for n in range(2):
    ...:     for j in range(3):
    ...:         temp = a[n,:,j]
    ...:         nz = temp[np.nonzero(temp)]
    ...:         avg[n, j] = np.mean(nz[-2:])
95.1 µs ± 596 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [20]: %timeit np.array([[sum(r[r!=0][-2:])/2 for r in m.T] for m in a])
45.5 µs ± 394 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

编辑2

In [22]: %timeit np.array([[np.mean(list(filter(None, a[n,:,j]))[-2:]) for j in range(3)] for n in range(2)])
145 µs ± 689 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

编辑3

In [25]: %%timeit
    ...: i = np.indices(a.shape)
    ...: i[:, a == 0] = -1
    ...: i = np.sort(i, axis=2)
    ...: i = i[:, :, -2:, :]
    ...: a[tuple(i)].mean(axis=1)
64 µs ± 239 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Edit4 突发新闻信息

安回答的罪魁祸首是np.mean!!

In [29]: %timeit np.array([[sum(list(filter(None, a[n,:,j]))[-2:])/2 for j in range(3)] for n in range(2)])
32.7 µs ± 111 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

【讨论】:

    【解决方案2】:

    您可以使用filter 方法从数组中过滤掉0s。

    这是一个列表理解方法:

    import numpy as np
    
    a_3d_array = np.array([[[1, 2, 3],
                            [1, 1, 1],
                            [2, 2, 2],
                            [0, 3, 3],
                            [0, 0, 4]],
                           [[1, 2, 3],
                            [2, 2, 2],
                            [3, 3, 3],
                            [0, 4, 4],
                            [0, 0, 5]]])
    
    aveCol = np.array([[np.mean(list(filter(None, a_3d_array[n,:,j]))[-2:]) for j in range(3)] for n in range(2)])
    print(aveCol)
    

    输出:

    [[1.5 2.5 3.5] 
     [2.5 3.5 4.5]]
    

    @gboffi 的注释:为了提高效率,请使用

    aveCol = np.array([[sum([i for i in a_3d_array[n,:,j] if i][-2:])/2 for j in range(3)] for n in range(2)])
    

    而不是

    aveCol = np.array([[np.array([i for i in a_3d_array[n,:,j] if i][-2:]) for j in range(3)] for n in range(2)])
    

    【讨论】:

    • 嗨,我最终发现你的解决方案实际上是最快的,只要你使用sum()/2 代替np.mean — 我猜 Numpy 函数的开销根本不合适当取 2 个数字的平均值时……
    • 感谢您的所有建议。我真的很感激。
    【解决方案3】:

    您可以获取数组a的索引,用负数标记零项,排序,限制,然后将结果用作索引:

    i = np.indices(a.shape)
    i[:, a == 0] = -1
    i = np.sort(i, axis=2)
    i = i[:, :, -2:, :]
    a[tuple(i)].mean(axis=1)
    # array([[1.5, 2.5, 3.5],
    #        [2.5, 3.5, 4.5]])
    

    【讨论】:

      猜你喜欢
      • 2013-08-02
      • 1970-01-01
      • 2014-12-24
      • 2013-12-29
      • 2021-03-27
      • 1970-01-01
      • 2018-12-07
      • 2021-06-16
      • 2023-01-31
      相关资源
      最近更新 更多