Условие
Нужно создать новую колонку по условиям. Когда использовать np.where, когда np.select, когда булеву маску с присваиванием?
Решение
Случай 1: одно условие if-else
df['bonus'] = np.where(df['vip'], df['amount']*0.2, df['amount']*0.05)Случай 2: несколько условий
np.select — самый чистый способ:
conds = [
df['amount'] >= 100_000,
df['amount'] >= 10_000,
df['amount'] >= 1_000,
]
choices = ['platinum', 'gold', 'silver']
df['tier'] = np.select(conds, choices, default='bronze')Случай 3: модификация по маске in-place
mask = df['amount'] < 0
df.loc[mask, 'amount'] = 0 # «обнулить отрицательные»
df.loc[mask, 'is_refund'] = True # ещё и поставить флагСлучай 4: nested-условия
Лучше избегать вложенных np.where — становится нечитаемо. Использовать np.select.
# Плохо:
df['tier'] = np.where(df['amount'] >= 100000, 'platinum',
np.where(df['amount'] >= 10000, 'gold',
np.where(df['amount'] >= 1000, 'silver', 'bronze')))
# Хорошо: np.select как вышеПодводные камни
np.where(cond, A, B)всегда вычисляет иA, иB— если один из них тяжёлый, считается зря. Маска ленивее.np.selectберёт первое подходящее условие — порядок важен.- Типы в
choicesмогут смешиваться (['gold', 0]) → итоговый dtype object. - Маска с присваиванием меняет df in-place — при цепочках копирования возможен
SettingWithCopyWarning. - На pandas-Series лучше
Series.where(cond, other)илиSeries.mask(cond, other)— сохраняют индекс и dtype.
Эталонный ответ
Одно условие → np.where; много → np.select; модификация in-place → df.loc[mask, col] = value. Вложенные np.where заменяйте на np.select.