Golangで言語処理100本ノック2015 第8章: 機械学習

言語処理100本ノック 2015の第8章: 機械学習の10問です。

本章では,Bo Pang氏とLillian Lee氏が公開しているMovie Review Dataのsentence polarity dataset v1.0を用い,文を肯定的(ポジティブ)もしくは否定的(ネガティブ)に分類するタスク(極性分析)に取り組む.

70. データの入手・整形

文に関する極性分析の正解データを用い,以下の要領で正解データ(sentiment.txt)を作成せよ.

  1. rt-polarity.posの各行の先頭に"+1 "という文字列を追加する(極性ラベル"+1"とスペースに続けて肯定的な文の内容が続く)
  2. rt-polarity.negの各行の先頭に"-1 "という文字列を追加する(極性ラベル"-1"とスペースに続けて否定的な文の内容が続く)
  3. 上述1と2の内容を結合(concatenate)し,行をランダムに並び替える sentiment.txtを作成したら,正例(肯定的な文)の数と負例(否定的な文)の数を確認せよ.

gist7abcc67e5e41ca5b7de31020c28aac7a

# go run q70.go
positive:  5331
negative:  5331

// 最初の5文のみ抜粋
# head -n 5 ../data/sentiment.txt
+1 you might want to take a reality check before you pay the full ticket price to see " simone , " and consider a dvd rental instead .
+1 birthday girl doesn't try to surprise us with plot twists , but rather seems to enjoy its own transparency .
+1 efteriades gives the neighborhood -- scenery , vibe and all -- the cinematic equivalent of a big , tender hug .
-1 the unceasing sadism is so graphically excessive , the director just ends up exposing his own obsession .
+1 works as pretty contagious fun .

教師データの作成ですが、実装内容自体は、今までやってきた内容で十分対応できます。

71. ストップワード

英語のストップワードのリスト(ストップリスト)を適当に作成せよ.さらに,引数に与えられた単語(文字列)がストップリストに含まれている場合は真,それ以外は偽を返す関数を実装せよ.さらに,その関数に対するテストを記述せよ.

giste459315cbddf0b696e9ec4241b349ac1

gist035fa3046d847cc7f82c2123e8282792

// PATHだけ書き換えています
# go test .
ok      _<PATH>/goNLP100knock2015/src/q71 0.007s

E Oracle Textのストップリストpythonのライブラリを参考にしました。

72-77は同じ問題として扱ったほうが見通しがいいのでまとめます。

72. 素性抽出

極性分析に有用そうな素性を各自で設計し,学習データから素性を抽出せよ.素性としては,レビューからストップワードを除去し,各単語をステミング処理したものが最低限のベースラインとなるであろう.

73. 学習

72で抽出した素性を用いて,ロジスティック回帰モデルを学習せよ.

74. 予測

73で学習したロジスティック回帰モデルを用い,与えられた文の極性ラベル(正例なら"+1",負例なら"-1")と,その予測確率を計算するプログラムを実装せよ.

75. 素性の重み

73で学習したロジスティック回帰モデルの中で,重みの高い素性トップ10と,重みの低い素性トップ10を確認せよ

76. ラベル付け

学習データに対してロジスティック回帰モデルを適用し,正解のラベル,予測されたラベル,予測確率をタブ区切り形式で出力せよ.

77. 正解率の計測

76の出力を受け取り,予測の正解率,正例に関する適合率,再現率,F1スコアを求めるプログラムを作成せよ.

gist3159bfb9a6735815106e74f20eba411d

# go run q72to77.go
**** labeling and the probablity ****
No. correct predicted   probability
--------------------------------------------
[ 0 ]    -1      -1      0.00022938614422040216
[ 1 ]    +1      +1      0.980844143721765
[ 2 ]    -1      -1      0.00708968717145575
[ 3 ]    +1      +1      0.6373159883859113
[ 4 ]    +1      +1      0.9916602446447373
[ 5 ]    +1      -1      0.03358930745405741
[ 6 ]    +1      +1      0.9719198377002579
[ 7 ]    -1      -1      0.01690622239135617
[ 8 ]    -1      -1      0.18087393421803644
[ 9 ]    +1      +1      0.9819855696689674

**** 10 highest weighted words ****
rank    word    weight
--------------------------------------------
[ 0 ]    engross     4.153318843524091
[ 1 ]    rare    3.9660695001044313
[ 2 ]    enjoy   3.646668750763667
[ 3 ]    beauti      3.5124131099641485
[ 4 ]    refreshingli    3.4833226288262464
[ 5 ]    memori      3.2698092911328422
[ 6 ]    move    3.181494225222411
[ 7 ]    consider    3.171432544641585
[ 8 ]    smart   3.1655141347852407
[ 9 ]    refresh     3.1581078779050067

