Pythonは、新しい不動産の現在のステータスデータをクロールし、データを視覚的に分析します

序文

この記事のテキストと写真はインターネットからのものであり、学習とコミュニケーションのみを目的としており、商用目的ではありません。ご不明な点がございましたら、処理についてお問い合わせください。

次の記事は、データSTUDIO、著者YunDuojunからのものです

第13回全国人民代表大会の第4回会期は、5日午前9時に人民大会堂で開かれ、大都市の顕著な住宅問題を解決するための住宅政策「住宅は憶測ではない」。

この論文では、全国のさまざまな都市で販売されている新しい家をクロールすることによって視覚的な分析を行います。

データ収集

全国の都市で販売されている新しいプレセールディスクをクロールすることにより、以下では、クロールデータ部門のメインコードを紹介する例として単一の都市を取り上げます。

関数を定義する

各項目の情報を取得する関数を定義します。

def get_house_status(soup):
  """
  获取房屋状态信息
  """
    house_status = []
    status = soup.find_all(attrs={'class': 'fangyuan'})
    for state in status:
        _status = state.span.text
        house_status.append(_status)
    return house_status

def get_house_price(soup):
  """
  获取房屋价格信息
  """
    house_price = []
    regex = re.compile('\s(\S+)\s')
    prices = soup.find_all(attrs={'class': 'nhouse_price'})
    for price in prices:
        _prices = regex.findall(price.text)
        _price = ''
        if _prices[0] == '价格待定':
            pass
        else:
            p = _prices[0].split('元')[0]
            if '万' in p:
                _price = p + '元/套'
            else:
                _price = p + '元/m2'
        house_price.append(_price)
    return house_price

def get_house_address(soup, c_city):
  """
  获取房屋地址信息
  """
    house_address = []
    region = []
    regex = re.compile('\s(\S+)\s')
    addresses = soup.find_all(attrs={'class': 'address'})
    for address in addresses:
        _address = regex.findall(address.text)
        if len(_address) > 1:
            region.append(_address[0].split('[')[1].split(']')[0])
        else:
            region.append(c_city)
        house_address.append(address.a['title'])
    return region, house_address

def get_house_type(soup):
  """
  获取房屋类型信息
  """
    house_type = []
    regex = re.compile('\s(\S+)\s')
    house_types = soup.find_all(attrs={'class': 'house_type clearfix'})
    for _house_type in house_types:
        type_list = regex.findall(_house_type.text)
        type_str = ''
        for i in type_list:
            type_str += i
        house_type.append(type_str)
    return house_type

def get_house_name(soup):
  """
  获取项目名称信息
  """
    house_name = []
    regex = re.compile('\s(\S+)\s')
    nlcd_names = soup.find_all(attrs={'class': 'nlcd_name'})
    for nlcd_name in nlcd_names:
        name = ''
        names = regex.findall(nlcd_name.text)

        if len(names) > 1:
            for n in names:
                name += n
            house_name.append(name)
        else:
            house_name.extend(names)
    return house_name

データを取得する主な機能

def get_data(c_city, city, start_page, cache):
  """
  获取数据
  """
    requests_cache.install_cache()
    requests_cache.clear()
    session = requests_cache.CachedSession()  # 创建缓存会话
    session.hooks = {'response': make_throttle_hook(np.random.randint(8, 12))}  # 配置钩子函数
    print(f'现在爬取{c_city}'.center(50, '*'))
    last_page = get_last_page(city)
    print(f'{c_city}共有{last_page}页')
    time.sleep(np.random.randint(15, 20))
    df_city = pd.DataFrame()
    user_agent = UserAgent().random
    for page in range(start_page, last_page):
        try:
            cache['start_page'] = page
            print(cache)
            cache_json = json.dumps(cache, ensure_ascii=False)
            with open('cache.txt', 'w', encoding='utf-8') as fout:
                fout.write(cache_json)
            print(f'现在爬取{c_city}的第{page + 1}页.')
            if page == 0:
                df_city = pd.DataFrame()
            else:
                df_city = pd.read_csv(f'df_{c_city}.csv', encoding='utf-8')
            url = html_url(city, page + 1)
            if page % 2 == 0:
                user_agent = UserAgent().random  
                # 创建随机请求头
            header = {"User-Agent": user_agent}
            res = session.post(url, headers=header)
            if res.status_code == 200:
                res.encoding = 'gb18030'
                soup = BeautifulSoup(res.text, features='lxml')  
                # 对html进行解析,完成初始化
                region, house_address = get_house_address(soup, c_city)
                house_name = get_house_name(soup)
                house_type = get_house_type(soup)
                house_price = get_house_price(soup)
                house_status = get_house_status(soup)
                df_page = to_df(c_city, 
                                region, 
                                house_name, 
                                house_address, 
                                house_type, 
                                house_price, 
                                house_status)
                df_city = pd.concat([df_city, df_page])
                df_city.head(2)
                time.sleep(np.random.randint(5, 10))
                df_city.to_csv(f'df_{c_city}.csv', 
                               encoding='utf-8', 
                               index=False)
        except:
           # 若报错则保存数据、以便继续
            df_city.to_csv(f'df_{c_city}.csv', encoding='utf-8', index=False)
            cache_json = json.dumps(cache, ensure_ascii=False)
            with open('cache.txt', 'w', encoding='utf-8') as fout:
                fout.write(cache_json)
    return df_city

