基于LinearRegression的波士顿房价预测

LinearRegression中文叫做线性回归,是一种基础、常用的回归方法。

2018年8月22日笔记
sklearn官方英文用户使用指南:https://sklearn.org/user_guide.html
sklearn翻译中文用户使用指南:http://sklearn.apachecn.org/cn/0.19.0/user_guide.html

0.打开jupyter notebook

不知道怎么打开jupyter notebook的朋友请查看我的入门指南文章:https://www.jianshu.com/p/bb0812a70246

1.载入数据集

波士顿房价数据集详细中文解释链接:http://sklearn.apachecn.org/cn/0.19.0/datasets/index.html#boston-house-prices
网页中内容截图如下:

image.png

查看数据集对象的属性和方法,代码如下:

from sklearn.datasets import load_boston
dir(load_boston())

上面一段代码的运行结果如下:

['DESCR', 'data', 'feature_names', 'target']

查看数据集的描述,即打印数据集对象的DESCR属性,代码如下:

from sklearn.datasets import load_boston
print(load_boston().DESCR)

与上图中文文档的图对照阅读,可以加强对数据集的理解。
上面一段代码的运行结果如下图所示:


image.png

将506个样本13个特征组成的矩阵赋值给变量X,变量X为大写字母的原因是数学中表示矩阵使用大写字母。
将506个样本1个预测目标值组成的矩阵赋值给变量y。
载入数据集的代码如下:

from sklearn.datasets import load_boston

X = load_boston().data
y = load_boston().target

2.数据观察

使用pandas库完成数据分析阶段的任务。
首先实例化1个DataFrame对象赋值给变量df,DataFrame对象类似于Excel表格。
查看变量df的前10行,代码如下:

import pandas as pd

df = pd.DataFrame(X, columns=load_boston().feature_names)
df.head(10)

上面一段代码的运行结果如下图所示:


image.png

查看变量df中是否有空值,如果有空值,则需要对其进行处理,代码如下:

df.info()

上面一段代码的运行结果如下图所示:

image.png

从上图的结果我们可以看出,数据总共有506行,13列。
在数据科学领域中,一般称事物的属性为字段,13个字段中都有506个非空的float64类型的数值,即没有空值。
从上图的最后1行可以看出,该表格总共占用内存51.5KB。
在计算机科学中,B表示Byte,中文叫做字节,b表示bit,中文叫做比特,1Byte = 8bit
占用内存的计算也并不复杂,1个float64类型的数值占用64bit,即8Byte,则总共13*506*8/1024=51.39KB
占用内存51.5KB比51.39KB略大,原因是表格中除了数据还得存储一些描述信息。

表格聚合运算的中文与英文简写对照如下表所示:

中文名 英文名
计数 count
平均值 mean
标准差 std
最小值 min
下四分位数 25%
中位数 50%或median
上四分位数 75%
最大值 max

.T表示对矩阵进行转置
查看变量df中各个字段的计数、平均值、标准差、最小值、下四分位数、中位数、上四分位、最大值,代码如下:

df.describe().T

上面一段代码的运行结果如下图所示:


image.png

3.特征提取

机器学习有60%以上的时间会被用于特征提取。
我们需要使用数据分析得出有用的特征,数据可视化来展示数据分析结果。
使用matplotlib库画图时,导入画板对象plt和防止中文出现乱码,一定要先运行下面3行代码,后面不再重复。

import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号

3.1 字段CRIM分析

CRIM表示城镇人均犯罪率,把它作为x轴的数值。
朴素的想法是如果一个城镇犯罪率很高,则社会不稳定,经济不发达,房价不会过高。
绘制城镇人均犯罪率与房价散点图,代码如下:

plt.scatter(df['CRIM'], y)
plt.title('城镇人均犯罪率与房价散点图')
plt.xlabel('城镇人均犯罪率')
plt.ylabel('房价')
plt.show()

上面一段代码的运行结果如下:


