【问题标题】:Replacing values in multiple columns in dataframe替换数据框中多列中的值
【发布时间】:2016-04-09 12:58:32
【问题描述】:

在以下示例中,res 有 90 行和 6 列,并包含多个 NA。还有一个矩阵,tmpCombs,有 6 行 2 列。 tmpCombs的每一行对应res中的一组15行(6*15=90)。它的列数 (2) 意味着我必须用指定的字符(比如“B”)替换 res 的每一行中的 2 个现有 NA。 (保证每行至少有2个NA)。

例如,tmpCombs 的第 5 行中的值 2 和 4 意味着对于 res 的组 61-75 (4*15+1):(5*15) 中的每一行,出现的第 2 和第 4 个 NA 必须替换为“B” .

我可以使用嵌套的 for 循环来完成这项工作,但我正在寻找一种更快/更大规模的方法来执行这些替换(可能使用 dplyrdata.table),因为我的代码变得越来越慢,因为尺寸增加。

下面给出了restmpCombs 的示例。还有第二个数据帧res2,其中包含所需的输出。

res <- structure(list(X1 = c("A", "A", "A", "A", "A", NA, NA, NA, NA, 
NA, NA, NA, NA, NA, NA, "A", "A", "A", "A", "A", NA, NA, NA, 
NA, NA, NA, NA, NA, NA, NA, "A", "A", "A", "A", "A", NA, NA, 
NA, NA, NA, NA, NA, NA, NA, NA, "A", "A", "A", "A", "A", NA, 
NA, NA, NA, NA, NA, NA, NA, NA, NA, "A", "A", "A", "A", "A", 
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "A", "A", "A", "A", "A", 
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), X2 = c("A", NA, NA, 
NA, NA, "A", "A", "A", "A", NA, NA, NA, NA, NA, NA, "A", NA, 
NA, NA, NA, "A", "A", "A", "A", NA, NA, NA, NA, NA, NA, "A", 
NA, NA, NA, NA, "A", "A", "A", "A", NA, NA, NA, NA, NA, NA, "A", 
NA, NA, NA, NA, "A", "A", "A", "A", NA, NA, NA, NA, NA, NA, "A", 
NA, NA, NA, NA, "A", "A", "A", "A", NA, NA, NA, NA, NA, NA, "A", 
NA, NA, NA, NA, "A", "A", "A", "A", NA, NA, NA, NA, NA, NA), 
    X3 = c(NA, "A", NA, NA, NA, "A", NA, NA, NA, "A", "A", "A", 
    NA, NA, NA, NA, "A", NA, NA, NA, "A", NA, NA, NA, "A", "A", 
    "A", NA, NA, NA, NA, "A", NA, NA, NA, "A", NA, NA, NA, "A", 
    "A", "A", NA, NA, NA, NA, "A", NA, NA, NA, "A", NA, NA, NA, 
    "A", "A", "A", NA, NA, NA, NA, "A", NA, NA, NA, "A", NA, 
    NA, NA, "A", "A", "A", NA, NA, NA, NA, "A", NA, NA, NA, "A", 
    NA, NA, NA, "A", "A", "A", NA, NA, NA), X4 = c(NA, NA, "A", 
    NA, NA, NA, "A", NA, NA, "A", NA, NA, "A", "A", NA, NA, NA, 
    "A", NA, NA, NA, "A", NA, NA, "A", NA, NA, "A", "A", NA, 
    NA, NA, "A", NA, NA, NA, "A", NA, NA, "A", NA, NA, "A", "A", 
    NA, NA, NA, "A", NA, NA, NA, "A", NA, NA, "A", NA, NA, "A", 
    "A", NA, NA, NA, "A", NA, NA, NA, "A", NA, NA, "A", NA, NA, 
    "A", "A", NA, NA, NA, "A", NA, NA, NA, "A", NA, NA, "A", 
    NA, NA, "A", "A", NA), X5 = c(NA, NA, NA, "A", NA, NA, NA, 
    "A", NA, NA, "A", NA, "A", NA, "A", NA, NA, NA, "A", NA, 
    NA, NA, "A", NA, NA, "A", NA, "A", NA, "A", NA, NA, NA, "A", 
    NA, NA, NA, "A", NA, NA, "A", NA, "A", NA, "A", NA, NA, NA, 
    "A", NA, NA, NA, "A", NA, NA, "A", NA, "A", NA, "A", NA, 
    NA, NA, "A", NA, NA, NA, "A", NA, NA, "A", NA, "A", NA, "A", 
    NA, NA, NA, "A", NA, NA, NA, "A", NA, NA, "A", NA, "A", NA, 
    "A"), X6 = c(NA, NA, NA, NA, "A", NA, NA, NA, "A", NA, NA, 
    "A", NA, "A", "A", NA, NA, NA, NA, "A", NA, NA, NA, "A", 
    NA, NA, "A", NA, "A", "A", NA, NA, NA, NA, "A", NA, NA, NA, 
    "A", NA, NA, "A", NA, "A", "A", NA, NA, NA, NA, "A", NA, 
    NA, NA, "A", NA, NA, "A", NA, "A", "A", NA, NA, NA, NA, "A", 
    NA, NA, NA, "A", NA, NA, "A", NA, "A", "A", NA, NA, NA, NA, 
    "A", NA, NA, NA, "A", NA, NA, "A", NA, "A", "A")), .Names = c("X1", 
"X2", "X3", "X4", "X5", "X6"), row.names = c(NA, -90L), class = "data.frame")

