从符合R中条件的行中提取值

时间:2014-04-14 15:47:21

标签: r data.table dplyr

数据集

我有一个包含数百万行和超过20列的大数据框。让我先描述一下数据是什么让问题更清楚。原始数据框架包括15分钟内2169辆车的位置,速度和加速度。每辆车都有一个唯一的Vehicle.ID,即观察到它的时间范围的ID,即Frame.ID,车辆在该帧中的速度,即svel,车辆在该帧中的加速度即sacc和该车辆的等级vehicle.class,即1 =摩托车,2 =汽车,3 =卡车。每0.1秒后记录这些变量,即每帧为0.1秒。以下是前6行:

> dput(head(df))
structure(list(Vehicle.ID = c(2L, 2L, 2L, 2L, 2L, 2L), Frame.ID = 133:138, 
    Vehicle.class = c(2L, 2L, 2L, 2L, 2L, 2L), Lane = c(2L, 2L, 
    2L, 2L, 2L, 2L), svel = c(37.29, 37.11, 36.96, 36.83, 36.73, 
    36.64), sacc = c(0.07, 0.11, 0.15, 0.19, 0.22, 0.25)), .Names = c("Vehicle.ID", 
"Frame.ID", "Vehicle.class", "Lane", "svel", "sacc"), row.names = 7750:7755, class = "data.frame")

在15分钟的录音期间,车辆行程中有些情况会完全停止,即svel==0。对于某些帧继续这种情况,然后车辆再次获得速度。出于再现性的目的,我创建了一个示例数据集,如下所示:

x <- data.frame(Vehicle.ID = c(rep(10,5), rep(20,5), rep(30,5), rep(40,5), rep(50,5)),
                    vehicle.class = c(rep(2,10), rep(3,10),rep(1,5)),
                    svel = rep(c(1,0,0,0,3),5),
                    sacc = rep(c(0.3,0.001,0.001,0.002,0.5),5))

我想找到什么?

如上所述,一些车辆停止并且在一段时间内具有零速度但随后加速以加速。我想找到加速度sacc,它们在零速度一段时间后应用(从静止位置移动)。这意味着我应该能够查看svel==0的最后一帧之后的第一行。在示例数据中,这意味着具有vehicle.class==2的汽车(Vehicle.ID==10)的速度svel等于1,如第一行所示。之后,它停止了3帧(连续3行),然后加速到速度svel,等于3.我希望在这2帧(行4和5用于车辆)中应用加速度sacc 10,出来是0.002和0.500)。这意味着,例如数据,以下应该是vehicle.class

的输出
output <- data.frame(Vehicle.ID = c(10,10,20,20,30,30,40,40,50, 50),
                     vehicle.class = c(2,2,2,2,3,3,3,3,1,1),
                     xf = rep(c('l','f'),10),
                     sacc = rep(c(0.002,0.500),5))

xf标识lsvel==0之后的第一行f。我尝试使用plyrfor loopvehicle.class进行拆分,但不确定如何提取sacc

注意

  1. xf应该是输出的一部分。它不在给定的数据中。
  2. 原始数据框df有2169辆车,有些停了下来 有些并非所有车辆都没有svel==0
  3. 停止的车辆没有同时进行。而且, svel==0与车辆不同的行数。

4 个答案:

答案 0 :(得分:1)

可能有一种更优雅的方式来做到这一点,但这有效:

require(data.table)
x <- data.table(x)  ## much easier as data.table
x[, xf:='n']        ## create vector with 'n', neither first nor last

# create diff(svel) shifted upwards, 
# padding last observation with 0 to avoid cycling
x[, dsvel:=c(diff(svel, lag=1), 0), by=Vehicle.ID]

# svel is zero and dsvel positive at the last 0 value
x[svel==0 & dsvel > 0, xf:='l']

# there may be a better way to do this part
# get index of observation next to 'l'
# there is no risk of spilling to next Vehicle.ID,  
# because 'l' can only be second to last
i <- which(x$xf=='l') + 1
x[i, xf:='f']

这应该会为您提供所需的xf向量。


