python房价预测_python——房价预测案例(完整项目流程)

Step 1: 检视源数据集

import numpy as np

import pandas as pd

1.1 读入数据

file=open("D:/python练习/housing.csv")

train_df=pd.read_csv(file)

1.2 检视原数据

train_df.head(5)

image.png

每一行都表示一个街区。共有 10 个属性:经度、维度、房屋年龄中位数、总房间数、卧室数量、人口数、家庭数、收入中位数、房屋价值中位数、离大海距离。

train_df.info()

image.png

可以看出total_bedrooms这一项有缺失值,后面要进行处理。ocean_proximity这一项的数据类型为类别型数据。

train_df.ocean_proximity.value_counts()

image.png

value_counts()方法查看都有什么类型,每个类都有多少街区

train_df.describe()

image.png

画出每个数值属性的柱状图

%matplotlib inline

from matplotlib import pyplot as plt

plt.style.use('ggplot')

train_df.hist(bins=50,figsize=(16,9))

image.png

从柱状图中可以发现以下问题:

1.这些属性的量度不一样,在后面需要进行特征缩放

2.许多柱状图的尾巴过长,对某些机器学习的算法检测规律会变得更难,所以在后面要处理成正态分布。

3.房屋年龄中位数和房屋价值中位数也被设了上限。后者可能是个严重的问题,因为它是你的目标属性(你的标签)。你的机器学习算法可能学习到价格不会超出这个界限。你需要与下游团队核实,这是否会成为问题。如果他们告诉你他们需要明确的预测值,即使超过 500000,你则有两个选项:1)对于设了上限的标签,重新收集合适的标签;2)将这些街区从训练集移除(也从测试集移除,因为若房价超出 500000,你的系统就会被差评)。

4.收入数据经过了缩放处理。

Step 2: 创建测试集

目的:防止数据透视偏差。如果一开始就看过测试集,就会不经意间按照其中的规律选择合适的算法,当再用测试集进行评估时,就会导致结果比较乐观,而实际部署时就比较差了。

from sklearn.model_selection import train_test_split

train_set,test_set=train_test_split(train_df,test_size=0.2,random_state=42)

train_test_split函数用于将矩阵随机划分为训练子集和测试子集,并返回划分好的训练集测试集样本和训练集测试集标签。test_size:如果是浮点数,在0-1之间,表示样本占比;如果是整数的话就是样本的数量。random_state:是随机数的种子。产生总是相同的洗牌指数;如果没有这个每次运行会产生不同的测试集,多次之后会得到整个数据集。

train_set.head(5)

image.png

不足之处:目前都是采用的纯随机抽样,如果数据量比较小,可能会产生偏差。所以需要关注比较重要的属性,对其进行分层抽样,比如说收入中位数。从直方图中可以看出,大多数的值在2-5(万美元),进行分层抽样时保证每一层都要有足够多的数据,这就意味着,层数不能过多。后面的代码将收入中位数除以1.5(以限制分类的数量),创建收入类别属性,用ceil对值舍入(产生离散的分类),并将大于5的分类归入到分类5。inplace=True原数组内容被改变。

train_df["income_cat"]=np.ceil(train_df.median_income/1.5)

train_df["income_cat"].where(train_df["income_cat"]<5,5.0,inplace=True)

train_df["income_cat"].head(5)

train_df["income_cat"].value_counts()/len(train_df)

image.png

from sklearn.model_selection import StratifiedShuffleSplit

split=StratifiedShuffleSplit(n_splits=1,test_size=0.2,random_state=42)

for train_index,test_index in split.split(train_df,train_df["income_cat"]):

start_train_set=train_df.loc[train_index]

start_test_set=train_df.loc[test_index]

start_train_set.head(5)

image.png

for set in(start_train_set,start_test_set):

set.drop(["income_cat"],axis=1,inplace=True)

start_test_set.head(5)

image.png

需要删除income_cat属性,使数据回到初始状态。

Step 3: 数据探索及可视化

目的:以上只是粗略的查看了统计信息,还需要从样本中发现更多的信息。如果训练集非常大,可能还需要采样一个探索集。如果比较小,可以建立一个副本。

housing=start_train_set.copy()

3.1 地理数据可视化

原因:样本中有经度和纬度,所以考虑创建散点图

housing.plot(kind="scatter",x="longitude",y="latitude",alpha=0.4,figsize=(15, 10)

)

image.png

高密度区域:湾区、洛杉矶和圣迭戈等

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

s=housing.population/50,label="population",

c=housing.median_house_value,cmap=plt.get_cmap('jet'),colorbar=True,

figsize=(15, 10))

plt.legend()

image.png

