-- Views
April 16, 26
スライド概要
東北大学で2023年に開講していた「パターン認識論」のスライドです
本スライドでは、Irisデータセットを取得し可視化した上で、主成分分析やLDAによる次元圧縮を行います。その後、Nearest Neighbor、プロトタイプ法、パーセプトロン、3層ニューラルネット、GMMといった分類アルゴリズムを実装し、精度を比較します。最後に、Titanicデータセットを用いて生存予測を行う演習を提示しています。
I'll be writing programs, papers, and ramblings.
パターン認識論 第5回 伊藤彰則 1
実践編(その1) これまでの内容から実際にパターン を認識してみよう ◦Nearest Neighbor法 ◦線形識別関数 ◦ニューラルネットワーク(3層) ◦GMM ◦+次元圧縮 2
データセット Iris データセット ◦ アヤメの花弁と萼のサイズに対する花の種類のデータ ベース (Fisher, 1936) Iris setosa (ヒオウギアヤメ) Iris versicolor (ブルーフラッグ) Iris verginica (バージニカ) 3
データセット ◦Iris flower data set ◦ https://archive-beta.ics.uci.edu/dataset/53/iris クラス数 3 (setosa, versicolor, virginica) サンプル数 150 (50サンプル/クラス) 特徴量 4種類 萼の長さと幅 (sepal length, sepal width) 花弁の長さと幅 (petal length , petal width) 分析に R を利用 (Python民は自力でやってください) R自体の説明はしません 4
データの取得と確認 > data("iris") > head(iris) Sepal.Length Sepal.Width Petal.Length Petal.Width Species 1 5.1 3.5 1.4 0.2 setosa 2 4.9 3.0 1.4 0.2 setosa 3 4.7 3.2 1.3 0.2 setosa 4 4.6 3.1 1.5 0.2 setosa 5 5.0 3.6 1.4 0.2 setosa 6 5.4 3.9 1.7 0.4 setosa > summary(iris) Sepal.Length Min. :4.300 1st Qu.:5.100 Median :5.800 Mean :5.843 3rd Qu.:6.400 Max. :7.900 Sepal.Width Min. :2.000 1st Qu.:2.800 Median :3.000 Mean :3.057 3rd Qu.:3.300 Max. :4.400 Petal.Length Min. :1.000 1st Qu.:1.600 Median :4.350 Mean :3.758 3rd Qu.:5.100 Max. :6.900 Petal.Width Min. :0.100 1st Qu.:0.300 Median :1.300 Mean :1.199 3rd Qu.:1.800 Max. :2.500 Species setosa :50 versicolor:50 virginica :50 5
可視化 > library(ggplot2) > ggplot(iris,aes(x=Sepal.Length,y=Sepal.Width,col=Species))+ geom_point() 4.5 Sepal.Width 4.0 3.5 Species setosa versicolor 3.0 virginica 2.5 2.0 5 6 7 8 Sepal.Length 6
可視化2 > ggplot(iris,aes(x=Petal.Length,y=Petal.Width,col=Species))+ geom_point() 2.5 Petal.Width 2.0 Species 1.5 setosa versicolor virginica 1.0 0.5 0.0 2 4 6 Petal.Length 7
次元を潰してみる
> model <- princomp(iris[,1:4]) # 主成分分析
> model$sdev^2 # 主成分軸の分散
Comp.1
Comp.2
Comp.3
Comp.4
4.20005343 0.24105294 0.07768810 0.02367619
> barplot(model$sdev^2,col=2,ylab="variance")
8
累積寄与率 > total<-sum(model$sdev^2) > cumm<-Reduce(`+`,model$sdev^2/total,accumulate = TRUE) > plot(cumm,type="b") 9
2次元に圧縮 > compressed<-cbind(as.data.frame(model$scores),iris$Species) > ggplot(compressed,aes(x=Comp.1,y=Comp.2,col=iris$Species)) +geom_point() 10
各軸に対する寄与 > model$loadings Loadings: Comp.1 Comp.2 Comp.3 Comp.4 Sepal.Length 0.361 0.657 0.582 0.315 Sepal.Width 0.730 -0.598 -0.320 Petal.Length 0.857 -0.173 -0.480 Petal.Width 0.358 -0.546 0.754 Comp.1 Comp.2 Comp.3 Comp.4 SS loadings 1.00 1.00 1.00 1.00 Proportion Var 0.25 0.25 0.25 0.25 Cumulative Var 0.25 0.50 0.75 1.00 11
LDAによる次元圧縮 library(MASS) model.lda <- lda(Species~.,data=iris) lda.compressed <- predict(model.lda,iris) result <- data.frame(Dim1=lda.compressed$x[,1], Dim2=lda.compressed$x[,2], Species=iris$Species) ggplot(result,aes(x=Dim1,y=Dim2,color=Species))+geom_point() 12
分類してみよう まず全体を学習データと評価データに分ける > train_index <- sample(1:150,100) > train_data <- iris[train_index,] > test_data <- iris[-train_index,] > table(train_data$Species) setosa versicolor virginica 34 30 36 > table(test_data$Species) setosa versicolor 16 20 virginica 14 13
Nearset Neighbor法
学習データの全てのサンプルをプロトタイプとしたNN法
> library(class)
> result <- knn1(train_data[,-5],test_data[,-5],train_data[,5])
> sum(result==test_data$Species)/nrow(test_data)
[1] 0.94
各クラスの平均ベクトル1つをプロトタイプとしたNN法
> library(dplyr)
> library(foreach)
> species <-c("setosa","versicolor","virginica")
> foreach(s=species,.combine=rbind) %do% {filter(train_data,Species==s) %>%
select(-Species) %>% colMeans} -> proto
> proto
Sepal.Length Sepal.Width Petal.Length Petal.Width
result.1
5.029412
3.438235
1.473529
0.2676471
result.2
5.850000
2.763333
4.213333
1.3200000
result.3
6.605556
2.977778
5.575000
2.0277778
> result <- knn1(proto,test_data[,-5],species)
> sum(result==test_data$Species)/nrow(test_data)
[1] 0.88
14
分類結果の可視化 ◦全学習サンプルをプロトタイプとした 場合 15
分類結果の可視化 ◦各クラス1プロトタイプとした場合 16
プロトタイプはどこにある のか見てみる plot(test_data$Sepal.Length,test_data$Sepal.Width, pch=16,col=test_data$Species) points(proto$Sepal.Length,proto$Sepal.Width, pch=3,cex=5,col=1:3) 17
線形識別(パーセプトロン)
◦ 準備:2クラスにする(virginicaとそれ以外)
train_2cls <- as.numeric(train_data$Species ==
"virginica")*2-1
Test_2cls <- as.numeric(test_data$Species ==
“virginica”)*2-1
◦ パーセプトロンの計算
perceptron_test <- function(x,w) {
res <- rep(0,nrow(x))
for (i in 1:nrow(x)) {
xx <- as.numeric(c(1,x[i,]))
z <- w %*% xx; res[i] <- sign(z)
}
res
}
18
線形識別(パーセプトロン)
◦ パーセプトロン学習
perceptron_train <- function(x,y,rho,niter) {
w <- runif(ncol(x)+1)
corr <- rep(0,niter)
for (k in 1:niter) {
correct <- 0
for (i in 1:nrow(x)) {
xx <- as.numeric(c(1,x[i,])); z <- sign(w %*% xx)
if (z != y[i]) {
w <- w+y[i]*rho*xx
} else {
correct <- correct+1
}
}
corr[k] <- correct/nrow(x)
}
return(list(corr=corr,weight=w))
}
19
線形識別(パーセプトロン) ◦ やってみる(学習) result <- perceptron_train(train_data[,1:4], train_2cls,0.01,10) plot(result$corr,type="b",xlab="iteration",ylab="accuracy") 20
線形識別(パーセプトロ ン) ◦学習データに対する性能 result1 <- perceptron_test(train_data[,1:4],result$weight) plot(train_data$Sepal.Length,train_data$Sepal.Width, pch=16,col=1+(train_2cls+1)/2) points(train_data$Sepal.Length,train_data$Sepal.Width, cex=3,col=1+(result1+1)/2) 識別率89% 21
線形識別(パーセプトロ ン) ◦テストデータに対する性能 > result2 <- perceptron_test(test_data[,1:4],result$weight) > plot(test_data$Sepal.Length,test_data$Sepal.Width, pch=16,col=1+(test_2cls+1)/2) > points(test_data$Sepal.Length,test_data$Sepal.Width, cex=3,col=1+(result2+1)/2) 識別率74% 22
ニューラルネット(3層) ◦ とりあえず中間1層ユニット数10 > library(nnet) > nnmax <- max(train_data[,1:4]) > nnmin <- min(train_data[,1:4]) > nntrain_data <- (train_data[,1:4]-nnmin)/(nnmax-nnmin) > model <- nnet(nntrain_data,train_2cls,size=10,linout=TRUE) > nntest_data <- (test_data[,1:4]-nnmin)/(nnmax-nnmin) > result <- predict(model,nntest_data) > sum(sign(result)==test_2cls)/length(result) [1] 0.94 23
ニューラルネット(3層) ◦ 可視化 > result3 <- sign(result) > plot(test_data$Sepal.Length,test_data$Sepal.Width, pch=16,col=1+(test_2cls+1)/2) > points(test_data$Sepal.Length,test_data$Sepal.Width, cex=3,col=1+(result3+1)/2) 24
ニューラルネット(3層)
◦ 中間層のユニット数を変えて様子を見てみる
size_result <- rep(0,20)
for (i in 1:20) {
model <- nnet(nntrain_data,train_2cls,size=i,
linout=TRUE)
res <- predict(model,nntest_data)
size_result[i] <- sum(sign(res)==test_2cls)/length(res)
}
plot(size_result,type="b")
25
ニューラルネット(3層)
◦3クラス分類をやってみよう
train_onehot <- matrix(0,nrow=nrow(train_data),ncol=3)
for (i in 1:nrow(train_data)) {
train_onehot[i,as.numeric(train_data[i,5])] <- 1
}
model <- nnet(nntrain_data,train_onehot,size=10)
result <- predict(model,nntest_data)
result <- apply(result,1,which.max)
sum(result==as.numeric(test_data[,5]))/length(result)
[1] 0.98
26
ニューラルネット(3層) ◦可視化 plot(test_data$Sepal.Length,test_data$Sepal.Width, pch=16,col=test_data[,5]) points(test_data$Sepal.Length,test_data$Sepal.Width, cex=3,col=result) 27
GMM
library(mclust)
gmm <- list()
for (i in 1:3) {
dplyr::filter(train_data,as.numeric(Species)==i) %>%
dplyr::select(-Species) %>%
Mclust(modelNames="EVI") -> gmm[[i]]
}
result.m <- matrix(0,nrow=nrow(test_data),ncol=3)
for (cl in 1:3) {
result.m[,cl] <- rowSums(cdens(test_data[,1:4], "EVI",
parameters=gmm[[cl]]$parameters))
}
result <- apply(result.m,1,which.max)
sum(result==as.numeric(test_data$Species))/length(result)
[1] 0.94
28
GMMの分布を見てみる
library(ellipse)
plot(train_data$Sepal.Length,train_data$Sepal.Width,pch=16,
col=train_data[,5])
for (k in 1:3) {
p <- gmm[[k]]$parameter
for (i in 1:gmm[[k]]$G) {
points(ellipse(p$variance$sigma[1:2,1:2,i]*p$pro[i],
centre=p$mean[1:2,i]),type="l",col=k)
}
}
29
演習5 ◦The Titanic Dataset を使い、これま で説明した手法のいずれかを使って生 存/非生存の予測を行い、正解率を計算 せよ。 30
The Titanic Dataset ◦タイタニック号の乗客の情報と、生存/ 死亡のデータセット ◦ https://www.kaggle.com/vinicius15098 7/titanic3 より取得、クリーニング済み ◦ クラスルームにアップロードされたCSV ファイルを利用する ◦ titanic_train.csv 学習用 ◦ titanic_test.csv 評価用 31
The Titanic Dataset ◦データ項目 ◦ pclass: 船室等級 ◦ age: 年齢 ◦ sibsp: 乗船した兄弟の人数 ◦ parch: 乗船した親または子の人数 ◦ fare: 乗船料 ◦ sex: 性別 (0=女 1=男) ◦ survived: 生存/死亡 (0=死亡 1=生存) 32
The Titanic Dataset ◦基本情報 ◦ サンプル数 1043 (欠損値は除いてあ る) ◦ 生存数 425 / 死亡数 618 ◦ 全てを「死亡」と判定すると6割当たる 33
演習5 ◦The Titanic Dataset を使い、これま で説明した手法のいずれかを使って生 存/非生存の予測を行い、正解率を計算 せよ。 ◦ モデル学習には titanic_train.csv を利用 ◦ 評価には titanic_test.csv を利用 ◦ レポートには、使った手法とシステム、 データの分析結果、評価データの正解率を 記載すること 34
何を使えばいいのか? ◦何を使っても構いません ◦ ツールを使ってもいいし、自分でプログラ ムを1から書き起してもよい ◦代表的なツール ◦R ◦ データ分析に使われる代表的なプログラミング言 語/実行環境 ◦ 手法が豊富だが言語仕様には癖がある 35
何を使えばいいのか? ◦代表的なツール ◦ Python ◦ データ処理・深層学習などで人気のプログラミン グ言語 ◦ 今回の演習にはscikit-learnを使うと良い ◦ Excel ◦ ご存知表計算ツールだが基本的には何でもできる ◦ [Excel 機械学習]でググるとたくさん出てくる 36
何を使えばいいのか? ◦ 代表的なツール ◦ MATLAB ◦ 有料だけど強力なツール ◦ 東北大では使い放題 ◦ MathWorks のWebサイトにビデオ教材などがある ◦ WEKA ◦ Javaで書かれた機械学習ツール ◦ データを入力して識別器を選ぶだけで識別ができる ◦ https://www.cs.waikato.ac.nz/ml/weka/ 37
何を使えばいいのか? ◦代表的なツール ◦ H2O ◦ Javaで書かれた機械学習ツール ◦ 単体のアプリではなく、Webサーバとして動く ◦ https://github.com/h2oai/h2o-3 ◦ ググると日本語の解説が結構出てくる 38
注意点 ◦パターン認識のモデルと実際のツール との対応付けを目的としている ◦ 性能がいいからといって、中身のよくわか らないモデルを使わないこと ◦ 使う場合は、モデルの原理についての説明をレ ポートに含める ◦ 性能の良し悪しは問わない ◦ データの分析、結果の分析をすること ◦ データの可視化は望ましい 39
ちなみにこれがChatGPTの 答えだ! *参考*にしてね! 40