数学建模竞赛篇--使用tensorflow搭建了一个预测线任务路定价的模型

最近参加了2020年的第十届MathorCup高校数学建模挑战赛,这次竞赛的问题总的来说是一个定价问题。由于我和我的小伙伴是第一次参加所以感觉有很多做的不是很好的地方,希望大家多多批评指正。

我会把我的所有实现代码及数据放到博客上,大家有兴趣可以去下载。首先附上我的代码结构图。

目录

  1. 问题分析
  2. 第一题的思路及具体做法
  3. 第二题的思路
  4. 第三题的思路及具体做法

1. 问题分析

首先是相关数据的解读

附件1是已经交易完成的货运线路任务数据,其中附件1数据文件中的线路指导价为平台首次发布的线路价格。附件2是尚未完成定价的货运线路任务单包含了线路任务的一些基本信息,包括总里程、业务类型、交易对象、需求紧急程度等指标。附件3附件2的计算结果,通过建立适当的数学模型计算出附件2的线路任务的三次报价以及总成本定价,并填充在附件3的表格中。

下面是附件一字段释义

字段释义
任务id唯一标识任务ID
总里程任务里程
业务类型运输产品的大类,重货,速运(普通快递)
需求类型1需求的业务场景,如普通,接驳等
需求类型2需求产生的形式,计划&临时
线路价格(不含税)线路成交价
线路编码线路id(线路的定义为始发地地点+目的地地点+执行时间)
调价比例调整后的价格和原价格的比值
线路指导价(不含税)线路指导价,不一定成交
是否续签若本期任务执行较好,可选择以某个价格在下个承包周期继续执行这些任务
始发网点始发地地点
实际到车时间任务执行时实际的到达目的地点的时间
目的网点目的地地点
交易成功时长从发布交易到交易结束的耗时
交易成功时间交易成功的具体时间
交易成功日期交易成功的具体日期
计划发车时间任务计划发车的时间
计划发车日期任务计划发车的日期
分拨时间任务信息准备完成时间
成交对象成交的对象类型(B:承运商 C:个体司机)
车辆长度车长
车辆吨位吨位
标的展示策略发布信息的方式,BDC:发布平台抢单交易,DIR:定向指派
打包类型线路任务组合的方式
C端议价反馈数量C端反馈价格司机的数量
最后一次询价时间最后一次询问价格的时间
子包号线路任务组合的代号
装卸的次数装卸共多少次
装的次数装的总次数
运输等级运输任务的线路等级
卸的次数卸的总次数
调价审核完成时间调价需要的行政审批流程完成时间
调价类型调价的类型成交价在指导价的95%-105%内都属于未调整)
调价紧急程度调价的紧急情况描述
调价ECP创建时间调价需要的行政审批流程创建时间
是否需要装卸运输过程是否需要装卸
始发地省份名称始发地省份的名称
实际靠车时间车辆执行任务时实际到达任务出发点的时间
实际结束时间车辆执行任务时实际完成任务的时间
实际发车时间车辆执行任务时实际的发车时间
任务状态当前任务的执行状态
车辆类型分类车辆的类型
目的地省份名称目的地省份的名称
交易开始时间该任务交易开始的时间
交易结束时间该任务交易结束的时间
交易对象交易面向的司机类型
计划卸货完成时间该任务计划卸货完成的时间
计划卸货等待时长该任务从到车到卸货之间的等待时长
计划靠车时间该任务计划车辆到达出发点的时间
计划到达时间该任务计划车辆到达目的地点的时间
地区类型地区的类型
地区地区代码
标的状态任务标的的状态
标的_创建时间标的创建的时间
标的_创建日期标的创建的日期
异常状态标的的异常状态
交易模式标的的交易模式
C端议价最低价C端司机给出的最低价格
B端议价最低价B端司机给出的最低价格
B端议价反馈数量B端反馈价格的司机数量
线路总成本任务的执行成本(参考)
需求状态任务需求当前的状态
需求紧急程度需求的紧急程度

可以看出字段非常多而且复杂,让人眼花缭乱一时不知从何下手。其实是我们根据他们给出的问题一步一步来进行就好了。

