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 œuvre 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 voie à 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 connaît 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: 2025-05-26
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 |
anyio | 4.9.0 |
appdirs | 1.4.4 |
archspec | 0.2.3 |
asttokens | 2.4.1 |
attrs | 24.2.0 |
babel | 2.17.0 |
bcrypt | 4.2.0 |
beautifulsoup4 | 4.12.3 |
black | 24.8.0 |
blinker | 1.8.2 |
blis | 1.3.0 |
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.1.9 |
Cartopy | 0.24.1 |
catalogue | 2.0.10 |
cattrs | 24.1.3 |
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.21.1 |
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.11 |
cytoolz | 1.0.0 |
dask | 2024.9.1 |
dask-expr | 1.1.15 |
databricks-sdk | 0.33.0 |
dataclasses-json | 0.6.7 |
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 | 1.1.1 |
en_core_web_sm | 3.8.0 |
entrypoints | 0.4 |
et_xmlfile | 2.0.0 |
exceptiongroup | 1.2.2 |
executing | 2.1.0 |
fastexcel | 0.14.0 |
fastjsonschema | 2.21.1 |
fiona | 1.10.1 |
Flask | 3.0.3 |
folium | 0.19.6 |
fontawesomefree | 6.6.0 |
fonttools | 4.54.1 |
frozendict | 2.4.4 |
frozenlist | 1.4.1 |
fsspec | 2024.9.0 |
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 |
h11 | 0.16.0 |
h2 | 4.1.0 |
hpack | 4.0.0 |
htmltools | 0.6.0 |
httpcore | 1.0.9 |
httpx | 0.28.1 |
httpx-sse | 0.4.0 |
hyperframe | 6.0.1 |
idna | 3.10 |
imageio | 2.37.0 |
importlib_metadata | 8.5.0 |
importlib_resources | 6.4.5 |
inflate64 | 1.0.1 |
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 | 2025.4.1 |
jupyter-cache | 1.0.0 |
jupyter_client | 8.6.3 |
jupyter_core | 5.7.2 |
kaleido | 0.2.1 |
kiwisolver | 1.4.7 |
langchain | 0.3.25 |
langchain-community | 0.3.9 |
langchain-core | 0.3.61 |
langchain-text-splitters | 0.3.8 |
langcodes | 3.5.0 |
langsmith | 0.1.147 |
language_data | 1.3.0 |
lazy_loader | 0.4 |
libmambapy | 1.5.9 |
locket | 1.0.0 |
loguru | 0.7.3 |
lxml | 5.4.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 |
marshmallow | 3.26.1 |
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.13 |
mypy_extensions | 1.1.0 |
narwhals | 1.41.0 |
nbclient | 0.10.0 |
nbformat | 5.10.4 |
nest_asyncio | 1.6.0 |
networkx | 3.3 |
nltk | 3.9.1 |
numpy | 2.1.2 |
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 |
orjson | 3.10.18 |
OWSLib | 0.33.0 |
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.1.1 |
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.10 |
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.22.0 |
pyarrow | 17.0.0 |
pyarrow-hotfix | 0.6 |
pyasn1 | 0.6.1 |
pyasn1_modules | 0.4.1 |
pybcj | 1.0.6 |
pycosat | 0.6.6 |
pycparser | 2.22 |
pycryptodomex | 3.23.0 |
pydantic | 2.11.5 |
pydantic_core | 2.33.2 |
pydantic-settings | 2.9.1 |
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.1 |
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.3 |
referencing | 0.36.2 |
regex | 2024.9.11 |
requests | 2.32.3 |
requests-cache | 1.2.1 |
requests-toolbelt | 1.0.0 |
retrying | 1.3.4 |
rich | 14.0.0 |
rpds-py | 0.25.1 |
rsa | 4.9 |
ruamel.yaml | 0.18.6 |
ruamel.yaml.clib | 0.2.8 |
s3fs | 2024.9.0 |
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.1.0 |
smmap | 5.0.0 |
sniffio | 1.3.1 |
sortedcontainers | 2.4.0 |
soupsieve | 2.5 |
spacy | 3.8.4 |
spacy-legacy | 3.0.12 |
spacy-loggers | 1.0.5 |
SQLAlchemy | 2.0.35 |
sqlparse | 0.5.1 |
srsly | 2.5.1 |
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.3.6 |
threadpoolctl | 3.5.0 |
tifffile | 2025.5.24 |
toolz | 1.0.0 |
topojson | 1.9 |
tornado | 6.4.1 |
tqdm | 4.67.1 |
traitlets | 5.14.3 |
truststore | 0.9.2 |
typer | 0.16.0 |
typing_extensions | 4.12.2 |
typing-inspect | 0.9.0 |
typing-inspection | 0.4.1 |
tzdata | 2024.2 |
Unidecode | 1.4.0 |
url-normalize | 2.2.1 |
urllib3 | 2.2.3 |
uv | 0.7.8 |
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 |
---|---|---|---|
d6b67125 | 2025-05-23 18:03:48 | Lino Galiana | Traduction des chapitres NLP (#603) |
ff42cf23 | 2024-04-25 20:05:33 | linogaliana | Editorisalisation NLP |
005d89b8 | 2023-12-20 17:23:04 | Lino Galiana | Finalise l’affichage des statistiques Git (#478) |
4cd44f35 | 2023-12-11 17:37:50 | Antoine Palazzolo | Relecture NLP (#474) |
deaafb6f | 2023-12-11 13:44:34 | Thomas Faria | Relecture Thomas partie NLP (#472) |
1f23de28 | 2023-12-01 17:25:36 | Lino Galiana | Stockage des images sur S3 (#466) |
a1ab3d94 | 2023-11-24 10:57:02 | Lino Galiana | Reprise des chapitres NLP (#459) |
7bd768a6 | 2023-08-28 09:14:55 | linogaliana | Erreur image |
862ea4b3 | 2023-08-28 11:07:31 | Lino Galiana | Ajoute référence au post de Raschka (#398) |
3bdf3b06 | 2023-08-25 11:23:02 | Lino Galiana | Simplification de la structure 🤓 (#393) |
f2905a7d | 2023-08-11 17:24:57 | Lino Galiana | Introduction de la partie NLP (#388) |
5d4874a8 | 2023-08-11 15:09:33 | Lino Galiana | Pimp les introductions des trois premières parties (#387) |
f21a24d3 | 2023-07-02 10:58:15 | Lino Galiana | Pipeline Quarto & Pages 🚀 (#365) |
a408cc96 | 2023-02-01 09:07:27 | Lino Galiana | Ajoute bouton suggérer modification (#347) |
164fa689 | 2022-11-30 09:13:45 | Lino Galiana | Travail partie NLP (#328) |
495599d7 | 2021-12-19 18:33:05 | Lino Galiana | Des éléments supplémentaires dans la partie NLP (#202) |
4f675284 | 2021-12-12 08:37:21 | Lino Galiana | Improve website appareance (#194) |
4cdb759c | 2021-05-12 10:37:23 | Lino Galiana | :sparkles: :star2: Nouveau thème hugo :snake: :fire: (#105) |
d164635d | 2020-12-08 16:22:00 | Lino Galiana | :books: Première partie NLP (#87) |
Notes de bas de page
While writing these lines, I asked
ChatGPT
to tell me a joke.Why do programmers hate the beach? Because the sand keeps changing paradigms!
Not understanding it, I asked for an explanation. Here’s what I got:
Of course, I’d be happy to explain! This joke plays on the double meaning of the word “paradigm” and is a pun involving programming and the beach.
In programming, a “paradigm” refers to a model or method of programming, such as object-oriented or functional programming. Programmers are often familiar with different paradigms.
On the other hand, in a beach context, “paradigm” is humorously misused to mean “tide”—alluding to the natural shifting of sand and water.
The joke plays on the humorous frustration programmers might feel when adapting to new programming paradigms, just like how sand constantly shifts with the tides. By combining both meanings of “paradigm,” the joke creates an absurd and amusing scenario that will resonate with those familiar with programming and beaches.
In the end, I found the explanation funnier than the joke itself.↩︎
The concept of “natural language processing” has tended to replace the more specific term “text mining.” Text mining refers to the search for — or mining of — information within a set of texts. While it is one application area of NLP, it is not the only one. Advances in computing power and in the formalization of language have expanded the scope of fields where computational linguistics is applied.↩︎
For example, the concept of embedding—the transformation of a text field into a multidimensional numeric vector—is central in NLP today but is only briefly mentioned here.↩︎
An example of the value of this approach can be seen in ?@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.