在R中,更改矩阵中某些项的值而不复制整个矩阵?

huangapple go评论116阅读模式
英文:

In R, change the values of some items in a matrix without causing a copy of the entire matrix?

问题

以下是您要翻译的代码部分:

MList <- list(M1, M2)
unionCols <- Reduce(union, lapply(MList, colnames))
MTotal <- matrix(as.double(rep(0, (length(unionCols))^2)), nrow = length(unionCols))
rownames(MTotal) <- colnames(MTotal) <- unionCols
DFTotal <- as.data.frame(MTotal)
DFList <- lapply(MList, as.data.frame)
for (i in 1:length(MList)) {
  tracemem(MTotal)
  tracemem(DFTotal)
  mCol <- match(colnames(MList[[i]]), colnames(MTotal))
  MTotal[mCol, mCol] <- MTotal[mCol, mCol] + MList[[i]] # this causes a copy
  DFTotal[mCol, mCol] <- DFTotal[mCol, mCol] + DFList[[i]] # this causes a copy
}
M1
M2
MTotal

# rbindlist method
.AggDMCMatsSingleM2 <- function(M1, M2) {
  .MyMelt <- function(M) {
    DT <- setnames(reshape2::melt(M, id.vars = colnames(M)), c('Var1', 'Var2'), c('row', 'col'))
  }
  M_total <- as.matrix(data.table::dcast(rbindlist(lapply(list(M1, M2), .MyMelt)),
                                         formula = as.formula(row ~ col),
                                         value.var = 'value',
                                         fun.aggregate = sum,
                                         fill = 0),
                       rownames = 'row')
  return(M_total)
}
M1
M2
.AggDMCMatsSingleM2(M1, M2)

希望这有所帮助。

英文:

I have a "small" square matrix that I want to add to a "big" matrix. The big matrix contains all the rows and columns of the small matrix plus extras. I want to add the values where the indices are in common and just keep the values from the big one where that index is not contained in the small one. Unfortunately, all the data is copied on the addition so it takes a long time and can temporarily spike memory when the matrices are large.

I have tried adding subsets using matrices and data.frames, as well as a data.table method using rbindlist. Both the data.frame and matrix methods seem to cause a memory copy (why?) and the rbindlist method is not ideal because it requires a melt and dcast and temporarily spiking the memory by spiking the number of rows.

Is there any way to just change the values of some items in a matrix without causing a copy of the entire matrix?

Here are my attempts:


MList &lt;- list(M1,M2)
unionCols &lt;- Reduce(union, lapply(MList, colnames))
MTotal &lt;- matrix(as.double(rep(0,(length(unionCols))^2)), nrow = length(unionCols))
rownames(MTotal) &lt;- colnames(MTotal) &lt;- unionCols
DFTotal &lt;- as.data.frame(MTotal)
DFList &lt;- lapply(MList, as.data.frame)
for(i in 1:length(MList)){
  tracemem(MTotal)
  tracemem(DFTotal)
  mCol &lt;- match(colnames(MList[[i]]), colnames(MTotal))
  MTotal[mCol,mCol] &lt;- MTotal[mCol,mCol] + MList[[i]] # this causes a copy
  DFTotal[mCol,mCol] &lt;- DFTotal[mCol,mCol] + DFList[[i]] # this causes a copy
}
M1
M2
MTotal

