Search code examples
pythonpandasintegercurrency

I can not convert the currency conversion, using Forex, to the integer for removing the decimal division, in Python


I am using Pandas to read a CSV file, Forex to convert the currency to other currencies and the integer mode (int) to remove the decimal division, but it gave an error.

Sample CSV:

Item,Price (BRL)
Dining devices,100
Dishwasher,600
Electric shower,200
Fridge,1600
Induction cooktop cooker,1800
Kitchen cabinet,900
Kit pans,200
Microwave,700

And:

import pandas as pd
from forex_python.converter import CurrencyRates
from pandas.io.parsers import read_csv

cc = CurrencyRates()

cad = cc.convert('BRL', 'CAD', 1)
nzd = cc.convert('BRL', 'NZD', 1)
usd = cc.convert('BRL', 'USD', 1)

c = read_csv('data/purchases.csv')
c.loc["Total"] = c.sum()
c["Item"].values[-1] = "  "

I replaced round with int, as suggested from Python: Remove division decimal:

c["USD"] = int((((c["Price (BRL)"] * usd) / 2) * 2 + 1))
c["CAD"] = int((((c["Price (BRL)"] * cad) / 2) * 2 + 1))
c["NZD"] = int((((c["Price (BRL)"] * nzd) / 2) * 2 + 1))
c

It gave an error:

TypeError: cannot convert the series to <class 'int'>
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-c0af80ffd537> in <module>
     14 c["Item"].values[-1] = "  "
     15 
---> 16 c["USD"] = int((((c["Price (BRL)"] * usd) / 2) * 2 + 1))
     17 c["CAD"] = int((((c["Price (BRL)"] * cad) / 2) * 2 + 1))
     18 c["NZD"] = int((((c["Price (BRL)"] * nzd) / 2) * 2 + 1))

~/GitLab/Gustavo/global/.env/lib/python3.9/site-packages/pandas/core/series.py in wrapper(self)
    139         if len(self) == 1:
    140             return converter(self.iloc[0])
--> 141         raise TypeError(f"cannot convert the series to {converter}")
    142 
    143     wrapper.__name__ = f"__{converter.__name__}__"

TypeError: cannot convert the series to <class 'int'>

Solution

  • While most operations on a series are vectorized, i.e. pd.Series([n for n in ...]) + 1 means pd.Series([n + 1 for n in ...]), that is not the case of int(), which attemps to convert the full pandas.Series object to an integer. That doesn’t work.

    Instead you want a pandas way of casting each element to int, try astype() for example

    >>> df['Price (BRL)'] * usd
    0     20.0
    1    120.0
    2     40.0
    3    320.0
    4    360.0
    5    180.0
    6     40.0
    7    140.0
    Name: Price (BRL), dtype: float64
    >>> (df['Price (BRL)'] * usd).astype(int)
    0     20
    1    120
    2     40
    3    320
    4    360
    5    180
    6     40
    7    140
    Name: Price (BRL), dtype: int64
    

    I suppose your multiplication/division by 2 and adding 1 is in order to round to nearest. Casting directly to int does indeed round down. Instead you can use pd.Series.round():

    >>> pd.Series([.6]).astype(int)
    0    0
    dtype: int64
    >>> pd.Series([.6]).round().astype(int)
    0    1
    dtype: int64
    

    So probably what you’re trying to achieve is (df['Price (BRL)'] * usd).round().astype(int)