Comment randomiser (ou permuter) un dataframe en ligne et en colonne?

96

J'ai un dataframe (df1) comme celui-ci.

     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 colonne d1 ... d4 est le nom de la ligne, la ligne f1 ... f5 est le nom de la colonne.

Pour faire un échantillon (df1), j'obtiens un nouveau dataframe avec un nombre de 1 identique à df1. Ainsi, le nombre de 1 est conservé pour l'ensemble de la trame de données, mais pas pour chaque ligne ou chaque colonne.

Est-il possible de faire la randomisation par ligne ou par colonne?

Je veux randomiser le df1 par colonne pour chaque colonne, c'est-à-dire que le nombre de 1 dans chaque colonne reste le même. et chaque colonne doit être modifiée au moins une fois. Par exemple, je peux avoir un df2 aléatoire comme celui-ci: (A noté que le nombre de 1 dans chaque colonne reste le même mais le nombre de 1 dans chaque ligne est différent.

     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

De même, je veux également randomiser le df1 par ligne pour chaque ligne, c'est-à-dire le no. de 1 dans chaque ligne reste le même, et chaque ligne doit être modifiée (mais le nombre d'entrées modifiées peut être différent). Par exemple, un df3 aléatoire pourrait être quelque chose comme ceci:

     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. Merci beaucoup pour l'aide de Gavin Simpson, Joris Meys et Chase pour les réponses précédentes à ma question précédente sur la randomisation de deux colonnes.

a83
la source
voulez-vous permuter à la fois la ligne et les colonnes en même temps. En relisant cela, il semble que la contrainte de colonne (même nombre de 1 dans chaque colonne) ne tenait pas dans votre deuxième exemple de permutation de lignes.
Gavin Simpson
1
Veuillez ne pas vous inscrire à plusieurs comptes. J'ai demandé aux modérateurs de fusionner le compte que vous avez utilisé ici avec celui utilisé lors de la précédente Q.
Gavin Simpson

Réponses:

233

Compte tenu du R data.frame:

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

Aléatoire par ligne:

> 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

Par défaut, sample()réorganise aléatoirement les éléments passés comme premier argument. Cela signifie que la taille par défaut est la taille du tableau passé. Passer le paramètre replace=FALSE(par défaut) à sample(...)garantit que l'échantillonnage est effectué sans remplacement, ce qui effectue un mélange par ligne.

Lecture aléatoire des colonnes:

> 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
la source
5
Je pense que c'est drôle de voir que ce n'est pas le principal commentaire, et pourtant c'est plus simple que d'aller et d'apprendre sur un autre package. C'est vrai pour presque toutes les questions sur la permutation. UTILISEZ JUSTE UN ÉCHANTILLON ()!
Brash Equilibrium
Ai-je raison de supposer que cette méthode maintiendra les noms de lignes?
tumultous_rooster
Une raison d'utiliser = au-dessus de la norme <- dans ce cas?
Christian
4
Eh bien, cela change l'ordre des lignes et des colonnes, mais ce que OP voulait est différent: mélanger chaque colonne / ligne indépendamment
JelenaČuklina
exactement ce dont j'avais besoin!
ChuckCottrill
18

C'est une autre façon de mélanger le data.framepackage using dplyr:

par ligne:

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

ou

df2 <- sample_frac(df1, 1L)

Par colonne:

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

Jetez un coup d'œil à permatswap()l' emballage végétalien . Voici un exemple de conservation des totaux de ligne et de colonne, mais vous pouvez assouplir cela et corriger une seule des sommes de ligne ou de colonne.

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

Cela donne:

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

Pour expliquer l'appel:

out <- permatswap(mat, times = 99, burnin = 20000, thin = 500, mtype = "prab")
  1. times est le nombre de matrices aléatoires que vous voulez, ici 99
  2. burninest le nombre de swaps effectués avant de commencer à prélever des échantillons aléatoires. Cela permet à la matrice à partir de laquelle nous échantillonnons d'être assez aléatoire avant de commencer à prendre chacune de nos matrices aléatoires
  3. thindit de ne faire qu'un tirage au sort à chaque thinéchange
  4. mtype = "prab" dit traiter la matrice comme présence / absence, c'est-à-dire des données binaires 0/1.

Quelques points à noter, cela ne garantit pas qu'une colonne ou une ligne a été randomisée, mais si elle burninest suffisamment longue, il devrait y avoir de bonnes chances que cela se produise. De plus, vous pouvez dessiner plus de matrices aléatoires que nécessaire et supprimer celles qui ne correspondent pas à toutes vos exigences.

Votre exigence d'avoir un nombre différent de modifications par ligne n'est pas non plus traitée ici. Encore une fois, vous pouvez échantillonner plus de matrices que vous le souhaitez, puis supprimer celles qui ne répondent pas à cette exigence.

Gavin Simpson
la source
6

vous pouvez également utiliser la randomizeMatrixfonction dans le package Rpicante

exemple:

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'option null.model="frequency"gère les sommes des colonnes et les sommes richnessdes lignes. Bien que principalement utilisé pour randomiser les ensembles de données sur l'absence de présence d'espèces dans l'écologie communautaire, il fonctionne bien ici.

Cette fonction a également d'autres options de modèle nulles, consultez le lien suivant pour plus de détails (page 36) de la documentation picante

Anne Héloïse Théo
la source
4

Bien sûr, vous pouvez échantillonner chaque ligne:

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

va mélanger les lignes lui-même, de sorte que le nombre de 1dans chaque ligne ne change pas. Petits changements et cela fonctionne également très bien avec les colonnes, mais c'est un exercice pour le lecteur :-P

binfalse
la source
2
Il n'y a rien dans ce qui tente de mettre en œuvre les contraintes que l'OP voudrait imposer.
Gavin Simpson
2

Vous pouvez également "échantillonner" le même nombre d'éléments dans votre bloc de données avec quelque chose comme ceci:

nr<-dim(M)[1]
random_M = M[sample.int(nr),]
Marcos
la source
au lieu de dim(M)[1], vous pouvez utiliser nrow(M)pour que l'ensemble de la procédure devienne un one-liner:random_M <- M[nrow(M),]
Agile Bean
1

Si l'objectif est de mélanger au hasard chaque colonne, certaines des réponses ci-dessus ne fonctionnent pas car les colonnes sont mélangées conjointement (cela préserve les corrélations inter-colonnes). D'autres nécessitent l'installation d'un package. Pourtant, une ligne unique existe:

df2 = lapply(df1, function(x) { sample(x) })
rimorob
la source
0

Échantillons aléatoires et permutations dans un dataframe S'il est sous forme de matrice, convertissez en data.frame, utilisez la fonction sample du package de base indexes = sample (1: nrow (df1), size = 1 * nrow (df1)) Echantillons aléatoires et permutations

Thrinadhn
la source