2017-12-30 27 views
1

ich das Excel United Nations Energy Indicators den Code-Schnipsel hier mit Datei lese:Mit read_excel mit Konvertern für das Lesen von Excel-Datei in Pandas Dataframe Ergebnisse in einer numerischen Spalte von Objekttyp

def convert_energy(energy): 
    if isinstance(energy, float): 
     return energy*1000000 
    else: 
     return energy 

def energy_df(): 
    return pd.read_excel("Energy Indicators.xls", skiprows=17, skip_footer=38, usecols=[2,3,4,5], na_values=['...'], names=['Country', 'Energy Supply', 'Energy Supply per Capita', '% Renewable'], converters={1: convert_energy}).set_index('Country') 

Dies führt zu Energieversorgung Spalte den Objekttyp anstelle von float haben. Warum ist es so?

energy = energy_df() 
print(energy.dtypes) 

Energy Supply    object 
Energy Supply per Capita float64 
% Renewable     float64 
+0

Eine Vermutung ist, dass es nicht-numerische Einträge gibt, die die 'else'-Bedingung auslösen. Warum nicht 'np.nan' im' else'-Bit zurückgeben? –

+0

Warum überhaupt einen Konverter benutzen? Einfach laden, sehen, ob Pandas einen numerischen Typ bekommt und multipliziert, wenn nicht, die Spalte mit einem erzwungenen 'pd.to_numeric' * 1000000 überschreiben? –

+0

Es stimmt, wenn ich keinen Konverter verwende, ist der Typ float64. Das ist eine Konvertierung, die auf der Spalte ausgeführt werden muss, und ich dachte, dass Konverter eine gute Möglichkeit ist, dies zu tun. –

Antwort

3

Lassen Sie uns das converters Argument für einen Moment entfernen -

c = ['Energy Supply', 'Energy Supply per Capita', '% Renewable'] 
df = pd.read_excel(
    "Energy Indicators.xls", 
    skiprows=17, 
    skip_footer=38, 
    usecols=[2,3,4,5], 
    na_values=['...'], 
    names=c, 
    index_col=[0]  
) # thanks to the puppy (Jon Clements) for improving the formatting 

df.index.name = 'Country' 
df.head()  
       Energy Supply Energy Supply per Capita % Renewable 
Country                
Afghanistan    321.0      10.0 78.669280 
Albania     102.0      35.0 100.000000 
Algeria    1959.0      51.0  0.551010 
American Samoa   NaN      NaN  0.641026 
Andorra     9.0      121.0 88.695650 

df.dtypes 

Energy Supply    float64 
Energy Supply per Capita float64 
% Renewable     float64 
dtype: object 

Ihre Daten werden problemlos ohne Konverter geladen. Es gibt einen Trick, warum das passiert.

Standardmäßig liest pandas in der Spalte und versucht, Ihre Daten zu "interpretieren". Wenn Sie einen eigenen Konverter angeben, überschreiben Sie die Pandas-Konvertierung, so dass dies nicht geschieht.

pandas übergibt Integer- und String-Werte an convert_energy, so dass isinstance(energy, float) niemals zu True ausgewertet wird. Stattdessen wird else ausgeführt, und diese Werte werden unverändert zurückgegeben, sodass die resultierende Spalte eine Mischung aus Zeichenfolgen und Ganzzahlen ist. Wenn Sie eine print(type(energy)) innerhalb Ihrer Funktion setzen, wird dies offensichtlich.

Da es sich um Mischungen von Typen handelt, ist der resultierende Typ object. Wenn Sie jedoch keinen Konverter verwenden, versucht Pandas, Ihre Daten zu interpretieren und analysiert sie erfolgreich auf numerisch. So

, gerade tun -

df['Energy Supply'] *= 1000000 

Wäre mehr als genug.

+0

Benötigt, um 'c' auch zu bearbeiten, aber' index_col = [0] 'hat sich letztendlich ausgearbeitet.Man musste den Namen später manuell eingeben, aber jetzt sollte es effizienter sein als zuvor. –

+0

Ahhh ... richtig ... du kannst post naming verwenden, solange es aufgelistet ist ... also setze 'Country' zurück in die Namensliste und setze dann 'index_col =' Country'' scheint für mich zu funktionieren ... –

+0

@ JonClements Wirklich? Das war eine andere Option, die ich ausprobierte, und es endete damit, dass ich einen "ValueError: Index-Land ungültig" erhielt, selbst nachdem ich "Country" am Anfang wieder in c gesetzt hatte. Ich renne auf 0,21. Was ist mit Ihnen? –

1

Einer der Werte für Energie in Ihrer Excel-Datei ist eine Zeichenfolge „...“ und wenn in Ihrer coverter Funktion, die Sie gerade Energie zurück, wie ist es, wenn ein String-Datentyp ist.

Daher erhalten Sie eine Zeichenfolge mit Ihren Zahlen zurückgegeben, die dann den Dtyp Ihrer Spalte zu "Objekt" ändert.

Man könnte so etwas wie dies versuchen:

def convert_energy(energy): 
    if energy == "...": 
     return np.nan 
    elif isinstance(energy, float): 
     return float(energy*1000000) 
    else: 
     return float(energy) 

df = pd.read_excel('http://unstats.un.org/unsd/environment/excel_file_tables/2013/Energy%20Indicators.xls', 
        skiprows=17, skip_footer=38, 
        usecols=[2,3,4,5], na_values=['...'], 
        names=['Country', 'Energy Supply', 'Energy Supply per Capita', '% Renewable'], 
        converters={1: convert_energy}).set_index('Country') 

df.info() 

Ausgang:

<class 'pandas.core.frame.DataFrame'> 
Index: 227 entries, Afghanistan to Zimbabwe 
Data columns (total 3 columns): 
Energy Supply    222 non-null float64 
Energy Supply per Capita 222 non-null float64 
% Renewable     227 non-null float64 
dtypes: float64(3) 
memory usage: 6.2+ KB 
+0

Und mit na_values ​​= ['...'] scheint nicht zu wirken? –

+0

Da Sie nur einen na_value haben, versuchen wir es ohne die eckigen Klammern, die es zu einer Liste machen. –

Verwandte Themen