# 数据竞赛入门-金融风控（贷款违约预测）三、特征工程

## 导入包并读取数据

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import datetime
from tqdm import tqdm
from sklearn.preprocessing import LabelEncoder
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
from sklearn.preprocessing import MinMaxScaler
import xgboost as xgb
import lightgbm as lgb
from catboost import CatBoostRegressor
import warnings
from sklearn.model_selection import StratifiedKFold, KFold
from sklearn.metrics import accuracy_score, f1_score, roc_auc_score, log_loss
warnings.filterwarnings('ignore')



## 特征预处理

• 数据EDA部分我们已经对数据的大概和某些特征分布有了了解，数据预处理部分一般我们要处理一些EDA阶段分析出来的问题，这里介绍了数据缺失值的填充，时间格式特征的转化处理，某些对象类别特征的处理。

numerical_fea = list(data_train.select_dtypes(exclude=['object']).columns)
category_fea = list(filter(lambda x: x not in numerical_fea,list(data_train.columns)))
label = 'isDefault'
numerical_fea.remove(label)


• 把所有缺失值替换为指定的值0
data_train = data_train.fillna(0)

• 向用缺失值上面的值替换缺失值

data_train = data_train.fillna(axis=0,method=‘ffill’)

• 纵向用缺失值下面的值替换缺失值,且设置最多只填充两个连续的缺失值

data_train = data_train.fillna(axis=0,method=‘bfill’,limit=2)

#查看缺失值情况
data_train.isnull().sum()
'''
id                        0
loanAmnt                  0
term                      0
interestRate              0
installment               0
employmentTitle           1
employmentLength      46799
homeOwnership             0
annualIncome              0
verificationStatus        0
issueDate                 0
isDefault                 0
purpose                   0
postCode                  1
regionCode                0
dti                     239
delinquency_2years        0
ficoRangeLow              0
ficoRangeHigh             0
openAcc                   0
pubRec                    0
pubRecBankruptcies      405
revolBal                  0
revolUtil               531
totalAcc                  0
initialListStatus         0
applicationType           0
earliesCreditLine         0
title                     1
policyCode                0
n0                    40270
n1                    40270
n2                    40270
n2.1                  40270
n4                    33239
n5                    40270
n6                    40270
n7                    40270
n8                    40271
n9                    40270
n10                   33239
n11                   69752
n12                   40270
n13                   40270
n14                   40270
dtype: int64
'''

#按照平均数填充数值型特征
data_train[numerical_fea] = data_train[numerical_fea].fillna(data_train[numerical_fea].median())
data_test_a[numerical_fea] = data_test_a[numerical_fea].fillna(data_train[numerical_fea].median())
#按照众数填充类别型特征
data_train[category_fea] = data_train[category_fea].fillna(data_train[category_fea].mode())
data_test_a[category_fea] = data_test_a[category_fea].fillna(data_train[category_fea].mode())

data_train.isnull().sum()
'''
id                        0
loanAmnt                  0
term                      0
interestRate              0
installment               0
employmentTitle           0
employmentLength      46799
homeOwnership             0
annualIncome              0
verificationStatus        0
issueDate                 0
isDefault                 0
purpose                   0
postCode                  0
regionCode                0
dti                       0
delinquency_2years        0
ficoRangeLow              0
ficoRangeHigh             0
openAcc                   0
pubRec                    0
pubRecBankruptcies        0
revolBal                  0
revolUtil                 0
totalAcc                  0
initialListStatus         0
applicationType           0
earliesCreditLine         0
title                     0
policyCode                0
n0                        0
n1                        0
n2                        0
n2.1                      0
n4                        0
n5                        0
n6                        0
n7                        0
n8                        0
n9                        0
n10                       0
n11                       0
n12                       0
n13                       0
n14                       0
dtype: int64
'''
#查看类别特征
category_fea


• category_fea：对象型类别特征需要进行预处理，其中[‘issueDate’]为时间格式特征。

#转化成时间格式
for data in [data_train, data_test_a]:
data['issueDate'] = pd.to_datetime(data['issueDate'],format='%Y-%m-%d')
startdate = datetime.datetime.strptime('2007-06-01', '%Y-%m-%d')
#构造时间特征
data['issueDateDT'] = data['issueDate'].apply(lambda x: x-startdate).dt.days

