【自然言語処理】Google Colaboratoryでword2vecを実装してみよう!

【自然言語処理】Google Colaboratoryでword2vecを実装してみよう!

当ページのリンクには広告が含まれています。


本記事では、word2vecを実装していきます。


word2vecとはなにか?については、以下の記事でまとめています。

実装の全体像

1. word2vecを実装する環境を用意する

本記事では、Google Colaboratoryを使用します。

Google Colaboratoryとは、ブラウザ上でPythonを記述し実行できる環境です。

Googleのアカウントを持っていればすぐに利用できます。

GPUも無料で利用できるなど、嬉しい機能がたくさん備わっています。

詳しい使い方は、こちらで紹介されています。

もし、ローカルの環境に、Google Colaboratoryと似たような開発環境を用意したい場合は、以下の記事を参照いただければと思います。Anaconda Navigatorを用いてjupyter notebookを利用する方法です。

2. Livedoorニュースのファイルをダウンロードしカテゴリ数と内容を確認する

本記事では、livedoor newsコーパスというテキストコーパスを使用します。

Google colabで以下のコードを入力し実行してみましょう。

Livedoorコーパスのダウンロード
1
! wget "https://www.rondhuit.com/download/ldcc-20140209.tar.gz"

以下のような出力がされたら、ダウンロード成功です。

出力
1
2
3
4
5
6
7
8
9
10
--2021-04-29 08:42:51--  https://www.rondhuit.com/download/ldcc-20140209.tar.gz
Resolving www.rondhuit.com (www.rondhuit.com)... 59.106.19.174
Connecting to www.rondhuit.com (www.rondhuit.com)|59.106.19.174|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 8855190 (8.4M) [application/x-gzip]
Saving to: ‘ldcc-20140209.tar.gz’

ldcc-20140209.tar.g 100%[===================>] 8.44M 2.00MB/s in 4.2s

2021-04-29 08:42:56 (2.00 MB/s) - ‘ldcc-20140209.tar.gz’ saved [8855190/8855190]

また、Google colabの画面左側に表示されるフォルダに、Livedoorコーパスのファイルがダウンロードされていることを確認しましょう。Ldcc-20140209.tar.gzというファイルが、Livedoorコーパスファイルです。



Livedoorコーパスがダウンロードされていることを確認

次に、ダウンロードしたファイルを解凍し、カテゴリーの数と内容を確認します。

以下のコードを実行します。

ファイルの解凍とカテゴリー数の確認
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# ファイルを解凍し、カテゴリー数と内容を確認
import tarfile
import os

# 解凍
tar = tarfile.open("ldcc-20140209.tar.gz", "r:gz")
tar.extractall("./data/livedoor/")
tar.close()

# フォルダのファイルとディレクトリを確認
files_folders = [name for name in os.listdir("./data/livedoor/text/")]
print(files_folders)

# カテゴリーのフォルダのみを抽出
categories = [name for name in os.listdir(
"./data/livedoor/text/") if os.path.isdir("./data/livedoor/text/"+name)]

print("カテゴリー数:", len(categories))
print(categories)

こちらのコードを実行すると、以下のような出力が得られます。

出力
1
2
3
['topic-news', 'kaden-channel', 'README.txt', 'sports-watch', 'CHANGES.txt', 'it-life-hack', 'movie-enter', 'dokujo-tsushin', 'smax', 'livedoor-homme', 'peachy']
カテゴリー数: 9
['topic-news', 'kaden-channel', 'sports-watch', 'it-life-hack', 'movie-enter', 'dokujo-tsushin', 'smax', 'livedoor-homme', 'peachy']

カテゴリーの数は9つ存在することが分かります。

9つのカテゴリは、['topic-news', 'kaden-channel', 'sports-watch', 'it-life-hack', 'movie-enter', 'dokujo-tsushin', 'smax', 'livedoor-homme', 'peachy']です。

3. 記事を2つ抽出し、記事の全文と記事のラベル(カテゴリ)を表示してみる

まずは、word2vecを実装するために必要なライブラリを導入します。以下のコードを実行して、janomeをインストールします。

1
!pip install janome

以下のような出力が得られたら成功です。

