Python
AWS
matplotlib
kibana
meraki

Meraki WiFi 位置情報の活用シーン

はじめに

以下2つの記事は Meraki Scanning API に関して、設定手順を中心にまとめています:

本記事はこれらの補足として、もう少しイメージが付くよう活用シーン付きで基本的な事柄も交えながら説明を試みます。

活用シーン

Meraki WiFi の活用シーンを小売店と想定します。Meraki WiFi はもともと次のような用途に向いています。

  • 店舗で WiFi を使えるようにしたい
  • 用途は業務用・お客様用の両方に使いたい
  • ビデオ視聴も可能な高速アクセスが必要
  • 店舗数は一店~数万店
  • 専任管理者がいないのでできるだけ簡単に運用したい
  • WiFi 位置情報を活用したい

Meraki WiFi の説明

そもそも Meraki WiFi とは?

Meraki WiFi はクラウド管理型 WiFi サービスです。

一般に、クラウドとは皆さんご存知の通り、データの保存や処理を手元の端末で行うのではなくインターネットを通じて「向こう側」に保存・処理する手法を指します。ところが、中には「向こう側」では不都合が出るサービスもあります。例えばリアルタイム処理が必要で遅延が問題となる場合には「こちら側」で処理できるよう機器を置くといいかもしれません。

WiFi も「向こう側」で全てを行うことはできません。WiFi 電波は仕様上 30メートルほどしか飛びませんので例えば東京タワーから送信しても「こちら側」の端末まで届きません。そこで Meraki アクセスポイント(AP) を「こちら側=店舗」に置くことになります。

AP がこちらにある以外は通常のクラウドサービスと同じ使い勝手で設定や監視ができるため、従来の WiFi AP を買ってきて個々に設定・設置する方法に比べると、特に多店舗では工数が圧倒的に少なくなるメリットがあります。

写真1:Meraki AP

image.png

クラウドへは Web ブラウザ経由でアクセスします。仮に複雑な機能を使ってもクラウド上に設定が残りますので、故障などで AP を交換した場合に一から再設定する必要はありません。また、数万 AP に対して一斉に設定変更を行うこともできます。

イメージ1:Meraki ダッシュボード(日本語対応済)
image.png

WiFi 端末の位置情報について(Meraki ダッシュボード)

スマホ等の WiFi 端末は使っていなくても(WiFi がオンになっていれば)プローブリクエストを定期的に送信します。送信間隔は機器の種類や状態によって異なります。

スマホの状態(iOS、アンドロイド等) プローブリクエストの間隔
スリープ(スクリーンオフ) 1分に1回程度
スリープ(スクリーンオン) 10-15回/分
APにアソシエート アプリケーションに大きく依存

WiFi 端末の送信するプローブリクエストを Meraki AP が受信すると、その時刻を SeenTime として記録します。また、プローブリクエストから端末の位置を算出する機能を持ちます。

WiFi 端末の識別には MACアドレスが使われますが、プライバシーの問題もあるため Meraki クラウドは一切の MAC アドレス情報を保存せず、そのハッシュ値のみを保存しています。

これらデータを利用して生成された端末位置情報ヒートマップを Meraki ダッシュボード(標準の管理インターフェイス)で見ることができます。

イメージ2:端末位置情報ヒートマップ(青はアソシエートした端末、灰色はアソシエートしていない端末、風船アイコンはAP)
image.png

また、データ解析レポートも Meraki ダッシュボードで見ることができます。

イメージ3:データ解析レポート
image.png

グラフは上から順に以下の意味を持っています:

  • 一つ目:近くを通っただけの人(Passersby)、訪問した人(Visitors)、接続して使った人(Connected)の割合
  • 二つ目:滞在時間毎の割合
  • 三つ目:訪問頻度の割合

データ解析レポートでは次のような比較が可能です。マーケティング的な分析に使えそうです。

  • 一店舗内のデータを異なる期間で比較(今週と先週)
  • 複数店舗間のデータを同一期間で比較(A店とB店、A店と全店の平均、A店とA~D店の平均、A~D店の平均と全店の平均)

以上は標準の Meraki ダッシュボードで利用可能です。

Scanning API の活用方法