data_train['employmentLength'].value_counts(dropna=False).sort_index()
'''
1 year        52489
10+ years    262753
2 years       72358
3 years       64152
4 years       47985
5 years       50102
6 years       37254
7 years       35407
8 years       36192
9 years       30272
< 1 year      64237
NaN           46799
Name: employmentLength, dtype: int64
'''


def employmentLength_to_int(s):
if pd.isnull(s):
return s
else:
return np.int8(s.split()[0])
for data in [data_train, data_test_a]:
data['employmentLength'].replace(to_replace='10+ years', value='10 years', inplace=True)
data['employmentLength'].replace('< 1 year', '0 years', inplace=True)
data['employmentLength'] = data['employmentLength'].apply(employmentLength_to_int)

data['employmentLength'].value_counts(dropna=False).sort_index()
'''
0.0     15989
1.0     13182
2.0     18207
3.0     16011
4.0     11833
5.0     12543
6.0      9328
7.0      8823
8.0      8976
9.0      7594
10.0    65772
NaN     11742
Name: employmentLength, dtype: int64
'''


data_train['earliesCreditLine'].sample(5)
'''
519915    Sep-2002
564368    Dec-1996
768209    May-2004
453092    Nov-1995
763866    Sep-2000
Name: earliesCreditLine, dtype: object
'''
for data in [data_train, data_test_a]:
data['earliesCreditLine'] = data['earliesCreditLine'].apply(lambda s: int(s[-4:]))


DataFrame.sample(n=None, frac=None, replace=False, weights=None, random_state=None, axis=None)

'''
n是要抽取的行数。（例如n=20000时，抽取其中的2W行）

frac是抽取的比列。（有一些时候，我们并对具体抽取的行数不关系，我们想抽取其中的百分比，这个时候就可以选择使用frac，例如frac=0.8，就是抽取其中80%）

replace：是否为有放回抽样，取replace=True时为有放回抽样。

weights这个是每个样本的权重，具体可以看官方文档说明。

random_state这个在之前的文章已经介绍过了。

axis是选择抽取数据的行还是列。axis=0的时是抽取行，axis=1时是抽取列（也就是说axis=1时，在列中随机抽取n列，在axis=0时，在行中随机抽取n行）
'''


# 部分类别特征
'applicationType', 'initialListStatus', 'title', 'policyCode']
for f in cate_features:
print(f, '类型数：', data[f].nunique())
'''
employmentTitle 类型数： 79282
homeOwnership 类型数： 6
verificationStatus 类型数： 3
purpose 类型数： 14
postCode 类型数： 889
regionCode 类型数： 51
applicationType 类型数： 2
initialListStatus 类型数： 2
title 类型数： 12058
policyCode 类型数： 1
'''


for data in [data_train, data_test_a]:

# 类型数在2之上，又不是高维稀疏的,且纯分类特征
for data in [data_train, data_test_a]:
data = pd.get_dummies(data, columns=['subGrade', 'homeOwnership', 'verificationStatus', 'purpose', 'regionCode'], drop_first=True)


## 异常值处理

• 当你发现异常值后，一定要先分清是什么原因导致的异常值，然后再考虑如何处理。首先，如果这一异常值并不代表一种规律性的，而是极其偶然的现象，或者说你并不想研究这种偶然的现象，这时可以将其删除。其次，如果异常值存在且代表了一种真实存在的现象，那就不能随便删除。在现有的欺诈场景中很多时候欺诈数据本身相对于正常数据勒说就是异常的，我们要把这些异常点纳入，重新拟合模型，研究其规律。能用监督的用监督模型，不能用的还可以考虑用异常检测的算法来做。
• 注意test的数据不能删。

def find_outliers_by_3segama(data,fea):
data_std = np.std(data[fea])
data_mean = np.mean(data[fea])
outliers_cut_off = data_std * 3
lower_rule = data_mean - outliers_cut_off
upper_rule = data_mean + outliers_cut_off
data[fea+'_outliers'] = data[fea].apply(lambda x:str('异常值') if x > upper_rule or x < lower_rule else '正常值')
return data

