课程地址:《菜菜的机器学习sklearn课堂》_哔哩哔哩_bilibili
在过去两周已经学习了两个算法:
建模之前的流程:数据预处理和特征工程
目录
概述
(一)数据挖掘的五大流程
(二)sklearn中的模块
数据预处理 Preprocessing & Impute
(一)数据无量纲化
preprocessing.MinMaxScaler(归一化Normalization)
preprocessing.StandardScaler(标准化)
总结与对比
(二)缺失值
impute.SimpleImputer
使用pandas和numpy进行填补
(三)处理分类型特征:编码与哑变量
preprocessing.LabelEncoder(对标签)
preprocessing.OrdinalEncoder(对特征)
preprocessing.OneHotEncoder(对标签;哑变量)
总结
(四)处理连续型特征:二值化(将特征值设置为0或1)与分段(即分箱)
preprocessing.Binarizer(对特征)
preprocessing.KBinsDiscretizer
sklearn六大板块中有两块都是关于数据预处理和特征工程的:
特例:决策树和树的集成算法,不需要无量纲化,可以把任意数据都处理得很好
3. 分类:
数据归一化(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
数据标准化(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. 对比
3. 其他
除了StandardScaler和MinMaxScaler之外,sklearn中也提供了各种其他缩放处理,比如:
中心化只需要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() # 观察数据
这个类是专门用来填补缺失值的,包括四个重要参数:
填补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()
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)转换
标签专用,将分类转换为分类数值
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])
特征专用(不能导入一维数组),将分类特征转换为分类数值
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] 这三个数字在算法看来,是连续且可计算的,相互不等,有大小,可以相加相乘。这是说,把分类转换成数字的时候,忽略了数字中自带的数学性质,所以给算法传达了一些不准确的信息,这会影响建模
独热编码,创建哑变量
三种不同性质的分类数据:
(1)名义变量:如舱门(S,C,Q),三种取值是相互独立的,彼此之间完全没有联系 —— 只能用哑变量处理
(2)有序变量:如学历(小学,初中,高中),三种取值不是完全独立的,学历有高低,但取值之间却不是可以计算的 —— OrdinalEncoder可以处理
(3)有距变量:如体重(>45kg,>90kg,>135kg),各个取值之间有联系,且可以互相计算,分类之间可以通过数学计算互相转换
数据类型及常用的统计量:
注意:
在泰坦尼克号数据中,性别和舱门都是名义变量,需要使用独热编码,将两个特征都转换为哑变量
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
许多算法都可以处理多标签问题(如决策树),但这种做法在现实中不常见
根据阈值将数据二值化,用于处理连续型变量,大于阈值的值映射为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
二值化是对文本计数数据的常见操作,分析人员可以决定仅考虑某种现象的存在与否;还可以用作考虑布尔随机变量的估计器的预处理步骤,如使用贝叶斯设置中的伯努利分布建模
将连续型变量划分为分类变量,能够将连续型变量排序后,按顺序分箱后编码
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 查看类的详细参数