用Python分析北京市蛋殼公寓租房數據

本文的文字及圖片來源於網絡,僅供學習、交流使用,不具備任何商業用途,若有問題請及時聯繫咱們以做處理html

近期,蛋殼公寓「爆雷」事件持續發酵,期間因拖欠房東房租與租客退款,蛋殼公寓陷入討債風波,全國多地蛋殼公寓辦公區域出現大規模解約事件,而做爲蛋殼公寓總部所在地北京,天然首當其衝。web

爲了應對大規模的解約,北京在全市已經設立了100多個蛋殼公寓矛盾糾紛接待點,包含了蛋殼公寓涉及到的12個區,這些接待點下沉到了街道甚至社區,以方便涉及蛋殼公寓事件的房東和租客諮詢和處理糾紛。正則表達式

長租公寓暴雷,很多年輕人不得不流離失所,構成疫情下的另外一個經濟寫照,事態何去何從,值得關注。本文從數據角度出發,爬取了蛋殼公寓北京區域共6025條公寓數據,清洗數據,並進行可視化分析,爲你們瞭解蛋殼公寓提供一個新的視角。服務器

數據獲取

蛋殼公寓網頁結構相對簡單,數據結構統一,簡單的url翻頁構造便可。須要注意的是極少數網頁會返回404,須要添加判斷過濾掉。本文用request請求到數據,用xpath對返回的數據進行解析,最後以追加模式將數據存儲爲csv文件。爬蟲核心代碼以下:網絡

def get_danke(href):
    time.sleep(random.uniform(0, 1))  #設置延時,避免對服務器產生壓力
    response = requests.get(url=href, headers=headers)
    if response.status_code == 200:  #部分網頁會跳轉404,須要作判斷
        res = response.content.decode('utf-8')
        div = etree.HTML(res)
        items = div.xpath("/html/body/div[3]/div[1]/div[2]/div[2]")
        for item in items:
            house_price=item.xpath("./div[3]/div[2]/div/span/div/text()")[0]
            house_area=item.xpath("./div[4]/div[1]/div[1]/label/text()")[0].replace('建築面積:約','').replace('㎡(以現場勘察爲準)','')
            house_id=item.xpath("./div[4]/div[1]/div[2]/label/text()")[0].replace('編號:','')
            house_type=item.xpath("./div[4]/div[1]/div[3]/label/text()")[0].replace('\n','').replace(' ','').replace('戶型:','')
            house_floor=item.xpath("./div[4]/div[2]/div[3]/label/text()")[0].replace('樓層:','')
            house_postion_1=item.xpath("./div[4]/div[2]/div[4]/label/div/a[1]/text()")[0]
            house_postion_2=item.xpath("./div[4]/div[2]/div[4]/label/div/a[2]/text()")[0]
            house_postion_3=item.xpath("./div[4]/div[2]/div[4]/label/div/a[3]/text()")[0]
            house_subway=item.xpath("./div[4]/div[2]/div[5]/label/text()")[0]
    else:
        house_price = None
        house_area = None
        house_id = None
        house_type = None
        house_floor = None
        house_postion_1 = None
        house_postion_2 = None
        house_postion_3 = None
        house_subway = None
......

因爲代碼運行過程當中中斷了幾回,最終將數據保存爲如下幾個csv文件中: 數據結構

數據處理

導入數據分析包

import pandas as pd
import numpy as np
from pathlib import Path
import re

導入數據併合並

找到文件夾中的全部csv文件,遍歷讀取數據,最後用concat方法合併全部數據。app

files = Path(r"D:\菜J學Python\數據分析\蛋殼公寓").glob("*.csv")
dfs = [pd.read_csv(f) for f in files]
df = pd.concat(dfs)
df.head()

數據去重

數據爬取過程當中有中斷,所以可能存在重複爬取的狀況,須要去重處理。echarts

df = df.drop_duplicates()

查看數據

用df.info()方法查看總體數據信息,結合預覽的數據,咱們能夠很容易發現,價格和麪積字段不是數字類型,須要轉換處理。樓層字段能夠提取出所在樓層和總樓層。dom

