С кодом на Python

Введение

В этом новом выпуске серии Основы машинного обучения мы создадим модель для задачи многомерной линейной регрессии и проверим нашу модель, используя библиотеки Mathplotlib, Pandas и NumPy в Python. При создании нашей модели мы будем использовать набор данных Kaggle в качестве ресурса для обучения и проверки. Для этой цели мы будем использовать и объяснять основные части следующего блокнота Kaggle:



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



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

Мы также представим две новые концепции: Векторизация и Масштабирование объектов. Итак, начнем с векторизации.

Векторизация

Векторизация — это перспектива скорости в реализации [1]. Одним из способов реализации алгоритмов машинного обучения является использование программных циклов в нашем коде. Поскольку нам нужно добавлять или удалять значения для каждой выборки данных для реализации алгоритмов машинного обучения, использование программных циклов кажется очевидным. С другой стороны, различные библиотеки числовой линейной алгебры, которые мы можем использовать, либо встроены, либо быстро доступны в большинстве языков программирования. Эти библиотеки более эффективны и могут использовать параллельное оборудование на наших компьютерах, если оно доступно. Поэтому вместо менее эффективных циклов мы можем использовать векторы и матрицы в этих библиотеках для ускорения. Более того, мы напишем меньше кода, что приведет к более чистой реализации [2]. Эта концепция известна как векторизация.

В этом сообщении блога для векторизации будет использоваться библиотека Python NumPy.

Масштабирование функций

Мы можем ускорить градиентный спуск, имея каждое входное значение примерно в одном диапазоне [2]. Этот подход называется масштабированием признаков. Применение масштабирования признаков может быть необходимо для точной работы целевых функций в некоторых алгоритмах машинного обучения или для надлежащего штрафа за коэффициенты при регуляризации [3].

Тем не менее, для нашего конкретного случая градиентный спуск может сходиться быстрее, если мы применим масштабирование признаков, поскольку θ будет снижаться быстрее в малых диапазонах, чем в больших диапазонах, что вызывает колебания при поиске оптимальных значений θ [2].

Существуют различные методы масштабирования; мы представим три из них:

Стандартизация

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

Средняя нормализация

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

Мин-макс масштабирование

Для каждого выборочного значения x признака, если мы вычтем минимальное значение этого признака из x и разделим результат на разницу между максимальным и минимальным значениями этого признака, мы получим масштабированное решение
min-max. С математической точки зрения:

Функция нормализации

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

Мы используем методы min() и max() библиотеки Pandas внутри блока кода. Вы можете обратиться к разделу Импорт для импорта библиотеки Pandas. Заинтересованные читатели могут также обратиться к записной книжке Многомерная линейная регрессия с нуля, чтобы узнать, какие столбцы выбраны для масштабирования.

Импорт

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

Мы будем использовать библиотеку NumPy для операций с матрицами и целей векторизации и библиотеку Pandas для задач обработки данных. Для визуализации будет использоваться библиотека Matplotlib.

Scikit-learn (или sklearn) — распространенная библиотека для машинного обучения. train_test_split от sklearn используется для разделения набора данных на две части для обучения и проверки. Хотя мы не будем использовать train_test_split в нашем коде в этом сообщении блога, нам нужно использовать его для разделения наших данных. Заинтересованные читатели могут обратиться к записной книжке Многомерная линейная регрессия с нуля, чтобы узнать, как она используется.

Гипотеза

Гипотеза будет вычислять прогнозируемые значения для заданного набора входных данных и весов.

Гипотеза для задачи линейной регрессии с несколькими переменными имеет вид:

Приведенное выше уравнение не подходит для векторизованного решения. Итак, давайте определим векторы-столбцы θ и x так, чтобы;

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

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

Однако, как описано выше, нам нужно x₀ = 1 для векторизованного решения. Итак, мы должны настроить наш набор данных с новым столбцом x₀ со всеми единицами.

Следовательно, для набора данных из m выборок и n объектов мы можем вставить новый столбец x₀ из единиц, а затем вычислить вектор-столбец размером (m x 1) так, чтобы каждый элемент вектора-столбца был прогнозируемой целью для одного образца набора данных. Формула выглядит следующим образом:

Обратите внимание, что мы присвоили новый столбец x₀ матрице x, которая равна единице. Это необходимо для векторизованного решения, и мы увидим, как это сделать, в разделе «Обучение модели».

