机器学习实战——房价预测完整案例建议收藏慢慢品


写在前面

参考书籍Hands-On Machine Learning with Scikit-Learn,Keras,and TensorFlow

本文为机器学习实战学习笔记,主要内容为第二章房价预测项目,文中除了书中主要内容,还包含部分博主少量自己修改的部分,如果有什么需要改进的地方,可以在评论区留言


❤更多内容❤

机器学习实战——分类及性能测量完整案例(建议收藏慢慢品)



1. 获取数据

下载数据可以直接通过浏览器下载压缩包,也可以通过函数来进行。
数据集下载地址

import os
import tarfile
import urllib.request

DOWNLOAD_ROOT = "https://raw.githubusercontent.com/ageron/handson-ml2/master/"
HOUSING_PATH = os.path.join("datasets", "housing")    # datasets\test
HOUSING_URL = DOWNLOAD_ROOT + "datasets/housing/housing.tgz"

def fetch_housing_data(housing_url=HOUSING_URL, housing_path=HOUSING_PATH):
    # 创建目录
    if not os.path.isdir(housing_path):
        os.makedirs(housing_path)
    tgz_path = os.path.join(housing_path, "housing.tgz")    # datasets\test\housing.tgz
    # 将housing_url下载的文件保存到tgz_path路径
    urllib.request.urlretrieve(housing_url, tgz_path)
    housing_tgz = tarfile.open(tgz_path)
    # 解压到housing_path路径
    housing_tgz.extractall(path=housing_path)
    housing_tgz.close()
    
fetch_housing_data()

每次调用 fetch_housing_data() ,就会自动在工作区创建一个 datasets/housing 目录,然后下载 housing.tgz 文件,并解压到当前文件夹。


再创建一个函数来加载数据,返回值为 DataFrame 对象。

import pandas as pd

def load_housing_data(housing_path=HOUSING_PATH):
    csv_path = os.path.join(housing_path, "housing.csv")
    return pd.read_csv(csv_path)

housing = load_housing_data()


1.1 查看数据结构

显示数据集前五行, head() 中也可以指定显示的行数。

housing.head()

在这里插入图片描述


使用 info() 获取数据集的简单描述。包括总行数、每个属性的类型和非空值的数量等。

housing.info()

在这里插入图片描述


使用 describe() 获取数值属性的描述,注意统计时的空值会被忽略。

housing.describe()

在这里插入图片描述


绘制每个数值的直方图。直方图横轴表示数值范围,纵轴表示实例数量

import matplotlib.pyplot as plt
# 绘制直方图
housing.hist(bins=50, figsize=(20,15))
# 保存图片
plt.savefig("./images/end_to_end_project/attribute_histogram_plots.png", dpi=300)

在这里插入图片描述

根据直方图需要注意:

  1. 根据 housing_median_agemedian_house_value 右侧的数据可以看出,房龄中位数和房价中位数被设置了上限,如果直接用这些数据进行模型训练,那么模型学习到的价格很可能永远不会超过这个限制。如果需要精确的预测房价,甚至可以超过 50 万美元,那么有以下两个选择:
    • 对那些标签值被设置了上限的区域,重新收集标签值。即使用真实的房价数据,尽管它超过 50 万。
    • 将这些区域的数据数据集中移除
  2. 这些属性值被缩放的程度各不相同。
  3. 直方图中的图形向右侧延伸比左侧要远得多,这可能会导致某些机器学习算法难以检测模式,可以尝试一些转化方法,将这些属性转化为更偏钟形的分布。


2. 划分测试集

经调研可知,收入中位数对于预测房价中位数十分重要。所以在收入这一属性上,我们希望测试集能够代表各种不同类型的收入,即分层抽样。首先要根据上面图中的 median_income 直方图中的数值,大多数收入中位数聚集在 [1.5,6] 之间,划分层次时,每层要有足够多的实例,因此,使用 pd.cut() 方法创建 5 个收入类别, 0-1.51.5-33-4.54.5-66- +∞

housing["income_cat"] = pd.cut(housing["median_income"],
                               bins=[0., 1.5, 3.0, 4.5, 6., np.inf],
                               labels=[1, 2, 3, 4, 5])
# 根据income_cat数据绘制直方图                   
housing["income_cat"].hist()

在这里插入图片描述


根据 income_cat 列进行分层抽样,使用 Scikit-learnStratfiedShuffleSplit 类来实现。划分完测试集就可以将 income_cat 列删除。

from sklearn.model_selection import StratifiedShuffleSplit

s = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)
for train_index, test_index in s.split(housing, housing["income_cat"]):
	# train_index: [17606 18632 14650 ... 13908 11159 15775]
    strat_train_set = housing.loc[train_index]
    # test_index: [5241 10970 20351 ...  4019 12107  2398]
    strat_test_set = housing.loc[test_index]

for dataset in (strat_train_set, strat_test_set):
    dataset.drop("income_cat", axis=1, inplace=True)
housing_train = strat_train_set.copy()


3. 可视化获取更多信息

根据数据集中的经纬度,可以绘制一个各区域的分布图。

# 显示中文
plt.rcParams['font.family'] = 'SimHei'
# 显示负号
plt.rcParams['axes.unicode_minus'] = False

housing_train.plot(kind="scatter", x="longitude", y="latitude")
plt.xlabel('经度')
plt.ylabel('纬度')
plt.savefig("./images/end_to_end_project/bad_visualization_plot.png", dpi=300)

在这里插入图片描述


alpha 设置为1,显示高密度点的位置。

housing_train.plot(kind="scatter", y="latitude", alpha=0.1)
plt.xlabel('经度')
plt.ylabel('纬度')
plt.savefig("./images/end_to_end_project/better_visualization_plot.png", dpi=300)

在这里插入图片描述


为了更加图像能够凸显更多的信息,将每个区域的人口数量作为图中每个圆的半径大小,房价中位数表示圆的颜色,使用预定义颜色表 "jet" ,颜色由(低房价)到红(高房价)。

housing_train.plot(kind="scatter", alpha=0.3,
             s=housing_train["population"]/50, label="population", figsize=(10,7),
             c="median_house_value", cmap=plt.get_cmap("jet"), colorbar=True,
             sharex=False)
plt.legend()
plt.xlabel('经度')
plt.ylabel('纬度')
plt.savefig("./images/end_to_end_project/housing_prices_scatterplot.png", dpi=300)

在这里插入图片描述



4. 寻找相关性

使用 corr() 方法计算每对属性之间的皮尔逊相关系数。相关系数范围 [-1,1] ,越接近 1 表示有越强的正相关,越接近 -1 表示有越强的负相关。

corr_matrix = housing_train.corr()
corr_matrix 

在这里插入图片描述


具体看每个属性与房价中位数的相关性。

corr_matrix["median_house_value"].sort_values(ascending=False)

在这里插入图片描述


也可以使用 pandasscatter_matrix 函数,他会绘制出每个数值属性相对于其他数值属性的相关性。比如现在有 9 个数值属性,能够得到 81 个图像,根据 corr() 计算的相关性,我们选取前 4 个属性来绘制图像,这样只得到 16 个图像。

from pandas.plotting import scatter_matrix

attributes = ["median_house_value", "median_income", "total_rooms",
              "housing_median_age"]
scatter_matrix(housing_train[attributes], figsize=(12, 8))
plt.savefig("./images/end_to_end_project/scatter_matrix_plot.png", dpi=300)

在这里插入图片描述


与房价中位数最相关的属性是收入中位数,我们将上图中的收入中位数散点图单独拿出来。

housing_train.plot(kind="scatter", x="median_income", y="median_house_value",
             alpha=0.2)
plt.axis([0, 16, 0, 550000])
plt.savefig("./images/end_to_end_project/income_vs_house_value_scatterplot.png", dpi=300)

在这里插入图片描述

根据图中的点,可以看出两个属性确实具有较强的相关性,除此之外,图中还有几条比较明显的直线, 50 万、 45 万、 35 万时,甚至还有更多,这些比较“怪”的数据,再投入模型之前,要尝试删除这些相关区域。



5. 属性组合

在把训练集投入模型之前,我们应该尝试各种属性的组合,例如相比于一个区域的房间总数 (total_rooms) 与家庭数量 (households) ,我们可能更需要的是单个家庭的房间数量 (rooms_per_household) 。下面尝试创建一些新的组合属性。

housing_train["rooms_per_household"] = housing_train["total_rooms"]/housing_train["households"]
housing_train["bedrooms_per_room"] = housing_train["total_bedrooms"]/housing_train["total_rooms"]
housing_train["population_per_household"]=housing_train["population"]/housing_train["households"]

# 计算相关矩阵
corr_matrix = housing_train.corr()
corr_matrix["median_house_value"].sort_values(ascending=False)

在这里插入图片描述


通过计算得到的相关性可以看到,某些组合属性与房价中位数的相关性比单个属性的相关性都要高。



6. 数据处理

6.1 数据清洗

填补 total_bedrooms 属性中的缺失值。

# 获取删除标签列后的数据集
housing = strat_train_set.drop("median_house_value", axis=1)
# 标签列
housing_labels = strat_train_set["median_house_value"].copy()

