R:如何生成每个 rowSum 为 1 的数据框

R: How do I generate a data frame with each rowSum is 1

我有一个包含 15 列和 11 行的数据框。行值从 0.0 到 1.0,增量为 0.1。我想做的是生成所有组合,但只保留每行总和为 1 的组合。我尝试使用 expand.grid 但显然有 15 列我 运行 内存不足。

例如,以下代码适用于 5 列,但我需要对 15 或 20 列执行相同的操作。

df <- data.frame(matrix(rep(seq(0.0,1.0,by=0.1),5), 11, 5))
df.grid <- expand.grid(df)
df.grid[which(rowSums(df.grid)==1),]

我确信有一种简单的方法可以做到这一点,但我是 R 的新手。

感谢您的帮助。

我想我可能已经从右侧的推荐帖子之一找到了答案。我还在检查。但答案在这里。

library("partitions")
numColumns <- 15 
numIncrements <- 10
weights <- t(compositions(n=numIncrements, m=numColumns, include.zero=TRUE)/numIncrements)
weights

您需要尽量减少计算机需要做的工作,因为您在这里要处理很多组合。首先,将您正在操作的数字集限制为最小集。鉴于 1 总和为 1,您不希望集合中有一个以上的 1。另一方面,您不希望超过 10 个 0.1。你可以得到完整的集合,然后,取1除以唯一数字序列的结果:

x <- seq(.1, 1, by = .1)    # initialize 0.1:1 sequence
x <- rep(x, floor(1/x))    # repeat minimal set for all combinations

只有27个号码:

> x
 [1] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.2 0.2 0.2 0.3 0.3 0.3 0.4 0.4 0.5 0.5 0.6
[24] 0.7 0.8 0.9 1.0

现在你需要循环 combn 组合中可能的项数,这将从 运行 从 1 到 1/min(x),即 10。然后我们可以索引到colSums == 1 的行(combn returns 组合作为列):

lapply(seq_len(1/min(x)), function(y){z <- combn(x, y); z[,colSums(z) == 1]})

考虑到大小(在我的笔记本电脑上 37 秒生成 10 个矩阵的 1Mb 列表),这在不合理的时间内工作,但它仍然 returns 很多 重复组合,因为每次迭代都包含比必要更多的某些数字的副本;例如选择 3 时,一秒 0.5 没有意义,否则 0.2 0.3 0.5 将返回两次。

它也不是一种非常方便的格式,因为所有矩阵都有不同的维度。如果我们在 combn 中添加一个函数来添加 NAs 这样每个组合的长度都是 10,那么 lapply 需要 2-3 倍的时间,但它确实可以让我们轻松组合它们与 do.call(rbind, ... ) 并因此很容易使用 unique.matrix 将其减少为独特的组合。

x <- seq(.1, 1, by = .1)    # initialize 0.1:1 sequence
x <- rep(x, floor(1/x))    # repeat minimal set for all combinations
results <- lapply(seq_len(max(x)/min(x)), function(y){
  # calculate combinations; fill lengths to 10 with NA to allow easy joining later
  z <- combn(x, y, function(x){c(x, rep(NA, 10 - y))})
  z[,colSums(z, na.rm = TRUE) == 1]})    # chop to combinations with sum == 1
results <- do.call(cbind, results)    # combine 10 matrices
results <- unique.matrix(results, MARGIN = 2)    # remove remaining repeats

或者,您可以用 unique.matrix 执行第二个 lapply 并在之后插入 NAs,这可能会更快,但上面的版本是一个很好的桥接案例不过接下来是什么。

如果我们优化可能有用的数字列表以在我们的循环中进行组合,我们可以计算出更多、更少的组合,从而显着加快该过程,使其几乎可以立即执行。仍然会有一些重复,因为有些数字对于某些组合需要比其他数字重复更多,但是我们可以使用上面的方法来简化:

