プリキュアとセーラームーンはどちらの方がサザエさんに近いのか?

この記事ではこんなことを書くよ

はじめに

計算機分野に所属する人たちは時々、本当に間抜けなことを真面目に取り組もうとします。

例えば、自然言語処理の最新手法"word2vec"で艦これ加賀さんから乳を引いてみるとか眼鏡っ娘分類器を作る話とか。

ぼくも多分に漏れず、間抜けなことをよく取り組もうとします。 きっと、データサイエンティストと言っているけど、実際は、データマゾヒストなのですね。

さて、きょう、取くんで見る課題は「プリキュアセーラームーンはどっちの方がサザエさんに近いのだろう?」というお題です。

実にどーでもいいお題ですが、簡単に答えられる人もそうそういないでしょう。

Googleにも聞いてみましたが、満足な答えは得られませんでした。

それでは、計算機に聞いてみることにします。

やってみること

最近、t-SNEという新しいおもちゃを知ったので、これを試してみたいのが、本音です。

類似度を計算するなら、word2vecとかdoc2vecとかもっとスマートな方法があります。

でも、そ・う・じゃ・な・く・て。ぼくは2次元平面にプロットしたいのです。

ときどき、「えっ、ベクトル空間とかなにそれ?めんどくせーからグラフで出してよ。xとyがあるやつ(鼻くそほじほじ)」とか言われるたびに「くっそーいつかfxxxkしてやる!」と思っていたので、2次元平面で表現したいのです。

t-SNEは高次元空間を2次元平面に射影するのを得意としているようです。著者のHPをみると、とてもクールな2次元プロットの例がたくさん見れます。

今回は、wikipediaの記事からデータを作って、tSNEに突っ込んで見ることを目標とします。

そもそもtSNEって何なん?

ここに詳しく書いてありますが、長いんで面倒くさいですよね。ぼくが理解したことをかいつまんで書いていこうと思います。

そもそもSNEって何なん?

そもそもSNEの話をしなくてはいけません。

SNE(Stochastic Neighbor Embedding)は高次元空間のデータを低次元(だいたい目標は2次元)に射影するのを目的とするアルゴリズムです。

「えっ、それPCAでいいじゃん」っていう方、もう少しお待ちくださいね。あとで書きます。

SNEの基本原理は、こんな感じです。

  • 高次元空間と低次元空間の両方で条件付き確率を考える。
    • 高次元空間で、ある点x_iがすべての点からx_jをサンプリングする確率を延々を求めます。この分布をp_(j|i)とします。
    • 低次元空間でも、ある点y_iがすべての点からy_jをサンプリングする確率を延々を求めます。この分布をq_(j|i)とします。
  • p(j|i)とq(j|i)の差が最小になるように最適化をします。具体的には、分布の差分ですから、カルバック・ライブナー距離の最小化です。この最小化式をコスト関数とします。
  • コスト関数にStochastic Descendentを実行します。アルゴリズムの名前の通りですね。

しかし、SNEには欠点があります。

それは、パラメタの探索範囲が広いことです。

SNEは最適な射影を探すときにlocal最適化に陥るのを避けるために、ガウシアンノイズを加えます。[1]

ガウシアンノイズのパラメタがまた別のパラメタに影響を与えて・・・みたいな感じで、「つまり遅い!」ということです。

t-SNEはこの点を改善しています。コスト関数の中身をとっかえて、条件付き確率の計算をガウス分布でなく、Student-t分布にしてます。

どうして、これでパラメタチューニング問題が解決できるのか、まだわかってません。が、解決できたと書いてあります。

次元削減だったらPCAでいーじゃん

話が前後してしまいました。

高次元データでは、「非線形なデータの塊」[2]みたなものが存在(することがある)します。

scikit-learnの画像なんかはイメージしやすいと思います。

こういった「非線形な塊」を低次元に射影するには、「塊どうしは近くに配置したいけど、同時に塊でない点は遠くに配置したい」という希望を満たす射影でないといけないわけです。

