次の方法で共有



April 2016

Volume 31 Number 4

ビッグ データ - Spark でのデータ処理と機械学習

Eugene Chuvyrov

いきなり、クイズです。「Microsoft Dryad プロジェクトからその大部分を流用し、2015 年に最も普及したオープン ソース プロジェクトで、100 TB のデータをわずか 23 分で並べ替えるというデータ処理の記録も打ち立てたフレームワークの名前は何というでしょう」。答えは、「Apache Spark」です。

今回は、Spark の速度と人気について、および現状のビッグ データ処理と分析の分野で Spark が他をリードする存在になっている理由を紹介します。Microsoft Azure サブスクリプションを使用して、機械学習 (ML) の問題を Spark によって解決する例を取り上げ、ソフトウェア エンジニアリングからデータ サイエンスの世界への小さな一歩を踏み出します。ですが、データ分析と ML の話に進む前に、Spark フレームワークのさまざまなコンポーネントについて、および Spark と Azure の関係について少し説明しておくことにします。

Spark のコンポーネント

Spark フレームワークの価値は、市販のコンピューターのクラスターで、ビッグ データのワークロードを処理できる点にあります。Spark Core は、このワークロードの処理を可能にし、データ クエリをパッケージ化して、それをクラスター全体にシームレスに分散するエンジンです。Spark Core 以外にもいくつかコンポーネントがあり、各コンポーネントがそれぞれ特定の問題領域に対応します。大きなデータ ワークロードを操作し、レポートを作成するだけならば、このような特定問題領域向けのコンポーネントはまったく必要ありません。と言いながら、今回使用するのは Spark MLLib です。このコンポーネントを使用して、手書きの数字をかなり正確に「推測」できるようにする ML モデルをビルドします (詳しくは後ほど)。Spark フレームワークの他のコンポーネントには、ストリーミング データの処理を可能にする Spark Streaming、グラフの操作と著名なページランク アルゴリズムの計算を可能にする GraphX、分散データの SQL クエリの実行を可能にする Spark SQL などがあります。

Azure での Spark の実行

Spark を試す方法はかなりたくさんあり、databricks.com (Spark を開発し強化を続けている企業、英語) のマネージ サービスを使用する方法、Docker コンテナーをプロビジョニングしてプレインストールされた Spark イメージを Docker Hub から取得する方法、GitHub (github.com/apache/spark、英語) からソース コード リポジトリ全体を入手し自身でビルドする方法などがあります。ただし、今回のテーマは Azure なので、Azure に Spark クラスターを作成する方法を示すことになります。この方法が非常に興味深い理由は、Azure では Azure のコンピューティング クラスターにデプロイされた Spark に対してエンタープライズレベルの保証が与えられるためです。Azure はすべての Spark クラスターに対して 99.9% の SLA をマイクロソフトがサポートし、年中無休のエンタープライズ サポートとクラスター監視も提供します。これらの保証に加えて、クラスターのデプロイが容易なことと、Build 2016 カンファレンスで Spark や Azure に関する情報が豊富に提供されたことが、Microsoft Cloud を優れたビッグ データ処理環境にしています。

妖精の粉

今日、データ科学者の間で Spark が急速に普及した理由は 2 つあります。1 つは高速なこと、もう 1 つはこのフレームワークでのプログラミングの容易さです。まず、Spark がそれ以前のフレームワークよりもはるかに高速になっている理由から見ていきます。

Spark の前身となるのが Hadoop MapReduce です。Hadoop MapReduce は、2005 年に Doug Cutting と Mike Cafarella が Apache Hadoop プロジェクトを共同設立して以来、ビッグ データ分析の分野の主力として活躍していました。Hadoop はクラスター上でのバッチ分析処理の実行に適していましたが、柔軟性がきわめて低いことが難点でした。Map 操作と Reduce 操作は連携します。つまり、Map タスクが完了してから Reduce タスクが完了します。タスクが複雑になれば、複数の Map ステップと複数の Reduce ステップを組み合わせなければなりません。また、すべてのタスクを Map 操作から Reduce 操作につながるように分解しなければなりません。このようにシーケンシャルな操作を実行するには非常に時間がかかり、プログラミングは退屈になります。端的に言えば、これはリアルタイム分析ではありませんでした。

