仓库选址问题.Python实例操作
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
目录
先更新部分~~需要数据集可以私信我
前言
近段时间,训练了一道仓库选址问题研究建模,在这里详细分享给大家我的结题过程.
PS:有错误欢迎指出
一、题目
不多说了,直接上题目
二、解题思想
2.1 问题1
网上的订货需要在一天内送达,求至少建多少的仓库。这是一道集合覆盖问题。覆盖模型适用于一些特殊场景,例如消防中心、救护车、巡逻车等应急设施的区位选址问题
Step1:处理数据Data_1.xlsx,下面给数据集的预览
首先,对每个城市按表中数据按1-50进行编号,再将系数矩阵进行补全(这里通过Excel可以手动几步解决)得到下图
因为题目的要求是一天内送达,所以我们系数矩阵保留所有两城市距离为一天的数据,其余数据都替换为0
# 读取数据
data = pd.read_excel("数据位置")
# 将 Nan 替换为 0
data[1:50].fillna(0,inplace=True)
#删掉无用的列 具体按个人数据实例进行操作
del data['Unnamed: 0']
del data['到达']
data.drop([0],axis=0,inplace=True)
data[1:50].fillna(0,inplace=True)
#大于1的距离进行删除
reachable = data.values #将Excel表中数据存储到数组中
reachable[reachable > 1] = 0
Step2:建立0-1整数规划模型,需要对每个城市建仓库可能性进行尝试
代表城市
代表城市间的距离(也可以理解为城市送达城市只要一天的集合)
限制条件: 即每个城市都可覆盖
目标函数: 求至少需要建立几个仓库
代码实现:
#写问题
SetCoverLP = pulp.LpProblem("SetCover_problem_for_Warehouse", sense=pulp.LpMinimize)
#建立变量x
Zones = list(range(50))
x = pulp.LpVariable.dicts("Zone",Zones,cat="Binary")
#目标函数
SetCoverLP += pulp.lpSum(x[i] for i in range(50))
#限制条件
for j in range(50):
SetCoverLP += (pulp.lpSum([x[i] * reachable[i][j] for i in range(50)]) >= 1)
SetCoverLP.solve()
print(SetCoverLP.name)
# 格式化输出
temple = "区域 %(zone)d 的决策是:%(status)s"
# 获得最优解
y = np.array(range(50))
if pulp.LpStatus[SetCoverLP.status] == "Optimal":
for i in range(50):
if x[i].varValue:#将建仓位置存储到数组中
y[i] = 1
else:
y[i] = 0
output = {'zone': i+1, 'status': '建仓' if x[i].varValue else '--'}
print(temple % output)
print("需要建立 {} 个仓库。".format(pulp.value(SetCoverLP.objective)))
Step3:运行结果得到答案
2.2 问题2
从第二个问题中,我们知道有两个目的:建尽量少的仓库,最低的消费税负担。
Step1:消费税负担的计量:对于消费者来说他们关心的是购买商品时 需要承担额外的消费税,所以我们使用人均消费税来衡量消费者承担的消费税负担。假设仓库建在第个城市仓库,计算人均消费税:
Step2:加权法系数,标准化统一量纲:通过加权平均法引入系数,对仓库数量和仓库平均消费税两者进行标准化处理(此处标准化处理我采用的是最大最小法),进行统一,将多目标函数转化为单目标函数:
修建仓库的最大数量
修建仓库的最小数量
仓库目标
人均消费税目标
目标函数:
代码实现:
data1['总税金'] = data1['服装消费']*data1['服装消费税率']*1000 + data1['娱乐设施消费'] * data1['消费税率']*1000
data1['人均税'] = data1['总税金'] / data1['人口']
# print(type(data1['人均消费税']))
m = np.array(data1['人均税'])
reachable = data2.values
Warehouse_max = 50
Warehouse_min = 18
SetCoverLP = pulp.LpProblem("SetCover_problem_for_Warehouse", sense=pulp.LpMinimize)
w=0.8 #可以修改系数
#list1是题一中的建立的仓库,目的计算最小值y[i]*m[i] 即人均消费税
list1=[0,1,0,1,1,1,0,1,0,1,0,1,1,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1]
y = np.array(list1,dtype="int")
Zones = list(range(50))
x = pulp.LpVariable.dicts("Zone",Zones,cat="Binary")
Z_1 = (pulp.lpSum(x[i] for i in range(50)) - Warehouse_min) / (Warehouse_max - Warehouse_min)
Z_2 = (pulp.lpSum(x[i]*m[i] for i in range(50)) - pulp.lpSum(y[i]*m[i] for i in range(50))) / (pulp.lpSum(m[i] for i in range(50)) - pulp.lpSum(y[i]*m[i] for i in range(50)))
SetCoverLP += (w * Z_1 + (1 - w) * Z_2)
for j in range(50):
SetCoverLP += (pulp.lpSum([x[i] * reachable[i][j] for i in range(50)]) >= 1)
SetCoverLP.solve()
print(SetCoverLP.name)
temple = "区域 %(zone)d 的决策是:%(status)s"
n = 0
y = np.array(range(50))
if pulp.LpStatus[SetCoverLP.status] == "Optimal":
for i in range(50):
if x[i].varValue:
n += 1
y[i] = 1
else:
y[i] = 0
output = {'zone': i+1, 'status': '建仓' if x[i].varValue else '--'}
print(temple % output)
print("目标函数全局最优解为:{}。".format(pulp.value(SetCoverLP.objective)))
print("共建仓数:",n,"个")
Step3:运行结果得到答案:
2.3 问题3
总结
多进行实战练习,多总结才是提升自己的良好途径