Блиц-проверка алгоритмов машинного обучения: скорми свой набор данных библиотеке scikit-learn

Глобальная паутина изо дня в день пополняется статьями о популярных, наиболее употребляемых алгоритмах машинного обучения для решения различных задач. Причём основа этих статей, немного изменённая по форме в том или ином месте, кочует от одного исследователя данных к другому. При этом все эти работы объединяет один общепринятый, непреложный постулат: применение того или иного алгоритма машинного обучения зависит от размера и природы имеющихся в распоряжении данных и поставленной задачи.
Вдобавок к этому особо настоявшиеся исследователи данных, делясь своим опытом, подчёркивают: «Выбор метода оценки должен частично зависеть от ваших данных и от того, в чём, по вашему мнению, модель должна быть хороша» («Data Science: инсайдерская информация для новичков. Включая язык R», авторы Кэти О’Нил, Рэйчел Шатт).
Другими словами, за плечами статистика/исследователя данных должен быть не только опыт в предметной области, но и широкий багаж разношёрстных знаний: «Исследователь данных – тот, кто обладает познаниями в следующих сферах: математика, статистика, вычислительная техника, машинное обучение, визуализация, средства обмена данными…» (из той же книги). Только основательно загрузив в голову познания из вышеупомянутых областей можно подступать к машинному обучению и находить решения обозначенных проблем.
Как по мне, подобное начало вполне годится для какой-нибудь очередной полуторакилограммовой книги по Data Science, либо научной статьи-страшилки с последующими «ниочёмными» двухэтажными формулами, символами и закорючками, оказывающими гнетущее, тягчайшее воздействие на новичков в области машинного обучения и просто случайно заинтересовавшихся данным направлением неискушённых читателей, не обременённых «необходимыми знаниями». К тому же круглое число 10 из тех же статей про 10 наиболее популярных алгоритмов машинного обучения (к примеру) только усиливают накладываемый эффект.
На habr’е также отличились: «Ответ на вопрос: “Какой алгоритм машинного обучения использовать?”- всегда звучит так: “Смотря по обстоятельствам”. Выбор алгоритма зависит от объёма, качества и природы данных. Он зависит от того, как вы распорядитесь результатом. Он зависит от того, как из алгоритма были созданы инструкции для реализующего его компьютера, а ещё от того, сколько у вас времени. Даже самые опытные специалисты по анализу данных не скажут вам, какой алгоритм лучше, пока сами не попробуют».
Бесспорно, все эти знания, а также упорство и интерес необходимы и пригодятся в достижении хороших результатов не только на пути постижения машинного обучения, но и во многих других направлениях. К тому же они облегчат понимание того, что алгоритмов машинного обучения (далее – алгоритмов) далеко не один десяток; но это уже потом, при самостоятельном изучении.
Моя цель – познакомить читателя с наиболее используемыми алгоритмами с практической и доступной точки зрения. (Подстелить интерес в повествовании должен тот факт, что я отнюдь не программист и – уж тем более – не математик (свят-свят-свят!). Инженерное образование плюс опыт в «предметной отрасти» размером 10 лет (прямо какое-то магическое число) – вот, как говорится, и все мои вещи, весь мой багаж, с которым я пошёл в лоб на машинное обучение. Благодаря накопившемуся опыту в «нефтянке», идеи применения искусственных нейронных сетей и алгоритмов машинного обучения нашлись сразу (читай – имелись необходимые наборы данных). Оставалось лишь разобраться с малым – научиться крутить-вертеть данными, чтобы корректно подать их на вход «программы» и какой, собственно, алгоритм выбрать. И далее по замкнутому кругу. Отмечу, что путь мой был тернистым и весёлым — «пули свистели над головой» (из м/ф «Приключения Фунтика»), — но всё же мне удавалось делать заметки, и если обозначится интерес, то в будущем опубликую и другие сообщения.)
Итак, предлагаю подступиться к «машинлёрнингу» с другой стороны: почему бы не скормить имеющийся у вас набор данных (в примерах будут подгружены наборы данных, хорошо поддающийся обучению) множеству алгоритмов сразу, а по результатам решить, каким из них уделить более пристальное внимание с последующим тщательным изучением и подбором оптимальных параметров, усиливающих результат. Более того, главная ценность метода, о котором речь впереди, в том, что его результаты позволят ответить на вопрос, чего стоит ваш набор данных: «начинайте с решения задачи и убедитесь в том, что вам есть что оптимизировать» (тоже от какого-то настоявшегося статистика пошло, «респект» ему, совет дельный!).
Известно, что основная масса задач, решаемых при помощи алгоритмов, относится к проблемам классификации (classification) и регрессионного анализа (predictive analysis). Под классификацией понимается устойчивое разграничение единиц наблюдения (экземпляров) набора данных к определённой категории (классу) по результатам обучения. Регрессионный анализ представляет собой набор статистических методов и процессов для оценки взаимосвязи между переменными [Статистика: Учеб.пособие/Под ред. проф. М.Р. Ефимовой. – М.: ИНФРА-М, 2002]. Цель регрессионного анализа состоит в том, чтобы оценить значение непрерывной выходной переменной по значениям входных переменных [ссылка].
Оставим за скобками тот факт, что регрессионный анализ имеет в своём распоряжении два разных метода – predictive modeling и forecasting. Отметим только, что если имеется временной ряд (time-series data), то с помощью регрессионной модели на основе явного тренда при соблюдении стационарности (постоянства) можно выполнить прогнозирование (forecasting). Если условия формирования уровней временного ряда изменяются, то есть стационарности (non-stationary process) не наблюдается, то дело за predictive modeling. Особо нацеленным на полное овладение ML предлагаю прочесть вот эту статью на английском языке: ссылка. Если по этому поводу возникнет дискуссия, то с удовольствием приму в ней участие.
Поскольку в примерах данной статьи временные ряды использоваться не будут, то под термином прогнозирование понимается predictive analysis.
Для решения проблем классификации и прогнозирования подходит целый диапазон алгоритмов, часть из которых мы рассмотрим далее. Для удобства последующий текст будет разделён на две части: в первой рассмотрим наиболее распространённые алгоритмы классификации, вторую посвятим алгоритмам регрессионного анализа. Для каждой части будет представлен «игрушечный» набор данных, подгруженный из библиотеки scikit-learn (v0.21.3): digits dataset (classification) и boston house-price dataset (regression), а также приведены ссылки на каждый рассматриваемый алгоритм библиотеки scikit-learn для самостоятельного ознакомления и, возможно, изучения.
Все примеры кода выполнены в консоли IDE Spyder 3.3.3 на Python 3.7.3.
Проблема классификации
Сначала импортируем необходимые модули и функции, которые мы будем использовать для решения проблемы классификации данных:
# Импортирование необходимых модулей и атрибутов from sklearn.datasets import load_digits from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression from sklearn.discriminant_analysis import LinearDiscriminantAnalysis from sklearn.neighbors import KNeighborsClassifier from sklearn.tree import DecisionTreeClassifier from sklearn.naive_bayes import GaussianNB from sklearn.svm import LinearSVC from sklearn.svm import SVC from sklearn.neural_network import MLPClassifier from sklearn.ensemble import BaggingClassifier from sklearn.ensemble import RandomForestClassifier from sklearn.ensemble import ExtraTreesClassifier from sklearn.ensemble import AdaBoostClassifier from sklearn.ensemble import GradientBoostingClassifier from sklearn.model_selection import KFold from sklearn.model_selection import cross_val_score from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler from sklearn.preprocessing import MinMaxScaler from sklearn.preprocessing import Normalizer from matplotlib import pyplot
Загружаем набор данных ‘digits’ напрямую из модуля ‘sklearn.datasets’ :
# Загрузка набора данных dataset = load_digits()
IDE Spyder предоставляет удобный инструмент «Менеджер переменных», который пригодится на всех порах изучения машинного обучения (во всяком случае, для меня), как и другие «фишки»:
Запускаем код. В консоли «менеджер переменных» кликаем на переменную dataset. Выводится следующий словарь:

Описание набора данных следующее:

В данном примере ключ ‘images’ нам не понадобится, поэтому переменной Х присваиваем ‘data’, представляющий собой многомерный массив NumPy с набором признаков, размерностью 1797 строк на 64 столбца, а переменной Y – ‘target’, многомерный массив NumPy с маркером на каждую строку.
# Загрузка набора данных # dataset = load_digits() X = dataset.data Y = dataset.target
Далее разделяем набор данных на тренировочную и тестовую части, настраиваем параметры оценивания алгоритмов (используется кросс-валидация[один, два]), определяя метрику ‘accuracy’ в параметре ‘scoring’ [ссылка]. Accuracy – это доля верно классифицированных объектов относительно общего количества объектов. Чем ближе результат к 1, тем лучше [ссылка]. При этом в одной из книг встречалось, что отличными считаются результаты от 0.95 (или 95%) и выше.
# Разделение набора данных на тренировочные и тестовые части test_size = 0.2 seed = 7 X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=test_size, random_state=seed) # Настройка параметров оценивания алгоритма num_folds = 10 n_estimators = 100 scoring = 'accuracy'
Переменные X_train и Y_train пустим на тренировочные нужды, X_test и Y_test – на выработку прогнозных значений. При этом переменная Y_test не участвует в расчёте прогноза: с помощью метода ‘score’, одинакового для каждого из представленных далее алгоритмов, мы подсчитаем правильные ответы с помощью метрики ‘accuracy’. Это позволит нам судить о том, как справляется алгоритм с поставленной задачей. Не спорю, с нашей стороны это так по-человечески подло не подсказывать машине правильные ответы, но как иначе проверить её performance?
Ниже представлен список алгоритмов, которым-то мы и скормим набор данных. По результатам выполнения расчётов будем делать вывод, какой алгоритм (какие из алгоритмов) показывает наибольшую эффективность. Данный метод вполне может носить название «блиц-проверка алгоритмов машинного обучения» (далее – блиц-проверка).
Для удобства вывода информации рядом с каждым алгоритмом будет проставлена аббревиатура. Необходимо отметить, что настройки каждого алгоритма принимаются по умолчанию (default), за исключением некоторых моментов, дабы предоставить равные условия.
Линейные алгоритмы:
— Логистическая регрессия* / Logistic Regression (‘LR’)
* Слово «регрессия» может сбить с толку. Но не забываем, что «Логистическая регрессия» — это алгоритм классификации
— Линейный дискриминантный анализ / Linear Discriminant Analysis (‘LDA’)
Нелинейные алгоритмы:
— Метод k-ближайших соседей (классификация) / K-Neighbors Classifier (‘KNN’)
— Деревья принятия решений / Decision Tree Classifier (‘CART’)
— Наивный классификатор Байеса / Naive Bayes Classifier (‘NB’)
— Линейный метод опорных векторов (классификация) / Linear Support Vector Classification (‘LSVC’)
— Метод опорных векторов (классификация) / C-Support Vector Classification (‘SVC’)
Алгоритм искусственной нейронной сети:
Ансамблевые алгоритмы:
— Bagging (классификация) / Bagging Classifier (‘BG’) (Bagging = Bootstrap aggregating)
— Случайный лес (классификация) / Random Forest Classifier (‘RF’)
— Экстра-деревья (классификация) / Extra Trees Classifier (‘ET’)
— AdaBoost (классификация) / AdaBoost Classifier (‘AB’) (AdaBoost = Adaptive Boosting)
— Градиентный boosting (классификация) / Gradient Boosting Classifier (‘GB’)
Таким образом, список ‘models’ содержит следующие модели:
models = [] models.append(('LR', LogisticRegression())) models.append(('LDA', LinearDiscriminantAnalysis())) models.append(('KNN', KNeighborsClassifier())) models.append(('CART', DecisionTreeClassifier())) models.append(('NB', GaussianNB())) models.append(('LSVC', LinearSVC())) models.append(('SVC', SVC())) models.append(('MLP', MLPClassifier())) models.append(('BG', BaggingClassifier(n_estimators=n_estimators))) models.append(('RF', RandomForestClassifier(n_estimators=n_estimators))) models.append(('ET', ExtraTreesClassifier(n_estimators=n_estimators))) models.append(('AB', AdaBoostClassifier(n_estimators=n_estimators, algorithm='SAMME'))) models.append(('GB', GradientBoostingClassifier(n_estimators=n_estimators)))
Как уже было сказано, оценивание эффективности каждого алгоритма выполняется с помощью кросс-валидации. В итоге выводится сообщение (msg – сокр. от message), содержащее следующие сведения: имя модели в виде аббревиатуры, средняя оценка 10-кратной перекрёстной проверки на тренировочных данных (метрика ‘accuracy’), в скобках представлено среднее квадратичное отклонение (standard deviation), а также значение метрики ‘accuracy’ на тестовых данных.
# Оценивание эффективности выполнения каждого алгоритма scores = [] names = [] results = [] predictions = [] msg_row = [] for name, model in models: kfold = KFold(n_splits=num_folds, random_state=seed) cv_results = cross_val_score(model, X_train, Y_train, cv=kfold, scoring=scoring) names.append(name) results.append(cv_results) m_fit = model.fit(X_train, Y_train) m_predict = model.predict(X_test) predictions.append(m_predict) m_score = model.score(X_test, Y_test) scores.append(m_score) msg = "%s: train = %.3f (%.3f) / test = %.3f" % (name, cv_results.mean(), cv_results.std(), m_score) msg_row.append(msg) print(msg)
После запуска кода получаем следующие результаты:
LR: train = 0.957 (0.014) / test = 0.948 LDA: train = 0.951 (0.014) / test = 0.946 KNN: train = 0.985 (0.013) / test = 0.981 CART: train = 0.843 (0.033) / test = 0.830 NB: train = 0.819 (0.048) / test = 0.806 LSVC: train = 0.942 (0.017) / test = 0.928 SVC: train = 0.343 (0.079) / test = 0.342 MLP: train = 0.972 (0.012) / test = 0.961 BG: train = 0.952 (0.021) / test = 0.941 RF: train = 0.968 (0.017) / test = 0.965 ET: train = 0.980 (0.010) / test = 0.975 AB: train = 0.827 (0.049) / test = 0.823 GB: train = 0.964 (0.013) / test = 0.968
Диаграмма размаха («ящик с усами») (box-and-whiskers diagram or plot, box plot):

