无法使线性回归收敛,尝试模拟scikitlearn的LinearRegression

为了更好地理解数据科学中的线性回归主题,我一直在尝试重现scikitlearn的LinearRegression模块的内部工作原理。我遇到的问题是,当我使用我的数据开始对斜率和截距进行梯度下降时,无论我使用什么步长或下降迭代次数,斜率和截距的值都无法收敛。我试图寻找线性关系的数据是NBA的投篮命中率和胜率百分比,可以在这里找到(数据只有大约250行,但我认为在pastebin上分享会更容易…)。您可以通过以下方式重新创建数据的初始图表:

import pandas as pdimport matplotlib.pyplot as pltfrom sklearn.linear_model import LinearRegressiondef graph1(axis = []):    x = FG_pct    y = W_L_pct    plt.scatter(x, y)    plt.title('NBA FG% vs. Win%')    plt.xlabel('FG pct (%)')    plt.ylabel('Win pct (%)')    if len(axis) > 1:        plt.axis(axis)    plt.legend()

它看起来会像这样(没有颜色):

enter image description here

这两个变量之间存在非常明显的关系,您基本上可以很好地猜测最佳拟合线会是什么(我的猜测是斜率为5,截距约为-1.75)。

我使用的梯度下降方程,通过对损失函数关于斜率和截距的导数得出,是这样的:

def get_b_gradient(x_pts, y_pts, m, b):    N = len(x_pts)    tot = 0    for x, y in zip(x_pts, y_pts):        tot += y - (m*x + b)    gradient = (-2/N)*tot    return gradientdef get_m_gradient(x_pts, y_pts, m, b):    N = len(x_pts)    tot = 0    for x, y in zip(x_pts, y_pts):        tot += x * (y - (m*x + b))    gradient = (-2/N)*tot    return gradientdef get_step(x_pts, y_pts, m, b, learning_rate):    init_b = get_b_gradient(x_pts, y_pts, m, b)    init_m = get_m_gradient(x_pts, y_pts, m, b)    final_b = b - (init_b*learning_rate)    final_m = m - (init_m*learning_rate)    return final_m, final_bdef gradient_descent(x_pts, y_pts, m, b, learning_rate, num_iterations):    for i in range(num_iterations):        m, b = get_step(x_pts, y_pts, m, b, learning_rate)    return m, b

获得这些后,关键在于找到正确的迭代次数和学习率,使斜率和截距收敛到最优值。由于我不确定如何系统地找到这些值,我只是尝试在gradient_descent函数中输入不同的数量级:

# 1000次迭代,学习率为0.1,初始斜率和截距猜测为0m, b = gradient_descent(df['FG%'], df['W/L%'], 0, 0, 0.1, 1000)

您可以使用这样的图表来跟踪斜率和截距的收敛情况:

def convergence_graph(iterations, learning_rate, m, b):    plt.subplot(1, 2, 1)    for i in range(iterations):        plt.scatter(i,b, color='orange')        plt.title('convergence of b')        m, b = get_step(df['FG%'], df['W/L%'], m, b, learning_rate)    plt.subplot(1, 2, 2)    for i in range(iterations):        plt.scatter(i,m, color='blue')        plt.title('convergence of m')        m, b = get_step(df['FG%'], df['W/L%'], m, b, learning_rate)

这正是问题明显的地方。使用与之前相同的迭代次数(1000)和学习率(0.1),您会看到这样的图表:

enter image description here

我认为这些图表的线性意味着它在那个点上仍在收敛,所以答案是增加学习率,但无论我为学习率选择什么数量级(一直到数百万),图表仍然保持线性,永远不会收敛。我也尝试使用较小的学习率并调整迭代次数…没有任何效果。最终我决定将其放入sklearn,看看它是否会遇到任何问题:

FG_pct = np.array(FG_pct)FG_pct = FG_pct.reshape(-1, 1)line_fitter = LinearRegression().fit(FG_pct, W_L_pct)win_loss_predict = line_fitter.predict(FG_pct)

它没有任何问题:

enter image description here

这篇文章已经很长了,很抱歉。我没有直接可以询问的数据科学人员,也没有教授在周围,所以我想我会把它放在这儿。最终,我不确定问题是出在1)我的梯度下降方程上,还是2)我在寻找适当的学习率和迭代次数的方法上。如果有人能指出发生了什么,为什么斜率和截距没有收敛,以及我做错了什么,那将非常感激!


回答:

我建议您从数据科学材料呈现这些主题的方式上退后一步。线性回归,梯度下降。这些不是数据科学的主题。这些是统计学概念。我建议您开始查找入门统计学材料。您拿到的任何材料几乎都会有一章关于普通线性回归(OLS)。

梯度下降是牛顿法寻找零点的一个更复杂的版本。我强烈建议您研究那个算法。如果您对微积分有很好的理解,这听起来您可能已经有了,那么它非常容易理解。如果您确实研究了它,请注意其中没有“学习率”。这个词让我感到恶心。在“数据科学”之前的日子,也就是大约10年前,它被称为步长。

步长对收敛速度至关重要。但是如果步长太大,您很可能永远不会收敛。假设您的步长是10,而您的导数(单变量情况)是0.1。您的猜测移动了1。但如果最小值距离当前猜测只有0.25单位呢?恭喜。您的解决方案刚刚变得更糟。您可以整天在最小值周围跳来跳去,永远找不到它(我怀疑这可能是您的代码中发生的情况)。许多算法使用的是递减的步长。通常与迭代次数成比例。例如,在第j次迭代中,您的步长可能是10/j。这也有一些问题,可以通过稳定值和对步长形状的额外边界来解决,随着迭代的演进。

您正在尝试做的事情实际上非常棒。有太多人在“做数据科学”,但他们对实际发生的事情一无所知。缺点是这条路并不容易走。我鼓励您继续前进!!这是值得的。但您需要认识到,您有点跳进了深水区。有更简单的算法,您可以从中获得更多,并为以后的更高级内容奠定基础。

编辑:更直接的回答

所以,您代码中唯一需要更改的是梯度。在两个梯度计算中,将

gradient = (-2/N)*tot

改为

gradient = (-2)*tot

梯度在分母中没有N。一些推导可能会以这种方式显示,但那可能是因为它们是在推导闭合形式的解,并且已经将整个东西设为零。

看起来您的参数之所以会变得疯狂,是因为您的步长太大。使用那个更改后,它返回的参数是:

m, b = gradient_descent(FG_pct, W_L_pct, 6, -1, 0.003, 10000)m = 6.465b = -2.44

我认为在您的例子中,您使用初始猜测0, 0来启动算法。一个好的初始猜测可以产生巨大的差异。

闭合形式的替代方案这里是一个使用闭合形式的例子。它在没有搜索的情况下产生精确的答案。

from matplotlib.pyplot import plot, scatterimport numpy as npY = np.array(W_L_pct)X = np.array([np.ones(len(FG_pct)), FG_pct]).reshape(2, 270).TA = np.linalg.inv(np.matmul(X.T, X))B = np.matmul(X.T, Y)beta = np.matmul(A, B)m, b = beta[1], beta[0]print(m, b)r = np.arange(0.4, 0.52, 0.01)scatter(FG_pct, Y)plot(r, m * r + b)

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

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