如何对数据框进行子集操作?

3

我有一个类似这样的数据集

a <- data.frame(var1 = c("patientA", "patientA", "patientA", "patientB", "patientB", "patientB", "patientB"),
                var2 = as.Date(c("2015-01-02","2015-01-04","2015-02-02","2015-02-06","2015-01-02","2015-01-07","2015-04-02")),
                var3 = c(F, T, F, F, F, T, F)               
                )
sequ <- rle(as.character(a$var1))
a$sequ <- sequence(sequ$lengths)

生产
> a
      var1       var2  var3 sequ
1 patientA 2015-01-02 FALSE    1
2 patientA 2015-01-04  TRUE    2
3 patientA 2015-02-02 FALSE    3
4 patientB 2015-02-06 FALSE    1
5 patientB 2015-01-02 FALSE    2
6 patientB 2015-01-07  TRUE    3
7 patientB 2015-04-02 FALSE    4

如何对数据集进行子集/筛选,以获取所有 var3 == TRUE 且 var2 日期值大于 var3 == TRUE 所在行的日期值(按病人、 var1 分组)?我已经尝试了。

subset(a, (var3 == TRUE) & (var2 > var3))

但是这并不能产生正确的结果集。正确的结果集应该是:
#       var1       var2  var3 sequ
# 1 patientA 2015-01-04  TRUE    2
# 2 patientA 2015-02-02 FALSE    3
# 3 patientB 2015-02-06 FALSE    1
# 4 patientB 2015-01-07  TRUE    3
# 5 patientB 2015-04-02 FALSE    4

1
您所需的输出不是非常清晰。如果日期比较大,您是否希望获取var3 == TRUE之后的所有日期?如果每个患者有多个var3 == TRUE,会发生什么? - David Arenburg
是的,我希望将TRUE行包含在结果集中,并且还包括var3为FALSE但日期大于TRUE行的行。在我的数据集中,每个患者只有一行TRUE。 - jrara
3个回答

6

您可以尝试使用 data.table。在这里,我们将 'data.frame' 转换为 'data.table' (setDT(a)),按 'var1' 分组后,获取一个逻辑索引,以便筛选出 'var2' 元素大于或等于对应的 'var3' 为 TRUE 的 'var2' 元素,并对数据集进行子集筛选 .SD

library(data.table)
setDT(a)[,.SD[var2 >= var2[var3]], var1]
#       var1       var2  var3 sequ
#1: patientA 2015-01-04  TRUE    2
#2: patientA 2015-02-02 FALSE    3
#3: patientB 2015-02-06 FALSE    1
#4: patientB 2015-01-07  TRUE    3
#5: patientB 2015-04-02 FALSE    4

一种使用基础R的选项(假设数据已按'var1'排序)

a[with(a, var2>=rep(var2[var3], table(var1))),]
#      var1       var2  var3 sequ
#2 patientA 2015-01-04  TRUE    2
#3 patientA 2015-02-02 FALSE    3
#4 patientB 2015-02-06 FALSE    1
#6 patientB 2015-01-07  TRUE    3
#7 patientB 2015-04-02 FALSE    4

@AlexA。没问题,这种情况我也遇到过。 - akrun
感谢@akrun。这将产生正确的结果集。有没有使用基本R的方法来做到这一点?我不熟悉data.table语法。 - jrara
@jrara 更新了一个基础 R 选项。 - akrun

4

我添加了一个列,用于存储var3TRUE时的日期,并基于此进行筛选,最后再将它删除。

library(dplyr)

a %>% group_by(var1)%>%
    mutate(truedate = first(var2[var3])) %>%
    filter(var2 >= truedate) %>%
    select(-truedate)

# Source: local data frame [5 x 4]
# Groups: var1

#       var1       var2  var3 sequ
# 1 patientA 2015-01-04  TRUE    2
# 2 patientA 2015-02-02 FALSE    3
# 3 patientB 2015-02-06 FALSE    1
# 4 patientB 2015-01-07  TRUE    3
# 5 patientB 2015-04-02 FALSE    4

3

一种基于R的解决方案:首先,不要费心处理你的 rle/sequ 问题。相反,对你的数据进行排序:

a <- a[order(a$var1,a$var2),]

查找已选行:

myrows <- tapply(
  1:nrow(a),
  a$var1,
  function(ivec){
    istar <- ivec[a$var3[ivec]]
    ivec[ivec>=istar]
  })

使用a[unlist(myrows),]进行子集操作。


我加了另一个基本的R选项,虽然我不确定是否存在任何边缘情况 :-) - akrun
@akrun,是的,我在发布后才看到那个。虽然它也是基于R的,但很高兴看到我的代码不是完全重复的:没有其他人坚持让OP排序 :) - Frank

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接