Python Pandas更新一个数据框的值,来自另一个数据框

70

我有两个Python数据框。我想使用另一个数据框中的匹配值更新第一个数据框中的行。第二个数据框作为覆盖。

这里有一个带有相同数据和代码的示例:

DataFrame 1:

进入图像描述

DataFrame 2:

进入图像描述

我想根据匹配的代码和名称更新数据框1。在此示例中,应将DataFrame1更新如下:

进入图像描述

注意:具有Code =2和Name = Company2的行已更新为值1000(来自数据框2)

import pandas as pd

data1 = {
         'Code': [1, 2, 3],
         'Name': ['Company1', 'Company2', 'Company3'],
         'Value': [200, 300, 400],

    }
df1 = pd.DataFrame(data1, columns= ['Code','Name','Value'])

data2 = {
         'Code': [2],
         'Name': ['Company2'],
         'Value': [1000],
    }

df2 = pd.DataFrame(data2, columns= ['Code','Name','Value'])

有什么指导或提示吗?

10个回答

82

6
这似乎是所有解决方案中最理想的一个......但 Nic,你能帮我一个忙吗?...如果 df1 和 df2 中每个都有5列,但我只想更新“Value”列,而不是其他列(上面的代码会更新与该“index”相关的所有列)......这是否可行?请帮帮我…… - Lokkii9
为什么Value列被转换为float类型? - AXO
这就是我一直在寻找的解决方案。你还可以扩展到多个查找列:df1.set_index(['Code', 'Name'], inplace=True),并且可以更新多个度量列,比如Value、Sales等。 - undefined

41
你可以使用 concat + drop_duplicates,它会更新 df2 中的共同行并添加新的行。
pd.concat([df1,df2]).drop_duplicates(['Code','Name'],keep='last').sort_values('Code')
Out[1280]: 
   Code      Name  Value
0     1  Company1    200
0     2  Company2   1000
2     3  Company3    400

以下评论更新

df1.set_index(['Code', 'Name'], inplace=True)

df1.update(df2.set_index(['Code', 'Name']))

df1.reset_index(drop=True, inplace=True)

10
我想指出这个解决方案不仅会更新entries frame dataframe1,还会添加来自dataframe2的新条目,这些条目在之前的dataframe1中不存在。 - mjspier
2
它还会使内存爆炸,因为在删除重复项之前,它必须复制两个数据框。 - anishtain4

15

您可以先合并数据,然后使用numpy.where,这里是如何使用numpy.where

updated = df1.merge(df2, how='left', on=['Code', 'Name'], suffixes=('', '_new'))
updated['Value'] = np.where(pd.notnull(updated['Value_new']), updated['Value_new'], updated['Value'])
updated.drop('Value_new', axis=1, inplace=True)

   Code      Name   Value
0     1  Company1   200.0
1     2  Company2  1000.0
2     3  Company3   400.0

谢谢。因此,左连接然后更新“Value_new”字段的“Value”字段,以便非 NaN 行。 - ProgSky

14

1
已经存在更早、相同且更好的答案。 - H.C.Chen

9
您可以对齐索引,然后使用 combine_first 函数:
res = df2.set_index(['Code', 'Name'])\
         .combine_first(df1.set_index(['Code', 'Name']))\
         .reset_index()

print(res)

#    Code      Name   Value
# 0     1  Company1   200.0
# 1     2  Company2  1000.0
# 2     3  Company3   400.0

1
这不是一个有效的答案,原因是:通过使用另一个DataFrame中的非空值填充一个DataFrame中的空值来合并两个DataFrame对象。结果DataFrame的行和列索引将是两者的并集。https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.combine_first.html @safiqul islam在下面提到了update函数,它似乎可以工作。https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.update.html - Corina Roca
@CorinaRosa 你能给一个反例吗? - undefined

4
假设companycode是冗余的标识符,您也可以这样做。
import pandas as pd
vdic = pd.Series(df2.Value.values, index=df2.Name).to_dict()

df1.loc[df1.Name.isin(vdic.keys()), 'Value'] = df1.loc[df1.Name.isin(vdic.keys()), 'Name'].map(vdic)

#   Code      Name  Value
#0     1  Company1    200
#1     2  Company2   1000
#2     3  Company3    400

4

我经常做的事情是:

我首先合并“左侧”:

df_merged = pd.merge(df1, df2, how = 'left', on = 'Code')

在Pandas中,会为左侧数据框创建一个带有扩展名 '_x' 的列,为右侧数据框创建一个带有扩展名 '_y' 的列。

您需要的是来自右侧数据框的列。因此,只需删除所有带有 '_x' 扩展名的列,并将 '_y' 扩展名进行重命名即可:

for col in df_merged.columns:
    if '_x' in col:
        df_merged .drop(columns = col, inplace = True)
    if '_y' in col:
        new_name = col.strip('_y')
        df_merged .rename(columns = {col : new_name }, inplace=True)

3
你可以在左连接 df1df2 的结果上使用 pd.Series.where
merged = df1.merge(df2, on=['Code', 'Name'], how='left')
df1.Value = merged.Value_y.where(~merged.Value_y.isnull(), df1.Value)
>>> df1
    Code    Name    Value
0   1   Company1    200.0
1   2   Company2    1000.0
2   3   Company3    400.0

您可以将该行更改为:

df1.Value = merged.Value_y.where(~merged.Value_y.isnull(), df1.Value).astype(int)

为了将值返回为整数。

为什么它会在值后面添加 .0?(不是什么大问题,只是好奇) - ProgSky
1
@ProgSky 这是因为类型发生了变化。我更新了答案,展示如何将其返回为 int - Ami Tavory

2
  1. 追加数据集
  2. 根据code删除重复项
  3. 排序数值
combined_df = combined_df.append(df2).drop_duplicates(['Code'],keep='last').sort_values('Code')

1

以上解决方案均不适用于我的特定示例,我认为问题源于我的列的数据类型,但最终我找到了这个解决方案

indexes = df1.loc[df1.Code.isin(df2.Code.values)].index
df1.at[indexes,'Value'] = df2['Value'].values

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