关于归一化算法的简单实践

需求来源

前段时间有个需求要对矩阵数据做归一化处理,之后在对数据做一致性校验,并获取数据对应的权重。

需求分析

1、了解归一化算法
2、通过数据构建矩阵信息
3、数据处理
4、获取权重

实现方案

1、简单说一下概念:
归一化是一种数据处理方式,能将数据经过处理后限制在某个固定范围内。当前的需求是将数据处理为[0,1]之间的小数。

2、计算方法
2.1、归一化算法公式:

2.2、权重算法公式:

2.3、一致性校验公式:

2.4、一致性比例计算:

注:当CR<0.1时,具有一致性;否则不具有一致性。

代码实现

代码如下,做个记录:

package com.***.***.**;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;

import java.text.DecimalFormat;
import java.util.HashMap;

public class MatrixSet {

    /**
     * 矩阵横向编码
     */
    private static final String MATRIX_X = "X";

    /**
     * 矩阵纵向编码
     */
    private static final String MATRIX_Y = "Y";

    /**
     * 对应的平均随机一致性指标 RI,目前存放15阶
     */
    private static final HashMap<Integer, Double> RI_MAP = new HashMap<>();

    private static final DecimalFormat DF = new DecimalFormat("######0.00");

    static {
        RI_MAP.put(1, 0d);
        RI_MAP.put(2, 0d);
        RI_MAP.put(3, 0.52d);
        RI_MAP.put(4, 0.89d);
        RI_MAP.put(5, 1.12d);
        RI_MAP.put(6, 1.26d);
        RI_MAP.put(7, 1.36d);
        RI_MAP.put(8, 1.41d);
        RI_MAP.put(9, 1.46d);
        RI_MAP.put(10, 1.49d);
        RI_MAP.put(11, 1.52d);
        RI_MAP.put(12, 1.54d);
        RI_MAP.put(13, 1.56d);
        RI_MAP.put(14, 1.58d);
        RI_MAP.put(15, 1.59d);
    }

    public static void main(String[] args) {
        try {
            // 存放权重
            HashMap<String, String> weightMap = new HashMap<>();
            // 矩阵信息
            String matrixData = "[[\"A\",\"1\",\"2\",\"3\"],[\"B\",\"1\",\"5\",\"1/3\"],[\"C\",\"1/5\",\"1\",\"1/7\"],[\"D\",\"3\",\"7\",\"1\"]]";
            // 获取矩阵数据
            String[][] data = JSON.parseObject(matrixData, String[][].class);

            if (data.length > 0) {
                // 获取double精度的二维数组
                // 原数据数组
                double[][] arr = getDoubleArrData(data);

                // 数据校验(可对数据做其他逻辑处理)
                boolean flag = dataCheck(arr);

                // sumColumn值计算
                // parameter="X"--横向
                // parameter="Y"--纵向
                double[] sumColumn = getSumData(arr, "Y");

                // 归一化矩阵
                double[][] normalizationArr = getNormalizationArrData(arr, sumColumn);

                // sumRowColumn值计算
                double[] sumRowColumn = getSumData(normalizationArr, "X");

                // ω(权重)
                double[] weightColumn = getWeightData(sumRowColumn, arr.length);
                System.out.println("权重为:" + JSON.toJSON(weightColumn));

                // 𝛼ω
                double[] aWeightColumn = getAWeightdata(arr, weightColumn);

                // λmax = sum(每个𝛼ω/每个ω)
                double λmax = getAmax(aWeightColumn, weightColumn);

                // CI=(λmax-n)/(n-1)
                double ci = (λmax - arr.length) / (arr.length - 1);

                // RI
                double ri = RI_MAP.get(arr.length);

                // CR=CI/RI
                double cr = ci / ri;

                if (cr >= 0.1) {
                    System.out.println("当前矩阵不具有一致性");
                }
                else {
                    // 存放指标权重
                    for (int i = 0; i < weightColumn.length; i++) {
                        // 可根据需要做数据处理
                        weightMap.put(i + "", DF.format(weightColumn[i]));
                    }
                }
            }
            else {
                System.out.println("当前矩阵值为空");
            }
        }
        catch (Exception e) {
            System.out.println("矩阵数据处理异常,consistencyCheck:" + e.getMessage());
        }
    }

