机器学习——特征工程之分类变量

  • 前言
  • 分类变量的编码
    • 1、one-hot 编码
    • 2、虚拟编码
    • 3、效果编码
  • 处理大型分类变量
    • 1、特征散列化
    • 2、分箱计数
  • 总结

前言

关于特征工程,已经对空值、数值型和文本数据的处理做了大致方法的说明,这篇对数据类型中的另一大重要部分——分类变量,作处理方法总结。

声明:关于编程语法相关问题不会展开论述,本文只针对方法路线

分类变量的编码

先说明什么样的数据被称为分类变量:分类变量是用来表示类别或标记的,例如西瓜书(周志华的,应该都知道的吧)中西瓜数据集里的色泽(青绿,乌黑,浅白)、纹理(清晰,稍糊)等。更加不好处理的情况是,这些分类变量与数值变量掺杂在一起作为整个数据集,如下图(仅截取一部分):
但是,在实际的数据集中,类别的数量总是有限的,为了参与数学算法运算(特别是回归),一定要将分类变量转成数值型,可以用数字表示,但与数值型变量不同,分类变量不能被排序(尽最大可能要避免有顺序)。

1、one-hot 编码

one-hot使用一组比特位,每个比特位表示一种可能的类别。每一个比特位表示一个特征,因此,一个可能有k个类别的分类器就可以编码为一个长度为K的特征向量。
**举例:**使用原数据集中(自己建立)的一个分类变量的列作为例子,该列原始数据如下:

df = pd.DataFrame({"City":["SF","SF","SF","NYC","NYC","NYC","Seattle","Seattle","Seattle"],"Rent":[3999,300,3333,2222,4444,888,88888,44443,3222]})City   Rent
0       SF   3999
1       SF    300
2       SF   3333
3      NYC   2222
4      NYC   4444
5      NYC    888
6  Seattle  88888
7  Seattle  44443
8  Seattle   3222

可以看到,该数据集有两个属性,一个为分类变量,一个为数值型变量。使用pandas中的get_dummies(pd,col)一键one-hot。
代码如下:

ont_hot_df = pd.get_dummies(df,["City"])

一键one-hot后,原数据集就变成了:

    Rent  City_NYC  City_SF  City_Seattle
0   3999         0        1             0
1    300         0        1             0
2   3333         0        1             0
3   2222         1        0             0
4   4444         1        0             0
5    888         1        0             0
6  88888         0        0             1
7  44443         0        0             1
8   3222         0        0             1

仅在该属性有值的位置取1,其余为0。
one-hot缺点:

  1. 分类较多时,会造成冗余,使得同一个问题有多个有效模型;
  2. 分类较多时,不可避免地会造成维数灾难;
  3. List item很明显,对于one-hot编码,各行的和一定等于1,即存在线性关系,线性相关的特征会使训练出的模型不唯一。特征的不同线性组合可以做出同样的预测,所以需要做些额外的努力才能理解某个特征对预测结果的作用。

2、虚拟编码

如果一个样本中有k个分类,one-hot编码会产生k个自由度,但是变量本身只需要k-1个自由度,虚拟编码在进行表示时只使用k-1 个特征,除去了额外的自由度。
这么说有点绕,不好理解,下面举个例子:

             e1      e2
San Francisco    1       0
New York         0       1
Seattle          0       0

上面有三个分类,使用one-hot编码应该有3(k)列(自由度),但是虚拟编码将其中的一类通过一个全零向量表示,它被称为参照类(上例中的“Seattle”)。
代码:

dummy_df = pd.get_dummies(df, prefix=['city'], drop_first=True)

结果(如果看不明白虚拟编码和one-hot编码的话,可以用下表与上面one-hot后的表作下对比):

 Rent    city_SF city_Seattle
