在回归问题中,我们得到一组具有输入特征和输出值的数据点。我们的工作是构建一个数学模型,可以准确地预测输入特征的输出值。在数学上,这意味着构造一个函数
F (xi,1, xi,2,…,xi,n)
它可以预测数据集中每个点的输出值yi。我们的目标是构建一个模型函数,使预测的平方和误差最小化:
在线性回归中,我们将自己限制为输入特征的线性函数的模型函数。
f(ξ1,ξ2,…,xi, n) =β0 +β1,1 +β2,2 +⋯+βn, n
这也可以写成
f(ξ1,ξ2,…,xi, n) =β0 1 +β1,1 +β2,2 +⋯+βn, n
= β·Xi
其中Xi是数据点i的原始输入特征列表,加上一个偏置项x0 = 1。
如果我们的目标是构建一个线性函数,使一组数据点的平方和误差最小化,那么实际上可以通过常规方程求解最佳的β值集:
β = (x x)-1 (y x)
这里X是一个矩阵,它的行是输入向量Xi,它被补充了一个偏置项,Y是数据集的Y值的向量。
在下面的讲义中,我将为上节课中介绍的循环数据集构建一个线性回归模型。
第一步是重复我们在上一讲中介绍的数据清理和准备步骤。
进口熊猫一样pd进口numpy np df = pd.read_csv (rides.csv) df(“dir”)= df(“dir”).fillna(值= 184)df [s] = df(“风”)* np.cos (((df(“dir”)-180)/ 180)* np.pi) df (' w ') = df(“风”)* np.cos (((df(“dir”)-270)/ 180)* np.pi) df['年']= df(-2016 '年']df = df.drop((“风”、“dir”),轴= 1).dropna ()
接下来,我们需要为偏置项添加一列。要创建一个包含1的列,我们使用numpy ones()函数,该函数将生成一个由所需长度的1填充的数组。
Df ['bias'] = np.ones(len(Df))
为了准备模型构建和评估,我们接下来必须将数据集分成训练集和测试集。我们将使用训练数据来构建回归模型,然后使用测试集计算误差。下面的代码将52个元素的原始数据集拆分为11个随机选择的测试项和其余41个训练项的测试集。为了随机化数据帧,我使用pandas sample()方法,该方法可以返回数据帧中指定部分行的随机样本。我们将分数设置为1,这有效地打乱了整个数据帧的行。
Df = Df .sample(frac=1) test = Df .iloc[0:11].copy() train = Df .iloc[11:20].copy()
为了将前11行复制到测试数据帧中,我们使用pandas iloc[]方法,该方法用于根据数据帧的整数位置索引选择行。
为了建立正常方程,我们将训练集分成输入特征列和输出值列。pandas数据帧的values属性返回一个numpy数组,其中包含我们想要操作的数据。
X = train.drop(columns=['speed']).values Y = train['speed'].values
为了求解正规方程,我们使用numpy线性代数函数。对于这个例子,我将使用numpy dot()和转置()函数的对象形式:
np.dot (A, B)
变成了
A.dot (B)
和
np.transpose (X)
变成了
X.T
这使得我们可以更简洁地写出标准方程:
1 = np.linalg.inv(X.T.dot(X)) 2 = X.T.dot(Y) beta = one.dot(2)
我们现在可以在测试数据上评估模型并计算测试数据的mse。
testX = test.drop(columns=['speed'])。values testY = test['speed']。values preds = testX.dot(beta.T) errors = testY - preds sse = (errors * errors).sum()/len(errors) mse = np.sqrt(sse) print(mse)
上述过程的一个问题是,我们计算的MSE依赖于测试集和训练集的选择。您可以观察到,如果多次运行上面的程序,MSE值将会有很大的不同,因为sample()方法给了我们不同的训练/测试分割。
获得更可靠的MSE估计的一种方法是使用一种称为交叉验证的策略。以下是该策略的概要。
修改上面的程序以进行交叉验证,而不是单个训练/测试分离。让您的程序打印五轮中每一轮的MSE值以及MSE值的最终平均值。
这里有一些建议可以帮助你。由于原始数据集包含52个条目,您可能会在将其划分为片时遇到一些麻烦。当数据集不能被5整除时,创建切片的一种简单方法是使用numpy linspace()函数。给定起始值、结束值和整数N, linspace()返回一个数字列表,这些数字将原始范围划分为N个大致相等的子范围。
您将遇到的另一个问题是将四个片重新组装成一个数组。要做到这一点,你应该使用numpy array append()方法,它可以将两个数组组合成一个更大的数组:
Xcombined = X1.append(X2)
为了方便起见,这里有一个包含今天的程序和CSV文件的存档。
我们的线性回归模型产生的结果有些平淡无奇。这是由于两个主要因素。首先,这个例子中的数据非常嘈杂。你可以很容易地找到一些数据点的例子,这些数据点的特征是相似的,但结果(骑行的平均速度)却大不相同。这是因为我们的模型数据并没有捕捉到对结果有影响的每一个因素,比如我在骑行当天有多累,或者我决定在某个特定的骑行中有多激进。
第二个因素是,结果可能不是某些特征的线性函数。这里有两组特征是相关的:温度和风速。温度对骑行速度的影响是,随着温度的升高,速度通常会上升,但一旦温度超过某一点(可能在华氏70度左右),温度的升高很可能导致速度的降低。风速也具有明显的非线性效应:由于风速可以是正的,也可以是负的,并且绝对值较大的风速更能降低车速,因此风速与结果之间存在非线性关系。
当我们怀疑某些因素和结果之间可能存在非线性关系时,我们可以用多项式回归代替线性回归。在这种技术中,我们引入新的因子,这些因子是一些原始因子的多项式函数,然后对扩展的特征集进行线性回归。
例如,假设我们想在模型中更有效地模拟风速的影响。目前,该模型有两个提供风速信息的因素,即数据框中的“s”和“w”列。在原来的线性模型中,这两个因素在线性回归模型中看起来是这样的
βs xs + βw xw
在多项式回归模型中,我们可以用
βs xs + βs2 (xs)2 + βsw (xs xw) + βw2 (xw)2 + βw xw
为了在代码中实现这一变化,我们只需在流程开始时向数据框架添加三个新列:
df [' s2 '] = df [s] * * 2 df(“软件”)= df [s] * df [' w '] df (w2的)= df [' w '] * * 2
然后继续进行线性回归的其余步骤。
不幸的是,这没有帮助。问题是,我们会遇到另一个问题,叫做过拟合。在我们努力使我们的模型更准确的过程中,它在训练集上变得更准确。不幸的是,如果我们将更精确的模型赢博体育于测试集,它的表现就会更差。过度拟合的通常解决方法是在问题中添加更多的数据。不幸的是,在这个例子中,我们的数据集固定为52个观测值。直到我走出去,在同一条路线上再骑几年自行车,我们才会有足够的数据来克服这个问题。