library(conflicted) # 関数名の衝突を警告
conflicts_prefer( # 優先的に使う関数を指定
::filter(),
dplyr::select(),
dplyr::lag(),
dplyr
)library(tidyverse)
library(MASS)
library(broom) # 解析結果を tibble 形式に集約
library(gt) # 表の作成
library(gtsummary) # 分析結果の表の作成
library(ggfortify) # biplot表示のため
統計データ解析
第8講 サンプルコード
準備
以下で利用する共通パッケージを読み込む.
線形判別
問題
東京の気候データを用いて以下の分析を行いなさい.
9月と10月の気温と湿度のデータを抽出する.
<- read_csv("data/tokyo_weather.csv") tw_data <- tw_data |> tw_subset filter(month %in% c(9,10)) |> select(temp, humid, month) |> mutate(month = as_factor(month)) # 月を因子化
半分のデータを用いて線形判別関数を構成し,残りのデータを用いて判別を行う.
<- seq(2, 60, by = 2) idx <- tw_subset[ idx,] # 訓練データ tw_train <- tw_subset[-idx,] # 試験データ tw_test <- lda(month ~ temp + humid, data = tw_train) # 線形判別関数の構成 tw_lda <- predict(tw_lda) # 判別関数によるクラス分類結果の取得 tw_lda_fitted <- predict(tw_lda, newdata = tw_test) # 新しいデータの予測 tw_lda_predict
解答例
必要なデータを整理する.
<- read_csv("data/tokyo_weather.csv")
tw_data <- tw_data |>
tw_subset filter(month %in% c(9,10)) |> # 9,10月のデータ
select(temp, humid, month) |> # 気温・湿度・月を選択
mutate(month = as_factor(month)) # 月を因子化
<- seq(1, nrow(tw_subset), by = 2) # データの分割(1つおき)
idx <- tw_subset[ idx,] # 訓練データ(推定に用いる)
tw_train <- tw_subset[-idx,] # 試験データ(評価に用いる) tw_test
ランダムに分割するには例えば以下のようにすれば良い.
<- nrow(tw_subset); idx <- sample(1:n, n/2) n
関数 lubridate::month()
を用いれば月を文字列(因子)とすることもできる.
mutate(month = month(month, label = TRUE))
以下のようにして最初に月を因子化することもできるが,関数によっていは処理で使われない因子(例えば1月)も表示してしまうので注意が必要である.
read_csv("data/tokyo_weather.csv") |>
mutate(month = as_factor(month))
また複数の項目をそれぞれ因子化するには例えば以下のようにすればよい.
mutate(across(c(year, month, day), as_factor))
気温と湿度の散布図を作成して,データを視覚化する.
|> #
tw_subset ggplot(aes(x = temp, y = humid)) +
geom_point(aes(colour = month)) + # 月ごとに点の色を変える
labs(x = "Temperature", y = "Humidity",
title = "September & October")
訓練データを用いて線形判別関数(等分散性を仮定)を作成する.
<- month ~ temp + humid
tw_model <- lda(formula = tw_model, data = tw_train) tw_lda
判別関数によるクラス分類結果を確認する.
<- predict(tw_lda) #
tw_lda_fitted tibble(true = tw_train[["month"]]) |> # 真値と予測値の対応表を作成
mutate(predict = tw_lda_fitted[["class"]]) |>
table() # 混同行列
predict
true 9 10
9 14 1
10 1 15
as_tibble(tw_lda_fitted[["x"]]) |> # リストから判別関数値(配列)を取得
mutate(month = tw_train[["month"]]) |> # 月(真値)を追加
ggplot(aes(x = LD1, fill = month)) +
geom_histogram(aes(y = after_stat(density)),
bins = 30) +
facet_grid(month ~ .) # 月ごとに表示(y方向に並べる)
この例ではデータフレームを作成しているが,関数 table()
のみで混同行列を作ることはできる.
table(true = tw_train[["month"]],
predict = tw_lda_fitted[["class"]])
試験データによる評価を行う.
<- predict(tw_lda, newdata = tw_test)
tw_lda_predict tibble(true = tw_test[["month"]]) |> # 真値と予測値の対応表を作成
mutate(predict = tw_lda_predict[["class"]]) |>
table() # 混同行列
predict
true 9 10
9 14 1
10 0 15
as_tibble(tw_lda_predict[["x"]]) |> # 判別関数値の視覚化
mutate(month = tw_test[["month"]]) |>
ggplot(aes(x = LD1, fill = month)) +
geom_histogram(aes(y = after_stat(density)),
bins = 30) +
facet_grid(month ~ .)
推定された線形判別関数の識別境界を図示する.
<- range(tw_subset[["temp"]]) # 気温の値域
range_x <- range(tw_subset[["humid"]]) # 湿度の値域
range_y <- pretty(range_x, 100) # 気温の値域の格子点を作成
grid_x <- pretty(range_y, 100) # 湿度の値域の格子点を作成
grid_y <- expand.grid(temp = grid_x,
grid_xy humid = grid_y) # 2次元の格子点を作成
<- predict(tw_lda, # 格子点上の判別関数値を計算
tw_lda_grid newdata = grid_xy)
<- as_tibble(grid_xy) |> # 判別関数により予測されるラベルの図示
p mutate(predict = tw_lda_grid[["class"]]) |>
ggplot(aes(x = temp, y = humid)) +
geom_tile(aes(fill = predict), alpha = 0.3) +
labs(x = "Temperature", y = "Humidity",
title = "Linear Discriminant Analysis")
print(p) # 判別境界の表示
上記の図にデータ点を重ね描きする.
+
p geom_point(data = tw_subset,
aes(x = temp, y = humid, colour = month))
判別関数値を色づけして図示するには以下のようにすればよい.
<-
p2 as_tibble(grid_xy) |>
mutate(LD = tw_lda_grid[["x"]][,"LD1"]) |> # LD1列のみ利用
ggplot(aes(x = temp, y = humid)) +
geom_raster(aes(fill = LD), alpha = 0.5) +
scale_fill_gradientn(colours=c("red","white","blue")) +
labs(x = "Temperature", y = "Humidity",
title = "Scores of Discriminant Variables")
print(p2) # 判別関数値の表示
+ # データ点の重ね描き
p2 geom_point(data = tw_subset,
aes(x = temp, y = humid, colour = month))
2次判別
問題
東京の気候データを用いて以下の分析を行いなさい.
前問と同様な設定で2次判別を行いなさい.
<- qda(month ~ temp + humid, data = tw_train) # 2次判別関数の構成 tw_qda <- predict(tw_qda) # 判別関数によるクラス分類結果の取得 tw_qda_fitted <- predict(tw_qda, newdata = tw_test) # 新しいデータの予測 tw_qda_predict
別の月や変数を用いて判別分析を行いなさい.
解答例
前の練習問題で作成した tw_train
および tw_test
を利用する.
まず,訓練データで2次判別関数(等分散性を仮定しない)を作成する. 線形判別関数と同じモデル式を用いる.
<- qda(formula = tw_model, data = tw_train)
tw_qda <- predict(tw_qda) # 判別関数によるクラス分類結果の取得
tw_qda_fitted tibble(true = tw_train[["month"]]) |> # 真値と予測値の対応表を作成
mutate(predict = tw_qda_fitted[["class"]]) |>
table() # 予測値の比較(混同行列)
predict
true 9 10
9 14 1
10 1 15
試験データによる評価を行う.
<- predict(tw_qda, newdata = tw_test)
tw_qda_predict table(true = tw_test[["month"]], # 混同行列
predict = tw_qda_predict[["class"]])
predict
true 9 10
9 14 1
10 0 15
tibble(true = tw_test[["month"]]) |> # 比較表
mutate(predict = tw_qda_predict[["class"]])
# A tibble: 30 × 2
true predict
<fct> <fct>
1 9 9
2 9 9
3 9 9
4 9 9
5 9 9
6 9 9
7 9 9
8 9 9
9 9 9
10 9 9
# ℹ 20 more rows
推定された2次判別関数を図示する.
<- predict(tw_qda, # 格子点上の判別関数値を計算
tw_qda_grid newdata = grid_xy)
<- as_tibble(grid_xy) |> # 判別関数により予測されるラベルの図示
p mutate(predict = tw_qda_grid[["class"]]) |>
ggplot(aes(x = temp, y = humid)) +
geom_tile(aes(fill = predict), alpha = 0.3) +
labs(x = "Temperature", y = "Humidity",
title = "Quadratic Discriminant Analysis")
print(p) # 判別境界の表示
+
p geom_point(data = tw_subset, # データ点の重ね描き
aes(x = temp, y = humid, colour = month))
多値判別
問題
東京の気候データを用いて以下の分析を行いなさい.
9月,10月,11月の気温と湿度のデータを用いて判別関数を作成しなさい.
<- tw_data |> tw_subset filter(month %in% c(9,10,11)) |> select(temp, humid, month) |> mutate(month = as_factor(month))
別の月や変数を用いて判別分析を行いなさい.
#' 雨の有無を識別する例 <- tw_data |> tw_subset2 mutate(rain = factor(rain > 0), month = as_factor(month)) |> # 雨の有無でラベル化する select(rain, temp, solar, wind, month) <- lda(rain ~ ., data = tw_subset2) # 'rain' をそれ以外で判別 tw_lda2
解答例
3値判別のためにデータの整理を行う.
<- tw_data |>
tw_subset3 filter(month %in% c(9,10,11)) |>
select(temp, humid, month) |>
mutate(month = as_factor(month))
線形判別関数(3値)を作成する.
<- lda(formula = tw_model, data = tw_subset3)
tw_lda3 <- predict(tw_lda3) # 判別関数によるクラス分類結果の取得
tw_lda3_fitted table(true = tw_subset3[["month"]], # 真値
predict = tw_lda3_fitted[["class"]]) # 予測値の比較(混同行列)
predict
true 9 10 11
9 28 2 0
10 1 26 4
11 0 10 20
推定された線形判別関数(3値)により予測されるラベルを図示する. 格子点は再計算する必要があるので注意する.
<- range(tw_subset3[["temp"]]) # 気温の値域
range_x <- range(tw_subset3[["humid"]]) # 湿度の値域
range_y <- pretty(range_x, 100) # 気温の値域の格子点を作成
grid_x <- pretty(range_y, 100) # 湿度の値域の格子点を作成
grid_y <- expand.grid(temp = grid_x,
grid_xy humid = grid_y) # 2次元の格子点を作成
<- predict(tw_lda3, # 格子点上の判別関数値を計算
tw_lda3_grid newdata = grid_xy)
as_tibble(grid_xy) |>
mutate(predict = tw_lda3_grid[["class"]]) |>
ggplot(aes(x = temp, y = humid)) +
geom_tile(aes(fill = predict), alpha = 0.3) +
geom_point(data = tw_subset3,
aes(x = temp, y = humid, colour = month)) +
labs(x = "Temperature", y = "Humidity",
title = "Multi-label Discriminant Analysis")
3値判別の場合には2つの判別関数を構成するので,これを用いてデータ点の散布図を作成することができる.
<- bind_cols(tw_lda3_fitted[["x"]], # 判別関数値(LD1,LD2)
p "month"]) |> # データフレームとして抽出
tw_subset3[ggplot(aes(x = LD1, y = LD2)) +
geom_point(aes(colour = month)) # 月ごとに色を変更
print(p)
関数 geom_tile()
が座標軸に沿った格子点を想定しているため,判別関数値の散布図上で判別境界とデータ点を表示するには工夫が必要となる.ここでは関数 geom_point()
で代用した簡便な例を示す.
+ geom_point(data = # 判別関数値と予測ラベルのデータフレームを作成
p bind_cols(tw_lda3_grid[["x"]],
predict = tw_lda3_grid[["class"]]),
aes(colour = predict), alpha = 0.1)
12ヶ月分のデータを用いる.数が多いのでサンプリングする.
<- sample(nrow(tw_data), 100)
idx <- slice(tw_data, idx) |>
tw_subset12 mutate(month = as_factor(month))
<- lda(month ~ temp + solar + wind + humid,
tw_lda12 data = tw_subset12)
<- predict(tw_lda12)
tw_lda12_fitted table(true = tw_subset12[["month"]], # 混同行列
predict = tw_lda12_fitted[["class"]])
predict
true 1 2 3 4 5 6 7 8 9 10 11 12
1 12 0 0 0 0 0 0 0 0 0 0 0
2 2 0 0 0 0 0 0 0 0 0 0 2
3 0 0 5 1 0 0 0 0 0 0 1 1
4 0 0 1 6 2 0 0 0 0 1 2 0
5 0 0 0 3 3 0 0 0 0 0 0 0
6 0 0 0 0 0 3 0 0 0 1 0 0
7 0 0 0 0 0 0 5 4 1 0 0 0
8 0 0 0 0 0 0 0 13 0 0 0 0
9 0 0 0 0 0 0 1 1 1 0 0 0
10 0 0 0 0 0 0 1 0 0 10 0 0
11 1 0 1 0 0 0 0 0 0 3 1 4
12 2 0 0 0 0 0 0 0 0 0 3 2
bind_cols(tw_lda12_fitted[["x"]], # 判別関数値の散布図を作成
"month"]) |>
tw_subset12[::ggpairs(aes(colour = month),
GGallyupper = list(continuous = GGally::wrap("cor", size = 1.5)))
判別関数は説明変数の数までしか作成できないので,精度はあまり高くないことがわかる.
雨の有無を識別する例は以下のようになる.
<- tw_data |>
tw_rain mutate(rain = factor(rain > 0), # 雨の有無でラベル化する
month = as_factor(month)) # 月ごとの気候の違いの補正のため
<- lda(rain ~ temp + solar + wind + month,
tw_rain_lda data = tw_rain,
subset = idx) # 一部のデータで推定する例
<- predict(tw_rain_lda)
tw_rain_lda_fitted as_tibble(tw_rain_lda_fitted[["x"]]) |> # 判別関数値の視覚化
mutate(rain = tw_rain[["rain"]][idx]) |>
ggplot(aes(x = LD1, fill = rain)) +
geom_histogram(aes(y = after_stat(density)),
bins = 30) +
facet_grid(rain ~ .)
全データを予測する.
<- predict(tw_rain_lda, newdata = tw_rain)
tw_rain_lda_predict table(true = tw_rain[["rain"]][idx], # 推定に用いたデータの混同行列
predict = tw_rain_lda_predict[["class"]][idx])
predict
true FALSE TRUE
FALSE 69 6
TRUE 11 14
table(true = tw_rain[["rain"]][-idx], # 未知データに対する予測の混同行列
predict = tw_rain_lda_predict[["class"]][-idx])
predict
true FALSE TRUE
FALSE 178 12
TRUE 38 37