Home > database >  Percent format inside function
Percent format inside function

Time:10-19

I am trying to divide the numbers in two columns, as a percent and catch any ZeroDivisionErrors. I have been trying to figure out the formatting works, and so far nothing has worked.

import pandas as pd


def percent_diff(col1, col2):
    """
    This function will avoid any error caused by a divide by 0.  The result will be 1, 
    representing that there is a 100 % difference
    """
    try:
        x = 1 - (col1 / col2) 
        x = "{:,.2%}".format(x)
        return x
    except ZeroDivisionError:
        x = 'Error'
        return x


data = {'a' : [1, 2, 3, 4, 5, 6, 7, 0, 9, 10],
        'b' : [10, 9, 0, 7, 6, 5, 4, 3, 2, 1]}

df = pd.DataFrame(data)

df['c'] = percent_diff(df['a'], df['b'])
df.head(10)

I would like another column with a percent like 25.12%, or Error if there is a division error. 100.00% would also work in my instance.

CodePudding user response:

A straightforward solution using zip:

[a / b for (a, b) in zip(la, lb)]

You can replace the a / b with a function call (percent_diff) that handles your zero division case, like you have, but without needing to manage the list iteration.

That said, zip will zip up two lists into a tuple that you can utilize:

>>> la = [1,2,3]
>>> lb = [2,2,2]
>>> [i for i in zip(la, lb)]
[(1, 2), (2, 2), (3, 2)]
>>> [a / b for (a, b) in zip(la, lb)]
[0.5, 1.0, 1.5]

A full solution looks like:

def perc(a, b):
    try:
        result = 1 - (a / b)  # Note this inverts the percentage.
        return "{:,.2%}".format(result)
    except ZeroDivisionError:
        return "Error"

data = {'a' : [1, 2, 3, 4, 5, 6, 7, 0, 9, 10],
        'b' : [10, 9, 0, 7, 6, 5, 4, 3, 2, 1]}
data["c"] = [perc(a, b) for (a, b) in zip(data.get("a", []), data.get("b", []))]

Yielding the result:

>>> pprint(data)
{'a': [1, 2, 3, 4, 5, 6, 7, 0, 9, 10],
 'b': [10, 9, 0, 7, 6, 5, 4, 3, 2, 1],
 'c': ['90.00%',
       '77.78%',
       'Error',
       '42.86%',
       '16.67%',
       '-20.00%',
       '-75.00%',
       '100.00%',
       '-350.00%',
       '-900.00%']}

CodePudding user response:

You're passing a pd.Series into the format, which isn't supported apparently.

This answer shows you can just use map()

df['c'] = (1-df['a']/df['b']).map('%{:,.2%}'.format)

CodePudding user response:

You could save yourself the exception management by computing your expected result directly:

return f"{1-(col1/col2):,.2%}" if col2 else "Error"

or (to abide by the function's comment)

return f"{1-(col1/col2):,.2%}" if col2 else "100%"
  • Related