【人工智能】—美国加利福尼亚州房价预测实战案例

引言

在当今快速发展的房地产市场中,房价预测已成为一个至关重要的领域。它不仅关系到投资者的决策,也直接影响到普通购房者的生活质量。特别是在美国加利福尼亚州,这个以其高房价和房地产市场的波动性而闻名的地方,准确的房价预测显得尤为重要。本文将通过实战案例,深入探讨如何利用数据分析和机器学习技术来预测加利福尼亚州的房价走势。

背景信息

加利福尼亚州房地产市场概况
加利福尼亚州,作为美国经济最发达的地区之一,其房地产市场长期以来一直是国内外投资者关注的焦点。从硅谷的高科技产业到洛杉矶的娱乐业,再到旧金山的金融中心,加利福尼亚州的经济多元化为房地产市场提供了坚实的基础。然而,与经济活力相伴的是房价的高涨和快速波动,这给市场参与者带来了不小的挑战。

数据集信息

美国加利福尼亚州房价数据集是一个公开的数据集,通常用于机器学习和数据科学项目中的回归分析。根据搜索结果,这个数据集包含以下特征(本文涉及数据集已绑定上传,可免费获取):

  • 经度(Longitude):表示房屋所在位置的经度坐标。
  • 纬度(Latitude):表示房屋所在位置的纬度坐标。
  • Housing Median Age:区域中房屋的中位年龄,即一半房屋比这个年龄新,一半房屋比这个年龄旧。
  • Total Rooms:该区域内所有房屋的房间总数。
  • Total Bedrooms:该区域内所有房屋的卧室总数,这个特征可能存在缺失值。
  • Population:该区域内的总人口数。
  • Households:该区域内的家庭总数。
  • Median Income:该区域内家庭的收入中位数。
  • Median House Value:该区域内房屋的中位数价格,通常作为目标变量用于预测。

数据挖掘目标

通过房子的信息特征,预测Median House Value(该区域房价中位数)。

数据的读入和初步分析

数据读入:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt 
import seaborn as sns 
import plotly as py
import plotly.graph_objs as go
import warnings
import os
warnings.filterwarnings("ignore")
data = pd.read_csv('housing.csv')
data.head()

展示前五行数据:
在这里插入图片描述

描述性统计:
在这里插入图片描述
分割测试集与训练集:

from sklearn.model_selection import train_test_split
train_set, test_set = train_test_split(data, test_size=0.2, random_state=42)

老规矩80%数据用于训练,20%数据用于测试。

数据的初步分析:

# 设置图形窗口的大小为宽度15英寸,高度9英寸。  
plt.figure(3 , figsize = (15 , 9))    
# 初始化一个计数器n,用于跟踪当前正在处理的列(或子图)的索引。  
n = 0     
# 遍历DataFrame data的所有列名。  
for x in data.columns.to_list():       
    # 对每一列,增加计数器n的值。  
    n += 1        
    # 创建一个子图,在3行3列的网格中,位置由n决定(注意:这里需要确保n的值在1到9之间,否则会出现错误)。  
    plt.subplot(3 , 3 , n)        
    # 调整子图之间的间距。注意:通常最好在循环外只调用一次subplots_adjust,因为它会调整整个图形中所有子图的布局。  
    # 这里的调用可能不会有预期的效果,因为它在每次迭代时都会重新设置。  
    plt.subplots_adjust(hspace =0.5 , wspace = 0.5)        
    # 使用seaborn的distplot函数绘制data中当前列x的分布图,并设置直方图的bin数量为20。  
    # 注意:seaborn的distplot函数在较新版本中已被displot取代。  
    sns.distplot(data[x] , bins = 20)        
    # 为当前子图设置标题,标题内容为“Distplot of ”,后面跟着当前列的名称x。  
    plt.title('Distplot of {}'.format(x))    
# 显示所有子图。  
plt.show()

9个变量的直方图展示:
在这里插入图片描述
直方图是一种统计图表,用于表示数据分布的可视化。它通常用于展示数据集中数值型数据的分布情况。以下是直方图的一些关键特点和解释方法:

  • 数据分组:首先,将数据分成若干个连续的、通常是等宽的区间或“箱子”(bins)。
  • 箱子高度:每个箱子的高度表示落在该区间内的数据点的数量,即频数。
  • 连续性:与条形图不同,直方图的箱子是连续的,没有间隙,因为它们表示的是数值型数据的连续区间。
  • 范围:每个箱子覆盖一个特定的数值范围,例如,在房价数据中,一个箱子可能代表20万美元到30万美元的价格区间。
  • 频率分布:直方图可以展示数据的频率分布,即不同数值区间内数据点的集中程度。
  • 形状识别:通过直方图的形状,可以识别数据的分布特性,如是否对称、是否存在偏斜(右偏或左偏)、是否有双峰(双模态)等。
  • 密度曲线:有时在直方图上叠加一个平滑的曲线,称为核密度估计(KDE),它可以更平滑地展示数据的分布。