**** 10 lowest weighted words ****
rank    word    weight
--------------------------------------------
[ 0 ]    dull    -4.366239700419224
[ 1 ]    neither     -4.070251251158453
[ 2 ]    name    -4.016387870547353
[ 3 ]    littl   -3.534095627137484
[ 4 ]    bore    -3.4944640249118266
[ 5 ]    badli   -3.397328927368818
[ 6 ]    worst   -3.3778081685478982
[ 7 ]    sort    -3.3675428257686875
[ 8 ]    bare    -3.3492559829926902
[ 9 ]    colleg      -3.3407574407648783

**** rates ****
accuracy rate:   0.812886888013506
precision rate:  0.8719892952720785
recall rate:     0.733445882573626
F1 score:    0.7967396841569028

予測率が上がらないと思ったら学習フェーズでデータXが参照渡しになっていて、ScaleVecによって更新されてしまっていました。値渡しかどうかは気をつけないとダメですね。

78. 5分割交差検定

76-77の実験では,学習に用いた事例を評価にも用いたため,正当な評価とは言えない.すなわち,分類器が訓練事例を丸暗記する際の性能を評価しており,モデルの汎化性能を測定していない.そこで,5分割交差検定により,極性分類の正解率,適合率,再現率,F1スコアを求めよ.

gist44a00f5d2f3cfeaf00c39b54c41e5d80

# go run q78.go
**** rates ( 0 / 5 ) ****
accuracy rate:   0.70042194092827
precision rate:  0.7175974710221286
recall rate:     0.6473384030418251
F1 score:    0.6806596701649176

**** rates ( 1 / 5 ) ****
accuracy rate:   0.6980778246601032
precision rate:  0.7402597402597403
recall rate:     0.6286764705882353
F1 score:    0.679920477137177

**** rates ( 2 / 5 ) ****
accuracy rate:   0.7018284106891702
precision rate:  0.7192982456140351
recall rate:     0.6569274269557022
F1 score:    0.6866995073891625

**** rates ( 3 / 5 ) ****
accuracy rate:   0.6957337083919363
precision rate:  0.7040816326530612
recall rate:     0.657769304099142
F1 score:    0.6801379990142927

**** rates ( 4 / 5 ) ****
accuracy rate:   0.6873239436619718
precision rate:  0.6619828259172521
recall rate:     0.7844588344125809
F1 score:    0.7180355630821337

学習データをそのまま判別データとすると8割だったので、もっと落ちるかと思いましたが、7割程度の判別率が出てますね。

79. 適合率-再現率グラフの描画

ロジスティック回帰モデルの分類の閾値を変化させることで,適合率-再現率グラフを描画せよ.

gistdc829ce8a45d892126337e30c6bdf184

f:id:cipepser:20171015142932p:plain

f:id:cipepser:20171015142939p:plain

感想

機械学習の流れ自体は、学生時代に触っていたので頭に入っているものの素性など、NLP特有の用語で少し戸惑いました。あと2値分類といえば、SVMばかりだったのでロジスティック回帰も改めて勉強して整理できたのでよかったです。

いつも通りコードはGithubにも置いてあります。

Reference

はてなブログでベクトルをbold表記したい[markdown]

TeXでいうところの\boldmath{x}をやりたいもののはてなでは表示されないので、以下の書式をメモ代わりに残しておきます。 はてなでベクトルのbold表記は以下でできます。


 \boldsymbol{x}

\boldsymbol{x} 

ちなみに検索すると以下がよく見つかるのですが、斜体でないのでやりたいこととは違いました。

 \textbf{x}

\textbf{x}

Reference

zplugのautosuggestionsのカラー設定方法

fishコマンドとbash/zshコマンドの微妙な差異で時間を浪費するのをやめるべく、zshに戻る決心をしました。 一方でzshでも、AutoSuggestionを使いたく、 zsh-autosuggestions を導入したものの、デフォルトの色が見えないほど薄かったので変える方法をまとめます。

変え方

READMEZSH_AUTOSUGGEST_HIGHLIGHT_STYLEを設定すればよいとあります。

今回はzplugzplug "zsh-users/zsh-autosuggestions"と設定したため、 設定ファイルは、~/.zplug/repos/zsh-users/zsh-autosuggestions/zsh-autosuggestions.zshにあると思います。

READMEを見てもfg=8がデフォルトだという情報しか載っておらず、 好みの色にするためにはどうすればいいのか一見わかりませんでしたが、 色指定は、oh-my-zshなどで使われているcolor code tableと同じようです。 こちらの下部にテーブルがあります。

自分は、背景がダークカラーのため、以下のように設定しています。

ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=242'

References

Golangで言語処理100本ノック2015 第7章: データベース

言語処理100本ノック 2015の第7章: データベースの10問です。

redisとMongoDBを使うことにします。

redis

// 起動
# redis-server /usr/local/etc/redis.conf

// cli
# redis-cli

MongoDB

