183條地鐵線路,3034個地鐵站,發現中國地鐵名字的秘密。
- 2019 年 10 月 8 日
- 筆記
來源 | 法納斯特
最近看了新周刊的一篇推送,有關地鐵名字的分析,鏈接如下。
於是乎也想著自己去獲取數據,然後進行分析一番。
當然分析水平不可能和他們的相比,畢竟文筆擺在那裡,也就那點水平。
大家看著樂呵就好,能提高的估摸著也就只有數據的準確性啦。
文中所用到的地鐵站數據並沒有去重,對於換乘站,含有大量重複。
即使作者一直在強調換乘站佔比很小,影響不是很大。
但於我而言,去除重複數據還是比較簡單的。
然後照著人家的路子去分析,多學習一下。
/ 01 / 獲取分析
地鐵資訊獲取從高德地圖上獲取。

上面主要獲取城市的「id」,「cityname」及「名稱」。
用於拼接請求網址,進而獲取地鐵線路的具體資訊。

找到請求資訊,獲取各個城市的地鐵線路以及線路中站點詳情。
/ 02 / 數據獲取
具體程式碼如下。
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()最後成功獲取數據。

包含換乘站數據,一共3541個地鐵站點。
/ 03 / 數據可視化
先對數據進行清洗,去除重複的換乘站資訊。
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 # 設置列名與數據對齊 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) # 讀取數據 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)通過城市及地鐵線路進行分組,得到全國地鐵線路總數。

一共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): """ 生成城市地鐵線路數量分布情況 """ 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("各城市地鐵線路數量分布", title_pos='center', title_top='18', width=800, height=400) bar.add("", attr, v1, is_stack=True, is_label_show=True) bar.render("各城市地鐵線路數量分布.html") # 各個城市地鐵線路數 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)已經開通地鐵的城市數據,還有各個城市的地鐵線路數。

一共32個城市開通地鐵,其中北京、上海線路已經超過了20條。
城市分布情況。

大部分都是省會城市,還有個別經濟實力強的城市。
線路數量分布情況。

可以看到大部分還是在「0-5」這個階段的,當然最少為1條線。
# 哪個城市哪條線路地鐵站最多 print(df_line.sort_values(by='station', ascending=False))
探索一下哪個城市哪條線路地鐵站最多。

北京10號線第一,重慶3號線第二。


還是蠻懷念北京1張票,2塊錢地鐵隨便做的時候。
可惜好日子一去不復返了。
去除重複換乘站數據。
# 去除重複換乘站的地鐵數據 df_station = df.groupby(['city', 'station']).count().reset_index() print(df_station)
一共包含3034個地鐵站,相較新周刊中3447個地鐵站數據。
減少了近400個地鐵站。

接下來看一下哪個城市地鐵站最多。
# 統計每個城市包含地鐵站數(已去除重複換乘站) print(df_station.groupby(['city']).count().reset_index().sort_values(by='station', ascending=False))
32個城市,上海第一,北京第二。
沒想到的是,武漢居然有那麼多地鐵站。

現在來實現一下新周刊中的操作,生成地鐵名詞雲。
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:WindowsFonts華康儷金黑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): """ 統計單字頻率 """ 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)統計一下,大家最喜歡用什麼字來命名地鐵。

路最多,在此之中上海的佔比很大。
不信往下看。
# 選取上海的地鐵站 df1 = df_station[df_station['city'] == '上海'] print(df1)
統計上海所有的地鐵站,一共345個。

選取包含路的地鐵站。
# 選取上海地鐵站名字包含路的數據 df2 = df1[df1['station'].str.contains('路')] print(df2)有210個,約佔上海地鐵的三分之二,路的七分之二。

看來上海對路是情有獨鐘的。
具體緣由這裡就不解釋了,詳情見新周刊的推送,裡面還是講解蠻詳細的。
武漢和重慶則是對家這個詞特別喜歡。
標誌著那片土地開拓者們的籍貫與姓氏。
# 選取武漢的地鐵站 df1 = df_station[df_station['city'] == '武漢'] print(df1) # 選取武漢地鐵站名字包含家的數據 df2 = df1[df1['station'].str.contains('家')] print(df2) # 選取重慶的地鐵站 df1 = df_station[df_station['city'] == '重慶'] print(df1) # 選取重慶地鐵站名字包含家的數據 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") # 選取地鐵站名字包含門的數據 df1 = df_station[df_station['station'].str.contains('門')] # 對數據進行分組計數 df2 = df1.groupby(['city']).count().reset_index().sort_values(by='line', ascending=False) print(df2) create_door(df2)一共有21個城市,地鐵站名包含門。

其中北京,南京,西安作為多朝古都,佔去了大部分。

具體的地鐵站名數據。
# 選取北京的地鐵站 df1 = df_station[df_station['city'] == '北京'] # 選取北京地鐵站名字包含門的數據 df2 = df1[df1['station'].str.contains('門')] print(df2) # 選取南京的地鐵站 df1 = df_station[df_station['city'] == '南京'] # 選取南京地鐵站名字包含門的數據 df2 = df1[df1['station'].str.contains('門')] print(df2) # 選取西安的地鐵站 df1 = df_station[df_station['city'] == '西安'] # 選取西安地鐵站名字包含門的數據 df2 = df1[df1['station'].str.contains('門')] print(df2)輸出如下。


這裡摘一段新周刊的話。
可以說,一個小小的地鐵名就是一座城市風貌的一部分。
它反映著不同地方的水土,也承載著各個城市的文化和歷史。
確實如此,靠山的城市地鐵名多「山」,靠水的城市地鐵名「含水量」則是杠杠的。