【问题标题】:numpy convert categorical string arrays to an integer arraynumpy 将分类字符串数组转换为整数数组
【发布时间】:2011-03-11 11:50:04
【问题描述】:

我正在尝试将分类变量的字符串数组转换为分类变量的整数数组。

例如

import numpy as np
a = np.array( ['a', 'b', 'c', 'a', 'b', 'c'])
print a.dtype
>>> |S1

b = np.unique(a)
print b
>>>  ['a' 'b' 'c']

c = a.desired_function(b)
print c, c.dtype
>>> [1,2,3,1,2,3] int32

我意识到这可以通过循环来完成,但我想有一种更简单的方法。谢谢。

【问题讨论】:

    标签: python statistics numpy machine-learning


    【解决方案1】:

    np.unique 有一些可选的返回

    return_inverse 给出了我经常使用的整数编码

    >>> b, c = np.unique(a, return_inverse=True)
    >>> b
    array(['a', 'b', 'c'], 
          dtype='|S1')
    >>> c
    array([0, 1, 2, 0, 1, 2])
    >>> c+1
    array([1, 2, 3, 1, 2, 3])
    

    它可以用来从uniques重新创建原始数组

    >>> b[c]
    array(['a', 'b', 'c', 'a', 'b', 'c'], 
          dtype='|S1')
    >>> (b[c] == a).all()
    True
    

    【讨论】:

      【解决方案2】:

      ……多年后……

      为了完整性(因为答案中没有提到)和个人原因(我总是在我的模块中导入了pandas,但不一定是sklearn),这也很简单pandas.get_dummies()

      import numpy as np
      import pandas
      
      In [1]: a = np.array(['a', 'b', 'c', 'a', 'b', 'c'])
      
      In [2]: b = pandas.get_dummies(a)
      
      In [3]: b
      Out[3]: 
            a  b  c
         0  1  0  0
         1  0  1  0
         2  0  0  1
         3  1  0  0
         4  0  1  0
         5  0  0  1
      
      In [3]: b.values.argmax(1)
      Out[4]: array([0, 1, 2, 0, 1, 2])
      

      【讨论】:

      • 谢谢。终于找到了我想要的答案。
      【解决方案3】:

      一种方法是使用scikits.statsmodels 中的categorical 函数。例如:

      In [60]: from scikits.statsmodels.tools import categorical
      
      In [61]: a = np.array( ['a', 'b', 'c', 'a', 'b', 'c'])
      
      In [62]: b = categorical(a, drop=True)
      
      In [63]: b.argmax(1)
      Out[63]: array([0, 1, 2, 0, 1, 2])
      

      categorical (b) 的返回值实际上是一个设计矩阵,因此调用上面的argmax 使其接近您想要的格式。

      In [64]: b
      Out[64]:
      array([[ 1.,  0.,  0.],
             [ 0.,  1.,  0.],
             [ 0.,  0.,  1.],
             [ 1.,  0.,  0.],
             [ 0.,  1.,  0.],
             [ 0.,  0.,  1.]])
      

      【讨论】:

        【解决方案4】:

        另一种选择是使用分类熊猫系列:

        >>> import pandas as pd
        >>> pd.Series(['a', 'b', 'c', 'a', 'b', 'c'], dtype="category").cat.codes.values
        
        array([0, 1, 2, 0, 1, 2], dtype=int8)
        

        【讨论】:

          【解决方案5】:

          另一种方法是使用sklearn.preprocessing.LabelEncoder

          它可以将字符串等可哈希标签转换为介于 0 和n_classes-1 之间的数值。

          这样做是这样的:

          # Repeating setup from the question to make example copy/paste-able
          import numpy as np
          a = np.array( ['a', 'b', 'c', 'a', 'b', 'c'])
          b = np.unique(a)
          
          # Answer to the question
          from sklearn import preprocessing
          pre = preprocessing.LabelEncoder()
          pre.fit(b)
          c = pre.transform(a)
          
          print(c)    # Prints [0 1 2 0 1 2]
          

          如果您坚持让结果数组中的值从 1 开始,您可以在之后简单地执行 c + 1

          将 sklearn 作为项目的依赖项引入只是为了做到这一点可能不值得,但如果您已经导入了 sklearn,这是一个不错的选择。

          【讨论】:

          • 我们怎样才能知道'a'是'0'等等。有什么代码可以返回这样的吗?
          • @bib:我相信在从左到右遍历数组时,每次遇到新字符串时都会分配一个新的运行编号/索引。所以'a'0,因为它是第一个看到的字符串。
          【解决方案6】:

          另一种方法是使用 Pandas factorize 将项目映射到数字:

          In [1]: import numpy as np
          In [2]: import pandas as pd
          In [3]: a = np.array(['a', 'b', 'c', 'a', 'b', 'c'])
          In [4]: a_enc = pd.factorize(a)
          In [5]: a_enc[0]
          Out[5]: array([0, 1, 2, 0, 1, 2])
          In [6]: a_enc[1]
          Out[6]: array(['a', 'b', 'c'], dtype=object)
          

          【讨论】:

            【解决方案7】:

            嗯,这是一个 hack……但它有帮助吗?

            In [72]: c=(a.view(np.ubyte)-96).astype('int32')
            
            In [73]: print(c,c.dtype)
            (array([1, 2, 3, 1, 2, 3]), dtype('int32'))
            

            【讨论】:

            • 您真的想补充一点,这仅适用于长度为 1 的字符串。
            【解决方案8】:

            ...又过了几年...

            我想我会提供一个纯粹的 python 解决方案来保证完整性:

            def count_unique(a):
                def counter(item, c=[0], items={}):
                    if item not in items:
                        items[item] = c[0]
                        c[0] += 1
                    return items[item]
                return map(counter, a)
            
            a = [0, 2, 6, 0, 2]
            print count_unique(a)
            >> [0, 1, 2, 0, 1]
            

            【讨论】:

              【解决方案9】:

              你也可以试试这样的:

              a = np.array( ['a', 'b', 'c', 'a', 'b', 'c'])
              a[a == 'a'] = 1
              a[a == 'b'] = 2
              a[a == 'c'] = 3
              a = a.astype(np.float32)
              

              如果你知道里面有什么并希望为每个值设置特定的索引会更好。

              如果只有两个类别,下一个代码将像魅力一样工作:

              a = np.array( ['a', 'b', 'a', 'b'])
              a = np.float32(y == 'a')
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2013-05-05
                • 2018-09-19
                • 2021-04-26
                • 2015-03-28
                • 2019-04-21
                相关资源
                最近更新 更多