Python机器学习实践指南-第二章

# # -*- coding:utf-8 -*-
#准备数据
import pandas as pd
import re
import numpy as np
import matplotlib.pyplot as plt
plt.style.use(('ggplot'))

pd.set_option("display.max_columns",30)
pd.set_option("display.max_colwidth",100)
pd.set_option("display.precision",3)
CSV_PATH = r"D:/python机器学习+数据分析/Python机器学习实践指南(中文版带书签)、原书代码、数据集/PMLB Datasets/PMLB Datasets/PMLB Datasets copy/magic.csv"
df = pd.read_csv(CSV_PATH)
# print(df.columns)   #输出列标题
# print(df.head())
# print(df.describe())
# print(df.T)
# print(df.T.ix[:,1:2])
# nn = df[df['routable_link/_text'].str.contains('203 Rivington')|df['routable_link/_text'].str.contains('280 E 2nd')]
# print(nn[:2].T)
#有上面代码输出结果可以看到,有不少缺失值
#multiple units
mu = df[df['listingtype_value'].str.contains('Apartments For')]

#single units
su = df[df['listingtype_value'].str.contains('Apartment For')]
# print(len(mu))  #161
# print(len(su))  #339

"""
大多数房源属于单一单元的类型。需要将数据格式化为标准结构,例如卧室数、浴室数等准备一列。
"""
# print(su['propertyinfo_value'])

#以上数据看出,包含卧室和浴室,也有的数据包含年份

#检查没有包含‘bd'或者’Studio的行数
num=len(su[~(su['propertyinfo_value'].str.contains('Studio')|su['propertyinfo_value'].str.contains('bd'))])
# print(num)  #0
# #检查有没有包含ba的行数
# print(len(su[~(su['propertyinfo_value'].str.contains('ba'))]))   #6
#显示有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)
# print(attr)

#在取值中将字符串删除
attr_cln = attr.applymap(lambda x:x.strip().split(' ')[0] if isinstance(x,str) else np.nan)
# print(attr_cln)
sujnd = sucln.join(attr_cln)
# print(sujnd.T)

"""
数据基本出来了。可以基于浴室、卧室的数量和面积,测试公寓的价值。
"""
"""
如果可能,尝试提取楼层的信息。假设一个模式,其中一个数字后面跟随一个字母,
该字母就表示建筑的楼层。
"""
#parse out zip,floor
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)
# print(flrzip)
# print(len(flrzip[~flrzip['Floor'].isnull()]))
# print(len(flrzip[~flrzip['Zip'].isnull()]))
suf = sujnd.join(flrzip)
# print(suf.T)


"""
当楼层和邮编信息出现的时候,从333个房源中获得320个带有邮编的房源和164个带有楼层信息的房源,
"""
#将数据减少为所感兴趣的那些列
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)
# print(sudf)

"""
2.2.1分析数据
"""
# print(sudf.describe())
"""
可以看到租金的统计细分。
"""
#将出现的'Studio'替换成0
sudf.loc[:,'Beds'] = sudf['Beds'].map(lambda x:0 if 'Studio' in x else x)
# print(sudf)

#解决了上面的问题,还有一个问题,统计数据的列必须是数值型的。
# print(sudf.info())

#解决列中数据类型的问题
sudf.loc[:,'Rent'] = sudf['Rent'].astype(int)
sudf.loc[:,'Beds'] = sudf['Beds'].astype(int)
#存在半浴室的情况,使用浮点型
sudf.loc[:,'Baths'] = sudf['Baths'].astype(float)

#存在NAN的,需要浮点型,但是要首先将逗号替换掉
sudf.loc[:,'Sqft'] = sudf['Sqft'].str.replace(',','')
sudf.loc[:,'Sqft'] = sudf['Sqft'].astype(float)
sudf.loc[:,'Floor'] = sudf['Floor'].astype(float)

#看看结果如何
# print(sudf.info())
# print(sudf.describe())

#索引标号318是有问题的房源,可以放弃此数据
sudf = sudf.drop([318])
# print(sudf.describe())

"""
使用数据透视查看数据。首先看邮政编码和卧室数量来检查价格
"""
# print(sudf.pivot_table('Rent','Zip','Beds',aggfunc='mean'))
"""
以上结果可以根据邮编查看结果。随着房间数量的增加,看到越来越少的房源。nan值就是最好的证明。
"""
#基于房源数量进行透视
# print(sudf.pivot_table('Rent','Zip','Beds',aggfunc='count'))
"""
由结果可知,数据是稀疏的。没关系,还可以继续分析。
"""

#2.2.2可视化数据

"""
由于目前的数据是基于邮政编码的,最好使用热图作为可视化数据的方法。使用folium的python库来实现。
"""

#由于缺少包含两到三间卧室的公寓,可以先缩减数据,聚焦到工作室和一间卧室的房源。
su_lt_two = sudf[sudf['Beds']<2]

