使用一致的映射跨数据框列分解值

Factorize values across dataframe columns with consistent mappings

如何将 pandas factorize 与存在于两列中的值一起使用?

具体来说,我尝试将两列中存在的值转换为数值,并将相应的因式分解值放入新的列中,使得因式分解与两个输入列 'A' 和 'B'.

现有数据框:

     A   B
0    a   b
1    c   a
2    d   a
3    e   c
4    c   b
5    b   e
6    e   f

期望的输出:

     A   B   A_ID  B_ID 
0    a   b     0     4
1    c   a     1     0
2    d   a     2     0
3    e   c     3     1
4    c   b     1     4
5    b   e     4     3
6    e   f     3     5

我可以使用 factorize 成功地用于一列:

df['A_ID'] = pd.factorize(df.A)[0]

如何使用跨两列的值的一致映射来实现这一点?我是否需要求助于使用自定义 lambda 函数,或者有没有办法使用 factorize?

来完成此操作

如果您想重复使用因式分解值,这是一种方法。

In [2637]: facts = np.unique(np.unique(df[['A', 'B']]), return_index=True)

In [2638]: mapping = dict(zip(*facts))

In [2639]: df.join(df[['A', 'B']].apply(lambda x: x.map(mapping)).add_suffix('_ID'))
Out[2639]:
   A  B  A_ID  B_ID
0  a  b     0     1
1  c  a     2     0
2  d  a     3     0
3  e  c     4     2
4  c  b     2     1
5  b  e     1     4
6  e  f     4     5

或者, 使用 replace

In [2640]: df.join(df[['A', 'B']].replace(mapping).add_suffix('_ID'))
Out[2640]:
   A  B  A_ID  B_ID
0  a  b     0     1
1  c  a     2     0
2  d  a     3     0
3  e  c     4     2
4  c  b     2     1
5  b  e     1     4
6  e  f     4     5

并且,为了保留您的值顺序使用

In [2]: mapping = dict(zip(*pd.factorize(df['A'].append(df['B']).drop_duplicates())[::-1]))

In [2]: mapping
Out[2666]: {'a': 0, 'b': 4, 'c': 1, 'd': 2, 'e': 3, 'f': 5}

In [3]: df.join(df[['A', 'B']].replace(mapping).add_suffix('_ID'))
Out[3]:
   A  B  A_ID  B_ID
0  a  b     0     4
1  c  a     1     0
2  d  a     2     0
3  e  c     3     1
4  c  b     1     4
5  b  e     4     3
6  e  f     3     5

详情

In [2641]: facts
Out[2641]:
(array(['a', 'b', 'c', 'd', 'e', 'f'], dtype=object),
 array([0, 1, 2, 3, 4, 5], dtype=int64))

In [2642]: mapping
Out[2642]: {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5}

让我们将 applyadd_suffixpd.factorizeassign 一起使用:

f = pd.factorize(df.stack().drop_duplicates().sort_index(level=1))
s1 = pd.Series(f[0], index=f[1])
print(df.assign(**df.apply(lambda x: x.map(s1)).add_suffix('_ID')))

输出:

   A  B  A_ID  B_ID
0  a  b     0     1
1  c  a     2     0
2  d  a     3     0
3  e  c     4     2
4  c  b     2     1
5  b  e     1     4

更新数据集的输出:

   A  B  A_ID  B_ID
0  a  b     0     4
1  c  a     1     0
2  d  a     2     0
3  e  c     3     1
4  c  b     1     4
5  b  e     4     3
6  e  f     3     5

pd.factorize, apply + pd.Categorical:

_, b = pd.factorize(df.values.T.reshape(-1, ))  
                           # or df.values.ravel('F'), as suggested by Zero
r = df.apply(lambda x: pd.Categorical(x, b).codes).add_suffix('_ID')

   A_ID  B_ID
0     0     4
1     1     0
2     2     0
3     3     1
4     1     4
5     4     3
6     3     5

pd.concat([df, r], 1)

   A  B  A_ID  B_ID
0  a  b     0     4
1  c  a     1     0
2  d  a     2     0
3  e  c     3     1
4  c  b     1     4
5  b  e     4     3
6  e  f     3     5