DPCデータの分析とかやるブログ

DPCデータの分析なんかをテキトーにやってます。

EFファイルを自力で統合する(2017年版)

どうも最近、EFファイル統合でこのブログに来られる方が多いようです。

stagira.hatenablog.com

こんな記事も書きましたが、中身に関しては「適当にコード読んどいてね!」と投げっぱなし感溢れてましたので、ちゃんとした解説を書くことにしました。 ちょっと長いですが、EFファイル統合の流れを追っていきます。

方針

  • 実装はPythonのライブラリ、Pandasに全面的に頼る。
  • ライブラリの便利メソッドにおんぶにだっこ、極力難しいことはしない。

ということでPython環境のない方はAnaconndaを導入して下さい。
EFファイル統合スクリプトこちらにあります。並行してご覧ください。

おさらい

EファイルとFファイルに共通する項目で、重要なのはデータ識別番号 入院年月日 データ区分 順序番号の4項目です。
実際には、この4項目をキーにして結合を行い、同一の順序番号の中で更に行為明細番号を割り振ります。 図にするとこんな感じ。

データ識別番号  入院年月日  データ区分 順序番号 行為明細番号
000001 (Eファイル由来) 2017-04-01 60 1    0
000001 (Fファイル由来) 2017-04-01 60 1 1
000001 (Fファイル由来) 2017-04-01 60 1 2

重要なことは行為明細番号はFファイルにしかなく、Eファイル由来の行の行為明細番号は0になるということです。 これは、この後再び言及します。統合のミソです。

下準備

まず、カラム名のリストを用意します。

e_names = ['施設コード','データ識別番号','退院年月日','入院年月日','データ区分','順序番号',
'病院点数マスタコード','レセプト電算コード','解釈番号','診療明細名称','行為点数','行為薬剤料',
'行為材料料','円点区分','行為回数','保険者番号','レセプト種別コード','実施年月日',
'レセプト科区分  ','診療科区分','医師コード','病棟コード','病棟区分','入外区分','施設タイプ']
#正しくはEファイルには「診療明細名称」ではなく「診療行為名称」だが、統合のため変えている

f_names = ['施設コード','データ識別番号','退院年月日','入院年月日','データ区分',
'順序番号','行為明細番号','病院点数マスタコード','レセプト電算コード','解釈番号','診療明細名称',
'使用量','基準単位','行為明細点数','行為明細薬剤料','行為明細材料料','円点区分',
'出来高実績点数','行為明細区分情報']

続いて、EファイルとFファイルを読み込みます。医師コードを文字列(str)で読み込んでいるのは、病院によって数字のみだったり英数字で管理していたりとバラバラだからです。
shift_jisx0213でエンコード指定していますが、単にshift-jisでも行けるかも知れません。

edata = pd.read_csv('DRGE.TXT',delimiter='\t',parse_dates=['入院年月日','実施年月日'],dtype={'医師コード':str},
    encoding = 'shift_jisx0213',names=e_names)

fdata = pd.read_csv('DRGF.TXT',delimiter='\t',parse_dates=['入院年月日'],dtype={'行為明細区分情報':str},
    encoding = 'shift_jisx0213',names=f_names)

EFファイルの「明細点数・金額」は、Fファイルの'行為明細点数','行為明細薬剤料','行為明細材料料を一緒くたにしたものです。
ここでは、まず3つを単純に足し合わせた新たなカラムを作り、元の3つをdropしています。

fdata['明細点数・金額'] = fdata['行為明細点数'] + fdata['行為明細薬剤料'] + fdata['行為明細材料料']
fdata.drop(['行為明細点数','行為明細薬剤料','行為明細材料料'],axis=1,inplace = True)

下準備が終わりました。ここからは結合処理に入ります。

結合処理と行為明細番号

efdata = pd.concat([edata,fdata])

まずはpd.concatで縦方向に連結します。この時点では、本当に

Eファイル ↓ Fファイル

の順で縦に繋げただけです。
実際には [‘データ識別番号’,‘入院年月日’,‘データ区分’,‘順序番号’,‘行為明細番号’]の順番に並べる必要があります。
さっそく並べましょう!…と言いたいのですが、Eファイルには行為明細番号がありません。
そう、初っ端に言及した通り、Eファイル由来の行は行為明細番号0になります。並べる前に埋めておきましょう。

efdata['行為明細番号'].fillna(0,inplace=True)

fillnaメソッドは単純な穴埋めから高度な補完まで使えます。ここでは単純に0での穴埋めをしていますが、この先もうちょっと高度なことをやってもらいます。
続いては単純な並び替えです。

efdata.sort_values(['データ識別番号','入院年月日','データ区分','順序番号','行為明細番号'],inplace = True)
efdata.reset_index(inplace=True)

項目ごとの穴埋め

EFファイルにしかない項目を、穴埋めリストにしてみます。

fill_list='行為回数','実施年月日','診療科区分','医師コード','病棟コード','病棟区分'

さて、各項目がEファイル由来ということは、必ずレコードの先頭にある(=行為明細番号が0)ということです。 その後の空白行については、直近の一番上のデータから穴埋めしていけばよいのです。
fillna(method='pad')正にそのような挙動をしてくれます。

for val in fill_list:
    efdata[val].fillna(method='pad',inplace=True)

さて、これで殆ど出来上がりですが、私の環境では

データ区分、データ識別番号、レセプト電算コード…

のようにカタカナ順になり、続いて漢字…という並び方になってしまいました。
これでは困るので、続いてカラムの順番を変えます。

sort_list = '施設コード','データ識別番号','退院年月日','入院年月日','データ区分',\
'順序番号','行為明細番号','病院点数マスタコード','レセプト電算コード','解釈番号','診療明細名称',\
'使用量','基準単位','明細点数・金額','円点区分','出来高実績点数','行為明細区分情報','行為点数','行為薬剤料',\
'行為材料料','行為回数','保険者番号','レセプト種別コード','実施年月日','レセプト科区分',\
'診療科区分','医師コード','病棟コード','病棟区分','入外区分','施設タイプ'


efdata_sorted = efdata.reindex(columns=sort_list)

df.reindexはcolumnsに指定してやることで、カラムの指定が可能です。

おまけ

DB取り込み用に、0をinfinityに置換してやります。
また、入院年月日に0が入っていた場合は、こちらも'epoch'に置換してやります(多くの場合、この手順はスキップして 構いません。通常は起きない筈なので…)

efdata_sorted['退院年月日'] = efdata_sorted['退院年月日'].replace(0,'infinity')
efdata_sorted['入院年月日'] = efdata_sorted['入院年月日'].replace('0','epoch')

最後に空白のままになっている項目を、便宜上0で埋めておきます。

Fillzero = ['行為点数','行為薬剤料','行為材料料','使用量','基準単位','明細点数・金額','出来高実績点数']
for fillzero in Fillzero:
    efdata_sorted[fillzero].fillna(0,inplace=True)

あとはCSVに吐き出せばおしまいです。
GitHubのコードでは医師コードをいじってますが、環境によって先頭に空白が交じることがあるからで、特に意味はありません。
(悪さをするようなコードでもないです)
実際には、思わぬエラーが出てくることもあり得ますので、適宜修正するのがオススメです。

注記

この統合はDB登録を目的にしたもので、データ提出を視野に入れていません!
データ提出に使うと文字コード絡みで確実に弾かれますので、注意して下さい。