[Из песочницы] Машинное обучение — это легко

В данной статье речь пойдёт о машинном обучении в целом и взаимодействии с датасетами. Если вы начинающий, не знаете с чего начать изучение и вам интересно узнать, что такое «датасет», а также зачем вообще нужен Machine Learning и почему в последнее время он набирает все большую популярность, прошу под кат. Мы будем использовать Python 3, так это как достаточно простой инструмент для изучения машинного обучения.

Для кого эта статья?


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

image

В цифрах


С каждым годом растёт потребность в изучении больших данных как для компаний, так и для активных энтузиастов. В таких крупных компаниях, как Яндекс или Google, всё чаще используются такие инструменты для изучения данных, как язык программирования R, или библиотеки для Python (в этой статье я привожу примеры, написанные под Python 3). Согласно Закону Мура (а на картинке — и он сам), количество транзисторов на интегральной схеме удваивается каждые 24 месяца. Это значит, что с каждым годом производительность наших компьютеров растёт, а значит и ранее недоступные границы познания снова «смещаются вправо» — открывается простор для изучения больших данных, с чем и связано в первую очередь создание «науки о больших данных», изучение которого в основном стало возможным благодаря применению ранее описанных алгоритмов машинного обучения, проверить которые стало возможным лишь спустя полвека. Кто знает, может быть уже через несколько лет мы сможем в абсолютной точности описывать различные формы движения жидкости, например.

Анализ данных — это просто?


Да. А так же интересно. Наряду с особенной важностью для всего человечества изучать большие данные стоит относительная простота в самостоятельном их изучении и применении полученного «ответа» (от энтузиаста к энтузиастам). Для решения задачи классификации сегодня имеется огромное количество ресурсов; опуская большинство из них, можно воспользоваться средствами библиотеки Scikit-learn (SKlearn). Создаём свою первую обучаемую машину:
clf = RandomForestClassifier()
clf.fit(X, y)

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

 — Если все так просто, почему до сих пор не каждый предсказывает, например, цены на валюту?

С этими словами можно было бы закончить статью, однако делать я этого, конечно же, не буду (буду конечно, но позже) существуют определенные нюансы выполнения корректности прогнозов для поставленных задач. Далеко не каждая задача решается вот так легко (о чем подробнее можно прочитать здесь)

Ближе к делу


 — Получается, зарабатывать на этом деле я не сразу смогу?

Да, до решения задач за призы в $100 000 нам ещё далеко, но ведь все начинали с чего-то простого.

Итак, сегодня нам потребуются:

  • Python 3 (с установленной pip3)
  • Jupyter
  • SKlearn, NumPy и matplotlib

Если чего-то нет: ставим всё за 5 минут
Для начала, скачиваем и устанавливаем Python 3 (при установке не забудьте поставить pip и добавить в PATH, если скачали установщик Windows). Затем, для удобства был взят и использован пакет Anaconda, включающий в себя более 150 библиотек для Python (ссылка на скачивание). Он удобен для использования Jupyter, библиотек numpy, scikit-learn, matplotlib, а так же упрощает установку всех. После установки, запускаем Jupyter Notebook через панель управления Anaconda, или через командную строку (терминал): «jupyter notebook».

Дальнейшее использование требует от читателя некоторых знаний о синтаксисе Python и его возможностях (в конце статьи будут представлены ссылки на полезные ресурсы, среди них и «основы Python 3»).
Как обычно, импортируем необходимые для работы библиотеки:
import numpy as np
from pandas import read_csv as read

 — Ладно, с Numpy всё понятно. Но зачем нам Pandas, да и еще read_csv?

Иногда бывает удобно «визуализировать» имеющиеся данные, тогда с ними становится проще работать. Тем более, большинство датасетов с популярного сервиса Kaggle собрано пользователями в формате CSV.

А вот так выглядит визуализированный pandas’ом датасет
image
Здесь колонка Activity показывает, идёт реакция или нет (1 при положительном, 0 при отрицательном ответе). А остальные колонки — множества признаков и соответствующие им значения (различные процентные содержания веществ в реакции, их агрегатные состояния и пр.)

 — Помнится, ты использовал слово «датасет». Так что же это такое?

Датасет — выборка данных, обычно в формате «множество из множеств признаков» → «некоторые значения»(которыми могут быть, например, цены на жильё, или порядковый номер множества некоторых классов), где X — множество признаков, а y — те самые некоторые значения. Определять, например, правильные индексы для множества классов — задача классификации, а искать целевые значения (такие как цена, или расстояния до объектов) — задача ранжирования. Подробнее о видах машинного обучения можно прочесть в статьях и публикациях, ссылки на которые, как и обещал, будут в конце статьи.

Знакомимся с данными


Предложенный датасет можно скачать здесь. Ссылка на исходные данные и описание признаков будет в конце статьи. По представленным параметрам нам предлагается определять, к какому сорту относится то или иное вино. Теперь мы можем разобраться, что же там происходит:
path = "%путь к файлу%/wine.csv"
data = read(path, delimiter=",")
data.head()

Работая в Jupyter notebook, получаем такой ответ:
image

Это значит, что теперь нам доступны данные для анализа. В первом столбце значения Grade показывают, к какому сорту относится вино, а остальные столбцы — признаки, по которым их можно различать. Попробуйте ввести вместо data.head () просто data — теперь для просмотра вам доступна не только «верхняя часть» датасета.

Простая реализация задачи на классификацию


