R Mutando várias colunas com correspondência
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
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())
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