特征工程系列学习(一)简单数字的奇淫技巧(下)

对数转换实战

  让我们看看在监督学习中对数转换如何执行。我们将使用上面的两个数据集。对于 Yelp 评论数据集, 我们将使用评论的数量来预测商户的平均评级。对于 Mashable 的新闻文章, 我们将使用文章中的字数来预测其流行程度。由于输出是连续的数字, 我们将使用简单的线性回归作为模型。我们在没有对数变换和有对数变换的特色上,使用 Scikit Learn 执行10折交叉验证的线性回归。模型由 R 方评分来评估, 它测量训练后的回归模型预测新数据的良好程度。好的模型有较高的 R 方分数。一个完美的模型得到最高分1。分数可以是负的, 一个坏的模型可以得到一个任意低的负评分。通过交叉验证, 我们不仅得到了分数的估计, 还获得了方差, 这有助于我们判断两种模型之间的差异是否有意义。

例2-8:使用对数转换 YELP 评论数预测平均商户评级

  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
import pandas as pdimport numpy as npimport jsonfrom sklearn import linear_modelfrom sklearn.model_selection import cross_val_scorebiz_df['log_review_count'] = np.log10(biz_df['review_count'] + 1)biz_df.head()

  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
## Train linear regression models to predict the average stars rating of a business,## using the review_count feature with and without log transformation## Compare the 10-fold cross validation score of the two modelsm_orig = linear_model.LinearRegression()scores_orig = cross_val_score(    m_orig, biz_df[['review_count']], biz_df['stars'], cv=10)m_log = linear_model.LinearRegression()scores_log = cross_val_score(    m_log, biz_df[['log_review_count']], biz_df['stars'], cv=10)print("R-squared score without log transform: %0.5f (+/- %0.5f)" %      (scores_orig.mean(), scores_orig.std() * 2))print("R-squared score with log transform: %0.5f (+/- %0.5f)" %      (scores_log.mean(), scores_log.std() * 2))

输出:R-squared score without log transform: 0.00215 (+/- 0.00329) R-squared score with log transform: 0.00136 (+/- 0.00328)

  从实验的结果来看, 两个简单的模型 (有对数变换和没有对数变换) 在预测目标时同样不好, 而有对数变换的特征表现略差。真令人失望!这并不奇怪, 他们都不是很好, 因为他们都只使用一个功能。但是, 人们本来希望日志转换的功能执行得更好。

数据可视化的重要性

  对数变换在两个不同数据集上的影响的比较,说明了可视化数据的重要性。在这里,我们故意保持输入和目标变量简单,以便我们可以很容易地可视化它们之间的关系。另一方面,人们可以令人信服地在给定平均星级模拟评论数的分布。在建立模型时,最好直观地检查输入和输出之间的关系,以及不同输入特征之间的关系。

功率变换:对数变换的推广

  对数变换是一个称为功率变换的变换族的特殊例子。在统计方面,这些是方差稳定的变换。为了理解为什么方差稳定是好的,考虑泊松分布。这是一个方差等于它的平均值的重尾分布。因此,它的质量中心越大,其方差越大,尾部越重。功率变换改变变量的分布,使得方差不再依赖于平均值。例如,假设一个随机变量X具有泊松分布。假如我们使用开平方根变换𝑋, 𝑋˜=𝑋⎯⎯⎯√X的方差大致是恒定的, 而不是等于平均值。

平方根变换和对数变换的简单推广称为Box-Cox变换: 图2-12, 展示出了在 𝜆=0(log变换),𝜆=0.25,𝜆=0.5(平方根的缩放和移位版本),λ=0.75, 和𝜆=1.5时的Box-Cox变换。设置𝜆小于1时压缩较高的值,并且设置λ大于1时具有相反的效果。   只有当数据为正值时, Box-Cox 公式才能工作。对于非正数据, 可以通过加上固定常量来移动数值。当应用 Box-Cox 变换或更一般的功率变换时, 我们必须确定参数𝜆的值。这可能是通过最大似然(找到的𝜆,使产生的变换信号的高斯似然最大) 或贝叶斯方法。完全介绍 Box-Cox 和一般功率变换的使用超出了本书的范围。感兴趣的读者可以通过 Jack Johnston 和John DiNardo (McGraw Hill) 编写的Econometric Methods 找到更多关于幂转换的信息。幸运的是, Scipy 的数据包包含了一个 Box-Cox 转换的实现, 其中包括查找最佳变换参数。

例2-12:Yelp商户评论数的 Box-Cox 变换

  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
