机器学习 - 数据预处理中的特征离散化方法

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

可供参考的三种特征离散化方法

在数据分析中,我们认为在某个范围内取值过于密集的特征认为是取值”连续“的特征。出于某些需求经常需要将这些”连续特征进行离散化“。本文介绍三种比较实用的数据离散化方法。

李俊才 的个人博客
邮箱 :[email protected]
本文地址blog.csdn.net/qq_28550263…

方法1:尺度缩小法

这种方法是对于数值元素的一种简单粗暴的方法。离散化的目的不就是减少取值数目吗。那么好,只要把数据除以某个值,大数就变小数,抹掉小数位,自然取值个数就少了很多。很显然,这种离散化方法的特点在于对越小的数整合归并能力越强。 经常我们将数据读取为一个二维DataFrame结构的表,而需要离散化的是该DataFrame对象中的一列。以下该方法离散化的源代码。

def scaling(DF, feature, scale, submit=True):
    """
    数据尺度缩小法离散化

    Parameters
    -------
     - DF:      DataFrame,假设我们需要离散化的是DF种索引为feature的那一列
     - feature: str,特征名,将用作从DF中索引该列特征的有序所有取值
     - scale:   该列特征数值的放缩尺度。
     - submit:  bool,离散化后直接提交更改到DF中的该特征
    """
    dis_feature = DF[feature].copy()
    dis_feature = np.array(np.floor(np.array(DF[feature]/scale)))
    if submit:
        DF[feature] = dis_feature
    return dis_feature
复制代码

方法2:按数值区间分割数据法(使用pandas.cut())

经常我们将数据读取为一个二维DataFrame结构的表,而需要离散化的是该DataFrame对象中的一列。以下该方法离散化的源代码。

def pd_cut(DF,feature,bins,submit=True):
    """
    离散化备选方法2:
    按数值区间分割数据离散化——先按照数据取值将数据分割成n组。

    Parameters
    ----------
     - DF:      DataFrame,假设我们需要离散化的是DF种索引为feature的那一列
     - feature: str,特征名,将用作从DF中索引该列特征的有序所有取值
     - bins: 若为Series,则序列中数据元素各为分割点;
             若为int,则特征值定义范围内的等宽bin数。x的范围在每一侧
             都扩展了0.1%,以包括x的最小值和最大值。
     - submit: bool,离散化后直接提交更改到self.DF中的该特征
    """
    dis_feature  = DF[feature].copy()
    dis_feature  = pd.cut(Feature,bins)
    if submit:
        self.DF[feature] = dis_feature 
    return dis_feature 
复制代码

方法3:等元素个数分割法(使用pandas.qcut())

经常我们将数据读取为一个二维DataFrame结构的表,而需要离散化的是该DataFrame对象中的一列。以下该方法离散化的源代码。

def pd_qcut(self,feature,q,submit=True,**kw):
    """
    离散化备选方法3:
    等元素个数分割数据——分割后每个存储组有相同元素个数。

    Parameters
    -------
     - feature: str,特征名,将用作从DF中索引该列特征的有序所有取值
     - q: 频数,int,也就是分割后的组数
     - q_label: serial,分割后,必须用新的标签代表旧的数据,标签数目必
                须和分割的频数对应一致
     - submit: bool,离散化后直接提交更改到self.DF中的该特征
    """
    if kw.get('q_label') != None:
        q_label = kw.get('q_label')
    else:
        q_label = list(range(q))
    dis_feature = self.DF[feature].copy()
    dis_feature = pd.qcut(dis_feature,q,q_label,duplicates="drop") # duplicates="drop"表示如果bin边缘(每组的分位点处)不是唯一则丢弃非唯一变量
    if submit:
        self.DF[feature] = dis_feature
    return dis_feature
复制代码

使用作图法以对比DF中所有feature列离散前后的效果

直接上代码:

