R foverlaps相当于Python

时间:2016-10-25 18:26:25

标签: python r pandas join bigdata

我正在尝试用Python重写一些R代码,并且无法通过一些特定的代码。我发现R中的foverlaps函数在执行基于时间的连接时非常有用,但是在Python3中找不到任何可行的函数。

我正在做的是加入两个数据表,其中一个表中的time介于另一个表中的start_timeend_time之间。两个表的周期不同 - table_A每秒发生一次,每个时间间隔可以有多个条目,而table_B每隔0到10分钟会有一个条目,不定期。

这个问题与我提出的问题非常相似: Merge pandas dataframes where one value is between two others

以下代码在R中提供了我想要的输出:

# Add dummy column to use with foverlaps
table_A <- table_A[, dummy := time]

# Set keys
setkey(table_B, x, y, start_time, end_time)
setkey(table_A, x, y, time, dummy)

# Join tables based on time
joined <- foverlaps(table_A, table_B, type = "within", by.x=c("x", "y", "time", "dummy"), by.y=c("x", "y", "start_time", "end_time"), nomatch=0L)[, dummy := NULL]


> head(table_A)
   time                         x       y     dummy
1: 2016-07-11 11:52:27          4077    1     2016-07-11 11:52:27 
2: 2016-07-11 11:52:27          4077    1     2016-07-11 11:52:27
3: 2016-07-11 11:52:27          4077    1     2016-07-11 11:52:27
4: 2016-07-11 11:52:27          4077    1     2016-07-11 11:52:27
5: 2016-07-11 11:52:32          4077    1     2016-07-11 11:52:32
6: 2016-07-11 11:52:32          4077    1     2016-07-11 11:52:32


> head(table_B)
                x       y   start_time              end_time
1:              6183    1   2016-07-11 12:00:45     2016-07-11 12:00:56 
2:              6183    1   2016-07-11 12:01:20     2016-07-11 12:01:20   
3:              6183    1   2016-07-11 12:01:40     2016-07-11 12:03:26  
4:              6183    1   2016-07-11 12:04:20     2016-07-11 12:04:40  
5:              6183    1   2016-07-11 12:04:55     2016-07-11 12:04:57  
6:              6183    1   2016-07-11 12:05:40     2016-07-11 12:05:51  

因此,table_A中时间落在start_time和end_time之间的任何行都将与table_B中的相应行连接,给出如下所示的输出。我在Python中尝试了很多不同的东西,但尚未找到解决方案。

从示例数据中可能不明显的一件事是,在同一timestart_time s内的end_time s处出现多个x和y值。

> head(joined)
  y      x      start_time              end_time                time 
1 1      4077   2016-07-11 12:00:45     2016-07-11 12:00:56     2016-07-11 12:00:46    
2 1      4077   2016-07-11 12:00:45     2016-07-11 12:00:56     2016-07-11 12:00:46    
3 1      4077   2016-07-11 12:00:45     2016-07-11 12:00:56     2016-07-11 12:00:46    
4 1      4077   2016-07-11 12:00:45     2016-07-11 12:00:56     2016-07-11 12:00:46    
5 1      4077   2016-07-11 12:00:45     2016-07-11 12:00:56     2016-07-11 12:00:46    
6 1      4077   2016-07-11 12:00:45     2016-07-11 12:00:56     2016-07-11 12:00:55 

1 个答案:

答案 0 :(得分:2)

考虑使用pandas.Series.between()与子集直接合并。合并连接连接列的所有组合,子集保持与时间间隔对齐的行。

df = pd.merge(table_A, table_B, on=['x', 'y'])                   
df = df[df['time'].between(df['start_time'], df['end_time'], inclusive=True)]

但是,一个重要的项目是您的日期应该作为日期时间类型。目前,您的帖子显示的字符串日期会影响.between()以上。以下假设美国日期以月份为MM/DD/YYYY。您可以在文件读取期间转换类型:

dateparse = lambda x: pd.datetime.strptime(x, '%m/%d/%Y %H:%M:%S')

table_A = pd.read_csv('data.csv', parse_dates=[0], date_parser=dateparse, dayfirst=False)

table_B = pd.read_csv('data.csv', parse_dates=[0,1], date_parser=dateparse, dayfirst=False)

或者在阅读之后:

table_A['time'] = pd.to_datetime(table_A['time'], format='%m/%d/%Y %H:%M:%S')

table_B['start_time'], table_B['end_time']=(pd.to_datetime(ser, format='%m/%d/%Y %H:%M:%S') \
                                    for ser in [table_B['start_time'], table_B['end_time']])