全国地铁城市数据分析(python实现) |
您所在的位置:网站首页 › 各个城市的地铁 › 全国地铁城市数据分析(python实现) |
全国地铁城市数据分析(数据清洗+可视化分析) 一确定问题: 由题看出其属于开放问题,没有明确的目的(即可认为无题),其重点是让人发现问题(比如过程中分析时发现数据有哪些实在的问题就可以拿出来单独分析),了解数据处理,数据可视化 但是可以通过该问题比较系统的了解数据分析的过程(实际上这里重点是数据分析中的评估部分) 1.获取数据-采用爬虫访问百度地铁地图获取数据的方法 request+xpath爬虫: 得到url-http://map.amap.com/subway/index.html?&1100发出请求得到响应对象-request模块获取响应对象数据-使用text函数直接获取网页文本。有些数据为json字符串的形式,需要用到json转化解析数据-使用xpath持久化存储-在数据分析中一般将数据保存为csv格式,跟利于处理在过程中使用了time模块-sleep函数防止网站宕机 主要的3个函数 #3个函数 headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3947.100 Safari/537.36 2345Explorer/10.11.0.20694'} def get_city():#用于得到城市ID和城市名称 url = 'http://map.amap.com/subway/index.html?&1100' time.sleep(2) res = requests.get(url=url, headers=headers) res.raise_for_status() res.encoding = res.apparent_encoding html = res.text Html = etree.HTML(html) # 城市列表 res1 = Html.xpath('/html/body/div[1]/div[1]/div[1]/div[2]/div[1]/a') res2 = Html.xpath('/html/body/div[1]/div[1]/div[1]/div[2]/div[2]/div[2]/a') for i in res1: # 城市ID值 ID = ''.join(i.xpath('.//@id')) # 属性需要加上双斜杠 # 城市拼音名 cityname = ''.join(i.xpath('.//@cityname')) # ./表示在当层目录下使用 # 城市名 name = ''.join(i.xpath('./text()')) get_message(ID, cityname, name) city_ID.update({name: ID}) for i in res2: # 城市ID值 ID = ''.join(i.xpath('.//@id')) # 城市拼音名 cityname = ''.join(i.xpath('.//@cityname')) # 城市名 name = ''.join(i.xpath('./text()')) # print(cityname) get_message(ID, cityname, name) city_ID = {} def get_message(ID, cityname, name):#用于得到城市的具体线路信息 """ 地铁线路信息获取 """ url = 'http://map.amap.com/service/subway?_1555502190153&srhdata=' + ID + '_drw_' + cityname + '.json' # global end_list global stations # if end_list.get(cityname) == None: # end_list[cityname] = [] # end_list[cityname].setdefault([]) response = requests.get(url=url, headers=headers) time.sleep(2) html = response.text # print(html) result = json.loads(html) for i in result['l']: for j in i['st']: # 判断是否含有地铁分线 if len(i['la']) > 0: # print(name,cityname,j['sl'],j['poiid'], i['ln'] + '(' + i['la'] + ')', j['n']) with open('subway.csv', 'a+', encoding='utf-8') as f: f.write(name + ',' + cityname + ',' + j['poiid'] + ',' + j['sl'] + ',' + i['ln'] + '(' + i[ 'la'] + ')' + ',' + j['n'] + '\n') f.close() else: # print(name,cityname,j['sl'],j['poiid'], i['ln'], j['n']) with open('subway.csv', 'a+', encoding='utf-8')as f: f.write( name + ',' + cityname + ',' + j['poiid'] + ',' + j['sl'] + ',' + i['ln'] + ',' + j['n'] + '\n') f.close() # end_list[cityname].append(j['n']) print(name + '地铁站点爬取结束') f.close() def get_district(df_data):#用于得到每个地铁站点的行政区 url1 = 'https://www.youbianku.com/SearchResults?address=' # response=requests.get(url=url1,headers=headers) # response.enconding='utf-8' # print(response.text) from selenium.webdriver.common.desired_capabilities import DesiredCapabilities chrome_options = webdriver.ChromeOptions() desired_capabilities = DesiredCapabilities.CHROME desired_capabilities["pageLoadStrategy"] = "none" chrome_options.add_argument('--headless') chrome_options.add_argument('--disable-gpu') driver = webdriver.Chrome(options=chrome_options, executable_path=r'C:\Users\Dcnightmare\Desktop\chromedriver') list_city=[] last_text='' # driver.get(url='https://www.youbianku.com') for i in list(zip(df_data['站点城市'].values, df_data['地铁站点名称'])): driver.get(url=url1 + ''.join(list(i))) # driver.find_element_by_id('mySearchInput').send_keys(''.join(list(i))) # driver.find_element_by_id('mySearchButton').click() html_from_page = driver.page_source html = etree.HTML(html_from_page) try: text = html.xpath('//div[@class="mw-parser-output"]/div[1]//table//tr[2]/td/text()')[0] text = text.split('市')[1].split('区')[0] + '区' except Exception: driver.execute_script("window.stop()") list_city.append(last_text) continue if text=='区': list_city.append(last_text) continue last_text=text list_city.append(last_text) df_data['行政区']=list_city2.有了初步数据之后,需要进一步将数据变为我们可以使用的数据 缺失值处理(标准化,归一化,离散化…)这里没有使用因为这些数据处理都是用于分类,回归等任务中,而本文主要是对地铁站数据的简单分析重复项处理 import pandas as pd df_data = pd.read_csv('subway.csv', sep=',') # 使用pd的好处可以使用行和列名进行数据访问 print(df_data) # 缺失值处理: # 得到其读取到的行 print('删除之前的行:',df_data.shape) # 得到所有的属性非空项 print(df_data.info()) # 得出其中没有缺失值的行 # 重复数据处理 # """删除完全重复的站点""" df_data_1 = df_data.drop_duplicates() # 删除掉完全相同的行 # 得到删除之后的行 print('删除之后的行:',df_data_1.shape)这得到的数据真的就是最终数据集了吗? 其实不然,如果仔细观察可以发现其中有很多的站点存在重复(即一个站可能是多条地铁线路站点的情况),所以在考虑求一个城市总的站点数量时还需要去除其中的重复站点数量。 number_sum=0#统计总的站点数量 num_station_check = {} # 用于检查多余情况 num_station_old = {}#统计处理前的各城市站点数量 num_station_new = {} # 得到站点城市的地铁站点实际数量 for p in zip(df_data_3['站点城市'], df_data_3['地铁站点名称']): (i, j) = p # 原始数据 if num_station_old.get(i) == None: num_station_old[i] = 1 else: num_station_old[i] += 1 # 处理后的数据 if num_station_check.get(p) == None: number_sum+=1 if num_station_new.get(i) == None: num_station_new[i] = 1 else: num_station_new[i] += 1 num_station_check[p] = 1到此数据集的准备工作就差不多了. 让我们来试试做最有意思的部分吧! 3.数据分析+可视化 每个人开始分析的入手角度不同,所以看个人 分析各个城市的站点数量,因为他是最直观的数据分析城市的地铁站点在全国分布情况分析各城市地铁站点在全国站点中的比率分析各个城市的具体数据(内部行政区/市)出于比较所以我还找了2020年的地铁站点数据,如果有兴趣也可这样做,不过很可能有错误项,比如2020某城市地铁数据量反而比2021年的高,不过找到这种情况之后可以通过自己再查新闻是否如此(还是挺有趣的) 这里主要通过的是pyecharts来进行的图表绘制,因为其数据可视化效果比较好,maltplotlib我用着不好使 一.分析各个城市的站点数量 from pyecharts.charts import Bar from pyecharts import options as opts from pyecharts.charts import Line import pandas as pd attr = list(num_station_new.keys()) v1 = list(num_station_new.values())#新2021站点数据,主要体现数据处理 v2 = list(num_station_old.values())#旧2021站点数据 v1_v2 = [] # 用于得到换乘站点占比, 主要体现数据分析 # 解释:换乘占比越大其地铁线路越是密集,其地铁相对城市的规模也比较大,因为前期地铁是以向外拓宽为核心,一般都会尽量避免出现换乘站点,导致其资源浪费 # 当然也不是绝对的,可能有所偏差,但是大方向是对的 for i in range(0, len(v1)): v1_v2.append(round((v2[i] - v1[i]) / v1[i], 3)) # round用于保留数据的位数 # print(('%.2f' %12.234456))#使用两个%也可以达到格式化数据的目的 bar1 = ( Bar(init_opts=opts.InitOpts(width="1700px", height="800px")) # 注意添加默认参数时是在init_opts参数中设置 .add_xaxis(attr) .add_yaxis('station_number_2021_new', v1, itemstyle_opts=opts.ItemStyleOpts(color='blue'), label_opts=opts.LabelOpts(is_show=True, position='top', formatter="{c}", color='black')) # 显示数据标签 .add_yaxis('station_number_2021_old', v2, itemstyle_opts=opts.ItemStyleOpts(color='green'), label_opts=opts.LabelOpts(is_show=True, position='top', formatter="{c}", color='blue')) # 显示数据标签 .add_yaxis('换乘站点占比', v1_v2, itemstyle_opts=opts.ItemStyleOpts(color='orange'), label_opts=opts.LabelOpts(is_show=True, position='top', formatter="{c}", color='green')) # 显示数据标签 .extend_axis( # 设置次坐标轴 yaxis=opts.AxisOpts( name="换乘站点占比率", # 次坐标轴名称 type_="value", # 次坐标手类型 min_=0, # 最小值 max_=50, # 最大值 is_show=True, # 是否显示 axisline_opts=opts.AxisLineOpts(is_show=False, # y轴线不显示 linestyle_opts=opts.LineStyleOpts(color='#f6c065')), # 设置线颜色, 字体颜色也变 axistick_opts=opts.AxisTickOpts(is_show=False), # 刻度线不显示 axislabel_opts=opts.LabelOpts(formatter="{value}%"), # 次坐标轴数据显示格式 ) ) .set_global_opts( # 对x轴标签,y轴,标题,图例的格式和类型进行修改 # 图例默认放到 上中 位置 xaxis_opts=opts.AxisOpts( name='城市', name_location='middle', name_gap=30, # 与x轴线的距离 # name_Rorate设置旋转角度 # x轴名称的格式配置 name_textstyle_opts=opts.TextStyleOpts( font_family='Microsoft Yahei', font_size=20, ), # 坐标轴刻度配置项 axistick_opts=opts.AxisTickOpts( is_show=True, # is_show=False, # 是否显示 is_inside=True, # 刻度线是否在内侧 ), # 坐标轴线的配置 axisline_opts=opts.AxisLineOpts( linestyle_opts=opts.LineStyleOpts( width=1, color='black', ) ), axislabel_opts=opts.LabelOpts( rotate=40, font_size=12, font_family='Arial', font_weight='bold' ), ), yaxis_opts=opts.AxisOpts( name='station_number', name_location='middle', name_gap=30, name_textstyle_opts=opts.TextStyleOpts( font_family='Times New Roman', font_size=20, color='black', # font_weight='bolder', ), axistick_opts=opts.AxisTickOpts( is_show=False, # 是否显示 is_inside=True, # 刻度线是否在内侧 ), axislabel_opts=opts.LabelOpts( font_size=12, font_family='Times New Roman', formatter="{value}" # y轴显示方式以数据形式 ), splitline_opts=opts.SplitLineOpts(is_show=True), # y轴网格线 axisline_opts=opts.AxisLineOpts(is_show=False), # y轴线 ), title_opts=opts.TitleOpts( title="城市地铁站点数量", # 标题 title_textstyle_opts=opts.TextStyleOpts(font_size=20), # 主标题字体大小 subtitle="hello_data_analysis", # 副标题 pos_left='6%'), toolbox_opts=opts.ToolboxOpts(is_show=True), ) ) bar1.render('bar_2021_and_2020.html') # 将其输出为html文件 #使用webbrowser模块直接打开网页 import webbrowser webbrowser.open('bar_2021_and_2020.html') print("直方图分析结束!")解释这里的一个数据-换乘站点占比,由其地铁站点实际分布的地图,我初步认为,在城市建立地铁的初期都是在扩大其覆盖区域,把居民区(郊区)和商业区(市中心)以及火车站、机场尽可能与客流量挂钩的地方等连接起来,很少会出现站点重合的现象导致其换乘点占比就比较小,所以如果换乘站点占比大,可以粗略估计其地铁的发展比较好,规模相对该城市规模而言也比较大,侧面反映了当地的经济发展水平比较高.当然还存在一些其他情况比如说考虑到地质结构,太容易塌陷的地方或者地震断裂带也是不行的. 来看结果: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210617155151880.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2EyODQzNjU=,size_16,color_FFFFFF,t_70 换乘站点占比: 得到各城市的经纬度数据之后就可以绘制地图了 #全国地图 from pyecharts import options as opts from pyecharts.globals import ChartType data_yy=list(num_station_new.values()) data_xx=list(num_station_new.keys()) get_jinwei(data_xx) data=num_station_new provice={} for i in data_xx: provice.setdefault(city_provice[i],0) provice[city_provice[i]]+=data[i] from pyecharts import options as opts from pyecharts.charts import Map china_map = ( Map(init_opts=opts.InitOpts(width="1530px", height="684px",theme=ThemeType.CHALK)) .add("中国地铁", [list(z) for z in provice.items()], "china") .set_global_opts( title_opts=opts.TitleOpts(title="中国地铁数据"), visualmap_opts=opts.VisualMapOpts(max_=max(provice.values()), is_piecewise=True,textstyle_opts=opts.TextStyleOpts(color='write',font_size=20,font_family='Microsoft YaHei')), ) ) #地铁在各大城市的分布情况(从中国地图来看 3D) from pyecharts import options as opts from pyecharts.charts import Map3D from pyecharts.globals import ChartType from pyecharts.commons.utils import JsCode for i in num_station_new: jinwei[i].append(num_station_new[i])#添加城市的站点数量,也相当于加上高度 example_data = [ (p,jinwei[p]) for p in num_station_new.keys()] c = ( Map3D(init_opts=opts.InitOpts(width="1500px", height="700px")) .add_schema( itemstyle_opts=opts.ItemStyleOpts( color="rgb(5,101,123)", opacity=1, border_width=0.8, border_color="rgb(62,215,213)", ), map3d_label=opts.Map3DLabelOpts( is_show=False, formatter=JsCode("function(data){return data.name + " " + data.value[2];}"), ), emphasis_label_opts=opts.LabelOpts( is_show=False, color="#fff", font_size=10, background_color="rgba(0,23,11,0)", ), light_opts=opts.Map3DLightOpts( main_color="#fff", main_intensity=1.2, main_shadow_quality="high", is_main_shadow=False, main_beta=10, ambient_intensity=0.3, ), ) .add( series_name="数据", data_pair=example_data, type_=ChartType.BAR3D, bar_size=1, shading="lambert", label_opts=opts.LabelOpts( is_show=False, formatter=JsCode("function(data){return data.name + ' ' + data.value[2];}"), ), ) .set_global_opts(title_opts=opts.TitleOpts(title="城市数据")) .render("带有数据展示地图.html") ) import webbrowser webbrowser.open('带有数据展示地图.html') print("地铁城市在中国分布分析结束!")结果如下: 可以看出地铁城市的分布主要是一些沿海城市,而我们也知道沿海城市的经济发展相对其他城市要高出一截,也因为经济发展好,其流动人数也比较多. 查找原因后 发现实际上不是城市想修地铁就可以修的,需要有高经济支持(一般都是GDP达到…才行)和人口数量的要求. 三.分析各城市地铁站点在全国站点中的比率 如果数量不好直接比较的话,那么通过数据所占百分比就可以较好的实现比较各个城市地铁站点数量 station_proportion=[] for i in num_station_new.values(): station_proportion.append(("%.2f" %(i/number_sum*100))) from pyecharts.charts import Pie import pyecharts.options as opts data_pie=tuple(zip(num_station_new.keys(),station_proportion)) # print(data_pie) pie=( Pie(init_opts=opts.InitOpts(width="1600px", height="1000px")) .add(series_name='城市地铁站点占比',data_pair=data_pie,center=[600,600],label_opts=opts.LabelOpts(distance=30,is_show=True) ,tooltip_opts=opts.TooltipOpts(is_show=True),radius=None # ,rosetype='radius' # ,rosetype='area' ) ) pie.render('station_number_pie.html') import webbrowser webbrowser.open('station_number_pie.html') print('站点数据饼状图展示结束!')结果如下: |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |