通过两个变量标记大型数据框中的每一行

时间:2017-10-21 03:38:57

标签: r dataframe time row

我有一个像这样的数据框(真正的数据框要大得多):

time<-c(as.POSIXct('2011-11-11 06:00:00'),as.POSIXct('2011-11-11 06:05:00'),as.POSIXct('2011-11-11 07:05:00'),
          as.POSIXct('2011-11-11 07:10:00'),as.POSIXct('2011-11-11 07:13:00'),as.POSIXct('2011-11-11 07:33:00'),
          as.POSIXct('2011-11-11 05:05:00'),as.POSIXct('2011-11-11 06:05:00'),as.POSIXct('2011-11-11 06:20:00'),
          as.POSIXct('2011-11-11 09:05:00'))
plate<-c('a','a','a','b','c','d','e','e','e','e')
df<-data.frame(time,plate)

time变量表示视频设备识别车辆的时间。 plate变量代表车辆的牌照。首先plate和其次time已对数据框进行了良好的排序。

鉴于此,我想通过标记行来分配每个车辆的行程。不同的车辆(plates)肯定代表不同的旅程。对于一辆车,一次行程中确定的时差应短于30分钟,否则,行应属于不同的行程。

按照我的方式,我将通过以下代码执行此操作:

trip<-vector()
trip[1]<-1
time_diff<-as.POSIXct('2011-11-11 07:00:00')-as.POSIXct('2011-11-11 06:30:00')
for (x in 2:nrow(df)) {
  if (!df$plate[x]==df$plate[x-1]) (trip[x]<-trip[x-1]+1
  ) else{if (df$time[x]-df$time[x-1]<time_diff) (trip[x]<-trip[x-1]
  ) else (trip[x]<-trip[x-1]+1)}
}
df<-cbind(df,trip)

但是,我的df包含超过七百万行,因此我的方法会非常慢。所以我问是否有更有效的方法来做到这一点。

1 个答案:

答案 0 :(得分:2)

我建议您使用dplyr,但如果这对您来说效果不佳,则可以考虑使用data.table解决方案。

library(dplyr)

time_diff<-as.POSIXct('2011-11-11 07:00:00')-as.POSIXct('2011-11-11 06:30:00')

df %>%
  arrange(time) %>% # it's important, so I reinforce it here
  group_by(plate) %>%
  mutate(
    trip = cumsum( c(TRUE, diff(time) > time_diff) )
  ) %>%
  ungroup()
# # A tibble: 10 × 3
#                   time  plate  trip
#                 <dttm> <fctr> <int>
# 1  2011-11-11 06:00:00      a     1
# 2  2011-11-11 06:05:00      a     1
# 3  2011-11-11 07:05:00      a     2
# 4  2011-11-11 07:10:00      b     1
# 5  2011-11-11 07:13:00      c     1
# 6  2011-11-11 07:33:00      d     1
# 7  2011-11-11 05:05:00      e     1
# 8  2011-11-11 06:05:00      e     2
# 9  2011-11-11 06:20:00      e     2
# 10 2011-11-11 09:05:00      e     3

我更喜欢使用group_by的上述解决方案,但是如果你希望trip在板块之间是唯一的,那么一种技术就是自己处理分组(需要严格的排序):

df %>%
  arrange(plate, time) %>%
  mutate(
    trip = cumsum( plate != lag(plate, default = plate[1]) | c(TRUE, diff(time) > time_diff) )
  )
#                   time plate trip
# 1  2011-11-11 06:00:00     a    1
# 2  2011-11-11 06:05:00     a    1
# 3  2011-11-11 07:05:00     a    2
# 4  2011-11-11 07:10:00     b    3
# 5  2011-11-11 07:13:00     c    4
# 6  2011-11-11 07:33:00     d    5
# 7  2011-11-11 05:05:00     e    6
# 8  2011-11-11 06:05:00     e    7
# 9  2011-11-11 06:20:00     e    7
# 10 2011-11-11 09:05:00     e    8