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

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

【Pythonデータ分析】薬剤師が少ない県はどこ?人口10万人あたりの数を日本地図で可視化

薬剤師の数は右肩上がりで増えていると言われていますが、都道府県別で見るとどれくらい偏りがあるのでしょうか。これから薬剤師として働こうしている学生の方や、すでに現場で働いている薬剤師の方でも、自分のいる所が多いのか少ないのかを数字として把握している人は意外と少ないかもしれません。また、異動のある会社に勤めていたり、就職・転職を考えていたりすると地域ごとの需給バランスは気になるところです。
そこで今回は、Pythonのjapanmapライブラリを使い、人口10万人あたりの薬剤師数を都道府県別に可視化してみました。

使用データ

令和6(2024)年医師・歯科医師・薬剤師統計の概況|厚生労働省
ページ中ほどの「図表データのダウンロード」よりExcelファイルがダウンロードできます。令和6(2024)年の調査データを使用しました。

実行環境

  • Python 3.x
  • pandas
  • matplotlib
  • japanmap

 

データの概要

ダウンロードファイル「R06_DL-toukeihyo.xlsx」シート名「統計表10-1」の表から以下の薬剤師のデータを読み込みました。

※列名(薬局・医療)は「薬局・医療施設の従事者」の略です。以後このように表記します。

都道府県 総数 薬局・医療
0 全国 265.8 210.6
1 北海道 235.1 202.7
2 青森 206.4 175.5
3 岩手 219.0 188.5
4 宮城 254.0 210.4
5 秋田 225.4 198.8
6 山形 218.7 186.7
7 福島 223.2 188.9
8 茨城 230.8 188.3
9 栃木 231.8 191.4
10 群馬 220.8 187.0
11 埼玉 235.5 200.8
12 千葉 243.4 205.6
13 東京 388.1 240.3
14 神奈川 262.5 223.6
15 新潟 219.0 186.1
16 富山 291.4 189.6
17 石川 263.2 203.6
18 福井 201.9 170.4
19 山梨 243.7 208.5
20 長野 238.9 203.7
21 岐阜 220.1 190.0
22 静岡 241.5 198.2
23 愛知 226.9 186.3
24 三重 211.8 186.0
25 滋賀 248.2 202.7
26 京都 269.8 203.3
27 大阪 320.4 232.4
28 兵庫 296.8 245.6
29 奈良 240.2 199.7
30 和歌山 269.4 215.6
31 鳥取 226.0 195.1
32 島根 223.2 192.2
33 岡山 234.6 198.7
34 広島 269.8 231.6
35 山口 268.7 224.7
36 徳島 382.0 256.6
37 香川 262.8 215.0
38 愛媛 249.8 211.7
39 高知 267.2 226.7
40 福岡 257.1 223.1
41 佐賀 251.6 215.4
42 長崎 238.1 201.8
43 熊本 238.4 203.6
44 大分 218.4 193.9
45 宮崎 219.7 186.7
46 鹿児島 218.7 194.8
47 沖縄 169.2 155.3


「人口10万人あたり」の意味

これらのデータが表している数値は各都道府県の人口10万人あたりの薬剤師数で、以下の式で計算されます。

 各都道府県の数値 = \dfrac{その県の薬剤師数}{その県の人口} \times 100,000

実数(実際の数)だと大都市があるような人口の多い都道府県が多いことが簡単に想像がつきますが、実数だと比較には向きません。
しかし、人口10万人あたりに換算*1することで、人口規模の違いをならした比較ができるようになります。「住民から見て薬剤師がどれくらいいるか」や密度をイメージしてもらえれば良いと思います。

平均についての補足
取得データの先頭行を見ると次のようになっています。

都道府県 総数 薬局・医療
0 全国 265.8 210.6

それぞれ、1)全国の総数の平均、2)全国の薬局・医療施設の従事者の平均ですが、今回の記事でもこれらの値を全国平均として扱っています。
なぜわざわざ言うかというと、この値は両方とも「全国の薬剤師数 ÷ 全国人口×10万」で計算された値(加重平均)ですが、これは表の10万人対の47都道府県の数値を全部足して47で割った「算術平均」とは異なる値になりますので、念のため。
ちなみに2)の方について言うと、もう一つのR06_DL-hyo.xlsxファイルの方ではこの平均のことを「全国の水準線」と表記していました。
(統計表9-1シートに1)、2)とも実数の記載もあります。また、2024年の全国人口は1億2380万2千人です。*2

都道府県別データを日本地図で可視化する

プログラムの流れとしては、

  1. Excelファイルからデータ読み込み
  2. データ整形、「全国平均との差」列の付加
  3. グラフ描画

と単純です。
以下に各データをマップに可視化したものを載せます。
ここでは取り込んだデータをそのまま可視化させるだけでなく、不足・充足がより直感的にわかりやすくなるよう全国平均との差も可視化することにしました。

