赞
踩
特征提取:http://scikit-learn.org/stable/modules/feature_extraction.html#feature-extraction
sklearn.feature_extraction模块可以用于从由诸如文本和图像的格式组成的数据集中提取机器学习算法支持的格式的特征。
注意:特征提取与特征选择非常不同:前者包括将任意数据(如文本或图像)转换为可用于机器学习的数值特征。 后者是应用于这些特征的机器学习技术。
4.2.1 从词典中加载特征
类DictVectorizer可用于将表示为标准Python dict对象列表的要素数组转换为scikit-learn估计量使用的NumPy / SciPy表示。虽然处理不是特别快,但是Python的dict具有使用方便,除了值的优势外还有稀疏(没有功能不需要存储)和存储特征名称。
DictVectorizer为分类(也称为标称,离散)特征实现所谓的one-of-K或“one-hot(独热)”编码。 分类特征是“属性值”对,其中值被限制到无序的离散可能性的列表(例如主题标识符,对象的类型,标签,名称...)。
在下面,“city”是分类属性,而“temperature”是传统的数字特征:
- measurements = [
- {'city': 'Dubai', 'temperature': 33.},
- {'city': 'London', 'temperature': 12.},
- {'city': 'San Fransisco', 'temperature': 18.},
- ]
-
- from sklearn.feature_extraction import DictVectorizer
- vec = DictVectorizer()
-
- vec.fit_transform(measurements).toarray()
- """
- 输出:
- array([[ 1., 0., 0., 33.],
- [ 0., 1., 0., 12.],
- [ 0., 0., 1., 18.]])
- """
- vec.get_feature_names()
- """
- 输出:
- ['city=Dubai', 'city=London', 'city=San Fransisco', 'temperature']
- """

DictVectorizer也是自然语言处理模型中的训练序列分类器的有用的表示变换,其通常通过提取围绕感兴趣的特定词的特征窗口来工作。例如,假设我们具有提取我们想要用作训练序列分类器(例如块)的互补标签的部分语音(PoS)标签的第一算法。 以下dict可以是在'猫坐在席子上'的句子“sat”周围提取的这样一个窗口。
- pos_window = [
- {
- 'word-2': 'the',
- 'pos-2': 'DT',
- 'word-1': 'cat',
- 'pos-1': 'NN',
- 'word+1': 'on',
- 'pos+1': 'PP',
- },
- # 在实际应用中,将提取许多这样的字典
- ]
该描述可以被矢量化为适于馈送到分类器中的稀疏二维矩阵(可能在被管道化到文本之后。用于归一化的TfidfTransformer):
- vec = DictVectorizer()
- pos_vectorized = vec.fit_transform(pos_window)
- pos_vectorized
- """
- 输出:
- <1x6 sparse matrix of type '<class 'numpy.float64'>'
- with 6 stored elements in Compressed Sparse Row format>
- """
- pos_vectorized.toarray()
- """
- 输出:
- array([[ 1., 1., 1., 1., 1., 1.]])
- """
- vec.get_feature_names()
- """
- 输出:
- ['pos+1=PP', 'pos-1=NN', 'pos-2=DT', 'word+1=on', 'word-1=cat', 'word-2=the']
- """

