目次


Spark と Bluemix を使用して位置データをクレンジングしてから視覚化する

屋内位置情報検出プラットフォームの精度を向上させる

Comments

この記事では、屋内位置情報検出プラットフォームの精度を向上させるために、IBM Presence Insights チームがどのように位置データ平滑化アルゴリズムを実装したかについて紹介します。なぜ特定のテクノロジーを選んだのか、そしてデータの処理と視覚化の際に直面した問題についても説明します。さらに、Bluemix 上の Spark で独自のノートブック・インスタンスを作成し、Scala と Spark の両方を使用してデータを視覚化するための簡潔なチュートリアルも含んでいます。データ平滑化アルゴリズムの高度な知識を身に付けて、リアルタイム・データを処理する際に発揮される Spark の利点を学び、独自の Spark ノートブック・インスタンスをセットアップしてそれらの利点を実際に確認できるようになってください。

屋内の軌跡をどのようにして平滑化するか

来年の屋内位置情報市場には、急激な成長が見込まれてはいるものの、この新しい分野を悩ませている問題があります。それは、既存のあらゆる屋内位置情報検出プラットフォームには、位置決めの精度に限界があることです。この問題に対処すべく、IBM Haifa Research Lab では Wi-Fi ベースの屋内位置決めデータのクレンジングを目的とした、一連のノイズ低減およびデータ平滑化アルゴリズムを開発しました。これらのアルゴリズムを開発する際に使用した主な手法は、以下の 2 つです。

  • ロングジャンプ排除
    フロアーやエリア全体での動きの平均速度を推測することで、その特定の時間枠内では発生するはずのないイベントを排除することが可能になります。つまり、ロングジャンプ排除とは、無効とみなされるサンプルを特定して除外するために使用する手法です。
  • ウィンドウイングを使用した移動平均
    データ平滑化アルゴリズムでは、時間のスナップショット (例えば、60 秒) に基づく線形加重移動平均を使用しました。位置決めは、一定の時間枠内に受信した有効なサンプルの平均を取って行われます。指数時間減衰関数を使用したこの手法は、指数加重移動平均 (EWMA) と呼ばれています。

屋内位置データ平滑化を試みるときに私たちが使用した重みは、時間と 受信信号強度インジケーター (RSSI) です。図 1 に、動的デバイスのサンプルを描画したグラフを示します。平滑化アルゴリズムによって修正する前は (a)、修正した後は (b) のようになっています。

図 1. 平滑化する前と平滑化した後
星のようにギザギザのグラフと、数字の 9 のように平滑化されたグラフを示す図
星のようにギザギザのグラフと、数字の 9 のように平滑化されたグラフを示す図

Spark ストリーミングが最良の選択肢となるのはなぜなのか

方法論としてなぜ Spark ストリーミングを採用したのかというと、これが完璧なデータ・ストリーミングおよびアナリティクス候補であることがわかったからです。Spark によって、大量のリアルタイム位置データ・ストリームを受信して平滑化変換処理を行い、出力の精度を向上させることができました。ロングジャンプ排除およびウィンドウイングを使用した移動平均の両方の手法を取り込むことができて、素晴らしい結果になりました。私たちは屋内位置情報検出プラットフォーム内での位置決め精度の限界という問題に対する実行可能なソリューションを作り上げたのです。