问题重述

问题一:通过定量分析的方法,研究影响无车承运人平台进行货运线路定价的主要因素有哪些,并说明理由。

问题二:根据附件1数据,通过建立数学模型,对已经成交货运线路历史交易数据中的定价进行评价。

问题三:建立关于线路定价的数学模型,给出附件2的线路任务的三次报价以及总成本定价,并填充在附件3的表格中;给出合适的调价策略;并对附件2的线路任务所给出的定价进行评价。附件3将用于测试报价的准确性,对于某个确定的任务,三次报价中有一次成交,则后续价格将不再考虑。

问题四:结合对上述问题的研究,给无车承运人平台写一封不超过一页的建议信。

2. 问题一的思路及解法

思路

问题一要求我们运用定量分析的方法,对影响无车承运人平台进行货运线路定价的主要因素进行分析。我们主要采用相关性分析的方法对两个或多个具备相关性的变量进行分析,计算其相关系数,从而衡量两个变量因素的相关密切程度。相关性分析需要对于数据进行无量纲化处理,因此,该问的难点主要在于对附件1数据的预处理。

我的数据处理是使用python的pandas库进行数据处理的。程序在jupyter notebook中全部运行通过

数据处理完成之后,分别将定价和附件1中的因素进行相关性分析,计算出相关系数并进行排序,得出影响平台线路定价的主要因素。

具体做法

首先导入所需要的包

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

然后把附件一的数据读取到pandas对象中

data = pd.read_excel("附件1:货运线路历史交易数据.xlsx")

查看一下数据的信息

可以看出数据量比较大,而且存在很多离散型变量和时间类型的数据,而且我们需要对离散型变量进行编码然后才能做相关系数的运算。由于没有找到更好的编码方式 所以采用硬编码的方式。比如对于{'二级运输', '三级运输', '一级运输'} 编码为{1,2,3}。对于时间类型的数据我采用直接删除的方式处理

对数据进行硬编码

首先查看这些离散型数据都包含什么数值

print(set(data["业务类型"]))
print(set(data["需求类型1"]))
print(set(data["需求类型2"]))
print(set(data["是否续签"]))
print(set(data["成交对象"]))
print(set(data["标的展示策略"]))
print(set(data["打包类型"]))
print(set(data["子包号"]))
print(set(data["运输等级"]))
print(set(data["调价类型"]))
print(set(data["调价紧急程度"]))
print(set(data["车辆类型分类"]))
print(set(data["交易对象"]))
print(set(data["地区类型"]))
print(set(data["需求紧急程度"]))

运行结果如下

然后对他们进行编码,在编码的时候我对(“业务类型”,“需求类型1”,“运输等级”,“调价类型”,“调价紧急程度”,“需求紧急程度”)字段进行了指定重要性的编码,其他的字段的编码时随机编码。

代码如下

Map1 = {elem:index+1 for index,elem in enumerate(['重货', '速运'])}
Map2 = {elem:index+1 for index,elem in enumerate([ '普通','区域发运'])}
Map3 = {elem:index+1 for index,elem in enumerate(set(data["需求类型2"]))}
Map4 = {elem:index+1 for index,elem in enumerate(set(data["是否续签"]))}
Map6 = {elem:index+1 for index,elem in enumerate(set(data["成交对象"]))}
Map7 = {elem:index+1 for index,elem in enumerate(set(data["标的展示策略"]))}
Map8 = {elem:index+1 for index,elem in enumerate(set(data["打包类型"]))}
Map9 = {elem:index+1 for index,elem in enumerate(set(data["子包号"]))}
Map10 = {elem:index+1 for index,elem in enumerate(['三级运输','二级运输', '一级运输'])}
Map11 = {elem:index+1 for index,elem in enumerate(['调低', '未调整', '调高'])}
Map12 = {elem:index+1 for index,elem in enumerate(['N', '常规', '紧急', '非常紧急'])}
Map13 = {elem:index+1 for index,elem in enumerate(set(data["车辆类型分类"]))}
Map14 = {elem:index+1 for index,elem in enumerate(set(data["交易对象"]))}
Map15 = {elem:index+1 for index,elem in enumerate(set(data["地区类型"]))}
Map16 = {elem:index+1 for index,elem in enumerate([ '常规订单', '紧急订单','特急订单'])}
data['业务类型'] = data['业务类型'].map(Map1)
data['需求类型1'] = data['需求类型1'].map(Map2)
data['需求类型2'] = data['需求类型2'].map(Map3)
data['是否续签'] = data['是否续签'].map(Map4)
data['成交对象'] = data['成交对象'].map(Map6)
data['标的展示策略'] = data['标的展示策略'].map(Map7)
data['打包类型'] = data['打包类型'].map(Map8)
data['子包号'] = data['子包号'].map(Map9)
data['运输等级'] = data['运输等级'].map(Map10)
data['调价类型'] = data['调价类型'].map(Map11)
data['调价紧急程度'] = data['调价紧急程度'].map(Map12)
data['车辆类型分类'] = data['车辆类型分类'].map(Map13)
data['交易对象'] = data['交易对象'].map(Map14)
data['地区类型'] = data['地区类型'].map(Map15)
data['需求紧急程度'] = data['需求紧急程度'].map(Map16)

