鐵人賽2019 Day24 交通資料-國道ETC

  1. 1. 關於旅次資料
  2. 2. 資料解析
  3. 3. 門架資料
  4. 4. 進休息站的旅次
  5. 5. 後記

今天試著來看看高速公路局ETC的資料。

交通與GIS的結合有許多應用,在實務上也有各種不同的議題,三言兩語也討論不完
既然討論不完就找一個資料來試試…

大綱:

  • 關於旅次資料
  • 資料解析
  • 門架資料
  • 進休息站旅次

關於旅次資料

高速公路局提供了每小時ETC旅次流量等資料,
幾乎隔天就可以下載前一天的ETC資料,下載請點這
我們下載的是M06A中的11/5 下午五點的資料做測試

M06A每一筆資料代表一個旅次,包含:(取自M06A)
VehicleType:車種,31小客車、32小貨車、41大客車、42大貨車、5聯結車。
DerectionTime_O:車輛通過本旅次第1個測站時間。
Gantry_O:車輛通過本旅次第1個測站編號。
DerectionTime_D:車輛通過本旅次最後1個測站時間。
Gantry_D:車輛通過本旅次最後1個測站編號。
TripLength:本旅次行駛距離。
TripEnd:旅次標記(Y正常結束,N異常)
TripInformation:本旅次經過各個測站之通過時間及編號。

資料解析

今天我們想看看11/5五點這份旅次資料經過清水休息站的可能旅次
首先我們先把資料讀起來

1
2
csv=pd.read_csv(fname, header=None, engine='python',encoding='utf-8')
csv.columns['VehicleType','DerectionTime_O','GantryID_O','DerectionTime_D','GantryID_D','TripLength','TripEnd','TripInformation']

https://ithelp.ithome.com.tw/upload/images/20181108/20107816kRk2nOBh4p.png

門架資料

接下來我們要知道清水休息站在哪,
我們下載國道門架資料國道計費門架座標及里程牌價表

打開QGIS並把圖層匯進去
找到清水休息站
https://ithelp.ithome.com.tw/upload/images/20181108/20107816TG2gLlqcRX.png

我們觀察清水交流道大致位於03F1710與03F1739兩個區間內
把它挑出來

利用正規表達式挑出TripInformation含有這門架的資料

1
2
3
4
5
6
7
import re
service_go=[]
for idx,row in csv.iterrows():
if len(re.findall('03F1739',str(row['TripInformation'])))>0 or len(re.findall('03F1710',str(row['TripInformation'])))>0:
service_go.append(row)
df=pd.DataFrame(service_go)
df.head()

https://ithelp.ithome.com.tw/upload/images/20181108/201078163j67Ycxt76.png

進休息站的旅次

我們進一步將資料分為北上與南下,並取出TripInformation中經過03F1710與03F1739的時間
(有點醜見諒啦~~)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 03F1739 南方門架
# 03F1710 北方門架
for idx,row in df.iterrows():
trip=df.at[idx,'TripInformation']
check_time=0
for triptime in trip.split('; '):
if len(re.findall('03F1739',triptime))>0:
df.at[idx,'03F1739_t']=pd.Timestamp(triptime[:19])
check_time+=1
if len(re.findall('03F1710',triptime))>0:
df.at[idx,'03F1710_t']=pd.Timestamp(triptime[:19])
check_time+=1
if check_time>1:
if df.at[idx,'03F1710_t']>df.at[idx,'03F1739_t']:
df.at[idx,'direction']='S'
df.at[idx,'start'] = df.at[idx,'03F1739_t']
df.at[idx,'end'] = df.at[idx,'03F1710_t']
df.at[idx,'diff'] = (df.at[idx,'03F1710_t'] - df.at[idx,'03F1739_t'])
else:
df.at[idx,'direction']='N'
df.at[idx,'start'] = df.at[idx,'03F1710_t']
df.at[idx,'end'] = df.at[idx,'03F1739_t']
df.at[idx,'diff'] = (df.at[idx,'03F1739_t'] - df.at[idx,'03F1710_t'])
break

df.head()

https://ithelp.ithome.com.tw/upload/images/20181108/20107816egBNLdtsl2.png

其中direction是南北向
start經過休息站之前的門架時間
end為遠離休息站後的門架時間
diff為這兩段的時間

為了能繼續下去,只經過一次的我們就不算啦…
這邊假設經過這兩個門架的時間越長代表有進去休息站

1
2
3
df_new=df[df['start'].notna()]
df_new=df_new[df_new['end'].notna()]
df_new=df_new[df_new['diff'].notna()]

先排序觀察看看

1
2
# sorting
df_new[df_new['direction'].notna()].sort_values('diff',ascending=False).head()

https://ithelp.ithome.com.tw/upload/images/20181108/20107816gPjRqLEaoz.png

1
2
# sorting
df_new[df_new['direction'].notna()].sort_values('diff',ascending=True).head()

https://ithelp.ithome.com.tw/upload/images/20181108/20107816xuuf9S7qN1.png

觀察後可能還不夠明顯,我們把時間尺度方到17-18時,並繪製散布圖

先做一些處理,把時間拆解,並把資料異常的刪除

1
2
3
4
import matplotlib.pyplot as plt
df_new['h']=df_new['start'].dt.hour
df_new['m']=df_new['start'].dt.minute
df_new['diff_s']=[pd.Timedelta.total_seconds(row['diff']) for idx, row in df_new.iterrows()]

用散布圖呈現17-18時的資料,x軸是時間(分鐘),y軸為經過這個區間的時間(單位是秒)

1
2
3
import matplotlib.pyplot as plt
df17=df_new[df_new['h']==17]
df17.plot.scatter(x='m',y='diff_s',c='DarkBlue')

https://ithelp.ithome.com.tw/upload/images/20181108/20107816LZBDflxFr7.png

上面的成果可以看到大部分的車子經過的時間都差不多,明顯地離群值就是進站的車次
(我們可以用二階多項式擬合這些散佈點,並找出其除離群值,這邊就先跳過了直接手動給應門檻200秒)
綠色為進站,紅色為未進站

1
2
ax=df17[df17['diff_s']>200].plot.scatter(x='m',y='diff_s',c='green')
df17[df17['diff_s']<=200].plot.scatter(x='m',y='diff_s',c='red',ax=ax)

https://ithelp.ithome.com.tw/upload/images/20181108/20107816UHgGrXR42F.png

ps.今天只拿11/06 17時開始偵測到的旅次,正式計算應該把整天的旅次都讀進來分析喔!

後記

今天只是簡單試試高速公路ETC資料
個人認為台灣國道的交通資料是相對單純的,幾乎是單一線路
交通資訊的發布可能是點狀(車禍)的或線狀和面狀的(塞車,封路),
為了將資訊映射到路網或是地圖上,有一些問題需要探討
有機會再分享與討論囉!

參考資料
https://github.com/tomtom-international/openlr-js
http://openlr.itinero.tech/?code=CwKhciRM1yMoLP6KBAUjcyEE