获取时间戳在不规则时间间隔pandas内的行(时间序列)
Get rows whose timestamps are within irregular time intervals pandas (Time Series)
假设我有一个这样的数据框:
>>> i = pd.to_datetime(np.random.randint(time.time(), time.time()+10000, 15), unit='ms').sort_values()
>>> df = pd.DataFrame({'A':range(15),'B':range(10,40,2),'C':range(10,55,3)},index = i)
>>> df
A B C
1970-01-19 05:31:36.629 0 10 10
1970-01-19 05:31:36.710 1 12 13
1970-01-19 05:31:37.779 2 14 16
1970-01-19 05:31:38.761 3 16 19
1970-01-19 05:31:39.520 4 18 22
1970-01-19 05:31:39.852 5 20 25
1970-01-19 05:31:39.994 6 22 28
1970-01-19 05:31:41.370 7 24 31
1970-01-19 05:31:41.667 8 26 34
1970-01-19 05:31:42.515 9 28 37
1970-01-19 05:31:42.941 10 30 40
1970-01-19 05:31:43.037 11 32 43
1970-01-19 05:31:43.253 12 34 46
1970-01-19 05:31:43.333 13 36 49
1970-01-19 05:31:44.135 14 38 52
我想要的是:
A B C
1970-01-19 05:31:37.779 2.0 14.0 16.0 #last value within 2000 milli-sec interval from 05:31:36
1970-01-19 05:31:38.761 3.0 16.0 19.0 ##last value from the ^ value within 1000 msec interval
1970-01-19 05:31:39.994 6.0 22.0 28.0 #last value within 2000 milli-sec interval from 05:31:38
1970-01-19 05:31:39.994 6.0 22.0 28.0 *##last value from the ^ value within 1000 msec interval
1970-01-19 05:31:41.667 8.0 26.0 34.0 #last value within 2000 milli-sec interval from 05:31:40
1970-01-19 05:31:42.515 9.0 28.0 37.0 ##last value from the ^ value within 1000 msec interval
1970-01-19 05:31:43.333 13.0 36.0 49.0 #last value within 2000 milli-sec interval from 05:31:42
1970-01-19 05:31:44.135 14.0 38.0 52.0 ##last value from the ^ value within 1000 msec interval
我可以使用以下代码实现标有 #
s 的行:
>>> df.resample('2000ms').ffill().dropna(axis=0)
A B C
1970-01-19 05:31:38 2.0 14.0 16.0
1970-01-19 05:31:40 6.0 22.0 28.0
1970-01-19 05:31:42 8.0 26.0 34.0
1970-01-19 05:31:44 13.0 36.0 49.0
# note I do not care about how the timestamps are getting printed, I just want the correct values.
我找不到 pandas 的解决方案,可以给我所需的输出。我可以用两个数据帧来做到这一点,一个在 2000ms
采样,另一个在 1000ms
采样,然后可能循环,并相应地插入。
问题是,我的数据的实际大小非常大,超过 4000000 行和 52 列。如果可以避免两个 dfs,或者循环,我肯定会接受它。
注意:*
标记的行会重复,因为在距离最后一个值的1000ms时间间隔内没有数据,所以重复最后一个看到的值。对于 2000 毫秒的时间间隔也应该发生同样的情况。
如果可能请告诉我一个方法...谢谢!
EDIT:根据 :
编辑
import datetime
def last_time(time):
time = str(time)
start_time = datetime.datetime.strptime(time[11:],'%H:%M:%S.%f')
end_time = start_time + datetime.timedelta(microseconds=1000000)
tempdf = df.between_time(*pd.to_datetime([str(start_time),str(end_time)]).time).iloc[-1]
return tempdf
df['timestamp'] = df.index
df2 = df.resample('2000ms').ffill().dropna(axis=0)
df3 = df2.apply(lambda x:last_time(x['timestamp']), axis = 1)
pd.concat([df2, df3]).sort_index(kind='merge')
这给出:
A B C timestamp
1970-01-19 05:31:38 2.0 14.0 16.0 1970-01-19 05:31:37.779
1970-01-19 05:31:38 3.0 16.0 19.0 1970-01-19 05:31:38.761
1970-01-19 05:31:40 6.0 22.0 28.0 1970-01-19 05:31:39.994
1970-01-19 05:31:40 6.0 22.0 28.0 1970-01-19 05:31:39.994
1970-01-19 05:31:42 8.0 26.0 34.0 1970-01-19 05:31:41.667
1970-01-19 05:31:42 9.0 28.0 37.0 1970-01-19 05:31:42.515
1970-01-19 05:31:44 13.0 36.0 49.0 1970-01-19 05:31:43.333
1970-01-19 05:31:44 14.0 38.0 52.0 1970-01-19 05:31:44.135
没关系,除了应用部分需要很长时间!
为了更容易复制:
,A,B,C
1970-01-19 05:31:36.629,0,10,10
1970-01-19 05:31:36.710,1,12,13
1970-01-19 05:31:37.779,2,14,16
1970-01-19 05:31:38.761,3,16,19
1970-01-19 05:31:39.520,4,18,22
1970-01-19 05:31:39.852,5,20,25
1970-01-19 05:31:39.994,6,22,28
1970-01-19 05:31:41.370,7,24,31
1970-01-19 05:31:41.667,8,26,34
1970-01-19 05:31:42.515,9,28,37
1970-01-19 05:31:42.941,10,30,40
1970-01-19 05:31:43.037,11,32,43
1970-01-19 05:31:43.253,12,34,46
1970-01-19 05:31:43.333,13,36,49
1970-01-19 05:31:44.135,14,38,52
您现有代码中较慢的部分是 df3
的创建,所以我会对其进行优化。
首先,请注意您的 last_time(x)
函数查找 x 到 x + 1 秒时间范围内的最后一条记录。
不使用循环,我们可以从偏移整个向量中的时间开始:
end_times = df2.timestamp + datetime.timedelta(microseconds=1000000)
然后我们可以使用numpy.searchsorted()
(一个被严重低估的函数!)来搜索df
中的那些时间:
idx = np.searchsorted(df.timestamp, end_times)
顺便说一下,df.timestamp.searchsorted(end_times)
做同样的事情。
最后,请注意,每个生成的索引都在我们想要的之后(我们不想要 1 秒之后的值,我们想要之前的值):
df3a = df.iloc[idx - 1]
除了索引没有向下舍入外,这与您的 df3
得到的结果相同,因此只需替换它:
df3a.index = df2.index
这与您的 df3
完全相同,但计算速度更快。
假设我有一个这样的数据框:
>>> i = pd.to_datetime(np.random.randint(time.time(), time.time()+10000, 15), unit='ms').sort_values()
>>> df = pd.DataFrame({'A':range(15),'B':range(10,40,2),'C':range(10,55,3)},index = i)
>>> df
A B C
1970-01-19 05:31:36.629 0 10 10
1970-01-19 05:31:36.710 1 12 13
1970-01-19 05:31:37.779 2 14 16
1970-01-19 05:31:38.761 3 16 19
1970-01-19 05:31:39.520 4 18 22
1970-01-19 05:31:39.852 5 20 25
1970-01-19 05:31:39.994 6 22 28
1970-01-19 05:31:41.370 7 24 31
1970-01-19 05:31:41.667 8 26 34
1970-01-19 05:31:42.515 9 28 37
1970-01-19 05:31:42.941 10 30 40
1970-01-19 05:31:43.037 11 32 43
1970-01-19 05:31:43.253 12 34 46
1970-01-19 05:31:43.333 13 36 49
1970-01-19 05:31:44.135 14 38 52
我想要的是:
A B C
1970-01-19 05:31:37.779 2.0 14.0 16.0 #last value within 2000 milli-sec interval from 05:31:36
1970-01-19 05:31:38.761 3.0 16.0 19.0 ##last value from the ^ value within 1000 msec interval
1970-01-19 05:31:39.994 6.0 22.0 28.0 #last value within 2000 milli-sec interval from 05:31:38
1970-01-19 05:31:39.994 6.0 22.0 28.0 *##last value from the ^ value within 1000 msec interval
1970-01-19 05:31:41.667 8.0 26.0 34.0 #last value within 2000 milli-sec interval from 05:31:40
1970-01-19 05:31:42.515 9.0 28.0 37.0 ##last value from the ^ value within 1000 msec interval
1970-01-19 05:31:43.333 13.0 36.0 49.0 #last value within 2000 milli-sec interval from 05:31:42
1970-01-19 05:31:44.135 14.0 38.0 52.0 ##last value from the ^ value within 1000 msec interval
我可以使用以下代码实现标有 #
s 的行:
>>> df.resample('2000ms').ffill().dropna(axis=0)
A B C
1970-01-19 05:31:38 2.0 14.0 16.0
1970-01-19 05:31:40 6.0 22.0 28.0
1970-01-19 05:31:42 8.0 26.0 34.0
1970-01-19 05:31:44 13.0 36.0 49.0
# note I do not care about how the timestamps are getting printed, I just want the correct values.
我找不到 pandas 的解决方案,可以给我所需的输出。我可以用两个数据帧来做到这一点,一个在 2000ms
采样,另一个在 1000ms
采样,然后可能循环,并相应地插入。
问题是,我的数据的实际大小非常大,超过 4000000 行和 52 列。如果可以避免两个 dfs,或者循环,我肯定会接受它。
注意:*
标记的行会重复,因为在距离最后一个值的1000ms时间间隔内没有数据,所以重复最后一个看到的值。对于 2000 毫秒的时间间隔也应该发生同样的情况。
如果可能请告诉我一个方法...谢谢!
EDIT:根据
import datetime
def last_time(time):
time = str(time)
start_time = datetime.datetime.strptime(time[11:],'%H:%M:%S.%f')
end_time = start_time + datetime.timedelta(microseconds=1000000)
tempdf = df.between_time(*pd.to_datetime([str(start_time),str(end_time)]).time).iloc[-1]
return tempdf
df['timestamp'] = df.index
df2 = df.resample('2000ms').ffill().dropna(axis=0)
df3 = df2.apply(lambda x:last_time(x['timestamp']), axis = 1)
pd.concat([df2, df3]).sort_index(kind='merge')
这给出:
A B C timestamp
1970-01-19 05:31:38 2.0 14.0 16.0 1970-01-19 05:31:37.779
1970-01-19 05:31:38 3.0 16.0 19.0 1970-01-19 05:31:38.761
1970-01-19 05:31:40 6.0 22.0 28.0 1970-01-19 05:31:39.994
1970-01-19 05:31:40 6.0 22.0 28.0 1970-01-19 05:31:39.994
1970-01-19 05:31:42 8.0 26.0 34.0 1970-01-19 05:31:41.667
1970-01-19 05:31:42 9.0 28.0 37.0 1970-01-19 05:31:42.515
1970-01-19 05:31:44 13.0 36.0 49.0 1970-01-19 05:31:43.333
1970-01-19 05:31:44 14.0 38.0 52.0 1970-01-19 05:31:44.135
没关系,除了应用部分需要很长时间!
为了更容易复制:
,A,B,C
1970-01-19 05:31:36.629,0,10,10
1970-01-19 05:31:36.710,1,12,13
1970-01-19 05:31:37.779,2,14,16
1970-01-19 05:31:38.761,3,16,19
1970-01-19 05:31:39.520,4,18,22
1970-01-19 05:31:39.852,5,20,25
1970-01-19 05:31:39.994,6,22,28
1970-01-19 05:31:41.370,7,24,31
1970-01-19 05:31:41.667,8,26,34
1970-01-19 05:31:42.515,9,28,37
1970-01-19 05:31:42.941,10,30,40
1970-01-19 05:31:43.037,11,32,43
1970-01-19 05:31:43.253,12,34,46
1970-01-19 05:31:43.333,13,36,49
1970-01-19 05:31:44.135,14,38,52
您现有代码中较慢的部分是 df3
的创建,所以我会对其进行优化。
首先,请注意您的 last_time(x)
函数查找 x 到 x + 1 秒时间范围内的最后一条记录。
不使用循环,我们可以从偏移整个向量中的时间开始:
end_times = df2.timestamp + datetime.timedelta(microseconds=1000000)
然后我们可以使用numpy.searchsorted()
(一个被严重低估的函数!)来搜索df
中的那些时间:
idx = np.searchsorted(df.timestamp, end_times)
顺便说一下,df.timestamp.searchsorted(end_times)
做同样的事情。
最后,请注意,每个生成的索引都在我们想要的之后(我们不想要 1 秒之后的值,我们想要之前的值):
df3a = df.iloc[idx - 1]
除了索引没有向下舍入外,这与您的 df3
得到的结果相同,因此只需替换它:
df3a.index = df2.index
这与您的 df3
完全相同,但计算速度更快。