2
\$\begingroup\$

I have a matrix A containing numeric values and a matrix B containing 0/1s:

A <- matrix(1:25, 5, 5)
B <- matrix(c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0), 5, 5)

A                             B
1    6   11   16   21         0    0    1    0    0
2    7   12   17   22         0    0    0    0    1
3    8   13   18   23         0    0    0    0    1
4    9   14   19   24         0    0    1    0    0
5   10   15   20   25         0    0    1    0    0

I want to extract the elements of A where B==1 in row order. The desired result is:

11 22 23 14 15

I've come up with two possible ways to do this:

#1
rowSums(A*B)

#2
t(A)[as.logical(t(B))]

It seems like there should be a better (more elegant or faster) way to do this...

\$\endgroup\$
4
  • \$\begingroup\$ Did you profile both? \$\endgroup\$
    – Mast
    Aug 27, 2018 at 16:45
  • \$\begingroup\$ @Mast -- Not yet. In my application, my matrices are fairly small, but they occur in a loop that is called many times. I just figured that this would be a fairly common matrix operation, but I couldn't find "direct" way to implement it. \$\endgroup\$
    – DanY
    Aug 27, 2018 at 16:49
  • \$\begingroup\$ @Amstel made a point (that is now deleted), but maybe the "solution" is to store information as t(A) and t(B) instead of as A and B so that A[B] will work. \$\endgroup\$
    – DanY
    Aug 27, 2018 at 16:59
  • 3
    \$\begingroup\$ If how you store your information is up for changes/review, I'd recommend you replace the B matrix by a vector of indices, here b = c(3, 5, 5, 3, 3). (I am basing my assumption that there is only one 1 per row from your rowSums(A*B) suggestion). Storing the info in a vector is the most memory efficient. Then you could do A[cbind(seq_along(b), b)]. Otherwise I find t(A)[as.logical(t(B))] elegant enough and it is probably very fast. \$\endgroup\$
    – flodel
    Aug 28, 2018 at 2:15

2 Answers 2

1
\$\begingroup\$

While rowSums(A*B) looks pretty nice for me, you can also try

A[which(t(B) == 1, arr.ind = T)[,2:1]]
\$\endgroup\$
1
\$\begingroup\$

Although I don't have any substantial improvements, this is another way:

t(A)[t(B) == 1]

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.