ChatGPTに、二つの文章の類似度を判定してもらうPythonプログラムを書いてもらった

ChatGPTに、二つの文章の類似度を判定してもらうPythonプログラムを書いてもらいました。最初の指示だとあまり使えないコードが出力されたので、そのあとに改良版として少し具体的に指示した結果ものせてます。

指示文(プロンプト)1:

二つの文章の類似度を判定するpythonプログラムを提示ください。比較する文章は標準入力とします。

回答:

以下はPythonで二つの文章の類似度を判定するプログラムの例です。入力された文章を前処理し、テキストの類似度を計算するためにcosine類似度を使用しています。


import re
from collections import Counter
import math

def preprocess(text):
    # テキストの前処理を行う関数
    text = text.lower()  # 小文字に変換
    text = re.sub(r'\W+', ' ', text)  # 英数字以外の文字を削除
    text = re.sub(r'\s+', ' ', text)  # 連続するスペースを1つに置換
    return text

def get_cosine_similarity(text1, text2):
    # 2つのテキストのcosine類似度を計算する関数

    # テキストを前処理
    text1 = preprocess(text1)
    text2 = preprocess(text2)

    # テキストを単語に分割
    words1 = text1.split()
    words2 = text2.split()

    # 単語の出現回数をカウント
    word_count1 = Counter(words1)
    word_count2 = Counter(words2)

    # 共通の単語の出現回数を取得
    common_words = set(word_count1.keys()) & set(word_count2.keys())

    # cosin類似度の計算に必要な分子と分母を計算
    numerator = sum([word_count1[word] * word_count2[word] for word in common_words])
    denominator1 = sum([word_count1[word] ** 2 for word in words1])
    denominator2 = sum([word_count2[word] ** 2 for word in words2])

    # 分子と分母が共に0であれば類似度は0とする
    if denominator1 == 0 or denominator2 == 0:
        similarity = 0
    else:
        similarity = numerator / (math.sqrt(denominator1) * math.sqrt(denominator2))

    return similarity

if __name__ == '__main__':
    # 比較する2つの文章を標準入力から取得
    text1 = input('1つ目の文章を入力してください: ')
    text2 = input('2つ目の文章を入力してください: ')

    # 2つの文章の類似度を計算
    similarity = get_cosine_similarity(text1, text2)

    # 類似度を出力
    print('2つの文章の類似度は: {:.2%}'.format(similarity))

        

このプログラムは、2つの文章を入力として受け取り、cosine類似度を計算して出力します。cosine類似度は0から1の値を取り、1に近いほど類似していることを示します。類似度が高いほど、2つの文章の内容が似ていると言えます。

結果:

一応、動作はしますが、精度が全然よくありません。下記はほぼ同じ文章を、単語の言い換えや言い回しの変更のみを施したものです。

まったく同じ文章の場合は100%:

少しだけ違う文章にしたら44.7%

指示文(プロンプト)2:

二つの文章の類似度を判定するpythonプログラムを提示ください。比較する文章は標準入力とします。精度を上げるために、形態素解析も使ってください。

回答:

import MeCab
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

# MeCabのインスタンスを作成
mecab = MeCab.Tagger()

# 文章を入力
text1 = input("文1を入力してください: ")
text2 = input("文2を入力してください: ")

# 文章を形態素解析して単語に分割する関数
def tokenize(text):
    tokens = mecab.parse(text)
    tokens = [t.split('\t')[0] for t in tokens.split('\n')]
    return tokens[:-2]

# TfidfVectorizerを用いて文書をベクトル化する
vectorizer = TfidfVectorizer(tokenizer=tokenize)
tfidf_matrix = vectorizer.fit_transform([text1, text2])

# コサイン類似度を計算する
similarity = cosine_similarity(tfidf_matrix[0:1], tfidf_matrix[1:2])

# 類似度を出力
print("類似度: ", similarity[0][0])        
        
結果:

以下のように、かなり良い精度になりました。

単語が少し違うだけの文章の比較:

文章の前後を入れ替えたもので、意味は同じ:

全く違う文章:

形態素解析janomeを指定した場合:

形態素解析MeCabではなく、Janomeを指定したプロンプトへの回答はこちら。JanomeはPure pythonでインストールが楽なので、MeCabがない環境でさくっとやりたいときなどに。


from janome.tokenizer import Tokenizer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

def tokenize(text):
    """文章を形態素解析してトークン化する関数"""
    tokenizer = Tokenizer()
    tokens = [token.surface for token in tokenizer.tokenize(text)]
    return tokens

def calculate_similarity(text1, text2):
    """二つの文章の類似度を計算する関数"""
    # 形態素解析してトークン化
    tokens1 = tokenize(text1)
    tokens2 = tokenize(text2)
    
    # 文章を単語のリストに結合
    text1 = " ".join(tokens1)
    text2 = " ".join(tokens2)
    
    # TF-IDFベクトル化
    vectorizer = TfidfVectorizer()
    tfidf_matrix = vectorizer.fit_transform([text1, text2])
    
    # コサイン類似度を計算
    similarity = cosine_similarity(tfidf_matrix[0], tfidf_matrix[1])
    
    return similarity[0][0]

if __name__ == "__main__":
    # 入力された二つの文章を取得
    text1 = input("文章1を入力してください: ")
    text2 = input("文章2を入力してください: ")

    # 類似度を計算
    similarity = calculate_similarity(text1, text2)

    # 類似度を出力
    print("二つの文章の類似度: {:.2f}".format(similarity))

    
結果:

こちらもきちんと動作しますが、精度は少しだけ落ちるかも。