作者:陈颖祥、杨子晗

编译:AI有道

基于 Jupyter 的特征工程手册:数据预处理的上一篇:

专栏 | 基于 Jupyter 的特征工程手册:数据预处理(一)

项目地址:

https://github.com/YC-Coder-Chen/feature-engineering-handbook

本项目将探讨数据预处理部分:介绍了如何利用 scikit-learn 处理静态的连续变量,利用 Category Encoders 处理静态的类别变量以及利用 Featuretools 处理常见的时间序列变量。

目录

特征工程的数据预处理我们将分为三大部分来介绍:

  • 静态连续变量

  • 静态类别变量

  • 时间序列变量

本文将介绍 1.2 静态类别变量的数据预处理(上部分,即1.2.1-1.2.6)。下面将结合 Jupyter,使用 sklearn,进行详解。

1.2 Static Categorical Variables 静态类别变量

真实世界的数据集还往往包含类别特征。但是由于scikit-learn中的模型只能处理数值特征,因此我们需要将类别特征编码为数值特征但是,很多新的模型开始直接提供类别变量支持,例如lightGBM和Catboost。这里我们使用category_encoders包,因为它涵盖了更多的编码方法。

1.2.1 Ordinal Encoding 序数编码

序数编码将类别变量转化为一列序数变量,包含从1到类别数量之间的整数

import numpy as np
import pandas as pd
from category_encoders import OrdinalEncoder
# category_encoders 直接支持dataframe# 随机生成一些训练集
train_set = pd.DataFrame(np.array([['male',10],['female', 20], ['male',10], ['female',20],['female',15]]),columns = ['Sex','Type'])
train_y = np.array([False, True, True, False, False])# 随机生成一些测试集, 并有意让其包含未在训练集出现过的类别与缺失值
test_set = pd.DataFrame(np.array([['female',20],['male', 20], ['others',15], ['male',20],['female',40], ['male', 25]]),columns = ['Sex','Type'])
test_set.loc[4,'Type'] = np.nan
train_set # 原始训练集

test_set # 原始测试集

encoder = OrdinalEncoder(cols = ['Sex', 'Type'], handle_unknown = 'value', handle_missing = 'value').fit(train_set,train_y) # 在训练集上训练
# 将 handle_unknown设为‘value’,即测试集中的未知特征值将被标记为-1
# 将 handle_missing设为‘value’,即测试集中的缺失值将被标记为-2
# 其他的选择为:‘error’:即报错;‘return_nan’:即未知值/缺失之被标记为nan
encoded_train = encoder.transform(train_set) # 转换训练集
encoded_test = encoder.transform(test_set) # 转换测试集# 以测试集结果为例
encoded_test# 在序数编码中:# 变量Sex中: 'male' => 1.0, 'female' => 2.0, 未知 => -1.0, 缺失值 => -2.0
# (事实上,测试集中完全有可能出现未知与缺失情况)
# 在我们的例子中, Sex这一变量中的'other' 类别从未在训练集中出现过# 变量 Type 中: 10 => 1.0, 20 => 2.0, 15 => 3.0, 未知 => -1.0, 缺失值 => -2.0

encoded_train.astype(float) # 训练集结果

1.2.2 One-hot Encoding 独热编码

Scikit-learn中也提供来独热编码函数,其可以将具有n_categories个可能值的一个分类特征转换为n_categories个二进制特征,其中一个为1,所有其他为0在category_encoders中,它包含了附加功能,即指示缺失或未知的值。在这里,我们继续使用category_encoders

import numpy as np
import pandas as pd
from category_encoders import OneHotEncoder
# category_encoders 直接支持dataframe# 随机生成一些训练集
train_set = pd.DataFrame(np.array([['male',10],['female', 20], ['male',10], ['female',20],['female',15]]),columns = ['Sex','Type'])
train_y = np.array([False, True, True, False, False])# 随机生成一些测试集, 并有意让其包含未在训练集出现过的类别与缺失值
test_set = pd.DataFrame(np.array([['female',20],['male', 20], ['others',15], ['male',20],['female',40], ['male', 25]]),columns = ['Sex','Type'])
test_set.loc[4,'Type'] = np.nan
train_set # 原始训练集

