我试图在R中通过检查每个值是否存在于一个特定的列表中,如果存在,则保留它,来子集一个数据框。例如在下面的数据框中,我怎样才能将它子集为只包含1、3和4这三个值呢?
x <- data.frame(A = sample(1:5, 5),
B = sample(1:5, 5),
C = sample(1:5, 5))
A B C
1 2 2 1
2 3 3 3
3 1 4 4
4 4 5 2
5 5 1 5
我怎样才能将它子集到只包含1,3和4这三个值,结果如下:
A B C
1 1
2 3 3 3
3 4 4
4 4
5 1
缺少的值如何处理并不重要 - 如果这样更容易的话,可以将它们改为NA。从浏览类似的问题来看,似乎lapply可能会做到这一点,但作为一个新手,我很难将我所看到的应用到这个场景中。
set.seed(47)
x <- data.frame(A = sample(1:5, 5),
B = sample(1:5, 5),
C = sample(1:5, 5))
# with lapply
keep_vals = c(1, 3, 4)
x[] = lapply(x, function(y) {
y[! y %in% keep_vals] = NA
return(y)
})
x
# A B C
# 1 3 1 1
# 2 1 NA NA
# 3 NA NA 4
# 4 4 3 NA
# 5 NA 4 3
或者用for循环。
set.seed(47) # reset data
x <- data.frame(A = sample(1:5, 5),
B = sample(1:5, 5),
C = sample(1:5, 5))
keep_vals = c(1, 3, 4)
for (i in 1:ncol(x)) {
x[, i][!x[, i] %in% keep_vals] <- NA
}
x
# A B C
# 1 3 1 1
# 2 1 NA NA
# 3 NA NA 4
# 4 4 3 NA
# 5 NA 4 3
循环: dplyr
x %>% mutate_all(
~replace(., !. %in% keep_vals, NA)
)
# A B C
# 1 3 1 1
# 2 1 NA NA
# 3 NA NA 4
# 4 4 3 NA
# 5 NA 4 3
使用 dplyr::bind_rows
do.call(bind_rows,apply(x,1, function(a) a[a %in% c(1,3,4)]))
# A tibble: 5 x 3
A B C
<int> <int> <int>
1 4 NA NA
2 1 1 1
3 3 3 NA
4 NA NA 4
5 NA 4 3
将每一行折叠成匹配的数字,并调整每个 length
到 ncol
. 假设你想 "左对齐 "你的数字,如你的预期输出所示。
d <- setNames(as.data.frame(t(apply(d, 1, function(x) {
x <- x[x %in% c(1, 3, 4)]
`length<-`(x, ncol(d))
}))), names(d))
d
# A B C
# 1 1 NA NA
# 2 3 3 3
# 3 1 4 4
# 4 4 NA NA
# 5 NA NA NA
由于 apply
抛出一个矩阵,我们告诉R,我们要的是矩阵的 t
姿势 as.data.frame
和 setNames
来恢复这些。
注意: 我修改了你的示例数据的第5行,使其不包含任何匹配的数字,这样就不会太容易。
数据
d <- read.table(text="A B C
1 2 2 1
2 3 3 3
3 1 4 4
4 4 5 2
5 5 2 5", header=TRUE)