// 起動
# sudo mongod --dbpath /var/lib/mongodb --logpath /var/log/mongodb.log

// cli
# mongo

60. KVSの構築

Key-Value-Store (KVS) を用い,アーティスト名(name)から活動場所(area)を検索するためのデータベースを構築せよ.

gist103c8ead51aad42cfc5b6686caa2039a

bufioのdefault sizeである4096だとReadLine()しきれないところがあるのでNewReaderSize()を使っています。 Goでredisを扱うためには、redigoを使っています。
また、setを使ってKVSを構築すると同じアーティスト名が存在した場合に、上書きされてしまうのでのちのQ62,66で結果に不整合が生じます。

61. KVSの検索

60で構築したデータベースを用い,特定の(指定された)アーティストの活動場所を取得せよ.

giste6d4ca51b7b23914fadd5bdc0ec93c75

// 存在するアーティスト
# go run q61.go supercell
Japan

// 存在しないアーティスト
# go run q61.go hoge
` hoge ` is not found.

Q60でKVSの構築は済んでいるので、標準入力で受け取ったアーティストを検索するのみです。検索アーティストは趣味です。2015年当時のデータなので最近のアーティストはないようですが、知っているアーティストで検索すると引っかかるので楽しいです。

62. KVS内の反復処理

60で構築したデータベースを用い,活動場所が「Japan」となっているアーティスト数を求めよ.

gist6ac674e08083ff19c9154084b3d4787d

# go run q62.go
22821

keys *で全keyを取得して、それを反復してareaを検索しました。

63. オブジェクトを値に格納したKVS

KVSを用い,アーティスト名(name)からタグと被タグ数(タグ付けされた回数)のリストを検索するためのデータベースを構築せよ.さらに,ここで構築したデータベースを用い,アーティスト名からタグと被タグ数を検索せよ.

gista57f35c159e2693ca841051ecbc390ef

# go run q63.go "Fear of War"
count   |tag
--------------------
1   | punk
1   | sweden
1   | hardcore
1   | fagersta

list型でtagを入れました。検索は適当に複数タグがあるアーティストにしてみました。

64. MongoDBの構築

アーティスト情報(artist.json.gz)をデータベースに登録せよ.さらに,次のフィールドでインデックスを作成せよ: name, aliases.name, tags.value, rating.value

gistb4ce4fe18042ae02c8eafe941f59548b

# go run q64.go
before:  392.39824ms
after:  1.308422ms

Indexをはる前後でのnameでのクエリの実行時間を測定してみましたが、速くなっていますね。aliases.name, tags.value, rating.valueにはIndexをはらずに、nameのみIndexをはると800us程度になるので、むやみやたらにIndexをはればいいわけではないですね。
GolangでMongoDBを扱うためのbsonについては以前記事にまとめましたので、そちらも御覧ください。

65. MongoDBの検索

MongoDBのインタラクティブシェルを用いて,"Queen"というアーティストに関する情報を取得せよ.さらに,これと同様の処理を行うプログラムを実装せよ.

// インタラクティブシェル
> db.artist.find({"name": "Queen"})
{ "_id" : ObjectId("59aa3c32bb03c3f9e15a51ce"), "name" : "Queen", "tags" : [ { "count" : 1, "value" : "kamen rider w" }, { "count" : 1, "value" : "related-akb48" } ], "rating" : { "count" : 0, "value" : 0 }, "sortname" : "Queen", "ended" : true, "gid" : "420ca290-76c5-41af-999e-564d7c71f1a7", "id" : 701492, "area" : "Japan", "aliases" : [ { "name" : "Queen", "sortname" : "Queen" } ], "begin" : { "year" : 0, "month" : 0, "date" : 0 }, "end" : { "year" : 0, "month" : 0, "date" : 0 }, "gender" : "Female", "type" : "Character" }
{ "_id" : ObjectId("59aa3c3abb03c3f9e15bdf28"), "name" : "Queen", "tags" : [ { "count" : 2, "value" : "hard rock" }, { "count" : 1, "value" : "70s" }, { "count" : 1, "value" : "queen family" }, { "count" : 1, "value" : "90s" }, { "count" : 1, "value" : "80s" }, { "count" : 1, "value" : "glam rock" }, { "count" : 4, "value" : "british" }, { "count" : 1, "value" : "english" }, { "count" : 2, "value" : "uk" }, { "count" : 1, "value" : "pop/rock" }, { "count" : 1, "value" : "pop-rock" }, { "count" : 1, "value" : "britannique" }, { "count" : 1, "value" : "classic pop and rock" }, { "count" : 1, "value" : "queen" }, { "count" : 1, "value" : "united kingdom" }, { "count" : 1, "value" : "langham 1 studio bbc" }, { "count" : 1, "value" : "kind of magic" }, { "count" : 1, "value" : "band" }, { "count" : 6, "value" : "rock" }, { "count" : 1, "value" : "platinum" } ], "rating" : { "count" : 24, "value" : 92 }, "sortname" : "Queen", "ended" : true, "gid" : "0383dadf-2a4e-4d10-a46a-e9e041da8eb3", "id" : 192, "area" : "United Kingdom", "aliases" : [ { "name" : "女王", "sortname" : "女王" } ], "begin" : { "year" : 1970, "month" : 6, "date" : 27 }, "end" : { "year" : 0, "month" : 0, "date" : 0 }, "gender" : "", "type" : "Group" }
{ "_id" : ObjectId("59aa3c4bbb03c3f9e15f53d9"), "name" : "Queen", "tags" : [ ], "rating" : { "count" : 0, "value" : 0 }, "sortname" : "Queen", "ended" : true, "gid" : "5eecaf18-02ec-47af-a4f2-7831db373419", "id" : 992994, "area" : "", "aliases" : [ ], "begin" : { "year" : 0, "month" : 0, "date" : 0 }, "end" : { "year" : 0, "month" : 0, "date" : 0 }, "gender" : "", "type" : "" }

