必要なパッケージ
require(tidyverse)
## 要求されたパッケージ tidyverse をロード中です
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2 ──
## ✔ ggplot2 3.3.6 ✔ purrr 0.3.4
## ✔ tibble 3.1.8 ✔ dplyr 1.0.9
## ✔ tidyr 1.2.0 ✔ stringr 1.4.0
## ✔ readr 2.1.2 ✔ forcats 0.5.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
require(maps)
## 要求されたパッケージ maps をロード中です
##
## 次のパッケージを付け加えます: 'maps'
##
## 以下のオブジェクトは 'package:purrr' からマスクされています:
##
## map
require(plotly)
## 要求されたパッケージ plotly をロード中です
##
## 次のパッケージを付け加えます: 'plotly'
##
## 以下のオブジェクトは 'package:ggplot2' からマスクされています:
##
## last_plot
##
## 以下のオブジェクトは 'package:stats' からマスクされています:
##
## filter
##
## 以下のオブジェクトは 'package:graphics' からマスクされています:
##
## layout
require(geosphere)
## 要求されたパッケージ geosphere をロード中です
データを読み込む。
capital <- read.csv("prefCapital.csv")
中身を確認する。
head(capital)
## Prefecture Capital Longitude Latitude
## 1 Hokkaido Sapporo 141.3469 43.06417
## 2 Aomori Aomori 140.7400 40.82444
## 3 Iwate Morioka 141.1525 39.70361
## 4 Miyagi Sendai 140.8719 38.26889
## 5 Akita Akita 140.1025 39.71861
## 6 Yamagata Yamagata 140.3633 38.24056
47都道府県の県庁所在地の情報である。
world <- map_data("world")
データを図示する。
world %>%
ggplot(aes(x = long, y = lat, group = group)) +
geom_polygon(fill = "lightgrey", colour = "black", size = 0.1)
日本だけ抜き出してくる。
japan <- world %>% filter(region == "Japan")
日本地図を描く。
japan %>%
ggplot(aes(x = long, y = lat, group = group)) +
geom_polygon(fill = "lightgray", colour = "black", size = 0.1)
日本地図を描く。
japan %>%
ggplot(aes(x = long, y = lat, group = group)) +
geom_polygon(fill = "lightgray", colour = "black", size = 0.1) +
geom_point(data = capital, mapping = aes(x = Longitude, y = Latitude, group = Prefecture))
## 主成分分析
主成分分析を行うデータ(県庁所在地の緯度経度)を準備する。
geo <- capital %>% select(Capital, Longitude, Latitude) %>% column_to_rownames(var = "Capital")
geo <- as.matrix(geo)
head(geo)
## Longitude Latitude
## Sapporo 141.3469 43.06417
## Aomori 140.7400 40.82444
## Morioka 141.1525 39.70361
## Sendai 140.8719 38.26889
## Akita 140.1025 39.71861
## Yamagata 140.3633 38.24056
主成分分析を行う。
pca <- prcomp(geo)
summary(pca)
## Importance of components:
## PC1 PC2
## Standard deviation 4.3639 1.22318
## Proportion of Variance 0.9272 0.07284
## Cumulative Proportion 0.9272 1.00000
第1主成分の寄与率が93%、第2主成分は7%である。
主成分得点を図示する。
df <- data.frame(Capital = rownames(geo), pca$x)
plot_ly(data = df, x = ~PC1, y = ~PC2, text = ~Capital,
type = "scatter", mode = "markers")
バイプロットを描く。
biplot(pca)
第1主成分は、緯度経度の両方が小さく(大きく)なると得点が大きく(小さく)なる。
第2主成分は、経度が大きく(小さく)緯度が小さい(大きい)と得点が大きく(小さく)なる。
固有値と固有ベクトルを確認してみる。
pca$sdev^2
## [1] 19.043569 1.496168
pca$rotation
## PC1 PC2
## Longitude -0.8333102 0.5528057
## Latitude -0.5528057 -0.8333102
この計算は、以下のようにして行うこともできる。
まずは、分散共分散行列を求める。
V <- var(geo) # 分散共分散行列を計算する
V
## Longitude Latitude
## Longitude 13.681186 8.083362
## Latitude 8.083362 6.858551
次に、分散共分散行列の固有値分解を行う。
eig <- eigen(V) # 固有値分解をする
eig # 結果を表示する
## eigen() decomposition
## $values
## [1] 19.043569 1.496168
##
## $vectors
## [,1] [,2]
## [1,] -0.8333102 0.5528057
## [2,] -0.5528057 -0.8333102
主成分スコアを計算する。スコアを計算する前に、各変数(緯度・経度)の平均を0に基準化する。
X <- scale(geo, center = T, scale = F)
pcs <- X %*% eig$vectors # 主成分得点の計算
head(pcs)
## [,1] [,2]
## Sapporo -8.668767 -3.467641518
## Aomori -6.924862 -1.936771640
## Morioka -6.649001 -0.774740245
## Sendai -5.622086 0.265731346
## Akita -5.782318 -1.367685904
## Yamagata -5.182596 0.008176506
主成分得点を図示する。
plot_ly(x = pcs[,1], y = pcs[,2], text = rownames(pcs),
type = "scatter", mode = "markers")
prcompを使って計算した場合と同じ結果となる(場合によっては、正負が逆転する)。
多次元尺度法を適用する前に都市間の距離行列を求める。
緯度経度で表された2点間の距離は、geosphereパッケージのdistGeo関数で求められる。
distGeo(p1 = geo["Tokyo", ], p2 = geo["Osaka", ])
## [1] 395874.3
結果はメートルで表され、東京-大阪間はおよそ396 kmあることがわかる。
次に、全ての都市間で距離行列を計算する。
dm <- distm(geo, fun = distGeo)
rownames(dm) <- colnames(dm) <- rownames(geo)
dm <- dm / 1000 # kmの単位にする。
dm[1:5, 1:5]
## Sapporo Aomori Morioka Sendai Akita
## Sapporo 0.0000 253.8096 373.58228 534.0140 385.85116
## Aomori 253.8096 0.0000 129.30802 283.9589 134.22907
## Morioka 373.5823 129.3080 0.00000 161.1198 90.05514
## Sendai 534.0140 283.9589 161.11979 0.0000 174.19775
## Akita 385.8512 134.2291 90.05514 174.1977 0.00000
距離行列をもとに多次元尺度法を当てはめる。
mds <- cmdscale(dm)
head(mds)
## [,1] [,2]
## Sapporo -887.5166 -381.26148655
## Aomori -699.6291 -210.60184148
## Morioka -653.8852 -89.52139326
## Sendai -539.6094 24.15571884
## Akita -582.6652 -144.76377589
## Yamagata -502.0629 0.02311809
得点が計算されている。
プロットする。
plot_ly(x = mds[,1], y = mds[,2], text = rownames(mds),
type = "scatter", mode = "markers")
得点間の関係を確認する。
plot_ly(x = pcs[,1], y = mds[,1], text = rownames(pcs),
type = "scatter", mode = "markers")
plot_ly(x = pcs[,2], y = mds[,2], text = rownames(pcs),
type = "scatter", mode = "markers")
両者はほぼ直線関係にあることがわかる。両者が完全に直線に乗らない理由は、緯度・経度が完全な直交座標ではないためである。
仮に、緯度経度が直交していて、都市間の距離が緯度・経度座標上のユークリッド距離で表されるとすると(実際はそうではない)、以下のように計算される。
都市間の距離を、緯度経度のユークリッド距離で計算する。
dm.euc <- dist(geo)
mds.euc <- cmdscale(dm.euc)
プロットする。
plot_ly(x = mds.euc[,1], y = mds.euc[,2], text = rownames(mds),
type = "scatter", mode = "markers")
得点間の関係を確認する。
plot_ly(x = pcs[,1], y = mds.euc[,1], text = rownames(pcs),
type = "scatter", mode = "markers")
plot_ly(x = pcs[,2], y = mds.euc[,2], text = rownames(pcs),
type = "scatter", mode = "markers")
完全に直線関係になる。主成分分析を行った座標系上で計算されたユークリッド距離をもとに多次元尺度法を適用すると、完全に一致する。
なお、緯度・経度のユークリッド距離として計算されたものと、地理的距離として計算されたものを比較する。
plot(x = as.vector(dm), y = as.vector(as.matrix(dm.euc)),
xlab = "Euclid-distance based on Latitude/Logitude", ylab = "Geographic distance")
完全には一致しない。これが、主成分分析と多次元尺度法の結果が完全に一致しなかった理由である。