前回時間が足りなくてできなかったところがあります。探索的データプロットというところです。今回はそこから始めたいと思います。
今回改めてデータファイルを用意しましたので,baseball2015a.csv というデータファイルをプロジェクトフォルダに入れ,次の一行で読み込んでください。
b.data <- read.csv("baseball2015a.csv",head=T)
データは図にする。プロットする。 これが分析の基本です。まずデータがどういう特徴を持っているかを,しっかりと目で把握しましょう。 それができていないと,データにモデルを当てはめるという話が始まりませんので。
探索的データプロットのパッケージ,ggplot2をインストールします。
install.packages("ggplot2")
インストールしただけでは使えません。library関数(またはrequire関数)で装備します。
library(ggplot2)
まずはデータと全体設定を持ったggplotオブジェクトを作ります。
gp <- ggplot(b.data,aes(x=year,y=pay,color=team))
点を打ってみましょう。
gp_point <- gp + geom_point()
plot(gp_point)
色だけじゃなく,大きさや形状を変えてプロットすることもできます。
gp <- ggplot(b.data,aes(x=year,y=pay,color=team,shape=position,size=blood))
gp_point <- gp + geom_point()
plot(gp_point)
タイトルや軸ラベルも書いておきましょう。
gp <- ggplot(b.data,aes(x=year,y=pay,color=team,shape=position,size=blood))
gp_point <- gp + geom_point()+xlab("プレイ期間")+ylab("年俸")+ggtitle("野球選手の年棒とプレイ期間の関係")
plot(gp_point)
画を複数に分けることもできます。
gp <- ggplot(b.data,aes(x=year,y=pay,color=team,shape=position))
gp_point <- gp + geom_point() + facet_wrap(~blood)
plot(gp_point)
横軸がカテゴリカルであれば,箱ひげ図や棒グラフになります。
gp <- ggplot(b.data,aes(x=team,y=pay,fill=position))
gp_box <- gp + geom_boxplot()
plot(gp_box)
gp_bar <- gp + geom_bar(stat="identity",position="dodge")
plot(gp_bar)
# 平均が見たい
gp_bar <- gp + stat_summary(fun.y=mean,geom="bar",position="dodge")
plot(gp_bar)
# 中央値が見たい
gp_bar <- gp + stat_summary(fun.y=median,geom="bar",position="dodge")
plot(gp_bar)
エラーバーを追加する例。
gp <- ggplot(b.data,aes(x=position,y=pay,fill=position))
gp_bar <- gp + stat_summary(fun.y=mean,geom="bar",position="dodge") +
stat_summary(fun.data=mean_se,geom="errorbar",width=0.5)
plot(gp_bar)
様々な角度からデータをプロットし,分布の形状や変数間関係をしっかり見極める癖をつけましょう。
今週のテーマは クラスタリング です。
多変量解析とは,要約すること,まとめあげること,でもあるわけです。 まとめたものを同じ「クラスター」に入れる。これを機械的にするのがクラスタリングです。
基本は似ているもの同士をまとめていきます。
数字と数字が似ている=距離が近い,です。距離は引き算で出します。データで見ていきましょう。先ほどと同じデータセットを例にします。
例えば「身長」変数を例にします。
b.data[1,] #case1
## name team pay position year age height weight blood home BirthY
## 1 杉内 俊哉 巨人 50000 投手 14 34 175 82 A型 福岡 1980
## BirthM BirthD throw hit
## 1 10 30 左 左
b.data[2,] #case2
## name team pay position year age height weight blood home
## 2 金子 千尋 オリックス 50000 投手 11 31 180 77 O型 新潟
## BirthY BirthM BirthD throw hit
## 2 1983 11 8 右 左
b.data[3,] #case3
## name team pay position year age height weight blood home BirthY
## 3 内海 哲也 巨人 40000 投手 12 33 186 93 A型 京都 1982
## BirthM BirthD throw hit
## 3 4 29 左 左
b.data$height[1] #case1の身長
## [1] 175
b.data$height[2] #case2の身長
## [1] 180
b.data$height[3] #case3の身長
## [1] 186
b.data$height[1]-b.data$height[2] #case1とcase2の差
## [1] -5
b.data$height[1]-b.data$height[3] #case1とcase2の差
## [1] -11
b.data$height[2]-b.data$height[3] #case1とcase2の差
## [1] -6
sqrt((b.data$height[1]-b.data$height[2])^2) #case1とcase2の距離
## [1] 5
sqrt((b.data$height[1]-b.data$height[3])^2) #case1とcase2の距離
## [1] 11
sqrt((b.data$height[2]-b.data$height[3])^2) #case1とcase2の距離
## [1] 6
これをみると,case1-2の距離はcase1-3より近い。 こういうデータを全部の組み合わせについて見て行きたいわけです。 とても大変な計算量ですが,統計ソフトだと簡単。
こうした組み合わせをひとつずつ計算するのは面倒だけど,dist関数を使うと簡単。 ** head()はデータの上の部分だけを取り出す関数です。全部やるとたくさん出力されるので,便宜的にそうしています。実際はデータ全部を使うのが普通です。**
dist(head(b.data$height)) #身長変数について,最初の6行分だけ,距離を計算する
## 1 2 3 4 5
## 2 5
## 3 11 6
## 4 8 3 3
## 5 10 5 1 2
## 6 6 1 5 2 4
こうして,近い方から「これは同じクラスタだね」とまとめていく。例えばcase5とcase3,case6とcase3は距離が1しかないから同じクラスタにする。簡単ですね。
身長だけでなく,体重も考えたい,というときは,ユークリッド距離を算出します。
dist(head(b.data[,7:8]))
## 1 2 3 4 5
## 2 7.071068
## 3 15.556349 17.088007
## 4 13.601471 16.278821 3.000000
## 5 14.866069 16.763055 1.000000 2.000000
## 6 16.155494 20.024984 6.403124 4.472136 5.656854
変数が三つ以上になっても基本的に同じです。
もっともこの場合は,身長(cm)と体重(kg)という異なる単位のものを等価に扱っているという問題があります。単位の違いを考慮するならば,データを標準化*しておいたほうがいいですね。標準化する関数はscaleというのがあります。
scale(head(b.data[,7:8]))
## height weight
## 1 -1.6736548 -0.9178485
## 2 -0.4184137 -1.5582078
## 3 1.0878756 0.4909422
## 4 0.3347310 0.4909422
## 5 0.8368274 0.4909422
## 6 -0.1673655 1.0032297
## attr(,"scaled:center")
## height weight
## 181.66667 89.16667
## attr(,"scaled:scale")
## height weight
## 3.983298 7.808115
これを使って距離データを準備しておくことにしましょう。
b.distance <- dist(scale(b.data[,7:8]))
まとまったclusterをAとします。次は,cluster Aとcase2,3,4,6はどこが近いかな?あるいは他のクラスターB(case4と3とか)との距離は?ということを考える必要があります。 まとめ方によっていろいろ変わりますが,代表的なものを三つ挙げておきます。
顎の長さデータをつかって,階層的クラスター分析をやってみよう。
result <- hclust(b.distance,method="ward.D2") #ward法
plot(result)
このような図をデンドログラムという。これを見ながら,いくつのグループに分けるかを考えます。いくつのグループに分けるかはご随意に!
2つのグループかしら?というあたりをつけたとしましょう。この木の枝をカットし,元変数に足しておきます。
b.data$class <- cutree(result,2)
b.data$class
## [1] 1 1 2 2 2 2 2 2 1 2 2 2 1 2 2 2 2 1 1 1 2 2 2 2 2 2 2 2 1 2 1 2 2 1 1
## [36] 1 2 1 1 2 2 1 2 2 2 1 2 1 1 2 2 2 2 2 2 1 2 1 2 1 1 1 2 2 1 2 1 2 1 2
## [71] 1 1 1 2 2 2 1 1 2 2 1 1 2 1 2 2 1 2 1 2 2 1 1 2 1 2 1 2 1 1 2 2 2 1 2
## [106] 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 1 1 2 1 2 2 2 2
## [141] 1 2 1 1 1 2 2 2 1 2 2 1 2 1 2 1 2 1 1 2 2 2 1 2 2 1 2 2 1 1 1 1 1 1 1
## [176] 1 2 2 1 1 1 2 1 1 2 2 2 2 2 1 1 1 1 1 1 1 2 2 1 1
さてこの違いはどこから来てるのでしょうか? 度数を数えるときはクロス集計表というのがいいですね。あるいは検定して調べるとか。
xtabs(~position+class,data=b.data)
## class
## position 1 2
## 外野手 12 22
## 投手 42 59
## 内野手 24 33
## 捕手 4 4
chisq.test(xtabs(~position+class,data=b.data))
## Warning in chisq.test(xtabs(~position + class, data = b.data)): Chi-squared
## approximation may be incorrect
##
## Pearson's Chi-squared test
##
## data: xtabs(~position + class, data = b.data)
## X-squared = 0.76852, df = 3, p-value = 0.857
t.test(pay~class,data=b.data)
##
## Welch Two Sample t-test
##
## data: pay by class
## t = -3.7347, df = 193.13, p-value = 0.0002472
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -7781.285 -2402.961
## sample estimates:
## mean in group 1 mean in group 2
## 10456.10 15548.22
とりあえず多くのデータがあって困っているときに,いくつかのグループに分けて,グループごとの平均や相関などをみて,このクラスターはこういう特徴だったのだと事後的に解釈することは少なくありません。そのために,検定があったり,群ごとに検証するモデリングがでてきたりします。