以下に、私たちに Spark ストリーミングの採用を確信させた Spark の機能と特徴について説明します。

  • 大規模なデータ処理

    Apache Spark はオープンソースのクラスター型コンピューティング・システムであり、複数のノードに分散された複雑なアナリティクス・プロセスを単純な API を使用して操作できるようになっています。Spark の API は Scala、Java、Python、R、および SQL の各言語で用意されています。さらに、Spark は分散データ・セットのインメモリー・キャッシングをサポートしているため、重複するジョブをスキップしてデータ変換を高速化することができます。

  • RDD (Resilient Distributed Dataset)
    • 耐障害性を持ち、再構築可能で、不変のデータ・セットの集まりです。
    • RDD の作成は確定的であり、反復可能です。
    • RDD を変換したものはその RDD の系譜 (lineage) になります。
    • 並列処理できるようにノード全体で区分化されます。
    • RDD の API は、マッピング、フィルター、集約、結合などの粒度の粗い変換処理に制限されています。
  • Spark SQL / DataFrames
    • 構造化データと非構造化データ (JSON を含む) のクエリーをサポートしています。
    • RDD にスキーマを加えた DataFrame を使用します。
    • 自動クエリー計画により、コアとなる RDD API のファサードとして SQL クエリーをサポートします。
  • Spark ストリーミング
    • 離散ストリーム (DStreams) では、メッセージ・キューなどのデータ・ストリームを取り込み、一定の間隔で一連の RDD を出力します。
    • 変換処理の演算子により、派生 DStreams を生成します。
    • ノードの障害や孤立に対する回復力があります。
    • 通常の RDD と同じ処理をサポートします。
    • 傾向分析などのタイムスキュー処理をサポートしています。
    • ノイズ除去などのウィンドウイング処理をサポートしています。
    • キーによって状態を管理します。
  • Kafka 統合
    • Kafka データ・ストリームはキー別に区分化されて、マシンのクラスターに分散されます。
    • Kafka により、位置イベントをフロアー別に区分化することが可能になります。
      • 1 秒あたりに見込まれるデバイス位置イベントは、何万件にも上ります。
      • フロアー構成の変更イベントはめったに発生しないことが見込まれます。
    • Kafka を利用することで、位置イベントを、対応するフロアーがキャッシュされている Spark ノードに区分化できます。

リアルタイム位置情報分析において Spark の利点が持つ意味

リアルタイムの位置情報分析に対して上記に挙げた Spark の利点がどのように当てはまるかを、具体的な適用例と合わせて以下にまとめます。

  • リアルタイム・データのスケーラブルな取り込みと変換処理
  • 位置イベントとフロアー構成キャッシュのスケーラブルな結合
    • フェンスによって囲まれたデバイス位置と突き合わせることができます。
    • 顧客定義の通知ルールと突き合わせることができます。
  • ウィンドウイングを使用した変換処理のサポート
    • 信号強度に基づき、一定の時間枠内の重複するイベントを削減できます。
    • フェンスごとに毎分のエントリー数を出力できます。
  • キーによる状態管理のサポート
    • デバイスごとにフェンスへの入出イベントと滞在イベントを追跡および出力できます。
    • アクティブ・デバイスごとに直近 5 件のイベントを追跡し、指数加重移動平均 (EWMA) アルゴリズムを使用して x,y を平滑化できます。
    • 同じビーコンから 3 回連続してイベントを受信するまで、精度しきい値を超える IBeacon イベントをブロックできます。

Spark ストリーミングと Spark SQL を使用した JSON 往復変換

さまざまな関数にそれぞれ異なる制約事項があることから、非構造化 JSON ペイロードの処理は難しくなりがちです。場合によっては、開発時にスキーマをハード・コーディングしなければならないこともあります。このセクションでは、Spark ストリーミングと Spark SQL を使用して JSON の読み取り/書き込みを行う際の秘訣について説明します。

JSON 配列の列を SQL モジュール内の個々のデータ行にマッピングするには、いくつかの方法があります。配列内のデータ・スキーマが前もってわからなければ、インライン SQL explode メソッドが唯一のマッピング方法になりそうです。

  • 配列に含まれる JSON の構造が既知であれば、DataFrame.explode API を使用してカスタム explode 動作を定義できます。
  • 構造がわからない場合、あるいはカスタム動作の必要がない場合は、代わりに SQL explode メソッドを使用できます。例えば、列データが不明なスキーマの配列だとしたら、以下のメソッドを作成できます。myDataFrame.select( $"floorKey", explode($"data").alias("datum"), $"z")

