txt todas por lineas linea leer las importar guardar gestion escribir ejercicios datos como archivos archivo python dictionary multidimensional-array enumerate readlines

todas - python: aumenta la eficacia de la búsqueda de archivos grandes por readlines(tamaño)



leer linea por linea txt python (2)

Una alternativa funcional escrita en Python 3.5. Simplifiqué tu ejemplo para que solo tomara 5 palabras en ambos lados. Existen otras simplificaciones con respecto al filtrado de valor no deseado, pero solo requerirá modificaciones menores. fn paquete fn de PyPI para hacer que este código funcional sea más natural de leer.

from typing import List, Tuple from itertools import groupby, filterfalse from fn import F

Primero necesitamos extraer la columna:

def getcol3(line: str) -> str: return line.split("/t")[2]

Entonces tenemos que dividir las líneas en bloques separados por un predicado:

TARGET_WORDS = {"target1", "target2"} # this is out predicate def istarget(word: str) -> bool: return word in TARGET_WORDS

Permite filtrar basura y escribir una función para tomar la última y las primeras 5 palabras:

def isjunk(word: str) -> bool: return word == "(unknown)" def first_and_last(words: List[str]) -> (List[str], List[str]): first = words[:5] last = words[-5:] return first, last

Ahora, vamos a los grupos:

words = (F() >> (map, str.strip) >> (filter, bool) >> (map, getcol3) >> (filterfalse, isjunk))(lines) groups = groupby(words, istarget)

Ahora, procesa los grupos

def is_target_group(group: Tuple[str, List[str]]) -> bool: return istarget(group[0]) def unpack_word_group(group: Tuple[str, List[str]]) -> List[str]: return [*group[1]] def unpack_target_group(group: Tuple[str, List[str]]) -> List[str]: return [group[0]] def process_group(group: Tuple[str, List[str]]): return (unpack_target_group(group) if is_target_group(group) else first_and_last(unpack_word_group(group)))

Y los pasos finales son:

words = list(map(process_group, groups))

PD

Este es mi caso de prueba:

from io import StringIO buffer = """ _/t_/tword _/t_/tword _/t_/tword _/t_/t(unknown) _/t_/tword _/t_/tword _/t_/ttarget1 _/t_/tword _/t_/t(unknown) _/t_/tword _/t_/tword _/t_/tword _/t_/ttarget2 _/t_/tword _/t_/t(unknown) _/t_/tword _/t_/tword _/t_/tword _/t_/t(unknown) _/t_/tword _/t_/tword _/t_/ttarget1 _/t_/tword _/t_/t(unknown) _/t_/tword _/t_/tword _/t_/tword """ # this simulates an opened file lines = StringIO(buffer)

Dado este archivo obtendrá este resultado:

[([''word'', ''word'', ''word'', ''word'', ''word''], [''word'', ''word'', ''word'', ''word'', ''word'']), ([''target1''], [''target1'']), ([''word'', ''word'', ''word'', ''word''], [''word'', ''word'', ''word'', ''word'']), ([''target2''], [''target2'']), ([''word'', ''word'', ''word'', ''word'', ''word''], [''word'', ''word'', ''word'', ''word'', ''word'']), ([''target1''], [''target1'']), ([''word'', ''word'', ''word'', ''word''], [''word'', ''word'', ''word'', ''word''])]

Desde aquí puede soltar las primeras 5 palabras y las últimas 5 palabras.

Soy nuevo en Python y actualmente estoy usando Python 2. Tengo algunos archivos fuente que constan de una gran cantidad de datos (aproximadamente 19 millones de líneas). Se parece a lo siguiente:

apple /t N /t apple n&apos garden /t N /t garden b/ta/md great /t Adj /t great nice /t Adj /t (unknown) etc

Mi tarea es buscar en la tercera columna de cada archivo algunas palabras objetivo y cada vez que se encuentra una palabra objetivo en el corpus, las 10 palabras antes y después de esta palabra deben agregarse a un diccionario multidimensional.

EDITAR: Las líneas que contienen un ''&'', un ''/' o la cadena ''(desconocido)'' deben ser excluidas.

Traté de resolver esto usando readlines () y enumerate () como puedes ver en el siguiente código. El código hace lo que debería pero obviamente no es lo suficientemente eficiente para la cantidad de datos proporcionados en el archivo fuente.

Sé que readlines () o read () no deberían usarse para grandes conjuntos de datos, ya que carga todo el archivo en la memoria. Sin embargo, al leer el archivo línea por línea, no logré usar el método enumerate para obtener las 10 palabras antes y después de la palabra objetivo. Tampoco puedo usar mmap ya que no tengo el permiso para usarlo en ese archivo.

Entonces, supongo que el método readlines con alguna limitación de tamaño sería la solución más eficiente. Sin embargo, yendo para eso, ¿no cometeré algunos errores ya que cada vez que alcanzo el límite de tamaño, las 10 palabras después de que la palabra objetivo no se capture como el código simplemente se rompe?

