特征工程之类别特征
系外行星研究生 微信公众号:计算机视觉cv博主
2 人赞同了该文章
类别特征
一个类别特征,见名思义,就是用来表达一种类别或标签。比如,一个类别特征能够表达世界上的主要城市,一年四季,或者说一个公司的产品(石油、路程、技术)。在真实世界的数据集中,类别值的数量总是无限的。同时这些值一般可以用数值来表示。但是,与其他数值变量不一样的是,类别特征的数值变量无法与其他数值变量进行比较大小。(作为行业类型,石油与旅行无法进行比较)它们被称之为非序的。
一个简单的问题可以作为测试是否应该是一个分类变量的试金石测试:“两个价值有多么不同,或者只是它们不同?”500美元的股票价格比100美元的价格高5倍。 所以股票价格应该用一个连续的数字变量表示。 另一方面,公司的产业(石油,旅游,技术等)应该无法被比较的,也就是类别特征。
大的分类变量在交易记录中特别常见。 对于实例中,许多Web服务使用id作为分类变量来跟踪用户具有数百至数百万的值,取决于唯一的数量服务的用户。 互联网交易的IP地址是另一个例子一个很大的分类变量。 它们是分类变量,因为即使用户ID和IP地址是数字,它们的大小通常与任务无关在眼前。 例如,在进行欺诈检测时,IP地址可能是相关的个人交易。 某些IP地址或子网可能会产生更多欺骗性交易比其他人。 但是164.203.x.x
的子网本质上并不多欺诈性比164.202.x.x
; 子网的数值无关紧要。
文档语料库的词汇可以被解释为一个大的分类变量,类别是唯一的单词。 它可能在计算上很昂贵代表如此多的不同类别。 如果一个类别(例如,单词)出现多个数据点(文档)中的时间,然后我们可以将它表示为一个计数并表示所有的类别通过他们的统计数字。 这被称为bin-counting。 我们用分类变量的共同表示开始讨论,并且最终蜿蜒曲折地讨论了大范围的bin-counting问题变量,这在现代数据集中非常普遍。
对类别特征进行编码
分类变量的类别通常不是数字。例如,眼睛的颜色可以是“黑色”,“蓝色”,“棕色”等。因此,需要使用编码方法将这些非数字类别变为数字。 简单地将一个整数(比如1到k)分配给k个可能的类别中的每一个都是诱人的。 但是,由此产生的价值观可以互相授权,这在类别中不应该被允许。
One-hot 编码
将类别特征进行表示一个最好的办法就是使用一组比特位来表达。每一位代表一个可能的类别。 如果该变量不能一次成为多个类别,那么该组中只有一位可以是1。 这被称为独热编码,它在Scikit Learn中实现sklearn.preprocessing.OneHotEncoder。 每个位都是一个特征。 因此是一个绝对的具有k个可能类别的变量被编码为长度为k的特征向量。
表5-1 对3个城市的类别进行独热编码
Citye1e2e3San Francisco100New York010Seattle001
独热编码非常易于理解。 但它使用的是比严格必要的更多的一点。 如果我们看到k-1位是零,那么最后一位必须是1,因为变量必须具有k个值中的一个。 在数学上,可以写下这个约束条件为“所有位的和必须等于1”。
等式 5-1. 独热编码e1,e2,e3
限制条件。
因此,我们有一个线性的依赖性。 线性相关特征,就像我们一样在tfidf
中发现,有点烦人,因为它意味着训练线性模型不会是唯一的。 特征的不同线性组合可以做出同样的预测,所以我们需要跳过额外条件的来理解特征对预测的影响。
dummy编码
独热编码的问题是它允许个自由度,其中变量本身只需要
。 虚拟编码通过仅使用表示中的
个特征来消除额外的自由度。
公共汽车下面有一个特征,由全零向量表示。 这被称为参考类别。 虚拟编码和独热编码都是在Pandas中以pandas.get_dummies的形式实现的。
表5-2 对3个城市的类别进行dummy编码
Citye1e2San Francisco10New York01Seattle00
使用虚拟编码进行建模的结果比单编码更易解释。这很容易在简单的线性回归问题中看到。 假设我们有一些数据关于三个城市的公寓租赁价格:旧金山,纽约和西雅图。(见表5-3)
表5-3 三个不同城市的公寓价格数据集
idcityRent0SF39991SF40002SF40013NYC34994NYC35005NYC35016Seattle24997Seattle25008Seattle2501
图5-1 公寓租金价格在one-hot编码中的向量空间表示。点的大小表达了数据集中租金不同价格的平均数。
我们这时能够仅仅依靠城市这一个变量来建立线性回归来预测租金的价格。
线性回归模型可以这样写
习惯上我们还添加一个常量来,这样的话当全部为0,
不会为0.
例5-1.在独热编码上的线性回归
import pandas as pd
from sklearn import linear_model
df = pd.DataFrame({
'City':
['SF', 'SF', 'SF', 'NYC', 'NYC', 'NYC', 'Seattle', 'Seattle', 'Seattle'],
'Rent': [3999, 4000, 4001, 3499, 3500, 3501, 2499, 2500, 2501]
})
df['Rent'].mean()
输出3333.3333333333335
one_hot_df = pd.get_dummies(df, prefix=['city'])
one_hot_df
输出:
model = linear_model.LinearRegression()
model.fit(one_hot_df[['city_NYC', 'city_SF', 'city_Seattle']],
one_hot_df[['Rent']])
model.coef_
输出array([[ 166.66666667, 666.66666667, -833.33333333]])
使用dummy code进行回归
dummy_df = pd.get_dummies(df, prefix=['city'], drop_first=True)
dummy_df
输出:
model.fit(dummy_df[['city_SF', 'city_Seattle']], dummy_df['Rent'])
输出:LinearRegression(copy_X=True, fit_intercept=True, n_jobs=None, normalize=False)
print(model.coef_)
print(model.intercept_)
输出:array([ 500., -1000.])
3500.0
通过独热编码,截距项表示目标变量的全局均值租金价格,并且每个线性系数表示该城市的平均租金与全局平均值的差异。
通过虚拟编码,偏差系数代表响应的平均值参考类别的变量y,在这个例子中是纽约市。该第i个特征的系数等于平均响应之间的差异第i类别的值和参考类别的平均值。
表5-4:线性回归学得的系数
idx1x2x3bone-hot166.67666.67-833.333333.33dummy coding0500-10003500
Effect编码
分类变量编码的另一种变体称为Effect编码。 Effect编码与虚拟编码非常相似,区别在于参考类别现在由所有-1的向量表示。
表5-5: Effect编码表示3个城市
Citye1e2San Francisco10New York01Seattle-1-1
Effect编码与虚拟编码非常相似,但是在线性回归中更容易被拟合。例子5-2表达了运行机理。截距项表示目标的全球平均值变量,单个系数表示各个类别的平均值与全球平均值有多少差异。 (这被称为类别或级别的主要效果,因此名称为“效果编码”。)独热编码实际上具有相同的截距和系数,但在这种情况下,每个城市都有线性系数。 在效果编码中,没有单一特征代表参考类别。 因此,参考类别的影响需要分别计算为所有其他类别的系数的负和。(查看what is effect coding?)
例子5-2 Effect编码的线性回归
effect_df = dummy_df.copy()
effect_df.loc[3:5, ['city_SF', 'city_Seattle']] = -1.0
effect_df
输出:
model.fit(effect_df[['city_SF', 'city_Seattle']], effect_df['Rent'])
输出:LinearRegression(copy_X=True, fit_intercept=True, n_jobs=None, normalize=False)
print(model.coef_)
print(model.intercept_)
输出:array([ 666.66666667, -833.33333333])
3333.3333333333335
类别变量的优点和缺点
独热,虚拟和效果编码非常相似。 他们每个人都有优点和缺点。 独热编码是多余的,它允许多个有效模型一样的问题。 非唯一性有时候对解释有问题。该优点是每个特征都明显对应于一个类别。 此外,失踪数据可以编码为全零矢量,输出应该是整体目标变量的平均值。
虚拟编码和效果编码不是多余的。 他们产生独特和可解释的模型。 虚拟编码的缺点是它不能轻易处理缺少数据,因为全零矢量已经映射到参考类别。它还编码每个类别相对于参考类别的影响,其中看起来很奇怪。 效果编码通过使用不同的代码来避免此问题参考类别。 但是,所有-1的矢量都是一个密集的矢量,对于存储和计算来说都很昂贵。 因此,Pandas和Scikit Learn等流行的ML软件包选择了虚拟编码或独热编码,而不是效应编码。当类别数量变得非常多时,所有三种编码技术都会失效大。 需要不同的策略来处理非常大的分类变量。
处理大量的类别特征
互联网上的自动数据收集可以生成大量的分类变量。这在诸如定向广告和欺诈检测等应用中很常见。 在有针对性的广告中,任务是根据用户的搜索查询或当前页面将用户与一组广告进行匹配。 功能包括用户ID,广告的网站域,搜索查询,当前页面以及这些功能的所有可能的成对连词。 (查询是一个文本字符串,可以切分成常用的文本特征,但查询通常很短,通常由短语组成,因此在这种情况下最好的行为通常是保持完整,或 通过哈希函数来简化存储和比较,我们将在下面更详细地讨论哈希。)其中每一个都是一个非常大的分类变量。 我们面临的挑战是如何找到一个能够提高内存效率的优秀特征表示,并生成训练速度快的准确模型。
对于这种类别特征处理的方案有:
- 对编码不做任何事情。 使用便宜的训练简单模型。 在许多机器上将独热编码引入线性模型(逻辑回归或线性支持向量机)。
- 压缩编码,有两种方式
- a. 对特征进行哈希--在线性回归中特别常见
- b. bin-counting--在线性回归中与树模型都常见
使用one-hot编码是可行的。在微软搜索广告研究中,Graepel等人 [2010]报告在贝叶斯概率回归模型中使用这种二值特征,可以使用简单更新在线进行培训。 与此同时,其他组织则争论压缩方法。 来自雅虎的研究人员 通过特征散列方式[Weinberger et al.2009年]。 尽管McMahan等人[2013]在谷歌的广告引擎上尝试了功能哈希,并没有找到显着的改进。 然而,微软的其他人则被认为是计数[Bilenko,2015]。
我们将会看到,所有这些想法都有利有弊。 我们将首先描述解决方案本身,然后讨论他们的权衡。
特征哈希
散列函数是一个确定性函数,它映射一个潜在的无界整数到有限整数范围。 由于输入域可能大于输出范围,多个数字可能会映射到相同的输出。 这被称为a碰撞。 统一的散列函数可确保大致相同数量的数字被映射到每个
箱。 在视觉上,我们可以将散列函数视为一台机器可以吸入编号的球并将它们传送到一个m箱。 球与相同的号码将始终被路由到同一个bin。
散列函数可以为任何可以用数字表示的对象构造(对于可以存储在计算机上的任何数据都是如此):数字,字符串,复杂的结构等。
当有很多特征时,存储特征向量可能占用很多空间。 特征散列将原始特征向量压缩为m维通过对特征ID应用散列函数来创建矢量。 例如,如果原件特征是文档中的单词,那么散列版本将具有固定的词汇大小为m,无论输入中有多少独特词汇。
例5-3 对单词的特征哈希
def hash_features(word_list, m):
output = [0] * m
for word in word_list:
index = hash_fcn(word) % m
output[index] += 1
return output
功能散列的另一个变体添加了一个符号组件,因此计数也是从哈希箱中增加或减少。 这确保了内部产品之间散列特征与原始特征的期望值相同。
def hash_features(word_list, m):
output = [0] * m
for word in word_list:
index = hash_fcn(word) % m
sign_bit = sign_hash(word) % 2
if (sign_bit == 0):
output[index] -= 1
else:
output[index] += 1
return output
哈希后内积的值在时间复杂度在O(1/(m**0.5))
.所以哈希表m的大小可以根据可接受的错误来选择。在实践中,选择合适的m可能需要一些试验和错误。特征哈希可以用于涉及特征内积的模型矢量和系数,例如线性模型和核心方法。 它一直证明在垃圾邮件过滤任务中取得成功[Weinberger等,2009]。在有针对性的广告案例中,McMahan et al. [2013年]报告不能将预测误差降低到可接受的水平,除非m的数量级为数十亿。散列特征的一个缺点是散列特征是聚合的原始特征,不再可解释。
在这个例子中,我们将使用Yelp评论数据集来演示存储和,解释性使用的为sklearn的库FeatureHasher
。
import pandas as pd
import json
js = []
#data文件夹下的数据集需要自己下载
with open('data/yelp_academic_dataset_review.json') as f:
for i in range(10000):
js.append(json.loads(f.readline()))
review_df = pd.DataFrame(js)
m = len(review_df.business_id.unique())
from sklearn.feature_extraction import FeatureHasher
h = FeatureHasher(n_features=m, input_type='string')
f = h.transform(review_df['business_id'])
review_df['business_id'].unique().tolist()[0:5]
输出:['9yKzy9PApeiPPOUJEtnvkg', 'ZRJwVLyzEJq1VAihDhYiow', '6oRAC4uyJCsJl1X0WZpVSA', '_1QQZuf4zZOyFCvXc0o6Vg', '6ozycU1RpktNG2-1BroVtw']
print(f.toarray())
输出:array([[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]])
我们看看特征的存储
from sys import getsizeof
print('Our pandas Series, in bytes: ', getsizeof(review_df['business_id']))
print('Our hashed numpy array, in bytes: ', getsizeof(f))
输出:Our pandas Series, in bytes: 790104 Our hashed numpy array, in bytes: 56
我们可以清楚地看到如何使用特征散列会以计算方式使我们受益,牺牲直接的用户解释能力。 这是一个容易的权衡来接受何时从数据探索和可视化发展到机器学习管道对于大型数据集。
发布于 05-01
=============================================================================================
特征工程(四)HashingVectorizer
Datawhale 2018-09-23 19:19:46 1848
收藏 2
分类专栏: 达观杯nlp算法比赛总结
版权
'''
将原始数据的word特征数字化为hash特征,并将结果保存到本地
article特征可做类似处理
'''
import pandas as pd
from sklearn.feature_extraction.text import HashingVectorizer
import pickle
import time
t_start = time.time()
"""=====================================================================================================================
1 加载原始数据
"""
# 读取原始数据train和test文件
df_train=pd.read_csv('train_set.csv')
df_test=pd.read_csv('test_set.csv')
# 删除特征article,只保留特征word
df_train.drop(columns='article', inplace=True)
df_test.drop(columns='article', inplace=True)
# 按行拼接df_train和df_test
df_all = pd.concat(objs=[df_train, df_test], axis=0, sort=True)
# 获取train文件中的特征class
y_train = (df_train['class'] - 1).values
"""=====================================================================================================================
2 特征工程
"""
print('2 特征工程')
# 将原始数据数字化为hash特征
vectorizer = HashingVectorizer(ngram_range=(1, 2), n_features=200)
d_all = vectorizer.fit_transform(df_all['word_seg'])
x_train = d_all[:len(y_train)]
x_test = d_all[len(y_train):]
"""=====================================================================================================================
3 保存至本地
"""
print('3 保存特征')
data = (x_train.toarray(), y_train, x_test.toarray())
with open('hash_word.pkl', 'wb') as f:
pickle.dump(data,f)
t_end = time.time()
print("共耗时:{}min".format((t_end-t_start)/60))
# 共耗时:4.8min
================================================================================================
十二种特征工程相关技术简介
机器学习 作者:dicksonjyl560101 时间:2019-06-24 20:20:37 5473 0
https://www.toutiao.com/a6705743599167865347/
本文主要包含的目录如下:
- 一、简介
- 二、错误数据和缺失值
- 三、特征的种类
- 四、特征工程技巧
- 4.1、分箱(Binning)
- 4.2、独热编码(One-Hot Encoding)
- 4.3、特征哈希(Hashing Trick)
- 4.4、嵌套法(Embedding)
- 4.5、取对数(Log Transformation)
- 4.6、特征缩放(Scaling)
- 4.7、标准化(Normalization)
- 4.8、特征交互(Feature Interaction)
- 五、时间特征处理
- 5.1、分箱法
- 5.2、趋势线(Treadlines)
- 5.3、事件贴近(Closeness to major events)
- 5.4、时间差(Time Difference)
一、简介
机器学习的特征工程是将原始的输入数据转换成特征,以便于更好的表示潜在的问题,并有助于提高预测模型准确性的过程。
找出合适的特征是很困难且耗时的工作,它需要专家知识,而应用机器学习基本也可以理解成特征工程。但是,特征工程对机器学习模型的应用有很大影响,有句俗话叫做“数据和特征决定了机器学习模型的性能上限”。
二、错误数据和缺失值
特征工程之前需要对 缺失数据 和 错误数据 进行处理。错误数据可以矫正,有的错误是格式错误,如日期的格式可能是“201·8-09-19”和“20180920”这种混合的,要统一。
缺失数据的处理:
- 去掉所在行/列
- 取均值
- 中位数
- 众数
- 使用算法预测
三、特征的种类
机器学习的输入特征包括几种:
数值特征:包括整形、浮点型等,可以有顺序意义,或者无序数据。
分类特征:如ID、性别等。
时间特征:时间序列如月份、年份、季度、日期、小时等。
空间特征:经纬度等,可以转换成邮编,城市等。
文本特征:文档,自然语言,语句等,这里暂时不介绍处理。
四、特征工程技巧
4.1、分箱(Binning)
数据分箱(Binning)是一种数据预处理技术,用于减少轻微观察错误的影响。落入给定小间隔bin的原始数据值由代表该间隔的值(通常是中心值)代替。这是一种量化形式。 统计数据分箱是一种将多个或多或少连续值分组为较少数量的“分箱”的方法。例如,如果您有关于一组人的数据,您可能希望将他们的年龄安排到较小的年龄间隔。对于一些时间数据可以进行分箱操作,例如一天24小时可以分成早晨[5,8),上午[8,11),中午[11,14),下午[14,19),夜晚[10,22),深夜[19,24)和[24,5)。因为比如中午11点和12点其实没有很大区别,可以使用分箱技巧处理之后可以减少这些“误差”。
4.2、独热编码(One-Hot Encoding)
独热编码(One-Hot Encoding)是一种数据预处理技巧,它可以把类别数据变成长度相同的特征。例如,人的性别分成男女,每一个人的记录只有男或者女,那么我们可以创建一个维度为2的特征,如果是男,则用(1,0)表示,如果是女,则用(0,1)。即创建一个维度为类别总数的向量,把某个记录的值对应的维度记为1,其他记为0即可。对于类别不多的分类变量,可以采用独热编码。
4.3、特征哈希(Hashing Trick)
对于类别数量很多的分类变量可以采用特征哈希(Hashing Trick),特征哈希的目标就是将一个数据点转换成一个向量。利用的是哈希函数将原始数据转换成指定范围内的散列值,相比较独热模型具有很多优点,如支持在线学习,维度减小很多灯。具体参考数据特征处理之特征哈希(Feature Hashing)。
4.4、嵌套法(Embedding)
嵌套法(Embedding)是使用神经网络的方法来将原始输入数据转换成新特征,嵌入实际上是根据您想要实现的任务将您的特征投影到更高维度的空间,因此在嵌入空间中,或多或少相似的特征在它们之间具有小的距离。 这允许分类器更好地以更全面的方式学习表示。例如,word embedding就是将单个单词映射成维度是几百维甚至几千维的向量,在进行文档分类等,原本具有语义相似性的单词映射之后的向量之间的距离也比较小,进而可以帮助我们进一步进行机器学习的应用,这一点比独热模型好很多。
4.5、取对数(Log Transformation)
取对数就是指对数值做log转换,可以将范围很大的数值转换成范围较小的区间中。Log转换对分布的形状有很大的影响,它通常用于减少右偏度,使得最终的分布形状更加对称一些。它不能应用于零值或负值。对数刻度上的一个单位表示乘以所用对数的乘数。在某些机器学习的模型中,对特征做对数转换可以将某些连乘变成求和,更加简单,这不属于这部分范围了。
如前所述,log转换可以将范围很大的值缩小在一定范围内,这对某些异常值的处理也很有效,例如用户查看的网页数量是一个长尾分布,一个用户在短时间内查看了500个和1000个页面都可能属于异常值,其行为可能差别也没那么大,那么使用log转换也能体现这种结果。
4.6、特征缩放(Scaling)
特征缩放是一种用于标准化独立变量或数据特征范围的方法。 在数据处理中,它也称为数据标准化,并且通常在数据预处理步骤期间执行。特征缩放可以将很大范围的数据限定在指定范围内。由于原始数据的值范围变化很大,在一些机器学习算法中,如果没有标准化,目标函数将无法正常工作。 例如,大多数分类器按欧几里德距离计算两点之间的距离。 如果其中一个要素具有宽范围的值,则距离将受此特定要素的控制。 因此,应对所有特征的范围进行归一化,以使每个特征大致与最终距离成比例。
应用特征缩放的另一个原因是梯度下降与特征缩放比没有它时收敛得快得多。特征缩放主要包括两种:
- 最大最小缩放(Min-max Scaling)
- 标准化缩放(Standard(Z) Scaling)
4.7、标准化(Normalization)
在最简单的情况下,标准化意味着将在不同尺度上测量的值调整到概念上的共同尺度。在更复杂的情况下,标准化可以指更复杂的调整,其中意图是使调整值的整个概率分布对齐。在一般情况下,可能有意将分布与正态分布对齐。
在统计学的另一种用法中,标准化上将不同单位的数值转换到可以互相比较的范围内,避免总量大小的影响。标准化后的数据对于某些优化算法如梯度下降等也很重要。
4.8、特征交互(Feature Interaction)
在回归模型中加入交互项是一种非常常见的处理方式。它可以极大的拓展回归模型对变量之间的依赖的解释。具体参见回归模型中的交互项简介(Interactions in Regression)。
五、时间特征处理
几乎所有的时间特征都要处理,时间特征有序列性,其顺序有意义。这里简单列举几种处理方式。
5.1、分箱法
这是最常用的方法,如前面所述。有时候11点与12点之间差别并没有意义,可以采用上述分箱法处理。
5.2、趋势线(Treadlines)
多使用趋势量而不是总量来编码,例如使用上个星期花销,上个月花销,去年的花销,而不是总花销。两个总花销相同的客户可能在消费行为上有很大差别。
5.3、事件贴近(Closeness to major events)
假日之前几天,每个月第一个周六等。这种重要时间节点附近的值可能更有意义。
5.4、时间差(Time Difference)
上次用户交互的时间到这次用户交互时间间隔,这种时间差别意义也很大。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/29829936/viewspace-2648602/,如需转载,请注明出处,否则将追究法律责任。