自学内容网 自学内容网

利用模糊综合评价法进行数值评分计算——代码实现

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;
  }
}

原文地址:https://blog.csdn.net/yinwenjie/article/details/142609440

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!