読者です 読者をやめる 読者になる 読者になる

データサイエンスしてみる

新米エンジニアがデータサイエンスを勉強する。機械学習とかRとかPythonとか

KH Coderを使って自然言語解析する

統計学 自然言語処理 KHコーダー

日本語の自然言語解析における強力なツールであるKH Coderを使って自然言語解析をしてみます。

対象した文章は青空文庫から夏目漱石の「それから」です。
ちなみにGrahamianは「それから」を読んだことがありません。
なので今回は小説を読まずに小説の内容を予想してみようと思います。

それではさっそくKH Coderを使ってみます。
ちなみにちゃんと使い方を勉強したわけではないので使い方間違っていたらスミマセン…

ダウンロードは下記からできます。
KH Coder Index Page

起動して解析対象の文章を読み込みます。
プロジェクト→新規→参照で文章を選びます。

次に文章の前処理を行います。
前処理→分析対象ファイルのチェック、次に前処理→前処理の実行です。

これで前処理が終わるので、解析に移ります。
KHコーダーは簡単にいろんな解析を実行することができます。

今回は文章中の単語について注目して解析します。
ツール→抽出後から解析を実行できます。

階層的クラスター解析と共起ネットワークについて実行します。
パラメータをいろいろと設定できますが、とりあえずデフォルトでOKです。
出現数による取捨選択は、選択対象となる単語を出現数で足切りできます。
オプションの方法や距離は計算するときの方法や距離の定義になります。
出現数は簡単ですが、オプションは今度別途説明してみます。

さて、解析を実行してみましょう。
階層的クラスター分析の結果はこんな感じです。
f:id:Grahamian:20160919194400p:plain

次に共起解析はこんな感じです。
f:id:Grahamian:20160919194441p:plain

クラスター解析の結果は「父さん」「兄さん」「結婚」「働」「金」など生活に近い言葉が同じクラスターとなっています。
このことから生活して様子を書いた小説だとわかります。
戦争小説とかSFとかではなさそうですね。
共起分析の結果を見ると「自分」が共起の中心になっていることがわかります。
「自分」から「父」「三千代」が共起しており、他の人物が繋がっていないことから「自分」と「父」「三千代」のつながりが物語の中心に見えますね。
また、「助」という字もそこそこ強い共起の中心になっているので「助」がキーワードっぽいですね。
でも「助ける」なのか「助けられる」なのかは分からないです。

上記解析結果から、「それから」はなんとなーく家族のことを書いた小説であることがわかりますね。
次回はパラメータについて説明してみます。

Rを使ったポアソン分布における最尤推定

R言語 統計学

本格的に統計を学ぶためにデータ解析のための統計モデリング入門、いわゆる緑本を読み始めました。
ナナメ読みで概観を捉えながら、追ってRで手を動かして勉強してます。
統計はツマミ食いでしか学んでいなかったので、こうやって体系的に学ぶと、いままでの知識が繋がって面白いですね。

今回は緑本の最初にあるポアソン分布について実際にRを使って勉強します。
内容は本に書いてあるコードを追っているだけです。
※コード中の"data.RData"は緑本の参考データです。

load("data.RData")
hist(data,breaks = seq(-0.5,9.5,1))

これでこんな感じのヒストグラムが得られます。
f:id:Grahamian:20160912221454p:plain
さて、この得られたヒストグラムについて最も適したパラメータを求めます。
今回は得られたデータがポアソン分布に基づいていると仮定したとこから始まります。
ポアソン分布は平均値λのみをパラメータとして持ちます。
そのため、今回はλのみ考えます。

最も適したλを求めるために最尤推定法を使います。
最尤推定法とは尤度という値の当てはまりのよさを示す統計量です。
これは尤度関数L(λ)で求まります。
L(λ)は各応答変数の出現確率の積です。
このままでは使いにくいので、対数をとったlogLを対数尤度関数として使います。
こうすることで対数尤度logL最も大きい(ゼロに近い)とき分布への値の当てはまりが良い、ということになります。

では、実際にRで求めてみましょう。

logL <- function(m) sum(dpois(data,m,log=TRUE))
lambda <- seq(2,5,0.1)
plot(lambda,sapply(lambda, logL),type="l")

これにより次のようなλvsLogLのグラフが得られます。
f:id:Grahamian:20160912221701p:plain
このグラフを微分したときゼロになるのが最尤推定値です。
ね、簡単でしょ?

ということで、Rを使うことで非常に簡単に最尤推定を行うことができました。
まだまだ分からないことだらけですが、手を動かすのは大事ですね。

トピックモデルについて簡単に考えてみる

自然言語処理

たまには解析ではなく解析モデルについて考えてみます。

今回考えるのは基本のトピックモデル。
トピックモデルとは種々の文章があったとき、それらがどのトピックに属するのか分類するためのモデルです。
クラスタリングの一種とも言えるでしょう。

例えば、ニュースには政治や経済、スポーツ、科学などの欄があるでしょう。
この「政治」とか「経済」とかによって、記事の中に出てくる単語に違いが出る、というのがトピックモデルの基本になります。
自然な仮定ですよね?
この考えにもとづいて分布を作って、文章がどのジャンルに属するのか分類するのがトピックモデルです。

