R:在 0 和 1 的矩阵中查找包含最多 1 的列集

标签 r matrix set max

我有一个由 1 和 0 组成的矩阵,其中行是个体,列是事件。 1 表示事件发生在个人身上,0 表示没有发生。

我想找出哪一组(在示例中)5 列/事件涵盖了最多的行/个人。

测试数据

#Make test data
set.seed(123)
d <- sapply(1:300, function(x) sample(c(0,1), 30, T, c(0.9,0.1)))
colnames(d) <- 1:300
rownames(d) <- 1:30

我的尝试

我最初的尝试只是基于将 5 列的集合与最高的 colMeans 相结合:

#Get top 5 columns with highest row coverage
col_set <- head(sort(colMeans(d), decreasing = T), 5)

#Have a look the set
col_set

>
      197       199        59        80        76 
0.2666667 0.2666667 0.2333333 0.2333333 0.2000000 

#Check row coverage of the column set
sum(apply(d[,colnames(d) %in% names(col_set)], 1, sum) > 0) / 30 #top 5

>
[1] 0.7

但是这个集合并没有涵盖最多的行。我通过伪随机抽样 10.000 组不同的 5 列进行测试,然后找到覆盖率最高的组:

#Get 5 random columns using colMeans as prob in sample
##Random sample 10.000 times
set.seed(123)
result <- lapply(1:10000, function(x){
  col_set2 <- sample(colMeans(d), 5, F, colMeans(d))
  cover <- sum(apply(d[,colnames(d) %in% names(col_set2)], 1, sum) > 0) / 30 #random 5
  list(set = col_set2, cover = cover)
})

##Have a look at the best set
result[which.max(sapply(result, function(x) x[["cover"]]))]

>
[[1]]
[[1]]$set
        59        169        262         68        197 
0.23333333 0.10000000 0.06666667 0.16666667 0.26666667 

[[1]]$cover
[1] 0.7666667

sample 提供 colMeans 的原因是覆盖率最高的列是我最感兴趣的列。

因此,使用伪随机抽样,我可以收集一组覆盖率高于仅使用前 5 列的列。但是,由于我的实际数据集比示例大,所以我正在寻找一种更有效、更合理的方法来查找覆盖率最高的列集。

编辑

对于感兴趣的人,我决定对所提供的 3 个解决方案进行微基准测试:

#Defining G. Grothendieck's coverage funciton outside his solutions
coverage <- function(ix) sum(rowSums(d[, ix]) > 0) / 30

#G. Grothendieck top solution
solution1 <- function(d){
  cols <- tail(as.numeric(names(sort(colSums(d)))), 20)
  co <- combn(cols, 5)
  itop <- which.max(apply(co, 2, coverage))
  co[, itop]
}

#G. Grothendieck "Older solution"
solution2 <- function(d){
  require(lpSolve)
  ones <- rep(1, 300)
  res <- lp("max", colSums(d), t(ones), "<=", 5, all.bin = TRUE, num.bin.solns = 10)
  m <- matrix(res$solution[1:3000] == 1, 300)
  cols <- which(rowSums(m) > 0)
  co <- combn(cols, 5)
  itop <- which.max(apply(co, 2, coverage))
  co[, itop]
}

#user2554330 solution
bestCols <- function(d, n = 5) {
  result <- numeric(n)
  for (i in seq_len(n)) {
    result[i] <- which.max(colMeans(d))
    d <- d[d[,result[i]] != 1,, drop = FALSE]
  }
  result
}

#Benchmarking...
microbenchmark::microbenchmark(solution1 = solution1(d),
                               solution2 = solution2(d),
                               solution3 = bestCols(d), times = 10)

>
Unit: microseconds
      expr        min         lq       mean      median         uq       max neval
 solution1 390811.850 497155.887 549314.385 578686.3475 607291.286 651093.16    10
 solution2  55252.890  71492.781  84613.301  84811.7210  93916.544 117451.35    10
 solution3    425.922    517.843   3087.758    589.3145    641.551  25742.11    10

最佳答案

由于列的交互方式,这看起来像是一个相对困难的优化问题。一个近似的策略是选择具有最高平均值的列;然后删除该列中的行,然后重复。您不一定会通过这种方式找到最佳解决方案,但您应该会找到一个相当不错的解决方案。

例如,

set.seed(123)
d <- sapply(1:300, function(x) sample(c(0,1), 30, T, c(0.9,0.1)))
colnames(d) <- 1:300
rownames(d) <- 1:30
bestCols <- function(d, n = 5) {
  result <- numeric(n)
  for (i in seq_len(n)) {
    result[i] <- which.max(colMeans(d))
    d <- d[d[,result[i]] != 1,, drop = FALSE]
  }
  cat("final dim is ", dim(d))
  result
}
col_set <- bestCols(d)
sum(apply(d[,colnames(d) %in% col_set], 1, sum) > 0) / 30 #top 5

这提供了 90% 的覆盖率。

关于R:在 0 和 1 的矩阵中查找包含最多 1 的列集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63618665/

相关文章:

python - 用于稀疏矩阵计算的 Scipy 或 Pandas?

r - 在 Mac OS X Lion 上安装 rgeos 和 rgdal 时出现问题

r - 将部分添加到 R 包的帮助/文档

r - R中的K均值聚类 - 忽略行ID

algorithm - 找到边界上包含相似单元格的最大子矩阵

c++ - 如何迭代容器的前 N ​​个元素?

r - Shiny模块之间的通信

MATLAB : Dimension reduction

java - 集合操作的复杂性

java - 在 while 条件下添加到集合中的良好做法?