ナード戦隊データマン

機械学習, 自然言語処理, データサイエンスについてのブログ

名詞と形容詞の文内における共起関係

名詞と形容詞の共起関係の抽出は、その名詞の持つ性質についてなにか手がかりが得られるかもしれません。ここでは、名詞と形容詞の共起関係を抽出する単純なスクリプトを作成してみます。

コード

# coding: utf-8
import nltk
import nltk.tokenize as nt
 
 
def tokenize(text):
    ss = nt.sent_tokenize(text)
    tokenized_sent = [nt.word_tokenize(sent) for sent in ss]
    pos_sentences = [nltk.pos_tag(sent) for sent in tokenized_sent]
    return pos_sentences
 
 
def extract_word_by_pos(pos_sentences, pos_list):
    return [[x for x in pos_sentence if x[1] in pos_list]
            for pos_sentence in pos_sentences]
 
 
def get_continuous_chunks(pos_sentences):
    for pos_sentence in pos_sentences:
        tmp_words = []
        all_words = []
        for word, pos in pos_sentence:
            if pos.startswith("NNP"):
                tmp_words.append(word)
            elif tmp_words:
                all_words.append(' '.join(tmp_words))
                tmp_words = []
        if tmp_words:
            all_words.append(' '.join(tmp_words))
        yield all_words
        all_words = []
 
 
def run(debug=False):
    from collections import defaultdict
    import pickle
    from tqdm import tqdm
    out = defaultdict(dict)
 
    # wikipediaをtxt形式へ落とし込んだものを読み込む。
    with open("wiki.txt") as f:
        for i, line in tqdm(enumerate(f)):
            if debug and i > 1000:
                print(out)
                return False
            pos_sentences = tokenize(line)
            adjs_list = extract_word_by_pos(pos_sentences,
                                            pos_list=["JJ", "JJR", "JJS"])
            nouns_list = get_continuous_chunks(pos_sentences)
            for adjs, nouns in zip(adjs_list, nouns_list):
                for noun in nouns:
                    for adj in adjs:
                        adj = adj[0].strip().lower()
                        if len(adj) < 3:
                            continue
                        noun = noun.strip().lower()
                        if adj not in out[noun]:
                            out[noun][adj] = 0
                        out[noun][adj] += 1
 
    with open("noun_adj_wiki.pkl", "wb") as f:
        pickle.dump(out, f, protocol=4)
    return True
 
 
if __name__ == "__main__":
    run(debug=False)

sentiment140の例

wikipediaからの抽出は時間がかかっているので、sentiment140コーパス1で試します。

# coding: utf-8
import pickle
with open("./noun_adj.pkl", "rb") as f:
    data = pickle.load(f)

print(sorted(data["korea"].items(), key=lambda x: x[1], reverse=True)[:15])
print(sorted(data["america"].items(), key=lambda x: x[1], reverse=True)[:15])
print(sorted(data["japan"].items(), key=lambda x: x[1], reverse=True)[:15])
print(sorted(data["china"].items(), key=lambda x: x[1], reverse=True)[:15])

[出力]

[('sad', 3), ('north', 3), ('more', 2), ('wish', 2), ('korean', 2), ('nice', 2), ('update', 2), ('guilty', 2), ('bad', 2), ('first', 1), ('rant', 1), ('impossible', 1), ('scary', 1), ('new', 1), ('bloody', 1)]
[('good', 30), ('great', 11), ('last', 9), ('wish', 9), ('next', 9), ('sad', 7), ('most', 7), ('best', 6), ('top', 5), ('nice', 5), ('ready', 4), ('little', 4), ('wanted', 4), ('first', 4), ('funniest', 3)]
[('last', 15), ('good', 10), ('much', 8), ('few', 7), ('little', 6), ('first', 5), ('wish', 5), ('more', 5), ('next', 4), ('big', 4), ('best', 4), ('japanese', 4), ('great', 4), ('long', 3), ('cheap', 3)]
[('new', 8), ('good', 5), ('happy', 5), ('best', 4), ('next', 4), ('little', 4), ('chinese', 4), ('able', 3), ('more', 3), ('sad', 3), ('better', 3), ('other', 3), ('slow', 3), ('wish', 3), ('mainland', 2)]

koreaに対する形容詞は、北の関係で血生臭くなっていますが、americaやjapan,chinaはそれよりも良い印象があるようです。しかし、データが少ないため、あまり確かなことは言えません。

MeCabとは違って、tokenizeにかなり時間がかかるので、wikipedia全体から抽出するために、3~5日ぐらいはかかってしまうかもしれません。