机器学习之特征工程

1.Scikit-learn与特征工程

1.1 数据来源与类型

大部分的数据都来数据库或者爬虫以及平时的记录等。

  • 数据的类型

    按照机器学习的数据分类,可以将数据分成:

    • 标称型:标称型目标变量的结果只在有限目标集中取值,如真与假(标称型目标变量主要用于分类)
    • 数值型:数值型目标变量则可以从无限的数值集合中取值,如0.100,42.001等 (数值型目标变量主要用于回归分析)

    按照数据的本身分布特性

    • 离散型
    • 连续型

    那么什么是离散型和连续型数据呢?首先连续型数据是有规律的,离散型数据是没有规律的

    • 离散变量是指其数值只能用自然数或整数单位计算的则为离散变量.例如,班级人数、进球个数、是否是某个类别等等
    • 连续型数据是指在指定区间内可以是任意一个数值,例如,票房数据、花瓣大小分布数据

1.2 数据的特征抽取

现实世界中多数特征都不是连续变量,比如分类、文字、图像等,为了对非连续变量做特征表述,需要对这些特征做数学化表述,因此就用到了特征提取. sklearn.feature_extraction提供了特征提取的很多方法。

  • 分类特征变量提取

    我们将城市和环境作为字典数据,来进行特征的提取。

    1. sklearn.feature_extraction.DictVectorizer(sparse = True)
    2. 将映射列表转换为Numpy数组或scipy.sparse矩阵
    3. sparse 是否转换为scipy.sparse矩阵表示,默认开启
    方法
    1. fit_transform(X,y) 应用并转化映射列表X,y为目标类型

    2. .get_feature_names() 获取特征名

    3. inverse_transform(X[, dict_type]) 将Numpy数组或scipy.sparse矩阵转换为映射列表

      from sklearn.feature_extraction import DictVectorizer
      def dictvec():
          onehot=DictVectorizer() #实例化
          instances=[{'city':'北京','temperature':100},{'city':'上海','temperature':60},{'city':'广州','temperature':30}]
          X=onehot.fit_transform(instances).toarray() #如果结果不用toarray,请开启sparse=False
          print(onehot.get_feature_names())
          print(X)
          print(onehot.inverse_transform(X))
          return None
      
      ['city=上海', 'city=北京', 'city=广州', 'temperature']
      [[  0.   1.   0. 100.]
       [  1.   0.   0.  60.]
       [  0.   0.   1.  30.]]
      [{'city=北京': 1.0, 'temperature': 100.0}, {'city=上海': 1.0, 'temperature': 60.0}, {'city=广州': 1.0, 'temperature': 30.0}]
      
  • 文本特征提取

    文本的特征提取应用于很多方面,比如说文档分类、垃圾邮件分类和新闻分类。那么文本分类是通过词是否存在、以及词的概率(重要性)来表示。

    1.文档中词的出现

    1. 数值为1表示词表中的这个词出现,为0表示未出现
    2. sklearn.feature_extraction.text.CountVectorizer()
    3. 将文本文档的集合转换为计数矩阵(scipy.sparse matrices)
    方法
    1. fit_transform(raw_documents,y) 学习词汇词典并返回词汇文档矩阵

    英文文本特征提取

    from sklearn.feature_extraction.text import CountVectorizer
    def countvec():
        vectorizer=CountVectorizer() 
        content =['life is short,i ike python','life is too long,i dislike python']
        X=vectorizer.fit_transform(content).toarray()
        print(vectorizer.get_feature_names())
        print(X)
        return None
    
    ['dislike', 'ike', 'is', 'life', 'long', 'python', 'short', 'too']
    [[0 1 1 1 0 1 1 0]
     [1 0 1 1 1 1 0 1]]
    

    需要toarray()方法转变为numpy的数组形式

    温馨提示:每个文档中的词,只是整个语料库中所有词,的很小的一部分,这样造成特征向量的稀疏性(很多值为0)为了解决存储和运算速度的问题,使用Python的scipy.sparse矩阵结构

    中文文本特征提取

    在中文文本特征提取之前,需要对中文文本进行分词(采用jieba模块进行分词处理)。

    from sklearn.feature_extraction.text import CountVectorizer
    import jieba 
    def cutword():
        con1=jieba.cut('曾几何时,一颗热情似火的心,世界充满了温情,周边充满了友情,家庭充满了亲情。')
        con2=jieba.cut('曾几何时,社会充满人情味。也许是与生俱来的良知,使每一个人都拥有善良。')
        con3=jieba.cut('但是,忽然有一天,正如世界蒙上了面纱,朦胧了你的双眼,难以发现美的风景。')
        #转换成列表
        c1=list(con1)
        c2=list(con2)
        c3=list(con3)
        #把列表转换成字符串
        c1= ' '.join(c1)
        c2= ' '.join(c2)
        c3= ' '.join(c3)   
        return c1,c2,c3
    
    def chvec():
        c1,c2,c3=cutword()
        #print(c1,c2,c3)
        cv=CountVectorizer()
        data=cv.fit_transform([c1,c2,c3])
        print(cv.get_feature_names())
        print(data.toarray())
        return None
    
    ['一个', '一天', '一颗', '与生俱来', '世界', '也许', '亲情', '人情味', '似火', '但是', '充满', '友情', '双眼', '发现', '周边', '善良', '家庭', '忽然', '拥有', '曾几何时', '朦胧', '正如', '温情', '热情', '社会', '美的', '良知', '蒙上', '难以', '面纱', '风景']
    [[0 0 1 0 1 0 1 0 1 0 3 1 0 0 1 0 1 0 0 1 0 0 1 1 0 0 0 0 0 0 0]
     [1 0 0 1 0 1 0 1 0 0 1 0 0 0 0 1 0 0 1 1 0 0 0 0 1 0 1 0 0 0 0]
     [0 1 0 0 1 0 0 0 0 1 0 0 1 1 0 0 0 1 0 0 1 1 0 0 0 1 0 1 1 1 1]]
    

    2.TF-IDF表示词的重要性

    1. TfidfVectorizer会根据指定的公式将文档中的词转换为概率表示。(朴素贝叶斯介绍详细的用法
    2. class sklearn.feature_extraction.text.TfidfVectorizer()
    方法
    1. fit_transform(raw_documents,y) 学习词汇和idf,返回术语文档矩阵。
    from sklearn.feature_extraction.text import TfidfVectorizer
    def tfidfvec():
        c1,c2,c3=cutword()
        #print(c1,c2,c3)
        tf=TfidfVectorizer()
        data=tf.fit_transform([c1,c2,c3])
        print(tf.get_feature_names())
        print(data.toarray())
        return None
    
    ['一个', '一天', '一颗', '与生俱来', '世界', '也许', '亲情', '人情味', '似火', '但是', '充满', '友情', '双眼', '发现', '周边', '善良', '家庭', '忽然', '拥有', '曾几何时', '朦胧', '正如', '温情', '热情', '社会', '美的', '良知', '蒙上', '难以', '面纱', '风景']
    [[0.         0.         0.26386791 0.         0.20067835 0.
      0.26386791 0.         0.26386791 0.         0.60203505 0.26386791
      0.         0.         0.26386791 0.         0.26386791 0.
      0.         0.20067835 0.         0.         0.26386791 0.26386791
      0.         0.         0.         0.         0.         0.
      0.        ]
     [0.33046705 0.         0.         0.33046705 0.         0.33046705
      0.         0.33046705 0.         0.         0.25132871 0.
      0.         0.         0.         0.33046705 0.         0.
      0.33046705 0.25132871 0.         0.         0.         0.
      0.33046705 0.         0.33046705 0.         0.         0.
      0.        ]
     [0.         0.28195987 0.         0.         0.21443775 0.
      0.         0.         0.         0.28195987 0.         0.
      0.28195987 0.28195987 0.         0.         0.         0.28195987
      0.         0.         0.28195987 0.28195987 0.         0.
      0.         0.28195987 0.         0.28195987 0.28195987 0.28195987
      0.28195987]]
    

1.3 数据的特征预处理

  • 单个特征

    1.归一化

    归一化首先在特征(维度)非常多的时候,可以防止某一维或某几维对数据影响过大,也是为了把不同来源的数据统一到一个参考区间下,这样比较起来才有意义,其次可以程序可以运行更快。 例如:一个人的身高和体重两个特征,假如体重50kg,身高175cm,由于两个单位不一样,数值大小不一样。如果比较两个人的体型差距时,那么身高的影响结果会比较大,k-临近算法会有这个距离公式。

    min-max方法

    常用的方法是通过对原始数据进行线性变换把数据映射到[0,1]之间,变换的函数为:
    X^{\prime}=\frac{x-\min }{\max -\min }

    X^{\prime \prime}=X^{\prime} *(m x-m i)+m i

    其中min是样本中最小值,max是样本中最大值,其中mx默认为1,mi默认为0。注意在数据流场景下最大值最小值是变化的,另外,最大值与最小值非常容易受异常点影响,所以这种方法鲁棒性较差,只适合传统精确小数据场景

    from sklearn.preprocessing import MinMaxScaler
    def min_max():
        mm=MinMaxScaler(feature_range=(0,1))
        data = mm.fit_transform([[90,2,10,40],[60,4,19,40],[70,4,15,46]])
        print(data)
        return None
    
    [[1.         0.         0.         0.        ]
     [0.         1.         1.         0.        ]
     [0.33333333 1.         0.55555556 1.        ]]
    

    2.标准化

    常用的方法是z-score标准化,经过处理后的数据均值为0,标准差为1,处理方法是:
    X^{'}{=}\frac{x-\mu}{\sigma}

其中μ是样本的均值,σ是样本的标准差,它们可以通过现有的样本进行估计,在已有的样本足够多的情况下比较稳定,适合嘈杂的数据场景。

sklearn中提供了StandardScalar类实现列标准化:

from sklearn.preprocessing import tandardScaler
def stand():
    std=StandardScaler()
    data=std.fit_transform([[1,-1,3],[2,4,2],[4,6,-1]])
    print(data)
    return None
[[-1.06904497 -1.35873244  0.98058068]
 [-0.26726124  0.33968311  0.39223227]
 [ 1.33630621  1.01904933 -1.37281295]]

3.缺失值

由于各种原因,许多现实世界的数据集包含缺少的值,通常编码为空白,NaN或其他占位符。然而,这样的数据集与scikit的分类器不兼容,它们假设数组中的所有值都是数字,并且都具有和保持含义。使用不完整数据集的基本策略是丢弃包含缺失值的整个行和/或列。然而,这是以丢失可能是有价值的数据(即使不完整)的代价。更好的策略是估算缺失值,即从已知部分的数据中推断它们。

  1. 填充缺失值 使用sklearn.preprocessing中的Imputer类进行数据的填充:
from sklearn.preprocessing import Imputer
import numpy as np
def im():
    im=Imputer(missing_values='NaN',strategy='mean',axis=0)
    data=im.fit_transform([[1,2],[np.nan,3],[7,6]])
    print(data)
    return None
[[1. 2.]
 [4. 3.]
 [7. 6.]]

2.pandas中缺失值处理

判断数据是否为NaN:pd.isnull(df),pd.notnull(df)

处理方式1:删除NaN所在的行列dropna (axis=0, how='any', inplace=False)

处理方式2:填充数据,t.fillna(t.mean()),t.fiallna(t.median()),t.fillna(0)

处理为0的数据:t[t==0]=np.nan

具体内容请参考pandas基础教程

  • 多个特征

    降维

    PCA(Principal component analysis),主成分分析。特点是保存数据集中对方差影响最大的那些特征,PCA极其容易受到数据中特征范围影响,所以在运用PCA前一定要做特征标准化,这样才能保证每维度特征的重要性等同。

    sklearn.decomposition.PCA

    from sklearn.decomposition import PCA
    def pca():
        pca=PCA(n_components=0.9) #保留90%的主要特征
        data=pca.fit_transform([[2,8,4,5],[6,3,0,8],[5,4,9,1]])
        print(data)
        return None
    
    [[ 0.          3.82970843]
     [-5.74456265 -1.91485422]
     [ 5.74456265 -1.91485422]]
    

1.4 数据的特征选择

  • 降维本质上是从一个维度空间映射到另一个维度空间,特征的多少别没有减少,当然在映射的过程中特征值也会相应的变化。举个例子,现在的特征是1000维,我们想要把它降到500维。降维的过程就是找个一个从1000维映射到500维的映射关系。原始数据中的1000个特征,每一个都对应着降维后的500维空间中的一个值。假设原始特征中有个特征的值是9,那么降维后对应的值可能是3。而对于特征选择来说,有很多方法:

    • Filter(过滤式):VarianceThreshold
    • Embedded(嵌入式):正则化、决策树
    • Wrapper(包裹式)

    其中过滤式的特征选择后,数据本身不变,而数据的维度减少。而嵌入式的特征选择方法也会改变数据的值,维度也改变。Embedded方式是一种自动学习的特征选择方法,后面讲到具体的方法的时候就能理解了。

    特征选择主要有两个功能:

    (1)减少特征数量,降维,使模型泛化能力更强,减少过拟合

    (2)增强特征和特征值之间的理解

    sklearn.feature_selection

    去掉取值变化小的特征(删除低方差特征)

    VarianceThreshold 是特征选择中的一项基本方法。它会移除所有方差不满足阈值的特征。默认设置下,它将移除所有方差为0的特征,即那些在所有样本中数值完全相同的特征。

    假设我们要移除那些方差为小于1的特征:

    from sklearn.feature_selection import VarianceThreshold
    def var():
        var = VarianceThreshold(threshold=1.0)
        d=[[0, 2, 0, 3], [0, 1, 4, 3], [0, 1, 1, 3]]
        print(d)
        data= var.fit_transform(d)
        print(data)
        return None
    
    [[0, 2, 0, 3], 
    [0, 1, 4, 3], 
    [0, 1, 1, 3]]
    [[0]
     [4]
     [1]]
    

    内容源自于:
    《黑马程序员之机器学习》的视频整理

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容