def get_target_to_dict(file): targets_dict = {} with open(file) as f: for line in f: targets_dict[line.strip()] = {} return targets_dict targets_dict = get_target_to_dict(''targets_uniq.txt'') # browse directory and process each file # find the target words to include the 10 words before and after to the dictionary # exclude lines starting with <,-,; to just have raw text def get_co_occurence(path_file_dir, targets, results): lines = [] for file in os.listdir(path_file_dir): if file.startswith(''corpus''): path_file = os.path.join(path_file_dir, file) with gzip.open(path_file) as corpusfile: # PROBLEMATIC CODE HERE # lines = corpusfile.readlines() for line in corpusfile: if re.match(''[A-Z]|[a-z]'', line): if ''(unknown)'' in line: continue elif ''//' in line: continue elif ''&'' in line: continue lines.append(line) for i, line in enumerate(lines): line = line.strip() if re.match(''[A-Z][a-z]'', line): parts = line.split(''/t'') lemma = parts[2] if lemma in targets: pos = parts[1] if pos not in targets[lemma]: targets[lemma][pos] = {} counts = targets[lemma][pos] context = [] # look at 10 previous lines for j in range(max(0, i-10), i): context.append(lines[j]) # look at the next 10 lines for j in range(i+1, min(i+11, len(lines))): context.append(lines[j]) # END OF PROBLEMATIC CODE for context_line in context: context_line = context_line.strip() parts_context = context_line.split(''/t'') context_lemma = parts_context[2] if context_lemma not in counts: counts[context_lemma] = {} context_pos = parts_context[1] if context_pos not in counts[context_lemma]: counts[context_lemma][context_pos] = 0 counts[context_lemma][context_pos] += 1 csvwriter = csv.writer(results, delimiter=''/t'') for k,v in targets.iteritems(): for k2,v2 in v.iteritems(): for k3,v3 in v2.iteritems(): for k4,v4 in v3.iteritems(): csvwriter.writerow([str(k), str(k2), str(k3), str(k4), str(v4)]) #print(str(k) + "/t" + str(k2) + "/t" + str(k3) + "/t" + str(k4) + "/t" + str(v4)) results = open(''results_corpus.csv'', ''wb'') word_occurrence = get_co_occurence(path_file_dir, targets_dict, results)

Copié toda la parte del código por razones de integridad ya que es parte de una función que crea un diccionario multidimensional de toda la información extraída y luego lo escribe en un archivo csv.

Realmente agradecería cualquier pista o sugerencia para hacer que este código sea más eficiente.

EDITAR Corregí el código, para que tenga en cuenta las 10 palabras exactas antes y después de la palabra objetivo


mi idea era crear un búfer para almacenar antes de 10 líneas y otro búfer para almacenar después de 10 líneas, como el archivo que se está leyendo, se insertará antes del búfer y el búfer se desactivará si el tamaño supera 10

para el buffer posterior, clono otro iterador del iterador de archivo primero. Luego ejecuta ambos iteradores en paralelo dentro del ciclo con el iterador de clonación ejecutando 10 iteraciones adelante para obtener las 10 líneas posteriores.

Esto evita usar readlines () y cargar todo el archivo en la memoria. Espero que funcione para ti en el caso real

editado: solo llene el búfer antes que el anterior si la columna 3 no contiene ninguno de ''&'', ''/', ''(desconocido)''. También cambie la división (''/ t'') en solo división () para que se encargue de todo espacio en blanco o pestaña

import itertools def get_co_occurence(path_file_dir, targets, results): excluded_words = [''&'', ''//', ''(unknown)''] # modify excluded words here for file in os.listdir(path_file_dir): if file.startswith(''testset''): path_file = os.path.join(path_file_dir, file) with open(path_file) as corpusfile: # CHANGED CODE HERE before_buf = [] # buffer to store before 10 lines after_buf = [] # buffer to store after 10 lines corpusfile, corpusfile_clone = itertools.tee(corpusfile) # clone file iterator to access next 10 lines for line in corpusfile: line = line.strip() if re.match(''[A-Z]|[a-z]'', line): parts = line.split() lemma = parts[2] # before buffer handling, fill buffer excluded line contains any of excluded words if not any(w in line for w in excluded_words): before_buf.append(line) # append to before buffer if len(before_buf)>11: before_buf.pop(0) # keep the buffer at size 10 # next buffer handling while len(after_buf)<=10: try: after = next(corpusfile_clone) # advance 1 iterator after_lemma = '''' after_tmp = after.split() if re.match(''[A-Z]|[a-z]'', after) and len(after_tmp)>2: after_lemma = after_tmp[2] except StopIteration: break # copy iterator will exhaust 1st coz its 10 iteration ahead if after_lemma and not any(w in after for w in excluded_words): after_buf.append(after) # append to buffer # print ''after'',z,after, '' - '',after_lemma if (after_buf and line in after_buf[0]): after_buf.pop(0) # pop off one ready for next if lemma in targets: pos = parts[1] if pos not in targets[lemma]: targets[lemma][pos] = {} counts = targets[lemma][pos] # context = [] # look at 10 previous lines context= before_buf[:-1] # minus out current line # look at the next 10 lines context.extend(after_buf) # END OF CHANGED CODE # CONTINUE YOUR STUFF HERE WITH CONTEXT