source: consulta_publica/utils/freeling.py

baseconstituyenteestudiantesgeneralplan_patriasala
Last change on this file was 0ff122b, checked in by rudmanmrrod <rudman22@…>, 7 años ago

Agregado módulo de gestión de perfiles de procesamiento, incorporado el módulo de visualización de modelado de tópicos

  • Propiedad mode establecida a 100755
File size: 10.7 KB
Línea 
1# -*- coding: utf-8 -*-
2"""
3Sistema de Modelado de Tópicos
4
5Copyleft (@) 2014 CENDITEL nodo Mérida - https://planificacion.cenditel.gob.ve/trac/
6"""
7## @package django_topic_explorer.utils
8#
9# Métodos utilizados para realizar el pre-procesamiento
10# @author Jorge Redondo (jredondo at cenditel.gob.ve)
11# @author <a href='http://www.cenditel.gob.ve'>Centro Nacional de Desarrollo e Investigación en Tecnologías Libres
12# (CENDITEL) nodo Mérida - Venezuela</a>
13# @copyright <a href='http://www.gnu.org/licenses/gpl-2.0.html'>GNU Public License versión 2 (GPLv2)</a>
14# @version 1.3
15from subprocess import Popen, PIPE
16import shlex, os
17from codecs import open
18from nltk.corpus import stopwords
19import math, operator
20
21def files_to_lower(path_orig,path_dest):
22    """!
23    Función para convertir los archivos a sólo letras minusculas
24   
25    @author Jorge Redondo (jredondo at cenditel.gob.ve)
26    @copyright GNU/GPLv2
27    @param path_orig Ruta de Origen
28    @param path_dest Ruta de Destino
29    """
30    files = os.listdir(path_orig)
31    for file in files:
32        file_string = open(path_orig+file,'r','utf8').read()
33        f = open(path_dest+file,'w','utf8')
34        f.write(file_string.lower())
35        f.close()
36
37#os.environ['FREELINGSHARE'] = '/home/jredondo/Proyectos/Analisis_del_Discurso/src/freeling/share/freeling'
38
39#Ruta de la librería del freeling
40os.environ['FREELINGSHARE'] = '/usr/local/share/freeling'
41def call_freeling(freeling_cmd,file_string):
42    """!
43    Función para llamar al proceso del freeling
44   
45    @author Jorge Redondo (jredondo at cenditel.gob.ve)
46    @copyright GNU/GPLv2
47    @param freeling_cmd Recibe el subproceso a ejecutar
48    @param file_string Recibe el contenido del archivo
49    @return output Retorna la salida del subproceso
50    """
51    p = Popen(freeling_cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
52    output, err = p.communicate(file_string.encode('utf8'))
53    print output
54
55    if err < 0:
56        return "ERROR: FALLÓ EJECUCIÓN DE FREELING" 
57
58    return output
59
60def clean_words(w):
61    """!
62    Función para limpiar la palabra de caracteres molestos
63   
64    @author Jorge Redondo (jredondo at cenditel.gob.ve)
65    @copyright GNU/GPLv2
66    @param w Recibe la palabra
67    @return w Retorna la palabra limpia
68    """
69    w = w.encode('unicode-escape')
70    return w.replace(u'\xe0'.encode('unicode-escape'),u'a').replace(u'\xe8'.encode('unicode-escape'),u'e').replace(u'\xec'.encode('unicode-escape'),u'i').replace(u'\xf2'.encode('unicode-escape'),u'o').replace(u'\xfa'.encode('unicode-escape'),u'u').replace(u'\xe1'.encode('unicode-escape'),u'a').replace(u'\xe9'.encode('unicode-escape'),u'e').replace(u'\xed'.encode('unicode-escape'),u'i').replace(u'\xf3'.encode('unicode-escape'),u'o').replace(u'\xfa'.encode('unicode-escape'),u'u').replace(u'á',u'a').replace(u'é',u'e').replace(u'í',u'i').replace(u'ó',u'o').replace(u'ú',u'u').replace(u'à',u'a').replace(u'Ú',u'e').replace(u'ì',u'i').replace(u'ò',u'o').replace(u'ù',u'u').decode('unicode-escape')
71
72def is_pos(word,pos_list):
73    """!
74    Función para comparar si una palabra esta en una lista
75   
76    @author Jorge Redondo (jredondo at cenditel.gob.ve)
77    @copyright GNU/GPLv2
78    @param word Recibe la palabra
79    @param pos_list Recibe la lista con las palabras
80    @return Si la palabra esta en la lista retorna Verdadero, en caso contrario retorna Falso
81    """
82    for item in pos_list:
83        if word.startswith(item): return True
84    return False
85
86def complete_word(words_list,word):
87    indexes = [i for i,j in enumerate(words_list) if j == word]
88    if len(indexes) == 1: return word
89    if len(indexes) == 0: return word
90
91    index = 1
92    complete_word = word
93    i1 = indexes[0]
94    while True:
95        for i2 in indexes[1:]:
96            try:
97                if words_list[i1+index] != words_list[i2+index]:
98                    return complete_word
99            except IndexError:
100                return complete_word
101        complete_word += '-' + words_list[i1+index]       
102        index += 1
103        if indexes[1] == i1+index or i1+index == len(words_list): 
104            return complete_word
105
106def all_complete_words(words_list):
107    """!
108    Función para remover STOPWORDS y caracteres no deseados
109   
110    @author Jorge Redondo (jredondo at cenditel.gob.ve)
111    @copyright GNU/GPLv2
112    @param words_list Recibe la lista de las palabras
113    @return Las palabras pre-procesadas
114    """
115    words_list = [w for w in words_list]
116    ret_val = []
117    c = ''.encode('utf8')
118    for w in words_list:
119        c_aux = complete_word(words_list,w)
120        if c_aux in c:
121            continue
122
123        c = c_aux
124        ret_val += [c]
125    return list(set(ret_val))
126
127
128
129def select_pos(path,words_fl,pos_list=['V','A','N','R','D','P','C','I','S']):
130    """!
131    Función que crea los corpus sin acentos y demás excluye verbos, adjetivos, sutantivos, etc
132   
133    @author Jorge Redondo (jredondo at cenditel.gob.ve)
134    @copyright GNU/GPLv2
135    @param path Recibe la palabra
136    @param words_fl Recibe las palabras resultantes del freeling
137    @param pos_list Recibe los elementos a tomar en cuenta
138    @return output_list Retorna una lista con las palabras limpias (sin acentos)
139    """
140    output_list = []
141    all_words_list = []
142    for item in words_fl.split('\n'):
143        try:
144            w = item.split(' ')[0] 
145            cleaned_word = clean_words(w.decode('utf8'))
146            all_words_list += [cleaned_word]
147            if w.decode('utf8') not in stopwords.words('spanish') and is_pos(item.split(' ')[2],pos_list) and w not in '*+.,?¿!¡":;-=/$@#“”()[]{}' and not w.isdigit() and len(w) > 3:
148                # Selecciona el lema
149                #output_list += [item.split(' ')[1]]
150                # Selecciona la palabra original
151                #output_list += [item.split(' ')[0]]
152                output_list += [cleaned_word]
153        except IndexError:
154            pass
155    na_file = open(path,'w','utf8')
156    na_file.write(' '.join(all_words_list))
157    na_file.close()
158    return output_list
159
160def preprocess(corpus_path,do_fl=True,pos_list = ['V','A','N','R','D','P','C','I','S']):
161    """!
162    Función para realizar el pre-procesamiento
163   
164    @author Jorge Redondo (jredondo at cenditel.gob.ve)
165    @copyright GNU/GPLv2
166    @param corpus_path Recibe la ruta del corpus
167    @param do_fl Recibe la opcion del preprocesamiento (True si se quiere ejecutar, False en caso contrario)
168    @return ret_val Retorna un diccionario de los archivos preprocesados
169    @return set(corpus_words) Retorna un diccionario con las palabras del corpus preprocesados
170    """
171    freeling_corpus_path = corpus_path + '../freeling/'
172    no_accent_path = corpus_path + '../noaccent/'
173    ret_val = dict()
174    corpus_words = []
175    i = 0
176    for file in os.listdir(corpus_path):
177        file_string = open(corpus_path+file,'r','utf8').read()
178        if do_fl:
179            ## Comando por consola que ejecutará el freeling
180            freeling_cmd = shlex.split('/usr/local/bin/analyzer -f /usr/local/share/freeling/config/es.cfg',' ')
181            # Lematización con FREELING
182            words_fl = call_freeling(freeling_cmd,file_string)
183            fl_file = open(freeling_corpus_path+file,'w','utf8')
184            fl_file.write(words_fl.decode('utf-8'))
185            fl_file.close()
186        else:
187            words_fl = open(freeling_corpus_path+file,'r').read()
188        ####################################
189        ####################################
190        #'V', verbos
191        #'A', adjetivos
192        #'N', sustantivos
193        #'R', adverbios
194        #'D', determinantes
195        #'P', pronombres     
196        #'C', conjunciones
197        #'I', interjecciones
198        #'S', preposiciones
199        ####################################
200        ####################################
201
202        words_fl = select_pos(no_accent_path+file,words_fl=words_fl,pos_list=pos_list)
203
204        # Quitar STOPWORDS y caracteres no deseados
205        words_pp = all_complete_words(words_fl)
206        ret_val[file] = words_pp
207        corpus_words += words_pp
208        i += 1
209
210    return ret_val,set(corpus_words)
211
212def idf(file_words_pp,corpus_words):
213    idf = {}
214    num_docs = len(file_words_pp)
215    for w in corpus_words:
216        count = 0
217        for file,words in file_words_pp.items():
218            if w in words: count += 1
219        idf[w] = math.log(float(num_docs)/float(1+count))
220    return idf
221
222def generate_exluded_file(corpus_path,pp_corpus_path,file_words_pp,exclude_words):
223    """!
224    Función que generra el archivo de palabras excluidas
225   
226    @author Jorge Redondo (jredondo at cenditel.gob.ve)
227    @copyright GNU/GPLv2
228    @param corpus_path Recibe la ruta del corpus
229    @param pp_corpus_path Recibe la ruta de los archivos pre-procesados
230    @param file_words_pp Recibe los archivos pre-procesados
231    @param exclude_words Recibe la lista con las palabras excluidas
232    """
233    excluded = open(corpus_path+'excluded.txt','w','utf8')
234    added_files = []
235    repeated_count = 0
236    flag = False
237    for file,words_pp in file_words_pp.items():
238        # Excluir documentos repetidos
239        for aux_words_pp in added_files:
240            if words_pp == aux_words_pp:
241                repeated_count += 1
242                print "Repetido: " + file
243                flag = True
244                break
245        if flag:
246            flag = False
247            continue
248             
249        if len(words_pp) <= 50: continue
250        # Guardar archivo
251        file_pp = open(pp_corpus_path+file,'w','utf8')
252        added_files.append(words_pp)
253        for w in words_pp:
254            if w not in exclude_words and not '_' in w:
255                file_pp.write(w + ' ')
256            else:
257                try:
258                    excluded.write(w.encode('utf8') + ' (' + file + ')\n')
259                except UnicodeDecodeError:
260                    excluded.write(w + ' (' + file + ')\n')
261        file_pp.close()
262    excluded.close()
263
264 
265if __name__ == '__main__':
266   
267    ## Ruta donde se encuentra el corpus
268    corpus_path = '/home/rodrigo/Proyectos/Interpretacion/demo-data/corta/'
269    orig_corpus_path = corpus_path + 'orig/'
270    lower_corpus_path = corpus_path + 'lower/'
271    pp_corpus_path = corpus_path + 'pp/'
272   
273    ## Crea los archivos de puro minusculas
274    files_to_lower(orig_corpus_path,lower_corpus_path)
275   
276    ## Se realiza el pre-procesamiento
277    file_words_pp,corpus_words = preprocess(lower_corpus_path,do_fl=True,pos_list=['A','R','V','N'])
278    ## Palabras a excluir
279    exclude_words = ['descripcion','justificacion','construccion','desarrollo','comunidad','comunal','proyecto','prueblo','desarrollar','mismo','nacional','pueblo','sistema','año','años']
280    ## Se decodifican las ñ
281    other_words = [x.decode('utf8') for x in exclude_words]
282    ## Se genera el archivo de vocabulario excluido
283    generate_exluded_file(corpus_path,pp_corpus_path,file_words_pp,other_words)
284   
285
Nota: Vea TracBrowser para ayuda de uso del navegador del repositorio.