from sklearn.impute import SimpleImputer

# 创建SimpleImputer实例,设置中位数替换
imputer = SimpleImputer(strategy="median")
# 创建一个没有文本属性"ocean_proximity"的数据集
housing_num = housing.drop("ocean_proximity", axis=1)
# 将imputer实例适配到housing_num
imputer.fit(housing_num)
# 执行中位数替换缺失值的转化。
X = imputer.transform(housing_num)
# 将numpy数组转换成DataFrame
housing_tr = pd.DataFrame(X, columns=housing_num.columns,
                          index=housing.index)


6.2 处理文本和分类属性

对于文本属性 ocean_proximity ,我们先看一下它的大致内容。

# 注意:[["ocean_proximity"]]获得DataFrame类型的数据,因为后面需要对二维数据进行转化
housing_cat = housing[["ocean_proximity"]]
housing_cat.value_counts()

在这里插入图片描述


可以看出它的值不是任意文本,而是每个值代表一个类别,可以使用 Scikit-Learn 中的 OrdinalEncoder 类将这些类别从文本转成数字。

from sklearn.preprocessing import OrdinalEncoder

ordinal_encoder = OrdinalEncoder()
# 拟合并转换
housing_cat_encoded = ordinal_encoder.fit_transform(housing_cat)
housing_cat_encoded[:10]

在这里插入图片描述


使用 Categories_ 实例变量获取类别列表。

ordinal_encoder.categories_

在这里插入图片描述


这样表征方式会产生一个问题,模型训练时会认为两个相近的值比两个相远的值更相似一些。在某些情况下是对的( ['坏',‘平均’,‘好’,‘优秀 ’] ),但在目前的序列 categories 中,情况可能就不是这样( 1H OCEANNEAR OCEAN 的相似度比相邻情况下的 1H OCEANINLAND 的相似度高)。常见的解决方案是给每个类别创建一个二进制属性:当类别为 1H OCEAN 时,它的某个属性为 1 (其他属性为 0 ),当类别是 INLAND 时,另一个属性为 1 (其他属性为 0 ),以此类推,这就是独热编码可以使用 sklearn 中的 OneHotEncoder 编码器,将整数类别值转换为独热向量。

from sklearn.preprocessing import OneHotEncoder

cat_encoder = OneHotEncoder()
housing_cat_1hot = cat_encoder.fit_transform(housing_cat)
housing_cat_1hot

在这里插入图片描述


从结果可以知道,这是一个 Scipy 稀疏矩阵。稀疏矩阵选择仅存储非零元素的位置。如果需要也可以使用 toarray() 方法得到一个(密集的) NumPy 数组。

housing_cat_1hot.toarray()

在这里插入图片描述


注意: 如果类别中的种类有很多,那么独热编码会导致过多的输入特征,可能会减慢训练速度并降低性能。如果出现这种情况,可以使用相关的数字特征代替类别。如上面的 ocean_proximity 特征,可以使用海洋的距离作为特征进行替换。



6.3 自定义转换器

Scikit-Learn 中有许多有用的转换器,但对于一些自定义清理操作或者组合特定属性等任务需要编写自己的转换器。由于 Scikit-Learn 的编译特性,编写转换器也十分方便,我们只需创建一个类,然后实现 fit()transformm()fit_transform() 。该类可以通过添加 TransformMixin 作为基类,直接得到 fit_transform() 方法,同时可以添加 BaseEstimator 作为基类(并在构造函数中避免 *arg**kargs ),还可以获得自动调整参数的方法( get_params()set_params() )。下面实现一个简单的转换器类,用来添加之前的组合属性。

from sklearn.base import BaseEstimator, TransformerMixin

# 选取列名
col_names = ["total_rooms", "total_bedrooms", "population", "households"]
rooms_ix, bedrooms_ix, population_ix, households_ix = [housing.columns.get_loc(c) for c in col_names]

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
    
    def transform(self, X):
        rooms_per_household = X[:, rooms_ix] / X[:, households_ix]
        population_per_household = X[:, population_ix] / X[:, households_ix]
        # 根据超参数add_bedrooms_per_room判断是否需要添加该组合属性
        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, population_per_household]

attr_adder = CombinedAttributesAdder(add_bedrooms_per_room=False)
housing_extra_attribs = attr_adder.transform(housing.values)

# 将housing_extra_attribs从array转为DataFrame
housing_extra_attribs = pd.DataFrame(
    housing_extra_attribs,
    columns=list(housing.columns)+["rooms_per_household", "population_per_household"],
    index=housing.index)
housing_extra_attribs.head()

