2021年数学建模C题,解决其第一问
一、问题分析:
1.1问题:
根据附件 1,对 402 家供应商的供货特征进行量化分析,建立反映保障企业生产重要性的数学模型,在此基础上确定 50 家最重要的供应商,并在论文中列表给出结果。
1.2分析:
显而易见这是评价类问题,题目没有给出具体评价指标,我们自主构建,这里选取四个指标——供货强度、完成率、订单率和风险作为指标对供应商的重要性进行评估。
1.3指标构建:
供货强度:240周总供货量(第二个表每一行的总计)
完成率:240周总供货量/240周总订货量(2表每行总计/1表每行总计)
订单率:订单量大于10的周数/240
风险:供货量标准差(2表每行标准差)
二、Topsis:
前提条件:指标由数值衡量,稍后我们将对指标进行评分
2.1指标分类——原始矩阵正向化:
风险为极小型指标,这样处理!!!
完成率为中间型指标这样处理!!!
当然别忘了还有一种区间型指标,本题没用到
2.2消除量纲的影响:
标准化还有很多方法,如Z-score 标准化,最小-最大归一化,均值归一化,正则化等,大家可以多多尝试,本文使用的是L2 正则化。
2.3构造计算评分的公式:
单指标:
不足:最大和最小值永远都是1和0。
多指标:
注意:!不要纠结欧氏距离还是曼哈顿距离,都可以的,图片中是欧氏距离。
拓:指标权重,可以根据指标的重要性赋予一定的权重系数
哦豁,最后有一个小惊喜,我还以为上一篇看的那个层次分析法用不到了,没想到可以用在这里给指标确定权重,不错不错nice。
2.4归一化:
(比较简单,略)
三、具体代码:
3.1每一步代码解释:
1.首先导入数据,并计算出我们的四个指标,构成新的df。
import numpy as np
import pandas as pd
# 指定 Excel 文件的路径
path = "附件1 近5年402家供应商的相关数据.xlsx"
# 读取两个表
sheet1 = pd.read_excel(path, sheet_name='企业的订货量(m³)')
sheet2 = pd.read_excel(path, sheet_name='供应商的供货量(m³)')
# 计算每一行的总订货量和总供货量
total_order = sheet1.sum(axis=1)
total_supply = sheet2.sum(axis=1)
# 计算完成率
completion_rate = total_supply / total_order
# 创建一个新的 DataFrame 来存储结果
df = pd.DataFrame({
'Total_Supply': total_supply,
'Completion_Rate': completion_rate
})
# 计算订单率:订单量大于10的周数 / 240
orders_above_10 = (sheet1.iloc[:, 2:] > 10).sum(axis=1)
df['Order_Rate'] = orders_above_10 / 240
# 计算供货量的标准差
df['Supply_StdDev'] = sheet2.std(axis=1)
2.指标正向化
风险为极小型指标,这样处理!!!(具体公式见前面)
#对极小型风险指标正向化处理
max_value = df['Supply_StdDev'].max()
df['Supply_StdDe'] = df['Supply_StdDev'].apply(lambda x: max_value - x)
完成率为中间型指标这样处理!!!(具体公式见前面)
max_distance = (df['Completion_Rate'] - 1).abs().max()
df['Normalized_Completion_Rate'] = ((df['Completion_Rate'] - 1).abs() / max_distance).apply(lambda x: 1 - x)
3.消除量纲影响
# 使用 L2 正则化对每一列进行处理
df = df.apply(lambda x: x / np.sqrt(np.sum(np.square(x))))
4.计算得分
# 定义最大值和最小值矩阵
Z_plus = df.max()
Z_minus = df.min()
# 计算每个评价对象与最大值的距离 D^+
D_plus = np.sqrt(((df - Z_plus) ** 2).sum(axis=1))
# 计算每个评价对象与最小值的距离 D^-
D_minus = np.sqrt(((df - Z_minus) ** 2).sum(axis=1))
# 计算未归一化的得分 S_i
S_i = D_minus / (D_plus + D_minus)
df['Score'] = S_i/S_i.sum(axis=0)
5.排序输出结果(在排序前将供应商编号设为索引,排序后即可根据索引看出得分对应的供应商编号)
df['ID']=sheet1.iloc[:, 0]
df.set_index('ID', inplace=True)
df= df.sort_values(by='Score')
df
由图可以看出,得分最高的为S083,最低的为S140(ps:本题没有缺失数据,不需要预处理)
3.2代码汇总:
import numpy as np
import pandas as pd
# 指定 Excel 文件的路径
path = "附件1 近5年402家供应商的相关数据.xlsx"
# 读取两个表
sheet1 = pd.read_excel(path, sheet_name='企业的订货量(m³)')
sheet2 = pd.read_excel(path, sheet_name='供应商的供货量(m³)')
# 计算每一行的总订货量和总供货量
total_order = sheet1.sum(axis=1)
total_supply = sheet2.sum(axis=1)
# 计算完成率
completion_rate = total_supply / total_order
# 创建一个新的 DataFrame 来存储结果
df = pd.DataFrame({
'Total_Supply': total_supply,
'Completion_Rate': completion_rate
})
# 计算订单率:订单量大于10的周数 / 240
orders_above_10 = (sheet1.iloc[:, 2:] > 10).sum(axis=1)
df['Order_Rate'] = orders_above_10 / 240
# 计算供货量的标准差
df['Supply_StdDev'] = sheet2.std(axis=1)
max_value = df['Supply_StdDev'].max()
df['Supply_StdDe'] = df['Supply_StdDev'].apply(lambda x: max_value - x)
max_distance = (df['Completion_Rate'] - 1).abs().max()
df['Normalized_Completion_Rate'] = ((df['Completion_Rate'] - 1).abs() / max_distance).apply(lambda x: 1 - x)
# 使用 L2 正则化对每一列进行处理
df = df.apply(lambda x: x / np.sqrt(np.sum(np.square(x))))
# 定义最大值和最小值矩阵
Z_plus = df.max()
Z_minus = df.min()
# 计算每个评价对象与最大值的距离 D^+
D_plus = np.sqrt(((df - Z_plus) ** 2).sum(axis=1))
# 计算每个评价对象与最小值的距离 D^-
D_minus = np.sqrt(((df - Z_minus) ** 2).sum(axis=1))
# 计算未归一化的得分 S_i
S_i = D_minus / (D_plus + D_minus)
df['Score'] = S_i/S_i.sum(axis=0)
df['ID']=sheet1.iloc[:, 0]
df.set_index('ID', inplace=True)
df= df.sort_values(by='Score')
df
四、番外:权重的确定
无数据用层次分析法,有数据用熵权法。
接下来主要介绍熵权法,层次分析法见另一篇文章——层次分析法AHP(评价类问题)-优快云博客
4.1熵权法:
原理:指标变异程度越小(可片面理解为方差),所反映信息量越少,所对应的权值越低。
通俗解释:如果所有方案的某一指标数值相同,则该指标对方案评价排名无作用,权值应该为0.
4.2基本概念:
信息量:概率越大,信息量越小
信息熵——某事件的信息量期望:根据期望公式和信息量公式结合可得
信息熵越大,信息量越小,信息熵最大值为lnn(证明见图)
信息熵与信息量成反比,所以我们引入信息效用值:1-信息熵,代表事件信息量大小
4.3计算步骤:
1.计算指标信息熵
利用topsis第一步正向化和第二步消除量纲后得到的矩阵,我们计算出每个指标对应的信息熵,从而确定每个指标对应的权重。
指标=事件,n种方案=事件可能发生的n种情况,每种方案对应概率=该方案指标数值/总方案指标数值,如图:
2.对信息熵归一化处理
除以lnn,因为信息熵最大值为lnn,所以可将所有信息熵数值映射到[0,1]区间。
信息熵公式:
3.计算信息效用值