数据预处理与特征工程—12.常见的数据预处理与特征工程手段总结

引言

  数据预处理与特征工程包括Data PreProcessing(数据预处理)、Feature Extraction(特征提取)、Feature Selection(特征选择)和Feature construction(特征构造)等步骤

1.数据预处理

  数据预处理又包括数据清洗与特征预处理两步

1.1 数据清洗

  数据清洗主要是删除原始数据集中的无关数据、重复数据,平滑噪声数据,筛选掉与挖掘主题无关的数据,处理缺失值、异常值等

1.1.1 异常值处理

  异常值是否需要处理需要视具体情况而定,因为有些异常值可能蕴含着有用的信息。

  1. 简单统计量分析
    在进行异常值分析时,可以先对变量做一个描述性统计,进而查看哪些数据是不合理的。最常用的统计量是最大值和最小值,用来判断这个变量的取值是否超出了合理范围。如客户年龄的最大值为199岁,则判断该变量的取值存在异常。

  2. 通过箱线图分析删除异常值;
    箱型图提供了识别异常值的一个标准:异常值通常被定义为小于 Q L − 1.5 I Q R Q_L-1.5IQR QL1.5IQR或大于 Q U + 1.5 I Q R Q_U+1.5IQR QU+1.5IQR的值。 Q L Q_L QL称为下四分位数,表示全部观察值中有四分之一的数据取值比它小; Q U Q_U QU称为上四分位数,表示全部观察值中有四分之一的数据取值比它大;IQR称为四分位数间距,是上四分位数 Q U Q_U QU与下四分位数 Q L Q_L QL之差,其间包含了全部观察值的一半。这里的1.5可以根据问题的不同进行改变。

    箱型图依据实际数据绘制,对数据没有任何限制性要求,如服从某种特定的分布形式,它只是真实直观地表现数据分布的本来面貌;另一方面,箱型图判断异常值的标准以四分位数和四分位距为基础,四分位数具有一定的鲁棒性:多达25%的数据可以变得任意远而不会严重扰动四分位数,所以异常值不能对这个标准施加影响。由此可见,箱型图识别异常值的结果比较客观,在识别异常值方面有一定的优越性

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import seaborn as sns
    
    
    def box_plot_outliers(data_ser, box_scale):
        """
        利用箱线图去除异常值
        :param data_ser: 接收 pandas.Series 数据格式
        :param box_scale: 箱线图尺度,
        :return:
        """
        iqr = box_scale*(data_ser.quantile(0.75) - data_ser.quantile(0.25))
        # Q_L - 1.5IQR为下界
        val_low = data_ser.quantile(0.25) - iqr
        # Q_U + 1.5IQR为上界
        val_up = data_ser.quantile(0.75) + iqr
        rule_low = (data_ser < val_low)
        rule_up = (data_ser > val_up)
        return (rule_low, rule_up), (val_low, val_up)
    
    def outliers_proc(data, col_name, scale=1.5):
        """
        用于清洗异常值,默认用 box_plot(scale=1.5)进行清洗
        :param data: 接收 pandas 数据格式
        :param col_name: pandas 列名
        :param scale: 尺度
        :return:
        """
        # 复制数据
        data_n = data.copy()
        # 针对哪一个特征清洗异常值
        data_series = data_n[col_name]
        # 返回异常值索引(bool格式)与上下边界
        rule, value = box_plot_outliers(data_series, box_scale=scale)
        # 得到异常值得索引
        # |会先转化成二进制,然后相同位数的数字有1则为1,否则为0
        index = np.arange(data_series.shape[0])[rule[0] | rule[1]]
        print("Delete number is: {}".format(len(index)))
    
        # 删除异常值
        data_n = data_n.drop(index)
        # 重置索引
        data_n.reset_index(drop=True, inplace=True)
        print("Now column number is: {}".format(data_n.shape[0]))
        # 统计低于下界的异常值
        index_low = np.arange(data_series.shape[0])[rule[0]]
        outliers = data_series.iloc[index_low]
        print("Description of data less than the lower bound is:")
        print(pd.Series(outliers).describe())
    
        # 统计高于上界的异常值
        index_up = np.arange(data_series.shape[0])[rule[1]]
        outliers = data_series.iloc[index_up]
        print("Description of data larger than the upper bound is:")
        print(pd.Series(outliers).describe())
    
        # 查看删除异常值前后图形的区别
        fig, ax = plt.subplots(1, 2, figsize=(10, 7))
        sns.boxplot(y=data[col_name], data=data, palette="Set1", ax=ax[0])
        sns.boxplot(y=data_n[col_name], data=data_n, palette="Set1", ax=ax[1])
        return data_n
    
  3. 通过 3 σ 3σ 3σ原则删除异常值

    如果数据服从正态分布,在 3 σ 3σ 3σ原则下,异常值被定义为一组测定值中与平均值的偏差超过3倍标准差的值。在正态分布的假设下,距离平均值 3 σ 3σ 3σ之外的值出现的概率为P(x-u |> 3 σ 3σ 3σ)≤0.003,属于极个别的小概率事件。
    如果数据不服从正态分布,也可以用远离平均值的标准差倍数来描述。

  4. 长尾截断;

    长尾截断主要也是分布不符合正态分布,而是类似于“长尾”。例如房价中,低价占大部分,豪宅属于小部分。应对这种数据分布,一般可以通过神奇的log化处理转化类近似正态分布或者使用Box-Cox转换将数据转换为正态。数据预处理—5.box-cox变换及python实现

  5. 将异常值视为缺失值,利用缺失处理方法进行处理