def barchart_ax(discrete_df, title='各个特征取值数量统计', xlabel='特征名称', ylabel='特征的不同取值量', background_color= "#EAEAF2", Batch1_color = "#25AFF3"):
    
    feature_values = []
    x_text = []
    for c in discrete_df.columns[1:]:
        x_text.append(c)
        ct = discrete_df[c].duplicated(keep ='first')

        feature_values.append(len(ct[ct==False]))
    batch1=feature_values
    
    pylab.rcParams['figure.figsize'] = (19.0, 10.0)
    plt.rcParams['font.sans-serif'] = ['KaiTi']
    matplotlib.rcParams['axes.unicode_minus'] = False
    x = np.arange(len(x_text))
    width = 0.66
    fig, ax = plt.subplots()
  
    rects = ax.bar(x - width/2, batch1, width, color = Batch1_color)                               

    ax.patch.set_facecolor(background_color)  
  
    ax.set_title(title, fontsize=26)     
    ax.set_xlabel(xlabel, fontsize=22)   
    ax.set_ylabel(ylabel, fontsize=22)  
  
    ax.set_xticks(x)    
    ax.set_xticklabels(x_text, fontsize=22)   
  
  
    for rect in rects:
        height = rect.get_height()
        ax.annotate('{}'.format(height),      
            xy=(rect.get_x() + rect.get_width() / 2, height),
            xytext=(0,3),      
            textcoords="offset points",
            ha='center', va='bottom')
        plt.grid(linestyle = "dotted",color = "g")
   
    plt.xticks(rotation=89)
    fig.tight_layout()
    plt.show()
复制代码

案例:等待编写。

小结

import pandas as pd
import numpy as np
class discretization(object):
    """
    离散化类:提供几种可供选择的离散化方法。
    离散化就是将特征中多个不同的特征值用相对少的取值表示。
    每种离散化方法一次工作中对特定的列(特征)进行离散化操作,返回被离散的列的离散化结果
    如果最终需要获取完成所有特征离散化的DataFrame,则使用该类实例的DF属性(discretization.DF)即可
    """
    def __init__(self,DataF):
        """
        初始化:拷贝一份传入的DataFrame。
        仅当各备选的离散化方法中,submit = True 时,将改变 self.DF 中该列特征的数据。
        """
        self.DF = DataF.copy()
        
    def scaling(self,feature,scale,submit=True):
        """
        离散化备选方法1:
        数据尺度缩小法离散化——该方法法通过将数值除以特定的数来进行离散化。
        
        Parameters
        -------
         - feature: str,特征名,将用作从DF中索引该列特征的有序所有取值
         - scale: 该列特征数值的放缩尺度。
         - submit: bool,离散化后直接提交更改到self.DF中的该特征
        """
        dis_feature = self.DF[feature].copy()
        dis_feature = np.array(np.floor(np.array(self.DF[feature]/scale)))
        if submit:
            self.DF[feature] = dis_feature
        return dis_feature

    def pd_cut(self,feature,bins,submit=True):
        """
        离散化备选方法2:
        按数值区间分割数据离散化——先按照数据取值将数据分割成n组。
        
        Parameters
        -------
         - feature: str,特征名,将用作从DF中索引该列特征的有序所有取值
         - bins: 若为Series,则序列中数据元素各为分割点;
                 若为int,则特征值定义范围内的等宽bin数。x的范围在每一侧
                 都扩展了0.1%,以包括x的最小值和最大值。
         - submit: bool,离散化后直接提交更改到self.DF中的该特征
        """
        dis_feature = self.DF[feature].copy()
        dis_feature = pd.cut(dis_feature ,bins)
        if submit:
            self.DF[feature] = dis_feature 
        return dis_feature 
        
    def pd_qcut(self,feature,q,submit=True,**kw):
        """
        离散化备选方法3:
        等元素个数分割数据离散化——分割后每个存储组有相同元素个数。
        
        Parameters
        -------
         - feature: str,特征名,将用作从DF中索引该列特征的有序所有取值
         - q: 频数,int,也就是分割后的组数
         - q_label: serial,分割后,必须用新的标签代表旧的数据,标签数目必
                    须和分割的频数对应一致
         - submit: bool,离散化后直接提交更改到self.DF中的该特征
        """
        if kw.get('q_label') != None:
            q_label = kw.get('q_label')
        else:
            q_label = list(range(q))
        dis_feature = self.DF[feature].copy()
        dis_feature = pd.qcut(dis_feature,q,q_label,duplicates="drop") # duplicates="drop"表示如果bin边缘(每组的分位点处)不是唯一则丢弃非唯一变量
        if submit:
            self.DF[feature] = dis_feature
        return dis_feature
复制代码

猜你喜欢

转载自juejin.im/post/7095623421387620360