出力
1
2
3
4
5
Collecting janome
Downloading https://files.pythonhosted.org/packages/a8/63/98858cbead27df7536c7e300c169da0999e9704d02220dc6700b804eeff0/Janome-0.4.1-py2.py3-none-any.whl (19.7MB)
|████████████████████████████████| 19.7MB 1.2MB/s
Installing collected packages: janome
Successfully installed janome-0.4.1

その上で、以下のコードを実行すれば、2つの記事のラベルと全文が確認できます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import glob
from janome.tokenizer import Tokenizer
from gensim.models import word2vec

def load_livedoor_news_corpus():
category = {
"dokujo-tsushin": 1,
"it-life-hack":2,
"kaden-channel": 3,
"livedoor-homme": 4,
"movie-enter": 5,
"peachy": 6,
"smax": 7,
"sports-watch": 8,
"topic-news":9
}
docs = []
labels = []

for c_name, c_id in category.items():
files = glob.glob("./data/livedoor/text/{c_name}/{c_name}*.txt".format(c_name=c_name))
for file in files:
with open(file, "r", encoding="utf-8") as f:
lines = f.read().splitlines()
url = lines[0]
datetime = lines[1]
subject = lines[2]
body = "".join(lines[3:])
text = subject + body

docs.append(text)
labels.append(c_id)

return docs, labels

docs, labels = load_livedoor_news_corpus()

print("\nlabel: ", labels[0], "\ndocs:\n", docs[0])
print("\nlabel: ", labels[1000], "\ndocs:\n", docs[1000])

簡単にコードの内容を説明します。合わせて、pythonのコードも学んでおきましょう。

import globは、globというモジュールを導入しています。globモジュールは、ファイルやディレクトリを操作するときに便利なモジュールであり、正規表現を用いてパスを指定できます。

def load_livedoor_news_corpus()関数では、全ての記事の文章データとそのラベル(カテゴリー)を取得しています。

辞書型のループ処理をする際、items()というメソッドを使うことで、キーとバリューの両方を変数に格納することができます。このコードでは、キーはc_nameという変数に、バリューはc_idという変数に格納されています。

ファイルを読み込む際は以下のメソッドを使用します。

  • open(): ファイルを開く
  • read(): ファイルを読み込む
  • close(): ファイルを閉じる

本コードで用いているopen()の第二引数に"r"と記述されています。これはファイルを開くときのモードを指定するもので、この場合だとreadの意味になり、読み込み専用であることを表しています。

通常、ファイルを読み込み、処理を行った後は、close()を用いてファイルを閉じる必要があるのですが、このclose()を書き忘れてしまったり、途中でエラーが発生し、ファイルが閉じることができず、無駄にメモリを専有するといったことが起こります。

それを防ぐために、with文を使用します。

with文を用いると、ファイルが自動的にclose()されるため、明示的にclose()を記述する必要がありません。また、ファイルを開いている間にエラーが発生しても、適切な例外処理が自動的に行われるため、メモリを専有することも防げます。

本コードのポイントとしては以上です。

このコードを実行すると、以下のような出力が得られるかと思います。

