はじめに
エンジニアリングGの西場(@m_nishiba)です。 エムスリー Advent Calendar 2018に参加しています。
文書間の類似度計算をしたい。
エムスリーでは20以上のサービスを展開しています。各サービスごとにコンテンツのフォーマットが大きく異なるのですが、横断して類似するコンテンツを表示したいというニーズがあります。
例えば、下記の3つの文書があるとします。
例1
糖尿病患者に実践してほしい ○○○○○ ・演者:〇〇先生(大阪府立大学 地域保健学域) 【ライブ放送】 18:00〜18:40(17:30サイトオープン) ※ライブのみの1回限りの講演会です。
例2
喘息患者に実践してほしい ○○○○○ ・演者:〇〇先生(名古屋大学 地域保健学域) 【ライブ放送】 18:00〜18:40(17:30サイトオープン) ※ライブのみの1回限りの講演会です。
例3
糖尿病は、血糖値やヘモグロビンA1c(HbA1c)値が一定の基準を 超えている状態をさす疾患である。東洋医学では消渇と呼ばれる。 なお、腎臓での再吸収障害のため尿糖の出る腎性糖尿は別の疾患である。 (出典: wikipedia)
この例では、例1と例3が共に糖尿病という単語を含んでおり、似ていると判定したい組合せです。 逆に例1と例2はどちらも講演会の告知文であり、一般的には似ていると判定されそうですが、糖尿病と喘息ではターゲットユーザーが大きく異なるので似ていないと判定したいです。
さらに下記の文書のように 糖尿病という言葉を含んでいないですが、インスリンを含んでいるので似ていると判定したいです。
インスリン製剤の価格高騰により、患者の4人に1人が本来必要なインスリン治療を...
また単語や文書の観点では似ていないが同じユーザーが興味を持ちそうなものは似ていると判定したいです。 さらに例のごとくコールドスタート問題です。つまり新しい文書に対して関連する文書を探したいです。
方針
これらの問題を解くために下記のようなアプローチを取ります。
類似度
まず学習データとして下記のように類似度を事前に計算します。
- 文書自体の類似度として、同じ医療用語(疾患名・薬剤名)を含むものは似ているとする。
- ユーザー目線の類似度として、協調フィルタリングを行いcos類似度で関連度が高いもの(しきい値以上のもの)は似ているとする。
2つの方法で類似度を計算し、2つのうち少なくとも1つが似ていると判定したら、類似度を1とします。
またここでは医療用語として疾患名と薬剤名のみを使います。しかし、最終的にはそれらに含まれない"インスリン"や"glp-1"等の用語も考慮して類似度を計算したいので、医療用語間の類似度だけでは不十分になります。
文書の表現ベクトル
類似度を予測するために文書の表現ベクトルを計算します。計算方法としては下記の手法が候補になります。
- word2vec+平均
- word2vec+TFIDF
- doc2vec
- SCDV
今回はSCDVを使用します。アルゴリズムについては下記を参考にしてください。
- SCDV : Sparse Composite Document Vectors using soft clustering over distributional representations
- 文書ベクトルをお手軽に高い精度で作れるSCDVって実際どうなのか日本語コーパスで実験した(EMNLP2017)
- [論文メモ] SCDV : Sparse Composite Document Vectors using soft clustering over distributional representations
SCDVの良いところは各単語をGaussian Mixture Modelでクラスタリングを行い、文章中の単語を各クラスタごとに足し合わせていきます。これにより医療用語が他の用語に埋もれてしまうことを避けれることができるのではないかと期待しています。
類似の予測モデル
上記の方法で計算した類似度を文書の表現ベクトルから予測するモデルとしてXGBoostを使います。ここではハイパーパラメータのチューニング等は行いません。(※ 今後行います。)
入力として、2つの文書の表現ベクトルの要素積のベクトルを使います。 また、SCDVを使うときは使用する要素を限定します。詳しくは上記で紹介した論文やQiita記事を見てほしいのですが、SCDVの次元数は(word2vecの次元数) × (Gaussian Mixture Modelのクラスタ数)となり非常に大きくなります。
そこで、SCDVを使って薬剤名・疾患名の表現ベクトルを計算し、各要素を2乗して要素ごとに足し合わせ上位n個の要素を使用します。
Negative Sampling
学習用のデータの正例として類似度が1の組合せを使います。
負例のサンプリング方法は、類似度が0なものを各医療用語ごとに一定数をサンプリングします。また文書の表現ベクトルのcos類似度を計算し、類似度が0にもかかわらずcos類似度が高いものを負例に追加します。
結果
スコア
類似度 | precision | recall | f1-score | support |
---|---|---|---|---|
0 | 0.89 | 0.98 | 0.93 | 17279 |
1 | 0.88 | 0.58 | 0.70 | 4865 |
micro avg | 0.89 | 0.89 | 0.89 | 22144 |
macro avg | 0.89 | 0.78 | 0.82 | 22144 |
weighted avg | 0.89 | 0.89 | 0.88 | 22144 |
precisionはそこそこいいですが、類似度=1のrecallが悪いですね。しかし想定しているサービス上ではprecisionが重要になります。というのは関連コンテンツとして表示したときに関連していないコンテンツを表示することを避けたいからです。
キーワードに対する関連度の高い記事例
キーワードをタイトル・本文には含まないがキーワードと関連が高いと判断された記事の実例を紹介します。
アレルギー性鼻炎
- 季節性鼻炎に対する抑制作用
- 風邪ではないのにくしゃみと鼻水?
- 夏にも花粉は飛んでいる!イネ科の花粉症
アレルギー性鼻炎 という単語が含まれていないですが、それに関連しそうな記事が選ばれています。
糖尿病
- 持効型インスリンを基本とした2型糖尿病治療ストラテジー
- 日本人2型糖尿病治療の現状と今後
- SGLT2阻害薬を適正使用するポイント
2型糖尿病やSGLT2阻害薬といった糖尿病に関連する単語が含まれてる記事が選ばれています。
まとめ
SCDVを使うと、ある程度上手く医療用語に注目した文書の類似度の計算ができそうです。 訓練データの作り方、XGBoostのパラメータチューニング、GCNの適用など、実用化に向けて改善していく予定です。
We are hiring !
機械学習エンジニアを募集中です!