薬剤師のプログラミング学習日記

プログラミングやコンピュータに関する記事を書いていきます

病棟薬剤業務実施加算を届出している病院について調べる

薬剤師が重要な役割を果たすことで算定できる施設基準は数多くありますが、今回は病棟薬剤業務実施加算の届出をしている病院について、病床数やその他の施設基準との関係をPythonを使って調べてみました。記事の前半は主にデータの概要やプログラムのデータ構造について、後半(目次6以降)で結果について書いています。


結果

先に調べた結果をざっと書いておきます。
3つの地方厚生局から得たデータ『施設基準の届出受理状況(全体)』によると、

  • 総病床数が20床以上である医療機関の件数:4502
  • 病棟薬剤業務実施加算1を届出している病院の件数:1241
  • 病棟薬1/全病院 = 1241 / 4502 ≒ 0.28
  • 「病棟薬1」届出病院の病床数の度数分布表
  • 「病棟薬1」を届出している病院と病院全体の病床数のヒストグラム
  • 病床数別の病棟薬1届出病院の割合
病床数 届出率(%)
病床数 20-99
15.1
病床数 100-199
22.0
病床数 200-299
25.5
病床数 300-399
51.0
病床数 400-499
54.0
病床数 500-1199
73.4
他の施設基準/病棟薬1 届出率(%)
菌/病棟薬1
77.8
医療安全1/病棟薬1
62.3
医療安全2/病棟薬1
26.2
感染防止1/病棟薬1
54.2
感染防止2/病棟薬1
39.1

※'菌'は無菌製剤処理料


データのダウンロード

今回は以下の3つの地方厚生局のページからデータをダウンロードしました(順不同)。

  1. 近畿厚生局
  2. 東海北陸厚生局
  3. 関東信越厚生局

1は『施設基準の届出受理状況(全体)』
2は『6.東海北陸厚生局管内の施設基準の届出受理状況(全体)』
3は『施設基準の届出状況(全体)(届出受理医療機関名簿)』
の『各都府県エクセルデータ-医科』からZIPのところをクリックしてデータをダウンロードします。ダウンロードが終わったら、中のExcelファイルをまとめて適当な場所に展開しておきます。
なお、データについては関東信越厚生局は令和2年11月1日現在、あとの2つの厚生局は令和2年12月1日現在となっていました。

データの概要

各都府県のExcelファイルを開いてみると列の項目名として以下のようなものがあります(一部抜粋)。
項番、都道府県コード、医療機関番号、医療機関名称、病床数、受理届出名称、受理記号、・・・等いろいろありますが、有難いことにどの地方厚生局のExcelファイルも列の順番や格納するデータの形式など、同じ書式で作成されているようです。
今回のプログラムで使用するのは都道府県コード、医療機関番号、病床数、受理記号です。これらについてざっとみておきます。

  • 医療機関番号:各医療機関に振られた7桁の数字です。この7桁の番号の頭に都道府県コード2桁と医科、歯科等の保険区分1桁の計3桁の数字を加えた数字が医療機関コードとしてレセプトや処方せんで使用されます。今回のプログラムでは、医療機関ごとの重複のないキーとして使用できればOKなので、医科を示す1は加えずにこの7桁の数字の頭に都道府県コードを加えた9桁を医療機関コードとして使用します。
  • 病床数:「一般 100/ 療養 50」のような表記となっています。今回は各病棟の病床数を合計したものを「総病床数」、使用されている「一般」や「療養」等のワードを「病床分類」として扱いました。
  • 受理記号:届出施設基準の正式名称だと長いので、略称である受理記号を用います。対応表も各地方厚生局のページにあります(リンク先は関東信越厚生局)。

  届出受理医療機関名簿の受理番号欄における略称一覧(PDF)

pandasを使ってExcelファイルをCSVファイルに変換する

ダウンロードしたExcelファイルにはある程度サイズが大きなファイル*2もあるので、省メモリと速度の観点から、必要な項目のみを抜き出したCSVファイルを最初に作成しておくことにしました。
次のようなフォルダ構成にして以下のコードを実行します。save_excelフォルダのファイルがダウンロードして展開したExcelファイルです。

