【python数据分析入门到高级】:分类型数据处理
在构建模型时,我们经常遇见一些分类型数据,此时需要对这些分类型数据进行相应转换。本章介绍如何使用python处理分类型数据,首先分类型数据主要包括以下两种。
- 本身没有顺序的称为nominal,也称为==名义变量==
例如性别 - 本身具有顺序的称为ordinal,也称为==定序变量==
例如年纪:老年、中年、青年
如果我们不对分类型数据进行处理的话,那么无法将它们直接构建模型,在机器学习中,处理分类型数据最常用的方法是进行one-hot(独热编码)
1.对名义变量进行转换
使用sklearn的LabelBinarizer对这些分类数据进行编码,具体代码如下
# 导入相关库 import numpy as np from sklearn.preprocessing import LabelBinarizer, MultiLabelBinarizer
# 创建模拟数据 feature = np.array([['Texas'], ['California'], ['Texas'], ['Delaware'], ['Texas']])
# 创建one-hot编码器 也就是将其以矩阵0 1 来表示, one_hot = LabelBinarizer()
classes = one_hot.fit_transform(feature)
classes
array([[0, 0, 1], [1, 0, 0], [0, 0, 1], [0, 1, 0], [0, 0, 1]])
如上图所示,001表示Texas,010表示Delaware
使用classes_查看分类
one_hot.classes_
array(['California', 'Delaware', 'Texas'], dtype='<U10')
# 对one_hot 进行逆编码转换 one_hot.inverse_transform(classes)
array(['Texas', 'California', 'Texas', 'Delaware', 'Texas'], dtype='<U10')
import pandas as pd
使用pandas来进行one-hot编码
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 还可以处理每个观测值有多个分类的情况 multiclass_feature = [('Texas', 'Florida'), ('California', 'Alabama'), ('Texas', 'Florida'), ('Delware', 'Florida'), ('Texas', 'Alabama')]
one_hot_multiclass = MultiLabelBinarizer()
one_hot_multiclass.fit_transform(multiclass_feature)
array([[0, 0, 0, 1, 1], [1, 1, 0, 0, 0], [0, 0, 0, 1, 1], [0, 0, 1, 1, 0], [1, 0, 0, 0, 1]])
one_hot_multiclass.classes_
array(['Alabama', 'California', 'Delware', 'Florida', 'Texas'], dtype=object)
2.对ordinal分类特征编码
对于定序类变量,这些变量的取值是有一定顺序的,此时,我们需要指定对应的编码
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 Name: Score, dtype: int64
其中:
- 1-Low
- 2-Medium
- 3-High
3. 对特征字典编码
有的时候我们还会遇见一些特征字典,例如颜色的RGB值,如下所示
data_dict = [{'Red':2, 'Blue':4}, {'Red':2, 'Blue':3}, {'Red':1, 'Yellow':2}, {'Red':2, 'Yellow':2}] data_dict
[{'Red': 2, 'Blue': 4}, {'Red': 2, 'Blue': 3}, {'Red': 1, 'Yellow': 2}, {'Red': 2, 'Yellow': 2}]
此时的data_dict就是一个特征字典,下面我们看如何使用DictVectorizer将其进行编码
from sklearn.feature_extraction import DictVectorizer
dictvectorizer = DictVectorizer(sparse=False)# 默认的是会返回稀疏矩阵,此时由于矩阵比较小,我们设置强制返回稠密矩阵
features = dictvectorizer.fit_transform(data_dict)
features
array([[4., 2., 0.], [3., 2., 0.], [0., 1., 2.], [0., 2., 2.]])
第一列表示Blue的值,第二列表示Red的值,第三列表示Yellow的值
feature_names = dictvectorizer.get_feature_names() feature_names
['Blue', 'Red', 'Yellow']
pd.DataFrame(features, columns=feature_names)
Blue | Red | Yellow | |
---|---|---|---|
0 | 4.0 | 2.0 | 0.0 |
1 | 3.0 | 2.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]])
# 第一列为nan X_with_nan = np.array([[np.nan, 0.87, 1.31], [np.nan, -0.67, -0.22]])
# 训练knn分类器 clf = KNeighborsClassifier(3, weights='distance') train_model = clf.fit(X[:, 1:], X[:,0])
# 预测缺失值的分类 imputed_values = train_model.predict(X_with_nan[:,1:])
# 将所预测的分类与原来的特征连接 X_with_imputed = np.hstack((imputed_values.reshape((2,1)), X_with_nan[:,1:]))
X_with_imputed
array([[ 0. , 0.87, 1.31], [ 1. , -0.67, -0.22]])
np.vstack((X, X_with_imputed))
array([[ 0. , 2.1 , 1.45], [ 1. , 1.18, 1.33], [ 0. , 1.22, 1.27], [ 1. , -0.21, -1.19], [ 0. , 0.87, 1.31], [ 1. , -0.67, -0.22]])
这种方法是通过将其他特征作为特征矩阵来进行预测,从而求得缺失值
==方法二==:选取特征中出现最多的特征值来进行填充,使用simpleimputer
# 导入相关库 from sklearn.impute import SimpleImputer
X_complete = np.vstack((X,X_with_imputed))
imputet = SimpleImputer(strategy='most_frequent')
imputet.fit_transform(X_complete)
array([[ 0. , 2.1 , 1.45], [ 1. , 1.18, 1.33], [ 0. , 1.22, 1.27], [ 1. , -0.21, -1.19], [ 0. , 0.87, 1.31], [ 1. , -0.67, -0.22]])
方法二在处理很多数据的时候可能会方便一些,方法一使用KNN预测的效果更好
5. 处理不均衡分类
- 收集更多的数据
- 改变评估模型的衡量标准
- 使用嵌入分类权重参数的模型
使用鸢(yuan)尾花 数据集 ,默认每种类型都有五十个数据,这里我们删除山鸢尾的四十个数据
# 首先导入相关数据 from sklearn.datasets import load_iris from sklearn.ensemble import RandomForestClassifier#随机森林分类器
# 加载iris数据集 iris = load_iris()
features = iris.data
target = iris.target target
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])
# 移除前40个features features = features[40:, :] target = target[40:]
# 转换成一个二元来观察观测值是否为0 target = np.where((target == 0), 0, 1)
target
array([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])
对于这种不均衡的数据,我们可以选择在训练时对其进行加权处理,我们在这里使用随机森林分类,通过weights参数来进行处理权重
# 创建权重 weights = {0: .9, 1:0.1}
# 创建一个带权重的随机森林分类器 RandomForestClassifier(class_weight=weights)
RandomForestClassifier(class_weight={0: 0.9, 1: 0.1})
还可以传入balanced参数,自动创建于分类的频数成反比的权重
# 训练一个带均衡分类权重的随机森林分类器 RandomForestClassifier(class_weight='balanced')
RandomForestClassifier(class_weight='balanced')
6.重采样
处理不均衡分类数据的另一个思路是使用重采样方法,对占多数的使用下采样,对占少数部分的使用上采样,在下采样中,从占多数的分类中取出观测值,创建一个数量与占少数的分类相同的子集
下面对鸢尾花数据进行操作
# 给每个分类的观察值标签 i_class0 = np.where(target==0)[0] i_class1 = np.where(target==1)[0]
# 计算每个分类值的观察值数量 n_class0 = len(i_class0) n_class1 = len(i_class1)
# 对于每个分类为0的观察值,从分类为一的数据进行无放回的随机采样 i_class1_downsampled = np.random.choice(i_class1, size=n_class0, replace=False)
np.hstack((target[i_class0], target[i_class1_downsampled]))
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
# 将分类为0和分类为1的特征矩阵连接起来 np.vstack((features[i_class0,:], features[i_class1_downsampled, :]))[0:5]
array([[5. , 3.5, 1.3, 0.3], [4.5, 2.3, 1.3, 0.3], [4.4, 3.2, 1.3, 0.2], [5. , 3.5, 1.6, 0.6], [5.1, 3.8, 1.9, 0.4]])