具体的には政治のニュースを集めて政治のニュースに使われる単語の分布を作っておきます。
次にジャンルが未知のニュースが来た時、そのニュース中の単語の分布を調べます。
このときに政治の分布と近ければ、政治のニュースではないか?と推定することができます。
簡単ですね。

こんな感じにいろんなジャンルの分布を作っておけば、記事を簡単に分類することができます。
手法が単純なため、簡単に実装することができ、シンプルさに比べて高い効果を期待できる手法みたいです。
実装はpythonならgensimというライブラリで簡単に実装できるようです。

もちろん、モデルの作成や帰属には多くの手法が存在し、それぞれ特徴があります。
統計や数学が必要ですが難しくはなさそうなので、なるべく抽象的にでも理解したいとこです。

まずは実際に実装してその威力を確かめたいですね。

RMeCabで文章マトリックスとTF-IDFを計算する

R言語 自然言語処理

今回はテキストマイニングへの一歩としてRMecabを勉強します。
RMeCabの標準関数として文章の単語マトリクスとTF-IDFの計算を行います。

単語マトリクスとは複数の文章における単語の出現頻度をベクトル表示したものです。
bag of wordsモデルでは単語同士を互いに独立に扱うため、このような単語マトリクスが用いられるようです。
次のTF-IDFは文章中の出現単語への重み付けです。
ある文章中に出現する単語がほかの文章で出現しない場合は、その単語はその文章を特徴付ける単語であるといえるでしょう。
その単語がどれくらい特徴的かを表すのがTF-TDFになります。
詳しい数学的な背景は置いておくとしてとりあえず解析してみましょう。

今回使う文章は青空文庫より夏目漱石の「こころ」、「三四郎」、「それから」を使用しました。
青空文庫 Aozora Bunko

それぞれテキスト形式をダウンロードし、一つのフォルダに保存しておきます。
一つのフォルダ直下にテキストファイルを置いておくことで手軽に一括で解析できます。
私の環境では"C:/work/aozora"という形でC直下に作業用のフォルダに突っ込んでます。

さて、さっそくテキストマイニングをします。
今回は名詞のみ抽出して計算します。

library(RMeCab)
matrix <- docMatrix("C:/work/aozora", pos=c("名詞"))
tfidf <- docMatrix("C:/work/aozora", weight="tf*idf")

なんと解析はこれだけで出来ます。
結果はこんな感じ

単語マトリクス
                           docs
terms                       kokoro.txt sanshiro.txt sorekara.txt
  -                                 71           75           86
  -------------------------          2            2            2
  [[LESS-THAN-1]]                    0            0            0
  [[TOTAL-TOKENS]]              104587        96039       113026
  あい                               5            5            9
  あいさつ                          18           16           14
  アイスクリーム                     3            0            1
  あいそ                             1            1            2
  あいだ                            17           79            1
  あいまい                           2            1            5
  アイロニー                         2            2            0
  あおみ                             1            0            0
  あか                               3            4            2
  あからさま                         1            2            1
  あかり                             1            0            2
  あき                               2            1           10
  あく                               3            0            2
  あくび                             1            2            2
  あぐら                             2            5            5
  あげく                             2            0            0
  あご                               2            3            7
  あし                               2            2            2
  あすこ                             3           10            2
  あそこ                             1            0            0
  あたい                             3            0            2
  あたり                             3            7           11
  あちら                             4            1            0
  あて                              11            5            9
  あと                              78           73           20
  あなた                           187           61           29
TF-IDF
                           docs
terms                       kokoro.txt sanshiro.txt sorekara.txt
  -                          71.000000    75.000000    86.000000
  -------------------------   2.000000     2.000000     2.000000
  あい                        5.000000     5.000000     9.000000
  あいさつ                   18.000000    16.000000    14.000000
  アイスクリーム              4.754888     0.000000     1.584963
  あいそ                      1.000000     1.000000     2.000000
  あいだ                     17.000000    79.000000     1.000000
  あいまい                    2.000000     1.000000     5.000000
  アイロニー                  3.169925     3.169925     0.000000
  あおみ                      2.584963     0.000000     0.000000
  あか                        3.000000     4.000000     2.000000
  あからさま                  1.000000     2.000000     1.000000
  あかり                      1.584963     0.000000     3.169925
  あき                        2.000000     1.000000    10.000000
  あく                        4.754888     0.000000     3.169925
  あくび                      1.000000     2.000000     2.000000
  あぐら                      2.000000     5.000000     5.000000
  あげく                      5.169925     0.000000     0.000000
  あご                        2.000000     3.000000     7.000000
  あし                        2.000000     2.000000     2.000000
  あすこ                      3.000000    10.000000     2.000000
  あそこ                      2.584963     0.000000     0.000000
  あたい                      4.754888     0.000000     3.169925
  あたじけない                1.584963     0.000000     1.584963
  あたたかい                  3.169925     0.000000     1.584963
  あたり                      3.000000     7.000000    11.000000

