【问题标题】:One Hot Encoding using numpy [duplicate]使用 numpy 的一种热编码 [重复]
【发布时间】:2016-11-30 05:54:20
【问题描述】:

如果输入为零,我想创建一个如下所示的数组:

[1,0,0,0,0,0,0,0,0,0]

如果输入为 5:

[0,0,0,0,0,1,0,0,0,0]

对于上面我写的:

np.put(np.zeros(10),5,1)

但它不起作用。

有什么方法可以在一行中实现吗?

【问题讨论】:

  • 怎么没用?
  • 为什么要在一行中做到这一点?如果你想保持紧凑,只需编写一个函数即可。
  • 当您得到至少一个可以解决您的问题的答案时,通常会选择其中一个。

标签: python numpy one-hot-encoding


【解决方案1】:

通常,当您想要获得用于机器学习分类的 one-hot 编码时,您有一个索引数组。

import numpy as np
nb_classes = 6
targets = np.array([[2, 3, 4, 0]]).reshape(-1)
one_hot_targets = np.eye(nb_classes)[targets]

one_hot_targets 现在是

array([[[ 0.,  0.,  1.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  1.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  1.,  0.],
        [ 1.,  0.,  0.,  0.,  0.,  0.]]])

.reshape(-1) 用于确保您拥有正确的标签格式(您可能还拥有[[2], [3], [4], [0]])。 -1 是一个特殊值,意思是“把所有剩余的东西都放在这个维度上”。由于只有一个,它会将数组展平。

复制粘贴解决方案

def get_one_hot(targets, nb_classes):
    res = np.eye(nb_classes)[np.array(targets).reshape(-1)]
    return res.reshape(list(targets.shape)+[nb_classes])

您可以使用mpu.ml.indices2one_hot。它经过测试且易于使用:

import mpu.ml
one_hot = mpu.ml.indices2one_hot([1, 3, 0], nb_classes=5)

【讨论】:

  • 但它是如何工作的? np.eye(nb_classes) 应该是 6x6 矩阵,但是它的形状变成了 4x6。你能详细说明一下吗?
  • np.eye(nb_classes) 是一个 6x6 矩阵。然后我选择目标中指定的行。我只选择了四个,所以它是一个 4x6 矩阵。
  • 这似乎只适用于 2-dim 目标,但可以通过执行 .reshape(list(targets.shape)+[nb_classes]) 推广到更多形状
  • 你能解释一下为什么np.eye(nb_classes)[np.array(targets).reshape(-1)]works吗?它是一个由 H*W 矩阵索引的 CxC 矩阵?!这是怎么回事?
  • @gebbissimo 首先,尝试了解np.eye(n) 的作用。然后np.eye(5)[[3, 1]]
【解决方案2】:

类似:

np.array([int(i == 5) for i in range(10)])

应该做的伎俩。 但我想还有其他使用 numpy 的解决方案。

编辑:您的公式不起作用的原因:np.put 不返回任何内容,它只是修改了第一个参数中给出的元素。使用np.put() 时最好的答案是:

a = np.zeros(10)
np.put(a,5,1)

问题是不能一行行完成,需要先定义好数组再传给np.put()

【讨论】:

  • @AbhijayGhildyal:这只是实现您想要的最低效的方式。
  • @PM2Ring 我知道我写的单行代码很糟糕,但是你有任何消息来源告诉你应该和不应该对 list 和 numpy 数组做什么?
  • @HolyDanna:Python 中的一般规则是 Python 循环比使用 C 代码执行的循环运行得慢。因此,如果有一种明显的方法可以使用 C 循环而不是 Python 循环,那么您应该使用 C 循环。使用 Numpy 的重点是尽可能以 C 速度进行数组处理。我不熟悉 numpy 源代码,但 numpy.zeros 可能比 C for 循环运行得更快,因为 CPU 可以用单个值 very 快速填充一块内存。
  • 顺便说一句,我不是说你的第一个代码示例不好。在非 Numpy 程序中,这样做是一种的方法,而仅仅为了这个操作而导入 Numpy 是很愚蠢的。但是,如果程序已经在使用 Numpy,那么利用 Numpy 提供的功能是有意义的。
【解决方案3】:

你可以使用列表推导:

[0 if i !=5 else 1 for i in range(10)]

转向

[0,0,0,0,0,1,0,0,0,0]

