授業で扱う題材 (Education)

授業中に扱う資料などをまとめています。


1.授業等で扱うアプリ

リアルタイムアンケート

リアルタイムに結果が反映されるよう、ゼミで扱っているGithub(privateリポジトリ)を経由し、VercelやSpabaseなどのサービスを利用して教育目的に使用しています。

栄養素計算アプリ

現場に出てからAI等との協働をリテラシーをもって進められるよう1、ベースとなるアプリを作成し、ゼミ等で学生が改変できるようにしています。


2.模擬症例資料例

Tip

データサイエンスを社会で活かすには、データを扱う力だけでなく、エビデンスに基づいて「何をどこまで言えるか」を判断する力が必要です。
病院や企業に求められる説明責任(Accountability:結果責任とも)を果たすため、大学院・ゼミ・実習では、症例を通じて病態・エビデンス・アウトカムを整理し、疫学的に責任をもって伝える技術の基本を学びます。

症例

64歳、男性

主訴

腎機能低下精査と専門的介入を目的とした紹介受診

現病歴

55歳時に健診で高血圧、脂質異常症を指摘された。近医で降圧薬および脂質異常症治療薬を開始されたが、通院は不定期であり、服薬アドヒアランスも十分には把握されていなかった。
62歳時に血清クレアチニン上昇も指摘された。当時のeGFRは58 mL/min/1.73m²で、尿蛋白はA2相当であった。以後、高血圧性腎硬化症として外来フォローされていた。
64歳受診時にeGFR 42 mL/min/1.73m²まで低下し、尿蛋白も増加傾向を認めたため腎硬化症だけでは説明がつかない事もあり、専門医による介入が必要と考えられ、腎臓内科専門外来へ紹介受診となった。
家庭血圧は145〜155/85〜90 mmHgで推移していた。かかりつけ医師より「食塩6 g/日未満、たんぱく質0.8 g/kg/日以下、飲酒は控えめに」と説明された後に不機嫌となり、「透析になるのは嫌だ。でも、ラーメンも酒もやめろと言うなら、そんな生活は生きている意味がない」と主張されているとの事。

既往歴

糖尿病の診断歴なし。心筋梗塞、脳卒中の既往なし

家族歴

父:高血圧、脳卒中で死亡。母:詳細不明。腎疾患の家族歴なし。

内服薬

テルミサルタン 40 mg/日、アムロジピン 5 mg/日、ロスバスタチン 2.5 mg/日。

本人は「薬はだいたい飲んでいる」と話すが、飲み忘れの頻度は明確ではない。NSAIDsの常用はないが、腰痛時に市販鎮痛薬を自己判断で使用することがある。サプリメントの常用はないものの、最近インターネットで「腎臓にやさしい食品」「透析予防」「医師監修の減塩ラーメン」といった広告を閲覧しており、「病院の食事制限より楽なら試してもよい」と話している。

身体所見

身長:168 cm 体重:70 kg 血圧:診察室 158/88 mmHg(家庭血圧:145〜155/85〜90 mmHg) 脈拍:72/分、整 浮腫:明らかでない 心雑音:なし 呼吸音:清 握力:年齢相応または軽度低下 歩行速度:明らかな低下なし 食欲:保たれている

検査所見

   55歳 62歳 64歳
Cr, mg/dL 1.05 1.18 1.35
eGFR, mL/min/1.73m² 65 58 42
尿蛋白区分 A1 A2 A3相当
尿蛋白/Cr比, g/gCr 0.15 0.35 0.85
Na, mEq/L 140 140 139
K, mEq/L 4.4 4.7 4.7
Cl, mEq/L 103 104 104
補正Ca, mg/dL 9.4 9.3 9.1
P, mg/dL 3.4 3.8 4.4
Alb, g/dL 4.2 4.1 4.0
Hb, g/dL 14.1 13.8 13.5
HbA1c, % 5.2 5.5 5.8
LDL-C, mg/dL 148 128 116
TG, mg/dL 180 165 172
尿酸, mg/dL 7.1 7.3 7.5

臨床診断

# 慢性腎臓病 (CKD G3bA3)
## 腎硬化症 s/o
## 慢性糸球体腎炎 r/o
# 高血圧症 (管理不十分)
# 脂質異常症
# 高尿酸血症
Tip

飲酒習慣および高食塩食を背景とした生活習慣上のリスク
低栄養・フレイルは現時点で明らかでないが、過度なたんぱく質制限により将来的リスクあり

生活歴・社会歴

