从480个有约束的元素中找到11个元素的最大和

问题描述

我有一个熊猫数据框,其列如下所示:

   ict    |constraint1|constraint2|
 float(x) |     y     |     z     |

我在数据框中有480行,当前按ict排序。我需要找到11个元素的ict的最大可能总和,然后检查该集合是否满足条件(例如constraint1只能等于b少于5倍)。如果不符合条件,我需要找到11个元素中ict的下一个最大和。

我目前有一个函数check_ict(list1),它检查作为数据帧行索引列表输入的11个元素中的ict。我还有一个函数check_constraints(list1),用于检查同一输入是否满足约束条件。但是,我正在努力寻找如何找到“ ict s的下一个最大和”。

由于数据已经按ict进行排序,因此我知道最好的组合是数据帧的第0-10行。下一个最佳组合是第0-9行+第11行。但是之后,事情变得棘手。没有明显的方法可以知道[0,1,2,3,4,5,6,7,8,9,12]是更大还是[0,10,11]。而且没有明显的方法知道那之后最大的是什么。

我如何不断寻找下一个最佳组合? 10^21可能包含480个元素中的11个元素的组合,因此绝对不能使用强行强制。

解决方法

如评论中所述,使用数学优化来解决此问题。如果可能,在约束可以写为线性的条件下,线性优化是数学优化的简单子集。在这种情况下,像pulp这样的软件包可能会为您提供帮助。

一些示例代码:

import numpy as np
import pandas as pd
import pulp as pl

# Generate some data
np.random.seed(42)
n_rows = 20

constraint1_capacities = {
    'a': 3,'b': 20,'c': 5
}

constraint2_capacities = {
    'x': 5,'y': 10,'z': 15
}

df = pd.DataFrame({
    'ict': np.random.rand(n_rows),'constraint1': np.random.choice(list(constraint1_capacities),n_rows),'constraint2': np.random.choice(list(constraint2_capacities),})

print(df)

# Solve the actual problem
take_best = 11

# Create variables: x_i denotes that the i'th element is included,we create
# one for each row in the dataframe
x = [pl.LpVariable(f"x_{i:02}",cat=pl.LpBinary) for i in range(len(df))]

# Initialise the problem
problem = pl.LpProblem("choices",pl.LpMaximize)

# Define the objective function as the sum of all x_i * ict_i
problem += pl.lpSum(x * df.ict.values)

# Constraints:
# In total,at most `take_best` rows can be taken:
problem += pl.lpSum(x) <= take_best

for key,_max in constraint1_capacities.items():
    # x_i * constraint1_i <= _max for every potential key
    problem += pl.lpSum(x * (df.constraint1 == key).values) <= _max

for key,_max in constraint2_capacities.items():
    # x_i * constraint2_i <= _max for every potential key
    problem += pl.lpSum(x * (df.constraint2 == key).values) <= _max

problem.solve()
print(pl.LpStatus[problem.status])

print("Choose rows: ")
for v in problem.variables():
    if v.varValue != 0:
        print(v)

产生

Optimal
Choose rows: 
x_01
x_02
x_03
x_07
x_08
x_09
x_11
x_12
x_16
x_18
x_19