DATAWHALE-数据挖掘竞赛入门-task4-建模调参
背景
在这次Datawhale的组队学习中,我们主要学习数据竞赛的相关知识,其中task4是有关于建模调参的知识。
建立模型
1.主要模型
- 线性回归模型 ——>线性回归模型知乎专栏
线性回归是一种被广泛应用的回归技术,也是机器学习里面最简单的一个模型,它有很多种推广形式,本质上它是一系列特征的线性组合,在二维空间中,你可以把它视作一条直线,在三维空间中可以视作是一个平面。
- Lasso回归
- Ridge回归
- 决策树模型 ——>决策树模型知乎专栏
- GBDT模型 ——>梯度提升树GBDT知乎专栏
GBDT是一个集成模型,可以看做是很多个基模型的线性相加,其中的基模型就是CART回归树。
- XGBoost模型 ——>XGBoost模型知乎专栏
- LightGBM模型 ——>LightGBM模型知乎专栏
2.模型性能验证
- 评价函数与目标函数
- 交叉验证方法
- 留一验证方法
- 引入时间序列验证
- 绘制学习率曲线
- 绘制验证曲线
调参方法
- 贪心调参方法
- 网格调参方法
- 贝叶斯调参方法
相关代码
代码的Notebooks链接 : 点击这里查看jupyter notebook
本章的学习手册由小雨姑娘编写,首先小雨写了一个优化内存占用的函数,主要是优化各种变量的数据类型。具体代码如下:
def reduce_mem_usage(df):
""" iterate through all the columns of a dataframe and modify the data type
to reduce memory usage.
"""
start_mem = df.memory_usage().sum()
print('Memory usage of dataframe is {:.2f} MB'.format(start_mem/(1024*1024)))
for col in df.columns:
col_type = df[col].dtype
if 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)
elif str(col_type)[:5] == 'float':
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()
print('Memory usage after optimization is: {:.2f} MB'.format(end_mem/(1024*1024)))
print('Decreased by {:.1f}%'.format(100 * (start_mem - end_mem) / start_mem))
return df
用这个函数处理一下这次二手车的训练集,缩小了72.6%的内存占用,效果不错。
Memory usage of dataframe is 35.48 MB
Memory usage after optimization is: 9.73 MB
Decreased by 72.6%
接着,小雨建立了一个连续型变量列表,剔除了一些离散变量,具体剔除依据不太清楚,我感觉还有一些变量也是离散的,这个还要再研究一下。
continuous_feature_names = [x for x in train.columns if x not in ['price','brand','model','brand']]
然后,小雨简单做了做数据清洗(精细的话还得用特征工程的知识,参考上一章),并最终确定了用于训练的训练集与标签。
sample_feature = train.dropna().replace('-', 0).reset_index(drop=True) # dropna 只要有一个null就删除,how参数可以设置any默认或all
sample_feature['notRepairedDamage'] = sample_feature['notRepairedDamage'].astype(np.float32)
train_data = sample_feature[continuous_feature_names + ['price']]
train_X = train_data[continuous_feature_names]
train_y = train_data['price']
做好上述准备后,可以用一个最基本的模型——线型回归模型来试一试效果。这里调用了sklearn的库函数进行拟合。
from sklearn.linear_model import LinearRegression
model = LinearRegression(normalize=True)
model = model.fit(train_X, train_y)
通过model.intercept_可以查看截距,而model.coef_可以查看各个变量前的权重(斜率)。
但是直接这么回归效果并不好,它的MAE高达2600。因此小雨通过研究预测值的分布推断出训练前最好对预测值进行log变换,“因为预测值是长尾分布,很多模型都假设数据误差项符合正态分布,而长尾分布的数据违背了这一假设”。在这里我有个疑问,数据误差项的分布与预测值分布之间具体有什么联系,我不太清楚,还需要研究一下。
那么如果按照小雨所说作log变换后
train_y_ln = np.log(train_y + 1)
训练一下
model = model.fit(train_X, train_y_ln)
最后得出来的MAE是987.6,可见降低了很多。然后我抱着试一试的态度,向天池提交了一下这个模型的预测结果,最后得出来的MAE是974,更训练集差别也不多。
总结
由于时间原因,目前这篇文章代码部分只展示了一部分成果,还待进一步更新。