这是一个 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_df 和min_df 值控制)构建一个布尔掩码。然后,要将掩码限制为仅高于limit 的值,它会:
mask_inds = (-tfs[mask]).argsort()[:limit]
这实际上返回了使用[:limit] 切片被切片为limit 长度的术语频率数组的排序索引。由于.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 使用的是稳定的算法,我相信我们可以说会保留字典顺序最高的词,但是,由于它不稳定,我们不能做出这样的保证。