前置き
TF-IDF変換を未知の入力に対して使うため、変換した内容を保存する必要があるため、今回はその保存方法について残しておく。
mecabで形態素解析
tyamagu2.xyzさんの記事を引用してクラス定義してみます。
※MeCab
をimport忘れずに
※ストップワードは、京大のSlothlibを使っているので、引っ張って来てください
import MeCab
'''
MeCabで名詞だけを抜き取るクラスの定義
辞書は"mecab-ipadic-neologd"を使用
'''
class WordDividor:
INDEX_CATEGORY = 0
TARGET_CATEGORY = ['名詞']
def __init__(self, dictionary="mecabrc"):
self.dictionary = dictionary
self.tagger = MeCab.Tagger(self.dictionary)
def extract_words(self, text):
if not text:
return []
# テキストの余分なデータの削除(ex : httpなど)
text = re.sub(r'https?://[\w/:%#\$&\?\(\)~\.=\+\-…]+', "", text)
text = re.sub(r'[!-~]', "", text) # 半角記号,数字,英字
text = re.sub(r'[︰-@]', "", text) # 全角記号
text = re.sub('\n', " ", text) # 改行文字
words = []
# 文字列がGCされるのを防ぐ
self.tagger.parse('')
node = self.tagger.parseToNode(text)
while node:
# ","で文字列の分割を行い, ターゲットになる品詞と比較を行う.
if node.feature.split(',')[self.INDEX_CATEGORY] in self.TARGET_CATEGORY:
# ストップワードの判定を行う(stopwordsに引っかかってない名詞を入れる)
if node.surface not in stopwords:
words.append(node.surface)
node = node.next
return words
使う時は、
wd = WordDividor()
extract_word = wd.extract_word(text="ほげほげテスト")
このように使うと、一時的に用意した変数extract_word
にmecabにより形態素解析され、名詞だけ抜き出されたものが入ります。
TF-IDF変換
次に、TF-IDF変換を行います。
これも下記のようにクラス定義してあげます.
※TfidfVectorizer
をimport忘れずに
from sklearn.feature_extraction.text import TfidfVectorizer
'''
TF-IDF変換を行うクラスの定義
1. TfidfVectorizerインスタンスの作成(analyzerにmecabの形態素解析手法を指定)
2. fitメソッドを行ったTfidfVectorizerインスタンスを返す(新しいデータに用いるため)
'''
class WordPreProcessor:
# コンストラクタ
def __init__(self, analyze_method):
self.tfidf = TfidfVectorizer(analyzer=analyze_method, use_idf=True, norm='l2', smooth_idf=True)
def wordspreprocess(self, raw_data):
# fitの状態を格納(TfidfVectorizerインスタンスが格納される)
tfidf_condition = self.tfidf.fit(raw_data)
# 形態素解析されたワードを、fitで作ったTF-IDF特徴空間行列に変換する
tfidf_vector = self.tfidf.transform(raw_data).toarray()
return tfidf_condition, np.matrix(tfidf_vector)
ここで2つpointがあり、
英語などを形態素解析する場合はそもそもMeCabが必要ではないので、python機械学習プログラミングなんかは
TfidfVectorizer(analyzer='word', use_idf=True, norm='l2', smooth_idf=True)
とデフォルト指定で生成しています。
なのでインスタンス生成する際は
wpp = WordPreProcessor(analyze_method=wd.extract_words)
こんな感じで、wdインスタンスのメソッドを指定してあげます。
- fit_transformを使わずfitだけ使う
fitメソッドは公式ライブラリを引用すると
Learn vocabulary and idf from training set.
訓練データからidfと語彙を学習します。返り値は学習後のTfidfVectorizerインスタンスです。
そのインスタンスを使ってTF-IDF変換を行うメソッドがtransform
メソッドになります。
公式のライブラリではこの2つを一緒くたにしたfit_transform
メソッドが親切に用意されているので、用途で使い分けるべきだと思います。
ということで、fitした状態をpickleなどで保存すれば、新しい文章を保存した規準でTF−IDF変換できるということです。
TF-IDF保存
# オブジェクト保存ライブラリの導入
import pickle
# インスタンスの生成
wpp = WordPreProcessor(analyze_method=wd.extract_words)
tfidf_condition, feature_matrix = wpp.wordspreprocess(raw_data="ほげほげテスト", is_dimension_compact=is_dimension_compact)
# 保存
pickle.dump(tfidf_condition, open("tfidf.pkl", "wb"))
SwigPyObject????
どうやら、analyze_methodに形態素クラスのメソッドを指定しているのでクラスインスタンスのネストになっているため保存できないということなのだ。
なので、この解決策は
tfidf_condition.set_params(analyzer='word')
# 保存
pickle.dump(tfidf_condition, open("tfidf.pkl", "wb"))
一旦analyzer='word'と置き換えることで保存する('word'はデフォルトである)
使う際は,
from dataPreProcessor import WordDividor
import pickle
def main():
wd = WordDividor()
tfidf_vectorizer = pickle.load(open("tfidf.pkl", "rb"))
# 一時的に置き換えていたanalyzerを指定
tfidf_vectorizer.set_params(analyzer=wd.extract_words)
tfidf_vector = tfidf_vectorizer.transform(['新しくものあるほげほげテスト'])
if __name__ == '__main__':
main()
こんな感じで、保存したものをロードして、set_params
メソッドを使って再度MeCabクラスのメソッドを指定し直して、使ってあげる。
fitで学習済みなので、analyzeメソッドが一時的に変更されても問題ありません。
最後に
意外と回りくどいやり方をしているので、そもそもpickleがナンセンス
とか他にいい方法があればコメントください。