183條地鐵線路,3034個地鐵站,發(fā)現(xiàn)中國地鐵名字的秘密
最近看了新周刊的一篇推送,有關(guān)地鐵名字的分析。于是乎也想著自己去獲取數(shù)據(jù),然后進行分析一番。
當然分析水平不可能和他們的相比,畢竟文筆擺在那里,也就那點水平。
大家看著樂呵就好,能提高的估摸著也就只有數(shù)據(jù)的準確性啦。
文中所用到的地鐵站數(shù)據(jù)并沒有去重,對于換乘站,含有大量重復。
即使作者一直在強調(diào)換乘站占比很小,影響不是很大。
但于我而言,去除重復數(shù)據(jù)還是比較簡單的。
然后照著人家的路子去分析,多學習一下。
一、獲取分析
地鐵信息獲取從高德地圖上獲取。
上面主要獲取城市的「id」,「cityname」及「名稱」。
用于拼接請求網(wǎng)址,進而獲取地鐵線路的具體信息。
找到請求信息,獲取各個城市的地鐵線路以及線路中站點詳情。
二、數(shù)據(jù)獲取
具體代碼如下。
- import json
- import requests
- from bs4 import BeautifulSoup
- headers = {'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}
- def get_message(ID, cityname, name):
- """
- 地鐵線路信息獲取
- """
- url = 'http://map.amap.com/service/subway?_1555502190153&srhdata=' + ID + '_drw_' + cityname + '.json'
- response = requests.get(url=url, headers=headers)
- html = response.text
- result = json.loads(html)
- for i in result['l']:
- for j in i['st']:
- # 判斷是否含有地鐵分線
- if len(i['la']) > 0:
- print(name, i['ln'] + '(' + i['la'] + ')', j['n'])
- with open('subway.csv', 'a+', encoding='gbk') as f:
- f.write(name + ',' + i['ln'] + '(' + i['la'] + ')' + ',' + j['n'] + '\n')
- else:
- print(name, i['ln'], j['n'])
- with open('subway.csv', 'a+', encoding='gbk') as f:
- f.write(name + ',' + i['ln'] + ',' + j['n'] + '\n')
- def get_city():
- """
- 城市信息獲取
- """
- url = 'http://map.amap.com/subway/index.html?&1100'
- response = requests.get(url=url, headers=headers)
- html = response.text
- # 編碼
- html = html.encode('ISO-8859-1')
- html = html.decode('utf-8')
- soup = BeautifulSoup(html, 'lxml')
- # 城市列表
- res1 = soup.find_all(class_="city-list fl")[0]
- res2 = soup.find_all(class_="more-city-list")[0]
- for i in res1.find_all('a'):
- # 城市ID值
- ID = i['id']
- # 城市拼音名
- cityname = i['cityname']
- # 城市名
- name = i.get_text()
- get_message(ID, cityname, name)
- for i in res2.find_all('a'):
- # 城市ID值
- ID = i['id']
- # 城市拼音名
- cityname = i['cityname']
- # 城市名
- name = i.get_text()
- get_message(ID, cityname, name)
- if __name__ == '__main__':
- get_city()
***成功獲取數(shù)據(jù)。
包含換乘站數(shù)據(jù),一共3541個地鐵站點。
二、數(shù)據(jù)可視化
先對數(shù)據(jù)進行清洗,去除重復的換乘站信息。
- from wordcloud import WordCloud, ImageColorGenerator
- from pyecharts import Line, Bar
- import matplotlib.pyplot as plt
- import pandas as pd
- import numpy as np
- import jieba
- # 設(shè)置列名與數(shù)據(jù)對齊
- pd.set_option('display.unicode.ambiguous_as_wide', True)
- pd.set_option('display.unicode.east_asian_width', True)
- # 顯示10行
- pd.set_option('display.max_rows', 10)
- # 讀取數(shù)據(jù)
- df = pd.read_csv('subway.csv', header=None, names=['city', 'line', 'station'], encoding='gbk')
- # 各個城市地鐵線路情況
- df_line = df.groupby(['city', 'line']).count().reset_index()
- print(df_line)
通過城市及地鐵線路進行分組,得到全國地鐵線路總數(shù)。
一共183條地鐵線路。
- def create_map(df):
- # 繪制地圖
- value = [i for i in df['line']]
- attr = [i for i in df['city']]
- geo = Geo("已開通地鐵城市分布情況", title_pos='center', title_top='0', width=800, height=400, title_color="#fff", background_color="#404a59", )
- geo.add("", attr, value, is_visualmap=True, visual_range=[0, 25], visual_text_color="#fff", symbol_size=15)
- geo.render("已開通地鐵城市分布情況.html")
- def create_line(df):
- """
- 生成城市地鐵線路數(shù)量分布情況
- """
- title_len = df['line']
- bins = [0, 5, 10, 15, 20, 25]
- level = ['0-5', '5-10', '10-15', '15-20', '20以上']
- len_stage = pd.cut(title_len, bins=bins, labels=level).value_counts().sort_index()
- # 生成柱狀圖
- attr = len_stage.index
- v1 = len_stage.values
- bar = Bar("各城市地鐵線路數(shù)量分布", title_pos='center', title_top='18', width=800, height=400)
- bar.add("", attr, v1, is_stack=True, is_label_show=True)
- bar.render("各城市地鐵線路數(shù)量分布.html")
- # 各個城市地鐵線路數(shù)
- df_city = df_line.groupby(['city']).count().reset_index().sort_values(by='line', ascending=False)
- print(df_city)
- create_map(df_city)
- create_line(df_city)
已經(jīng)開通地鐵的城市數(shù)據(jù),還有各個城市的地鐵線路數(shù)。
一共32個城市開通地鐵,其中北京、上海線路已經(jīng)超過了20條。
城市分布情況。
大部分都是省會城市,還有個別經(jīng)濟實力強的城市。
線路數(shù)量分布情況。
可以看到大部分還是在「0-5」這個階段的,當然最少為1條線。
- # 哪個城市哪條線路地鐵站最多
- print(df_line.sort_values(by='station', ascending=False))
探索一下哪個城市哪條線路地鐵站最多。
北京10號線***,重慶3號線第二。
還是蠻懷念北京1張票,2塊錢地鐵隨便做的時候。
可惜好日子一去不復返了。
去除重復換乘站數(shù)據(jù)。
- # 去除重復換乘站的地鐵數(shù)據(jù)
- df_station = df.groupby(['city', 'station']).count().reset_index()
- print(df_station)
一共包含3034個地鐵站,相較新周刊中3447個地鐵站數(shù)據(jù)。
減少了近400個地鐵站。
接下來看一下哪個城市地鐵站最多。
- # 統(tǒng)計每個城市包含地鐵站數(shù)(已去除重復換乘站)
- print(df_station.groupby(['city']).count().reset_index().sort_values(by='station', ascending=False))
32個城市,上海***,北京第二。
沒想到的是,武漢居然有那么多地鐵站。
現(xiàn)在來實現(xiàn)一下新周刊中的操作,生成地鐵名詞云。
- def create_wordcloud(df):
- """
- 生成地鐵名詞云
- """
- # 分詞
- text = ''
- for line in df['station']:
- text += ' '.join(jieba.cut(line, cut_all=False))
- text += ' '
- backgroud_Image = plt.imread('rocket.jpg')
- wc = WordCloud(
- background_color='white',
- mask=backgroud_Image,
- font_path='C:\Windows\Fonts\華康儷金黑W8.TTF',
- max_words=1000,
- max_font_size=150,
- min_font_size=15,
- prefer_horizontal=1,
- random_state=50,
- )
- wc.generate_from_text(text)
- img_colors = ImageColorGenerator(backgroud_Image)
- wc.recolor(color_func=img_colors)
- # 看看詞頻高的有哪些
- process_word = WordCloud.process_text(wc, text)
- sort = sorted(process_word.items(), key=lambda e: e[1], reverse=True)
- print(sort[:50])
- plt.imshow(wc)
- plt.axis('off')
- wc.to_file("地鐵名詞云.jpg")
- print('生成詞云成功!')
- create_wordcloud(df_station)
詞云圖如下。
廣場、大道、公園占了前三,和新周刊的圖片一樣,說明分析有效。
- words = []
- for line in df['station']:
- for i in line:
- # 將字符串輸出一個個中文
- words.append(i)
- def all_np(arr):
- """
- 統(tǒng)計單字頻率
- """
- arr = np.array(arr)
- key = np.unique(arr)
- result = {}
- for k in key:
- mask = (arr == k)
- arr_new = arr[mask]
- v = arr_new.size
- result[k] = v
- return result
- def create_word(word_message):
- """
- 生成柱狀圖
- """
- attr = [j[0] for j in word_message]
- v1 = [j[1] for j in word_message]
- bar = Bar("中國地鐵站***用的字", title_pos='center', title_top='18', width=800, height=400)
- bar.add("", attr, v1, is_stack=True, is_label_show=True)
- bar.render("中國地鐵站***用的字.html")
- word = all_np(words)
- word_message = sorted(word.items(), key=lambda x: x[1], reverse=True)[:10]
- create_word(word_message)
統(tǒng)計一下,大家最喜歡用什么字來命名地鐵。
路最多,在此之中上海的占比很大。
不信往下看。
- # 選取上海的地鐵站
- df1 = df_station[df_station['city'] == '上海']
- print(df1)
統(tǒng)計上海所有的地鐵站,一共345個。
選取包含路的地鐵站。
- # 選取上海地鐵站名字包含路的數(shù)據(jù)
- df2 = df1[df1['station'].str.contains('路')]
- print(df2)
有210個,約占上海地鐵的三分之二,路的七分之二。
看來上海對路是情有獨鐘的。
具體緣由這里就不解釋了,詳情見新周刊的推送,里面還是講解蠻詳細的。
武漢和重慶則是對家這個詞特別喜歡。
標志著那片土地開拓者們的籍貫與姓氏。
- # 選取武漢的地鐵站
- df1 = df_station[df_station['city'] == '武漢']
- print(df1)
- # 選取武漢地鐵站名字包含家的數(shù)據(jù)
- df2 = df1[df1['station'].str.contains('家')]
- print(df2)
- # 選取重慶的地鐵站
- df1 = df_station[df_station['city'] == '重慶']
- print(df1)
- # 選取重慶地鐵站名字包含家的數(shù)據(jù)
- df2 = df1[df1['station'].str.contains('家')]
- print(df2)
武漢共有17個,重慶共有20個。
看完家之后,再來看一下名字包含門的地鐵站。
- def create_door(door):
- """
- 生成柱狀圖
- """
- attr = [j for j in door['city'][:3]]
- v1 = [j for j in door['line'][:3]]
- bar = Bar("地鐵站***用“門”命名的城市", title_pos='center', title_top='18', width=800, height=400)
- bar.add("", attr, v1, is_stack=True, is_label_show=True, yaxis_max=40)
- bar.render("地鐵站***用門命名的城市.html")
- # 選取地鐵站名字包含門的數(shù)據(jù)
- df1 = df_station[df_station['station'].str.contains('門')]
- # 對數(shù)據(jù)進行分組計數(shù)
- df2 = df1.groupby(['city']).count().reset_index().sort_values(by='line', ascending=False)
- print(df2)
- create_door(df2)
一共有21個城市,地鐵站名包含門。
其中北京,南京,西安作為多朝古都,占去了大部分。
具體的地鐵站名數(shù)據(jù)。
- # 選取北京的地鐵站
- df1 = df_station[df_station['city'] == '北京']
- # 選取北京地鐵站名字包含門的數(shù)據(jù)
- df2 = df1[df1['station'].str.contains('門')]
- print(df2)
- # 選取南京的地鐵站
- df1 = df_station[df_station['city'] == '南京']
- # 選取南京地鐵站名字包含門的數(shù)據(jù)
- df2 = df1[df1['station'].str.contains('門')]
- print(df2)
- # 選取西安的地鐵站
- df1 = df_station[df_station['city'] == '西安']
- # 選取西安地鐵站名字包含門的數(shù)據(jù)
- df2 = df1[df1['station'].str.contains('門')]
- print(df2)
輸出如下。
三、總結(jié)
源碼及相關(guān)文件已上傳GitHub,點擊閱讀原文即可獲取。
這里摘一段新周刊的話。
可以說,一個小小的地鐵名就是一座城市風貌的一部分。
它反映著不同地方的水土,也承載著各個城市的文化和歷史。
確實如此,靠山的城市地鐵名多“山”,靠水的城市地鐵名“含水量”則是杠杠的。