Практические вопросы машинного обучения. Часть 2

Sci-Kit Learn

Здравствуйте и вновь добро пожаловать на занятия по теме «Обработка данных: машинное обучение с учителем на языке Python».

В продолжение предыдущей статьи мы обсудим популярную библиотеку машинного обучения для языке Python, которая называется Sci-Kit Learn. Она содержит все обсуждавшиеся в этом курсе модели и многие другие.

Вы могли заметить, что каждая из моделей в этом курсе создавалась одним и тем же способом: мы определяли класс с тремя соответствующими методами: fit, predict и score. Конечно же, это делалось целенаправленно, поскольку Sci-Kit Learn имеет в точности такой же API. Поэтому пользоваться Sci-Kit Learn очень просто – это как использовать уже написанные нами модели, разве что кто-то другой написал их для нас и оптимизировал для повышения производительности. Это чудесный замысел, поскольку в дальнейших курсах мы будем обсуждать даже более сложные модели и, конечно же, все они уже описаны в Sci-Kit Learn, так что вы автоматически можете ими пользоваться, даже не нуждаясь в понимании, как они работают.

Можетвозникнуть вопрос: а чего же мы не использовали Sci-Kit Learnс самого начала? Надеюсь, ответ очевиден: машинное обучение – это не о том, какпользоваться конкретным API. Чтобынаучиться пользоваться API Sci-Kit Learn, необходимо от 5 до 15 минут, и любой, кто умеетписать программы, может прочитать документацию и научиться API чего угодно. Но если вы хотите стать хорошимспециалистом в машинном обучении, то это подразумевает понимание деталей напродвинутом уровне, когда вы можете реализовать код самостоятельно. Это необязательно означает, что код должен быть эффективным или оптимизированным, ноон должен корректно реализовывать алгоритм. А кроме того, это помогает понятьвсе плюсы и минусы каждого алгоритма, когда вы будете выбирать, какой из нихиспользовать.

Итак,пройдёмся по некоторым дополнительным приятным особенностям Sci-Kit Learn. Большим преимуществом при использованииклассификатора вроде логистической регрессии, нейронной сети или байесовскогоклассификатора является то, что они дают вероятностную меру нашего исходящегопрогноза. К примеру, если мы получим P(C|X) = 0,55, тобудем не столь уверенны в ответы, чем если бы получили P(C|X) = 0,99. В Sci-Kit Learnдаже такие классификаторы, как деревья решений и метод k-ближайшихсоседей получают апостериорную вероятность. Если такая возможность имеется, онавызывается функцией predict_proba. Это может оказаться полезным в случаях, когда насбольше интересует апостериорная вероятность, а не просто округлённый результатпрогноза.

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

Другимпримером может служить нахождение площади под кривой, или AUC-оценки, – площади под кривой ROC, где ROC означает кривуюрабочей характеристики приёмника. Вероятно, вам это ни о чём говорит, если вы сэтим ранее не сталкивались. Это график, где по оси y откладывается коэффициент истинной положительности,а по оси x– коэффициент ложной положительности. Коэффициент истинной положительности определяетсякак количество истинных положительных результатов, делённое на сумму истинныхположительных и ложных отрицательных результатов:

Коэффициентложной положительности определяется как количество ложных положительныхрезультатов, делённое на сумму ложно положительных и истинно отрицательныхрезультатов:

Коэффициентложной положительности определяется как количество ложных положительныхрезультатов, делённое на сумму ложно положительных и истинно отрицательныхрезультатов:

Случайноеугадывание даёт AUC, равное 0,5, акривая ROC будет прямой из нижнего левого угла в правыйверхний. Идеальный классификатор даёт AUC, равное 1,кривая ROC будет идти из левого нижнего угла в левый правый, аоттуда – до верхнего правого угла, охватывая весь график, так что площадь будетравна единице. В реальных же задачах AUC, вероятнеевсего, будет иметь значение между 0,5 и 1. В этом случае мы рассматриваемисходящую вероятность как оценку между 0 и 1 и используем для определенияпорогового значения с целью решения, каким должен быть прогнозируемый класс.Обычно предполагается, это должно быть 0,5, но это не обязательно. Можно,например, дать прогноз 1, если исходящая вероятность больше 0,3, и 0 впротивном случае.

Такимобразом, кривая ROC на самом делепредставляет собой график истинной и ложной положительности для различныхзначений этого порога принятия решения, лежащего между 0 и 1. На всякий случай:порог может быть только один, поскольку это двоичная классификация.

Зачеммогут понадобиться различные пороговые значения? Возможно, существуют случаи,когда нас не волнует большинство ложных положительных результатов и мы хотимпрогнозировать положительный класс более часто. Примером такого случая можетбыть начальный тест на заболевание: мы не хотим рисковать, получив ложныйотрицательный результат и в результате не оказав помощи заболевшему. Тогдалучше снизить порог и чаще прогнозировать положительный класс, даже если можемошибиться.

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

Ещёодним примером того, когда мы можем хотеть использовать AUC для определения, насколько хороша наша модель, –это когда в наличии дисбаланс классов. Для примера, пусть у нас есть только 10примеров класса 0 и 990 примеров класса 1. Если просто каждый разпрогнозировать класс 1, то коэффициент классификации достигает 99% безкакого-либо машинного обучения. AUC, однако, будетдавать более реалистичное число.

