XGBoost 入门实战 - 配合sklearn应用

"""
本节内容
* xgboost 和 sklearn一起使用
* 使用校验集选择最佳模型
"""
from xgboost import XGBClassifier
# 加载LibSVM格式数据模块
from sklearn.datasets import load_svmlight_file
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from matplotlib import pyplot
from sklearn.model_selection import KFold
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import GridSearchCV

# 数据读取
"""
* scikit-learn支持多种格式的数据,包括LibSVM格式数据
* XGBoost提供一个wrapper类,允许模型可以和scikit-learn框架中其他分类器或回归器一样对待
* XGBoost中分类模型为XGBClassifier
"""
work_path = '../data/'
X_train, y_train = load_svmlight_file(work_path + 'agaricus.txt.train')
X_test, y_test = load_svmlight_file(work_path + 'agaricus.txt.test')

# print(X_train.shape)
# print(X_test.shape)
# (6513, 126)
# (1611, 126)
# print(X_train)

# 训练模型
num_round = 2   # 迭代次数(树的数目)
# 构造分类器,模型参数在构造时传递
bst = XGBClassifier(max_depth=2,
                    learning_rate=1,
                    n_estimators=num_round,
                    objective='binary:logistic')
# 类似train函数
bst.fit(X_train, y_train)

# 查看训练模型准确度
train_preds = bst.predict(X_train)
train_predictions = [round(value) for value in train_preds]
train_accuracy = accuracy_score(y_train, train_predictions)
print("Train Accuary: %.2f%%" % (train_accuracy * 100.0))       # 97.77%

# 对测试数据进行测试
test_preds = bst.predict(X_test)
test_predictions = [round(value) for value in test_preds]
test_accuracy = accuracy_score(y_test, test_predictions)
print("Test Accuary: %.2f%%" % (test_accuracy * 100.0))     # 97.83%

"""
校验集
* 我们在train集和test集都检查了模型的性能
* 实际场景中test数据是未知的(无监督数据),如何评估模型? -> 校验集
* 校验集:将train数据中一部分流出来,不参与训练,作为校验使用,余下train数据进行模型训练,
  训练好的模型在校验集上进行测试,校验集上的性能表现可以视为在未知数据上的表现,
  从而选择表现最好的模型
* 上面的代码是将所有训练集进行模型训练,下面的代码会将之前的训练集进行分割,然后训练模型、校验模型
* 总结就是:sklearn为我们提供了训练数据分组的train_test_split函数
"""

# 构造数据:训练集 + 校验集
seed = 7
# 假设取1/3的训练数据作为校验数据
test_size = 0.33
# 将训练集X_train分割成X_train_part &  X_validate
# 将训练集y_train分割成y_train_part &  y_validate
X_train_part, X_validate, y_train_part, y_validate = train_test_split(X_train,
                                                                      y_train,
                                                                      test_size=test_size,
                                                                      random_state=seed)

bst_part = XGBClassifier(max_depth=2,
                         learning_rate=1,
                         n_estimators=num_round,
                         objective='binary:logistic')
bst_part.fit(X_train_part, y_train_part)

# 校验集上的性能
validate_preds = bst_part.predict(X_validate)
validate_predictions = [round(value) for value in validate_preds]
train_part_accuracy = accuracy_score(y_validate, validate_predictions)
print("Validate Accuary: %.2f%%" % (train_part_accuracy * 100.0))     # 97.63%

"""
学习曲线
* 模型预测性能随某个变化的学习参数如样本数目、迭代次数变化的情况
* 输出并图形化模型评估数据
* eval_set:评估集,数组形势,可以同时评估多个集合
* eval_metric:评价指标
    * error:错误率
    * logloss:对数损失,模型越好数越小
        比较难理解需要深究一下:
        https://www.cnblogs.com/klchang/p/9217551.html
        https://zhuanlan.zhihu.com/p/52100927
        https://cloud.tencent.com/developer/article/1165263
"""

num_round = 100     # 画学习曲线使用
bst = XGBClassifier(max_depth=2,
                    learning_rate=1,
                    n_estimators=num_round,
                    objective='binary:logistic')
eval_set = [(X_train_part, y_train_part), (X_validate, y_validate)]
bst.fit(X_train_part,
        y_train_part,
        eval_metric=["error", "logloss"],
        eval_set=eval_set,
        verbose=True)   # 评估数据会log出来

# 显示学习曲线
results = bst.evals_result()    # 训练的时候有评估集合可以产生评估结果

epochs = len(results['validation_0']['error'])
x_axis = range(0, epochs)

