使用词袋表示的主要缺点之一就是完全舍弃了单词顺序。因此“its bad,not good at all”和“its good,not bad at all”这两个字符串的词袋表示完全相同,尽管它们的含义相反。幸运的是,使用词袋表示时有一种获取上下文的方法,就是不仅考虑单一词例的计数,而且还考虑相邻的两个或是哪个词例的计数。
两个词例被称为二元分词,三个词例被称为三元分词,更一般的词例序列被称为n元分词。我们可以通过改变CountVectorizer或TfidfVectorizer的ngram_range参数来改变作为特征的词例范围。ngram_range参数是一个元组,包含要考虑的词例序列的最小长度和最大长度。
下面是之前用过的数据上的一个实例:
print('bards_words:{}'.format(bards_words))
默认情况下,为每个长度为1且最大为1的词例序列创建一个特征——单个单词也被称为一元分词:
cv=CountVectorizer(ngram_range=(1,1)).fit(bards_words)
print('词表大小:{}'.format(len(cv.vocabulary_)))
print('词表:{}'.format(cv.get_feature_names_out()))
要想仅查看二元分词,可以将ngram_range设为(2,2)
cv=CountVectorizer(ngram_range=(2,2)).fit(bards_words)
print('词表大小:{}'.format(len(cv.vocabulary_)))
print('词表:{}'.format(cv.get_feature_names_out()))
使用更长的词例序列通常会得到更多的特征,也会得到更具体的特征。bards_words的两个短语中没有相同的二元分词:
print('Transform data(dende):\n{}'.format(cv.transform(bards_words).toarray()))
对于大多数应用来说,最小的词例数量应该是1,因为单个单词通常包含丰富的含义,在大多数情况下,添加二元分词会有帮助,添加更长的序列(一致到五元分词)也可能有帮助,但这会导致特征数量的大大增加,也可能导致过拟合,因为其中包含许多非常具体的特征。
原则上来说,二元分词的数量是一元分词数量的平方,三元分词的数量是一元分词数量的三次方,从而导致非常大的特征空间。
实践中,更高的n元分词在数据中的出现次数实际上更少。