PySpark结合Pulp做FTE利润优化时int与NoneType相乘报错求助
报错问题解决方法
- 修复Spark代码语法错误
你提供的Spark过滤逻辑缺失右括号,会导致过滤规则不生效,混入不符合要求的数据:
同时新增# 错误写法 .filter(F.col("Channel")=="A" # 修正后 .filter(F.col("Channel")=="A")ftes > 0的过滤规则,避免除以0生成的NaN在转换为Python类型时变为None:.filter(F.col("ftes") > 0)- 修复Spark代码语法错误
- 修正数据采集逻辑,避免多次collect导致的长度不匹配
分开三次采集字段如果遇到Spark数据并发变更,会出现三个列表长度不一致的问题,zip后部分key对应的值为None,改为一次性采集所有字段:
rows = US_AEI.select("Customer_Name", "profit", "profit_per_fte", "ftes").collect() profit_per_fte = {} ftes = {} profit = {} for row in rows: profit_per_fte[row.Customer_Name] = row.profit_per_fte ftes[row.Customer_Name] = row.ftes profit[row.Customer_Name] = row.profit keys = list(profit_per_fte.keys())- 修正数据采集逻辑,避免多次collect导致的长度不匹配
- 校验重复客户名
如果存在重复的Customer_Name,LpVariable.dicts生成变量时会出现覆盖,后续访问重复key的变量会返回None,可通过以下代码校验:
assert len(keys) == len(set(keys)), "存在重复客户名"- 校验重复客户名
逻辑问题修正
你当前的目标函数定义错误,你要最大化的是总利润,不是单位FTE利润的和,正确的目标函数写法为:
prob += lpSum([profit[i] * customer_vars[i] for i in keys])
多渠道场景优化建议
- 决策变量简化
不需要单独定义渠道启用变量,直接定义客户-渠道维度的二进制决策变量即可:
channels = ["A", "B", "C", "D", "E", "F"] # x[i,j] = 1 代表客户i选择渠道j x = LpVariable.dicts("x", [(i,j) for i in customers for j in channels], lowBound=0, cat='Binary')- 决策变量简化
- 新增客户渠道唯一约束
保证每个客户最多选择一个渠道,也可以不选:
for i in customers: prob += lpSum([x[(i,j)] for j in channels]) <= 1- 新增客户渠道唯一约束
- 修正约束与目标函数
按客户-渠道维度存储FTE投入和利润数据,调整对应逻辑:
# FTE总约束 prob += lpSum([x[(i,j)] * ftes[i,j] for i in customers for j in channels]) <= fte_envelope # 总利润最大化目标函数 prob += lpSum([x[(i,j)] * profit[i,j] for i in customers for j in channels])- 修正约束与目标函数
- 修正拼写错误
你提供的全量代码中sovle为拼写错误,正确写法为prob.solve()
- 修正拼写错误
内容的提问来源于stack exchange,提问作者user99137
相关产品推荐
相关产品推荐