你可以想象,如果一个文档的每个单词提取这样的上下文,所得到的矩阵将非常宽(许多个独热特征),大多数的零需要花费很多的内存和时间。 为了使得到的数据结构能够适应内存,DictVectorizer类默认使用scipy.sparse矩阵,而不是numpy.ndarray。
4.2.2 特征散列
FeatureHasher类是一个高速,低内存的向量化器,使用一种称为特征散列或“散列法”的技术。代替在训练中构建训练中遇到的特征的哈希表,如向量化所做的那样,FeatureHasher的实例将哈希函数应用于特征以直接确定其在样本矩阵中的列索引。结果是以牺牲可检查性为代价,提高速度和减少存储器使用;哈希不记得输入要素的样子,没有inverse_transform方法。
由于散列函数可能导致(不相关的)特征之间的冲突,使用带符号的散列函数,并且散列值的符号确定存储在特征的输出矩阵中的值的符号。这样,冲突可能抵消而不是累积误差,并且任何输出特征的值的预期平均值为零。如果non_negative = True传递给构造函数,则采用绝对值。这撤消了一些冲突处理,但允许输出传递到估计器,如sklearn.naive_bayes.MultinomialNB或sklearn.feature_selection.chi2特征选择器,期望非负输入。
FeatureHasher接受映射(如Python的dict及其在collections模块中的变体),(feature,value)对或字符串,具体取决于构造函数参数input_type。 映射被视为(feature,value)对的列表,而单个字符串的隐式值为1,因此['feat1','feat2','feat3']被解释为[('feat1',1), 'feat2',1),('feat3',1)]。 如果单个特征在样本中出现多次,则相关值将被求和(因此('feat',2)和('feat',3.5)变为('feat',5.5))。 FeatureHasher的输出总是CSR格式中的scipy.sparse矩阵。
在文档分类中可以使用特征散列,但是与text.CountVectorizer不同,FeatureHasher不执行字分割或除Unicode到UTF-8编码之外的任何其他预处理; 对于组合的tokenizer / hasher,请参阅下面的散列技巧的大文本语料库的矢量化。
作为示例,考虑需要从(token,part_of_speech)对提取的特征的词级自然语言处理任务。 可以使用Python生成器函数来提取特征:
- def token_features(token, part_of_speech):
- if token.isdigit():
- yield "numeric"
- else:
- yield "token={}".format(token.lower())
- yield "token,pos={},{}".format(token, part_of_speech)
- if token[0].isupper():
- yield "uppercase_initial"
- if token.isupper():
- yield "all_uppercase"
- yield "pos={}".format(part_of_speech)
-
- #然后,要馈送到FeatureHasher.transform的raw_X可以使用以下来构造:
- raw_X = (token_features(tok, pos_tagger(tok)) for tok in corpus)
-
- #并且馈送到具有以下的散列:
- hasher = FeatureHasher(input_type='string')
- X = hasher.transform(raw_X)

