Come randomizzare (o permutare) un dataframe per riga e per colonna?


96

Ho un dataframe (df1) come questo.

     f1   f2   f3   f4   f5
d1   1    0    1    1    1  
d2   1    0    0    1    0
d3   0    0    0    1    1
d4   0    1    0    0    1

La colonna d1 ... d4 è il nome del nome, la riga f1 ... f5 è il nome della colonna.

Per fare il campione (df1), ottengo un nuovo dataframe con conteggio di 1 uguale a df1. Quindi, il conteggio di 1 viene conservato per l'intero dataframe ma non per ogni riga o colonna.

È possibile eseguire la randomizzazione per riga o per colonna?

Voglio randomizzare la colonna df1 per ogni colonna, cioè il numero di 1 in ogni colonna rimane lo stesso. e ogni colonna deve essere modificata almeno una volta. Ad esempio, potrei avere un df2 randomizzato come questo: (notato che il conteggio di 1 in ogni colonna rimane lo stesso ma il conteggio di 1 in ogni riga è diverso.

     f1   f2   f3   f4   f5
d1   1    0    0    0    1  
d2   0    1    0    1    1
d3   1    0    0    1    1
d4   0    0    1    1    0

Allo stesso modo, voglio anche randomizzare il df1 per riga per ogni riga, cioè il no. di 1 in ogni riga rimane lo stesso e ogni riga deve essere modificata (ma il numero delle voci modificate potrebbe essere diverso). Ad esempio, un df3 randomizzato potrebbe essere qualcosa del genere:

     f1   f2   f3   f4   f5
d1   0    1    1    1    1  <- two entries are different
d2   0    0    1    0    1  <- four entries are different
d3   1    0    0    0    1  <- two entries are different
d4   0    0    1    0    1  <- two entries are different

PS. Mille grazie per l'aiuto di Gavin Simpson, Joris Meys e Chase per le risposte precedenti alla mia precedente domanda sulla randomizzazione di due colonne.


vuoi permutare sia la riga che le colonne allo stesso tempo. Rileggendo questo, sembra che il vincolo di colonna (lo stesso numero di 1 in ogni colonna) non sia stato mantenuto nel secondo esempio che permuta le righe.
Gavin Simpson,

1
Si prega di non registrarsi per più account. Ho chiesto ai moderatori di unire l'account che hai usato qui con quello usato nel precedente Q.
Gavin Simpson

Risposte:


233

Dato il data.frame R:

> df1
  a b c
1 1 1 0
2 1 0 0
3 0 1 0
4 0 0 0

Shuffle row-wise:

> df2 <- df1[sample(nrow(df1)),]
> df2
  a b c
3 0 1 0
4 0 0 0
2 1 0 0
1 1 1 0

Per impostazione predefinita, sample()riordina casualmente gli elementi passati come primo argomento. Ciò significa che la dimensione predefinita è la dimensione dell'array passato. Il passaggio del parametro replace=FALSE(impostazione predefinita) a sample(...)assicura che il campionamento venga eseguito senza sostituzione, il che compie una riproduzione casuale per riga.

Riproduzione casuale per colonna:

> df3 <- df1[,sample(ncol(df1))]
> df3
  c a b
1 0 1 1
2 0 1 0
3 0 0 1
4 0 0 0

5
Penso che sia divertente come questo non sia il commento più importante, eppure è più semplice che andare a conoscere qualche altro pacchetto. Questo è vero per quasi tutte le domande sulla permutazione. BASTA USARE SAMPLE ()!
Brash Equilibrium

Ho ragione nel presumere che questo metodo manterrà il file row.names?
tumultous_rooster

Qualche motivo per usare = rispetto allo standard <- in questo caso?
Christian

4
Bene, questo sta cambiando l'ordine di righe e colonne, ma ciò che OP voleva è diverso: mescola ogni colonna / riga in modo indipendente
JelenaČuklina

esattamente quello di cui avevo bisogno!
ChuckCottrill

18

Questo è un altro modo per mescolare il data.framepacchetto using dplyr:

a livello di riga:

df2 <- slice(df1, sample(1:n()))

o

df2 <- sample_frac(df1, 1L)

a livello di colonna:

df2 <- select(df1, one_of(sample(names(df1)))) 

10

Date un'occhiata permatswap()nel vegan pacchetto. Di seguito è riportato un esempio che mantiene sia i totali di riga che di colonna, ma è possibile attenuarlo e correggere solo una delle somme di riga o colonna.

mat <- matrix(c(1,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,1,0,1,1), ncol = 5)
set.seed(4)
out <- permatswap(mat, times = 99, burnin = 20000, thin = 500, mtype = "prab")

Questo da:

R> out$perm[[1]]
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    0    1    1    1
[2,]    0    1    0    1    0
[3,]    0    0    0    1    1
[4,]    1    0    0    0    1
R> out$perm[[2]]
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    1    0    1    1
[2,]    0    0    0    1    1
[3,]    1    0    0    1    0
[4,]    0    0    1    0    1

Per spiegare la chiamata:

out <- permatswap(mat, times = 99, burnin = 20000, thin = 500, mtype = "prab")
  1. times è il numero di matrici randomizzate che desideri, qui 99
  2. burninè il numero di scambi effettuati prima di iniziare a prelevare campioni casuali. Ciò consente alla matrice da cui campioniamo di essere abbastanza casuale prima di iniziare a prendere ciascuna delle nostre matrici randomizzate
  3. thindice di prendere solo un'estrazione casuale ogni thinscambio
  4. mtype = "prab" dice considera la matrice come presenza / assenza, cioè dati 0/1 binari.

Un paio di cose da notare, questo non garantisce che nessuna colonna o riga sia stata randomizzata, ma se burninè abbastanza lunga dovrebbe esserci una buona probabilità che ciò sia accaduto. Inoltre, potresti disegnare più matrici casuali del necessario e scartare quelle che non corrispondono a tutti i tuoi requisiti.

Anche la tua esigenza di avere un numero diverso di modifiche per riga non è trattata qui. Anche in questo caso potresti campionare più matrici di quanto desideri e quindi scartare anche quelle che non soddisfano questo requisito.


6

puoi anche usare la randomizeMatrixfunzione nel pacchetto R.picante

esempio:

test <- matrix(c(1,1,0,1,0,1,0,0,1,0,0,1,0,1,0,0),nrow=4,ncol=4)
> test
     [,1] [,2] [,3] [,4]
[1,]    1    0    1    0
[2,]    1    1    0    1
[3,]    0    0    0    0
[4,]    1    0    1    0

randomizeMatrix(test,null.model = "frequency",iterations = 1000)

     [,1] [,2] [,3] [,4]
[1,]    0    1    0    1
[2,]    1    0    0    0
[3,]    1    0    1    0
[4,]    1    0    1    0

randomizeMatrix(test,null.model = "richness",iterations = 1000)

     [,1] [,2] [,3] [,4]
[1,]    1    0    0    1
[2,]    1    1    0    1
[3,]    0    0    0    0
[4,]    1    0    1    0
> 

L'opzione null.model="frequency"mantiene le somme di colonna e richnessmantiene le somme di riga. Sebbene utilizzato principalmente per randomizzare i set di dati sull'assenza della presenza di specie nell'ecologia della comunità, funziona bene qui.

Questa funzione ha anche altre opzioni di modello nullo, controlla il seguente link per maggiori dettagli (pagina 36) della documentazione picante


4

Ovviamente puoi campionare ogni riga:

sapply (1:4, function (row) df1[row,]<<-sample(df1[row,]))

mescolerà le righe stesse, quindi il numero di 1in ogni riga non cambia. Piccole modifiche e funziona benissimo anche con le colonne, ma questo è un esercizio per il lettore :-P


2
Non c'è nulla in ciò che tenti di attuare i vincoli che il PO vorrebbe imporre.
Gavin Simpson

2

Puoi anche "campionare" lo stesso numero di elementi nel tuo data frame con qualcosa del genere:

nr<-dim(M)[1]
random_M = M[sample.int(nr),]

invece di dim(M)[1], puoi usare in nrow(M)modo che l'intera procedura diventi una riga:random_M <- M[nrow(M),]
Agile Bean

1

Se l'obiettivo è mescolare in modo casuale ogni colonna, alcune delle risposte precedenti non funzionano poiché le colonne vengono mescolate insieme (questo preserva le correlazioni tra le colonne). Altri richiedono l'installazione di un pacchetto. Eppure esiste una battuta:

df2 = lapply(df1, function(x) { sample(x) })

0

Campioni casuali e permutazioni in un dataframe Se è in forma di matrice, convertire in data.frame usa la funzione sample dal pacchetto base indexes = sample (1: nrow (df1), size = 1 * nrow (df1)) Campioni casuali e permutazioni

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.