用 Python 分析香港樓市

背景
香港的貧富差距問(wèn)題一直十分尖銳,最突出的體現(xiàn)就是收入和樓價(jià)的巨大差異。早在60年代末香港房?jī)r(jià)就經(jīng)歷了暴漲,人們?cè)缫褜?duì)不動(dòng)產(chǎn)的金融屬性了如指掌,全港的投資情緒一直都相當(dāng)火熱。即便香港當(dāng)前失業(yè)率高企,經(jīng)濟(jì)環(huán)境較差,但購(gòu)買(mǎi)力仍在,樓市依然堅(jiān)挺。
為了深入了解香港房地產(chǎn)市場(chǎng),本文用Pyhton采集了香港在售26281套二手房數(shù)據(jù)并做可視化分析,試圖從數(shù)據(jù)層面理解香港樓市現(xiàn)狀。
可視化分析
九龍房源最多,港島價(jià)格更高
香港特別行政區(qū),下轄香港島、九龍半島、新界3個(gè)地區(qū)共18個(gè)分區(qū)。九龍半島在售二手房源共8108個(gè),占比28.62%。根據(jù)中原城市指數(shù)CCI(僅包括大型屋苑),港島報(bào)187.66點(diǎn),高于香港其他地區(qū)。
具體分區(qū)來(lái)看,香港在售二手房源集中分布在葵青區(qū)、元朗區(qū)、屯門(mén)區(qū)等地,而九龍城區(qū)、深水埗區(qū)、中西區(qū)、灣仔區(qū)、東區(qū)等地房?jī)r(jià)較高。香港在售二手房實(shí)用呎價(jià)均價(jià)為$18688/呎(折合人民幣約172652元/平方米),最低實(shí)用呎價(jià)$4421/呎,最高實(shí)用呎價(jià)$96965/呎。
將軍澳二手房源最多
將軍澳、元朗和屯門(mén)在售二手房均超1000套,其中,將軍澳以2112套二手房源居首。
九龍站二手房均價(jià)最高
九龍站、山頂/南區(qū)、貝沙灣和中半山在售二手房均價(jià)超過(guò)$3萬(wàn)/呎,九龍站以$37232/呎遙遙領(lǐng)先,遠(yuǎn)高于香港二手房整體均價(jià)。
小戶(hù)型為主,2房占比超一半
從建筑面積來(lái)看,香港在售二手房普遍建面在500呎-1200呎(46-111平方米),占比高達(dá)78.52%,共計(jì)18825套。
從居室來(lái)看,香港在售二手房中,2房共計(jì)12231套,占比51.05%;3房共計(jì)7613套,占比31.76%;4房以上71套,占比僅為0.29%。
各樓齡段均有一定比例分布
從香港在售二手房樓齡來(lái)看,25-39年樓齡的二手房源最多,共7396套,占比31.31%;15-24年5939套,占比25.36%;40年以上房源也有2347套,占比10.93%。
50%以上二手房低于1000萬(wàn)
從香港在售二手房售價(jià)來(lái)看,$501-$1000萬(wàn)(約429-858萬(wàn)人民幣)房源數(shù)量為12301套,占比51.31%。
描述性統(tǒng)計(jì)

相關(guān)性分析



從相關(guān)系數(shù)表和回歸圖來(lái)看,間隔(即居室)和樓齡都與香港二手房房?jī)r(jià)無(wú)明顯的相關(guān)性。實(shí)用面積與房?jī)r(jià)具有較強(qiáng)的正相關(guān)性,一般來(lái)說(shuō),人們?cè)诳捶孔訒r(shí)看到的面積是建筑面積,但卻不是實(shí)用面積。套內(nèi)建筑面積=套內(nèi)使用面積+套內(nèi)墻體面積+陽(yáng)臺(tái)面積,而實(shí)用面積就是套內(nèi)使用面積。另外,實(shí)用率與房?jī)r(jià)也無(wú)相關(guān)性,這與大部分人的感性認(rèn)識(shí)存在偏差。
技術(shù)實(shí)現(xiàn)
本文數(shù)據(jù)來(lái)源于中原地產(chǎn),網(wǎng)頁(yè)結(jié)構(gòu)相對(duì)簡(jiǎn)單。數(shù)據(jù)清洗主要用到Python的pandas庫(kù),由于內(nèi)容較多,僅提供核心字段清洗代碼。數(shù)據(jù)可視化主要用到Python的pyecharts庫(kù),都是一些基礎(chǔ)圖表。
數(shù)據(jù)獲取
爬蟲(chóng)核心代碼
#將繁體轉(zhuǎn)換成簡(jiǎn)體
def tradition2simple(line):
return Converter('zh-hans').convert(line)
#解析網(wǎng)頁(yè)
def get_page(page):
if page <11:
url = 'http://hk.centanet.com/findproperty/BLL/Result_SearchHandler.ashx?url=http%3A%2F%2Fhk.centanet.com%2Ffindproperty%2Fzh-HK%2FHome%2FSearchResult%3Fposttype%3DS%26src%3DC%26minprice%3D%26maxprice%3D%26sortcolumn%3D%26sorttype%3D%26limit%3D100%26currentpage%3D{0}'.format(page)
else:
url = 'http://hk.centanet.com/findproperty/BLL/Result_SearchHandler.ashx?url=http%3A%2F%2Fhk.centanet.com%2Ffindproperty%2Fzh-HK%2FHome%2FSearchResult%3Fposttype%3DS%26src%3DC%26minprice%3D%26maxprice%3D%26sortcolumn%3D%26sorttype%3D%26limit%3D-1%26currentpage%3D{0}'.format(page)
req = requests.get(url, headers = headers)
bs = req.json()
# print(bs)
ts = tradition2simple(bs['post'])
# print(ts)
html = etree.HTML(ts)
if __name__ == '__main__':
ua = UserAgent(verify_ssl=False)
headers = {"User-Agent": ua.random}
for page in range(1,2624): #共2623頁(yè)
get_page(page)
# time.sleep(1)
print("第%d頁(yè)爬取完成"%page)
print('-'*100)
數(shù)據(jù)預(yù)覽

