【问题标题】:Filter certain rows in data frame based on time根据时间过滤数据框中的某些行
【发布时间】:2021-06-22 23:10:51
【问题描述】:

我有大量数据,这里显示了一个虚拟对象

在这里,事件就像一个循环。它可以从任何 event 开始,在任何 event 处停止,但总是以 event-final 结束。我得到了基于时间的序列。我在这里要做的是只保留不完整的循环记录。例如,在上面显示的图像中,event-1 到 event-final(前 4 行)表示循环已完成,因此我需要删除“final-event”之前存在的所有行,我只需要包含事件的行在“最终事件”之后(在上图中是事件 2)。

对于特定 ID,大约有 20 个事件可以按任何顺序发生。所以我想做的只是删除 final-event 之前的所有行。我有时间列来获取序列。

我的想法是根据时间降序排序,并在“最终事件”之后删除行。但我不确定如何在熊猫中做到这一点。有人可以帮忙吗?

除了我对给定数据的想法之外,还有更好的方法吗?

编辑后按代码发布组(@Joe Ferndz):

def remove_cycle(group):
    group = group.reset_index(drop=True)
    if not group[group['Event']=='event_final'].empty:
        tmp = group[group['Event']=='event_final']['time'].iloc[0]
        return group[group['time']>tmp]
    else:
        index = len(group)
    return group[:index]


temp2 = df.sort_values("time",ascending=False).groupby(["ID"]).apply(remove_cycle)

所以,这就是我尝试过的。我根据时间按降序排序,然后按 ID 分组。然后在 remove_cycle 中,我找出事件为“事件最终”的时间索引。然后我只返回具有更大时间列值的行。

这可以达到目的,但速度很慢。

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    更新版本:适用于多个 ID

    这个解决方案的灵感来自这个thread的回复

    import pandas as pd
    df = pd.DataFrame({'ID':['001']*10 + ['002']*10,
                       'Event':['event-1','event-2','event-3','event-final','event-1',
                                'event-2','event-3','event-final','event-1','event-2',
                                'event-1','event-2','event-3','event-final','event-1',
                                'event-2','event-final','event-1','event-2','event-3'],
                       'time':pd.date_range('2021-03-22 09:00:00', periods=20, freq="T")
                    })
    
    #converting time to string format to match your data
    df['time'] = df['time'].dt.strftime("%H:%M")
    
    #checking for values of 'event-final' and reversing the dataframe to find groupby cumsum
    #A value of 0 indicates that its after 'event-final'
    #Picking those values will give you the desired results
    
    print (df[df.Event.eq('event-final')[::-1].astype(int).groupby(df.ID).cumsum().eq(0)])
    
    print (df)
    

    输出将是:

         ID    Event   time
    8   001  event-1  09:08
    9   001  event-2  09:09
    17  002  event-1  09:17
    18  002  event-2  09:18
    19  002  event-3  09:19
    

    对于数据框:

         ID        Event   time
    0   001      event-1  09:00
    1   001      event-2  09:01
    2   001      event-3  09:02
    3   001  event-final  09:03
    4   001      event-1  09:04
    5   001      event-2  09:05
    6   001      event-3  09:06
    7   001  event-final  09:07
    8   001      event-1  09:08
    9   001      event-2  09:09
    10  002      event-1  09:10
    11  002      event-2  09:11
    12  002      event-3  09:12
    13  002  event-final  09:13
    14  002      event-1  09:14
    15  002      event-2  09:15
    16  002  event-final  09:16
    17  002      event-1  09:17
    18  002      event-2  09:18
    

    单一 ID 的上一个答案

    您可以找到最后一次出现 event-final 的索引,然后列出从该点开始的所有值。是的,在执行此操作之前,您需要按时间和 reset_index 排序值。

    import pandas as pd
    df = pd.DataFrame({'ID':['001']*10,
                       'Event':['event-1','event-2','event-3','event-final','event-1',
                                'event-2','event-3','event-final','event-1','event-2'],
                       'time':pd.date_range('2021-03-22 09:00:00', periods=10, freq="T")})
    
    #converting time to string format to match your data
    
    df['time'] = df['time'].dt.strftime("%H:%M")
    
    #sorting time in ascending order (assume this is within same day
    #if date goes beyond 24 hrs, then you should keep df['time'] in datetime format
    
    df = df.sort_values(by='time').reset_index(drop=True)
    
    print (df)
    
    #find out the index of all events that have `event-final`
    #and get only the last one using [-1]
    
    idx = df.index[df['Event']=='event-final'][-1]
    
    #using iloc or loc, you can get all records after the last `event-final` row
    print (df.loc[idx+1:])
    

    这个输出将是:

    原始数据框:

        ID        Event   time
    0  001      event-1  09:00
    1  001      event-2  09:01
    2  001      event-3  09:02
    3  001  event-final  09:03
    4  001      event-1  09:04
    5  001      event-2  09:05
    6  001      event-3  09:06
    7  001  event-final  09:07
    8  001      event-1  09:08
    9  001      event-2  09:09
    

    没有事件最终值的最终数据帧。

        ID    Event   time
    8  001  event-1  09:08
    9  001  event-2  09:09
    

    【讨论】:

    • 我有很多ID,不仅是'001'。那么在那种情况下我应该先 groupby 然后我必须使用 apply 功能,然后按照你说的做吗?
    • 啊!!!是的,如果您有很多 id,那么我们应该分组并选择值。让我创建一个具有多个 id 的数据框并发布更新的答案。它在深夜。我明天会发布答案。希望没关系。请尝试使用 groupby 进行探索。使用转换来标记您需要截止的行。这样您就可以从那时起获取所有行
    • 非常感谢,我使用 group by 和 apply 函数来获得所需的结果。太费时间了..
    • 我已编辑帖子并按代码包含该组。让我知道我可以改进的地方。我尝试不完全复制粘贴您编写的相同代码,并根据您的想法自行尝试。让我知道你的想法。
    • 非常感谢更新的答案,它比我的应用方法快得多
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-23
    • 1970-01-01
    • 2016-08-02
    • 2021-06-07
    • 1970-01-01
    • 2023-02-13
    相关资源
    最近更新 更多