编码完成后我们的数据就变成了这样

 对数据进行清洗

在这一步我们需要对无用的数据以及空数据进行清洗

第一步:删除无用的列

dfclr = data.drop(["任务id","始发网点","实际到车时间","目的网点","交易成功时间","交易成功日期","计划发车时间","计划发车日期","分拨时间","最后一次询价时间","装卸的次数",
                         "装的次数","卸的次数","调价审核完成时间","调价ECP创建时间","是否需要装卸","始发地省份名称","实际靠车时间",
                         "实际结束时间","实际发车时间","任务状态","目的地省份名称","交易开始时间","交易结束时间","计划卸货完成时间","计划卸货等待时长","计划靠车时间",
                        "计划到达时间","地区","标的状态","标的_创建时间","标的_创建日期","异常状态","交易模式","需求状态","C端议价最低价","B端议价最低价","车辆类型分类","B端议价反馈数量"],axis=1)

第二步:删除线路总成本字段中有空值的行

dfclr = dfclr[~dfclr["线路总成本"].isin(["N"])]

第三步:将所有的数值转换成float类型

dfclr=pd.DataFrame(dfclr,dtype=np.float)

处理完成后查看我们的数据信息感觉清爽了很多 ,只剩下了23个字段,并且所有字段的数据类型都是float类型

相关系数的计算

下面进入我们的正题,计算相关系数。相关系数可以考察两个事物(在数据里我们称之为变量)之间的相关程度。下面是它的计算公式

formula

下面是计算相关系数的代码,直接调用pandas库的函数计算

dfclr.corr()

 现在我们就得到了所有字段之间的相关系数,下面我们根据这些相关系数画出他们的热力图

#设置字体为SimHei显示中文
plt.rcParams['font.sans-serif'] = 'SimHei'
#设置正常显示字符
plt.rcParams['axes.unicode_minus'] = False
# 设置图幅大小
plt.rcParams['figure.figsize'] = (17, 12)
plt.title('相关系数热力图',fontsize="xx-large")
plt.tick_params(labelsize=17)
# 计算相关系数
corrmatrix = dfclr.corr()
# 绘制热力图,热力图横纵坐标分别是data的index/column,vmax/vmin设置热力图颜色标识上下限,center显示颜色标识中心位置,cmap颜色标识颜色设置
sns.heatmap(corrmatrix,square=True,vmax=1,annot=True,vmin=-1,center=0.0,cmap='coolwarm')

然而我们需要的知识跟定价有关的相关系数 ,现在我们把那一列单独摘出来画一个柱状图并按相关系数值的大小进行排序

