Использование Python для Машинного обучения. Линейная регрессия. Точность модели. Часть 2.

Продолжаем знакомство с Линейной регрессией.

В данной статье мы рассмотрим, как оценить степень точности построенной модели и влияние флуктуаций на точность модели.

Рассмотрение будет производиться на простом примере.  

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

Набор данных создан искусственно и (для упрощения понимания) очень мал.

#Импортируем модули

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
import sklearn.linear_model as lm
from sklearn.metrics import r2_score , mean_absolute_error, mean_squared_error

# Загружаем данные
df = pd.read_csv('Grade_Set_1.csv')
print(df)

# Создаем объект Линейная регрессия
lr = lm.LinearRegression()

# x - выберем в качестве свойства (feature) массив с исходными данными
# А теперь, внимание, вместо решейпинг (изменение формата)
# x = df.iloc[:,1].values
# x=np.reshape(x, (-1,1))

# мы используем функцию np.newaxis, создающую новую ось
# и, по сути, решающую ту же проблему
x= df.Hours_Studied[:, np.newaxis]      # Это Features
y= df.Test_Grade.values                         # Это Labels

 # Тренируем модель
lr.fit(x, y)

#При необходимости мы можем рассчитать точку пересечений с осью и коэффициент
# наклона линии регрессии
print ("Intercept: ", lr.intercept_)
print ("Coefficient: ", lr.coef_)

# Добавим новый столбец в объект DataFrame и поместим в него предсказанное значение
df['Test_Grade_Pred']=lr.predict(x)
print(df)

# Визуализация результатов тестового набор данных
# Выводит оригинальный набор данных
plt.scatter(x,y,color = 'red')

# Выводит линию регрессии рассчитанную через вызов regressor.predict(x)
plt.plot(x, lr.predict(x), color='blue', linewidth=3)
plt.title('Grade vs Hours Studied')
plt.ylabel('Test_Grade')
plt.xlabel('Hours_Studied')
plt.show()
1jpg

# Как видим линия регрессии "легла" достаточно близко к точкам в переменной "y"
# Давайте рассчитаем точность нашего предсказания
# Для начала рассчитаем отклонение исходных значений, хранящихся в переменной "y"
# от среднего значения
# SST - sum of squares template
df['SST'] = np.square(df['Test_Grade'] - df['Test_Grade'].mean())

# Далее рассчитаем отклонение предсказанных значений, хранящихся в столбце
# DataFrame
# df['Test_Grade_Pred'], от среднего значения
# SSR - sum of squares regression
df['SSR'] = np.square(df['Test_Grade_Pred'] - df['Test_Grade'].mean())
print ("Sum of SSR:", df['SSR'].sum())
print ("Sum of SST:", df['SST'].sum())

# Рассчитаем коэффициент детерминации, показывающий на сколько точно мы предсказали значения
print ("R Squared using manual calculation: ", df['SSR'].sum() / df['SST'].sum())

R Squared using manual calculation: 0.9757431074095351

# Как видим точность достаточно большая, так как значение близко к единице, что, собственно, и видно на графике
# Произведем вычисление точности с использованием встроенных функций
print ("R Squared using built-in function: ", r2_score(df.Test_Grade, df.Test_Grade_Pred))
print ("Mean Absolute Error: ", mean_absolute_error(df.Test_Grade, df.Test_Grade_Pred))
print ("Root Mean Squared Error: ", np.sqrt(mean_squared_error(df.Test_Grade, df.Test_Grade_Pred)))

R Squared using built-in function: 0.9757431074095347
Mean Absolute Error: 1.618518518518523 Root
Mean Squared Error: 2.0422995995497297

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

# Теперь давайте внесем некоторый уровень "сумятицы" в равномерный ряд
# исходный данных.
# Для начала перезагрузим данные
df = pd.read_csv('Grade_Set_1.csv')

# Для внесения "сумятицы" добавим в данные точку со значением, явно выходящим за пределы общей тенденции
df.loc[9] = np.array([5, 100])
print(df)

# Далее делаем все тоже самое, как и в предыдущем примере, и посмотрим, что получилось
lr = lm.LinearRegression()
x= df.Hours_Studied[:, np.newaxis]   # Это Features
y= df.Test_Grade.values                # Это Labels
lr.fit(x, y)
print ("Intercept: ", lr.intercept_)
print ("Coefficient: ", lr.coef_)
df['Test_Grade_Pred']=lr.predict(x)
print(df)
plt.scatter(x,y,color = 'red')
plt.plot(x, lr.predict(x), color='blue', linewidth=3)
plt.title('Grade vs Hours Studied')
plt.ylabel('Test_Grade')
plt.xlabel('Hours_Studied')
plt.show()

2jpg

# Как видно линия регрессии не может пройти даже близко возле вновь добавленной точки, и точность предсказания остальных точек тоже ухудшилась.
# Проверим точность модели
print ("R Squared using built-in function: ", r2_score(df.Test_Grade, df.Test_Grade_Pred))
print ("Mean Absolute Error: ", mean_absolute_error(df.Test_Grade, df.Test_Grade_Pred))
print ("Root Mean Squared Error: ", np.sqrt(mean_squared_error(df.Test_Grade, df.Test_Grade_Pred)))

Почему добавление одной точки так сильно повлияло на результат? Почему коэффициент детерминации стал значительно меньше?

Проблема состоит в том, что в нашем примере слишком мало значений, что не характерно для статистической обработки реальных данных. В нашем примере мы изменили 10% данных (добавив одну точку к существующим 9-ти), что значительно изменило статистику и повлияло на точность модели. Если бы точек было несколько сотен или тысяч, то добавление одной не изменило бы статистику данных.

Alexander Kalenik,
Senior Premier Field Engineer,
Microsoft Support,
PhD