総数(人口10万人あたり)

 

薬局・医療施設の従事者数(人口10万人あたり)

 

要約統計量と読み取れる傾向

.describeした内容は以下の通りです。

--- 要約統計量 (df.describe) ---
               総数       薬局・医療
count   47.000000   47.000000
mean   246.663830  202.917021
std     39.596884   19.502679
min    169.200000  155.300000
25%    222.000000  189.250000
50%    238.400000  200.800000
75%    262.650000  213.350000
max    388.100000  256.600000

これらの要約と地図から読み取れることを整理しました。

総数のバラつきは薬局・医療施設従事者の約2倍

これは要約のstd(標準偏差)を見ると一目瞭然です。

  • 総数のstd:39.5
  • 薬局・医療のstd:19.5

総数の方には企業・研究・行政職等が含まれています*3が、これらの非臨床薬剤師が偏在しているということが見て取れます。製薬メーカーの本社や工場、研究所、官公庁は特定の大都市や産業拠点に集中しているため、総数のデータはその影響を大きく受けているということですね。一方で「薬局・医療」のバラつきがその約半分に収まっているということは、臨床に携わる薬剤師は総数に比べれば、まだ全国的に分散していると言えそうです。
また要約の算術平均(mean)を見ると、どちらのデータも全国平均を下回っています。これは一部の数字が飛び抜けて高いために、平均が引き上げられているだけで、多くの県が全国平均に達していないことがわかります。
薬局・医療の方はまだバラつきが少ない、と書きましたが、(実際、医師の偏在に比べると随分マシなようです)単純計算では、人口10万人あたりで150人の地域の薬剤師は、200人の地域の薬剤師に比べて、一人当たり1.33倍の患者さんに対応していることになります。リアルな現場感覚で1.3倍くらい多く担当することになる・・と考えると、より身が引き締まる思いがしますね。

富山県は総数と臨床現場の薬剤師数のギャップが大きい
  • 総数: 291.4人(全国上位25%以内、平均+25.6人)
  • 薬局・医療: 189.6人(全国下位25%、平均-21.0人)

富山県は「くすりの富山」として知られ、医薬品製造業が盛んなのだそうです。そのため多くの方々は製造・研究開発などに従事していたりと、医療現場以外の方が多いのかもしれませんね。 しかしちょっと検索してみたところでは、近年は製薬企業においても採用充足率は低く、薬剤師の不足は深刻な問題になってきているようです。

東京も臨床以外の薬剤師が多い

総数の最大値(max)は東京都でした。2位とともに、ダントツと言っていいくらい飛び抜けています。

  • 総数: 388.1人(1位)
  • 薬局・医療: 240.3人(上位だけど、徳島や兵庫よりは下)
  • その差: 約148人

東京には、人口10万人あたり約148人もの「薬局・医療施設の従事者以外の薬剤師」がいることになります。これは沖縄県の薬剤師総数(169.2人)に匹敵する人数となっています。 東京の数字を押し上げているのは、製薬企業の本社や官公庁、大学研究職などが考えられますが、先の富山県とは異なり、東京は臨床現場の薬剤師も多いです。

総合でトップは徳島県
  • 総数: 382.0人(東京に次いで2位)
  • 薬局・医療: 256.6人(全国1位)

徳島県は、総数でも臨床の数でも圧倒的に高い数値です。県内に薬学部の大学が2つあること、大手の製薬企業の拠点があること、人口あたりの医療機関数が多いことなどが影響して需要と供給とも高い水準を保っていると言えそうです。

全国的には西高東低の傾向

これは医師数についてよく言われていることですが、薬剤師についても同様の傾向がみられます。
地図をざっと見ると、臨床(薬局・医療)の数値においては西日本が多く、北関東・東北あたりが少ない傾向が見て取れます。

  • 上位グループ: 徳島(256.6)、兵庫(245.6)、広島(231.6)、高知(226.7) など西日本勢が目立つ。
  • 下位グループ: 青森(175.5)、福井(170.4)、沖縄(155.3) など。
  • 関東周辺: 東京・神奈川は多いが、埼玉(200.8)、千葉(205.6)、茨城(188.3)などは平均並みかそれ以下。

大都市(東京・大阪)に勤務地があっても、住んでいるのは周りの県で、そこから通勤している場合があると、その周囲の県の数値は少なく出ます。これは、(ファイル中にも書いてある通り)「従業地別データ」なので、東京は分子↑/分母↓、周囲の県は分子↓/分母↑ということになります。なので埼玉や千葉の数値が低いのは、「東京で働いている〇〇県民薬剤師」が東京のスコアに含まれているということもありそうですね。
 

まとめ

