pei’s blog

情報系の大学を出たSE1年生。主にプログラミング(機械学習寄り)の話題を書いていきます。

久々に機械学習の論文読みました

From Social Media to Public Health Surveillance: Word Embedding based Clustering Method for Twitter Classification

という論文を読んだのでさらっと内容を紹介していきます。

 私は教師あり学習を使う機会が多く、教師なし学習が実際にどう用いられているのか知りたくて、とりあえずGoogle Scholarでテキトーに探してこの論文を読んで見ました。



内容

 ざっくりいうと「あるツイートが、指定したトピックに関連するかどうかを機械学習(クラスタリング)を用いて判別する」という内容です。

 この論文ではインフルエンザに関連するツイートかどうかを判別するという実験をしていました。

 クラスタリングとword2vecを知っていれば理解しやすい内容です。ちなみにデータセットは全て英語です。



手法

 基本的にはベクトル化はword2vec、類似度はコサイン類似度です。


  1. 1. ツイートの不要な情報の除去

  2.  ハッシュタグや@を除去


  3. 2. 単語を整形

  4.  URLやストップワードを除去、スペル間違えを修正、全て小文字に変換など...


  5. 3. 単語をベクトル化

  6.  word2vecを使ってベクトル化しています。word2vecは単語の意味を考慮しつつベクトル化表現する手法です(かなりざっくりですみません...)。
     詳しくはこちらを参照してください→自然言語処理に新風を巻き起こしたWord2Vecとは何か


  7. 4. クラスタリング

  8.  ツイート内の全単語を類似度の一番高いクラスタに追加する。クラスタを増やすかどうかは確率を用いたアルゴリズムを使用するが、だいたいクラスタ数は3〜5に収束する。


  9. 5. 分類

  10.  クラスタごとに単語ベクトルの平均を計算し、その平均ベクトルとベクトル化したトピックの類似度を計算。
     類似度が閾値より高ければそのトピックに関連したツイートだと判別する。閾値は0.5, 0.6が最適だった。



分類性能など

 インフルエンザに関連するツイートかどうかの分類性能を評価しています。テストデータは、関連するツイートが1200, そうでないツイートが1000個です。

 最適な閾値0.5, 0.6の結果は以下の通りです。各指標は詳しくはこちらを見てください→
抑えておきたい評価指標「正解率」「精度」「再現率」






精度 再現率 F値 正確性
閾値0.5 77.1% 95.7% 84.7% 84.6%
閾値0.6 96.2% 75.6% 84.6% 87.1%



感想

 閾値の決定は正解づけされたデータが必要でなので、やっぱり人の手が必要だな〜と感じました。

 英語の論文というとすごく難しそうだと思うかもしれませんが、そんなに難しいわけじゃないのでぜひみなさん読んでみてください!

VueJSで子コンポーネントにメソッドを渡す

 子コンポーネントにv-bind="{メソッド名}"を指定することで、props経由で親コンポーネントのメソッドを渡せます。

 ちなみに子コンポーネントで(this.)$parent.親メソッドでも実行できますが非推奨みたいです。
 $parentを使った直接参照はコンポーネント間の依存度を高めると思うのでできるだけ回避した方がいいですね。

 VueJSを使ってタスク管理のサンプルプログラムを書いたのでぜひ参考にしてください。
peiprog.hatenablog.com

parent.vue

<div id="app">
  <!-- v-bindでメソッドを子コンポーネントに渡す -->
  <child v-bind="{parentMethod}"></child>
</div>
<script>
  import Child from "./child.vue"

  new Vue({
    el: "#app",
    components: {
      // 子コンポーネント
      "child": Child
    },
    ...
  }
);
</script>
child.vue

<template>
  <div>
    <!-- 親コンポーネントのメソッド実行 -->
    <button @click="parentMethod">親コンポーネントのメソッド実行</button>
  </div>