import numpy as np
# 将全局的字体设置为黑体
plt.rcParams['font.family'] = 'SimHei'
# 设置图幅大小
plt.rcParams['figure.figsize'] = (15, 10)
list = dfclr.corr()["线路价格(不含税)"]
list = sorted(np.abs(np.array(list)),reverse=True)
# 数据
N = 24
x = np.arange(N)
# 显示纵轴标签
plt.ylabel("相关系数",fontsize="xx-large")
# 添加地名坐标
str1 = ["线路价格(不含税)","总里程","线路总成本","线路指导价格","车辆吨位","车辆长度","运输等级","调价类型","地区类型","业务类型",
        "调价比例","需求类型2","需求紧急程度","C端反馈数量","交易成功时长","交易对象","打包类型","线路编码","调价紧急程度", "是否续签",
        "成交对象","标的展示策略","子包号","需求类型1"]

# 绘图 x x轴, height 高度, 默认:color="blue", width=0.8
p1 = plt.bar(x, height=list, width=0.5, label="相关系数柱状图", tick_label=str1)
plt.xticks(rotation=-90)  
# 添加数据标签
for a, b in zip(x, list):
    plt.text(a, b+ 0.02,'%.2f' % b, ha='center', va='bottom', fontsize=13)
    
plt.tick_params(labelsize=18)
# 添加图例
plt.legend(fontsize="xx-large")

# 展示图形
plt.show()

我们还需要一个线路指导价格的先关系数柱状图,也一并画出来

import numpy as np
# 将全局的字体设置为黑体
plt.rcParams['font.family'] = 'SimHei'
# 设置图幅大小
plt.rcParams['figure.figsize'] = (15, 10)
list = dfclr.corr()["线路指导价(不含税)"]
list = sorted(np.abs(np.array(list)),reverse=True)
# 数据
N = 24
x = np.arange(N)
# 显示纵轴标签
plt.ylabel("相关系数",fontsize="xx-large")
# 添加地名坐标
str1 = ["线路指导价格","总里程","线路总成本","线路价格(不含税)","车辆吨位","车辆长度","运输等级","调价类型","地区类型","业务类型",
        "调价比例","需求类型2","需求紧急程度","C端反馈数量","交易成功时长","交易对象","打包类型","线路编码","调价紧急程度", "是否续签",
        "成交对象","标的展示策略","子包号","需求类型1"]

# 绘图 x x轴, height 高度, 默认:color="blue", width=0.8
p1 = plt.bar(x, height=list, width=0.5, label="相关系数柱状图", tick_label=str1)
plt.xticks(rotation=-90)  
# 添加数据标签
for a, b in zip(x, list):
    plt.text(a, b+ 0.02,'%.2f' % b, ha='center', va='bottom', fontsize=13)
    
plt.tick_params(labelsize=18)
# 添加图例
plt.legend(fontsize="xx-large")

# 展示图形
plt.show()

进行到这里我们可以根据柱状图很容易得出结果,我们只考虑相关系数0.5以上的字段。

3. 问题二的思路以及具体实现

思路

问题二要求我们建立适当的数学模型对附件1中已成交的线路任务定价数据进行评价。本文中平台采用的是动态定价方式,因此我们站在平台的角度以价格溢出率[(成交价-成本价)/成本价]为评价指标对附件1中的定价数据进行评价。

在这个问题中主要是对数据进行了可视化分析

这是我们的整体思路

具体实现

首先导入所需要的库

from pyecharts.charts import Line
from pyecharts import options as opts
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

读取数据

data = pd.read_excel("附件1:货运线路历史交易数据.xlsx")

在这里我们只对线路成交价格和线路指导价格进行分析

df1 = pd.DataFrame({"线路价格":data['线路价格(不含税)'],"线路指导价(不含税)":data["线路指导价(不含税)"]})

 首先我们画出调价比例的箱线图

# 将全局的字体设置为黑体
plt.rcParams['font.family'] = 'SimHei'
plt.style.use("ggplot")  #使用ggplot的图形style
plt.rcParams["font.sans-serif"] = "SimHei"
plt.rcParams["axes.unicode_minus"] = False   # 设置中文、负号正常显示
plt.figure(figsize=(10,12))
plt.boxplot(x = data["调价比例"],     # 绘图数据 
            widths=0.2,   #设置箱体宽度
            medianprops={'color':'red'},  #中位线设置为红色
            boxprops=dict(color="blue"),  #箱体边框设置为蓝色
            labels="A",  #设置标签
            whiskerprops = {'color': "black"}, #设置须的颜色,黑色
            capprops = {'color': "green"},      #设置箱线图顶端和末端横线的属性,颜色为绿色
            flierprops={'color':'purple','markeredgecolor':"purple"} #异常值属性,这里没有异常值,所以没表现出来
            ) 
