业界流传一句话:数据和特征决定了机器学习的上限,而模型和算法只是无限逼近这个上线而已。
一、什么是特征工程
特征工程本质是一项工程活动,目的是最大限度地从原始数据中提取特征以供算法和模型使用。
二、特征工程的目标
1、对于特征进行进一步分析,并对于数据进行处理
2、完成对于特征工程的分析,并对于数据进行一些图表或者文字总结
三、特征工程包括内容介绍
1、异常处理
通过箱线图(或3-Sigma)分析删除异常值
BOX-COX转换(处理有偏分布)
长尾截断
2、特征归一化、标准化
标准化(转换为标准正太分布)
归一化(抓换到[0,1]区间)
3、数据分桶
等频分桶
等距分桶
Best-Ks分桶(类似利用基尼指数进行二分类)
卡方分桶
4、缺失值处理
不处理(针对类似XGBoost等树模型)
删除(缺失数据太多)
插值补全,包括均值、中位数、众数、建模预测、多重插补、压缩感知补全、矩阵补全等
分箱,缺失值一个箱
5、特征构造
构造统计量特征,报告计数、求和、比例、标准差等
时间特征,包括相对时间和绝对时间,节假日、双休日等
地理信息,包括分箱、分布编码等方法
非线性变换,包括log、平方、根号等
特征组合,特征交叉
6、特征筛选
过滤式(filter):先对数据进行特征选择,然后在训练学习器,常见的方法有Relief、方差选择法、相关系数法、卡方检验法、互信息法
包裹式(wrapper):直接把最终将要使用的学习器的性能作为特征子集的评价准则,常见方法有LVM(Las Vegas Wrapper)
嵌入式(embedding):结合过滤式和包裹式,学习器训练过程中自动进行了特征选择,常见的有lasso回归;
7、降维
PCA、LDA、ICA
特征选择也是一种降维
四、案例详解
from sklearn.datasets import load_iris
导入IRIS数据集
iris = load_iris()
特征矩阵
iris.data
print ("iris_shape",iris.data.shape)
目标向量
iris.target
print ("target_vector",iris.target.shape)
import pandas as pd
import numpy as np
filepath = "/home/yanyongqiang/datawhale_study/Iris.csv"
iris_data = pd.read_csv(filepath,header=None,names=['sepal_length','sepal_width','petal_length','petal_width','target'])
iris_data.head(4)
iris_data.describe() #进行探索阶段分析(EDA)
iris_data.target.unique() #判断有几类
%matplotlib inline
iris_data.boxplot()
%matplotlib inline
iris_df.plot(kind='density')
iris_data.boxplot(column='sepal_length',by='target')
使用preproccessing库的StandardScaler类对数据进行标准化的代码如下:
from sklearn.preprocessing import StandardScaler
标准化,返回值为标准化后的数据
StandardScaler().fit_transform(iris.data)
array([[ -9.00681170e-01, 1.03205722e+00, -1.34127240e+00,
-1.31297673e+00],
[ -1.14301691e+00, -1.24957601e-01, -1.34127240e+00,
-1.31297673e+00],
...
--- 例子就是如下,他是对列也就是同一特征下进行缩放,而不是对一个数据的不同特征之间(行)进行缩放 ---
from sklearn.preprocessing import StandardScaler
data = np.array([[1,2],[3,4],[5,6]]).reshape(3,2)
print data
[[1 2]
[3 4]
[5 6]]
print np.mean(data,axis=0) # 计算每一列均值 [ 3. 4.]
print np.std(data,axis=0) # 计算每一列标准差 [ 1.63299316 1.63299316]
print (data[0][0]-np.mean(data,axis=0)[0])/np.std(data,axis=0)[0] # 计算第一个元素的标准化后的值 -1.22474487139
区间缩放,返回值为缩放到[0, 1]区间的数据
StandardScaler().fit_transform(data)
array([[-1.22474487, -1.22474487],
[ 0. , 0. ],
[ 1.22474487, 1.22474487]])
使用preproccessing库的MinMaxScaler类对数据进行区间缩放的代码如下:
from sklearn.preprocessing import MinMaxScaler
区间缩放,返回值为缩放到[0, 1]区间的数据
MinMaxScaler().fit_transform(iris.data)
array([[ 0.22222222, 0.625 , 0.06779661, 0.04166667],
[ 0.16666667, 0.41666667, 0.06779661, 0.04166667],
[ 0.11111111, 0.5 , 0.05084746, 0.04166667],
...
--- 例子就是如下,他是对列也就是同一特征下进行缩放,而不是对一个数据的不同特征之间(行)进行缩放 ---
from sklearn.preprocessing import MinMaxScaler
data = np.array([[1,2],[3,4],[5,6]]).reshape(3,2)
print data
[[1 2]
[3 4]
[5 6]]
区间缩放,返回值为缩放到[0, 1]区间的数据
MinMaxScaler().fit_transform(data)
array([[ 0. , 0. ],
[ 0.5, 0.5],
[ 1. , 1. ]])
使用preproccessing库的Normalizer类对数据进行归一化的代码如下:
from sklearn.preprocessing import Normalizer
归一化,返回值为归一化后的数据
Normalizer().fit_transform(iris.data)
--- 例子就是如下,他是对一行数据的不同特征进行处理 ---
from sklearn.preprocessing import Normalizer
import math
data = np.array([[1,2],[3,4],[5,6]]).reshape(3,2)
print data
[[1 2]
[3 4]
[5 6]]
print data[0][0]/math.sqrt((data[0][0])2 + (data[0][1])2) # 计算第一个元素L2正则化后的值 0.4472135955
规范化
Normalizer().fit_transform(data)
array([[-1.22474487, -1.22474487],
[ 0. , 0. ],
[ 1.22474487, 1.22474487]])
使用preproccessing库的Binarizer类对数据进行二值化的代码如下:
from sklearn.preprocessing import Binarizer
二值化,阈值设置为3,返回值为二值化后的数据
Binarizer(threshold=3).fit_transform(iris.data)
preproccessing库的OneHotEncoder类对数据进行哑编码的代码如下:
from sklearn.preprocessing import OneHotEncoder
哑编码,对IRIS数据集的目标值,返回值为哑编码后的数据
OneHotEncoder().fit_transform(iris.target.reshape((-1,1)))
使用preproccessing库的Imputer类对数据进行缺失值计算的代码如下:
import numpy as np
from sklearn.preprocessing import Imputer
imp = Imputer(missing_values='NaN', strategy='mean', axis=0) # 使用特征的均值进行填充,其余还有使用众数填充等,只需要把mean改成median即可
data = np.array([np.nan, 2, 6, np.nan, 7, 6]).reshape(3,2)
print data
[[ nan 2.]
[ 6. nan]
[ 7. 6.]]
print imp.fit_transform(data)
[[ 6.5 2. ]
[ 6. 4. ]
[ 7. 6. ]]
使用preproccessing库的PolynomialFeatures类对数据进行多项式转换的代码如下:
from sklearn.preprocessing import PolynomialFeatures
多项式转换
参数degree为度,默认值为2
PolynomialFeatures().fit_transform(iris.data)
使用decomposition库的PCA类选择特征的代码如下:
from sklearn.decomposition import PCA
主成分分析法,返回降维后的数据
参数n_components为主成分数目
PCA(n_components=2).fit_transform(iris.data)
--- 例子 ---
from sklearn.decomposition import PCA,KernelPCA
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
iris_data = load_iris()
category = pd.Categorical(iris_data.target) # 将标签进行量化,就是说本来都是字符串啊,但是最后计算的时候都需要量化成1,2,3类等
pca_2c = PCA(n_components=2) # 使用PCA降到2维
pca_2c = KernelPCA(n_components=2)
x_pca_2c = pca_2c.fit_transform(iris_data.data)
x_pca_2c.shape
plt.scatter(x_pca_2c[:,0],x_pca_2c[:,1],c=category.codes)
plt.show()
使用lda库的LDA类选择特征的代码如下:
from sklearn.lda import LDA
线性判别分析法,返回降维后的数据
参数n_components为降维后的维数
LDA(n_components=2).fit_transform(iris.data, iris.target)
--- 例子 ---
LDA相较于pca是有监督的,但不能用于回归分析
from sklearn.lda import LDA
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
iris_data = load_iris()
category = pd.Categorical(iris_data.target) # 将标签进行量化,就是说本来都是字符串啊,但是最后计算的时候都需要量化成1,2,3类等
lda_2c = LDA(n_components=2)
x_pca_2c = lda_2c.fit_transform(iris_data.data,iris_data.target)
x_pca_2c.shape
plt.scatter(x_pca_2c[:,0],x_pca_2c[:,1],c=category.codes)
plt.show()
五、经验总结
特征工程是比赛中最至关重要的的一块,特别的传统的比赛,大家的模型可能都差不多,调参带来的效果增幅是非常有限的,但特征工程的好坏往往会决定了最终的排名和成绩。
特征工程的主要目的还是在于将数据转换为能更好地表示潜在问题的特征,从而提高机器学习的性能。比如,异常值处理是为了去除噪声,填补缺失值可以加入先验知识等。
特征构造也属于特征工程的一部分,其目的是为了增强数据的表达。
有些比赛的特征是匿名特征,这导致我们并不清楚特征相互直接的关联性,这时我们就只有单纯基于特征进行处理,比如装箱,groupby,agg 等这样一些操作进行一些特征统计,此外还可以对特征进行进一步的 log,exp 等变换,或者对多个特征进行四则运算(如上面我们算出的使用时长),多项式组合等然后进行筛选。由于特性的匿名性其实限制了很多对于特征的处理,当然有些时候用 NN 去提取一些特征也会达到意想不到的良好效果。
对于知道特征含义(非匿名)的特征工程,特别是在工业类型比赛中,会基于信号处理,频域提取,丰度,偏度等构建更为有实际意义的特征,这就是结合背景的特征构建,在推荐系统中也是这样的,各种类型点击率统计,各时段统计,加用户属性的统计等等,这样一种特征构建往往要深入分析背后的业务逻辑或者说物理原理,从而才能更好的找到 magic。
当然特征工程其实是和模型结合在一起的,这就是为什么要为 LR NN 做分桶和特征归一化的原因,而对于特征的处理效果和特征重要性等往往要通过模型来验证。
总的来说,特征工程是一个入门简单,但想精通非常难的一件事。
六、学习总结
通过不断的学习数据挖掘的基础知识,我发现数据挖掘、机器学习、深度学习等这些都是触类旁通的,处理的方式,过程等都差不太多。由于有机器学习的基础,python等用的还挺熟悉,所以学习数据挖掘的基础知识还是很顺利的,接下来希望自己更加努力和队员小伙伴一起更上一层楼。
对于简书发布附件不知道怎么搞,所以代码的py文件,我就直接把内容粘贴文章中了。
参考:https://www.jianshu.com/p/1c4ec02dd33f
网友评论