TF-IDF

La méthode term frequency–inverse document frequency est une manière de transformer des mots en chiffres. Cela se base sur une intuition: un mot qui est très présent dans un document et qui n’est pas très présent dans le reste du corpus est un mot qui peut bien caractériser ce document.

Concrètement la formule fonctionne comme suit:

  • fréquence d’un mot dans un document: on compte combien de fois un mot apparaît dans un document

  • fréquence inverse: on regarde combien de fois ce mot apparaît dans le reste du corpus

Finalement on applique la formule suivante:

inverse_document_frequency = log(total number of documents / number of documents with term) + 1

Par exemple: admettons que le mot “amour” apparaisse 10 fois dans 1 document et qu’il aparaisse au total dans 5 documents sur 10 analysés. son idf sera:

# Import math Library
import math 
math.log(10/5)+1
1.6931471805599454

Considérons que le log de 1 est 0 ce qui signifie que si le mot apparaît dans tout les documents la idf est 1.

math.log(1)
0.0
math.log(1)+1
1.0

Le tf-idf d’amour sera donc:

tf-idf = term_frequency * inverse_document_frequency

Son tf-idf sera :

liste = []
liste.append(10 * (math.log(10/5)+1))
10 * (math.log(10/5)+1)
16.931471805599454

Si amour apparaissait dans tous les documents il aurait un plus bas résultat:

liste.append(10 * (math.log(10/10)+1))
10 * (math.log(10/10)+1)
10.0

Si amour n’apparaissait que dans ce document alors son idf serait:

liste.append(10 * (math.log(10/1)+1))
10 * (math.log(10/1)+1)
33.02585092994046

Donc résultat élevé car le mot apparaît seulement dans le document et il y est 10 fois.

Et encore si amour aparaissait 1 fois dans chaque document:

liste.append(1 * (math.log(10/10)+1))
1 * (math.log(10/10)+1)
1.0
liste
[16.931471805599454, 10.0, 33.02585092994046, 1.0]
import numpy as np
from sklearn import preprocessing
x_array = np.array(liste)
normalized_arr = preprocessing.normalize([x_array])
print(normalized_arr)
[[0.44035349 0.26007986 0.85893588 0.02600799]]
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_extraction.text import CountVectorizer
import pandas as pd
pd.set_option("max_rows", 600)
from pathlib import Path  
import glob
import requests
import json
/home/marcello/.local/lib/python3.7/site-packages/sklearn/feature_extraction/image.py:167: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.
Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations
  dtype=np.int):
data = requests.get('http://anthologia.ecrituresnumeriques.ca/api/v1/entities').json()
mes_textes = []
for epigram in data:
    titre = epigram['title']
    if 'Greek Anthology 5' in titre or 'Greek Anthology 4' in titre:
        for version in epigram['versions']:
        
            if version['id_language'] == 2:
                texte = version['text_translated']
        dictio = {'title': titre, 'texte' : texte}
        mes_textes.append(dictio)
mes_textes[70]
{'title': 'Greek Anthology 5.60',
 'texte': 'Une jeune fille aux pieds d’argent se baignait, arrosant les pommes d’or de ses seins de lait\xa0; ses fesses rondes palpitaient, d’un mouvement inconscient, et l’on voyait frissonner leur chair plus onduleuse que l’eau\xa0; cependant, de sa main étendue, elle voilait le renflement de son… Eurotas, non pas en entier, mais tout ce qu’elle en pouvait couvrir. '}
