各位同学好,今天和大家介绍一下python机器学习中的特征工程。在将数据放入模型之前,需要对数据的一些特征进行特征抽取,方法有:
由于模型训练函数.fit() 函数只能传入数值类型的特征值,因此我们需要将特征值中的文本类型转换成数值类型。
字典特征提取方法在前面的章节已经讲述过,见下文2.3小节:【机器学习入门】(5) 决策树算法实战:sklearn实现决策树,实例应用(沉船幸存者预测)附python完整代码及数据集
这里再简单复习一下。
首先我们定义一个由字典组成的列表,使用 vect 接收字典向量化方法,注意:传入字典向量化方法的变量必须是一个由字典组成的列表,特征提取完成之后,返回sparse矩阵,通过.toarray()函数将sparse矩阵转化成普通列表,便于观察。获取的特征名对应sparse矩阵转换后的列表的列名。
#(1)字典特征抽取
# 定义一个由字典组成的列表
fruits = [{'fruits':'苹果','price':5},{'fruits':'橘子','price':3.9},{'fruits':'菠萝','price':8.5}]
# 导入字典特征抽取方法
from sklearn.feature_extraction import DictVectorizer
# 接收字典向量化方法
vect = DictVectorizer()
# 将列表传入特征抽取方法,返回sparse矩阵,sparse矩阵只会记录传入的数据中,非0位置的值
result = vect.fit_transform(fruits)
# 将sparse矩阵转换成数组形式,便于观察
result_arr = result.toarray()
# 获取sparse矩阵的每一列的特征名
result_names = vect.get_feature_names()
观察sparse变成的数组,第0列表示橘子,第1列表示苹果,第2列表示菠萝,result_arr的第0行表示我们定义的fruits列表的第0行。我们定义的列表的第0行是苹果,因此只有在sparse数组中的第1列计数为1。而price列是三个字典共有的key,因此都有值。
将字符串类型转换成sparse数值矩阵之后我们就能将其放入模型进行训练。
文本特征抽取应用于很多方面,比如文档分类、垃圾邮件分类、新闻分类。文本分类是通过词是否存在、以及词的概率(重要性)来表示。
通过记录字符串中某些单词出现的个数。
对单词的文档抽取方法之前已经介绍过,见下文第1.4小节:【机器学习入门】(2) 朴素贝叶斯算法:原理、实例应用(文档分类预测)附python完整代码及数据集_小狄同学的博客-CSDN博客
这里再简单复习一下。
首先,我们定义一个由两个字符串组成的列表,使用vect接收文本抽取方法,将字符串列表传入特征提取函数,得到一个sparse矩阵。
## 对英文操作
# 定义一个字符串
string = ['life is short, i need python, life is short','life is too long, i do not need python']
# 导入文本抽取方法
from sklearn.feature_extraction.text import CountVectorizer
# 接收方法
vect = CountVectorizer()
# 记录字符串中单词出现的次数,返回sparse矩阵
result = vect.fit_transform(string)
# 将sparse矩阵转换成数组形式,便于观察
result_arr = result.toarray()
# 获取sparse矩阵的每一列的特征名
result_names = vect.get_feature_names()
sparse矩阵转换后的result_arr列表的每一行分别代表两个字符串,列代表res_names中的特征值名称。矩阵第一列为'do'出现的次数,第一行代表第一个字符串,第二行代表第二个字符串。'do'在第一个字符串中没有出现,在第二个字符串中出现了1次。'is'在第一个字符串中出现了2次,在第二个字符串中出现了1次。
如果想统计中文中某些词出现的次数,首先要对中文进行分词,这时需要第三方库 jieba分词
通过 pip install jieba 安装,通过 import jieba 导入该库,再自定义三个中文文档。
# 安装jieba库
pip install jieba
# 导入jieba库
import jieba
# 自定义中文句子
word1 = '党的十九届六中全会是在重要历史关头召开的一次具有重大历史意义的会议。'
word2 = '民主不是装饰品,不是用来做摆设的,而是要用来解决人民需要解决的问题的。'
word3 = '坚持党的领导,坚持人民至上,坚持理论创新,坚持独立自主,坚持中国道路。'
在文档特征抽取时,中文的标点符号对于文档分类没有意义,我们需要把标点符号删除,我们创建一个删除中文标点的函数。
# 删除所有的中文标点符号
punct = set(u'''!·~?。,:“”‘’@#¥%……&*()《》、|''')
fileterpunt = lambda s:''.join(filter(lambda x: x not in punct,s))
然后,以word1操作为例,使用jieba库的切分方法 jieba.cut() 对删除标点后的文档进行切分,返回Token对象,将其转换成列表list(),便于观察。分完词以后在每个词后面加一个空格,再使用 ' '.join() 方法将字词重新组合起来,形成一个新的字符串,这样文本提取函数才能识别。
# 对中文word1去除标点并进行切分,返回Token对象
con1 = jieba.cut(fileterpunt(word1))
# 转换成列表,便于观察
con1_list = list(con1)
# 分完词以后,需要将每个词后面加一个空格,再拼接成字符串
con1 = ' '.join(con1_list)
到此,我们就完成了对中文字词的切分,可以用来进行文本特征提取。以上是对word1的操作,word2和3的操作同理如下。
# 同理对word2和word3操作
con2 = ' '.join(jieba.cut(fileterpunt(word2)))
con3 = ' '.join(jieba.cut(fileterpunt(word3)))
接下来的文本提取方法和处理英文类似,我们使用 CountVectorizer() 方法对中文进行文本提取,返回 sparse 矩阵,如下。
# 文本提取
vect_chinese = CountVectorizer()
# 传入剪切后的中文,返回sparse矩阵
result = vect_chinese.fit_transform([con1,con2,con3])
# 转换成列表
result_list = result.toarray()
# 显示每一列的特征名
result_names = vect_chinese.get_feature_names()
在三个文档中,'一次' 这个词在第一个字符串中出现了1次,在第二和三个字符串中出现了0次。
方法介绍: tf-idf 文本抽取是一种用于信息检索与文本挖掘的常用加权技术。td-idf 是一种统计方法,用以评估一个字词对于一个文件集或一个语料库中的其中一份文件的重要程度。
字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着他在语言库中出现的频数成反比下降。
比如,‘创新’ 这个词在一篇文章中出现很多次,在其他文章中出现的比较少,说明‘创新’这个词对于文章分类很重要。而 ‘我们’‘你好’ 等词在一篇文章中出现了很多次,但在别的文件中也出现了很多次,该词的重要程度也不高。
计算方法: (一篇文章的关键词次数/一篇文章总字数) / log(文章总篇数/出现过关键词的文章数)
假设现在总共有1000篇文章,‘民主’这个词在500篇文章中出现了,并且A文章中总共有800个词,‘民主’出现了12次,那么 ‘民主’对文章A的tf-idf 的值为:(12/800)/log(1000/500)。值越大说明越重要。
首先自定义三个文档,以中文文档为例,先删除无意义的中文标点符号,再进行字词切分 jieba.cut(),再将每个字词后面加上一个空格,把字词拼接再一起 ' '.join(),重新组合成字符串。
# 自定义文档
document1 = '深刻总结我们党一百年来团结带领人民从胜利走向胜利的伟大历程,教育引导全党深刻认识红色政权来之不易、新中国来之不易、中国特色社会主义来之不易,增强我们继续前进的勇气和力量;'
document2 = '深刻总结我们党一百年来从小到大、从弱到强的成长历程,教育引导全党深刻认识加强党的政治建设的重要性,增强全党团结统一的自觉性和坚定性;'
document3 = '深刻总结我们党一百年来加强自身建设、推进自我革命的伟大实践,教育引导全党深刻认识全面从严治党的重要性和必要性,确保我们党始终成为中国特色社会主义事业的坚强领导核心。'
# 由于是中文,所有需要进行文档分词操作
import jieba
# 除去标点符号的函数
punct = set(u'''!·~?。,:“”‘’@#¥%……&*()《》、|''')
fileterpunt = lambda s:''.join(filter(lambda x: x not in punct,s))
# 文档分割后每个关键词后面加空格,然后拼接在一起,重新组成一个字符串
document1 = ' '.join(jieba.cut(fileterpunt(document1)))
document2 = ' '.join(jieba.cut(fileterpunt(document2)))
document3 = ' '.join(jieba.cut(fileterpunt(document3)))
处理完成之后的中文文档如下:
通过sklearn库使用 tfidf 方法进行文档特征提取,接收tf-idf方法 TfidfVectorizer() ,将文档组成的列表输入到特征抽取函数中,返回sparse数值矩阵。
from sklearn.feature_extraction.text import TfidfVectorizer
# 接收tf-idf方法
tfidf = TfidfVectorizer()
# 输入文档,提取特征值并转换,返回sparse矩阵
result = tfidf.fit_transform([document1,document2,document3])
# 转换成列表便于观察
result_array = result.toarray()
# 显示特征名
result_names = tfidf.get_feature_names()
结果可见,'事业'这个词在第三个文档中的itfidf值为0.21,即重要度为0.21,在第一和二个文档中的if-idf值为0,没出现。
在我之前写的朴素贝叶斯文档分类案例中使用的是文档抽取方法,也可以使用tfidf方法,感兴趣的可以试一下。
python完整代码:
# 特征抽取
# 将数据放入模型之前,需要对数据的一些特征进行特征抽取
#(1)字典特征抽取
# .fit() 函数只能传入数值类型的特征值,因此我们需要将特征值中的文本类型转换成数值类型
# 定义一个由字典组成的列表
fruits = [{'fruits':'苹果','price':5},{'fruits':'橘子','price':3.9},{'fruits':'菠萝','price':8.5}]
# 导入字典特征抽取方法
from sklearn.feature_extraction import DictVectorizer
# 接收字典向量化方法
vect = DictVectorizer()
# 将列表传入特征抽取方法,返回sparse矩阵,sparse矩阵只会记录传入的数据中,非0位置的值
result = vect.fit_transform(fruits)
# 将sparse矩阵转换成数组形式,便于观察
result_arr = result.toarray()
# 获取sparse矩阵的每一列的特征名
result_names = vect.get_feature_names()
# 观察sparse变成的数组,第一列表示橘子,第一行表示我们定义的列表的第一行
# 我们定义的列表的第一行是苹果,因此只有在第二列计数为1,橘子列和菠萝列计数为0
# price列是三个字典共有的key,因此都有值
# 将字符串类型转换成sparse数值矩阵之后我们就能将其放入模型进行训练
#(2)文本特征抽取
# 文本特征抽取应用于很多方面,比如文档分类、垃圾邮件分类、新闻分类。
# 文本分类是通过词是否存在、以及词的概率(重要性)来表示。
# ==1== 文档中词出现的个数
# 记录字符串中某些单词出现的个数
## 对英文操作
# 定义一个字符串
string = ['life is short, i need python, life is short','life is too long, i do not need python']
# 导入文本抽取方法
from sklearn.feature_extraction.text import CountVectorizer
# 接收方法
vect = CountVectorizer()
# 记录字符串中单词出现的次数,返回sparse矩阵
result = vect.fit_transform(string)
# 将sparse矩阵转换成数组形式,便于观察
result_arr = result.toarray()
# 获取sparse矩阵的每一列的特征名
result_names = vect.get_feature_names()
# 矩阵第一列为do,第一行代表第一个字符串,第二行代表第二个字符串。
# 表示do在第一个字符串中没有出现,在第二个字符串中出现了1次
## 对中文操作
# 如果想统计中文中某些词出现的次数,首先要对中文进行分词,这是需要第三方库jieba分词,通过 pip install jieba 安装
# 导入jieba库
import jieba
# 自定义中文句子
word1 = '党的十九届六中全会是在重要历史关头召开的一次具有重大历史意义的会议。'
word2 = '民主不是装饰品,不是用来做摆设的,而是要用来解决人民需要解决的问题的。'
word3 = '坚持党的领导,坚持人民至上,坚持理论创新,坚持独立自主,坚持中国道路。'
# 文本抽取时,标点符号对于预测没有意义,可以把标点删除
# 删除所有的中文标点符号
punct = set(u'''!·~?。,:“”‘’@#¥%……&*()《》、|''')
fileterpunt = lambda s:''.join(filter(lambda x: x not in punct,s))
# 对中文word1去除标点并进行切分,返回Token对象
con1 = jieba.cut(fileterpunt(word1))
# 转换成列表,便于观察
con1_list = list(con1)
# 分完词以后,需要将每个词后面加一个空格,再拼接成字符串,这样文本提取才能识别出来
con1 = ' '.join(con1_list)
# 同理对word2和word3操作
con2 = ' '.join(jieba.cut(fileterpunt(word2)))
con3 = ' '.join(jieba.cut(fileterpunt(word3)))
# 文本提取
vect_chinese = CountVectorizer()
# 传入剪切后的中文,返回sparse矩阵
result = vect_chinese.fit_transform([con1,con2,con3])
# 转换成列表
result_list = result.toarray()
# 显示每一列的特征名
result_names = vect_chinese.get_feature_names()
# ==2== tf-idf文本抽取
# 自定义文档
document1 = '深刻总结我们党一百年来团结带领人民从胜利走向胜利的伟大历程,教育引导全党深刻认识红色政权来之不易、新中国来之不易、中国特色社会主义来之不易,增强我们继续前进的勇气和力量;'
document2 = '深刻总结我们党一百年来从小到大、从弱到强的成长历程,教育引导全党深刻认识加强党的政治建设的重要性,增强全党团结统一的自觉性和坚定性;'
document3 = '深刻总结我们党一百年来加强自身建设、推进自我革命的伟大实践,教育引导全党深刻认识全面从严治党的重要性和必要性,确保我们党始终成为中国特色社会主义事业的坚强领导核心。'
# 由于是中文,所有需要进行文档分词操作
import jieba
# 除去标点符号
punct = set(u'''!·~?。,:“”‘’@#¥%……&*()《》、|''')
fileterpunt = lambda s:''.join(filter(lambda x: x not in punct,s))
# 文档分割后每个关键词后面加空格,然后拼接在一起,重新组成一个字符串
document1 = ' '.join(jieba.cut(fileterpunt(document1)))
document2 = ' '.join(jieba.cut(fileterpunt(document2)))
document3 = ' '.join(jieba.cut(fileterpunt(document3)))
# 导入sklearn库的tfidf方法
from sklearn.feature_extraction.text import TfidfVectorizer
# 接收tf-idf方法
tfidf = TfidfVectorizer()
# 输入文档,提取特征值并转换,返回sparse矩阵
result = tfidf.fit_transform([document1,document2,document3])
# 转换成列表便于观察
result_array = result.toarray()
# 显示特征名
result_names = tfidf.get_feature_names()