Task3.特征工程
- 对特征工程的痛苦早有耳闻,今天也来好好学习一下
- 特征工程目标
对于特征进行进一步分析,并对于数据进行处理
完成对于特征工程的分析,并对于数据进行一些图表或者文字总结并打卡。
- 内容介绍
常见的特征工程包括:
- 异常处理:
- 通过箱线图(或 3-Sigma)分析删除异常值;
- BOX-COX 转换(处理有偏分布);
- 长尾截断;
- 特征归一化/标准化:
- 标准化(转换为标准正态分布);
- 归一化(抓换到 [0,1] 区间);
- 针对幂律分布,可以采用公式: log(1+x1+median)log(1+x1+median)
- 数据分桶:
- 等频分桶;
- 等距分桶;
- Best-KS 分桶(类似利用基尼指数进行二分类);
- 卡方分桶;
- 缺失值处理:
- 不处理(针对类似 XGBoost 等树模型);
- 删除(缺失数据太多);
- 插值补全,包括均值/中位数/众数/建模预测/多重插补/压缩感知补全/矩阵补全等;
- 分箱,缺失值一个箱;
- 特征构造:
- 构造统计量特征,报告计数、求和、比例、标准差等;
- 时间特征,包括相对时间和绝对时间,节假日,双休日等;
- 地理信息,包括分箱,分布编码等方法;
- 非线性变换,包括 log/ 平方/ 根号等;
- 特征组合,特征交叉;
- 仁者见仁,智者见智。
- 特征筛选
- 过滤式(filter):先对数据进行特征选择,然后在训练学习器,常见的方法有 Relief/方差选择发/相关系数法/卡方检验法/互信息法;
- 包裹式(wrapper):直接把最终将要使用的学习器的性能作为特征子集的评价准则,常见方法有 LVM(Las Vegas Wrapper) ;
- 嵌入式(embedding):结合过滤式和包裹式,学习器训练过程中自动进行了特征选择,常见的有 lasso 回归;
- 降维
- PCA/ LDA/ ICA;
- 特征选择也是一种降维。
删除异常值
-
箱线图的原理即显示异常数据的依据:
箱线图中间是一个箱体,也就是粉红色部分,箱体左边,中间,右边分别有一条线,左边是下四分位数(Q1),右边是上四分位数(Q3),中间是中位数(Median),上下四分位数之差是四 分位距(IQR),用 Q1-1.5IQR 得到下边缘(最小值),Q3+1.5IQR 得到上边缘(最大值)。在 上边缘之外的数据就是极大异常值,在下边缘之外的数据极小异常值,总之在上下边缘之外的数据 就是异常值。
搞清楚异常数据的产生原理之后,想要剔除它们就十分简单了,这里给出一个简单的步骤: 求出这组数据的四分位数,其中上下四分位数分别为 Q3,Q1; 求出这组数据的四分位距 IQR; Q1- 1.5IQR 得到这组数据的下边缘; Q3+1.5IQR 得到这组数据的上边缘; 过滤掉上下边缘之外的异常数据;
我们剔除其中的异常数据后,得到的箱线图依然存在异常值,但是并不是对所有数据都是如此,有的数据经过一次极端值剔除操作后,就没有极端值了,但是有的数据需要经过几次操作,才能使得绘制的箱线图没有极端值显示。 那这就引出了另外一个问题:如果需要多次操作,才能使得对这组数据绘制箱线图没有极端值显 示,那么需要剔除几次极端值? 这里我们来举个例子:我手里有一批调查得到的人们的收入数据(数据集A),通过绘制箱线图发现 其中存在极端值,如下图所示: 通过本文第一部分所述的方法剔除其中的异常值,得到数据集B,对数据集B再次绘制箱线图,发现 仍然存在极端值: **此时我们来思考一下,对于数据集A而言,剔除其中的极端值就得到数据集B,换句话说,数据集B 是数据集A剔除极端值后的数据集,因此对于数据集A而言,我们操作一次其实就已经删除了其中的极端值了。当我们再次对数据集B绘制箱线图所识别出的极端值应该算是数据集B的极端值,而不是 数据集A的。**因此数据集当中的极端异常值一般来说,只需要剔除一次即可。
特征构造
-
# 训练集和测试集放在一起,方便构造特征 Train_data['train']=1 Test_data['train']=0 data = pd.concat([Train_data, Test_data], ignore_index=True) print(data['train'].tail()) print(data.shape)
-
使用时间:
# 使用时间: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
传入 errors=‘coerce’ Pandas 遇到不能转换的数据就会赋值为 NaN(Not a Number)
-
# 看一下空数据,有 15k 个样本的时间是有问题的,我们可以选择删除,也可以选择放着。 # 但是这里不建议删除,因为删除缺失数据占总样本量过大,7.5% # 我们可以先放着,因为如果我们 XGBoost 之类的决策树,其本身就能处理缺失值,所以可以不用管; data['used_time'].isnull().sum()
-
# 从邮编中提取城市信息,相当于加入了先验知识 data['city'] = data[