根据天池项目建模调参总结而出
机器学习算法的基础知识详见:
1.线性回归模型
- 将训练集分为train_X特征变量,train_y结果变量
train_X = train[continuous_feature_names]
train_y = train['price']
- 用sklearn进行线性模型训练
from sklearn.linear_model import LinearRegression
model = LinearRegression(normalize=True)
model = model.fit(train_X, train_y)
sorted(dict(zip(continuous_feature_names,model.coef_)).items(),key=lambda x:x[1],reverse=True)
- 将train_y与模型预测出的值进行散点分布对比
plt.scatter(x=train_X['v_9'][subsample_index],y=train_y[subsample_index],color='black')#真实y值
plt.scatter(x=train_X['v_9'][subsample_index],y=model.predict(train_X.loc[subsample_index]),color='blue')#训练后的y值
image.png
- 可见真实值和训练值相差较大,因此模型存在问题。
price是长尾分布,因为模型多数假设为正态分布,可以试着将其转换成正态分布
train_y_ln = np.log((train_y)+1)
sns.distplot(train_y_ln)
- 将train_y与新的模型预测值进行散点图分布对比
model = model.fit(train_X,train_y_ln)
sorted(dict(zip(continuous_feature_names,model.coef_)).items(),key=lambda x:x[1],reverse=True)
plt.scatter(x=train_X['v_9'][subsample_index],y=train_y[subsample_index],color='black')
plt.scatter(x=train_X['v_9'][subsample_index],y=np.exp(model.predict(train_X.loc[subsample_index])),color='blue')
image.png
再次进行可视化,发现预测结果与真实值较为接近,且未出现异常状况
2.交叉验证
在进行训练时,通常会分为三组,训练集、验证集、测试集。测试集不参加训练,只测试训练结果。训练集和验证集是从训练数据中取出,为了使验证结果更加有效,使用交叉验证。K折交叉验证就是将训练数据分为K层,其中每一层有一次机会作为验证集,其他作为训练集,循环K次,返回评分数组,求该数组的均值。
cross_val_score(estimator-训练对象如model, X, y=None, scoring=None调用方法, cv=None-K折, n_jobs=1, verbose=0, fit_params=None, pre_dispatch=‘2*n_jobs’)
因为对价格标签做了对数变化,想对比变换前和变换后的得分,这时因为两者的数值区间不同,因此需要对未做变换的y和yhat预测进行log转换到同一个数值区间中,在进行比较。因此需要对MSE进行自定义log方法。
- log变换前MSE得分(error:1.36)
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
scores = cross_val_score(model,X=train_X,y=train_y,cv=5,scoring=make_scorer(log_transfer(mean_absolute_error)))
print('AVG:', np.mean(scores))
个人理解:make_scorer构造评估函数,cross_val_score传两个值给scoring参数,一个是y,一个是根据model后的y即yhat。
log_transfer的目的是对MSE方法进行改造,改成y和yhat均为log后的。
- log变换后MSE得分(error:0.19)
scores = cross_val_score(model,X=train_X,y=train_y_ln,cv=5,scoring=make_scorer(mean_absolute_error))
print('AVG:', np.mean(scores))
可以看出变换后效果还是有很大提升。
注意:考虑到事实上我们并不能通过2018年数据预测2017数据,因此可以采用时间顺序对数据进行分隔,这里采用的是靠前时间的4/5样本当作训练集,靠后时间的1/5当作验证集。
split_point = len(sample_feature) // 5 * 4#分成4/5份
model = model.fit(train_X, train_y_ln)
mean_absolute_error(val_y_ln, model.predict(val_X))
#mean_absolute_error(y_true验证集的y,y_pre验证集x放入训练模型得出的y)
#mean_absolute_error(y_true验证集的y,y_pre验证集x放入训练模型得出的y)
3. 绘制学习曲线
学习曲线:一种用来判断训练模型的一种方法,通过观察绘制出来的学习曲线图,我们可以比较直观的了解到我们的模型处于一个什么样的状态,如:过拟合(overfitting)或欠拟合(underfitting)
(1)观察左上图,训练集准确率与验证集准确率收敛,但是两者收敛后的准确率远小于我们的期望准确率(上面那条红线),所以由图可得该模型属于欠拟合(underfitting)问题。由于欠拟合,所以我们需要增加模型的复杂度,比如,增加特征、增加树的深度、减小正则项等等,此时再增加数据量是不起作用的。
(2)观察右上图,训练集准确率高于期望值,验证集则低于期望值,两者之间有很大的间距,误差很大,对于新的数据集模型适应性较差,所以由图可得该模型属于过拟合(overfitting)问题。由于过拟合,所以我们降低模型的复杂度,比如减小树的深度、增大分裂节点样本数、增大样本数、减少特征数等等。
(3)一个比较理想的学习曲线图应当是:低偏差、低方差,即收敛且误差小。
未完待续?????稍后补充
4.多模型对比
嵌入特征选择直接在训练时进行特征筛选,嵌入式选择最常用的是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)]
result
参考:
https://tianchi.aliyun.com/notebook-ai/detail?spm=5176.12586969.1002.12.1cd8593auEGaCE&postId=95460源代码
数据建模、调参、模型融合需要大量基础知识点,因此需要时间整理,所以本项目停更一段时间~感谢!
网友评论