为什么我的数组值没有更新?线性回归

我需要在Python中创建一个线性回归模型,但不使用scikit。你可以忽略输入部分,因为那部分是根据我提供的文件来的。我已经添加了我的完整代码,以防我犯了什么错误。

import pandas as pdimport numpy as npimport matplotlib.pyplot as mltfrom 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 jdef 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_historytheta, cost_history = gradient(x_train, y_train, theta, 0.001, 1000)#print(theta) 

我注释掉的所有行输出都是适当大小的nan值。

我使用了类似于这个博客上的逻辑。如果我错了,请告诉我。


回答:

总的来说,我认为你的代码是工作的。你观察到的情况很可能是由于alpha的设置过高,导致theta发散。在某个点上它会变成inf-inf,之后在下一次迭代中你会得到NaN值。我也遇到了同样的问题。

你可以通过一个简单的设置来验证这一点:

# 在你的函数中输出theta 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# 使用一个简单的线性关系设置示例数据# 我们可以用不同的参数数量进行试验# 方便起见,加入一些噪声num_params= 2   # 你想要估计的参数数量(最多5个)# 取一些固定的参数(我们只取num_params个)real_params= [2.3, -0.1, 8.5, -1.8, 3.2]# 现在为选择的参数数量生成数据x_train= np.random.randint(-100, 100, size=(80, num_params))x_noise= np.random.randint(-100, 100, size=(80, num_params)) * 0.001y_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没有明确传递        # 所以初始化它        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:            # 误差没有减少            # 所以减小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'):            # 只有当误差是有限的才应用变化            # 避免theta中出现无限值            theta = theta - alpha * g            theta_change= np.sum(np.abs(theta_old - theta))            if theta_change < change_threshold:                # 这可能看起来有点奇怪,但                # change_threshold的比较                # 考虑了theta和g之间的关系。请注意,如果theta比g大几个数量级,                # 即使g本身很大,g也不会有影响。                # (我是指逐元素考虑g和theta)                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

Related Posts

神经网络反向传播代码不工作

我需要编写一个简单的由1个输出节点、1个包含3个节点的…

值错误:y 包含先前未见过的标签:

我使用了 决策树分类器,我想将我的 输入 作为 字符串…

使用不平衡数据集进行特征选择时遇到的问题

我正在使用不平衡数据集(54:38:7%)进行特征选择…

广义随机森林/因果森林在Python上的应用

我在寻找Python上的广义随机森林/因果森林算法,但…

如何用PyTorch仅用标量损失来训练神经网络?

假设我们有一个神经网络,我们希望它能根据输入预测三个值…

什么是RNN中间隐藏状态的良好用途?

我已经以三种不同的方式使用了RNN/LSTM: 多对多…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注