14 votes

création d'une matrice triangulaire

Il doit y avoir un moyen élégant de le faire, mais je n'arrive pas à le trouver :

Les colonnes sont des probabilités de 1 à 0 pour aller à droite.

Les rangées sont des probabilités de 0 à 1 en descendant.

Ce code maladroit donne le résultat souhaité (mais je veux le faire avec une matrice beaucoup plus grande que celle-ci) :

# Vector entries are rowname - colname, if >= 0
#
rb0 <-  c(NA,NA,NA,NA,NA,NA,NA,NA,NA,NA, 0)
rb1 <-  c(NA,NA,NA,NA,NA,NA,NA,NA,NA, 0,.1)
rb2 <-  c(NA,NA,NA,NA,NA,NA,NA,NA, 0,.1,.2)
rb3 <-  c(NA,NA,NA,NA,NA,NA,NA, 0,.1,.2,.3)
rb4 <-  c(NA,NA,NA,NA,NA,NA, 0,.1,.2,.3,.4)
rb5 <-  c(NA,NA,NA,NA,NA, 0,.1,.2,.3,.4,.5)
rb6 <-  c(NA,NA,NA,NA, 0,.1,.2,.3,.4,.5,.6)
rb7 <-  c(NA,NA,NA, 0,.1,.2,.3,.4,.5,.6,.7)
rb8 <-  c(NA,NA, 0,.1,.2,.3,.4,.5,.6,.7,.8)
rb9 <-  c(NA, 0,.1,.2,.3,.4,.5,.6,.7,.8,.9)
rb10 <- c( 0,.1,.2,.3,.4,.5,.6,.7,.8,.9,1 )
indbias <- rbind(rb0,rb1,rb2,rb3,rb4,rb5,rb6,rb7,rb8,rb9,rb10)
colnames(indbias) <- seq(1,0,by=-.1)
rownames(indbias) <- seq(0,1,by=.1)
indbias

Gracias.

19voto

BondedDust Points 105234
 mat <- matrix(NA, 10,10)
 mat[row(mat)+col(mat) >=11] <- (row(mat)+col(mat) -11)[row(mat)+col(mat)>=11]/10
 mat
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
 [1,]   NA   NA   NA   NA   NA   NA   NA   NA   NA   0.0
 [2,]   NA   NA   NA   NA   NA   NA   NA   NA  0.0   0.1
 [3,]   NA   NA   NA   NA   NA   NA   NA  0.0  0.1   0.2
 [4,]   NA   NA   NA   NA   NA   NA  0.0  0.1  0.2   0.3
 [5,]   NA   NA   NA   NA   NA  0.0  0.1  0.2  0.3   0.4
 [6,]   NA   NA   NA   NA  0.0  0.1  0.2  0.3  0.4   0.5
 [7,]   NA   NA   NA  0.0  0.1  0.2  0.3  0.4  0.5   0.6
 [8,]   NA   NA  0.0  0.1  0.2  0.3  0.4  0.5  0.6   0.7
 [9,]   NA  0.0  0.1  0.2  0.3  0.4  0.5  0.6  0.7   0.8
[10,]    0  0.1  0.2  0.3  0.4  0.5  0.6  0.7  0.8   0.9

Je pense que cela sera beaucoup plus rapide qu'une solution plyr et je pense que c'est plus facile à comprendre. Il s'agit essentiellement de mettre en place un test pour les entrées qui sont dans le "triangle" inférieur droit et ensuite de diviser les résultats de cette matrice "test" par 10. Vous pouvez regarder la matrice test avec ce code :

row(mat)+col(mat) -11

Edit : J'ai pensé qu'il était possible que faire la matrice une fois comme sebastian-c l'a illustré et ensuite faire un seul test pour faire le réglage NA pourrait être plus rapide ( avec un tiers du nombre d'appels à row y col ) mais il semble qu'il ne soit qu'un tiers moins rapide. Il semble que les deux appels seq prennent plus de temps que le :

mat <- round(outer(seq(-0.5, 0.5, 0.1), seq(-0.5, 0.5, 0.1), `+`), 1)
is.na(mat) <- row(mat)+col(mat) <= 11
mat

J'ai trouvé une autre solution basée sur le peu connu embed fonction :

mat <- embed(seq(-1,1, by=0.1), 11 )[,11:1]
is.na(mat) <- row(mat)+col(mat) <= 11

Bien qu'elle soit 50 % plus rapide que la nouvelle solution, elle est toujours plus lente que l'originale.

10voto

sebastian-c Points 5657

Une solution légèrement différente, proche du style de celle de @DWin :

Créez une matrice avec le triangle inférieur approprié (je ne pense pas que l'arrondi soit strictement nécessaire, mais sinon l'erreur de virgule flottante lui donne un aspect affreux) :

mat <- round(outer(seq(-0.5, 0.5, 0.1), seq(-0.5, 0.5, 0.1), `+`), 1)
mat

      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11]
 [1,] -1.0 -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2  -0.1   0.0
 [2,] -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1   0.0   0.1
 [3,] -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1  0.0   0.1   0.2
 [4,] -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1  0.0  0.1   0.2   0.3
 [5,] -0.6 -0.5 -0.4 -0.3 -0.2 -0.1  0.0  0.1  0.2   0.3   0.4
 [6,] -0.5 -0.4 -0.3 -0.2 -0.1  0.0  0.1  0.2  0.3   0.4   0.5
 [7,] -0.4 -0.3 -0.2 -0.1  0.0  0.1  0.2  0.3  0.4   0.5   0.6
 [8,] -0.3 -0.2 -0.1  0.0  0.1  0.2  0.3  0.4  0.5   0.6   0.7
 [9,] -0.2 -0.1  0.0  0.1  0.2  0.3  0.4  0.5  0.6   0.7   0.8
