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
Posted by gushwell at 21:00│Comments(0)