欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

datawhale 学习笔记——建模调参入门

程序员文章站 2022-06-04 12:46:34
...

前言

居然又拖到了最后一天才开始打卡,。果然 ddl 是第一生产力。

放上这次的教程链接:Datawhale 零基础入门数据挖掘-Task4 建模调参

看标题就知道这次的这次的内容是建模和调参。虽然说是零基础入门系列,但是这次的教程对真的零基础的人来讲并不是很友好,还是需要很多前置知识的。主要是机器学习模型方面的教程,教程里给出了几篇作者写的文章。个人感觉需要一定门槛,如果看不懂建议参考其他的。

这次打卡还是按照教程走一遍,先梳理一下主要内容的结构。这次任务主体分为五大部分:

  • 线性回归模型
  • 模型验证
  • 嵌入式特征选择(上一次任务没讲的)
  • 模型对比
  • 模型调参

开始之前,先把数据准备好。

还是依旧要先读取数据,不过这次任务的读取数据有两点不同:

  1. 读取的数据是上一次任务中做特征工程时生成的,没有的话需要运行一下 task3 的代码生成一下
  2. 教程中作者写了一个 reduce_mem_usage() 函数。通过转换数据的存储类型来达到节约内存空间的目的。

代码就不全粘贴了,没什么可说的,后面需要用到的变量是 sample_featurecontinuous_feature_names

sample_feature = reduce_mem_usage(pd.read_csv('data_for_tree.csv'))
continuous_feature_names = [x for x in sample_feature.columns if x not in ['price','brand','model','brand']]

需要根据所选特征构造训练集。

# 特征处理,删除空的数据并重置数据下标和类型
sample_feature = sample_feature.dropna().replace('-', 0).reset_index(drop=True)
sample_feature['notRepairedDamage'] = sample_feature['notRepairedDamage'].astype(np.float32)
# 构造训练数据
train = sample_feature[continuous_feature_names + ['price']]
train_X = train[continuous_feature_names]
train_y = train['price']

线性回归模型

线性回归模型就是简单的线性关系,类似于 a1x1+a2x2+a3x3+...+anxn+b=ya_1x_1 + a_2x_2 + a_3x_3 + ... + a_nx_n + b = y

