在 R 中有条件地添加列元素
Adding column elements conditionally in R
可重现的例子:
set.seed(1)
testMat <- matrix(round(runif(3*6,1,5)), nrow = 3, ncol = 6)
输出:
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 2 5 5 1 4 3
[2,] 2 2 4 2 3 4
[3,] 3 5 4 2 4 5
此处前 3 列 (1,2,3) 属于一组,接下来的 3 列 (4,5,6) 属于另一组。我想从每组中添加一列,并且需要为所有可能的组合添加一列。
对于这个例子,我应该得到 9 个结果向量,因为有 9 种组合:
Combination 1: (1,4) = (3,4,5)
Combination 2: (1,5) = (6,5,7)
Combination 3: (1,6) = (.,.,.)
Combination 4: (2,4) = (.,.,.)
Combination 5: (2,5) = (.,.,.)
Combination 6: (2,6) = (.,.,.)
Combination 7: (3,4) = (.,.,.)
Combination 8: (3,5) = (.,.,.)
Combination 9: (3,6) = (.,.,.)
有什么优雅的方法可以做到这一点,尤其是当列数可以更高时?例如 9、12 等将分别产生 27 和 81 的组合。
编辑:更多说明:每 3 列(例如 1:3、4:6、7:9、10:12、...等)构造一组,然后objective是每组取1列相加。例如,如果我们在 testMat 中有 6 列,我们从 1:3 中取 1 列,从 4:6 中取另一列,将 tese 2 列加在一起。类似地,对于 9,我们添加 3,对于 12,我们从每个集合中添加 4 列。
expand.grid 会出奇地有用:
nc <- ncol( testMat )
if( nc %% 3 != 0 ) {
stop( "Your data's number of columns should be a multiple of 3!")
}
n <- ncol( testMat ) / 3
args <- sapply( 1:n, function(i) (i*3-2):(i*3), simplify=FALSE )
combs <- do.call( expand.grid, args ) %>% arrange( Var1 )
combs %>% apply( 1, function(r) {
rowSums( testMat[, r] )
})
输出:
> combs %>% apply( 1, function(r) {
+ rowSums( testMat[, r ] )
+ })
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,] 3 6 5 6 9 8 6 9 8
[2,] 4 5 6 4 5 6 6 7 8
[3,] 5 7 8 7 9 10 6 8 9
这是一种方法:
#Create a sequence from 1 to number of columns in the data
cols <- seq(ncol(testMat))
n <- 3
#Create a list of every n columns and use expand.grid
#to create all possible combinations
vals <- expand.grid(split(cols, ceiling(cols/n)))
#RowSums every combination using `sapply`.
sapply(asplit(vals, 1), function(x) rowSums(testMat[, x]))
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
#[1,] 3 6 6 6 9 9 5 8 8
#[2,] 4 4 6 5 5 7 6 6 8
#[3,] 5 7 6 7 9 8 8 10 9
这是一种使用 rcppalgos 生成排列的方法:
library(RcppAlgos)
my_vals = function (...) {
dots = list(...)
ncols = ...length()
cols = permuteGeneral(3L, ncols, TRUE)
Reduce(`+`, Map(`[`, dots, asplit(cols,2L)))
}
do.call('my_fun', asplit(array(testMat, c(3L, 3L, ncol(testMat) / 3L)), 3L))
这种方法将矩阵转换为子矩阵列表,然后通过排列对子矩阵进行子矩阵化。
可重现的例子:
set.seed(1)
testMat <- matrix(round(runif(3*6,1,5)), nrow = 3, ncol = 6)
输出:
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 2 5 5 1 4 3
[2,] 2 2 4 2 3 4
[3,] 3 5 4 2 4 5
此处前 3 列 (1,2,3) 属于一组,接下来的 3 列 (4,5,6) 属于另一组。我想从每组中添加一列,并且需要为所有可能的组合添加一列。
对于这个例子,我应该得到 9 个结果向量,因为有 9 种组合:
Combination 1: (1,4) = (3,4,5)
Combination 2: (1,5) = (6,5,7)
Combination 3: (1,6) = (.,.,.)
Combination 4: (2,4) = (.,.,.)
Combination 5: (2,5) = (.,.,.)
Combination 6: (2,6) = (.,.,.)
Combination 7: (3,4) = (.,.,.)
Combination 8: (3,5) = (.,.,.)
Combination 9: (3,6) = (.,.,.)
有什么优雅的方法可以做到这一点,尤其是当列数可以更高时?例如 9、12 等将分别产生 27 和 81 的组合。
编辑:更多说明:每 3 列(例如 1:3、4:6、7:9、10:12、...等)构造一组,然后objective是每组取1列相加。例如,如果我们在 testMat 中有 6 列,我们从 1:3 中取 1 列,从 4:6 中取另一列,将 tese 2 列加在一起。类似地,对于 9,我们添加 3,对于 12,我们从每个集合中添加 4 列。
expand.grid 会出奇地有用:
nc <- ncol( testMat )
if( nc %% 3 != 0 ) {
stop( "Your data's number of columns should be a multiple of 3!")
}
n <- ncol( testMat ) / 3
args <- sapply( 1:n, function(i) (i*3-2):(i*3), simplify=FALSE )
combs <- do.call( expand.grid, args ) %>% arrange( Var1 )
combs %>% apply( 1, function(r) {
rowSums( testMat[, r] )
})
输出:
> combs %>% apply( 1, function(r) {
+ rowSums( testMat[, r ] )
+ })
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,] 3 6 5 6 9 8 6 9 8
[2,] 4 5 6 4 5 6 6 7 8
[3,] 5 7 8 7 9 10 6 8 9
这是一种方法:
#Create a sequence from 1 to number of columns in the data
cols <- seq(ncol(testMat))
n <- 3
#Create a list of every n columns and use expand.grid
#to create all possible combinations
vals <- expand.grid(split(cols, ceiling(cols/n)))
#RowSums every combination using `sapply`.
sapply(asplit(vals, 1), function(x) rowSums(testMat[, x]))
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
#[1,] 3 6 6 6 9 9 5 8 8
#[2,] 4 4 6 5 5 7 6 6 8
#[3,] 5 7 6 7 9 8 8 10 9
这是一种使用 rcppalgos 生成排列的方法:
library(RcppAlgos)
my_vals = function (...) {
dots = list(...)
ncols = ...length()
cols = permuteGeneral(3L, ncols, TRUE)
Reduce(`+`, Map(`[`, dots, asplit(cols,2L)))
}
do.call('my_fun', asplit(array(testMat, c(3L, 3L, ncol(testMat) / 3L)), 3L))
这种方法将矩阵转换为子矩阵列表,然后通过排列对子矩阵进行子矩阵化。