└── 作業フォルダ
    ├── code1.py
    └── save_excel
        ├── 2020.12_sisetukijun_fukui_ika.xlsx
        ├── 2020.12_sisetukijun_hyogo_ika.xlsx
        │   ・
        │   ・
        └── (愛知医科)届出受理医療機関名簿_20201201_173946.xlsx
<code1.py>

import glob, os, re
import pandas as pd
 
# save_excelフォルダのExcelファイルからCSVファイルを作成する
 
current_dir = os.path.abspath('.')
excel_files = glob.glob(current_dir + '\\save_excel\\*.xlsx')
os.makedirs(current_dir + '\\save_csv', exist_ok=True)
 
for readfile in excel_files:
    df = pd.read_excel(readfile, dtype=str,
                        usecols=[1, 4, 12, 14],  # 使うカラム
                        skiprows=[0, 1, 2])      # 冒頭3行飛ばす
 
    df.insert(0, '医療機関コード', df['都道府県コード'] + df['医療機関番号'])
    df.drop(labels=['都道府県コード', '医療機関番号'], axis=1, inplace=True)
    # 日本語がファイル名に混ざっているとread_csvで読み込み時にエラーになるので
    # 半角英数字,ハイフン,アンダーバーのみ残す
    f_name = os.path.splitext(os.path.basename(readfile))[0]  # ファイル名
    new_f_name = ''.join(re.findall(r'[-_0-9a-zA-Z]', f_name))
    print(new_f_name)
    # index=FalseでDataFrameの持つ行番号は出力しない
    df.to_csv(current_dir + '\\save_csv\\' + new_f_name + '.csv', encoding='utf-8-sig',  index=False)
 

このプログラムを実行すると、作業フォルダ内に新たにsave_csvというフォルダを作りその中にCSVファイルが作成されます。
Excelファイルの読み込みはPandasのpandas.read_excel()を使っています。Pandasとはデータ分析などでよく使われるライブラリで、数表や時系列データの操作・統計的な処理を簡単に行うことができます。Anacondaをインストールした方は上のコードをそのまま実行することができますが、環境にない方はインストールが必要です。(また、read_excel()は内部でxlrdというライブラリを使っているので、Anacondaでない方はこちらのインストールも必要になります)

話を戻します。pandas.read_excel()のパラメータのusecolsで読み込む列(都道府県コード、医療機関番号、病床数、受理記号に対応する列)を指定しています。また、先頭の3行は「空行、作成日、空行」でこれらも必要ないので行番号のリストをskiprowsで指定して読み飛ばします。
前述したように都道府県コードと医療機関番号は合わせて「医療機関コード」として0列目に挿入し、その後使用した都道府県コードと医療機関番号はもう必要ないので削除しています。
あとはfor文の最後でto_csv()メソッドを使ってCSVファイルとして書き出しています。その際、encoding='utf-8-sig'と指定することで、出来たCSVファイルをExcelで開いても文字化けしなくなります。
実行の結果、以下のようなCSVファイルが作成されます(一部編集・加工しています)。

医療機関コード 病床数 受理記号
720115101 がん指
720115101 電情
720115420 一般 500/一般(感染)10 無菌1
720115420 一般 500/一般(感染)10 栄養チ
720115420 一般 500/一般(感染)10 病棟薬1



ひとつの医療機関コードに対して、届出をしている施設基準(受理記号)が複数ある場合には、医療機関コード、病床数は同じで異なる受理記号の行が重ねられているデータ形式となっています。


医療機関ごとに総病床数と病床分類、施設基準リストを持つ辞書をつくる

各医療機関には一意の「医療機関コード」があり、また「病床数」*3と「(届出)受理記号」という決まった項目を持つため、これらをキーとして対応する要素を管理できる辞書にこれらの値を入れていくことにします。
作成する辞書のイメージは次のようなものです。

 
{医療機関コード: {総病床数:int, 病床分類:['一般', ...], 受理記号:[A, B, ...]}}