plt.ylim(0,3.5)  # 设置y轴的取值范围
plt.tick_params(labelsize=18)
plt.title("调价比例箱线图",fontsize="xx-large",color="#DE0052")
plt.tick_params(top="off", right="off")  # 去掉o箱线图的上方及右方边框的刻度标签
plt.show()   # 显示图形,jupyter notebook有另一种写法,可以不用每一次画图都码这句

从调价比例箱线图可以看出调价比例大部分分布在0.9~1.5之间

下面我们将调价比例画成散点图

import numpy as np
import matplotlib.pyplot as plt
x = sorted(data.index.to_list())
y = data["调价比例"]

plt.scatter(x,y,c="b",marker='.',s=50,edgecolor='b',alpha=0.5)
plt.show()

额... ...效果好像不是很好,但也能反映出一些问题

下面我们来分析线路知道价格与线路成交价格之间的差值频率分布直方图

#设置字体为SimHei显示中文
plt.rcParams['font.sans-serif'] = 'SimHei'
# 将全局的字体设置为黑体
plt.rcParams['font.family'] = 'SimHei'
df2["new"] = df2["线路指导价(不含税)"] - df2["线路价格"]
plt.hist(df2["new"], bins=50, facecolor="g",density=True, edgecolor="black", alpha=0.7)
# 显示横轴标签
plt.xlabel("区间",fontsize="xx-large")
# 显示纵轴标签
plt.ylabel("频数/频率",fontsize="xx-large")
# 显示图标题
plt.title("频数/频率分布直方图")
plt.tick_params(labelsize=18)
plt.show()

对该图进行分析,发现两种价格差值极小值为-10000,极大值为7500,,差值为0附近的所有数据频率约为0.002,而99%以上的线路指导价格都经过调整,即平台首次发布的线路指导价格不合理,不符合承运人的接受价格,在超过一定时间无人交易后需要进行调价处理。

然后其实还画了其它很多乱七八糟的图,但都有点辣眼睛,这里就不展示了

4. 问题三的思路与 具体实现

对于问题三,应该是本次竞赛的核心问题了。

这里给出我们的定价策略

需求等级程度

第一次定价

第二次定价

第三次定价

特急订单

Min(成本价,预测价)

Min+(Max-min)/2

Max(成本价,预测价)

紧急订单

Min(成本价,预测价)

Min+(Max-min)/2

Max(成本价,预测价)

常规订单

Min(成本价,预测价)

Min+(Max-min)/2

Max(成本价,预测价)

目标变化趋势

较低的承运成本                                  交易完成率和交易完成时间

对于价格我们根据附件一的数据训练了两个模型,第一个是对线路总成本的预测模型,第二个是对最终成交价的预测,分别对应上表中的成本价和预测价,对于调价策略自我感觉我们做的不是很好,但由于时间有限能力有限我们只能选择了当时认为最好的策略。

对于附件一和附件二的数据预处理主要有以下操作

  1. 若任务的某个指标的数据信息缺失严重,则直接剔除该指标;若对于某一特定指标的任务相对应的数据信息缺失严重则直接剔除相应的任务。
  2. 由于我们的值集群较多因此选用z-score 标准化的方法对数据进行标准化。这种方法基于原始数据的均值(mean)和标准差(standard deviation)进行数据的标准化。将A的原始值x使用z-score标准化到x'。该方法适用于属性A的最大值和最小值未知的情况,或有超出取值范围的离群数据的情况。表达式如下:新数据=(原数据-均值)/标准差
  3. 在第三问中我们对附件1中的离散型数据采用one-Hot编码进行了量化。One-Hot编码是分类编码作为二进制向量的表示,主要采用N位状态寄存器来对N个状态进行编码,每个状态都有它独立的寄存器位,并且在任意时候只有一位有效。

