2017-02-13 3 views
0

Ich habe einige schrecklich schmutzige Daten, die ich wirklich kämpfe, um zu reinigen. Ein Beispiel für das Problem ist unten:tidyr/dplyr - verteilt mehrere Variablen für doppelte IDs

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 

Die gewünschte Ausgabe ist so etwas wie diese:

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 

Mit dem Verständnis, dass es eine beliebige Erweiterung der EMAIL und PHN Variablen sein kann (dh es könnte n Wiederholungen von ID sein, die unterschiedlichen (oder NA) Werte haben)

Meine Lösung so weit.

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

Aber das erzeugt eine noch malformed 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 

Hilfe? Ich vermute, dass mein Problem etwas mit dem Befehl spread() zu tun hat, aber meine bisherigen Versuche haben sich als ziemlich fruchtlos erwiesen. Vielen Dank.

+0

Was passiert, wenn Sie die Mutanten herausnehmen? –

+0

@RyanMorton: wenn ich ersetzen Sie den Code mit: '' 'df.test <- df %>% group_by (ID)%>% Spread (ID, E-Mail)%>% Spread (ID, PHN)' '' Ich bekomme Fehler: Doppelte Bezeichner für Zeilen (4,5) –

+0

Hm, könnten Sie NAME zum group_by hinzufügen? –

Antwort

2

Sie müssen summarize nicht mutate, dann verwenden Sie separate, um die Ergebnisse zu teilen. Um dies dynamisch durchzuführen, können Sie die Anzahl der unterschiedlichen E-Mail- und Telefongruppen festlegen, die Sie im Voraus verwenden möchten. Verwenden Sie dazu separate_ und setzen Sie dann fill = right, um die Warnungen zu entfernen. Die letzten beiden mutate Anweisungen sind da, um NA Werte in Strings zu bereinigen.

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> 

Die Warnungen werden

+0

) Das wirft Ihnen viele Fehler? Die Ausgabe ist korrekt, aber ich erhielt Diese Liste von Fehlern bei der Ausführung: '' 'Warnmeldungen: 1: Zu viele Werte an 1 Stellen: 3 2: Zu wenige Werte an 2 Stellen: 2, 4 3: Zu viele Werte an 1 Stellen: 3 4: Zu wenige Werte an 2 Stellen: 2, 4 '' ' –

+0

Sie erhalten Warnungen, keine Fehler.Die Warnungen beziehen sich auf die zusätzlichen Elemente, die von einigen Kombinationen erzeugt werden, die größer als die Anzahl der geteilten Spalten sind 'und schaue auf meine Notiz in Bezug auf' separate_' –

+0

Aha! Es funktioniert auf meine nicht-Beispiel-Daten. Danke! –

0

1) umformen Mit Base R geworfen werden kann dies in 3 Zeilen durchgeführt werden. Die erste Codezeile fügt für jede ID eine Sequenznummer hinzu, und die letzte führt die Transformation von lang nach breit durch. Die zweite Codezeile formt den Datenrahmen von lang nach breit um und die letzte Codezeile entfernt Spalten, die nur NAs enthalten. (Falls Spalten von NAs unwahrscheinlich sind oder es Ihnen nichts ausmacht sie nicht dann die dritte Zeile des Codes weggelassen werden könnte.)

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)) 

geben:

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 den gleichen Code außer gebildet in könnte eine magrittr Pipeline geschrieben werden:

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)) 

Hinweis: Der Eingang df.test in reproduzierbarer Form ist:

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) 
Verwandte Themen