1. Эта статья — просто копия моего Jupyter Notebook, но почти без кода — только рисунки. Если вы хотите получить код, он у меня есть:
    * Github: https://github.com/alexkataev/Case-Study-UCI-Bank-Marketing-Dataset
    * И Kaggle: https://www.kaggle.com/alexkataev/uci-bank-marketing-dataset-part-1-eda
  2. Иногда я буду использовать изображения кода и его вывода, потому что это более компактно, чем уценка кода Medium.
  3. Информация в первых двух главах взята из репозитория машинного обучения UCI: https://archive.ics.uci.edu/ml/datasets/bank+marketing.

Оглавление

1. Информация о наборе данных

В этом примере я использовал:

1. bank-additional-full.csv со всеми примерами (41188) и т.д.

2. Информация об атрибутах

3. Базовый анализ

Проверка пропущенных значений, типов данных и некоторых других вещей:

Пропущенных значений нет.

И краткий обзор числовых столбцов:

4. Исследовательский анализ данных (EDA)

4.1 Распределение цели

Очевидно, набор данных несбалансирован.
Давайте сделаем y двоичным файлом признака прямо на этом шаге:

df['y'].replace({'no': 0, 'yes': 1}, inplace=True)

Выводы о функции y (цель):

  • Наша целевая переменная сильно несбалансирована.

Более подробный анализ находится в разделе 4.3.6.

4.2 Корреляционная матрица

Числовые характеристики, которые больше всего коррелируют с y:

4.3 Анализ функций

4.3.1 Функция: месяц (категория)

month: last contact month of year (categorical: ‘jan’, ‘feb’, ‘mar’, …, ‘nov’, ‘dec’)

Во-первых, мы проверим распределение наблюдений по месяцам, а также посмотрим их ДА-долю:

Распределение неравномерное, и похоже, что некоторые месяцы предпочтительнее с точки зрения получения ДА-ответов, но нам нужно это проверить. Давай сделаем это.

Из описания набора данных мы знаем, что:

bank-additional-full.csv со всеми примерами (41188) и 20 входными данными, упорядоченными по дате (с мая 2008 г. по ноябрь 2010 г.), что очень близко к данным, проанализированным в [Moro et al., 2014]

Учитывая, что наш набор данных касается согласия людей подписаться на срочный депозит, я полагаю, все вы согласитесь, что каждый месяц имеет свой социальный и экономический контекст. И, несомненно, экономические факторы повлияли на решения людей (т.е. на нашу цель y). Поэтому я решил немного углубиться в вопрос о месяцах.

Позвольте мне добавить новую функцию с именем year. Я хочу посмотреть, смогу ли я получить некоторые полезные сведения об этом.

ВАЖНОЕ ПРИМЕЧАНИЕ. я добавлю функцию year только для целей анализа и не буду использовать ее для обучения модели.

Что у нас есть:

2008 → [0..27690)
2009 → [27690..39130)
2010 → [39130..41188)

Давайте жестко закодируем функцию year на основе этих индексов:

df['year'] = np.hstack((np.array([2008] * (27690 - 0)),
                        np.array([2009] * (39130 - 27690)),
                        np.array([2010] * (41188 - 39130))))

И немного переупорядочения (я хочу переместить year сразу после month):

df = df[['age', 'job', 'marital', 'education', 'default', 'housing',
         'loan', 'contact', 'month', 'year', 'day_of_week',
         'duration', 'campaign', 'pdays', 'previous', 'poutcome',
         'emp.var.rate', 'cons.price.idx', 'cons.conf.idx',
         'euribor3m', 'nr.employed', 'y']]

Идеальный! Теперь вернемся назад и посмотрим, действительно ли какие-то месяцы предпочтительнее с точки зрения получения ДА-ответов:

Создание строгого порядка месяцев облегчит понимание информации:

months = ['mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct',
          'nov', 'dec']
months_order = pd.Categorical(months, ordered=True)

И построение:

Так что каких-то заметных закономерностей между годами мы не видим.
Хорошо, а теперь проанализируем месяцы с учетом годов:

  • Распределение крайне неравномерное
  • Больше всего наблюдений получено в 2008 г. (≈67%).
  • Наиболее успешным был 2010 год (доля ДА ≈0,52).

