в Статьи

Байесовская линейная регрессия в Python: использование машинного обучения для прогнозирования оценок учащихся

Spread the love

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

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

Полный код для этого проекта доступен на Jupyter Notebook на GitHub. Я призываю всех, кто интересуется, проверить его и создать свой собственный проект основываясь на нем. В любом случае не стесняйтесь использовать, строить и распространять код!

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

Исследование данных

Первым шагом в решении проблемы науки о данных (после очистки данных) является Разведочный анализ данных (Exploratory data analysis). Это открытый процесс, когда мы ищем аномалии, интересные тенденции или шаблоны и корреляции в наборе данных. Они могут быть интересны сами по себе, и они могут помочь при моделировании. В принципе, мы используем EDA, чтобы узнать, что могут сказать наши данные!

Прежде всего, давайте посмотрим на данные, используя pandas dataframe:

import pandas as pd
df = pd.read_csv('data/student-mat.csv')
df.head()

Всего имеется 633 наблюдения с 33 переменными. Каждая строка — один студент с каждым столбцом, содержащим разные характеристики. Столбец «Оценка» (Grade) — это наша целевая переменная (также известная как «ответ»), которая характеризует эту задачу как «обучение с учителем». У нас есть набор данных обучения с известными целями, и во время обучения мы хотим, чтобы наша модель научилась прогнозировать оценку по другим переменным. Мы будем рассматривать оценку как непрерывную, что делает эту проблему регрессией (технически оценка принимает только целочисленные значения, поэтому это номинальная переменная).

Основная переменная, представляющая интерес, — это оценка, поэтому давайте посмотрим на распределение, чтобы проверить распределение:

import matplotlib.pyplot as plt
# Histogram of grades
plt.hist(df['Grade'], bins = 14)
plt.xlabel('Grade')
plt.ylabel('Count')
plt.title('Distribution of Final Grades')

 

Оценки близки к нормальному распределению к 11 (шкала оценки в этой школе идет от 0-20). В то время как общие оценки не имеют заметного перекоса, вполне возможно, что учащиеся из определенных категорий будут иметь перекошенные оценки. Чтобы посмотреть на влияние категориальных переменных на оценки, мы можем сделать их графики плотности распределения, окрашенные значением категориальной переменной. Для этого мы используем seaborn библиотеку и функцию kdeplot. Вот код для построения распределения по местоположению (городскому или сельскому):

import seaborn as sns
# Make one plot for each different location
sns.kdeplot(df.ix[df['address'] == 'U', 'Grade'],
label = 'Urban', shade = True)
sns.kdeplot(df.ix[df['address'] == 'R', 'Grade'],
label = 'Rural', shade = True)
# Add labeling
plt.xlabel('Grade')
plt.ylabel('Density')
plt.title('Density Plot of Final Grades by Location')

Мы можем использовать аналогичный код для построения распределения оценок опекуном с приведенными ниже графиками:

 

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

Выбор фич

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

Чтобы выбрать ограниченное число переменных, мы можем найти те, которые имеют наибольшую корреляцию (отрицательную или положительную) с итоговой оценкой. Найти корреляции в Pandas очень просто:

# Find correlations and sort
df.corr()['Grade'].sort_values()
failures -0.384569
absences -0.204230
Dalc -0.196891
Walc -0.178839
traveltime -0.129654
goout -0.111228
freetime -0.105206
health -0.096461
age -0.042505
famrel 0.072888
Fedu 0.204392
studytime 0.249855
Medu 0.278690

Эти корреляции, по-видимому, имеют смысл, по крайней мере, благодаря моим элементарным знаниям в области социальных наук! Неудачи — это число предыдущих видов неудач и негативно влияет на оценку — отсутствия на уровках. С другой стороны, время обучения (количество часов в неделю) и образование матери позитивно коррелирует с оценками.

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

Унитарное кодирование является стандартным шагом в машинных процессах и очень просто взаимосвязано с библиотекой pandas:

# Select only categorical variables
category_df = df.select_dtypes('object')
# One hot encode the variables
dummy_df = pd.get_dummies(category_df)
# Put the grade back in the dataframe
dummy_df['Grade'] = df['Grade']
# Find correlations with grade
dummy_df.corr()['Grade'].sort_values()
higher_no -0.343742
school_MS -0.227632
Mjob_at_home -0.158496
reason_course -0.138195
internet_no -0.131408
address_R -0.128350
address_U 0.128350
internet_yes 0.131408
Fjob_teacher 0.160938
Mjob_teacher 0.173851
reason_reputation 0.185979
school_GP 0.227632
higher_yes 0.343742

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

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

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

