Reputation: 23
I have two data frames as follows :
x<-data.frame("Trait1" =c(1,1,0,1),
"Trait2"=c(1,NA,1,1),
"Trait3" =c(0,1,0,1))
rownames(x)<-c("A","B","C","D")
y <- matrix(c("A","A","B","C","D","C"),
nrow = 2, ncol = 3, byrow = TRUE, dimnames = list(c("individual1", "individual2"),
c("Trait1","Trait2","Trait3")))
Such that:
x
Trait1 Trait2 Trait3
A 1 1 0
B 1 NA 1
C 0 1 0
D 1 1 1
y
Trait1 Trait2 Trait3
individual1 "A" "A" "B"
individual2 "C" "D" "C"
I need to match the row names of x with the values in y, and the column names in both data frames to get values for each individual as follows:
Trait1 Trait2 Trait3
individual1 1 1 1
individual2 0 1 0
Any suggestions would be much appreciated. Thanks.
Upvotes: 2
Views: 3476
Reputation: 287
Here's a proposal:
#make table of row coordinates
coordinaterow<-y
#make table of col coordinates
coordinatecol<-matrix(colnames(y),
nrow=nrow(y),
ncol=ncol(y),
byrow=TRUE)
#Use coordinates in mapply function to produce the final table.
finalresult<-y
finalresult[]<-mapply(function(r,c)
x[r,c],
coordinaterow,
coordinatecol,
SIMPLIFY = TRUE)
Upvotes: 0
Reputation: 2210
A possible solution with tidyverse : just a matter of joining tables using information about each treatment number and treatment name, so the first step is to transform (gather
) the two data sets into a common form where the treatment number and the treatment are both columns, not column names or row names.
library(dplyr)
library(tidyr)
x %>% mutate(v=rownames(.)) %>%
gather(k,w,-v) -> x1
y %>% as.data.frame(stringsAsFactors=FALSE) %>% mutate(ID=rownames(.)) %>%
gather(k,v,-ID) %>%
inner_join(x1,by=c("k","v")) %>%
select(-v) %>% spread(k,w)
# ID Trait1 Trait2 Trait3
#1 individual1 1 1 1
#2 individual2 0 1 0
Upvotes: 1
Reputation: 171
I don't really like my solution and I feel there should be a better way to do this but for the time being this should work(it's not that nice though).
Here's the code:
t(sapply(1:nrow(y),function(i) sapply(1:ncol(y),function(j) x[match(y[i,],rownames(x))
[j],j])))
Output:
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 0 1 0
Explanation:
match(y[i,],rownames(x))
The above matches each column of the i'th row of y to the rownames of x. For i=1 the result is:
[1] 1 1 2
Each element in this vector is the row's of x we'll use. Now we just need to match it to the columns of y(The order of the vector corresponds to the columns of y i.e element 1 corresponds to column 1(trait1) and element 2 to column 2(trait2)).So we apply to each column of y as follows:
For i=1
sapply(1:ncol(y),function(j) x[match(y[i,],rownames(x))[j],j])
#[1] 1 1 1
This is the first row of your new matrix now we just apply this to each row of y to get the other rows of the new matrix:
t(sapply(1:nrow(y),function(i) sapply(1:ncol(y),function(j)
x[match(y[i,],rownames(x))[j],j])))
*Note I take the transpose since sapply returns it per column.
Anyway this works and you can just name the the new matrix the same as with y but the solution is a bit complicated for something I feel should be simpler, so check if you can improve the code. Maybe sapply isn't needed if you can use the following statement a bit better:
i=1
match(y[i,],rownames(x))
Upvotes: 1