stopwords = requests.get('https://raw.githubusercontent.com/stopwords-iso/stopwords-fr/master/stopwords-fr.txt').text.split('\n')
stopwords
['a',
 'abord',
 'absolument',
 'afin',
 'ah',
 'ai',
 'aie',
 'aient',
 'aies',
 'ailleurs',
 'ainsi',
 'ait',
 'allaient',
 'allo',
 'allons',
 'allô',
 'alors',
 'anterieur',
 'anterieure',
 'anterieures',
 'apres',
 'après',
 'as',
 'assez',
 'attendu',
 'au',
 'aucun',
 'aucune',
 'aucuns',
 'aujourd',
 "aujourd'hui",
 'aupres',
 'auquel',
 'aura',
 'aurai',
 'auraient',
 'aurais',
 'aurait',
 'auras',
 'aurez',
 'auriez',
 'aurions',
 'aurons',
 'auront',
 'aussi',
 'autant',
 'autre',
 'autrefois',
 'autrement',
 'autres',
 'autrui',
 'aux',
 'auxquelles',
 'auxquels',
 'avaient',
 'avais',
 'avait',
 'avant',
 'avec',
 'avez',
 'aviez',
 'avions',
 'avoir',
 'avons',
 'ayant',
 'ayez',
 'ayons',
 'b',
 'bah',
 'bas',
 'basee',
 'bat',
 'beau',
 'beaucoup',
 'bien',
 'bigre',
 'bon',
 'boum',
 'bravo',
 'brrr',
 'c',
 'car',
 'ce',
 'ceci',
 'cela',
 'celle',
 'celle-ci',
 'celle-là',
 'celles',
 'celles-ci',
 'celles-là',
 'celui',
 'celui-ci',
 'celui-là',
 'celà',
 'cent',
 'cependant',
 'certain',
 'certaine',
 'certaines',
 'certains',
 'certes',
 'ces',
 'cet',
 'cette',
 'ceux',
 'ceux-ci',
 'ceux-là',
 'chacun',
 'chacune',
 'chaque',
 'cher',
 'chers',
 'chez',
 'chiche',
 'chut',
 'chère',
 'chères',
 'ci',
 'cinq',
 'cinquantaine',
 'cinquante',
 'cinquantième',
 'cinquième',
 'clac',
 'clic',
 'combien',
 'comme',
 'comment',
 'comparable',
 'comparables',
 'compris',
 'concernant',
 'contre',
 'couic',
 'crac',
 'd',
 'da',
 'dans',
 'de',
 'debout',
 'dedans',
 'dehors',
 'deja',
 'delà',
 'depuis',
 'dernier',
 'derniere',
 'derriere',
 'derrière',
 'des',
 'desormais',
 'desquelles',
 'desquels',
 'dessous',
 'dessus',
 'deux',
 'deuxième',
 'deuxièmement',
 'devant',
 'devers',
 'devra',
 'devrait',
 'different',
 'differentes',
 'differents',
 'différent',
 'différente',
 'différentes',
 'différents',
 'dire',
 'directe',
 'directement',
 'dit',
 'dite',
 'dits',
 'divers',
 'diverse',
 'diverses',
 'dix',
 'dix-huit',
 'dix-neuf',
 'dix-sept',
 'dixième',
 'doit',
 'doivent',
 'donc',
 'dont',
 'dos',
 'douze',
 'douzième',
 'dring',
 'droite',
 'du',
 'duquel',
 'durant',
 'dès',
 'début',
 'désormais',
 'e',
 'effet',
 'egale',
 'egalement',
 'egales',
 'eh',
 'elle',
 'elle-même',
 'elles',
 'elles-mêmes',
 'en',
 'encore',
 'enfin',
 'entre',
 'envers',
 'environ',
 'es',
 'essai',
 'est',
 'et',
 'etant',
 'etc',
 'etre',
 'eu',
 'eue',
 'eues',
 'euh',
 'eurent',
 'eus',
 'eusse',
 'eussent',
 'eusses',
 'eussiez',
 'eussions',
 'eut',
 'eux',
 'eux-mêmes',
 'exactement',
 'excepté',
 'extenso',
 'exterieur',
 'eûmes',
 'eût',
 'eûtes',
 'f',
 'fais',
 'faisaient',
 'faisant',
 'fait',
 'faites',
 'façon',
 'feront',
 'fi',
 'flac',
 'floc',
 'fois',
 'font',
 'force',
 'furent',
 'fus',
 'fusse',
 'fussent',
 'fusses',
 'fussiez',
 'fussions',
 'fut',
 'fûmes',
 'fût',
 'fûtes',
 'g',
 'gens',
 'h',
 'ha',
 'haut',
 'hein',
 'hem',
 'hep',
 'hi',
 'ho',
 'holà',
 'hop',
 'hormis',
 'hors',
 'hou',
 'houp',
 'hue',
 'hui',
 'huit',
 'huitième',
 'hum',
 'hurrah',
 'hé',
 'hélas',
 'i',
 'ici',
 'il',
 'ils',
 'importe',
 'j',
 'je',
 'jusqu',
 'jusque',
 'juste',
 'k',
 'l',
 'la',
 'laisser',
 'laquelle',
 'las',
 'le',
 'lequel',
 'les',
 'lesquelles',
 'lesquels',
 'leur',
 'leurs',
 'longtemps',
 'lors',
 'lorsque',
 'lui',
 'lui-meme',
 'lui-même',
 'là',
 'lès',
 'm',
 'ma',
 'maint',
 'maintenant',
 'mais',
 'malgre',
 'malgré',
 'maximale',
 'me',
 'meme',
 'memes',
 'merci',
 'mes',
 'mien',
 'mienne',
 'miennes',
 'miens',
 'mille',
 'mince',
 'mine',
 'minimale',
 'moi',
 'moi-meme',
 'moi-même',
 'moindres',
 'moins',
 'mon',
 'mot',
 'moyennant',
 'multiple',
 'multiples',
 'même',
 'mêmes',
 'n',
 'na',
 'naturel',
 'naturelle',
 'naturelles',
 'ne',
 'neanmoins',
 'necessaire',
 'necessairement',
 'neuf',
 'neuvième',
 'ni',
 'nombreuses',
 'nombreux',
 'nommés',
 'non',
 'nos',
 'notamment',
 'notre',
 'nous',
 'nous-mêmes',
 'nouveau',
 'nouveaux',
 'nul',
 'néanmoins',
 'nôtre',
 'nôtres',
 'o',
 'oh',
 'ohé',
 'ollé',
 'olé',
 'on',
 'ont',
 'onze',
 'onzième',
 'ore',
 'ou',
 'ouf',
 'ouias',
 'oust',
 'ouste',
 'outre',
 'ouvert',
 'ouverte',
 'ouverts',
 'o|',
 'où',
 'p',
 'paf',
 'pan',
 'par',
 'parce',
 'parfois',
 'parle',
 'parlent',
 'parler',
 'parmi',
 'parole',
 'parseme',
 'partant',
 'particulier',
 'particulière',
 'particulièrement',
 'pas',
 'passé',
 'pendant',
 'pense',
 'permet',
 'personne',
 'personnes',
 'peu',
 'peut',
 'peuvent',
 'peux',
 'pff',
 'pfft',
 'pfut',
 'pif',
 'pire',
 'pièce',
 'plein',
 'plouf',
 'plupart',
 'plus',
 'plusieurs',
 'plutôt',
 'possessif',
 'possessifs',
 'possible',
 'possibles',
 'pouah',
 'pour',
 'pourquoi',
 'pourrais',
 'pourrait',
 'pouvait',
 'prealable',
 'precisement',
 'premier',
 'première',
 'premièrement',
 'pres',
 'probable',
 'probante',
 'procedant',
 'proche',
 'près',
 'psitt',
 'pu',
 'puis',
 'puisque',
 'pur',
 'pure',
 'q',
 'qu',
 'quand',
 'quant',
 'quant-à-soi',
 'quanta',
 'quarante',
 'quatorze',
 'quatre',
 'quatre-vingt',
 'quatrième',
 'quatrièmement',
 'que',
 'quel',
 'quelconque',
 'quelle',
 'quelles',
 "quelqu'un",
 'quelque',
 'quelques',
 'quels',
 'qui',
 'quiconque',
 'quinze',
 'quoi',
 'quoique',
 'r',
 'rare',
 'rarement',
 'rares',
 'relative',
 'relativement',
 'remarquable',
 'rend',
 'rendre',
 'restant',
 'reste',
 'restent',
 'restrictif',
 'retour',
 'revoici',
 'revoilà',
 'rien',
 's',
 'sa',
 'sacrebleu',
 'sait',
 'sans',
 'sapristi',
 'sauf',
 'se',
 'sein',
 'seize',
 'selon',
 'semblable',
 'semblaient',
 'semble',
 'semblent',
 'sent',
 'sept',
 'septième',
 'sera',
 'serai',
 'seraient',
 'serais',
 'serait',
 'seras',
 'serez',
 'seriez',
 'serions',
 'serons',
 'seront',
 'ses',
 'seul',
 'seule',
 'seulement',
 'si',
 'sien',
 'sienne',
 'siennes',
 'siens',
 'sinon',
 'six',
 'sixième',
 'soi',
 'soi-même',
 'soient',
 'sois',
 'soit',
 'soixante',
 'sommes',
 'son',
 'sont',
 'sous',
 'souvent',
 'soyez',
 'soyons',
 'specifique',
 'specifiques',
 'speculatif',
 'stop',
 'strictement',
 'subtiles',
 'suffisant',
 'suffisante',
 'suffit',
 'suis',
 'suit',
 'suivant',
 'suivante',
 'suivantes',
 'suivants',
 'suivre',
 'sujet',
 'superpose',
 'sur',
 'surtout',
 't',
 'ta',
 'tac',
 'tandis',
 'tant',
 'tardive',
 'te',
 'tel',
 'telle',
 'tellement',
 'telles',
 'tels',
 'tenant',
 'tend',
 'tenir',
 'tente',
 'tes',
 'tic',
 'tien',
 'tienne',
 'tiennes',
 'tiens',
 'toc',
 'toi',
 'toi-même',
 'ton',
 'touchant',
 'toujours',
 'tous',
 'tout',
 'toute',
 'toutefois',
 'toutes',
 'treize',
 'trente',
 'tres',
 'trois',
 'troisième',
 'troisièmement',
 'trop',
 'très',
 'tsoin',
 'tsouin',
 'tu',
 'té',
 'u',
 'un',
 'une',
 'unes',
 'uniformement',
 'unique',
 'uniques',
 'uns',
 'v',
 'va',
 'vais',
 'valeur',
 'vas',
 'vers',
 'via',
 'vif',
 'vifs',
 'vingt',
 'vivat',
 'vive',
 'vives',
 'vlan',
 'voici',
 'voie',
 'voient',
 'voilà',
 'voire',
 'vont',
 'vos',
 'votre',
 'vous',
 'vous-mêmes',
 'vu',
 'vé',
 'vôtre',
 'vôtres',
 'w',
 'x',
 'y',
 'z',
 'zut',
 'à',
 'â',
 'ça',
 'ès',
 'étaient',
 'étais',
 'était',
 'étant',
 'état',
 'étiez',
 'étions',
 'été',
 'étée',
 'étées',
 'étés',
 'êtes',
 'être',
 'ô']
