2014-12-17 9 views
5

Ho un .csv con la seguente struttura:Importazione di dati finanziari Into Python Pandas utilizzando read_csv

date_begin,date_end,name,name_code,active_accounts,transaction_amount,transaction_count 
1/1/2008,1/31/2008,Name_1,1001,"123,456","$7,890,123.45","67,890" 
2/1/2008,2/29/2008,Name_1,1001,"43,210","$987,654.32","109,876" 
3/1/2008,3/31/2008,Name_1,1001,"485,079","$1,265,789,433.98","777,888" 
... 
12/1/2008,12/31/2008,Name_1,1001,"87,543","$432,098,987","87,987" 
1/1/2008,1/31/2008,Name_2,1002,"268,456","$890,123.45","97,890" 
2/1/2008,2/29/2008,Name_2,1002,"53,210","$987,654.32","109,876" 
... 
etc 

Sto cercando di leggerli in in un dataframe panda utilizzando il seguente codice:

import pandas as pd 

data = pd.read_csv('my_awesome_csv.csv'),parse_dates=[[0,1]], 
        infer_datetime_format=True) 

Questo funziona bene, tranne che mi piacerebbe controllare i tipi di dati in ogni colonna. Quando eseguo il seguente codice nell'interprete scopro che i numeri tra virgolette non vengono riconosciuti come numeri, né dollari né altro.

In [10]: data.dtypes 
Out[10]: 
date_begin_date_end  object 
name      object 
name_code     int64 
active_accounts   object # Problem, I want this to be a number 
transaction_amount  object # Ditto, I want this to be a number (it's a dollar amount) 
transaction_count   object # Still a number! 
dtype: object 

Ho fatto qualche curiosare in giro nel Pandas csv documentation ma non ho trovato quello che sto cercando per circa dichiarare tipi che sono valori quando vengono salvati come stringhe con virgole e segni di dollaro nel csv. Il mio obiettivo finale qui è di essere in grado di fare alcune operazioni aritmetiche sui valori in queste colonne.

Qualche idea?

risposta

5

Si potrebbe utilizzare vectorized string methods per analizzare le colonne dopo la chiamata a read_csv:

import pandas as pd 
import decimal 
D = decimal.Decimal 

data = pd.read_csv('data', parse_dates=[[0,1]], infer_datetime_format=True) 

for col in ('active_accounts', 'transaction_count'): 
    data[col] = data[col].str.replace(r',', '').astype(int) 

data['transaction_amount'] = (data['transaction_amount'] 
           .str.replace(r'[^-+\d.]', '').astype(D)) 


print(data.dtypes) 
# date_begin_date_end object 
# name     object 
# name_code    int64 
# active_accounts   int64 
# transaction_amount  object 
# transaction_count  int64 
# dtype: object 

print(data) 

cede

date_begin_date_end name name_code active_accounts \ 
0 1/1/2008 1/31/2008 Name_1  1001   123456 
1 2/1/2008 2/29/2008 Name_
2 3/1/2008 3/31/2008 Name_1  1001   485079 
3 12/1/2008 12/31/2008 Name_1  1001   87543 
4 1/1/2008 1/31/2008 Name_2  1002   268456 
5 2/1/2008 2/29/2008 Name_

    transaction_amount transaction_count 
0   7890123.45    67890 
1   987654.32    109876 
2  1265789433.98    777888 
3   432098987    87987 
4   890123.45    97890 
5   987654.32    109876 

PS. read_csv dispone di un converters parameter con il quale è possibile fornire una funzione per analizzare le colonne problematiche. Queste funzioni vengono chiamate una volta per ogni stringa. Se hai un sacco di righe, potrebbe essere necessaria una grande quantità di chiamate di funzione Python . Gestire le colonne utilizzando metodi di stringa vettoriali, come mostrato sopra dovrebbe essere molto più veloce.

import pandas as pd 
import re 
import decimal 
D = decimal.Decimal 

def make_parser(cls): 
    def parse_commas(text): 
     return cls(re.sub(r'[^-+\d.]', '', text)) 
    return parse_commas 

to_int = make_parser(int) 
to_decimal = make_parser(D) 

data = pd.read_csv('data', parse_dates=[[0,1]], infer_datetime_format=True 
        , converters={4: to_int, 5: to_decimal, 6: to_int}) 

print(data) 

cede

date_begin_date_end name name_code active_accounts \ 
0 1/1/2008 1/31/2008 Name_1  1001   123456 
1 2/1/2008 2/29/2008 Name_
2 3/1/2008 3/31/2008 Name_1  1001   485079 
3 12/1/2008 12/31/2008 Name_1  1001   87543 
4 1/1/2008 1/31/2008 Name_2  1002   268456 
5 2/1/2008 2/29/2008 Name_

    transaction_amount transaction_count 
0   7890123.45    67890 
1   987654.32    109876 
2  1265789433.98    777888 
3   432098987    87987 
4   890123.45    97890 
5   987654.32    109876 

ei valori nella colonna transaction_amount sono decimal.Decimals:

In [64]: data.loc[0, 'transaction_amount'] 
Out[64]: Decimal('7890123.45') 
+0

Grazie per questo, sembra come una soluzione elegante e veloce. Lavoro con SAS da un po 'e sono abituato a dichiarare i formati per i dati quando importo ogni colonna, ad esempio "dollar20.2". In questo modo conservo il fatto che le unità sono dollari. Speravo che i panda potessero avere qualcosa di simile a questo, oltre a float64, int64, ecc. – invoker

+0

I panda non hanno un tipo di valuta (almeno non ancora). In Python, un modo comune per rappresentare le valute è usare il modulo 'decimal' o un [modulo di terze parti come python-money] (http://stackoverflow.com/q/1406737/190597). Lo svantaggio di utilizzare questi dati in un DataFrame panda è che i calcoli numerici non utilizzeranno più i dtypes nativi di NumPy e quindi saranno molto più lenti. Quindi se la precisione è la tua priorità principale, converti i valori in 'decimal.Decimals' (o istanze della classe Python-money equivalente). Ma se la tua priorità è la velocità, usa i float. – unutbu

+0

Ho modificato il codice 'convertitori' qui sopra per mostrare come convertire la colonna' transaction_amount' in 'decimal.Decimal's. – unutbu

Problemi correlati