目录
一:单特征分析:
问题: 什么是好的特征?
答: 覆盖度高的,区分度高的,相关性符合的,稳定性强的。
1.1: 覆盖度:
问题: 覆盖率你是如何计算的?
答: 计算,缺失率 和 零值率。缺失率 = 缺失的数量/带有标签的总数量。零值率 = 值为0的数量/带有标签的总数量。
1.2: 区分度:
问题: 你是如何判断区分度的好坏的?
答: 方法一: 计算单特征的AUC ,KS指标。
方法二: 计算单特征的IV值:
案例:计算IV值:
1: 计算每个标签下好人的概率 = p_good = good / good_总计
2:计算每个标签下坏人的概率 = p_bad = bad / bad_总计
3: 计算好人概率和坏人概率的差值 = p_good - p_bad
4: 计算ln(p_good/p_bad)的值。
5: 计算 IV = ln(p_good/p_bad) * (p_good - p_bad)
问题:IV值如何评估我们的区分度?
答: IV小于0.02 ,则认为区分度小,建模时应该抛弃。
IV在0.02到0.5之间,则认为区分度大,可以建模时使用。
IV大于0.5表示可以单独拿出来当做一个规则使用,不再参与训练了。
模型中尽可能使用区分度相对较弱的特征,将多个弱特征组合,得到评分卡模型
连续变量的IV值计算,先离散化再求IV,跟分箱结果关联很大(一般分3-5箱)
1.3:相关性:
- 1: 需要对相关系数较大的特征进行筛选,只保留其中对标签区分贡献度最大的特征,即保留IV较大的。
- 2: 如果一个特征可以用另外的集合特征通过线性计算得到,那么我们没必要用这个特征了。
问题: 如何判定特征与特征之间的相关性呢?
答:皮尔逊相关系数,斯皮尔曼相关系数,肯德尔相关系数
问题:如何选择用那个相关系数呢?
1:连续的数值类型 + 数据具有正态分布 = 皮尔逊系数
2:连续的数值类型 + 数据不具有正态分布 = 斯皮尔曼相关系数或者肯德尔相关系数。
3:有序分类变量 = 斯皮尔曼相关系数
4:一个分类一个连续 = 肯德尔相关系数
案例: 计算两列的三种系数:
import pandas as pd
df = pd.DataFrame({'A':[5,91,3],'B':[90,15,66],'C':[93,27,3]})
1.4:使用toad库来过滤大量的特征:
1: 加载数据:
import pandas as pd
import toad
data = pd.read_csv('data/germancredit.csv')
data.replace({'good':0,'bad':1},inplace=True)
data.shape
2: 使用toad.selection.select 来选出缺失率大于0.5,IV值小于0.05,相关性大于0.7的特征列:
#缺失率大于0.5,IV值小于0.05,相关性大于0.7来进行特征筛选
selected_data, drop_list= toad.selection.select(data,target = 'creditability', empty = 0.5, iv = 0.05, corr = 0.7, return_drop=True)
print('保留特征:',selected_data.shape[1],'缺失删除:',len(drop_list['empty']),'低iv删除:',len(drop_list['iv']),'高相关删除:',len(drop_list['corr']))
1.5 : 稳定性:
如何评估一个特征的稳定性呢 ?
答: 特征稳定性主要通过计算不同时间段内同一类用户特征的分布的差异来评估。常用的度量手段是:PSI
二:多特征筛选:
- 特征筛选的方法有: 星座特征,Boruta, 方差膨胀系数, 后向筛选, L1惩罚系数, 业务逻辑。
2.1: 星座特征:
2.2: Boruta算法:
Boruta算法的案例:
1:安装boruta算法包:
2: 加载数据:
import numpy as np
import pandas as pd
import joblib
from sklearn.ensemble import RandomForestClassifier
from boruta import BorutaPy
#加载数据
pd_data = joblib.load('data/train_woe.pkl')
pd_data
3:获取特征列和标签列:
#1: 处理数据,去掉id 和 目标值
pd_x = pd_data.drop(['SK_ID_CURR', 'TARGET'], axis=1)
# 2: 拿到所有的特征列
x = pd_x.values
# 3: 拿到目标列
y = pd_data[['TARGET']].values
# 4: 将多维数组降位一维
y = y.ravel()
4:使用Boruta,选择features:
# 1:先定义一个随机森林分类器
# 用于拟合和预测的并行运行的工作(作业)数量。如果值为-1,那么工作数量被设置为核的数量。
# class_weight='balanced',指定随机森林的的平衡性
# max_depth = 5 : 设置树的最大深度是5
rf = RandomForestClassifier(n_jobs=-1, class_weight='balanced', max_depth=5)
'''
BorutaPy function
estimator : 所使用的分类器
n_estimators : 分类器数量, 默认值 = 1000
max_iter : 最大迭代次数, 默认值 = 100
'''
# 1:定义一个BorutaPy对象
feat_selector = BorutaPy(rf, n_estimators='auto', random_state= 1, max_iter=10)
# 2: 进行训练
feat_selector.fit(x, y)
5:展示选择出来的feature:
pd_ft_select = pd.DataFrame({'feature':pd_x.columns.to_list(), "selected": feat_selector.support_})
pd_ft_select
显示结果:
2.3: 方差膨胀系数:
- 1: 描述一个特征跟另一个特征之间的线性关系。
- 2:膨胀系数越大,和别的线性越强,越可以被剔除。
案例:计算方差膨胀系数:
1: 安装膨胀系数包:
2:加载数据:
import numpy as np
import pandas as pd
import joblib
from statsmodels.stats.outliers_influence import variance_inflation_factor
pd_data = joblib.load('./data/train_woe.pkl')
#去掉ID和目标值
pd_x = pd_data.drop(['SK_ID_CURR', 'TARGET'], axis=1)
3: 计算方差膨胀系数:
#定义计算函数
def checkVIF_new(df):
lst_col = df.columns # 获取dataframe的列
x = np.matrix(df)# 将df转换成矩阵
# variance_inflation_factor(x,i),传入x是矩阵, i 是第几列,从0 到shape[1]-1,得到每个计算得到的方差膨胀系数。
VIF_list = [variance_inflation_factor(x,i) for i in range(x.shape[1])]
# 创建新的dataframe :一列是原来的列名,另一列是方差膨胀系数
VIF = pd.DataFrame({'feature':lst_col,"VIF":VIF_list})
# 获取最大的方差膨胀系数: inf无穷大
max_VIF = max(VIF_list)
print(max_VIF)
return VIF
df_vif = checkVIF_new(pd_x)
df_vif
2.4: RFE递归特征消除:
- 递归特征消除的思路: 使用排除法的方式训练模型,把模型性能下降最少的那个特征去掉,反复上述训练直到达到指定的特征个数。
案例:
1: 导入数据:
import numpy as np
import pandas as pd
import joblib
from sklearn.feature_selection import RFE
from sklearn.svm import SVR
pd_data = joblib.load('data/final_data.pkl')
pd_data
2: 数据进行处理:
pd_x = pd_data.drop(['SK_ID_CURR', 'TARGET'], axis=1) # 干掉标签列和索引列
x = pd_x.values # 转换成数组格式
y = pd_data[['TARGET']].values # 标签列,也转换成标签列
y = y.ravel() # 去掉外面的一层列
3: 使用RFE,选择features:
#定义分类器
estimator = SVR(kernel="linear") # 创建SVR模型对象
selector = RFE(estimator, 3, step=1) # step 一次去掉几个特征 ,最后只留3个。
selector = selector.fit(x, y) # 进行训练
pd_ft_select = pd.DataFrame({'feature':pd_x.columns.to_list(), "selected": selector.support_})
pd_ft_select
4: 显示结果:
2.5: 基于L1的特征选择 (L1-based feature selection)
- 1: 使用L1范数作为惩罚项的线性模型(Linear models)会得到稀疏解:大部分特征对应的系数为0。
- 2:希望减少特征维度用于其它分类器时,可以通过 feature_selection.SelectFromModel 来选择不为0的系数。
from sklearn.svm import LinearSVC
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectFromModel
iris = load_iris()
X, y = iris.data, iris.target
X.shape
# 进行L1正则化
lsvc = LinearSVC(C=0.01, penalty="l1", dual=False).fit(X, y)
# 选择不系数为0的列
model = SelectFromModel(lsvc, prefit=True)
X_new = model.transform(X)
X_new.shape
三:内部特征的监控:
3.1: 授信之前的监控:
- 1: 大多数情况下,随着业务越来越稳定,缺失率应该呈现逐渐降低的趋势。
- 2:如果缺失率突然增大,大概率是数据采集过程或者数据传输过程出现问题。
- 3: PSI ,特征维度的PSI,如果大于0.1,可以观察一段时间。
案例:要求能够根据这个看出异常信息:分析出异常信息的原因:
3.2:放款之后的监控:
1:特征区分度监控:
首先看AUC指标和KS指标波动是否在10%以内。
KS 如果是线上A卡 0.2是合格的水平
IV值的波动稍大可以容忍,和分箱相关,每周数据分布情况可能不同,对IV影响大一些
案例:看看是否异常:发现都挺正常的:
案例:看看分箱是否异常:
1:每一箱 的bad_rate有波动,容忍度相对高一些。
2:要高度重视不同箱之间风险趋势发生变化,如分箱1,分箱2,在week2和week3 风险趋势发生了变化
3:如果风险趋势单调性发生变化,要考虑特征是不是要进行迭代
四:外部特征的评估: