导语: 总所周知,机器学习中特征工程处于十分重要的位置,整个学习中至少会花二分之一甚至更多的时间用于特征工程至少(对于统计学习)。但是如何能够有效地实现特征的自动化扩展、组合和量化,大家都会有各自的方法,但也是相对较繁杂且可控性不太好的方法。本文将结合我在特征自动化实现中的一些发现与大家分享,希望能够对大家的工作有所帮助。
机器学习是通过机器来处理大量的、有效的数据来获得我们所需的信息,因此学习其本质就是处理海量数据并训练模型、寻找规则的过程。由著名的“天下没有免费的午餐”等可知,机器学习中特征工程的作用是不言而喻的。然而除了对特征关联性的求解外,特征的量化和变换也是十分重要的。这就类似于侦探在分析案件时能够很好地通过现有的信息找到关键线索,并且将这些线索转成有利的破案证据,以及将这些线索进行组合和处理找到新的线索。然而在做特征量化和特征扩展的过程中,通常会遇到如下三个问题:
1、特征简单量化后无意义、不可解释:如数据中存在城市这样的特征且假设有100个城市,简单处理就是将每个城市映射成一个阿拉伯数字如下左图。
[1505962663317_9389_1505962663641.png] [1505962683988_9020_1505962684199.png]
学习结果中可能会出现上右图的效果,不禁发问这样的划分是啥意思呢?南方、北方,还是西方、东方呢?还是说这样的特征可解释性差就不用了呢?
2、特征扩展和组合可控性不好:对于离散特征不愿将其丢掉,而是想通过特征值打平(扩展)的形式使用,如上述中城市的特征,可以扩成是否是深圳、是否是上海,......,是否是南京这样100个特征,这样就能够将这样城市的特征考虑进去。还有当如果存在有特征组合的需求时,如想了解人们购物的习惯,那么就可能将性别和省市组合起来成为一个新的特征。想了解消费者购房的情况,那么可能将年龄和收入组合成一个新的特征等。
特征的扩展和组合在学习中很有用,大家通常使用不可控、全量展开的独热编码(One-Hot-Encoding)。但当出现有很多长尾的特征值的时候,就会展开或组合成很多没有意义的特征,这样会大大消耗我们的计算资源和降低我们的执行效率。如用户城市这样的特征,可能聚集的也就是100个以内(大多为国内),但是业务是全球的所以还有几千个城市的量都是个位这样很小的。如果这样需要扩展和组合的特征不可控那么效果是很差的。
如下图所示左边的图是量相对大的特征值,也是我们想要处理的特征值,而右图则是长尾的特征值,其量很少以至于我们认为这样的特征值在训练中是不会有影响的。
3、当离散特征是类似衣服大小码(M、L、XL等)数据时,我们希望能够使用上这样的可比较大小的特征,但是这样的数据中也会存在有一部分数据量较大可单独存在,而有一部分数据量很好我们希望设定这样的数据为其他。如下图所示,特征值中可能就0和1占量交大我们希望单独成为一个节点,而剩余的量很少的特征值(可能有100个、1000个.........)我们之希望他们为“其他”。
现在大家在遇到离散特征时的处理方式主要有有种(我所了解和资料显示的)。第一种就是在做前期数据分析的时候,将想要扩展和组合的数据提前处理好,在做数据处理的时候就把这样的数据给处理成特征数据。但是是人工处理,而且基本是写死成数据的,后期模型训练中不易调整。第二种是使用类似独热编码(One-Hot-Encoding)的方案,将特征值全量打开实现特征的自动化扩展。但是数据是全量打开,以至过程和结果是不可控的,且可能存在无意义特征的爆炸导致不可计算或者计算效率低等。
这里讲到了独热编码(One-Hot-Encoding),简单的介绍以下:
独热编码即 One-Hot 编码,又称一位有效编码,其方法是使用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候,其中只有一位有效。例如:
自然状态码为:000,001,010,011,100,101
独热编码为:000001,000010,000100,001000,010000,100000
可以这样理解,对于每一个特征,如果它有m个可能值,那么经过独热编码后,就变成了m个二元特征。并且,这些特征互斥,每次只有一个激活。因此,数据会变成稀疏的。
from sklearn import preprocessing
enc = preprocessing.OneHotEncoder()
enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]])
enc.transform([[0, 1, 3]]).toarray()
输出结果:
array([[ 1., 0., 0., 1., 0., 0., 0., 0., 1.]])
其实python中pandas的get_dummies也可以实现独热编码(One-Hot-Encoding)的效果:
df_tmp = pandas.get_dummies(df[‘client_city’])
df = df + df_tmp
本文的方法主要是通过将要处理的离散特征的特征值情况进行展现,然后基于其实际情况进行有选择可控制的特征自动化扩展和组合。通过使用这样的方法可以很好地解决背景中存在的问题,并且可以独立成为特征模块应用于不同的学习过程。本方法的大前提是类似2/8的原则,海量数据学习过程中,有效的影响因素一定是相对量较大的,如果量很少则认为其为可不考虑因素。如有一个100万的训练集或者更多,其中有几个量较大的值且之和为总和的95%以上。剩下的还有许多特征值每个不到100的量,之和也是总和的很小一部分。那么我们就可以认为我们不需要展开、组合这些量很小的特征值,或者可以将这部分特征值定位“其他”。
方法如下:
1、产生离散特征值的量的情况:通过循环多个离散特征,使用python中pandas的value_counts()函数(如df‘sip_city’.value_counts()),或者Java中的Map等。将各个离散特征值的量以倒叙的形式存放在数据结构中,或者保存到项目本地的文件中。
2、处理排序后的特征值:该步骤十分关键,控制了参与扩展和组合的特征值,以及特征值展示效果(确定哪些是“其他”,或者分等级等)。实现方式有:
a. 通过打开文件或者展示数据结构中的数据情况,手动的进行删除或合并操作;
b. 设置比例阀值,如设置value=10%,那么可以自动实现对小于总量10%的特征值进行自动删除或合并操作;
c. 设置个数阀值,如设置value=10,那么就可以自动地选择量排在前10的特征值进行扩展或组合操作;
d. 当然也可以通过不删除或合并任何特征值,实现类似的独热编码全量的效果。
3、基于选择、处理后的特征值扩展特征:遍历所有的处理过的离散特征(features),每一个特征逐个顺序取每个特征值作为一个新特征(feature_key ),并且这样的特征是特征值的yes or no的情况(也就是等于该特征值为1,否则为0)。如python实现如下:
for feature in features:
file = filePath + feature + ".csv"
if (os.path.isfile(file)):
lines = open(file).readlines()
for line in lines:
key = line.split(',')[0]
df[feature+'_'+key] = df[feature].apply(lambda x: 1 if x == key else 0)
4、基于选择、处理后的特征值组合特征:很多时候我们希望一些特征之间能够通过组合产生新的特征,这些组合特征有时会表现出非常好的效果。如性别和省市组合,我们可以研究不同省市男、女购物的偏爱等。Python实现如下:
for feature1_value in feature1s:
for feature2_value in feature2s:
key = str('%s_%s_%s_%s'%(feature1,feature2,feature1_value,
feature2_value))
df[key] = map(lambda x,y:do_equal(x,y,feature1_value,feature2_value)
,df[feature1],df[feature2])
5、特征量化:原有离散特征或产生的新特征,都可能是以字符串或中文等形式存在的值,需要对这样的特征进行量化后才可进行训练。Python实现如下:
keys = []
for feature_value in features:
keys.append(feature_value)
other = len(keys)
new_feature = df[feature].apply(lambda x:keys.index(x) if keys.__contains__(x) else str(other))
df[feature] = new_feature
6、关键特征的规范化:训练结束后特征可能因为编码问题,或者需要以特定的形式展示,所以需要对结果特征或关键特征做规范化处理。这时可以通过不同的算法模型的特性获取其结果特征,并通过预设值或者修改的方式进行规范化。
特征工程对于机器学习来说是十分重要的,上述的一些方法是我在做机器学习过程中的一点积累。可以针对具体的问题使用其中的一个或者多个方式,也可以是基于这些方式的进一步优化。当然,特征还应该做与结果指标关联性分析,这个就可以根据具体的数据选择相应的关联算法实现。最后,希望大家可以多花些时间在数据质量和特征工程上,必将为你带来令你满意的效果。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。