对于网络模型的结构参考下图

数据清洗

数据清洗包括对附件一和附件2的数据清洗,对于附件一由于要预测的值不同,所以要清洗出两份表格,这里只展示了对附件1的线路总成本预测模型所需要的数据进行清洗的流程。其他两个数据清洗流程跟这个大同小异,这里就不进行展示了。

首先是对附件一的数据清洗

导入所需要的库

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

读取数据

data = pd.read_excel("附件1:货运线路历史交易数据.xlsx")

对数据进行清理,清除掉不能用的字段

dfclr = data.drop(["任务id","始发网点","实际到车时间","目的网点","交易成功时间","交易成功日期","计划发车时间","计划发车日期",
                   "分拨时间","最后一次询价时间","装卸的次数","成交对象","调价紧急程度","调价类型","子包号","需求类型1",
                         "装的次数","卸的次数","调价审核完成时间","调价ECP创建时间","是否需要装卸","始发地省份名称","实际靠车时间",
                         "实际结束时间","实际发车时间","任务状态","目的地省份名称","交易开始时间","交易结束时间","计划卸货完成时间",
                  "计划靠车时间","C端议价反馈数量","线路价格(不含税)","交易成功时长","计划卸货等待时长","线路指导价(不含税)",
                        "计划到达时间","地区","标的状态","标的_创建时间","标的_创建日期","异常状态","交易模式",
                   "需求状态","C端议价最低价","B端议价最低价","车辆类型分类","B端议价反馈数量","调价比例"],axis=1)

删除线路总成本中空值行

dfclr = dfclr[~dfclr["线路总成本"].isin(["N"])]

对离散型数据进行one-hot编码

先将线路总成本对应的列弹出

dfclr1 = dfclr.copy()
dfclr1.pop("线路总成本")

进行编码

dfclr1 = pd.get_dummies(dfclr1)

删除附件二中没有对应字段的字段 

dfclr1.pop("是否续签_续签ECP审批驳回或撤销")

查看编码完成后的数据对象信息

 查看前五行数据

现在将线路总成本列添加进来,然后将所有数据 类型转化为float类型

dfclr1["线路总成本"] = dfclr["线路总成本"]

dfclr1=pd.DataFrame(dfclr1,dtype=np.float)

为了更好地训练网络,对数据进行标准化处理

首先将我们要预测的列弹出

dfclr1.pop("线路总成本")

将数据进行标准化处理

新数据=(原数据-均值)/标准差

def norm(x):
  return (x - dfclr1.mean()) / dfclr1.std()
data_normal = norm(dfclr1)

查看标准化完成后的数据

现在将要预测的数据列添加进来

data_normal["线路总成本"] = dfclr["线路总成本"] 
data_normal=pd.DataFrame(data_normal,dtype=np.float)

最后将处理好的数据保存到Excel文件中

data_normal.to_excel('清洗完成后的数据1.xlsx')

搭建神经网络模型,并进行训练

在这里我搭建了两个模型,一个是对线路总成本进行预测的模型,另一个是对最终成交价进行预测的模型,这里只展示对线路总成本进行预测的模型训练过程

导入所需要的库

from __future__ import absolute_import, division, print_function, unicode_literals

import pathlib

import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

import tensorflow as tf

from tensorflow import keras
from tensorflow.keras import layers

print(tf.__version__)

加载数据,这里用的是清洗完成后的数据

data = pd.read_excel("清洗完成后的数据1.xlsx")
dataset = data.copy()
dataset.tail()

运行结果

查看是否有缺失值

dataset.isna().sum()

拆分训练数据和测试数据集

现在需要将数据集拆分为一个训练数据集和一个测试数据集。

我们最后将使用测试数据集对模型进行评估。

train_dataset = dataset.sample(frac=0.8,random_state=0)
test_dataset = dataset.drop(train_dataset.index)

数据检查

快速查看训练集中的几队列联合分布

