【问题标题】:Why are my array values not getting updated? Linear regression为什么我的数组值没有更新?线性回归
【发布时间】:2020-01-28 20:23:55
【问题描述】:

我需要在不使用 scikit 的情况下在 python 中制作线性回归模型。 您可以忽略涉及输入的部分,因为该部分是根据给我的文件。我已经添加了我的整个代码,以防我做错了什么。

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 输出。

我使用了类似于 on this blog 的逻辑 如果我错了,请告诉我。

【问题讨论】:

    标签: python pandas numpy machine-learning linear-regression


    【解决方案1】:

    我认为您的代码总体上是有效的。您观察到的很可能与您的 alpha 设置有关。它似乎太高了,所以theta发散了。在某个时候,它会得到inf-inf,然后在下一次迭代中得到NaNs。我认识到了同样的问题。

    您可以使用简单的设置来验证:

    # 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)
    

    您很可能会观察到,您的 theta 值的指数会越来越高,直到最终达到 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 采用无限值。您只需要在最小情况下传递Xy,所有其他参数都获得默认值。设置verbose=True如果你想看看,损失在每个迭代中是如何减少的。

    【讨论】:

    • 感谢您的回复。我不太确定我是否完全理解您的代码。但我没有得到我需要的输出。事实上,它即将到来。
    • 通过减少迭代次数(在我发布的代码 sn-p 上),我注意到每次迭代后损失都在增加,这不应该发生对吗?
    • 我正在使用波士顿住房数据集,如果有用的话。
    • 是的,你是对的,损失是分散的。那是因为alpha 太高,因此theta 的每次更改都会超出最佳值。因此,如果您喜欢那张照片,您的零钱就会沿着最深点的“损失谷”向下走,然后爬上另一边,最终落在比开始时更高的地方。您的结果位于theta。这就是函数学习的内容。但是theta 不是预测值,而是您获得预测的值。你知道的,对吧?
    • 顺便说一句,“它即将到来”是什么意思?我真的建议您尝试我添加的代码来试验您的功能。如果您了解它对不同参数的反应以及如何从评估的theta 中获取预测,您还将知道如何将其应用于更复杂的场景,例如波士顿住房示例,它会为您提供更多帮助,就好像您只需接管现有代码(否则您可能只是从 scikit learn 中获取线性模型)。
    猜你喜欢
    • 2012-04-09
    • 2020-02-05
    • 1970-01-01
    • 1970-01-01
    • 2016-02-24
    • 2020-10-27
    • 2021-08-01
    • 1970-01-01
    • 2015-03-21
    相关资源
    最近更新 更多