[10,] -0.1  0.0  0.1  0.2  0.3  0.4  0.5  0.6  0.7   0.8   0.9
[11,]  0.0  0.1  0.2  0.3  0.4  0.5  0.6  0.7  0.8   0.9   1.0

Inverser les colonnes

mat <- mat[,rev(seq.int(ncol(mat)))]

Retirez le triangle supérieur :

mat[upper.tri(mat)] <- NA

Inversez les colonnes :

mat <- mat[,rev(seq_len(ncol(mat)))]
mat

      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11]
 [1,]   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA   0.0
 [2,]   NA   NA   NA   NA   NA   NA   NA   NA   NA   0.0   0.1
 [3,]   NA   NA   NA   NA   NA   NA   NA   NA  0.0   0.1   0.2
 [4,]   NA   NA   NA   NA   NA   NA   NA  0.0  0.1   0.2   0.3
 [5,]   NA   NA   NA   NA   NA   NA  0.0  0.1  0.2   0.3   0.4
 [6,]   NA   NA   NA   NA   NA  0.0  0.1  0.2  0.3   0.4   0.5
 [7,]   NA   NA   NA   NA  0.0  0.1  0.2  0.3  0.4   0.5   0.6
 [8,]   NA   NA   NA  0.0  0.1  0.2  0.3  0.4  0.5   0.6   0.7
 [9,]   NA   NA  0.0  0.1  0.2  0.3  0.4  0.5  0.6   0.7   0.8
[10,]   NA  0.0  0.1  0.2  0.3  0.4  0.5  0.6  0.7   0.8   0.9
[11,]    0  0.1  0.2  0.3  0.4  0.5  0.6  0.7  0.8   0.9   1.0

Vous pouvez modifier les noms de domaine à partir de là.

EDIT : Étant donné qu'il y a tant de solutions, vous serez peut-être intéressé de voir comment elles se comparent. En utilisant microbenchmark :

Unit: microseconds
   expr       min         lq     median         uq       max
1 AGS()   682.491   738.9370   838.0955   892.8815  4518.740
2  DW()    23.244    27.1680    31.3930    34.8650    70.937
3 MvG() 15469.664 15920.4820 17352.3215 17827.4380 18989.270
4  SC()   118.629   131.4575   144.1360   157.7190   631.779

La solution de @DWin semble être la plus rapide, et de loin.

5voto

MvG Points 22342

Un moyen possible, en utilisant ma bibliothèque préférée actuelle :

library(plyr)
daply(expand.grid(x=seq(1,0,-.1), y=seq(0,1,.1)),
      .(y, x), with,
      if (x+y >= 1) x+y-1 else NA)

Cela donne le résultat suivant :

     x
y      0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9   1
  0   NA  NA  NA  NA  NA  NA  NA  NA  NA  NA 0.0
  0.1 NA  NA  NA  NA  NA  NA  NA  NA  NA 0.0 0.1
  0.2 NA  NA  NA  NA  NA  NA  NA  NA 0.0 0.1 0.2
  0.3 NA  NA  NA  NA  NA  NA  NA 0.0 0.1 0.2 0.3
  0.4 NA  NA  NA  NA  NA  NA 0.0 0.1 0.2 0.3 0.4
  0.5 NA  NA  NA  NA  NA 0.0 0.1 0.2 0.3 0.4 0.5
  0.6 NA  NA  NA  NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6
  0.7 NA  NA  NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7
  0.8 NA  NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8
  0.9 NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9
  1    0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0

L'idée est que le expand.grid crée un cadre de données de toutes les valeurs possibles des cellules. Vous pourriez tout aussi bien utiliser merge pour cela. Ensuite, vous appliquez une fonction à chacune de ces valeurs pour calculer le contenu de la cellule. Et vous avez daply transformer cela en une belle matrice pour vous, y compris les noms.

EDITAR:
OK, tu voulais que les colonnes soient étiquetées dans l'ordre inverse. ddply les classera par ordre croissant. Essayez donc ceci :

daply(expand.grid(x=seq(0,1,.1), y=seq(0,1,.1)),
      .(y, x), with,
      if (y-x >= 0) y-x else NA)[,11:1]

     x
y      1 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1   0
  0   NA  NA  NA  NA  NA  NA  NA  NA  NA  NA 0.0
  0.1 NA  NA  NA  NA  NA  NA  NA  NA  NA 0.0 0.1
  0.2 NA  NA  NA  NA  NA  NA  NA  NA 0.0 0.1 0.2
  0.3 NA  NA  NA  NA  NA  NA  NA 0.0 0.1 0.2 0.3
  0.4 NA  NA  NA  NA  NA  NA 0.0 0.1 0.2 0.3 0.4
  0.5 NA  NA  NA  NA  NA 0.0 0.1 0.2 0.3 0.4 0.5
  0.6 NA  NA  NA  NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6
  0.7 NA  NA  NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7
  0.8 NA  NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8
  0.9 NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9
  1    0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0

2voto

AGS Points 5594
require(matlab)
x=matrix(seq(0,1,.1),1)
X=x[rep(1,c(11)),]
X[upper.tri(X)]=NA
X=t(X)
for(a in 1:11){
  X[1:a,a]=rev(X[1:a,a])
}
X=flipud(X)
colnames(X) <- seq(1,0,by=-.1)
rownames(X) <- seq(0,1,by=.1)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X