【ゼロからのTellusの使い方】Jupyter Labで位置情報データ「Profile Passport」を取得する
先日リリースされたTellusバージョン1.1で追加された位置情報データ「Profile Passport」を取得する方法をご紹介いたします。
記事作成時から、Tellusからデータを検索・取得するAPIが変更になっております。該当箇所のコードについては、以下のリンクをご参照ください。
https://www.tellusxdp.com/ja/howtouse/access/traveler_api_20220310_
firstpart.html
2022年8月31日以降、Tellus OSでのデータの閲覧方法など使い方が一部変更になっております。新しいTellus OSの基本操作は以下のリンクをご参照ください。
https://www.tellusxdp.com/ja/howtouse/tellus_os/start_tellus_os.html
本記事ではTellusのJupyter Labを使って位置情報データ「Profile Passport」を取得する方法を紹介します。
TellusでJupyter Lab(Jupyter Notebook)を使う方法は、「Tellusの開発環境でAPI引っ張ってみた」をご覧ください。
1. 位置情報データ「Profile Passport」を取得するには
「Profile Passport」とは、ブログウォッチャー社が提供する独自開発SDKによるスマートフォンの位置情報データです。
東京近郊に限られますが、2016年7月から2017年9月までの期間の「Profile Passport」のデータを、Tellus上では利用することができます。
※画像を利用する際は、データ詳細のデータポリシーを確認して、規約を違反しないように注意してください。
Tellus OS上ではヒートマップとして利用できます。
Tellus IDE(開発環境)からはAPIを使ってデータを取得することができます。
https://pflow.tellusxdp.com/api/v1/profile_passport/get_count{?begin_time,end_time,interval,bouds}
引数
begin_time | 必須str | 開始時刻(世界標準時) 例:’2017-01-01 09:00:00’ |
end_time | 必須int | 終了時刻(世界標準時) 例:’2017-01-01 10:59:59’ |
interval | 必須str | 時間頻度(分) 例:60(30 or 60) |
bounds | 必須str | 取得する地理的範囲 ’最小緯度,最小経度,最大緯度,最大経度’で指定する。 例:’-90.0,-180.0,90.0,180.0’ |
※期間や地域を広く指定すると取得するデータが多くなり504エラーが出る場合があります。
詳しくはAPIリファレンスの「Tellus 人流 API」を参照してください。
ではこれをJupyter Lab上で呼び出してみましょう。
Tellus IDEを開き、「work」ディレクトリに移動してから「Python3」を選択し、以下のコードを貼り付けます。
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)
トークンはマイページのAPIアクセス設定(要ログイン)から取得してください。
上部の三角形アイコンをクリックしてコードを実行すると、指定した範囲の位置情報データが返ってきます。
取得できる位置情報データ
begin_time | 集計開始時刻(世界標準時) |
end_time | 集計終了時刻(世界標準時) |
mesh | 集計範囲の地域メッシュコード(4分の1地域メッシュ) |
count | 人数 ※ブログウォッチャー社が計測した数値であり、実際のメッシュ内の総数を示すものではありません。 |
サンプルコードでは、2017年4月1日12時から13時の新宿西口付近のデータを取得しています。
結果より抜粋
{
'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の間(世界標準時)の値です。データは日本時間と9時間ずれた世界標準時で返ってくることに注意してください。
meshは地域メッシュコードを表します
地域メッシュコードとは、日本工業規格で定められた区域を識別するコードのことで、このAPIでは4分の1地域メッシュ区分で値が返却されます。
地域メッシュについて詳しくはこちらを参考にしてください。
2. 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時間毎に取得しています。
では取得したデータをグラフ化してみましょう。
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つのグラフを単純に見比べるだけでも、一般的な商業施設が集まる銀座は昼から夕方にかけて人が集まるのに対し、市場である築地は朝から昼にかけて人が集まっており、地域性によりピーク時間が異なることがわかります。
3. 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
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')
人数が多い日が飛び飛びで存在していますが、調べてみると東京ヤクルトスワローズのホーム戦が4/1 – 4/2、4/12 – 4/13、4/21 – 4/23、4/28 – 4/30と行われており、グラフの尖った部分の日付と一致しています(他にも東京六大学の試合や東京都高校野球の試合が開催された日に小山が立っています)。
東京ヤクルトスワローズ 試合日程・結果 2017年4月
データをうまく加工することで、以下のように3次元プロットも可能です。ぜひ挑戦してみてください。
2017年4月1日から7日にかけての東京ディズニーランド、ディズニーシー滞在人数
(x, y)=(3, 2)近辺がランドで、(x, y)=(6, 3)近辺がシーです。
以上が、TellusのJupyter Labを使って位置情報データ「Profile Passport」を取得する方法でした。
滞在人数は、他のデータと組み合わせたり、衛星画像を解析する際の補正情報として利用できます。また人の動きをグラフとして眺めるだけでも得られる気づきはたくさんあります。
東京以外の地域のデータも今後公開していく予定ですので、楽しみにお待ちください。