项目来源: https://www.kaggle.com/anthonypino/melbourne-housing-market
项目简介: 利用以往的房屋销售信息,分析哪种房屋最值得推荐给投资者进行投资。
PS: 本次项目是在jupyter上运行的。
导入模块:
%matplotlib inline
import pandas as pd
import seaborn as sns
import statsmodels.formula.api as smf
from sklearn.linear_model import LinearRegression
from sklearn import metrics
from sklearn.model_selection import train_test_split
import numpy as np
from scipy.stats import norm
from scipy import stats, integrate
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['font.size'] = 12
plt.rcParams['axes.unicode_minus'] = False
加载数据:
melbourne_data = pd.read_csv("./Melbourne_housing_FULL.csv")
melbourne_data.head(10)
接下来正式开始进行分析啦!
1 数据探索与数据清洗
1.1 数据探索
melbourne_data.shape
melbourne_data.info()
从上面的数据信息可以看出,非数值数据被视为对象。该列表包括以下列:“suburban”、“Address”、“Type”、“Method”、“SellerG”、“Date”、“councileArea”、“Regionname”。在接下来的几个步骤中,我们将把对象数据类型更改为category和Date数据类型。
melbourne_data.select_dtypes(["object"]).columns
1.2 更换数据类型
objdtype_cols = melbourne_data.select_dtypes(["object"]).columns
melbourne_data[objdtype_cols] = melbourne_data[objdtype_cols].astype('category')
melbourne_data.info()
melbourne_data['Date'] = pd.to_datetime( melbourne_data['Date'])
melbourne_data.info()
在接下来的几个步骤中,我们将对数值特征变量进行数据预处理。
melbourne_data.describe().T
观察以上有关数字数据的信息,可以注意到邮政编码也被视为数字数据。既然我们知道邮政编码是一个分类数据,我们将把它分类。
melbourne_data["Postcode"] = melbourne_data["Postcode"].astype('category')
melbourne_data.describe().T
仔细评估数据后,可以注意到变量“Rooms”和“Bedroom2”非常相似,应该删除其中一列以避免重复数据。
melbourne_data['b 2 r'] = melbourne_data["Bedroom2"] - melbourne_data["Rooms"]
melbourne_data[['b 2 r', 'Bedroom2', 'Rooms']].head()
melbourne_data = melbourne_data.drop(['b 2 r', 'Bedroom2'], 1)
1.3 缺失值处理
我们可以使用多种方法来探索缺失的数据。在这里,我们将首先使用一个可视化的方式来获得一些提示。在后面的步骤中,我们将进行一些计算,以获得每个变量中丢失数据的确切数量。根据数据、我们的经验和业务需要,我们要么填写缺失的值,要么删除具有空值的行或列。
fig, ax = plt.subplots(figsize=(15,7))
sns.heatmap(melbourne_data.isnull(), yticklabels=False,cmap='viridis')
从上图可以得出结论,price,bathroom,car和landsize,lattitude和longtitude有部分缺失值,在buildingarea和bulityear中有许多缺少的值。在下一步中,让我们研究缺失值的计数。
melbourne_data.isnull().sum()/len(melbourne_data)*100
从上面的信息中,我们可以注意到很少的特性变量仍然有很大比例的缺失值。此时我们将忽略它,但在稍后的状态中,如果我们将这些作为后续的特征变量,我们将探索填充这些信息或从数据中删除这些信息的方法。
melbourne_data = melbourne_data.drop(["Landsize", "BuildingArea", "YearBuilt"], axis=1)
melbourne_data.dropna(subset=["Price"], inplace=True)
melbourne_data['Car']=melbourne_data['Car'].fillna(melbourne_data['Car'].mode()[0])
melbourne_data['Bathroom']=melbourne_data['Bathroom'].fillna(melbourne_data['Bathroom'].mode()[0])
melbourne_data.shape
melbourne_data.isnull().sum()/len(melbourne_data)*100
1.4 寻找异常数据
异常值可以显著影响数据分析,也可以影响数据的规范化。在数据预处理过程中,识别和删除它们是非常重要的。在接下来的几个步骤中,我们将在数据中处理异常值(如果有的话)。
melbourne_data.describe().T
从上面的统计总结中我们可以看到,我们数据中的最高价格接近1120万美元。这看起来像是一个明显的异常值。但是在删除它之前,让我们首先确保在这个范围内只有很少的值。
melbourne_data['PriceRange'] = np.where(melbourne_data['Price'] <= 100000, '0-100,000',
np.where ((melbourne_data['Price'] > 100000) & (melbourne_data['Price'] <= 1000000), '100,001 - 1M',
np.where((melbourne_data['Price'] > 1000000) & (melbourne_data['Price'] <= 3000000), '1M - 3M',
np.where((melbourne_data['Price']>3000000) & (melbourne_data['Price']<=5000000), '3M - 5M',
np.where((melbourne_data['Price']>5000000) & (melbourne_data['Price']<=6000000), '5M - 6M',
np.where((melbourne_data['Price']>6000000) & (melbourne_data['Price']<=7000000), '6M - 7M',
np.where((melbourne_data['Price']>7000000) & (melbourne_data['Price']<=8000000), '7M-8M',
np.where((melbourne_data['Price']>8000000) & (melbourne_data['Price']<=9000000), '8M-9M',
np.where((melbourne_data['Price']>9000000) & (melbourne_data['Price']<=10000000), '9M-10M',
np.where((melbourne_data['Price']>10000000) & (melbourne_data['Price']<=11000000), '10M-11M',
np.where((melbourne_data['Price']>11000000) & (melbourne_data['Price']<=12000000), '11M-12M', '')
))))))))))
melbourne_data.groupby(['PriceRange']).agg({'PriceRange': ['count']})
通过研究上表,可以得出以下结论:
- 1个数据项,范围0-100,00
- 7M-8M范围内有2个数据
- 8M-9M范围内有1个数据
- 11M-12M范围内有1个数据,
为了本研究的目的,让我们删除符合上述条件的行。
melbourne_data.info()
melbourne_data.describe().T
melbourne_data.drop(melbourne_data[(melbourne_data['PriceRange'] == '0-100,000') |
(melbourne_data['PriceRange'] == '7M-8M') |
(melbourne_data['PriceRange'] == '8M-9M') |
(melbourne_data['PriceRange'] == '11M-12M')].index, inplace=True)
melbourne_data.describe().T
melbourne_data.groupby(['Rooms'])['Rooms'].count()
melbourne_data.drop(melbourne_data[(melbourne_data['Rooms'] == 12) |
(melbourne_data['Rooms'] == 16)].index, inplace=True)
melbourne_data.describe().T
numerics = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
melbourne_data.select_dtypes(include = numerics).hist(bins=15, figsize=(15, 6), layout=(2, 4))
melbourne_data['Distance'] = round(melbourne_data['Distance'])
melbourne_data.shape
2 数据呈现与关系
2.1 我们考虑的第一个因素是价格与年份和季节的关系。然后利用线性函数预测2019年和2020年的价格。
2.1.1 每种类型的房子价格年趋势
melbourne_data['Year']=melbourne_data['Date'].apply(lambda x:x.year)
melbourne_data.head(5)
melbourne_data_h=melbourne_data[melbourne_data['Type']=='h']
melbourne_data_u=melbourne_data[melbourne_data['Type']=='u']
melbourne_data_t=melbourne_data[melbourne_data['Type']=='t']
melbourne_data_h_y=melbourne_data_h.groupby('Year').mean()
melbourne_data_u_y=melbourne_data_u.groupby('Year').mean()
melbourne_data_t_y=melbourne_data_t.groupby('Year').mean()
melbourne_data_h_y.head()
melbourne_data_h_y['Price'].plot(kind='line', color='r',label='House')
melbourne_data_u_y['Price'].plot(kind='line', color='g',label='Condo')
melbourne_data_t_y['Price'].plot(kind='line', color='b',label='Townhouse')
year_xticks=[2016,2017,2018]
plt.ylabel('Price')
plt.xticks(year_xticks)
plt.title('每种类型的房子价格年趋势')
plt.legend()
House大幅下跌10万套,Condo价格缓慢攀升,而Townhouse价格保持稳定。从这张图上可以看出,预计House会下降,但坡度较小的Townhouse房价会下降,不变的Condo价格会上升。对开发商来说,是时候在2019年建更多的公寓了。购房者的住房预算需要削减,是时候在2019年买房了。
2.2 预测2019年和2020年Southern Metropolitan所有类型的房屋、Southern Metropolitan的Condo和Eastern Metropolitan的Condo价格
melbourne_data.shape
melbourne_data.columns
melbourne_data_South_M=melbourne_data[melbourne_data['Regionname']=='Southern Metropolitan']
melbourne_data_South_M_average=melbourne_data_South_M.groupby(['Year'])['Price'].mean()
X = melbourne_data_South_M[[ 'Year']]
y = melbourne_data_South_M[['Price']]
lm2 = LinearRegression()
lm2.fit(X, y)
lm2.intercept_
lm2.coef_
X_new = pd.DataFrame({'Year': [2019,2020,2021]})
lm2.predict(X_new)
根据这一粗略估算,2019年和2020年墨尔本房屋平均价格将为1557639、1630019。
2.2.1 Southern Metropolitan的Condo价格预测
melbourne_data_SM=melbourne_data[melbourne_data['Regionname']=='Southern Metropolitan']
melbourne_data_SM_u=melbourne_data_SM[melbourne_data_SM['Type']=='u']
melbourne_data_SM_u.shape
lm1 = smf.ols(formula='Price ~ Year', data=melbourne_data_SM_u).fit()
lm1.params
X_new = pd.DataFrame({'Year': [2016,2017,2018,2019,2020,2021]})
lm1.predict(X_new)
lm1.rsquared
这拟合度,看看就得了。
2.2.2 Eastern Metropolitan的Condo价格预测
melbourne_data_E=melbourne_data[melbourne_data['Regionname']=='Eastern Metropolitan']
melbourne_data_E_u=melbourne_data_E[melbourne_data_E['Type']=='u']
lme = smf.ols(formula='Price ~ Year', data=melbourne_data_E_u).fit()
lme.params
melbourne_data_E_u.shape
X_new = pd.DataFrame({'Year': [2016,2017,2018,2019,2020,2021]})
lme.predict(X_new)
对于Eastern Metropolitan,预计2016年至2017年价格将增长10%,2018年至2019年价格将增长7.7%。虽然和南部地区相比,这个数字要少一些。
2.3 Seasonal performance
melbourne_data['Month']=pd.DatetimeIndex(melbourne_data['Date']).month
melbourne_data_2016=melbourne_data[melbourne_data['Year']==2016]
melbourne_data_2017=melbourne_data[melbourne_data['Year']==2017]
melbourne_data_2018=melbourne_data[melbourne_data['Year']==2018]
melbourne_data_2016_count=melbourne_data_2016.groupby(['Month']).count()
melbourne_data_2017_count=melbourne_data_2017.groupby(['Month']).count()
melbourne_data_2018_count=melbourne_data_2018.groupby(['Month']).count()
Comparison={2016:melbourne_data_2016.shape,2017:melbourne_data_2017.shape,2018:melbourne_data_2018.shape}
Comparison
label_2016=['January','March','April','May','June','July','August','September','October','November','December']
plt.pie(melbourne_data_2016_count['Price'],labels=label_2016,autopct='%.1f %%')
plt.title('Year 2016')
plt.show()
label_2017=['January','February','March','April','May','June','July','August','September','October','November','December']
plt.pie(melbourne_data_2017_count['Price'],labels=label_2017,autopct='%.1f %%')
plt.title('Year 2017')
label_2018=['January','February','March','June','October']
plt.pie(melbourne_data_2018_count['Price'],labels=label_2018,autopct='%.1f %%')
plt.title('Year 2018')
总的来说,2016年和2017年的冬季似乎销量最少。这意味着从5月到11月房屋销售将有更多优惠。2018年的数据缺失较多,与其他年份相比只有三分之一左右,因此很难得出结论。
2.4 Region versus Price
melbourne_data['Regionabb'] = melbourne_data['Regionname'].map({'Northern Metropolitan':'N Metro',
'Western Metropolitan':'W Metro',
'Southern Metropolitan':'S Metro',
'Eastern Metropolitan':'E Metro',
'South-Eastern Metropolitan':'SE Metro',
'Northern Victoria':'N Vic',
'Eastern Victoria':'E Vic',
'Western Victoria':'W Vic'})
2.4.1每种类型的地区价格变化与年份
总的来说,东、北、南和西Metropolitan都是受欢迎的地区。 接下来看看每种类型的地区价格。
sns.lmplot(x="Year", y="Price",hue="Type", data=melbourne_data,col='Regionabb', x_estimator=np.mean,col_wrap=2)
plt.ylim(200000, 2000000)
plt.xlim(2015,2020)
sns.lmplot(x="Year", y="Price",hue="Type", data=melbourne_data[melbourne_data['Regionabb']=='S Metro'], x_estimator=np.mean);
总体而言, Townhouse in E Metro, Condo in East Metro, House in S Metro, Condo in S Metro and Condo in N Metro每年都在增长。
melbourne_data_S=melbourne_data[melbourne_data['Regionabb']=='S Metro']
sns.lmplot(x="Year", y="Price", data=melbourne_data_S[melbourne_data_S['Type']=='u'], x_estimator=np.mean)
2.4.2 特征工程,以获得每个地区和类型的年数量增长率和价格增长率
Pct_change=melbourne_data.groupby(['Year','Regionabb','Type'],as_index=False)['Price'].mean()
Pct_change = Pct_change.sort_values(['Regionabb', 'Type','Year']).set_index(np.arange(len(Pct_change.index)))
Pct_change.info()
melbourne_data_count_region_y=melbourne_data.groupby(['Year','Regionabb','Type'],as_index=False)['Price'].count()
melbourne_data_count_region_y = melbourne_data_count_region_y.sort_values(['Regionabb', 'Type','Year']).set_index(np.arange(len(melbourne_data_count_region_y.index)))
melbourne_data_count_region_y.rename(columns={'Price':'Count'}, inplace=True)
def PCTM(gg):
df=pd.DataFrame(gg['Price'].pct_change())
df['Year']=gg['Year']
df['region']=gg['Regionabb']
df['Type']=gg['Type']
df=df[df['Year']!=2016]
return df
2.4.2.1 每个地区和类型的价格增长率超过5%
melboune_growthrate_y_t=PCTM(Pct_change)
melboune_growthrate_y_t1=melboune_growthrate_y_t[melboune_growthrate_y_t['region'].isin(['N Metro','S Metro','E Metro','SE Metro','W Metro','S Metro'])]
melboune_growthrate_y_t1.rename(columns={'Price':'Price Growth Rate'}, inplace=True)
melboune_growthrate_y_t1[melboune_growthrate_y_t1['Price Growth Rate']>0.05]
由于2018年大量数据缺失,S Metro的condo在2017年和2018年分别为8.7%和2.7%。如果选择2017年来看价格的增长,E Metro、SE Metro和S Metro的condo和townhouse、W Metro的townhouse和S Metro的house均呈现超过5%的正增长。展望2018年,人们似乎转向在SE、E Metro或者S Metro购买更多。
2.4.2.2 按类型划分,数量最多的20个地区
Sales_count=melbourne_data.groupby(['Regionabb','Type'])['Price'].count()
Sales_count.nlargest(20)
def PCTMC(gg):
df=pd.DataFrame(gg['Count'].pct_change())
df['Year']=gg['Year']
df['region']=gg['Regionabb']
df['Type']=gg['Type']
df=df[df['Year']!=2016]
return df
2.4.2.3 每个地区和类型的计数增长率超过20%
melboune_growthrate_y_c=PCTMC(melbourne_data_count_region_y)
melboune_growthrate_y_c1=melboune_growthrate_y_c[melboune_growthrate_y_c['region'].isin(['N Metro','S Metro','E Metro','SE Metro','W Metro','S Metro'])]
melboune_growthrate_y_c1.rename(columns={'Count':'Count Growth Rate'}, inplace=True)
melboune_growthrate_y_c1[melboune_growthrate_y_c1['Count Growth Rate']>0.2]
2.4.2.4 按年份地区和类型划分,实际计数超过1000
melboune_count1=melbourne_data_count_region_y[melbourne_data_count_region_y['Regionabb'].isin(['S Metro','E Metro','SE Metro','W Metro','S Metro','N Metro'])]
melboune_count1[melboune_count1['Count']>1000]
从以上信息统计的增长百分比和实际销售额按年度计算,S Metro和N Metro似乎是人们倾向于支付更多,购买更多的地区,但随着价格不断上涨,那些住在南部的试图转移到E Metro和SE Metro。
本节结论: 1.house方面,S Metro 2017年价格增长5%以上,三年销售4718套,排名第二;Condo方面,S Metro 2017年销售2782套,排名第四,价格增长8.7%。 2.E Metro和SE Metro的condo和townhouse潜力很大,现在没有S Metro那么吸引人。他们的数量增长率超过100%,价格增长率超过8%。
2.5 其他数值特征与价格间的关系
2.5.1 Method vs Price
sns.boxplot(x = 'Method', y = 'Price', data = melbourne_data)
plt.show()
2.5.2 Rooms
sns.lmplot(x="Year", y="Price", hue="Rooms", data=melbourne_data, x_estimator=np.mean)
2.5.3 Distance vs Price
结论:离城中心越远,价格越低。
sns.lmplot(x="Distance", y="Price", data=melbourne_data, x_estimator=np.mean);
2.5.4 Car spot vs Price
sns.lmplot(x="Car", y="Price", data=melbourne_data, x_estimator=np.mean)
2.6 Ideal house type
找出最理想的房子类型。
2.6.1 在S Metro,按类型、rooms、bathroom统计排名前10的房子类型
Ideal_House=melbourne_data.groupby(['Regionabb','Type','Rooms','Bathroom'])['Price'].count()
Ideal_House.loc[['S Metro'],'h'].nlargest(10)
结论:在S Metro,3房1卫或2卫的房子和4房2卫的房子销量最大。
2.6.2 按类型、rooms、bathroom统计排名前10的房子类型
Ideal_House.nlargest(10)
结论:其中,N Metro房最受欢迎,W Metro紧随其后。一般来说,house比其他类型的好。拥有两间卧室和一间浴室的S Metro的condo被列为销量前三名。
2.6.3 在E Metro的condo中,按类型、rooms、bathroom统计排名前10的房子类型
Ideal_House.loc[['E Metro'],'u'].nlargest(10)
E Metro区最好的公寓类型是两室一厅。
2.7 关系热图
corrmat=melbourne_data.corr()
fig,ax=plt.subplots(figsize=(12,10))
sns.heatmap(corrmat,annot=True,annot_kws={'size': 12})
与其他因素相比,rooms和bathroom与price的相关性最高。
3 最终结论
- 从2.1.1可以得出:house一般会下降,condo价格会上升。这意味着投资公寓会更好。
- 从2.4得出:在hous方面,S Metro 2017年价格增长超过5%,三年销售4718套,排名第二;在condo方面,S Metro 2017年销售2782套,排名第四,价格增长8.7%。
- 从2.4得出:E Metro和SE Metro的condo和townhouse潜力很大,现在没有S Metro那么吸引人。增长率超过100%,价格增长率超过8%。
- 从2.6得出,南方地铁的condo排在第三位。虽然N Metro和W Metro的house数量最多,但它们的价格正在下降,如第2.4节sns.lmplot所示。从数量上看,S Metro的condo具有巨大的市场潜力,因为其数量排名第三,价格在第2.4节中呈现出逐年上升的趋势。S Metro的house也有很大的市场,但增长率不如condo。
- 最后在结合理想户型,2rooms1bathroom的S Metro的condo将被推荐给投资者或开发商。
另外为方便需要的朋友运行代码,我也把完整的代码和数据文件放到了网盘上,需要的朋友自取。 链接:https://pan.baidu.com/s/1qw-fwmykg6-G3RmLBKUT7A 提取码:1024
|