2015-04-25 13 views
6

Ho questo dataframe:Come selezionare colonne specifiche contenenti determinate stringhe/caratteri?

df1 <- data.frame(a = c("correct", "wrong", "wrong", "correct"), 
    b = c(1, 2, 3, 4), 
    c = c("wrong", "wrong", "wrong", "wrong"), 
    d = c(2, 2, 3, 4)) 

a  b c  d 
correct 1 wrong 2 
wrong 2 wrong 2 
wrong 3 wrong 3 
correct 4 wrong 4 

e vorrei selezionare solo le colonne sia con le stringhe 'corretto' o 'sbagliato' (vale a dire, b colonne e d in df1), in modo tale che ottengo questo dataframe :

df2 <- data.frame(a = c("correct", "wrong", "wrong", "correct"), 
     c = c("wrong", "wrong", "wrong", "wrong")) 

     a  c 
1 correct wrong 
2 wrong wrong 
3 wrong wrong 
4 correct wrong 

Posso usare dplyr per fare questo? In caso contrario, quale funzione (s) posso usare per fare questo? L'esempio che ho dato è semplice, nel senso che io posso solo fare questo (dplyr):

select(df1, a, c) 

Tuttavia, a mio dataframe attuale, ho circa 700 variabili/colonne e qualche centinaio di colonne che contengono le stringhe 'corretto' o 'sbagliato' e non conosco i nomi delle variabili/colonne.

Qualche suggerimento su come farlo rapidamente? Molte grazie!

risposta

8

È possibile utilizzare basamento RFilter che opererà su ciascuna delle colonne df1 s' e mantenere tutti quelli soddisfare il test logico nella funzione:

Filter(function(u) any(c('wrong','correct') %in% u), df1) 
#  a  c 
#1 correct wrong 
#2 wrong wrong 
#3 wrong wrong 
#4 correct wrong 

È possibile anche utilizzare grepl:

Filter(function(u) any(grepl('wrong|correct',u)), df1) 
+0

Stavo per fare 'df1 [sapply (df1, function (x) any (x% in% c (" correct "," wrong ")))]' ma questo è più bello. – A5C1D2H2I1M1N2O1R2T1

+0

Non sapevo che ci fosse il filtro nella base R! Molte grazie! – hsl

2

---- update ----- Grazie Colonnello Beavel. Che soluzione elegante. Userò lo Filter di più.

voglio verificare una soluzione di velocità troppo giusto in tempo caso è un fattore importante:

locator <- apply(df1, 2, function(x) grepl("correct|wrong", x)) 
index <- apply(locator, 2, any) 
newdf <- df1[,!index] 

ho ampliato la cornice di dati a 500.000 colonne:

dftest <- as.data.frame(replicate(500000, df1[,1])) 

poi testato l'ora del sistema per una funzione con apply, Filter con Grepl, e Filter con pattern% in%:

f <- function() { 
locator <- apply(dftest, 2, function(x) grepl("correct|wrong", x)) 
index <- apply(locator, 2, any) 
newdf <- dftest[,!index] 
} 

f1 <- function() {newdf <- (Filter(function(x) any(c("wrong", "correct") %in% x), dftest))} 

f2 <- function() {newdf <- Filter(function(u) any(grepl('wrong|correct',u)), dftest)} 


system.time(f()) 
    user system elapsed 
    24.32 0.00 24.35 
system.time(f1()) 
    user system elapsed 
    2.31 0.00 2.34 
system.time(f2()) 
    user system elapsed 
    8.66 0.01 8.71 

La soluzione del colonnello è di gran lunga la migliore. È pulito e funziona meglio. --credit @akrun per il suggerimento data.frame.

+0

'dftest' è una matrice. Il 'Filtro' darebbe una uscita vettoriale, quindi non sono sicuro che il confronto sia corretto. Potrebbe essere necessario convertire il 'dftest' in' data.frame' e poi fare il confronto. Se converto 'dftest' in' data.frame', il tempo di sistema che ho ottenuto è 'system.time (f()) #user system trascorso # 19.010 0.095 19.097; system.time (f1()) # sistema utente trascorso 2.290 0.004 2.292 ' – akrun

+0

Ho anche provato con' dftest' come una 'matrice '. 'system.time (f()) # sistema utente scaduto # 7.081 0,008 7.084'. Tuttavia non ha battuto la funzione del Colonel Beauvel. – akrun

+0

@akrun l'hai fatto di nuovo. Grazie, aggiornerò. –

Problemi correlati