PCAのような線形なテクニックではうまくいきません。というのも、「似てない点はとりあえずどっかやってまえ〜」という思想なので、「非線形な塊」をうまく低次元に射影できないのです。

というのが論文に書いてあった内容です。

個人的な理解だと、「PCAは共分散行列の固有値分解をえいや!ってやってるだけじゃん。分解した後をみてないじゃん。SNEは違うもんね。ちゃんと射影後の分散をみてるもんね(^^)」by 筆者 だと解釈してます。

使ってみる

さて、実装はすでに公開されているので、使うだけです。

作者のページでも公開されてますが、アルゴリズムを忠実に再現しているので遅いです。pythonならscikit-learnが良いでしょう。

ここでもscikit-learnを使います。

t-SNEを使うまえに、次元削減をしておくと良いです。とここに書いてある。

密な行列ならPCAをスパースな行列ならSVDを使います。

ここでは単語出現数matrix、通称term document matrixなので、スパースです。

なのでSVDを使います。

svdオブジェクトの入力はscipy.sparse.csr.csr_matrixなので、うまいこと変換していてくださいね。

from sklearn.decomposition import TruncatedSVD
X = csr_matrix(csc_matrix)
svd = TruncatedSVD(n_components=low_dims, random_state=0)
X_input = svd.fit_transform(X)

後は、tSNEに入れるだけです。

from sklearn.manifold import TSNE
model = TSNE(n_components=2, perplexity=40, verbose=2)
two_dimension_array = model.fit_transform(X_input)

two_dimension_arraynumpy.arrayです。

おしまい!

せっかくなので、二次元平面にプロットしてみましょう。

Rでプロットすることにします。

two_dimension_arrayにラベルをつけて、csvに保存します。

Rではcsvファイルを読み込んで、directlabelsライブラリでラベル付きの散布図をプロットします。

ラベルに日本語をつけると豆腐(文字が四角になっちゃう現象)になるので、英数でラベルつけてくださいね。

  par(family = "")
  plot_data <- read.table(file = path_plot_data, sep = ",", header = T)
  
  q <- ggplot(plot_data, aes(x=x, y=y)) + geom_point(aes(colour=label))
  aa <- directlabels::direct.label(q)
  ggsave(file = path_png_file, plot = aa, dpi = 100, width = 10, height = 8)

本題 プリキュアセーラームーンはどっちの方がサザエさんに近いのか?

さて、こんな図がプロットされます。

f:id:kensuke-mi:20150717051437p:plain

おやおや、セーラームーンの方がいくぶんか、サザエさんに近いようですね・・。

言い忘れてましたが、関係のないデータも入れておきました。どれくらい離れるか見たかったからです。ridergolgo_titlesultraが関係ないやつですね。仮面ライダーゴルゴ13ウルトラマンですが。

念のため、SVDの結果も見てみましょう。(SVDだけで2次元まで削減した。という意味です)

f:id:kensuke-mi:20150717051441p:plain

おおっ・・・これは・・・全然違う。

プリキュアセーラームーンが似たところにプロットされてたり、ゴルゴ13仮面ライダーが遠くに行ってたり、SVDの結果の方が直感によく合いますね・・・

こっちを採用しましょう。

ユークリッド距離で計算すると、プリキュアの方がわずかに0.12くらいサザエさんに近いです。

というわけで、プリキュアの方がセーラームーンより、わずかにサザエさんに似ているという結論が出ました。

うーん。。。サザエさんプリキュアも日曜に放送してるから。。かな?

まぁ、発火した素性がたまたまあったから、と言われるとそれまでなんだけど・・・

元の空間でcos類似度を計算した方がいいかもしれませんね。

ところで、何か忘れてないでしょうか。

そう、どうしてt-SNEはうまくプロットされなかったのか。

ちょっと試してみました。

高次元でなかったからうまくいかなかった?

