仅当一列没有值时,Pandas DataFrame才会从另一个数据框中更新

时间:2019-11-15 20:58:30

标签: python pandas dataframe

我正在尝试使用另一个数据框中的值来更新数据框,但是我希望仅在特定列没有值的情况下进行更新。

from datetime import datetime
import pandas as pd

dr = pd.bdate_range(periods=3, end=datetime.now().date())

df1 = pd.DataFrame([1, 2], columns=['myid'])
for d in dr:                                                                                                                                   
    df1[d.to_pydatetime()] = pd.np.nan
df1.loc[df1['myid'] == 1, dr[2]] = 4.0
df1 = df1.set_index('myid')


df1
      2019-11-13 00:00:00  2019-11-14 00:00:00  2019-11-15 00:00:00
myid                                                               
1                     NaN                  NaN                  4.0
2                     NaN                  NaN                  NaN

df2 = pd.DataFrame([1, 2], columns=['myid'])
for d in dr:                                                                                                                                   
    df2[d.to_pydatetime()] = pd.np.nan
df2.loc[df2['myid'] == 2, dr[2]] = 4.0
df2.loc[df2['myid'] == 1, dr[0]] = 6.0
df2 = df2.set_index('myid')

df2
      2019-11-13 00:00:00  2019-11-14 00:00:00  2019-11-15 00:00:00
myid                                                               
1                     6.0                  NaN                  NaN
2                     NaN                  NaN                  4.0

如果df1没有dr[2] (current date)的值,我想用df2中的值更新df1。

因此,在上面的示例中,仅df1中的第二行应被更新。

我尝试了update,但不确定如何根据列是否有值进行过滤

df1.update(df2, overwrite=False)

我确实查看了更新所需的filter_func,但再次无法使用它。任何帮助深表感谢。谢谢

编辑:

预期输出:

不应触摸行1,因为它在列2019-11-15 00:00:00中已经有一个值

df1
      2019-11-13 00:00:00  2019-11-14 00:00:00  2019-11-15 00:00:00
myid                                                               
1                     NaN                  NaN                  4.0
2                     NaN                  NaN                  4.0

1 个答案:

答案 0 :(得分:0)

更新:这似乎是filter_func参数的明显用法。仅更新df1的所有列均为空的行:

df1.update(df2, filter_func=lambda df: df1.isnull().all(1))
#      2019-11-13 00:00:00  2019-11-14 00:00:00  2019-11-15 00:00:00
#myid                                                               
#1                     NaN                  NaN                  4.0
#2                     NaN                  NaN                  4.0

旧答案,更多实际操作:

您可以分隔要更新的行,仅更新那些行,然后合并。 update在原地运行,因此我们需要将其分解。

m = df1.notnull().any(1)

# These get updated
u = df1[~m].copy()
u.update(df2)

df1 = pd.concat([df1[m], u])
#      2019-11-13 00:00:00  2019-11-14 00:00:00  2019-11-15 00:00:00
#myid                                                               
#1                     NaN                  NaN                  4.0
#2                     NaN                  NaN                  4.0

或者,您可以使用combine_first,然后屏蔽不应该更新的行并将其重置为df1中的原始值

df1.combine_first(df2).mask(df1.notnull().any(1)).fillna(df1)