机器学习--sklearn库的详细学习记录(一)特征提取

本人反思了之前学习的方法,总的来说还是如同我的上一篇机器学习(Python)–sklearn库相关内容中说的,不应该按照网上给的那些千篇一律的东西来学习。所以本人在试水了之后决定对我的学习记录进行重新规划。所以本人准备按照模块来进行记录我的学习笔记。

机器学习–特征工程

我们在理解了机器学习的原理之后我们就会了解到,由于我们是希望计算机可以按照我们给定的数据进行学习并总结,从而达到预测的功能。但是如何让计算机能够较好的进行预测,那么我们前期供给的数据则是决定了我们计算机学习精度的一个上限。这个数据我们就称之为特征值预测的结果我们就称之为目标值。所以我们可以得到一个结论,特征值的提取是非常重要的一步。

通过sklearn进行特征抽取

特征抽取的函数都存放在sklearn.feature_extraction这个模块中。其中最为简单的就是对字典的特征进行提取。

字典类型的特征提取

首先、我们使用下面这段数据进行测试

[{'name': '小明', 'grade': 100},
 {'name': '小红', 'grade': 60},
 {'name': '大黄', 'grade': 30}]

从数据中我们可以看到,这串数据有两个字段,一个是姓名,一个是他们的分数。假如我们想要通过找到某一个人的分数,对于计算机来说,他应该怎么做呢?因为计算机是不知道小明、小红、大黄他们究竟是谁的,所以我们就需要将他们数字化。具体操作如下:

from sklearn.feature_extraction import DictVectorizer


def dictvect():
    dict = [{'name': '小明', 'grade': 100},
            {'name': '小红', 'grade': 60},
            {'name': '大黄', 'grade': 30}]
    dictvect = DictVectorizer(sparse=False);
    data = dictvect.fit_transform(dict);
    print(data)
    print(dictvect.get_feature_names())
    return None


if __name__ == "__main__":
    dictvect()
  • 首先我们导入模块DictVectorizer,在之前我已经说过了,关于特征提取的函数都是定义sklearn.feature_extraction中的。
  • 我们定义一个函数,为了方便演示。第一步是实例化一个对象dictvect = DictVectorizer(sparse=False);
    其中的参数sparsesklearn库自定义的一种数组类型,总的来说就是为了节省内存。
  • 使用fit_transform(dict),这个方法就可以对数据进行特征提取。

输出结果如下:

[[100.   0.   1.   0.]
 [ 60.   0.   0.   1.]
 [ 30.   1.   0.   0.]]
['grade', 'name=大黄', 'name=小明', 'name=小红']