今回扱った数値は、あくまで都道府県単位のデータです。同じ都道府県内でも、都市部と郊外、医療機関の集積度などによって、実際の状況にはさらに偏りがあると考えられます。そのため、この記事の結果は「大まかな傾向をつかむためのもの」として見てもらえればと思います。
なお、厚生労働省では最近は人口10万人対の人数だけでなく医療ニーズを考慮した偏在指標の導入も進めています。
今回はそこまで踏み込めませんでしたが、今後は年収や薬学部の数といったデータも組み合わせて、もう少し違った切り口からも可視化してみたいと考えています。
 
最後に、今回のコードです。


※クリックしてコード全体を表示

import pandas as pd
import matplotlib.pyplot as plt
from japanmap import picture
from matplotlib import cm, colors
import matplotlib.colors as mcolors
 
 
def draw_japan_map(df, col_name, title, cmap_name, norm, label):
    # 色コード生成
    cmap = plt.get_cmap(cmap_name)
    data_dict = dict(zip(df["都道府県"], df[col_name]))
 
    pref_colors = {}
    for pref, val in data_dict.items():
        pref_colors[pref] = colors.to_hex(cmap(norm(val)))
 
    # 地図作成
    img = picture(pref_colors)
 
    fig, ax = plt.subplots(figsize=(10, 10))
    plt.imshow(img)
    plt.axis('off')
    plt.title(title, fontsize=16)
 
    # カラーバー
    mappable = cm.ScalarMappable(norm=norm, cmap=cmap)
    cbar = plt.colorbar(mappable, ax=ax, orientation='horizontal', shrink=0.8, pad=0.05, aspect=30)
    cbar.set_label(label, fontsize=12)
 
    plt.show()
    return fig
 
 
def main():
    file_name = "R06_DL-toukeihyo.xlsx"
    sheet_name = "統計表10-1"
 
    # データ読み込みと前処理
    df = pd.read_excel(file_name, sheet_name=sheet_name,
                       header=None, skiprows=6, skipfooter=22)
    df = df.iloc[:, [3, 13, 14]]
    df.columns = ["都道府県", "総数", "薬局・医療"]

    df = df.dropna(subset=["都道府県"])
    df["都道府県"] = df["都道府県"].str.replace(" ", "").str.replace(" ", "")
 
    print(df)
    # 全国平均値の取得
    nat_row = df[df["都道府県"] == "全国"]
    avg_total = nat_row.iloc[0]["総数"]
    avg_medical = nat_row.iloc[0]["薬局・医療"]
 
    print(f"全国平均 総数: {avg_total:.1f}, 医療: {avg_medical:.1f}")
 
    df = df[df["都道府県"] != "全国"].copy()
    # 差分列の作成
    df["総数_差"] = df["総数"] - avg_total
    df["医療_差"] = df["薬局・医療"] - avg_medical
 
    # 要約統計量の表示
    print("\n--- 要約統計量 (df.describe) ---")
    desc = df.iloc[:, :3].describe()
    print(desc)
 
    # グラフ作成ループ設定
    plot_configs = [
        # 1. 総数
        {
            "col": "総数",
            "title": "薬剤師の総数(人口10万人対)",
            "cmap": "YlOrRd",
            "label": "人数(人/10万人)",
            "type": "absolute"
        },
        # 2. 薬局・医療施設従事者
        {
            "col": "薬局・医療",
            "title": "薬局・医療施設の従事者数(人口10万人対)",
            "cmap": "YlOrRd",
            "label": "人数(人/10万人)",
            "type": "absolute"
        },
        # 3. 総数(平均差)
        {
            "col": "総数_差",
            "title": f"総数(人口10万人対):全国平均({avg_total:.1f})との差",
            "cmap": "RdBu_r",
            "label": "全国平均との差(人)\n青:不足傾向 / 赤:充足傾向",
            "type": "diff"
        },
        # 4. 薬局・医療施設従事者(平均差)
        {
            "col": "医療_差",
            "title": f"薬局・医療施設の従事者(人口10万人対):全国平均({avg_medical:.1f})との差",
            "cmap": "RdBu_r",
            "label": "全国平均との差(人)\n青:不足傾向 / 赤:充足傾向",
            "type": "diff"
        }
    ]

    for config in plot_configs:
        col = config["col"]

        # Norm(色の基準)の設定
        if config["type"] == "absolute":
            norm = colors.Normalize(vmin=df[col].min(), vmax=df[col].max())
        else:
            # 0を基準(白)にするTwoSlopeNorm
            norm = mcolors.TwoSlopeNorm(
                vmin=df[col].min(),
                vcenter=0,
                vmax=df[col].max()
            )

        # 描画関数の呼び出し
        draw_japan_map(
            df=df,
            col_name=col,
            title=config["title"],
            cmap_name=config["cmap"],
            norm=norm,
            label=config["label"]
        )
 
if __name__ == "__main__":
    main()

*1:=標準化(正規化)

*2:総務省統計局より

*3:また免許を持っていて働いていない人も