remplir lignes d'une matrice selon un ordre précis

Postez ici vos questions, réponses, commentaires ou suggestions - Les sujets seront ultérieurement répartis dans les archives par les modérateurs

Modérateur : Groupe des modérateurs

Fabrice Yaméogo
Messages : 24
Enregistré le : 22 Mar 2019, 10:09

remplir lignes d'une matrice selon un ordre précis

Messagepar Fabrice Yaméogo » 27 Fév 2021, 17:33

Bonjour,
Je dispose d'une matrice de 13 lignes et 12 colonnes constituée de 0.

Code : Tout sélectionner

mat<-matrix(0, ncol = 12, nrow = 13)
colnames(mat)<-rep(paste0("X",1:4),3)

La matrice "mat" est une matrice de contraintes. En colonnes, j'ai quatre variables de décision (X1,X2,X3,X4); chaque variable est répétée trois fois.
En lignes, j'ai des contraintes (au nombre de 13).
Lignes 1 à 4: contraintes de validité pour mes variables de décision.

Les autres variables de contrainte évoluent par groupe de 3.
Lignes 5 à 7: contraintes de ma première variable
Lignes 8 à 10: contraintes de ma deuxième variable
Lignes 11 à 13: contraintes de ma troisième variable

Je dispose également d'un dataframe

Code : Tout sélectionner

df<-structure(list(names = c("X1", "X2", "X3", "X4"),
car = c(1,1,1,1),                   
value1 = c(1,0,2,4),     
value2 = c(3,5,7,9)),
class = "data.frame", row.names = c(NA, -4L))   


L'objectif est de remplir les lignes de la matrice suivant un ordre et des conditions. Je souhaiterais obtenir une matrice de ce type à la fin:

Code : Tout sélectionner

nb<-4
for(i in 1:nb){
  mat[i,i] <- 1
  mat[i, nb+i] <- 1
  mat[i, (2*nb)+i] <- 1
}

mat[5,c(1:nb)] <- t(df$car)
mat[6,c((nb+1):(nb+4))] <- (df$car)
mat[7,c((nb+5):(nb+8))] <- (df$car)

mat[8,c(1:nb)] <- t(df$value1)
mat[9,c((nb+1):(nb+4))] <- t(df$value1)
mat[10,c((nb+5):(nb+8))] <- t(df$value1)

mat[11,c(1:nb)] <- t(df$value2)
mat[12,c((nb+1):(nb+4))] <- t(df$value2)
mat[13,c((nb+5):(nb+8))] <- t(df$value2)

mat


Je voudrais procéder en deux étapes pour y arriver.
1re étape: Je considère mes contraintes de validité (quatre premières lignes). Chaque ligne doit seulement être constituée du chiffre 1 trois fois.

2ème étape: Remplir les autres lignes de la matrice avec les données de mon dataframe en décalant à chaque fois.

Je sollicite de l'aide pour automatiser le code. Je dispose en réalité d'un dataframe de 500 lignes et de 11 variables. Mes variables de contraintes évoluent par groupe de 50. J'ai donc une matrice de 25.000 colonnes (500*50) et 1050 lignes (500 + 50*11).

J'ai lu qu'il est recommandé d'utiliser les matrices creuses (sparse matrix) dans de telles situations mais je ne sais pas comment procéder.

Merci d'avance pour l'aide.

Fabrice Yaméogo

Facundo Muñoz
Messages : 156
Enregistré le : 04 Juil 2019, 09:58
Contact :

Re: remplir lignes d'une matrice selon un ordre précis

Messagepar Facundo Muñoz » 28 Fév 2021, 20:56

Bonjour Fabrice,

le problème me semble très adapté pour construire la matrice par blocs.
Cette fonction fait l'affaire, et peut servir pour n'importe quelle dimension de problème.
L'utilisation de matrices sparse en option.

Code : Tout sélectionner

library(Matrix)  # Optionally, for sparse matrices.
build_cmat <- function(x) {
  n_decisions <- nrow(x)
  n_contraints <- ncol(x) - 1L
 
  ## Validity contraints
  validity_contraints <- do.call(
    "cbind",
    rep(list(diag(n_decisions)), n_contraints)
  )
 
  ## Optionally
  validity_contraints <- as(validity_contraints, "sparseMatrix")
 
  ## Contraints for the first variable
  c1 <- matrix(0, n_contraints**2, n_decisions)
  idx <- (seq.int(n_contraints) - 1) * n_contraints + 1
  c1[idx, ] <- t(as.matrix(df[, -1]))
 
  ## Optionally
  c1 <- as(c1, "sparseMatrix")
 
  ## Move the last r rows of a matrix to the beginning
  circ_shift_rows <- function (r, x) {
    n <- nrow(x)
    rbind(tail(x, r-n), head(x, n-r))
  }
 
  ## Contraints for all variables
  var_contraints <- do.call(
    "cbind",
    lapply(seq.int(n_contraints) - 1, circ_shift_rows, x = c1)
  )
 
  ans <- rbind(
    validity_contraints,
    var_contraints
  )

  rownames(ans) <- NULL
  colnames(ans) <- rep(x[, 1], times = n_contraints)  # or x$names
 
  return(ans)
}

identical(as.matrix(build_cmat(df)), mat)
#> [1] TRUE


Cordialement,
ƒacu.-

Fabrice Yaméogo
Messages : 24
Enregistré le : 22 Mar 2019, 10:09

Re: remplir lignes d'une matrice selon un ordre précis

Messagepar Fabrice Yaméogo » 01 Mar 2021, 12:29

Bonjour,

Merci pour la réponse et la fonction.

J'ai effectivement pu l'adapter à mon problème.

Cordialement

Fabrice


Retourner vers « Questions en cours »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 1 invité