В этом простом проекте мы создадим алгоритм линейной регрессии и построим простую, но надежную модель с нуля на python. После этого мы будем использовать эту модель для прогнозирования уровня сахара в крови пациента с диабетом на основе их данных ИМТ.

Узнайте больше об индексе массы тела и о том, как он по-разному влияет на здоровье людей и, в конечном итоге, как он влияет на уровень сахара в крови у пациентов с диабетом здесь: https://en.wikipedia.org/wiki/Body_mass_index

Данные, взятые из http://www4.stat.ncsu.edu/~boos/var.select/diabetes.tab.txt, показывают уровень сахара в крови 442 пациента с диабетом с 10 исходными переменными или характеристиками. , возраст, пол, индекс массы тела, артериальное давление и шесть измерений сыворотки крови. Из этих переменных или характеристик мы будем использовать только одну переменную ИМТ и предположим, что она имеет прямую линейную связь с уровнем сахара в крови. Мы уже выполнили все операции по изменению данных и подготовили для вас данные с необходимыми столбцами. Пожалуйста, просмотрите файл данных на GitHub Repo:
https://github.com/pankymathur/simple-linear-regression-using-python-only/blob/master/diabetes.csv
Перед вами двигаться вперед, Да, вы правильно поняли в заголовке этой статьи, мы не будем использовать современный SciKit Learn, но будем строить модель линейной регрессии собственными руками с нуля ... и будем объяснять вещи по ходу

Мы будем освещать:

  • Подгонка данных к уравнению прямой y = mx + b
  • Вычисление ошибок через квадрат ошибок (y_predicted - y) ²
  • Минимизация ошибок с помощью частных производных, также известных как градиентный спуск
  • Вычисление новых m & b с использованием градиентного спуска с скоростью обучения на многих итерациях
  • Используйте этот новый m & b для прогнозирования уровня сахара в крови по данным образца / теста ИМТ

Обратите внимание: эта статья никоим образом не подрывает статус SciKit-Learn или GraphLab и что эти пакеты не нужны (потому что они абсолютно замечательные, широко используются в промышленности и очень необходимые пакеты для любых реальных проектов машинного обучения или науки о данных. )

Тем не менее, цель состоит в том, чтобы показать математику и красоту Python, а также обоснование того, что все эти пакеты каким-то образом используют схожую математику и логику за дверями. Кроме того, эти пакеты предоставляют множество других функций и очень устойчивые модели машинного обучения с помощью простых вызовов функций. Подробнее о SciKit. Узнайте здесь, http://scikit-learn.org/stable/ и https://turi.com

Хорошо, хватит предыстории, давайте начнем этот нано-проект.

  • Подгонка данных к уравнению прямой y = mx + b

В этом нанопроекте мы используем простое линейное уравнение y = mX + b для построения контролируемой модели линейной регрессии.

Основываясь на данных, мы принимаем y (цель) как уровень сахара в крови и X (характеристика) как ИМТ пациентов с диабетом. Посмотрите на данные здесь (нет столбцов с именами), но обратите внимание, что первый столбец - это ИМТ, а второй столбец - уровень сахара в крови. Https://github.com/pankymathur/simple-linear-regression-using-python-only/blob/master/diabetes.csv

Наша модель предполагает, что существует связь между y (уровень сахара в крови) и X (ИМТ), и они следуют схеме, которая представлена ​​уравнением линии y = mx + b.

Здесь «m» - это наклон между «X» (ИМТ) и «y» (уровень сахара в крови), то есть коэффициент взаимосвязи, и по сравнению с нашими данными это означает, что для каждой единицы ИМТ (X) уровень сахара в крови ( y) изменится m раз.

'b' - это точка пересечения по оси Y (постоянное значение), точка пересечения по оси Y, это значение по умолчанию для y, когда x = 0, и всегда постоянное значение для любых значений x ›0, и по сравнению с нашими данными это означает, что любое значение ИМТ (X) дано нашей модели или нет, всегда есть значение сахара в крови (y), равное b.

Кто бы мог подумать, что ИИ предпочел бы строгий здоровый образ жизни…. :)

  • Вычисление ошибок с помощью функции квадрата ошибок (y_predicted - y) ²

Давайте двигаться дальше, но учтите, что значения «m» и «b» будут генерироваться во время обучения модели или иногда называются в мире машинного обучения «процессом подгонки модели». (Все модели SciKit-Learn использовали метод .fit () для обучения модели на основе данных)

Вкратце, так они и работают Обучение или подгонка модели (по крайней мере, в моем понимании ..) заключается в том, что мы будем использовать тип уравнения y = mX + b для заданных данных, пытаясь подогнать все значения X по отношению к « y »и найдя правильный наклон« m »и добавив к нему« b »(точка пересечения оси y с постоянным значением).

