替换数据框中多列中的值

时间:2016-04-09 12:58:32

标签: r performance loops

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

例如,tmpCombs第5行中的值2和4表示对于(4*15+1):(5*15)的组61-75 res中的每一行,第2和第4个出现的NAs必须用“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")

2 个答案:

答案 0 :(得分:2)

可以扩展

tmpCombs以获取每行的映射:

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

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

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

答案 1 :(得分:1)

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

# 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)

N.B。

我建议您将res转换为matrix个字符,因为matrix元素的访问速度通常比data.frame