Google Maps APIで所要時間を取得する

  • Google APIのサービスサイト対し、GET型の引数にパラメータを指定する
  • pythonではurllibライブラリを使う
  • データはjson形式。json形式とは、pythonの辞書オブジェクトの構造を{}や[]、カンマなどを含む文字列として表したもの。(単純なデータ交換では、バイナリデータではなくアスキー(文字列)とするのが互換性がある。)

甲府市飯田通の取得プログラム例

APIKEYは各自取得して試してみてほしい。

  • APIKEYの取得の仕方は、internet上で"Google api key"のようなキーワードで検索すればたくさんの情報がある。
  • toyokiのキーをテスト的に使ってみたい場合は、google driveに、そのキーを置いてあるので使ってみてもよい。

2地点間のデータをゲットできるだけなので、複数の経路がある場合に対しては、緯度経度のデータをあらかじめ作っておいて、繰り返しリクエストする必要がある。

In [1]:
import json, urllib
from datetime import datetime as dt


# APIキー (自分で取るのが望ましい)
APIKEY = ""

# 出発地
# 県庁前
Lat1 = "35.665292"
Lon1 = "138.567933"

# 目的地
# 気象台東

Lat2 = "35.667866"
Lon2 = "138.555587"

# 出発時間
now = dt.now()
departure_time_unix = int(dt.now().timestamp())

url = ("https://maps.googleapis.com/maps/api/distancematrix/json?units=metric" + 
       "&departure_time="  + str(departure_time_unix) + # 出発予定時刻(Unixtime(UTC))
       "&traffic_model=" + "best_guess" +          # 最適な旅行時間
       "&origins=" + str(Lat1) + "," + str(Lon1) +           # 出発地緯度経度
       "&destinations=" + str(Lat2) + "," + str(Lon2) +      # 到着地緯度経度
       "&key=" + APIKEY)    
req = urllib.request.Request(url)
res = urllib.request.urlopen(req)
json_data = res.read().decode('utf8')
url_obj = urllib.request.urlopen(url)

# 日本語文字など多国言語文字コードはutf8が標準
json_data = url_obj.read().decode('utf8')
# json形式のデータを辞書に変換
json_dict = json.loads(json_data)
In [2]:
# データの内容を確かめる
json_dict
Out[2]:
{'destination_addresses': ['4-chōme-1-24 Iida, Kofu, Yamanashi 400-0035, Japan'],
 'origin_addresses': ['Japan, 〒400-0031 Yamanashi, Kofu, Marunouchi, 2-chōme−16−1 富士急行ビル'],
 'rows': [{'elements': [{'distance': {'text': '1.2 km', 'value': 1169},
     'duration': {'text': '4 mins', 'value': 239},
     'duration_in_traffic': {'text': '4 mins', 'value': 242},
     'status': 'OK'}]}],
 'status': 'OK'}
In [3]:
# 必要な項目だけを取りだす

data1 = json_dict['rows'][0]['elements'][0]
print(now.strftime("%Y/%m/%d %H:%M:%S") + ","
      + str(data1['distance']['value']) + ","
      + str(data1['duration']['value']) + ','
      + str(data1['duration_in_traffic']['value']))
2020/05/01 09:22:41,1169,239,242

実用的なデータ収集のテスト

テストとして、飯田通り・県庁前ー気象台東間の双方向データを取ってみる (もっと簡潔に書けるのだがとりあえず。)

12/05の昼ころより、20分間隔でデータを取り始めている。 そのデータは、8topsの/ssd/toyoki/googleData/iida/iidaBothTrafficByGoogle.csv に置いてある。(簡単には、下の方にあるスクリプトにより、jupyterでも閲覧できる。)

以下は、古い初期バージョンである。

より洗練されたコードについては、城東通りや白州エリアの流動分析のノートブックを参照してほしい。</span>

下の飯田通のデータ表示については、活きている。

In [4]:
#!/usr/bin/env python3
import json
import urllib.request
from datetime import datetime as dt
import csv


def getTraffic(url):
    req = urllib.request.Request(url)
    try:
        with urllib.request.urlopen(req) as res:
            json_data = res.read().decode('utf8')
            json_dict = json.loads(json_data)
            data1 = json_dict['rows'][0]['elements'][0]
            return data1
    except urllib.error.HTTPError as e:
        # Status codeでエラーハンドリング
        if e.code >= 400:
            print(e.reason)
        else:
            raise e


# APIキー (自分で取るのが望ましい)
APIKEY = ""

# ####双方向####

# 気象台東(1)
Lat1 = "35.667866"
Lon1 = "138.555587"

# 県庁前 (2)
Lat2 = "35.665292"
Lon2 = "138.567933"


# 出発時間
now = dt.now()
departure_time_unix = int(dt.now().timestamp())

url1 = ("https://maps.googleapis.com/maps/api/distancematrix/json?units=metric" +
        # 出発予定時刻(Unixtime(UTC))
        "&departure_time=" + str(departure_time_unix) +
        "&traffic_model=" + "best_guess" +          # 最適な旅行時間
        "&origins=" + str(Lat1) + "," + str(Lon1) +           # 出発地緯度経度
        "&destinations=" + str(Lat2) + "," + str(Lon2) +      # 到着地緯度経度
        "&key=" + APIKEY)
url2 = ("https://maps.googleapis.com/maps/api/distancematrix/json?units=metric" +
        # 出発予定時刻(Unixtime(UTC))
        "&departure_time=" + str(departure_time_unix) +
        "&traffic_model=" + "best_guess" +          # 最適な旅行時間
        "&origins=" + str(Lat2) + "," + str(Lon2) +           # 出発地緯度経度
        "&destinations=" + str(Lat1) + "," + str(Lon1) +      # 到着地緯度経度
        "&key=" + APIKEY)