gist2f86dd77e7d54026d04bf478bff96fb0

# go run q65.go
{Queen [{1 kamen rider w} {1 related-akb48}] {0 0} Queen true 420ca290-76c5-41af-999e-564d7c71f1a7 701492 Japan [{Queen Queen}] {0 0 0} {0 0 0} Female Character}
{Queen [{2 hard rock} {1 70s} {1 queen family} {1 90s} {1 80s} {1 glam rock} {4 british} {1 english} {2 uk} {1 pop/rock} {1 pop-rock} {1 britannique} {1 classic pop and rock} {1 queen} {1 united kingdom} {1 langham 1 studio bbc} {1 kind of magic} {1 band} {6 rock} {1 platinum}] {24 92} Queen true 0383dadf-2a4e-4d10-a46a-e9e041da8eb3 192 United Kingdom [{女王 女王}] {1970 6 27} {0 0 0}  Group}
{Queen [] {0 0} Queen true 5eecaf18-02ec-47af-a4f2-7831db373419 992994  [] {0 0 0} {0 0 0}  }

Q64で構築したDBのクエリを投げるだけです。

66. 検索件数の取得

MongoDBのインタラクティブシェルを用いて,活動場所が「Japan」となっているアーティスト数を求めよ.

> db.artist.find({"area": "Japan"}).count()
22821

67. 複数のドキュメントの取得

特定の(指定した)別名を持つアーティストを検索せよ.

gist2ae3e6047aa223568e14a7abef7bd9b5

# go run q67.go supercell
{supercell [] {3 100} supercell true 9b15ff5e-5bd1-43c2-821d-e31240aad334 311779 Japan [{超级单体 超级单体} {supercell スーパーセル}] {2007 0 0} {0 0 0}  Group}

ほぼQ65と同じですね。

68. ソート

"dance"というタグを付与されたアーティストの中でレーティングの投票数が多いアーティスト・トップ10を求めよ.

gist6ae30eb5984a5b4699604fe6baa6eb0d

# go run q68.go
Madonna
Björk
The Prodigy
Rihanna
Britney Spears
Maroon 5
Adam Lambert
Fatboy Slim
Basement Jaxx
Gigi D’Agostino
Cornershop
Duran Duran

sortパッケージがgo1.8以上で変わっていたのは知っていたものの試していなかったので触れてよかったです。

69. Webアプリケーションの作成

ユーザから入力された検索条件に合致するアーティストの情報を表示するWebアプリケーションを作成せよ.アーティスト名,アーティストの別名,タグ等で検索条件を指定し,アーティスト情報のリストをレーティングの高い順などで整列して表示せよ.

gistb97736d9ce01ae3766f919d2d749fcb6

テンプレートファイルは以下です。

gist3d7903a98687bfcf6e5ce9f49be189a3

gist308ac9755a102f56f44f9f1eb7307304

どうやらginというHttpRouterが有名そうなので、今回はginを使って、検索フォームから検索し、テーブルで結果を表示するようにしてみました。 CLIからq69.goを実行した状態で、ブラウザでhttp://localhost:8080/indexへアクセスすると以下のように表示されます。

f:id:cipepser:20170903234012p:plain

検索してあげるとこんな感じです。空欄は元データが入っていないところです。

f:id:cipepser:20170903234017p:plain

初めてginを使ってみましたが、c.JSONなどとすると簡単にjsonを返せるようなのでAPIサーバも書けそうです。
今回のフォームからユーザに入力させる形式のところはインジェクション対策は何もしていないのでこのままでは使えないですが、Goでひと通り書いてみて勉強になりました。

感想

redisは軽くしか触れたことがなかったので、復習も兼ねて勉強になりました。Q68まではサクサク進みますが、Q69は重めですね。実りが多かったのでよかったですが。

