Рубрики
Без рубрики

Введение в машинное обучение с помощью Python Scikit-learn

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

Автор оригинала: Gareth Dwyer.

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

Мы научим компьютер различать заголовки “кликбейт” и “обычные” заголовки, где первые-это раздражающие заголовки типа “Вы не поверите, что X делает с Y”, которые намеренно скрывают информацию, чтобы заставить людей нажать на статью.

Традиционно, чтобы написать такой классификатор, мы вручную проверяли сотни заголовков clickbait и пытались определить шаблоны, чтобы отличить их от “хороших” заголовков. Затем мы напишем сценарий с большим количеством правил ручной работы, который попытается отличить заголовки clickbait от хороших. Это трудоемкий процесс, который требует эксперта для создания правил и требует большого обслуживания кода, потому что нам, вероятно, придется постоянно обновлять и изменять правила.

Используя подход машинного обучения, нам не нужно писать никаких правил. Мы просто выбираем алгоритм машинного обучения и “показываем” ему множество помеченных примеров заголовков clickbait и non-clickbait. Затем алгоритм самостоятельно изучает правила — надеюсь, правила, которые можно обобщить на новые данные, которые машина еще не видела.

Требования к выполнению данного руководства

Мы будем писать наш классификатор на Python 3, используя библиотеку scikit-learn. Вы должны иметь Python, настроенный на вашем компьютере, и иметь возможность устанавливать сторонние модули через pip или Conda. Если вам нужна помощь с этим шагом, есть отличный учебник доступный от Django Girls, который дает вам пошаговые инструкции для всех платформ.

Вы можете отредактировать пример кода в любом текстовом редакторе или IDE по вашему выбору и запустить их с помощью Python, интегрированного с вашей IDE, или с помощью вызова командной строки. Однако мы настоятельно рекомендуем вам использовать Jupyter Notebook , браузерное приложение , которое позволяет редактировать и запускать код Python модульным способом. В нашем сопутствующем репозитории GitHub мы предоставляем код в виде записной книжки Jupyter , которую вы можете скачать и поиграть с ней. Репозиторий также содержит код в виде простых файлов .py, если вы предпочитаете не использовать Jupyter.

Вы должны иметь некоторые существующие знания Python, но мы подробно объясним каждый шаг, поэтому, если вы знаете какие-либо другие языки, такие как Java, JavaScript или C++, вы должны быть в состоянии идти в ногу со временем.

Остальная часть этого руководства предполагает среду Linux или Mac. Если вам удобно работать с Python в Windows и вы знаете, как создавать новые файлы и каталоги, у вас не должно возникнуть проблем с адаптацией команд.

Если вы используете Windows, вам следует рассмотреть возможность установки Git for Windows и запуска его с включенными инструментами Unix во время процесса установки, как показано ниже. Это гарантирует, что большинство команд, которые мы будем использовать позже в этом уроке, будут работать так, как ожидалось.

Установка инструментов Git и включенных инструментов Unix

Настройка вашего проекта

Первое, что мы сделаем, это создадим каталог проекта и установим наши зависимости в виртуальной среде. Выполните следующие команды в терминале или командной строке.

mkdir ~/clickbait
cd ~/clickbait
virtualenv clickbait-env
source clickbait-env/bin/activate

С помощью приведенной выше команды мы создали каталог проекта с именем clickbait и перешли в этот новый каталог. Затем мы создадим новую виртуальную среду Python и активируем ее. Если у вас возникли проблемы с любым из вышеперечисленных шагов, обратитесь к official virtualenv installation docs или this guide , чтобы все настроить с помощью Windows.

Установка зависимостей

Теперь мы можем установить библиотеки, которые будем использовать, а именно Jupyter (необязательно) и scikit-learn. В вашей оболочке вы увидите, что новая виртуальная среда, которую мы создали, активна, потому что ее имя будет заключено в скобки в начале вашего запроса. Например, моя подсказка выглядит так:

(clickbait-env) ~/clickbait g$

Вы можете установить необходимые нам зависимости с помощью pip следующим образом:

pip install jupyter numpy scipy scikit-learn

