利用模糊综合评价法进行数值评分计算——代码实现
1、前情回顾
之前的文章,我们详细介绍了模糊评分法的具体计算过程(不清楚的读者可点击此处的传送门《利用模糊综合评价法进行数值评分计算——算法过程》)。本篇文章我们展示模糊评分法的主要实现代码(Java版本,实际上Python、GoLang等逻辑是相同的,之后会提供GoLang版本的代码)。
2、具体计算过程
本文的介绍将通过以下示例场景进行:
// 行表示每个参与者的数据,列表示每一个评分指标
// 且矩阵中的每列数据,都是正向数据
double points[][] = new double[][] {
{1.0 , 1.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 2.0 , 1.0 , 0.0 , 1.0},
{4.0 , 1.0 , 3.0 , 0.0 , 0.0 , 1.0 , 1.0 , 0.0 , 1.0 , 1.0 , 1.0},
{1.0 , 1.0 , 0.0 , 1.0 , 0.0 , 0.0 , 1.0 , 1.0 , 0.0 , 0.0 , 1.0},
{2.0 , 0.0 , 0.0 , 0.0 , 0.0 , 1.0 , 1.0 , 1.0 , 0.0 , 2.0 , 3.0},
{4.0 , 1.0 , 0.0 , 2.0 , 1.0 , 0.0 , 0.0 , 1.0 , 1.0 , 0.0 , 2.0}};
从以上代码中我们知道了,评分参与者有11人(或者理解成11个品牌的车、11款电视型号,等等)。评分指标一共有5个,其中每一项指标都是正向指标。注意,以上矩阵中,列表示评分参与者,行表示指标。
2.1、进行数据标准化
/**
* 数据标准化,主要是区分正向因子和负向因子,进行数据标准化,以便进行下一步计算(这里修正了一下,导致结果不可能为0)
* @param points 原始数据数组
* @param index 需要进行标准化的原始数据的索引位置
* @param forward 是否是正向因子
* @return 返回的标准化之后的数值
*/
private static double standard(double points[] , int index , boolean forward) {
if(index < 0 || index > points.length - 1) {
throw new IllegalArgumentException("错误的参数");
}
double max = new Max().evaluate(points);
double min = new Min().evaluate(points);
// 正向指标
double result = 0.0;
if(forward) {
result = (points[index] - min + 1) / (max - min + 1);
} else {
result = (max - points[index] + 1) / (max - min + 1);
}
return result;
}
// 下面开始进行矩阵的标准化
// 数据标准化后的对应矩阵,存储在这里
double standards[][] = new double[5][11];
for (int t = 0 ; t < points.length ; t++) {
double[] pointItems = points[t];
for (int index = 0 ; index < pointItems.length ; index++) {
double result = standard(points[t], index, true);
standards[t][index] = result;
}
}
以上代码标段中得到的标准化之后的矩阵standards,后续的计算步骤主要就是使用这个standards矩阵进行。注意,和前文介绍的熵权法计算过程不一样,由于调用代码的矩阵确认方式,所以计算矩阵在这里暂时还不需要进行矩阵翻转。
2.2、求模糊关系矩阵
这一步也可以看做是求每一个评分要素的数值占比。
/**
* 求关系矩阵
* @param points
* @param index 需要求值的原始数据的索引位置
* @return
*/
private static double relatMatrix(double standards[] , int index) {
double sum = new Sum().evaluate(standards);
double result = standards[index] / sum;
return result;
}
// 以下是调用代码
double matrixs[][] = new double[5][11];
for (int t = 0 ; t < points.length ; t++) {
double[] pointItems = points[t];
for (int index = 0 ; index < pointItems.length ; index++) {
double matrix = relatMatrix(standards[t], index);
matrixs[t][index] = matrix;
}
}
请注意以上代码片段中的matrixs矩阵,求得的关系矩阵数据就存储在这里,并且后续继续基于此矩阵进行计算。
2.3、设置或计算权重以及权重比
// 给定权重,由人工指定的权重,并求权重因子
double weights[] = new double[] {1,1,1,1,1};
double weightMatrixs[] = new double[5];
for (int index = 0 ; index < weights.length ; index++) {
double matrix = relatMatrix(weights, index);
weightMatrixs[index] = matrix;
}
if(weights.length != matrixs.length) {
throw new IllegalArgumentException("错误参数,因子数和权重数不一致");
}
通过以上代码我们可以看到,技术人员人为设置了一个权重,记为weights变量。由于本示例中,参与评分的评分指标一共有5个,所以这里将5个指标的权重,全部设置为1。
2.4、计算基准得分和使用者能看懂的百分制得分
/**
* 转换为100分制
* @param benchScores
* @param index 要将哪一个基准数转换为100分制
*/
private static double percentageScores(double benchScores[] , int index) {
int len = benchScores.length;
Double maxScore = new Max().evaluate(benchScores);
Double maxScaleScore = new BigDecimal(maxScore.toString()).setScale(2, RoundingMode.UP).doubleValue();
Double total = (100 * len) / (maxScaleScore * len) * benchScores[index];
return new BigDecimal(total.toString()).setScale(2, RoundingMode.HALF_UP).doubleValue();
}
/**
* 矩阵翻转
* @param matrixs 原始数据矩阵(二维矩阵)
* @param index 需要翻转的原始矩阵的索引号
*/
private static double[] matrixFlipping(double matrixs[][] , int index) {
int matrixLen = matrixs.length;
double flips[] = new double[matrixLen];
for(int lenIndex = 0 ; lenIndex < matrixLen ; lenIndex++) {
flips[lenIndex] = matrixs[lenIndex][index];
}
return flips;
}
// 以下代码是调用代码
// 求第X列,实际上就是第X个指标,有11条采样数据
int weightLen = weights.length;
double benchScores[] = new double[11];
for(int index = 0 ; index < 11 ; index++) {
double[] matrixFlips = matrixFlipping(matrixs, index);
double result = 0d;
for(int weightIndex = 0 ; weightIndex < weightLen ; weightIndex++) {
result += weightMatrixs[weightIndex] * matrixFlips[weightIndex];
}
benchScores[index] = result;
}
// 接着准换为100分数
Double percentageScores[] = new Double[11];
for(int index = 0 ; index < 11 ; index++) {
percentageScores[index] = percentageScores(benchScores, index);
}
System.out.println("percentageScores = " + StringUtils.join(percentageScores, " | "));
}
注意,以上代码需要进行矩阵翻转,矩阵翻转的方法为matrixFlipping方法所示。最终我们可以得到实例评分场景中的各个得分结果,如下所示:
percentageScores = 94.57 | 53.32 | 44.17 | 46.61 | 34.58 | 39.96 | 46.88 | 60.94 | 46.4 | 45.57 | 75.24
3、总结说明
最后,为了各位读者学习方便,本文在这里放出完整的代码示例:
// 模糊综合评价法示例
public class FceTest {
public static void main(String[] args) {
double points[][] = new double[][] {
{1.0 , 1.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 2.0 , 1.0 , 0.0 , 1.0},
{4.0 , 1.0 , 3.0 , 0.0 , 0.0 , 1.0 , 1.0 , 0.0 , 1.0 , 1.0 , 1.0},
{1.0 , 1.0 , 0.0 , 1.0 , 0.0 , 0.0 , 1.0 , 1.0 , 0.0 , 0.0 , 1.0},
{2.0 , 0.0 , 0.0 , 0.0 , 0.0 , 1.0 , 1.0 , 1.0 , 0.0 , 2.0 , 3.0},
{4.0 , 1.0 , 0.0 , 2.0 , 1.0 , 0.0 , 0.0 , 1.0 , 1.0 , 0.0 , 2.0}};
// 进行这列数的标准化
double standards[][] = new double[5][11];
for (int t = 0 ; t < points.length ; t++) {
double[] pointItems = points[t];
for (int index = 0 ; index < pointItems.length ; index++) {
double result = standard(points[t], index, true);
standards[t][index] = result;
}
}
// 求模糊关系矩阵
double matrixs[][] = new double[5][11];
for (int t = 0 ; t < points.length ; t++) {
double[] pointItems = points[t];
for (int index = 0 ; index < pointItems.length ; index++) {
double matrix = relatMatrix(standards[t], index);
matrixs[t][index] = matrix;
}
}
// 给定权重,由人工指定的权重,并求权重因子
double weights[] = new double[] {1,1,1,1,1};
double weightMatrixs[] = new double[5];
for (int index = 0 ; index < weights.length ; index++) {
double matrix = relatMatrix(weights, index);
weightMatrixs[index] = matrix;
}
if(weights.length != matrixs.length) {
throw new IllegalArgumentException("错误参数,因子数和权重数不一致");
}
// 求第X列,实际上就是第X天的业务数据,有11条采样数据
int weightLen = weights.length;
double benchScores[] = new double[11];
for(int index = 0 ; index < 11 ; index++) {
double[] matrixFlips = matrixFlipping(matrixs, index);
double result = 0d;
for(int weightIndex = 0 ; weightIndex < weightLen ; weightIndex++) {
result += weightMatrixs[weightIndex] * matrixFlips[weightIndex];
}
benchScores[index] = result;
}
// 接着准换为100分数
Double percentageScores[] = new Double[11];
for(int index = 0 ; index < 11 ; index++) {
percentageScores[index] = percentageScores(benchScores, index);
}
System.out.println("percentageScores = " + StringUtils.join(percentageScores, " | "));
}
/**
* 转换为100分制
* @param benchScores
* @param index 要将哪一个基准数转换为100分制
* @return
*/
private static double percentageScores(double benchScores[] , int index) {
int len = benchScores.length;
Double maxScore = new Max().evaluate(benchScores);
Double maxScaleScore = new BigDecimal(maxScore.toString()).setScale(2, RoundingMode.UP).doubleValue();
Double total = (100 * len) / (maxScaleScore * len) * benchScores[index];
return new BigDecimal(total.toString()).setScale(2, RoundingMode.HALF_UP).doubleValue();
}
/**
* 矩阵翻转
* @param matrixs 原始数据矩阵(二维矩阵)
* @param index 需要翻转的原始矩阵的索引号
* @return
*/
private static double[] matrixFlipping(double matrixs[][] , int index) {
int matrixLen = matrixs.length;
double flips[] = new double[matrixLen];
for(int lenIndex = 0 ; lenIndex < matrixLen ; lenIndex++) {
flips[lenIndex] = matrixs[lenIndex][index];
}
return flips;
}
/**
* 求关系矩阵
* @param points
* @param index 需要求值的原始数据的索引位置
* @return
*/
private static double relatMatrix(double standards[] , int index) {
double sum = new Sum().evaluate(standards);
double result = standards[index] / sum;
return result;
}
/**
* 数据标准化,主要是区分正向因子和负向因子,进行数据标准化,以便进行下一步计算(这里修正了一下,导致结果不可能为0)
* @param points 原始数据数组
* @param index 需要进行标准化的原始数据的索引位置
* @param forward 是否是正向因子
* @return 返回的标准化之后的数值
*/
private static double standard(double points[] , int index , boolean forward) {
if(index < 0 || index > points.length - 1) {
throw new IllegalArgumentException("错误的参数");
}
double max = new Max().evaluate(points);
double min = new Min().evaluate(points);
// 正向指标
double result = 0.0;
if(forward) {
result = (points[index] - min + 1) / (max - min + 1);
} else {
result = (max - points[index] + 1) / (max - min + 1);
}
return result;
}
}