data1 = getTraffic(url1)
data2 = getTraffic(url2)

# ファイルへの追加
with open("/ssd/toyoki/googleData/iida/iidaBothTrafficByGoogle.csv", "a") as f:
    writer = csv.writer(f)
    writer.writerow([now.strftime("%Y/%m/%d %H:%M:%S"),
                     str(data1['distance']['value']),
                     str(data1['duration']['value']),
                     str(data1['duration_in_traffic']['value']),
                     str(data2['duration']['value']),
                     str(data2['duration_in_traffic']['value'])])
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-4-d1af99fc1f63> in <module>
     55         "&key=" + APIKEY)
     56 
---> 57 data1 = getTraffic(url1)
     58 data2 = getTraffic(url2)
     59 

<ipython-input-4-d1af99fc1f63> in getTraffic(url)
     12             json_data = res.read().decode('utf8')
     13             json_dict = json.loads(json_data)
---> 14             data1 = json_dict['rows'][0]['elements'][0]
     15             return data1
     16     except urllib.error.HTTPError as e:

IndexError: list index out of range

既存データの閲覧と図示

飯田通の場合

In [1]:
# 8tops上で採取しているデータの閲覧
import pandas as pd
df = pd.read_csv("/ssd/toyoki/googleData/iida/iidaBothTrafficByGoogle.csv",sep=",",skipinitialspace=True)
df.head()
Out[1]:
date distance east_bound_std east_bound west_bound_std west_bound
0 2019/12/05 10:11:25 1169 244 254 244 237
1 2019/12/05 11:20:01 1169 244 288 244 278
2 2019/12/05 11:40:01 1169 244 254 244 279
3 2019/12/05 12:00:01 1169 244 224 244 275
4 2019/12/05 12:20:01 1169 244 250 244 252
In [2]:
df.tail()
Out[2]:
date distance east_bound_std east_bound west_bound_std west_bound
9004 2020/04/08 12:40:01 1169 238 222 240 276
9005 2020/04/08 13:00:02 1169 238 221 240 244
9006 2020/04/08 13:20:01 1169 238 244 240 243
9007 2020/04/08 13:40:01 1169 238 236 240 230
9008 2020/04/08 14:00:01 1169 238 218 240 246
In [3]:
df.plot(x='date', y=['east_bound','west_bound'], figsize=(16,8))
Out[3]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f8a7567f6a0>
In [4]:
# これまでに得られた日にちについて時刻ごとに平均した値 (平日、休日を分けたほうが良いのだが)

df['date_obj'] = pd.to_datetime(df['date'])          # dateは文字列なので、datetime型の列を新設
df['hour_min'] = df['date_obj'].dt.strftime("%H:%M") # 時分の文字列の列を新設
# groupbyによる平均値計算mean()を行うとマルチインデックスのデータ構造になる
# reset_index()によりマルチインデックスが解除になる
mean_df = df.groupby('hour_min').mean().reset_index()
mean_df
Out[4]:
hour_min distance east_bound_std east_bound west_bound_std west_bound
0 00:00 1169.0 241.872 184.232 240.008 190.368
1 00:20 1169.0 241.872 186.368 240.008 187.232
2 00:40 1169.0 241.872 190.208 240.008 185.744
3 01:00 1169.0 241.872 192.840 240.008 192.496
4 01:20 1169.0 241.872 197.704 240.008 194.000
... ... ... ... ... ... ...
68 22:20 1169.0 241.872 194.320 240.008 193.280
69 22:40 1169.0 241.872 193.880 240.008 195.160
70 23:00 1169.0 241.872 189.712 240.008 194.400
71 23:20 1169.0 241.872 184.936 240.008 190.736
72 23:40 1169.0 241.872 180.144 240.008 189.376

73 rows × 6 columns

In [11]:
# 取得期間を平均した日変位データmean_dfをプロット
import matplotlib.pyplot as plt

plt.rcParams["font.size"] = 14
fig, ax = plt.subplots(figsize=(10, 5))
mean_df.plot(x='hour_min', y=['east_bound','west_bound'], lw=2, ax=ax)
ax.set_title("県庁前 - 気象台東 所要時間(秒)")
Out[11]:
Text(0.5, 1.0, '県庁前 - 気象台東 所要時間(秒)')
In [6]:
# 移動平均 (1:00のデータを0:40, 1:00, 1:20の平均値とする)
# 1:00 - 2:00 の平均値としては (a_0 + 2a_1 + 2a_2 + a_3)/6のような計算が望ましい
tmp = mean_df.set_index('hour_min')
mean_df1 = tmp.rolling(3, center=True, min_periods=1).mean().reset_index()
mean_df1.head()
Out[6]:
hour_min distance east_bound_std east_bound west_bound_std west_bound
0 00:00 1169.0 241.872 185.300000 240.008 188.800000
1 00:20 1169.0 241.872 186.936000 240.008 187.781333
2 00:40 1169.0 241.872 189.805333 240.008 188.490667
3 01:00 1169.0 241.872 193.584000 240.008 190.746667
4 01:20 1169.0 241.872 196.794667 240.008 196.149333
In [7]:
mean_df1.plot(x='hour_min', y=['east_bound','west_bound'], figsize=(16,8),fontsize=14)
Out[7]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f8a731ee550>
In [ ]: