python - 解决具有特定约束的分配问题

标签 python r graph-theory mathematical-optimization lpsolve

想象以下数据(重现所有输出的代码位于末尾):

df

           cars horsepower year safety
1        Toyota        140 2008      4
2      Chrysler        120 2009      4
3          Ford        140 2010      5
4           BMW        150 2008      3
5 Mercedes-Benz        150 2008      3
6       Hyundai        120 2009      4
7        Jaguar        150 2007      3
8         Tesla        120 2010      5

我想交换汽车以获得类似的东西:

   cars_initial    cars_match horsepower year safety horsepowerMatch yearMatch safetyMatch
1        Toyota           BMW        140 2008      4             150      2008           3
2         Tesla      Chrysler        120 2010      5             120      2009           4
3 Mercedes-Benz          Ford        150 2008      3             140      2010           5
4        Jaguar       Hyundai        150 2007      3             120      2009           4
5       Hyundai        Jaguar        120 2009      4             150      2007           3
6          Ford Mercedes-Benz        140 2010      5             150      2008           3
7      Chrysler         Tesla        120 2009      4             120      2010           5
8           BMW        Toyota        150 2008      3             140      2008           4

现在这是一个典型的分配问题,在上述情况下随机解决,即在所有情况下通过将成本矩阵设置为 0。

我感兴趣的是结果。在上述情况下,解决方案会产生以下统计数据:

stats

  horsepower year safety
1       0.25 0.25      0

也就是说,1/4 的交换具有相同的马力,等等。

这是我的问题:如何通过直接对结果统计数据到底应该是什么设置约束来解决此类分配,而不使用试错法来设置成本?

例如,如果我想要一个 safety 匹配度超过 0.20、year 至少 0.10 的解决方案,如下所示,该怎么办?

desiredOutput

   cars_initial    cars_match
1        Toyota      Chrysler
2         Tesla Mercedes-Benz
3 Mercedes-Benz           BMW
4        Jaguar        Toyota
5       Hyundai         Tesla
6          Ford       Hyundai
7      Chrysler        Jaguar
8           BMW          Ford

statsDesired

  horsepower year safety
1       0.25 0.12   0.25

当然,在汽车安全性相同的所有情况下,我可以将成本矩阵设置为较低的数字。

但是有没有办法通过直接设置对结果统计数据的约束来影响结果?

也许有一种方法可以优化成本以达到预期的结果?

代码:

library(lpSolve)
library(dplyr)
library(tidyr)

set.seed(1)

df <- data.frame(
  cars = c("Toyota", "Chrysler", "Ford", "BMW", "Mercedes-Benz", "Hyundai", "Jaguar", "Tesla"),
  horsepower = c(140, 120, 140, 150, 150, 120, 150, 120),
  year = c(2008, 2009, 2010, 2008, 2008, 2009, 2007, 2010),
  safety = c(4, 4, 5, 3, 3, 4, 3, 5)
)

mat <- df %>% select(cars) %>%
  crossing(df %>% select(cars)) %>%
  mutate(val = 0) %>% 
  spread(cars, val)

solved <- lp.assign(mat %>% select(-cars1) %>% as.matrix())$solution

matches <- as.data.frame(solved) %>%
  setNames(., names(mat %>% select(-cars1))) %>%
  bind_cols(mat %>% select(cars1)) %>%
  gather(key, val, -cars1) %>%
  filter(val == 1) %>% select(-val, cars_initial = cars1, cars_match = key)

nms <- c("cars", paste0(names(df %>% select(-cars)), "Match"))

matches <- matches %>%
  left_join(df, by = c("cars_initial" = "cars")) %>%
  left_join(df %>% setNames(., nms), by = c("cars_match" = "cars"))

stats <- matches %>%
  summarise(
    horsepower = round(sum(horsepower == horsepowerMatch) / n(), 2),
    year = round(sum(year == yearMatch) / n(), 2),
    safety = round(sum(safety == safetyMatch) / n(), 2)
  )

desiredOutput <- data.frame(cars_initial = matches$cars_initial, cars_match = c("Chrysler", "Mercedes-Benz", "BMW", "Toyota", "Tesla", "Hyundai", "Jaguar", "Ford"))

statsDesired <- desiredOutput %>%
  left_join(df, by = c("cars_initial" = "cars")) %>%
  left_join(df %>% setNames(., nms), by = c("cars_match" = "cars")) %>%
  summarise(
    horsepower = round(sum(horsepower == horsepowerMatch) / n(), 2),
    year = round(sum(year == yearMatch) / n(), 2),
    safety = round(sum(safety == safetyMatch) / n(), 2)
  )

我希望上面的例子足够了,这是我的第一个问题,所以如果我需要提供更多内容,请告诉我。

代码位于 R 中,但我还添加了标签 Python,因为我并不介意可能的解决方案的语言。

最佳答案

这是该问题作为整数规划 (IP) 问题的部分表述。

I 为汽车类型的集合。对于 I 中的汽车类型 ij,令:

  • h[i,j] = 1 如果汽车 ij 具有相同的马力
  • y[i,j] = 1 如果汽车 ij 具有相同的年份
  • 对于s[i,j](安全)也类似

这些是参数,意味着模型的输入。 (您需要编写代码来根据数据表计算这些二进制数量。)

现在引入以下决策变量,即您的 IP 模型将选择其值的变量:

  • x[i,j] = 1 如果我们将汽车类型 j 指定为类型 i 的匹配项

现在,通常 IP 具有我们想要最小化或最大化的目标函数。在这种情况下,没有目标函数——您只想找到一组满足您的约束的匹配项。所以你的目标函数可以是:

minimize 0

这是第一个约束。它说:至少a 的火柴必须具有相同的马力。 (a 是分数。)左侧是具有相同马力的比赛数量:对于每对汽车类型 ij,如果 j 被指定为 i 的匹配并且它们具有相同的马力,则计为 1;否则,计数 0。右侧是您想要的匹配数,即整个集合的 a 分数。

subject to sum {i in I, j in I} h[i,j] * x[i,j] >= a * |I|

现在为其他类别制定类似的约束。

接下来,您需要一个约束,规定每种汽车类型 i 必须恰好分配给一种汽车类型 j:

subject to sum {j in I} x[i,j] == 1 for all i in I

最后,您需要约束条件来表明决策变量是二元的:

subject to x[i,j] in {0,1} for all i, j in I

现在,为了解决这个问题,您需要使用 AMPL 或 GAMS 等数学建模语言,或者用于 Python 的 PuLP 包。

我希望这有帮助。我在这里咬下的东西可能比你能咀嚼的还要多。

关于python - 解决具有特定约束的分配问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56282517/

相关文章:

python - Polars 读取文件导致错误

r - 突出显示每隔一行 knitr+Rmd

algorithm - Prim 算法时间复杂度

c++ - 迭代最大匹配

r - 哪些 IDE 可用于 Linux 中的 R?

algorithm - 查找有向图中的所有顶点以及到图中每个其他顶点的路径

python - 如何从 .pyo 文件恢复源 python 代码 (.py)?

java - cloudfoundry 中有多个构建包

python - pandas dataframe - 根据唯一用户对艺术家进行分组

file - 将 p 值写入 R 中的文件