# 将全局的字体设置为黑体
plt.rcParams['font.family'] = 'SimHei'
#设置正常显示字符
plt.rcParams['axes.unicode_minus'] = False
sns.pairplot(train_dataset[["线路总成本", "总里程", "车辆吨位", "车辆长度"]], diag_kind="kde")
plt.show()

将要预测的标签特征分离出来

train_labels = train_dataset.pop('线路总成本')
test_labels = test_dataset.pop('线路总成本')

搭建模型

这个模型有两个全连接层和一个连续值的输出层

def build_model():
  model = keras.Sequential([
    layers.Dense(64, activation='relu', input_shape=[len(train_dataset.keys())]),
    layers.Dense(32, activation='relu'),
    layers.Dense(1)
  ])

  optimizer = tf.keras.optimizers.RMSprop(0.001)

  model.compile(loss='mse',
                optimizer=optimizer,
                metrics=['mae', 'mse'])
  return model

创建一个模型实例

model = build_model()

查看模型信息

model.summary()

现在试用下这个模型。从训练数据中批量获取‘10’条例子并对这些例子调用 model.predict 。

example_batch = train_dataset[:10]
example_result = model.predict(example_batch)
example_result

它在正常工作,产生了我们预期的输出数据类型的结果

训练模型

对模型进行500个周期的训练,并在 history 对象中记录训练和验证的准确性。

# 通过为每个完成的时期打印一个点来显示训练进度
class PrintDot(keras.callbacks.Callback):
  def on_epoch_end(self, epoch, logs):
    if epoch % 100 == 0: print('')
    print('.', end='')

EPOCHS = 500

history = model.fit(
  train_dataset, train_labels,
  epochs=EPOCHS, validation_split = 0.2, verbose=0,
  callbacks=[PrintDot()])

使用 history 对象中存储的统计信息可视化模型的训练进度。

hist = pd.DataFrame(history.history)
hist['epoch'] = history.epoch
hist.tail()

下面是输出的结果 

lossmaemseval_lossval_maeval_mseepoch
49530695.35937568.66534430695.35937532048.01171971.15033732048.011719495
49630554.22070368.84791630554.22070327903.93164163.92776527903.931641496
49730955.89257868.82836930955.89257828582.39843865.22719628582.398438497
49831000.63476668.84743531000.63476628017.33007865.29377728017.330078498
49930943.39453168.54085530943.39453128377.32031265.54468528377.320312499

我们将训练过程进行可视化

def plot_history(history):
  hist = pd.DataFrame(history.history)
  hist['epoch'] = history.epoch

  plt.figure()
  plt.xlabel('Epoch')
  plt.ylabel('Mean Abs Error [MPG]')
  plt.plot(hist['epoch'], hist['mae'],
           label='Train Error')
  plt.plot(hist['epoch'], hist['val_mae'],
           label = 'Val Error')
  plt.ylim([0,2000])
  plt.legend()

  plt.figure()
  plt.xlabel('Epoch')
  plt.ylabel('Mean Square Error [$MPG^2$]')
  plt.plot(hist['epoch'], hist['mse'],
           label='Train Error')
  plt.plot(hist['epoch'], hist['val_mse'],
           label = 'Val Error')
  plt.ylim([0,100000])
  plt.legend()
  plt.show()


plot_history(history)

该图表显示在约100个 epochs 之后误差非但没有改进,反而出现恶化。 让我们更新 model.fit 调用,当验证值没有提高上是自动停止训练。 我们将使用一个 EarlyStopping callback 来测试每个 epoch 的训练条件。如果经过一定数量的 epochs 后没有改进,则自动停止训练。

model = build_model()

# patience 值用来检查改进 epochs 的数量
early_stop = keras.callbacks.EarlyStopping(monitor='val_loss', patience=10)

history = model.fit(train_dataset, train_labels, epochs=EPOCHS,
                    validation_split = 0.2, verbose=0, callbacks=[early_stop, PrintDot()])

plot_history(history)

 现在让我们看看通过使用 测试集 来泛化模型的效果如何,我们在训练模型时没有使用测试集。

loss, mae, mse = model.evaluate(test_dataset, test_labels, verbose=2)

print("Testing set Mean Abs Error: {:5.2f} 元".format(mae))

