Python机器学习第一章-(线性回归)

本文是Python机器学习的初步介绍,通过线性回归解决租房价格预测问题。利用Pandas和Numpy处理数据,包括数据清洗、特征选择,并使用statsmodels建立线性回归模型,探讨卧室数量和邮政编码对租金的影响。通过数据可视化展示模型效果,为初学者提供了机器学习的基本框架。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Python机器学习第一章-(线性回归)

这次我们通过python的一些库来研究一下机器学习,至于什么是机器学习,网上写的东西很多,也很杂,具体是啥我们通过后面的教程来看一下。Pandas和Numpy是学习机器学习的前提,不熟悉的同学可以先找一些教程学习,本人后续也会更新Pandas和Numpy的教程。
    
    这一章我们的目标是如何找到一个适合自己的出租房。。。
相信大多数人都遇到过找房的尴尬,无数的坑蒙拐骗和奔波,今天我们尝试用机器学习来解决这个问题。
数据源
Chapter 1中的magic.csv就是我们的数据了
检查一下数据

import pandas as pd
import numpy as np
import re
import matplotlib.pyplot as plt
plt.style.use("ggplot")
CSV_PATH = r"/Users/GLdata/magic.csv"
df = pd.read_csv(CSV_PATH)
df.head()

我们看一下这个dataframe究竟啥样子
在这里插入图片描述
这只是图片的一部分,右侧还有不少列。
我们瞧瞧这些列都有啥

df.columns
len(df.columns)

在这里插入图片描述
一共有23个列,当然了不是所有的列我们都用得上,而且有不少缺失值(NaN)
我们注意到一个参数“listingtype_value”,这个列的值只单一单元有“Apartment for Rent”和多个单元“Apartments for Rent”
在这里插入图片描述
我们看一下这两个房源类型的数量

mu = df[df["listingtype_value"].str.contains("Apartments For")]
len(mu)
su = df[df["listingtype_value"].str.contains("Apartment For")]
len(su)

在这里插入图片描述
大多数的房源属于单一单元的类型,接下来我们将数据格式化为标准结构,至少需要把“卧室数”,“面积”,“浴室数”,“地址”标准化
我们发现,上面我们说的几个数据基本都在“pricelarge_value_prices”中。
而且这列数据没有缺失值,先来看一下这列数据吧。

su["propertyinfo_value"]

在这里插入图片描述
为了在图片占的少一点,我把该数据经过了转置,当然各位在操作的过程中不比进行这一步。
看上去这个列有卧室和浴室的数量,偶尔也有年份这样的额外信息。
检查一下没有包含“bd”或“Studio”的行数,和没有“ba”的行数

len(su[~(su["propertyinfo_value"].str.contains("Studio") | su["propertyinfo_value"].str.contains("bd"))])
len(su[~su["propertyinfo_value"].str.contains("ba")])

在这里插入图片描述
OK,没有不包含Studio和bd的公寓,只有6间公寓不包含浴室

出现这种数据缺失情况的原因非常多,我们可以用一些方法将其补充上去,针对这些缺失值的处理你可以专门买一本书来看看。这一章我们先删除这些确缺失的数据。

no_baths = su[~(su["propertyinfo_value"].str.contains("ba"))]
sucln = su[~su.index.isin(no_baths.index)]

我们将得到的数据切分一下,获取到我们想要的数据

def parse_info(row):
    if not "sqft" in row:
        br,ba = row.split("•")[:2]
        sqft = np.nan
    else:
        br,ba,sqft = row.split("•")[:3]
    return pd.Series({"Beds":br,"Baths":ba,"Sqft":sqft})
