0

I am conditionally assigning a column based on whether another column is null:

df = pd.DataFrame([
   { 'stripe_subscription_id': 1, 'status': 'past_due' },
   { 'stripe_subscription_id': 2, 'status': 'active' },
   { 'stripe_subscription_id': None, 'status': 'active' },
   { 'stripe_subscription_id': None, 'status': 'active' },
])
def get_cancellation_type(row):
    if row.stripe_subscription_id:
        if row.status == 'past_due':
            return 'failed_to_pay'
        elif row.status == 'active':
            return 'cancelled_by_us'
    else:
        return 'cancelled_by_user'
df['cancellation_type'] = df.apply(get_cancellation_type, axis=1)
df

But I don't get the results I expect:

enter image description here

I would expect the final two rows to read cancelled_by_user, because the stripe_subscription_id column is null.

If I amend the function:

def get_cancellation_type(row):
    if row.stripe_subscription_id.isnull():

Then I get an error: AttributeError: ("'float' object has no attribute 'isnull'", 'occurred at index 0'). What am I doing wrong?

Richard
  • 62,943
  • 126
  • 334
  • 542

1 Answers1

1

With pandas and numpy we barely have to write our own functions, especially since our own functions will perform slow because these are not vectorized and pandas + numpy provide a rich pool of vectorized methods for us.

In this case your are looking for np.select since you want to create a column based on multiple conditions:

conditions = [
    df['stripe_subscription_id'].notna() & df['status'].eq('past_due'),
    df['stripe_subscription_id'].notna() & df['status'].eq('active')
]

choices = ['failed_to_pay', 'cancelled_by_us']

df['cancellation_type'] = np.select(conditions, choices, default='cancelled_by_user')
     status  stripe_subscription_id   cancellation_type
0  past_due                     1.0       failed_to_pay
1    active                     2.0     cancelled_by_us
2    active                     NaN   cancelled_by_user
3    active                     NaN   cancelled_by_user
Erfan
  • 40,971
  • 8
  • 66
  • 78