加入人口信息,用点的大小来展示(s)。加入房价信息,用颜色的深浅来表示(c),用预先定义的颜色图“jet”,范围从蓝色到红色,即低价到高价。从图中可以发现房价和位置(沿海地区)以及人口密度存在联系。

import seaborn as sns

sns.set(style = "whitegrid")#设置样式

x = housing.longitude#X轴数据

y = housing.latitude#Y轴数据

z = housing.median_income#用来调整各个点的大小s

cm = plt.get_cmap('jet')

fig,ax = plt.subplots(figsize = (15,10))

#注意s离散化的方法,因为需要通过点的大小来直观感受其所表示的数值大小

#参数是X轴数据、Y轴数据、各个点的大小、各个点的颜色

bubble = ax.scatter(x, y , s = housing.population/50, c = z, cmap = cm, linewidth = 0.5, alpha = 0.5)

ax.grid()

fig.colorbar(bubble)

ax.set_xlabel('longitude', fontsize = 15)#X轴标签

ax.set_ylabel('latitude', fontsize = 15)#Y轴标签

plt.show()

image.png

利用seaborn作图也可以达到同样效果。加入人口信息,用点的大小来展示(s)。加入收入信息,用颜色的深浅来表示(c),用预先定义的颜色图“jet”,范围从蓝色到红色,即低价到高价。从图中可以发现收入和位置(沿海地区)以及人口密度存在一定的联系,但是效果不是十分明显。

3.2 查看特征之间的相关性

corr_matrix=housing.corr()

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

image.png

用热力图的方式展现相关性。annot(annotate的缩写):默认取值False;如果是True,在热力图每个方格写入数据;vmax,vmin:分别是热力图的颜色取值最大和最小范围,默认是根据data数据表里的取值确定。

import seaborn as sns

fig=plt.figure(figsize=(12,8),dpi=80)

sns.heatmap(housing.corr(),annot =True,vmin = 0, vmax = 1)

image.png

用可视化的方式展现相关性,因为属性过多,所以选取部分属性。

from pandas.tools.plotting import scatter_matrix

attributes=["median_house_value","median_income","total_rooms","housing_median_age" ]

scatter_matrix(housing[attributes],figsize=(12,8))

image.png

对角线表示每个属性的柱状图。图中可以看出收入对房价的影响还是比较大的,所以可以放大进行研究。

housing.plot(kind="scatter",x="median_income",y="median_house_value",alpha=0.5,figsize=(12,8))

image.png

可以看出相关性还是很高的。其次,可以看到一些直线:500000,450000,350000,280000美元,可能是收集资料时设立的边界。

3.3 属性组合试验

有一些属性,比如总房间数,在不知道街区有多少户的情况下用处不大。同理总卧室数和总人口数。

housing["rooms_per_household"]=housing.total_rooms/housing.households

housing["bedrooms_per_room"]=housing.total_bedrooms/housing.total_rooms

housing["population_per_household"]=housing.population/housing.households

corr_matrix =housing.corr()

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

image.png

间数和卧室数更有信息。而且每户的房间数越多,意味着房屋更大,房价越高,比单纯的看总房间数更有信息。

Step 4: 数据预处理

目的:为机器学习算法准备数据。

housing=start_train_set.drop("median_house_value",axis=1)

housing_copy=housing.copy()

housing_labels=start_train_set.median_house_value.copy()

print(housing.head(5))

print(housing_labels.head(5))

image.png

将训练集中预测量和标签分开,因为之后对其要进行不同的转换;drop()创建备份,不影响原数据集。

4.1 数据清洗

目的:处理缺省值。因为很多机器学习算法对缺省值比较敏感(例如LR和SVM,决策树和朴素贝叶斯相对好一点)

思路:1)去掉缺失的行数据dropna();2)去掉缺失的列drop();3)进行赋值fillna(),可以是0、平均数和中位数。

median=housing.total_bedrooms.median()

housing.total_bedrooms=housing.total_bedrooms.fillna(median)

housing.isnull().sum().sum()

image.png

4.2 处理文本和类别属性

housing=pd.get_dummies(housing)

housing.head(5)

image.png

pandas自带的get_dummies方法,可以帮你一键做到One-Hot。可以看出类别属性ocean_proximity被我们分成了5个column,每一个代表一个category。是就是1,不是就是0。

4.3 特征缩放

当输入的属性量度不同时,会影响机器学习算法的性能。比如总房间数分布范围在6-39320,收入中位数在0-15。两种方法:归一化和标准化。归一化将数值缩放到0-1之间,标准化不会限定到某个范围,对一些算法有影响,像神经网络算法输入值就必须是0-1。但是异常值对标准化的影响较小。

numeric_cols=housing_copy.columns[housing_copy.dtypes!="object"]

