Keras Tokenizer 的 num_words 起不到限制词表大小的作用?
问题复现:
from keras.preprocessing.text import Tokenizer
tokenizer = Tokenizer(num_words=5)
text = ["今天 武汉 下 雨 了", "我 今天 上课", "我 明天 不 上课", "武汉 明天 不 下 雨"]
tokenizer.fit_on_texts(text)
word_index = tokenizer.word_index
num_words参数在官网文档中的解释如下:
num_words: the maximum number of words to keep, based on word frequency. Only the most common
num_words-1
words will be kept.
查看 word_index :
{'今天': 1, '武汉': 2, '下': 3, '雨': 4, '我': 5, '上课': 6, '明天': 7, '不': 8, '了': 9}
num_words
指定为5,按理说,词汇表中应该只有4个词。为什么word_index中有全部的词汇?
问题解释:
测试代码:
tokenizer.texts_to_sequences(['今天 武汉 下 雨 我 上课 明天 不 了'])
对应输出:
[[1, 2, 3, 4]]
可见,只有今天
武汉
下
雨
这四个词被映射了。
如果不指定num_words
参数,词汇表会收录所有出现的单词。测试代码的对应输出将如下:
[[1, 2, 3, 4, 5, 6, 7, 8, 9]]
若在实例化Tokenizer
的时候,加上oov_token
参数
from keras.preprocessing.text import Tokenizer
tokenizer = Tokenizer(num_words=5, oov_token='<OOV>')
text = ["今天 武汉 下 雨 了", "我 今天 上课", "我 明天 不 上课", "武汉 明天 不 下 雨"]
tokenizer.fit_on_texts(text)
word_index = tokenizer.word_index
print(word_index)
# {'<OOV>': 1,
# '今天': 2,
# '武汉': 3,
# '下': 4,
# '雨': 5,
# '我': 6,
# '上课': 7,
# '明天': 8,
# '不': 9,
# '了': 10}
sequences = tokenizer.texts_to_sequences(['今天 武汉 下 雨 我 上课 明天 不 了'])
print(sequences)
#[[2, 3, 4, 1, 1, 1, 1, 1, 1]]
这在参考链接1
中也有解释。
有人提问如下:
Hi,
I am currently working with the Tokenizer class and I have a question about the relevance of num_words. Reading the documentation suggests that when .fit_on_texts is run the Tokenizer will only take the most common num_words amounts. I currently have a dataset consisting of 10358 uniques words. When I run Tokenizer specifying num_words = 1000 I then call the word index which has a length of 10358. Does the Tokenizer generate an index of the top 1000 then add any others on after this when running fit_on_texts?
Thanks
作者回答如下:
The
Tokenizer
stores everything in theword_index
duringfit_on_texts
. Then, when calling thetexts_to_sequences
method, only the topnum_words
are considered.
In [1]: from keras.preprocessing.text import Tokenizer
In [2]: texts = ['a a a', 'b b', 'c']
In [3]: tokenizer = Tokenizer(num_words=2)
In [4]: tokenizer.fit_on_texts(texts)
In [5]: tokenizer.word_index
Out[5]: {'a': 1, 'b': 2, 'c': 3}
In [6]: tokenizer.texts_to_sequences(texts)
Out[6]: [[1, 1, 1], [], []]
There’s actually an off-by-one error as you can see; the output should be
[[1, 1, 1], [2, 2], []]
. I am fixing, but in the meantime you can set yournum_words
to be one more than you intended.
总结:
虽然word_index属性中维护了所有的词信息,但是在使用(如:tokenizer.texts_to_sequences()
)的时候,词汇表中只有num_words-1
个单词能够正常使用。
参考链接:
-
https://github.com/keras-team/keras/issues/7836
-
https://github.com/keras-team/keras/issues/7551