元・建設会社の現場監督。若い頃から現場で部下をまとめる立場であり、「人から指図されること」を嫌う。白黒をはっきりさせたい性格で、曖昧な説明や「とりあえず控えましょう」という表現に反発しやすい。
妻と二人暮らし。妻は本人の体調を心配しているが、食事について強く言うと本人が怒るため、十分に介入できていない。
趣味はラーメン店巡り、町中華、晩酌。本人は「仕事を引退して、ようやく好きなものを食べる時間ができた」と話す。
孫が現在中学2年生であり、本人は「孫の大学卒業式までは元気でいたい」と話している。

食事・飲酒状況

食事記録および聞き取りでは、以下の傾向を認めた。
* ラーメン:週3回
* ラーメンのスープ:ほぼ毎回完飲
* 町中華:週1〜2回
* 晩酌:ほぼ毎日
* 飲酒量:日本酒2合/日、またはビール500 mL+焼酎水割り1〜2杯
* つまみ:漬物、干物、練り物、塩辛、揚げ物が多い
* 朝食:食パン、ハム、チーズ、味噌汁など
* 昼食:外食またはコンビニ弁当
* 夕食:妻の手料理が中心だが、本人が味の薄さに不満を言うため、醤油や漬物を追加することが多い
* 水分摂取:制限なし
* サプリメント・健康食品:現在は使用していないが、インターネット広告で「腎臓にやさしい食品」「減塩ラーメン」に関心を示している

Question (実習生向け)

Question 0

この症例の要点を整理し、30秒程度で説明しなさい

Question 1

この患者に、あなたなら最初に何と言いますか?
その助言は何を根拠にしていますか?エビデンスレベルの観点を加えて説明してください。

Question 2

なぜ生活習慣病を放っておいてはいけないかと聞かれたら、どのように説明しますか?メタボリックドミノの観点から説明してください。

Question 3

なぜCKDでは食塩やタンパク質の摂取量が問題になるのでしょうか?
腎臓や心臓を含めた、解剖生理(血圧調節など)から説明してください。

Question (実習で余力のある学生向け)

Question 4

この患者に科学的根拠(疫学的根拠)をもって指導するために必要なPICOを作るとしたら、P、I、C、Oはどう設定しますか?3つ挙げてください。

Question 5

この患者のCKD Stageでは、どんな根拠をもって日常生活・栄養指導を行いますか?

Note

栄養疫学が単一栄養素から食品、食事パターン、置換設計へ視点を広げてきた流れを踏まえ、栄養素・食品・食事パターン・置換設計の順に論じてください。

Question (ゼミ生〜院生向け)

Question 6

Outcomeを、代替アウトカム、臨床アウトカム、患者中心アウトカムに分けると、医療従事者・患者・企業の立場等からは、構造的にどのようにすれ違いが起こりうるでしょうか?

Question 7

科学的根拠に基づくと、次の表現は言ってよいでしょうか?もしくは「補足」や「言い換え」が必要でしょうか?

  1. 「腎臓病の人はカリウムを含む野菜や果物を控えるべきなので、あなたも食べてはいけません」
  2. 「減塩すれば透析を防げるので、これから1日の塩分は6g以下にするべきです」
  3. 「医師監修だからCKDの方にもおすすめで、薬を減らすことができます」
  4. 「通常のラーメンより食塩を50%カットしているので、腎臓にやさしいラーメンです」
  5. 「この商品を3か月続けると、腎機能の低下を抑えられます」
Note

可能な限り改正景品表示法やステマ規制も念頭に答えてください

Question 8

食品企業の商品説明と病院の栄養指導の両方の立場から、管理栄養士はどんなスキルを身につけて、どのように社会に関わるべきでしょうか?


3.統計資料

予測・分類・推定・検定・回帰などの基本的な概念を理解するための題材2を扱います。

年収に関して解析してみるとは?

予測と推定の違いを理解する

まずはデータベースを作る。

何らかのsamplingを行い、一人づつ年収や資格の有無、年齢、性別、学歴などを記録して、c(200,1,25,1,0)のような形でデータを記入していく。

ここでは便宜上、年収と年齢を数値、資格と性別と学歴を二値という形を、データ定義書で決めているとする。

