本文首先分类介绍主客观赋权法,然后简述四种客观赋权法的算法步骤,分别给出python代码。



0x01、权重计算方法简述

1.1 赋权方法的分类

在用户建模的过程中,常常需要从用户的各项行为指标 ( x 1 , x 2 , . . . , x n ) (x_{1}, x_{2}, ... , x_{n}) (x1,x2,...,xn),以加权求和的方式计算用户的总体活跃度,形如: S = a 1 x 1 + a 2 x 2 + . . . + a n x n S = a_{1} x_{1} + a_{2} x_{2} + ... + a_{n} x_{n} S=a1x1+a2x2+...+anxn

其中 a 1 , a 2 , . . . , a n a_{1}, a_{2}, ... , a_{n} a1,a2,...,an 分别为 x 1 , x 2 , . . . , x n x_{1}, x_{2}, ... , x_{n} x1,x2,...,xn 的权重。通过对 x i   ( i = 1 , 2 , . . . , n ) x_{i} ~ (i=1,2,...,n) xi (i=1,2,...,n) 的 “重要性” 的设置,加权求和,计算用户的总得分。

对于如何确定 a 1 , a 2 , . . . , a n a_{1}, a_{2}, ... , a_{n} a1,a2,...,an 的值,主要有八种方法,可分为以下四类:

  • 第1类(主观赋权法):AHP层次法和优序图法。利用数字的相对大小信息计算权重;
  • 第2类(根据信息量):熵值法(熵权法)。利用数据熵值信息即信息量大小计算权重;
  • 第3类(根据数据波动):CRITIC、独立性权重和信息量权重。利用数据的波动性或者数据之间的相关关系计算权重;
  • 第4类(信息浓缩思想):因子分析和主成分法。根据数据的信息浓缩原理,利用方差解释率计算权重。
名称数据波动性数据间相关关系数字大小信息适用性
AHP层次法适用于多个层次指标计算权重,专家打分赋权有一定的主观性
优序图法计算较简便,较多指标时使用得到的权重结果更可靠
熵值法适用于指标较多的、底层方案层指标计算权重,但对样本的依赖性较大,随着样本数据变化,权重会有一定的波动
CRITIC权重法综合考虑数据波动情况和指标间的相关性,适合指标自身带有一定相关性和波动性的数据
信息量权重法适用于将数据差异性视作一种信息,用数据波动程度来衡量指标权重
独立性权重法适用于指标本身带有一些相关性、属于同一系统下的指标计算权重
因子分析法指标较多时降维得到具有可解释性的因子权重,也可单独得到各指标权重,需要大量样本数据
主成分分析法适用于指标较多时降维得到主成分权重,也可单独得到各项指标权重,需要大量样本数据

注意:

  • 一般来说,计算权重时,可使用四种客观赋权法(熵权法、CRITIC权重法、信息量权重法、独立性权重法)分别计算各指标的权重,然后计算四种方法所得结果的均值,从而得到最终的权重。
  • 如果只想使用专家的意见,可以使用主观赋权法。
  • 因子分析法、主成分分析法主要用于降维并计算权重,只能得到各个因子的权重,无法得到具体每个分析项的权重
  • 如果想要将主客观的权重结合起来,可以使用组合赋权法(集成赋权法)。

1.2 数据处理函数

这里把后面需要用到的MinMax归一化、标准化、均值、标准差、方差、相关系数等函数都一起给出,后面的代码将仅给出算法,不再包含这些函数。

import pandas as pd
import numpy as np
import math
from sklearn.preprocessing import StandardScaler, MinMaxScaler

# 标准化
def normalize_Standard(df): 
    scaler = StandardScaler()
    return pd.DataFrame(scaler.fit_transform(df), columns=df.columns.values)

# MinMax归一化(0-1 归一化)
def normalize_MinMax(df):
    scaler = MinMaxScaler(feature_range=(0,1))
    return pd.DataFrame(scaler.fit_transform(df), columns=df.columns.values)

