Линейная регрессия машинного обучения (реализация на чистом Python)

машинное обучение искусственный интеллект

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

Линейная регрессия

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

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

image.png

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

image.png

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

image.png

i выше представляет i-е данные. Как правило, убыток усредняется как окончательный убыток.

Свести к минимуму ошибку

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

Наименьших квадратов

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

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

image.png
image.png
Найдите m и b, чтобы получить искомую прямую.

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

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

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

инициализация:

def init_data():
    data = np.loadtxt('data.csv', delimiter=',')
    return data

def linear_regression():
    learning_rate = 0.01 #步长
    initial_b = 0
    initial_m = 0
    num_iter = 1000 #迭代次数

    data = init_data()
    [b, m] = optimizer(data, initial_b, initial_m, learning_rate, num_iter)
    plot_data(data,b,m)
    print(b, m)
    return b, m

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

def optimizer(data, initial_b, initial_m, learning_rate, num_iter):
    b = initial_b
    m = initial_m

    for i in range(num_iter):
        b, m = compute_gradient(b, m, data, learning_rate)
        # after = computer_error(b, m, data)
        if i % 100 == 0:
            print(i, computer_error(b, m, data)) # 损失函数,即误差
    return [b, m]

Градиент рассчитывается для каждой итерации для обновления параметров:

def compute_gradient(b_cur, m_cur, data, learning_rate):
    b_gradient = 0
    m_gradient = 0

    N = float(len(data))
    #
    # 偏导数, 梯度
    for i in range(0, len(data)):
        x = data[i, 0]
        y = data[i, 1]

        b_gradient += -(2 / N) * (y - ((m_cur * x) + b_cur))
        m_gradient += -(2 / N) * x * (y - ((m_cur * x) + b_cur)) #偏导数

    new_b = b_cur - (learning_rate * b_gradient)
    new_m = m_cur - (learning_rate * m_gradient)
    return [new_b, new_m]

Расчет стоимости убытка:

def computer_error(b, m, data):
    totalError = 0
    x = data[:, 0]
    y = data[:, 1]
    totalError = (y - m * x - b) ** 2
    totalError = np.sum(totalError, axis=0)
    return totalError / len(data)

Выполнить результат вычисления функции:

if __name__ == '__main__':
    linear_regression()

Результат операции следующий:

0 3.26543633854
100 1.41872132865
200 1.36529867423
300 1.34376973304
400 1.33509372632
500 1.33159735872
600 1.330188348
700 1.32962052693
800 1.32939169917
900 1.32929948325
1.23930380135 1.86724196887

Видно, что с увеличением количества итераций функция Loss все ближе и ближе к минимальному значению, а m и b также все ближе и ближе к оптимальному решению.

Уведомление:

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

def optimizer_two(data, initial_b, initial_m, learning_rate, num_iter):
    b = initial_b
    m = initial_m

    while True:
        before = computer_error(b, m, data)
        b, m = compute_gradient(b, m, data, learning_rate)
        after = computer_error(b, m, data)
        if abs(after - before) < 0.0000001:  #不断减小精度
            break
    return [b, m]

def compute_gradient_two(b_cur, m_cur, data, learning_rate):
    b_gradient = 0
    m_gradient = 0

    N = float(len(data))

    delta = 0.0000001

    for i in range(len(data)):
        x = data[i, 0]
        y = data[i, 1]
        # 利用导数的定义来计算梯度
        b_gradient = (error(x, y, b_cur + delta, m_cur) - error(x, y, b_cur - delta, m_cur)) / (2*delta)
        m_gradient = (error(x, y, b_cur, m_cur + delta) - error(x, y, b_cur, m_cur - delta)) / (2*delta)

    b_gradient = b_gradient / N
    m_gradient = m_gradient / N
    #
    new_b = b_cur - (learning_rate * b_gradient)
    new_m = m_cur - (learning_rate * m_gradient)
    return [new_b, new_m]


def error(x, y, b, m):
    return (y - (m * x) - b) ** 2

В приведенных выше двух случаях количество итераций достаточно для аппроксимации оптимального решения. Полученные оптимальные решения соответственно таковы: 1: 1,23930380135 1,86724196887 2: 1,24291450769 1,86676417482

простое сравнение

В sklearn есть соответствующий метод для поиска линейной регрессии, который напрямую использует метод наименьших квадратов для поиска оптимального решения. Простая реализация для сравнения.

def scikit_learn():
    data = init_data()
    y = data[:, 1]
    x = data[:, 0]
    x = (x.reshape(-1, 1))
    linreg = LinearRegression()
    linreg.fit(x, y)
    print(linreg.coef_)
    print(linreg.intercept_)

if __name__ == '__main__':
    # linear_regression()
    scikit_learn()

Решение на данный момент такое: 1,24977978176 1,86585571. Можно показать, что приведенные выше результаты расчетов являются удовлетворительными, а лучшие результаты могут быть достигнуты путем последующей настройки параметров.

Исходный код и ссылка на данные:GitHub.com/Облачные водные билеты…

Спасибо и обратитесь к сообщению в блоге:Понимание линейной регрессии (с реализацией на чистом Python)
Градиентный спуск Градиентный спуск
Резюме градиентного спуска