Domanda

I'm trying to define a function manipulating matrices of strings in R.

{+,*} MATRICES MULTIPLICATION

The {+,*}-product of two square matrices A and B of dimension n is a matrix C defined by the elements: Ci,j = Sumk=1,...,nAi,k * Bk,j.

For example, consider the matrix M <- matrix(c(a,b,0,0,c,d,0,0,e),3,3). Then M times M is M <- matrix(c(a^2,a*b+b*c,b*d,0,c^2,c*d+d*e,0,0,e^2),3,3).

{c(,),paste0(,)} MATRICES MULTIPLICATION

The rule of this operation I would like to implement are the same of the previous stated multiplication with the essential mutation that the sum should be a concatenation and the product should be a paste. In other words, where in the previous formula we found a+b, now the output should be "c(a,b)", and when we found a*b, now we should read this as paste0(a,b).

Some of the usual properties have to be respescted, namely the distributive properties and the 0 element properties. Hence, if a <- c("q",0,"w") and b <- c("e") then a*b <- c("qe",0,"we") (and we should freely forget the 0 element, dropping it as it won't affect the computation.

Moreover, we are multiplying equaldimensioned matrices, hence each element Ci,j = Sumk=1,...,nAi,k * Bk,j is now to be read as c("A[i,1]B[1,j]",...,"A[i,n]B[n,j]").

For semplicity sakeness, let's consider B always a simple matrix, meaning that each of its elements are atomic string, and not concatenation of string (the generalization is a subsequent step).

Let's give an example. Let A <- matrix(c("a","b",0,0,"c","d",0,0,"e"),3,3), then mult(A,A) = matrix(c("aa",c("ab","bc"),"bd",0,"cc",c("cd","de"),0,0,"ee"),3,3) and mult(mult(A,A),A) = matrix(c("aaa",c("aab","abc","bcc"),c("abd","bcd","bde"),0,"ccc",c("ccd","cde","dee"),0,0,"eee"),3,3).

PARTIAL (NOT WORKING) IMPLEMENTATION

Consider as input a couple of nxn matrices M , N with whether 0 or array of strings c(s1,s2,...) as i,j elements. As output I would like to have a matrix MN = M x N where the multiplication is defined in analogy with the symbolic multiplication:

MNi,j = 0 if Mi,. or N.,j is 0
MNi,j = paste(Mi,.,N.,j) otherwise (using the distributive property of paste())

I gave a (wrong, does not check properly the zeros) definition of the base row/column paste function as

MijPaste <- function(Row,Col){
  if(Col[1]=="0"){
    Mij <- 0
  } else if(Row[1]=="0"){
      Mij <- 0
    } else
      Mij <- paste(Row,Col,sep="")
  return(Mij)
}

I've not been able to go from this step to a proper definition of the multiplication function, as the element Mij that I would like to insert inside the matrix are not of the right dimension. And hence I get a number of items to replace is not a multiple of replacement length error. My current implementation is:

# define the dimension of the matrix, here for example 3
dim <- 3
# define the Multiplication function as an iteration of the MijPaste function
Mult <- function(M1,M2){
    #allocate a matrix of dimension nxn
    M <-  matrix(0,dim,dim)
    #for each element i,j define it as the MijPaste of row i column j
      for(i in 1:dim){
      for(j in 1:dim){
        stringi <- M1[i,]
        stringj <- M2[,j]
        M[i,j] <- MijPaste(stringi,stringj)
      }
    }
  return(M)
}

The code doesn't work. I could probably change the matrix into a multidimensional array, but I would like the output to be usable as a matrix for further multiplication (for example to defin (MxN)xC).

How can I do?

Thank you!

P.S. You can test the code using a simple example matrix

Matr <- matrix(c("11","12","13","21","22","23","31","32","33"),dim,dim)

and running

Mult(Matr,Matr)
È stato utile?

Soluzione

You can use paste directly with the matrices, if you set the dimensions manually:

MN <- matrix(paste(M, N, sep=""), nrow=nrow(M), ncol=ncol(M))

Now filter the zeros and replace:

MN[(M==0) | (N==0)] <- 0

EDIT: the pointwise product shown above is NOT what the OP wants.

As I said in the comment, you can fix your function adding collapse="" to your first function. I get the following results:

> M <- matrix(LETTERS[1:9],3,3)
> N <- matrix(LETTERS[10:18],3,3)

> M
     [,1] [,2] [,3]
[1,] "A"  "D"  "G" 
[2,] "B"  "E"  "H" 
[3,] "C"  "F"  "I" 
> N
     [,1] [,2] [,3]
[1,] "J"  "M"  "P" 
[2,] "K"  "N"  "Q" 
[3,] "L"  "O"  "R" 

> Mult(M,N)
     [,1]     [,2]     [,3]    
[1,] "AJDKGL" "AMDNGO" "APDQGR"
[2,] "BJEKHL" "BMENHO" "BPEQHR"
[3,] "CJFKIL" "CMFNIO" "CPFQIR"

As you can see, your function matches the elements in matrices M and N before pasting.

If you want to keep the elements of each matrix together, you can use these two lines:

> coll <- function(x)paste(x,collapse="")
> outer(apply(M,1,coll),apply(N,2,coll),paste0)
     [,1]     [,2]     [,3]    
[1,] "ADGJKL" "ADGMNO" "ADGPQR"
[2,] "BEHJKL" "BEHMNO" "BEHPQR"
[3,] "CFIJKL" "CFIMNO" "CFIPQR"

Of course, you have to insert the zeros manually after this.

Altri suggerimenti

pmat <- function(m1, m2) matrix(
          ifelse(m1=="0"|m2=="0", "0", paste0(m1,m2) ) ,
                            dim(m1)[1], dim(m1)[2] )


> pmat(Matr, Matr)
     [,1]   [,2]   [,3]  
[1,] "1111" "2121" "3131"
[2,] "1212" "2222" "3232"
[3,] "1313" "2323" "3333"

I couldn't tell whether you were ready for the dimensional multiplication or not. If you expect N elements per index then you want the kronecker function, which will require a slightly different function:

Insert:

Maybe you should have posted a better test case? Then you could have been more explicit about what you wanted. This shows how kronecker-applied pmat rearranged as an array will give you MN[1,1] as the 1st column of the first matrix:

 M <- matrix(c("a1","b1","c1","0"),2,2)
 N <- matrix(c("c2","d2","e2","f2"),2,2)
 MN <- array( kmat,c( 2,2,4))
 MN[ , 1,1]
#[1] "a1c2" "a1d2"

> pmat <- function(m1, m2) matrix( ifelse(m1=="0"|m2=="0", "0", paste0(m1,m2) )  )
> kronecker(Matr, Matr, pmat)
      [,1]   [,2]   [,3]   [,4]   [,5]   [,6]   [,7]   [,8]   [,9]  
 [1,] "1111" "1121" "1131" "2111" "2121" "2131" "3111" "3121" "3131"
 [2,] "1112" "1122" "1132" "2112" "2122" "2132" "3112" "3122" "3132"
 [3,] "1113" "1123" "1133" "2113" "2123" "2133" "3113" "3123" "3133"
 [4,] "1211" "1221" "1231" "2211" "2221" "2231" "3211" "3221" "3231"
 [5,] "1212" "1222" "1232" "2212" "2222" "2232" "3212" "3222" "3232"
 [6,] "1213" "1223" "1233" "2213" "2223" "2233" "3213" "3223" "3233"
 [7,] "1311" "1321" "1331" "2311" "2321" "2331" "3311" "3321" "3331"
 [8,] "1312" "1322" "1332" "2312" "2322" "2332" "3312" "3322" "3332"
 [9,] "1313" "1323" "1333" "2313" "2323" "2333" "3313" "3323" "3333"
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top