生の結果には数字や記号が混じっていて非常に見づらいのでそれらを削除してやる必要がありますが、それは追々やっていくということで。

単語マトリクスの作成はともかく、TF-IDFは自分の手で書くにはちょっと面倒なので、このように手軽に使えるのは便利です。

Rはオンメモリなので大量のテキスト解析はできませんが実験レベルではやはり強力ですね。
今後もRMeCabの関数を一通り触ってみようと思います。

主成分分析したあとSVMを回してみる

Python 機械学習

前回に引き続き、主成分分析をしてからSVMを回してみます。
主成分分析とSVMは話したので過去の記事を参照してください。

grahamian.hatenablog.com

grahamian.hatenablog.com

それでは早速SVMを回してみましょう。
コードは主成分分析も含めてこんな感じです。
データセットはirisを使用。

import sklearn
import pylab
from sklearn.decomposition import PCA
from sklearn import datasets
from sklearn.cluster import KMeans
from sklearn.cross_validation import train_test_split
from sklearn.svm import LinearSVC

iris = datasets.load_iris()
x = iris.data
y = iris.target

pca = PCA(n_components = 2)
pca.fit(x)
x_pca=pca.transform(x)

data_train, data_test, label_train, label_test = train_test_split(x_pca, y)

estimator = LinearSVC(C=1.0)
estimator.fit(data_train,label_train)
label_predict = estimator.predict(data_test)

from sklearn.metrics import confusion_matrix
confusion_matrix(label_test, label_predict)

結果は次が得られます。

array([[17,  0,  0],
       [ 0,  9,  2],
       [ 0,  0, 10]])

まあ、ほぼ正解って感じですね。
ちなみに元のデータを使っても正答率はほぼ同様です。

前回の散布図を見ると2クラスターの分離が難しそうでしたが、さすがSVMなのかキレイに分割できました。
機械学習は強力な手法だと感じますね。

Scikit-learnでirisを主成分分析してみる

Python 機械学習

主成分分析(Principal Component Analysis)とはデータの各ベクトルを独立にし次元を下げる手法です。
データを独立にするとは入力ベクトルを直行にさせると考えればOKです。
複数のベクトルの要素を見て独立なベクトルを再構築させます。
次元の低減はベクトルへの寄与度に応じてベクトルを削除していく、というものです。
(厳密なことは分かってないので要勉強)

主成分分析の目的としては、いわゆる次元の呪いを回避するにあります。
次元の呪いとは、多次元化による計算コストの爆発と機械学習時の精度低下です。
前者は容易に想像がつくかと思いますが、面白いのは後者です。
機械学習をするときはデータがたくさんあったほうが良いと一般に考えられます。
しかし、次元の低下という情報を減らすことによって精度が向上します。
ノイズや過学習が減るのでしょうか?
詳しいことはより勉強してみたいと思います。

主成分分析はここが非常に分かりやすいので参考になります。
http://dev.classmethod.jp/statistics/pythonscikit-learn-pca1/

さて、今回も早速コードを書いてみようと思います。
今回はirisを使用します。
もとのデータは4次元150行のデータです。
これを主成分分析して2次元に圧縮します。

import sklearn
import pylab
from sklearn.decomposition import PCA
from sklearn import datasets

iris = datasets.load_iris()
x = iris.data
y = iris.target

pca = PCA(n_components = 2)
pca.fit(x)
x_pca=pca.transform(x)

pylab.scatter(x_pca[:,0],x_pca[:,1])

結果はこんな感じのグラフになります。
3種類のアヤメのデータを含んでいるはずなので、次元圧縮してしまうと少し分解能が悪いように見えますね。

f:id:Grahamian:20160823200515p:plain

次回はこのデータを使って分類してみようと思います。

scikit-learnのSVMで数字を線形分離してみる

Python 機械学習

先日はanacondaを導入して簡単なプロットをしてみました。
が、anacondaはscikit-learnのような機械学習ライブラリがまとめて入っています。
せっかくなので、簡単な機械学習について手を出してみようと思います。

参考にしたのは下記ブログです。
参考というかそのまんま写経させていただきました。
先人に感謝!

sucrose.hatenablog.com

内容としてはグレースケールの数字画像をSVMで分類する、というものです。
SVMについての説明はまた今度ということで、とりあえずやってみます。

from sklearn.datasets import load_digits
from sklearn.cross_validation import train_test_split
from sklearn.svm import LinearSVC

digits = load_digits(2)

data_train, data_test, label_train, label_test = train_test_split(digits.data, digits.target)

estimator = LinearSVC(C=1.0)
estimator.fit(data_train,label_train)
label_predict = estimator.predict(data_test)

from sklearn.metrics import confusion_matrix
confusion_matrix(label_test, label_predict)

これで結果として下記が返ってきました。

array([[49,  0],
       [ 0, 41]])

実際のlabelと予想したlabelがすべてあっているので100%分離ですね。
と、こんな感じにSVMを簡単に実装することができるscikit-learnさんマジでスゴいという話でした。