目录
第二章 端到端的机器学习项目
第二章是加州房价问题,很经典的问题了,这里把重要的东西总结出来就可以。
2.2.2 选择性能指标
RMSE算是经典的误差表示形式。对于较大的误差,因为平方的缘故,数值较大。
\[\operatorname{RMSE}(\mathbf{X}, h)=\sqrt{\frac{1}{m} \sum_{i=1}^m\left(h\left(\mathbf{x}^{(i)}\right)-y^{(i)}\right)^2}\]个别数值较大或有异常区域是,使用MAE(Mean Absolute Error)
\[\operatorname{MAE}(\mathbf{X}, h)=\frac{1}{m} \sum_{i=1}^m\left|h\left(\mathbf{x}^{(i)}\right)-y^{(i)}\right|\]RMSE对应欧几里得范数,也叫做$\ell_2$范数,也即是距离。记作:
\[\|\cdot\|_2\]或
\[\|\cdot\|\]MAE对应$\ell_1$范数,也称为曼哈顿范数。理解为街区移动两点间的距离。记作: \(\|\cdot\|_1\) 一般而言,包含$n$个元素的向量$v$的$\ell_k$定义为: \(\|\mathbf{v}\|_k=\left(\left|v_0\right|^k+\left|v_1\right|^k+\cdots+\left|v_n\right|^k\right)^{\frac{1}{k}}\) 性质:
- 范数指标越高,越关注大值忽略小值。
2.3 获取数据
数据基本情况见上图,总共有10列数据,一共有20640个数据,其中total_bedrooms有20433个非空值,意味着有207个空值。
观察ocean_proximity中有多少种情况,使用value_counts()
使用describe显示概要。分别画出每个属性的直方图:
2.3.4 创建测试集
``
import numpy as np
def split_train_test(data, test_ratio):
shuffled_indices = np.random.permutation(len(data))
test_set_size = int(len(data) * test_ratio)
test_indices = shuffled_indices[:test_set_size]
train_indices = shuffled_indices[test_set_size:]
return data.iloc[train_indices], data.iloc[test_indices]
``
np.random.permutation method randomly permute a sequence, or return a permuted range.If x is a multi-dimensional array, it is only shuffled along its first index.在这里的作用就是打乱标签。iloc取相应行,返回dataframe。
如果想要让每次的数据集都相同,可以在np.random.permutation前加上np.random.seed(66)。这个方法也有缺陷,其缺陷在于在数据集更新之后,还是会产生不同的结果,因此可以采用更加稳定的方式划分。常见的解决方案是让每个数据都有一个标识符,比如zlib.crc()可以计算出某个数的hash值,按照于最大值的比例来筛选出测试集。
我们也可以直接使用Scikit-Learn提供的train_test_split()函数。
随机抽样对于大样本数据通常效果不错,但是对于样本较少的情况,往往容易产生偏差,比如调查公司找1000个人来调查,为了让这些人能代表所有人,性别分布也需要和实际情况接近。再比如测试集和数据在不同数据层级的比例要保持一致,就可以用Scikit-Learn的StratifiedShuffleSplit
2.4 数据探索及可视化
2.4.1可视化
将经度纬度绘制出来,再设置圆的半径代表人口数量,颜色代表价格。
2.4.2 寻找相关性
使用corr()方法可以计算出每对属性之间的相关系数。相关系数的变化由-1到1,越接近-1代表负相关,反之为正相关。相关性和斜率无关。
2.4.3 试验不同属性的组合
使用不同的组合如每个家庭的房间数。寻找相关关系。
2.5 数据准备
2.5.1 数据清理
对于缺失值的处理:
-
放弃相应区域
-
放弃整个属性
-
将缺失值设为某个值
相对应的函数:
- dropna()
- drop()
- fillna()
Scikit-Learn使用SimpleImputer类来处理缺失值。
2.5.2 处理文本和分类属性
- OridinalEncoder
- OneHotEncoder
2.5.3 自定义转换器
``
from sklearn.base import BaseEstimator, TransformerMixin
rooms_ix, bedrooms_ix, population_ix, households_ix = 3, 4, 5, 6
class CombinedAttributesAdder(BaseEstimator, TransformerMixin):
def __init__(self, add_bedrooms_per_room = True): # no *args or **kargs
self.add_bedrooms_per_room = add_bedrooms_per_room
def fit(self, X, y=None):
return self # nothing else to do
def transform(self, X, y=None):
rooms_per_household = X[:, rooms_ix] / X[:, households_ix]
population_per_household = X[:, population_ix] / X[:, households_ix]
if self.add_bedrooms_per_room:
bedrooms_per_room = X[:, bedrooms_ix] / X[:, rooms_ix]
return np.c_[X, rooms_per_household, population_per_household,bedrooms_per_room]
else:
return np.c_[X, rooms_per_household, population_per_household]
attr_adder = CombinedAttributesAdder(add_bedrooms_per_room=False)
housing_extra_attribs = attr_adder.transform(housing.values)
``
2.5.4 特征缩放
- MinMaxScaler
- StandardScaler
2.5.5 转换流水线
- Pipeline
- ColumnTransform
2.6 选择和训练模型
2.6.1 训练和评估训练集
分别使用LinearRegression 和 DecisionTree训练模型,使用RMSE进行验证发现线性模型效果很差,但是决策树的RMSE为0。真的有这么好吗?应该是出现了过拟合。
2.6.2 使用交叉验证进行评估
- 方案一:使用train_test_split()函数划分数据集和验证集进行评估。
- 方案二:使用Scikit-Learn的K-fold交叉验证。
使用cross- validation可以发现更真实的模型性能的反映。
2.7 微调模型
2.7.1 网格搜索
- 方案一:手动调整(枯燥乏味)
- 方案二:使用GridSearchCV进行搜索
2.7.2 随机搜索
网格搜索适用于参数较少的情况,因为考虑到参数组合和K-fold,总尝试次数可能会很大,因此需要引入随机搜索,RandomizedSearchCV。
2.10 练习题
1.
``
from sklearn.svm import SVR
from sklearn.model_selection import GridSearchCV
param_grid = [
{'kernel': ['linear'], 'C': [10., 30., 100., 300., 1000., 3000., 10000., 30000.0]},
{'kernel': ['rbf'], 'C': [1.0, 3.0, 10., 30., 100., 300., 1000.0],
'gamma': [0.01, 0.03, 0.1, 0.3, 1.0, 3.0]},
]
svm_reg = SVR()
grid_search = GridSearchCV(svm_reg, param_grid, cv=5, scoring='neg_mean_squared_error', verbose=2)
grid_search.fit(housing_prepared, housing_labels)
``