Jak randomizować (lub permutować) ramkę danych wierszową i kolumnową?

96

Mam taką ramkę danych (df1).

     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

Kolumna d1 ... d4 to nazwa kolumny, a wiersz f1 ... f5 to nazwa kolumny.

Aby zrobić próbkę (df1), otrzymuję nową ramkę danych z liczbą 1 taką samą jak df1. Tak więc liczba 1 jest zachowywana dla całej ramki danych, ale nie dla każdego wiersza lub każdej kolumny.

Czy można przeprowadzić randomizację według wierszy lub kolumn?

Chcę randomizować kolumny df1 dla każdej kolumny, tj. Liczba 1 w każdej kolumnie pozostaje taka sama. i każda kolumna musi zostać zmieniona co najmniej raz. Na przykład mogę mieć losowe df2 w ten sposób: (Zauważyłem, że liczba 1 w każdej kolumnie pozostaje taka sama, ale liczba 1 w każdym wierszu jest inna.

     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

Podobnie, chcę również losować wiersze df1 dla każdego wiersza, tj. Nie. 1 w każdym wierszu pozostaje taka sama i każdy wiersz musi zostać zmieniony (ale liczba zmienionych wpisów może być inna). Na przykład losowy plik df3 może wyglądać mniej więcej tak:

     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. Wielkie dzięki za pomoc Gavina Simpsona, Jorisa Meysa i Chase'a za poprzednie odpowiedzi na moje poprzednie pytanie dotyczące losowania dwóch kolumn.

a83
źródło
chcesz permutować jednocześnie wiersz i kolumny. Czytając to ponownie, wygląda na to, że ograniczenie kolumny (taka sama liczba jedynek w każdej kolumnie) nie zachowało się w drugim przykładzie permutacji wierszy.
Gavin Simpson,
1
Nie rejestruj wielu kont. Poprosiłem moderatorów o połączenie konta, którego użyłeś tutaj, z kontem używanym w poprzednim pytaniu.
Gavin Simpson

Odpowiedzi:

233

Biorąc pod uwagę R data.frame:

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

Tasuj wierszami:

> 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

Domyślnie sample()losowo zmienia kolejność elementów przekazanych jako pierwszy argument. Oznacza to, że domyślny rozmiar to rozmiar przekazanej tablicy. Przekazywanie parametru replace=FALSE(wartość domyślna) w celu sample(...)zapewnienia, że ​​próbkowanie jest wykonywane bez zamiany, co powoduje przetasowanie wierszy.

Pomieszaj według kolumn:

> 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
źródło
5
Myślę, że to zabawne, że nie jest to główny komentarz, a mimo to jest prostszy niż pójście i poznanie innego pakietu. Dotyczy to prawie każdego pytania o permutację. PO PROSTU UŻYJ PRÓBKI ()!
Brash Equilibrium,
Czy mam rację, zakładając, że ta metoda zachowa wiersz.names?
tumultous_rooster
Czy jest jakiś powód do używania = ponad standardową <- w tym przypadku?
Christian,
4
Cóż, to zmienia kolejność wierszy i kolumn, ale to, czego chciał OP, jest inne:
potasuj
dokładnie to, czego potrzebowałem!
ChuckCottrill
18

Oto kolejny sposób na przetasowanie data.framepakietu using dplyr:

wierszowo:

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

lub

df2 <- sample_frac(df1, 1L)

kolumnowo:

df2 <- select(df1, one_of(sample(names(df1)))) 
Enrique Pérez Herrero
źródło
10

Przyjrzeć się permatswap()w wegańskiej opakowaniu. Oto przykład utrzymujący sumy wierszy i kolumn, ale możesz to złagodzić i naprawić tylko jedną sumę wierszy lub kolumn.

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

To daje:

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

Aby wyjaśnić wezwanie:

out <- permatswap(mat, times = 99, burnin = 20000, thin = 500, mtype = "prab")
  1. times to liczba losowych macierzy, które chcesz, tutaj 99
  2. burninto liczba swapów dokonanych przed rozpoczęciem pobierania próbek losowych. Dzięki temu macierz, z której próbujemy, jest dość losowa, zanim zaczniemy pobierać każdą z naszych losowych macierzy
  3. thinmówi tylko losowe losowanie każdej thinzamiany
  4. mtype = "prab" mówi traktuj macierz jako obecność / brak, czyli dane binarne 0/1.

Kilka rzeczy do zapamiętania, to nie gwarantuje, że jakakolwiek kolumna lub wiersz został losowy, ale jeśli burninjest wystarczająco długi, powinna istnieć duża szansa, że ​​tak się stanie. Możesz także narysować więcej losowych macierzy niż potrzebujesz i odrzucić te, które nie spełniają wszystkich Twoich wymagań.

Twój wymóg posiadania różnej liczby zmian w wierszu również nie jest tutaj uwzględniony. Ponownie możesz próbkować więcej macierzy niż chcesz, a następnie odrzucić te, które również nie spełniają tego wymagania.

Gavin Simpson
źródło
6

możesz także użyć randomizeMatrixfunkcji z pakietu R.picante

przykład:

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
> 

Ta opcja null.model="frequency"zachowuje sumy kolumn i richnesssumy wierszy. Chociaż jest używany głównie do randomizacji zbiorów danych o nieobecności gatunków w ekologii społeczności, sprawdza się tutaj dobrze.

Ta funkcja ma również inne opcje modelu zerowego, sprawdź poniższe łącze, aby uzyskać więcej informacji (strona 36) w dokumentacji picante

Anne Heloise Theo
źródło
4

Oczywiście możesz próbkować każdy wiersz:

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

sam potasuje wiersze, więc liczba 1w każdym wierszu się nie zmieni. Drobne zmiany i świetnie też działa z kolumnami, ale to jest ćwiczenie dla czytelnika :-P

binfalse
źródło
2
Nie ma w tym nic, co próbuje wdrożyć ograniczenia, które chciałby nałożyć PO.
Gavin Simpson
2

Możesz także „próbkować” tę samą liczbę elementów w ramce danych za pomocą czegoś takiego:

nr<-dim(M)[1]
random_M = M[sample.int(nr),]
Marcos
źródło
zamiast tego dim(M)[1]możesz użyć, nrow(M)aby cała procedura stała się jedną linijką:random_M <- M[nrow(M),]
Agile Bean
1

Jeśli celem jest losowe tasowanie każdej kolumny, niektóre z powyższych odpowiedzi nie działają, ponieważ kolumny są tasowane łącznie (zachowuje to korelacje międzykolumnowe). Inne wymagają zainstalowania pakietu. Jednak istnieje jedna linijka:

df2 = lapply(df1, function(x) { sample(x) })
rimorob
źródło
0

Próbki losowe i permutacje w ramce danych Jeśli jest w postaci macierzy, przekonwertuj ją na dane.frame użyj funkcji próbki z pakietu podstawowego indeksy = sample (1: nrow (df1), size = 1 * nrow (df1)) Random Samples and Permutations

thrinadhn
źródło