2015-04-28 10 views
8

Ho un file separato scheda con 1 miliardo di linee di questi (Imagine 200 colonne, invece di 3):leggere un file separato scheda con la prima colonna come chiave e il resto come valori

abc -0.123 0.6524 0.325 
foo -0.9808 0.874 -0.2341 
bar 0.23123 -0.123124 -0.1232 

I vuoi creare un dizionario in cui la stringa nella prima colonna è la chiave e il resto sono i valori. Ho fatto come questo, ma è computazionalmente costoso:

import io 

dictionary = {} 

with io.open('bigfile', 'r') as fin: 
    for line in fin: 
     kv = line.strip().split() 
     k, v = kv[0], kv[1:] 
     dictionary[k] = list(map(float, v)) 

Come altro posso fare ottenere il dizionario desiderato? In realtà una matrice numpy sarebbe più appropriata di una lista di float per il valore.

risposta

4

È possibile utilizzare panda per caricare il df, quindi costruire un nuovo df come desiderato e quindi chiamare to_dict:

In [99]: 

t="""abc -0.123 0.6524 0.325 
foo -0.9808 0.874 -0.2341 
bar 0.23123 -0.123124 -0.1232""" 
df = pd.read_csv(io.StringIO(t), sep='\s+', header=None) 
df = pd.DataFrame(columns = df[0], data = df.ix[:,1:].values) 
df.to_dict() 
Out[99]: 
{'abc': {0: -0.12300000000000001, 
    1: -0.98080000000000001, 
    2: 0.23123000000000002}, 
'bar': {0: 0.32500000000000001, 1: -0.2341, 2: -0.1232}, 
'foo': {0: 0.65239999999999998, 1: 0.87400000000000011, 2: -0.123124}} 

EDIT

Un metodo più dinamico e uno che sarebbe ridurre la necessità di costruire un df temporaneo:

In [121]: 

t="""abc -0.123 0.6524 0.325 
foo -0.9808 0.874 -0.2341 
bar 0.23123 -0.123124 -0.1232""" 
# determine the number of cols, we'll use this in usecols 
col_len = pd.read_csv(io.StringIO(t), sep='\s+', nrows=1).shape[1] 
col_len 
# read the first col we'll use this in names 
cols = pd.read_csv(io.StringIO(t), sep='\s+', usecols=[0], header=None)[0].values 
# now read and construct the df using the determined usecols and names from above 
df = pd.read_csv(io.StringIO(t), sep='\s+', header=None, usecols = list(range(1, col_len)), names = cols) 
df.to_dict() 
Out[121]: 
{'abc': {0: -0.12300000000000001, 
    1: -0.98080000000000001, 
    2: 0.23123000000000002}, 
'bar': {0: 0.32500000000000001, 1: -0.2341, 2: -0.1232}, 
'foo': {0: 0.65239999999999998, 1: 0.87400000000000011, 2: -0.123124}} 

Ulteriore aggiornamento

In realtà non occorre la prima lettura, la lunghezza della colonna può essere implicitamente derivato per il numero di colonne nella prima colonna in ogni caso:

In [128]: 

t="""abc -0.123 0.6524 0.325 
foo -0.9808 0.874 -0.2341 
bar 0.23123 -0.123124 -0.1232""" 
cols = pd.read_csv(io.StringIO(t), sep='\s+', usecols=[0], header=None)[0].values 
df = pd.read_csv(io.StringIO(t), sep='\s+', header=None, usecols = list(range(1, len(cols)+1)), names = cols) 
df.to_dict() 
Out[128]: 
{'abc': {0: -0.12300000000000001, 
    1: -0.98080000000000001, 
    2: 0.23123000000000002}, 
'bar': {0: 0.32500000000000001, 1: -0.2341, 2: -0.1232}, 
'foo': {0: 0.65239999999999998, 1: 0.87400000000000011, 2: -0.123124}} 
+0

posso quindi fare 'df ['foo']. Values ​​()' per ottenere un elenco ordinato tramite i tasti funzione? O il 'values ​​()' può mescolare l'ordine delle colonne? – alvas

+0

I valori sono sempre in ordine – EdChum

+0

Uh, ma il metodo dinamico starebbe leggendo un file csv di miliardi di righe tre volte? o mi sto perdendo qualcosa qui? – Zero

