【问题标题】:How to remove datetime values in a row that are within a certain time relative to another row?如何删除相对于另一行在特定时间内的一行中的日期时间值?
【发布时间】:2022-06-21 11:54:29
【问题描述】:

如果我有如下的 DataFrame:

Letter Time
0 x 2021-01-01 14:00:00
1 y 2021-01-01 18:00:00
2 y 2021-01-03 14:00:00

如果“时间”列(日期时间)中的值在上述行中的时间的 14 小时内,我将如何删除一行?

我尝试过使用:

from datetime import datetime, timedelta
for i, row in enumerate(df):
    if i > 0:
        if df.at[i, 'Time'] - df.at[i-1, 'Time'] < timedelta(hours=14):
            df = df.drop(i)
        else:
            pass
    else:
        pass

但我得到与线路相关的 KeyError 1

如果 df.at[i, 'Time'] - df.at[i-1, 'Time']

【问题讨论】:

    标签: python pandas dataframe datetime timedelta


    【解决方案1】:

    如果时间戳在较早时间戳的 14 小时内,是否删除它取决于是否删除较早的时间戳?这个答案考虑了这个问题的答案是“是”的情况。 (如果答案是“否”,那么下面测试数据的结果解决方案将只是第一个时间戳)。

    设置

    测试数据:

    import pandas as pd
    
    timestamps = pd.Series([0, 6,10,14,16,29,33,45,46]).apply(pd.Timedelta, unit="hours") + pd.Timestamp("2022")
    

    timestamps 看起来像这样:

    0   2022-01-01 00:00:00
    1   2022-01-01 06:00:00
    2   2022-01-01 10:00:00
    3   2022-01-01 14:00:00
    4   2022-01-01 16:00:00
    5   2022-01-02 05:00:00
    6   2022-01-02 09:00:00
    7   2022-01-02 21:00:00
    8   2022-01-02 22:00:00
    dtype: datetime64[ns]
    

    我们的目标解决方案包括第 1、4、6 和 8 个时间戳。

    解决方案

    此解决方案将使用piso(pandas 间隔集操作)包。这个想法是为每个时间戳创建一个 14 小时窗口,即间隔,并迭代地删除属于较早开始的间隔的时间戳。

    import piso
    
    # sort timestamps if not already sorted
    timestamps = timestamps.sort_values()
    
    # create 14 hour windows for each timestamp.  Can be left-closed or right-closed, but not both
    intervals = pd.IntervalIndex.from_arrays(timestamps, timestamps+pd.Timedelta("14h"))
    
    # create the "disjoint adjacency matrix", which indicates pairwise if intervals are disjoint
    mat = piso.adjacency_matrix(intervals, edges="disjoint")
    

    mat 将是一个数据框,其索引和列是timestampsmat.values 是这样的

    array([[False, False, False,  True,  True,  True,  True,  True,  True],
           [False, False, False, False, False,  True,  True,  True,  True],
           [False, False, False, False, False,  True,  True,  True,  True],
           [ True, False, False, False, False,  True,  True,  True,  True],
           [ True, False, False, False, False, False,  True,  True,  True],
           [ True,  True,  True,  True, False, False, False,  True,  True],
           [ True,  True,  True,  True,  True, False, False, False, False],
           [ True,  True,  True,  True,  True,  True, False, False, False],
           [ True,  True,  True,  True,  True,  True, False, False, False]])
    

    将此矩阵的对角线设置为真

    mat.iloc[range(len(mat)),range(len(mat))] = True
    

    我们将从第一个间隔开始。从mat 的第一行可以推断出需要删除第二个和第三个区间。所以我们过滤掉这些区间对应的行和列,然后移动下一个区间(行),以此类推,直到到达最后一行。请注意,我们不需要检查最后一行的任何交叉点。

    i = 0
    while i < len(mat) -1:
        mat = mat.loc[mat.iloc[i],mat.iloc[i]]
        i+=1
    

    结果将是一个数据框,其值全部为 True。更重要的是,索引(和列)将是间隔,其左端点是删除 14 小时内的时间戳后剩余的时间戳。

    pd.Series(mat.index.left)给了

    0   2022-01-01 00:00:00
    1   2022-01-01 14:00:00
    2   2022-01-02 05:00:00
    3   2022-01-02 21:00:00
    dtype: datetime64[ns]
    

    您可以使用 pandas.Series.isin 过滤您的原始数据框

    注意:我是 piso 的创造者。如果您有任何反馈或问题,请随时与我们联系。

    【讨论】:

    • 完美运行,以防万一这对像我这样的其他新手很方便,我通过简单地用 df['Time'] 抓取列来从数据框中形成我需要的系列
    【解决方案2】:

    您可以使用shift + rsub(查找连续时间之间的差异)+ div(转换为小时)创建一个布尔掩码并对其进行过滤:

    msk = df['Time'].shift().rsub(df['Time']).div(np.timedelta64(1, 'h')) > 14
    out = df[msk]
    

    输出:

      Letter                Time
    2      y 2021-01-03 14:00:00
    

    【讨论】:

    • 是的,在这种情况下,它只是中间的,因为第一行作为一种参考框架很重要@Riley
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-24
    • 1970-01-01
    • 2021-05-24
    相关资源
    最近更新 更多