Bag-of-words (BoW) – technika uproszczonej reprezentacji tekstu. Polega na przekształeceniu sekwencji segmentów do policzonego zbioru segmentów. Kolejność segmentów nie ma znaczenia. Głównym zastosowaniem jest odwzorowanie podobieństwa znaczeniowego/miar podobieństwa dokumentów.¶
In [1]:
import spacy
nlp = spacy.load('pl_core_news_sm')
In [2]:
texts = [
"Agnieszka ma nowy samochód",
"Agnieszka z Warszawy ma piękny samochód",
"Arek ma nowy rower",
"Samochód Agnieszki jest nowy"
]
Podział tekstu na tokeny
In [3]:
docs = [nlp(text) for text in texts]
docs
Out[3]:
[Agnieszka ma nowy samochód, Agnieszka z Warszawy ma piękny samochód, Arek ma nowy rower, Samochód Agnieszki jest nowy]
Przekształcenie listy do słownika wraz z liczbą wystąpień poszczególnych elementów sprowadzonych do podstawowej postaci (użyjemy obiekt z biblioteki nltk).
In [4]:
from nltk.probability import FreqDist
In [5]:
# dla każdego elementu stwórz lemat rzutowany do małych liter i stwórz obiekt FreqDist
freq_lemma = [FreqDist([t.lemma_.lower() for t in doc]) for doc in docs]
freq_lemma
Out[5]:
[FreqDist({'agnieszka': 1, 'mieć': 1, 'nowy': 1, 'samochód': 1}), FreqDist({'agnieszka': 1, 'z': 1, 'warszawa': 1, 'mieć': 1, 'piękny': 1, 'samochód': 1}), FreqDist({'arka': 1, 'mieć': 1, 'nowy': 1, 'rower': 1}), FreqDist({'samochód': 1, 'agnieszka': 1, 'być': 1, 'nowy': 1})]
Miara podobieństwa zbiorów w oparciu o indeks Jaccarda.¶
- przecięcie zbiorów = zbiór lematów występujących w obu zbiorach jednoczesnie
- suma zbiorów = zbiów wszystkich lematów występujących w obu zbiorach
- J(A,B) = |przecięcie zbiorów| / |suma zbiorów|
In [6]:
# funkcja przyjmuje 2 argumenty - reprezentacje dwóch dokumentów
def bow_similarity(bow1: FreqDist, bow2: FreqDist) -> float:
# suma zbiorów
bow_all = bow1 + bow2
# przecięcie zbiorów. Iteracja po elementach sumy zbiorów i sprawdzanie czy występuje w każdym z dokumentów
bow_common = [word for word in bow_all.keys() if word in bow1 and word in bow2]
# jeżeli liczność sumy zbiorów jest zerowa to zwracamy zero
# jeżeli liczność sumy zbiorów nie jest zerowa to postępujemy zgodnie ze wzorem Jaccarda: J(A,B)
return 0 if len(bow_all) == 0 else len(bow_common) / len(bow_all)
In [8]:
print(texts[0], "\n")
for n in range(1, 4):
sim = bow_similarity(freq_lemma[0], freq_lemma[n])
print(f"{sim:<6.4} {texts[n]}")
Agnieszka ma nowy samochód 0.4286 Agnieszka z Warszawy ma piękny samochód 0.3333 Arek ma nowy rower 0.6 Samochód Agnieszki jest nowy
W powyższym przykładzie prównujemy miarę podobieństwa pomiędzy zdaniem „Agnieszka ma nowy samochód”, a pozostałymi. Najbardziej podobnym zdaniem jest „Samochód Agnieszki jest nowy”.