【机器学习-02】特征工程

目录

特征工程包含的内容

一、特征提取

1.1 特征提取API 

1.2 特征提取分类

1.2.1 字典特征提取

1.2.2 文本特征提取

方法一:CountVectorizer

方法二:TF-IDF特征提取

二、特征预处理

2.1 特征预处理API

2.2 数值数据的无量纲化

2.2.1 归一化

2.2.2 标准化

三、特征降维

3.1 特征选择 

3.1.1 方法一:Filter过滤式

1. 方差选择法

2. 相关系数 

3.1.2 方法二:Embedded嵌入式

3.2 主成分分析(PCA)


pandas:数据清洗、数据处理

sklearn:特征工程

特征工程包含的内容

一、特征提取

将任意原始数据(如文本或图像)转换为可用于机器学习的数字特征,便于计算机更好地去理解。

  • 字典特征提取(特征离散化)
  • 文本特征提取
  • 图像特征提取
1.1 特征提取API 

      sklearn.feature_extraction

1.2 特征提取分类
1.2.1 字典特征提取

作用:对字典数据进行特征值化,将字典内容转换为一个one-hot编码矩阵

sklearn.feature_extraction.DictVectorizer(sparse=True, …)

sparse默认为True,sparse=True时会返回sparse矩阵(稀疏矩阵),矩阵中不包括0,且会将非零值用其位置表示,节省内存,提高加载效率

  • DictVectorizer.fit_transform(X)

         X:字典或者包含字典的迭代器(包含字典的列表),返回sparse矩阵

  • DictVectorizer.inverse_transform(X)

         X:array数组或者sparse矩阵,返回值:转换之前数据格式

  • DictVectorizer.get_feature_names()

         返回类别的名称

字典特征提取:将类别转换为one-hot编码,节省内存,提高下载效率

from sklearn.feature_extraction import DictVectorizer  #导入字典特征提取模块

def dict_demo():
    """
    字典特征抽取
    :return:
    """
    data = [{'city':'北京', 'temperature':100},
            {'city':'上海', 'temperature':60},
            {'city':'深圳', 'temperature':30}]
    # 1、实例化一个转换器类
    transfer = DictVectorizer(sparse=False)
    # sparse=False返回的不是稀疏矩阵,会把零显示出来 
    # 2、调用fit_transform()
    data_new = transfer.fit_transform(data)
    print("data_new:\n", data_new)   # 转化后的
    print("特征名字:\n", transfer.get_feature_names_out())

    return None

if __name__ == "__main__":
    dict_demo()

 运行结果:

data_new:
 [[  0.   1.   0. 100.]
 [  1.   0.   0.  60.]
 [  0.   0.   1.  30.]]
 特征名字:
 ['city=上海', 'city=北京', 'city=深圳', 'temperature']

#第一列中值为1的那一行是上海
#第二列中值为1的那一行是北京
#第三列中值为1的那一行是深圳

应用场景 

  • 数据集当中类别特征比较多:

       先将数据集的特征转化为字典类型,再用 DictVectorizer 进行特征抽取

  • 本身拿到的数据就是字典类型
1.2.2 文本特征提取

作用:对文本数据进行特征值化,一般将文本中的单词作为特征(停用词不作为特征)

方法一:CountVectorizer

返回特征词的词频矩阵

API: sklearn.feature_extraction.text.CountVectorizer(stop_words=[ ])

  • CountVectorizer.fit_transform(X)

       X:文本或者包含文本字符串的可迭代对象(包含文本字符串的列表),返回sparse矩阵

  • CountVectorizer.inverse_transform(X)

       X:array数组或者sparse矩阵,返回值:转换之前数据格

  • CountVectorizer.get_feature_names()

       返回值:单词列表

英文文本特征提取:

from sklearn.feature_extraction.text import CountVectorizer
# 导入转换器类

