理解特征工程Part1-连续数值数据,读英文原文Understanding Feature Engineering (Part 1) — Continuous Numeric Data,用中文记录一些关键点。

总述

典型的机器学习pipeline
端到端的机器学习pipeline如下

获取原始数据(raw data)并且在这些数据之上直接构建模型(models)是鲁莽的因为我们不会拿到想要的结果或者表现,并且算法也不足够只能来自动从原始数据中提取有意义的特征(features)。
这里主要关注的是上图中的data preparation,我们使用各种方法论来从原始数据中提取有意义的属性或者特征,主要是Feature Extraction&Engineering部分。
Prof. Pedro Domingos在他的论文 “A Few Useful Things to Know about Machine Learning”中说:
“At the end of the day, some machine learning projects succeed and some fail. What makes the difference? Easily the most important factor is the features used.”

Understanding Features(理解特征)

feature一般是原始数据上的特定表示,它是一个独立的(individual)可衡量的(measurable)属性。一般被描述为数据集的一列。假设有一个二维数据集,每行描述了一个观察(observation),每列表示一个特征,形式如下:


典型的机器学习算法处理这些数值矩阵或张量(tensors),因此大部分特征工程技术主要是将原始数据转换为一些能被这些算法理解的数值表示。
基于数据集特征可以分为两类,原始特征(raw features)可以直接从数据集上获取而不需要额外的数据处理或工程。衍生特征(derived features)经常是从特征工程获取,我们需要从现有数据属性中提取。一个简单的例子是从一个员工包含生日“Birthdate”的数据集中通过拿当前日期减去生日创建新的特征“Age”。
也有不通的数据类型比如结构化数据和非结构化数据,本文主要讨论的是处理结构化数据的特征工程。

Feature Engineering on Numeric Data(数值数据特征工程)

这里的数值数据指的是连续数据而不是离散数据,数值数据也可以用值的向量来表示,其中向量中每个值表示一个特定的特征。int和float是最常用的表示连续数值数据的类型。虽然数值数据可以直接喂给机器学习模型,但是你可能根据场景,问题和领域的不通在构建模型前还是需要特征工程。
我们用python来看看一些数值数据的特征工程的策略:

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import scipy.stats as spstats
%matplotlib inline

Raw Measures(原始度量)

之前提到,原始数值数据经常可以直接喂给机器学习模型,raw measures就是不经过任何转换直接使用的数值变量,一般这些特征表示成值或者计数(counts),比如数据集Pokémon dataset中如下一段数据:

poke_df = pd.read_csv('datasets/Pokemon.csv', encoding='utf-8') poke_df.head()


这些数据集由各种特点的各种统计组成。

Values(数值)

来看一些数值数据

poke_df[['HP', 'Attack', 'Defense']].head()


包括HP,Attack等都是连续数值数据,这些数值可以直接作为特征,再看下这些数据的统计评估:

poke_df[['HP', 'Attack', 'Defense']].describe()

Counts(计数)

另外一个原始度量就是表示频率的特征,特定属性发生的计数,
看看表示大多数用户经常听的歌曲的频率的数据集millionsong dataset。

popsong_df = pd.read_csv('datasets/song_views.csv', encoding='utf-8')
popsong_df.head(10)


上面截图中的listen_count就是统计计数值。

Binarization(二值化)

有时候原始计数可能和我们要构建的模型无关,比如当我在构建歌曲推荐系统的时候,为想知道一个人是否听过一个特定的歌曲,这就不需要该歌曲被听的次数因为为更关心用户是否听了,这是好用二值(比如0/1)就比count更合适,比如:

上面的watched就是用二值0/1表示是否看过。

Rounding(凑整)

经常我们处理像比例或者百分比这样连续数值属性的时候,我们可能不需要原始数值有很高的精度,因此舍去这些精度为数值int型就很合理了,这些int值然后可以直接用于做特征。我们尝试将这个概念用于虚拟数据集来描述items和相应流行比例。

