2018年11月11日
言語処理100本ノックでPython入門 #76 - 機械学習、scikit-learnでの予測確率
今日は言語処理100本ノック 2015の第8章・機械学習の問題76に挑戦です。
■ 問題
76. ラベル付け
学習データに対してロジスティック回帰モデルを適用し,正解のラベル,予測されたラベル,予測確率をタブ区切り形式で出力せよ.
■ どう解いたか
今回も、3つのクラス(Stopwords,SentimentFeatures,SentimentAnalyser)は前回と同じです。
学習に利用したデータをすべて予測するために、getFeatureDataでデータを取得し、それを predictメソッドとLogisticRegressionオブジェクトのpredict_probaメソッドを使って予測と予測確率を得ています。
このロジックは、すでに問題74で、予測確率を求めるメソッドとして定義していたので、今回は、mainメソッドだけの変更ですみました。
■ Pythonのコード
import re from nltk import stem from sklearn.feature_extraction.text import CountVectorizer from sklearn.linear_model import LogisticRegression from sklearn.externals import joblib class Stopwords: words = [ \ 'a', 'about', 'all', 'an', 'and', 'any', 'are', 'as', \ 'at', 'be', 'been', 'but', 'by', 'can', 'could', 'do', \ 'does', 'for', 'from', 'has', 'have', 'he', 'her', 'his', \ 'how', 'i', 'if', 'in', 'into', 'is', 'it', 'its', 'made', \ 'make', 'may', 'me', 'my', 'no', 'not', 'of', 'on', 'one', \ 'or', 'out', 'she', 'should', 'so', 'some', 'than', 'that', \ 'the', 'their', 'them', 'there', 'then', 'they', 'this', \ 'those', 'to', 'too', 'us', 'was', 'we', 'what', 'when',\ 'which', 'who', 'with', 'would', 'you', 'your', '' ] @staticmethod def exists(word): return word in Stopwords.words class SentimentFeatures: def __init__(self): self.stemmer = stem.PorterStemmer() self.validreg = re.compile(r'^[-=!@#$%^&*()_+|;";,.<>/?]+$') self.splitreg = re.compile(r'\s|,|\.|\(|\)|\'|/|\'|\[|\]|-') def isValid(self, word): if word == '' or len(word) <= 2: return False if self.validreg.match(word): return False return not Stopwords.exists(word) def getFromLine(self, line): array = self.splitreg.split(line) # こういう時はlambda キーワードいらないんですね。 words = filter(self.isValid, array) xs = map(self.stemmer.stem, words) return xs def enumerate(self, filename, encoding): with open(filename, 'r', encoding=encoding) as fin: for line in fin: sentiment = line[:3] yield sentiment, self.getFromLine(line[3:]) class SentimentAnalyser: def __init__(self): self.cv = CountVectorizer(encoding='utf-8') self.lr = LogisticRegression(solver='sag', max_iter=10000) # LogisticRegression を使い学習する def fit(self, X_train, y_train): X_train_cv = self.cv.fit_transform(X_train) self.lr.fit(X_train_cv, y_train) # LogisticRegression を使い予測する def predict(self, X_test): x = self.cv.transform(X_test) return self.lr.predict(x) # 予測し、分類毎に確率を得る def predict_proba(self, X_test): x = self.cv.transform(X_test) return self.lr.predict_proba(x) # 学習済みデータをロードする def load(self): self.cv = joblib.load('chapter08/cv73.learn') self.lr = joblib.load('chapter08/lr73.learn') # 学習済みデータを保存する def save(self): # 学習したデータを保存する joblib.dump(self.cv, 'chapter08/cv73.learn') joblib.dump(self.lr, 'chapter08/lr73.learn') # 学習に利用するデータを取り出す # y[] は、センチメント # X[] は、素性データ @staticmethod def getFeatureData(filename): X = [] y = [] sf = SentimentFeatures() for sentiment, features in sf.enumerate(filename, 'cp1252'): y.append(1.0 if sentiment[0] == '+' else 0.0) X.append(' '.join(features)) return X, y def getLabel(val): return '+1' if val > 0.5 else '-1' def main(): sa = SentimentAnalyser() sa.load() X_test, y_test = sa.getFeatureData('chapter08/sentiment.txt') y_test_pred = sa.predict(X_test) pr = sa.predict_proba(X_test) for right, pred, proba in zip(y_test, y_test_pred, pr): print('{}\t{}\t{}'.format(getLabel(right), getLabel(pred), \ proba[0] if pred == 0 else proba[1])) if __name__ == '__main__': main()
■ 結果
先頭の20個だけを掲載します。
-1 -1 0.6097303429740366 -1 -1 0.7237875917615046 +1 +1 0.8452377813768515 +1 +1 0.6449560336941579 +1 +1 0.543156360826781 +1 +1 0.9113562170418062 +1 +1 0.6398913869466663 -1 -1 0.6568220959620661 +1 +1 0.7594696176352425 -1 -1 0.7002498960488786 +1 +1 0.927910364837036 +1 +1 0.9032093714572444 +1 +1 0.714278110906943 +1 +1 0.8908909959384128 +1 +1 0.588722939785566 +1 +1 0.7755451604607824 +1 +1 0.9985328530583656 +1 +1 0.747913188658218 -1 -1 0.6764951558532446 +1 +1 0.9859825558428327
2018年10月28日
言語処理100本ノックでPython入門 #75 - 機械学習、scikit-learnのcoef_ プロパティ
今日は言語処理100本ノック 2015の第8章・機械学習の問題75に挑戦です。
■ 問題
75. 素性の重み
73で学習したロジスティック回帰モデルの中で,重みの高い素性トップ10と,重みの低い素性トップ10を確認せよ.
■ どんなふうに解くか
今回は、3つのクラス(Stopwords,SentimentFeatures,SentimentAnalyser)は前回と同じです、mainメソッドだけを変更しています。
やっていることは、まず学習済みデータをロードして、CountVectorizerのget_feature_names メソッドで重複が除かれた素性データ一覧(単語一覧)を得ます。
これだけだと、重み順になっていないので、LogisticRegressionオブジェクトの coef_ を参照します。 ここには get_feature_namesで得た素性リストの順に重みデータがリストで入っています。
numpyのargsortを使って、素性リストをソート使しています。 このargsortはちょっと変わっていて、リストの中身で(重み順で)ソートしてくれるのですが、 その結果は、ソート順に並び替えられた要素のインデックスが得られます。 まあ、処理速度を考慮するとそれが妥当なのかも。これを使ってTop10, Bottom 10を取り出しています。
■ Pythonのコード
import re from nltk import stem import numpy as np from sklearn.feature_extraction.text import CountVectorizer from sklearn.linear_model import LogisticRegression from sklearn.externals import joblib class Stopwords: words = ['a', 'about', 'all', 'an', 'and', 'any', 'are', 'as', \ 'at', 'be', 'been', 'but', 'by', 'can', 'could', 'do', \ 'does', 'for', 'from', 'has', 'have', 'he', 'her', 'his', \ 'how', 'i', 'if', 'in', 'into', 'is', 'it', 'its', 'made', \ 'make', 'may', 'me', 'my', 'no', 'not', 'of', 'on', 'one', \ 'or', 'out', 'she', 'should', 'so', 'some', 'than', 'that', \ 'the', 'their', 'them', 'there', 'then', 'they', 'this', \ 'those', 'to', 'too', 'us', 'was', 'we', 'what', 'when',\ 'which', 'who', 'with', 'would', 'you', 'your', '' ] @staticmethod def exists(word): return word in Stopwords.words class SentimentFeatures: def __init__(self): self.stemmer = stem.PorterStemmer() self.validreg = re.compile(r'^[-=!@#$%^&*()_+|;";,.<>/?]+$') self.splitreg = re.compile(r'\s|,|\.|\(|\)|\'|/|\'|\[|\]|-') def isValid(self, word): if word == '' or len(word) <= 2: return False if self.validreg.match(word): return False return not Stopwords.exists(word) def getFromLine(self, line): array = self.splitreg.split(line) # こういう時はlambda キーワードいらないんですね。 words = filter(self.isValid, array) xs = map(self.stemmer.stem, words) return xs def enumerate(self, filename, encoding): with open(filename, 'r', encoding=encoding) as fin: for line in fin: sentiment = line[:3] yield sentiment, self.getFromLine(line[3:]) class SentimentAnalyser: def __init__(self): self.cv = CountVectorizer(encoding='utf-8') self.lr = LogisticRegression(solver='sag', max_iter=10000) # LogisticRegression を使い学習する def fit(self, X_train, y_train): X_train_cv = self.cv.fit_transform(X_train) self.lr.fit(X_train_cv, y_train) # LogisticRegression を使い予測する def predict(self, X_test): x = self.cv.transform(X_test) return self.lr.predict(x) # 予測し、分類毎に確率を得る def predict_proba(self, X_test): x = self.cv.transform(X_test) return self.lr.predict_proba(x) # 学習済みデータをロードする def load(self): self.cv = joblib.load('chapter08/cv73.learn') self.lr = joblib.load('chapter08/lr73.learn') # 学習済みデータを保存する def save(self): # 学習したデータを保存する joblib.dump(self.cv, 'chapter08/cv73.learn') joblib.dump(self.lr, 'chapter08/lr73.learn') # 学習に利用するデータを取り出す # y[] は、センチメント # X[] は、素性データ @staticmethod def getFeatureData(filename): X = [] y = [] sf = SentimentFeatures() for sentiment, features in sf.enumerate(filename, 'cp1252'): y.append(1.0 if sentiment[0] == '+' else 0.0) X.append(' '.join(features)) return X, y def main(): sa = SentimentAnalyser() sa.load() # fit_transform/transformに渡した単語一覧(学習データ一覧)を得る (重複はなし) features = sa.cv.get_feature_names() # coef_ には学習した結果の重みが入る。 # これをソートして、そのインデックスを得る argsortはソートした結果のインデックスが返る sorted_idx = np.argsort(sa.lr.coef_)[0] print('重みの高い素性トップ10') for i in sorted_idx[-1:-11:-1]: print(features[i]) print() print('重みの低い素性トップ10') for i in sorted_idx[:10]: print(features[i]) if __name__ == '__main__': main()
■ 結果
重みの高い素性トップ10 engross refresh smarter unexpect remark resist grown examin refreshingli confid 重みの低い素性トップ10 bore dull fail mediocr plod routin wasn neither badli wast
2018年10月08日
言語処理100本ノックでPython入門 #74 - 機械学習、scikit-learnでロジスティック回帰の予測
今日は言語処理100本ノック 2015の第8章・機械学習の問題74を解きました。
■ 問題
74. 予測
73で学習したロジスティック回帰モデルを用い,与えられた文の極性ラベル(正例なら"+1",負例なら"-1")と,その予測確率を計算するプログラムを実装せよ.
■ Pythonのコード
import re from nltk import stem from sklearn.feature_extraction.text import CountVectorizer from sklearn.linear_model import LogisticRegression #from sklearn.metrics import accuracy_score, classification_report from sklearn.externals import joblib class Stopwords: words = ['a', 'about', 'all', 'an', 'and', 'any', 'are', 'as', \ 'at', 'be', 'been', 'but', 'by', 'can', 'could', 'do', \ 'does', 'for', 'from', 'has', 'have', 'he', 'her', 'his', \ 'how', 'i', 'if', 'in', 'into', 'is', 'it', 'its', 'made', \ 'make', 'may', 'me', 'my', 'no', 'not', 'of', 'on', 'one', \ 'or', 'out', 'she', 'should', 'so', 'some', 'than', 'that', \ 'the', 'their', 'them', 'there', 'then', 'they', 'this', \ 'those', 'to', 'too', 'us', 'was', 'we', 'what', 'when',\ 'which', 'who', 'with', 'would', 'you', 'your', '' ] @staticmethod def exists(word): return word in Stopwords.words class SentimentFeatures: def __init__(self): self.stemmer = stem.PorterStemmer() self.validreg = re.compile(r'^[-=!@#$%^&*()_+|;";,.<>/?]+$') self.splitreg = re.compile(r'\s|,|\.|\(|\)|\'|/|\'|\[|\]|-') def isValid(self, word): if word == '' or len(word) <= 2: return False if self.validreg.match(word): return False return not Stopwords.exists(word) def getFromLine(self, line): array = self.splitreg.split(line) # こういう時はlambda キーワードいらないんですね。 words = filter(self.isValid, array) xs = map(self.stemmer.stem, words) return xs def enumerate(self, filename, encoding): with open(filename, 'r', encoding=encoding) as fin: for line in fin: sentiment = line[:3] yield sentiment, self.getFromLine(line[3:]) class SentimentAnalyser: def __init__(self): self.cv = CountVectorizer(encoding='utf-8') self.lr = LogisticRegression(solver='sag', max_iter=10000) # LogisticRegression を使い学習する def fit(self, X_train, y_train): X_train_cv = self.cv.fit_transform(X_train) self.lr.fit(X_train_cv, y_train) # LogisticRegression を使い予測する def predict(self, X_test): x = self.cv.transform(X_test) return self.lr.predict(x) # 予測し、分類毎に確率を得る def predict_proba(self, X_test): x = self.cv.transform(X_test) return self.lr.predict_proba(x) # 学習済みデータをロードする。ファイル名が良くなかったなー def load(self): self.cv = joblib.load('chapter08/cv73.learn') self.lr = joblib.load('chapter08/lr73.learn') # 学習済みデータを保存する def save(self): # 学習したデータを保存する joblib.dump(self.cv, 'chapter08/cv73.learn') joblib.dump(self.lr, 'chapter08/lr73.learn') # 学習に利用するデータを取り出す # y[] は、センチメント # X[] は、素性データ @staticmethod def getFeatureData(filename): X = [] y = [] sf = SentimentFeatures() for sentiment, features in sf.enumerate(filename, 'cp1252'): y.append(1.0 if sentiment[0] == '+' else 0.0) X.append(' '.join(features)) return X, y # dataのセンチメントを予測する def predictSentiment(sa, data): x = [data] y_test_pred = sa.predict(x) pr = sa.predict_proba(x) print(data.rstrip('\n')) print('予測:{} 確率:{}\n'.format('+1' if y_test_pred[0] == 1 else '-1', \ pr[0][0] if y_test_pred[0] == 0 else pr[0][1])) def main(): sa = SentimentAnalyser() sa.load() # テストの文を考えるのが面倒なので、元のデータから6つほど借用して、テストデータにしている。 # これだとあまり意味がないけど... texts = [\ 'perhaps the best sports movie i''ve ever seen.', \ 'i had more fun watching spy than i had with most of the big summer movies.', \ 'vividly conveys the shadow side of the 30-year friendship between two english women.', \ 'an excruciating demonstration of the unsalvageability of a movie saddled with an amateurish screenplay.', \ 'sadly , hewitt''s forte is leaning forward while wearing low-cut gowns , not making snappy comebacks.', \ 'since lee is a sentimentalist , the film is more worshipful than your random e ! true hollywood story.' ] sf = SentimentFeatures() for text in texts: features = sf.getFromLine(text) x_test = ' '.join(features) predictSentiment(sa, x_test) if __name__ == '__main__': main()
■ 少し解説
今回は、前回定義したSentimentAnalyserクラスに新たに3つのメソッドを追加しました。
predictメソッド
LogisticRegression を使い予測します。予測した結果は0か1に分類されます。0がネガティブである"-1"を、 1がポジティブである"+1"を表します。
predict_proba
予測し、分類毎に確率を得ています。
本当は、このメソッドだけにしたいのですが、LogisticRegressionのpredict_probaが返すデータの中に、 LogisticRegressionのpredictメソッドが返すデータが入っていないような気がするので、predictメソッドとこのメソッドの2つを定義しています。
load
学習済みデータをロードします。
それと、単独の関数predictSentimentも定義。
predictSentiment
これは単独の関数。与えられた文章から結果を予測し、その予測した結果と、予測確率を表示しています。 予測確率は、predict_probaメソッドが返すデータから取得しています。 予測結果(0か1)により、予測確率の取り出す場所が異なっています。
■ 結果
perhap best sport movi ive ever seen 予測:+1 確率:0.9006017914136548 had more fun watch spi had most big summer movi 予測:+1 確率:0.7479161215615849 vividli convey shadow side year friendship between two english women 予測:+1 確率:0.9409305758954958 excruci demonstr unsalvag movi saddl amateurish screenplay 予測:-1 確率:0.8628974528161055 sadli hewitt fort lean forward while wear low cut gown make snappi comeback 予測:-1 確率:0.9293995549165373 sinc lee sentimentalist film more worship random true hollywood stori 予測:-1 確率:0.8095457186618346
2018年09月30日
言語処理100本ノックでPython入門 #73 - 機械学習、scikit-learnでロジスティック回帰
今日は言語処理100本ノック 2015の第8章・機械学習の問題73に挑戦です。
■ 問題
73. 学習
72で抽出した素性を用いて,ロジスティック回帰モデルを学習せよ.
■ scikit-learnの準備
問題72までやって、やっと機械学習のための下準備ができたので、これから機械学習に入ります。第8章の学習項目には、scikit-learn とあるので、scikit-learnを使って機械学習をさせようと思います。 anaconda3には、scikit-learnモジュールが含まれているので、そのままimportするだけです。
以下の3つをimportします。
from sklearn.linear_model import LogisticRegression from sklearn.feature_extraction.text import CountVectorizer from sklearn.externals import joblib
LogisticRegressionがロジスティック回帰分析を行うモジュールです。 CountVectorizerは、単語リストをベクトル化するために使います。 joblibは、学習した結果をファイルに保存するために使います。
今回作成したクラスは、SentimentAnalyserクラスです。SentimentFeatures、Stopwordsは前回と同じです。
まだ、scikit-learnについてあまり知識がない状況なので、いろんなサイトを見ながら作成しています。 以下にコードを載せます。
■ Pythonのコード
import re from nltk import stem from sklearn.linear_model import LogisticRegression from sklearn.feature_extraction.text import CountVectorizer from sklearn.externals import joblib class Stopwords: words = [ 'a', 'about', 'all', 'an', 'and', 'any', 'are', 'as', \ 'at', 'be', 'been', 'but', 'by', 'can', 'could', 'do', \ 'does', 'for', 'from', 'has', 'have', 'he', 'her', 'his', \ 'how', 'i', 'if', 'in', 'into', 'is', 'it', 'its', 'made', \ 'make', 'may', 'me', 'my', 'no', 'not', 'of', 'on', 'one', \ 'or', 'out', 'she', 'should', 'so', 'some', 'than', 'that', \ 'the', 'their', 'them', 'there', 'then', 'they', 'this', \ 'those', 'to', 'too', 'us', 'was', 'we', 'what', 'when',\ 'which', 'who', 'with', 'would', 'you', 'your', '' ] @staticmethod def exists(word): return word in Stopwords.words class SentimentFeatures: def __init__(self, filename): self.filename = filename self.stemmer = stem.PorterStemmer() @staticmethod def isValid(word): if word == '' or len(word) <= 2: return False if re.match(r'^[-=!@#$%^&*()_+|;";,.<>/?]+$', word): return False return not Stopwords.exists(word) def getFromLine(self, line): sentiment = line[:3] array = re.split(r'\s|,|\.|\(|\)|\'|/|\'|\[|\]|-', line[3:]) # こういう時はlambda キーワードいらないんですね。 words = filter(self.isValid, array) xs = map(self.stemmer.stem, words) return sentiment, xs def enumerate(self): with open(self.filename, 'r') as fin: for line in fin: yield self.getFromLine(line) class SentimentAnalyser: def __init__(self): self.cv = CountVectorizer(encoding='utf-8') self.lr = LogisticRegression(solver='sag', max_iter=10000) # LogisticRegression を使い学習する def fit(self, X_train, y_train): X_train_cv = self.cv.fit_transform(X_train) self.lr.fit(X_train_cv, y_train) # 学習済みデータを保存する def save(self): # 学習したデータを保存する joblib.dump(self.cv, 'chapter08/cv73.learn') joblib.dump(self.lr, 'chapter08/lr73.learn') # 学習に利用するデータを取り出す # X[] は、素性データ # y[] は、センチメント (正解データ) @staticmethod def getFeatureData(filename): X = [] y = [] sf = SentimentFeatures(filename) for sentiment, features in sf.enumerate(): y.append(1.0 if sentiment[0] == '+' else 0.0) X.append(' '.join(features)) return X, y def main(): sa = SentimentAnalyser() X_train, y_train = sa.getFeatureData('chapter08/sentiment.txt') sa.fit(X_train, y_train) sa.save() if __name__ == '__main__': main()
■ ちょっと解説
getFeatureDataは、学習に利用する素性データをファイルから取り出すメソッドです。リストにいっぺんに入れています。
戻り値のXが学習用データ、yが正解データです。
fitが学習メソッド 与えられたデータをもとにfitメソッドで学習します。 fitメソッドを呼び出す前に、
X_train_cv = self.cv.fit_transform(X_train)
で、X_Trainデータをベクトル化しています。self.cv.は、CountVectorizerオブジェクトです。 って、本当にこれでいいのかはっきり言って自身がないです。
ベクトル化したものをLogisticRegressionのオブジェクトのfitメソッドに渡して学習させます。 もちろん、正解データも一緒に渡します。
LogisticRegressionのオブジェクト生成時のsolverには、
'newton-cg', 'lbfgs', 'liblinear', 'sag', 'saga'のいずれかを指定しますが、この学習ではどれが良いのかよくわかっていません。ここでは、'sag'を選びました。
saveが学習済みのデータを保存するメソッドです。 CountVectorizerオブジェクトも保存しています。
main関数では、SentimentAnalyserクラスのインスタンスを生成し、getFeatureData, fit, save を順番に呼び出しています。
実行して、しばらく待つと、2つのファイルが作成されます。
2018年09月25日
言語処理100本ノックでPython入門 #72 - 機械学習、素性抽出
今日は言語処理100本ノック 2015の第8章・機械学習の問題72に挑戦です。
■ 問題
72. 素性抽出
極性分析に有用そうな素性を各自で設計し,学習データから素性を抽出せよ.素性としては,レビューからストップワードを除去し,各単語をステミング処理したものが最低限のベースラインとなるであろう.
■ どうやって解くか
素性を各自で設計しと言われても、その知識が無いので困りました。
ただ、「素性としては,レビューからストップワードを除去し,各単語をステミング処理したものが最低限のベースラインとなるであろう.」 とあるので、極性分析(+評価か-評価か)に不要そうな単語を取り除けばよさそうです。 ステミングは、第6章でやったので、その時に使った nltkモジュールを使いました。
Stopwordsクラスは前問と同じものです。 新たに、SentimentFeaturesクラスを定義しました。
main関数では、このSentimentFeaturesクラスのenumerateで素性を列挙し、確認用に先頭50個だけを表示しています。
SentimentFeaturesクラスのメソッドは以下の3つです。
isValid
極性分析に有効そうな単語かどうかを判断、isValidならば、素性データとして残す。無効な単語は、「ストップワード」「文字数が2以下の単語」「記号からなるもの」の3つ。
getFromLine
与えられた1行(問題70で作成したテキストファイルの1行)を単語に分割しisValidの単語を抜き出し、それをステミングしたものを返す。この時、極性データ(+1, -1)とともにタプルで返す。
enumerate
問題70で作成したsentiment.txtから1行ずつ読み込み、getFromLineにその1行を渡して得られたデータ(極性データと、素性としての単語のタプル)を列挙。
ところで、getFromLineメソッドの中でfilterとmap関数を使っていますが、ラムダ式ではなくて、関数名だけを指定することもできるんですね。 これは、C#と同じです。ちゃんとpylintが指摘してくれました。
■ Pythonのコード
import re from nltk import stem class Stopwords: words = ['a', 'about', 'all', 'an', 'and', 'any', 'are', 'as', \ 'at', 'be', 'been', 'but', 'by', 'can', 'could', 'do', \ 'does', 'for', 'from', 'has', 'have', 'he', 'her', 'his', \ 'how', 'i', 'if', 'in', 'into', 'is', 'it', 'its', 'made', \ 'make', 'may', 'me', 'my', 'no', 'not', 'of', 'on', 'one', \ 'or', 'out', 'she', 'should', 'so', 'some', 'than', 'that', \ 'the', 'their', 'them', 'there', 'then', 'they', 'this', \ 'those', 'to', 'too', 'us', 'was', 'we', 'what', 'when',\ 'which', 'who', 'with', 'would', 'you', 'your', '' ] @staticmethod def exists(word): return word in Stopwords.words class SentimentFeatures: def __init__(self, filename): self.filename = filename self.stemmer = stem.PorterStemmer() @staticmethod def isValid(word): if word == '' or len(word) <= 2: return False if re.match(r'^[-=!@#$%^&*()_+|;";,.<>/?]+$', word): return False return not Stopwords.exists(word) def getFromLine(self, line): sentiment = line[:3] array = re.split(r'\s|,|\.|\(|\)|\'|/|\'|\[|\]|-', line[3:]) # こういう時はlambda キーワードいらないんですね。 words = filter(self.isValid, array) xs = map(self.stemmer.stem, words) return sentiment, xs def enumerate(self): with open(self.filename, 'r') as fin: for line in fin: yield self.getFromLine(line) def main(): sf = SentimentFeatures('chapter08/sentiment.txt') for sentiment, features in list(sf.enumerate())[:50]: print(sentiment, " ".join(features)) if __name__ == '__main__': main()
■ 結果
10個だけ載せます。
-1 film depress life itself -1 ill fit tuxedo strictli off rack -1 clich escap perfervid treatment gang warfar call ce wild -1 circuit queen won learn thing busi curs film strateg place white sheet -1 waterlog script plumb unchart depth stupid incoher sub sophomor sexual banter +1 imax strap pair goggl shut real world take vicari voyag last frontier space -1 analyz movi three word thumb friggin down +1 stori haven seen big screen befor stori american human be know -1 bray complet sea noth savag garden music video resum clue make movi +1 teen review such recommend onli under year age onli veri mild rental
2018年09月19日
言語処理100本ノックでPython入門 #71 - 機械学習、ストップワード
今日は言語処理100本ノック 2015の第8章・機械学習の問題71に挑戦です。
■ 問題
71. ストップワード
英語のストップワードのリスト(ストップリスト)を適当に作成せよ.さらに,引数に与えられた単語(文字列)がストップリストに含まれている場合は真,それ以外は偽を返す関数を実装せよ.さらに,その関数に対するテストを記述せよ.
■ どうやって解くか
ストップワードとは、言語処理する際にに、あまりにも一般的過ぎるため処理対象から外す単語のことらしいです。適当に作成せよとのことなので。いくつかのサイトを参考にして適当に作成(笑)。きっとこれによって学習結果が変わってくる可能性もあるので、本当ならばもっと吟味する必要があるのかもしれません。このストップワードのリストはStopwordsクラスのなかに、リテラル値で定義。
「引数に与えられた単語(文字列)がストップリストに含まれている場合は真,それ以外は偽を返す関数」を実装せよ.
とのことで、Stopwordsクラスにexistsメソッドを定義しました。このメソッドは静的メソッドにしたかったので、アノテーション @staticmethod を付加しています。
静的メソッドは、自分自身のオブジェクトは受け取る必要はないので、純粋な引数だけを指定しています。
in 演算子で、リストの中に含まれているかどうかを判定しているだけの単純なメソッドです。
■ Pythonのコード
class Stopwords: words = ['a', 'about', 'all', 'an', 'and', 'any', 'are', 'as', \ 'at', 'be', 'been', 'but', 'by', 'can', 'could', 'do', \ 'does', 'for', 'from', 'has', 'have', 'he', 'her', 'his', \ 'how', 'i', 'if', 'in', 'into', 'is', 'it', 'its', 'made', \ 'make', 'may', 'me', 'my', 'no', 'not', 'of', 'on', 'one', \ 'or', 'out', 'she', 'should', 'so', 'some', 'than', 'that', \ 'the', 'their', 'them', 'there', 'then', 'they', 'this', \ 'those', 'to', 'too', 'us', 'was', 'we', 'what', 'when',\ 'which', 'who', 'with', 'would', 'you', 'your', '' ] @staticmethod def exists(word): return word in Stopwords.words def test(): w = 'in' print(w, Stopwords.exists(w)) w = 'what' print(w, Stopwords.exists(w)) w = 'list' print(w, Stopwords.exists(w)) w = 'yes' print(w, Stopwords.exists(w)) def main(): test() if __name__ == '__main__': main()
■ 結果
以下、testメソッドの結果です。
in True what True list False yes False