# import folium
# map = folium.Map(location=[40.748817,-73.985428],zoom_start=13)
# map.geo_json(geo_path=r'D:/python机器学习+数据分析/Python机器学习实践指南(中文版带书签)、原书代码、数据集/PMLB Datasets/PMLB Datasets/PMLB Datasets copy/nyc_boroughs.geojson',
#              data=su_lt_two,
#              columns=['Zip','Rent'],
#              key_on ='feature.properties.postalCode',
#              threshold_scale=[1700.00,1900.00,2100,2300.00,2500.00,2750.00],
#              fill_color='YlOrRd',fill_opacity=0.7,line_opacity=0.2,
#              legend_name='Rent(%)',reset=True
#              )
# map.create_map(path='nyc.html')

"""
对数据建模
"""
import patsy
import statsmodels.api as sm
f = 'Rent~Zip + Beds'  #Rent是因变量,Zip+Beds是预测变量。邮编和卧室数量如何影响价格
"""
将公式和包含相应列名的数据放一起,传递给patsy.dmatrices().
然后设置patsy,返回一个数据框,其中X矩阵由预测变量组成,而y向量由响应变量组成。
传递给sm.OLS(),之后调研fit()运行模型。
"""
y,X = patsy.dmatrices(f,su_lt_two,return_type='dataframe')
results = sm.OLS(y,X).fit()
"""
  打印结果分析:看到模型包含262个观测样本,调整后的R2位0.282,F值尾1.21e-10,具有统计显示性。
显著性质所建模型,仅仅使用卧室数量和邮政编码,就已经能够解释约三分之一的价格差异。
  看看中间一大堆数据吧。中间部分提供了模型中每个自变量的有关信息。从左至右,看到有变量、变量在模型中的系数。
标准误差,t统计值,t统计值的p值,及置信区间。
  如果看P值这一列,可以确定独立变量从统计的角度来看是否具有意义。在回归模型中具有统计学意义,
意味着一个独立变量和响应变量之间的关系不太可能偶然发生。通常,统计学家使用0.05的p值来确定。
一个0.05的p值意味着看到的结果只有5%的几率是偶然发生的。从结果看,卧室的数量显然有意义。
   邮编会有什么影响呢?截距代表了10001的邮编。建立线性回归模型的时候,是需要截距。
截距就是回归线和y轴交叉的地方。Statsmodels会自动选择一个预测变量作为截距。
   卧室的数量,截距是显著的。邮编并不显著。显著的几个10001,10029和10035,具有很高的负置信区间。
"""
# print(results.summary())

"""
2.3.1预测
"""
# print(X.head())
"""
结果看出,输入是用所谓的虚拟变量进行编码。由于邮编不是胡数字的,为了表示这个特征,
系统使用了虚拟编码。如果某个公寓在10003中,那么该列将被编码为1,而其他编码都是0.
卧室是数值型的,系统根据实际的数字进行编码。
"""
to_pred_idx = X.iloc[0].index
to_pred_zeros = np.zeros(len(to_pred_idx))
tpdf = pd.DataFrame(to_pred_zeros,index = to_pred_idx,columns=['value'])
# print(tpdf)
"""
刚刚使用了X矩阵索引,并用0填充数据。现在填充一些实际的值,比如对10009区域的、包含一间卧室的公寓估价。
"""
tpdf.loc['Intercept']=1
tpdf.loc['Beds']=1
tpdf.loc['Zip[T.10009]']=1
# print(tpdf)  #截距10009邮政编码已经被设置为1了。卧室数量’Beds也变成1了。

#已经将特征设置为适当的值,现在使用该模型返回一个预测。
# print(results.predict(tpdf['value']))  #2529.56

#results是保存模型的变量名。这个模型对象有一个.predict()方法,使用自己的输入值调用该方法。

#如果想要增加一间卧室怎么办?
tpdf['value'] = 0
tpdf.loc['Intercept'] = 1
tpdf.loc['Beds'] =2
tpdf.loc['Zip[T.10009]'] = 1
# print(tpdf)  #卧室数量更新为2

# print(results.predict(tpdf['value']))   #2378.035。可以看出,增加一间卧室,大概多花200美元。
#如果地区选择在10002的话,会是什么情况呢?
tpdf['value'] = 0
tpdf.loc['Intercept'] = 1
tpdf.loc['Beds'] = 2
tpdf.loc['Zip[T.10002]']=1
print(results.predict(tpdf['value']))  #2651.176 .10002地区比10009地区稍微便宜点呢。

"""
目前,只检视了邮政编码、卧室和出租价格之间的关系。虽然有一定的解释能力,但是数据量太小,特征太少,
无法充分的观测房地产估值。
也可以添加更多的特征和数据。
"""

"""
本章,学习了如何获取房地产列表的数据,利用pandas的功能操作和清洗数据,通过热图检视数据,最后,
构建并使用回归模型预估公寓价格。
目前只是接触了机器学习的表层,下面继续探索深层算法和应用。
"""


猜你喜欢

转载自blog.csdn.net/wuxiaosi808/article/details/86640148