アイソモカ

知の遊牧民の開発記録

開発記録 200227 Thu (100本ノック #071, ストップワード)

今回はストップワードかどうかを判定するコードを書きました。さらに、実際どのような単語が多く出現しているのかも見てみました。

言語処理100本ノック #071

71. ストップワード

英語のストップワードのリスト(ストップリスト)を適当に作成せよ.さらに,引数に与えられた単語(文字列)がストップリストに含まれている場合は真,それ以外は偽を返す関数を実装せよ.さらに,その関数に対するテストを記述せよ.

単語の数が多いほど時間がかかるので、今回なら肯定的な文にも否定的な文にも共通して現れるような単語は除いたほうが効率的に分析ができる。このように省く単語を「ストップワード」という。

準備

適当に作成するのもなんかアレかなと思って、既存のやつを利用することにした。 参考 👉 NLTK’s list of english stopwords · GitHub

NLTK (Natural Language Toolkit) をインストール

$ pip install nltk
        ...
Successfully installed nltk-3.4.5

ストップワードを使うためには、最初だけダウンロードする必要がある。

>>> import nltk
>>> nltk.download('stopwords')
[nltk_data] Downloading package stopwords to /Users/🕶/nltk_data...
[nltk_data]   Unzipping corpora/stopwords.zip.
True

あとはインポートして、english を指定。

>>> from nltk.corpus import stopwords
>>> stopwords.words(‘english’)
[‘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”]

ストップワードのリストが手に入った。

解答

# knock_071.py
import sys
import nltk
# nltk.download('stopwords')
from nltk.corpus import stopwords

def stop_evaluator(word):
    if word in stopwords.words('english'):
        return True
    else:
        return False

def show_stopwords():
    print(stopwords.words('english'))

if __name__ == '__main__':
    if len(sys.argv) < 2:
        show_stopwords()
    else:
        for w in sys.argv[1:]:
            print(w, '->', stop_evaluator(w))

テスト出力

$ python knock_071.py hello , my name is piijey
hello -> False
, -> False
my -> True
name -> False
is -> True
piijey -> False

頻出単語を調べる

rt-polarity.pos と rt-polarity.neg それぞれにある単語の頻度50位までと、総合頻度50位までの頻度分布を作った。

コード

zip(*c.most_common(50))* は、行列の転置。

頻度を調べるのに Python の Collections Counter を使った。参考 👉 PythonのCounterでリストの各要素の出現個数をカウント | note.nkmk.me

# knock_071_2.py
import codecs
import collections
import matplotlib.pyplot as plt
POSFILE = './rt-polaritydata/rt-polaritydata/rt-polarity.pos'
NEGFILE = './rt-polaritydata/rt-polaritydata/rt-polarity.neg'
FIG1 = './knock_071_2_posneg.png'

def word_list(file):
    with codecs.open(file, 'r', 'utf-8', 'ignore') as fr:
        out_list = []
        for line in fr:
            for word in line[:-1].split(' '):
                out_list.append(word)
    return out_list


def count_freq(wlist):
    c = collections.Counter(wlist)
    values, counts = zip(*c.most_common(50))
    return values, counts


def plot_bar(values, counts, title):
    plt.bar(values, counts)
    plt.xticks(rotation=70, fontsize=8)
    plt.yticks(fontsize=8)
    plt.title(title)

def plot_commons(file1, file2):
    plt.figure(figsize=(10, 8))
    plt.subplot(3, 1, 1)
    values, counts = count_freq(word_list(file1))
    plot_bar(values, counts, file1.split('/')[-1])

    plt.subplot(3, 1, 2)
    values, counts = count_freq(word_list(file2))
    plot_bar(values, counts, file2.split('/')[-1])

    plt.subplot(3, 1, 3)
    values, counts = count_freq(word_list(file1)+word_list(file2))
    plot_bar(values, counts, file1.split('/')[-1]+' and '+file2.split('/')[-1])

    plt.subplots_adjust(wspace=0.4, hspace=0.6)
    plt.savefig(FIG1)


if __name__ == '__main__':
    plot_commons(POSFILE, NEGFILE)

頻度分布

f:id:piijey:20200229113405p:plain
knock_071_2_posneg.png

ざっと見ると、NLTK のストップワードリストに、記号(. など)と今回固有の頻出単語 moviefilm を加えて使った方が良いかなと思った。