写点什么

【机器学习入门与实践】数据挖掘 - 二手车价格交易预测(含 EDA 探索、特征工程、特征优化、模型融合等)

作者:汀丶
  • 2023-04-13
    浙江
  • 本文字数:9059 字

    阅读完需:约 30 分钟

【机器学习入门与实践】数据挖掘-二手车价格交易预测(含EDA探索、特征工程、特征优化、模型融合等)

【机器学习入门与实践】数据挖掘-二手车价格交易预测(含 EDA 探索、特征工程、特征优化、模型融合等)


note:项目链接以及码源见文末

1.赛题简介

了解赛题


  • 赛题概况

  • 数据概况

  • 预测指标

  • 分析赛题

  • 数据读取 pandas

  • 分类指标评价计算示例

  • 回归指标评价计算示例


EDA 探索


  • 载入各种数据科学以及可视化库

  • 载入数据

  • 总览数据概况

  • 判断数据缺失和异常

  • 了解预测值的分布

  • 特征分为类别特征和数字特征,并对类别特征查看 unique 分布

  • 数字特征分析

  • 类别特征分析

  • 用 pandas_profiling 生成数据报告


特征工程


  • 导入数据

  • 删除异常值

  • 特征构造

  • 特征筛选


建模调参,相关原理介绍与推荐


  • 线性回归模型

  • 决策树模型

  • GBDT 模型

  • XGBoost 模型

  • LightGBM 模型

  • 推荐教材

  • 读取数据

  • 线性回归 & 五折交叉验证 & 模拟真实业务情况

  • 多种模型对比

  • 模型调参


模型融合


  • 回归\分类概率-融合

  • 分类模型融合

  • 一些其它方法

  • 本赛题示例

1.1 数据说明

比赛要求参赛选手根据给定的数据集,建立模型,二手汽车的交易价格。


来自 Ebay Kleinanzeigen 报废的二手车,数量超过 370,000,包含 20 列变量信息,为了保证比赛的公平性,将会从中抽取 10 万条作为训练集,5 万条作为测试集 A,5 万条作为测试集 B。同时会对名称、车辆类型、变速箱、model、燃油类型、品牌、公里数、价格等信息进行脱敏。


一般而言,对于数据在比赛界面都有对应的数据概况介绍(匿名特征除外),说明列的性质特征。了解列的性质会有助于我们对于数据的理解和后续分析。Tip:匿名特征,就是未告知数据列所属的性质的特征列。


train.csv


  • name - 汽车编码

  • regDate - 汽车注册时间

  • model - 车型编码

  • brand - 品牌

  • bodyType - 车身类型

  • fuelType - 燃油类型

  • gearbox - 变速箱

  • power - 汽车功率

  • kilometer - 汽车行驶公里

  • notRepairedDamage - 汽车有尚未修复的损坏

  • regionCode - 看车地区编码

  • seller - 销售方

  • offerType - 报价类型

  • creatDate - 广告发布时间

  • price - 汽车价格

  • v_0', 'v_1', 'v_2', 'v_3', 'v_4', 'v_5', 'v_6', 'v_7', 'v_8', 'v_9', 'v_10', 'v_11', 'v_12', 'v_13','v_14'(根据汽车的评论、标签等大量信息得到的 embedding 向量)【人工构造 匿名特征】


数字全都脱敏处理,都为 label encoding 形式,即数字形式

1.2 预测指标

本赛题的评价标准为 MAE(Mean Absolute Error):


$$MAE=\frac{\sum_{i=1}^{n}\left|y_{i}-\hat{y}{i}\right|}{n}$y{i}i\hat{y}_{i}i$个样本的预测值。


一般问题评价指标说明:


什么是评估指标:


评估指标即是我们对于一个模型效果的数值型量化。(有点类似与对于一个商品评价打分,而这是针对于模型效果和理想效果之间的一个打分)


一般来说分类和回归问题的评价指标有如下一些形式:


分类算法常见的评估指标如下:


  • 对于二类分类器/分类算法,评价指标主要有 accuracy, [Precision,Recall,F-score,Pr 曲线],ROC-AUC 曲线。

  • 对于多类分类器/分类算法,评价指标主要有 accuracy, [宏平均和微平均,F-score]。


