课程内容提交

This commit is contained in:
LSGOMYP
2020-07-30 09:17:18 +08:00
parent f31e9e35d9
commit f5f1c7be26
10 changed files with 57884 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,446 @@
# Datawhale 零基础入门数据挖掘-Task1 赛题理解
## 一、 赛题理解
Tip:此部分为零基础入门数据挖掘的 Task1 赛题理解 部分,为大家入门数据挖掘比赛提供一个基本的赛题入门讲解,欢迎后续大家多多交流。
**赛题:零基础入门数据挖掘 - 二手车交易价格预测**
地址https://tianchi.aliyun.com/competition/entrance/231784/introduction?spm=5176.12281957.1004.1.38b02448ausjSX
## 1.1 学习目标
* 理解赛题数据和目标,清楚评分体系。
* 完成相应报名,下载数据和结果提交打卡(可提交示例结果),熟悉比赛流程
## 1.2 了解赛题
- 赛题概况
- 数据概况
- 预测指标
- 分析赛题
### 1.2.1 赛题概况
比赛要求参赛选手根据给定的数据集,建立模型,二手汽车的交易价格。
赛题以预测二手车的交易价格为任务数据集报名后可见并可下载该数据来自某交易平台的二手车交易记录总数据量超过40w包含31列变量信息其中15列为匿名变量。为了保证比赛的公平性将会从中抽取15万条作为训练集5万条作为测试集A5万条作为测试集B同时会对name、model、brand和regionCode等信息进行脱敏。
通过这道赛题来引导大家走进 AI 数据竞赛的世界,主要针对于于竞赛新人进行自我练
习、自我提高。
### 1.2.2 数据概况
---
一般而言,对于数据在比赛界面都有对应的数据概况介绍(匿名特征除外),说明列的性质特征。了解列的性质会有助于我们对于数据的理解和后续分析。
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.3 预测指标
---
**本赛题的评价标准为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 [PrecisionRecallF-scorePr曲线]ROC-AUC曲线。
* 对于多类分类器/分类算法评价指标主要有accuracy [宏平均和微平均F-score]。
#### 对于回归预测类常见的评估指标如下:
* 平均绝对误差Mean Absolute ErrorMAE均方误差Mean Squared ErrorMSE平均绝对百分误差Mean Absolute Percentage ErrorMAPE均方根误差Root Mean Squared Error R2R-Square
**平均绝对误差**
**平均绝对误差Mean Absolute ErrorMAE**:平均绝对误差,其能更好地反映预测值与真实值误差的实际情况,其计算公式如下:
$$
MAE=\frac{1}{N} \sum_{i=1}^{N}\left|y_{i}-\hat{y}_{i}\right|
$$
**均方误差**
**均方误差Mean Squared ErrorMSE**,均方误差,其计算公式为:
$$
MSE=\frac{1}{N} \sum_{i=1}^{N}\left(y_{i}-\hat{y}_{i}\right)^{2}
$$
**R2R-Square的公式为**
残差平方和:
$$
SS_{res}=\sum\left(y_{i}-\hat{y}_{i}\right)^{2}
$$
总平均值:
$$
SS_{tot}=\sum\left(y_{i}-\overline{y}_{i}\right)^{2}
$$
其中$\overline{y}$表示$y$的平均值
得到$R^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}}
$$
$R^2$用于度量因变量的变异中可由自变量解释部分所占的比例,取值范围是 0~1$R^2$越接近1,表明回归平方和占总平方和的比例越大,回归线与各观测点越接近用x的变化来解释y值变化的部分就越多,回归的拟合程度就越好。所以$R^2$也称为拟合优度Goodness of Fit的统计量。
$y_{i}$表示真实值,$\hat{y}_{i}$表示预测值,$\overline{y}_{i}$表示样本均值。得分越高拟合效果越好。
### 1.2.4. 分析赛题
1. 此题为传统的数据挖掘问题,通过数据科学以及机器学习深度学习的办法来进行建模得到结果。
2. 此题是一个典型的回归问题。
3. 主要应用xgb、lgb、catboost以及pandas、numpy、matplotlib、seabon、sklearn、keras等等数据挖掘常用库或者框架来进行数据挖掘任务。
4. 通过EDA来挖掘数据的联系和自我熟悉数据。
## 1.3 代码示例
本部分为对于数据读取和指标评价的示例。
### 1.3.1 数据读取pandas
```python
import pandas as pd
import numpy as np
path = './data/'
## 1) 载入训练集和测试集;
Train_data = pd.read_csv(path+'train.csv', sep=' ')
Test_data = pd.read_csv(path+'testA.csv', sep=' ')
print('Train data shape:',Train_data.shape)
print('TestA data shape:',Test_data.shape)
```
Train data shape: (150000, 31)
TestA data shape: (50000, 30)
```python
Train_data.head()
```
<div>
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>SaleID</th>
<th>name</th>
<th>regDate</th>
<th>model</th>
<th>brand</th>
<th>bodyType</th>
<th>fuelType</th>
<th>gearbox</th>
<th>power</th>
<th>kilometer</th>
<th>...</th>
<th>v_5</th>
<th>v_6</th>
<th>v_7</th>
<th>v_8</th>
<th>v_9</th>
<th>v_10</th>
<th>v_11</th>
<th>v_12</th>
<th>v_13</th>
<th>v_14</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>0</td>
<td>736</td>
<td>20040402</td>
<td>30.0</td>
<td>6</td>
<td>1.0</td>
<td>0.0</td>
<td>0.0</td>
<td>60</td>
<td>12.5</td>
<td>...</td>
<td>0.235676</td>
<td>0.101988</td>
<td>0.129549</td>
<td>0.022816</td>
<td>0.097462</td>
<td>-2.881803</td>
<td>2.804097</td>
<td>-2.420821</td>
<td>0.795292</td>
<td>0.914762</td>
</tr>
<tr>
<th>1</th>
<td>1</td>
<td>2262</td>
<td>20030301</td>
<td>40.0</td>
<td>1</td>
<td>2.0</td>
<td>0.0</td>
<td>0.0</td>
<td>0</td>
<td>15.0</td>
<td>...</td>
<td>0.264777</td>
<td>0.121004</td>
<td>0.135731</td>
<td>0.026597</td>
<td>0.020582</td>
<td>-4.900482</td>
<td>2.096338</td>
<td>-1.030483</td>
<td>-1.722674</td>
<td>0.245522</td>
</tr>
<tr>
<th>2</th>
<td>2</td>
<td>14874</td>
<td>20040403</td>
<td>115.0</td>
<td>15</td>
<td>1.0</td>
<td>0.0</td>
<td>0.0</td>
<td>163</td>
<td>12.5</td>
<td>...</td>
<td>0.251410</td>
<td>0.114912</td>
<td>0.165147</td>
<td>0.062173</td>
<td>0.027075</td>
<td>-4.846749</td>
<td>1.803559</td>
<td>1.565330</td>
<td>-0.832687</td>
<td>-0.229963</td>
</tr>
<tr>
<th>3</th>
<td>3</td>
<td>71865</td>
<td>19960908</td>
<td>109.0</td>
<td>10</td>
<td>0.0</td>
<td>0.0</td>
<td>1.0</td>
<td>193</td>
<td>15.0</td>
<td>...</td>
<td>0.274293</td>
<td>0.110300</td>
<td>0.121964</td>
<td>0.033395</td>
<td>0.000000</td>
<td>-4.509599</td>
<td>1.285940</td>
<td>-0.501868</td>
<td>-2.438353</td>
<td>-0.478699</td>
</tr>
<tr>
<th>4</th>
<td>4</td>
<td>111080</td>
<td>20120103</td>
<td>110.0</td>
<td>5</td>
<td>1.0</td>
<td>0.0</td>
<td>0.0</td>
<td>68</td>
<td>5.0</td>
<td>...</td>
<td>0.228036</td>
<td>0.073205</td>
<td>0.091880</td>
<td>0.078819</td>
<td>0.121534</td>
<td>-1.896240</td>
<td>0.910783</td>
<td>0.931110</td>
<td>2.834518</td>
<td>1.923482</td>
</tr>
</tbody>
</table>
<p>5 rows × 31 columns</p>
</div>
### 1.3.2 分类指标评价计算示例
```python
## accuracy
import numpy as np
from sklearn.metrics import accuracy_score
y_pred = [0, 1, 0, 1]
y_true = [0, 1, 1, 1]
print('ACC:',accuracy_score(y_true, y_pred))
```
ACC: 0.75
```python
## Precision,Recall,F1-score
from sklearn import metrics
y_pred = [0, 1, 0, 0]
y_true = [0, 1, 0, 1]
print('Precision',metrics.precision_score(y_true, y_pred))
print('Recall',metrics.recall_score(y_true, y_pred))
print('F1-score:',metrics.f1_score(y_true, y_pred))
```
Precision 1.0
Recall 0.5
F1-score: 0.6666666666666666
```python
## AUC
import numpy as np
from sklearn.metrics import roc_auc_score
y_true = np.array([0, 0, 1, 1])
y_scores = np.array([0.1, 0.4, 0.35, 0.8])
print('AUC socre:',roc_auc_score(y_true, y_scores))
```
AUC socre: 0.75
### 1.3.3 回归指标评价计算示例
```python
# coding=utf-8
import numpy as np
from sklearn import metrics
# MAPE需要自己实现
def mape(y_true, y_pred):
return np.mean(np.abs((y_pred - y_true) / y_true))
y_true = np.array([1.0, 5.0, 4.0, 3.0, 2.0, 5.0, -3.0])
y_pred = np.array([1.0, 4.5, 3.8, 3.2, 3.0, 4.8, -2.2])
# MSE
print('MSE:',metrics.mean_squared_error(y_true, y_pred))
# RMSE
print('RMSE:',np.sqrt(metrics.mean_squared_error(y_true, y_pred)))
# MAE
print('MAE:',metrics.mean_absolute_error(y_true, y_pred))
# MAPE
print('MAPE:',mape(y_true, y_pred))
```
MSE: 0.2871428571428571
RMSE: 0.5358571238146014
MAE: 0.4142857142857143
MAPE: 0.1461904761904762
```python
## R2-score
from sklearn.metrics import r2_score
y_true = [3, -0.5, 2, 7]
y_pred = [2.5, 0.0, 2, 8]
print('R2-score:',r2_score(y_true, y_pred))
```
R2-score: 0.9486081370449679
## 1.4 经验总结
作为切入一道赛题的基础,赛题理解是极其重要的,对于赛题的理解甚至会影响后续的特征工程构建以及模型的选择,最主要是会影响后续发展工作的方向,比如挖掘特征的方向或者存在问题解决问题的方向,对了赛题背后的思想以及赛题业务逻辑的清晰,也很有利于花费更少时间构建更为有效的特征模型,赛题理解要达到的地步是什么呢,把一道赛题转化为一种宏观理解的解决思路。
以下将从多方面对于此进行说明:
* 1 赛题理解究竟是理解什么:
理解赛题是不是把一道赛题的背景介绍读一遍就OK了呢并不是的理解赛题其实也是从直观上梳理问题分析问题是否可行的方法有多少可行度赛题做的价值大不大理清一道赛题要从背后的赛题背景引发的赛题任务理解其中的任务逻辑可能对于赛题有意义的外在数据有哪些并对于赛题数据有一个初步了解知道现在和任务的相关数据有哪些其中数据之间的关联逻辑是什么样的。 对于不同的问题在处理方式上的差异是很大的。如果用简短的话来说并且在比赛的角度或者做工程的角度就是该赛题符合的问题是什么问题大概要去用哪些指标哪些指标是否会做到线上线下的一致性是否有效的利于我们进一步的探索更高线上分数的线下验证方法在业务上你是否对很多原始特征有很深刻的了解并且可以通过EDA来寻求他们直接的关系最后构造出满意的特征。
* 2 有了赛题理解后能做什么:
在对于赛题有了一定的了解后,分析清楚了问题的类型性质和对于数据理解的这一基础上,是不是赛题理解就做完了呢? 并不是的就像摸清了敌情后我们至少就要有一些相应的理解分析比如这题的难点可能在哪里关键点可能在哪里哪些地方可以挖掘更好的特征用什么样得线下验证方式更为稳定出现了过拟合或者其他问题估摸可以用什么方法去解决这些问题哪些数据是可靠的哪些数据是需要精密的处理的哪部分数据应该是关键数据背景的业务逻辑下比如CTR的题一个寻常顾客大体会有怎么样的购买行为逻辑规律或者风电那种题如果机组比较邻近相关一些风速转速特征是否会很近似。这时是在一个宏观的大体下分析的有助于摸清整个题的思路脉络以及后续的分析方向。
* 3 赛题理解的-评价指标:
为什么要把这部分单独拿出来呢,因为这部分会涉及后续模型预测中两个很重要的问题:
1 本地模型的验证方式,很多情况下,线上验证是有一定的时间和次数限制的,所以在比赛中构建一个合理的本地的验证集和验证的评价指标是很关键的步骤,能有效的节省很多时间。
2 不同的指标对于同样的预测结果是具有误差敏感的差异性的比如AUClogloss, MAERSME或者一些特定的评价函数。是会有很大可能会影响后续一些预测的侧重点。
* 4 赛题背景中可能潜在隐藏的条件:
其实赛题中有些说明是很有利益-都可以在后续答辩中以及问题思考中所体现出来的,比如高效性要求,比如对于数据异常的识别处理,比如工序流程的差异性,比如模型运行的时间,比模型的鲁棒性,有些的意识是可以贯穿问题思考,特征,模型以及后续处理的,也有些会对于特征构建或者选择模型上有很大益处,反过来如果在模型预测效果不好,其实有时也要反过来思考,是不是赛题背景有没有哪方面理解不清晰或者什么其中的问题没考虑到。
**Task1 赛题理解 END.**
--- By: AI蜗牛车
PS东南大学研究生研究方向主要是时空序列预测和时间序列数据挖掘
公众号: AI蜗牛车
知乎: https://www.zhihu.com/people/seu-aigua-niu-che
github: https://github.com/chehongshu
**关于Datawhale**
> Datawhale是一个专注于数据科学与AI领域的开源组织汇集了众多领域院校和知名企业的优秀学习者聚合了一群有开源精神和探索精神的团队成员。Datawhale 以“for the learner和学习者一起成长”为愿景鼓励真实地展现自我、开放包容、互信互助、敢于试错和勇于担当。同时 Datawhale 用开源的理念去探索开源内容、开源学习和开源方案,赋能人才培养,助力人才成长,建立起人与人,人与知识,人与企业和人与未来的联结。
本次数据挖掘路径学习专题知识将在天池分享详情可关注Datawhale
![](http://jupter-oss.oss-cn-hangzhou.aliyuncs.com/public/files/image/2326541042/1584426326920_9FOUExG2be.jpg)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,851 @@
# Datawhale 零基础入门数据挖掘-Task3 特征工程
## 三、 特征工程目标
Tip:此部分为零基础入门数据挖掘的 Task3 特征工程 部分,带你来了解各种特征工程以及分析方法,欢迎大家后续多多交流。
**赛题:零基础入门数据挖掘 - 二手车交易价格预测**
地址https://tianchi.aliyun.com/competition/entrance/231784/introduction?spm=5176.12281957.1004.1.38b02448ausjSX
## 3.1 特征工程目标
* 对于特征进行进一步分析,并对于数据进行处理
* 完成对于特征工程的分析,并对于数据进行一些图表或者文字总结并打卡。
## 3.2 内容介绍
常见的特征工程包括:
1. 异常处理:
- 通过箱线图(或 3-Sigma分析删除异常值
- BOX-COX 转换(处理有偏分布);
- 长尾截断;
2. 特征归一化/标准化:
- 标准化(转换为标准正态分布);
- 归一化(抓换到 [0,1] 区间);
- 针对幂律分布,可以采用公式: $log(\frac{1+x}{1+median})$
3. 数据分桶:
- 等频分桶;
- 等距分桶;
- Best-KS 分桶(类似利用基尼指数进行二分类);
- 卡方分桶;
4. 缺失值处理:
- 不处理(针对类似 XGBoost 等树模型);
- 删除(缺失数据太多);
- 插值补全,包括均值/中位数/众数/建模预测/多重插补/压缩感知补全/矩阵补全等;
- 分箱,缺失值一个箱;
5. 特征构造:
- 构造统计量特征,报告计数、求和、比例、标准差等;
- 时间特征,包括相对时间和绝对时间,节假日,双休日等;
- 地理信息,包括分箱,分布编码等方法;
- 非线性变换,包括 log/ 平方/ 根号等;
- 特征组合,特征交叉;
- 仁者见仁,智者见智。
6. 特征筛选
- 过滤式filter先对数据进行特征选择然后在训练学习器常见的方法有 Relief/方差选择发/相关系数法/卡方检验法/互信息法;
- 包裹式wrapper直接把最终将要使用的学习器的性能作为特征子集的评价准则常见方法有 LVMLas Vegas Wrapper
- 嵌入式embedding结合过滤式和包裹式学习器训练过程中自动进行了特征选择常见的有 lasso 回归;
7. 降维
- PCA/ LDA/ ICA
- 特征选择也是一种降维。
## 3.3 代码示例
## 3.3.0 导入数据
```python
import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
from operator import itemgetter
%matplotlib inline
```
```python
train = pd.read_csv('train.csv', sep=' ')
test = pd.read_csv('testA.csv', sep=' ')
print(train.shape)
print(test.shape)
```
(150000, 30)
(50000, 30)
```python
train.head()
```
<div>
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>name</th>
<th>regDate</th>
<th>model</th>
<th>brand</th>
<th>bodyType</th>
<th>fuelType</th>
<th>gearbox</th>
<th>power</th>
<th>kilometer</th>
<th>notRepairedDamage</th>
<th>...</th>
<th>v_5</th>
<th>v_6</th>
<th>v_7</th>
<th>v_8</th>
<th>v_9</th>
<th>v_10</th>
<th>v_11</th>
<th>v_12</th>
<th>v_13</th>
<th>v_14</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>736</td>
<td>20040402</td>
<td>30.0</td>
<td>6</td>
<td>1.0</td>
<td>0.0</td>
<td>0.0</td>
<td>60</td>
<td>12.5</td>
<td>0.0</td>
<td>...</td>
<td>0.235676</td>
<td>0.101988</td>
<td>0.129549</td>
<td>0.022816</td>
<td>0.097462</td>
<td>-2.881803</td>
<td>2.804097</td>
<td>-2.420821</td>
<td>0.795292</td>
<td>0.914762</td>
</tr>
<tr>
<th>1</th>
<td>2262</td>
<td>20030301</td>
<td>40.0</td>
<td>1</td>
<td>2.0</td>
<td>0.0</td>
<td>0.0</td>
<td>0</td>
<td>15.0</td>
<td>-</td>
<td>...</td>
<td>0.264777</td>
<td>0.121004</td>
<td>0.135731</td>
<td>0.026597</td>
<td>0.020582</td>
<td>-4.900482</td>
<td>2.096338</td>
<td>-1.030483</td>
<td>-1.722674</td>
<td>0.245522</td>
</tr>
<tr>
<th>2</th>
<td>14874</td>
<td>20040403</td>
<td>115.0</td>
<td>15</td>
<td>1.0</td>
<td>0.0</td>
<td>0.0</td>
<td>163</td>
<td>12.5</td>
<td>0.0</td>
<td>...</td>
<td>0.251410</td>
<td>0.114912</td>
<td>0.165147</td>
<td>0.062173</td>
<td>0.027075</td>
<td>-4.846749</td>
<td>1.803559</td>
<td>1.565330</td>
<td>-0.832687</td>
<td>-0.229963</td>
</tr>
<tr>
<th>3</th>
<td>71865</td>
<td>19960908</td>
<td>109.0</td>
<td>10</td>
<td>0.0</td>
<td>0.0</td>
<td>1.0</td>
<td>193</td>
<td>15.0</td>
<td>0.0</td>
<td>...</td>
<td>0.274293</td>
<td>0.110300</td>
<td>0.121964</td>
<td>0.033395</td>
<td>0.000000</td>
<td>-4.509599</td>
<td>1.285940</td>
<td>-0.501868</td>
<td>-2.438353</td>
<td>-0.478699</td>
</tr>
<tr>
<th>4</th>
<td>111080</td>
<td>20120103</td>
<td>110.0</td>
<td>5</td>
<td>1.0</td>
<td>0.0</td>
<td>0.0</td>
<td>68</td>
<td>5.0</td>
<td>0.0</td>
<td>...</td>
<td>0.228036</td>
<td>0.073205</td>
<td>0.091880</td>
<td>0.078819</td>
<td>0.121534</td>
<td>-1.896240</td>
<td>0.910783</td>
<td>0.931110</td>
<td>2.834518</td>
<td>1.923482</td>
</tr>
</tbody>
</table>
<p>5 rows × 30 columns</p>
</div>
```python
train.columns
```
Index(['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')
```python
test.columns
```
Index(['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')
## 3.3.1 删除异常值
```python
# 这里我包装了一个异常值处理的代码,可以随便调用。
def outliers_proc(data, col_name, scale=3):
"""
用于清洗异常值,默认用 box_plotscale=3进行清洗
:param data: 接收 pandas 数据格式
:param col_name: pandas 列名
:param scale: 尺度
:return:
"""
def box_plot_outliers(data_ser, box_scale):
"""
利用箱线图去除异常值
:param data_ser: 接收 pandas.Series 数据格式
:param box_scale: 箱线图尺度,
:return:
"""
iqr = box_scale * (data_ser.quantile(0.75) - data_ser.quantile(0.25))
val_low = data_ser.quantile(0.25) - iqr
val_up = data_ser.quantile(0.75) + iqr
rule_low = (data_ser < val_low)
rule_up = (data_ser > val_up)
return (rule_low, rule_up), (val_low, val_up)
data_n = data.copy()
data_series = data_n[col_name]
rule, value = box_plot_outliers(data_series, box_scale=scale)
index = np.arange(data_series.shape[0])[rule[0] | rule[1]]
print("Delete number is: {}".format(len(index)))
data_n = data_n.drop(index)
data_n.reset_index(drop=True, inplace=True)
print("Now column number is: {}".format(data_n.shape[0]))
index_low = np.arange(data_series.shape[0])[rule[0]]
outliers = data_series.iloc[index_low]
print("Description of data less than the lower bound is:")
print(pd.Series(outliers).describe())
index_up = np.arange(data_series.shape[0])[rule[1]]
outliers = data_series.iloc[index_up]
print("Description of data larger than the upper bound is:")
print(pd.Series(outliers).describe())
fig, ax = plt.subplots(1, 2, figsize=(10, 7))
sns.boxplot(y=data[col_name], data=data, palette="Set1", ax=ax[0])
sns.boxplot(y=data_n[col_name], data=data_n, palette="Set1", ax=ax[1])
return data_n
```
```python
# 我们可以删掉一些异常数据,以 power 为例。
# 这里删不删同学可以自行判断
# 但是要注意 test 的数据不能删 = = 不能掩耳盗铃是不是
train = outliers_proc(train, 'power', scale=3)
```
Delete number is: 963
Now column number is: 149037
Description of data less than the lower bound is:
count 0.0
mean NaN
std NaN
min NaN
25% NaN
50% NaN
75% NaN
max NaN
Name: power, dtype: float64
Description of data larger than the upper bound is:
count 963.000000
mean 846.836968
std 1929.418081
min 376.000000
25% 400.000000
50% 436.000000
75% 514.000000
max 19312.000000
Name: power, dtype: float64
![output_12_1](https://img-blog.csdnimg.cn/20200321230643257.png)
## 3.3.2 特征构造
```python
# 训练集和测试集放在一起,方便构造特征
train['train']=1
test['train']=0
data = pd.concat([train, test], ignore_index=True, sort=False)
```
```python
# 使用时间data['creatDate'] - data['regDate'],反应汽车使用时间,一般来说价格与使用时间成反比
# 不过要注意,数据里有时间出错的格式,所以我们需要 errors='coerce'
data['used_time'] = (pd.to_datetime(data['creatDate'], format='%Y%m%d', errors='coerce') -
pd.to_datetime(data['regDate'], format='%Y%m%d', errors='coerce')).dt.days
```
```python
# 看一下空数据,有 15k 个样本的时间是有问题的,我们可以选择删除,也可以选择放着。
# 但是这里不建议删除因为删除缺失数据占总样本量过大7.5%
# 我们可以先放着,因为如果我们 XGBoost 之类的决策树,其本身就能处理缺失值,所以可以不用管;
data['used_time'].isnull().sum()
```
15072
```python
# 从邮编中提取城市信息,因为是德国的数据,所以参考德国的邮编,相当于加入了先验知识
data['city'] = data['regionCode'].apply(lambda x : str(x)[:-3])
```
```python
# 计算某品牌的销售统计量,同学们还可以计算其他特征的统计量
# 这里要以 train 的数据计算统计量
train_gb = train.groupby("brand")
all_info = {}
for kind, kind_data in train_gb:
info = {}
kind_data = kind_data[kind_data['price'] > 0]
info['brand_amount'] = len(kind_data)
info['brand_price_max'] = kind_data.price.max()
info['brand_price_median'] = kind_data.price.median()
info['brand_price_min'] = kind_data.price.min()
info['brand_price_sum'] = kind_data.price.sum()
info['brand_price_std'] = kind_data.price.std()
info['brand_price_average'] = round(kind_data.price.sum() / (len(kind_data) + 1), 2)
all_info[kind] = info
brand_fe = pd.DataFrame(all_info).T.reset_index().rename(columns={"index": "brand"})
data = data.merge(brand_fe, how='left', on='brand')
```
```python
# 数据分桶 以 power 为例
# 这时候我们的缺失值也进桶了,
# 为什么要做数据分桶呢,原因有很多,= =
# 1. 离散后稀疏向量内积乘法运算速度更快,计算结果也方便存储,容易扩展;
# 2. 离散后的特征对异常值更具鲁棒性,如 age>30 为 1 否则为 0对于年龄为 200 的也不会对模型造成很大的干扰;
# 3. LR 属于广义线性模型,表达能力有限,经过离散化后,每个变量有单独的权重,这相当于引入了非线性,能够提升模型的表达能力,加大拟合;
# 4. 离散后特征可以进行特征交叉,提升表达能力,由 M+N 个变量编程 M*N 个变量,进一步引入非线形,提升了表达能力;
# 5. 特征离散后模型更稳定,如用户年龄区间,不会因为用户年龄长了一岁就变化
# 当然还有很多原因LightGBM 在改进 XGBoost 时就增加了数据分桶,增强了模型的泛化性
bin = [i*10 for i in range(31)]
data['power_bin'] = pd.cut(data['power'], bin, labels=False)
data[['power_bin', 'power']].head()
```
<div>
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>power_bin</th>
<th>power</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>5.0</td>
<td>60</td>
</tr>
<tr>
<th>1</th>
<td>NaN</td>
<td>0</td>
</tr>
<tr>
<th>2</th>
<td>16.0</td>
<td>163</td>
</tr>
<tr>
<th>3</th>
<td>19.0</td>
<td>193</td>
</tr>
<tr>
<th>4</th>
<td>6.0</td>
<td>68</td>
</tr>
</tbody>
</table>
</div>
```python
# 利用好了,就可以删掉原始数据了
data = data.drop(['creatDate', 'regDate', 'regionCode'], axis=1)
```
```python
print(data.shape)
data.columns
```
(199037, 38)
Index(['name', 'model', 'brand', 'bodyType', 'fuelType', 'gearbox', 'power',
'kilometer', 'notRepairedDamage', 'seller', 'offerType', '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', 'train', 'used_time', 'city',
'brand_amount', 'brand_price_average', 'brand_price_max',
'brand_price_median', 'brand_price_min', 'brand_price_std',
'brand_price_sum', 'power_bin'],
dtype='object')
```python
# 目前的数据其实已经可以给树模型使用了,所以我们导出一下
data.to_csv('data_for_tree.csv', index=0)
```
```python
# 我们可以再构造一份特征给 LR NN 之类的模型用
# 之所以分开构造是因为,不同模型对数据集的要求不同
# 我们看下数据分布:
data['power'].plot.hist()
```
<matplotlib.axes._subplots.AxesSubplot at 0x12904e5c0>
![output_23_1](https://img-blog.csdnimg.cn/20200321230713988.png)
```python
# 我们刚刚已经对 train 进行异常值处理了,但是现在还有这么奇怪的分布是因为 test 中的 power 异常值,
# 所以我们其实刚刚 train 中的 power 异常值不删为好,可以用长尾分布截断来代替
train['power'].plot.hist()
```
<matplotlib.axes._subplots.AxesSubplot at 0x12de6bba8>
![output_24_1](https://img-blog.csdnimg.cn/20200321230833552.png)
```python
# 我们对其取 log在做归一化
from sklearn import preprocessing
min_max_scaler = preprocessing.MinMaxScaler()
data['power'] = np.log(data['power'] + 1)
data['power'] = ((data['power'] - np.min(data['power'])) / (np.max(data['power']) - np.min(data['power'])))
data['power'].plot.hist()
```
<matplotlib.axes._subplots.AxesSubplot at 0x129ad5dd8>
![output_25_1](https://img-blog.csdnimg.cn/202003212308573.png)
```python
# km 的比较正常,应该是已经做过分桶了
data['kilometer'].plot.hist()
```
<matplotlib.axes._subplots.AxesSubplot at 0x12de58cf8>
![26-1](https://img-blog.csdnimg.cn/20200321230916398.png)
```python
# 所以我们可以直接做归一化
data['kilometer'] = ((data['kilometer'] - np.min(data['kilometer'])) /
(np.max(data['kilometer']) - np.min(data['kilometer'])))
data['kilometer'].plot.hist()
```
<matplotlib.axes._subplots.AxesSubplot at 0x128b4fd30>
![27-1](https://img-blog.csdnimg.cn/20200321230928854.png)
```python
# 除此之外 还有我们刚刚构造的统计量特征:
# 'brand_amount', 'brand_price_average', 'brand_price_max',
# 'brand_price_median', 'brand_price_min', 'brand_price_std',
# 'brand_price_sum'
# 这里不再一一举例分析了,直接做变换,
def max_min(x):
return (x - np.min(x)) / (np.max(x) - np.min(x))
data['brand_amount'] = ((data['brand_amount'] - np.min(data['brand_amount'])) /
(np.max(data['brand_amount']) - np.min(data['brand_amount'])))
data['brand_price_average'] = ((data['brand_price_average'] - np.min(data['brand_price_average'])) /
(np.max(data['brand_price_average']) - np.min(data['brand_price_average'])))
data['brand_price_max'] = ((data['brand_price_max'] - np.min(data['brand_price_max'])) /
(np.max(data['brand_price_max']) - np.min(data['brand_price_max'])))
data['brand_price_median'] = ((data['brand_price_median'] - np.min(data['brand_price_median'])) /
(np.max(data['brand_price_median']) - np.min(data['brand_price_median'])))
data['brand_price_min'] = ((data['brand_price_min'] - np.min(data['brand_price_min'])) /
(np.max(data['brand_price_min']) - np.min(data['brand_price_min'])))
data['brand_price_std'] = ((data['brand_price_std'] - np.min(data['brand_price_std'])) /
(np.max(data['brand_price_std']) - np.min(data['brand_price_std'])))
data['brand_price_sum'] = ((data['brand_price_sum'] - np.min(data['brand_price_sum'])) /
(np.max(data['brand_price_sum']) - np.min(data['brand_price_sum'])))
```
```python
# 对类别特征进行 OneEncoder
data = pd.get_dummies(data, columns=['model', 'brand', 'bodyType', 'fuelType',
'gearbox', 'notRepairedDamage', 'power_bin'])
```
```python
print(data.shape)
data.columns
```
(199037, 369)
Index(['name', 'power', 'kilometer', 'seller', 'offerType', 'price', 'v_0',
'v_1', 'v_2', 'v_3',
...
'power_bin_20.0', 'power_bin_21.0', 'power_bin_22.0', 'power_bin_23.0',
'power_bin_24.0', 'power_bin_25.0', 'power_bin_26.0', 'power_bin_27.0',
'power_bin_28.0', 'power_bin_29.0'],
dtype='object', length=369)
```python
# 这份数据可以给 LR 用
data.to_csv('data_for_lr.csv', index=0)
```
## 3.3.3 特征筛选
### 1) 过滤式
```python
# 相关性分析
print(data['power'].corr(data['price'], method='spearman'))
print(data['kilometer'].corr(data['price'], method='spearman'))
print(data['brand_amount'].corr(data['price'], method='spearman'))
print(data['brand_price_average'].corr(data['price'], method='spearman'))
print(data['brand_price_max'].corr(data['price'], method='spearman'))
print(data['brand_price_median'].corr(data['price'], method='spearman'))
```
0.5737373458520139
-0.4093147076627742
0.0579639618400197
0.38587089498185884
0.26142364388130207
0.3891431767902722
```python
# 当然也可以直接看图
data_numeric = data[['power', 'kilometer', 'brand_amount', 'brand_price_average',
'brand_price_max', 'brand_price_median']]
correlation = data_numeric.corr()
f , ax = plt.subplots(figsize = (7, 7))
plt.title('Correlation of Numeric Features with Price',y=1,size=16)
sns.heatmap(correlation,square = True, vmax=0.8)
```
<matplotlib.axes._subplots.AxesSubplot at 0x129059470>
![35-1](https://img-blog.csdnimg.cn/20200321231015664.png)
### 2) 包裹式
```python
!pip install mlxtend
```
```python
# k_feature 太大会很难跑,没服务器,所以提前 interrupt 了
from mlxtend.feature_selection import SequentialFeatureSelector as SFS
from sklearn.linear_model import LinearRegression
sfs = SFS(LinearRegression(),
k_features=10,
forward=True,
floating=False,
scoring = 'r2',
cv = 0)
x = data.drop(['price'], axis=1)
x = x.fillna(0)
y = data['price']
sfs.fit(x, y)
sfs.k_feature_names_
```
STOPPING EARLY DUE TO KEYBOARD INTERRUPT...
('powerPS_ten',
'city',
'brand_price_std',
'vehicleType_andere',
'model_145',
'model_601',
'fuelType_andere',
'notRepairedDamage_ja')
```python
# 画出来,可以看到边际效益
from mlxtend.plotting import plot_sequential_feature_selection as plot_sfs
import matplotlib.pyplot as plt
fig1 = plot_sfs(sfs.get_metric_dict(), kind='std_dev')
plt.grid()
plt.show()
```
/Users/chenze/anaconda3/lib/python3.7/site-packages/numpy/core/_methods.py:140: RuntimeWarning: Degrees of freedom <= 0 for slice
keepdims=keepdims)
/Users/chenze/anaconda3/lib/python3.7/site-packages/numpy/core/_methods.py:132: RuntimeWarning: invalid value encountered in double_scalars
ret = ret.dtype.type(ret / rcount)
![39-1](https://img-blog.csdnimg.cn/20200321231035835.png)
### 3) 嵌入式
```python
# 下一章介绍Lasso 回归和决策树可以完成嵌入式特征选择
# 大部分情况下都是用嵌入式做特征筛选
```
## 3.4 经验总结
特征工程是比赛中最至关重要的的一块,特别的传统的比赛,大家的模型可能都差不多,调参带来的效果增幅是非常有限的,但特征工程的好坏往往会决定了最终的排名和成绩。
特征工程的主要目的还是在于将数据转换为能更好地表示潜在问题的特征,从而提高机器学习的性能。比如,异常值处理是为了去除噪声,填补缺失值可以加入先验知识等。
特征构造也属于特征工程的一部分,其目的是为了增强数据的表达。
有些比赛的特征是匿名特征这导致我们并不清楚特征相互直接的关联性这时我们就只有单纯基于特征进行处理比如装箱groupbyagg 等这样一些操作进行一些特征统计,此外还可以对特征进行进一步的 logexp 等变换,或者对多个特征进行四则运算(如上面我们算出的使用时长),多项式组合等然后进行筛选。由于特性的匿名性其实限制了很多对于特征的处理,当然有些时候用 NN 去提取一些特征也会达到意想不到的良好效果。
对于知道特征含义(非匿名)的特征工程,特别是在工业类型比赛中,会基于信号处理,频域提取,丰度,偏度等构建更为有实际意义的特征,这就是结合背景的特征构建,在推荐系统中也是这样的,各种类型点击率统计,各时段统计,加用户属性的统计等等,这样一种特征构建往往要深入分析背后的业务逻辑或者说物理原理,从而才能更好的找到 magic。
当然特征工程其实是和模型结合在一起的,这就是为什么要为 LR NN 做分桶和特征归一化的原因,而对于特征的处理效果和特征重要性等往往要通过模型来验证。
总的来说,特征工程是一个入门简单,但想精通非常难的一件事。
## Task 3-特征工程 END.
--- By: 阿泽
PS复旦大学计算机研究生
知乎:阿泽 https://www.zhihu.com/people/is-aze主要面向初学者的知识整理
关于Datawhale
> Datawhale是一个专注于数据科学与AI领域的开源组织汇集了众多领域院校和知名企业的优秀学习者聚合了一群有开源精神和探索精神的团队成员。Datawhale 以“for the learner和学习者一起成长”为愿景鼓励真实地展现自我、开放包容、互信互助、敢于试错和勇于担当。同时 Datawhale 用开源的理念去探索开源内容、开源学习和开源方案,赋能人才培养,助力人才成长,建立起人与人,人与知识,人与企业和人与未来的联结。
本次数据挖掘路径学习专题知识将在天池分享详情可关注Datawhale
![](http://jupter-oss.oss-cn-hangzhou.aliyuncs.com/public/files/image/2326541042/1584426326920_9FOUExG2be.jpg)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,22 @@
1. 赛题数据
赛题以预测二手车的交易价格为任务数据集报名后可见并可下载该数据来自某交易平台的二手车交易记录总数据量超过40w包含31列变量信息其中15列为匿名变量。为了保证比赛的公平性将会从中抽取15万条作为训练集5万条作为测试集A5万条作为测试集B同时会对name、model、brand和regionCode等信息进行脱敏。
字段表
Field Description
SaleID 交易ID唯一编码
name 汽车交易名称,已脱敏
regDate 汽车注册日期例如201601012016年01月01日
model 车型编码,已脱敏
brand 汽车品牌,已脱敏
bodyType 车身类型豪华轿车0微型车1厢型车2大巴车3敞篷车4双门汽车5商务车6搅拌车7
fuelType 燃油类型汽油0柴油1液化石油气2天然气3混合动力4其他5电动6
gearbox 变速箱手动0自动1
power 发动机功率:范围 [ 0, 600 ]
kilometer 汽车已行驶公里单位万km
notRepairedDamage 汽车有尚未修复的损坏01
regionCode 地区编码,已脱敏
seller 销售方个体0非个体1
offerType 报价类型提供0请求1
creatDate 汽车上线时间,即开始售卖时间
price 二手车交易价格(预测目标)
v系列特征 匿名特征包含v0-14在内15个匿名特征