2015-08-25 25 views
10

Il mio problema deriva dal fatto che ho già identificato le righe che desidero selezionare per il livello di un fattore, utilizzando un codice diverso. Fondamentalmente quello che ho è questo:Seleziona riga per livello di un fattore

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 corrisponde all'indice della riga ma all'interno di un unico livello di ID, non in tutto dataframe DF2. Quindi sto cercando un modo per selezionare le righe per ogni ID secondo l'indice corretto (quindi il loro numero di riga all'interno del livello di ciascun fattore di df2).

Questo sarebbe poi darmi:

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

risposta

9

Ecco la soluzione di base R:

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 

Se df2 è ordinato secondo ID, si può solo fare df2$pos <- sequence(table(df2$ID)) per la prima linea.

+0

Funziona perfettamente, grazie! –

+0

Buona idea. Invece di creare un set di dati intermedi, si potrebbe fare 'df2 $ pos <- sequence (lengths (split (df2 $ ID, df2 $ ID))' e quindi basta 'unire (df, df2)' I'd argomentare che quella via non è molto più brutta di dplyr. – Frank

+0

Ancora meglio (e più veloce) con questa modifica. –

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 

base di R

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

by divide il frame di dati unito df2m per df2m$ID e opera su ciascuna parte; restituisce risultati in un elenco, quindi devono essere rbind ed insieme alla fine. Ogni sottoinsieme dei dati (associato a ciascun valore di ID) viene filtrato da pos e deseleziona la colonna "pos" utilizzando la normale sintassi data.frame.

data.table suggerite da @DavidArenburg in un commento

library(data.table) 

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

La prima parte - setkey(setDT(df2),"ID")[df] - è l'unione. Successivamente, la tabella risultante viene divisa by = ID e ogni Sottoinsieme di dati, .SD viene attivato. pos[1L] ha un sottotitolo nel modo normale, mentre !"pos", with=FALSE corrisponde alla caduta della colonna pos.

Vedere la risposta di @ eddi per un approccio data.table migliore.

+4

Forse anche 'library (data.table); setkey (setDT (df2), "ID") [df] [, .SD [pos [1L]], di = ID] 'o qualcosa di simile. –

+0

La tua soluzione sembra essere la più elegante ... Ma non riesco a installare dplyr. So che non ti riguarda, ma comunque, volevo dirlo qui, quindi non pensi di aver ignorato il primo posto. –

+0

@ user2092517 Nessun problema, grazie per aver chiarito. – Frank

7

Uso data.table versione 1.9.5+:

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

che fonde il ID colonna, quindi seleziona la riga pos per ciascuna delle righe di df.

+3

O semplicemente "setkey (setDT (df2)," ID ") [df, .SD [pos], di = .EACHI]' senza la versione di sviluppo –