r语言 - 如何将数据帧的两列与缺失的数据组合在一起?



这是这个早期问题的扩展。如何将数据框的两列合并为

data <- data.frame('a' = c('A','B','C','D','E'),
'x' = c("t",2,NA,NA,NA),
'y' = c(NA,NA,NA,4,"r"))

显示为

'a' 'x' 'y'  
A   t   NA  
B   2   NA  
C  NA   NA  
D  NA   4  
E  NA   r

要得到

'a' 'mycol'  
A   t  
B   2  
C   NA  
D   4  
E   r  

我试过这个

cbind(data[1], mycol = na.omit(unlist(data[-1])))

但它显然没有保持NA行。

你可以通过使用ifelse来做到这一点,就像这样:

data$mycol <- ifelse(!is.na(data$x), data$x, data$y)
> data
##   a  x  y mycol
## 1 A  1 NA     1
## 2 B  2 NA     2
## 3 C NA NA    NA
## 4 D NA  4     4
## 5 E NA  5     5

按照你的逻辑,你可以执行以下操作:

cbind(data[1], mycol = unlist(apply(data[2:3], 1, function(i) ifelse(
length(is.na(i))==length(i),
na.omit(i),
NA)
)))
#  a mycol
#1 A     1
#2 B     2
#3 C    NA
#4 D     4
#5 E     5

这已经在这里间接解决。这是一个基于此的简单解决方案:

data$mycol <- coalesce(data$x, data$y)

将答案扩展到任意数量的列,并使用我发现的整洁的max.col()函数,这要归功于这个问题:

coalesce <- function(value_matrix) {
value_matrix <- as.matrix(value_matrix)
first_non_missing <- max.col(!is.na(value_matrix), ties.method = "first")
indices <- cbind(
row = seq_len(nrow(value_matrix)),
col = first_non_missing
)
value_matrix[indices]
}
data$mycol <- coalesce(data[, c('x', 'y')])
data
#   a  x  y mycol
# 1 A  1 NA     1
# 2 B  2 NA     2
# 3 C NA NA    NA
# 4 D NA  4     4
# 5 E NA  5     5

max.col(..., ties.method = "first")为每一行返回具有最大值的第一列的索引。由于我们在逻辑矩阵上使用它,因此最大值通常为TRUE.因此,我们将获得每行的第一个非NA值。如果整行NA,那么我们将根据需要获得一个NA值。

之后,该函数使用行列索引矩阵来子集值。

编辑

与 mrip 的合并相比,当有几根长列时,我的max.col速度较慢,但当有许多短列时,我的速度更快。

coalesce_reduce <- function(...) {
Reduce(function(x, y) {
i <- which(is.na(x))
x[i] <- y[i]
x},
list(...))
}
coalesce_maxcol <- function(...) {
value_matrix <- cbind(...)
first_non_missing <- max.col(!is.na(value_matrix), ties.method = "first")
indices <- cbind(
row = seq_len(nrow(value_matrix)),
col = first_non_missing
)
value_matrix[indices]
}
set.seed(100)
wide <- replicate(
1000,
{sample(c(NA, 1:10), 10, replace = TRUE)},
simplify = FALSE
)
long <- replicate(
10,
{sample(c(NA, 1:10), 1000, replace = TRUE)},
simplify = FALSE
)
microbenchmark(
do.call(coalesce_reduce, wide),
do.call(coalesce_maxcol, wide),
do.call(coalesce_reduce, long),
do.call(coalesce_maxcol, long)
)
# Unit: microseconds
#                           expr      min        lq       mean   median       uq      max neval
# do.call(coalesce_reduce, wide) 1879.460 1953.5695 2136.09954 2007.303 2152.654 5284.583   100
# do.call(coalesce_maxcol, wide)  403.604  423.5280  490.40797  433.641  456.583 2543.580   100
# do.call(coalesce_reduce, long)   36.829   41.5085   45.75875   43.471   46.942   79.393   100
# do.call(coalesce_maxcol, long)   80.903   88.1475  175.79337   92.374  101.581 3438.329   100

最新更新