library(readxl)
library(knitr)
<- readRDS("df.rds")
df library(showtext)
showtext_auto()
弘前データ5:BART によるフローラタイプ予測
備考は全て外し,LOX_Index
と 判別式
も説明変数としては考慮しない.
library(dplyr)
<- df %>%
df_filtered filter(is.na(BP備考), type != "D") %>%
select(-c(BP備考, LOX_Index, 判別式, id, med_col, 年代)) %>%
droplevels()
1 CART モデル
library(rpart)
library(rpart.plot)
# 目的変数が5クラスになっても、式は同じ
# rpartが自動で多クラス分類として扱ってくれる
<- rpart(
cart_model_5class ~ ., # 目的変数を5クラスのものに変更
type data = df_filtered,
method = "class" # 分類なので "class" のまま
)printcp(cart_model_5class)
Classification tree:
rpart(formula = type ~ ., data = df_filtered, method = "class")
Variables actually used in tree construction:
[1] BMI BP diversity FLCΣ sex イライラ感
Root node error: 167/564 = 0.2961
n= 564
CP nsplit rel error xerror xstd
1 0.013473 0 1.00000 1.0000 0.064923
2 0.011976 10 0.83234 1.0299 0.065471
3 0.010000 11 0.82036 1.0299 0.065471
# 決定木を可視化
rpart.plot(
cart_model_5class,type = 4,
extra = 104, # 各ノードのクラス別サンプル数を表示
box.palette = "auto", # 色を自動で設定
shadow.col = "gray",
nn = TRUE
)
初っ端から「女性ならばほとんど Type B だ」と決めつけているのが面白い.
2 男女で違う CART モデルを推定する
男性の場合正答率が6割しか出ないが,女性の場合は8割出る.これは女性の方に C, E type がないためである.
2.1 男性の場合
「 BMI が小さくて多様性が3ならば A タイプ」というルールは変わらないようである.
library(rpart)
library(rpart.plot)
<- df_filtered %>%
df_male filter(sex == 1)
# 目的変数が5クラスになっても、式は同じ
# rpartが自動で多クラス分類として扱ってくれる
<- rpart(
cart_model_5class ~ ., # 目的変数を5クラスのものに変更
type data = df_male,
method = "class" # 分類なので "class" のまま
)printcp(cart_model_5class)
Classification tree:
rpart(formula = type ~ ., data = df_male, method = "class")
Variables actually used in tree construction:
[1] BMI BP diversity FLCΣ イライラ感
Root node error: 99/237 = 0.41772
n= 237
CP nsplit rel error xerror xstd
1 0.030303 0 1.00000 1.0000 0.076692
2 0.023569 6 0.78788 1.1111 0.077551
3 0.020202 9 0.71717 1.1111 0.077551
4 0.010000 10 0.69697 1.1010 0.077501
# 決定木を可視化
rpart.plot(
cart_model_5class,type = 4,
extra = 104, # 各ノードのクラス別サンプル数を表示
box.palette = "auto", # 色を自動で設定
shadow.col = "gray",
nn = TRUE
)
# 予測値を取得
<- predict(cart_model_5class, newdata = df_male, type = "class")
predictions
# 混同行列を作成
<- table(Actual = df_male$type, Predicted = predictions)
confusion_matrix print(confusion_matrix)
Predicted
Actual A B C E
A 6 4 0 1
B 4 121 2 11
C 2 14 4 5
E 5 20 1 37
# 正答率を計算
<- sum(predictions == df_male$type, na.rm = TRUE) / sum(!is.na(df_male$type))
accuracy cat("正答率:", round(accuracy * 100, 2), "%\n")
正答率: 70.89 %
58% の正解率が 68% になる.
2.2 女性の場合
library(rpart)
library(rpart.plot)
<- df_filtered %>%
df_female filter(sex == 2)
# 目的変数が5クラスになっても、式は同じ
# rpartが自動で多クラス分類として扱ってくれる
<- rpart(
cart_model_5class ~ ., # 目的変数を5クラスのものに変更
type data = df_female,
method = "class" # 分類なので "class" のまま
)printcp(cart_model_5class)
Classification tree:
rpart(formula = type ~ ., data = df_female, method = "class")
Variables actually used in tree construction:
[1] diversity Weight
Root node error: 68/327 = 0.20795
n= 327
CP nsplit rel error xerror xstd
1 0.014706 0 1.00000 1.0000 0.10792
2 0.010000 2 0.97059 1.0882 0.11127
# 決定木を可視化
rpart.plot(
cart_model_5class,type = 4,
extra = 104, # 各ノードのクラス別サンプル数を表示
box.palette = "auto", # 色を自動で設定
shadow.col = "gray",
nn = TRUE
)
# 予測値を取得
<- predict(cart_model_5class, newdata = df_female, type = "class")
predictions
# 混同行列を作成
<- table(Actual = df_female$type, Predicted = predictions)
confusion_matrix print(confusion_matrix)
Predicted
Actual A B C E
A 4 16 0 0
B 2 257 0 0
C 3 15 0 0
E 0 30 0 0
# 正答率を計算
<- sum(predictions == df_female$type, na.rm = TRUE) / sum(!is.na(df_female$type))
accuracy cat("正答率:", round(accuracy * 100, 2), "%\n")
正答率: 79.82 %
これは正答の個数が,タイプ B 259 人から,261 人になっただけ.
3 BART による変数選択
3.1 推定
library(BART)
# 説明変数と被説明変数を準備
<- df_filtered[, !(names(df_filtered) %in% c("type"))]
x_vars <- df_filtered$type
y_var
# 欠損値を含む行を削除
<- complete.cases(x_vars, y_var)
complete_cases <- x_vars[complete_cases, ]
x_vars_clean <- y_var[complete_cases]
y_var_clean
# x を必ず base::data.frame に
<- as.data.frame(x_vars_clean) # tibble/data.table/sparse -> NG なので明示変換
x_train
# y は 1..K の整数
<- droplevels(y_var_clean)
y <- nlevels(y) # K = 4 K
<- BART::mbart(
fit x.train = x_train,
y.train = y_int,
x.test = x_train, # 例として同データで
type = "lbart", # or "pbart"
power = 3.0
)
<- readRDS("bart_fit_5class.rds")
fit # 予測と混同行列
<- matrix(fit$prob.test.mean, ncol = K, byrow = TRUE)
p <- factor(levels(y)[max.col(p)], levels = levels(y))
pred table(truth = y, pred = pred)
pred
truth A B C E
A 4 22 0 1
B 0 373 0 6
C 1 37 2 3
E 0 71 0 20
sum(y == pred) / length(y)
[1] 0.7388889
3.2 変数重要度の出力
# 変数重要度を計算・描画
# fit$varcount に各変数が使用された回数の情報が入っている
<- fit$varcount # リスト形式
var_counts_list <- (var_counts_list[[1]] + var_counts_list[[2]] + var_counts_list[[3]]) / 3 # 2カテゴリの平均
var_counts_combined <- colMeans(var_counts_combined) # MCMCの全ステップで平均
var_counts
<- sort(var_counts, decreasing = TRUE)
var_counts_sorted
# 上位15件などをプロット
barplot(head(var_counts_sorted, 10),
horiz = TRUE,
las = 1, # y軸ラベルを水平に
main = "Variable Importance (BART)",
xlab = "Inclusion Frequency")
3.3 タイプごとの重要度
# カテゴリごとの変数重要度
<- colMeans(var_counts_list[[1]]) # A vs その他
var_counts_cat1 <- colMeans(var_counts_list[[2]]) # B vs その他
var_counts_cat2 <- colMeans(var_counts_list[[3]]) # C vs その他
var_counts_cat3
# 比較
<- data.frame(
comparison_df Variable = names(var_counts_cat1),
A = var_counts_cat1,
B = var_counts_cat2,
C = var_counts_cat3,
Overall = var_counts
)
# 上位10件を表示
head(comparison_df[order(comparison_df$Overall, decreasing = TRUE), ], 10)
Variable A B C Overall
イライラ感 イライラ感 4.012 2.985 4.851 3.949333
diversity3 diversity3 4.586 3.370 3.588 3.848000
活気 活気 3.237 4.056 4.044 3.779000
sex sex 3.229 4.219 3.762 3.736667
diversity1 diversity1 3.904 3.387 3.751 3.680667
不安感 不安感 4.561 3.439 2.983 3.661000
疲労感 疲労感 4.623 3.224 2.891 3.579333
diversity2 diversity2 2.964 3.448 3.844 3.418667
抑うつ感 抑うつ感 3.310 3.819 3.053 3.394000
age age 3.331 3.622 2.958 3.303667