我想根据其他列中NA的数量删除列a具有重复值的行。与此类似,但是我无法获得计算在内的NA来解决那里的解决方案。
Deleting rows that are duplicated in one column based on the conditions of another column
这是我的玩具数据集:
df1 <- data.frame(a = c("x","y","y","z","x", "z"), b = c(1,2,NA,4,8,3), c = c(NA,2,2,NA,NA,4), d= c(1:4,NA,NA))
给出:
a b c d
1 x 1 NA 1
2 y 2 2 2
3 y NA 2 3
4 z 4 NA 4
5 x 8 NA NA
6 z 3 4 NA
我只想在a列中保留具有唯一值的行,而在cols b和c中仅保留NA数量最少的行(忽略d列中的NA)
这是我想出的代码:
df1 %>%
mutate(NAs= apply(is.na(cbind(b,c)), 1, sum)) %>%
group_by(a) %>%
top_n(n=1, -NAs)
我的问题是,如果有平局,top_n返回的行多。如果是平局,我只希望返回第一行。比起cbind,还有一种更好的方法来选择mutate中的列。我也不需要使用mutate创建的“ NAs”变量。我想要的输出是这样:
a b c d
x 1 NA 1
y 2 2 2
z 3 4 NA
答案 0 :(得分:3)
@markus建议这也可以作为答案。也许是对的,因为在dplyr
的情况下,使代码简短可能会有所帮助,否则,您通常可能会得到非常冗长的脚本。
但是,我认为的主要部分是rowSums
,因为它已经被突出显示了。
df1 %>%
arrange(a, rowSums(is.na(.[, c("b", "c")]))) %>%
distinct(a, .keep_all = TRUE)
a b c d
1 x 1 NA 1
2 y 2 2 2
3 z 3 4 NA
P.S。如果您关心速度,那么实际上我会尝试使用尽可能少的dplyr
动词,例如仅使用arrange
和distinct
的方法比使用group
,slice
,top_n
,filter
等的其他方法快3倍。>
答案 1 :(得分:2)
这是一个选择
library(dplyr)
df1 %>%
mutate(NAs = rowSums(is.na(.[, c("b", "c")]))) %>%
group_by(a) %>%
top_n(n = 1, -NAs) %>%
slice(1) %>%
select(-NAs)
# A tibble: 3 x 4
# Groups: a [3]
# a b c d
# <fct> <dbl> <dbl> <int>
#1 x 1 NA 1
#2 y 2 2 2
#3 z 3 4 NA
rowSums
是apply(..., 1, sum)
的更有效替代。
您也可以尝试data.table
。下面的解决方案应该非常快(但可读性可能较低)。
library(data.table)
setDT(df1)
df1[df1[order(a, df1[, rowSums(is.na(.SD)), .SDcols = c("b", "c")]), .I[1], by = "a"]$V1]
# a b c d
#1: x 1 NA 1
#2: y 2 2 2
#3: z 3 4 NA
答案 2 :(得分:1)
一个稍微不同的dplyr
选项:
df1 %>%
mutate(miss = rowSums(is.na(cbind(b,c)))) %>%
group_by(a) %>%
filter(miss == min(miss)) %>%
slice(1) %>%
select(-miss) %>%
ungroup()
或者:
df1 %>%
mutate(miss = rowSums(is.na(cbind(b,c)))) %>%
group_by(a) %>%
mutate(dupl = seq_along(a)) %>%
filter(miss == min(miss)) %>%
filter(dupl == min(dupl)) %>%
select(-miss, -dupl) %>%
ungroup()