А теперь давайте проверим, что скрывает от нас каждый год:

  • Каждый год имеет неравномерное распределение наблюдений по месяцам
  • Как будто у нас есть аномалии в октябре 2008 года и в апреле и мае 2009 года.

Давайте углубимся в 2008 год, чтобы увидеть, есть ли в октябре какие-нибудь странности:

Хм, в октябре нет ничего уникального. Давайте проверим категориальные столбцы:

Если мы внимательно посмотрим на функцию default, то заметим, что в октябре и декабре вообще нет категорий unknown и yes:

Хорошо. Теперь позвольте мне обратить ваше внимание на другие интересные месяцы, но уже 2009 года:

Давайте углубимся в 2009 год. Опять же, мы сравним медианные значения всех числовых признаков, но для 2009 года:

Как видите, ничего необычного для апреля и мая 2009 года нет. Итак, давайте двигаться дальше. Возможно, мы найдем что-то интересное, изучая другие особенности.

И последнее, мы проверим корреляцию нашей новой функции, year, с другими:

Итак, year больше всего коррелирует с признаками, относящимися к социально-экономическому контексту, что кажется вполне логичным.

Выводы о функции month:

Нам вряд ли удастся выяснить, какой период года более или менее удачный с точки зрения ДА-ответов, по двум причинам:

  • количество наблюдений сильно различается по месяцам и годам (распределение внутри каждого года неравномерно);
  • некоторые месяцы некоторых лет вообще не имеют наблюдений

Поэтому я не уверен на 100%, но я думаю, что мы НЕ должны использовать month для обучения модели. Однако я на 100% уверен, что мы можем использовать признаки month и year в качестве вспомогательных для анализа других.

4.3.2 Данные о клиенте банка

4.3.2.1 Функция: возраст (числовой)

Анализ распределения и доли ДА:

Нет корреляции между age и y.

Выводы о функции age:

  • Средний возраст: 38 лет.
  • Средний возраст: ≈40 лет.
  • Люди старше 65 лет. с большей вероятностью согласятся оформить банковский срочный вклад, но в целом корреляции между age и ДА-долей нет.

4.3.2.2 Функция: работа (категория)

Из второго графика видно, что студенты и пенсионеры с большей вероятностью согласятся подписаться на банковский срочный вклад, но, рассматривая последний график, мы видим, что эта модель работает только для 2009 года. Она также работает гораздо меньше для 2008 года и абсолютно исчезнуть в 2010 году. Поэтому мы не можем быть уверены в такой находке.

Выводы о функции job:

  • Большинство людей в наборе данных принадлежат к рабочему классу (администратор + рабочий + техник + сервис ≈73%).
  • Существенных доказательств связи между категориями должностей и ответами ДА нет.

4.3.2.3 Характеристика: брачные (категориальные)

Опять же, single людей выглядят так, как будто они склонны больше соглашаться (на основе первого графика), но мы не видим этой ситуации на графике ДА-пропорции по годам.

Что касается unknown, то у нас просто мало наблюдений.

Выводы о функции marital:

  • Большинство людей в наборе данных женаты (≈61%).
  • Существенных доказательств взаимосвязи между категориями брака и ДА-ответами нет.

4.3.2.4 Характеристика: образование (категория)

6 наблюдений 2009 года с ДА-пропорцией 0,50 кажутся здесь какой-то аномалией.

Заключение о функции education:

Нет существенных доказательств связи между категориями образования и ДА-ответами.

4.3.2.4 Функция: по умолчанию (категория)

default: has credit in default? (categorical: 'no', 'yes', 'unknown')

Выводы о функции default:

  • Большинство людей в наборе данных (≈79%) не имеют кредита по умолчанию.
  • Кажется, что люди, у которых НЕТ кредита по умолчанию, с большей вероятностью согласятся подписаться на банковский срочный депозит, но это связано с результатами 2009 года. Мы не видим существенной разницы в 2008 и 2010 годах.

4.3.2.4 Функция: жилье (категория)

housing: has housing loan? (categorical: 'no', 'yes', 'unknown')

