Profile PassportのAPIを利用する
Tag
はじめに
本記事ではTellusのJupyterLabを使って位置情報データ「Profile Passport」を取得する方法を紹介します。
Profile PassprotのAPIに必要なパラメータは期間(begin_timeとend_time)、時間頻度(interval)、そして地理的な範囲(bounds)となります。詳しくは商品情報のAPIリファレンスを参照してください。
https://pflow.tellusxdp.com/api/v1/profile_passport/get_count{?begin_time,end_time,interval,bouds}
Name | Input | Description |
---|---|---|
begin_timestring(query) | 必須 | 開始時刻 UTC (yyyy-mm-dd HH:MM:SS) ※端数の時刻は、時間頻度(分)単位で切り上げされます。例:’2017-01-01 09:00:00’ |
end_timestring(query) | 必須 | 終了時刻 UTC (yyyy-mm-dd HH:MM:SS) ※端数の時刻は、時間頻度(分)単位で切り捨てされます。例:’2017-01-01 10:59:59’ |
intervalnumber(query) | 必須 | 時間頻度 ※開始時刻~終了時刻の間で集計する間隔を30(分)か、または60(分)で指定します。例:60(30 or 60) |
boundsnumber(query) | 必須 | 緯度・経度での地理的範囲 ※カンマ区切りで最小緯度,最小経度,最大緯度,最大経度の順で設定します。例:’-90.0,-180.0,90.0,180.0’ |
※期間や地域を広く指定すると取得するデータが多くなり504エラーが出る場合があります。
位置情報データ「Profile Passport」を取得するには
「Profile Passport」とは、プロファイルパスポート SDKを通して、スマートフォンアプリから取得された位置情報データのことです。東京近郊に限られますが、2016年7月から2017年9月までの期間の「Profile Passport」のデータを、Tellus上で利用できます。
※画像を利用する際は、商品情報の利用ポリシーを確認して、規約を違反しないように注意してください。
Profile PassportはTellus OS上ではヒートマップとして利用できます。
Profile Passportのデータを取得する関数を定義しましょう。関数ではデータの開始時間や終了時間などを変数として入力する必要があります。
import os, json, requests from io import BytesIO from datetime import datetime from datetime import timedelta from dateutil import relativedelta TOKEN = 'ここには自分のアカウントのトークンを貼り付ける' TIME_FORMAT = "%Y-%m-%d %H:%M:%S" INTERVAL = 60 def get_profile_passport_count(begin_time, end_time, interval, bounds): """ /api/v1/profile_passport/get_count Parameters ---------- begin_time : str 取得開始時刻 UTC(yyyy-mm-dd HH:MM:SS) end_time : str 取得終了時刻 UTC(yyyy-mm-dd HH:MM:SS) interval : number 取得間隔(30 or 60) bbox : str 取得範囲(最小緯度,最小経度,最大緯度,最大経度) Returns ------- content : list 結果 """ url = 'https://pflow.tellusxdp.com/api/v1/profile_passport/get_count' headers = { 'Authorization': 'Bearer ' + TOKEN } payload = { 'begin_time': begin_time, 'end_time': end_time, 'interval': interval, 'bounds': bounds } r = requests.get(url, headers=headers, params=payload) if r.status_code is not 200: raise ValueError('status error({}).'.format(r.status_code)) return json.loads(r.content)
トークンはマイページのAPIアクセス設定(要ログイン)から取得してください。取得できる位置情報データは以下の通りです。
Outcome | Description |
---|---|
begin_time | 集計開始時刻(世界標準時) |
end_time | 集計終了時刻(世界標準時) |
mesh | 集計範囲の地域メッシュコード(4分の1地域メッシュ) |
count | 人数※ブログウォッチャー社が計測した数値であり、実際のメッシュ内の総数を示すものではありません。 |
日本時間が分かりやすいためデータを取得する関数の開始時間は日本時間で入力する形としていますが、APIは世界標準時を基準に構成されています。そのため次の関数内では日本時間を世界標準時に直す処理を行なっています。さらに、データを取得する領域を指定し、その領域に対して一定間隔のデータを取得するための処理を加えていきます。
def get_profile_passport_count_per_hour(begin_year, begin_month, begin_day, begin_hour, bbox, days=0, hours=0): """ 1時間ごとのprofile_passportの結果を取得する。 Parameters ---------- begin_year : int 取得する年(日本標準時) begin_month : int 取得する月(日本標準時) begin_day : int 取得する日(日本標準時) begin_hour : int 取得する時間(日本標準時) begin_bbox : array_like 取得する領域のBounding Box days : int 何日後まで取得するか hours : int 何時間後まで取得するか(0 ~ 23) Returns ------- data : list 結果 """ # APIには世界標準時で渡す begin_datetime = datetime(begin_year, begin_month, begin_day, begin_hour, 0, 0, 0) - timedelta(hours=9) end_datetime = begin_datetime + timedelta(days=days,hours=hours) bounds = str(bbox[1])+","+str(bbox[0])+","+str(bbox[3])+","+str(bbox[2]) try: data = get_profile_passport_count(begin_datetime.strftime(TIME_FORMAT), end_datetime.strftime(TIME_FORMAT), INTERVAL, bounds) except ValueError as e: print(e) return data
定義した関数を実行しましょう。取得するデータは4月1日の12時から13時までの新宿西口付近です。
shinjuku_bbox = [139.687011, 35.683024, 139.700284, 35.692078] data_shinjuku_20170401 = get_profile_passport_count_per_hour(2017, 4, 1, 12, shinjuku_bbox, hours=1) print(len(data_shinjuku_20170401)) print(data_shinjuku_20170401)
{ 'begin_time': '2017-04-01 03:00:00', 'end_time': '2017-04-01 03:59:59', 'mesh': '5339452511', 'count': 160 }
begin_timeとend_timeは集計時刻です。このデータは世界標準時で2017年4月1日の03:00:00から03:59:59の間の値です。meshは地域メッシュコードを表します。地域メッシュコードとは、日本工業規格で定められた区域を識別するコードのことで、このAPIでは4分の1地域メッシュ区分で値が返却されます。
Tellus OSではOS右上にあるツールからグリッドツールを選択し、メッシュコードの表示をオンにすることで地域メッシュを確認できます。地域メッシュについて詳しくはこちらを参考にしてください。
1日の人の動きをグラフ化しよう
続いて、1日の間にメッシュ内に滞在する人の数がどれだけ変化するか調べてみましょう。
ginza_bbox = [139.765034, 35.668432, 139.769242, 35.671083] data_ginza_20170401 = get_profile_passport_count_per_hour(2017, 4, 1, 0, ginza_bbox, days=1) print(data_ginza_20170401[0:3])
サンプルコードでは2017年4月1日の銀座駅周辺(メッシュコード:5339460114)のデータを1時間毎に取得しています(data_ginza_20170401)。取得したデータをグラフ化してみましょう。
# load libraries import matplotlib.pyplot as plt import matplotlib.dates as mdates %matplotlib inline # only begin_data is enough to draw the transitional data x_period = [] y_value = [] for i in range(len(data_ginza_20170401)): x_period.append(datetime.strptime(data_ginza_20170401[i]['begin_time'],"%Y-%m-%d %H:%M:%S") + timedelta(hours=9)) y_value.append(data_ginza_20170401[i]['count']) # change date format x_period = [x.strftime("%m/%d %H:%M:%S") for x in x_period] fig, ax= plt.subplots(figsize=(12, 6)) ax.plot(x_period, y_value, label = 'no marker') plt.xticks(rotation=90) ax.set_xlabel("time") ax.set_ylabel("count") ax.set_xlim(x_period[0], x_period[-1]) plt.show()
時間は日本時に戻してあります。次に上の処理を関数化します。
import matplotlib.pyplot as plt import matplotlib.dates as mdates %matplotlib inline def plot_daily_count(data, year, month, day, mesh): """ 1日分のprofile_passportの結果をグラフ化 Parameters ---------- year : int 取得する年(日本標準時) month : int 取得する月(日本標準時) day : int 取得する日(日本標準時) mesh : str 図示する地域のメッシュコード """ begin_datetime = datetime(year, month, day, 0, 0, 0, 0) end_datetime = begin_datetime + timedelta(days=1) temp_start = begin_datetime periods = [] while temp_start < end_datetime: periods.append(temp_start) temp_start = temp_start + timedelta(minutes=INTERVAL) counts = [] for i in range(len(periods)): begin_time = (periods[i] - timedelta(hours=9)).strftime(TIME_FORMAT) found = next((d['count'] for d in data if d['begin_time']==begin_time and d['mesh']==mesh) ,0) counts.append(found) fig, ax= plt.subplots(figsize=(12, 6)) ax.plot(periods, counts, label = 'no marker') xfmt = mdates.DateFormatter("%H") xloc = mdates.HourLocator() ax.xaxis.set_major_locator(xloc) ax.xaxis.set_major_formatter(xfmt) ax.set_xlabel("hour") ax.set_ylabel("count") ax.set_xlim(periods[0], periods[-1]) plt.show() plot_daily_count(data_ginza_20170401, 2017, 4, 1, '5339460114')
同様の結果を得ることができました。続いて、2017年4月1日の築地市場周辺(メッシュコード:5339369123)のデータを1時間毎に取得しグラフ化します。
tsukiji_bbox = [139.768487,35.660063, 139.772149,35.662768] data_tsukiji_20170401 = get_profile_passport_count_per_hour(2017, 4, 1, 0, tsukiji_bbox, days=1) print(data_tsukiji_20170401[:3]) plot_daily_count(data_tsukiji_20170401, 2017, 4, 1, '5339369123')
2つのグラフを単純に見比べるだけでも、一般的な商業施設が集まる銀座は昼から夕方にかけて人が集まるのに対し、市場である築地は朝から昼にかけて人が集まっており、地域性によりピーク時間が異なることがわかります。
1ヶ月の人の動きをグラフ化しよう
1ヶ月間で滞在人数がどれだけ変化するか調べてみましょう。
以下のサンプルコードを実行してください。サンプルでは2017年4月の神宮球場周辺(メッシュコード:5339450734)のデータを1時間毎に取得しています。
※実行して結果が返ってくるまで、数分以上かかる場合があります。
jingu_bbox = [139.715106, 35.672617, 139.719169, 35.675419] start_day = 1 duration = 10 end_day = 30 data_jingu_201704 = [] while start_day <= end_day: data_jingu_201704.extend(get_profile_passport_count_per_hour(2017, 4, start_day, 0, jingu_bbox, days=duration)) start_day += duration len(data_jingu_201704)
700件のデータを取得することができました。続いて、グラフの描画を行います。手順は1日の動きをグラフにしたのとほぼ同じになります。
# only begin_data is enough to draw the transitional data x_period = [] y_value = [] for i in range(len(data_jingu_201704)): x_period.append(datetime.strptime(data_jingu_201704[i]['begin_time'],"%Y-%m-%d %H:%M:%S")+ timedelta(hours=9)) y_value.append(data_jingu_201704[i]['count']) # Axes settings are in Locator and Formatter fig, ax= plt.subplots(figsize=(12, 6)) ax.plot(x_period, y_value, label = 'no marker') # set ticks ax.xaxis.set_major_locator(mdates.DayLocator(bymonthday=None, interval=4, tz=None)) ax.xaxis.set_major_formatter(mdates.DateFormatter("%Y-%m-%d")) # rotate ticks and set font size labels = ax.get_xticklabels() plt.setp(labels, rotation=45, fontsize=10); # show line graph with grids ax.grid()
続いて、関数として定義します。
def plot_monthly_count(data, year, month, mesh): """ 1ヶ月のprofile_passportの結果をグラフ化 Parameters ---------- year : int 取得する年(日本標準時) month : int 取得する月(日本標準時) mesh : str 図示する地域のメッシュコード """ begin_datetime = datetime(year, month, 1, 0, 0, 0, 0) end_datetime = begin_datetime + relativedelta.relativedelta(months=1,day=1) temp_start = begin_datetime periods = [] while temp_start < end_datetime: periods.append(temp_start) temp_start = temp_start + timedelta(minutes=INTERVAL) counts = [] for i in range(len(periods)): begin_time = (periods[i] - timedelta(hours=9)).strftime(TIME_FORMAT) found = next((d["count"] for d in data if d['begin_time']==begin_time and d['mesh']==mesh) ,0) counts.append(found) fig, ax= plt.subplots(figsize=(12, 6)) ax.plot(periods, counts, label = 'no marker') xfmt = mdates.DateFormatter('%m/%d') ax.set_xticklabels(periods, size='small') ax.xaxis.set_major_formatter(xfmt) ax.set_xlabel("day") ax.set_ylabel("count") ax.set_xlim(periods[0], periods[-1]) plt.show() plot_monthly_count(data_jingu_201704, 2017, 4, '5339450734')
2017年4月の神宮球場周辺の滞在人数(横軸が日時、縦軸が人数)(出典:ブログウォッチャー)
人数が多い日が飛び飛びで存在していますが、調べてみると東京ヤクルトスワローズのホーム戦が4/1 – 4/2、4/12 – 4/13、4/21 – 4/23、4/28 – 4/30と行われており、グラフの尖った部分の日付と一致しています(他にも東京六大学の試合や東京都高校野球の試合が開催された日に小山が立っています)。
データをうまく加工することで、以下のように3次元プロットも可能です。ぜひ挑戦してみてください。
2017年4月1日から7日にかけての東京ディズニーランド、ディズニーシー滞在人数
(x, y)=(3, 2)近辺がランドで、(x, y)=(6, 3)近辺がシーです。
以上が、TellusのJupyter Labを使って位置情報データ「Profile Passport」を取得する方法でした。
指定した空間での滞在人数は、POS(Point of Sales)情報を始めとした他のデータと組み合わせることで、付加価値が増します。気象情報を含めた衛星データなどを組み合わせることで、人流データに付加価値をつけることも可能です。人の動きをグラフとして眺めるだけでも得られる気づきはたくさんあります。東京以外の地域のデータも今後公開していく予定ですので、楽しみにお待ちください。
import os, json, requests from io import BytesIO from datetime import datetime from datetime import timedelta from dateutil import relativedelta TOKEN = "ここに自分のトークンを貼る" TIME_FORMAT = "%Y-%m-%d %H:%M:%S" INTERVAL = 60 def get_profile_passport_count(begin_time, end_time, interval, bounds): """ /api/v1/profile_passport/get_count Parameters ---------- begin_time : str 取得開始時刻 UTC(yyyy-mm-dd HH:MM:SS) end_time : str 取得終了時刻 UTC(yyyy-mm-dd HH:MM:SS) interval : number 取得間隔(30 or 60) bbox : str 取得範囲(最小緯度,最小経度,最大緯度,最大経度) Returns ------- content : list 結果 """ url = 'https://pflow.tellusxdp.com/api/v1/profile_passport/get_count' headers = { 'Authorization': 'Bearer ' + TOKEN } payload = { 'begin_time': begin_time, 'end_time': end_time, 'interval': interval, 'bounds': bounds } r = requests.get(url, headers=headers, params=payload) if r.status_code is not 200: raise ValueError('status error({}).'.format(r.status_code)) return json.loads(r.content) def get_profile_passport_count_per_hour(begin_year, begin_month, begin_day, begin_hour, bbox, days=0, hours=0): """ 1時間ごとのprofile_passportの結果を取得する。 Parameters ---------- begin_year : int 取得する年(日本標準時) begin_month : int 取得する月(日本標準時) begin_day : int 取得する日(日本標準時) begin_hour : int 取得する時間(日本標準時) begin_bbox : array_like 取得する領域のBounding Box days : int 何日後まで取得するか hours : int 何時間後まで取得するか(0 ~ 23) Returns ------- data : list 結果 """ # APIには世界標準時で渡す begin_datetime = datetime(begin_year, begin_month, begin_day, begin_hour, 0, 0, 0) - timedelta(hours=9) end_datetime = begin_datetime + timedelta(days=days,hours=hours) bounds = str(bbox[1])+","+str(bbox[0])+","+str(bbox[3])+","+str(bbox[2]) try: data = get_profile_passport_count(begin_datetime.strftime(TIME_FORMAT), end_datetime.strftime(TIME_FORMAT), INTERVAL, bounds) except ValueError as e: print(e) return data shinjuku_bbox = [139.687011, 35.683024, 139.700284, 35.692078] data_shinjuku_20170401 = get_profile_passport_count_per_hour(2017, 4, 1, 12, shinjuku_bbox, hours=1) print(len(data_shinjuku_20170401)) print(data_shinjuku_20170401) ginza_bbox = [139.765034, 35.668432, 139.769242, 35.671083] data_ginza_20170401 = get_profile_passport_count_per_hour(2017, 4, 1, 0, ginza_bbox, days=1) print(data_ginza_20170401[0:3]) import matplotlib.pyplot as plt import matplotlib.dates as mdates get_ipython().run_line_magic('matplotlib', 'inline') def plot_daily_count(data, year, month, day, mesh): """ 1日分のprofile_passportの結果をグラフ化 Parameters ---------- year : int 取得する年(日本標準時) month : int 取得する月(日本標準時) day : int 取得する日(日本標準時) mesh : str 図示する地域のメッシュコード """ begin_datetime = datetime(year, month, day, 0, 0, 0, 0) end_datetime = begin_datetime + timedelta(days=1) temp_start = begin_datetime periods = [] while temp_start < end_datetime: periods.append(temp_start) temp_start = temp_start + timedelta(minutes=INTERVAL) counts = [] for i in range(len(periods)): begin_time = (periods[i] - timedelta(hours=9)).strftime(TIME_FORMAT) found = next((d['count'] for d in data if d['begin_time']==begin_time and d['mesh']==mesh) ,0) counts.append(found) fig, ax= plt.subplots(figsize=(12, 6)) ax.plot(periods, counts, label = 'no marker') xfmt = mdates.DateFormatter("%H") xloc = mdates.HourLocator() ax.xaxis.set_major_locator(xloc) ax.xaxis.set_major_formatter(xfmt) ax.set_xlabel("hour") ax.set_ylabel("count") ax.set_xlim(periods[0], periods[-1]) plt.show() plot_daily_count(data_ginza_20170401, 2017, 4, 1, '5339460114') tsukiji_bbox = [139.768487,35.660063, 139.772149,35.662768] data_tsukiji_20170401 = get_profile_passport_count_per_hour(2017, 4, 1, 0, tsukiji_bbox, days=1) print(data_tsukiji_20170401[:3]) plot_daily_count(data_tsukiji_20170401, 2017, 4, 1, '5339369123') jingu_bbox = [139.715106, 35.672617, 139.719169, 35.675419] start_day = 1 duration = 10 end_day = 30 data_jingu_201704 = [] while start_day <= end_day: data_jingu_201704.extend(get_profile_passport_count_per_hour(2017, 4, start_day, 0, jingu_bbox, days=duration)) start_day += duration def plot_monthly_count(data, year, month, mesh): """ 1ヶ月のprofile_passportの結果をグラフ化 Parameters ---------- year : int 取得する年(日本標準時) month : int 取得する月(日本標準時) mesh : str 図示する地域のメッシュコード """ begin_datetime = datetime(year, month, 1, 0, 0, 0, 0) end_datetime = begin_datetime + relativedelta.relativedelta(months=1,day=1) temp_start = begin_datetime periods = [] while temp_start < end_datetime: periods.append(temp_start) temp_start = temp_start + timedelta(minutes=INTERVAL) counts = [] for i in range(len(periods)): begin_time = (periods[i] - timedelta(hours=9)).strftime(TIME_FORMAT) found = next((d["count"] for d in data if d['begin_time']==begin_time and d['mesh']==mesh) ,0) counts.append(found) fig, ax= plt.subplots(figsize=(12, 6)) ax.plot(periods, counts, label = 'no marker') xfmt = mdates.DateFormatter('%m/%d') ax.set_xticklabels(periods, size='small') ax.xaxis.set_major_formatter(xfmt) ax.set_xlabel("day") ax.set_ylabel("count") ax.set_xlim(periods[0], periods[-1]) plt.show() plot_monthly_count(data_jingu_201704, 2017, 4, '5339450734')