R subset data.frame columns by group 最大化行值

R subset data.frame columns by group to maximize row values

我遇到的问题与此处描述的非常相似:

subset of data.frame columns to maximize "complete" observations

我正在尝试安排一个会面五次的研讨会。我有十天的时间来选择会议日期,每天都有三个重叠的可能会议时间。因此,我将 30 列分为十组(天),每组三列(会议时间)。我需要 select 5 列(或会议日期-时间组合)符合以下条件:每天只有一个会议时间 selected(每组一列);可以参加所有 5 次会议的受访者(行)的数量已最大化。理想情况下,如果我放宽受访者必须参加所有 5 次会议的标准,只要求他们参加 4 或 3 次等,我还想知道最佳列 selection 如何变化

为了简单的可视化,假设我想知道我应该选择哪两列——V1、V2 和 V3 各不超过一列——这样我就可以最大限度地增加没有零的行数(即行总和为 2)。

V1A   V1B   V1C   V2A   V2B   V2C   V3A   V3B   V3C  
1     0     1     0     1     1     1     0     1   
1     1     0     0     1     1     0     1     1   
0     0     1     1     1     0     0     1     1   
1     1     1     1     0     0     1     0     0 
1     0     0     0     1     1     0     1     0 
0     1     1     0     1     1     0     0     0 
1     0     1     1     1     0     1     0     1

实际数据在这里:https://drive.google.com/file/d/0B03dE9-8088aMklOUVhuV3gtRHc/view组是 mon1* tue1* [...] mon2* tue2* [...] fri2*。

如果我不需要 select 组中的列,上面 link 中提出的代码将解决我的问题。理想情况下,我还可以说出我应该选择哪些列以在行可能有一个零的较弱条件下最大化行数(即行总和为 5 或 4 或 3,等等)。

非常感谢!

对于您的数据集,这会传送满足传送所有行的要求的行==1:

> lapply( 1:3, function(grp) which( apply( dat[, grep(grp, names(dat))] , 1, 
                                           function(z) sum(z, na.rm=TRUE)==3) ) )
[[1]]
[1] 4

[[2]]
integer(0)

[[3]]
integer(0)

如果您放宽允许值小于 3 的要求,您将获得更多候选人:

> lapply( 1:3, function(grp) which( apply( dat[, grep(grp, names(dat))] , 1, function(z) sum(z, na.rm=TRUE)>=2) ) )
[[1]]
[1] 1 2 4 6 7

[[2]]
[1] 1 2 3 5 6 7

[[3]]
[1] 1 2 3 7

现在,这个任务的具体路线是什么?????

您可以使用 rowSums 获取大于或等于两个 1 的行的索引。 (条件不是很清楚)

  lapply(split(names(df),sub('.$', '', names(df))), 
          function(x) which(rowSums(df[x])>=2))
  #$V1
  #[1] 1 2 4 6 7

  #$V2
  #[1] 1 2 3 5 6 7

  #$V3
  #[1] 1 2 3 7

这只是在三组中的每一组中找到第一列索引为 1(如果全为零,则为第一列),返回一个三列矩阵,每组一列。

f <- substring(colnames(df), 1L, nchar(colnames(df))-1L)
ans <- lapply(split(as.list(df), f),
              function(x) max.col(do.call(cbind, x), ties.method="first"))
do.call(cbind, ans)