# 均值
def compute_mat_mean(df):
    return pd.DataFrame(df.mean(), columns=['mean_value'])

## 标准差(使用df.std)
def compute_mat_std(df):
    return pd.DataFrame(df.std(), columns=['std_value'])

# 方差(标准差的平方)
def compute_mat_var(df):
    df_std = pd.DataFrame(df.std(), columns=['std_value'])
    df_std['var_value'] = df_std['std_value'].apply(lambda x: x ** 2)
    return pd.DataFrame(df_std['var_value'], columns=['var_value'])

# 相关矩阵(相关系数矩阵)
def compute_mat_corr(df):
    return pd.DataFrame(df.corr(), columns=df.columns.values)

0x02、利用信息量计算权重

2.1 熵权法

1、基本思想

利用信息量的多少,即数据携带的信息量大小(物理学上的熵值原理)进行权重计算

2、适用范围

各信息(数据指标)之间存在差异。主要用于解决评价类问题(例如:选择哪种方案最好、哪位运动员或员工表现的更优秀)。

3、算法步骤

  • 对数据样本进行MinMax归一化处理,成为一个 m × n m \times n m×n 的矩阵, m m m 为指标个数, n n n 为样本个数;
  • 计算每个指标数据项的比值: p i j = x i j ∑ i = 1 n x i j p_{ij} = \frac{x_{ij}}{\sum_{i=1}^{n} x_{ij}} pij=i=1nxijxij
  • 计算每个指标的熵值: e j = − 1 ln ⁡ n ∑ i = 1 n ( p i j ln ⁡ p i j ) e_{j} = \frac{-1}{\ln n} \sum_{i=1}^{n} ( p_{ij} \ln p_{ij} ) ej=lnn1i=1n(pijlnpij)
  • 计算指标的熵权: w j = 1 − e j n − ∑ e j w_{j} = \frac{1-e_{j}}{n - \sum e_{j}} wj=nej1ej

4、python代码

# 计算指标的熵值 (输入:标准化df; 输出:熵值df; )
def compute_entropy(df):
    col_names = df.columns.values
    df_mid = df[col_names]
    new_col_names = []
    for cc in col_names:
        new_cc = '{}_1'.format(cc)
        new_col_names.append(new_cc)
        num_cc = df_mid[cc].count()
        sum_cc = df_mid[cc].sum()
        df_mid.loc[df_mid[cc] > 0, new_cc] = df_mid.loc[df_mid[cc] > 0, cc]\
                                                   .apply(lambda x: 0 - (x/sum_cc * math.log(x/sum_cc)) / math.log(num_cc))
        df_mid.loc[df_mid[cc] == 0, new_cc] = 0
    df_mid = df_mid[new_col_names]
    df_mid.columns = col_names
    return pd.DataFrame(df_mid.sum(), columns=['etp_value'])

# 根据熵值计算权重 (输入:熵值df; 输出:权重df;)
def compute_entropy_weight(df):
    df_mid = df[df.columns.values]
    num_cc = df_mid.count()
    sum_cc = df_mid.sum()
    df_mid['w_value'] = df_mid['etp_value'].apply(lambda x: (1 - x)/(num_cc - sum_cc))
    df_mid['p_name'] = df_mid.index.values
    return df_mid[['p_name','w_value']]

# 熵权法主函数 (输入:指标df; 输出:权重df;)
def weight_entropy(df):
    df_mid = normalize_MinMax(df)
    return compute_entropy_weight(compute_entropy(df_mid))

0x03、根据数据波动计算权重

3.1 CRITIC权重法

1、基本思想

基于 指标的对比强度(标准差) 和 指标之间的冲突性(相关系数) 来综合衡量指标的客观权重。

2、适用范围

数据稳定性可视作一种信息,并且分析的指标或因素之间有着一定的关联关系。

