6月からの調剤報酬改定で「特定薬剤管理指導加算3のイ」が新設された。これに伴って世の薬局では、在庫とRMP提出品目の照らし合わせや、患者向けRMP資料の製薬会社への資料請求が行われている。みんな大変やなぁ。
かく言う私も勤務する薬局でも同様の対応を行っており、私がこの件の担当となった。本記事では私が行った手順を書いていく。
RMP提出品目の元データ
まず、RMP提出品目で尚且つ患者向け資料がある薬品のデータをリストアップする必要があるわけだが、それにはこのサイトで先人が作成したデータを利用した。
ここですごいのが、患者向け資料がないものがちゃんと落とされていたことである。自分がパッと調べた感じだと、患者向け資料の有無はPMDAのサイトから一つ一つ潜って調べる必要があり、これを全部やったのかと思うとすごい。先人の努力には感謝しかない。感謝以外何もない。先人の努力に拍手。しかもYJコードでの突合ができるようにしてある。素晴らしい。
類似距離算出
しかし、私が勤務する薬局の在庫管理システムではYJコードを出力できず(もしかしたら出せるのかもしれないが)、薬品名は取り出すことができたため、名称類似性でフィルタリングを行う必要があった。
そこでfuzzywuzzを使用し、以下のコードを実行した。上記の薬品名データと薬局在庫の商品名のカラムをcsvにして食わせれてば下準備はOK。Google Colablatoryで動作させたが、おそらくローカル環境でもそこまで重くならないと思うので、ChatGPTなどを活用してPythonを実行できる環境を整えれば利用可能である。
!pip install fuzzywuzzy
!pip install python-Levenshtein
import pandas as pd
import re
from fuzzywuzzy import fuzz, process
# Load the CSV file
file_path = 'set/your/file.csv'
df = pd.read_csv(file_path, encoding='cp932')
# Preview the dataframe to understand its structure
df.head()
# 前処理を名前に適用
medicine_names = df['薬品名'].dropna().tolist()
product_names = df['商品名'].dropna().tolist()
# 頭文字が一致するmedicine_namesのリストを取得する関数
def get_matching_medicine_names(product_name, medicine_names):
first_char = product_name[0]
return [name for name in medicine_names if name.startswith(first_char)]
# 各商品名に対して、頭文字が一致する薬品名を抽出し、ファジーマッチングを行う
results = []
for product in product_names:
matching_medicines = get_matching_medicine_names(product, medicine_names)
top_matches = process.extract(product, matching_medicines, limit=3)
for match in top_matches:
results.append((product, match[0], match[1]))
# 結果をデータフレームに変換
results_df = pd.DataFrame(results, columns=['商品名', '薬品名', 'スコア'])
# 各薬品名に対してスコア上位3つのデータ行のみを残すフィルタリング処理
results_df = results_df.sort_values(by=['薬品名', 'スコア'], ascending=[True, False])
results_df = results_df.groupby('薬品名').head(3)
results_df
# 薬品名ごとに最高スコアの範囲を確認し、その範囲にすべての項目を含める
results_df['範囲'] = pd.cut(results_df['スコア'], bins=[-1, 34.999, 39.999, 44.999, 49.999, 54.999, 100], labels=['<35', '35-40', '40-45', '45-50', '50-55', '55-100'])
grouped = results_df.groupby('薬品名')
# 各スコア範囲ごとにデータを分けるための辞書
range_dfs = {label: pd.DataFrame(columns=results_df.columns) for label in ['<35', '35-40', '40-45', '45-50', '50-55', '55-100']}
# 各薬品名のデータを適切な範囲に振り分ける
for name, group in grouped:
top_range = group['範囲'].iloc[0]
range_dfs[top_range] = pd.concat([range_dfs[top_range], group])
# エクセルファイルに保存
for label, df in range_dfs.items():
if not df.empty: # 空のデータフレームは保存しない
file_path = f'set/your/dir/matched_results_{label}.xlsx'
df.to_excel(file_path, index=False)
処理の流れとしては、まず薬品名データと薬局在庫の商品名のリストを取得するところから始める。薬品名と商品名のリストが用意できたら、次に各商品名に対して頭文字が一致する薬品名のリストを取得する。このステップでは、商品名の最初の文字に基づいて薬品名をフィルタリングし、関連性の高い候補を絞り込む。
次に、fuzzywuzzyライブラリを使用してファジーマッチングを行う。具体的には、各商品名に対して抽出された薬品名リストから最も類似性の高い上位3つのマッチを見つけ出す。このマッチングは、商品名と薬品名の間の文字列の類似度を計算することで行われる。
マッチングが完了したら、結果をスコアの高い順に並べ替える。スコアが高いほど、商品名と薬品名の一致度が高いことを示している。その後、各薬品名に対してスコア上位3つのデータ行のみを残すフィルタリング処理を行う。これにより、最も関連性の高いマッチのみがリストに残る。
さらに、スコア範囲ごとにデータを分け、各範囲に属するデータを別々のエクセルファイルに保存する。これにより、必要に応じて特定のスコア範囲のデータを簡単に参照できるようにする。例えば、「55-100」のスコア範囲に属するデータは高い一致度を持つため、優先的に確認することができる。
ここまで数が減ったら目視でも行けるくらいになるので、目検でがんばる。がんばれ。多分50未満くらいだったらもうヒットしないと思うので見なくてもいいと思う。
あとは電話をかけろ!!
あとは電話をかけろ!!なんやかんやこれが一番めんどくさい。
ちなみにデエビゴの指導箋は今品切れしてるっぽい。指導箋も品切れするんやなぁ。
コメント
コメントを投稿するにはログインしてください。
リプライするにはログインしてください。
リプライするにはログインしてください。
リプライするにはログインしてください。
リプライするにはログインしてください。