Содержание страницы
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-регрессоравыглядел более плавным.