正在加载中...

展开本页目录
算法教程TODIM-交互式多准则决策法

TODIM-交互式多准则决策法

No.097 · 在线教程

TODIM(Tomada de Decisao Interativa Multicriterio,交互式多准则决策法)是一类基于前景理论思想的排序方法。其核心特征在于:不是直接对单个方案给出线性加权和,而是对任意两个方案在各指标上的“优势”与“劣势”分别赋予不同形式的效用函数,…

TODIM-交互式多准则决策法

1. 方法概述

TODIM(Tomada de Decisao Interativa Multicriterio,交互式多准则决策法)是一类基于前景理论思想的排序方法。其核心特征在于:不是直接对单个方案给出线性加权和,而是对任意两个方案在各指标上的“优势”与“劣势”分别赋予不同形式的效用函数,再汇总为总体支配度。

就本项目 具体的算法3/多指标评价/TODIM-交互式多准则决策法 的当前实现而言,完整流程为:

  • 读取对象列与指标列数据;
  • 对正向指标、负向指标、适度指标做同向化处理;
  • 对全部指标做 min-maxz-score + min-max 标准化;
  • 通过标准差赋权或自定义权重得到指标权重;
  • 以最大权重指标作为参考权重;
  • 计算两两方案间的 TODIM 优势函数与总体支配度;
  • 计算每个对象的总支配值并归一化为综合得分;
  • 按得分排序并导出 Excel、图表与复现脚本。

设共有 \(m\) 个评价对象、\(n\) 个指标,原始决策矩阵记为

$$ X=(x_{ij})_{m\times n}, \quad i=1,2,\ldots,m, \quad j=1,2,\ldots,n \tag{1} $$

设最终权重向量为

$$ w=\big(w_1,w_2,\ldots,w_n\big)^\top, \quad w_j\ge 0, \quad \sum_{j=1}^{n}w_j=1 \tag{2} $$

项目最终结果表中的核心列为:

  • 对象
  • 得分
  • 排名

其中 得分 越大表示对象越优,排名=1 表示最优对象

2. 输入结构与项目流程

2.1 输入数据要求

上传页 ui/upload_widget.py 支持 .xlsx.xls.csv 文件,也支持示例数据。结合 utils/data_validator.py,当前项目对输入数据的要求为:

  • 第 1 列为对象名称;
  • 第 2 列及以后为指标列;
  • 指标列必须全部可转为数值;
  • 指标列不允许空值;
  • 对象名称不允许重复;
  • 常数列不允许存在。

因此,进入核心 Calculator.run_analysis() 的数据结构可写为

$$ \mathcal{D}=\{A_i,\ x_{i1},x_{i2},\ldots,x_{in}\}_{i=1}^{m} \tag{3} $$

与 StandardDeviation 类似,当前核心还要求:

  • 至少选择 2 个指标;
  • 所选指标名必须都存在于数据表中。

2.2 界面参数流程

主窗口 ui/main_window.py 的标准流程为:

  1. 上传数据;
  2. 选择参与计算的指标;
  3. 设置每个指标的类型;
  4. 在参数页选择标准化方式、权重方式、标准差口径、风险参数 \(\theta\) 及敏感性分析;
  5. 结果页自动启动 TODIM 计算并导出结果。

方法页 ui/methods_widget.py 当前提供的关键参数为:

  • normalizationmin-maxz-score
  • weight_methodstdcustom
  • std_ddof01
  • theta:风险参数;
  • sensitivity:是否开启敏感性分析;
  • sensitivity_delta:权重扰动比例 \(\Delta\)。

若用户选择自定义权重,方法页会显示“设置自定义权重”按钮,并跳转到独立页面 ui/weight_editor_widget.py。该页面支持:

  • 逐页录入权重;
  • 当前页归一化;
  • 保存前自动校验总和是否约等于 1;
  • 必要时自动归一化到 1。

这意味着:与 SWARA 不同,TODIM 的自定义权重路径在当前 UI 主流程中是真正打通的。

3. 指标类型处理与标准化口径

3.1 中间矩阵定义

设方向调整后的中间矩阵记为

$$ U=(u_{ij})_{m\times n} \tag{4} $$

