Kostenlos

Машинное обучение доступным языком

Text
Als gelesen kennzeichnen
Schriftart:Kleiner AaGrößer Aa

Преобразование данных

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

Стандартизация

Чтобы числа разной величины в разных признаках не путали модель, приведем их к единому масштабу. В этом нам поможет стандартизация (standardization). Это преобразование значений таким образом, что из каждого наблюдения вычитается среднее значение фичи. Затем результат делится на стандартное отклонение (standard deviation) этого признака. Стандартное отклонение показывает, насколько исходное значение ячейки отклоняется от среднего значения столбца. К примеру, в столбце “Длительность” средним значением является 258 секунд. Для ряда № 4 длительность равна 103. Стандартное отклонение равно 258 – 103 = 155 секунд. Стандартизованное значение будет равно: (103 – 258) ÷ 155 ≈ 0,98.

x = StandardScaler().fit_transform(x)

pd.DataFrame(data = x, columns = features).head()

StandardScaler() на месте заменил данные на их стандартизированную версию.


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

Нормализация

Существует еще несколько возможных стадий EDA. К этому датасету их применять уже не стоит.

Один из них – это нормализация (normalization). Это похоже на перевод в процент от максимального значения. Допустим, для того же столбца “Длительность” максимальным значением является 4918 секунд. У записи № 4, где значением длительности является 103, нормализация происходит так: 103 ÷ 4918 ≈ 0,02.

Мы прошлись лишь по EDA классических табличных данных. Для других разновидностей информации применяются совершенно иные методы.

Пересэмплирование
(oversampling)

Классов у банковского датасета всего два – “Да” (взял кредит) и “Нет” (не взял). То есть мы имеем дело с двоичной классификацией (binary classification).

Уравняем доли классов с помощью техники переcэмплирования синтетического меньшинства (SMOTE). Для этого категориальные и булевые признаки придется конвертировать в числовые (такое требование у SMOTE). Перечислим еще раз категориальные признаки в виде списка. pandas по умолчанию присваивает им общий тип – “объект”, потому сменим тип на категориальный явно. pandas.Series.cat.codes заменит текст на буквы на месте.

categoricalColumns = ['Работа', 'Семейный статус', 'Образование', 'Контакт', 'Месяц', 'День недели', 'Доходность']

df[categoricalColumns] = df[categoricalColumns].astype('category')

df[categoricalColumns] = df[categoricalColumns].apply(lambda x: x.cat.codes)

Тоже самое для булевых признаков:

booleanColumns = ['Кредитный дефолт', 'Ипотека', 'Займ', 'y']

df[booleanColumns] = df[booleanColumns].astype('category')

df[booleanColumns] = df[booleanColumns].apply(lambda x: x.cat.codes)

Посмотрим, насколько сбалансирован наш датасет. Для этого разделим его на X (все факторы) и y (целевой признак):

X = df.loc[:, df.columns != 'y']

y = df.iloc[:, -1]

Подсчитаем представителей каждого из двух классов:

counter = Counter(y)

print(counter)

Разница между классами почти девятикратная:

Counter({'Нет': 36548, 'Да': 4640})

Запускаем SMOTE:

oversample = SMOTE()

X, y = oversample.fit_resample(X, y)

И вызываем счетчик классов еще раз:

counter = Counter(y)

print(counter)

Теперь наступил баланс. Модель не будет ошибаться из-за перекоса.

Counter({'Нет': 36548, 'Да': 36548})

Другие методы разведочного анализа данных

Зачастую немалый объем работы помимо EDA представляет собой скраббинг (scrubbing), в который входят:

• Исправление грамматических ошибок

• Удаление не несущих смысла частей текста (например, номер обращения из строки с заявкой пользователя)

• Удаление пустых или слишком коротких текстовых ячеек (из них не извлечь смысл)

• В отдельную категорию преобразований помещу методы, которые выполняются над текстовыми данными после EDA и в преддверии моделирования:

• Стемминг (stemming) – извлечение основ слов

• Лемматизация (lemmatization) – приведение слова к исходной форме.

Для начала более чем достаточно. Рекомендую изучать EDA других типов данных, когда наступит комфорт в обращении с классическими табличными датасетами.

Ноутбук с кодом можно пощупать с помощью QR-кода.



Модель



Модель – это код, который прогнозирует или преобразовывает. Она может выражаться одним числом, таким как среднее значение датасета, функцией y = a * x + b или набором правил дерева решений.

Список существующих моделей постоянно растет. Но вот некоторые популярные из них:

• Бустинг (boosting)

• Машина градиентного бустинга (GBM)

• Дерево решений (decision tree)

• Линейная регрессия (linear regression)

• Логистическая регрессия (logistic regression)

• Метод k-ближайших соседей (kNN)

• Метод k-средних (K-Means)

• Метод опорных векторов (SVM)

• Наивный байесовский классификатор (naive Bayes)

• Случайный лес (random forest)

В отдельную категорию выносят ансамблевые модели, то есть комбинации перечисленных выше видов.

Моделирование



Давайте попробуем построить дерево решений. Этот инструмент определяет способы разделения данных на группы на основе различных условий.

Выделим столбцы-предикторы X, на которых будет основывать свое предсказание модель, и целевой признак y – ответ на вопрос “Возьмет ли клиент кредит?”:

X = df[df.columns[:-1]]

y = df['y']

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

Эти новые сведения – и есть тестовые данные. Они используются для оценки производительности модели. Так мы получим представление о том, насколько хорошо модель будет работать на новой информации в будущем. test_size, равный 0.3 означает, что размер тестовой выборки составляет 30% от общего объема данных. 70% приходится, соответственно, на тренировочные.

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=25, shuffle=True)

Инициируем экземпляр дерева решений. max_depth означает количество разветвлений, как бы этажность дерева:



В random_state можно записать любое число. Этот параметр позволит перезапустить модель в будущем и получить подобные результаты. Метод fit() принимает тренировочную часть данных и непосредственно учит модель.

tr = tree.DecisionTreeClassifier(max_depth=3, random_state=25)

tr.fit(X_train, y_train)

Модель готова, и теперь мы визуализируем дерево с помощью matplotlib.figure(). У дерева решений scikit-learn есть свой метод plot_tree(), где лаконично указываются и названия признаков. Параметр filled, равный True, раскрашивает узлы. rounded придает узлам-прямоугольникам небольшое закругление. fontsize отвечает за размер шрифта.

fig=plt.figure(figsize=(23,15))

tree.plot_tree(tr.fit(X_train, y_train), feature_names=X.columns, filled=True, rounded=True, fontsize=16)



Часть этого дерева мы с легкостью интерпретируем сами. Если число сотрудников меньше или равно 5087, мы учитываем длительность разговора. Если длительность меньше или равна 172,5 секунд, то учитываем доходность. Если доходность меньше 1,5 (значение стандартизировано и не является суммой в валюте), 1134 не возьмут кредит, а 202 возьмут. Голубым цветом окрашен класс большинства. value показывает, сколько записей классов “взял” / “не взял” попадает в категорию того или иного разветвления. Мы установили глубину дерева равной трем, так что ветвление можно продолжать.

Весьма неочевидная логика, но так в банках решения и принимают.

Вы могли подметить значения gini и samples в разветвлениях. Индекс Джини (Gini) показывает вероятность того, что случайный экземпляр будет неправильно классифицирован при случайном выборе. samples – число записей в данном разветвлении. То есть сколько из них удовлетворяют всем условиям вплоть до корня дерева (корень здесь сверху).

Пощупать модель можно с помощью QR-кода.

Настало время оценить производительность нашей модели.