医療通訳支援Webアプリ第2弾 医療通訳対応記録システム

The record system for medical interpretation in a hospital(English only)

医療通訳担当者(英語)のための通訳後記(反省録)保管システム

f:id:HealthcareIT_interpreter:20170514165043p:plain

医療機関のスタッフが医療通訳の現場経験を記録しておき、後学に生かすためのシステムです。

機能1: 対応記録記入(データベースへの書き込み)

以下の情報を記載可能です。(1案件ごとに書き込む方式です)

  • 通訳実施者氏名
  • 通訳開始日時
  • 通訳終了日時
  • 依頼者
  • 依頼部署
  • 外国人患者さんの入外区分
  • 外国人患者さんの国籍
  • サマリー

f:id:HealthcareIT_interpreter:20170514165055p:plain f:id:HealthcareIT_interpreter:20170514165106p:plain

データベースはSQLite3を使用。同時多発的書き込みに対応するため将来的にはPosgresに変更予定。

機能2: 対応記録表の表示(データベースのテーブルを表示)

機能1で書き込んだ内容を確認できます。検索機能あり。そのため例えば「眼科だけの対応記録」を眼科から通訳依頼を受けた直後にささっとおさらいをして現場に入るといった使い方が可能です。その他特定の文言が記載されたレコードだけ絞り込む機能もあり。f:id:HealthcareIT_interpreter:20170514165119p:plainf:id:HealthcareIT_interpreter:20170514165131p:plain

JavaScriptのライブラリVue.jsのグリッドコンポーネント機能を借用させていただきました。(中身については目下勉強中) https://jp.vuejs.org/v2/examples/grid-component.html

機能3: 累積対応時間のビジュアライゼーション(対応時間を月別にスタックバーチャートとして表示)

担当者別に出ます。医療通訳系の資格を取る際現場実習時間の報告とかに使えるかなと。集計したい期間を選択し、Getボタンを押すとpngファイルをダウンロードできます。f:id:HealthcareIT_interpreter:20170514165149p:plainf:id:HealthcareIT_interpreter:20170514165336p:plain

matplotlibを使っています。集計にはpandasを使っています。バーチャートの下にデータテーブルを表示させています。 こちらをほぼパクりました。 https://matplotlib.org/examples/pylab_examples/table_demo.html

Requirements(すみません、バージョンとか細かいことは省略させてください)

  • Python3
  • Flask
  • SQLite3
  • matplotlib
  • pandas
  • numpy
  • Vue.js
  • bootstrap.css
改修予定リスト
  • 機能3で集計期間に対応情報が皆無だった場合Flaskのエラーページに飛んでしまう(functool.reduceのエラー) が、エラー処理を書き加えてポップアップメッセージ「集計期間にデータはありませんでした。」を出すなどエレガントな対応をしたい。

  • 機能2の対応記録表で一番必要になるのはサマリーの列だが、左端で列幅が狭いなどやや見にくいので何とかする。

  • 5人程度の少人数で使用するならばSQLite3で問題ないと思うが、それ以上になるとやはりサーバ型のデータベースが欲しい。近いうちにPosgresバージョンを公開したい。

以上GitHubからの転記でした。

github.com

医療通訳支援Webアプリ第1弾 視力換算システム

以前投稿で視力の伝え方について書きました。 healthcareit-interpreter.hatenablog.com

iOSのアプリでも作ってみるかと構想しておりましたが、友人(こちらのブログの著者

stagira.hatenablog.com

)からWebアプリにした方が楽だという助言をいただきました。 それで出来上がったのがこちらです。

視力換算システム

https://riow1983.github.io/visual_acuity_conversion/

JavaScriptのライブラリvue.jsを使った実装の大方はその友人によるものです。私はレイアウトを少しいじった程度です。じっくり腰を据えてFlask(Pythonのライブラリ)あたりを使って作ろうと思っていたのにこんなに早く出来上がるなんて。JavaScripterに完敗です。

さてさて、それではこれを眼科の先生に見せて感想を聞いてみることにしますか。

病院の医療情報部門の端末払出しアルゴリズム

スマホ5台新規で払出してください。」 「電子カルテ端末が足りないのよ。あと3台出して。」

こんな要望を受けて、さて在庫数は○○台だから、いくつ払出せるな・・・とその度に頭を悩ませることが多いのが病院の医療情報部門のあるあるではないでしょうか?基準が無くて恣意的で人治主義的なさじ加減で無駄に幅を効かせている総務課の事務員ならまだしも、病院のIT化を推進する医療情報部門の医療情報技師ならドクターの診断アルゴリズムも顔負けな”端末払出しアルゴリズム”で払出業務の透明化を図るべきでしょう。