</template>
<script>
  export default {
    // 親コンポーネントからprops経由でメソッドを受け取る
    props: ["parentMethod"],
    methods: {
      childMethod: function () {
        // 親コンポーネントのメソッド実行
        this.parentMethod();
      }
    }
  }
</script>

VueJSでタスク管理アプリを作ってみた。

 VueJSで簡単なタスク管理アプリを1ヶ月くらいちまちま作ってたので仕組みとか書いていきます。Herokuでテキトーにデプロイしました。
 VueJS初学者、仕組みなどが分からない人の参考になれば嬉しいです。


作ったWebアプリはこちら(herokuの無料枠のため時間がかかります)
http://vtodoapp.herokuapp.com/


ソースコードはこちら(VueJS関連のはapp/javascriptに入ってます)
github.com



仕組み


f:id:peiprog:20180303190941p:plain

 詳しい人に怒られそうな気がしますが、こんな感じです。間違ってたらぜひコメントください!
 サーバーとエンドユーザー間はJSONデータのみやりとりして、受け取ったJSONデータからVueJSがHTMLをレンダリングして、ユーザーにはそのHTMLが表示されるといった感じです。


フロントエンド側の仕組み


f:id:peiprog:20180303190630p:plain

 フロントエンド側は左の図のようになっています。他にも認証などのページはありますが、ただ入力フォーム出してPOSTしたり認証用トークンの処理とかなので省略します。
 例としてindex.vueについて説明します。index.vueはTODO一覧を表示するページです。出力するTODOのデータや検索条件、現在何ページ目なのか、などのデータを保持します。
 
 paging.vueはindex.vueが保持しているページ数・検索条件を使って指定したページにジャンプしたり、ページのリストを表示する"ページング処理"をします。
 指定したページへジャンプする処理はAPIサーバから検索条件とページ数を指定したTODOデータを取得して、index.vueにあるTODOのリストを更新することで再レンダリングするという感じです。
 
 searchbox.vueは検索ボックスの表示、検索の処理をします。検索ボックスで指定された条件を使ってTODOデータを取得して、index.vueにあるTODOのリストを更新することで再レンダリングします。

 sign_in_header.vueはログイン中の時のヘッダーを表し、TODO一覧と新規登録などで子コンポーネントとして利用します。ログアウト処理や各メニューへのリンクの表示をします。


感想

 やはりサーバー側でHTMLレンダリングする構成に比べて速いと感じました。特にサーバ側の処理能力が低いのでより効果を実感しました。
 今回はherokuだったため単一デプロイでした。RailsAPIサーバとVueJS、HTMLを置くHTTPサーバを分けると、より各構成の依存度が低くなると思います。
 ちなみに認証関連はDeviseというgemを使っており、テキストエリアはSimpleMDEで装飾してます。レイアウトはBootstrap、fontawesome、jQueryなど使ってます。

機械学習でテキスト分類器を作る


 今回は私が作った機械学習を使った教師ありデータを用いるテキスト分類器(ざっくりいうと例えばテキストがスパムかそうでないかを自動で識別するなど)のシステム構成について説明します。

 教師ありデータとは答えとデータがセットになっているデータのことです(例えばこのテキストはスパム、このテキストはスパムじゃないっていう答えがテキストと組みになったデータ)。

 機械学習を知らない人ややり始めたばかりの人の参考になれば嬉しいです。
 また、使うと容易に機能を実現できるライブラリについても書いておきました。

流れ


ドキュメントの下処理


ベクトル化


分類器を学習・推論


 全体の流れは右の図の通りです。
 ドキュメントの下処理とは、記号や数字など分類に不要な情報を取り除くことです。
 次にその下処理したドキュメントを分類器が処理できるようなデータの形に変換します。
 最後に分類器を学習させます。実際に分類する場合はここで推論を行います。
 ここからそれぞれの工程を詳しく見ていきます。
 データセットどうするの?とか交差検証など性能評価については長くなるので省略します。