• 得到特征的异常值后可以进一步分析变量异常值和目标变量的关系
data_train = data_train.copy()
for fea in numerical_fea:
data_train = find_outliers_by_3segama(data_train,fea)
print(data_train[fea+'_outliers'].value_counts())
print(data_train.groupby(fea+'_outliers')['isDefault'].sum())
print('*'*10)
'''

Name: id_outliers, dtype: int64
id_outliers

Name: isDefault, dtype: int64
**********

Name: loanAmnt_outliers, dtype: int64
loanAmnt_outliers

Name: isDefault, dtype: int64
**********

Name: term_outliers, dtype: int64
term_outliers

Name: isDefault, dtype: int64
**********

Name: interestRate_outliers, dtype: int64
interestRate_outliers

Name: isDefault, dtype: int64
**********

Name: installment_outliers, dtype: int64
installment_outliers

Name: isDefault, dtype: int64
**********

Name: employmentTitle_outliers, dtype: int64
employmentTitle_outliers

Name: isDefault, dtype: int64
**********

Name: homeOwnership_outliers, dtype: int64
homeOwnership_outliers

Name: isDefault, dtype: int64
**********

Name: annualIncome_outliers, dtype: int64
annualIncome_outliers

Name: isDefault, dtype: int64
**********

Name: verificationStatus_outliers, dtype: int64
verificationStatus_outliers

Name: isDefault, dtype: int64
**********

Name: purpose_outliers, dtype: int64
purpose_outliers

Name: isDefault, dtype: int64
**********

Name: postCode_outliers, dtype: int64
postCode_outliers

Name: isDefault, dtype: int64
**********

Name: regionCode_outliers, dtype: int64
regionCode_outliers

Name: isDefault, dtype: int64
**********

Name: dti_outliers, dtype: int64
dti_outliers

Name: isDefault, dtype: int64
**********

Name: delinquency_2years_outliers, dtype: int64
delinquency_2years_outliers

Name: isDefault, dtype: int64
**********

Name: ficoRangeLow_outliers, dtype: int64
ficoRangeLow_outliers

Name: isDefault, dtype: int64
**********

Name: ficoRangeHigh_outliers, dtype: int64
ficoRangeHigh_outliers

Name: isDefault, dtype: int64
**********

Name: openAcc_outliers, dtype: int64
openAcc_outliers

Name: isDefault, dtype: int64
**********

Name: pubRec_outliers, dtype: int64
pubRec_outliers

Name: isDefault, dtype: int64
**********

Name: pubRecBankruptcies_outliers, dtype: int64
pubRecBankruptcies_outliers

Name: isDefault, dtype: int64
**********

Name: revolBal_outliers, dtype: int64
revolBal_outliers

Name: isDefault, dtype: int64
**********

Name: revolUtil_outliers, dtype: int64
revolUtil_outliers

Name: isDefault, dtype: int64
**********

Name: totalAcc_outliers, dtype: int64
totalAcc_outliers

Name: isDefault, dtype: int64
**********

Name: initialListStatus_outliers, dtype: int64
initialListStatus_outliers

Name: isDefault, dtype: int64
**********

Name: applicationType_outliers, dtype: int64
applicationType_outliers

Name: isDefault, dtype: int64
**********

Name: title_outliers, dtype: int64
title_outliers

Name: isDefault, dtype: int64
**********

Name: policyCode_outliers, dtype: int64
policyCode_outliers

Name: isDefault, dtype: int64
**********

Name: n0_outliers, dtype: int64
n0_outliers

Name: isDefault, dtype: int64
**********

Name: n1_outliers, dtype: int64
n1_outliers

Name: isDefault, dtype: int64
**********

Name: n2_outliers, dtype: int64
n2_outliers

Name: isDefault, dtype: int64
**********

Name: n2.1_outliers, dtype: int64
n2.1_outliers

Name: isDefault, dtype: int64
**********

Name: n4_outliers, dtype: int64
n4_outliers

Name: isDefault, dtype: int64
**********

Name: n5_outliers, dtype: int64
n5_outliers

Name: isDefault, dtype: int64
**********

Name: n6_outliers, dtype: int64
n6_outliers

Name: isDefault, dtype: int64
**********

Name: n7_outliers, dtype: int64
n7_outliers

Name: isDefault, dtype: int64
**********

Name: n8_outliers, dtype: int64
n8_outliers

Name: isDefault, dtype: int64
**********

Name: n9_outliers, dtype: int64
n9_outliers

Name: isDefault, dtype: int64
**********

Name: n10_outliers, dtype: int64
n10_outliers

Name: isDefault, dtype: int64
**********

Name: n11_outliers, dtype: int64
n11_outliers

Name: isDefault, dtype: int64
**********

Name: n12_outliers, dtype: int64
n12_outliers

Name: isDefault, dtype: int64
**********

Name: n13_outliers, dtype: int64
n13_outliers

Name: isDefault, dtype: int64
**********

Name: n14_outliers, dtype: int64
n14_outliers

Name: isDefault, dtype: int64
**********
'''

