【问题标题】:Elegant way to encode a list of lists编码列表列表的优雅方式
【发布时间】:2020-09-04 17:17:16
【问题描述】:

目前我正在尝试对包含单个元素的列表列表进行热编码。从表示 2 到表示 1 的干净 Pythonic 方式是什么?另外,我想知道一种从表示 1 到表示 2 的干净方法。

表示 1

[[1. 0. 0. 0. 0. 0.]
 [0. 0. 0. 1. 0. 0.]
 [0. 0. 0. 1. 0. 0.]
 ...
 [0. 0. 1. 0. 0. 0.]
 [0. 0. 0. 1. 0. 0.]
 [0. 0. 1. 0. 0. 0.]]
(256, 6)

表示 2

[[0.]
 [3.]
 [3.]
 ...
 [2.]
 [3.]
 [2.]]
(256, 1)

【问题讨论】:

    标签: python numpy encoding one-hot-encoding


    【解决方案1】:

    使用纯基本条件列表理解,用于表示 1 到 2:

    r1 = [[1., 0., 0., 0., 0., 0.],
          [0., 0., 0., 1., 0., 0.],
          [0., 0., 0., 0., 1., 0.]]
    len_r1l = len(r1[0]) # length of each sublist, here 6
    
    r2 = [[0], [3], [4]]
    
    r1_r2 = [[i] for l in r1 for i in range(len_r1l) if l[i]==1]
    >>> [[0], [3], [4]]
    

    对于表示 2 到 1:

    r2_r1 = [[1. if i==idx[0] else 0 for i in range(len_r1l)] for idx in r2]
    >>> [[1.0, 0, 0, 0, 0, 0],
         [0, 0, 0, 1.0, 0, 0],
         [0, 0, 0, 0, 1.0, 0]]
    

    等效地使用 numpy,使用 np.nonzero:

    # convert to array
    r1_np = np.asarray(r1)
    r2_np = np.asarray(r2)
    
    r1_r2 = np.nonzero(r1_np)[1]
    >>> array([0, 3, 4])
    
    r2_r1 = np.zeros_like(r1_np)
    r2_r1[np.arange(r1_r2.shape[0]),r1_r2] = 1.
    >>> array([[1., 0., 0., 0., 0., 0.],
               [0., 0., 0., 1., 0., 0.],
               [0., 0., 0., 0., 1., 0.]])
    

    那么如果你真的想保留它到list 使用np.ndarray.tolist 方法:

    r1_r2.tolist()
    >>> [0, 3, 4]
    r2_r1.tolist()
    >>> [[1.0, 0.0, 0.0, 0.0, 0.0, 0.0],
         [0.0, 0.0, 0.0, 1.0, 0.0, 0.0],
         [0.0, 0.0, 0.0, 0.0, 1.0, 0.0]]
    

    针对256 的预期输入对这些答案进行基准测试清楚地表明了 numpy 的效率:

    # representation 1 to 2
    %timeit [[i] for l in r1 for i in range(len_r1l) if l[i]==1]
    >>> 199 µs ± 431 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    
    %timeit np.nonzero(r1_np)[1]
    >>> 13 µs ± 32.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
    
    # representation 2 to 1
    %timeit [[1. if i==idx[0] else 0 for i in range(len_r1l)] for idx in r2]
    >>> 243 µs ± 820 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    
    %timeit r2_r1 = np.zeros_like(r1_np); r2_r1[np.arange(r1_r2.shape[0]),r1_r2] = 1.
    >>> 9.42 µs ± 15.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
    

    希望这会有所帮助。

    【讨论】:

      【解决方案2】:

      使用 numpy,

      rep_2 = np.where(condition)[1].reshape(rep1.shape[0], 1)
      

      condition 可以有多种表述方式,其中有:

      • rep_1 == 1
      • rep_1 != 0

      取决于您的要求。如果您愿意,请将 rep_2 转换为列表。

      【讨论】:

        【解决方案3】:

        表示 1 --> 2:

        如果您知道每个列表将只有一个1,您可以在list comprehension 中使用list.index

        list_of_lists = [  # Your initial list
            [1, 0, 0],
            [0, 1, 0],
            [0, 0, 1]
        ]
        
        list_of_ones_indices = [[lst.index(1)] for lst in list_of_lists]
        # [0, 1, 2]
        

        表示 2 --> 1:

        This numpy solution 可能更接近您正在寻找的内容。如果你想要一个纯 Python 的解决方案,你可以去:

        index_list = [1, 2, 3]
        LENGTH = 6
        one_hot_list = []
        
        # This can also be achieved with a list comprehension and range()
        for index in index_list:
            one_hot = [0] * LENGTH
            one_hot[index[0]] = 1
            one_hot_list.append(one_hot)
        
        print(one_hot_list)
        # [
        #     [0, 1, 0, 0, 0, 0],
        #     [0, 0, 1, 0, 0, 0],
        #     [0, 0, 0, 1, 0, 0]
        # ]
        

        【讨论】:

        • 请注意,在第一种情况下,您的答案是一个列表,而不是问题中的列表列表
        【解决方案4】:

        IIUC,

        np.argmax(a, axis=1)[:, None]
        

        使用@Yacola 设置:

        r1 = [[1., 0., 0., 0., 0., 0.],
              [0., 0., 0., 1., 0., 0.],
              [0., 0., 0., 0., 1., 0.]]
        
        a = np.array(r1)
        np.argmax(a, axis=1)[:, None]
        

        输出:

        array([[0],
               [3],
               [4]])
        

        【讨论】:

          【解决方案5】:

          要从表示 2 转换为表示 1,您可以使用类似 keras.np_utils.to_categorical:

          >>> y = [0, 1, 2]
          >>> np_utils.to_categorical(y)
          array([[ 1., 0., 0.],
                 [ 0., 1., 0.],
                 [ 0., 0., 1.]])
          

          【讨论】:

          • 请注意,它涉及列表列表:[[0], [1], [2]] 而不是 [0, 1, 2]。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-09-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多