USER
具体概括下面使用的数据、特征、解决的问题、统计方法和分析过程中有什么发现,及如何发现的:!pip安装mllibs
收集mllibs下载mllibs-0.0.1-py2.py3-none-any.whl(12 kB)安装收集的软件包:mllibs成功安装mllibs-0.0.1警告:您正在使用pip版本20.2.4;但是,版本23.1可用。您应该考虑通过'/opt/conda/bin/python3.7 -m pip install --upgrade pip'命令进行升级。
unfold_more显示隐藏的单元格
unfold_more显示隐藏代码
1 | 导言
问题陈述
有很多因素会影响房屋财产的价值(例如位置、大小、条件、时间),这些因素可能会因房产而发生相当大的变化
房地产市场本身是一个相当动荡的行业,非常依赖需求和供应波动,更不用说利率和通货膨胀等经济因素了,因此预测价格随时间变化是一个相当大的挑战
由于可用的数据有限,预测房价也相当具有挑战性,大多数数据集包含与每个房产相关的功能数量有限,这就是为什么特征工程非常重要
因此,考虑到影响房地产的所有因素,通常很难准确预测房地产价格
加州住房数据集包含位于加利福尼亚州的房产的不同房屋相关属性
学习目标
建模的目的是预测中median_house_value,这是我们的目标变量
通过基本的无监督学习数据估算来克服缺失的数据
识别数据集中的异常值
了解如何将一个简单的模型变成您自己的sklearn可比类,我们的目标不是创建最完美的模型
笔记本封面
介绍基本的ML原则,如missing data、scaling、feature engineering、outliers、
sklearn兼容类、model exploration和model modification的基本介绍,试图改进我们的模型
模型选择
我们将使用现有模型;类结构中的Bayesian Linear Regression,可以与sklearn的Pipeline和cross validation选项一起使用,因此我们可以在这里使用它。
2 | 数据准备
2.1 | 加载数据集
df.info(),describe(),head()可能是我们可能想要检查熊猫数据帧的第一批东西之一;分别显示特征名称、限制/统计和几列,以获得对数据的初步印象
我对原始数据集进行了一些小幅调整,并从除两个坐标特征外的所有特征中提取了一些随机数据,因此我们可以进行一些数据估算,数据集位于下方,即使它没有公开。
# 加载数据集
df = pd.read_csv('/kaggle/input/calihouse/housing.csv')
df.info()
<类'pandas.core.frame.DataFrame'>范围索引:20640个条目,0到20639数据列(共9列):# 列非空计数D类型--- ------ ------------ -----0经度20640非空浮子641 纬度 20640 非空浮点642 housing_median_age 20637 non-null float643 total_rooms 20635 non-null float644 total_bedrooms 20429 non-null float645 人口 20628 非空浮点646户20630非空浮动647中位数_收入20631非空浮动648 median_house_value 20632 非空浮子64dtypes:float64(9)内存使用量:1.4 MB
df.head()
经度 纬度 住房_中位数年龄 总房间 总卧室 人口 家庭 收入中位数 中位数_房子_价值
0 -122.23 37.88 41.0 880.0 129.0 322.0 126.0 8.3252 452600.0
1 -122.22 37.86 21.0 7099.0 1106.0 2401.0 1138.0 8.3014 358500.0
2 -122.24 37.85 52.0 1467.0 190.0 496.0 177.0 7.2574 352100.0
3 -122.25 37.85 52.0 1274.0 235.0 558.0 219.0 5.6431 341300.0
4 -122.25 37.85 52.0 1627.0 280.0 565.0 259.0 3.8462 342200.0
.info()也许是一个很好的起点,将数据读取并加载到熊猫数据框架中
RangeIndex告诉我们最大加载的数据,因此我们可以快速识别缺少数据的列
pandas可以读取各种数据类型;因此Dtype信息非常方便了解
.head()是我们数据集峰值的好方法,.tail也是滚动到数据集底部的快速方法
#让我们也显示所有缺少数据的列:
df[df.isnull().any(axis=1)] # 列中任何缺失的数据
经度 纬度 住房_中位数年龄 总房间 总卧室 人口 家庭 收入中位数 中位数_房子_价值
290 -122.16 37.77 47.0 1256.0 NaN 570.0 218.0 4.3750 161900.0
341 -122.17 37.75 38.0 992.0 NaN 732.0 259.0 1.6196 85100.0
532 -122.27 37.78 52.0 1408.0 NaN 718.0 265.0 2.6806 207900.0
538 -122.28 37.78 29.0 5154.0 NaN 3741.0 1273.0 2.5762 173400.0
563 -122.24 37.75 45.0 891.0 NaN 384.0 146.0 4.9489 247100.0
... ... ... ... ... ... ... ... ... ...
20268 -119.18 34.19 19.0 2393.0 NaN 1938.0 762.0 1.6953 167400.0
20372 -118.88 34.17 15.0 4260.0 NaN 1701.0 669.0 5.1033 410700.0
20460 -118.75 34.29 17.0 5512.0 NaN 2734.0 814.0 6.6073 258100.0
20484 -118.72 34.28 17.0 3051.0 NaN 1705.0 495.0 5.7376 218600.0
20566 -121.84 38.65 29.0 NaN 548.0 1554.0 534.0 4.3487 200700.0
257行×9列
2.2 | 数据估算
我们可以注意到,我们有一些功能,其中缺少一些数据,但总体上没有太多的实例(257/20640);
让我们尝试基于kNN模型的Unsupervised Learning (UL)方法,我们可以使用下面的函数,并传递一个数据帧来生成一个估算的数据帧
kNN无监督学习估算
使用无监督模型来忽视丢失的数据的功能。
从sklearn.neighbors导入KNeighborsRegressor
# 赋予数据帧的函数
def impute_knn(df):
'''输入:熊猫df包含特征矩阵'''
'''输出:NaN归因的数据帧'''
#使用KNN无监督方法进行估算
#将数据帧分离成数字/分类
ldf = df.select_dtypes(include=[np.number]) # 在df中选择数字列
ldf_putaside = df.select_dtypes(exclude=[np.number]) # 在df中选择分类列
#定义列w/和w/o丢失数据
cols_nan = ldf.columns[ldf.isna().any()].tolist() # columns w/ nan
cols_no_nan = ldf.columns.difference(cols_nan).values # columns w/o nan
对于col在cols_nan:
imp_test = ldf[ldf[col].isna()] # 缺少数据的指标将成为我们的测试集
imp_train = ldf.dropna() # 没有丢失数据的所有指示
model = KNeighborsRegressor(n_neighbors=5) # KNR 无监督方法
knr = model.fit(imp_train[cols_no_nan], imp_train[col])
ldf.loc[df[col].isna(), col] = knr.predict(imp_test[cols_no_nan])
返回pd.concat([ldf,ldf_putaside],axis=1)
# 调用归因缺失数据的函数
df2 = impute_knn(df)
#看起来我们有一个完整的功能矩阵
df2.info()
<类'pandas.core.frame.DataFrame'>范围索引:20640个条目,0到20639数据列(共9列):# 列非空计数D类型--- ------ ------------ -----0经度20640非空浮子641 纬度 20640 非空浮点642 housing_median_age 20640 non-null float643 total_rooms 20640 non-null float644 total_bedrooms 20640 non-null float645人口20640非空浮标646户20640非空浮动647 中位数_收入 20640 非空浮点648 median_house_value 20640 non-null float64dtypes:float64(9)内存使用量:1.4 MB
2.3 | 创建保留集
彻底的整个数据集&没有新数据的可用性是不可取的。
我们想保留一些数据,并用它来看看模型对看不见的数据的预测有多好,所以让我们使用train_test_split
trdata:训练数据子集(让我们检查数据,就好像我们只有这个数据一样)
tedata:测试数据子集(使用此子集进行模型评估)
# 70/30 拆分应该做
trdata,tedata = train_test_split(df2,test_size=0.3,random_state=43)
3 | 探索性数据分析
我们想更多地了解我们的数据,这里进行了一种简单的数据探索方法
3.1 | 单变量直方图
让我们使用univariate analysis(分析1个变量)来查看我们的数据分布。我们可能会在直方图中寻找什么:
数据分布(某些模型更喜欢不那么倾斜的分布)
异常值(低噪声假设可能对模型性能有害)
数据中的奇异模式(数据异常也会影响模型性能)
轴比例(特征比例值会影响模型性能)
trdata.hist(bins=60, figsize=(15,9),color=color1);plt.show()
奇异模式和异常值
略微突出的数据分布:
第一印象是,我们的数据中存在一些异常值(与整套不一致)组;可能是由于数据采样的方式(“housing_median_age”和“median_house_value”)
House_median_age是具有此类异常值的一个可能特征。也有很多局部峰值(都是相当渐进的),但一个最大值的非常奇怪的峰值脱颖而出。它在数据中有一些轻微的不连续性(随着垃圾桶的调整而变得可见)
Feature Median_house_value在其最大值(约500k)处有一个奇数峰值,这可能是一个异常值。
不太明显的异常值
我们有相当多的倾斜(不太集中)的数据分布,6个特征有这样的分布,这相当多,而且有点令人担忧,因为我们将使用一个相对简单的模型。
其中一些特征的x轴范围相当广泛(例如population),表明我们有相当多的异常值,但与前两个不同,我们可以对特征进行transformation并尝试纠正它。
人口、total_bedrooms和total_rooms代表一些相互关联的东西,也有类似的分布,这偏离了较小的值。
3.2 | 二元相关矩阵
二元(两个特征)两个特征关系;correlation meature
非常快速地了解数据集。
相关矩阵仅包含有关两个特征关系线性相似性的信息
我们可能会寻找什么:
经常强调应该放弃too highly或too lowly correlated特征
数据集中的任何非线性迹象,例如相当多的低线性相关值
多个特征之间的高相关值可能表明特征可能代表类似的东西
unfold_more显示隐藏代码
corrMat(trdata) # 图掩蔽 numpy 相关矩阵
目标变量median_house_value与这里除一个特征外的所有特征都非常温和地相关:median_income,因此人们可能会将其概述为一个重要特征。
-0.02和-0.05(population/longitude)与目标变量median_house_value的相关性可能值得降低,但它们可能不值得。事实上,低值并不完全是放弃功能的理由。这可能只是意味着数据分布很大,这是非线性的有力指标。
通常建议放弃此类特征,特别是对于不太复杂的模型,因为该模型可能无法选择具有这种非线性的一个特征,更不用说多重了。
可以绘制一个移位矩阵,它看起来更好一点,代码可以在这里找到
3.3 | 二元散射数据
配对图/散射矩阵非常有洞察力,可用于查找有趣的散射盘无bivariate(两个特征数据图)关系
散点图允许添加color标签,但通常很难在散点矩阵中区分color标签
我们可能会寻找什么:
不规则的两个特征模式或异常值(多个特征可以更清楚地了解异常值)
二维数据集群(使用KDE近似)
二维空间中的两个特征线性相关值可视化(数据是线性或完全随机排序)
unfold_more显示隐藏代码
# Seaborn有点慢,让我们绘制一些有趣的功能
tlist = ['median_income','total_rooms','housing_median_age','latitude','median_house_value','population']
snsPairGrid(trdata[tlist])
与“Median_House_Value”相关
median_house_valuemedian_income关系看起来相当线性,与线性线有相当多的偏差,我们还可以注意到“中位数收入”所有值的可见上限,这在两个维度上看起来绝对不合时宜。
在median_house_age与median_house_value关系中,数据似乎完全分布在各个地方;KDE帮助识别两个峰值大约20年,也许这些峰值与增加可负担性有关(鉴于它们集中在下半部分)
我们注意到两个特征的峰值附近还有一个额外的峰值。这种关系是非常非线性的,分散在各处,在图表的几乎所有部分都有数据。
median_house_value& total_rooms,population似乎是相当复杂的建模特征,KDE表示,它高度集中在两者的较低值,在较大的值处相当多,主集群外有大量数据,可归类为outliers。
我们的许多功能具有完全不同的轴尺度,更高的值可能会被解释为更重要,因此绝对应该考虑缩放。
3.4 | 地理空间多变量数据
Multivariate可视化可能比bivariate更有洞察力。在散点数据中添加“色调”/颜色,使数据具有我们可以插入的额外维度,前提是重叠最小
地理绘图是这种可视化的一种形式。了解地理如何影响各种特征会很有趣。
我们正在处理地理数据,所以地盘非常有用,folium和情节也非常有用
您可能想添加的其他模块(主要用于3D)k3d和pyvista也非常适合多变量可视化。
unfold_more显示隐藏代码
trdata.info()
<类'pandas.core.frame.DataFrame'>Int64索引:14448个条目,11440至14148数据列(共9列):# 列非空计数D类型--- ------ ------------ -----0经度14448非空浮点641 纬度 14448 非空浮点642 housing_median_age 14448 non-null float643 total_rooms 14448 non-null float644 total_bedrooms 14448 non-null float645人口14448非空浮标646户14448非空浮动647中位数_收入14448非空浮动648 median_house_value 14448 non-null float64dtypes:float64(9)内存使用量:1.7 MB
# 绘制两个地理熊猫图的调用函数
plotTwo(trdata,['population','median_income'])
plotTwo(trdata,['housing_median_age','median_house_value'])
del trdata['geometry'] # 对gpd可视化以外的任何东西都没有用
For our target variable, median_house_value, just by looking at these graphs, one could immediately note some patterns; geography(location) and median_house_income show clear relation; generally increasing the closer you get to the two main clusters, so these two features would probably be important.
Housing_median_age对于许多地区来说,它也与目标变量密切相关,但在许多地区,它不是(稍微内陆一点),所以它不是那么清晰。这种关系可能只是非线性的。回顾对图,我们在数据中看到了相当多的传播,然而,人们可以注意到该图中的两个主要集群,这显示了一些线性方面。
Population有点棘手,它有点相关,尽管我们有一些异常值(甚至在单变量直方图上都不可见),这使得我们更难看到关系,因为值在<10k组中更拥挤,但确实倾向于存在关系,如correlation值所示。
4 | 审查外线
从对图数据中,我们注意到异常值的存在,这更像是一个手动识别过程,您可能对使用EllipticEnvelope的自动评估感兴趣,这是Chris Albon的食谱中的一个例子
异常 @ housing_median_age == 52
我们检查了数据集直方图,发现一个相当奇怪的集群,值为52,1D数据并不能很好地说明整个故事,当然,我们的直方图数据过渡相当稳定,但也许在今年,它非常实惠。2D对图倾向于显示这些数据比任何东西都更像一个约束,与其他数据(数据中的行)相比,看起来非常奇怪。总的来说,这并不完全是结论性的。
异常值 @ median_house_value == 500,001
与housing_median_age不同,非常怀疑的是,离群值峰值不是高于最大中位数_house_值的所有情况的分类定义的总和,让我们删除这个子集,并保留另一个子集。
不太显著的异常值
Having just plotted population in a multivariate plot, we would have noted how the scale created values that are barely visible to the eye, in fact, a model with poorly allocated weights to these outliers can sevely degrade in accuracy, one counter to these outliers is a weight function approach, such as Inverse Distance Weighting (IDW) in models such as Weighted Least Sqaures (WLS) or Covariance Functions in Gaussian Process Models, BR() unfortunately doesn't have this functionality, so we'll have to attempt a common approach known as skewness correction via feature transformation. I thought we'd give it a go and attempt to implement these functions into the BR() model as well, why not.
让我们通过简单地选择最大值(在这里工作)来删除median_house_value的异常值
# trdata_upd:带移除异常值的训练数据
maxval2 = trdata['median_house_value'].max() # 获取最大值
trdata_upd = trdata[trdata['median_house_value'] != maxval2]
tedata_upd = tedata[tedata['median_house_value'] != maxval2]
trdata_upd.hist(bins=60, figsize=(15,9),color=color1);plt.show() # 看起来完全删除了。
5 | 特征工程
创建和修改特征矩阵数据,Feature Engineering非常重要,是一个相当循环的过程,我们希望输入一个特征矩阵,以帮助教授模型一些有用的东西。
我们希望确保我们提供与目标变量预测最相关的模型数据,也许也尽可能减少重叠。
具有非常高相关性的特征多次教模型类似的东西,也许可以考虑梳理它们并放弃其他东西。
我们可以尝试的一些事情:
在这个问题上,我们没有很多功能可以玩,但我们注意到我们有一些非常相似的功能。让我们从中创建一个相对简单的组合,然后放弃其余的。
我们还将创建一个结合我们在多变量数据中看到的两个坐标的特征,在对角线上(更接近海洋和内陆)有一个相当稳定的变化关系。
# 制作一个同时包含长度和纬度的功能
trdata_upd['diag_coord'] = (trdata_upd['longitude'] + trdata_upd['latitude']) # 'diagonal coordinate', works for this coord
trdata_upd['bedperroom'] = trdata_upd['total_bedrooms']/trdata_upd['total_rooms'] # feature w/ bedrooms/room ratio
corrMat(trdata_upd)
#也更新测试数据
tedata_upd['diag_coord'] = (tedata_upd['longitude'] + tedata_upd['latitude'])
tedata_upd['bedperroom'] = tedata_upd['total_bedrooms']/tedata_upd['total_rooms'] # feature w/ bedrooms/room ratio
# 让我们也绘制他们
plotTwo(trdata_upd,['diag_coord','median_house_value'])
plotTwo(trdata_upd,['bedperroom','median_house_value'])
del trdata_upd['geometry'] # 删除gpd几何特征
我们可以从地图图中注意到diag_coord和目标变量的明确相关性(反相关)
另一方面,bedperroom并不像希望的那样有启发性,尽管如相关矩阵所示,它仍然是相关性更高的特征之一
6 | 定义自定义类ML模型
我们已经做了一些数据可视化,清理了异常值,并准备了一套现成的功能,我们将用于训练模型
所有评估功能都使用更简单的自动hyperparameter调优方法,但我也包括了网格搜索,以防有用。
6.1 | 贝叶斯线性回归
我们决定在这个问题中使用Bayesian Linear Regression模型。
您可以尝试用更高级的模型替换当前模型,解释和代码隐藏在下面。
贝叶斯线性回归的详细而有洞察力的解释取自Github
前期和后向分布
对于线性回归的贝叶斯处理,我们需要模型参数的先验概率分布w。出于简单起见,我们将使用参数上的各向同性高斯分布w平均值为零:
p(w|α)=(w|0,α−1I)(8)
各向同性高斯分布具有对角线协方差矩阵,其中所有对角线元素都具有相同的方差α−1(α是先验的精度)。零均值有利于参数的小值wj先验。先验与可能性并行p(t|w,β)这意味着后验分布具有与先验相同的功能形式,即也是高斯。在这个特殊情况下,后方有一个分析解决方案,有以下足够的统计数据
mNS−1N=βSNΦTt=αI+βΦTΦ(9)(10)
(9)是后部和后部的平均矢量(10)逆协方差矩阵(=精度矩阵)。因此,后验分布可以写成
p(w|t,α,β)=(w|mN,SN)(11)
目前,我们假设价值观α和β是已知的。由于后验与似然和先验的乘积成正比,后验分布的对数与对数似然和先验的对数之和成正比
logp(w|t,α,β)=−βED(w)−αEW(w)+const。(12)
地点ED(w)定义为(6)和
EW(w)=12wTw(13)
最大化日志后w.r.t.w给出最大后(MAP)估计值w。最大化对数后验相当于最小化平方和误差函数ED加上一个二次正则化项EW。这种特殊形式的正则化被称为L2正则化或重量衰减,因为它限制了重量的大小wj。正规化期限的贡献由比率决定α/β。
后验预测分布
为了做出预测t在一个新地点x我们使用后验预测分布,定义为
p(t|x,t,α,β)=∫p(t|x,w,β)p(w|t,α,β)dw(14)
后验预测分布包括参数的不确定性w通过加权条件分布进入预测p(t|x,w,β)权重的后验概率p(w|t,α,β)在整个重量参数空间上。通过使用预测分布,我们不仅获得了预期值t在一个新地点x还有那个预测的不确定性。在我们的特殊情况下,后验预测分布是高斯分布
p(t|x,t,α,β)=(t|mTNφ(x),σ2N(x))(15)
哪里意味着mTNφ(x)是之后的回归函数N观察和σ2N(x)是相应的预测方差
σ2N(x)=1β+φ(x)TSNφ(x)(16)
第一个学期(16)代表数据中的固有噪声,第二项涵盖了参数的不确定性w。到目前为止,我们已经假设了α和β是已知的。然而,在完全贝叶斯的处理中,我们应该定义先验α和β并使用相应的后验来额外包括关于α和β进入预测。不幸的是,所有三个参数都完全集成w,α和β在分析上难以处理,我们必须使用另一种方法。
证据功能
估计α和β也可以通过首先积分似然和先验参数的乘积来获得w
p(t|α,β)=∫p(t|w,β)p(w|α)dw(17)
然后最大化由此产生的边际似然或证据函数w.r.t。α和β。这种方法被称为经验贝叶斯。可以证明,这是完全贝叶斯治疗的一个很好的近似值,如果后方α和β在最可能的值周围急剧达到峰值,先验相对平坦,这通常是一个合理的假设。集成模型参数或使用良好的近似值,使我们能够估计值α和β,因此正则化强度α/β,仅从训练数据,即不使用验证集。
边际可能性的对数由
logp(t|α,β)=M2logα+N2logβ−E(mN)−12日志|S−1N|−N2log2π(18)
地点
E(mN)=β2‖t−ΦmN‖2+α2mTNmN(19)
为了完整性,证据、可能性、先验、后验之间的关系当然由贝叶斯定理给出
p(w|t,α,β)=p(t|w,β)p(w|α)p(t|α,β)(20)
最大化
最大化对数边际似然w.r.t.α和β给出了以下隐式解决方案。
α=γmTNmN(21)
和
1β=1N−γ∑i=1N(t我−mTNφ(x我))2(22)
地点
γ=∑i=0M−1λ我α+λ我(23)
和λ我是特征值βΦTΦ。解决方案是隐含的,因为α和γ以及β和γ相互依赖。解决方案α和β因此,可以通过从这些参数的初始值开始,然后遍及上述方程直到收敛来获得。
7 | 预测中位房屋价值的ML模型
7.1 | 基线贝叶斯回归模型
对于基本模型,让我们使用5倍交叉验证方法调查三件事:
最重要的是,让我们创建一个简单的基线模型,DummyRegressor()
我们有两个现成的数据帧,原始功能数据帧trdata和tradata_upd,以及另外两个功能。我们将在交叉验证中对所有BR()生成的模型使用自动调整的超参数(lamda和alpha)
此外,我们注意到几个功能(total_rooms,total_bedrooms,population)之间具有很高的相关性,因此了解删除其中一些功能是否会对模型性能产生任何影响很有趣
unfold_more显示隐藏代码
# 带交叉验证的模型评估
def modelEval(ldf,feature='median_house_value',model_id = 'dummy'):
#输入:功能和目标数据帧
#拆分功能/目标变量
y = ldf[功能].copy()
X = ldf.copy()
del X[功能] # 删除目标变量
# 挑选模型
if(model_id是'dummy'):model = DummyRegressor()
if(model_id is 'br'): model = BR(verbose=False)
if(model_id是'rf'):model = RandomForestRegressor(n_estimators=10,random_state=10)
'''基于参数的交叉验证(无管道)'''
# gscv = GridSearchCV(模型,param_grid,cv=5)
# gscv.fit(X,y)
# results = pd.DataFrame(gscv.cv_results_)
# scores = np.array(results.mean_test_score).reshape(7,7)
# # 绘制交叉验证平均分数
# heatmap1(scores,xlabel='lamda',xticklabels=param_grid['lamd'],
# ylabel='alpha',yticklabels=param_grid['alph'])
''' 标准交叉验证 '''
cv_score = np.sqrt(-cross_val_score(model,X,y,cv=5,scoring='neg_mean_squared_error'))
print("Scores:",cv_score);print("Mean:", cv_score.mean());print("std:", cv_score.std())
#一个简单的比较模型
modelEval(trdata,model_id='dummy')
分数:[116663.53235572 114143.42502379 115145.56368682 113864.46156817117200.05430992]平均:115403.40738888175std:1329.5298616480632
# 原始功能
modelEval(trdata,model_id='br')
分数:[75797.52378542 75349.23486214 76392.33891711 73783.9087415875561.49602675]平均值:75376.90046659937std:869.5404263856306
We can see that the BR() Linear Model performs as expected, much better than the baseline model, DummyRegressor(), a quick indicator that the model actually learns something meaningful
# 额外功能
modelEval(trdata_upd,model_id='br')
分数:[66353.36011913 67405.27346371 68388.66787427 66139.8159157166811.94056519]平均值:67019.8115876007std:810.4453955463844
添加两个新功能(diag_coord,bedperroom)极大地提高了模型的性能
#让我们删除三个相似功能中的两个
del trdata_upd['total_bedrooms']
del trdata_upd['total_rooms']
modelEval(trdata_upd,model_id='br')
分数:[66446.80203401 67491.60907266 68308.69503952 66232.6024444567210.32023912]平均:67138.005765951std:748.1037134542368
我们可以注意到,通过删除很大一部分高度相关的特征,对模型性能的影响最小,这表明这两个特征教会了模型与population非常相似的东西,并且不需要。
我们获得的唯一好处是减少训练代码,减少功能
7.2 | ML管道模型
Pipelines是将模型准备过程的多个步骤分组的非常整洁的方法,从feature matrix调整到实际模型评估步骤。Pipelines也用于防止data leakage。
让我们尝试使用Pipelines两件事:
我们注意到,我们的数据表现出非线性特征关系,因此我们将创建一个使用PolynomialFeatures()的简单管道,看看这是否有助于模型适应我们许多数据的非线性性质(我们将查看二阶和三阶特征)
我们还注意到,我们的功能具有非常不同的值范围,这可能是一个问题。除非所有功能都有类似的缩放,否则某些模型的性能不是很好,所以让我们看看BR()是否是这些模型之一。
unfold_more显示隐藏代码
#带管道的模型评估功能
def modelEval2(ldf,feature='median_house_value',model_id = 'dummy',scaling_id=False):
#给定一个数据帧,拆分特征/目标变量
y = ldf[功能].copy()
X = ldf.copy()
del X[功能] # 删除目标变量
tlst = []
对于我在[2,3]:
# 挑选模型
if(model_id是'dummy'):model = DummyRegressor()
if(model_id is 'br'): model = BR(verbose=False)
if(model_id是'rf'):model = RandomForestRegressor(n_estimators=10,random_state=10)
#选择管道(多项式特征调整+模型)
if(scaling_id为False):
管道=管道(步骤=[('poly',PolynomialFeatures(i)),
('模型',模型)])
其他:
pipe = Pipeline(steps=[('scaler',StandardScaler()),
('poly',多项式特征(i)),
('模型',模型)])
'''基于参数的交叉验证(带管道)'''
# 定义参数搜索网格,pipepines需要略有不同的符号w/ __
# param_grid = {
# 'model__lamd': [0.0001,0.001, 0.01, 0.1, 1, 10, 100],
# 'model__alph': [0.0001,0.001, 0.01, 0.1, 1, 10, 100]}
# gscv2 = GridSearchCV(pipe, param_grid,cv=5)
# gscv2.fit(X,y)
# ypred = gscv2.predict(X)
# results2 = pd.DataFrame(gscv2.cv_results_)
# scores2 = np.array(results2.mean_test_score).reshape(7,7)
# tlst.append(scores2)
''' 标准交叉验证 '''
cv_score = np.sqrt(-cross_val_score(pipe,X,y,cv=5,scoring='neg_mean_squared_error'))
print("Scores:",cv_score.round(2))
print("Mean:", cv_score.mean().round(2));print("std:", cv_score.std().round(2))
# 5个交叉验证段得分的图平均值
# heatmap2(tlst[0],tlst[1],xlabel='lamd', xticklabels=param_grid['model__lamd'],
# ylabel='alph', yticklabels=param_grid['model__alph'])
modelEval2(trdata_upd,model_id=“br”,scaling_id=False)
分数:[ 2992148.64 10408465.03 16934806.01 55638604.29 21297212.87]平均值:21454247.37std:18176240.89评分:[5.19452554e+07 3.05340738e+08 2.34006900e+08 2.19964003e+082.14349689e+08]平均值:205121317.05std:83242637.31
嗯,这并没有完全实现计划&我们获得了非常高的误差模型。可能的原因是特征缩放的不平衡。
让我们实际确认scaling是否可以解决这个问题:
modelEval2(trdata_upd,model_id='br',scaling_id=True)
分数:[57224.75 57147.77 58137.41 56240.81 56510.27]平均值:57052.2std:658.58分数:[56455.1 59809.27 89225.6 54031.27 67156.44]平均值:65335.54std:12737.65
有趣的是,随着二阶功能的添加,我们的准确性有了相当大的提高,然而三阶功能给我们带来了更糟糕的结果。
随着PolynomialFeatures()的添加,这是一个相当常见的现象。如果我们进一步增加订单,我们可能会得到改善,但这种方法存在一些小问题。
为了更有效地利用多项式特征,必须仔细管理输入模型的特征数量,并尽可能减少它们。矩阵反转的成本往往会有点过高,在这种限制下,最好使用更有效的东西,如高斯过程回归GP()来适应更复杂的数据,在更高维度上传播,没有PolynomialFeatures()
类BR()已经使用了伪反转,pinv()而不是标准矩阵反转,没有它,三阶可能会给我们一个奇异矩阵条件;表明模型对特征编号有明确的限制(您可以轻松确认这一点)
让我们快速检查一下我们的模型对一个非常常见和强大的ensemble模型RandomForest()的表现:
modelEval(trdata_upd,model_id='rf')
评分:[48078.93558134 48376.18009495 48989.2628633 47516.8455606648382.16223432]平均:48268.6772669145std:478.5252593847063
我们可以看到,即使是像RandomForest()这样非常强大的功能,也不能用当前功能和实例组合集进一步减少RMSE(尽管是一个很容易过度预测的模型)
在目标值的背景下,48,000的错误是相当大的,调查当前数据集的有效性并审查它可能是一个合理的想法
该数据集相当古老,不包含与最新数据集相比的最佳功能,如介绍性房价问题(这很有趣!),但希望人们能采取的基本方法是明确的。
linkcode
8 | 总结性评论
我们从一个包含missing data的数据集开始,我们研究了数据估算的unsupervised learning方法。
数据分析显示,我们的数据可能会给我们的模型带来问题,例如nonlinearity、skewness、large variation in range、too highly correlated features,仅举几例。
我们评估了基本特征模型,该模型不是很好,并继续尝试了各种改进模型:
添加了额外的功能
删除了没有教给模型任何新东西的功能
添加了PolynomialFeatures(),帮助模型适应数据的非线性性质
添加了功能缩放,将所有功能调整到类似的范围
我们获得了一个比我们开始时表现明显更好的模型,所以很高兴取得一些进展
其他可以尝试的事情是skewness correction和更彻底的特征基础影响分析