【问题标题】:replace a column of a df with the another column of an another df based on specific condition in pandas根据熊猫中的特定条件,将 df 的一列替换为另一个 df 的另一列
【发布时间】:2020-07-16 16:08:39
【问题描述】:

我有两个dataframe如下图df1和df2如下图。

df1:

Date                t_factor     category
2020-02-01             5         A   
2020-02-02             2         B       
2020-02-03             1         C       
2020-02-04             2         A
2020-02-05             3         B
2020-02-06             3         C 
2020-02-07             3         A    
2020-02-08             9         B     
2020-02-09             1         C
2020-02-10             8         A
2020-02-11             3         B         
2020-02-12             3         C               

df2:

Date                  beta     
2020-02-01             100             
2020-02-02             230              
2020-02-03             150           
2020-02-04             100
2020-02-05             200  
2020-02-06             180          
2020-02-07             190            
2020-02-08             290 

从上面我想根据输入日期范围将 df1 的 t_factor 列替换为 df2 的 beta 列。

函数可以是这样的。

def replace_column(df1, df2, start_date = `2020-02-03`, end_date = `2020-02-06`):
     df1 = df1.copy()
     df2 = df2.copy()
     df1 = df1.sort_values(['Date'], ascending=True)
     df2 = df2.sort_values(['Date'], ascending=True)
     df1['t_factor'] = df1['beta']  # for that date range
     return df1

预期输出:对于 start_date = 2020-02-03 和 end_date = 2020-02-06

df1:

 Date                t_factor   category
2020-02-01             5         A   
2020-02-02             2         B       
2020-02-03             150       C       
2020-02-04             100       A
2020-02-05             200       B
2020-02-06             180       C 
2020-02-07             3         A    
2020-02-08             9         B     
2020-02-09             1         C
2020-02-10             8         A
2020-02-11             3         B         
2020-02-12             3         C               





   

注意:df2 的数据较少,df2 的最终日期为2020-02-08

if start_date = `2020-02-07`  and end_date = `2020-02-11`.

然后预期输出

Date                t_factor     category
2020-02-01             5         A   
2020-02-02             2         B       
2020-02-03             1         C       
2020-02-04             2         A
2020-02-05             3         B
2020-02-06             3         C 
2020-02-07             190       A    
2020-02-08             290       B     
2020-02-09             1         C
2020-02-10             8         A
2020-02-11             3         B         
2020-02-12             3         C   

print ('df2 dont have data after 2020-02-08')

【问题讨论】:

    标签: python-3.x pandas dataframe


    【解决方案1】:

    使用pd.to_datetimeDate like 列转换为pandas datetime 系列。

    df1['Date'] = pd.to_datetime(df1['Date'])
    df2['Date'] = pd.to_datetime(df2['Date'])
    

    然后使用Series.between并指定开始日期(left)和结束日期(right)来创建一个布尔掩码m,然后使用boolean indexing这个掩码并使用Series.map进行映射从df2t_functionbeta 值在df1 中。

    m = df1['Date'].between('2020-02-03', '2020-02-06', inclusive=True)
    df1.loc[m, 't_factor'] = df1['Date'].map(df2.set_index('Date')['beta']).fillna(df1['t_factor'])
    

    另一个想法使用DataFrame.merge

    df1 = df1.merge(df2, on='Date', how='left')
    m = df1['Date'].between('2020-02-03', '2020-02-06', inclusive=True)
    df1.loc[m, 't_factor'] = df1.pop('beta').fillna(df1['t_factor'])
    

    结果:

    # start=2020-02-03, end=2020-02-06
             Date  t_factor category
    0  2020-02-01       5.0        A
    1  2020-02-02       2.0        B
    2  2020-02-03     150.0        C
    3  2020-02-04     100.0        A
    4  2020-02-05     200.0        B
    5  2020-02-06     180.0        C
    6  2020-02-07       3.0        A
    7  2020-02-08       9.0        B
    8  2020-02-09       1.0        C
    9  2020-02-10       8.0        A
    10 2020-02-11       3.0        B
    11 2020-02-12       3.0        C
    
    # start=2020-02-07, end=2020-02-11.
             Date  t_factor category
    0  2020-02-01       5.0        A
    1  2020-02-02       2.0        B
    2  2020-02-03       1.0        C
    3  2020-02-04       2.0        A
    4  2020-02-05       3.0        B
    5  2020-02-06       3.0        C
    6  2020-02-07     190.0        A
    7  2020-02-08     290.0        B
    8  2020-02-09       1.0        C
    9  2020-02-10       8.0        A
    10 2020-02-11       3.0        B
    11 2020-02-12       3.0        C
    

    包装merging方法(Method 2)

    函数

    def fx(df1, df2, start, end):
        if df2['Date'].max() < pd.Timestamp(end):
            print(f"we dont have data beyound {df2['Date'].max()}")
    
        df1 =  df1.merge(df2, on='Date', how='left')
        m = df1['Date'].between(start, end, inclusive=True)
        df1.loc[m, 't_factor'] = df1.pop('beta').fillna(df1['t_factor'])
        return df1
    

    【讨论】:

    • 如果 df2 没有超过 end_date 的数据怎么办
    • @Danish 代码会处理这种情况。请稍等一下,我会添加示例。
    • 你能不能把它做成一个返回df1的函数
    • 如果 end_date 大于 df2 最大日期,请打印一条说明,我们在 df2 中没有超出 df2.Date.max() 的数据
    • 我喜欢第二种方法。这两种方法都很棒..你是天才。太感谢了。愿上帝保佑你
    【解决方案2】:

    我的解决方案使用df.joindf.loc 方法。

    首先初始化数据。

    df1 = pd.DataFrame({'Date' : ['2020-02-01', '2020-02-05', '2020-02-06', '2020-02-12'],'t_factor' : [5, 3, 3, 3]})
    df2 = pd.DataFrame({'Date' : ['2020-02-05', '2020-02-06'],'beta' : [200, 180]})
    

    然后将Date设置为索引。

    df1d = df1.set_index('Date')
    df2d = df2.set_index('Date')
    

    现在是关键步骤。

    dfres=df1d.join(df2d)
    dfres.loc[dfres['beta'].notnull(), 't_factor'] = dfres.loc[dfres['beta'].notnull()].beta
    

    再一步来匹配预期的输出。

    output=dfres.drop(columns='beta')
    

    【讨论】:

    • @Dharman 你能用参数 df1, df2, start_date, end_date 做一个函数吗
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-12-03
    • 2020-10-24
    • 2020-04-06
    • 1970-01-01
    • 2012-10-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多