题目:
一年一度的全国大学生数学建模竞赛是高等院校的重要赛事。由于竞赛场地、经费等原因,不是所有想参加竞赛的人都能被录用。为了能够选拔出真正优秀的同学代表学校参加竞赛,数学建模指导教师需要投入大量的精力,但是每年在参赛的时候还是有很多不如意之处:有的学生言过其实,有的队员之间合作不默契,影响了数学建模的成绩。
数学建模需要学生具有较好的数学基础知识、良好的编程能力、较强的写作能力、良好的团队合作精神,同时还要求具有一定的创新能力。
**问:**根据上表中信息,建立建模队员选拔的数学模型,要求从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(" A:") print("VectorA: ", VectorA) print("RootA: ", 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(" math:") print("mathVectorB: ", mathVectorB) print("mathRootBmax: ", 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(" write:") print("writeVectorB: ", writeVectorB) print("writeRootBmax: ", 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(" code:") print("codeVectorB: ", codeVectorB) print("codeRootBmax: ", 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(" team:") print("teamVectorB: ", teamVectorB) print("teamRootBmax: ", 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(" create:") print("createVectorB: ", createVectorB) print("createRootBmax: ", 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," 方案层判别矩阵的CR:",list_CRB) list_CR = list_CRB.copy() list_CR.append(CRA) print("B1~B5: CR: ", list_CRB) print("B1~B5: CI: ", 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("相对优势矩阵: ",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("各人最大相对优势: ", 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("各人的最大相对优势在矩阵中的坐标: ",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人的分数 ",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")
分组结果:请粘贴代码运行