Это будет достигнуто путем выбора любого случайного значения m и b для каждой строки данных и использования значения X в уравнении (y = mX + b), что даст нам новое значение y. Этот новый y aka y_predicted будет сравниваться с фактическим y из той же строки данных, а затем мы возьмем квадрат разницы ошибок, этот процесс будет повторяться для каждой строки данных, а затем мы вычислим общую ошибку, суммируя вверх для каждой строки и нормализовать (усреднить) ее путем деления на количество всех строк данных. См. Ниже код Python для вычисления ошибки для всех строк данных с использованием функции ошибок f (x) = ((y_initial - y_predicted) ²) / Количество строк данных

# The Square of Error function
def compute_error_for_line_given_points(b, m, points):
 
  totalError = 0
  error = 0
 
  for i in range(0, len(points)):
     x = points[i,0]
     y = points[i,1]
 # Our Error funcion f(x) = ((y_initial - y_predicted)^2) / Number  of data rows
 
 error = ((y - (m*x + b)) ** 2) / len(points)
 totalError += error / len(points)
 
 print "At Row {0}, using b = {1} and m = {2}, Error = {3}".format(i, b, m, error)
 
 print "\n Total Error is: {0}".format(totalError)
 return error, totalError

например, если вы откроете Diabetes.csv https://github.com/pankymathur/simple-linear-regression-using-python-only/blob/master/diabetes.csv, вы увидите в первой строке первый столбец как ИМТ (X) = 41,3 и второй столбец как уровень сахара в крови (y) = 346 мг / дл

скажем, мы используем случайным образом m = 1 и b = 1. Затем мы помещаем эти значения в уравнение y_predicted = mX + b.

поэтому y_predicted = (1) (41,3) + 1 = ~ 41 мг / дл

теперь фактический y был 103 мг / дл, поэтому результат функции ошибки равен f (x) = ((y_initial - y_predicted) ^ 2) / Number of data rows = ((341-41) ^ 2) / 442 = ((300) ^ 2) / 442 = (90000) / 442 = ~ 204 мг / дл погрешности. Это звучит как огромная неумолимая ошибка для предсказания уровня сахара в крови человека. Однако именно здесь проявляется логика самообучения, обучения на своих ошибках.

Теперь мы будем следить за этой ошибкой и постараемся минимизировать эту ошибку, выбрав разные значения m и b. Как мы узнаем, какое значение m и b является правильным на данный момент, на самом деле мы не знаем, однако мы знаем, в каком направлении мы можем двигаться, то есть мы знаем, что, выбирая m = 1 и b = 1, мы недостаточно для предсказания правильного уровня сахара в крови 346 мг / дл. так что пойдем в сторону выбора более высоких m и b.

как насчет m = 10 и b = 10, поэтому new y_predicted = (m) (X) + b = (10) (41,3) + 10 = 423 мг / дл.

Итак, результат функции ошибки: f (x) = ((y_initial - y_predicted) ^ 2) / Number of data rows = ((341 - 423) ^ 2) / 442 = ((-82) ^ 2) / 442 = ( 6724) / 442 = ~ 15 мг / дл ошибки. (вы видели, почему мы решили возводить ошибки в квадрат, чтобы получить положительное значение ошибки ..)

Ошибка 15 мг / дл намного лучше, чем 423 мг / дл, но все же может быть улучшена.

Теперь, глядя на y_predicted и error, мы видим, что мы немного перестали предсказывать правильный уровень сахара в крови, поэтому нам нужно постепенно двигаться вниз ... в направлении более низких m и b.

как насчет m = 8 и b = 8, поэтому new y_predicted = (m) (X) + b = (8) (41,3) + 8 = ~ 338 мг / дл. Итак, результат функции ошибки равен f (x) = (y_initial - y_predicted) ^ 2 = ((341 - 338) ^ 2) / 442 = ((-2,6) ^ 2) / 442 = ~ 0,02 мг / дл ошибки.

