Bagaimana cara mengacak (atau mengubah) kerangka data secara berurutan dan menurut kolom?

96

Saya memiliki dataframe (df1) seperti ini.

     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

Kolom d1 ... d4 adalah nama rowname, baris f1 ... f5 adalah nama kolom.

Untuk melakukan sample (df1), saya mendapatkan dataframe baru dengan hitungan 1 sama dengan df1. Jadi, hitungan 1 dipertahankan untuk seluruh kerangka data tetapi tidak untuk setiap baris atau setiap kolom.

Apakah mungkin untuk melakukan pengacakan baris atau kolom?

Saya ingin mengacak kolom df1 untuk setiap kolom, yaitu nomor 1 di setiap kolom tetap sama. dan setiap kolom perlu diubah setidaknya satu kali. Sebagai contoh, saya mungkin memiliki df2 acak seperti ini: (Tercatat bahwa hitungan 1 di setiap kolom tetap sama tetapi jumlah 1 di setiap baris berbeda.

     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

Demikian juga, saya juga ingin mengacak baris df1 untuk setiap baris, yaitu no. dari 1 di setiap baris tetap sama, dan setiap baris perlu diubah (tetapi jumlah entri yang diubah bisa berbeda). Misalnya, df3 yang diacak bisa menjadi seperti ini:

     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. Terima kasih banyak atas bantuan dari Gavin Simpson, Joris Meys, dan Chase untuk jawaban sebelumnya atas pertanyaan saya sebelumnya tentang pengacakan dua kolom.

a83
sumber
apakah Anda ingin mengubah baris dan kolom secara bersamaan. Membaca ulang ini, sepertinya batasan kolom (jumlah 1 yang sama di setiap kolom) tidak berlaku dalam contoh kedua Anda yang mengubah baris.
Gavin Simpson
1
Harap jangan mendaftar untuk banyak akun. Saya telah meminta moderator untuk menggabungkan akun yang Anda gunakan di sini dengan yang digunakan pada Q sebelumnya.
Gavin Simpson

Jawaban:

233

Mengingat R data.frame:

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

Acak baris-bijaksana:

> 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

Secara default sample()mengurutkan ulang elemen yang diteruskan sebagai argumen pertama secara acak. Ini berarti bahwa ukuran default adalah ukuran dari array yang diteruskan. Meneruskan parameter replace=FALSE(default) untuk sample(...)memastikan bahwa pengambilan sampel dilakukan tanpa penggantian yang menyelesaikan shuffle bijaksana baris.

Acak berdasarkan kolom:

> 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
pms
sumber
5
Saya pikir lucu bagaimana ini bukan komentar teratas, namun ini lebih sederhana daripada pergi dan belajar tentang beberapa paket lain. Itu benar untuk hampir semua pertanyaan tentang permuting. HANYA GUNAKAN SAMPEL ()!
Brash Equilibrium
Apakah saya benar dalam mengasumsikan metode ini akan mempertahankan row.names?
tumultous_rooster
Ada alasan untuk menggunakan = melebihi standar <- dalam kasus ini?
Christian
4
Nah, ini mengubah urutan baris dan kolom, tetapi yang diinginkan OP berbeda: mengocok setiap kolom / baris secara terpisah
JelenaČuklina
persis apa yang saya butuhkan!
ChuckCottrill
18

Ini adalah cara lain untuk mengocok data.framepaket yang menggunakan dplyr:

baris-bijaksana:

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

atau

df2 <- sample_frac(df1, 1L)

kolom-bijaksana:

df2 <- select(df1, one_of(sample(names(df1)))) 
Enrique Pérez Herrero
sumber
10

Lihatlah permatswap()di vegan paket. Berikut adalah contoh mempertahankan total baris dan kolom, tetapi Anda bisa melonggarkannya dan memperbaiki hanya satu dari jumlah baris atau kolom.

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")

Ini memberi:

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

Untuk menjelaskan panggilan:

out <- permatswap(mat, times = 99, burnin = 20000, thin = 500, mtype = "prab")
  1. times adalah jumlah matriks acak yang Anda inginkan, di sini 99
  2. burninadalah jumlah swap yang dilakukan sebelum kita mulai mengambil sampel acak. Hal ini memungkinkan matriks yang kita contohkan menjadi sangat acak sebelum kita mulai mengambil setiap matriks acak kita
  3. thinmengatakan hanya mengambil undian acak setiap thinswap
  4. mtype = "prab" mengatakan memperlakukan matriks sebagai ada / tidak adanya, yaitu data 0/1 biner.

Beberapa hal yang perlu diperhatikan, ini tidak menjamin bahwa setiap kolom atau baris telah diacak, tetapi jika burnincukup panjang seharusnya ada kemungkinan besar hal itu terjadi. Selain itu, Anda dapat menggambar lebih banyak matriks acak daripada yang Anda butuhkan dan membuang matriks yang tidak sesuai dengan semua persyaratan Anda.

Persyaratan Anda untuk memiliki jumlah perubahan yang berbeda per baris, juga tidak dibahas di sini. Sekali lagi Anda dapat mencicipi lebih banyak matriks daripada yang Anda inginkan dan kemudian membuang matriks yang tidak memenuhi persyaratan ini juga.

Gavin Simpson
sumber
6

Anda juga dapat menggunakan randomizeMatrixfungsi dalam paket R.picante

contoh:

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
> 

Opsi ini null.model="frequency"mempertahankan jumlah kolom dan richnessmempertahankan jumlah baris. Meskipun terutama digunakan untuk mengacak kumpulan data ketiadaan spesies dalam ekologi komunitas, metode ini berfungsi dengan baik di sini.

Fungsi ini memiliki opsi model null lainnya juga, lihat tautan berikut untuk detail selengkapnya (halaman 36) dari dokumentasi picante

Anne Heloise Theo
sumber
4

Tentu saja Anda dapat mengambil sampel setiap baris:

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

akan mengocok baris itu sendiri, sehingga jumlah 1di setiap baris tidak berubah. Perubahan kecil dan juga berfungsi dengan baik dengan kolom, tetapi ini adalah latihan untuk pembaca :-P

binfalse
sumber
2
Tidak ada upaya untuk menerapkan batasan yang ingin diterapkan oleh OP.
Gavin Simpson
2

Anda juga dapat "mengambil sampel" jumlah item yang sama dalam bingkai data Anda dengan sesuatu seperti ini:

nr<-dim(M)[1]
random_M = M[sample.int(nr),]
Marcos
sumber
alih-alih dim(M)[1], Anda dapat menggunakan nrow(M)sehingga seluruh prosedur menjadi satu baris:random_M <- M[nrow(M),]
Agile Bean
1

Jika tujuannya adalah untuk mengacak setiap kolom secara acak, beberapa jawaban di atas tidak berfungsi karena kolom diacak secara bersamaan (ini mempertahankan korelasi antar kolom). Yang lain membutuhkan penginstalan paket. Namun ada satu baris:

df2 = lapply(df1, function(x) { sample(x) })
rimorob.dll
sumber
0

Random Samples and Permutations ina dataframe Jika dalam bentuk matriks konversikan ke dalam data.frame gunakan fungsi sample dari base package indexes = sample (1: nrow (df1), size = 1 * nrow (df1)) Random Samples and Permutations

thrinadhn
sumber