def count_demo():
    """
    文本特征抽取:CountVectorizer
    :return:
    """
    data = ['life is short,i like like python',
            'life is too long,i dislike python']
    # 1、实例化一个转换器类
   # transfer = CountVectorizer(stop_words=["is","too"]) 使用停用词,将不计入该词
    transfer = CountVectorizer()  #CountVectorizer()中没有sparse参数,默认返回一个稀疏矩阵
    
    # 2、调用fit_transform
    data_new = transfer.fit_transform(data)
    print("data_new:\n", data_new.toarray())  
    # toarray:将sparse矩阵转换为二维数组,将稀疏矩阵转换为普通矩阵
    print("特征名字:\n", transfer.get_feature_names_out())
    # 新版本的sklearn中get_feature_names()已被重命名为get_feature_names_out()
    return None
    
if __name__ == "__main__":
    count_demo()

 运行结果:

data_new:
 [[0 1 1 2 0 1 1 0]
 [1 1 1 0 1 1 0 1]]
特征名字:
 ['dislike', 'is', 'life', 'like', 'long', 'python', 'short', 'too']

#统计每一个样本中出现特征词的个数
#如矩阵中第一行表示该样本中出现特征词dislike的次数为0,出现特征词like的次数为2
#停用词不作为特征词

中文文本特征提取:

英文中每个单词之间都有空格隔开,但中文没有,如果处理中文也用上面的方法则会认为一整句话就是一个特征词。

data_new:
 [[0 1]
 [1 0]]
特征名字:
 ['天安门上太阳升' '我爱北京天安门']

解决方法:

1、手动给中文词语之间添加空格进行分词

手动分词结果:  
data = ['我 爱 北京 天安门',
        '天安门 上 太阳 升']

运行结果:
data_new:
 [[1 1 0]
 [0 1 1]]
特征名字:
 ['北京' '天安门' '太阳']

2、使用jieba等分词工具给中文文本分词后再进行特征提取

from sklearn.feature_extraction.text import CountVectorizer
import jieba  #导入jieba库

def count_chinese_demo2():
    '''
    中文文本特征提取
    '''
    data = ['一种还是一种今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。',
            '我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。',
            '如果只用一种方式了解某件事物,他就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。']
    data_new=[]
    for sent in data:       #将列表中的文本进行逐个分词处理
        data_new.append(cut_word(sent))
    transfer=CountVectorizer() #可加stop_word
    data_final=transfer.fit_transform(data_new)
    print('data_final=\n',data_final.toarray())   #将稀疏矩阵转化为普通的二维矩阵
    print('特征名字:\n',transfer.get_feature_names())
    return None

def cut_word(text):
    '''进行中文分词'''
    a=' '.join(list(jieba.cut(text)))
    print(a)
    return a

if __name__=="__main__":
    count_chinese_demo2()

运行结果:

一种 还是 一种 今天 很 残酷 , 明天 更 残酷 , 后天 很 美好 , 但 绝对 大部分 是 死 在 明天 晚上 , 所以 每个 人 不要 放弃 今天 。
我们 看到 的 从 很 远 星系 来 的 光是在 几百万年 之前 发出 的 , 这样 当 我们 看到 宇宙 时 , 我们 是 在 看 它 的 过去 。
如果 只用 一种 方式 了解 某件事 物 , 他 就 不会 真正 了解 它 。 了解 事物 真正 含义 的 秘密 取决于 如何 将 其 与 我们 所 了解 的 事物 相 联系 。
data_final=
 [[2 0 1 0 0 0 2 0 0 0 0 0 1 0 1 0 0 0 0 1 1 0 2 0 1 0 2 1 0 0 0 1 1 0 0 1 0]
 [0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0 1 3 0 0 0 0 1 0 0 0 0 2 0 0 0 0 0 1 0  1]
 [1 1 0 0 4 2 0 0 0 0 1 1 0 1 0 1 1 0 1 0 0 1 0 0 0 1 0 0 0 2 1 0 0 1 0 0  0]]
