Перевод статьи «Machine Learning For Complete Beginners»
Начало работы
Многие другие руководства по машинному обучению рассчитаны на то, что ученик уже является кандидатом наук в области математики или статистики. Настоящее руководство написано для тех, кто раннее не был знаком с машинным обучением.
Формат работы: вы начнёте с введения в машинное обучение на основе написания алгоритма, который будет предсказывать, сколько человек выживет при крушении «Титаника». Затем последуют две тренировочные сессии. Руководство будет направлять вас в дальнейшей работе, но код вы должны будете писать самостоятельно.
Требуемые знания: предполагается, что вы уже имеете опыт работы с Python или знаете его на уровне выше базового. Также предполагается, что вы знакомы с Pandas на базовом уровне. Если вы желаете подтянуть знания по Pandas, предлагаем ознакомиться со специальной статьёй. Также предлагаем вам посмотреть курс по основам Pandas.
Разработка будет выполняться с использованием Ipython (если вы раньше не работали с этой оболочкой, можете посмотреть вводный видеоурок и ознакомиться с командной оболочкой для интерактивных вычислений Jupyter Notebook в нашей статье). По определённым причинам рекомендуется использовать пакет Anaconda с Python 3.
Введение в машинное обучение
В презентации вам дано небольшое задание на проверку логики (чем чаще вы будете уделять время на подобные упражнения, тем лучше вы сможете организовать рабочий процесс). Следует открыть файл titanic_train.csv
и определить, какие поля, на ваш взгляд, имеют наибольшее значение для обучения. Вы можете сделать это сейчас, чтобы в середине статьи сравнить свой результат и результат автора.
Машинное обучение с Python
Исходный код, с которым вы будете работать, доступен на платформе Github. Для его загрузки регистрация не требуется. Titanic_Machine_Learning.ipynb — название файла, с которым вам предстоит работать.
Начнём с импорта основных библиотек: Pandas и Numpy.
import numpy as np
import pandas as pd
Для машинного обучения будет использоваться алгоритм Random Forest. На данный момент вам не нужно знать, как он работает (но в будущем обязательно изучите), но вам нужно знать, как его следует применять в деле.
#Алгоритм машинного обучения
from sklearn.ensemble import RandomForestClassifier
Если вы посмотрели презентацию (что действительно стоило сделать, иначе вы не сможете следовать половине кода), вы знаете, что нужно разделять данные для теста и для тренировки, чтобы не произошло переобучение. Поэтому нужно импортировать функцию train_test_split()
.
#Импорт функции
from sklearn.cross_validation import train_test_split
Теперь давайте отключим предупреждения от Pandas.
# Отключение предупреждений Pandas
pd.options.mode.chained_assignment = None
Пришло время импортировать функцию joblib
. Она будет использоваться для написания модели в файле для повторного использования.
#Используется для записи модели в файл
from sklearn.externals import joblib
Теперь нужно открыть файл с расширением csv
в Pandas. (Вы можете сделать это с помощью Excel или OpenOffice.)
data = pd.read_csv("titanic_train.csv")
data.head()
Вы увидите что-то вроде таблицы сверху (обращаем внимание, что некоторые колонки не отображены из-за чрезмерной ширины таблицы).
Посмотрите на колонку age. В таблице на изображении выше нет ячеек со значением NaN, что означает, что нет данных. В нашем случае есть просто пустые ячейки. Но обратите внимание, что NaN и пустая ячейка — одно и то же.
В презентации вам было дано задание: нужно было найти полезные, на ваш взгляд, входные данные для алгоритма.
Ожидаемые выходные данные — данные, которые мы получим в колонке survived (выжившие). Как насчёт входных данных?
Вы ведь смотрели фильм «Титаник»? (Если нет, то сейчас будет спойлер: он утонет.) Когда пришло время распределения людей по шлюпкам, больше шансов на спасение имели обладатели билетов первого класса. Также предпочтение отдавалось женщинам и детям.
Таким образом мы можем определить, что наиболее важные моменты, определяющие шанс спасения, это класс билета, возраст и пол.
Если вы женщина солидного возраста с детьми и с билетом первого класса, то вам повезло — вероятность выжить увеличивается.
Если же речь идёт о мужчине среднего возраста с билетом третьего или второго класса, то шансов на выживание становится в разы меньше. Всё как в фильме. Несмотря на то, что в таблице также указана цена билета, нам важнее знать, к какому классу относится этот билет. Если к первому, то шансы на выживание заметно возрастают.
Давайте вернёмся к пустым ячейкам. Мы не можем их оставить пустыми, потому что нам нужна информация в них для выполнения вычислений.
Решение проблемы: заменяем пустые поля медианой.
Перед тем, как продолжить чтение, убедитесь, что вы понимаете следующие термины:
- Среднее арифметическое — сумма чисел вы выборке, делённая на количество чисел в выборке. Пример: вы написали 5 строк кода, ваш друг написал 9 строк кода, ваша подруга написала 7 строк кода. В среднем вы все написали по 7 строк: 5 + 9 + 7 = 21, 21 / 3 = 7.
- Медиана (серединное число) — это такое число выборки, при котором половина значений выборки больше него, а другая половина меньше него. Пример: 1, 2, 5, 10, 21, 33, 57. Медианой в данном случае будет 10, так как числа слева меньше, а числа справа больше и с обеих сторон расположено одинаковое количество чисел.
- Мода — самое повторяющееся число из всех повторяющихся.
В нашем случае сейчас будем использовать медиану для определения возраста.
median_age = data['age'].median()
print("Median age is {}".format(median_age))
Median age is 29.0
Можно подсчитать медиану с помощью функции median()
в Pandas, из примера выше видно, что медианой является число 29.
Теперь нужно заменить пустые значения в колонке age
на значение медианы. Для этого следует использовать функцию fillna()
.
data['age'].fillna(median_age, inplace = True)
data['age'].head()
0 29
1 65
2 59
3 46
4 29
Помните пустые (NaN) значения? Теперь они заменены на 29.
Теперь нужно извлечь три нужных нам поля: class
(класс), age
(возраст), sex
(пол).
Для чего это нужно делать?
Это делается для того, чтобы не запутать алгоритм и не создавать лишний шум.
data_inputs = data[["pclass", "age", "sex"]]
data_inputs.head()
Ожидаемые выходные данные:
expected_output = data[["survived"]]
expected_output.head()
Как видите, у нас возникла проблема. Алгоритмы в библиотеке Scikit, которая используется, работают только с числами. Иначе говоря, алгоритм не понимает, что 1st
— первый класс.
Давайте исправим проблему. Просто заменим 1st
на 1
, 2nd
на 2
, 3d
на 3
. Элементарно!
data_inputs["pclass"].replace("3rd", 3, inplace = True)
data_inputs["pclass"].replace("2nd", 2, inplace = True)
data_inputs["pclass"].replace("1st", 1, inplace = True)
data_inputs.head()
Теперь проблема с классом исправлена. Возраст выставлен правильно. Остаётся поправить проблему с полом.
Будем использовать функцию np.where()
, которая не является интуитивной.
data_inputs["sex"] = np.where(data_inputs["sex"] == "female", 0, 1)
data_inputs.head()
Функция заменила female
на 0
и male
на 1
.
Тестирование для предотвращения переобучения
Как вы могли запомнить из презентации, данные были разделены на набор для тестирования и на набор для обучения. Учебный набор используется для тренировки алгоритма, в то время как набор для теста используется для выявления точности алгоритма. (Так как у нас есть предполагаемые выходные данные, мы можем сравнить их с результатами алгоритма и вычислить процент неточности.)
Пришло время разделить наборы данных. Хотя это и можно сделать вручную, в руководстве это будет выполнено с помощью встроенной функции. Она также будет выполнять другие задачи. Например, перетасовывать данные для нас.
inputs_train, inputs_test, expected_output_train, expected_output_test = train_test_split(data_inputs, expected_output, test_size = 0.33, random_state = 42)
Функция возвращает учебные входные и выходные данные, а также выходной набор данных.
test_size=0.33
значит, что 33% набора данных будет использоваться для тестирования, остальное — для обучения. random_state
используется для запуска встроенного генератора случайных выборок.
Давайте выведем несколько значений:
print(inputs_train.head())
print(expected_output_train.head())
pclass age sex
618 3 19 1
169 3 29 1
830 1 54 1
140 3 29 1
173 2 28 1
survived
618 0
169 0
830 1
140 0
173 0
Теперь нужно запустить машинное обучение.
rf = RandomForestClassifier (n_estimators=100)
Создаём образец алгоритма Random forest.
rf.fit(inputs_train, expected_output_train)
Функция fit()
используется для обучения нашего алгоритма. Он берёт часть выходных данных и пытается приблизить свой результат к ним. Поэтому мы и сузили поля для сканирования, теперь у алгоритма нет серьёзных помех, которые могли бы быть из-за прочей информации.
В идеале образец алгоритма научится предсказывать количество выживших корабле. Давайте проверим точность алгоритма.
accuracy = rf.score(inputs_test, expected_output_test)
print("Accuracy = {}%".format(accuracy * 100))
Accuracy = 79.60526315789474%
Функция score()
работает с тестовыми входными данными и выясняет, насколько точным является прогноз на основе известных выходных тестовых данных.
В примере выше показана точность, которая составила 79%. Мы узнаем, на сколько это хорошо, только когда сможем сравним с чем-нибудь.
Последний шаг близок. Всё это время тренировался алгоритм. Но нам ведь не нужно, чтобы он всё время повторял этот процесс. (Если каждый день складывать одни и те же числа, то умнее человек не станет, верно?) Следующая часть статьи не отнимет у вас много времени, так как наш набор данных невелик.
Мы можем записать модель машинного обучения в файл, чтобы в будущем иметь возможность использовать её повторно.
joblib.dump(rf, "titanic_model1", compress=9)
Раньше для этого использовалась библиотека Pickle, но функция joblib.dump
намного проще. Применение compress=9
является необходимым условием, в противном случае будут созданы десятки файлов.
Практика
В этой секции созданный алгоритм машинного обучения будет запущен в новом файле.
Работать предстоит с новым файлом, который раннее не использовался — titanic_test.csv
. Он был создан с использованием оригинальных данных, от которых были отсечены 30% данных.
Извлеките из набора данные класса и пола, как мы это сделали для первой практики.
rf = joblib.load("titanic_model2")
Теперь нужно взять входные данные и пропустить их через прогнозирующую функцию:
pred = rf.predict()# поместите сюда ваши переменные данные
Сверху вы видите пустую функцию predict()
. Вам нужно сделать predict(data)
, чтобы прогнозирование запустить.
На этом урок закончен. Спасибо за внимание!