実は元の空間は3,000次元ちょっとにすぎません。

これじゃ、高次元空間とは言えないだろ〜ということで、wikipedia青空文庫から文長が長そうな記事をコピペしまくります。

まずはt-SNE

f:id:kensuke-mi:20150717052455p:plain

形は綺麗そうなんだけど・・・・

chrchillの記事がはじっこなのはいいとしてmarxgermanbismarkが離れているのは気になります。

また、iran_rev2(イラン革命)khomeini(ホメイニ)の距離も違和感があります。

あ、そういえば、核問題が進展してよかったですね。

!اَلْحَمْدُ لِلَّهِ

さて、SVDの方をみてましょう。

f:id:kensuke-mi:20150717052501p:plain

t-SNEと違って、ホメイニイラン革命がほぼ同じところに位置したり、マルクスとドイツとビスマルクが同じところに位置するのは直感的に正しそうといえます。

anpan_characters(アンパンマンの登場人物)とkokoro(夏目漱石のこころ)がどっか行っているのは仕方ないですね。内容的も外れ値とみなしてよさそうです。

そういえば、アンパンマンの登場人物という記事はこまーめに整備されているようで感心するばかりです。

毎週、新しいキャラが出ると更新しているのでしょうか・・・・・

さて、この時の次元数は13,000次元でした。ちょい高次元と言ってもいいかな〜と思います。

じゃあ、どーしてt-SNEはビミョーな結果になったのでしょうか?

推測ですが、元の空間で記事に「非線形な塊」が存在してなかったんじゃないかと思います。

t-SNEがプロットした結果が、元の空間での距離を忠実に表現しているのかもしれません。

また、元の空間でノイズが多すぎたのが原因かもしれません。SVDで綺麗にノイズ除去できて、初めて、類似することにプロットできたとか・・・

でもどうやってそれを調べたらいいんだろう。元の空間での分散値でも調べましょうかね・・・。

まとめ

  • t-SNEを使ってみたよ。でも、うまくいかなかったよ。

    • 非線形な塊」が存在しないデータだった?
    • いずれにせよ、図は両方とも出すのがよさそう
  • プリキュアの方が若干、サザエさんに近いらしいよ

[1] 具体的には、射影後の点yにノイズをのせるのだと思います" In addition, in the early stages of the optimization, Gaussian noise is added to the map points after each iteration."と論文に書いてありました〜

[2] non-linear manifoldとか呼ぶみたいです

SPARQLで人類の知にアクセスしよう

やりたいこと

DBpediaにアクセスして、人類の英知を我が物にしたい。

どうやって解決するか?

SPARQLをマスターする。

DBpediaはRDFモデル(正確にはOWL)で記述されているデータである。

データの実体はXMLで記述されるが、データを効率良く取得するには、クエリ言語のSPARQLを使うのが一番よい。 SPARQLでSELECTが実行できるとこまで試してみる。

そもそもRDFモデルってどんなんよ?

グラフモデルの一種。

だいたいのコア概念は

  • すべてのモノ(実体・概念とわず)は「リソース」で表現される
    • リソースはURIで一意に紐付けされている
  • 知識はトリプル(リソース, プロパティ, リソース)で表現できる。トリプルの中身は(主語, 述語, 目的語)
  • プロパティはリソースを表現するモノである。

RDFのクラス関係図はこのスライドの6ページ目がわかりやすい。

SPARQLってなんなんよ?

SPARQLはRDFモデルのデータを探索するためのクエリ言語

SQLっぽいが、トリプルを表現するために、WHERE句の中が特殊だったり、デリミタが.だったり、変数宣言が?がだったりと、演算子が違う。

まずは基本を抑えるために、SELECT命令だけはできるようにする。

SELECT命令を実行するためには

SELECT 変数
WHERE {
    タプル表現のグラフ
}

クエリの書き方はこのスライドがとてもわかりやすい。

エンドポイントはここで公開されているので、簡単に試すことができる。