3.2 正向指标

若第 \(j\) 个指标为正向指标,则程序直接保留原值:

$$ u_{ij}=x_{ij} \tag{5} $$

3.3 负向指标

若第 \(j\) 个指标为负向指标,当前项目先做一次线性镜像变换:

$$ u_{ij}=x_j^{\max}+x_j^{\min}-x_{ij} \tag{6} $$

其中

$$ x_j^{\max}=\max_{1\le i\le m}x_{ij}, \quad x_j^{\min}=\min_{1\le i\le m}x_{ij} \tag{7} $$

随后再统一进入标准化流程。

3.4 适度指标

若第 \(j\) 个指标为适度指标,项目先构造“越接近目标值越好”的接近度:

$$ u_{ij}=1-\frac{|x_{ij}-t_j|}{\max\left(|x_j^{\max}-t_j|,\ |x_j^{\min}-t_j|\right)} \tag{8} $$

若分母为 0,则程序直接令

$$ u_{ij}=1 \tag{9} $$

这里 \(t_j\) 为适度指标标准值。当前项目在这点上的工程口径必须单独说明:

  • 核心 core/calculator.py 对适度指标要求必须提供 standard_values[col],否则直接报错;
  • 指标页 ui/indicators_widget.py 当前允许适度指标标准值取 0,并且不再强制非零校验;
  • 因此,若用户在界面中把某列切为“适度指标”但未手工改值,默认会把 0 传给核心。

也就是说,当前 TODIM 模块允许适度指标标准值为 0,但不会像 StandardDeviation 那样自动回退到均值或中位数。

3.5 Z-score 标准化

当用户选择 normalization="z-score" 时,程序先对 \(U\) 做标准分数变换:

$$ z_{ij}=\frac{u_{ij}-\mu_j}{\sigma_j} \tag{10} $$

其中

$$ \mu_j=\frac{1}{m}\sum_{i=1}^{m}u_{ij} \tag{11} $$

$$ \sigma_j=\sqrt{\frac{1}{m}\sum_{i=1}^{m}(u_{ij}-\mu_j)^2} \tag{12} $$

这里使用的是 std(ddof=0),不受 std_ddof 影响。

若 \(\sigma_j=0\),程序直接令该列

$$ z_{ij}=0 \tag{13} $$

随后再统一映射到 \([0,1]\):

$$ n_{ij}=\frac{z_{ij}-z_j^{\min}}{z_j^{\max}-z_j^{\min}} \tag{14} $$

3.6 Min-Max 标准化

当用户选择 normalization="min-max" 时,程序直接对 \(U\) 做线性归一化:

$$ n_{ij}=\frac{u_{ij}-u_j^{\min}}{u_j^{\max}-u_j^{\min}} \tag{15} $$

若分母为 0,则程序把该列直接置为 0。

3.7 最终标准化矩阵

综合上述处理后,TODIM 后续实际使用的标准化矩阵记为

$$ N=(n_{ij})_{m\times n} \tag{16} $$

TODIM 模块不会像某些文献实现那样分别为不同步骤准备不同尺度矩阵,而是直接在 \(N\) 上完成:

  • 标准差赋权;
  • TODIM 优势函数计算;
  • 敏感性分析。

4. 权重确定

4.1 标准差赋权

weight_method="std" 时,程序直接对标准化矩阵 \(N\) 的各列计算标准差。设第 \(j\) 个指标列均值为

$$ \bar{n}_j=\frac{1}{m}\sum_{i=1}^{m}n_{ij} \tag{17} $$

则其标准差定义为

$$ s_j=\sqrt{\frac{1}{m-\text{ddof}}\sum_{i=1}^{m}(n_{ij}-\bar{n}_j)^2} \tag{18} $$

其中

$$ \text{ddof}\in\{0,1\} \tag{19} $$

并由参数页中的 std_ddof 决定。

最终权重为

$$ w_j=\frac{s_j}{\sum_{k=1}^{n}s_k} \tag{20} $$

若所有标准差之和不大于 0,则程序直接报错“标准差为 0,无法计算权重”。

4.2 自定义权重

analysis_params 中传入 weights,核心会优先使用该权重输入,而不再依赖 weight_method 分支。设用户输入原始权重向量为