• 例如可以看到异常值在两个变量上的分布几乎复合整体的分布，如果异常值都属于为1的用户数据里面代表什么呢？
此用户有问题？？
#删除异常值
for fea in numerical_fea:
data_train = data_train[data_train[fea+'_outliers']=='正常值']
data_train = data_train.reset_index(drop=True)


• 总结一句话：四分位数会将数据分为三个点和四个区间，IQR = Q3 -Q1，下触须=Q1 − 1.5x IQR，上触须=Q3 + 1.5x IQR；

## 数据分桶

• 特征分箱的目的：
• 从模型效果上来看，特征分箱主要是为了降低变量的复杂性，减少变量噪音对模型的影响，提高自变量和因变量的相关度。从而使模型更加稳定。

• 数据分桶的对象：

• 将连续变量离散化
• 将多状态的离散变量合并成少状态
• 分箱的原因：

• 数据的特征内的值跨度可能比较大，对有监督和无监督中如k-均值聚类它使用欧氏距离作为相似度函数来测量数据点之间的相似度。都会造成大吃小的影响，其中一种解决方法是对计数值进行区间量化即数据分桶也叫做数据分箱，然后使用量化后的结果。
• 分箱的优点：

• 处理缺失值：当数据源可能存在缺失值，此时可以把null单独作为一个分箱。
• 处理异常值：当数据中存在离群点时，可以把其通过分箱离散化处理，从而提高变量的鲁棒性（抗干扰能力）。例如，age若出现200这种异常值，可分入“age > 60”这个分箱里，排除影响。
• 业务解释性：我们习惯于线性判断变量的作用，当x越来越大，y就越来越大。但实际x与y之间经常存在着非线性关系，此时可经过WOE变换。
• 特别要注意一下分箱的基本原则：

• （1）最小分箱占比不低于5%
• （2）箱内不能全部是好客户
• （3）连续箱单调
1. 固定宽度分箱

# 通过除法映射到间隔均匀的分箱中，每个分箱的取值范围都是loanAmnt/1000
data['loanAmnt_bin1'] = np.floor_divide(data['loanAmnt'], 1000)

## 通过对数函数映射到指数宽度分箱
data['loanAmnt_bin2'] = np.floor(np.log10(data['loanAmnt']))

1. 分位数分箱
data['loanAmnt_bin3'] = pd.qcut(data['loanAmnt'], 10, labels=False)

1. 卡方分箱

可以看这篇博客：之间补实现
一文介绍特征工程里的卡方分箱，附代码实现

### 特征交互

• 交互特征的构造非常简单，使用起来却代价不菲。如果线性模型中包含有交互特征对，那它的训练时间和评分时间就会从 O(n) 增加到 O(n2)，其中 n 是单一特征的数量。
for col in ['grade', 'subGrade']:
temp_dict = data_train.groupby([col])['isDefault'].agg(['mean']).reset_index().rename(columns={'mean': col + '_target_mean'})
temp_dict.index = temp_dict[col].values
temp_dict = temp_dict[col + '_target_mean'].to_dict()

data_train[col + '_target_mean'] = data_train[col].map(temp_dict)
data_test_a[col + '_target_mean'] = data_test_a[col].map(temp_dict)

# 其他衍生变量 mean 和 std
for df in [data_train, data_test_a]:
for item in ['n0','n1','n2','n3','n4','n5','n6','n7','n8','n9','n10','n11','n12','n13','n14']:


### 特征编码

labelEncode 直接放入树模型中

#label-encode:subGrade,postCode,title
# 高维类别特征需要进行转换
for col in tqdm(['employmentTitle', 'postCode', 'title','subGrade']):
le = LabelEncoder()
le.fit(list(data_train[col].astype(str).values) + list(data_test_a[col].astype(str).values))
data_train[col] = le.transform(list(data_train[col].astype(str).values))
data_test_a[col] = le.transform(list(data_test_a[col].astype(str).values))
print('Label Encoding 完成')
'''
100%|██████████| 4/4 [00:08<00:00,  2.04s/it]

Label Encoding 完成
'''


