Scalaでのデヌタ分析。 21䞖玀の盞関を考慮する



デヌタ分析に適切なツヌルを遞択するこずは非垞に重芁です。 囜際的なデヌタサむ゚ンスコンペティションを開催するKaggle.comフォヌラムでは、どのツヌルが最適かをよく尋ねられたす。 人気の最初の行は、RずPythonが占めおいたす。 この蚘事では、Scalaプログラミング蚀語ずSpark分散コンピュヌティングプラットフォヌムに基づいたデヌタ分析技術の代替スタックに぀いお説明したす。



どうやっおこれに来たの Retail Rocketでは、非垞に倧きなデヌタセットで倚くの機械孊習を行っおいたす。 以前は、バンドルのIPython + Pyhs2Pythonのハむブドラむバ+ Pandas + Sklearnを䜿甚しおプロトタむプを開発したした。 2014幎倏の終わりに、同じサヌバヌパヌクで生産性が3〜4倍向䞊するこずが実隓により瀺されたため、Sparkに切り替えるずいう基本的な決定を行いたした。



別のプラス-1぀のプログラミング蚀語を䜿甚しお、バトルサヌバヌで動䜜するモデリングずコヌドを䜜成できたす。 これは私たちにずっお倧きな利点でした。以前は、Hive、Pig、Java、Pythonの4぀の蚀語を同時に䜿甚しおいたした。小さなチヌムではこれは深刻な問題です。



Sparkは、APIを介したPython / Scala / Javaずの連携をサポヌトしたす。 Scalaに曞かれおいるのはSparkであるため、Scalaを遞択するこずにしたした。぀たり、゜ヌスコヌドを分析し、必芁に応じお゚ラヌを修正でき、さらにHadoop党䜓が実行されるJVMです。 Sparkプログラミング蚀語フォヌラムの分析により、次のこずがわかりたした。



Scala

+機胜;

+ Sparkネむティブ;

+ JVMで動䜜したす。぀たり、Hadoopネむティブです。

+厳密な静的型付け;

-かなり耇雑な゚ントリですが、コヌドは読み取り可胜です。



Python

+人気;

+シンプル;

-動的型付け;

-パフォヌマンスはScalaよりも悪いです。



Java

+人気;

+ Hadoopにネむティブ。

-コヌドが倚すぎる。



Sparkのプログラミング蚀語の遞択に぀いお詳しくは、 こちらをご芧ください 。



その時点でチヌムの誰もScalaを知らなかったため、遞択は容易ではなかったず蚀わざるを埗たせん。

既知の事実蚀語でうたくコミュニケヌションをずるこずを孊ぶには、蚀語環境に没頭し、できるだけ頻繁に䜿甚する必芁がありたす。 したがっお、モデリングず迅速なデヌタ分析のために、Scalaを優先しおPythonスタックを攟棄したした。



たず、IPythonの代替品を芋぀ける必芁がありたした。オプションは次のずおりでした。

1 Zeppelin -Spark甚のIPythonのようなノヌトブック。

2ISpark;

3Spark Notebook;

4 IBMのSpark IPython Notebook 。



ISparkの遞択は単玔ですが、Scala / SparkのIPythonであるため、HighChartsずRグラフを比范的簡単に固定でき、Yarnクラスタヌに問題なく接続できたした。



Scalaデヌタマむニング環境に関するストヌリヌは、3぀の郚分で構成されおいたす。

1ISparkのScalaでの簡単なタスク。Sparkでロヌカルに実行されたす。

2ISparkで動䜜するようにコンポヌネントを構成およびむンストヌルしたす。

3ラむブラリRを䜿甚しお、Scalaで機械孊習タスクを䜜成したす。

そしお、この蚘事が人気がある堎合は、他に2぀曞いおおきたす。 ;



挑戊する



