为什么文本的特征提取未返回所有可能的特征名称?

use*_*115 2 python nlp feature-extraction scikit-learn pytorch

这是《 使用PyTorch进行自然语言处理》一书中的代码片段:

import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
import seaborn as sns

corpus = ['Time flies flies like an arrow.', 'Fruit flies like a banana.']
one_hot_vectorizer = CountVectorizer()
vocab = one_hot_vectorizer.get_feature_names()
Run Code Online (Sandbox Code Playgroud)

的值vocab

vocab = ['an', 'arrow', 'banana', 'flies', 'fruit', 'like', 'time']
Run Code Online (Sandbox Code Playgroud)

为什么'a'提取的要素名称中没有?如果自动将其排除为太普通的单词,出于同样的原因为什么不排除“ an”?如何也.get_feature_names()过滤其他单词?

alv*_*vas 7

很好的问题!虽然这不是一个pytorch问题,但sklearn一个=)

我鼓励首先浏览一下https://www.kaggle.com/alvations/basic-nlp-with-nltk,特别是。“ 使用sklearn进行矢量化 ”部分


TL; DR

如果我们使用CountVectorizer

from io import StringIO
from sklearn.feature_extraction.text import CountVectorizer

sent1 = "The quick brown fox jumps over the lazy brown dog."
sent2 = "Mr brown jumps over the lazy fox."

with StringIO('\n'.join([sent1, sent2])) as fin:
    # Create the vectorizer
    count_vect = CountVectorizer()
    count_vect.fit_transform(fin)

# We can check the vocabulary in our vectorizer
# It's a dictionary where the words are the keys and 
# The values are the IDs given to each word. 
print(count_vect.vocabulary_)
Run Code Online (Sandbox Code Playgroud)

[出]:

{'brown': 0,
 'dog': 1,
 'fox': 2,
 'jumps': 3,
 'lazy': 4,
 'mr': 5,
 'over': 6,
 'quick': 7,
 'the': 8}
Run Code Online (Sandbox Code Playgroud)

我们没有告诉矢量化器删除标点符号以及将符号化和小写字母删除,它们是如何做到的?

另外,词汇表中有,它是一个停用词,我们希望它消失……而且跳动不会受到阻碍或限制!

如果我们查看sklearn中CountVectorizer的文档,则会看到:

CountVectorizer(
    input=’content’, encoding=’utf-8’, 
    decode_error=’strict’, strip_accents=None, 
    lowercase=True, preprocessor=None, 
    tokenizer=None, stop_words=None, 
    token_pattern=’(?u)\b\w\w+\b’, ngram_range=(1, 1), 
    analyzer=’word’, max_df=1.0, min_df=1, 
    max_features=None, vocabulary=None, 
    binary=False, dtype=<class ‘numpy.int64’>)
Run Code Online (Sandbox Code Playgroud)

更具体地说:

分析器:字符串,{'word','char','char_wb'}或可调用

该功能部件应由单词还是字符n-gram组成。选项'char_wb'仅从单词边界内的文本创建字符n-gram;单词边缘的n-gram用空格填充。如果传递了Callable,它将用于从未经处理的原始输入中提取特征序列。

预处理器:可调用或无(默认)

覆盖预处理(字符串转换)阶段,同时保留标记化和n-gram生成步骤。

tokenizer:可调用或无(默认)

覆盖字符串标记化步骤,同时保留预处理和n-gram生成步骤。仅在分析器=='word'时适用。

stop_words:字符串{'english'},列表或无(默认值)

如果为“ english”,则使用内置的英语停用词列表。如果是列表,则假定该列表包含停用词,所有停用词将从结果标记中删除。仅在分析器=='word'时适用。如果为None,则不使用停用词。

小写:布尔值,默认为True

在标记化之前,将所有字符转换为小写。

但是,以http://shop.oreilly.com/product/0636920063445.do中的示例为例,这并不是造成该问题的停用词。

如果我们明确地使用英语禁用词https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/feature_extraction/stop_words.py

>>> from sklearn.feature_extraction.text import CountVectorizer
>>> one_hot_vectorizer = CountVectorizer(stop_words='english')

>>> one_hot_vectorizer.fit(corpus)
CountVectorizer(analyzer='word', binary=False, decode_error='strict',
        dtype=<class '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='english',
        strip_accents=None, token_pattern='(?u)\\b\\w\\w+\\b',
        tokenizer=None, vocabulary=None)

>>> one_hot_vectorizer.get_feature_names()
['arrow', 'banana', 'flies', 'fruit', 'like', 'time']
Run Code Online (Sandbox Code Playgroud)

那么,当stop_words参数保留为None时,到底发生了什么呢?

让我们尝试一个在输入中添加一些单字符单词的实验:

>>> corpus = ['Time flies flies like an arrow 1 2 3.', 'Fruit flies like a banana x y z.']

>>> one_hot_vectorizer = CountVectorizer()

>>> one_hot_vectorizer.fit(corpus)
CountVectorizer(analyzer='word', binary=False, decode_error='strict',
        dtype=<class '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)
>>> one_hot_vectorizer.get_feature_names()                                         
['an', 'arrow', 'banana', 'flies', 'fruit', 'like', 'time']
Run Code Online (Sandbox Code Playgroud)

他们都消失了!!!

现在,如果我们深入研究文档,https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/feature_extraction/text.py#L738

token_pattern:字符串正则表达式,表示什么构成“令牌”,仅在时使用analyzer == 'word'。默认的regexp选择标记包括2个或更多字母数字字符(标点符号被完全忽略,并始终被视为标记分隔符)。

啊哈,这就是为什么所有单个字符标记都将被删除的原因!

的默认模式CountVectorizertoken_pattern=r"(?u)\b\w\w+\b",要使其采用单个字符,您可以尝试:

>>> one_hot_vectorizer = CountVectorizer(token_pattern=r"(?u)\b\w+\b")           
>>> one_hot_vectorizer.fit(corpus)
CountVectorizer(analyzer='word', binary=False, decode_error='strict',
        dtype=<class '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+\\b', tokenizer=None,
        vocabulary=None)
>>> one_hot_vectorizer.get_feature_names()
['1', '2', '3', 'a', 'an', 'arrow', 'banana', 'flies', 'fruit', 'like', 'time', 'x', 'y', 'z']
Run Code Online (Sandbox Code Playgroud)