sk-learn机器学习三
特征提取
从类别变量中提取特征
许多问题的解释变量是类别变量或者名义变量
类别变量:取值范围为一组固定值的变量
比如:一个预测职位薪水的应用可能会使用类似职位所在城市这样的类别变量,通常类别变量使用one-of-k编码算法或者one-hot编码算法进行编码,将使用一个二进制特征来表示解释变量的所有可能值
下面我们使用one-hot算法将类别变量编码
from sklearn.feature_extraction import DictVectorizer
onehot_encoder = DictVectorizer()
x = [
{'city':'beijing'},
{'city':'nanjing'},
{'city':'guangzhou'},
{'city':'shanghai'}
]
print(onehot_encoder.fit_transform(x).toarray())
# .toarray转换为数组表示
# 注意这里特征的顺序再结果向量中是随机的
输出结果:
[[1. 0. 0. 0.]
[0. 0. 1. 0.]
[0. 1. 0. 0.]
[0. 0. 0. 1.]]
特征标准化
我们可以使用prepocessing模块中的scale函数将数据集的任何轴进行标准化
from sklearn import preprocessing
import numpy as np
x = np.array[[……]]
print(preprocessing.scale(x))
从文本中提取特征
许多机器学习问题会使用文本,文本通常表示为自然语言。文本必须转换为一个向量,以此来将文本内容的某些方面进行编码
机器学习中最常用的两种文本表示形式的变体是词袋模型和词向量
词袋模型
这种表示法使用一个多重袋或袋对文本中出现的单词进行编码
词袋模型不会编码任何文本句法,同时忽略单词的顺序,忽略所有的语法
词袋模型可以有效地用于文档分类和检索
这里我们给出两个语句,使用CountVectorizer生成词包表示
from sklearn.feature_extraction.text import CountVectorizer
corpus = ['UNC played Duke in basketball',
'Duck lost the basketball game']
vect = CountVectorizer()
print(vect.fit_transform(corpus).todense())
print(vect.vocabulary_)
输出结果:
[[1 0 1 0 1 0 1 0 1]
[1 1 0 1 0 1 0 1 0]]
{'unc': 8, 'played': 6, 'duke': 2, 'in': 4,
'basketball': 0, 'duck': 1, 'lost': 5, 'the': 7, 'game': 3}
我们可以添加第三个文本并使用欧几里得距离这样的标准进行度量
语义最为相似的文档在向量空间中最为靠近
corpus.append('I ate a sandwich')
print(vect.fit_transform(corpus).todense())
print(vect.vocabulary_)
from sklearn.metrics.pairwise import euclidean_distances
x = vect.fit_transform(corpus).todense()
print(euclidean_distances(x[0], x[1]))
print(euclidean_distances(x[0], x[2]))
print(euclidean_distances(x[1], x[2]))
输出结果
[[0 1 1 0 1 0 1 0 0 1]
[0 1 1 1 0 1 0 0 1 0]
[1 0 0 0 0 0 0 1 0 0]]
{'unc': 9, 'played': 6, 'duke': 2, 'in': 4,
'basketball': 1, 'lost': 5, 'the': 8,
'game': 3, 'ate': 0, 'sandwich': 7}
[[2.44948974]]
[[2.64575131]]
[[2.64575131]]
是个单词,通过0, 1的编码表示在该文本中是否有出现过(1表示存在)
最后输出了三个距离,我们可以看到文本1和文本2的距离最近
可以认为他们的语义内容最为靠近
注意到如果我们的字典中包含成百上千的独特单词,那么表示文章的特征向量将包含成百上千的元素,其中许多元素都将为0。包含许多0元素的高维向量被称为稀疏向量
使用高维数据会给所有的机器学习任务带来一些问题,这些问题被称为
维度诅咒
所以我们应该减少文本特征的维度,下面介绍几种策略
降低特征空间维度的一种基本策略是将所有文本转换为小写——因为字母的大小写一般对单词的意思没有影响。可以看到,词包以及去除了所以偶来此单词顺序和语法的信息
停用词过滤
第二个策略是去掉语料库大部分文档中经常出现的单词,这些单词并称为
停用词,包括the a an 这样的限定词,还有do be will这样的助动词,on around beneath 这样的介词
我们通过stop_words关键词参数过滤停用词
vest = CountVectorizer(stop_words='english')
词干提取和词性还原
这是两种能进一步减少维度的策略
基本原理是将同一个单词的词尾变化形式和派生形式压缩成单个特征的策略
tf-idf 权重扩展包
一个单词在文档中出现的频率可以表明该文档与单词的相关程度。所以两个长文档中,一个单词在一个文档只出现1次,在另一个文档中出现了几百次,那么这两个文档讨论的问题可能完全不同,所以我们还可以创建编码单词频数的特征向量
corpus = ['the dog ate a sandwich, the wizard transfigured a sandwich, and i ate a sandwich']
test = CountVectorizer(stop_words='english')
freq = np.array(test.fit_transform(corpus).todense())[0]
print(freq)
for token, index in test.vocabulary_.items():
print(token,freq[index])
输出去掉停用词后每个词的频率:
[2 1 3 1 1]
dog 1
ate 2
sandwich 3
wizard 1
transfigured 1
但是这种比较需要假设所有文档都有相似的长度,许多单词也许在两个文档中出现的频数相同,但两个文档长度差距很大,那么这两个文档仍然会有很大差别
所以我们使用sklearn库中的TfdfTransformer类,通过将单词频数向量矩阵转换为一个标准化单词频数权重矩阵来缓和这个问题
那么我们可以这样编写代码:
from sklearn.feature_extraction.text import TfidfVectorizer
corpus = ['the dog ate a sandwich, the wizard transfigured a sandwich',
'and i ate a sandwich']
test1 = TfidfVectorizer(stop_words='english')
print(test1.fit_transform(corpus).todense())
# 通过比较tf-idf权重和真实单词频数,我们能看到语料库中常见单词,都已被惩罚
空间有效特征向量化与哈希技巧
前面的示例中,都有一个字典包含语料库中所有独特标记被用于将文档中的标记映射到特征向量元素。但是创建这个字典有两个缺点:首先我们得遍历两次语料库,其次字典必须存储在内存中,这对于大语料库来说是很昂贵的
为了解决这个问题,我们可以通过对边集使用哈希函数直接决定其在特征向量中的索引来避免创建这个字典,这个捷径叫做哈希技巧
from sklearn.feature_extraction.text import HashingVectorizer
corpus = ['the', 'ate', 'bacon', 'the', 'cat']
ve = HashingVectorizer(n_features=6) # n_features是一个可选关键字
print(ve.transform(corpus).todense())
但是它也有缺点:字典没有存储,所以产出的模型难以检查
词向量
一种减轻了一些词袋模型缺点的文本表示法
词袋模型使用一个标量表示一个标记,词向量使用一个向量
具体来说,词向量参数化的函数,接受一个来自一些语言的标记作为输入项,并产出一个向量。而这个函数本质上就是一个词向量矩阵参数化的查找表
词向量比较复杂,这里不详细讲解,有兴趣的同学可以自行查找哟!
从图像中提取特征
计算视觉是对处理和理解图像计算构建的研究和设计,我们这里简单的讲解计算视觉中用于机器学习图像表示的基本技巧
从像素强度中提取特征
一幅图像可以视为一个矩阵,其中每一个元素都表示一种颜色。一种图像表示的基本技巧时通过将矩阵的行拼接成一个向量来构造。OCR光学字符辨识时一个典型的机器学习问题。这里我们使用这种技巧创建基本特征表示,其可以于一个OCR应用中识别以字符分隔形式的手写数字
在sk-learn库中的digits数据集包括1700个0~9之间的手写数字的灰度图片。我们选取一张图片,通过把该图片的矩阵改造成一个64维的向量,为图片创建一个特征向量
from sklearn import datasets
digits = datasets.load_digits()
print(digits.images[0])
print(digits.images[0].reshape(-1, 64))
输出结果:
[[ 0. 0. 5. 13. 9. 1. 0. 0.]
[ 0. 0. 13. 15. 10. 15. 5. 0.]
[ 0. 3. 15. 2. 0. 11. 8. 0.]
[ 0. 4. 12. 0. 0. 8. 8. 0.]
[ 0. 5. 8. 0. 0. 9. 8. 0.]
[ 0. 4. 11. 0. 1. 12. 7. 0.]
[ 0. 2. 14. 5. 10. 12. 0. 0.]
[ 0. 0. 6. 13. 10. 0. 0. 0.]]
[[ 0. 0. 5. 13. 9. 1. 0. 0. 0. 0. 13. 15. 10. 15. 5. 0. 0. 3.
15. 2. 0. 11. 8. 0. 0. 4. 12. 0. 0. 8. 8. 0. 0. 5. 8. 0.
0. 9. 8. 0. 0. 4. 11. 0. 1. 12. 7. 0. 0. 2. 14. 5. 10. 12.
0. 0. 0. 0. 6. 13. 10. 0. 0. 0.]]
使用卷积神经网络激活项作为特征
卷积神经网络(CNN)已经成功运用到各式各样的任务中,包括计算视觉任务,如目标识别和语义切分
由于CNN大多用于深度学习,而sk-learn库并不适合深度学习,所以这里不再举例说明
等到学习tensorflow时再和大家分享吧!
都看到这里了还不点个赞嘛