attr = sucln["propertyinfo_value"].apply(parse_info)
attr_cln = attr.applymap(lambda x:x.strap(" ")[0] if isinstance(x,str) else np.nan
sujnd = sucln.join(attr_cln)

在这里插入图片描述
OK,基本上已经算是大功告成了。
租房的价格很大程度上取决于 房屋面积,居室数量,浴室数量和所在的地理位置,楼层。这个数据中routable_link/text就是公寓所在的地理位置举个例子看一下710 Riverside Dr APT 2C, New York, NY10031 ,最有用的数据就是这个NY10035,表示了所在的街区,有的数据中还包含了所在楼层,当然了有些数据是不包含楼层的,我们先把这两个数据搞出来看一下

def parse_addy(r):
    so_zip = re.search('NY(\d+)',r)
    so_flr = re.search('(?:APT|#)\s+(\d+)[A-Z]+',r)
    if so_zip:
        zipc = so_zip.group(1)
    else:
        zipc =np.nan
    if so_flr:
        flr = so_flr.group(1)
    else:
        flr = np.nan
    return pd.Series({"Zip":zipc,"Floor":flr})
flrzip = sujnd['routable_link/_text'].apply(parse_addy)
suf = sujnd.join(flrzip)
suf.T

在这里插入图片描述

suf[suf["Zip"].isnull()]

看了一眼邮政编码有13个缺失值(邮政编码对应了所在的街区)

suf[suf["Floor"].isnull()]

楼层的缺失值有165个

现在我们把有用的列搞出来,把不规则的列名修改一下,数据处理阶段就结束了。感觉最费劲的就是处理各式各样蛋疼的数据

sudf = suf[["pricelarge_value_prices","Beds","Baths","Sqft","Floor","Zip"]]
sudf.rename(columns={"pricelarge_value_Prices":"Rent"},inplace=True)
sudf.reset_index(drop=True,inplace=True)
sudf

在这里插入图片描述

分析数据
先看一下这个我们整理过的数据吧

sudf.describe()

在这里插入图片描述
纳尼?只有第一列的租金生成了描述。
那看来其余的列不是数值型,我们来看一下

sudf.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 333 entries, 0 to 332
Data columns (total 6 columns):
Rent     333 non-null float64
Beds     333 non-null object
Baths    333 non-null object
Sqft     108 non-null object
Floor    165 non-null object
Zip      320 non-null object
dtypes: float64(1), object(5)
memory usage: 15.7+ KB

对应的修改一下

sudf.loc[:,'Rent'] = sudf['Rent'].astype(int)
sudf.loc[:,"Beds"] = sudf["Beds"].map(lambda x:0 if x == "Studio" else x)
sudf.loc[:,"Beds"] = sudf['Beds'].astype(int)
sudf.loc[:,"Baths"] = sudf['Baths'].astype(float)
sudf.loc[:,"Sqft"] =sudf['Sqft'].str.replace(",","")
sudf.loc[:,"Sqft"] = sudf['Sqft'].astype(float)
sudf.loc[:,"Floor"] = sudf["Floor"].astype(float)
sudf.describe()

在这里插入图片描述
等等,为什么会出现一个1107层的公寓,这个数据我看到字段是“APT 1107A” 这应该是一个门牌号。为了安全性,我决定放弃这个房源

sudf = sudf.drop([318])
sudf.describe()

在这里插入图片描述
这下看起来就没什么问题了。
下面我们会用一下pandas我非常非常喜欢的一个功能pivot_table!!!大致就和EXCEL的数据透视表差不多,当然了group_by也可以

sudf.pivot_table("Rent","Zip","Beds",aggfunc="mean)

在这里插入图片描述
截一部分图看一下Bed越多房价越高,

sudf.pivot_table("Rent","Zip","Beds",aggfunc="count)

在这里插入图片描述
问题来了,我们有非常多的空值,我们需要更多房源的数据作为支撑。不过暂时先这样吧。

数据可视化
下面我们会通过folium这个包来实现数据可视化
由于我们beds 2和3的数据缺失的太多,我们居中分析开间和一居室。

su_lt_two = sudf[sudf["Beds"]<2]
import folium
map = folium.Map(location=[40.748817, -73.985428], zoom_start=13)
map.choropleth(geo_data=r'/Users/gn/GLdata/nyc.json', data=su_lt_two,
             columns=['Zip', 'Rent'],
             key_on='feature.properties.postalCode',
             fill_color='YlOrRd',
               legend_name="Rent (%)",
               fill_opacity = 0.7,
               line_opacity = 0.2  
           )

在这里插入图片描述
颜色越深代表房源价格越高
这个folium包的API改动过,网上找到的大多数都是老版本的API,详情请大家根据最新的API来进行制图。
同时还需要一个GeoJSON的json数据,这诗一个表示地理属性的开放格式,通过搜索你可以自行下载包含邮编的GeoJSON数据,也可以使用我在Github中的GeoJSON数据

建模
建模的过程我们会使用两个包,第一个statsmodels,这是Python机器学习中非常非常非常常用的一个包,实在是太常用了。第二个Patsy,这个包搭配statsmodels使用。让我们可以使用R风格的公式。

import patsy
import statsmodels.api as sm
f = "Rent ~ Zip + Beds"
y,X = patsy.dmatrices(f,su_lt_two,return_type="dataframe")
results = sm.OLS(y,X).fit()
results.summary()

这段函数什么意思呢?第一行使我们要使用的公式,我们想知道Zip和Beds对Rent有什么影响,
然后我们将公式和数据传递给patsy.dmatrices()
X矩阵由预测变量组成,y向量有相应变量组成,这些江北传递给sm.OLS()
之后调用fit运行我们的模型,最后打印我们的结果(下面是其中一部分,我们会按步骤看一下返回的数据)
在这里插入图片描述
OK,262个观察样本,调整后的R2值为0.283,F-statistic为1.21e-10,表示了是有统计的显著性的,调整后的R2越接近1说明模型越拟合,意味着我们创造的模型仅使用我是数量和邮政编码就能够解释将近1/3的价格。
我们继续往下看
在这里插入图片描述
在这里插入图片描述
从左到右依次是变量,变量在模型中的系数,标准误差,t统计量,t统计量的P值,以及95%置信区间。
通常统计学家用0.05的p值来确定是否为偶然发生。就这个输出而言Beds卧室的数量显然和价格有关系。那么邮政编码呢?
受限,我们截距代表了10001的邮政编码,statsmodels自动预测变量作为截距,在这里它使用的诗10001地区。
我们看了一下其他的地区,大多数情况他们并不显著。我们看几个显著地10029,10035,非常显著,而且具有很高的负置信区间。这告诉我们,和10001地区相比,这些地区同样类型的公寓价格要不10001低不少。

预测

我们看看刚才输入进去的矩阵是啥样子

X.head()

在这里插入图片描述
ok,就是这样的一个dataframe,哪个街区的输入1剩余的都是0,再输入一个BEDS的数量,当然截距也要设置为1
那我们创建一个我们想要预测的邮编的dataframe

tpdf = X[1:2]
tpdf.index =[1]
tpdf.loc[1] = 0
tpdf.loc[1,'Intercept'] = 1
tpdf.loc[1,'Beds'] = 1
tpdf.loc[1,'Zip[T.10009]'] = 1
#预测一下看看结果
results.predict(tpdf)

在这里插入图片描述
这个resluts使我们保存的迷行变量名,这个模型对象有一个predict()方法,我们用自己的输入值调用该方法就可以返回预测值。同学们也可以自己测试一下,更换一个街区,更换一个beds数试试。

当然了我们的数据量比较小,很多街区的都不显著。随着数据量的增多,合理条件的增多。我们模型的准确率也会越来越高,因为暂时我们只使用了邮政编码(对应街区)卧室,出租价格之间的关系。方然了房地产是一个非常复杂的市场,这些就简单的选项没办法观测他,我们展示了一个框架,一个可以预测房地产市场的框架。拓展模型的方法有很多,相信你的模型会不断完善,加油!

这一章我们接触了机器学习的表层,后续我们会继续探索不同的算法和应用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值