问题
I have 2 adjacency matrices with different dimesnsions. I want to make their dimensions compatible so that when I replace any column of one matrix from any column of second matrix then I don't get the following error message: Error: number of items to replace is not a multiple of replacement length Here are my matrices:
> mat1
Tommy Roy Addy Sam
Tommy 0 1 0 -1
Roy -1 -1 1 0
Addy 1 0 -1 0
Sam 0 0 -1 1
> mat2
Mike Roy Addy Sam Dan
Mike 0 1 0 -1 0
Roy -1 -1 1 0 1
Addy 1 0 -1 0 -1
Sam 0 0 -1 1 0
Dan 1 0 0 -1 1
To make the mat1 compatible to mat2 I have to add 2 columns and 2 rows in mat1, so that it become:
> newMat1
Tommy Roy Addy Sam Mike Dan
Tommy 0 1 0 -1 0 0
Roy -1 -1 1 0 0 0
Addy 1 0 -1 0 0 0
Sam 0 0 -1 1 0 0
Mike 0 0 0 0 0 0
Dan 0 0 0 0 0 0
Here 2 new column and rows have been added (Mike
and Dan
) as they were not there before but were part of the second matrix. Please notice that newly added rows and columns have been initialized with 0
value. Similarly newMat2 will become:
> newMat2
Mike Roy Addy Sam Dan Tommy
Mike 0 1 0 -1 0 0
Roy -1 -1 1 0 1 0
Addy 1 0 -1 0 -1 0
Sam 0 0 -1 1 0 0
Dan 1 0 0 -1 1 0
Tommy 0 0 0 0 0 0
Here are the original matrices dput:
> dput(mat1)
structure(c(0L, -1L, 1L, 0L, 1L, -1L, 0L, 0L, 0L, 1L, -1L, -1L,
-1L, 0L, 0L, 1L), .Dim = c(4L, 4L), .Dimnames = list(c("Tommy",
"Roy", "Addy", "Sam"), c("Tommy", "Roy", "Addy", "Sam")))
> dput(mat2)
structure(c(0L, -1L, 1L, 0L, 1L, 1L, -1L, 0L, 0L, 0L, 0L, 1L,
-1L, -1L, 0L, -1L, 0L, 0L, 1L, -1L, 0L, 1L, -1L, 0L, 1L), .Dim = c(5L,
5L), .Dimnames = list(c("Mike", "Roy", "Addy", "Sam", "Dan"),
c("Mike", "Roy", "Addy", "Sam", "Dan")))
EDIT:
As mentioned in question, I want to later replace the the columns between the matrices and problem is that when I do this the different ordering of colnames and rownames affect the values in the indices. for example:
Change <- c("Mike", "Dan")
for(i in 1:length(Change)){
ifelse(Change[i] %in% colnames(newMat1), newMat1[,Change[i]] <- newMat2[,Change[i]], newMat1[,Change[i]][newMat1[,Change[i]] == 1] <- 0)}
newMat1
Tommy Roy Addy Sam Mike Dan
Tommy 0 1 0 -1 0 0
Roy -1 -1 1 0 -1 1
Addy 1 0 -1 0 1 -1
Sam 0 0 -1 1 0 0
Mike 0 0 0 0 1 1
Dan 0 0 0 0 0 0
Here the Mike column in newMat1 has been replaced by Mike column in newMat2. As you can see that index Mike-to-Mike is 0 in original newMat2 but it is 1 in freshly obtained newMat1, and that is because of ordering of rownames and colnames is different.
Answer: For this purpose ordering was required and it was done by:
newMat2 <- newMat2[rownames(newMat1), colnames(newMat1)]
回答1:
A simple function:
complete_matrix <- function(mat, ref) {
dif <- setdiff(rownames(ref), rownames(mat))
mat <- rbind(mat, matrix(0, length(dif), ncol(mat), dimnames = list(dif, NULL)))
mat <- cbind(mat, matrix(0, nrow(mat), length(dif), dimnames = list(NULL, dif)))
return(mat)
}
newMat1 <- complete_matrix(mat1, mat2)
newMat2 <- complete_matrix(mat2, mat1)
It first finds the missing names between the focal matrix mat
and the reference matrix ref
, then binds two matrices with 0s for the missing names..
> newMat1
Tommy Roy Addy Sam Mike Dan
Tommy 0 1 0 -1 0 0
Roy -1 -1 1 0 0 0
Addy 1 0 -1 0 0 0
Sam 0 0 -1 1 0 0
Mike 0 0 0 0 0 0
Dan 0 0 0 0 0 0
> newMat2
Mike Roy Addy Sam Dan Tommy
Mike 0 1 0 -1 0 0
Roy -1 -1 1 0 1 0
Addy 1 0 -1 0 -1 0
Sam 0 0 -1 1 0 0
Dan 1 0 0 -1 1 0
Tommy 0 0 0 0 0 0
Another solution:
complete_matrix2 <- function(mat, ref) {
nam <- union(rownames(ref), rownames(mat))
out <- matrix(0, length(nam), length(nam), dimnames = list(nam, nam))
out[rownames(mat), colnames(mat)] <- mat
return(mat)
}
回答2:
The following will do it.
m1 <- setdiff(rownames(mat2), rownames(mat1))
newMat1 <- rbind(mat1, matrix(0, nrow = length(m1), ncol = ncol(mat1)))
newMat1 <- cbind(newMat1, matrix(0, nrow = nrow(newMat1), ncol = length(m1)))
rownames(newMat1) <- c(rownames(mat1), m1)
colnames(newMat1) <- c(colnames(mat1), m1)
m2 <- setdiff(rownames(mat1), rownames(mat2))
newMat2 <- rbind(mat2, matrix(0, nrow = length(m2), ncol = ncol(mat2)))
newMat2 <- cbind(newMat2, matrix(0, nrow = nrow(newMat2), ncol = length(m2)))
rownames(newMat2) <- c(rownames(mat2), m2)
colnames(newMat2) <- c(colnames(mat2), m2)
Since the code repeats, it would be possible to write a function. If this is a one time problem, there's really no reason for it, but if you have more such problems, say so.
回答3:
Maybe a bit overkill, but here's a general solution:
library(tidyverse)
imap_dfr(list(mat1,mat2),~ .x %>%
as.data.frame(stringsAsFactors=F) %>%
mutate(v = row.names(.),mat = .y) %>%
gather(h,value,-(ncol(.)+c(0,-1)))) %>%
right_join(expand(.,v,h,mat)) %>%
replace_na(list(value=0)) %>%
split(.$mat) %>%
map(. %>%
spread(h,value,0) %>%
`row.names<-`(.$v) %>%
select(-v,-mat) %>%
as.matrix)
$`1`
Addy Dan Mike Roy Sam Tommy
Addy -1 0 0 0 0 1
Dan 0 0 0 0 0 0
Mike 0 0 0 0 0 0
Roy 1 0 0 -1 0 -1
Sam -1 0 0 0 1 0
Tommy 0 0 0 1 -1 0
$`2`
Addy Dan Mike Roy Sam Tommy
Addy -1 -1 1 0 0 0
Dan 0 1 1 0 -1 0
Mike 0 0 0 1 -1 0
Roy 1 1 -1 -1 0 0
Sam -1 0 0 0 1 0
Tommy 0 0 0 0 0 0
来源:https://stackoverflow.com/questions/46295687/r-how-to-make-2-adjacency-matrices-compatible-to-eachother