test_set  # 原始测试集

encoder = OneHotEncoder(cols=['Sex', 'Type'], handle_unknown='indicator', handle_missing='indicator', use_cat_names=True).fit(train_set,train_y) # 在训练集上训练
encoded_train = encoder.transform(train_set) # 转换训练集
encoded_test = encoder.transform(test_set) # 转换测试集
# 将 handle_unknown设为‘indicator’,即会新增一列指示未知特征值
# 将 handle_missing设为‘indicator’,即会新增一列指示缺失值
# 其他的handle_unknown/handle_missing 的选择为:
# ‘error’:即报错; ‘return_nan’:即未知值/缺失之被标记为nan; ‘value’:即未知值/缺失之被标记为0# 以测试集结果为例
encoded_test# 在独热编码中:# 变量 Sex => 变为了4个新变量: 'male' => [1 ,0 ,0, 0];
#                           'female' => [0 ,1 ,0, 0];
#                           未知 =>  [0 ,0 ,0, 1];
#                           缺失 => [0, 0, 1, 0];# 变量 Type => 变为了5个新变量: 10 => [1, 0, 0, 0, 0];
#                            20 => [0, 1, 0, 0, 0];,
#                            15 => [0, 0, 1, 0, 0];
#                            未知 => [0, 0, 0, 0, 1];
#                            缺失 => [0, 0, 0, 1, 0];

1.2.3 Hashing Encoding 哈希编码

哈希编码基于特征哈希的方法。它将哈希函数应用于变量,将任意数量的变量以一定的规则映射到给定数量的变量。特征哈希可能会导致要素之间发生冲突。但哈希编码的优点是它不需要制定和维护原变量与新变量之间的映射关系。因此,哈希编码器的大小及复杂程度不随数据类别的增多而增多。

import numpy as np
import pandas as pd
from category_encoders.hashing import HashingEncoder
# category_encoders 直接支持dataframe# 随机生成一些训练集
train_set = pd.DataFrame(np.array([['male',10],['female', 20], ['male',10], ['female',20],['female',15]]),columns = ['Sex','Type'])
train_y = np.array([False, True, True, False, False])# 随机生成一些测试集, 并有意让其包含未在训练集出现过的类别与缺失值
test_set = pd.DataFrame(np.array([['female',20],['male', 20], ['others',15], ['male',20],['female',40], ['male', 25]]),columns = ['Sex','Type'])
test_set.loc[4,'Type'] = np.nan
train_set # 原始训练集

test_set # 原始测试集

encoder = HashingEncoder(cols=['Sex', 'Type'],  n_components = 5).fit(train_set,train_y)
encoded_train = encoder.transform(train_set) # 转换训练集
encoded_test = encoder.transform(test_set) # 转换测试集# 将两列的数据集哈希编码为5列
# 哈希编码结果与训练集/测试集中的内容无关
# 只要列名匹配,我们就可以在任何新数据集上使用哈希编码方法
# 编码结果仅由哈希函数确定# 通常哈希编码应用于更高和更稀疏的维空间,这里以两个变量作为哈希编码的例子
# 以测试集结果为例
encoded_test

encoded_train # 训练集结果

1.2.4 Helmert Encoding Helmert 编码

Helmert编码通常在计量经济学中使用。在Helmert编码(分类特征中的每个值对应于Helmert矩阵中的一行)之后,线性模型中编码后的变量系数可以反映在给定该类别变量某一类别值的情形下因变量的平均值与给定该类别其他类别值的情形下因变量的平均值的差值。在category_encoders包中实现的Helmert编码为反向Helmert编码。更多信息:

