数据预处理:特征编码

发布于:2024-03-28 ⋅ 阅读:(24) ⋅ 点赞:(0)




1、特征编码概述


在机器学习中,处理离散属性(分类特征/类别特征)是一个重要的任务,需要将离散属性转换为可供模型使用的数值表示

机器学习算法本质上都是在基于矩阵做线性代数计算,因此参加计算的特征必须是数值型的,对于非数值型的特征需要进行编码处理

分类特征是用来表示分类的,分类特征是离散的,非连续的。例如性别(男/女)、等级(优/良/合格)等

有些分类特征也是数值,例如,账号ID、IP地址等,但是这些数值并不是连续的。连续的数字是数值特征,离散的数字是分类特征

对于离散型数据的编码,针对小型分类和大型分类,我们通常有以下几种常用的实现方式,它们各有优缺点

2、小型分类特征的编码方式

2.1、序列编码(Ordinal Encoding)


将离散特征的各个类别映射为自然数序号,适用于类别间本来就有一定的排序关系,并且不同样本之间的距离计算有一定的意义。例如,学历中的学士(0)、硕士(1)、博士(2),学士与硕士的距离和硕士与博士的距离相等

以下是序列编码的实现方式:

1)使用Pandas

import pandas as pd

degree_list = ["硕士", "博士", "学士", "硕士"]
data = pd.DataFrame(degree_list, columns=["学历"])
# 手动编码
ordinal_map = {"学士": 0, "硕士": 1, "博士": 2}
data["Code"] = data["学历"].map(ordinal_map)
print(data)
'''
   学历  Code
0  硕士     1
1  博士     2
2  学士     0
3  硕士     1
'''

2)使用Scikit-Learn库

Scikit-Learn库提供了序列编码API:OrdinalEncoder

官方文档:https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OrdinalEncoder.html

中文官方文档:https://scikit-learn.org.cn/view/744.html

import numpy as np
from sklearn.preprocessing import OrdinalEncoder

# 序列编码器
enc = OrdinalEncoder()

# fit_transform():拟合数据,自动编码,需要一个2D数组
data["Code"] = enc.fit_transform(np.array(data["学历"]).reshape(-1, 1))
print(data)
'''
   学历  Code
0  硕士   2.0
1  博士   0.0
2  学士   1.0
3  硕士   2.0
'''
# 解码
print(enc.inverse_transform(np.array(data["Code"]).reshape(-1, 1)))
'''
[['硕士']
 ['博士']
 ['学士']
 ['硕士']]
'''

3)使用Category_Encoders库

Category_Encoders库是一个Python第三方库,涵盖多种编码方式,且与Scikit-Learn完全兼容

官方文档:https://contrib.scikit-learn.org/category_encoders/

安装:

pip install category_encoders
import category_encoders as ce

# 序列编码器
enc = ce.OrdinalEncoder()
# 编码
data["Code"] = enc.fit_transform(data["学历"])
print(data)
'''
   学历  Code
0  硕士     1
1  博士     2
2  学士     3
3  硕士     1
'''
# 解码报错:方法内部调用了get_loc(key),key为被编码的列名,而我们这里重新赋值了,被编码的列值没变
print(enc.inverse_transform(data["Code"]))

2.2、独热编码(One Hot Encoding)


独热编码使用N位状态寄存器来对N个状态(分类)进行编码,每个状态都它独立的寄存器位,并且在任意时刻只有其中一位有效。例如,颜色特征有三种:红、绿、蓝,转换为独热编码分别表示为:001、010、100

像颜色、品牌等这些特征就不适合使用序列编码,因为这些特征是没有排序关系的。使用独热编码可以让不同的分类处在平等的地位

以下是独热编码的实现方式:

1)使用Pandas

colors = ['Green', 'Blue', 'Red', 'Blue']
data = pd.DataFrame(colors, columns=['Color'])
# pd.get_dummies():对DataFrame指定列进行独热编码,默认返回bool类型,可通过dtype指定
data_dum = pd.get_dummies(data['Color'], dtype=int)
print(data_dum)
'''
   Blue  Green  Red
0     0      1    0
1     1      0    0
2     0      0    1
3     1      0    0
'''

2)使用Scikit-Learn库

A、LabelBinarizer:仅支持一维输入

from sklearn.preprocessing import LabelBinarizer, OneHotEncoder

# 独热编码器
lb = LabelBinarizer()
# 编码
colors_code = lb.fit_transform(colors)
print(colors_code)
'''
[[0 1 0]
 [1 0 0]
 [0 0 1]
 [1 0 0]]
'''
# 解码
print(lb.inverse_transform(colors_code))
'''
['Green' 'Blue' 'Red' 'Blue']
'''

B、OneHotEncoder:仅支持二维输入

