【问题标题】:Python: filter dataFrame with keep only last data by ActiveFlag and DatePython:过滤dataFrame,只保留ActiveFlag和Date的最后一个数据
【发布时间】:2020-07-06 22:38:12
【问题描述】:

我已按DateID 数据集(df)排序:

Date          ID      Start_flag    End_flag                               
01-01-2019    100     1             0     
01-02-2019    100     0             0
01-03-2019    100     0             0
01-04-2019    100     0             0
01-05-2019    100     0             1
01-09-2019    100     1             0 
01-10-2019    100     0             0
01-11-2019    100     0             0
01-12-2019    100     0             0
01-03-2019    500     1             0     
01-04-2019    500     0             0
01-05-2019    500     0             0
01-06-2019    500     0             0
01-07-2019    500     0             0
01-08-2019    500     0             0 
01-09-2019    700     1             0
01-10-2019    700     0             0
01-11-2019    700     0             1

我想通过最后一个实际的Date 过滤df,其中出现了Start_flag=1,不应该提取之前与Start_flag=1 相同的ID 的所有数据。

换句话说,如果同一ID 发生几次Start_flag=1,则只保留最后一个Start_flag=1,最大Date

df 的预期视图是:

Date          ID      Start_flag    End_flag                               
01-09-2019    100     1             0 
01-10-2019    100     0             0
01-11-2019    100     0             0
01-12-2019    100     0             0
01-03-2019    500     1             0     
01-04-2019    500     0             0
01-05-2019    500     0             0
01-06-2019    500     0             0
01-07-2019    500     0             0
01-08-2019    500     0             0 
01-09-2019    700     1             0
01-10-2019    700     0             0
01-11-2019    700     0             1 

我尝试通过.groupby(['ID','Start_flag'])['Date'].last() 来做,但这不是正确的方法。

您能帮我如何过滤来自df 的额外数据吗?谢谢

编辑: 可能的解决方案是:

def filterTable(df):
    result_list = []
    for x in df['ID'].unique():
        df_1 = df[df['ID']==x]
        indx = df_1.where(((df_1['Start_flag']==0) & (df_1['Date']==df_1['Date'].min())) | (df_1['Start_flag'] == 1)).last_valid_index()
        result_list.append(df_1.loc[indx:])   
    result= pd.concat(result_list)
    return result

添加条件 df_1['Start_flag']==0 是因为在最初 Start_flag=0 直到 End_flag=1 的情况下返回 last_valid_index

此外,由于大型数据帧的执行时间,这不是最佳解决方案。尝试为它找到更好的解决方案。

【问题讨论】:

    标签: python dataframe filter group-by apply


    【解决方案1】:

    不是pythonic

    result = []
    for i in df['ID'].unique():
        adf = df[df['ID'] == i].sort_values(by="Date").reset_index(drop=True)
        i = adf.where(adf['Start_flag'] == 1).last_valid_index()
        result.append(adf.iloc[range(i, len(adf))])   
    print (pd.concat(result).reset_index(drop=True))
    

    输出:

             Date   ID  Start_flag  end
    0  2019-01-09  100           1    0
    1  2019-01-10  100           0    0
    2  2019-01-11  100           0    0
    3  2019-01-12  100           0    0
    4  2019-01-03  500           1    0
    5  2019-01-04  500           0    0
    6  2019-01-05  500           0    0
    7  2019-01-06  500           0    0
    8  2019-01-07  500           0    0
    9  2019-01-08  500           0    0
    10 2019-01-09  700           1    0
    11 2019-01-10  700           0    0
    12 2019-01-11  700           0    1
    

    注意:我们可以通过将逻辑移动到函数并通过apply 调用函数而不是groupby 来避免循环。但是,groupby 在第一个组上运行了两次函数,所以我们必须确保我们的函数没有副作用。

    使用 groupby:

    def fun(adf):
        adf = adf.sort_values(by="Date").reset_index(drop=True)
        i = adf.where(adf['Start_flag'] == 1).last_valid_index()
        return adf.iloc[range(i, len(adf))]
    
    print (df.groupby('ID').apply(fun).reset_index(drop=True))
    

    【讨论】:

    • 感谢您的帮助和想法。我也尝试在作品中进行验证。但是在尝试应用完整数据集时只出现一个奇怪的错误:'NoneType' object cannot be interpreted as an integer。我还在探索为什么Nonetype会在iloc中发生?!变量i- 是整数,len(df) 也是整数,这就是range 的用法所需要的。
    • 我修复了每个组的用法:adf.loc[i:]。谢谢
    【解决方案2】:

    最终更正的解决方案是:

    def validateData(adf):  
        adf = adf.sort_values(by="Date").reset_index(drop=True)
        indx = adf.where(((adf['Start_flag']==0) & (adf['Date']==adf['Date'].min())) | (adf['Start_flag'] == 1)).last_valid_index()
    
        return adf.iloc[range(indx, len(adf))]
    
    def filterData(df):
        start_time = datetime.now()
        print('Start_time=', start_time)
        RESULT_DF = df.groupby('ID').apply(lambda x: validateData(x))
        print("--- %s seconds ---" % (datetime.now() - start_time))
        return RESULT_DF
    

    要应用于数据: RESULT_DF = filterData(df)

    【讨论】:

      猜你喜欢
      • 2020-03-22
      • 2019-02-19
      • 1970-01-01
      • 1970-01-01
      • 2023-02-08
      • 1970-01-01
      • 2018-04-21
      • 2023-02-22
      • 1970-01-01
      相关资源
      最近更新 更多