okpy

Pythonエンジニア兼テックリーダーが、多くのプロジェクトとチーム運営から得た実践的な知識を共有するブログです。

Pythonで「似ている文章」探し、もう迷わない!SentenceTransformers入門

Pythonで「似ている文章」探し、もう迷わない!SentenceTransformers入門

📝 TL;DR (3行要約)

SentenceTransformersは、文章をコンピュータが理解できる数値のリスト(ベクトル)に変換するためのPythonライブラリです。 文章同士が意味的にどれだけ似ているかを計算したり、意味に基づいた検索システムを構築する際に使われます。 複雑なモデルの知識がなくても、わずか数行のコードで高精度な文章のベクトル化を実現できるのが最大の利点です。


1. 🤔 一体SentenceTransformersとは何?(核心的な役割と主な使用例)

Pythonを学び始めると、テキストデータを扱う機会はたくさんありますよね。「この単語とあの単語は似ているかな?」くらいなら何とかなりそうですが、「この文章とあの文章は意味が似ている?」と聞かれたら、どうしますか?

キーワードが含まれているかチェックするだけでは、「車が走る」と「自動車が走行する」が同じ意味だと判定するのは難しいでしょう。ここで登場するのが、今回ご紹介するSentenceTransformersです!

核心的な役割: 文章のための「意味の翻訳機」兼「GPS」 🗺️

SentenceTransformersの核心的な役割をたとえるなら、それは「文章を意味の空間に配置するGPSです。

ちょっと想像してみてください。あらゆる「意味」が詰まった、広大な地図のような空間があるとします。例えば、「スポーツ」に関する意味が集まったエリア、「料理」に関する意味が集まったエリア、といった具合です。

私たちが「今日の天気は晴れです」という文章をSentenceTransformersに渡すと、ライブラリはそれを解析し、この広大な"意味の地図"上の正確な座標(緯度経度のようなもの)を計算してくれます。この座標こそが、コンピュータが扱える数値のリスト、専門用語でいう「ベクトル(vector)」「埋め込み(embedding)」と呼ばれるものです。

この「意味のGPS」が優れている点は、意味が近い文章は、地図上でも非常に近い位置にプロットされることです。

  • 「猫が日向ぼっこをしている」
  • 「子猫が暖かい場所で眠っている」

この2つの文章は、使われている単語は少し違いますが、意味はとても似ていますよね。SentenceTransformersは、これらを意味の地図上でごく近所の座標として示してくれます。

一方で、

  • 「宇宙旅行の費用はいくらですか?」

という文章は、全く違うエリアの、遠く離れた座標にプロットされるわけです。

このように、人間が感覚的に捉えている「意味の近さ」を、コンピュータが計算できる「座標(ベクトル)の距離」に変換してくれる。これがSentenceTransformersが解決してくれる根本的な問題であり、その核心的な役割なのです。

主な使用例: こんな時に大活躍! ✨

この「意味のGPS」機能は、具体的にどんな場面で役立つのでしょうか?代表的な例を3つ見てみましょう。

  1. 意味に基づいた検索(セマンティック検索) 🚀 従来の検索エンジンは、入力されたキーワード(単語)が文章に完全に一致するかどうかで検索結果を返していました。しかし、SentenceTransformersを使えば、キーワードが一致しなくても意味が類似している文章を見つけ出す「セマンティック検索」が実現できます。

    • 例: ECサイトのQ&Aで、ユーザーが「商品の届け先を変えたい」と検索したとします。過去のQ&Aに「配送先の住所変更は可能ですか?」という質問があれば、単語は違えど意味が同じなので、それを検索結果として提示できます。これにより、ユーザーは探している情報にたどり着きやすくなります。
  2. 文章の類似度計算 📏 2つの文章が、意味的にどれくらい似ているかを0から1(または-1から1)のスコアで数値化できます。これは、文章間の「意味の距離」を測るようなものです。

    • 例: オンライン学習サイトで、受講生からの質問が投稿された際に、それが過去の質問とどれくらい似ているかを自動で判定します。類似度が非常に高ければ、「この質問は、以前あったこちらの質問と似ています。回答を参考にしてください」とサジェストすることで、講師の負担を減らし、受講生はすぐに回答を得られます。
  3. 文章のクラスタリング(グループ分け) 📚 大量の文章データを、意味の似ているもの同士で自動的にグループ分け(クラスタリング)することができます。

    • 例: 顧客から寄せられた大量のレビューメールを分析する際に、SentenceTransformersで各レビューをベクトル化します。そして、そのベクトルをクラスタリングアルゴリズムにかけることで、「製品への要望」「配送に関する不満」「スタッフへの感謝」といったトピックごとに自動で分類できます。これにより、膨大なテキストデータから効率的にインサイトを得ることが可能になります。