df.info()
<class 'pandas.core.frame.DataFrame'>
    Int64Index: 6026 entries, 0 to 710
    Data columns (total 9 columns):
     #   Column  Non-Null Count  Dtype 
    ---  ------  --------------  ----- 
     0   價格      6025 non-null   object
     1   面積      6025 non-null   object
     2   編號      6025 non-null   object
     3   戶型      6025 non-null   object
     4   樓層      6025 non-null   object
     5   位置1     6025 non-null   object
     6   位置2     6025 non-null   object
     7   小區      6025 non-null   object
     8   地鐵      6025 non-null   object
    dtypes: object(9)
    memory usage: 470.8+ KB

數據類型轉換

在字段類型轉換時報錯,檢查發現是數據存在一行髒數據,所以先刪除髒數據再作轉換便可。數據類型轉換用到astype()方法,提取所在樓層和總樓層時根據字符"/"分列便可,採用split()方法。函數

#刪除包含髒數據的行
jg = df['價格'] != "價格" 
df = df.loc[jg,:]

#將價格字段轉爲數字類型
df["價格"] = df["價格"].astype("float64")

#將面積字段轉爲數字類型
df["面積"] = df["面積"].astype("float64")

#提取所在樓層
df = df[df['樓層'].notnull()]
df['所在樓層']=df['樓層'].apply(lambda x:x.split('/')[0])
df['所在樓層'] = df['所在樓層'].astype("int32")

#提取總樓層
df['總樓層']=df['樓層'].apply(lambda x:x.split('/')[1])
df['總樓層'] = df['總樓層'].str.replace("層","").astype("int32")

地鐵字段清洗

地鐵字段能夠提取出地鐵數和距離地鐵距離。地鐵數經過統計字符"號線」的數量來計算,而距離地鐵距離經過正則表達式匹配出字符"米"前面的數字便可。爲方便理解,這裏直接構造函數進行清洗。

def get_subway_num(row):
    subway_num=row.count('號線')
    return subway_num

def get_subway_distance(row):
    distance=re.search(r'\d+(?=米)',row)
    if distance==None:
        return-1
    else:
        return distance.group()
df['地鐵數']=df['地鐵'].apply(get_subway_num)
df['距離地鐵距離']=df['地鐵'].apply(get_subway_distance)
df['距離地鐵距離']=df['距離地鐵距離'].astype("int32")

保存數據

數據清洗完畢後,用df.to_excel()將數據保存爲excel文件。

df.to_excel(r"\菜J學Python\數據分析\蛋殼公寓.xlsx")
df.head()

數據可視化

導入可視化相關包

import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
plt.rcParams['font.sans-serif'] = ['SimHei']  # 設置加載的字體名
plt.rcParams['axes.unicode_minus'] = False# 解決保存圖像是負號'-'顯示爲方塊的問題 
import jieba
from pyecharts.charts import *
from pyecharts import options as opts 
from pyecharts.globals import ThemeType  
import stylecloud
from IPython.display import Image

各行政區公寓數量

根據清洗後的數據繪製北京蛋殼公寓分佈地圖,咱們能夠很清晰的看到蛋殼公寓的佈局,朝陽區和通州區是蛋殼公寓主要分佈區域,延慶、密雲、懷柔、平谷和門頭溝地區蛋殼公寓分佈極少。 ​ 從各行政區數量上來看,朝陽區和通州區蛋殼公寓數量均超過1000個,朝陽區遙遙領先其餘地區,共計1877個,通州區緊隨其後,爲1027個。

df7 = df["位置1"].value_counts()[:10]
df7 = df7.sort_values(ascending=True)
df7 = df7.tail(10)
print(df7.index.to_list())
print(df7.to_list())
c = (
    Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK))
    .add_xaxis(df7.index.to_list())
    .add_yaxis("",df7.to_list()).reversal_axis() #X軸與y軸調換順序
    .set_global_opts(title_opts=opts.TitleOpts(title="各行政區公寓數量",subtitle="數據來源:蛋殼公寓 \t製圖:菜J學Python",pos_left = 'left'),
                       xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=13)), #更改橫座標字體大小
                       yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=13)), #更改縱座標字體大小
                       )
    .set_series_opts(label_opts=opts.LabelOpts(font_size=16,position='right'))
    )
c.render_notebook()

小區公寓數量TOP10

