熵权法

简介

熵权法是一种基于信息熵的权重确定方法。信息熵用于衡量系统的不确定性。指标越分散,其熵值越大,说明该指标包含的信息越多。在熵权法中,所有指标的权重由其信息熵决定,熵值越小,权重越大。熵权法的优势在于它能够客观地确定权重,减少人为因素的影响。

求解流程

  1. 数据标准化:将原始数据进行标准化处理,以消除不同指标量纲的影响。
  2. 计算各指标的比重:计算每个评价对象在各个指标上的比重。
  3. 计算信息熵:根据比重,计算每个指标的信息熵。
  4. 计算熵权:根据信息熵计算各指标的权重。
  5. 加权得分:根据权重和标准化后的数据计算每个评价对象的综合得分。

Python实现

建立EntropyWeightMethod类:

Python
import numpy as np


def calculate_proportion(norm_data):
    prop_data = norm_data / np.sum(norm_data, axis=0)
    return prop_data


def calculate_entropy(prop_data):
    k = 1.0 / np.log(prop_data.shape[0])
    entropy = -k * np.sum(prop_data * np.log(prop_data + 1e-12), axis=0)
    return entropy


def calculate_weights(entropy):
    d = 1 - entropy
    weights = d / np.sum(d)
    return weights


def calculate_scores(norm_data, weights):
    scores = np.dot(norm_data, weights)
    return scores


class EntropyWeightMethod(object):

    def __init__(self, data):
        self.data = data

    def normalize(self):
        norm_data = self.data / np.sqrt(np.sum(self.data ** 2, axis=0))
        return norm_data

    def core_method(self, output=True):
        def print_method():
            print("标准化数据:\n", norm_data)
            print("指标信息熵:", entropy)
            print("指标权重:", weights)
            print("评价对象的得分:", scores)

        norm_data = self.normalize()  # 步骤1:数据标准化
        prop_data = calculate_proportion(norm_data)  # 步骤2:计算各指标的比重
        entropy = calculate_entropy(prop_data)  # 步骤3:计算信息熵
        weights = calculate_weights(entropy)  # 步骤4:计算熵权
        scores = calculate_scores(norm_data, weights)  # 步骤5:加权得分
        if output:
            print_method()

给定一个简单算例:假设有三个评价对象A、B、C,它们对应的三个指标分别是指标1、指标2、指标3。

指标1指标2指标3
A0.90.60.8
B0.70.80.5
C0.80.70.9

引用并求解:

Python
import numpy as np
from models.EntropyWeight import EntropyWeightMethod

# 原始数据
data = np.array([
    [0.9, 0.6, 0.8],
    [0.7, 0.8, 0.5],
    [0.8, 0.7, 0.9]
])

ew = EntropyWeightMethod(data)
ew.core_method()

TOPSIS法

简介

TOPSIS法(Technique for Order Preference by Similarity to an Ideal Solution),是一种多指标决策分析方法。这个方法的基本思想是通过计算每个选项与理想解和负理想解的距离来进行排序。理想解是所有指标值最优的组合,负理想解则是所有指标值最差的组合。选择距离理想解最近且距离负理想解最远的选项作为最优方案。

求解流程

  1. 数据标准化:将原始数据进行标准化处理,以消除不同指标量纲的影响。
  2. 构建标准化矩阵:将标准化数据构造成一个标准化决策矩阵。
  3. 确定正负理想解:确定各指标的正理想解(最大值)和负理想解(最小值)。
  4. 计算距离:计算每个评价对象与正理想解和负理想解的距离。
  5. 计算相对接近度:根据与正负理想解的距离,计算每个评价对象的相对接近度。
  6. 排序:根据相对接近度对评价对象进行排序。

Python实现

建立TopsisMethod类:

Python
import numpy as np


def ideal_solutions(norm_data):
    positive_ideal = np.max(norm_data, axis=0)
    negative_ideal = np.min(norm_data, axis=0)
    return positive_ideal, negative_ideal


def calculate_distances(norm_data, positive_ideal, negative_ideal):
    dist_to_positive = np.sqrt(np.sum((norm_data - positive_ideal)**2, axis=1))
    dist_to_negative = np.sqrt(np.sum((norm_data - negative_ideal)**2, axis=1))
    return dist_to_positive, dist_to_negative


def calculate_relative_closeness(dist_to_positive, dist_to_negative):
    relative_closeness = dist_to_negative / (dist_to_positive + dist_to_negative)
    return relative_closeness