辞書がネスト(入れ子)になっていて、親辞書のキーは"医療機関コード"、値として子の辞書を持ちます。子の辞書はそれぞれ"総病床数"と"病床分類"、"受理記号"をキーに持ちます。
出来た辞書をループで回してキーと値を表示させると次のようになります(編集・加工しています)。

720117200 {'総病床数': 0, '病床分類': ['nan'],  '受理記号': ['外後発使', '酸単']}
720117400 {'総病床数': 0,  '病床分類': ['nan'], '受理記号': ['オン診']}
720119200 {'総病床数': 80,  '病床分類': ['一般'], '受理記号': ['機能強化', '一般入院', '診療録2','感染防止2', '後発使1', '薬',]}

総病床数は病床数の項目から数字のみを抜き出して合計した値、病床分類は病床数の項目から数字以外のワードを抽出、受理記号は全部をまとめてリストとして持つような辞書です。
プログラムでは「Pythonでダブルクォーテーション囲いのCSVファイルを作成する」でやったように1行ずつ読み込んで処理していきますが、受理記号のリストを作る部分ではpandasのgroupbyメソッドを利用しています。

次のコードで医療機関コードでグループ分けされたものがdgに入ります。

dg = df.groupby('医療機関コード')['受理記号'].apply(list)
print(dg)
# 医療機関コード1   [ニコ, 175]
# 医療機関コード2   [がん指, 電情, 画1, 175]
# 医療機関コード3   [オン診, 一般入院, 療養入院, 診療録2, 療養1, 後発...]
・・・

あとは辞書に格納する際に、該当する受理記号のリストを医療機関コードで呼び出してやります。

h_dict[h_code]['受理記号'] = dg[int(h_code)]

あとの2つのキーについてですが、"総病床数"の方は「病床数」の項目にfindall()を使って数字にマッチする部分をリストで取得後、それらを合計するようにし、"病床分類"は数字や/(スラッシュ)を取り除くことで「一般」「療養」などのワードを得られるようにしました。

特定の要素を抽出した病院の件数を出してみる

ここまでの作業で辞書には各医療機関ごとの総病床数、病床分類と届出している施設基準(=受理記号)が紐づけされています。次はこの辞書を使っていろいろ件数を出してみます。
例えば、総病床数が20床以上である医療機関の件数は次のコードで出せます。

# 病院(20床以上)件数
print(len([k for k, v in h_dict.items() if v['総病床数'] >= 20]))
# 4502

では、次は「病棟薬剤業務実施加算1」を届出している病院の件数*4を見てみます。受理記号では「病棟薬1」なので、これを受理記号の値として持つ医療機関コードの数を調べます。

# 病棟薬剤業務実施加算1を届出している病院の件数
print(len([k for k, v in h_dict.items() if '病棟薬1' in v['受理記号']]))
# 1241 

1241件です。ということは、病棟薬1/全病院 = 1241 / 4502 ≒ 0.28と約3割の病院*5が「病棟薬1」を届出していることになります。

こちらのページ
中小病院の病棟業務加算の要件緩和が濃厚に:DI Online
によると、『病棟薬剤業務実施加算の届出を行っている病院は全体の約2割(平成30年7月1日現在の届出状況)』とあります。こちらのデータは全国でしょうか、少なくとも一部の地域だけとは書いていないので単純に比較はできませんが、徐々に増えてきているのかもしれませんね。

病棟薬剤業務実施加算1を届出している病院の病床数の分布をみる

病棟薬1を届け出ている病院の病床数をヒストグラムにして分布を見てみます。
ヒストグラムというのは、それぞれの値(ここでは病床数)の度数(値が出現する回数)を示すグラフのことです。
階級数を決めるには、スタージェスの公式(階級数=1+log2(データ数))や平方根などいろいろありますが、先ほどのDI Onlineのページの病床別のデータが100区切りとなっていた(こちらはヒストグラムではありませんが)ので、ここでも階級幅は区切りの良い100*6とし、それに合わせて階級数を11と決めました。

