目录

  • 前言
    • 算法原理
  • 一、模型对比与性能评估
    • 1.1 逻辑回归
    • 1.2 决策树模型
    • 1.3 模型评估的方法
  • 二、代码示例
    • 2.1 导入相关包
    • 2.2 读取数据
    • 2.3 简单建模
  • 三、模型调参
    • 3.1 贪心调参
    • 3.2 网格搜索
  • 总结

前言

算法原理

  1. 逻辑回归
  2. 决策树
  3. GBDT
  4. XGBoost
  5. LightGBM
  6. Catboost
  7. 时间序列模型(RNN)
  8. 时间序列模型(LSTM)

一、模型对比与性能评估

1.1 逻辑回归

优点:

  • 训练速度快,分类的时候,计算量仅仅只和特征的数目相关;
  • 简单易理解,模型的可解释性非常好,从特征的权重可以看到不同的特征对最后结果的影响;
  • 适合二分类问题,不需要缩放输入特征;
  • 内存资源占用小,只需要存储各个维度的特征值;

缺点:

  • 逻辑回归需要预先处理缺失值和异常值;
  • 不能用 LogisticLogisticLogistic 回归去解决非线性问题,因为 LogisticLogisticLogistic 的决策面是线性的;
  • 对多重共线性数据较为敏感,且很难处理数据不平衡的问题;
  • 准确率并不是很高,因为形式非常简单,很难去拟合数据的真实分布;

1.2 决策树模型

优点:

  • 简单直观,生成的决策树可以可视化展示;
  • 数据不需要预处理,不需要归一化,不需要处理缺失数据
  • 既可以处理离散值,也可以处理连续值;

缺点:

  • 决策树算法非常容易过拟合,导致泛化能力不强(可进行适当的剪枝)可参考这篇文章;
  • 采用的是贪心算法,容易得到局部最优解;

1.3 模型评估的方法

对于模型来说,其在训练集上面的误差称之为训练误差或者经验误差,而在测试集上的误差称之为测试误差

对于我们来说,我们更关心的是模型对于新样本的学习能力,即我们希望通过对已有样本的学习,尽可能的将所有潜在样本的普遍规律学到手,而如果模型对训练样本学的太好,则有可能把训练样本自身所具有的一些特点当做所有潜在样本的普遍特点,这时候我们就会出现过拟合的问题。

模型评估方法: 在机器学习中, 我们通常把样本分为训练集和测试集, 训练集用于训练模型, 测试集用于评估模型。 在样本划分和模型验证的过程中, 存在着不同的抽样方法和验证方法。 HoldoutHoldoutHoldout 检验. HoldoutHoldoutHoldout 检验是最简单也是最直接的验证方法, 它将原始的样本集合随机划分成训练集和验证集两部分。比方说, 我们把样本按照 707070%~303030% 的比例分成两部分, 707070% 的样本用于模型训练; 303030% 的样本用于模型验证, 包括绘制 ROCROCROC 曲线、 计算精确率和召回率等指标来评估模型性能。HoldoutHoldoutHoldout 检验的缺点很明显, 即在验证集上计算出来的最后评估指标与原始分组有很大关系。为了消除随机性, 研究者们引入了“交叉检验”的思想。

二、代码示例

2.1 导入相关包

# In[1]:导包import pandas as pd
import numpy as np
from sklearn.metrics import f1_scoreimport os
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
import warnings
from lightgbm.sklearn import LGBMRegressorfrom sklearn.model_selection import cross_val_score
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.neural_network import MLPRegressor
from xgboost.sklearn import XGBRegressor
from sklearn.metrics import mean_absolute_error,  make_scorer
warnings.filterwarnings("ignore")

2.2 读取数据

reducereducereduce _ memmemmem_usageusageusage 函数通过调整数据类型,帮助我们减少数据在内存中占用的空间。

