forked from filipg/aitech-eks-pub
38 KiB
38 KiB
Ekstrakcja informacji
3. tfidf (1) [ćwiczenia]
Jakub Pokrywka (2021)
Zajęcia 2
Na tych zajęciach za aktywnośc można otrzymać po 5 punktów za wartościową wypowiedź. Maksymalnie jedna osoba może zdobyć na tych ćwiczeniach do 15 punktów.
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?
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']
PYTANIA
jak będzie słowo "jak" w reprezentacji wektorowej TF?
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
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
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 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ę
query = 'i chomika'
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.24999999999999994
'Ola lubi zwierzęta oraz ma kota a także chomika!'
0.2357022603955158
'I Jan jeździ na rowerze.'
0.31622776601683794
'2 wojna światowa była wielkim konfliktem zbrojnym'
0.0
'Tomek lubi psy, ma psa i jeździ na motorze i rowerze.'
0.39223227027636803
ZADANIE 4 NAPISAĆ IDF w celu zmiany wag z TF na TF- IDF
Proszę użyć wersję 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