Concat python 数据帧,删除重复项并保留行原点记录

Tha*_*yen 2 python pandas

我有多个数据框,示例数据:

df1:

user_id    username firstname lastname 
 123         abc      abc       abc
 456         def      def       def 
 789         ghi      ghi       ghi
Run Code Online (Sandbox Code Playgroud)

df2:

user_id     username  firstname lastname
 111         xyz       xyz       xyz
 456         def       def       def
 234         mnp       mnp       mnp
Run Code Online (Sandbox Code Playgroud)

df3:

user_id     username  firstname lastname
 789         ghi       ghi       ghi       
 456         def       def       def
 222         uwv       uwv       uwv       
Run Code Online (Sandbox Code Playgroud)

我想连接这些数据框,删除重复的行,并通过添加更多列来跟踪行的来源。期望的输出:

df1:

user_id    username firstname lastname df1 df2 df3
 123         abc       abc       abc    1   0   0
 456         def       def       def    1   1   1
 789         ghi       ghi       ghi    1   0   1
 111         xyz       xyz       xyz    0   1   0
 234         mnp       mnp       mnp    0   1   0
 222         uwv       uwv       uwv    0   0   1      
Run Code Online (Sandbox Code Playgroud)

我可以通过使用连接来做第一步:

pd.concat([df1, df2, df3]).drop_duplicates('user_id').reset_index(drop=True)
Run Code Online (Sandbox Code Playgroud)

我该如何做最后一步(制作原点列)?我不知道如何在没有 forloop 的情况下执行此操作,这对于大数据框不实用。谢谢

sha*_*eed 5

由于您df's在连接后需要名称的详细信息,因此不应删除它们。

需要将dfname添加为列,以便连接后我们可以知道,哪一行来自df.

>>> cols = df1.columns.to_list() # Store columns before adding `origin` column to use later in groupby
>>> df1['origin'] = 'df1'
>>> df2['origin'] = 'df2'
>>> df3['origin'] = 'df3'
Run Code Online (Sandbox Code Playgroud)

现在,使用groupby您的任务变得容易。

>>> df = pd.concat([df1, df2, df3])\
    .reset_index(drop=True)\
    .groupby(by = cols, axis=0)\
    .apply(lambda x: x['origin'].values)\
    .to_frame('origin')\
    .reset_index()
Run Code Online (Sandbox Code Playgroud)

输出:

>>> df

   user_id username firstname lastname           origin
0      111      xyz       xyz      xyz            [df2]
1      123      abc       abc      abc            [df1]
2      222      uwv       uwv      uwv            [df3]
3      234      mnp       mnp      mnp            [df2]
4      456      def       def      def  [df1, df2, df3]
5      789      ghi       ghi      ghi       [df1, df3]
Run Code Online (Sandbox Code Playgroud)

您需要进行一种热编码才能获得预期的结果,例如(从此处引用)

使用sklearn.preprocessing.MultiLabelBinarizer(你也可以使用pd.get_dummies,检查这个

>>> from sklearn.preprocessing import MultiLabelBinarizer
>>> mlb = MultiLabelBinarizer()
>>> expandedLabelData = mlb.fit_transform(df["origin"])
>>> labelClasses = mlb.classes_
>>> encoded_df = pd.DataFrame(expandedLabelData, columns=labelClasses)
   df1  df2  df3
0    0    1    0
1    1    0    0
2    0    0    1
3    0    1    0
4    1    1    1
5    1    0    1
Run Code Online (Sandbox Code Playgroud)

最后,

>>> pd.concat([df.drop('origin', axis=1), encoded_df], axis=1)
   user_id username firstname lastname  df1  df2  df3
0      111      xyz       xyz      xyz    0    1    0
1      123      abc       abc      abc    1    0    0
2      222      uwv       uwv      uwv    0    0    1
3      234      mnp       mnp      mnp    0    1    0
4      456      def       def      def    1    1    1
5      789      ghi       ghi      ghi    1    0    1
Run Code Online (Sandbox Code Playgroud)