3、算法步骤

  • 对数据进行标准化处理,设有 n n n 条记录, m m m 个指标;
  • 计算每个指标的标准差 σ j \sigma_{j} σj 和 相关矩阵 R R R
  • 计算每个指标包含的信息量: C j = σ j ∑ i = 1 n ( 1 − r i j ) C_{j} = \sigma_{j} \sum_{i=1}^{n} (1 - r_{ij}) Cj=σji=1n(1rij)
  • 计算指标的权重: w j = C j ∑ j = 1 m C j w_{j} = \frac{C_{j}}{\sum_{j=1}^{m} C_{j}} wj=j=1mCjCj

4、python代码

# CRITIC权重法 主函数
def weight_critic(df):
    df_scale = normalize_MinMax(df)
    # 标准差
    df_std = compute_mat_std(df_scale)
    df_std['p_name'] = df_std.index.values
    # 相关系数矩阵
    df_corr = compute_mat_corr(df_scale)
    col_names = df_corr.columns.values
    # 求相关系数和
    df_mid = df_corr[col_names]
    new_col_names = []
    for cc in col_names:
        new_cc = '{}_1'.format(cc)
        new_col_names.append(new_cc)
        df_mid[new_cc] = df_mid[cc].apply(lambda x: 1-x)
    df_mid = df_mid[new_col_names]
    df_mid = pd.DataFrame(df_mid.sum(), columns=['r_value'])
    df_mid['p_name'] = col_names
    # 标准差与相关系数相乘
    df_mix = pd.merge(df_std, df_mid, on='p_name')
    df_mix['pp_value'] = df_mix.apply(lambda x: x['std_value'] * x['r_value'], axis=1)
    # 最后计算权重值
    sum_pp = df_mix['pp_value'].sum()
    df_mix['weight_value'] = df_mix['pp_value'].apply(lambda x: x/sum_pp)
    return df_mix[['p_name','weight_value']]

3.2 信息量权重法(变异系数法)

1、基本思想

基于指标数据所包含的信息量来确定指标权重,利用数据的变异系数进行权重赋值,变异系数越大,所赋的权重也越大。

2、适用范围

专家打分、或者面试官进行面试打分时对评价对象(面试者)进行综合评价。

3、算法步骤

  • 对数据进行标准化处理;
  • 计算每个指标的均值 μ i \mu_{i} μi 和标准差 σ i \sigma_{i} σi
  • 计算变异系数: C V i = σ i μ i CV_{i} = \frac{\sigma_{i}}{\mu_{i}} CVi=μiσi
  • 计算权重: w i = C V i ∑ i = 1 m C V i w_{i} = \frac{CV_{i}}{\sum_{i=1}^{m} CV_{i}} wi=i=1mCViCVi

4、python代码

# 信息量权重法 主函数
def weight_information(df):
    df_scale = normalize_MinMax(df)
    df_mid = df_scale[df_scale.columns.values]
    # 计算标准差 和 均值
    df_std = compute_mat_std(df_mid)
    df_std['p_name'] = df_std.index.values
    df_mean = compute_mat_mean(df_mid)
    df_mean['p_name'] = df_mean.index.values
    # 合并两个df
    df_mix = pd.merge(df_std, df_mean, on='p_name')
    # 计算变异系数,再计算权重
    df_mix['cof_value'] = df_mix.apply(lambda x: x['std_value'] / x['mean_value'], axis=1)
    sum_cof = df_mix['cof_value'].sum()
    df_mix['weight_value'] = df_mix['cof_value'].apply(lambda x: x / sum_cof)
    return df_mix[['p_name','weight_value']]

3.3 独立性权重法

1、基本思想

利用指标之间的共线性强弱(复相关系数)来确定权重,仅仅只考虑了数据之间相关性;

2、适用范围

数据指标之间具有相关性;

3、算法步骤

  • 对数据进行MinMax归一化处理;
  • 计算各指标的复相关系数 R R R 及其倒数 C = 1 / R C = 1/R C=1/R
  • 计算各指标的权重: w i = C i ∑ i = 1 m C i w_{i} = \frac{C_{i}}{\sum_{i=1}^{m} C_{i}} wi=i=1mCiCi

