zoukankan      html  css  js  c++  java
  • 【机器学习】scikit-learn中的数据预处理小结(归一化、缺失值填充、离散特征编码、连续值分箱)

    一.概述

    1. 数据预处理

    数据预处理是从数据中检测,修改或删除不准确或不适用于模型的记录的过程
    可能面对的问题有:数据类型不同,比如有的是文字,有的是数字,有的含时间序列,有的连续,有的间断。 也可能,数据的质量不行,有噪声,有异常,有缺失,数据出错,量纲不一,有重复,数据是偏态,数据量太大或太小 。
    数据预处理的目的:让数据适应模型,匹配模型的需求 。

    2.sklearn中的数据预处理

    sklearn中包含众多数据预处理相关的模块,包括:

    • 模块preprocessing:几乎包含数据预处理的所有内容
    • 模块Impute:填补缺失值专用

    二 . 数据预处理

    1.归一化

    在机器学习算法实践中,我们往往有着将不同规格的数据转换到同一规格,或不同分布的数据转换到某个特定分布 的需求,这种需求统称为将数据“无量纲化”。
    譬如梯度和矩阵为核心的算法中,譬如逻辑回归,支持向量机,神经 网络,无量纲化可以加快求解速度;而在距离类模型,譬如K近邻,K-Means聚类中,无量纲化可以帮我们提升模型精度,避免某一个取值范围特别大的特征对距离计算造成影响。

    (1)preprocessing.MinMaxScaler

    当数据(x)按照最小值中心化后,再按极差(最大值 - 最小值)缩放,数据移动了最小值个单位,并且会被收敛到 [0,1]之间,而这个过程,就叫做数据归一化(Normalization,又称Min-Max Scaling)。
    归一化之后的数据服从正态分 布,公式如下:

    [x^{*} = frac{x-min(x)}{max(x)-min(x)} ]

    在sklearn当中,我们使用preprocessing.MinMaxScaler来实现这个功能。

    • MinMaxScaler有一个重要参数, feature_range,控制我们希望把数据压缩到的范围,默认是[0,1].
    from sklearn.preprocessing import MinMaxScaler
     
    data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
    #实现归一化 
    scaler = MinMaxScaler(feature_range=[5,10])         #实例化,feature_range默认是[0,1]
    # scaler = scaler.fit(data)                         #fit,在这里本质是生成min(x)和max(x) 
    # result = scaler.transform(data)                   #通过接口导出结果 result
    result_ = scaler.fit_transform(data)                #训练和导出结果一步达成,可以替代上两行数据
    result_
    
    array([[ 5.  ,  5.  ],
           [ 6.25,  6.25],
           [ 7.5 ,  7.5 ],
           [10.  , 10.  ]])
    

    (2) preprocessing.StandardScale

    当数据(x)按均值(μ)中心化后,再按标准差(σ)缩放,数据就会服从为均值为0,方差为1的正态分布(即标准正态分 布),而这个过程,就叫做数据标准化(Standardization,又称Z-score normalization),公式如下:

    [x^{*} = frac{x-μ}{σ} ]

    from sklearn.preprocessing import StandardScaler 
    data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
     
    scaler = StandardScaler()                           #实例化 
    # scaler = scaler.fit(data)                                    #fit,本质是生成均值和方差
    # result = scaler.transform(data)                      #通过接口导出结果
     
    result_ = scaler.fit_transform(data)                #使用fit_transform(data)一步达成结果
    result_
    
    array([[-1.18321596, -1.18321596],
           [-0.50709255, -0.50709255],
           [ 0.16903085,  0.16903085],
           [ 1.52127766,  1.52127766]])
    

    (3) StandardScaler和MinMaxScaler选哪个?

    看情况。大多数机器学习算法中,会选择StandardScaler来进行特征缩放,因为MinMaxScaler对异常值非常敏 感。在PCA,聚类,逻辑回归,支持向量机,神经网络这些算法中,StandardScaler往往是最好的选择。
    MinMaxScaler在不涉及距离度量、梯度、协方差计算以及数据需要被压缩到特定区间时使用广泛,比如数字图像 处理中量化像素强度时,都会使用MinMaxScaler将数据压缩于[0,1]区间之中。

    2.缺失值

    数据预处理中非常重要的一项就是处理缺失值。

    • 对于连续值,常常使用均值或者中位数去填充缺失值;
    • 对于离散值,常常使用众数填充,或者把缺失值当作一个单独的类别。
    • 对于缺失率超过一定阈值的特征,可以考虑直接舍弃。
    import pandas as pd 
    data = pd.read_csv(r"./../Narrativedata.csv",index_col=0)
    data.info()
    
    <class 'pandas.core.frame.DataFrame'>
    Int64Index: 891 entries, 0 to 890
    Data columns (total 4 columns):
    Age         714 non-null float64
    Sex         891 non-null object
    Embarked    889 non-null object
    Survived    891 non-null object
    dtypes: float64(1), object(3)
    memory usage: 34.8+ KB
    

    以Titanic数据为例,可以看到其中Age和Embarked两列有缺失值,且分别为连续值和离散值。

    (1) impute.SimpleImputer

    from sklearn.impute import SimpleImputer 
    # 对连续值Age进行填充    
    Age = data.loc[:,"Age"].values.reshape(-1,1)            #sklearn当中特征矩阵必须是二维 
    # 实例化
    age_median = SimpleImputer(strategy="median")           #用中位数填补 (默认均值填补) 
    age_0 = SimpleImputer(strategy="constant",fill_value=0) #使用具体值填补,用fill_value指定
    # 转化
    age_median = age_median.fit_transform(Age)    #fit_transform一步完成调取结果 
    age_0 = age_0.fit_transform(Age)
    #把填补后的列赋值回原来的矩阵里
    data.loc[:,"Age"] = age_median
    data.info()
    
    <class 'pandas.core.frame.DataFrame'>
    Int64Index: 891 entries, 0 to 890
    Data columns (total 4 columns):
    Age         891 non-null float64
    Sex         891 non-null object
    Embarked    889 non-null object
    Survived    891 non-null object
    dtypes: float64(1), object(3)
    memory usage: 34.8+ KB
    
    # 对离散值Embarked进行填充 
    Embarked = data.loc[:,"Embarked"].values.reshape(-1,1) 
    Embarked_most = SimpleImputer(strategy = "most_frequent")   #使用众数填补
    data.loc[:,"Embarked"] = Embarked_most.fit_transform(Embarked)
    data.info()
    
    <class 'pandas.core.frame.DataFrame'>
    Int64Index: 891 entries, 0 to 890
    Data columns (total 4 columns):
    Age         891 non-null float64
    Sex         891 non-null object
    Embarked    891 non-null object
    Survived    891 non-null object
    dtypes: float64(1), object(3)
    memory usage: 34.8+ KB
    

    (2) 用Pandas和Numpy进行填补

    • pd.fillna() 使用特定的值填充
    • pd.dropna(axis=0)删除所有有缺失值的行/列
    import pandas as pd 
    data1 = pd.read_csv(r"./../Narrativedata.csv",index_col=0)
     
    data1.loc[:,"Age"] = data1.loc[:,"Age"].fillna(data1.loc[:,"Age"].median()) #.fillna 在data1Frame里面直接进行填补
     
    data1.dropna(axis=0,inplace=True) #.dropna(axis=0)删除所有有缺失值的行,.dropna(axis=1)删除所有有缺失值的列
    data1.info()
    
    <class 'pandas.core.frame.DataFrame'>
    Int64Index: 889 entries, 0 to 890
    Data columns (total 4 columns):
    Age         889 non-null float64
    Sex         889 non-null object
    Embarked    889 non-null object
    Survived    889 non-null object
    dtypes: float64(1), object(3)
    memory usage: 34.7+ KB
    

    3.处理离散特征:编码和哑变量

    在sklearn当中,除了专用来处理文字的算法,其他算法在fit的时候全部要求输入数组或矩阵,也不能够导 入文字型数据。
    为了让数据适 应算法和库,我们必须将数据进行编码,即是说,将文字型数据转换为数值型。

    (1) preprocessing.LabelEncoder:标签专用,能够将分类转换为分类数值

    from sklearn.preprocessing import LabelEncoder 
    y = data.iloc[:,-1]                         #要输入的是标签,不是特征矩阵,所以允许一维
    print(y[:10])
    le = LabelEncoder()                         #实例化 
    label = le.fit_transform(y)                 # 匹配加转化一步到位
    # le = le.fit(y)                            
    # label = le.transform(y)                  
    print(label[:10])
    print(le.classes_)                           # 查看有多少类
    data.iloc[:,-1] =label
    
    0     No
    1    Yes
    2    Yes
    3    Yes
    4     No
    5     No
    6     No
    7     No
    8    Yes
    9    Yes
    Name: Survived, dtype: object
    [0 2 2 2 0 0 0 0 2 2]
    ['No' 'Unknown' 'Yes']
    

    (2)preprocessing.OrdinalEncoder:特征专用,能够将分类特征转换为分类数 (一般用于有序变量)

    data_ =data.copy()
    # 观察特征的原样式
    data_.iloc[:,1:-1][:10]
    
    Sex Embarked
    0 male S
    1 female C
    2 female S
    3 female S
    4 male S
    5 male Q
    6 male S
    7 male S
    8 female S
    9 female C
    from sklearn.preprocessing import OrdinalEncoder
    # 类似的,把实例化,匹配,转化和赋值写在一条语句上
    data_.iloc[:,1:-1] = OrdinalEncoder().fit_transform(data_.iloc[:,1:-1])
    #接口categories_对应LabelEncoder的接口classes_,一模一样的功能 
    print(OrdinalEncoder().fit(data_.iloc[:,1:-1]).categories_)
    #查看数据,
    data_.head() 
    
    [array([0., 1.]), array([0., 1., 2.])]
    
    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
    data_.info() 
    
    <class 'pandas.core.frame.DataFrame'>
    Int64Index: 891 entries, 0 to 890
    Data columns (total 4 columns):
    Age         891 non-null float64
    Sex         891 non-null float64
    Embarked    891 non-null float64
    Survived    891 non-null int32
    dtypes: float64(3), int32(1)
    memory usage: 31.3 KB
    

    由以上的数据情况可以看出,Age和Embarked的缺失值已被填充,特征Sex和Embarked等分类特征已转化为分类数值,标签Survived也已转化为分类数值。

    (3) preprocessing.OneHotEncoder:独热编码,创建哑变量

    由上面的处理可以看到OrdinalEncoder会把类别变量变成数值,比如转化为[0,1,2],这三个数字在算法看来,是连续且可以计算的,可能有大小并且有着可以相加相乘的联系。但是有的类别变量各类别是独立的,如果转化成数值会给算法传达了一些不准确的信息,而这会影响我们的建模。

    因此,类别OrdinalEncoder可以用来处理有序变量,但对于名义变量,我们只有使用独热编码,以哑变量的方式来处理,才能够尽量 向算法传达最准确的信息。

    # 同样的,观察下原数据样式
    data.iloc[:,1:-1][:10]
    
    Sex Embarked
    0 male S
    1 female C
    2 female S
    3 female S
    4 male S
    5 male Q
    6 male S
    7 male S
    8 female S
    9 female C
    from sklearn.preprocessing import OneHotEncoder 
    X = data.iloc[:,1:-1]
     
    #可以直接一步到位
    result = OneHotEncoder(categories='auto').fit_transform(X).toarray()
    # # 也可以分开成两步计算
    # enc = OneHotEncoder(categories='auto').fit(X) 
    # result = enc.transform(X).toarray() 
    # 把独热编码拼接到原数据上
    newdata = pd.concat([data,pd.DataFrame(result)],axis=1)
    newdata.drop(["Sex","Embarked"],axis=1,inplace=True) 
    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 0 0.0 1.0 0.0 0.0 1.0
    1 38.0 2 1.0 0.0 1.0 0.0 0.0
    2 26.0 2 1.0 0.0 0.0 0.0 1.0
    3 35.0 2 1.0 0.0 0.0 0.0 1.0
    4 35.0 0 0.0 1.0 0.0 0.0 1.0

    (4) 使用pandas的.get_dummies函数 实现独热编码

    dummies_Sex = pd.get_dummies(data.Sex,prefix='Sex')                    #ptefix 是前缀,因子化之后的字段名为 前缀_类名
    dummies_Embarked = pd.get_dummies(data.Embarked,prefix='Embarked')    
    newdata = pd.concat([data, dummies_Sex, dummies_Embarked], axis=1)         #将哑编码的内容拼接到data后
    newdata.drop([ 'Sex', 'Embarked'], axis=1, inplace=True)                # 把编码前的字段删除
    newdata.head() 
    
    Age Survived Sex_female Sex_male Embarked_C Embarked_Q Embarked_S
    0 22.0 0 0 1 0 0 1
    1 38.0 2 1 0 1 0 0
    2 26.0 2 1 0 0 0 1
    3 35.0 2 1 0 0 0 1
    4 35.0 0 0 1 0 0 1

    4.处理连续特征:二值化和分段

    (1) sklearn.preprocessing.Binarize 用于处理连续变量的二值化

    根据阈值将数据二值化(将特征值设置为0或1),用于处理连续型变量。大于阈值的值映射为1,而小于或等于阈值的值映射为0。默认阈值为0。

    # 将年龄二值化
    data_2 = data.copy()
    from sklearn.preprocessing import Binarizer 
    X = data_2.iloc[:,0].values.reshape(-1,1)               #类为特征专用,所以不能使用一维数组 
    Age = Binarizer(threshold=30).fit_transform(X)          # 以30为阈值,>30为1,<30为0
    Age[:10]
    
    array([[0.],
           [1.],
           [0.],
           [1.],
           [1.],
           [0.],
           [1.],
           [0.],
           [0.],
           [0.]])
    

    (2) sklearn.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)[:5]
    
    array([[0.],
           [1.],
           [0.],
           [1.],
           [1.]])
    
    est = KBinsDiscretizer(n_bins=3, encode='onehot', strategy='uniform') #查看转换后分的箱:变成了哑变量 
    est.fit_transform(X).toarray()
    
    array([[1., 0., 0.],
           [0., 1., 0.],
           [1., 0., 0.],
           ...,
           [0., 1., 0.],
           [1., 0., 0.],
           [0., 1., 0.]])
  • 相关阅读:
    抽奖软件分享
    常用网页元素命名规范参考
    基于.NET平台常用的框架整理
    【Jquery Mobile教程】【问题】- 在页面切换时会闪烁
    SSO单点登录三种情况的实现方式详解
    outlook 2013撤消已经发送的邮件
    【TFS 2010配置】总是提示:Error [ System Checks ] TF255466
    iOS9.3描述文件怎么安装
    精进-12周:成为很历害的人 第一周:Axure学习日志
    精进-12周:成为很历害的人 第一周:XMIND学习日志
  • 原文地址:https://www.cnblogs.com/laiyaling/p/14087014.html
Copyright © 2011-2022 走看看