Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Scala による自然言語処理

8,285 views

Published on

DSIRNLP 4 の資料です。
http://partake.in/events/76854228-ba38-4f6e-87b9-f79e30add75c

Published in: Technology
  • Be the first to comment

Scala による自然言語処理

  1. 1. Scala による自然言語処理 2013-09-01 Hiroyoshi Komatsu @torotoki 1
  2. 2. プロフィール • @torotoki • 興味 • 質問応答 • トピックモデル • 言語 • Scala 歴は半年くらい • NTCIR RITE という含意関係認識の ワークショップで触れた • 他の関数型言語をやったことはない • 高2 2
  3. 3. 前置き 3
  4. 4. なぜ Scala なのか • Scala の利点 • 一般的な書き方をしつつも、面倒な部分は関数型言語らしく簡 潔に書ける • スクリプト言語と比べて早い • 静的型付けなのでコンパイル時にエラーが分かる • 型推論が強力で動的型付け言語並みに型を省略できる • JVM で動く • Java の力を借りられる 4
  5. 5. 今回の議題 • 自然言語処理/機械学習をする人に Scala を知ってもらう • なぜ Scala を使うのか • 関数型言語のおかげでデータ構造が比較的簡単に扱える • グラフとかツリーとか扱うので便利 • 好きなところだけ関数型な構文でかける • 言語処理/機械学習のライブラリが充実 しつつ ある 5
  6. 6. Scala の構文 • セミコロンや型名などごちゃごちゃせずに奇麗に書ける var capital = Map("US" -> "Washington", "France" -> "Paris") capital += ("Japan" -> "Tokyo") println(capital("France")) 6
  7. 7. タイプ推論 val list = List(1, 3, 4) var list2 = list list2 = List(4,5,6) // OK list2 = List(“Test!”) // error 7
  8. 8. マップ処理 val list = List(1,2,3) def plus1(x: Int) = x + 1 val increaseList = list.map(plus1) 8
  9. 9. マップ処理(別バージョン) val list = List(1,2,3) val increaseList = list.map(_ + 1) 9
  10. 10. Scala のデータ構造 10
  11. 11. データ構造 • 関数型的な データ構造とは • 全ての変数をイミュータブル(不変)にする • 望ましい構造 • スケーラブルでも同等の性能を出す • 非破壊的 • 更新の際は元のデータを書き換えるのではなく、新たなデー タを生成する • イメージとして 関数型的 非破壊的 11
  12. 12. Scala のリスト構造 List(a, b, c, d) A B C D 要素と次の要素のリンクを持つ簡素なもの 12
  13. 13. Scala のリストの関数 • 頑張ってなるべく O(1) の操作を使う O(1) O(log n) O(n) 最初の値 先頭に追加 最後に追加 連結 挿入 最後の値 n番目の値 13
  14. 14. キュー • キュー(Queue)は enqueue と dequeue という2つの 操作ができるデータ構造 • enqueue: 一番後ろにデータを入れる • dequeue: 一番前にデータを取り出す http://en.wikipedia.org/wiki/Queue_(abstract_data_type) 14
  15. 15. 単純な非破壊的なキュー • 単純にやると全コピー: 計算量: O(n) 1 2 3 4 ・ ・ 追加 1 2 3 4 ・・ コピー コピー コピー 15
  16. 16. 非破壊的なキュー • ちょっと工夫 • 後ろのほうは逆順で持つ • 単純な順番しかないリストなので先頭への追加は O(1) 1 2 3 ・ 5 4 ・ 16
  17. 17. キューの Scala 実装 case class Queue[T](leading: List[T], trailing: List[T]) { private def mirror = if (leading.isEmpty) new Queue(trailing.reverse, Nil) else this def head = mirror.leading.head def tail = { val q = mirror new Queue(q.leading.tail, q.trailing) } def enqueue(x: T) = new Queue(leading, x :: trailing) def dequeue = this.tail } 17
  18. 18. 関数型言語だけど… • Scala は関数型言語だが、for文やwhile文など「普通の書 き方」ができる • 変数も可能 var a = 0 while (a != 100) { println(a) a += 1 }   for (i <- 1 to 100) { println(a) } val a = 3 // 定数 var b = 15 // 変数 18
  19. 19. ライブラリ 19
  20. 20. NLP/MLのライブラリ • 「ScalaNLP」という5つのライブラリがある http://www.scalanlp.org 20
  21. 21. ScalaNLP • ScalaNLP の5つのライブラリ • Breeze: 線形代数, 数値計算, 可視化 • Nak: 機械学習 • Chalk: テキスト処理 • Epic: パーサー • Junto: ラベル伝搬 • 依存関係 • Breeze -> 他の全て • Nak -> Chalk • Epic -> Chalk • Junto は独立したライブラリ Breeze のロゴ 21
  22. 22. Breeze scala> val m = DenseMatrix.zeros[Int](5,5) m: breeze.linalg.DenseMatrix[Int] = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 scala> (m.rows, m.cols) res10: (Int, Int) = (5,5) scala> m(::,1) res7: breeze.linalg.DenseVector[Int] = DenseVector(0, 0, 0, 0, 0) scala> m(4,::) := DenseVector(1,2,3,4,5).t // 転置 res8: breeze.linalg.DenseMatrix[Int] = 1 2 3 4 5 scala> m res9: breeze.linalg.DenseMatrix[Int] = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 22
  23. 23. Python vs Scala • 公式サイトのスライドから引用 • http://www.scalanlp.org/documentation/ • 詳しい条件があまり書いてないが… 23
  24. 24. ScalaNLP 所感 • Breeze 以外はドキュメント不足 • 現状 README とサンプルが手がかり • サイトには Breeze 以外のプロジェクトについてあまり記述が ないため、今後作成予定だと思われる • 開発は進行中 • それぞれを見るとまだ超大規模なプロジェクトではないので、 今なら色々貢献できる? 24
  25. 25. おまけ 25
  26. 26. Scala で XML 処理 • 個人的には XML 処理がもっとも Scala の拡張性がよく 現れていると思う • 前提 • XML を構文としてサポートしている • Scala では記号は関数として扱われるため、ユーザー も簡単に記号を定義できる • これを生かして XML では XPath が埋め込める val p = <a> This is some XML. Here is a tag: <atag/> </a> X + X, X * 3, X ??? “aaa” //=> X.+(X) X.*(3) X.???(“aaa”) 26
  27. 27. MeCab の XML の処理 val sentence = <sentence> <chunk id="0" link="6" rel="D" score="2.909358" head="0" func="1"> <tok id="0" feature="名詞,固有名詞,人名,名,*,*,太郎,タロウ,タロー" ne="B-PERSON">太郎</tok> <tok id="1" feature="助詞,係助詞,*,*,*,*,は,ハ,ワ" ne="O">は</tok> </chunk> <chunk id="1" link="2" rel="D" score="1.257926" head="2" func="2"> <tok id="2" feature="連体詞,*,*,*,*,*,この,コノ,コノ" ne="O">この</tok> </chunk> <!-- 省略... --> </sentence> for (tok <- sentence "tok") { val feature = tok "@feature" println(feature + ": " + tok.text) }) 27
  28. 28. 実際の処理で感じたこと • メリット • 構文解析の木構造、グラフ構造に関するデータ処理がや りやすい • 小規模 大規模なプログラムまで耐えられる • Java との互換性があるおかげで、特に英語圏のライブラ リがけっこう使える • 並列化が楽 • デメリット • コンパイル速度が Java よりかなり遅い • 実行速度も Java に比べると遅いらしい 28
  29. 29. 実際の処理で感じたこと • メリット • 構文解析の木構造、グラフ構造に関するデータ処理がや りやすい • 小規模 大規模なプログラムまで耐えられる • Java との互換性があるおかげで、特に英語圏のライブラ リがけっこう使える • 並列化が楽 • デメリット • コンパイル速度が Java よりかなり遅い • 実行速度も Java に比べると遅いらしい (1 to 10000).par.sum 29

×