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

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

DPCチェッカー0.08 デザインをちょっと修正

例によってこちらからどうぞ。

バージョン0.08の変更点:デザイン修正

これを書いている人間は、残念ながら「デザイン」とか「絵心」というものは皆無です。
ということでGoogle様のMaterial Design Liteに乗っかりました。
といっても所々昔のままで、ツギハギ感がひどいですが、ドキュメント読み始めてまだ数時間なので…
しかしこういうデザインテンプレートがオープンソースで山ほど転がってるのが、Web技術のいいところです。
デスクトップ向けのUIだと、あんまりこういうのは見つからないので…

次回アップデートではようやくグラフ描画機能を追加する予定です。
Flaskの勉強もちょこちょこしてますので、各種の挙動がもう少しマシになると思います。

SQL方言について(ついでにDPCチェッカーにクエリを追加)

SQLの方言

残念なことですが、SQLは実装ごとに方言があります。
私はPostgreSQLばっかりいじってたので気にも留めていませんでしたが、今回DPCチェッカーを作っていて否が応でも気付かざる得ませんでした。
DPCチェッカーは組み込みで配布するため、SQLite3を使っています。exe単体で実行できるSQLで、Pythonには何とビルトインされています。
こちらの実装はPostgreSQLとかなり違っていて、例えば日付データをネイティブで扱うことが出来ません。
そこにさえ目をつむれば、大抵のクエリは走るのですが、今回はここで詰まりました。

select データ識別番号,実施年月日,診療明細名称,SUM(明細点数・金額*行為回数) 
from etable
Where データ区分 = 60 
AND (データ識別番号,実施年月日) IN (select データ識別番号,実施年月日 from dtable Where データ区分 = 93) 
group by データ識別番号,実施年月日,診療明細名称
HAVING SUM(明細点数・金額*行為回数) > 0;

以前このブログで紹介した、DPC期間中に行った検査を探すクエリです。 INを使った相関サブクエリで、「Dファイル上でDPC入院料を算定した患者と日付」に条件に絞る、ということをやっています。
このクエリはPostgresでは走りますが、SQLiteでは走りません。 AND (データ識別番号,実施年月日) IN...の部分が問題です。
これをAND データ識別番号 IN...とすると走ります(これでは条件を満たしませんが)。
()でカラムを複数指定するやり方は、行値式というそうで、実装されているSQLは限られています。 (メジャーどころでは、MicrosoftSQL Serverも対応していないとか)
どんなに頭を悩ましたところで、実装されていないものは走りません。書き方を変えます。

select e.データ識別番号,e.実施年月日,e.診療明細名称,SUM(明細点数・金額*行為回数) 
from etable AS e
Where データ区分 = 60 
AND EXISTS (select d.データ識別番号,d.実施年月日 from dtable Where データ区分 = 93
AND dtable.データ識別番号 = etable.データ識別番号
AND dtable.実施年月日 = etable.実施年月日)
group by e.データ識別番号,e.実施年月日,e.診療明細名称
HAVING SUM(明細点数・金額*行為回数) > 0;

今度はEXISTSを使いました。意味合いは違いますが、求める結果は同じです。
Postgresでは走りますので、意気揚々とSQLiteで走らせると・・・答えが返ってきません。
どうやら私がやっつけで書いたクエリに問題があって、Postgresが優しく(見えないところで)始末をつけてくれたのでしょうか。それとも、SQLiteのEXISTS実装にパフォーマンスの問題があるのでしょうか。または、その両方?
前者である可能性が高いですね。 さて困りました。もうちょっとEXISTSについて調べてもいいのですが、手っ取り早いのは以下のクエリです。

WITH d93 AS (select データ識別番号,実施年月日 from dtable Where データ区分 = 93),
e60 AS (select データ識別番号,実施年月日,診療明細名称,SUM(明細点数・金額*行為回数)  AS 出来高金額
from etable
Where データ区分 = 60 
group by データ識別番号,実施年月日,診療明細名称
HAVING SUM(明細点数・金額*行為回数) > 0)
select d93.データ識別番号,d93.実施年月日,e60.診療明細名称,e60.出来高金額
from d93
INNER JOIN e60
USING(データ識別番号,実施年月日);