Если это не работает должным образом, обратитесь к руководству по установке Jupyter и scikit-learn installation docs . В частности, scikit-learn опирается на Numpy и SciPy. Они могут быть немного сложны в установке, особенно в Windows, поэтому, если у вас есть какие-либо проблемы, вы можете изучить использование Conda или WinPython, как это предлагается в документации scikit-learn.

Получение набора данных

Мы будем использовать набор заголовков, помеченных как clickbait и normal, полученный из набора данных, используемого исследователями этой статьи . Исходный набор данных доступен в их репозитории GitHub , но мы будем использовать подмножество этого набора данных, которое я сделал доступным в виде одного файла .txt . Загрузите этот файл .txt в каталог вашего проекта. Вы можете сделать это, перейдя к файлу с помощью веб-браузера или выполнив следующую команду в командной оболочке:

wget https://raw.githubusercontent.com/sixhobbits/sklearn-intro/master/clickbait.txt

Понимание данных

Давайте быстро взглянем на данные, чтобы понять, какова наша цель. Если вы откроете clickbait.txt файл в вашем любимом редакторе вы увидите, что первые несколько строк выглядят так:

Egypt's top envoy in Iraq confirmed killed  0
Carter: Race relations in Palestine are worse than apartheid    0
After Years Of Dutiful Service, The Shiba Who Ran A Tobacco Shop Retires    1
In Books on Two Powerbrokers, Hints of the Future   0
These Horrifyingly Satisfying Photos Of "Baby Foot" Will Haunt You  1
You've Definitely Had These Arguments With Your BFF 1
11 Reasons Leslie Knope Is The Queen Of Compliments 1

Каждая строка содержит заголовок, за которым следует символ табуляции ( \t ), а затем либо 1 или 0 . Заголовки Clickbait обозначаются 1 , и нормальные заголовки по 0 . Хотя все эти примеры уже были помечены, мы хотим научить компьютер “предсказывать” ярлык, глядя только на заголовок. Наш алгоритм машинного обучения должен посмотреть на текст заголовка и решить, следует ли назначить положительную метку 1, чтобы указать, что заголовок выглядит как clickbait, или отрицательную метку 0, чтобы указать, что заголовок выглядит нормально.

Написание кода

Теперь, когда все настроено, мы можем сразу приступить к написанию некоторого кода на Python. Приведенные ниже инструкции предполагают, что вы установили Jupyter Notebook и будете использовать его. Если вы предпочитаете следовать дальше без Jupyter Notebook, просто поместите тот же код в файл .py и запустите его как обычно.

Создание записной книжки Python с помощью Jupiter

Запустите Jupyter Notebook из каталога проекта (виртуальная среда все еще активирована) и создайте новый блокнот Python. Вы можете сделать это, выполнив следующую команду в своей оболочке, которая должна открыть ваш веб-браузер и автоматически перейти к веб-приложению Jupyter:

jupyter notebook

Теперь вы можете создать новый блокнот Ipython, выбрав “Новый” в правом верхнем углу и выбрав создать блокнот Python 3, как указано ниже:

Создание новой записной книжки Python в Jupiter

Измените имя вновь созданного блокнота на clickbait_classifier , нажав на заголовок (обозначенный верхним красным прямоугольником на рисунке ниже). Вы можете добавить любой код Python, который вы хотите, в ячейку, указанную нижним красным прямоугольником, и запустить код, нажав кнопку “выполнить” (как указано средним красным прямоугольником).

Навигация по записной книжке Python

Jupyter Notebook имеет много функций, но мы будем использовать его в основном для того, чтобы он мог видеть вывод кода на промежуточных этапах. Обычно, когда вы запускаете код Python, вам нужно написать целый сценарий, а затем выполнить его. Используя Jupyter Notebook, мы можем писать наш код в меньших частях и запускать каждую “ячейку” по отдельности. Если мы хотим увидеть результаты определенного этапа или отредактировать какой-то код, который мы написали ранее, нет необходимости запускать весь сценарий снова, потому что локальные переменные каждой ячейки сохраняются и становятся доступными для других ячеек.

