プリキュアとセーラームーンはどちらの方がサザエさんに近いのか?
この記事ではこんなことを書くよ
はじめに
計算機分野に所属する人たちは時々、本当に間抜けなことを真面目に取り組もうとします。
例えば、自然言語処理の最新手法"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_array
はnumpy.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)
本題 プリキュアとセーラームーンはどっちの方がサザエさんに近いのか?
さて、こんな図がプロットされます。
おやおや、セーラームーンの方がいくぶんか、サザエさんに近いようですね・・。
言い忘れてましたが、関係のないデータも入れておきました。どれくらい離れるか見たかったからです。rider
とgolgo_titles
とultra
が関係ないやつですね。仮面ライダーとゴルゴ13とウルトラマンですが。
念のため、SVDの結果も見てみましょう。(SVDだけで2次元まで削減した。という意味です)
おおっ・・・これは・・・全然違う。
プリキュアとセーラームーンが似たところにプロットされてたり、ゴルゴ13と仮面ライダーが遠くに行ってたり、SVDの結果の方が直感によく合いますね・・・
こっちを採用しましょう。
ユークリッド距離で計算すると、プリキュアの方がわずかに0.12くらいサザエさんに近いです。
というわけで、プリキュアの方がセーラームーンより、わずかにサザエさんに似ているという結論が出ました。
うーん。。。サザエさんもプリキュアも日曜に放送してるから。。かな?
まぁ、発火した素性がたまたまあったから、と言われるとそれまでなんだけど・・・
元の空間でcos類似度を計算した方がいいかもしれませんね。
ところで、何か忘れてないでしょうか。
そう、どうしてt-SNEはうまくプロットされなかったのか。
ちょっと試してみました。
高次元でなかったからうまくいかなかった?
実は元の空間は3,000次元ちょっとにすぎません。
これじゃ、高次元空間とは言えないだろ〜ということで、wikipediaと青空文庫から文長が長そうな記事をコピペしまくります。
まずはt-SNE
形は綺麗そうなんだけど・・・・
chrchillの記事がはじっこなのはいいとしてmarxとgermanとbismarkが離れているのは気になります。
また、iran_rev2(イラン革命)とkhomeini(ホメイニ)の距離も違和感があります。
あ、そういえば、核問題が進展してよかったですね。
!اَلْحَمْدُ لِلَّهِ
さて、SVDの方をみてましょう。
t-SNEと違って、ホメイニとイラン革命がほぼ同じところに位置したり、マルクスとドイツとビスマルクが同じところに位置するのは直感的に正しそうといえます。
anpan_characters(アンパンマンの登場人物)とkokoro(夏目漱石のこころ)がどっか行っているのは仕方ないですね。内容的も外れ値とみなしてよさそうです。
そういえば、アンパンマンの登場人物という記事はこまーめに整備されているようで感心するばかりです。
毎週、新しいキャラが出ると更新しているのでしょうか・・・・・
さて、この時の次元数は13,000次元でした。ちょい高次元と言ってもいいかな〜と思います。
じゃあ、どーしてt-SNEはビミョーな結果になったのでしょうか?
推測ですが、元の空間で記事に「非線形な塊」が存在してなかったんじゃないかと思います。
t-SNEがプロットした結果が、元の空間での距離を忠実に表現しているのかもしれません。
また、元の空間でノイズが多すぎたのが原因かもしれません。SVDで綺麗にノイズ除去できて、初めて、類似することにプロットできたとか・・・
でもどうやってそれを調べたらいいんだろう。元の空間での分散値でも調べましょうかね・・・。
まとめ
[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
こんな結果が返ってくる
いろんなサイトを見た補足(私的な)など
- 主語は
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に記述
TermExtractをgit clone
してくる。
すでに、Mecabのインストール環境は整っているので、特に設定は不要。
Pythonスクリプトで、TermExtractorのラッパー的なものを書く。
処理の流れはこんな感じ
システム作ったら、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.py
がJsonを標準入力でうけとって、いろいろやってから、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は要は、「クラスとの関連性がでかい単語ほど大きい値になるよ」というやり方。
簡潔にまとめると、
- 単語数×クラス数のクロス集計表をつくる。クロス表は(termが出現 or Not)×(クラス=c or Not)の4要素
- クロス表で同時確率と周辺確率を求めて、IGの式に代入。値を求める。
Chi-squared test
日本ではみんなカイ二乗検定とよく言う(と思うたぶん)。英語ではChiと省略すると思う(たぶん)
クロス集計表を作りまくって、データ中でよく特徴を示している要因を特定するときに使ったりしていた。
feature selectionも同じ発想で行う。
クロス表をつくる点では、IGと似ている。
が、Chiは「featureとインスタンス(文書)が独立だった場合を仮定して、実際の出現数と差を取る。」という点で異なる。
ちなみに、独立仮定時と実際の差が大きいほど、「クラスとの関係性が大きい単語」とみなされる。
Bi-Normal Separation
よく頭文字をとってBNSと表現される
これだけは日本語で上手く説明されたところが見つからなかったので、自分で色々と試してみた。
BNSは直感的に説明すると、「正クラスと負クラスでfeatureが出現している量を比較して、その差を値に示す」というもの。
こう書くと、IGとChiと何ら変わらないように聞こえてしまうが、BNSは2クラスでの出現割合を考慮しているところがミソになる(後述)
2値の文書分類タスクを例に考えてみる。
いま、"iphone"というtermが図の回数で文書に登場しているとする。
まずはこの回数から、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の例で一連の流れをしめすと、下図のような感じ
さっきの図でのデータセット中での"iphone"は1.624435603のBNS値を持つことになる。
ちなみに、tprとnprの値を変化させてBNSを求めると、下図のようになった
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.9から0.1まで変化させると、左下がりの形になった
MacでKH coderを動かす
やりたいこと
MacでKH coderを利用可能な状態にしたい
解決法
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
chasenのperlバンドルインストール
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ではデフォルトの設定では日本語はサポートされていないので、フォントの指定が必要。
でも、そもそも、サーバーにフォントが入っていないこともあるので、サーバーにフォントのインストールから始める
やったこと
作業の流れ
- インストール済みの日本語フォントの確認
- 任意の日本語フォントのインストール
- ggplot2で設定する
1 日本語フォントの確認
fc-list|less
でインストール済みのフォント一覧が確認可能。
IPA系統がなければ、日本語フォントなしと考えてもよさそう。
2 日本語フォントのインストール
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を作る必要はない。
解決策
タプルで共起語ペアを作って、カウントする
手順は
- 共起語のタプルを作って、リストに放り込んでいく
- 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)]