2017-05-25 4 views
3

Angenommen, ich habe mehrere Spalten in einem Datenrahmen, die das gleiche Konzept messen, aber in verschiedenen Methoden (zB gibt es mehrere Arten von IQ-Tests, und Schüler könnten eine haben sie oder gar keine). Ich möchte die verschiedenen Methoden in einer einzigen Spalte kombinieren (offensichtlicher Anwendungsfall für tidyr).tidyr :: versammeln na.rm mit fehlenden Daten

Wenn die Daten so etwas wie diese:

mydata <- data.frame(ID = 55:64, 
       age = c(12, 12, 14, 11, 20, 10, 13, 15, 18, 17), 
       Test1 = c(100, 90, 88, 115, NA, NA, NA, NA, NA, NA), 
       Test2 = c(NA, NA, NA, NA, 100, 120, NA, NA, NA, NA), 
       Test3 = c(NA, NA, NA, NA, NA, NA, 110, NA, 85, 150)) 

ich natürlich so etwas wie dies möchte ausführen (beachten Sie, dass ich na.rm = TRUE, um nicht über die viele, viele NA in meinen Daten verwenden ihre eigenen Reihen erhalten):

library(tidyr) 
tests <- gather(mydata, key=IQSource, value=IQValue, c(Test1, Test2, Test3), na.rm = TRUE) 
tests 

Geben Sie mir:

ID age IQSource IQValue 1 55 12 Test1 100 2 56 12 Test1 90 3 57 14 Test1 88 4 58 11 Test1 115 15 59 20 Test2 100 16 60 10 Test2 120 27 61 13 Test3 110 29 63 18 Test3 85 30 64 17 Test3 150

Das Problem ist, dass ich einen Schüler (ID = 62), die keine IQ-Ergebnisse in einer der drei hat, und ich möchte nicht ihre anderen Daten verlieren (die Daten in der ID und Alter Säulen).

Gibt es eine Möglichkeit zu unterscheiden, in Tidyr, Ja, ich möchte NA entfernen, wo ich Daten in mindestens einer Spalte habe Ich sammle, aber gleichzeitig Datenverlust zu verhindern, wenn alle die Säulen zu sammeln sind NA)

Antwort

1

Wenn die Schüler können jeweils nur einen IQ-Test. ..

library(tidyverse) 

mydata %>% 
    gather(key=IQSource, value=IQValue, Test1:Test3) %>% 
    group_by(ID) %>% 
    arrange(IQValue) %>% 
    slice(1) 
 ID age IQSource IQValue 
1 55 12 Test1  100 
2 56 12 Test1  90 
3 57 14 Test1  88 
4 58 11 Test1  115 
5 59 20 Test2  100 
6 60 10 Test2  120 
7 61 13 Test3  110 
8 62 15 Test1  NA 
9 63 18 Test3  85 
10 64 17 Test3  150 

Wenn die Schüler jeweils mehrere IQ-Tests haben können ...

mydata %>% 
    # Add an ID with multiple IQ tests 
    bind_rows(data.frame(ID=65, age=13, Test1=100, Test2=100, Test3=NA)) %>% 
    gather(key=IQSource, value=IQValue, Test1:Test3) %>% 
    group_by(ID) %>% 
    filter(!is.na(IQValue) | all(is.na(IQValue))) %>% 
    filter(all(!is.na(IQValue)) | !duplicated(IQValue)) %>% 
    arrange(ID, IQSource) 
 ID age IQSource IQValue 
1 55 12 Test1  100 
2 56 12 Test1  90 
3 57 14 Test1  88 
4 58 11 Test1  115 
5 59 20 Test2  100 
6 60 10 Test2  120 
7 61 13 Test3  110 
8 62 15 Test1  NA 
9 63 18 Test3  85 
10 64 17 Test3  150 
11 65 13 Test1  100 
12 65 13 Test2  100 
+0

Ich wählte dies als die richtige Antwort B/C der Einfachheit, Einhaltung der Ordinate und Erweiterung über die ursprüngliche Frage hinaus. Alle gegebenen Antworten waren jedoch großartig und hilfreich! Danke allen! – Joy

1

ich denke, das den Trick für Sie tun?

# make another data frame which has just ID and whether or not they missed all 3 tests 
    missing = mydata %>% 
     mutate(allNA = is.na(Test1) & is.na(Test2) & is.na(Test3)) %>% 
     select(ID, allNA) 

    # Gather and keep NAs 
    tests <- gather(mydata, key=IQSource, value=IQValue, c(Test1, Test2, Test3), na.rm = FALSE) 

    # Keep the rows that have a IQValue or missed all tests 
    tests = left_join(tests, missing) %>% 
     filter(!is.na(IQValue) | allNA) 
    # Remove duplicated rows of individuals who missed all exams 
    tests = tests[!is.na(tests$IQValue) | !duplicated(tests[["ID"]]), ] 
3

ich eine direkte Lösung finden did'nt, aber man konnte das ursprüngliche data.frame und dann aufheben right_join zurück Spalten, die Sie nicht brauchen.

library(tidyr) 
library(dplyr) 

mydata %>% 
    gather(key, val, Test1:Test3, na.rm = T) %>% 
    right_join(mydata) %>% 
    select(-contains("Test")) 
#> Joining, by = c("ID", "age") 
#> ID age key val 
#> 1 55 12 Test1 100 
#> 2 56 12 Test1 90 
#> 3 57 14 Test1 88 
#> 4 58 11 Test1 115 
#> 5 59 20 Test2 100 
#> 6 60 10 Test2 120 
#> 7 61 13 Test3 110 
#> 8 62 15 <NA> NA 
#> 9 63 18 Test3 85 
#> 10 64 17 Test3 150 

Alternativ können Sie natürlich könnte zunächst eine data.frame mit allen Variablen erstellen Sie behalten möchten und es dann beitreten:

id_data <- select(mydata, ID, age) 

mydata %>% 
    gather(key, val, Test1:Test3, na.rm = T) %>% 
    right_join(id_data) 
+1

Welp, die viel schöner als meins ist. Vielen Dank! – svenhalvorson