外部合并 pandas 个具有覆盖的数据帧
Outer merge pandas dataframes with overwrite
我有两个 DataFrames df_old
和 df_new
具有相同的列 x
(=标识符或索引)和 y
(=数据)。
现在我想覆盖 df_old
中可用的数据 df_new
+ 添加 df_new
中不在 df_old
中的数据,所以基本上是一个外部合并 x
并覆盖 y
.
我用 pandas.DataFrame.merge
和 pandas.DataFrame.update
尝试过,但我无法在一行中或不进行逐行计算就获得所需的结果。
示例:
x = np.array(range(0, 10))
y = np.array(range(0, 10))
df_old = pd.DataFrame(data={'x':x,'y':y})
x = np.array(range(5, 15))
y = np.array(range(0, 10))
df_new = pd.DataFrame(data={'x':x,'y':y})
x = np.array(range(0, 15))
y = np.append(np.array(range(0, 5)), np.array(range(0, 10)))
df_desired = pd.DataFrame(data={'x':x,'y':y})
编辑:
解决方案的重点应该放在执行时间和内存效率上。简单的解决方案,例如单线会很好。
所以我会按照你的建议使用pd.merge
,然后处理数据以尽可能覆盖。
使用您的示例:
df_merged = pd.merge(df_old, df_new, on="x", how="outer")
>>> df_merged
x y_x y_y
0 0 0.0 NaN
1 1 1.0 NaN
2 2 2.0 NaN
3 3 3.0 NaN
4 4 4.0 NaN
5 5 5.0 0.0
6 6 6.0 1.0
7 7 7.0 2.0
8 8 8.0 3.0
9 9 9.0 4.0
10 10 NaN 5.0
11 11 NaN 6.0
12 12 NaN 7.0
13 13 NaN 8.0
14 14 NaN 9.0
然后创建一个新的 y 列,并在适用的情况下使用您想要覆盖旧数据的数据:
df_merged["y"] = [y if pd.notna(y) else x for x,y in zip(df_merged["y_x"], df_merged["y_y"])]
>>> df_merged
x y_x y_y y
0 0 0.0 NaN 0.0
1 1 1.0 NaN 1.0
2 2 2.0 NaN 2.0
3 3 3.0 NaN 3.0
4 4 4.0 NaN 4.0
5 5 5.0 0.0 0.0
6 6 6.0 1.0 1.0
7 7 7.0 2.0 2.0
8 8 8.0 3.0 3.0
9 9 9.0 4.0 4.0
10 10 NaN 5.0 5.0
11 11 NaN 6.0 6.0
12 12 NaN 7.0 7.0
13 13 NaN 8.0 8.0
14 14 NaN 9.0 9.0
然后 select 正确的列:
df_merged = df_merged[["x","y"]]
>>> df_merged
x y
0 0 0.0
1 1 1.0
2 2 2.0
3 3 3.0
4 4 4.0
5 5 0.0
6 6 1.0
7 7 2.0
8 8 3.0
9 9 4.0
10 10 5.0
11 11 6.0
12 12 7.0
13 13 8.0
14 14 9.0
我找到了一个可能的有效解决方案,因为它只使用布尔映射,但它仍然很丑陋,我希望 pandas 有一个更方便的解决方案来处理此类任务:
df_desired = pd.merge(df_old, df_new, how='outer', on='x')
df_desired['y'] = df_desired.loc[df_desired['y_y'].isna(), 'y_x'].append(df_desired.loc[df_desired['y_y'].notna(), 'y_y'])
df_desired = df_desired[['x','y']]
编辑:我的最终解决方案如下所示:
df_desired = pd.merge(df_old, df_new, how='outer', on='x')
df_desired.loc[df_desired['y_y'].isnull(), 'y_y'] = df_desired['y_x']
df_desired = df_desired.drop('y_x', axis=1).rename({'y_y': 'y'}, axis=1)
我有两个 DataFrames df_old
和 df_new
具有相同的列 x
(=标识符或索引)和 y
(=数据)。
现在我想覆盖 df_old
中可用的数据 df_new
+ 添加 df_new
中不在 df_old
中的数据,所以基本上是一个外部合并 x
并覆盖 y
.
我用 pandas.DataFrame.merge
和 pandas.DataFrame.update
尝试过,但我无法在一行中或不进行逐行计算就获得所需的结果。
示例:
x = np.array(range(0, 10))
y = np.array(range(0, 10))
df_old = pd.DataFrame(data={'x':x,'y':y})
x = np.array(range(5, 15))
y = np.array(range(0, 10))
df_new = pd.DataFrame(data={'x':x,'y':y})
x = np.array(range(0, 15))
y = np.append(np.array(range(0, 5)), np.array(range(0, 10)))
df_desired = pd.DataFrame(data={'x':x,'y':y})
编辑: 解决方案的重点应该放在执行时间和内存效率上。简单的解决方案,例如单线会很好。
所以我会按照你的建议使用pd.merge
,然后处理数据以尽可能覆盖。
使用您的示例:
df_merged = pd.merge(df_old, df_new, on="x", how="outer")
>>> df_merged
x y_x y_y
0 0 0.0 NaN
1 1 1.0 NaN
2 2 2.0 NaN
3 3 3.0 NaN
4 4 4.0 NaN
5 5 5.0 0.0
6 6 6.0 1.0
7 7 7.0 2.0
8 8 8.0 3.0
9 9 9.0 4.0
10 10 NaN 5.0
11 11 NaN 6.0
12 12 NaN 7.0
13 13 NaN 8.0
14 14 NaN 9.0
然后创建一个新的 y 列,并在适用的情况下使用您想要覆盖旧数据的数据:
df_merged["y"] = [y if pd.notna(y) else x for x,y in zip(df_merged["y_x"], df_merged["y_y"])]
>>> df_merged
x y_x y_y y
0 0 0.0 NaN 0.0
1 1 1.0 NaN 1.0
2 2 2.0 NaN 2.0
3 3 3.0 NaN 3.0
4 4 4.0 NaN 4.0
5 5 5.0 0.0 0.0
6 6 6.0 1.0 1.0
7 7 7.0 2.0 2.0
8 8 8.0 3.0 3.0
9 9 9.0 4.0 4.0
10 10 NaN 5.0 5.0
11 11 NaN 6.0 6.0
12 12 NaN 7.0 7.0
13 13 NaN 8.0 8.0
14 14 NaN 9.0 9.0
然后 select 正确的列:
df_merged = df_merged[["x","y"]]
>>> df_merged
x y
0 0 0.0
1 1 1.0
2 2 2.0
3 3 3.0
4 4 4.0
5 5 0.0
6 6 1.0
7 7 2.0
8 8 3.0
9 9 4.0
10 10 5.0
11 11 6.0
12 12 7.0
13 13 8.0
14 14 9.0
我找到了一个可能的有效解决方案,因为它只使用布尔映射,但它仍然很丑陋,我希望 pandas 有一个更方便的解决方案来处理此类任务:
df_desired = pd.merge(df_old, df_new, how='outer', on='x')
df_desired['y'] = df_desired.loc[df_desired['y_y'].isna(), 'y_x'].append(df_desired.loc[df_desired['y_y'].notna(), 'y_y'])
df_desired = df_desired[['x','y']]
编辑:我的最终解决方案如下所示:
df_desired = pd.merge(df_old, df_new, how='outer', on='x')
df_desired.loc[df_desired['y_y'].isnull(), 'y_y'] = df_desired['y_x']
df_desired = df_desired.drop('y_x', axis=1).rename({'y_y': 'y'}, axis=1)