使用熊猫对两个数据框进行多次操作

时间:2020-05-05 20:43:57

标签: python pandas dataframe

这是我上一个问题enter link description here

的扩展

我有两个长度不同的数据帧df1和df2,还有两个列作为关键列。我想对这些数据帧执行以下多个操作:

  1. 基于键列,仅用df2中的相应值替换df1中的空白(NAs)单元格
  2. 对于每个键列对,应在一个新的数据帧中报告两个数据帧中值相互矛盾的单元格

df1

id_col1   id_col2   name    age    sex
---------------------------------------
101         1M              21  
101         3M              21      M
102         1M      Mark    25  

df2

id_col1    id_col2    name     age     sex
-------------------------------------------
101          1M       Steve             M
101          2M                         M
101          3M       Steve    25   
102          1M       Ria      25       M
102          2M       Anie     22       F

执行操作1后,即用df2中的相应值替换df1中的NA,我应该得到以下信息:

result_1

id_col1    id_col2    name     age     sex
-------------------------------------------
101         1M        Steve    21      M
101         3M        Steve    25      M
102         1M        Mark     25      M

执行操作2后,即相同键列的df1和df2中的单元格冲突,我应该得到以下信息:

result_2

id_col1    id_col2    name     age     sex
-------------------------------------------
101          3M                21   
101          3M                25   
102          1M        Mark     
102          1M        Ria      

有人可以帮助解决这些问题吗?

2 个答案:

答案 0 :(得分:1)

使用 df1

enter image description here

df2

enter image description here

合并

df3=df2.merge(df1, left_index=True,right_index=True,suffixes=('_left', ''), how='left')

解决方案1,使用np.where传输详细信息并删除不需要的行

df3['name']=np.where(df3['name'].isna(),df3['name_left'],df3['name'])
df3['sex']=np.where(df3['sex_left'].isna(),df3['sex'],df3['sex_left'])
df4=df3[df3.index.isin(df1.index)].iloc[:,-3::]

结果

enter image description here

您对冲突不太清楚,因此我假设在姓名和年龄方面存在冲突。因此,我不建议使用NaN,因为它们存在于我未填充它们的地方

df3=df3.dropna(subset=['age','age_left'])

一系列布尔选择的派生数据框

df3[(df3['name_left']!=df3['name'])& df3['age_left']!=df3['age']].dropna(thresh=1, inplace=True)

答案 1 :(得分:1)

我将采用的方法与原始问题的答案非常相似。

与原始文章一样,将id列设置为索引,使用combine_first。但是,由于combine_first返回了两个数据框标签(即行和列)的并集,因此在应用后,请仅选择属于df1

的那些索引
idx = ['id_col1', 'id_col2']
df1 = df1.set_index(idx)
df2 = df2.set_index(idx)
result_1 = df1.combine_first(df2).loc[df1.index]
# result_1 outputs:
                  name   age sex
id_col1 id_col2
101     1M       Steve  21.0   M
        3M       Steve  21.0   M
102     1M        Mark  25.0   M

要生成result_2,请首先按照早先帖子中建议的方法进行操作:

mask = pd.notnull(df1) & ~df1.eq(df2) & pd.notnull(df2)
result_2 = pd.concat([df1[mask], df2[mask]]).dropna(how='all')

这会生成所需的数据,但是顺序与您显示的顺序略有不同,因为df1[mask]堆积在df2[mask]的顶部。

按索引排序以获得最终结果:

result_2.sort_index()
# outputs 
                 name   age  sex
id_col1 id_col2
101     3M        NaN  21.0  NaN
        3M        NaN  25.0  NaN
102     1M       Mark   NaN  NaN
        1M        Ria   NaN  NaN

与第一篇文章中介绍的解决方案相比,该解决方案的唯一区别是额外的...loc[df1.index]result_2.sort_index()