
简介这是一份基于MATLAB实现的数据包络分析DEA资源包内含DEA-Solver工具箱及配套示例面向经济管理、工程评估等方向的师生和企业分析人员适用于企业、医院、学校等组织的相对效率评价也可作为运筹学相关课程的辅助教学材料。压缩包共21个文件体积仅2.54MB以xls示例/结果数据表为主并包含PDF方法文献、M脚本、MAT数据文件、使用说明txt及doc文档等既有可直接运行的模型代码也有理论参考资料。目前已有442人学习。资源覆盖DEA建模全流程从CCR与BCC模型定义、输入输出变量选择到数据预处理、线性规划求解、效率排序及结果输出同时附有区域创新政策排名、地方政府效率内在决定因素等应用案例文献便于读者理解模型的实际使用方式。借助DEA-Solver的主函数库、示例数据和说明文档使用者既可系统掌握DEA原理也可以替换数据完成自定义的效率评价还可用于教学演示与课题验证。 做项目绩效评价和效率分析时数据包络分析DEA是我几乎绕不开的工具。前阵子有个课题需要评估一组同类型机构的运营效率指标多、样本量不算大、又不想强行假设生产函数形式我第一反应就是拿MATLAB写一个DEA求解程序顺带把手头的DEA Solver流程也统一跑了一遍。这篇就基于这个项目完整拆一下DEA的MATLAB实现思路、核心代码、常见坑位以及怎么用solver配套交叉验证给准备做效率评价的朋友一份能直接参考的实操稿。1. DEA要解决什么问题为什么用MATLAB1.1 一个场景先立起来假设你有20家医院每家都有几个投入指标床位数、医生数、年度运营成本和几个产出指标门诊量、出院人数、满意度评分。现在要判断哪几家医院“更有效率”哪几家还有改进空间。这个问题难就难在多个投入多个产出量纲不同无法用单指标直接算综合效率。DEA的做法很聪明它不预设任何函数关系而是把所有被评价对象叫决策单元DMU放在一起用“数据包络”的方式勾勒出一条最优前沿面。落在前沿面上的DMU效率为1没落上去的根据它与前沿面的距离得到一个0到1之间的效率值。这本质上就是一个线性规划问题而MATLAB的linprog就是干这个的。1.2 为什么选MATLAB而不是其他工具如果你只是做一次简单的两投入两产出分析用Excel插件也没问题。但项目但凡有一点扩展需求——比如要批量跑数百个DMU、要做Malmquist指数、要嵌入到自己的算法循环里做灵敏度分析——Excel就非常吃力了。MATLAB的优势在于线性规划求解器成熟linprog支持多种算法处理小规模DEA绰绰有余数据预处理、结果统计、可视化在一个环境里完成可以封装成函数批量调用复用到不同数据集上我在这套程序里也内置了DEA Solver的验证逻辑说白了就是用两个不同实现互相核对结果防止代码写错导致整个分析白做。2. DEA模型怎么选CCR、BCC和导向问题2.1 CCR模型规模报酬不变下的效率DEA最早、最经典的模型是CCRCharnes-Cooper-Rhodes。它假设被评价对象处于规模报酬不变的状态也就是投入翻倍、产出也应该翻倍。对于制造业生产线这类场景这个假设还算合理但放到医院、高校、银行网点规模效应往往是递减或递增的这时候继续用CCR就会把规模效率也混进纯技术效率里得到的结果会产生误导。CCR投入导向模型的线性规划形式数学上可以写成这样min θs.t. Σⱼ xᵢⱼ λⱼ ≤ θ xᵢ₀i 1,…,mΣⱼ yᵣⱼ λⱼ ≥ yᵣ₀r 1,…,sλⱼ ≥ 0其中θ就是要算的效率值xᵢ₀和yᵣ₀是被评价DMU的投入产出λ为权重变量。2.2 BCC模型规模报酬可变实际项目里我用得更多的是BCCBanker-Charnes-Cooper。它只比CCR多了一个约束Σλⱼ 1相当于要求被评价DMU只和规模相近的DMU比较。这样算出来的效率值剔除了规模因素专业叫法叫“纯技术效率”。当我对同一组数据同时跑CCR和BCC时两者相减还能算出规模效率。具体判断标准是若CCR效率 BCC效率说明DMU处于最优规模状态若两者不等再看Σλ的取值趋势可以判断是规模报酬递增还是递减这个信息对管理决策极其有用因为规模报酬递增的DMU应适当扩大规模递减的则应控制扩张。2.3 投入导向还是产出导向这个选择并不复杂如果经营管理者手上主要能控制投入降本、优化资源选投入导向如果投入相对固定、要想办法提升产出比如医院床位已经满负荷该想的是提高周转率选产出导向。两种导向求解出来的效率值略有差异严格说只有规模报酬不变时才等同。我在代码里默认做了投入导向同时在函数里预留了导向切换的参数避免后期返工。3. MATLAB代码实现从零写一个DEA求解函数3.1 核心函数代码我实现的是基于linprog的对偶模型变量顺序为θ、λ向量、投入松弛变量、产出松弛变量。由于linprog默认求解min fx所以目标函数里只有θ的系数为1其余全是0。function [theta, lambda, slack_minus, slack_plus] dea_ccr_io(X, Y, j0) % dea_ccr_io CCR投入导向DEA求解 % X: n×m 矩阵每行为一个DMU的m个投入指标 % Y: n×s 矩阵每行为一个DMU的s个产出指标 % j0: 被评价DMU的行号 % theta: 效率值 % lambda: 参照权重 % slack_minus: 投入松弛变量 % slack_plus: 产出松弛变量 n size(X, 1); m size(X, 2); s size(Y, 2); x0 X(j0, :); y0 Y(j0, :); % 变量顺序: theta, lambda(1:n), s_minus(1:m), s_plus(1:s) numVar 1 n m s; f [1; zeros(numVar - 1, 1)]; Aeq zeros(m s, numVar); beq zeros(m s, 1); % 投入约束: sum_j X(i,j)*lambda_j - theta*x0(i) s_minus(i) 0 for i 1:m Aeq(i, 1) -x0(i); Aeq(i, 2:n1) X(:, i); Aeq(i, n1i) 1; end % 产出约束: sum_j Y(r,j)*lambda_j - s_plus(r) y0(r) for r 1:s Aeq(mr, 2:n1) Y(:, r); Aeq(mr, n1mr) -1; beq(mr) y0(r); end lb [0; zeros(n m s, 1)]; ub inf(numVar, 1); options optimoptions(linprog, Display, off, Algorithm, dual-simplex); [x, fval, exitflag] linprog(f, [], [], Aeq, beq, lb, ub, options); if exitflag 0 theta NaN; lambda []; slack_minus []; slack_plus []; warning(DMU %d 求解失败, j0); return; end theta fval; lambda x(2:n1); slack_minus x(n2:nm1); slack_plus x(nm2:end); end这里有个比较关键的细节把θ放在变量向量首位投入约束里θ的系数就是-x0。一开始我写的时候把符号搞反了算出来的效率值全都大于1折腾了半天才发现是约束写成了等式右边的常量没把θ移到左侧。3.2 批量求解全部DMU有了单个函数批量求解就很简单了n size(X, 1); theta_all zeros(n, 1); for k 1:n [theta_all(k), ~, ~, ~] dea_ccr_io(X, Y, k); end需要注意DEA的效率值是按DMU逐个求的每个DMU本质上是一个独立的线性规划问题求解顺序互不影响。如果数据集比较大可以先用parfor并行但要注意每个工作进程都要能访问dea_ccr_io函数。3.3 BCC模型的扩展把CCR改成BCC只需要多加一行约束。决策变量尾部加一个变量专门用来做Σλ1的等式约束% 在Aeq和beq末尾追加一行 Aeq(end1, 2:n1) 1; beq(end1) 1;变量数量不用变因为Σλ1不需要新的变量。但要把ub里λ部分的上限设为1不需要λ可以大于1规模报酬可变的含义是允许权重和等于1而不是λ本身受限。4. 用DEA Solver交叉验证4.1 DEA Solver是什么DEA Solver是一套专门做DEA分析的工具很多版本以Excel加载项的形式存在也支持常见的CCR、BCC、超效率、SBM模型。项目里我把它作为MATLAB程序的交叉验证工具先让MATLAB跑一遍再用DEA Solver对同一份数据跑一遍两者差距在1e-6以内才算代码可靠。DEA-Solver官方渠道有多个版本Learning版面向教学功能相对基础Pro版覆盖模型比较全支持中文界面商业项目用得比较多。网上能找到免费的试用版和学习版追求完整模型的话建议支持正版授权。4.2 交叉验证的流程第一步MATLAB程序导出效率值保存为CSV第二步DEA Solver读取同一份X和Y数据第三步对比每个DMU的效率和松弛变量如果出现个别DMU结果不一致先检查数据读取是否对齐。实际项目中常见的原因是Excel里数据列顺序调换了或者某个DMU的投入产出数据为0导致求解器路径不同。只要代码逻辑正确两个工具的解应该高度一致。4.3 为什么还要信任手写代码有现成工具为什么还自己写MATLAB因为DEA Solver这类工具适合单次分析但项目做到后面通常要反复调参比如换指标组合、做窗口分析、算Malmquist指数。写成函数后这些操作就是几行循环的事。而且DEA Solver输出的是静态报告想画效率分布的直方图、做效率值和环境变量的回归分析还是得回到MATLAB或Python环境。手写代码的意义不在于“不用工具”而在于把分析流程工程化。5. 实际案例医院运营效率评估5.1 数据准备与指标选取拿一个简化的例子来演示。假设要评估10家医院的效率选了两个投入指标和两个产出指标医院床位数医生数门诊量千人次出院人数百人A42018085.232.1B35015278.430.5C51021092.635.2D2809555.722.3E46018888.931.8F39017082.529.6G53022595.438.7H30011062.324.5I44017579.830.2J37014374.627.8指标选取上有一个经验法则DMU数量要大于投入产出指标数量之和的两倍最好在3倍以上否则区分度会很差大量DMU效率都等于1。我这个例子样本量偏小仅作演示正式研究里10个DMU配4个指标是偏紧的至少要扩展到30个以上。5.2 运行结果用上面代码批量跑一遍数据大致长这样X [420 180; 350 152; 510 210; 280 95; 460 188; 390 170; 530 225; 300 110; 440 175; 370 143]; Y [85.2 32.1; 78.4 30.5; 92.6 35.2; 55.7 22.3; 88.9 31.8; 82.5 29.6; 95.4 38.7; 62.3 24.5; 79.8 30.2; 74.6 27.8]; theta_all zeros(size(X, 1), 1); for k 1:size(X, 1) [theta_all(k), ~, ~, ~] dea_ccr_io(X, Y, k); end bar(theta_all);结果中一部分医院比如G、D这类投入产出结构特殊的效率值会靠近1其他医院的效率值在0.85到0.99之间。这里有个分析小技巧不要只看效率排名一定要结合λ权重看它的“参照集”。比如医院F的效率是0.91那就看它λ中权重最大的几个DMU是谁这些DMU就是它的标杆。管理上可以直接让F院对标G院的资源配置结构。5.3 松弛变量怎么用效率值小于1只说明“缩水的空间有多大”具体哪些指标要改进、改进多少要看松弛变量。在CCR投入导向下投入松弛量除以当前投入量就是该指标的冗余比例。比如某医院医生数的松弛量是15人那就意味着在不减少产出的前提下理论上可以精简15名医生。产出松弛也类似。需要注意一点效率等于1的DMU也可能有松弛这种情况被称为“弱有效”。判断是否强有效要同时看θ是否等于1以及所有松弛是否为0。我在程序里特意把松弛变量也返回出来就是为了避免只看效率值导致误判。6. 常见问题与排查技巧6.1 为什么算出来的效率全是1出现这个情况九成原因是指标太多、DMU太少DEA的数据包络太松每个DMU都能找到自己的一套权重把自己包进去。解决方法增加DMU数量精简投入产出指标优先选相关性低的指标用主成分分析先降维6.2 求解失败或无可行解最常发生在新手刚接触时把投入产出方向搞反了。linprog返回exitflag小于等于0时不要硬读theta。另外注意linprog在旧版MATLAB2020a之前默认算法可能对这类带等式约束的小规模问题不友好建议指定algorithm为dual-simplex。我在项目里就遇到过一次同样的代码在两个版本结果不一样的情况最后统一锁定了算法选项才对齐。6.3 数据和DEA Solver对不上很多情况下不是程序问题而是Excel数据里有隐藏行、空值或者文本型数字。建议在MATLAB里用isnan和isinf先做一次检查也把数据round到统一精度再导出。DEA对小数位数并不敏感但完全相同的输入才能保证完全一致的输出。6.4 零值和负值怎么处理DEA默认要求投入产出数据非负。遇到某些指标存在0有两种常见处理一是换模型比如SBMSlacks-Based Measure允许处理非期望产出和部分零值二是给零值加一个很小的正数但这会影响效率结果不推荐。产出指标里若存在负值一般要先做数据平移但平移会改变效率测量结果最好先想清楚经济含义。7. 写在最后的个人体会这套MATLAB DEA程序前前后后改过好几版从最初只用linprog裸写CCR到后来支持BCC、加入松弛变量输出、对接DEA Solver验证每次改动都踩了不少坑。现在回头看最有价值的不是代码本身而是“用什么模型、在什么假设下、怎么解读结果”这套分析思路。数据进去、效率出来只是第一步真正给管理决策提供依据的是对参照集、松弛变量和规模收益状态的深度解读。如果你也在做类似效率评价建议先把CCR和BCC的手推线性规划弄明白再动手写代码后面换任何模型都不慌。本文还有配套的精品资源点击获取