Импорт наших зависимостей

В первую ячейку добавьте следующие операторы импорта, которые вытягивают части scikit-learn, которые мы будем использовать. Как только вы это сделаете, нажмите Shift + Enter на клавиатуре, чтобы запустить код в этой ячейке и вставить новую ячейку ниже.

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.svm import LinearSVC
from sklearn.metrics import accuracy_score

В приведенном выше коде мы еще ничего не запускаем. Но давайте взглянем на каждую строчку:

  • Строка 1 импортирует векторизатор. Мы будем использовать это для преобразования заголовков текста в числовой формат, поскольку компьютеры понимают числа гораздо лучше, чем слова.
  • Строка 2 импортирует классификатор Машины опорных векторов (SVM). Мы не будем объяснять теорию и математику, стоящие за этим. Если вам интересно узнать больше, ознакомьтесь со статьей Wikipedia и этим постом Ирины Папаконстантину, которая дает очень четкое и интуитивно понятное объяснение того, как работают SVM. Это алгоритм, который “научится” отличать кликбейт от обычных заголовков.
  • Строка 3 импортирует метрический калькулятор, чтобы мы могли измерить, насколько хорошо работает наш классификатор.

Загрузка нашего набора данных

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

Добавьте следующий код в следующую ячейку блокнота и снова запустите его с помощью Shift + Enter.

# Load our data into two Python lists
with open("clickbait.txt") as f:
    lines = f.read().strip().split("\n")
    lines = [line.split("\t") for line in lines]
headlines, labels = zip(*lines)

Приведенный выше код читает ваш clickbait.txt файл и разбивает каждую строку на компоненты заголовка и метки. Затем мы используем оператор zip , чтобы разделить наш список кортежей на два отдельных списка, по одному для заголовков и меток. Теперь мы можем посмотреть, как структурированы наши данные, выводя первые несколько элементов каждого массива. В следующей ячейке добавьте следующий код и нажмите Shift + Enter.

headlines[:5]

Это должно вывести первые пять заголовков в нашем наборе данных, которые должны выглядеть следующим образом:

("Egypt's top envoy in Iraq confirmed killed",
 'Carter: Race relations in Palestine are worse than apartheid',
 'After Years Of Dutiful Service, The Shiba Who Ran A Tobacco Shop Retires',
 'In Books on Two Powerbrokers, Hints of the Future',
 'These Horrifyingly Satisfying Photos Of "Baby Foot" Will Haunt You')

Мы видим, что третий и пятый заголовки не содержат много информации. Это заголовки clickbait, и мы можем подтвердить это, взглянув на первые несколько ярлыков. Добавьте следующий код в следующую ячейку и выполните как обычно:

labels[:5]

Вы должны увидеть следующий вывод:

('0', '0', '1', '0', '1')

Первая метка соответствует первому заголовку, вторая метка-второму заголовку и так далее. Мы видим 1 в третьей и пятой позициях, что указывает на то, что эти заголовки являются кликбейтом, как мы и подозревали, читая их.

Разбиение нашего набора данных на обучающие и тестовые наборы

Мы могли бы обучить наш классификатор всем нашим данным сразу, но нам было бы трудно узнать, насколько хорошо он работает. Очень маловероятно, что классификатор будет идеальным — то есть иногда он будет смотреть на заголовок clickbait и ошибочно принимать его за обычный или наоборот. Если наши данные или методология каким-то образом ошибочны, наш классификатор может сделать очень плохо и просто “угадать”, являются ли заголовки наживкой или нет.

Чтобы оценить наш классификатор, мы покажем ему только часть имеющихся у нас данных. Мы назовем это “обучающим” набором, потому что наш классификатор будет смотреть на заголовки и метки и пытаться найти шаблоны, которые указывают на заголовок clickbait. Мы будем держать некоторые данные в качестве “тестового” набора. Классификатор никогда не увидит метки тестового набора, но попытается предсказать, какие заголовки являются наживкой, основываясь на паттернах, которые он узнал из обучающего набора. Затем мы сравним предсказания классификатора с метками, которые, как мы знаем, верны, чтобы увидеть, насколько хорошо работает классификатор.