Выводы о функции housing:

  • Количество людей, у которых есть жилищный кредит, почти равно количеству людей, у которых его нет (52% против 45%).
  • Существенных доказательств связи между категориями жилья и ДА-ответами нет.

4.3.2.4 Функция: ссуда (категория)

loan: has personal loan? (categorical: 'no', 'yes', 'unknown')

Выводы о функции loan:

  • Подавляющее большинство людей не имеют личного кредита (≈82%)
  • Нет существенных доказательств взаимосвязи между категориями кредита и ответами ДА.

4.3.3 Связано с последним контактом в текущей кампании

4.3.3.1 Функция: контакт (категория)

contact: contact communication type (categorical: 'cellular', 'telephone')

В 2010 году разница довольно большая, так что давайте углубимся в нее.
Cellular контактов по месяцам:

И telephone контакты:

Вы видите, что мы получили аномально высокие ДА-пропорции для cellular типа контакта в 2010 году. Причина этого пока неизвестна.

Выводы о функции contact:

  • С большинством людей связывались по сотовому телефону (≈63%).
  • Люди, с которыми связались по сотовому, с небольшой долей вероятности согласятся оформить банковский срочный депозит. Но совсем немного:
    — 2008 г.: 0,06 против 0,04
    — 2009 г.: 0,20 против 0,15
    — 2010 г.: 0,58 против 0,28 (аномальные результаты относительно 2008–09 гг.)

4.3.3.2 Функция: месяц (категория)

month: last contact month of year (categorical: 'jan', 'feb', 'mar', ..., 'nov', 'dec')

Мы уже анализировали это — см. раздел 4.3.1.

4.3.3.3 Функция: day_of_week (категория)

day_of_week: last contact day of the week (categorical: 'mon', 'tue', 'wed', 'thu', 'fri')

Заключение о функции day_of_week:

  • Понедельник кажется немного худшим днем ​​для получения ДА, но в целом нет существенных доказательств взаимосвязи между категориями дня_недели и ответами ДА.

4.3.3.4 Функция: продолжительность (числовая)

duration: last contact duration, in seconds (numeric).
Important note: this attribute highly affects the output target (e.g., if duration=0 then y='no'). Yet, the duration is not known before a call is performed. Also, after the end of the call y is obviously known. Thus, this input should only be included for benchmark purposes and should be discarded if the intention is to have a realistic predictive model.

Существует корреляция между duration и y.

Выводы о функции duration:

  • Если рассматривать только первые 3–4 группы (при достаточном количестве наблюдений), совершенно очевидно, что чем длиннее вызов, тем выше шансы получить положительное решение (и здравый смысл говорит о том же).
  • И мы также не должны забывать о важном примечании, которое гласит:
    «этот атрибут сильно влияет на цель вывода (например, if duration=0 then y='no')».

4.3.4 Другие атрибуты

4.3.4.1 Функция: кампания (числовая)

campaign: number of contacts performed during this campaign and for this client (numeric, includes last contact)

Рассмотрим подробнее первый бин (от 1 до 4 контактов) и попробуем посмотреть, влияет ли количество контактов во время этой кампании на пропорцию ДА:

График выше показывает, что чем больше контактов, тем меньше ДА-ответов, НО с другой стороны, каждый раз мы получаем дополнительные положительные ответы от людей, которые ранее не соглашались :) Да, доля становится все меньше и меньше, следовательно, она все еще там :)

Между campaign и y нет корреляции.

Заключение о функции campaign:

  • Почти 43% связались только один раз.
  • С 88% людей связывались менее 5 раз.
  • Больше контактов приводит к меньшему количеству ДА-ответов, но это все равно эффективно.

4.3.4.2 Функция: pdays (число)

pdays: number of days that passed by after the client was last contacted from a previous campaign (numeric; 999 means client was not previously contacted)

ВАЖНОЕ ПРИМЕЧАНИЕ. Здесь стоит упомянуть, что фраза «с ним ранее не связывались» относится только к предыдущей кампании и не означает, что они ранее вообще не связывались.

Заменим 999 на -1 и повторим анализ:

Существует слабая корреляция между pdays и y.

