user2323534
user2323534

Reputation: 595

R: Expand a vector of matrix column numbers into a matrix with those columns filled

I have two vectors in R and want to generate a new matrix based on them.

a=c(1,2,1,2,3)      # a[1] is 1: thus row 1, column 1 should be equal to...
b=c(10,20,30,40,50) # ...b[1], or 10.

I want to produce matrix 'v' BUT without my 'for' loop through columns of v and my multiplication:

v = as.data.frame(matrix(0,nrow=length(a),ncol=length(unique(a))))
for(i in 1:ncol(v)) v[[i]][a==i] <- 1   # looping through columns of 'v'
v <- v*b

I am sure there is a fast/elegant way to do it in R. At least of expanding 'a' into the earlier version of 'v' (before its multiplication by 'b').

Thanks a lot!

Upvotes: 1

Views: 1290

Answers (2)

Rick
Rick

Reputation: 898

# Setup the problem:
set.seed(4242)
a <- sample(1:100, 1000000, replace = TRUE)
b <- sample(1:500, length(a), replace = TRUE)  
# Start the timer 
start.time <- proc.time()[3]

# Actual code
# We use a matrix instead of a data.frame
# The  number of columns matches the largest column index in vector "a"
v <- matrix(0,nrow=length(a), ncol= max(a))
v[cbind(seq_along(a), a)] <- b

# Show elapsed time
stop.time <- proc.time()[3]
cat("elapsed time is: ", stop.time - start.time, "seconds.\n")

# For a million rows and a hundred columns, my prehistoric
# ... laptop says: elapsed time is:  2.597 seconds.

# these checks take much longer to run than the function itself
# Make sure the modified column in each row matches vector "a"
stopifnot(TRUE == all.equal(a, apply(v!=0, 1, which)))
# Make sure the modified value in each row equals vector "b"
stopifnot(TRUE == all.equal(rowSums(v), b))

Upvotes: 2

Gregor Thomas
Gregor Thomas

Reputation: 145785

This is one way that sparse matrices can be defined.

Matrix::sparseMatrix(i = seq_along(a), j = a, x = b)

Upvotes: 3

Related Questions