0   3999        1.0      0.0
1   4000        1.0      0.0
2   4001        1.0      0.0
3   3499        0.0      0.0
4   3500        0.0      0.0
5   3501        0.0      0.0
6   2499        0.0      1.0
7   2500        0.0      1.0
8   2501        0.0      1.0

使用虚拟编码的好处: 使用虚拟编码的模型结果比使用one-hot 编码的模型结果更具解释性**,没有冗余。(具体实际效果只能使用交叉验证来选择则编码方式)

缺点: 不直观,全零向量不太容易处理缺失数据。

3、效果编码

效果编码与虚拟编码非常相似,简单地说,区别就在于参照类由全零向量改成了全-1向量,如下:

             e1      e2
San Francisco    1       0
New York         0       1
Seattle         -1      -1

效果编码需要在虚拟编码的基础上,将参照类的全零向量改成全-1向量:
代码:

ffect_df = dummy_df.copy()  #dummy_df为上面虚拟编码后的数据集
effect_df.ix[3:5, ['city_SF', 'city_Seattle']] = -1.0

效果如下(注意对比):

 Rent    city_SF city_Seattle
0   3999        1.0      0.0
1   4000        1.0      0.0
2   4001        1.0      0.0
3   3499       -1.0     -1.0
4   3500       -1.0     -1.0
5   3501       -1.0     -1.0
6   2499        0.0      1.0
7   2500        0.0      1.0
8   2501        0.0      1.0

效果编码使用另外一种编码表示参照类,从而避免了虚拟编码存在的问题,但是全由-1 组成的向量是个密集向量,计算和存储的成本都比较高。正是因为这个原因,像Pandas 和scikit-learn这样的常用机器学习软件包更喜欢使用虚拟编码或one-hot 编码,而不是效果编码。

处理大型分类变量

当类别的数量变得非常大时,上面介绍的3种编码方式都会出现问题,所以需要另外的策略来处理超大型分类变量。
处理大型分类变量的目标:既要内存高效,又能生成精确的、训练速度很快的模型。
现有的解决方案可以分类如下。
(1) 不在编码问题上搞什么花样,使用一个简单、容易训练的模型,在很多机器上使用one-hot 编码训练线性模型(逻辑回归或线性支持向量机)。
(2) 压缩特征,有两种方式。
a) 特征散列化,通常用于线性模型。
b) 分箱计数,常用于线性模型和树模型。
one-hot编码上面已经说完了,下面谁基于特征的处理方法。

1、特征散列化

先放一张图:

图中的散列函数 (有点类似于哈希化)是一种确定性函数,他可以将一个可能无界的整数映射到一个有限的整数范围[1,m]中。

举例: 图中的每一个单词可以看成一个分类,散列函数经过算法,将每一分类映射成一个散列值

因为输入域可能大于输出范围,所以可能有多个值被映射为同样的输出,这称为碰撞。均匀散列函数可以确保将大致相同数量的数值映射到m 个分箱中。
代码:

from sklearn.feature_extraction import FeatureHasherh = FeatureHasher(n_features=m, input_type='string')

举例:

from sklearn.feature_extraction import FeatureHasher
h = FeatureHasher(n_features = 3,input_type='string')
f = h.transform(df["City"])
print(f.toarray())
结果:[[-1.  0. -1.][-1.  0. -1.][-1.  0. -1.][-2.  0. -1.][-2.  0. -1.][-2.  0. -1.][-3.  2.  2.][-3.  2.  2.][-3.  2.  2.]]

优点:特征散列化对计算能力大有裨益
缺点:牺牲了直观的用户可解释性

2、分箱计数

思想:分箱计数不使用分类变量的值作为特征,而是使用目标变量取这个值的概率。换个说法,不对分类变量的值进行编码,而是计算分类变量值与要预测的目标变量之间的相关统计量。

