【3 - 数据预处理】菜菜sklearn机器学习

课程地址:《菜菜的机器学习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. 数据预处理:从数据中检测、纠正或删除损坏、不准确或不适用于模型的记录

    可能面对的问题有:
    数据类型不同(文字/数字);有的含时间序列(连续/间断);数据质量不行(有噪声/异常/缺失);数据出错(量纲不一/有重复);数据是偏态;数据量太大或太小
     
  3. 特征工程:将原始数据转换为更能代表预测模型的潜在问题的特征,可以通过挑选最相关的特征(特征选择)、提取特征(特征提取)以及创造特征(特征创造,经常以降维算法的方式实现)来实现

    可能面对的问题有:特征之间有相关性、特征与标签无关、特征太多或太小
    特征工程的目的:(1)降低计算成本(2)提升模型上限(至少保证模型在一个比较好的水平)
     
  4. 建模,测试模型并预测出结果
  5. 上线,验证模型效果

(二)sklearn中的模块

sklearn六大板块中有两块都是关于数据预处理和特征工程的:

  • 模块preprocessing:几乎包含数据预处理的所有内容
  • 模块Impute:填补缺失值
  • 模块feature_selection:特征选择
  • 模块decomposition:降维算法

数据预处理 Preprocessing & Impute

(一)数据无量纲化

  1. 定义:将不同规格的数据转换到同一规格,或不同分布的数据转换到某个特定分布
  2. 作用:
  • 梯度和矩阵为核心的算法(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 查看类的详细参数
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cheeryang_ego

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值