对于回归预测类常见的评估指标如下:


  • 平均绝对误差(Mean Absolute Error,MAE),均方误差(Mean Squared Error,MSE),平均绝对百分误差(Mean Absolute Percentage Error,MAPE),均方根误差(Root Mean Squared Error), R2(R-Square)


平均绝对误差平均绝对误差(Mean Absolute Error,MAE)


:平均绝对误差,其能更好地反映预测值与真实值误差的实际情况,其计算公式如下:



均方误差均方误差(Mean Squared Error,MSE)


,均方误差,其计算公式为:



R2(R-Square)的公式为:残差平方和:$$SS_{res}=\sum\left(y_{i}-\hat{y}{i}\right)^{2}$$SS{tot}=\sum\left(y_{i}-\overline{y}_{i}\right)^{2}$$


其中表示的平均值得到表达式为:$$R^{2}=1-\frac{SS_{res}}{SS_{tot}}=1-\frac{\sum\left(y_{i}-\hat{y}{i}\right)^{2}}{\sum\left(y{i}-\overline{y}\right)^{2}}$$用于度量因变量的变异中可由自变量解释部分所占的比例,取值范围是 0~1,越接近 1,表明回归平方和占总平方和的比例越大,回归线与各观测点越接近,用 x 的变化来解释 y 值变化的部分就越多,回归的拟合程度就越好。所以也称为拟合优度(Goodness of Fit)的统计量。


表示真实值,$\hat{y}{i}\overline{y}{i}$表示样本均值。得分越高拟合效果越好。

1.3 分析赛题

  1. 此题为传统的数据挖掘问题,通过数据科学以及机器学习深度学习的办法来进行建模得到结果。

  2. 此题是一个典型的回归问题。

  3. 主要应用 xgb、lgb、catboost,以及 pandas、numpy、matplotlib、seabon、sklearn、keras 等等数据挖掘常用库或者框架来进行数据挖掘任务。

2.数据探索

# 下载数据!wget http://tianchi-media.oss-cn-beijing.aliyuncs.com/dragonball/DM/data.zip# 解压下载好的数据!unzip data.zip
复制代码


# 导入函数工具## 基础工具import numpy as npimport pandas as pdimport warningsimport matplotlibimport matplotlib.pyplot as pltimport seaborn as snsfrom scipy.special import jnfrom IPython.display import display, clear_outputimport time
warnings.filterwarnings('ignore')%matplotlib inline
## 模型预测的from sklearn import linear_modelfrom sklearn import preprocessingfrom sklearn.svm import SVRfrom sklearn.ensemble import RandomForestRegressor,GradientBoostingRegressor
## 数据降维处理的from sklearn.decomposition import PCA,FastICA,FactorAnalysis,SparsePCA
import lightgbm as lgbimport xgboost as xgb
## 参数搜索和评价的from sklearn.model_selection import GridSearchCV,cross_val_score,StratifiedKFold,train_test_splitfrom sklearn.metrics import mean_squared_error, mean_absolute_error
复制代码

2.1 数据读取

## 通过Pandas对于数据进行读取 (pandas是一个很友好的数据读取函数库)Train_data = pd.read_csv('/home/aistudio/dataset/used_car_train_20200313.csv', sep=' ')TestA_data = pd.read_csv('/home/aistudio/dataset/used_car_testA_20200313.csv', sep=' ')
## 输出数据的大小信息print('Train data shape:',Train_data.shape)print('TestA data shape:',TestA_data.shape)
复制代码


Train data shape: (150000, 31)TestA data shape: (50000, 30)
复制代码

2.2 数据简要浏览

## 通过.head() 简要浏览读取数据的形式Train_data.head()
复制代码


.dataframe tbody tr th:only-of-type { vertical-align: middle; }<pre><code>.dataframe&nbsp;tbody&nbsp;tr&nbsp;th&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;vertical-align:&nbsp;top;<br/>}<br/><br/>.dataframe&nbsp;thead&nbsp;th&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;text-align:&nbsp;right;<br/>}<br/></code></pre><p>



5 rows × 31 columns

2.3 数据信息查看

## 通过 .info() 简要可以看到对应一些数据列名,以及NAN缺失信息Train_data.info()
复制代码


