Du corpus à la matrice en passant par la matrice
document1
: "un trou noir empêche toute forme de matière ou de rayonnement de s' en échapper"
document2
: "le trou noir est un cocktail à base d' alcool généralement servi dans un shooter"
document3
: "les pays avérés du trou noir de le immobilier sont le Japon et l' Allemagne"
document4
: "un trou de ver relierait deux feuillets distincts un trou noir et un trou blanc"
document5
: "placer une saucisse cocktail au bord de une bande de pâte enrouler la pâte autour de la saucisse"
document1 = "un trou noir empêche toute forme de matière ou de rayonnement de s' en échapper"
document2 = "le trou noir est un cocktail à base d' alcool généralement servi dans un shooter"
document3 = "les pays avérés du trou noir de le immobilier sont le Japon et l' Allemagne"
document4 = "un trou de ver relierait deux feuillets distincts un trou noir et un trou blanc"
document5 = "placer une saucisse cocktail au bord de une bande de pâte enrouler la pâte autour de la saucisse"
documents = {"document1": document1, "document2": document2, "document3": document3, "document4": document4, "document5": document5}
documents["document4"]
def creer_index():
index = {}
for nom, texte in documents.items():
for terme in texte.split():
if terme not in index:
index[terme] = set()
index[terme].add(nom)
index = {terme:sorted(list(noms)) for terme, noms in index.items()}
return index
index = creer_index()
for terme, noms in list(index.items())[:]:
print(terme,noms)
documents/termes | $terme_1$ | $terme_2$ | $terme_3$ | $\cdots$ | $terme_J$ |
---|---|---|---|---|---|
$document_1$ | $A_{1,1}$ | $A_{1,2}$ | $A_{1,3}$ | $\cdots$ | $A_{1, J}$ |
$document_2$ | $A_{2,1}$ | $\ddots$ | $\vdots$ | ||
$document_3$ | $A_{3,1}$ | $\ddots$ | $\vdots$ | ||
$\vdots$ | $\vdots$ | $\ddots$ | $\vdots$ | ||
$document_I$ | $A_{I,1}$ | $\cdots$ | $\cdots$ | $\cdots$ | $A_{I,J}$ |
def creer_index_inverse():
index_inverse = {}
for nom, texte in documents.items():
index_inverse[nom] = dict()
for terme in texte.split():
if terme not in index_inverse[nom]:
index_inverse[nom][terme] = 1
else:
index_inverse[nom][terme] += 1
return index_inverse
index_inverse = creer_index_inverse()
print(index_inverse)
def requeter_documets(requete, index):
documents_trouves = list()
requete_mots = requete.split() # découper la requête en mots
# chercher pour chaque mot les documents où il apparaît
for mot in requete_mots:
if mot in index:
for document in index[mot]:
if document not in documents_trouves:
documents_trouves.append(document)
return documents_trouves
requete = "matière et le trou noir"
documents_trouves = requeter_documets(requete, index)
print(documents_trouves)
$ J(A,B) = { {|A \cap B| } \over |A \cup B| }$
$|A \cap B|$ : Taille de l'intersection des documents considérés
$|A \cup B|$ : Taille de l'union des documents considérés
def creer_matrice_jaccard(index_inverse):
matrice_sim = dict()
for nom, termes_document in index_inverse.items():
matrice_sim[nom] = dict()
for nom_int, termes_document_int in index_inverse.items():
#Taille de l'intersection des documents considérés
intersection = len(set(termes_document).intersection(set(termes_document_int)))
#Taille de l'union des documents considérés
union = len(set(termes_document).union(set(termes_document_int)))
matrice_sim[nom][nom_int] = intersection/union
noms = matrice_sim.keys()
print("JACCARD\t\t"+"\t".join(noms))
for nom in noms:
print(nom, end="\t")
for nom_int in noms:
print("{:.3f}".format(matrice_sim[nom][nom_int]), end="\t\t")
print("")
return matrice_sim
matrice_sim = creer_matrice_jaccard(index_inverse)
print("*"*40)
print(matrice_sim)
def calculer_ponderation_jaccard(requete, index_inverse, documents_trouves):
ponderations = dict()
requete_mots = requete.split()
for document in documents_trouves:
#Termes du document trouvé
termes_document = index_inverse[document]
#Taille de l'intersection des documents considérés
intersection = len(set(termes_document).intersection(set(requete_mots)))
#Taille de l'union des documents considérés
union = len(set(termes_document).union(set(requete_mots)))
ponderations[document] = intersection/union
return ponderations
requete = "matière et le trou noir"
documents_trouves = requeter_documets(requete, index)
print(documents_trouves)
ponderations_jaccard = calculer_ponderation_jaccard(requete, index_inverse, documents_trouves)
print(ponderations_jaccard)
Permet de calculer la similarité entre deux documents ($A$ et $B$) à $n$ termes en déterminant le cosinus de l'angle entre eux.
$sim(A,B) = \cos(\mathbf{A},\mathbf{B}) = \frac{\mathbf{A} \cdot \mathbf{B}}{||\mathbf{A}|| \cdot ||\mathbf{B}||} ; [-1,+1]$
$\mathbf{A} \cdot \mathbf{B} = \sum_{i=1}^{n} A_iB_i $ ; produit scalaire entre $\mathbf{A}$ et $\mathbf{B}$
$||\mathbf{A}|| = \sqrt{\sum{_{i=1}^{n}}A_i^2}$ ; norme de $\mathbf{A}$
$||\mathbf{B}|| = \sqrt{\sum{_{i=1}^{n}}B_i^2}$ ; norme de $\mathbf{B}$
$A$ = le chat noir mignon
$B$ = le chien blanc mignon
documents/termes | le | chat | noir | chien | blanc | mignon |
---|---|---|---|---|---|---|
$A$ | 1 | 1 | 1 | 0 | 0 | 1 |
$B$ | 1 | 0 | 0 | 1 | 1 | 1 |
$n = 6 $
$\mathbf{A} = (1,1,1,0,0,1)$
$\mathbf{B} = (1,0,0,1,1,1)$
$\mathbf{A} \cdot \mathbf{B} = \sum_{i=1}^{n} A_iB_i = (1\times1)+(1\times0)+(1\times0)+(0\times1)+(0\times1)+(1\times1) = 2$
$||\mathbf{A}|| = \sqrt{\sum{_{i=1}^{n}}A_i^2} = \sqrt{1^2+1^2+1^2+0^2+0^2+1^2} = \sqrt{4} = 2$
$||\mathbf{B}|| = \sqrt{\sum{_{i=1}^{n}}B_i^2} = \sqrt{1^2+0^2+0^2+1^2+1^2+1^2} = \sqrt{4} = 2$
$sim(A,B) = \cos(\mathbf{A},\mathbf{B}) = \frac{\mathbf{A} \cdot \mathbf{B}}{||\mathbf{A}|| \cdot ||\mathbf{B}||} = \frac{2}{2 \times 2} = \frac{2}{4} = \frac{1}{2} = 0.5$
import math
def calculer_sim_cosinus(docA, docB):
termes_communs = list(set(docA).intersection(set(docB)))
#produit scalaire
AB = 0
for terme_commun in termes_communs:
AB += docA[terme_commun] * docB[terme_commun]
#norme A
A_norme = 0
for terme, freq in docA.items():
A_norme += pow(freq, 2)
A_norme = math.sqrt(A_norme)
#norme B
B_norme = 0
for terme, freq in docB.items():
B_norme += pow(freq, 2)
B_norme = math.sqrt(B_norme)
sim_cosinus = AB / (A_norme * B_norme)
return sim_cosinus
r1 = calculer_sim_cosinus(index_inverse["document1"], index_inverse["document2"])
print(r1)
r2 = calculer_sim_cosinus(index_inverse["document1"], index_inverse["document5"])
print(r2)
import itertools
def creer_matrice_cosinus(index_inverse):
matrice_sim = dict()
paires_docs = list(itertools.permutations(index_inverse.keys(), 2))
for docA, docB in paires_docs:
if docA not in matrice_sim:
matrice_sim[docA] = dict()
a=calculer_sim_cosinus(index_inverse[docA], index_inverse[docB])
matrice_sim[docA][docB] = calculer_sim_cosinus(index_inverse[docA], index_inverse[docB])
noms = matrice_sim.keys()
print("COSINUS\t\t"+"\t".join(noms))
for nom in noms:
print(nom, end="\t")
for nom_int in noms:
if nom_int not in matrice_sim[nom]:
print("1.000", end="\t\t")
else:
print("{:.3f}".format(matrice_sim[nom][nom_int]), end="\t\t")
print("")
return matrice_sim
matrice_sim = creer_matrice_cosinus(index_inverse)
print("*"*40)
print(matrice_sim)
def indexer_requete(requete):
index_requete = dict()
for terme in requete.split():
if terme not in index_requete:
index_requete[terme] = 1
else:
index_requete[terme] += 1
return index_requete
def calculer_ponderation_cosinus(requete, index_inverse, documents_trouves):
ponderations = dict()
index_requete = indexer_requete(requete)
for docA in documents_trouves:
ponderations[docA] = calculer_sim_cosinus(index_inverse[docA], index_requete)
return ponderations
requete = "matière et le trou le noir"
documents_trouves = requeter_documets(requete, index)
print(documents_trouves)
ponderations_cosinus = calculer_ponderation_cosinus(requete, index_inverse, documents_trouves)
print(ponderations_cosinus)
À partir de notre exemple de Similarité cosinus :
$A$ = le chat noir mignon
$B$ = le chien blanc mingon
alldocs = {"A": {"le": 1, "chat": 1, "noir": 1, "mignon": 1},
"B": {"le": 1, "chien": 1, "blanc": 1, "mignon": 1}}
allvoc = {"le": 2 , "chat": 1, "noir": 1, "mignon": 2, "chien": 1, "blanc":1}
Term Frequency (TF) : le taux d'apparition d'un mot dans un document. Il est toujours dans l'interval de 0 à 1 (inclus). Cette mesure présente si ce mot est fréquent (donc important) par rapport aux autres mots du même document.
$TF_{(terme_m, document_d)}=$ (nombre d'occurrence du $terme_m$ dans $document_d$) / (nombre total de toutes les occurrences de tous les termes dans $document_d$)
TF = {"A": {"le": 0.25, "chat": 0.25, "noir": 0.25, "mignon": 0.25},
"B": {"le": 0.25, "chien": 0.25, "blanc": 0.25, "mignon": 0.25}}
Inverse Document Frequency (IDF) : Une mesure globale pour un terme. Cette mesure est dans l'interval de 0 à >1. Elle représente l'importance d'un mot pour marquer un document dans la base. Si un mot n'est présent dans qu'un seul document, ce mot est important pour retrouver le document. En revanche, si un mot est présent dans tous les documents de la base, il n'est pas significatif et son score IDF sera faible.
$IDF{(terme_m)} = log_{10}( $ (nombre total de documents)/(nombre de documents où $terme_m$ est présent) $)$
Total de documents : 2
IDF = {"le": 0.0 , "chat": 0.301, "noir": 0.301, "mignon": 0.0, "chien": 0.301, "blanc": 0.301}
print(math.log10(2/1))
print(math.log10(2/2))
Finalement,
TF = {"A": {"le": 0.25, "chat": 0.25, "noir": 0.25, "mignon": 0.25},
"B": {"le": 0.25, "chien": 0.25, "blanc": 0.25, "mignon": 0.25}}
IDF = {"le": 0.0 , "chat": 0.301, "noir": 0.301, "mignon": 0.0, "chien": 0.301, "blanc": 0.301}
TF-IDF = $TF \cdot IDF$
alldocs_TFIDF = {"A": {"le": 0.25*0.0, "chat": 0.25*0.301, "noir": 0.25*0.301, "mignon": 0.25*0.0},
"B": {"le": 0.25*0.0, "chien": 0.25*0.301, "blanc": 0.25*0.301, "mignon": 0.25*0.0}}
alldocs_TFIDF = {"A": {"le": 0.0, "chat": 0.075, "noir": 0.075, "mignon": 0.0},
"B": {"le": 0.0, "chien": 0.075, "blanc": 0.075, "mignon": 0.0}}
$A$ = le chat noir mignon
$B$ = le chien blanc mingon
documents/termes | le | chat | noir | chien | blanc | mignon |
---|---|---|---|---|---|---|
$A$ | 0 | 0.075 | 0.075 | 0 | 0 | 0 |
$B$ | 0 | 0 | 0 | 0.075 | 0.075 | 0 |
import math
import copy
def calculer_tfidf(index_inverse, index):
tfidf_index_inverse = copy.deepcopy(index_inverse)
# Calculer TF
for nom, termes_document in index_inverse.items():
totale_freqs = 0
for _, freq in termes_document.items():
totale_freqs += freq
for terme in tfidf_index_inverse[nom].keys():
tfidf_index_inverse[nom][terme] /= totale_freqs
# Calculer IDF
totale_docs = len(index_inverse.keys())
idf_index = copy.deepcopy(index)
for terme, noms in idf_index.items():
terme_rep = len(noms)
idf_val = math.log10(totale_docs / terme_rep)
idf_index[terme] = idf_val
# Calculer TFIDF
for nom, termes_document in tfidf_index_inverse.items():
for terme in termes_document.keys():
tfidf_index_inverse[nom][terme] *= idf_index[terme]
return tfidf_index_inverse, idf_index
tfidf_index_inverse, idf_index = calculer_tfidf(index_inverse, index)
print(tfidf_index_inverse["document1"])
print(index_inverse["document1"])
tfidf_matrice_jaccard = creer_matrice_jaccard(tfidf_index_inverse)
tfidf_matrice_cosinus = creer_matrice_cosinus(tfidf_index_inverse)
def calculer_ponderation_cosinus_tfidf(requete, index_inverse, idf_index, documents_trouves):
ponderations = dict()
index_requete = indexer_requete(requete)
for terme in index_requete.keys():
index_requete[terme] *= idf_index[terme]
for docA in documents_trouves:
ponderations[docA] = calculer_sim_cosinus(index_inverse[docA], index_requete)
return ponderations
requete = "matière et le trou noir"
documents_trouves = requeter_documets(requete, index)
print(documents_trouves)
print("....")
ponderations_cosinus = calculer_ponderation_cosinus(requete, index_inverse, documents_trouves)
print(ponderations_cosinus)
print("....")
ponderations_cosinus_tfidf = calculer_ponderation_cosinus_tfidf(requete, tfidf_index_inverse, idf_index, documents_trouves)
print(ponderations_cosinus_tfidf)