在这里插入图片描述


我们可以设置转换器中的超参数 add_bedrooms_per_room 的值,来轻松的知晓添加这个属性是否有助于机器学习的算法。



6.4 流水线式数据转换

大多数据转换的步骤需要以正确的顺序来执行, Sickit-Learn 中的 Pipeline 类正好支持这样的转换,下面是对数值转换的流水线。

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

num_pipeline = Pipeline([
		# 中位数替换缺失值
        ('imputer', SimpleImputer(strategy="median")),
        # 添加组合属性
        ('attribs_adder', CombinedAttributesAdder()),
        # 归一化,统一量纲
        ('std_scaler', StandardScaler()),
    ])

housing_num_tr = num_pipeline.fit_transform(housing_num)
housing_num_tr

在这里插入图片描述


Pipeline 构造函数会通过一系列的名称/估算器的配对来定义步骤序列。除了最后一个是估算器之外,前面都必须是转换器(必须有 fit_transform() 方法)。当调用流水线的 fit() 方法时,会在所有转换器上按照顺序依次调用 fit_transform() ,每次将一个调用的输出作为输出传递给下一个调用方法,知道传递到最终的估算器,则只会调用 fit() 方法。


现在我们已经分别处理了类别列和数值列。然后可以构造一个能够处理所有列的转换器。将是当的转换应用到每个列,对此我们可以使用 ColumnTransformer 。下面用它来将所有的转换应用到房屋数据。

from sklearn.compose import ColumnTransformer

# 获得数值列名称列表
num_attribs = list(housing_num)
# 获得类别列名称列表
cat_attribs = ["ocean_proximity"]

# 元组中的三个参数分别代表:名称(自定),转换器,以及一个该转换器能够应用的列名字(或索引)的列表
full_pipeline = ColumnTransformer([
		# 数值属性列转换器
        ("num", num_pipeline, num_attribs),
        # 文本属性列转换器
        ("cat", OneHotEncoder(), cat_attribs),
    ])
# 将ColumnTranformer应用到房屋数据
housing_prepared = full_pipeline.fit_transform(housing)
housing_prepared

在这里插入图片描述


我们观察上面的结果可以看出,它是一个密集矩阵,然而转换器 OneHotEncoder 返回一个稀疏矩阵。当一个稀疏矩阵和密集矩阵混合在一起时, ColumnTransformer 会估算最终矩阵的密度(即单元格的非零比率),如果密度低于给定的阈值(默认值 sparse_threshold=0.3 ),则返回一个稀疏矩阵。



7. 选择和训练模型

7.1 训练和评估训练集

首先,先训练一个线性回归模型。

from sklearn.linear_model import LinearRegression

lin_reg = LinearRegression()
# 模型训练
lin_reg.fit(housing_prepared, housing_labels)

使用 5 个训练集的实例进行测试。

# 在几个训练实例上应用完整的预处理
some_data = housing.iloc[:5]    # 测试集
some_labels = housing_labels.iloc[:5]    # 测试标签
some_data_prepared = full_pipeline.transform(some_data)

print("Predictions:", lin_reg.predict(some_data_prepared))
print("Labels:", list(some_labels))

在这里插入图片描述


预测的结果还不太准确。可以使用 Scikit-Learnmean_squared_errod() 函数来测量整个训练集上回归模型的 RMSERoot Mean Square Error 均方根误差)。

在这里插入图片描述

from sklearn.metrics import mean_squared_error

housing_predictions = lin_reg.predict(housing_prepared)
# 均方误差
lin_mse = mean_squared_error(housing_labels, housing_predictions)
# 均方根误差
lin_rmse = np.sqrt(lin_mse)
lin_rmse

在这里插入图片描述


根据结果可以看出,这个模型的效果并不是很好,根据之前的统计,大多数区域的 median_housing_values 分布在 120000~265000 美元之间,所以预测的误差达到 68628 美元难以让人接受。这是典型的模型对训练数据欠拟合的情况。欠拟合的情况下,往往说明这些特征无法提供足够的信息来做出更好的预测,或者是模型的本身有所欠缺。想要修正的话,可以通过选择更强大的模型,或为算法训练提供更好的特征,又或者减少对模型的限制。 LinearRegression 并不是一个正则化模型,所以只能通过选择更强大的模型,或是对特征进行修改。接下来尝试一个更强大的模型 DecisionTreeRegressor ,它能够从数据中只好到复杂的非线性关系。

from sklearn.tree import DecisionTreeRegressor