試しにスライドに従って、クエリを記述してみることにする

SELECT ?p ?o
WHERE
{
    <http://ja.dbpedia.org/resource/東京都> ?p ?o
} LIMIT 10

こんな結果が返ってくる

f:id:kensuke-mi:20150624192547p:plain

いろんなサイトを見た補足(私的な)など

  • 主語はs, 述語はp, 目的語はoで表記することが多い
  • 目的語にはリテラルでデータの内容を指定できる ex. "東京都"
  • 主語と目的語にはリソースを指定できる。述語には、プロパティを指定する
    • プロパティはw3で定義されているプロパティと、DBpedia日本語版で独自のプロパティを指定できる
  • リソースが存在してるorNotはDBpedia 単語とでもGoogle検索すれば、実体が見れる
    • リソースの存在を調べるASKコマンドがSPARQLで利用可能

と、いうことで、人生初の自分で考えたSPARQLクエリを書いてみる。

表現するグラフは「渡辺麻友のバイトサイズは?p」

グラフをクエリにしてみると、

SELECT DISTINCT ?o
WHERE {
<http://ja.dbpedia.org/resource/渡辺麻友>  <http://ja.dbpedia.org/property/バスト> ?o .
}

実行してみる。

71

71! まゆゆのバストサイズは71! (公表値です)

まとめ

71! まゆゆのバストサイズは71!

Dockerで処理をまとめておく

やりたいこと

処理をまとめて簡単に動かせるようにしておきたい。

環境設定とか毎回するの面倒なので、コマンド一発で動かせるくらいにしておきたい。

解決策

Docker使う。

ソースコードを動かせる状態にしておいて、Dockerの仮想環境の中で稼働させる。

そもそもDockerとは

仮想環境を作成する作成できるプラットフォーム。以上。

今回の設定

なので、処理システムをDockerの環境にぶっこんで、DockerコンテナがJsonを標準入力で受け取って、Jsonを標準出力で返すようにすればいい。

具体的な処理内容

具体的には、形態素解析+複合語抽出を行う

形態素解析にはMecab、複合語抽出にはTermExtractを利用する。

TermExtractはすでに作者さんがありがたくもDocker環境化してくれているので、楽。

今回は、このDockerファイルをそのまま継承することにする。

要件など

TermExtractはcontainer内部に学習済みのDBファイルを持つので、定期的にDBファイルをContainerから取り出して、管理できるようにしておく。

作業ログ

pythonでシステム組んで、Dockerfileに記述

TermExtractgit cloneしてくる。

すでに、Mecabのインストール環境は整っているので、特に設定は不要。

Pythonスクリプトで、TermExtractorのラッパー的なものを書く。

処理の流れはこんな感じ

  1. 標準入力でJsonを受け取る。system.pyという名前にしておく。
  2. TermExtractorを呼び出して、複合語抽出
  3. 複合語抽出の結果使って、Mecabで単語分割
  4. Jsonで結果を返却

システム作ったら、Dockerfileにpythonスクリプト群をコピーするレシピを記述する。

Dockerfileコマンドについては参考記事

2 Dockerfileをビルド

TermExtractのDockerは/var/lib/termextract を共有ディレクトリに使うので、ローカルマシンでディレクトリを作っておく。

buildコマンドでdocker imageをビルドする。

docker build -t naoa/termextract .

ビルドできたら、ログインを確認する。

docker run -v /var/lib/termextract:/var/lib/termextract -i -t naoa/termextract /bin/bash

CentOsのcontainerにログインできるはず。

-v /var/lib/termextract:/var/lib/termextractはローカルマシンとContainerの共有ディレクトリを設定している。

-iは標準入力を開きっぱなしにするコマンド

Jsonで入力を与えて、出力を受け取るテストをする。

cat ./dockerfiles/resources/received.json |\
docker run -v /var/lib/termextract:/var/lib/termextract \
-a stdin -a stdout -a stderr -i naoa/termextract python2.7 system.py