https://www.statsmodels.org/devel/contrasts.html

import numpy as np
import pandas as pd
from category_encoders import HelmertEncoder
# category_encoders 直接支持dataframe# 随机生成一些训练集
train_set = pd.DataFrame(np.array([['male',10],['female', 20], ['male',10], ['female',20],['female',15]]),columns = ['Sex','Type'])
train_y = np.array([False, True, True, False, False])# 随机生成一些测试集, 并有意让其包含未在训练集出现过的类别与缺失值
test_set = pd.DataFrame(np.array([['female',20],['male', 20], ['others',15], ['male',20],['female',40], ['male', 25]]),columns = ['Sex','Type'])
test_set.loc[4,'Type'] = np.nan
train_set # 原始训练集

test_set # 原始测试集

encoder = HelmertEncoder(cols=['Sex', 'Type'], handle_unknown='indicator', handle_missing='indicator').fit(train_set,train_y) # 在训练集上训练
encoded_train = encoder.transform(train_set) # 转换训练集
encoded_test = encoder.transform(test_set) # 转换测试集
# 将 handle_unknown设为‘indicator’,即会新增一列指示未知特征值
# 将 handle_missing设为‘indicator’,即会新增一列指示缺失值
# 其他的handle_unknown/handle_missing 的选择为:
# ‘error’:即报错; ‘return_nan’:即未知值/缺失之被标记为nan; ‘value’:即未知值/缺失之被标记为0# 以测试集结果为例
encoded_test# 在Helmert编码中:# 变量 Sex => 变为了4个新变量(包含常数项): 'male' => [ 1. -1. -1. -1.];
#                                      'female' => [ 1.  1. -1. -1.];
#                                      未知 =>  [ 1.  0.  0.  3.];
#                                      缺失 => [ 1.  0.  2. -1.];# 变量 Type => 变为了5个新变量(包含常数项): 10 => [ 1. -1. -1. -1. -1.];
#                                        20 => [ 1.  1. -1. -1. -1.];,
#                                        15 => [ 1.  0.  2. -1. -1.];
#                                        未知 =>  [ 1.  0.  0.  0.  4.];
#                                        缺失 => [ 1.  0.  0.  3. -1.];

# 可以通过如下代码计算变量Type的Helmert 矩阵from patsy.contrasts import Helmert
levels = [1,2,3,4,5] # 3个变量值 + 1个未知值 + 1个缺失值
contrast = Helmert().code_with_intercept(levels)
print(contrast.matrix) # 第一列为常数项
[[ 1. -1. -1. -1. -1.][ 1.  1. -1. -1. -1.][ 1.  0.  2. -1. -1.][ 1.  0.  0.  3. -1.][ 1.  0.  0.  0.  4.]]
encoded_train # 训练集结果

1.2.5 Sum (Deviation) Encoding 偏差编码

偏差编码也通常在计量经济学中被使用。偏差编码后,线性模型的系数可以反映该给定该类别变量值的情况下因变量的平均值与全局因变量的平均值的差异。更多信息:

https://www.statsmodels.org/devel/contrasts.html

import numpy as np
import pandas as pd
from category_encoders.sum_coding import SumEncoder
# category_encoders 直接支持dataframe# 随机生成一些训练集
train_set = pd.DataFrame(np.array([['male',10],['female', 20], ['male',10], ['female',20],['female',15]]),columns = ['Sex','Type'])
train_y = np.array([False, True, True, False, False])# 随机生成一些测试集, 并有意让其包含未在训练集出现过的类别与缺失值
test_set = pd.DataFrame(np.array([['female',20],['male', 20], ['others',15], ['male',20],['female',40], ['male', 25]]),columns = ['Sex','Type'])
test_set.loc[4,'Type'] = np.nan
train_set # 原始训练集

test_set # 原始测试集

