3 changed files with 322 additions and 0 deletions
@ -0,0 +1,49 @@ |
|||
package org.dromara.demo.controller.test; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* DEA模型使用示例 |
|||
*/ |
|||
public class DEAExample { |
|||
public static void main(String[] args) { |
|||
// 示例:3个DMU,2个投入指标,1个产出指标
|
|||
// 投入矩阵: 每行代表一个DMU的投入
|
|||
// 例如: 投入可以是员工数量和资金投入
|
|||
double[][] inputs = { |
|||
{2, 3}, // DMU 0的投入
|
|||
{3, 4}, // DMU 1的投入
|
|||
{1, 5}, // DMU 2的投入
|
|||
{2, 3}, // DMU 3的投入
|
|||
{3, 4}, // DMU 4的投入
|
|||
{1, 5} // DMU 5的投入
|
|||
}; |
|||
|
|||
// 产出矩阵: 每行代表一个DMU的产出
|
|||
// 例如: 产出可以是利润
|
|||
double[][] outputs = { |
|||
{5}, // DMU 0的产出
|
|||
{6}, // DMU 1的产出
|
|||
{4}, // DMU 2的产出
|
|||
{5}, // DMU 0的产出
|
|||
{6}, // DMU 1的产出
|
|||
{4} // DMU 2的产出
|
|||
|
|||
}; |
|||
|
|||
// 计算所有DMU的效率值
|
|||
List<DEAUtils.DEAResult> results = DEAUtils.calculateAllDMUs(inputs, outputs); |
|||
|
|||
// 输出结果
|
|||
for (DEAUtils.DEAResult result : results) { |
|||
System.out.println(result); |
|||
} |
|||
|
|||
// 单独计算某个DMU的效率值
|
|||
int targetDMU = 1; |
|||
DEAUtils.DEAResult specificResult = DEAUtils.calculateDEA(inputs, outputs, targetDMU); |
|||
System.out.println("\n单独评估DMU " + targetDMU + " 的详细结果:"); |
|||
System.out.println("效率值: " + specificResult.getEfficiency()); |
|||
System.out.println("是否DEA有效: " + specificResult.isEfficient()); |
|||
} |
|||
} |
@ -0,0 +1,267 @@ |
|||
package org.dromara.demo.controller.test; |
|||
|
|||
import org.apache.commons.math3.linear.Array2DRowRealMatrix; |
|||
import org.apache.commons.math3.linear.RealMatrix; |
|||
import org.apache.commons.math3.optim.*; |
|||
import org.apache.commons.math3.optim.linear.*; |
|||
import org.apache.commons.math3.optim.nonlinear.scalar.GoalType; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* DEA(数据包络分析)工具类,实现面向投入的CCR模型 |
|||
*/ |
|||
public class DEAUtils { |
|||
|
|||
/** |
|||
* 计算指定DMU的效率值 |
|||
* |
|||
* @param inputs 投入矩阵,每行代表一个DMU的所有投入,行数为DMU数量,列数为投入指标数量 |
|||
* @param outputs 产出矩阵,每行代表一个DMU的所有产出,行数为DMU数量,列数为产出指标数量 |
|||
* @param dmuIndex 要评估的DMU索引(从0开始) |
|||
* @return DEA计算结果,包含效率值和松弛变量等信息 |
|||
* @throws IllegalArgumentException 输入数据不合法时抛出 |
|||
*/ |
|||
public static DEAResult calculateDEA(double[][] inputs, double[][] outputs, int dmuIndex) { |
|||
// 验证输入数据合法性
|
|||
validateInput(inputs, outputs, dmuIndex); |
|||
|
|||
int n = inputs.length; // DMU数量
|
|||
int m = inputs[0].length; // 投入指标数量
|
|||
int s = outputs[0].length; // 产出指标数量
|
|||
|
|||
// 变量数量: n个lambda + 1个theta + m个投入松弛变量 + s个产出松弛变量
|
|||
int varCount = n + 1 + m + s; |
|||
|
|||
// 目标函数: 最小化theta(第n个变量)
|
|||
double[] objectiveCoefficients = new double[varCount]; |
|||
objectiveCoefficients[n] = 1.0; // theta的系数为1,其他变量系数为0
|
|||
|
|||
// 创建线性规划问题
|
|||
LinearObjectiveFunction objective = new LinearObjectiveFunction(objectiveCoefficients, 0); |
|||
|
|||
// 约束条件列表
|
|||
List<LinearConstraint> constraints = new ArrayList<>(); |
|||
|
|||
// 1. 投入约束: sum(lambda_j * x_ij) + s_i^- = theta * x_ik (i=1..m)
|
|||
for (int i = 0; i < m; i++) { |
|||
double[] coefficients = new double[varCount]; |
|||
// 设置lambda_j的系数
|
|||
for (int j = 0; j < n; j++) { |
|||
coefficients[j] = inputs[j][i]; |
|||
} |
|||
// 设置theta的系数
|
|||
coefficients[n] = -inputs[dmuIndex][i]; |
|||
// 设置投入松弛变量的系数
|
|||
coefficients[n + 1 + i] = 1.0; |
|||
|
|||
// sum(lambda_j * x_ij) - theta * x_ik + s_i^- = 0
|
|||
constraints.add(new LinearConstraint(coefficients, Relationship.EQ, 0.0)); |
|||
} |
|||
|
|||
// 2. 产出约束: sum(lambda_j * y_rj) - s_r^+ = y_rk (r=1..s)
|
|||
for (int r = 0; r < s; r++) { |
|||
double[] coefficients = new double[varCount]; |
|||
// 设置lambda_j的系数
|
|||
for (int j = 0; j < n; j++) { |
|||
coefficients[j] = outputs[j][r]; |
|||
} |
|||
// 设置产出松弛变量的系数
|
|||
coefficients[n + 1 + m + r] = -1.0; |
|||
|
|||
// sum(lambda_j * y_rj) - s_r^+ = y_rk
|
|||
constraints.add(new LinearConstraint(coefficients, Relationship.EQ, outputs[dmuIndex][r])); |
|||
} |
|||
|
|||
// 3. 变量非负约束
|
|||
// lambda_j >= 0 (j=1..n)
|
|||
// theta无符号限制,但在CCR模型中通常theta <= 1
|
|||
// s_i^- >= 0 (i=1..m)
|
|||
// s_r^+ >= 0 (r=1..s)
|
|||
for (int j = 0; j < n; j++) { |
|||
double[] coefficients = new double[varCount]; |
|||
coefficients[j] = 1.0; |
|||
constraints.add(new LinearConstraint(coefficients, Relationship.GEQ, 0.0)); |
|||
} |
|||
|
|||
// 投入松弛变量非负
|
|||
for (int i = 0; i < m; i++) { |
|||
double[] coefficients = new double[varCount]; |
|||
coefficients[n + 1 + i] = 1.0; |
|||
constraints.add(new LinearConstraint(coefficients, Relationship.GEQ, 0.0)); |
|||
} |
|||
|
|||
// 产出松弛变量非负
|
|||
for (int r = 0; r < s; r++) { |
|||
double[] coefficients = new double[varCount]; |
|||
coefficients[n + 1 + m + r] = 1.0; |
|||
constraints.add(new LinearConstraint(coefficients, Relationship.GEQ, 0.0)); |
|||
} |
|||
|
|||
// 4. theta <= 1约束
|
|||
double[] thetaCoeff = new double[varCount]; |
|||
thetaCoeff[n] = 1.0; |
|||
constraints.add(new LinearConstraint(thetaCoeff, Relationship.LEQ, 1.0)); |
|||
|
|||
// 求解器配置
|
|||
SimplexSolver solver = new SimplexSolver(); |
|||
LinearOptimizer optimizer = solver; |
|||
|
|||
// 求解线性规划问题
|
|||
PointValuePair solution = optimizer.optimize( |
|||
new LinearConstraintSet(constraints), |
|||
objective, |
|||
GoalType.MINIMIZE, |
|||
new NonNegativeConstraint(false), // 已单独设置非负约束
|
|||
new MaxIter(1000) |
|||
); |
|||
|
|||
// 解析结果
|
|||
double[] solutionPoint = solution.getPoint(); |
|||
double theta = solutionPoint[n]; // 效率值
|
|||
|
|||
// 投入松弛变量
|
|||
double[] inputSlacks = new double[m]; |
|||
System.arraycopy(solutionPoint, n + 1, inputSlacks, 0, m); |
|||
|
|||
// 产出松弛变量
|
|||
double[] outputSlacks = new double[s]; |
|||
System.arraycopy(solutionPoint, n + 1 + m, outputSlacks, 0, s); |
|||
|
|||
// lambda值
|
|||
double[] lambdas = new double[n]; |
|||
System.arraycopy(solutionPoint, 0, lambdas, 0, n); |
|||
|
|||
return new DEAResult(theta, inputSlacks, outputSlacks, lambdas, dmuIndex); |
|||
} |
|||
|
|||
/** |
|||
* 计算所有DMU的效率值 |
|||
* |
|||
* @param inputs 投入矩阵 |
|||
* @param outputs 产出矩阵 |
|||
* @return 所有DMU的DEA计算结果列表 |
|||
*/ |
|||
public static List<DEAResult> calculateAllDMUs(double[][] inputs, double[][] outputs) { |
|||
List<DEAResult> results = new ArrayList<>(); |
|||
for (int i = 0; i < inputs.length; i++) { |
|||
results.add(calculateDEA(inputs, outputs, i)); |
|||
} |
|||
return results; |
|||
} |
|||
|
|||
/** |
|||
* 验证输入数据的合法性 |
|||
*/ |
|||
private static void validateInput(double[][] inputs, double[][] outputs, int dmuIndex) { |
|||
if (inputs == null || outputs == null) { |
|||
throw new IllegalArgumentException("投入和产出矩阵不能为null"); |
|||
} |
|||
|
|||
if (inputs.length != outputs.length) { |
|||
throw new IllegalArgumentException("投入和产出矩阵的行数(DMU数量)必须一致"); |
|||
} |
|||
|
|||
if (inputs.length == 0) { |
|||
throw new IllegalArgumentException("至少需要一个DMU"); |
|||
} |
|||
|
|||
int m = inputs[0].length; |
|||
for (double[] input : inputs) { |
|||
if (input.length != m) { |
|||
throw new IllegalArgumentException("所有DMU的投入指标数量必须一致"); |
|||
} |
|||
} |
|||
|
|||
int s = outputs[0].length; |
|||
for (double[] output : outputs) { |
|||
if (output.length != s) { |
|||
throw new IllegalArgumentException("所有DMU的产出指标数量必须一致"); |
|||
} |
|||
} |
|||
|
|||
if (dmuIndex < 0 || dmuIndex >= inputs.length) { |
|||
throw new IllegalArgumentException("DMU索引超出范围"); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* DEA计算结果封装类 |
|||
*/ |
|||
public static class DEAResult { |
|||
private final double efficiency; // 效率值(theta)
|
|||
private final double[] inputSlacks; // 投入松弛变量
|
|||
private final double[] outputSlacks; // 产出松弛变量
|
|||
private final double[] lambdas; // 各DMU的权重
|
|||
private final int dmuIndex; // 对应的DMU索引
|
|||
|
|||
public DEAResult(double efficiency, double[] inputSlacks, double[] outputSlacks, |
|||
double[] lambdas, int dmuIndex) { |
|||
this.efficiency = efficiency; |
|||
this.inputSlacks = inputSlacks; |
|||
this.outputSlacks = outputSlacks; |
|||
this.lambdas = lambdas; |
|||
this.dmuIndex = dmuIndex; |
|||
} |
|||
|
|||
/** |
|||
* 判断该DMU是否为DEA有效 |
|||
* 当效率值=1且所有松弛变量为0时,DMU为DEA有效 |
|||
*/ |
|||
public boolean isEfficient() { |
|||
if (Math.abs(efficiency - 1.0) > 1e-9) { |
|||
return false; |
|||
} |
|||
for (double slack : inputSlacks) { |
|||
if (Math.abs(slack) > 1e-9) { |
|||
return false; |
|||
} |
|||
} |
|||
for (double slack : outputSlacks) { |
|||
if (Math.abs(slack) > 1e-9) { |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
// getter方法
|
|||
public double getEfficiency() { |
|||
return efficiency; |
|||
} |
|||
|
|||
public double[] getInputSlacks() { |
|||
return inputSlacks.clone(); |
|||
} |
|||
|
|||
public double[] getOutputSlacks() { |
|||
return outputSlacks.clone(); |
|||
} |
|||
|
|||
public double[] getLambdas() { |
|||
return lambdas.clone(); |
|||
} |
|||
|
|||
public int getDmuIndex() { |
|||
return dmuIndex; |
|||
} |
|||
|
|||
@Override |
|||
public String toString() { |
|||
StringBuilder sb = new StringBuilder(); |
|||
sb.append("DMU ").append(dmuIndex).append(" 评估结果:\n"); |
|||
sb.append(" 效率值: ").append(String.format("%.4f", efficiency)).append("\n"); |
|||
sb.append(" 是否DEA有效: ").append(isEfficient()).append("\n"); |
|||
sb.append(" 投入松弛变量: "); |
|||
for (double slack : inputSlacks) { |
|||
sb.append(String.format("%.4f ", slack)); |
|||
} |
|||
sb.append("\n 产出松弛变量: "); |
|||
for (double slack : outputSlacks) { |
|||
sb.append(String.format("%.4f ", slack)); |
|||
} |
|||
return sb.toString(); |
|||
} |
|||
} |
|||
} |
Loading…
Reference in new issue