tfidf_vectorizer = TfidfVectorizer(stop_words=stopwords)
len(mes_textes)
214
tfidf_vector = tfidf_vectorizer.fit_transform([texte['texte'] for texte in mes_textes])
/home/marcello/.local/lib/python3.7/site-packages/sklearn/feature_extraction/text.py:301: UserWarning: Your stop_words may be inconsistent with your preprocessing. Tokenizing the stop words generated tokens ['quelqu'] not in stop_words.
  'stop_words.' % sorted(inconsistent))
tfidf_df = pd.DataFrame(tfidf_vector.toarray(), index=[texte['title'] for texte in mes_textes], columns=tfidf_vectorizer.get_feature_names())
tfidf_slice = tfidf_df[['amour', 'mort', 'éros', 'fille', 'garçon', 'fleur', 'pouvoir']]
tfidf_slice.sort_index().round(decimals=2).head(20)
amour mort éros fille garçon fleur pouvoir
Greek Anthology 4.1 0.00 0.00 0.03 0.00 0.0 0.10 0.00
Greek Anthology 4.2 0.00 0.00 0.00 0.00 0.0 0.00 0.00
Greek Anthology 4.3 0.02 0.00 0.00 0.03 0.0 0.03 0.00
Greek Anthology 4.4 0.00 0.00 0.00 0.00 0.0 0.00 0.00
Greek Anthology 4.5 0.00 0.14 0.00 0.00 0.0 0.00 0.00
Greek Anthology 5.0 0.00 0.00 0.20 0.00 0.0 0.00 0.00
Greek Anthology 5.1 0.16 0.00 0.00 0.00 0.0 0.00 0.00
Greek Anthology 5.10 0.00 0.00 0.14 0.00 0.0 0.00 0.00
Greek Anthology 5.100 0.00 0.00 0.12 0.00 0.0 0.00 0.00
Greek Anthology 5.101 0.00 0.00 0.00 0.19 0.0 0.00 0.00
Greek Anthology 5.102 0.00 0.00 0.00 0.00 0.0 0.00 0.00
Greek Anthology 5.103 0.00 0.00 0.00 0.00 0.0 0.00 0.23
Greek Anthology 5.104 0.00 0.00 0.00 0.00 0.0 0.00 0.00
Greek Anthology 5.105 0.00 0.00 0.00 0.00 0.0 0.00 0.00
Greek Anthology 5.106 0.00 0.00 0.00 0.14 0.0 0.00 0.00
Greek Anthology 5.107 0.10 0.00 0.00 0.00 0.0 0.00 0.00
Greek Anthology 5.108 0.00 0.00 0.00 0.00 0.0 0.00 0.00
Greek Anthology 5.109 0.00 0.00 0.00 0.00 0.0 0.00 0.00
Greek Anthology 5.11 0.00 0.00 0.00 0.00 0.0 0.00 0.00
Greek Anthology 5.110 0.00 0.00 0.00 0.00 0.0 0.00 0.00
tfidf_df = tfidf_df.stack().reset_index()
tfidf_df = tfidf_df.rename(columns={0:'tfidf', 'level_0': 'document','level_1': 'term', 'level_2': 'term'})
tfidf_df.sort_values(by=['document','tfidf'], ascending=[True,False]).groupby(['document']).head(10)
document term tfidf
2954 Greek Anthology 4.1 ajouté 0.232646
3933 Greek Anthology 4.1 fleurs 0.187602
4869 Greek Anthology 4.1 poète 0.162023
4511 Greek Anthology 4.1 muses 0.135984
3540 Greek Anthology 4.1 cueillie 0.116323
... ... ... ...
305104 Greek Anthology 5.99 joueuse 0.323712
306230 Greek Anthology 5.99 toucher 0.323712
305043 Greek Anthology 5.99 instrument 0.306048
305289 Greek Anthology 5.99 milieu 0.256255
304687 Greek Anthology 5.99 faire 0.238591