为了能够较好发现其中的规律,我同时打印出了他的特征变量(使用方法get_feature_names()

  • 第一列,我们可以看到,对应的是分数。而后面的三列我们单独来看可以发现,这就是one-hot编码格式。
  • 单独来看后三列,对于第一行数据来说,因为它代表的数据是小明,所以在大黄小红这两列上都置为0,在小明这一列上置为1。
  • 关于什么是one-hot编码,各位可以自行百度,这是一个很简单的知识点。

至此,关于字典类型的特征提取就大致介绍完了。因为字典类型的提取是较为简单的,了解即可。

文本类型的特征提取

在对文本类型的数据进行特征提取时,我们会有许多较为常用的函数,本人将会介绍两种,第一种是CountVectorizerTfidfVectorizer首先介绍的是CountVectorizer

英文文本的特征提取

首先给出要处理的文本如下:

["i like english, what about you", "i dislike math and english"]

接下来是给出相应的处理代码:

from sklearn.feature_extraction import DictVectorizer

from sklearn.feature_extraction.text import CountVectorizer


def dictvect():
    dict = [{'name': '小明', 'grade': 100},
            {'name': '小红', 'grade': 60},
            {'name': '大黄', 'grade': 30}]
    dictvect = DictVectorizer(sparse=False);
    data = dictvect.fit_transform(dict);
    print(data)
    print(dictvect.get_feature_names())
    return None


def countvect():
    count = CountVectorizer()
    text = ["i like english, what about you", "i dislike math and english"]
    data = count.fit_transform(text)

    print(count.get_feature_names())
    # print(data)
    print(data.toarray())

    return None


if __name__ == "__main__":
    # dictvect()
    countvect()
  • 由于都是对特征进行提取,所以本人将相关的代码放在了同一个文档当中。
  • 与处理字典类型相同,首先我们需要导入相应的模块,需要注意的是,处理文本类型的模块有很多,第一个例子则是采用CountVectorizer对文本进行处理
  • 对数据进行特征提取转化的方法都是一样的fit_transform,但是当前的区别在于,这个实例化中(count = CountVectorizer())没有sparse这个参数,所以返回的值将是sparse数组形式。但是我们可以通过toarray()对其进行转化。

输出结果如下:

//特征值
['about', 'and', 'dislike', 'english', 'like', 'math', 'what', 'you']
//sparse数组形式
  (0, 7)	1
  (0, 0)	1
  (0, 6)	1
  (0, 3)	1
  (0, 4)	1
  (1, 1)	1
  (1, 5)	1
  (1, 2)	1
  (1, 3)	1
  //array数组形式
[[1 0 0 1 1 0 1 1]
 [0 1 1 1 0 1 0 0]]
  • 通过将特征值和array数组形式的结果结合起来来看,我们则能较为容易的看出其中的特点。
  • 首先,特征值是所有文本中出现的单词(重复的也只算为一次,单个字母的单词不计入特征,因为单个字母我们可以认为对文本的意义没有影响
  • 按照特征值的顺序,第一句话中about出现了则为1and没有出现则为0,依此类推,通过这种方式我们就以以数字的形式来表示我们的文本。
    从上面的内容上我们可以看到,这是对英文文本进行处理的结果,如果我们想要处理中文文本是否依然可以使用这个CountVectorizer
中文文本的特征提取

首先我们给出需要处理三段文字:

["短文是中国汉语词语,指报纸或期刊上的一段短的新闻报道或特写或篇幅短的文章。",
 "短文,并不是一种文学体裁,因而以前并没有短文这一提法。",
 "短文篇幅的衡量标准由于载体的不同而有所差异。通常在2千字以下,个别的有所放宽。"]

接下来是相应的处理代码:

def chinesevect():
    count = CountVectorizer()
    text = ["短文是中国汉语词语,指报纸或期刊上的一段短的新闻报道或特写或篇幅短的文章。",
            "短文,并不是一种文学体裁,因而以前并没有短文这一提法。",
            "短文篇幅的衡量标准由于载体的不同而有所差异。通常在2千字以下,个别的有所放宽。"]
    data = count.fit_transform(text)
    print(count.get_feature_names())
    print(data.toarray())
    return None
  • 与处理英文时使用的方法相同,我们直接来看输出结果。
['个别的有所放宽', '因而以前并没有短文这一提法', '并不是一种文学体裁', '指报纸或期刊上的一段短的新闻报道或特写或篇幅短的文章', '短文', '短文是中国汉语词语', '短文篇幅的衡量标准由于载体的不同而有所差异', '通常在2千字以下']
[[0 0 0 1 0 1 0 0]
 [0 1 1 0 1 0 0 0]
 [1 0 0 0 0 0 1 1]]
  • 我们从结果中可以看出,该方法是通过分隔符对每个词进行分割的,所以在中文中这种方法并不适用,以此方法分割的中文文本都是以短句的形式呈现的
  • 同样的,如果是单个中文字,也是会被除去的。
  • 提问:我们应该如何对中文文本进行特征提取呢?

其实这个问题的解决方法是很简单的,因为我们只要提前对中文文本进行分词,再将结果传入该方法中即可。这时我们需要用到一个较好用的中文分词库jieba,如果大家不熟悉jieba分词库的话,大家可以参考我的另一篇博客

接下来我将直接给出我的代码(如果我没有提到要导包则代表当前导入的包以已经够用):

import jieba
...
def cutword():
    c1 = jieba.cut('短文是中国汉语词语,指报纸或期刊上的一段短的新闻报道或特写或篇幅短的文章。')
    c2 = jieba.cut('短文,并不是一种文学体裁,因而以前并没有短文这一提法。')
    c3 = jieba.cut('短文篇幅的衡量标准由于载体的不同而有所差异。通常在2千字以下,个别的有所放宽。')
    content1 = ' '.join(list(c1))
    content2 = ' '.join(list(c2))
    content3 = ' '.join(list(c3))
    return content1, content2, content3


def chinesevect():
    count = CountVectorizer()
    content1, content2, content3 = cutword()
    text = [content1, content2, content3]
    data = count.fit_transform(text)
    print(count.get_feature_names())
    print(data.toarray())
    return None

输出结果如下:

['一段', '一种', '不同', '不是', '个别', '中国', '以下', '以前', '体裁', '千字', '因而', '差异', '报纸', '提法', '放宽', '文学', '文章', '新闻报道', '有所', '期刊', '汉语', '没有', '特写', '由于', '短文', '篇幅', '衡量标准', '词语', '载体', '这一', '通常']
[[1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 1 1 0 1 1 0 1 0 1 1 0 1 0 0 0]
 [0 1 0 1 0 0 0 1 1 0 1 0 0 1 0 1 0 0 0 0 0 1 0 0 2 0 0 0 0 1 0]
 [0 0 1 0 1 0 1 0 0 1 0 1 0 0 1 0 0 0 2 0 0 0 0 1 1 1 1 0 1 0 1]]
  • 其含义和英文文本是相同的,因为中文文本的特殊性,所以我们需要提前对文本进行处理
  • CountVectorizer()中是可以添加停用词的,相应的参数为stop_words,停用词的含义大家也可以参照我的博客。我在这篇博客中进行了较为细致的介绍,当然大家也可以自行Google停用词的含义。

TFidf文本特征提取

由于这个方法真的是非常非常的重要,所以本人以一个模块的形式来表达我对该方法的看重。

我们在进行文本特征提取的时候,主要目的就是为了一段文本的中心词,一次来判断文本想要表达的含义,但是当某个词在很多篇文章中出现的次数都比较高时我们该怎么办呢?我在这里给出结论,就是使用TFidf进行文本特征提取。

TF-IDF的主要思想:如果某个词或者是短语在一篇文章中出现的概率比较高,同时在别的文章中出现的概率比较低,我们则有理由认为这个词或者是短语具有较强的特征。(ps:关于更加详细的介绍,大家可以去自行查找,网上有很多关于这个算法的公式和介绍)

当然啦,代码的实现是很简答的。我们依旧使用中文文本特征提取中的数据;同时给出代码:

from sklearn.feature_extraction.text import TfidfVectorizer
import jieba
...
def chinesevectwo():
    count = TfidfVectorizer()
    content1, content2, content3 = cutword()
    text = [content1, content2, content3]
    data = count.fit_transform(text)
    print(count.get_feature_names())
    print(data.toarray())
    return None
  • 我们可以看到,其实我们只是更改了实例化的对象,将CountVectorizer改为了TfidfVectorizer
  • 下面是运行的结果。
['一段', '一种', '不同', '不是', '个别', '中国', '以下', '以前', '体裁', '千字', '因而', '差异', '报纸', '提法', '放宽', '文学', '文章', '新闻报道', '有所', '期刊', '汉语', '没有', '特写', '由于', '短文', '篇幅', '衡量标准', '词语', '载体', '这一', '通常']
[[0.31738473 0.         0.         0.         0.         0.31738473
  0.         0.         0.         0.         0.         0.
  0.31738473 0.         0.         0.         0.31738473 0.31738473
  0.         0.31738473 0.31738473 0.         0.31738473 0.
  0.18745253 0.24137927 0.         0.31738473 0.         0.
  0.        ]
 [0.         0.31015679 0.         0.31015679 0.         0.
  0.         0.31015679 0.31015679 0.         0.31015679 0.
  0.         0.31015679 0.         0.31015679 0.         0.
  0.         0.         0.         0.31015679 0.         0.
  0.36636719 0.         0.         0.         0.         0.31015679
  0.        ]
 [0.         0.         0.25882751 0.         0.25882751 0.
  0.25882751 0.         0.         0.25882751 0.         0.25882751
  0.         0.         0.25882751 0.         0.         0.
  0.51765502 0.         0.         0.         0.         0.25882751
  0.1528677  0.19684499 0.25882751 0.         0.25882751 0.
  0.25882751]]

Process finished with exit code 0
  • 大家看到这么多的数据可能会有些头晕眼花,其实这个也是有规律可行的。
  • 第一段文本数字化后得到的数据就是这个二维数组重的第一列。观察第一列我们可以看到一段在第一段文本出现过,同时它的重要性0.31738473;第二个一种没有出现,所以对于本文的重要性为0
  • 由于我们测试的文本单词数较少,所以很多词语的重要性值是相同的。

总结

欢迎大家订阅我的博客,希望大家可以学到更多的知识。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值