- 目标
o 应用DictVectorizer实现对类别特征值进行数据化、离散化
o 应用Countvectorizer实现对文本特征值进行数值化
o 应用TfidVectorizer实现对文本特征值进行数值化
o 说出两种文本特征提取的方式区别 - 应用
o 无
文章目录
什么是特征提取?
文本类型–>数值
类型–>数值
2.3.1 特征提取
1. 将任意数据(如文本或者图像)转换为可用于机器学习的数学特征
注:特征值是为了计算机更好的去理解数据
- 字典特征提取(特征离散化)
- 文本特征提取
- 图像特征提取(深度学习将介绍)
2. 特征提取API
sklearn.feature_extraction
2.3.2 字典特征提取
作用:对字典数据进行特征值化
类别–> one-hot编码
sklearn.feature_extraction.DicVectorize(sparse=True,…)
vector 数学:向量 物理:矢量
矩阵: matrix 二维数组
向量: vector 一维数组
- DicVectorizer.fit_transform(X) X:字典或包含字典的迭代器 返回值:返回sparse矩阵
- DicVectorizer.inverse_transform(X) X:array数组或者sparse矩阵 返回值:转换之前数据格式
- DicVectorizer.get_feature_name() 返回类别名称
1. 应用
我们对以下数据进行特征提取:
[{'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.]]
2. 流程分析
- 实例化类DictVectorizer
- 调用fit_transform方法输入数据并转换(注意返回格式)
from sklearn.feature_extraction import DictVectorizer
data = [{'city':'北京','temperature':100},{'city':'上海','temperature':60},{'city':'深圳','temperature':30}]
# 实例化一个转换器类
transfer = DictVectorizer(sparse=False)
# 调用fit_transform()
data_new = transfer.fit_transform(data)
print("data_new:\n",data_new)
# 打印特征名字
print("特征名字:\n",transfer.get_feature_names)
因为当实例化DicVectorize时候,默认sparse=True,也就是没加上sparse=False参数的输出结果:
返回的名字
(0, 1) 1.0
(0, 3) 100.0
(1, 0) 1.0
(1, 3) 60.0
(2, 2) 1.0
(2, 3) 30.0
特征名字:
['city=上海', 'city=北京', 'city=深圳', 'temperature']
这个结果并不是我们想看见的,所以加上参数sparse=False,得到想要的结果:
[[ 0. 1. 0. 100.]
[ 1. 0. 0. 60.]
[ 0. 0. 1. 30.]]
特征名字:
['city=上海', 'city=北京', 'city=深圳', 'temperature']
对比:
(sparse=True)data_new中没有0值,数值表示的是(sparse=False)data_new中的非零值
稀疏矩阵:将非零值按位置表示出来–>节省内存–>提高加载效率
我们把这个处理数据的技巧叫做"one-hot"编码
转化为:
我们做的是为每个类别生成一个布尔列,这些列中只有一列可以为每个样本取值1。因此,术语一个热编码。
3. 总结
对于特征当中存在类别信息的我们会做one-hot编码处理
4. 应用场景
- pclass,sex 数据集当中类别特征比较多
- 将数据集的特征–>字典类型
- DictVectorizer转换
- 本身拿到的数据就是数据类型
2.3.3 文本特征提取
作用:对文本数据进行特征值化
特征:特征词(单词)
方法1: CountVectorizer
统计每个样本特征词出现的次数
- sklearn.feature_extraction.text.CountVectorizer(stop_words=[])
返回词频矩阵 - CountVectorizer.fit_transform(X) X:文本或者包含文本字符串的可迭代对象 返回值:返回sparse矩阵
- CountVectorizer.inverse_transform(X) X:array 数组或者sparse矩阵 返回值:转换之前数据格
- CountVectorizer.get_feature_names() 返回值:单词列表
- sklearn.feature_extraction.text.TfidfVectorizer
1. 应用
我们对一下数据进行特征提取
["life is short, I like like python",
"life is too longs,i dislike python"]
i 不计入其中,认为 i 对情感没有影响。
['dislike', 'is', 'life', 'like', 'longs', 'python', 'short', 'too']
[[0 1 1 2 0 1 1 0]
[1 1 1 0 1 1 0 1]]
说明统计的是样本特征词出现的个数,而不是是否存在。
2. 流程分析
from sklearn.feature_extraction.text import CountVectorizer
data= ["life is short, i like like python",
"life is too longs ,i dislike python"]
# 1.实例化一个转换器类
transfer = CountVectorizer()
# 2.调用fit_transform()
data_new = transfer.fit_transform(data)
print("data_new:\n",data_new)
print("打印特征名字:\n",transfer.get_feature_names())
data_new:
(0, 2) 1
(0, 1) 1
(0, 6) 1
(0, 3) 2
(0, 5) 1
(1, 2) 1
(1, 1) 1
(1, 5) 1
(1, 7) 1
(1, 4) 1
(1, 0) 1
打印特征名字:
['dislike', 'is', 'life', 'like', 'longs', 'python', 'short', 'too']
输出结果不是我们想要的,发现如果参考上面改变参数(sparse=False)也不行,这时候我们调用toarray函数后的输出结果如下
print("data_new:\n",data_new.toarray())
data_new:
[[0 1 1 2 0 1 1 0]
[1 1 1 0 1 1 0 1]]
打印特征名字:
['dislike', 'is', 'life', 'like', 'longs', 'python', 'short', 'too']
问题:如果将数据替换成中文呢?
"我爱北京天安门","天安门上太阳升"
from sklearn.feature_extraction.text import CountVectorizer
data = ["我爱北京天安门","天安门上太阳升"]
transfer = CountVectorizer()
data_new = transfer.fit_transform(data)
print("data_new:\n",data_new.toarray())
print("打印特征名字:\n",transfer.get_feature_names())
输出结果:
data_new:
[[0 1]
[1 0]]
打印特征名字:
['我爱北京天安门','天安门上太阳升']
为什么会出现这个情况?
因为语言特性,英文一个词一个空格,而中文是一个句子一个空格,如果我们也想让中文的时候和英文一样处理,需要把每个词中间都加个空格
修改data = ["我 爱 北京 天安门","天安门 上 太阳 升"]
后的输出结果:
data_new:
[[1 1 0]
[0 1 1]]
打印特征名字:
['北京', '天安门', '太阳']
同样不支持单个中文字
但这种分词也属于傻瓜式分词,可以用其他例如jieba分词,下面会学习
stop_words: 停用词(有停用词表)
目的:有些词不具备对最终分类有意义,例如 is、too……专门以列表的形式传递
实践操作:
from sklearn.feature_extraction.text import CountVectorizer
data= ["life is short, i like like python",
"life is too longs ,i dislike python"]
transfer = CountVectorizer(stop_words=["is","too"])
data_new = transfer.fit_transform(data)
print("data_new:\n",data_new.toarray())
print("打印特征名字:\n",transfer.get_feature_names())
输出结果:
data_new:
[[0 1 2 0 1 1]
[1 1 0 1 1 0]]
打印特征名字:
['dislike', 'life', 'like', 'longs', 'python', 'short']
3. jiaba分词
- jieba.cut()
o 返回词组组成的生成器
需要安装下jieba库
pip3 install jieba
字符串分词:
import jieba
text="我爱北京天安门"
a = " ".join(list(jieba.cut(text)))
print(a)
print(type(a))
输出:
我 爱 北京 天安门
<class 'str'>
4. 案例分析
对以下三句话进行特征值化
今天很残酷,明天更残酷,后天很美好,
但绝大部分是死在明天晚上,所以每个人不要放弃今天。
我们看到的从很远星系来的光是几百万年之前发出的,
这样当我们看到宇宙时,我们是在看它的过去。
如果只是一种方式了解某件事物,你就不会真正了解它。
了解事物真正含义的秘密去取决于如何将其与我们所了解的事物相联系。
- 分析
o 准备句子,利用jieba.cut进行分词
o 不是字符串是列表,迭代分词
o 实例化CountVectorizer
o 将分词结果变成字符串当作fit_transform的输入值
data = ["今天很残酷,明天更残酷,后天很美好,但绝大部分是死在明天晚上,所以每个人不要放弃今天。","我们看到的从很远星系来的光是几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。","如果只是一种方式了解某件事物,你就不会真正了解它。了解事物真正含义的秘密去取决于如何将其与我们所了解的事物相联系。"]
import jieba
data_new=[]
for sent in data:
data_new.append(" ".join(list(jieba.cut(sent))))
print(data_new)
['今天 很 残酷 , 明天 更 残酷 , 后天 很 美好 , 但 绝大部分 是 死 在 明天 晚上 , 所以 每个 人 不要 放弃 今天 。', '我们 看到 的 从 很 远 星系 来 的 光是 几百万年 之前 发出 的 , 这样 当 我们 看到 宇宙 时 , 我们 是 在 看 它 的 过去 。', '如果 只是 一种 方式 了解 某件事 物 , 你 就 不会 真正 了解 它 。 了解 事物 真正 含义 的 秘密 去 取决于 如何 将 其 与 我们 所 了解 的 事物 相 联系 。']
transfer = CountVectorizer()
data_final = transfer.fit_transform(data_new)
print("data_new:\n",data_final.toarray())
print("打印特征名字:\n",transfer.get_feature_names())
data_new:
[[0 0 1 0 0 0 2 0 0 0 0 0 1 0 0 0 0 0 1 1 0 2 0 1 0 2 1 0 0 0 1 1 0 0 0]
[0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 1 3 0 0 0 0 1 0 0 0 0 2 0 0 0 0 0 1 1]
[1 1 0 0 4 2 0 0 0 0 1 1 0 1 1 1 0 1 0 0 1 0 0 0 1 0 0 0 2 1 0 0 1 0 0]]
打印特征名字:
['一种', '不会', '不要', '之前', '了解', '事物', '今天', '光是', '几百万年', '发出', '取决于', '只是', '后天', '含义', '如何', '如果', '宇宙', '我们', '所以', '放弃', '方式', '明天', '星系', '晚上', '某件事', '残酷', '每个', '看到', '真正', '秘密', '绝大部分', '美好', '联系', '过去', '这样']
可以把指定的词语去掉不作为特征词
transfer = CountVectorizer(stop_words=["一种","所以"])
data_new:
[[0 1 0 0 0 2 0 0 0 0 0 1 0 0 0 0 0 1 0 2 0 1 0 2 1 0 0 0 1 1 0 0 0]
[0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 1 3 0 0 0 1 0 0 0 0 2 0 0 0 0 0 1 1]
[1 0 0 4 2 0 0 0 0 1 1 0 1 1 1 0 1 0 1 0 0 0 1 0 0 0 2 1 0 0 1 0 0]]
打印特征名字:
['不会', '不要', '之前', '了解', '事物', '今天', '光是', '几百万年', '发出', '取决于', '只是', '后天', '含义', '如何', '如果', '宇宙', '我们', '放弃', '方式', '明天', '星系', '晚上', '某件事', '残酷', '每个', '看到', '真正', '秘密', '绝大部分', '美好', '联系', '过去', '这样']
思考:对于我们用CountVectorizer最后实现文本分类有什么不好的地方?
一般我们认为数值上比较大的对样本的影响更大一点,用上面的例子,第三排第四个出现了4次,第五个出现了3次,也就是在第三个样本中出现了4次“了解”和3次“事物”,但是,“了解”、“事物”和诸如“你们”、“我们”、“他们”、“因为”、“所以”……这些词在很多文章中经常出现,会出现很大的数值,但是却不利于分类。
我们更想找到关键词:在某一个类别的文章中,出现的次数很多,但是在其他类型的文章中出现很少词
这就引入我们文本抽取的第二个方法
方法2:TfidfVectorizer
引入问题:有两篇文章,根据这两篇文章中出现的高频次,来判断该文章属于哪种类别
第一篇大量出现“车”、“共享”大概率是跟共享单车共享汽车有关的,这篇文章可能属于科技类或互联网类别的。
第二篇大量出现“银行”、“证券”、“经济”很可能是属于财经,金融类型的文章。
Tf-idf文本特征提取
- TF-IDF的主要思想是:如果某个词或短语在一篇文章中出现的概率高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。
- TF-IDF作用:用以评估一个字词对于一个文件集或一个语料库中的其中一份文件的重要程度
1. 公式
- 词频(term frequency,tf)指的是某一个给定的词语在该文件中出现的频率
- 逆向文档频率(inverse document frequency,idf)是一个词语普遍重要性的度量。某一特定词语的idf,可以由总文件数目除以包含该词语之文件的数目,再将得到的商以10为底取对数得到
t f i d f i , j = t f i , j × i d f i tfidf_{i,j} = tf_{i,j} \times idf_i tfidfi,j=tfi,j×idfi
举例,一个词叫“经济”,一个词叫“非常”,假设语料库有1000篇文章,有100篇有“非常”,10篇文章有“经济”
文章A(100个词):出现10次“经济”
tf = 10/100 = 0.1
idf = lg(1000/10) = 2
tf-idf=0.2
文章B(100个词):出现10次“非常”
tf = 10/100 = 0.1
idf = lg(1000/100) = 1
tf-idf = 0.1
最终得出结果可以理解为重要程度;通过数值上比较,“经济”的影响更大
2. API
- sklearn.feature_extraction.text.TfidVectorizer(stop_words=None,…)
- 返回次的权重矩阵
o TfidVectorizer.fit_transform(X)
X:文本或者包含文本字符串的可迭代对象
返回值:返回sparse矩阵
o TfidVectorizer.inverse_transform(X)
X:array数组或者sparse矩阵
返回值:转换之前数据格式
o TfidVectorizer.get_feature_names()
返回值:单词列表
3. 案例
data = ["今天很残酷,明天更残酷,后天很美好,但绝大部分是死在明天晚上,所以每个人不要放弃今天。","我们看到的从很远星系来的光是几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。","如果只是一种方式了解某件事物,你就不会真正了解它。了解事物真正含义的秘密去取决于如何将其与我们所了解的事物相联系。"]
data_new=[]
for sent in data:
data_new.append(" ".join(list(jieba.cut(sent))))
transfer = TfidfVectorizer(stop_words=["一种","所以"])
data_final = transfer.fit_transform(data_new)
print("data_new:\n",data_final.toarray())
print("打印特征名字:\n",transfer.get_feature_names())
data_new:
[[0. 0.22941573 0. 0. 0. 0.45883147
0. 0. 0. 0. 0. 0.22941573
0. 0. 0. 0. 0. 0.22941573
0. 0.45883147 0. 0.22941573 0. 0.45883147
0.22941573 0. 0. 0. 0.22941573 0.22941573
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.2410822 0. 0. 0.
0. 0.48216441 0. 0. 0. 0.
0. 0.2410822 0.2410822 ]
[0.17005819 0. 0. 0.68023277 0.34011638 0.
0. 0. 0. 0.17005819 0.17005819 0.
0.17005819 0.17005819 0.17005819 0. 0.12933364 0.
0.17005819 0. 0. 0. 0.17005819 0.
0. 0. 0.34011638 0.17005819 0. 0.
0.17005819 0. 0. ]]
打印特征名字:
['不会', '不要', '之前', '了解', '事物', '今天', '光是', '几百万年', '发出', '取决于', '只是', '后天', '含义', '如何', '如果', '宇宙', '我们', '放弃', '方式', '明天', '星系', '晚上', '某件事', '残酷', '每个', '看到', '真正', '秘密', '绝大部分', '美好', '联系', '过去', '这样']
Tf-idf的重要性
分类机器学习算法进行文章分类中前期数据处理方式