encoder = SumEncoder(cols=['Sex', 'Type'], handle_unknown='indicator', handle_missing='indicator').fit(train_set,train_y) # 在训练集上训练
encoded_train = encoder.transform(train_set) # 转换训练集
encoded_test = encoder.transform(test_set) # 转换测试集
# 将 handle_unknown设为‘indicator’,即会新增一列指示未知特征值
# 将 handle_missing设为‘indicator’,即会新增一列指示缺失值
# 其他的handle_unknown/handle_missing 的选择为:
# ‘error’:即报错; ‘return_nan’:即未知值/缺失之被标记为nan; ‘value’:即未知值/缺失之被标记为0# 以测试集结果为例
encoded_test# 在Helmert编码中:# 变量 Sex => 变为了4个新变量(包含常数项): 'male' => [ 1.  1.  0.  0.];
#                                      'female' => [ 1.  0.  1.  0.];
#                                       未知 =>  [ 1. -1. -1. -1.];
#                                       缺失 => [ 1.  0.  0.  1.];# 变量 Type => 变为了5个新变量(包含常数项): 10 => [ 1.  1.  0.  0.  0.];
#                                        20 => [ 1.  0.  1.  0.  0.];,
#                                        15 => [ 1.  0.  0.  1.  0.];
#                                        未知 =>  [ 1. -1. -1. -1. -1.];
#                                        缺失 => [ 1.  0.  0.  0.  1.];

# 可以通过如下代码计算变量Type的Deviation 矩阵from patsy.contrasts import Sum
levels = [1,2,3,4,5] # 3个变量值 + 1个未知值 + 1个缺失值
contrast = Sum().code_with_intercept(levels)
print(contrast.matrix) # 第一列为常数项
[[ 1.  1.  0.  0.  0.][ 1.  0.  1.  0.  0.][ 1.  0.  0.  1.  0.][ 1.  0.  0.  0.  1.][ 1. -1. -1. -1. -1.]]
encoded_train # 训练集结果

1.2.6 Target Encoding 目标编码

目标编码是一种不仅基于特征值本身,还基于相应因变量的类别变量编码方法。对于分类问题:将类别特征替换为给定某一特定类别值的因变量后验概率与所有训练数据上因变量的先验概率的组合。对于连续目标:将类别特征替换为给定某一特定类别值的因变量目标期望值与所有训练数据上因变量的目标期望值的组合。该方法严重依赖于因变量的分布,但这大大减少了生成编码后特征的数量。

公式:

‍‍‍‍其中min_samples_leaf和smoothing是用户定义的参数;
min_samples_leaf:计算类别平均值时的最小样本数(即若该类别出现次数少,则将被忽略),用以控制过拟合;
smoothing:平衡分类平均值与先验平均值的平滑系数。其值越高,则正则化越强;
????′????是类别特征X中类别为k的编码值;
Prior Prob:目标变量的先验概率/期望;
n:类别特征X中,类别为k的样本数;
????+:不仅在类别特征X中具有类别k,而且具有正结果的样本数(分类问题);‍‍‍‍

参考文献: Micci-Barreca, D. (2001). A preprocessing scheme for high-cardinality categorical attributes in classification and prediction problems. ACM SIGKDD Explorations Newsletter, 3(1), 27-32.

import numpy as np
import pandas as pd
from category_encoders.target_encoder import TargetEncoder
# category_encoders 直接支持dataframe# 随机生成一些训练集
train_set = pd.DataFrame(np.array([['male',10],['female', 20], ['male',10], ['female',20],['female',15]]),columns = ['Sex','Type'])
train_y = np.array([False, True, True, False, False])# 随机生成一些测试集, 并有意让其包含未在训练集出现过的类别与缺失值
test_set = pd.DataFrame(np.array([['female',20],['male', 20], ['others',15], ['male',20],['female',40], ['male', 25]]),columns = ['Sex','Type'])
test_set.loc[4,'Type'] = np.nan
train_set # 原始训练集

test_set # 原始测试集