ドキュメントの下処理

 ここでは単語に分割、記号・数字の除去、ストップワードの除去などを行います。ストップワードとは「私」、「です」、「ます」などの不要な情報です。
 単語の分割にはjanomeMeCabといったライブラリを用います。英語であればもともと単語の間に空白があるので分割が容易です。

ベクトル化



 前の段階で単語に分割され、不要な情報が除去されたデータをベクトル化します。ベクトル化の対象とする単語を選び、その単語をベクトル化(重み付け)します。今回は単語の順序を考えず出現回数のみを考えるBaf of Words手法を使います。

 ここのベクトル化の仕方で性能が非常に変わってしまいます。また、選ぶ単語の個数によって分類器全体の実行時間、性能が大きく変わります。
 単語の選び方、ベクトル化方法は右の表の通りです。今回は構成についての記事のため詳しいことは書きません。

 PythonであればsklearnのVectorizerを使うと簡単にTFIDFや出現確率のベクトルが生成できるのでおすすめです。

 相互情報量を使った単語の選び方とOkapi BM25については詳しく書いた記事があるのでそちらを見てください。
 ちなみに私が作ったシステムでは単語の選び方は相互情報量、ベクトル化はOkapi BM25+を使い、単語数を2000個にしました。

peiprog.hatenablog.com
peiprog.hatenablog.com

分類器の学習・推論

 前の段階でベクトル化したデータを分類器に学習・推論させます。今回は教師あり学習の手法を使います。これは答えとデータがセットになっているデータを使って学習する手法です(例えばこのテキストはスパム、このテキストはスパムじゃないっていう答えがテキストと組みになったデータ)。

 分類器にはBag of Words手法で生成したベクトルならベイジアンフィルタサポートベクターマシンSVM)、(全結合)ニューラルネットワークなどが使えます。それぞれの仕組みについては超長くなるので省略します。
 SVMベイジアンフィルタリングならsklearn、ニューラルネットワークならkerasなどを使うと容易に実現できます。

 ちなみに私は3層の全結合ニューラルネットワークを使いました。全結合層とDropout層、活性化関数を3層重ねたオーソドックス?なネットワーク構成です。


まとめ

 テキスト分類システムの構成についてざっくり書いてみました。
 工程が多く、ベクトル化にも様々な方法があったり、分類器も多くの種類があったり大変に見えますが、sklearnやtensorflowなど非常に便利なライブラリがあり容易にシステムが実現できるので是非手を動かして楽しんで見てください!



エッセンシャル思考を読みました。


 エッセンシャル思考という本を読んだので紹介します。仕事術・自己啓発本のようなジャンルの本です。

どんな本?

 ざっくりいうと広く浅くではなく、狭く深くで質を高めようという内容です。選ぶ・捨てる・手放す・削るのような言葉がキーワードです。
 それを実現するために主に以下のような力が必要になると述べられています。


  • 不要なことを断る技術
  •  不本意に引き受けるなら断る方が長期的に見て良い、本当に必要なことのみ引き受けるべきだと述べられている。不要なことを断れと言っても難しいが、上手な断り方についても紹介されている。

  • いらないことを捨てる技術
  •  そのためにも損切り、境界線の引き方が重要になる。絶対にイエスだと言い切れないならノーだ、今それがなければお金を出して(時間を割いて)手に入れるだろうか?などと基準を厳しくするなど方法についても書かれている。

  • トレードオフを受け入れる・本質的なことを選ぶ力
  •  何かを選ぶということは何かを捨てることだと受け入れる。もちろん情報の本質の掴み方についても説明されています。選ぶ力を発揮するには余裕をもつことや睡眠・孤独でいる時間・遊びなども重要と述べられている。

 自己啓発本にありがちな抽象的すぎる内容という訳ではなく、それぞれ実現するための方法や根拠についてもある程度具体的に書かれています。


個人的な感想

 私は情報科学系の技術が好きでなんでもできるようになろうと思って色んな技術に手を出した結果、詳しいと言えるような技術が一つもできなかったのでトレードオフを受け入れて軸となる技術を選択しなきゃな〜と感じました。