從小區數量來看,新建村小區、花香東苑和連心園西區蛋殼公寓數量最多,均超過50個。這也意味着,這些小區的租戶受蛋殼風波的影響相較於其餘小區更大。

df7 = df["小區"].value_counts()[:10]
df7 = df7.sort_values(ascending=True)
df7 = df7.tail(10)
print(df7.index.to_list())
print(df7.to_list())
c = (
    Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK,width="1100px",height="600px"))
    .add_xaxis(df7.index.to_list())
    .add_yaxis("",df7.to_list()).reversal_axis() #X軸與y軸調換順序
    .set_global_opts(title_opts=opts.TitleOpts(title="小區公寓數量TOP10",subtitle="數據來源:蛋殼公寓 \t製圖:菜J學Python",pos_left = 'left'),
                       xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=11)), #更改橫座標字體大小
                       yaxis_opts=opts.AxisOpts(axislabel_opts={"rotate":30}), #更改縱座標字體大小
                       )
    .set_series_opts(label_opts=opts.LabelOpts(font_size=16,position='right'))
    )
c.render_notebook()

蛋殼公寓租金分佈

對租金進行區間分段,咱們發現,北京蛋殼公寓的租金仍是至關有吸引力的,超過一半的公寓租金在2000-3000元/月。2000元/月如下的公寓數量佔比也高達26.13%。

#租金分段
df['租金分段'] = pd.cut(df['價格'],[0,1000,2000,3000,4000,1000000],labels=['1000元如下','1000-2000元','2000-3000元','3000-4000元','4000元以上'],right=False)
df11 = df["租金分段"].value_counts()
df11 = df11.sort_values(ascending=False)
df11 = df11.round(2)
print(df11)
c = (
        Pie(init_opts=opts.InitOpts(theme=ThemeType.DARK))
        .add(
            "",
            [list(z) for z in zip(df11.index.to_list(),df11.to_list())],
            radius=["20%", "80%"],   #圓環的粗細和大小
            rosetype='area'
 
        )
        .set_global_opts(legend_opts = opts.LegendOpts(is_show = False),title_opts=opts.TitleOpts(title="蛋殼公寓租金分佈",subtitle="數據來源:蛋殼公寓\n製圖:菜J學Python",pos_top="0.5%",pos_left = 'left'))
        .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}:{d}%",font_size=16))
    )
c.render_notebook()

各行政區租金分佈

咱們繼續將地區因素引入租金分析中,發現,不一樣行政區內的租金分佈也存在較大差別。以朝陽區爲例,2000-3000元/月的公寓佔比最多,而通州區1000-2000元/月的公寓佔比更多。這也很容易理解,畢竟所處的區位和經濟發展情況差別較大。

h = pd.pivot_table(df,index=['租金分段'],values=['價格'],
               columns=['位置1'],aggfunc=['count'])
k = h.droplevel([0,1],axis=1)  #刪除指定的索引/列級別
c = (
    Polar(init_opts=opts.InitOpts(theme=ThemeType.DARK))
    .add_schema(angleaxis_opts=opts.AngleAxisOpts(data=k.columns.tolist(), type_="category"))
    .add("1000如下",h.values.tolist()[0], type_="bar", stack="stack0")
    .add("1000-2000元",h.values.tolist()[1], type_="bar", stack="stack0")
    .add("2000-3000元", h.values.tolist()[2], type_="bar", stack="stack0")
    .add("3000-4000元", h.values.tolist()[3], type_="bar", stack="stack0")
    .add("4000元以上", h.values.tolist()[4], type_="bar", stack="stack0")
    .set_global_opts(title_opts=opts.TitleOpts(title="各行政區租金狀況",subtitle="數據來源:蛋殼公寓\n製圖:菜J學Python"))

)
c.render_notebook()

蛋殼公寓樓層分佈

從北京蛋殼公寓的樓層分佈來看,10層如下佔比高達73.92,高層和超高層不是蛋殼公寓的理想選擇。

# 漏斗圖 
df['樓層分段'] = pd.cut(df['所在樓層'],[0,10,20,30,40,1000000],labels=['10層如下','10-20層','20-30層','30-40層','40層以上'],right=False)
count = df['樓層分段'].value_counts() # pd.Series
print(count)
job = list(count.index)
job_count = count.values.tolist()
from pyecharts.charts import Funnel

