日本語WordNetを使用して、類義語を検索してリスト化するためのコードを作成しました。
そもそもWordNetとは
下記の記事を参考にしましょう。
日本語WordNetを知る
日本語WordNetを使って、類義語を検索できるツールをpythonで作ってみた
※2つ目のリンク記事はコード作成時にも参考にさせて頂きました
早速コード
環境:Google Colaboratory
日本語WordNetのHPからダウンロードした「wnjpn.db」をsqliteで加工/抽出して、pandasのDataFrameに格納、作成したDataFrameから類似語を検索する、という流れとなります。
import gzip
import shutil
import sqlite3
import pandas as pd
# 日本語wordnetをDLして解凍
! wget "http://compling.hss.ntu.edu.sg/wnja/data/1.1/wnjpn.db.gz" # 1~2分
with gzip.open('wnjpn.db.gz', 'rb') as f_in:
with open('wnjpn.db', 'wb') as f_out:
shutil.copyfileobj(f_in, f_out)
# synset(概念ID)とlemma(単語)の組み合わせDataFrameの作成
conn = sqlite3.connect("wnjpn.db")
q = 'SELECT synset,lemma FROM sense,word USING (wordid) WHERE sense.lang="jpn"'
sense_word = pd.read_sql(q, conn)
# 類義語をリストにして返す関数を定義
def get_synonyms(word):
"""inputしたwordの類義語をリストにして返す。
Args:
word(str): 類義語を検索する単語
Returns:
list[str]: 類義語リスト
"""
# 類義語を検索する単語のsynsetを検索する
synsets = sense_word.loc[sense_word.lemma == word, "synset"]
# そのsynsetに紐づく全ての単語を取得(重複する可能性があるのでsetにする)
synset_words = set(sense_word.loc[sense_word.synset.isin(synsets), "lemma"])
# 元の単語が入ってしまうので削除
if word in synset_words:
synset_words.remove(word)
return list(synset_words)
# 使用例
get_synonyms("単語")
# >> ['辞', 'ワード', '言葉', '語']
# WordNetにない単語を指定した場合は空リスト
get_synonyms("超単語")
# >> []
補足
ここの部分が分かりづらいと思うので少し補足です。
# synset(概念ID)とlemma(単語)の組み合わせDataFrameの作成
conn = sqlite3.connect("wnjpn.db")
q = 'SELECT synset,lemma FROM sense,word USING (wordid) WHERE sense.lang="jpn"'
sense_word = pd.read_sql(q, conn)
ここではsqliteで「wnjpn.db」に含まれる「sense」テーブル、「word」テーブルを結合するクエリを発行し、synset(概念ID)とlemma(単語)の全ての組み合わせが含まれるテーブルが作成しています。ここでsynsetとは単語の概念(をID化したもの)で、synset(概念)が同じ単語同士は類義語となります。
作成されるテーブルは下記のような形となり、同じsynset「00001740-v」である「息吹く」「息衝く」「吐く」「呼吸」「息づく」は類義語となります。
synset | lemma | |
---|---|---|
1 | 00001740-n | 実体 |
2 | 00001740-r | アカペラで |
3 | 00001740-v | 息吹く |
4 | 00001740-v | 息衝く |
5 | 00001740-v | 吐く |
6 | 00001740-v | 呼吸 |
7 | 00001740-v | 息づく |
結合に使用するテーブルの中身
「sense」テーブル、「word」テーブルがどうなっているのかを知らないとイメージが付きにくいと思うので、それぞれの中身もざっくりご紹介します。詳しく知りたい人は、一番最初に貼ったリンク記事を読みましょう。
sense
synset(概念ID)に含まれるwordid(単語ID)が分かるテーブルです。
synsetとwordidの組み合わせでユニークとなっています。また、今回のクエリでも使用していますが、lang列で単語が日本語(jpn)か英語(eng)を判別することができます。
synset | wordid | lang | rank | lexid | freq | src | |
---|---|---|---|---|---|---|---|
0 | 02130160-v | 155287 | eng | 0 | 1 | 1 | eng-30 |
1 | 00001740-v | 186954 | jpn | nan | nan | nan | hand |
2 | 00001740-v | 216393 | jpn | nan | nan | nan | hand |
word
wordid(単語ID)とlemma(単語)の対応表です。
wordidでユニークとなっています。今回はsenseのwordidを単語に変換するために使用しています。lang列はsenseと同様です。
wordid | lang | lemma | pron | pos | |
---|---|---|---|---|---|
0 | 155287 | eng | lay_eyes_on | v | |
1 | 186954 | jpn | 呼吸 | v | |
2 | 216393 | jpn | 息づく | v |
以上となります。
間違っているところがありましたらご指摘いただけますと幸いです。