Запустите следующий код в новой ячейке, чтобы увидеть, насколько велик наш набор данных:

# How big is our dataset?
len(headlines)

Это должно привести к выводу, что наш набор данных содержит 10 000 примеров. Мы используем 8000 из них для обучения нашего классификатора и удерживаем 2000 примеров для его тестирования. Мы можем достичь этого разделения, выполнив следующий код в новой ячейке:

# Break dataset into test and train sets
train_headlines = headlines[:8000]
test_headlines = headlines[8000:]

train_labels = labels[:8000]
test_labels = labels[8000:]

Создание векторизатора и классификатора

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

Мы будем использовать схему векторизации, известную как “частота термина — обратная частота документа”, или более широко tf-idf . По этой схеме каждый заголовок будет представлен в виде большого разреженного массива (то есть большинство элементов массива будут равны 0). Каждый элемент в массиве представляет, как часто конкретное слово встречается в заголовке. Поскольку мы не можем учесть все возможные слова, мы предполагаем, что все слова в нашем наборе данных-это все слова, которые существуют в мире. Слова, которые очень часто встречаются в наборе данных (например, “the” и “and”), имеют низкий вес и считаются неважными. Слова, которые встречаются реже (например, “Зимбабве”), имеют более высокий вес и считаются более важными. О специфике этих расчетов вы можете прочитать на странице Википедии tf-idf .

Второе, что нам нужно, – это классификатор. Как обсуждалось ранее, мы будем использовать линейный SVM-классификатор. Благодаря простоте scikit-learn векторизатор и классификатор могут быть созданы в одной строке кода. Добавьте следующее в новую ячейку и запустите ее:

# Create a vectorizer and classifier
vectorizer = TfidfVectorizer()
svm = LinearSVC()

Обучение нашего классификатора

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

Преобразование текстовых данных в векторы выполняется в два этапа. Во-первых, нам нужно “подогнать” векторизатор. На этом этапе наш векторизатор просматривает все уникальные слова в нашем наборе данных, чтобы решить, сколько измерений нужно нашим векторам. Во-вторых, мы вызовем “преобразование” и передадим наши тестовые данные, которые векторизатор затем преобразует в матрицу векторов. В scikit-learn мы можем выполнить оба шага одновременно, вызвав функцию fit_transform .

Мы вызовем fit_transform на наших обучающих данных, что означает, что наш векторизатор будет считать, что слова, найденные в нашем обучающем наборе, представляют весь интересующий нас словарь. Мы будем вызывать только transform (без fit ) в нашем тестовом наборе, поэтому любые слова в нашем тестовом наборе, которые не входят в наш обучающий набор, будут отброшены. Мы можем создать наши обучающие и тестовые векторы, запустив следующий код в новой ячейке:

# Transform our text data into numerical vectors
train_vectors = vectorizer.fit_transform(train_headlines)
test_vectors = vectorizer.transform(test_headlines)

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

# Train the classifier and predict on test set
svm.fit(train_vectors, train_labels)

Это “показывает” все наши учебные заголовки и связанные с ними метки нашему классификатору. Наш SVM видит эти данные как точки в многомерном пространстве и пытается найти гиперплоскость, которая отделяет заголовки clickbait от других. Это итеративный и вычислительно дорогостоящий процесс, который может занять очень много времени для больших наборов данных, но должен завершиться за секунду или меньше для нашего небольшого набора данных.

Оценка нашего классификатора

Наш классификатор теперь “обучен.” Теоретически мы можем показать ему новые заголовки, которые он не видел во время тренировки, и он сможет сделать обоснованное предположение о том, какие из них являются кликбейтами.

Давайте проверим это.

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

predictions = svm.predict(test_vectors)

Переменная predictions теперь содержит массив меток — по одной метке для каждого заголовка в нашем тестовом наборе. Если наш классификатор работает хорошо, эти “предсказания” должны быть очень похожи на реальные метки, которые мы имеем в массиве test_labels . Давайте вручную рассмотрим первые несколько, прежде чем использовать оценочные функции, которые мы использовали для получения более широкого представления картины.

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

