假设我们有以下数据集
set.seed(144)
dat <- matrix(rnorm(100), ncol=5)
以下函数创建所有可能的列组合并删除第一个
(cols <- do.call(expand.grid, rep(list(c(F, T)), ncol(dat)))[-1,])
# Var1 Var2 Var3 Var4 Var5
# 2 TRUE FALSE FALSE FALSE FALSE
# 3 FALSE TRUE FALSE FALSE FALSE
# 4 TRUE TRUE FALSE FALSE FALSE
# ...
# 31 FALSE TRUE TRUE TRUE TRUE
# 32 TRUE TRUE TRUE TRUE TRUE
我的问题是如何只计算单,二元和三元组合?
使用以下函数选择包含不超过3个TRUE值的行适用于此向量:cols[rowSums(cols)<4L, ]
但是,它为较大的向量提供了以下误差,主要是因为带有长向量的expand.grid中的错误:
Error in rep.int(seq_len(nx), rep.int(rep.fac, nx)) :
invalid 'times' value
In addition: Warning message:
In rep.fac * nx : NAs produced by integer overflow
任何可以让我只计算单个,二元和三元组合的建议吗?
答案 0 :(得分:2)
您可以尝试
cols[rowSums(cols) < 4L, ]
或者
cols[Reduce(`+`, cols) < 4L, ]
答案 1 :(得分:1)
您可以使用此解决方案:
col.i <- do.call(c,lapply(1:3,combn,x=5,simplify=F))
# [[1]]
# [1] 1
#
# [[2]]
# [1] 2
#
# <...skipped...>
#
# [[24]]
# [1] 2 4 5
#
# [[25]]
# [1] 3 4 5
此处,col.i
是一个列表,其中每个元素都包含列索引。
工作原理:combn
生成1到5的数字的所有组合(x
= 5请求),一次m
simplify=FALSE
确保结果有一个列表结构)。 lapply
调用隐式循环以将m
从1迭代到3并返回列表列表。 do.call(c,...)
将列表列表转换为普通列表。
您可以使用col.i
从dat
获取某些列,例如dat[,col.i[[1]],drop=F]
(1是列组合的索引,因此您可以使用1到25之间的任意数字; drop=F
确保当您从dat
中选择一列时,结果为没有简化为向量,这可能会导致意外的程序行为)。另一种选择是使用lapply
,例如
lapply(col.i, function(cols) dat[,cols])
将返回一个数据框列表,每个数据框包含dat
列的某个子集。
如果您想将列索引作为布尔矩阵,可以使用:
col.b <- t(sapply(col.i,function(z) 1:5 %in% z))
# [,1] [,2] [,3] [,4] [,5]
# [1,] TRUE FALSE FALSE FALSE FALSE
# [2,] FALSE TRUE FALSE FALSE FALSE
# [3,] FALSE FALSE TRUE FALSE FALSE
# ...
[<强>更新强>
更有效的实现:
library("gRbase")
coli <- function(x=5,m=3) {
col.i <- do.call(c,lapply(1:m,combnPrim,x=x,simplify=F))
z <- lapply(seq_along(col.i), function(i) x*(i-1)+col.i[[i]])
v.b <- rep(F,x*length(col.i))
v.b[unlist(z)] <- TRUE
matrix(v.b,ncol=x,byrow = TRUE)
}
coli(70,5) # takes about 30 sec on my desktop