これとは対照的に、Spark フレームワークは、手元にあるデータ分析タスクにインテリジェンスを持ち込みます。Spark フレームワークは、タスクをスケジューリングする前にタスク実行の有向非巡回グラフ (DAG: Directed Acyclic Graph) を作成します。考え方は、SQL Server がデータの取得や操作を実行する前にクエリ実行プランを作成するのによく似ています。DAG はデータ上で実行予定の変換についての情報を提供し、Spark はそれら多くの変換を適切に 1 つのステージに組み合わせてから、すべての変換を一度に実行します。このアイデアは、Microsoft Research がプロジェクト Dryad で初めて考案したものです。

また、Spark は、弾性分散データセット (RDD: Resilient Distributed Datasets) という構造を使ってメモリ内にデータをインテリジェントに永続化し、DAG 間でデータを共有します。RDD については後ほど説明します。このように DAG 間でデータを共有して最適化することで、それを行わない場合よりも高速にジョブが完了します。図 1 は、データ科学分野の「hello world」(特定のテキスト ファイルの単語数のカウント) についての DAG を示しています。ここでは、いくつかの操作 (テキスト ファイルの読み取り、flatMap、および Map) を 1 つのステージに組み合わせ、高速に実行できるようにしています。以下のコードは、単語カウントを実行する実際の Scala コード (Spark は Scala で記述) を示しています。Scala コードを今まで見たことがなくても、Spark に単語カウントを実装する方法を簡単に理解できます。

val wordCounts = textFile.flatMap(line => line.split(" ")).map(word => (word,1))  
  .reduceByKey((a, b) => a + b)

単語カウント用有向非巡回グラフ (DAG)
図 1 単語カウント用有向非巡回グラフ (DAG)

Spark が広く普及したもう 1 つの理由は、そのプログラミング モデルにあります。Spark (Scala コード) での単語カウント実装は、Hadoop MapReduce での実装よりもはるかにシンプルです。Spark アプリケーションは、Scala 以外に Java や Python でも作成できます。ここでは Python を使用します。Spark 以前、データ科学者やプログラマは、Hadoop MapReduce を使用するために、複雑なタスクを一連の Map 操作と Reduce 操作に分解するという不自然なパラダイムを使用しなければなりませんでした。Spark では、.NET 開発者が LINQ とラムダ関数を扱うように、関数型プログラミングのアプローチを使用してデータの変換や分析を実行できます。

この後、Spark のプログラミング モデルがどれほど簡単で強力かを示します。しかし、データセットの大小を問わず等しく機能する、優れた関数型コードを記述する前に、コンピューターの分散クラスターを作成する必要があります。このクラスターには Spark の必要なコンポーネントをすべてインストールし、クラスターに送信するプログラミング タスクが受け入れられるように準備します。自身で Spark クラスターを作成および構成しなければならないとしたら、きわめて困難な作業になりますが、さいわい、Microsoft Cloud を利用すれば、数回クリックするだけでプロビジョニングが完了します。ここからはこうしたプロビジョニングの方法を取り上げます。

Spark クラスターのデプロイ

ここで、Azure 上に HDInsight クラスターを作成します。「HDInsight」は、Hadoop テクノロジと Sparkテクノロジの両方を含む包括的な用語と考えてください。Hadoop HDInsight と Spark HDInsight は、どちらも Azure 上のビッグ データ マネージ サービスです。

Spark クラスターをプロビジョニングするには、Azure ポータル (portal.azure.com) にログオンし、[新規]、[データ + 分析]、[HDInsight]、[作成] の順にクリックします。HDInsight クラスターのプロパティを設定します。名前を指定し、クラスターの種類を Spark に、クラスターのオペレーティング システムを Linux に設定 (Spark は Linux で開発されているため) します。バージョンのフィールドは変更しないでそのままにします (図 2 参照)。クラスターにログオンするための資格情報、ストレージ アカウントとストレージ コンテナーの名前の指定など、残りの必須情報を入力します。その後、[作成] をクリックします。クラスターの作成プロセスは 15 ~ 30 分で完了します。