from scipy import stats
# Continuing from the previous example, assume biz_df contains# the Yelp business reviews data# Box-Cox transform assumes that input data is positive.# Check the min to make sure.biz_df['review_count'].min()输出:3
biz_df.columns输出:Index(['business_id', 'categories', 'city', 'full_address', 'latitude',       'longitude', 'name', 'neighborhoods', 'open', 'review_count', 'stars',       'state', 'type', 'log_review_count'],      dtype='object')      # Setting input parameter lmbda to 0 gives us the log transform (without constant offset)rc_log = stats.boxcox(biz_df['review_count'], lmbda=0)biz_df['rc_log']=rc_log# By default, the scipy implementation of Box-Cox transform finds the lmbda parameter# that will make the output the closest to a normal distributionrc_bc, bc_params = stats.boxcox(biz_df['review_count'])print(bc_params)输出:-0.5631160899391674biz_df['rc_bc']=rc_bc

图2-13 提供了原始和转换评论数分布的可视化比较。

  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
### 例2-13。可视化评论数的原始、对数转换和 Box-Cox 转换的直方图。
fig, (ax1, ax2, ax3) = plt.subplots(3, 1)fig.tight_layout(pad=0, w_pad=4.0, h_pad=4.0)# original review count histogrambiz_df['review_count'].hist(ax=ax1, bins=100)ax1.set_yscale('log')ax1.tick_params(labelsize=14)ax1.set_title('Review Counts Histogram', fontsize=14)ax1.set_xlabel('')ax1.set_ylabel('Occurrence', fontsize=14)
# review count after log transformbiz_df['rc_log'].hist(ax=ax2, bins=100)ax2.set_yscale('log')ax2.tick_params(labelsize=14)ax2.set_title('Log Transformed Counts Histogram', fontsize=14)ax2.set_xlabel('')ax2.set_ylabel('Occurrence', fontsize=14)
# review count after optimal Box-Cox transformbiz_df['rc_bc'].hist(ax=ax3, bins=100)ax3.set_yscale('log')ax3.tick_params(labelsize=14)ax3.set_title('Box-Cox Transformed Counts Histogram', fontsize=14)ax3.set_xlabel('')ax3.set_ylabel('Occurrence', fontsize=14)输出:Text(29.125,0.5,'Occurrence')

特征缩放或归一化

  某些特征的值有界的,如纬度或经度。其他数值特征 (如数量) 可能会在无界的情况下增加。那些关于输入是平滑函数的模型, 如线性回归、逻辑回归或任何涉及矩阵的东西, 都受输入的数值范围影响。另一方面, 基于树的模型不太在意这个。如果你的模型对输入特征的数值范围敏感, 则特征缩放可能会有所帮助。顾名思义, 特征缩放会更改特征值的数值范围。有时人们也称它为特征规范化。功能缩放通常分别针对单个特征进行。有几种常见的缩放操作, 每个类型都产生不同的特征值分布。

Min-max缩放

  设𝑋是一个单独的特征值(即,在某些数据点中的一个特征值),以及 𝑚𝑖𝑛(𝑥)和 𝑚𝑎𝑥(𝑥) ,分别是整个数据集上该特征的最小值和最大值。Min-max缩放压缩(或拉伸)所有特征值到[0,1]的范围内。最小最大尺度的公式是

标准化(方差缩放)

  特征标准化的定义为:   减去特征 (所有数据点) 的平均值并除以方差。因此, 它也可以称为方差缩放。缩放后的特征的平均值为0, 方差为1。如果原始特征具有高斯分布, 则缩放特征为标准高斯。下图包含了标准化的说明。

不要中心化稀疏数据

  最小最大缩放和标准化都从原始特征值中减去一个数量。对于最小最大缩放, 移动量是当前特征的所有值中最小的。对于标准化, 移动的量是平均值。如果移动量不是零, 则这两种转换可以将稀疏特征(大部分值为零)的向量转换为一个稠密的向量。这反过来会给分类器带来巨大的计算负担, 取决于它是如何实现的。词袋是一种稀疏表示, 大多数分类库都对稀疏输入进行优化。如果现在的表示形式包含了文档中没有出现的每个单词, 那就太可怕了。请谨慎对稀疏特征执行最小最大缩放和标准化操作。

L2 normalization

这项技术通过所谓的 L2 范数 (也称为欧几里德范数) 正常化 (划分) 原始特征值。 L2范数度量向量在坐标空间中的长度。这个定义可以从众所周知的勾股定理中得到,给出三角形两边的长度,可以得到斜边长度。

L2 范数将求特征的各数据点的平方和, 然后取平方根。L2 规范化后, 该特征列具有范数1。它也可以称为 L2 缩放。(不严谨的说, 缩放意味着和常量相乘, 而规范化可能涉及许多操作。)图2-17说明了 L2 规范化。

