user3390169
user3390169

Reputation: 1045

R add arrays by column name

This seems really basic but I can't figure it out. How do you add two arrays together in R by column name? For example:

a<-matrix(1:9,ncol=3)
colnames(a)<-c("A","B","C")
a
#     A B C
#[1,] 1 4 7
#[2,] 2 5 8
#[3,] 3 6 9

b <-matrix(10:18,ncol=3)
colnames(b)<-c("C","B","D")
b
#      C  B  D
#[1,] 10 13 16
#[2,] 11 14 17
#[3,] 12 15 18

I would like to add them together in such a way to yield:

#      A  B  C  D
#[1,]  1 17 17 16
#[2,]  2 19 19 17
#[3,]  3 21 21 18

I suppose I could add extra columns to both matrices but it seems like there would be a one line command to accomplish this. Thanks!

Upvotes: 3

Views: 466

Answers (2)

akrun
akrun

Reputation: 887118

We could use melt/acast from reshape2 after cbinding both the 'a' and 'b' matrices (inspired from @thelatemail's post).

library(reshape2)
acast(melt(cbind(a,b)), Var1~Var2, value.var='value', sum)
#  A  B  C  D
#1 1 17 17 16
#2 2 19 19 17
#3 3 21 21 18

Or we find the column names that are common in both by using intersect, column names that is found in one matrix and not in other with setdiff. By subsetting both the matrices with the common names, we add it together, then cbind the columns in both 'a' and 'b' based on the setdiff output.

nm1 <- intersect(colnames(a), colnames(b))
nm2 <- setdiff(colnames(a), colnames(b))
nm3 <- setdiff(colnames(b), colnames(a))

cbind(a[,nm2, drop=FALSE], a[,nm1]+b[,nm1], b[,nm3,drop=FALSE])
#     A  B  C  D
#[1,] 1 17 17 16
#[2,] 2 19 19 17
#[3,] 3 21 21 18

Another option would be create another matrix with all the unique columns in 'a' and 'b', and then replace the values in that

nm <- union(colnames(a), colnames(b))
m1 <- matrix(0, ncol=length(nm), nrow=nrow(a), dimnames=list(NULL, nm))
m1[,colnames(a)] <- a
m1[,colnames(b)] <- m1[,colnames(b)] +b
m1
#     A  B  C  D
#[1,] 1 17 17 16
#[2,] 2 19 19 17
#[3,] 3 21 21 18

We could also cbind both the matrices and use tapply to get the sum after grouping with column and row indices

m2 <- cbind(a, b)
t(tapply(m2,list(colnames(m2)[col(m2)], row(m2)), FUN=sum))

Or we loop through 'nm' and get the sum

sapply(nm, function(i) rowSums(m2[,colnames(m2) ==i, drop=FALSE]))

Upvotes: 2

thelatemail
thelatemail

Reputation: 93813

Using xtabs , after melting a combined table to a long data.frame:

xtabs(Freq ~ ., data=as.data.frame.table(cbind(a,b)))
#    Var2
#Var1  A  B  C  D
#   A  1 17 17 16
#   B  2 19 19 17
#   C  3 21 21 18

The rownames will just be cycling through LETTERS

Upvotes: 3

Related Questions