城镇人均犯罪率与房价散点图.png

分析结论:
1.高房价的房屋都集中在低犯罪率地区;
2.城镇人均犯罪率超过20%的情况下,房价最高不高于20;
3.城镇人均犯罪率处于(10, 20)区间的情况下,房价最高不高于30。

3.2 字段ZN分析

ZN表示住宅用地所占比例,把它作为x轴的数值。
绘制住宅用地所占比例与房价散点图,代码如下:

plt.scatter(df['ZN'], y)
plt.title('住宅用地所占比例与房价散点图')
plt.xlabel('住宅用地所占比例')
plt.ylabel('房价')
plt.yticks(range(0,60,5))
plt.grid()
plt.show()

上面一段代码的运行结果如下:


image.png

分析结论:
1.两者之间的线性关系不明显;
2.在住宅用地所占比例等于0的情况下,房价可以为任意值;
3.在住宅用地所占比例大于0的情况下,房价最低不低于15;
4.在住宅用地所占比例处于(40,80)区间的情况下,房价最高不高过40;
5.在住宅用地所占比例超过80的情况下,房价最低不低于30。

在编程当中,相同运行逻辑的代码出现2次是可以容忍的,但是出现3次及以上需要对此部分代码进行封装成函数。
对绘制散点图的代码封装如下:

def drawScatter(x, y, xlabel):
    plt.scatter(x, y)
    plt.title('%s与房价散点图' %xlabel)
    plt.xlabel(xlabel)
    plt.ylabel('房价')
    plt.yticks(range(0,60,5))
    plt.grid()
    plt.show()

3.3 字段INDUS分析

INDUS表示城镇中非商业用地的所占比例,把它作为x轴的数值。
plt.yticks方法指定y轴的刻度,plt.grid方法为绘制网格。
绘制城镇中非商业用地所占比例与房价散点图,代码如下:

drawScatter(df['INDUS'], y, '城镇中非商业用地所占比例')

上面一段代码的运行结果如下:


image.png

分析结论:
1.当城镇中非商业用地所占比例处于(0, 5)区间的情况下,房价处于(15, 50)区间;
2.当城镇中非商业用地所占比例处于(7, 15)区间的请况下,房价处于(10, 30)区间;
3.当城镇中非商业用地所占比例高于25的情况下,房价最高不高于25。

3.4 字段CHAS分析

CHAS表示地产是否处于查尔斯河边,1表示在河边,0表示不在河边。
绘制是否处于查尔斯河边与房价散点图,代码如下:

plt.xticks([0,1])
drawScatter(df['CHAS'], y, '是否处于查尔斯河边')

上面一段代码的运行结果如下图所示:


是否处于查尔斯河边与房价散点图.png

分析结论:
1.地产不在查尔斯河边的情况下,房价处于(5,55)区间;
2.地产在查尔斯河边的情况下,房价最低不低于10。

3.5 字段NOX分析

NOX表示一氧化氮的浓度,把它作为x轴的数值。
朴素的想法是一氧化氮为有毒气体,浓度过高的地区不适宜人居住,房价不会过高。
或者可以认为,浓度过高的地区靠近工业区,工业区房价比商业区房价低。
绘制一氧化氮浓度与房价散点图,代码如下:

drawScatter(df['NOX'], y, '一氧化氮浓度')

上面一段代码的运行结果如下图所示:


一氧化氮浓度与房价散点图.png

分析结论:
1.一氧化氮浓度高于0.7的情况下,房价最高不高于30,绝大部分不高于25;
2.一氧化氮处于(0.6, 0.7)区间的情况下,房价可能出现最低值;
3.一氧化氮低于0.5的情况下,房价绝大部分高于15。

3.6 字段RM分析

RM表示每栋住宅的房间数,把它作为x轴的数值。
朴素的想法是每栋住宅的房间数越多,则住宅面积越大,房价越高。
绘制住宅房间数与房价散点图,代码如下:

