k-折交叉验证
转自:https://zhuanlan.zhihu.com/p/106375583
https://zhuanlan.zhihu.com/p/85855015
import gc
X=train
X_test=test
del train
del test
gc.collect()
from sklearn.model_selection import StratifiedKFold
import lightgbm as lgb
params = {'num_leaves': 491,
'feature_fraction': 1,#0.3797454081646243,
'bagging_fraction': 1,#0.4181193142567742,
'objective': 'binary',
'max_depth': -1,
'learning_rate': 0.1,
"boosting_type": "gbdt",
"bagging_seed": 11,
"metric": 'auc',
"verbosity": -1,
'random_state': 47,
}
NFOLDS = 5
folds = StratifiedKFold(n_splits=NFOLDS)
##建立一个5折的分层交叉检验(根据标签不同去采样),
##因为正负样本量极为不平衡,所以不能简单用KFold,可能会导致train/validate集里没有负样本,
##对fit/validate模型来说都不利
columns = X.columns ##这里的columns其实就是dataframe X或者说是train的所有列的列命,是个list
splits = folds.split(X, y) ##根据5折划分train和valid数据
y_preds = np.zeros(X_test.shape[0])
##新建一个空的numpy array,shape同X_test的样本数,之后用来存放对test数据的预测类别
y_oof = np.zeros(X.shape[0])
##oof可以解读为out of fold,就是5折当中用来validate的那一折的预测类别,
##shape同X的样本数,因为5折之后所有样本都当过validate数据
score = 0
feature_importances = pd.DataFrame() ##新建一个dataframe用来存放lgb模型判断的特征重要性
feature_importances['feature'] = columns ##在feature_importance当中新建一列叫feature的,存储特征名称
for fold_n, (train_index, valid_index) in enumerate(splits):
##根据过去看到的一些代码,enumerate可以生成序号,从0开始,使得序号和值成为一对出现
X_train, X_valid = X[columns].iloc[train_index], X[columns].iloc[valid_index]
y_train, y_valid = y.iloc[train_index], y.iloc[valid_index]
##以上两行其实和sklearn上KFold的举例是一样的,就是划分train和validate数据集
dtrain = lgb.Dataset(X_train, label=y_train)
dvalid = lgb.Dataset(X_valid, label=y_valid)
##建立lgb的dataset,一个train一个validate。
##顺便一说,如果要查看lgb也好xgboost像sklearn那样的说明的话,左边目录里查看python API就可以了
clf = lgb.train(params, dtrain, 1000, valid_sets = [dtrain, dvalid], verbose_eval=200, early_stopping_rounds=100)
feature_importances[f'fold_{fold_n + 1}'] = clf.feature_importance()
##这里应用f的灵活写法很重要,可以按行把各特征的feature importance写到事先建立好的dataframe里
y_pred_valid = clf.predict(X_valid) ##预测X_valid的类别
y_oof[valid_index] = y_pred_valid
##把预测到的X_valid的类别存储起来
##valid_index在这里可能还有点抽象,只要想象成[0, 1, 2, ... 5000]这样的index就好了,会有这样5组index,因为有5fold
##所以原来塞满0的y_oof会在跑完5fold validate之后全部被替换成预测的类别
print(f"Fold {fold_n + 1} | AUC: {roc_auc_score(y_valid, y_pred_valid)}")
##因为比赛的evaluation是 roc_auc_score
score += roc_auc_score(y_valid, y_pred_valid) / NFOLDS ##这里计算了5折的平均roc_auc_score
y_preds += clf.predict(X_test) / NFOLDS
##y_preds原来是一个全部都为0的numpy array,通过+=把lgb预测的类别更新到y_preds当中去
del X_train, X_valid, y_train, y_valid
gc.collect()
print(f"\nMean AUC = {score}")
# print(f"Out of folds AUC = {roc_auc_score(y, y_oof)}")
## 把5fold中validate得到的结果和真实标签比较,得到一个AUC分数(其实这里每一个fold都出了一个模型)