限制指定列的重复

时间:2017-09-19 00:43:05

标签: r linear-programming

我正在尝试找到一种方法来将一些约束添加到线性程序中,以迫使解决方案具有一定程度的唯一性。我会尝试解释一下我的意思。以下面的例子为例,线性程序返回2个男性和1个女性组合的最大可能得分

查看团队/成绩/代表列,但我们可以看到行与行之间存在大量重复。实际上Shana和Jason完全相同。

Name<-c("Jane","Brad","Harry","Shana","Debra","Jason")
Sex<-c("F","M","M","F","F","M")
Score<-c(25,50,36,40,39,62)
Team<-c("A","A","A","B","B","B")
Grade<-c(1,2,1,2,1,2)
Rep<-c("C","D","C","D","D","D")

df<-data.frame(Name,Sex,Score,Team,Grade,Rep)
df
   Name Sex Score Team Grade Rep
1  Jane   F    25    A     1   C
2  Brad   M    50    A     2   D
3 Harry   M    36    A     1   C
4 Shana   F    40    B     2   D
5 Debra   F    39    B     1   D
6 Jason   M    62    B     2   D

library(Rglpk)

num <- length(df$Name)
obj<-df$Score
var.types<-rep("B",num)
matrix <- rbind(as.numeric(df$Sex == "M"),as.numeric(df$Sex == "F"))
direction <- c("==","==")
rhs<-c(2,1)
sol <- Rglpk_solve_LP(obj = obj, mat = matrix, dir = direction, rhs = rhs,types = var.types, max = TRUE)

df[sol$solution==1,]
   Name Sex Score Team Grade Rep
2  Brad   M    50    A     2   D
4 Shana   F    40    B     2   D
6 Jason   M    62    B     2   D

我想要解决的是如何限制最后三列中的随机性水平。例如,我希望在任何两行中不超过2列相同。因此,这意味着Shana行或Jason行将在模型中替换为替换。

我不确定这是否可以轻松添加到Rglpk模型中?感谢可以提供的任何帮助。

2 个答案:

答案 0 :(得分:3)

这听起来像是在问你如何防止有一对“太相似”的人。从优化模型返回。一旦你确定了一对规则使得一对人过于相似&#34;,你可以简单地为每一对添加一个约束,限制你的解决方案只有这两个人中的一个。

例如,如果我们使用不超过2列相同的规则,我们可以轻松识别出要阻止的所有对:

pairs <- t(combn(nrow(df), 2))
(blocked <- pairs[rowSums(sapply(df[,c("Team", "Grade", "Rep")], function(x) {
   x[pairs[,1]] == x[pairs[,2]]
 })) >= 3,])
#      [,1] [,2]
# [1,]    1    3
# [2,]    4    6

我们希望阻止对Jane / Harry和Shana / Jason。线性约束很容易做到这一点:

library(Rglpk)

num <- length(df$Name)
obj<-df$Score
var.types<-rep("B",num)
matrix <- rbind(as.numeric(df$Sex == "M"), as.numeric(df$Sex == "F"),
                outer(blocked[,1], seq_len(num), "==") + outer(blocked[,2], seq_len(num), "=="))
direction <- rep(c("==", "<="), c(2, nrow(blocked)))
rhs<-c(2, 1, rep(1, nrow(blocked)))
sol <- Rglpk_solve_LP(obj = obj, mat = matrix, dir = direction, rhs = rhs,types = var.types, max = TRUE)

df[sol$solution==1,]
#    Name Sex Score Team Grade Rep
# 2  Brad   M    50    A     2   D
# 5 Debra   F    39    B     1   D
# 6 Jason   M    62    B     2   D

计算每一对被阻止的方法很有吸引力,因为我们可以有一个更复杂的规则来阻止对,因为我们不需要将规则编码到线性程序中。我们需要做的就是计算需要阻止的每一对。

答案 1 :(得分:1)

对于具有相同最后3列的每组行,我们构造一个约束,使得最多可以出现其中一行。如果a是这样一组行的指示符向量,那么约束将如下所示:

a'x <= 1

为此,将最后3列的行号拆分为向量列表s,其中每个组件的组成部分是具有相同后3列的行的行号向量。只保留那些行号超过1的conponents s1。在这种情况下,s1的第一个成分是c(1,3),指的是Jane和Harry行,第二个成分是c(4,6),指的是Shana和Jason行。在此特定数据中,每个组中有2行,但在其他数据中,组中可能有2行以上。对于excl的每个元素,s1都有一行(约束)。

问题中的数据只有大小为2的组,但一般情况下,如果某些组中有k行,则需要k选择2个约束行,以确保如果成对完成,则只选择其中一个k,而这里的方法只需要整个组的一个约束行。例如,如果k = 10,则选择(10,2)= 45,因此使用1个约束代替45。

最后rbind exclmatrixmatrix2并相应调整其他Rglpk_solve_LP参数:

nr <- nrow(df)

s <- split(1:nr, df[4:6])
s1 <- s[lengths(s) > 1]
excl <-t(sapply(s1, "%in%", x = 1:nr)) + 0

matrix2 <- rbind(matrix, excl)
direction2 <- c(direction, rep("<=", nrow(excl)))
rhs2 <- c(rhs, rep(1, nrow(excl)))
sol2 <- Rglpk_solve_LP(obj = obj, mat = matrix2,
  dir = direction2, rhs = rhs2, types = "B", max = TRUE)

df[ sol2$solution == 1, ]

,并提供:

   Name Sex Score Team Grade Rep
2  Brad   M    50    A     2   D
5 Debra   F    39    B     1   D
6 Jason   M    62    B     2   D