inja inja - 2 months ago 12
Python Question

The truth value of a Series is ambiguous - Error When when calling a function - Pandas

I know following error

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
has been asked a long time ago.

However, I am trying to create a basic function and return a new column with
df[busy']
with
1
or
0
. My function looks like this,

def hour_bus(df):
if df[(df['hour'] >= '14:00:00') & (df['hour'] <= '23:00:00')&\
(df['week_day'] != 'Saturday') & (df['week_day'] != 'Sunday')]:
return df['busy'] == 1
else:
return df['busy'] == 0


I can execute the function, but when I call it with the dataframe, I get the error mentioned above. I followed the following thread and another thread to create that function. I used
&
instead of
and
in my
if
clause.

Anyhow,when I do the following, I am getting my desired output.

df['busy'] = np.where((df['hour'] >= '14:00:00') & (df['hour'] <= '23:00:00') & \
(df['week_day'] != 'Saturday') & (df['week_day'] != 'Sunday'),'1','0')


Any ideas on what mistake am I making in my
hour_bus
function? Thank you in advance.

Answer Source

The

(df['hour'] >= '14:00:00') & (df['hour'] <= '23:00:00')& (df['week_day'] != 'Saturday') & (df['week_day'] != 'Sunday')

gives a boolean array, and when you index your df with that you'll get a (probably) smaller part of your df.

Just to illustrate what I mean:

import pandas as pd

df = pd.DataFrame({'a': [1,2,3,4]})
mask = df['a'] > 2
print(mask)
# 0    False
# 1    False
# 2     True
# 3     True
# Name: a, dtype: bool
indexed_df = df[mask]
print(indexed_df)
#    a
# 2  3
# 3  4

However it's still a DataFrame so it's ambiguous to use it as expression that requires a truth value (in your case an if).

bool(indexed_df)
# ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

You could use the np.where you used - or equivalently:

def hour_bus(df):
    mask = (df['hour'] >= '14:00:00') & (df['hour'] <= '23:00:00')& (df['week_day'] != 'Saturday') & (df['week_day'] != 'Sunday')
    res = df['busy'] == 0                             
    res[mask] = (df['busy'] == 1)[mask]  # replace the values where the mask is True
    return res

However the np.where will be the better solution (it's more readable and probably faster).