以下に「病棟薬1」届出病院の病床数の度数分布表を示します。

階級 度数 相対度数 累積度数 累積相対度数
0~100未満
228
0.184765
228
0.184765
100~200未満
334
0.270665
562
0.455429
200~300未満
140
0.113452
702
0.568882
300~400未満
208
0.168558
910
0.737439
400~500未満
136
0.110211
1046
0.847650
500~600未満
76
0.061588
1122
0.909238
600~700未満
46
0.037277
1168
0.946515
700~800未満
21
0.017018
1189
0.963533
800~900未満
20
0.016207
1209
0.979741
900~1000未満
16
0.012966
1225
0.992707
1000~1100未満
9
0.007293
1234
1.000000

病床数が1100以上のデータは切り捨てたので、累積度数は1241ではなく1234となっています。
なお、度数分布表についてのコードはこちらを参考にさせてもらいました。
Pythonで度数分布表を一発で自動生成する - Qiita

下に「病棟薬1」を届出している病院と病院全体の病床数の分布を並べてみました。
f:id:enokisaute:20201219112134p:plainf:id:enokisaute:20201219112137p:plain
病棟薬1届出病院のヒストグラムは、全体的には病院の病床数の分布と似たような、右に裾を引く形をしていますが、分布の形が同じとまでは言えません。例えば、100床未満の病院の数は100~200未満の病院と同じくらいあるにも関わらず、比較するとその度数は100程度落ち込んでいるのがわかります。割合で言うと、100未満の病院は病院全体の中では3割強ありますが、病棟薬1届出病院の中で見ると2割に届いていません。
このようになっている原因は、病床数によって届出率が異なるからです。これについては次の項目で見てみます。

集合演算を使って病床数別の病棟薬1届出の割合を求める

上の度数分布表の相対度数は「全体に対するその階級の度数の割合」でしたが、今度は病床数別に見たときに、どれくらいの割合で病棟薬1を取得しているかを見てみます。

# 病床数別の割合を集合演算を用いて求める
min_list = [20, 100, 200, 300, 400, 500]    # 病床数の下限
max_list = [100, 200, 300, 400, 500, 1200]  # 〃上限
# 病棟薬1届出病院の集合
s1 = set([k for k, v in h_dict.items() if '病棟薬1' in v['受理記号']])
for _min, _max in zip(min_list, max_list):
    # 総病床数が_min以上_max未満の病院の集合
    s2 = set([k for k, v in h_dict.items() if _min <= v['総病床数'] < _max])
    print('病床数{0}-{1}: {2:.1f}%'.format(_min, _max - 1, len(s1 & s2) / len(s2) * 100))

s1には受理記号に「病棟薬1」を届け出ている医療機関コードのリストを取得し、それをset()で同じ要素を重複して持たない集合と呼ばれるデータ型に変換しています*7。このset型と「&」や「|」という演算子を使うと、set型同士で集合演算を行うことができます。各集合の関係を下図に示しました。
f:id:enokisaute:20201219103349p:plain

以下が実行結果です。

病床数 20-99: 15.1%
病床数 100-199: 22.0%
病床数 200-299: 25.5%
病床数 300-399: 51.0%
病床数 400-499: 54.0%
病床数 500-1199: 73.4%

先ほどのDIonlineのページでも示されている通り、病床数が多くなるにつれ、届出率は高くなっています。

次のグラフは病床規模別に病棟薬1の届出あり・なしで病床分類を比べたものです。
f:id:enokisaute:20201220215259p:plain
各病院ごとに病床数の列に使われているワードを抽出し、カウントしていったものの割合をグラフにしています。
なお、便宜上「病床分類」としましたが、医療法による病床分類とは少し異なります。中には「介護」や「特定」、「その他」というワードもありましたが、そのままカウントしています。また、「一般 100/一般(感染) 感染 10」みたいなものも混じっていましたが、この場合には「一般: 1, 一般(感染):1, 感染: 1」とカウントしているので(ただし、「一般 一般 100」などの場合はきちんと重複は削除しています)、だいたいの傾向である、というくらいの認識で見ていただければと思います。
ざっと見た感じでは、やはりどの病床数でも「届出あり」病院は一般病床が多いようですね。