# rbindlist method
.AggDMCMatsSingleM2 &lt;- function(M1, M2){
  .MyMelt &lt;- function(M){
    DT &lt;- setnames(reshape2::melt(M, id.vars = colnames(M)), c(&#39;Var1&#39;,&#39;Var2&#39;), c(&#39;row&#39;,&#39;col&#39;))
  }
  M_total &lt;- as.matrix(data.table::dcast(rbindlist(lapply(list(M1,M2), .MyMelt)),
                                         formula = as.formula(row ~ col),
                                         value.var = &#39;value&#39;,
                                         fun.aggregate = sum,
                                         fill = 0),
                       rownames = &#39;row&#39;)
  return(M_total)
}
M1
M2
.AggDMCMatsSingleM2(M1,M2)

答案1

得分: 1

以下是代码部分的翻译:

如果我理解你的问题,我们可以直接使用小矩阵的行/列名称的方括号表示法将数据添加到大矩阵中:

big_matrix <- matrix(data=rep(1, 25), nrow=5, 
                   dimnames = list(c(LETTERS[1:5]), 
                                   c(letters[1:5])))
#  a b c d e
# A 1 1 1 1 1
# B 1 1 1 1 1
# C 1 1 1 1 1
# D 1 1 1 1 1
# E 1 1 1 1 1
small_matrix <- matrix(data=c(1:9), nrow=3, 
                     dimnames = list(c(LETTERS[2:4]), 
                                     c(letters[2:4])))
#  b c d
# B 1 4 7
# C 2 5 8
# D 3 6 9    
big_matrix[rownames(small_matrix), colnames(small_matrix)] <- 
  big_matrix[rownames(small_matrix), colnames(small_matrix)] + small_matrix

#  a b c  d e
# A 1 1 1  1 1
# B 1 2 5  8 1
# C 1 3 6  9 1
# D 1 4 7 10 1
# E 1 1 1  1 1

更复杂的测试:

big_matrix <- matrix(data=rep(1, 25), nrow=5, 
                   dimnames = list(c(LETTERS[1:5]), 
                                   c(letters[1:5])))
#  a b c d e
# A 1 1 1 1 1
# B 1 1 1 1 1
# C 1 1 1 1 1
# D 1 1 1 1 1
# E 1 1 1 1 1
small_matrix <- matrix(data=c(1:9), nrow=3, 
                     dimnames = list(c("A", "D", "C"), 
                                     c(letters[c(2:4)])))
#  b c d
# A 1 4 7
# D 2 5 8
# C 3 6 9

big_matrix[rownames(small_matrix), colnames(small_matrix)] <- 
  big_matrix[rownames(small_matrix), colnames(small_matrix)] + small_matrix
big_matrix
#  a b c  d e
# A 1 2 5  8 1
# B 1 1 1  1 1
# C 1 4 7 10 1
# D 1 3 6  9 1
# E 1 1 1  1 1
英文:

If I follow what you are asking we can directly add and write to the big matrix using the bracket notation row/col names of the small matrix:

big_matrix&lt;-matrix(data=rep(1, 25), nrow=5, 
                   dimnames = list(c(LETTERS[1:5]), 
                                   c(letters[1:5])))
#  a b c d e
#A 1 1 1 1 1
#B 1 1 1 1 1
#C 1 1 1 1 1
#D 1 1 1 1 1
#E 1 1 1 1 1
small_matrix&lt;-matrix(data=c(1:9), nrow=3, 
                     dimnames = list(c(LETTERS[2:4]), 
                                     c(letters[2:4])))
#  b c d
#B 1 4 7
#C 2 5 8
#D 3 6 9    
big_matrix[rownames(small_matrix), colnames(small_matrix)] &lt;- 
  big_matrix[rownames(small_matrix), colnames(small_matrix)] + small_matrix

#  a b c  d e
#A 1 1 1  1 1
#B 1 2 5  8 1
#C 1 3 6  9 1
#D 1 4 7 10 1
#E 1 1 1  1 1

More complex test:

big_matrix&lt;-matrix(data=rep(1, 25), nrow=5, 
                   dimnames = list(c(LETTERS[1:5]), 
                                   c(letters[1:5])))
#  a b c d e
#A 1 1 1 1 1
#B 1 1 1 1 1
#C 1 1 1 1 1
#D 1 1 1 1 1
#E 1 1 1 1 1
small_matrix&lt;-matrix(data=c(1:9), nrow=3, 
                     dimnames = list(c(&quot;A&quot;, &quot;D&quot;, &quot;C&quot;), 
                                     c(letters[c(2:4)])))
#  b c d
#A 1 4 7
#D 2 5 8
#C 3 6 9

    big_matrix[rownames(small_matrix), colnames(small_matrix)] &lt;- 
      big_matrix[rownames(small_matrix), colnames(small_matrix)] + small_matrix
big_matrix
#  a b c  d e
#A 1 2 5  8 1
#B 1 1 1  1 1
#C 1 4 7 10 1
#D 1 3 6  9 1
#E 1 1 1  1 1

huangapple
  • 本文由 发表于 2023年2月16日 03:22:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/75464551.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定