Numpy数组在掩码时丢失维度

32

我想选择数组的某些元素并根据其值执行加权平均计算。然而,使用筛选条件会破坏数组的原始结构。形状为(2, 2, 3, 2)arr数组被转换为一维数组。这对我没有用,因为并不是所有这些元素都需要稍后与彼此结合(而是它们的子数组)。如何避免这种平坦化?

>>> arr = np.asarray([ [[[1, 11], [2, 22], [3, 33]], [[4, 44], [5, 55], [6, 66]]], [ [[7, 77], [8, 88], [9, 99]], [[0, 32], [1, 33], [2, 34] ]] ])
>>> arr
array([[[[ 1, 11],
         [ 2, 22],
         [ 3, 33]],

        [[ 4, 44],
         [ 5, 55],
         [ 6, 66]]],


       [[[ 7, 77],
         [ 8, 88],
         [ 9, 99]],

        [[ 0, 32],
         [ 1, 33],
         [ 2, 34]]]])
>>> arr.shape
(2, 2, 3, 2)
>>> arr[arr>3]
array([11, 22, 33,  4, 44,  5, 55,  6, 66,  7, 77,  8, 88,  9, 99, 32, 33,
       34])
>>> arr[arr>3].shape
(18,)

1
请详细说明您需要使用这些值进行的计算。您将如何使用“arr”结构? - hpaulj
5个回答

34

查看 numpy.where

http://docs.scipy.org/doc/numpy/reference/generated/numpy.where.html

为保持相同的维度,您需要一个填充值。在下面的示例中,我使用0,但您也可以使用np.nan

np.where(arr>3, arr, 0)

返回值

array([[[[ 0, 11],
         [ 0, 22],
         [ 0, 33]],

        [[ 4, 44],
         [ 5, 55],
         [ 6, 66]]],


       [[[ 7, 77],
         [ 8, 88],
         [ 9, 99]],

        [[ 0, 32],
         [ 0, 33],
         [ 0, 34]]]])

13

您可以考虑使用np.ma.masked_array来表示满足条件的元素子集:

import numpy as np

arr = np.asarray([[[[1, 11], [2, 22], [3, 33]],
                   [[4, 44], [5, 55], [6, 66]]],
                  [[[7, 77], [8, 88], [9, 99]],
                   [[0, 32], [1, 33], [2, 34]]]])

masked_arr = np.ma.masked_less(arr, 3)

print(masked_arr)
# [[[[-- 11]
#    [-- 22]
#    [3 33]]

#   [[4 44]
#    [5 55]
#    [6 66]]]


#  [[[7 77]
#    [8 88]
#    [9 99]]

#   [[-- 32]
#    [-- 33]
#    [-- 34]]]]

正如您所看到的,掩码数组保留其原始尺寸。您可以通过.data.mask属性访问底层数据和掩码。大多数NumPy函数将不考虑掩码值,例如:

# mean of whole array
print(arr.mean())
# 26.75

# mean of non-masked elements only
print(masked_arr.mean())
# 33.4736842105

对掩码数组和非掩码数组进行逐元素操作的结果将保留掩码的值:

masked_arrsum = masked_arr + np.random.randn(*arr.shape)

print(masked_arrsum)
# [[[[-- 11.359989067421582]
#    [-- 23.249092437269162]
#    [3.326111354088174 32.679132708120726]]

#   [[4.289134334263137 43.38559221094378]
#    [6.028063054523145 53.5043991898567]
#    [7.44695154979811 65.56890530368757]]]


#  [[[8.45692625294376 77.36860675985407]
#    [5.915835159196378 87.28574554110307]
#    [8.251106168209688 98.7621940026713]]

#   [[-- 33.24398289945855]
#    [-- 33.411941757624284]
#    [-- 34.964817895873715]]]]

这个总和仅计算masked_arr的非掩码值 - 您可以通过查看masked_sum.data来了解这一点:

print(masked_sum.data)
# [[[[  1.          11.35998907]
#    [  2.          23.24909244]
#    [  3.32611135  32.67913271]]

#   [[  4.28913433  43.38559221]
#    [  6.02806305  53.50439919]
#    [  7.44695155  65.5689053 ]]]


#  [[[  8.45692625  77.36860676]
#    [  5.91583516  87.28574554]
#    [  8.25110617  98.762194  ]]

#   [[  0.          33.2439829 ]
#    [  1.          33.41194176]
#    [  2.          34.9648179 ]]]]

1
我在你的代码和np.where之间犹豫不决。我选择了它,因为它在一行代码中就能达到目的。它似乎是最合适的选择。所有的答案都很好... - orange

5
请看arr>3:
In [71]: arr>3
Out[71]: 
array([[[[False,  True],
         [False,  True],
         [False,  True]],

        [[ True,  True],
         [ True,  True],
         [ True,  True]]],


       [[[ True,  True],
         [ True,  True],
         [ True,  True]],

        [[False,  True],
         [False,  True],
         [False,  True]]]], dtype=bool)

arr[arr>3]选取那些掩码为True的元素。您希望选择具有什么样的结构或形状?只有平坦是有意义的,不是吗?arr本身没有改变。

您可以将不符合掩码的项清零,

In [84]: arr1=arr.copy()
In [85]: arr1[arr<=3]=0
In [86]: arr1
Out[86]: 
array([[[[ 0, 11],
         [ 0, 22],
         [ 0, 33]],

        [[ 4, 44],
         [ 5, 55],
         [ 6, 66]]],


       [[[ 7, 77],
         [ 8, 88],
         [ 9, 99]],

        [[ 0, 32],
         [ 0, 33],
         [ 0, 34]]]])

现在你可以对各个维度进行加权求和或平均值。使用 np.nonzero(或np.where)可能也很有用,它会给出所选项的索引:
In [88]: np.nonzero(arr>3)
Out[88]: 
(array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]),
 array([0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1]),
 array([0, 1, 2, 0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2, 0, 1, 2]),
 array([1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1]))

1

如果你需要将小于所检查的值(在你的例子中为3)的最小值替换掉,那么你可以使用numpy.clip()ndarray.clip():

In [27]: np.clip(arr, 3, np.max(arr))
Out[27]: 
array([[[[ 3, 11],
         [ 3, 22],
         [ 3, 33]],

        [[ 4, 44],
         [ 5, 55],
         [ 6, 66]]],


       [[[ 7, 77],
         [ 8, 88],
         [ 9, 99]],

        [[ 3, 32],
         [ 3, 33],
         [ 3, 34]]]])

-4

显然,你需要做的是首先重新整理数组,然后进行转换,如下所示:

maschked_data = data[:,0][np.zeros(np.reshape(data, -1), np.reshape(data, -1).shape[0])[:,0].shape[0]]

data[:,0] <3


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接