このように、SentenceTransformersは、文章の「表面的な文字列」ではなく、その背後にある「意味」を捉えて活用するための、非常に強力なツールなのです。


2. 💻 インストール方法

インストールは非常に簡単です。ターミナル(またはコマンドプロンプト)を開いて、pipコマンドを一行実行するだけです。

pip install sentence-transformers

これだけで、必要なライブラリが一式インストールされます。簡単ですね!


3. 🛠️ 実際に動作するサンプルコード

それでは、実際にSentenceTransformersがどのように動作するのか、最も基本的な「文章のベクトル化」と「類似度計算」を行うコードを見てみましょう。 以下のコードをコピーして、example.pyのような名前で保存し、実行してみてください。

from sentence_transformers import SentenceTransformer, util

# 1. 事前学習済みの多言語対応モデルをロード
# 初回実行時は、モデルのダウンロードに少し時間がかかります。
print("モデルをロードしています...")
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
print("モデルのロードが完了しました。")

# 2. 比較したい文章のリストを準備
sentences = [
    "少年が公園でサッカーをしています。",
    "男の子がグラウンドでボールを蹴っています。",
    "美味しいレストランの予約方法を教えてください。",
    "その少女は静かに本を読んでいた。",
    "ディナーの席を確保するにはどうすればいいですか?"
]

# 3. 文章リストをベクトル(エンべディング)に変換
print("\n文章をベクトルに変換しています...")
embeddings = model.encode(sentences, convert_to_tensor=True)
print("ベクトル変換が完了しました。")

# 4. 最初の文章と他のすべての文章との類似度を計算
print("\n類似度を計算しています...")
# 基準となる文章は「少年が公園でサッカーをしています。」
target_embedding = embeddings[0]

# util.cos_simを使ってコサイン類似度を計算
# target_embedding と embeddings の全てのベクトルとの類似度を一括で計算します。
cosine_scores = util.cos_sim(target_embedding, embeddings)

# 5. 結果を表示
print("\n--- 計算結果 ---")
print(f"基準の文章: 「{sentences[0]}」\n")

for i in range(len(sentences)):
    # cosine_scores[0][i] でi番目の文章との類似度スコアを取得
    score = cosine_scores[0][i].item()
    print(f"比較対象: 「{sentences[i]}」")
    print(f"類似度スコア: {score:.4f}\n")

実行結果の例:

モデルをロードしています...
モデルのロードが完了しました。

文章をベクトルに変換しています...
ベクトル変換が完了しました。

類似度を計算しています...

--- 計算結果 ---
基準の文章: 「少年が公園でサッカーをしています。」

比較対象: 「少年が公園でサッカーをしています。」
類似度スコア: 1.0000

比較対象: 「男の子がグラウンドでボールを蹴っています。」
類似度スコア: 0.8682

比較対象: 「美味しいレストランの予約方法を教えてください。」
類似度スコア: 0.0357

比較対象: 「その少女は静かに本を読んでいた。」
類似度スコア: 0.1601

