首页 > 解决方案 > 保留跨越多个时间范围的行

问题描述

我有一个数据框 ( da),其中每一行都有一个按升序排列的时间戳(每个时间戳之间的间隔是随机的)。

我想da根据它的时间是否在其他两个向量(first.timessecond.times)之间的时间范围内来保留行。所以我会迭代地遍历向量,first.time看看second.timeda这些间隔内是否有时间(min =first times和 max = second.times),我保留这些时间,其余的我没有。

我想出如何做到这一点的唯一方法是使用for循环,但这可能需要一段时间。这是带有一些示例数据的代码:

#Set start and end dates
date1 <- as.POSIXct(strptime('1970-01-01 00:00', format = '%Y-%m-%d %H:%M'))
date2 <- as.POSIXct(strptime('1970-01-05 23:00', format = '%Y-%m-%d %H:%M'))

#Interpolate 250000 dates in between (dates are set to random intervals)
dates <- c(date1 + cumsum(c(0, round(runif(250000, 20, 200)))), date2)

#Set up dataframe
da <- data.frame(dates = dates,
                 a = round(runif(1, 1, 10)),
                 b = rep(c('Hi', 'There', 'Everyone'), length.out = length(dates)))
head(da); dim(da)

#Set up vectors of time
first.times <- seq(date1,      #First time in sequence is date1
                   date2,      #Last time in sequence is date2
                   by = 13*60) #Interval of 13 minutes between each time (13 min * 60 sec)

second.times <- first.times + 5*60 #Second time is 5 min * 60 seconds later
head(first.times); length(first.times)
head(second.times); length(second.times)

#Loop to obtain rows
subsetted.dates <- da[0,]
system.time(for(i in 1:length(first.times)){
  subsetted.dates <- rbind(subsetted.dates, da[da$dates >= first.times[i] & da$dates < second.times[i],])
})
 user  system elapsed 
2.590   0.825   3.520 

我想知道是否有更有效和更快的方法来做我在for循环中所做的事情。这个示例数据集运行得非常快,但我的实际数据集每次迭代可能需要 45 秒,并且要进行 1000 次迭代,这可能需要一段时间!

任何帮助都会大有帮助!

谢谢!

标签: rfor-loop

解决方案


永远不要使用rbindcbind在循环内!这会导致内存中的过度复制。参见Patrick Burns 的 R Interno:Circle 2 -Growing Objectsrbind相反,在循环之外构建一个数据帧列表:

由于您在相等长度的向量之间迭代元素,请考虑mapply或其列表包装器,Map

df_list <- Map(function(f, s) da[da$dates >= f & da$dates < s,],
               first.times, second.times)

# EQUIVALENT CALL
df_list <- mapply(function(f, s) da[da$dates >= f & da$dates < s,],
                  first.times, second.times, SIMPLIFY=FALSE)

甚至考虑将第一次和第二次添加到数据框中transform以添加列:

df_list <- Map(function(f, s) transform(da[da$dates >= f & da$dates < s,], 
                                        first_time = f, second_time = s),
               first.times, second.times)

从那里,使用许多解决方案来行绑定数据框列表:

# BASE
final_df <- do.call(rbind, df_list)

# PLYR
final_df <- rbind.fill(df_list)

# DPLYR
final_df <- bind_rows(df_list)

# DATA TABLE
final_df <- rbindlist(df_list)

在此处查看基准示例:将数据帧列表转换为一个数据帧


推荐阅读