# In[2]: 读取数据def reduce_mem_usage(df):start_mem = df.memory_usage().sum() / 1024**2 print('Memory usage of dataframe is {:.2f} MB'.format(start_mem))for col in df.columns:col_type = df[col].dtypeif col_type != object:c_min = df[col].min()c_max = df[col].max()if str(col_type)[:3] == 'int':if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:df[col] = df[col].astype(np.int8)elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:df[col] = df[col].astype(np.int16)elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:df[col] = df[col].astype(np.int32)elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:df[col] = df[col].astype(np.int64)  else:if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:df[col] = df[col].astype(np.float16)elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:df[col] = df[col].astype(np.float32)else:df[col] = df[col].astype(np.float64)else:df[col] = df[col].astype('category')end_mem = df.memory_usage().sum() / 1024**2 print('Memory usage after optimization is: {:.2f} MB'.format(end_mem))print('Decreased by {:.1f}%'.format(100 * (start_mem - end_mem) / start_mem))return df
# In[3]:# 读取数据
data = pd.read_csv('D:/Cadabra_tools002/tianqi_file/train.csv')
# 简单预处理
data_list = []
for items in data.values:data_list.append([items[0]] + [float(i) for i in items[1].split(',')] + [items[2]])data = pd.DataFrame(np.array(data_list))
data.columns = ['id'] + ['s_'+str(i) for i in range(len(data_list[0])-2)] + ['label']data = reduce_mem_usage(data)

2.3 简单建模

这里是基于树模型的算法特性,异常值、缺失值处理可以跳过。

注: 以下建模的据集并未构造任何特征,直接使用原特征。本次主要进行模建模调参。

# In[4]: 建模前的预操作from sklearn.model_selection import KFold
# 分离数据集,方便进行交叉验证
X_train = data.drop(['id','label'], axis=1)
y_train = data['label']# 5折交叉验证
folds = 5
seed = 2021
kf = KFold(n_splits=folds, shuffle=True, random_state=seed)

因为树模型中没有 f1−scoref1-scoref1−score 评价指标,所以需要自定义评价指标,在模型迭代中返回验证集 f1−scoref1-scoref1−score 变化情况。

# In[5]:def f1_score_vali(preds, data_vali):labels = data_vali.get_label()preds = np.argmax(preds.reshape(4, -1), axis=0)score_vali = f1_score(y_true=labels, y_pred=preds, average='macro')return 'f1_score', score_vali, True

使用 LightgbmLightgbmLightgbm 进行建模:

# In[6]:"""对训练集数据进行划分,分成训练集和验证集,并进行相应的操作"""
from sklearn.model_selection import train_test_split
import lightgbm as lgb
# 数据集划分
X_train_split, X_val, y_train_split, y_val = train_test_split(X_train, y_train, test_size=0.2)
train_matrix = lgb.Dataset(X_train_split, label=y_train_split)
valid_matrix = lgb.Dataset(X_val, label=y_val)params = {"learning_rate": 0.1,"boosting": 'gbdt',  "lambda_l2": 0.1,"max_depth": -1,"num_leaves": 128,"bagging_fraction": 0.8,"feature_fraction": 0.8,"metric": None,"objective": "multiclass","num_class": 4,"nthread": 10,"verbose": -1,
}"""使用训练集数据进行模型训练"""
model = lgb.train(params, train_set=train_matrix, valid_sets=valid_matrix, num_boost_round=2000, verbose_eval=50, early_stopping_rounds=200,feval=f1_score_vali)

对验证集进行预测:

# In[7]:对验证集进行预测val_pre_lgb = model.predict(X_val, num_iteration=model.best_iteration)
preds = np.argmax(val_pre_lgb, axis=1)
score = f1_score(y_true=y_val, y_pred=preds, average='macro')
print('未调参前lightgbm单模型在验证集上的f1:{}'.format(score))

更进一步的,使用 555 折交叉验证进行模型性能评估:

# In[8]:使用 5折交叉验证进行建模预测"""使用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 = {"learning_rate": 0.1,"boosting": 'gbdt',  "lambda_l2": 0.1,"max_depth": -1,"num_leaves": 128,"bagging_fraction": 0.8,"feature_fraction": 0.8,"metric": None,"objective": "multiclass","num_class": 4,"nthread": 10,"verbose": -1,}model = lgb.train(params, train_set=train_matrix, valid_sets=valid_matrix, num_boost_round=2000, verbose_eval=100, 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)))

三、模型调参

介绍两种调参的方法

3.1 贪心调参

先使用当前对模型影响最大的参数进行调优,达到当前参数下的模型最优化,再使用对模型影响次之的参数进行调优,如此下去,直到所有的参数调整完毕。

这个方法的缺点就是可能会调到局部最优而不是全局最优,但是只需要一步一步的进行参数最优化调试即可,容易理解。

