题目:
一年一度的全国大学生数学建模竞赛是高等院校的重要赛事。由于竞赛场地、经费等原因,不是所有想参加竞赛的人都能被录用。为了能够选拔出真正优秀的同学代表学校参加竞赛,数学建模指导教师需要投入大量的精力,但是每年在参赛的时候还是有很多不如意之处:有的学生言过其实,有的队员之间合作不默契,影响了数学建模的成绩。
数学建模需要学生具有较好的数学基础知识、良好的编程能力、较强的写作能力、良好的团队合作精神,同时还要求具有一定的创新能力。
**问:**根据上表中信息,建立建模队员选拔的数学模型,要求从9名同学中选择6名组成2队参加竞赛,使得这两个参赛队有较好的竞技水平,要求模型具有可推广性。
明确问题:问题叫我们从9个人里面选6个人【并且这6个人要分为2组,每一组要有较好的竞技水平】
再次审题: 1.题目要求各方面都需要较良好,所以首先要考虑综合水平最强的。2.搭配3人一组,这三人要有所特质,取长补短。
分析:本题建立层次分析模型,逐一算出各方案层、准则层,然后做出决断选出最优秀的6个人;之后在这6个人里面,根据每个人的优势进行组队。为了便于计算,我就只选取了数学成绩、写作能力、编程能力这三个特征来作为优势度的选取。最后算出每个人的每个特征的相对本人自己的其它特征的相对优势,然后根据相对优势进行三三搭配,每个人的优势都得到发挥,要是出现几个人的相对优势最高的都出现在同一项特征里面,则选取次高的特征作为分组参考;
模型优缺点分析:使用层次分析模型会涉及人为的打相对优势权重【其实、我看来,经验的判断也属于人为的,因为经验是前人或者你自己积累出来的】;这里采取经验的赋予权重,也就是如果这个人的某项比另一项特征高分,则对于这个人来说,高分项比较重要。
代码实现:
【基于anaconda python3.7 注释包含在代码中】
# -*- coding: utf-8 -*-
# @Time : 2019/5/22 14:41
# @Author : data mining
# @File : AHP.py
import numpy as np
import numpy.matlib
import heapq
class AHP:
#所研究数据
arry = np.array([[98,90,87,76,90,83,79,88,94],
['优','良','优','良','中','优','优','良','中'],
[78,90,69,96,84,96,82,79,95],
['良','良','差','优','良','优','优','优','中'],
['优','中','优','中','优','良','良','良','中']])
resxx = []
# res1 = []
def __init__(self):
self.resxx = self.resxx
self.arry1 = np.copy(self.arry) #备用
self.arry2 = np.copy(self.arry)
def get_matrixA(self,data1,data2): #获得准则层 判别矩阵A
matrix = np.matlib.ones((len(data1),len(data2))) #生成以1填充的矩阵
matrix = np.asarray(matrix)
#交叉比较
for i in range(0,len(data1)):
for j in range(0, len(data2)):
if data1[i] - data2[j] == 4:
matrix[i][j] = 4.0
elif data1[i] - data2[j] == 3:
matrix[i][j] = 5.0
elif data1[i] - data2[j] == 2:
matrix[i][j] = 3.0
elif data1[i] - data2[j] == 1:
matrix[i][j] = 2.0
elif data1[i] - data2[j] == 0:
matrix[i][j] = 1.0
elif data1[i] - data2[j] == -4:
matrix[i][j] = 1 / 4
elif data1[i] - data2[j] == -3:
matrix[i][j] = 1 / 5
elif data1[i] - data2[j] == -2:
matrix[i][j] = float(str(1 / 3)[:4])
elif data1[i] - data2[j] == -1:
matrix[i][j] = 1 / 2
matrixA = np.asmatrix(matrix)
print("matrixA:")
print(matrixA)
return matrixA #判别矩阵A
def get_matrixB(self,data1,data2): #获得方案层 判别矩阵B
matrix = np.matlib.ones((9,9))
matrix = np.asarray(matrix)
if type(data1[0]) is float:
for i in range(0, len(data1)):
for j in range(0, len(data2)):
if i == j:
matrix[i][j] = 1.0
else:
if data1[i] == data2[j]:
matrix[i][j] = 1.0
elif data1[i] > data2[j]: ##行大于列
if (data1[i]-data2[j]) <=2:
matrix[i][j] = 1.0
elif 3<=(data1[i]-data2[j]) <5:
matrix[i][j] = 2.0
elif 5<=(data1[i]-data2[j]) <6:
matrix[i][j] = 3.0
elif 6<=(data1[i]-data2[j]) <8:
matrix[i][j] = 4.0
else:
matrix[i][j] = 5.0
elif data1[i] < data2[j]: #行小于列
if (data1[i] - data2[j])>= -3:
matrix[i][j] = 1.0
elif -5 <(data1[i]-data2[j]) <-3:
matrix[i][j] = float(str(1/3)[:4])
else:
matrix[i][j] = 1/5
else:
for i in range(0, len(data1)):
for j in range(0, len(data2)):
if i == j:
matrix[i][j] = str(1.0)
else:
if data1[i] == data2[j]:
matrix[i][j] = str(1.0)
elif data1[i]=='优' and data2[j]=='良':
matrix[i][j] = str(3.0)
elif data1[i]=='优' and data2[j]=='中':
matrix[i][j] = str(5.0)
elif data1[i]=='优' and data2[j]=='差':
matrix[i][j] = str(9.0)
elif data1[i]=='良' and data2[j]=='优':
matrix[i][j] = str(str(1/3)[:4])
elif data1[i]=='良' and data2[j]=='中':
matrix[i][j] = str(4.0)
elif data1[i]=='良' and data2[j]=='差':
matrix[i][j] = str(7.0)
elif data1[i]=='中' and data2[j]=='优':
matrix[i][j] = str(1/5)
elif data1[i]=='中' and data2[j]=='良':
matrix[i][j] = str(1/4)
elif data1[i]=='中' and data2[j]=='差':
matrix[i][j] = str(3.0)
elif data1[i]=='差' and data2[j]=='优':
matrix[i][j] = str(str(1/9)[:4])
elif data1[i]=='差' and data2[j]=='良':
matrix[i][j] = str(str(1/7)[:4])
elif data1[i]=='差' and data2[j]=='中':
matrix[i][j] = str(str(1/3)[:4])
matrix = np.asarray(matrix,dtype=float)
matrixB = np.asmatrix(matrix)
return matrixB #判别矩阵B
def getA_function(self): #准则层判别矩阵 5*5
abilityList = [5,4,3,2,1]
matrixA = AHP.get_matrixA(self,data1=abilityList,data2=abilityList) # 判别矩阵
VectorA,RootA = AHP.get_Vector_Root(self,matrixA)
print("\nA:")
print("VectorA:\n", VectorA)
print("RootA:\n", RootA)
return VectorA,RootA
def get_Vector_Root(self,dataArray): #特征根和特征向量
dataArray = np.asarray(dataArray)
dataCenter = np.copy(dataArray)
# dataCenter按列求和
columnMatrixCenter = dataCenter.sum(axis=0)
for i in range(1, len(dataArray) + 1): # dataCenter列向量归一化
dataCenter[:, i - 1:i] = dataCenter[:, i - 1:i] * (1 / columnMatrixCenter[i - 1])
# dataCenter行向量求和
linedataCenter = np.asarray(np.asmatrix(np.asarray(dataCenter.sum(axis=1))).T)
# linedataCenter按列求和 【只有一列求和了】
columnLinedataCenter = linedataCenter.sum(axis=0)
for i in range(1, len(linedataCenter)): # linedataCenter列向量归一化
linedataCenter[:, i - 1:i] = linedataCenter[:, i - 1:i] * (1 / columnLinedataCenter)
vector = linedataCenter # 特征向量
root = dataArray @ vector
sumi = 0
for i in range(0,len(dataArray)):
sumi += root[i] / vector[i]
Rootmax = (1 / len(dataArray)) * sumi #最大特征根
return vector, Rootmax
def getB_function(self): #计算方案层 判别矩阵 Value特征根 Vector特征向量 #B1~B5矩阵 9*9
mathTrixB = AHP.get_matrixB(self,data1=list(map(float,list(self.arry2[0]))),data2=list(map(float,list(self.arry2[0]))))
mathVectorB,mathRootBmax = AHP.get_Vector_Root(self,mathTrixB)
print("\nmath:")
print("mathVectorB:\n", mathVectorB)
print("mathRootBmax:\n", mathRootBmax)
writeTrixB = AHP.get_matrixB(self, data1=list(self.arry2[1]), data2=list(self.arry2[1]))
writeVectorB, writeRootBmax = AHP.get_Vector_Root(self, writeTrixB)
print("\nwrite:")
print("writeVectorB:\n", writeVectorB)
print("writeRootBmax:\n", writeRootBmax)
codeTrixB = AHP.get_matrixB(self,data1=list(map(float,list(self.arry2[2]))),data2=list(map(float,list(self.arry2[2]))))
codeVectorB, codeRootBmax = AHP.get_Vector_Root(self, codeTrixB)
print("\ncode:")
print("codeVectorB:\n", codeVectorB)
print("codeRootBmax:\n", codeRootBmax)
teamTrixB = AHP.get_matrixB(self,data1=list(self.arry2[3]),data2=list(self.arry2[3]))
teamVectorB,teamRootBmax = AHP.get_Vector_Root(self, teamTrixB)
print("\nteam:")
print("teamVectorB:\n", teamVectorB)
print("teamRootBmax:\n", teamRootBmax)
createTrixB = AHP.get_matrixB(self,data1=list(self.arry2[4]),data2=list(self.arry2[4]))
createVectorB, createRootBmax = AHP.get_Vector_Root(self, createTrixB)
print("\ncreate:")
print("createVectorB:\n", createVectorB)
print("createRootBmax:\n", createRootBmax)
rootB = [mathRootBmax,writeRootBmax,codeRootBmax,teamRootBmax,createRootBmax]
vectorB = [mathVectorB,writeVectorB,codeVectorB,teamVectorB,createVectorB]
# root 特征根
#vector 特征向量
return rootB,vectorB
def CR(self,vector,root): #计算一致性比率CR和一致性指标CI
# n = len(array) 5的时候n = 1.12 9的时候n = 1.45【查表得知】
if(len(vector)==5):
RI=1.12
CI = (root-len(vector)) / (len(vector)-1)
CR = CI/RI
else:
RI = 1.45
CI = (root - len(vector)) / (len(vector) - 1)
CR = CI / RI
return CR,CI
def judge_choose(self):
VectorA,RootA = AHP.getA_function(self)
CRA,CIA = AHP.CR(self,VectorA,RootA) #通过检测
print("CRA",CRA)
print("CIA",CIA)
listRootB, listVectorB = AHP.getB_function(self)
list_CRB = [] #通过检测
list_CIB = []
for i in range(0,5):
CR,CI = AHP.CR(self,listVectorB[i],listRootB[i])
list_CRB.append(CR)
list_CIB.append(CI)
# print("准则层判别矩阵的CR: ",CRA,"\n方案层判别矩阵的CR:",list_CRB)
list_CR = list_CRB.copy()
list_CR.append(CRA)
print("B1~B5: CR:\n", list_CRB)
print("B1~B5: CI: \n", list_CIB)
testList = []
for i in list_CR:
if i[0]<0.1:
testList.append(1)
# 所有判别矩阵的CR都小于0.1,不一致性程度在容许范围内,此时特征向量作为权向量。
# self.resxx = []
if sum(testList) == 6:
self.arry = np.hstack([listVectorB[0], listVectorB[1]])
for i in range(2,5):
self.arry = np.hstack([self.arry, listVectorB[i]])
# 选人
reslute = [] #存储人的序号 的列表
for i in range(0,9):
reslute.append((self.arry@VectorA)[i][0])
self.res1 = list(map(reslute.index, heapq.nlargest(6, reslute)))
self.resxx = [i+1 for i in self.res1]
else:
pass
self.res1 = self.res1
print("选中的人的矩阵行号:",self.res1)
print("被命运选中的人",self.resxx)
return self.resxx,self.res1
def grouping(self):
chooseNum,res = AHP.judge_choose(self)
self.arry1 = np.asarray(np.asmatrix(self.arry1).T)
self.target = np.vstack([self.arry1[res[0]],self.arry1[res[1]]])
for i in range(2,6):
self.target = np.vstack([self.target,self.arry1[res[i]]])
self.target = np.asarray(np.asmatrix(self.target))[:,:3]
for i in range(0,len(self.target)):
for j in range(0,len(self.target[i])):
if self.target[i][j] == '优':
self.target[i][j] = '95'
elif self.target[i][j] == '良':
self.target[i][j] = '85'
elif self.target[i][j] == '中':
self.target[i][j] = '75'
elif self.target[i][j] == '差':
self.target[i][j] = '65'
self.target = np.asarray(self.target,dtype=float)
cmean = self.target.mean(axis=0) #按列求均值
cstd = self.target.std(axis=0) #求标准差
relative_adv = (self.target-cmean)/cstd #相对优势
print("相对优势矩阵:\n",relative_adv)
relative_adv_Max = np.max(relative_adv, axis=1) #按行
maxAdv = []
for i in range(0,len(relative_adv_Max)):
maxAdv.append(float(relative_adv_Max[i]))
# print("各人最大相对优势:\n", maxAdv)
position = []
relative_adv_matrix = np.asmatrix(relative_adv)
for value in range(0,len(maxAdv)):
index = np.argwhere(relative_adv_matrix == maxAdv[value])
if value == 3:
position.append(index[2])
elif value == 4:
position.append(index[3])
else:
position.append(index)
print("各人的最大相对优势在矩阵中的坐标:\n",np.asarray(position).reshape(6,1))
self.group = []
for i in range(0,len(chooseNum)):
self.group.append([chooseNum[i],self.target[i]])
print("被选中的6人的分数\n",np.asarray(self.group))
allList = [] #在满足条件下,所有可能分组
firstList = []
secondList = []
manTime = []
chooseOne = chooseNum.copy()
chooseTWo = chooseNum.copy()
for i in range(1,4):
#0-1 1-2 2-3
if i == 1:
coumIndex = np.argwhere(relative_adv_matrix == float(np.max(relative_adv[:, i - 1:i], axis=0)[0]))
manTime.append(coumIndex[0][0])
firstList.append(chooseNum[int(coumIndex[0][0])]) #添加第几号人
chooseOne.remove(chooseOne[int(coumIndex[0][0])])
secondList.append(chooseNum[int(coumIndex[0][0])]) # 添加第几号人
chooseTWo.remove(chooseTWo[int(coumIndex[0][0])])
elif i == 2:
coumIndex = np.argwhere(relative_adv_matrix == float(np.max(relative_adv[:, i - 1:i], axis=0)[0]))
coumIndex2 = coumIndex
i = 3
coumIndex3 = np.argwhere(relative_adv_matrix == float(np.max(relative_adv[:, i - 1:i], axis=0)[0]))
manTime.append(coumIndex3[0][0])
firstList.append(chooseNum[int(coumIndex3[0][0])])
chooseOne.remove(chooseOne[int(coumIndex3[0][0])-1])
secondList.append(chooseNum[int(coumIndex3[0][0])])
chooseTWo.remove(chooseTWo[int(coumIndex3[0][0]) - 1])
for j in range(0, len(coumIndex2)):
if coumIndex2[j][0] == manTime[0]:
pass
elif coumIndex2[j][0] == manTime[1]:
pass
else:
if coumIndex2[j][0] == 3:
firstList.append(chooseNum[int(coumIndex2[j][0])])
chooseOne.remove(chooseOne[int(coumIndex2[0][0])-3])
allList.append((firstList,chooseOne))
if coumIndex2[j][0] == 4:
secondList.append(chooseNum[int(coumIndex2[j][0])])
chooseTWo.remove(chooseTWo[int(coumIndex2[0][0]) - 2])
allList.append((secondList, chooseTWo))
elif i == 3:
pass
return allList
def main(self):
chooseGroup = AHP.grouping(self)
for i in range(0,len(chooseGroup)):
print("第{}种有效的分组:".format(i+1),chooseGroup[0])
if __name__ == '__main__':
a = AHP()
a.main()
print("【查RI表得知】:")
print("RI: n=5的时候 RI5=1.12 ; n=9的时候 RI9=1.45")
分组结果:请粘贴代码运行