2012-03-09 4 views
12

Esiste un buon metodo per ottenere un campione di righe da una parte di un dataframe?Esempio casuale di righe da sottoinsieme di un frame di dati R

Se devo solo dati come

gender <- c("F", "M", "M", "F", "F", "M", "F", "F") 
age <- c(23, 25, 27, 29, 31, 33, 35, 37) 

allora posso facilmente assaggiare le età di tre delle Fs con

sample(age[gender == "F"], 3) 

e ottenere qualcosa di simile

[1] 31 35 29 

ma se trasformo questi dati in un dataframe

mydf <- data.frame(gender, age) 

non posso usare l'ovvio

sample(mydf[mydf$gender == "F", ], 3) 

se posso inventare qualcosa di contorto con un numero assurdo di staffe come

mydf[sample((1:nrow(mydf))[mydf$gender == "F"], 3), ] 

e ottenere ciò che voglio, che è qualcosa di simile

gender age 
7  F 35 
4  F 29 
1  F 23 

C'è un modo migliore che mi richiede meno tempo per capire come scrivere?

risposta

17

Il tuo modo convoluto è praticamente come farlo - Penso che tutte le risposte saranno variazioni su quel tema.

Per esempio, mi piace per generare le mydf$gender=="F" indici prima:

idx <- which(mydf$gender=="F") 

Poi ho campione dal che:

mydf[ sample(idx,3), ] 

Così in una linea (anche se, si riduce il numero assurdo di staffe e forse rendere il tuo codice più facile da capire avendo più linee):

mydf[ sample(which(mydf$gender=='F'), 3), ] 

Mentre il "wheee sono un hacker!" una parte di me preferisce l'one-liner, la parte ragionevole di me dice che anche se il two-liner è a due linee, è molto più comprensibile - è solo una tua scelta.

+0

6 staffe (sia su una o due linee) è sicuramente meglio di 10. – Henry

+0

Non riesco ancora a credere che non ci sia un modo semplice per portare avanti una procedura statistica così funzionale in R. Ci deve essere un'app, voglio dire, un pacchetto per questo. –

9

Tu dici non posso usare l'ovvio:

sample(mydf[mydf$gender == "F", ], 3) 

ma si potrebbe scrivere la propria funzione per farlo:

sample.df <- function(df, n) df[sample(nrow(df), n), , drop = FALSE] 

quindi eseguirlo alla selezione sottoinsieme:

sample.df(mydf[mydf$gender == "F", ], 3) 
# gender age 
# 5  F 31 
# 4  F 29 
# 1  F 23 

(Personalmente trovo più semplice sample.df(subset(mydf, gender == "F"), 3) leggere.)

2

Questo è ora più semplice con la versione avanzata di sample nel mio pacchetto:

library(devtools); install_github('kimisc', 'krlmlr') 

library(kimisc) 
sample.rows(subset(mydf, gender == "F"), 3) 

Vedi anche questo related answer per maggiori dettagli.