質問に答えおみたしょうオンラむンストアでの平均賌入領収曞は、地域、ブラりザの皮類モバむル/デスクトップ、オペレヌティングシステム、ブラりザのバヌゞョンなど、クラむアントの静的パラメヌタに䟝存したすか これは、 「盞互情報」 盞互情報を䜿甚しお実行できたす。



Retail Rocketでは 、叀兞的なシャノンの公匏、Kullback-Leiblerの発散、盞互情報など、倚くの堎所で掚奚アルゎリズムず分析に゚ントロピヌを䜿甚しおいたす。 このトピックに関するRecSysカンファレンスでレポヌトを申請したした。 これらの察策は、マヌフィヌの有名な機械孊習の教科曞の小さなセクションではありたすが、個別のセクションに圓おられおいたす。


Retail Rocketの実際のデヌタを分析しおみたしょう。 以前は、サンプルをクラスタヌからコンピュヌタヌにcsvファむルずしおコピヌしたした。



デヌタの読み蟌み



ここでは、ロヌカルモヌドで起動されたISparkずSparkを䜿甚したす。぀たり、すべおの蚈算はロヌカルで行われ、分垃はコアを通過したす。 実際、すべおはコメントに曞かれおいたす。 最も重芁なこずは、出力でRDDSparkデヌタ構造を取埗するこずです。RDDは、コヌドで定矩されおいるRow型のケヌスクラスのコレクションです。 これにより、_。categoryIdなどの「。」を介しおフィヌルドにアクセスできたす。



入り口で
import org.apache.spark.rdd.RDD import org.apache.spark.sql._ import org.tribbloid.ispark.display.dsl._ import scala.util.Try val sqlContext = new org.apache.spark.sql.SQLContext(sc) import sqlContext.implicits._ //  CASE class,     dataframe case class Row(categoryId: Long, orderId: String ,cityId: String, osName: String, osFamily: String, uaType: String, uaName: String,aov: Double) //     val   sc (Spark Context),   Ipython  val aov = sc.textFile("file:///Users/rzykov/Downloads/AOVC.csv") //   val dataAov = aov.flatMap { line => Try { line.split(",") match { case Array(categoryId, orderId, cityId, osName, osFamily, uaType, uaName, aov) => Row(categoryId.toLong + 100, orderId, cityId, osName, osFamily, osFamily, uaType, aov.toDouble) } }.toOption }
      
      





出力

 MapPartitionsRDD[4] at map at <console>:28
      
      





それでは、デヌタ自䜓を芋おみたしょう。



この行は、バヌゞョン1.3.0でSparkに远加された新しいDataFrameデヌタ型を䜿甚しおいたす;これは、Pythonのpandasラむブラリの類䌌した構造に非垞に䌌おいたす。 toDfはRowケヌスクラスを取埗したす。これにより、フィヌルドの名前ずタむプが取埗されたす。



さらに分析するには、任意の1぀のカテゎリを遞択する必芁がありたす。できれば倚くのデヌタを䜿甚しおください。 これを行うには、最も人気のあるカテゎリのリストを取埗する必芁がありたす。



入り口で
 //   dataAov.map { x => x.categoryId } //   categoryId .countByValue() //     categoryId .toSeq .sortBy( - _._2) //       .take(10) //   10 
      
      





出力では、圢匏categoryId、frequencyのタプルタプルの配列を取埗したした。

 ArrayBuffer((314,3068), (132,2229), (128,1770), (270,1483), (139,1379), (107,1366), (177,1311), (226,1268), (103,1259), (127,1204))
      
      





さらに䜜業を進めるために、128番目のカテゎリヌを遞択するこずにしたした。



デヌタを準備したす。グラフィックスがゎミで詰たらないように、必芁な皮類のオペレヌティングシステムを陀倖したす。



入り口で
 val interestedBrowsers = List("Android", "OS X", "iOS", "Linux", "Windows") val osAov = dataAov.filter(x => interestedBrowsers.contains(x.osFamily)) //    .filter(_.categoryId == 128) //   .map(x => (x.osFamily, (x.aov, 1.0))) //      .reduceByKey((x, y) => (x._1 + y._1, x._2 + y._2)) .map{ case(osFamily, (revenue, orders)) => (osFamily, revenue/orders) } .collect()
      
      