分析:

  • 通过观察直方图,可以快速了解数据的中心趋势、分散程度和分布形态,为进一步的统计分析提供直观信息。
  • 多变量比较:直方图也可以用来比较不同组别的数据分布,只需为每组数据创建一个直方图并并排显示。
  • 局限性:直方图的一个局限性是选择箱子的宽度和位置可能会影响图表的解释。不同的箱子设置可能会展示出数据的不同特征。

直方图是数据分析中的重要工具,特别是在探索性数据分析(EDA)阶段,它帮助数据分析师快速把握数据的关键特征

绘制经度和纬度的散点图:经纬度的二维分布也就是实际的地形分布。

散点图多用于相关性分析,具体介绍请查看我的专栏《从0开始学统计》内的从0开始学统计-什么是相关?

# 经度与纬度关系图
sns.relplot(data=data,
            x="longitude",
            y="latitude")

在这里插入图片描述
绘制房价随人口数量变化的折线图:

# 房价随人口变化折线图
data.plot('population', 'medianHouseValue')    
plt.show()

在这里插入图片描述简单的图形我就不介绍了,感兴趣可以在网上查。

绘制皮尔逊相关系数热力图:

# 设置seaborn的绘图样式和字体,这里设置了绘图上下文为"paper"(适合论文的样式)和字体为"monospace"(等宽字体)  
sns.set(context="paper",font="monospace")    
# 计算DataFrame 'data' 中各列之间的相关系数,并将结果存储在'housing_corr_matrix'中  
housing_corr_matrix = data.corr()  # 注意:这里假设'data'是已经加载好的一个DataFrame    
# 设置matplotlib的图形和坐标轴。这里创建了一个图形对象'fig'和一个坐标轴对象'axe'(但注意,这里应该是'ax'而不是'axe')  
# figsize参数设置了图形的大小为12x8英寸  
fig, ax = plt.subplots(figsize=(12,8))  # 修改'axe'为'ax'    
# 使用seaborn的diverging_palette函数生成一个颜色映射(cmap),从颜色220(接近蓝色)渐变到颜色10(接近红色)  
# center参数设置为"light",表示颜色映射的中心是亮色  
# as_cmap=True表示返回的是一个颜色映射对象  
cmap = sns.diverging_palette(220,10,center = "light", as_cmap=True)    
# 使用seaborn的heatmap函数绘制热力图。这里使用了之前计算的相关系数矩阵'housing_corr_matrix'  
# vmax参数设置了颜色映射的最大值,这里为1(因为相关系数范围是-1到1)  
# square=True表示每个单元格都是正方形  
# cmap参数指定了使用的颜色映射  
# annot=True表示在每个单元格中显示数值  
sns.heatmap(housing_corr_matrix, vmax=1, square=True, cmap=cmap, annot=True)    
# 显示图形  
plt.show()

在这里插入图片描述
之前的案例有介绍怎样辨识相关热图,这里就不再重复了,感兴趣可以翻下以前的案例。

在经纬图上绘制房屋价格和人口分布:

# 使用Pandas的DataFrame.plot()方法绘制散点图  
# kind="scatter" 指定了绘制的是散点图  
# x="longitude" 指定了x轴的数据是'longitude'列  
# y="latitude" 指定了y轴的数据是'latitude'列  
# alpha=0.4 设置了点的透明度,使得重叠的点可以部分可见  
# s=data["population"]/50 设置了点的大小,大小与'population'列的值成正比,但除以50是为了缩放大小  
# label="population" 设置了图例的标签为"population"(但通常这个标签可能更适合用于s参数,表示大小与人口相关)  
# figsize=(10,7) 设置了图形的大小为10x7英寸  
# c=data["medianHouseValue"] 设置了点的颜色,颜色由'medianHouseValue'列的值决定  
# cmap=plt.get_cmap("jet") 设置了颜色映射为"jet"  
# colorbar=True 在图上显示颜色条,表示不同的颜色对应的'medianHouseValue'值  
# sharex=False (在.plot()方法中,sharex通常不是有效的参数,除非您在子图网格中使用subplot_kws或gridspec_kws)  
# 如果是在使用subplot或subplots时,sharex可能用于控制x轴是否共享    
data.plot(kind="scatter", x="longitude", y="latitude", alpha=0.4,  
    s=data["population"]/50, label="population (size)", figsize=(10,7),  
    c=data["medianHouseValue"], cmap=plt.get_cmap("jet"), colorbar=True,  
    # sharex=False  # 在这个上下文中,sharex参数不适用,可以移除  
)    
# plt.legend() 显示图例,图例通常显示在图的某个角落,根据label参数来标识不同的数据系列  
plt.legend()