system.pyJsonを標準入力でうけとって、いろいろやってから、Jsonを標準出力で返すスクリプト。いまはcontainerの/直下に置いてある。

3 DBのデータを引き継いで利用できるようにする。

前述のようにTermExtractはcontainer内部にDBデータを残すので、新しいcontainerを作りまくっても意味がない。同じcontainerを呼び出して、処理をさせないと、真価が発揮できない。

まず、containerを起動させる。

docker run -v /var/lib/termextract:/var/lib/termextract -i -t naoa/termextract /bin/bash

ログインを確認したら、exitでログアウトする。

この状態だと、containerがExitになっているので、containerを再起動する。

その前に、いまさっき、閉じたばかりのcontainer IDを確認する。

% docker ps -a                              
CONTAINER ID        IMAGE                     COMMAND                CREATED             STATUS                      PORTS               NAMES
36880ed4a975        naoa/termextract:latest   "/bin/bash"            4 minutes ago       Exited (0) 3 minutes ago                        pensive_hawking     

container IDがわかったので、再起動を行う。

docker start 36880ed4a975

これで、containerが再起動した。

最後に、再起動させたcontainerを使って処理をさせる。

cat dockerfiles/resources/received.json |\
docker exec -i 1cb049204e0d python2.7 system.py

docker execは起動中のイメージを呼び出すコマンド。

-iをつけておくと、標準入力がONになる。

最後に、実行したいbashコマンドを書いて実行する。

Jsonが標準出力で返ってくるはず。

これで、データを引き継ぎしながら処理を行えるコンテナが使えるようになった。

最後に

環境設定がめんどうなソフトウェア群はdockerでまとめてしまっていいと思う。

特に実行時間を気にしないbatch処理なら、速度よりも楽さをとるべきでないっすかねー。

文書分類タスクでよく利用されるfeature selection

"Bias Analysis in Text Classification for Highly Skewed Data"(Lei and Huan)を読んでいて、「文書分類タスクでよく使われるfeature selectionは4つある。Information GainとChi-squared testとOdds ratioとBi-Normal Separationだ」みたいなことが書いてあった。

自分の中で、あんまりわかってないまま使ってる感があったので、しっかり調べてみた。

Information Gain

Information GainはよくIGとか省略される。

IGは要は、「クラスとの関連性がでかい単語ほど大きい値になるよ」というやり方。

簡潔にまとめると、

  1. 単語数×クラス数のクロス集計表をつくる。クロス表は(termが出現 or Not)×(クラス=c or Not)の4要素
  2. クロス表で同時確率と周辺確率を求めて、IGの式に代入。値を求める。

とってもわかりやすい説明

Chi-squared test

日本ではみんなカイ二乗検定とよく言う(と思うたぶん)。英語ではChiと省略すると思う(たぶん)

クロス集計表を作りまくって、データ中でよく特徴を示している要因を特定するときに使ったりしていた。

feature selectionも同じ発想で行う。

クロス表をつくる点では、IGと似ている。

が、Chiは「featureとインスタンス(文書)が独立だった場合を仮定して、実際の出現数と差を取る。」という点で異なる。

ちなみに、独立仮定時と実際の差が大きいほど、「クラスとの関係性が大きい単語」とみなされる。

引き続きわかりやすい説明

Bi-Normal Separation

よく頭文字をとってBNSと表現される

これだけは日本語で上手く説明されたところが見つからなかったので、自分で色々と試してみた。

BNSは直感的に説明すると、「正クラスと負クラスでfeatureが出現している量を比較して、その差を値に示す」というもの。

こう書くと、IGとChiと何ら変わらないように聞こえてしまうが、BNSは2クラスでの出現割合を考慮しているところがミソになる(後述)

2値の文書分類タスクを例に考えてみる。

いま、"iphone"というtermが図の回数で文書に登場しているとする。

f:id:kensuke-mi:20150429170802p:plain

