2015-06-26 12 views
5

Ho molti file CSV con gli stessi titoli di colonne da analizzare. In questi file, ci possono essere diversi pattern per rappresentare NA, ad esempio: "-", "-", "/", ...Come convertire rapidamente le colonne in numeri senza conoscere i modelli di valori NA

Non conosco tutti gli schemi, quindi non posso impostare Argomento na_values per read_csv() correttamente.

C'è un modo rapido per trovare tutti i pattern NA in questi file, o senza conoscere tutti i pattern, posso ancora convertire tutte le colonne in numero? Ecco cosa ho provato:

patterns = set() 
for i, fn in enumerate(glob(u"data/*.csv")): 
    df = pd.read_csv(fn, encoding="utf-8-sig", usecols=cols, dtype=str, keep_default_na=False) 
    df_num = df.convert_objects(convert_numeric=True) 
    patterns.update(df[df_num.isnull()].stack().value_counts().index) 

Ma convert_objects() è lento. Ecco alcune prove:

  • read_csv(dtype=str): circa 2.2s
  • read_csv() senza dtype argomento: circa 2.5s
  • read_csv(dtype=str) + convert_objects(): 8.4s

Quindi, read_csv() può convertire le stringhe in numeri molto rapidamente di convert_objects(). Ma se c'è un elemento che non può essere convertito in numero, l'intera colonna diventerà una colonna di stringhe.

Esistono metodi più veloci che possono convertire tutte le colonne in numeri senza impostare l'argomento na_values?

+1

Non potresti semplicemente passare tutti i valori possibili noti per 'NaN' a' na_values'? Altrimenti, penso che sei bloccato con i tuoi attuali metodi – EdChum

+0

numpy .astype (float) è più veloce? – dmargol1

risposta

0

Perché non basta impostare l'argomento 'index_col' su False. Ciò farà sì che i panda numerino le colonne in sequenza partendo da zero, credo. Ecco quello che il codice sarà simile con il cambiamento:

patterns = set() 
for i, fn in enumerate(glob(u"data/*.csv")): 
    df = pd.read_csv(fn, encoding="utf-8-sig", index_col=False, usecols=cols, dtype=str, keep_default_na=False) 
    df_num = df.convert_objects(convert_numeric=True) 
    patterns.update(df[df_num.isnull()].stack().value_counts().index) 
+0

Non sono completamente sicuro, ma quando uso index_col = False potresti non aver più bisogno di usecols = cols. – Alex

0

Se si dispone di versione panda> = 0.17.0 si potrebbe tentare di applicare pandas.to_numeric per ogni colonna (o può essere si sa colonne sospette):

import pandas as pd 

df = pd.DataFrame({'a':[1, 2, 3, 4, 'b', 'a', 6], 'b':[0, 1, 2, 'a', 3, 4, 'b']}, dtype=str) 

Alcuni di benchmarking:

In [78]: %timeit df.convert_objects(convert_numeric=True) 
1000 loops, best of 3: 480 µs per loop 

In [79]: %timeit df.apply(pd.to_numeric, errors='coerce') 
1000 loops, best of 3: 880 µs per loop 

Abbiamo potuto vedere che è più lento quindi convert_object. Passiamo raw=True per apply:

In [82]: %timeit df.apply(pd.to_numeric, raw=True, errors='coerce') 
1000 loops, best of 3: 288 µs per loop 

E ora la cosa si fa quasi 2 volte più veloce convert_objects.

Problemi correlati