hatunina’s blog

メモと日記です

NLTKでIOBタグ付けと頻出単語描画とストップワード除去とシノニムを探す

色々試しました。

Tokenize ~ Pos tagging ~ chunking ~ IOB tagging

いじくる文章はiPhonewikiを使います。

import nltk

sent = """iPhone is a line of smartphones designed and marketed by Apple Inc. 
The iPhone line of products use Apple's iOS mobile operating system software. 
The first-generation iPhone was released on June 29, 2007, 
and multiple new hardware iterations with new iOS releases have been released since."""


まず、Tokenizeはこう

tokens= nltk.word_tokenize(sent)
print(tokens)


実行結果

['iPhone', 'is', 'a', 'line', 'of', 'smartphones', 'designed', 'and', 'marketed', 'by', 'Apple', 'Inc', '.', 'The', 'iPhone', 'line', 'of', 'products', 'use', 'Apple', "'s", 'iOS', 'mobile', 'operating', 'system', 'software', '.', 'The', 'first-generation', 'iPhone', 'was', 'released', 'on', 'June', '29', ',', '2007', ',', 'and', 'multiple', 'new', 'hardware', 'iterations', 'with', 'new', 'iOS', 'releases', 'have', 'been', 'released', 'since', '.']


単語で分けるだけですね。英語なのでわかりやすくて良い。
次は品詞タグ付けです。

pos_tags = nltk.pos_tag(tokens)
print(pos_tags)


実行結果

[('iPhone', 'NN'), ('is', 'VBZ'), ('a', 'DT'), ('line', 'NN'), ('of', 'IN'), ('smartphones', 'NNS'), ('designed', 'VBN'), ('and', 'CC'), ('marketed', 'VBN'), ('by', 'IN'), ('Apple', 'NNP'), ('Inc', 'NNP'), ('.', '.'), ('The', 'DT'), ('iPhone', 'JJ'), ('line', 'NN'), ('of', 'IN'), ('products', 'NNS'), ('use', 'VBP'), ('Apple', 'NNP'), ("'s", 'POS'), ('iOS', 'NN'), ('mobile', 'NN'), ('operating', 'VBG'), ('system', 'NN'), ('software', 'NN'), ('.', '.'), ('The', 'DT'), ('first-generation', 'NN'), ('iPhone', 'NN'), ('was', 'VBD'), ('released', 'VBN'), ('on', 'IN'), ('June', 'NNP'), ('29', 'CD'), (',', ','), ('2007', 'CD'), (',', ','), ('and', 'CC'), ('multiple', 'JJ'), ('new', 'JJ'), ('hardware', 'NN'), ('iterations', 'NNS'), ('with', 'IN'), ('new', 'JJ'), ('iOS', 'NN'), ('releases', 'NNS'), ('have', 'VBP'), ('been', 'VBN'), ('released', 'VBN'), ('since', 'IN'), ('.', '.')]


はい。
そしてチャンキング

tree = nltk.ne_chunk(pos_tags)
print(tree)


実行結果

