Преобразование фрагмента текста на основе подобранного словаря вернет вам матрицу с количеством известных слов.
Например, если ваш входной документ такой же, как в вашем примере:
from sklearn.feature_extraction.text import CountVectorizer
vec = CountVectorizer(ngram_range=(1, 2))
docs = ['hello world and stackoverflow']
vec.fit(docs)
Тогда подобранный словарь может выглядеть следующим образом:
In [522]: print(vec.vocabulary_)
{'hello': 2,
'world': 5,
'and': 0,
'stackoverflow': 4,
'hello world': 3,
'world and': 6,
'and stackoverflow': 1}
, который представляет токен для сопоставления индекса.Преобразование некоторых новых документов впоследствии возвращает матрицу с количеством всех известных лексемных токенов. Слова, которых нет в словаре, игнорируются!
other_docs = ['hello stackoverflow',
'hello and hello',
'oh hello world and stackoverflow this is a great morning']
X = vec.transform(other_docs)
In [523]: print(X.A)
[[0 0 1 0 1 0 0]
[1 0 2 0 0 0 0]
[1 1 1 1 1 1 1]]
Ваш словарь состоит из 7 элементов, следовательно, матрица X
содержит 7 столбцов.И мы преобразовали 3 документа, так что это матрица 3x7
.Элементы матрицы являются подсчетами того, как часто конкретное слово встречается в документе.Например, для второго документа «привет и привет» у нас есть счет 2
в столбце 2 (0-индексированный) и счет 1
в столбце 0, которые ссылаются на «привет» и «и»,
Обратное преобразование - это сопоставление объектов (т. е. индексов) с элементами словаря:
In [534]: print(vec.inverse_transform([1, 2, 3, 4, 5, 6, 7]))
[array(['and', 'and stackoverflow', 'hello', 'hello world',
'stackoverflow', 'world', 'world and'], dtype='<U17')]
Примечание: Теперь это индексированное 1к индексам словаря, напечатанным выше.
Теперь давайте перейдем к вашему актуальному вопросу, который идентифицирует все элементы вне словаря (OOV) в данном входном документе.Довольно просто использовать sets
, если вас интересуют только униграммы:
tokens = 'oh hello world and stackoverflow this is a great morning'.split()
In [542]: print(set(tokens) - set(vec.vocabulary_.keys()))
{'morning', 'a', 'is', 'this', 'oh', 'great'}
Вещи немного сложнее, если вам интересны биграммы (или любые другие n-граммы, где n> 1), так как сначала вам нужно будет сгенерировать все биграммы из вашего входного документа (обратите внимание, что существуют разные способы создания всех нграмм из входного документа, из которых следующее только одно):
bigrams = list(map(lambda x: ' '.join(x), zip(tokens, tokens[1:])))
In [546]: print(bigrams)
['oh hello', 'hello world', 'world and', 'and stackoverflow', 'stackoverflow this', 'this is', 'is a', 'a great', 'great morning']
Эта строка выглядитНеобычно, но все это делает zip
два списка вместе (второй список начинается со второго элемента), что приводит к кортежу, например ('oh', 'hello')
, оператор map
просто присоединяет кортеж к одному пробелу вчтобы преобразовать ('oh', 'hello')
в 'oh hello'
, и впоследствии генератор карт преобразуется в list
.Теперь вы можете создать объединение униграмм и биграмм:
doc_vocab = set(tokens) | set(bigrams)
In [549]: print(doc_vocab)
{'and stackoverflow', 'hello', 'a', 'morning', 'hello world', 'great morning', 'world', 'stackoverflow', 'stackoverflow this', 'is', 'world and', 'oh hello', 'oh', 'this', 'is a', 'this is', 'and', 'a great', 'great'}
Теперь вы можете сделать то же самое, что и с униграммами выше, чтобы получить все элементы OOV:
In [550]: print(doc_vocab - set(vec.vocabulary_.keys()))
{'morning', 'a', 'great morning', 'stackoverflow this', 'is a', 'is', 'oh hello', 'this', 'this is', 'oh', 'a great', 'great'}
Теперь это представляет все униграммыи биграммы, которых нет в лексиконе вашего векторизатора.