数据空间与特征空间

  请注意,上图中的说明是在数据空间中,而不是特征空间。还可以对数据点进行L2归一化,而不是特征,这将导致具有单位范数(范数为1)的数据向量。(参见词袋中关于数据向量和特征向量的互补性质的讨论)不管缩放方法如何,特征缩放总是将特征除以常数(也称为归一化常数)。因此,它不会改变单特征分布的形状。我们将用在线新闻文章标记计数来说明这一点。

  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
import pandas as pdimport sklearn.preprocessing as preproc
# Load the online news popularity datasetdf = pd.read_csv('data/OnlineNewsPopularity.csv', delimiter=', ')
# Look at the original data - the number of words in an articledf['n_tokens_content'].as_matrix()输出:array([219., 255., 211., ..., 442., 682., 157.])
# Min-max scalingdf['minmax'] = preproc.minmax_scale(df[['n_tokens_content']])# Standardization - note that by definition, some outputs will be negativedf['standardized'] = preproc.StandardScaler().fit_transform(df[['n_tokens_content']])# L2-normalizationdf['l2_normalized'] = preproc.normalize(df[['n_tokens_content']], axis=0)print(df['l2_normalized'].as_matrix())输出:array([0.00152439, 0.00177498, 0.00146871, ..., 0.00307663, 0.0047472 ,       0.00109283])

  我们也可以可视化用不同的特征缩放方法后的数据的分布。如图2-18所示,与对数变换不同,特征缩放不会改变分布的形状;只有数据的规模发生变化。 例2-16。绘制原始数据和缩放数据的直方图。¶

  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
fig, (ax1, ax2, ax3, ax4) = plt.subplots(4,1)fig.tight_layout(pad=0, w_pad=1.0, h_pad=2.0)# fig.tight_layout()
df['n_tokens_content'].hist(ax=ax1, bins=100)ax1.tick_params(labelsize=14)ax1.set_xlabel('Article word count', fontsize=14)# ax1.set_ylabel('Number of articles', fontsize=14)
df['minmax'].hist(ax=ax2, bins=100)ax2.tick_params(labelsize=14)ax2.set_xlabel('Min-max scaled word count', fontsize=14)ax2.set_ylabel('Number of articles', fontsize=14)
df['standardized'].hist(ax=ax3, bins=100)ax3.tick_params(labelsize=14)ax3.set_xlabel('Standardized word count', fontsize=14)# ax3.set_ylabel('Number of articles', fontsize=14)
df['l2_normalized'].hist(ax=ax4, bins=100)ax4.tick_params(labelsize=14)ax4.set_xlabel('L2-normalized word count', fontsize=14)ax4.set_ylabel('Number of articles', fontsize=14)

  在一组输入特征在比例上差异很大的情况下,特征缩放非常有用。例如,一个流行的电子商务网站的每日访问者数量可能是十万,而实际销售额可能是几千。如果这两种功能都投入到模型中,那么该模型需要在确定要做什么的同时平衡它们的规模。输入特征的极大变化会导致模型训练算法的数值稳定性问题。在这些情况下,标准化功能是个好主意。

特征选择

  特征选择技术会删除非有用的特征,以降低最终模型的复杂性。最终目标是快速计算的简约模型,预测准确性降低很小或不会降低。为了得到这样的模型,一些特征选择技术需要训练多个候选模型。换句话说,特征选择并不是减少训练时间,实际上有些技巧增加了整体训练时间,但是减少了模型评分时间。

粗略地说,特征选择技术分为三类。

•Filtering(过滤): 预处理可以删除那些不太可能对模型有用的特征。例如,可以计算每个特征与响应变量之间的相关或相互信息,并筛除相关信息或相互信息低于阈值的特征。过滤比下面的包装(wrapper)技术便宜得多,但是他们没有考虑到正在使用的模型。因此他们可能无法为模型选择正确的特征。最好先保守地进行预过滤,以免在进行模型训练步骤之前无意中消除有用的特征。

•Wrapper methods(包装方法):这些技术是昂贵的,但它们允许您尝试特征子集,这意味着你不会意外删除自身无法提供信息但在组合使用时非常有用的特征。包装方法将模型视为提供特征子集质量分数的黑盒子。shi一个独立的方法迭代地改进子集。

•Embedded methods(嵌入式方法):嵌入式方法执行特征选择作为模型训练过程的一部分。 例如,决策树固有地执行特征选择,因为它在每个训练步骤选择一个要在其上进行树分裂的特征。另一个例子是𝐿1正则,它可以添加到任何线性模型的训练目标中。𝐿1鼓励模型使用一些特征而不是许多特征。因此它也被称为模型的稀疏约束。嵌入式方法将特征选择作为模型训练过程的一部分。它们不如包装方法那么强大,但也远不如包装方法那么昂贵。与过滤相比,嵌入式方法会选择特定于模型的特征。从这个意义上讲,嵌入式方法在计算费用和结果质量之间取得平衡。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小谢先生

支持知识付费

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值