name <- c("nensyu","shikaku","age","gender","gakureki")
X1 <- rbind(
   c(200,1,25,1,0)
  ,c(300,1,30,1,1)
  ,c(200,0,27,0,0)
  ,c(240,0,26,0,1)
  ,c(180,0,23,1,0)
  ,c(650,1,27,1,1)
  ,c(550,1,30,1,1)
  ,c(600,1,24,1,1)
  ,c(580,1,26,0,1)
)
colnames(X1) <- name
rownames(X1) <- 1:nrow(X1)
X1 <- data.frame(X1)
X1$gender   <- as.factor(X1$gender)
X1$shikaku  <- as.factor(X1$shikaku)
X1$gakureki <- as.factor(X1$gakureki)
head(X1)
  nensyu shikaku age gender gakureki
1    200       1  25      1        0
2    300       1  30      1        1
3    200       0  27      0        0
4    240       0  26      0        1
5    180       0  23      1        0
6    650       1  27      1        1

目視で、データベース完成してそうな事を確認した。

Table.1

次は、集計する。資格の有無で各テーブルに差はないか?

library(tableone)
CreateTableOne(vars = c("age","gender","gakureki","nensyu"), 
               strata = c("shikaku"), 
               data = X1
               )
                    Stratified by shikaku
                     0              1               p      test
  n                       3              6                     
  age (mean (SD))     25.33 (2.08)   27.00 (2.53)    0.361     
  gender = 1 (%)          1 (33.3)       5 (83.3)    0.453     
  gakureki = 1 (%)        1 (33.3)       5 (83.3)    0.453     
  nensyu (mean (SD)) 206.67 (30.55) 480.00 (183.85)  0.043     

これがいわゆる素データの比較(単変量解析)で、資格の有無で年収や年齢などに差があるかをみている。

解析

今、何のために解析ソフトを回しているのか、を再度考えてみましょう。

summary(lm(nensyu~shikaku,data=X1))

Call:
lm(formula = nensyu ~ shikaku, data = X1)

Residuals:
    Min      1Q  Median      3Q     Max 
-280.00  -26.67   33.33  100.00  170.00 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)  
(Intercept)    206.7       90.2   2.291   0.0557 .
shikaku1       273.3      110.5   2.474   0.0426 *
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 156.2 on 7 degrees of freedom
Multiple R-squared:  0.4665,    Adjusted R-squared:  0.3903 
F-statistic: 6.121 on 1 and 7 DF,  p-value: 0.04257
summary(lm(nensyu~shikaku+gender+age+gakureki,data=X1))

Call:
lm(formula = nensyu ~ shikaku + gender + age + gakureki, data = X1)

Residuals:
      1       2       3       4       5       6       7       8       9 
-118.98 -155.12   98.11 -118.98   20.87  134.41   94.88   23.94   20.87 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)
(Intercept)   646.09     635.88   1.016    0.367
shikaku1      200.16     152.51   1.312    0.260
gender1       -23.39     130.54  -0.179    0.867
age           -20.16      25.15  -0.801    0.468
gakureki1     236.93     136.85   1.731    0.158

Residual standard error: 150.4 on 4 degrees of freedom
Multiple R-squared:  0.7174,    Adjusted R-squared:  0.4348 
F-statistic: 2.539 on 4 and 4 DF,  p-value: 0.1944
Tip

推定か予測かによって、結果で着目する所が違うので、どこをみて解析結果をどのように解釈しているかを覚えておきましょう。
また、どのようにデータを集めてきたのか、によって話が全然違ってくる、という事も理解できればなおよしです。

コイントスを何度行えばイカサマに気づく?

検定とは何かを理解する

あなたは何回コインが表が出たら、イカサマコインだと判定しますか?

まずは仮説が必要

「普通のコインって表裏平等に出るんじゃないか?」を検証する

上から1回目とし、表をo、裏をxと表現するとし、5回コイントスを行う全パターンを考える。

5回の時

# Tree drawing function
draw_tree <- function(depth, x, y, dx, heads = 0) {
  if (depth == 0) {
    # Bottom: print number of heads (non-overlapping)
    text(x, y, heads, cex = 0.9, col = "blue", font = 2)
  } else {
    x_left <- x - dx
    x_right <- x + dx
    y_next <- y - 1
    
    segments(x, y, x_left, y_next)
    segments(x, y, x_right, y_next)
    
    text((x + x_left)/2, (y + y_next)/2, "o", pos = 3, cex = 0.8)
    text((x + x_right)/2, (y + y_next)/2, "x", pos = 3, cex = 0.8)
    
    draw_tree(depth - 1, x_left, y_next, dx / 2, heads + 1)
    draw_tree(depth - 1, x_right, y_next, dx / 2, heads)
  }
}