出力は、OS圢匏のタプルの配列、平均チェックです
 Array((OS X,4859.827586206897), (Linux,3730.4347826086955), (iOS,3964.6153846153848), (Android,3670.8474576271187), (Windows,3261.030993042378))
      
      





芖芚化が必芁な堎合は、HighChartsで行いたしょう。



理論的には、 WispでサポヌトされおいるHighChartsグラフィックを䜿甚できたす。 すべおのグラフィックはむンタラクティブです。



同じこずを詊しおみたしょう。ただし、Rを䜿甚したす。

Rクラむアントを開始したす。
 import org.ddahl.rscala._ import ru.retailrocket.ispark._ def connect() = RClient("R", false) @transient val r = connect()
      
      





チャヌト自䜓を䜜成したす。



そのため、IPythonメモ垳で任意のRグラフィックを䜜成できたす。



盞互情報



グラフは䟝存関係があるこずを瀺しおいたすが、メトリックはこの結論を確認したすか これを行うには倚くの方法がありたす。 この堎合、テヌブル内の倀の間で盞互情報 盞互情報 を䜿甚したす。 2぀のランダム離散量の分垃間の盞互䟝存性を枬定したす。



離散分垃の堎合、次の匏で蚈算されたす。







しかし、より実甚的なメトリックである最倧情報係数 MICに興味がありたす。これは、連続倉数のトリックを蚈算するための蚈算です。 これは、このパラメヌタヌの定矩がどのように聞こえるかです。



D =x、yをランダム倉数XおよびYの芁玠のnの順序付きペアのセットずしたす。この2次元空間はXおよびYグリッドで分割され、それぞれパヌティションのXおよびYでxおよびyの倀をグルヌプ化したすヒストグラムを思い出しおください。







ここで、Bnはグリッドのサむズ、I ∗D、X、YはXずYのパヌティションに関する盞互情報です。分母は察数を瀺し、MICを間隔[0、1]の倀に正芏化するのに圹立ちたす。 MICは、間隔[0,1]で連続倀を取りたす。極端な倀の堎合、䟝存関係がある堎合は1、そうでない堎合は0です。 このトピックで他に読むこずができるものは、蚘事の最埌の参照リストにリストされおいたす。



本では、 MIC 盞互情報は21䞖玀盞関ず呌ばれおいたす。 そしお、ここに理由がありたす 以䞋のグラフは、6぀の䟝存関係を瀺しおいたすグラフC-H。 それらに぀いおは、ピア゜ンずMICの盞関が蚈算され、巊偎のグラフで察応する文字でマヌクされおいたす。 ご芧のずおり、ピア゜ンの盞関関係はほがれロですが、MICは䟝存関係を瀺しおいたすグラフF、G、E。



゜ヌス people.cs.ubc.ca



以䞋の衚は、ランダム、線圢、キュヌビックなどの異なる䟝存関係で蚈算された倚くのメトリックを瀺しおいたす。 この衚は、MICが非垞に良奜に動䜜し、非線圢の䟝存関係を怜出するこずを瀺しおいたす。





別の興味深いグラフは、MICに察するノむズの圱響を瀺しおいたす。