Выводы о функции pdays:

  • Около 96% не связались с последней кампанией.
  • Шансы получить ДА довольно высоки в течение первых 2 недель (до 14–15 дней); далее у нас высокая дисперсия и небольшие данные.
  • Люди, с которыми ранее не связывались, имеют наименьшую вероятность сказать ДА (0,09).

4.3.4.3 Функция: предыдущая (числовая)

previous: number of contacts performed before this campaign and for this client (numeric)

Поскольку мы получили здесь такое небольшое количество уникальных значений, давайте для удобства проанализируем его как категориальный признак:

Существует слабая корреляция между previous и y.

Выводы о функции previous:

  • Около 86% не связывались до этой кампании.
  • Кажется, что установить контакты перед кампанией намного лучше, чем не делать их вообще (для чисел больше 3 у нас есть небольшое количество наблюдений).
  • Кроме того, мы можем предположить, что чем больше предыдущих контактов, тем больше шансов получить ДА, но только до некоторой степени.

4.3.4.4 Функция: результат (категориальный)

poutcome: outcome of the previous marketing campaign (categorical: 'failure', 'nonexistent', 'success')

Выводы о функции poutcome:

  • 86% не участвовали в предыдущей маркетинговой кампании, поэтому у нас нет для них предыдущих результатов.
  • Около 2,2% клиентов ответили ДА как во время предыдущей, так и в текущей кампании.
  • Около 1,4% клиентов ответили ДА на текущую кампанию, в то время как НЕТ на предыдущую.
  • Если у нас есть положительный ответ с предыдущей кампанией, то мы, скорее всего, получим ответ ДА ​​во время текущей.
  • Если у нас есть отрицательный ответ на предыдущую кампанию, то у нас меньше шансов получить ответ ДА, и еще меньше вероятность для тех, чьи результаты не существуют.

4.3.5 Атрибуты социального и экономического контекста

ВАЖНОЕ ПРИМЕЧАНИЕ. Мы собираемся проанализировать следующие функции, используя нашу пользовательскую функцию — year.

Во-первых, давайте посмотрим, как эти функции связаны друг с другом:

Сильная корреляция:

  • emp.var.rate и euribor3m (0,97)
  • nr.employed и euribor3m (0,95)
  • emp.var.rate и nr.employed (0,91)
  • emp.var.rate и cons.price.idx (0,78)

Довольно высокая корреляция:

  • cons.price.idx и euribor3m (0,69)
  • cons.price.idx и nr.employed (0,52)

4.3.5.1 Функция: emp.var.rate (числовой)

emp.var.rate: employment variation rate - quarterly indicator (numeric)

Просто для общего представления о том, как выглядит emp.var.rate за все три года наблюдений:

  • 2008 год: курс был довольно стабильным и даже немного рос, за исключением конца года (он снизился).
  • 2009 г.: большую часть времени был стабилен, затем снизился, а в самом конце 2009 г. начал расти.
  • 2010 год: курс рос.

Несмотря на то, что emp.var.rate является числовым признаком, он имеет небольшое количество уникальных значений:

Теперь давайте посмотрим, как пропорция ДА коррелирует с emp.var.rate по месяцам и годам и по всему набору данных:

Как видите, это легкая отрицательная корреляция. Это означает, что чем выше коэффициент вариации занятости, тем ниже доля ДА, и наоборот. И это кажется вполне разумным: если уровень занятости сильно различается, люди не уверены в своем будущем и склонны принимать взвешенные решения — поэтому они реже отвечают ДА. Но здесь следует быть осторожным и помнить, что корреляция не является причинно-следственной связью.

Проверим распределение на наличие ответов ДА/НЕТ:

Очевидно, что между медианами существует огромная разница, поэтому эта функция будет очень полезна для классификации.

И последняя находка здесь. Проверим дисперсию по годам:

И в 2008, и в 2009 году наблюдается более высокая вариация коэффициента вариации занятости, что составляет около 95% всех наблюдений. Как известно, 2008 и 2009 годы были годами мирового финансового кризиса, поэтому эти 95% были получены в достаточно тяжелое для экономики время.