數(shù)據(jù)清洗
建筑面積/單價(jià)
#異常字符替換為空
df["建筑面積"] = df["建筑面積"].str.replace(",","").astype("float")
df["建面單價(jià)"] = df["建面單價(jià)"].str.replace("$","").str.replace(",","").str.replace("/呎","").astype("float")
#建筑面積和建面單價(jià)缺失值用均值填充
df = df.fillna(value={'建筑面積':df["建筑面積"].mean(),'建面單價(jià)':df["建面單價(jià)"].mean()})
間隔
# 存在缺失值、換行符、非數(shù)字型、無(wú)房間數(shù)等臟數(shù)據(jù)
df["間隔"] = df["間隔"].str.replace("\r\n","").str[:1]
df = df[ ~ df['間隔'].isin(['('])] #刪除某列包含特殊字符的行
df["間隔"] = df["間隔"].str.replace("開(kāi)","0").astype("float")
df = df.fillna(value={'間隔':df["間隔"].mean()})
df["間隔"] = df["間隔"].astype("int")
售價(jià)
#售價(jià)單位存在萬(wàn)和億,進(jìn)行統(tǒng)一化處理
df["售價(jià)"] = (df["售價(jià)"].str.replace("$","").str.replace(",","").str[:-1].astype(float) * df['售價(jià)'].str[-1].map({"萬(wàn)": 1, "億": 10000})).astype("int")
數(shù)據(jù)可視化
回歸圖
fig,axes=plt.subplots(5,1,figsize=(12,30))
sns.regplot(x='間隔',y='實(shí)用單價(jià)',data=df1,color='green',marker='*',ax=axes[0])
sns.regplot(x='樓齡',y='實(shí)用單價(jià)',data=df1,color='green',marker='*',ax=axes[1])
sns.regplot(x='實(shí)用面積',y='實(shí)用單價(jià)',data=df1,color='green',marker='*',ax=axes[2])
sns.regplot(x='建筑面積',y='實(shí)用單價(jià)',data=df1,color='green',marker='*',ax=axes[3])
sns.regplot(x='實(shí)用率',y='實(shí)用單價(jià)',data=df1,color='green',marker='*',ax=axes[4])
條形圖
df5 = df1.groupby('屋苑位置')['實(shí)用單價(jià)'].count()
df5 = df5.sort_values(ascending=True)
df5 = df5.tail(10)
print(df5.index.to_list())
print(df5.to_list())
c = (
Bar(init_opts=opts.InitOpts(theme=ThemeType.WONDERLAND))
.add_xaxis(df5.index.to_list())
.add_yaxis("",df5.to_list()).reversal_axis() #X軸與y軸調(diào)換順序
.set_global_opts(title_opts=opts.TitleOpts(title="香港二手房數(shù)量TOP10",subtitle="數(shù)據(jù)來(lái)源:中原地產(chǎn) \t制圖:J哥",pos_left = 'left'),
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=13)), #更改橫坐標(biāo)字體大小
yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=13)), #更改縱坐標(biāo)字體大小
)
.set_series_opts(label_opts=opts.LabelOpts(font_size=16,position='right'))
)
c.render_notebook()
餅圖
df2 = df1.groupby('間隔')['實(shí)用單價(jià)'].count()
print(df2)
df2 = df2.sort_values(ascending=False)
regions = df2.index.to_list()
values = df2.to_list()
c = (
Pie(init_opts=opts.InitOpts(theme=ThemeType.WONDERLAND))
.add("", list(zip(regions,values)))
.set_global_opts(title_opts=opts.TitleOpts(title="香港二手房間隔分布",subtitle="數(shù)據(jù)來(lái)源:中原地產(chǎn)\n制圖:J哥",pos_top="1%",pos_left = 'left'))
.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}:go7utgvlrp%",font_size=16))
)
c.render_notebook()
更多閱讀
特別推薦

點(diǎn)擊下方閱讀原文加入社區(qū)會(huì)員
