python pandas

python - Lea el archivo de pares repetidos "clave=valor" en DataFrame



pandas (7)

Tengo un archivo txt con datos en este formato. Las primeras 3 líneas se repiten una y otra vez.

name=1 grade=A class=B name=2 grade=D class=A

Me gustaría generar los datos en un formato de tabla, por ejemplo:

name | grade | class 1 | A | B 2 | D | A

Estoy luchando por configurar los encabezados y simplemente recorrer los datos. Lo que he intentado hasta ahora es:

def myfile(filename): with open(file1) as f: for line in f: yield line.strip().split(''='',1) def pprint_df(dframe): print(tabulate(dframe, headers="keys", tablefmt="psql", showindex=False,)) #f = pd.DataFrame(myfile(''file1'') df = pd.DataFrame(myfile(''file1'')) pprint_df(df)

La salida de eso es

+-------+-----+ | 0 | 1 | |-------+-----| | name | 1 | | grade | A | | class | B | | name | 2 | | grade | D | | class | A | +-------+-----+

Realmente no es lo que estoy buscando.


Como tiene una salida, así es como trataría el problema:

Primero cree un índice único basado en la repetibilidad de las columnas,

df[''idx''] = df.groupby(df[''0''])[''0''].cumcount() + 1 print(df) 0 1 idx 0 name 1 1 1 grade A 1 2 class B 1 3 name 2 2 4 grade D 2 5 class A 2

luego usamos esto para pivotar su marco de datos usando la función de crosstab

df1 = pd.crosstab(df[''idx''],df[''0''],values=df[''1''],aggfunc=''first'').reset_index(drop=True) print(df1[[''name'',''grade'',''class'']]) 0 name grade class 0 1 A B 1 2 D A


En mi humilde opinión, todas las respuestas actuales parecen demasiado complicadas. Lo que haría, es usar ''='' como un parámetro sep de read_csv para leer 2 columnas, y luego pivot el DataFrame obtenido:

import pandas as pd df = pd.read_csv(''myfile'', sep=''='', header=None) # 0 1 # 0 name 1 # 1 grade A # 2 class B # 3 name 2 # 4 grade D # 5 class A df = df.pivot(index=df.index // len(df[0].unique()), columns=0) # 1 # 0 class grade name # 0 B A 1 # 1 A D 2

Si no desea ese índice de columna de varios niveles en el resultado, puede eliminarlo de la siguiente manera:

df.columns = df.columns.get_level_values(1) # 0 class grade name # 0 B A 1 # 1 A D 2


Esta solución supone que el formato de texto es el que usted ha descrito, pero puede modificarlo para usar una palabra diferente para indicar el comienzo de una nueva línea. Aquí, asumimos que una nueva línea comienza con el campo de name . He modificado tu función myfile() continuación, espero que te dé algunas ideas :)

def myfile(filename): d_list = [] with open(filename) as f: d_line = {} for line in f: split_line = line.rstrip("/n").split(''='') # Strip /n characters and split field and value. if (split_line[0] == ''name''): if d_line: d_list.append(d_line) # Append if there is previous line in d_line. d_line = {split_line[0]: split_line[1]} # Start a new dictionary to collect the next lines. else: d_line[split_line[0]] = split_line[1] # Add the other 2 fields to the dictionary. d_list.append(d_line) # Append the last line. return pd.DataFrame(d_list) # Turn the list of dictionaries into a DataFrame.


Lo que también podría hacer es leer su file en bloques de 3, construir una lista anidada y ponerla en un marco de datos:

from itertools import zip_longest import pandas as pd # taken from https://docs.python.org/3.7/library/itertools.html: def grouper(iterable, n, fillvalue=None): "Collect data into fixed-length chunks or blocks" # grouper(''ABCDEFG'', 3, ''x'') --> ABC DEF Gxx" args = [iter(iterable)] * n return zip_longest(*args, fillvalue=fillvalue) data = [[''name'', ''grade'', ''class'']] with open(file, ''r'') as fobj: blocks = grouper(fobj, 3) for b in blocks: data.append([i.split(''='')[-1].strip() for i in b]) df = pd.DataFrame(data[1:], columns=data[0])

df sería directamente

name grade class 0 1 A B 1 2 D A

Nota n. ° 1: Aunque esto genera más líneas de código que una solución de pandas pura, en mi experiencia es probable que sea más eficiente ya que utiliza menos funciones de pandas , por lo tanto, menos sobrecarga.

Nota # 2: En general, argumentaría que sería mejor almacenar sus datos de entrada en otro formato, por ejemplo, json o csv . eso facilitaría mucho la lectura, por ejemplo, con la función pandas read_csv en el caso de un archivo csv.


Puede generar esa salida utilizando el módulo Diccionario de Python y Pandas.

import pandas as pd from collections import defaultdict text = ''''''name=1 grade=A class=B name=2 grade=D class=A'''''' text = text.split() new_dict = defaultdict(list) for i in text: temp = i.split(''='') new_dict[temp[0]].append(temp[1]) df = pd.DataFrame(new_dict)

Este enfoque puede no ser el más eficiente, pero no utiliza ninguna de las funciones avanzadas de Pandas. Espero eso ayude.

La salida:

name grade class 0 1 A B 1 2 D A


Puede usar pandas para leer el archivo y procesar los datos. Puedes usar esto:

import pandas as pd df = pd.read_table(r''file.txt'', header=None) new = df[0].str.split("=", n=1, expand=True) new[''index''] = new.groupby(new[0])[0].cumcount() new = new.pivot(index=''index'', columns=0, values=1)

new salidas:

0 class grade name index 0 B A 1 1 A D 2


Sé que tienes suficientes respuestas, pero aquí hay otra forma de hacerlo usando el diccionario:

import pandas as pd from collections import defaultdict d = defaultdict(list) with open("text_file.txt") as f: for line in f: (key, val) = line.split(''='') d[key].append(val.replace(''/n'', '''')) df = pd.DataFrame(d) print(df)

Esto le da la salida como:

name grade class 0 1 A B 1 2 D A

Solo para tener otra perspectiva.