SQLのWHERE句の書き方による実行速度の違い

今回はSQLの書き方によって実行速度がどのくらい変わるのか簡単な実験をします。
最近バイトでSQLを書いている時、よく「WHERE句の記述の順序を変えたらどのくらいパフォーマンスが変わるのだろう?」と思っていたのでやってみました。


目次

  1. 準備
  2. 実験内容
  3. 結果・考察


準備

CREATE TABLE (id integer primary key autoincrement, name text, grade integer);

文字列型のname、数値型のgradeを持つ構造のテーブルを用意して、1,000,000件データを入れておきます。 nameは1つのアルファベット30文字を繋げた文字列を25種類(a〜y)生成します。gradeは0〜24までの数字を入れます。


実験内容

以下の2つのSQL文を比較します。

  1. SELECT * FROM SAMPLE_TABLE1 WHERE name = 'aaa...' AND grade = 1;
  2. SELECT * FROM SAMPLE_TABLE1 WHERE grade = 1 AND name = 'aaa...';

1.のSQL文は、最初にnameで文字列比較をして40,000件に絞り、その後にgradeで数値比較して1,600件に絞ります。すなわち、文字列比較回数は1,000,000回、数値比較回数は40,000回になります。

2.のSQL文は、最初にgradeで数値比較して40,000件に絞り、その後にnameで文字列比較して1,600件に絞ります。すなわち、文字列比較回数は40,000回、数値比較回数は1,000,000回になります。

数値より文字列の比較の方が処理時間は長くなるため、2つめの処理の方が速くなると予想されます。


結果・考察

結果は以下の通りです。100回試行した平均の数値です。

実行時間
SQL1 0.0776s
SQL2 0.0667s

2. の方が0.01速いことがわかり、やはりWHERE句の順序により実行速度が変わることが確認できました。どのくらい速くなるかはデータ構造次第ですが、文字数が増えれば比較処理時間が増えるのでより差が開くと考えられます。


参考書レビュー 詳解ディープラーニング

今回は詳解ディープラーニングのレビューについて書きます。※私個人の感想です。


ざっくり言うとどんな本?

ニューラルネットワークの道具としての使い方がわかり、なおかつ仕組みについても詳しくわかる本です。

目次

  • 前提知識
  • 内容
  • 特徴
  • 他の参考書との違い
  • 終わりに

  • 前提知識

    が必要だと思います。これらは一応ニューラルネットワークの内容の前に説明があります。ただ、微分偏微分は全くわからない人がこの本の説明のみで理解するのは厳しいと思います。


    内容

    Pythonの基本的な文法、微分線形代数の基礎から始まり、Numpy, Tensorflow, kerasなどライブラリについて、単純・多層パーセプトロンからLSTM, GRUを含む再帰ニューラルネットワークまで載っています。その他勾配消失、オーバーフィッティング問題など仕組み以外の周辺知識についても書かれています。


    特徴

    Early Stoppingや勾配消失問題の説明など周辺知識も多数載っています。また、実装の設計や学習の可視化などの記述もあり実用的な内容だと思います。また、畳み込みニューラルネットワーク(CNN)については載っていません。


    他の参考書との違い

    他に有名なニューラルネットワークの参考書はゼロから作るDeep Learningがあります。こちらは仕組みに特化しており実際にニューラルネットワークのライブラリ自体を手を動かして作るような内容です。一方、詳解ディープラーニングは仕組みも詳しく載ってますが、ライブラリを使った実装が書かれていてより実用的な内容だと思います。


    おわりに

    Tensorflow, kerasなどライブラリの使い方、再帰ニューラルネットワークについても載っており、私が知りたかったことが全部書いてあった本でした。個人的にはゼロから作るDeep Learningで仕組みを理解して、この本で周辺技術やライブラリを使った実装の仕方を学ぶと良いと思います。