Почему значения моего массива не обновляются?Линейная регрессия - PullRequest
3 голосов
/ 29 сентября 2019

Мне нужно сделать модель линейной регрессии в Python без использования Scikit.Вы можете игнорировать часть, связанную с вводом, так как эта часть соответствует предоставленному мной файлу.Я добавил весь код на случай, если что-то сделал не так.

import pandas as pd
import numpy as np
import matplotlib.pyplot as mlt
from sklearn.cross_validation import train_test_split 
data = pd.read_csv("housing.csv", delimiter = ' ', skipinitialspace = True, names = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV'])
df_x = data.drop('MEDV', axis = 1)
df_y = data['MEDV']
x_train, x_test, y_train, y_test = train_test_split(df_x.values, df_y.values, test_size = 0.2, random_state = 4)
theta = np.zeros((1, 13))

В приведенном выше коде я только что взял ввод и создал массив параметров с именем theta.

def costfn(x, y, theta):
    j = np.sum(x.dot(theta.T) - y) ** 2 / (2 * len(y))
    return j


def gradient(x, y, theta, alpha, iterations):
    cost_history = [0] * iterations

    for i in range(iterations):
        h = theta.dot(x.T) #hypothesis
        loss = h - y
        #print(loss)
        g = loss.dot(x) / len(y)
        #print(g)
        theta = theta - alpha * g
        cost_history[i] = costfn(x, y, theta)
    #print(theta)
    return theta, cost_history

theta, cost_history = gradient(x_train, y_train, theta, 0.001, 1000)
#print(theta) 

Все прокомментированные строки дают вывод в виде nan соответствующего размера.

Я использовал логику, аналогичную логике в этом блоге Скажите мне, если я ошибаюсь.

1 Ответ

0 голосов
/ 29 сентября 2019

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

Вы можете проверить это, используя простую настройку:

# output theta in your function
def gradient(x, y, theta, alpha, iterations):
    cost_history = [0] * iterations

    for i in range(iterations):
        h = theta.dot(x.T) #hypothesis
        #print('h:', h)
        loss = h - y
        #print('loss:', loss)
        g = loss.dot(x) / len(y)
        #print('g:', g)
        theta = theta - alpha * g
        print('theta:', theta)
        cost_history[i] = costfn(x, y, theta)
    #print(theta)
    return theta, cost_history

# set up example data with a simple linear relationship
# where we can play around with different numbers of parameters
# conveniently
# with some noise
num_params= 2   # how many params do you want to estimate (up to 5)
# take some fixed params (we only take num_params of them)
real_params= [2.3, -0.1, 8.5, -1.8, 3.2]

# now generate the data for the number of parameters chosen
x_train= np.random.randint(-100, 100, size=(80, num_params))
x_noise= np.random.randint(-100, 100, size=(80, num_params)) * 0.001
y_train= (x_train + x_noise).dot(np.array(real_params[:num_params]))
theta= np.zeros(num_params)

Теперь попробуйте с высокой скоростью обучения

theta, cost_history = gradient(x_train, y_train, theta, 0.1, 1000)

Скорее всего, вызаметим, что показатели ваших тэта-значений будут становиться все выше и выше, пока они, наконец, не достигнут inf или -inf.После этого вы получите NaN значения.

Если вы установите его на низкое значение, например 0,00001, вы увидите, что оно сходится:

theta: [ 0.07734451 -0.00357339]
theta: [ 0.15208803 -0.007018  ]
theta: [ 0.22431803 -0.01033852]
theta: [ 0.29411905 -0.01353942]
theta: [ 0.36157275 -0.01662507]
theta: [ 0.42675808 -0.01959962]
theta: [ 0.48975132 -0.02246712]
theta: [ 0.55062617 -0.02523144]
...
theta: [ 2.29993382 -0.09981407]
theta: [ 2.29993382 -0.09981407]
theta: [ 2.29993382 -0.09981407]
theta: [ 2.29993382 -0.09981407]

Что очень близко к реальномупараметры 2.3 и -0.1.

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

Например, вы можете использовать следующую модификацию вашей функции:

def gradient(
        x, 
        y, 
        theta=None, 
        alpha=0.1, 
        alpha_factor=0.1 ** (1/5), 
        change_threshold=1e-10, 
        max_iterations=500, 
        verbose=False):
    cost_history = list()
    if theta is None:
        # theta was not passed explicitely
        # so initialize it
        theta= np.zeros(x.shape[1])
    last_loss_sum= float('inf')
    len_y= len(y)
    for i in range(1, max_iterations+1):
        h = theta.dot(x.T) #hypothesis
        loss = h - y
        loss_sum= np.sum(np.abs(loss))
        if last_loss_sum <= loss_sum:
            # the loss didn't decrease
            # so decrease alpha
            alpha= alpha * alpha_factor
        if verbose:
            print(f'pass: {i:4d} loss: {loss_sum:.8f} / alpha: {alpha}')
        theta_old= theta
        g= loss.dot(x) / len_y
        if loss_sum <= last_loss_sum and last_loss_sum < float('inf'):
            # only apply the change if the loss is
            # finite to avoid infinite entries in theta
            theta = theta - alpha * g
            theta_change= np.sum(np.abs(theta_old - theta))
            if theta_change < change_threshold:
                # Maybe this seems a bit awkward, but
                # the comparison of change_threshold
                # takes the relationship between theta and g
                # into account. Note that g will not have
                # an effect if theta is orders of magnitude
                # larger than g, even if g itself is large.
                # (I mean if you consider g and theta elementwise)
                cost_history.append(costfn(x, y, theta))
                break
        cost_history.append(costfn(x, y, theta))
        last_loss_sum= loss_sum
    return theta, cost_history

Изменения адреса ранней остановки, автоматической настройки alpha и кодирования theta для получения бесконечных значений.Вам нужно только передать X и y в минимальном случае, все остальные параметры имеют значения по умолчанию.Установите verbose=True, если хотите увидеть, как убыток уменьшается в каждом итераторе.

...