read_csv con encabezado faltante / incompleto o número irregular de columnas

Tengo un file.csv con ~ 15k filas que tienen este aspecto

 SAMPLE_TIME, POS, OFF, HISTOGRAM 2015-07-15 16:41:56, 0-0-0-0-3, 1, 2,0,5,59,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, 2015-07-15 16:42:55, 0-0-0-0-3, 1, 0,0,5,9,0,0,0,0,0,2,0,0,0,50,0, 2015-07-15 16:43:55, 0-0-0-0-3, 1, 0,0,5,5,0,0,0,0,0,2,0,0,0,0,4,0,0,0, 2015-07-15 16:44:56, 0-0-0-0-3, 1, 2,0,5,0,0,0,0,0,0,2,0,0,0,6,0,0,0,0 

Quería que se importara a pandas.DataFrame con cualquier valor aleatorio dado a la columna que no tenga un encabezado, algo como esto:

 SAMPLE_TIME, POS, OFF, HISTOGRAM 1 2 3 4 5 6 2015-07-15 16:41:56, 0-0-0-0-3, 1, 2, 0, 5, 59, 4, 0, 0, 2015-07-15 16:42:55, 0-0-0-0-3, 1, 0, 0, 5, 0, 6, 0, nan 2015-07-15 16:43:55, 0-0-0-0-3, 1, 0, 0, 5, 0, 7, nan nan 2015-07-15 16:44:56, 0-0-0-0-3, 1, 2, 0, 5, 0, 0, 2, nan 

Esto ha sido imposible de importar, ya que probé una solución diferente, como darle un encabezado específico , pero aún así no me alegro, la única forma de hacerlo funcionar es agregar un encabezado manualmente al archivo .csv . Que algo derrotan el propósito de la automatización!


Entonces probé esta solución : haciendo esto

 lines=list(csv.reader(open('file.csv'))) header, values = lines[0], lines[1:] 

lee correctamente los archivos y me da una lista de ~ 15k values elementos, cada elemento es una lista de cadenas, donde cada cadena se analiza correctamente en el campo de datos del archivo, pero cuando bash hacer esto:

 data = {h:v for h,v in zip (header, zip(*values))} df = pd.DataFrame.from_dict(data) 

o esto:

 data2 = {h:v for h,v in zip (str(xrange(16)), zip(*values))} df2 = pd.DataFrame.from_dict(data) 

Luego desaparecen las columnas sin encabezado y el orden de las columnas se mezcla completamente. ¿Alguna idea de una posible solución?

Puede crear columnas basadas en la longitud de la primera fila real:

 from tempfile import TemporaryFile with open("out.txt") as f, TemporaryFile("w+") as t: h, ln = next(f), len(next(f).split(",")) header = h.strip().split(",") f.seek(0), next(f) header += range(ln) print(pd.read_csv(f, names=header)) 

Lo que te dará:

  SAMPLE_TIME POS OFF HISTOGRAM 0 1 2 3 \ 0 2015-07-15 16:41:56 0-0-0-0-3 1 2 0 5 59 0 1 2015-07-15 16:42:55 0-0-0-0-3 1 0 0 5 9 0 2 2015-07-15 16:43:55 0-0-0-0-3 1 0 0 5 5 0 3 2015-07-15 16:44:56 0-0-0-0-3 1 2 0 5 0 0 4 5 ... 13 14 15 16 17 18 19 20 21 22 0 0 0 ... 0 0 0 0 0 NaN NaN NaN NaN NaN 1 0 0 ... 0 NaN NaN NaN NaN NaN NaN NaN NaN NaN 2 0 0 ... 4 0 0 0 NaN NaN NaN NaN NaN NaN 3 0 0 ... 0 0 0 0 NaN NaN NaN NaN NaN NaN [4 rows x 27 columns] 

O puedes limpiar el archivo antes de pasar a pandas:

 import pandas as pd from tempfile import TemporaryFile with open("in.csv") as f, TemporaryFile("w+") as t: for line in f: t.write(line.replace(" ", "")) t.seek(0) ln = len(line.strip().split(",")) header = t.readline().strip().split(",") header += range(ln) print(pd.read_csv(t,names=header)) 

Lo que te da:

  SAMPLE_TIME POS OFF HISTOGRAM 0 1 2 3 4 5 ... 11 \ 0 2015-07-1516:41:56 0-0-0-0-3 1 2 0 5 59 0 0 0 ... 0 1 2015-07-1516:42:55 0-0-0-0-3 1 0 0 5 9 0 0 0 ... 0 2 2015-07-1516:43:55 0-0-0-0-3 1 0 0 5 5 0 0 0 ... 0 3 2015-07-1516:44:56 0-0-0-0-3 1 2 0 5 0 0 0 0 ... 0 12 13 14 15 16 17 18 19 20 0 0 0 0 0 0 0 NaN NaN NaN 1 50 0 NaN NaN NaN NaN NaN NaN NaN 2 0 4 0 0 0 NaN NaN NaN NaN 3 6 0 0 0 0 NaN NaN NaN NaN [4 rows x 25 columns] 