他の施設基準との関係をみる

病棟薬1届出病院のうち、他の施設基準の届出の割合を見てみます。選んだ施設基準は『無菌製剤処理料、医療安全対策加算1と2、感染防止対策加算1と2』の5つです。これらを選んだ理由として、特に根拠といえるほどのものはありませんが、無菌製剤処理料についてはある程度関係がありそうかなというのと、医療安全対策と感染防止対策加算については1と2で差が出そうかな、と思ったという程度です。略号についてはコード内をご参照ください。

notifi_list = ['菌', '医療安全1', '医療安全2', '感染防止1', '感染防止2']  # '菌'は無菌製剤処理料
for n in notifi_list:
    s = set([k for k, v in h_dict.items() if n in v['受理記号']])
    print('{0}/病棟薬1* 100 = {1:.1f}%'.format(n, len(s1 & s) / len(s1) * 100))
 
# 菌/病棟薬1* 100 = 77.8%
# 医療安全1/病棟薬1* 100 = 62.3%
# 医療安全2/病棟薬1* 100 = 26.2%
# 感染防止1/病棟薬1* 100 = 54.2%
# 感染防止2/病棟薬1* 100 = 39.1%

無菌製剤処理料とは専用の設備で抗がん剤等の無菌製剤処理を行う場合に算定できる(注:正確な書き方ではありません。詳しくは厚生労働省のページ等でお調べください。)施設基準で、病棟薬剤業務として実施・計上することもできます。
77.8%というのはなかなか高い数字だと思います。しかし、少し資料が古いですが、大阪府病院薬剤師会のアンケート(平成25年6月)の『2.病棟薬剤業務の実施状況、所要時間の順位、所要時間(時間/週/病棟)』によれば、抗がん薬等の無菌調整は4~6位なので、病棟薬剤業務のメインといえるものではなく、あくまでその業務の内の1つという捉え方で良いと思います。

医療安全対策加算と感染防止対策加算については、どちらも2よりも1の方が多いという結果でした。病棟薬1の届出率は病床数が多くなるにつれて高くなっているということと、届出の基準としては、1の方がハードルが高いと思っていたので、まあこれはそうだろうな、というかんじです。ただ、私もあまり施設基準に関して詳しいわけではないので、これ以上の言及は控えておきます。

まとめ

今回は病棟薬剤業務実施加算を届け出ている病院について調べてみました。pandasはいろいろな機能がありデータの分析には便利ですが、使いこなすには一朝一夕というわけにはいきません。これからも使用機会を増やしていきたいところです。
結果としてはだいたい予想通りでしたが、一方では病床規模が小さくても届出をしている病院数も決して少なくないという、少し意外な事実も知ることができました。

参考

pandasに関する情報 | note.nkmk.me
辞書をpd.DataFrameに変換 - Qiita
みんなのPython 第4版
Think Stats 第2版 ―プログラマのための統計入門
・Excelで学ぶ統計解析本格入門



こちらがコード全文です。実行時はcode1.pyと同じ場所に置いてください。

import csv, glob, os, re, unicodedata
import matplotlib.pyplot as plt
from collections import OrderedDict
import numpy as np
import pandas as pd
 
# 先にcode1.pyを実行してExcelからCSVへ変換しておくことが必要
# 地方厚生局の施設基準届出データを使って, 病棟薬剤業務実施加算届出病院について調べる
 
# 全角半角を正規化してスペースを全て削除する
def normalize(value):
    return unicodedata.normalize('NFKC', value).replace(' ', '')
 
# 各病棟('一般', '療養'等)のベッド数を合計する
def get_num_of_beds(value):
    num_list = re.findall(r'\d+', value)
    return sum([int(x) for x in num_list])
 