# Set plotting area for the tree
par(mfrow = c(2, 1), mar = c(4, 4, 3, 2))

# Tree structure
plot(0, 0, type = "n", xlim = c(-16, 16), ylim = c(-6.5, 1.5),
     xlab = "", ylab = "", axes = FALSE, main = "Coin Toss Tree (5 flips)")

# Draw tree
draw_tree(depth = 5, x = 0, y = 1, dx = 8)

# Generate simulation data
set.seed(42)
n_trials <- 1000
sim_result <- rbinom(n_trials, size = 5, prob = 0.5)

# Plot probability density function
density_obj <- density(sim_result, from = -0.5, to = 5.5)

plot(density_obj, main = "Empirical Density of 'o' in 1000 Trials",
     xlab = "Number of 'o' ", ylab = "Density", col = "darkgreen", lwd = 2)
rug(sim_result, col = "gray")

このふにゃふにゃは?

全パターンが、\(2^5=32\)なので、\(1 \div32=0.03125\)となるので、全部表になった場合は0.05以下にはなっている。

# Simulate coin toss outcomes
set.seed(42)
n_trials <- 1000
sim_result <- rbinom(n_trials, size = 5, prob = 0.5)

# Smooth density estimation (adjust controls smoothness)
density_obj <- density(sim_result, from = -0.5, to = 5.5, adjust = 3)#滑らかに

# Plot density
plot(density_obj, main = "Smoothed Density of 'Heads' in 1000 Trials",
     xlab = "Number of Heads", ylab = "Density", col = "darkgreen", lwd = 2)
rug(sim_result, col = "gray")

8回くらいに増やすと、、、

# Function to draw coin toss tree
draw_coin_tree <- function(depth, x_pos, y_pos, dx, num_heads = 0) {
  if (depth == 0) {
    text(x_pos, y_pos, num_heads, cex = 0.7, col = "blue", font = 2)
  } else {
    x_left <- x_pos - dx
    x_right <- x_pos + dx
    y_next <- y_pos - 1

    segments(x_pos, y_pos, x_left, y_next)
    segments(x_pos, y_pos, x_right, y_next)

    text((x_pos + x_left)/2, (y_pos + y_next)/2, "H", pos = 3, cex = 0.6)
    text((x_pos + x_right)/2, (y_pos + y_next)/2, "T", pos = 3, cex = 0.6)

    draw_coin_tree(depth - 1, x_left, y_next, dx / 2, num_heads + 1)
    draw_coin_tree(depth - 1, x_right, y_next, dx / 2, num_heads)
  }
}

# Parameters
num_flips <- 8
num_simulations <- 1000
set.seed(42)

# Simulate coin toss outcomes (number of heads per trial)
head_counts <- rbinom(num_simulations, size = num_flips, prob = 0.5)

# Prepare 2-panel layout
par(mfrow = c(2, 1), mar = c(4, 4, 3, 2))

# Plot the coin toss tree
plot(0, 0, type = "n", xlim = c(-140, 140), ylim = c(-9.5, 1.5),
     xlab = "", ylab = "", axes = FALSE,
     main = "Binary Tree of Coin Toss Outcomes (8 flips)")

draw_coin_tree(depth = num_flips, x_pos = 0, y_pos = 1, dx = 128)

# Estimate and plot smoothed density of head counts
head_density <- density(head_counts, from = -0.5, to = 8.5, adjust = 2)

plot(head_density, main = "Smoothed Density of Number of Heads (1000 trials)",
     xlab = "Number of Heads", ylab = "Density", col = "darkgreen", lwd = 2)
rug(head_counts, col = "gray")

1000だとどうなるか?

# Parameters
num_flips <- 1000
num_simulations <- 10000  # 増やすことで密度が安定

set.seed(42)
head_counts <- rbinom(num_simulations, size = num_flips, prob = 0.5)

# Estimate smoothed density of head counts
head_density <- density(head_counts, from = 300, to = 700, adjust = 2)

# Plot density
par(mar = c(5, 4, 3, 2))  # Default margins
plot(head_density,
     main = "Smoothed Density of 'Heads' in 10000 Trials (100 Coin Flips)",
     xlab = "Number of Heads", ylab = "Density",
     col = "darkblue", lwd = 2, xlim = c(300, 700))
rug(head_counts, col = "gray", ticksize = 0.05)

一番高い所は? この解釈は?

Footnotes

  1. 要するに、便利さにつられて、危ない使い方をしないように!↩︎

  2. 要するに、授業中にcopy等を用いて使用するための場所です↩︎