TFIDFとコサイン類似度によるドキュメントの推奨


学習のきっかけ


現在の日記データから作成した日記に似た日記を推奨するシステムを作成します.TFIDFを使用して類似度を測定する場合、どのような問題がありますか?

仮想環境の設定


まず、プロジェクトで使用するモジュールをロードするために仮想環境を設定します.
python3 -m venv venv
現在のプロジェクトでは、sklearningおよび前処理用のmecabをインストールします.
mecabはmac上で良好に動作し,mac上で行う.
追加のモジュールは、次の機能要件です.txtを表示すればいいです.

プリプロセッシングデータ


まず、正規表現を使用して、以前にインポートした天気データを韓国語、数字、英語から除外します.

大きなニサをmecabでそれぞれ作製した.
名詞、動詞、形容詞だけを抽出した.
また、100個の非用語辞書を提供し、単語辞書を表示するときに追加します.
def tokenizer(raw, pos=["NNG","NNP","VV","VA"], stopword=stopwords): 
from konlpy.tag import 
Mecab m = Mecab() 
return [word for word, tag in m.pos(raw) if len(word) > 1 and tag in pos and word not in stopword ]

TFIDFの使用


次に、サイドカット運転によって提供されるtfidfベクトルマシンを作成します.
tf = TfidfVectorizer(
    stop_words=stopwords, tokenizer=tokenizer, ngram_range=(1, 2), max_features=200000, sublinear_tf=True)
上に作成したベクトルをインスタンス化してshapeを表示すると、2つのカラムで構成されていることがわかります.ex) (9321,301506)
これはcoo matrixで改良されたマトリクスであり、前9321は学習された文字数を表し、後301506は学習に使用される単語数を表す.

生成されたインスタンスとベクトルを保存


日記データを最初に収集したデータとして学習するが、さらに学習するためにはベクトルオブジェクトとインスタンスを保存する必要がある.
Pythonの内部ライブラリで提供されているpickleを使っています.
X = tf.fit_transform(article)
    tf.n_docs = len(article)
    with open(mtx_path, "wb") as fw:
        pickle.dump(X, fw)
    with open(tf_path, "wb") as fw:
        pickle.dump(tf, fw)
その後、他のデータを入力すると、オブジェクトを再ロードできます.
with open(mtx_path, "rb") as fr:
        X = pickle.load(fr)
    with open(tf_path, "rb") as fr:
        tf = pickle.load(fr)

新しいデータの比較


次に、新しく入力した日記を上記と同じ前処理し、保存したベクトル化器で変換して、既存の保存された辞書を使用してバックグラウンドを作成します.
example_vector = tf.transform([more])
    tf.partial_fit([more])
ここで注意しなければならないのは、上記のようにtransformではなくfit transformを使用している場合、注意してください:)
def recommand(more):
    with open(mtx_path, "rb") as fr:
        X = pickle.load(fr)
    with open(tf_path, "rb") as fr:
        tf = pickle.load(fr)
    # X = mmread(mtx_path).tocsr()
    example_vector = tf.transform([more])
    tf.partial_fit([more])
    with open(tf_path, "wb") as fw:
        pickle.dump(tf, fw)

    cos_similar = linear_kernel(example_vector, X).flatten()

    sim_rank_idx = cos_similar.argsort()[::-1]
    sim_rank_idx = sim_rank_idx[:5]
    for i in sim_rank_idx:
        print(cos_similar[i])
上の図に示すように、変換が完了すると、変更したベクトルを保存し、Xデータを追加して比較し、Xデータを変更する必要があります.X.語彙値はexample vectorです.語彙値に変更し、vstackを使用してXデータに文の数を追加する必要があります.

その他の改善点を考慮


最初は、10以上の新しい天気データが入ったら、fit transformを使って勉強し直してみます.しかし,以前学習したデータを再学習したため,効率が低下した.stackoverflowを検索するときに良いコードリンクが残っています.
https://stackoverflow.com/questions/39109743/adding-new-text-to-sklearn-tfidif-vectorizer-python
import re
import numpy as np
from scipy.sparse.dia import dia_matrix
def partial_fit(self, X):
    max_idx = max(self.vocabulary_.values())
    for a in X:
        # update vocabulary_
        
        tokens = re.findall(self.token_pattern, a)
        for w in tokens:
            if w not in self.vocabulary_:
                max_idx += 1    
                self.vocabulary_[w] = max_idx

        # update idf_
        df = (self.n_docs + self.smooth_idf) / \
            np.exp(self.idf_ - 1) - self.smooth_idf
        self.n_docs += 1
        df.resize(len(self.vocabulary_))
        for w in tokens:
            df[self.vocabulary_[w]] += 1
        idf = np.log((self.n_docs + self.smooth_idf) /
                     (df + self.smooth_idf)) + 1
        self._tfidf._idf_diag = dia_matrix(
            (idf, 0), shape=(len(idf), len(idf)))
ハングルデータを使用しているので、大文字と小文字の変更コードのみを変更して適用しました.これにより、新しく入力したデータを語彙に追加できます.0

TFIDFに問題がある


今見ているように、新しい文章があるときに追加すればいいので、OOVは起こらないはずです.しかし、欠点は単語だけを見て比較しないことです.もう一つのdocumentのtopicには一定の限界があり、同音異義語にはあまり詳しくないかもしれません.
勉強を始めたばかりの頃、Sikittrunが提供してくれたTFIDF-VectorはWord 2 vecと変わらないと思っていました.TFIDFもword-document方式で単語をマッピングしているからです.しかし,単語の順序を無視して純単語のみを評価し,word 2 vecは単語の近くに現れる特定の単語に特殊な接尾辞を提供する.したがって,TF−IDFはTDMを作成するために用いられ,word 2 vecこそ単語を接尾辞に置き換える.
https://www.quora.com/Is-TF-IDF-and-Word2vec-the-same
http://doc.mindscale.kr/km/unstructured/qna11.html
最後に、ハブアドレスとリファレンスリンクを残して、これで終わります.

ハブアドレス


https://github.com/denhur62/TFIDF_mecab

参考資料


https://towardsdatascience.com/tf-term-frequency-idf-inverse-document-frequency-from-scratch-in-python-6c2b61b78558
https://bkshin.tistory.com/entry/NLP-8-%EB%AC%B8%EC%84%9C-%EC%9C%A0%EC%82%AC%EB%8F%84-%EC%B8%A1%EC%A0%95-%EC%BD%94%EC%82%AC%EC%9D%B8-%EC%9C%A0%EC%82%AC%EB%8F%84
https://wikidocs.net/book/2155
https://sikaleo.tistory.com/62