我想通过选择数据框中包含的元素不包含NA的列的名称来构建矩阵或数据框。例如,假设我有:
zz <- data.frame(a = c(1, NA, 3, 5),
b = c(NA, 5, 4, NA),
c = c(5, 6, NA, 8))
给出:
a b c
1 1 NA 5
2 NA 5 6
3 3 4 NA
4 5 NA 8
我想识别每个NA并构建一个新的矩阵或df,如下所示:
a c
b c
a b
a c
输入矩阵/ df的每一行中将有相同数量的NA。我似乎无法获得正确的代码来执行此操作。建议赞赏!
答案 0 :(得分:3)
library(dplyr)
library(tidyr)
zz %>%
mutate(k = row_number()) %>%
gather(column, value, a, b, c) %>%
filter(!is.na(value)) %>%
group_by(k) %>%
summarise(temp_var = paste(column, collapse = " ")) %>%
separate(temp_var, into = c("var1", "var2"))
# A tibble: 4 × 3
k var1 var2
* <int> <chr> <chr>
1 1 a c
2 2 b c
3 3 a b
4 4 a c
答案 1 :(得分:3)
这是一种可能的矢量化基础R方法
indx <- which(!is.na(zz), arr.ind = TRUE)
matrix(names(zz)[indx[order(indx[, "row"]), "col"]], ncol = 2, byrow = TRUE)
# [,1] [,2]
#[1,] "a" "c"
#[2,] "b" "c"
#[3,] "a" "b"
#[4,] "a" "c"
这会找到非NA索引,按行排序,然后根据排序索引对zz
数据集的名称进行子集化。如果您喜欢矩阵,可以将其包装到as.data.frame
。
答案 2 :(得分:1)
编辑:在处理前将数据帧转置一次,因此不需要在第一版中循环转置两次。
cols <- names(zz)
for (column in cols) {
zz[[column]] <- ifelse(is.na(zz[[column]]), NA, column)
}
t_zz <- t(zz)
cols <- vector("list", length = ncol(t_zz))
for (i in 1:ncol(t_zz)) {
cols[[i]] <- na.omit(t_zz[, i])
}
new_dt <- as.data.frame(t(do.call("cbind", cols)))
这里棘手的部分是你的目标是实际改变数据框架结构,所以&#34;删除每一行中的NA&#34;必须逐行构建新数据框,因为每行中的每一列都可能来自原始数据框的不同列。
zz[1, ]
是一行数据框,使用t
将其转换为向量,以便我们可以使用na.omit
,然后转置回行。
我使用2 for循环,但for循环在R中不一定是坏的。第一个是为每列进行矢量化。无论如何,第二个需要逐行完成。
编辑:在R中,增长对象的性能非常糟糕。我知道我可以使用rbindlist
中的data.table
来获取数据框列表,但是OP不想要新的包。我的第一次尝试只使用rbind
,它不能将列表作为输入。后来我发现另一种方法是使用do.call
。 It's still slower than rbindlist
though