CountVectorizer max_features如何处理具有相同频率的ngrams?

时间:2018-03-26 12:05:37

标签: python machine-learning scikit-learn nlp

我对CountVectorizer和TfidfVectorizer有疑问。

我不清楚如何在max_features中以相同的频率选择ngrams。如果我们在边界上具有相同频率的语料库中说max_features = 10000和100 ngrams,那么CountVectorizer如何分离ngram在特征中的含义以及哪些不是?玩具的例子,我们有一个包含八个独特单词的语料库。单词“jeans”和“cat”具有相同的freq 1.我们采用max_features = 7。为什么“猫”出现在功能和“牛仔裤”不是,但反之亦然?

data = ['gpu processor cpu performance',
        'gpu performance ram computer computer',
        'cpu computer ram processor jeans processor cat']

cv = CountVectorizer(ngram_range=(1, 1), max_features=7)
cv_fit = cv.fit_transform(data).toarray()
cv.vocabulary_

out:
{'cat': 0,
 'computer': 1,
 'cpu': 2,
 'gpu': 3,
 'performance': 4,
 'processor': 5,
 'ram': 6}

2 个答案:

答案 0 :(得分:3)

这是link to the relevant source code _limit_features辅助方法:

    # Calculate a mask based on document frequencies
    dfs = _document_frequency(X)
    tfs = np.asarray(X.sum(axis=0)).ravel()
    mask = np.ones(len(dfs), dtype=bool)
    if high is not None:
        mask &= dfs <= high
    if low is not None:
        mask &= dfs >= low
    if limit is not None and mask.sum() > limit:
        mask_inds = (-tfs[mask]).argsort()[:limit]
        new_mask = np.zeros(len(dfs), dtype=bool)
        new_mask[np.where(mask)[0][mask_inds]] = True
        mask = new_mask

    new_indices = np.cumsum(mask) - 1  # maps old indices to new
    removed_terms = set()
    for term, old_index in list(six.iteritems(vocabulary)):
        if mask[old_index]:
            vocabulary[term] = new_indices[old_index]
        else:
            del vocabulary[term]
            removed_terms.add(term)
    kept_indices = np.where(mask)[0]

注意,limit是此辅助方法的参数,它传递的值为self.max_features。因此,正如您所看到的,计算了一系列术语频率:

tfs = np.asarray(X.sum(axis=0)).ravel()

代码本质上是基于文档频率值构建一个布尔掩码(由max_dfmin_df值控制)。然后,要仅将掩码限制为高于limit的值,它会:

mask_inds = (-tfs[mask]).argsort()[:limit]

本质上返回使用limit切片切成[:limit]长度的term-frequency数组的排序索引。由于.argsort默认使用快速排序算法,因此排序不稳定,因此,我相信您无法对保留哪些术语做出很多保证频率相等。无论快速排序发生在什么地方。如果使用了稳定的排序算法(在这种情况下,唯一的一种是合并排序),那么从the vocabulary is first sorted before the _limit_features helper function is called开始:

    if not self.fixed_vocabulary_:
        X = self._sort_features(X, vocabulary)

        n_doc = X.shape[0]
        max_doc_count = (max_df
                         if isinstance(max_df, numbers.Integral)
                         else max_df * n_doc)
        min_doc_count = (min_df
                         if isinstance(min_df, numbers.Integral)
                         else min_df * n_doc)
        if max_doc_count < min_doc_count:
            raise ValueError(
                "max_df corresponds to < documents than min_df")
        X, self.stop_words_ = self._limit_features(X, vocabulary,
                                                   max_doc_count,
                                                   min_doc_count,
                                                   max_features)

因此,词汇表将按字典顺序排序。因此,如果假设argsort使用稳定的算法,我相信我们可以说按字典顺序最高的术语会被保留,但是,由于它不稳定,我们无法做出这样的保证。

答案 1 :(得分:3)

CountVectorizer会切断术语频率,可能会使用普通排序来剪切max_features的项目。

  

max_features:int或None,默认=无如果不是None,则构建一个   只考虑按术语排序的最高max_features的词汇表   语料库中的频率。

我将数据从cat更改为zat,现在jeans将数据转到列表中。

>>> data = ['gpu processor cpu performance',
'gpu performance ram computer computer',
'cpu computer ram processor zat processor jeans']
>>> cv = CountVectorizer(ngram_range=(1, 1), max_features=7)
>>> cv_fit = cv.fit_transform(data).toarray()
>>> cv.vocabulary_
{u'ram': 6, u'jeans': 3, u'processor': 5, u'computer': 0, u'performance': 4, u'gpu': 2, u'cpu': 1}

本质上它取决于排序顺序。