Search code examples
pythonpandasdataframevalueerror

ValueError: The truth value of a Series is ambiguous (API NaN handling)


I am developing an API in django-rest-framework where depending on your input parameters you get different responses. The API is calculating indicators that will return to the user against a database.

I wrote a function to handle NaN values like so:

def nan_to_none(value):
    if not isinstance(value, str) and value is not None and np.isnan(value):
        return None
    return value

This is the element of the response where the error pops:

 "prog": nan_to_none(row["average_items_prog"])

This is the line of SQL that is raising the issue:

  ((((coalesce(qte_art, 0) / nullif(nb_client, 0)) - (coalesce(qte_art_n1, 0) / nullif(nb_client_n1, 0))) / (coalesce(qte_art_n1, 0) / nullif(nb_client_n1, 0))) * 100) as average_items_prog,

And this is the error message:

  File "C:\Users\wdc\views.py", line 464, in get
    "prog": nan_to_none(row["average_items_prog"])},
  File "C:\Users\wdc\views.py", line 28, in nan_to_none
    if not isinstance(value, str) and value is not None and np.isnan(value):
  File "C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\generic.py", line 1478, in __nonzero__
    .format(self.__class__.__name__))
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

I have no clue how to fix this !


Solution

  • Try change:

    "prog": nan_to_none(row["average_items_prog"])
    

    with Series.apply:

    "prog": row["average_items_prog"].apply(nan_to_none)
    

    Test:

    s = pd.Series(['a', 0, 0, 1, None, np.nan])
    print (s)
    0       a
    1       0
    2       0
    3       1
    4    None
    5     NaN
    dtype: object
    
    def nan_to_none(value):
        if not isinstance(value, str) and value is not None and np.isnan(value):
            return None
        return value
    
    print (s.apply(nan_to_none))
    #in your solution
    #"prog": row["average_items_prog"].apply(nan_to_none)
    0       a
    1       0
    2       0
    3       1
    4    None
    5    None
    dtype: object
    

    Also seems solution should be simplify with testing np.nan != np.nan:

    def nan_to_none(value):
        if value != value:
            return None
        return value
    
    print (s.apply(nan_to_none))
    #in your solution
    #"prog": row["average_items_prog"].apply(nan_to_none)
    0       a
    1       0
    2       0
    3       1
    4    None
    5    None
    dtype: object
    

    Or set None with Series.mask:

    print (s.mask(s.isna(), None))
    #in your solution
    #"prog": row["average_items_prog"].mask(s.isna(), None)
    0       a
    1       0
    2       0
    3       1
    4    None
    5    None
    dtype: object