假设有10000个分类变量,one-hot 编码会生成一个长度为10 000 的稀疏向量,只在对应当前数据点的列上有一个1。分箱计数会将所有10 000 个二值列编码为一个单独的特征,是0和1 之间的一个实数值。简而言之,分箱计数将一个分类变量转换为与其值相关的统计量,它可以将一个大型的、稀疏的、二值的分类变量表示(如one-hot 编码生成的结果)转换为一个小巧的、密集的、实数型的数值表示。
举例:

import pandas as pd
# 使用这个超过6GB的数据集的前10 000行作为训练集
df = pd.read_csv('data/train_subset.csv')
# 看看训练集中有多少个唯一的特征
len(df['device_id'].unique())
7201
# 对每个类别,我们要计算:
# Theta = [counts, p(click), p(no click), p(click)/p(no click)]
def click_counting(x, bin_column):clicks = pd.Series(x[x['click'] > 0][bin_column].value_counts(),name='clicks')no_clicks = pd.Series(x[x['click'] < 1][bin_column].value_counts(),name='no_clicks')counts = pd.DataFrame([clicks,no_clicks]).T.fillna('0')counts['total_clicks'] = counts['clicks'].astype('int64') +counts['no_clicks'].astype('int64')return counts
def bin_counting(counts):counts['N+'] = counts['clicks'].astype('int64').divide(counts['total_clicks'].astype('int64'))counts['N-'] = counts['no_clicks'].astype('int64').divide(counts['total_clicks'].astype('int64'))counts['log_N+'] = counts['N+'].divide(counts['N-'])# 如果只想返回分箱属性就进行过滤bin_counts = counts.filter(items= ['N+', 'N-', 'log_N+'])return counts, bin_counts# 分箱计数示例:device_id
bin_column = 'device_id'
device_clicks = click_counting(df.filter(items=[bin_column, 'click']),bin_column)
device_all, device_bin_counts = bin_counting(device_clicks)
# 检查一下,确定我们处理了所有设备
print(len(device_bin_counts))
7201
print(device_all.sort_values(by = 'total_clicks', ascending=False).head(4))
#结果clicks   no_clicks   total       N+         N-      log_N+
a99f214a    15729   71206       86935   0.180928 0.819072 0.220894
c357dbff    33      134         167     0.197605 0.802395 0.246269
31da1bd0    0       62          62      0.000000 1.000000 0.000000
936e92fb    5       54          59      0.084746 0.915254 0.092593

后面还有关于如何处理稀有类、防止数据泄露、无界计数等情况的处理方法,以后如果遇到了再详细的说吧!

总结

对分类变量说了这么方法,下面总结下各自的优缺点:

one-hot编码
|优点:  容易实现、可能是最精确的、可用于在线学习
|缺点: 计算效率不高、不能适应可增长的类别、只适用于线性模型、对于大数据集,需要大规模的分布式优化特征散列化
|优点: • 容易实现• 模型训练成本更低• 容易适应新类别• 容易处理稀有类• 可用于在线学习
|缺点 :• 只适合线性模型或核方法• 散列后的特征无法解释• 精确度难以保证
分箱计数
优点: • 训练阶段的计算负担最小• 可用于基于树的模型• 比较容易适应新类别• 可使用 back-off 方法或最小计数图处理稀有类• 可解释
缺点: • 需要历史数据• 需要延迟更新,不完全