В результате выполнения блиц-проверки на «сырых» данных видно, что наибольшую эффективность на тестовых данных показали алгоритмы ‘KNN’ (k-ближайшие соседи), ‘ET’ (экстра-деревья), ‘GB’ (градиентный «бустинг»), ‘RF’ (случайный лес) и ‘MLP’ (многослойный персептрон):
KNN: train = 0.985 (0.013) / test = 0.981 ET: train = 0.980 (0.010) / test = 0.975 GB: train = 0.964 (0.013) / test = 0.968 RF: train = 0.968 (0.017) / test = 0.965 MLP: train = 0.972 (0.012) / test = 0.961 LR: train = 0.957 (0.014) / test = 0.948 LDA: train = 0.951 (0.014) / test = 0.946 BG: train = 0.952 (0.021) / test = 0.941 LSVC: train = 0.942 (0.017) / test = 0.928 CART: train = 0.843 (0.033) / test = 0.830 AB: train = 0.827 (0.049) / test = 0.823 NB: train = 0.819 (0.048) / test = 0.806 SVC: train = 0.343 (0.079) / test = 0.342
При этом многие алгоритмы очень привередливы к тем данным, которые им подают. Поэтому одним из обязательных шагов является так называемая предварительная подготовка данных (data pre-processing [ссылка])
Однако бывает, что алгоритм показывает лучшие результаты без предварительной обработки. Отсюда следующая рекомендация: включить в блиц-проверку несколько преобразований исходного набора данных и по выполнении расчётов сравнить результаты, чтобы выловить суть проблемы в целом.
Наиболее часто используемыми методами предварительной подготовки данных являются:
Данные операции с последующей оценкой можно автоматизировать и поставить на конвейер с помощью инструмента Pipeline.
Фрагмент кода со стандартизацией исходных данных имеет следующий вид:
# Блиц-проверка алгоритмов на стандартизованных исходных данных # Стандартизация исходных данных (функция StandardScaler) pipelines = [] pipelines.append(('SS_LR', Pipeline([('Scaler', StandardScaler()), ('LR', LogisticRegression())]))) pipelines.append(('SS_LDA', Pipeline([('Scaler', StandardScaler()), ('LDA', LinearDiscriminantAnalysis())]))) pipelines.append(('SS_KNN', Pipeline([('Scaler', StandardScaler()), ('KNN', KNeighborsClassifier())]))) pipelines.append(('SS_CART', Pipeline([('Scaler', StandardScaler()), ('CART', DecisionTreeClassifier())]))) pipelines.append(('SS_NB', Pipeline([('Scaler', StandardScaler()), ('NB', GaussianNB())]))) pipelines.append(('SS_LSVC', Pipeline([('Scaler', StandardScaler()), ('LSVC', LinearSVC())]))) pipelines.append(('SS_SVC', Pipeline([('Scaler', StandardScaler()), ('SVC', SVC())]))) pipelines.append(('SS_MLP', Pipeline([('Scaler', StandardScaler()), ('MLP', MLPClassifier())]))) pipelines.append(('SS_BG', Pipeline([('Scaler', StandardScaler()), ('BG', BaggingClassifier(n_estimators=n_estimators))]))) pipelines.append(('SS_RF', Pipeline([('Scaler', StandardScaler()), ('RF', RandomForestClassifier(n_estimators=n_estimators))]))) pipelines.append(('SS_ET', Pipeline([('Scaler', StandardScaler()), ('ET', ExtraTreesClassifier(n_estimators=n_estimators))]))) pipelines.append(('SS_AB', Pipeline([('Scaler', StandardScaler()), ('AB', AdaBoostClassifier(n_estimators=n_estimators, algorithm='SAMME'))]))) pipelines.append(('SS_GB', Pipeline([('Scaler', StandardScaler()), ('GB', GradientBoostingClassifier(n_estimators=n_estimators))]))) # Оценивание эффективности выполнения каждого алгоритма scores_SS = [] names_SS = [] results_SS = [] predictions_SS = [] msg_SS = [] for name, model in pipelines: kfold = KFold(n_splits=num_folds, random_state=seed) cv_results = cross_val_score(model, X_train, Y_train, cv=kfold) names_SS.append(name) results_SS.append(cv_results) m_fit = model.fit(X_train, Y_train) m_predict = model.predict(X_test) predictions_SS.append(m_predict) m_score = model.score(X_test, Y_test) scores_SS.append(m_score) msg = "%s: train = %.3f (%.3f) / test = %.3f" % (name, cv_results.mean(), cv_results.std(), m_score) msg_SS.append(msg) print(msg) # ящик с усами (StandardScaler) fig = pyplot.figure() fig.suptitle('Сравнение результатов выполнения алгоритмов на стандарт. данных') ax = fig.add_subplot(111) red_square = dict(markerfacecolor='r', marker='s') pyplot.boxplot(results_SS, flierprops=red_square) ax.set_xticklabels(names_SS, rotation=45) pyplot.show()
Обратите внимание на добавку ‘_SS’ (сокращение от StandardScaler) к именам списков. Это сделано для того, чтобы не сваливать в кучу результаты, а также для их удобного просмотра с помощью «менеджера переменных» после выполненных преобразований.
Запуск фрагмента кода выдаёт следующие результаты:
SS_LR: train = 0.958 (0.015) / test = 0.949 SS_LDA: train = 0.951 (0.014) / test = 0.946 SS_KNN: train = 0.968 (0.023) / test = 0.970 SS_CART: train = 0.853 (0.036) / test = 0.835 SS_NB: train = 0.756 (0.046) / test = 0.751 SS_LSVC: train = 0.945 (0.018) / test = 0.941 SS_SVC: train = 0.976 (0.015) / test = 0.990 SS_MLP: train = 0.976 (0.012) / test = 0.973 SS_BG: train = 0.947 (0.018) / test = 0.948 SS_RF: train = 0.973 (0.016) / test = 0.970 SS_ET: train = 0.980 (0.012) / test = 0.975 SS_AB: train = 0.827 (0.049) / test = 0.823 SS_GB: train = 0.964 (0.013) / test = 0.968
Ящик с усами (StandardScaler):

По итогам расчёта на стандартизованных данных в лидеры выбились следующие алгоритмы:
SS_SVC: train = 0.976 (0.015) / test = 0.990 SS_ET: train = 0.980 (0.012) / test = 0.975 SS_MLP: train = 0.976 (0.012) / test = 0.973 SS_KNN: train = 0.968 (0.023) / test = 0.970 SS_RF: train = 0.973 (0.016) / test = 0.970 SS_GB: train = 0.964 (0.013) / test = 0.968 SS_LR: train = 0.958 (0.015) / test = 0.949 SS_BG: train = 0.947 (0.018) / test = 0.948 SS_LDA: train = 0.951 (0.014) / test = 0.946 SS_LSVC: train = 0.945 (0.018) / test = 0.941 SS_CART: train = 0.853 (0.036) / test = 0.835 SS_AB: train = 0.827 (0.049) / test = 0.823 SS_NB: train = 0.756 (0.046) / test = 0.751
Как говорится, из грязи в князи: метод опорных векторов (‘SVC’), накормленный стандартизованными данными, уделал остальные, показав отличный результат. При «ручной» проверке, сравнивая значения переменных Y_test и predictions_SS[6], алгоритм не пережевал только несколько значений.
Далее выполняется аналогичный код для функций MinMaxScaler (масштабирование) и Normalizer (нормализация). Приводить полностью код в статье не стану. Вы можете скачать его из моего репозитория на GitHub’е: ссылка.
Только не забудьте ненадолго зависнуть и посмеяться про себя над ‘for educational purpose only’! 🙂
В итоге, после прохода по всему коду, получаем следующие результаты:
LR: train = 0.957 (0.014) / test = 0.948 LDA: train = 0.951 (0.014) / test = 0.946 KNN: train = 0.985 (0.013) / test = 0.981 CART: train = 0.843 (0.033) / test = 0.830 NB: train = 0.819 (0.048) / test = 0.806 LSVC: train = 0.942 (0.017) / test = 0.928 SVC: train = 0.343 (0.079) / test = 0.342 MLP: train = 0.972 (0.012) / test = 0.961 BG: train = 0.952 (0.021) / test = 0.941 RF: train = 0.968 (0.017) / test = 0.965 ET: train = 0.980 (0.010) / test = 0.975 AB: train = 0.827 (0.049) / test = 0.823 GB: train = 0.964 (0.013) / test = 0.968 SS_LR: train = 0.958 (0.015) / test = 0.949 SS_LDA: train = 0.951 (0.014) / test = 0.946 SS_KNN: train = 0.968 (0.023) / test = 0.970 SS_CART: train = 0.853 (0.036) / test = 0.835 SS_NB: train = 0.756 (0.046) / test = 0.751 SS_LSVC: train = 0.945 (0.018) / test = 0.941 SS_SVC: train = 0.976 (0.015) / test = 0.990 SS_MLP: train = 0.976 (0.012) / test = 0.973 SS_BG: train = 0.947 (0.018) / test = 0.948 SS_RF: train = 0.973 (0.016) / test = 0.970 SS_ET: train = 0.980 (0.012) / test = 0.975 SS_AB: train = 0.827 (0.049) / test = 0.823 SS_GB: train = 0.964 (0.013) / test = 0.968 MMS_LR: train = 0.961 (0.013) / test = 0.953 MMS_LDA: train = 0.951 (0.014) / test = 0.946 MMS_KNN: train = 0.985 (0.013) / test = 0.981 MMS_CART: train = 0.850 (0.027) / test = 0.840 MMS_NB: train = 0.796 (0.045) / test = 0.786 MMS_LSVC: train = 0.964 (0.012) / test = 0.958 MMS_SVC: train = 0.963 (0.016) / test = 0.956 MMS_MLP: train = 0.972 (0.011) / test = 0.963 MMS_BG: train = 0.948 (0.024) / test = 0.946 MMS_RF: train = 0.973 (0.014) / test = 0.968 MMS_ET: train = 0.983 (0.010) / test = 0.981 MMS_AB: train = 0.827 (0.049) / test = 0.823 MMS_GB: train = 0.963 (0.013) / test = 0.968 N_LR: train = 0.938 (0.020) / test = 0.919 N_LDA: train = 0.952 (0.013) / test = 0.949 N_KNN: train = 0.981 (0.012) / test = 0.985 N_CART: train = 0.834 (0.028) / test = 0.825 N_NB: train = 0.825 (0.043) / test = 0.805 N_LSVC: train = 0.960 (0.014) / test = 0.953 N_SVC: train = 0.551 (0.053) / test = 0.586 N_MLP: train = 0.963 (0.018) / test = 0.946 N_BG: train = 0.949 (0.016) / test = 0.938 N_RF: train = 0.973 (0.015) / test = 0.970 N_ET: train = 0.982 (0.012) / test = 0.980 N_AB: train = 0.825 (0.040) / test = 0.820 N_GB: train = 0.953 (0.022) / test = 0.956
‘Top 5’ результатов:
SS_SVC: train = 0.976 (0.015) / test = 0.990 N_KNN: train = 0.981 (0.012) / test = 0.985 KNN: train = 0.985 (0.013) / test = 0.981 MMS_KNN: train = 0.985 (0.013) / test = 0.981 MMS_ET: train = 0.983 (0.010) / test = 0.981
Таким образом, по результатам блиц-проверки алгоритмов машинного обучения для решения проблемы классификации набора данных ‘digits’ наиболее подходящими алгоритмами машинного обучения являются: метод k-ближайших соседей (‘KNN’), метод опорных векторов (‘SVC’) и экстра-деревья (‘ET’). Данным алгоритмам стоит уделить более пристальное внимание для дальнейшего развития результатов, направленных на увеличение эффективности расчётов. Всё, как говорится, решаемо.
И на этой приподнятой ноте гладко переходим ко 2-й части.
Проблема прогнозирования
Двигаемся по накатанной:
# Импортирование необходимых модулей и атрибутов from sklearn.datasets import load_boston from sklearn.model_selection import train_test_split from sklearn.linear_model import LinearRegression from sklearn.linear_model import Ridge from sklearn.linear_model import Lasso from sklearn.linear_model import ElasticNet from sklearn.linear_model import LarsCV from sklearn.linear_model import BayesianRidge from sklearn.neighbors import KNeighborsRegressor from sklearn.tree import DecisionTreeRegressor from sklearn.svm import LinearSVR from sklearn.svm import SVR from sklearn.ensemble import AdaBoostRegressor from sklearn.ensemble import BaggingRegressor from sklearn.ensemble import ExtraTreesRegressor from sklearn.ensemble import GradientBoostingRegressor from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import KFold from sklearn.model_selection import cross_val_score from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler from sklearn.preprocessing import Normalizer from matplotlib import pyplot # Загрузка набора данных dataset = load_boston()
Запускаем код и разбираемся со словарём. Описание и ключи следующие:


