提问人:astabada 提问时间:8/23/2023 更新时间:8/24/2023 访问量:73
如何使 int8 python numpy 数组对用户显示为 bool
How to make an int8 python numpy array appear as bool to the user
问:
需要存储一个 bool numpy 数组,但它必须与只能存储 int8 的旧规范 (astropy.io.fits.ImageHDU) 兼容(其他类型是可能的,但 int8 是最小的占用空间)。关键问题是用户想要做
mask = np.array((True, False, False, True))
print(np.arange(4, 8)[mask])
[4, 7]
如果 mask 是 int,这将给出完全不同的结果
[5, 4, 4, 5]
这里有两个(错误的)实现,可以让我了解我需要什么
import numpy as np
class MyClass(dict):
@property
def mask(self):
return self['mask'].astype(bool)
@mask.setter
def mask(self, inmask):
self['mask'] = inmask.astype(np.int8)
input_mask = np.array((0, 1), dtype=np.int8)
obj = MyClass((('mask', input_mask),))
期望的行为应该并且始终是同步的,即obj.mask
obj['mask']
print(obj.mask)
[False, True]
print(obj['mask'])
[0, 1]
obj['mask'][0] = 1
print(obj.mask)
[True, True]
obj.mask[0] = False
print(obj.mask)
[False, True]
print(obj['mask'])
[0, 1]
但是实现失败,因为总是返回与 不同的实例。所以,作为替代方案,我尝试了mask
self['mask']
import numpy as np
class MyClass(dict):
@property
def mask(self):
try:
return self._mask
except AttributeError:
self._mask = self['mask'].astype(bool)
return self._mask
@mask.setter
def mask(self, inmask):
self._mask = inmask
self['mask'] = inmask.astype(np.int8)
input_mask = np.array((0, 1), dtype=np.int8)
obj = MyClass((('mask', input_mask),))
这失败了,因为并且不同步self._mask
self['mask']
obj.mask[0] = True
print(obj.mask, ' - ', obj['maks'])
[True True] - [0 1]
答:
在该特定设置中,我将直接利用 Numpy 中布尔数组的值在后台使用字节(即 8 位值)处理的事实。我不完全确定这是否被认为是一个实现细节,但到目前为止,它对我有用。
这意味着我们可以使用 Numpy 的 ndarray.view
() 来创建掩码内存的两种表示形式:布尔表示(用于实际掩码)和 int8 表示(用于规范一致性)。由于这两种表示都引用相同的内存,这意味着它们已经保持同步,而无需我们进行进一步的工作。
例如,调整您的第一次实现尝试,我们可以编写:
import numpy as np
class MyClass(dict):
@property
def mask(self):
return self['mask'].view(bool)
@mask.setter
def mask(self, inmask):
assert inmask.dtype in (np.uint8, np.int8, bool)
self['mask'] = inmask.view(np.int8)
这将为我们提供预期的行为:
input_mask = np.array((0, 1), dtype=np.int8)
obj = MyClass((('mask', input_mask),))
# Check behavior
print(obj.mask)
# >>> [False True]
print(obj['mask'])
# >>> [0 1]
obj['mask'][0] = 1
print(obj.mask)
# >>> [ True True]
obj.mask[0] = False
print(obj.mask)
# >>> [False True]
print(obj['mask'])
# >>> [0 1]
请注意,在此实现中,我们实际上有三种相同内存的表示形式:进入 setter 的 、 和 。如果我们想确保在更改或(或者,同样,更改为不更改和 ),我们可以像以前一样在 setter 中使用。inmask
obj['mask']
obj.mask
inmask
obj.mask
obj['mask']
inmask
obj.mask
obj['mask']
astype()
评论
mask = np.array((1, 0, 0, 1), dtype=np.int8)
np.arange(4, 8)[mask.view(dtype=bool)]
astype
self['mask'].view(dtype=bool)