Совсем неплохо, мы просто достигаем ошибки всего 0,02 мг / дл всего за 3 шага, начиная со случайных значений m и b, а затем узнавая из ошибки, в каком направлении нам нужно двигаться, чтобы минимизировать ошибку. . Это похоже на самообучение.

  • Минимизация ошибок с помощью частных производных, также известных как градиентный спуск
  • Хорошие новости, и именно здесь проявляется сила математики (точнее, исчисления). В приведенном выше примере мы минимизировали ошибки, изменяя вручную более высокие или более низкие значения m и b, выбирая направление, в котором ошибка имеет тенденцию к снижению, и повторяя этот процесс несколько раз, пока ошибка не будет минимизирована. Весь этот процесс можно автоматизировать, используя частные производные (http://mathinsight.org/partial_derivative_introduction).
  • Подождите. Не паникуйте… Я постараюсь простыми словами объяснить, что такое частная производная и как это связано с изменением значений m и b путем выбора направления уменьшения ошибки.
    Частная производная - это ветвь исчисления, Исчисление - это ветвь математики, которая занимается изучением изменений, как геометрия, которая занимается изучением форм и пространства, или как алгебра, которая занимается изучением функций. Частная производная вычисляет скорость изменения функции по отношению к одной переменной за один раз и сохраняет другие переменные постоянными.
  • Вот изображение от MATT NEDRICH, одного из моих любимых блоггеров, который часто пишет о IOS, Swift-разработке и машинном обучении. Следующее изображение представляет градиентный спуск в действии с использованием частных производных и показывает, как мы можем минимизировать ошибки прогнозирования y как продолжительности жизни человека с заданным X как BMI и, конечно же, найти линию наилучшего соответствия во всех строках данных, изменив более высокие или низкие значения m. и значения b

  • В нашем примере функция ошибок f (x) = (y_initial - y_predicted) ², поэтому, используя частную производную от f (x) по отношению к «b» и сохраняя m постоянным, мы можем получить скорость изменения ошибки функцию относительно b, мы можем назвать это «b_gradient», это может быть положительное или отрицательное значение, и его нужно применить к предыдущему значению b, чтобы получить новое значение «b».
    Здесь математическая формула для вычисления b_gradient:

  • и вот код Python для вычисления b_gradient:
  • b_градиент + = - (2 / N) * 1 * (y - ((m_current * x) + b_current))
  • Точно так же, используя частную производную от f (x) = (y_initial - y_predicted) ² относительно m и сохраняя b как постоянное, мы можем получить m_gradient, это может быть положительное или отрицательное значение, и его необходимо применить к предыдущему значению m. , чтобы получить новое значение m.
    Вот математическая формула для вычисления m_gradient:

  • и вот код Python для вычисления m_gradient:
  • m_gradient + = - (2 / N) * x * (y - ((m_current * x) + b_current))
  • Вычисление новых m & b с использованием градиентного спуска с скоростью обучения на многих итерациях

и вот код Python для вычисления new_m и new_b с использованием m_gradient и b_gradient, которые мы вычислили выше:

new_b = b_current - (learningRate * b_gradient)
new_m = m_current - (learningRate * m_gradient)

Теперь мы будем использовать b_gradient и m_gradient, которые могут быть положительными или отрицательными значениями, и мы применим их к предыдущему значению 'b' и 'm', чтобы получить новое значение 'b' и 'm'. . Однако вместо того, чтобы напрямую добавлять b_gradient и m_gradient, мы добавим коэффициент скорости обучения к этим градиентам. Затем мы запустим этот же процесс на многих итерациях, чтобы найти наиболее подходящие b_gradient и m_gradient.

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

#Here is complete step_gradient function
def step_gradient(b_current, m_current, points, learningRate, iteration):
 
 b_gradient = 0
 m_gradient = 0
 N = float(len(points))
 
 for i in range(len(points)):
 x = points[i,0]
 y = points[i,1]
 
 # Partial derivatives calcultion for b_gradient an m_gradient for error funcion f(X)= (y_initial-y_predicted)^2
 b_gradient += - (2/N) * 1 * (y - ((m_current * x) + b_current))
 m_gradient += - (2/N) * x * (y - ((m_current * x) + b_current))
 new_b = b_current - (learningRate * b_gradient)
 new_m = m_current - (learningRate * m_gradient)
 
 print "\n After {0} iterations the new b = b_current - (learningRate * b_gradient) = {1} - ({3} * {2}) = {4}".format(iteration+1, b_current, b_gradient, learningRate, new_b)
 print "After {0} iterations the new m = m_current - (learningRate * m_gradient) = {1} - ({3} * {2}) = {4} \n".format(iteration+1, m_current, m_gradient, learningRate, new_m)
return [new_b, new_m]
#Here is complete Gradient Runner Function that run step gradient over many iterations to come up with # new b and m
def gradient_descent_runner(points, starting_b, starting_m, learning_rate, num_iterations):
 
  b1 = starting_b
  m1 = starting_m
  for i in range(num_iterations):
  b1, m1 = step_gradient(b1, m1, array(points), learning_rate, i)
 
 return [b1, m1]
  • Используйте этот новый m & b, чтобы предсказать уровень сахара в крови по данным образца / теста ИМТ
# now lets use this new b and m to predict some random person expected life expectancy by given BMI
 print "\n Enter BMI to get Blood Sugar\n"
 X_test = 27.6
 print "\n Test/Sample BMI is: {0}\n".format(X_test)
 y_test = m * X_test + b
 print "\n Blood Sugar is {0} \n".format(y_test)

Надеюсь, все это имеет для вас смысл ... Вот наш последний код на GitHub.

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

#simple linear regression using python and numpy, no fancy sklearn, pandas packages needed
# Note we have use only 2 functions from numpy: genfromtxt and array
# import packages
from __future__ import division
from numpy import genfromtxt, array
# we are goning to use Linear equation of type y = mx + b
# where m is slope, and b is y-intercept, a constant
# x is independent varaible aka feature and y is depdendent variable aka target
# The Step Gradient Descent function => use the error/ cost function and then minimize it using partial deriviatives
def step_gradient(b_current, m_current, points, learningRate, iteration):
 
 b_gradient = 0
 m_gradient = 0
 N = float(len(points))
 
 for i in range(len(points)):
 x = points[i,0]
 y = points[i,1]
 # Partial derivatives calcultion for b_gradient an m_gradient for error funcion f(X)= (y_initial-y_predicted)^2
 b_gradient += - (2/N) * 1 * (y - ((m_current * x) + b_current))
 m_gradient += - (2/N) * x * (y - ((m_current * x) + b_current))
# print "At row = {0}, b_gradient = {1}, m_gradient = {2}".format(i, b_gradient, m_gradient)
new_b = b_current - (learningRate * b_gradient)
 new_m = m_current - (learningRate * m_gradient)
 print "\n After {0} iterations the new b = b_current - (learningRate * b_gradient) = {1} - ({3} * {2}) = {4}".format(iteration+1, b_current, b_gradient, learningRate, new_b)
 print "After {0} iterations the new m = m_current - (learningRate * m_gradient) = {1} - ({3} * {2}) = {4} \n".format(iteration+1, m_current, m_gradient, learningRate, new_m)
return [new_b, new_m]
# The Square of Error function
def compute_error_for_line_given_points(b, m, points):
 
 totalError = 0
 error = 0
 
 for i in range(0, len(points)):
 x = points[i,0]
 y = points[i,1]
 # Our Error funcion f(x) = ((y_initial - y_predicted)^2) / Number of data rows
 error = ((y - (m*x + b)) ** 2) / len(points)
 totalError += error / len(points)
 print "At Row {0}, using b = {1} and m = {2}, Error = {3}".format(i, b, m, error)
print "\n Total Error is: {0}".format(totalError)
 return error, totalError
def gradient_descent_runner(points, starting_b, starting_m, learning_rate, num_iterations):
 
 b1 = starting_b
 m1 = starting_m
 for i in range(num_iterations):
 b1, m1 = step_gradient(b1, m1, array(points), learning_rate, i)
 
 return [b1, m1]
def pankax():
#data from data.csv cotaining number of study hours and GPA
 points = genfromtxt("diabetes.csv", delimiter=",")
 
 # choose learning rate
 learning_rate = 0.001
 
 # iniital y-intercept guess aka the constant in linear equation
 initial_b = 1
 
 # iniital slope guess
 initial_m = 1
 
 # choose numbr of iterations to run linear regression
 num_iterations = 100
 
 #print linear regression is working
 print "\n First compute Error for each row by using equation y_predicted = mx +b and error = (y - y_predicted) ^2 by using random b = {0}, and m = {1} \n".format(initial_b, initial_m)
# compute errors
 compute_error_for_line_given_points(initial_b, initial_m,points)
 
 print "\n Now, let's run gradient_descent_runner to get new m and b with learning rate of {1} and {0} iterations \n".format(num_iterations, learning_rate)
 
 [b,m] = gradient_descent_runner(points, initial_b, initial_m, learning_rate, num_iterations)
# compute final error with new b and m calculated from gradient_descent_runner
 
 compute_error_for_line_given_points(b,m,points)
 print "\n After {0}nd iterations final b = {1}, m = {2} \n".format(num_iterations,b,m)
# now lets use this new b and m to predict some random person expected life expectancy by given BMI
 
 print "\n Enter BMI to get Blood Sugar\n"
 X_test = 27.6
 
 print "\n Test/Sample BMI is: {0}\n".format(X_test)
 y_test = m * X_test + b
 
 print "\n Blood Sugar is {0} \n".format(y_test)
# as usual start with main function and put it in the end of the code
 if __name__ == '__main__':
  pankax()

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

Пожалуйста, дайте мне знать ваши отзывы, мысли, вопросы в разделе комментариев.