WITH句でテーブルを2つ作ってINNER JOINでくっつけています。
結局、今回やりたいのは「検査を行った患者とその日付」の集合と、「DPC入院料を算定した患者とその日付」の積を求めること、つまり二つの集合の共通集合を導き出すことです。
ならばINNER JOINで良いわけですね。

(ちなみに、上記のクエリは検査版と注射版を作って、DPCチェッカーに追加しておきました)

DPCチェッカー0.07 : 外部クエリの読み込みに対応しました

例によってこちらからどうぞ。

バージョン0.07の変更点:外部クエリの読み込み機能について

今まで当ツールはコード内部にそのまんまSQLクエリが書いてあるというシロモノでした。
拡張性もへったくれもありませんので、バージョン0.07でSQLクエリは本体から切り離し、queryフォルダに置く形式となっています。
その副産物で、外部クエリの読み込みにも対応出来ました。
お好きなSQL文をqueryフォルダにtxtで置けば、メニューに選択肢が増えます。
なお、エンコーディングUTF-8にして下さい。

あと幾つかのクエリを追加してあります。 当ブログでも紹介してきましたが、

  • EF/Dファイルの区分別集計
  • 手術のカテゴリ別金額
  • 副傷病分岐なしチェック

です。 本来ならばDPC中に行った検査/注射のチェック機能も追加する筈でしたが、当該のクエリがSQLiteで走りません・・・
移植にはもう少しかかりそうですので、気長にお待ち下さい。
(この件で「SQLクエリの移植」というひどい問題にも出会いました。これは追々記事にします)

今後の課題と予定

見た目がひどい

ほんとにひどい。見づらい。
ということで、多分レイアウト修正をやります。ついでにbootstrapでも勉強するつもりです。

ビジュアライゼーション

かっこいい分析機能とかあるといいですね。こう、どかーんとダッシュボードが開いて、グラフがぬるぬるっとアニメーションして描画されるようなの。
すごい適当なことを書きましたが、こういう機能を楽に実装するなら、もうJavaScriptのライブラリを使うしかありません。
(このブログで紹介したBokehはPythonで動くグラフを作れますが、出力結果はJavaScriptです)
このツールがウェブアプリなのは、私がC#に挫折しただけではなく、グラフ描画にまつわる問題もあるのでした。
まあ、D3.jsみたいなのは他にありませんしね。

DPCチェッカーを0.06にアップデートしました

といっても、csvエクスポート機能をつけただけですが…
例によってこちらからどうぞ。
今後の予定としては

  • さっさと外部クエリ読み込みを実装する
  • というか今までブログに上げてきたクエリを整理してGitHubにまとめる
  • Bokehを使った可視化は業務でやってるので、早めに組み込む

となっております。
如何せん片手間仕事なのでペースは遅いですけど。

もし時間があれば、ロジックをそのまんま流用してJavaScriptで書き直し、Electronでアプリ化したものを配布したいですが、うーん。
今の状況だと難しそうです。
ちなみにPyinstallerを使えば、Pythonのままでexeに出来るのですが、様々なライブラリを全てバンドルしてしまうようで、500MB超にまで膨れ上がります。ソースのサイズを考えると無駄があり過ぎますね。

DPCチェッカー 0.05を公開しました

DPCチェッカー 0.05

いきなりですが、業務の片手間にツールを作ったので公開します。
こちらからどうぞ。 DPCチェッカーはEF/Dファイルを読み込み、出来高対比を算出したり、退院時処方のエラーチェックを行うソフトです。
Flask/Pandas/SQLite3で実装されたウェブアプリケーションで、ブラウザ上で動作しますが、実際にはローカルで動いています。
(初回起動時に、dpc.dbというDBファイルを作成し、そこにデータをストアする仕組み)

こんなのを作ろうと思った経緯

私は普段のDPC分析業務の殆どを、Jupyter Notebook上で行っていますが、それだと他の人が困るかなーと、ここ数ヶ月ぼんやり考えていました。誰でも使えるGUIがあるといいよね、と。
この数週間はすごく調子に乗っていて、「ちょっとC#かじってアプリをでっち上げよう!」と意気軒昂でしたが、うん、これ、そんな簡単なもんじゃないですね…SQLiteのドライバの挙動とか、C#の言語仕様とか、WPF(Windows Presentation Foundation、Visual C#GUIアプリケーションを作るときの枠組みのひとつ)とかと1週間ちょい格闘した後、ふと我に返りました。

