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

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

行値式を使った条件指定について(Postgres SQL前提)

保険算定というのは奇々怪々です。
あまりにも制度が複雑になりすぎて、「○○を行った患者さんで、××は算定してなくて、でも△△を算定してる人が知りたい」みたいな問題が割と出てきます。
一つ一つの条件は単純ですが、重なってくると面倒ですね。
さて、入院データを元に抽出をかけるとすると、「一人」ではなく「一入院」を単位とするのが一般的です。
つまり、先ほどのめんどくさいパターンマッチは、「その人」ではなく「その入院」に対してかけないといけません。
具体的に言えば、データ識別番号だけでは駄目で、入院年月日も使って探す必要があります。
(DPCデータの分析では、まずデータ識別番号と入院年月日を組み合わせてキーを作るのが基本です) では実際にやってみましょう。こんな感じでしょうか。

select *
from ef1612
Where 診療明細名称 LIKE '%探しているもの%'
AND (データ識別番号,入院年月日) NOT IN (select distinct データ識別番号,入院年月日
from efile
Where 診療明細名称 LIKE '%算定してない条件%')
AND (データ識別番号,入院年月日) IN (select distinct データ識別番号,入院年月日
from efile 
Where 診療明細名称 LIKE '%算定してる条件%')

--以下延々と続く

さて、上記のSQLは一体何をしているのでしょう。

AND (データ識別番号,入院年月日) IN (select distinct データ識別番号,入院年月日
from efile
Where 診療明細名称 LIKE '%なんとか%')

SQLでは、INを使って一定の条件に当てはまるデータを抽出出来ます。イメージとしては

123 in [123,456,789]

のような処理を考えてみましょう。上の例では123は右側のリストの先頭にあります。 同じように上記の例では、データ識別番号,入院年月日ペアが存在するかどうかを探しているのです。
INの横で唐突にSELECT文が走っていますが、よく見ると'データ識別番号,入院年月日'のペアを引っ張るようになっています。
逆に特定条件を満たしていないものを探したければ、NOT INを使えばいいだけです。 この例で分かるとおり、ブロックを並び続けることで、いくらでも条件を追加出来ます。 ただし、上記の()を使ってペア(もしくはそれ以上の複数条件)を使う記法は行値式といって、Postgresなど一部SQLにしか実装されていません。 (代表的なところでは、MicrosoftSQL Serverでは未対応です)
その場合はEXISTSなどを使って書き換える必要があります。 非常に便利で、自分は実務で連発してますが、案外使わないもんなんでしょうか・・・?

DPC疾患の月別推移を可視化する(修正版)

前回はタイトル通り、DPC疾患の月別推移を可視化する関数を書きました。
あれは実行するとデータを作り、同時にグラフを描画するというひどい代物で、流石に反省しましたのでクラスに書き換えてみました。
何気にこのブログでクラスを書くのは初めてですね。
今までいかにサボっていたかよく分かります・・・

class diff_dpc:
        
    '''前月との疾患別比較を出す。funcはmean,sum,count辺りがいいが、
    groupbyで使えるなら何でもよい
    kaはオプションだが、あった方がグラフが見やすい'''
    
    def __init__(self,df,ka=None,func='sum'):
    
        self.df = df
        self.ka = ka
        self.func = func
        if self.ka:
            self.df = self.df[self.df['診療科区分'] == self.ka]
        else:
            pass

        self.df['MDC6'] = [x[0:6] for x in self.df['分類番号']]
        self.result = self.df.groupby(['month','MDC6']).agg(self.func)
        self.result.reset_index(inplace=True)
    
    
    def plot(self):
        ax = sns.barplot(x='MDC6',y='dpc総点数',hue='month',data=self.result)
        for item in ax.get_xticklabels():
            item.set_rotation(90)
        plt.show()
    
    def getdata(self):
        return self.result

使い方は test = diff_dpc(df,ka=110,func='count') のようにしてやります。すると二つのメソッドを持ったオブジェクトが出来ますので、 test.plot()でグラフを描画、'test.getdata()'でデータの取り出しが出来ます。
(別にインスタンス変数を指定しても同じ事なので、'test.result'としても問題ありません)

DPC疾患の月別推移を可視化する

今回はDPC入院料の分析のお話です。
DPC入院料の推移を見ると、時折奇妙な動きをすることがあります。特定の科の数字が跳ね上がったり、下がったりです。
もちろん中身をチェックすることになりますが、毎回集計して目で見るのは面倒ですね。自動化しましょう。 まず、元のデータとしてこんなものを用意します。

