2012-07-20 53 views
3

我确信这个答案已经到位,但我不认为我一直在使用正确的搜索条件。根据行和列名称添加矩阵

这是我的问题。我有多个矩阵(我将在这里简化为两个),其中每行是一个唯一标记的个体(其中一些在矩阵之间共享,其中一些不是)以及共享的共同列标题。

例如:

first<-matrix(rbinom(20,1,.5),4,5) 
first[,1]=c(122,145,186,199) 
colnames(first)<-c("ID",901,902,903,904) 
first 
     ID 901 902 903 904 
[1,] 122 1 0 0 0 
[2,] 145 0 0 0 1 
[3,] 186 0 0 1 1 
[4,] 199 1 0 0 0 

second<-matrix(rbinom(30,1,.5),6,5) 
second[,1]=c(122,133,142,151,186,199) 
colnames(second)<-c("ID",901,902,903,904) 
second 
     ID 901 902 903 904 
[1,] 122 0 1 1 1 
[2,] 133 0 0 0 1 
[3,] 142 1 1 0 1 
[4,] 151 0 1 0 0 
[5,] 186 1 0 1 1 
[6,] 199 1 0 0 0 

我想补充“第一”和“第二”一起基于“ID”和列名。这应该导致一个有7行的矩阵(因为'第一'矩阵中有4个ID,'第二'矩阵中有3个新ID和3个旧ID:“122,133,142,145,151,186,199”)和相同的列数。

在这个例子中,结果我想应该是:

 ID 901 902 903 904 
[1,] 122 1 1 1 1 
[2,] 133 0 0 0 1 
[3,] 142 1 1 0 1 
[4,] 145 0 0 0 1 
[5,] 151 0 1 0 0 
[6,] 186 1 0 2 2 
[7,] 199 2 0 0 0 

回答

1

我一直在寻找一个解决方案,而一个“为”使用内建函数没有成功循环。 因此,这里是我的方法

set.seed(1) # make it reproducible 
first <- matrix(rbinom(20,1,.5),4,5) 
first[ ,1] <- c(122, 145, 186, 199) 
colnames(first) <- c("ID", 901, 902, 903, 904) 

second <- matrix(rbinom(30, 1, .5), 6, 5) 
second[ ,1] <- c(122, 133, 142, 151, 186, 199) 
colnames(second) <- c("ID", 901, 902, 903, 904) 

first 

     ID 901 902 903 904 
[1,] 122 0 1 1 1 
[2,] 145 1 0 0 1 
[3,] 186 1 0 1 0 
[4,] 199 1 0 0 1 

second 
     ID 901 902 903 904 
[1,] 122 0 0 1 1 
[2,] 133 0 0 0 1 
[3,] 142 1 1 1 0 
[4,] 151 0 1 1 0 
[5,] 186 0 1 1 1 
[6,] 199 1 0 1 1 

## stack them rowise 
mat <- rbind(first, second) 

ind <- unique(mat[,"ID"]) 

result <- matrix(nrow = length(ind), ncol = 5) 
result[,1] <- ind 

for (i in seq_along(ind)) { 
    result[i,-1] <- colSums(mat[mat[ ,"ID"] == ind[i], -1, drop = FALSE]) 
} 
colnames(result) <- colnames(mat) 

result 
     ID 901 902 903 904 
[1,] 122 0 1 2 2 
[2,] 145 1 0 0 1 
[3,] 186 1 1 2 1 
[4,] 199 2 0 1 2 
[5,] 133 0 0 0 1 
[6,] 142 1 1 1 0 
[7,] 151 0 1 1 0 
1

我设置您的问题略有不同:

first <- matrix(rbinom(16,1,.5),4,4) 
rownames(first) <- c(122,145,186,199) 
colnames(first) <- c(901,902,903,904) 

second <- matrix(rbinom(24,1,.5),6,4) 
rownames(second) <- c(122,133,142,151,186,199) 
colnames(second) <- c(901,902,903,904) 

矩阵现在有一个名为rownames

> first 
    901 902 903 904 
122 1 0 0 1 
145 1 0 0 0 
186 0 0 1 1 
199 1 0 1 1 
> second 
    901 902 903 904 
122 1 1 0 0 
133 0 0 1 1 
142 1 0 1 0 
151 1 0 1 1 
186 0 1 0 1 
199 0 0 0 0 

现在很容易对排名进行设置操作:

SumOnID <- function(A, B){ 
    rnA <- rownames(A) 
    rnB <- rownames(B) 

    ls.id <- list(ids = intersect(rnA, rnB), #shared indices 
       idA = setdiff(rnA, rnB), #only in A 
       idB = setdiff(rnB, rnA)) #only in B 

    do.call(rbind, 
    lapply(names(ls.id), function(x){ 
     if (x == "ids") return(A[x,, drop = F] + B[x,, drop = F]) 
     if (x == "idA") return(A[x,, drop = F]) 
     if (x == "idB") return(B[x,, drop = F]) 
    })) 
} 

让我们试试吧:

> SumOnID(first, second) 
    901 902 903 904 
122 2 1 1 1 
186 1 1 0 1 
199 2 1 1 0 
145 1 1 0 1 
133 1 0 1 1 
142 1 0 1 0 
151 1 1 1 1 
2

原来的答复

大厦从@RYogi在您使用rownames和colnames来形容你的矩阵的方法,我提出以下建议:

res <- rbind(first,second) 
res <- tapply(res, expand.grid(dimnames(res)), sum) 

所有具有相同的rownames的行将被总结。

当使用数据帧

如果输入是data.frame,以上都不行,作为data.frame不能有任何重复的行名。另一种方法在这里也适用:

rowsum(rbind(first, second), c(rownames(first), rownames(second))) 

这种方法也适用于矩阵。由于它只需要一行,你可能会认为它更简单。我想这也可能更有效,因为它不如tapply

rowsum(rbind(first, second)[,-1], c(first[,1], second[,1])) 

注意,结果仍命名行,包含这些名称不是列:你可以从你的问题,那里的标识符在一个单独的列调整此解决方案中的数据格式。

有趣的是,我偶然读了rowsum,同时寻找rowSums这个问题的data.frame版本的一个相当复杂的方法。幸运的我。

附加提示

如果发现所产生的名字Var1Var2的尺寸混淆,您可以使用

names(dimnames(res)) <- NULL 

删除它们。如果你的数据真的是你所描述的格式,与行可以使用以下命令将它们更改为适当的行名称:

rownames(first) <- first[,1] 
first <- first[,-1] 
+0

'expand.grid'的工作原理与魔术类似。 – Ryogi 2012-07-20 23:16:00

+0

我不知道为什么,但是当我在我的真实数据集上使用rbind时(我使用ID作为rownames),重复的rownames在它们的末尾附加了一个数字。例如,如果ID#165320128出现3次,一行将是'165320128',下一个'1653201281'和最后一个'1653201282' – user1399311 2012-07-22 18:01:55

+1

@ user1399311,它可能是您的原始数据存储在数据帧而不是矩阵?看起来它们表现出您描述的行为,因为data.frame不允许重复的行名称。你可以将它们转换成矩阵,但我会编辑我的答案以提供更好的解决方案。 – MvG 2012-07-22 18:24:51