encoder = TargetEncoder(cols=['Sex','Type'], handle_unknown='value',  handle_missing='value').fit(train_set,train_y) # 在训练集上训练
encoded_train = encoder.transform(train_set) # 转换训练集
encoded_test = encoder.transform(test_set) # 转换测试集# handle_unknown 和 handle_missing 被设定为 'value'
# 在目标编码中,handle_unknown 和 handle_missing 仅接受 ‘error’, ‘return_nan’ 及 ‘value’ 设定
# 两者的默认值均为 ‘value’, 即对未知类别或缺失值填充训练集的因变量平均值encoded_test # 编码后的变量数与原类别变量数一致

# 验证一下计算的结果,在测试集中,‘male’类别的编码值为 0.473106
prior = train_y.mean() # 先验概率
min_samples_leaf = 1.0 # 默认为1.0
smoothing = 1.0 # 默认为1.0
n = 2 # 训练集中,两个样本包含‘male’这个标签
n_positive = 1 # 在训练集中,这两个包含‘male’标签的样本中仅有一个有正的因变量标签???????????????????????? = 1 / (1 + np.exp(-(n - min_samples_leaf) / smoothing))
male_encode = prior * (1-????????????????????????) + ???????????????????????? * n_positive/n
male_encode # return 0.4731058578630005,与要验证的值吻合
0.4731058578630005
encoded_train # 训练集结果

好了,以上就是关于静态类别变量(上部分)的数据预处理介绍。建议读者结合代码,在 Jupyter 中实操一遍。

目前该项目完整中文版正在制作中,请持续关注哦~

中文版 Jupyter 地址:

http://localhost:8888/notebooks/feature-engineering-handbook-master/%E4%B8%AD%E6%96%87%E7%89%88/1.%20%E6%95%B0%E6%8D%AE%E9%A2%84%E5%A4%84%E7%90%86.ipynb#Ordinal-Encoding-%E5%BA%8F%E6%95%B0%E7%BC%96%E7%A0%81


推荐阅读

(点击标题可跳转阅读)

干货 | 公众号历史文章精选

我的深度学习入门路线

我的机器学习入门路线图

重磅!

林轩田机器学习完整视频和博主笔记来啦!