得到一个scipy.sparse矩阵X.
注意使用生成器理解,其将惰性引入到特征提取中:令牌仅在来自哈希的请求时处理。
4.2.2.1 实现细节
FeatureHasher使用MurmurHash3的带符号32位变体。 结果(并且由于scipy.sparse的限制),支持的特征的最大数目当前是2 ^ {31} - 1。Weinberger等人的散列技巧的原始公式 使用两个单独的散列函数h和\ xi来分别确定特征的列索引和符号。 本实现在假定MurmurHash3的符号位与其它位无关的假设下工作。由于使用简单模数将散列函数转换为列索引,因此建议使用2的幂作为n_features参数; 否则这些要素将不会均匀地映射到列。
4.2.3文本特征提取
4.2.3.1 词袋表示(词袋模型)
文本分析是机器学习算法的主要应用领域。然而,原始数据,符号序列不能直接馈送到算法本身,因为大多数人期望具有固定大小的数字特征向量而不是具有可变长度的原始文本文档。为了解决这个问题,scikit-learn提供了用于从文本内容中提取数字特征的最常用方法的实用程序,即:
令牌(tokenizing)化字符串并为每个可能的令牌给出整数id,例如通过使用空格和标点符号作为令牌分隔符。//单词分割
计数(counting)每个文档中标记的出现次数。//单词计数
使用大多数样本/文档中出现的减少的重要性标记进行归一化和加权(normalizing and weighting)。//归一化/标准化
在该方案中,特征和样本定义如下:
每个单独的标记出现频率(标准化或不标准)被视为特征。
给定文档的所有令牌频率的向量被认为是多元样本。
因此,文档语料库可以由每个文档具有一行和在语料库中出现每个令牌(例如,词)的列的矩阵表示。
我们将向量化称为将文本文档的集合转换为数字特征向量的一般过程。这种具体的策略(标记化,计数和归一化)被称为词袋或“n-gram袋”表示。文档由单词出现来描述,同时完全忽略文档中的单词的相对位置信息。
4.2.3.2 稀疏性
由于大多数文档通常使用语料库中非常小的子集的单词,所以得到的矩阵将具有许多为零(通常大于99%)的特征值。例如,10,000个短文本文档(例如电子邮件)的集合将使用具有总共100,000个唯一字词的大小的词汇表,而每个文档将单独使用100到1000个唯一字词。为了能够在存储器中存储这样的矩阵,但是为了加速代数运算矩阵/向量,实现方式通常使用稀疏表示,例如在scipy.sparse包中可用的实现。
4.2.3.3。常用Vectorizer的使用
CountVectorizer在单个类中实现标记化和计数:
from sklearn.feature_extraction.text import CountVectorizer
此模型有很多参数,但是默认值是相当合理的(有关详细信息,请参阅参考文档):
- vectorizer = CountVectorizer(min_df=1)
- vectorizer
- 输出:CountVectorizer(analyzer=...'word', binary=False, decode_error=...'strict',
- dtype=<... 'numpy.int64'>, encoding=...'utf-8', input=...'content',
- lowercase=True, max_df=1.0, max_features=None, min_df=1,
- ngram_range=(1, 1), preprocessor=None, stop_words=None,
- strip_accents=None, token_pattern=...'(?u)\\b\\w\\w+\\b',
- tokenizer=None, vocabulary=None)
让我们使用它来标记和计数文本文档的简约语料库的单词出现:
- corpus = [
- 'This is the first document.',
- 'This is the second second document.',
- 'And the third one.',
- 'Is this the first document?',
- ]
- X = vectorizer.fit_transform(corpus)
- X
- 输出:<4x9 sparse matrix of type '<... 'numpy.int64'>'
- with 19 stored elements in Compressed Sparse ... format>
默认配置通过提取至少2个字母的单词对字符串进行标记化。 可以明确请求执行此步骤的特定函数:
- analyze = vectorizer.build_analyzer()
- analyze("This is a text document to analyze.") == (
- ... ['this', 'is', 'text', 'document', 'to', 'analyze'])
- 输出:True
在拟合期间由分析器发现的每个项被分配与所得矩阵中的列对应的唯一整数索引。 这些列的解释可以如下检索:
- vectorizer.get_feature_names() == (
- ['and', 'document', 'first', 'is', 'one',
- 'second', 'the', 'third', 'this'])
- 输出:True
-
- X.toarray()
- 输出:array([[0, 1, 1, 1, 0, 0, 1, 0, 1],
- [0, 1, 0, 1, 0, 2, 1, 0, 1],
- [1, 0, 0, 0, 1, 0, 1, 1, 0],
- [0, 1, 1, 1, 0, 0, 1, 0, 1]]...)
从特征名到列索引的逆转换映射存储在向量化器的vocabulary_属性中:
- vectorizer.vocabulary_.get('document')
- 输出:1
因此,在未来调用变换方法时,在训练语料库中看不到的词将被完全忽略:
- vectorizer.transform(['Something completely new.']).toarray()
- 输出:array([[0, 0, 0, 0, 0, 0, 0, 0, 0]]...)
注意,在先前的语料库中,第一个和最后一个文档具有完全相同的字,因此被编码在相等的向量中。 特别是我们失去的信息,最后一个文件是一个疑问形式。 为了保留一些本地排序信息,我们可以提取除了1克(单个词)之外的2克词:
- bigram_vectorizer = CountVectorizer(ngram_range=(1, 2),token_pattern=r'\b\w+\b', min_df=1)
- analyze = bigram_vectorizer.build_analyzer()
- analyze('Bi-grams are cool!') == (['bi', 'grams', 'are', 'cool', 'bi grams', 'grams are', 'are cool'])
- 输出:True
因此,由该向量化器提取的词汇更大,并且现在可以解决以局部定位模式编码的模糊性:
- X_2 = bigram_vectorizer.fit_transform(corpus).toarray()
- X_2
- 输出:array([[0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0],
- [0, 0, 1, 0, 0, 1, 1, 0, 0, 2, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0],
- [1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0],
- [0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1]]...)
特别是,“这是”的疑问形式只出现在最后一份文件中:
- feature_index = bigram_vectorizer.vocabulary_.get('is this')
- X_2[:, feature_index]
- 输出:array([0, 0, 0, 1]...)
Tf表示术语频率,而tf-idf表示术语 - 频率乘以逆文档频率:
使用TfidfTransformer的默认设置,TfidfTransformer(norm ='l2',use_idf = True,smooth_idf = True,sublinear_tf = False)术语频率,术语在给定文档中出现的次数乘以idf分量, 其计算为
,
其中n_d是文档的总数,并且\ text {df}(d,t)是包含项t的文档的数目。 然后通过欧几里得范数标准化所得的tf-idf载体:
.
这最初是为信息检索开发的术语加权方案(作为搜索引擎结果的排名函数),其也已经在文档分类和聚类中被良好使用。
以下部分包含进一步的说明和示例,说明如何精确计算tf-idfs,以及如何在scikit-learn的TfidfTransformer和TfidfVectorizer中计算的tf-idfs与标准教科书符号略有不同,定义为:
在TfidfTransformer和TfidfVectorizer中,smooth_idf = False,“1”计数被添加到idf而不是idf的分母:
这个规范化由TfidfTransformer类实现:
- >>> from sklearn.feature_extraction.text import TfidfTransformer
- >>> transformer = TfidfTransformer(smooth_idf=False)
- >>> transformer
- TfidfTransformer(norm=...'l2', smooth_idf=False, sublinear_tf=False,
- use_idf=True)
- >>> counts = [[3, 0, 1],
- ... [2, 0, 0],
- ... [3, 0, 0],
- ... [4, 0, 0],
- ... [3, 2, 0],
- ... [3, 0, 2]]
- ...
- >>> tfidf = transformer.fit_transform(counts)
- >>> tfidf
- <6x3 sparse matrix of type '<... 'numpy.float64'>'
- with 9 stored elements in Compressed Sparse ... format>
-
- >>> tfidf.toarray()
- array([[ 0.81940995, 0. , 0.57320793],
- [ 1. , 0. , 0. ],
- [ 1. , 0. , 0. ],
- [ 1. , 0. , 0. ],
- [ 0.47330339, 0.88089948, 0. ],
- [ 0.58149261, 0. , 0.81355169]])