Выводы о функцииemp.var.rate:

  • Существует легкая отрицательная корреляция (-0,3) между emp.var.rate и долей ДА.
  • Существует огромная разница между медианами emp.var.rate для ответов ДА/НЕТ.
  • 95% ответов были получены в достаточно тяжелое для экономики и людей время.
  • Значения:
    — Количество уникальных значений: 10
    — Варьируется от -3,4 до 1,4.

4.3.5.1 Функция: cons.price.idx (числовой)

cons.price.idx: consumer price index - monthly indicator (numeric)

Общий вид cons.price.idx за все три года наблюдений:

  • 2008 и 2009 годы: индекс постепенно снижался с небольшими периодами роста. А в конце 2009 года он начал расти.
  • 2010: цены резко выросли.

Здесь у нас также есть небольшое количество наблюдений:

Теперь давайте посмотрим, как пропорция ДА коррелирует с cons.price.idx по месяцам и годам и по всему набору данных:

Существует небольшая отрицательная корреляция между cons.price.idx и y.

Проверим распределение на наличие ответов ДА/НЕТ:

Опять же, между медианами огромная разница, и это хорошо для задач классификации.

Теперь давайте проверим дисперсию по годам:

2008 и 2010 годы были более бурными, чем 2009 год.

Несмотря на сильную корреляцию между cons.price.idx и emp.var.rate, мы не видим, чтобы 2009 г. был хуже 2010 г. с точки зрения потребительских цен.

Выводы о функции cons.price.idx:

  • Существует небольшая отрицательная корреляция (-0,14) между cons.price.idx и y.
  • Существует огромная разница между медианами cons.price.idx для ответов ДА/НЕТ.
  • Значения:
    — Количество уникальных значений: 26
    — Варьируется от 92,201 до 94,767.

Функция 4.3.5.1: cons.conf.idx (числовой)

cons.conf.idx: consumer confidence index - monthly indicator (numeric)

Общий вид cons.conf.idx за все три года наблюдений:

  • 2008 г.: доверие потребителей сильно варьировалось и в конце года снижалось.
  • 2009 год: индекс рос и стал довольно высоким перед падением в конце.
  • 2010 г.: доверие потребителей быстро падало, что полностью коррелирует с индексом потребительских цен того времени.

Здесь у нас также есть небольшое количество наблюдений:

Теперь давайте посмотрим, как пропорция ДА коррелирует с cons.conf.idx по месяцам и годам и по всему набору данных:

Между cons.conf.idx и y нет существенной корреляции.

Проверим распределение на наличие ответов ДА/НЕТ:

Здесь мы видим, что медианы почти равны.

Теперь давайте проверим дисперсию по годам:

По данным Инвестопедии:

Индекс потребительского доверия (CCI) — это исследование, проводимое The Conference Board, которое измеряет, насколько оптимистично или пессимистично потребители оценивают свое ожидаемое финансовое положение. CCI основан на предпосылке, что если потребители настроены оптимистично, они будут тратить больше и стимулировать экономику, но если они настроены пессимистично, то их структура расходов может привести к рецессии.

Так, в 2009 и 2010 годах настроения сильно изменились по сравнению с 2008 годом.

Выводы о функции cons.conf.idx:

  • Заметной корреляции между индексом доверия потребителей и ответами людей нет.
  • Средние значения cons.conf.idx для ответов ДА/НЕТ почти равны.
  • Значения:
    — Количество уникальных значений: 26
    — Варьируется от -50,8 до -26,9.

4.3.5.4 Функция: euribor3m (числовое)

euribor3m: euribor 3 month rate — daily indicator (numeric)

Euribor — межбанковская ставка предложения в евро — это ежедневная справочная ставка, публикуемая Европейским институтом денежных рынков и основанная на усредненных процентных ставках, по которым банки еврозоны предлагают кредитовать необеспеченные средства другим банкам на оптовом денежном рынке евро. До 2015 года курс публиковался Европейской банковской федерацией.

Общий вид euribor3m за все три года наблюдений:

  • 2008: в течение этого года euribor3m был стабильным и в конце упал.
  • 2009 г.: euribor3m продолжало постепенно снижаться, но гораздо медленнее, чем в последние месяцы 2008 г., и в конце года произошло очередное падение.
  • 2010: euribor3m росло.