需要注意的是在树模型中参数调整的顺序,也就是各个参数对模型的影响程度,这里列举一下日常调参过程中常用的参数和调参顺序:

  1. maxmaxmax_depthdepthdepth、numleavesnum_leavesnuml​eaves
  2. minminmindatadatadatainininleafleafleaf、minminminchildchildchild_weightweightweight
  3. baggingbaggingbaggingfractionfractionfraction、 featurefeaturefeaturefractionfractionfraction、baggingbaggingbagging_freqfreqfreq
  4. regregreglambdalambdalambda、regregregalphaalphaalpha
  5. minminminsplitsplitsplitgaingaingain
# In[9-1]:
## LGB的参数集合:objective = ['regression', 'regression_l1', 'mape', 'huber', 'fair']num_leaves = [3,5,10,15,20,40, 55]
max_depth = [3,5,10,15,20,40, 55]
bagging_fraction = []
feature_fraction = []
drop_rate = []
# In[9-2]:贪心调参from sklearn.model_selection import cross_val_score
# 调objective
best_obj = dict()
for obj in objective:model = LGBMRegressor(objective=obj)"""预测并计算roc的相关指标"""score = cross_val_score(model, X_train, y_train, cv=5, scoring='f1').mean()best_obj[obj] = score# num_leaves
best_leaves = dict()
for leaves in num_leaves:model = LGBMRegressor(objective=min(best_obj.items(), key=lambda x:x[1])[0], num_leaves=leaves)"""预测并计算roc的相关指标"""score = cross_val_score(model, X_train, y_train, cv=5, scoring='f1').mean()best_leaves[leaves] = score# max_depth
best_depth = dict()
for depth in max_depth:model = LGBMRegressor(objective=min(best_obj.items(), key=lambda x:x[1])[0],num_leaves=min(best_leaves.items(), key=lambda x:x[1])[0],max_depth=depth)"""预测并计算roc的相关指标"""score = cross_val_score(model, X_train, y_train, cv=5, scoring='f1').mean()best_depth[depth] = score

可依次将模型的参数通过上面的方式进行调整优化,并且通过可视化观察在每一个最优参数下模型的得分情况

3.2 网格搜索

sklearnsklearnsklearn 提供 GridSearchCVGridSearchCVGridSearchCV 用于进行网格搜索,只需要把模型的参数输进去,就能给出最优化的结果和参数。相比起贪心调参,网格搜索的结果会更优,但是网格搜索只适合于小数据集,一旦数据的量级上去了,很难得出结果。

同样以 LightgbmLightgbmLightgbm 算法为例,进行网格搜索调参:

# In[10]:网格搜索"""通过网格搜索确定最优参数"""
from sklearn.model_selection import GridSearchCVdef get_best_cv_params(learning_rate=0.1, n_estimators=581, num_leaves=31, max_depth=-1, bagging_fraction=1.0, feature_fraction=1.0, bagging_freq=0, min_data_in_leaf=20, min_child_weight=0.001, min_split_gain=0, reg_lambda=0, reg_alpha=0, param_grid=None):# 设置5折交叉验证cv_fold = KFold(n_splits=5, shuffle=True, random_state=2021)model_lgb = lgb.LGBMClassifier(learning_rate=learning_rate,n_estimators=n_estimators,num_leaves=num_leaves,max_depth=max_depth,bagging_fraction=bagging_fraction,feature_fraction=feature_fraction,bagging_freq=bagging_freq,min_data_in_leaf=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')grid_search = GridSearchCV(estimator=model_lgb, cv=cv_fold,param_grid=param_grid,scoring=f1)grid_search.fit(X_train, y_train)print('模型当前最优参数为:{}'.format(grid_search.best_params_))print('模型当前最优得分为:{}'.format(grid_search.best_score_))
# In[11]:
"""以下代码未运行,耗时较长,请谨慎运行,且每一步的最优参数需要在下一步进行手动更新,请注意""""""
需要注意一下的是,除了获取上面的获取num_boost_round时候用的是原生的lightgbm(因为要用自带的cv)
下面配合GridSearchCV时必须使用sklearn接口的lightgbm。
"""
"""设置n_estimators 为581,调整num_leaves和max_depth,这里选择先粗调再细调"""
lgb_params = {'num_leaves': range(10, 80, 5), 'max_depth': range(3,10,2)}
get_best_cv_params(learning_rate=0.1, n_estimators=581, num_leaves=None, max_depth=None, min_data_in_leaf=20, min_child_weight=0.001,bagging_fraction=1.0, feature_fraction=1.0, bagging_freq=0, min_split_gain=0, reg_lambda=0, reg_alpha=0, param_grid=lgb_params)"""num_leaves为30,max_depth为7,进一步细调num_leaves和max_depth"""
lgb_params = {'num_leaves': range(25, 35, 1), 'max_depth': range(5,9,1)}
get_best_cv_params(learning_rate=0.1, n_estimators=85, num_leaves=None, max_depth=None, min_data_in_leaf=20, min_child_weight=0.001,bagging_fraction=1.0, feature_fraction=1.0, bagging_freq=0, min_split_gain=0, reg_lambda=0, reg_alpha=0, param_grid=lgb_params)"""
确定min_data_in_leaf为45,min_child_weight为0.001 ,下面进行bagging_fraction、feature_fraction和bagging_freq的调参
"""
lgb_params = {'bagging_fraction': [i/10 for i in range(5,10,1)], 'feature_fraction': [i/10 for i in range(5,10,1)],'bagging_freq': range(0,81,10)}
get_best_cv_params(learning_rate=0.1, n_estimators=85, num_leaves=29, max_depth=7, min_data_in_leaf=45, min_child_weight=0.001,bagging_fraction=None, feature_fraction=None, bagging_freq=None, min_split_gain=0, reg_lambda=0, reg_alpha=0, param_grid=lgb_params)"""
确定bagging_fraction为0.4、feature_fraction为0.6、bagging_freq为 ,下面进行reg_lambda、reg_alpha的调参
"""
lgb_params = {'reg_lambda': [0,0.001,0.01,0.03,0.08,0.3,0.5], 'reg_alpha': [0,0.001,0.01,0.03,0.08,0.3,0.5]}
get_best_cv_params(learning_rate=0.1, n_estimators=85, num_leaves=29, max_depth=7, min_data_in_leaf=45, min_child_weight=0.001,bagging_fraction=0.9, feature_fraction=0.9, bagging_freq=40, min_split_gain=0, reg_lambda=None, reg_alpha=None, param_grid=lgb_params)"""
确定reg_lambda、reg_alpha都为0,下面进行min_split_gain的调参
"""
lgb_params = {'min_split_gain': [i/10 for i in range(0,11,1)]}
get_best_cv_params(learning_rate=0.1, n_estimators=85, num_leaves=29, max_depth=7, min_data_in_leaf=45, min_child_weight=0.001,bagging_fraction=0.9, feature_fraction=0.9, bagging_freq=40, min_split_gain=None, reg_lambda=0, reg_alpha=0, param_grid=lgb_params)

由于这段代码还未跑完(执行的时间真的巨长),。。。,有耐心的小伙伴可以去跑一下,我跑了 333~444 小时未果后,手动暂停了(实在是没耐心等待了呜呜呜)

# In[12]:
"""
参数确定好了以后,我们设置一个比较小的learning_rate 0.005,来确定最终的num_boost_round
"""
# 设置5折交叉验证
# cv_fold = StratifiedKFold(n_splits=5, random_state=0, shuffle=True, )
final_params = {'boosting_type': 'gbdt','learning_rate': 0.01,'num_leaves': 29,'max_depth': 7,'objective': 'multiclass','num_class': 4,'min_data_in_leaf':45,'min_child_weight':0.001,'bagging_fraction': 0.9,'feature_fraction': 0.9,'bagging_freq': 40,'min_split_gain': 0,'reg_lambda':0,'reg_alpha':0,'nthread': 6}cv_result = lgb.cv(train_set=lgb_train,early_stopping_rounds=20,num_boost_round=5000,nfold=5,stratified=True,shuffle=True,params=final_params,feval=f1_score_vali,seed=0,)

在实际调整过程中,可先设置一个较大的学习率(上面的例子中 0.10.10.1),通过 LgbLgbLgb 原生的 cvcvcv 函数进行树个数的确定,之后再通过上面的实例代码进行参数的调整优化。

最后针对最优的参数设置一个较小的学习率(例如 0.050.050.05),同样通过 cvcvcv 函数确定树的个数,确定最终的参数。

注: 针对大数据集,上面每一层参数的调整都需要耗费较长时间


总结

这部分只介绍了贪心调参、网格搜索调参,接下来会继续推出用贝叶斯模型来调参的文章!