来自Arun的编辑:+1 @ilir,一个非常好的答案。通过使用data.table的内置变量.I.N,您可以采用另一种方式:

idx = x[, {
            ix = tail(.I[svel==0L], 1);
            iy = (ix+1L)*((ix+1L) <= .I[.N] | NA) 
            list(idx = c(ix, iy))
          }, by = list(Vehicle.ID, vehicle.class)]$idx

您现在可以将idx添加lf:=进行对,如下所示:

ans <- x[idx][, xf := c("l", "f")]
    Vehicle.ID vehicle.class svel  sacc xf
 1:         10             2    0 0.002  l
 2:         10             2    3 0.500  f
 3:         20             2    0 0.002  l
 4:         20             2    3 0.500  f
 5:         30             3    0 0.002  l
 6:         30             3    3 0.500  f
 7:         40             3    0 0.002  l
 8:         40             3    3 0.500  f
 9:         50             1    0 0.002  l
10:         50             1    3 0.500  f

.I包含每个组的x行号。 .N包含每个组的观察数。请阅读?data.table了解更多信息。

ix获取0的最后一次出现。我们使用tail为每个组子集对应于最后0的行号。

iy通常应该是下一个条目= ix+1L。但由于0可能是某个组的最后一个条目,我们通过比较(ix+1L) <= .I[.N]来检查是否是这样。如果它为FALSE意味着ix是最后一个条目,所以我们要输出NA,否则我们要输出(ix+1L)

HTH。

答案 1 :(得分:1)

我想我已经想出了一种相当优雅的方式来代表 dplyr的问题。对于每辆车,我们对其中的行感兴趣 它没有停在这一行,但在上一行停止了:

library(dplyr)
df <- tbl_df(data.frame(
  id = c(rep(10, 5), rep(20, 5), rep(30, 5), rep(40, 5), rep(50, 5)), 
  class = c(rep(2, 10), rep(3, 10), rep(1, 5)), 
  svel = rep(c(1, 0, 0, 0, 3), 5), 
  sacc = rep(c(0.3, 0.001, 0.001, 0.002, 0.5), 5)
))

df %.% group_by(id) %.% 
  mutate(stopped = svel == 0) %.%
  filter(lag(stopped) == TRUE, stopped == FALSE)

#> Source: local data frame [5 x 5]
#> Groups: id
#> 
#>   id class svel sacc stopped
#> 1 10     2    3  0.5   FALSE
#> 2 20     2    3  0.5   FALSE
#> 3 30     3    3  0.5   FALSE
#> 4 40     3    3  0.5   FALSE
#> 5 50     1    3  0.5   FALSE

你可以把它写得更紧凑一点

df %.% group_by(id) %.% 
  mutate(stopped = svel == 0) %.%
  filter(lag(stopped), !stopped)

#> Source: local data frame [5 x 5]
#> Groups: id
#> 
#>   id class svel sacc stopped
#> 1 10     2    3  0.5   FALSE
#> 2 20     2    3  0.5   FALSE
#> 3 30     3    3  0.5   FALSE
#> 4 40     3    3  0.5   FALSE
#> 5 50     1    3  0.5   FALSE

答案 2 :(得分:0)

我不确定我完全理解这个问题,但我认为这就是你所追求的目标:

x <- data.frame(Vehicle.ID = c(rep(10,5), rep(20,5), rep(30,5), rep(40,5), rep(50,5)),
                vehicle.class = c(rep(2,10), rep(3,10),rep(1,5)),
                svel = rep(c(1,0,0,0,3),5),
                sacc = rep(c(0.3,0.001,0.001,0.002,0.5),5)
)

# find "l" rows, the last row for a given Vehicle.ID where svel==0
l <- FALSE
l[x$svel==0] <- !duplicated(x$Vehicle.ID[x$svel==0], fromLast=TRUE)
# extract all rows following an l row.
x[which(l) + 1, c(1, 2, 4)]

答案 3 :(得分:0)

library(data.table)
x = data.table(x)
output = x[xf == "f",sacc.after.zero := sacc, by = vehicle.class]
output[!is.na(sacc.after.zero),]