根据另一个选定的行和列部分更新数据框

Posted

技术标签:

【中文标题】根据另一个选定的行和列部分更新数据框【英文标题】:Partially update a dataframe based on selected rows and columns from another 【发布时间】:2019-12-19 02:02:14 【问题描述】:

我有两个数据框如下:

df1

Name    Id   c1  c2  c3  c4
---------------------------
asd     101  a   b   c   d
cdf     231  e   ?   1  
zxs     342  f   o      
ygg     521  g   k   p  
mlk     432  h   m       z
abc     343  c   x   q  
xyz     254  1   d   2  
fgg     165  c   z   d   mm
mnd     766  2   d   v  

df2

df2_Name    df2_Id  df2_c2  df2_c4
----------------------------------
asd          101      h      d2
ygg          521      x      cd
fgg          165      o      cm

我想将 df1 中的“名称”和“id”与 df2 的“df2_Name”和“df2_id”进行匹配。只要找到匹配项,df1 中的“c2”和“c4”的值就会被 df2 中的“df2_c2”和“df2_c4”中的值替换。

期望的输出

Name    Id    c1    c2  c3  c4
-------------------------------
asd     101    a    h   c   d2
cdf     231    e    ?   1   
zxs     342    f    o       
ygg     521    g    x   p   cd
mlk     432    h    m       z
abc     343    c    x   q   
xyz     254    1    d   2   
fgg     165    c    o   d   cm
mnd     766    2    d   v   

尝试解决方案 1

df1[df1.set_index(['Name', 'id']).index.isin(df2.set_index(['df2_Name','df2_id']).index)].iloc[:,[3,5]].update(df2.iloc[:,[2,3]]) 

结果: 原 df1 原样返回。

已尝试解决方案 2

df1.loc[df1.set_index(['Name', 'id']).index.isin(df2.set_index(['df2_Name','df2_id']).index), ['c2', 'c4']] = df2[['df2_c2', 'df2_c4']]

结果:引入了 NaN

Name    id   c1 c2  c3  c4
----------------------------
asd     101  a  NaN c   NaN
cdf     231  e  ?   1   
zxs     342  f  o       
ygg     521  g  NaN p   NaN
mlk     432  h  m       z
abc     343  c  x   q   
xyz     254  1  d   2   
fgg     165  c  NaN d   NaN
mnd     766  2  d   v   

已尝试的解决方案 3(仅适用于 c2)

merged = df1.merge(df2, left_on=["id", "Name"], right_on=["df2_id", "df2_Name"])

merged["c2"] = merged.apply(lambda x: x["c2"] if pd.isnull(x["df2_c2"]) else x["df2_c2"], axis=1)

结果:

Name    id    c1 c2 c3  c4  df2_Name    df2_id  df2_c2  df2_c4
--------------------------------------------------------------
asd     101   a   h c   d   asd         101      h       d2
ygg     521   g   x p       ygg         521      x       cd
fgg     165   c   o d   mm  fgg         165      o       cm

此解决方案 3 替换了选定列的值,但是它返回合并的数据框,而不是带有更新的整个 df1。

谁能帮我解决这个问题?

注意:

在尝试以下解决方案后提出此问题,但没有成功:

    update-a-pandas-dataframe-with-data-from-another-dataframe replace-column-values-based-on-another-dataframe-python-pandas-better-way

【问题讨论】:

你能提供你想要的输出来证实我们答案的正确性吗?同时提供样本数据,而不是图片 现在添加了所需的输出。 欢迎来到 SO。请查看How to Ask 并创建minimal reproducible example。如果您在发布之前阅读了推荐给您的材料,您会注意到其中明确指出不包括代码图像。这包括您的示例数据框。 pandas: merge (join) two data frames on multiple columns的可能重复 尤卡,这不是简单的合并操作。它是一个部分替换操作,其中棘手的部分不是合并列,而是用新值替换某些列值。 【参考方案1】:

我会使用merge 来加入这两个数据框。然后,您将获得包含旧值的列以及包含新值和 nan 值的列。之后使用apply 加入这些列:

merged = df1.merge(df2, how='outer', left_on=["id", "name"], right_on=["df2_id", "df2_name"])
merged["c2"] = merged.apply(lambda x: x["c2"] if pd.isnull(x["df2_c2"]) else x["df2_c2"], axis=1)
# Same for c4
# Drop df2_c2 and df2_c4

我目前无法对其进行测试,因此请告诉我这是否适合您。

【讨论】:

尝试了您的解决方案。它可以使用 df2_c2 值替换 df1 中 C2 的值,但是生成的合并数据帧不是 df1,而是合并 df1 和 df2 后的结果数据帧。更换完成后,我想取回 df1。 我不确定我是否遇到了问题。删除不需要的行能解决您的问题吗? 请比较我想要的结果(上)和你的解决方案(上面的解决方案3)。我有兴趣获得更新的整个 df1 以及其他行和列。您的解决方案导致生成 df1 和 df2 的合并数据框,其中仅包含更新的列。 ArsenieBoca,我在您建议的解决方案中添加了进行外部合并的选项,然后它就可以工作了! 太好了,我更新了答案。当你不测试你的解决方案时会发生这种情况^^

以上是关于根据另一个选定的行和列部分更新数据框的主要内容,如果未能解决你的问题,请参考以下文章

如何根据行Spark DataFrame的数组值创建新的行和列[重复]

通过直接索引数据框来选择特定的行和列

如何将特定的行和列值乘以常数来创建新列?

请问如何获得GridView选中行的每一列的信息?

在python中通过多个条件合并不同数量的行和列

Pyspark - 使用 python 或 pyspark 转换 excel 文件的行和列