1
2
3
4
5
6
7
label:  1 
docs:
ムダな抵抗!? 加齢の現実 ヒップの加齢による変化は「たわむ→下がる→内に流れる」、バストは「そげる→たわむ→外に流れる」という。バストの変化はすでに20代から始まり、20代にして「たわむ」になっている人もいる。そして、元に戻った人は一人もいない。さらに、体の各部位の20代〜50代までの変化をみると、ウエストとお腹の変化が最も大きく、お腹はバストと同じ大きさになっている。 これは、4月に開催されたワコール人間科学研究所の記者発表「からだのエイジング(加齢による体型変化)について一定の法則を発見」での内容の一部。延べ4万人分の経年変化の数値を集計・分析したデータとともに、写真や映像で説明させるので説得力は抜群だ。 現実を直視させられた後に、体型変化の少ない人達の身体的特徴や日常の行動・意識を紹介。その主な内容は、日頃から体を動かし、姿勢をチェック、下着は必ず試着してフィット感を確かめるというもの。そして、パネルディスカッションでは、歩幅の広い歩き方を1年間続ける実験に参加した人が、背筋が伸び、脂肪が落ちたという結果などが紹介されていた。 興味は尽きず、知人たちに内容を伝えるとさまざまな意見や経験が聞けた。 「ずっと計測されているから、体型変化の少ない人はスポーツをしてたのでは?」という疑問もあったが、この回答は、「運動を一生懸命しているというより日常生活を気をつけている印象が強い。そして、ダイエットはあまりしたことがない」とのこと。 「叔母もそんなことを言っていた」と言うのはY子。60歳代の叔母さんが友人たちと温泉旅行に行ったとき、「バストの変化が少ないとほめられた」と喜んでいたので、バストのケア方法を尋ねたそうだ。「叔母はブラジャーを常に着用し、購入時は必ず計測して試着している。一方、友人達は『苦しい』からと家ではブラジャーをしないこともあるらしい」。それを聞いて以来、Y子は下着を買うときには試着はもちろん、計ってもらうようにしている。 「私も歩いてやせた」と話すのは、腰痛に悩まされていたK子。医師に筋力の低下を指摘されて、駅までの自転車を止めて、片道30分の道のりを毎日往復歩くことに。筋力をつけるために始めたことで体全体が引き締まり、結果として減量にも成功した。 「でも、スポーツすればしまるよね」と言うA子は、不摂生がたたって気になり始めたウエスト回りをスポーツクラブに通って改善。ジーンズがワンサイズ小さくなったと喜んでいる。 パネルディスカッションでは、「加齢は一方通行だが、現状維持は可能」「アンチエイジングは医学界でも注目だが、身体的な美しさの維持と健康維持の関係性は表裏一体のはず」とも言われていた。それならば、体型変化という加齢への抵抗はあきらめないほうが得策だ。杉本彩が言っていたっけ、「若いころに戻りたいとか、若く見られたい、とは思わない。今の自分がどう美しくあるかを追求したい」って。(オフィスエムツー/オオノマキ)詳細はコチラ

label: 2
docs:
Excel表のデータの合計値を計算式を使わず表示する方法【知っ得・虎の巻】Excelでいくつかのセルの合計値を知りたい場合、どうしているだろう? 合計値を入力するセルがあるのなら、合計の計算式を入力しておけばいいわけだが、表内のある一部分の合計値を知りたい場合などだ。実は計算式など利用しなくても、合計値を知る方法がある。■知っ得No.287 ステータスバーの情報を利用する複数のセルの合計値は、実は特に設定しなくても、初期設定で画面上に表示されるようになっている。その場所がステータスバーだ。合計の他にも、平均もわかるようになっている。●複数のファイルを選択して、合計を確認する合計を知りたいセルを選択状態にし、画面下部のステータスバーの右側部分を見てほしい。[平均:●● データの個数:●● 合計:●●]と表示されているはずだ(画面1)。 画面1 セルを選択すると、ステータスバーの右側に合計値が表示される。 なんと、セルを選択するだけで、そのセルに入力されている数値の合計だけでなく、平均や、選択しているセルの個数までわかるのである。計算機を取り出して計算したり、仮にどこかのセルに計算式を入力して計算させてみたりといった手間は全然必要ない。ステータスバーに表示する内容は、ステータスバーを右クリックすると表示される[ステータスバーのユーザー設定]で選択することで変更することもできる(画面2)。 画面2 [ステータスバーのユーザー設定]で表示する内容を指定できる。 その時々で、必要とする情報が表示されるよう、設定を変更するといいだろう。編集部:池田利夫+岡本奈知子(ジャムハウス)制作編集:エヌプラスCopyright 2012 livedoor. All rights reserved.■PC便利技が満載!「知っ得!虎の巻」ブログ■の記事をもっとみる・最近使ったファイルを素早くスタートメニューから開く・先頭行を固定したままスクロールするには?−−今さら聞けないExcelワザ・WordやExcelでよく使うコマンドをワンクリックで実行する・ウィンドウを閉じることなくデスクトップのアイコンを操作するマル秘ワザ・今さら聞けないExcelワザ 入力後のカーソルを右方向に動かすには?

4. Word2Vecの実装

Word2Vecを実装するには、gensimというモジュールを使用します。