Spark ストリーミング内で Spark SQL モジュールを使用する際に注意しなければならない重要な点は、参照されている列が現在のミニバッチに 1 つも出現しないと、コマンドが失敗することです。この事態は、ミニバッチのいずれかが空である場合や、参照されている列がペイロード内で任意選択となっている場合に発生します。この問題の回避策の 1 つは、各ミニバッチにプレース・ホルダー行を結合して、明示的に参照するすべての列をその行に格納する一方、この偽のデータの存在が適切でないすべてのセットからプレース・ホルダー行をフィルター処理によって除外することです。このようにすると、すべてのミニバッチに、参照されている列のそれぞれを格納する行が少なくとも 1 つ含まれることになります。

DataFrames を変換して JSON に戻す際は、以下のコツに留意してください。

  • struct SQL 関数を使用すると、複数の列を結合して 1 つの新しいオブジェクトにすることができます。
  • 従来の RDD を DataFrames に変換するには、SQLContext.createDataFrame メソッドを RDD と行のマッピングに適用して、一致するスキーマを指定します。

新しいスキーマを構成する際は、元の JSON パーサーで生成された型を再利用できます (例: StructField("data", ArrayType(otherDataFrame.schema.apply("data").dataType))。個々のミニバッチのスキーマが実行時に変化する場合は、この方法が役立ちます。

データの視覚化

このアルゴリズムを調査するには、平滑化プロセスの前と後のデータを視覚化するのが何よりも有効な方法でしょう。Wi-Fi センサーから受信した未処理のデータ・ポイントを、加重位置決めアルゴリズムの出力データと比較すると、違いがわかります。図 2 に、未処理の位置データのグラフを示します。

図 2. 未処理の位置データ
未処理の位置データのグラフ
未処理の位置データのグラフ

図 3 に、平滑化後の位置データのグラフを示します。

図 3. 平滑化された位置データ
平滑化された位置データのグラフ
平滑化された位置データのグラフ

上記の出力内では、グラフの線が滑らかになっています。データがクレンジングされていることを検証しましょう。それには、標準偏差が減っていることを確認すれば良いだけです。実際にクレンジングされたデータ・ポイントの数を確認するには正確な基準データ・セットと比較する必要があります。しかし、この点は、多くの屋内位置決めプラットフォームの直面している問題です。実際の Wi-Fi データを使用しているときに、個人が実際にいる x,y 位置を検証する有効な方法がないのです。

ノートブックの選択

データ視覚化に対応するテクノロジーはさまざまにありますが、Spark に関しては、ノートブックを使用することが妥当な方法になります。分析に関連するすべてのことを 1 か所にまとめられるノートブックは、あらゆる類のデータ分析に役立つ優れたツールです。ノートブックを使用することで、コード、出力、メモを整理するオーバーヘッドが減るだけでなく、データ操作がインラインで視覚化されます。さらに、プログラム全体を再実行するのではなく、その一部だけを再実行できるので、大規模なデータ・セットを使った実験がしやすくなります。

ノートブックを使用したくないとしたら、視覚化フレームワークを使用して Web アプリケーションを開発し、そのアプリケーションを介してデータをストリーミングするという方法もあります。私たちのグラフ描画の取り組みでは、平滑化する前と後のデータをテストして分析するために迅速に可視化することに重点を置いていたので、単純さを重視してノートブックを使用することにしました。

Apache Zeppelin、Bluemix 上の Spark、Spark ノートブックをはじめとする多くのオープンソース・ノートブックには、Spark インタープリターとグラフ描画用ライブラリーが組み込まれています。最も用途が広く、使いやすいノートブックは Spark Notebook ですが、私たちが推奨するのは、他のサービスに簡単に統合できる Bluemix 上の Spark です。

Apache Zeppelin ノートブック

ノートブックを試しに使ってみる際に、私たちが最初に選んだのは Apache Zeppelin です。Apache Zeppelin は Scala インタープリターと Python Spark インタープリターの両方をサポートしており、独自の言語のバックエンドを追加することもできます。けれどもさらに重要なことに、Zeppelin に組み込まれているデータ視覚化では、Spark の SQLContext の他にも、さまざまなデータ・セットが認識されます。一方、欠点としては、組み込み可視化機能であることから、グラフ描画に少々の限界を感じます。

Spark ノートブック

Spark ノートブックは多種多様なフレームワークと相性が良く、膨大なデータ・セットを分析して情報を引き出すにはどのようにするのかをデモする多数のサンプルも用意されています。現在サポートされている言語は Scala だけですが、各種のウィジェットを提供する複数のフレームワークが実装されています。JavaScript をコードに総合して、そうしないとアクセスできない D3.js や Rickshaw などの視覚化フレームワークにアクセスすることもできます。Spark ノートブックには、インライン視覚化用にほぼすべての Scala グラフ描画用ライブラリーもインストールされています。多種多様なインストール・オプションを誇る Spark ノートブックでは、Scala、Spark、および Hadoop バージョンを個別に変更することができます。私たちは Spark ノートブックを強くお勧めします。

Bluemix 上の Spark ノートブック

Bluemix 上の Spark は、有名な Jupyter ノートブック (旧称 Ipython ノートブック) 上で動作します。Bluemix 上の Spark には、Scala と Python 両方のサポートを含め、その前身のノートブックに備わっていたすべてのインライン機能が引き継がれています。このノートブックの最大の利点は、MessageHub や Object Storage などの他の Bluemix サービスに直接アクセスできるため、規模の大きいプロジェクトを統合しやすいことです。

欠点としては、Bluemix アカウントへのアクセスが必要なことが挙げられますが、30 日間無償の Bluemix トライアル・アカウントを利用できます。学校関係者の場合は、現在 Bluemix アカウントを 1 年間無料で利用でき、学生は 6 カ月間無料で利用できます。さらに、誰でも購入することができる developerWorks Premium には現在、1 年間の Bluemix アクセスに加え、カンファレンスの割引などのさまざまな特典が含まれています。

サンプル・チュートリアルでは、Bluemix 上の Spark ノートブックを使用します。

データのグラフ描画

私たちが試してみる機会があった各種のグラフ描画用ライブラリーについて詳細を説明することはしませんが、いくつかの選択肢を紹介しておきます。Scala の場合は、WISPBokehBreeze-vizBrunel を使用できます。Python の場合は、評判の高い Matplotlib を使用できます。Bluemix 上の Spark (別名 Jupyter) には、Scala の Brunel に代わるインライン機能が備わっています。また、Python の Matplotlib もサポートしています。

サンプル・チュートリアルを実行する

このセクションでは、加重位置決め平滑化アルゴリズムで処理した出力データを取り、そのデータを Bluemix 上の Spark 上で Python を使用して描画するにはどのようにするのかを説明します。ここで説明する手順は、Scala を使用する場合にも当てはまりますが、当然、コーディングには多少の違いがあります。Python を使用する手順と Scala を使用する手順は、両方ともノートブック自体に含まれています。

Bluemix 上の Spark 上で Python を使用してこのサンプルを実行するには、以下のものが必要です。

  1. Bluemix アカウント。必要に応じて、無償のトライアル・アカウントを作成してください。
  2. github から入手できるサンプル・データ (JSON として保存)

ステップ 1. Spark サービスを開始して実行する

  1. Bluemix にログインし、Bluemix カタログに含まれる Apache Spark サービス (図 4 を参照) にナビゲートします。
図 4. 平滑化された位置データ
Bluemix 上の Apache Spark サービスのスクリーン・キャプチャー
Bluemix 上の Apache Spark サービスのスクリーン・キャプチャー
  1. 「Create (作成)」 > 「Notebooks (ノートブック)」の順にクリックします。
  2. 「Object Storage (オブジェクト・ストレージ)」タブをクリックします。
  3. 「Add Object Storage (オブジェクト・ストレージの追加)」ボタンをクリックします。追加するオブジェクト・ストレージにはデフォルトのコンテナー名「notebooks」を使用します。
図 5. Spark インスタンスへのオブジェクト・ストレージの追加
「Add Object Storage (オブジェクト・ストレージの追加)」ボタンを示すスクリーン・キャプチャー
「Add Object Storage (オブジェクト・ストレージの追加)」ボタンを示すスクリーン・キャプチャー
  1. 「Create (作成)」をクリックします。
  2. 「My Notebooks (マイ・ノートブック)」タブをクリックし、「New Notebook (新規ノートブック)」をクリックします。
  3. 「From URL (URL から)」タブをクリックし、以下の URL を入力して、Matplotlib と一緒に Python 用サンプル・ノートブックをダウンロードします。https://raw.githubusercontent.com/reicruz/bluemix-spark-viz/master/python-viz.ipynb

    注: Scala 上で Brunel を使用する場合は、https://raw.githubusercontent.com/reicruz/bluemix-spark-viz/master/scala-viz.ipynb からサンプル・ノートブックをダウンロードして以下の手順に従います。ただし、この記事で説明する手順は Python を対象としています。

ステップ 2. サンプル・データをロードする

  1. ノートブックが起動したら、右側にあるパレット上で「Data Source (データ・ソース)」タブをクリックし、「Add Source (ソースの追加)」をクリックします (図 6 を参照)。
図 6. Spark ノートブックへのサンプル・データの追加
「Add Source (ソースの追加)」ボタンを示すスクリーン・キャプチャー
  1. サンプル・データをダウンロードした場所を参照し (右クリックして「Save As... (名前を付けて保存)」)、データ・ソースを追加します。

ステップ 3. 個々のイベントを分離する

  1. 以下に示すように、explode を使用してイベントごとの行を作成します。
from pyspark.sql.functions import explode 

# Use explode to create rows for each individual device event
df = json.select("sites", explode("data").alias("data")) 

devicesDF = df.select( 
		df.data.original.device_descriptor.alias("device"), 
		df.sites.floors.properties.z.getItem(0).alias("z"), 
		"data.original.x", 
		"data.original.y", 
		"data.smooth_x", 
		"data.smooth_y")
  1. devicesDF.registerTempTable("devices") と入力して、イベントを SQL テーブルに登録します。
  2. 以下に示すように、デバイスとフロアーを選択します。
    plot_data = sqlContext.sql("SELECT * FROM devices WHERE device='device1' AND z=0").collect()

ステップ 4. matplotlib を使用してグラフを描画する

  1. 以下のコードを使用して、データを収集します。
    x = []
    y = []
    smooth_x = []
    smooth_y = []            
    for data in plot_data:
        x.append(data.x)
        y.append(data.y)
        smooth_x.append(data.smooth_x)
        smooth_y.append(data.smooth_y)
  2. 以下のコードを使用して、未処理のデータを描画します。
    %matplotlib inline
    import matplotlib
    import numpy as np
    import matplotlib.pyplot as plt
    
    area = np.pi * 15
    plt.scatter(x, y, s=area, c="blue")
    plt.title('Raw Data Points')
    plt.xlabel('x-coordinates')
    plt.ylabel('y-coordinates')
    plt.show()
  3. 以下のコードを使用して、平滑化されたデータを描画します。
    plt.scatter(smooth_x, smooth_y, s=area, c="red")
    plt.title('Smooth Data Points')
    plt.xlabel('x-coordinates')
    plt.ylabel('y-coordinates')
    plt.show()
  4. これで完了です!結果を比較して、このシステムによってどれほど素晴らしく位置データが円滑化されたか確かめてください。

まとめ

この記事では、屋内位置検出テクノロジーについて解説し、それらのテクノロジーをどのようにして適用するのかを説明しました。データ・ストリーミングおよびアナリティクスには Spark が最適です。Spark は、大幅なオーバーヘッドを伴わずに膨大な量のデータを操作するために必要なツールを備えています。他の結果をもたらすには、恐れずに各種のデータ変換を試してください。私たちの手法にも多くの試行錯誤が必要でしたが、試行錯誤の末解決できました。屋内位置情報検出プラットフォーム内での精度の限界という問題に対して、私たちが至った解決策を共有するために、この記事を作成しました。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=ビジネス・アナリティクス
ArticleID=1040241
ArticleTitle=Spark と Bluemix を使用して位置データをクレンジングしてから視覚化する
publish-date=12082016