# 独热编码器
enc = OneHotEncoder()
# 编码
colors_code = enc.fit_transform(np.array(colors).reshape(-1, 1))
print(colors_code.toarray())
'''
[[0. 1. 0.]
 [1. 0. 0.]
 [0. 0. 1.]
 [1. 0. 0.]]
'''
# 解码
print(enc.inverse_transform(colors_code.toarray()))
'''
[['Green']
 ['Blue']
 ['Red']
 ['Blue']]
'''

2.3、标签编码(Label Encoding)


标签编码将每个分类映射到整数值,从0开始递增。和序列编码类似,标签编码同样适用于有序特征,并且不同样本之间的距离计算要有一定的意义

以下是标签编码的实现方式:

1)使用Pandas

# 标签编码:返回二元组,元素1为编码(数组类型);元素2为分类,无重复(Index类型)
codes, ctgs = pd.factorize(data['Color'])
print(codes)   # [0 1 2 1]

2)使用Scikit-Learn库

from sklearn.preprocessing import LabelEncoder

# 标签编码器
le = LabelEncoder()
# 编码
colors_code = le.fit_transform(colors)
print(colors_code)   # [1 0 2 0]
# 解码
print(le.inverse_transform(colors_code))
'''
['Green' 'Blue' 'Red' 'Blue']
'''

2.4、频数编码(Count Encoding)


频数编码将每个类别替换为该类别在数据集中的频数或出现次数。例如类别A在训练集中出现了10次,则类别A的编码为10

以下是频数编码的实现方式:

1)使用Pandas

data = pd.DataFrame({
    "City": ['beijing', 'beijing', 'beijing', 'shanghai', 'shanghai'],
    "Val": [9, 8, 10, 9, 7]
})
# 使用分组计数实现
data_count = data.groupby('City', as_index=False).agg('count')
print(data_count)
'''
       City  Val
0   beijing    3
1  shanghai    2
'''

2)使用Category_Encoders库

import category_encoders as ce

# 频数编码编码器
cen = ce.CountEncoder()
# 编码
data['Code'] = cen.fit_transform(data['City'])
print(data)
'''
       City  Val  Code
0   beijing    9     3
1   beijing    8     3
2   beijing   10     3
3  shanghai    9     2
4  shanghai    7     2
'''

3、大型分类特征的编码方式

3.1、目标编码(Target Encoding)


目标编码是表示分类列的一种非常有效的方法,并且仅占用一个特征空间,也称为均值编码。该列中的每个值都被该类别的平均目标值替代。这可以更直接地表示分类变量和目标变量之间的关系

以下是目标编码的实现方式:

1)使用Pandas

# 使用分组求和/计数实现
data_code = data.groupby('City')['Val'].sum() / data.groupby('City')['City'].count()
print(data_code.reset_index().rename(columns={0: 'Code'}))
'''
       City  Code
0   beijing   9.0
1  shanghai   8.0
'''

2)使用Scikit-Learn库(K折目标编码+正则化:平滑参数smooth)

API文档:https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.TargetEncoder.html

from sklearn.preprocessing import TargetEncoder

# 目标编码器,默认5折
ten = TargetEncoder(target_type='continuous')
# 编码
ten.fit_transform(np.array(data['City']).reshape(-1, 1), data['Val'])
# 类别编码
print(ten.encodings_)     # [array([8.92957746, 8.19480519])]
# 类别
print(ten.categories_)    # [array(['beijing', 'shanghai'], dtype=object)]
# 目标的总体平均值
print(ten.target_mean_)   # 8.6

3)使用Category_Encoders库(正则化:平滑参数smoothing)

API文档:https://contrib.scikit-learn.org/category_encoders/targetencoder.html

from category_encoders.target_encoder import TargetEncoder

# 目标编码器
ten = TargetEncoder(cols=['City'])

# 编码
data['Code'] = ten.fit_transform(data['City'], data['Val'])
print(data)
'''
       City  Val      Code
0   beijing    9  8.661786
1   beijing    8  8.661786
2   beijing   10  8.661786
3  shanghai    9  8.514889
4  shanghai    7  8.514889
'''

3.2、哈希编码(Hashing Encoding)


哈希编码将哈希函数应用于变量,将任意数量的变量以一定的规则映射到给定数量的变量。特征哈希可能会导致元素之间发生冲突

以下是哈希编码的实现方式:

API文档:https://contrib.scikit-learn.org/category_encoders/hashing.html

from category_encoders.hashing import HashingEncoder

# 哈希编码器
hen = HashingEncoder(cols=['City'], n_components=4)

# 编码(此处报错,原因未知,后续补充解决)
print(hen.fit_transform(data['City'], data['Val']))


参考文章:
https://zhuanlan.zhihu.com/p/643196576
https://www.cnblogs.com/dangui/p/15836197.html


本文含有隐藏内容,请 开通VIP 后查看