Ксчастью, в Sci-Kit Learn уже имеется функция для вычисления AUC. Она находится в sklearn.metrics и называется roc_auc_score. Обратитевнимание, что в то время как первый её параметр принимает истинные метки,которые могут быть либо 0, либо 1, второй параметр принимает оценку исходящихвероятностей.

Ранеев курсе упоминалось, что существует две категории машинного обучения с учителем:классификация и регрессия. Этот курс сфокусирован на классификации. Но многиемодели Sci-Kit Learn способны проводить и классификацию, и регрессию. Кпримеру, существует KNeighboursRegressor, представляющийсобой метод k-ближайших соседей для задач регрессии, и DecisionTreeRegressor, являющийся деревом решений длярегрессии. Заметьте, эти регрессоры имеют всё те же базовые функции API – fit, predict и score,причём score возвращает коэффициент классификации в случаезадачи классификации и коэффициент детерминации в случае регрессии. Коэффициентдетерминации обсуждается в предпосылках к данному курсу – «Линейной регрессиина языке Python».

Ипоследнее интересное свойство Sci-Kit Learn,о котором мы поговорим, – это возможность сохранять и загружать модели. Кпримеру, предположим, мы хотим обучить модель оффлайн, а затем развернуть её нанескольких серверах в кластере. Нет никакой необходимости обучать каждую модельпо отдельности и дублировать работу. Другой пример – сервер может выйти изстроя, но ведь не хочется же обучать модель заново. Sci-Kit Learnдаёт возможность сохранять и загружать все эти модели, так что можно их однаждыобучить и использовать их вновь позже.

Делаетсяэто с помощью библиотеки Pickle. Если вызнакомы с JSON, то функции вызываются очень похоже. Технически JSON также сохраняет загружаемые им объекты, разве чтосохраняются они в строчном формате, а не двоичном. Вот пример кода для этого.Мы импортируем Pickle, создаёммодель, используем её применительно к данным, затем сохраняем её в файле mymodel.pkl,а позже загружаем её из того же файла:

import pickle

model = DecisionTreeClassifier()

model.fit(X, Y)

with open (‘’mymodel.pkl’’, ‘’wb’’) as f:

   pickle.dump(model, f)

# …позже…

with open (‘’mymodel.pkl’’’) as f:

    model = pickle.load(f)

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

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

Регрессия со Sci-Kit Learn – это легко

В заключение мы увидим, как можно выполнять задачу регрессии с помощью Sci-Kit Learn.

Напомню, что регрессия – это прогнозирование реально значащего числа, а не категории. Как только начать применять Sci-Kit Learn, использование любой модели становится настолько простым, что даже не требуется теоретических лекций, чтобы объяснить, что происходит, – можно переходить прямо к написанию кода. В данном случае мы рассмотрим регрессию с помощью метода k-ближайших соседей и деревьев решений. Цель всего этого состоит в том, чтобы увидеть, сможете ли вы распознать характеристики этих алгоритмов при их решении задачи регрессии. Соответствующий файл для данной лекции называется regression.py.

Итак, импортируем Numpy, Matplotlib, чтобы отобразить наши данные, а также Sklearn.neighbors, где находится KneighborsRegressor, и Sklearn.tree, где находится DecisionTreeRegressor.

import numpy as np

import matplotlib.pyplot as plt

from sklearn.neighbors import KNeighborsRegressor

from sklearn.tree import DecisionTreeRegressor

Создадимнаши данные. У нас будет 200 точек. Используем linspace, чтобы разместить наши N точек между 0 и 10; при этом прийдётсяпреобразовать данные, поскольку Sci-Kit Learn ожидает матрицу NxD, даже если D= 1. Иначе Sci-Kit Learn не будет работать. Учебными у нас будут 20 точек – 10%от общего числа. В качестве Y у нас будет синусоида.

N = 200

X = np.linspace(0, 10, N).reshape(N,1)

Y = np.sin(X)

Ntrain = 20

idx = np.random.choice(N, Ntrain)

Xtrain = X[idx]

Ytrain = Y[idx]

Далеесоздаём наши модели. Чтобы узнать больше о параметрах, можете обратиться ксоответствующей документации. Так, n_neighbors указывает количество ближайших соседей,мы установим это значение, равным 2.

knn = KNeighborsRegressor(n_neighbors=2)

knn.fit(Xtrain, Ytrain)

Yknn = knn.predict(X)

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

dt = DecisionTreeRegressor()

dt.fit(Xtrain, Ytrain)

Ydt = dt.predict(X)

Теперьнарисуем наши графики.

plt.scatter(Xtrain, Ytrain)

plt.plot(X, Y)

plt.plot(X, Yknn, label=’KNN’)

plt.plot(X, Ydt, label=’DecisionTree’)

plt.legend()

plt.show()

Запустими посмотрим, что получится.

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

Ачто с методом k-ближайших соседей? Напомню, мы установиликоличество соседей, равное 2. Если присмотреться, станет ясно что данный методпросто берёт двух ближайших соседей и выдаёт в качестве прогноза среднее междуними, так что по сути получается блочная структура, прямо как у дерева решений.Можно представить, что простейшее видоизменение вроде взвешивания среднейдистанции между этими двумя точками, вероятно, улучшит результат. Давайтепопробуем и посмотрим, что получится.

Введемпараметр weights.

knn = KNeighborsRegressor(n_neighbors=2, weights=’distance’)

Запустимещё раз.

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

Андрей Никитенко
Андрей Никитенко
Задать вопрос эксперту
Понравилась статья? Поделить с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: