数据预处理1:分类特征编码

作者: 章光辉_数据 | 来源:发表于2017-11-28 00:04 被阅读18次

    背景音乐:We Don't Talk Anymore

    很多时候,在我们拿到的数据集里,特征不都是连续的值,而是由某些离散化取值的数据组成。例如,性别特征可以具有如下取值:["male", "female"],天气特征有如下取值:["rainy", "sunny", "snowy"...]。

    1. 数字化编码LabelEncoder

    这样的特征是无法直接被模型识别的,因此需要将这些特征转换为数学模型能动的语言,一个很容易想到的方法就是,对这些特征进行数字化,也就是编号,比如,["male", "female"]可以用[0, 1]表示,["rainy", "sunny", "snowy"...]可以用[0,1, 2, ...]表示。总之,对于一个有N个类别的特征,总是可以用[0, N-1]之间的连续整数进行编号。

    # 用sklearn实现
    from sklearn.preprocessing import LabelEncoder
    Le = LabelEncoder()  # 构造编码器
    Le.fit(['sunny','rainy','snowy'])  # 训练编码器
    Le.classes_  # 等于array(['rainy', 'snowy', 'sunny'])
    Le.transform(['sunny'])  # 等于array([2])
    

    2. 独热编码OneHotEncoder

    上述的编码方式,归根结底,只是把离散型数据换了个表达方式,本质上还是不连续的。而且如果直接用的话,容易被当成是连续的数值型数据进行处理,造成错误,除非编码后得到的数据连续性是有实际意义的。

    对此,我们可以选择用独热编码来解决。通俗地讲,对于一个有N个类别的特征,总是可以构造N个新特征来唯一表示,比如,对于性别特征可以构造两个新特征,两个新特征的取值分别为:"male"→[1, 0],"female"→[0, 1]。总之,这N个新特征,在任何情况下,均只有1个特征取值为1,其他特征取值为0,从而保证了唯一性。

    # 用sklearn实现
    from sklearn.preprocessing import OneHotEncoder
    Ohe = OneHotEncoder()  # 构造编码器
    Ohe.fit([[1],[2],[3],[1],[3]])  # 训练编码器,输入是LabelEncoder得到的整数型数据
    Ohe.active_features_  # 等于array([1, 2, 3])
    Ohe.transform([[2]]).toarray()  # 等于array([[ 0.,  1.,  0.]])
    

    3. 为什么要用独热编码

    可能你会感觉奇怪,特征取值为[0, 1],还是离散的呀,何以解决数据的离散问题?那么我们要回到本质上来看,为什么我们不喜欢离散型数据?归根结底,是因为没办法对此类特征进行任何计算。(那你算帮我算算“李雷”和“韩梅梅”的距离有多远?)

    而我们将用OneHotEncoder编码后的特征当成是向量,相当于将特征扩展到了欧式空间,那么某个取值就对应着空间里的某个点。在机器学习算法中,特征之间往往要进行相似性的计算,或者距离的计算,这些计算都是在欧式空间里完成的。实际上,大部分机器学习算法是基于向量空间中的度量来进行计算的。所以,OneHotEncoder编码满足了我们对于计算的要求。(为了通俗一点就这么解释啦)

    4. 独热编码的优缺点

    • 优点
      解决了分类器不好处理属性数据的问题,在一定程度上也起到了扩充特征的作用。它的值只有0和1,不同的类型存储在垂直的空间。
    • 缺点
      当类别的数量很多时,特征空间会变得非常大。在这种情况下,一般可以用PCA来减少维度。而且OneHotEncoder + PCA这种组合在实际中也非常有用。

    5. 注意事项

    上面也讲到了,OneHotEncoder编码的目的是扩展到欧式空间,便于计算距离。但是对于某些算法,不需要计算特征的距离,特征是离散的也OK,那么我们就没必要多此一举。比如决策树算法,以及以决策树为基学习器的各类算法。

    相关文章

      网友评论

        本文标题:数据预处理1:分类特征编码

        本文链接:https://www.haomeiwen.com/subject/nfujbxtx.html