Pyhton机器学习手册(五)

第5章 处理分类数据

有时,根据某种特征而不是数量来度量对象会更有效。通常使用这种定性的信息来判断一个观察值的属性,比如按照性别、颜色这样的类别对其进行分类。但并不是所有的分类数据都是这样的。有的数据本身没有内在顺序的类别称为nominal;有的数据天然拥有内在的顺序称为ordinal。
(1)本身没有内在的顺序,如下列示例:

  • 蓝色、红色、绿色
  • 男性、女性
  • 香蕉、草莓、苹果

(2)天然拥有内在的顺序,如下列示例:

  • 低、中、高
  • 年轻、年迈

分类信息通常用一个字符串型的向量或列(例如,“Maine”,“Texas”,“Delaware”)表示,但是大部分机器学习算法都要求其输入是数值型的数据。
KNN算法就是一个简单的例子。该算法的第一步是家算两个观察值之间的距离,通常使用的是欧氏距离。

5.1 对nominal型分类特征进行编码

利用scikit-learn的LableBinarizer对特征进行one-hot编码(独热编码)

onehot编码又叫独热编码,其为一位有效编码,主要是采用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候只有一位有效.
onehot编码是分类变量作为二进制向量的表示。这首先要求将分类值映射到整数值。然后,每个整数值被表示为二进制向量,除了整数的索引之外,它都是零值,它被标记为1。

举个例子:
在机器学习算法中,我们经常会遇到分类特征。
例如:人的性别有男女,祖国有中国,美国,法国等。
这些特征值并不是连续的,而是离散的,无序的。
通常我们需要对其进行特征数字化。
那什么是特征数字化呢?如下:

1.性别特征:[“男”,“女”]
按照N位状态寄存器来对N个状态进行编码的原理,咱们处理后应该是这样的(这里只有两个特征,所以N=2):
男 → 10
女 → 01
2.祖国特征:[“中国”,"美国,“法国”](N=3):
中国 → 100
美国 → 010
法国 → 001
3.运动特征:[“足球”,“篮球”,“羽毛球”,“乒乓球”](N=4):
足球 → 1000
篮球 → 0100
羽毛球 → 0010
乒乓球 → 0001

当一个样本为[“男”,“中国”,“乒乓球”]的时候,完整的特征数字化的结果为:
[1,0,1,0,0,0,0,0,1]
其实就是对应,男(01),中国(100),乒乓球(0001)合起来的编码

#加载库
import numpy  as np
from sklearn.preprocessing import  LabelBinarizer,MultiLabelBinarizer
#创建特征
feature=np.array([["Texas"],["California"],["Texas"],["Delaware"],["Texas"]])
#创建one-hot编码器
one_hot=LabelBinarizer()
#对特征进行ont—hot编码
one_hot.fit_transform(feature)

在这里插入图片描述

#可以使用classes_方法输出分类
#查看特征的分类
one_hot.classes_

在这里插入图片描述

如果希望对one-hot编码进行逆转换,可以使用inverse_transfrom

#对one-hot编码逆转换
one_hot.inverse_transform(one_hot.transform(feature))

在这里插入图片描述
可以使用pandas对特征进行one-hot编码

#加载库
import pandas as pd
#创建虚拟变量
pd.get_dummies(feature[:,0])

在这里插入图片描述
scikit-learn还能处理每个观察值有多个分类的情况

#创建有多个分类的特征
multiclass_feature = [("Texas","Florida"),("California","Alabama"),("Texas","Florida"),("Delware","Florida"),("Texas","Alabama")]
#创建能处理多个分类任务的one-hot编码器
one_hot_multiclass = MultiLabelBinarizer()
#对特征进行one-hot编码
one_hot_multiclass.fit_transform(multiclass_feature)

在这里插入图片描述

#查看分类
one_hot_multiclass.classes_

在这里插入图片描述
给每个分类赋予一个数值型的值是一个很不错的方法(California=1,Alabama=2)但是由于分类并没有内在的顺序,对分类进行数值赋值就会产生一个顺序问题。因此对分类创建二元特征,这种方法被称为one-hot编码。每个分类被当作一个特征,如果特征存在就赋值为1,不存在就赋值为0(时刻牢记分类没有层级)
在one-hot编码后,最好从结果矩阵中删除一个one-hot编码的特征,以避免线性依赖。

5.2 对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)

在这里插入图片描述
用于机器学习的特征进行编码时,需要将ordinal分类转换成数值,同时保留其顺序。最常见的方法就是,创建一个字典,将分类的字符串映射成一个数字,然后将其映射在特征值上。
有一点很关键,只有知道ordinal分类的顺序信息,才能决定每个分类对应的数值。

5.3 对特征字典编码

将一个字典转换成一个特征矩阵,使用DictVectorizer

#加载库
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)
#将字典转换成特征矩阵
feature = dictvectorizer.fit_transform(data_dict)
#查看特征矩阵
feature

在这里插入图片描述
通常情况下,DictVectorizer会输出一个稀疏矩阵来存储0以外的元素。如果矩阵很庞大(在自然语言处理中,大矩阵是很常见的),这么做有助于节省内存。通过指定sparse=False能强制DictVectorize输出一个稠密矩阵
使用get_featue_names方法可以获取所生成的特征的名字

#获取特征的名字
feature_names=dictvectorizer.get_feature_names()
#查看特征的名字
feature_names

