24 KiB
24 KiB
Ekstrakcja informacji
3. tfidf (1) [ćwiczenia]
Jakub Pokrywka (2021)
Zajęcia 3
import numpy as np
import re
zbiór dokumentów
documents = ['Ala lubi zwierzęta i ma kota oraz psa!',
'Ola lubi zwierzęta oraz ma kota a także chomika!',
'I Jan jeździ na rowerze.',
'2 wojna światowa była wielkim konfliktem zbrojnym',
'Tomek lubi psy, ma psa i jeździ na motorze i rowerze.',
]
CZEGO CHCEMY?
- chcemy zamienić teksty na zbiór słów
PYTANIE
- czy możemy ztokenizować tekst np. documents.split(' ') jakie wystąpią wtedy problemy?
ODPOWIEDŹ
- lepiej użyć preprocessingu i dopiero później tokenizacji
preprocessing
def get_str_cleaned(str_dirty):
punctuation = '!"#$%&\'()*+,-./:;<=>?@[\\\\]^_`{|}~'
new_str = str_dirty.lower()
new_str = re.sub(' +', ' ', new_str)
for char in punctuation:
new_str = new_str.replace(char,'')
return new_str
sample_document = get_str_cleaned(documents[0])
sample_document
'ala lubi zwierzęta i ma kota oraz psa'
tokenizacja
def tokenize_str(document):
return document.split(' ')
tokenize_str(sample_document)
['ala', 'lubi', 'zwierzęta', 'i', 'ma', 'kota', 'oraz', 'psa']
documents_cleaned = [get_str_cleaned(d) for d in documents]
documents_cleaned
['ala lubi zwierzęta i ma kota oraz psa', 'ola lubi zwierzęta oraz ma kota a także chomika', 'i jan jeździ na rowerze', '2 wojna światowa była wielkim konfliktem zbrojnym', 'tomek lubi psy ma psa i jeździ na motorze i rowerze']
documents_tokenized = [tokenize_str(d) for d in documents_cleaned]
documents_tokenized
[['ala', 'lubi', 'zwierzęta', 'i', 'ma', 'kota', 'oraz', 'psa'], ['ola', 'lubi', 'zwierzęta', 'oraz', 'ma', 'kota', 'a', 'także', 'chomika'], ['i', 'jan', 'jeździ', 'na', 'rowerze'], ['2', 'wojna', 'światowa', 'była', 'wielkim', 'konfliktem', 'zbrojnym'], ['tomek', 'lubi', 'psy', 'ma', 'psa', 'i', 'jeździ', 'na', 'motorze', 'i', 'rowerze']]
PYTANIA
- jaki jest następny krok w celu stworzenia wektórów TF lub TF-IDF
- jakie wielkości będzie wektor TF lub TF-IDF?
vocabulary = []
for document in documents_tokenized:
for word in document:
vocabulary.append(word)
vocabulary = sorted(set(vocabulary))
vocabulary
['2', 'a', 'ala', 'była', 'chomika', 'i', 'jan', 'jeździ', 'konfliktem', 'kota', 'lubi', 'ma', 'motorze', 'na', 'ola', 'oraz', 'psa', 'psy', 'rowerze', 'także', 'tomek', 'wielkim', 'wojna', 'zbrojnym', 'zwierzęta', 'światowa']
ZADANIE 1 stworzyć funkcję word_to_index(word:str), funkcja ma zwarać one-hot vector w postaciu numpy array
def word_to_index(word):
pass
word_to_index('psa')
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
ZADANIE 2 NAPISAC FUNKCJĘ, która bierze listę słów i zamienia na wetktor TF
def tf(document):
pass
tf(documents_tokenized[0])
array([0., 0., 1., 0., 0., 1., 0., 0., 0., 1., 1., 1., 0., 0., 0., 1., 1., 0., 0., 0., 0., 0., 0., 0., 1., 0.])
documents_vectorized = list()
for document in documents_tokenized:
document_vector = tf(document)
documents_vectorized.append(document_vector)
documents_vectorized
[array([0., 0., 1., 0., 0., 1., 0., 0., 0., 1., 1., 1., 0., 0., 0., 1., 1., 0., 0., 0., 0., 0., 0., 0., 1., 0.]), array([0., 1., 0., 0., 1., 0., 0., 0., 0., 1., 1., 1., 0., 0., 1., 1., 0., 0., 0., 1., 0., 0., 0., 0., 1., 0.]), array([0., 0., 0., 0., 0., 1., 1., 1., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0.]), array([1., 0., 0., 1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 0., 1.]), array([0., 0., 0., 0., 0., 2., 0., 1., 0., 0., 1., 1., 1., 1., 0., 0., 1., 1., 1., 0., 1., 0., 0., 0., 0., 0.])]
IDF
Wersja bez żadnej normalizacji
$idf_i = \Large\frac{|D|}{|\{d : t_i \in d \}|}$
$|D|$ - ilość dokumentów w korpusie $|\{d : t_i \in d \}|$ - ilość dokumentów w korpusie, gdzie dany term występuje chociaż jeden raz
idf = np.zeros(len(vocabulary))
idf = len(documents_vectorized) / np.sum(np.array(documents_vectorized) != 0,axis=0)
display(idf)
array([5. , 5. , 5. , 5. , 5. , 1.66666667, 5. , 2.5 , 5. , 2.5 , 1.66666667, 1.66666667, 5. , 2.5 , 5. , 2.5 , 2.5 , 5. , 2.5 , 5. , 5. , 5. , 5. , 5. , 2.5 , 5. ])
for i in range(len(documents_vectorized)):
documents_vectorized[i] = documents_vectorized[i] * idf
ZADANIE 3 Napisać funkcję similarity, która zwraca podobieństwo kosinusowe między dwoma dokumentami w postaci zwektoryzowanej
def similarity(query, document):
pass
documents[0]
'Ala lubi zwierzęta i ma kota oraz psa!'
documents_vectorized[0]
array([0., 0., 1., 0., 0., 1., 0., 0., 0., 1., 1., 1., 0., 0., 0., 1., 1., 0., 0., 0., 0., 0., 0., 0., 1., 0.])
documents[1]
'Ola lubi zwierzęta oraz ma kota a także chomika!'
documents_vectorized[1]
array([0., 1., 0., 0., 1., 0., 0., 0., 0., 1., 1., 1., 0., 0., 1., 1., 0., 0., 0., 1., 0., 0., 0., 0., 1., 0.])
similarity(documents_vectorized[0],documents_vectorized[1])
0.5892556509887895
def transform_query(query):
query_vector = tf(tokenize_str(get_str_cleaned(query)))
return query_vector
transform_query('psa')
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
similarity(transform_query('psa kota'), documents_vectorized[0])
0.4999999999999999
# tak są obsługiwane 2 słowa
query = 'psa kota'
for i in range(len(documents)):
display(documents[i])
display(similarity(transform_query(query), documents_vectorized[i]))
'Ala lubi zwierzęta i ma kota oraz psa!'
0.4999999999999999
'Ola lubi zwierzęta oraz ma kota a także chomika!'
0.2357022603955158
'I Jan jeździ na rowerze.'
0.0
'2 wojna światowa była wielkim konfliktem zbrojnym'
0.0
'Tomek lubi psy, ma psa i jeździ na motorze i rowerze.'
0.19611613513818402
# dlatego potrzebujemy mianownik w cosine similarity
# dłuższe dokumenty, w który raz wystąpie słowo rower są gorzej punktowane od
# krótszych. Jeżeli słowo rower wystąpiło w bardzo krótki dokumencie, to znaczy
# że jest większe prawdopodobieństwo że dokument jest o rowerze
query = 'rowerze'
for i in range(len(documents)):
display(documents[i])
display(similarity(transform_query(query), documents_vectorized[i]))
'Ala lubi zwierzęta i ma kota oraz psa!'
0.0
'Ola lubi zwierzęta oraz ma kota a także chomika!'
0.0
'I Jan jeździ na rowerze.'
0.4472135954999579
'2 wojna światowa była wielkim konfliktem zbrojnym'
0.0
'Tomek lubi psy, ma psa i jeździ na motorze i rowerze.'
0.2773500981126146
# dlatego potrzebujemy term frequency → wiecej wystąpień słowa w dokumencie
# znaczy bardziej dopasowany dokument
query = 'i'
for i in range(len(documents)):
display(documents[i])
display(similarity(transform_query(query), documents_vectorized[i]))
'Ala lubi zwierzęta i ma kota oraz psa!'
0.35355339059327373
'Ola lubi zwierzęta oraz ma kota a także chomika!'
0.0
'I Jan jeździ na rowerze.'
0.4472135954999579
'2 wojna światowa była wielkim konfliktem zbrojnym'
0.0
'Tomek lubi psy, ma psa i jeździ na motorze i rowerze.'
0.5547001962252291
# dlatego IDF - żeby ważniejsze słowa miał większą wagę
# słowo chomik ma większą wagę od i, ponieważ występuje w mniejszej ilości dokumentów
query = 'i chomika'
for i in range(len(documents)):
display(documents[i])
display(similarity(transform_query(query), documents_vectorized[i]))
[0;31m---------------------------------------------------------------------------[0m [0;31mNameError[0m Traceback (most recent call last) [0;32m<ipython-input-3-ca637083c8f1>[0m in [0;36m<module>[0;34m[0m [1;32m 2[0m [0;31m# słowo chomik ma większą wagę od i, ponieważ występuje w mniejszej ilości dokumentów[0m[0;34m[0m[0;34m[0m[0;34m[0m[0m [1;32m 3[0m [0mquery[0m [0;34m=[0m [0;34m'i chomika'[0m[0;34m[0m[0;34m[0m[0m [0;32m----> 4[0;31m [0;32mfor[0m [0mi[0m [0;32min[0m [0mrange[0m[0;34m([0m[0mlen[0m[0;34m([0m[0mdocuments[0m[0;34m)[0m[0;34m)[0m[0;34m:[0m[0;34m[0m[0;34m[0m[0m [0m[1;32m 5[0m [0mdisplay[0m[0;34m([0m[0mdocuments[0m[0;34m[[0m[0mi[0m[0;34m][0m[0;34m)[0m[0;34m[0m[0;34m[0m[0m [1;32m 6[0m [0mdisplay[0m[0;34m([0m[0msimilarity[0m[0;34m([0m[0mtransform_query[0m[0;34m([0m[0mquery[0m[0;34m)[0m[0;34m,[0m [0mdocuments_vectorized[0m[0;34m[[0m[0mi[0m[0;34m][0m[0;34m)[0m[0;34m)[0m[0;34m[0m[0;34m[0m[0m [0;31mNameError[0m: name 'documents' is not defined
Uwaga
Powyższe przykłady pokazują score dokuemntu. Aby zrobić wyszukiwarkę, powinniśmy posortować te dokumenty po score (od największego) i zaprezentwoać w tej kolejności.