Заменить несколько столбцов, если в группирующей переменной отсутствуют все наблюдения - PullRequest
0 голосов
/ 16 июня 2020

Я пытаюсь изменить столбцы «a» и «b» , только если в переменной группировки «group» отсутствуют все наблюдения. Попытка решения изменяет группу «синий», в которой отсутствуют все наблюдения. Заранее благодарим за ваше драгоценное время!

Код ниже:

library(tidyverse)

# sample data
a <- c(NA,NA,1,1,NA,1)
b <- c(1,1,NA,NA,1,NA)
c  <- letters[1:6]
group <- c("yellow","yellow","black","black", "blue", "blue")

(data <- as_tibble(data.frame(a,b,c,group)))

# a     b c     group 
# <dbl> <dbl> <fct> <fct> 
# 1    NA     1 a     yellow
# 2    NA     1 b     yellow
# 3     1    NA c     black 
# 4     1    NA d     black 
# 5    NA     1 e     blue  
# 6     1    NA f     blue 

# failed attempt: observations from group "blue" change 
(data %>% 
  dplyr::group_by(group) %>%
  dplyr::mutate(across(1:2, ~ ifelse(all(is.na(.x)), 99999,.x))))

# a     b c     group 
# <dbl> <dbl> <fct> <fct> 
# 1 99999     1 a     yellow
# 2 99999     1 b     yellow
# 3     1 99999 c     black 
# 4     1 99999 d     black 
# 5    NA     1 e     blue  
# 6    NA     1 f     blue

# desired output - observations from blue remain the same
a2 <- c(99999,99999,1,1,NA,1)
b2 <- c(1,1,99999,99999,1,NA)
c2  <- letters[1:6]
group2 <- c("yellow","yellow","black","black", "blue", "blue")

(data_desired <- as_tibble(data.frame(a2,b2,c2,group2)))

# a2    b2 c2    group2
# <dbl> <dbl> <fct> <fct> 
# 1 99999     1 a     yellow
# 2 99999     1 b     yellow
# 3     1 99999 c     black 
# 4     1 99999 d     black 
# 5    NA     1 e     blue  
# 6     1    NA f     blue

Ответы [ 3 ]

0 голосов
/ 16 июня 2020

Не лучшее решение, но с ним можно справиться ...

data <- data %>% 
  group_by(group) %>% 
  mutate(new = paste0(a, "_", b),
         new1 = if_else(new == lag(new), str_replace(new, "NA", "99999"), new),
         new2 = if_else(new == lead(new), str_replace(new, "NA", "99999"), new)
         ) %>% 
  separate(col = new1, into = c("a_new1", "b_new1"), sep = "_", extra = "drop") %>% 
  separate(col = new2, into = c("a_new2", "b_new2"), sep = "_", extra = "drop") %>% 
  mutate(a2 = if_else(is.na(a_new1), replace_na(a_new2), a_new1),
         b2 = if_else(is.na(b_new1), replace_na(b_new2), b_new1)
         ) %>% 
  select(a, b, c, group, a2, b2) %>% 
  type_convert()

data

# A tibble: 6 x 6
# Groups:   group [3]
      a     b c     group     a2    b2
  <dbl> <dbl> <fct> <fct>  <dbl> <dbl>
1    NA     1 a     yellow 99999     1
2    NA     1 b     yellow 99999     1
3     1    NA c     black      1 99999
4     1    NA d     black      1 99999
5    NA     1 e     blue      NA     1
6     1    NA f     blue       1    NA
0 голосов
/ 18 июня 2020

Спасибо всем за вклад!

Наконец, вот как я решил эту проблему с помощью списков и мурлыканья.

library(tidyverse)
library(purrr)

# sample data
a <- c(NA,NA,1,1,NA,1)
b <- c(1,1,NA,NA,1,NA)
c  <- letters[1:6]
group <- c("yellow","yellow","black","black", "blue", "blue")

(data <- as_tibble(data.frame(a,b,c,group)))

# list with groups in which all cases are NA
list1 <- data %>% 
  split(.,.$group) %>%
  map(~select(.x,as.vector(which(colSums(is.na(.)) == nrow(.))))) %>% 
  map(~mutate_all(.x, replace_na, 99999))  

# list with groups in which there is at least one valid observation
list2 <- data %>%
  split(.,.$group) %>%
  map(~select(.x, as.vector(which(colSums(is.na(.)) != nrow(.))))) 

# putting the groups together into a dataframe
list3 <- mapply(cbind, list1, list2, SIMPLIFY=FALSE)

(desired_output <- do.call(rbind.data.frame, list3))

0 голосов
/ 16 июня 2020

Вы можете попробовать это:

library(tidyverse)

# sample data
a <- c(NA,NA,1,1,NA,1)
b <- c(1,1,NA,NA,1,NA)
c  <- letters[1:6]
group <- c("yellow","yellow","black","black", "blue", "blue")

(data <- as_tibble(data.frame(a,b,c,group)))

(data %>% 
     dplyr::group_by(group) %>%
     dplyr::mutate(across(1:2, ~ ifelse(is.na(.x), 99999,.x))))

# A tibble: 6 x 4
# Groups:   group [3]
      a     b c     group 
  <dbl> <dbl> <fct> <fct> 
1 99999     1 a     yellow
2 99999     1 b     yellow
3     1 99999 c     black 
4     1 99999 d     black 
5 99999     1 e     blue  
6     1 99999 f     blue  
...