items_popularity = pd.read_csv('datasets/item_popularity.csv',  encoding='utf-8')
items_popularity['popularity_scale_10'] = np.array(np.round((items_popularity['pop_percent'] * 10)),  dtype='int')
items_popularity['popularity_scale_100'] = np.array(np.round((items_popularity['pop_percent'] * 100)),    dtype='int')
items_popularity


上图中有两列rounding,分别转换为1-10和1-100,你可以使用这些值根据场景和问题做数值特征或者分类特征。

Interactions(交叉)

监督机器学习模型经常尝试对输出结果(离散类型或者连续值)建模成一个输入是特征变量的函数,例如,一个简单的线性回归公式描述如下:

其中输入特征描述为:

每个特征有个权重或者系数如下:

在这个例子中,简单的线性模型描述来input和output之间的关系,仅仅根据独立的、分离的输入特征。
但是,在真实世界场景中,尝试并抓住这些特征变量直接的交叉关系来作为输入特征集是很有意义的,比如一个简单的带交叉特征的上面线下回归方程的扩展描述如下:

其中特征表示为:

Binning(分箱)

处理原始的连续数值特征的问题是经常这些特征值的分布是偏态分布(skewed),这意味着一些值会经常出现而有些却很少出现。除此之外,还有个问题就是这些特征的值的变化幅度。例如特定音乐的计数值非常的大,而有些却很少,直接使用这些特征可能会导致很多问题从而影响模型。因此下面是处理这个问题的一些策略,包括分箱(binning)和变换(transformations)。
Binning也叫量化(quantization),是用于将连续数值特征转换为离线的(分类)。这些离散值或数字可以看作把原始、连续数值特征分组到分类或箱子里。其中每个箱子代表特定的惊吓程度(degree of intensity),因此特点范围的连续数值会落入该箱子,明确的数据分箱策略包括定宽(fixed-width)和自适应分箱(adaptive binning)。我们用从数据集2016 FreeCodeCamp Developer\Coder survey(关于码农和软件工程师的调查)中提取的子集看看。

fcc_survey_df = pd.read_csv('datasets/fcc_2016_coder_survey_subset.csv',
encoding='utf-8')
fcc_survey_df[['ID.x', 'EmploymentField', 'Age', 'Income']].head()


ID.x是参与调查的coder的唯一id。

Fixed-Width Binning(定宽分箱)

如名字所示,在定宽分箱,我们为每个箱子指定固定的宽度,每个箱子应该根据领域知识基础、规则或限制预先固定值的范围。基于取整的分箱是一种方式,可以使用前面讨论的rounding操作来分箱。
我们先来看看数据集中Age特征的分布:

fig, ax = plt.subplots()
fcc_survey_df['Age'].hist(color='#A9C5D3', edgecolor='black',  grid=False)
ax.set_title('Developer Age Histogram', fontsize=12)
ax.set_xlabel('Age', fontsize=12)
ax.set_ylabel('Frequency', fontsize=12)


上面的直方图描述了开发者年龄稍微右偏(上了年纪的开发者较少),我们现在把这些原始age值根据如下schema分箱:

Age Range: Bin
---------------0 -  9  : 0
10 - 19  : 1
20 - 29  : 2
30 - 39  : 3
40 - 49  : 4
50 - 59  : 5
60 - 69  : 6... and so on

处理后如下:

Adaptive Binning

使用定宽分箱的缺点是由于人工决定分箱范围,我们可能得到的是不规则的箱子,这些箱子落入每个箱子的数据个数不均匀,有些箱子很稠密而有些很稀疏甚至为空。自适应分享在这些场景中是一种安全的策略,即让数据自己说话,就是说我们使用数据分布来决定我们分享的范围。
基于分位数的分箱(Quantile based binning)是用于自适应分享的不错的策略。分位数是特点的值或割点(cut-points)来将特定数值域的连续值分布划分为离散临近的箱子或间隔。因此q-Quantiles帮助把数值属性划分为q份。比如2-Quantile(2分位)也叫中位数(median)就是将数据分布放入两个箱子。4-Quantiles是四分位数(quartiles),下面看看开发者收入字段的数据分布。