在这里插入图片描述上图点越密集,对应区域的颜色就越深,通过颜色深浅就可以看出数据的几种区域。越大、透明度越低的地方代表人口越多,越接近colorbar顶端的颜色的地方代表房产价格越高。经过这一系列分析后,对数据可以有非常直观的了解。

拆分数据:

housing=train_set.drop("medianHouseValue",axis=1)
labels=train_set["medianHouseValue"].copy()

得到输入数据和目标变量(label)。

数据标准化:采用z-score标准化,之前博客有过介绍,感兴趣的可以点超链接进入。

# 从 sklearn.impute 模块中导入 SimpleImputer 类,这个类用于填充数据集中的缺失值。  
from sklearn.impute import SimpleImputer    
# 从 sklearn.preprocessing 模块中导入 StandardScaler 类,这个类用于数据的标准化处理,即将数据转换为均值为0,标准差为1的分布。  
from sklearn.preprocessing import StandardScaler    
# 从 sklearn.pipeline 模块中导入 Pipeline 类,这个类用于构建数据处理的流水线,可以按照定义的顺序依次执行多个数据转换步骤。  
from sklearn.pipeline import Pipeline    
# 创建一个 Pipeline 对象,其中包含了 SimpleImputer 和 StandardScaler  
pipeline = Pipeline([  
    ('imputer', SimpleImputer(strategy="median")),  # 使用 SimpleImputer,策略为中位数填充  
    ('scaler', StandardScaler()),  # 使用 StandardScaler 进行标准化  
])  
data_prepared = pipeline.fit_transform(housing)#最终的结果,为numpy数组

在这里插入图片描述
上图为标准化后的5组数据。

模型构建

查看不同模型的表现

# 从 sklearn.linear_model 模块中导入 LinearRegression, ElasticNet, 和 Lasso 类。这些类分别代表线性回归、弹性网络(结合了L1和L2正则化的线性回归)和Lasso回归(L1正则化的线性回归)。  
from sklearn.linear_model import LinearRegression, ElasticNet, Lasso    
# 从 sklearn.ensemble 模块中导入 RandomForestRegressor 类。这是一个基于随机森林的回归模型。  
from sklearn.ensemble import RandomForestRegressor    
# 从 sklearn.pipeline 模块中导入 make_pipeline 函数(尽管在您的代码中并未直接使用它)。make_pipeline 是一个快捷方式来创建 pipeline。  
from sklearn.pipeline import make_pipeline    
# 从 sklearn.model_selection 模块中导入 KFold 和 cross_val_score 函数。KFold 用于生成K折交叉验证的索引,cross_val_score 用于计算模型的交叉验证得分。  
from sklearn.model_selection import KFold, cross_val_score    
# 设定交叉验证的折数为10  
n_folds = 10    
# 定义一个函数 get_rmse,该函数接收一个模型作为参数,并返回模型在数据上的均方根误差(RMSE)。  
# RMSE 是通过计算 cross_val_score 的负均方误差的平方根来获得的,因为 cross_val_score 默认返回的是负指标,所以需要先取负值再平方根。  
def get_rmse(model):  
    rmse = np.sqrt(-cross_val_score(model, data_prepared, labels, scoring="neg_mean_squared_error", cv=n_folds))  
    return rmse    
# 创建四个不同的回归模型实例:  
# linreg 是线性回归模型  
linreg = LinearRegression()    
# forest 是随机森林回归模型,设置了10个决策树估计器和随机状态为42  
forest = RandomForestRegressor(n_estimators=10, random_state=42)    
# lasso 是Lasso回归模型,设置了正则化强度为0.0005和随机状态为1  
lasso = Lasso(alpha=0.0005, random_state=1)    
# enet 是弹性网络模型,设置了正则化强度为0.0005,L1和L2正则化的比例为0.9,以及随机状态为3  
enet = ElasticNet(alpha=0.0005, l1_ratio=.9, random_state=3)    
# 使用之前定义的 get_rmse 函数来计算并打印每个模型的RMSE  
print(get_rmse(linreg))  
print(get_rmse(forest))  
print(get_rmse(lasso))  
print(get_rmse(enet))

