2017-02-13 12 views
0

У меня есть ужасно грязные данные, которые я действительно пытаюсь очистить. Пример вопроса ниже:tidyr/dplyr - распространение нескольких переменных для повторяющихся идентификаторов

ID NAME ADDRESS    EMAIL  PHN 
1 Alice 123 Street  [email protected] 5555555 
1 Alice 123 Street    <NA> 4444444 
2  Bob 9 Circle  [email protected] 1111111 
3 Charlie  4 Ave [email protected] 3333333 
3 Charlie  4 Ave [email protected] 3333333 
3 Charlie  4 Ave    <NA>  NA 
4 Doug 1 Court    <NA> 6666666 

Нужный выход что-то вроде этого:

ID NAME ADDRESS   EMAIL_1    EMAIL_2 PHN_1 PHN_2 
1 Alice 123 Street [email protected]    <NA> 5555555 4444444 
2  Bob 9 Circle  [email protected]    <NA> 1111111  NA 
3 Charlie  4 Ave [email protected] [email protected] 3333333  NA 
4 Doug 1 Court    <NA>    <NA> 6666666  NA 

С пониманием того, что может быть произвольное расширение переменных EMAIL и PHN (то есть, может быть п повторений ID, которые имеют разные (или NA) значения)

Мое решение до сих пор:.

df.test <- df %>% 
    group_by(ID) %>% 
    mutate(EMAILID = paste0("EMAIL_",row_number())) %>% 
    spread(EMAILID,EMAIL) %>% 
    mutate(PHONEID = paste0('PHN_',row_number())) %>% 
    spread(PHONEID,PHN) 

Но это приводит к еще более искаженный data.frame:

ID NAME ADDRESS   EMAIL_1    EMAIL_2 EMAIL_3 PHN_1 PHN_2 PHN_3 
1 Alice 123 Street [email protected]    <NA> <NA> 5555555  NA NA 
1 Alice 123 Street    <NA>    <NA> <NA>  NA 4444444 NA 
2  Bob 9 Circle  [email protected]    <NA> <NA> 1111111  NA NA 
3 Charlie  4 Ave [email protected]    <NA> <NA> 3333333  NA NA 
3 Charlie  4 Ave    <NA> [email protected] <NA>  NA 3333333 NA 
3 Charlie  4 Ave    <NA>    <NA> <NA>  NA  NA NA 
4 Doug 1 Court    <NA>    <NA> <NA> 6666666  NA NA 

Любая помощь? Я подозреваю, что моя проблема связана с командой spread(), но мои попытки до сих пор оказались бесплодными. Благодарю.

+0

Что произойдет, если вы выберете мутации? –

+0

@RyanMorton: если заменить код: '' 'df.test <- df %>% group_by (ID)%>% спрэд (ID, EMAIL)%>% спрэд (ID, НЗП)' '' Я получаю сообщение об ошибке: Дублирующие идентификаторы для строк (4,5) –

+0

Хм, не могли бы вы добавить NAME в group_by? –

ответ

2

Необходимо, чтобы summarize не mutate, а затем используйте separate, чтобы разбить результаты. Чтобы сделать это динамически, вы можете определить количество различных групп электронной почты и телефонов для использования досрочно, используйте separate_, а затем установите fill = right, чтобы удалить предупреждения. Последние два заявления mutate предназначены для очистки NA значений, преобразованных в строки.

library(dplyr) 
library(tidyr) 

cols <- cols <- df %>% 
    group_by(ID) %>% 
    filter(!is.na(PHN), !is.na(EMAIL)) %>% 
    group_size() %>% 
    max() 

df %>% 
    group_by(ID, NAME, ADDRESS) %>% 
    summarize_each(funs(toString(unique(.[!is.na(.)]))), EMAIL, PHN) %>% 
    separate_("EMAIL", sprintf("EMAIL%s", 1:cols), sep = ",", fill = "right") %>% 
    separate_("PHN", sprintf("PHN%s", 1:cols), sep = ",", fill = "right") %>% 
    mutate_if(is.character, trimws) %>% 
    mutate_each(funs(replace(., grep("NA", .), NA))) 

    Source: local data frame [4 x 7] 
Groups: ID, NAME [4] 

    ID NAME ADDRESS   EMAIL1    EMAIL2 PHN1 PHN2 
    <int> <fctr>  <fctr>    <chr>    <chr> <chr> <chr> 
1  1 Alice 123 Street [email protected]    <NA> 5555555 4444444 
2  2  Bob 9 Circle  [email protected]    <NA> 1111111 <NA> 
3  3 Charlie  4 Ave [email protected] [email protected] 3333333 <NA> 
4  4 Doug 1 Court    <NA>    <NA> 6666666 <NA> 

Предупреждения будут выброшены

+0

Делает ли это многочисленные ошибки для вас? Результат правильный, но я получил этот список ошибок при запуске: '' 'Предупреждающие сообщения: 1: Слишком много значений в 1 месте: 3 2: Слишком мало значений в двух местах: 2, 4 3: Слишком много значений в 1 месте: 3 4: Слишком мало значений в 2-х местах: 2, 4 '' ' –

+0

Вы получите предупреждения, а не ошибки. Предупреждения ссылаются на дополнительные элементы, созданные в результате некоторых комбинаций, превышающих количество разделенных столбцов. 'и посмотрите на мою заметку относительно' separate_' –

+0

Aha! Он работает с моими не-примерными данными. Спасибо! –

0

1) перекроить Использование базового R это может быть сделано в 3-х линий. Первая строка кода добавляет порядковый номер для каждого ID, а последний выполняет преобразование от длинного к широкому. Вторая строка кода преобразует кадр данных с длинного на широкий, а последняя строка кода удаляет столбцы, содержащие только НС. (Если столбцы НСБУ маловероятно, или вы не против них, то третья строка кода может быть опущен.)

df2 <- transform(df.test, seq = ave(ID, ID, FUN = seq_along)) 
df2 <- reshape(df2, dir = "wide", timevar = "seq", idvar = c("ID", "NAME", "ADDRESS")) 
subset(df2, select = !apply(is.na(df.test2), 2, all)) 

дает:

ID NAME ADDRESS   EMAIL.1 PHN.1    EMAIL.2 PHN.2 
1 1 Alice 123 Street [email protected] 5555555    <NA> 4444444 
3 2  Bob 9 Circle  [email protected] 1111111    <NA>  NA 
4 3 Charlie  4 Ave [email protected] 3333333 [email protected] 3333333 
7 4 Doug 1 Court    <NA> 6666666    <NA>  NA 

2) magrittr Тот же код, за исключением формуют в magrittr трубопровод может быть записано:

library(magrittr) 

df.test %>% 
    transform(seq = ave(ID, ID, FUN = seq_along)) %>% 
    reshape(dir = "wide", timevar = "seq", idvar = c("ID", "NAME", "ADDRESS")) %>% 
    subset(select = !apply(is.na(.), 2, all)) 

Примечание: входной df.test в воспроизводимой форме:

Lines <- " 
ID,NAME,ADDRESS,EMAIL,PHN 
1,Alice,123 Street,[email protected],5555555 
1,Alice,123 Street,NA,4444444 
2,Bob,9 Circle,[email protected],1111111 
3,Charlie,4 Ave,[email protected],3333333 
3,Charlie,4 Ave,[email protected],3333333 
3,Charlie,4 Ave,NA, 
4,Doug,1 Court,NA,6666666" 
df.test <- read.csv(text=Lines)