结果还不错

下面要用我们的模型来对测试数据做预测

#设置字体为SimHei显示中文
plt.rcParams['font.sans-serif'] = 'SimHei'
#设置正常显示字符
plt.rcParams['axes.unicode_minus'] = False
# 设置图幅大小
plt.rcParams['figure.figsize'] = (10, 8)
test_predictions = model.predict(test_dataset).flatten()
plt.tick_params(labelsize=17)
plt.scatter(test_labels, test_predictions)
plt.xlabel('真实值 [线路总成本]',fontsize="xx-large")
plt.ylabel('预测值 [线路总成本]',fontsize="xx-large")
plt.axis('equal')
plt.axis('square')
plt.xlim([0,plt.xlim()[1]])
plt.ylim([0,plt.ylim()[1]])
_ = plt.plot([-15000, 15000], [-15000, 15000])

从图中可以看出模型预测结果基本拟合在一条直线上,说明我们的模型预测结果还不错

下面我们来看一下模型预测的误差分布

#设置字体为SimHei显示中文
plt.rcParams['font.sans-serif'] = 'SimHei'
#设置正常显示字符
plt.rcParams['axes.unicode_minus'] = False
# 设置图幅大小
plt.rcParams['figure.figsize'] = (10, 8)
plt.tick_params(labelsize=17)
error = test_predictions - test_labels
plt.hist(error, bins = 25)
plt.xlabel("预测值损失 [线路总成本]",fontsize="xx-large")
_ = plt.ylabel("数量",fontsize="xx-large")

从图中可以看出我们的模型预测结果误差分布呈高斯分布,大部分误差值都分布在0附近。

最后一步,使用我们的模型对附件2  的数据进行定价

导入附件2清洗后的数据

df_pre = pd.read_excel("附件2数据清理.xlsx")

做预测

result = model.predict(df_pre).flatten()

将预测结果存储到一个pandas对象中

data={
    '线路总成本':result
}
df_result = pd.DataFrame(data)

将预测的结果存到一个Excel表格中

df_result.to_excel('线路总成本的预测结果.xlsx')

至此,我们的定价预测已经完成

最后针对问题四,要求向无车承运人平台提出合理化建议。首先结合前三问的研究成果对当前无车承运人平台的线路定价策略进行评价,并且指出现阶段该无车承运人平台模式的优势以及劣势,最后,结合自己的研究成果向无车承运人平台提出合理化建议。这个我没有参与太多,这里就不多说了。

在这次竞赛过程中我主要负责实现队友的想法,所以对于数学建模和论文部分我没有参与太多。

对于以上内容希望大家多多批评指正。

  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
软件众包任务定价模型与人员匹配方法研究及工具实现,近年来,互联网新兴社会媒体和开放式创新正逐步重塑人与人之间分享信 息及协作的方式,同时也为软件开发模式带来了革新的机遇。基于众包的软件 开发通过互联网召集全球的在线开发者完成覆盖软件生命周期的多种任务。一 方面,该模式通过利用群体智慧可帮助企业整合外部资源,提升软件生产效率, 减少内部雇用开支,降低软件缺陷率。另一方面,由于软件众包与传统软件开 发模式存在着显著差异,其新特性也为其资源配置带来了新的挑战,主要体现 在软件众包任务资金和人员这两类核心资源的配置问题上:现有任务定价实践 对决策者的相关经验要求较高,且定价结果具有较强的主观性,不合理的任务 资金配置会增加额外的开发成本或降低用户参与度,进而影响项目预算或产品 交付:而开发人员面对大量并发任务,其任务选择行为具有一定的盲目性,易 于形成不恰当的人员配置结果,进而降低软件开发效率和制品质量。 基于以上研究背景,本文研究工作针对软件众包任务资源配置中亟待解决 的关键性问题,即对于任务报酬激励机制,如何制定合适的任务价格来尽可能 保证软件制品的交付率和质量;对于开放式开发模式,如何通过适当的机制, 引导外部开发人员在软件众包任务上形成合理的人员配置,促进软件开发效率 和制品质量的提升。总体而言,本论文的主要贡献如下。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值