Python 使用一致映射跨数据帧列分解值

Python 使用一致映射跨数据帧列分解值,python,pandas,dataframe,categories,Python,Pandas,Dataframe,Categories,如何对跨两列存在的值使用pandasfactorize 具体来说,我尝试将两列中存在的值转换为数值,并将相应的分解值放入新列中,以便分解与两个输入列“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

如何对跨两列存在的值使用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
我能够使用以下方法成功地对一列使用
因子分解

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

如何通过跨两列的值的一致映射来实现这一点?我是否需要转而使用自定义的
lambda
函数,或者是否有一种方法可以通过
factorize
实现这一点?

如果您想重用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

或,使用
替换

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}

让我们使用
apply
add_suffix
pd.factorize
assign

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
具有更新数据集的输出:
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

感谢@Zero,这适用于我的原始问题,其中B列中的所有值也出现在A列中。我更新了B列中有一个不在A列中的值的问题。我如何解决这种情况?目前,在这种情况下,
B_ID
将返回
NaN
,因为该值在
facts
中不存在。另外,在我的系统上,
B_ID
值以双倍(4.0,0.0,…)的形式返回。在这个过程中,如何将它们转换为int,以匹配
A_ID
?我喜欢在这个解决方案中使用numpy整形+1@ScottBoston感兴趣地返回:-)您可以使用
df.values.ravel('F')
代替
df.values.T.restrape(-1,)
aswell@Zero真漂亮!谢谢:-)谢谢@cᴏʟᴅsᴘᴇᴇᴅ, 这很有效。我用一个额外的列“C”更新了这个问题。因此,当我在解决方案的第1行和第2行中使用
df[['A','B']]
而不是
df
来解释并在数据框中包含这个额外的列“C”时,这对我来说是有效的。这是解决这个问题的最佳方法吗?
_, 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