2

È possibile utilizzare il modulo csv per la lettura del file, per ottenere giro di dividere le linee quindi utilizzare np.array per convertire i valori float ad un oggetto array NumPy:

import csv 
import numpy as np 
dictionary = {} 
with open('bigfile.csv', 'rb') as csvfile: 
    spamreader = csv.reader(csvfile, delimiter='\t',) 
    for row in spamreader: 
     k, v = row[0], row[1:] #in python3 do k,*v = row 
     dictionary[k] = np.array(map(float, v)) 
+0

i panda saranno più veloci o più efficienti? – alvas

+0

@alvas Spiacente, non ho familiarità con i panda! quindi non ne ho idea! – Kasramvd

+0

Mi piace sapere del motivo del voto negativo, quindi se ho torto posso modificare la mia risposta e migliorarla! – Kasramvd

0

Un modo per utilizzare Pandas. Supponendo di fare df = pd.read_csv(file) e df è come

In [220]: df 
Out[220]: 
    k  a1  a2  a3 
0 abc -0.12300 0.652400 0.3250 
1 foo -0.98080 0.874000 -0.2341 
2 bar 0.23123 -0.123124 -0.1232 

Ho aggiunto i nomi di colonna fittizia, avete la flessibilità di cambiare la situazione durante la lettura del file CSV

Allora si potrebbe fare quanto segue.

In [221]: df.set_index('k').T.to_dict('list') 
Out[221]: 
{'abc': [-0.12300000000000001, 0.65239999999999998, 0.32500000000000001], 
'bar': [0.23123000000000002, -0.123124, -0.1232], 
'foo': [-0.98080000000000001, 0.87400000000000011, -0.2341]} 
2

si potrebbe fare uso di la funzione numpy.genfromtxt(), se si specifica il numero di colonne:

import numpy as np 

a = np.genfromtxt('bigfile.csv',dtype=str,usecols=(0)) 
b = np.genfromtxt('bigfile.csv',dtype=float,delimiter='\t',usecols=range(1,4)) 
                      #^enter # of cols here 

d = dict(zip(a,b.tolist())) #if you want a numpy array, just remove .tolist() 

print d 

uscita:

{'abc': [-0.123, 0.6524, 0.325], 'bar': [0.23123, -0.123124, -0.1232], 'foo': [-0.9808, 0.874, -0.2341]} 

Nota: Per trovare programatically il numero di cols si potrebbe fare:

with open('bigfile.csv', 'r') as f: 
    num_cols = len(f.readline().split()) 

e quindi utilizzare num_cols per il parametro usecols.

+0

mi sto 'linea # 1 (ottenuto 1 colonne invece di 400) 'da' b = np.genfromtxt ('bigfile', dtype = 'float', delimitatore = '\ t', usecols = intervallo (1.401) '400 è il numero di colonne. – alvas

+0

@ alvas Sei sicuro che ci sono in realtà 400 colonne separate da ''\ t''? Inoltre, non hai bisogno di quotazioni intorno a' float' – logic

+0

@alvas Dovresti anche aggiungere un'estensione a '' bigfile'', per esempio e, ''bigfile.csv'' – logic

0

Spiacente, questa non è davvero una risposta, ma è troppo lunga per un commento.

Si dice di avere 1 miliardo di righe con 200 colonne di float. Significa memoria minimo di

109 * 200 * 8 = 1.6 1012 bytes

Dà più di 1,5 G senza contare l'overhead per la dict.

Ovviamente, è possibile provare a utilizzare gli array numpy anziché gli elenchi di float, ma ogni array è piccolo (200 elementi), quindi dubito fortemente che il guadagno sia importante.

IMHO, per tanti dati, non si deve considere la fase di carico indipendentemente da come si intende elaborare i dati e se si realmente bisogno di un Dictionnary di un miliardo di record di 200 valori float ciascuno, si attuale implementazione è corretta come è un array numpy uno.

È possibile ottenere un guadagno importante nell'ulteriore elaborazione se si possiedono tutti i dati in un singolo array numpy e si è utilizzato numpy per la parte di elaborazione, ma senza saperne di più è solo una speculazione.

Problemi correlati