クロールプロセス中に、各都市を個別にcsvファイルとして保存します。

 

データを統合する

import os
import pandas as pd
df_total = pd.DataFrame()
for root, dirs, files in os.path.walk('./全国房价数据集'):
   for file in files:
       split_file = os.path.splitext(file)
        file_ext = split_file[1]
        if file_ext == '.csv':
           path = root + os.sep + file
           df_city = pd.read_csv(path, encoding='utf-8')
           df_total = pd.concat([df_total, df_city])
    df_total.to_csv(root+os.sep+'全国新房202102.csv', encoding='utf-8', index=False)

データクリーニング

必要なモジュールをインポートします

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import missingno as msno

データを読む

raw_data = pd.read_csv('全国新房202102.csv', encoding='utf-8')
raw_data.sample(5)

 

データの基本的な状況を確認する

>>> raw_data.shape
(54733, 7)

>>> len(raw_data.city.drop_duplicates())
581

全国の581の都市をクロールし、合計54733の不動産プロジェクトが販売および先行販売されています。

取得したデータには欠測値や外れ値、直接使用できないデータが含まれているため、欠測値や外れ値などを処理してから分析する必要があります。

欠測値分析

msno.matrix(raw_data)

 

全体として、house_priceの処理には欠測値があります。これは、不動産のこの部分が販売前の状態であり、価格がまだ発表されていないためです。

house_type

注意深く分析すると、house_priceには2つの形式があります

 

販売前の欠測値に加えて、単価と合計価格の2種類があります。統計を容易にするために、合計価格を面積で割って、平均単価として統一する必要があります。したがって、house_typeは次のように処理する必要があります。

def deal_house_type(data):
    res = []
    if data is np.nan:
        return [np.nan, np.nan, np.nan]
    else:
        if '-'in data:
            types = data.split('-')[0]
            areas = data.split('-')[1]
            area = areas.split('~')
            if len(area) == 1:        
                min_area = areas.split('~')[0][0:-2]
                max_area = areas.split('~')[0][0:-2]
            else:
                min_area = areas.split('~')[0]
                max_area = areas.split('~')[1][0:-2]

            res = [types, int(min_area), int(max_area)]
            return res
        else:
            return [np.nan, np.nan, np.nan]
series_type = raw_data.house_type.map(lambda x: deal_house_type(x))
df_type = pd.DataFrame(series_type.to_dict(), index=['house_type', 'min_area', 'max_area']).T
data_type = pd.concat([data_copy.drop(labels='house_type',axis=1), df_type], axis=1)
data_type.head()

次の表を入手してください

 

house_price

床面積を取得したら、次のステップは住宅価格を処理することです。

def deal_house_price(data):
    try:
        if data.house_price is np.nan:
            return np.nan
        else:
            if "价格待定" in data.house_price:
                return np.nan

            elif "万" not in data.house_price:
                price = int(data.house_price.split('元')[0])
            else:
                price_total = int(float(data.house_price.split('万')[0])* 10000)
                if data.min_area is np.nan and data.max_area is np.nan:
                    return np.nan
                elif data.min_area is np.nan:
                    price = price_total/ data.max_area
                elif data.max_area is np.nan:
                    price = price_total / data.min_area
                else:
                    price = price_total / (data.min_area + data.max_area)
        return int(price)
    except:
        return np.nan
 
series_price = data_type.apply(lambda x:deal_house_price(x), axis=1 )
data_type['house_price'] = series_price
data_type.head()

 

答えを得た

 

欠測値の処理

data = data_type.copy()
# 房价缺失值用0填充
data['house_price'] = data_type.house_price.fillna(0)
data['house_type'] = data_type.house_type.fillna('未知')

外れ値分析

data.describe([.1, .25, .5, .75, .99]).T

明らかに欠落している値があります。元のWebページを確認してください。この値は特殊であるため、クリーニングプロセス中に100000が乗算されるため、この値を直接変更できます。

 

視覚化(箱ひげ図)を通じて外れ値を表示することもできます。

from pyecharts import options as opts
from pyecharts.charts import Boxplot

v = [int(i) for i in data.house_price]
c = Boxplot()
c.add_xaxis(["house_price"])
c.add_yaxis("house_price", v)
c.set_global_opts(title_opts=opts.TitleOpts(title="house_price"))
c.render_notebook()

 

