2.3 特征工程之特征提取

1.为什么要特征工程

业界广泛流传∶数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。

2.什么是特征工程

意义:会直接影响机器学习的效果
sklearn 特征工程
pandas 数据清洗、数据处理
应用 DictVectorizer 实现对类别特征进行数值化、离散化
应用 CountVectorizer 实现对文本特征进行数值化
应用 TfidfVectorizer 实现对文本特征进行数值化

2.1特征抽取

机器学习算法 - 统计方法 - 数学公式
文本类型 -> 数值
image

类型 -> 数值
image

2.2 特征提取(字典类型进行特征提取方便一些)

将任意数据(如文本或图像)转换为可用于机器学习的数字特征
注:特征值化是为了计算机更好的去理解数据·字典特征提取(特征离散化)

·字典特征提取(特征离散化)
·文本特征提取
·图像特征提取(深度学习将介绍)

(1)特征提取API

sklearn.feature_extraction

2.2.1字典特征提取 - 类别 -> one-hot编码

字典类型数据进行特征提取方便一些,所以要把数据转化成字典类型比较方便处理

作用:对字典数据进行特征值化

类别 -> one-hot 编码(独热编码)

sklearn.feature_extraction.DictVectorizer(sparse=True,...)
  DictVectorizer.fit_transform(X) X:字典或者包含字典的迭代器返回 sparse 矩阵(稀疏矩阵 - 将非零值按位置表示出来,可以节省内存,提高加载效率)
  DictVectorizer.inverse_transform(X) X:array 数组或者 sparse 矩阵 返回值:转换之前数据格式
  DictVectorizer.get_feature_names() 返回类别名称
总结:对于特征当中存在类别信息的我们都会做 one-hot 编码处理

vector 数学:向量 物理:矢量
矩阵 matrix 二维数组
向量 vector 一维数组

image

[{'city':'北京','temperature':100},
{'city':'上海','temperature':60},
{'city':'深圳','temperature':30}]
转化完为
['city'='上海','city'='北京','city'='深圳','temperature']
[[0.1.0.100.]
[1.0.0.60.]
[0.0.1.30.]]
因为这给city为类别,所以需要拆开,要表示成数值,所以返回成3行4列的数组,
就是类别 -> one-hot编码

在调用这个sklearn.feature_extraction.DictVectorizer默认sparse=True,也就是会返回一个稀疏矩阵

执行的结果为这样的

from sklearn.feature_extraction import DictVectorizer

def dict_demo():
    """"
    字典特征提取
    """
    data=[{'city':'北京','temperature':100},
            {'city':'上海','temperature':60},
            {'city':'深圳','temperature':30}]
    #1.实例化一个转化器类
    transfer=DictVectorizer()
    #2.调用fit_transform()
    data_new=transfer.fit_transform(data)
    print("data_new:\n",data_new)
data_new:
   (0, 1)	1.0
  (0, 3)	100.0
  (1, 0)	1.0
  (1, 3)	60.0
  (2, 2)	1.0
  (2, 3)	30.0
  
其实在这个跟那个是等价的,这个左边就是所有的非0值,然后右边就是非0值的位置
sparse稀疏
将非零值 按位置表示出来
节省内存 - 提高加载效率(如果类别很多时可以节省内存)

所以在例化一个转化器类要设置sparse=False,或者在最后输出的时候输
data_new.toarray()

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction import DictVectorizer

def datasets_demo():
    """
    sklearn数据集的使用
    :return:
    """
    # 获取数据集
    #iris=sklearn.datasets.load_iris()
    iris = load_iris()
    print("鸢尾花数据集:\n", iris)
    print("查看数据集的描述:\n", iris["DESCR"])
    print("查看特特征值的名字:\n", iris.feature_names)
    print("查看特征值:\n",iris.data, iris.data.shape)
    # 数据集的划分
    x_train, x_test, y_train, y_test=train_test_split(iris.data, iris.target, test_size=0.2, random_state=22)
    print("训练集的特征值:\n", x_train, x_train.shape)
    return

def dict_demo():
    """"
    字典特征提取
    """
    data=[{'city':'北京','temperature':100},
          {'city':'上海','temperature':60},
          {'city':'深圳','temperature':30}]
    #1.实例化一个转化器类
    transfer=DictVectorizer(sparse=False)
    #2.调用fit_transform()
    data_new=transfer.fit_transform(data)
    print("data_new:\n",data_new)
    print("特征名字:\n",transfer.get_feature_names())
