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

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

レセ電パーサを公開しました

とても人類には読み取れないレセ電ファイルを読み込むパーサ、Receparserを公開しました。 こちらです。

github.com

現在、医科レセプトファイルと、DPCレセプトファイルに対応しています。
なお、サンプルファイルは支払基金公開しているサンプルを修正したものです。
テスト用にJupyter Notebookファイルも付けておきましたので、ご覧ください。

使い方

from receparser import MonthlyRece,Rece

で、必要なオブジェクトをインポートします。

サンプルファイルを読み込みます。 読み込みの際には、codesオプションに"dpc"か"ika"を指定します。

.keysでカルテ番号の一覧を見ることが出来ます。 ディクショナリのように動きます。.items(),.values()も使えます。

dpc = MonthlyRece('dpcsample.csv',codes="dpc")
dpc.keys()

out: 
dict_keys(['1111', '', '2222', '3333', '4444', '5555', '6666', '8888', '9999', '101010'])

電子レセプトファイルは各行にレコードと呼ばれるアルファベットが振られており、それぞれ異なる内容を持っています。カルテ番号から更に深掘りしてみましょう。

dpc['1111'].keys()

とすると、

dict_keys(['RE', 'HO', 'KO', 'BU', 'SB', 'KK', 'GA', 'HH', 'GT', 'CO', 'SI', 'CD'])

が返ってきます。それぞれの内容を追っていくと…

dpc['1111']['RE']

out:
{'レコード識別番号': 'RE', 'レセプト番号': '1', 'レセプト種別': '1127', '診療年月': '42806', '氏名': 'サンプルDPC01', '男女区分': '1', '生年月日': '3160822', '給付割合': '', '入院年月日': '', '病棟区分': '', '一部負担金区分': '', 'レセプト特記事項': '', 'カルテ番号等': '1111', '割引点数単価': '', 'レセプト総括区分': '0', '明細情報数': '', '検索番号': '', '記録条件仕様年月情報': '', '請求情報': '', '診療科名': '59', '診療科_人体の部位': '', '診療科_性別等': '', '診療科_医学的処置': '', '診療科_特定疾病': ''}

dpc['1111']['HO']

out:
{'レコード識別番号': 'HO',
 '保険者番号': '06132013',
 '合計点数': '57706',
 '職務上の理由': '',
 '被保険者証の番号': '1',
 '被保険者証の記号': '1234567',
 '診療実日数': '5',
 '証明者番号': '',
 '負担金額_医療保険': '44400',
 '負担金額_減免区分': '',
 '負担金額_減額割合': '',
 '負担金額_減額金額': '',
 '食事_合計金額': '2072',
 '食事_回数': '3',
 '食事療養・生活療養_標準負担額': '1080'}

このような感じになります。
何だかんだ、2,3日かけて突貫で書き上げました。 (ファイル仕様を書き出すのと、サンプルファイルの修正が一番大変でした……) 最低限の機能しか実装していませんので、これから色々拡張していきたいですね。
具体的には、各レセプトごとの情報を統合して見やすく表示する機能とか、全体のサマリを表示する機能とか…

2017年振り返りと、2018年の展望

はい、今年の後半は本当にブログ書いてませんでした!ごめんなさい!
暇ができたら、レセ電ファイルを読み取るパーサーでも書こうと思ってましたが……うーん、全然時間が取れませんでしたね。
で、何をやってたかと言うと…

本ばっかり読んでいた

私は読書が趣味です。出身が人文学部なので、とにかく沢山読みます。
元々は西洋哲学や、ヨーロッパ史を中心に読み漁ってましたが、この数年はプログラムの本を読むのが趣味になりました。
ええ、趣味です。結局肝心のコードを書けてないので、実益は(殆ど)ありません。
ということで、以下に最近買った本をつらつらと。

Fluent Python ―Pythonicな思考とコーディング手法

Fluent Python ―Pythonicな思考とコーディング手法

Pythonによるテキストマイニング入門

Pythonによるテキストマイニング入門

基礎からわかる Scala

基礎からわかる Scala

Javaの絵本 第3版 Javaが好きになる新しい9つの扉

Javaの絵本 第3版 Javaが好きになる新しい9つの扉

経済・ファイナンスデータの計量時系列分析 (統計ライブラリー)

経済・ファイナンスデータの計量時系列分析 (統計ライブラリー)

いや、これは無理でしょう

