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

3

I have two dataframes as follows:

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中的“Name”和“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。

有人能帮我解决这个问题吗?

注意:

在尝试以下解决方案后,仍然没有成功:

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

你能否提供你期望的输出结果以验证我们的答案是否正确?同时请提供样本数据,而非图片。 - Yuca
现在添加所需的输出。 - Hanif
1
欢迎来到SO。请查看[提问]并创建一个[mcve]。如果您在发布之前阅读了推荐给您的材料,您会注意到其中明确说明不要包含代码图像。这也包括您的样本数据框。 - user3483203
1
可能是重复的问题,参考pandas:在多个列上合并(连接)两个数据帧 - Yuca
Yuca,如下答案所建议,我尝试了它,但生成的数据框是一个合并版本,它是df1的子集,而不是具有所有行和列的df1。这就是为什么我认为先合并不是更好的解决方案。 - Hanif
显示剩余2条评论
2个回答

2
我会使用merge来连接这两个数据帧。然后你将得到一个包含旧值、新值和nan值的列。最后使用apply来连接这些列。"Original Answer"翻译成"原始回答"。
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。 - Hanif
我不确定我是否理解了问题。删除不必要的行是否解决了您的问题? - ArsenieBoca
请比较我的期望结果(上文)和您的解决方案(上面的solution3)。我希望获得更新以及其他行和列的整个df1。您的解决方案导致生成仅包含更新列的df1和df2合并数据框。 - Hanif
ArsenieBoca,我在你提出的解决方案中添加了进行外部合并的选项,现在它可以工作了! - Hanif
1
太好了,我更新了答案。这就是当你不测试解决方案时会发生的事情^^ - ArsenieBoca

0
# Excel file name df1_df2.xlsx with 2 sheets name df1 & df2
# In df2 the column names are 'Name' 'Id' 'c_2' 'c_4'
# In df1 the column names are 'Name' 'Id' 'c1'  'c2' 'c3' 'c4'
import pandas as pd
import openpyxl
import xlsxwriter
url = "df1_df2.xlsx"
df = pd.ExcelFile(url) 
df1 = df.parse('df1')
df2 = df.parse('df2')
merged = pd.merge(df1,df2, how='outer', on=['Id'])
merged["c2"] = merged.apply(lambda x: x["c2"] if pd.isnull(x["c_2"])   
else x["c_2"], axis=1)
merged.reindex(['Name','Id','c1','c2','c3','c4'], axis=1)

你的回答可以通过添加更多支持信息来改进。请 [编辑] 添加更多细节,例如引用或文档,以便其他人可以确认您的答案是否正确。您可以在 帮助中心 中找到有关编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接