[R] matrix values linked to vector index

arun smartpink111 at yahoo.com
Sat Oct 12 18:04:10 CEST 2013


This looks better.  My previous solution (makeMatrix2) also did the matrix indexing  without using sapply() route.  Replacing the max(x) by n for non-symmetric matrix:

makeMatrix2<- function(x,n){ #including "n"
 if(is.numeric(x)){
x <- as.integer(round(x))
x}
stopifnot(is.integer(x))
m1<- matrix(0,length(x),n) #change max(x) to n
 indx <- cbind(rep(seq_along(x),x),seq_len(sum(x))-rep(cumsum(c(0L,x[-length(x)])),x))
m1[indx]<- 1
m1}

identical(makeMatrix2(x3,4),makemx(x3,4))
#[1] TRUE

 identical(makeMatrix2(x1,5),makemx(x1,5))
#[1] TRUE

identical(makeMatrix2(x2,7),makemx(x2,7))
#[1] TRUE

A.K.






On Saturday, October 12, 2013 11:37 AM, Bert Gunter <gunter.berton at gene.com> wrote:
This seems to do it, but as I mentioned in my original post, my
"solution" was tricky. Thinking about it some more, I now realize that
it was too tricky and has the additional flaw of using underlying
representations of objects rather than their exposed interfaces -- i.e
it treats a matrix as a vector.

Here is, I think, a much better solution that treats a matrix as a
matrix by making use of a not-often-enough-used technique (mea culpa!)
of matrix indexing. It obviously needs to be cleaned up to check
inputs, etc. , but I think it should work. Feel free to publish and
clean up bugs.

makemx <- function(x,n)
{
  out <- matrix(0, nr=length(x), nc=n)
  ix <- cbind(rep(seq_along(x),x),unlist(sapply(x,seq_len)))
  out[ix]<- 1
  out
}

> makemx(c(3,2,1,4),4)
     [,1] [,2] [,3] [,4]
[1,]    1    1    1    0
[2,]    1    1    0    0
[3,]    1    0    0    0
[4,]    1    1    1    1
> makemx(c(3,2,1,4),5)
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    1    1    0    0
[2,]    1    1    0    0    0
[3,]    1    0    0    0    0
[4,]    1    1    1    1    0

Cheers,
Bert


