You are on page 1of 95

レセプトデータ解析

鈴木瑞人
東京大学大学院 新領域創成科学研究科
メディカル情報生命専攻
博士課程1年

1
NDBオープンデータ
以下のスライドは下記リンクからの引用です。
http://www.mhlw.go.jp/stf/seisakunitsuite/bunya/0000139390.html

2
3
4
5
6
7
8
9
個別データの棒グラフに関しては資料にある

10
たとえばこのようなもの→

11
大部分都道府県別に集計してある。

12
この棒グラフからどうするか?
• 今のような一次元の情報(棒グラフ)からヒントを得て、
• それぞれがなぜ高いか低いかの理由の特定をするとなにかわかるかもしれな
い、、、
• 大部分、人口に比例しているが、そうでないところがあるので、その原因を何か
に帰着させることが出来れば何かの気づきにつながるかもしれない。。
• 遺伝
• 気候
• 慣習
• 食生活
• 医療の質
• ・・・
13
解析方針
• 本来のレセプトデータは、個人個人の情報でそれを追跡していくこと
でいろいろできますが、今回は集計データです。
• なのでレセプトデータに関する考え方を少し変えないといけません。
• まずデータ形式に沿って、できることをひとつづつやっていこうと思い
ます。

14
生データを見てみる
• とりあえず生データを目で見てみましょう。
• Excelの表(数値)を見やすくする方法
→色の濃さでヒートマップ
→棒の長さで値の大小を表す
→スタンプで値の大小を表す

15
たとえば、、

16
17
各都道府県のデータ選択の後、
条件付き書式を選択

18
カラースケールを選択(カラースケールの中の左上のもの)
値の大きさが色でわかるので、こ
れでデータを眺めてみる。

19
もっと解析したい場合
• 回帰
• 分類
• クラスタリング。。。

現状ではどのデータも説明変数がなくてこれらができない状態。。。
→説明変数を作る。
→目的変数(予測したいもの)を持ってくる

20
説明変数を作る
医科診療行為のA~N, 歯科傷病, 薬剤に関しては、
1、性年齢別で名寄せ
2、都道府県別で名寄せ

特定健診については、
3、都道府県別性年齢階級別で名寄せ
(ただし後述するが3、は相当大変)

21
1、性年齢別で名寄せ(イメージ)
初再診料 入院基本料 入院基本料等加算 特定入院料
0-4歳男
5-9歳男
10-14歳男
15-20男
・・・
0-4歳女

この一行一行を一個体として扱う。

22
2、都道府県別で名寄せ(イメージ)
初再診料 入院基本料 入院基本料等加算 特定入院料 ・・・・
北海道
青森
岩手
・・・

沖縄

47都道府県の一つ一つを1個体として扱う。

23
3、都道府県別性年齢階級別で名寄せ(イメージ)
BMI 腹周 空腹時血糖 収縮期血圧

北海道・男・0-4歳

北海道・男・5-9歳

北海道・男・10-14歳

・・・

青森・男・0-4歳

また目的変数の作製もしづらい。これはかなり手間がかかるので断念。
24
• 以上のように整形できれば、機械学習が出来る。
• また可視化もしやすい。

25
• ファイル形式がcsvでなく、excel形式であり、セルの結合などしている
こと、ファイルサイズがそんなに大きくないことから今回は手作業で
Excelファイルの中身を整形することにした。
• 前処理として、
• 欠損値の除去、説明変数にするものの名前を数字とアルファベット
の列に変える,桁区切りのコロンの除去、説明変数の名前付けを
行った。
• 今回は簡単のため、各説明変数を人口で割ることはしなかったが、
単位人口ごとの数を見たければ、人口で割るべき。

26
たとえば、、

27
28
新しいシートを作成。そのあと、G4からBA105までを選択してコピー。

29
A2を選択して、貼り付けボタンを押し、形式を選択して貼り付けを選択、行列を入れ替えるでOK.

30
ホーム→検索と選択→置換→”-”を”0”に変換(すべて置換を選択)

31
外来のシートに戻って、C5~C105までを選択
先ほどのシートに戻り、B1へ貼り付け(形式を選択して貼り付け→行列を入れ替える)

32
都道府県名をアルファベットに書き直す

33
桁区切りコンマを消す(すべての範囲を選択し、ホーム→数値→“標準”を“数値”へ変更)
(コンマがあると、csvファイルの読み込みの時にうまくいかないため)

34
目的のシートをcsvファイルとして出力。
ファイル→名前を付けて保存→ファイルの種類を“CSV(カンマ区切り)”
保存したものを開いてみると以下のように出てくる。1行目が変化しているようにみえるが、クリックしてみれば変化し
ていないことが分かる。