まずはこの回数から、tpr(True classに出現する割合)とnpr(False classに出現する割合)を求める。

この例だと、

tpr=19 / (19 + 5), npr=5 / (19 + 5)になる。

そして、tprとnprを「正規累積分布の逆関数」に代入して、値を求める。(「正規累積分布の逆関数」に関しては後述しまーす)

そして、求めた値の差をとって、BNSの値にする。

「正規累積分布の逆関数」をF_inv()と表現すると、BNSは次に式になる。

BNS= | F_inv(tpr) - F_inv(fpr) |

iphoneの例で一連の流れをしめすと、下図のような感じ

f:id:kensuke-mi:20150429171625p:plain

さっきの図でのデータセット中での"iphone"は1.624435603のBNS値を持つことになる。

ちなみに、tprとnprの値を変化させてBNSを求めると、下図のようになった

f:id:kensuke-mi:20150429175614p:plain

IGとChiとBNSの違い

3つとも出発点になっている考え方は似ているのだが、BNSは他の2つと大きく表現方法が違っている。

この違いはSkewed data(クラスに属するデータ量に偏りがでかいデータセット)のときに、差が如実に現れる。

Lei and HuanではSkewed dataにおけるfeature selectionの比較を行っている。

Lei and HuanはIGとChiとオッズ比とBNSを使って、skewed dataからfeature selectionをしてみた。

その結果、IGとChiは選択するfeature数を少なくすれば少なくするほど、Majorなclassのfeatureばかりが選択される現象を報告している。(ちなみにオッズ比は論外の結果だと言っている)

対して、BNSだけは、選択するfeature数を少なくしても、Majorなclassのfeatureばかりが選ばれることはなく、skewed dataに頑健なfeature selectionだと言っている。

つまり

skewed dataで2値分類をするときは、BNSをfeature selectionに使いましょう。

(参考)正規累積分布の逆関数ってなによ

一言で説明すると、「正規累積分布の逆関数をとったもの」。。としか説明できない。

一応、挙動を確かめてみた。

まず、正規確率密度関数から。もちろん平均は0で標準偏差は1

もちろん、一般的に知られている形になる

f:id:kensuke-mi:20150429172111p:plain

そして、確率累積関数にしてみる

f:id:kensuke-mi:20150429172136p:plain

確率累積関数なので、累積確率を代入すると、元の値になる(一応、確認のため)

f:id:kensuke-mi:20150429172229p:plain

累積確率の逆関数を0.9から0.1まで変化させると、左下がりの形になった

f:id:kensuke-mi:20150429172329p:plain

MacでKH coderを動かす

やりたいこと

MacでKH coderを利用可能な状態にしたい

MacOS X Yosemite

解決法

Macをやめる

もう少し噛み砕いて言うと、Windows仮想マシンを立ち上げて、Windows内でKH coderを利用する

やるべきこと

1 Virtual Boxを利用できる状態にする

特に詳しい説明とかいらないと思うので、リンクだけ

2 Modern.IEを落としてくる

Modern.IEのページに行き、仮想イメージをダウンロードする。

正直、どれでもいいが、私はIE10 on Win8を選んだ。

もちろん、PlatformはVirtualBoxにする。

以上。あとは、KH coderのページに行き、windowsパッケージをダウンロードし、展開して使うだけ。

仮想マシンのメモリは1G程度を割り当てたが、それでもそれなりに動いてくれた。

MacのネイティブでKH coderを使おうとしたまとめ

一応は試してみた。半日近くを費やして、解決できなかった結果、windowsを使うという判断に至っている。

何かの役に立つかもしれないので、残しておく。

chasenのインストール

./configure --with-libiconv=/usr/local

make

sudo make install

chasenperlバンドルインストール

cd chasen-2.4.5/perl

perl Makefile.PL LIBS="-L/usr/local/lib -lchasen -lstdc++"

make

sudo make install

ここを参考

※実は、KH coderはMecabも呼び出せるので、無理にchasenにする必要は無い。

