美文网首页
某公司手机点餐门店分布可视化

某公司手机点餐门店分布可视化

作者: zcdm | 来源:发表于2019-10-14 01:01 被阅读0次

    背景:该公司是全球大型连锁快餐企业,为了解其手机点餐门店分布情况,爬取门店详细地址,实现数据分析及可视化。可视化需要解决的思路:

    • 1.需要把门店地址转换成经纬度;
    • 2.需要根据得到的经纬度提取门店详细的省份、城市等信息;
    • 3.构造Geopandas所需数据格式;
    • 4.合并各省市2018年GDP(亿元)和常住人口(万人)数据。

    导入相关包

    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.pylab as plb
    from  matplotlib import cm
    import seaborn as sns
    plt.rc('font', family='SimHei', size=18)# 显示中文标签
    plt.rcParams['axes.unicode_minus'] = False
    sns.set()
    %matplotlib inline
    import geopandas 
    from shapely.geometry import LineString,Point
    import re
    import requests
    import json
    import hashlib
    from wordcloud import WordCloud
    from matplotlib.patches import Polygon
    from mpl_toolkits.basemap import Basemap
    from matplotlib.collections import PatchCollection
    import warnings
    warnings.filterwarnings('ignore')
    

    数据处理

    导入数据

    data=pd.read_excel(r"D:\PycharmProjects\BK_store.xls")
    data.head()
    
    storename address
    0 北京星泰中心 北京市朝阳区酒仙桥路甲16号星泰中心A1-02
    1 后街商业广场 昆山市虹祺路243号后街商业广场C5幢楼一楼部分商铺。
    2 哈尔滨国际餐厅 哈尔滨西大直街4号567漫天地二层
    3 海那城百联奥特莱斯 济南市槐荫区美里路555号10号楼一层商铺
    4 扬州三盛店 扬州市邗江中路358号三盛国际广场5号楼1 - 4号商铺。

    数据查看

    data.info()
    
    <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 1150 entries, 0 to 1149
    Data columns (total 2 columns):
    storename    1150 non-null object
    address      1150 non-null object
    dtypes: object(2)
    memory usage: 18.0+ KB
    
    data.dtypes
    
    storename    object
    address      object
    dtype: object
    
    data.isnull().sum()#查看缺失值
    
    storename    0
    address      0
    dtype: int64
    
    data.duplicated().sum()#查看重复值
    
    0
    

    自定义函数,根据地址查询经纬度

    data.storename=data.storename.astype(str)
    data.address=data.address.astype(str)
    
    def get_locationdata(address):
        requests.adapters.DEFAULT_RETRIES =5
        requests.session().keep_alive = False
        url='http://restapi.amap.com/v3/geocode/geo?key=1fbbc548b828f33ccc64f4613ae52497&s=rsv3&city=35&address={}'.format(address)
        headers = {'User-Agent': 'Mozilla/5.0'}
        response = requests.get(url, headers=headers)
        if 'location' in response.text:
            for i in json.loads(response.text)['geocodes']:
                return i.get('location')
        else:
            pass
    
    get_locationdata('昆山市虹祺路243号后街商业广场C5幢楼一楼部分商铺')
    
    '120.920690,31.411805'
    
    data['loncationdetail']=data.address.apply(get_locationdata)
    
    data[data.loncationdetail.isnull()]#查看缺失值
    
    storename address loncationdetail city province district township
    data.drop([1018],inplace=True)#索引1018为测试门店数据,删除该行数据
    data.loc[95].address='徐州市'+data.loc[95].address
    data.loc[332].address='昆明市'+data.loc[332].address
    data.loc[648].address='常州市'+data.loc[648].address
    data.loc[740].address='昆明市'+data.loc[740].address
    data.loc[1033].address='镇江市'+data.loc[1033].address
    data.loc[1095].address='嘉兴市'+data.loc[1095].address
    
    data['loncationdetail']=data.address.apply(get_locationdata)#之前缺失的行再执行一次,获取经纬度信息
    
    data[data.loncationdetail.isnull()]#查看缺失值
    
    storename address loncationdetail city province district township
    data['lon']=data.loncationdetail.str.split(',').apply(lambda x:x[0]).astype(float)##经度
    data['lat']=data.loncationdetail.str.split(',').apply(lambda x:x[1]).astype(float)#纬度
    
    data.head()
    
    storename address loncationdetail city province district township lon lat
    0 北京星泰中心 北京市朝阳区酒仙桥路甲16号星泰中心A1-02 116.490200,39.971870 北京市 北京市 朝阳区 将台镇 116.490200 39.971870
    1 后街商业广场 昆山市虹祺路243号后街商业广场C5幢楼一楼部分商铺。 120.920690,31.411805 苏州市 江苏省 昆山市 玉山镇 120.920690 31.411805
    2 哈尔滨国际餐厅 哈尔滨西大直街4号567漫天地二层 126.643240,45.756718 哈尔滨市 黑龙江省 南岗区 花园街道 126.643240 45.756718
    3 海那城百联奥特莱斯 济南市槐荫区美里路555号10号楼一层商铺 116.913773,36.716513 济南市 山东省 槐荫区 美里湖街道 116.913773 36.716513
    4 扬州三盛店 扬州市邗江中路358号三盛国际广场5号楼1 - 4号商铺。 119.397392,32.380924 扬州市 江苏省 邗江区 邗上街道 119.397392 32.380924
    data.isnull().sum()#再次查看缺失值
    
    storename          0
    address            0
    loncationdetail    0
    city               0
    province           0
    district           0
    township           0
    lon                0
    lat                0
    dtype: int64
    

    自定义函数,根据经纬度查询详细地址

    def get_data(location):
        url='https://restapi.amap.com/v3/geocode/regeo?key=1fbbc548b828f33ccc64f4613ae52497&s=rsv3&city=35&location={}'.format(location)
        requests.adapters.DEFAULT_RETRIES =5
        requests.session().keep_alive = False
        headers = {'User-Agent': 'Mozilla/5.0'}
        response = requests.get(url, headers=headers)
        address_dict={}
        if 'regeocode' in response.text:
            address_detail=re.search('"addressComponent":(.*),(.*),(.*),(.*)',response.text).group(1)
            address_dict['city']=json.loads(address_detail)['city']
            address_dict["province"]=json.loads(address_detail)["province"]
            address_dict["district"]=json.loads(address_detail)["district"]
            address_dict["township"]=json.loads(address_detail)["township"]
        else:
            pass
        return address_dict 
    
    get_data('119.397392,32.380924')
    
    {'city': '扬州市', 'province': '江苏省', 'district': '邗江区', 'township': '邗上街道'}
    
    data['city']=data.loncationdetail.apply(get_data).apply(lambda x:x['city'])#提取城市
    
    data['province']=data.loncationdetail.apply(get_data).apply(lambda x:x['province'])#提取省份
    
    data['district']=data.loncationdetail.apply(get_data).apply(lambda x:x['district'])#提取辖区
    
    data['township']=data.loncationdetail.apply(get_data).apply(lambda x:x['township'])#提取街道
    
    data.head()
    
    storename address loncationdetail city province district township lon lat
    0 北京星泰中心 北京市朝阳区酒仙桥路甲16号星泰中心A1-02 116.490200,39.971870 北京市 北京市 朝阳区 将台镇 116.490200 39.971870
    1 后街商业广场 昆山市虹祺路243号后街商业广场C5幢楼一楼部分商铺。 120.920690,31.411805 苏州市 江苏省 昆山市 玉山镇 120.920690 31.411805
    2 哈尔滨国际餐厅 哈尔滨西大直街4号567漫天地二层 126.643240,45.756718 哈尔滨市 黑龙江省 南岗区 花园街道 126.643240 45.756718
    3 海那城百联奥特莱斯 济南市槐荫区美里路555号10号楼一层商铺 116.913773,36.716513 济南市 山东省 槐荫区 美里湖街道 116.913773 36.716513
    4 扬州三盛店 扬州市邗江中路358号三盛国际广场5号楼1 - 4号商铺。 119.397392,32.380924 扬州市 江苏省 邗江区 邗上街道 119.397392 32.380924
    for i in ['city','province','district','township']:#查看含有空列表的列
            print(str(i),':',(data[i].apply(len)==0).sum())
    
    city : 294
    province : 0
    district : 10
    township : 7
    
    data[data.province.str.contains('市')].index#查看含有city列为空列表的行索引
    
    Int64Index([   0,    5,    7,    9,   11,   14,   20,   21,   28,   29,
                ...
                1123, 1130, 1131, 1134, 1135, 1136, 1137, 1138, 1146, 1147],
               dtype='int64', length=294)
    
    for i in data[data.province.str.contains('市')].index:
        data.loc[i,'city']=data.loc[i,'province']
    
    data.head()
    
    storename address loncationdetail city province district township
    0 北京星泰中心 北京市朝阳区酒仙桥路甲16号星泰中心A1-02 116.490200,39.971870 北京市 北京市 朝阳区 将台镇
    1 后街商业广场 昆山市虹祺路243号后街商业广场C5幢楼一楼部分商铺。 120.920690,31.411805 苏州市 江苏省 昆山市 玉山镇
    2 哈尔滨国际餐厅 哈尔滨西大直街4号567漫天地二层 126.643240,45.756718 哈尔滨市 黑龙江省 南岗区 花园街道
    3 海那城百联奥特莱斯 济南市槐荫区美里路555号10号楼一层商铺 116.913773,36.716513 济南市 山东省 槐荫区 美里湖街道
    4 扬州三盛店 扬州市邗江中路358号三盛国际广场5号楼1 - 4号商铺。 119.397392,32.380924 扬州市 江苏省 邗江区 邗上街道

    可视化分析

    转换点数据

    xy = [Point(xy) for xy in zip(data.lon,data.lat)]
    geo_data=geopandas.GeoDataFrame(data,geometry=xy)
    geo_data.head()
    
    storename address loncationdetail city province district township lon lat geometry
    0 北京星泰中心 北京市朝阳区酒仙桥路甲16号星泰中心A1-02 116.490200,39.971870 北京市 北京市 朝阳区 将台镇 116.490200 39.971870 POINT (116.4902 39.97187)
    1 后街商业广场 昆山市虹祺路243号后街商业广场C5幢楼一楼部分商铺。 120.920690,31.411805 苏州市 江苏省 昆山市 玉山镇 120.920690 31.411805 POINT (120.92069 31.411805)
    2 哈尔滨国际餐厅 哈尔滨西大直街4号567漫天地二层 126.643240,45.756718 哈尔滨市 黑龙江省 南岗区 花园街道 126.643240 45.756718 POINT (126.64324 45.756718)
    3 海那城百联奥特莱斯 济南市槐荫区美里路555号10号楼一层商铺 116.913773,36.716513 济南市 山东省 槐荫区 美里湖街道 116.913773 36.716513 POINT (116.913773 36.716513)
    4 扬州三盛店 扬州市邗江中路358号三盛国际广场5号楼1 - 4号商铺。 119.397392,32.380924 扬州市 江苏省 邗江区 邗上街道 119.397392 32.380924 POINT (119.397392 32.380924)

    导入中国地图shp

    gdf = geopandas.read_file(r"D:\PycharmProjects\中国地图shp格式\china_basic_map\bou2_4p.shp",encoding='gbk')
    gdf.head()
    
    AREA PERIMETER BOU2_4M_ BOU2_4M_ID ADCODE93 ADCODE99 NAME geometry
    0 54.447 68.489 2 23 230000 230000 黑龙江省 POLYGON ((121.4884414672852 53.33264923095703,...
    1 129.113 129.933 3 15 150000 150000 内蒙古自治区 POLYGON ((121.4884414672852 53.33264923095703,...
    2 175.591 84.905 4 65 650000 650000 新疆维吾尔自治区 POLYGON ((96.38328552246094 42.72695541381836,...
    3 21.315 41.186 5 22 220000 220000 吉林省 POLYGON ((123.1710433959961 46.24668121337891,...
    4 15.603 38.379 6 21 210000 210000 辽宁省 POLYGON ((123.6901931762695 43.37676620483398,...

    各省市门店分布空间分析

    gdf.plot(figsize=(15,15), alpha=0.5, edgecolor='white',color='gray')
    plt.gca().xaxis.set_major_locator(plt.NullLocator()) #去掉x轴刻度
    plt.gca().yaxis.set_major_locator(plt.NullLocator()) #去掉y轴刻度
    
    output_41_0.png
    geo_data.plot(ax=gdf.plot(figsize=(15,15),legend=True,edgecolor='white',color='gray'),color='yellow',markersize=8)
    plt.rc('font', family='SimHei', size=20)# 显示中文标签
    plt.rcParams['axes.unicode_minus'] = False
    plt.title('B快餐公司微信手机点餐门店城市分布图',size=20)
    plt.gca().xaxis.set_major_locator(plt.NullLocator()) #去掉x轴刻度
    plt.gca().yaxis.set_major_locator(plt.NullLocator()) #去掉y轴刻度
    
    output_42_0.png
    geo_data['shop_counts']=geo_data.groupby('province')['geometry'].transform(lambda x: x.count())
    
    geo_data.head()
    
    storename address loncationdetail city province district township lon lat geometry shop_counts
    0 北京星泰中心 北京市朝阳区酒仙桥路甲16号星泰中心A1-02 116.490200,39.971870 北京市 北京市 朝阳区 将台镇 116.490200 39.971870 POINT (116.4902 39.97187) 102
    1 后街商业广场 昆山市虹祺路243号后街商业广场C5幢楼一楼部分商铺。 120.920690,31.411805 苏州市 江苏省 昆山市 玉山镇 120.920690 31.411805 POINT (120.92069 31.411805) 156
    2 哈尔滨国际餐厅 哈尔滨西大直街4号567漫天地二层 126.643240,45.756718 哈尔滨市 黑龙江省 南岗区 花园街道 126.643240 45.756718 POINT (126.64324 45.756718) 15
    3 海那城百联奥特莱斯 济南市槐荫区美里路555号10号楼一层商铺 116.913773,36.716513 济南市 山东省 槐荫区 美里湖街道 116.913773 36.716513 POINT (116.913773 36.716513) 68
    4 扬州三盛店 扬州市邗江中路358号三盛国际广场5号楼1 - 4号商铺。 119.397392,32.380924 扬州市 江苏省 邗江区 邗上街道 119.397392 32.380924 POINT (119.397392 32.380924) 156
    geo_data.plot(ax=gdf.plot(figsize=(15,15),legend=True,edgecolor='white',color='gray'),column='shop_counts', cmap='rainbow',scheme='quantiles',legend=True,figsize=(8,10)
                 ,marker='o', markersize=100) #按个数多少叠加底色
    plt.gca().xaxis.set_major_locator(plt.NullLocator()) #去掉x轴刻度
    plt.gca().yaxis.set_major_locator(plt.NullLocator()) #去年y轴刻度
    
    output_45_0.png

    各省市门店数统计

    #各省市门店数
    province_pc=geo_data.groupby('province',as_index=False)['shop_counts'].count().sort_values(by='shop_counts',ascending=False)
    province_pc.head(10)
    
    province shop_counts
    14 江苏省 156
    11 广东省 132
    0 上海市 113
    3 北京市 102
    18 浙江省 73
    9 山东省 68
    25 辽宁省 60
    5 四川省 49
    23 福建省 44
    6 天津市 42
    #对含有自治区的字符串换行处理
    import textwrap
    for i in province_pc[province_pc.province.str.contains('区')].index.to_list():
         province_pc.loc[i,'province']=textwrap.fill( province_pc.loc[i,'province'],province_pc.loc[i,'province'].find('自'))
    
    province_pc[province_pc.province.str.contains('区')]
    
    province shop_counts
    13 新疆维吾尔\n自治区 7
    2 内蒙古\n自治区 7
    12 广西壮族\n自治区 5
    7 宁夏回族\n自治区 4
    import squarify
    labels = province_pc.apply(lambda x: str(x[0]) + "\n (" + str(x[1]) + ")", axis=1)
    sizes = province_pc['shop_counts'].values.tolist()
    colors = [plt.cm.Set1(i/float(len(labels))) for i in range(len(labels))]
    plt.figure(figsize=(10,12),dpi= 80)
    squarify.plot(sizes=sizes, label=labels, color=colors, alpha=.8)
    plt.rc('font',size=10)
    plt.title('各省市门店数树形图')
    plt.axis('off')#去除上边框和右边框刻度
    plt.tick_params(top='off',right='off')##去除上边框和右边框刻度
    
    output_50_0.png
    • 结论1:门店主要集中以下区域:江苏省、上海市、浙江省、广东省、北京市及山东省

    各省市门店数标准化分析:Z-Score

    x=province_pc.shop_counts
    province_pc['province_z']= (x - x.mean())/x.std()#各省市门店数量的z分位数
    province_pc['colors'] = ['red' if x < 0 else 'green' for x in province_pc['province_z']]
    province_pc.sort_values('province_z', inplace=True)
    province_pc.reset_index(inplace=True)
    province_pc.head(10)
    
    index province shop_counts province_z colors
    0 28 青海省 3 -0.870936 red
    1 24 贵州省 4 -0.846264 red
    2 7 宁夏回族自治区 4 -0.846264 red
    3 12 广西壮族自治区 5 -0.821592 red
    4 22 甘肃省 5 -0.821592 red
    5 19 海南省 6 -0.796919 red
    6 2 内蒙古自治区 7 -0.772247 red
    7 13 新疆维吾尔自治区 7 -0.772247 red
    8 15 江西省 9 -0.722902 red
    9 10 山西省 12 -0.648885 red
    plt.figure(figsize=(16,20), dpi= 80)
    
    plt.hlines(y=province_pc.index, xmin=0, xmax=province_pc.province_z, color=province_pc.colors, alpha=0.6, linewidth=15)
    
    for x, y, tex in zip(province_pc.province_z, province_pc.index, province_pc.province_z):
    
        t = plt.text(x, y, round(tex,2), horizontalalignment='right' if x < 0 else 'left',
    
                     verticalalignment='center', fontdict={'color':'red' if x < 0 else 'green', 'size':15})
    
    plt.gca().set(ylabel='省市', xlabel='门店数量')
    
    plt.yticks(province_pc.index, province_pc.province, fontsize=15)
    
    plt.title('各省市门店数量Z-Score', fontdict={'size':20})
    
    plt.grid(linestyle='--', alpha=0.1)
    
    output_54_0.png
    #门店数Top10省市
    province_pc.sort_values(by='shop_counts',ascending=False).head(10).province.to_list()
    
    ['江苏省', '广东省', '上海市', '北京市', '浙江省', '山东省', '辽宁省', '四川省', '福建省', '天津市']
    
    • 结论2:Z-Score衡量各省市门店数相比于整体均值的偏差水平。其中门店数Top10的省市Z-Score>0,其他省市Z-Score<0。

    各省市门店数与GDP、常住人口数相关性分析

    #导入各省市2018年GDP(亿元)和常住人口(万人)数据
    gp=pd.read_csv(r"D:\PycharmProjects\分省年度GDP及人口数据.csv",encoding="gbk")
    gp.head()
    
    province GDP (亿元) Popluation (万人)
    0 北京市 30319.98 2154
    1 天津市 18809.64 1560
    2 河北省 36010.27 7556
    3 山西省 16818.11 3718
    4 内蒙古自治区 17289.22 2534
    #将各省份门店数、2018年GDP、常住人口数合并
    result=pd.merge(province_pc.loc[:,['province','shop_counts']],gp,how='left',on='province')
    corr = result.corr()#相关系数
    corr
    
    shop_counts GDP (亿元) Popluation (万人)
    shop_counts 1.000000 0.797473 0.431992
    GDP\n(亿元) 0.797473 1.000000 0.841422
    Popluation\n(万人) 0.431992 0.841422 1.000000
    cmap = sns.diverging_palette(220,10, as_cmap=True) 
    sns.heatmap(corr, cmap=cmap,center=0.5, annot=True)
    plt.xticks(fontsize=10)
    plt.yticks(fontsize=10)
    plt.title('各省市2018年GDP、常住人口数与门店数热度图', fontsize=15)
    
    output_60_1.png
    • 结论3:各市门店数与2018年GDP、常住人口数均正相关,其中与GDP相关性较高。

    门店数Top14城市

    #各城市门店数
    city_pc=geo_data.groupby('city',as_index=False)['shop_counts'].count().sort_values(by='shop_counts',ascending=False)
    city_pc
    
    city shop_counts
    3 上海市 113
    21 北京市 102
    109 苏州市 46
    90 深圳市 44
    41 天津市 42
    22 南京市 39
    59 成都市 39
    127 重庆市 37
    69 杭州市 35
    52 广州市 32
    118 西安市 28
    40 大连市 25
    77 沈阳市 24
    73 武汉市 24
    63 无锡市 23
    134 青岛市 20
    84 济南市 20
    105 福州市 19
    65 昆明市 16
    131 长春市 15
    101 珠海市 14
    28 厦门市 14
    45 宁波市 14
    30 合肥市 13
    50 常州市 12
    26 南通市 12
    104 石家庄市 12
    34 哈尔滨市 11
    125 郑州市 11
    132 长沙市 10
    ... ... ...
    5 东营市 1
    7 临汾市 1
    9 丹东市 1
    10 丽江市 1
    12 亳州市 1
    13 伊犁哈萨克自治州 1
    15 佳木斯市 1
    17 信阳市 1
    27 南阳市 1
    32 周口市 1
    37 嘉峪关市 1
    38 四平市 1
    39 大庆市 1
    48 宝鸡市 1
    100 牡丹江市 1
    49 宿迁市 1
    54 延边朝鲜族自治州 1
    55 张家口市 1
    62 揭阳市 1
    64 日照市 1
    66 晋中市 1
    67 普洱市 1
    68 曲靖市 1
    1 三明市 1
    72 梅州市 1
    75 汕尾市 1
    82 泸州市 1
    88 淮北市 1
    98 潮州市 1
    139 齐齐哈尔市 1

    140 rows × 2 columns

    y=city_pc.shop_counts
    city_pc['city_z']= (y - y.mean())/y.std()#各省市门店数量的z分位数
    city_pc.sort_values('city_z', inplace=True,ascending=False)
    city_pc.reset_index(inplace=True)
    del city_pc["index"]
    
    #门店数Top14城市
    city_pc[city_pc.city_z>=1]
    
    city shop_counts city_z
    0 上海市 113 6.735240
    1 北京市 102 6.028248
    2 苏州市 46 2.429020
    3 深圳市 44 2.300476
    4 天津市 42 2.171932
    5 南京市 39 1.979116
    6 成都市 39 1.979116
    7 重庆市 37 1.850573
    8 杭州市 35 1.722029
    9 广州市 32 1.529213
    10 西安市 28 1.272125
    11 大连市 25 1.079309
    12 沈阳市 24 1.015037
    13 武汉市 24 1.015037
    input_colors =cm.rainbow(np.arange(len(city_pc.values))-2/len(city_pc.values)-2) 
    plt.rc('font', family='SimHei', size=18)# 显示中文标签
    plt.rcParams['axes.unicode_minus'] = False
    plt.figure(figsize=(10,10))
    plt.pie(city_pc.shop_counts.head(14),  startangle=70, labels=city_pc.city.head(14),  
        autopct='%1.2f%%', pctdistance=0.8,  
        labeldistance=1.1, textprops={'fontsize':15,'color':'black'},colors=input_colors)  
    plt.legend(bbox_to_anchor=(1.05, 0), loc=3, borderaxespad=0)
    plt.title('门店数Top14城市',fontsize=20)
    
    output_66_1.png

    相关文章

      网友评论

          本文标题:某公司手机点餐门店分布可视化

          本文链接:https://www.haomeiwen.com/subject/yzklmctx.html