Как видно, для записи функции гипотезы нам нужны два параметра. Это матрица x размерности (m X n+1) для обучающих (или тестовых) данных и вектор-столбец θ из (n+1) элементов для весов. m — количество выборок, n — количество признаков. Итак, давайте напишем функцию Python для гипотезы:

Внутри функции гипотезы мы возвращаем скалярное произведение параметров, используя метод dot() библиотеки NumPy.

Функция стоимости

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

Чтобы получить векторизованное решение, мы можем использовать следующий вектор:

Этот вектор (m X 1) имеет некоторое сходство с вектором Гипотезы, описанным выше, и мы воспользуемся этим сходством. Сумма элементов этого вектора является частью Σ функции стоимости, а именно:

Мы получим приведенный ниже вектор, если учтем квадраты в каждом элементе вектора.

Это уравнение можно переписать как скалярное произведение следующих векторов строки и столбца.

Мы получим следующие векторы, если изменим порядок переменных в уравнении.

И, заменив векторизованную гипотезу на Xθ, мы получим следующее уравнение.

Наконец, мы получаем векторизованную функцию стоимости, умножая это уравнение на единицу на два, умноженных на m.

Нам нужны три параметра для функции стоимости: вектор X, y и θ. Параметр X представляет собой матрицу размеров (m X n+1), где m — количество примеров, а n — количество признаков, и это обучающий (или тестовый) набор данных. Параметр y представляет собой вектор размеров (m X 1), который содержит фактические выходные данные для каждой выборки. Параметр θ представляет собой вектор размеров (n+1 X 1) для весов.

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

Мы можем разложить формулу функции стоимости на три части. Постоянная часть, вектор размерами (mX1) и транспонирование того же вектора с размерами (1Xm).

Итак, внутри функции стоимости мы сначала вычисляем постоянную часть. Затем мы вычисляем вектор (mX1), используя функцию гипотезы и вектор y. Затем мы можем использовать функцию транспонирования NumPy, чтобы вычислить транспонирование того же вектора. Наконец, мы можем произвести точечное произведение двух векторов, используя библиотеку Numpy, умножить на константу и вернуть результат.

Градиентный спуск

Вычисление градиентного спуска идентично одномерной версии, но уравнение должно быть расширено для n + 1 веса [2].

В приведенной выше формуле n — количество признаков, θⱼ (для j = 0, 1,…, n) — соответствующие веса функции гипотезы, α — скорость обучения, m — количество примеров, h(x ⁽ⁱ⁾) — результат функции гипотезы для обучающего примера iᵗʰ, y⁽ⁱ⁾ — фактическое значение для обучающего примера iᵗʰ и xₖ⁽ⁱ⁾ (для k=0, 1, …, n; i=1 , 2, …, m) — значение признака kᵗʰ для обучающего примера iᵗʰ.

Подобно тому, что мы сделали с функцией стоимости, мы можем переписать Σ часть этих уравнений как скалярное произведение двух векторов для j = 0, 1, …, n:

Таким образом, векторизованное решение для градиентного спуска становится:

Как видно, нам нужны четыре параметра для функции градиентного спуска: вектор X, y, θ и скорость обучения α.

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

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

Данные

Для создания и проверки нашей модели мы будем использовать следующий набор данных [4] от Kaggle:



Набор данных включает несколько параметров, критических для применения магистерских программ [5]:

Баллы GRE (из 340)
Баллы TOEFL (из 120)
Рейтинг университета (из 5)
Заявление о целях и рекомендательное письмо (из 5)< br /> Средний балл бакалавриата (из 10)
Исследовательский опыт (0 или 1)
Вероятность поступления (от 0 до 1)

Целевой переменной является параметр Шанс допуска. Мы будем использовать 80 % данных для обучения и 20 % для тестирования. Кроме того, мы будем использовать процентную оценку вместо определения вероятности для целевой переменной. Мы не будем объяснять, как загружать и обрабатывать данные. Заинтересованные читатели могут обратиться к Блокноту Многомерная линейная регрессия с нуля для загрузки и разделения данных.

В наборе данных есть две версии файлов CSV [5]. Мы будем использовать версию 1.1, в которой 500 примеров.

Обучение модели

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

Чтобы применить векторизованное решение, мы должны определить функцию X₀, равную 1, для всех обучающих примеров. Итак, наша первая задача — вставить столбец X₀ в данные обучения и проверки. Далее нам нужно инициализировать вектор θ, и мы установим все веса равными нулю. В качестве последнего шага перед градиентным спуском мы назначим скорость обучения и пороговые значения.

