目錄
概述
熵值法是基於信息熵(或簡稱熵)的一種信息管理方法。根據熵的特性,可以據此判斷出一個事件的隨機性以及無序程度,也可以基於熵值判斷某個指標的離散程度。離散程度越大,即信息量越大,不確定性就越小,熵也就越小;信息量越小,不確定性越大,熵也越大。基於該思想,熵值法只考慮數據內部的信息量大小,有效地避免了人為主觀因素的影響。
熵值法原理及實例講解
步驟:
(1). 數據的非負化處理;
(2). 計算第j個指標下第i個方案占該指標的比重;
(3). 計算第j箱指標的熵值
注:上述鏈接中存在一處錯去:這里的常數k=1/ln(n).n
表示樣本個數,而不是指標個數。
(4). 計算第j項指標的差異系數;
(對於第j箱指標,指標值的差異越大,對方案評價的作用越大,熵值就越小。)
(5). 求權數:保證權重之和為1;
(6). 計算各方案的得分。
代碼實現
# -*- coding=utf-8-*-
# author :Han X.Y
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
import math
class EntropyWeights:
"""
這個類用來實現熵值法
"""
def __init__(self, store_path=None, data=None, vars_num=None, maxValue_vars=None,
minValue_vars=None):
"""
初始化
:param store_path: 數據文件的存儲路徑
:param data: 若無需導數據,則可指定到具體數據集
:param vars_num: 變量個數,默認是從前往后看
:param maxValue_vars: 高優指標個數
:param minValue_vars: 低優指標個數
"""
# 高優指標
self.maxValue_vars = maxValue_vars
# 低優指標
self.minValue_vars = minValue_vars
# 原始指標名稱
self.raw_var_names = None
# 原始指標個數
self.vars_num = vars_num
# 基礎數據集的存儲路徑
self.raw_data_store_path = store_path
self.raw_data = data
def getReadData(self):
"""
讀入原始數據
:return:
"""
if self.raw_data is None:
data = pd.read_csv(self.raw_data_store_path, encoding='utf-8', index_col=0)
self.raw_data = data
data = self.raw_data
data_colnames = data.columns
if self.vars_num is None or \
self.maxValue_vars is None or \
self.minValue_vars is None:
print("請輸入關鍵參數{vars_num,maxValue_vars,minValue_vars}")
# 其他
self.raw_var_names = data_colnames[:self.vars_num] # 變量指標
# self.maxValue_vars = self.raw_var_names[:2] # 高優指標
# self.minValue_vars = self.raw_var_names[2:] # 低優指標
# self.vars_num = len(data_colnames[:-1]) # 總的指標個數
# 基礎數據
self.raw_data = data
# 非負化數據
self.non_neg_data = None
self.k = None
# 熵值
self.entropy_values = None
# 變異系數
self.G_values = None
# 最終的權重
self.final_weights = None
def precess_1_to_NNeg(self):
"""
進行非負化處理
:return:
"""
data = self.raw_data
colnames = self.raw_var_names
# tmp_data = data.copy()
# for name in colnames:
# tmp_data = tmp_data[tmp_data[name] > 0]
# if tmp_data.shape[0] == data.shape[0]:
# print(f"不存在負數,不需要進行非負化處理")
# self.non_neg_data = data[self.raw_var_names]
# else:
scaler = MinMaxScaler().fit(data[self.raw_var_names])
tmp_data = pd.DataFrame(scaler.transform(data[self.raw_var_names]), columns=self.raw_var_names,
index=self.raw_data.index)
print("tmp_data", tmp_data)
# 低優指標的計算方法與高優指標的計算不同
if len(self.minValue_vars) > 0:
for name in self.minValue_vars:
tmp_data[name] = tmp_data[[name]].apply(lambda x: 1 - x, axis=0)
print("分高優指標、和低優指標進行非負化處理")
self.non_neg_data = tmp_data
else:
self.non_neg_data = tmp_data
def calElementsProAndEntropy(self):
"""
計算各元素的比重和熵值
:return:
"""
self.k = 1 / math.log(self.raw_data.shape[0]) # 計算常數k
data = self.non_neg_data.copy()
for name in self.raw_var_names:
data[name] = data[[name]].apply(lambda x: (x + 1) / sum(x + 1), axis=0)
# 計算熵值
for name in self.raw_var_names:
data[name] = data[name].apply(lambda x: -(self.k * x * math.log(x)))
# 不同指標的熵值
entropy_list = data.apply(sum, axis=0).to_list()
self.entropy_values = entropy_list
print("".center(100, "="))
print(f"熵值:\n \t {entropy_list}")
print("".center(100, "="))
# 變異系數
G_list = [1 - i for i in entropy_list]
self.G_values = G_list
print("".center(100, "="))
print(f"變異系數:\n \t {G_list}")
print("".center(100, "="))
# 最終的權重
weights = [round(i / sum(G_list), 4) for i in G_list]
self.final_weights = dict([(i, j) for i, j in zip(self.raw_var_names, weights)])
print("".center(100, "="))
print(f"最終的權重:\n \t {self.final_weights}")
print("".center(100, "="))
def calTotalScores(self):
"""
計算綜合得分指標
:return:
"""
data = self.non_neg_data
# scores = data.apply(lambda x, y: x, self.final_weights, axis=0)
scores = data.apply(lambda x: sum([i * j for i, j in zip(x, self.final_weights.values())]), axis=1).to_list()
# print(f'綜合得分:{scores}')
self.raw_data['Total_Scores'] = scores
print("熵值法計算完畢!".center(50, "*"))
def main(self):
"""
實現熵值法
:return:
"""
print("熵值法計算:".center(100, "*"))
print("".center(100, "="))
self.getReadData()
self.precess_1_to_NNeg()
self.calElementsProAndEntropy()
self.calTotalScores()
print("".center(100, "="))
print("熵值法計算完畢!".center(100, "*"))
if __name__ == '__main__':
test = EntropyWeights()
test.main()
測試:測試數據來源於上述某參考文獻案例:
A=[[85,70,20,20],
[70,70,60,50],
[80,60,80,90]]
A=pd.DataFrame(A,index=['A',"B","C"],columns=['甲','乙','丙',''])
test2=EntropyWeights(data=A,vars_num=4,maxValue_vars=['甲','乙','丙','丁'],minValue_vars=[])
test2.main()
測試輸出:
***********************************************熵值法計算:***********************************************
====================================================================================================
熵值:[0.9657130652315669, 0.9602297178607612, 0.9657130652315666, 0.9648412112801078]
變異系數:[0.03428693476843314, 0.03977028213923883, 0.034286934768433364, 0.0351587887198922]
最終的權重:{'甲': 0.2389, '乙': 0.2771, '丙': 0.2389, '': 0.245}
綜合得分:[0.31812579451118506, 0.3255810212000094, 0.32017663843929145]
*********************熵值法計算完畢!*********************
====================================================================================================
**********************************************熵值法計算完畢!**********************************************