1
votes

Quel est le moyen le plus rapide de transformer ce vecteur en matrice symétrique?

toutes les personnes! Supposons que j'ai un vecteur de longueur n (n + 1) / 2:

a = (a_11, a_12, a_22, ...., a_nn) 

Maintenant, j'aimerais le transformer en une matrice symétrique, c'est à dire

entrez la description de l'image ici

Je pourrais attribuer la valeur une par une, mais je me demande s'il y en a plus rapidement pour créer cette matrice? Merci beaucoup!!

r

2 commentaires

Fournir un vecteur réel et la sortie attendue correspondante au lieu des indices faciliterait beaucoup la réponse.


est-ce le cas que a_12 dans le vecteur d'entrée doit être inséré à la fois dans a_12 et a_21 dans la matrice?


5 Réponses :


0
votes
 sq.m[ upper.tri(sq.m) ] <- sq.m[lower.tri(sq.m)]
> sq.m
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    2    3    5   10
[2,]    2    7    4    8   14
[3,]    3    8   13    9   15
[4,]    4    9   14   19   20
[5,]    5   10   15   20   25

6 commentaires

OP n'a pas n ^ 2 éléments dans le vecteur d'entrée. Je pense que l'intention est de dupliquer certains éléments sur la diagonale pour en créer un


Sa présentation du problème m'a suggéré qu'il avait n ^ 2 éléments. Quelle est votre preuve du contraire.?


Suppose I have a vector of length n(n+1)/2:


Vous n'avez donc que les éléments triangulaires inférieurs? Ah, maintenant je vois. Il n'a que les éléments triangulaires diagonaux et supérieurs.


Peu importe, c'est une matrice symétrique. Il peut être triangulaire supérieur ou inférieur.


@RonakShah Vous lisez mieux le problème que moi. Vous obtenez mon vote.



1
votes

Tu peux essayer :

#define n
n <- 2

#Create n(n+1)/2 objects in global environment
#OP already has that
a_11 <- 5
a_12 <- 9
a_22 <- 8

#Create n X n matrix with NA
mat <- matrix(nrow = n, ncol = n)
#Get all the individual objects in one vector
vec <- unlist(mget(ls(pattern = 'a_')), use.names = FALSE)
#Replace upper (or lower) triangular elements with it
mat[upper.tri(mat, diag = TRUE)] <- vec
#Copy the elements to other half.
mat[lower.tri(mat)] <- mat[upper.tri(mat)]

#      [,1] [,2]
#[1,]    5    9
#[2,]    9    8


0 commentaires

2
votes

Vous pouvez écrire une fonction qui fait ceci:

SI vous aviez votre vecteur comme a11,a12,a13..a1n,a22,a23..a2n, a33,..a3n,..ann Vous pouvez faire:

vec2mat <- function(x){
  p <- sqrt(1 + 8 * length(x))/ 2 - 0.5
  m <- matrix(0, p, p)
  m[upper.tri(m, diag = TRUE)] <- x
  m[lower.tri(m)] <- t(m)[lower.tri(m)]
  m
}
 vec2mat(1:10)
     [,1] [,2] [,3] [,4]
[1,]    1    2    4    7
[2,]    2    3    5    8
[3,]    4    5    6    9
[4,]    7    8    9   10

Maintenant:

vec2mat(1:6)
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    2    4    5
[3,]    3    5    6
vec2mat(1:10)
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    2    5    6    7
[3,]    3    6    8    9
[4,]    4    7    9   10

si vous aviez a11, a12,a22,a31, a32, a33...

vec2mat <- function(x){
  p <- sqrt(1 + 8 * length(x))/ 2 - 0.5
  m <- matrix(0, p, p)
  m[lower.tri(m, diag = TRUE)] <- x
  m[upper.tri(m)] <- (t(m))[upper.tri(m)]
  m
}


4 commentaires

Merci beaucoup :) Cela fonctionne vraiment!


pour 1000 éléments ça plante ... pourquoi ça?


@ManosPapadakis car vous ne pouvez pas avoir 1000 éléments. Notez que le nombre doit être un nombre triangulaire. c'est-à-dire le triangle inférieur ou triangle supérieur d'une matrice carrée comprenant la diagonale. donc le nombre, c'est-à-dire le vecteur, doit avoir une longueur de 990 s'il s'agit d'un carré de 44 lignes et 44 colonnes ou 1035 s'il s'agit d'un carré de 45 lignes et 45 colonnes.


Merci beaucoup!



1
votes

Vous pouvez créer une matrice clairsemée comme celle-ci:

a <- 1:6
n <- as.integer(-0.5 + sqrt(0.25 + 2 * length(a)))

library(Matrix)
sparseMatrix(x = a, dims = c(n, n), symmetric = TRUE, 
             i = sequence(1:n), j = rep(1:n, 1:n))
#3 x 3 sparse Matrix of class "dsCMatrix"
#          
#[1,] 1 2 4
#[2,] 2 3 5
#[3,] 4 5 6

Utilisez as.matrix sur le résultat si vous avez besoin d'une matrice dense. Si l'ordre de votre vecteur est différent de celui que vous montrez (par exemple, ligne-majeure comme le supposent certaines des autres réponses), vous devez ajuster légèrement le calcul de i et j .


0 commentaires

0
votes

si vous avez de gros vecteurs et que la vitesse compte, vous pouvez utiliser cette fonction (tirée de @Onyambu) qui utilise le package Rfast.

vec2mat_rfast <- function(x){
    p <- sqrt(1 + 8 * length(x))/ 2 - 0.5
    m <- matrix(0, p, p)
    m[Rfast::upper_tri(m, diag = TRUE)] <- x
    m[Rfast::lower_tri(m)] <- Rfast::transpose(m)[Rfast::lower_tri(m)]
    m
}

vec2mat <- function(x){
    p <- sqrt(1 + 8 * length(x))/ 2 - 0.5
    m <- matrix(0, p, p)
    m[upper.tri(m, diag = TRUE)] <- x
    m[lower.tri(m)] <- t(m)[lower.tri(m)]
    m
}

y=numeric(500500)


> microbenchmark::microbenchmark(a<-vec2mat(y),b<-vec2mat_rfast(y),times = 10)
Unit: milliseconds
                    expr     min       lq      mean    median       uq      max neval
         a <- vec2mat(y) 88.9461 101.5294 114.96752 108.86680 112.9854 180.9679    10
   b <- vec2mat_rfast(y) 33.1351  34.5294  49.61295  45.26955  62.8214  80.5069    10

> all.equal(a,b)
[1] TRUE


0 commentaires