if __name__ == "__main__":
    # 代码1:sklearn()数据集的使用
    #datasets_demo()
    #代码2:字典特征提取
    dict_demo()

然后结果就是我们熟悉的了

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

之前在学习pandas中的离散化的时候,也实现了类似的效果。
我们把这个处理数据的技巧叫做”one-hot“编码:
image

这样处理的话不好,这个会给你一个错觉,数字带着一定的权重
然后看看下面的
image

应用场景:
1)pclass,sex 数据集当中类别特征比较多
1、将数据集的特征->字典类型
2、DictVectorizer转换
2)本身拿到的数据就是字典类型

2.2.2文本特征提取

单词作为特征值
特征:特征词

方法1.Countvectorizer

(1)sklearn.feature_extraction.text.CountVectorizer(stop_words=[]) 返回词频矩阵,stop_words 停用词列表,表示没什么用,就不做特征词了,可以到网上找停用词表

(2)
CountVectorizer.fit_transform(X) X: 文本或者包含文本字符串的可迭代对象 返回值:返回 sparse 矩阵
CountVectorizer.inverse_transform(X) X: array 数组或者 sparse 矩阵 返回值:转换之前数据格
CountVectorizer.get_feature_names() 返回值:单词列表
**sklearn.feature_extraction.text.TfidfVectorizer**

就是先实例化一个转换器类
然后再fit_transform()

image

在下面的例子中我们可以看出来,这个上面一行的特征词是不包含字母和标点符号的,然后每个出现的单词都列出来,然后下面的矩阵就是如果这个句子出现这个特征词,相应的下表就是这个词出现的次数

代码:

from sklearn.feature_extraction.text import CountVectorizer
import jieba

def count_demo():
    """
    文本特征抽取CountVecotrizer
    :return:
    """
    data=["life is short,i like like python","life is too long,i dislike python"]
    #1.实例化一个转换器类
    transfer = CountVectorizer()
    #2.调用fit_fransform
    data_new=transfer.fit_transform(data)
    print("data_new:\n",data_new)
    return None
  (0, 5)	1
  (0, 3)	2
  (0, 6)	1
  (0, 1)	1
  (0, 2)	1
  (1, 0)	1
  (1, 4)	1
  (1, 7)	1
  (1, 5)	1
  (1, 1)	1
  (1, 2)	1

很明显这个运行结果不是我们想要的
在这个里面我们不能用设置sparce=False来解决这个问题
我们可以用data_new.toarray()来解决,上一个也是可以用的

from sklearn.feature_extraction.text import CountVectorizer
import jieba
def count_demo():
    """
    文本特征抽取CountVecotrizer
    :return:
    """
    data=["life is short,i like like python","life is too long,i dislike python"]
    #1.实例化一个转换器类
    transfer = CountVectorizer()
    #2.调用fit_fransform
    data_new=transfer.fit_transform(data)
    print("data_new:\n",data_new.toarray())
    print("特征名字:\n",transfer.get_feature_names())
    return None
#运行结果
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']

注意这个中文是以单词作为特征词的
看看这个
data_new:
[[0 1]
[1 0]]
特征名字:
['天安门上太阳升', '我爱北京天安门']

特征提取的时候还会有一些停用词,stop_word=[],就是我们认为这些词没有意义,可以跳过,网上可以搜索停用词表

from sklearn.feature_extraction.text import CountVectorizer
import jieba
def count_demo():
    """
    文本特征抽取CountVecotrizer
    :return:
    """
    data=["life is short,i like like python","life is too long,i dislike python"]
    #1.实例化一个转换器类
    transfer = CountVectorizer(stop_words=["is","too"])
    #2.调用fit_fransform
    data_new=transfer.fit_transform(data)
    print("data_new:\n",data_new.toarray())
    print("特征名字:\n",transfer.get_feature_names())
    return None
data_new:
 [[0 1 2 0 1 1]
 [1 1 0 1 1 0]]
特征名字:
 ['dislike', 'life', 'like', 'long', 'python', 'short']

2.2.3中文文本特征提取(jieba分词)

我们在做中文的特征提取的时候他会把一个句子当成一个特征词,或者我们自动加空格,但是正常是没有空格的,所以我们需要自动分词
可以用jieba或者其他的库函数