1.1.2 缺失值处理

  缺失值处理的方法可分为3种:删除记录、数据插补和不处理

  1. 不处理(针对类似 XGBoost 等树模型);
  2. 删除(缺失数据太多);
  3. 插值补全,包括均值/中位数/众数/使用固定值/最近邻插补/回归方法/插值法(拉格朗日插值法、牛顿插值法)等;
    前面几种方面使用pandas中的fillna函数可以轻松实现
    插值法数据预处理—7.数据插补之拉格朗日插值法、牛顿差值法及python实现
    回归方法:对带有缺失值的变量,根据已有数据和其有关的其他变量(因变量)的数据建立拟合模型来预测缺失的属性值。6.4 随机森林实战这里面使用了随机森林来预测年龄中的缺失值作为填充
  4. 分箱,缺失值一个箱;
    见后面

1.2 特征预处理

1.2.1 数值型特征无量纲化

  数值型特征无量纲化是为了消除样本不同属性具有不同量级(大小)时的影响,不仅提高精度,而且提高迭代精度

  1. 标准化(转换为标准正态分布);

    from sklearn.preprocessing import MinMaxScaler,StandardScaler
    # 标准化
    scaler = StandardScaler()
    result = scaler.fit_transform(data)  # 将data标准化
    
    scaler.inverse_transform(result)  # 将标准化结果逆转
    

    优点:
    标准化最大的优点就是简单,容易计算,Z-Score能够应用于数值型的数据,并且不受数据量级(数据多少)的影响,因为它本身的作用就是消除量级给分析带来的不便。
    缺点:

    • 估算Z-Score需要总体的平均值与方差,但是这一值在真实的分析与挖掘中很难得到,大多数情况下是用样本的均值与标准差替代。

    • Z-Score对于数据的分布有一定的要求,正态分布是最有利于Z-Score计算的。

    • Z-Score消除了数据具有的实际意义,属性A的Z-Score与属性B的Z-Score与他们各自的分数不再有关系,因此Z-Score的结果只能用于比较数据间的结果,数据的真实意义还需要还原原值。

    • 在存在异常值时无法保证平衡的特征尺度。

  2. 归一化(转换到 [0,1] 区间);

    from sklearn.preprocessing import MinMaxScaler,StandardScaler
    # 归一化
    scaler = MinMaxScaler()
    result = scaler.fit_transform(data)  # 将data归一化
    
    scaler.inverse_transform(result) # 将归一化结果逆转
    

    缺点:

    • 这种方法有一个缺陷就是当有新数据加入时,可能导致max和min的变化,需要重新定义。

    • MinMaxScaler对异常值的存在非常敏感。

  3. MaxAbs归一化
    定义:单独地缩放和转换每个特征,使得训练集中的每个特征的最大绝对值将为1.0,将属性缩放到[-1,1]。它不会移动/居中数据,因此不会破坏任何稀疏性。
    在这里插入图片描述

    from sklearn.preprocessing import MaxAbsScaler
    maxAbsScaler = MaxAbsScaler().fit(X_train) 
    maxAbsScaler.transform(X_train)
    

    缺点:

    1. 这种方法有一个缺陷就是当有新数据加入时,可能导致max和min的变化,需要重新定义;
    2. 对异常值的存在非常敏感
  4. 正态分布化(Normalization)
    定义:正则化的过程是将每个样本缩放到单位范数(每个样本的范数为1)。Normalization主要思想是对每个样本计算其p-范数,然后对该样本中每个元素除以该范数,这样处理的结果是使得每个处理后样本的p-范数(l1-norm,l2-norm)等于1。
    在这里插入图片描述
    适用情形:如果要使用如二次型(点积)或者其它核方法计算两个样本之间的相似性这个方法会很有用。该方法是文本分类和聚类分析中经常使用的向量空间模型(Vector Space Model)的基础。

    from sklearn.preprocessing import Normalizer
    #正态归一化,返回值为正态归一化后的数据 
    normalizer = Normalizer(norm='l2').fit(X_train) 
    normalizer.transform(X_train)
    
  5. 针对幂律分布,可以采用公式: l o g 1 + x 1 + m e d i a n log\frac{1+x}{1+median} log1+median1+x