c = (
    Funnel(init_opts=opts.InitOpts(theme=ThemeType.DARK))
    .add("", [list(i) for i in zip(job,job_count)])
    .set_global_opts(
        title_opts=opts.TitleOpts(title="蛋殼公寓樓層分佈",subtitle="數據來源:蛋殼公寓\n製圖:菜J學Python",pos_top="0.1%",pos_left = 'left'),legend_opts = opts.LegendOpts(is_show = False))
    .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}:{d}%",font_size=16))
)
c.render_notebook()

蛋殼公寓戶型分佈

從北京蛋殼公寓的戶型分佈來看,3室1衛爲主,共計2783個,其次纔是4室1衛。這與深圳蛋殼公寓以4室1衛爲主的狀況存在較大差別。

df2 = df.groupby('戶型')['價格'].count() 
df2 = df2.sort_values(ascending=False)[:10]
# print(df2)
bar = Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK))
bar.add_xaxis(df2.index.to_list())
bar.add_yaxis("",df2.to_list()) #X軸與y軸調換順序
bar.set_global_opts(title_opts=opts.TitleOpts(title="蛋殼公寓戶型分佈",subtitle="數據來源:蛋殼公寓\t製圖:菜J學Python",pos_top="2%",pos_left = 'center'),
                   xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改橫座標字體大小
                   yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改縱座標字體大小
                   )
bar.set_series_opts(label_opts=opts.LabelOpts(font_size=16,position='top'))
bar.render_notebook()

蛋殼公寓面積分布

從北京蛋殼公寓的面積分布來看,86.77%的公寓面積不足20㎡。北京10㎡如下的蛋殼公寓佔比達到了21.2%,即使如此,這個數字仍不足深圳的一半。

df['面積分段'] = pd.cut(df['面積'],[0,10,20,30,40,1000000],labels=['10㎡如下','10-20㎡','20-30㎡','30-40㎡','40㎡以上'],right=False)
df2 = df["面積分段"].astype("str").value_counts()
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.DARK))
        .add("", list(zip(regions,values)))
        .set_global_opts(legend_opts = opts.LegendOpts(is_show = False),title_opts=opts.TitleOpts(title="蛋殼公寓面積分布",subtitle="數據來源:蛋殼公寓\n製圖:菜J學Python",pos_top="0.5%",pos_left = 'left'))
        .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}:{d}%",font_size=14))
        
    )
c.render_notebook()

蛋殼公寓商圈分佈

經過對北京幾個主要行政區商圈進行詞雲統計(字體越大表示蛋殼公寓數量最多),朝陽區的管莊、望京,通州區的北關,豐臺區的樊羊路、方莊和角門,昌平區的天通苑,海淀區的永豐和西二旗,大興區的黃村和亦莊,是蛋殼公寓主要選擇的商圈。

# 繪製詞雲圖
text1 = get_cut_words(content_series=df1['位置2'])
stylecloud.gen_stylecloud(text=' '.join(text1), max_words=100,
                          collocations=False,
                          font_path=r'C:\WINDOWS\FONTS\MSYH.TTC',
                          icon_name='fas fa-home',
                          size=653,
                          palette='cartocolors.diverging.ArmyRose_2',
                          output_name='./1.png')
Image(filename='./1.png')

相關性分析

從相關係數表能夠看出,北京蛋殼公寓的面積、周邊地鐵數對公寓的價格有較大的的影響,相關係數分別爲0.81和0.36。蛋殼公寓在進行房屋訂價時,對公寓的面積以及公寓的地鐵配套有較大權重的考慮。因爲北京蛋殼公寓距離地鐵都很近,所以,距離的遠近對公寓的價格影響有限。另外,所在樓層也不是北京蛋殼公寓租金高低的重要影響因素。

color_map = sns.light_palette('orange', as_cmap=True)  #light_palette調色板
df.corr().style.background_gradient(color_map)


最後,願全部受蛋殼公寓「暴雷」事件影響的年輕人都能熬過這個寒冬。

想要獲取更多Python學習資料能夠加QQ:2955637827私聊或加Q羣630390733你們一塊兒來學習討論吧!

相關文章
相關標籤/搜索