接着剤の精進日記

競プロでの精進や研究に関係したことを書いていきます。

日本語WordNetで上位語を取得する

はじめに

日本語版WordNetを使って上位語を取得したかったので、やります。

参考記事

以下の記事を参考にしています。
おおよそのプログラムは以下の記事のものを利用させてもらいました。
日本語WordNetを使って、上位語を検索できるツールをpythonで作ってみた - Qiita

WordNetのダウンロード

日本語 Wordnetのページに行き、
「Japanese Wordnet and English WordNet in an sqlite3 database」をダウンロードします。
適当なディレクトリを作り、そこにダウンロードしたものを解凍しましょう。
自分はjwordnetというディレクトリ名にしました。
解答するとwnjpn.dbというファイルができます。

上位語の取得

参考記事では最上位のものしか取得していなかったので、
ある概念の上位語をすべて取得するようにしました。
以下のプログラムでは、猫という単語の上位語をすべて取得しています。

import sqlite3
import sys
conn = sqlite3.connect("wnjpn.db")

# 上位-下位の関係にある概念の抽出
hierarchy_dict = {}  # key:上位語(String), value:下位語(List of String)
n_term_set = set()  # 下位語に含まれる単語集合

class node:
    def __init__(self, name, children=None):
        self.name = name  # String
        self.children = children  # List of Class node

    # 結果表示用
    def display(self, indent = 0):
        if self.children != None:
            print(' '*indent + self.name)
            for c in self.children:
                c.display(indent+1)
        else:
            print(' '*indent + self.name)

# 特定の単語を入力とした時に、上位語をすべて検索する関数
def SearchUpperConceptWords(word, hierarchy_dict):

    # 問い合わせしたい単語が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])

    for synset in synsets:
        #上位語を取得する対象のsynsetを表示
        print('------------------%s---------------------'% synset_name_dict[synset])
        #現在のsynsetの上位語をすべて取得するため,tmp_synsetに代入
        tmp_synset=synset
        #synsetの上位語を最上位まで列挙する
        while(tmp_synset in hierarchy_dict.values()):
            #エラーが発生=最上位語を取得したら終了
            try:
                print(synset_name_dict[hierarchy_dict[tmp_synset]])
                tmp_synset = hierarchy_dict[tmp_synset]
            except:
                break

# 下位-上位の関係にある概念の抽出
cur = conn.execute("select synset1,synset2 from synlink where link='hypo'")

hierarchy_dict = {}  # key:下位語(String), value:上位語(String)

for row in cur:
    b_term = row[0]
    n_term = row[1]

    if n_term not in hierarchy_dict:
        hierarchy_dict[n_term] = b_term

# synset(概念)のIDから、概念の名称に変換する辞書の作成
synset_name_dict = {}  # key:synsetのID, value:synsetの名称
cur = conn.execute("select synset,name from synset")
for row in cur:
    synset_name_dict[row[0]] = row[1]

#猫という単語の上位語をすべて取得する
SearchUpperConceptWords("猫", hierarchy_dict)

結果は次のようになります。
f:id:tkm-kyudo:20190425113911p:plain

猫の上位語がfeline(ネコ科)、その上位語がcarnivore(有胎盤)、・・・のように取得した結果を表示しています。
SearchUpperConceptWords("猫", hierarchy_dict)の猫の部分を書き換えれば任意のものの上位語を取得できます。

おわりに

今回は日本語WordNetを使って、ある単語の上位語をすべて取得しました。
上位語を日本語で表示させるやり方は残念ながらわかりませんでしたが、WordNetのデーターベースに存在すれば上手く取って来ることは可能だと思います。気が向いたらやるかもしれないです。
今回のプログラムはgithubにも公開しています。
GitHub - EmulsionBondo/jwordnet: 日本語WordNetで上位語を取得する