これ、完成しないんじゃね?

偉い人は言いました。「たぶん動くと思うからリリースしようぜ」と。
私の技術では動くところにすら到達出来ません。さっさと諦めて、いつも使っているPythonでWebアプリケーションにすることにしました。
こっちはプレゼン目的にでっち上げたこともありますので、すぐに作れます。
今、Jupyter Notebookでやっているデータの可視化や、このブログで書き殴ってきた様々なクエリ発行も、このアプリケーションに纏めていこうと考えています。

ちなみにGit Hubを使うのはこれが初めてで、ろくに使い方がわかってません。色々ヘンテコなところがあると思いますがご勘弁ください。
ツールの中身については…はい、ひどいシロモノです。色んな修正点が必要になると分かっています。
「なんてひどい!こんなの書き換えてやる!」と思った方は是非そうしてください。当然改変・再配布・利用フリーです。

持参薬の記録についてあれこれ

10月から持参薬の記録が必須になりました。
面倒極まりない仕様ですが、データを扱うときにも注意点が増えます。
というのも、この持参薬情報、

出来高実績点数や明細点数情報を保持したままなのです!

つまり、普通にEFファイルを集計すると、持参薬込の点数が出てしまいます。 (ひょっとすると、それが狙いでこういう仕様なのかも知れませんが…)

持参薬の有無や種別は行為明細区分情報の3桁目に記録されますので、こちらを利用すれば区分けは可能です。 例えば以下に、持参薬を除外した出来高点数集計の例を挙げます。

SELECT データ識別番号,入院年月日,SUM(出来高実績点数*行為回数) AS 出来高総点数
FROM ef1610
WHERE データ区分 <> 92
AND データ区分 <> 97
AND 行為明細区分情報 LIKE '__0_________'
group by データ識別番号,入院年月日

該当のポイントはAND 行為明細区分情報 LIKE '__0_________'です。
SQLなら大して難しいことではありませんが、面倒くさいですね。

再びのアプリケーション考察

データ分析をやっていると、やっぱり「アプリケーションで配布したい!」と思うときがあります。
(このブログで書いている諸々のSQL文も、まとめてアプリケーションにバンドルしてしまいたいのです)
最近真剣に選択肢を検討してみたので、結果をつらつら書くことにしました。

1. Pythonのままアプリケーション化する

ネットで検索すると色々な方法が見つかりますが、Pyinstallerを使うのが最も現実的でしょう。
他の方法、例えばPy2exeなんかは更新が止まっちゃってますし… とはいえ、環境によってはPandasを含むアプリが上手くビルド出来なかったりします。 私が正にそうで、GitHubの開発中のビルドをぶっ込んだら走りましたが、うーん、安定はしてなさそうですね…
また、GUIをどうするか、という問題もあります。 PyQtが一番有名みたいですが、ライセンスがややこしそうです。別の選択肢として、Kivyが熱いみたいですが日本語の情報があまり出回っていません。
FlaskでWebアプリを作ってブラウザで使う、という手もありますけど…うーん…

2. Javascript + Node.js + Electronでアプリケーション化する

自分でもなぜこうしようと思ったのか分かりませんが、Node.jsで組んだウェブアプリをElectronというライブラリでデスクトップアプリに変換出来ます。
実際に使ってみようと、しばらくJavascriptとNode.jsの勉強をしてましたが…ましたが…うーん…csvを開くための方法が何パターンかあり、dataframeっぽいライブラリを使うにはbabelが必要で、うーん…
ただし、素の状態でJavascriptPythonより速いです。numpy / PandasのようなC言語ライブラリを使えば話は変わってきますが。
ちょっと大きなデータの分析にも十分使えそう。今回は、学習時間が全く足りなかったということで…

3. 素直にC#を使う

初めからそうしろよ、と言われそうですがC#をいじってます。Visual Studioすごいべんりですね!(今更
別にJavaでもいいんですが、せっかくVisual Studioが無料化されたので。 Windowsをターゲットにするなら、最初っからこれで良かったですね… ただ、グラフのプロット周りはあんまり期待できそうにありません。
(こちらはPythonが充実し過ぎているだけ、とも言えますが)