日本語WordNetを使って、何か面白いことができないか調べていきたいと思います。
今回は、とりあえず日本語WordNetについて簡単に情報をまとめ、類義語を検索できるツールをpython3で作ってみました。
WordNetとは?
同義語、上位・下位語などがまとめられている、概念の辞書です。
元々英語で整備が進んでいました。
日本語版は、2006~2010に、国立研究開発法人情報通信研究機構(NICT)が整備を進めました。
詳しくはWikipediaで
https://ja.wikipedia.org/wiki/WordNet
WordNetはどうやったら使えるの?
以下の日本語WordNetのHPから、ダウンロードできます。商用フリーです。申し込み不要です。
日本語 WordNet:
http://compling.hss.ntu.edu.sg/wnja/
私はpython経由で使いやすそうな「Japanese Wordnet and English WordNet in an sqlite3 database」をダウンロードしました。
以降では、sqliteDB形式のWordNetをpythonから呼ぶ方式で説明します。
WordNetをpythonから呼ぶ
WordNetをダウンロードしたら、pythonからWordNetを呼びます。
sqlite3という標準ライブラリを使えば、通常のSQLの感覚で操作できます。
まず、WordNetのDBに接続します。
import sqlite3
conn = sqlite3.connect("wnjpn.db")
どのようなテーブルが含まれているか確認してみます。
# 含まれるテーブルの確認
cur = conn.execute("select name from sqlite_master where type='table'")
for row in cur:
print(row)
出力:
('pos_def',)
('link_def',)
('synset_def',)
('synset_ex',)
('synset',)
('synlink',)
('ancestor',)
('sense',)
('word',)
('variant',)
('xlink',)
出力を確認すると、
'pos_def','link_def','synset_def','synset_ex','synset','synlink','ancestor','sense','word','variant','xlink'
の計11のテーブルが含まれることが分かりました。(思ったより、多い。。)
調べた感じだと、以下の5つを、とりあえず押さえておけば良いようです。
テーブル名 | 内容 |
---|---|
word | 単語と品詞に関する情報。単語と単語IDを紐づけている |
sense | 単語とsynset(概念)に関する情報。単語IDとsynsetのIDを紐づけている |
synset | 概念に関する情報。synsetのIDと概念名称を紐づけている |
synset_def | 概念の定義に関する情報。synsetのIDと概念の定義を紐づけている |
synlink | 2つの概念の関連性の情報。上位・下位、包含・被包含などが定義されている |
以降で簡単に中身を見てみます。
WordNetからデータを抽出する
以下のようにSQL感覚で、データ抽出できます。
# Wordnetデータの内容の確認
cur = conn.execute("select * from word limit 10")
for row in cur:
print(row)
出力:
(1, 'eng', 'expletive', None, 'n')
(2, 'eng', 'measles', None, 'n')
(3, 'eng', 'contras', None, 'n')
(4, 'eng', 'beef_man', None, 'n')
(5, 'eng', 'dwelling', None, 'n')
(6, 'eng', 'acetum', None, 'n')
(7, 'eng', 'mount_carmel', None, 'n')
(8, 'eng', 'class_taxopsida', None, 'n')
(9, 'eng', 'vascular_ray', None, 'n')
(10, 'eng', 'genus_salamandra', None, 'n')
実行結果は、sqlite3内で定義されているオブジェクトで返ってきますが、for文で回せばtupleで要素を取り出すことができます。
ちなみに列名が取得したくなった場合は、以下のようにします。
(このあたりの書き方は、SQLiteとMySQLとかで違う感じです)
# Wordnetデータに含まれるカラムの確認
cur = conn.execute("PRAGMA TABLE_INFO(word)")
for row in cur:
print(row)
出力:
(0, 'wordid', 'integer', 0, None, 1)
(1, 'lang', 'text', 0, None, 0)
(2, 'lemma', 'text', 0, None, 0)
(3, 'pron', 'text', 0, None, 0)
(4, 'pos', 'text', 0, None, 0)
一応データ数のオーダーも確認しておきます。
# Wordnetに登録されているデータ数の確認(wordDB)
cur = conn.execute("select count(*) from word")
for row in cur:
print("Wordnetに登録されているWordDBの単語数:%s" % row[0])
出力:
Wordnetに登録されている単語数:247528
日本語版WordNetについて分かったこと
前述のような感じで、少し触ってみて分かったことをまとめます。
- 基本的に、英語と日本語の単語が混在している(一部英語のみ)
- 標準形を前提として整備されている
- 形態素解析で標準形に変換しておく必要がありそう
- 名詞(n)、動詞(v)、形容詞(a)、副詞(r)の4種類の品詞が対象
- 一部の情報は英語にしか付与されていない(senseテーブルのfreqカラムなど)
どうも本家の英語版のWordNetに日本語の情報を足しているようで、一部の情報は日本語版では不足しているようです。今後活用を検討する上で注意が必要そうです。
とりあえず類義語を検索できるツールを作ってみた
本当は、上位・下位などの関係性を上手く使ってみたかったのですが、まずはシンプルな類義語の検索処理部分をツールにしてみたいと思います。
以下のように類義語検索関数を書きました。
# 特定の単語を入力とした時に、類義語を検索する関数
def SearchSimilarWords(word):
# 問い合わせしたい単語がWordnetに存在するか確認する
cur = conn.execute("select wordid from word where lemma='%s'" % word)
word_id = 99999999 #temp
for row in cur:
word_id = row[0]
# Wordnetに存在する語であるかの判定
if word_id==99999999:
print("「%s」は、Wordnetに存在しない単語です。" % word)
return
else:
print("【「%s」の類似語を出力します】\n" % word)
# 入力された単語を含む概念を検索する
cur = conn.execute("select synset from sense where wordid='%s'" % word_id)
synsets = []
for row in cur:
synsets.append(row[0])
# 概念に含まれる単語を検索して画面出力する
no = 1
for synset in synsets:
cur1 = conn.execute("select name from synset where synset='%s'" % synset)
for row1 in cur1:
print("%sつめの概念 : %s" %(no, row1[0]))
cur2 = conn.execute("select def from synset_def where (synset='%s' and lang='jpn')" % synset)
sub_no = 1
for row2 in cur2:
print("意味%s : %s" %(sub_no, row2[0]))
sub_no += 1
cur3 = conn.execute("select wordid from sense where (synset='%s' and wordid!=%s)" % (synset,word_id))
sub_no = 1
for row3 in cur3:
target_word_id = row3[0]
cur3_1 = conn.execute("select lemma from word where wordid=%s" % target_word_id)
for row3_1 in cur3_1:
print("類義語%s : %s" % (sub_no, row3_1[0]))
sub_no += 1
print("\n")
no += 1
この関数に単語を入力することで、類義語を検索できます。
初めに「ネコ」の類義語を検索してみます。
# 「ネコ」の類義語を検索する
SearchSimilarWords("ネコ")
出力:
【「ネコ」の類似語を出力します】
1つめの概念 : true_cat
意味1 : 通常、厚く柔らかい毛皮を持ち、吠えることのできないネコ科の哺乳類:家ネコ
意味2 : ヤマネコ
類義語1 : true_cat
類義語2 : cat
類義語3 : ねんねこ
類義語4 : にゃんにゃん
類義語5 : 猫
類義語6 : キャット
何となく上手くいってそうです。
「ねんねこ」とか「にゃんにゃん」もWordNetに含まれているのですね。。恐るべし。
別の単語でも確認してみます。
# 「月」の類義語を検索する
SearchSimilarWords("月")
出力:
【「月」の類似語を出力します】
1つめの概念 : moonlight
意味1 : 月の光
類義語1 : moonlight
類義語2 : moon
類義語3 : moonshine
類義語4 : 月灯かり
類義語5 : 月色
類義語6 : 月明り
類義語7 : ムーンライト
類義語8 : 月あかり
類義語9 : 月影
類義語10 : 月桂
類義語11 : 月明
類義語12 : 月光
類義語13 : 月明かり
2つめの概念 : month
意味1 : 暦年を12に分けた中の1つ
類義語1 : month
類義語2 : calendar_month
類義語3 : 暦月
3つめの概念 : month
意味1 : 約30日間という時間単位
類義語1 : month
4つめの概念 : moon
意味1 : 地球の天然衛星
類義語1 : moon
類義語2 : 月代
類義語3 : 御月様
類義語4 : お月さま
類義語5 : 玉兎
類義語6 : ムーン
類義語7 : 玉桂
類義語8 : 月球
類義語9 : 桂月
類義語10 : お月様
類義語11 : 月夜見
類義語12 : 月の輪
類義語13 : 太陰
類義語14 : 月桂
類義語15 : 月読
類義語16 : 月輪
類義語17 : 月読み
一見上手くいってそうですが、「月曜日=monday」の概念がないので、実用上は問題が生じるかもしれません。
まとめと今後
日本語版WordNetは利用は簡単ではあるものの、英語版ではない固有の問題(日本語の構造自体に起因するものも含め)がありそうなことが分かりました。
今後は、上位・下位の概念を用いるなど、WordNetならではの解析に挑戦してみたいです。
次回:
「日本語WordNetを使って、上位語を検索できるツールをpythonで作ってみた」
参考:
[1] [日本語 WordNet]
(http://compling.hss.ntu.edu.sg/wnja/)
[2] [[自然言語] Wordnet × Pythonで類義語を抽出する]
(https://www.yoheim.net/blog.php?q=20160201)
[3] [【API】日本語WordNetの全内容にアクセスできるWebAPIを公開した]
(http://blog.apitore.com/2017/05/17/api-wordnet-detail/)