あと、一般的に、HMMベースのChasenよりもCRFベースのMecabの方が、形態素解析の世界では、良い性能を示すことが報告されている。

libconvのインストール

文字コード変換ライブラリのlibconvをインストールする。

tar xvzf libiconv-1.10.tar.gz
./configure --prefix=/usr/local
make
sudo make install

dartsのインストール

ダブルアレイのライブラリ、dartsをインストールする

tar xvzf darts-0.32.tar.gz

./configure

make

make check

sudo make install

perlモジュールのインストール

KH coderはperlで構築されているので、perlモジュールをひたすらインストールしていく

cpanmを使うと便利。

sudo perl -MCPAN -e shell

install Jcode

Tk.pmのインストールについて

Tk.pmのインストールには問題が起きやすい。

sudo perl -MCPAN -e shell
install Tk

問題が発生

capanmを使ってインストールを試みる

sudo cpanm Tk

→エラーが出る

仕方がないので、ソースからコンパイルする

MAC0019-2150044% sudo perl Makefile.PL XFT=1
perl is installed in /System/Library/Perl/5.18/darwin-thread-multi-2level okay
PPM for perl5.018002
Test Compiling config/signedchar.c
Test Compiling config/Ksprintf.c
Test Compiling config/tod.c
Generic gettimeofday()
Using -L/usr/X11R6/lib to find /usr/X11R6/lib/libX11.6.dylib
Cannot find X include files via /usr/X11R6/include
Cannot find X include files anywhere at ./myConfig line 332.
Compilation failed in require at Makefile.PL line 36.
BEGIN failed--compilation aborted at Makefile.PL line 38.

で、結局はダメだった。

macでインストールするチュートリアルを見つけたので、従ってインストールをしてみるが、失敗する。

具体的には、makeで次のエラーがでる

cd pTk && make DEFINE="" LIBPERL_A="libperl.a" LINKTYPE="dynamic" OPTIMIZE="-Os" PREFIX="/usr/local" PASTHRU_DEFINE="" PASTHRU_INC=""
Unrecognized switch: --center  (-h will show valid options).
make[1]: *** [manifypods] Error 255
make: *** [subdirs] Error 2

解決法

githubからソースもってきて、compileする。

cloneして、perl MakeFile.PL; make; sudo make installでおしまいだった。

どうやら、Yosemite特有のバグだったらしい。ここに報告がされている。

残りのperlモジュールもインストールしていく

sudo cpanm DBD::CSV

Spreadsheet::WriteExcel

sudo cpanm Unicode::String

sudo cpanm DBD::mysql

sudo cpanm Net::Telnet

sudo cpanm YAML

sudo cpanm Spreadsheet::ParseExcel

sudo cpanm Spreadsheet::XLSX

sudo cpanm Clipboard

sudo cpanm Statistics::Lite

sudo cpanm Algorithm::NaiveBayes

が、

sudo cpam Text::Iconv

で、こけた。

libiconvへのパスを求められる。

LIBSとINCをオプションで指定しても、やっぱりパスを求められる。

ソースを読んだが、perlはよく分からない。

結果

やめた。

ggplot2で日本語入りのグラフが入ったhtmlレポートメールをサーバーから送る

やりたいこと

ggplot2で日本語を利用できるようにする

前提

  • サーバーでRを実行している
  • レポートhtmlを作成している
  • レポートのグラフ中に日本語が含まれる

ggplot2ではデフォルトの設定では日本語はサポートされていないので、フォントの指定が必要。

でも、そもそも、サーバーにフォントが入っていないこともあるので、サーバーにフォントのインストールから始める

やったこと

作業の流れ

  1. インストール済みの日本語フォントの確認
  2. 任意の日本語フォントのインストール
  3. ggplot2で設定する

1 日本語フォントの確認

fc-list|less

でインストール済みのフォント一覧が確認可能。

