在实际项目中,在读取多维特征之前,需要先对数据进行缩放处理。为什么呢?
因为当引入多维特征和多变量梯度下降法时,为了使算法更快收敛,必须对所选特征进行尺度缩放,即将多个特征的值调整至相近的范围内,通常是在 [-1, 1] 之间。
例如:
在未进行特征缩放前,两个参数的梯度下降等高线图呈现为竖椭圆形,这是因为横轴和纵轴参数范围不同,导致算法在寻找最小值时需要进行多次迭代。
而在缩放后,横纵轴范围接近一致,等高线图基本呈现为圆形,算法在迭代时能更快找到最小值,从而显著减少迭代次数。
缩放的最终结果不必严格限定在 [-1, 1] 范围内,比如 [-3, 3] 或 [-2, 1] 也可以接受。一个常用的简单缩放方法是:
其中 是平均值, 是(max - min)。例如,可以用此公式对房屋面积和卧室数量进行缩放: - 房屋面积:1000 是面积平均值,2000 是最大面积减最小面积。 - 卧室数量:2 是卧室数量平均值,5 是最大卧室数量减去最小卧室数量。
掌握特征缩放后,我们来看看实际的特征缩放代码:
```python
def normalize_feature(df): return df.apply(lambda column: (column - column.mean()) / column.std()) ```
接下来,我们将使用上述函数对包含两个特征的原始房价数据进行缩放:
```python
rawdata = pd.readcsv('ex1data2.txt', names=['square', 'bedrooms', 'price'])
raw_data.head()
data = normalizefeature(rawdata)
data.head() ```
从缩放后的数据可以看出,其数值范围大多集中在 [-1, 1] 附近,说明特征缩放已经成功。
还记得上一篇文章介绍的第一个机器学习算法吗?
即通过房屋面积来预测价格。现实生活中,多数问题都涉及多个特征,因为使用多个特征训练出的模型通常更准确。
那么,机器学习算法如何处理多个特征的输入呢?
我们仍然以房价预测为例,这次增加三个新特征:卧室数量、房屋楼层和房屋年龄。
这样,我们就有四个输入特征了。随着特征数量的增加,表示方法也需要升级:
随着特征数量的增加,之前的假设函数需要进行调整,以包含新增的特征变量和参数:
尽管这种表示方法可行,但不太适合使用向量进行计算,因为参数 有 n + 1 个,而 只有 n 个。解决办法是额外添加一个 ,使上式变为:
这样就可以通过向量相乘来实现:
为什么要用向量形式表示呢?主要有两个原因:
通过添加一个维度 ,最终训练集的特征矩阵大小为 ,其中 m 为行数,n + 1 为列数。
接下来,我们看看如何读取多维数据并添加一列全 1 向量:
```python
def get_X(df): ones = pd.DataFrame({'ones': np.ones(len(df))}) data = pd.concat([ones, df], axis=1) return data.iloc[:, :-1].values ```
假设原始房价数据只有两个输入特征:房屋面积和卧室数量。我们可以用以下函数读取数据特征到向量 X:
```python
X = get_X(data)
print(X.shape, type(X)) print(X) ```
输入结果如下:
(47, 3)
可以看到特征矩阵的第一列全是 1,后两列保持不变(数据转换为科学计数法表示),这与我们对多维特征的操作结果一致。
读取多维特征后,我们可以将特征矩阵 X 的每一行作为一个特征向量,并用它们来训练机器学习算法。
读取多维特征后,我们可以学习多变量梯度下降法。其实,这与单变量梯度下降原理相同,只是增加了特征变量和相应的参数。
例如,线性回归的多变量假设函数、代价函数和梯度下降法如下:
由于参数增加到 n 个,因此梯度下降的偏导数也需要对每个参数求一次导,然后同时更新 n 个参数:
例如,当 时更新前三个参数:
我认为理解这一点相对容易,只需将单变量梯度下降的逻辑扩展到更多变量和参数即可,前提是必须完全理解单变量的梯度下降。
接下来,我们看看多变量梯度下降的算法代码,与单变量梯度下降类似,先计算偏导数:
```python
def gradient(theta, X, y): m = X.shape[0] inner = X.T @ (X @ theta - y) return inner / m ```
再迭代下降:
```python
def batchgradientdecent(theta, X, y, epoch, alpha=0.01): costdata = [lrcost(theta, X, y)] _theta = theta.copy()
for _ in range(epoch):
_theta = _theta - alpha * gradient(_theta, X, y)
cost_data.append(lr_cost(_theta, X, y))
return _theta, cost_data
```
调用此梯度下降函数,初始学习率 alpha 设为 0.01,迭代 epoch 设为 500 次:
python
final_theta, cost_data = batch_gradient_decent(theta, X, y, epoch, alpha=alpha)
这是最终的成本和迭代次数的曲线,可以看到成本 cost 最终基本趋于稳定,表明梯度下降算法已收敛。
所有代码可以在我的 GitHub 仓库中找到,直接下载运行即可,别忘了给我点个星哦!
GitHub 仓库地址:https://github.com/DLonng/AI-Notes/blob/master/MachineLearning/code/ex1-linear-regression/multi_feature.ipynb