Python Scikit-Learn 实现机器学习线性回归预测房价
文章目录
前言
本教程在anaconda中的notebook进行实现,python版本3.10.9。
线性回归-房价数据,scikit-learn。
实验数据可在最上方的链接下载,如下图所示:
1.引入基本库
#导入所需要的库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
from sklearn.datasets import fetch_california_housing
from sklearn.linear_model import LinearRegression
2.读入数据
#sklearn中的california_housing数据,这里只做展示,相关教程可到sklearn中进行学习。
X, y = fetch_california_housing(return_X_y=True)
#真实数据,本实验主要针对该数据进行训练
cal_data = pd.read_csv('housing.csv')
为更好地扩展实验内容,在接下来的实验中,将采用真实数据cal_data 进行模型训练。
有关真实数据cal_data 数据的信息
- longitude,经度:房子向西多远的量度;越往西,数值越高
- latitude,纬度:衡量房子往北多远的尺度;越往北,数值越高
- housing_median_age:街区内房屋年龄的中位数;较低的数字代表较新的建筑
- total_rooms:一个街区内的房间总数
- total_bedrooms:一个街区内的卧室总数
- population,人口:居住在一个街区内的总人数
- households,住户:一个街区的住户总数,即居住在一个家庭单位内的一群人
- median_income:街区内住户收入中位数(以万美元计)
- median_house_value:街区内住户的房屋价值中位数(以美元计算)
- oceanProximity:房子靠近海洋/海洋的位置
3.划分数据集,并查看缺失值
把数据分成训练集和测试集。这是因为在数据分析和处理的过程中,可能会出现“数据泄露”,即不希望模型看到将要测试的数据。在模型训练时使用训练集,在模型评估时使用测试集。
from sklearn.model_selection import train_test_split
train_data, test_data = train_test_split(cal_data, test_size=0.1,random_state=20)
#检查数据中的缺失值
train_data.isnull().sum()
4.分析数据集中的特征关系
#检查特征之间的相关性,并进行热力图可视化
correlation = train_data.iloc[:,0:9].corr()#读取0-8列数据
plt.figure()
sns.heatmap(correlation,annot=True,cmap='crest')
绘制地理特征
既然有了经纬度,我们来画一下。它可以帮助我们知道某些房子在地图上的位置
plt.figure(figsize=(12,7))
sns.scatterplot(data = train_data, x='longitude', y='latitude')
画一下,地理位置对应的房价中位数对应图。
plt.figure(figsize=(12,7))
sns.scatterplot(data = train_data, x='longitude', y='latitude', hue='median_house_value')
再按照房子靠近海洋/海洋的位置进行可视化
plt.figure(figsize=(12,7))
sns.scatterplot(data = train_data, x='longitude', y='latitude', hue='ocean_proximity',
size='median_house_value')
5.划分出Y标签,并去除缺失值
training_input_data = train_data.drop('median_house_value', axis=1)
training_labels = train_data['median_house_value']
缺失值在现实世界的数据集中是不可避免的,所以知道如何处理它们是很好的。
在处理缺失值时,有三种选择:
- 完全移除它们
- 用不同的策略填充它们,如mean, median, frequency或constant。
- 让他们保持原样。大多数机器学习模型无法识别缺失值,因此它们无法处理缺失值,但有些模型不受缺失值的影响,例如基于树的算法。因为现在使用的是线性模型,所以这不是一个选择。
Sklearn提供了一个名为“SimpleImputer”的函数来填充缺失的值。这里将用相关特征的平均值填充这些值,还可以使用中位数或最常见的值。
from sklearn.impute import SimpleImputer
num_feats = training_input_data.drop('ocean_proximity', axis=1)
def handle_missing_values(input_data):
mean_imputer = SimpleImputer(strategy='mean')
num_feats_imputed = mean_imputer.fit_transform(input_data)
num_feats_imputed = pd.DataFrame(num_feats_imputed,
columns=input_data.columns, index=input_data.index )
return num_feats_imputed
num_feats_imputed = handle_missing_values(num_feats)
num_feats_imputed.isnull().sum()
6.编码分类特征
分类特征是具有分类值的特征。我们数据集中的一个例子是’ ocean_proximity ',它具有以下值。
training_input_data['ocean_proximity'].value_counts()
有很多方法可以处理分类特性,但在这个项目中,我们只看3种技术,即简单的Python映射、普通编码和一个热编码。Label和One Hot可以在Sklearn中轻松实现。
映射很简单。我们创建一个分类值及其相应数值的字典。然后,我们把它映射到分类特征上。
下面是它是如何实现的。
cat_feats = training_input_data['ocean_proximity']
feat_map = {
'<1H OCEAN': 0,
'INLAND': 1,
'NEAR OCEAN': 2,
'NEAR BAY': 3,
'ISLAND': 4
}
cat_feats_encoded = cat_feats.map(feat_map)
cat_feats_encoded.head()
One Hot Encoding
当类别没有任何顺序时,One Hot Encoding是最受欢迎的,这正是我们的分类特征的方式。这就是我所说的无序类别:如果你有3个城市,并分别用数字(1,2,3)对它们进行编码,机器学习模型可能会学习到城市1靠近城市2和城市3。由于这是一个错误的假设,如果城市特征在分析中起重要作用,该模型可能会给出不正确的预测。
另一方面,如果你有有序范围的特征,比如低、中、高,那么数字可能是一种有效的方法,因为你想保持这些范围的顺序。
在我们的例子中,海洋邻近特征并不是按任何顺序排列的。通过使用一个热点,将类别转换为二进制表示(1或0),并将原有的分类特征拆分为更多的特征,相当于类别的数量。
from sklearn.preprocessing import OneHotEncoder
def one_hot(input_data):
one_hot_encoder = OneHotEncoder()
output = one_hot_encoder.fit_transform(input_data)
output = output.toarray()
return output
cat_feats = training_input_data[['ocean_proximity']]
cat_feats_hot = one_hot(cat_feats)
cat_feats_hot
7.缩放数字特征
在我们输入缺失值并将分类特征转换为数字之后,是时候缩放数字特征了。
但是为什么我们要缩放数值特征呢?大多数机器学习模型在给定较小的输入值时都能很好地工作,如果它们在相同的范围内则效果最好。
出于这个原因,有两种最常用的技术来扩展功能:
*归一化,将特征缩放到0到1之间的值。和
*标准化,其中特征被重新缩放为具有0平均值和单位标准差。当处理包含异常值的数据集(如时间序列)时,在这种特殊情况下,标准化是正确的选择。
这两种技术在Sklearn中都很容易实现,使用’ MinMaxScaler ‘进行规范化,使用’ StandardScaler '进行标准化。
#归一化数值特征
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
num_scaled = scaler.fit_transform(num_feats)
#标准化数值特征
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
num_scaled = scaler.fit_transform(num_feats)
8.将所有数据预处理步骤放入单个Pipeline中
拥有数据Pipeline可以无缝地运行数据处理:
- 创建具有所有数值预处理步骤的数值Pipeline(处理缺失值和标准化)
- 创建一个分类Pipeline来编码分类特征
- 将两个Pipeline合并为一个Pipeline
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
num_feats_pipe = Pipeline([('imputer', SimpleImputer(strategy='mean')), ('scaler', StandardScaler()) ])
cat_feats_pipe = Pipeline([('encoder', OneHotEncoder())])
num_list = list(num_feats)
cat_list = list(cat_feats)
final_pipe = ColumnTransformer([
('num', num_feats_pipe, num_list),
('cat', cat_feats_pipe, cat_list) ])
training_data_preprocessed = final_pipe.fit_transform(training_input_data)
9.训练和评估模型
你可能听说过这样一个概念:机器学习只占整个ML项目的5%左右,其余的百分比用于数据处理。本文确实花了很多时间处理数据。这里使用sklearn中提供的线性回归模型。
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
reg_model = LinearRegression()
#训练模型
reg_model.fit(training_data_preprocessed, training_labels)
predictions = reg_model.predict(training_data_preprocessed)
#评估模型使用 mse 、rmse
mse = mean_squared_error(training_labels, predictions)
rmse = np.sqrt(mse)#这里值为:68438.90242790822
也可以使用交叉验证将训练数据分成训练和验证的不同折叠或子集。通过对模型进行多次训练和验证,比如10次,最终会得到10个不同的分数,可以取平均值。请注意,预测是在看不见的子集上进行的,模型不会看到它正在评估的数据。
from sklearn.model_selection import cross_val_score
scoring = 'neg_root_mean_squared_error'
scores = cross_val_score(reg_model, training_data_preprocessed, training_labels, scoring=scoring, cv=10)
scores = -scores
scores.mean()#这里值为:68493.74387894807
总结
该模型很简单,因此可以尝试其他复杂的模型,如随机森林、决策树或集成方法。因为我们将在下一个实验中讨论这些模型。另外,需要注意的是,大多数情况下,如果您有一个简单的数据集,简单模型将工作得很好,因为复杂模型可能会过拟合数据。此外,好的模型来自好的数据,所以最好花时间整理数据,而不是在模型中来回跳来跳去。
作者:(ง •_•)ง up