Переменной Х присваиваем ключ ‘data’, представляющий собой многомерный массив NumPy с набором признаков, размерностью 506 строк на 13 столбцов, а переменной Y – ‘target’, многомерный массив NumPy с маркером на каждую строку.
# Загрузка набора данных #dataset = load_boston() X = dataset.data Y = dataset.target
Разделяем набор данных на тренировочную и тестовую части, настраиваем параметры оценивания алгоритмов. В параметре ‘scoring’ устанавливаем одну из традиционных для регрессионного анализа метрику ‘r2’:
# Загрузка набора данных dataset = load_boston() X = dataset.data Y = dataset.target # Разделение набора данных на тренировочные и тестовые части test_size = 0.2 seed = 7 X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=test_size, random_state=seed) # Настройка параметров оценивания алгоритма num_folds = 10 n_iter = 1000 n_estimators = 100 scoring = 'r2'
R2 – коэффициент детерминации – это доля дисперсии зависимой переменной, объясняемая рассматриваемой моделью (ссылка).
«Коэффициент детерминации для модели с константой принимает значения от 0 до 1. Чем ближе значение коэффициента к 1, тем сильнее зависимость. При оценке регрессионных моделей это интерпретируется как соответствие модели данным. Для приемлемых моделей предполагается, что коэффициент детерминации должен быть хотя бы не меньше 50% (в этом случае коэффициент множественной корреляции превышает по модулю 70%). Модели с коэффициентом детерминации выше 80% можно признать достаточно хорошими (коэффициент корреляции превышает 90%). Равенство коэффициента детерминации единице означает, что объясняемая переменная в точности описывается рассматриваемой моделью» (там же).
Для решения проблемы прогнозирования задействуем следующие алгоритмы:
Линейные алгоритмы:
— Линейная регрессия / Linear Regression (‘LR’)
— Гребневая регрессия (ридж-регрессия) / Ridge Regression (‘R’)
— Лассо-регрессия (от англ. LASSO — Least Absolute Shrinkage and Selection Operator) / Lasso Regression (‘L’)
— Метод регрессии «Эластичная сеть» / Elastic Net Regression (‘ELN’)
— Метод наименьших углов / Least Angle Regression (LARS) (‘LARS’)
— Байесовская гребневая регрессия / Bayesian ridge regression (‘BR’)
Нелинейные алгоритмы:
— Метод k-ближайших соседей (регрессия) / k-nearest neighbors regressor (‘KNR’)
— Деревья регрессии / Decision Tree Regressor (‘DTR’)
— Линейный метод опорных векторов (регрессия) / Linear Support Vector Machine – Regression / (‘LSVR’)
— Метод опорных векторов (регрессия) / Epsilon-Support Vector Regression (‘SVR’)
Ансамблевые алгоритмы:
— AdaBoost (регрессия) / AdaBoost Regressor (‘ABR’) (AdaBoost = Adaptive Boosting)
— Bagging (регрессия) / Bagging Regressor (‘BR’) (Bagging = Bootstrap aggregating)
— Экстра-деревья (регрессия) / Extra Trees Regressor (‘ETR’)
— Градиентный boosting (регрессия) / Gradient Boosting Regressor (‘GBR’)
— Случайный лес (регрессия) / Random Forest Classifier (‘RFR’)
Таким образом, список ‘models’ содержит следующие модели:
models = [] models.append(('LR', LinearRegression())) models.append(('R', Ridge())) models.append(('L', Lasso())) models.append(('ELN', ElasticNet())) models.append(('LARS', Lars())) models.append(('BR', BayesianRidge(n_iter=n_iter))) models.append(('KNR', KNeighborsRegressor())) models.append(('DTR', DecisionTreeRegressor())) models.append(('LSVR', LinearSVR())) models.append(('SVR', SVR())) models.append(('ABR', AdaBoostRegressor(n_estimators=n_estimators))) models.append(('BR', BaggingRegressor(n_estimators=n_estimators))) models.append(('ETR', ExtraTreesRegressor(n_estimators=n_estimators))) models.append(('GBR', GradientBoostingRegressor(n_estimators=n_estimators))) models.append(('RFR', RandomForestRegressor(n_estimators=n_estimators)))
Как и в случае с классификацией, оценивание эффективности каждого алгоритма выполняется с помощью кросс-валидации. Выводимое сообщение содержит следующие сведения: имя модели в виде аббревиатуры, средняя оценка 10-кратной перекрёстной проверки на тренировочных данных (метрика ‘r2’), в скобках представлено среднее квадратичное отклонение (standard deviation), а также коэффициент детерминации r2 на тестовых данных.
# Оценивание эффективности выполнения каждого алгоритма scores = [] names = [] results = [] predictions = [] msg_row = [] for name, model in models: kfold = KFold(n_splits=num_folds, random_state=seed) cv_results = cross_val_score(model, X_train, Y_train, cv=kfold, scoring=scoring) names.append(name) results.append(cv_results) m_fit = model.fit(X_train, Y_train) m_predict = model.predict(X_test) predictions.append(m_predict) m_score = model.score(X_test, Y_test) scores.append(m_score) msg = "%s: train = %.3f (%.3f) / test = %.3f" % (name, cv_results.mean(), cv_results.std(), m_score) msg_row.append(msg) print(msg) # Диаграмма размаха («ящик с усами») fig = pyplot.figure() fig.suptitle('Сравнение результатов выполнения алгоритмов') ax = fig.add_subplot(111) red_square = dict(markerfacecolor='r', marker='s') pyplot.boxplot(results, flierprops=red_square) ax.set_xticklabels(names, rotation=45) pyplot.show()
После запуска кода получаем следующие результаты:
LR: train = 0.746 (0.068) / test = 0.579 R: train = 0.744 (0.067) / test = 0.570 L: train = 0.689 (0.070) / test = 0.641 ELN: train = 0.677 (0.074) / test = 0.662 LARS: train = 0.744 (0.069) / test = 0.579 BR: train = 0.739 (0.069) / test = 0.571 KNR: train = 0.434 (0.288) / test = 0.538 DTR: train = 0.671 (0.145) / test = 0.637 LSVR: train = 0.550 (0.144) / test = 0.459 SVR: train = -0.012 (0.048) / test = -0.003 ABR: train = 0.810 (0.078) / test = 0.763 BR: train = 0.854 (0.064) / test = 0.805 ETR: train = 0.889 (0.047) / test = 0.836 GBR: train = 0.878 (0.042) / test = 0.863 RFR: train = 0.852 (0.068) / test = 0.819

