以天池比赛-二手车数据挖掘为例,比赛地址:https://tianchi.aliyun.com/competition/entrance/231784/introduction?spm=5176.12281957.1004.1.38b02448ausjSX
主要内容
常见的特征工程主要包括异常值处理,特征归一化/标准化,数据分桶,缺失值处理,特征构造,特征筛选,降维等。
首先导入需要的包:
import pandas as pd
import numpy as np
import matplotlib
from matplotlib import pyplot as plt
import seaborn
from operator import itemgetter
%matplotlib inline
导入数据,查看一下形状:
Train_data = pd.read_csv('C:\\Users\\lzf33\\Desktop\\used_car_train_20200313.csv',sep = ' ')
Train_data = pd.read_csv('C:\\Users\\lzf33\\Desktop\\used_car_train_20200313.csv',sep = ' ')
print(Train_data.shape)
print(Test_data.shape)
输出如下,可以看到训练集有150000个样本,30个特征(31列是因为包含y)测试集有5000个样本,30个特征(不包含y)
可以简单查看一下数据,这里不贴结果了:
Train_data.head()
Train_data.columns
Test_data.head()
test_data.columns
同样可以看一下简单的统计量,数据类型等
Train_data.describe()
Train_data.info()
Test_data.describe()
test_data.info()
异常值
通常异常值的处理主要包括剔除异常值(3sigma原则),BOX-COX转换(处理有偏分布),长尾截断等等。
下面是阿泽封装的剔除异常值代码:
def outliers_proc(data, col_name, scale=3):
"""
用于清洗异常值,默认用 box_plot(scale=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
# 以power这个特征看一下结果
Train_data = outliers_proc(Train_data,'power',scale = 3)
BOX-COX转换,如下:
以对数转换为例,可以看一下转换前后的数据对比
他的原理大概是对数转换能够把很小教密的数据转换得相对稀疏一点,大一点较稀疏的点转化的相对密集一点,这个可以根据下图,以x,y轴分别画一个密度图观察一下。会发现左右两边的数据慢慢向中间靠拢了。
特征归一化、标准化
标准化将数据转化为均值为0,方差为1的数据。归一化将数据转换到 [0,1] 的区间,来克服度量不一致的问题。
def normalization(data):
_range = np.max(data) - np.min(data)
return (data - np.min(data)) / _range
def standardization(data):
mu = np.mean(data, axis=0)
sigma = np.std(data, axis=0)
return (data - mu) / sigma
数据分桶
Bin values into discrete intervals,将值划分到离散区间。好比不同大小的苹果归类到几个事先布置的箱子中;不同年龄的人划分到几个年龄段中。数据分桶的意义在于:
- 离散后稀疏向量内积乘法运算速度更快,计算结果也方便存储,容易扩展;
- 离散后的特征对异常值更具鲁棒性,如 age>30 为 1 否则为 0,对于年龄为 200 的也不会对模型造成很大的干扰;
- LR 属于广义线性模型,表达能力有限,经过离散化后,每个变量有单独的权重,这相当于引入了非线性,能够提升模型的表达能力,加大拟合;
- 离散后特征可以进行特征交叉,提升表达能力,由 M+N 个变量编程 M*N 个变量,进一步引入非线形,提升了表达能力;
- 特征离散后模型更稳定,如用户年龄区间,不会因为用户年龄长了一岁就变化
使用pandas的cat函数可以实现分桶:
pandas.cut(x, bins, right=True, labels=None, retbins=False, precision=3, include_lowest=False, duplicates='raise')
# x:被切分的类数组数据,注意必须是1维;
# bins:简单理解为分箱规则,就是桶。支持int 标量、序列;
# right:表示是否包含区间的右边界,默认包含;
# labels:分割后的bins打标签;
# retbins:表示是否将分割后的bins返回,默认不返回;
# precision:保留区间小数点的位数,默认为3;
# include_lowest: bool型的参数,表示区间的左边是开还是闭的,默认为false,也就是不包含区间左部(闭);
# duplicates: 是否允许重复区间。
1)等宽分箱:将变量的取值范围分为k个等宽的区间,每个区间当作一个分箱。
2)等频分箱:把观测值按照从小到大的顺序排列,根据观测的个数等分为k部分,每部分当作一个分箱,例如,数值最小的1/k比例的观测形成第一个分箱。
缺失值处理
有些模型不需要处理缺失值,如XGBoost模型,当数据缺失太多时,可以删除特征,当数据缺失不是很严重是可以采用插值补全的方法,可以用均值、中位数、众数建模预测、多重插补、压缩感知补全、矩阵补全等等。或者采用分箱的方法,将缺失值作为一个单独的箱。
特征构造
可以参考:https://www.csdn.net/gather_22/MtTaggwsMDUzMi1ibG9n.html
特征筛选
特征筛选主要是为了降低噪声和计算复杂度,增加模型预测能力。特征筛选一般有过滤式,包裹式和嵌入式:
1)过滤式:先对数据进行特征选择,然后在训练学习器,常见的方法有 Relief/方差选择发/相关系数法/卡方检验法/互信息法;
2)包裹式:直接把最终将要使用的学习器的性能作为特征子集的评价准则,常见方法有 LVM(Las Vegas Wrapper)
3)嵌入式:结合过滤式和包裹式,学习器训练过程中自动进行了特征选择,常见的有 lasso 回归;
降维
PCA,LDA等,可参考:https://blog.csdn.net/qq_15719037/article/details/80454113
不平衡数据
特征工程方法一般是重采样,包括欠采样(减少多数类)和过采样(增加少数类),一般简单随机采样可能造成过拟合或者信息丢失等问题,所以可以采用SMOTE算法。当然处理不平衡数据可以在算法层面引入代价敏感方法,加大对少数类样本错分类的惩罚代价。评价不平衡数据问题可以采用AUC,因为它的计算不涉及到样本比例,所以能够较好的衡量模型性能。
参考
https://tianchi.aliyun.com/competition/entrance/231784/introduction?spm=5176.12281957.1004.1.38b02448ausjSX
https://tianchi.aliyun.com/notebook-ai/detail?spm=5176.12586969.1002.9.1cd8593anAZBvP&postId=95501
https://www.csdn.net/gather_22/MtTaggwsMDUzMi1ibG9n.html
https://blog.csdn.net/qq_15719037/article/details/80454113