2140 rows × 3 columns

epigramtitle= 'Greek Anthology 5.2'
myfilter = tfidf_df['document'] == epigramtitle
tfidf_df[myfilter].sort_values(by=['document','tfidf'], ascending=[True,False]).groupby(['document']).head(10)
document term tfidf
14635 Greek Anthology 5.2 barbare 0.226372
15024 Greek Anthology 5.2 côtés 0.226372
15055 Greek Anthology 5.2 devrai 0.226372
15183 Greek Anthology 5.2 désirent 0.226372
15520 Greek Anthology 5.2 gratuitement 0.226372
16759 Greek Anthology 5.2 sthénélaïde 0.226372
16774 Greek Anthology 5.2 supplier 0.226372
17035 Greek Anthology 5.2 villes 0.226372
14348 Greek Anthology 5.2 accorde 0.210205
14722 Greek Anthology 5.2 brûler 0.210205

Les mots-clés avec le résultat le plus élévé:

tfidf_df.sort_values(by='tfidf', ascending=False).head(50)
document term tfidf
282602 Greek Anthology 5.91 parfum 0.833659
452379 Greek Anthology 5.147 tresserai 0.831331
430376 Greek Anthology 5.143 couronne 0.769574
350366 Greek Anthology 5.115 démô 0.747863
547996 Greek Anthology 5.182 dorcas 0.712228
279737 Greek Anthology 5.90 parfum 0.707856
154091 Greek Anthology 5.81 roses 0.707594
138386 Greek Anthology 5.42 déteste 0.695684
591619 Greek Anthology 5.197 jure 0.651053
268582 Greek Anthology 5.86 rapides 0.630348
471045 Greek Anthology 5.154 gracieuse 0.629178
117372 Greek Anthology 5.34 zeus 0.607010
475504 Greek Anthology 5.155 âme 0.600876
116390 Greek Anthology 5.34 or 0.573892
427511 Greek Anthology 5.142 couronne 0.567477
298692 Greek Anthology 5.97 dieu 0.564334
363537 Greek Anthology 5.119 tourne 0.560606
86234 Greek Anthology 5.24 avertit 0.559712
439544 Greek Anthology 5.146 grâces 0.558608
558754 Greek Anthology 5.186 aimes 0.544756
427601 Greek Anthology 5.142 denys 0.540659
453869 Greek Anthology 5.148 grâces 0.526554
489341 Greek Anthology 5.160 sabbat 0.518416
532536 Greek Anthology 5.176 terrible 0.515981
234114 Greek Anthology 5.71 protomachos 0.509846
309779 Greek Anthology 5.101 bonjour 0.500076
237653 Greek Anthology 5.72 vite 0.496751
331205 Greek Anthology 5.108 nom 0.491863
411970 Greek Anthology 5.136 répète 0.488525
70163 Greek Anthology 5.1 jeunes 0.471226
87079 Greek Anthology 5.24 fuir 0.469380
150680 Greek Anthology 5.292 nature 0.468573
150123 Greek Anthology 5.292 gagner 0.468573
147815 Greek Anthology 5.45 nature 0.468573
147258 Greek Anthology 5.45 gagner 0.468573
364639 Greek Anthology 5.120 dormir 0.462042
107795 Greek Anthology 5.31 or 0.459855
292947 Greek Anthology 5.95 dercylis 0.458494
292392 Greek Anthology 5.95 aphrodites 0.458494
484620 Greek Anthology 5.159 ceintures 0.456738
414868 Greek Anthology 5.137 santé 0.456704
108782 Greek Anthology 5.31 âge 0.456385
128438 Greek Anthology 5.38 simylos 0.455288
547963 Greek Anthology 5.182 dis 0.451048
474331 Greek Anthology 5.155 modelée 0.447760
146343 Greek Anthology 5.45 art 0.447596
149208 Greek Anthology 5.292 art 0.447596
49069 Greek Anthology 5.19 bouche 0.446698
37609 Greek Anthology 5.14 bouche 0.446698
40474 Greek Anthology 5.15 bouche 0.446698
def getep(c):
    for t in mes_textes:
        if t['title'] == 'Greek Anthology '+c:
            print(t)
getep('5.143')
{'title': 'Greek Anthology 5.143', 'texte': 'La couronne d’Héliodôra sur sa tête se flétrit\xa0; mais elle-même elle resplendit, couronne de sa couronne. '}