pandas 如何将df2合并到df1并在合并时填写NaN?

8wtpewkr  于 2023-03-28  发布在  其他
关注(0)|答案(3)|浏览(155)

我有2个 Dataframe df1, df2
df1具有列["id", "time", "cost", "quantity]
df2具有列["id", "time", "modified_cost", "modified_quantity]
我想将df2合并到df1中。目前我正在做

df1 = df1.merge(df2["id", "time", "modified_cost", "modified_quantity"], on=["id", "time"], how="left")

但是如果df2没有与df1相同的["id", "time"]集合,那么这最终会填充NaN。
下面是一个例子:

import pandas as pd

df1 = pd.DataFrame({"id": [1,2,3,4], "time": [3, 4, 5, 6], "cost": [1.1, 2.2, 3.3, 4.4], "quantity": [10,20,30,40]})

df2 = pd.DataFrame({"id": [2,3,4], "time": [4, 5, 6], "modified_cost": [2.2, 3.3, 4.4], "modified_quantity": [20,30,40]}) 

df1 = df1.merge(df2, on=["id", "time"], how="left")

print(df1)

给予

id  time  cost  quantity  modified_cost  modified_quantity
0   1     3   1.1        10            NaN                NaN
1   2     4   2.2        20            2.2               20.0
2   3     5   3.3        30            3.3               30.0
3   4     6   4.4        40            4.4               40.0

而不是这样,我希望NaN成为costquantity列中的任何内容,因此

id  time  cost  quantity  modified_cost  modified_quantity
0   1     3   1.1        10            1.1                10.0
1   2     4   2.2        20            2.2               20.0
2   3     5   3.3        30            3.3               30.0
3   4     6   4.4        40            4.4               40.0

合并时如何实现此行为?
目前,唯一的解决办法,我知道的是这样做后合并

df1.loc[df1.modified_cost.isna(), "modified_cost"] = df1[df1.modified_cost.isna()].cost
gab6jxml

gab6jxml1#

无法在merge函数中找到实现它的方法。但您可以使用apply在一行中进行后处理。其想法是将'modified_xxx'替换为'xxx'。

df1 = pd.DataFrame({"id": [1,2,3,4], "time": [3, 4, 5, 6], "cost": [1.1, 2.2, 3.3, 4.4], "quantity": [10,20,30,40]})

df2 = pd.DataFrame({"id": [2,3,4], "time": [4, 5, 6], "modified_cost": [2.2, 3.3, 4.4], "modified_quantity": [20,30,40]}) 

df1 = df1.merge(df2, on=["id", "time"], how="left").apply(lambda x:x.fillna(df1.loc[:,x.name.replace('modified_','')]))
webghufk

webghufk2#

在问题中,你展示了一种对merge()的结果进行后处理以获得所需结果的方法。还有一些方法可以使用mask()对df2进行预处理以获得所需结果,但它们不一定比你的解决方案更好。
例如,您可以执行以下操作:

idTime = ['id','time']
df1 = df1.set_index(idTime)
df2 = df2.set_index(idTime).reindex(df1.index)
df1 = df1.merge(df2.mask(df2.isna(), df1.to_numpy()), on=idTime, how='left').reset_index()

......或者这个:

df1 = ( df1.merge(
    df2.set_index(idTime).pipe(lambda d2, d1: 
        d2.reindex(d1.index).pipe(lambda d: d.mask(d.isna(), d1.to_numpy())),
        df1.set_index(idTime)
    ).reset_index(), on=idTime, how="left") )

......或者这个:

df1 = df1.set_index(idTime)
df2 = df2.set_index(idTime).reindex(df1.index)
df1 = pd.concat([df1, df2.mask(df2.isna(), df1.to_numpy())], axis=1).reset_index()

可以说,上面的最后一个是最精简的预处理策略,因为在调用reindex()之后,对merge()的调用实际上只是用于追加列(而不是进行任何数据库风格的连接),这可以使用concat()实现。

yquaqz18

yquaqz183#

基于用另一个 Dataframe 值填充 Dataframe 的答案。
我用fillna来做这个。

r = (df1[['cost', 'quantity']] \
     .rename(columns=dict(zip(df1.columns[2:4], df1.columns[-2:])))
     )
df1.loc[:, df1.columns[-2:]] = df1[df1.columns[-2:]].fillna(r)

print(df1)
id  time  cost  quantity  modified_cost  modified_quantity
0   1     3   1.1        10            1.1               10.0
1   2     4   2.2        20            2.2               20.0
2   3     5   3.3        30            3.3               30.0
3   4     6   4.4        40            4.4               40.0

加速时间

测试上述策略。

import time

start = time.time()
# ...
end = time.time()

print(end-start) # 0.016285171508789062 seconds (on my computer)

相关问题