【问题标题】:How do I discretize values in a pandas DataFrame and convert to a binary matrix?如何离散化 pandas DataFrame 中的值并转换为二进制矩阵?
【发布时间】:2012-06-03 05:37:59
【问题描述】:

我的意思是这样的:

我有一个DataFrame,其中的列可能是分类的或名义的。对于每个观察(行),我想生成一个新行,其中变量的每个可能值现在都是它自己的二进制变量。比如这个矩阵(第一行是列标签)

'a'     'b'     'c'
one     0.2     0
two     0.4     1
two     0.9     0
three   0.1     2
one     0.0     4
two     0.2     5

会被转换成这样的:

'a'              'b'                                                    'c'
one  two  three  [0.0,0.2)  [0.2,0.4)  [0.4,0.6)  [0.6,0.8)  [0.8,1.0]   0   1   2   3   4   5

 1    0     0        0          1          0          0          0       1   0   0   0   0   0
 0    1     0        0          0          0          0          1       0   1   0   0   0   0
 0    1     0        0          0          0          0          1       1   0   0   0   0   0
 0    0     1        1          0          0          0          0       0   0   1   0   0   0
 1    0     0        1          0          0          0          0       0   0   0   0   1   0
 0    1     0        0          1          0          0          0       0   0   0   0   0   1

初始矩阵中的每个变量(列)都被合并为所有可能的值。如果它是分类的,那么每个可能的值都会成为一个新列。如果它是一个浮点数,那么这些值会以某种方式分箱(例如,总是分成 10 个分箱)。如果它是一个 int,那么它可以是所有可能的 int 值,或者也可能是 binning。

仅供参考:在我的实际应用程序中,表格最多有 200 万行,而完整的“扩展”矩阵可能有数百列。

有没有简单的方法来执行这个操作?

另外,我也愿意跳过这一步,因为我真的想计算一个 Burt 表(它是交叉表的对称矩阵)。有没有一种简单的方法可以用crosstab 函数做类似的事情?否则,计算交叉表只是一个简单的矩阵乘法。

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    您可以使用某种广播:

        In [58]: df
        Out[58]:
               a    b  c
        0    one  0.2  0
        1    two  0.4  1
        2    two  0.9  0
        3  three  0.1  2
        4    one  0.0  4
        5    two  0.2  5
    
        In [41]: (df.a.values[:,numpy.newaxis] == df.a.unique()).astype(int)
        Out[41]:
        array([[1, 0, 0],
               [0, 1, 0],
               [0, 1, 0],
               [0, 0, 1],
               [1, 0, 0],
               [0, 1, 0]])
    
        In [54]: ((0 <= df.b.values[:,numpy.newaxis]) & (df.b.values[:,numpy.newaxis] < 0.2)).astype(int)
        Out[54]:
        array([[0],
               [0],
               [0],
               [1],
               [1],
               [0]])
    
        In [59]: (df.c.values[:,numpy.newaxis] == df.c.unique()).astype(int)
        Out[59]:
        array([[1, 0, 0, 0, 0],
               [0, 1, 0, 0, 0],
               [1, 0, 0, 0, 0],
               [0, 0, 1, 0, 0],
               [0, 0, 0, 1, 0],
               [0, 0, 0, 0, 1]])
    

    然后将所有部分与pandas.concat 或类似的连接在一起。

    【讨论】:

    • 有没有办法通过巧妙地使用crosstabpivot_tablestack 或类似的东西来执行类似的操作?
    • 当然,对于 'a' 和 'c' 很简单:pandas.concat([pandas.crosstab(df.index, [df.a]), pandas.crosstab(df.index, [df.c])], axis=1)。对于'b',我想可以在crosstab 中指定一个正确的aggfunc ...
    【解决方案2】:

    请注意,我已经实现了新的 cutqcut 函数来离散化连续数据:

    http://pandas-docs.github.io/pandas-docs-travis/basics.html#discretization-and-quantiling

    【讨论】:

      【解决方案3】:

      将其他几个 cmets 组合成一个回答 OPs 问题的答案。

      d = {'a' : pd.Series(['one', 'two', 'two', 'three', 'one', 'two']), 
           'b' : pd.Series([0.2, 0.4, 0.9, 0.1, 0.0, 0.2]),
           'c' : pd.Series([0, 1, 0, 2, 4, 5]) }
      
      data = pd.DataFrame(d)
      a_cols = pd.crosstab(data.index, [data.a])
      b_bins = pd.cut(data.b, [0.0, 0.2, 0.4, 0.6, 0.8, 1.0], right=False)
      b_cols = pd.crosstab(data.index, b_bins)
      c_cols = pd.crosstab(data.index, [data.c], )
      new_data = a_cols.join(b_cols).join(c_cols)
      new_data.index.names = ['']
      print new_data.to_string()
      
      """
             one  three  two  [0, 0.2)  [0.2, 0.4)  [0.4, 0.6)  [0.8, 1)  0  1  2  4  5
      
          0    1      0    0         0           1           0         0  1  0  0  0  0
          1    0      0    1         0           0           1         0  0  1  0  0  0
          2    0      0    1         0           0           0         1  1  0  0  0  0
          3    0      1    0         1           0           0         0  0  0  1  0  0
          4    1      0    0         1           0           0         0  0  0  0  1  0
          5    0      0    1         0           1           0         0  0  0  0  0  1
      """
      

      【讨论】:

        【解决方案4】:

        我怀疑你会打败patsy 的简单性。它专为这项任务而设计:

        >>> from patsy import dmatrix
        >>> dmatrix('C(a) + C(b) + C(c) - 1', df, return_type='dataframe')
        
           C(a)[one]  C(a)[three]  C(a)[two]  C(b)[T.0.1]  C(b)[T.0.2]  C(b)[T.0.4]   C(b)[T.0.9]  C(c)[T.1]  C(c)[T.2]  C(c)[T.4]  C(c)[T.5]  
        0          1            0          0            0            1            0             0          0          0          0          0  
        1          0            0          1            0            0            1             0          1          0          0          0  
        2          0            0          1            0            0            0             1          0          0          0          0  
        3          0            1          0            1            0            0             0          0          1          0          0  
        4          1            0          0            0            0            0             0          0          0          1          0  
        5          0            0          1            0            1            0             0          0          0          0          1  
        

        这里C(a) 表示将变量转换为分类,-1 是为了避免输出截距列。

        【讨论】:

          【解决方案5】:

          对于示例中的ac 列等标记列,您可以使用pandas 内置方法get_dummies()

          例如:

          import pandas as pd
          s1 = ['a', 'b', np.nan]
          pd.get_dummies(s1)
                 a  b
              0  1  0
              1  0  1
              2  0  0
          

          【讨论】:

          • 哇!这是一个伟大的。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-04-21
          • 1970-01-01
          • 2016-03-06
          • 1970-01-01
          • 2022-01-23
          • 1970-01-01
          • 2015-09-17
          相关资源
          最近更新 更多