fig, ax = plt.subplots()
fcc_survey_df['Income'].hist(bins=30, color='#A9C5D3', edgecolor='black', grid=False)
ax.set_title('Developer Income Histogram', fontsize=12)
ax.set_xlabel('Developer Income', fontsize=12)
ax.set_ylabel('Frequency', fontsize=12)


上面的分布描述了一种右偏分布,表示赚更多钱的开发者更少,反之亦然。对上面数据分布采用四分位自适应分箱:

quantile_list = [0, .25, .5, .75, 1.]
quantiles = fcc_survey_df['Income'].quantile(quantile_list)
quantilesOutput
------
0.00      6000.0
0.25     20000.0
0.50     37000.0
0.75     60000.0
1.00    200000.0
Name: Income, dtype: float64

显示如下:

上面分布中红线描述了四分位值和可能的分箱。利用这个方法来构建我们四分位分箱计划。

quantile_labels = ['0-25Q', '25-50Q', '50-75Q', '75-100Q']
fcc_survey_df['Income_quantile_range'] = pd.qcut(fcc_survey_df['Income'], q=quantile_list)
fcc_survey_df['Income_quantile_label'] = pd.qcut(fcc_survey_df['Income'], q=quantile_list,       labels=quantile_labels)fcc_survey_df[['ID.x', 'Age', 'Income', 'Income_quantile_range', 'Income_quantile_label']].iloc[4:9]

结果如下:

这应该能给你一个四分位自适应分享如何工作的概念。还有个要记住的重要的点是分箱合成的结果能生成离散值类型特征,但是在把这些用于任何模型前可能还需要额外的特征工程来处理。(将在下一部分讲针对分类数据categorical data的特征工程策略)。

Statistical Transformations(统计变换)

我们前面简短地讨论过有偏数据分布的不利影响。下面来看看利用统计/数学变换的特征工程策略,我们会看看log变换(Log transform)还有Box-Cox变换(Box-Cox transform),这两个都属于幂变换(Power transform)函数族,一般用于创建单调数据转换(monotonic data transformations),主要的意义是它们可以帮助稳定方差(variance),密切服从正态分布并且让数据和基于分布的均值独立。

Log Transform

log变换公式如下:

公式可以转换为:

常用的有b为e=2.71828 (欧拉数)或者b=10
log变换在应用有偏分布时很有用,因为它们倾向于扩展落在较低幅度范围内的值,并倾向于压缩或减小落在较高幅度范围内的值。这倾向于让有偏分布尽可能像正态分布。我们来对前面用过的开发者收入特征使用log变换。

fcc_survey_df['Income_log'] = np.log((1+ fcc_survey_df['Income']))
fcc_survey_df[['ID.x', 'Age', 'Income', 'Income_log']].iloc[4:9]


Income_log字段描述了变换后的特征,我们来看看变换特征的数据分布:

income_log_mean = np.round(np.mean(fcc_survey_df['Income_log']), 2)
fig, ax = plt.subplots()
fcc_survey_df['Income_log'].hist(bins=30, color='#A9C5D3', edgecolor='black', grid=False)
plt.axvline(income_log_mean, color='r')
ax.set_title('Developer Income Histogram after Log Transform', fontsize=12)
ax.set_xlabel('Developer Income (log scale)', fontsize=12)
ax.set_ylabel('Frequency', fontsize=12)
ax.text(11.5, 450, r'$\mu$='+str(income_log_mean), fontsize=10)


从上图可以清晰地比起原始数据的有偏分布看到分布更像正态/高斯分布了。

Box-Cox Transform

Box-Cox变换是另一个属于幂函数族的有名的函数,该函数有个前提条件是要被转换的数值必须是正数,如果为负数,可以使用使用恒定值进行移位。从数学上说,Box-Cox变换函数可以如下表示:

这样得到的变换输出y是输入x和变换参数λ的函数,使得当λ= 0时,合成变换是我们之前讨论的自然对数变换。 通常使用最大似然或对数似然估计来确定λ的最佳值。 现在让我们将Box-Cox转换应用于我们的开发者收入特征。 首先,我们通过删除非空值来从数据分布中获得最佳lambda值,如下所示:

income = np.array(fcc_survey_df['Income'])
income_clean = income[~np.isnan(income)]
l, opt_lambda = spstats.boxcox(income_clean)
print('Optimal lambda value:', opt_lambda)Output
------
Optimal lambda value: 0.117991239456

现在我们已经获得了最佳λ值,让我们使用Box-Cox变换得到λ的两个值,使得λ= 0和λ=λ(最优)并转换开发者收入特征。

fcc_survey_df['Income_boxcox_lambda_0'] = spstats.boxcox((1+fcc_survey_df['Income']), lmbda=0)
fcc_survey_df['Income_boxcox_lambda_opt'] = spstats.boxcox(fcc_survey_df['Income'], lmbda=opt_lambda)fcc_survey_df[['ID.x', 'Age', 'Income', 'Income_log', 'Income_boxcox_lambda_0',       'Income_boxcox_lambda_opt']].iloc[4:9]


变换的特征在上面的数据框中描述。 就像我们预期的那样,Income_log和Income_boxcox_lamba_0具有相同的值。 让我们看一下用最优λ转换后转换后的收入特征的分布。

income_boxcox_mean = np.round(np.mean(fcc_survey_df['Income_boxcox_lambda_opt']),2)
fig, ax = plt.subplots()
fcc_survey_df['Income_boxcox_lambda_opt'].hist(bins=30, color='#A9C5D3', edgecolor='black', grid=False)
plt.axvline(income_boxcox_mean, color='r')
ax.set_title('Developer Income Histogram after Box–Cox Transform', fontsize=12)
ax.set_xlabel('Developer Income (Box–Cox transform)', fontsize=12)
ax.set_ylabel('Frequency', fontsize=12)
ax.text(24, 450, r'$\mu$='+str(income_boxcox_mean), fontsize=10)


分布看起来更像正态分布,和我们在对数变换后获得的分布类似。

Conclusion(结论)

特征工程是机器学习和数据科学的一个非常重要的方面,绝不应该被忽视。 虽然我们有自动化的特征工程方法,如深度学习以及自动机器学习框架,如AutoML(它仍然强调它需要良好的特征才能正常工作!)。 特征工程存在于此,甚至这些自动化方法中通常需要基于数据类型,领域和要解决的问题的特定工程特征。
上面所有的code都可以在作者的github上找到。
也可以用jupyter notebook查看。

