2016-05-02 2 views
1

In R habe ich einen Datenrahmen df dieser Form:Tropfen Untergruppe von obs in Datenrahmen, wenn erste Beobachtung Gruppe na ist

a b year month id 
1 2 2012 01 1234758 
1 1 2012 02 1234758 

NA 5 2011 04 1234759 
5 5 2011 05 1234759 
5 5 2011 06 1234759 

2 2 2001 11 1234760 
NA NA 2001 11 1234760 

Einige der einen und bs NAs sind. Ich möchte den Datenrahmen nach ID unterteilen, habe jede Teilmenge nach Jahr und Monat geordnet und lasse dann die ganze Teilmenge/ID fallen, wenn die erste Beobachtung in der Reihenfolge der Zeit von entweder a oder b na ist.

Für das obige Beispiel, des bestimmungsgemäßen Ergebnis ist:

a b year month id 
1 2 2012 01 1234758 
1 1 2012 02 1234758 

2 2 2001 11 1234760 
NA NA 2001 11 1234760 

Ich tat es das nicht vektorisiert Weise, die für immer nahm zu laufen, wie folgt:

df_summary <- as.data.frame(table(df$id),stringsAsFactors=FALSE) 
df <- df[order(df$id,df$year,df$month),] 
remove <- "" 

j <- 1 
l <- 0 
for(i in 1:nrow(df_summary)){ 

    m <- df_summary$Var1[i] 
    if(is.na(df$a[j]) | is.na(df$b[j])) { 
     l <- l + 1 
     remove[l] <- df_summary$id[i] 
    } 
    j <- j + m 
} 

df <- df[!(df$id %in% remove),] 

Was ist ein schneller, vektorisierte Weise, um das gleiche Ergebnis zu erzielen?

Was habe ich versucht, auch meinen Code doppelt überprüfen:

dt <- setDT(df) 
remove_vectorized <- dt[,list(remove_first_na=(is.na(a[1]) | is.na(b[1]))),by=id] 

, die mir alle Beobachtung zu entfernen schlägt vor, die offensichtlich falsch ist.

+0

Wenn Sie mit ' is.na', warum sind die Werte "x" anstatt "NA"? Anstatt es klarer zu machen, fügen Sie Verwirrung hinzu. In Bezug auf Ihren 'data.table'-Versuch könnten Sie' setDT (df) [versuchen, wenn (! Is.na (a [1]) &! Is.na (b [1])) .SD, by = id] ' –

+0

Sie haben Recht, behoben. –

+0

Oder eine andere Option könnte 'indx <- na.omit (unique (setDT (df), durch =" id "), durch = c (" a "," b ")); df [indx, on = "id", nomatch = 0L] 'oder anstelle eines Joins können Sie den letzten Teil durch' df [id% in% indx $ id] ' –

Antwort

2

Hier sind einige data.table mögliche Ansätze

First- Festsetzung Ihr Versuch

library(data.table) 
setDT(df)[, if(!is.na(a[1L]) & !is.na(b[1L])) .SD, by = id] 
#   id a b year month 
# 1: 1234758 1 2 2012  1 
# 2: 1234758 1 1 2012  2 
# 3: 1234760 2 2 2001 11 
# 4: 1234760 NA NA 2001 11 

Oder wir können dies verallgemeinern (auf Kosten der Geschwindigkeit wahrscheinlich)

setDT(df)[, if(Reduce(`&`, !is.na(.SD[1L, .(a, b)]))) .SD, by = id] 
## OR maybe `setDT(df)[, if(Reduce(`&`, !sapply(.SD[1L, .(a, b)], is.na))) .SD , by = id]` 
## in order to avoid to matrix conversions) 
#   id a b year month 
# 1: 1234758 1 2 2012  1 
# 2: 1234758 1 1 2012  2 
# 3: 1234760 2 2 2001 11 
# 4: 1234760 NA NA 2001 11 

Ein anderer Weg ist zu kombinieren unique und na.omit Methoden

indx <- na.omit(unique(setDT(df), by = "id"), by = c("a", "b")) 

Dann wird eine einfache Teilmenge tun

df[id %in% indx$id] 
#   id a b year month 
# 1: 1234758 1 2 2012  1 
# 2: 1234758 1 1 2012  2 
# 3: 1234760 2 2 2001 11 
# 4: 1234760 NA NA 2001 11 

Oder vielleicht ein binäres beitreten?

df[indx[, .(id)], on = "id"] 
#   id a b year month 
# 1: 1234758 1 2 2012  1 
# 2: 1234758 1 1 2012  2 
# 3: 1234760 2 2 2001 11 
# 4: 1234760 NA NA 2001 11 

Oder

indx <- na.omit(unique(setDT(df, key = "id")), by = c("a", "b")) 
df[.(indx$id)] 
#   id a b year month 
# 1: 1234758 1 2 2012  1 
# 2: 1234758 1 1 2012  2 
# 3: 1234760 2 2 2001 11 
# 4: 1234760 NA NA 2001 11 

(Die letzten beiden sind vor allem für die Darstellung)


Für weitere Informationen data.table in Bezug auf, besuchen Sie bitte Getting Started auf GH