在一般的训练中,通常可以选取多个模型,通过计算误差得出最好的模型。在本案例中,对线性回归、随机森林、Lasso、ElasticNet模型进行训练,得出了随机森林(random forest regressor)的效果是最好的,因为它的均方根误差最小。

在这里插入图片描述
选择效果最好的模型进行展示:

# 从测试数据集 test_set 中删除 "medianHouseValue" 列(这通常是因为我们要对这部分数据进行预测,而不是作为特征),  
# axis=1 表示我们是在列的方向上进行操作(即删除列)。  
# 结果存储在 test_housing 变量中,它只包含用于预测的特征,但不包含目标变量 "medianHouseValue"。  
test_housing = test_set.drop("medianHouseValue", axis=1)    
# 从测试数据集 test_set 中复制 "medianHouseValue" 列的值,这列通常是我们想要预测的目标变量。  
# 使用 copy() 方法是为了确保我们得到的是原始数据的副本,而不是视图或引用,以避免后续可能的数据修改。  
# 结果存储在 test_labels 变量中,它包含了与 test_housing 对应的真实目标值。  
test_labels = test_set["medianHouseValue"].copy()    
# 使用之前定义的 pipeline 对象(它可能包含了数据预处理步骤,如缺失值填充和标准化)来拟合(fit)并转换(transform)  
# test_housing 数据集。注意,这里我们只使用了 transform 方法而不是 fit_transform,  
# 因为 pipeline 已经通过训练集进行了拟合(通常在之前的数据准备步骤中)。  
# 结果(即预处理后的特征)存储在 test_data 变量中,这些特征将用于后续的模型预测。  
test_data = pipeline.transform(test_housing)

在这里插入图片描述

下面代码对测试集数据进行处理:

# 使用RandomForestRegressor(随机森林回归模型)的fit方法,将预处理后的训练数据(data_prepared)和对应的标签(labels)作为输入,  
# 对模型进行训练。fit方法会计算每个决策树所需的参数,并构建整个随机森林模型。  
forest.fit(data_prepared, labels)    
# 使用训练好的RandomForestRegressor模型的predict方法,对预处理后的测试数据(test_data)进行预测。  
# predict方法会返回测试数据集中每个样本的预测值,这些预测值存储在predict_labels变量中。  
predict_labels = forest.predict(test_data)

训练数据和预测:

# 使用RandomForestRegressor(随机森林回归模型)的fit方法,将预处理后的训练数据(data_prepared)和对应的标签(labels)作为输入,  
# 对模型进行训练。fit方法会计算每个决策树所需的参数,并构建整个随机森林模型。  
forest.fit(data_prepared, labels)    
# 使用训练好的RandomForestRegressor模型的predict方法,对预处理后的测试数据(test_data)进行预测。  
# predict方法会返回测试数据集中每个样本的预测值,这些预测值存储在predict_labels变量中。  
predict_labels = forest.predict(test_data)

对实际数据和预测数据进行可视化:

# 假设您已经导入了NumPy库(import numpy as np)和Matplotlib的pyplot模块(import matplotlib.pyplot as plt)。  
# 这行代码将test_labels(可能是一个Pandas Series或列表)转换为NumPy数组,并存储在origin_labels变量中。  
# 这样做是为了确保数据类型与Matplotlib兼容,并可能为了后续的数值操作。  
origin_labels = np.array(test_labels)    
# 使用Matplotlib的plot函数绘制origin_labels数组的前100个值。  
# 这通常用于可视化原始数据的标签值,以便与预测值进行比较。  
# label参数为这条线指定了一个标签,该标签稍后会显示在图例中。  
plt.plot(origin_labels[0:100], label='origin_labels')    
# 使用Matplotlib的plot函数绘制predict_labels数组的前100个值。  
# 这用于可视化模型的预测值,以便观察预测结果与实际标签之间的差异。  
# 同样,通过label参数为这条线指定了一个标签。  
plt.plot(predict_labels[0:100], label='predict_labels')    
# 显示图例,其中包含了之前通过label参数指定的标签。  
# 图例会解释图中的每条线分别代表什么。  
plt.legend()

在这里插入图片描述
比较预测和实际结果(红棕色线为预测数据,蓝色为实际数据),可以看出模型的预测能力还是相当不错的,当然有更多的数据,我相信预测结果会更加准确。

大家可能觉得看图没有感觉,我就给大家把预测数据合并到表内,给大家展示预测完全正确的部分数据(见下图,倒数第二列为实际结果,最后一列为预测结果)。

在这里插入图片描述

创作不易,点赞、关注、评论、转发4连!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花花 Show Python

你的打赏会让我有创作的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值