機械学習が人気ですが、「Word2Vec」「Doc2Vec」という、文章などを分析するニューラルネットワークモデルを知っていますか?
すごーく簡単に言うと、「Word2Vec」は単語の類似度のベクトル、「Doc2Vec」は文章の類似度のベクトルを表現します。
結構前に話題になったので既に知っている人も多いかもしれませんが、今回はpaizaのスキルチェック問題に提出された一部のコードを対象に、「Word2Vec」と「Doc2Vec」でどんなことができるかやってみたいと思います。(※スキルチェック問題や回答の内容は判別できないように処理しています)
■Word2Vecについて
ざっくり言うと、ある単語の周辺に別の単語が出現する確率……みたいなものを見てくれます。ニューラルネットワークを使って、類似度を求めています。Word2Vecは隠れ層1、出力層1の、2層のニューラルネットワークです。
例えば、「ピーマン」と「焼肉」という単語の比較を考えてみましょう。
「ピーマン」は「おいしい」、「焼肉」は「まずい」と思う人もいるとは思いますが、それは珍しいケースだった場合に
「ピーマン」の周りには「まずい」の頻度が高い
「焼肉」の周りには「おいしい」の頻度が高い
という結果が出たら、「ピーマン」と「焼肉」という単語はベクトルとして異なるんだな、ということがわかります。何となくわかるでしょうか。(※これはあくまで分析データ内にそういう文が多かったら、という例です。私は焼肉もピーマンもおいしいです)
■Doc2Vecについて
Doc2Vecは、単語ベクトルとパラグラフベクトルを組み合わせることで、文章自体のベクトルを求めます。
実際にPythonとgensimというライブラリを使って試してみました。
対象は、スキルチェック問題へ提出されたコードのうち、Pythonで書かれたコードとします。(ブロックインデントでスペース区切りが多く、関数名とか変数名とかバラしやすいから)
gensimのインストールに関してはPythonですので
pip install gensim
だけで済みます。
■ディープラーニングをやってみる
今回は、前にこのブログでデータ分析をやってみた記事(後でリンク貼ります)でも使った、Jupyter上で実際に動かして結果を見てみましょう。
Doc2Vecを作ればWord2Vecの方も一緒に参照できるので、まずDoc2Vecから求めます。
Doc2Vecに与えるデータとしては、提出されたPythonのコードのうち、「B問題で1点以上を獲得したもの」を対象とします。また、コメントは取り除き、スペース、タブ、改行区切りで単語に分解します。
コードのラベルとしては、提出したユーザーのランクを割り当てます。
これで、例えばあるランクのユーザーが提出したコードは、その前後のランクのユーザーが書いたコードに類似しているかどうか……みたいなことがわかるのでは?と想定しています。
データ取得に関しては、以前データ分析をやってみた記事と同じ方法でSQLを叩いて、必要な部分だけを取り出しています。
上記のような入力をcodeに関しては空白文字で分割して使用します。
import gensim from gensim.models.doc2vec import Doc2Vec from gensim.models.doc2vec import TaggedDocument training_code = [] for i in df.iterrows(): training_code.append(TaggedDocument(words=i[1].code.split(), tags=[str(i[1].user_rank)])) model = Doc2Vec(documents=training_code, size=100 , window=3, min_count=1, dm=1)
TaggedDocumentでwords="対象の文章", tags=["タグ"] というように、文章とタグを引数として与えます。
それをまずリストに入れて、Doc2Vecで documents=TaggedDocumet のリストを指定し、その他のオプションを指定していきます。
sizeは単語ベクトルの次元数、windowはどの周辺単語まで見るか、min_countは未満の出現頻度の単語は無視する、dm=1はdmpvというアルゴリズムを使う、ということをそれぞれ指定しています。
パラメータのチューニングの余地はまだあるかもしれませんが、windowが3単語なのは、ソースコードにおいてそこまで広い範囲で単語の関係性はないのでは?という理由です。その他は公式のドキュメントのデフォルトの値(size=100など)にしました。
■結果を見てみる
まずWord2Vecの結果として、似ている単語について見てみましょう。
model.most_similar(positive="if") とすると、"if"に類似している単語上位10件を取得できます。
for i in model.most_similar(positive="if"): print(i[0], i[1])
これを実行した結果がこちら。
なんとなーくandとかelseとかelifとかが引っかかりますね。ただ単語の分割が微妙で、変なワードも含まれています。もう少し入力データを整えてからの方がよかったかもしれません……。
続いて、"True"に類似している単語は以下のような結果が出ました。
Falseはまさに、という感じですね。他にも"flg1"や"deta"などは条件文とかで出てきそうなので、近い感じがありますね。
今度はDoc2Vecを使い、ユーザーのランクをタグとして、ソースコードの類似度を比較していきましょう。
model.docvecs.most_similar(['S']) とすると、'S'をタグとして上位10件の類似度を出力できます。今回はタグがS、A、B、C、Dの5種なのでどれかのタグを指定すると4件結果が返ってきます。
Sランクのコードに似ているのはどのランクのコードなのか?Sランクは最高ランクなので、A、B、C、Dとランクの高い順に似ているのでは?と思いますが、実際はDランクユーザーの書いたコードが2番目に近いという結果が出ました。
Dランクユーザーの解答はシンプルなコードが多く、それで逆にSランクのコードとの類似度が上がってしまうのかな?という感じがします。
同様に、CランクのコードもBランクのコードより類似していますね。Sランクユーザーは、上位問題で正解できることはもちろん、よりシンプル化したコードを提出している傾向がある?ということが言えるかもしれません。
では、サンプル対象のコードをさらに絞ってみます。Dランク問題への提出コードで、点数が100点のものだけに絞り込んでみました。
ランクの高い順に近づきましたね。ただ、やはりDとCが微妙に前後していますね……パラメータのチューニングによってはもう少しよくなるかも?
■まとめ
こういう調査を進めていくと、Dランク問題を解いてもらうだけでランクがわかってしまうとか、実行結果を見なくても書いたコードを分析すれば高ランク取得者かそうでないかがわかってしまうとか……もしかしたら、そんな可能性もあるのかもしれませんね。
できれば単純な単語分割だけでなく、Pythonのastとかでコードの構文木などをデータに落とし込んで詳しく分析してみたいのですが……それはまた別の機会にしたいと思います。
「機械学習どころかプログラミング自体が初心者なので、Pythonを基礎から学びたい!」という方は、プログラミングが動画で学べる「paizaラーニング」の「Python入門編」から始めてみると、無理なく基礎を習得できると思います。
■動画でプログラミングが学べるpaizaラーニングにPython×AI・機械学習入門編が登場!
動画でプログラミングが学べるpaizaラーニングでは、Python、Java、C言語、C#、PHP、Ruby、SQL、JavaScript、HTML/CSSなど、プログラミング初心者でも動画で学べる入門レッスンを公開しています。
そしてこのたび、新たに「Python×AI・機械学習入門編」が追加されました。
人気声優の上坂すみれさんによる進行役のスベトラーナ・小百合・ベレフスカヤと一緒に、実際に画像認識技術を使いながら、初心者でも機械学習を体験・学習できるレッスン内容になっています。
Python×AI・機械学習入門編は全編無料でごらんいただけます。詳しくはこちら
そして、paizaでは、Webサービス開発企業などで求められるコーディング力や、テストケースを想定する力などが問われるプログラミングスキルチェック問題も提供しています。
スキルチェックに挑戦した人は、その結果によってS・A・B・C・D・Eの6段階のランクを取得できます。必要なスキルランクを取得すれば、書類選考なしで企業の求人に応募することも可能です。「自分のプログラミングスキルを客観的に知りたい」「スキルを使って転職したい」という方は、ぜひチャレンジしてみてください。