如何将Pandas DataFrame集成到PuLP/Pyomo中作为约束实现成本最小化分配
解决Pandas DataFrame约束集成到PuLP的成本分配问题
我来帮你搞定这个把Pandas数据转化为PuLP约束的问题!你的核心需求是根据零件和系统的属性规则,批量生成禁止分配的约束,咱们用Pandas的批量处理能力来实现,比嵌套循环更高效好维护。
第一步:批量标记合法的零件-系统分配对
首先,我们把零件表和系统表做笛卡尔积,这样能一次性处理所有可能的分配组合,然后给每个组合标记是否符合规则:
import pandas as pd import pulp # 你的原始数据 data_part = [ {'Part': 'A', 'Units': 20, 'Engine': True, 'TurboCharger': True, 'Restricted': True}, {'Part': 'B', 'Units': 15, 'Engine': False, 'TurboCharger': True, 'Restricted': False}, {'Part': 'C', 'Units': 15, 'Engine': False, 'TurboCharger': True, 'Restricted': False}, {'Part': 'D', 'Units': 40, 'Engine': False, 'TurboCharger': True, 'Restricted': False}, {'Part': 'E', 'Units': 25, 'Engine': True, 'TurboCharger': True, 'Restricted': False}, {'Part': 'F', 'Units': 20, 'Engine': True, 'TurboCharger': False, 'Restricted': True}, ] df_part = pd.DataFrame(data_part) data_system = [ {'System': 'Rapidx', 'Type': 'Engine Super', 'Condition': 'Restricted'}, {'System': 'Assex', 'Type': 'Engine', 'Condition': ''}, {'System': 'Dulingo', 'Type': 'TurboCharger', 'Condition': ''}, {'System': 'Das', 'Type': 'TurboCharger', 'Condition': ''}, ] df_system = pd.DataFrame(data_system) # 创建所有零件-系统的组合(笛卡尔积) cross_df = df_part.assign(temp_key=1).merge(df_system.assign(temp_key=1), on='temp_key').drop('temp_key', axis=1) # 定义类型匹配规则:系统类型对应零件的布尔字段 def check_type_match(row): sys_type = row['Type'] if sys_type == 'Engine': return row['Engine'] elif sys_type == 'TurboCharger': return row['TurboCharger'] elif sys_type == 'Engine Super': # 按你的示例,Engine Super要求零件Engine为True,可按需调整为同时要TurboCharger=True return row['Engine'] return False # 未知类型默认不允许 # 定义约束匹配规则:受限系统只能放受限零件,非受限系统只能放非受限零件 def check_condition_match(row): sys_condition = row['Condition'] part_restricted = row['Restricted'] if sys_condition == 'Restricted': return part_restricted else: return not part_restricted # 如果非受限系统允许放受限零件,改成return True即可 # 给每个组合标记是否允许分配 cross_df['type_ok'] = cross_df.apply(check_type_match, axis=1) cross_df['condition_ok'] = cross_df.apply(check_condition_match, axis=1) cross_df['is_allowed'] = cross_df['type_ok'] & cross_df['condition_ok']
第二步:生成PuLP约束
接下来,我们把每个系统下不允许分配的零件组合起来,生成你要的约束:
# 初始化PuLP变量(你的原有代码) allocate = pulp.LpVariable.dicts("allocate", [(p, s) for p in df_part.Part for s in df_system.System], cat='Binary') # 初始化PuLP问题 allocation_prob = pulp.LpProblem("Minimize_Allocation_Cost", pulp.LpMinimize) # 按系统分组,生成约束 for system, group in cross_df[~cross_df['is_allowed']].groupby('System'): # 收集该系统下所有禁止的分配变量 forbidden_assignments = [allocate[(row['Part'], system)] for _, row in group.iterrows()] # 添加约束:这些变量的和必须<=0(等价于每个变量都为0) allocation_prob += pulp.lpSum(forbidden_assignments) <= 0, f"No_Assign_{system}" # 打印约束看结果(和你期望的输出一致) for constraint_name, constraint in allocation_prob.constraints.items(): print(constraint)
运行后的输出
你会得到和你期望完全一致的约束:
allocate_('B',_'Rapidx') + allocate_('C',_'Rapidx') + allocate_('D',_'Rapidx') + allocate_('E',_'Rapidx') <= 0 allocate_('A',_'Assex') + allocate_('B',_'Assex') + allocate_('C',_'Assex') + allocate_('D',_'Assex') + allocate_('F',_'Assex') <= 0 allocate_('A',_'Dulingo') + allocate_('F',_'Dulingo') <= 0 allocate_('A',_'Das') + allocate_('F',_'Das') <= 0
灵活调整规则
如果后续你的匹配规则变了,比如Engine Super需要同时满足Engine和TurboCharger为True,只需要修改check_type_match里的对应分支:
elif sys_type == 'Engine Super': return row['Engine'] and row['TurboCharger']
如果非受限系统允许分配受限零件,就把check_condition_match的else分支改成return True就行。
内容的提问来源于stack exchange,提问作者Greg
相关产品推荐
相关产品推荐