比較対象: 「ディナーの席を確保するにはどうすればいいですか?」
類似度スコア: 0.0528

結果を見ると、基準の文章と意味が非常に近い「男の子がグラウンドでボールを蹴っています。」のスコアが0.8682と非常に高くなっているのが分かります。一方で、全く関係のないレストラン予約に関する文章はスコアがとても低いですね。 このように、単語が完全に一致していなくても、文脈や意味を捉えて類似度を計算できていることが一目瞭然です!


4. 🔍 コードの詳細説明

先ほどのサンプルコードが何をしているのか、少し詳しく見ていきましょう。一行ずつではなく、意味のあるかたまり(チャンク)ごとに解説します。

【チャンク1】ライブラリとモデルの準備 📚

from sentence_transformers import SentenceTransformer, util

print("モデルをロードしています...")
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
print("モデルのロードが完了しました。")
  • from ... import ...: まず、sentence-transformersライブラリから必要な道具であるSentenceTransformerクラスと、便利な関数群が入ったutilをインポートします。
  • SentenceTransformer(...): これがライブラリの心臓部です。ここで、文章をベクトルに変換するための「脳」となる事前学習済みモデルを指定して読み込んでいます。
  • 'paraphrase-multilingual-MiniLM-L12-v2': これはモデルの名前です。世界中の開発者が事前に大量のテキストデータを学習させて作った、賢いモデルの一つです。multilingualと名前にある通り、日本語を含む多くの言語に対応しているため、非常に汎用性が高く便利です。初回実行時に自動でダウンロードされるため少し時間がかかりますが、2回目以降はPCに保存されたものを読み込むので高速です。

【チャンク2】文章のベクトル化 🔢

sentences = [ ... ] # 比較したい文章のリスト

print("\n文章をベクトルに変換しています...")
embeddings = model.encode(sentences, convert_to_tensor=True)
print("ベクトル変換が完了しました。")
  • model.encode(sentences, ...): ここが、先ほど説明した「意味のGPSで座標を計算する」処理に相当します。encodeメソッドに文章のリストを渡すだけで、リスト内の各文章がそれぞれ数値のリスト(ベクトル)に変換されます。
  • embeddingsという変数には、5つの文章に対応する5つのベクトルが格納されています。一つ一つのベクトルは、このモデルの場合384個の数値からなるリスト(配列)です。この384個の数値の組み合わせが、意味の地図上でのユニークな座標を表しているのです。

【チャンク3】類似度の計算と結果表示 📊

target_embedding = embeddings[0]
cosine_scores = util.cos_sim(target_embedding, embeddings)

print("\n--- 計算結果 ---")
# ... (forループで結果を表示)
  • util.cos_sim(...): 2つのベクトルがどれだけ似ているかを計算するための便利な関数です。ここではコサイン類似度(Cosine Similarity)という指標を計算しています。
  • コサイン類似度は、ベクトルの「向き」がどれだけ似ているかを示す指標で、-1から1の間の値を取ります。
    • 1 に近いほど、意味が非常に似ている(同じ方向を向いている)。
    • 0 に近いほど、意味に関連性がない(直角に交わっている)。
    • -1 に近いほど、意味が正反対である(逆の方向を向いている)。
  • ここでは、基準となる文章のベクトル (target_embedding) と、全文章のベクトル (embeddings) との類似度を一括で計算しています。
  • 最後のforループは、計算されたスコアを人間が見やすいように一つずつ取り出して表示しているだけです。score.item()は、計算結果のテンソル(PyTorchのデータ形式)から純粋な数値を取り出すためのおまじないだと考えてください。

5. ⚠️ 注意点またはヒント

このライブラリを使い始める際に、初心者が特に注意すべき点と、知っておくと便利なヒントを1つずつご紹介します。

⚠️ 注意点: モデル選びは慎重に!日本語には多言語モデル