Явные лидеры – ансамблевые методы ‘GBR’ (градиентный «бустинг»), ‘ETR’ (экстра-деревья), ‘RFR’ (случайный лес) и ‘BR’ («бэггинг»):
GBR: train = 0.878 (0.042) / test = 0.863 ETR: train = 0.889 (0.047) / test = 0.836 RFR: train = 0.852 (0.068) / test = 0.819 BR: train = 0.854 (0.064) / test = 0.805 ABR: train = 0.810 (0.078) / test = 0.763 ELN: train = 0.677 (0.074) / test = 0.662 L: train = 0.689 (0.070) / test = 0.641 DTR: train = 0.671 (0.145) / test = 0.637 LR: train = 0.746 (0.068) / test = 0.579 LARS: train = 0.744 (0.069) / test = 0.579 BR: train = 0.739 (0.069) / test = 0.571 R: train = 0.744 (0.067) / test = 0.570 KNR: train = 0.434 (0.288) / test = 0.538 LSVR: train = 0.550 (0.144) / test = 0.459 SVR: train = -0.012 (0.048) / test = -0.003
Один «адабуст», «лошара» эдакая, отстаёт.
Возможно, тройку лидеров причешут стандартизация и нормализация. Давайте выясним, выполнив оставшуюся часть кода.
SS_LR: train = 0.746 (0.068) / test = 0.579 SS_R: train = 0.746 (0.068) / test = 0.578 SS_L: train = 0.678 (0.054) / test = 0.510 SS_ELN: train = 0.665 (0.060) / test = 0.513 SS_LARS: train = 0.744 (0.069) / test = 0.579 SS_BR: train = 0.746 (0.066) / test = 0.576 SS_KNR: train = 0.763 (0.098) / test = 0.739 SS_DTR: train = 0.610 (0.242) / test = 0.629 SS_LSVR: train = 0.727 (0.091) / test = 0.482 SS_SVR: train = 0.653 (0.126) / test = 0.610 SS_ABR: train = 0.811 (0.076) / test = 0.819 SS_BR: train = 0.853 (0.074) / test = 0.813 SS_ETR: train = 0.887 (0.048) / test = 0.846 SS_GBR: train = 0.878 (0.038) / test = 0.860 SS_RFR: train = 0.851 (0.071) / test = 0.818 N_LR: train = 0.751 (0.099) / test = 0.576 N_R: train = 0.287 (0.126) / test = 0.271 N_L: train = -0.030 (0.032) / test = -0.000 N_ELN: train = -0.007 (0.030) / test = 0.023 N_LARS: train = 0.751 (0.099) / test = 0.576 N_BR: train = 0.744 (0.100) / test = 0.589 N_KNR: train = 0.485 (0.192) / test = 0.504 N_DTR: train = 0.729 (0.080) / test = 0.765 N_LSVR: train = 0.182 (0.108) / test = 0.136 N_SVR: train = 0.086 (0.076) / test = 0.084 N_ABR: train = 0.795 (0.053) / test = 0.752 N_BR: train = 0.854 (0.054) / test = 0.827 N_ETR: train = 0.877 (0.048) / test = 0.850 N_GBR: train = 0.852 (0.063) / test = 0.872 N_RFR: train = 0.852 (0.051) / test = 0.801
Как видно, ансамблевые методы по-прежнему впереди всех.
‘Top 5’ вмещает следующие результаты:
N_GBR: train = 0.852 (0.063) / test = 0.872 GBR: train = 0.878 (0.042) / test = 0.863 SS_GBR: train = 0.878 (0.038) / test = 0.860 N_ETR: train = 0.877 (0.048) / test = 0.850 SS_ETR: train = 0.887 (0.048) / test = 0.846
Выведем диаграмму сравнения результатов:

Y-test – это эталон. Пять отборных результатов, представленные на диаграмме, выделены пунктирной линией (dashed). Видно, что все пики были воспроизведены либо с точным повторением, либо в той или иной степени.
Небольшая выдержка ручного сравнения эталонных значений и прогнозных значений алгоритма, входящего в Top 5:

Таким образом, по результатам блиц-проверки алгоритмов машинного обучения для решения проблемы прогнозирования набора данных ‘boston house-price’ наиболее подходящими алгоритмами являются градиентный «бустинг» (‘GBR’) и экстра-деревья (‘ETR’). Данным алгоритмам стоит уделить более пристальное внимание для дальнейшего развития результатов и усиления эффективности прогнозов.
Послесловие
Блиц-проверка алгоритмов машинного обучения позволяет в первом приближении выявить наиболее эффективные алгоритмы для решения проблем классификации и регрессионного анализа (прогнозирования). Мы убедились в этом, обработав набор данных ‘digits’, блестяще рассортировав экземпляры на 10 классов, а также набор данных ‘boston house-price’, «изюмительно» разобравшись с нахождением зависимостей и выполнив «колеблющийся» прогноз зависимой переменной.
Вам же предлагается опробовать этот метод на ваших собственных наборах данных либо на тех, которые вы можете нарыть на различных репозиториях, включая GitHub. К примеру: ссылка.
Раздобудьте подходящий по цели набор данных — и натравите на него стайку алгоритмов в упряжке блиц-проверки. А там и выяснится, чья возьмёт: один в поле не воин. 🙂
И в заключение. Я буду благодарен за ваши комментарии, вопросы и пожелания, так как основу этой статьи составляет информация, которой я делюсь с новыми коллегами по каждому новому проекту в области машинного обучения. У каждого из них своя специализация, про машинное обучение и искусственные нейронные сети многие из них только «где-то слышали», поэтому для меня важно рассказать о сложном, многогранном и, наконец, неподступном (это я про ИНС и машинное обучение в целом):), простым и понятным языком; показать, что не боги горшки обжигают; и что если есть интерес, то можно не один десяток алгоритмов «запрячь». 🙂
P.S. К концу статьи уже сам стал предсказывать, поэтому на подступающие вопросы о том, где я взял схему-шпаргалку на первом рисунке выдаю: всё на том же сайте scikit-learn.org (‘Choosing the right estimator’): ссылка. А олицетворение искусственного интеллекта в виде зарумянившегося Самоделкина – так это по волнам памяти моего счастливого детства.
- машинное обучение
- machine learning
- python
- Python
- Машинное обучение
Saved searches
Use saved searches to filter your results more quickly
Cancel Create saved search
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.
thelie/Data-Science-Portfolio
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Switch branches/tags
Branches Tags
Could not load branches
Nothing to show
Could not load tags
Nothing to show
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Cancel Create
- Local
- Codespaces
HTTPS GitHub CLI
Use Git or checkout with SVN using the web URL.
Work fast with our official CLI. Learn more about the CLI.
Sign In Required
Please sign in to use Codespaces.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching Xcode
If nothing happens, download Xcode and try again.
Launching Visual Studio Code
Your codespace will open once ready.
There was a problem preparing your codespace, please try again.
Latest commit
Git stats
Files
Failed to load latest commit information.
Latest commit message
Commit time
README.md
Data-Science-Portfolio:
Репозиторий для проектов, созданных в ходе изучения машинного обучения и data science.
1. Кредитный скоринг:
Задача: Определить влияние семейного положения, количества детей и других данных на погашение кредита в срок.
Навыки и библиотеки: Pandas, PyMystem3, предобработка данных, лемматизация.
Вывод: Подтверждена зависимость количества детей, семейного положения и уровня дохода и целей кредита на кредитоспособность.
2. Исследование рынка недвижимости в Санкт-Петербурге
Задача: По данным объявлений о продаже квартир в Санкт-Петербурге и области определить параметры влияющие на стоимость недвижимости.
Навыки и библиотеки: Pandas, NumPy, Matplotlib, выявление корреляций, построение графиков.
Вывод: Выявлено сколько обычно занимает продажа.
Найдены населенные пункты с наиболее высокой и низкой стоимостью жилья в регионе, Исследована зависимость цены от удаленности от центра. Определены факторы влияющие на стоимость квартиры.
3. Анализ тарифов телеком компании
Задача: По небольшой выборке данных пользователей определить наиболее выгодный тариф.
Навыки и библиотеки: Pandas, NumPy, Matplotlib, SciPy, статистический анализ, проверка гипотез.
Вывод: В ходе анализа подтвердилось различие в выручке пользователей разных тарифов. Различие средней выручки абонентов Москвы и других регионов не выявлено.
4. Исследование игровых платформ
Задача: Определить актуальные и наиболее прибыльные игровые платформы по историческим данным о продажах игр. Найти наиболее популярные жанры в различных регионах.
Использованные библиотеки: Pandas, NumPy, Matplotlib, SciPy, Requests, статистический анализ, проверка гипотез, http запросы.
Вывод: По результатам анализа выявлено что для планирования игр продаж на 2017 год стоит ориентироваться на игровые платформы Playstation 4 и Xbox One. Они являются актуальными и наиболее прибыльными на текущих период с 2013 года. Наиболее перспективным жанром являются Action, Shooter и Sports с возрастным рейтингом 17+, для всех возрастов и 10+ лет.
5. Рекомендации нового тарифа телеком компании
Анализ поведения клиентов, использующих архивные тарифы, для рекомендации новых тарифов.
Задача: Построить модель классификации для рекомендации нового тарифа.
Использованные библиотеки: Pandas, NumPy, Scikit-learn, Catboost, различные модели классификации, подбор параметров, проверка моделей на вменяемость.
Вывод:
- Сравнение результата случайной модели с другими доказывает вменяемость всех рассмотренных моделей.
- По результатам тестирования модели выделены две с наибольшими результатами. RandomForestClassifier и CatBoostClassifier . Так как разница между ними не велика и скорость обучения модели CatBoost выше, то данная модель выбрана как наиболее предпочтительная.
6. Прогнозирование оттока клиентов банка
Задача: По историческим данным поведения клиентов и расторжении договоров спрогнозировать возможный уход клиента.
Использованные библиотеки: Pandas, NumPy, Scikit-learn, Matplotlib, Catboost, различные модели классификации, подбор параметров, балансировка классов.
Вывод: По результатам тестирования модели выделены две с наибольшими результатами. Это случайны лес RandomForestClassifier с уменьшением в выборке доли отрицательных результатов и CatBoost CatBoostClassifier . Обе модели показали значение F1-меры выше требуемого значения.
7. Определение наиболее перспективного региона
Задача: По характеристикам нефтяных скважин в различных регионах определить регион с наибольшей прибылью.
Использованные библиотеки: Pandas, NumPy, Scikit-learn, Matplotlib, Catboost, Seaborn, различные модели классификации, подбор параметров, bootstrap.
Вывод: Найдено распределение прибыли для каждого региона, риск убытков и средняя прибыль. По этим характеристикам выбран регион для разработки скважин.
Как проверить модель на вменяемость sklearn
Метрики, используемые в задачах классификации и регрессии, различаются. В задаче классификации используются такие метрики, как точность, точность, отзыв . В задаче регрессии используются такие метрики, как средняя абсолютная ошибка, оценка R2 .
Поскольку это проблема классификации, я буду использоватьоценка точностиВот.
Получите быструю начальную оценку метрик.
Основная идея этого шага — получить базовую оценку показателей, которая оптимизируется. Эта базовая линия будет работать как ссылка на дальнейших этапах проверки модели. Есть несколько способов получить базовую оценку для задачи классификации. Я использую класс большинства для прогнозирования. Базовый показатель точности составляет примерно77%,
Разработка функций для оптимизации метрик.
Проектирование функций — это процесс использования знаний о предметной области для создания функций, обеспечивающих работу алгоритмов машинного обучения. Проектирование функций является основополагающим для применения машинного обучения, и сложным, и дорогостоящим.
От Википедия
Это означает выявление взаимосвязей между независимыми и зависимыми функциями. Это с помощью графиков, таких как парные графики или корреляционная матрица. Затем идентифицированные отношения мы можем добавить в качестве полинома или функции взаимодействия.
Этап разработки функций является точкой входа для последовательных итераций. Это критический шаг и играет большую роль в прогнозах по сравнению с проверкой модели.
В качестве быстрого решения мы можем добавить некоторые полиномиальные функции, используя Полиномиальные особенности в научном наборе,
Знание предметной области по рассматриваемой проблеме будет очень полезно для разработки функций. Это большая тема сама по себе и требует значительных затрат времени и ресурсов.
Предварительная обработка данных.
Предварительная обработка данных преобразует характеристики в формат, который больше подходит для оценщиков. В целом, модели машинного обучения предпочитают стандартизацию набора данных. Я буду использоватьRobustScalerдля нашего примера.
Обратитесь к Sci-Kit узнать Предварительная обработка данных раздел для подробной информации.
Выбор функций.
Выбор характеристик или уменьшение размерности в наборах данных помогает
- Либо улучшить показатели точности моделей
- Повысить их производительность на очень многомерных наборах данных.
я используюSelectKBest, одномерный метод выбора объекта. Функция оценки, используемая для задач классификации и регрессии, будет различной.
Обратитесь к Sci-Kit узнать Выбор функции раздел для подробной информации
Выбор модели.
Так как мы работаем с проблемой классификации, я буду использоватьЛогистическая регрессиямодель. Для проблем регрессии мы можем использоватьЛинейная регрессияилигрядамоделей. Выбор модели зависит от поставленной задачи. Исходя из сложности данных, мы можем использовать либо простую линейную модель, либо расширенные модели.
Обратитесь к Sci-Kit узнать Обобщенные линейные модели раздел для подробной информации.
Существует элегантный способ объединить вышеупомянутые три шага, используя Sci-Kit Learn. Трубопровод,Трубопроводприменяет список преобразований перед окончательной моделью.
Проверка модели.
Гиперпараметры — это параметры, которые не изучаются в самой модели. Гиперпараметры передаются в качестве аргументов в конструктор шагов в конвейере. На основе оценки перекрестной проверки можно выбрать наилучшие возможные параметры.
Для настройки гиперпараметровGridSearchCVэто один из вариантов. Он выполняет исчерпывающий поиск по указанным значениям параметров для модели. Здесь мы передаем гиперпараметры шагам в конвейере, используяparam_grid,резюмеустановлен в5так как мы должны выполнить 5-кратную перекрестную проверку.счетустановлен вточностьтак как мы хотим предсказать точность модели.
Обратитесь к Sci-Kit узнать Настройка гиперпараметров оценки раздел для подробной информации.
Интерпретировать результаты.
GridSearchCV возвращает немного важной информации, такой как:
- best_estimator_Оценщик, который дал наивысший балл. Используя это, мы можем получить информацию о выбранных функциях.
- лучший результат_,Средний перекрестный результат оценки best_estimator. Для нашего набора задач мы получили лучший результат78%для нашей самой первой итерации. Это кажется немного, но мы уже побили наш базовый показатель точности.
- best_params_, настройка параметров, которая дала наилучшие результаты на данных удержания. Для гиперпараметров, которые передаются в модель, приведенные ниже настройки дают наилучшие результаты.
- ‘Logisticregression__C’: 1.0
- ‘Logisticregression__class_weight’: нет
- ‘Selectkbest__k’: 4
На этом заканчивается первая итерация проверки модели. Теперь мы можем вернуться и повторить процесс, начиная с этапа разработки функций. В конце каждой итерации мы можем проверить изменение показателя точности. Повторите процедуру до достижения желаемой оценки точности или выбранных показателей.
Получите лучшую модель и сравните ее с набором тестовых данных.
После выбора окончательной модели проверьте ее работоспособность, используя набор тестовых данных. Здесь мы получаем оценку точности75%на тестовом наборе данных.
Обратите внимание, что этот блог предназначен для быстрого ознакомления с проверкой правильности модели машинного обучения. Идея здесь состоит в том, чтобы не получить лучший показатель метрик в самой первой итерации. Используйте этот подход, чтобы установить базовый показатель метрик. Улучшите нашу оценку валидации модели на каждой итерации.
Получить полный блокнот Вот,
Вы можете найти мои другие блоги интересными. Проверьте их.
Обзор методов классификации в машинном обучении с помощью Scikit-Learn
Для машинного обучения на Python написано очень много библиотек. Сегодня мы рассмотрим одну из самых популярных — Scikit-Learn.
Scikit-Learn упрощает процесс создания классификатора и помогает более чётко выделить концепции машинного обучения, реализуя их с помощью понятной, хорошо документированной и надёжной библиотекой.
Что такое Scikit-Learn?
Scikit-Learn — это Python-библиотека, впервые разработанная David Cournapeau в 2007 году. В этой библиотеке находится большое количество алгоритмов для задач, связанных с классификацией и машинным обучением в целом.
Scikit-Learn базируется на библиотеке SciPy, которую нужно установить перед началом работы.
Основные термины
В системах машинного обучения или же системах нейросетей существуют входы и выходы. То, что подаётся на входы, принято называть признаками (англ. features).
Признаки по существу являются тем же, что и переменные в научном эксперименте — они характеризуют какой-либо наблюдаемый феномен и их можно как-то количественно измерить.
Когда признаки подаются на входы системы машинного обучения, эта система пытается найти совпадения, заметить закономерность между признаками. На выходе генерируется результат этой работы.
Этот результат принято называть меткой (англ. label), поскольку у выходов есть некая пометка, выданная им системой, т. е. предположение (прогноз) о том, в какую категорию попадает выход после классификации.
В контексте машинного обучения классификация относится к обучению с учителем. Такой тип обучения подразумевает, что данные, подаваемые на входы системы, уже помечены, а важная часть признаков уже разделена на отдельные категории или классы. Поэтому сеть уже знает, какая часть входов важна, а какую часть можно самостоятельно проверить. Пример классификации — сортировка различных растений на группы, например «папоротники» и «покрытосеменные». Подобная задача может быть выполнена с помощью Дерева Решений — одного из типов классификатора в Scikit-Learn.
При обучении без учителя в систему подаются непомеченные данные, и она должна попытаться сама разделить эти данные на категории. Так как классификация относится к типу обучения с учителем, способ обучения без учителя в этой статье рассматриваться не будет.
Процесс обучения модели — это подача данных для нейросети, которая в результате должна вывести определённые шаблоны для данных. В процессе обучения модели с учителем на вход подаются признаки и метки, а при прогнозировании на вход классификатора подаются только признаки.
Принимаемые сетью данные делятся на две группы: набор данных для обучения и набор для тестирования. Не стоит проверять сеть на том же наборе данных, на которых она обучалась, т. к. модель уже будет «заточена» под этот набор.
Типы классификаторов
Scikit-Learn даёт доступ ко множеству различных алгоритмов классификации. Вот основные из них:
- Метод k-ближайших соседей (K-Nearest Neighbors);
- Метод опорных векторов (Support Vector Machines);
- Классификатор дерева решений (Decision Tree Classifier) / Случайный лес (Random Forests);
- Наивный байесовский метод (Naive Bayes);
- Линейный дискриминантный анализ (Linear Discriminant Analysis);
- Логистическая регрессия (Logistic Regression);
На сайте Scikit-Learn есть много литературы на тему этих алгоритмов с кратким пояснением работы каждого из них.
Обзор самых популярных алгоритмов машинного обучения
Метод k-ближайших соседей (K-Nearest Neighbors)
Этот метод работает с помощью поиска кратчайшей дистанции между тестируемым объектом и ближайшими к нему классифицированным объектами из обучающего набора. Классифицируемый объект будет относится к тому классу, к которому принадлежит ближайший объект набора.
Классификатор дерева решений (Decision Tree Classifier)
Этот классификатор разбивает данные на всё меньшие и меньшие подмножества на основе разных критериев, т. е. у каждого подмножества своя сортирующая категория. С каждым разделением количество объектов определённого критерия уменьшается.
Классификация подойдёт к концу, когда сеть дойдёт до подмножества только с одним объектом. Если объединить несколько подобных деревьев решений, то получится так называемый Случайный Лес (англ. Random Forest).
Наивный байесовский классификатор (Naive Bayes)
Такой классификатор вычисляет вероятность принадлежности объекта к какому-то классу. Эта вероятность вычисляется из шанса, что какое-то событие произойдёт, с опорой на уже на произошедшие события.
Каждый параметр классифицируемого объекта считается независимым от других параметров.
Линейный дискриминантный анализ (Linear Discriminant Analysis)
Этот метод работает путём уменьшения размерности набора данных, проецируя все точки данных на линию. Потом он комбинирует эти точки в классы, базируясь на их расстоянии от центральной точки.
Этот метод, как можно уже догадаться, относится к линейным алгоритмам классификации, т. е. он хорошо подходит для данных с линейной зависимостью.
Метод опорных векторов (Support Vector Machines)
Работа метода опорных векторов заключается в рисовании линии между разными кластерами точек, которые нужно сгруппировать в классы. С одной стороны линии будут точки, принадлежащие одному классу, с другой стороны — к другому классу.
Классификатор будет пытаться увеличить расстояние между рисуемыми линиями и точками на разных сторонах, чтобы увеличить свою «уверенность» определения класса. Когда все точки построены, сторона, на которую они падают — это класс, которому эти точки принадлежат.
Логистическая регрессия (Logistic Regression)
Логистическая регрессия выводит прогнозы о точках в бинарном масштабе — нулевом или единичном. Если значение чего-либо равно либо больше 0.5 , то объект классифицируется в большую сторону (к единице). Если значение меньше 0.5 — в меньшую (к нулю).
У каждого признака есть своя метка, равная только 0 или только 1. Логистическая регрессия является линейным классификатором и поэтому используется, когда в данных прослеживается какая-то линейная зависимость.
Примеры задач классификации
Задача классификации — эта любая задача, где нужно определить тип объекта из двух и более существующих классов. Такие задачи могут быть разными: определение, кошка на изображении или собака, или определение качества вина на основе его кислотности и содержания алкоголя.
В зависимости от задачи классификации вы будете использовать разные типы классификаторов. Например, если классификация содержит какую-то бинарную логику, то к ней лучше всего подойдёт логистическая регрессия.
По мере накопления опыта вам будет проще выбирать подходящий тип классификатора. Однако хорошей практикой является реализация нескольких подходящих классификаторов и выбор наиболее оптимального и производительного.
Реализация классификатора
Первый шаг в реализации классификатора — его импорт в Python. Вот как это выглядит для логистической регрессии:
from sklearn.linear_model import LogisticRegression
Вот импорты остальных классификаторов, рассмотренных выше:
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis from sklearn.neighbors import KNeighborsClassifier from sklearn.naive_bayes import GaussianNB from sklearn.tree import DecisionTreeClassifier from sklearn.svm import SVC
Однако, это не все классификаторы, которые есть в Scikit-Learn. Про остальные можно прочитать на соответствующей странице в документации.
После этого нужно создать экземпляр классификатора. Сделать это можно создав переменную и вызвав функцию, связанную с классификатором.
logreg_clf = LogisticRegression()
Теперь классификатор нужно обучить. Перед этим нужно «подогнать» его под тренировочные данные.
Обучающие признаки и метки помещаются в классификатор через функцию fit :
logreg_clf.fit(features, labels)
После обучения модели данные уже можно подавать в классификатор. Это можно сделать через функцию классификатора predict , передав ей параметр (признак) для прогнозирования:
logreg_clf.predict(test_features)
Эти этапы (создание экземпляра, обучение и классификация) являются основными при работе с классификаторами в Scikit-Learn. Но эта библиотека может управлять не только классификаторами, но и самими данными. Чтобы разобраться в том, как данные и классификатор работают вместе над задачей классификации, нужно разобраться в процессах машинного обучения в целом.
Процесс машинного обучения
Процесс содержит в себе следующие этапы: подготовка данных, создание обучающих наборов, создание классификатора, обучение классификатора, составление прогнозов, оценка производительности классификатора и настройка параметров.
Во-первых, нужно подготовить набор данных для классификатора — преобразовать данные в корректную для классификации форму и обработать любые аномалии в этих данных. Отсутствие значений в данных либо любые другие отклонения — все их нужно обработать, иначе они могут негативно влиять на производительность классификатора. Этот этап называется предварительной обработкой данных (англ. data preprocessing).
Следующим шагом будет разделение данных на обучающие и тестовые наборы. Для этого в Scikit-Learn существует отличная функция traintestsplit.
Как уже было сказано выше, классификатор должен быть создан и обучен на тренировочном наборе данных. После этих шагов модель уже может делать прогнозы. Сравнивая показания классификатора с фактически известными данными, можно делать вывод о точности классификатора.
Вероятнее всего, вам нужно будет «корректировать» параметры классификатора, пока вы не достигните желаемой точности (т. к. маловероятно, что классификатор будет соответствовать всем вашим требованиям с первого же запуска).
Ниже будет представлен пример работы машинного обучения от обработки данных и до оценки.
Реализация образца классификации
# Импорт всех нужных библиотек import pandas as pd from sklearn.metrics import classification_report from sklearn.metrics import confusion_matrix from sklearn.metrics import accuracy_score from sklearn.neighbors import KNeighborsClassifier from sklearn.svm import SVC
Поскольку набор данных iris достаточно распространён, в Scikit-Learn он уже присутствует, достаточно лишь заложить эту команду:
sklearn.datasets.load_iris
Тем не менее, тут ещё нужно подгрузить CSV-файл, который можно скачать здесь.
Этот файл нужно поместить в ту же папку, что и Python-файл. В библиотеке Pandas есть функция read_csv() , которая отлично работает с загрузкой данных.
data = pd.read_csv('iris.csv') # Проверяем, всё ли правильно загрузилось print(data.head(5))
Благодаря тому, что данные уже были подготовлены, долгой предварительной обработки они не требуют. Единственное, что может понадобиться — убрать ненужные столбцы (например ID ) таким образом:
data.drop('Id', axis=1, inplace=True)
Теперь нужно определить признаки и метки. С библиотекой Pandas можно легко «нарезать» таблицу и выбрать определённые строки/столбцы с помощью функции iloc() :
# ".iloc" принимает row_indexer, column_indexer X = data.iloc[. -1].values # Теперь выделим нужный столбец y = data['Species']
Код выше выбирает каждую строку и столбец, обрезав при этом последний столбец.
Выбрать признаки интересующего вас набора данных можно также передав в скобках заголовки столбцов:
# Альтернативный способ выбора нужных столбцов: X = data.iloc['SepalLengthCm', 'SepalWidthCm', 'PetalLengthCm']
После того, как вы выбрали нужные признаки и метки, их можно разделить на тренировочные и тестовые наборы, используя функцию train_test_split() :
# test_size показывает, какой объем данных нужно выделить для тестового набора # Random_state — просто сид для случайной генерации # Этот параметр можно использовать для воссоздания определённого результата: X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=27)
Чтобы убедиться в правильности обработки данных, используйте:
print(X_train) print(y_train)
Теперь можно создавать экземпляр классификатора, например метод опорных векторов и метод k-ближайших соседей:
SVC_model = svm.SVC() # В KNN-модели нужно указать параметр n_neighbors # Это число точек, на которое будет смотреть # классификатор, чтобы определить, к какому классу принадлежит новая точка KNN_model = KNeighborsClassifier(n_neighbors=5)
Теперь нужно обучить эти два классификатора:
SVC_model.fit(X_train, y_train) KNN_model.fit(X_train, y_train)
Эти команды обучили модели и теперь классификаторы могут делать прогнозы и сохранять результат в какую-либо переменную.
SVC_prediction = SVC_model.predict(X_test) KNN_prediction = KNN_model.predict(X_test)
Теперь пришло время оценить точности классификатора. Существует несколько способов это сделать.
Нужно передать показания прогноза относительно фактически верных меток, значения которых были сохранены ранее.
# Оценка точности — простейший вариант оценки работы классификатора print(accuracy_score(SVC_prediction, y_test)) print(accuracy_score(KNN_prediction, y_test)) # Но матрица неточности и отчёт о классификации дадут больше информации о производительности print(confusion_matrix(SVC_prediction, y_test)) print(classification_report(KNN_prediction, y_test))
Вот, к примеру, результат полученных метрик:
SVC accuracy: 0.9333333333333333 KNN accuracy: 0.9666666666666667
Поначалу кажется, что KNN работает точнее. Вот матрица неточностей для SVC:
[[ 7 0 0] [ 0 10 1] [ 0 1 11]]
Количество правильных прогнозов идёт с верхнего левого угла в нижний правый. Вот для сравнения метрики классификации для KNN:
precision recall f1-score support Iris-setosa 1.00 1.00 1.00 7 Iris-versicolor 0.91 0.91 0.91 11 Iris-virginica 0.92 0.92 0.92 12 micro avg 0.93 0.93 0.93 30 macro avg 0.94 0.94 0.94 30 weighted avg 0.93 0.93 0.93 30
Оценка классификатора
Когда дело доходит до оценки точности классификатора, есть несколько вариантов.
Точность классификации
Точность классификации измерять проще всего, и поэтому этот параметр чаще всего используется. Значение точности — это число правильных прогнозов, делённое на число всех прогнозов или, проще говоря, отношение правильных прогнозов ко всем.
Хоть этот показатель и может быстро дать вам явное представление о производительности классификатора, его лучше использовать, когда каждый класс имеет хотя бы примерно одинаковое количество примеров. Так как такое будет случаться редко, рекомендуется использовать другие показатели классификации.
Логарифмические потери
Значение Логарифмических Потерь (англ. Logarithmic Loss) — или просто логлосс — показывает, насколько классификатор «уверен» в своём прогнозе. Логлосс возвращает вероятность принадлежности объекта к тому или иному классу, суммируя их, чтобы дать общее представление об «уверенности» классификатора.
Этот показатель лежит в промежутке от 0 до 1 — «совсем не уверен» и «полностью уверен» соответственно. Логлосс сильно падает, когда классификатор сильно «уверен» в неправильном ответе.
Площадь ROC-кривой (AUC)
Такой показатель используется только при бинарной классификации. Площадь под ROC-кривой представляет способность классификатора различать подходящие и не подходящие какому-либо классу объекты.
Значение 1.0 : вся область, попадающая под кривую, представляет собой идеальный классификатор. Следовательно, 0.5 означает, что точность классификатора соответствует случайности. Кривая рассчитывается с учётом точности и специфичности модели. Подробнее о расчётах можно прочитать здесь.
Матрица неточностей
Матрица неточностей (англ. Confusion Matrix) — это таблица или диаграмма, показывающая точность прогнозирования классификатора в отношении двух и более классов. Прогнозы классификатора находятся на оси X, а результат (точность) — на оси Y.
Ячейки таблицы заполняются количеством прогнозов классификатора. Правильные прогнозы идут по диагонали от верхнего левого угла в нижний правый. Про это можно почитать в данной статье.
Отчёт о классификации
В библиотеке Scikit-Learn уже встроена возможность создавать отчёты о производительности классификатора. Эти отчёты дают интуитивно понятное представление о работе модели.
Заключение
Чтобы лучше вникнуть в работу с Scikit-Learn, неплохо было бы узнать больше о работе различных методов классификации. После этого стоит лучше узнать о замере производительности классификаторов. Однако понимание многих нюансов в классификации приходит только со временем.