例如,我们可以在计数数组中计算第一个文档中的第一项的tf-idf,如下所示:
现在,如果我们对文档中的剩余2项重复这个计算,我们得到:
raw tf-idfs的向量:
然后,应用欧几里德(L2)范数,我们获得以下文档1的tf-idfs:
此外,默认参数smooth_idf = True为分子和分母添加“1”,就好像看到一个额外的文档包含集合中的每个术语一次,这样可以防止零分割:
使用该修改,文档1中的第三项的tf-idf改变为1.8473:
L2归一化的tf-idf变为
- >>> transformer = TfidfTransformer()
- >>> transformer.fit_transform(counts).toarray()
- array([[ 0.85151335, 0. , 0.52433293],
- [ 1. , 0. , 0. ],
- [ 1. , 0. , 0. ],
- [ 1. , 0. , 0. ],
- [ 0.55422893, 0.83236428, 0. ],
- [ 0.63035731, 0. , 0.77630514]])
由拟合方法调用计算的每个要素的权重存储在模型属性中:
- >>> transformer.idf_
- array([ 1. ..., 2.25..., 1.84...])
由于tf-idf通常用于文本特性,因此还有另一个类TfidfVectorizer将单个模型中的CountVectorizer和TfidfTransformer的所有选项组合在一起:
- >>> from sklearn.feature_extraction.text import TfidfVectorizer
- >>> vectorizer = TfidfVectorizer(min_df=1)
- >>> vectorizer.fit_transform(corpus)
- ...
- <4x9 sparse matrix of type '<... 'numpy.float64'>'
- with 19 stored elements in Compressed Sparse ... format>
4.2.3.5 解码文本文件
文本由字符组成,但文件由字节组成。 这些字节表示根据某种编码的字符。 要在Python中使用文本文件,它们的字节必须解码为一个称为Unicode的字符集。 常见的编码是ASCII,Latin-1(西欧),KOI8-R(俄罗斯)和通用编码UTF-8和UTF-16。 许多其他存在。
- >>> import chardet
- >>> text1 = b"Sei mir gegr\xc3\xbc\xc3\x9ft mein Sauerkraut"
- >>> text2 = b"holdselig sind deine Ger\xfcche"
- >>> text3 = b"\xff\xfeA\x00u\x00f\x00 \x00F\x00l\x00\xfc\x00g\x00e\x00l\x00n\x00 \x00d\x00e\x00s\x00 \x00G\x00e\x00s\x00a\x00n\x00g\x00e\x00s\x00,\x00 \x00H\x00e\x00r\x00z\x00l\x00i\x00e\x00b\x00c\x00h\x00e\x00n\x00,\x00 \x00t\x00r\x00a\x00g\x00 \x00i\x00c\x00h\x00 \x00d\x00i\x00c\x00h\x00 \x00f\x00o\x00r\x00t\x00"
- >>> decoded = [x.decode(chardet.detect(x)['encoding'])
- ... for x in (text1, text2, text3)]
- >>> v = CountVectorizer().fit(decoded).vocabulary_
- >>> for term in v: print(v)
4.2.3.7 词袋表示的限制
4.2.4 图像特征提取
4.2.4.1 补丁提取
extract_patches_2d函数从存储为二维阵列的图像或沿着第三轴的具有颜色信息的三维提取片段。 要从所有其修补程序重建图像,请使用reconstruct_from_patches_2d。 例如,让使用生成具有3个颜色通道的4×4像素图片(例如,以RGB格式):
>>> import numpy as np >>> from sklearn.feature_extraction import image >>> one_image = np.arange(4 * 4 * 3).reshape((4, 4, 3)) >>> one_image[:, :, 0] # R channel of a fake RGB picture array([[ 0, 3, 6, 9], [12, 15, 18, 21], [24, 27, 30, 33], [36, 39, 42, 45]]) >>> patches = image.extract_patches_2d(one_image, (2, 2), max_patches=2, ... random_state=0) >>> patches.shape (2, 2, 2, 3) >>> patches[:, :, :, 0] array([[[ 0, 3], [12, 15]], [[15, 18], [27, 30]]]) >>> patches = image.extract_patches_2d(one_image, (2, 2)) >>> patches.shape (9, 2, 2, 3) >>> patches[4, :, :, 0] array([[15, 18], [27, 30]])让我们现在尝试通过在重叠区域上求平均来从补片重建原始图像:
>>> reconstructed = image.reconstruct_from_patches_2d(patches, (4, 4, 3)) >>> np.testing.assert_array_equal(one_image, reconstructed)补丁提取器类的工作方式与extract_patches_2d相同,只是它支持多个图像作为输入。 它被实现为一个估计器,因此它可以在管道中使用。 看到:
>>> five_images = np.arange(5 * 4 * 4 * 3).reshape(5, 4, 4, 3) >>> patches = image.PatchExtractor((2, 2)).transform(five_images) >>> patches.shape (45, 2, 2, 3)4.2.4.2 图像的连接图
为此,估计器使用“连通性”矩阵,给出哪些样本被连接。
函数img_to_graph从2D或3D图像返回这样的矩阵。 类似地,grid_to_graph为给定这些图像的形状的图像构建连接矩阵。
这些矩阵可用于在使用连通性信息(例如Ward聚类(Hierarchical clustering))的估计器中强加连接性,但也建立预先计算的内核或相似性矩阵。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。