R Mutando várias colunas com correspondência

Sep 07 2020

Estou processando um grande conjunto de dados adaptado à minha pesquisa. Suponha que eu tenha 4 observações (registros) e 5 colunas como segue:

x <- data.frame("ID" = c(1, 2, 3, 4),
                "group1" = c("A", NA, "B", NA), 
                "group2" = c("B", "A", NA, "C"),
                "hours1" = c(3, NA, 5, NA),
                "hours2" = c(1, 2, NA, 5))

> x
ID group1 group2 hours1 hours2
 1      A      B      3      1
 2   <NA>      A     NA      2
 3      B   <NA>      5     NA
 4   <NA>      C     NA      5

O "grupo1" e o "grupo2" são colunas de referência contendo os valores dos caracteres A, B e C, e as duas últimas colunas, "horas1" e "horas2", são numéricas indicando horas, obviamente.

A coluna "grupo1" corresponde à coluna "horas1"; da mesma forma, "grupo2" corresponde às "horas 2".

Quero criar várias colunas de acordo com os valores A, B e C das colunas de referência correspondentes aos valores de "horas1" e "horas2" da seguinte maneira:

ID group1 group2 hours1 hours2  A  B  C
 1      A      B      3      1  3  1 NA
 2   <NA>      A     NA      2  2 NA NA
 3      B   <NA>      5     NA NA  5 NA
 4   <NA>      C     NA      5 NA NA  5

Por exemplo, ID 1 tem A em "grupo1", correspondendo a 3 em "horas1", que se encontra na coluna "A". ID 3 tem B no "grupo1", correspondendo a 5 em "horas1", que se encontra nas colunas "B". No "grupo 2", ID 4 tem C, correspondendo a 5 em horas2, que se encontra na coluna "C".

Existe uma maneira de fazer isso usando R?

Respostas

2 RonakShah Sep 07 2020 at 08:01

Uma maneira seria combinar todas as colunas "hora" em uma coluna e as colunas "grupo" em outra coluna. Isso pode ser feito usando pivot_longer. Depois disso, podemos obter dados em formato amplo e juntá-los aos dados originais.

library(dplyr)
library(tidyr)

x %>%
  pivot_longer(cols = -ID, 
               names_to = c('.value'), 
               names_pattern = '(.*?)\\d+', 
               values_drop_na = TRUE) %>%
  pivot_wider(names_from = group, values_from = hours) %>%
  left_join(x, by = 'ID') %>%
  select(ID, starts_with('group'), starts_with('hour'), everything())

# A tibble: 4 x 8
#     ID group1 group2 hours1 hours2     A     B     C
#  <dbl> <chr>  <chr>   <dbl>  <dbl> <dbl> <dbl> <dbl>
#1     1 A      B           3      1     3     1    NA
#2     2 NA     A          NA      2     2    NA    NA
#3     3 B      NA          5     NA    NA     5    NA
#4     4 NA     C          NA      5    NA    NA     5

Para o conjunto de dados do OP, podemos modificar ligeiramente o código para obter o resultado desejado.

zz %>%
  pivot_longer(cols = -id, 
               names_to = c('.value'), 
               names_pattern = '(.*)_', 
               values_drop_na = TRUE) %>%
  arrange(fu2a) %>%
  pivot_wider(names_from = fu2a, values_from = fu2b) %>%
  left_join(zz, by = 'id') %>%
  select(id, starts_with('fu2a'), starts_with('fu2b'), everything())
2 Duck Sep 07 2020 at 08:05

Outra abordagem usando dplyrpoderia ser feita separando variáveis ​​de grupo e horas para calcular as variáveis ​​desejadas e, em seguida, mesclar com o original x:

library(tidyverse)
#Data
x <- data.frame("ID" = c(1, 2, 3, 4),
                "group1" = c("A", NA, "B", NA), 
                "group2" = c("B", "A", NA, "C"),
                "hours1" = c(3, NA, 5, NA),
                "hours2" = c(1, 2, NA, 5),stringsAsFactors = F)
#Reshape
x %>% 
  left_join(x %>% select(1:3) %>%
              pivot_longer(cols = -ID) %>% 
              group_by(ID) %>% mutate(id=1:n()) %>%
              left_join(x %>% select(c(1,4:5)) %>%
                          pivot_longer(cols = -ID) %>%
                          rename(name2=name,value2=value) %>%
                          group_by(ID) %>% mutate(id=1:n())) %>%
              filter(!is.na(value)) %>% select(ID,value,value2) %>%
              pivot_wider(names_from = value,values_from=value2))
 

Resultado:

  ID group1 group2 hours1 hours2  A  B  C
1  1      A      B      3      1  3  1 NA
2  2   <NA>      A     NA      2  2 NA NA
3  3      B   <NA>      5     NA NA  5 NA
4  4   <NA>      C     NA      5 NA NA  5