<class 'pandas.core.frame.DataFrame'>RangeIndex: 150000 entries, 0 to 149999Data columns (total 31 columns): #   Column             Non-Null Count   Dtype  ---  ------             --------------   -----   0   SaleID             150000 non-null  int64   1   name               150000 non-null  int64   2   regDate            150000 non-null  int64   3   model              149999 non-null  float64 4   brand              150000 non-null  int64   5   bodyType           145494 non-null  float64 6   fuelType           141320 non-null  float64 7   gearbox            144019 non-null  float64 8   power              150000 non-null  int64   9   kilometer          150000 non-null  float64 10  notRepairedDamage  150000 non-null  object  11  regionCode         150000 non-null  int64   12  seller             150000 non-null  int64   13  offerType          150000 non-null  int64   14  creatDate          150000 non-null  int64   15  price              150000 non-null  int64   16  v_0                150000 non-null  float64 17  v_1                150000 non-null  float64 18  v_2                150000 non-null  float64 19  v_3                150000 non-null  float64 20  v_4                150000 non-null  float64 21  v_5                150000 non-null  float64 22  v_6                150000 non-null  float64 23  v_7                150000 non-null  float64 24  v_8                150000 non-null  float64 25  v_9                150000 non-null  float64 26  v_10               150000 non-null  float64 27  v_11               150000 non-null  float64 28  v_12               150000 non-null  float64 29  v_13               150000 non-null  float64 30  v_14               150000 non-null  float64dtypes: float64(20), int64(10), object(1)memory usage: 35.5+ MB
复制代码


## 通过 .columns 查看列名Train_data.columns
复制代码


Index(['SaleID', 'name', 'regDate', 'model', 'brand', 'bodyType', 'fuelType',       'gearbox', 'power', 'kilometer', 'notRepairedDamage', 'regionCode',       'seller', 'offerType', 'creatDate', 'price', 'v_0', 'v_1', 'v_2', 'v_3',       'v_4', 'v_5', 'v_6', 'v_7', 'v_8', 'v_9', 'v_10', 'v_11', 'v_12',       'v_13', 'v_14'],      dtype='object')
复制代码


TestA_data.info()
复制代码


<class 'pandas.core.frame.DataFrame'>RangeIndex: 50000 entries, 0 to 49999Data columns (total 30 columns): #   Column             Non-Null Count  Dtype  ---  ------             --------------  -----   0   SaleID             50000 non-null  int64   1   name               50000 non-null  int64   2   regDate            50000 non-null  int64   3   model              50000 non-null  float64 4   brand              50000 non-null  int64   5   bodyType           48587 non-null  float64 6   fuelType           47107 non-null  float64 7   gearbox            48090 non-null  float64 8   power              50000 non-null  int64   9   kilometer          50000 non-null  float64 10  notRepairedDamage  50000 non-null  object  11  regionCode         50000 non-null  int64   12  seller             50000 non-null  int64   13  offerType          50000 non-null  int64   14  creatDate          50000 non-null  int64   15  v_0                50000 non-null  float64 16  v_1                50000 non-null  float64 17  v_2                50000 non-null  float64 18  v_3                50000 non-null  float64 19  v_4                50000 non-null  float64 20  v_5                50000 non-null  float64 21  v_6                50000 non-null  float64 22  v_7                50000 non-null  float64 23  v_8                50000 non-null  float64 24  v_9                50000 non-null  float64 25  v_10               50000 non-null  float64 26  v_11               50000 non-null  float64 27  v_12               50000 non-null  float64 28  v_13               50000 non-null  float64 29  v_14               50000 non-null  float64dtypes: float64(20), int64(9), object(1)memory usage: 11.4+ MB
复制代码

2.4 数据统计信息浏览

## 通过 .describe() 可以查看数值特征列的一些统计信息Train_data.describe()
复制代码


.dataframe tbody tr th:only-of-type { vertical-align: middle; }<pre><code>.dataframe&nbsp;tbody&nbsp;tr&nbsp;th&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;vertical-align:&nbsp;top;<br/>}<br/><br/>.dataframe&nbsp;thead&nbsp;th&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;text-align:&nbsp;right;<br/>}<br/></code></pre><p>



