Аккуратные данные: переименуйте столбцы, получите имена столбцов, не относящиеся к Северной Америке, а затем соберите

У меня есть довольно уродливые данные, которые нужно привести в порядок, и мне нужна помощь! Как сейчас выглядят мои данные:

countries <- c("Austria", "Belgium", "Croatia")

df <- tibble("age" = c(28,42,19, 67),
         "1_recreate_1"=c(NA,15,NA,NA), 
         "1_recreate_2"=c(NA,10,NA,NA), 
         "1_recreate_3"=c(NA,8,NA,NA),
         "1_recreate_4"=c(NA,4,NA,NA),
         "1_fairness" = c(NA, 7, NA, NA),
         "1_confidence" = c(NA, 5, NA, NA),
         "2_recreate_1"=c(29,NA,NA,30),
         "2_recreate_2"=c(20,NA,NA,24),
         "2_recreate_3"=c(15,NA,NA,15),
         "2_recreate_4"=c(11,NA,NA,9),
         "2_fairness" = c(4, NA, NA, 1),
         "2_confidence" = c(5, NA, NA, 4),
         "3_recreate_1"=c(NA,NA,50,NA), 
         "3_recreate_2"=c(NA,NA,40,NA), 
         "3_recreate_3"=c(NA,NA,30,NA),
         "3_recreate_4"=c(NA,NA,20,NA),
         "3_fairness" = c(NA,  NA, 2, NA),
         "3_confidence" = c(NA, NA, 2, NA),
         "overall" = c(3,3,2,5))    

Как мне нужно, чтобы они выглядели в конце (жестко кодируя):

df <- tibble(age = rep(c(28,42,19,67), each=4),
         country = rep(c("Belgium", "Austria", "Croatia", "Belgium"), each=4),
         recreate = rep(1:4, times=4),
         fairness = rep(c(4,7,2,1), each=4),
         confidence = rep(c(5,5,2,4), each=4),     
         allocation = c(29, 20, 15, 11,
                        15, 10, 8, 4,
                        50, 40, 30, 20, 
                        30, 24, 15, 9),
         overall = rep(c(3,3,2,5), each=4))

Шаги, чтобы добраться туда (я думаю!):

<сильный>1. Замените начальные числа для этих столбцов, используя мой список стран.
Число, с которого начинается строка, является индексом в countries. Другими словами, 16_recreate_1 будет соответствовать 16-й стране в векторе countries. Я думаю, что следующий код работает (хотя я не уверен, что это точно):

for(i in length(countries):1){
    colnames(df) <- str_replace(colnames(df), paste0(i,"_"), paste0(countries[i],"_"))
}  

<сильный>2. Создайте новую переменную с именем "страна", получив имя столбца (столбцов), которое НЕ является НПД для каждой строки.

Я перепробовал МНОГО экспериментов с which.max и names, но не смог заставить его работать полностью.

<сильный>3. Создайте новые переменные (recreate_1...recreate_4), которые получают значение [country_name]_recreate_1...[country_name]_recreate_4 для каждой строки, независимо от страны, не относящейся к NA для этого человека.

Может быть, rowSums это способ сделать это?

<сильный>4. Сделайте данные длинными, а не широкими Я думаю, что для этого потребуется gather, но я не уверен, как собрать данные только из переменных country и recreate_1...recreate_4.

Мне очень жаль, что это так сложно. Предпочтение отдается решениям Tidyverse, но мы очень ценим любую помощь!


person wscampbell    schedule 17.03.2019    source источник
comment
Упс! Извините за это - обновлено.   -  person wscampbell    schedule 17.03.2019


Ответы (2)


Несколько иная tidyverse возможность может заключаться в следующем:

df %>%
 gather(variable, allocation, na.rm = TRUE) %>%
 separate(variable, c("ID", "variable", "recreate"), convert = TRUE) %>%
 left_join(data.frame(countries) %>%
            mutate(country = countries,
                   ID = seq_along(countries)) %>%
            select(-countries), by = c("ID" = "ID")) %>%
 select(-variable, -ID) 

   recreate allocation country
      <int>      <dbl> <fct>  
 1        1         15 Austria
 2        2         10 Austria
 3        3          8 Austria
 4        4          4 Austria
 5        1         29 Belgium
 6        1         30 Belgium
 7        2         20 Belgium
 8        2         24 Belgium
 9        3         15 Belgium
