2015-08-25 11 views
10

Mein Problem rührt von der Tatsache her, dass ich die Zeilen, die ich auswählen möchte, bereits anhand der Ebene eines Faktors mithilfe eines anderen Codes identifiziert habe. Im Grunde, was ich habe, ist dies:Zeile für Ebene eines Faktors auswählen

df<-data.frame(ID=c("A","B","C"), pos=c(1,3,2)) 
df2<-data.frame(ID=c(rep("A",5),rep("B",5),rep("C",5)),obs=c(1:15)) 

In df, pos an den Index der Zeile entspricht, jedoch innerhalb einer einzigen Ebene von ID, nicht in dem gesamten Datenrahmen df2. Also ich suche nach einer Möglichkeit, die Zeilen für jede ID nach dem richtigen Index (so ihre Zeilennummer innerhalb der Ebene von jedem Faktor df2) auszuwählen.

Das würde mir dann geben:

df3<-data.frame(ID=c("A","B","C"), obs=c(1,8,12)) 

Antwort

9

Hier ist die Basis R Lösung:

df2$pos <- ave(df2$obs, df2$ID, FUN=seq_along) 
merge(df, df2) 
    ID pos obs 
1 A 1 1 
2 B 3 8 
3 C 2 12 

Wenn df2 von ID sortiert ist, können Sie einfach tun df2$pos <- sequence(table(df2$ID)) für die erste Zeile.

+0

Funktioniert perfekt, danke! –

+0

Gute Idee. Anstatt einen Zwischendatensatz zu erstellen, konnte man 'df2 $ pos <- sequence (länge (split (df2 $ ID, df2 $ ID)))' 'und dann einfach' merge (df, df2) 'machen argumentieren, dass dieser Weg nicht viel hässlicher ist als dplyr. – Frank

+0

Noch besser (und schneller) mit dieser Bearbeitung. –

11

dplyr

library(dplyr) 

merge(df,df2) %>% 
    group_by(ID) %>% 
    filter(row_number() == pos) %>% 
    select(-pos) 

# ID obs 
# 1 A 1 
# 2 B 8 
# 3 C 12 

Basis R

df2m <- merge(df,df2) 
do.call(rbind, 
    by(df2m, df2m$ID, function(SD) SD[SD$pos[1], setdiff(names(SD),"pos")]) 
) 

by teilt das fusionierte Datenrahmen df2m von df2m$ID und arbeitet auf jedem Teil; Es gibt Ergebnisse in einer Liste zurück, daher müssen sie am Ende zusammen rbind ed sein. Jede Teilmenge der Daten (die mit jedem Wert von ID verknüpft sind) wird durch pos gefiltert und die "pos"-Spalte unter Verwendung der normalen Datenrahmensyntax abgewählt.

data.table von @DavidArenburg in einem Kommentar vorgeschlagen

library(data.table) 

setkey(setDT(df2),"ID")[df][, 
    .SD[pos[1L], !"pos", with=FALSE] 
, by = ID] 

Der erste Teil - setkey(setDT(df2),"ID")[df] - ist die Zusammenführung. Danach wird die resultierende Tabelle aufgeteilt by = ID, und jede Teilmenge von Daten, .SD wird bearbeitet. pos[1L] wird auf die normale Weise untergeordnet, während !"pos", with=FALSE dem Löschen der pos Spalte entspricht.

Siehe @ eddis Antwort für einen besseren data.table-Ansatz.

+4

Vielleicht auch 'library (data.table); setkey (setDT (df2), "ID") [df] [, .SD [pos [1L]], mit = ID] 'oder etwas Ähnliches. –

+0

Ihre Lösung scheint die eleganteste zu sein ... Aber ich kann dplyr nicht installieren. Ich weiß, es geht dich nichts an, aber trotzdem wollte ich es hier sagen, also denkst du nicht, dass ich den obersten Posten ignoriert habe. –

+0

@ user2092517 Kein Problem, danke für die Klärung. – Frank

7

Verwendung data.table Version 1.9.5+:

setDT(df2)[df, .SD[pos], by = .EACHI, on = 'ID'] 

die auf ID Spalte übergeht, dann wählt die pos Zeile für jede der Zeilen von df.

+3

Oder einfach 'setkey (setDT (df2)," ID ") [df, .SD [pos], by = .EACHI]' ohne die Entwicklungsversion –