いつも通りコードはGithubにも置いてあります。

Reference

Golangでロジスティック回帰

技評連載の機械学習 はじめようを拝見したので、Golangでロジスティック回帰を実装してみます。

イメージしやすいように結果の散布図を先に載せます。 赤と青がそれぞれ正解ラベルを表しており、緑色の実践が学習した判別境界です。

f:id:cipepser:20170921224958p:plain

問題設定

以下のように2次元平面上で、一様乱数を生成します。

// テストデータの用意
rand.Seed(time.Now().UnixNano())

x1 := make([]float64, N)
x2 := make([]float64, N)
for i := 0; i < N; i++ {
  x1[i] = 10*rand.Float64() - 5
  x2[i] = 10*rand.Float64() - 5
}

直線 2x_1+3x_2-1 = 0を境界として、生成した乱数に対して、

 2x_1+3x_2-1 \geq 0 :  t_n = 1,

 2x_1+3x_2-1 \lt 0 :  t_n = 0

とラベル付けします。

境界線である直線は、特徴ベクトル \boldsymbol{x} = [1, x_1, x_2]^Tと 学習したい重み \boldsymbol{w} = [w_0, w_1, w_2]^Tを用いて、  \boldsymbol{w}^T \boldsymbol{x} = 0と書けます。 直線 2x_1+3x_2-1 = 0なので  \boldsymbol{w} = [w_0, w_1, w_2]^T = [-1, 2, 3]^Tに近づくことを期待して、 \boldsymbol{w} = [w_0, w_1, w_2]^Tを学習するのが目標となります。

方針

式の導出などは機械学習 はじめよう に書かれているため、詳細はそちらを見ていただくとして、  \boldsymbol{w} = [w_0, w_1, w_2]^Tを学習するためには、結局、以下を実装すればよいことになります。

 \boldsymbol{w}_{i+1} = \boldsymbol{w}_{i} - \eta \cdot \Bigl(\sigma\bigl( \boldsymbol{w}_{i}^T \phi(\boldsymbol{x}_{n}) \bigr) - t_{n} \Bigr)\phi(\boldsymbol{x}_{n})

ここで \etaは学習率、 \sigma(\cdot)シグモイド関数です。

また特徴量は、元データが線形分離可能であることからも、特徴ベクトル \phi(\boldsymbol{x}) = \boldsymbol{x} = [1, x_1, x_2]^Tとすれば十分でしょう。第1成分の1はいわゆる切片を表しています。

実装

実装は以下のようになりました。 結果を図示するためにgonum/plotを使っています。なのでちょっとコードは長いです。 行列やベクトルも同じくgonumのgonum/matを使っています。ちなみにgonum/matrixは既にメンテナンスされておらず、今回用いたgonum/matに移行しているようです。 教師データとテストデータはそれぞれ1000個ずつにしています。

giste98445af5552e366cfcb57e81722a0c2

結果

学習した重み\boldsymbol{w}と、教師データ/テストデータを判別した結果は以下です。

// 学習結果
// 参考) 真値: [-1, 2, 3]
&{{1 [-0.5416022992823583 1.6422051384123924 -2.760912629909472]} 3}

// 判別結果
training data:  0.986
new data:  0.982

判別はシグモイド関数の値が0.5を境界として行っています。false positive/negativeをどれくらい許容できる/できないでチューニングも可能です。

結果を見る限り、ある程度は真値に近い値になっていますね。判別結果も新たに生成したデータであっても教師データと同程度の判別率を達成できているのがわかります。

感想

Golangで実装したかったので実装してみましたが、gonum/matのようなパッケージを使うと[]float64からmat.VecDense型への変換などもあって、さくっと書くには少し面倒ですね。そこら辺は動的型付けの言語のほうがよさそうです。

あとは、ロジスティック回帰の理解があやふやだったので、実装してある程度整理できたのでよかったです。特徴量の設計によって非線形の分布に対しても、うまく線形分離可能な空間に飛ばせればロジスティック回帰でかなりの精度が出そうですね。その関数を探すのが大変ですが。。。

References

GithubのGraphQLを触ったメモ書き

最近GraphQLなる言葉をよく見るようになったので、調べつつ、習うより慣れろで触ってみたのでその形跡を残します。

GraphQLとは

GraphQLを読んだ印象としては、API越しのQuery languageと理解しました。 RESTの次のパラダイムはGraphQLかにもあるようにREST APIとの対比で語られているようです。

自分でもなんらかのサービスで提供されているAPIを叩くことがありますが、レスポンスには実際に欲しいデータだけでなく、余分なデータも含まれています。リクエストを投げる時点で欲しい情報をクエリパラメタとして渡してあげることで、必要な情報だけをレスポンスとして得られるのが利点と考えます。 RESTの次のパラダイムはGraphQLかでは、その他の問題も完結にまとめられているのでわかりやすいです。