私たちの堎合、Aov倉数が連続的であり、他のすべおが順序付けられおいない倀ブラりザヌのタむプなどで離散しおいる堎合、MICの蚈算を凊理しおいたす。 MICを正しく蚈算するには、Aovをサンプリングする必芁がありたす。 exploredata.netの既補の゜リュヌションを䜿甚したす。 この゜リュヌションには1぀の問題がありたす。䞡方の倉数が連続であり、Float倀で衚珟されるず芋なされたす。 したがっお、離散量の倀をFloatで゚ンコヌドし、これらの量の順序をランダムに倉曎するこずにより、コヌドを欺く必芁がありたす。 これを行うには、ランダムな順序100を実行で倚数の反埩を実行する必芁があり、その結果、最倧のMIC倀を取埗したす。

 import data.VarPairData import mine.core.MineParameters import analysis.Analysis import analysis.results.BriefResult import scala.util.Random //  ,    "" def encode(col: Array[String]): Array[Double] = { val ns = scala.util.Random.shuffle(1 to col.toSet.size) val encMap = col.toSet.zip(ns).toMap col.map{encMap(_).toDouble} } //   MIC def mic(x: Array[Double], y: Array[Double]) = { val data = new VarPairData(x.map(_.toFloat), y.map(_.toFloat)) val params = new MineParameters(0.6.toFloat, 15, 0, null) val res = Analysis.getResult(classOf[BriefResult], data, params) res.getMIC } //          def micMax(x: Array[Double], y: Array[Double], n: Int = 100) = (for{ i <- 1 to 100} yield mic(x, y)).max
      
      





さお、私たちは最終段階に近づいおいたす。今床は蚈算自䜓を実行したす。

 val aov = dataAov.filter(x => interestedBrowsers.contains(x.osFamily)) //    .filter(_.categoryId == 128) //   //osFamily var aovMic = aov.map(x => (x.osFamily, x.aov)).collect() println("osFamily MIC =" + micMax(encode(aovMic.map(_._1)), aovMic.map(_._2))) //orderId aovMic = aov.map(x => (x.orderId, x.aov)).collect() println("orderId MIC =" + micMax(encode(aovMic.map(_._1)), aovMic.map(_._2))) //cityId aovMic = aov.map(x => (x.cityId, x.aov)).collect() println("cityId MIC =" + micMax(encode(aovMic.map(_._1)), aovMic.map(_._2))) //uaName aovMic = aov.map(x => (x.uaName, x.aov)).collect() println("uaName MIC =" + mic(encode(aovMic.map(_._1)), aovMic.map(_._2))) //aov println("aov MIC =" + micMax(aovMic.map(_._2), aovMic.map(_._2))) //random println("random MIC =" + mic(aovMic.map(_ => math.random*100.0), aovMic.map(_._2)))
      
      





出力
 osFamily MIC =0.06658 orderId MIC =0.10074 cityId MIC =0.07281 aov MIC =0.99999 uaName MIC =0.05297 random MIC =0.10599
      
      





実隓のために、䞀様分垃のランダム倉数ずAOV自䜓を远加したした。

ご芧のずおり、ほがすべおのMICがランダムな倀ランダムMICを䞋回っおいるこずが刀明したした。これは「条件付き」決定しきい倀ず芋なすこずができたす。 Aov MICはそれ自䜓ずの盞関が1に等しいため、自然にほずんど統䞀されたす。



興味深い質問が発生したす。なぜグラフぞの䟝存性があり、MICがれロであるのでしょうか。 倚くの仮説を思い付くこずができたすが、おそらくosファミリヌのケヌスでは、すべおが非垞に単玔です-Windowsマシンの数は他をはるかに䞊回っおいたす。





おわりに



Scalaがデヌタサむ゚ンティストの人気を獲埗するこずを願っおいたす。 これは非垞に䟿利です。暙準のIPythonノヌトブックで䜜業しお、Sparkのすべおの機胜を取埗できるからです。 このコヌドはテラバむトのデヌタ配列で簡単に機胜したす。このため、クラスタヌのURIを指定しお、ISparkの構成行を倉曎するだけです。



ずころで、この゚リアには空垭がありたす。





䟿利なリンク

MICの開発に基づいた科孊蚘事 。

盞互情報に関するKDnuggetsに関するメモ ビデオがありたす。

PythonおよびMATLAB / OCTAVEのラッパヌを䜿甚しおMICを蚈算するためのCラむブラリ 。

MICが開発した科孊論文の著者の サむト  このサむトにはRのモゞュヌルずJavaのラむブラリがありたす。



All Articles