# -*- coding: utf-8 -*- """ Sistema de Modelado de Tópicos Copyleft (@) 2014 CENDITEL nodo Mérida - https://planificacion.cenditel.gob.ve/trac/ """ ## @package django_topic_explorer.utils # # Métodos utilizados para realizar el pre-procesamiento # @author Jorge Redondo (jredondo at cenditel.gob.ve) # @author Centro Nacional de Desarrollo e Investigación en Tecnologías Libres # (CENDITEL) nodo Mérida - Venezuela # @copyright GNU Public License versión 2 (GPLv2) # @version 1.3 from subprocess import Popen, PIPE import shlex, os from codecs import open from nltk.corpus import stopwords import math, operator def files_to_lower(path_orig,path_dest): """! Función para convertir los archivos a sólo letras minusculas @author Jorge Redondo (jredondo at cenditel.gob.ve) @copyright GNU/GPLv2 @param path_orig Ruta de Origen @param path_dest Ruta de Destino """ files = os.listdir(path_orig) for file in files: file_string = open(path_orig+file,'r','utf8').read() f = open(path_dest+file,'w','utf8') f.write(file_string.lower()) f.close() #os.environ['FREELINGSHARE'] = '/home/jredondo/Proyectos/Analisis_del_Discurso/src/freeling/share/freeling' #Ruta de la librería del freeling os.environ['FREELINGSHARE'] = '/usr/local/share/freeling' def call_freeling(freeling_cmd,file_string): """! Función para llamar al proceso del freeling @author Jorge Redondo (jredondo at cenditel.gob.ve) @copyright GNU/GPLv2 @param freeling_cmd Recibe el subproceso a ejecutar @param file_string Recibe el contenido del archivo @return output Retorna la salida del subproceso """ p = Popen(freeling_cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE) output, err = p.communicate(file_string.encode('utf8')) print output if err < 0: return "ERROR: FALLÓ EJECUCIÓN DE FREELING" return output def clean_words(w): """! Función para limpiar la palabra de caracteres molestos @author Jorge Redondo (jredondo at cenditel.gob.ve) @copyright GNU/GPLv2 @param w Recibe la palabra @return w Retorna la palabra limpia """ w = w.encode('unicode-escape') 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') def is_pos(word,pos_list): """! Función para comparar si una palabra esta en una lista @author Jorge Redondo (jredondo at cenditel.gob.ve) @copyright GNU/GPLv2 @param word Recibe la palabra @param pos_list Recibe la lista con las palabras @return Si la palabra esta en la lista retorna Verdadero, en caso contrario retorna Falso """ for item in pos_list: if word.startswith(item): return True return False def complete_word(words_list,word): indexes = [i for i,j in enumerate(words_list) if j == word] if len(indexes) == 1: return word if len(indexes) == 0: return word index = 1 complete_word = word i1 = indexes[0] while True: for i2 in indexes[1:]: try: if words_list[i1+index] != words_list[i2+index]: return complete_word except IndexError: return complete_word complete_word += '-' + words_list[i1+index] index += 1 if indexes[1] == i1+index or i1+index == len(words_list): return complete_word def all_complete_words(words_list): """! Función para remover STOPWORDS y caracteres no deseados @author Jorge Redondo (jredondo at cenditel.gob.ve) @copyright GNU/GPLv2 @param words_list Recibe la lista de las palabras @return Las palabras pre-procesadas """ words_list = [w for w in words_list] ret_val = [] c = ''.encode('utf8') for w in words_list: c_aux = complete_word(words_list,w) if c_aux in c: continue c = c_aux ret_val += [c] return list(set(ret_val)) def select_pos(path,words_fl,pos_list=['V','A','N','R','D','P','C','I','S']): """! Función que crea los corpus sin acentos y demás excluye verbos, adjetivos, sutantivos, etc @author Jorge Redondo (jredondo at cenditel.gob.ve) @copyright GNU/GPLv2 @param path Recibe la palabra @param words_fl Recibe las palabras resultantes del freeling @param pos_list Recibe los elementos a tomar en cuenta @return output_list Retorna una lista con las palabras limpias (sin acentos) """ output_list = [] all_words_list = [] for item in words_fl.split('\n'): try: w = item.split(' ')[0] cleaned_word = clean_words(w.decode('utf8')) all_words_list += [cleaned_word] 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: # Selecciona el lema #output_list += [item.split(' ')[1]] # Selecciona la palabra original #output_list += [item.split(' ')[0]] output_list += [cleaned_word] except IndexError: pass na_file = open(path,'w','utf8') na_file.write(' '.join(all_words_list)) na_file.close() return output_list def preprocess(corpus_path,do_fl=True,pos_list = ['V','A','N','R','D','P','C','I','S']): """! Función para realizar el pre-procesamiento @author Jorge Redondo (jredondo at cenditel.gob.ve) @copyright GNU/GPLv2 @param corpus_path Recibe la ruta del corpus @param do_fl Recibe la opcion del preprocesamiento (True si se quiere ejecutar, False en caso contrario) @return ret_val Retorna un diccionario de los archivos preprocesados @return set(corpus_words) Retorna un diccionario con las palabras del corpus preprocesados """ freeling_corpus_path = corpus_path + '../freeling/' no_accent_path = corpus_path + '../noaccent/' ret_val = dict() corpus_words = [] i = 0 for file in os.listdir(corpus_path): file_string = open(corpus_path+file,'r','utf8').read() if do_fl: ## Comando por consola que ejecutará el freeling freeling_cmd = shlex.split('/usr/local/bin/analyzer -f /usr/local/share/freeling/config/es.cfg',' ') # Lematización con FREELING words_fl = call_freeling(freeling_cmd,file_string) fl_file = open(freeling_corpus_path+file,'w','utf8') fl_file.write(words_fl.decode('utf-8')) fl_file.close() else: words_fl = open(freeling_corpus_path+file,'r').read() #################################### #################################### #'V', verbos #'A', adjetivos #'N', sustantivos #'R', adverbios #'D', determinantes #'P', pronombres #'C', conjunciones #'I', interjecciones #'S', preposiciones #################################### #################################### words_fl = select_pos(no_accent_path+file,words_fl=words_fl,pos_list=pos_list) # Quitar STOPWORDS y caracteres no deseados words_pp = all_complete_words(words_fl) ret_val[file] = words_pp corpus_words += words_pp i += 1 return ret_val,set(corpus_words) def idf(file_words_pp,corpus_words): idf = {} num_docs = len(file_words_pp) for w in corpus_words: count = 0 for file,words in file_words_pp.items(): if w in words: count += 1 idf[w] = math.log(float(num_docs)/float(1+count)) return idf def generate_exluded_file(corpus_path,pp_corpus_path,file_words_pp,exclude_words): """! Función que generra el archivo de palabras excluidas @author Jorge Redondo (jredondo at cenditel.gob.ve) @copyright GNU/GPLv2 @param corpus_path Recibe la ruta del corpus @param pp_corpus_path Recibe la ruta de los archivos pre-procesados @param file_words_pp Recibe los archivos pre-procesados @param exclude_words Recibe la lista con las palabras excluidas """ excluded = open(corpus_path+'excluded.txt','w','utf8') added_files = [] repeated_count = 0 flag = False for file,words_pp in file_words_pp.items(): # Excluir documentos repetidos for aux_words_pp in added_files: if words_pp == aux_words_pp: repeated_count += 1 print "Repetido: " + file flag = True break if flag: flag = False continue if len(words_pp) <= 50: continue # Guardar archivo file_pp = open(pp_corpus_path+file,'w','utf8') added_files.append(words_pp) for w in words_pp: if w not in exclude_words and not '_' in w: file_pp.write(w + ' ') else: try: excluded.write(w.encode('utf8') + ' (' + file + ')\n') except UnicodeDecodeError: excluded.write(w + ' (' + file + ')\n') file_pp.close() excluded.close() if __name__ == '__main__': ## Ruta donde se encuentra el corpus corpus_path = '/home/rodrigo/Proyectos/Interpretacion/demo-data/corta/' orig_corpus_path = corpus_path + 'orig/' lower_corpus_path = corpus_path + 'lower/' pp_corpus_path = corpus_path + 'pp/' ## Crea los archivos de puro minusculas files_to_lower(orig_corpus_path,lower_corpus_path) ## Se realiza el pre-procesamiento file_words_pp,corpus_words = preprocess(lower_corpus_path,do_fl=True,pos_list=['A','R','V','N']) ## Palabras a excluir exclude_words = ['descripcion','justificacion','construccion','desarrollo','comunidad','comunal','proyecto','prueblo','desarrollar','mismo','nacional','pueblo','sistema','año','años'] ## Se decodifican las ñ other_words = [x.decode('utf8') for x in exclude_words] ## Se genera el archivo de vocabulario excluido generate_exluded_file(corpus_path,pp_corpus_path,file_words_pp,other_words)