我有一个数据集,可以随着时间的推移垂直存储参与者的实例.他们基本上可以有任何数量的后续行动,参与者的数量从1到14行不等,但随着时间的推移,预计会增加更多.

我有一个变量列表var,参与者大概已经在每个后续行动中报告了这些变量,并且想要创建一组新的"曾经"变量vare,其描述在该后续行动之前的任何时间,参与者对相应的变量报告"是"的情况.

以下是所需输入/输出的示例:

var  = c("var1","var2")
vare = paste0(var,"_ever")

data = data.frame(idno         = c(123,123,123,123,123,123,123)
                  followup_num = c(0,1,2,3,4,5,6)
                  var1         = c(0,NA,0,1,0,NA,1)
                  var2         = c(1,NA,NA,0,0,0,1)
                 )         
data$var1_ever = c(0,0,0,1,1,1,1)
data$var2_ever = c(1,1,1,1,1,1,1)
idno followup_num var1 var1_ever var2 var2_ever
123 0 0 0 1 1
123 1 NA 0 NA 1
123 2 0 0 NA 1
123 3 1 1 0 1
123 4 0 1 0 1
123 5 NA 1 0 1
123 6 1 1 1 1

这是我目前使用的代码.显然,嵌套的for循环在R中并不理想,这段代码在处理几千行代码时特别慢.

#For each ID
for (i in unique(data$idno)) {

  id  = data$idno%in%i              #Get the relevant lines for this ID
  fus = sort(data$followup_num[id]) #Get the follow-up numbers
  
  #For each variable in the list
  for (v in seq_along(var)) {

    #Loop through the follow-ups. If you see that the variable reports "yes", mark 
    #  this and every proceeding follow-up as having reported that variable ever 
    #  Otherwise, mark the opposite at that line and move to the next follow-up
    for (f in fus) {
      if (t(data[id & data$followup_num%in%f,var[v]])%in%1) {
        data[id & data$followup_num >= f,vare[v]] = 1
        break
      } else {
        data[id & data$followup_num%in%f,vare[v]] = 0
      }
    }    
  }
}

这是现有解决方案的问题吗?有没有优化/简化的方法?有没有我没有try 过的应用/sApply/等函数的用法?

推荐答案

在其核心,解决方案是基本函数cummax().我们需要考虑NA,所以我加了replace_na().我们需要通过使用group_by()来解释额外的IDNO

最小向量化解是

df$var1_test<-cummax(x=replace_na(df$var1, 0))

这是一个需要用tidyverse-mutate-across函数集来解决的大问题!

df = data.frame(idno         = c(123,123,123,123,123,123,123),
                  followup_num = c(0,1,2,3,4,5,6),
                  var1         = c(0,NA,0,1,0,NA,1),
                  var2         = c(1,NA,NA,0,0,0,1))

df %>% group_by(idno) %>%  
       arrange(idno, followup_num) %>% 
       mutate(across(.cols=starts_with("var"), 
                     .fns= ~ cummax(tidyr::replace_na(.x, 0)), 
                     .names="{.col}_ever2"))
   idno followup_num  var1  var2 var1_ever2 var2_ever2
1   123            0     0     1          0          1
2   123            1    NA    NA          0          1
3   123            2     0    NA          0          1
4   123            3     1     0          1          1
5   123            4     0     0          1          1
6   123            5    NA     0          1          1
7   123            6     1     1          1          1

或者,如果您希望将数据汇总到一行,则可以使用分组的最大值

df %>%
  group_by(idno) %>%
  summarise(across(.cols=starts_with("var"), 
                   .fns= ~ max(.x, na.rm=T), 
                   .names="{.col}_ever3"))
   idno var1_ever3 var2_ever3
1   123          1          1

PS.data是内部函数,最好调用变量df.

R相关问答推荐

使用ggcorrplot在相关性矩阵上标注supertitle和index标签

根据列表中项目的名称多次合并数据框和列表

如何根据组大小应用条件过滤?

在"gt"表中添加第二个"groupname_col",而不连接列值

当两个图层映射到相同的美学时,隐藏一个图层的图例值

r替换lme S4对象的字符串的一部分

整数成随机顺序与约束R?

如何调整曲线图中的y轴标签?

移除仪表板Quarto中顶盖和车身之间的白色区域

2个Rscript.exe可执行文件有什么区别?

您是否可以折叠R中的重复行,同时保留基于所选列的值?

R中1到n_1,2到n_2,…,n到n_n的所有组合都是列表中的向量?

将选定的索引范围与阈值进行比较

从数据创建数字的命名列表.R中的框

快速合并R内的值

如何在R中创建这些列?

如何创建直方图与对齐的每月箱?

合并多个数据帧,同时将它们的名称保留为列名?

如何根据每个子框架中分类因子的唯一计数来过滤子框架列表?

使用循环改进功能( struct 简单)