复相关系数 R R R计算:

  • 对指标 x i x_{i} xi,用余下 ( n − 1 ) (n-1) (n1) 个指标线性表示,得到: x i ^ = a 1 x 1 + . . . + a n − 1 x n − 1 \hat{x_{i}} = a_{1}x_{1} + ... + a_{n-1}x_{n-1} xi^=a1x1+...+an1xn1
  • 计算复相关系数 R R R,即计算 x i ^ \hat{x_{i}} xi^ X 1 , X 2 , . . . , X n − 1 X_{1},X_{2},...,X_{n-1} X1,X2,...,Xn1 之间的简单相关系数: R = ∑ ( x − x ˉ ) ( x ^ − x ˉ ) ∑ ( x − x ˉ ) 2 ( x ^ − x ˉ ) 2 R = \frac{\sum(x - \bar{x})(\hat{x} - \bar{x})}{\sqrt{\sum (x - \bar{x})^{2} (\hat{x} - \bar{x})^{2}}} R=(xxˉ)2(x^xˉ)2 (xxˉ)(x^xˉ)

4、python代码

# 独立性权重法
from sklearn.linear_model import LinearRegression

# 回归计算单元 使用sklearn.linear_model.LinearRegression
def linear_regression(train_X, train_y):
    lrm = LinearRegression().fit(train_X, train_y)
    return lrm.predict(train_X)

# 指标的回归计算 调度流程
def quota_regression(df):
    col_names = df.columns.values
    df_mid = df[col_names]
    new_col_names = []
    for cc in col_names:
        new_cc = '{}_1'.format(cc)
        new_col_names.append(new_cc)
        train_cols = list(col_names)
        train_cols.remove(cc)
        df_mid[new_cc] = linear_regression(df_mid[train_cols], df_mid[cc])
    return df_mid

# 计算每个特征的简单相关系数
def get_corr_coef(df, col_names):
    df_mid = df[df.columns.values]
    new_col_names = []
    for cc in col_names:
        new_cc = '{}_1'.format(cc) 
        new_cc_corr = '{}_2'.format(cc) 
        new_col_names.append(new_cc_corr) 
        mean_cc = df_mid[cc].mean() 
        cov_cc = df_mid.apply(lambda x: ((x[cc] - mean_cc) ** 2) * ((x[new_cc] - mean_cc) ** 2), axis=1).sum()
        #print('col_name: {}, mean: {}, cov: {} '.format(cc,mean_cc,cov_cc))
        df_mid[new_cc_corr] = df_mid.apply(lambda x: (x[cc] - mean_cc) * (x[new_cc] - mean_cc) / math.sqrt(cov_cc), axis=1)
    df_out = pd.DataFrame(df_mid[new_col_names].sum(), columns=['coef_values'])
    df_out['p_name'] = col_names
    df_out.index = list(range(len(df_out)))
    df_out = df_out[['p_name','coef_values']]
    return df_out

# 独立性权重法主函数
def weight_independ(df):
    column_names = df.columns.values
    df_scale = normalize_MinMax(df)
    df_mid = df_scale[column_names]
    df_coef = get_corr_coef(quota_regression(df_mid),column_names)
    df_coef['bw_coef'] = df_coef['coef_values'].apply(lambda x: 1/x)
    sum_bw = df_coef['bw_coef'].sum()
    df_coef['weight_value'] = df_coef['bw_coef'].apply(lambda x: x/sum_bw)
    return df_coef[['p_name','weight_value']]

参考资料

  1. 不知道怎样计算权重?告诉你8种确定权重方法 - 知乎
  2. 因子分析法 - MBA智库百科
  3. 熵权法评价估计详细原理讲解 - 知乎
  4. 权重计算方法_综合评价指标权重方法汇总 - CSDN
  5. CRITIC方法 - MBA智库百科
  6. 指标权重确定方法之独立性权系数法 - CSDN
  7. 指标权重确定方法之信息量权数法 - 新浪博客
  8. 特征值与特征向量的意义 - CSDN
  9. 复相关系数 - MBA智库百科
  10. 复相关系数的性质及推导 - 知乎
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