【问题标题】:pandas.factorize on an entire data framepandas.factorize 在整个数据帧上
【发布时间】:2017-01-16 08:10:24
【问题描述】:

pandas.factorize 将输入值编码为枚举类型或分类变量。

但是我怎样才能轻松有效地转换数据框中的许多列呢?反向映射步骤呢?

示例:此数据框包含带有字符串值的列,例如“类型 2”,我想将其转换为数值 - 并可能稍后将它们转换回来。

【问题讨论】:

    标签: python pandas dataframe machine-learning


    【解决方案1】:

    我还发现这个答案很有帮助: https://stackoverflow.com/a/20051631/4643212

    我试图从 Pandas DataFrame 中的现有列(名为“SrcIP”的 IP 地址列表)中获取值,并将它们映射到新列中的数值(在本例中名为“ID”)。

    解决方案:

    df['ID'] = pd.factorize(df.SrcIP)[0]
    

    结果:

            SrcIP | ID    
    192.168.1.112 |  0  
    192.168.1.112 |  0  
    192.168.4.118 |  1 
    192.168.1.112 |  0
    192.168.4.118 |  1
    192.168.5.122 |  2
    192.168.5.122 |  2
    ...
    

    【讨论】:

      【解决方案2】:

      我想重定向我的答案:https://stackoverflow.com/a/32011969/1694714

      旧答案

      当您希望在生成的 DataFrame 中保持类别一致时,此问题的另一个可读解决方案是使用替换:

      def categorise(df):
          categories = {k: v for v, k in enumerate(df.stack().unique())}
          return df.replace(categories)
      

      性能比@jezrael 的示例稍差,但更易于阅读。此外,对于更大的数据集,它可能会更好地升级。如果有人感兴趣,我可以做一些适当的测试。

      【讨论】:

        【解决方案3】:

        如果需要factorize每列单独使用,可以使用apply

        df = pd.DataFrame({'A':['type1','type2','type2'],
                           'B':['type1','type2','type3'],
                           'C':['type1','type3','type3']})
        
        print (df)
               A      B      C
        0  type1  type1  type1
        1  type2  type2  type3
        2  type2  type3  type3
        
        print (df.apply(lambda x: pd.factorize(x)[0]))
           A  B  C
        0  0  0  0
        1  1  1  1
        2  1  2  1
        

        如果你需要相同的字符串值相同的数字:

        print (df.stack().rank(method='dense').unstack())
             A    B    C
        0  1.0  1.0  1.0
        1  2.0  2.0  3.0
        2  2.0  3.0  3.0
        

        如果您只需要对某些列应用该函数,请使用子集:

        df[['B','C']] = df[['B','C']].stack().rank(method='dense').unstack()
        print (df)
               A    B    C
        0  type1  1.0  1.0
        1  type2  2.0  3.0
        2  type2  3.0  3.0
        

        factorize 的解决方案:

        stacked = df[['B','C']].stack()
        df[['B','C']] = pd.Series(stacked.factorize()[0], index=stacked.index).unstack()
        print (df)
               A  B  C
        0  type1  0  0
        1  type2  1  2
        2  type2  2  2
        

        可以通过map dict 将它们翻译回来,您需要通过drop_duplicates 删除重复项:

        vals = df.stack().drop_duplicates().values
        b = [x for x in df.stack().drop_duplicates().rank(method='dense')]
        
        d1 = dict(zip(b, vals))
        print (d1)
        {1.0: 'type1', 2.0: 'type2', 3.0: 'type3'}
        
        df1 = df.stack().rank(method='dense').unstack()
        print (df1)
             A    B    C
        0  1.0  1.0  1.0
        1  2.0  2.0  3.0
        2  2.0  3.0  3.0
        
        print (df1.stack().map(d1).unstack())
               A      B      C
        0  type1  type1  type1
        1  type2  type2  type3
        2  type2  type3  type3
        

        【讨论】:

        • 如果我不想将函数应用于每一列,而只是应用于列列表?
        • 你可以使用子集,给我一秒钟。
        • 如果我必须处理一个大型数据集(100 个分类值和 50 个数值),如何应用您的最后一种方法将它们翻译回来.. 仅用于分类值。我的意思是只对分类变量进行编码,不要触及其他变量。
        • @IbD - 如何区分分类列?喜欢df = df.select_dtypes(object) ?
        • 是的,在我这边我有一些东西:char_cols = df.dtypes.pipe(lambda x: x[x == 'object']).index for c in char_cols: df[c] = pd.factorize(df[c], na_sentinel = 1)[0]
        猜你喜欢
        • 1970-01-01
        • 2020-06-10
        • 2019-09-09
        • 1970-01-01
        • 1970-01-01
        • 2019-10-28
        • 2023-01-12
        • 1970-01-01
        • 2018-08-18
        相关资源
        最近更新 更多