(S
  (GPE iPhone/NN)
  is/VBZ
  a/DT
  line/NN
  of/IN
  smartphones/NNS
  designed/VBN
  and/CC
  marketed/VBN
  by/IN
  (PERSON Apple/NNP Inc/NNP)
  ./.
  The/DT
・
・
・


ちょっとこれよくわからず。。

なんだろ。treeって描画用?

まあ、気にせずIOBタグ付けはこう

iob = nltk.tree2conlltags(tree)
print(iob)


実行結果

[('iPhone', 'NN', 'B-GPE'), ('is', 'VBZ', 'O'), ('a', 'DT', 'O'), ('line', 'NN', 'O'), ('of', 'IN', 'O'), ('smartphones', 'NNS', 'O'), ('designed', 'VBN', 'O'), ('and', 'CC', 'O'), ('marketed', 'VBN', 'O'), ('by', 'IN', 'O'), ('Apple', 'NNP', 'B-PERSON'), ('Inc', 'NNP', 'I-PERSON'), ('.', '.', 'O'), ('The', 'DT', 'O'), ('iPhone', 'JJ', 'B-ORGANIZATION'), ('line', 'NN', 'O'), ('of', 'IN', 'O'), ('products', 'NNS', 'O'), ('use', 'VBP', 'O'), ('Apple', 'NNP', 'B-PERSON'), ("'s", 'POS', 'O'), ('iOS', 'NN', 'B-ORGANIZATION'), ('mobile', 'NN', 'O'), ('operating', 'VBG', 'O'), ('system', 'NN', 'O'), ('software', 'NN', 'O'), ('.', '.', 'O'), ('The', 'DT', 'O'), ('first-generation', 'NN', 'O'), ('iPhone', 'NN', 'B-ORGANIZATION'), ('was', 'VBD', 'O'), ('released', 'VBN', 'O'), ('on', 'IN', 'O'), ('June', 'NNP', 'O'), ('29', 'CD', 'O'), (',', ',', 'O'), ('2007', 'CD', 'O'), (',', ',', 'O'), ('and', 'CC', 'O'), ('multiple', 'JJ', 'O'), ('new', 'JJ', 'O'), ('hardware', 'NN', 'O'), ('iterations', 'NNS', 'O'), ('with', 'IN', 'O'), ('new', 'JJ', 'O'), ('iOS', 'NN', 'B-ORGANIZATION'), ('releases', 'NNS', 'O'), ('have', 'VBP', 'O'), ('been', 'VBN', 'O'), ('released', 'VBN', 'O'), ('since', 'IN', 'O'), ('.', '.', 'O')]


めっちゃ簡単やんけ〜
英語ずるくない?
チャンキングとIOBタグ付けこれだけでできるのってすごくないですか?
日本語だったら品詞タグ付けまではMeCabでやって、チャンキングとかIOBタグ付け、、、どうすんの?目視?

頻出単語描画

他にも便利な関数がたくさんあったのでついでに試します。
文章は引き続き同じものを使います。
FreqDistという関数を使うと計算できるっぽい。

freq = nltk.FreqDist(tokens)
print(freq.items())


実行結果

dict_items([('first-generation', 1), ('software', 1), ('June', 1), ('have', 1), ('been', 1), ('and', 2), ('is', 1), ('mobile', 1), ("'s", 1), ('new', 2), ('iPhone', 3), ('The', 2), ('.', 3), ('Apple', 2), ('released', 2), ('multiple', 1), ('marketed', 1), (',', 2), ('operating', 1), ('2007', 1), ('use', 1), ('29', 1), ('designed', 1), ('system', 1), ('iOS', 2), ('a', 1), ('line', 2), ('iterations', 1), ('was', 1), ('Inc', 1), ('on', 1), ('of', 2), ('products', 1), ('releases', 1), ('since', 1), ('hardware', 1), ('smartphones', 1), ('by', 1), ('with', 1)])


数字部分は各単語の登場回数です。
これをグラフで描画することができます。

freq.plot(20, cumulative=False)


実行結果

f:id:hatunina:20180414222329p:plain
便利〜、何かに使えそう〜

ストップワードでクリーニング

上のグラフを見ると真ん中ぐらいに「of」があります。
こういう文章によく登場するけどあんま意味ない、みたいなやつは除去してあげる必要があります。
nltkには各言語のストップワードが用意されています。

from nltk.corpus import stopwords
stopwords = stopwords.words('english')

print(len(stopwords))
print(stopwords)


実行結果

179
['i', 'me', 'my', 'myself', 'we', 'our', 'ours', 'ourselves', 'you', "you're", "you've", "you'll", "you'd", 'your', 'yours', 'yourself', 'yourselves', 'he', 'him', 'his', 'himself', 'she', "she's", 'her', 'hers', 'herself', 'it', "it's", 'its', 'itself', 'they', 'them', 'their', 'theirs', 'themselves', 'what', 'which', 'who', 'whom', 'this', 'that', "that'll", 'these', 'those', 'am', 'is', 'are', 'was', 'were', 'be', 'been', 'being', 'have', 'has', 'had', 'having', 'do', 'does', 'did', 'doing', 'a', 'an', 'the', 'and', 'but', 'if', 'or', 'because', 'as', 'until', 'while', 'of', 'at', 'by', 'for', 'with', 'about', 'against', 'between', 'into', 'through', 'during', 'before', 'after', 'above', 'below', 'to', 'from', 'up', 'down', 'in', 'out', 'on', 'off', 'over', 'under', 'again', 'further', 'then', 'once', 'here', 'there', 'when', 'where', 'why', 'how', 'all', 'any', 'both', 'each', 'few', 'more', 'most', 'other', 'some', 'such', 'no', 'nor', 'not', 'only', 'own', 'same', 'so', 'than', 'too', 'very', 's', 't', 'can', 'will', 'just', 'don', "don't", 'should', "should've", 'now', 'd', 'll', 'm', 'o', 're', 've', 'y', 'ain', 'aren', "aren't", 'couldn', "couldn't", 'didn', "didn't", 'doesn', "doesn't", 'hadn', "hadn't", 'hasn', "hasn't", 'haven', "haven't", 'isn', "isn't", 'ma', 'mightn', "mightn't", 'mustn', "mustn't", 'needn', "needn't", 'shan', "shan't", 'shouldn', "shouldn't", 'wasn', "wasn't", 'weren', "weren't", 'won', "won't", 'wouldn', "wouldn't"]


そして、これらを元の文章から取り除き、もう一度頻出単語をチェックしてみます。

clean_tokens = tokens[:]
 
for token in tokens:
    if token in stopwords:
        clean_tokens.remove(token)

clean_freq = nltk.FreqDist(clean_tokens)
clean_freq.plot(20, cumulative=False)


f:id:hatunina:20180414223303p:plain
真ん中ぐらいにあった「of」が無くなってますね。

シノニムを探す

シノニム(類義語)も辞書が用意されているらしい。

from nltk.corpus import wordnet
 
syn = wordnet.synsets('Japan')

print(syn[0].definition())
print(syn[0].examples())


実行結果

a string of more than 3,000 islands to the east of Asia extending 1,300 miles between the Sea of Japan and the western Pacific Ocean
[]


wordnet.synsets('Japan')でシノニムを探す単語を指定します。
そして、syn[0].definition()とするとwordnetに登録されている定義を取得できます。
上ではJapanの定義を取得してますが、島3,000もないでしょ、おかしくね?って思ってググったら、

海上保安庁は、1987年(昭和62年)に『海上保安の現況』において日本を構成する島の数を「6,852」としている。

日本の島の一覧 - Wikipedia

めっちゃあるやん、島


で、シノニムはこう

for syn in wordnet.synsets('Japan'): 
    for lemma in syn.lemmas(): 
        print(lemma.name())


実行結果

Japan
Japanese_Islands
Japanese_Archipelago
Japan
Nippon
Nihon
japan
japan
japan


ちゃんと「Nihon」とかもあるのがいいすね。

参考

参考はこの辺です。

Natural Language Toolkit — NLTK 3.2.5 documentation

便利機能系はこちらです。

likegeeks.com

他にも対義語を探すこと等もできるみたいです。