替换dataframe中多列中的值
在下面的示例中,替换dataframe中多列中的值,r,performance,loops,R,Performance,Loops,在下面的示例中,res有90行6列,包括几个NAs。还有一个矩阵,tmpCombs,有6行2列。tmpcomb的每一行对应于res中的一组15行(6*15=90)。它的列数(2)意味着我必须用指定的字符(如“B”)替换res每行中的2个现有NA。(确保每行至少有2个NAs) 例如,tmpCombs的第5行中的值2和4意味着对于res的组61-75(4*15+1):(5*15)中的每一行,出现的第2和第4个NAs必须替换为“B” 我可以使用嵌套for循环来完成这项工作,但我正在寻找一种更快/更大规
res
有90行6列,包括几个NAs。还有一个矩阵,tmpCombs
,有6行2列。tmpcomb
的每一行对应于res
中的一组15行(6*15=90)。它的列数(2)意味着我必须用指定的字符(如“B”)替换res
每行中的2个现有NA。(确保每行至少有2个NAs)
例如,tmpCombs
的第5行中的值2和4意味着对于res
的组61-75(4*15+1):(5*15)
中的每一行,出现的第2和第4个NAs必须替换为“B”
我可以使用嵌套for循环来完成这项工作,但我正在寻找一种更快/更大规模的方法来执行这些替换(可能使用dplyr
或data.table
),因为随着维度的增加,我的代码变得越来越慢
下面给出了res
和tmpCombs
的示例。还有第二个数据帧,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")
res我不认为它比for-loop解决方案好多少,但这里有一个可能的选择:
# 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)
#基本R解决方案:
#请注意,res是字符的data.frame,但
#返回值将是一个字符矩阵
toBind我不认为它比for-loop解决方案好多少,但这里有一个可能的选择:
# 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)
#基本R解决方案:
#请注意,res是字符的data.frame,但
#返回值将是一个字符矩阵
toBindtmpcomb
可以展开以获得每行的映射:
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
tmpcomb
可以展开以获得每行的映射:
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
非常感谢。你能建议一个通用的方法,允许tmpcomb有任意数量的列吗?@GeorgeDontas:做了一些编辑;我认为as.logical(rowSums(x==y))
(logical->numeric->logical)可能比在x==y
的列上累积|
的工作量要多,但是,我想,这应该不会太低效。我将res转换成了一个矩阵——这样代码运行得更快。然后我对您的代码进行了一些必要的更改,并获得了更快的执行速度。恭喜你@乔治顿塔斯:我认为使用“矩阵”可能会减慢速度,因为一般来说,data.frame[[j]]
不会复制,而matrix[,j]
会复制,而且,在上面的设置中,似乎没有任何“data.frame”方法的开销。还是我在你的评论中遗漏了什么?更多细节请查看该帖子,谢谢。你能建议一个通用的方法,允许tmpcomb有任意数量的列吗?@GeorgeDontas:做了一些编辑;我认为as.logical(rowSums(x==y))
(logical->numeric->logical)可能比在x==y
的列上累积|
的工作量要多,但是,我想,这应该不会太低效。我将res转换成了一个矩阵——这样代码运行得更快。然后我对您的代码进行了一些必要的更改,并获得了更快的执行速度。恭喜你@乔治顿塔斯:我认为使用“矩阵”可能会减慢速度,因为一般来说,data.frame[[j]]
不会复制,而matrix[,j]
会复制,而且,在上面的设置中,似乎没有任何“data.frame”方法的开销。或者我在你的评论中遗漏了什么?更多细节请查看该帖子