tmpCombs <- structure(c(1L, 1L, 1L, 2L, 2L, 3L, 2L, 3L, 4L, 3L, 4L, 4L), .Dim = c(6L, 
2L))

res2 <- structure(list(X1 = c("A", "A", "A", "A", "A", "B", "B", "B", 
"B", "B", "B", "B", "B", "B", "B", "A", "A", "A", "A", "A", "B", 
"B", "B", "B", "B", "B", "B", "B", "B", "B", "A", "A", "A", "A", 
"A", "B", "B", "B", "B", "B", "B", "B", "B", "B", "B", "A", "A", 
"A", "A", "A", NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "A", "A", 
"A", "A", "A", NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "A", "A", 
"A", "A", "A", NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), X2 = c("A", 
"B", "B", "B", "B", "A", "A", "A", "A", "B", "B", "B", "B", "B", 
"B", "A", "B", "B", "B", "B", "A", "A", "A", "A", NA, NA, NA, 
NA, NA, NA, "A", "B", "B", "B", "B", "A", "A", "A", "A", NA, 
NA, NA, NA, NA, NA, "A", NA, NA, NA, NA, "A", "A", "A", "A", 
"B", "B", "B", "B", "B", "B", "A", NA, NA, NA, NA, "A", "A", 
"A", "A", "B", "B", "B", "B", "B", "B", "A", NA, NA, NA, NA, 
"A", "A", "A", "A", NA, NA, NA, NA, NA, NA), X3 = c("B", "A", 
"B", "B", "B", "A", "B", "B", "B", "A", "A", "A", NA, NA, NA, 
"B", "A", NA, NA, NA, "A", NA, NA, NA, "A", "A", "A", "B", "B", 
"B", "B", "A", NA, NA, NA, "A", NA, NA, NA, "A", "A", "A", NA, 
NA, NA, NA, "A", "B", "B", "B", "A", "B", "B", "B", "A", "A", 
"A", "B", "B", "B", NA, "A", "B", "B", "B", "A", "B", "B", "B", 
"A", "A", "A", NA, NA, NA, NA, "A", NA, NA, NA, "A", NA, NA, 
NA, "A", "A", "A", "B", "B", "B"), X4 = c("B", "B", "A", NA, 
NA, "B", "A", NA, NA, "A", NA, NA, "A", "A", NA, NA, NA, "A", 
"B", "B", NA, "A", "B", "B", "A", "B", "B", "A", "A", NA, NA, 
NA, "A", NA, NA, NA, "A", NA, NA, "A", NA, NA, "A", "A", "B", 
"B", "B", "A", "B", "B", "B", "A", "B", "B", "A", "B", "B", "A", 
"A", NA, "B", "B", "A", NA, NA, "B", "A", NA, NA, "A", NA, NA, 
"A", "A", "B", NA, NA, "A", "B", "B", NA, "A", "B", "B", "A", 
"B", "B", "A", "A", "B"), X5 = c(NA, NA, NA, "A", NA, NA, NA, 
"A", NA, NA, "A", NA, "A", NA, "A", "B", "B", "B", "A", NA, "B", 
"B", "A", NA, "B", "A", NA, "A", NA, "A", NA, NA, NA, "A", "B", 
NA, NA, "A", "B", NA, "A", "B", "A", "B", "A", "B", "B", "B", 
"A", NA, "B", "B", "A", NA, "B", "A", NA, "A", NA, "A", NA, NA, 
NA, "A", "B", NA, NA, "A", "B", NA, "A", "B", "A", "B", "A", 
"B", "B", "B", "A", "B", "B", "B", "A", "B", "B", "A", "B", "A", 
"B", "A"), X6 = c(NA, NA, NA, NA, "A", NA, NA, NA, "A", NA, NA, 
"A", NA, "A", "A", NA, NA, NA, NA, "A", NA, NA, NA, "A", NA, 
NA, "A", NA, "A", "A", "B", "B", "B", "B", "A", "B", "B", "B", 
"A", "B", "B", "A", "B", "A", "A", NA, NA, NA, NA, "A", NA, NA, 
NA, "A", NA, NA, "A", NA, "A", "A", "B", "B", "B", "B", "A", 
"B", "B", "B", "A", "B", "B", "A", "B", "A", "A", "B", "B", "B", 
"B", "A", "B", "B", "B", "A", "B", "B", "A", "B", "A", "A")), .Names = c("X1", 
"X2", "X3", "X4", "X5", "X6"), row.names = c(NA, -90L), class = "data.frame")

