2014-05-05 7 views
6

Ho un file CSV con le intestazioni nella parte superiore delle colonne di dati come ...Modo più Pythonic per leggere i valori CSV in dict di liste

<Header1>, <Header2>, ... ,<HeaderN> 
<data11> , <data12> , ... ,<data1N> 
<data21> , <data12> , ... ,<data2N> 
...  , ... , ... , ... 
<dataM1> , <dataM2> , ... ,<dataMN> 

(vale a dire i dati standard tabulato)

Quando lettura di questo con DictReader sto usando un ciclo annidato per aggiungere elementi nella riga leggere all'elenco nella rispettiva tonalità

f = <path_to_some_csv_file.csv> 
dr = csv.DictReader(open(f)) 
    dict_of_lists = dr.next() 
    for k in dict_of_lists.keys(): 
     dict_of_lists[k] = [dict_of_lists[k]] 
    for line in dr: 
     for k in dict_of_lists.keys(): 
      dict_of_lists[k].append(line[k]) 

il primo ciclo, tutti i valori nel dict al lista vuota. Il prossimo loop su ogni riga letta dal file csv, da cui DictReader crea una dict di valori-chiave. Il ciclo interno aggiunge il valore alla lista corrispondente al valore della chiave corrispondente, quindi termino con l'elenco di diti desiderato. Finisco per doverlo scrivere abbastanza spesso.

La mia domanda è, c'è un modo più Python per farlo usando funzioni incorporate senza il ciclo annidato, o un idioma migliore, o un modo alternativo per memorizzare questa struttura dati in modo tale che io possa restituire un elenco indicizzabile interrogando con un valore chiave? Se è così, c'è anche un modo per formattare i dati che vengono ingeriti dalla colonna in primo piano? (per un MWE basta copiare i dati sopra in un file di testo ed eseguirlo attraverso il codice) Grazie in anticipo!

+0

'per k in dict_of_lists.keys():' -> 'per k in dict_of_lists:' –

risposta

5

A seconda del tipo di dati che si stanno memorizzando e se siete ok con l'utilizzo di NumPy, un buon modo per fare questo può essere con numpy.genfromtxt:

import numpy as np 
data = np.genfromtxt('data.csv', delimiter=',', names=True) 

Che cosa farà è di creare un numpy Structured Array, che fornisce un'interfaccia piacevole per interrogare i dati in base al nome dell'intestazione (assicurarsi di utilizzare names=True se si dispone di una riga di intestazione).

esempio, dato data.csv contenente:

a,b,c 
1,2,3 
4,5,6 
7,8,9 

è quindi possibile accedere agli elementi con:

>>> data['a']  # Column with header 'a' 
array([ 1., 4., 7.]) 
>>> data[0]   # First row 
(1.0, 2.0, 3.0) 
>>> data['c'][2]  # Specific element 
9.0 
>>> data[['a', 'c']] # Two columns 
array([(1.0, 3.0), (4.0, 6.0), (7.0, 9.0)], 
     dtype=[('a', '<f8'), ('c', '<f8')]) 

genfromtext fornisce anche un modo, come da lei richiesto, a "formattare i dati che vengono ingeriti per colonna in anticipo."

convertitori: variabile, opzionali

L'insieme di funzioni che convertono i dati di una colonna a un valore. I convertitori possono anche essere utilizzati per fornire un valore predefinito per i dati mancanti: convertitori = {3: lambda s: float (s o 0)}.

1

Se siete disposti a utilizzare una libreria di terze parti, quindi la funzione merge_with da Toolz rende tutta questa operazione una battuta:

dict_of_lists = merge_with(list, *csv.DictReader(open(f))) 

Utilizzando solo lo stdlib, un defaultdict rende il codice meno ripetitivo:

Se è necessario farlo spesso, inserirlo in una funzione, ad es. transpose_csv.

-1

È possibile utilizzare dict e impostare comprensioni per rendere il vostro intento più evidente:

dr=csv.DictReader(f) 
data={k:[v] for k, v in dr.next().items()}    # create the initial dict of lists 
for line_dict in dr: 
    {data[k].append(v) for k, v in line_dict.items()} # append to each 

È possibile utilizzare Alex Martelli's method per appiattire una lista di liste in Python per appiattire un iteratore di iteratori, che riduce ulteriormente il prima forma di:

dr=csv.DictReader(f) 
data={k:[v] for k, v in dr.next().items()} 
{data[k].append(v) for line_dict in dr for k, v in line_dict.items()} 

su Python 2.X, considerare l'utilizzo di {}.iteritems vs {}.items() se il file CSV è considerevole.


ulteriore esempio:

Assumere questo file CSV:

Header 1,Header 2,Header 3 
1,2,3 
4,5,6 
7,8,9 

Ora supponiamo che si desidera un dict di liste di ogni valore convertito in un float o int. Si può fare:

def convert(s, converter): 
    try: 
     return converter(s) 
    except Exception: 
     return s  

dr=csv.DictReader(f) 
data={k:[convert(v, float)] for k, v in dr.next().items()} 
{data[k].append(convert(v, float)) for line_dict in dr for k, v in line_dict.items()} 

print data 
# {'Header 3': [3.0, 6.0, 9.0], 'Header 2': [2.0, 5.0, 8.0], 'Header 1': [1.0, 4.0, 7.0]} 
+0

E 'in genere non Pythonic usare la comprensione (in questo caso, una serie di comprensione, di tutti cose) per eseguire un ciclo. Basta scrivere invece il ciclo esplicito, è più naturale e molto più chiaro su quello che stai facendo. – Blckknght

Problemi correlati