在数组的数组上使用numpy掩码数组,而不会获得扁平输出

bakd9h0s  于 2023-04-30  发布在  其他
关注(0)|答案(4)|浏览(142)

考虑下面的代码

x = np.array([[1, 2, 3], ['NaN', 4, 'NaN'], [7, 8, 9]])

# Convert 'NaN' strings to masked values
mask = np.ma.masked_where(x == 'NaN', x)

# Get a boolean array indicating where the original array is not masked
bool_arr = ~mask.Mask

# Filter the original array using the boolean array
filtered_arr = x[bool_arr]

print(filtered_arr)

上面的代码产生以下输出

['1' '2' '3' '4' '7' '8' '9']

但是,我希望我的输出如下所示

[['1' '2' '3'],
 ['4'],
 ['7' '8' '9']]

我哪里做错了?

y3bcpkx1

y3bcpkx11#

创建一个字符串数组:

In [22]: x
Out[22]: 
array([['1', '2', '3'],
       ['NaN', '4', 'NaN'],
       ['7', '8', '9']], dtype='<U11')

和一个具有相同字符串的掩码数组:

In [23]: masked
Out[23]: 
masked_array(
  data=[['1', '2', '3'],
        [--, '4', --],
        ['7', '8', '9']],
  mask=[[False, False, False],
        [ True, False,  True],
        [False, False, False]],
  fill_value='N/A',
  dtype='<U11')

掩码数组有一个返回值的方法:

In [24]: masked.compressed()
Out[24]: array(['1', '2', '3', '4', '7', '8', '9'], dtype='<U11')

In [25]: masked.compressed?
Signature: masked.compressed()
Docstring:
Return all the non-masked data as a 1-D array.

所有使用布尔数组的索引都会返回一个1d数组。它不能像原始数组那样返回2d数组,因为通常每行可能有不同数量的元素。特别是在你的例子中,你想要一个包含3,1,3大小的元素的列表。numpy整个数组方法不会产生这种东西。
要逐行获取1d数组,您必须逐行工作:

In [30]: [row[row!='NaN'] for row in x]
Out[30]: 
[array(['1', '2', '3'], dtype='<U11'),
 array(['4'], dtype='<U11'),
 array(['7', '8', '9'], dtype='<U11')]

或者,您可能希望删除“nan”by列:

In [32]: [row[row!='NaN'] for row in x.T]
Out[32]: 
[array(['1', '7'], dtype='<U11'),
 array(['2', '4', '8'], dtype='<U11'),
 array(['3', '9'], dtype='<U11')]

可能不会,但你看到你的追求中固有的模糊性了吗?
如果将数组强制转换为float:

In [34]: x = x.astype(float)
In [35]: x
Out[35]: 
array([[ 1.,  2.,  3.],
       [nan,  4., nan],
       [ 7.,  8.,  9.]])

并且可以用以下物质掩蔽:

In [36]: np.ma.masked_invalid(x)
Out[36]: 
masked_array(
  data=[[1.0, 2.0, 3.0],
        [--, 4.0, --],
        [7.0, 8.0, 9.0]],
  mask=[[False, False, False],
        [ True, False,  True],
        [False, False, False]],
  fill_value=1e+20)

在提取非掩码值时,仍然存在展平问题。

In [40]: np.ma.masked_invalid(x).compressed()
Out[40]: array([1., 2., 3., 4., 7., 8., 9.])

但是有很多函数可以让你处理数组的非nan值,比如取行平均值:

In [42]: np.nanmean(x,axis=1)
Out[42]: array([2., 4., 8.])

你想要的列表(或数组)的列表失去了你通常使用2d数组获得的大部分计算优势。

5ktev3wc

5ktev3wc2#

这段代码的问题是,当你用一个布尔数组索引它时,它会使数组变平。您可以使用列表解析来创建一个新的列表列表,而不是使用布尔数组来索引原始数组,其中每个内部列表都包含来自原始数组相应行的非掩码元素

import numpy as np

x = np.array([[1, 2, 3], ['NaN', 4, 'NaN'], [7, 8, 9]])

mask = np.ma.masked_where(x == 'NaN', x)

filtered_arr = [row[row != 'NaN'].tolist() for row in x]

print(filtered_arr)
wsxa1bj1

wsxa1bj13#

预期的输出不是有效的numpy数组,它应该是所有维度的倍数。
运行x[bool_arr]时,numpy会在内部展平数组。这使您能够指定任何输入,因为它也将被展平:

x[bool_arr] = list('ABCDEFG')

array([['A', 'B', 'C'],
       ['NaN', 'D', 'NaN'],
       ['E', 'F', 'G']], dtype='<U21')

你可能想回到python列表:

filtered_arr = [d[~m].tolist() for d,m in zip(mask.data, mask.mask)]

输出:

[['1', '2', '3'], ['4'], ['7', '8', '9']]
pkwftd7m

pkwftd7m4#

尝试使用mask[bool_arr]代替x[bool_arr]

相关问题