有时候根据某种特征而不是数量来度量对象会更有效。常常使用这种定性的信息来判断一个观察值的属性,比如按照性别、颜色或者车的品牌这样的类别对其进行分类。但并不是所有的分类数据都是这样的。本身没有内在顺序的类别称为nominal,相反,如果一组分类天然拥有内在的顺序性,就被称为ordinal。
1. 对nominal型分类特征编码
存在一个没有内部顺序的nominal型分类特征,现在对其进行处理
- 利用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()
#对特征进行one-hot编码
one_hot.fit_transform(feature)
—>
array([[0, 0, 1],
[1, 0, 0],
[0, 0, 1],
[0, 1, 0],
[0, 0, 1]])
#对one-hot编码逆转换
one_hot.inverse_transform(one_hot.transform(feature))
—>
array(['Texas', 'California', 'Texas', 'Delaware', 'Texas'], dtype='<U10')
- 使用pandas对特征进行one-hot编码:
import pandas as pd
#创建虚拟变量
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
scikit-learn还可以处理每个观察值存在对个分类的情况,使用MultiLabelBinarizer()。
另外,在one-hot编码之后,最好从结果矩阵中删除一个one-hot编码的特征,以避免线性依赖。
2. 对ordinal分类特征编码
问题描述:存在一个ordinal分类特征(例如,高,中等,低),现在要对其编码。
解决方案:使用pandas数据帧的replace方法将字符串标签转换成相应的数字。
import pandas as pd
#创建特征
dataframe = pd.DataFrame({"score":["Low","Low","Medium","Medium","High"]})
#创建映射器
scale_mapper = {"Low":1,
"Medium":2,
"High":3}
#使用映射器来替换特征
dataframe['score'].replace(scale_mapper)
—>
0 1
1 1
2 2
3 2
4 3
对那些用于机器学习的特征进行编码时,需要将ordinal分类转换成数值,同时保留其顺序。最常见的方法就是,创建一个字典,将分类的字符串映射成一个数字,然后将其映射在特征上。
3. 对特征字典编码
使用DictVectorizer将一个字典转换成一个特征矩阵:
from sklearn.feature_extraction import DictVectorizer
#创建一个字典
data_dict = [{"Red":2,"Blue":4},
{"Red":4,"Blue":3},
{"Red":1,"Yello":2},
{"Red":2,"Yello":2}]
#创建字典向量化器
dictvectorizer = DictVectorizer(sparse=False)
#将字典转换成特征矩阵
features = dictvectorizer.fit_transform(data_dict)
#查看特征矩阵
features
—>
array([[4., 2., 0.],
[3., 4., 0.],
[0., 1., 2.],
[0., 2., 2.]])
默认情况下,Dictvectorizer会输出一个稀疏矩阵来存储除0以外的元素。如果矩阵很庞大,这么做有助于节省内存。通过指定sparse=False能强制DictVectorizer输出一个稠密矩阵。
使用get_feature_names方法可以获得所生成的特征的名字:
#获取特征的名字
feature_names = dictvectorizer.get_feature_names()
feature_names
—>
['Blue', 'Red', 'Yello']
import pandas as pd
#从特征中创建数据帧
pd.DataFrame(features,columns=feature_names)
—>
Blue Red Yello
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
4. 填充缺失的分类值
问题描述:有一个分类特征中包含缺失值,需要用预测值来填充。
解决方案:最理想的解决方案是训练一个机器学习分类器来预测缺失值,通常会使用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:]))
#连接两个特征矩阵
np.vstack((X_with_imputed,X))
—>
array([[ 0. , 0.87, 1.31],
[ 1. , -0.67, -0.22],
[ 0. , 2.1 , 1.45],
[ 1. , 1.18, 1.33],
[ 0. , 1.22, 1.27],
[ 1. , -0.21, -1.19]])
另一个解决方案是用特征中出现次数最多的值来填充缺失值
from sklearn.impute import SimpleImputer
#连接两个特征矩阵
X_complete = np.vstack((X_with_nan,X))
imputer = SimpleImputer(missing_values=np.nan,strategy='most_frequent')
imputer.fit_transform(X_complete)
—>
array([[ 0. , 0.87, 1.31],
[ 0. , -0.67, -0.22],
[ 0. , 2.1 , 1.45],
[ 1. , 1.18, 1.33],
[ 0. , 1.22, 1.27],
[ 1. , -0.21, -1.19]])
当分类特征中存在缺失值时,最好的解决方案是利用机器学习算法预测缺失值。将带缺失值的特征作为目标向量,将其他特征作为特征矩阵,就能完成预测。常用的算法是KNN,它会将k个最近的观察值的中位数作为缺失值的填充值。
另外,可以用特征中出现次数最多的分类来填充缺失值。虽然比使用KNN效果差一些,但是能更容易地扩展到大数据集上。