f:id:HealthcareIT_interpreter:20170425223051p:plain

さて、数学を使わなければならない局面というのはこういう所に出てくるんですね。払出優先度指数の算出はともかく、当月最大払出可能数については数式を考える前にフリーハンドで「在庫管理にはこういう曲線が望ましいよな」と線を描いてから、さてこういうカーブの曲線を描く式ってなんだ?とネットで調べて行き当たるという体験をしました。(今回はロジスティック曲線というものらしいです。)兵站業務(logistics)に向いている曲線だからlogistic曲線というのか?と一瞬思ってしまうほどの運命的な出会いでした。 そういった意味合いはないのですが語源としては同源のようですね。 http://www.weblio.jp/content/%E3%83%AD%E3%82%B8%E3%82%B9%E3%83%86%E3%82%A3%E3%83%83%E3%82%AF

外国人観光客が病院に受診した際、病院の医事課が旅行保険会社に確認すべき事項

通訳に呼ばれた外国人患者が観光のため来日した旅行者だった場合、医療通訳担当者にお会計のことで医事課から色々と注文がついて面倒なことになります。 (うちの病院はスキー場に近いことから、スキー観光客が多いようです。) 外国人観光客が旅行保険に加入していた場合、旅行保険会社から病院に電話してもらいます。日本人スタッフがいれば日本語で電話対応可能ですが(その場合は速攻で医事課に転送しましょう)、英語で対応する必要がある可能性もあります。医療通訳担当者が旅行保険会社に確認すべき事項をまとめてみました。

旅行保険会社に確認すべき事項 (Things to confirm with a travel insurance company):

「まず最初に1つ確認させてください。日本語を話せるスタッフはいますか?」(まだ諦めていません)

"First let me verify one thing. Does your company have any personnel who speak Japanese?"

・会計の方法(The method for billing):

「会計に必要なものを教えてください。請求書、診断書、その他にありますか?」

"Let me know things we must have to prepare for billing. We suppose an invoice, a certificate, and others?"