特征名字:
 ['一种', '不会', '不要', '之前', '了解', '事物', '今天', '光是在', '几百万年', '发出', '取决于', '只用', '后天', '含义', '大部分', '如何', '如果', '宇宙', '我们', '所以', '放弃', '方式', '明天', '星系', '晚上', '某件事', '残酷', '每个', '看到', '真正', '秘密', '绝对', '美好', '联系', '过去', '还是', '这样']
方法二:TF-IDF特征提取

返回特征词的TF-IDF矩阵

      CountVectorizer方法中只考虑文本样本中特征词的出现次数,不考虑其他因素。

关键词:再某一类别的文章中,出现次数很多,但在其他类别的文章中出现很少。

主要思想:如果某个词或短语在一篇文章中出现的概率高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。

公式:TF-IDF = TF x IDF

  • 作用:用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。TF-IDF的值越大,表示该词越重要。
  • 词频(term frequency,TF):某一个给定的词语在该文中出现的频率。
  • 逆向文档频率(inverse document frequency,IDF):词语普遍重要性的度量,可以由总文件数目除以包含该词语文件的数目,再将得到的商取以10为底的对数得到。

如一个语料库(文件集)中共有1000篇文章,其中有100篇文章中包含“经济”这个词语。

某篇文章共有100个词语,其中“经济”出现了10次,则“经济”在该文中的词频为0.1。

在该语料库中“经济”的逆向文档频率为\log_{10}(1000/100)=1

所以在该语料库中“经济”的TF-IDF=0.1

API: sklearn.feature_extraction.text.TfidfVectorizer(stop_words=[ ])

  • TfidfVectorizer.fit_transform(X)

       X:文本或者包含文本字符串的可迭代对象(包含文本字符串的列表),返回sparse矩阵

  • TfidfVectorizer.inverse_transform(X)

       X:array数组或者sparse矩阵,返回值:转换之前数据格

  • TfidfVectorizer.get_feature_names()

       返回值:单词列表

from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
import jieba

def tfidf_demo():
    """
    用TF-IDF的方法进行文本特征抽取
    :return:
    """
    data = ['今天很残酷,明天更残酷,后天很美好,但绝大部分是死在明天晚上,所以每个人不要放弃今天。',
            '我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。',
            '如果只用一种方式了解某件事物,他就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。']
    data_new = []
    for sent in data:
        data_new.append(cut_word(sent))
    print(data_new)

    # 1、实例化一个转换器类
    transfer = TfidfVectorizer()
    # 2、调用fit_transform
    data_final = transfer.fit_transform(data_new)
    print("data_final:\n", data_final.toarray())
    print("特征名字:\n", transfer.get_feature_names())
    return None

def cut_word(text):
    '''进行中文分词'''
    a=' '.join(list(jieba.cut(text)))
    print(a)
    return a

if __name__ == "__main__":
    tfidf_demo()

运行结果:

今天 很 残酷 , 明天 更 残酷 , 后天 很 美好 , 但 绝大部分 是 死 在 明天 晚上 , 所以 每个 人 不要 放弃 今天 。
我们 看到 的 从 很 远 星系 来 的 光是在 几百万年 之前 发出 的 , 这样 当 我们 看到 宇宙 时 , 我们 是 在 看 它 的 过去 。
如果 只用 一种 方式 了解 某件事 物 , 他 就 不会 真正 了解 它 。 了解 事物 真正 含义 的 秘密 取决于 如何 将 其 与 我们 所 了解 的 事物 相 联系 。
['今天 很 残酷 , 明天 更 残酷 , 后天 很 美好 , 但 绝大部分 是 死 在 明天 晚上 , 所以 每个 人 不要 放弃 今天 。', '我们 看到 的 从 很 远 星系 来 的 光是在 几百万年 之前 发出 的 , 这样 当 我们 看到 宇宙 时 , 我们 是 在 看 它 的 过去 。', '如果 只用 一种 方式 了解 某件事 物 , 他 就 不会 真正 了解 它 。 了解 事物 真正 含义 的 秘密 取决于 如何 将 其 与 我们 所 了解 的 事物 相 联系 。']
data_final:
 [[0.         0.         0.2236068  0.         0.         0.
  0.4472136  0.         0.         0.         0.         0.
  0.2236068  0.         0.         0.         0.         0.
  0.2236068  0.2236068  0.         0.4472136  0.         0.2236068
  0.         0.4472136  0.2236068  0.         0.         0.
  0.2236068  0.2236068  0.         0.         0.        ]
 [0.         0.         0.         0.2410822  0.         0.
  0.         0.2410822  0.2410822  0.2410822  0.         0.
  0.         0.         0.         0.         0.2410822  0.55004769
  0.         0.         0.         0.         0.2410822  0.
  0.         0.         0.         0.48216441 0.         0.
  0.         0.         0.         0.2410822  0.2410822 ]
 [0.16765125 0.16765125 0.         0.         0.670605   0.3353025
  0.         0.         0.         0.         0.16765125 0.16765125
  0.         0.16765125 0.16765125 0.16765125 0.         0.1275031
  0.         0.         0.16765125 0.         0.         0.
  0.16765125 0.         0.         0.         0.3353025  0.16765125
  0.         0.         0.16765125 0.         0.        ]]
特征名字:
 ['一种', '不会', '不要', '之前', '了解', '事物', '今天', '光是在', '几百万年', '发出', '取决于', '只用', '后天', '含义', '如何', '如果', '宇宙', '我们', '所以', '放弃', '方式', '明天', '星系', '晚上', '某件事', '残酷', '每个', '看到', '真正', '秘密', '绝大部分', '美好', '联系', '过去', '这样']

# 特征词对应数组中的数越大,表示该词越重要

二、特征预处理

作用:通过一些转换函数,将特征数据转换成更适合算法模型的特征数据的过程

2.1 特征预处理API

      sklearn.preprocessing

2.2 数值数据的无量纲化

  • 归一化
  • 标准化

为什么要无量纲化:

有时不同特征的单位或者大小相差较大,或者某特征相比其他的特征要大出几个数量级,因此某些特征容易影响(支配)目标结果,(例如在计算欧式距离时,数量级较大的特征则较容易决定最终距离的大小),使得一些算法无法学习到其它的特征。而且在统计人看来,可能不同的特征是同等重要的。

因此,需要对特征数据进行无量纲化,统一量纲,使不同规格的数据转换到同一规格。

2.2.1 归一化

定义:通过对原始数据进行变换,把数据映射到某一区间( 默认为[0,1] )

公式: 

注意:上述公式的计算是以列为单位的,max为x所在列的最大值,min为x所在列的最小值,mx,mi 分别为指定区间值,默认mx为1 ,mi为0。X''为归一化的最终结果。

特征1特征2特征3特征4
9021040
6041545
7531346

例如,15的归一化结果为1

x' = (15 - 10) / (15 - 10) = 1

x'' = 1 x (1 - 0) + 0 = 1
API : sklearn.preprocessing.MinMaxScaler(feature_range=(0,1)…)

feature_range为特征数据转换的范围。

  • MinMaxScaler.fit_transform(X)

       X:numpy.array格式的数据,是[n_samples, n_features]型的数组
       返回值:与转换前形状相同的数组
 

import pandas as pd
from sklearn.preprocessing import MinMaxScaler

def minmax_demo():
    """
    归一化
    :return:
    """
    # 1、获取数据
    data = pd.read_csv("dating.txt")
    data = data.iloc[:, :3] #只需处理前三列,不需要对目标值进行处理
    print("data:\n", data)

    # 2、实例化一个转换器类
    transform = MinMaxScaler()
    #transform = MinMaxScaler(feature_range=[2,3]) #转化到[2,3]范围内

    # 3、调用fit_transform进行转化
    data_new = transform.fit_transform(data)
    print("data_new:\n", data_new)

    return None

