Teaching - TAL

Page principale de l'UE


Traitement Automatique de la Langue

1. Téléchargement d'un corpus de données

Analyse de livres

Revues de films:

Classification thématique:

Classification de locuteur

Segmentation thématique

La section suivante donne plusieurs techniques de chargement des données en partant de l'automatique vers celle tout à la main (et avec un détour par la gestion du XML). Essayez la méthode automatique, si la librairie n'est pas installée, tester la procédure manuelle.

1. Chargement des données (automatique)

Si une librairie comme nltk est installée, il suffit d'utiliser les outils existants et de regarder la documentation.

Pour le corpus 20newsgroups

Par exemple, pour charger un ensemble de documents présents dans un répertoire (à raison d'un document par fichier .txt), il faut exécuter le code suivant

import nltk.corpus.reader as pt

filename = # chemin vers le repertoire
rdr = pt.CategorizedPlaintextCorpusReader(filename, r'.*\.txt', cat_pattern=r'(\w+)/*')
docs = [[rdr.raw(fileids=[f]) for f in rdr.fileids(c) ] for c in rdr.categories()]

2. Chargement des données

Outils de gestion de fichier (tools.py)

Gestion la plus simple (cf plus loin pour résoudre les problèmes d'encodage de textes)

def readAFile(nf):
    f = open(nf, 'rb')

    txt = f.readlines()
    txt = ' '.join(txt)

    f.close()
    return txt

def compteLignes(nf, fdl='\n', tbuf=16384):
    """Compte le nombre de lignes du fichier nf"""
    c = 0
    f = open(nf, 'rb')
    while True:
        buf = None
        buf = f.read(tbuf)
        if len(buf)==0:
            break
        c += buf.count(fdl)
    f.seek(-1, 2)
    car = f.read(1)
    if car != fdl:
        c += 1
    f.close()
    return c

Import des jeux de données sur le texte:

Obligation de savoir jouer (un peu) avec les expressions régulières:

  • Livre regular expresssion cookbook (dispo. gratuitement online)
  • Wikipedia regex

Code pour les livres de Gutenberg

Lecture simple d'un fichier (et gestion de l'encodage)

def read_file(fn):
    with codecs.open(fn,encoding="utf-8") as f:
        return f.read()

Note: attention à l'encodage des fichiers... Sur Gutenberg, il s'agit de l'UTF-8

Code pour Chirac/Mitterrand

import codecs
import re
from tools import * # import du fichier défini plus haut

nblignes = compteLignes(fname)
print "nblignes = %d"%nblignes

alltxts = []
labs = np.ones(nblignes)
s=codecs.open(fname, 'r','utf-8') # pour régler le codage

cpt = 0
for i in range(nblignes):
    txt = s.readline()
    #print txt

    lab = re.sub(r"<[0-9]*:[0-9]*:(.)>.*","\\1",txt)
    txt = re.sub(r"<[0-9]*:[0-9]*:.>(.*)","\\1",txt)

    #assert(lab == "C" or lab == "M")

    if lab.count('M') >0:
        labs[cpt] = -1
    alltxts.append(txt)

    cpt += 1
    if cpt %1000 ==0:
        print cpt

A vous de charger les données de test pour vérifier que tout est OK;

Code pour movies


from tools import *
import os.path

path = "/Users/vguigue/Documents/Cours/AFD/projetTexteRessources/dataSent/movies1000/"

alltxts = [] # init vide
labs = []
cpt = 0
for cl in os.listdir(path): # parcours des fichiers d'un répertoire
    print cl
    for f in os.listdir(path+cl):
        txt = readAFile(path+cl+'/'+f)
        alltxts.append(txt)
        labs.append(cpt)

    cpt += 1
 

!!! 3. Gestion du XML

Gestion des fichiers XML

Le XML permet de gérer des fichiers avec une structure arborescente, des balises, des sous-balises, et des sous-sous-balises... Il faut donc parcourir l'arbre de manière efficace, par exemple en utilisant la librairie xml de python.

Imaginons une structure type:

  • TOUSLESDOCS
    • DOC
      • DATE ... /DATE
      • TEXTE ... /TEXTE
    • /DOC
    • DOC

...

  • /TOUSLESDOCS
import os.path
import xml.etree.ElementTree as ET

   for cl in os.listdir(path2data): # tous les fichiers du repertoire (1 fichier = 1 classe)
        if cl[0] == '.':
            continue
        cptDoc = 0
        print u"reading class: ",cl,"..."
        p2file = path2data+cl+'/'+filename
        tree = ET.parse(p2file)
        root = tree.getroot()
        for child in root: # root = TOUSLESDOCS, child = DOC
            txt=u''
            for cchild in child: # cchild = DATE, TEXTE...
                ...

Gestion des données Reuter (XML + beautifulsoup)

Il est souvent utile de faire un détour par google pour trouver directement la solution de chargement d'un corpus en particulier (surtout si le corpus est connu). Pour les données Reuter:

Etape 1 Remplacer la balise BODY qui pose problème (par exemple par content):

  sed 's/BODY/content/g' reut2-000.sgm > tmp.xml

Etape 2 Installer le package BeautifulSoup qui permet de gérer ces fichiers

  pip install BeautifulSoup

Etape 3 Le code devient tout simple (avec les bons outils):

import BeautifulSoup

filename = u'tmp.xml'
f = open(filename, 'r')
data= f.read()
soup = BeautifulSoup.BeautifulSoup(data)
contents = soup.findAll('content') # recherche de la nouvelle balise
for content in contents:
    print content.text

20 newsgroups (chargement automatique avec les outils paramétrables nltk)

Base de données contenant 20 types de news. Idéal pour la catégorisation.

import nltk.corpus.reader as pt
path2data = u'/Users/vguigue/Documents/data/20news-bydate/20news-bydate-train/'

rdr = pt.CategorizedPlaintextCorpusReader(path2data, '.*/[0-9]+', encoding='latin1', cat_pattern='([\w\.]+)/*')
docs = [[rdr.raw(fileids=[f]) for f in rdr.fileids(c) ] for c in rdr.categories()]

Note: attention à l'encodage des fichiers... Dans ce corpus, il s'agit de latin1 (à spécifier dans les outils)

Corpus jeux vidéos

Le fichier sur les jeux vidéos est encodé en latin1... Ce qui pose des problèmes. De plus les balises DOCUMENT ne sont pas reconnues par beautifulsoup. Le script suivant permet de récupérer toutes les informations utiles en déjouant ces pièges.

# -*- coding: utf-8 -*-
import subprocess
from subprocess import CalledProcessError
import BeautifulSoup
import codecs

# CHEMINS vers les données
path2data = u'/Users/vguigue/Documents/data/deft07'
filename = u'corpus_jeuxvideo_learn.xml'

str = "".join([path2data,'/', filename])

# CONVERSIONS diverses pour que ça marche
# sed veut de l'UTF8...
print "conv txts"
#cmd1 = "".join(["iconv -f latin1 -t utf-8 ", str, " > tmp_utf8.xml"])
#cmd = "".join(["sed 's/DOCUMENT/content/g' tmp_utf8.xml > tmpPP.xml"])
cmd2 = "".join(["sed 's/DOCUMENT/content/g' ", str ,  "> tmpPP.xml"])
try:
#    process = subprocess.check_call(cmd1, shell=True)
#    process = subprocess.check_call(cmd, shell=True)
    process = subprocess.check_call(cmd2, shell=True)
except CalledProcessError:
    print 'erreur dans ',cmd2

# LECTURE
print "read txts"
f = codecs.open("tmpPP.xml", 'r') # ATTENTION, le fichier a déjà été converti
data= f.read()
soup = BeautifulSoup.BeautifulSoup(data)
txts = [doc.text for doc in soup.findAll('content')]
print "reading finished"
f.close()