# 病床分類をリストにする
def get_bed_category(value):
    value = re.sub(r'\d+|/', '', value)
    return value.split()
 
# {病床分類: カウント数}の辞書を作成しデータフレームに変換して返す
def dict_to_df(code_list, _dict, cat_list):
    # 記事中と同じグラフの色にしたい場合は以下をコメントアウト. 並び順で変わるため
    # cat_list = ['一般', '一般(感染)', '感染', '感Ⅱ', '結核', '療養', '精神', '介護', '特定', 'その他']
    new_dict = OrderedDict({key: 0 for key in cat_list})
    for c in code_list:
        for cat in list(set(_dict[c]['病床分類'])):  # 重複するワードを削除するため一旦setに
            new_dict[cat] += 1
    return pd.DataFrame.from_dict(new_dict, orient='index').T
 
# 2つのデータフレームを結合して行方向の比率を求めて返す
def get_df_proportion(df_1, df_2):
    df_concat = pd.concat([df_1, df_2])    # 結合
    df_concat.fillna(0, inplace=True)      # nanをゼロ埋め
    df = df_concat.reset_index(drop=True)  # インデックスを連番に振り直し
    df.index = ['あり', 'なし']        # 届出の有無
    return df.apply(lambda x: x / sum(x), axis=1)  # 行方向に各値の割合を求める
 
 
