本文首先分类介绍主客观赋权法,然后简述四种客观赋权法的算法步骤,分别给出python代码。
在用户建模的过程中,常常需要从用户的各项行为指标 ( 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 的值,主要有八种方法,可分为以下四类:
名称 | 数据波动性 | 数据间相关关系 | 数字大小信息 | 适用性 |
---|---|---|---|---|
AHP层次法 | 无 | 无 | 有 | 适用于多个层次指标计算权重,专家打分赋权有一定的主观性 |
优序图法 | 无 | 无 | 有 | 计算较简便,较多指标时使用得到的权重结果更可靠 |
熵值法 | 无 | 无 | 无 | 适用于指标较多的、底层方案层指标计算权重,但对样本的依赖性较大,随着样本数据变化,权重会有一定的波动 |
CRITIC权重法 | 有 | 有 | 无 | 综合考虑数据波动情况和指标间的相关性,适合指标自身带有一定相关性和波动性的数据 |
信息量权重法 | 有 | 无 | 无 | 适用于将数据差异性视作一种信息,用数据波动程度来衡量指标权重 |
独立性权重法 | 无 | 有 | 无 | 适用于指标本身带有一些相关性、属于同一系统下的指标计算权重 |
因子分析法 | 无 | 有 | 无 | 指标较多时降维得到具有可解释性的因子权重,也可单独得到各指标权重,需要大量样本数据 |
主成分分析法 | 无 | 有 | 无 | 适用于指标较多时降维得到主成分权重,也可单独得到各项指标权重,需要大量样本数据 |
注意:
- 一般来说,计算权重时,可使用四种客观赋权法(熵权法、CRITIC权重法、信息量权重法、独立性权重法)分别计算各指标的权重,然后计算四种方法所得结果的均值,从而得到最终的权重。
- 如果只想使用专家的意见,可以使用主观赋权法。
- 因子分析法、主成分分析法主要用于降维并计算权重,只能得到各个因子的权重,无法得到具体每个分析项的权重。
- 如果想要将主客观的权重结合起来,可以使用组合赋权法(集成赋权法)。
这里把后面需要用到的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)
1、基本思想
利用信息量的多少,即数据携带的信息量大小(物理学上的熵值原理)进行权重计算。
2、适用范围
各信息(数据指标)之间存在差异。主要用于解决评价类问题(例如:选择哪种方案最好、哪位运动员或员工表现的更优秀)。
3、算法步骤
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))
1、基本思想
基于 指标的对比强度(标准差) 和 指标之间的冲突性(相关系数) 来综合衡量指标的客观权重。
2、适用范围
数据稳定性可视作一种信息,并且分析的指标或因素之间有着一定的关联关系。
3、算法步骤
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']]
1、基本思想
基于指标数据所包含的信息量来确定指标权重,利用数据的变异系数进行权重赋值,变异系数越大,所赋的权重也越大。
2、适用范围
专家打分、或者面试官进行面试打分时对评价对象(面试者)进行综合评价。
3、算法步骤
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']]
1、基本思想
利用指标之间的共线性强弱(复相关系数)来确定权重,仅仅只考虑了数据之间相关性;
2、适用范围
数据指标之间具有相关性;
3、算法步骤
复相关系数 R R R 的计算:
- 对指标 x i x_{i} xi,用余下 ( n − 1 ) (n-1) (n−1) 个指标线性表示,得到: 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+...+an−1xn−1
- 计算复相关系数 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,...,Xn−1 之间的简单相关系数: 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=∑(x−xˉ)2(x^−xˉ)2∑(x−xˉ)(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']]