results <- lapply(seq_len(10), function(y){
  x <- seq(.1, 1, by = .1)    # initialize 0.1:1 sequence
  # calculate minimum repititions of each number; .099 to avoid floating point error
  reps <- ifelse(y <= floor((1 - .1 * (y - 1)) / (x - .099)),
                 ifelse(y * x == 1, y, y - 1), 
                 floor((1 - .1 * (y - 1)) / (x - .099)) )
  x <- rep(x, reps)    # build set with necessary repeats
  # calculate combinations; fill lengths to 10 with NA to allow easy joining later
  z <- combn(x, y, FUN = function(x){c(x, rep(NA, 10 - y))})
  z[, colSums(z, na.rm = TRUE) == 1]    # chop to combinations with sum == 1
  })
results <- do.call(cbind, results)    # combine 10 matrices
results <- unique.matrix(results, MARGIN = 2)    # remove remaining repeats

请注意,reps 表达式在数学上可能并不理想,但会为此处的所有 10 次迭代生成正确的集合。 (如果你有更好的版本,欢迎评论!)

总而言之,您得到了一个包含 41 种组合的矩阵,您可能可以手写出来。

> results
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15] [,16]
 [1,]    1  0.1  0.2  0.3  0.4  0.5  0.1  0.1  0.1   0.1   0.2   0.2   0.2   0.3   0.1   0.1
 [2,]   NA  0.9  0.8  0.7  0.6  0.5  0.1  0.2  0.3   0.4   0.2   0.3   0.4   0.3   0.1   0.1
 [3,]   NA   NA   NA   NA   NA   NA  0.8  0.7  0.6   0.5   0.6   0.5   0.4   0.4   0.1   0.2
 [4,]   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA    NA    NA    NA    NA   0.7   0.6
 [5,]   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA    NA    NA    NA    NA    NA    NA
 [6,]   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA    NA    NA    NA    NA    NA    NA
 [7,]   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA    NA    NA    NA    NA    NA    NA
 [8,]   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA    NA    NA    NA    NA    NA    NA
 [9,]   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA    NA    NA    NA    NA    NA    NA
[10,]   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA    NA    NA    NA    NA    NA    NA
      [,17] [,18] [,19] [,20] [,21] [,22] [,23] [,24] [,25] [,26] [,27] [,28] [,29] [,30] [,31]
 [1,]   0.1   0.1   0.1   0.1   0.2   0.2   0.1   0.1   0.1   0.1   0.1   0.1   0.2   0.1   0.1
 [2,]   0.1   0.1   0.2   0.2   0.2   0.2   0.1   0.1   0.1   0.1   0.1   0.2   0.2   0.1   0.1
 [3,]   0.3   0.4   0.2   0.3   0.2   0.3   0.1   0.1   0.1   0.2   0.2   0.2   0.2   0.1   0.1
 [4,]   0.5   0.4   0.5   0.4   0.4   0.3   0.1   0.2   0.3   0.2   0.3   0.2   0.2   0.1   0.1
 [5,]    NA    NA    NA    NA    NA    NA   0.6   0.5   0.4   0.4   0.3   0.3   0.2   0.1   0.2
 [6,]    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA   0.5   0.4
 [7,]    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA
 [8,]    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA
 [9,]    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA
[10,]    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA
      [,32] [,33] [,34] [,35] [,36] [,37] [,38] [,39] [,40] [,41]
 [1,]   0.1   0.1   0.1   0.1   0.1   0.1   0.1   0.1   0.1   0.1
 [2,]   0.1   0.1   0.1   0.1   0.1   0.1   0.1   0.1   0.1   0.1
 [3,]   0.1   0.1   0.2   0.1   0.1   0.1   0.1   0.1   0.1   0.1
 [4,]   0.1   0.2   0.2   0.1   0.1   0.1   0.1   0.1   0.1   0.1
 [5,]   0.3   0.2   0.2   0.1   0.1   0.2   0.1   0.1   0.1   0.1
 [6,]   0.3   0.3   0.2   0.1   0.2   0.2   0.1   0.1   0.1   0.1
 [7,]    NA    NA    NA   0.4   0.3   0.2   0.1   0.2   0.1   0.1
 [8,]    NA    NA    NA    NA    NA    NA   0.3   0.2   0.1   0.1
 [9,]    NA    NA    NA    NA    NA    NA    NA    NA   0.2   0.1
[10,]    NA    NA    NA    NA    NA    NA    NA    NA    NA   0.1

真的有点虎头蛇尾。