いろいろ倉庫

KNIME、EXCEL、R、Pythonなどの備忘録

【Python】文章の類似度を算出したい

・お題:文章がたくさんある中で、自分が気になる文章と似ている文章を探したい。cos類似度というやつを使って、類似度をランキングしてみたい。

 

・先日、文章をその中に含んでいる単語で数値化して表現した。今回は、その数値化された文章を使って、cos類似度というやつを算出し、類似度をランキングしてみたい。

・まずは文章を作成する。ここは以前と同じ。

A="I am a doctor."
B="My dream is to become a doctor."
C="My father is a doctor."
D="I am a lawyer."
E="My father is a lawyer and I am a lawyer too."
F="My mother is a lawyer"
import pandas as pd
df=pd.DataFrame({"ID":["A","B","C","D","E","F"],
                "text":[A,B,C,D,E,F]})

・次に、TF-IDFを算出する。ここも前回と同じ。

from sklearn.feature_extraction.text import TfidfVectorizer
tfidf_vectorizer = TfidfVectorizer(token_pattern='(?u)\\b\\w+\\b',lowercase=False)
tfidf_matrix = tfidf_vectorizer.fit_transform(df["text"])
terms = tfidf_vectorizer.get_feature_names()
tfidfs = tfidf_matrix.toarray()

df_TFIDF=pd.DataFrame(tfidfs,
                 index=df["ID"],
                 columns=terms)

・次に、cos類似度を算出する。それぞれの文章A~Fを、多次元のベクトルであるととらえ、cosを求める。ベクトルの内積をベクトルの長さで割れば良いのだけれど、前回scikit-learnのTF-IDFの定義てみたように、L2 normalizationされているので、各ベクトルの成分の二乗和は、どの文章も1になる。

sum(df_TFIDF.loc["A",:]**2)

1.0

・ということで、内積がそのままcosになり、1に近いほど文章の類似度が高いことになる。文章を二つずつピックアップしてやり、積を求めたMatrixを作成する。

import pandas as pd
temp1=
temp2=

for n in range(len(df)):
    for m in range(len(df)):
        temp1.append(sum(df_TFIDF.iloc[n,:]*df_TFIDF.iloc[m,:]))
    temp2.append(temp1)
    temp1=[]
df_cos_matrix=pd.DataFrame(temp2,
                       index=df["ID"],
                       columns=df["ID"])

・味気ないので、Heatmapにしてみる。

import seaborn as sns
%matplotlib inline
sns.heatmap(df_cos_matrix, vmin=0, vmax=1, cmap="Reds", annot=True)

・見てみると、文章Aと文章Dが一番高いスコアになっている。doctorとlawyerが入れ替わっただけの文章なので、まぁそんなものかなとも思う。だけど、aやto、tooなどのなくても意味が通じてしまう単語をdoctorやfatherなど文章を特徴づけるクリティカルな単語と同列に扱うのは無理があるような気がする。そういう意味では、doctorとlawyerが入れ替わっているのはそれなりに一大事にも思える。

・世の中的には、より特徴的な単語を抜き出して類似性を評価することがあるみたいなので、その辺も元気があれば少し見てみたい気がする。

 

おわり。