изменить форму фрейма данных с пропущенными значениями в tidyr

#r #dplyr #tidyverse #tidyr

#r #dplyr #tidyverse #tidyr

Вопрос:

У меня есть фрейм данных, подобный:

 library(tidyverse) 

df_mess <- tibble::tribble(
  ~id, ~value, ~answer_text,
  123,     25,        "age",
  123,     NA,     "female",
  234,     29,        "age",
  234,     NA,       "male",
  345,     14,        "age",
  345,     NA,     "female"
  )
  

Я хотел бы изменить форму таким образом, чтобы иметь «аккуратные» данные, то есть по 1 строке для каждого наблюдения.

 df <- tibble::tribble(
  ~id, ~age,     ~sex,
  123,   25, "female",
  234,   29,   "male",
  345,   14, "female"
  )
  

Я попробовал версию gather / spread , но мне не повезло.

Приветствуется любая зацепка.

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

1. Привет @xxxvinxxx. Я просто хотел проверить и посмотреть, решил ли предоставленный ответ вашу проблему. Если нет, не могли бы вы рассказать нам, почему этого не произошло? Спасибо!

Ответ №1:

Вот решение с распределением и сбором. spread Будут получены все переменные типа age , где имя переменной отображается в столбце answer_text. Если значения переменной находятся в столбце answer_text (например, sex в данном случае), вам нужно будет gather вернуть их обратно, как показано ниже.

Чтобы заставить столбец sex работать, я изменил NAs in value на -99. Однако вы могли бы использовать любое значение. Если вы распространяете без чего-либо в value столбце, это будет отображаться как NA в столбцах female и male , которые создаются на основе распространения.

 df_mess[is.na(df_mess)] <- -99

df_mess %>% 
  spread(answer_text, value) %>% 
  gather(sex, temp, female, male, na.rm = TRUE) %>% 
  select(-temp)
  

вывод

 # A tibble: 3 x 3
     id   age sex   
  <dbl> <dbl> <chr> 
1   123    25 female
2   345    14 female
3   234    29 male 
  

Пример с большим количеством переменных и допустимой NA в size переменной для id 123.

    df_mess <- tibble::tribble(
  ~id, ~value, ~answer_text,
  123,     25,        "age",
  123,     NA,     "female",
  234,     29,        "age",
  234,     NA,       "male",
  345,     14,        "age",
  345,     NA,     "female",
  123,     NA,      "brown",
  234,     NA,     "blonde",
  345,     NA,      "black",
  123,     NA,       "size",
  234,     30,       "size",
  345,     40,       "size",

)
df_mess[is.na(df_mess)] <- -99
df_clean <- df_mess %>% 
  spread(answer_text, value) %>% 
  gather(sex, temp, female, male, na.rm = TRUE) %>% 
  select(-temp) %>% 
  gather(hair, temp, black:brown, na.rm = TRUE) %>% 
  select(-temp)

df_clean[df_clean == -99] <- NA
df_clean
  

вывод

      id   age  size sex    hair  
  <dbl> <dbl> <dbl> <chr>  <chr> 
1   345    14    40 female black 
2   234    29    30 male   blonde
3   123    25    NA female brown
  

Ответ №2:

Если структура ваших данных всегда одинакова, я бы сделал что-то вроде:

 df_mess$new <- lead(df_mess$answer_text)
df_mess <- subset(df_mess,df_mess$value>0)
  

но это возможное решение только для этого конкретного случая.