一. AHP层次分析法介绍
层次分析法(Analytic Hierarchy Process,简称AHP)是对一些较为复杂、较为模糊的问题作出决策的简易方法,
它特别适用于那些难于完全定量分析的问题。它是美国运筹学家T. L. Saaty 教授于70年代初期提出的一种简便、
灵活而又实用的多准则决策方法。
1 层次分析法的基本原理与步骤
人们在进行社会的、经济的以及科学管理领域问题的系统分析中,面临的常常是一个由相互关联、相互制约的众多因素构成的
复杂而往往缺少定量数据的系统。层次分析法为这类问题的决策和排序提供了一种新的、简洁而实用的建模方法。
运用层次分析法建模,大体上可按下面四个步骤进行:
(i) 建立递阶层次结构模型;
(ii) 构造出各层次中的所有判断矩阵;
(iii) 层次单排序及一致性检验;
(iv) 层次总排序及一致性检验。
2 递阶层次结构的建立与特点
应用AHP分析决策问题时,首先要把问题条理化、层次化,构造出一个有层次的结构模型。
在这个模型下,复杂问题被分解为元素的组成部分。这些元素又按其属性及关系形成若干层次。
上一层次的元素作为准则对下一层次有关元素起支配作用。这些层次可以分为三类:
(i) 最高层:这一层次中只有一个元素,一般它是分析问题的预定目标或理想结果,因此也称为目标层。
(ii) 中间层:这一层次中包含了为实现目标所涉及的中间环节,它可以由若干个层次组成,包括所需考虑的准则、子准则,
因此也称为准则层。
(iii)最底层:这一层次包括了为实现目标可供选择的各种措施、决策方案等,因此也称为措施层或方案层。
递阶层次结构中的层次数与问题的复杂程度及需要分析的详尽程度有关,一般地层次数不受限制。
每一层次中各元素所支配的元素一般不要超过9个。这是因为支配的元素过多会给两两比较判断带来困难。
二. Java代码:
package boke.ahp;
import java.math.BigDecimal;
import java.util.Arrays;
/**
* AHP层次分析法计算权重
*
* @since jdk1.6
* @author 毛正吉
* @version 1.0
* @date 2010.05.25
*
*/
public class AHPComputeWeight {
/**
* @param args
*/
public static void main(String[] args) {
/** a为N*N矩阵 */
double[][] a = new double[][] { { 1, 3, 5, 1, 3 },
{ 1 / 3.0, 1, 2, 1 / 3.0, 1 / 4.0 },
{ 1 / 5.0, 1 / 2.0, 1, 1 / 3.0, 1 / 2.0 }, { 1, 3, 3, 1, 1 },
{ 1 / 3.0, 4, 2, 1, 1 } };
int N = a[0].length;
double[] weight = new double[N];
AHPComputeWeight instance = AHPComputeWeight.getInstance();
instance.weight(a, weight, N);
System.out.println(Arrays.toString(weight));
}
// 单例
private static final AHPComputeWeight acw = new AHPComputeWeight();
// 平均随机一致性指针
private double[] RI = { 0.00, 0.00, 0.58, 0.90, 1.12, 1.21, 1.32, 1.41,
1.45, 1.49 };
// 随机一致性比率
private double CR = 0.0;
// 最大特征值
private double lamta = 0.0;
/**
* 私有构造
*/
private AHPComputeWeight() {
}
/**
* 返回单例
*
* @return
*/
public static AHPComputeWeight getInstance() {
return acw;
}
/**
* 计算权重
*
* @param a
* @param weight
* @param N
*/
public void weight(double[][] a, double[] weight, int N) {
// 初始向量Wk
double[] w0 = new double[N];
for (int i = 0; i < N; i++) {
w0[i] = 1.0 / N;
}
// 一般向量W(k+1)
double[] w1 = new double[N];
// W(k+1)的归一化向量
double[] w2 = new double[N];
double sum = 1.0;
double d = 1.0;
// 误差
double delt = 0.00001;
while (d > delt) {
d = 0.0;
sum = 0;
// 获取向量
int index = 0;
for (int j = 0; j < N; j++) {
double t = 0.0;
for (int l = 0; l < N; l++)
t += a[j][l] * w0[l];
// w1[j] = a[j][0] * w0[0] + a[j][1] * w0[1] + a[j][2] * w0[2];
w1[j] = t;
sum += w1[j];
}
// 向量归一化
for (int k = 0; k < N; k++) {
w2[k] = w1[k] / sum;
// 最大差值
d = Math.max(Math.abs(w2[k] - w0[k]), d);
// 用于下次迭代使用
w0[k] = w2[k];
}
}
// 计算矩阵最大特征值lamta,CI,RI
lamta = 0.0;
for (int k = 0; k < N; k++) {
lamta += w1[k] / (N * w0[k]);
}
double CI = (lamta - N) / (N - 1);
if (RI[N - 1] != 0) {
CR = CI / RI[N - 1];
}
// 四舍五入处理
lamta = round(lamta, 3);
CI = round(CI, 3);
CR = round(CR, 3);
for (int i = 0; i < N; i++) {
w0[i] = round(w0[i], 4);
w1[i] = round(w1[i], 4);
w2[i] = round(w2[i], 4);
}
// 控制台打印输出
System.out.println("lamta=" + lamta);
System.out.println("CI=" + CI);
System.out.println("CR=" + CR);
// 控制台打印权重
System.out.println("w0[]=");
for (int i = 0; i < N; i++) {
System.out.print(w0[i] + " ");
}
System.out.println("");
System.out.println("w1[]=");
for (int i = 0; i < N; i++) {
System.out.print(w1[i] + " ");
}
System.out.println("");
System.out.println("w2[]=");
for (int i = 0; i < N; i++) {
weight[i] = w2[i];
System.out.print(w2[i] + " ");
}
System.out.println("");
}
/**
* 四舍五入
*
* @param v
* @param scale
* @return
*/
public double round(double v, int scale) {
if (scale < 0) {
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b = new BigDecimal(Double.toString(v));
BigDecimal one = new BigDecimal("1");
return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 返回随机一致性比率
*
* @return
*/
public double getCR() {
return CR;
}
}