Заменить все нулевые столбцы с NA - PullRequest
3 голосов
/ 24 июня 2019

У меня есть следующий фрейм данных в 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))

Это полностью преобразует А1 и B1 в значения NA.

Я прошу некоторую помощь здесь.

Ответы [ 2 ]

3 голосов
/ 24 июня 2019

Мы можем 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 заключалась в том, что в case_when не определено ни одного случая TRUE, поэтому, если не найдено ни одного условия, по умолчанию возвращается 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 голос
/ 24 июня 2019

С 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)])
...