視覚分析

全国の都市で販売されている新築住宅の平均価格はTOP15です。

全国の都市の新築住宅の平均価格の分析によると、住宅価格は私たちが最も懸念している特性の1つです。そこで、どの都市が国内で最も高い平均価格を持っているかを見てみましょう。

# 将空值筛选掉
data1 =  data.query('house_price != 0')
data_pivot = data1.pivot_table(values='house_price',
                               index='city').sort_values(by='house_price', 
                                                         ascending=False)
data_pivot

 

 

全国の都市で販売されている新築住宅の平均価格の棒グラフ

from pyecharts.charts import Bar
from pyecharts.globals import ThemeType

x_axis = [i for i in data_pivot.index[0:15]]
y_axis = [round(float(i), 1) for i in data_pivot.house_price.values[0:15]]

c = (
    Bar({"theme": ThemeType.DARK})
    .add_xaxis(x_axis)
    .add_yaxis("house_price_avg", y_axis)
    .set_global_opts(
        title_opts=opts.TitleOpts(title="全国城市在售新房均价TOP15", subtitle="数据: STUDIO"),
        brush_opts=opts.BrushOpts(),
    )
)
c.render_notebook()

結果は以下のとおりです。トップランクの都市は、常に深セン、北京、上海などの一流都市でした。

 

全国住宅価格のロケーションマップ

import pandas as pd
from pyecharts.globals import ThemeType, CurrentConfig, GeoType
from pyecharts import options as opts
from pyecharts.charts import Geo

#自定义各城市的经纬度
# geo_cities_coords = {df.iloc[i]['城市']:[df.iloc[i]['经度'],df.iloc[i]['纬度']] for i in range(len(df))}

datas = [(i, int(j)) for i, j in zip(data_pivot.index, data_pivot.values)]
# print(datas)

geo = (Geo(init_opts=opts.InitOpts(width='1000px', 
                                   height='600px', 
                                   theme=ThemeType.PURPLE_PASSION),
           is_ignore_nonexistent_coord = True)
       .add_schema(maptype='china', 
                   label_opts=opts.LabelOpts(is_show=True))   # 显示label  省名
       .add('均价', 
            data_pair=datas, 
            type_=GeoType.EFFECT_SCATTER, 
            symbol_size=8,
            # geo_cities_coords=geo_cities_coords
           )
       .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
       .set_global_opts(
           title_opts=opts.TitleOpts(title='全国城市在售新房均价', subtitle="制图: 数据STUDIO"),
           visualmap_opts=opts.VisualMapOpts(max_=550,
                                             is_piecewise=True,
                                             pieces=[
                     {"max": 5000, "min": 1000, "label": "1000-5000", "color": "#708090"},
                     {"max": 10000, "min": 5001, "label": "5001-10000", "color": "#00FFFF"},
                     {"max": 20000, "min": 10001, "label": "10001-20000", "color": "#FF69B4"},
                     {"max": 30000, "min": 20001, "label": "20001-30000", "color": "#FFD700"},
                     {"max": 40000, "min": 30001, "label": "30001-40000", "color": "#FF0000"},
                     {"max": 100000, "min": 40001, "label": "40000-100000", "color": "#228B22"},])
       )
      )

geo.render('全国城市在售新房均价.html')

 

近年、注目の不動産市場の価格が高騰しており、住宅価格を安定させるために、地方自治体はさまざまな規制政策を次々と導入しています。統計によると、今年は全国で合計97回(100件近く)の不動産市場管理政策が発令されており、その中で1月の全国の不動産市場管理政策は42回にも上り、 2月は1月より​​3回多く、合計45回でした。

全国の新築住宅プロジェクト総数ランキング