机器学习——特征工程之分类变量相关推荐

  1. 特征工程:分类变量的处理方式总结

    1.什么是分类变量? 通常来说,分类变量是用来表示某一属性的类别或标识的.例如:一年中的四季,月份,OS,brand,行业(银行.保险.券商.科技......),地区等等:大型分类变量例如:IP地址, ...

  2. python特征工程有序变量处理_R与Python手牵手:特征工程(分类变量)

    作者:黄天元,复旦大学博士在读,热爱数据科学与R,热衷推广R在业界的应用.邮箱:huang.tian-yuan@qq.com.欢迎交流! 这次给大家分享的是对分类变量进行特征工程.很多时候我们会遇到一 ...

  3. 双样本T检验——机器学习特征工程相关性分析实战

    最近在做数据分析方面的工作,经常需要检验两组样本之间是否存在差异,所以会遇到统计学中假设检验相关的知识.在机器学习特征工程这一步,笔者最常用到的是假设检验中的卡方检验去做特征选择,因为卡方检验可以做两 ...

  4. 机器学习-特征工程中的特征选择

    对于一个机器学习问题,数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限.由此可见,数据和特征在模型的整个开发过程中是比较重要.特征工程,顾名思义,是对原始数据进行一系列工程处理,将其提炼为 ...

  5. 机器学习-特征工程中的数据预处理

    对于一个机器学习问题,数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限.由此可见,数据和特征在模型的整个开发过程中是比较重要.特征工程,顾名思义,是对原始数据进行一系列工程处理,将其提炼为 ...

  6. 机器学习实战 | 机器学习特征工程最全解读

    作者:韩信子@ShowMeAI 教程地址:https://www.showmeai.tech/tutorials/41 本文地址:https://www.showmeai.tech/article-d ...

  7. 机器学习-特征工程中的特征降维

    对于一个机器学习问题,数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限.由此可见,数据和特征在模型的整个开发过程中是比较重要.特征工程,顾名思义,是对原始数据进行一系列工程处理,将其提炼为 ...

  8. 机器学习——特征工程——数据的标准化(Z-Score,Maxmin,MaxAbs,RobustScaler,Normalizer)

    数据标准化是一个常用的数据预处理操作,目的是处理不同规模和量纲的数据,使其缩放到相同的数据区间和范围,以减少规模.特征.分布差异等对模型的影响. 比如线性回归模型.逻辑回归模型或包含矩阵的模型,它们会 ...

  9. 探讨使用UML设计机器学习特征工程与深度学习建模等大数据分析软件

    大数据人工智能软件产品研发,是在传统软件工程的基础上,增加了数据特征分析.人工智能算法建模及模型训练过程,同时也增加了很大的不确定性. 0. 前言 本文以程序员视角,以客户流失为案例,使用UML方式设 ...

最新文章

  1. MySQL面试题 | 附答案解析(五)
  2. qpython3安装lxml_centos python安装lxml报错
  3. PhoneGap API帮助文档翻译—Camera (摄像头)
  4. 集群节点列表编辑程序
  5. 对 *.google.com/* 产品进行大规模的 CSRFing 研究,意外获得3万美元奖金
  6. 编译lzlib mysql5.6_CentOS下编译安装MySQL5.6
  7. php unset引用变量后不会删除值
  8. Unity AssetBundle加载的理解
  9. 【微信小程序】(一)开发工具下载与界面介绍
  10. 李明洋十讲学会ADS教学课程笔记
  11. torch.nn.Module.parameters(recurse=True)
  12. php fpm配置和php.ini,php安装完后配置php.ini和php-fpm.conf
  13. APP下载量全面概述,含统计方法
  14. linux下读取ntfs数据,在Linux中读取NTFS分区上的数据
  15. StringUtils常用方法(五)
  16. 软件测试论文参考文献
  17. 计算H时M分S秒以后是_消防考试必会计算题汇总!
  18. 腾讯云部署hexo博客系统
  19. NDCG评价指标讲解
  20. 字节跳动大数据研发面试——自我反省

热门文章

  1. Java学习路线(语法基础+算法与数据结构部分)
  2. python中map的使用
  3. linux如何判断是文件还是目录
  4. 北京奥运会-欢迎焰火
  5. 关于Bean标签的一些属性以及getBean()方法
  6. php调用Python找不到模块,从php调用python脚本不导入所需模块
  7. skynet中actor模型
  8. Matplotlib中annotate详解
  9. 【Simulink 仿真】SISO Fading Channel模块介绍
  10. Nginx使用SSL加密并隐藏真实地址详细教程