サルでデータサイエンティストスマートフォン用の表示で見るコンサルでデータサイエンティスト仕事でPythonを書いてます。機械学習、Webマーケティングに興味があります。この広告は、90日以上更新していないブログに表示しています。機械学習を扱うSparkアプリケーションの開発を行うにあたり、Spark上で使用することのできる機械学習パッケージ(ライブラリ)について調べてみたのでまとめます。はじめに機械学習を扱うような分析タスクや、機械学習を活用したソリューションの開発タスクなどがますます増えています。そのような中で、ビッグデータと呼ばれるような大規模データを扱わなければいけない場面が増えています。数十GB~数TBのデータに対して機械学習を適用しようとした場合、通常の単一マシンで動作するようなPythonプログラムではそのデータを扱いきれないことがほとんどです。このような場合、分散コンピューティングを実現することのできるHadoopやSparkの活用を検討していくことになります。今回はSpark上で使うことのできる機械学習(ML)パッケージについてまとめます。大規模データに適用する機械学習タスク扱うデータが大規模であるからといって、必ずしもSpark上で機械学習を実施する必要があるわけではありません。件数でみれば数十億のレコードを持つログデータがあったとしても、SparkやHiveなどで何かしらの集約処理をすることで単一マシンで扱えるようなデータサイズに圧縮できる場合があります。このような場合には、豊富な機械学習ライブラリが用意されているPythonプログラムで処理をするという選択をとることが多いでしょう。レコメンデーションなどがあります。Sparkで使える機械学習パッケージはこのようなタスクを実現する機械学習手法が実装されています。それぞれの機械学習パッケージの特徴に触れつつ、実装されている手法の違いについて比較していきます。Sparkで使える機械学習パッケージSpark上で扱うことのできる機械学習パッケージは年々増えてきていますが、まだまだ数は限られています。SparkやDatabricksRunTimeMLなどの機械学習基盤が増えていますが、特定のクラウド上でしか使うことができないという不便さがあります。任意の環境で使用することのできる機械学習パッケージの選択肢は少なく、Sparkが公式で提供しているSparkMLパッケージが有名です。Sparkや、Databricks社が開発しているspark-deep-learningなどがある。本記事では、このような機械学習パッケージの中からいくつかについて詳しく取り上げ、それらの違いについて比較していきます。Mahout*1は分散コンピューティングの歴史の中で最初期の機械学習パッケージです。MahoutはIBM*2が2011年に発表し、その後Hadoopの発展と共にOSS化が進んだパッケージです。Mahoutの読み方はマハウトであり、アイコンがHadoopの象に乗っていることからもわかるように「象使い」という意味です。現在はほとんど開発が進んでいないようです。Mahoutは、従来Hadoop上で動く機械学習パッケージでしたが、現在はSpark上で動作します。用意されている主な機械学習手法は以下の通りです。TF-IDFこのように実装されている手法は極めて限定的であるため、現在では使いどころはないと考えてよいと思います。SparkMLlib/SparkMLSparkMLlib及びSparkMLはSpark公式*3が提供している機械学習パッケージです。2013年から開発が始まっており、最も広く使われているSparkの機械学習パッケージです。Rなどの言語からアクセスすることができます。SparkMLlibはSpark初期の機械学習パッケージとして一定の支持を得ていましたが、現在ではメンテナンスモードとなっておりこれ以上の追加開発はされない予定となっています。一方で、SparkMLはSpark2.0に向けて開発された比較的新しいパッケージであり、こちらは現在でも広く使われています。SparkMLlibとSparkMLの違いとしては、SparkMLlibはRDDで扱うことを想定して実装されており、SparkMLはDataFrameおよびDatasetで扱うことを想定して開発されています。このように、大きな違いがある両者ですが、Github上では同一のリポジトリにて管理されています。両者に実装されている機械学習手法も共通のものが多いです。以下にその一部を列挙します。一般化線形モデル、Ridge回帰、Lasso回帰このように用意されている手法は限られているものの、一般的によく使われるアルゴリズムはおさえてあるようです。Spark)は2017年にMicrosoft社がAzure向けに開発・リリースした機械学習パッケージです。Rなどの言語によりアクセスすることができます。本パッケージはAzureクラウド向けに作られているものの、任意の環境で使用することが可能であるという特長があります。Sparkに実装されている主な機械学習手法は以下の通りです。DeepLearning系モデル注目すべき点として、データサイエンティストに人気なLightGBMが実装されているということがあります。SparkMLそのものにはxgboostも実装されていないため、この点では優れたパッケージであるといえます。(SAR)が実装されていることは、ALSによる協調フィルタリングしか存在しないSparkMLと比較するべき点でもあると思います。この手法では、単純な協調フィルタリングではなく、コンテンツ間の情報も活用することでコールドスタート問題を解決するものであるとのことなので、実用面で活用できるのではないかと考えています。まとめSparkで使える機械学習パッケージについてまとめました。一般的によく使われているSparkMLやSparkMLlib以外にも、いくつかのパッケージがあることがわかりました。SparkやDatabricksRunTimeMLについて紹介できなかったので、それらに触れる機会があれば今回紹介したいくつかのパッケージと比較をしたいと思います。08:30Sparkで使える機械学習(ML)パッケージについてまとめるTweet広告を非表示にするもっと読むコメントを書く2019-08-08Scalaの配列(リスト)の各要素の出現個数をカウントするScalaScalaの配列(リスト)の各要素の出現個数をカウントする方法について調べたのでまとめます。Pythonであればcollections.Counterやcountメソッドで実現できることを、Scalaでは関数型言語の思想に近い形で記述することができます。Score)の算出方法についても書いています。Scalaの配列(リスト)の各要素の出現個数をカウント次のような長さ10の文字列配列があるとします。この配列中の各要素の出現回数は次のように求めることができます。ここでの出力はMap型になります。2)各要素の個数についてアクセスしたい場合は次のように書きます。要素“A”の個数は7個であることがわかります。7配列内のカテゴリ変数のばらつき度合い(分散)をジニ係数で求めるジニ係数とは配列内の各要素がどの程度ばらついているかを求める指標であり、0から1の範囲をとります。すべての要素が”A”であればジニ係数は0になり、すべての要素が互いに異なる場合は1に近い値をとります。ジニ係数の詳細については次の記事に記載しています。http://hktech.hatenablog.com/entry/2018/10/05/004235ジニ係数は次の式で求めることができます。ここでは配列全体の要素数が必要となるので、次のように求めます。部分については、次のように求められます。2)最終的なジニ係数の算出はfoldLeft関数を使って以下のように書くことができます。2))まとめScalaの配列の各要素の出現個数をカウントする方法についてご紹介しました。配列内のばらつき度合いを表すジニ係数の求め方についてもまとめました。メソッドをチェーンすることで複雑な処理も関数風に1行で書くことでScalaの特徴を活かすことができるので、本記事での記述方法を参考にしてみてください。機械学習LSTNetの論文*1を読む機会があったので、関連手法であるニューラルネットワークをベースとした時系列予測の手法についてまとめました。本記事では、RNNをはじめとして、その派生であるLSTM、GRU、LSTNetについて紹介していきます。ある層の出力を別の層の入力として利用するような再帰的構造を持ったニューラルネットワークです。組み合わせて活性化したものです。tanh(ハイパボリックタンジェント)を使った活性化は下式のように表すことができます。RNNのメリットは、独立した各時点での情報だけでなく前後の時系列情報を活用することができることです。一方で、RNNにはデメリットもあります。RNNのデメリットは、直前の中間出力のみを使うため長期の時系列情報をうまく学習することができない点にあります。Memory)LSTMとは、RNNのデメリットであった長期の時系列情報を考慮することで長期的な依存関係の学習を可能にしたRNNの派生モデルです。LSTMのメリットは長期間記憶を保持することで長期的な依存関係を考慮して回帰を実現できる点にあります。LSTMの中間出力はRNNでも中間情報として出力されていた隠れ状態とLSTM特有のセル状態の2種類があります。LSTMの特徴として忘却ゲート、入力ゲート、出力ゲートの3種類のゲートを持つという点があります。ゲートとは、情報をどの程度つぎの時刻に伝達するかを制御するコンポーネントであり、0から1の値をとります。Unit)GRUとは、LSTMの忘却ゲートと入力ゲートを単一の更新ゲートにマージし隠れ状態のみを伝達していくニューラルネットワークのモデルです。GRUのメリットは、LSTMと比べて学習パラメータが少ないためより短い時間で学習することができるという点にあります。隠れ層出力LSTNetLSTNetは、ニューラルネットワークベースの多変量時系列予測モデルです。LSTNetは大きく以下の3つのコンポーネントで構成されています。Recurrent層出力を結合しARモデルの出力と統合する層Convolution層Convolution層では入力された多次元時系列データに対し、畳み込みフィルタを複数適用させることで短期間の特徴および変数間の関係について抽出するように学習します。すると下式で表すことができます。Layer(GRU)と他Layerの2-Layer構造になっています。Layerの組み合わせは以下の通りです。Convolution層の出力を入力としています。活性化関数は一般的なGRUモデルとは異なり、tanhではなくRELUを採用しています。Recurrent-Layerの出力は以下の式で表すことができます。Convolution層の出力を入力としたGRUモデルが採用されています。周期がわかっているデータについては、p個周期ごとの隠れ状態のみを使った予測を行うことができます。pを明示的に定め、p個分スキップすることで重要な情報を失うことなく伝達することができます。電力消費のデータであれば、24時間周期になるようにpを設定するといった使い方をします。Skip-Layerの出力は以下の式で表すことができます。Layerの全結合後の出力は次のように表すことができます。Skip-Layerの出力の和を表しています。Layerを用いて過去系列の隠れ表現の注目度を算出し、予測に使用する過去系列の重みを決定して予測を行います。データに既知の周期性がない場合や、周期が動的変化する場合に有効です。各時点の隠れ表現とt-1時刻の隠れ表現との間の類似度を求めたものであり以下のように表すことができます。Layerの出力は以下のように表現することができます。(ARモデルの出力)の和となります。ARモデルの出力結果と合わせることで、スケール変化の大きいデータに対してよりロバストな予測を実現することができるとされており、これは論文内の評価セクションにて説明されています。GRU、LSTNetの4手法についてご紹介しました。次元が大きい多次元時系列データに対しては一般的な回帰モデルよりも高い精度が期待できるため、このあたりの手法はおさえておきたいですね。Python前回の記事からだいぶ時間があいてしまいましたが、平成最後ということでひとつ書かせてください。はじめに先日登壇した勉強会で「データサイエンティストはエンジニアリングスキルを高めるべき」という趣旨の主張を展開した上で、「エンジニアリングスキルを高めるために競技プログラミングをやっている」と言ったところ、参加者から以下の質問を頂きました。本記事では上記の疑問に対する自分なりの考えをまとめていこうと思います。アルゴリズム重視や可読性の低いコードばかりで実務に役立たないと思われがちな競技プログラミングですが、実はいろんな側面で業務に役立つことを学ぶことができます。今回の記事はエンジニア全般を対象とした話をするので、データサイエンティストでない方にも読んでいただきたい内容になっています。実装・テストまとめ競技プログラミングとは競技プログラミングとは、プログラミングを使って速く・正確に・多くの問題を解き、その結果を競う競技です。現在、世界中でオンラインコンテストが実施されています。日本で競技プログラミングの話がされる場合は、Atcoderというオンラインコンテストサイトが連想されることが多いです。(2019/04時点)。ほとんどの競技プログラミングサイトではオンラインジャッジという仕組みが採用されています。これは出題された問題に対するソースコードを提出すると、問いの条件を満たすようなテストケースを自動でチェックしてくれるというものです。提出コードがすべてのテストケースを満たしていて、実行時間も制限時間内だったとき初めてその問題をクリアしたことになります。オンラインコンテストでは100~120分という制限時間の中で、複数の問題を世界中の人と同時に解き、その結果を競います。競技プログラミングで身につくスキル競技プログラミングで身につくスキルは、開発の各フェーズで必要とされるスキルにかなり近いです。開発業務にどのようなフェーズがあるのか確認していきます。開発を行う時のフェーズはおおよそ以下のようになります。これをベースに、競プロでどのようなスキルが身につくのかをみていきましょう。問題や仕様の理解はコンテストにおいては最も重要なポイントです。問題の理解を誤ったまま先に進んでしまうと、すべて最初からやり直しとなってしまいます。これでは素早くたくさんの問題を解くことができません。仕事で炎上するときもだいたい認識の齟齬が原因ですよね。問題読解能力は国語力でもあり、業務を行う上でもとても大切なスキルです。競技プログラミングを始めると、問題文から瞬時にイメージを正確にとらえるスキルを身につけることができます。次のような問題があります。上級者であれば瞬時に理解して実装に落とし込めるようですが、私は凡人なのでまず紙でイメージを書き出します。この問題では隣り合ってる数字のペアの正負を何回でも操作して入れ替えられるよということなので、それを書き出すとこんな感じになります。全ての数字を正にすることができました。入出力例と合っているのでこの解釈で間違いなさそうです。ひとつ例を書くと今度は全ての数字を正にすることはできず、1つだけ負の数字が残っています。このように問題を理解し、イメージをアウトプットすることが大切です。チーム開発などでは認識齟齬が致命傷になることが多いですが、実際の業務でも仕様を理解してイメージをチームメンバーと共有することが大事だと思います。競技プログラミングを始めてから、このような作業が速く・正確に行えるようになった気がします。問題の理解ができたら、次は実装方針の設計を行います。データサイエンティストの人はこの設計をせずにコードを書き出してしまう場合が多い*1ですが、開発では設計を必ず行いましょう。競技プログラミングで上位を目指すのであれば設計をしている暇なんてありませんが...慣れるまでは急がば回れで堅実にやっていきましょう。「仕様の理解」パートで、この問題設定では以下のパターンがあることがなんとなくわかりました。すべての数字を正にできるパターン1つだけ負の数字が残ってしまうパターンここで、いくつか入力例を書き出してみます。22ここまで書くと、以下のことがわかります。すべての数字を正にできるつまり、以下のような設計方針を立てることができます。引く(既に足した分も引くため)また、コンテストでは実行時間制限が設けられているため、おおまかな計算量を試算しておく必要があります。頑張ってコードを書いて回した結果、計算時間オーバーではもったいないです。今回の方針は、入力列(長さN)に対して1回のループを回すためO(n)で解けそうだということがわかります。前段でテストパターンを洗い出したものの、これで全パターンを満たせているでしょうか?競技プログラミングでは全てのテストケースを通過しなければ、正解とはなりません。Atcoderではミスをおかす度にペナルティが付与されてしまうため、テストケースに漏れがないかよく確認したいところです。実装する前にテスト設計を行う理由としては、テストパターンに漏れがあった場合に実装方針に影響が出てしまうからです。手戻りは未然に防ぎたいですよね。先の例で、入力パターンをいくつか用意して設計を行い、これを実際のテストパターンとして使う開発手法はテスト駆動開発と呼ばれていたりします。テスト設計と実装設計を同時にやってしまうようなものなのですが、テストパターンが完璧に押さえられている場合は、これを満たすようにロジックを実装するだけなのでとても楽で確実です。前章で列挙した入力パターンを確認すると、どうやら0が入るパターンを考慮できていなかったようです。このパターンでは、負の数字カウントが奇数なのにもかかわらず全ての数字を正にすることができています。テストケース漏れ??と思いましたが、そもそも0が入る場合は最後に引くものがないため問題なさそうです。引く(既に足した分も引くため)符号が変わるポイントは忘れがちなので、与えられる数字の範囲に注意してテストケースを設計したいです。念のため新たな入力例もテストパターンに加えて準備万端です。あとは、これらのテストケースが全て通るようなコードを書くだけです。テスト駆動開発がいかに有用であるかということを、競技プログラミングを通して肌で理解することができます。実装・テスト多くのオンラインコンテストでは、好きなプログラミング言語を選んで実装することができます。高速で実行ができるという点で、C++を使っている方が多いですが、実務で使っている好きな言語で書けば良いと思います。実装方針はすでに立っているので、実装をしていきましょう。以下が私がPythonで書いたコードです。min(abs_list))競技プログラミングはプログラムを書くことがメインだと思われがちですが、実は実装に入るまでにほとんどのことは終わっています。上記のコードはプログラミング初心者でもぐぐったら書けるレベルですし、初心者向けの問題であれば実装の高度なテクニックは求められません。他にも、Atcoderではいろいろな人のコードをみることができます。以下の例は、同じ方針を短いコードでまとめあげています。テストという流れは一般的な開発フローと似ていますし、アルゴリズムや実装テクニックといった部分以外にも実務に役立つことをたくさん学ぶことができます。実装に入るまでにほとんどのことが終わっていると書きましたが、実務でもこのように仕様理解と設計をしっかりと行うことが早く仕事をこなす近道だと思います。今回はアルゴリズム以外の部分に着目しましたが、今後はアルゴリズムや計算量を意識した実装に関する記事を書ければいいなと思います。15:49データサイエンティストが競技プログラミングをやるべき理由Tweet広告を非表示にするもっと読むコメントを書く2019-02-20Scalaで配列/リストを操作するSeqコレクションについてまとめたScalaで配列またはリストを使う際はSeqがおすすめです。本記事では、他のプログラミング言語における配列やリストとは少し異なる挙動を示すSeqコレクションの文法および操作についてまとめました。Seqの宣言ScalaのSeqは以下のように作ることができます。Three)Seqの要素についてString型をあらかじめ宣言する必要がある点が、Pythonなどのスクリプト言語との大きな違いです。Seqの要素にアクセスするScalaでSeqの要素にアクセスする方法について紹介します。次のように添字1を指定して要素を取り出すことができます。TwoScalaの添字は他の多くのプログラミング言語と同じく0で始まるため、2番目の要素が抽出されていることがわかります。Seqの先頭要素や末尾要素へのアクセスはheadやlastを使って次のように行うことができます。要素を取り出すことができます。Two)Seqの要素を追加または削除するScalaでSeqに要素を追加または削除する方法について紹介します。Four)このとき、元のseqは変化していないことに気づかれた方もいると思います。Scalaのコレクションは基本的に非破壊的であるため、新しいオブジェクトが返されるということを覚えておきましょう。複数のSeqを連結するScalaで複数のSeqを結合する方法は次の通りです。World)Seq同士が連結されていることが確認できます。Seqの要素をソートするScalaでSeqをソートするにはsortedを使います。逆順に表示するにはreverseを使います。この辺りはpythonと同じメソッド名ですね。8)まとめScalaのSeqコレクションの文法および操作についてまとめました。特徴的なメソッドがまだまだあります。これらについては別記事で紹介できればと思います。する方法についてご紹介します。Scalaに入門したばかりの私が、次の入門書を参考にしながらまとめました。単行本(ソフトカバー)この商品を含むブログを見るパッケージのインポートScalaでは、Javaと同様にクラス、オブジェクト、トレイトなどは必ず何らかのパッケージに所属します。パッケージのインポートは他のプログラミング言語と同じく、プログラムの冒頭で行われます。ドメイン名を逆順にしたものをパッケージ名とするのが一般的な慣習です。SparkのWindow関数を使うためのクラスをインポートする方法は以下の通りです。参照することができるようになります。ここで、Windowという同じ名前のクラスがインポートされていて衝突してしまった場合にはどのようにすればいいでしょうか?Scalaではインポート時の名前衝突を以下のように防ぐことができます。SparkWindow}また、特定のクラスだけでなく、あるパッケージ配下に所属するすべてのクラスやオブジェクトをインポートしたいときには以下のようなインポート文を書くことができます。org.apache.spark.sql.expressions._このようなインポートはワイルドカードインポートなどと呼ばれます。まとめScalaでパッケージをインポートする方法についてまとめました。Javaに馴染みがある方にとっては特に違和感のない内容となっていますが、他の言語から始められた方はこの機会にインポートの仕方を確認してみてください。Sparkの学習の一環としてScalaに触れてみることにしました。本記事では、Scalaの基本的な構文を確認した後にFizzBuzz問題を解いていきます。SparkとScalaの関係性について詳しく知りたい方はこちらhktech.hatenablog.comFizzBuzz問題とはFizzBuzz問題とは1から100までの数字について、3で割り切れる場合に”Fizz”、5で割り切れる場合に”Buzz”、両者で割り切れる場合に”FizzBuzz”、それ以外の場合はその数字を出力させるプログラミング問題です。調べてみたらもともとは英語圏で遊ばれている言葉遊びらしいです。プレイヤーは円状に座る。最初のプレイヤーは「1」と数字を発言する。次のプレイヤーは直前のプレイヤーの次の数字を発言していく。Buzz」)を数の代わりに発言しなければならない。発言を間違えた者や、ためらった者は脱落となる。ja.wikipedia.orgいや、ただの宴会ゲーム。Scalaのプログラミング構文いきなりScalaの実装に入る前に、基本的なプログラミング構文を確認しておきます。FizzBuzz問題で必要となるのは大きく3つです。条件分岐するためのif-else文リストまずはリストの構文について確認していきます。1から3までのリストを作ります。Scalaって型推論あるのか、、、確かに型宣言はしてないですよね。次に1から100のリストを作ります。1から100まですべて書き出すわけにはいかないですよね。そこで、Rangeというものを使います。これはPythonと同じですね。101できてそうですね。これをリスト型にします。100)こんな書き方もできます。100)for文Scalaにおけるfor文の書き方についてみていきます。