【问题标题】:Python Pandas update a dataframe value from another dataframePython Pandas 从另一个数据帧更新数据帧值
【发布时间】:2018-04-19 19:05:10
【问题描述】:

我在 python 中有两个数据框。我想使用来自另一个数据帧的匹配值更新第一个数据帧中的行。第二个数据框用作覆盖。

这是一个数据和代码相同的例子:

数据帧 1:

数据帧 2:

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

注意:代码 =2 和名称 = Company2 的行已更新为值 1000(来自 Dataframe 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'])

任何指针或提示?

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    使用 DataFrame.update,它在索引上对齐 (https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.update.html):

    >>> df1.set_index('Code', inplace=True)
    >>> df1.update(df2.set_index('Code'))
    >>> df1.reset_index()  # to recover the initial structure
    
       Code      Name   Value
    0     1  Company1   200.0
    1     2  Company2  1000.0
    2     3  Company3   400.0
    

    【讨论】:

    • 这似乎是所有解决方案中最理想的...但是 Nic,您能帮我做一件事吗?...如果 df1 和 df2 各有 5 列,但我想仅更新“值”列,而不更新其余列(上面的代码更新与该“索引”有关的所有列)......这可能吗?请帮助...
    【解决方案2】:

    您可以使用concat + drop_duplicates

    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
    

    由于以下cmets而更新

    df1.set_index(['Code', 'Name'], inplace=True)
    
    df1.update(df2.set_index(['Code', 'Name']))
    
    df1.reset_index(drop=True, inplace=True)
    

    【讨论】:

    • 只想指出,此解决方案不仅更新了条目框架 dataframe1,而且还添加了来自 dataframe2 的新条目,这些条目之前在 dataframe1 中不存在。
    • 它还会炸毁内存,因为它必须在删除副本之前复制两个数据帧。
    • @anishtain4 好的并更新~
    【解决方案3】:

    可以先合并数据再使用numpy.where,here的使用方法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' 更新非 NaN 行的 'Value' 字段。
    【解决方案4】:

    有一个更新功能可用

    示例:

    df1.update(df2)

    更多信息:

    https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.update.html

    【讨论】:

    • 旧的相同和更好的答案已经存在
    【解决方案5】:

    您可以对齐索引,然后使用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
    

    【讨论】:

    【解决方案6】:

    假设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
    

    【讨论】:

      【解决方案7】:

      你可以在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 是因为类型变了。我更新了答案以显示如何将其返回给int
      【解决方案8】:

      我经常做一些事情。

      我先合并'left':

      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)
      

      【讨论】:

        【解决方案9】:
        1. 附加数据集
        2. 通过code删除副本
        3. 对值进行排序
        combined_df = combined_df.append(df2).drop_duplicates(['Code'],keep='last').sort_values('Code')
        

        【讨论】:

          【解决方案10】:

          以上解决方案都不适用于我的特定示例,我认为这源于我的专栏的 dtype,但我最终找到了这个解决方案

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-09-20
            • 2019-07-10
            • 2023-03-25
            • 2016-09-15
            • 2021-05-27
            • 1970-01-01
            • 2018-03-09
            • 2021-06-19
            相关资源
            最近更新 更多