当前位置: 首页 > article >正文

机器学习加州房价预测模型报告

目录

1.项目概述

1.1划定问题

1.2选择性能指标

2.获取数据

2.1创建工作环境

2.2下载数据

2.3查看数据结构

3.发现并可视化数据,发现规律

3.1地理数据可视化 

3.2查找关联 

3.3属性组合试验

4.为机器学习算法准备数据

4.1数据清洗 

4.2处理文本和分类属性 

4.3自定义转换量 

4.4特征缩放

4.5转换Pipeline

5.选择模型,进行训练

5.1在训练集上训练和评估

5.2使用交叉验证做更佳的评估

5.3尝试新方法:随机森林 

6.微调模型

6.1网格搜索

6.2随机搜索

 6.3集成方法

6.4分析最佳模型和它们的误差

7.给出解决方案

8.个人心得体会


1.项目概述

任务是利用加州普查数据,建立一个加州房价模型。这个数据包含每个分区组的人口、收入中位数、房价中位数等指标。分区组是美国调查局发布样本数据的最小地理单位(一个分区通常有600到3000人)。我们将其简称为“分区”。你的模型要利用这个数据进行学习,然后根据其它指标,预测任何分区的的房价中位数。

1.1划定问题

首先,你需要划定问题:监督或非监督,还是强化学习?这是个分类任务、回归任务,还是其它的?要使用批量学习还是线上学习?

答:这是一个典型的监督学习任务,因为你要使用的是有标签的训练样本(每个实例都有预定的产出,即分区的房价中位数)。并且,这是一个典型的回归任务,因为你要预测一个值。讲的更细些,这是一个多变量回归问题,因为系统要使用多个变量进行预测(要使用分区的人口,收入中位数等等)。最后,没有连续的数据流进入系统,没有特别需求需要对数据变动作出快速适应。数据量不大可以放到内存中,因此批量学习就够了。

1.2选择性能指标

下一步是选择性能指标。回归问题的典型指标是均方根误差(RMSE)。均方根误差测量的是系统预测误差的标准差。计算RMSE的计算方法如下:

虽然大多数时候RMSE是回归任务可靠的性能指标,在有些情况下,你可能需要另外的函数。例如,假设存在许多异常的分区。此时,你可能需要使用绝对平均误差(Mean Absolute Error,也称作平均绝对偏差。MAE的计算如下:

2.获取数据

2.1创建工作环境

我的工作环境是Jupyter notebook,使用python3.0版本,安装Python模块:Jupyter、NumPy、Pandas、Matplotlib和Scikit-Learn。

2.2下载数据

然后使用Pandas加载数据: 

2.3查看数据结构

使用DataFrame的head()方法查看该数据集的顶部5行。

housing = load_housing_data()

housing.head()

每一行都表示一个分区。共有10个属性(截图中可以看到6个):经度、维度、房屋年龄中位数、总房间数、卧室数量、人口数、家庭数、收入中位数、房屋价值中位数、大海距离。

info()方法可以快速查看数据的描述,包括总行数、每个属性的类型和非空值的数量。

housing.info()

所有的属性都是数值的,除了大海距离这项。它的类型是对象,因此可以包含任意Python对象,但是因为是从CSV文件加载的,所以必然是文本。当查看顶部的五行时,你可能注意到那一列的值是重复的,意味着它可能是一个分类属性。可以使用value_counts()方法查看都有什么类型,每个类都有多少分区:

housing["ocean_proximity"].value_counts()

 

describe()方法展示了数值属性的概括:

housing.describe()

count、mean、min和max几行的意思很明了。注意,空值被忽略了(所以,卧室总数是20433而不是20640)。std是标准差(揭示数值的分散度)。25%、50%、75%展示了对应的分位数:每个分位数指明小于这个值,且指定分组的百分比。例如,25%的分区的房屋年龄中位数小于18,而50%的小于29,75%的小于37。

另一种快速了解数据类型的方法是画出每个数值属性的柱状图。柱状图(的纵轴)展示了特定范围的实例的个数。你还可以一次给一个属性画图,或对完整数据集调用hist()方法,后者会画出每个数值属性的柱状图。

2.4创建测试集

纯随机采样测试集

1.自己编写代码,设置随机数生成器的种子(比如np.random.seed(42)),以产生总是相同的混合指数(shuffled indices)

 

 

2.使用hash

 

 如果使用行索引作为唯一识别码,你需要保证新数据放到现有数据的尾部,且没有行被深处。如果做不到,则可以用最稳定的特征来创建唯一识别码。例如,一个区的维度和经度在几百万年之内是不变的,所以可以将两者结合成一个ID:

 

3.sklean实现

 

分层采样的测试集

当你的数据集很大时(尤其是和属性数相比),这通常可行;但如果数据集不大,就会有采样偏差的风险。当一个调查公司想要对1000个人进行调查,它们不是在电话亭里随机选1000个人出来。调查公司要保证这1000个人对人群整体有代表性。例如,美国人口的51.3%是女性,48.7%是男性。所以在美国,严谨的调查需要保证样本也是这个比例:513名女性,487名男性。这称作分层采样(stratified sampling):将人群分成均匀的子分组,称为分层,从每个分层取出合适数量的实例,以保证测试集对总人数有代表性。

假设专家告诉你,收入中位数是预测房价中位数非常重要的属性。你可能想要保证测试集可以代表整体数据集中的多种收入分类。因为收入中位数是一个连续的数值属性,你首先需要创建一个收入分类属性。大多数的收入中位数的值聚集在2-5(一万美元),但是一些收入中位数会超过6。数据集中的每个分层都要有足够的实例位于你的数据中,这点很重要。否则,对分层重要性的评估就会有偏差。这意味着,你不能有过多的分层,且每个分层都要足够大。后面的代码通过将收入中位数除以1.5(以限制收入分类的数量),创建了一个收入分类属性,用ceil对值舍入(以产生离散的分类),然后将所有大于5的分类归入到分类5:

根据收入分类,使用Scikit-Learn的StratifiedShuffleSplit类进行分层采样:

在测试集和完整的房产数据集中查看收入分类比例:

 

对比了总数据集、分层采样的测试集、纯随机采样测试集的收入分类比例。可以看到,分层采样测试集的收入分类比例与总数据集几乎相同,而随机采样数据集偏差严重。

 

 

删除income_cat属性,使数据回到初始状态:

我们用了大量时间来生成测试集的原因是:测试集通常被忽略,但实际是机器学习非常重要的一部分。还有,生成测试集过程中的许多思路对于后面的交叉验证讨论是非常有帮助的。

3.发现并可视化数据,发现规律

首先,保证你将测试集放在了一旁,只是研究训练集。另外,如果训练集非常大,你可能需要再采样一个探索集,保证操作方便快速。在我们的案例中,数据集很小,所以可以在全集上直接工作。创建一个副本,以免损伤训练集:

housing = strat_train_set.copy()

3.1地理数据可视化 

因为存在地理信息(纬度和经度),创建一个所有分区的散点图来数据可视化是一个不错的主意。

housing.plot(kind="scatter", x="longitude", y="latitude", alpha=0.1)

 

可以非常清楚地看到高密度区域,湾区、洛杉矶和圣迭戈,以及中央谷,特别是从萨克拉门托到弗雷斯诺。现在来看房价,每个圈的半径表示分区的人口(选项s),颜色代表价格(选项c)。我们用预先定义的颜色图(选项cmap)jet,它的范围是从蓝色(低价)到红色(高价): 

 

 

这张图说明房价和位置(比如,靠海)和人口密度联系密切,这点你可能早就知道。可以使用聚类算法来检测主要的聚集,用一个新的特征值测量聚集中心的距离。海洋距离属性也可能有用,尽管北加州海岸区域的房价并不高,所以这不是一个简单的规则。 

3.2查找关联 

1.因为数据集并不是非常大,你可以很容易地使用corr()方法计算出每对属性间的标准相关系数(也称作皮尔逊相关系数):

 

 

相关系数的范围是-1到1。当接近1时,意味强正相关;例如,当收入中位数增加时,房价中位数也会增加。当相关系数接近-1时,意味强负相关;你可以看到,纬度和房价中位数有轻微的负相关性(即,越往北,房价越可能降低)。最后,相关系数接近0,意味没有线性相关性。 

2.另一种检测属性间相关系数的方法是使用Pandas的scatter_matrix函数,它能画出每个数值属性对每个其它数值属性的图。因为现在共有11个数值属性,你可以得到112=121张图,在一页上画不下,所以只关注几个和房价中位数最有可能相关的属性。

 

 

如果pandas将每个变量对自己作图,主对角线(左上到右下)都会是直线图。所以Pandas展示的是每个属性的柱状图(也可以是其它的,请参考Pandas文档)。

最有希望用来预测房价中位数的属性是收入中位数,因此将这张图放大:

 

这张图说明了几点。首先,相关性非常高;可以清晰地看到向上的趋势,并且数据点不是非常分散。第二,我们之前看到的最高价,清晰地呈现为一条位于500000美元的水平线。这张图也呈现了一些不是那么明显的直线:一条位于450000美元的直线,一条位于350000美元的直线,一条在$280000的线,和一些更靠下的线。你可能希望去除对应的分区,以防止算法重复这些巧合。

3.3属性组合试验

给算法准备数据之前,你需要做的最后一件事是尝试多种属性组合。例如,如果你不知道某个分区有多少户,该分区的总房间数就没什么用。你真正需要的是每户有几个房间。相似的,总卧室数也不重要:你可能需要将其与房间数进行比较。每户的人口数也是一个有趣的属性组合。让我们来创建这些新的属性:

 

 

与总房间数或卧室数相比,新的bedrooms_per_room属性与房价中位数的关联更强。显然,卧室数/总房间数的比例越低,房价就越高。每户的房间数也比分区的总房间数的更有信息,很明显,房屋越大,房价就越高。 

4.为机器学习算法准备数据

回到清洗训练集(通过再次复制strat_train_set),将预测量和标签分开,因为我们不想对预测量和目标值应用相同的转换(注意copy()创建了一份数据的备份,而不影响strat_train_set):

 

4.1数据清洗 

大多机器学习算法不能处理特征丢失,因此先创建一些函数来处理特征丢失的问题。前面,你应该注意到了属性total_bedrooms有一些缺失值。有三个解决选项:

  1. 去掉对应的分区;
  2. 去掉整个属性;
  3. 进行赋值(0、平均值、中位数等等)。

用DataFrame的dropna(), drop(),和 fillna()方法,可以方便地实现:

 

如果选择选项3,你需要计算训练集的中位数,用中位数填充训练集的缺失值,不要忘记保存该中位数。后面用测试集评估系统时,需要替换测试集中的缺失值,也可以用来实时替换新数据中的缺失值。

Scikit-Learn提供了一个方便的类来处理缺失值:Imputer。下面是其使用方法:首先,需要创建一个Imputer实例,指定用该属性的中位数替换它的每个缺失值:

 

因为只有数值属性才能算出中位数,我们需要创建一份不包括文本属性ocean_proximity的数据副本:

housing_num = housing.drop("ocean_proximity", axis=1)

 现在,就可以用fit()方法将imputer实例拟合到训练数据:

imputer.fit(housing_num)

imputer计算出了每个属性的中位数,并将结果保存在了实例变量statistics_中。只有属性total_bedrooms有缺失值,但是我们要确保一旦系统运行起来,新的数据中没有缺失值,所以安全的做法是将imputer应用到每个数值。使用这个“训练过的”imputer来对训练集进行转换,通过将缺失值替换为中位数:

X = imputer.transform(housing_num)

结果是一个普通的Numpy数组,包含有转换后的特征。如果你想将其放回到Pandas DataFrame中,也很简单:

housing_tr = pd.DataFrame(X, columns=housing_num.columns)

4.2处理文本和分类属性 

我们丢弃了分类属性ocean_proximity,因为它是一个文本属性,不能计算出中位数。大多数机器学习算法更喜欢和数字打交道,所以让我们把这些文本标签转换为数字。

Scikit-Learn为这个任务提供了一个转换量LabelEncoder:

 

查看映射表,编码器是通过属性classes_来学习的(“<1H OCEAN”被映射为0,“INLAND”被映射为1,等等):

 

显然这样不对(比如,分类0和4比0和1更相似)。要解决这个问题,一个常见的方法是给每个分类创建一个二元属性:当分类是“<1H OCEAN”,该属性为1(否则为0),当分类是“INLAND”,另一个属性等于1(否则为0),以此类推。这称作独热编码,因为只有一个属性会等于1(热),其余会是0(冷)。

使用类LabelBinarizer,我们可以用一步执行这两个转换(从文本分类到整数分类,再从整数分类到独热矢量):

 

 

4.3自定义转换量 

尽管Scikit-Learn提供了许多有用的转换量,你还是需要自己动手写转换量执行任务,比如自定义的清理操作,或属性组合。你需要让自制的转换量与Scikit-Learn组件(比如pipeline)无缝衔接工作,因为Scikit-Learn是依赖鸭子类型的(而不是继承),你所需要做的是创建一个类并执行三个方法:fit()(返回self),transform(),和fit_transform()。通过添加TransformerMixin作为基类,可以很容易地得到最后一个。另外,如果你添加BaseEstimator作为基类(且构造器中避免使用*args和**kargs),你就能得到两个额外的方法(get_params()和set_params()),二者可以方便地进行超参数自动微调。例如,一个小转换量类添加了上面讨论的属性:

 

4.4特征缩放

数据要做的最重要的转换之一是特征缩放。除了个别情况,当输入的数值属性量度不同时,机器学习算法的性能都不会好。这个规律也适用于房产数据:总房间数分布范围是6到39320,而收入中位数只分布在0到15。不需要对目标值进行缩放。

有两种常见的方法可以让所有的属性有相同的量度:线性函数归一化(Min-Max scaling)和标准化(standardization)。

线性函数归一化(许多人称其为归一化(normalization))很简单:值被转变、重新缩放,直到范围变成0到1。我们通过减去最小值,然后再除以最大值与最小值的差值,来进行归一化。Scikit-Learn提供了一个转换量MinMaxScaler来实现这个功能。它有一个超参数feature_range,可以让你改变范围,如果不希望范围是0到1。

标准化就很不同:首先减去平均值(所以标准化值的平均值总是0),然后除以方差,使得到的分布具有单位方差。与归一化不同,标准化不会限定值到某个特定的范围,这对某些算法可能构成问题(比如,神经网络常需要输入值得范围是0到1)。但是,标准化受到异常值的影响很小。例如,假设一个分区的收入中位数是100。归一化会将其它范围是0到15的值变为0-0.15,但是标准化不会受什么影响。Scikit-Learn提供了一个转换量StandardScaler来进行标准化。

4.5转换Pipeline

你已经看到,存在许多数据转换步骤,需要按一定的顺序执行。幸运的是,Scikit-Learn提供了类Pipeline,来进行这一系列的转换。下面是一个数值属性的小pipeline,将替换缺失值、添加属性、替换文本值为数值的操作结合在一起

 

5.选择模型,进行训练

5.1在训练集上训练和评估

  1. 线性回归模型

 

大多数分区的median_housing_values位于120000美元到265000美元之间,因此预测误差$68628不能让人满意。这是一个模型欠拟合训练数据的例子。当这种情况发生时,意味着特征没有提供足够多的信息来做出一个好的预测,或者模型并不强大。就像前一章看到的,修复欠拟合的主要方法是选择一个更强大的模型,给训练算法提供更好的特征,或去掉模型上的限制。这个模型还没有正则化,所以排除了最后一个选项。你可以尝试添加更多特征(比如,人口的对数值),但是首先让我们尝试一个更为复杂的模型,看看效果。

  1. 决策树

训练一个DecisionTreeRegressor。这是一个强大的模型,可以发现数据中复杂的非线性关系。代码:

 

 没有误差?这个模型可能是绝对完美的吗?当然,更大可能性是这个模型严重过拟合数据。

5.2使用交叉验证做更佳的评估

评估决策树模型的一种方法是用函数train_test_split来分割训练集,得到一个更小的训练集和一个验证集,然后用更小的训练集来训练模型,用验证集来评估。这需要一定工作量,并不难而且也可行。

另一种更好的方法是使用Scikit-Learn的交叉验证功能。下面的代码采用了K折交叉验证(K-fold cross-validation):它随机地将训练集分成十个不同的子集,成为“折”,然后训练评估决策树模型10次,每次选一个不用的折来做评估,用其它9个来做训练。结果是一个包含10个评分的数组:

 

 决策树的结果:

 

计算线性回归模型的的相同分数 :

 

判断没错:决策树模型过拟合很严重,它的性能比线性回归模型还差。

5.3尝试新方法:随机森林 

 

随机森林看起来很有希望。但是,训练集的评分仍然比验证集的评分低很多。解决过拟合可以通过简化模型,给模型加限制(即,规整化),或用更多的训练数据。 

6.微调模型

6.1网格搜索

微调的一种方法是手工调整超参数,直到找到一个好的超参数组合。这么做的话会非常冗长,你也可能没有时间探索多种组合。

使用Scikit-Learn的GridSearchCV来做这项搜索工作。你所需要做的是告诉GridSearchCV要试验有哪些超参数,要试验什么值,GridSearchCV就能用交叉验证试验所有可能超参数值的组合。例如,下面的代码搜索了RandomForestRegressor超参数值的最佳组合:

 

param_grid告诉Scikit-Learn首先评估所有的列在第一个dict中的n_estimators和max_features的3 × 4 = 12种组合(不用担心这些超参数的含义,会在第7章中解释)。然后尝试第二个dict中超参数的2 × 3 = 6种组合,这次会将超参数bootstrap设为False而不是True(后者是该超参数的默认值)。总之,网格搜索会探索12 + 6 = 18种RandomForestRegressor的超参数组合,会训练每个模型五次(因为用的是五折交叉验证)。换句话说,训练总共有18 × 5 = 90轮!折将要花费大量时间,完成后,你就能获得参数的最佳组合。

grid_search.best_params_

 

还能直接得到最佳的估计量:

grid_search.best_estimator_

也可以得到评估值:

 

 

6.2随机搜索

当探索相对较少的组合时,就像前面的例子,网格搜索还可以。但是当超参数的搜索空间很大时,最好使用RandomizedSearchCV。这个类的使用方法和类GridSearchCV很相似,但它不是尝试所有可能的组合,而是通过选择每个超参数的一个随机值的特定数量的随机组合。这个方法有两个优点:

  1. 如果你让随机搜索运行,比如1000次,它会探索每个超参数的1000个不同的值(而不是像网格搜索那样,只搜索每个超参数的几个值)。
  2. 你可以方便地通过设定搜索次数,控制超参数搜索的计算量。

 6.3集成方法

另一种微调系统的方法是将表现最好的模型组合起来。组合(集成)之后的性能通常要比单独的模型要好(就像随机森林要比单独的决策树要好),特别是当单独模型的误差类型不同时。

6.4分析最佳模型和它们的误差

通过分析最佳模型,常常可以获得对问题更深的了解。比如,RandomForestRegressor可以指出每个属性对于做出准确预测的相对重要性:

feature_importances = grid_search.best_estimator_.feature_importances_

 

将重要性分数和属性名放到一起:

 有了这个信息,你就可以丢弃一些不那么重要的特征(比如,显然只要一个分类ocean_proximity就够了,所以可以丢弃掉其它的)。

有了这个信息,你就可以丢弃一些不那么重要的特征(比如,显然只要一个分类ocean_proximity就够了,所以可以丢弃掉其它的)。 

7.给出解决方案

用测试集评估系统:

调节完系统之后,你终于有了一个性能足够好的系统。现在就可以用测试集评估最后的模型了。这个过程没有什么特殊的:从测试集得到预测值和标签,运行full_pipeline转换数据(调用transform(),而不是fit_transform()!),再用测试集评估最终模型:

 

8.个人心得体会

作为一个机器学习项目实验的入门者,我从自己的实际经验中总结了以下几个关键步骤和体会:

确定问题和目标:在开始实验之前,需要明确问题的定义和实验的目标。明确你想要解决的问题,并设定实验的目标和衡量指标。这将有助于确定实验的方向和评估实验结果。

数据准备和探索:数据是机器学习实验的核心。在进行实验之前,你需要对数据进行准备和探索。这包括数据清洗、缺失值处理、特征选择、特征工程和数据可视化等。通过这些步骤,你可以更好地理解数据,并为后续的建模和评估做好准备。

模型选择和建模:根据问题的类型和数据的特点,选择适合的机器学习模型。这可能包括分类模型、回归模型、聚类模型等。选择合适的模型后,你需要构建模型并进行训练。根据需要,你还可以进行模型调参和优化,以提高模型的性能。

实验评估和结果分析:在完成模型训练后,需要评估实验的结果。这涉及使用适当的指标进行模型评估,并分析实验结果。可以比较不同模型的性能,分析模型的优劣以及找出模型的局限性和改进空间。

结果解释和应用:在对实验结果进行分析后,需要解释实验结果并根据需要进行应用。这可能包括解释模型的预测结果和特征的重要性,并识别如何将实验结果应用到实际问题中。

持续学习和改进:机器学习是一个不断发展和演进的领域,需要保持学习的态度,不断更新自己的知识和技能。参与学术论坛、参加讨论小组、阅读最新的研究成果等都是提升自己的有效途径。


http://www.kler.cn/a/509535.html

相关文章:

  • RabbitMQ基础篇
  • [计算机网络]一. 计算机网络概论第一部分
  • AV1视频编解码简介、码流结构(OBU)
  • Spark任务提交流程
  • 光伏储能电解水制氢仿真模型Matlab/Simulink
  • iOS - TLS(线程本地存储)
  • 华为数据中心CE系列交换机级联M-LAG配置示例
  • 13-1类与对象
  • 【21】Word:德国旅游业务❗
  • 游戏引擎学习第81天
  • 探索 Transformer²:大语言模型自适应的新突破
  • wow-agent---task2使用llama-index创建Agent
  • Ubuntu 空闲硬盘挂载到 文件管理器的 other locations
  • Apache 如何设置 Upgrade-Insecure-Requests 报头 ?
  • 用于零镜头视频对象分割的深度感知测试时训练
  • PyTorch基本功能与实现代码
  • 浙江安吉成新照明电器:Acrel-1000DP 分布式光伏监控系统应用探索
  • vector迭代器的使用以及迭代器失效
  • 非科班转码第5年零241天
  • STM32 物联网智能家居 (五) 设备子系统之点亮LED灯
  • wireshark 网络分析工具
  • 1.5 GPT 模型家族全解析:从 GPT-1 到 GPT-4 的演进与创新
  • Scrapy 爬取 Bangumi 网站的分页与详情页数据
  • unity——Preject3——摄像机动画
  • Java并发05 - AQS共享模式的数据结构
  • windows 搭建flutter环境,开发windows程序