【问题标题】:Apply a match and replace function over series of rows in a dataframe in order按顺序对数据框中的一系列行应用匹配和替换函数
【发布时间】:2016-09-14 03:16:58
【问题描述】:

起始数据帧

data_start <- data.frame(marker = c("yes","yes","no","yes","no"),
                         id_out = c(5,3,1,1,7), 
                         id_new = c(6,8,9,4,2))

> data_start
  marker id_out id_new
1    yes      5      6
2    yes      3      8
3     no      1      9
4    yes      1      4
5     no      7      2

在下面添加三个带有空列的列标题。附加起始 var1:var3 值。

data_start[,c("var1", "var2", "var3")] <- NA
vars <- c(5,3,1)
data_start[1, 4:6] <- vars

> data_start
  marker id_out id_new var1 var2 var3
1    yes      5      6    5    3    1
2    yes      3      8   NA   NA   NA
3     no      1      9   NA   NA   NA
4    yes      1      4   NA   NA   NA
5     no      7      2   NA   NA   NA

我想通过对 IF marker = yes AND id_out 匹配任何var1:var3 的每一行应用一个函数来更新我的var1:var3 列,将var1:var3 中的任何一个替换为@987654330 @。我找到了这个解决方案,但适用于一行代码,并且仍然需要更新行的每个新 var1:var3 部分。

data_start[1, 4:6][data_start[1, 4:6] == data_start[1,"id_out"]] <- data_start[1,"id_new"]

在再次应用函数之前,每一行还取决于使用上一行中的值。

最终输出如下所示,其中当标记 = no 时行保持不变并且随后更新每一行。

> data_final
  marker id_out id_new var1 var2 var3
1    yes      5      6    6    3    1
2    yes      3      8    6    8    1
3     no      1      9    6    8    1
4    yes      1      4    6    8    4
5     no      7      2    6    8    4

【问题讨论】:

    标签: r dataframe apply


    【解决方案1】:

    这可以与任意数量的列一起使用,并且可以与基本 R 一起使用:

    cols <- c("var1", "var2", "var3")
    
    for(j in 1:length(cols)) {
      var <- cols[j]
      for(i in 1:nrow(data_start)){
        if(i > 1) {
          data_start[i, var] <- data_start[i-1, var]
        }
        if(data_start[i, "marker"] == "yes" & data_start[i, var] == data_start[i,"id_out"]) {
          data_start[i,var] <- data_start[i, "id_new"]
        } 
      }
    }
    

    【讨论】:

    • 谢谢,终于回到了这个问题,它按预期工作。
    【解决方案2】:

    这是非常粗略的,因为我必须运行,但这应该可以。

    data_start <- data.frame(marker = c("yes","yes","no","yes","no"),
                             id_out = c(5,3,1,1,7), 
                             id_new = c(6,8,9,4,2))
    
    data_start[,c("var1", "var2", "var3")] <- NA
    vars <- c(5,3,1)
    data_start[1, 4:6] <- vars
    
    onVars <- c("var1", "var2", "var3")
    
    for (i in 2:nrow(data_start)) {
    
      print(i)
    
      for (var in onVars) {
    
        if (data_start$marker[i] == "yes" & data_start$id_out[i] == data_start[i - 1, var]) {
    
          data_start[i, var] <- data_start$id_new[i]
    
        } else {
    
          data_start[i, var] <- data_start[i - 1, var]
    
        }
    
      }
    
    }
    

    data_start 是你的输出。

    糟糕,看起来我可能忽略了评估第一行,但希望您现在可以自己处理。

    【讨论】:

      【解决方案3】:

      没有for循环和if似乎很难找到解决方案,所以在这里。我尝试使用其他设置(例如c(1,3,1))更改原始值,并且代码工作正常。如果需要,我们还可以添加更多变量列。

      # Re-create the data
      dt <- data.table(marker = c("yes","yes","no","yes","no"),
                       id_out = c(5,3,1,1,7),
                       id_new = c(6,8,9,4,2))
      var.col <- paste0("var", 1:3)
      dt[1, (var.col) := .(5,3,1)]
      
      # Processing
      for(i in 1:nrow(dt)) {
        if(i > 1) dt[i, (var.col) := as.list(dt[i-1, var.col, with = F])]
        var.i <- dt[i, var.col, with = F] %in% dt[i, id_out]
        if(dt[i]$marker == 'yes' & sum(var.i) != 0) {
          dt[i, (var.col[var.i]) := dt[i, id_new]]
        }
      }
      

      【讨论】:

        【解决方案4】:

        这是一个 sn-p,即使您有超过三列,也可以进行此计算:

        library(data.table)
        dt <- data.table(marker = c("yes","yes","no","yes","no"),
                                 id_out = c(5,3,1,1,7), 
                                 id_new = c(6,8,9,4,2))
        
        dt[, change := cumsum(marker == "yes")]
        
        ref.new <- dt[marker == "yes", id_new] # Reference to values where marker is "yes"
        ref.out <- dt[marker == "yes", id_out]
        for (x in 1:length(ref.new)) {
          dt[, paste("var", x, sep="") := ifelse(change >= x, ref.new[x] , ref.out[x])]
        }
        head(dt)
        #     marker id_out id_new change var1 var2 var3
        #1:    yes      5      6      1    6    3    1
        #2:    yes      3      8      2    6    8    1
        #3:     no      1      9      2    6    8    1
        #4:    yes      1      4      3    6    8    4
        #5:     no      7      2      3    6    8    4
        

        【讨论】:

        • 这是一种有趣的方法,但似乎你在这里假设了一些 OP 没有提到的模式,所以我不确定这是否是偶然的,或者这真的是应该的
        • 我想我明白你的意思了。好吧,无论哪种方式都很容易改变,我只是使用了最直接的选项。
        猜你喜欢
        • 1970-01-01
        • 2020-12-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-06
        • 2021-12-07
        • 2021-10-11
        相关资源
        最近更新 更多