• 对特征做归一化，去除相关性高的特征
• 归一化目的是让训练过程更好更快的收敛，避免特征大吃小的问题
• 去除相关性是增加模型的可解释性，加快预测过程。
# 举例归一化过程
#伪代码
for fea in [要归一化的特征列表]：
data[fea] = ((data[fea] - np.min(data[fea])) / (np.max(data[fea]) - np.min(data[fea])))


### 特征选择

• 特征选择技术可以精简掉无用的特征，以降低最终模型的复杂性，它的最终目的是得到一个简约模型，在不降低预测准确率或对预测准确率影响不大的情况下提高计算速度。特征选择不是为了减少训练时间（实际上，一些技术会增加总体训练时间），而是为了减少模型评分时间。

1. Filter
• 方差选择法
• 相关系数法（pearson 相关系数）
• 卡方检验
• 互信息法
2. Wrapper （RFE）
• 递归特征消除法
3. Embedded
• 基于惩罚项的特征选择法
• 基于树模型的特征选择

Filter

• 基于特征间的关系进行筛选

• 方差选择法中，先要计算各个特征的方差，然后根据设定的阈值，选择方差大于阈值的特征]
from sklearn.feature_selection import VarianceThreshold
#其中参数threshold为方差的阈值
VarianceThreshold(threshold=3).fit_transform(train,target_train)


• Pearson 相关系数 皮尔森相关系数是一种最简单的，可以帮助理解特征和响应变量之间关系的方法，该方法衡量的是变量之间的线性相关性。 结果的取值区间为 [-1，1] ， -1 表示完全的负相关， +1表示完全的正相关，0 表示没有线性相关。
from sklearn.feature_selection import SelectKBest
from scipy.stats import pearsonr
#选择K个最好的特征，返回选择特征后的数据
#第一个参数为计算评估特征是否好的函数，该函数输入特征矩阵和目标向量，
#输出二元组（评分，P值）的数组，数组第i项为第i个特征的评分和P值。在此定义为计算相关系数
#参数k为选择的特征个数

SelectKBest(k=5).fit_transform(train,target_train)


• 经典的卡方检验是用于检验自变量对因变量的相关性。 假设自变量有N种取值，因变量有M种取值，考虑自变量等于i且因变量等于j的样本频数的观察值与期望的差距。 其统计量如下： χ2=∑(A−T)2T，其中A为实际值，T为理论值
• (注：卡方只能运用在正定矩阵上，否则会报错Input X must be non-negative)
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
#参数k为选择的特征个数

SelectKBest(chi2, k=5).fit_transform(train,target_train)


• 经典的互信息也是评价自变量对因变量的相关性的。 在feature_selection库的SelectKBest类结合最大信息系数法可以用于选择特征，相关代码如下：
from sklearn.feature_selection import SelectKBest
from minepy import MINE
#由于MINE的设计不是函数式的，定义mic方法将其为函数式的，
#返回一个二元组，二元组的第2项设置成固定的P值0.5
def mic(x, y):
m = MINE()
m.compute_score(x, y)
return (m.mic(), 0.5)
#参数k为选择的特征个数
SelectKBest(lambda X, Y: array(map(lambda x:mic(x, Y), X.T)).T, k=2).fit_transform(train,target_train)


Wrapper （Recursive feature elimination，RFE）

• 递归特征消除法 递归消除特征法使用一个基模型来进行多轮训练，每轮训练后，消除若干权值系数的特征，再基于新的特征集进行下一轮训练。 在feature_selection库的RFE类可以用于选择特征，相关代码如下（以逻辑回归为例）：
from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression
#递归特征消除法，返回特征选择后的数据
#参数estimator为基模型
#参数n_features_to_select为选择的特征个数

RFE(estimator=LogisticRegression(), n_features_to_select=2).fit_transform(train,target_train)


Embedded

• 基于惩罚项的特征选择法 使用带惩罚项的基模型，除了筛选出特征外，同时也进行了降维。 在feature_selection库的SelectFromModel类结合逻辑回归模型可以用于选择特征，相关代码如下：
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
#带L1惩罚项的逻辑回归作为基模型的特征选择