就是说,每个自变量 xix_i 的单位变化都会导致因变量 yy 的成比例的变化(aixia_ix_i

这里使用的是 sklearn 库下的 LinearRegression 函数。

# 简单的线性建模
from sklearn.linear_model import LinearRegression
model = LinearRegression(normalize=True)
model = model.fit(train_X, train_y)
print('intercept:'+ str(model.intercept_))
print(sorted(dict(zip(continuous_feature_names, model.coef_)).items(), key=lambda x:x[1], reverse=True))

运行结果:

intercept:-111820.66151155639
[(‘v_6’, 3372669.6439296836), (‘v_8’, 701432.2110340319), (‘v_9’, 169509.42711357534), (‘v_7’, 32757.63135064817), (‘v_12’, 23807.649529600818), (‘v_3’, 19739.216689565477), (‘v_11’, 13163.940983386958), (‘v_13’, 11963.46498465866), (‘v_10’, 3659.757920045777), (‘gearbox’, 878.481625388411), (‘fuelType’, 372.24870228828286), (‘bodyType’, 185.9175590029288), (‘city’, 46.98275955422143), (‘power’, 30.882991521559063), (‘brand_price_median’, 0.46125248465967494), (‘brand_amount’, 0.14337558626062372), (‘brand_price_std’, 0.13126146237474134), (‘brand_price_max’, 0.01264373865111078), (‘used_time’, 0.0006779416045904323), (‘SaleID’, 5.0161735988244534e-05), (‘train’, 3.982800990343094e-06), (‘seller’, -5.443580448627472e-06), (‘offerType’, -6.388872861862183e-06), (‘brand_price_sum’, -1.969811652902229e-05), (‘name’, -0.00024808160266330667), (‘brand_price_average’, -0.22234169615526606), (‘brand_price_min’, -1.9643720815997738),
(‘power_bin’, -56.46399500590243), (‘v_14’, -340.80766284241344), (‘kilometer’, -372.8800824482724), (‘notRepairedDamage’, -490.61611815679447), (‘v_0’, -2054.722036477167), (‘v_5’, -4343.72864602462), (‘v_4’, -15543.94705998868), (‘v_2’, -29430.03630720955), (‘v_1’, -45074.18455513423)]

这里我得到的结果跟教程稍微不同,猜测特征工程部分做的操作不完全一样。

可视化可以发现,预测目标拟合得并不好。由于很多模型都假设预测目标是正态分布的,因此后面对预测的目标 price 做了一个 log 操作。可视化后发现效果还不错。

v_9 单一特征进行预测,不取 log 和 取 log 的对比如下:

datawhale 学习笔记——建模调参入门

datawhale 学习笔记——建模调参入门

模型验证

五折交叉验证

对模型进行五折交叉验证,这里需要说明的是 cross_val_score 函数,它可以将数据分为训练集和测试集,并返回每次验证时模型的得分情况。

# 交叉验证
from sklearn.model_selection import cross_val_score
from sklearn.metrics import mean_absolute_error,  make_scorer

def log_transfer(func):
    def wrapper(y, yhat):
        result = func(np.log(y), np.nan_to_num(np.log(yhat)))
        return result
    return wrapper
# 使用线性模型对未经过 log 变换的数据进行预测
scores = cross_val_score(model, X=train_X, y=train_y_org, verbose=1, cv = 5, scoring=make_scorer(log_transfer(mean_absolute_error)))
print('AVG-org:', np.mean(scores))
# 使用线性模型对 log 变换后的数据进行预测
scores = cross_val_score(model, X=train_X, y=train_y, verbose=1, cv = 5, scoring=make_scorer(log_transfer(mean_absolute_error)))
print('AVG:', np.mean(scores))

运行结果如下:

[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done 5 out of 5 | elapsed: 1.1s finished
AVG-org: 1.3684950216832068
[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done 5 out of 5 | elapsed: 0.7s finished
AVG: 0.02487489588467453

可以看到,做 log 处理后,模型的效果提升了两个数量级。

模拟真实环境

需要说明的一点是,有时数据是存在时序性的,我们不能拥有上帝视角预测未来的数据。因此划分验证集时,需要考虑数据的时序性,模拟真实环境。即前一部分是训练集,后一部分是验证集,验证集后不应再有训练集。这是作者当时直播强调的一点,不过在这里,并没有什么影响。

绘制学习率曲线

这里利用了教程里的 plot_learning_curve 函数来绘制,其中最主要的是调用了 learning_curve 来获得测试和训练时的得分。

plot_learning_curve(LinearRegression(), 'Liner_model', train_X[:1000], train_y[:1000], ylim=(0.0, 0.5), cv=5, n_jobs=1)  
plt.show()

运行结果:

datawhale 学习笔记——建模调参入门

嵌入式特征选择

上一次任务中讲的,特征选择一共有三种。前两种是过滤式和包裹式,他们在做特征选择时,可以明显的与训练过程分离开。但嵌入式特征选择是边训练便选择,典型的方法是L1正则化与L2正则化。(以前只知道L1、L2正则化,但并不知道这是属于嵌入式特征选择,。孤陋寡闻了)

线性回归模型加入两种正则化方法后,就分别变成了岭回归与Lasso回归。

代码粘贴一下:

from sklearn.linear_model import LinearRegression
from sklearn.linear_model import Ridge
from sklearn.linear_model import Lasso

models = [LinearRegression(),
          Ridge(),
          Lasso()]

result = dict()
for model in models:
    model_name = str(model).split('(')[0]
    scores = cross_val_score(model, X=train_X, y=train_y_ln, verbose=0, cv = 5, scoring=make_scorer(mean_absolute_error))
    result[model_name] = scores
    print(model_name + ' is finished')

result = pd.DataFrame(result)
result.index = ['cv' + str(x) for x in range(1, 6)]
print(result)

运行结果:

		LinearRegression     Ridge     Lasso
cv1          0.190851  0.194948  0.383810
cv2          0.193835  0.197714  0.382179
cv3          0.194196  0.198252  0.383611
cv4          0.191812  0.195694  0.380331
cv5          0.195868  0.199817  0.383783

这里简单介绍一下 L1 和 L2 的区别,就不粘贴教程里的可视化代码了。

L1 的惩罚项是权值的绝对值之和,因此学到的权值参数小的会尽可能趋向于0,大的会尽可能变大,最后会得到一个稀疏矩阵,0 很多;L2 的惩罚项是权值的平方和,因此权值的绝对值会尽可能小,这样平方求和后的值就会变小,最后得到一个所有权值都向 0 靠近的参数矩阵。

模型对比

这部分教程介绍的比较少,主要是做了一个简单模型性能的对比,包括线性模型、决策树模型、随机森林、梯度提升树、多层感知机、XGBoost 和 LGBM。

运行教程代码的结果:

datawhale 学习笔记——建模调参入门

可以明显看出来,随机森林、XGBoost 和 LGBM的效果比较好。

模型调参

主要有三种方式:贪心、网格和贝叶斯。

需要提前设定好可能的参数集合。

这部分代码就不粘贴了,主要记录一下我的理解。

贪心调参

主要思路是遍历每一个参数,使用其中效果最好的参数继续训练模型,搜索下一个参数。

网格搜索

教程里使用的是 sklearn.model_selection 库里的 GridSearchCV 函数。网格调参是一种穷举搜索方法,遍历所有的参数组合,选出最好的那一组。

贝叶斯调参

教程中使用的是 BayesianOptimization 函数来做的。

贝叶斯调参的方法是一种自动调参的方式。前两种调参的方法运行效率比较低,运行时间很慢。贝叶斯的方法在于,他会建立一个概率模型,基于以前的评估结果,来最小化这个模型值。简而言之,在尝试下一组参数时,会参考以前的参数结果,避免做无用功。

最后

不得不说,还是高估了自己的自控力,拖延症真的得治呀。

不过这次学习还是学到了很多东西,虽然很多东西没有深入了解。最让人兴奋的还是大佬的各种可视化操作,看着各种数据被各种可视化出来,感觉好TM神奇。

好好学习,天天向上。又是瞎捅咕的一天,没干毕设的事内心还是有点愧疚。

相关标签: 比赛