Azure での Spark クラスターの作成
図 2 Azure での Spark クラスターの作成

作成プロセスが完了すると、新しく作成した HDInsight クラスターを表すタイルが Azure ポータルに表示されます。いよいよ、コードに着手します。ですが、コードに着手する前に、Spark で利用可能なプログラミング環境と言語について確認しておきます。

Spark 環境でのプログラミングにはいくつか方法があります。直感的でわかりやすい最初のオプションは、spark-shell コマンドを使って Spark シェルにアクセスする方法 (bit.ly/1ON5Vy4、英語) です。この方法では、Spark クラスターのヘッド ノードで SSH セッションを確立し、REPL 式の手法で Scala プログラムを記述して、プログラミングの構成要素を 1 つずつ送信します (この文章が外国語で書かれているように思え不安な方は、オプション 3 にそのまま進んでください)。オプション 2 は、Spark で完成形の Scala アプリケーションを実行する方法 (bit.ly/1fqgZHY、英語) です。アプリケーションは spark-submit コマンドを使って送信します。オプション 3 は、Spark の上位で Jupyter Notebook (jupyter.org、英語) を使用する方法です。Jupyter プロジェクトについて簡単に説明すると、Jupyter Notebook とは、Web ベースのビジュアル インタラクティブ環境で、そこでデータ分析スクリプトを実行きるようになっています。データ分析を行うツールとして手頃なので、一度使えば、Spark のプログラミング ツールとしてお気に入りになること請け合いです。Azure HDInsight がクラスターの上位に Jupyter Notebook 環境をインストールするため、使い始めるのは簡単です。

Jupyter Notebook にアクセスするには、図 3 に示すように [クラスター ダッシュボード] でタイルをクリック後、スライドアウト ウィンドウで [Jupyter Notebook] タイルをクリックします。クラスター作成時に指定した資格情報を使用してログインし、Jupyter 環境が新しい Notebook の受け入れや古い Notebook の編集を行えるようになっているかどうかを確認します。ここで、右上隅の [New] をクリックして、[Python 2] を選択します。Python 2 を選択する理由は、Spark 自体は Scala で記述され、多くの Spark プログラミングは Scala で行われますが、Python ブリッジも Pyspark によって利用可能になっているためです。ところで、Scala と Python のどちらでコーディングするべきかについては白熱した議論が交わされています。どちらの言語にも明らかなメリットがあります。Scala はその潜在能力として高速ですが、Python は表現力が高く、データ科学で最も広く使用されている言語です (bit.ly/1WTSemP、英語)。これを踏まえて、Spark クラスターの上位でプログラミングする際は、表現力に富んでいながら簡潔な Python を使用します。Python は (R と共に) データ分析におけるお気に入りの言語なので、使い慣れた強力な Python ライブラリも利用できます。

クラスター ダッシュボードからの Azure HDInsight の Jupyter Notebook へのアクセス
図 3 クラスター ダッシュボードからの Azure HDInsight の Jupyter Notebook へのアクセス

ようやく、Jupyter Notebook で ML とデータ分析タスクに着手して実行する準備が整いました。

Spark による機械学習

Spark での機械学習 (ML) を説明するために、封筒の郵便番号のような手書き数字の認識という、ML では著名な問題の形式で「小さめの」データ例を使用します。今回のデータセットは決して大きくありませんが、このソリューションが優れているのは、データが 1000 倍に増えても、クラスターにコンピューターを追加すれば、妥当な時間内にデータ分析を完了できる点にあります。クラスターにコンピューターを追加しても、ここで示しているコードを変更する必要はありません。クラスター内の個別のコンピューターへのワークロードの分散は Spark フレームワークが担当します。使用するデータ ファイルは古典的なファイルで、多くの場合 MNIST データセットと呼ばれ、分析対象として利用できる 50,000 文字の手書き数字を含んでいます。さまざまな場所からオンラインで MNIST データセットを入手できますが、今回のデータには Kaggle の Web サイトから簡単にアクセスできます (bit.ly/1QJN20c、英語)。