test_headlines[0:5]

Это должно привести к следующему результату:

('The Earliest I\'ve Said "I Love You"',
 "Stop What You're Doing And Worship These Matt Bomer Pictures",
 '23 Of The Funniest "Nancy Drew" Game Memes',
 'Policeman killed in football-related violence in Italy',
 'Do You Remember Which Disney Star Sang These Lyrics')

Мы можем увидеть, что наш классификатор думает о каждом из этих заголовков, запустив следующее в новой ячейке:

predictions[:5]

Существует некоторая случайность, используемая как часть алгоритма обучения, поэтому ваши результаты могут немного отличаться. Мой вывод выглядит следующим образом:

array(['1', '1', '1', '0', '1'],
      dtype='

Это означает, что классификатор считал, что четыре из первых пяти тестовых заголовков выглядят как кликбейт. В 0 в четвертой позиции массива указано, что он думал, что только четвертый заголовок “Полицейский убит в результате насилия, связанного с футболом в Италии”, не был наживкой. Читая заголовки, мы, вероятно, можем согласиться с классификатором, но мы можем проверить предоставленные метки, чтобы быть уверенными. Выполните следующий код в новой ячейке:

test_labels[:5]

Это должно вывести следующее, подтверждая, что классификатор получил все пять случаев правильно:

('1', '1', '1', '0', '1')

Мы можем вычислить оценку точности всех тестовых случаев с помощью функции accuracy_score . Это просто число раз, когда классификатор был правильным (когда метка, которую он предсказал, была такой же, как метка, которую мы предоставили), деленное на общее количество меток (2000 для нашего тестового набора). Мы можем получить это число, запустив следующий код в новой ячейке:

accuracy_score(test_labels, predictions)

Опять же, ваши результаты могут немного отличаться из-за случайности, используемой во время тренировки, но вы должны увидеть что-то похожее на результат ниже:

0.96099999999999997

Это показывает, что наш классификатор получил 96 процентов тестовых случаев правильно. То есть наш классификатор получил правильный ответ примерно в 1920 из 2000 тестовых случаев.

Использование нашего классификатора

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

Давайте составим новые данные и посмотрим, насколько хорошо работает наш классификатор. Buzzfeed – отличный источник заголовков, которые часто, но не всегда, являются clickbait, поэтому посетите домашнюю страницу и возьмите любой заголовок, который вы хотите. Я выбрал 10 Городов, В Которые Скоро Переедет Каждый Хипстер и Вице-Президент Майк Пенс Покидает Игру НФЛ , Говоря, Что Игроки Проявили “Неуважение” К Гимну, Флагу , оба из которых сегодня находятся на главной странице Buzzfeed. Давайте посмотрим, что наш классификатор думает об этих заголовках.

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

new_headlines = ["10 Cities That Every Hipster Will Be Moving To Soon", 'Vice President Mike Pence Leaves NFL Game Saying Players Showed "Disrespect" Of Anthem, Flag']
new_vectors = vectorizer.transform(new_headlines)
new_predictions = svm.predict(new_vectors)

Мы можем посмотреть на новые предсказания в новой ячейке. Выполните следующие действия:

new_predictions

Мой вывод выглядит следующим образом:

array(['1', '0'],
      dtype='

Это указывает на то, что классификатор считал, что первый заголовок о хипстерах-это clickbait, а второй заголовок о Майке Пенсе-нет. Поскольку у нас нет ярлыков для этих заголовков, у нас нет ничего, кроме нашего собственного суждения, чтобы проверить предсказания нашего классификатора. Надеюсь, очевидно, что классификатор снова прав!

Заключение и движение вперед

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

Машинное обучение-это большая и сложная тема, и мы только что поцарапали поверхность в этом посте. Если вы хотите увидеть более практичные проекты классификации текстов, взгляните на мой Yelp Dataset Challenge GitHub repository , где я показываю, как делать анализ настроений и атрибуцию авторства с помощью онлайн-обзоров.

Не стесняйтесь комментировать ниже или связаться со мной на Twitter если у вас есть вопросы или комментарии по поводу этого урока!