端末位置情報を保持するには?

Meraki クラウドは上述のレポート提供を目的として WiFi 端末の位置情報を利用していますが、「個々の端末の時系列の位置情報」を保存している訳ではありません。保存したいと思った場合には Meraki クラウドから Scanning API を経由して取得可能です。ただし、保存用サーバを準備する必要があります。

サーバの準備が面倒であれば、例えば AWS の API Gateway/Lambda/DynamoDB を組み合わせて使うことでサーバレスにて比較的簡単に実現できます。手順はこちらの記事をご参照下さい(データ量は多くなり得るのでご注意下さい)。

DynamoDB は NoSQL データベースで可視化はあまり得意ではありません。可視化には同じく AWS の Elasticsearch service/kibana が利用できます。手順はこちらの記事をご参照ください。

端末位置情報から来店の有無を確認する

多くの小売店ではポイントカードを導入しており、お客様毎の購買履歴をデータとして蓄積しているかもしれません。ポイントカードは基本的に購入時のみ使うので、お客様が何も購入せずに店舗を去った場合には履歴が残りません。

それに対し、WiFi 位置情報はお客様が来店すれば(WiFi がオンになっている端末を持っている前提)データが残るため、これまでに扱えなかったデータの分析ができるようになる可能性があります。例えば、来店に対する購入頻度や、商品入替え・欠品による機会損失のより正確な額が求められるかもしれません。

イメージ4:既存お客様購買履歴とWiFi位置情報をマッピングした例。Meraki が提供する機能ではなくあくまでアイデアです。
image.png

※ イメージ4を実現するには、MACアドレスと個人情報の紐づけを何らかの方法で行う必要もあります

もっとも、お客様にとって来店記録が残ること自体気持ち良いものではなく、個人情報保護法を遵守しながらプライバシーを慎重に扱う必要があります(オプトイン・オプトアウト、保存データのハッシュ化等)。お客様にとって不利益が無く、新しい顧客体験を提供できることが何より重要かもしれません。技術の領域を越えますのでこの議論はここまでにしておきたいと思います。

最後に、MAC アドレス毎の SeenTime (AP が端末のプローブリクエストを受信した時刻)を可視化したグラフを作ってみました。Meraki の位置情報にご興味持たれた方は、データ活用に使えそうか眺めて頂けると幸いです。

DynamoDB 上のデータを CSV でファイルへ出力し、matplotlib で読み込んで描画しました。

イメージ5:MACアドレス毎の SeenTime (MACアドレスは左側をちょん切ってます)
image.png

イメージ5のコード
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import pylab
from datetime import datetime as dt

# グラフ表示する MACアドレスの数を指定
cmac_num4graph = 50

# DynamoDB から取得した CSV ファイルの読込み
df = pd.read_csv("cmxdata.csv", parse_dates = ['seenString (S)'])

# MACアドレスの一覧作成
cmac_index = set(df['clientMac (S)'])

# MACアドレスの一覧作成(グラフ表示用)
cmac_index = list(cmac_index)[:cmac_num4graph]

# CSV ファイルから 'clientMac (S)' と 'seenString (S)' のみ抜き出したデータフレーム StringMac を作成
StringMac = pd.concat([df['clientMac (S)'], df['seenString (S)']], axis = 1)

# グラフ描画用のデータフレーム result_df を作成
result_df = pd.DataFrame()
for mac in cmac_index:
    seenString = StringMac[StringMac['clientMac (S)'] == mac]['seenString (S)']
    seenString = pd.Series(seenString, name = mac)
    df_seenString = seenString.to_frame()
    result_df = pd.concat([result_df, seenString], axis = 1)

# グラフを描画
pylab.figure(figsize=(15, 8))
xmin = dt(2017,12,17,7,22,0)
xmax = dt(2017,12,17,7,33,0)
for (y, mac) in enumerate(cmac_index):
    m = result_df[mac].dropna()
    y = np.linspace(y, y, len(m))
    result_df[mac].dropna()
    plt.scatter(m.tolist(), y)

plt.grid(True)
plt.xlim(xmin,xmax)
plt.yticks(range(0, cmac_num4graph, 1), cmac_index, fontsize = 8)
plt.show()