ノート/テキストマイニング
1818   2017-07-21 (金) 17:23:02

Python/NLTKからWordNet 3.0を使ってみる

nltk (Natural Language Took Kit)を使う。日本語対応のためには新しいバージョンが必要。

 ≫ ノート/テキストマイニング/NLTK

実際に使っている様子は、HowToの中にあるサンプルを見るとよい。

>>> from nltk.corpus import wordnet as wn
>>> wn.synsets('dog')

NLTK/corpus/wordnet.pyの中に含まれているデモプログラムを抜き出して、単独で走るようにimportなどを追加したもの。

細かい説明は 『入門 自然言語処理』2章 テキストコーパスと語彙資源へのアクセス (3)

######################################################################
# Demo
######################################################################
from nltk.corpus import wordnet
from nltk.corpus.reader import WordNetCorpusReader, WordNetICCorpusReader

def demo():
    import nltk
    print('loading wordnet')
    wn = WordNetCorpusReader(nltk.data.find('corpora/wordnet'), None)
    print('done loading')
    S = wn.synset
    L = wn.lemma

    print('getting a synset for go')
    move_synset = S('go.v.21')
    print(move_synset.name(), move_synset.pos(), move_synset.lexname())
    print(move_synset.lemma_names())
    print(move_synset.definition())
    print(move_synset.examples())

    zap_n = ['zap.n.01']
    zap_v = ['zap.v.01', 'zap.v.02', 'nuke.v.01', 'microwave.v.01']

    def _get_synsets(synset_strings):
        return [S(synset) for synset in synset_strings]

    zap_n_synsets = _get_synsets(zap_n)
    zap_v_synsets = _get_synsets(zap_v)

    print(zap_n_synsets)
    print(zap_v_synsets)

    print("Navigations:")
    print(S('travel.v.01').hypernyms())
    print(S('travel.v.02').hypernyms())
    print(S('travel.v.03').hypernyms())

    print(L('zap.v.03.nuke').derivationally_related_forms())
    print(L('zap.v.03.atomize').derivationally_related_forms())
    print(L('zap.v.03.atomise').derivationally_related_forms())
    print(L('zap.v.03.zap').derivationally_related_forms())

    print(S('dog.n.01').member_holonyms())
    print(S('dog.n.01').part_meronyms())

    print(S('breakfast.n.1').hypernyms())
    print(S('meal.n.1').hyponyms())
    print(S('Austen.n.1').instance_hypernyms())
    print(S('composer.n.1').instance_hyponyms())

    print(S('faculty.n.2').member_meronyms())
    print(S('copilot.n.1').member_holonyms())

    print(S('table.n.2').part_meronyms())
    print(S('course.n.7').part_holonyms())

    print(S('water.n.1').substance_meronyms())
    print(S('gin.n.1').substance_holonyms())

    # 以下3行は、エラーが出る
    # print(L('leader.n.1.leader'))  # Have some error possibly in data?
    # print(L('leader.n.1.leader').antonyms())
    # print(L('increase.v.1.increase').antonyms())

    print(S('snore.v.1').entailments())
    print(S('heavy.a.1').similar_tos())
    print(S('light.a.1').attributes())
    print(S('heavy.a.1').attributes())

    # print(L('English.a.1.English').pertainyms())   # Same error as above

    print(S('person.n.01').root_hypernyms())
    print(S('sail.v.01').root_hypernyms())
    print(S('fall.v.12').root_hypernyms())

    print(S('person.n.01').lowest_common_hypernyms(S('dog.n.01')))
    print(S('woman.n.01').lowest_common_hypernyms(S('girlfriend.n.02')))

    print(S('dog.n.01').path_similarity(S('cat.n.01')))
    print(S('dog.n.01').lch_similarity(S('cat.n.01')))
    print(S('dog.n.01').wup_similarity(S('cat.n.01')))

    wnic = WordNetICCorpusReader(nltk.data.find('corpora/wordnet_ic'),
                                 '.*\.dat')
    ic = wnic.ic('ic-brown.dat')
    print(S('dog.n.01').jcn_similarity(S('cat.n.01'), ic))

    ic = wnic.ic('ic-semcor.dat')
    print(S('dog.n.01').lin_similarity(S('cat.n.01'), ic))

    print(S('code.n.03').topic_domains())
    print(S('pukka.a.01').region_domains())
    print(S('freaky.a.01').usage_domains())

if __name__ == '__main__':
    demo()

実行結果は、

loading wordnet
done loading
getting a synset for go
move.v.15 v verb.competition
['move', 'go']
have a turn; make one's move in a game
['Can I go now?']
[Synset('zap.n.01')]
[Synset('zap.v.01'), Synset('zap.v.02'), Synset('nuke.v.01'), Synset('microwave.v.01')]
Navigations:
[]
[Synset('travel.v.03')]
[]
[Lemma('atomic_warhead.n.01.nuke')]
[Lemma('atomization.n.02.atomization')]
[Lemma('atomization.n.02.atomisation')]
[]
[Synset('canis.n.01'), Synset('pack.n.06')]
[Synset('flag.n.07')]
[Synset('meal.n.01')]
[Synset('banquet.n.02'), Synset('bite.n.04'), Synset('breakfast.n.01'), 
Synset('brunch.n.01'), Synset('buffet.n.02'), Synset('dinner.n.01'), Synset('lunch.n.01'), 
Synset('mess.n.04'), Synset('nosh-up.n.01'), Synset('picnic.n.03'), 
Synset('ploughman's_lunch.n.01'), Synset('potluck.n.01'), Synset('refection.n.01'), 
Synset('square_meal.n.01'), Synset('supper.n.01'), Synset('tea.n.02')]
[Synset('writer.n.01')]
[Synset('ambrose.n.01'), Synset('bach.n.01'), Synset('barber.n.01'), 
Synset('bartok.n.01'), Synset('beethoven.n.01'), Synset('bellini.n.01'), 
Synset('berg.n.02'), Synset('berlioz.n.01'), Synset('bernstein.n.01'), 
Synset('bizet.n.01'), Synset('blitzstein.n.01'), Synset('bloch.n.01'), 
Synset('borodin.n.01'), Synset('boulez.n.01'), Synset('brahms.n.01'), 
Synset('britten.n.01'), Synset('bruch.n.01'), Synset('bruckner.n.01'), 
Synset('byrd.n.01'), Synset('cage.n.03'), Synset('chavez.n.01'), 
Synset('cherubini.n.01'), Synset('chopin.n.03'), Synset('copland.n.01'), 
Synset('corelli.n.01'), Synset('couperin.n.01'), Synset('coward.n.02'), 
Synset('czerny.n.01'), Synset('debussy.n.01'), Synset('delibes.n.01'), 
Synset('delius.n.01'), Synset('donizetti.n.01'), Synset('dowland.n.01'), 
Synset('dukas.n.01'), Synset('dvorak.n.01'), Synset('elgar.n.01'), Synset('enesco.n.01'), 
Synset('falla.n.01'), Synset('franck.n.01'), Synset('gershwin.n.02'), 
Synset('glinka.n.01'), Synset('gluck.n.01'), Synset('gounod.n.01'), 
Synset('grainger.n.01'), Synset('grieg.n.01'), Synset('halevy.n.01'), 
Synset('handel.n.01'), Synset('handy.n.01'), Synset('haydn.n.01'), 
Synset('hindemith.n.01'), Synset('honegger.n.01'), Synset('humperdinck.n.01'), 
Synset('ibert.n.01'), Synset('ives.n.01'), Synset('joachim.n.01'), Synset('joplin.n.02'), 
Synset('kachaturian.n.01'), Synset('kern.n.01'), Synset('khachaturian.n.01'), 
Synset('lambert.n.02'), Synset('lasso.n.01'), Synset('ledbetter.n.01'), 
Synset('lehar.n.01'), Synset('liszt.n.01'), Synset('lloyd_webber.n.01'), 
Synset('loewe.n.01'), Synset('lully.n.02'), Synset('macdowell.n.01'), 
Synset('mahler.n.01'), Synset('massenet.n.01'), Synset('mendelssohn.n.01'), 
Synset('menotti.n.01'), Synset('meyerbeer.n.01'), Synset('milhaud.n.01'), 
Synset('monteverdi.n.01'), Synset('moore.n.01'), Synset('mozart.n.01'), 
Synset('mussorgsky.n.01'), Synset('nielsen.n.01'), Synset('offenbach.n.01'), 
Synset('orbison.n.01'), Synset('palestrina.n.01'), Synset('piston.n.01'), 
Synset('porter.n.04'), Synset('poulenc.n.01'), Synset('prokofiev.n.01'), 
Synset('puccini.n.01'), Synset('purcell.n.01'), Synset('rachmaninoff.n.01'), 
Synset('rameau.n.01'), Synset('ravel.n.01'), Synset('reich.n.03'), 
Synset('respighi.n.01'), Synset('rimsky-korsakov.n.01'), Synset('rodgers.n.01'), 
Synset('romberg.n.01'), Synset('rossini.n.01'), Synset('rubinstein.n.02'), Synset('saint-saens.n.01'),
Synset('satie.n.01'), Synset('schnabel.n.01'), Synset('schonberg.n.01'), 
Synset('schubert.n.01'), Synset('schumann.n.01'), Synset('schumann.n.02'), 
Synset('scriabin.n.01'), Synset('segovia.n.01'), Synset('sessions.n.01'), 
Synset('shostakovich.n.01'), Synset('sibelius.n.01'), Synset('smetana.n.01'), 
Synset('sondheim.n.01'), Synset('sousa.n.01'), Synset('strauss.n.01'), 
Synset('strauss.n.02'), Synset('strauss.n.03'), Synset('stravinsky.n.01'), 
Synset('sullivan.n.05'), Synset('tallis.n.01'), Synset('taylor.n.01'), 
Synset('tchaikovsky.n.01'), Synset('telemann.n.01'), Synset('thomson.n.01'), 
Synset('varese.n.01'), Synset('vaughan_williams.n.01'), Synset('verdi.n.01'), 
Synset('villa-lobos.n.01'), Synset('vivaldi.n.01'), Synset('wagner.n.02'), 
Synset('walton.n.01'), Synset('weber.n.05'), Synset('weill.n.01'), Synset('wolf.n.02')]
[Synset('professor.n.01')]
[Synset('crew.n.01')]
[Synset('leg.n.03'), Synset('tabletop.n.01'), Synset('tableware.n.01')]
[Synset('meal.n.01')]
[Synset('hydrogen.n.01'), Synset('oxygen.n.01')]
[Synset('gin_and_it.n.01'), Synset('gin_and_tonic.n.01'), Synset('martini.n.01'), Synset('pink_lady.n.01')]
[Synset('sleep.v.01')]
[Synset('dense.s.03'), Synset('doughy.s.01'), Synset('heavier-than-air.s.01'), Synset('hefty.s.02'), Synset('massive.s.04'), Synset('non-buoyant.s.01'), 
Synset('ponderous.s.02')]
[Synset('weight.n.01')]
[Synset('weight.n.01')]
[Synset('entity.n.01')]
[Synset('travel.v.01')]
[Synset('act.v.01'), Synset('fall.v.17')]
[Synset('organism.n.01')]
[Synset('woman.n.01')]
0.2
2.0281482472922856
0.8571428571428571
0.4497755285516739
0.8863288628086228
[Synset('computer_science.n.01')]
[Synset('india.n.01')]
[Synset('slang.n.02')]

日本語の対応について

いろいろとあったが、新しい目のバージョンのNLTKでは多言語サポートが入っている。

参照ページはBond先生らの Open Multilingual Wordnet で、日本語WordNetの研究の延長で多言語(からのリンク)にしたものらしい。

このページに記述されているようなデータやインターフェースは、NLTK(少なくとも3.2.4には)に入っているようだ。

使い方は、

>>> from nltk.corpus import wordnet as wn
>>> wn.synsets('鯨', lang='jpn')
[Synset('whale.n.02')]
>>> wn.synset('spy.n.01').lemma_names('jpn')
['いぬ', 'スパイ', '回者', '回し者', '密偵', '工作員', '廻者', '廻し者', '探', '探り', '犬', '秘密捜査員',
'まわし者', '諜報員', '諜者', '間者', '間諜', '隠密']

というところ。

使い方の説明は NLTKのHOWTOsの wordnet HOWTO に例が出ている。曰く

The WordNet corpus reader gives access to the Open Multilingual WordNet, using ISO-639 language codes.

>>> sorted(wn.langs())
['als', 'arb', 'cat', 'cmn', 'dan', 'eng', 'eus', 'fas', 'fin', 'fra', 'fre', 'glg', 'heb', 'ind', 'ita', 'jpn', 'nno',
'nob', 'pol', 'por', 'spa', 'tha', 'zsm']
>>> wn.synsets(b'\xe7\x8a\xac'.decode('utf-8'), lang='jpn')
[Synset('dog.n.01'), Synset('spy.n.01')]
(以下略)

日本語WordNetを使ってみた例

>>> wp.synsets('リンゴ', lang='jpn')
[Synset('apple.n.01'), Synset('apple.n.02')]
>>> wp.synset('リンゴ', lang='jpn')     <-- synsetSではなくsynsetの場合はダメ
TypeError: synset() got an unexpected keyword argument 'lang'
>>> wp.synsets('りんご', lang='jpn') 
[]                                                     <-- ひらがなの'りんご'では登録されていない
>>> wn.synsets('ミカン', lang='jpn')[0]
Synset('orange.n.01')                    <-- 'ミカン'は1つだけ
>>> wn.synsets('リンゴ', lang='jpn')[0].path_similarity(wn.synsets('ミカン', lang='jpn')[0])
0.25                    <-- 経路距離メソッド path_simlarityを使ってみる。どちらも[0]の単一要素にして問うた
>>> wn.synsets('リンゴ', lang='jpn')[1].path_similarity(wn.synsets('ミカン', lang='jpn')[0])
0.05263157894736842          <-- 'リンゴ'の2要素目を試してみた

>>> orange = wn.synsets('ミカン', lang='jpn')[0]
>>> orange.hypernyms()      <--  [Synset('citrus.n.01')]
>>> orange.hyponyms()
[Synset('bitter_orange.n.02'), Synset('sweet_orange.n.01'), Synset('temple_orange.n.02')]
>>> orange.member_holonyms()
[]
>>> orange.root_hypernyms()    <--  [Synset('entity.n.01')]
>>> apple = wn.synsets('リンゴ', lang='jpn')[0]
>>> orange.lowest_common_hypernyms(apple)   <-- [Synset('edible_fruit.n.01')]
>>> wn.synset('orange.n.01').lowest_common_hypernyms(wn.synset('apple.n.01'))
[Synset('edible_fruit.n.01')]
>>> wn.lemmas('dog', lang='jpn')
[]
>>> wn.lemmas('犬', lang='jpn')
[Lemma('dog.n.01.犬'), Lemma('spy.n.01.犬')]
>>> wn.synset('dog.n.01').lemmas('jpn')
[Lemma('dog.n.01.イヌ'), Lemma('dog.n.01.ドッグ'), Lemma('dog.n.01.洋犬'), 
Lemma('dog.n.01.犬'), Lemma('dog.n.01.飼犬'), Lemma('dog.n.01.飼い犬')]
>>> [u.lemma_names('jpn') for u in list(wn.synsets('犬', lang='jpn'))]
[['イヌ', 'ドッグ', '洋犬', '犬', '飼犬', '飼い犬'], 
 ['いぬ', 'スパイ', '回者', '回し者', '密偵', '工作員', '廻者', '廻し者', '探', '探り', '犬',
  '秘密捜査員', 'まわし者', '諜報員', '諜者', '間者', '間諜', '隠密']]

裏は、corpus reader

class nltk.corpus.reader.wordnet.WordNetCorpusReader(root, omw_reader)

のところに、omw_reader (omw=open multilingual wordnet) が追加されていること。 (これが新し目のバージョンが必要な理由)

「歴史的には」もともとBond先生らを中心にした研究の成果として日本語WordNet として公開されていたものがあり、 ダウンロードページも整備されていた。

また、本 Steven Bird, Ewan Klein, Edward Loper: Natural Language Processing with Python の翻訳「入門 自然言語処理」(2010年)に当たって、訳者の萩原正人氏らが第12章「Python による日本語自然言語処理」を追加した(この章はWebでも公開されている。Python による日本語自然言語処理)が、その中で日本語WordNetの使い方を取り上げている。この時はNLTKのWordNetリーダーの外側に自前のリーダーを作っていた(Example II.1 (12_1_5_jpwordnet.py))ため、それなりの手順が必要であった。 (ちなみに、このコードは、NLTKのWordNetCorpusReaderの__init__に(このomw対応の改変のために)パラメタ(まさにomw_reader)が追加されたため、そのままでは動かないようだ。) その後、NLTK側にインターフェースを追加したようで、現在の簡単な形になっているようだ。


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2017-07-21 (金) 17:23:02 (149d)