if __name__ == '__main__':
    current_dir = os.path.abspath('.')
    csvfiles = glob.glob(current_dir + '\\save_csv\\*.csv')
 
    CODE = 0    # 医療機関コード(CSVファイル列番号)
    BEDS = 1    # 病床数(〃)
 
    h_dict = {}   # {医療機関コード: {総病床数: int, 病床分類: ['一般', ...], 受理記号:[A, B, ...]}, ...}
    prev = 0
 
    for readfile in csvfiles:
        f_in = open(readfile, 'r', encoding='utf-8-sig')
        csvreader = csv.reader(f_in)
        header = next(csvreader)
        df = pd.read_csv(readfile)
        dg = df.groupby('医療機関コード')['受理記号'].apply(list)
        for row in csvreader:
            h_code = normalize(row[CODE])
            if h_code == prev:  # 医療機関コードが同じものは飛ばす
                continue
            h_dict.setdefault(h_code, {})
            h_dict[h_code]['総病床数'] = get_num_of_beds(normalize(row[BEDS]))
            h_dict[h_code]['病床分類'] = get_bed_category(row[BEDS])
            h_dict[h_code]['受理記号'] = dg[int(h_code)]
            prev = h_code
 
    print('医療機関全件数: ', len(h_dict))
    print('病院(20床以上)件数: ', len([k for k, v in h_dict.items() if v['総病床数'] >= 20]))
    print('病棟薬1届出件数: ', len([k for k, v in h_dict.items() if '病棟薬1' in v['受理記号']]))
 
    # 病棟薬剤業務実施加算1を届出している病院の医療機関コードのリスト
    code = [k for k, v in h_dict.items() if '病棟薬1' in v['受理記号'] and v['総病床数'] >= 20]
    # その医療機関コードの総病床数のリスト
    kasan1_beds = [h_dict.get(c)['総病床数'] for c in code]
 
    print('病棟薬1届出病院の病床数の度数分布表\n')
    bins = np.arange(0, 1200, 100)
    hist, _ = np.histogram(kasan1_beds, bins)  # 度数, ビンの境界のリストが返る
    cumsum = hist.cumsum()      # np.cumsum()で累積和を取得
    pd.set_option('display.unicode.east_asian_width', True)
    print(pd.DataFrame({'度数': hist,
                        '累積度数': cumsum,
                        '相対度数': hist / cumsum[-1],  # 度数 / 度数の合計
                        '累積相対度数': cumsum / cumsum[-1]},
                        index=pd.Index([f'{bins[i]}~{bins[i+1]}未満'
                                for i in range(hist.size)],
                                name='階級')))
 
    # 20床以上の病院(内包表記をネストにすれば1行で書けないことはないが, 後でわかりにくいので分ける)
    code = [k for k, v in h_dict.items() if v['総病床数'] >= 20]
    beds = [h_dict.get(c)['総病床数'] for c in code]
 
    # ヒストグラムの表示
    plt.subplot(1, 2, 1)
    plt.hist(kasan1_beds, ec='black', bins=11, range=(0, 1100))
    plt.title('病棟薬1届出病院の病床数')
    plt.subplot(1, 2, 2)
    plt.title('病院の病床数')
    plt.hist(beds, ec='black', bins=11, range=(0, 1100))
    axs = plt.gcf().get_axes()
    for ax in axs:
        ax.grid(axis='y', alpha=0.7, linestyle='--')
        ax.set_xlim(0,)
        ax.set_xlabel('病床数')
        ax.set_ylabel('度数')
    plt.show()
 
    print('病床数別の病棟薬1届出の割合')
    min_list = [20, 100, 200, 300, 400, 500]      # 病床数の下限
    max_list = [100, 200, 300, 400, 500, 1200]    # 〃上限
    # 病棟薬1届出病院の集合
    s1 = set([k for k, v in h_dict.items() if '病棟薬1' in v['受理記号']])
    for _min, _max in zip(min_list, max_list):
        # 総病床数がmin以上max未満の病院の集合
        s2 = set([k for k, v in h_dict.items() if _min <= v['総病床数'] < _max])
        print('病床数 {0}-{1}: {2:.1f}%'.format(_min, _max - 1, len(s1 & s2) / len(s2) * 100))
 
    fig = plt.figure()
    fig.suptitle('病棟薬1届出別の病床分類の比較', fontsize=25)
    # すべての病床分類を重複のないリストとして取得する
    cat_list = list(set([cat for k, v in h_dict.items() for cat in v['病床分類'] if cat != 'nan']))
    for i, (_min, _max) in enumerate(zip(min_list, max_list)):
        ax = fig.add_subplot(2, 3, i + 1)
        s2 = set([k for k, v in h_dict.items() if _min <= v['総病床数'] < _max])
        df1 = dict_to_df(s1 & s2, h_dict, cat_list)   # 病棟薬1届出あり
        df2 = dict_to_df(s2 - s1, h_dict, cat_list)   # 病棟薬1届出なし
        df = get_df_proportion(df1, df2)
        df.plot.bar(stacked=True, ax=ax, width=0.4, colormap='Paired').legend(
            loc="upper center", bbox_to_anchor=(0.5, -0.25,),
            borderaxespad=0, ncol=4)
        plt.setp(ax.get_xticklabels(), rotation=45, fontsize=10)
        plt.title('病床数{0}以上{1}未満'.format(_min, _max))
    plt.subplots_adjust(left=0.1, bottom=0.15, wspace=0.5, hspace=0.7)
    plt.show()
 
    print('病棟薬1病院の他の施設基準届出の割合')
    notifi_list = ['菌', '医療安全1', '医療安全2', '感染防止1', '感染防止2']     # '菌'は無菌製剤処理料
    for n in notifi_list:
        s = set([k for k, v in h_dict.items() if n in v['受理記号']])
        print('{0}/病棟薬1* 100 = {1:.1f}%'.format(n, len(s1 & s) / len(s1) * 100))
 

*1:無菌製剤処理料、医療安全対策加算1と2、感染防止対策加算1と2

*2:といっても数万行程度ですが

*3:診療所等で病床が空欄の場合は0とします

*4:加算2は1を取っていることが前提なので、ここでは1だけをみていきます

*5:20床未満で病棟薬1を取っている施設はありません。

*6:通常は階級幅もデータの最小値から最大値の範囲を階級数で均等割りするなどして求めます。

*7:医療機関コードには元々重複はありませんが、集合演算を行うためです。もちろん、if以下の条件式をandで付け加えてやればリストのままでも同じ結果を得ることができます。