1 Introduction
Les parties précédentes étaient consacrées à l’acquisition de compétences transversales pour la valorisation des données. De manière naturelle, nous nous sommes jusqu’à présent plutôt consacrés à la valorisation de données structurées, d’une dimension certes modeste mais qui ouvraient déjà énormément de problématiques à creuser. Cette partie propose maintenant de se consacrer à un sujet dont il n’est pas évident a priori que les ordinateurs s’emparent, source de débats philosophiques séculaires, de Platon à Saussure : le langage humain et sa richesse.
En faisant l’analogie entre langue et langage, c’est-à-dire en définissant ce dernier comme la capacité d’expression et de communication d’une pensée par le biais de signes et en définissant la langue comme la mise en oeuvre conventionnelle de cette capacité, on peut se placer dans les traces de la linguistique et représenter le langage sous une forme de données. Ceci ouvre la voix à l’analyse statistique ou algorithmique. Néanmoins, même s’il existe des régularités statistiques , comment des ordinateurs, qui au fond ne connaissent que le 0 et le 1, peuvent-ils s’approprier cet objet éminemment complexe qu’est le langage et qu’un humain met lui-même des années à comprendre et s’approprier ?1
2 Le traitement automatique du langage
Le traitement automatique du langage - traduction française du concept de natural language processing (NLP) - est l’ensemble des techniques permettant aux ordinateurs de comprendre, analyser, synthétiser et générer le langage humain2.
Il s’agit d’un champ disciplinaire à l’intersection de la statistique
et de la linguistique qui connait depuis quelques années un engouement
important, que ce soit d’un point de vue académique, opérationnel ou industriel.
Certaines des applications de ces techniques sont devenues incontournables
dans nos tâches quotidiennes, notamment les moteurs de recherche, la traduction
automatique et plus récemment les chatbots dont le développement connaît depuis l’émergence de ChatGPT
en décembre 2022 un rythme fou.
3 Résumé de la partie
Cette partie du cours est consacrée à l’analyse des données textuelles avec des exemples de 📖 pour s’amuser. Elle est une introduction progressive à ce sujet en se concentrant sur des concepts de base, nécessaires à la compréhension ultérieure de principes plus avancés et de techniques sophistiquées3. Cette partie présente principalement :
- Les enjeux de nettoyage de champs textuels et d’analyse de fréquence. Il s’agit de NLP un peu old school mais dont la compréhension est nécessaire pour aller plus loin ;
- La modélisation du langage, selon plusieurs approches.
Avant d’en arriver au sujet des embeddings, il est précieux de comprendre les apports et les limites de concepts comme le sac de mot (bag of words) ou la distance TF-IDF (term frequency - inverse document frequency). L’un des apports principaux des grands modèles de langage, à savoir la richesse de la fênetre contextuelle leur permettant de mieux saisir les nuances textuelles et l’intentionalité du locuteur, s’éclairent lorsqu’on saisit les limites du NLP traditionnel.
Dans une optique introductive, ce cours se focalise donc sur les approches fréquentistes, notamment l’approche sac de mot, pour faciliter l’ouverture ultérieure de la boite de Pandore que sont les embeddings.
3.1 Nettoyages textuels et analyse de fréquences
Python
est un excellent outil pour l’analyse de données textuelles.
Les méthodes de base de transformation de données textuelles ou de dictionnaires, associées à des librairies spécialisées
comme NLTK
et SpaCy
, permettent d’effectuer des tâches de normalisation et d’analyse de données textuelles de manière
très efficace. Python
est bien mieux outillé que R
pour l’analyse de
données textuelles.
Les ressources en ligne sur le sujet sont très
nombreuses et la meilleure des écoles dans le domaine reste la pratique sur un corpus à nettoyer.
Dans un premier temps, cette partie propose de revenir sur la manière de structurer et nettoyer un corpus textuel au travers de l’approche bag of words (sac de mots). Elle vise à montrer comment transformer un corpus en outil propre à une analyse statistique :
- Elle propose d’abord une introduction aux enjeux du nettoyage des données textuelles à travers l’analyse du Comte de Monte Cristo d’Alexandre Dumas ici qui permet de synthétiser rapidement l’information disponible dans un large volume de données (à l’image de la ?@fig-wordcloud-dumas)
- Elle propose ensuite une série d’exercices sur le nettoyage de textes à partir des oeuvres d’Edgar Allan Poe, Mary Shelley et H.P. Lovecraft visant à distinguer la spécificité du vocabulaire employé par chaque auteurs (par exemple ?@fig-waffle-fear). Ces exercices sont disponibles dans le deuxième chapitre de la partie.
Cette analyse fréquentiste permet de prendre du recul sur la nature des données textuelles et sur les enjeux récurrents dans la réduction de dimension de corpus en langue naturelle. Comme la statistique descriptive entraîne naturellement la modélisation, cette approche fréquentiste va généralement amener rapidement à vouloir synthétiser quelques lois derrière nos corpus textuels.
3.2 Modélisation du langage
La suite de cette partie proposera une introduction aux enjeux de modélisation
du langage. Ceux-ci sont très à la mode du fait du succès de ChatGPT
. Néanmoins, avant
d’en arriver aux grands modèles de langage (LLM), ces réseaux de neurone ayant des milliards de paramètres et entraînés sur des volumes massifs de données, il est nécessaire de passer par quelques modélisations
préliminaires.
Nous proposerons d’abord d’explorer une approche alternative, prenant en compte le contexte d’apparition d’un mot. L’introduction à la Latent Dirichlet Allocation (LDA) sera l’occasion de présenter la modélisation de documents sous la forme de topics. Celle-ci est néanmoins passée de mode au profit des méthodes liées au concept d’embedding.
Nous introduirons ainsi à la fin de cette partie du cours les enjeux de la transformation de champs textuels
sous forme de vecteurs numériques. Pour cela, nous présenterons le principe
de Word2Vec
qui permet ainsi, par exemple,
malgré une distance syntaxique importante,
de dire que sémantiquement Homme
et Femme
sont proches.
Ce chapitre est une passerelle vers le concept d’embedding, véritable
révolution récente du NLP, et qui permet de rapprocher des corpus
non seulement sur leur proximité syntaxique (partagent-ils par exemple des mots
communs ?) mais aussi sur leur proximité sémantique (partagent-ils un thème ou un sens commun ?)4. Ce passage par Word2Vec
permettra aux curieux de pouvoir ensuite passer aux modèles de type transformers, les modèles faisant aujourd’hui office de référence dans le domaine du NLP.
Pour aller plus loin
La recherche dans le domaine du NLP est très active. Il est donc recommandé de faire preuve de curiosité pour en apprendre plus car une ressource unique ne compilera pas l’ensemble des connaissances, a fortiori dans un champ de recherche aussi dynamique que le NLP.
Pour approfondir les compétences évoquées dans ce cours, je recommande vivement
ce cours d’HuggingFace
.
Pour comprendre l’architecture interne d’un LLM, ce post de Sebastian Raschka est très utile.
Ces chapitres n’épuisent pas les cas d’usage du NLP pour les data scientists. Ils n’en sont que la surface émergée de l’iceberg. Par exemple, dans le domaine de la statistique publique, un des principaux cas d’usage du NLP est l’utilisation de techniques de classification automatique pour transformer des réponses libres dans des questionnaires en champs prédéfinis dans une nomenclature. Il s’agit donc d’une adaptation, un peu spécifique à la statistique publique, grande utilisatrice de nomenclatures normalisées, de problématiques de classification multi-niveaux.
Voici un exemple sur un projet de classification automatisée des professions dans la typologie
des nomenclatures d’activités (les PCS) à partir d’un modèle entraîné par la librairie Fasttext
:
Informations additionnelles
environment files have been tested on.
Latest built version: 2024-10-12
Python version used:
'3.12.6 | packaged by conda-forge | (main, Sep 30 2024, 18:08:52) [GCC 13.3.0]'
Package | Version |
---|---|
affine | 2.4.0 |
aiobotocore | 2.15.1 |
aiohappyeyeballs | 2.4.3 |
aiohttp | 3.10.8 |
aioitertools | 0.12.0 |
aiosignal | 1.3.1 |
alembic | 1.13.3 |
altair | 5.4.1 |
aniso8601 | 9.0.1 |
annotated-types | 0.7.0 |
appdirs | 1.4.4 |
archspec | 0.2.3 |
asttokens | 2.4.1 |
attrs | 24.2.0 |
babel | 2.16.0 |
bcrypt | 4.2.0 |
beautifulsoup4 | 4.12.3 |
black | 24.8.0 |
blinker | 1.8.2 |
blis | 0.7.11 |
bokeh | 3.5.2 |
boltons | 24.0.0 |
boto3 | 1.35.23 |
botocore | 1.35.23 |
branca | 0.7.2 |
Brotli | 1.1.0 |
cachetools | 5.5.0 |
cartiflette | 0.0.2 |
Cartopy | 0.24.1 |
catalogue | 2.0.10 |
cattrs | 24.1.2 |
certifi | 2024.8.30 |
cffi | 1.17.1 |
charset-normalizer | 3.3.2 |
click | 8.1.7 |
click-plugins | 1.1.1 |
cligj | 0.7.2 |
cloudpathlib | 0.19.0 |
cloudpickle | 3.0.0 |
colorama | 0.4.6 |
comm | 0.2.2 |
commonmark | 0.9.1 |
conda | 24.9.1 |
conda-libmamba-solver | 24.7.0 |
conda-package-handling | 2.3.0 |
conda_package_streaming | 0.10.0 |
confection | 0.1.5 |
contextily | 1.6.2 |
contourpy | 1.3.0 |
cryptography | 43.0.1 |
cycler | 0.12.1 |
cymem | 2.0.8 |
cytoolz | 1.0.0 |
dask | 2024.9.1 |
dask-expr | 1.1.15 |
databricks-sdk | 0.33.0 |
debugpy | 1.8.6 |
decorator | 5.1.1 |
Deprecated | 1.2.14 |
diskcache | 5.6.3 |
distributed | 2024.9.1 |
distro | 1.9.0 |
docker | 7.1.0 |
duckdb | 0.10.1 |
en-core-web-sm | 3.7.1 |
entrypoints | 0.4 |
et-xmlfile | 1.1.0 |
exceptiongroup | 1.2.2 |
executing | 2.1.0 |
fastexcel | 0.11.6 |
fastjsonschema | 2.20.0 |
fiona | 1.10.1 |
Flask | 3.0.3 |
folium | 0.17.0 |
fontawesomefree | 6.6.0 |
fonttools | 4.54.1 |
frozendict | 2.4.4 |
frozenlist | 1.4.1 |
fsspec | 2023.12.2 |
gensim | 4.3.2 |
geographiclib | 2.0 |
geopandas | 1.0.1 |
geoplot | 0.5.1 |
geopy | 2.4.1 |
gitdb | 4.0.11 |
GitPython | 3.1.43 |
google-auth | 2.35.0 |
graphene | 3.3 |
graphql-core | 3.2.4 |
graphql-relay | 3.2.0 |
graphviz | 0.20.3 |
great-tables | 0.12.0 |
greenlet | 3.1.1 |
gunicorn | 22.0.0 |
h2 | 4.1.0 |
hpack | 4.0.0 |
htmltools | 0.5.3 |
hyperframe | 6.0.1 |
idna | 3.10 |
imageio | 2.35.1 |
importlib_metadata | 8.5.0 |
importlib_resources | 6.4.5 |
inflate64 | 1.0.0 |
ipykernel | 6.29.5 |
ipython | 8.28.0 |
itsdangerous | 2.2.0 |
jedi | 0.19.1 |
Jinja2 | 3.1.4 |
jmespath | 1.0.1 |
joblib | 1.4.2 |
jsonpatch | 1.33 |
jsonpointer | 3.0.0 |
jsonschema | 4.23.0 |
jsonschema-specifications | 2024.10.1 |
jupyter-cache | 1.0.0 |
jupyter_client | 8.6.3 |
jupyter_core | 5.7.2 |
kaleido | 0.2.1 |
kiwisolver | 1.4.7 |
langcodes | 3.4.1 |
language_data | 1.2.0 |
lazy_loader | 0.4 |
libmambapy | 1.5.9 |
locket | 1.0.0 |
lxml | 5.3.0 |
lz4 | 4.3.3 |
Mako | 1.3.5 |
mamba | 1.5.9 |
mapclassify | 2.8.1 |
marisa-trie | 1.2.1 |
Markdown | 3.6 |
markdown-it-py | 3.0.0 |
MarkupSafe | 2.1.5 |
matplotlib | 3.9.2 |
matplotlib-inline | 0.1.7 |
mdurl | 0.1.2 |
menuinst | 2.1.2 |
mercantile | 1.2.1 |
mizani | 0.11.4 |
mlflow | 2.16.2 |
mlflow-skinny | 2.16.2 |
msgpack | 1.1.0 |
multidict | 6.1.0 |
multivolumefile | 0.2.3 |
munkres | 1.1.4 |
murmurhash | 1.0.10 |
mypy-extensions | 1.0.0 |
narwhals | 1.9.3 |
nbclient | 0.10.0 |
nbformat | 5.10.4 |
nest_asyncio | 1.6.0 |
networkx | 3.3 |
nltk | 3.9.1 |
numpy | 1.26.4 |
opencv-python-headless | 4.10.0.84 |
openpyxl | 3.1.5 |
opentelemetry-api | 1.16.0 |
opentelemetry-sdk | 1.16.0 |
opentelemetry-semantic-conventions | 0.37b0 |
OWSLib | 0.28.1 |
packaging | 24.1 |
pandas | 2.2.3 |
paramiko | 3.5.0 |
parso | 0.8.4 |
partd | 1.4.2 |
pathspec | 0.12.1 |
patsy | 0.5.6 |
Pebble | 5.0.7 |
pexpect | 4.9.0 |
pickleshare | 0.7.5 |
pillow | 10.4.0 |
pip | 24.2 |
platformdirs | 4.3.6 |
plotly | 5.24.1 |
plotnine | 0.13.6 |
pluggy | 1.5.0 |
polars | 1.8.2 |
preshed | 3.0.9 |
prometheus_client | 0.21.0 |
prometheus_flask_exporter | 0.23.1 |
prompt_toolkit | 3.0.48 |
protobuf | 4.25.3 |
psutil | 6.0.0 |
ptyprocess | 0.7.0 |
pure_eval | 0.2.3 |
py7zr | 0.20.8 |
pyarrow | 17.0.0 |
pyarrow-hotfix | 0.6 |
pyasn1 | 0.6.1 |
pyasn1_modules | 0.4.1 |
pybcj | 1.0.2 |
pycosat | 0.6.6 |
pycparser | 2.22 |
pycryptodomex | 3.21.0 |
pydantic | 2.9.2 |
pydantic_core | 2.23.4 |
Pygments | 2.18.0 |
PyNaCl | 1.5.0 |
pynsee | 0.1.8 |
pyogrio | 0.10.0 |
pyOpenSSL | 24.2.1 |
pyparsing | 3.1.4 |
pyppmd | 1.1.0 |
pyproj | 3.7.0 |
pyshp | 2.3.1 |
PySocks | 1.7.1 |
python-dateutil | 2.9.0 |
python-dotenv | 1.0.1 |
python-magic | 0.4.27 |
pytz | 2024.1 |
pyu2f | 0.1.5 |
pywaffle | 1.1.1 |
PyYAML | 6.0.2 |
pyzmq | 26.2.0 |
pyzstd | 0.16.2 |
querystring_parser | 1.2.4 |
rasterio | 1.4.1 |
referencing | 0.35.1 |
regex | 2024.9.11 |
requests | 2.32.3 |
requests-cache | 1.2.1 |
retrying | 1.3.4 |
rich | 13.9.2 |
rpds-py | 0.20.0 |
rsa | 4.9 |
ruamel.yaml | 0.18.6 |
ruamel.yaml.clib | 0.2.8 |
s3fs | 2023.12.2 |
s3transfer | 0.10.2 |
scikit-image | 0.24.0 |
scikit-learn | 1.5.2 |
scipy | 1.13.0 |
seaborn | 0.13.2 |
setuptools | 74.1.2 |
shapely | 2.0.6 |
shellingham | 1.5.4 |
six | 1.16.0 |
smart-open | 7.0.5 |
smmap | 5.0.0 |
sortedcontainers | 2.4.0 |
soupsieve | 2.5 |
spacy | 3.7.5 |
spacy-legacy | 3.0.12 |
spacy-loggers | 1.0.5 |
SQLAlchemy | 2.0.35 |
sqlparse | 0.5.1 |
srsly | 2.4.8 |
stack-data | 0.6.2 |
statsmodels | 0.14.4 |
tabulate | 0.9.0 |
tblib | 3.0.0 |
tenacity | 9.0.0 |
texttable | 1.7.0 |
thinc | 8.2.5 |
threadpoolctl | 3.5.0 |
tifffile | 2024.9.20 |
toolz | 1.0.0 |
topojson | 1.9 |
tornado | 6.4.1 |
tqdm | 4.66.5 |
traitlets | 5.14.3 |
truststore | 0.9.2 |
typer | 0.12.5 |
typing_extensions | 4.12.2 |
tzdata | 2024.2 |
Unidecode | 1.3.8 |
url-normalize | 1.4.3 |
urllib3 | 1.26.20 |
wasabi | 1.1.3 |
wcwidth | 0.2.13 |
weasel | 0.4.1 |
webdriver-manager | 4.0.2 |
websocket-client | 1.8.0 |
Werkzeug | 3.0.4 |
wheel | 0.44.0 |
wordcloud | 1.9.3 |
wrapt | 1.16.0 |
xgboost | 2.1.1 |
xlrd | 2.0.1 |
xyzservices | 2024.9.0 |
yarl | 1.13.1 |
yellowbrick | 1.5 |
zict | 3.0.0 |
zipp | 3.20.2 |
zstandard | 0.23.0 |
View file history
SHA | Date | Author | Description |
---|---|---|---|
ff42cf2 | 2024-04-25 20:05:33 | linogaliana | Editorisalisation NLP |
005d89b | 2023-12-20 17:23:04 | Lino Galiana | Finalise l’affichage des statistiques Git (#478) |
4cd44f3 | 2023-12-11 17:37:50 | Antoine Palazzolo | Relecture NLP (#474) |
deaafb6 | 2023-12-11 13:44:34 | Thomas Faria | Relecture Thomas partie NLP (#472) |
1f23de2 | 2023-12-01 17:25:36 | Lino Galiana | Stockage des images sur S3 (#466) |
a1ab3d9 | 2023-11-24 10:57:02 | Lino Galiana | Reprise des chapitres NLP (#459) |
7bd768a | 2023-08-28 09:14:55 | linogaliana | Erreur image |
862ea4b | 2023-08-28 11:07:31 | Lino Galiana | Ajoute référence au post de Raschka (#398) |
3bdf3b0 | 2023-08-25 11:23:02 | Lino Galiana | Simplification de la structure 🤓 (#393) |
f2905a7 | 2023-08-11 17:24:57 | Lino Galiana | Introduction de la partie NLP (#388) |
5d4874a | 2023-08-11 15:09:33 | Lino Galiana | Pimp les introductions des trois premières parties (#387) |
f21a24d | 2023-07-02 10:58:15 | Lino Galiana | Pipeline Quarto & Pages 🚀 (#365) |
a408cc9 | 2023-02-01 09:07:27 | Lino Galiana | Ajoute bouton suggérer modification (#347) |
164fa68 | 2022-11-30 09:13:45 | Lino Galiana | Travail partie NLP (#328) |
495599d | 2021-12-19 18:33:05 | Lino Galiana | Des éléments supplémentaires dans la partie NLP (#202) |
4f67528 | 2021-12-12 08:37:21 | Lino Galiana | Improve website appareance (#194) |
4cdb759 | 2021-05-12 10:37:23 | Lino Galiana | :sparkles: :star2: Nouveau thème hugo :snake: :fire: (#105) |
d164635 | 2020-12-08 16:22:00 | Lino Galiana | :books: Première partie NLP (#87) |
Notes de bas de page
En écrivant ces lignes j’ai demandé à
ChatGPT
de me faire une blague.Pourquoi les programmeurs détestent-ils la plage ? Parce que le sable change tout le temps de paradigme !
Ne l’ayant pas comprise, je lui ai demandé de me l’expliquer. Voici sa réponse :
Bien sûr, je serais ravi de l’expliquer ! Cette blague joue sur le double sens du mot “paradigme” et fait un jeu de mots avec les notions liées à la programmation et à la plage.
Dans le domaine de la programmation, un “paradigme” désigne un modèle ou une méthode de programmation, comme la programmation orientée objet, la programmation fonctionnelle, etc. Les programmeurs sont souvent familiers avec différents paradigmes de programmation.
D’autre part, en contexte de plage, “paradigme” est utilisé pour signifier “marée qui monte et descend”, se référant à l’action naturelle du sable et de l’eau sur la plage.
La blague joue sur la frustration humoristique que peuvent ressentir les programmeurs lorsqu’ils doivent s’adapter à de nouveaux paradigmes de programmation, tout comme le sable de la plage qui change constamment avec les marées. En associant les deux sens du mot “paradigme”, la blague crée une situation absurde et amusante, faisant sourire ceux qui comprennent les références à la programmation et à la plage.
Finalement, j’ai trouvé son explication plus drôle que sa blague.↩︎
Le concept de natural language processing tend à remplacer celui de text mining dont le périmètre était plus spécifique. Le text mining renvoie à la recherche d’information - la fouille - dans un ensemble de textes. C’est l’un des champs d’applications du natural language processing mais ce n’est pas l’unique. L’accroissement des ressources de calcul et les progrès dans la formalisation du langage ont permis d’élargir le champ des domaines où la linguistique computationnelle intervient.↩︎
Par exemple, le concept d’embedding - transformation d’un champ textuel en un vecteur numérique multidimensionnel - aujourd’hui central dans le NLP n’est évoqué qu’à quelques reprises.↩︎
Un exemple d’intérêt de ce type d’approche est la ?@fig-relevanc-table-embedding.↩︎
Citation
BibTeX
@book{galiana2023,
author = {Galiana, Lino},
title = {Python pour la data science},
date = {2023},
url = {https://pythonds.linogaliana.fr/},
doi = {10.5281/zenodo.8229676},
langid = {fr}
}
Veuillez citer ce travail comme suit :
Galiana, Lino. 2023. Python pour la data science. https://doi.org/10.5281/zenodo.8229676.