如何删除一行中相对于另一行在特定时间内的日期时间值?
How to remove datetime values in a row that are within a certain time relative to another row?
如果我有如下数据框:
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
如果时间列 (datetime) 中的值与上一行中的时间相差 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
if df.at[i, 'Time'] - df.at[i-1, 'Time'] < timedelta(hours=14):
您可以使用 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
如果时间戳在较早时间戳的 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 小时 window,即间隔,并迭代地删除属于较早开始的间隔的时间戳。
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
将是一个数据框,其索引和列为 timestamps
。 mat.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]])
将此矩阵的对角线设置为 True
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
过滤您的原始数据框
如果我有如下数据框:
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 |
如果时间列 (datetime) 中的值与上一行中的时间相差 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 1if df.at[i, 'Time'] - df.at[i-1, 'Time'] < timedelta(hours=14):
您可以使用 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
如果时间戳在较早时间戳的 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 小时 window,即间隔,并迭代地删除属于较早开始的间隔的时间戳。
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
将是一个数据框,其索引和列为 timestamps
。 mat.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]])
将此矩阵的对角线设置为 True
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