2016年5月14日土曜日

共起関係の表示

前回まで、N-gramで隣接する文字の間、あるいは隣接する単語の間の共起関係を求めました。でも、例えば、「風の又三郎」でbi-gramを求めると、その数は「名詞」と「形容詞」だけでも4千組近くあります。これがたとえ100組くらいに減ったとしても、これ全体を確認するのは骨が折れます。で、この共起関係を図にできれば、状況を一望できるでしょう。Rは図の表示に関しても、便利な関数を備えています。
igraphというパッケージを使って、「風の又三郎」のbi-gramを図にしてみましょう。例によって、「風の又三郎」のテキストファイルがフォルダNORUBYの中にあるものとします。ない、という方は、前回までの「Rあれこれ」を参照して下さい。
で、まず、「風の又三郎」を読み込んで、bi-gramを求めます。ただし、今回は形容詞も含めることにします。
> library(RMeCab)
> ngr2 <- NgramDF("NORUBY/kazeno_matasaburo2.txt", type = 1, pos = c("名詞","形容詞") )
file = NORUBY/kazeno_matasaburo2.txt Ngram = 2
> head(ngr2)
  Ngram1     Ngram2 Freq
1   あい     あいだ    1
2   あい       そこ    1
3   あい       づあ    1
4   あい づやっぱり    1
5   あい       一郎    1
6   あい       嘉助    1
>
次に、igraphパッケージを読み込みます。igraphは、インタラクティブにグラフを操作する機能を持つ関数群です。グラフに表示するとき、数が多いとゴチャゴチャするので、まず、bi-gramの頻度が3以上のものを抽出します。で、データフレーム形式をネットワークグラフを扱う形式に変換します。
> library(igraph)
> ngr2limit <- ngr2[ngr2[,3] > 2 , ]
> bigraph<-graph_from_data_frame(ngr2limit)
> tkplot(bigraph, vertex.color = "Yellow", vertex.size = 20)
[1] 4
>
このtkplotというのを実行すると、別画面にグラフが表示されるでしょう。表示が偏っている場合は、ポップアップした別画面のメニューでView > Fit to screenとやると、画面全体に表示されます。このグラフでは、名詞や形容詞の関係を矢印で示しています。

2016年5月1日日曜日

N-gram

前回まで、tf-idfを求めて特徴ベクトルとし、文書の比較を行いました。文書を特徴づける指標は他にもあります。少し前に共起性というのがありました。隣接する単語の共起性を指標にするものとして、N-gramがあります。N-gramは、文書の中でN個の文字あるいは単語の組合せが、どの程度出現するかを調べます。これは、その文字あるいは単語の発生確率が直前の文字や単語に依存すると考えているからです。
例えば、「私はRを勉強しています」という文章があったとして、N=1(uni-gram)ならば、各文字が一つずつ出現することが得られます。N=2(bi-gram)ならば、「私は」「はR」「Rを」というように、2文字の組みで出現することを得ます。この文字の組は、共起関係と言います。この共起関係がどの程度の頻度で出現するかを調べたのが、共起頻度です。で、共起頻度がわかると、何が嬉しいかが問題ですよね。例えば、共起頻度を調べて文書の性質を見つけたり、ある文字列の直後に来やすい文字列を求めたり、音声認識なんかで訂正するときの情報として利用したりします。
では、RでN-gramを実行してみましょう。例文として、前回読み込んだ「風の又三郎」「セロ弾きのゴーシュ」「注文の多い料理店」を使います。フォルダ「NORUBY」の中に「kazeno_matasaburo2.txt」などのファイルが置いてあるものとします。このテキストファイルがない、という方は、前回までの「Rあれこれ」を見てご用意下さい。
> library(RMeCab)
> ngr1 <- Ngram("NORUBY/kazeno_matasaburo2.txt", type = 1)
file = NORUBY/kazeno_matasaburo2.txt Ngram = 2
length = 3967
> head(ngr1)
              Ngram Freq
1     [あい-あいだ]    1
2       [あい-そこ]    1
3       [あい-づあ]    1
4 [あい-づやっぱり]    1
5       [あい-一郎]    1
6       [あい-嘉助]    1
>

