Datawhale task4打卡——二手车价格预测

  • 1. 线性回归模型
    • 1.1 *特征要求(易忽略)
    • 1.2 *处理长尾分布(易忽略)
  • 2. 模型性能验证
    • 2.1 目标函数
    • 2.2 交叉验证
      • 2.2.1 保留交叉验证(hand-out cross validation)
      • 2.2.2 N折交叉验证
    • 2.3 留一验证(leave one out, LOO)
    • 2.4 *针对时间序列问题的验证
    • 2.5 *学习率曲线绘制
    • 2.6 *验证曲线绘制
  • 3. 特征选择
    • 3.1 LASSO
    • 3.2 Ridge
    • 3.3 决策树
  • 4. *模型对比(新技能)
    • 4.1 常用线性模型&嵌入式选择
    • 4.2 常用非线性模型
  • 5. 调参
    • 5.1 *[贪心法](https://www.jianshu.com/p/ab89df9759c8)
    • 5.2 [网格搜参](https://blog.csdn.net/weixin_43172660/article/details/83032029)
    • 5.3 [贝叶斯搜参](https://blog.csdn.net/linxid/article/details/81189154)
  • 6. 模型原理
    • 6.1 [线性回归](https://zhuanlan.zhihu.com/p/49480391)
    • 6.2 [决策树](https://zhuanlan.zhihu.com/p/65304798)
    • 6.3 [GBDT](https://zhuanlan.zhihu.com/p/45145899)
    • 6.4 [XGBoost](https://zhuanlan.zhihu.com/p/86816771)
    • 6.5 [LightGBM](https://zhuanlan.zhihu.com/p/89360721)
  • 7. 推荐教材

学习参考: datawhale学习笔记task4

代码风格非常棒,简明扼要

数据载入

import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings('ignore')
  • 新技能: reduce_mem_usage 函数通过调整数据类型,帮助我们减少数据在内存中占用的空间
def reduce_mem_usage(df):""" iterate through all the columns of a dataframe and modify the data typeto reduce memory usage.        """start_mem = df.memory_usage().sum() 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() 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
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']

1. 线性回归模型

建模三段论

from sklearn.linear_model import LinearRegression
model = LinearRegression(normalize=True)
model = model.fit(train_X, train_y)

查看训练的线性回归模型的截距(intercept)

'intercept:'+ str(model.intercept_)

权重(coef)

  • 这里的代码风格很棒!
sorted(dict(zip(continuous_feature_names, model.coef_)).items(), key=lambda x:x[1], reverse=True)

1.1 *特征要求(易忽略)

1.2 *处理长尾分布(易忽略)

对呈现长尾分布的标签进行log(1+x)处理

随机采样分析

from matplotlib import pyplot as pltsubsample_index = np.random.randint(low=0, high=len(train_y), size=50)

绘制特征v_9的值与标签的散点图,图片发现模型的预测结果(蓝色点)与真实标签(黑色点)的分布差异较大,且部分预测值出现了小于0的情况,说明我们的模型存在一些问题

plt.scatter(train_X['v_9'][subsample_index], train_y[subsample_index], color='black')
plt.scatter(train_X['v_9'][subsample_index], model.predict(train_X.loc[subsample_index]), color='blue')
plt.xlabel('v_9')
plt.ylabel('price')
plt.legend(['True Price','Predicted Price'],loc='upper right')
print('The predicted price is obvious different from true price')
plt.show()

通过作图我们发现数据的标签(price)呈现长尾分布,不利于我们的建模预测。
原因是很多模型都假设数据误差项符合正态分布,而长尾分布的数据违背了这一假设。

参考博客:https://blog.csdn.net/Noob_daniel/article/details/76087829

import seaborn as sns
print('It is clear to see the price shows a typical exponential distribution')
plt.figure(figsize=(15,5))
plt.subplot(1,2,1)
sns.distplot(train_y)
plt.subplot(1,2,2)
sns.distplot(train_y[train_y < np.quantile(train_y, 0.9)])

  • *在这里我们对标签进行了log(x+1)变换,使标签贴近于正态分布(新技能)
train_y_ln = np.log(train_y + 1)
import seaborn as sns
print('The transformed price seems like normal distribution')
plt.figure(figsize=(15,5))
plt.subplot(1,2,1)
sns.distplot(train_y_ln)
plt.subplot(1,2,2)
sns.distplot(train_y_ln[train_y_ln < np.quantile(train_y_ln, 0.9)])

model = model.fit(train_X, train_y_ln)print('intercept:'+ str(model.intercept_))
sorted(dict(zip(continuous_feature_names, model.coef_)).items(), key=lambda x:x[1], reverse=True)


再次进行可视化,发现预测结果与真实值较为接近,且未出现异常状况

plt.scatter(train_X['v_9'][subsample_index], train_y[subsample_index], color='black')
plt.scatter(train_X['v_9'][subsample_index], np.exp(model.predict(train_X.loc[subsample_index])), color='blue')
plt.xlabel('v_9')
plt.ylabel('price')
plt.legend(['True Price','Predicted Price'],loc='upper right')
print('The predicted price seems normal after np.log transforming')
plt.show()

2. 模型性能验证

2.1 目标函数

2.2 交叉验证

2.2.1 保留交叉验证(hand-out cross validation)

随机将训练样本集分成训练集(training set)和交叉验证集(cross validation
set),比如分别占70%,30%。然后使用模型在训练集上学习得到假设。最后使用交叉验证集对假设进行验证,看预测的是否准确,选择具有误差小的模型。

2.2.2 N折交叉验证

以下引用自:知乎
适用场景:

  • 数据集较小

结果:

  • 可以选择平均N次训练的模型参数
  • 或者用N次结果中validation error最小的那个模型参数

    使用线性回归模型,对未处理标签的特征数据进行五折交叉验证
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 resultreturn wrapper
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))

使用线性回归模型,对处理过标签的特征数据进行五折交叉验证

scores = cross_val_score(model, X=train_X, y=train_y_ln, verbose=1, cv = 5, scoring=make_scorer(mean_absolute_error))

print('AVG:', np.mean(scores))


超喜欢下面的代码风格,可以直接看每一个fold的情况:

scores = pd.DataFrame(scores.reshape(1,-1))
scores.columns = ['cv' + str(x) for x in range(1, 6)]
scores.index = ['MAE']
scores

2.3 留一验证(leave one out, LOO)

只留下一个样本来验证模型的准确性

2.4 *针对时间序列问题的验证

但在事实上,由于我们并不具有预知未来的能力,五折交叉验证在某些与时间相关的数据集上反而反映了不真实的情况。通过2018年的二手车价格预测2017年的二手车价格,这显然是不合理的,

因此我们还可以采用时间顺序对数据集进行分隔。在本例中,我们选用靠前时间的4/5样本当作训练集,靠后时间的1/5当作验证集,最终结果与五折交叉验证差距不大

import datetimesample_feature = sample_feature.reset_index(drop=True)
split_point = len(sample_feature) // 5 * 4train = sample_feature.loc[:split_point].dropna()
val = sample_feature.loc[split_point:].dropna()train_X = train[continuous_feature_names]
train_y_ln = np.log(train['price'] + 1)
val_X = val[continuous_feature_names]
val_y_ln = np.log(val['price'] + 1)model = model.fit(train_X, train_y_ln)
mean_absolute_error(val_y_ln, model.predict(val_X))

2.5 *学习率曲线绘制

from sklearn.model_selection import learning_curve, validation_curvedef plot_learning_curve(estimator, title, X, y, ylim=None, cv=None,n_jobs=1, train_size=np.linspace(.1, 1.0, 5 )):  plt.figure()  plt.title(title)  if ylim is not None:  plt.ylim(*ylim)  plt.xlabel('Training example')  plt.ylabel('score')  train_sizes, train_scores, test_scores = learning_curve(estimator, X, y, cv=cv, n_jobs=n_jobs, train_sizes=train_size, scoring = make_scorer(mean_absolute_error))  train_scores_mean = np.mean(train_scores, axis=1)  train_scores_std = np.std(train_scores, axis=1)  test_scores_mean = np.mean(test_scores, axis=1)  test_scores_std = np.std(test_scores, axis=1)  plt.grid()#区域  plt.fill_between(train_sizes, train_scores_mean - train_scores_std,  train_scores_mean + train_scores_std, alpha=0.1,  color="r")  plt.fill_between(train_sizes, test_scores_mean - test_scores_std,  test_scores_mean + test_scores_std, alpha=0.1,  color="g")  plt.plot(train_sizes, train_scores_mean, 'o-', color='r',  label="Training score")  plt.plot(train_sizes, test_scores_mean,'o-',color="g",  label="Cross-validation score")  plt.legend(loc="best")  return plt
plot_learning_curve(LinearRegression(), 'Liner_model', train_X[:1000], train_y_ln[:1000], ylim=(0.0, 0.5), cv=5, n_jobs=1)

2.6 *验证曲线绘制

3. 特征选择

3.1 LASSO

3.2 Ridge

3.3 决策树

4. *模型对比(新技能)

train = sample_feature[continuous_feature_names + ['price']].dropna()train_X = train[continuous_feature_names]
train_y = train['price']
train_y_ln = np.log(train_y + 1)

4.1 常用线性模型&嵌入式选择

嵌入式特征选择在学习器训练过程中自动地进行特征选择。嵌入式选择最常用的是L1正则化与L2正则化。在对线性回归模型加入两种正则化方法后,他们分别变成了岭回归与Lasso回归。

from sklearn.linear_model import LinearRegression
from sklearn.linear_model import Ridge
from sklearn.linear_model import Lassomodels = [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] = scoresprint(model_name + ' is finished')

对三种方法的效果对比(这种一步到位的对比方式真是酷毙了)

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


*可视化权重(新技能)

model = LinearRegression().fit(train_X, train_y_ln)
print('intercept:'+ str(model.intercept_))
sns.barplot(abs(model.coef_), continuous_feature_names)

L2正则化在拟合过程中通常都倾向于让权值尽可能小,最后构造一个所有参数都比较小的模型

因为一般认为参数值小的模型比较简单,能适应不同的数据集,也在一定程度上避免了过拟合现象。
可以设想一下对于一个线性回归方程,若参数很大,那么只要数据偏移一点点,就会对结果造成很大的影响;但如果参数足够小,数据偏移得多一点也不会对结果造成什么影响,专业一点的说法是『抗扰动能力强』

岭回归

model = Ridge().fit(train_X, train_y_ln)
print('intercept:'+ str(model.intercept_))
sns.barplot(abs(model.coef_), continuous_feature_names)

L1正则化有助于生成一个稀疏权值矩阵,进而可以用于特征选择。如下图,我们发现power与userd_time特征非常重要。

model = Lasso().fit(train_X, train_y_ln)
print('intercept:'+ str(model.intercept_))
sns.barplot(abs(model.coef_), continuous_feature_names)


除此之外,决策树通过信息熵或GINI指数选择分裂节点时,优先选择的分裂特征也更加重要,这同样是一种特征选择的方法。XGBoost与LightGBM模型中的model_importance指标正是基于此计算的

4.2 常用非线性模型

from sklearn.linear_model import LinearRegression
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 lightgbm.sklearn import LGBMRegressormodels = [LinearRegression(),DecisionTreeRegressor(),RandomForestRegressor(),GradientBoostingRegressor(),MLPRegressor(solver='lbfgs', max_iter=100), XGBRegressor(n_estimators = 100, objective='reg:squarederror'), LGBMRegressor(n_estimators = 100)]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] = scoresprint(model_name + ' is finished')

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

5. 调参

以lightgbm为例:

## 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 = []

5.1 *贪心法

best_obj = dict()
for obj in objective:model = LGBMRegressor(objective=obj)score = np.mean(cross_val_score(model, X=train_X, y=train_y_ln, verbose=0, cv = 5, scoring=make_scorer(mean_absolute_error)))best_obj[obj] = scorebest_leaves = dict()
for leaves in num_leaves:model = LGBMRegressor(objective=min(best_obj.items(), key=lambda x:x[1])[0], num_leaves=leaves)score = np.mean(cross_val_score(model, X=train_X, y=train_y_ln, verbose=0, cv = 5, scoring=make_scorer(mean_absolute_error)))best_leaves[leaves] = scorebest_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)score = np.mean(cross_val_score(model, X=train_X, y=train_y_ln, verbose=0, cv = 5, scoring=make_scorer(mean_absolute_error)))best_depth[depth] = score
sns.lineplot(x=['0_initial','1_turning_obj','2_turning_leaves','3_turning_depth'], y=[0.143 ,min(best_obj.values()), min(best_leaves.values()), min(best_depth.values())])

5.2 网格搜参

查看最优参数

from sklearn.model_selection import GridSearchCVparameters = {'objective': objective , 'num_leaves': num_leaves, 'max_depth': max_depth}
model = LGBMRegressor()
clf = GridSearchCV(model, parameters, cv=5)
clf = clf.fit(train_X, train_y)clf.best_params_
model = LGBMRegressor(objective='regression',num_leaves=55,max_depth=15)
np.mean(cross_val_score(model, X=train_X, y=train_y_ln, verbose=0, cv = 5, scoring=make_scorer(mean_absolute_error)))

5.3 贝叶斯搜参

from bayes_opt import BayesianOptimizationdef rf_cv(num_leaves, max_depth, subsample, min_child_samples):val = cross_val_score(LGBMRegressor(objective = 'regression_l1',num_leaves=int(num_leaves),max_depth=int(max_depth),subsample = subsample,min_child_samples = int(min_child_samples)),X=train_X, y=train_y_ln, verbose=0, cv = 5, scoring=make_scorer(mean_absolute_error)).mean()return 1 - valrf_bo = BayesianOptimization(rf_cv,{'num_leaves': (2, 100),'max_depth': (2, 100),'subsample': (0.1, 1),'min_child_samples' : (2, 100)}
)

开始搜参

rf_bo.maximize()

查看loss

1 - rf_bo.max['target']

6. 模型原理

6.1 线性回归

6.2 决策树

6.3 GBDT

6.4 XGBoost

6.5 LightGBM

7. 推荐教材

a. 机器学习
b. 统计学习方法
c. Python大战机器学习
d. 面向机器学习的特征工程
e. 数据科学家访谈录

Datawhale task4打卡——二手车价格预测相关推荐

  1. Datawhale task3打卡——二手车价格预测

    Datawhale task3打卡--二手车价格预测 1. 异常处理(*易忽略) 1.1 通过箱线图(或 3-Sigma)分析删除异常值 1.2 BOX-COX 转换(处理有偏分布) 1.3 长尾截断 ...

  2. 【组队学习】【24期】河北邀请赛(二手车价格预测)

    河北邀请赛(二手车价格预测) 开源内容: https://github.com/datawhalechina/team-learning-data-mining/tree/master/SecondH ...

  3. 基于二手车价格预测——特征工程

    特征工程 特征工程 分析: 第一步:异常值处理 箱型图法: 第二步:特征构造 第三步:数据分桶 数据分桶详解 删除不需要的数据 特征归一化 总结--特征 1.特征构造: 2.异常类型处理 3.构造新特 ...

  4. 二手车价格预测task03:特征工程

    二手车价格预测task03:特征工程 1.学习了operator模块operator.itemgetter()函数 2.学习了箱线图 3.了解了特征工程的方法 (内容介绍) 4.敲代码学习,加注解 以 ...

  5. 二手车价格预测--EDA

    二手车价格预测--EDA 二. EDA-数据探索性分析分析 2.1 EDA 目标 2.2 内容介绍 2.3 代码实例 2.3.1 导入函数工具包 2.3.2 载入数据: 所有特征集均脱敏处理(方便大家 ...

  6. 数据挖掘二手车价格预测 Task05:模型融合

    模型融合是kaggle等比赛中经常使用到的一个利器,它通常可以在各种不同的机器学习任务中使结果获得提升.顾名思义,模型融合就是综合考虑不同模型的情况,并将它们的结果融合到一起.模型融合主要通过几部分来 ...

  7. 数据挖掘-二手车价格预测 Task04:建模调参

    数据挖掘-二手车价格预测 Task04:建模调参 模型调参部分 利用xgb进行五折交叉验证查看模型的参数效果 ## xgb-Model xgr = xgb.XGBRegressor(n_estimat ...

  8. 二手车价格预测数据探索

    二手车价格预测数据探索 1.赛题理解 [类型]属于回归问题. [数据字段] 训练数据字段: 字段名字 含义 类型 name 汽车编码 int regDate 汽车注册时间 int model 车型编码 ...

  9. Python二手车价格预测(二)—— 模型训练及可视化

    系列文章目录 一.Python数据分析-二手车数据获取用于机器学习二手车价格预测 二.Python二手车价格预测(一)-- 数据处理 文章目录 系列文章目录 前言 一.明确任务 二.模型训练 1.引入 ...

最新文章

  1. Docker 1.3.2发布:修复重大安全问题
  2. [译]Effective Kotlin系列之探索高阶函数中inline修饰符(三)
  3. 《C++ Primer》13.1.6节练习(部分)
  4. 第十八期:专家认为对“人工智能+教育”应持审慎态度
  5. js字符串转数字(小数),数字转字符串
  6. 计算机网络学习笔记-1.2.2OSI参考模型(1)
  7. 如何在Spring框架中使用RMI技术
  8. 计算机组成原理微指令cpth,计算机组成原理(西安理工大学)实验二 CPTH模型机综合实验——微控制器实验.doc...
  9. 软考软件设计师下午真题-面向对象的程序设计与实现-组合设计模式(2011年上半年试题六))Java代码讲解
  10. 软件项目的需求变更及对策
  11. 利用牛顿迭代公式开方
  12. 分享你喜欢的杀毒软件
  13. Zabbix5.0监控CenterOS(RPM版)
  14. 小米手机显示流量数据连接到服务器,小米手机流量总不稳定,这三项设置可能你会用到...
  15. django html 插入网页背景图片
  16. 人工智能调度如何改变现场服务行业
  17. 统一社会信用代码=营业执照注册号 + 营业执照注册号+营业执照注册号
  18. [2022软工第三次作业]结对编程项目——最长英语单词链
  19. 重磅丨中国信通院发布ICT深度观察十大趋势
  20. git--基本知识点--1--工作区/暂存区/版本库

热门文章

  1. MP4封装格式介绍 -- Atom结构
  2. https://github.com
  3. vue之插件 (Plugins)
  4. CSS3 white-space 属性
  5. only whitespace content allowed before start tag and not \u0 (position: START_DOCUMENT
  6. 酒店管理系统的设计与实现
  7. Blog of Friends
  8. C++ friend 用法总结
  9. Oracle 11gr2 RAC安装笔记(五)安装 Database 软件
  10. layui页面发送手机验证码(一)前端