扫描下方二维码,添加 AI有道小助手微信,可申请入群,并获得林轩田机器学习完整视频 + 博主红色石头的精炼笔记(一定要备注:入群 + 地点 + 学校/公司。例如:入群+上海+复旦

长按扫码,申请入群

(添加人数较多,请耐心等待)

最新 AI 干货,我在看 

专栏 | 基于 Jupyter 的特征工程手册:数据预处理(二)相关推荐

  1. 专栏 | 基于 Jupyter 的特征工程手册:数据预处理(三)

    作者:陈颖祥.杨子晗 编译:AI有道 基于 Jupyter 的特征工程手册:数据预处理的上一篇: 专栏 | 基于 Jupyter 的特征工程手册:数据预处理(一) 专栏 | 基于 Jupyter 的特 ...

  2. 使用jupyter计算正态分布_专栏 | 基于 Jupyter 的特征工程手册:数据预处理(三)...

    红色石头的个人网站: 红色石头的个人博客-机器学习.深度学习之路​www.redstonewill.com 基于 Jupyter 的特征工程手册:数据预处理的上一篇: 专栏 | 基于 Jupyter ...

  3. 【完结篇】专栏 | 基于 Jupyter 的特征工程手册:特征降维

    作者:陈颖祥.杨子晗 编译:AI有道 经过数据预处理和特征选择,我们已经生成了一个很好的特征子集.但是有时该子集可能仍然包含过多特征,导致需要花费太多的计算能力用以训练模型.在这种情况下,我们可以使用 ...

  4. 专栏 | 基于 Jupyter 的特征工程手册:特征选择(五)

    作者:陈颖祥.杨子晗 编译:AI有道 数据预处理后,我们生成了大量的新变量(比如独热编码生成了大量仅包含0或1的变量).但实际上,部分新生成的变量可能是多余:一方面它们本身不一定包含有用的信息,故无法 ...

  5. 专栏 | 基于 Jupyter 的特征工程手册:特征选择(四)

    作者:陈颖祥.杨子晗 编译:AI有道 数据预处理后,我们生成了大量的新变量(比如独热编码生成了大量仅包含0或1的变量).但实际上,部分新生成的变量可能是多余:一方面它们本身不一定包含有用的信息,故无法 ...

  6. 专栏 | 基于 Jupyter 的特征工程手册:特征选择(三)

    作者:陈颖祥.杨子晗 编译:AI有道 数据预处理后,我们生成了大量的新变量(比如独热编码生成了大量仅包含0或1的变量).但实际上,部分新生成的变量可能是多余:一方面它们本身不一定包含有用的信息,故无法 ...

  7. 专栏 | 基于 Jupyter 的特征工程手册:特征选择(二)

    作者:陈颖祥.杨子晗 编译:AI有道 数据预处理后,我们生成了大量的新变量(比如独热编码生成了大量仅包含0或1的变量).但实际上,部分新生成的变量可能是多余:一方面它们本身不一定包含有用的信息,故无法 ...

  8. 专栏 | 基于 Jupyter 的特征工程手册:特征选择(一)

    作者:陈颖祥.杨子晗 编译:AI有道 数据预处理后,我们生成了大量的新变量(比如独热编码生成了大量仅包含0或1的变量).但实际上,部分新生成的变量可能是多余:一方面它们本身不一定包含有用的信息,故无法 ...

  9. 专栏 | 基于 Jupyter 的特征工程手册:数据预处理(一)

    点击上方"AI有道",选择"置顶"公众号 重磅干货,第一时间送达 作者:Yingxiang Chen & Zihan Yang 编辑:红色石头 特征工程 ...

最新文章

  1. 导师(老板)推荐的学术前沿号
  2. php-curl小记
  3. system函数-linux
  4. php oracle 锁表,频繁使用的一张表经常好被锁死?怎样处理!
  5. 容器技术之二.Docker的安装和常见问题
  6. 一道清华期中考试题(逃)
  7. 3. 机器学习中为什么需要梯度下降_梯度提升(Gradient Boosting)算法
  8. [Swift]LeetCode1044. 最长重复子串 | Longest Duplicate Substring
  9. 陈彬 2019-1-17
  10. stata 将数据集变量名称导出_Stata 15 统计数据分析软件
  11. 论用户体验测试:牛逼的功能千篇一律,好的体验万里挑一
  12. 脑洞大开!华为云桌面和无纸化会议系统结合会怎样?
  13. [洛谷P3939]数颜色
  14. qt4.8.5在arm下的移植
  15. 小程序源码:后台版本趣味测试微信小程序源码下载支持自定义问题等等
  16. Linux系统查看gcc,g++,java 等的版本
  17. 《Mining of Massive Datasets》读书笔记
  18. Python - 在定义函数时,为什么默认参数不能放在必选参数前面?
  19. GNSS卫星编号PRN
  20. android 标签云的实现 关于x轴 冒泡排序~瞬间让你高达上

热门文章

  1. CodeVs 1059 汽车装油
  2. 外媒炒作中国黑客入侵美保险公司 并无相关证据
  3. 出现了奇数次的数字的算法
  4. 90后,一个即将成为程序员的我
  5. 易宝典文章——用ISA 2006标准版发布Exchange 2010的OWA系列之申请Excha
  6. CodeForce 534C Polycarpus' Dice (数学推理)
  7. ZT Android4.2蓝牙基础架构学习
  8. 《Advanced Data Structures》读书笔记
  9. SQL之SELECT语句执行顺序及子句功能
  10. 纯CSS3画出小黄人并实现动画效果