<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:itunes="http://www.itunes.com/DTDs/Podcast-1.0.dtd">
  <channel>
    <title>Seesaa京都アプリエンジニアブログ</title>
    <link>https://seesaakyoto.seesaa.net/</link>
    <description>Seesaa京都でアプリ開発しているエンジニアが定期的につぶやきます。</description>
    <language>ja</language>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <itunes:subtitle></itunes:subtitle>
    <itunes:summary>Seesaa京都でアプリ開発しているエンジニアが定期的につぶやきます。</itunes:summary>
    <itunes:keywords></itunes:keywords>
    
    <itunes:author>Seesaa京都スタッフ</itunes:author>
    <itunes:owner>    
       <itunes:name></itunes:name>
       <itunes:email></itunes:email>
    </itunes:owner>
        <itunes:explicit>no</itunes:explicit>
        <item>
      <link>https://seesaakyoto.seesaa.net/article/467209243.html</link>
      <title>Swift For TensroFlow の発表を行いました</title>
      <pubDate>Mon, 17 Jun 2019 15:00:00 +0900</pubDate>
            <description>エモトです．最終章第二話はご覧になりましたか？私はまだ1回しか見れてません．引き続き通いたいと思ってます．前回記事にした Swift For TensorFlow を KyotoLT 第24回 にて発表しました．ブログ記事からちょこっと情報を足しました．Swift For TensorFlow は実用面や実務レベルでは難しいところはありますが，Swift で書けるという iOS エンジニアにはご褒美な開発環境なので，興味ある方はどうぞ．</description>
            <itunes:summary><![CDATA[
エモトです．最終章第二話はご覧になりましたか？私はまだ1回しか見れてません．引き続き通いたいと思ってます．

前回記事にした Swift For TensorFlow を <a href="https://kyotolt.connpass.com/event/132819/" target="_blank">KyotoLT 第24回</a> にて発表しました．ブログ記事からちょこっと情報を足しました．Swift For TensorFlow は実用面や実務レベルでは難しいところはありますが，Swift で書けるという iOS エンジニアにはご褒美な開発環境なので，興味ある方はどうぞ．

<a></a>

]]></itunes:summary>
      <content:encoded><![CDATA[
エモトです．最終章第二話はご覧になりましたか？私はまだ1回しか見れてません．引き続き通いたいと思ってます．<br /><br />前回記事にした Swift For TensorFlow を <ins><a href="https://kyotolt.connpass.com/event/132819/" target="_blank">KyotoLT 第24回</a></ins> にて発表しました．ブログ記事からちょこっと情報を足しました．Swift For TensorFlow は実用面や実務レベルでは難しいところはありますが，Swift で書けるという iOS エンジニアにはご褒美な開発環境なので，興味ある方はどうぞ．<br /><br /><script async class="speakerdeck-embed" data-id="1925862f4efa4711a9c7d85893536e94" data-ratio="1.77777777777778" src="//speakerdeck.com/assets/embed.js"></script><a name="more"></a>

]]><![CDATA[
]]></content:encoded>
            <category>機械学習</category>
      <author>Seesaa京都スタッフ</author>
      <guid isPermaLink="false">blog:https://blog.seesaa.jp,seesaakyoto/467209243</guid>
                </item>
        <item>
      <link>https://seesaakyoto.seesaa.net/article/465201045.html</link>
      <title>超入門 Swift for TensorFlow</title>
      <pubDate>Wed, 17 Apr 2019 16:00:00 +0900</pubDate>
            <description>エモトです．GWは引きこもろうと思ってます．深層学習のコードを書くときは，Python + TensorFlow を使っています．Python は書きやすい言語だと思いますが，コード量が増えてくると，もっとモダンな言語で描きたい，コンパイラが欲しいと思います．私が完璧にPythonを理解してないのもありますが，ちょっと他の言語に浮気しました．Swift For TensorFlowSwift for TensorFlow は，Python 向けに開発された数値計算ライブラリ ..</description>
            <itunes:summary><![CDATA[
エモトです．GWは引きこもろうと思ってます．


深層学習のコードを書くときは，Python + TensorFlow を使っています．Python は書きやすい言語だと思いますが，コード量が増えてくると，もっとモダンな言語で描きたい，コンパイラが欲しいと思います．私が完璧にPythonを理解してないのもありますが，ちょっと他の言語に浮気しました．

Swift For TensorFlow

<a href="https://www.tensorflow.org/swift" target="_blank">Swift for TensorFlow</a> は，Python 向けに開発された数値計算ライブラリ TensorFlow を Swift で利用することができます．一般的に多いラッパーではなく，Swift コンパイラを拡張したものになります．また，Swift は Python を使用することができるので，Python の豊富な数値計算ライブラリを使用できます．


インストール

公式サイトの <a href="https://github.com/tensorflow/swift/blob/master/Installation.md" target="_blank">Install Swift for TensorFlow</a> に従えばインストールできます．なお，最近Swift 5がリリースされましたが，最新版の Xcode  では上手くできず，Xcode 10.1 (Swift 4.2) で確認しました．

Google Colab を使おう

ローカル環境でインストール可能ですが，普段 iOS アプリ開発を行っていると，標準と拡張のコンパイラの管理が面倒になります．一先ずは，Google Colab を使用した方がおすすめです（ただし，補完などの補助機能がXcodeより貧弱なのが辛い）．

これも公式の <a href="https://github.com/tensorflow/swift/blob/master/Usage.md" target="_blank">Using Swift for TensorFlow</a> にて，Swiftが実行可能な <a href="https://colab.research.google.com/github/tensorflow/swift/blob/master/notebooks/blank_swift.ipynb" target="_blank">blank Swift notebook</a> が公開されているので，それを自身のドライブにコピーすれば，すぐに使えます．

以降のソースコードは，Colab上で動作確認したものです．

SwiftでPythonを使う

Swift for TensorFlow を使う前に，Swift 自体の機能で Python を使ってみました．Python の豊富な数値計算ライブラリを使用できます．SwiftでNumPyが動くのは，何か不思議な感じです．


import Python
PythonLibrary.useVersion(3, 6)

let np = Python.import("numpy")

let a = np.array([[1, 0], [0, 1]])
let b = np.array([[2], [3]])
let c = np.matmul(a, b)

Swift For TensorFlow を使ってみた


Swift For TensorFlow を使って，XOR を簡単な NN で学習しました．Keras もしくは TensorFlow2 を触っていれば，あまり違和感ない感じでした．



import Foundation
import TensorFlow

struct XOR: Layer {
  
  var layer1: Dense&lt;Float&gt;
  var layer2: Dense&lt;Float&gt;
  
  init(hiddenSize:Int = 2){
    self.layer1 = Dense(inputSize: 2,
                        outputSize: hiddenSize,
                        activation: sigmoid)
    self.layer2 = Dense(inputSize: hiddenSize,
                        outputSize: 1, 
                        activation: sigmoid)
  }
  
  @differentiable
  func applied(to input: Tensor&lt;Float&gt;, in context: Context) -&gt; Tensor&lt;Float&gt; {
    return input.sequenced(in: context, through: layer1, layer2)
    }
}

let x: Tensor&lt;Float&gt; = [[0, 0], [0, 1], [1, 0], [1, 1]]
let y: Tensor&lt;Float&gt; = [[0], [1], [1], [0]]

var model = XOR()
let optimizer = SGD&lt;XOR, Float&gt;(learningRate: 0.1)
let context = Context(learningPhase: .training)

for _ in 1...5000 {
  let dmodel = model.gradient { m -&gt; Tensor&lt;Float&gt; in
    let t = m.applied(to: x, in: context)
    let loss = sigmoidCrossEntropy(logits: t, labels: y)
    return loss
  }
  optimizer.update(&model.allDifferentiableVariables, along: dmodel)
}

let inference = round(model.inferring(from: x))
print(inference)

パフォーマンスは？

上記コードを Google Colab (CPU) で計算したところ，約13秒程度で終わりました．比較として，Python + TensorFlow2 (Keras) でもほぼ同様なモデルと学習方法で XOR を計算したところ，約6秒でした．コンパイラ言語であるSwiftの方が早いかと思いましたが，今回はPython版の方が早かったです．理由は分かりませんが，複雑な反復処理を行っていない，Swiftは複数のライブラリの読み込みがネックになった？のかなと．ColabのSwiftコンパイル時の最適化オプションなどは未調査です．

まとめ

Swift For TensorFlowを使用して，Swiftでも機械学習のコードを実装できました．まだまだPython版の方が良いかなと思いました．TensorFlow自体の更新頻度が高いうえに，Swiftもアップデートの頻度が高いので，安定性があるかは怪しいところです．また，入門エントリーが公式ぐらいしかないので，ちょっと調べ物は大変です．とはいえ，慣れたSwiftを使うことができる，実行する前にコンパイラが動くというメリットは感じました．

<a></a>

]]></itunes:summary>
      <content:encoded><![CDATA[
エモトです．GWは引きこもろうと思ってます．<br/><br/>


深層学習のコードを書くときは，Python + TensorFlow を使っています．Python は書きやすい言語だと思いますが，コード量が増えてくると，もっとモダンな言語で描きたい，コンパイラが欲しいと思います．私が完璧にPythonを理解してないのもありますが，ちょっと他の言語に浮気しました．<br/><br/>

<span style="font-size:large;"><strong>Swift For TensorFlow</strong></span><br/><br/>

<ins><a href="https://www.tensorflow.org/swift" target="_blank">Swift for TensorFlow</a></ins> は，Python 向けに開発された数値計算ライブラリ TensorFlow を Swift で利用することができます．一般的に多いラッパーではなく，Swift コンパイラを拡張したものになります．また，Swift は Python を使用することができるので，Python の豊富な数値計算ライブラリを使用できます．
<br/><br/>

<strong>インストール</strong><br/><br/>

公式サイトの <ins><a href="https://github.com/tensorflow/swift/blob/master/Installation.md" target="_blank">Install Swift for TensorFlow</a></ins> に従えばインストールできます．なお，最近Swift 5がリリースされましたが，最新版の Xcode  では上手くできず，Xcode 10.1 (Swift 4.2) で確認しました．<br/><br/>

<strong>Google Colab を使おう</strong><br/><br/>

ローカル環境でインストール可能ですが，普段 iOS アプリ開発を行っていると，標準と拡張のコンパイラの管理が面倒になります．一先ずは，Google Colab を使用した方がおすすめです（ただし，補完などの補助機能がXcodeより貧弱なのが辛い）．<br/><br/>

これも公式の <ins><a href="https://github.com/tensorflow/swift/blob/master/Usage.md" target="_blank">Using Swift for TensorFlow</a></ins> にて，Swiftが実行可能な <ins><a href="https://colab.research.google.com/github/tensorflow/swift/blob/master/notebooks/blank_swift.ipynb" target="_blank">blank Swift notebook</a></ins> が公開されているので，それを自身のドライブにコピーすれば，すぐに使えます．<br/><br/>

以降のソースコードは，Colab上で動作確認したものです．<br/><br/>

<strong><span style="font-size:large;">SwiftでPythonを使う</span></strong><br/><br/>

Swift for TensorFlow を使う前に，Swift 自体の機能で Python を使ってみました．Python の豊富な数値計算ライブラリを使用できます．SwiftでNumPyが動くのは，何か不思議な感じです．

<pre class="brush: python3">
import Python
PythonLibrary.useVersion(3, 6)

let np = Python.import("numpy")

let a = np.array([[1, 0], [0, 1]])
let b = np.array([[2], [3]])
let c = np.matmul(a, b)</pre><br/>

<strong><span style="font-size:large;">Swift For TensorFlow を使ってみた</span></strong><br/><br/>


Swift For TensorFlow を使って，XOR を簡単な NN で学習しました．Keras もしくは TensorFlow2 を触っていれば，あまり違和感ない感じでした．


<pre class="brush: oc">
import Foundation
import TensorFlow

struct XOR: Layer {
  
  var layer1: Dense&lt;Float&gt;
  var layer2: Dense&lt;Float&gt;
  
  init(hiddenSize:Int = 2){
    self.layer1 = Dense(inputSize: 2,
                        outputSize: hiddenSize,
                        activation: sigmoid)
    self.layer2 = Dense(inputSize: hiddenSize,
                        outputSize: 1, 
                        activation: sigmoid)
  }
  
  @differentiable
  func applied(to input: Tensor&lt;Float&gt;, in context: Context) -> Tensor&lt;Float&gt; {
    return input.sequenced(in: context, through: layer1, layer2)
    }
}

let x: Tensor&lt;Float&gt; = [[0, 0], [0, 1], [1, 0], [1, 1]]
let y: Tensor&lt;Float&gt; = [[0], [1], [1], [0]]

var model = XOR()
let optimizer = SGD&lt;XOR, Float&gt;(learningRate: 0.1)
let context = Context(learningPhase: .training)

for _ in 1...5000 {
  let dmodel = model.gradient { m -> Tensor&lt;Float&gt; in
    let t = m.applied(to: x, in: context)
    let loss = sigmoidCrossEntropy(logits: t, labels: y)
    return loss
  }
  optimizer.update(&model.allDifferentiableVariables, along: dmodel)
}

let inference = round(model.inferring(from: x))
print(inference)</pre><br/>

<strong>パフォーマンスは？</strong><br/><br/>

上記コードを Google Colab (CPU) で計算したところ，約13秒程度で終わりました．比較として，Python + TensorFlow2 (Keras) でもほぼ同様なモデルと学習方法で XOR を計算したところ，約6秒でした．コンパイラ言語であるSwiftの方が早いかと思いましたが，今回はPython版の方が早かったです．理由は分かりませんが，複雑な反復処理を行っていない，Swiftは複数のライブラリの読み込みがネックになった？のかなと．ColabのSwiftコンパイル時の最適化オプションなどは未調査です．<br/><br/>

<span style="font-size:large;"><strong>まとめ</strong></span><br/><br/>

Swift For TensorFlowを使用して，Swiftでも機械学習のコードを実装できました．まだまだPython版の方が良いかなと思いました．TensorFlow自体の更新頻度が高いうえに，Swiftもアップデートの頻度が高いので，安定性があるかは怪しいところです．また，入門エントリーが公式ぐらいしかないので，ちょっと調べ物は大変です．とはいえ，慣れたSwiftを使うことができる，実行する前にコンパイラが動くというメリットは感じました．

<a name="more"></a>

]]><![CDATA[
]]></content:encoded>
            <category>iOS</category>
      <author>Seesaa京都スタッフ</author>
      <guid isPermaLink="false">blog:https://blog.seesaa.jp,seesaakyoto/465201045</guid>
                </item>
        <item>
      <link>https://seesaakyoto.seesaa.net/article/464519007.html</link>
      <title>Swift でもRuntime Exceptionキャッチがしたい</title>
      <pubDate>Fri, 08 Mar 2019 12:00:00 +0900</pubDate>
            <description>エモトです．先日「翔んで埼玉」を見ました．京都も海がないのでよくわかります．中京区民なので洛外のことはよく分かりません．先日，KyotoLT 第23回 にて，「Swift でもRuntime Exceptionキャッチがしたい」というタイトルで発表しました．Swiftがリリースされた当初，「あれ？try-catchがない？」とモヤモヤしてました．後に実装された例外（エラー）処理を見て，「あれ？Objective-Cのときのような多様性がないぞ」とさらにモヤモヤしたことを覚えて..</description>
            <itunes:summary><![CDATA[
エモトです．先日「翔んで埼玉」を見ました．京都も海がないのでよくわかります．中京区民なので洛外のことはよく分かりません．

先日，<a href="https://kyotolt.connpass.com/event/118256/" target="_blank">KyotoLT 第23回</a> にて，「Swift でもRuntime Exceptionキャッチがしたい」というタイトルで発表しました．

Swiftがリリースされた当初，「あれ？try-catchがない？」とモヤモヤしてました．後に実装された例外（エラー）処理を見て，「あれ？Objective-Cのときのような多様性がないぞ」とさらにモヤモヤしたことを覚えています．ランタイム例外が起こらないように実装するのが良いですが，あるなら保険として用意しておきたい．ある冬の夜の四条を歩いているとき，「あれ？Objective-Cを経由したらSwiftでもランタイム例外がキャッチできるんじゃね？」と色々やったことを発表しました．



Swiftでも色々やればランタイム例外は取得できました（実用的かは別として）．より詳細はQiitaに投稿しています．ご興味があれば，「<a href="https://qiita.com/mitsuharu_e/items/9e149447d49c0786d814" target="_blank">Swift の Runtime Exception はキャッチできるのかと試したこと - Qiita</a>」をどうぞ．サンプルコードをGitHubにて公開しております．Swiftでもランタイム例外をキャッチしたい方は <a href="https://github.com/mitsuharu/demo_swift_catches_exceptions" target="_blank">mitsuharu/demo_swift_catches_exceptions</a> もどうぞ．

<a></a>

]]></itunes:summary>
      <content:encoded><![CDATA[
エモトです．先日「翔んで埼玉」を見ました．京都も海がないのでよくわかります．中京区民なので洛外のことはよく分かりません．<br /><br />先日，<ins><a href="https://kyotolt.connpass.com/event/118256/" target="_blank">KyotoLT 第23回</a></ins> にて，「Swift でもRuntime Exceptionキャッチがしたい」というタイトルで発表しました．<br /><br />Swiftがリリースされた当初，「あれ？try-catchがない？」とモヤモヤしてました．後に実装された例外（エラー）処理を見て，「あれ？Objective-Cのときのような多様性がないぞ」とさらにモヤモヤしたことを覚えています．ランタイム例外が起こらないように実装するのが良いですが，あるなら保険として用意しておきたい．ある冬の夜の四条を歩いているとき，「あれ？Objective-Cを経由したらSwiftでもランタイム例外がキャッチできるんじゃね？」と色々やったことを発表しました．<br /><br /><script async class="speakerdeck-embed" data-id="5809666f35094222813d764f9cec42d5" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"></script><br /><br />Swiftでも色々やればランタイム例外は取得できました（実用的かは別として）．より詳細はQiitaに投稿しています．ご興味があれば，「<ins><a href="https://qiita.com/mitsuharu_e/items/9e149447d49c0786d814" target="_blank">Swift の Runtime Exception はキャッチできるのかと試したこと - Qiita</a></ins>」をどうぞ．サンプルコードをGitHubにて公開しております．Swiftでもランタイム例外をキャッチしたい方は <ins><a href="https://github.com/mitsuharu/demo_swift_catches_exceptions" target="_blank">mitsuharu/demo_swift_catches_exceptions</a></ins> もどうぞ．<br /><br /><a name="more"></a>

]]><![CDATA[
]]></content:encoded>
            <category>iOS</category>
      <author>Seesaa京都スタッフ</author>
      <guid isPermaLink="false">blog:https://blog.seesaa.jp,seesaakyoto/464519007</guid>
                </item>
        <item>
      <link>https://seesaakyoto.seesaa.net/article/463090674.html</link>
      <title>京都DevかふぇでiOSアプリ開発の昔話をしてきました</title>
      <pubDate>Thu, 06 Dec 2018 18:00:00 +0900</pubDate>
            <description>エモトです。近々公開のドラゴンボール映画のために，スーパーを見直してます．先日，フリュー株式会社さんが主催の勉強会 京都Devかふぇ#4 〜レガシーシステム考古学〜  にて発表してきました．テーマがレガシーということで『iPhone OSアプリ開発の昔話』というタイトルで，まだiPhone OSだったころからのアプリ開発話をしてきました．資料作成で改めて，昔の開発を思い出すと，だいぶ苦労してたなーと．</description>
            <itunes:summary><![CDATA[
エモトです。近々公開のドラゴンボール映画のために，スーパーを見直してます．

先日，フリュー株式会社さんが主催の勉強会 <a href="https://kyoto-dev-cafe.connpass.com/event/107535/" target="_blank">京都Devかふぇ#4 〜レガシーシステム考古学〜 </a> にて発表してきました．テーマがレガシーということで『iPhone OSアプリ開発の昔話』というタイトルで，まだiPhone OSだったころからのアプリ開発話をしてきました．資料作成で改めて，昔の開発を思い出すと，だいぶ苦労してたなーと．

<a></a>

]]></itunes:summary>
      <content:encoded><![CDATA[
エモトです。近々公開のドラゴンボール映画のために，スーパーを見直してます．<br /><br />先日，フリュー株式会社さんが主催の勉強会 <ins><a href="https://kyoto-dev-cafe.connpass.com/event/107535/" target="_blank" rel="noopener">京都Devかふぇ#4 〜レガシーシステム考古学〜 </a></ins> にて発表してきました．テーマがレガシーということで『iPhone OSアプリ開発の昔話』というタイトルで，まだiPhone OSだったころからのアプリ開発話をしてきました．資料作成で改めて，昔の開発を思い出すと，だいぶ苦労してたなーと．<br /><br /><script async class="speakerdeck-embed" data-id="6001916e83344cf2a82c121e0ebb2af7" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"></script><a name="more"></a>

]]><![CDATA[
]]></content:encoded>
            <category>iOS</category>
      <author>Seesaa京都スタッフ</author>
      <guid isPermaLink="false">blog:https://blog.seesaa.jp,seesaakyoto/463090674</guid>
                </item>
        <item>
      <link>https://seesaakyoto.seesaa.net/article/462682996.html</link>
      <title>「自然言語と機械学習（その２）」を発表しました</title>
      <pubDate>Mon, 12 Nov 2018 11:35:41 +0900</pubDate>
            <description>エモトです。今週はついにポケモン新作の発売ですね．赤緑世代なので，そわそわしてます．またまた，運営協力している Kyoto.LT 第22回 にて『自然言語と機械学習（その２）「ランダムな文字列を判定したい」』というタイトルで発表しました。以前と同じ自然言語をテーマにした発表です．ランダム文字列をどうすれば判定・評価できるかを苦労した話になります．</description>
            <itunes:summary><![CDATA[
エモトです。今週はついにポケモン新作の発売ですね．赤緑世代なので，そわそわしてます．

またまた，運営協力している <a href="https://kyotolt.connpass.com/event/105374/" target="_blank">Kyoto.LT 第22回</a> にて『自然言語と機械学習（その２）「ランダムな文字列を判定したい」』というタイトルで発表しました。以前と同じ自然言語をテーマにした発表です．ランダム文字列をどうすれば判定・評価できるかを苦労した話になります．

<a></a>

]]></itunes:summary>
      <content:encoded><![CDATA[
エモトです。今週はついにポケモン新作の発売ですね．赤緑世代なので，そわそわしてます．<br /><br />またまた，運営協力している <ins><a href="https://kyotolt.connpass.com/event/105374/" target="_blank">Kyoto.LT 第22回</a></ins> にて『自然言語と機械学習（その２）「ランダムな文字列を判定したい」』というタイトルで発表しました。以前と同じ自然言語をテーマにした発表です．ランダム文字列をどうすれば判定・評価できるかを苦労した話になります．<br /><br /><script async class="speakerdeck-embed" data-id="7bb7058b6c244ca2b6c927450b693dff" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"></script><a name="more"></a>

]]><![CDATA[
]]></content:encoded>
            <category>機械学習</category>
      <author>Seesaa京都スタッフ</author>
      <guid isPermaLink="false">blog:https://blog.seesaa.jp,seesaakyoto/462682996</guid>
                </item>
        <item>
      <link>https://seesaakyoto.seesaa.net/article/461482670.html</link>
      <title>iOSDC Japan 2018に参加しました</title>
      <pubDate>Tue, 04 Sep 2018 16:49:19 +0900</pubDate>
            <description>エモトです．最近は機械学習ばかりやっていますが，元々はiOSアプリ開発をやっております．2018年8月30日（木）から9月2日（日）まで iOSDC Japan 2018 に京都から参加しました．京都では大規模なカンファレンスがあまりないので，こういう大きなイベントはすごく楽しいです．内容も充実していて，とても刺激的でした．いろいろ興味深い発表がありましたが，考えされられたのは，Ray Fixさんの「アルゴリズムを通じてよりよいアプリを」です．私のiOSアプリ開発は3GSから..</description>
            <itunes:summary><![CDATA[
エモトです．最近は機械学習ばかりやっていますが，元々はiOSアプリ開発をやっております．

2018年8月30日（木）から9月2日（日）まで <a href="https://iosdc.jp/2018/" target="_blank">iOSDC Japan 2018</a> に京都から参加しました．京都では大規模なカンファレンスがあまりないので，こういう大きなイベントはすごく楽しいです．内容も充実していて，とても刺激的でした．

いろいろ興味深い発表がありましたが，考えされられたのは，Ray Fixさんの「<a href="https://fortee.jp/iosdc-japan-2018/proposal/8ec9fea5-2224-4da2-b43c-45783dd83537" target="_blank">アルゴリズムを通じてよりよいアプリを</a>」です．私のiOSアプリ開発は3GSからで，当時はその低スペックに悩まされて慎重に開発していました．最近はスペックも上がり，マシンパワーに頼って簡単なプログラムで計算負荷を犠牲にしたコードを書いたこともあります．しかし，やっぱり速いアルゴリムは重要ですよね．以前はiPhone 4s基準で開発してたんですが，4sのOSアップデートが終わったので，今はちょっと良いスペックで検証してました．当時を思い出しました．意識を改めて，5系やiPod touchでもアルゴリズムから動きが早いアプリを作っていきたいです．

最後に，Ray Fixさんをはじめ発表者のみなさま，運営のみなさま，本当に楽しいカンファレンスをありがとうございました．<a></a>

]]></itunes:summary>
      <content:encoded><![CDATA[
エモトです．最近は機械学習ばかりやっていますが，元々はiOSアプリ開発をやっております．<br /><br />2018年8月30日（木）から9月2日（日）まで <a href="https://iosdc.jp/2018/" target="_blank"><ins>iOSDC Japan 2018</ins></a> に京都から参加しました．京都では大規模なカンファレンスがあまりないので，こういう大きなイベントはすごく楽しいです．内容も充実していて，とても刺激的でした．<br /><br />いろいろ興味深い発表がありましたが，考えされられたのは，Ray Fixさんの「<a href="https://fortee.jp/iosdc-japan-2018/proposal/8ec9fea5-2224-4da2-b43c-45783dd83537" target="_blank"><ins>アルゴリズムを通じてよりよいアプリを</ins></a>」です．私のiOSアプリ開発は3GSからで，当時はその低スペックに悩まされて慎重に開発していました．最近はスペックも上がり，マシンパワーに頼って簡単なプログラムで計算負荷を犠牲にしたコードを書いたこともあります．しかし，やっぱり速いアルゴリムは重要ですよね．以前はiPhone 4s基準で開発してたんですが，4sのOSアップデートが終わったので，今はちょっと良いスペックで検証してました．当時を思い出しました．意識を改めて，5系やiPod touchでもアルゴリズムから動きが早いアプリを作っていきたいです．<br /><br />最後に，Ray Fixさんをはじめ発表者のみなさま，運営のみなさま，本当に楽しいカンファレンスをありがとうございました．<a name="more"></a>

]]><![CDATA[
]]></content:encoded>
            <category>iOS</category>
      <author>Seesaa京都スタッフ</author>
      <guid isPermaLink="false">blog:https://blog.seesaa.jp,seesaakyoto/461482670</guid>
                </item>
        <item>
      <link>https://seesaakyoto.seesaa.net/article/460931681.html</link>
      <title>「自然言語と機械学習」という題目で発表しました</title>
      <pubDate>Mon, 06 Aug 2018 12:00:00 +0900</pubDate>
            <description>エモトです。先日「カメラを止めるな！」を見てきました。なんか評判がいいホラー映画？自主映画？程度の知識で見に行きましたが、ど肝を抜かれました。前半で感じた幾つもの違和感は、後半でそれぞれ拾われていく。「まじかーそうだったのかー」と面白い。あとカメアシの赤メガネがかわいいです。上映館が増えているようなので、みなさん見るのをおすすめします。運営協力している Kyoto.LT 第21回 にて「自然言語と機械学習」というタイトルで発表しました。自然言語と銘打ってますが、これまでの経験..</description>
            <itunes:summary><![CDATA[
エモトです。先日「カメラを止めるな！」を見てきました。なんか評判がいいホラー映画？自主映画？程度の知識で見に行きましたが、ど肝を抜かれました。前半で感じた幾つもの違和感は、後半でそれぞれ拾われていく。「まじかーそうだったのかー」と面白い。あとカメアシの赤メガネがかわいいです。上映館が増えているようなので、みなさん見るのをおすすめします。

運営協力している <a href="https://kyotolt.connpass.com/event/93043/" target="_blank">Kyoto.LT 第21回</a> にて「自然言語と機械学習」というタイトルで発表しました。自然言語と銘打ってますが、これまでの経験を元に計算用にデータ化する場合にどうするかを簡単にまとめました。後半はその特徴量を用いて、RCNNでレーティング分類をした分類実験を簡単に紹介しています。

<a></a>

]]></itunes:summary>
      <content:encoded><![CDATA[
エモトです。先日「カメラを止めるな！」を見てきました。なんか評判がいいホラー映画？自主映画？程度の知識で見に行きましたが、ど肝を抜かれました。前半で感じた幾つもの違和感は、後半でそれぞれ拾われていく。「まじかーそうだったのかー」と面白い。あとカメアシの赤メガネがかわいいです。上映館が増えているようなので、みなさん見るのをおすすめします。<br /><br />運営協力している <ins><a href="https://kyotolt.connpass.com/event/93043/" target="_blank">Kyoto.LT 第21回</a></ins> にて「自然言語と機械学習」というタイトルで発表しました。自然言語と銘打ってますが、これまでの経験を元に計算用にデータ化する場合にどうするかを簡単にまとめました。後半はその特徴量を用いて、RCNNでレーティング分類をした分類実験を簡単に紹介しています。<br /><br /><script async class="speakerdeck-embed" data-id="27567b541fc54725a5f1423f8827e856" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"></script><a name="more"></a>

]]><![CDATA[
]]></content:encoded>
            <category>機械学習</category>
      <author>Seesaa京都スタッフ</author>
      <guid isPermaLink="false">blog:https://blog.seesaa.jp,seesaakyoto/460931681</guid>
                </item>
        <item>
      <link>https://seesaakyoto.seesaa.net/article/460597412.html</link>
      <title>ランダムフォレストを使って分類してみた</title>
      <pubDate>Fri, 20 Jul 2018 12:00:00 +0900</pubDate>
            <description>エモトです．暑い日が続きますね．暑いのが苦手なので一苦労です．さて先週ポケモン映画を行きました．テレビ版は最近見なくなってしまったのですが，劇版特有のパラレル設定のおかげで「関係性がわからん」といこともなくサクッと見れました．次はあの名作のリメイク，これは赤緑世代なのでいまから楽しみです．今回はランダムフォレスト（Random Forest，以下RF）についてです．RFは，簡単に言うと複数の決定木を束ねたものになります．精度も高く，回帰や分類に使用されてます．いま深層学習が流..</description>
            <itunes:summary><![CDATA[
エモトです．暑い日が続きますね．暑いのが苦手なので一苦労です．さて先週ポケモン映画を行きました．テレビ版は最近見なくなってしまったのですが，劇版特有のパラレル設定のおかげで「関係性がわからん」といこともなくサクッと見れました．次はあの名作のリメイク，これは赤緑世代なのでいまから楽しみです．


今回はランダムフォレスト（Random Forest，以下RF）についてです．RFは，簡単に言うと複数の決定木を束ねたものになります．精度も高く，回帰や分類に使用されてます．いま深層学習が流行っていますが，すべてが深層学習に適しているとは限りません．まずはRFで検証するのも良いアプローチだと思います．



以下，RFの分類についての実装を紹介します（エラーや例外の処理は省いています）．今回も <a href="http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html" target="_blank">scikit-learn</a> を使って行きます．まずは必要な import をまとめておきます．


from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
from sklearn.metrics import f1_score
from sklearn.metrics import confusion_matrix
from sklearn.externals import joblib


学習です．特に難しいことはなく，訓練データの入出力データを渡して学習させます．データ規模も特別大きくなければ，学習は短時間で行われると思います．また学習したRFはファイルに保存しています．


def train_random_forest(x_train, y_train, save_name: str):

    # RFの定義
    forest = RandomForestClassifier(n_estimators=100, n_jobs=-1)

    # 学習
    forest.fit(x_train, y_train)

    # 保存
    joblib.dump(forest, save_name, compress=True)

    return forest


学習したRFの予測値や精度をテスト（検証）します．また，RFは入力データの特徴量の重要度を求めることができます．あまり重要度が高くない特徴量は入力データから削除して，より効率化を行うことができます．下記例では，特徴量名は適当に設定しているので実際は自信の環境に合わせる必要があります．


def test_random_forest(x_test, y_test, model_name: str):

    # RFの読み込み
    forest = joblib.load(model_name)

    # 予測データの作成
    y_predict = forest.predict(x_test)
    y_proba = forest.predict_proba(x_test)

    # 正解率
    acc_score = accuracy_score(y_test, y_predict)
    print("acc: {}".format(acc_score))

    # F値と混同行列
    f1_sc = f1_score(y_test, y_predict)
    conf_mat = confusion_matrix(y_test, y_predict)
    print('f1 score: {}'.format(f1_sc))
    print('Confusion matrix: {}'.format(conf_mat))

    # 特徴量の重要度
    # 特徴量名があればさらに見やすい結果になります
    # ここで定義した特徴量名は適当です
    feature_names = ["feature0", "feature1", "feature2"]
    importances = forest.feature_importances_
    for (f, i) in zip(feature_names, importances):
        print("{}, {}".format(f, i))


また，RFに関わらず，不均衡データを取り扱う場合は注意が必要です．不均衡が大きければ，データ数が多いクラスに影響され学習されます．一見精度は高くなりますがF値が下がった結果になり，実用できるレベルにはなりません．前処理として，データを調整するのもありますが，RFには不均衡データ向けの学習オプションがあります．


forest = RandomForestClassifier(class_weight="balanced")


しかしながら，あまり変化があるようには見えませんでした．リンク先を失念していまいましたが，内部実装からもあまり効果ないという記事を見たことがあります．また，別の方法として，<a href="http://contrib.scikit-learn.org/imbalanced-learn/stable/generated/imblearn.ensemble.BalancedBaggingClassifier.html" target="_blank">imbalanced-learn</a> のRFを使用する方法もあります．


from imblearn.ensemble import BalancedBaggingClassifier
forest = BalancedBaggingClassifier(n_estimators=100,n_jobs=-1)


これは scikit-learn とほぼほぼ同じメソッドや変数が使用できるので簡単に入れ替えができます（ただ，特徴量の重要度がなかったと思います）．ちなみに，私が検証したデータだと，これを使用しても大きく結果が変わることはありませんでした．前処理でデータ割合を調整するのが最も効果がありました．


<a></a>

]]></itunes:summary>
      <content:encoded><![CDATA[
エモトです．暑い日が続きますね．暑いのが苦手なので一苦労です．さて先週ポケモン映画を行きました．テレビ版は最近見なくなってしまったのですが，劇版特有のパラレル設定のおかげで「関係性がわからん」といこともなくサクッと見れました．次はあの名作のリメイク，これは赤緑世代なのでいまから楽しみです．
<br/><br/>

今回はランダムフォレスト（Random Forest，以下RF）についてです．RFは，簡単に言うと複数の決定木を束ねたものになります．精度も高く，回帰や分類に使用されてます．いま深層学習が流行っていますが，すべてが深層学習に適しているとは限りません．まずはRFで検証するのも良いアプローチだと思います．

<br/><br/>

以下，RFの分類についての実装を紹介します（エラーや例外の処理は省いています）．今回も <ins><a href="http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html" target="_blank">scikit-learn</a></ins> を使って行きます．まずは必要な import をまとめておきます．

<pre class="brush: py3">
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
from sklearn.metrics import f1_score
from sklearn.metrics import confusion_matrix
from sklearn.externals import joblib
</pre>

学習です．特に難しいことはなく，訓練データの入出力データを渡して学習させます．データ規模も特別大きくなければ，学習は短時間で行われると思います．また学習したRFはファイルに保存しています．

<pre class="brush: py3">
def train_random_forest(x_train, y_train, save_name: str):

    # RFの定義
    forest = RandomForestClassifier(n_estimators=100, n_jobs=-1)

    # 学習
    forest.fit(x_train, y_train)

    # 保存
    joblib.dump(forest, save_name, compress=True)

    return forest
</pre>

学習したRFの予測値や精度をテスト（検証）します．また，RFは入力データの特徴量の重要度を求めることができます．あまり重要度が高くない特徴量は入力データから削除して，より効率化を行うことができます．下記例では，特徴量名は適当に設定しているので実際は自信の環境に合わせる必要があります．

<pre class="brush: py3">
def test_random_forest(x_test, y_test, model_name: str):

    # RFの読み込み
    forest = joblib.load(model_name)

    # 予測データの作成
    y_predict = forest.predict(x_test)
    y_proba = forest.predict_proba(x_test)

    # 正解率
    acc_score = accuracy_score(y_test, y_predict)
    print("acc: {}".format(acc_score))

    # F値と混同行列
    f1_sc = f1_score(y_test, y_predict)
    conf_mat = confusion_matrix(y_test, y_predict)
    print('f1 score: {}'.format(f1_sc))
    print('Confusion matrix: {}'.format(conf_mat))

    # 特徴量の重要度
    # 特徴量名があればさらに見やすい結果になります
    # ここで定義した特徴量名は適当です
    feature_names = ["feature0", "feature1", "feature2"]
    importances = forest.feature_importances_
    for (f, i) in zip(feature_names, importances):
        print("{}, {}".format(f, i))
</pre>

また，RFに関わらず，不均衡データを取り扱う場合は注意が必要です．不均衡が大きければ，データ数が多いクラスに影響され学習されます．一見精度は高くなりますがF値が下がった結果になり，実用できるレベルにはなりません．前処理として，データを調整するのもありますが，RFには不均衡データ向けの学習オプションがあります．

<pre class="brush: py3">
forest = RandomForestClassifier(class_weight="balanced")
</pre>

しかしながら，あまり変化があるようには見えませんでした．リンク先を失念していまいましたが，内部実装からもあまり効果ないという記事を見たことがあります．また，別の方法として，<a href="http://contrib.scikit-learn.org/imbalanced-learn/stable/generated/imblearn.ensemble.BalancedBaggingClassifier.html" target="_blank"><ins>imbalanced-learn</ins></a> のRFを使用する方法もあります．

<pre class="brush: py3">
from imblearn.ensemble import BalancedBaggingClassifier
forest = BalancedBaggingClassifier(n_estimators=100,n_jobs=-1)
</pre>

これは scikit-learn とほぼほぼ同じメソッドや変数が使用できるので簡単に入れ替えができます（ただ，特徴量の重要度がなかったと思います）．ちなみに，私が検証したデータだと，これを使用しても大きく結果が変わることはありませんでした．前処理でデータ割合を調整するのが最も効果がありました．


<a name="more"></a>

]]><![CDATA[
]]></content:encoded>
            <category>機械学習</category>
      <author>Seesaa京都スタッフ</author>
      <guid isPermaLink="false">blog:https://blog.seesaa.jp,seesaakyoto/460597412</guid>
                </item>
        <item>
      <link>https://seesaakyoto.seesaa.net/article/459948239.html</link>
      <title>Pythonで自作ライブラリのパスを設定する</title>
      <pubDate>Fri, 15 Jun 2018 12:00:00 +0900</pubDate>
            <description>エモトです．みなさまDP2はご覧になりましたでしょうか．こまけぇことはいいんだよのAAがよく似合うエピローグ（いや全編でか），これが映画なんだよと圧巻でした．※文末に追記ありPythonに限らず，作成したメソッドやライブラリを他の自プロジェクトに使いたいことはあると思います．今回はそんなときのお話です．ライブラリを公開して，pip コマンドでインストール可能にすれば便利ですが，一般公開するまでもないものや，公開してはダメなものもあるので，今回はローカル環境でパスを設定します．..</description>
            <itunes:summary><![CDATA[
エモトです．みなさまDP2はご覧になりましたでしょうか．こまけぇことはいいんだよのAAがよく似合うエピローグ（いや全編でか），これが映画なんだよと圧巻でした．


※文末に追記あり



Pythonに限らず，作成したメソッドやライブラリを他の自プロジェクトに使いたいことはあると思います．今回はそんなときのお話です．



ライブラリを公開して，pip コマンドでインストール可能にすれば便利ですが，一般公開するまでもないものや，公開してはダメなものもあるので，今回はローカル環境でパスを設定します．



PYTHONPATH を設定すればできるようですが，私の環境は pyenv で作成しているのか，うまく反映されませんでした．



$ export PYTHONPATH="hogehoge/mylib"


そこで，すでにパスが通っているところに pthファイル を置いて，新たにパスを設定します．それらのパスは以下のようにして確認できます．


import sys
for path in sys.path:
  print(path)


pthファイルは site-packages に保存します．私の環境では以下のパスになりました．


/Users/user/.pyenv/versions/3.6.1/lib/python3.6/site-packages


次に，pth ファイル名を mylib.pth，設定したいパスを hogehoge/mylib としたとき，以下のようにすれば pth ファイルを追加できます．


pth_file = "mylib.pth"
pth_body = "hogehoge/mylib"
for path in sys.path:
  if ".pyenv" in path and path.endswith("site-packages") is True:
    save_path = os.path.join(path, pth_file)
    with open(save_path, "w") as f:
      f.write(pth_body)


また，ファイル追加をしたら，削除も用意した方もいいでしょう．ここは簡単にコマンドラインの引数から，削除を追加しました．


# $ python add_pth_file.py delete
if len(args) &gt; 1 and args[1] == "delete":
  if os.path.exists(save_path):
    os.remove(save_path)



いまのところ，他プロジェクトでも使うライブラリは，このpthファイル作成と一緒に1つのリポジトリに入れて管理しています．新しい環境でも，gitクローンしたらパス追加コマンドを使えば，簡単にライブラリが使えるようになります．また，パス指定のところでディレクトリ位置を動的に取得して反映するように変更し，クローンを行うディレクトリに依存しないようにしています．



（追記）最近，PyPIに自作パッケージを登録したことで気づいてしまいました（今さらやっと）．このパスを設定せずとも，プライベートのライブラリをPyPI登録直前まで用意して，ローカルでpip installした方がインストールと管理が簡単ですね．プライベートのライブラリをプライベートのgit環境でメンテしておけばアップデートも管理しやすい．

<a></a>

]]></itunes:summary>
      <content:encoded><![CDATA[
エモトです．みなさまDP2はご覧になりましたでしょうか．こまけぇことはいいんだよのAAがよく似合うエピローグ（いや全編でか），これが映画なんだよと圧巻でした．

<br/><br/>
※文末に追記あり
<br/><br/>


Pythonに限らず，作成したメソッドやライブラリを他の自プロジェクトに使いたいことはあると思います．今回はそんなときのお話です．

<br/><br/>

ライブラリを公開して，pip コマンドでインストール可能にすれば便利ですが，一般公開するまでもないものや，公開してはダメなものもあるので，今回はローカル環境でパスを設定します．

<br/><br/>

PYTHONPATH を設定すればできるようですが，私の環境は pyenv で作成しているのか，うまく反映されませんでした．


<pre class="brush: py3">
$ export PYTHONPATH="hogehoge/mylib"
</pre>

そこで，すでにパスが通っているところに pthファイル を置いて，新たにパスを設定します．それらのパスは以下のようにして確認できます．

<pre class="brush: py3">
import sys
for path in sys.path:
  print(path)
</pre>

pthファイルは site-packages に保存します．私の環境では以下のパスになりました．

<pre class="brush: py3">
/Users/user/.pyenv/versions/3.6.1/lib/python3.6/site-packages
</pre>

次に，pth ファイル名を mylib.pth，設定したいパスを hogehoge/mylib としたとき，以下のようにすれば pth ファイルを追加できます．

<pre class="brush: py3">
pth_file = "mylib.pth"
pth_body = "hogehoge/mylib"
for path in sys.path:
  if ".pyenv" in path and path.endswith("site-packages") is True:
    save_path = os.path.join(path, pth_file)
    with open(save_path, "w") as f:
      f.write(pth_body)
</pre>

また，ファイル追加をしたら，削除も用意した方もいいでしょう．ここは簡単にコマンドラインの引数から，削除を追加しました．

<pre class="brush: py3">
# $ python add_pth_file.py delete
if len(args) > 1 and args[1] == "delete":
  if os.path.exists(save_path):
    os.remove(save_path)
</pre>


いまのところ，他プロジェクトでも使うライブラリは，このpthファイル作成と一緒に1つのリポジトリに入れて管理しています．新しい環境でも，gitクローンしたらパス追加コマンドを使えば，簡単にライブラリが使えるようになります．また，パス指定のところでディレクトリ位置を動的に取得して反映するように変更し，クローンを行うディレクトリに依存しないようにしています．

<br/><br/>

（追記）最近，PyPIに自作パッケージを登録したことで気づいてしまいました（今さらやっと）．このパスを設定せずとも，プライベートのライブラリをPyPI登録直前まで用意して，ローカルでpip installした方がインストールと管理が簡単ですね．プライベートのライブラリをプライベートのgit環境でメンテしておけばアップデートも管理しやすい．

<a name="more"></a>

]]><![CDATA[
]]></content:encoded>
            <category>機械学習</category>
      <author>Seesaa京都スタッフ</author>
      <guid isPermaLink="false">blog:https://blog.seesaa.jp,seesaakyoto/459948239</guid>
                </item>
        <item>
      <link>https://seesaakyoto.seesaa.net/article/459288506.html</link>
      <title>Bayesian Gaussian mixture model（BGMM）を使ってクラスタリング数を求める</title>
      <pubDate>Fri, 11 May 2018 12:00:00 +0900</pubDate>
            <description>エモトです．みなさま某IWはご覧になりましたでしょうか．私は原作を知らなかったのでこんな展開になるのかよ！と驚きました．しかし幸いなことに，直前に某アニメの王位争奪戦を見直していたので，心のダメージは最小に抑えられました．アタルありがとう．フェイスフラッシュで無事解決したように，来年公開の4を待ちましょう．前回，混合ガウスモデル（Gaussian mixture model, GMM）を使用して，クラスタリングを行いました．クラスタリングで問題になるのは，やはり最適なクラスタ..</description>
            <itunes:summary><![CDATA[
エモトです．みなさま某IWはご覧になりましたでしょうか．私は原作を知らなかったのでこんな展開になるのかよ！と驚きました．しかし幸いなことに，直前に某アニメの王位争奪戦を見直していたので，心のダメージは最小に抑えられました．アタルありがとう．フェイスフラッシュで無事解決したように，来年公開の4を待ちましょう．




前回，混合ガウスモデル（Gaussian mixture model, GMM）を使用して，クラスタリングを行いました．クラスタリングで問題になるのは，やはり最適なクラスタリング数は何かです．



前回はBIC（ベイズ情報量規準）から最適なクラスタリング数を求めました．ここで，潜在的ディリクレ配分法（Latent Dirichlet Allocation, LDA）に階層ディリクレ過程（Hierechical Dirichlet Process, HDP）があるように，GMMにもクラスタリング数を自動推定する Bayesian Gaussian mixture model（BGMM）があります．今回は，そのBGMMを簡単に説明します．



なお，同様な手法として Dirichlet Process Gaussian Mixture Model (DPGMM) があるのですが，今回使用するライブラリ scikit-learn では deprecated になっていました（これらの経緯は勉強不足です，すみません）．



今回は簡単な例を示した後に，複雑なデータを与えたときの結果を紹介します．なお，前半のコード例は <a href="https://github.com/mitsuharu/tutorials_python/blob/master/ipynb/BayesianGaussianMixture.ipynb" target="_blank">こちら</a> で公開しています．



BayesianGaussianMixtureの使い方



まず，検証用のデータを生成します．今回は2クラスに分類されそうなデータを作成しました．


from numpy.random import rand
vec_list = []
for base in [[10, 10], [0, 0]]:
  for _ in range(100):
    temp = [base[0] + rand(), base[1] + rand()]
    vec_list.append(temp)


<img alt="1F1BC2E6D3FAEFA026E5FE9BEF6FC562.png" src="http://seesaakyoto.up.seesaa.net/image/1F1BC2E6D3FAEFA026E5FE9BEF6FC562.png" width="362" height="248" border="0">



BGMMの学習を行います．前述通り，<a href="http://scikit-learn.org/stable/modules/generated/sklearn.mixture.BayesianGaussianMixture.html" target="_blank">scikit-learn</a> を使用しています．ここでは，BGMMの推定クラスターの最大候補数 n_components を10に，学習回数  max_iter を1000にしています．この例では学習回数はデフォルトの100のままでも大丈夫ですが，実際に複雑なデータでは100より大きい数値に設定しておくと良いと思います．



import numpy as np
nvec = np.array(vec_list)

from sklearn.mixture import BayesianGaussianMixture
gmm = BayesianGaussianMixture(n_components=10, verbose=1, max_iter=1000)
gmm.fit(nvec)


分類結果を見ると，今回はクラスター番号2と5のクラスターに分かれました．クラスターごとに色付けた散布図をみると，綺麗に2クラスに分かれたことがわかります．


clusters = gmm.predict(nvec)
print("clusters:", clusters)

'''
clusters: [5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2]
'''



<img alt="5A5F4268F47E0D856FBF4F181D9BEBF0.png" src="http://seesaakyoto.up.seesaa.net/image/5A5F4268F47E0D856FBF4F181D9BEBF0.png" width="363" height="247" border="0">



また，分類結果のクラスター番号を集合(set)に変換すると，クラスター数がわかりやすくなると思います．


clusters_set = set(clusters)
print("clusters_set:", clusters_set)
print("len(clusters_set):", len(clusters_set))
'''
clusters_set: {2, 5}
len(clusters_set): 2
'''



次に，BGMMで学習した各クラスター番号の重みを確認します．クラスタリング番号2と5に重みが集中して，他がほとんど0になっています．この重みからも2クラスターになったのが判断できます．


weights = gmm.weights_
components = gmm.n_components
x_clusters = np.arange(components)
plt.bar(x_clusters, weights, tick_label=x_clusters)
plt.show


<img alt="1197D336BADA29F45CCB19C8EF080875.png" src="http://seesaakyoto.up.seesaa.net/image/1197D336BADA29F45CCB19C8EF080875.png" width="367" height="247" border="0">



より複雑なデータはどうなるか？



上記の例ではきれいに分かれましたが．実際のデータ（より複雑なデータ）ではそう簡単にはいきません．下図は，あるデータに対してBGMMを行ったときの各カテゴリーごとの重みの計算結果です．

<img alt="94C04508A40C2F2A81EA26BF037F7DAE.png" src="http://seesaakyoto.up.seesaa.net/image/94C04508A40C2F2A81EA26BF037F7DAE.png" width="600" height="371" border="0">



グラフを比べてわかるように，後者の図からクラスター数をポンっと決めるのは難しいです．しかしながら，いくつか0に近い重みのクラスターがあるので，それら考慮して取捨選択していけば，ある程度の目星はつきそうです．クラスター数の候補を絞って，GMMを行い，結果を比較すれば，最適なクラスター数を絞り込めそうです．


<a></a>

]]></itunes:summary>
      <content:encoded><![CDATA[
エモトです．みなさま某IWはご覧になりましたでしょうか．私は原作を知らなかったのでこんな展開になるのかよ！と驚きました．しかし幸いなことに，直前に某アニメの王位争奪戦を見直していたので，心のダメージは最小に抑えられました．アタルありがとう．フェイスフラッシュで無事解決したように，来年公開の4を待ちましょう．

<br/><br/>


前回，混合ガウスモデル（Gaussian mixture model, GMM）を使用して，クラスタリングを行いました．クラスタリングで問題になるのは，やはり最適なクラスタリング数は何かです．

<br/><br/>

前回はBIC（ベイズ情報量規準）から最適なクラスタリング数を求めました．ここで，潜在的ディリクレ配分法（Latent Dirichlet Allocation, LDA）に階層ディリクレ過程（Hierechical Dirichlet Process, HDP）があるように，GMMにもクラスタリング数を自動推定する Bayesian Gaussian mixture model（BGMM）があります．今回は，そのBGMMを簡単に説明します．

<br/><br/>

なお，同様な手法として Dirichlet Process Gaussian Mixture Model (DPGMM) があるのですが，今回使用するライブラリ scikit-learn では deprecated になっていました（これらの経緯は勉強不足です，すみません）．

<br/><br/>

今回は簡単な例を示した後に，複雑なデータを与えたときの結果を紹介します．なお，前半のコード例は <ins><a href="https://github.com/mitsuharu/tutorials_python/blob/master/ipynb/BayesianGaussianMixture.ipynb" target="_blank">こちら</a></ins> で公開しています．

<br/><br/>

<strong><span style="font-size:large;">BayesianGaussianMixtureの使い方</span></strong>

<br/><br/>

まず，検証用のデータを生成します．今回は2クラスに分類されそうなデータを作成しました．

<pre class="brush: py3">
from numpy.random import rand
vec_list = []
for base in [[10, 10], [0, 0]]:
  for _ in range(100):
    temp = [base[0] + rand(), base[1] + rand()]
    vec_list.append(temp)
</pre>

<div style="text-align:center;"><img alt="1F1BC2E6D3FAEFA026E5FE9BEF6FC562.png" src="http://seesaakyoto.up.seesaa.net/image/1F1BC2E6D3FAEFA026E5FE9BEF6FC562.png" width="362" height="248" border="0" onclick="location.href = 'https://seesaakyoto.seesaa.net/upload/detail/image/1F1BC2E6D3FAEFA026E5FE9BEF6FC562.png.html'; return false;" style="cursor:pointer;" /></div>

<br/><br/>

BGMMの学習を行います．前述通り，<ins><a href="http://scikit-learn.org/stable/modules/generated/sklearn.mixture.BayesianGaussianMixture.html" target="_blank">scikit-learn</a></ins> を使用しています．ここでは，BGMMの推定クラスターの最大候補数 n_components を10に，学習回数  max_iter を1000にしています．この例では学習回数はデフォルトの100のままでも大丈夫ですが，実際に複雑なデータでは100より大きい数値に設定しておくと良いと思います．


<pre class="brush: py3">
import numpy as np
nvec = np.array(vec_list)

from sklearn.mixture import BayesianGaussianMixture
gmm = BayesianGaussianMixture(n_components=10, verbose=1, max_iter=1000)
gmm.fit(nvec)
</pre>

分類結果を見ると，今回はクラスター番号2と5のクラスターに分かれました．クラスターごとに色付けた散布図をみると，綺麗に2クラスに分かれたことがわかります．

<pre class="brush: py3">
clusters = gmm.predict(nvec)
print("clusters:", clusters)

'''
clusters: [5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2]
'''
</pre>


<div style="text-align:center;"><img alt="5A5F4268F47E0D856FBF4F181D9BEBF0.png" src="http://seesaakyoto.up.seesaa.net/image/5A5F4268F47E0D856FBF4F181D9BEBF0.png" width="363" height="247" border="0" onclick="location.href = 'https://seesaakyoto.seesaa.net/upload/detail/image/5A5F4268F47E0D856FBF4F181D9BEBF0.png.html'; return false;" style="cursor:pointer;" /></div>

<br/><br/>

また，分類結果のクラスター番号を集合(set)に変換すると，クラスター数がわかりやすくなると思います．

<pre class="brush: py3">
clusters_set = set(clusters)
print("clusters_set:", clusters_set)
print("len(clusters_set):", len(clusters_set))
'''
clusters_set: {2, 5}
len(clusters_set): 2
'''
</pre>


次に，BGMMで学習した各クラスター番号の重みを確認します．クラスタリング番号2と5に重みが集中して，他がほとんど0になっています．この重みからも2クラスターになったのが判断できます．

<pre class="brush: py3">
weights = gmm.weights_
components = gmm.n_components
x_clusters = np.arange(components)
plt.bar(x_clusters, weights, tick_label=x_clusters)
plt.show
</pre>

<div style="text-align:center;"><img alt="1197D336BADA29F45CCB19C8EF080875.png" src="http://seesaakyoto.up.seesaa.net/image/1197D336BADA29F45CCB19C8EF080875.png" width="367" height="247" border="0" onclick="location.href = 'https://seesaakyoto.seesaa.net/upload/detail/image/1197D336BADA29F45CCB19C8EF080875.png.html'; return false;" style="cursor:pointer;" /></div>

<br/><br/>

<strong><span style="font-size:large;">より複雑なデータはどうなるか？</span></strong>

<br/><br/>

上記の例ではきれいに分かれましたが．実際のデータ（より複雑なデータ）ではそう簡単にはいきません．下図は，あるデータに対してBGMMを行ったときの各カテゴリーごとの重みの計算結果です．<br/>

<div style="text-align:center;"><img alt="94C04508A40C2F2A81EA26BF037F7DAE.png" src="http://seesaakyoto.up.seesaa.net/image/94C04508A40C2F2A81EA26BF037F7DAE.png" width="600" height="371" border="0" onclick="location.href = 'https://seesaakyoto.seesaa.net/upload/detail/image/94C04508A40C2F2A81EA26BF037F7DAE.png.html'; return false;" style="cursor:pointer;" /></div>

<br/><br/>

グラフを比べてわかるように，後者の図からクラスター数をポンっと決めるのは難しいです．しかしながら，いくつか0に近い重みのクラスターがあるので，それら考慮して取捨選択していけば，ある程度の目星はつきそうです．クラスター数の候補を絞って，GMMを行い，結果を比較すれば，最適なクラスター数を絞り込めそうです．


<a name="more"></a>

]]><![CDATA[
]]></content:encoded>
            <category>機械学習</category>
      <author>Seesaa京都スタッフ</author>
      <guid isPermaLink="false">blog:https://blog.seesaa.jp,seesaakyoto/459288506</guid>
                </item>
        <item>
      <link>https://seesaakyoto.seesaa.net/article/458984330.html</link>
      <title>Topic Model で学習したデータをGMMでクラスタリングする</title>
      <pubDate>Tue, 24 Apr 2018 13:00:00 +0900</pubDate>
            <description>エモトです．GWは某VR，吹奏楽，ヒーロー大集合，オリジンの映画と映画館に連日通いつめそうです．さすがGW．あ，サッカーも見に行くよ．以前 Topic Model を使って，文章の解析を行いました．そこでも問題になったのは，最適なトピック数は何か？です．今回は別のクラスタリング手法を加えて，最適なクラスタリング数を探してみます．クラスタリングの有名な手法だとk-meansがありますが，今回は混合ガウスモデル（Gaussian mixture model, GMM）を選択しまし..</description>
            <itunes:summary><![CDATA[
エモトです．GWは某VR，吹奏楽，ヒーロー大集合，オリジンの映画と映画館に連日通いつめそうです．さすがGW．あ，サッカーも見に行くよ．


以前 <a href="http://seesaakyoto.seesaa.net/article/457025212.html" target="_blank">Topic Model を使って，文章の解析</a>を行いました．そこでも問題になったのは，最適なトピック数は何か？です．今回は別のクラスタリング手法を加えて，最適なクラスタリング数を探してみます．


クラスタリングの有名な手法だとk-meansがありますが，今回は混合ガウスモデル（Gaussian mixture model, GMM）を選択しました．<a href="https://www.quora.com/What-are-the-differences-and-similarities-between-LDA-and-k-means-for-topic-detection-assuming-that-I-can-cluster-documents-with-k-means-and-extract-some-common-key-phrases-to-represent-their-topics" target="_blank">調べている</a>と，単一のドキュメントが幾つかの異なるトピックに属すためLDAと相性が良い，とのことで採用しました．


Topic Modelの計算結果から，コーパスデータを特徴量に変換します．可変長のコーパスデータが，LDAで指定したトピック数だけの次元の特徴量に変換されます．



corpus_vec_list = []
for corpus in corpus_data:
  temp_vec = [0 for i in range(topic_count)]
  for tp in lda.get_document_topics(corpus):
    temp_vec[tp[0]] = tp[1]
  corpus_vec_list.append(temp_vec)


GMMは <a href="http://scikit-learn.org/stable/modules/mixture.html" target="_blank">scikit-learn</a> を使用しました．


def calc_gmm(vec_list, component):
	from sklearn.mixture import GaussianMixture
	gmm = GaussianMixture(n_components=component, covariance_type='full')
	
	import numpy as np
	nvec = np.array(vec_list)
	
	gmm.fit(nvec)
	clusters = gmm.predict(nvec)
	proba = gmm.predict_proba(nvec)
	bic = gmm.bic(nvec)
	return clusters, proba, bic

候補のクラスタリング数だけ，GMMを計算します．BIC（ベイズ情報量規準）から最適なクラスタリング数を求めます．単純に大小の比較を行いましたが，最適化計算からの乱数によるブレが生じるので，候補それぞれでの数値や複数回処理するなどを加味すると良いと思われます．


import sys
min_bic = sys.float_info.max
best_component = 0
        
for component in range(20, 30):
	clusters, proba, bic = calc_gmm(corpus_vec_list, component)
	if bic &lt; min_bic:
		min_bic = bic
		best_component = component

今回は．文章が持つトピック数を求めるために使用したTopic Modelを，トピック特徴空間への写像方法として使用して，その特徴空間でGMMを使ってクラスタリングを行いました．これで，文章の最適なトピック数・クラスタリング数が絞れれば良いのですが，逆に候補が増えて混乱になったりも．自然言語の扱いは難しいですね．
<a></a>

]]></itunes:summary>
      <content:encoded><![CDATA[
エモトです．GWは某VR，吹奏楽，ヒーロー大集合，オリジンの映画と映画館に連日通いつめそうです．さすがGW．あ，サッカーも見に行くよ．<br/><br/>


以前 <a href="http://seesaakyoto.seesaa.net/article/457025212.html" target="_blank"><ins>Topic Model を使って，文章の解析</ins></a>を行いました．そこでも問題になったのは，最適なトピック数は何か？です．今回は別のクラスタリング手法を加えて，最適なクラスタリング数を探してみます．<br/><br/>


クラスタリングの有名な手法だとk-meansがありますが，今回は混合ガウスモデル（Gaussian mixture model, GMM）を選択しました．<a href="https://www.quora.com/What-are-the-differences-and-similarities-between-LDA-and-k-means-for-topic-detection-assuming-that-I-can-cluster-documents-with-k-means-and-extract-some-common-key-phrases-to-represent-their-topics" target="_blank"><ins>調べている</ins></a>と，単一のドキュメントが幾つかの異なるトピックに属すためLDAと相性が良い，とのことで採用しました．<br/><br/>


Topic Modelの計算結果から，コーパスデータを特徴量に変換します．可変長のコーパスデータが，LDAで指定したトピック数だけの次元の特徴量に変換されます．<br/>


<pre class="brush: oc">
corpus_vec_list = []
for corpus in corpus_data:
  temp_vec = [0 for i in range(topic_count)]
  for tp in lda.get_document_topics(corpus):
    temp_vec[tp[0]] = tp[1]
  corpus_vec_list.append(temp_vec)</pre>


GMMは <a href="http://scikit-learn.org/stable/modules/mixture.html" target="_blank"><ins>scikit-learn</ins></a> を使用しました．<br/>

<pre class="brush: oc">
def calc_gmm(vec_list, component):
	from sklearn.mixture import GaussianMixture
	gmm = GaussianMixture(n_components=component, covariance_type='full')
	
	import numpy as np
	nvec = np.array(vec_list)
	
	gmm.fit(nvec)
	clusters = gmm.predict(nvec)
	proba = gmm.predict_proba(nvec)
	bic = gmm.bic(nvec)
	return clusters, proba, bic</pre>

候補のクラスタリング数だけ，GMMを計算します．BIC（ベイズ情報量規準）から最適なクラスタリング数を求めます．単純に大小の比較を行いましたが，最適化計算からの乱数によるブレが生じるので，候補それぞれでの数値や複数回処理するなどを加味すると良いと思われます．<br/>

<pre class="brush: oc">
import sys
min_bic = sys.float_info.max
best_component = 0
        
for component in range(20, 30):
	clusters, proba, bic = calc_gmm(corpus_vec_list, component)
	if bic < min_bic:
		min_bic = bic
		best_component = component</pre>

今回は．文章が持つトピック数を求めるために使用したTopic Modelを，トピック特徴空間への写像方法として使用して，その特徴空間でGMMを使ってクラスタリングを行いました．これで，文章の最適なトピック数・クラスタリング数が絞れれば良いのですが，逆に候補が増えて混乱になったりも．自然言語の扱いは難しいですね．
<a name="more"></a>

]]><![CDATA[
]]></content:encoded>
            <category>機械学習</category>
      <author>Seesaa京都スタッフ</author>
      <guid isPermaLink="false">blog:https://blog.seesaa.jp,seesaakyoto/458984330</guid>
                </item>
        <item>
      <link>https://seesaakyoto.seesaa.net/article/458204198.html</link>
      <title>TensorFlowのハンズオンをしました</title>
      <pubDate>Thu, 22 Mar 2018 13:00:00 +0900</pubDate>
            <description>エモトです．先日，某作品のOVA・劇場版・最終章の三連続マサラ上映に参加しました．発生可能な応援上映に加えて，クラッカーや紙吹雪も大丈夫な上映形態，楽しくないわけがない．約3時間半ほど，クラッカーを発砲やイベントシーンのタイミングに合わせて鳴らしてました．次はあのシーンだなと右手で数個のクラッカーを持ち，左手でタイミングよく順々に鳴らしたときの達成感はなんともすごい．少しセーブしたものの，持ち込んだ200個のクラッカーでは足りなかった．劇場の音響の力に，クラッカーの音と火薬の..</description>
            <itunes:summary><![CDATA[
エモトです．先日，某作品のOVA・劇場版・最終章の三連続マサラ上映に参加しました．発生可能な応援上映に加えて，クラッカーや紙吹雪も大丈夫な上映形態，楽しくないわけがない．約3時間半ほど，クラッカーを発砲やイベントシーンのタイミングに合わせて鳴らしてました．次はあのシーンだなと右手で数個のクラッカーを持ち，左手でタイミングよく順々に鳴らしたときの達成感はなんともすごい．少しセーブしたものの，持ち込んだ200個のクラッカーでは足りなかった．劇場の音響の力に，クラッカーの音と火薬の匂いが混じり，とても楽しい時間でした．静かに映画を見るのも良いですが，わいわい見れる映画館も本当に良いですね．

運営協力している Kyoto.LT にて <a href="https://kyotolt.connpass.com/event/81639/" target="_blank">TensorFlow ハンズオン</a>を行いました． 

周りに機械学習する人・興味ある人が増えたらいいなと入門的なハンズオンをしたいと思っていましたが，環境構築で時間が終わりそうなので断念していました．そうしていたところ，<a href="https://colab.research.google.com/" target="_blank">Google Colab</a> で GPU が利用できるようになったと聞き，これはやらねばということで，開催しました（実際は簡単なコードしか取り扱わなかったので CPU 計算で十分ですが）．

ハンズオン資料はこちらで <a href="https://github.com/mitsuharu/tensorflow_handson" target="_blank">公開</a> しています．各自の環境で ipynb ファイルを展開してもらえば，動くと思います．理論も紹介したいし，肝心のコードもやらないといけないと，時間が足りず中途半端な感じになっていますが，雰囲気を体験してもらえば幸いです．


<a></a>

]]></itunes:summary>
      <content:encoded><![CDATA[
エモトです．先日，某作品のOVA・劇場版・最終章の三連続マサラ上映に参加しました．発生可能な応援上映に加えて，クラッカーや紙吹雪も大丈夫な上映形態，楽しくないわけがない．約3時間半ほど，クラッカーを発砲やイベントシーンのタイミングに合わせて鳴らしてました．次はあのシーンだなと右手で数個のクラッカーを持ち，左手でタイミングよく順々に鳴らしたときの達成感はなんともすごい．少しセーブしたものの，持ち込んだ200個のクラッカーでは足りなかった．劇場の音響の力に，クラッカーの音と火薬の匂いが混じり，とても楽しい時間でした．静かに映画を見るのも良いですが，わいわい見れる映画館も本当に良いですね．<br /><br />運営協力している Kyoto.LT にて <ins><a href="https://kyotolt.connpass.com/event/81639/" target="_blank">TensorFlow ハンズオン</a></ins>を行いました． <br /><br />周りに機械学習する人・興味ある人が増えたらいいなと入門的なハンズオンをしたいと思っていましたが，環境構築で時間が終わりそうなので断念していました．そうしていたところ，<a href="https://colab.research.google.com/" target="_blank"><ins>Google Colab</ins></a> で GPU が利用できるようになったと聞き，これはやらねばということで，開催しました（実際は簡単なコードしか取り扱わなかったので CPU 計算で十分ですが）．<br /><br />ハンズオン資料はこちらで <a href="https://github.com/mitsuharu/tensorflow_handson" target="_blank"><ins>公開</ins></a> しています．各自の環境で ipynb ファイルを展開してもらえば，動くと思います．理論も紹介したいし，肝心のコードもやらないといけないと，時間が足りず中途半端な感じになっていますが，雰囲気を体験してもらえば幸いです．<br /><br /><br /><a name="more"></a>

]]><![CDATA[
]]></content:encoded>
            <category>機械学習</category>
      <author>Seesaa京都スタッフ</author>
      <guid isPermaLink="false">blog:https://blog.seesaa.jp,seesaakyoto/458204198</guid>
                </item>
        <item>
      <link>https://seesaakyoto.seesaa.net/article/457025212.html</link>
      <title>TopicModelを使って，livedoorニュースコーパスを解析してみた</title>
      <pubDate>Wed, 21 Feb 2018 14:00:00 +0900</pubDate>
            <description>エモトです．さいきんバーフバリというインド映画にどハマりしました．インド映画特有の歌とダンスに加え，ストーリーやアクションシーンの完成度もすごい．出演陣も敵味方含めて全員かっこいい．敵役の中の人が私より年下だったことが一番の驚きでした．まだ見てない方は是非．オームシャンティオームやクリッシュもおすすめ．Topic Modelとは簡単に説明すると，文書は複数の潜在的なトピックから確率的に生成されると仮定したモデルです．下記に図例を示しました．この例では，ニュース記事は動物トピッ..</description>
            <itunes:summary><![CDATA[


エモトです．さいきんバーフバリというインド映画にどハマりしました．インド映画特有の歌とダンスに加え，ストーリーやアクションシーンの完成度もすごい．出演陣も敵味方含めて全員かっこいい．敵役の中の人が私より年下だったことが一番の驚きでした．まだ見てない方は是非．オームシャンティオームやクリッシュもおすすめ．

Topic Modelとは

簡単に説明すると，文書は複数の潜在的なトピックから確率的に生成されると仮定したモデルです．下記に図例を示しました．この例では，ニュース記事は動物トピックとイベントトピックから文章が生成されて，特に動物トピックの影響が大きいのを示してます．なお，xxトピックと書いてますが，実際の計算ではトピックのラベル付けまで行われずに，計算終了後に別途でラベル付けを行います．

<img alt="tm01.png" src="http://seesaakyoto.up.seesaa.net/image/tm01-thumbnail2.png" width="500" height="153" border="0">

さて今回，そのTopic Modelを実装してみました．対象データは <a href="https://www.rondhuit.com/download.html#ldcc" target="_blank">livedoor ニュースコーパス</a> を使用しました．実装言語はPython，主な使用ライブラリはGensimを使用しています

1. データ作成

ニュースの本文を入力データ，カテゴリーをラベルとしました．本文はMeCabを使用して分かち書きにしました。なお、名詞と動詞の原形を使用しました。形容詞など他の品詞は、今回の実装では精度が上がらなかったのでデータから外しました。


docments = [["分かち書き", "された", "文章1"], ... ]
categories = ["文章1のカテゴリー", ...]


全データ7367件中，訓練データには9割，テストデータには1割を使用しました．

2. 実装

gensimのLDAmodel（Latent Dirichlet Allocation，潜在的ディリクレ配分法）を使用して実装しました．コードの一部を紹介します．なお，ストップワードの選定には，<a href="http://svn.sourceforge.jp/svnroot/slothlib/CSharp/Version1/SlothLib/NLP/Filter/StopWord/word/Japanese.txt" target="_blank">Slothlibのストップワード</a> を使用しました．


from gensim import corpora
from gensim import models
from sklearn.model_selection import train_test_split

dictionary = corpora.Dictionary(documents)

# ストップワード
ignores = []
ignored_words_file = "./stop_words.txt"
with open(ignored_words_file, "r", encoding="utf-8") as f:
    ignores = [line.replace(os.linesep, "") for line in f]

# フィルタリング
dictionary.filter_extremes(no_below=20, no_above=0.5, keep_n=100000)
stop_ids = [dictionary.token2id[ig] for ig in ignores if ig in dictionary.token2id]
dictionary.filter_tokens(stop_ids)
dictionary.compactify()




コーパスデータを訓練とテストに分けて，LDAを学習します．学習時にトピック数を指定するのですが，今回は入力するカテゴリーと同数の9を設定しています．なお，学習メソッドのパラメータはヒューリスティックにいじって調整した値なので，本当に適正かどうかは不明です．


corpus = [dictionary.doc2bow(text) for text in documents]
x_train, x_test, y_train, y_test = train_test_split(corpus, categories, test_size=0.1, random_state=1)
    
lda = models.LdaModel(corpus=x_train, id2word=dictionary, num_topics=9, iterations=50, passes=20)




評価には，パープレキシティ，学習したトピックの上位語彙および分類結果を用いました．
    

def calc_perplexity(m, c):
    import numpy as np
    return np.exp(-m.log_perplexity(c))

# パープレキシティ
p = calc_perplexity(lda, x_test)

# 上位語彙
each_topics = []
for i in range(lda.num_topics):
    words = lda.show_topic(i, topn=topic_count)
    each_topics += [[w[0] for w in words]]

# 分類
for x in x_test:
    topics = lda.get_document_topics(x)
    top_topic = sorted(topics, key=lambda topic: topic[1], reverse=True)[0][0]




パープレキシティ（分類精度を示し，1に近いほど良い）です．訓練でさえ2000を超えているので，あまり良い分類精度ではないようでした．




訓練
テスト





2090.9748423332085
4603.607550110796






各カテゴリの上位語彙．学習したトピック（1列目）それぞれの上位5つの語彙を示してます． 





topics
0
1
2
3
4





0
twitter
声
ネット掲示板
情報
当選


1
肌
使う
女子
人気
女性


2
話題
機能
見る
使う
pc


3
思う
女性
結婚
男性
仕事


4
smartphone
対応
搭載
max
2012年


5
アプリ
更新
画面
表示
ソフトウェア


6
転職
写真
知る
仕事
得る


7
思う
選手
語る
日本
試合


8
映画
公開
作品
監督
本作






訓練データに対して，実際のラベル（1列目）がどのトピック（2列目以降）に分類されたかの表です．ニュースコーパスのカテゴリー分類に従えば，それぞれのデータ群が1つの固有トピックに集中するのが望ましい結果と言えるでしょう．




訓練
0
1
2
3
4
5
6
7
8





dokujo-tsushin
4
122
2
628
1
0
4
3
27


it-life-hack
52
12
385
20
66
107
121
8
15


kaden-channel
40
51
612
20
10
7
22
4
20


livedoor-homme
3
161
37
60
3
8
131
8
29


movie-enter
19
2
2
25
0
0
0
2
726


peachy
45
459
9
137
1
9
17
1
86


smax
5
11
22
0
416
334
0
0
3


sports-watch
38
2
0
28
0
0
1
728
5


topic-news
498
6
29
65
0
3
8
61
24






上記の結果をテストデータに対して行った結果．




テスト
0
1
2
3
4
5
6
7
8





dokujo-tsushin
0
9
0
66
0
0
1
0
3


it-life-hack
7
1
44
2
11
12
3
1
3


kaden-channel
5
6
54
4
1
4
1
1
2


livedoor-homme
1
25
9
5
0
0
19
2
10


movie-enter
0
0
0
3
0
0
0
0
91


peachy
2
48
1
13
0
2
1
0
11


smax
0
7
3
0
41
28
0
0
0


sports-watch
3
0
0
2
0
0
0
92
1


topic-news
56
1
1
9
0
0
0
7
2






分類結果の表から dokujo-tsushin と sports-watch と topic-news と movie-enter が上手に分類できるように見えます．しかしながら，トピック2は it-life-hack と kaden-channel が混在しました．ただ，その両者はもともと近しいジャンルのように見えるので，妥当な結果とも言えます．

HDP

ここで，LDAでトピックモデルを行ったとき，トピック数を指定して学習しました．例では入力データのカテゴリー数と同数を設定しましたが，本当にこのトピック数が適正な値かどうかは，わかりません．いくつもの候補を設定して，パープレキシティや分類結果を確認して決定する工程が必要になると思います．

その工程が面倒なので，HDP（Hierarchical Dirichlet Process，階層ディリクレ過程）を用いて，トピック数自体を推定しました．


# 推定トピック数の最大値はデフォルトで150に設定されている
hdp = models.hdpmodel.HdpModel(corpus, id2word=dictionary, alpha=0.1)




学習結果の評価は，<a href="https://stackoverflow.com/questions/31543542/hierarchical-dirichlet-process-gensim-topic-number-independent-of-corpus-size" target="_blank">こちら</a> を参考に推定したトピックそれぞれの重みを加算して，比較しました．


def topic_prob_extractor(hdp, save_csv_file=None):
    import pandas as pd
    shown_topics = hdp.show_topics(num_topics=-1, formatted=False)
    topics_nos = [x[0] for x in shown_topics]
    weights = [sum([item[1] for item in shown_topics[topicN][1]]) for topicN in topics_nos]
    data_frame = pd.DataFrame({'topic_id': topics_nos, 'weight': weights})
    if save_csv_file is not None:
        data_frame.to_csv(save_csv_file)
    return data_frame


<img alt="hdp.png" src="http://seesaakyoto.up.seesaa.net/image/hdp-thumbnail2.png" width="500" height="399" border="0">

最も重みが高い9が最適なトピック数となるでしょうか．25や50手前でいきなり重みがポンっと上がっているのがすごく気になります．

最適なトピック数は？



今回だと，最適なトピック数は9のようにみえます．しかしながら，より複雑なデータ（不特定多数が書いた，文章作成規則があいまい，など）を対象とした場合，HDPでも判定が難しい方が多いです．<a href="https://datascience.stackexchange.com/questions/128/latent-dirichlet-allocation-vs-hierarchical-dirichlet-process/499#499" target="_blank">色々な質問サイト</a> を眺めていると，はやりHDPでは決められずに，LDAの計算を反復して決定してるのをよく見かけます．


まとめ

Topic Modelのトピック数を幾つに設定することが大きな問題です．望ましい結果と比べて地道に設定していくことになると思います．しかしながら，Topic Modelは良い分類結果をもたらし，非常に興味深いですね．
<a></a>

]]></itunes:summary>
      <content:encoded><![CDATA[
<style>
.table-result {
  border-collapse: collapse;
  text-align: center;
  width: 400px;
  margin-left: auto;
  margin-right: auto;
}
.table-result th {
  background-color: #cccccc;
}
</style>

エモトです．さいきんバーフバリというインド映画にどハマりしました．インド映画特有の歌とダンスに加え，ストーリーやアクションシーンの完成度もすごい．出演陣も敵味方含めて全員かっこいい．敵役の中の人が私より年下だったことが一番の驚きでした．まだ見てない方は是非．オームシャンティオームやクリッシュもおすすめ．<br/><br/>

<span style="font-size:large;"><strong>Topic Modelとは</strong></span><br/><br/>

簡単に説明すると，文書は複数の潜在的なトピックから確率的に生成されると仮定したモデルです．下記に図例を示しました．この例では，ニュース記事は動物トピックとイベントトピックから文章が生成されて，特に動物トピックの影響が大きいのを示してます．なお，xxトピックと書いてますが，実際の計算ではトピックのラベル付けまで行われずに，計算終了後に別途でラベル付けを行います．<br/><br/>

<div style="text-align:center;"><img alt="tm01.png" src="http://seesaakyoto.up.seesaa.net/image/tm01-thumbnail2.png" width="500" height="153" border="0" onclick="location.href = 'https://seesaakyoto.seesaa.net/upload/detail/image/tm01-thumbnail2.png.html'; return false;" style="cursor:pointer;" /></div><br/>

さて今回，そのTopic Modelを実装してみました．対象データは <ins><a href="https://www.rondhuit.com/download.html#ldcc" target="_blank">livedoor ニュースコーパス</a></ins> を使用しました．実装言語はPython，主な使用ライブラリはGensimを使用しています<br/><br/>

<strong><span style="font-size:large;">1. データ作成</span></strong><br/><br/>

ニュースの本文を入力データ，カテゴリーをラベルとしました．本文はMeCabを使用して分かち書きにしました。なお、名詞と動詞の原形を使用しました。形容詞など他の品詞は、今回の実装では精度が上がらなかったのでデータから外しました。<br/>

<pre class="brush: oc">
docments = [["分かち書き", "された", "文章1"], ... ]
categories = ["文章1のカテゴリー", ...]
</pre>

全データ7367件中，訓練データには9割，テストデータには1割を使用しました．<br/><br/>

<strong><span style="font-size:large;">2. 実装</span></strong><br/><br/>

gensimのLDAmodel（Latent Dirichlet Allocation，潜在的ディリクレ配分法）を使用して実装しました．コードの一部を紹介します．なお，ストップワードの選定には，<ins><a href="http://svn.sourceforge.jp/svnroot/slothlib/CSharp/Version1/SlothLib/NLP/Filter/StopWord/word/Japanese.txt" target="_blank">Slothlibのストップワード</a></ins> を使用しました．<br/>

<pre class="brush: oc">
from gensim import corpora
from gensim import models
from sklearn.model_selection import train_test_split

dictionary = corpora.Dictionary(documents)

# ストップワード
ignores = []
ignored_words_file = "./stop_words.txt"
with open(ignored_words_file, "r", encoding="utf-8") as f:
    ignores = [line.replace(os.linesep, "") for line in f]

# フィルタリング
dictionary.filter_extremes(no_below=20, no_above=0.5, keep_n=100000)
stop_ids = [dictionary.token2id[ig] for ig in ignores if ig in dictionary.token2id]
dictionary.filter_tokens(stop_ids)
dictionary.compactify()
</pre>

<br/>

コーパスデータを訓練とテストに分けて，LDAを学習します．学習時にトピック数を指定するのですが，今回は入力するカテゴリーと同数の9を設定しています．なお，学習メソッドのパラメータはヒューリスティックにいじって調整した値なので，本当に適正かどうかは不明です．

<pre class="brush: oc">
corpus = [dictionary.doc2bow(text) for text in documents]
x_train, x_test, y_train, y_test = train_test_split(corpus, categories, test_size=0.1, random_state=1)
    
lda = models.LdaModel(corpus=x_train, id2word=dictionary, num_topics=9, iterations=50, passes=20)
</pre>

<br/>

評価には，パープレキシティ，学習したトピックの上位語彙および分類結果を用いました．
    
<pre class="brush: oc">
def calc_perplexity(m, c):
    import numpy as np
    return np.exp(-m.log_perplexity(c))

# パープレキシティ
p = calc_perplexity(lda, x_test)

# 上位語彙
each_topics = []
for i in range(lda.num_topics):
    words = lda.show_topic(i, topn=topic_count)
    each_topics += [[w[0] for w in words]]

# 分類
for x in x_test:
    topics = lda.get_document_topics(x)
    top_topic = sorted(topics, key=lambda topic: topic[1], reverse=True)[0][0]
</pre>

<br/>

パープレキシティ（分類精度を示し，1に近いほど良い）です．訓練でさえ2000を超えているので，あまり良い分類精度ではないようでした．

<table border="1" class="table-result" >
<thead>
<tr>
<th>訓練</th>
<th>テスト</th>
</tr>
</thead>

<tbody>
<tr>
<td>2090.9748423332085</td>
<td>4603.607550110796</td>
</tr>
</tbody>
</table>

<br/>

各カテゴリの上位語彙．学習したトピック（1列目）それぞれの上位5つの語彙を示してます． 


<table border="1" class="table-result" >
<thead>
<tr>
<th style="text-align: center">topics</th>
<th style="text-align: center">0</th>
<th style="text-align: center">1</th>
<th style="text-align: center">2</th>
<th style="text-align: center">3</th>
<th style="text-align: center">4</th>
</tr>
</thead>

<tbody>
<tr>
<td style="text-align: center">0</td>
<td style="text-align: center">twitter</td>
<td style="text-align: center">声</td>
<td style="text-align: center">ネット掲示板</td>
<td style="text-align: center">情報</td>
<td style="text-align: center">当選</td>
</tr>
<tr>
<td style="text-align: center">1</td>
<td style="text-align: center">肌</td>
<td style="text-align: center">使う</td>
<td style="text-align: center">女子</td>
<td style="text-align: center">人気</td>
<td style="text-align: center">女性</td>
</tr>
<tr>
<td style="text-align: center">2</td>
<td style="text-align: center">話題</td>
<td style="text-align: center">機能</td>
<td style="text-align: center">見る</td>
<td style="text-align: center">使う</td>
<td style="text-align: center">pc</td>
</tr>
<tr>
<td style="text-align: center">3</td>
<td style="text-align: center">思う</td>
<td style="text-align: center">女性</td>
<td style="text-align: center">結婚</td>
<td style="text-align: center">男性</td>
<td style="text-align: center">仕事</td>
</tr>
<tr>
<td style="text-align: center">4</td>
<td style="text-align: center">smartphone</td>
<td style="text-align: center">対応</td>
<td style="text-align: center">搭載</td>
<td style="text-align: center">max</td>
<td style="text-align: center">2012年</td>
</tr>
<tr>
<td style="text-align: center">5</td>
<td style="text-align: center">アプリ</td>
<td style="text-align: center">更新</td>
<td style="text-align: center">画面</td>
<td style="text-align: center">表示</td>
<td style="text-align: center">ソフトウェア</td>
</tr>
<tr>
<td style="text-align: center">6</td>
<td style="text-align: center">転職</td>
<td style="text-align: center">写真</td>
<td style="text-align: center">知る</td>
<td style="text-align: center">仕事</td>
<td style="text-align: center">得る</td>
</tr>
<tr>
<td style="text-align: center">7</td>
<td style="text-align: center">思う</td>
<td style="text-align: center">選手</td>
<td style="text-align: center">語る</td>
<td style="text-align: center">日本</td>
<td style="text-align: center">試合</td>
</tr>
<tr>
<td style="text-align: center">8</td>
<td style="text-align: center">映画</td>
<td style="text-align: center">公開</td>
<td style="text-align: center">作品</td>
<td style="text-align: center">監督</td>
<td style="text-align: center">本作</td>
</tr>
</tbody>
</table>

<br/>

訓練データに対して，実際のラベル（1列目）がどのトピック（2列目以降）に分類されたかの表です．ニュースコーパスのカテゴリー分類に従えば，それぞれのデータ群が1つの固有トピックに集中するのが望ましい結果と言えるでしょう．

<table border="1" class="table-result" >
<thead>
<tr>
<th style="text-align: center">訓練</th>
<th style="text-align: center">0</th>
<th style="text-align: center">1</th>
<th style="text-align: center">2</th>
<th style="text-align: center">3</th>
<th style="text-align: center">4</th>
<th style="text-align: center">5</th>
<th style="text-align: center">6</th>
<th style="text-align: center">7</th>
<th style="text-align: center">8</th>
</tr>
</thead>

<tbody>
<tr>
<td style="text-align: center">dokujo-tsushin</td>
<td style="text-align: center">4</td>
<td style="text-align: center">122</td>
<td style="text-align: center">2</td>
<td style="text-align: center">628</td>
<td style="text-align: center">1</td>
<td style="text-align: center">0</td>
<td style="text-align: center">4</td>
<td style="text-align: center">3</td>
<td style="text-align: center">27</td>
</tr>
<tr>
<td style="text-align: center">it-life-hack</td>
<td style="text-align: center">52</td>
<td style="text-align: center">12</td>
<td style="text-align: center">385</td>
<td style="text-align: center">20</td>
<td style="text-align: center">66</td>
<td style="text-align: center">107</td>
<td style="text-align: center">121</td>
<td style="text-align: center">8</td>
<td style="text-align: center">15</td>
</tr>
<tr>
<td style="text-align: center">kaden-channel</td>
<td style="text-align: center">40</td>
<td style="text-align: center">51</td>
<td style="text-align: center">612</td>
<td style="text-align: center">20</td>
<td style="text-align: center">10</td>
<td style="text-align: center">7</td>
<td style="text-align: center">22</td>
<td style="text-align: center">4</td>
<td style="text-align: center">20</td>
</tr>
<tr>
<td style="text-align: center">livedoor-homme</td>
<td style="text-align: center">3</td>
<td style="text-align: center">161</td>
<td style="text-align: center">37</td>
<td style="text-align: center">60</td>
<td style="text-align: center">3</td>
<td style="text-align: center">8</td>
<td style="text-align: center">131</td>
<td style="text-align: center">8</td>
<td style="text-align: center">29</td>
</tr>
<tr>
<td style="text-align: center">movie-enter</td>
<td style="text-align: center">19</td>
<td style="text-align: center">2</td>
<td style="text-align: center">2</td>
<td style="text-align: center">25</td>
<td style="text-align: center">0</td>
<td style="text-align: center">0</td>
<td style="text-align: center">0</td>
<td style="text-align: center">2</td>
<td style="text-align: center">726</td>
</tr>
<tr>
<td style="text-align: center">peachy</td>
<td style="text-align: center">45</td>
<td style="text-align: center">459</td>
<td style="text-align: center">9</td>
<td style="text-align: center">137</td>
<td style="text-align: center">1</td>
<td style="text-align: center">9</td>
<td style="text-align: center">17</td>
<td style="text-align: center">1</td>
<td style="text-align: center">86</td>
</tr>
<tr>
<td style="text-align: center">smax</td>
<td style="text-align: center">5</td>
<td style="text-align: center">11</td>
<td style="text-align: center">22</td>
<td style="text-align: center">0</td>
<td style="text-align: center">416</td>
<td style="text-align: center">334</td>
<td style="text-align: center">0</td>
<td style="text-align: center">0</td>
<td style="text-align: center">3</td>
</tr>
<tr>
<td style="text-align: center">sports-watch</td>
<td style="text-align: center">38</td>
<td style="text-align: center">2</td>
<td style="text-align: center">0</td>
<td style="text-align: center">28</td>
<td style="text-align: center">0</td>
<td style="text-align: center">0</td>
<td style="text-align: center">1</td>
<td style="text-align: center">728</td>
<td style="text-align: center">5</td>
</tr>
<tr>
<td style="text-align: center">topic-news</td>
<td style="text-align: center">498</td>
<td style="text-align: center">6</td>
<td style="text-align: center">29</td>
<td style="text-align: center">65</td>
<td style="text-align: center">0</td>
<td style="text-align: center">3</td>
<td style="text-align: center">8</td>
<td style="text-align: center">61</td>
<td style="text-align: center">24</td>
</tr>
</tbody>
</table>

<br/>

上記の結果をテストデータに対して行った結果．

<table border="1" class="table-result" >
<thead>
<tr>
<th style="text-align: center">テスト</th>
<th style="text-align: center">0</th>
<th style="text-align: center">1</th>
<th style="text-align: center">2</th>
<th style="text-align: center">3</th>
<th style="text-align: center">4</th>
<th style="text-align: center">5</th>
<th style="text-align: center">6</th>
<th style="text-align: center">7</th>
<th style="text-align: center">8</th>
</tr>
</thead>

<tbody>
<tr>
<td style="text-align: center">dokujo-tsushin</td>
<td style="text-align: center">0</td>
<td style="text-align: center">9</td>
<td style="text-align: center">0</td>
<td style="text-align: center">66</td>
<td style="text-align: center">0</td>
<td style="text-align: center">0</td>
<td style="text-align: center">1</td>
<td style="text-align: center">0</td>
<td style="text-align: center">3</td>
</tr>
<tr>
<td style="text-align: center">it-life-hack</td>
<td style="text-align: center">7</td>
<td style="text-align: center">1</td>
<td style="text-align: center">44</td>
<td style="text-align: center">2</td>
<td style="text-align: center">11</td>
<td style="text-align: center">12</td>
<td style="text-align: center">3</td>
<td style="text-align: center">1</td>
<td style="text-align: center">3</td>
</tr>
<tr>
<td style="text-align: center">kaden-channel</td>
<td style="text-align: center">5</td>
<td style="text-align: center">6</td>
<td style="text-align: center">54</td>
<td style="text-align: center">4</td>
<td style="text-align: center">1</td>
<td style="text-align: center">4</td>
<td style="text-align: center">1</td>
<td style="text-align: center">1</td>
<td style="text-align: center">2</td>
</tr>
<tr>
<td style="text-align: center">livedoor-homme</td>
<td style="text-align: center">1</td>
<td style="text-align: center">25</td>
<td style="text-align: center">9</td>
<td style="text-align: center">5</td>
<td style="text-align: center">0</td>
<td style="text-align: center">0</td>
<td style="text-align: center">19</td>
<td style="text-align: center">2</td>
<td style="text-align: center">10</td>
</tr>
<tr>
<td style="text-align: center">movie-enter</td>
<td style="text-align: center">0</td>
<td style="text-align: center">0</td>
<td style="text-align: center">0</td>
<td style="text-align: center">3</td>
<td style="text-align: center">0</td>
<td style="text-align: center">0</td>
<td style="text-align: center">0</td>
<td style="text-align: center">0</td>
<td style="text-align: center">91</td>
</tr>
<tr>
<td style="text-align: center">peachy</td>
<td style="text-align: center">2</td>
<td style="text-align: center">48</td>
<td style="text-align: center">1</td>
<td style="text-align: center">13</td>
<td style="text-align: center">0</td>
<td style="text-align: center">2</td>
<td style="text-align: center">1</td>
<td style="text-align: center">0</td>
<td style="text-align: center">11</td>
</tr>
<tr>
<td style="text-align: center">smax</td>
<td style="text-align: center">0</td>
<td style="text-align: center">7</td>
<td style="text-align: center">3</td>
<td style="text-align: center">0</td>
<td style="text-align: center">41</td>
<td style="text-align: center">28</td>
<td style="text-align: center">0</td>
<td style="text-align: center">0</td>
<td style="text-align: center">0</td>
</tr>
<tr>
<td style="text-align: center">sports-watch</td>
<td style="text-align: center">3</td>
<td style="text-align: center">0</td>
<td style="text-align: center">0</td>
<td style="text-align: center">2</td>
<td style="text-align: center">0</td>
<td style="text-align: center">0</td>
<td style="text-align: center">0</td>
<td style="text-align: center">92</td>
<td style="text-align: center">1</td>
</tr>
<tr>
<td style="text-align: center">topic-news</td>
<td style="text-align: center">56</td>
<td style="text-align: center">1</td>
<td style="text-align: center">1</td>
<td style="text-align: center">9</td>
<td style="text-align: center">0</td>
<td style="text-align: center">0</td>
<td style="text-align: center">0</td>
<td style="text-align: center">7</td>
<td style="text-align: center">2</td>
</tr>
</tbody>
</table>

<br/>

分類結果の表から dokujo-tsushin と sports-watch と topic-news と movie-enter が上手に分類できるように見えます．しかしながら，トピック2は it-life-hack と kaden-channel が混在しました．ただ，その両者はもともと近しいジャンルのように見えるので，妥当な結果とも言えます．<br/><br/>

<strong><span style="font-size:large;">HDP</span></strong><br/><br/>

ここで，LDAでトピックモデルを行ったとき，トピック数を指定して学習しました．例では入力データのカテゴリー数と同数を設定しましたが，本当にこのトピック数が適正な値かどうかは，わかりません．いくつもの候補を設定して，パープレキシティや分類結果を確認して決定する工程が必要になると思います．<br/><br/>

その工程が面倒なので，HDP（Hierarchical Dirichlet Process，階層ディリクレ過程）を用いて，トピック数自体を推定しました．

<pre class="brush: oc">
# 推定トピック数の最大値はデフォルトで150に設定されている
hdp = models.hdpmodel.HdpModel(corpus, id2word=dictionary, alpha=0.1)
</pre>

<br/>

学習結果の評価は，<ins><a href="https://stackoverflow.com/questions/31543542/hierarchical-dirichlet-process-gensim-topic-number-independent-of-corpus-size" target="_blank">こちら</a></ins> を参考に推定したトピックそれぞれの重みを加算して，比較しました．

<pre class="brush: oc">
def topic_prob_extractor(hdp, save_csv_file=None):
    import pandas as pd
    shown_topics = hdp.show_topics(num_topics=-1, formatted=False)
    topics_nos = [x[0] for x in shown_topics]
    weights = [sum([item[1] for item in shown_topics[topicN][1]]) for topicN in topics_nos]
    data_frame = pd.DataFrame({'topic_id': topics_nos, 'weight': weights})
    if save_csv_file is not None:
        data_frame.to_csv(save_csv_file)
    return data_frame
</pre>

<div style="text-align:center;"><img alt="hdp.png" src="http://seesaakyoto.up.seesaa.net/image/hdp-thumbnail2.png" width="500" height="399" border="0" onclick="location.href = 'https://seesaakyoto.seesaa.net/upload/detail/image/hdp-thumbnail2.png.html'; return false;" style="cursor:pointer;" /></div>

最も重みが高い9が最適なトピック数となるでしょうか．25や50手前でいきなり重みがポンっと上がっているのがすごく気になります．<br/><br/>

<span style="font-size:large;"><strong>最適なトピック数は？</strong></span>

<br/><br/>

今回だと，最適なトピック数は9のようにみえます．しかしながら，より複雑なデータ（不特定多数が書いた，文章作成規則があいまい，など）を対象とした場合，HDPでも判定が難しい方が多いです．<ins><a href="https://datascience.stackexchange.com/questions/128/latent-dirichlet-allocation-vs-hierarchical-dirichlet-process/499#499" target="_blank">色々な質問サイト</a></ins> を眺めていると，はやりHDPでは決められずに，LDAの計算を反復して決定してるのをよく見かけます．<br/><br/>


<span style="font-size:large;"><strong>まとめ</strong></span><br/><br/>

Topic Modelのトピック数を幾つに設定することが大きな問題です．望ましい結果と比べて地道に設定していくことになると思います．しかしながら，Topic Modelは良い分類結果をもたらし，非常に興味深いですね．
<a name="more"></a>

]]><![CDATA[
]]></content:encoded>
            <category>機械学習</category>
      <author>Seesaa京都スタッフ</author>
      <guid isPermaLink="false">blog:https://blog.seesaa.jp,seesaakyoto/457025212</guid>
                </item>
        <item>
      <link>https://seesaakyoto.seesaa.net/article/456444752.html</link>
      <title>fastText が Python をサポートしてた</title>
      <pubDate>Thu, 25 Jan 2018 17:31:52 +0900</pubDate>
            <description>エモトです．7.1ch最高かよ．引き続き通いたいと思ってます．いぜんfastTextに関して，fastTextをPythonで使いたいならpyfasttext という記事を2017年10月に書いたように，fastTextはPythonを公式にサポートせず，公式サイトにも非公式のパッケージを使ってよという記載があったのを記憶してます．ところが，fastText の readme を眺めていると， Building fastText for Python が追加されている．更新履..</description>
            <itunes:summary><![CDATA[
エモトです．7.1ch最高かよ．引き続き通いたいと思ってます．

いぜんfastTextに関して，<a href="http://seesaakyoto.seesaa.net/article/453981586.html" target="_blank">fastTextをPythonで使いたいならpyfasttext</a> という記事を2017年10月に書いたように，fastTextはPythonを公式にサポートせず，公式サイトにも非公式のパッケージを使ってよという記載があったのを記憶してます．

ところが，fastText の readme を眺めていると， <a href="https://github.com/facebookresearch/fastText#building-fasttext-for-python" target="_blank">Building fastText for Python</a> が追加されている．更新履歴を確認したところ，去年の11月あたりに追加されたようです．

$ git clone https://github.com/facebookresearch/fastText.git
$ cd fastText
$ pip install .
pip1行で済まないのがちょっと気になりますが，非公式のパッケージは本家fastTextのバージョンアップに追いつかなくて利用できないことがあったので，公式で対応されたのは嬉しいことですね．

<a></a>

]]></itunes:summary>
      <content:encoded><![CDATA[
エモトです．7.1ch最高かよ．引き続き通いたいと思ってます．<br /><br />いぜんfastTextに関して，<ins><a href="http://seesaakyoto.seesaa.net/article/453981586.html" target="_blank">fastTextをPythonで使いたいならpyfasttext</a></ins> という記事を2017年10月に書いたように，fastTextはPythonを公式にサポートせず，公式サイトにも非公式のパッケージを使ってよという記載があったのを記憶してます．<br /><br />ところが，fastText の readme を眺めていると， <ins><a href="https://github.com/facebookresearch/fastText#building-fasttext-for-python" target="_blank">Building fastText for Python</a></ins> が追加されている．更新履歴を確認したところ，去年の11月あたりに追加されたようです．<br /><br /><blockquote>$ git clone <a href="https://github.com/facebookresearch/fastText.git" target="_blank">https://github.com/facebookresearch/fastText.git</a><br />$ cd fastText<br />$ pip install .</blockquote><br />pip1行で済まないのがちょっと気になりますが，非公式のパッケージは本家fastTextのバージョンアップに追いつかなくて利用できないことがあったので，公式で対応されたのは嬉しいことですね．<br /><br /><a name="more"></a>

]]><![CDATA[
]]></content:encoded>
            <category>機械学習</category>
      <author>Seesaa京都スタッフ</author>
      <guid isPermaLink="false">blog:https://blog.seesaa.jp,seesaakyoto/456444752</guid>
                </item>
        <item>
      <link>https://seesaakyoto.seesaa.net/article/455792186.html</link>
      <title>Recurrent Convolutional Neural Networks (RCNN) を使ってテキスト分類してみた</title>
      <pubDate>Tue, 26 Dec 2017 10:37:00 +0900</pubDate>
            <description>エモトです．みなさん，ガルパン最終章は見られましたか？私はまだ二回しか見に行けてません．また近いうちに爆音上映をキメたいです．深層学習（ディープラーニング）といえば，まず先に画像を対象にしたものが例に挙がりますが，今回はテキスト分類をしてみたいと思い，ちょっと試してみました．手法テキストは画像と比較しても，可変長であり，単語（語彙）を順々に書き繋いでいくので，Recurrent Neural Networks (RNN) ベースの手法が良いだろうと思い，Siwei Lai ら..</description>
            <itunes:summary><![CDATA[


エモトです．みなさん，ガルパン最終章は見られましたか？私はまだ二回しか見に行けてません．また近いうちに爆音上映をキメたいです．



深層学習（ディープラーニング）といえば，まず先に画像を対象にしたものが例に挙がりますが，今回はテキスト分類をしてみたいと思い，ちょっと試してみました．



手法



テキストは画像と比較しても，可変長であり，単語（語彙）を順々に書き繋いでいくので，Recurrent Neural Networks (RNN) ベースの手法が良いだろうと思い，Siwei Lai らが2015年に発表した <a href="https://www.aaai.org/ocs/index.php/AAAI/AAAI15/paper/view/9745" target="_blank">
Recurrent Convolutional Neural Networks for Text Classification</a> から，Recurrent Convolutional Neural Networks (RCNN) を用いて，検証しました．



RCNN



RCNN は名前が示す通りに，recurrent と convolutional を組み合わせた NN です．時系列データの扱いにかけた recurrent に，画像分類でその性能を発揮した convolutional の組合せ，なにか強そうですね．ここで，同様な手法として，Bradbury らが提案した <a href="https://arxiv.org/abs/1611.01576" target="_blank">QRNN</a> というのがあります．こちらは RCNN が組み合わせに対して，CNN を擬似的に recurrent にするように設計されています．対照実験を行いたいところですが，時間の都合上，今回は RCNN のみになります．



RCNN の実装は Keras で行いました．実装したモデルを下図になります．冒頭に深層学習と言いましたが，それほど層は深くないです．ここで，vanilla RNN ではなく LSTM を使用して，入力テキストの形態素解析には <a href="https://github.com/neologd/mecab-ipadic-neologd" target="_blank">MeCab (mecab-ipadic-NEologd)</a> ，埋め込み層には <a href="https://github.com/facebookresearch/fastText" target="_blank">fastText</a> を使用しました．



<a href="http://seesaakyoto.up.seesaa.net/image/keras-rcnn.png" target="_blank"><img alt="keras-rcnn.png" src="http://seesaakyoto.up.seesaa.net/image/keras-rcnn-thumbnail2.png" width="500" border="0" height="321"></a>



実験



アマゾンのレビューデータを用いて，コメントをレーティングごとに分類しました．商品286個のレビューデータ115,349件を用意して，以下のように分けて実験を行いました．





trainvaltesttotal


83051922823070115349





結果



学習したモデルでテストデータを分類した結果を下記に示します（レーティングは1から始まりますが，計算の都合上0からになっています）．この表は行ごとに予測したレーティングが実際はどのレーティングだったかをカウントしています（対角行列のように対角線上に数値が集まっていれば良い結果といえます）．





予測＼正解01234


05051671318197
11401831798863
2101193634439394
3529647420271665
49891597250112074





予想と実際のレーティングが一致したのは，約68% となりました．少し精度が低いと思いましたが，表を見ると，低いレーティングは低く，高いレーティングは高く，正解に近く分布しているので，完全一致という指標でなければ，まずまずの結果のように見えます．言い訳をしておくと，レーティングという人間の曖昧さ，日本語という自然言語の難しさから，この手法と結果は悪くはないと思っています．



まとめ



RCNNでテキスト分類を行い，比較的良い結果が得られました．しかしながら，レーティングのようにラベル付けがはっきりしているデータは多くはなく，文章はメディア（媒体）や書き手によって，いくつもの形になります．銀の弾丸はないと．テキスト分離は難しい分野ですが，それゆえ面白いですね．



最後に，本年，本ブログへの訪問，ありがとうございました．来年もよろしくお願いします．





<a></a>

]]></itunes:summary>
      <content:encoded><![CDATA[
<style>
.table-result {
  border-collapse: collapse;
  width: 400px;
  text-align: center;
  margin-left: auto;
  margin-right: auto;
}
.table-result th {
  background-color: #cccccc;
}
</style>

エモトです．みなさん，ガルパン最終章は見られましたか？私はまだ二回しか見に行けてません．また近いうちに爆音上映をキメたいです．

<br/><br/>

深層学習（ディープラーニング）といえば，まず先に画像を対象にしたものが例に挙がりますが，今回はテキスト分類をしてみたいと思い，ちょっと試してみました．

<br/><br/>

<strong><span style="font-size:large;">手法</span></strong>

<br/><br/>

テキストは画像と比較しても，可変長であり，単語（語彙）を順々に書き繋いでいくので，Recurrent Neural Networks (RNN) ベースの手法が良いだろうと思い，Siwei Lai らが2015年に発表した <ins><a href="https://www.aaai.org/ocs/index.php/AAAI/AAAI15/paper/view/9745" target="_blank">
Recurrent Convolutional Neural Networks for Text Classification</a></ins> から，Recurrent Convolutional Neural Networks (RCNN) を用いて，検証しました．

<br/><br/>

<strong><span style="font-size:large;">RCNN</span></strong>

<br/><br/>

RCNN は名前が示す通りに，recurrent と convolutional を組み合わせた NN です．時系列データの扱いにかけた recurrent に，画像分類でその性能を発揮した convolutional の組合せ，なにか強そうですね．ここで，同様な手法として，Bradbury らが提案した <ins><a href="https://arxiv.org/abs/1611.01576" target="_blank">QRNN</a></ins> というのがあります．こちらは RCNN が組み合わせに対して，CNN を擬似的に recurrent にするように設計されています．対照実験を行いたいところですが，時間の都合上，今回は RCNN のみになります．

<br/><br/>

RCNN の実装は Keras で行いました．実装したモデルを下図になります．冒頭に深層学習と言いましたが，それほど層は深くないです．ここで，vanilla RNN ではなく LSTM を使用して，入力テキストの形態素解析には <ins><a href="https://github.com/neologd/mecab-ipadic-neologd" target="_blank">MeCab (mecab-ipadic-NEologd)</a></ins> ，埋め込み層には <ins><a href="https://github.com/facebookresearch/fastText" target="_blank">fastText</a></ins> を使用しました．

<br/><br/>

<div style="text-align:center;"><a href="http://seesaakyoto.up.seesaa.net/image/keras-rcnn.png" target="_blank"><img alt="keras-rcnn.png" src="http://seesaakyoto.up.seesaa.net/image/keras-rcnn-thumbnail2.png" width="500" border="0" height="321" onclick="location.href = 'https://seesaakyoto.seesaa.net/upload/detail/image/keras-rcnn-thumbnail2.png.html'; return false;" style="cursor:pointer;" /></a></div>

<br/><br/>

<span style="font-size:large;"><strong>実験</strong></span>

<br/><br/>

アマゾンのレビューデータを用いて，コメントをレーティングごとに分類しました．商品286個のレビューデータ115,349件を用意して，以下のように分けて実験を行いました．

<br/><br/>

<table border="1" class="table-result" >
<thead>
<tr><th>train</th><th>val</th><th>test</th><th>total</th></tr>
</thead>
<tbody>
<tr><td>83051</td><td>9228</td><td>23070</td><td>115349</td></tr>
</tbody>
</table>

<br/>

<span style="font-size:large;"><strong>結果</strong></span>

<br/><br/>

学習したモデルでテストデータを分類した結果を下記に示します（レーティングは1から始まりますが，計算の都合上0からになっています）．この表は行ごとに予測したレーティングが実際はどのレーティングだったかをカウントしています（対角行列のように対角線上に数値が集まっていれば良い結果といえます）．

<br/><br/>

<table border="1" class="table-result" >
<thead>
<tr><th>予測＼正解</th><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th></tr>
</thead>
<tbody>
<tr><td>0</td><td>505</td><td>167</td><td>131</td><td>81</td><td>97</td></tr>
<tr><td>1</td><td>140</td><td>183</td><td>179</td><td>88</td><td>63</td></tr>
<tr><td>2</td><td>101</td><td>193</td><td>634</td><td>439</td><td>394</td></tr>
<tr><td>3</td><td>52</td><td>96</td><td>474</td><td>2027</td><td>1665</td></tr>
<tr><td>4</td><td>98</td><td>91</td><td>597</td><td>2501</td><td>12074</td></tr>
</tbody>
</table>

<br/>

予想と実際のレーティングが一致したのは，約68% となりました．少し精度が低いと思いましたが，表を見ると，低いレーティングは低く，高いレーティングは高く，正解に近く分布しているので，完全一致という指標でなければ，まずまずの結果のように見えます．言い訳をしておくと，レーティングという人間の曖昧さ，日本語という自然言語の難しさから，この手法と結果は悪くはないと思っています．

<br/><br/>

<span style="font-size:large;"><strong>まとめ</strong></span>

<br/><br/>

RCNNでテキスト分類を行い，比較的良い結果が得られました．しかしながら，レーティングのようにラベル付けがはっきりしているデータは多くはなく，文章はメディア（媒体）や書き手によって，いくつもの形になります．銀の弾丸はないと．テキスト分離は難しい分野ですが，それゆえ面白いですね．

<br/><br/>

最後に，本年，本ブログへの訪問，ありがとうございました．来年もよろしくお願いします．





<a name="more"></a>

]]><![CDATA[
]]></content:encoded>
            <category>機械学習</category>
      <author>Seesaa京都スタッフ</author>
      <guid isPermaLink="false">blog:https://blog.seesaa.jp,seesaakyoto/455792186</guid>
                </item>
      </channel>
</rss>

