【精通特征工程】学习笔记Day4&2.22&D5章&P65-81页
5、分类变量:自动化时代的数据计数
- 分类变量是用来表示类别或标记的,又称为无序变量
- 大型分类变量,分箱计数
5.1 分类变量的编码
分类变量中的类别通常不是数值型的。例如,眼睛的颜色可以是“黑色”“蓝色”和“褐 色”,等等。因此,需要一种编码方法来将非数值型的类别转换为数值。如果简单地为 k 个可能类别中的每个类别分配一个整数,如从 1 到 k,但这样做的结果是 使类别彼此之间有了顺序,这在分类变量中是不允许的。
- 三个不同城市的公寓价格数据集
5.1.1 one-hot 编码
使用一组比特位,每个比特位表示一种可能的类别。如果变量不能同时属于 多个类别,那么这组值中就只有一个比特位是“开”的。这就是 one-hot 编码,它可以通 过scikit-learn
中 的 sklearn.preprocessing.OneHotEncoder
实 现。 每 个 比 特 位 表 示 一 个 特 征,因此,一个可能有 k 个类别的分类变量就可以编码为一个长度为 k 的特征向量。
- 对3个城市的类别进行独热编码
5.1.2 虚拟编码
one-hot 编码的问题是它允许有 k 个自由度,而变量本身只需要 k-1 个自由度。虚拟编码在进行表示时只使用 k-1 个特征,除去了额外的自由度。没有被使用的那个特征通过一个全零向量来表示,它称为参照类。虚拟编码和 one-hot 编码都可以通过 Pandas 包中的pandas.get_dummies
来实现。
- 对3个城市的类别进行dummy编码
eg:在独热编码上的线性回归
>>> import pandas
>>> from sklearn import linear_model
# 定义一个模拟数据集,表示纽约、旧金山和西雅图的公寓租金
>>> df = pd.DataFrame({'City': ['SF', 'SF', 'SF', 'NYC', 'NYC', 'NYC','Seattle', 'Seattle', 'Seattle'],
'Rent': [3999, 4000, 4001, 3499, 3500, 3501, 2499, 2500, 2501]})
>>> df['Rent'].mean()
3333.3333333333335
# 将数据框中的分类变量转换为one-hot编码并拟合一个线性回归模型
>>> one_hot_df = pd.get_dummies(df, prefix=['city'])
>>> one_hot_df
Rent city_NYC city_SF city_Seattle
0 3999 0 1 0
1 4000 0 1 0
2 4001 0 1 0
3 3499 1 0 0
4 3500 1 0 0
5 3501 1 0 0
6 2499 0 0 1
7 2500 0 0 1
8 2501 0 0 1
model = linear_model.LinearRegression()
model.fit(one_hot_df[['city_NYC', 'city_SF', 'city_Seattle']],
one_hot_df[['Rent']])
>>> model.coef_
array([[ 166.66666667, 666.66666667, -833.33333333]])
>>> model.intercept_
array([ 3333.33333333])
- eg:在虚拟变量上进行线性回归
dummy_df = pd.get_dummies(df, prefix=['city'], drop_first=True)
>>> dummy_df
Rent city_SF city_Seattle
0 3999 1 0
1 4000 1 0
2 4001 1 0
3 3499 0 0
4 3500 0 0
5 3501 0 0
6 2499 0 1
7 2500 0 1
8 2501 0 1
>>> model.fit(dummy_df[['city_SF', 'city_Seattle']], dummy_df['Rent'])
>>> model.coef_
array([ 500., -1000.])
>>> model.intercept_
3500.0
使用 one-hot 编码时,截距项表示目标变量 Rent 的整体均值,每个线性系数表示相应城市的租金均值与整体均值有多大差别。
使用虚拟编码时,偏差系数表示响应变量 y 对于参照类的均值,本例中参照类是纽约。第 i个特征的系数等于第 i 个类别的均值与参照类均值的差。
- 线性回归系数差距
5.1.3 效果编码
分类变量编码的另一种变体称为Effect编码。 Effect编码与虚拟编码非常相似,区别在于参考类别现在由所有-1的向量表示。
- Effect编码表示3个城市
Effect编码与虚拟编码非常相似,但是在线性回归中更容易被拟合。截距项表示目标变量的整体均值,各个系数表示了各个类别的均值与整体均值之间的差。one-hot 编码实际上也可以得到同样的截距和系数,但它的每个城市都有一个线性系数。在 效果编码中,没有单独的特征来表示参照类,所以参照类的效果需要单独计算,它是所有其他类别的系数的相反数之和。
- 使用效果编码的线性回归
>>> effect_df = dummy_df.copy()
>>> effect_df.ix[3:5, ['city_SF', 'city_Seattle']] = -1.0
>>> effect_df
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
>>> model.fit(effect_df[['city_SF', 'city_Seattle']], effect_df['Rent'])
>>> model.coef_
array([ 666.66666667, -833.33333333])
>>> model.intercept_
3333.3333333333335
5.1.4 各种分类变量编码的优缺点
one-hot 编码、虚拟编码和效果编码彼此之间非常相似,它们都有各自的优缺点。one-hot 编码有冗余,这会使得同一个问题有多个有效模型,这种非唯一性有时候比较难以解释。 它的优点是每个特征都明确对应一个类别,而且可以把缺失数据编码为全零向量,模型输 出也是目标变量的总体均值。
虚拟编码和效果编码没有冗余,它们可以生成唯一的可解释的模型。虚拟编码的缺点是不 太容易处理缺失数据,因为全零向量已经映射为参照类了。它还会将每个类别的效果表示 为与参照类的相对值,这看上去有点不直观。
效果编码使用另外一种编码表示参照类,从而避免了这个问题,但是全由 -1 组成的向量 是个密集向量,计算和存储的成本都比较高。正是因为这个原因,像 Pandas 和 scikit-learn 这样的常用机器学习软件包更喜欢使用虚拟编码或 one-hot 编码,而不是效果编码。
当类别的数量变得非常大时,这 3 种编码方式都会出现问题,所以需要另外的策略来处理 超大型分类变量。
5.2 处理大型分类变量
5.2.1 特征散列化
- demo : 使用
scikit-learn
的FeatureHasher
函数
>>> from sklearn.feature_extraction import FeatureHasher
>>> h = FeatureHasher(n_features=m, input_type='string')
>>> f = h.transform(review_df['business_id'])
5.2.2 分箱计数
分箱计数它不使用分类变量的值作为特征,而是使用目标变量取这 个值的条件概率。换句话说,我们不对分类变量的值进行编码,而是要计算分类变量值与 要预测的目标变量之间的相关统计量。
小结
one-hot encoding
空间使用:O(n) 时间复杂度:O(nk)
优点:
- 容易实现
- 更高的精度
- 在线学习特别容易扩展
缺点
- 计算不足
- 如果类别增加则不能够使用
- 对线性模型以外的任何其他方法都不可行
- 对于大数据集需要分布式训练
特征散列化 Feature hashing
空间使用:O(n) 时间复杂度:O(nm)
优点:
- 容易实现
- 容易训练
- 容易扩展到新类别
- 容易处理稀有类别
- 在线学习容易扩展
缺点
- 只能够使用线性或核模型
- 哈希编码很难解释
- 精度有争议
分箱计数 Bin-counting
空间使用:O(n+k) 时间复杂度:O(n)
优点:
- 训练快
- 能够使用树模型
- 容易扩展到新列类别
- 容易处理稀有类别
- 可解释
缺点
- 需要利用历史信息
- 对于在线学习有困难
- 会有数据泄露
参考:《精通特征工程》爱丽丝·郑·阿曼达·卡萨丽
面向机器学习的特征工程学习笔记:
【精通特征工程】学习笔记(一)
【精通特征工程】学习笔记(二)
【精通特征工程】学习笔记(三)