Campionamento casuale stratificato dal frame di dati

Ho un frame di dati nel formato:

head(subset) # ants 0 1 1 0 1 # age 1 2 2 1 3 # lc 1 1 0 1 0 

Ho bisogno di creare un nuovo frame di dati con campioni casuali in base all’età e al lc. Ad esempio voglio 30 campioni di età: 1 e lc: 1, 30 campioni di età: 1 e lc: 0 ecc.

Ho guardato il metodo di campionamento casuale come;

 newdata <- function(subset, age, 30) 

Ma non è il codice che voglio.

Suggerirei di utilizzare sia stratified dal mio pacchetto “splitstackshape”, sia sample_n dal pacchetto “dplyr”:

 ## Sample data set.seed(1) n <- 1e4 d <- data.table(age = sample(1:5, n, T), lc = rbinom(n, 1 , .5), ants = rbinom(n, 1, .7)) # table(d$age, d$lc) 

Per stratified , si specifica in sostanza il set di dati, le colonne di stratificazione e un numero intero che rappresenta la dimensione desiderata da ciascun gruppo O un decimale che rappresenta la frazione che si desidera restituire (ad esempio, .1 rappresenta il 10% di ciascun gruppo).

 library(splitstackshape) set.seed(1) out <- stratified(d, c("age", "lc"), 30) head(out) # age lc ants # 1: 1 0 1 # 2: 1 0 0 # 3: 1 0 1 # 4: 1 0 1 # 5: 1 0 0 # 6: 1 0 1 table(out$age, out$lc) # # 0 1 # 1 30 30 # 2 30 30 # 3 30 30 # 4 30 30 # 5 30 30 

Per sample_n devi prima creare una tabella raggruppata (usando group_by ) e quindi specificare il numero di osservazioni che vuoi. Se invece preferisci il campionamento proporzionale, dovresti usare sample_frac .

 library(dplyr) set.seed(1) out2 <- d %>% group_by(age, lc) %>% sample_n(30) # table(out2$age, out2$lc) 

Ecco alcuni dati:

 set.seed(1) n <- 1e4 d <- data.frame(age = sample(1:5,n,TRUE), lc = rbinom(n,1,.5), ants = rbinom(n,1,.7)) 

Vuoi una strategia di combinazione split-apply-together, in cui dividi il tuo data.frame ( d in questo esempio), campiona righe / osservazioni da ciascun sottocampione, quindi combina e poi ritorna con rbind . Ecco come funziona:

 sp <- split(d, list(d$age, d$lc)) samples <- lapply(sp, function(x) x[sample(1:nrow(x), 30, FALSE),]) out <- do.call(rbind, samples) 

Il risultato:

 > str(out) 'data.frame': 300 obs. of 3 variables: $ age : int 1 1 1 1 1 1 1 1 1 1 ... $ lc : int 0 0 0 0 0 0 0 0 0 0 ... $ ants: int 1 1 0 1 1 1 1 1 1 1 ... > head(out) age lc ants 1.0.2242 1 0 1 1.0.4417 1 0 1 1.0.389 1 0 0 1.0.4578 1 0 1 1.0.8170 1 0 1 1.0.5606 1 0 1 

Vedi la funzione strata dal campionamento del pacchetto. La funzione seleziona il campionamento casuale semplice stratificato e fornisce un campione come risultato. Vengono aggiunte due colonne aggiuntive: probabilità di inclusione ( Prob ) e indicatore di strato ( Stratum ). Guarda l’esempio.

 require(data.table) require(sampling) set.seed(1) n <- 1e4 d <- data.table(age = sample(1:5, n, T), lc = rbinom(n, 1 , .5), ants = rbinom(n, 1, .7)) # Sort setkey(d, age, lc) # Population size by strata d[, .N, keyby = list(age, lc)] # age lc N # 1: 1 0 1010 # 2: 1 1 1002 # 3: 2 0 993 # 4: 2 1 1026 # 5: 3 0 1021 # 6: 3 1 982 # 7: 4 0 958 # 8: 4 1 940 # 9: 5 0 1012 # 10: 5 1 1056 # Select sample set.seed(2) s <- data.table(strata(d, c("age", "lc"), rep(30, 10), "srswor")) # Sample size by strata s[, .N, keyby = list(age, lc)] # age lc N # 1: 1 0 30 # 2: 1 1 30 # 3: 2 0 30 # 4: 2 1 30 # 5: 3 0 30 # 6: 3 1 30 # 7: 4 0 30 # 8: 4 1 30 # 9: 5 0 30 # 10: 5 1 30 

A meno che non abbia frainteso la domanda, questo è incredibilmente facile da fare con semplici funzioni.

Passaggio 1: creare un indicatore di strato utilizzando la funzione di interaction .

Passaggio 2: utilizzare la tapply su una sequenza di indicatori di riga per identificare gli indici del campione casuale.

Passaggio 3: impostare i dati con questi indici

Utilizzando l’esempio di dati di @Thomas:

 set.seed(1) n <- 1e4 d <- data.frame(age = sample(1:5,n,TRUE), lc = rbinom(n,1,.5), ants = rbinom(n,1,.7)) ## stratum indicator d$group <- interaction(d[, c('age', 'lc')]) ## sample selection indices <- tapply(1:nrow(d), d$group, sample, 30) ## obtain subsample subsampd <- d[unlist(indices, use.names = FALSE), ] 

Verificare la stratificazione appropriata

 > table(subsampd$group) 1.0 2.0 3.0 4.0 5.0 1.1 2.1 3.1 4.1 5.1 30 30 30 30 30 30 30 30 30 30