$$ \hat{w}=(\hat{w}_1,\hat{w}_2,\ldots,\hat{w}_n)^\top \tag{21} $$

则程序按指标顺序重排后统一归一化:

$$ w_j=\frac{\hat{w}_j}{\sum_{k=1}^{n}\hat{w}_k} \tag{22} $$

若自定义权重数量与指标数量不一致,或权重和不大于 0,则直接报错。

这一点需要单独指出:在核心实现中,weights_input 的优先级高于 weight_method。不过当前主窗口只有在用户明确选择“自定义权重”后才会构造该参数,因此 UI 主流程与用户感知是一致的。

4.3 参考权重

TODIM 计算中需要指定参考权重。当前实现采用“最大权重指标”为参考准则,即

$$ w_r=\max_{1\le j\le n}w_j \tag{23} $$

这正是 _todim_scores() 中的 w_r = np.max(w)

5. TODIM 优势函数与综合得分

5.1 成对差值

对任意两个对象 \(A_i\) 与 \(A_k\),在第 \(j\) 个指标上的标准化差值定义为

$$ d_{ijk}=n_{ij}-n_{kj} \tag{24} $$

5.2 单指标优势函数

若 \(d_{ijk}\ge 0\),程序采用收益型优势函数

$$ \phi_j(i,k)=\sqrt{\frac{w_j}{w_r}\,d_{ijk}} \tag{25} $$

若 \(d_{ijk}<0\),则采用损失型函数

$$ \phi_j(i,k)= -\frac{1}{\theta}\sqrt{\frac{w_j}{w_r}\,(-d_{ijk})} \tag{26} $$

其中 \(\theta>0\) 为 TODIM 风险参数。当前实现中:

  • \(\theta\) 越大,负向差异的惩罚幅度越弱;
  • \(\theta\) 越小,负向差异的惩罚越强。

程序会在参数检查阶段强制要求

$$ \theta>0 \tag{27} $$

5.3 总体支配度

对对象 \(A_i\) 相对于对象 \(A_k\) 的总体支配度,程序定义为

$$ \delta(i,k)=\sum_{j=1}^{n}\phi_j(i,k) \tag{28} $$

把所有对象两两比较后,得到支配矩阵

$$ \Delta=\big(\delta(i,k)\big)_{m\times m} \tag{29} $$

代码中 dominance_matrix 即对应式(29)。

5.4 对象总支配值与最终得分

对每个对象 \(A_i\),程序汇总其对所有其他对象的支配值:

$$ \Delta_i=\sum_{k=1}^{m}\delta(i,k) \tag{30} $$

然后再做一次线性归一化,得到最终 TODIM 得分:

$$ S_i=\frac{\Delta_i-\min_r \Delta_r}{\max_r \Delta_r-\min_r \Delta_r} \tag{31} $$

若所有 \(\Delta_i\) 相同,则程序会把所有得分置为 0。

5.5 排名规则

TODIM 当前采用

rank(ascending=False, method="dense")

生成名次,因此排名函数可写为

$$ R_i=\operatorname{rank}_{\downarrow}^{\text{dense}}(S_i) \tag{32} $$

这意味着:若存在并列得分,后续名次不会跳号。例如两个对象并列第 1,则下一名次为第 2,而不是第 3。

这一点与 StandardDeviation 模块使用的 method="min" 不同。

6. 敏感性分析

当参数页勾选敏感性分析时,程序会对每个指标权重分别构造“上调”和“下调”两个场景。

设原始权重为 \(w\),扰动比例为 \(\lambda\),若对第 \(j\) 个指标做正向扰动,则先令

$$ \tilde{w}_j^{(+)}=w_j(1+\lambda) \tag{33} $$

若做负向扰动,则令

$$ \tilde{w}_j^{(-)}=w_j\max(0,1-\lambda) \tag{34} $$

然后统一归一化得到新权重向量,再重新调用 TODIM 得分函数。

设扰动场景下第 \(i\) 个对象得分为 \(S_i^{(\pm,j)}\),则程序输出两项指标:

