【Python】文字列の類似度を測るdifflib.SequenceMatcherの使い方

みなさん,こんにちは。
シンノユウキ(shinno1993)です。

今回はPythonを使用して文字列の類似度を調べる方法を紹介します。

2つの文字列があり,それらがどのくらい類似しているか。これを使うことで,人の目に近い形で重複を検出できるようになるかもしれません。

Pythonには,標準ライブラリとしてdifflibが搭載されており,それに含まれるSequenceMatcherを使用することで目的を達成できそうですので,下記で紹介していきます。

2つの文字列の類似度を表示する

文字列の類似度を表示するためには,difflibSequenceMatcherを使用します。さっそくコードを示すと,下記になります:

from difflib import SequenceMatcher

str1 = "ほうれんそうの明太子和え"
str2 = "ほうれんそうのたらこ和え"

s = SequenceMatcher(None, str1, str2)
print(s.ratio())
0.75

結果として,下記のように「0.75」がプリントされます。「ほうれんそうの明太子和え」と「ほうれんそうのたらこ和え」の類似度が75%であるということですね。

SequenceMatcherは下記のように使用することができます:

s = SequenceMatcher(None, 比較する文字列1, 比較する文字列2)

引数の2つ目と3つ目に比較したい文字列を指定します。なお,類似度を測りたい場合は,ratioメソッドを使用します:

s.ratio()

なお,SequenceMatcherの類似度計算では,「ゲシュタルトパターンマッチング」というアルゴリズムを使用しているそうです。私は詳しくわかりませんので,詳細は割愛。

リストからキーワードに類似の文字列を抽出する

あるリストから,特定のキーワードに類似している文字列を抽出することもできます。これには,get_close_matchesを使用します。まずはコードを見てみましょう。

from difflib import get_close_matches

keyword = "ほうれんそうとえのきの和え物"
lst = [
    "ほうれんそうとエリンギのごま和え",
    "ほうれんそうの明太子和え",
    "ほうれんそうのたらこ和え",
    "ほうれんそうとにんじんのごま和え",
    "ほうれんそうのおかか和え",
    "ほうれんそうのごま和え",
    "ほうれんそうのソテー",
    "ほうれんそうのソテー温泉たまごのせ",
]
ret = get_close_matches(keyword, lst, n=3, cutoff=0.6)
print(ret)
['ほうれんそうのごま和え', 'ほうれんそうの明太子和え', 'ほうれんそうのたらこ和え']

結果として,3つの文字列がプリントされています。リスト中の文字列のうち「ほうれんそうとえのきの和え物」に似た文字列として,「ほうれんそうのごま和え」,「ほうれんそうの明太子和え」,「ほうれんそうのたらこ和え」が抽出できました。

get_close_matchesは下記のように使用することができます:

get_close_matches(キーワード, 文字列のリスト, n=3, cutoff=0.6)

  • キーワード:マッチさせたい文字列を指定します。
  • 文字列のリスト:マッチさせる文字列のリストを指定します。
  • n:マッチされた文字列のうち,上位何件を返すかを指定します。デフォルトは3です。
  • cutoff:何パーセント以上の一致率であれば表示するかを指定します。デフォルトは0.6です。つまり,一致率が60%未満であればマッチしたことになりません(表示されません)。

リストから類似の文字列の組み合わせを抽出する

最後に,1つのリスト中から類似している文字列の組み合わせを抽出する方法を紹介します。コードは下記のようになります。

from difflib import SequenceMatcher
import itertools

lst = [
    "ほうれんそうとえのきの和え物",
    "ほうれんそうとエリンギのごま和え",
    "ほうれんそうの明太子和え",
    "ほうれんそうのたらこ和え",
    "ほうれんそうとにんじんのごま和え",
    "ほうれんそうのおかか和え",
    "ほうれんそうのごま和え",
    "ほうれんそうのソテー",
    "ほうれんそうのソテー温泉たまごのせ",
]

for i in itertools.combinations(lst, 2):
    s = SequenceMatcher(None, *i)
    if s.ratio() > 0.7:
        print('類似度:{0}%,{1}'.format(round(s.ratio()*100,1), i))
類似度:72.0%,('ほうれんそうとえのきの和え物', 'ほうれんそうのごま和え')
類似度:75.0%,('ほうれんそうとエリンギのごま和え', 'ほうれんそうとにんじんのごま和え')
類似度:81.5%,('ほうれんそうとエリンギのごま和え', 'ほうれんそうのごま和え')
類似度:75.0%,('ほうれんそうの明太子和え', 'ほうれんそうのたらこ和え')
類似度:75.0%,('ほうれんそうの明太子和え', 'ほうれんそうのおかか和え')
類似度:78.3%,('ほうれんそうの明太子和え', 'ほうれんそうのごま和え')
類似度:75.0%,('ほうれんそうのたらこ和え', 'ほうれんそうのおかか和え')
類似度:78.3%,('ほうれんそうのたらこ和え', 'ほうれんそうのごま和え')
類似度:81.5%,('ほうれんそうとにんじんのごま和え', 'ほうれんそうのごま和え')
類似度:78.3%,('ほうれんそうのおかか和え', 'ほうれんそうのごま和え')
類似度:74.1%,('ほうれんそうのソテー', 'ほうれんそうのソテー温泉たまごのせ')

itertools.combinationsを使用することで,リスト中のすべての文字列の組み合わせで類似度を測定しています。そして,類似度が0.7より高い場合は,プリントしています。0.7がカットオフ値です。

まとめ

今回は,Pythonを使用してPythonを使用して文字列の類似度を調べる方法を紹介しました。

目的によって下記の3つを紹介しました:

  1. 2つの文字列の類似度を表示する
  2. リストからキーワードに類似の文字列を抽出する
  3. リストから類似の文字列の組み合わせを抽出する

どなたかの参考になれば幸いです。

タイトルとURLをコピーしました