ちなみに、kaggle.com についてよく知らない方のために説明すると、この企業は、世界中から約 500,000 人のデータ科学者が賞金や一流 ML 企業への入社のチャンスを争う、オンラインの ML コンテストを主催する企業です。筆者は Kaggle のコンテストに 5 回参加しましたが、競争心の強い人であれば、かなり病みつきになるような体験が可能です。Kaggle のサイト自体は Azure で運用されています。

少し時間をとって、train.csv の中身を理解してみます。ファイルの各行は、図 4 (拡大表示で示した図) で示すような手書き数字の画像 (28 ピクセル x 28 ピクセル) をピクセル単位に表現しています。最初の列は数字の実際の桁です。残りの列は 784 ピクセル (28x28) すべてを 0 ~ 255 のピクセル明度で表現した情報を含みます。

MNIST データセットで表現る数字「7」の拡大サンプル
図 4 MNIST データセットで表現る数字「7」の拡大サンプル

新しい Jupyter Notebook を開いて、以下のコードを最初のセルに貼り付けます。

from pyspark import SparkContext
from pyspark.mllib.regression import LabeledPoint
from pyspark.mllib.tree import RandomForest
import time
sc = SparkContext(appName="MNISTDigitsDT")
#TODO: provide your own path to the train.csv in the line(s) below, 
# you can use Azure Storage 
#Explorer to upload files into the cloud and to read their full path
fileNameTrain = 'wasb://datasets@chuvyrov.blob.core.windows.net/trainingsample.csv'
fileNameTest = 'wasb://datasets@chuvyrov.blob.core.windows.net/validationsample.csv'
mnist_train = sc.textFile(fileNameTrain)
mnist_test = sc.textFile(fileNameTest)

