Posté par Marotte ⛧ .
En réponse au journal Analyse de texte.
Évalué à 2.
Dernière modification le 21 décembre 2015 à 23:36.
Merci encore pour toutes vos suggestions. Il faut souligner qu’elles étaient toutes plutôt pertinentes... J’ai pu appliquer beaucoup de vos conseils même si j’ai dû abandonner certains (je pense notamment au islice du module itertools, qui est exactement ce que je cherchais à faire...) parce que je suis parti sur d’autres types de variables et une nouvelle approche du problème.
D’une point de vue fonctionnel je désire ne plus saucissoner l’input à l’arrache mais essayer de découper sur les phrases en me basant sur les règles typographiques (une phrase finit par un point, '«' ouvre un dialogue (ou pas...), etc...). Ça fait nettement moins d’enregistrements en base !
D’un point de vue technique j’ai utilisé une classe afin que le code principal soit plus clair.
Donc voici le code, j’ai viré les commentaires inutiles et il est de toute façon plus concis.
#!/usr/bin/env python3"""Reader.py: Read text for sentences frequencies."""__author__="M4rotte"__copyright__="Copyright 2015, Institut Marotte for Mouling"__license__="GPL"__version__="0.3"importsysimportreimportsqlite3fromcollectionsimportCounterclassReader:def__init__(self):self.sb=''self.characters=Counter()self.sentences=Counter()self.start=re.compile(r'^(\n|)[\-–—«ÉÀÇÔÎÖÏA-Za-z]$')self.stop=re.compile(r'(.|\n)+[.!?...:]( |)$')self.nb_insert=0self.nb_update=0self.discard=re.compile(r'^(([0-9]+)([\\]+)|^//).')defread(self,f):"""Read input and populate `sentences`"""whileTrue:c=f.read(1)ifc=='\xa0':c=' 'self.sb+=cself.sb=self.sb.replace(' ',' ')ifnotc:breakifself.start.match(self.sb):continueifself.stop.match(self.sb):self.sentences[self.sb]+=1self.sb=''continueifself.sb==' 'orself.sb=='\n'orself.sb=='«'orself.sb=='»':self.sb=''defstore(self,dbfile):""" Update the database from `sentences` """connection=sqlite3.connect(dbfile)cursor=connection.cursor()cursor.execute('create table if not exists sentences (sentence text primary key unique, freq int)')## For futur use :) # cursor.execute('create virtual table if not exists fts_strings using fts4(string text, freq int, tokenize=unicode61 "remove_diacritics=0" "tokenchars= ")')# Store `sentences` into databaseforsinself.sentences.most_common():ifnotself.discard.match(s[0]):try:cursor.execute("insert into sentences values (?, ?)",(s[0],s[1]))self.nb_insert+=1exceptsqlite3.IntegrityError:self.nb_update+=1cursor.execute("update sentences set freq=freq+? where sentence = ?",(s[1],s[0]))sys.stderr.write('Database update: '+str(self.nb_insert)+' inserts '+str(self.nb_update)+' updates. \n')connection.commit()connection.commit()try:reader=Reader()reader.read(sys.stdin)reader.store('reader.sqlite')exceptKeyboardInterruptaserror:print('\n'+repr(error),file=sys.stderr)sys.stderr.flush()sys.stdout.flush()exit(1)
D’un point de vu performance je trouve que ça tourne pas mal (à partir d’une base inexistante) :
Les fichiers sont des classiques de la littérature issus de sites comme http://www.ebooksgratuits.com/ (principalement), convertis from EPUB par un script choppé sur github. Les fichiers ayant été ensuite légèrement toilettés à la main est au grep avant traitement... Ça représente 6,6M de texte UTF-8.
Voici le résultat de quelques requêtes effectuées sur la base suite au traitement de ces fichiers :
sqlite> select * from sentences order by freq desc limit 10;
M.|213
Ah !|184
« Ah !|181
- Oh !|112
- Ah !|98
Oh !|91
« Oh !|85
– Ah !|67
Eh bien !|54
- Tiens !|38
sqlite> select * from sentences where sentence like '%?' order by freq desc limit 10;
Hein ?|33
- Hein ?|27
– Pourquoi ?|18
« Eh bien ?|13
pourquoi ?|12
quoi ?|11
« Pourquoi ?|11
– Pourquoi cela ?|10
– Comment cela ?|9
« Comment ?|9
sqlite> select * from sentences where sentence like '%moule%' order by freq desc limit 10;
« Il n’y a plus de ténors, disait-il, le moule en est brisé.|1
Mme Arnoux fit exhiber les moules pour les ouvrages plus difficiles.|1
J’ai déjà noté que je devrais appliquer mon expression régulière "discard" dans la fonction read() plutôt qu’au niveau store()...
# Version 0.3
Posté par Marotte ⛧ . En réponse au journal Analyse de texte. Évalué à 2. Dernière modification le 21 décembre 2015 à 23:36.
Merci encore pour toutes vos suggestions. Il faut souligner qu’elles étaient toutes plutôt pertinentes... J’ai pu appliquer beaucoup de vos conseils même si j’ai dû abandonner certains (je pense notamment au islice du module itertools, qui est exactement ce que je cherchais à faire...) parce que je suis parti sur d’autres types de variables et une nouvelle approche du problème.
D’une point de vue fonctionnel je désire ne plus saucissoner l’input à l’arrache mais essayer de découper sur les phrases en me basant sur les règles typographiques (une phrase finit par un point, '«' ouvre un dialogue (ou pas...), etc...). Ça fait nettement moins d’enregistrements en base !
D’un point de vue technique j’ai utilisé une classe afin que le code principal soit plus clair.
Donc voici le code, j’ai viré les commentaires inutiles et il est de toute façon plus concis.
D’un point de vu performance je trouve que ça tourne pas mal (à partir d’une base inexistante) :
Les fichiers sont des classiques de la littérature issus de sites comme http://www.ebooksgratuits.com/ (principalement), convertis from EPUB par un script choppé sur github. Les fichiers ayant été ensuite légèrement toilettés à la main est au grep avant traitement... Ça représente 6,6M de texte UTF-8.
Voici le résultat de quelques requêtes effectuées sur la base suite au traitement de ces fichiers :
J’ai déjà noté que je devrais appliquer mon expression régulière "discard" dans la fonction read() plutôt qu’au niveau store()...