ナード戦隊データマン

データサイエンスを用いて悪と戦うぞ

wordnetを使った特徴量設計

wordnetとは、概念の関係を表すシソーラス(辞書)です。概念の階層はネットワークとして表せるため、networkxへ読み込むことができます。ここでは、日本語wordnetを使い、ルートノードから指定した日本語の単語までの概念パスを求めます。その概念パスを使った特徴量設計を考えます。

日本語wordnetのダウンロード

#!/bin/bash
mkdir data
pushd data
if [ -f wnjpn.db ]; then
    echo "wnjpn.db exists"
else
    wget http://compling.hss.ntu.edu.sg/wnja/data/1.1/wnjpn.db.gz
    gunzip *.gz
fi
popd

コード

# coding: utf-8
import sqlite3
import networkx as nx
import pickle
import pandas as pd

    
def get_synset_from_lemma(conn, lemma):
    cur = conn.cursor()
    cur.execute("select wordid from word where lemma=?",(lemma, ))
    wordid = cur.fetchone()[0]
    cur.execute("select synset from sense where wordid=?",(wordid,))
    return cur.fetchone()[0]


def calc_synset_path(conn, G, lemma):
    root_node = get_synset_from_lemma(conn, "entity")
    target_node = get_synset_from_lemma(conn, lemma)
    path = nx.shortest_path(G, root_node, target_node)
    out = []
    cur = conn.cursor()
    for node in path:
        cur.execute("select * from synset where synset=?",(node,))
        tmp = cur.fetchone()[2]
        out.append(tmp)
    return out

if __name__ == "__main__":
    import sys
    conn = sqlite3.connect("../data/wnjpn.db")
    cur = conn.cursor()
    cur.execute("select * from synlink")
    links = cur.fetchall()
    links = [(x[0], x[1]) for x in links]

    G = nx.DiGraph()
    G.add_edges_from(links)

    #with open("synlink_nx.pkl", "wb") as f:
    #    pickle.dump(G, f)

    print(calc_synset_path(conn, G, sys.argv[1]))

実行

python wn.py パン

出力

['entity', 'physical_entity', 'matter', 'solid', 'food', 'baked_goods', 'bread']

使いみち

概念パスの深さや、最短パス内の深さnの位置の概念IDを、自然言語処理における特徴量として使えます。概念パスの深さは「概念の抽象性」を表し、概念パス内の深さnの位置の概念IDは、概念の分類を表します。

特に、概念の分類を特徴量にする場合、深さnをどのように指定するかに依存します。深さが浅い場合はより抽象的な分類になり、分類カテゴリーの数が減ります。深さが深い場合は具体性が増しますが、分類カテゴリーが増えてしまい、未知のデータに対して未知のカテゴリーが出てきてしまう可能性が高まります。

ただし、wordnet特徴量は、wordnet内に存在する語にのみ対応できます。

リンク

http://compling.hss.ntu.edu.sg/wnja/