On distingue classiquement deux grandes catégories de données :
Une valeur numérique (digitale) consiste en:
char x; x = 'a';
x
une variable de type caractèrea
la valeur numérique (encodé):char c = '/'; int code = (int) c; System.out.println(code);
47
(le code ASCII du caractère '/
') '😃
' appartient à la norme utf-8. Pour obtenir la valeur entière correspondante :String s = "😃"; int code = s.codePointAt(0); System.out.println(code);
int code1 = 233; int code2 = 119070; char char1 = (char) code1; String char2 = new String(Character.toChars(code2)); System.out.println(char1); System.out.println(char2);
Chaîne de caractère :
String s = "bonjour";
s
est une variable"bonjour"
est une séquence de caractères for (char c : s.toCharArray()) { System.out.println(c); }
Affiche :
b o n j o u r
Le programme affiche les caractère 1 par 1, c’est une "chaîne" de plusieurs caractères individuels.
Donnée texte
Un texte, au même titre qu'un mot, est une chaîne de caractères (dont la longueur est définie par la longueur de la séquence de caractères qui définissent le texte, ponctuations, espaces et caractères de retour à la ligne compris).
Par définition les caractères séparateurs définissent la taille des espaces entre les mots, ainsi que les passages à la ligne lors de l'affichage du texte.
""
: caractère nul " "
: un espace simple"\t"
: tabulation"\n"
: passage à la ligne ("retour chariot")"\b"
: retour arrière ("backspace")Codage du texte
L'ensemble des messages possibles peut être réduit à l'ensemble des entiers naturels. En effet, chaque caractère d'un texte peut être traduit en entier en interprétant le code binaire correspondant comme un entier.
Pour traduire une chaîne de caractères en entier, il faut "construire un nombre" à partir de chaque caractère de la chaîne en prenant en compte sa position.
encode
qui effectue une telle traductionString s = "paul.poitevin@centrale-marseille.fr"; // Encodage de la chaîne en bytes en utilisant UTF-8 byte[] b = s.getBytes(); // Affichage des bytes encodés for (byte byteValue : b) { System.out.print(byteValue + " "); }
ce qui affiche:
112 97 117 108 46 112 111 105 116 101 118 105 110 64 99 101 110 116 114 97 108 101 45 109 97 114 115 101 105 108 108 101 46 102 114
Un nombre en base 256 est difficile à lire et interpréter. On le traduit en base 10 :
// Conversion des bytes en BigInteger BigInteger bigInteger = new BigInteger(b); // Affichage du résultat System.out.println("i = " + bigInteger);
Ce qui donne :
i = 852806586114976881510056778471769180697471859150728801241505293627173168229624211058
Un document texte pourra être décrit soit comme :
Recherche simple
d
: document de taille m
On cherche un algorithme qui retourne toutes les occurrences (position dans le doc) d’un certain terme t
(de taille k<m
)
t = "ami"
d
:
"Les amis de mes amis sont mes amis." ^ ^ ^ 4 16 30
on note d
le texte et t
le motif recherché dans le texte
Algo : recherche_simple Données : d, t : chaînes de caractères Début n = len (d) m = len (t) i <-- 0 tant que i < n - m: j <-- 0 tant que j < m et d[i+j] = t[j] : j += 1 si j == m : retourner i sinon : i <-- i + 1 Fin
Remarque : Il peut être nécessaire de vérifier que le terme est précédé et suivi par les caractères d’espacement pour éviter de détecter les mots dont le mot recherché est préfixe ou suffixe.
Cette approche a un inconvénient : après une comparaison infructueuse, la comparaison suivante débutera à la position i + 1, sans tenir aucun compte de celles qui ont déjà eu lieu à l'itération précédente, à la position i.
Algorithme de Boyer-Moore
L'algorithme de Boyer-Moore examine d'abord la chaîne t
et en déduit des informations permettant de ne pas comparer chaque caractère plus d'une fois.
c
appartient au motif t
en temps constantt
.i = m - 1
c
= d[i]
le dernier caractèrec
n'est pas dans t
, le décalage vaut m
k
la position de la dernière occurrence de c
dans t
k
vaut m-1
(dernier caractère), le décalage vaut m
m - 1 - k
RECHERCHE DE CHAINES CODEES EN MACHINE CHINE CHINE CHINE CHINE CHINE CHINE CHINE CHINE CHINE RECHERCHE DE CHAINES CODEES EN MACHINE
Lecture séquentielle des caractères :
"Les amis de mes amis sont mes amis." ^ position initiale de la tête de lecture
{a,à,ä,b,c,ç,d,e,é,è,ê,ë,...,z,A,B,C,...,Z,1,2,3,...,0}
{!,#,$,%,&,",',...}
remarque : pour extraire la liste des mots présents dans le texte, on doit identifier les débuts et les fins de mots :
Algo : compte-mots Données : - d : chaîne de caractères Début: nb_mots <-- 0 sep <-- Vrai pour tout c dans d: si sep est Vrai et c est alphanumérique: sep <-- Faux nb_mots <-- nb_mots + 1 sinon si sep est Faux et c est séparateur: sep <-- Vrai retourner nb_mots Fin
Code équivalent : compter les mots à l'aide d'un automate fini:
def compte_mots(d): state = 0 cpt = 0 for i in range(len(d)): if state == 0 and is_alpha(d[i]): state = 1 cpt += 1 if state == 1 and is_sep(d[i]): state = 0 return cpt
Présentation: un automate fini décrit les différentes étapes d'un calcul sous la forme d'un graphe orienté.
Pour réaliser des calculs, on a besoin d'opérandes. Les opérandes sont lus séquentiellement en entrée de l'automate. Ils obéissent à un certain alphabet (ou ensemble de symboles, …) $\Sigma$.
Enfin, des résultats de calcul sont produits en sortie de l'automate.
Plus concrètement, à chaque symbole lu en entrée, l'automate consulte une table des symboles acceptés à partir de l'état courant. Si le symbole est accepté, l'automate effectue la transition d'état, et produit une sortie (par exemple incrémenter le compteur de mots). Dans le cas contraire, il s'arrête.
Définition:
Un automate fini est défini par :
L'état initial et la séquence des symboles lus définit la séquence de symboles produits en sortie (le résultat du calcul)
La famille des automates finis définit une classe de calculs (l'ensemble des calculs réalisables par des automates finis):
Mais pas :
remarque: il existe des automates de calcul plus puissants :
permettant d'implémenter des calculs plus complexes
De manière plus générale recherche d’expressions peut être effectuée à l’aide d’automates finis non déterministes.
Remarque : pour tout automate fini non déterministe A, il existe un automate fini déterministe A′ qui reconnait le même langage (plus compliqué à écrire).
Représentation graphique :
Lecture séquentielle des caractères :
"Les amis de mes amis sont mes amis." ^ position initiale de la tête de lecture
L'automate doit reconnaître les mots suivants :
ab bab abab bbab aabab abbab babab bbbab aaabab etc..
Pour aller plus loin : Cours5.html
Exemples:
+4
, -455
, 1024
, 0
Remarques :
re
Traduction de l'automate non déterministe précédent sous forme d'expression régulière :
[ab]*ab
Remarque : les langages qui peuvent être reconnus par des expressions régulières sont appelés les langages réguliers.
Exemples de langages non réguliers:
Définition : Il s’agit d’une syntaxe “condensée” de description d’automates finis permettant de reconnaître des motifs dans un texte.
En Python, les expressions régulières sont implémentées dans la librairie re
import re d = "Les astronautes de la mission Gemini 8 sont désignés le 20 septembre 1965 : Armstrong est le commandant et David Scott le pilote. Ce dernier est le premier membre du groupe d'astronautes à recevoir une place dans l'équipage titulaire d'une mission spatiale. La mission est lancée le 16 mars 1966. Celle-ci est la plus complexe réalisée jusque-là, avec un rendez-vous et un amarrage du vaisseau Gemini avec l'étage de fusée Agena et une activité extravéhiculaire (EVA) qui constitue la deuxième sortie américaine et la troisième en tout, réalisée par Scott. La mission doit durer 75 heures et le vaisseau doit effectuer 55 orbites. Après le lancement de l'étage-cible Agena à 15 h 00 UTC, la fusée Titan II GLV transportant Armstrong et Scott décolle à 16 h 41 UTC. Une fois en orbite, la poursuite de l'étage Agena par le vaisseau Gemini 8 s'engage." liste_termes = re.findall(r"([1-9]\d*|0)", d)
a
: le caractère a[ab]
: le caractère a ou le caractère b[a-z]
: n'importe quel caractère minuscule entre a et z[^a]
: n'importe quel caractère sauf le caractère a
: le caractère espace\n
: le caractère "passage à la ligne".
: n'importe quel caractère\.
: le caractère "." uniquement[1-9]
: un chiffre entre 1 et 9\w
: n'importe quel caractère alphanumérique \s
: n'importe quel caractère d'espacement\d
: n'importe quel chiffreDef : une expression est définie comme une suite de transition. Le mot est accepté lorsque la suite de transitions est respectée
Exemple :
r"chal[eu]t"
accepte chalet et chalut
r"\w\w\w"
accepte tous les mots de 3 lettres
Branchements et itération
(artichaud)
(chien|chat)
*
: le caractère ou l'expression précédente répété entre 0 et n fois+
: le caractère ou l'expression précédente répété entre 1 et n fois?
: le caractère ou l'expression précédente répété entre 0 et 1 fois1. Caractères littéraux :
"abc"
correspond à la chaîne "abc"
.2. Caractères spéciaux :
. ^ $ * + ? { } [ ] \ | ( )
.3. Classes de caractères :
[abc]
: Correspond à un caractère qui est soit a
, b
ou c
.[^abc]
: Correspond à un caractère qui n'est pas a
, b
ou c
.[a-z]
: Correspond à un caractère alphabétique en minuscules.[A-Z]
: Correspond à un caractère alphabétique en majuscules.[0-9]
: Correspond à un chiffre.4. Caractères génériques :
.
: Correspond à n'importe quel caractère sauf une nouvelle ligne.\d
: Correspond à un chiffre (équivalent à [0-9]
).\D
: Correspond à un caractère qui n'est pas un chiffre.\w
: Correspond à un caractère alphanumérique (équivalent à [a-zA-Z0-9_]
).\W
: Correspond à un caractère qui n'est pas alphanumérique.5. Quantificateurs :
*
: Correspond à zéro ou plusieurs occurrences du caractère précédent.+
: Correspond à une ou plusieurs occurrences du caractère précédent.?
: Correspond à zéro ou une occurrence du caractère précédent.{n}
: Correspond exactement à n
occurrences du caractère précédent.{n,}
: Correspond à au moins n
occurrences du caractère précédent.{n,m}
: Correspond à entre n
et m
occurrences du caractère précédent.6. Ancrages :
^
: Correspond au début de la chaîne.$
: Correspond à la fin de la chaîne.7. Groupes et Alternatives :
()
: Crée un groupe. Par exemple, (abc)+
correspond à une ou plusieurs occurrences de "abc"
.|
: Représente une alternative (ou). Par exemple, a|b
correspond à "a"
ou "b"
.8. Échappement :
\
: Permet d'échapper un caractère spécial pour le traiter littéralement. Par exemple, \\
correspond à un seul backslash.r'\w[\.\w\-]*\w@\w[\.\w\-]*\.\w\w\w?'
Un algorithme de complétion est un mécanisme logique permettant d'anticiper la saisie et de proposer des mots automatiquement pour faciliter les recherches dans un formulaire sur une page web par exemple.
On utilise pour cela une structure de données arborescente, où chaque nœud de l'arbre est une étape de lecture et chaque arête correspond à la lecture d'une lettre. Les nœuds sont indexés par les lettres suivantes possibles du mot, avec un compteur par nœud pour savoir si celui-ci est final ou non (le nœud est final si le compteur est >0).
On commence par construire un arbre de complétion à partir de mots de vocabulaire,
L'arbre construit de cette manière est très large mais peu profond :
Une fois l'arbre construit, on l'utilise pour compléter un début de mot proposé par l'utilisateur (souvent plusieurs complétions possibles).
Exemple :
ar
{art, arbre}
On cherche à exprimer une distance entre deux chaînes de caractères. Une distance entre 2 textes d1 et d2 est telle que :
La distance de Hamming entre deux chaînes de même taille est définie comme le nombre de caractères non appariés. Ainsi la distance de Hamming entre "passoire" et "pastèque" est égale à 4.
Exemple :
p a s s o i r e | | | x x x x | p a s t e q u e
distance = 4
Peut-on généraliser cette distance à des chaînes de taille différente?
La distance d’édition est définie, pour deux chaînes de longueur quelconque, comme le nombre minimal d’opérations permettent de transformer d1 en d2, avec les opérations suivantes :
Il existe différentes manières de transformer la chaîne d1 en d2. On peut par exemple supprimer tous les caractères de d1 et insérer tous les caractères de d2, mais c'est rarement le nombre d'opérations optimal (|d1|+|d2|).
- r o b - e v | ^ | v | a r - b r e
dist = 3
r o b - e x | x v | p o r t e
dist = 3
a - r b r e x v | x ^ | p o r t - e
dist = 4
La résolution de ce problème repose sur les principes de la programmation dynamique.
Un problème d'optimisation combinatoire se caractérise par :
Le nombre de solutions possibles à un problème d'optimisation combinatoire croît exponentielleemnt avec la taille du problème. Trouver une solution par énumération à un tel problème devient rapidement impossible pour des problèmes de taille modérée.
Certains problèmes d'OC peuvent être résolus selon le principe de la programmation dynamique qui consiste à décomposer le problème en sous-problèmes (et en sous-solutions):
Dans le cas de l'appariement de chaîne:
En pratique:
Préparation
variables globales : d1, d2 : chaînes de caractères m = |d1| n = |d2|
Récursif!!
algo : distance données : i, j : etape de calcul début si i = m et j = n : retourner 0 sinon si i = m : retourner dist(i, j+1) + 1 sinon si j = n : retourner dist(i + 1, j) + 1 sinon si d1[i] = d2[j] : retourner min(dist(i, j+1) + 1, dist(i + 1, j) + 1, dist(i + 1, j + 1)) sinon retourner min(dist(i, j+1) + 1, dist(i + 1, j) + 1, dist(i + 1, j + 1) + 1) fin
Soit un document $d$ :
Une description statistique d’un texte correspond à un histogramme qui porte sur un ensemble de symboles :
Les modèles probabilistes interprètent les données de type texte comme étant générées par une distribution de probabilité $P$ inconnue.
La distribution $P$ définit le langage utilisé dans le texte. On ne s'intéresse pas au sens du message, on regarde seulement comment les symboles se répartissent dans les documents, leurs fréquences d'apparition, les régularités, …
Soit $\alpha \in A$ un symbole de l'alphabet. On note $P(X=\alpha)$ la fréquence d'apparition de ce symbole dans le langage $\mathcal{L}$ considéré.
On a par définition~: $$\sum_{\alpha \in V} P(X=\alpha) = 1$$
On s'intéresse maintenant aux fréquence d'apparition de couples de lettre successives.
Soient $\alpha$ et $\beta$ deux symboles de l'alphabet.
On notera $\boldsymbol{P}_\mathcal{L}$ la matrice des fréquences des bigrammes dans un langage $\mathcal{L}$ donné, où $P_{ij}$ donne la fréquence du bigramme $(\alpha_i,\alpha_j)$.
où
avec bien sûr : $$\sum_{(i,j) \in \{1,...,K\}^2} P_{ij}=1$$
La probabilité conditionnelle du caractère $\beta$ étant donné le caractère précédent $\alpha$ est définie comme :
$$P(Y = \beta | X=\alpha) = \frac{|\xi \in \Xi : (X,Y)=(\alpha,\beta)|}{|\xi \in \Xi : X = \alpha|}$$
Soit en français :
On peutétendre ce principe à la distribution des mots dans les textes, ce qui permet de produire des modèles génératifs de langage.
Le plongement des mots (word embedding)
Word2Vec est un algorithme d'apprentissage de représentations de mots (embeddings) développé par Tomas Mikolov et son équipe chez Google en 2013.
Il existe deux architectures principales de Word2Vec : Skip-Gram et CBOW
Dans l'approche Skip-Gram, le modèle tente de prédire les mots environnants (contexte) à partir d'un mot donné (mot central). Le processus d'apprentissage consiste à maximiser la probabilité d'observer les contextes donnés un mot central :
\[ \max \sum_{t=1}^{T} \sum_{-c \leq j \leq c, j \neq 0} \log P(w_{t+j} \mid w_t) \]
où \(T\) est la taille du corpus, \(w_t\) est le mot central, \(w_{t+j}\) est le mot contexte, et \(c\) est la taille de la fenêtre contextuelle.
Dans l'approche CBOW, le modèle tente de prédire le mot central à partir des mots contextuels (contexte). Le processus d'apprentissage consiste à maximiser la probabilité d'observer le mot central étant donnés les contextes:
\[ \max \sum_{t=1}^{T} \log P(w_t \mid w_{t-c}, \ldots, w_{t-1}, w_{t+1}, \ldots, w_{t+c}) \]
où \(T\) est la taille du corpus, \(w_t\) est le mot central, et \(w_{t-i}\) sont les mots contextuels dans la fenêtre de contexte.
Le processus d'apprentissage dans Word2Vec implique la création d'une matrice de co-occurrence, où chaque entrée représente la fréquence ou la probabilité d'occurrence conjointe de deux mots. À partir de cette matrice, le modèle ajuste les vecteurs de mots de manière itérative pour maximiser la probabilité d'observation du contexte étant donné le mot central.
Une fois l'apprentissage terminé, les vecteurs de mots obtenus (les embeddings) capturent les relations sémantiques entre les mots dans l'espace vectoriel. Des mots similaires seront représentés par des vecteurs similaires, ce qui permet d'effectuer des opérations algébriques intéressantes telles que \( \text{"roi"} - \text{"homme"} + \text{"femme"} \approx \text{"reine"} \).
Word2Vec a été révolutionnaire en raison de sa capacité à apprendre des représentations de mots utiles à partir de grands volumes de texte non annoté, et ses embeddings sont souvent utilisés comme points de départ pour de nombreuses tâches de traitement du langage naturel (NLP) et d'apprentissage automatique.