Ngramという関数が、N-gramを求めるものです。第1引数はファイル名で、第2引数が形態素のN-gramを求めることを指定しています。もし、第2引数を省略すると、文字の間のNgramを求めることになります。Ngram = 2 と表示されていますように、bi-gramを求めています。
関数Ngramでは[あい-一郎]というように、形態素の組で表示されました。形態素ごとに分けて表示したい場合、関数NgramDFを使います。
> ngr2 <- NgramDF("NORUBY/kazeno_matasaburo2.txt", type = 1, pos = "名詞")
file = NORUBY/kazeno_matasaburo2.txt Ngram = 2 
> head(ngr2)
  Ngram1     Ngram2 Freq
1   あい     あいだ    1
2   あい       そこ    1
3   あい       づあ    1
4   あい づやっぱり    1
5   あい       一郎    1
6   あい       嘉助    1
>
pos = "名詞"というのは、「名詞」だけ抽出しているということです。これを指定しないと、名詞と形容詞の形態素が抽出されます。
関数NgramDF2を使えば、第1引数にフォルダを指定してその中に含まれるファイルをすべて対象にできます。引数minFreqは、頻度の最低値を指定します。
> ngr3 <- NgramDF2("NORUBY", type = 1, pos = "名詞", minFreq=2)
file_name =  NORUBY/chumonno_oi_ryoriten2.txt opened
file_name =  NORUBY/kazeno_matasaburo2.txt opened
file_name =  NORUBY/serohikino_goshu2.txt opened
number of extracted terms = 727
> head(ngr3)
  Ngram1 Ngram2 chumonno_oi_ryoriten2.txt kazeno_matasaburo2.txt serohikino_goshu2.txt
1 あいつ     風                         0                      2                     0
2 あっち こっち                         0                      3                     0
3   あと   あと                         0                      2                     0
4   あと   だい                         0                      3                     0
5   あと   よう                         0                      0                     2
6   あと     一                         0                      2                     0
>

結果を見ると、「風の又三郎」「セロ弾きのゴーシュ」「注文の多い料理店」では隣接する単語の組がまったく違っています。まあ、当然と言えば当然ですが、この違いは作品の特徴の一つの指標と考えることができます。つまり、その文書の特徴を表すキーワードというわけです。逆に、3つの作品に共通する単語の組が抽出できれば、その作者特有のキーワードが抽出できるかも知れません。注意しなければいけないのは、文書に含まれる文字数が文書によって違っているという点です。比較するなら、頻度を正規化する操作が必要でしょうね。

2016年4月20日水曜日

文書の類似度