class TopsisMethod(object):

    def __init__(self,data):
        self.data = data

    def normalize(self):
        norm_data = self.data / np.sqrt(np.sum(self.data ** 2, axis=0))
        return norm_data

    def core_method(self, output=True):
        def print_method():
            print("标准化数据:\n", norm_data)
            print("正理想解:", positive_ideal)
            print("负理想解:", negative_ideal)
            print("到正理想解的距离:", dist_to_positive)
            print("到负理想解的距离:", dist_to_negative)
            print("相对接近度:", relative_closeness)
            print("排序(从优到劣):", rank + 1)

        norm_data = self.normalize()  # 步骤1:数据标准化
        # 步骤2:构建标准化矩阵(已经完成标准化)
        positive_ideal, negative_ideal = ideal_solutions(norm_data)  # 步骤3:确定正负理想解
        dist_to_positive, dist_to_negative = calculate_distances(norm_data, positive_ideal, negative_ideal)  # 步骤4:计算距离
        relative_closeness = calculate_relative_closeness(dist_to_positive, dist_to_negative)  # 步骤5:计算相对接近度
        rank = np.argsort(-relative_closeness)  # 步骤6:排序
        if output:
            print_method()

使用和熵权法同样的算例,引用求解:

Python
import numpy as np
from models.Topsis import TopsisMethod

# 原始数据
data = np.array([
    [0.9, 0.6, 0.8],
    [0.7, 0.8, 0.5],
    [0.8, 0.7, 0.9]
])

topsis = TopsisMethod(data)
topsis.core_method()

附录:正向化方法

要使得原始数据变得更适合运用指标评价方法进行分析,需要执行正向化操作(先于上述方法的第一步)。一种比较好的思路是针对非正向指标中的不同类型指标(极小型、中间型和区间型)执行不同的正向化思路:

参考文献:https://zhuanlan.zhihu.com/p/37738503

根据上述思路编写相应的正向化方法:

Python
import numpy as np

def min_method_rcp(arr):
    return np.reciprocal(arr)


def min_method_sub(arr):
    return np.max(arr) - arr


def mid_method(arr, e_min, e_max):
    '''
    中间型方法
    :param e_min: 指标可能取值的最小值,自行确定
    :param e_max: 指标可能取值的最大值,自行确定
    '''
    result = np.zeros_like(arr, dtype=float)
    mid_val = (e_min + e_max) / 2
    for i, val in enumerate(arr):
        if e_min <= val <= mid_val:
            result[i] = 2 * (val - e_min) / (e_max - e_min)
        elif mid_val < val <= e_max:
            result[i] = 2 * (e_max - val) / (e_max - e_min)
        else:
            result[i] = 0
    return result


def rng_method(arr, e_range, a_range):
    '''
    区间型方法
    :param e_range: 指标的最佳稳定区间,自行确定
    :param a_range: 指标的最大容忍区间,自行确定
    '''
    e_min, e_max, a_min, a_max = e_range[0], e_range[1], a_range[0], a_range[1]
    result = np.zeros_like(arr, dtype=float)
    for i, val in enumerate(arr):
        if val < a_min or val > a_max:
            result[i] = 0
        elif val < e_min:
            result[i] = (e_min - val) / (e_min - a_min)
        elif val > e_max:
            result[i] = (val - e_max) / (a_max - e_max)
        else:
            result[i] = 1
    return result


class PositiveMethod(object):
    def __init__(self, data, method, attr):
        self.data = data
        self.method = method
        self.attr = attr

    def process_by_row(self):
        positive_data = np.zeros_like(self.data, dtype=float)
        for _ in range(len(self.data)):
            if self.method[_] == 'rcp' or 'min':  # 取倒数,极小型默认方法
                positive_data[_, :] = min_method_rcp(self.data[_, :])
            elif self.method[_] == 'sub':  # 相减取反,极小型另一种方法
                positive_data[_, :] = min_method_sub(self.data[_, :])
            elif self.method[_] == 'mid':  # 中间型方法
                positive_data[_, :] = mid_method(self.data[_, :], self.attr[_][0], self.attr[_][1])
            else:  # 区间型方法
                positive_data[_, :] = rng_method(self.data[_, :], self.attr[_][0], self.attr[_][1])
        return positive_data

算例引用:

Python
import numpy as np
from models.Topsis import PositiveMethod

# 样例数据
data = np.array([
    [1, 2, 3, 4, 5],  # 极小型
    [3, 3.5, 4, 4.5, 5],  # 中间型
    [15, 20, 25, 30, 35]  # 区间型
])

method = ['min', 'mid', 'rng']
attr = [[], [2, 7], [[20, 30], [18, 32]]]

pm = PositiveMethod(data, method, attr)
positive_data = pm.process_by_row()
print(positive_data)