Задача 2. Простая, тест на дилетанта

На собеседовании как пить дать спросят Pandas. В больших данных все на Pandas, не надейся проскочить мимо. В этой статье дана классическая задача - смоделировать функцию ЕСЛИ из Excel. Это и просто, и сложно. На больших объемах данных код новичка положит сервер, это никто не хочет. На собеседовании ожидают, что ты напишешь эффективно или "нормально". Все три способа в статье: код новичка, нормальный код и отличный/быстрый код. CSV-файл с данными, прилагается.

Почему это - классическая задача?

Аналитики, по большей части, анализируют деньги. Продажи - это классика, ведь продажи - это и есть деньги. Кроме того, анализ продаж - универсальная предметная область. Она понятна любому человеку, не нужно дополнительно ничего объяснять. Именно поэтому такая задача скорее всего будет на вашем собеседовании. Не обязательно точь-в-точь, возможны вариации. Поэтому запоминайте не код, а идею.

Постановка задачи

Есть датасет с продажами в формате "регион-менеджер-продажи (число)".

Необходимо для каждого менеджера вывести уровень бонуса:

✅ если продажа больше 500, то бонус, скажем 10%,

✅ если меньше, то 5%.

Видим, что, по-сути, это - формула ЕСЛИ в Excel.

Лучше, чем уйти сразу

Безусловно, решить что-то лучше, чем не решить ничего. Поэтому предлагаю решение через lambda-функцию. Работает? - да, но не на больших данных.

#
# Дан файл в формате: регион - менеджер - продажи
# Вычислить бонус: 10% если больше 500, 5% - в противном случае
#
df = pd.read_csv("./data/sales.csv")
df = df.astype({
    'region': 'str',
    'manager': 'str',
    'sales': 'int32'
})
# better then nothing
df['bonus'] = df['sales'].apply(
    lambda x: 0.1 if x > 500 else 0.05  # type: ignore
)

Причина в том, что каждый раз Pandas задействует Python для выполнения этого кода. Ничего удивительного, скажете вы, ведь Pandas написан на Python. Но если задействовать векторизованные операции, то они будут реализованы под капотом уже не на языке Python, а на C, который работает гораздо быстрее. Также рост скорости будет обеспечен тем, что на Python интерпретатор будет проверять типы, а C-код это делать не будет (с соответствующими рисками).

Решение на 4+

Лучшее решение в данном случае - это использование атрибута loc у DataFrame:

# better
df.loc[df['sales'] > 500, 'bonus_new'] = 0.1
df.loc[df['sales'] < 500, 'bonus_new'] = 0.05

Что делает loc ? Он принимает 2 параметра, первый - диапазон строк, второй - диапазон колонок:

✅ В нашем случае мы устанавливаем значение 0.1 диапазону с продажами больше 500

✅ 0.05 для диапазона меньше 500.

Такая операция будет выполняться значительно быстрее. Неоспоримым достоинством этого кода является его простота и логичность. Обозначил диапазон, присвоил значение. Рекомендуется к применению

Решение на оффер

Предыдущее решение было хорошим, рабочим. Но есть лучше. Pandas основан на Numpy, поэтому мы можем использовать функции Numpy в коде на Pandas.

Речь идет о функции select , которая работает следующим образом:

✅ ей передается список условий и список значений. Значение, если условие выполнится, то будет подставлено соответствующее значение.

✅ если ни одно из условий не выполнено, select воспользуется значением по-умолчанию.

Звучит сложнее, чем есть на самом деле. Код ниже:

# best using np.select
cond_list = [
    (df['sales'] > 500),
    (df['sales'] < 500)
]
df['bonus_new_new'] = np.select(
    cond_list, 
    choicelist=[0.1, 0.05], 
    default=0
)
# get bonus value
df['bonus_value'] = df['sales'] * df['bonus']
df.head(10)

На первый взгляд, код более многословный, чем через loc , но причина в том, что я вынес условия в отдельную переменную. Мне видится, что так более логично. Попробуйте запустить эту программу и убедиться, что ничего особо сложного в ней нет.

Видео-версия на Youtube

Данная задача разбирается в видео на Youtube, есть тайм-коды.

Код и исходные данные

Код и исходные данные к нему доступны по ссылке