我在R中有以下数据框
library(dplyr)
library(tidyr)
df= data.frame("ID"= c("A", "A", "A", "A", "B", "B", "B"),
"A1"= c(0,0, 0, 0, 1,0,1), "B1"= c(1,0, 1,0, 0, 0, 0))
数据框显示如下
ID A1 B1
1 A 0 1
2 A 0 0
3 A 0 1
4 A 0 0
5 B 1 0
6 B 0 0
7 B 1 0
我想获得以下数据框
ID A1 B1
1 A NA 1
2 A NA 0
3 A NA 1
4 A NA 0
5 B 1 NA
6 B 0 NA
7 B 1 NA
我尝试了以下代码
df%>%group_by(ID)%>%
mutate(A1=case_when(sum(A1)==0~NA))%>%
mutate(B1=case_when(sum(B1)==0~NA))
这会将A1和B1完全转换为NA值。
我在这里寻求帮助。
答案 0 :(得分:3)
我们可以group_by
ID
并将mutate_all
与replace
一起使用
library(dplyr)
df %>%
group_by(ID) %>%
mutate_all(~replace(., all(. == 0), NA))
# ID A1 B1
# <fct> <dbl> <dbl>
#1 A NA 1
#2 A NA 0
#3 A NA 1
#4 A NA 0
#5 B 1 NA
#6 B 0 NA
#7 B 1 NA
如果还有其他列,我们只想将其应用于特定列,则可以使用mutate_at
df %>%
group_by(ID) %>%
mutate_at(vars(A1,B1), ~replace(., all(. == 0), NA))
使用case_when
,我们可以这样做
df %>%
group_by(ID) %>%
mutate_all(~case_when(all(. == 0) ~ NA_real_, TRUE ~ .))
OP尝试中的问题是TRUE
中没有定义case_when
大小写,因此当没有条件匹配时,默认情况下将返回NA
。来自?case_when
如果没有匹配的情况,则返回NA。
因此,如果我们定义TRUE
的情况,它将按预期工作。另外,我们不应该检查sum(A1)==0
,因为如果列中有负值和正值(如-2,+ 2),它们的总和将为0,从而产生意外结果。
df%>%
group_by(ID) %>%
mutate(A1 = case_when(all(A1 == 0) ~ NA_real_, TRUE ~ A1),
B1 = case_when(all(B1 == 0) ~ NA_real_, TRUE ~ B1))
答案 1 :(得分:1)
有了tidyverse
,我们可以使用if/else
library(tidyverse)
df %>%
group_by(ID) %>%
mutate_all(list(~ if(all(.==0)) NA_integer_ else .))
# ID A1 B1
# <fct> <dbl> <dbl>
#1 A NA 1
#2 A NA 0
#3 A NA 1
#4 A NA 0
#5 B 1 NA
#6 B 0 NA
#7 B 1 NA
或者没有任何if/else
df %>%
group_by(ID) %>%
mutate_all(~ NA^all(!.) * .)
或使用data.table
library(data.table)
setDT(df)[, lapply(.SD, function(x) replace(x, all(x == 0), NA)), ID]
或使用base R
by(df[-1], df$ID, FUN = function(x) x * (NA^ !colSums(!!x))[col(x)])