在这里插入图片描述

# 使用pandas的数据帧,一边更清楚的查看输出(虽然不是必须)
#加载库
import pandas as pd 
#从特征中创建数据帧
pd.DataFrame(feature,columns=feature_names)

在这里插入图片描述
机器学习算法要求数据结构是矩阵的形式,可以使用scikit-abslearn的dictvectorize可以实现这样的转换

5.4 填充缺失的分类值

有一个分类特征中包含缺失值,需要用预测值来填充
1、训练一个机器学习分类器来预测缺失值,通常会使用KNN
2、用特征中出现次数最多的值来填充缺失值

#方法1
#加载库
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
#用分类特征创建特征矩阵
X = np.array([[0,2.10,1.45],[1,1.18,1.33],[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))

在这里插入图片描述

# 方法2
from sklearn.preprocessing import Imputer
#连接连个特征矩阵
X_complete = np.vstack((X_with_nan,X))
imputer = Imputer(strategy='most_frequent',axis=0)
imputer.fit_transform(X_complete)

在这里插入图片描述
存在缺失值时,最好的解决方案是利用机器学习算法预测缺失值,将带缺失值的特征作为目标向量,其他特征作为特征矩阵,就能完成预测。
常用的KNN算法,将k个最近的观察值的中位数作为缺失值的填充值。
还可以用特征中出现次数最多的分类来填充缺失值。

5.5 处理不均衡分类

处理不均衡分类
方法1:收集更多的数据
方法2:无法收集更多的数据,改变评估模型的衡量标准
方法3:考虑嵌入分类权重参数的模型、scale_mapper采样、下采样

费雪鸢尾花数据集,包含了3个均衡的分类,每个分类有59个观察值,都标注了花的种类,山鸢尾花、维吉尼亚鸢尾、变色鸢尾。
为了不均衡的数据,先将40个山鸢尾花的数据移除,并将剩下两个鸢尾花的数据合并。
得到了一个二元目标向量,表示一个观察值的分类是否为山鸢尾。最后显示数据中有10个观察值是山鸢尾,有100个观察值不是山鸢尾。

#加载库
import numpy as np 
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
#加载鸢尾花数据
iris = load_iris()
#创建特征矩阵
target = iris.target
#移除前40个观察值
features =feature[40:,:]
target = target[40:]
#创建二元目标向量来标识观察值是否为类别0
target = np.where((target == 0),0,1)
#查看不均衡的目标向量
target 

在这里插入图片描述
scikit-learn的很多算法都提供了一个参数,可以在训练时对分类进行加权,以此抵消分类数据不均衡带来的影响。虽然之前没有提及,但是RandomForestClassifier是一个流行的算法,它也有一个class_weight参数。这个参数可以显示地指定想要的分类权重。

#创建权重
weights = {0:.9,1:0.1}
#创建带权重的随机森林分类器
RandomForestClassifier(class_weight=weights)
RandomForestClassifier(bootstrap=True,class_weight={0:0.9,1:0.1},criterion='gini',max_depth=None,max_features='auto',max_leaf_nodes=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=10,n_jobs=1,oob_score=False,random_state=None,verbose=0,warm_start=False)
#还可以传入参数balance,它会自动创建与分类的频数成反比的权重
#训练一个带均衡分类权重的随机森林分类器
# RandomForestClassifierandom(class_weight="balanced")
# RandomForestClassifier(bootstrap=True,class_weight='balanced',criterion='gini',max_depth=None,max_feature='auto',max_leaf_nodes=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=10,n_jobs=1,oob_score=False,random_state=None,verbose=0,warm_start=False)

在这里插入图片描述
对占多数的分类进行下采样和对占少数的分类进行上采样是种不错的方法。
下采样中,从占多数的分类(拥有更多观察值的分类)无放回地随机去除观察值,创建一个观察值数量与占少数的分类相同的子集。例如:如果占少数的分类有10个观察值,那么就从占多数的分类中随机无放回地选取10个观察值,然后用这20个观察值作为数据集。

#给每个分类的观察值打标签
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的观察值,从分类为1的数据中进行无放回的随机采样
i_class1_downsampled = np.random.choice(i_class1,size=n_class0,replace=False)

#将分类为0的目标向量和下采样的分类为1的目标向量连接起来
np.hstack((target[i_class0],target[i_class1_downsampled]))

#将分类为0的特征矩阵和下采样的分类为1的特征矩阵连接起来
np.vstack((features[i_class0,:],features[i_class1_downsampled,:]))[0:5]

另一个选择是对占多数的分类进行上采样。在上采样中,针对占多数的分类,从占少数的分类中进行有放回的随机采样。在最后得到的结果中,占少数的分类和站多数的分类观察值数量时是相同的。上采样和下采样的实现方式相似,只是反转了一下

#对于每个分类为1的观察值,从分类为0的数据中方进行有放回的随机采样
i_class0_upsampled = np.random.choice(i_class0,size=n_class1,replace=True)

#将上采样得到的分类为0的目标向量和分类为1的目标向量连接起来
np.concatenate((target[i_class0_upsampled],target[i_class1]))

#将上采样得到的分类为0的特征矩阵和分类为1的特征矩阵连接起来
np.vstack((features[i_class0_upsampled,:],features[i_class1,:]))[0:5]

收工!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值