Pandas的factorize在整个数据框上的应用

28

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

但是我如何轻松高效地转换数据帧的多个列呢?那么反向映射步骤呢?

示例:该数据帧包含具有字符串值的列,例如 "type 2",我想将它们转换为数字值,并可能稍后将它们翻译回来。

enter image description here

3个回答

51

如果您需要单独对每列进行因式分解,可以使用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

通过dict,可以使用map将它们翻译回来,您需要使用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

如果我不想将函数应用于每一列,只想应用于一列列表怎么办? - clstaudt
你可以使用子集,等我一下。 - jezrael
如果我有一个大数据集(100个分类值和50个数值),如何应用您的最后一种方法来将它们转换回去,只是针对分类变量。我的意思是仅对分类变量进行编码,不涉及其他变量。 - Ib D
@IbD - 如何区分分类列?例如 df = df.select_dtypes(object) - jezrael
是的,从我的角度来看,我有一些类似的东西:char_cols = df.dtypes.pipe(lambda x: x[x == 'object']).index对于每个c in char_cols: df[c] = pd.factorize(df[c], na_sentinel = 1)[0] - Ib D
目标是将分类列(dtype = object)与其他列分开,并执行与您上一个答案中最后一部分相同的工作。 - Ib D

11

我也觉得这个答案非常有帮助:https://dev59.com/QmUo5IYBdhLWcg3w2CaJ#20051631

我想从 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
...

0
我想要重定向我的回答:https://dev59.com/_FwY5IYBdhLWcg3w9rza#32011969 旧的回答 另一个可读的解决方案是使用replace来解决这个问题,当你想要在结果DataFrame中保持类别一致时。
def categorise(df):
    categories = {k: v for v, k in enumerate(df.stack().unique())}
    return df.replace(categories)

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接