【精通特征工程】学习笔记Day1&1.26&D1-2章&P1-32页
1、机器学习流程&基本概念
- 数据–任务–模型–特征–模型评价
- **数据:**是对现实世界的现象的观测
- **特征:**就是原始数据某个方面的数值表示
- **特征工程:**是指从原始数据中提取特征并将其转换为适合机器学习模型的格式
- 在统计机器学习中,所有数据最终都会转化为数值型特征。因此,所有特征工程最终都会归结为某种数值型特征工程技术
2、简单而又奇妙的数值
2.1 标量、向量、空间
- 单独的数值型特征称为标量,标量的有序列表称为向量,向量位于向量空间中。
2.2 处理计数
2.2.1 二值化
-
将大于等于某个次数的设为1,小于这个次数的设为0
-
二值目标变量是一个既简单又强壮的用户偏好衡量指标
-
eg1:歌曲收听次数及人数的原始分布如下,会发现原始的收听次数并不是衡量用户喜好的强壮指标,因此可以进行二值化,如果用户收听了某首歌曲至少一次,那么就认为该用户喜欢该歌曲
import pandas as pd
listen_count = pd.read_csv('millionsong/train_triplets.txt.zip',header=None, delimiter='\t')# 表中包含有形式为“用户-歌曲-收听次数”的三元组。只包含非零收听次数。 # 因此,要二值化收听次数,只需将整个收听次数列设为1。
listen_count[2] = 1
2.2.2 区间量化(分箱)
-
区间量化可以将连续型数值映射为离散型数值,可以将这种离散型数值看作一种有序的分箱序列,它表示的是对密度的测量
-
为了对数据进行区间量化,必须确定每个分箱的宽度。有两种确定分箱宽度的方法:固定宽度分箱和自适应分箱
-
eg2:商家点评数量数据,点评数量及用户量的分布如下,会发现大多数商家的点评数量很少,但有些商家具有几千条点评,原始的点评数量横跨了若干个数量,一种解决方法是对计数值进行区间量化,然后使用量化后的结果。换言之,将点评数量分到多个箱子里面,去掉实际的计数值
(1)固定宽度分箱
-
通过固定宽度分箱,每个分箱中会包含一个具体范围内的数值。这些范围可以人工定制, 也可以通过自动分段来生成,它们可以是线性的,也可以是指数性的
-
例如,可以按 10 年为一段来将人员划分到多个年龄范围中:0~9 岁的在分箱 1 中、10~19 岁的在分箱 2 中
-
要将计数值映射到分箱,只需用计数值除以分箱的宽度,然后取整数部分
-
eg3:通过固定宽度分箱对计数值进行区间量化
import numpy as np
small_counts = np.random.randint(0, 100, 20)# 生成20个随机整数,均匀分布在0~99之间
small_counts# 通过除法映射到间隔均匀的分箱中,每个分箱的取值范围都是0~9
np.floor_divide(small_counts, 10)#通过除法映射到间隔均匀的分箱中,每个分箱的取值范围都是0~9
-
当数值横跨多个数量级时,最好按照 10 的幂(或任何常数的幂)来进行分组,如:0-9、 10-99、100-999、1000-9999
-
这时分箱宽度是呈指数增长的,要将计数值映射到分箱,需要取计数值的对数。指数宽度分箱与对数变换的关系非常紧密
-
eg4:通过固定宽度分箱对计数值进行区间量化
large_counts = [296, 8286, 64011, 80, 3, 725, 867, 2215, 7689, 11495, 91897,44, 28, 7971, 926, 122, 22222]# 横跨若干数量级的计数值数组
np.floor(np.log10(large_counts))# 通过对数函数映射到指数宽度分箱
(2)分位数分箱
- 如果计数值中有比较大的缺口,就会产生很多没有任何数据的空箱子。根据数据的分布特点,进行自适应的箱体定位,可以使用数据分布的分位数来实现,分位数是可以将数据划分为相等的若干份数的值,如:中位数(即二分位数)、四分位数、十分位数等
eg5:计算 Yelp 商家点评数量的十分位数
>>> deciles = biz_df['review_count'].quantile([.1, .2, .3, .4, .5, .6, .7, .8, .9])
>>> deciles
0.1 3.0
0.2 4.0
0.3 5.0
0.4 6.0
0.5 8.0
0.6 12.0
0.7 17.0
0.8 28.0
0.9 58.0
在直方图上画出十分位数
-
要计算分位数并将数据映射到分位数分箱中,可以使用 Pandas 库,如例 6所示。
- pandas.DataFrame.quantile 可以计算分位数
- pandas.Series.quantile 可以计算分位数
- pandas.qcut 可以将数据映射为所需的分位数值
-
eg6:通过分位数对计数值进行分箱
import pandas as pd # 继续使用例4中的large_couts
pd.qcut(large_counts, 4, labels=False)# 将计数值映射为分位数
# 计算实际的分位数值
large_counts_series = pd.Series(large_counts)
large_counts_series.quantile([0.25, 0.5, 0.75])
2.3 对数变换
-
对数函数压缩高值区间并扩展低值区间
-
eg7:对数变换前后的点评数量分布可视化。
- 分析:比较对数变换前后的 Yelp 商家点评数量的直方图,如下所示,两幅图中的 y 轴都是正常(线性)标度。在下方的图形中,区间 (0.5, 1] 中的箱体间隔很大,是因为在 1 和 10 之间只有 10 个可能的整数计数值。请注意,初始的点评数量严重集中在低计数值区域,但有些异常值跑到了 4000 之外。经过对数变换之后,直方图在低计数值的集中趋势被减弱了,在 x 轴上的分布更均匀了一些
2.3.1 对数变换实战
- 代码demo:使用对数变换后的 Yelp 点评数量预测商家的平均评分
# 使用Yelp点评数据框,计算Yelp点评数量的对数变换值
# 注意,我们为原始点评数量加1,以免当点评数量为0时,对数运算结果得到负无穷大。
>>> biz_df['log_review_count'] = np.log10(biz_df['review_count'] + 1)
- 代码demo:使用在线新闻流行度数据集中经对数变换后的单词个数预测文章流行度
# 从UCI下载在线新闻流行度数据集,对n_tokens_content特征进行对数变换,这个特征表示的是一篇新闻文章中的单词 # (token)数量。
>>> df['log_n_tokens_content'] = np.log10(df['n_tokens_content'] + 1)
从下图可以看出,对数变换重组了 x 轴,对于那些目标变量值异常巨大(>200000 个分享)的文章,对数变换将它们更多地拉向了 x 轴的右侧,这就为线性模型在输入特征空间的低值端争取了更多的“呼吸空间”。 如果不进行对数变换(下面上方的图),模型就会面临更大的压力,要在输入变化很小的情况下去拟合变化非常大的目标值。
2.3.2 指数变换:对数变换的推广
-
指数变换是个变换族,对数变换只是它的一个特例。用统计学术语来说,它们都是方差稳定化变换
-
泊松分布是一种 重尾分布,它的方差等于它的均值。因此,它的质心越大,方差就越大,重尾程度也越 大。指数变换可以改变变量的分布,使得方差不再依赖于均值
-
例如,假设一个随机变量X 具有泊松分布,如果通过取它的平方根对它进行变换,那么它的平方根的方差就近似是一 个常数,而不是与均值相等。
-
下图为泊松分布的粗略表示,这是一个方差随均值变大的分布示例。它表示出了 λ 对泊松分布的影响,λ 表示泊松分布的均值。当 λ 变大时,不仅整个分 布模式向右移动,质量也更加分散,方差随之变大。
-
平方根变换和对数变换都可以简单推广为 Box-Cox 变换
-
下图展示了 λ = 0(对数变换)、λ = 0.25、λ = 0.5(平方根变换的一种缩放和平移形式)、 λ = 0.75 和 λ = 1.5 时的 Box-Cox 变换。λ 小于 1 时,可以压缩高端值;λ 大于 1 时,起的作 用是相反的。
-
只有当数据为正时,Box-Cox 公式才有效。对于非正数据,我们可以加上一个固定的常数, 对数据进行平移。
-
代码demo:对 Yelp 商家点评数量的 Box-Cox 变换
>>> from scipy import stats
# 接上一个例子,假设biz_df包含Yelp商家点评数据。
# Box-Cox变换假定输入数据都是正的。
# 检查数据的最小值以确定满足假定。
>>> biz_df['review_count'].min()
3
# 设置输入参数λ为0,使用对数变换(没有固定长度的位移)。
>>> rc_log = stats.boxcox(biz_df['review_count'], lmbda=0)
# 默认情况下,SciPy在实现Box-Cox转换时,会找出使得输出最接近于正态分布的λ参数。
>>> rc_bc, bc_params = stats.boxcox(biz_df['review_count'])
>>> bc_params
-0.4106510862321085
下面为Box-Cox 变换后的 Yelp 商家点评数量