data = psql.read_sql("select to_char(実施年月日,'YYYYMM') AS month,データ識別番号,実施年月日,診療科区分,分類番号, \
sum(行為点数*行為回数) AS DPC総点数 \
from dtable \
Where データ区分 = 93 \
group by month,データ識別番号,実施年月日,診療科区分,分類番号",connection)

これで、診療月/診療科区分/分類番号を含むデータが得られました。 さて、次に出すのは分類別の集計です。DPC分類を使うとデータが細かくなりすぎますので、MDC6を使うことにします。
(分類番号の頭6桁を切り出すだけです)
点数合計の推移が見たいときもあれば、延べ件数が見たいとき、平均が見たいときなどもあるでしょう。 グラフに出来るといいですね。
深く考えずに全部突っ込んでみます。

def diff_dpc(df,ka=None,func='sum'):
    '''月別・MDC6別に集計したDataFrameを返す。funcはmean,sum,count辺りが良いが、
    groupbyで使えるなら何でもいい。
  同時に比較結果をグラフにして表示する。
    kaはオプションだが、無いと項目数が多すぎてグラフが見づらい'''
    if ka:
        df = df[df['診療科区分'] == ka]
    else:
        pass
    
    df['MDC6'] = [x[0:6] for x in df['分類番号']]
    
    result = df.groupby(['month','MDC6']).agg(func)
    result.reset_index(inplace=True)

    ax = sns.barplot(x='MDC6',y='dpc総点数',hue='month',data=result)
    for item in ax.get_xticklabels():
        item.set_rotation(90)
    plt.show()
    
    return result

実際には diff_dpc(data,ka=110,func='count') のようにして使います。 グラフの描画は完全に副作用ですし、引数で指定するかclassに書き換えて独立メソッドにした方がいい気もしますね…

認知症ケア加算の算定ミスをチェックする

明けましておめでとうございます。
つい数日前のエントリで、今年はSQL紹介だけの単調なエントリはやらないぞ!と書いておいてアレですが、算定ミスチェックのSQLでございます。
認知症ケア加算は、「入院後14日以前か、15日以降か」で算定する点数が変わります。
残念ながら、手入力をしていると、わりかしポコポコ算定ミスが出てきます。そこで、簡単なチェックを作ってみました。

SELECT データ識別番号,入院年月日,実施年月日,診療明細名称
FROM EFILE
WHERE 診療明細名称 LIKE '%認知症ケア%14日%'
AND 行為明細番号 = 0
AND 実施年月日 - 入院年月日 + 1 > 14
ORDER BY データ識別番号

認知症ケア加算には1と2がありますが、どちらを算定する病院でも使えます。
ここでは、入院15日目以降にも14日以内のコードを算定しているものを拾っています。
新年早々こんなんで申し訳ありませんが、今年もよろしくお願いいたします。

2016年の終わりに

このブログを始めたのが今年の1月でしたので、年が明ければ一周年となります。
お読み頂いた皆さんには、お付き合い頂き有り難うございました。
来年はもう少しマシな内容になると思います・・・うーん、なる、はず・・・なるといいな・・・

2016年のまとめ

今年はずっとPostgresとPandasの話ばっかり書いていました。
個人的には2015年からやっていましたが、今年はPython本がたっぷり出版されて、いよいよ「データ分析=Python」という空気が広まった感があります。
また、Rについてもたくさん本が出ましたから、そういう年だったのでしょう。

個人的な体験からすると、Pythonプログラマではない人のための第一言語です。
更に言えば、日々の仕事を楽にするために、ちょっとしたハックが必要な人に最適です。シェルスクリプトより汎用性があり、習得が楽で、しかも最高のデータ操作ライブラリを持っています。こんな言語は他に見当たりません。

今年仕事をしながら感じたのは、そろそろ事務仕事にもコードが必要な頃合いだ、ということです。別にプロのプログラマを必要としているわけじゃありません・・・たぶん、10行か20行、ぱぱっとでっち上げるだけで、随分助かるという仕事は多いんじゃないでしょうか。

2017年の展望

出来れば来年は、もう少し応用的な話を書けるようになりたいものです。
Pythonを使った統計分析や、機械学習は、私自身も実務での適用例がありません。
基礎の勉強はそこそこやっていたので、来年はいよいよ実践かなあ・・・

また、ブログの趣旨からは外れますが、余談を少し。