35
目的変数の作製
• 今回は都道府県別自殺率のデータを目的変数とする。

36
37
http://grading.jpn.org/Popy2117029.html
38
http://grading.jpn.org/Popy2117029.html
人口10万人あたりの自殺者数を目的変数に

39
データの読み込み

カレントディレクトリをデータがおいてあるDesktopへ移動。

40
t=read.csv("recept2.csv",header=T,row.names=1)
head(t) head関数で頭出しを見てみると、2列目以降の列名の頭にXが付いているのが
分かる。列名が数字だとRが勝手につけてくれる。

41
パッケージの読み込み
install.packages("randomForest",dependencies=T)
library(randomForest)

42
パラメータチューリング(mtry)
dim(t) #列が何列か(102列)を確認
rf1=tuneRF(t[,2:102],t[,1],best=T)

43
パラメータチューリング(ntree)
rf2=randomForest(suiciderate~., data=t, mtry=17)

ntreeはデフォルトの500のままでよさそう。

44
rf3=randomForest(suiciderate~., data=t, mtry=17, ntree=500,importance=T)

45
varImpPlot(rf3)

46
どうやら自殺に影響している項目は、、
X120002370: 薬剤情報提供料
X113006010: 生活習慣病管理料(処方せんを交付
しない)(脂質異常症を主病)
X113003710: 小児科外来診療料(処方せんを交付
しない)初診時
X113010010:糖尿病合併症管理料

X113014010: 外来リハビリテーション診療料2
X120002370: 薬剤情報提供料
X113003710: 小児科外来診療料(処方せんを交付
しない)初診時
X113010010: 糖尿病合併症管理料
X113003810: 小児科外来診療料(処方せんを交付
しない)再診時
X113013910: 外来リハビリテーション診療料1

解釈は一番最後のスライドに載せておきました 47
• 説明変数を人口で割った方がいいかもですね。
• 人口による違いが消してあった方が、そのほかのものがより見やす
いかもしれません。
• 割ってみましょう。

48
各都道府県の人口データ

http://uub.jp/rnk/p_k.html 49
各都道府県の人口データを作る。

50
ファイルのあるディレクトリへ移動
getwd()
setwd("C:\\Users\\Administrator\\Desktop\\")
getwd()
dir()

51
t=read.csv("recept3.csv",header=T,row.names=1)
head(t)

52
3列目から、103列目を2列目の各都道府県の人口で割る。

for(i in 3:103){
t[,i]=t[,i]/t[,2]
}

head(t) #データの頭出しをみて、人口で割った結果を見る。

53
54
今回使用するアルゴリズム
• Randomforest
• Elasticnet
• xgboost

• まずはRandomforestから

55
パッケージのロード
library(randomForest)

56
パラメータチューリング(mtry)
rf4=tuneRF(t[,3:103],t[,1],best=T)
mtry=17 が最適

57
58
パラメータチューリング(ntree)
rf5=randomForest(t[,3:103],t[,1],mtry=17)
plot(rf5)

59
モデル作成
rf6=randomForest(t[,3:103],t[,1],mtry=17,ntree=500,importance=T)

60
重要な説明変数のプロット
varImpPlot(rf6)
左の上から、
X113014010:
X113003710:
X113006010:
X113002410:
X180016110:
X113008410:

右の上から、
X113014010:
X113003710:
X113008310:
X180016110:
X113006010:
X113008510: 61
左の上から、
X113014010:外来リハビリテーション診療料2
X113003710:小児科外来診療料(処方せんを交
付しない)初診時
X113006010:生活習慣病管理料(処方せんを交
付しない)(脂質異常症を主病)
X113002410:在宅療養指導料 今回の目的変数である、自殺率と各変数を2次元にプロットしてみる。
X180016110:診療情報提供料(1)
X113008410:ニコチン依存症管理料(2回目から
4回目まで)

右の上から、
X113014010:外来リハビリテーション診療料2
X113003710:小児科外来診療料(処方せんを交
付しない)初診時
X113008310:ニコチン依存症管理料(初回)
X180016110:診療情報提供料(1)
X113006010:生活習慣病管理料(処方せんを交
付しない)(脂質異常症を主病)
X113008510:ニコチン依存症管理料(5回目)

62
外来リハビリテーション診療料2(X113014010)

plot(t[,1],t[,"X113014010"],type="n")
text(t[,1],t[,"X113014010"],
rownames(t))

63
自殺率
小児科外来診療料(処方せんを交付しない)初診時
(X113003710)
plot(t[,1],t[,"X113003710"],type="n")
text(t[,1],t[,"X113003710"],
rownames(t))

自殺率 64
生活習慣病管理料(処方せんを交付しない)
(脂質異常症を主病)(X113006010)
plot(t[,1],t[,"X113006010"],type="n")
text(t[,1],t[,"X113006010"], rownames(t))