「御社が指定する様式の診断書はありますか?(御社のメールアドレスをメールしてもらえますか?当院のメールアドレスはfoo@hogeです。

"Should we make a private style document you specify? (Please send your e-mail to our address. The address is foo@hoge.)"

「患者の要望で作成した書類は保険適用されますか?」

"Are documents on patient’s demand covered by the insurance?"

「請求書の送付先を教えてください。患者による立替払いになりますか?それとも保険会社による直接支払いでしょうか?」

"To whom should we bill to? Is it an advance payment on behalf of the insurer or a direct payment from the insurer?"

(保険会社による直接支払いの場合)「保険会社様の社名、ご住所、患者様のお名前、案件番号を確認させてください。」

(In case of a direct payment) "Can I verify the company’s name and address, the patient’s name, and case No.?"

「他に準備すべきものはありますか?」

"Is there anything else we should prepare?"

・その他の費用について (About other expenses):

「松葉杖や付き添い寝具など入院中に発生する(した)その他の費用はどのように扱われますでしょうか?それらは患者様負担でしょうか?それとも保険会社様支払いでしょうか?」

"How do you deal with other expenses incurred during admission, namely a crutch, a bedding for rent? Are these things to be paid by the patient himself (herself) or by the the insurer? "

・・・と、こんな感じです。こうやって準備万端にしておけば少しは気が楽になります。

ランダムパスワードの生成

電子カルテの利用者IDの初期パスワードとして、大文字アルファベットと数字で構成された6桁のランダムパスワードを設定する方針が決定されました。え!今更かよ! さて生成コードをPythonで実装してみます。

import string
from random import choice

def get_PW(figures):
    pw = ''.join([choice(string.ascii_uppercase.replace('I','').replace('O','').replace('Z','')+string.digits.replace('0','').replace('1','').replace('2','')) for i in range(figures)])
    if pw.isdigit():#数字だけの場合
        return 'A'+pw[1:]
    elif set(pw).issubset(set(string.ascii_uppercase)):#文字だけの場合
        return "9"+pw[1:]
    else:#数字と文字ともに含有している場合
        return pw

get_PW(6)

数字だけの場合はint(pw)としても良いです。文字だけの場合はどうするか悩みましたが、文字列を集合に変換し、集合「パスワード」が集合「大文字アルファベット」のサブセット(部分集合)であればすなわちパスワードが全て大文字アルファベットで構成されていることになる、という性質を利用することにしました。 あとは、紛らわしい文字と数字の組み合わせ(1とI, 0とO,2とZ)を除外しておいて視認性を高める工夫をしています。 後はこれをVBAで実装し直すだけですね(笑)!

疾病別患者分布をジオプロットする方法

4月になり新採用職員の皆さんが多数入職されました。そんな彼らを前に電子カルテ研修と題してjupyter notebookのスライド機能(Reveal.js)を使ったプレゼンを行ってきました。それについてはまた別途記事にしたいと思いますが、ここではそのプレゼン資料にさらっと挟んでおいた疾病別患者分布の作り方を覚書きしておきます。

ステップ1:ジオコーディング

私の使用言語はPythonです。DWHから抽出してきた疾病別郵便番号一覧をあらかじめ五大疾病だけに絞り込んでおきます。絞り込みが完了したファイルを"五大疾病データ.xlsx"とします。それをPythonのライブラリpandasで読み取り、dataframeにした上で、ジオコーディング(郵便番号を緯度経度に変換)用公開API(http://geoapi.heartrails.com/api/json)に郵便番号を一つずつ投げていく関数を作り実行させます。

import requests
import json
import pandas as pd

df = pd.read_excel("五大疾病データ.xlsx")
df["latitude"] = ""
df["longitude"] = ""

def getlocation(dx):
    url = 'http://geoapi.heartrails.com/api/json'
    payload = {'method':'searchByPostal'}
    for i in dx.index:
        payload['postal'] = dx.loc[i,"郵便番号"]
        res = requests.get(url, params=payload).json()["response"]["location"][0]
        dx.loc[i,"latitude"] = res['y']
        dx.loc[i,"longitude"] = res['x']

getlocation(df)

さらっと書きましたが、実際には一気に処理させるとエラーになってしまいました。全部で9000レコード超だったのですが、500レコードずつ分割してgetlocation()を複数回実行させるという地道な作業が必要でした。(daskというpandasのdataframeを分割並列処理するライブラリが功を奏すか考えもしたのですが実際には試しませんでした。)

ステップ2:ジオプロット

次に、取得した経緯緯度を元に地図上に点描(ジオプロット)していく処理を行います。 前処理として、ステップ1で取得したdataframeを疾病ごとに分割し余分なカラムをそぎ落とします。

mf = df
cancer = mf[mf["疾病分類"] == "がん"]
ci = mf[mf["疾病分類"] == "脳卒中"]
mi = mf[mf["疾病分類"] == "急性心筋梗塞"]
di = mf[mf["疾病分類"] == "糖尿病"]
si = mf[mf["疾病分類"] == "精神疾患"]

ll_cancer = cancer[["latitude","longitude"]]
ll_ci = ci[["latitude","longitude"]]
ll_mi = mi[["latitude","longitude"]]
ll_di = di[["latitude","longitude"]]
ll_si = si[["latitude","longitude"]]

疾病ごとに緯度経度のみのdataframeが取得できました。これで準備万端です。

gmapsでやる場合

googlemapにジオプロットできるgmapsというライブラリを使う場合は以下の通りコードを書いていきます。

import gmaps
gmaps.configure(api_key="YOUR_GOOGLE_MAPS_API")

add_layer_cancer = gmaps.symbol_layer(ll_cancer, fill_color="red", stroke_color="red", scale=2)
add_layer_ci = gmaps.symbol_layer(ll_ci, fill_color="blue", stroke_color="blue", scale=2)
add_layer_mi = gmaps.symbol_layer(ll_mi, fill_color="green", stroke_color="green", scale=2)
add_layer_di = gmaps.symbol_layer(ll_di, fill_color="yellow", stroke_color="yellow", scale=2)
add_layer_si = gmaps.symbol_layer(ll_si, fill_color="purple", stroke_color="purple", scale=2)

m = gmaps.Map()

m.add_layer(add_layer_cancer) 
m.add_layer(add_layer_ci) 
m.add_layer(add_layer_mi) 
m.add_layer(add_layer_di) 
m.add_layer(add_layer_si) 

m

これで疾病ごとに色分けされたドットがプロットされたグーグルマップを表示することができます。(筆者はjupyter notebook上で実行し、inlineにマップが表示されることを確認しました。)

Foliumでやる場合

gmapsと異なりライブラリ内蔵の専用地図にジオプロットできるのが、Foliumというライブラリです。こちらはアウトプットをHTMLファイル保存できます。以下の通りコードを書いていきます。

import folium

map_ = folium.Map(location=[YOUR_LAT, YOUR_LON],
           tiles='Stamen Terrain',
           zoom_start=9)

for i in ll_cancer.index:
    x = ll_cancer.loc[i,"latitude"]
    y = ll_cancer.loc[i,"longitude"]
    folium.CircleMarker([x,y],
                 radius=4,
                 popup="がん",
                 color="#011efe",
                 fill_color="#011efe"
                 ).add_to(map_)

for i in ll_ci.index:
    x = ll_ci.loc[i,"latitude"]
    y = ll_ci.loc[i,"longitude"]
    folium.CircleMarker([x,y],
                 radius=4,
                 popup="脳卒中",
                 color="#fe0000",
                 fill_color="#fe0000"
                 ).add_to(map_)

for i in ll_mi.index:
    x = ll_mi.loc[i,"latitude"]
    y = ll_mi.loc[i,"longitude"]
    folium.CircleMarker([x,y],
                 radius=4,
                 popup="急性心筋梗塞",
                 color="#0bff01",
                 fill_color="#0bff01"
                 ).add_to(map_)

for i in ll_di.index:
    x = ll_di.loc[i,"latitude"]
    y = ll_di.loc[i,"longitude"]
    folium.CircleMarker([x,y],
                 radius=4,
                 popup="糖尿病",
                 color="#fdfe02",
                 fill_color="#fdfe02"
                 ).add_to(map_)

for i in ll_si.index:
    x = ll_si.loc[i,"latitude"]
    y = ll_si.loc[i,"longitude"]
    folium.CircleMarker([x,y],
                 radius=4,
                 popup="精神疾患",
                 color="#fe00f6",
                 fill_color="#fe00f6"
                 ).add_to(map_)

map_.save(outfile="fivemap_circle.html")

ちなみに保存したHTMLファイルをjupyter notebook上に表示する場合は

from IPython.display import HTML
HTML('<iframe src=./fivemap_circle.html width=800 height=500></iframe>')

とすればOKです。

考察:患者分布図で個人が特定されることはないか?

経度緯度を取得すると言っても、郵便番号が素ですから個人宅がピンポイントに指し示されることはありません。また病名についても五大疾病という大きな分類で表していますので、マイナーかつ詳細病名が地図上に表示されて推定されてしまうこともまずありません。(ただしアウトプットをネット公開することは控えたほうがいいかも知れません。あくまで院内資料ということで。)

患者分布図を作成する有料サービスも存在しているようですが今やオープンソースのライブラリで手軽に実行できる時代になっています。病院のデータ分析担当者は自らのスキルを院内にアピールし、病院長が無駄なコンサルタント料を支払うことの無いよう監視して行かなければなりません。

妊婦健診時の通訳

本日は妊婦健診の通訳に呼ばれました。場所は産婦人科外来です。医療情報技師で病院の医療情報部門で働く私(男性)にとって、産婦人科外来で電子カルテ端末のトラブルがあったときでも入るのに躊躇する部署ですが、女性の通訳担当がいない当院ではいたしかたありません。 さて妊婦健診は英語で

prenatal checkup

と言います。ドクターがいる診察室ではない、助産師が助産記録を作成する小部屋で話をしました。助産記録を取る時必ず聞くのが経産婦か否かという点です。これは英語でいうと

primipara, bipara or multipara

となります。つまり初産婦が

primipara

二回経産婦が

bipara

そして三回以上の経産婦が

multipara

となるそうですが、ちょっと混乱してきました。0,1,2,3とカウントするはずですが、0と1の両方とも初産婦ということになっているような気がします。気のせいでしょうか。 さてここはあまり突っ込まないことにします。どっちにしてもこれらの単語を並べたところで妊婦さんは「??」という顔をします。ですので結局こう聴き直すことになります

Is this your first delivery or more than that?

これで明確になります。 さて今回はそういった話はなく胎位調整のための体操の説明でした。胎位は

fetal position

でいいかと思います。看護師さんが妊婦さんに「ベッドの上に四つん這いになってください」と言いました。これが難しかった。

Please put your arms and legs on the bed.

と苦し紛れに言ったところなんとか通じましたが本当は

Please get down on all fours on the bed.

だそうです。更に困ったのが「右側に倒れてください」です。

Please get the right side of the body on the bed.

でいいんでしょうか?また「腕をこのようにしてください」というのも中々難しく感じました。

Get both arms bent like this.

でしょうか?「クッションを腰に当てて」というフレーズも出てきましたが、

Put a cushion on the back, ...

で良さそうです。クッションはそのまま英語で使えます。 何とか体操の説明は終了し、最後に入院証書の説明のところで連帯保証人の説明のところで「同居でなく生計を別にしている人」というのが出てきましたが、

Do you have any relatives who live separately and make their own living?

で良さそうです。ちなみに保証人と連帯保証人は

guarantor, joint guarantor

となります。