次に、TOP20にランクされた国で販売/先行販売されている新しい住宅プロジェクトの総数を見てみましょう。上位5つは、成都、四川-1,000、重慶-938、武漢、フーベイ-859、西安です。 、Shaanxi-840。Zhengzhou、Henan-822、これらはすべて新しい一次都市です(Chengdu、Hangzhou、Chongqing、Wuhan、Suzhou、Xi'an、Tianjin、Nanjing、Zhengzhou、Changsha、Shenyang、Qingdao、Ningbo、DongguanおよびWuxi)。

現在の新しい一次都市は比較的急速な経済発展を遂げており、将来の発展見通しは広く、北京、上海、広州、深センに次ぐと言えます。人口は引き続き流入し、人口流入により不動産需要は増加し、不動産需要の増加により不動産価格は着実に上昇します。投資する価値もあります。

from pyecharts import options as opts
from pyecharts.charts import Bar

city_counts = data.city.value_counts()[0:20]
x_values = city_counts.index.to_list()
y_values = [int(i) for i in city_counts.values]

bar = (
    Bar()
    .add_xaxis(x_values)
    .add_yaxis("",y_values,itemstyle_opts=opts.ItemStyleOpts(color="#749f83"))
    .set_global_opts(title_opts=opts.TitleOpts(title="全国新房项目总数TOP20"),
                     toolbox_opts=opts.ToolboxOpts(),
                     legend_opts=opts.LegendOpts(is_show=False),
                    datazoom_opts=opts.DataZoomOpts(),)
)
bar.render_notebook()

結果

 

市内のすべての行政区域で販売されている新築住宅の平均価格

販売/先行販売の不動産プロジェクトが最も多い成都を例にとり、市内のさまざまな行政区域で販売されている新築住宅の平均価格を見てみましょう。

「住宅投機なし」という一般的な環境下で、主要都市の購入制限政策はますます厳しくなっています。最近、成都は住宅購入の事前資格審査を実施しました。住宅のない世帯への販売はホット不動産が優先されており、それが必要な私たちにとっては大きな恩恵です。次に見てみましょう。

成都の行政区域で販売されている新築住宅の平均価格

data2 = data.query('house_price != 0 and city=="成都"')
data_pivot_cd = data2.pivot_table(values='house_price',
                               index='region').sort_values(by='house_price')

x_axis2 = [i for i in data_pivot_cd.index[10:]]
y_axis2 = [round(float(i), 1) for i in data_pivot_cd.house_price.values[10:]]

c = (
    Bar({"theme": ThemeType.DARK})
    .add_xaxis(x_axis2)
    .add_yaxis("house_price_avg", y_axis2)
    .reversal_axis()
    .set_global_opts(
        title_opts=opts.TitleOpts(title="成都各行政区在售新房均价TOP10", subtitle="制图: 数据STUDIO"),
        brush_opts=opts.BrushOpts()
    )
    .set_series_opts(label_opts=opts.LabelOpts(position="right"))
)
c.render_notebook()

結果は次のとおりです。

 

成都の行政区域における新築住宅の分布

from pyecharts.charts import Pie

data_cq = data[data.city=='成都']
df_cq = data_cq.region.value_counts()[0:15]
regions = df_cq.index.to_list()
values = df_cq.to_list()
c = (
   Pie(init_opts=opts.InitOpts(theme=ThemeType.DARK))
  .add("", list(zip(regions,values)))
  .set_global_opts(
    legend_opts = opts.LegendOpts(type_="scroll",
    pos_right="90%",
    pos_top='20%',
    orient="vertical"),
    title_opts=opts.TitleOpts(title="区域新房源数分布",
    subtitle="制图: 数据STUDIO",
    pos_top="0.5%",pos_left = 'left'))
  .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}占比:{d}%",font_size=14))
)
c.render_notebook()

結果は次のとおりです。

 

円グラフによると、成都の周辺地域(包括的)に加えて、天府新区は総住宅リストの割合が最も高く、成都の直接管理地区にある天府新区は、成都で強力な開発の勢いがある行政区でもあります。近年では。

2014年、四川天府新区は中国で11番目の州レベルの新区として正式に承認されました。2020年、四川天府新区は86の主要産業プロジェクトを導入し、合意された総投資額は2,285億元で、地域GDPは6.7%増の3,561億元を達成し、全国新区で5位にランクされます。

from pyecharts.charts import Pie

data_cq_notna = data[data.city=='成都']
data_cq_notna.dropna(subset=['min_area', 'max_area'], inplace=True)
data_cq_notna['min_area'] = data_cq_notna['min_area'].astype('int') 
data_cq_notna['max_area'] = data_cq_notna['max_area'].astype('int') 
data_cq_notna_pivot = data_cq_notna.pivot_table(values=['min_area', 'max_area'], index='region')
data_cq_notna_pivot.sort_values(by='max_area', ascending=False,inplace=True)
regions = data_cq_notna_pivot.index.to_list()
avg_area1 = data_cq_notna_pivot.min_area.to_list()
avg_area2 = data_cq_notna_pivot.max_area.to_list()

c = (
     Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))
    .add_xaxis(regions)
    .add_yaxis("平均最大铭面积", avg_area2, stack="stack1")
    .add_yaxis("平均最小铭面积", avg_area1, stack="stack1")
    .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    .set_global_opts(xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=13)),
                     #更改横坐标字体大小
                     yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=13)), 
                     #更改纵坐标字体大小
                     title_opts=opts.TitleOpts(title="区域新房源户型面积",
                                               subtitle="制图: 数据STUDIO",
                                               pos_top="0.5%",pos_left = 'left'),
                     datazoom_opts=opts.DataZoomOpts())
    )
c.render_notebook()

出力結果

おすすめ

転載: blog.csdn.net/m0_48405781/article/details/115081837