$$ \operatorname{MaxChange}_j^{(\pm)}= \max_i\left|S_i^{(\pm,j)}-S_i\right| \tag{35} $$

$$ \operatorname{MeanChange}_j^{(\pm)}= \frac{1}{m}\sum_i\left|S_i^{(\pm,j)}-S_i\right| \tag{36} $$

这些结果会写入:

  • step_results["sensitivity"]
  • Excel 的 Sensitivity 工作表

但只有开启敏感性分析时才会生成。

7. 输出结构、导出内容与复现

7.1 结果字典结构

Calculator.get_results() 返回的统一结果字典包括:

  • raw_data
  • processed_data
  • step_results
  • final_results
  • charts
  • parameters

其中:

  • raw_data 仅保存前 5 行预览;
  • processed_data 保存对象列名、指标集合和标准化矩阵;
  • step_results 保存权重、支配矩阵、\(\Delta_i\) 向量和敏感性分析;
  • final_results 保存最终权重和得分排名。

需要注意两点:

  • raw_data 并没有像 StandardDeviation 那样记录 shape/columns
  • processed_data["normalized"] 直接存储 to_dict(orient="list") 结果,而不是 DataFrame 预览对象。

7.2 Excel 工作表

当前模块导出的工作表包括:

  • Parameters
  • RawData
  • Normalized
  • Weights
  • DominanceMatrix
  • Delta
  • Scores
  • Sensitivity
  • Charts

其中:

  • DominanceMatrix 对应式(29)的支配矩阵;
  • Delta 对应式(30)的对象总支配值;
  • Scores 包含 对象/得分/排名

7.3 图表输出

当前模块默认输出两张图:

  • weights.png
  • scores.png

图表路径会写入 Charts 工作表和结果字典中的 charts 字段。

7.4 输出路径与复现脚本

若不传入 output_file,核心会在模块 results 目录下自动创建

TODIM-交互式多准则决策法分析结果_时间戳

目录,并生成

TODIM结果_时间戳.xlsx

若传入 output_file,则与 StandardDeviation 不同,TODIM 当前会 直接使用该路径,不会额外再套一层时间戳目录。

结果页 ui/results_widget.py 还支持导出复现脚本:

repro_todim_时间戳.py

该脚本会复用:

  • 原始数据路径;
  • 指标类型;
  • 适度指标标准值;
  • 标准化方式;
  • 权重方式;
  • 自定义权重;
  • std_ddof
  • theta
  • 敏感性分析参数。

因此,TODIM 当前已经形成“结果文件 + 图表 + 复现脚本”的完整复现实验输出链。

8. 与代码实现的对应关系

8.1 TODIM 前仍然要先做标准化和同向化

不少文献在介绍 TODIM 时直接从属性差值和优势函数切入,但本项目在进入 TODIM 优势函数之前,明确先做了:

  • 正向/负向/适度指标处理;
  • min-maxz-score + min-max 标准化。

因此,项目中的 TODIM 优势函数并不是直接建立在原始矩阵 \(X\) 上,而是建立在标准化矩阵 \(N\) 上。

8.2 权重不一定来自 TODIM 外部

传统 TODIM 经常把权重视为外部给定量。但在本项目中:

  • 可以直接用标准差赋权自动生成;
  • 也可以走自定义权重;
  • 主窗口默认推荐标准差赋权。

因此,这一模块在工程上已经把“客观赋权 + TODIM 排序”合并成一个完整算法页面。

8.3 std_ddof 只影响标准差赋权,不影响 Z-score

这与 StandardDeviation 模块类似,也是一个容易写错的点:

  • Z-score 固定使用 ddof=0
  • std_ddof 只影响标准差赋权中的式(18)。

8.4 排名采用 dense 规则

当前 TODIM 已按问题整改说明改为 dense 排名,不再使用会强制拆开并列名次的唯一次序规则。因此,在论文或系统说明中,应该把并列处理写成“dense 规则”。

9. 项目回归测试口径

当前模块已配套如下测试:

  • Z冒烟测试/test_todim_smoke.py
  • Z冒烟测试/test_todim_baseline.py
  • Z冒烟测试/test_todim_ui_flow.py

并有增强回归报告:

  • Z冒烟测试/TODIM-交互式多准则决策法_增强回归与UI链路报告_20260310.md