【问题讨论】:

    标签: r performance loops


    【解决方案1】:

    tmpCombs可以展开得到每一行的映射:

    tc2 = tmpCombs[rep(seq_len(nrow(tmpCombs)), 
                       each = nrow(res) %/% nrow(tmpCombs)), ]
    dim(tc2)
    #[1] 90  2
    

    然后,仅在列上循环并计算NAs 的连续出现,当NA 出现特定(根据tmpCombs)数量增加时替换:

    NAcounts = integer(nrow(res))
    for(j in seq_along(res)) {
       nas = is.na(res[[j]])
    
       NAcounts = NAcounts + nas  #`NA`s found so far in each row
    
       #only for rows with `NA`s 
       #(no need for extended lookup if few rows contain `NA`)
       #check if _this_ appearance of `NA` matches in `tmpCombs`
       wnas = which(nas)
       matches = NAcounts[wnas] == tc2[wnas, ]
    
       res[[j]][wnas[as.logical(rowSums(matches))]] = "B"
    }
    identical(res, res2)
    #[1] TRUE
    

    【讨论】:

    • 谢谢。您能否提出一个概括,允许 tmpCombs 具有任意数量的列?
    • @GeorgeDontas:做了一些编辑;我认为as.logical(rowSums(x == y))(逻辑-> 数字-> 逻辑)可能比在x == y 的列上累积| 可能是多余的工作,但是,我想,它应该不会太低效。跨度>
    • 我将 res 转换为矩阵 - 代码以这种方式运行得更快。然后我对您的代码进行了一些必要的更改并获得了更快的执行速度。恭喜!
    • @GeorgeDontas :我希望使用“矩阵”可能会减慢速度,因为通常data.frame[[j]] 不会复制,而matrix[, j] 会复制,而且还有上面的设置似乎没有任何“data.frame”方法的开销。还是我在您的评论中遗漏了什么?
    • 查看该帖子了解更多详情codereview.stackexchange.com/questions/125186/…
    【解决方案2】:

    我认为它不会比你的 for 循环解决方案好多少,但这里有一个可能的选项:

    # Base R solution: 
    # note that res is a data.frame of characters but 
    # returned value will be a matrix of characters
    toBind <- 
    lapply(1:nrow(tmpCombs),function(idx){
      rowIdxs<- ((idx-1)*15+1):(idx*15)
      replaceIdxs <- tmpCombs[idx,]
      tmp <- apply(res[rowIdxs,],1,function(row){
        row[na.omit(which(is.na(row))[replaceIdxs])] <- 'B'
        return(row)
      })
      return(t(tmp))
    })
    
    fixed <- do.call(rbind,toBind)
    

    注意

    我建议你把res变成matrix的字符,因为通常访问matrix元素比data.frame

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-07-06
      • 2014-11-12
      • 2018-02-11
      • 2018-09-29
      • 2014-11-04
      • 2016-01-03
      • 1970-01-01
      相关资源
      最近更新 更多