Полное описание переменных содержится в репозитории обучения машин UCI, но вот краткий обзор:

failures: неудачи предыдущего класса
higher_edu:  будет ли студент заниматься высшим образованием
mother_edu: уровень образования матери
studytime: количество занятий в неделю
father_edu: уровень образования отца
absences: отсутствие в школе в течении семестра

Пока мы выполняем выбор фич, мы также разделяем данные на набор для обучения и тестирования, используя функцию Scikit-learn. Это необходимо, потому что нам нужно провести перекрестную проверку, чтобы оценить нашу модель и убедиться, что она правильно работает:

from sklearn.model_selection import train_test_split
# df is features and labels are the targets
# Split by putting 25% in the testing set
X_train, X_test, y_train, y_test = train_test_split(df, labels,
test_size = 0.25,
random_state=42)

Это дает нам 474 учебных наблюдения и 159 тестовых точек данных.

Протестируйте выбранные фичи

Одной из моих любимых графиков является Pairs Plot, который отлично подходит для отображения как распределения переменных, так и отношений между парами переменных. Здесь я использую seaborn функцию PairGrid, чтобы показать Pair Plot для выбранных фич:

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

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

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

# X_train is our training data, we will make a copy for plotting
X_plot = X_train.copy()
# Compare grades to the median
X_plot['relation_median'] = (X_plot['Grade'] >= 12)
X_plot['Grade'] = X_plot['Grade'].replace({True: 'above',
False: 'below'})
# Plot all variables in a loop
plt.figure(figsize=(12, 12))
for i, col in enumerate(X_plot.columns[:-1]):
plt.subplot(3, 2, i + 1)
subset_above = X_plot[X_plot['relation_median'] == 'above']
subset_below = X_plot[X_plot['relation_median'] == 'below']
sns.kdeplot(subset_above[col], label = 'Above Median')
sns.kdeplot(subset_below[col], label = 'Below Median')
plt.legend()
plt.title('Distribution of %s' % col)

plt.tight_layout()

Код строит следующие графики:

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

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

Определение основных показателей

Одним из наиболее упущенных аспектов цикла машинного обучения является установление основных показателей. Да, это может показаться впечатляющим, если ваша модель классификации достигает 99% точности, но что, если мы можем получить 98% -ную точность, просто угадывая один и тот же класс каждый раз? Мы действительно хотим потратить время на создание модели для этой проблемы? Хорошая основа позволяет нам оценить, применима ли наша модель (или любая модель) к задаче.

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

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

Когда мы прогнозируем 12 для каждого примера тестового набора, мы получаем следующие результаты

Median Baseline MAE: 2.1761
Median Baseline RMSE: 2.6777

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

Основное внимание в моделировании уделяется байесовской линейной регрессии, но мы можем сравнить наши результаты с результатами стандартных методов, таких как линейная регрессия, SVN или деревья решений. Мы оценим некоторые из этих методов в нашем наборе данных. К счастью, все это очень легко реализовать с помощью библиотек Python, таких как Scikit-Learn. Вот результаты для 6 разных моделей:

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

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

Grade = 9.19 - 1.32 * failures + 1.86 * higher_edu + 0.26 *
mother_edu + 0.58 * studytime + 0.03 * father_edu - 0.07 * absences

Число 9.19 представляет наше предположение, если каждая переменная учащегося равна 0. Коэффициенты (также известные как параметры веса или модели) указывают на эффект увеличения единицы в соответствующей переменной. Например, с каждым дополнительным предыдущим провалом ожидается, что оценка ученика уменьшится на 1,32 балла, а при каждом дополнительном увеличении образования матери уровень ученика увеличится на 0,26 пункта. Я часто начинаю с линейной регрессии при решении проблемы, потому что, если она работает достаточно хорошо, у нас есть вполне объяснимая модель, которую мы можем использовать для прогнозирования.

Выводы

В то время как машинное обучение привлекает все больше внимание, оно часто включает небольшую часть проекта в области науки о данных. Большая часть работы — и большая часть ценности- заключается в получении, очистке и изучении данных. Только после того, как мы твердо поймем структуру наших данных и отношения внутри нее, мы должны приступить к построению моделей машинного обучения. Я хотел показать весь процесс, чтобы этот проект продемонстрировал типичный рабочий процесс в области data science. В первой половине этого проекта мы:

— Изучили данные, чтобы найти интересные шаблоны, тенденции или аномалии
— Проверили корреляции между фичами и целью
— Выбрали фичи на основе корреляции
— Установили основные метрики и оценки работы модели

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

 

Перевод осуществлен по материалам: William Koehrsen
Data Scientist and Master Student, Data Science Communicator and Advocate