nominal:本身没有内在顺序的类别,如:蓝色、红色;男性、女性等。
ordinal:天然拥有内在顺序的类别,如:低、中、高;同意、中立、反对等。
方法一:利用sklearn中的LabelBinarizer对特征进行one-hot编码(独热编码)。
import numpy as np
from sklearn.preprocessing import LabelBinarizer, MultiLabelBinarizer
feature = np.array([['Texas'],
['California'],
['Texas'],
['Delaware'],
['Texas']])
# 创建one-hot编码器
one_hot = LabelBinarizer()
# 对特征进行oune-hot编码
print(one_hot.fit_transform(feature))
[[0 0 1]
[1 0 0]
[0 0 1]
[0 1 0]
[0 0 1]]
# 查看特征分类
print(one_hot.classes_)
# oue-hot编码逆转换
print(one_hot.inverse_transform(one_hot.transform(feature)))
['California' 'Delaware' 'Texas']
['Texas' 'California' 'Texas' 'Delaware' 'Texas']
方法二:利用pandas进行one-hot编码
import numpy as np
import pandas as pd
# 创建虚拟变量
print(pd.get_dummies(feature[:,0]))
California Delaware Texas
0 0 0 1
1 1 0 0
2 0 0 1
3 0 1 0
4 0 0 1
其中,sklearn还能处理多个分类情况,利用MultiLabelBinarizer:
multiclass_feature = [('Texas', 'Florida'),
('California', 'Alabama'),
('Delware', 'Florida'),
('Texas', 'Alabama')]
# 创建能处理多个分类的one-hot编码器
one_hot_mlticlass = MultiLabelBinarizer()
# 对特征进行one-hot编码
print(one_hot_mlticlass.fit_transform(multiclass_feature))
# 查看分类
print(one_hot_mlticlass.classes_)
[[0 0 0 1 1]
[1 1 0 0 0]
[0 0 1 1 0]
[1 0 0 0 1]]
['Alabama' 'California' 'Delware' 'Florida' 'Texas']
【说明】:有的人会认为给每一个类别赋予数值型的值(如:1、2、3.....),但是由于这些分类没有内在顺序,使用这样的数值会错误的赋予分类一个并不存在的顺序。所以,正确的策略是为原特征中的每一分类都创建一个二元特征,这个方法成为“one-hot编码”或“虚拟变量”。另外值得注意的是,在one-hot编码后,最好从结果矩阵中删除一个one-hot编码的特征,以避免线性依赖。
利用pandas数据帧的replace方法将字符串转换成相应的数字:
import pandas as pd
# 创建特征
dataframe = pd.DataFrame({'Score': ['Low', 'Low', 'Medium', 'Medium', 'High']})
# 创建映射器
scale_mapper = {'Low':1, 'Medium':2, 'High':3}
# 使用映射器来替换特征
print(dataframe['Score'].replace(scale_mapper))
0 1
1 1
2 2
3 2
4 3
Name: Score, dtype: int64
由此可见,将分类的字符串标签映射为一个数字,然后将其映射在特征上,是个不错的想法。但是关键的一点是,要弄清楚ordinal分类的顺序信息,才能决定每个分类对应的值。在绝大多数场景下是没有问题的,但是如果分类之间的间隔不相等,问题就出现了:解决方案是通过间隔的大小,适当调整数字间隔,来间接的表示分类间隔的问题。
# 创建特征
dataframe = pd.DataFrame({'Score': ['Low', 'Low', 'Medium', 'Medium', 'High','Barely More Than Medium']})
# 创建映射器
scale_mapper = {'Low':1, 'Medium':2, 'Barely More Than Medium':2.1,'High':3}
# 使用映射器来替换特征
print(dataframe['Score'].replace(scale_mapper))
0 1.0
1 1.0
2 2.0
3 2.0
4 3.0
5 2.1
Name: Score, dtype: float64
from sklearn.feature_extraction import DictVectorizer
# 创建一个字典
data_dict = [{'Red': 2, 'Blue': 4},
{'Red': 4, 'Blue': 3},
{'Red': 1, 'Yellow': 2},
{'Red': 2, 'Yellow': 2}]
# 创建字典向量化器
dictvectorizer = DictVectorizer(sparse=False)
# 将字典转换成特征矩阵
features = dictvectorizer.fit_transform(data_dict)
print(features)
# 查看特征的名字
features_names = dictvectorizer.get_feature_names()
print(features_names)
[[4. 2. 0.]
[3. 4. 0.]
[0. 1. 2.]
[0. 2. 2.]]
['Blue', 'Red', 'Yellow']
默认情况下,Dictvectorizer会输出一个稀疏矩阵,如果矩阵很庞大(在自然语言处理中,大矩阵很常见),这么做有助于节省内存。通过sparse=False能强制输出一个稠密矩阵。
import pandas as pd
# 从特征中创建数据帧
print(pd.DataFrame(features, columns=features_names))
Blue Red Yellow
0 4.0 2.0 0.0
1 3.0 4.0 0.0
2 0.0 1.0 2.0
3 0.0 2.0 2.0
有一个分类特征中包含缺失值,需要用预测值来填充,最理想的解决方案是训练一个机器学习分类器来预测缺失值,通常使用KNN分类器:
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
# 用分类特征创建特征矩阵
X = np.array([[0, 2.10, 1.45],
[1, 1.18, 1.33],
[0, 1.22, 1.27],
[1, -0.21, -1.19]])
# 创建带缺失值的特征矩阵
X_with_nan= np.array([[np.nan, 0.87, 1.31],
[np.nan, -0.67, -0.22]])
# 训练KNN分类器
clf = KNeighborsClassifier(3, weights='distance')
trained_model = clf.fit(X[:,1:], X[:,0])
# 预测缺失值的分类
imputed_values = trained_model.predict(X_with_nan[:,1:])
# 将所预测的分类和它们的其他特征连接起来
X_with_imputed = np.hstack((imputed_values.reshape(-1,1), X_with_nan[:,1:]))
# 连接两个特征矩阵
print(np.vstack((X_with_imputed, X)))
[[ 0. 0.87 1.31] //预测结果为0
[ 1. -0.67 -0.22] //预测结果为1
[ 0. 2.1 1.45]
[ 1. 1.18 1.33]
[ 0. 1.22 1.27]
[ 1. -0.21 -1.19]]
另一个解决方案:用特征中出现次数最多的值来填充缺失值:
from sklearn.preprocessing import Imputer
# 连接两个特征矩阵
X_complete = np.vstack((X_with_nan, X))
imputer = Imputer(strategy='most_frequent', axis=0)
print(imputer.fit_transform(X_complete))
[[ 0. 0.87 1.31] //次数最多的值0
[ 0. -0.67 -0.22] //次数最多的值0
[ 0. 2.1 1.45]
[ 1. 1.18 1.33]
[ 0. 1.22 1.27]
[ 1. -0.21 -1.19]]
【说明】:当分类特征中存在缺失值时,最好的解决方案是利用机器学习算法预测缺失值,将带缺失值的特征作为目标向量,将其他特征作为特征矩阵,就能完成预测。常用的算法是KNN(以后的篇幅里会专门写),它将k个最近的观察之的中位数作为缺失值的补充值。另外,可以用特征中出现次数最多的分类来填充缺失值,虽然比KNN差一些,但是它更容易扩展到大数据集上。
处理一个分类极度不均衡的目标向量,主要有三种方案:
(1)收集更多数据
(2)改变评估模型的衡量标准
(3)考虑嵌入分类权重参数的模型、下采样或上采样
下面我们将利用经典数据集费雪鸢尾花来进行练习:
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
# 加载费雪鸢尾花数据集
iris = load_iris()
# 创建特征矩阵
features = iris.data
# 创建目标向量
target = iris.target
# 移除前40个观察值
features = features[40:, :]
target = target[40:]
# 创建二元目标向量来标识是否为分类0
target = np.where((target == 0), 0, 1)
# 查看不均衡的目标向量
print(target)
[0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]
scikit-learn的很多算法都提供了一个参数,可以在训练时对分类进行加权,以此抵消分类数据不均衡带来的影响。参数class_weight:显式指定分类权重:
# 创建权重
weights = {0:.9, 1: 0.1}
# 创建带权重的随机森林分类器
print(RandomForestClassifier(class_weight=weights))
RandomForestClassifier(bootstrap=True, ccp_alpha=0.0,
class_weight={0: 0.9, 1: 0.1}, criterion='gini',
max_depth=None, max_features='auto', max_leaf_nodes=None,
max_samples=None, min_impurity_decrease=0.0,
min_impurity_split=None, min_samples_leaf=1,
min_samples_split=2, min_weight_fraction_leaf=0.0,
n_estimators=100, n_jobs=None, oob_score=False,
random_state=None, verbose=0, warm_start=False)
# 训练一个带均衡分类权重的随机森林分类器
RandomForestClassifier(class_weight='balanced')
【说明】:处理不均衡的分类解决方案优解顺序:
(1)收集更多数据
(2)选择更适用于评估不均衡数据的标准
(3)分类权重参数
(4)下采样、上采样
评论