Переходим к основной части статьи — решаем задачу классификации. Всё по порядку:
  • создаём обучающую выборку
  • пробуем обучить машину на случайно подобранных параметрах и классах им соответствующих
  • подсчитываем качество реализованной машины

Посмотрим на реализацию (каждая выдержка из кода — отдельный Cell в notebook):

X = data.values[::, 1:14]
y = data.values[::, 0:1]

from sklearn.cross_validation import train_test_split as train
X_train, X_test, y_train, y_test = train(X, y, test_size=0.6)

from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(n_estimators=100, n_jobs=-1)
clf.fit(X_train, y_train)
clf.score(X_test, y_test)

Создаем массивы, где X — признаки (с 1 по 13 колонки), y — классы (0ая колонка). Затем, чтобы собрать тестовую и обучающую выборку из исходных данных, воспользуемся удобной функцией кросс-валидации train_test_split, реализованной в scikit-learn. С готовыми выборками работаем дальше — импортируем RandomForestClassifier из ensemble в sklearn. Этот класс содержит в себе все необходимые для обучения и тестирования машины методы и функции. Присваиваем переменной clf (classifier) класс RandomForestClassifier, затем вызовом функции fit () обучаем машину из класса clf, где X_train — признаки категорий y_train. Теперь можно использовать встроенную в класс метрику score, чтобы определить точность предсказанных для X_test категорий по истинным значениям этих категорий y_test. При использовании данной метрики выводится значение точности от 0 до 1, где 1 <=> 100% Готово!
Про RandomForestClassifier и метод кросс-валидации train_test_split
При инициализации clf для RandomForestClassifier мы выставляли значения n_estimators=100, n_jobs = -1, где первый отвечает за количество деревьев в лесу, а второй — за количество участвующих в работе ядер процессора (при -1 задействованы все ядра, по умолчанию стоит 1). Так как мы работаем с данным датасетом и нам негде взять тестирующую выборку, используем train_test_split для «умного» разбиения данных на обучающую выборку и тестирующую. Подробнее про них можно узнать, выделив интересующий Вас класс или метод и нажав Shift+Tab в среде Jupyter.

 — Неплохая точность. Всегда ли так получается?

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

 — Слишком легко. Больше мяса!

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

image

Да, с уменьшением количества признаков, падает и точность распознавания. И график получился не особенно-то красивым, но это и не решающее в простом анализе: вполне наглядно видно, как машина выделила обучающую выборку (точки) и сравнила её с предсказанными (заливка) значениями.
Реализация здесь
from sklearn.preprocessing import scale
X_train_draw = scale(X_train[::, 0:2])
X_test_draw = scale(X_test[::, 0:2])

clf = RandomForestClassifier(n_estimators=100, n_jobs=-1)
clf.fit(X_train_draw, y_train)

x_min, x_max = X_train_draw[:, 0].min() - 1, X_train_draw[:, 0].max() + 1
y_min, y_max = X_train_draw[:, 1].min() - 1, X_train_draw[:, 1].max() + 1

h = 0.02

xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
            np.arange(y_min, y_max, h))

pred = clf.predict(np.c_[xx.ravel(), yy.ravel()])
pred = pred.reshape(xx.shape)

import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap

cmap_light = ListedColormap(['#FFAAAA', '#AAFFAA', '#AAAAFF'])
cmap_bold = ListedColormap(['#FF0000', '#00FF00', '#0000FF'])

plt.figure()
plt.pcolormesh(xx, yy, pred, cmap=cmap_light)
plt.scatter(X_train_draw[:, 0], X_train_draw[:, 1], 
            c=y_train, cmap=cmap_bold)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())

plt.title("Score: %.0f percents" % (clf.score(X_test_draw, y_test) * 100))
plt.show()


Предлагаю читателю самостоятельно узнать почему и как он работает.

Последнее слово


Надеюсь, данная статья помогла хоть чуть-чуть освоиться Вам в разработке простого машинного обучения на Python. Этих знаний будет достаточно, чтобы продолжить интенсивный курс по дальнейшему изучению BigData+Machine Learning. Главное, переходить от простого к углубленному постепенно. А вот полезные ресурсы и статьи, как и обещал:

Материалы, вдохновившие автора на создание данной статьи


Исторические очерки:
  • Статья про то, зачем нужно машинное обучение сегодня, и что к этому привело
  • Как ни странно, довольно таки замысловатая статья с Википедии про машинное обучение в целом

Подробнее про машинное обучение:
  • Про машинное обучение и науку о данных
  • Еще одна интересная лекция от того же ведущего

Изучаем python, или до работы с данными:
  • Очень полезный курс от талантливых преподавателей из ИТМО и СПбАУ
  • Отличный русскоязычный ресурс для изучающих Python, но плохо ориентирующихся на англоязычных ресурсах

Однако для наилучшего освоения библиотеки sklearn пригодится знание английского: в этом источнике собраны все необходимые знания (так как это API reference)
Более углубленное изучение использования машинного обучения с Python стало возможным, и более простым благодаря преподавателям с Яндекса — этот курс обладает всеми необходимыми средствами объяснения, как же работает вся система, рассказывается подробнее о видах машинного обучения итд.
Файл сегодняшнего датасета был взят отсюда и несколько модифицирован.
Где брать данные, или «хранилище датасетов» — здесь собрано огромное количество данных от самых разных источников. Очень полезно тренироваться на реальных данных.

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

Комментарии (0)

© Habrahabr.ru