print(numeric_cols)

image.png

numeric_col_means = housing.loc[:, numeric_cols].mean()

numeric_col_std = housing.loc[:, numeric_cols].std()

housing.loc[:, numeric_cols] = (housing.loc[:, numeric_cols] - numeric_col_means) /numeric_col_std

housing.head()

image.png

housing_labels=(housing_labels-housing_labels.mean())/housing_labels.std()

housing_labels.head()

image.png

Step 5:模型选择和训练

5.1 在训练集上训练和评估

from sklearn.linear_model import LinearRegression

lin_reg=LinearRegression()

将DF转化为Numpy Array

X_train=housing.values

X_test=housing_labels.values

print(X_train)

print(X_test)

image.png

先训练一个线性回归模型

lin_reg.fit(X_train,X_test)

训练完成,用交叉验证法进行模型评估。交叉验证的基本思想是将训练数据集分为k份,每次用k-1份训练模型,用剩余的1份作为验证集。按顺序训练k次后,计算k次的平均误差来评价模型(改变参数后即为另一个模型)的好坏。

from sklearn.model_selection import cross_val_score

lin_reg_scores=cross_val_score(lin_reg,X_train,X_test,scoring="neg_mean_squared_error",cv=10)

lin_reg_rmse_scores=np.sqrt(-lin_reg_scores)

print(lin_reg_rmse_scores.mean())

image.png

均方根误差(RMSE),回归任务可靠的性能指标。

利用决策树模型试试看

from sklearn.tree import DecisionTreeRegressor

tree_reg=DecisionTreeRegressor()

tree_reg.fit(X_train,X_test)

tree_reg_scores=cross_val_score(tree_reg,X_train,X_test,scoring="neg_mean_squared_error",cv=10)

tree_reg_rmse_scores=np.sqrt(-tree_reg_scores)

print(tree_reg_rmse_scores.mean())

image.png

可以看出决策树模型的误差大于线性回归,性能更差一点。现在选择用随机森林尝试一下。

from sklearn.ensemble import RandomForestRegressor

RF_reg=RandomForestRegressor()

RF_reg.fit(X_train,X_test)

RF_reg_scores=cross_val_score(RF_reg,X_train,X_test,scoring="neg_mean_squared_error",cv=10)

RF_reg_rmse_scores=np.sqrt(-RF_reg_scores)

print(RF_reg_rmse_scores.mean())

image.png

随机森林速度慢一点,误差更小,明显更有希望。

5.2 利用网格搜索对模型进行微调

只要提供超参数和试验的值,网格搜索就可以使用交叉验证试验所有可能超参数值的组合。

from sklearn.model_selection import GridSearchCV

param_grid = [

{'n_estimators': [3, 10, 30], 'max_features': [2, 4, 6, 8]},

{'bootstrap': [False], 'n_estimators': [3, 10], 'max_features': [2, 3, 4]},

]

forest_reg = RandomForestRegressor()

grid_search = GridSearchCV(forest_reg, param_grid, cv=5,

scoring='neg_mean_squared_error')

grid_search.fit(X_train,X_test)

首先调第一行的参数为n_estimators和max_features,即有34=12种组合,然后再调第二行的参数,即23=6种组合,具体参数的代表的意思以后再讲述。总共组合数为12+6=18种组合。每种交叉验证5次,即18*5=90次模型计算,虽然运算量比较大,但运行完后能得到较好的参数

grid_search.best_params_

image.png

可以看到最好参数中30是选定参数的边缘,所以可以再选更大的数试验,可能会得到更好的模型,还可以在8附近选定参数,也可能会得到更好的模型。

grid_search.best_estimator_

image.png

得到最佳的估计器

5.3 用测试集去评估系统

from sklearn.metrics import mean_squared_error

final_model = grid_search.best_estimator_

X_test = start_test_set.drop("median_house_value", axis=1)

y_test = start_test_set["median_house_value"].copy()

median=X_test.total_bedrooms.median()

X_test.total_bedrooms=X_test.total_bedrooms.fillna(median)

X_test=pd.get_dummies(X_test)

numeric_col_means = X_test.loc[:, numeric_cols].mean()

numeric_col_std = X_test.loc[:, numeric_cols].std()

X_test.loc[:, numeric_cols] = (X_test.loc[:, numeric_cols] - numeric_col_means) /numeric_col_std

y_test=(y_test-y_test.mean())/y_test.std()

final_predictions = final_model.predict(X_test)

final_mse = mean_squared_error(y_test, final_predictions)

final_rmse = np.sqrt(final_mse)

print(final_rmse)

image.png

把测试集进行预处理,导入到系统中,误差为0.462982088615,模型的表现还不错。

你可能感兴趣的:(python房价预测)