翻译:理解特征工程(1)-连续数值数据相关推荐

  1. R语言caret包构建xgboost模型实战:特征工程(连续数据离散化、因子化、无用特征删除)、配置模型参数(随机超参数寻优、10折交叉验证)并训练模型

    R语言caret包构建xgboost模型实战:特征工程(连续数据离散化.因子化.无用特征删除).配置模型参数(随机超参数寻优.10折交叉验证)并训练模型 目录

  2. 按某列获取几行_机器学习获取数据难?别忘记特征工程

    现实世界中的数据可能十分混乱复杂,不论它是相关的SQL数据库.Excel文件或是其它任何数据源.尽管这些数据通常都是表格的结构,即每一行(样本)相对于每一列(特征)都有其对应的值,但是这些数据可能很难 ...

  3. 《特征工程三部曲》之一:数据处理

    要理解特征工程,首先要理解数据(Data)和特征(Feature)的概念 概念 特征工程(Feature Engineering) 其本质上是一项工程活动,它目的是最大限度地从原始数据中提取特征以供算 ...

  4. 《Python自然语言处理-雅兰·萨纳卡(Jalaj Thanaki)》学习笔记:05 特征工程和NLP算法

    05 特征工程和NLP算法 5.1 理解特征工程 5.1.1 特征工程的定义 5.1.2 特征工程的目的 5.1.3 一些挑战 5.2 NLP中的基础特征 5.2.1 句法解析和句法解析器 5.2.2 ...

  5. 特征工程-获取更好的训练数据

    转载 特征工程 -> 更好的数据 特征工程:特征选择特征提取特征构造 "数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已".特征工程在机器学习中占有相当重要的 ...

  6. 不会做特征工程的 AI 研究员不是好数据科学家!上篇 - 连续数据的处理方法 本文作者:s5248 编辑:杨晓凡 2018-01-19 11:32 导语:即便现代机器学习模型已经很先进了,也别

    不会做特征工程的 AI 研究员不是好数据科学家!上篇 - 连续数据的处理方法 雷锋网(公众号:雷锋网) AI 科技评论按:眨眼间我们就从人工特征.专家系统来到了自动特征.深度学习的人工智能新时代,众多 ...

  7. 特征工程的宝典-《Feature Engineering for Machine Learning》翻译及代码实现

    由O'Reilly Media,Inc.出版的<Feature Engineering for Machine Learning>(国内译作<精通特征工程>)一书,可以说是特征 ...

  8. 特征工程的准备:特征理解

    特征理解之前的知识储备(二) 导读 数据是否具有统一的格式 数值是指代类别还是具体数值 数据的四个等级 总结 导读 虽然我们介绍了数据的无量纲化,但是在实际编码之前我们还是需要多做一些准备工作. 在2 ...

  9. ML之二分类预测:以岩石水雷数据集(RockMine)为例从0到1深入理解科学预测之分类问题的思路框架(特征工程详细步骤(特征分析与特征处理)+分类模型设计)

    ML之二分类预测:以岩石水雷数据集(RockMine)为例从0到1深入理解科学预测之分类问题的思路框架(特征工程详细步骤+分类模型设计) 目录 一.总体思路框架 二.特征工程详细步骤(特征分析与特征处 ...

最新文章

  1. 看看Spring的源码(一)——Bean加载过程
  2. 开源、免费、提升办公效率,Win10官方出品
  3. 推荐几款软件和几个网站
  4. BugkuCTF-Misc:宽带信息泄露
  5. String.format() 格式化字符串
  6. Linux下多显卡选择绘制实验记录
  7. 动态加载JS脚本【转】
  8. geoserver安装(war安装+exe安装)
  9. android 横向铺满,Android开发全程记录(八)——设置ImageView显示的图片铺满全屏(适应魅族等不常见屏幕比例)...
  10. Python学习-logging
  11. vue 动画 抖动效果_css开发常用动画
  12. 概率图模型--马尔可夫随机场
  13. 1. 并行与分布式系统简介
  14. Ant Design 遭删库!
  15. 欧美大脑计划存在的问题和忽视的一个重要元素,互联网大脑计划系列三
  16. python发邮件被认定为垃圾邮件_python笔记:解决163邮件批量发送被误认为是垃圾邮件而导致无法方法是使用QQ邮件发...
  17. 机器学习、数据建模、数据挖掘分析 特征无量纲化的常见操作方法
  18. 当机械人也开始拥有感情‧谁来定义什么才是人类?
  19. Newtonsoft.Json.JsonSerializationException
  20. Spring-Core 中文翻译+总结文档(上)

热门文章

  1. java derby数据库_使用Apache Derby进行Java数据库开发,第1部分
  2. 【聚类算法】什么是聚类
  3. 开启电脑替我记忆之路
  4. 不讲武德,Kubernetes 弃用 Docker刷爆了网络,我们公司也慌了!
  5. Retrofit教程
  6. 百度人脸识别的两个方式的使用
  7. 第十六届中国大数据技术大会五大分论坛顺利举办!
  8. 【毕业设计源码】基于Python的校园生活助手(二手+活动+论坛+新闻)信息系统
  9. 【C++】C++标准库之iomanip库(格式输入输出)
  10. 计算机绘图中特征建模的概念,科大机械CADCAM习题集..doc