5. 特征工程
5.1重构数据集
承接上文提到的相似度排名,去掉部分无关的特征。
train_set.corr()["median_house_value"].sort_values(ascending=False)
为了提高模型训练后的鲁棒性,即防止过拟合,不建议删除关联度最低几项特征,防止‘应试’答题
y_train = train_set.pop('median_house_value') #pop()方法不仅从train_set中移除了指定的列,还返回了该列的值被存储到了变量y_train中成为目标数据
train_X = train_set.drop(['households','population_per_household','population','longitude'],axis=1) # 移除相关度低的四列特征后构建特征数
对测试集做同样特征工程处理(划分为训练集和测试集后,为了训练的有效性,对训练集做了什么对测试集就要相应的做什么)
# 在测试集上根据已有的特征构建三个新特征"rooms_per_household","population_per_household","bedrooms_per_room",使之和训练集的参数维度一致
test_set["rooms_per_household"] = strat_test_set["total_rooms"]/strat_test_set["households"]
test_set["population_per_household"]=strat_test_set["population"]/strat_test_set["households"]
test_set["bedrooms_per_room"] = strat_test_set["total_bedrooms"]/strat_test_set["total_rooms"]
y_test = test_set.pop('median_house_value')
test_X = test_set.drop(['households','population_per_household','population','longitude'],axis=1)
查看训练集的信息
train_X.info() # 通过输出信息观察数据是否存在缺失值
可以观察到total_bedrooms存在缺失值,bedroom_per_room受此影响也存在缺失值
# 观察总行数和总列数
train_X
6.数据清洗
6.1处理缺失值
pandas中的DataFrame对象有一些方便的数据清洗方法,用Dataframe的dropna(),drop(),和fillna()方法,可以方便地实现缺失值处理
1.删除缺失值所在的行,总行数变少
train_X.dropna(subset=["total_bedrooms"])
2.删除缺失值所在的列,总列数少1
train_X.drop("total_bedrooms", axis=1)
直接删除的效果不是特别好,一般考虑用一些数代替
3. 用中值替代缺失值,可以看到total_bedrooms总数量为16512,无缺失值了
如果要进一步验证可以用 train_X["total_bedrooms"].is_null.count()查看,输出为0表示没有缺失值了
median = train_X["total_bedrooms"].median()
train_X["total_bedrooms"].fillna(median)
通常,训练集要和测试集做同样的处理,比如我们使用训练集的中值来替换缺失值,那么我们最好也要用这个训练集的中值替换测试集的缺失值,这样才能保证是做了同样的处理(这是因为通常训练集要远大于测试集,训练集的中值更接近样本中值)
训练集的中值比测试集的中值代表性更强,数据基数更大
test_X["total_bedrooms"].fillna(median)
total_bedrooms共有4128个数据,已无缺失值
pandas的填充方法对于较大数据的处理时,还是比较麻烦的。
例如:如果采取了中位数填充,需要把中位数记下来(如上文的median变量),以便填充到测试集,但是加入数据中每一列都有缺失值,那我们可能要记录很多中值(这是使用pandas的缺陷)。
而使用sklearn自带的函数,可以有效解决这个问题,sklearn里提供了处理缺失值的工具Imputer
6.2用sklearn的内置方法处理缺失值
# 适应sklearn的不同版本
try:from sklearn.preprocessing import Imputer as SimpleImputer
except ImportError:from sklearn.impute import SimpleImputer # Scikit-Learn 0.20+imputer = SimpleImputer(strategy="median")
try - except 语句:这是 Python 中的错误处理机制。它首先尝试执行 try 块中的代码。如果在执行过程中遇到 ImportError(即尝试导入的模块或其部分不存在),它将执行 except 块中的代码。
无论哪个导入成功,都会创建 SimpleImputer 的一个实例,使用中位数策略来填补缺失值。这意味着对于每个特征,缺失值将被该特征的中位数替代。
这里注意输入数据格式不能是serise
imputer.fit(train_X[["total_bedrooms"]])
train_X["total_bedrooms"] =imputer.transform(train_X[["total_bedrooms"]]) #将处理后的数据分配回train_X 的对应列。transform不会直接修改原
之前使用"total_bedrooms"构建了新特征'bedrooms_per_room',这里需要重新构建一次,从而去掉里面的缺失值。
train_X['bedrooms_per_room'] = train_X['total_bedrooms']/train_X['total_rooms']
train_X.info()
对测试集做同样处理
test_X[["total_bedrooms"]] = imputer.transform(test_X[["total_bedrooms"]])
前面已经用训练集的‘total_bedrooms’的中值进行拟合,所以这里会用训练集的中值来填充测试集
test_X['bedrooms_per_room'] = test_X['total_bedrooms']/test_X['total_rooms']
test_X.info()
这里要注意,我们数据中实际包含两类数据,一类是数值型的,一类是类别型(字符型)的,这两类数据通常要分开处理,比如类别型数据不能进行标准化和数据统计(均值,方差,最值等)
7.不同类型的数据处理
7.1数值型数据处理
train_num = train_X.drop('ocean_proximity', axis=1) # 删除类别型数据列
train_num #只剩7列数值型数据
?具体作用是什么,这个填充器
Imputer的主要功能包括:
1.拟合(Fit):imputer.fit(train_num)这行代码的作用是在训练集train_num上拟合Imputer对象。在拟合过程中,Imputer会计算用于填充缺失值的统计信息,如均值、中位数或众数等,这些信息取决于Imputer的配置。
2.转换(Transform):拟合完成后,可以使用Imputer对象的transform方法来填充数据集中的缺失值。Imputer会根据拟合过程中学到的统计信息来替换缺失值。
3.统计信息:imputer.statistics_属性存储了拟合过程中计算的统计信息。对于默认的Imputer,这个属性包含了每列的均值。如果Imputer被配置为使用中位数,则statistics_属性将包含每列的中位数值。
4.参数配置:Imputer允许用户指定不同的策略来填充缺失值,常见的参数包括:
missing_values:指定缺失值的表示方式,可以是整数、浮点数或字符串。
5.strategy:指定填充策略,可以是mean(均值)、median(中位数)、most_frequent(众数)或constant(常数)。
6.应用:Imputer可以应用于单个数组或数据帧,也可以作为Pipeline的一部分,与其他预处理步骤一起使用。
imputer.fit(train_num) # 表示在训练集 train_num 上进行填充器(imputer)的拟合操作,拟合的过程是分析数据以学习填充所需的统计信息
imputer.statistics_ # 填充器imputer学习并记录了训练集中每列的中位数值,这些中位数值存储在 imputer.statistics_ 属性中。
train_num是pandas的DataFrame对象,用pandas的median()方法验证一下
train_num.median().values # 与用imputer得到中值一致
得到的结果一样
转换训练集
X_train = imputer.transform(train_num) #利用训练过的转换器对数据进行转换
对测试集做同样处理
test_num = test_X.drop('ocean_proximity', axis=1) # 删除类别型数据列
X_test = imputer.transform(test_num)
numpy数组不太方便观察数据,转换成DataFrame来观察
X_train_tr = pd.DataFrame(X_train, columns=train_num.columns) #如需要,可以把Numpy数组转换回DataFrame
X_train_tr.head()
标准化
特征缩放是重要的数据转换。数据量纲不同,会影响机器学习算法的性能。比如,总房间数分布范围是 6 到 39320,而收入中位数只分布在 0 到 15。
通常情况下,我们不需要对目标值进行缩放。
有两种常见的方法可以让所有的属性有相同的量度:
归一化(Min-Max scaling,离差)和标准化(standardization,标准差)。
1.归一化:from sklearn.preprocessing import MinMaxScaler。(很简单:值被转变、重新缩放,直到范围变成 0 到 1。我们通过减去最小值,然后再除以最大值与最小值的差值,来进行归一化。Sklearn 提供了一个转换器MinMaxScaler来实现这个功能。它有一个超参数feature_range, 可以让你改变范围,如果不希望范围是 0 到 1。
2.标准化:from sklearn.preprocessing import StandardScaler。首先减去平均值(所以标准化值的平均值总是 0)。但是,标准化受到异常值的影响很小。例如,假设一个街区的收入中位数由于某种错误变成了100,归一化会将其它范围是 0 到 15 的值变为 0-0.15,但是标准化不会受什么影响。Sklearn 提供了一个转换器StandardScaler来进行标准化。
归一化对异常值敏感,标准化对异常值不敏感,但是会改变原数据的分布情况。
from sklearn.preprocessing import StandardScaler # 均值为0和标准差为1的分布std_scaler = StandardScaler().fit(X_train)
X_train_std = std_scaler.fit_transform(X_train)
pd.DataFrame(X_train_std, columns=train_num.columns).head()
对测试集做同样处理
X_test_std = std_scaler.fit_transform(X_test)
7.2补充说明 Sklearn的API的设计特性
创建适用于sklearn转换器和估计器的规则
7.2.1一致性
1.转换器(transformer)。转换是通过transform()方法,被转换的数据集作为参数。返回的是经过转换的数据集。转换过程依赖学习到的参数,比如imputer的例子。所有的转换都有一个便捷的方法fit_transform(),等同于调用fit()再transform()(但有时fit_transform()经过优化,运行的更快)。
2.估计器(estimator)。任何可以基于数据集对一些参数进行估计的对象都被称为估计器(比如,imputer就是个估计器)。估计本身是通过fit()方法,只需要一个数据集作为参数(对于监督学习算法,需要两个数据集;第二个数据集包含标签)。任何其它用来指导估计过程的参数都被当做超参数(比如imputer的strategy),并且超参数要被设置成实例变量(通常通过构造器参数设置)。
3.预测器(predictor)。最后,一些估计器可以根据给出的数据集做预测,这些估计器称为预测器。预测器有一个predict()方法,可以用新实例的数据集做出相应的预测。预测器还有一个score()方法,可以根据测试集(如果是监督学习算法的话还需要标签)对预测进行衡量。
7.2.2可检验
所有估计器的超参数都可以通过实例的公有变量直接访问(比如,imputer.strategy),并且所有估计器学习到的参数也可以通过在实例变量名后加下划线来访问(比如,imputer.statistics_)。
类数据集被表示成 NumPy 数组或 SciPy 稀疏矩阵,而不是自制的类。超参数只是普通的 Python 字符串或数字。
7.2.3可组合
例如后面提到的流水线
7.2.4合理的默认值
Sklearn 给大多超参数提供了合理的默认值,大大降低了建模的难度。
7.3类别型数据处理
大多数机器学习算法都喜欢和数字打交道,一些非数值型数据需要转换成数值型。比如我们数据中的"ocean_proximity"特征
7.3.1LabelEncoder
转换器:LabelEncoder主要用于编码目标变量(通常为单列),即将标签转换为从0到n_classes-1的整数值。
train_X["ocean_proximity"].head()
train_cat = train_X[["ocean_proximity"]]
test_cat = test_X[["ocean_proximity"]]
7.3.2OrdinalEncoder
使用OrdinalEncoder用于将具有顺序关系的类别特征转换为整数值。它主要用于编码输入特征,而不是目标变量。
from sklearn.preprocessing import OrdinalEncoderordinal_encoder = OrdinalEncoder()
train_cat_encoded = ordinal_encoder.fit_transform(train_cat)
train_cat_encoded[:10]
ordinal_encoder.categories_
"ocean_proximity"特征的所有类别
7.3.3OneHotEncoder
LabelEncoder/OrdinalEncoder方法主要处理表示顺序类别的数据,对于普通类别(不是区间分段的)不合适,有些机器学习算法会认为两个临近的值比两个疏远的值要更相似。显然这样不对。
编码器OneHotEncoder:进行one-hot编码,这里是对整数类别进行编码
from sklearn.preprocessing import OneHotEncodercat_encoder = OneHotEncoder().fit(train_cat)
train_cat_1hot = cat_encoder.transform(train_cat)
train_cat_1hot
OneHotEncoder的返回值默认使用稀疏数组形式,需要使用toarray()来转换成ndarray
train_cat_1hot.toarray()
去掉稀疏存储,减少内存占用?
cat_encoder = OneHotEncoder(sparse=False).fit(train_cat)
train_cat_1hot = cat_encoder.transform(train_cat)
train_cat_1hot
对测试集做同样处理
test_cat_1hot = cat_encoder.transform(test_cat)
7.4合并数据
训练集
X_train_prepared = np.c_[X_train_std,train_cat_1hot]
X_train_prepared
测试集
X_test_prepared = np.c_[X_test_std,test_cat_1hot]
X_test_prepared
最终用于训练和测试的数据
至此,终于完成了数据处理的流程!
8.选择并训练模型
经过了一系列的探索,准备数据,现在可以训练你的机器学习模型了
回到任务本身,预测美国加州房价,那么这是个回归任务
训练一个决策树回归模型:估计器的使用
from sklearn.tree import DecisionTreeRegressortree_reg = DecisionTreeRegressor() # 构建模型
tree_reg.fit(X_train_prepared, y_train) # 训练模型
使用模型预测结果:预测器的使用
from sklearn.metrics import mean_squared_errory_train_predictions = tree_reg.predict(X_train_prepared) # 预测模型
tree_mse = mean_squared_error(y_train, y_train_predictions) # 计算均方误差
tree_rmse = np.sqrt(tree_mse) # 开平方,计算均方根误差
tree_rmse
均方误差为0,原因是用模型训练的数据来检验,带着答案做题显然没有意义,要用前面准备好的测试集来检验模型
y_test_predictions = tree_reg.predict(X_test_prepared) # 用训练好的模型测速测试集
tree_mse = mean_squared_error(y_test, y_test_predictions) #计算测试集的均方误差
tree_rmse = np.sqrt(tree_mse) # 计算测试集的均方根误差
tree_rmse
还可以用到其它的回归模型进行预测和比对,选择精度最高的模型来作为预测器
非运行代码
from sklearn.linear_model import LinearRegression, SGDRegressor
model = LinearRegression()
model = SGDRegressor()from sklearn.svm import SVR
model = SVR()# sklearn.ensemble集成学习
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor, AdaBoostRegressor, ExtraTreesRegressor
model = RandomForestRegressor()
model = GradientBoostingRegressor()
model = AdaBoostRegressor()
model = ExtraTreesRegressor()