知財のあれこれをPythonで何とかする

### ローカルファイルの特許リストの中からあいまい検索する
今回のテーマは「ローカルファイル化した特許リストからユーザ指定文を用いてPythonによりあいまい検索を行う」です。
AIチャットであいまい検索させるのも考えられますが特許リストが大量になるとデータ過多で処理が止まるおそれがあります。Pythonのローカル処理であれば大量のリストであっても処理が可能です。

### 特許リスト（ローカルファイル）の準備
まず特許リスト（ローカルファイル）を準備します。以下のサンプルデータをメモ帳にコピペして「エンコード」の設定で文字コードUTF-8形式でファイル名「list」、拡張子csvで保存してください。（今回もヤマハ株式会社さんの公報を利用させていただきました)
ご自分で特許リストを準備する場合、xlsxファイルでしたらサンプルと同様に1行目にnumber,summaryを記入してファイル名「list」、拡張子csvで保存してください。そのままだとExcelの文字コードがANSIのためUTF-8に変換する必要があります。変換作業としてはcsvファイルをメモ帳で開き、あとは上記の手順と同様に保存→「エンコード」の設定をANSIからUTF-8にする→上書き保存で文字コードの変換ができます。
注意事項：リストに空白セルがあるとエラーの原因になります。(あらかじめ削除しておく)

### サンプルデータ

```:list.csv
number,summary
特許7666767,【要約】  スピーカ用振動板は、主成分として熱可塑性樹脂を含む樹脂マトリックスと、樹脂マトリックス中に分散された繊維と、を有する基材を備える。繊維は、局所的に繊維が折れ曲がって破壊されている複数の損失領域、もしくは繊維の平均直径よりも５％～５０％大きい直径を有する複数の損失領域を有する。
特許7663147,(57)【要約】【課題】複数のチェンバーを有するエレクトリックギターのボディの音響現象を制御できるようにする。【解決手段】互いに間隔をあけて形成された第一チェンバー２４及び第二チェンバー２４と、第一チェンバー２４及び第二チェンバー２４を接続するスリット２５と、を有するボディ２０を備え、スリット２５に収納される吸音材を有するエレクトリックギターのボディ構造体２を提供する。【選択図】図２
特許7666692,(57)【要約】【課題】磁気誘導型センサを用いる操作装置の製造工程を容易化すること。【解決手段】鍵盤装置は、それぞれ導電体が配置された第１基板および第２基板を含み、前記第１基板と前記第２基板との距離を測定するための距離センサと、操作者によって操作可能な鍵と、前記鍵と前記第２基板との間において前記第１基板を保持する保持部であって、弾性変形可能な部分を有し、前記弾性変形可能な部分が変形することに応じて前記第１基板が変位する保持部と、を備える。【選択図】図２７
特許7658481,(57)【要約】【課題】簡易な鍵の支持構造により、鍵盤装置の外観の品質を向上させること。【解決手段】鍵盤装置の鍵の支持構造は、第１部材と、断面視において、前記第１部材に対して第１接点及び第２接点を有する第２部材と、断面視において、前記第１部材に対して第３接点を有する第３部材と、を備え、前記第１部材は、前記第２部材及び前記第３部材との間で構成される前記第１接点、前記第２接点及び前記第３接点により支持され、前記第１部材は鍵後端部の軸部であり、前記第２部材は第１軸受部である。【選択図】図１１
特許7666041,(57)【要約】【課題】仮想音源の音と対象空間で放音される模擬再生音とを比較可能にする。【解決手段】  音場支援方法は、仮想空間上で設定される音源の位置情報と、対象空間に設定されるスピーカからの出力音で音源の音を模擬するときの音源の定位情報と、のいずれか一方を選択し、選択された位置情報および定位情報に基づく音を用いて、スピーカによる音源の音像定位を調整する。【選択図】図１
特許7643113,(57)【要約】【課題】仮想空間での音像定位を明瞭に再現する。【解決手段】  音信号処理方法は、目的の音響空間の反射音を示す仮想音源を、スピーカの位置と受音点の位置との間に位置し、目的の音響空間の反射音の第１音源を示す第１仮想音源と、スピーカの外側に位置し、目的の音響空間の反射音の第２音源を示す第２仮想音源と分類し、第１仮想音源の場合のみ、第１仮想音源の近傍のスピーカの位置を用いて再生可能な位置に第１仮想音源の位置を移動する。【選択図】図１８
```
今回もcopilotに助けてもらって以下のサンプルプログラムを作成しました。
プログラムを実行するにはpythonのライブラリ「pandas」「scikit-learn」「Janome」のインストール（pip install pandas janome scikit-learn）が必要です。
ちなみに
scikit-learn：自然言語処理ライブラリ
Janome：形態素解析ライブラリ
pandas：データ解析ライブラリ
となります。

### サンプルプログラム

