Python 基于数据帧列的子集合并和更新数据帧

Python 基于数据帧列的子集合并和更新数据帧,python,pandas,dataframe,Python,Pandas,Dataframe,假设df的大小非常大,我想知道是否有最快的代码来替换这两个for循环。在我的真实案例中,每个数据帧是200行25列 data_df1 = np.array([['Name','Unit','Attribute','Date'],['a','A',1,2014],['b','B',2,2015],['c','C',3,2016],\ ['d','D',4,2017],['e','E',5,2018]]) data_df2 = np.array([['Name','

假设df的大小非常大,我想知道是否有最快的代码来替换这两个for循环。在我的真实案例中,每个数据帧是200行25列

data_df1 = np.array([['Name','Unit','Attribute','Date'],['a','A',1,2014],['b','B',2,2015],['c','C',3,2016],\
                 ['d','D',4,2017],['e','E',5,2018]])
data_df2 = np.array([['Name','Unit','Date'],['a','F',2019],['b','G',2020],['e','H',2021],\
                 ['f','I',2022]])
df1 = pd.DataFrame(data=data_df1)
print('df1:')
print(df1)
df2 = pd.DataFrame(data=data_df2)
print('df2:')
print(df2)
row_df1 = [1,2,5]
col_df1 = [1,3]
row_df2 = [1,2,3]
col_df2 = [1,2]
for i in range(0,len(row_df1)):
    for j in range(0, len(col_df1)):
        df1.set_value(row_df1[i],col_df1[j], df2.loc[row_df2[i],col_df2[j]])
print('df1 after operation:')
print(df1)
预期产出:

df1:
      0     1          2     3
0  Name  Unit  Attribute  Date
1     a     A          1  2014
2     b     B          2  2015
3     c     C          3  2016
4     d     D          4  2017
5     e     E          5  2018
df2:
      0     1     2
0  Name  Unit  Date
1     a     F  2019
2     b     G  2020
3     e     H  2021
4     f     I  2022
df1 after operation:
      0     1          2     3
0  Name  Unit  Attribute  Date
1     a     F          1  2019
2     b     G          2  2020
3     c     C          3  2016
4     d     D          4  2017
5     e     H          5  2021
我试过:

df1.loc[[1,2,5],[1,3]] = df2.loc[[1,2,3],[1,2]]
print('df1:')
print(df1)
print('df2:')
print(df2)
但结果如下。有一些意想不到的问题

df1:
      0     1          2     3
0  Name  Unit  Attribute  Date
1     a     F          1   NaN
2     b     G          2   NaN
3     c     C          3  2016
4     d     D          4  2017
5     e   NaN          5   NaN
df2:
      0     1     2
0  Name  Unit  Date
1     a     F  2019
2     b     G  2020
3     e     H  2021
4     f     I  2022
提前感谢您的帮助。

一些清洁:

def clean_df(df):
    df.columns = df.iloc[0]
    df.columns.name = None        
    df = df.iloc[1:].reset_index()

    return df

df1 = clean_df(df1)
df1
   index Name Unit Attribute  Date
0      1    a    A         1  2014
1      2    b    B         2  2015
2      3    c    C         3  2016
3      4    d    D         4  2017
4      5    e    E         5  2018

df2 = clean_df(df2)
df2    
   index Name Unit  Date
0      1    a    F  2019
1      2    b    G  2020
2      3    e    H  2021
3      4    f    I  2022

使用
merge
,指定
on=Name
,因此不考虑其他列

cols = ['Name', 'Unit_y', 'Attribute', 'Date_y']
df1 = df1.merge(df2, how='left', on='Name')[cols]\
              .rename(columns=lambda x: x.split('_')[0]).fillna(df1)

df1
  Name Unit Attribute  Date
0    a    F         1  2019
1    b    G         2  2020
2    c    C         3  2016
3    d    D         4  2017
4    e    H         5  2021

另一种基于转置数据帧和ffill的合并和删除副本的方法,即

new_df = df1.merge(df2,on=[0],how='outer').T.set_index(0).sort_index()
        .ffill().reset_index().drop_duplicates(0,keep='last').T.dropna()
转置后的数据帧将提供数据帧,以便我们可以应用ffill来填充nan值

1 2 3 4 5 6 0 Attribute 1 2 3 4 5 NaN Date 2014 2015 2016 2017 2018 NaN Date 2019 2020 NaN NaN 2021 2022 Name a b c d e f Unit A B C D E NaN Unit F G NaN NaN H I 这将使用前面的行数据填充nan值,并使用子集0的删除副本重置_索引,保留最后一行将保留完全填充的行

0 1 2 3 4 5 6 0 Attribute 1 2 3 4 5 NaN 2 Date 2019 2020 2016 2017 2021 2022 3 Name a b c d e f 5 Unit F G C D H I
这将旋转dataframe并删除带有nan值的行,从而获得所需的输出。

我还发现下面的代码实现了我想要的功能,比两个for循环快得多

df1.loc[[1,2,5],[1,3]] = df2.loc[[1,2,3],[1,2]].values

@如果你坚持说你得到了错误的答案,那是因为你的数据,而不是我的问题。我应该注意到,这是你第二次这样做,拒绝承认为回答你的问题所付出的努力以及随之而来的损坏的数据。@COLDSPEED我非常感谢你的帮助。事实上,我在笔记本中看到的结果是,在使用df1.T.reset_index()后,T没有第一行-列索引0,1,2,3,即“Name”、“Unit”等。结果返回为df1.columns.values。@John跳过这一步。@COLDSPEED我已将您的答案标记为回答我的问题question@John很乐意帮忙。另一个呢?
.ffill().reset_index().drop_duplicates(0,keep='last')
0 1 2 3 4 5 6 0 Attribute 1 2 3 4 5 NaN 2 Date 2019 2020 2016 2017 2021 2022 3 Name a b c d e f 5 Unit F G C D H I
.T.dropna()
df1.loc[[1,2,5],[1,3]] = df2.loc[[1,2,3],[1,2]].values