R:如何根据给定列的值删除数据帧的行

时间:2018-02-02 10:48:27

标签: r

我有100个模拟数据集,例如下面显示了单个集合

pid time status
1    2     1
1    6     0
1    4     1
2    3     0
2    1     1
2    7     1
3    8     1
3    11    1
3    2     0

pid表示患者身份。这表明每位患者在时间和状态列上有三条记录。 我想编写R代码来删除任何具有0状态的行,如果该行不是给定患者的第一次观察的记录,并且如果它表示第一次观察则保持行为0状态,而在此之后具有状态1的剩余行该患者将删除0。输出应该看起来像

pid time status
1    2     1
1    4     1
2    3     0
3    8     1
3    11    1

由于有100个模拟数据集,状态列中0和1的位置对于所有数据都不相同。任何人都可以帮助提供可以执行此任务的R代码吗? 先感谢您。

2 个答案:

答案 0 :(得分:3)

dplyr包可以提供帮助。我在您的数据示例中添加了一条记录,以便为pid包含多个0值。

按照pid分组,使用函数first,您可以保存第一个状态值。由于这个组将被保留为每个pid的所有记录。然后只是过滤第一条记录是0和row_number()= 1,以防有更多记录为0(参见pid 4)或第一条记录的状态为1并保留所有状态为1的记录。

df %>% 
  group_by(pid) %>% 
  filter((first(status) == 0 & row_number() == 1) | (first(status) == 1 & status == 1))

# A tibble: 6 x 3
# Groups:   pid [4]
    pid  time status
  <int> <int>  <int>
1     1     2      1
2     1     4      1
3     2     3      0
4     3     8      1
5     3    11      1
6     4     3      0

数据:

df <-
  structure(
    list(
      pid = c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 4L, 4L, 4L),
      time = c(2L, 6L, 4L, 3L, 1L, 7L, 8L, 11L, 2L, 3L, 6L, 8L),
      status = c(1L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 1L, 0L)
    ),
    .Names = c("pid", "time", "status"),
    class = "data.frame",
    row.names = c(NA,-12L)
  )

答案 1 :(得分:1)

这个问题更适合https://stackoverflow.com

以下是使用tapply()的尝试(它有点冗长):

dat <- structure(list(pid = c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L),
                      time = c(2L, 6L, 4L, 3L, 1L, 7L, 8L, 11L, 2L),
                      status = c(1L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 0L)),
                 .Names = c("pid", "time", "status"), class = "data.frame",
                 row.names = c(NA, -9L))
ind <- unlist(tapply(dat$status, dat$pid, function(x) {
    # browser()
    y <- (rep(FALSE, length(x)))
    if (x[1] == 1) {
        y[x != 0] <- TRUE
    } else {
        y[1] <- TRUE
    }
    y
}))
dat[ind, ]
#>   pid time status
#> 1   1    2      1
#> 3   1    4      1
#> 4   2    3      0
#> 7   3    8      1
#> 8   3   11      1

indTRUEFALSE s的向量,它将根据您的规则指示是否应保留dat行。

我将tapply(X, INDEX, FUN) apply函数用于向量的子集(此处为X = dat$status),这些子集由分组因子(此处为INDEX = dat$pid)定义。 在这里,我使用匿名函数(即FUN = function(x){})对X的每个子集执行某些操作。 特别是,我首先定义y,我将在稍后返回,它是FALSE s的向量。 如果子组的第一个状态为1,则将所有非零的元素(即y[x != 0])转换为TRUE。 否则,我只将第一个元素(即y[1])转换为TRUE

您可以取消注释browser()语句,并通过键入n(下一个)或xy来查看该功能的功能(看看它们是什么)是)。