2016-04-18 10 views
7

Ho giocato con una funzione che assume i dati CSV e utilizza la funzione to_dict di pand come una delle fasi verso l'obiettivo finale della conversione dei dati in JSON. Il problema è che sta modificando i numeri (ad esempio 1.6 diventa 1.6000000000000001). Non sono preoccupato per la perdita di precisione, ma poiché gli utenti vedranno il cambiamento nei numeri, sembra ... dilettantesco.Pandas to_dict che modifica i numeri

Sono consapevole che questo è qualcosa che è venuto fuori prima dello here, ma era 2 anni fa, non mi è stata data una risposta soddisfacente, e ho un'ulteriore complicazione: i frame di dati che sto cercando di convertire nei dizionari potrebbe essere una qualsiasi combinazione di tipi di dati. Come tale il problema con le soluzioni precedenti sono:

  1. La conversione di tutti i numeri per oggetti funziona solo se non avete bisogno di usare i numeri - voglio la possibilità di calcolare le somme e le medie, che reintroduce il problema decimale aggiunta
  2. Forza arrotondamento dei numeri per x decimali sarà o ridurre la precisione o aggiungere ulteriori 0s inutili a seconda dei dati che l'utente fornisce

Così, ad un alto livello, la mia domanda è:

c'è un modo migliore per garantire che i numeri non vengano modificati, ma che siano mantenuti in un tipo di dati numerico? Si tratta di cambiare il modo in cui importare i dati CSV in primo luogo? Sicuramente c'è una soluzione semplice che sto trascurando?

Ecco un semplice script che riprodurre il bug:

import pandas as pd 

import sys 
if sys.version_info[0] < 3: 
    from StringIO import StringIO 
else: 
    from io import StringIO 

CSV_Data = "Index,Column_1,Column_2,Column_3,Column_4,Column_5,Column_6,Column_7,Column_8\nindex_1,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8\nindex_2,2.1,2.2,2.3,2.4,2.5,2.6,2.7,2.8\nindex_3,3.1,3.2,3.3,3.4,3.5,3.6,3.7,3.8\nindex_4,4.1,4.2,4.3,4.4,4.5,4.6,4.7,4.8" 

input_data = StringIO(CSV_Data) 
df = pd.DataFrame.from_csv(path = input_data, header = 0, sep=',', index_col=0, encoding='utf-8') 
print(df.to_dict(orient = 'records')) 
+1

Perché non usare 'df.to_json (= orientare 'record')', se obiettivo finale è quello di utilizzare JSON? – Zero

+0

@JohnGalt Fondamentalmente, per consentire l'annidamento dinamico di colonne, il dizionario che creo usando to_dict viene inserito in un dizionario più grande che sto costruendo, che alla fine viene scaricato su un JSON. –

+0

potresti usare 'pd.io.json.dumps (nested_dicts_with_pd_objects)', funziona per te? Idealmente, non dovrebbe introdurre uno scenario di arrotondamento. – Zero

risposta

2

Si potrebbe utilizzare pd.io.json.dumps per gestire dicts nidificate con oggetti panda.

Creiamo un dettato summary con record dataframe e metrica personalizzata.

In [137]: summary = {'df': df.to_dict(orient = 'records'), 'df_metric': df.sum()/df.min()} 

In [138]: summary['df_metric'] 
Out[138]: 
Column_1 9.454545 
Column_2 9.000000 
Column_3 8.615385 
Column_4 8.285714 
Column_5 8.000000 
Column_6 7.750000 
Column_7 7.529412 
Column_8 7.333333 
dtype: float64 

In [139]: pd.io.json.dumps(summary) 
Out[139]: '{"df":[{"Column_7":1.7,"Column_6":1.6,"Column_5":1.5,"Column_4":1.4,"Column_3":1.3,"Column_2":1.2,"Column_1":1.1,"Column_8":1.8},{"Column_7":2.7,"Column_6":2.6,"Column_5":2.5,"Column_4":2.4,"Column_3":2.3,"Column_2":2.2,"Column_1":2.1,"Column_8":2.8},{"Column_7":3.7,"Column_6":3.6,"Column_5":3.5,"Column_4":3.4,"Column_3":3.3,"Column_2":3.2,"Column_1":3.1,"Column_8":3.8},{"Column_7":4.7,"Column_6":4.6,"Column_5":4.5,"Column_4":4.4,"Column_3":4.3,"Column_2":4.2,"Column_1":4.1,"Column_8":4.8}],"df_metric":{"Column_1":9.4545454545,"Column_2":9.0,"Column_3":8.6153846154,"Column_4":8.2857142857,"Column_5":8.0,"Column_6":7.75,"Column_7":7.5294117647,"Column_8":7.3333333333}}' 

Usa, double_precision per alterare la precisione massima cifra del doppio. Avviso. Valori df_metric.

In [140]: pd.io.json.dumps(summary, double_precision=2) 
Out[140]: '{"df":[{"Column_7":1.7,"Column_6":1.6,"Column_5":1.5,"Column_4":1.4,"Column_3":1.3,"Column_2":1.2,"Column_1":1.1,"Column_8":1.8},{"Column_7":2.7,"Column_6":2.6,"Column_5":2.5,"Column_4":2.4,"Column_3":2.3,"Column_2":2.2,"Column_1":2.1,"Column_8":2.8},{"Column_7":3.7,"Column_6":3.6,"Column_5":3.5,"Column_4":3.4,"Column_3":3.3,"Column_2":3.2,"Column_1":3.1,"Column_8":3.8},{"Column_7":4.7,"Column_6":4.6,"Column_5":4.5,"Column_4":4.4,"Column_3":4.3,"Column_2":4.2,"Column_1":4.1,"Column_8":4.8}],"df_metric":{"Column_1":9.45,"Column_2":9.0,"Column_3":8.62,"Column_4":8.29,"Column_5":8.0,"Column_6":7.75,"Column_7":7.53,"Column_8":7.33}}' 

Si potrebbe utilizzare orient='records/index/..' per gestire dataframe -> to_json costruzione.

In [144]: pd.io.json.dumps(summary, orient='records') 
Out[144]: '{"df":[{"Column_7":1.7,"Column_6":1.6,"Column_5":1.5,"Column_4":1.4,"Column_3":1.3,"Column_2":1.2,"Column_1":1.1,"Column_8":1.8},{"Column_7":2.7,"Column_6":2.6,"Column_5":2.5,"Column_4":2.4,"Column_3":2.3,"Column_2":2.2,"Column_1":2.1,"Column_8":2.8},{"Column_7":3.7,"Column_6":3.6,"Column_5":3.5,"Column_4":3.4,"Column_3":3.3,"Column_2":3.2,"Column_1":3.1,"Column_8":3.8},{"Column_7":4.7,"Column_6":4.6,"Column_5":4.5,"Column_4":4.4,"Column_3":4.3,"Column_2":4.2,"Column_1":4.1,"Column_8":4.8}],"df_metric":[9.4545454545,9.0,8.6153846154,8.2857142857,8.0,7.75,7.5294117647,7.3333333333]}' 

In sostanza, pd.io.json.dumps - consente di convertire oggetto arbitrario in modo ricorsivo in JSON, che usa internamente ultrajson

Problemi correlati