SentenceTransformersには、用途に応じて様々な事前学習済みモデルが用意されています。しかし、英語のドキュメントや記事を参考にしていると、うっかり英語専用のモデル(例: 'all-MiniLM-L6-v2')を選んでしまうことがあります。

英語専用モデルで日本語の文章をベクトル化しようとすると、期待したような精度が出ません。未知の文字として扱われてしまい、意味を正しく捉えられないためです。

必ず、日本語を扱う場合は、サンプルコードで使ったようなmultilingual(多言語)と名前がついたモデルや、日本語に特化して学習されたモデルを選んでください。

どのモデルを選べば良いか迷ったら、まずはサンプルコードの'paraphrase-multilingual-MiniLM-L12-v2'を使ってみるのがおすすめです。性能と速度のバランスが良く、多くのケースで十分な結果を得られます。

✨ ヒント: 大量のデータを扱うならバッチ処理が高速

model.encode()メソッドは、一度にたくさんの文章をリストとして渡すことで、内部で効率的に処理(バッチ処理)を行うように設計されています。

例えば、1000個の文章をベクトル化したい場合、forループで1文ずつencodeを呼び出すのは非常に非効率です。

# 悪い例 ❌ (処理が遅い)
embeddings = []
for sentence in sentences:
    emb = model.encode(sentence)
    embeddings.append(emb)

# 良い例 👍 (処理が速い)
embeddings = model.encode(sentences)

数個の文章なら違いは分かりませんが、数百、数千といった単位のデータを扱う場合は、リストにまとめて一度に渡すだけで処理速度が劇的に向上します。ぜひ覚えておいてください。


6. 🔗 一緒に見ておくと良いライブラリ

scikit-learn (サイキット・ラーン)

SentenceTransformersで文章をベクトルという「数値データ」に変換した後に、次にしたくなることは何でしょうか?多くの場合、その数値データを使った機械学習です。

scikit-learnは、Pythonで最も有名で使いやすい総合機械学習ライブラリです。

  • クラスタリング: SentenceTransformersで得たベクトルをscikit-learnKMeansアルゴリズムに入力すれば、簡単に文章のトピック分類ができます。
  • 分類: ポジティブ/ネガティブなレビューを分類するモデルを作る際も、ベクトルをscikit-learnの分類器(ロジスティック回帰やSVMなど)で学習させることができます。

SentenceTransformersが「文章を機械学習で扱える形に整える前処理」だとすれば、scikit-learnは「そのデータを使って予測や分類を行う本処理」を担当します。この2つを組み合わせることで、自然言語処理でできることの幅がぐっと広がりますよ。


7. 🎉 まとめ

今日はお疲れ様でした!最後に、学んだことの要点を振り返りましょう。

  • SentenceTransformersとは?: 文章を「意味の座標」であるベクトルに変換してくれる、強力なPythonライブラリです。
  • 何ができる?: 文章の類似度計算、意味に基づいた検索、テキストのクラスタリングなど、文章の意味を扱う様々なタスクに応用できます。
  • 使い方は?: SentenceTransformerでモデルを読み込み、model.encode()で文章をベクトル化し、util.cos_sim()で類似度を計算するのが基本の流れです。
  • 注意点は?: 日本語を扱う際は、必ず多言語対応(multilingual)モデルなどを選びましょう。

このライブラリの素晴らしさは、そのシンプルさにあります。これまで自然言語処理の専門家でなければ難しかった高度なタスクが、本当に数行のコードで実現できてしまうのです。

さあ、次はあなたの番です!

【挑戦課題】 🚀 あなたの好きな本、映画、またはアニメのあらすじを3〜5つほどインターネットで探してきて、今日のサンプルコードのsentencesリストを書き換えてみてください。そして、どの作品とどの作品が「物語のテーマ」として似ていると判定されるか、その類似度スコアを観察してみましょう!きっと面白い発見がありますよ。

この記事が、あなたのPython自然言語処理の世界への扉を開く、小さなきっかけになれば幸いです。

Happy Coding!