GithubのExploreで触ってみる

GithubGUIでGraphQLを触れるExploreを提供してくれているので、実際に触って所感を掴みましょう。 クエリのReferenceはこちら

以下は「自分のレポジトリを更新順に並べ、最初のn個を取得」するクエリです。 変数を$nとして受け取らせています。 また、viewerがログインしているユーザ(自分自身)を表します。

// query
query($n: Int!){
  viewer {
    repositories(orderBy: {field: UPDATED_AT, direction: DESC}, first: $n) {
      edges {
        node {
          name
        }
      }
    }
  }
}

// variables
{
  "n": 3
}

これを実行すると以下のようにjsonでレスポンスが返ってきます。

{
  "data": {
    "viewer": {
      "repositories": {
        "edges": [
          {
            "node": {
              "name": "goSExpression-sample"
            }
          },
          {
            "node": {
              "name": "poloniex"
            }
          },
          {
            "node": {
              "name": "goXML"
            }
          }
        ]
      }
    }
  }
}

型がある

GraphQLでは型も定義されており、今回の例だと repositoriesorderByフィールドはRepositoryOrder型になります。 ReferenceにもあるようにRepositoryOrderField型のfieldOrderDirection型のdirectionをメンバとして持っています。

なので以下のようにhogeという誤った型のクエリをわざと発行してみます。

query($n: Int!){
  viewer {
    repositories(orderBy: hoge, first: $n) {
      edges {
        node {
          name
        }
      }
    }
  }
}

すると以下のように、型が違うエラーが返ってくる実装になっていました。

{
  "data": null,
  "errors": [
    {
      "message": "Argument 'orderBy' on Field 'repositories' has an invalid value. Expected type 'RepositoryOrder'.",
      "locations": [
        {
          "line": 3,
          "column": 5
        }
      ]
    }
  ]
}

感想

とりあえず触ってみたというレベルですが、GraphQLでした。今後RESTを置き換えていくのかはわかりませんが、型があり、必要な情報だけを取ってこれるというのは場面によっては有効そうです。 RESTがこれだけ世の中に溢れていることを考えると、RESTからの移行をどうやって設計するのかなど考えるのは楽しそうですね。

Reference

Golangで言語処理100本ノック2015 第6章: 英語テキストの処理

言語処理100本ノック 2015の第6章: 英語テキストの処理の10問です。

50. 文区切り

(. or ; or : or ? or !) → 空白文字 → 英大文字というパターンを文の区切りと見なし,入力された文書を1行1文の形式で出力せよ.

gist4437579cb8e6b64166d0de27b1ce49b4

// 最初の7文のみ抜粋

# go run q50.go
Natural language processing
From Wikipedia, the free encyclopedia

Natural language processing (NLP) is a field of computer science, artificial intelligence, and linguistics concerned with the interactions between computers and human (natural) languages.
As such, NLP is related to the area of humani-computer interaction.

History

The history of NLP generally starts in the 1950s, although work can be found from earlier periods.
In 1950, Alan Turing published an article titled "Computing Machinery and Intelligence" which proposed what is now called the Turing test as a criterion of intelligence.

golangでは、lookaheadをサポートしていないので、次の一文のCapitalを回してあげるのがめんどうでした。

51. 単語の切り出し

空白を単語の区切りとみなし,50の出力を入力として受け取り,1行1単語の形式で出力せよ.ただし,文の終端では空行を出力せよ.

// q50の結果をtxtに保存しておく
# go run q50.go > ../data/q50_out.txt

gist154c531bd00e06627a06871620015ece

// 最初の3文のみ抜粋
# go run q51.go

Natural
language
processing

From
Wikipedia,
the
free
encyclopedia



Natural
language
processing
(NLP)
is
a
field
of
computer
science,
artificial
intelligence,
and
linguistics
concerned
with
the
interactions
between
computers
and
human
(natural)
languages.

As
such,
NLP
is
related
to
the
area
of
humani-computer
interaction.

Splitするだけなので余裕ですね。

52. ステミング

51の出力を入力として受け取り,Porterのステミングアルゴリズムを適用し,単語と語幹をタブ区切り形式で出力せよ. Pythonでは,Porterのステミングアルゴリズムの実装としてstemmingモジュールを利用するとよい.

// q51の結果をtxtに保存しておく
# go run q51.go > ../data/q51_out.txt

gist8a0fc9ac1d9432a9da14bd87d91476ae

# go run q52.go

// 最初の3文のみ抜粋
Natural      natur
language     languag
processing   process
From     from
Wikipedia,   wikipedia,
the      the
free     free
encyclopedia     encyclopedia
Natural      natur
language     languag
processing   process
(NLP)    (nlp)
is   is
a    a
field    field
of   of
computer     comput
science,     science,
artificial   artifici
intelligence,    intelligence,
and      and
linguistics      linguist
concerned    concern
with     with
the      the
interactions     interact
between      between
computers    comput
and      and
human    human
(natural)    (natural)
languages.   languages.
As   as
such,    such,
NLP      nlp
is   is
related      relat
to   to
the      the
area     area
of   of
humani-computer      humani-comput
interaction.     interaction.