10        3         15 Belgium
11        4         11 Belgium
12        4          9 Belgium
13        1         50 Croatia
14        2         40 Croatia
15        3         30 Croatia
16        4         20 Croatia

Здесь он, во-первых, преобразует данные из широкого формата в длинный, удаляя строки с NA. Во-вторых, он разделяет имена переменных на три столбца. В-третьих, он преобразует вектор стран в df и присваивает каждой стране уникальный идентификатор. Наконец, он объединяет их и удаляет избыточные переменные.

Решение отредактированного вопроса:

df %>%
 select(matches("(recreate)")) %>%
 rowid_to_column() %>%
 gather(var, allocation, -rowid, na.rm = TRUE) %>%
 separate(var, c("ID", "var", "recreate"), convert = TRUE) %>%
 select(-var) %>%
 left_join(data.frame(countries) %>%
            mutate(country = countries,
                   ID = seq_along(countries)) %>%
            select(-countries), by = c("ID" = "ID")) %>% 
 left_join(df %>%
            select(-matches("(recreate)")) %>%
            rowid_to_column() %>%
            gather(var, val, -rowid, na.rm = TRUE) %>%
            mutate(var = gsub("[^[:alpha:]]", "", var)) %>%
            spread(var, val), by = c("rowid" = "rowid")) %>%
 select(-rowid, -ID)

   recreate allocation country   age confidence fairness overall
      <int>      <dbl> <fct>   <dbl>      <dbl>    <dbl>   <dbl>
 1        1         15 Austria    42          5        7       3
 2        2         10 Austria    42          5        7       3
 3        3          8 Austria    42          5        7       3
 4        4          4 Austria    42          5        7       3
 5        1         29 Belgium    28          5        4       3
 6        1         30 Belgium    67          4        1       5
 7        2         20 Belgium    28          5        4       3
 8        2         24 Belgium    67          4        1       5
 9        3         15 Belgium    28          5        4       3
10        3         15 Belgium    67          4        1       5
11        4         11 Belgium    28          5        4       3
12        4          9 Belgium    67          4        1       5
13        1         50 Croatia    19          2        2       2
14        2         40 Croatia    19          2        2       2
15        3         30 Croatia    19          2        2       2
16        4         20 Croatia    19          2        2       2

Здесь он сначала выбирает столбцы, содержащие recreate, и добавляет столбцы с идентификатором строки. Во-вторых, он следует шагам исходного решения. В-третьих, он выбирает столбцы, не содержащие recreate, выполняет преобразование широких данных в длинные, удаляет число из имен столбцов и преобразует данные обратно в исходный широкий формат. Наконец, он объединяет два идентификатора строки и удаляет избыточные переменные.

person tmfmnk    schedule 17.03.2019

library(dplyr)
library(tidyr)
df %>% mutate(rid=row_number()) %>% 
       gather(key,val,-c(age,overall,rid, matches('recreate'))) %>% mutate(country=sub('(^\\d)_.*','\\1',key),country=countries[as.numeric(country)]) %>% 
       filter(!is.na(val)) %>% mutate(key=sub('(^\\d\\_)(.*)','\\2',key)) %>%
       spread(key,val) %>% gather(key = recreate,value = allocation,-c(rid,age,overall,Country,confidence,fairness)) %>% 
       filter(!is.na(allocation)) %>% mutate(recreate=sub('.*_(\\d$)','\\1',recreate))

Здесь (^\\d)_.* означает получение первой цифры, а .*_(\\d$) означает получение последней цифры.

person A. Suliman    schedule 17.03.2019
comment
Это возмутительно впечатляет - НАСТОЛЬКО эффективно. Спасибо, Сулиман! - person wscampbell; 17.03.2019
comment
2 вопроса: 1. У меня есть около дюжины переменных (например, name, age и т. д.) до и еще дюжина после списка 1_recreate_1... переменных, которые выбрасываются с помощью этого кода. Как сохранить их в новых данных gathered? 2. У меня также есть переменные с именами 1_confidence и 1_fairness, которые я хочу сделать так же, как и для 1_recreate_1, но они не заканчиваются на _#. Как я могу их получить (чтобы создать новую переменную с именами confidence и fairness)? Я исключил оба из своего первоначального вопроса, думая, что разберусь, но я теряюсь в sub и регулярном выражении. Я редактировал оригинал. - person wscampbell; 17.03.2019