Word2Vecは、引数として学習に使用する文章を指定するのですが、その文章は、分かち書きされている必要があります。

分かち書きは、janome.tokenizerを使って行います。

分かち書きを行う際、日本語では、「名詞、動詞、形容詞、形容動詞」以外は単語の関連性の分析に使用できません。

そのため、「名詞、動詞、形容詞、形容動詞」のみの分かち書きリストを作成します。

1
2
3
4
5
6
7
8
9
def tokenize(text):
tokens = t.tokenize(",".join(text))
word = []
for token in tokens:
part_of_speech = token.part_of_speech.split(",")[0]

if part_of_speech in ["名詞", "動詞", "形容詞", "形容動詞"]:
word.append(token.surface)
return word

Word2Vecは以下のようにして実装できます。

model = word2vec.Word2Vec(リスト, sg=1, size=a, min_count=b, window=c)

各パラメータは以下のとおりです。

  • リスト: 分かち書きされたリスト
  • sg: 1ならskip-gram。0ならCBOWで学習する
  • size: ベクトルの自演数
  • window: この数の前後の単語を、関連性のある単語とみなして学習を行う
  • min_count: n回未満登場する単語を破棄

作成したmodelに対して、.most_similar(positive=["単語"])のようにmost_similar()メソッドを用いるとその単語との類似度が高いものが出力されます。

ここでは、「家族」という単語の類似度を算出してみます。

Word2Vecの実装
1
2
3
4
5
6
# ラベルと文章に分類
docs, labels = load_livedoor_news_corpus()
t = Tokenizer() # 最初にTokenizerインスタンスを作成
sentences = tokenize(docs[0:100]) # データ量が多いため制限
model = word2vec.Word2Vec([sentences], sg=1, size=100, min_count=20, window=15)
print(model.most_similar(positive=["家族"]))
出力
1
2
3
[('意味', 0.9859291315078735), ('必要', 0.9851418137550354), ('お互い', 0.9839500188827515), ('親', 0.9809558987617493), ('思い', 0.9803527593612671), ('生活', 0.9785477519035339), ('母', 0.9776737689971924), ('32', 0.9745824337005615), ('あっ', 0.9723453521728516), ('みたい', 0.9685757756233215)]
/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:7: DeprecationWarning: Call to deprecated `most_similar` (Method will be removed in 4.0.0, use self.wv.most_similar() instead).
import sys

「家族」という単語と類似度が高い単語として、「意味」や「必要」、「お互い」、「親」といった関連性の高い単語が出力されていることが分かります。

いろいろな単語で試してみましょう。

1
print(model.most_similar(positive=["恋"]))
出力
1
2
3
[('夏', 0.9577336311340332), ('アイテム', 0.9559974670410156), ('できる', 0.9532942771911621), ('カフェ', 0.9497220516204834), ('映画', 0.9485588073730469), ('中', 0.943411111831665), ('今回', 0.9432932138442993), ('魅力', 0.9406061172485352), ('行動', 0.9401353001594543), ('感', 0.9322444200515747)]
/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:1: DeprecationWarning: Call to deprecated `most_similar` (Method will be removed in 4.0.0, use self.wv.most_similar() instead).
"""Entry point for launching an IPython kernel.

「恋」という単語と類似度が高い単語として「夏」、「アイテム」、「カフェ」といった単語が抽出されました。

まとめ: word2vecの実装方法を学びました

改めて全体を振り返りましょう。本記事では、以下のような流れでWord2Vecを実装してみました。

  1. word2vecを実装する環境を用意する
  2. Livedoorニュースのファイルをダウンロードしカテゴリ数と内容を確認する
  3. 記事を2つ抽出し、記事の全文と記事のラベル(カテゴリ)を表示してみる
  4. Word2Vecの実装

本記事で紹介したコードをベースに、他の単語で試してみたり、skip-gramとCBOWの比較や、処理速度の違いを試してみてください。

また、より専門的な自然言語処理技術は、Udemyで学ぶことが出来ます。

なかでも、自然言語処理とチャットボット: AIによる文章生成と会話エンジン開発
が特におすすめですので、ご確認ください。

参考記事

コメント