Я взял программу на Python, которая применяет градиентный спуск к линейной регрессии, и преобразовал ее в Ruby. Но сначала подведем итоги: мы используем линейную регрессию для численного прогнозирования.
Если x является входной (независимой) переменной, а y является выходной (зависимой) переменной, мы приходим к исходной формуле (уравнению), которая показывает математическое соотношение между ними.
Затем мы берем каждое значение x и вычисляем значение y, используя наше исходное уравнение. Разница между вычисленным значением y и фактическим значением y, соответствующим значению x, является ошибкой. Значения ошибок суммируются с помощью которого мы приходим к другому уравнению. Мы минимизируем это уравнение, используя алгоритм градиентного спуска, чтобы мы получили уравнение наилучшего соответствия.
Когда я искал в Интернете эту тему, я наткнулся на эту страницу « Введение в градиентный спуск и линейную регрессию » Мэтта Недрича, на которой он представляет пример Python. Программа находит наиболее подходящую линию для заданного набора данных значений x и y. Хороший улов для меня. Для практики я взял программу Мэтта и переписал ее на Ruby.
Мне понравилась статья в блоге Мэтта, поэтому я даю ее часть ниже, но с моими фрагментами Ruby.
Чтобы вычислить ошибку для данной линии, мы проведем итерацию по каждой точке (x, y) в нашем наборе данных и суммируем квадратные расстояния между значением y каждой точки и значением y линии-кандидата (вычисленным в mx + b).
Формально эта функция ошибок будет выглядеть так:
0.upto points.length-1 do |i|
x = points[i][0]
y = points[i][1]
totalError += (y - (m * x + b)) ** 2
end
return totalError / points.length
Когда мы запустим поиск градиентного спуска, мы начнем с некоторого места на этой поверхности и двинемся вниз, чтобы найти линию с наименьшей ошибкой. Чтобы запустить градиентный спуск для этой функции ошибки, нам сначала нужно вычислить ее градиент. Градиент будет действовать как компас и всегда будет направлять нас вниз.
Чтобы вычислить его, нам нужно будет дифференцировать нашу функцию ошибок. Поскольку наша функция определяется двумя параметрами (m и b), нам потребуется вычислить частную производную для каждого из них. Производные работают так:
0.upto points.length-1 do |i|
x = points[i][0]
y = points[i][1]
m_gradient += -(2/n) * x * (y - ((m_current * x) + b_current))
b_gradient += -(2/n) * (y - ((m_current * x) + b_current))
end
new_m = m_current - (learningRate * m_gradient)
new_b = b_current - (learningRate * b_gradient)
Наконец, мы подошли к полной программе:
require 'csv'
# y = mx + b
# m is slope, b is y-intercept
def compute_error_for_line_given_points(b, m, points)
totalError = 0
0.upto points.length-1 do |i|
x = points[i][0]
y = points[i][1]
totalError += (y - (m * x + b)) ** 2
end
return totalError / points.length
end
def step_gradient(b_current, m_current, points, learningRate)
b_gradient = 0
m_gradient = 0
n = points.length + 0.0
0.upto points.length-1 do |i|
x = points[i][0]
y = points[i][1]
m_gradient += -(2/n) * x * (y - ((m_current * x) + b_current))
b_gradient += -(2/n) * (y - ((m_current * x) + b_current))
end
new_m = m_current - (learningRate * m_gradient)
new_b = b_current - (learningRate * b_gradient)
return [new_b, new_m]
end
def gradient_descent_runner(points, starting_b, starting_m, learning_rate, num_iterations)
b = starting_b
m = starting_m
0.upto num_iterations-1 do |i|
b, m = step_gradient(b, m, points, learning_rate)
end
return [b, m]
end
def run()
points = CSV.read('data.csv', converters: :numeric)
learning_rate = 0.0001
initial_b = 0 # initial y-intercept guess
initial_m = 0 # initial slope guess
num_iterations = 1000
puts "Starting gradient descent at b = #{initial_b}, m = #{initial_m}, error = #{compute_error_for_line_given_points(initial_b, initial_m, points)}"
puts "Running..."
(b, m) = gradient_descent_runner(points, initial_b, initial_m, learning_rate, num_iterations)
puts "After #{num_iterations} iterations b = #{b}, m = #{m}, error = #{compute_error_for_line_given_points(b, m, points)}"
end
run()
Файл «data.cv», необходимый для запуска этой программы, доступен по этой ссылке .