9.1 基线参数口径

基线文件 todim_baseline.csv 使用:

  • 指标集合:指标1, 指标2, 指标3
  • 指标类型:正向, 负向, 适度
  • 适度指标标准值:指标3 = 5
  • 标准化方式:min-max
  • 权重方式:std
  • 标准差口径:std_ddof = 0
  • 风险参数:\(\theta = 1.0\)
  • 敏感性分析:关闭

在这一代码口径下,权重向量为

$$ w= \big( 0.3391344200,\ 0.3391344200,\ 0.3217311600 \big)^\top \tag{37} $$

对应对象排序为

$$ C \succ A \succ B \succ D \tag{38} $$

对应最终得分为

$$ \big( 1.0000000000,\ 0.6143689308,\ 0.3856310692,\ 0.0000000000 \big) \tag{39} $$

对应总支配值向量为

$$ \big( 1.6329931619,\ -1.6329931619,\ 7.1391467547,\ -7.1391467547 \big) \tag{40} $$

同时,基线测试还验证:

  • dominance_matrix 为 \(4\times 4\);
  • 权重和为 1;
  • 结果工作簿非空。

9.2 UI 流程验证

当前 UI 冒烟测试 test_todim_ui_flow.py 还验证了以下行为:

  • 上传 todim_baseline.csv 后能自动切到指标页;
  • 指标页与参数页点击确认后能自动进入结果页;
  • 结果页成功显示“打开结果目录”按钮;
  • 计算完成后能够通过“重置并回到主页面”返回首页。

因此,上述公式、参数与数值可以直接作为当前项目 TODIM 模块撰写论文说明、系统说明和复现实验文档时的代码依据。

10. 论文写作模板

10.1 方法描述模板

“本文采用 TODIM 方法对备选对象进行多准则排序。首先根据指标属性对原始数据进行同向化处理与标准化,得到标准化矩阵 \(N\)(式(4)–式(16));随后依据标准差赋权或自定义权重确定指标权重(式(17)–式(23)),并以最大权重指标作为参考准则。进一步地,对任意两个对象在各指标上的差值构造收益型与损失型优势函数(式(24)–式(27)),并汇总形成总体支配矩阵 \(\Delta\)(式(28)–式(29))。最终根据总支配值及其归一化得分 \(S_i\)(式(30)–式(31))完成排序(式(32))。”

10.2 结果解释模板

结果部分可写为:TODIM 结果表中的得分 \(S_i\) 越大表示对象整体优势越强。与简单加权和模型不同,TODIM 强调对象之间的两两比较和心理感知式收益/损失差异,因此能够同时体现‘优势收益’与‘劣势惩罚’。其中,风险参数 \(\theta\) 控制损失项的惩罚幅度:\(\theta\) 越大,负向差异的惩罚越弱;\(\theta\) 越小,负向差异的惩罚越强。若研究还进行了敏感性分析,则可进一步从最大变化量与平均变化量两方面评估结果稳健性。

10.3 表格标题模板

  1. 表 1 TODIM 指标类型、标准值与参数设置表
  2. 表 2 TODIM 指标权重结果表
  3. 表 3 TODIM 总支配值与综合得分结果表
  4. 表 4 TODIM 支配矩阵结果表
  5. 表 5 TODIM 敏感性分析结果表

10.4 图表题注模板

  1. 图 1 TODIM 指标权重图。
  2. 图 2 TODIM 综合得分图。

10.5 表格示例

表 1 TODIM 综合评价结果

对象 总支配值 \(\Delta_i\) 综合得分 \(S_i\) 排名
A
B

表注:总支配值 \(\Delta_i\) 按式(30)计算,综合得分 \(S_i\) 按式(31)归一化得到,取值越大表示对象越优。

表 2 TODIM 敏感性分析结果

指标 场景 最大得分变化 平均得分变化
指标1 \(+\lambda\)
指标1 \(-\lambda\)

表注:敏感性分析中的权重扰动规则见式(33)–式(36),用于评估得分对权重变化的稳定性。

11. 单篇终审补充

