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
中添加一个函数来添加 NA
s 这样每个组合的长度都是 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
并在之后插入 NA
s,这可能会更快,但上面的版本是一个很好的桥接案例不过接下来是什么。
如果我们优化可能有用的数字列表以在我们的循环中进行组合,我们可以计算出更多、更少的组合,从而显着加快该过程,使其几乎可以立即执行。仍然会有一些重复,因为有些数字对于某些组合需要比其他数字重复更多,但是我们可以使用上面的方法来简化:
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
真的有点虎头蛇尾。
我有一个包含 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
中添加一个函数来添加 NA
s 这样每个组合的长度都是 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
并在之后插入 NA
s,这可能会更快,但上面的版本是一个很好的桥接案例不过接下来是什么。
如果我们优化可能有用的数字列表以在我们的循环中进行组合,我们可以计算出更多、更少的组合,从而显着加快该过程,使其几乎可以立即执行。仍然会有一些重复,因为有些数字对于某些组合需要比其他数字重复更多,但是我们可以使用上面的方法来简化:
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
真的有点虎头蛇尾。