SelectFromModel(LogisticRegression(penalty="l1", C=0.1)).fit_transform(train,target_train)

• 基于树模型的特征选择 树模型中GBDT也可用来作为基模型进行特征选择。 在feature_selection库的SelectFromModel类结合GBDT模型可以用于选择特征，相关代码如下：
from sklearn.feature_selection import SelectFromModel
#GBDT作为基模型的特征选择


# 删除不需要的数据
for data in [data_train, data_test_a]:
data.drop(['issueDate'], axis=1,inplace=True)

"纵向用缺失值上面的值替换缺失值"
data_train = data_train.fillna(axis=0,method='ffill')

x_train = data_train.drop(['isDefault','id'], axis=1)
#计算协方差
data_corr = x_train.corrwith(data_train.isDefault) #计算相关性
result = pd.DataFrame(columns=['features', 'corr'])
result['features'] = data_corr.index
result['corr'] = data_corr.values

# 当然也可以直接看图
data_numeric = data_train[numerical_fea]
correlation = data_numeric.corr()

f , ax = plt.subplots(figsize = (7, 7))
plt.title('Correlation of Numeric Features with Price',y=1,size=16)
sns.heatmap(correlation,square = True,  vmax=0.8)


features = [f for f in data_train.columns if f not in ['id','issueDate','isDefault'] and '_outliers' not in f]
x_train = data_train[features]
x_test = data_test_a[features]
y_train = data_train['isDefault']

def cv_model(clf, train_x, train_y, test_x, clf_name):
folds = 5
seed = 2020
kf = KFold(n_splits=folds, shuffle=True, random_state=seed)

train = np.zeros(train_x.shape[0])
test = np.zeros(test_x.shape[0])

cv_scores = []

for i, (train_index, valid_index) in enumerate(kf.split(train_x, train_y)):
print('************************************ {} ************************************'.format(str(i+1)))
trn_x, trn_y, val_x, val_y = train_x.iloc[train_index], train_y[train_index], train_x.iloc[valid_index], train_y[valid_index]

if clf_name == "lgb":
train_matrix = clf.Dataset(trn_x, label=trn_y)
valid_matrix = clf.Dataset(val_x, label=val_y)

params = {
'boosting_type': 'gbdt',
'objective': 'binary',
'metric': 'auc',
'min_child_weight': 5,
'num_leaves': 2 ** 5,
'lambda_l2': 10,
'feature_fraction': 0.8,
'bagging_fraction': 0.8,
'bagging_freq': 4,
'learning_rate': 0.1,
'seed': 2020,
'n_jobs':24,
'silent': True,
'verbose': -1,
}

model = clf.train(params, train_matrix, 50000, valid_sets=[train_matrix, valid_matrix], verbose_eval=200,early_stopping_rounds=200)
val_pred = model.predict(val_x, num_iteration=model.best_iteration)
test_pred = model.predict(test_x, num_iteration=model.best_iteration)

# print(list(sorted(zip(features, model.feature_importance("gain")), key=lambda x: x[1], reverse=True))[:20])

if clf_name == "xgb":
train_matrix = clf.DMatrix(trn_x , label=trn_y)
valid_matrix = clf.DMatrix(val_x , label=val_y)

params = {'booster': 'gbtree',
'objective': 'binary:logistic',
'eval_metric': 'auc',
'gamma': 1,
'min_child_weight': 1.5,
'max_depth': 5,
'lambda': 10,
'subsample': 0.7,
'colsample_bytree': 0.7,
'colsample_bylevel': 0.7,
'eta': 0.04,
'tree_method': 'exact',
'seed': 2020,
"silent": True,
}

watchlist = [(train_matrix, 'train'),(valid_matrix, 'eval')]

model = clf.train(params, train_matrix, num_boost_round=50000, evals=watchlist, verbose_eval=200, early_stopping_rounds=200)
val_pred  = model.predict(valid_matrix, ntree_limit=model.best_ntree_limit)
test_pred = model.predict(test_x , ntree_limit=model.best_ntree_limit)

if clf_name == "cat":
params = {'learning_rate': 0.05, 'depth': 5, 'l2_leaf_reg': 10, 'bootstrap_type': 'Bernoulli',
'od_type': 'Iter', 'od_wait': 50, 'random_seed': 11, 'allow_writing_files': False}