8 rows × 30 columns


TestA_data.describe()
复制代码


.dataframe tbody tr th:only-of-type { vertical-align: middle; }<pre><code>.dataframe&nbsp;tbody&nbsp;tr&nbsp;th&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;vertical-align:&nbsp;top;<br/>}<br/><br/>.dataframe&nbsp;thead&nbsp;th&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;text-align:&nbsp;right;<br/>}<br/></code></pre><p>



8 rows × 29 columns

3.数据分析

#### 1) 提取数值类型特征列名numerical_cols = Train_data.select_dtypes(exclude = 'object').columnsprint(numerical_cols)
复制代码


Index(['SaleID', 'name', 'regDate', 'model', 'brand', 'bodyType', 'fuelType',       'gearbox', 'power', 'kilometer', 'regionCode', 'seller', 'offerType',       'creatDate', 'price', 'v_0', 'v_1', 'v_2', 'v_3', 'v_4', 'v_5', 'v_6',       'v_7', 'v_8', 'v_9', 'v_10', 'v_11', 'v_12', 'v_13', 'v_14'],      dtype='object')
复制代码


categorical_cols = Train_data.select_dtypes(include = 'object').columnsprint(categorical_cols)
复制代码


Index(['notRepairedDamage'], dtype='object')
复制代码


#### 2) 构建训练和测试样本## 选择特征列feature_cols = [col for col in numerical_cols if col not in ['SaleID','name','regDate','creatDate','price','model','brand','regionCode','seller']]feature_cols = [col for col in feature_cols if 'Type' not in col]
## 提前特征列,标签列构造训练样本和测试样本X_data = Train_data[feature_cols]Y_data = Train_data['price']
X_test = TestA_data[feature_cols]
print('X train shape:',X_data.shape)print('X test shape:',X_test.shape)
复制代码


X train shape: (150000, 18)X test shape: (50000, 18)
复制代码


## 定义了一个统计函数,方便后续信息统计def Sta_inf(data):    print('_min',np.min(data))    print('_max:',np.max(data))    print('_mean',np.mean(data))    print('_ptp',np.ptp(data))    print('_std',np.std(data))    print('_var',np.var(data))
复制代码


#### 3) 统计标签的基本分布信息print('Sta of label:')Sta_inf(Y_data)
复制代码


Sta of label:_min 11_max: 99999_mean 5923.327333333334_ptp 99988_std 7501.973469876635_var 56279605.942732885
复制代码


## 绘制标签的统计图,查看标签分布plt.hist(Y_data)plt.show()plt.close()
复制代码



#### 4) 缺省值用-1填补X_data = X_data.fillna(-1)X_test = X_test.fillna(-1)
复制代码

4. 模型训练与预测(特征工程、模型融合)

4.1 利用 xgb 进行五折交叉验证查看模型的参数效果

## xgb-Modelxgr = xgb.XGBRegressor(n_estimators=120, learning_rate=0.1, gamma=0, subsample=0.8,\        colsample_bytree=0.9, max_depth=7) #,objective ='reg:squarederror'
scores_train = []scores = []
## 5折交叉验证方式sk=StratifiedKFold(n_splits=5,shuffle=True,random_state=0)for train_ind,val_ind in sk.split(X_data,Y_data): train_x=X_data.iloc[train_ind].values train_y=Y_data.iloc[train_ind] val_x=X_data.iloc[val_ind].values val_y=Y_data.iloc[val_ind] xgr.fit(train_x,train_y) pred_train_xgb=xgr.predict(train_x) pred_xgb=xgr.predict(val_x) score_train = mean_absolute_error(train_y,pred_train_xgb) scores_train.append(score_train) score = mean_absolute_error(val_y,pred_xgb) scores.append(score)
print('Train mae:',np.mean(score_train))print('Val mae',np.mean(scores))
复制代码

4.2 定义 xgb 和 lgb 模型函数

def build_model_xgb(x_train,y_train):    model = xgb.XGBRegressor(n_estimators=150, learning_rate=0.1, gamma=0, subsample=0.8,\        colsample_bytree=0.9, max_depth=7) #, objective ='reg:squarederror'    model.fit(x_train, y_train)    return model
def build_model_lgb(x_train,y_train): estimator = lgb.LGBMRegressor(num_leaves=127,n_estimators = 150) param_grid = { 'learning_rate': [0.01, 0.05, 0.1, 0.2], } gbm = GridSearchCV(estimator, param_grid) gbm.fit(x_train, y_train) return gbm
复制代码

