Browse Source

DEA测试demo

environment_dev
gjh 6 hours ago
parent
commit
8f7e4739ad
  1. 6
      ruoyi-modules/ruoyi-demo/pom.xml
  2. 49
      ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/test/DEAExample.java
  3. 267
      ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/test/DEAUtils.java

6
ruoyi-modules/ruoyi-demo/pom.xml

@ -22,6 +22,12 @@
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>3.4.1</version>
</dependency>
<!-- 通用工具--> <!-- 通用工具-->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>

49
ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/test/DEAExample.java

@ -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());
}
}

267
ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/test/DEAUtils.java

@ -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…
Cancel
Save