上記のコードは Spark で ML を実行するために必要なライブラリをインポートしてから、モデルのトレーニングとテストに使用するデータ ファイルの場所を指定しています (このデータ ファイルは、Microsoft Cloud の Spark から wasb:// 参照を使ってアクセスできるストレージ アカウントに置くようにします)。末尾の 2 行は、そのテキスト ファイルから RDD を作成する場所を指定しています。RDD とは分散データ構造で、Spark を支える隠れた存在です。しかし、プログラマやユーザーはその実装の複雑さをあまり意識することはありません。また、この RDD は遅延評価されて永続化されるため、RDD を再度使用する必要がある場合でも、再計算や再取得を必要としないですぐに利用できます。RDD を操作すると、DAG の生成と Spark クラスターでステージングされたタスクの実行がトリガーされます (これについては前半でも触れました)。

Jupyter のセル内で Shift キーを押しながら Enter キーを押し、先ほど貼り付けたコードを実行します。何も表示されなければ (つまり、エラー メッセージが表示されなければ) OK です。クエリと操作に利用できる RDD が用意されたことになります。この時点の RDD にはコンマ区切りテキストの行が複数含まれています。それは、MNIST データがそのようになっているためです。

次に、シンプルな関数を定義し、これらのテキスト行をカスタム LabeledPoint オブジェクトに変換します。このオブジェクトは、トレーニングと予測に使用する ML アルゴリズムに必要です。簡単に言うと、このオブジェクトには「機能」と「ラベル」を含みます。機能とは 1 つのデータ ポイントの特性でデータベース テーブルの列と考えればわかりやすくなります。ラベルとは、予測のために学習を試みている値です。この説明がわかりにくければ、MNIST train.csv ファイルを見てみると、理解できるようになると思います。train.csv の各行には、最初の列に 1 つの数字、それ以外のすべての列に 0 から 255 までの一連の数字が含まれています。最初の列が「ラベル」です。それは数字を予測する方法の学習を試みているためです。それ以外の列が「機能」で、まとめて「機能ベクトル」と呼びます。今回の機能は数字の画像内の各ピクセルのでデジタル化された強度で、0 は黒、255 は白を表し、その間にも多くの値があります。画像はすべて高さ 28 ピクセル、幅 28 ピクセルで、train.csv ファイルはピクセル強度を含む 784 個 (28 x 28 = 784) の列で構成されます。

以下の関数をコピーして、Jupiter Notebook の新しいセルに貼り付けます。

def parsePoint(line):
  #Parse a line of text into an MLlib LabeledPoint object
  values = line.split(',')
  values = [0 if e == '' else int(e) for e in values]
  return LabeledPoint(int(values[0]), values[1:])

Shift キーを押しながら Enter キーを押してコードを実行します。これで parsePoint が定義されました。この関数が Spark によって評価され、読み取ったデータセットで使用できるようになります。この関数はコンマ区切りのテキストを 1 行受け取り、個別の値に分割して、各値を LabeledPoint オブジェクトに変換します。

次に、そのオブジェクトを学習アルゴリズムに使用できるように、データに基本的な最適化を施します。残念ながら、学習アルゴリズムは今のところ、データのどの部分に予測値が含まれているかを理解できるほど洗練されていません。そこで、stackoverflow.com (英語) から拝借した手法を使用して、train.csv ファイルのヘッダーを読み飛ばしてから、結果の RDD の最初の行を出力して、それが想定した状態になっているかどうかを確認します。

#skip header
header = mnist_train.first() #extract header
mnist_train = mnist_train.filter(lambda x:x !=header) 
#filter out header using a lambda
print mnist_train.first()

これで .map (parsePoint) 演算子によって関数型プログラミングのアプローチを当てはめ、RDD を Spark の ML のアルゴリズムに対応する形式に変換する準備が整いました。原則的に、この変換は mnist_train RDD 内部のすべての行を解析し、その RDD を一連の LabeledPoint オブジェクトに変換します。

RDD と対話性: Spark の能力の中心

ここでは重要な問題をいくつか取り上げます。まず、コンピューターのクラスターに分散されるデータ構造 (RDD) を操作していますが、分散コンピューティングの複雑さはまったくといっていいほど意識することはありません。関数型の変換を RDD に当てはめると、Spark が、利用可能なコンピューターのクラスターでの全処理と面倒な作業を自動的に最適化します。

labeledPoints = mnist_train.map(parsePoint)
#Split the data into training and test sets (30% held out for testing)
(trainingData, testData) = labeledPoints.randomSplit([0.7, 0.3])
print mnist_train.first()

最後の行 (print ステートメント) は余分に思えますが、大規模データセットを対話形式でクエリする機能は非常に強力で、Spark 以前の大規模データセット環境には事実上存在しませんでした。データ科学や、大規模データを操作するプロジェクトでは、当てはめていると考える変換が確実に適用されていることを検証できることは非常に便利です。この強力な対話形式の処理は、他のビッグ データ処理フレームワークにはない Spark のもう 1 つの強みです。

また、randomSplit を使用して、データがトレーニング データセットとテスト データセットに分割されているのもわかります。trainingData RDD のデータを使用して ML モデルを作成し、testData RDD のデータを使用してモデルをテストするという考え方は、コードからすぐに理解できます。

これで、作成したばかりの分散データセット (mnist_train) に ML アルゴリズムを適用する準備が整いました。簡単に説明しておくとて、ML の問題には、ほとんどの場合、2 つの独立した手順があります。1 つは、既知のデータセットと既知の結果を使ってモデルをトレーニングする手順です。もう 1 つは、最初の手順で作成 (学習) したモデルに基づいて予測を行う手順です。以下のコードでは、Spark の機械学習フレームワーク (Spark MLLib) 内で利用可能な RandomForest アルゴリズムを使ってモデルをトレーニングしています。RandomForest は、Spark MLLib 内で使用可能ないくつかの分散アルゴリズムの 1 つで、最も強力なものの 1 つです。以下のコードを新しいセルに貼り付けます。

depthLevel = 4
treeLevel = 3
#start timer
start_time = time.time()
#this is building a model using the Random Forest algorithm from Spark MLLib
model = RandomForest.trainClassifier(trainingData, numClasses=10, 
  categoricalFeaturesInfo={},
  numTrees=treeLevel, featureSubsetStrategy="auto",
  impurity='gini', maxDepth=depthLevel, maxBins=32) 
print("Training time --- %s seconds ---" % (time.time() - start_time))

コードでは、アルゴリズムの実行時間の計測を開始してから、RandomForest アルゴリズムが想定するパラメーターの一部 (maxDepth や numTrees など) に初期値を設定しています。Shift キーを押しながら Enter キーを押してコードを実行します。この RandomForest にはどのような役割があり、どのようなしくみになっているのでしょう。RandomForest は ML アルゴリズムの 1 つで、大まかに言えば、データについてのデシジョン ツリーを多数構成することによって機能します。1 つのデシジョン ツリーは、変数をランダムに選択することによって分割されます (つまり、「右下隅のピクセルが白になっていたら、おそらく数字の 2 である」というように 1 つのツリーをできるだけ簡単にします)。その後、構成したすべてのツリーにポーリングして最終の決断を下します。さいわい、Spark には利用可能なアルゴリズムの分散バージョンが既に存在します。ただし、独自のアルゴリズムを作成することにしても、何の問題もありません。たとえば、k 近傍法 (kNN) の分散アルゴリズムは Spark フレームワークにはまだ存在しません。

それでは、MNIST 数字認識タスクに戻ります。今回使用している環境に似ていれば、アルゴリズムをトレーニングする時間は約 21 秒です。つまり、21 秒あれば、RandomForest アルゴリズムを使用して、分析対象の機能で示される数字の予測に使用できるモデルを学習できます。これで、作成したモデルに基づいて予測を行う、ML タスクの最も重要な部分の準備が整いました。また、この予測の精度を評価する準備もできています (図 5 参照)。

図 5 予測精度の評価

# Evaluate model on test instances and compute test error
1 #start timer
2 start_time = time.time()
3 #make predictions using the Machine Learning created prior
4 predictions = model.predict(testData.map(lambda x: x.features))
5 #validate predictions using the training set
6 labelsAndPredictions = testData.map(lambda lp: lp.label).zip(predictions)
7 testErr = labelsAndPredictions.filter(lambda (v, p): v != p).count() /
8   float(testData.count())
9 print('Test Error = ' + str(testErr))
10 print("Prediction time --- %s seconds ---" % (time.time() - start_time))
11 #print('Learned classification tree model:')
12 #print(model.toDebugString())

図 5 の 4 行目の model.predict に注意します。この行で、以前に構築したモデルに基づいて実際の予測を行っています。この予測を行った後の数行 (5 ~ 7 行目) では、基本的なデータ操作手法をいくつか使用して、予測値を実際値に一時的に関連付け (zip 関数) ています。実際値は本稿付属のダウンロードの一部に含まれています。その後、このデータによる予測精度の率を単純に計算し、実行時間を出力します。

この最初の分類結果の誤差は非常に大きく、多少困惑することになります (モデルをすべて実行すると、誤差率は約 43% 程度になります)。「グリッド ハイパーパラメーター検索」という考え方を使用して、このモデルを強化できます。この考え方は、モデルの構築時に一連の値を試し、直後にモデルをテストして、最終的に全体のパフォーマンスが最高になるハイパーパラメーター値に収束させるというものです。つまり、体系的な実験をひと通り試し、最も高い予測値となるモデル パラメーターを判別します。

グリッド検索に適用するハイパーパラメーターは numTrees と maxDepth です。図 6 に示すコードを Notebook の新しいセルに貼り付けます。

図 6 Spark の RandomForest アルゴリズムの最適パラメーターの反復「グリッド検索」

1 bestModel = None
2 bestTestErr = 100
3 #Define a range of hyperparameters to try
4 maxDepths = range(4,10)
5 maxTrees = range(3,10)
6
7 #Loop over parameters for depth and tree level(s)
8 for depthLevel in maxDepths:
9 for treeLevel in maxTrees:
10       
11   #start timer
12   start_time = time.time()
13   #Train RandomForest machine learning classifier
14   model = RandomForest.trainClassifier(trainingData,
15     numClasses=10, categoricalFeaturesInfo={},
16     numTrees=treeLevel, featureSubsetStrategy="auto",
17     impurity='gini', maxDepth=depthLevel, maxBins=32)       
18              
19   #Make predictions using the model created above
20   predictions = model.predict(testData.map(lambda x: x.features))
21   #Join predictions with actual values from the data and determine the error rate
22   labelsAndPredictions = testData.map(lambda lp: lp.label).zip(predictions)
23   testErr = labelsAndPredictions.filter(lambda (v, p): v != p)
24     .count() / float(testData.count())
25       
26   #Print information about the model as we proceed with each iteration of the loop
27   print ('\maxDepth = {0:.1f}, trees = {1:.1f}: trainErr = {2:.5f}'
28          .format(depthLevel, treeLevel, testErr))
29   print("Prediction time --- %s seconds ---" % (time.time() - start_time))
30   if (testErr < bestTestErr):
31       bestModel = model
32       bestTestErr = testErr
33           
34 print ('Best Test Error: = {0:.3f}\n'.format(bestTestErr))

8 ~ 14 行目では、3 ~ 10 行目の RandomForest アルゴリズムに対して一連の numTrees パラメーターをすべてスキャンし、モデルを作成して、そのパフォーマンスを評価しています。次に、30 ~ 32 行目では、それ以前に試行したモデルよりも優れた結果を返すモデルを特定し、それ以外のモデルは無視しています。このループを何回か実行し、実行終了時には、予測誤差の値が 10% 未満になるようにします。

まとめ

今回の初期の目標は、Spark によるプログラミングが、特に関数型プログラミングと Azure を好む開発者にとっていかに簡単かを、例を使って示すことでした。もう 1 つの二次的な目標は、Spark MLLib ライブラリを利用して、データセットの大小にかかわらず ML タスクを実行する方法を例示することでした。この目標を目指す過程で、Spark が分散データ上で以前のフレームワークよりも高速に動作する理由を説明し、分散データ分析分野がこれまでどのように進化してきたかについてちょっとした雑学を共有しようと考えました。

Microsoft はビッグデータ、ML、分析、そして特に Spark の将来に大きな投資を行っています。これらのテクノロジを学び、Microsoft Cloude が提供するハイパースケール コンピューティングとデータ分析のメリットを真に活用するのは、今が絶好の機会です。Azure と Spark を連携させることで、高速かつ容易になり、大規模なデータセットにスケールアップできるようになります。そのすべてが、最高の企業クラウド プロパイダーからしか得られないサービスレベルの保証によって支えられています。

今回は、ML モデルを作成して既知のデータに基づいて予測を行いました。これを土台に、本当のラベルを含まないデータ、つまり Kaggle.com の test.csv ファイルのデータを使って予測を行うことも可能になります。そうすれば、プラットフォームの数字認識装置のコンテストの一環として、これを Kaggle.com に提出できます。本稿付属のすべてのコードと、提出ファイルを作成するコードは、GitHub.com/echuvyrov/SparkOnAzure (英語) からダウンロードできます。読者の評価をお待ちしています。ご質問、ご意見、ご提案、ML の成果については eugene.chuvyrov@microsoft.com (英語のみ) までメールでお送りください。


Eugene Chuvyrov は、Microsoft の Technical Evangelism and Development チームでクラウド ソリューション アーキテクトを務めています。彼は、サンフランシスコ ベイエリア周辺の企業が Microsoft Cloud から提供されるハイパー スケールを十分に活用できるよう手助けしています。彼は現在、ハイスケールのデータ パートナーに力を注いでいますが、ソフトウェア エンジニアとしてのルーツを忘れず、C#、JavaScript、および Python によるクラウド対応コードの記述を楽しんでいます。彼には Twitter (@EugeneChuvyrov、英語) から連絡できます。

この記事のレビューに協力してくれたマイクロソフト技術スタッフの Bruno Terkaly に心より感謝いたします。
Bruno Terkaly は、デバイスに依存しない、業界をリードするアプリケーションやサービスを開発できるようにすることを目標にするマイクロソフトのプリンシパル ソフトウェア エンジニアです。テクノロジが実現可能かどうかという視点を通り越して、米国で最高のクラウド商談やモバイル商談を進めることを担当しています。ISV が評価、開発、配置を行う際に、アーキテクチャに関するガイダンス提供したり、技術的な細かいサポート作業を行うことによって、パートナーがアプリケーションを市場に投入できるようにサポートしています。また、フィードバックを提供したり、ロードマップに影響を与えて、クラウドやモバイルのエンジニアリング グループと密接に連携することも行っています。