o para soltar las columnas todas nana:

 print(pd.read_csv(f, names=header).dropna(axis=1,how="all")) 

Te dio:

  SAMPLE_TIME POS OFF HISTOGRAM 0 1 2 3 \ 0 2015-07-15 16:41:56 0-0-0-0-3 1 2 0 5 59 0 1 2015-07-15 16:42:55 0-0-0-0-3 1 0 0 5 9 0 2 2015-07-15 16:43:55 0-0-0-0-3 1 0 0 5 5 0 3 2015-07-15 16:44:56 0-0-0-0-3 1 2 0 5 0 0 4 5 ... 8 9 10 11 12 13 14 15 16 17 0 0 0 ... 2 0 0 0 0 0 0 0 0 0 1 0 0 ... 2 0 0 0 50 0 NaN NaN NaN NaN 2 0 0 ... 2 0 0 0 0 4 0 0 0 NaN 3 0 0 ... 2 0 0 0 6 0 0 0 0 NaN [4 rows x 22 columns] 

Puede dividir la columna HISTOGRAM en el nuevo DataFrame y convertirlo en original.

 print df SAMPLE_TIME, POS, OFF, \ 0 2015-07-15 16:41:56 0-0-0-0-3, 1, 1 2015-07-15 16:42:55 0-0-0-0-3, 1, 2 2015-07-15 16:43:55 0-0-0-0-3, 1, 3 2015-07-15 16:44:56 0-0-0-0-3, 1, HISTOGRAM 0 2,0,5,59,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, 1 0,0,5,9,0,0,0,0,0,2,0,0,0,50,0, 2 0,0,5,5,0,0,0,0,0,2,0,0,0,0,4,0,0,0, 3 2,0,5,0,0,0,0,0,0,2,0,0,0,6,0,0,0,0 
 #create new dataframe from column HISTOGRAM h = pd.DataFrame([ x.split(',') for x in df['HISTOGRAM'].tolist()]) print h 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 0 2 0 5 59 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 1 0 0 5 9 0 0 0 0 0 2 0 0 0 50 0 None None None None 2 0 0 5 5 0 0 0 0 0 2 0 0 0 0 4 0 0 0 None 3 2 0 5 0 0 0 0 0 0 2 0 0 0 6 0 0 0 0 None None #append to original, rename 0 column df = pd.concat([df, h], axis=1).rename(columns={0:'HISTOGRAM'}) print df HISTOGRAM HISTOGRAM 1 2 3 4 5 ... 10 \ 0 2,0,5,59,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, 2 0 5 59 0 0 ... 0 1 0,0,5,9,0,0,0,0,0,2,0,0,0,50,0, 0 0 5 9 0 0 ... 0 2 0,0,5,5,0,0,0,0,0,2,0,0,0,0,4,0,0,0, 0 0 5 5 0 0 ... 0 3 2,0,5,0,0,0,0,0,0,2,0,0,0,6,0,0,0,0 2 0 5 0 0 0 ... 0 11 12 13 14 15 16 17 18 19 0 0 0 0 0 0 0 0 0 1 0 0 50 0 None None None None 2 0 0 0 4 0 0 0 None 3 0 0 6 0 0 0 0 None None [4 rows x 24 columns] 

Entonces, ¿qué tal esto? Hice un csv a partir de sus datos de muestra.

Cuando importo lineas:

 with open('test.csv','rb') as f: lines = list(csv.reader(f)) headers, values =lines[0],lines[1:] 

para generar buenos nombres de encabezado, usa esta línea:

 headers = [i or ind for ind, i in enumerate(headers)] 

así que debido a cómo (supongo) funciona csv, los encabezados deberían tener un montón de valores de cadena vacíos. las cadenas vacías se evalúan como Falso, por lo que esta comprensión devuelve columnas numeradas para cada columna sin encabezado.

Entonces simplemente haz un df:

 df = pd.DataFrame(values,columns=headers) 

que se parece a

 11: SAMPLE_TIME POS OFF HISTOGRAM 4 5 6 7 8 9 \ 0 15/07/2015 16:41 0-0-0-0-3 1 2 0 5 59 0 0 0 1 15/07/2015 16:42 0-0-0-0-3 1 0 0 5 9 0 0 0 2 15/07/2015 16:43 0-0-0-0-3 1 0 0 5 5 0 0 0 3 15/07/2015 16:44 0-0-0-0-3 1 2 0 5 0 0 0 0 ... 12 13 14 15 16 17 18 19 20 21 0 ... 2 0 0 0 0 0 0 0 0 0 1 ... 2 0 0 0 50 0 2 ... 2 0 0 0 0 4 0 0 0 3 ... 2 0 0 0 6 0 0 0 0 [4 rows x 22 columns] 

Suponiendo que sus datos estén en un archivo llamado foo.csv, podría hacer lo siguiente. Esto fue probado contra Pandas 0.17

 df = pd.read_csv('foo.csv', names=['sample_time', 'pos', 'off', 'histogram', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17'], skiprows=1)