if __name__ == "__main__":
    minmax_demo()
2.2.2 标准化

定义:通过对原始数据进行变换,把数据变换到均值为0,标准差为1

公式:

作用于每一列,\mu是平均值,\sigma是标准差 

标准化与归一化的比较: 

  • 归一化:如果出现异常点,影响了最大值或最小值,结果显然会发生变化。
  • 标准化:少量异常点对大量数据平均值和标准差影响较小。

总之,归一化的结果容易收到异常点的影响(异常点常常出现在最大值或最小值上),但标准差的计算方法是根据数据的标准差和平均值,收到异常点影响的程度比归一化小。 

因此标准化比归一化的鲁棒性更好。

API:sklearn.perprocessing.StandradScaler()

处理之后,对每列来说,所有数据都聚集在均值为0附近,标准差为1

  • StandardScaler.fit_transform(X)

       X:numpy.array格式的数据,[n_samples,n_features]形式的数组
       返回值:与转换前形状相同的数组

import pandas as pd
from sklearn.preprocessing import MinMaxScaler, StandardScaler

def stand_demo():
    """
    标准化
    :return:
    """
    # 1、获取数据
    data = pd.read_csv("dating.txt")
    data = data.iloc[:, :3]
    print("data:\n", data)

    # 2、实例化一个转换器类
    transform = StandardScaler()
    #transform = StandardScaler(feature_range=[2,3])

    # 3、调用fit_transform
    data_new = transform.fit_transform(data)
    print("data_new:\n", data_new)

    return None

if __name__ == "__main__":
    stand_demo()

三、特征降维

降维是指在某些限定条件下,降低随机变量(特征)个数,得到一组“不相关”主变量的过程。即减少二维特征矩阵中的列数(特征个数),使最终得到的各个特征之间不相关。

相关特征:某地区的相对湿度与降雨量

在训练模型时我们都是用特征进行学习的,如果特征本身存在问题或者特征之间相关性较强,对算法的学习预测影响较大,另外进行特征降维也可以减少冗余。

特征降维的两种方式:

  • 特征选择
  • 主成分分析

3.1 特征选择 

数据中包含冗余或相关变量(或称特征、属性、指标等),特征选择旨在从原有特征中找出主要特征。

模块: sklearn.feature_selection

3.1.1 方法一:Filter过滤式

主要探究特征本身特点、特征与特征和目标值之间关联

1. 方差选择法

过滤掉低方差特征,比如鸟类是否有翅膀这个特征的方差为0 ,可以过滤掉

  • 特征方差小:某个特征大多样本的值比较相近,删除该特征
  • 特征方差大:某个特征很多样本的值都有差别,保留该特征

API:sklearn.feature_selection.VArianceThreshold(threshold=0.0)

         threshold表示阈值,默认为0.0,表示当方差为0.0时则过滤该特征,也可以设置为范围

  • Variance.fit_transform(X)

      X:numpy.array格式的数组,[m_sample,n_features]
      返回值:训练集差异低于threadshold的特征将被删除,默认值是保留非零方差特征,即删除所有样本中具有相同值,方差为0的特征。

from sklearn.feature_selection import VarianceThreshold

def variance_demo():
    """
    过滤低方差特征
    :return:
    """
    # 1、获取数据
    data = pd.read_csv('factor_returns.csv')
    data = data.iloc[:,1:-2]  # 选取需要进行筛选的特征
    print('data:\n', data)

    # 2、实例化一个转换器类
    #transform = VarianceThreshold()
    transform = VarianceThreshold(threshold=10)

    # 3、调用fit_transform
    data_new = transform.fit_transform(data)
    print("data_new\n", data_new, data_new.shape)

    return None