golangでのstemming実装としてGo Porter Stemmerを使いました。

53. Tokenization

Stanford Core NLPを用い,入力テキストの解析結果をXML形式で得よ.また,このXMLファイルを読み込み,入力テキストを1行1単語の形式で出力せよ.

// 公式サイトからDownloadし、zipを解凍したフォルダで以下のshellを実行すると、実行したディレクトリにxmlファイルが生成される
# cd stanford-corenlp-full-2017-06-09
# ./corenlp.sh -annotators tokenize,ssplit,pos,lemma,ner,parse,dcoref -outputFormat xml -file <YOUR_PATH_TO>/nlp.txt
# mv ./nlp.txt.xml ../data

// xmlから自動的にgo structを作り出す
# chidley -G -e "" ../data/nlp.txt.xml

gist9672a32d376e48be9bf55571c799db31

// 最初の1文のみ抜粋
# go run q53.go
Natural
language
processing
From
Wikipedia
,
the
free
encyclopedia
Natural
language
processing
-LRB-
NLP
-RRB-
is
a
field
of
computer
science
,
artificial
intelligence
,
and
linguistics
concerned
with
the
interactions
between
computers
and
human
-LRB-
natural
-RRB-
languages
.

Stanford Core NLPを初めて触ったので実行の仕方がわからなくて苦労しました。 golangで実装するのはxmlの読み込みからです。 前処理にも書きましたが、自分でgo structを定義し直すのは面倒なので、chidleyを使って自動生成させています。

54. 品詞タグ付け

Stanford Core NLPの解析結果XMLを読み込み,単語,レンマ,品詞をタブ区切り形式で出力せよ.

gist701c1fdd47b0777c7a6c8cbb1f663bb5

# go run q54.go
Natural      natural     JJ
language     language    NN
processing   processing      NN
From     from    IN
Wikipedia    Wikipedia   NNP
,    ,   ,
the      the     DT
free     free    JJ
encyclopedia     encyclopedia    NN
Natural      natural     JJ
language     language    NN
processing   processing      NN
-LRB-    -lrb-   -LRB-
NLP      nlp     NN
-RRB-    -rrb-   -RRB-
is   be      VBZ
a    a   DT
field    field   NN
of   of      IN
computer     computer    NN
science      science     NN
,    ,   ,
artificial   artificial      JJ
intelligence     intelligence    NN
,    ,   ,
and      and     CC
linguistics      linguistics     NNS
concerned    concern     VBN
with     with    IN
the      the     DT
interactions     interaction     NNS
between      between     IN
computers    computer    NNS
and      and     CC
human    human   JJ
-LRB-    -lrb-   -LRB-
natural      natural     JJ
-RRB-    -rrb-   -RRB-
languages    language    NNS
.    .   .

Q53から出力部分を変えるのみです。

55. 固有表現抽出

入力文中の人名をすべて抜き出せ.

gist6ee9809052e2294a98ef9237316525c2

# go run q55.go
Alan
Turing
Joseph
Weizenbaum
MARGIE
Schank
Wilensky
Meehan
Lehnert
Carbonell
Lehnert
Racter
Jabberwacky
Moore

Stanford Core NLPで解析を行うと、人名がNERPERSONとして現れてくるのでそれを抜き出してあげるだけです。

56. 共参照解析

Stanford Core NLPの共参照解析の結果に基づき,文中の参照表現(mention)を代表参照表現(representative mention)に置換せよ.ただし,置換するときは,「代表参照表現(参照表現)」のように,元の参照表現が分かるように配慮せよ.

gistf36c33493e5d272f743916088a8ad6f5

// 最初の5文のみ抜粋
# go run q56.go
Natural language processing From Wikipedia , the free encyclopedia Natural language processing -LRB- NLP -RRB- is [the free encyclopedia Natural language processing -LRB- NLP -RRB-] (a field of computer science) , artificial intelligence , and linguistics concerned with the interactions between computers and human -LRB- natural -RRB- languages .
As such , NLP is related to the area of humani-computer interaction .
Many challenges in NLP involve natural language understanding , that is , enabling [computers] (computers) to derive meaning from human or natural language input , and others involve natural language generation .
History The history of NLP generally starts in the 1950s , although work can be found from earlier periods .
In 1950 , Alan Turing published an article titled `` Computing Machinery and Intelligence '' which proposed what is now called the [Alan Turing] (Turing) test as a criterion of intelligence .

