Manage text data sets with muliple-line text fields
Description
Contexte:
- utilisation d'une base kaggle comportant des champs texte multi-lignes
- ex: https://www.kaggle.com/datasets/crowdflower/twitter-airline-sentiment
Khiops ne traite que les champs mono-lignes, et va se contenter d'ignorer les records n'ayant pas le bon nombre de champs, avec des warnings.
Faut-il envisager:
- une évolution de Khiops
- mieux documenter cette limite, potentiellement via une Q&A
- donner dans la Q&A un exempte de script python permettant de reformater la base avec des enregistrements mono-lignes, en remplaçant les sauts de lignes par des espaces (via pandas?)
Questions/Ideas
Le format des données tabulaire admet des valeurs comportant un séparateur de champ, en mettant la valeur délimiteurs double-quotes: cf. https://fr.wikipedia.org/wiki/Comma-separated_values Ce format permet même d'avoir des valeurs multi-lignes.
Limites de Khiops
Khiops accepte ce format, à l'exception des valeurs contenant des retours à la ligne, pour les raisons suivantes:
- en cas d'erreur avec le délimiteur double-quote de fin manquant, on doit potentiellement absorber la fin du jeu de données (sans limites de Gb...)
- la solution de Khiops permet de se se réinitialiser en mode normal dès que l'on a trouvé la fin de ligne
- les lignes trop longues (au dela de 8 Mb) sont gérée avec des warning par Khiops
- l'équivalent "un record = une ligne" est supposé dans toute l'implémentation
- permet des reprises sur erreur efficaces
- permet des messages d'erreurs simples et corrects
- permet de générer un nombre aléatoire de façon reproductible pour le sampling des records
- permet le découpage d'un fichier de données en tronçon pour les traitement en parallèle, en le coupant de façon aléatoire, puis en se recalant sur la prochaine ligne pour obtenir le prochain record
- ...
Faire évoluer Khiops semble très coûteux et risqué à implémenter, pour un besoin ponctuel de mis en forme préalable.
Une nouvelle fonctionnalité dédiée?
Au delà de la Q&A et l'exemple de re-formatege via python, on pourrait éventuellement envisager une nouvelle fonctionnalité à étudier: prétraitement des jeu de données avec textes multi-lignes
- ajouter une fonctionnalité de type "Format text table"
- fonctionnalité de data management, comme le tri
- implémentation bas niveau en parallèle
- change tous les '\r' et '\n' en milieu de champ en ' '
- tronque les textes potentiellement trop long a la limite a un million de caractères
- ignore les lignes trop longues (8 millions de caractères)
- uniquement des warnings, avec en fin des stats sur le nombre de texte multi-lignes traites
Cela reste une fonctionnalité de niche, couteuse et hasardeuse, mais avec un risque limité
Context
- Khiops version: V11
Je viens de créer un jeu de test contenant des textes multi-lignes, dans LearningTest\TestKhiops\TextVariables\MultiLineTexts
Les lignes correspondantes sont ignorées, avec deux types de warning:
- pour la première ligne du texte multi-ligne: on indique qu'il manque un double-quote de fin de champs, et qu'il n'y a pas le bon nombre de champs
- pour la(les) ligne(s) suivante(s), qui est considérée comme une nouvelle ligne, on se contente d'indiquer qu'il n'y a pas le bon nombre de champs (très probablement)
warning : Data table ./Corona.txt : Record 5 : Variable TXT with value <"Quand c'est la même act...> : missing double-quote at the end of the field
warning : Data table ./Corona.txt : Record 5 : Ignored record, bad field number (2 read fields for 3 expected fields)
warning : Data table ./Corona.txt : Record 36 : Variable TXT with value <"Où trouver des informat...> : missing double-quote at the end of the field
warning : Data table ./Corona.txt : Record 36 : Ignored record, bad field number (2 read fields for 3 expected fields)
warning : Data table ./Corona.txt : Record 37 : Ignored record, bad field number (2 read fields for 3 expected fields)
warning : Data table ./Corona.txt : Record 39 : Ignored record, bad field number (2 read fields for 3 expected fields)
...
Toutes ces records multi-lignes étant ignorés, le traitement se fait sans problème sur les lignes correctes (avec texte mono-lignes), et on obtient un rapport d'analyse complet (et qui mémorise les warnings rencontrés dans les Logs de l'onglet 'Project info').
Le traitement actuel dans Khiops core est donc suffisant informer correctement l'utilisateur.
Ci-dessous un script python qui a permis de recoder le jeu de test NegativeAirlineTwwets (cf. issue https://github.com/KhiopsML/khiops/issues/566), et pourras alimenter une Q&A.
import pandas as pd
def preprocess_tweets():
"""Preprocess tweet data to remove multi-line values"""
df = pd.read_csv("Tweets.csv")
# Replace end of lines by blanks in order to obtain mono-line text fields
df = df.replace(['\r', '\n'],' ', regex=True)
# Export using the tab separator
df.to_csv("Tweets.txt", index=False, sep = '\t')
preprocess_tweets()
Pour info, si on a un jeu de données erroné avec un double-quote de fin de d'un champ multilignes manquant, python n'est pas content du tout:
Traceback (most recent call last):
File "C:\Applications\boullema\LearningTest.V10.6.0-b.0\TextDatasets\NegativeAirlineTweets\preprocess.py", line 11, in <module>
preprocess_tweets()
File "C:\Applications\boullema\LearningTest.V10.6.0-b.0\TextDatasets\NegativeAirlineTweets\preprocess.py", line 5, in preprocess_tweets
df = pd.read_csv("Tweets.csv")
^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\ProgramData\miniconda3\envs\PyCharmMiscProject\Lib\site-packages\pandas\io\parsers\readers.py", line 1026, in read_csv
return _read(filepath_or_buffer, kwds)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\ProgramData\miniconda3\envs\PyCharmMiscProject\Lib\site-packages\pandas\io\parsers\readers.py", line 626, in _read
return parser.read(nrows)
^^^^^^^^^^^^^^^^^^
File "C:\ProgramData\miniconda3\envs\PyCharmMiscProject\Lib\site-packages\pandas\io\parsers\readers.py", line 1923, in read
) = self._engine.read( # type: ignore[attr-defined]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\ProgramData\miniconda3\envs\PyCharmMiscProject\Lib\site-packages\pandas\io\parsers\c_parser_wrapper.py", line 234, in read
chunks = self._reader.read_low_memory(nrows)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "parsers.pyx", line 838, in pandas._libs.parsers.TextReader.read_low_memory
File "parsers.pyx", line 905, in pandas._libs.parsers.TextReader._read_rows
File "parsers.pyx", line 874, in pandas._libs.parsers.TextReader._tokenize_rows
File "parsers.pyx", line 891, in pandas._libs.parsers.TextReader._check_tokenize_status
File "parsers.pyx", line 2061, in pandas._libs.parsers.raise_parser_error
pandas.errors.ParserError: Error tokenizing data. C error: Expected 15 fields in line 7, saw 16
Suggestion: en cas d'erreur de type missing double-quote at the end of the field détecté au moins une fois dans l'analyse d'une base, émettre une recommandation de recodage de la base en mono-ligne?
Le jeu de données textuel https://www.kaggle.com/datasets/subhajournal/phishingemails comporte de très nombreux enregistrements multi-lignes:
- 18650 enregistrements (dont un de plus de 16 Mb)
- plus de 175000 lignes au total
Suite à analyse de ce jeu de données, Khiops dans sa version actuelle émet de nombreux messages, mais les erreurs diagnostiquées sont incomplètes l'outil est quasiment inutilisable sur ce type de corpus comportant des champs multi-lignes
- erreurs non diagnostiquées
- certaines lignes mono-champs sont à tort acceptées
- champs se terminant par un double-quote sans commencer par un double-quote acceptés à tort
- cela entraine des champs ayant à tord de très nombreuses valeurs (Khiops détecte par exemple plus de 3000 valeurs cibles, au lieu de 2...)
Il faudrait que l'outil reste utilisable même avec un corpus contenant des champs multi-lignes, en étant beaucoup moins tolérants aux erreurs:
- ignorer toute ligne comportant un champs débutant par un double-quote, mais sans double-quote à la fin
- ignorer toute ligne comportant un champs terminant par un double-quote, mais sans double-quote au début
- ignorer toute ligne avec le mauvais nombre de champs (c'est normalement déjà le cas, mais il semble y avoir un bug dans le cas d'un seul champs)
- garder une statistique globale du nombre de ligne ainsi traitées
- émettre un message récapitulatif final suggérant de prétraiter le fichier de données pour passer à des champs mono-lignes
Spécification d'évolution de la gestion des problèmes de double-quotes dans les champs de bases de données
Rappels sur l'existant
Norme d'encodage csv
cf. https://fr.wikipedia.org/wiki/Comma-separated_values
Les champs texte peuvent également être délimités par des guillemets. Lorsqu'un champ contient lui-même des guillemets, ils sont doublés afin de ne pas être considérés comme début ou fin du champ. Si un champ contient un signe utilisé comme séparateur de colonne (virgule, point-virgule, tabulation, etc.) ou comme séparateur de ligne (généralement le caractère de retour à la ligne), les guillemets sont obligatoires afin que ce signe ne soit pas confondu avec un séparateur.
Non gestion des champs multi-lignes par Khiops
Khiops ne gère pas les champs multi-lignes pour les raisons suivantes:
- gestion des erreurs
- un champ multi-lignes est spécifié en utilisant des double-quote
"en début et fin de champs - en cas d'erreur de spécification (double-quote final manquant), il n'y a pas de reprise sur erreur possible
- avec python, une seule erreur de ce type provoque un crash indescriptible
- il faut alors lire tout jusqu'à la fin de fichier
- non robustesse: une seule erreur dans un fichier de très grande taille invalide tout un traitement
- un champ multi-lignes est spécifié en utilisant des double-quote
- traitement des index de lignes
- avec des champs multi-ligne, on n'a plus l'équivalence entre ligne et enregistrement identifié par un index de ligne: tout devient alors plus complexe à gérer et à manipuler (une erreur sur un enregistrement renvoie à son index de ligne...)
- limites en volumétrie
- il n'est pas envisageable de faire évoluer Khiops sur ce point, mais il faudra que ceci soit bien documenté
Tout champ multi-ligne doit alors être préalablement recodé, par exemple en remplaçant les sauts de lignes internes aux champs multi-lignes (caractères \r et \n) par des caractères blancs).
Gestion des erreurs d'encodage par Khiops V10
Il y a quatre types d'erreur:
- E1:
"Missing end double-quote - E2:
"Missing middle " double-quote - E3:
Missing begin double-quote double-quote" - E4:
Missing internal middle " double-quote
Khiops V10 émet un warning uniquement pour les erreurs de type E1 et E2, et en cas d'erreur E1 tente de faire une reprise sur erreur en fin de ligne. Si le nombre de champs n'est pas celui attendu, la ligne est ignorée, avec un warning
Lors de l'écriture, on écrit le champs selon la norme d’encodage csv que si le champs commence par un double quote ou s'il contient un caractère séparateur. Les erreurs de type E2, E3, E4 sont donc laissées telles quelles.
Gestion des erreurs d'encodage par python pandas
Python pandas est muet sur toutes les erreurs d'encodage.
Avec l'option n_bad_lines='warn' de la méthodes read_csv, seules les lignes ayant un nombre de champs incorrect sont ignorées, avec un warning.
En cas d'erreur d'encodage multi-lignes, pandas reste muet, sauf si le fichier devant être parsé est trop gros, ce qui provoque une erreur cryptique de type memory overflow.
Proposition d’évolution Khiops V11
Lecture des champs
Toute erreur d'encodage de type E1, E2 ou E3 donne lieu à un warning.
- E3 n'était pas géré en V10, mais le warning peut dénoter un problème de fin de champ multi-ligne
- les erreurs de type E4 sont toujours tolérés de façon muette, car elles ne posent aucun problème
Pour toute erreur grave de type E1, la ligne est ignorée
- ce type d'erreur est grave, car il s'agit potentiellement de la première ligne d'un champs multi-ligne, incorrectement encodé pour Khiops
Ecriture des champs
Khiops V11 suit désormais strictement la norme d'encodage csv en entourant de double quotes tout champ contenant des doubles quotes ou des caractères séparateurs de champ.
Messages d'erreur globaux
Khiops V11 collecte les statistiques globales sur les erreurs d'encodage:
- un bilan complet est désormais présenté à l'utilisateur lors de l'utilisation de la fonctionnalité
Check database - pour tout autre traitement (apprentissage, déploiement, évaluation, tri...), en cas d'une seule erreur d'encodage, un warning global est émis pour signaler le problème, et recommander un recodage mono-lignes du jeu de données s'il comporte des champs multi-lignes
- exemple de message global:
Due to encoding errors related to missing double quotes, your dataset may contain multi-line fields. It is recommended to recode it using single-line encoding. - question: faut-il générer une erreur au lieu d'un warning pour alerter sur la non-validité potentielle des résultats obtenus: réponse oui
Impacts en back-porting Khiops V10
Pour éviter que les fichiers écrits en sortie par Khiops V10 provoquent des warnings avec Khiops V11, il faut backporter les points suivants (Size/Hours)
- écriture des champs entre double-quotes en respectant strictement la norme d'encodage csv
- ré-encodage de la base Accidents, qui comporte des champs contenant de double quotes
Nouvelle fonctionnalité d'encodage mono-ligne des champs multi-lignes
Il serait bien de prévoir une fonctionnalité d'encodage mono-lignes pour Khiops V11:
- spécification:
- menu "Format data table...", après le menu "Check database"
- ouvre une boite de dialogue très simple
- sous-fiche "Input data table" (sans onglet sampling ni sélection, comme dans la boite dialogue du Sort)
- sous-fiche "Output data table"
- bouton "Format data table"
- implémentation uniquement en séquentiel, ce qui ne pose pas de problème de reprise sur erreur
- affiches des statistiques sur le résultats, de type:
- nombre de lignes en entrée
- nombre de records en sorties
- nombre de records multi-lignes
- nombre moyen, max... de lignes par champs multi-ligne recodé
- ...
Related issue: https://github.com/KhiopsML/khiops-python/issues/413