jieba.cut()
返回词语组成的生成器

from sklearn.feature_extraction.text import CountVectorizer
import jieba
def cut_word(text):
    """
    进行中文分词:“我爱北京天安门”---->"我 爱 北京 天安门"
    :param text:
    :return:
    """
	#这里要转成字符串的类型
    text=" ".join(list(jieba.cut(text)))
    print(text)
    return text
cut_word("我爱北京天安门")
#结果就是
我 爱 北京 天安门

这个jieba库就是自动分词的

分析

  • 准备句子,利用jieba.cut进行分词
  • 实例化CountVectorizer
  • 将分词结果变成字符串当作fit_transform的输入值

最终代码

from sklearn.feature_extraction.text import CountVectorizer
import jieba

def count_chinese_demo2():
    """
    中文文本特征抽取,自动分词
    :return:
    """
    #1.将中文文本进行分词
    data = ["一种还是一种今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。",
            "我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",
            "如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。"]
    data_new=[]
    for sent in data:
        data_new.append(cut_word(sent))
    #print(data_new)
    # 1.实例化一个转换器类
    transfer = CountVectorizer()
    # 2.调用fit_fransform
    data_final = transfer.fit_transform(data_new)
    print("data_final:\n", data_final.toarray())
    print("特征名字:\n", transfer.get_feature_names())
    return None
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 3 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]]
特征名字:
 ['一种', '不会', '不要', '之前', '了解', '事物', '今天', '光是在', '几百万年', '发出', '取决于', '只用', '后天', '含义', '大部分', '如何', '如果', '宇宙', '我们', '所以', '放弃', '方式', '明天', '星系', '晚上', '某样', '残酷', '每个', '看到', '真正', '秘密', '绝对', '美好', '联系', '过去', '还是', '这样']

方法2:TfidfVectorizer

在上面的方法中你会看到有一些没有什么意义的词出现的频率很大,比如说“因为”“所以”,这种没有意义,但是出现的次数很多,很容易混淆视听,下面是解决方法:

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

image
该如何处理某个无用词或无用的短语在多篇文章中出现的次数高这种情况?

Tf-idf文本特征提取
TF-IDF的主要思想是∶如果某个词或短语在一篇文章中出现的概率高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。TF-IDF作用:用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。

公式
词频(term frequency,tf)指的是某一个给定的词语在该文件中出现的频率。
逆向文档频率(inverse document frequency,idf)是一个词语普遍重要性的度量。某一特定词语的idf,可以由总文件数目除以包含该词语之文件的数目,再将得到的商取以10为底的对数得到
if-idf=tf*idf

image

例如:
两个词 "经济","非常"
1000篇文章-语料库
100篇文章 - "非常"
10篇文章 - “经济”
两篇文章
文章A(100词) : 10次“经济” TF-IDF=0.1 * 2=0.2
tf:10/100 = 0.1
idf:lg 1000/10 = 2
文章B(100词) : 10次“非常” TF-IDF=1 * 0.1=0.1
tf:10/100 = 0.1
idf: log 10 1000/100 = 1

sklearn.feature_extraction.text.TfidfVectorizer(stop_words=None,...)
返回词的权重矩阵
TfidfVectorizer.fit_transform(x) X:文本或者包含文本字符串的可迭代对象 返回值:返回 sparse 矩阵
TfidfVectorizer.inverse_transform(x) X:array 数组或者 sparse 矩阵 返回值:转换之前数据格式
TfidfVectorizer.get_feature_names() 返回值:单词列表
from sklearn.feature_extraction.text import TfidfVectorizer
def tfidf_demo():
    """
    用TF—IDF的方法进行文本特征提取
    :return:
    """
    # 将中文文本进行分词
    data = ["一种还是一种今天很残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。",
            "我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",
            "如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何装其与我们所了解的事物相联系。"]
    data_new = []
    for sent in data:
        data_new.append(cut_word(sent))

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


if __name__ == "__main__":
    # 代码7:tfidf
    tfidf_demo()

Tf-idf的重要性
分类机器学习算法进行文章分类中前期数据处理方式

总结:

两种方法:
1.CountVectorizer 统计每个样本特征词出现的个数
2.TfidfVectorizer TF-IDF - 重要程度,判断每个词的重要程度

posted @ 2023-06-08 09:17  lipu123  阅读(44)  评论(0编辑  收藏  举报