Python 基于数据帧列的子集合并和更新数据帧
假设df的大小非常大,我想知道是否有最快的代码来替换这两个for循环。在我的真实案例中,每个数据帧是200行25列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','
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