数据挖掘-Task4:建模与调参相关推荐

  1. 零基础入门金融风控-贷款违约预测-Task4 建模与调参

    此部分为零基础入门金融风控的 Task4 建模调参部分,带你来了解各种模型以及模型的评价和调参策略,欢迎大家后续多多交流. 项目地址 比赛地址 4.1 学习目标 学习在金融分控领域常用的机器学习模型 ...

  2. 零基础入门数据挖掘:Task4 建模与调参

    Stacking 简单来说 stacking 就是当用初始训练数据学习出若干个基学习器后,将这几个学习器的预测结果作为新的训练集,来学习一个新的学习器. 开始实践,总之先导入数据和库 import p ...

  3. Datawhale 零基础入门数据挖掘- 建模与调参

    Task4 建模与调参 此部分为零基础入门数据挖掘之心电图分类的 Task4 建模调参部分,带你来了解各种模型以及模型的评价和调参策略,欢迎大家后续多多交流. 赛题:零基础入门数据挖掘 - 心电图分类 ...

  4. 【算法竞赛学习】心跳信号分类预测-建模与调参

    Task4 建模与调参 此部分为零基础入门数据挖掘之心电图分类的 Task4 建模调参部分,带你来了解各种模型以及模型的评价和调参策略,欢迎大家后续多多交流. 赛题:零基础入门数据挖掘 - 心电图分类 ...

  5. 【算法竞赛学习】金融风控之贷款违约预测-建模与调参

    Task4 建模与调参 此部分为零基础入门金融风控的 Task4 建模调参部分,带你来了解各种模型以及模型的评价和调参策略,欢迎大家后续多多交流. 赛题:零基础入门数据挖掘 - 零基础入门金融风控之贷 ...

  6. 天池大赛-心跳信号分类预测:建模与调参

    比赛地址:零基础入门数据挖掘-心跳信号分类预测 参考资料:由DataWhale开源的学习资料 1 内容介绍 逻辑回归模型: 理解逻辑回归模型: 逻辑回归模型的应用: 逻辑回归的优缺点: 树模型: 理解 ...

  7. 数据竞赛入门-金融风控(贷款违约预测)四、建模与调参

    前言 本次活动为datawhale与天池联合举办,为金融风控之贷款违约预测挑战赛(入门) 比赛地址:https://tianchi.aliyun.com/competition/entrance/53 ...

  8. 建模与调参+模型结果融合

    一.建模与调参 1.线性回归模型 线性回归(Linear Regression)是利用称为线性回归方程的最小平方函数对一个或多个自变量和因变量之间关系进行建模的一种回归分析. 训练模型的过程其实就是根 ...

  9. Datawhale 零基础入门数据挖掘-Task4 建模调参

    本节内容为各种模型以及模型的评价和调参策略. 一.读取数据 import pandas as pd import numpy as np import warnings warnings.filter ...

最新文章

  1. python判断密码是否正确_第一个python程序-判断登陆用户名和密码是否正确
  2. shell编程——sed用法
  3. HGOI 20181103 题解
  4. JQuery 网站换肤功能
  5. socket技术难点
  6. wince驱动异常调试方法(作者:wogoyixikexie@gliet)
  7. flume高可用-balance-配置文件编写
  8. 用C#写MSN机器人
  9. 基本的MySQL操作
  10. php能不能用MyBatis,Mybatis与Ibatis的区别
  11. C++(21)--Astah uml 画C++类图
  12. 二叉树、多叉树子路径遍历
  13. 权限系统设计学习总结(3)——多账户的统一登录
  14. maven的pom文件出现Multiple annotations found at this line...,已解决
  15. Ajax学习笔记-JQuery中的Ajax
  16. 免费的CRM真的免费吗
  17. wpsmac和pc版的区别_Mac系统下金山WPS和微软Office 哪个更好更好用
  18. 数据结构 javascript 描述[Data-Structure described byJavaScript]
  19. 解决手机浏览器无法显示本地html文件
  20. 配置系统初始化失败0 x84b10001当在Windows上安装SQL Server

热门文章

  1. OV10635 color HDR sensor module for Automotive - www.deltavision.io
  2. php将您重定向的次数过多,Laravel路线重定向次数过多
  3. 机器视觉与脑神经科学
  4. 代码洁癖系列(二):命名的艺术
  5. 转让一套基于 Flash 的网页版棋牌平台
  6. ubuntu安装计算器
  7. hp 430 系列安装xp系统问题.net framework 3.5 安装期间遇到问题,安装不上。
  8. 【电气专业知识问答】问:直流系统及其直流充电装置正常运行监视、检查的项目有哪些?
  9. android百度测试,【腾讯百度测试面试题】面试问题:Android… - 看准网
  10. 简单易用的终端工具——NxShell