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
4

3 回答 3

2

原始答案

基于@RYogi 的方法,您使用行名和列名来描述您的矩阵,我提出以下建议:

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

将汇总具有相同行名的所有行。

使用数据框时

如果您的输入是 a data.frame,则上述内容将不起作用,因为 adata.frame不能有任何重复的行名。另一种方法也适用于此:

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

这种方法也适用于矩阵。由于它只需要一行,您可能会认为它更简单。我想它也可能更有效,因为它不如tapply. 您可以将此解决方案调整为问题中的数据格式,其中标识符位于单独的列中:

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

请注意,结果仍将具有命名行,而不是包含这些名称的列。

有趣的是,我在这里以一种相当复杂的方法寻找这个问题的rowsum版本时无意中读到了。幸运的我。rowSumsdata.frame

附加提示

如果您发现生成的名称Var1Var2尺寸令人困惑,您可以使用删除它们

names(dimnames(res)) <- NULL

如果您的数据确实是您描述的格式,在第一个数据列中使用行名称,您可以使用以下命令将它们更改为正确的行名称:

rownames(first) <- first[,1]
first <- first[,-1]
于 2012-07-20T22:30:09.600 回答
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)

矩阵现在已命名为行名

> 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
于 2012-07-20T19:38:27.013 回答
1

我一直在寻找没有使用内置函数的“for”循环的解决方案,但没有成功。所以这是我的方法

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
于 2012-07-20T19:41:40.713 回答