心电图信号预测 - task 4 建模与调参
1. 学习模型
1.1 逻辑回归模型
- 优点:可解释性好,适合二分类问题,训练速度快,计算量仅与特征数目有关。
- 缺点:需要预先处理异常值和缺失值;对多重共线性数据较为敏感,很难处理数据不平衡问题,准确率不高。
1.2 决策树模型
- 优点:可以可视化,数据不需要预处理,可处理离散值和连续值。
- 缺点:易过拟合,泛化能力不强(可适当剪枝),采用贪心算法,容易得到局部最优解。
1.3 集成模型(ensemble method)
1.3.1 bagging 和 boosting
将若干个分类器整合为一个强分类器。
bagging | boosting | |
---|---|---|
样本选择 | 训练集是从原始集有放回的选择,所以选出的各轮训练集之间独立。 | 每一轮训练集不变,只是训练集中每个样本权重发生变化;权重是根据上一轮分类结果进行调整。 |
样例权重 | 用均匀取样,所以每个样本的权重相等 | 每个弱分类器都有相应的权重,对于分类误差小的分类器会有更大的权重 |
并行计算 | 各个预测函数可以并行生成 | 各个预测函数只能顺序生成,因为后一个模型参数需要前一轮模型的结果。 |
模型 | 随机森林 | AdaBoost, GBDT, XgBoost, LightGBM |
2 模型评估方法
2.1 数据集划分
- 训练集和测试集是从样本真实分布中独立同分布采样而得(训练集和测试集要与样本真实分布一致);训练集和测试集要互斥。
- 训练集上面的误差我们称之为训练误差或者经验误差,而在测试集上的误差称之为测试误差。
2.2 划分方法
1. 留出法:两个互斥集合。
数据集D -> 训练集S(大约2/3 ~ 4/5) + 测试集T (为保证数据分布的一致性,通常用**分层采样**的方式对数据采样。)
2. k折交叉验证法:分为k份,k-1份为训练集,剩余1份为测试集。
获得k组训练/测试集,k batches -> 结果为k个测试结果均值。数据集划分依然为**分层采样**。
k 常选10。 当 k=N 时,为留一法。
3. 自助法: 每次从数据集D中取一个样本作为训练集中的元素,然后把该样本放回,重复该行为m次,这样我们就可以得到大小为m的训练集,在这里面有的样本重复出现,有的样本则没有出现过,我们把那些没有出现过的样本作为测试集。**有放回重复采样**方式进行数据采样。
2.3 总结
1. 数据量充足 -> 留出法或者k折交叉验证法划分训练/测试集;
2. 数据集小且难以有效划分训练/测试集 -> 自助法;
3. 数据集小且可有效划分 -> 最好使用**留一法**,因为这种方法**最为准确**。
2.4 评价标准
自定义abs-sum。
3. 代码示例
3.1 导入工具包,读取数据
reduce_mem_usage 函数通过调整数据类型,减少数据占用内存。
3.2 简单建模
4. 模型调参
本次项目重点使用贝叶斯调参进行优化。
4.1 贪心调参
需要注意的是在树模型中参数调整的顺序,也就是各个参数对模型的影响程度,这里列举一下日常调参过程中常用的参数和调参顺序:
- max_depth、num_leaves
- min_data_in_leaf、min_child_weight
- bagging_fraction、 feature_fraction、bagging_freq
- reg_lambda、reg_alpha
- min_split_gain
4.2 网格搜索
sklearn 提供GridSearchCV用于进行网格搜索,只需要把模型的参数输进去,就能给出最优化的结果和参数。
相比起贪心调参,网格搜索的结果会更优,但是只适合于小数据集,一旦数据的量级上去了,很难得出结果。
4.3 贝叶斯调参
- 在使用之前需要先安装包bayesian-optimization。
- 给定优化的目标函数(广义的函数,只需指定输入和输出即可,无需知道内部结构以及数学性质),通过不断地添加样本点来更新目标函数的后验分布(高斯过程,直到后验分布基本贴合于真实分布)。简单的说,就是考虑了上一次参数的信息,从而更好的调整当前的参数。
from sklearn.model_selection import cross_val_score
"""定义优化函数"""
def rf_cv_lgb(num_leaves, max_depth, bagging_fraction, feature_fraction, bagging_freq, min_data_in_leaf,
min_child_weight, min_split_gain, reg_lambda, reg_alpha):
# 建立模型
model_lgb = lgb.LGBMClassifier(boosting_type='gbdt', objective='multiclass', num_class=4,
learning_rate=0.1, n_estimators=5000,
num_leaves=int(num_leaves), max_depth=int(max_depth),
bagging_fraction=round(bagging_fraction, 2), feature_fraction=round(feature_fraction, 2),
bagging_freq=int(bagging_freq), min_data_in_leaf=int(min_data_in_leaf),
min_child_weight=min_child_weight, min_split_gain=min_split_gain,
reg_lambda=reg_lambda, reg_alpha=reg_alpha,
n_jobs= 8
)
f1 = make_scorer(f1_score, average='micro')
val = cross_val_score(model_lgb, X_train_split, y_train_split, cv=5, scoring=f1).mean()
return val
from bayes_opt import BayesianOptimization
"""定义优化参数"""
bayes_lgb = BayesianOptimization(
rf_cv_lgb,
{
'num_leaves':(10, 200),
'max_depth':(3, 20),
'bagging_fraction':(0.5, 1.0),
'feature_fraction':(0.5, 1.0),
'bagging_freq':(0, 100),
'min_data_in_leaf':(10,100),
'min_child_weight':(0, 10),
'min_split_gain':(0.0, 1.0),
'reg_alpha':(0.0, 10),
'reg_lambda':(0.0, 10),
}
)
"""开始优化"""
bayes_lgb.maximize(n_iter=10)
"""显示优化结果"""
bayes_lgb.max
"""调整一个较小的学习率,并通过cv函数确定当前最优的迭代次数"""
base_params_lgb = {
'boosting_type': 'gbdt',
'objective': 'multiclass',
'num_class': 4,
'learning_rate': 0.01,
'num_leaves': 138,
'max_depth': 11,
'min_data_in_leaf': 43,
'min_child_weight':6.5,
'bagging_fraction': 0.64,
'feature_fraction': 0.93,
'bagging_freq': 49,
'reg_lambda': 7,
'reg_alpha': 0.21,
'min_split_gain': 0.288,
'nthread': 10,
'verbose': -1,
}
cv_result_lgb = lgb.cv(
train_set=train_matrix,
early_stopping_rounds=1000,
num_boost_round=20000,
nfold=5,
stratified=True,
shuffle=True,
params=base_params_lgb,
feval=f1_score_vali,
seed=0
)
print('迭代次数{}'.format(len(cv_result_lgb['f1_score-mean'])))
print('最终模型的f1为{}'.format(max(cv_result_lgb['f1_score-mean'])))
import lightgbm as lgb
"""使用lightgbm 5折交叉验证进行建模预测"""
cv_scores = []
for i, (train_index, valid_index) in enumerate(kf.split(X_train, y_train)):
print('************************************ {} ************************************'.format(str(i+1)))
X_train_split, y_train_split, X_val, y_val = X_train.iloc[train_index], y_train[train_index], X_train.iloc[valid_index], y_train[valid_index]
train_matrix = lgb.Dataset(X_train_split, label=y_train_split)
valid_matrix = lgb.Dataset(X_val, label=y_val)
params = {
'boosting_type': 'gbdt',
'objective': 'multiclass',
'num_class': 4,
'learning_rate': 0.01,
'num_leaves': 138,
'max_depth': 11,
'min_data_in_leaf': 43,
'min_child_weight':6.5,
'bagging_fraction': 0.64,
'feature_fraction': 0.93,
'bagging_freq': 49,
'reg_lambda': 7,
'reg_alpha': 0.21,
'min_split_gain': 0.288,
'nthread': 10,
'verbose': -1,
}
model = lgb.train(params, train_set=train_matrix, num_boost_round=4833, valid_sets=valid_matrix,
verbose_eval=1000, early_stopping_rounds=200, feval=f1_score_vali)
val_pred = model.predict(X_val, num_iteration=model.best_iteration)
val_pred = np.argmax(val_pred, axis=1)
cv_scores.append(f1_score(y_true=y_val, y_pred=val_pred, average='macro'))
print(cv_scores)
print("lgb_scotrainre_list:{}".format(cv_scores))
print("lgb_score_mean:{}".format(np.mean(cv_scores)))
print("lgb_score_std:{}".format(np.std(cv_scores)))