自殺率 65
在宅療養指導料(X113002410)
plot(t[,1],t[,"X113002410"],type="n")
text(t[,1],t[,"X113002410"], rownames(t))

自殺率 66
診療情報提供料(1)(X180016110)
plot(t[,1],t[,"X180016110"],type="n")
text(t[,1],t[,"X180016110"],
rownames(t))

自殺率 67
ニコチン依存症管理料(初回)(X113008310)
plot(t[,1],t[,"X113008310"],type="n")
text(t[,1],t[,"X113008310"],
rownames(t))

68
自殺率
ニコチン依存症管理料(2回目から4回目ま
で)(X113008410)
plot(t[,1],t[,"X113008410"],type="n")
text(t[,1],t[,"X113008410"],
rownames(t))

69
自殺率
ニコチン依存症管理料(5回目)
(X113008510)
plot(t[,1],t[,"X113008510"],type="n")
text(t[,1],t[,"X113008510"], rownames(t))

自殺率 70
次はelasticnet
Caretパッケージを使用
(正確にはcaretにラップされているglmnetパッケージ)

71
library(caret)

72
train関数による学習
enet_fit = train(t[,3:103],
t[,1],
method = "glmnet",
tuneLength = 10,
preProc = c("center", "scale"))

73
Overall
X113001610 100.00
X113009210 92.46
X120002370 90.04
X113003410 80.49
varImp(enet_fit) X113010010 77.81
X113013410 69.05
X113014710 65.85
X113012810 65.32
X113003610 65.26
X113011210 54.46
X180016110 52.49
X113001210 52.40
X113016010 50.29
X113002310 48.30
X113013910 46.02
X113011610 44.59
X113004110 40.88
X113014510 40.34
X113005710 39.13
X113014410 38.76
74
plot(varImp(enet_fit),top=20)

75
Overall
X113001610 100.00 randomForestの結果
X113009210 92.46
X120002370 90.04 左の上から、
X113003410 80.49 X113014010:
varImp(enet_fit) X113010010 77.81 X113003710:
X113013410 69.05 X113006010:
X113014710 65.85 X113002410:
X113012810 65.32 X180016110:
X113003610 65.26 X113008410:
X113011210 54.46
X180016110 52.49 右の上から、
X113001210 52.40 X113014010:
X113016010 50.29 X113003710:
X113002310 48.30 X113008310:
X113013910 46.02 X180016110:
X113011610 44.59 X113006010:
X113004110 40.88 X113008510:
X113014510 40.34
X113005710 39.13
X113014410 38.76
76
varImp(enet_fit)
Overall
X113001610 100.00 :心臓ペースメーカー指導管理料(イ又はロ以外)
X113009210 92.46 :ハイリスク妊産婦共同管理料(1)
X120002370 90.04 :薬剤情報提供料
X113003410 80.49 :集団栄養食事指導料
X113010010 77.81 :糖尿病合併症管理料
X113013410 69.05 :植込型輸液ポンプ持続注入療法指導管理料
X113014710 65.85 :認知症療養指導料
X113012810 65.32 :がん性疼痛緩和指導管理料(緩和ケアに係る研修を受
けた保険医)
X113003610 65.26 :小児科外来診療料(処方せんを交付)再診時
X113011210 54.46 :医療機器安全管理料(生命維持管理装置使用)
X180016110 52.49 :診療情報提供料(1)
X113001210 52.40 :悪性腫瘍特異物質治療管理料(尿中BTA)
X113016010 50.29 :介護保険リハビリテーション移行支援料
X113002310 48.30 :皮膚科特定疾患指導管理料(2)
X113013910 46.02 :外来リハビリテーション診療料1
X113011610 44.59 :地域連携夜間・休日診療料
X113004110 40.88
X113014510 40.34
X113005710 39.13
77
X113014410 38.76
学習の時、
These variables have zero variances: X113014810, X113015130,
X113006610, X113015510, X113015610, X113006110, X113015910,
X113011710, X190056910, X113009210
と出てきたので、これら、10個を削除して再度elasticnetにかける。

78
本当にzeroかを確認
summary(t[,c("X113014810", "X113015130", "X113006610", "X113015510", "X113015610", "X113006110",
"X113015910", "X113011710", "X190056910", "X113009210")])

↑全てが0というわけではないものの、
elasticnetとしてはだめらしい。。 79
ゼロの列を削除
A= c("X113014810", "X113015130", "X113006610", "X113015510",
"X113015610", "X113006110", "X113015910", "X113011710",
"X190056910", "X113009210")
for(i in 1:length(A)){
t <- t[ , colnames(t) != A[i]]
}