前回、tf-idfを使って、文書に含まれる語句の出現頻度から重み付けを行いました。これは、文書の特徴を抽出するためということでした。「風の又三郎」と「セロ弾きのゴーシュ」で名詞を抜き出し、tf-idfの値を導出しましたが、まあ、両者で違いがあることがわかったという程度で、両者が明示的に比較されたわけではありませんでした。両者の違いというのは、両者がどれだけ似ていないかということにもなります。そこで、両者の類似度を求めれば、明示的に比較したことになります。
類似度を計算するときによく用いられる指標は相関です。でも、テキスト処理の分野だと、コサイン類似度という指標の方がよく用いられます。で、コサイン類似度というのは、文書をベクトルで表しておいて、そのベクトルどうしの関係を表現します。以下の式で表されます。
cos(x, y) = x・y / |x||y| = {x / |x|}・{y / |y|}
x, yはそれぞれ、文書ベクトルx = (x_1, x_2, ..., x_n), y = (y_1, y_2, ..., y_n)を表します。ベクトルの要素は共にn個あります。で、前回まで求めてきたtf-idfの結果を、上式に代入します。文書ベクトルの要素は、各文書の単語に対するtf-idfの値です。
文書の類似度を、Rを使って実際に求めてみましょう。前回、「セロ弾きのゴーシュ」を読み込みました。そこまではできているとします。で、新たに「注文の多い料理店」を読み込みます。
> menu <- Aozora(url = "https://www.aozora.gr.jp/cards/000081/files/
43754_ruby_17594.zip")
> library(RMeCab)
> listTFIDF <- docMatrix("NORUBY", pos=c("名詞"), weight = "tf*idf*norm" )
> head(listTFIDF, 20)
              docs
terms          chumonno_oi_ryoriten2.txt kazeno_matasaburo2.txt serohikino_goshu2.txt
  HOUSE                      0.023302018            0.000000000           0.000000000
  RESTAURANT                 0.023302018            0.000000000           0.000000000
  WILDCAT                    0.023302018            0.000000000           0.000000000
  あいつ                     0.014287567            0.004440664           0.000000000
  あすこ                     0.023302018            0.000000000           0.000000000
  あたりまえ                 0.014287567            0.002220332           0.000000000
  あっち                     0.014287567            0.006660996           0.000000000
  あと                       0.009014451            0.023814849           0.021455069
  あなた                     0.018028902            0.001400873           0.006130020
  イギリス                   0.023302018            0.000000000           0.000000000
  いっしょ                   0.009014451            0.014008735           0.009195030
  いも                       0.023302018            0.000000000           0.000000000
  いらっしゃい               0.139812109            0.000000000           0.000000000
  うし                       0.027043354            0.030819216           0.003065010
  うち                       0.009014451            0.015409608           0.024520079
  オーバー                   0.023302018            0.000000000           0.000000000
  おなか                     0.023302018            0.000000000           0.000000000
  おまけ                     0.014287567            0.002220332           0.000000000
  お客                       0.069906055            0.000000000           0.000000000
  お見舞                     0.023302018            0.000000000           0.000000000
>
今回、docMatrixの引数weightをtf*idf*normとしています。normというのは正規化を意味していまして、各文書(列)の要素を2乗して合計すると1になります。これは、類似度を計算するとき、都合がよいです。先に示した類似度の式では|x|および|y|が1になるということですから、文書ベクトルの内積を求めれば済むことになります。
> v1 <- as.vector(listTFIDF[,1])
> v2 <- as.vector(listTFIDF[,2])
> v3 <- as.vector(listTFIDF[,3])
>
一列目を取り出してベクトルv1、二列目をv2、三列目をv3とします。そして、それぞれのベクトルの内積を取ります。Rでは、ベクトルの内積は %*% を使います。単なる * だけだと、要素毎のかけ算になることに注意します。
> s12 <- v1 %*% v2
> s12
          [,1]
[1,] 0.1672723
> s23 <- v2 %*% v3
> s23
          [,1]
[1,] 0.1438562
> s31 <- v3 %*% v1
> s31
          [,1]
[1,] 0.1510847
>
この結果からは、どの文書も同等程度に似ていないということのようです。

2016年4月9日土曜日

tf-idf

前回は、文書を分かち書きして形容詞を取り出し、その出現頻度を調べました。結果を見てわかると思いますが、案外、形容詞ってその文書の特徴を捉えているんですね。ということは、文書に出現する語句を調べると、その文書の特徴がわかるのではないか、という推測が成り立つわけです。これは直感的にも納得できます。例えば、あるの文書があったとして、その中に含まれる単語として「企業」とか「株価」とか「雇用」とかが含まれれば、その話題は経済かな、と推定されます。でも、単語の出現回数を数えただけだと、都合の悪いことがあります。どの文書にも出てくる単語があった場合、それがその文書を特徴付けるとは思われません。例えば、「彼」とか「それ」とかの語句は、文章を構成するとき頻出します。どの文書にも出てくるので、その文書を特徴付けるものにはなりません。
したがって、文書を特徴付けるのは、他の文書にあまり出てこない単語が何回も出てくる場合ということになります。そこで、そうした語句に重みを付けるようにします。このような手法の一つにtf-idfというのがあります。文書中の単語への重みづけを行い、文書の特徴を抽出するのに使われます。
tfはterm frequencyの頭文字をとったもので、単語の出現頻度を表します。定義は、tf =(文書dに含まれる単語tの出現頻度)/(文書dに含まれる全単語の出現頻度の和)です。idfはinverse document frequencyの頭文字をとったもので、多くの文書に出現する単語の重みを下げます。定義は、idf = log{(全文書数)/(単語tが出現する文書の数)}です。logを使っているのは、文書数に対する影響を少なくするためです。あと、log 0を避けるため、1を加える措置を施すことがあります。で、両者をかけ合わせたものが、tf-idfになります。
では、Rで試してみましょう。まず、以下のコマンドを打ち込んでみて下さい。ただし、前回やった青空文庫の「風の又三郎」が、ディレクトリ名NORUBYの中に「ルビなしファイル」として置いてあるものとします(前回のkazeまでやってある状態)。で、新たに「セロ弾きのゴーシュ」を読み込んで、両者を比較してみます。
> celo <- Aozora(url = "https://www.aozora.gr.jp/cards/000081/files/470_ruby_3987.zip")
> library(RMeCab)
> listTFIDF <- docMatrix("NORUBY", pos=c("名詞"), weight = "tf*idf" )
> head(listTFIDF, 20)
              docs
terms          kazeno_matasaburo2.txt serohikino_goshu2.txt
  アアハハハ                        2                     0
  アアハハハハ                      2                     0
  あい                             16                     0
  あいだ                            2                     0
  あいつ                            4                     0
  あかし                            2                     1
  あぐら                            2                     0
  あざみ                            4                     0
  あざらし                          2                     0
  あし                              2                     0
  あした                            4                     0
  あたり                            7                     2
  あたりまえ                        2                     0
  あちこち                          8                     0
  あっち                            6                     0
  あと                             17                     7
  あなた                            1                     2
  アルプス                          2                     0
  あん                              2                     0
  い                               12                     0
>

名詞だけを抽出して、各単語の重みを求めました。それぞれの作品では、どんな単語が重みづけられているでしょうか。注意点は、docMatrixはリスト形式で返されるということです。

2016年3月30日水曜日

語句の出現頻度

前回、文章を形態素に分割(分かち書き)しました。でも、「文章をいちいち入力するのー?」と思われた方もおられるでしょう。便利なことに、テキストファイルを読み込むコマンドが用意されています。で、文章として著作権がフリーの青空文庫(https://www.aozora.gr.jp/)の作品を読み込んでみましょう。ここでは、宮沢賢治の「風の又三郎」を読み込みます。
青空文庫のホームページにアクセスして、作品をダウンロードしようとすると、「テキストファイル(ルビあり)」とか書いてあります。ルビ付きなんですね。ということは、テキスト処理するときは、それを取り除かないといけないですね。で、RMeCabにはまたまた便利な機能があるんです。青空文庫の作品を読み込んでくれて、しかもルビを削除してくれる関数が。以下のようにコマンドを打ちこんで下さい。
> source("http://rmecab.jp/R/Aozora.R")
> kaze <- Aozora(url = "https://www.aozora.gr.jp/cards/000081/files/462_ruby_716.zip")
> kaze
[1] "./NORUBY/kazeno_matasaburo2.txt"
>

ルビのないテキストファイルが、NORUBYというディレクトリに作られました。このkazeno_matasaburo2.txtというファイルをテキストエディタで開いて、確認してみて下さい。ここで形態素解析をして、各単語の出現頻度を求めてみましょう。
> library(RMeCab)
> freqapp <- RMeCabFreq(kaze)
file = ./NORUBY/kazeno_matasaburo2.txt 
length = 2025
> head(freqapp)
    Term    Info1 Info2 Freq
1     あ フィラー     *   28
2   あの フィラー     *    3
3 うんと フィラー     *    1
4     え フィラー     *    4
5 なんか フィラー     *    1
6     ま フィラー     *    4

Termというのが形態素で、Info1が品詞(大分類)、Info2が品詞細分類、Freqが出現頻度を表しています。フィラーというのは、デジタル大辞泉によれば、「埋めるもの」「詰め物」の意です。こういう語句は必要なかったりしますので、subsetという関数を使って、抽出したい品詞や除外したい品詞を指定します。で、大分類から「形容詞」を残して、細分類から数、非自立、接尾にあたる用語を除外します。
> freqapp1 <- subset(freqapp, Info1 %in% c("形容詞"))
> freqapp2 <- subset(freqapp1, !Info2 %in% c("数", "非自立", "接尾"))
> freqapp3 <- freqapp2[order(freqapp2$Freq, decreasing = T),]
(上のコマンドは、単語を出現頻度順に並べ直しているだけです。)
> head(freqapp3)
    Term  Info1 Info2 Freq
65  ない 形容詞  自立   43
114 白い 形容詞  自立   19
101 青い 形容詞  自立   15
38  いい 形容詞  自立   14
79  悪い 形容詞  自立   13
104 赤い 形容詞  自立   13

で、1列目(Term)と4列目(Freq)を抜き出してデータフレームを作った上で、上位20個に絞り込みます。
> freqapp1.df <- data.frame(word=as.character(freqapp3[,1]), freq=freqapp3[,4])
> freqapp2.df <- subset(freqapp1.df, rank(-freq)<20)

barplotを使って、ヒストグラムを表示してみましょう。「風の又三郎」は、不思議な物語です。それが、文章表現に表れているでしょうか。
> x <- freqapp2.df$freq
> names(x) <- freqapp2.df$word
> barplot(x, ylab = "Freq", las = 2)

2016年3月22日火曜日

RMeCabのインストール

RにはRMeCab(石田基広氏による)というテキスト処理を行うためのパッケージがあり、日本語文章の解析ができるようになります。RMeCabは、MeCab(工藤拓氏による)という形態素解析ソフトと連携して動作しています。形態素解析は文章を形態素に分解し、各形態素の品詞を特定します。形態素は「意味を持つ語の最小単位」です。
で、RMeCabをインストールします。まず、準備としてMeCabをダウンロードし、インストールします。OSとしてWindowsを想定しています。MeCabは、http://taku910.github.io/mecab/ からダウンロードできます。

「ダウンロード」にある「Binary package for MS-Windows」の下、「mecab-0.996.exe」横のダウンロードをクリックします。ファイルがダウンロードできたら、この実行ファイルをダブルクリックします。そうすると、インストールが始まります。幾つかポップアップ画面が出て来ますが、defaultのままOKでよいです。

MeCabは、CドライブのProgram Files (x86)の中に入ります。Windowsではこれで辞書もインストールされますので、すぐRMeCabを使えます。Windowsならば、desktopに「MeCab」アイコンができているはずですから、これをダブルクリックします。もし見当たらなければ、menuから「MeCab」を選択して起動します。ウィンドウ画面が出てきますので、何か文章を入力します。で、形態素解析の結果が表示されれば、MeCabが正常にインストールされたことがわかります。

次に、RMeCabをインストールします。RMeCabは石田基広氏によって開発され、Rのinstall.packagesでインストールできます。RStudioを起動し、以下のコマンドを実行してインストールします。
install.packages("RMeCab", repos = "http://rmecab.jp/R")

インストールに成功したら、以下のコマンドを入力して、正常にインストールされたことを確認します。
> library(RMeCab)
> rmec <- RMeCabC("私は誰だ。")
> unlist(rmec)
  名詞   助詞   名詞 助動詞   記号
   "私"   "は"   "誰"   "だ"   "。"
>

2016年3月12日土曜日

Rのインストール

 統計解析ツールRのインストールの仕方をやっていませんでした。Rをインストールする機会がありましたので、ここに記録しておきます。Rのインストールの仕方については、書籍やネット上に情報がありますから、それも参考にして下さい。
 表計算ならExcelでもできますし、コマンドを打たなければいけないという面倒さはありますが、ちょっとした統計解析を行うなら、便利な関数が色々用意してあるRが良いようです。
  Rは、Rプロジェクトのホームページ(https://www.r-project.org/)からダウンロードします。このURLに行くと、以下のようなページが出てきます。
左側のメニューで、Downloadの下にある「CRAN」をクリックします。
と、このようなページが現れます。これはダウンロードサイトのリストで、日本のサイトはページの中程にあります。
どれかを選択してクリックしますと、このようなページが出現します。ここではOSとしてWindowsを使っていることを仮定して、「Download R for Windows」をクリックします。
そうすると、このようなページが表示されます。baseをクリックします。
2016年3月時点ではR-3.2.4が最新です。「Download R-3.2.4 for Windows」をクリックしますと、ダウンロードを開始します。 で、ダウンロードが完了したとします。ダウンロードされたファイルをダブルクリックします。
インストールプログラムが起動します。これは使用言語の選択で、自動的に「日本語」が選択されています。「OK」をクリックします。
セットアップウィザードが立ち上がりますので、そのポップアップ画面の下辺りにある「次へ」ボタンをクリックしていきます。ライセンスや設定について確認してきますが、取りあえず「次へ」ボタンでも大丈夫です。
このようにインストールが始まります。
インストールが終了すると、このような画面が出てきます。「完了」ボタンをクリックします。
インストールのセットアップ時に何も変更を加えなければ、このようなアイコンがデスクトップに出現します。64ビット機PCなら「R x64 3.2.4」と「R i386 3.2.4」とありますが、「R x64 3.2.4」を使います。これをダブルクリックします。
このような画面が表示されていれば、インストール成功です。「R Console」に右矢印「>」が、表示されています。これはプロンプトと呼ばれ、コマンドを入力できる状態であることを表します。Rを終了するコマンド「q()」を入力すると、Rが終了します。
このとき、このようなポップアップ画面が現れ、データを保存するかどうかを訊いてきます。データを保存するなら、必ず「はい」ボタンをクリックします。

2016年1月11日月曜日

数値の分類

 「1月の最低気温1度の日に、10km走に出場し、45分40秒で完走でき、880番だった。」
 この一文は日常よく耳にするものであり、取り立てて専門的な知識が無くても理解できます。一般的な情報であり、年明けの寒い日に、マラソン大会か何かに出場して、45分40秒で走った、、、もの凄く速いというわけでもないですが、そんなに遅いわけでもないです。これで880番ということは、この大会の出場者は割合多いのではないか、くらいの想像はつくでしょう。ところが、これらの数値は、厳密に言うと別々の尺度となります。
 心理学者Dr. Stanly Smith Stevensは「On the theory of scales of measurement」の中で、数値を「名義尺度」「順序尺度」「間隔尺度」「比例尺度」に分類しています。名義尺度は何かを分類するための便宜的な名前であり、ラベルのようなものです。例えば、性別や職業、話題などを区別する場合です。性別であれば、男を1、女を2にするし、職業なら、スポーツ選手を1、デザイナーを2、編集者を3、歌手を4、小説家を5、学芸員を6といった具合です。数値を入れ換えても本質的に影響ないし、区別するための数値なので、その大きさにも意味がありません。順序尺度は順序関係を表し、順序に意味があります。例えば、競技結果の順序やサービス満足度などです。前者は1番、2番といったものであり、後者は1:とても満足、2:やや満足、3:やや不満、4とても不満といった数値です。値が等しいのか、大きいのか、小さいのかが比較できるが、加減算はできません。間隔尺度は等間隔の目盛り上の数値を表し、一定の単位で測られた量を意味します。例えば、気温や年月、試験の成績などです。数値が等しいか、大きいか、小さいかの比較ができるし、その差にも意味がああります。加減算は可能だが、ゼロ(原点)でも「無」というわけではない点に注意を要します。比例尺度は原点が定義されていて、目盛りは等間隔です。例えば、身長や体重、質量や長さ、金額などです。数値の比較、数値の差に意味があり、加減乗除ができます。
 このようにして考えると、「1月の最低気温1度の日に、10km走に出場し、45分40秒で完走でき、880番だった。」という文は、少し違った見方ができます。1月、1度は間隔尺度、10km、45分40秒は比例尺度、880番は順序尺度です。データ分析を行うときは、数値の分類を考えておく方が間違いが少ないです。