1.2.2 连续数值型特征分箱

  一些数据挖掘算法,特别是某些分类算法,如ID3算法、Apriori算法等,要求数据是分类属性形式。这样,常常需要将连续属性变换成分类属性,即连续属性离散化。
  连续属性离散化的优势:

  • 离散后稀疏向量内积乘法运算速度更快,计算结果也方便存储,容易扩展;
  • 离散后的特征对异常值更具鲁棒性,如 age>30 为 1 否则为 0,对于年龄为 200 的也不会对模型造成很大的干扰;
  • LR 属于广义线性模型,表达能力有限,经过离散化后,每个变量有单独的权重,这相当于引入了非线性,能够提升模型的表达能力,加大拟合;
  • 离散后特征可以进行特征交叉,提升表达能力,由 M+N 个变量编程 M*N 个变量,进一步引入非线形,提升了表达能力;
  • 特征离散后模型更稳定,如用户年龄区间,不会因为用户年龄长了一岁就变化

  连续属性离散化就是在数据的取值范围内设定若干个离散的划分点,将取值范围划分为一些离散化的区间,最后用不同的符号或整数值代表落在每个子区间中的数据值。所以,连续属性离散化涉及两个子任务:确定分类数以及如何将连续属性值映射到这些分类值。特征分箱可分为无监督分箱与有监督分箱方法。