```python:program1.py
import janome.tokenizer
import numpy as np
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

# 特許リスト
df = pd.read_csv('list.csv')
patents = df.to_dict(orient='records')

# 指定文
target_text = input("検索したい文を入力してください　")

# Janomeで形態素解析
tokenizer = janome.tokenizer.Tokenizer()
def tokenize(text):
    return " ".join([token.base_form for token in tokenizer.tokenize(text) if token.part_of_speech.startswith("名詞")])

# 特許要約の処理
texts = [tokenize(p["summary"]) for p in patents]
texts.append(tokenize(target_text))  # 指定文も追加

# TF-IDFベクトル化
vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(texts)

# 類似度計算
cos_similarities = cosine_similarity(tfidf_matrix[-1], tfidf_matrix[:-1])[0]

# 上位3件の特許を取得
top_indices = np.argsort(cos_similarities)[-3:][::-1]  # 類似度の高い順に並べる

# 結果を表示
print("指定文に最も類似する上位3件の特許:")
for idx in top_indices:
    best_match = patents[idx]
    print(f"特許番号: {best_match['number']}")
    print(f"要約: {best_match['summary']}")
    print(f"一致率: {cos_similarities[idx]:.4f}")
    print("-" * 50)
```
(プログラムの解説)
・Janomeで形態素解析：形態素解析ツールjanomeで特許リストの要約を単語に分割するtokenize関数を宣言。
・特許要約の処理：tokenize関数を使ってlist.csvの複数の要約を処理し、名詞を抽出したリスト texts を作成。また、ユーザの入力した指定文 (target_text) もリストに追加。
・TF-IDFベクトル化：テキストデータをベクトル化する(特徴量の抽出)。
・類似度計算:scikit-learnにおけるcosine_similarity関数を使用する。ユーザが入力した指定文(tfidf_matrix[-1]→最後の要素が該当) とlist.csvに含まれる要約 (tfidf_matrix[:-1]) のコサイン類似度を求める。cosine_similarity() は 2D配列のため[0]を使って1D配列（リスト）に変換。
・上位3件の特許を取得：np.argsort(cos_similarities)[-3:]で最も類似度が高い3つ（末尾から3つの要素）を取得。[::-1]で末尾から3つの要素を逆順にする。
・結果を表示：cos_similarities[idx]:.4fの「:.4f」で一致率の表示を小数点以下4桁の固定小数点数形式に整形。

### 実行してみた
プログラムを実行すると「検索したい文を入力してください」と表示されるので、試しにサンプル内の1件をコピペして入力してください。一致率で上位3件が表示されます。一致率１位は当然ながら入力した案件自体となりますので、2位以下が比較的近しいものであれば、プログラムが想定通り動いていることがわかると思います。
また近くない案件ほど一致率が低いことが把握できます。
なお専門用語の同義語までは検索でカバーしてくれないようです(ここら辺が汎用ツールの限界なのかも)。
### おまけ
形態素解析ライブラリのJanomeの代わりにMecabを使ってみました。
実行前にライブラリ（Mecab）と辞書（IPAdic、標準辞書）を追加でインストールしてください（pip install Mecab ipadic）。Mecabだと辞書データが編集できるので辞書データのカスタマイズ次第でヒット率を改善できるかもしれません。これは今後の課題とします。

<details><summary>program2</summary>

```python:program2.py
import MeCab
import ipadic
mecab = MeCab.Tagger(ipadic.MECAB_ARGS)   # インストールした辞書を指定
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import csv

# [指定文]
query_text = input("検索したい文を入力してください")

# CSVファイルのパス
csv_file = "list.csv"

# 空の辞書を作成
patents = {}

# CSVを読み取り、辞書に変換
with open(csv_file, newline='', encoding="utf-8") as f:
    reader = csv.reader(f)
    next(reader)  # ヘッダーをスキップ
    
    for row in reader:
        patent_id = f"{row[0]}"  # キーにする
        patents[patent_id] = row[1]

# MeCabで形態素解析
query_tokens = mecab.parse(query_text).strip()
patent_tokens = {k: mecab.parse(v).strip() for k, v in patents.items()}

# TF-IDFベクトル化
vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform([query_tokens] + list(patent_tokens.values()))
cos_similarities = cosine_similarity(tfidf_matrix[0:1], tfidf_matrix[1:]).flatten()

# 類似度上位3つを抽出
top_indices = cos_similarities.argsort()[-3:][::-1]
top_patents = [(list(patents.keys())[i], list(patents.values())[i], cos_similarities[i]) for i in top_indices]

# 結果表示
print("最も類似する特許トップ3:")
for rank, (patent_num, summary, similarity) in enumerate(top_patents, 1):
    print(f"{rank}. 特許番号: {patent_num}")
    print(f"   要約: {summary}")
    print(f"   類似度: {similarity:.4f}")
    print("-" * 50)
```
</details>

### 最後に

市販の特許検索ソフトではあいまい検索を特徴としているものがありますが、いったん特許リストを作成しローカル保存してしまうとその中からさらにあいまい検索することはできず、リストの活用を困難にしていました。
上記の手法でローカルリストからあいまい検索が可能になれば活用性を上げられると思います。
今回はpythonライブラリとして初めて「scikit-learn」「Janome」「Mecab」を使ってみましたがこういった豊富なライブラリがVBAには無いPythonの魅力ではないかと思います。

今回の記事が何らかの助けになれば幸いです。