参照表現を()で括り、もとの代表参照表現を[]で括っています。
全文まとめてStanford Core NLPで解析したからか微妙な解析結果もちらほらあるようです。 しかし一文ずつ解析すると文をまたがった表現が拾えないので全文まとめた解析としました。

57. 係り受け解析

Stanford Core NLP係り受け解析の結果(collapsed-dependencies)を有向グラフとして可視化せよ.可視化には,係り受け木をDOT言語に変換し,Graphvizを用いるとよい.また,Pythonから有向グラフを直接的に可視化するには,pydotを使うとよい.

gistea1dc7dec630b507a0d3ce336acda10f

# go run q57.go
# dot -T png ../data/q57.dot -o ../data/q57.png
# open ../data/q57.png

f:id:cipepser:20170820125921p:plain

最初の一文をグラフにしました。 Goでの有向グラフの書き方は以前まとめたのでこちらをご覧ください。

58. タプルの抽出

Stanford Core NLP係り受け解析の結果(collapsed-dependencies)に基づき,「主語 述語 目的語」の組をタブ区切り形式で出力せよ.ただし,主語,述語,目的語の定義は以下を参考にせよ.

  • 述語: nsubj関係とdobj関係の子(dependant)を持つ単語
  • 主語: 述語からnsubj関係にある子(dependent)
  • 目的語: 述語からdobj関係にある子(dependent)

gist01e16fef3dd5e2f567fa7b63896e239d

# go run q58.go
challenges   involve     generation
others   involve     generation
understanding    enabling    computers
Turing   published   article
experiment   involved    translation
ELIZA    provided    interaction
patient      exceeded    base
ELIZA    provide     response
which    structured      information
underpinnings    discouraged     sort
that     underlies   approach
Some     produced    systems
which    make    decisions
systems      rely    which
that     contains    errors
implementations      involved    coding
algorithms   take    set
Some     produced    systems
which    make    decisions
models   have    advantage
they     express     certainty
Systems      have    advantages
Automatic    make    use
that     make    decisions

mapで実装しようとしたらcannot assign to struct fieldのエラーが出てハマりました。

59. S式の解析

Stanford Core NLP句構造解析の結果(S式)を読み込み,文中のすべての名詞句(NP)を表示せよ.入れ子になっている名詞句もすべて表示すること.

gist6f587f61adc2ca08abf5eda2201d2dcb

// 最初の1文のみ抜粋
# go run q59.go
(NP (JJ Natural)(NN language)(NN processing))
(NP (NNP Wikipedia))
(NP (NP (DT the)(JJ free)(NN encyclopedia)(JJ Natural)(NN language)(NN processing))(PRN (-LRB- -LRB-)(NP (NN NLP))(-RRB- -RRB-)))
(NP (DT the)(JJ free)(NN encyclopedia)(JJ Natural)(NN language)(NN processing))
(NP (NN NLP))
(NP (NP (NP (DT a)(NN field))(PP (IN of)(NP (NN computer)(NN science))))(, ,)(NP (JJ artificial)(NN intelligence))(, ,)(CC and)(NP (NP (NNS linguistics))(VP (VBN concerned)(PP (IN with)(NP (NP (DT the)(NNS interactions))(PP (IN between)(NP (NP (NNS computers))(CC and)(NP (JJ human)(-LRB- -LRB-)(JJ natural)(-RRB- -RRB-)(NNS languages)))))))))
(NP (NP (DT a)(NN field))(PP (IN of)(NP (NN computer)(NN science))))
(NP (DT a)(NN field))
(NP (NN computer)(NN science))
(NP (JJ artificial)(NN intelligence))
(NP (NP (NNS linguistics))(VP (VBN concerned)(PP (IN with)(NP (NP (DT the)(NNS interactions))(PP (IN between)(NP (NP (NNS computers))(CC and)(NP (JJ human)(-LRB- -LRB-)(JJ natural)(-RRB- -RRB-)(NNS languages))))))))
(NP (NNS linguistics))
(NP (NP (DT the)(NNS interactions))(PP (IN between)(NP (NP (NNS computers))(CC and)(NP (JJ human)(-LRB- -LRB-)(JJ natural)(-RRB- -RRB-)(NNS languages)))))
(NP (DT the)(NNS interactions))
(NP (NP (NNS computers))(CC and)(NP (JJ human)(-LRB- -LRB-)(JJ natural)(-RRB- -RRB-)(NNS languages)))
(NP (NNS computers))
(NP (JJ human)(-LRB- -LRB-)(JJ natural)(-RRB- -RRB-)(NNS languages))
--------------

S式の簡易パーサを実装したのでそちらを使いました。 Treeは再帰的に処理させやすくてよいですね。

感想

Stanford Core NLPはもう少し丁寧に触るとかなりおもしろそうですね。 ステミングあたりなどは言葉から知らなかったり、パーサを初めて書いてみたり色々収穫の多い章でした。

いつも通りコードはGithubにも置いてあります。

Reference