# 丢失率
fig, ax = pyplot.subplots()
ax.plot(x_axis, results['validation_0']['logloss'], label='Train')
ax.plot(x_axis, results['validation_1']['logloss'], label='Test')
ax.legend()
pyplot.ylabel('Log Loss')
pyplot.title('XGBoost Log Loss')
# pyplot.show()

# 错误率
fig, ax = pyplot.subplots()
ax.plot(x_axis, results['validation_0']['error'], label='Train')
ax.plot(x_axis, results['validation_1']['error'], label='Test')
ax.legend()
pyplot.ylabel('Classification Error')
pyplot.title('XGBoost Classification Error')
# pyplot.show()


"""
过拟合(overfitting)
* 机器学习中最棘手的障碍之一:过拟合(overfitting)一个极其重要的概念;防火防盗防过拟合;
* overfitting:
    * 定义: 为了得到一致假设而使假设变得过度严格称为过拟合。
    * 判断:一个假设在训练数据上能够获得比其他假设更好的拟合, 但是在训练数据外的数据集上却不能很好地拟合数据,
            此时认为这个假设出现了过拟合的现象。出现这种现象的主要原因是训练数据中存在噪音或者训练数据太少。
    * 个人理解:就是在训练数据的时候,过分的追求训练数据的准确度,导致模型的规则偏向"定制化",不能适应普遍数据;
                可能就会出现模型跑Train数据的时候效果很好,但是用在Test或者其他数据上效果并不好的现象,这就是过拟合。
    * 解决方法:
        1、增加数据量
        2、正则化:降低 "偏激" 数据对整体的影响
    * 更多深解:
        https://baike.baidu.com/item/%E8%BF%87%E6%8B%9F%E5%90%88
        https://www.jiqizhixin.com/articles/2019-02-13-13
        https://morvanzhou.github.io/tutorials/machine-learning/tensorflow/5-02-A-overfitting/
        此时我发现一个很棒的东西:bilibili "莫烦Python"
"""

"""
Early stop
* 一种防止训练复杂模型过拟合的方法
* 监控模型在校验集上的性能,如果在经过固定次数的迭代,性能不再提高时结束训练过程
* fit参数:early_stopping_rounds=10; 代表接下来10轮性能没有上升就停止
bst.fit(X_train_part, y_train_part, early_stopping_rounds=10, eval_metric="error",
    eval_set=eval_set, verbose=True) 可以看到输出结果
"""

"""
交叉验证
* train_test_split构造的校验集
    优点:速度快
    缺点:使训练数据减少,结果没那么精准
* 交差验证举例:
    比如3折交叉验证:将train数据均分3份,
    1.以1,2为train数据,3为校验
    2.以1,3为train数据,2为校验
    3.以2,3为train数据,1为校验
    特点:效果好,耗时长
* 如果每类样本不均衡或类别数较多,采用StratifiedKFold, 将数据集中每一类样本 的数据等分
"""

kfold = KFold(n_splits=10, random_state=7, shuffle=True)
results = cross_val_score(bst, X_train, y_train, cv=kfold)
# print("CV Accuracy: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))
# print(results)

"""
参数调优(GridSearchCV)
* 我们可以根据交叉验证评估的结果,选择最佳参数的模型
* 输入待调节参数的范围(grid),对一组参数对应的模型进行评估, 并给出最佳模型及其参数
* 完整方法:GridSearchCV(estimator, param_grid,scoring=None , fit_params=None, n_jobs=1, 
                    iid=True, refit=True, c v=None, verbose=0, pre_dispatch='2*n_jobs', 
                    error_ score='raise', return_train_score=True)
"""
param_test = {
 'n_estimators': range(1, 51, 1)
}
clf = GridSearchCV(estimator=bst, param_grid=param_test, scoring='accuracy', cv=5)
clf.fit(X_train, y_train)
clf.param_grid
# clf.grid_scores_, clf.best_params_, clf.best_score_
# 测试
preds = clf.predict(X_test)
predictions = [round(value) for value in preds]
test_accuracy = accuracy_score(y_test, predictions)
print("Test Accuracy of gridsearchcv: %.2f%%" % (test_accuracy * 100.0))

"""
模型评估小结
* 通常 k-折交叉验证是评估机器学习模型的黄金准则(k=3, 5, 10)
* 当类别数目较多,或者每类样本数目不均衡时,采用stratified交叉验证
* 当训练数据集很大, train/test split带来的模型性能估计偏差很小,或者模型训练很慢时,采用train/test split
* 对给定问题找到一种技术,速度快且能得到合理的性能估计
* 如果有疑问,对回归问题,采用10-fold cross-validation ; 对分类, 采用stratified 10-fold cross-validation
"""

你可能感兴趣的:(机器学习)