视频作者:菜菜TsaiTsai
链接:【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili
多标签和特征在数据收集完毕的时候,都不是以数字来表现的。比如说,学历的取值可以是["小学",“初中”,“高中”,"大学"]
,付费方式可能包含["支付宝",“现金”,“微信”]
等等。在这种情况下,为了让数据适应算法和库,我们必须将数据进行编码,即是说,将文字型数据转换为数值型。
LabelEncoder标签专用,能够将分类转换为分类数值
LabelEncoder()
# 啥也没有,作用就是把标签变成0-种类-1的值
y = data.iloc[:,-1] # 要输入的是标签,不是特征矩阵,所以允许一维,也允许高维,例如多标签问题
le = LabelEncoder() # 实例化
le = le.fit(y) # 导入数据
label = le.transform(y) # transform接口调取结果
np.unique(label) # 扔到set()里也行
---
array([0, 1, 2])
data.iloc[:,-1] = label
data.head()
---
Age Sex Embarked Survived
0 22.0 male S 0
1 38.0 female C 2
2 26.0 female S 2
3 35.0 female S 2
4 35.0 male S 0
np.unique(le.fit_transform(y))
data.iloc[:,-1] = LabelEncoder().fit_transform(data.iloc[:,-1]) # 一行完成
le.classes_# 属性.classer_查看标签中究竟有多少类别
---
array(['No', 'Unknown', 'Yes'], dtype=object)
np.unique(le.inverse_transform(label)) # 逆转
---
array(['No', 'Unknown', 'Yes'], dtype=object)
OrdinalEncoder:特征专用,能够将分类特征转换为分类数值
OrdinalEncoder(categories='auto', dtype=<class 'numpy.float64'>)
# 一般默认,类似LabelEncoder
from sklearn.preprocessing import OrdinalEncoder # 特征专用
data_ = data.copy()
data_.head()
---
Age Sex Embarked Survived
0 22.0 male S 0
1 38.0 female C 2
2 26.0 female S 2
3 35.0 female S 2
4 35.0 male S 0
OrdinalEncoder().fit(data_.iloc[:,[1,2]]).categories_
# OrdinalEncoder().fit(data_.iloc[:,1:-1]).categories_
# iloc包括前不包括后
---
[array(['female', 'male'], dtype=object), array(['C', 'Q', 'S'], dtype=object)]
data_.iloc[:,1:-1] = OrdinalEncoder().fit_transform(data_.iloc[:,1:-1])
data_.head()
---
Age Sex Embarked Survived
0 22.0 1.0 2.0 0
1 38.0 0.0 0.0 2
2 26.0 0.0 2.0 2
3 35.0 0.0 2.0 2
4 35.0 1.0 2.0 0
np.unique(data_.loc[:,'Embarked'])
---
array([0., 1., 2.])
OneHotEncoder:独热编码,创建哑变量
刚才已经用OrdinalEncoder把分类变量Sex和Embarked都转换成数字对应的类别了。在舱门Embarked这一列中,我们使用 [ 0 , 1 , 2 ] [0,1,2] [0,1,2]代表了三个不同的舱门,然而这种转换不是完全正确的,0,1,2之间有运算关系,但舱门显然没有,我们对于这些有不同性质的变量进行定义
然而在对特征进行编码的时候,这三种分类数据都会被我们转换为 [ 0 , 1 , 2 ] [0,1,2] [0,1,2],这三个数字在算法看来,是连续且可以计算的,这三个数字相互不等,有大小,并且有着可以相加相乘的联系。所以算法会把舱门这样的分类特征,都误会成是分类特征。
OrdinalEncoder可以用来处理有序变量,但对于名义变量,我们只有使用OneHotEncoder哑变量的方式来处理,才能够尽量向算法传达最准确的信息:
这样的变化,让算法能够彻底领悟,原来三个取值是没有可计算性质的,是“有你就没有我”的不等概念。在我们的数据中,性别和舱门,都是这样的名义变量。因此我们需要使用独热编码,将两个特征都转换为哑变量。
OneHotEncoder(
['n_values=None', 'categorical_features=None', 'categories=None', 'sparse=True', "dtype=" , "handle_unknown='error'"],
)
# 0.20以后不需要设置什么,默认就可以
from sklearn.preprocessing import OneHotEncoder
X = data.iloc[:,1:-1]
X.info()
---
<class 'pandas.core.frame.DataFrame'>
Int64Index: 889 entries, 0 to 890
Data columns (total 2 columns):
Sex 889 non-null object
Embarked 889 non-null object
dtypes: object(2)
memory usage: 20.8+ KB
enc = OneHotEncoder(categories='auto').fit(X) # 注意不能有空值
# categorties:每个特征中有几个类别,输入类别数量列表,或者默认categories='auto'自动匹配,不需要填写
result = enc.transform(X).toarray()
# enc.tranfrom(X)生成稀疏矩阵对象
result# 这五列,男女各占一列,舱门SCQ各占一列
---
array([[0., 1., 0., 0., 1.],
[1., 0., 1., 0., 0.],
[1., 0., 0., 0., 1.],
...,
[1., 0., 0., 0., 1.],
[0., 1., 1., 0., 0.],
[0., 1., 0., 1., 0.]])
OneHotEncoder(categories='auto').fit_transform(X).toarray()# 一步到位
enc.inverse_transform(result)# 也可以还原
---
array([['male', 'S'],
['female', 'C'],
['female', 'S'],
...,
['female', 'S'],
['male', 'C'],
['male', 'Q']], dtype=object)
enc.get_feature_names() # 稀疏矩阵中每个列代表什么
# 第一项代表哪个哑变量,第二项代表该变量的取值是什么
---
array(['x0_female', 'x0_male', 'x1_C', 'x1_Q', 'x1_S'], dtype=object)
# axis=1代表跨行合并,增宽,axis=1代表跨列合并,增长
newdata = pd.concat([data,pd.DataFrame(result)],axis=1)
newdata.head()
---
Age Sex Embarked Survived 0 1 2 3 4
0 22.0 male S No 0.0 1.0 0.0 0.0 1.0
1 38.0 female C Yes 1.0 0.0 1.0 0.0 0.0
2 26.0 female S Yes 1.0 0.0 0.0 0.0 1.0
3 35.0 female S Yes 1.0 0.0 0.0 0.0 1.0
4 35.0 male S No 0.0 1.0 0.0 0.0 1.0
newdata.drop(['Sex','Embarked'],axis=1,inplace=True)# 第一个参数删除的索引,axis=1删除列
newdata.columns = ['Age','Survived','Female','Male','Embarked_C','Embarked_Q','Embarked_S']
newdata.head()
---
Age Survived Female Male Embarked_C Embarked_Q Embarked_S
0 22.0 No 0.0 1.0 0.0 0.0 1.0
1 38.0 Yes 1.0 0.0 1.0 0.0 0.0
2 26.0 Yes 1.0 0.0 0.0 0.0 1.0
3 35.0 Yes 1.0 0.0 0.0 0.0 1.0
4 35.0 No 0.0 1.0 0.0 0.0 1.0
使用类sklearn.preprocessing.LabelBinarizer可以对做哑变量,许多算法都可以处理多标签问题(比如说决策树),但是这样的做法在现实中不常见,因此我们在这里就不赘述了。
Binarizer,根据阈值将数据二值化(将特征值设置为0或1),用于处理连续型变量。大于阈值的值映射为1,而小于或等于阈值的值映射为0。默认阈值为0
Binarizer(threshold=0.0, copy=True)
# threshold:阈值,默认为0
from sklearn.preprocessing import Binarizer # 连续型变量才能分箱
data_2 = data.copy()
data_2.head()
---
Age Sex Embarked Survived
0 22.0 male S No
1 38.0 female C Yes
2 26.0 female S Yes
3 35.0 female S Yes
4 35.0 male S No
X = data_2.iloc[:,0].values.reshape(-1,1)# 类为特征专用,所以不能使用一维数组
transformer = Binarizer(threshold=30).fit_transform(X)
transformer[:5,:]
---
array([[0.],
[1.],
[0.],
[1.],
[1.]])
data_2.iloc[:,0] = transformer
BinsDiscretizer,连续型变量划分为多个分类变量的类,能够将连续型变量排序后按顺序分箱后编码。
KBinsDiscretizer(n_bins=5, encode='onehot', strategy='quantile')
# n_bins:每个特征中分箱的个数,默认5,一次会被运用到所有导入的特征
# encode:编码的方式,默认“onehot” ,做哑变量,之后返回一个稀疏矩阵,每一列是一个特征中的一个类别,含有该类别的样本表示为1,不含的表示为0 ;“ordinal”,每个特征的每个箱都被编码为一个整数,返回每一列是一个特征,每个特征下含有不同整数编码的箱的矩阵
# strategy:用来定义箱宽的方式,默认"quantile" 表示等位分箱,即每个特征中的每个箱内的样本数量都相同;"uniform",表示等宽分箱,即每个特征中的每个箱的最大值之间的差为 (特征.max() - 特征.min())/(n_bins)
from sklearn.preprocessing import KBinsDiscretizer
X = data.iloc[:,0].values.reshape(-1,1)
est = KBinsDiscretizer(n_bins=3,encode='ordinal',strategy='uniform').fit_transform(X)
# 'ordinal'一个特征一列,等宽分箱
set(est.ravel())
---
{0.0, 1.0, 2.0}
est[:5,:]
---
array([[0.],
[1.],
[0.],
[1.],
[1.]])
est = KBinsDiscretizer(n_bins=3,encode='onehot',strategy='uniform').fit_transform(X).toarray()
# 独热编码生成稀疏矩阵对象,所以要toarray()
est[:5,:]
---
array([[1., 0., 0.],
[0., 1., 0.],
[1., 0., 0.],
[0., 1., 0.],
[0., 1., 0.]])
DataFrame对象需要iloc或者loc索引,ndarray对象不能用iloc、loc,直接用[]索引即可