ウェブは世の中全てにやって来ます。「ウェブ」という言葉で意味するのは、HTML/CSS/JavaScriptです。私の読みが間違いでなければ、恐らく新規のデスクトップアプリケーションの多くがElectronベースに、すなわちNode.js上に構築されるようになるでしょう。
自分でもElectronでプロトタイプを組んだのですが、思った以上に簡単にアプリケーションが出来てしまうので驚きました。
ウェブアプリケーションをそのままデスクトップに持ってこれる、というのは本当に大きいです。
ということで、来年は

あたりにチャレンジしようかなあ、と思います。
それでは皆様、よいお年を。

Pythonでのデータ可視化について色々

Pythonでグラフを描こうと思ったら

まあ、普通はmatplotlibですね。
matplotlibは事実上のデファクトであり、これで困ることはまずありません。以上、今回はこれで終わり・・・
というわけには行きませんね。他にも幾つかの選択肢がありますので、見ていきましょう。

seaborn

seabornはmatplotlibをベースに構築されたグラフライブラリです。
matplotlibのスタイルはいかにも「研究論文に載せてください!」というものですが、seabornはもうちょっと洗練された見た目になります。
「あんまりスタイルをいじってる時間は無いけど、綺麗なグラフが欲しい」という時に重宝しますね。
また、matplotlibとseabornをimportしてグラフを描くと、自動的にseabornのスタイルが適用されます。単にmatplotlibのグラフを綺麗に描画したい、というときにもいいでしょう。
が、それだけに使うにはちょっと勿体ないというか、オーバーキル気味のライブラリでもあります。
heatmapの例を見れば分かるとおり、ゴリゴリの理系論文で使いそうなライブラリで、出自や想定される用途はmatplotlibに近いんだろうなあ・・・

Pandas

なんとPandasにもグラフ描画機能があります!
ドキュメントを読めば分かるとおり、DataFrameのメソッドにplotがあるのです。やった!これで可視化の方法は決まりだ!
・・・と、なるかどうかはともかく、さっとグラフを描くにはとても便利です。
ちなみに実体はmatplotlibですので、勘違いしないように。

Bokeh

Bokehは期待の新星で、上の3つ(matplotlib/seaborn/pandas)とは全くの別系統です。
というよりは、上の3つか同一系統というのが正しいですが・・・ BokehはJavascriptベースの可視化ライブラリで、結果はHTMLファイルか、scriptタグで返ります。
Webアプリケーションに組み込むには非常に便利で、かつ書く分にはPythonで完結し、一行もJavaScriptを書かなくていいというお手軽さ。
Pandasとの相性もいいです。
問題点は、まだ荒削りなこと。バージョン0.9x系までは外れ値を含むデータを描画するとヒストグラムが壊れたりしました。
現行バージョンでも、データ量が多くなるとフリーズしたり、描画が変になったりすることがあります。

まとめ

matplotlib系統が返すのはグラフオブジェクトで、それをpngなりX11ウインドウなりで描画することになります。
ウェブアプリケーションなどに組み込むのであれば、Bokehの方が扱いやすいかも知れません。
一方、得体の知れないデータがあって、どんなメチャクチャな描画になってもいいから、とにかく一度グラフにして状況を見てみたい!というときは、seabornを使うのが無難でしょう。
Pythonを使ってデータ分析をする場合、そういうトライアンドエラーを繰り返すのが多いですので、普段使いにはseabornがオススメです。
Pandasから直接接続できるBIツールみたいのがあればいいんですけどね・・・

DPCチェッカー0.10 ダッシュボード機能を追加

例によってこちらです。

バージョン0.08の変更点:ダッシュボード機能

予告通りダッシュボードをつけました。
開くと科別・病棟別の出来高対比グラフ、また同じく科別・病棟別の収益分布がグラフで描画されます。
ネタが思いつけば追加は簡単なので、順次増やしていくつもりです。

ビジュアライゼーションについて

今回はC3.jsを利用させて頂きました。 こちらは有名なD3.jsのラッパーで、棒グラフや円グラフをある程度簡単に描画出来ます。
ただし、JSONを知らない界隈から来ると(私がそうです)、結構面食らいますね。
Pythonのグラフライブラリは殆どがPandasのDataFrameを想定しているので、一般的な表形式データ(即ちcsvのようなもの)を頭に浮かべればすぐ理解できます。
が、JavaScriptの世界で想定されているのはJSONです。頭の切り替えには結構苦労しました。

最初っからMatplotlibなりSeabornなり使えば楽なのですが、どちらも配布するにはフォントの問題があります。
具体的には、ユーザー側でフォントファイルの追加をしないと日本語が文字化けする筈です。
Pythonから使うにはダントツで簡単なんですけどね・・・