drawScatter(df['RM'], y, '住宅房间数')

上面一段代码的运行结果如下图所示:


image.png

分析结论:
1.两者之间存在较强的线性关系;
2.住宅房间数处于(4, 5)区间的情况下,房价绝大部分最高不超过25;
3.住宅房间数处于(5, 6)区间的情况下,房价绝大部分最高不超过30;
4.住宅房间数处于(6, 7)区间的情况下,房价绝大部分最高不超过40;
5.住宅房间数处于(7, 8)区间的情况下,房价绝大部分最低不低于30。

3.7 字段AGE分析

AGE表示1940年以前建成的业主自住单位的占比,把它作为x轴的数值。
绘制1940年以前建成的业主自住单位的占比与房价散点图,代码如下:

drawScatter(df['AGE'], y, '1940年以前建成的业主自住单位的占比')

上面一段代码的运行结果如下图所示:


1940年以前建成的业主自住单位的占比与房价散点图.png

分析结论:
1.自住单位的占比处于(0, 60)的情况下,房价最低不会低于15。

3.8 字段DIS分析

DIS表示距离5个波士顿就业中心的平均距离,把它作为x轴的数值。
朴素的想法是距离就业中心近则上下班距离近,人更愿意住在上下班距离近的地方,根据市场规律,需求高则房价会高。
绘制距离5个就业中心的平均距离与房价散点图,代码如下:

drawScatter(df['DIS'], y, '距离5个就业中心的平均距离')

上面一段代码的运行结果如下图所示:


距离5个就业中心的平均距离与房价散点图.png

分析结论:
1.平均距离小于2的情况下,房价处于(5, 55)区间;
2.平均距离处于(2, 6)的情况下,房价最低不低于10;
3.平均距离大于6的情况下,房价最低不低于15。

3.9 字段RAD分析

RAD表示距离高速公路的便利指数,把它作为x轴的数值。
朴素的想法是距离高速公路的便利越高,则越受欢迎,房价越高。
绘制距离高速公路的便利指数与房价散点图,代码如下:

drawScatter(df['RAD'], y, '距离高速公路的便利指数')

上面一段代码的运行结果如下图所示:


距离高速公路的便利指数与房价散点图.png

分析结论:
1.绝大多数房价高于30的房产,都集中在距离高速公路的便利指数低的地区;
2.距离高速公路的便利程度处于(6,10)区间时,房价最低不低于15;
3.朴素的想法与数据分析结果相反。

3.10 字段TAX分析

TAX每一万美元的不动产税率,把它作为x轴的数值。
绘制不动产税率与房价散点图,代码如下:

drawScatter(df['TAX'], y, '不动产税率')

上面一段代码的运行结果如下图所示:


image.png

分析结论:
1.不动产税率小于200的情况下,房价最低不低于15;
2.不动产税率小于500的情况下,房价最低不低于10;
3.只有在税率大于600的情况下,房价会低于10。

3.11 字段PTRATIO分析

PTRATIO表示城镇中学生教师比例,把它作为x轴的数值。
朴素的想法是教师较多的情况下,则教育资源多,房价也较高。
绘制学生教师比例与房价散点图,如下图所示:

drawScatter(df['PTRATIO'], y, '学生教师比例')

上面一段代码的运行结果如下图所示:


image.png

分析结论:
1.学生教师比例小于14的情况下,房价最低不低于20,绝大部分高于30;
2.学生教师比例处于(14, 20)区间的情况下,房价最低不低于10;
3.只有在学生教师比例大于20的情况下,房价会低于10,绝大部分不高于30。

3.12 字段B分析

B表示城镇中黑人比例,把它作为x轴的数值。
绘制黑人比例与房价散点图,如下图所示:

drawScatter(df['B'], y, '黑人比例')

上面一段代码的运行结果如下图所示:


image.png

分析结论:
1.只有在黑人比例高于350的地区,房价会高于30。
2.黑人比例处于(0, 100)区间的情况下,房价最高不高于20;
3.黑人比例处于(100,350)区间的情况下,房价最高不高于30。