On Sat, Oct 12, 2013 at 1:02 AM, arun <smartpink111 at yahoo.com> wrote:
>
>
> Modified Bert's solution for non-square matrices.  For the tested vectors, it worked.  There, could still be some bugs.
>
> x1<- c(3,2,1,4)
>  x2<- c(2,0,4,3,1)
> x3 <- c(2, 1, 2.2)
> x4 <- c("a",1,3)
>
> makeMat3 <- function(x,n){
>             if(is.numeric(x)){
> x <- as.integer(round(x))
> x}
> stopifnot(is.integer(x))
> indx<-rep(rep(c(1,0),n),c(as.vector(rbind(x,n-x)),rep(c(0,n),n-length(x))))
>  matrix(indx[seq_len(length(indx)-(n*(n-length(x))))],nc=n,byr=TRUE)
> }
> makeMat3(x1,4)
> makeMat3(x1,5)
> makeMat3(x1,6)
> makeMat3(x1,7)
>
>
> makeMat3(x2,7)
> makeMat3(x2,6)
> makeMat3(x2,4) # as length of vector > n
> #Error in rep(c(0, n), n - length(x)) : invalid 'times' argument
>
> makeMat3(x3,4)
> makeMat3(x3,5)
>
>  makeMat3(x4,4)
> #Error: is.integer(x) is not TRUE
>
> makeMat3(c(4,0,1,0,6),6)
>
> A.K.
>
>
>
> On Saturday, October 12, 2013 1:40 AM, Bert Gunter <gunter.berton at gene.com> wrote:
> Your examples are the problem:
>
> On Fri, Oct 11, 2013 at 2:43 PM, arun <smartpink111 at yahoo.com> wrote:
>> Seems like a bug in the code:
>> x<- c(3,4,1)
>> n<- 3
>>  matrix(rep(rep(c(1,0),n),rbind(x,n-x)),nc=n,byr=TRUE)
>> #Error in rep(rep(c(1, 0), n), rbind(x, n - x)) : invalid 'times' argument
>
> ## This can't work since x specifies 4 1's in the second row but you
> have specified a 3 column matrix with n.
>
>>  n<- 4
>>  matrix(rep(rep(c(1,0),n),rbind(x,n-x)),nc=n,byr=TRUE)
>> #Error in rep(rep(c(1, 0), n), rbind(x, n - x)) : invalid 'times' argument
>
> Yes, this shows that my claim that non-square matrices also work is
> false. I leave it as an exercise to fix it so that it works for
> non-square matrices.
>
> Cheers,
> Bert
>
>
>
>> x2
>> [1] 2 0 4 3 1
>>> matrix(rep(rep(c(1,0),n),rbind(x2,n-x2)),nc=n,byr=TRUE)
>> Error in rep(rep(c(1, 0), n), rbind(x2, n - x2)) :
>>   invalid 'times' argument
>>
>>
>> A.K.
>>
>>
>>
>>
>> On Friday, October 11, 2013 5:17 PM, Bert Gunter <gunter.berton at gene.com> wrote:
>> simpler (and sloppier) but with **no looping or apply's **
>>
>> **IFF* the matrix is structured as in the OP's example, then lower.tri
>> (or upper.tri) should be used:
>>
>> n <- 4 ## number of columns in matrix -- note that I changed it from
>> the example; does not have to be square
>>
>> x <- 1:3 ## the number of 1's per row
>> lower.tri(matrix(0,nr=length(x),nc=n),diagA=TRUE)+0
>>
>> A general, fast, but **tricky** way to do it that depends on knowing
>> that a matrix is just a vector in column major order is to generate
>> the vector using rep and then structure it as a matrix. eg.
>>
>> x <- c(3,2,1,4) ## your vector of indices
>> n <- 4 ## number of columns in matrix ## does not have to be square
>> matrix(rep(rep(c(1,0),n),rbind(x,n-x)),nc=n,byr=TRUE)
>>
>>     [,1] [,2] [,3] [,4]
>> [1,]    1    1    1    0
>> [2,]    1    1    0    0
>> [3,]    1    0    0    0
>> [4,]    1    1    1    1
>>
>>
>> Cheers,
>> Bert
>>
>> On Fri, Oct 11, 2013 at 1:41 PM, Dennis Murphy <djmuser at gmail.com> wrote:
>>> Attempting to follow the OP's conditions and assuming I understood
>>> them correctly, here is one way to wrap this up into a function:
>>>
>>> makeMat <- function(x)
>>> {
>>>     stopifnot(is.integer(x))
>>>     nr <- length(x)
>>>     nc <- max(x)
>>>
>>>     # Initialize a matrix of zeros
>>>     m <- matrix(0, nr, nc)
>>>     # Conditionally replace with ones
>>>     for(i in seq_len(nr)) if(x[i] != 0)  m[i, 1:x[i]] <- 1
>>>     m
>>> }
>>>
>>> ## Examples:
>>> x1 <- 1:3
>>> x2 <- as.integer(c(2, 0, 4, 3, 1))
>>> x3 <- c(2, 1, 2.2)
>>>
>>> makeMat(x1)
>>> makeMat(x2)
>>> makeMat(x3)
>>> makeMat(4:6)
>>>
>>>
>>> On Fri, Oct 11, 2013 at 9:49 AM, arun <smartpink111 at yahoo.com> wrote:
>>>> Hi,
>>>>
>>>> In the example you showed:
>>>>
>>>> m1<- matrix(0,length(vec),max(vec))
>>>> 1*!upper.tri(m1)
>>>>
>>>> #or
>>>>  m1[!upper.tri(m1)] <-  rep(rep(1,length(vec)),vec)
>>>>
>>>> #But, in a case like below, perhaps:
>>>> vec1<- c(3,4,5)
>>>>
>>>>  m2<- matrix(0,length(vec1),max(vec1))
>>>>  indx <- cbind(rep(seq_along(vec1),vec1),unlist(tapply(vec1,list(vec1),FUN=seq),use.names=FALSE))
>>>> m2[indx]<- 1
>>>>  m2
>>>> #     [,1] [,2] [,3] [,4] [,5]
>>>> #[1,]    1    1    1    0    0
>>>> #[2,]    1    1    1    1    0
>>>> #[3,]    1    1    1    1    1
>>>>
>>>>
>>>>
>>>>
>>>> A.K.
>>>>
>>>>
>>>> Hi-
>>>>
>>>> I'd like to create a matrix of 0's and 1's where the number of
>>>> 1's in each row defined by the value indexed in another vector, and
>>>> where the (value-1) is back-filled by 0's.
>>>>
>>>> For example, given the following vector:
>>>> vec= c(1,2,3)
>>>>
>>>> I'd like to produce a matrix with dimensions (length(vec), max(vec)):
>>>>
>>>> 1,0,0
>>>> 1,1,0
>>>> 1,1,1
>>>>
>>>> Thank you!
>>>>
>>>> ______________________________________________
>>>> R-help at r-project.org mailing list
>>>> https://stat.ethz.ch/mailman/listinfo/r-help
>>>> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
>>>> and provide commented, minimal, self-contained, reproducible code.
>>
>>>
>>> ______________________________________________
>>> R-help at r-project.org mailing list
>>> https://stat.ethz.ch/mailman/listinfo/r-help
>>> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
>>> and provide commented, minimal, self-contained, reproducible code.
>>
>>
>>
>> --
>>
>> Bert Gunter
>> Genentech Nonclinical Biostatistics
>>
>> (650) 467-7374

>
>>
>
>
>
> --
>
> Bert Gunter
> Genentech Nonclinical Biostatistics
>
> (650) 467-7374
>



-- 

Bert Gunter
Genentech Nonclinical Biostatistics

(650) 467-7374




More information about the R-help mailing list