IPA系統がなければ、日本語フォントなしと考えてもよさそう。

2 日本語フォントのインストール

IPAフォントのセットをインストールする。

IPAフォントをダウンロードできるページ

wget ファイルダウンロードのURL

落としてきて、

unzip 落としてきたファイル名

で展開する。

*ttfのファイルをまとめて、/usr/local/share/fonts/に移す。

コマンドは

sudo cp *ttf /usr/local/share/fonts/

当たり前だけど、sudo権限が必要。

コピーしたら、sudo fc-cache -fvを実行

3 ggplot2で設定

ggplotの命令をしている末尾に

+ theme_bw(base_family= "IPAPGothic")

を記述する。

これで日本語でレポートできるようになる。

※ Rstudioで日本語入りのグラフを見るには、Rstudioの再起動が必要

早く、簡単に共起語ペアの頻度を数える

やりたいこと

共起語ペアのカウントを取りたい。

単に基礎集計をやりたいだけなので、matrixを作る必要はない。

解決策

タプルで共起語ペアを作って、カウントする

手順は

  1. 共起語のタプルを作って、リストに放り込んでいく
  2. collection::Counter.most_common()で頻度とる(条件つきで頻度を知りたいときは、NLTK::ConditionalFreqDist)
# 共起語カウントをする方法
test_sent_list = ['I', 'am', 'so', 'happy', 'I', 'am', 'a', 'girl', 'with', 'golden', 'hair', '.']

# 文中の共起語のタプルペアをつくる
def tessa(source):
    result = []
    for p1 in range(len(source)):
        for p2 in range(p1+1,len(source)):
            result.append( (source[p1],source[p2]) )
            
    return result


list_res = tessa(test_sent_list)

#  単純にペアの頻度を知るだけなら、collections::Counter.most_common()を使う
from collections import Counter
counter_res = Counter(list_res)
print counter_res.most_common()

print '-'* 20
# 条件つけて頻度を知りたいときは、NLTK::ConditionalFreqDist.most_common()にする
cfd = nltk.ConditionalFreqDist(list_res)
print cfd['I'].most_common()

結果は

[(('I', 'am'), 3), (('am', '.'), 2), (('am', 'golden'), 2), (('I', 'with'), 2), (('am', 'hair'), 2), (('I', 'girl'), 2), (('I', '.'), 2), (('I', 'a'), 2), (('am', 'a'), 2), (('I', 'hair'), 2), (('I', 'golden'), 2), (('am', 'girl'), 2), (('am', 'with'), 2), (('girl', '.'), 1), (('so', 'girl'), 1), (('am', 'so'), 1), (('with', 'hair'), 1), (('so', 'happy'), 1), (('happy', 'hair'), 1), (('happy', '.'), 1), (('with', '.'), 1), (('so', 'am'), 1), (('hair', '.'), 1), (('happy', 'I'), 1), (('a', '.'), 1), (('golden', 'hair'), 1), (('so', 'golden'), 1), (('happy', 'girl'), 1), (('so', 'a'), 1), (('a', 'golden'), 1), (('am', 'happy'), 1), (('a', 'hair'), 1), (('so', 'I'), 1), (('so', '.'), 1), (('happy', 'a'), 1), (('am', 'I'), 1), (('happy', 'with'), 1), (('am', 'am'), 1), (('a', 'girl'), 1), (('girl', 'with'), 1), (('I', 'happy'), 1), (('I', 'so'), 1), (('happy', 'am'), 1), (('with', 'golden'), 1), (('so', 'with'), 1), (('a', 'with'), 1), (('so', 'hair'), 1), (('girl', 'hair'), 1), (('girl', 'golden'), 1), (('golden', '.'), 1), (('I', 'I'), 1), (('happy', 'golden'), 1)]
--------------------
[('am', 3), ('a', 2), ('golden', 2), ('.', 2), ('hair', 2), ('girl', 2), ('with', 2), ('I', 1), ('so', 1), ('happy', 1)]