在特征工程之特征选择中,咱们讲到了特征选择的一些要点。本篇咱们继续讨论特征工程,不过会重点关注于特征表达部分,即若是对某一个特征的具体表现形式作处理。主要包括缺失值处理,特殊的特征处理好比时间和地理位置处理,离散特征的连续化和离散化处理,连续特征的离散化处理几个方面。html
特征有缺失值是很是常见的,大部分机器学习模型在拟合前须要全部的特征都有值,不能是空或者NULL。那么若是有缺失值咱们须要怎么处理呢?python
首先咱们会看是该特征是连续值仍是离散值。若是是连续值,那么通常有两种选择,一是选择全部有该特征值的样本,而后取平均值,来填充缺失值,另外一种是取中位数来填充缺失值。若是是离散值,则通常会选择全部有该特征值的样本中最频繁出现的类别值,来填充缺失值。在sklearn中,可使用preprocessing.Imputer来选择这三种不一样的处理逻辑作预处理。算法
有些特征的默认取值比较特殊,通常须要作了处理后才能用于算法。好比日期时间,好比显示20180519,这样的值通常没办法直接使用。那么通常须要如何变换呢?微信
对于时间原始特征,处理方法有不少,这里只举例几种有表明性的方法。 第一种是使用连续的时间差值法,即计算出全部样本的时间到某一个将来时间之间的数值差距,这样这个差距是UTC的时间差,从而将时间特征转化为连续值。第二种方法是根据时间所在的年,月,日,星期几,小时数,将一个时间特征转化为若干个离散特征,这种方法在分析具备明显时间趋势的问题比较好用。第三种是权重法,即根据时间的新旧获得一个权重值。好比对于商品,三个月前购买的设置一个较低的权重,最近三天购买的设置一个中等的权重,在三个月内可是三天前的设置一个较大的权重。固然,还有其余的设置权重的方法,这个要根据要解决的问题来灵活肯定。app
对地理特征,好比“广州市天河区XX街道XX号”,这样的特征咱们应该如何使用呢?处理成离散值和连续值都是能够的。若是是处理成离散值,则须要转化为多个离散特征,好比城市名特征,区县特征,街道特征等。可是若是咱们须要判断用户分布区域,则通常处理成连续值会比较好,这时能够将地址处理成经度和纬度的连续特征。机器学习
有不少机器学习算法只能处理连续值特征,不能处理离散值特征,好比线性回归,逻辑回归等。那么想使用逻辑回归,线性回归时这些值只能丢弃吗?固然不是。咱们能够将离散特征连续化处理。post
最多见的离散特征连续化的处理方法是独热编码one-hot encoding。处理方法其实比较简单,好比某特征的取值是高,中和低,那么咱们就能够建立三个取值为0或者1的特征,将高编码为1,0,0这样三个特征,中编码为0,1,0这样三个特征,低编码为0,0,1这样三个特征。也就是说,以前的一个特征被咱们转化为了三个特征。sklearn的OneHotEncoder能够帮咱们作这个处理。学习
第二个方法是特征嵌入embedding。这个通常用于深度学习中。好比对于用户的ID这个特征,若是要使用独热编码,则维度会爆炸,若是使用特征嵌入就维度低不少了。对于每一个要嵌入的特征,咱们会有一个特征嵌入矩阵,这个矩阵的行很大,对应咱们该特征的数目。好比用户ID,若是有100万个,那么嵌入的特征矩阵的行就是100万。可是列通常比较小,好比能够取20。这样每一个用户ID就转化为了一个20维的特征向量。进而参与深度学习模型。在tensorflow中,咱们能够先随机初始化一个特征嵌入矩阵,对于每一个用户,能够用tf.nn.embedding_lookup找到该用户的特征嵌入向量。特征嵌入矩阵会在反向传播的迭代中优化。优化
此外,在天然语言处理中,咱们也能够用word2vec将词转化为词向量,进而能够进行一些连续值的后继处理。编码
离散特征有时间也不能直接使用,须要先进行转化。好比最多见的,若是特征的取值是高,中和低,那么就算你须要的是离散值,也是无法直接使用的。
对于原始的离散值特征,最经常使用的方法也是独热编码,方法在第三节已经讲到。
第二种方法是虚拟编码dummy coding,它和独热编码相似,可是它的特色是,若是咱们的特征有N个取值,它只须要N-1个新的0,1特征来代替,而独热编码会用N个新特征代替。好比一个特征的取值是高,中和低,那么咱们只须要两位编码,好比只编码中和低,若是是1,0则是中,0,1则是低。0,0则是高了。目前虚拟编码使用的没有独热编码广,所以通常有须要的话仍是使用独热编码比较好。
此外,有时候咱们能够对特征进行研究后作一个更好的处理。好比,咱们研究商品的销量对应的特征。里面有一个原始特征是季节春夏秋冬。咱们能够将其转化为淡季和旺季这样的二值特征,方便建模。固然有时候转化为三值特征或者四值特征也是能够的。
对于分类问题的特征输出,咱们通常须要用sklearn的LabelEncoder将其转化为0,1,2,...这样的类别标签值。
对于连续特征,有时候咱们也能够将其作离散化处理。这样特征变得高维稀疏,方便一些算法的处理。
对经常使用的方法是根据阈值进行分组,好比咱们根据连续值特征的分位数,将该特征分为高,中和低三个特征。将分位数从0-0.3的设置为高,0.3-0.7的设置为中,0.7-1的设置为高。
固然还有高级一些的方法。好比使用GBDT。在LR+GBDT的经典模型中,就是使用GDBT来先将连续值转化为离散值。那么如何转化呢?好比咱们用训练集的全部连续值和标签输出来训练GBDT,最后获得的GBDT模型有两颗决策树,第一颗决策树有三个叶子节点,第二颗决策树有4个叶子节点。若是某一个样本在第一颗决策树会落在第二个叶子节点,在第二颗决策树落在第4颗叶子节点,那么它的编码就是0,1,0,0,0,0,1,一共七个离散特征,其中会有两个取值为1的位置,分别对应每颗决策树中样本落点的位置。在sklearn中,咱们能够用GradientBoostingClassifier的 apply方法很方便的获得样本离散化后的特征,而后使用独热编码便可。
具体的一个示例代码以下:
from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split from sklearn.ensemble import GradientBoostingClassifier from sklearn.preprocessing import OneHotEncoder X, y = make_classification(n_samples=10) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5) gbc = GradientBoostingClassifier(n_estimators=2) one_hot = OneHotEncoder() gbc.fit(X_train, y_train) X_train_new = one_hot.fit_transform(gbc.apply(X_train)[:, :, 0]) print (X_train_new.todense())
输出是:
[[0. 1. 1. 0.]
[1. 0. 0. 1.]
[1. 0. 0. 1.]
[1. 0. 0. 1.]
[0. 1. 1. 0.]]
本文总结了特征表达的一些具体方法, 可是特征表达的方法便不止于上文中的方法,毕竟这是工程实践。可是上文中的方法是比较广泛的,但愿能够给你们一些帮助和启发。 下一篇咱们讨论特征预处理和分类类别不平衡的问题处理。
(欢迎转载,转载请注明出处。欢迎沟通交流: 微信:nickchen121)