Krzysztof Słowiński
Krzysztof Słowiński

Reputation: 7217

Using read_excel with converters for reading Excel file into Pandas DataFrame results in a numeric column of object type

I am reading this Excel file United Nations Energy Indicators using the code snippet here:

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')

This results in Energy Supply column having the object type instead of float. Why is it the case?

energy = energy_df()
print(energy.dtypes)

Energy Supply                object
Energy Supply per Capita    float64
% Renewable                 float64

Upvotes: 2

Views: 13830

Answers (3)

Ribinbaby
Ribinbaby

Reputation: 1

try using isinstance(energy, int) instead of isinstance(energy, float).

like this->

def convert_energy(energy):
    if isinstance(energy, int):
         return float(energy*10^6)

Upvotes: 0

cs95
cs95

Reputation: 402323

Let's remove the converters argument for a moment -

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])

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

Your data loads just fine without a converter. There's a trick to understanding why this happens.

By default, pandas will read in the column and try to "interpret" your data. By specifying your own converter, you override pandas conversion, so this does not happen.

pandas passes integer and string values to convert_energy, so the isinstance(energy, float) is never evaluated to True. Instead, the else runs, and these values are returned as is, so your resultant column is a mixture of strings and integers. If you put a print(type(energy)) inside your function, this becomes obvious.

Since you have mixtures of types, the resultant type is object. However, if you do not use a converter, pandas will attempt to interpret your data, and will successfully parse it to numeric.

So, just doing -

df['Energy Supply'] *= 1000000

Would be more than enough.

Upvotes: 5

Scott Boston
Scott Boston

Reputation: 153460

One of the values for energy in your excel file is a string "..." and when in your coverter function, you just return energy as is if it is a string datatype.

Therefore you are getting a string returned along with your numbers which then changes the dtype of you column to 'object.

You could try something like this:

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()

Output:

<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

Upvotes: 1

Related Questions