Как рандомизировать (или переставить) фрейм данных по строкам и столбцам?

96

У меня есть такой фрейм данных (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

Столбец d1 ... d4 - это имя строки, строка f1 ... f5 - это имя столбца.

Чтобы выполнить образец (df1), я получаю новый фрейм данных со счетчиком 1, таким же, как df1. Таким образом, счетчик 1 сохраняется для всего фрейма данных, но не для каждой строки или каждого столбца.

Можно ли выполнить рандомизацию по строкам или по столбцам?

Я хочу рандомизировать столбец df1 для каждого столбца, то есть число 1 в каждом столбце остается прежним. и каждый столбец нужно изменить хотя бы один раз. Например, у меня может быть рандомизированный df2 следующим образом: (Отметил, что счетчик 1 в каждом столбце остается таким же, но счетчик 1 в каждой строке отличается.

     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

Точно так же я также хочу рандомизировать df1 построчно для каждой строки, то есть no. 1 в каждой строке остается неизменным, и каждую строку необходимо изменить (но количество измененных записей может быть другим). Например, случайный df3 может быть примерно таким:

     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. Большое спасибо за помощь от Гэвина Симпсона, Джориса Мейса и Чейза за предыдущие ответы на мой предыдущий вопрос о рандомизации двух столбцов.

a83
источник
вы хотите переставить и строку, и столбцы одновременно. Перечитывая это, похоже, что ограничение столбца (такое же количество единиц в каждом столбце) не соблюдалось во втором примере перестановки строк.
Гэвин Симпсон
1
Пожалуйста, не создавайте несколько учетных записей. Я попросил модераторов объединить учетную запись, которую вы использовали здесь, с учетной записью, использованной в предыдущем вопросе.
Гэвин Симпсон,

Ответы:

233

Учитывая R data.frame:

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

Перемешать по строкам:

> 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

По умолчанию sample()случайным образом меняет порядок элементов, переданных в качестве первого аргумента. Это означает, что размер по умолчанию - это размер переданного массива. Передача параметра replace=FALSE(по умолчанию) в sample(...)гарантирует, что выборка будет выполняться без замены, что приводит к перетасовке строк.

Перемешать по столбцам:

> 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
источник
5
Мне кажется забавным, что это не самый популярный комментарий, и все же это проще, чем пойти и узнать о каком-то другом пакете. Это верно практически для любого вопроса о перестановке. ПРОСТО ИСПОЛЬЗУЙТЕ ОБРАЗЕЦ ()!
Brash Equilibrium
Правильно ли я предполагаю, что этот метод будет поддерживать row.names?
tumultous_rooster
Есть ли причина использовать = вместо стандартного <- в этом случае?
Кристиан
4
Ну, это меняет порядок строк и столбцов, но OP хотел другого: перетасовать каждый столбец / строку независимо
JelenaČuklina
именно то, что мне нужно!
ChuckCottrill
18

Это еще один способ перетасовать data.frameиспользуемый пакет dplyr:

по строкам:

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

или

df2 <- sample_frac(df1, 1L)

по столбцам:

df2 <- select(df1, one_of(sample(names(df1)))) 
Энрике Перес Эрреро
источник
10

Взгляните permatswap()в веганский пакете. Вот пример, поддерживающий итоги как по строкам, так и по столбцам, но вы можете ослабить это и исправить только одну из сумм по строке или столбцу.

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

Это дает:

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

Чтобы объяснить звонок:

out <- permatswap(mat, times = 99, burnin = 20000, thin = 500, mtype = "prab")
  1. times это количество рандомизированных матриц, которое вы хотите, здесь 99
  2. burnin- это количество замен, сделанных до того, как мы начнем брать случайные выборки. Это позволяет матрице, из которой мы делаем выборку, быть достаточно случайной, прежде чем мы начнем брать каждую из наших рандомизированных матриц.
  3. thinговорит, что при каждом thinобмене нужно брать только случайную ничью
  4. mtype = "prab" говорит, что матрица должна рассматриваться как наличие / отсутствие, т.е. двоичные данные 0/1.

Следует отметить пару моментов: это не гарантирует, что какой-либо столбец или строка были рандомизированы, но если burninоно достаточно длинное, должна быть хорошая вероятность того, что это произошло. Кроме того, вы можете нарисовать больше случайных матриц, чем вам нужно, и отбросить те, которые не соответствуют всем вашим требованиям.

Здесь также не рассматривается ваше требование иметь разное количество изменений в строке. Опять же, вы можете выбрать больше матриц, чем хотите, а затем отбросить те, которые также не соответствуют этому требованию.

Гэвин Симпсон
источник
6

вы также можете использовать randomizeMatrixфункцию в пакете Rpicante

пример:

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
> 

Опция null.model="frequency"поддерживает суммы столбцов и суммы richnessстрок. Хотя в основном используется для рандомизации наборов данных о присутствии и отсутствии видов в экологии сообществ, здесь он работает хорошо.

Эта функция также имеет другие параметры нулевой модели, дополнительные сведения см. По следующей ссылке (стр. 36) документации. picante

Энн Элоиза Тео
источник
4

Конечно, вы можете выбрать каждую строку:

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

перетасует строки, так что количество 1в каждой строке не изменится. Небольшие изменения, и он также отлично работает со столбцами, но это упражнение для читателя :-P

binfalse
источник
2
Нет ничего в том, что пытается реализовать ограничения, которые ОП хотела бы наложить.
Гэвин Симпсон
2

Вы также можете "пробовать" то же количество элементов во фрейме данных, например, так:

nr<-dim(M)[1]
random_M = M[sample.int(nr),]
Маркос
источник
вместо этого dim(M)[1]вы можете использовать, nrow(M)чтобы вся процедура стала однострочным:random_M <- M[nrow(M),]
Agile Bean
1

Если цель состоит в том, чтобы случайным образом перемешать каждый столбец, некоторые из приведенных выше ответов не работают, поскольку столбцы перемешиваются вместе (это сохраняет корреляции между столбцами). Другие требуют установки пакета. Тем не менее, существует однострочный:

df2 = lapply(df1, function(x) { sample(x) })
Римороб
источник
0

Случайные выборки и перестановки в кадре данных. Если он находится в матричной форме, преобразовать в data.frame, использовать функцию образца из базового пакета indexes = sample (1: nrow (df1), size = 1 * nrow (df1)) Случайные выборки и перестановки

Thrinadhn
источник