80
str(t)

81
enet_fit2 = train(t[,3:93],
t[,1],
method = "glmnet",
tuneLength = 10,
preProc = c("center", "scale"))

82
なぜか、説明変数の重要度が、not a numberになってしまうの
で、ここで断念。。今回alpha=1なのでLassoであり、Lassoはサ
ンプル数より、説明変数が多い時、説明変数の重要度が正し
く計算されないことが知られているので、今回はelasticnetの使
用は控えた方がよさそう。。 モデル選択の方法を別なものに
変更するのも一つの手だが(今回はデフォルト設定で行った)。。

83
次にxgboostでのモデル作成と
パラメータチューリング
xgb1 = train(
x = t[,3:103],
y = t[,1],
tuneLength=20,
method= "xgbTree"
)

84
85
86
X113014010 100.000
X113003710 75.676
X113002410 59.022
X180016110 56.825
X113006010 36.233
X113005910 29.253
X113014110 25.546
X180010510 25.538
X111000470 21.137
X120002370 18.353
X113003210 18.218
X113003510 16.057
X113001810 14.685
X113001010 12.782
X113002310 11.517
X113013810 10.616
X113008310 9.263
X113001510 9.243
X113011610 8.800
X113004110 8.548 87
X113014010 100.000 : 外来リハビリテーション診療料2
X113003710 75.676 : 小児科外来診療料(処方せんを交付しない)初診時
X113002410 59.022 : 在宅療養指導料
X180016110 56.825 : 診療情報提供料(1)
X113006010 36.233 : 生活習慣病管理料(処方せんを交付しない)(脂質異常症を主病)
X113005910 29.253 :生活習慣病管理料(処方せんを交付)(糖尿病を主病)
X113014110 25.546 :外来放射線照射診療料
X180010510 25.538 :開放型病院共同指導料(1)
X111000470 21.137 :乳幼児育児栄養指導料
X120002370 18.353 :薬剤情報提供料
X113003210 18.218 :ウイルス疾患指導料2
X113003510 16.057 :小児科外来診療料(処方せんを交付)初診時
X113001810 14.685 :特定疾患療養管理料(診療所)
X113001010 12.782 :外来栄養食事指導料
X113002310 11.517 :皮膚科特定疾患指導管理料(2)
X113013810 10.616 :夜間休日救急搬送医学管理料

説明変数の重要度高いものの上位は、randomForestの結果と似ている。

88
plot(varImp(xgb1))

89
xgboost グリッドサーチを行ったものの、これでは範囲が広かったらしく、計算が2時間
たっても終わらなかったのでいったん断念。今度はnroundsあたりを狭めて実
施予定。

xgb_grid_1 = expand.grid(
nrounds = seq(50,1000,50),
max_depth = c(5, 10, 15, 20),
eta = c(0.01, 0.001, 0.0001),
gamma = c(0, 1, 2),
colsample_bytree = c(0.4, 0.7, 1.0),
min_child_weight = c(0.5, 1, 1.5)
)

90
グリッドサーチを行ったものの、これでは範囲が広かったらしく、計算が2時間
たっても終わらなかったのでいったん断念。今度はnroundsあたりを狭めて実
施予定。

xgb2 = train(
x = t[,3:103],
y = t[,1],
tuneGrid = xgb_grid_1,
method = "xgbTree"
)

91
Xgboostで調整が必要なパラメータは6個、、多い。。tuneLengthだと4つまでしかやってくれないので、後の2
つは手動。ただ89ページのチューリングの結果を見てみた感じでは、デフォルトのganma=0を、少し動かす(1
や2に)のと、デフォルトのmin_child_weight=1を少し動かす(0.5や1.5に)ことをしてみればよいと思われる。

http://topepo.github.io/caret/available-models.html

92
今後試してみるもの

http://topepo.github.io/caret/available-models.html

93
今後試してみるもの

http://topepo.github.io/caret/available-models.html

94
まだ途中ではありますが。。
• こんな感じで、説明変数と目的変数の設定から、回帰を行い、説明
変数の重要度を出して、目的変数と任意の説明変数をxy平面上に
プロットしてみて、何がいえそうか考えてみるということが出来るかな
と思います。
• 今回の使ったデータは、各重要説明変数と目的変数との関係は、傾
きが-1に近いか、反比例に近いという傾向があることが分かりました。
• 地方の県は、一般に糖尿病患者が多かったり、あまり健康でないこ
とが知られている県がありますが、そういう県での、一人あたりの診
療得点が低かったことから、本来病院に行くべき人が行っておらず、
本来病院に行っていれば自殺しなかった人が自殺してしまっている
のではないかと個人的には判断しました。
• 実際の判断には専門家の知見が必須と思われます。
95

You might also like