如何在 Pandas 中对一个数据框中的两个类别进行分类

How to categorize two categories in one dataframe in Pandas

我有一个 pd,包括两个分类列和 150 个类别。可能是列 A 中的值未出现在列 B 中。例如

a = pd.DataFrame({'A':list('bbaba'),  'B':list('cccaa')})
a['A'] = a['A'].astype('category')
a['B'] = a['B'].astype('category')

输出为

Out[217]: 
   A  B
0  b  c
1  b  c
2  a  c
3  b  a
4  a  a

还有

cat_columns = a.select_dtypes(['category']).columns
a[cat_columns] = a[cat_columns].apply(lambda x: x.cat.codes)
a

输出为

Out[220]: 
   A  B
0  1  1
1  1  1
2  0  1
3  1  0
4  0  0

我的问题是,在 A 列中,b 被视为 1,但在 B 列中,c 被视为1。但是,我想要这样的东西:

Out[220]: 
   A  B
0  1  2
1  1  2
2  0  2
3  1  0
4  0  0

其中 2 被认为是 c

请注意,我有 150 个不同的标签。

使用 pd.Categorical() 您可以指定类别列表:

In [44]: cats = a[['A','B']].stack().sort_values().unique()

In [45]: cats
Out[45]: array(['a', 'b', 'c'], dtype=object)

In [46]: a['A'] = pd.Categorical(a['A'], categories=cats)

In [47]: a['B'] = pd.Categorical(a['B'], categories=cats)

In [48]: a[cat_columns] = a[cat_columns].apply(lambda x: x.cat.codes)

In [49]: a
Out[49]:
   A  B
0  1  2
1  1  2
2  0  2
3  1  0
4  0  0

如果您对转换为分类代码并能够通过字典访问映射感兴趣,pd.factorize可能更方便。

跨列获取唯一值的算法 via @AlexRiley

a = pd.DataFrame({'A':list('bbaba'),  'B':list('cccaa')})

fact = dict(zip(*pd.factorize(pd.unique(a[['A', 'B']].values.ravel('K')))[::-1]))

b = a.applymap(fact.get)

结果:

   A  B
0  0  2
1  0  2
2  1  2
3  0  1
4  1  1

我们可以一次性使用 pd.factorize

pd.DataFrame(
    pd.factorize(a.values.ravel())[0].reshape(a.shape),
    a.index, a.columns
)

   A  B
0  0  1
1  0  1
2  2  1
3  0  2
4  2  2

或者,如果您想按排序后的类别值进行因式分解,请使用 sort=True 参数

pd.DataFrame(
    pd.factorize(a.values.ravel(), True)[0].reshape(a.shape),
    a.index, a.columns
)

   A  B
0  1  2
1  1  2
2  0  2
3  1  0
4  0  0

或等同于 np.unique

pd.DataFrame(
    np.unique(a.values.ravel(), return_inverse=True)[1].reshape(a.shape),
    a.index, a.columns
)

   A  B
0  1  2
1  1  2
2  0  2
3  1  0
4  0  0