11.1 图题与表题对齐建议

  • Parameters 表可写为:表X TODIM 参数设置表。
  • RawData 表可写为:表X TODIM 原始数据表。
  • Normalized 表可写为:表X TODIM 标准化矩阵表。
  • Weights 表可写为:表X TODIM 指标权重表。
  • DominanceMatrix 表可写为:表X TODIM 支配矩阵表。
  • Delta 表可写为:表X TODIM 总支配值结果表。
  • Scores 表可写为:表X TODIM 综合得分与排序表。
  • Charts 表可写为:表X TODIM 图表索引表。
  • weights.png 建议写为:图X TODIM 指标权重图。
  • scores.png 建议写为:图X TODIM 综合得分图。

11.2 终审说明

  • 当前代表性结果目录可采用 results/manual_check_20260321_01。其中主工作簿为 TODIM_manual.xlsx,复现输出为 repro_outputs/TODIM_repro_output.xlsx
  • 当前真实工作表为 Parameters/RawData/Normalized/Weights/DominanceMatrix/Delta/Scores/Charts。论文表题应按这组英文 sheet 名落地。
  • 当前稳定实体图文件为 charts/weights.pngcharts/scores.png。正文若解释“优势收益/劣势惩罚”,应同时引用 DominanceMatrixDelta 两张表,而不是只展示最终得分图。
  • 真实 repro 脚本为 repro_todim_portable_20260321_051830.py。它不是读取 repro_inputs/...,而是直接通过 SRC_XLSX = THIS_DIR / 'TODIM_manual.xlsx' 回读主结果簿,再从 ParametersRawData 两张表中恢复计算参数与原始数据。附录应把这一“结果簿自恢复复现”机制写清。
  • 当前脚本依赖结果目录中的 repro_module/core/。论文若强调可移植复现,应补充说明结果包中已携带必要核心模块,而不是依赖外部主工程导入。

11.3 全量强化补充

  • 当前首层主结果目录应固定为 具体的算法3/多指标评价/TODIM-交互式多准则决策法/results/manual_check_20260321_01。首层主工作簿为 具体的算法3/多指标评价/TODIM-交互式多准则决策法/results/manual_check_20260321_01/TODIM_manual.xlsx
  • 当前主工作簿实际工作表为 ParametersRawDataNormalizedWeightsDominanceMatrixDeltaScoresCharts,与旧文一致。复现输出位于首层 repro_outputs/TODIM_repro_output.xlsx,但该复现结果不应与 TODIM_manual.xlsx 并列写成两份主结果。
  • 当前首层图文件只有两张,分别是 具体的算法3/多指标评价/TODIM-交互式多准则决策法/results/manual_check_20260321_01/charts/weights.pngscores.png。对应的复现图位于 具体的算法3/多指标评价/TODIM-交互式多准则决策法/results/manual_check_20260321_01/repro_outputs/charts/
  • 当前 repro 脚本为 具体的算法3/多指标评价/TODIM-交互式多准则决策法/results/manual_check_20260321_01/repro_todim_portable_20260321_051830.py,其真实输入机制是 SRC_XLSX = THIS_DIR / 'TODIM_manual.xlsx',然后从主结果簿的 RawDataParameters 中恢复计算条件,再将结果输出到 THIS_DIR / 'repro_outputs'。因此它属于标准的“结果簿自恢复复现”口径,而不是 repro_inputs/... 输入副本口径。
  • 当前目录内还打包了 repro_module/core/repro_module/utils/。因此这篇文档应明确说明:TODIM 的复现可移植性依赖结果包中附带的 repro_module,而不是依赖主工程运行时环境去导入原始模块。

12. 软件实现核查补充(2026-07)

  • 当前主结果目录应写作 具体的算法3/多指标评价/TODIM-交互式多准则决策法/results/manual_check_20260321_01
  • 正文应围绕 ParametersRawDataNormalizedWeightsDominanceMatrixDeltaScoresCharts 来写。
  • 图证应对应 weights.pngscores.png,并把优势收益、劣势惩罚与最终得分的关系写清。
  • 复现脚本应按 repro_todim_portable_20260321_051830.py + TODIM_manual.xlsx 的口径说明;repro_module/ 是结果包自带的可移植复现依赖。