3.13字段LSTAT分析

LSTAT表示低收入阶层占比,把它作为x轴的数值。
朴素的想法是低收入阶层占比低,则经济发展程度较高,则房价较高。

drawScatter(df['LSTAT'], y, '低收入阶层占比')

上面一段代码的运行结果如下图所示:


image.png

分析结论:
1.只有低收入阶层占比小于10的情况下,房价会高于35;
2.低收入阶层占比小于5的情况下,房价最低不低于20;
3.低收入阶层占比处于(10,20)区间的情况下,房价处于(10, 30)区间;
4.低收入阶层占比大于20的情况下,房价最高不高于25。

4.数据处理

根据字段分析的结果,提取出新的特征,做成字段。
分箱形成的新字段通过pd.concat方法连接组成表格赋值给变量cut_df,pd.concat方法返回值数据类型为DataFrame。
新字段表格与原表格继续通过pd.concat方法连接组成表格赋值给new_df。

field_cut = {
    'CRIM' : [0,10,20, 100],
    'ZN' : [-1, 5, 18, 20, 40, 80, 86, 100], 
    'INDUS' : [-1, 7, 15, 23, 40],
    'NOX' : [0, 0.51, 0.6, 0.7, 0.8, 1],
    'RM' : [0, 4, 5, 6, 7, 8, 9],
    'AGE' : [0, 60, 80, 100],
    'DIS' : [0, 2, 6, 14],
    'RAD' : [0, 5, 10, 25],
    'TAX' : [0, 200, 400, 500, 800],
    'PTRATIO' : [0, 14, 20, 23],
    'B' : [0, 100, 350, 450],
    'LSTAT' : [0, 5, 10, 20, 40]
}

cut_df = pd.DataFrame()
for field in field_cut.keys():
    cut_series = pd.cut(df[field], field_cut[field], right=True)
    onehot_df = pd.get_dummies(cut_series, prefix=field)
    cut_df = pd.concat([cut_df, onehot_df], axis=1)
new_df = pd.concat([df, cut_df], axis=1)
new_df.head()

上面一段代码的运行结果如下图所示:


image.png

5.线性回归模型

在评判线性回归模型的效果时,使用交叉验证更加客观和具有说服力。
下面介绍2种交叉验证的写法:
第1种交叉验证的写法,使用sklearn.model_selection中的KFold方法做交叉验证。

from sklearn.linear_model import LinearRegression
from sklearn.model_selection import KFold
import numpy as np

X = new_df.values
score_list = []
kf = KFold(n_splits=5, shuffle=True)
for train_index, test_index in kf.split(X):
    train_X = X[train_index]
    test_X = X[test_index]
    train_y = y[train_index]  
    test_y = y[test_index]
    linear_model = LinearRegression()
    linear_model.fit(train_X, train_y)
    score = linear_model.score(test_X, test_y)
    score_list.append(score)
    print(score)
np.mean(score_list)

上面一段代码的运行结果如下图所示:


image.png

第2种交叉验证的写法,使用sklearn.model_selection中的cross_val_score方法做交叉验证。
cross_val_score方法需要4个参数,第1个参数是模型对象,第2个参数是特征矩阵,第3个参数是预测目标,第4个关键字参数cv可以为整数或交叉验证对象。

from sklearn.model_selection import cross_val_score

linear_model = LinearRegression()
kf = KFold(n_splits=5, shuffle=True)
score_ndarray = cross_val_score(linear_model, X, y, cv=kf)
print(score_ndarray)
score_ndarray.mean()

上面一段代码的运行结果如下图所示:


image.png

6.学习更多

更多关于如何提高波士顿房价预测得分的内容,请阅读我的另一篇文章《基于xgboost+GridSearchCV的波士顿房价预测》
文章链接:https://www.jianshu.com/p/f34f22258a0a

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容