4.3 切分数据集(Train,Val)进行模型训练,评价和预测

## Split data with valx_train,x_val,y_train,y_val = train_test_split(X_data,Y_data,test_size=0.3)
复制代码


print('Train lgb...')model_lgb = build_model_lgb(x_train,y_train)val_lgb = model_lgb.predict(x_val)MAE_lgb = mean_absolute_error(y_val,val_lgb)print('MAE of val with lgb:',MAE_lgb)
print('Predict lgb...')model_lgb_pre = build_model_lgb(X_data,Y_data)subA_lgb = model_lgb_pre.predict(X_test)print('Sta of Predict lgb:')Sta_inf(subA_lgb)
复制代码


print('Train xgb...')model_xgb = build_model_xgb(x_train,y_train)val_xgb = model_xgb.predict(x_val)MAE_xgb = mean_absolute_error(y_val,val_xgb)print('MAE of val with xgb:',MAE_xgb)
print('Predict xgb...')model_xgb_pre = build_model_xgb(X_data,Y_data)subA_xgb = model_xgb_pre.predict(X_test)print('Sta of Predict xgb:')Sta_inf(subA_xgb)
复制代码

4.4 进行两模型的结果加权融合

## 这里我们采取了简单的加权融合的方式val_Weighted = (1-MAE_lgb/(MAE_xgb+MAE_lgb))*val_lgb+(1-MAE_xgb/(MAE_xgb+MAE_lgb))*val_xgbval_Weighted[val_Weighted<0]=10 # 由于我们发现预测的最小值有负数,而真实情况下,price为负是不存在的,由此我们进行对应的后修正print('MAE of val with Weighted ensemble:',mean_absolute_error(y_val,val_Weighted))
复制代码


sub_Weighted = (1-MAE_lgb/(MAE_xgb+MAE_lgb))*subA_lgb+(1-MAE_xgb/(MAE_xgb+MAE_lgb))*subA_xgb
## 查看预测值的统计进行plt.hist(Y_data)plt.show()plt.close()
复制代码

4.5.输出结果

sub = pd.DataFrame()sub['SaleID'] = TestA_data.SaleIDsub['price'] = sub_Weightedsub.to_csv('./sub_Weighted.csv',index=False)
复制代码


sub.head()
复制代码

5. 项目详细展开

因篇幅内容限制,将原学习项目拆解成多个 notebook 方便学习,只需一键 fork。

5.1 数据分析详解

  1. 载入各种数据科学以及可视化库:

  2. 数据科学库 pandas、numpy、scipy;

  3. 可视化库 matplotlib、seabon;

  4. 其他;

  5. 载入数据:

  6. 载入训练集和测试集;

  7. 简略观察数据(head()+shape);

  8. 数据总览:

  9. 通过 describe()来熟悉数据的相关统计量

  10. 通过 info()来熟悉数据类型

  11. 判断数据缺失和异常

  12. 查看每列的存在 nan 情况

  13. 异常值检测

  14. 了解预测值的分布

  15. 总体分布概况(无界约翰逊分布等)

  16. 查看 skewness and kurtosis

  17. 查看预测值的具体频数

  18. 特征分为类别特征和数字特征,并对类别特征查看 unique 分布

  19. 数字特征分析

  20. 相关性分析

  21. 查看几个特征得 偏度和峰值

  22. 每个数字特征得分布可视化

  23. 数字特征相互之间的关系可视化

  24. 多变量互相回归关系可视化

  25. 类型特征分析

  26. unique 分布

  27. 类别特征箱形图可视化

  28. 类别特征的小提琴图可视化

  29. 类别特征的柱形图可视化类别

  30. 特征的每个类别频数可视化(count_plot)

  31. 用 pandas_profiling 生成数据报告