Внутри блока кода первое, что нужно сделать, — это вычислить значения m и n для обучающих и тестовых данных. Далее мы создадим список из них для вставки в DataFrames в качестве первого столбца. Это потому, что нам нужно определить столбец X₀=1 для векторизованного решения. Затем мы устанавливаем вектор θ как все нули. После инициализации скорости обучения и пороговых значений мы можем рассчитать начальное значение стоимости и инициализировать некоторые важные переменные для целей отображения.

Пороговое значение будет использоваться для проверки того, сходится ли градиентный спуск. Для этого мы будем вычитать последовательные значения стоимости внутри цикла while. Если разница меньше определенного порога, мы сделаем вывод, что градиентный спуск сходится. В противном случае мы будем продолжать брать градиент и пересчитывать значение стоимости.

Результат

Нижеприведенный результат относится к начальным условиям в блоке кода обучения модели. Обучение заняло 24 итерации. Окончательное значение стоимости было вычислено примерно как 66, а вектор θ рассчитывается как:

θ: [2.03692557 1.13926025 1.14289218 6.02902784 6.60181418 6.82324225 1.20521232 1.25048269]

Мы также можем использовать кривую обучения, чтобы убедиться, что градиентный спуск работает правильно [2]. Кривая обучения представляет собой график, который показывает нам изменение значения стоимости на каждой итерации во время обучения, и значение стоимости должно уменьшаться после каждой итерации [2]. Заинтересованные читатели могут обратиться к блокноту Многомерная линейная регрессия с нуля, чтобы узнать, как построить кривую обучения.

Проверка модели

Как объяснялось выше, мы можем использовать кривые обучения для отладки нашей модели. Наша кривая обучения кажется правильной, и ее форма именно такая, как хотелось бы [2]. Но нам все еще требуется проверить нашу модель. Для этого мы можем использовать набор данных проверки, который мы разделили перед началом обучения, поскольку для проверки мы должны использовать данные, которые никогда не использовались в процессе обучения. Мы будем использовать вектор θ, рассчитанный ранее для проверки.

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

Заключение

В этом сообщении блога мы написали функции гипотезы, стоимости и градиентного спуска на Python с методом векторизации для задачи многомерной линейной регрессии. Мы также масштабировали часть наших данных, обучили модель линейной регрессии и проверили ее, разделив наши данные. Для этой цели мы использовали набор данных Kaggle Graduate Admission 2.

Мы установили высокую скорость обучения и низкий порог сходимости в демонстрационных целях, в результате чего стоимость обучения составила примерно 66, а стоимость проверки - примерно 76. Эту высокую стоимость легко увидеть, сравнив прогнозируемый и фактический шанс. допустимых значений. Играя со скоростью обучения и пороговыми значениями, мы можем получить значение стоимости обучения меньше 20, что приведет к более точным прогнозам.

Но мы должны знать, что набор данных был выбран только в демонстрационных целях для задачи многомерной линейной регрессии, и для этого набора данных могут быть гораздо лучшие алгоритмы.

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

Спасибо за чтение!

Рекомендации

[1] Нг, А. и Ма, Т. (2022) CS229 Lecture Notes, CS229: Machine Learning. Стэндфордский Университет. Доступно по адресу: https://cs229.stanford.edu/notes2022fall/main_notes.pdf (дата обращения: 24 декабря 2022 г.).

[2] Нг, А. (2012) Специализация машинного обучения, Coursera.org. Стэндфордский Университет. Доступно по адресу: https://www.coursera.org/specializations/machine-learning-introduction (дата обращения: 9 января 2023 г.).

[3] Масштабирование объектов (2022 г.) Википедия. Фонд Викимедиа. Доступно по адресу: https://en.wikipedia.org/wiki/Feature_scaling (дата обращения: 6 марта 2023 г.).

[4] Мохан С. Ачарья, Асфия Армаан, Анита С. Энтони: сравнение регрессионных моделей для прогнозирования поступления в аспирантуру, Международная конференция IEEE по вычислительному интеллекту в науке о данных, 2019 г.

[5] Ачарья, М.С. (2018) Прием в аспирантуру 2, Kaggle. Доступно по адресу: https://www.kaggle.com/datasets/mohansacharya/graduate-admissions (дата обращения: 14 марта 2023 г.).