    /**
     * 获取double精度的二维数组
     *
     * @param orginArr 原始矩阵数据
     * @return 结果
     */
    private static double[][] getDoubleArrData(String[][] orginArr) {
        double[][] data = new double[orginArr.length - 1][orginArr.length - 1];
        for (int i = 1; i < orginArr.length; i++) {
            for (int j = 1; j < orginArr.length; j++) {
                if (orginArr[i][j].indexOf("/") > 0) {
                    if (StringUtils.isNotBlank(orginArr[i][j].split("/")[1])
                        && NumberUtils.toDouble(orginArr[i][j].split("/")[1]) != 0) {
                        double newDoubleData = NumberUtils.toDouble(orginArr[i][j].split("/")[0], 0d)
                            / NumberUtils.toDouble(orginArr[i][j].split("/")[1]);
                        data[i - 1][j - 1] = newDoubleData;
                    }
                    else {
                        System.out.println("填写的数据不能为空!");
                    }
                }
                else {
                    data[i - 1][j - 1] = NumberUtils.toDouble(orginArr[i][j]);
                }
            }
        }
        return data;
    }

    /**
     * 数据校验
     *
     * @param arr 原数组
     * @return 结果
     */
    private static boolean dataCheck(double[][] arr) {
        boolean result = false;
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr.length; j++) {
                if (arr[i][j] == 0) {
                    result = true;
                }
            }
        }
        return result;
    }

    /**
     * 获取矩阵每行或者每列数据之和
     *
     * @param arr 矩阵参数
     * @param arr 矩阵参数
     * @return 结果
     */
    private static double[] getSumData(double[][] arr, String parameter) {
        double[] result = new double[arr.length];

        for (int i = 0; i < arr.length; i++) {
            double column = 0d;
            for (int j = 0; j < arr.length; j++) {
                if (StringUtils.equals(MATRIX_X, parameter)) {
                    column += arr[i][j];
                }
                else if (StringUtils.equals(MATRIX_Y, parameter)) {
                    column += arr[j][i];
                }
            }
            result[i] = column;
        }
        return result;
    }

    /**
     * 获取归一化矩阵
     *
     * @param arr 原数组
     * @param sumColumn 原数组纵向之和数组
     * @return 结果
     */
    private static double[][] getNormalizationArrData(double[][] arr, double[] sumColumn) {

        double[][] normalizationArr = new double[arr.length][arr.length];
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr.length; j++) {
                normalizationArr[i][j] = arr[i][j] / sumColumn[j];
            }
        }
        return normalizationArr;
    }

    /**
     * 获取权重数组
     *
     * @param sumRowColumn
     * @param length
     * @return
     */
    private static double[] getWeightData(double[] sumRowColumn, int length) {
        double[] weightColumn = new double[sumRowColumn.length];
        for (int i = 0; i < weightColumn.length; i++) {
            weightColumn[i] = sumRowColumn[i] / length;
        }
        return weightColumn;
    }

    /**
     * 获取𝛼ω
     *
     * @param arr 原数组
     * @param weightColumn 权重
     * @return 结果
     */
    private static double[] getAWeightdata(double[][] arr, double[] weightColumn) {
        double[] aWeightColumn = new double[arr.length];
        for (int i = 0; i < arr.length; i++) {
            double temp = 0d;
            for (int j = 0; j < arr.length; j++) {
                temp += arr[i][j] * weightColumn[j];
            }
            aWeightColumn[i] = temp;
        }
        return aWeightColumn;
    }

    /**
     * 获取λmax
     *
     * @param aWeightColumn 𝛼ω列表
     * @param weightColumn ω列表
     * @return 结果
     */
    private static double getAmax(double[] aWeightColumn, double[] weightColumn) {
        double λmax = 0d;
        for (int i = 0; i < weightColumn.length; i++) {
            λmax += aWeightColumn[i] / weightColumn[i];
        }
        return λmax / aWeightColumn.length;
    }
}

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
社会演员多的头像社会演员多普通用户
上一篇 2023年12月21日
下一篇 2023年12月21日

相关推荐