【讨论】:

    【解决方案4】:

    使用np.identitynp.eye。您可以使用输入 i 和数组大小 s 尝试这样的操作:

    np.identity(s)[i:i+1]
    

    例如,print(np.identity(5)[0:1]) 将导致:

    [[ 1.  0.  0.  0.  0.  0.  0.  0.  0.  0.]]
    

    如果你使用的是TensorFlow,可以使用tf.one_hothttps://www.tensorflow.org/api_docs/python/array_ops/slicing_and_joining#one_hot

    【讨论】:

      【解决方案5】:

      快速查看the manual,您会发现np.put 没有返回值。虽然您的技术很好,但您访问的是 None 而不是结果数组。

      对于一维数组,最好只使用直接索引,尤其是对于这种简单的情况。

      以下是如何以最少的修改重写您的代码:

      arr = np.zeros(10)
      np.put(arr, 5, 1)
      

      这里是如何使用索引而不是 put 来执行第二行:

      arr[5] = 1
      

      【讨论】:

        【解决方案6】:

        这里的问题是您无法将数组保存在任何地方。 put 函数在数组上工作并且不返回任何内容。由于您从不给数组命名,因此以后无法对其进行寻址。所以这个

        one_pos = 5
        x = np.zeros(10)
        np.put(x, one_pos, 1)
        

        可以,但你可以只使用索引:

        one_pos = 5
        x = np.zeros(10)
        x[one_pos] = 1
        

        在我看来,如果没有特殊原因作为一个班轮这样做的话,这将是正确的做法。这也可能更容易阅读和可读的代码是好的代码。

        【讨论】:

          【解决方案7】:

          np.put 改变了它的数组 arg 就地。在 Python 中,执行就地突变以返回 None 的函数/方法是常规的; np.put 遵守该约定。所以如果a 是一个一维数组,而你这样做

          a = np.put(a, 5, 1)
          

          然后a 将被None 替换。

          您的代码与此类似,但它将一个未命名的数组传递给np.put

          用一个简单的函数来做你想做的事,一个紧凑而有效的方法,例如:

          import numpy as np
          
          def one_hot(i):
              a = np.zeros(10, 'uint8')
              a[i] = 1
              return a
          
          a = one_hot(5) 
          print(a)
          

          输出

          [0 0 0 0 0 1 0 0 0 0]
          

          【讨论】:

          • 我不会接受,以免对人无礼
          【解决方案8】:

          我不确定性能,但是下面的代码可以工作而且很整洁。

          x = np.array([0, 5])
          x_onehot = np.identity(6)[x]
          

          【讨论】:

          • 这基本上等同于接受的答案。谢谢你再次回答。
          【解决方案9】:
          import time
          start_time = time.time()
          z=[]
          for l in [1,2,3,4,5,6,1,2,3,4,4,6,]:
              a= np.repeat(0,10)
              np.put(a,l,1)
              z.append(a)
          print("--- %s seconds ---" % (time.time() - start_time))
          
          #--- 0.00174784660339 seconds ---
          
          import time
          start_time = time.time()
          z=[]
          for l in [1,2,3,4,5,6,1,2,3,4,4,6,]:
              z.append(np.array([int(i == l) for i in range(10)]))
          print("--- %s seconds ---" % (time.time() - start_time))
          
          #--- 0.000400066375732 seconds ---
          

          【讨论】:

          • 使用a=np.zeros(10),我得到了第一个版本稍快的版本:0.0007712841033935547 seconds 反对0.0008835792541503906 seconds 第二个版本
          • 试试a = np.zeros(10); a[l] = 1;索引赋值比执行函数调用更快。我的one_hot 函数比这个内联版本慢一点,这也是由于函数调用的开销,但它比其他技术快。但是,这个时间信息不是很准确,您应该使用timeit 模块,并使用它的功能来执行您的测试数百(或数千)次以获得有意义的结果,而不会被其他的“噪音”淹没您的 CPU 正在执行的任务。
          • 谢谢。你知道检查代码运行时间的更好方法吗?
          • 如我所说,使用timeit 模块。 FWIW,这是我最近使用 timeit stackoverflow.com/a/38075792/4014959stackoverflow.com/a/36030019/4014959 的几个答案
          猜你喜欢
          • 2021-04-15
          • 1970-01-01
          • 1970-01-01
          • 2016-03-19
          • 2021-06-28
          • 2017-11-05
          • 2021-12-01
          • 2018-12-17
          • 1970-01-01
          相关资源
          最近更新 更多