今年の教訓は「自分の頭に入るだけの本を買いなさい」ですね!
どれもすごくいい本で、頭の中が整理されますが(特にFluent Pythonは素晴らしい)、いかんせん数が多すぎます。 途中で止まってる本も多いし……

2018年はどうするか

2016年の終わりには、「Webが全てにやって来るぞ!」と書きました。
マイクロソフトSkypeをElectronで書き直したと聞いた時は、椅子から転げ落ちそうになりましたね。何だかんだ言いつつ、Node.jsは避け得ないものになってますし、Reactは凄い存在感で……ん?

はい。2017年はこのブログが何度も「DPCデータ分析」から脱線しまくった1年でした(白目

2018年はそろそろデータ分析に戻ります……うん、戻る、はず……
ただ、流石にネタ切れなので、ブログのタイトルは変えます。DPCデータ分析=>医療データ分析、くらいに風呂敷を広げるか、もうちょい広い(そしてテキトーな)タイトルにするかも知れません。
一応予定しているリストをば。

  • 時系列分析。本まで買ってますし、記事は書きます。ただ、理解するのにすごい苦労してますが…

  • Pythonをシェル代わりに使おう話。オライリーPython自動化本で、os.walkの使い方を読んだ時は目からウロコでした。

  • 事務仕事はPythonで片付けましょう講座。

結局、機械学習でDPCデータ分析をしよう!という抱負は生煮えで終わってしまったので、2018年こそは何か形にしたいですね。
何だかんだ、グダグダな2017年でありましたが、2018年はブログの名前も変えますし、色々方向を変えようと思っております。
それでは皆様、よいお年を。

ICD10を正規表現でパースする

またもやお久しぶりとなってしまいました… さて、今回のお題はICD10のパースです。以前、「I20$のような、I200~209を指定するケースはどうしよう?」という問題を記事にしました。その時は、ゴリ押しでI200~I209までを連番生成して済ませてます。
が、今回(実際にあった話ですが)、「I20$もしくは、I50$もしくは、I1$のどれかに当てはまる疾患を探してね!」という案件が参りました。うーん、どうしたもんでしょうか。

正規表現を使わざるを得ないとき

問題に直面したとき、ある人々はこう考える……「そうか、正規表現を使うんだ!」そして問題が2つに増える

インターネットには賢者の箴言がありますが、そうも言っていられません。
上記のような問題に出くわしたとき、正規表現ではI20[0-9]|I50[0-9]|I1[0-9]のように表記します。 |はor条件を意味しており、[0-9]は0から9の数字に当てはまるもの、という意味です。 上記ですと、正に「I20$もしくは、I50$もしくは、I1$のどれか」という分けですね。 まあ、実際にはI500だけではなく、I5000にも当てはまっちゃうので、本当にそれでいいのかと言われるとアレですが…(この辺は、ICDのコード体系におんぶに抱っこしてます)

例としてPythonで書くとこんな感じですね。

import re
pattern = r"I20[0-9]|I50[0-9]|I1[0-9]"
re.findall(pattern,"I209,I11,I300")

out: ['I209,'I11']

実務でICD10の抽出をするときは、患者単位であることが殆どです。
その場合、患者別にICDのリストを作るのか(例:['I209','I11','I300'])、複数のICDを連結して文字列にしてしまうか(例:"I209,I11,I300")は、ケースバイケースでしょう。
私が関わった案件では単純に連結してしまいましたが、リストのほうが扱いやすいケースもある筈です。

pandasで移動平均を出してみる

お久しぶりです。
ブログはサボってましたが、仕事はサボれず、色々やっていました。
現在、時系列データに取り組んでいますが、全く経験がないので四苦八苦してます。
単に推移を見るだけならプロットすればオシマイですが、突発的な変動は無視して、傾向を見たいとなると、移動平均というものを扱う必要が出てきます。

エクセルでどうやるのかは知りませんが、pandasなら簡単!

ということで、以下の通りすぐに出来ました。
移動平均は一定期間(例えば3ヶ月毎)の平均を、ずらしながら取っていくという数字です。 統計WEBに記事があります
wikipediaにも記事がありますが……
うーん、これ読むよりはいきなりグラフ描いたほうが分かりやすいかも…
なお、wikipediaで紹介されている指数加重移動平均もpandasに実装されています。
数式の理解はともかく、実際にはどっちも使ってみればいいんじゃないでしょうか。使うのは簡単だし。

Pandas rolling_mean & emma example

scikit-learn 勉強ノート(2)

前回から大分間が空きましたが、scikit-learnの勉強メモです。
おさらいすると、サンプルとしてIrisデータセットを使い、アヤメの品種を分類していたのでした。
データセットは、がく片や花びらの長さが記録されたXと正解ラベルが記載されたyに分かれています。
これを分割して、

  • X_train, y_train

  • X_test, y_test

の2ペアにし、trainデータで学習して、testデータで正解率を見る、というのが流れです。

前回はRandom Forestモデルを使いましたが、今回はsvmモデルを使用することにします。

from sklearn.svm import LinearSVC
svc = LinearSVC()

さて早速学習しましょう…と言いたいところですが、ここで注意点。
Random Forestは特例で、データが数値データであろうがカテゴリデータであろうが、また桁違いのデータが混在していようが、一切構わず、そのまま投げ込んでも結果が出てしまいます。
機械学習のモデルの中では例外中の例外と言ってよく、他のモデルは

  • そもそもカテゴリデータは(そのままでは)扱えない

  • データのスケールが違う場合は、同じスケールになるよう変換する必要がある

ことが殆どです。
今回使うSVMも、これに該当します。手作業で変換するのは御免なので、ライブラリを使います。
SVMではMinMaxScalerを使うそうなので、早速インポートしましょう。

from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
scaler.fit(X_train)

学習のときと同じで、.fitメソッドを訓練データに適用します。
後の流れもよく似ています。

X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)

これで、同サイズに変換されたデータが手に入りました。 あとは

svc.fit(X_train_scaled,y_train)
svc.score(X_test_scaled,y_test)

とするだけです。scikit-learnは異なるモデルでも同じようなインターフェースを持っているので、一度基本を学ぶと色んなモデルを試してみることが出来ます。

例えばロジスティック回帰なら、

from sklearn.linear_model import LogisticRegression
logreg = LogisticRegression()
logreg.fit(X_train_scaled, y_train)

logreg.score(X_test_scaled, y_test)

と、殆ど同じコードで比較が出来ます。
実際にはもちろん、モデル毎に意味合いの異なるパラメータをいじる必要がありますが、モデルの比較が簡単に出来ていいですね。

[読書] 「達人に学ぶDB設計」「The Hitchhiker's Guide to Python」

特にネタもないので、最近読んだ本の話でも。

達人に学ぶDB設計

達人に学ぶDB設計 徹底指南書

達人に学ぶDB設計 徹底指南書

SQL解説本でご存じ、ミック先生のDB設計本です。
ひとまずSQL文を書けるようになる、くらいになった後で、「さてDBはどう設計したらいんだろ?」と思うことは、割とあります。
「そういえば正規化ってどうすればいいんだろ?」とか。
この本には、今まで読んだ中で一番わかりやすい正規化の説明があります。
そもそもデータをどのように保存すべきか、という基本中の基本から話が始まるので、SQLを始めるときにもいい本でしょう。

  • コンピュータが扱いやすい表とは何か

というのは、非常に重要な問題ですが、特に義務教育で教えることもなく、実務で学ぶしかありません。
こういう本で学べるなら、それに越したことはないでしょう。

The Hitchhiker’s Guide to Python

The Hitchhiker's Guide to Python: Best Practices for Development

The Hitchhiker's Guide to Python: Best Practices for Development

突然の洋書。
実際のところ、通読する気は更々無くて、Chapter 5 “Reading Great Code"のために買いました。
勉強がてらhowdoiのコードを読んだりしてたんですが、やっぱり解説書欲しいなーと思ったので・・・
本書のChapter5 では、howdoi, Diamond, Tablib, Requests, Werkzeug, Flaskのコードが解説されてます。
ちなみに、Chapter5以外の部分は、翻訳が無償公開されています。
「洋書なんて読んでられっか!」という向きは、こちらをどうぞ。

ICD→MDC6の変換表を作成する

色々あって、ICD10→DPCの頭6桁の変換を行う必要に迫られました。 とはいえ、電子点数表がありますから、楽勝でしょう。
そう思ってデータを見ると…ん…あれ…?

I20$ → 050050

とかありますね。 困りました。実データは、I209とかなのです。これを050050に変換するには、どうすればいいのでしょうか?

ICD表を拡張する

しょうがないので表を拡張することにします。 要は I200 I201 I202 ~以下省略

と、0~9まで増やしてやればよいのです。
ということで、以下のように作業してみました。
もっとスマートな方法がありそうなもんですが、とりあえずはこれで凌ぐことにします。

ICD10 => MDC6変換マスタ作成