0

I was wondering whether it was possible to format numbers as currency in a easy way, and the following question helped me a lot: Currency Formatting in Python.

I did it, and worked fine. But it transformed my data in strings, which is not what I want.

Suppose I want to sum all my items in a pd.Series to return a total amount of money: it will return a string concatenation of all my data, not a number.

How can I cast my values back to numbers, but with the formatting? Is it possible?

Thanks in advance.

Vini
  • 875
  • 1
  • 7
  • 14
  • 1
    A code snippet in your post would have really helped helping you, @Vini – Evgeny Feb 07 '18 at 14:27
  • I'd suggest you use a pd.DataFrame (hereafter named `df`), with one column "value" being the actual numbers as floats, and one column "pretty_print" where you use that trick from locale.currency you mentioned. Then what you're looking for is just `df['value'].sum()` – arnaud Feb 07 '18 at 14:31

3 Answers3

1

If you wanna stick to the pandas style, assuming you initially had a pd.Series called prices with all the prices (in float value) then you could create a pd.DataFrame with both the float values and the prettyprint values you mentioned using that locale package.

import locale
locale.setlocale( locale.LC_ALL, '' )
prices = pd.Series([123,4321,12.4])
df = pd.DataFrame(prices, columns=['price'])
df['price_pretty'] = df['price'].apply(locale.currency)

>>> df
    price   price_pretty
0   123.0   Fr. 123,00
1   4321.0  Fr. 4321,00
2   12.4    Fr. 12,40

From which you can easily compute the aggregation you wanted, but keep an access to a pretty-printed version (strings) in another column.

>>> df.price.sum()
4456.3999999999996
arnaud
  • 3,293
  • 1
  • 10
  • 27
1

One way to handle this is to create a new class that handles the formatting of the representation for you. Normally, I would just subclass float, but it looks like pandas recognizes floats and casts to a built-in representation. So in this case you will need to create an object from scratch.

import pandas as pd
from numbers import Number


class Currency:
    def __init__(self, x):
        self.x = x
    def __repr__(self):
        return '${:,.2f}'.format(self.x)
    def __str__(self):
        return self.__repr__()
    def __add__(self, other):
        if isinstance(other, Currency):
            return Currency(self.x + other.x)
        elif isinstance(other, Number):
            return Currency(self.x + other)
        else:
            return NotImplemented
    def __radd__(self, other):
        return self + other

df = pd.DataFrame({'item': ['banana', 'laptop', 'gold brick'], 
                   'cost':[0.25, 1299.99, 1210000]})

df.cost = df.cost.apply(Currency)
df
# returns:
            cost        item
0          $0.25      banana
1      $1,299.99      laptop
2  $1,210,000.00  gold brick

df.cost.sum()
# returns:
$1,211,300.24
James
  • 32,991
  • 4
  • 47
  • 70
0

You could make a class that boxes your numbers. If you made a class for a currency you can override the some of the basic functions of that class to behave like normal arithmetic. See link.

For example:

class Currency(object):
    #other stuff
    def __add__(self,other):
        summed_value = self.value + other.value
        return Currency(self.type,summed_value)

This would let you box your values into a currency with a given type ($, £ etc.) but let you treat the values as normal numbers.

If you feel keen you could add type checking or currency conversion to handle the case where some values are in one currency and others are not!