课程地址:《菜菜的机器学习sklearn课堂》_哔哩哔哩_bilibili
- 第一期:sklearn入门 & 决策树在sklearn中的实现
- 第二期:随机森林在sklearn中的实现
- 第三期:sklearn中的数据预处理和特征工程
- 第四期:sklearn中的降维算法PCA和SVD
- 第五期:sklearn中的逻辑回归
- 第六期:sklearn中的聚类算法K-Means
- 第七期:sklearn中的支持向量机SVM(上)
- 第八期:sklearn中的支持向量机SVM(下)
- 第九期:sklearn中的线性回归大家族
- 第十期:sklearn中的朴素贝叶斯
- 第十一期:sklearn与XGBoost
- 第十二期:sklearn中的神经网络
在过去两周已经学习了两个算法:
- 决策树(认识了sklearn)
- 随机森林(了解了机器学习中调参的基本思想)
建模之前的流程:数据预处理和特征工程
目录
概述
(一)数据挖掘的五大流程
(二)sklearn中的模块
数据预处理 Preprocessing & Impute
(一)数据无量纲化
preprocessing.MinMaxScaler(归一化Normalization)
preprocessing.StandardScaler(标准化)
总结与对比
(二)缺失值
impute.SimpleImputer
使用pandas和numpy进行填补
(三)处理分类型特征:编码与哑变量
preprocessing.LabelEncoder(对标签)
preprocessing.OrdinalEncoder(对特征)
preprocessing.OneHotEncoder(对标签;哑变量)
总结
(四)处理连续型特征:二值化(将特征值设置为0或1)与分段(即分箱)
preprocessing.Binarizer(对特征)
preprocessing.KBinsDiscretizer
概述
(一)数据挖掘的五大流程
- 获取数据
- 数据预处理:从数据中检测、纠正或删除损坏、不准确或不适用于模型的记录
可能面对的问题有:
数据类型不同(文字/数字);有的含时间序列(连续/间断);数据质量不行(有噪声/异常/缺失);数据出错(量纲不一/有重复);数据是偏态;数据量太大或太小
- 特征工程:将原始数据转换为更能代表预测模型的潜在问题的特征,可以通过挑选最相关的特征(特征选择)、提取特征(特征提取)以及创造特征(特征创造,经常以降维算法的方式实现)来实现
可能面对的问题有:特征之间有相关性、特征与标签无关、特征太多或太小
特征工程的目的:(1)降低计算成本(2)提升模型上限(至少保证模型在一个比较好的水平)
- 建模,测试模型并预测出结果
- 上线,验证模型效果
(二)sklearn中的模块
sklearn六大板块中有两块都是关于数据预处理和特征工程的:
- 模块preprocessing:几乎包含数据预处理的所有内容
- 模块Impute:填补缺失值
- 模块feature_selection:特征选择
- 模块decomposition:降维算法
数据预处理 Preprocessing & Impute
(一)数据无量纲化
- 定义:将不同规格的数据转换到同一规格,或不同分布的数据转换到某个特定分布
- 作用:
- 梯度和矩阵为核心的算法(LR、SVM、NN)中,无量纲化可以加快求解速度
- 距离类模型(K近邻、K-Means聚类)中,无量纲化可以提升模型精度,避免某一个取值范围特别大的特征对距离计算造成影响
特例:决策树和树的集成算法,不需要无量纲化,可以把任意数据都处理得很好
3. 分类:
- 可以线性,也可以非线性
- 线性的无量纲化包括:
- 中心化(Zero-centered或Mean-subtraction):让所有记录减去一个固定值,即让数据样本平移到某个位置
- 缩放(Scale):通过除以一个固定值,将数据固定在某个范围之中,取对数也算是一种缩放处理
preprocessing.MinMaxScaler(归一化Normalization)
数据归一化(Normalization/Min-Max Scaling):当数据按照最小值中心化后,再按极差(即最大值-最小值)缩放,数据移动了最小值个单位,并且会被收敛到 [0,1] 之间。归一化之后的数据服从正态分布
正则化是Regularization,不是数据预处理的一种手段
sklearn中使用preprocessing.MinMaxScaler来实现,有一个重要参数feature_range,控制希望把数据压缩到的范围,默认是[0,1]
from sklearn.preprocessing import MinMaxScaler
data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]] # 4行2列
#不太熟悉numpy的小伙伴,能够判断data的结构吗?
#如果换成表是什么样子?
import pandas as pd
pd.DataFrame(data)
#实现归一化(写法1)
scaler = MinMaxScaler() #实例化
scaler = scaler.fit(data) #fit,在这里本质是生成min(x)和max(x)
result = scaler.transform(data) #通过接口导出结果
result # 4行2列,值全都在0-1之间。原数据归一化后分布一致
# 写法2
result_ = scaler.fit_transform(data) #训练和导出结果一步达成
result_
scaler.inverse_transform(result) #将归一化后的结果逆转,返回归一化之前数据本来的样子
#使用MinMaxScaler的参数feature_range实现将数据归一化到[0,1]以外的范围中
data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
scaler = MinMaxScaler(feature_range=[5,10]) #依然实例化
result = scaler.fit_transform(data) #fit_transform一步导出结果
result
#当X中的特征数量非常多的时候,fit会报错并表示,数据量太大了我计算不了
#此时使用partial_fit作为训练接口
#scaler = scaler.partial_fit(data) 后面再transform即可
使用numpy实现归一化
import numpy as np X = np.array([[-1, 2], [-0.5, 6], [0, 10], [1, 18]]) # 数组 #归一化:对每一列计算 X-最小值 / 极差(最大值-最小值) X_nor = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0)) # X.min()返回所有数据中的最小值,X.min(axis=0)返回每一列的最小值 X_nor #逆转归一化 X_returned = X_nor * (X.max(axis=0) - X.min(axis=0)) + X.min(axis=0) X_returned
preprocessing.StandardScaler(标准化)
数据标准化(Standardization/Z-score Normalization):当数据x按均值μ中心化后,再按标准差σ缩放,数据就会服从均值为0、方差为1的正态分布(即标准正态分布)
from sklearn.preprocessing import StandardScaler
data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
scaler = StandardScaler() #实例化
scaler.fit(data) #fit,本质是生成均值和方差
scaler.mean_ #查看均值的属性mean_ array([-0.125, 9. ])
scaler.var_ #查看方差的属性var_ array([ 0.546875, 35. ])
x_std = scaler.transform(data) #通过接口导出结果
x_std # 两列数据虽然大小不同,但分布一样,所以归一化和标准化后结果一样
# 写法2
scaler.fit_transform(data) #使用fit_transform(data)一步达成结果
x_std.mean() #导出的结果是一个数组,用mean()查看均值 0.0
x_std.std() #用std()查看方差 1.0
scaler.inverse_transform(x_std) #使用inverse_transform逆转标准化
总结与对比
1. 总结
对于StandardScaler和MinMaxScaler来说,NaN会被当做缺失值,在fit时忽略,在transform时保持NaN的状态显示
在fit接口中,去量纲化依然只允许导入至少二维数组,一维数组导入会报错,需要用 reshape(-1,1) 改维度
2. 对比
- 大多数机器学习算法(PCA、聚类、LR、SVM、NN)会选择StandardScaler来进行特征缩放,因为MinMaxScaler对异常值非常敏感
- MinMaxScaler在不涉及距离度量、梯度、协方差计算,以及数据需要被压缩到特定区间时使用广泛。比如数字图像处理中量化像素强度时,都会使用MinMaxScaler将数据压缩于 [0,1]
- 先试试StandardScaler,效果不好换MinMaxScaler
3. 其他
除了StandardScaler和MinMaxScaler之外,sklearn中也提供了各种其他缩放处理,比如:
- 在希望压缩数据但不影响数据的稀疏性(不影响矩阵中取值为0的个数,故应该只压缩,不中心化)时,使用MaxAbsScaler
- 在异常值多、噪声非常大时,可能会用分位数来无量纲化,使用RobustScaler
中心化只需要pandas广播一下,减去某个数即可,因此 sklearn不提供任何中心化的功能,只提供压缩的功能
(二)缺失值
一种情况:重要的字段缺失值很多,但又不能舍弃字段 —— 处理缺失值
使用从泰坦尼克号提取出来的数据,有三个特征(一个数值型,两个字符型)以及标签(字符型)
import pandas as pd
data = pd.read_csv(r".\Narrativedata.csv"
,index_col=0
) #index_col=0将第0列作为索引,不写则认为第0列为特征
data.head()
data.info() # 观察数据
impute.SimpleImputer
这个类是专门用来填补缺失值的,包括四个重要参数:
填补Age列:
#填补年龄
#data.loc[:,"Age"]取出所有行和Age列,是Series(Pandas中的对象,由一列索引和一列数据组成)
Age = data.loc[:,"Age"].values.reshape(-1,1) #sklearn当中特征矩阵必须是二维,所以使用reshape(-1,1)来数据升维
Age[:20]
from sklearn.impute import SimpleImputer
imp_mean = SimpleImputer() #实例化,默认均值填补
imp_median = SimpleImputer(strategy="median") #用中位数填补
imp_0 = SimpleImputer(strategy="constant",fill_value=0) #用0填补
imp_mean = imp_mean.fit_transform(Age) #fit_transform一步完成调取结果
imp_median = imp_median.fit_transform(Age)
imp_0 = imp_0.fit_transform(Age)
imp_mean[:20] # 均值为29.69911765
imp_median[:20] # 中位数为28.
imp_0[:20]
#通常来说Age采用均值填补,但当均值和中位数差距不大时,采用中位数也可以
#在这里我们使用中位数填补Age(因为中位数是个整数)
data.loc[:,"Age"] = imp_median
data.info()
填补Embarked列:
实际中像Embarked这种只缺两条数据的特征,会删掉,不会填充;像Age缺失比较多才会填充
#使用众数填补Embarked(字符型列)
Embarked = data.loc[:,"Embarked"].values.reshape(-1,1)
imp_mode = SimpleImputer(strategy = "most_frequent")
data.loc[:,"Embarked"] = imp_mode.fit_transform(Embarked)
data.info()
使用pandas和numpy进行填补
import pandas as pd
data_ = pd.read_csv(r".\Narrativedata.csv"
,index_col=0
) #index_col=0将第0列作为索引,不写则认为第0列为特征
data_.head()
data_.loc[:,"Age"] = data_.loc[:,"Age"].fillna(data_.loc[:,"Age"].median())
#.fillna 在DataFrame里面直接进行填补,里面写希望用什么东西来填补Age这一列的缺失值
data_.dropna(axis=0,inplace=True) # 另一种写法:data_ = data_.dropna(axis=0,inplace=False)
#.dropna(axis=0)删除所有有缺失值的行,.dropna(axis=1)删除所有有缺失值的列
#参数inplace,为True表示在原数据集上进行修改,为False表示生成一个复制对象,不修改原数据,默认False
data_.info()
(三)处理分类型特征:编码与哑变量
机器学习中大多数算法(LR、SVM、K近邻算法等)都只能处理数值型数据,不能处理文字
在sklearn中,除了专用来处理文字的算法,其他算法在fit的时候全部要求输入数组或矩阵,也不能导入文字型数据
手写决策树(原理是分箱分枝)和朴素贝叶斯(原理是算概率)可以处理文字,但sklearn规定必须导入数值型
在现实中,许多标签和特征在数据收集完毕时都不是以数字来表现的。在这种情况下,为了让数据适应算法和库,必须将数据进行编码,将文字型数据转换为数值型
标签允许一维,而特征矩阵不允许一维,一定要用reshape(-1,1)转换
preprocessing.LabelEncoder(对标签)
标签专用,将分类转换为分类数值
from sklearn.preprocessing import LabelEncoder
y = data.iloc[:,-1] #要输入的是标签,不是特征矩阵,所以允许一维
le = LabelEncoder() #实例化
le = le.fit(y) #导入数据
label = le.transform(y) #transform接口调取结果
le.classes_ #属性.classes_查看标签中究竟有多少类别
label #查看获取的结果label
# 写法2
LabelEncoder().fit_transform(y) #也可以直接fit_transform一步到位
le.inverse_transform(label) #使用inverse_transform可以逆转
data.iloc[:,-1] = label #让标签等于我们运行出来的结果
data.head()
#如果不需要教学展示的话我会这么写:
from sklearn.preprocessing import LabelEncoder
# LabelEncoder()实例化
# data.iloc[:,-1]为最后一列(标签)
data.iloc[:,-1] = LabelEncoder().fit_transform(data.iloc[:,-1])
preprocessing.OrdinalEncoder(对特征)
特征专用(不能导入一维数组),将分类特征转换为分类数值
from sklearn.preprocessing import OrdinalEncoder
data_ = data.copy()
data_.head()
#接口categories_对应LabelEncoder的接口classes_,一模一样的功能
OrdinalEncoder().fit(data_.iloc[:,1:-1]).categories_
data_.iloc[:,1:-1] = OrdinalEncoder().fit_transform(data_.iloc[:,1:-1])
data_.head()
在舱门Embarked这一列中,使用 [0,1,2] 代表三个不同的舱门,这种转换不正确
[0,1,2] 这三个数字在算法看来,是连续且可计算的,相互不等,有大小,可以相加相乘。这是说,把分类转换成数字的时候,忽略了数字中自带的数学性质,所以给算法传达了一些不准确的信息,这会影响建模
preprocessing.OneHotEncoder(哑变量)
独热编码,创建哑变量
三种不同性质的分类数据:
(1)名义变量:如舱门(S,C,Q),三种取值是相互独立的,彼此之间完全没有联系 —— 只能用哑变量处理
(2)有序变量:如学历(小学,初中,高中),三种取值不是完全独立的,学历有高低,但取值之间却不是可以计算的 —— OrdinalEncoder可以处理
(3)有距变量:如体重(>45kg,>90kg,>135kg),各个取值之间有联系,且可以互相计算,分类之间可以通过数学计算互相转换
数据类型及常用的统计量:
注意:
- 这里“以摄氏度或华氏度为量纲的温度”是有距变量,因为温度为2°时感受到的热量不等于温度为1°时感受到的热量的2倍;
- 而“以开尔文为量纲的温度”是比率变量,可以乘除,因为1开尔文的热量乘以2就是2开尔文的热量
在泰坦尼克号数据中,性别和舱门都是名义变量,需要使用独热编码,将两个特征都转换为哑变量
from sklearn.preprocessing import OneHotEncoder
X = data.iloc[:,1:-1]
enc = OneHotEncoder(categories='auto').fit(X) # categories='auto'自动计算每个特征有多少类(该参数对于sklearn0.19版本需要传入一个列表,表示每个特征有多少类)
# enc.transform(X)是一个稀疏矩阵对象,即0和1组成的矩阵
result = enc.transform(X).toarray() # .toarray()转换成数组
result # 2个特征 ——> 5列,Sex有2列,Embarked有3列
# 写法2
# 依然可以直接一步到位,但为了给大家展示模型属性,所以还是写成了三步
OneHotEncoder(categories='auto').fit_transform(X).toarray()
#依然可以还原
pd.DataFrame(enc.inverse_transform(result)) # enc.inverse_transform(result)为array
enc.get_feature_names() #返回每一个经过哑变量后生成稀疏矩阵列的名字
#pd.concat()合并两个DataFrame
#axis=1,表示跨行进行合并,也就是将两表左右相连,如果是axis=0,就是将量表上下相连
newdata = pd.concat([data,pd.DataFrame(result)],axis=1)
newdata.head()
# 删除列/合并列/对列求均值:axis=1
newdata.drop(["Sex","Embarked"],axis=1,inplace=True)
newdata.columns = ["Age","Survived","Female","Male","Embarked_C","Embarked_Q","Embarked_S"]
newdata.head()
注:标签也可以做哑变量,使用类 sklearn.preprocessing.LabelBinarizer
许多算法都可以处理多标签问题(如决策树),但这种做法在现实中不常见
总结
(四)处理连续型特征:二值化(将特征值设置为0或1)与分段(即分箱)
preprocessing.Binarizer(对特征)
根据阈值将数据二值化,用于处理连续型变量,大于阈值的值映射为1,小于或等于阈值的值映射为0。默认阈值为0时,特征中所有正值都映射到1
用来处理特征的类里导入的数据不接受一维数组,必须用reshape(-1,1)升维
from sklearn.preprocessing import Binarizer
# data_2.iloc[:,0]为Series(一列索引+一列值),用.values取出值
X = data_2.iloc[:,0].values.reshape(-1,1) #类为特征专用,所以不能使用一维数组
transformer = Binarizer(threshold=30).fit_transform(X) # >30为1,≤30为0
data_2.iloc[:,0] = transformer
data_2.head()
也可以对标签做二值化处理,如泰坦尼克号原数据标签有3类:死亡0/未知1/存活2,可以把死亡和未知都归为死亡,转化为二分类问题,此时threshold=1
二值化是对文本计数数据的常见操作,分析人员可以决定仅考虑某种现象的存在与否;还可以用作考虑布尔随机变量的估计器的预处理步骤,如使用贝叶斯设置中的伯努利分布建模
preprocessing.KBinsDiscretizer
将连续型变量划分为分类变量,能够将连续型变量排序后,按顺序分箱后编码
from sklearn.preprocessing import KBinsDiscretizer
X = data.iloc[:,0].values.reshape(-1,1)
est = KBinsDiscretizer(n_bins=3, encode='ordinal', strategy='uniform')
est.fit_transform(X) # 二维
#查看转换后分的箱:变成了一列中的三箱
#set()集合,去掉重复值,可以用来查看有多少种取值,即有多少个箱
set(est.fit_transform(X).ravel()) #.ravel()降维
est = KBinsDiscretizer(n_bins=3, encode='onehot', strategy='uniform')
#查看转换后分的箱:变成了哑变量
est.fit_transform(X).toarray() # 3列0和1组成的稀疏矩阵
Shift + Tab 查看类的详细参数