if __name__ == "__main__":
    variance_demo()
2. 相关系数 

衡量特征与特征之间的相关程度,相关程度较高则存在冗余。

皮尔逊相关系数:反映变量之间相关关系密切程度的统计指标。

也可以使用画图的方式来表示两个特征之间的相关性。

公式:

n是样本个数、x,y是样本的x特征和y特征的取值。 

相关系数的值介于 -1 与 +1 之间:

  • 当r>0时,表示两变量正相关;r<0时,两变量为负相关。
  • 当|r|=1时,表示两变量为完全相关;当r=0时,表示两变量间无相关关系。
  • 当0<|r|<1时,表示两变量存在一定程度的相关。且|r|越接近1,两变量间线性关系越密切;|r|越接近0,表示两变量的线性相关越弱。
  • 一般可按三级划分:|r|<0.4为低度相关;0.4<=|r|<0.7为显著相关;0.7<=|r|<1为高维线性相关
     

 API :from scipy.stats import pearsonr 

  • pearsonr(data[x],data[y])

       x,y为数据data的两个特征 ,返回值为皮尔逊相关系数。

from sklearn.feature_selection import VarianceThreshold
from scipy.stats import pearsonr

def variance_demo():
    """
    低方差特征过滤
    :return:
    """
    # 1、获取数据
    data = pd.read_csv('factor_returns.csv')
    print('data:\n', data)
    data = data.iloc[:,1:-2]
    print('data:\n', data)

    # 2、实例化一个转换器类
    #transform = VarianceThreshold()
    transform = VarianceThreshold(threshold=10)

    # 3、调用fit_transform
    data_new = transform.fit_transform(data)
    print("data_new\n", data_new, data_new.shape)

    # 计算两个变量之间的相关系数
    r = pearsonr(data["pe_ratio"],data["pb_ratio"])
    print("相关系数:\n", r)
    return None

if __name__ == "__main__":
    variance_demo()

若通过皮尔逊相关系数计算出特征与特征之间的相关性较大,可采取以下方法:

  • 选取其中一个
  • 加权求和
  • 主成分分析
3.1.2 方法二:Embedded嵌入式

算法自动选择特征(特征与目标值之间的关联)

  • 决策树
  • 正则化
  • 深度学习 

3.2 主成分分析(PCA)

定义:高维数据转换为低维数据的过程,在此过程中可能会舍弃原有数据、创造新的变量

作用:是数据维数的压缩,尽可能降低原数据的维数(复杂度),尽可能损失较少的信息

应用:回归分析或者聚类分析中

 API:sklearn.decomposition.PCA(n_components=None)

将数据分解为较低维度空间

n_components:

  • 小数:表示保留百分之多少的信息
  • 整数:减少到多少特征

PCA.fit_transform(X)

X:numpy.array格式的数据,[N_samples, n_features]

返回值:转换后指定维度的array

from sklearn.decomposition import PCA

def pca_demo():
    """
    PCA降维
    :return:
    """
    data = [[2,8,4,5], [6,3,0,8], [5,4,9,1]]
    # 1、实例化一个转换器类
    transform = PCA(n_components=2)  # 4个特征降到2个特征

    # 2、调用fit_transform
    data_new = transform.fit_transform(data)
    print("data_new\n", data_new)

    transform2 = PCA(n_components=0.95)  # 保留95%的信息
    data_new2 = transform2.fit_transform(data)
    print("data_new2\n", data_new2)

    return None

if __name__ == "__main__":
    pca_demo()

运行结果:

data_new
 [[ 1.28620952e-15  3.82970843e+00]
 [ 5.74456265e+00 -1.91485422e+00]
 [-5.74456265e+00 -1.91485422e+00]]
data_new2
 [[ 1.28620952e-15  3.82970843e+00]
 [ 5.74456265e+00 -1.91485422e+00]
 [-5.74456265e+00 -1.91485422e+00]]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值