3D数组中最后两个非零元素的平均值

2024-09-30 01:18:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个(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×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]]

那很好。但我想知道是否有更好的Python式方法来做同样的事情

我发现与我的问题最相似的是here。但我不太理解在稍微不同的背景下解释的答案


Tags: inimportnumpy元素forasnpzeros
3条回答

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


每个m是一个n×i2D数组,接下来我们取其转置的r流,即执行计算的“列”——在这个“列”上,我们丢弃所有零,最后两个非零元素求和并取平均值

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]])

Edit1

它看起来比你的循环快

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)

Edit2

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)

Edit3

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)

您可以使用filter方法从数组中筛选出0

以下是一种列表理解方法:

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]]

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

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)])

您可以获取数组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]])

相关问题 更多 >

    热门问题