Python 熊猫:基于时间间隔加入数据帧

Python 熊猫:基于时间间隔加入数据帧,python,pandas,datetime,Python,Pandas,Datetime,我有一个数据框,每10分钟有一个datetime列和一个数值: df1 = pd.DataFrame({'time' : pd.date_range('1/1/2018', periods=20, freq='10min'), 'value' : np.random.randint(2, 20, size=20)}) 还有一个有活动时间表,有开始时间和结束时间。可以同时发生多个事件: df2 = pd.DataFrame({'start_time' : ['2018-01-01 00:00:0

我有一个数据框,每10分钟有一个datetime列和一个数值:

df1 = pd.DataFrame({'time' : pd.date_range('1/1/2018', periods=20, freq='10min'), 'value' : np.random.randint(2, 20, size=20)})
还有一个有活动时间表,有开始时间和结束时间。可以同时发生多个事件:

df2 = pd.DataFrame({'start_time' : ['2018-01-01 00:00:00', '2018-01-01 00:00:00','2018-01-01 01:00:00', '2018-01-01 01:00:00', '2018-01-01 01:00:00', '2018-01-01 02:00:00' ], 'end_time' : ['2018-01-01 01:00:00', '2018-01-01 01:00:00', '2018-01-01 02:00:00','2018-01-01 02:00:00', '2018-01-01 02:00:00', '2018-01-01 03:00:00'], 'event' : ['A', 'B', 'C', 'D', 'E', 'F'] })
df2[['start_time', 'end_time']] = df2.iloc[:,0:2].apply(pd.to_datetime)
我想在df1上做一个左连接,所有事件都在开始和结束时间内。我的输出表应该是:

                  time  value event
0  2018-01-01 00:00:00      5     A
1  2018-01-01 00:00:00      5     B
2  2018-01-01 00:10:00     15     A
3  2018-01-01 00:10:00     15     B
4  2018-01-01 00:20:00     16     A
5  2018-01-01 00:20:00     16     B
.....
17 2018-01-01 02:50:00      7     F

我尝试过,但由于重复的时间间隔,它们失败了。

我不完全确定您的问题,但是如果您试图加入“在开始和结束时间内的事件”,那么听起来您需要类似于SQL中的“介于”操作符的东西。你很抱歉,数据并没有说得特别清楚

熊猫不是天生就有这个,但Pandasql有。它允许您针对自己的数据帧运行sqlite。我认为你需要这样的东西:

import pandasql as ps

sqlcode = '''
select *
from df1
inner join df2 on df1.event=df2.event
where df2.time >= d1.start_time and df2.fdate <= d1.stop_time
'''

newdf = ps.sqldf(sqlcode,locals())
将pandasql作为ps导入
sqlcode=''
挑选*
来自df1
df1上的内部联接df2.event=df2.event
其中df2.time>=d1.start\u time和df2.fdate设置(为简洁起见,仅使用
df1
中的几个条目):

您可以使用几个直截了当的列表理解来实现您的结果。此答案假设所有日期列实际上都是数据框中的
datetime
类型:

步骤1
使用列表理解和简单的间隔检查查找特定时间范围内发生的所有事件:

packed = list(zip(df2.start_time, df2.end_time, df2.event))
df1['event'] = [[ev for strt, end, ev in packed if strt <= el <= end] for el in df1.time]

                  time  value      event
2  2018-01-01 00:20:00      8     [A, B]
14 2018-01-01 02:20:00     14        [F]
8  2018-01-01 01:20:00      6  [C, D, E]
19 2018-01-01 03:10:00     16         []
4  2018-01-01 00:40:00      7     [A, B]
输出:

                 time  value event
0 2018-01-01 00:20:00      8     A
1 2018-01-01 00:20:00      8     B
2 2018-01-01 02:20:00     14     F
3 2018-01-01 01:20:00      6     C
4 2018-01-01 01:20:00      6     D
5 2018-01-01 01:20:00      6     E
6 2018-01-01 00:40:00      7     A
7 2018-01-01 00:40:00      7     B

您可以使用
df2
为每个事件创建一个始终具有重采样
'10min'
(如
df1
)的列,然后使用
合并
。这需要大量的操作,所以可能不是最有效的

df2_manip = (df2.set_index('event').stack().reset_index().set_index(0)
                .groupby('event').resample('10T').ffill().reset_index(1))
而df2_manip
看起来像:

                        0 event     level_1
event                                      
A     2018-01-01 00:00:00     A  start_time
A     2018-01-01 00:10:00     A  start_time
A     2018-01-01 00:20:00     A  start_time
A     2018-01-01 00:30:00     A  start_time
A     2018-01-01 00:40:00     A  start_time
A     2018-01-01 00:50:00     A  start_time
A     2018-01-01 01:00:00     A    end_time
B     2018-01-01 00:00:00     B  start_time
B     2018-01-01 00:10:00     B  start_time
B     2018-01-01 00:20:00     B  start_time
B     2018-01-01 00:30:00     B  start_time
...
现在您可以
合并

df1 = df1.merge(df2_manip[[0, 'event']].rename(columns={0:'time'}))
您将得到
df1

                  time  value event
0  2018-01-01 00:00:00      9     A
1  2018-01-01 00:00:00      9     B
2  2018-01-01 00:10:00     16     A
3  2018-01-01 00:10:00     16     B
...
33 2018-01-01 02:00:00      6     D
34 2018-01-01 02:00:00      6     E
35 2018-01-01 02:00:00      6     F
36 2018-01-01 02:10:00      2     F
37 2018-01-01 02:20:00     18     F
38 2018-01-01 02:30:00     14     F
39 2018-01-01 02:40:00      5     F
40 2018-01-01 02:50:00      3     F
41 2018-01-01 03:00:00      9     F

我不明白前两个的
value=5
是从哪里来的。@user3483203
value
被设置为一个随机数,因此结果就是一个例子。啊,应该先读,谢谢:P
df1
没有
事件。看起来很方便。pandasql在幕后做什么?这对于提供的示例数据帧非常有效。如果我想在最终输出中保留更多的
df1
列,您是否看到了一种方法来抽象它?您应该能够将它们添加到步骤2中的
zip
列中。您可以在列表中跟踪它们,然后将其反向压缩。
df1 = df1.merge(df2_manip[[0, 'event']].rename(columns={0:'time'}))
                  time  value event
0  2018-01-01 00:00:00      9     A
1  2018-01-01 00:00:00      9     B
2  2018-01-01 00:10:00     16     A
3  2018-01-01 00:10:00     16     B
...
33 2018-01-01 02:00:00      6     D
34 2018-01-01 02:00:00      6     E
35 2018-01-01 02:00:00      6     F
36 2018-01-01 02:10:00      2     F
37 2018-01-01 02:20:00     18     F
38 2018-01-01 02:30:00     14     F
39 2018-01-01 02:40:00      5     F
40 2018-01-01 02:50:00      3     F
41 2018-01-01 03:00:00      9     F