最近在整理一批效率评价数据时,我又把MATLAB里的SBM-DEA模型翻出来完整重写了一遍。此前用CCR和BCC模型跑,结果一批决策单元全是效率1,根本没法排序;换到SBM模型,情况好转了一些,但有效单元之间还是拉不开差距。直到把超效率SBM也加进来,整个评价闭环才算真正补完。这篇就把SBM-DEA模型从原理到MATLAB落地做一个完整梳理,重点讲清楚超效率和非超效率分别怎么算、非期望产出怎么进入模型、安装环境需要准备什么、操作流程怎么走,最后补上我实际踩过的几个坑。适合正在写效率测算章节的研究生、做投入产出绩效评估的分析人员,以及所有需要在MATLAB里跑DEA的实践者参考。
1. SBM-DEA模型到底解决什么问题:原理与适用场景
1.1 传统DEA模型的两个明显短板
数据包络分析(DEA)做的是“相对效率评价”:不需要预设生产函数,只靠投入产出数据,就能判断每个决策单元(DMU)在样本集合内是否效率最优。传统CCR和BCC模型应用最广,但我实际用下来发现两个问题让人头疼。
第一个问题是径向假设。CCR/BCC计算效率时,要求所有投入(或所有产出)等比压缩或等比扩张,也就是“径向”调整。现实里一个企业资本冗余20%的同时,劳动力可能冗余35%,不同投入的冗余程度往往不一致。径向模型强迫它们按同一比例调整,就会高估效率值。
第二个问题是有效单元无法排序。只要效率值算出来等于1,所有有效单元在传统模型里地位完全相同。可实际业务中需要从多个有效单元里再分个高下,这种情况传统模型就无能为力了。
1.2 SBM的核心改进:把松弛变量写进目标函数
SBM(Slacks-Based Measure)模型是Tone在2001年前后提出的,核心思路非常直观:不再强行要求投入产出等比调整,而是把每一项投入的松弛、每一项产出的松弛都放进目标函数里,直接衡量“平均冗余程度”和“平均不足程度”。
非导向SBM的目标函数大概是这样的形式:
ρ = (1 - (1/m)Σ(s_i⁻/x_i0)) / (1 + (1/s)Σ(s_r⁺/y_r0))
分子衡量投入端的平均可压缩比例,分母衡量产出端的平均可扩张比例。如果一个单元没有任何投入冗余、也没有产出不足,ρ就等于1,有效;只要存在松弛,ρ就小于1,效率越低越接近0。
这个设计的好处是不用预先指定投入导向还是产出导向,投入压缩和产出扩张同时考虑,对数据形态更包容,测出来的效率也更能反映真实短板。
1.3 非期望产出如何放进模型
很多效率评价场景里,除了要“多产出”,还希望“少污染”。这类产出不属于传统意义上的好产出,比如二氧化碳、废水、不良品,统称非期望产出。
SBM处理非期望产出有成熟的处理方式:期望产出照常放进分母项,作为“扩大越多越好”的产出;非期望产出则作为“压缩越多越好”的项,和投入的处理方向类似。目标函数扩展成:
ρ = (1 - (1/m)Σ(s_i⁻/x_i0)) / (1 + (1/(s1+s2))(Σ(s_r^g/y_r0^g) + Σ(s_q^b/y_q0^b)))
其中s₁是期望产出数量,s₂是非期望产出数量。注意非期望产出本身的数值越低越好,所以它的松弛含义是“当前非期望产出相对参考前沿还能减少多少”。
1.4 非超效率和超效率的本质区别
非超效率SBM的输出范围是0到1,效率值为1就说明该单元已经落在生产前沿上。但它和传统DEA一样,无法区分不同有效单元之间的强弱。
超效率SBM的处理方法简单粗暴:计算某个有效单元的效率时,把这个单元自己从参考集中排除,让它无法“自己参照自己”,只能和其他单元的组合去比较。这时候有效单元的效率值可以大于1,数值越大代表它在前沿上的位置越“极端”、越难被其他单元模拟。无效单元不必算超效率,因为它本来就不在前沿上,普通SBM值已经能说明问题。
所以,完整方案应该是“先非超效率、后超效率”两阶段:先用非超效率SBM筛出ρ=1的有效单元,再对有效单元计算超效率值完成排序。这个逻辑也是本篇后续MATLAB代码的核心骨架。
2. 环境准备:MATLAB版本、工具箱安装与数据格式
2.1 确定MATLAB和优化工具箱可用
SBM模型最终要转化为线性规划求解,MATLAB里最方便的工具是linprog函数,这个函数属于Optimization Toolbox(优化工具箱)。如果连工具箱都没装,后续代码跑不起来,所以第一步是检查环境。
打开MATLAB命令行窗口,直接执行:
ver('optim')如果返回了Optimization Toolbox字样和版本号,说明工具箱已就绪。再看许可证状态:
license('test', 'Optimization_Toolbox')返回1表示有授权。这两条命令是我在排查环境问题时最常用的第一招。
如果提示找不到工具箱,就得确认安装版本。建议使用R2020a及以上的MATLAB版本,新旧版本的linprog接口有差异,但主流写法我后面统一按新版接口来写。
2.2 安装或修复优化工具箱的两种路径
第一种路径是安装MATLAB时手动勾选。安装界面里选择“优化工具箱”即可。不过很多人装完才发现当时没勾,这时候可以重新运行MATLAB安装程序,选择“修改”,把Optimization Toolbox勾上,后续自动补装。
第二种路径是在已经装好的MATLAB里补装。在“主页”选项卡右侧找到“附加功能”,点击“获取附加功能”,在搜索框输入Optimization Toolbox,登录账号后选择安装。装完建议重启MATLAB,再用ver('optim')确认。
还有一个容易被忽略的问题:即使工具箱存在,如果路径被误删,函数也找不到。可以在命令行执行pathtool,打开路径设置界面,确认工具箱目录在搜索路径列表中。这种情况多见于换电脑、重装系统或者复制了整个MATLAB文件夹后路径失效的场景。
2.3 数据结构设计:投入、期望产出、非期望产出三矩阵
我习惯把数据整理成三个矩阵:
- X矩阵:大小为m×n,m行投入指标,n列决策单元
- Yg矩阵:大小为s1×n,s1行期望产出指标
- Yb矩阵:大小为s2×n,s2行非期望产出指标
以常见的碳排放效率测算为例,可以选资本存量、劳动力、能源消费作为投入,GDP作为期望产出,CO2排放作为非期望产出。决策单元可以是不同地区、不同行业或不同年份的企业。
所有指标的方向必须符合等张性:投入增加不应导致期望产出减少,不应导致非期望产出减少。如果数据中出现反直觉的负相关,要重新审视指标选择。
关于样本量的经验法则,我一般要求决策单元数量不少于投入产出指标总数的3倍。比如指标总数是6,最好有18个以上决策单元;少于这个规模,DEA区分度会严重下降,大量DMU会同时落在前沿上。
2.4 从Excel导入数据的标准操作
实际项目里数据多是Excel表格。我习惯把Excel表做成下面这种格式:前几行是投入指标,接着是期望产出指标,最后是非期望产出指标,每一列是一个决策单元。
读取代码可以这样写:
data = readmatrix('效率分析数据.xlsx');如果Excel文件不在当前工作目录,需要写完整路径。如果第一行是指标名称,可以用:
data = readmatrix('效率分析数据.xlsx'); % 如果表头是文字,readmatrix默认忽略非数值行数据读进来后,再按行拆成X、Yg、Yb三个矩阵。我一般不直接写死矩阵大小,而是先从size函数获取维度信息,保证代码在不同数据规模下都能跑。
拆分的示范代码:
m = 3; % 投入指标数量 s1 = 1; % 期望产出指标数量 s2 = 1; % 非期望产出指标数量 X = data(1:m, :); Yg = data(m+1:m+s1, :); Yb = data(m+s1+1:m+s1+s2, :);这里的行数顺序必须和Excel里指标排列顺序一致。我之前因为Excel里把产出放前面、投入放后面,拆分代码没改,结果算出来的效率值全部异常,排查了半天才发现是矩阵拆串了。
3. 非超效率SBM的MATLAB实现:从分式规划到线性规划
3.1 为什么不能直接求解SBM分式规划
SBM目标函数是典型的非线性分式形式,包含松弛变量除以原始投入产出的比值求和。MATLAB里的遗传算法、fmincon都能尝试求解非线性问题,但有两点风险:一是容易陷入局部最优,二是求解效率低。DEA这种一次要跑几十上百个决策单元的非线性规划,慢得让人失去耐心。
解决办法是变量代换,把分式规划转成线性规划。思路来自Charnes-Cooper变换:先让分母等于一个名义变量t,再对松弛变量做相应缩放。转换后,目标函数和所有约束都变成线性的,可以用linprog快速精确求解。
3.2 变量代换的关键步骤
以非期望产出SBM为例,令:
t = 1 / (1 + (1/(s1+s2))Σ(s_r^g/y_r0^g + s_q^b/y_q0^b))
也就是目标函数分母的倒数。再定义:
Λ = t·λ S⁻ = t·s⁻ S^g = t·s^g S^b = t·s^b
经过整理,原分式目标函数变成一组线性等式等式约束下的线性目标,可以直接套用linprog。
整个转化过程看起来有点绕,但只要理解了“用t把分母归一化”这个核心思想,剩下的就是机械的约束改写。我当年第一次照着文献推导时绕了快一天,后来发现只要记住“把所有变量都乘上t,再把分母约束写成等式”就行了。
3.3 非超效率SBM完整求解代码
下面这段代码是我在MATLAB里实测可用的非超效率SBM求解函数。它会返回效率值、各决策单元参考权重、松弛变量和投影值。
function [rho, lambda, Sm, Sg, Sb, projection] = sbm_non_super(X, Yg, Yb, k, model) % 非超效率SBM求解 % 输入: % X : m×n 投入矩阵 % Yg : s1×n 期望产出矩阵 % Yb : s2×n 非期望产出矩阵 % k : 被评价决策单元编号 % model : 'CRS' 或 'VRS' % 输出: % rho : 效率值 % lambda : 各决策单元参考权重 % Sm, Sg, Sb : 投入、期望产出、非期望产出的松弛 % projection : 投影目标值 [m, n] = size(X); s1 = size(Yg, 1); s2 = size(Yb, 1); xk = X(:, k); yg_k = Yg(:, k); yb_k = Yb(:, k); % 决策变量顺序: % 1:n lambda % n+1:n+m S- % n+m+1:n+m+s1 Sg % n+m+s1+1:n+m+s1+s2 Sb % 最后1个 t numVar = n + m + s1 + s2 + 1; % 目标函数:min t - sum(S- / (m*xk)) f = zeros(numVar, 1); f(end) = 1; f(n+1:n+m) = -1 ./ (m * xk); % 等式约束矩阵 Aeq = []; beq = []; % 投入约束:X*lambda + S- - xk*t = 0 Aeq = [Aeq; X, eye(m), zeros(m, s1+s2), -xk]; % 期望产出约束:Yg*lambda - Sg - yg_k*t = 0 for r = 1:s1 row_temp = zeros(1, numVar); row_temp(1:n) = Yg(r, :); row_temp(n+m+r) = -1; row_temp(end) = -yg_k(r); Aeq = [Aeq; row_temp]; beq = [beq; 0]; end % 非期望产出约束:Yb*lambda + Sb - yb_k*t = 0 for q = 1:s2 row_temp = zeros(1, numVar); row_temp(1:n) = Yb(q, :); row_temp(n+m+s1+q) = 1; row_temp(end) = -yb_k(q); Aeq = [Aeq; row_temp]; beq = [beq; 0]; end % 标准化约束:t + sum(Sg/((s1+s2)*yg_k)) + sum(Sb/((s1+s2)*yb_k)) = 1 std_row = zeros(1, numVar); std_row(end) = 1; for r = 1:s1 std_row(n+m+r) = 1 / ((s1+s2) * yg_k(r)); end for q = 1:s2 std_row(n+m+s1+q) = 1 / ((s1+s2) * yb_k(q)); end Aeq = [Aeq; std_row]; beq = [beq; 1]; % 规模报酬约束:VRS 添加 sum(lambda) = t if strcmp(model, 'VRS') vr_row = zeros(1, numVar); vr_row(1:n) = 1; vr_row(end) = -1; Aeq = [Aeq; vr_row]; beq = [beq; 0]; end lb = zeros(numVar, 1); options = optimoptions('linprog', 'Display', 'off', 'Algorithm', 'dual-simplex'); [z, rho] = linprog(f, [], [], Aeq, beq, lb, [], options); lambda = z(1:n); Sm = z(n+1:n+m); Sg = z(n+m+1:n+m+s1); Sb = z(n+m+s1+1:end-1); t = z(end); % 投影值还原 projection.X = xk - Sm / t; projection.Yg = yg_k + Sg / t; projection.Yb = yb_k - Sb / t; end上面代码里我特意保持了矩阵拼装的原始性,方便读者看清约束结构。效率值rho已经是线性规划的目标值,SBM的ρ就等同于这个值,不需要再乘t还原。
3.4 结果字段说明与投影含义
效率值rho的判断规则很简单:等于1说明决策单元有效;小于1则无效,距离1的差距就是效率损失。
投影值才是实际管理上有用的信息。它表示如果无效单元要达到前沿水平,各指标应该调整到多少。比如某个企业的能源投入原始值是200万吨标准煤,投影值是175万吨,说明理论上可以减少25万吨而不影响产出。这个结果比单纯一个效率值实用得多。
我之前遇到过一种情况:效率值很低,但某个松弛变量是0,说明该项投入并不冗余,短板在别的指标上。所以分析时不要只盯效率值,要多看松弛变量分布,找到具体短板是在投入端、期望产出端还是非期望产出端。
4. 超效率SBM的实现:有效单元之间如何排序
4.1 超效率的核心思想:把自己从参考集中剔除
超效率SBM和前文的非超效率模型最大的区别,在于构建参考集时排除被评价单元本身。想象一下:全班同学互相评分,要评价某个成绩特别好的学生时,要求他不能给自己打分,只能由其他同学组合出来的虚拟成绩去对比。如果怎么组合都达不到他的水平,说明他确实优秀,而且其他同学越难接近他,他的“超效率值”就越高。
这个逻辑放到DEA里,有效单元的效率值可以突破1,排序就有了依据;无效单元通常算不出大于1的值,所以实践上只对有效单元计算超效率。
4.2 超效率SBM的线性化要点
超效率SBM的目标函数形式和非超效率版本类似,但变量含义不同。它不再直接考察松弛量,而是考察“为了到达自身产出水平,需要多大比例的投入重置”,因此要引入一组新的重置变量x̄和ȳ,表示相对原始投入产出的调整倍数。
线性化仍然用变量代换的思路:设置t为分母倒数,将x̄、ȳ、λ全部乘t,转成线性约束。参考集里排除第k个决策单元这一点,要在矩阵构建时用setdiff把第k列剔除。
这部分代码比非超效率版本稍微复杂一点,核心原因在于原始模型本身就多了“被评价单元不在参考集内”这一约束。但把握好“变量代换之后所有约束仍为线性”这一点,就能在MATLAB里实现。
4.3 超效率SBM核心代码
function [delta, lambda, u, Vg, Vb, t] = sbm_super(X, Yg, Yb, k, model) % 超效率SBM求解 % 输入输出类似sbm_non_super,效率值delta可以大于1 [m, n] = size(X); s1 = size(Yg, 1); s2 = size(Yb, 1); idx = setdiff(1:n, k); Xr = X(:, idx); Ygr = Yg(:, idx); Ybr = Yb(:, idx); xk = X(:, k); yg_k = Yg(:, k); yb_k = Yb(:, k); numVar = (n-1) + m + s1 + s2 + 1; % 变量顺序:Lambda'(n-1), u(m), Vg(s1), Vb(s2), t(1) % 目标函数:min sum(u_i / (m * xk_i)) f = zeros(numVar, 1); f(n:n+m-1) = 1 ./ (m * xk); Aineq = []; bineq = []; % 投入约束:Xr*Lambda' - u <= 0 Aineq = [Aineq; Xr, -eye(m), zeros(m, s1+s2+1)]; % 期望产出约束:Ygr*Lambda' - Vg >= 0 等价于 -Ygr*Lambda' + Vg <= 0 for r = 1:s1 row_temp = zeros(1, numVar); row_temp(1:n-1) = -Ygr(r, :); row_temp(n+m+r) = 1; Aineq = [Aineq; row_temp]; end % 非期望产出约束:Ybr*Lambda' - Vb <= 0 for q = 1:s2 row_temp = zeros(1, numVar); row_temp(1:n-1) = Ybr(q, :); row_temp(n+m+s1+q) = -1; Aineq = [Aineq; row_temp]; end % u >= xk*t 转为 -u + xk*t <= 0 for i = 1:m row_temp = zeros(1, numVar); row_temp(n+i) = -1; row_temp(end) = xk(i); Aineq = [Aineq; row_temp]; end % Vg <= yg_k*t for r = 1:s1 row_temp = zeros(1, numVar); row_temp(n+m+r) = 1; row_temp(end) = -yg_k(r); Aineq = [Aineq; row_temp]; end % Vb >= yb_k*t 转为 -Vb + yb_k*t <= 0 for q = 1:s2 row_temp = zeros(1, numVar); row_temp(n+m+s1+q) = -1; row_temp(end) = yb_k(q); Aineq = [Aineq; row_temp]; end bineq = zeros(size(Aineq, 1), 1); % 标准化约束:t + sum(Vg/((s1+s2)*yg_k)) + sum(Vb/((s1+s2)*yb_k)) = 1 Aeq = zeros(1, numVar); Aeq(end) = 1; for r = 1:s1 Aeq(n+m+r) = 1 / ((s1+s2) * yg_k(r)); end for q = 1:s2 Aeq(n+m+s1+q) = 1 / ((s1+s2) * yb_k(q)); end beq = 1; % VRS约束:sum(Lambda') = t if strcmp(model, 'VRS') vr_row = zeros(1, numVar); vr_row(1:n-1) = 1; vr_row(end) = -1; Aeq = [Aeq; vr_row]; beq = [beq; 0]; end lb = zeros(numVar, 1); options = optimoptions('linprog', 'Display', 'off', 'Algorithm', 'dual-simplex'); [z, delta] = linprog(f, Aineq, bineq, Aeq, beq, lb, [], options); lambda = zeros(1, n); lambda(idx) = z(1:n-1); u = z(n:n+m-1); Vg = z(n+m:n+m+s1-1); Vb = z(n+m+s1:end-1); t = z(end); end使用超效率函数时要注意一点:先对全部决策单元跑非超效率SBM,把rho等于1的单元筛选出来,再对这些单元跑超效率函数。如果对无效单元强行计算,可能遇到无可行解,这不是代码问题,而是模型定义本身决定的。
4.4 完整调用组合:两阶段评价流程
实际项目里我通常把两块功能包进主脚本,流程是这样的:
- 读取并拆分数据,得到X、Yg、Yb;
- 循环每个决策单元,调用非超效率SBM函数,记录rho;
- 输出第一轮效率表,标出有效单元(rho接近1);
- 对有效单元循环调用超效率SBM函数,记录delta;
- 最终效率值统一用规则显示:无效单元显示rho,有效单元显示delta。
这个组合非常实用:无效单元的排序用普通效率值,有效单元的排序用超效率值,一张表就能看完整个样本的优劣顺序。
5. 完整实操演示:从模拟数据到结果解读
5.1 快速构造一组演示数据
为了展示完整流程,我在脚本里用rng固定随机种子,生成一组12个决策单元的数据:3个投入指标、2个期望产出指标、1个非期望产出指标。你可以直接复制下面的代码生成演示数据,然后套用前文的两个函数跑完整流程。
rng(2024); n = 12; m = 3; s1 = 2; s2 = 1; X0 = 20 + rand(m, n) * 80; % 投入,范围20~100 Yg0 = 50 + rand(s1, n) * 60; % 期望产出,范围50~110 Yb0 = 5 + rand(s2, n) * 25; % 非期望产出,范围5~30同时也生成一份Excel样例数据,写入当前目录:
data_demo = [X0; Yg0; Yb0]; writematrix(data_demo, '演示数据.xlsx');如果你有自己的Excel数据,只需修改文件读取的路径和行列拆分参数即可。
5.2 主脚本的编写顺序
我会把主脚本拆成三个段落:数据读取、循环求解、结果整理。
数据读取段落无非是readmatrix加拆分。循环求解这段要重点注意:每算一个DMU都要清空上一次的约束矩阵吗?不用,因为约束矩阵在函数内部重新构建,外部循环不会累积残留变量。
data = readmatrix('演示数据.xlsx'); X = data(1:m, :); Yg = data(m+1:m+s1, :); Yb = data(m+s1+1:m+s1+s2, :); model = 'VRS'; rho_list = zeros(1, n); for k = 1:n [rho, ~] = sbm_non_super(X, Yg, Yb, k, model); rho_list(k) = rho; end effective_idx = find(rho_list >= 1 - 1e-6); delta_list = zeros(1, n); for k = effective_idx [delta, ~] = sbm_super(X, Yg, Yb, k, model); delta_list(k) = delta; end final_score = rho_list; final_score(effective_idx) = delta_list(effective_idx);处理有效单元的判断阈值,我习惯用1e-6而不是直接判断等于1,因为linprog求解结果会有浮点误差,rho可能是0.9999999或1.0000001。
5.3 输出结果表
结果表建议整理成四列:决策单元编号、非超效率值、是否有效、最终排序值。我用表格函数输出到文件,方便再导入Excel做后续排版:
T = table((1:n)', rho_list', final_score', ... 'VariableNames', {'DMU', 'SBM效率值', '最终得分'}); disp(T); writetable(T, '效率结果.csv');此时你会看到SBM效率值一列中,部分单元接近1,这些单元的最终得分列会大于1,这个大于1的数值就来自超效率计算。最终得分越高,说明在剔除自身后越难被其他单元超越。
5.4 怎么解读结果才是对业务有用的
拿到结果表,我一般按三步走。
第一步看整体分布:最终得分的中位数、最大值、最小值,判断样本整体效率水平是否偏低。如果大部分单元低于0.6,说明样本整体改进空间大,也说明指标选取可能偏严格。
第二步看有效单元名单:这些是标杆,后续经验和管理模式可以优先从中提取。第三步看无效单元的松弛分布:回到函数返回的Sm、Sg、Sb,找出主要短板。
我强调一遍,只看效率值的分析报告价值很有限。把投影值和原始值之差做成改进建议表,才是真正能交到业务方手上的内容。例如某个DMU的资本松弛较高,说明资本利用率低,可以建议调整投资结构;如果非期望产出松弛较高,说明减排空间大,可以建议优化工艺。
6. 常见问题与避坑指南
6.1 报错场景速查表
下面这些是我在实际运行和教学中最常遇到的几类问题。
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 提示Undefined function 'linprog' | 优化工具箱未安装或路径缺失 | 检查ver('optim'),用附加功能补装工具箱 |
| 计算结果出现NaN | 数据包含NaN或Inf | 用rmmissing或手动填充缺失值 |
| 所有DMU的效率值都是1 | 指标数过多或样本量过小 | 考虑减少指标,或增加决策单元数量 |
| VRS模型下超效率计算无可行解 | 对无效DMU强行计算超效率 | 仅对非超效率值等于1的单元计算超效率 |
| Excel数据拆错矩阵 | 指标行顺序和代码不一致 | 统一按投入、期望产出、非期望产出排列,并复核维度 |
| 结果和商业软件不一致 | 求解器容差或VRS/CRS设置差异 | 确认模型设定完全一致,检查归一化约束是否写全 |
6.2 模型选择上的三条实战经验
第一条,指标数量宁少勿多。DEA对指标数量很敏感,指标越多,有效单元越多,区分度越差。我一般控制在总指标5到7个、决策单元20个以上的样本结构。指标太多但样本不足时,很多部门都会变成效率1,结果没有管理含义。
第二条,CRS和VRS不能随手选。如果决策单元规模差异很大,比如大企业和小作坊放一起比,尽量选VRS,剔除规模因素对纯技术效率的影响。如果所有单元都在相近规模下运行,CRS更合适。这个选择对效率值和排序会产生实质性影响,一定要有经济理由,不要因为哪个结果好看就选哪个。
第三条,非期望产出不要简单当成投入处理。有些初学者把CO2排放当成投入放进X矩阵,模型也能跑,但业务含义完全变质:投入增加在DEA里被默认为“越多越好”,可CO2越多越好显然是反事实的。所以正确的做法是单独放在非期望产出矩阵里,约束方向才能反映“越少越好”的真实逻辑。
6.3 提高结果可靠性的几个小技巧
数据预处理阶段,最好先做指标的无量纲化检查。SBM模型本身不受量纲影响,因为松弛变量除以原始值得到相对比例,所以资本用亿元、劳动力用万人、能源用万吨标准煤完全可以直接混合使用。这一点和传统径向DEA一致,不需要特意归一化。
如果面板数据跨多年,我建议逐年单独跑或使用窗口DEA思路。把所有年份揉在一起跑会破坏生产前沿的时序可比性,导致某一年份的项目系统性偏高或偏低。
最后一个小细节:linprog默认算法是dual-simplex,对线性规划问题很稳。如果数据规模特别大,可以考虑用'interior-point'算法,速度更快。我实测下来,几百个决策单元的规模,dual-simplex完全够用。
我在实际操作中的体会是,SBM-DEA这套模型的难点并不在代码本身,而在于把业务问题翻译成模型结构。投入选什么、期望产出和非期望产出怎么界定、用CRS还是VRS、超效率用到什么程度,这些决策对结果的影响远大于模型求解细节。后面对这类效率评价项目,我会习惯先把指标体系和模型设定写成一段文字说明,再动手写MATLAB代码,避免跑完了才发现模型结构和业务目标对不上。如果看完这篇你还是觉得某些环节不顺手,最稳妥的办法是用真实数据小规模试跑一遍,把每个决策单元的松弛量逐一检查一遍,很快就能发现问题和改进方向。