python - Leggi il file delle coppie ripetute di "chiave=valore" in DataFrame




pandas (5)

Dato che hai un output, è così che affronterei il problema:

Innanzitutto crea un indice univoco basato sulla ripetibilità delle colonne,

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

lo usiamo quindi per ruotare il tuo frame di dati usando la funzione a 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

Ho un file txt con dati in questo formato. Le prime 3 righe si ripetono più volte.

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

Vorrei produrre i dati in un formato tabella, ad esempio:

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

Sto lottando per impostare le intestazioni e semplicemente scorrere i dati. Quello che ho provato finora è:

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)

L'output da questo è

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

Non proprio quello che sto cercando.


IMHO, tutte le risposte attuali sembrano troppo complicate. Quello che vorrei fare è usare '=' come parametro sep di read_csv per leggere 2 colonne e quindi pivot il DataFrame ottenuto:

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

Se non si desidera quell'indice di colonna a più livelli nel risultato, è possibile rimuoverlo:

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

Puoi usare i panda per leggere il file ed elaborare i dati. Puoi usare questo:

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 output:

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

Quello che potresti anche fare è leggere il tuo file di file testo in blocchi di 3, creare un elenco nidificato e inserirlo in un frame di dati:

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 sarebbe direttamente

  name grade class
0    1     A     B
1    2     D     A

Nota n. 1: sebbene ciò comporti più righe di codice rispetto a una soluzione pandas pura, nella mia esperienza è probabile che sia più efficiente poiché utilizza meno funzioni pandas e quindi un sovraccarico.

Nota n. 2: in generale direi che sarebbe meglio archiviare i dati di input in un altro formato, ad esempio json o csv . ciò renderebbe molto più facile la lettura, ad esempio con la funzione pandas read_csv nel caso di un file CSV.


So che hai abbastanza risposte, ma ecco un altro modo di farlo usando il dizionario:

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)

Questo ti dà l'output come:

name grade class
0    1     A     B
1    2     D     A

Solo per avere un'altra prospettiva.





pandas