R:从所有可能的组合中选择特定数量的组合

时间:2015-04-29 09:08:55

标签: r selection combinations

假设我们有以下数据集

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

任何可以让我只计算单个,二元和三元组合的建议吗?

2 个答案:

答案 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.idat获取某些列,例如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