model = clf(iterations=20000, **params)
model.fit(trn_x, trn_y, eval_set=(val_x, val_y),
cat_features=[], use_best_model=True, verbose=500)

val_pred  = model.predict(val_x)
test_pred = model.predict(test_x)

train[valid_index] = val_pred
test = test_pred / kf.n_splits
cv_scores.append(roc_auc_score(val_y, val_pred))

print(cv_scores)

print("%s_scotrainre_list:" % clf_name, cv_scores)
print("%s_score_mean:" % clf_name, np.mean(cv_scores))
print("%s_score_std:" % clf_name, np.std(cv_scores))
return train, test

def lgb_model(x_train, y_train, x_test):
lgb_train, lgb_test = cv_model(lgb, x_train, y_train, x_test, "lgb")
return lgb_train, lgb_test

def xgb_model(x_train, y_train, x_test):
xgb_train, xgb_test = cv_model(xgb, x_train, y_train, x_test, "xgb")
return xgb_train, xgb_test

def cat_model(x_train, y_train, x_test):
cat_train, cat_test = cv_model(CatBoostRegressor, x_train, y_train, x_test, "cat")

lgb_train, lgb_test = lgb_model(x_train, y_train, x_test)
'''
************************************ 1 ************************************
Training until validation scores don't improve for 200 rounds
[200]	training's auc: 0.749225	valid_1's auc: 0.729679
[400]	training's auc: 0.765075	valid_1's auc: 0.730496
[600]	training's auc: 0.778745	valid_1's auc: 0.730435
Early stopping, best iteration is:
[455]	training's auc: 0.769202	valid_1's auc: 0.730686
[0.7306859913754798]
************************************ 2 ************************************
Training until validation scores don't improve for 200 rounds
[200]	training's auc: 0.749221	valid_1's auc: 0.731315
[400]	training's auc: 0.765117	valid_1's auc: 0.731658
[600]	training's auc: 0.778542	valid_1's auc: 0.731333
Early stopping, best iteration is:
[407]	training's auc: 0.765671	valid_1's auc: 0.73173
[0.7306859913754798, 0.7317304414673989]
************************************ 3 ************************************
Training until validation scores don't improve for 200 rounds
[200]	training's auc: 0.748436	valid_1's auc: 0.732775
[400]	training's auc: 0.764216	valid_1's auc: 0.733173
Early stopping, best iteration is:
[386]	training's auc: 0.763261	valid_1's auc: 0.733261
[0.7306859913754798, 0.7317304414673989, 0.7332610441015461]
************************************ 4 ************************************
Training until validation scores don't improve for 200 rounds
[200]	training's auc: 0.749631	valid_1's auc: 0.728327
[400]	training's auc: 0.765139	valid_1's auc: 0.728845
Early stopping, best iteration is:
[286]	training's auc: 0.756978	valid_1's auc: 0.728976
[0.7306859913754798, 0.7317304414673989, 0.7332610441015461, 0.7289759386807912]
************************************ 5 ************************************
Training until validation scores don't improve for 200 rounds
[200]	training's auc: 0.748414	valid_1's auc: 0.732727
[400]	training's auc: 0.763727	valid_1's auc: 0.733531
[600]	training's auc: 0.777489	valid_1's auc: 0.733566
Early stopping, best iteration is:
[524]	training's auc: 0.772372	valid_1's auc: 0.733772
[0.7306859913754798, 0.7317304414673989, 0.7332610441015461, 0.7289759386807912, 0.7337723979789789]
lgb_scotrainre_list: [0.7306859913754798, 0.7317304414673989, 0.7332610441015461, 0.7289759386807912, 0.7337723979789789]
lgb_score_mean: 0.7316851627208389
lgb_score_std: 0.0017424259863954693
'''


## 总结

• 点赞
• 评论
• 分享
x

海报分享

扫一扫，分享海报

• 收藏
• 手机看

分享到微信朋友圈

x

扫一扫，手机阅读

• 打赏

打赏

越前浩波

你的鼓励将是我创作的最大动力

C币 余额
2C币 4C币 6C币 10C币 20C币 50C币
• 一键三连

点赞Mark关注该博主, 随时了解TA的最新博文
03-19
03-06

03-18