5.2 特征工程

  1. 异常处理:

  2. 通过箱线图(或 3-Sigma)分析删除异常值;

  3. BOX-COX 转换(处理有偏分布);

  4. 长尾截断;

  5. 特征归一化/标准化:

  6. 标准化(转换为标准正态分布);

  7. 归一化(抓换到 [0,1] 区间);

  8. 针对幂律分布,可以采用公式:

  9. 数据分桶:

  10. 等频分桶;

  11. 等距分桶;

  12. Best-KS 分桶(类似利用基尼指数进行二分类);

  13. 卡方分桶;

  14. 缺失值处理:

  15. 不处理(针对类似 XGBoost 等树模型);

  16. 删除(缺失数据太多);

  17. 插值补全,包括均值/中位数/众数/建模预测/多重插补/压缩感知补全/矩阵补全等;

  18. 分箱,缺失值一个箱;

  19. 特征构造:

  20. 构造统计量特征,报告计数、求和、比例、标准差等;

  21. 时间特征,包括相对时间和绝对时间,节假日,双休日等;

  22. 地理信息,包括分箱,分布编码等方法;

  23. 非线性变换,包括 log/ 平方/ 根号等;

  24. 特征组合,特征交叉;

  25. 仁者见仁,智者见智。

  26. 特征筛选

  27. 过滤式(filter):先对数据进行特征选择,然后在训练学习器,常见的方法有 Relief/方差选择发/相关系数法/卡方检验法/互信息法;

  28. 包裹式(wrapper):直接把最终将要使用的学习器的性能作为特征子集的评价准则,常见方法有 LVM(Las Vegas Wrapper) ;

  29. 嵌入式(embedding):结合过滤式和包裹式,学习器训练过程中自动进行了特征选择,常见的有 lasso 回归;

  30. 降维

  31. PCA/ LDA/ ICA;

  32. 特征选择也是一种降维。


5.3 模型优化

  1. 线性回归模型:

  2. 线性回归对于特征的要求;

  3. 处理长尾分布;

  4. 理解线性回归模型;

  5. 模型性能验证:

  6. 评价函数与目标函数;

  7. 交叉验证方法;

  8. 留一验证方法;

  9. 针对时间序列问题的验证;

  10. 绘制学习率曲线;

  11. 绘制验证曲线;

  12. 嵌入式特征选择:

  13. Lasso 回归;

  14. Ridge 回归;

  15. 决策树;

  16. 模型对比:

  17. 常用线性模型;

  18. 常用非线性模型;

  19. 模型调参:

  20. 贪心调参方法;

  21. 网格调参方法;

  22. 贝叶斯调参方法;


5.4 模型融合

  1. 简单加权融合:

  2. 回归(分类概率):算术平均融合(Arithmetic mean),几何平均融合(Geometric mean);

  3. 分类:投票(Voting)

  4. 综合:排序融合(Rank averaging),log 融合

  5. stacking/blending:

  6. 构建多层模型,并利用预测结果再拟合预测。

  7. boosting/bagging(在 xgboost,Adaboost,GBDT 中已经用到):

  8. 多树的提升方法

  9. 训练:



预测:


6.总结

二手车预测项目是非常经典项目,数据挖掘实践(二手车价格预测)的内容来自 Datawhale 与天池联合发起的,现在通过整理和调整让更多对机器学习感兴趣可以上手实战一下


因篇幅内容限制,将原学习项目拆解成多个 notebook 方便学习,只需一键 fork。

项目链接:

一键 fork 直接运行,所有项目码源都在里面


https://www.heywhale.com/mw/project/64367e0a2a3d6dc93d22054f


机器学习数据挖掘专栏:https://www.heywhale.com/home/column/64141d6b1c8c8b518ba97dcc


参考链接:


https://github.com/datawhalechina/team-learning-data-mining/tree/master/SecondHandCarPriceForecast


发布于: 刚刚阅读数: 3
用户头像

汀丶

关注

本博客将不定期更新关于NLP等领域相关知识 2022-01-06 加入

本博客将不定期更新关于机器学习、强化学习、数据挖掘以及NLP等领域相关知识,以及分享自己学习到的知识技能,感谢大家关注!

评论

发布
暂无评论
【机器学习入门与实践】数据挖掘-二手车价格交易预测(含EDA探索、特征工程、特征优化、模型融合等)_人工智能_汀丶_InfoQ写作社区