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...

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Aug 27, 2018 at 16:37
\$\endgroup\$
4
  • \$\begingroup\$ Did you profile both? \$\endgroup\$ Commented 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\$ Commented 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\$ Commented 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\$ Commented 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]]
answered Aug 28, 2018 at 13:46
\$\endgroup\$
1
\$\begingroup\$

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

t(A)[t(B) == 1]
answered Aug 3, 2023 at 14:38
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.