Сбор или pivot_longer для нескольких столбцов?

#r

#r

Вопрос:

Это данные, которые у меня есть:

 id<-c(1:7)
emp1<-c('ft','ft','pt','pt','ft','no','no')
emp2<-c('ft','ft','ft','ft','no','pt','ft')
marstat1<-c('married','married','divorced','single','single','single','single')
marstat2<-c('divorced','married','divorced','single','single','married','single')
df<-data.frame(id,emp1,emp2,marstat1,marstat2) 
  

Я хочу изменить (от широкого до длинного) его в

 id<-c(1,1,2,2,3,3,4,4,5,5,6,6,7,7)
year<-c(rep(1:2,7))
emp<-c('ft','ft','ft','ft','pt','ft','pt','ft','ft','no','no','pt','no','ft')
marstat<-c('married','divorced','married','married','divorced','divorced','single','single','single','single','single','married','single','single')
df2<-data.frame(id,year,emp,marstat)
  

Я пытался использовать dplyr::gather, но он дает мне 4 строки каждого идентификатора вместо 2. И мне непонятно, что делать с измерением года (мне не нужны два столбца года, только один)

 df2<-df %>% 
  gather(key='year',value='emp',emp1,emp2) %>% 
  gather(key='year2',value='marstat',marstat1,marstat2)
  

Ответ №1:

Рассмотрим этот подход

 df %>% 
  pivot_longer(matches("\d$"), names_to = c("name", "year"), names_pattern = "([^\d] )(\d )$") %>% 
  pivot_wider()
  

Сначала преобразуйте фрейм данных в один, содержащий только три столбца id , nameyear , и value ; одновременно разделите второй столбец nameyear на name и year . Затем просто поверните два столбца name и value шире.

Вывод

 # A tibble: 14 x 4
      id year  emp   marstat 
   <int> <chr> <chr> <chr>   
 1     1 1     ft    married 
 2     1 2     ft    divorced
 3     2 1     ft    married 
 4     2 2     ft    married 
 5     3 1     pt    divorced
 6     3 2     ft    divorced
 7     4 1     pt    single  
 8     4 2     ft    single  
 9     5 1     ft    single  
10     5 2     no    single  
11     6 1     no    single  
12     6 2     pt    married 
13     7 1     no    single  
14     7 2     ft    single
  

Комментарии:

1. Красиво! Я собираюсь записать это. Очень полезно! Спасибо!

2. Спасибо. Это сработало! Я не понимаю эти части: «\ d $», «([^ \ d] ) (\ d ) $») … но я предполагаю, что это базовая грамматика R для поиска числовых или символьных строк?

3. Нет, это регулярные выражения. Смотрите Это для получения дополнительной информации. @kna123

Ответ №2:

Может быть, это может быть полезно для вас:

 library(tidyverse)
#Code
newdf <- df %>% select(c('id',starts_with('emp'))) %>%
  pivot_longer(-id) %>%
  mutate(name=gsub('emp','',name)) %>%
  rename(emp=value,year=name) %>%
  left_join(
    df %>% select(c('id',starts_with('marstat'))) %>%
      pivot_longer(-id) %>%
      mutate(name=gsub('marstat','',name)) %>%
      rename(marstat=value,year=name)
  )
  

Вывод:

 # A tibble: 14 x 4
      id year  emp   marstat 
   <int> <chr> <fct> <fct>   
 1     1 1     ft    married 
 2     1 2     ft    divorced
 3     2 1     ft    married 
 4     2 2     ft    married 
 5     3 1     pt    divorced
 6     3 2     ft    divorced
 7     4 1     pt    single  
 8     4 2     ft    single  
 9     5 1     ft    single  
10     5 2     no    single  
11     6 1     no    single  
12     6 2     pt    married 
13     7 1     no    single  
14     7 2     ft    single  
  

Ответ №3:

Не самое элегантное решение, но это сработало бы:

 pivot_longer(df, cols=starts_with("marstat"), names_to="year", names_prefix="marstat", values_to="marstat") %>% 
pivot_longer(cols=starts_with("emp"), names_to="empyear", names_prefix="emp", values_to="emp") %>% 
filter(year==empyear) %>% 
select(-empyear)
  

Это приводит к двум последовательным сводкам, за которыми следует удаление строк, в которых номер года не совпадает, и, наконец, удаление лишнего столбца year. Обратите внимание, что «names_prefix» позволяет удалить текстовую часть marstat1 / 2 и emp1 / 2, но в итоге вы все равно получите chr вектор, который вам нужно будет преобразовать в целое число, если вам это нужно.

Дать вам это:

 A tibble: 14 x 4
      id year  marstat  emp  
   <int> <chr> <fct>    <fct>

 1     1 1     married  ft   
 2     1 2     divorced ft   
 3     2 1     married  ft   
 4     2 2     married  ft   
 5     3 1     divorced pt   
 6     3 2     divorced ft   
 7     4 1     single   pt   
 8     4 2     single   ft   
 9     5 1     single   ft   
10     5 2     single   no   
11     6 1     single   no   
12     6 2     married  pt   
13     7 1     single   no   
14     7 2     single   ft