Python 一个带>;的热编码numpy阵列;2暗
我有一个numpy数组的形状Python 一个带>;的热编码numpy阵列;2暗,python,numpy,machine-learning,one-hot-encoding,Python,Numpy,Machine Learning,One Hot Encoding,我有一个numpy数组的形状(1922241921)。最后一个维度是整数类,我想对其进行热编码。例如,如果我有12个类,我希望得到的数组的值是(192224192,12),最后一个维度是全零,但在与原始值对应的索引处是1 我可以用许多for循环天真地做到这一点,但我想知道是否有更好的方法来做到这一点。SciKit learn有一个编码器: from sklearn.preprocessing import OneHotEncoder # Data values = np.array([1, 3
(1922241921)
。最后一个维度是整数类,我想对其进行热编码。例如,如果我有12个类,我希望得到的数组的值是(192224192,12)
,最后一个维度是全零,但在与原始值对应的索引处是1
我可以用许多
for
循环天真地做到这一点,但我想知道是否有更好的方法来做到这一点。SciKit learn有一个编码器:
from sklearn.preprocessing import OneHotEncoder
# Data
values = np.array([1, 3, 2, 4, 1, 2, 1, 3, 5])
val_reshape = values.reshape(len(values), 1)
# One-hot encoding
oh = OneHotEncoder(sparse = False)
oh_arr = oh.fit_transform(val_reshape)
print(oh_arr)
output:
[[1. 0. 0. 0. 0.]
[0. 0. 1. 0. 0.]
[0. 1. 0. 0. 0.]
[0. 0. 0. 1. 0.]
[1. 0. 0. 0. 0.]
[0. 1. 0. 0. 0.]
[1. 0. 0. 0. 0.]
[0. 0. 1. 0. 0.]
[0. 0. 0. 0. 1.]]
您可以创建一个新的零数组并使用高级索引填充它
# sample array with 12 classes
np.random.seed(123)
a = np.random.randint(0, 12, (192, 224, 192, 1))
b = np.zeros((a.size, a.max() + 1))
# use advanced indexing to get one-hot encoding
b[np.arange(a.size), a.ravel()] = 1
# reshape to original form
b = b.reshape(a.shape[:-1] + (a.max() + 1,))
print(b.shape)
print(a[0, 0, 0])
print(b[0, 0, 0])
输出
(192, 224, 192, 12)
[2]
[0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
与数组整形类似,但与数组整形类似。如果已知给定数组
a
和m=a.max()+1的最大值,则可以在单个索引操作中执行此操作:
out = np.zeros(a.shape[:-1] + (m,), dtype=bool)
out[(*np.indices(a.shape[:-1], sparse=True), a[..., 0])] = True
如果删除不必要的尾部尺寸标注,则更容易:
a = np.squeeze(a)
out = np.zeros(a.shape + (m,), bool)
out[(*np.indices(a.shape, sparse=True), a)] = True
def onehot2(a, axis=None, dtype=bool):
shape = np.array(a.shape)
if axis is None:
axis = (shape == 1).argmax()
if shape[axis] != 1:
raise ValueError(f'Dimension at {axis} is non-singleton')
shape[axis] = a.max() + 1
out = np.zeros(shape, dtype)
ind = list(np.indices(a.shape, sparse=True))
ind[axis] = a
out[tuple(ind)] = True
return out
索引中的显式元组是进行星型扩展所必需的
如果要将其扩展到任意维度,也可以这样做。以下内容将在轴处的压缩数组中插入一个新维度。此处轴
是新轴在最终数组中的位置,与saynp.stack
一致,但与列表不一致。插入
:
def onehot(a, axis=-1, dtype=bool):
pos = axis if axis >= 0 else a.ndim + axis + 1
shape = list(a.shape)
shape.insert(pos, a.max() + 1)
out = np.zeros(shape, dtype)
ind = list(np.indices(a.shape, sparse=True))
ind.insert(pos, a)
out[tuple(ind)] = True
return out
如果要展开单个维度,则通用解决方案可以找到第一个可用的单个维度:
a = np.squeeze(a)
out = np.zeros(a.shape + (m,), bool)
out[(*np.indices(a.shape, sparse=True), a)] = True
def onehot2(a, axis=None, dtype=bool):
shape = np.array(a.shape)
if axis is None:
axis = (shape == 1).argmax()
if shape[axis] != 1:
raise ValueError(f'Dimension at {axis} is non-singleton')
shape[axis] = a.max() + 1
out = np.zeros(shape, dtype)
ind = list(np.indices(a.shape, sparse=True))
ind[axis] = a
out[tuple(ind)] = True
return out
要使用最后一个可用的单例,请将轴=(形状==1).argmax()替换为
axis = a.ndim - 1 - (shape[::-1] == 1).argmax()
以下是一些示例用法:
>>> np.random.seed(0x111)
>>> x = np.random.randint(5, size=(3, 2))
>>> x
array([[2, 3],
[3, 1],
[4, 0]])
>>> a = onehot(x, axis=-1, dtype=int)
>>> a.shape
(3, 2, 5)
>>> a
array([[[0, 0, 1, 0, 0], # 2
[0, 0, 0, 1, 0]], # 3
[[0, 0, 0, 1, 0], # 3
[0, 1, 0, 0, 0]], # 1
[[0, 0, 0, 0, 1], # 4
[1, 0, 0, 0, 0]]] # 0
>>> b = onehot(x, axis=-2, dtype=int)
>>> b.shape
(3, 5, 2)
>>> b
array([[[0, 0],
[0, 0],
[1, 0],
[0, 1],
[0, 0]],
[[0, 0],
[0, 1],
[0, 0],
[1, 0],
[0, 0]],
[[0, 1],
[0, 0],
[0, 0],
[0, 0],
[1, 0]]])
onehot2
要求您将要添加的维度标记为单个维度:
>>> np.random.seed(0x111)
>>> y = np.random.randint(5, size=(3, 1, 2, 1))
>>> y
array([[[[2],
[3]]],
[[[3],
[1]]],
[[[4],
[0]]]])
>>> c = onehot2(y, axis=-1, dtype=int)
>>> c.shape
(3, 1, 2, 5)
>>> c
array([[[[0, 0, 1, 0, 0],
[0, 0, 0, 1, 0]]],
[[[0, 0, 0, 1, 0],
[0, 1, 0, 0, 0]]],
[[[0, 0, 0, 0, 1],
[1, 0, 0, 0, 0]]]])
>>> d = onehot2(y, axis=-2, dtype=int)
ValueError: Dimension at -2 is non-singleton
>>> e = onehot2(y, dtype=int)
>>> e.shape
(3, 5, 2, 1)
>>> e.squeeze()
array([[[0, 0],
[0, 0],
[1, 0],
[0, 1],
[0, 0]],
[[0, 0],
[0, 1],
[0, 0],
[1, 0],
[0, 0]],
[[0, 1],
[0, 0],
[0, 0],
[0, 0],
[1, 0]]])
如果不这样做,总索引数组会更短reshape@RitchieV. 我已经发布了一个答案,并将其推广到任意维度。请告诉我您是否有机会玩它。我是从手机上发的,所以不能保证代码是无错误的。这个答案很好地解决了我的问题。我唯一需要做的更改是将a.max()+1
更改为我拥有的类的数量。这个特定的ML问题是分割,所以整个数组是我的标签,但不是每个类都表示在每个标签中,所以它必须是硬编码的。@ PDPDPDPD考虑了投票的MAD的答案,它实际上是更好的性能,包括一个通用函数,很高兴您修复了代码!看到使用np.index
非常有趣,我需要获得更多关于fancy的经验indexing@RichieV. 我已还原了您的编辑。onehot
中的索引是故意这样做的。它的意思是在a.squeak
上操作,而不是问题中的a
。但是关于这个错误你是对的:)@RichieV。我已经添加了一些示例来展示这两个函数是如何使用的,这符合您测试的精神。谢谢您的代码。这个答案非常棒,与其他一些答案相比速度非常快。@pdpd。里奇耶夫的答案非常相似。如果速度很重要的话,我会把它和我的进行比较。撕开和拆开是非常便宜的,因为它们不复制内存。