tree_reg = DecisionTreeRegressor(random_state=42)
# 模型训练
tree_reg.fit(housing_prepared, housing_labels)
# 模型预测
housing_predictions = tree_reg.predict(housing_prepared)
# 均方误差
tree_mse = mean_squared_error(housing_labels, housing_predictions)
# 均方根误差
tree_rmse = np.sqrt(tree_mse)
tree_rmse

在这里插入图片描述


根据 tree_rmse 的值,貌似结果非常完美,但事实却可能是这个模型对数据严重过拟合了。如何确认?可以使用下节的方式。



7.2 使用交叉验证来更好地进行评估

评估模型的一种方法是使用 train_test_split 函数将训练集划分为较小的训练集和测试集。还有一种方法是使用 Scikit-LearnK 折交叉验证的功能。比如:它可以将训练集分割成 10 个不同的子集,每个子集称为一个折叠,然后对模型进行 10 训练和评估——每次挑选一个折叠进行评估,使用其他 9 个折叠进行模型训练,返回一个包含 10 次评估分数的数组。

from sklearn.model_selection import cross_val_score

scores = cross_val_score(tree_reg, housing_prepared, housing_labels,
                         scoring="neg_mean_squared_error", cv=10)
tree_rmse_scores = np.sqrt(-scores)

def display_scores(temp_scores):
    print("Scores:", temp_scores)
    print("Mean:", temp_scores.mean())
    print("Standard deviation:", temp_scores.std())

display_scores(tree_rmse_scores)

在这里插入图片描述


注: Scikit-Learn 的交叉验证功能更倾向于使用效用函数(越大越好)而不是成本函数(越小越好),所以上述的 scores 中的分数实际是负的 MSE 函数,所以要是用 np.sqrt(-scores)


以这个结果来看决策树模型表现的也不太好,误差 71407 ,上下浮动 ±2439


再使用交叉验证计算一下线性回归模型的评分。

lin_scores = cross_val_score(lin_reg,
                             scoring="neg_mean_squared_error", cv=10)
lin_rmse_scores = np.sqrt(-lin_scores)
display_scores(lin_rmse_scores)

在这里插入图片描述


根据结果可以看出,决策树模型确实严重过拟合了,表现得比线性回归模型还要差。


接下来尝试最后一个模型 RandomForestRegressor 随机森林。它通过特征的随机子集进行多个决策树的训练,然后对其预测取平均,在多个模型的基础上建立模型,这就是集成学习。

from sklearn.ensemble import RandomForestRegressor

forest_reg = RandomForestRegressor(n_estimators=100, random_state=42)
forest_reg.fit(housing_prepared, housing_labels)

housing_predictions = forest_reg.predict(housing_prepared)
forest_mse = mean_squared_error(housing_labels, housing_predictions)
forest_rmse = np.sqrt(forest_mse)
forest_rmse

在这里插入图片描述


根据 RMSE 的结果来看,比较容易接受,接下来看一下交叉验证的评分。

from sklearn.model_selection import cross_val_score

forest_scores = cross_val_score(forest_reg,
                                scoring="neg_mean_squared_error", cv=10)
forest_rmse_scores = np.sqrt(-forest_scores)
display_scores(forest_rmse_scores)

交叉验证的结果 50182 ,虽然比之前的模型都要好,但还是远远高于训练集上的 18603 ,这就意味着该模型仍然对训练集过拟合。如此以来,我们可以着手对模型进行微调了,但在微调之前可以将训练好的模型进行保存,同时也要保存超参数和训练过的参数以及交叉验证的评分(忘记了就只有重新再跑一边模型了)和实际预测的结果。



8. 微调模型

8.1 网格搜索

使用 Scikit-LearnGridSearchCV 来寻找最佳的超参数组合,你只需要传入超参数是什么,以及它需要尝试的值, GridSearchCV 会使用交叉验证来评估超参数值的所有组合,下面通过 GridSearchCV 来搜索 RandomForestRegressor 的超参数值的最佳组合。

from sklearn.model_selection import GridSearchCV

param_grid = [
    # 尝试3×4=12种超参数组合
    {'n_estimators': [3, 10, 30], 'max_features': [2, 6, 8]},
    # 之后设置bootstrap=False,再尝试2×3=6种超参数组合
    {'bootstrap': [False], 'n_estimators': [3, 10], 4]},
  ]

forest_reg = RandomForestRegressor(random_state=42)
# 训练5次,总共(12+6)×5=90次
grid_search = GridSearchCV(forest_reg, param_grid, cv=5,
                           scoring='neg_mean_squared_error',
                           return_train_score=True)
grid_search.fit(housing_prepared, housing_labels)

在这里插入图片描述


上面代码中的 param_grid 参数中值的含义是,首先评估第一个字典中的 n_estimatormax_features 的所有 3×412 种组合;接着在尝试第二个字典中的 1×2×36 种组合。所以 GridSearchCV 将探索 RandomForestRegressor 超参数值的 18 种组合,并对每个模型进行 5 次训练( cv=5 ),总 5×1890 次训练,可能需要很长时间,但可能会得到最佳的超参数组合(可能得到的超参数值处于边界处,根据情况还需要扩大或缩小范围,再调参)。


查看评分最高的超参数组合。

grid_search.best_params_

在这里插入图片描述


由于超参数的最佳值都处于取值范围的右边界,可能需要再扩大取值范围,继续寻找。

param_grid = [
    {'n_estimators': [30, 50, 70, 90], 'max_features': [7, 8, 9]},
  ]
grid_search = GridSearchCV(forest_reg, housing_labels)
grid_search.best_params_

在这里插入图片描述


这个结果就比较满意了。


接下来看看当前的最佳估算器(输出只显示非默认的参数)。

grid_search.best_estimator_

在这里插入图片描述


GridSearchCV 计算的各种超参数组合的评分。

cvres = grid_search.cv_results_
for mean_score, params in zip(cvres["mean_test_score"], cvres["params"]):
    print(np.sqrt(-mean_score), params)

在这里插入图片描述


根据图中的两条红线的得分可以看出,相较于第一次调参结果,第二次的超参数组合确实要高一些。



8.2 随机搜索

如果探索的组合数量较少时,网格搜索是一种不错的方法,但当超参数的搜索范围较大时,通常会优先选择使用 RandomizedSearchCV 。它与 GridSearchCV 用法相似,但它不会尝试所有可能的组合,而是在每次迭代中为每个超参数选择一个随机值,然后对一定数量的随机组合进行评估,这种方法有两个显著的好处。

  • 如果运行随机 1000 个迭代,那么将会探索每个超参数的 1000 个不同的值(而不像网格搜索方法那样每个超参数仅探索少量几个值)。
  • 通过简单地设置迭代次数,可以更好地控制要分配给超参数搜索的计算预算。
from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import randint


param_distribs = {
        # 均匀离散随机变量
        'n_estimators': randint(low=1, high=200),
        'max_features': randint(low=7, high=9),
    }

forest_reg = RandomForestRegressor(random_state=42)
rnd_search = RandomizedSearchCV(forest_reg, param_distributions=param_distribs,
                                n_iter=10, scoring='neg_mean_squared_error', random_state=42)
rnd_search.fit(housing_prepared, housing_labels)

在这里插入图片描述


看一下 RandomizedSearchCV 计算的各种超参数组合的评分。

cvres = rnd_search.cv_results_
for mean_score, params)

在这里插入图片描述


结果显而易见,它相比于网格搜索有着更好的随机性,能够在相同时间内探索更多可能的区域,但带来的就是不确定性,就如同上面的结果, max_features 的取值绝大多数为 7 .



8.3 分析最佳模型及其误差

通过检查最佳模型,你总是可以得到一些好的洞见,如在进行准确预测时, RandomForestRegressor 可以指出每个属性的相对重要程度。

feature_importances = grid_search.best_estimator_.feature_importances_
feature_importances

在这里插入图片描述


将这些重要性分数显示在对应的属性名称旁边。

extra_attribs = ["rooms_per_hhold", "pop_per_hhold", "bedrooms_per_room"]
# cat_encoder: OneHotEncoder()
cat_encoder = full_pipeline.named_transformers_["cat"]
# cat_one_hot_attribs: ['<1H OCEAN','INLAND','ISLAND','NEAR BAY','NEAR OCEAN']
cat_one_hot_attribs = list(cat_encoder.categories_[0])
attributes = num_attribs + extra_attribs + cat_one_hot_attribs
sorted(zip(feature_importances, attributes), reverse=True)

在这里插入图片描述


有了这些信息可以尝试着删除一些不太有用的特征,如 ocean_proximity 中只有 INLAND 类别是有用的,我们可以试着删除其他所有的类别( <1H OCEAN>NEAR OCEANNEAR BAYISLAND )。



8.4 通过测试集评估系统

经过前面的训练,现在有了一个表现足够优秀的系统了,是时候用测试集评估最终模型的时候了,我们只需要从测试集中获取预测器和标签,运行 full_pipeline 来转换数据(调用 transform() 而不是 fit_transform() ),然后在测试集上评估最终模型。

final_model = grid_search.best_estimator_

X_test = strat_test_set.drop("median_house_value", axis=1)
y_test = strat_test_set["median_house_value"].copy()

# 数据处理
X_test_prepared = full_pipeline.transform(X_test)
# 模型预测
final_predictions = final_model.predict(X_test_prepared)

final_mse = mean_squared_error(y_test, final_predictions)
final_rmse = np.sqrt(final_mse)
final_rmse

在这里插入图片描述


在某些情况下,泛化误差的这种点估计将不足以说服你启动生产环境,我们可以使用 scipy.stats.t.interval() 计算泛化误差的 95% 置信区间。

from scipy import stats

confidence = 0.95
squared_errors = (final_predictions - y_test) ** 2
np.sqrt(stats.t.interval(confidence, len(squared_errors) - 1,
                         loc=squared_errors.mean(),
                         scale=stats.sem(squared_errors)))

在这里插入图片描述


如果之前进行过大量的超参数调整,这时的评估结果往往会略逊于你之前使用交叉验证是的表现结果(通过不断调整,系统在测试集上面终于表现良好,但在未知数据集上可能达不到这么好的效果)。在上面的结果中,结果尽管并非如此,但你也一定不要去继续调整参数,不要试图再努力让测试集的结果变得好看,因为这些改进在泛化到新的数据集时又会变成无用功。



9. 启动、监控和维护你的系统

将模型部署到生产环境中。比较简单的方法是保存训练好的 Scikit-Learn 模型(使用 joblib ),包括完整的预处理和预测流水线,然后在生产环境中加载经过训练的模型并通过调用 prepare() 方法来进行预测。


都看到这了,看在博主这么辛苦的份上,❤ 点个赞再走吧!!!❤

❤️源码获取方式❤️

像我这么宠粉的人~当然会给关注我的粉丝们亿点小福利啦,关注下方小卡片,回复 “房价预测” 即可获取源码哦!,另外还有博主各种文章源码及干货资料!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读5.3k次,点赞10次,收藏39次。本章详细写了mysql的安装,环境的搭建以及安装时常见的问题和解决办法。_mysql安装及配置超详细教程
文章浏览阅读1.8k次,点赞50次,收藏31次。本篇文章讲解Spark编程基础这门课程的期末大作业,主要围绕Hadoop基本操作、RDD编程、SparkSQL和SparkStreaming编程展开。_直接将第4题的计算结果保存到/user/root/lisi目录中lisipi文件里。
文章浏览阅读7.8k次,点赞9次,收藏34次。ES查询常用语法目录1. ElasticSearch之查询返回结果各字段含义2. match 查询3. term查询4. terms 查询5. range 范围6. 布尔查询6.1 filter加快查询效率的原因7. boosting query(提高查询)8. dis_max(最佳匹配查询)9. 分页10. 聚合查询【内含实际的demo】_es查询语法
文章浏览阅读928次,点赞27次,收藏18次。
文章浏览阅读1.1k次,点赞24次,收藏24次。作用描述分布式协调和一致性协调多个节点的活动,确保一致性和顺序。实现一致性、领导选举、集群管理等功能,确保系统的稳定和可靠性。高可用性和容错性Zookeeper是高可用的分布式系统,通过多个节点提供服务,容忍节点故障并自动进行主从切换。作为其他分布式系统的高可用组件,提供稳定的分布式协调和管理服务,保证系统的连续可用性。配置管理和动态更新作为配置中心,集中管理和分发配置信息。通过订阅机制,实现对配置的动态更新,以适应系统的变化和需求的变化。分布式锁和并发控制。
文章浏览阅读1.5k次,点赞26次,收藏29次。为贯彻执行集团数字化转型的需要,该知识库将公示集团组织内各产研团队不同角色成员的职务“职级”岗位的评定标准;
文章浏览阅读1.2k次,点赞26次,收藏28次。在安装Hadoop之前,需要进行以下准备工作:确认操作系统:Hadoop可以运行在多种操作系统上,包括Linux、Windows和Mac OS等。选择适合你的操作系统,并确保操作系统版本符合Hadoop的要求。安装Java环境:Hadoop是基于Java开发的,因此需要先安装和配置Java环境。确保已经安装了符合Hadoop版本要求的Java Development Kit (JDK),并设置好JAVA_HOME环境变量。确认硬件要求:Hadoop是一个分布式系统,因此需要多台计算机组成集群。
文章浏览阅读974次,点赞19次,收藏24次。# 基于大数据的K-means广告效果分析毕业设计 基于大数据的K-means广告效果分析。
文章浏览阅读1.7k次,点赞6次,收藏10次。Hadoop入门理论
文章浏览阅读1.3w次,点赞28次,收藏232次。通过博客和文献调研整理的一些农业病虫害数据集与算法。_病虫害数据集
文章浏览阅读699次,点赞22次,收藏7次。ZooKeeper使用的是Zab(ZooKeeper Atomic Broadcast)协议,其选举过程基于一种名为Fast Leader Election(FLE)的算法进行。:每个参与选举的ZooKeeper服务器称为一个“Follower”或“Candidate”,它们都有一个唯一的标识ID(通常是一个整数),并且都知道集群中其他服务器的ID。总之,ZooKeeper的选举机制确保了在任何时刻集群中只有一个Leader存在,并通过过半原则保证了即使部分服务器宕机也能维持高可用性和一致性。
文章浏览阅读10w+次,点赞62次,收藏73次。informatica 9.x是一款好用且功能强大的数据集成平台,主要进行各类数据库的管理操作,是使用相当广泛的一款ETL工具(注: ETL就是用来描述将数据从源端经过抽取(extract)、转换(transform)、加载(load)到目的端的过程)。本文主要为大家图文详细介绍Windows10下informatica powercenter 9.6.1安装与配置步骤。文章到这里就结束了,本人是在虚拟机中装了一套win10然后在此基础上测试安装的这些软件,因为工作学习要分开嘛哈哈哈。!!!!!_informatica客户端安装教程
文章浏览阅读7.8w次,点赞245次,收藏2.9k次。111个Python数据分析实战项目,代码已跑通,数据可下载_python数据分析项目案例
文章浏览阅读1.9k次,点赞61次,收藏64次。TDH企业级一站式大数据基础平台致力于帮助企业更全面、更便捷、更智能、更安全的加速数字化转型。通过数年时间的打磨创新,已帮助数千家行业客户利用大数据平台构建核心商业系统,加速商业创新。为了让大数据技术得到更广泛的使用与应用从而创造更高的价值,依托于TDH强大的技术底座,星环科技推出TDH社区版(Transwarp Data Hub Community Edition)版本,致力于为企业用户、高校师生、科研机构以及其他专业开发人员提供更轻量、更简单、更易用的数据分析开发环境,轻松应对各类人员数据分析需求。_星环tdh没有hive
文章浏览阅读836次,点赞21次,收藏19次。
文章浏览阅读1k次,点赞21次,收藏15次。主要介绍ETL相关工作的一些概念和需求点
文章浏览阅读1.4k次。本文以Android、java为开发技术,实现了一个基于Android的博物馆线上导览系统 app。基于Android的博物馆线上导览系统 app的主要使用者分为管理员和用户,app端:首页、菜谱信息、甜品信息、交流论坛、我的,管理员:首页、个人中心、用户管理、菜谱信息管理、菜谱分类管理、甜品信息管理、甜品分类管理、宣传广告管理、交流论坛、系统管理等功能。通过这些功能模块的设计,基本上实现了整个博物馆线上导览的过程。
文章浏览阅读897次,点赞19次,收藏26次。1.背景介绍在当今的数字时代,数据已经成为企业和组织中最宝贵的资源之一。随着互联网、移动互联网和物联网等技术的发展,数据的产生和收集速度也急剧增加。这些数据包括结构化数据(如数据库、 spreadsheet 等)和非结构化数据(如文本、图像、音频、视频等)。这些数据为企业和组织提供了更多的信息和见解,从而帮助他们做出更明智的决策。业务智能(Business Intelligence,BI)...
文章浏览阅读932次,点赞22次,收藏16次。也就是说,一个类应该对自己需要耦合或调用的类知道的最少,类与类之间的关系越密切,耦合度越大,那么类的变化对其耦合的类的影响也会越大,这也是我们面向对象设计的核心原则:低耦合,高内聚。优秀的架构和产品都是一步一步迭代出来的,用户量的不断增大,业务的扩展进行不断地迭代升级,最终演化成优秀的架构。其根本思想是强调了类的松耦合,类之间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会波及有关系的类。缓存,从操作系统到浏览器,从数据库到消息队列,从应用软件到操作系统,从操作系统到CPU,无处不在。
文章浏览阅读937次,点赞22次,收藏23次。大数据可视化是关于数据视觉表现形式的科学技术研究[9],将数据转换为图形或图像在屏幕上显示出来,并进行各种交互处理的理论、方法和技术。将数据直观地展现出来,以帮助人们理解数据,同时找出包含在海量数据中的规律或者信息,更多的为态势监控和综合决策服务。数据可视化是大数据生态链的最后一公里,也是用户最直接感知数据的环节。数据可视化系统并不是为了展示用户的已知的数据之间的规律,而是为了帮助用户通过认知数据,有新的发现,发现这些数据所反映的实质。大数据可视化的实施是一系列数据的转换过程。