Здесь у нас есть:

Теперь давайте посмотрим, как пропорция ДА коррелирует с euribor3m по месяцам и годам и по всему набору данных:

Существует слабая отрицательная корреляция между euribor3m и y.

Проверим распределение на наличие ответов ДА/НЕТ:

Между медианами огромная разница, поэтому эта функция будет полезна для классификации.

Теперь давайте проверим дисперсию по годам:

В 2008–2009 годах показатель варьировался значительно больше, чем в 2010 году.

Выводы о функции euribor3m:

  • Существует небольшая отрицательная корреляция (-0,31) между euribor3m и y.
  • Существует огромная разница между медианами euribor3m для ответов ДА/НЕТ.
  • Значения:
    — Количество уникальных значений: 316
    — Варьируется от 0,634 до 5,045.

Функция 4.3.5.5: nr.employed (числовой)

nr.employed: number of employees - quarterly indicator (numeric)

Общий вид nr.employed за все три года наблюдений:

  • 2008: в течение этого года nr.employed росло, но в конце упало.
  • 2009 год: было стабильно, а в последние месяцы было очередное падение
  • 2010: nr.employed продолжает падать.

Здесь у нас есть:

Теперь давайте посмотрим, как пропорция ДА коррелирует с nr.employed по месяцам и годам и по всему набору данных:

Между nr.employed и y существует отрицательная корреляция.

Проверим распределение на наличие ответов ДА/НЕТ:

Мы видим разницу между медианами, поэтому эта функция будет полезна для классификации.

Теперь давайте проверим дисперсию по годам:

В 2009 году численность занятых была вдвое выше, чем в 2008 и 2010 годах.

Выводы о функции nr.employed:

  • Существует отрицательная корреляция (-0,36) между nr.employed и y.
  • Существует огромная разница между медианами nr.employed для ответов ДА/НЕТ.
  • Значения:
    — количество уникальных значений: 11
    — варьируется от 4963,6 до 5228,1.

4.3.6 Выходная переменная (Цель)

y: has the client subscribed a term deposit? (binary: 'yes','no')

Сначала дистрибутив:

  • Весьма несбалансированное распределение в целом
  • Доля ДА-ответов росла с каждым годом

Давайте посмотрим на совокупную долю ДА во всем наборе данных:

А теперь проанализируем прирост ДА-ответов за год:

2008 г. был лучшим, и 2009 г. недалеко от него, но на этот результат, безусловно, повлияло неравномерное распределение наблюдений по годам.

Тогда как насчет скорости роста? Это даст нам гораздо лучшие значения для сравнения. Давай проверим:

Теперь мы видим, что хотя в 2010 году и наблюдается наименьший рост, этот рост был самым быстрым за все годы.

Выводы о функции y (цель):

  • В целом сильно несбалансированное распределение (89% НЕТ против 11% ДА).
  • Доля ДА-ответа с каждым годом росла.
  • 2008 год имеет самый высокий, но в то же время самый медленный рост доли YES.
  • 2010 год имеет самый низкий, но в то же время самый быстрый рост доли YES.

5 Резюме

В своем EDA я рассматривал только отношения «функция против периода времени + цель», потому что я готовился к следующим шагам проекта ML-классификации: выбор функций, предварительная обработка данных, поиск гиперпараметров, подгонка модели и, наконец, оценка модели.

Поскольку мы работаем с банковскими данными, и людей просят принять решение о своих финансах, опять же, я полагаю, все вы согласитесь, что на их ответы в той или иной степени влияет текущая экономическая ситуация. Именно поэтому я добавил новую функцию под названием year. И я думаю, что это действительно помогло мне получить более глубокое представление о том, что происходит.

В следующей главе я расскажу о предварительной обработке данных и выборе признаков.

Надеюсь, этот EDA был интересен и полезен для вас. Если у вас есть какие-либо вопросы, добро пожаловать в раздел комментариев ниже. Нажмите thumbs up 👍 и подпишитесь, если вам понравилось!

Спасибо за ваше время! 🎉
Подпишитесь на меня, чтобы не пропустить интересные темы 😉👍