1.2.2.1 无监督分箱法
  1. 自定义分箱
    定义:自定义分箱,是根据业务经验或者常识等自行设定划分的区间,然后将原始数据归类到各个区间中。

  2. 等距分箱
    将属性的值域分成具有相同宽度的区间,区间的个数由数据本身的特点决定或者用户指定。等距分箱只考虑区间宽度相同,每个区间里面的实例数量可能不等。

    	import pandas as pd
    import numpy as np
    
    df = pd.DataFrame([[22, 1], [13, 1], [33, 1],
                       [52, 0], [16, 0], [42, 1], [53, 1], [39, 1], [26, 0], [66, 0]], columns=['age', 'Y'])
    k = 4
    # 等宽离散化,各个类别依次命名为0,1,2,3
    df['age_bin'] = pd.cut(df['age'], k)
    df['age_bin_label'] = pd.cut(df['age'], k, labels=range(k))
    print(df)
    
       age  Y          age_bin age_bin_label
    0   22  1  (12.947, 26.25]             0
    1   13  1  (12.947, 26.25]             0
    2   33  1    (26.25, 39.5]             1
    3   52  0    (39.5, 52.75]             2
    4   16  0  (12.947, 26.25]             0
    5   42  1    (39.5, 52.75]             2
    6   53  1    (52.75, 66.0]             3
    7   39  1    (26.25, 39.5]             1
    8   26  0  (12.947, 26.25]             0
    9   66  0    (52.75, 66.0]             3
    

    缺点:一方面需要人为规定划分的区间个数,另一方面,它对离群点比较敏感,倾向于不均匀地把属性值分布到各个区间。有些区间包含许多数据,而另外一些区间的数据极少,这样会严重损坏建立的决策模型。

  3. 等频分箱;
    将相同数量的记录放进每个区间。

    import pandas as pd
    import numpy as np
    
    df = pd.DataFrame([[22, 1], [13, 1], [33, 1],
                       [52, 0], [16, 0], [42, 1], [53, 1], [39, 1], [26, 0], [66, 0]], columns=['age', 'Y'])
    k = 5
    # 等频离散化,各个类别依次命名为0,1,2,3,4
    df['age_bin'] = pd.qcut(df['age'], k)
    df['age_bin_label'] = pd.qcut(df['age'], k, labels=range(k))
    print(df)
    
       age  Y         age_bin age_bin_label
    0   22  1    (20.8, 30.2]             1
    1   13  1  (12.999, 20.8]             0
    2   33  1    (30.2, 40.2]             2
    3   52  0    (40.2, 52.2]             3
    4   16  0  (12.999, 20.8]             0
    5   42  1    (40.2, 52.2]             3
    6   53  1    (52.2, 66.0]             4
    7   39  1    (30.2, 40.2]             2
    8   26  0    (20.8, 30.2]             1
    9   66  0    (52.2, 66.0]             4
    

    缺点:
    等频法虽然避免了等距分箱问题的产生,却可能将相同的数据值分到不同的区间,以满足每个区间中固定的数据个数。

  4. 基于聚类分箱
    定义:基于k均值聚类的分箱方法,k均值聚类法将观测值聚为k类,但在聚类过程中需要保证分箱的有序性,第一个分箱中所有观测值都要小于第二个分箱中的观测值,第二个分箱中所有观测值都要小于第三个分箱中的观测值,以此类推。
    聚类分箱具体步骤:

    1. 对预处理后的数据进行归一化处理。
    2. 将归一化处理过的数据,应用k-means聚类算法,划分为多个区间:采用等距法设定k-means聚类算法的初始中心,得到聚类中心。
    3. 在得到聚类中心后将相邻的聚类中心的中点作为分类的划分点,将各个对象加入到距离最近的类中,从而将数据划分为多个区间。
    4. 重新计算每个聚类中心,然后重新划分数据,直到每个聚类中心不再变化,得到最终的聚类结果。
    import pandas as pd
    import numpy as np
    from sklearn.cluster import KMeans
    
    k = 4
    df = pd.DataFrame([[22, 1], [13, 1], [33, 1],
                       [52, 0], [16, 0], [42, 1], [53, 1], [39, 1], [26, 0], [66, 0]],
                      columns=['age', 'Y'])
    # k为聚成几类
    kmodel = KMeans(n_clusters=k)
    # 训练模型
    kmodel.fit(df['age'].values.reshape(len(df), 1))
    # 求聚类中心
    c = pd.DataFrame(kmodel.cluster_centers_,columns=['聚类中心'])
    # 排序  
    c = c.sort_values(by='聚类中心')
    # 用滑动窗口求均值的方法求相邻两项求中点,作为边界点
    w = c.rolling(window=2).mean().iloc[1:]
    # 把首末边界点加上
    w = [0] + list(w['聚类中心'].values) +[df['age'].max()]
    #
    df['age_bins'] = pd.cut(df['age'], w)
    df['age_bins_label'] = pd.cut(df['age'], w, labels=range(k))
    print(df)
    
       age  Y         age_bins age_bins_label
    0   22  1    (0.0, 28.625]              0
    1   13  1    (0.0, 28.625]              0
    2   33  1  (28.625, 45.25]              1
    3   52  0   (45.25, 59.25]              2
    4   16  0    (0.0, 28.625]              0
    5   42  1  (28.625, 45.25]              1
    6   53  1   (45.25, 59.25]              2
    7   39  1  (28.625, 45.25]              1
    8   26  0    (0.0, 28.625]              0
    9   66  0    (59.25, 66.0]              3
    
  5. 二值化分箱
    定义:二值化可以将数值型(numerical)的特征进行阀值化得到boolean型数据。这对于下游的概率估计来说可能很有用(比如:数据分布为Bernoulli分布时)。定量特征二值化的核心在于设定一个阈值,大于阈值的赋值为1,小于等于阈值的赋值为0。

    from sklearn.preprocessing import Binarize
  • 8
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
数据预处理和数据清洗是数据分析和机器学习中非常重要的步骤。以下是Python数据预处理数据清洗的关键技术: 1. 缺失值处理:缺失值是指数据中的空值或者未知值。常见的处理方法包括删除包含缺失值的行或列、使用均值或中位数填充缺失值、使用插值方法填充缺失值等。 2. 异常值处理:异常值是指与其他观测值明显不同的值。处理异常值的方法包括删除异常值、将异常值替换为其他合理的值、使用统计方法检测和处理异常值等。 3. 数据类型转换:将数据转换为正确的数据类型是数据预处理的重要步骤。例如,将字符串类型转换为数值类型、将日期类型转换为时间戳等。 4. 数据标准化:数据标准化是将不同尺度的数据转换为相同尺度的数据,常用的方法有Z-score标准化、Min-Max标准化等。 5. 数据编码:将分类变量转换为数值变量数据预处理常见任务。常用的方法包括独热编码(One-Hot Encoding)、标签编码(Label Encoding)等。 6. 特征选择特征选择是从原始数据中选择最相关的特征,以提高模型的性能和效率。常用的方法包括相关系数分析、方差分析、递归特征消除等。 7. 数据平衡:当数据集中某一类别的样本数量明显多于其他类别时,会导致模型对多数类别的预测效果更好。为了解决这个问题,可以使用欠采样、过采样或者生成合成样本的方法来平衡数据集。 8. 数据集划分:将数据集划分为训练集、验证集和测试集是机器学习中常用的方法,可以用来评估模型的性能和进行模型选择。 9. 数据可视化:数据可视化是数据预处理的重要手段,可以帮助我们更好地理解数据的分布、关系和异常情况,从而指导数据清洗和特征工程的过程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值