【R】ggpairs()あれこれ

ggpairsとは

  • ggplot系可視化パッケージ群であるGGallyパッケージに収録されている
  • ggpairsは特に多変量の可視化に特化
  • 複数の変数や,変数間の関係をまるごと1つの図に可視化
  • baseのgraphicsに収録されているpanel.pairs()のggplot版,という感じ
  • ggplotの知識を生かして自分好みにカスタム可能(自由度がとても高い)



こんな図が簡単に作れます

  • 分布や相関関係がひと目で理解できる!


少しの注意事項

  • たくさんの変数を抱えたデータフレームをそのまま突っ込むのはやめたほうがよいです
    • 思いの外,負荷はかかるっぽい
    • そもそも,1枚にあまり多くの変数が載っているとみづらい
    • 自分の場合,10変数以上は厳しかった(重くて描画されない)


  • 本ページではスクリプトにパイプ( %>% )を用いています
    • 慣れるとこっちの方法が楽だと思います
    • 詳細は割愛しますが,「先のデータフレームを後ろの関数に送り込む」という記述方式です
    • ご存知ない方は,「dplyr, パイプ」等で調べてみて下さい



本ページでの使用パッケージ

library("tidyverse")  #ggplot2収録
library("GGally")  #ggpairsはここに収録
library("ggthemes")  #ggplot2のテーマや色を拡張できるパッケージ
  • Rstudioを使っています



参考になるページ一覧


Back to top

iris&diamondsデータでとりあえず実践

サンプルデータの概要

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
head(diamonds)
# A tibble: 6 x 10
  carat cut       color clarity depth table price     x     y     z
  <dbl> <ord>     <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
1 0.23  Ideal     E     SI2      61.5    55   326  3.95  3.98  2.43
2 0.21  Premium   E     SI1      59.8    61   326  3.89  3.84  2.31
3 0.23  Good      E     VS1      56.9    65   327  4.05  4.07  2.31
4 0.290 Premium   I     VS2      62.4    58   334  4.2   4.23  2.63
5 0.31  Good      J     SI2      63.3    58   335  4.34  4.35  2.75
6 0.24  Very Good J     VVS2     62.8    57   336  3.94  3.96  2.48


  • 連続量(num)と離散量(fac)の区別がけっこう大事です

  • Iris: アヤメ
    • Sepal.Length: がく片の長さ(num)
    • Sepal.Width: がく片の幅(num)
    • Petal.Length: 花びらの長さ(num)
    • Petal.Width: 花びらの幅(num)
    • Species: 種類(fac)
      • Setosa(ヒオウギアヤメ),Versicolor(ハナショウブ),Virginica(カキツバタ)



まずは何も設定せずにggpairs()に突っ込んでみる

p0 <- iris %>% ggpairs()

# p0 <- ggpairs(iris) と挙動は全く同じ

p0

  • 出力には多少の時間がかかります
  • すでにそれっぽいのが出てくる



表示されるパネルの説明


パネル名称と図の見方

  • パネル名称
    • upper: 対角線を挟んで右上側
    • lower: 対角線を挟んで左下側
    • diag: 対角線上
  • 図の見方
    • 図全体の縦横に変数名が並ぶ
    • 同じ変数名が重なる対角線上のdiagは,当該変数についての記述
    • 2変数の関係は,upperとlowerの2つの情報をそれぞれ組み合わせてみることができる


各パネルでの図示方法(デフォルト)

  • upper
    • 連続量×連続量: 相関係数
    • 連続量×離散量(factor): 箱ひげ図
    • 離散量×離散量: factor別棒グラフ
  • lower
    • 連続量×連続量: 散布図
    • 連続量×離散量: factor別ヒストグラム
    • 離散量×離散量: factor別棒グラフ
  • diag
    • 連続量: 密度図
    • 離散量: 棒グラフ


Back to top

図示形式を指定してみる

指定方法

  • ggpairs()内で,
    • upper = list(), lower = list(), diag = list(), のlist()内に図示形式を指定
    • 図示形式は以下
      • 既存関数から選択する(かんたん)
      • wrapを使って既存関数に少し手を加える(ggplot2の知識があったほうがよい)
      • オリジナルのggplot関数を定義し,呼び出し(gglplot2の知識が必要)
  • 形式を指定する際は,変数型の組み合わせ毎に指定する
    • 連続量×連続量(continuous)
    • 連続量×離散量(combo)
    • 離散量×離散量(discrete)
  • パネル位置=list(変数の種別=グラフの種類) のようになる

p1 <- 
iris %>% 
  ggpairs(
    upper=list(continuous="smooth_loess", combo="facethist"),
     # upperの連続×連続を平滑化線型に,連続×離散をfactor別ヒストグラムに変更
    diag=list(continuous="barDiag"),
     # diagの連続×連続をヒストグラムに変更
    lower=list(continuous="cor", combo ="box")
     # lowerの連続×連続を相関係数に,連続×離散をボックスプロットに変更
          )
p1

  • 選択できる既存オプションは下記 図示形式一覧 または ?ggpairs ヘルプ等参照


Back to top

図示形式一覧

  • 指定できる既存オプション一覧 (参考:GGally GitHub Pages)
  • または ?ggpairs のヘルプに詳しい(Rstudio上で ?ggpairs を実行)

変数間パネル(upper&lower)

continuous (連続量×連続量)

(タブをクリックすると切り替わります)

“points” = 散布図 (lowerデフォルト)

iris %>% 
  dplyr::select(Sepal.Length, Petal.Length) %>%  #変数の一部を選択
  ggpairs(upper = list(continuous = "points"))

upper(右上)を変更中…



“smooth” = 回帰線(散布図・信頼区間付き)

iris %>% 
  dplyr::select(Sepal.Length, Petal.Length) %>%  #変数の一部を選択
  ggpairs(upper = list(continuous = "smooth"))



“smooth_loess” = 平滑化線(散布図・信頼区間付き)

iris %>% 
  dplyr::select(Sepal.Length, Petal.Length) %>%  #変数の一部を選択
  ggpairs(upper = list(continuous = "smooth_loess"))



“denty” = 等高線 (どう使う??)

iris %>% 
  dplyr::select(Sepal.Length, Petal.Length) %>%  #変数の一部を選択
  ggpairs(upper = list(continuous = "density"))



“cor” = 相関係数 (upperデフォルト)

iris %>% 
  dplyr::select(Sepal.Length, Petal.Length) %>%  #変数の一部を選択
  ggpairs(upper = list(continuous = "cor"))



“blank” = 表示しない

iris %>% 
  dplyr::select(Sepal.Length, Petal.Length) %>%  #変数の一部を選択
  ggpairs(upper = list(continuous = "blank"))



combo (連続量×離散量)

“box” = 箱ひげ図

iris %>% 
  dplyr::select(Sepal.Length, Species) %>%  #変数の一部を選択
  ggpairs(upper = list(combo = "box"))



“box_no_facet” = ファセットしない箱ひげ図 (upperデフォルト)

iris %>% 
  dplyr::select(Sepal.Length, Species) %>%  #変数の一部を選択
  ggpairs(upper = list(combo = "box_no_facet"))

  • あまり見た目変わらないが,グループを分けて横並べしない,ということらしい



“dot” = ドット

iris %>% 
  dplyr::select(Sepal.Length, Species) %>%  #変数の一部を選択
  ggpairs(upper = list(combo = "dot"))

  • グループ内での左右のばらつきには多分意味はない



“dot_no_facet” = ファセットしないドット

iris %>% 
  dplyr::select(Sepal.Length, Species) %>%  #変数の一部を選択
  ggpairs(upper = list(combo = "dot_no_facet"))

  • 位置づけは“box_no_facet”と同じ



“facethist” = グループ別ヒストグラム (lowerデフォルト)

iris %>% 
  dplyr::select(Sepal.Length, Species) %>%  #変数の一部を選択
  ggpairs(upper = list(combo = "facethist"))



“facetdensity” = グループ別密度図

iris %>% 
  dplyr::select(Sepal.Length, Species) %>%  #変数の一部を選択
  ggpairs(upper = list(combo = "facetdensity"))

  • これも横向き(lower)の方が見やすいかな?
  • あと色も付けてみよう


iris %>% 
  dplyr::select(Sepal.Length, Species) %>%  #変数の一部を選択
  ggpairs(lower = list(combo = "facetdensity"),
          mapping = aes(color = Species)) #そのままでは見づらいので色をつけておく

  • グループ別の色付けは下記 グループ変数(エステティック)の追加を参照



“denstrip” = 帯状密度図

iris %>% 
  dplyr::select(Sepal.Length, Species) %>%  #変数の一部を選択
  ggpairs(upper = list(combo = "denstrip"))



“blank” = 表示しない

  • continuousと同じなので割愛



discrete(離散量×離散量)

  • irisではなくdiamondsデータを使用


“facetbar” = 棒グラフ(デフォルト)

diamonds %>% dplyr::select(color, cut) %>% ggpairs(upper = list(discrete = "facetbar"), 
    mapping = aes(color = cut))  #見づらいのでグループ毎に色をつける



“ratio” = よくわからん(情報募集中)

diamonds %>% dplyr::select(color, cut) %>% ggpairs(upper = list(discrete = "ratio"), 
    mapping = aes(color = cut))  #見づらいのでグループ毎に色をつける

  • 面積でなにかを表している???



“blank” = 表示しない

  • 同じなので割愛


Back to top

変数内パネル(diag)

continuous (連続量)


“densityDiag” = 密度図 (デフォルト)

iris %>% dplyr::select(Sepal.Length, Species) %>% ggpairs(diag = list(continuous = "densityDiag"))



“barDiag” : ヒストグラム

iris %>% dplyr::select(Sepal.Length, Species) %>% ggpairs(diag = list(continuous = "barDiag"))



“blankDiag” : 表示しない

iris %>% dplyr::select(Sepal.Length, Species) %>% ggpairs(diag = list(continuous = "blankDiag"))



discrete (離散量)

  • 棒グラフ(デフォルト) か 表示しないのみ

“barDiag” : 棒グラフ(デフォルト)

iris %>% dplyr::select(Sepal.Length, Species) %>% ggpairs(diag = list(discrete = "barDiag"))

  • irisは3種のサンプル数が同じなので殺風景な図になった…



“blankDiag” : 表示しない

  • 割愛


Back to top

グループ変数(エステティック)を追加してグレードアップ

  • mapping = aes(color = グループ変数) などでエステティック属性を追加
p2 <- 
iris %>% 
  ggpairs(mapping = aes(color = Species), #Speciesでグループ分け

          
    diag=list(continuous="barDiag"),
     # diagの連続×連続を積み上げヒストグラムに変更
    lower=list(continuous="smooth", combo = "facetdensity")
     # lowerの連続×連続を回帰線に,連続×離散を密度図に変更
          )
p2


  • カラーパレットの変更や色の指定はここでは直接難しい
    • 方法については後述
  • aes(alpha = 0.8) 等で透過率はここで設定できる
  • パネル毎にエステティックを追加したいなら以下のようにlistの中に入れる
iris %>% 
  ggpairs(
    upper=list(continuous="smooth", combo="facethist",
               mapping = aes(color = Species)), 
     # upperの連続×連続を回帰線に,連続×離散をfactor別ヒストグラムに変更
     # Speciesでグループ分け
    diag=list(continuous="barDiag"),
     # diagの連続×連続をヒストグラムに変更
    lower=list(continuous="cor", combo ="box")
     # lowerの連続×連続を相関係数に,連続×離散をボックスプロットに変更
          )

  • upperだけにグループ化変数を設定できた


Back to top

wrap関数で少し手を加えてみる

  • wrap関数を使ってデフォルトの関数を上書きできる
  • wrap関数の第一引数(先頭)に既存関数名,続けて既存関数の「引数名 = 上書き値」で変更できる
  • ただ,ggpairsの既存関数の詳細がよくわからない(情報ください)ので,手探りで変えていく感じになる
    • 自由度があまり高くなさそう
    • 思い通りの図示をするなら,自作関数を作って組み込んでいく方が早い(詳細はさらに下記)


例1:ヒストグラムのビン幅(binwidth)を変更

  • デフォルトの“barDiag”と“facetbar”
iris %>% dplyr::select(Sepal.Length, Species) %>% ggpairs(diag = list(continuous = "barDiag"), 
    lower = list(combpo = "facetbar"))

  • wrapでビン幅を上書き
iris %>% dplyr::select(Sepal.Length, Species) %>% ggpairs(diag = list(continuous = wrap("barDiag", 
    binwidth = 1)), lower = list(combo = wrap("facetbar", binwidth = 1)))



例2:平滑化線の信頼区間(グレー)を消す

iris %>% dplyr::select(Sepal.Length, Petal.Length) %>% ggpairs(upper = list(continuous = wrap("smooth_loess", 
    se = FALSE)))



例3:散布図のドットサイズや文字サイズ,さらに透過率を変える

iris %>% 
  dplyr::select(Sepal.Length, Petal.Length, Species) %>% 
  
  ggpairs(mapping = aes(color = Species),
          #Speciesで色分け
          
          lower = list(continuous = wrap("smooth", size = 1.5, alpha = 0.8)),
          #散布図付き回帰線の散布図のドットサイズを1.5に,また透過率を0.8に
          
          upper = list(continuous = wrap("cor", size = 5)),
          #相関係数の文字サイズを5に
          
          diag = list(continuous = wrap("densityDiag", alpha = 0.5))
          #3種の密度図が重なるので,透過率0.5にして可視化
          
          )

  • いい感じになりました。これだけでもいろいろ見えてきそう。


Back to top

個人的見解

  • 先程も述べましたが,wrapを使った方法はあまり自由度は高くありません
    • あくまで既存関数の上書き
    • いろいろ細かい設定をするならば,やはり自作のggplot関数を作りましょう
  • ですが,例3のように少し手を加えてやるだけで見違えるようになるのも確かですね!


Back to top

上書き式で色やテーマを変更する

色を変更する

  • まずはデフォルト
iris %>% 
  dplyr::select(Sepal.Length, Petal.Length, Species) %>% 
  
  ggpairs(mapping = aes(color = Species),
          #Speciesで色分け
          
          lower = list(continuous = "smooth"),
          #散布図付き回帰線の散布図のドットサイズを1.5に,また透過率を0.8に
          diag = list(continuous = wrap("densityDiag", alpha = 0.5))
          #3種の密度図が重なるので,透過率0.5にして可視化
          
          )

  • グループ変数について,デフォルト色(“Pastel1”パレット)がそのまま適用されている
  • 色の変更は以下のようにする
    • 図を一旦格納(p)
    • 格納先(p)の,全てのパネルについて同様に色を上書き(for文を用いる)
    • 色指定にはscale_fillとscale_colorの区別があるので両方やっておくのがよい
p <- iris %>%  #図をpに格納
  
  dplyr::select(Sepal.Length, Petal.Length, Species) %>% 
  ggpairs(mapping = aes(color = Species),
          #Speciesで色分け
          
          lower = list(continuous = "smooth"),
          #散布図付き回帰線の散布図のドットサイズを1.5に,また透過率を0.8に
          diag = list(continuous = wrap("densityDiag", alpha = 0.5))
          #3種の密度図が重なるので,透過率0.5にして可視化
          )

for(i in 1:p$nrow) {
  for(j in 1:p$ncol){
    p[i,j] <- p[i,j] + 
        scale_fill_manual(values=c("blue", "red", "green")) + 
        scale_color_manual(values=c("blue", "red", "green"))
  }
}

#パネルのi行j列のggplotにscale_fill_manualとscale_color_manualを追加

p #図示

  • カラーコードからの直接指定(p2)やパレットを変更(p3)するなら以下
p2 <- iris %>%  #図をp2に格納
  
  dplyr::select(Sepal.Length, Petal.Length, Species) %>% 
  ggpairs(mapping = aes(color = Species),
          #Speciesで色分け
          
          lower = list(continuous = "smooth"),
          diag = list(continuous = wrap("densityDiag", alpha = 0.5))
          #3種の密度図が重なるので,透過率0.5にして可視化
          )

for(i in 1:p2$nrow) {
  for(j in 1:p2$ncol){
    p2[i,j] <- p2[i,j] + 
        scale_fill_manual(values=c("#FFCCFF", "#FF99FF", "#FF66FF")) +
        scale_color_manual(values=c("#FFCCFF", "#FF99FF", "#FF66FF")) 
  }
}

#パネルのi行j列のggplotにscale_fill_manualとscale_color_manualを追加

p2 #図示


p3 <- iris %>%  #図をp3に格納
  
  dplyr::select(Sepal.Length, Petal.Length, Species) %>% 
  ggpairs(mapping = aes(color = Species),
          #Speciesで色分け
          
          lower = list(continuous = "smooth"),
          diag = list(continuous = wrap("densityDiag", alpha = 0.5))
          #3種の密度図が重なるので,透過率0.5にして可視化
          )

for(i in 1:p3$nrow) {
  for(j in 1:p3$ncol){
    p3[i,j] <- p3[i,j] + 
        scale_fill_brewer(palette = "Spectral") +
        scale_color_brewer(palette = "Spectral") 
  }
}

#パネルのi行j列のggplotにscale_fill_brewerとscale_color_brewerを追加
#パレットには"Spectral"を指定した

p3 #図示



テーマを変更する

  • テーマの変更はggpairsの末尾に + で加えるだけでよい
p4 <- iris %>% 
  
  dplyr::select(Sepal.Length, Petal.Length, Species) %>% 
  ggpairs(mapping = aes(color = Species),
          #Speciesで色分け
        
          lower = list(continuous = "smooth"),
          diag = list(continuous = wrap("densityDiag", alpha = 0.5))
          #3種の密度図が重なるので,透過率0.5にして可視化
          ) + 
  theme_classic()

p4 #図示

  • theme_classic()はggplot2収録
p5 <- iris %>% 
  
  dplyr::select(Sepal.Length, Petal.Length, Species) %>% 
  ggpairs(mapping = aes(color = Species),
          #Speciesで色分け
        
          lower = list(continuous = "smooth"),
          diag = list(continuous = wrap("densityDiag", alpha = 0.5))
          #3種の密度図が重なるので,透過率0.5にして可視化
          ) + 
  theme_solarized(light = F) #テーマ変更

for(i in 1:p5$nrow) {
  for(j in 1:p5$ncol){
    p5[i,j] <- p5[i,j] + 
      scale_fill_solarized() +
      scale_color_solarized() 
  }
}
#各パネルの色を変更

p5 #図示

  • 最後はggthemes収録のテーマと色変更のあわせ技
    • 見栄えはハマると沼!!!!!


Back to top

補足

  • 例えばp[2,1] は,「pに格納した図の2行目1列目のパネル」を意味します
p[2, 1]

  • for文による色の変更はこの仕組みを利用しています
  • 特定のパネルだけ示したい時など便利です

  • これを使えば,特定のパネルだけ変更or差し替えも可能


Back to top

追加情報

position_jitterでドットをずらす

  • 散布図系で,position = position_jitter() を追加すればドットをジッター(乱数でずらす)できます
  • 同じ値を取るなど,ドットが重なってしまう場合に便利!
iris %>% dplyr::select(Sepal.Length, Sepal.Width) %>% dplyr::mutate(Sepal.Length = round(Sepal.Length), 
    Sepal.Width = round(Sepal.Width)) %>% # 2変数を四捨五入してしまう(無理やりな例)
ggpairs(lower = list(continuous = "points"))

  • lowerの散布図の点が重なってしまう
iris %>% dplyr::select(Sepal.Length, Sepal.Width) %>% dplyr::mutate(Sepal.Length = round(Sepal.Length), 
    Sepal.Width = round(Sepal.Width)) %>% # 2変数を四捨五入してしまう(無理やりな例)
ggpairs(lower = list(continuous = wrap("points", position = position_jitter(width = 0.2, 
    height = 0.2))))

  • 各値を乱数で少しずらして図示することで,密度的な視覚化が可能になる


Back to top

その他のオプション

図示する変数を指定する

  • columnsで変数名を入力して指定
iris %>% ggpairs(columns = c("Sepal.Length", "Petal.Length", "Species"))

使用例

  • グループ変数としてSpeciesを使用するが,図示するのは連続量のみ
iris %>% 
  ggpairs(columns = c("Sepal.Length", "Sepal.Width",
                      "Petal.Length", "Petal.Width"),
    
          mapping = aes(color = Species),
          #Speciesで色分け
          
          lower = list(continuous = "smooth"),
          diag = list(continuous = wrap("densityDiag", alpha = 0.5))
          #3種の密度図が重なるので,透過率0.5にして可視化
          )

  • 個人的にはこれが便利でお気に入りです



図示する変数名を書き換える

iris %>% ggpairs(columns = c("Sepal.Length", "Petal.Length", "Species"), columnLabels = c("がく片の長さ", 
    "花びらの長さ", "種")) + theme_gray(base_family = "HiraKakuPro-W3")


Back to top

自作ggplot関数を組み込む(上級)

  • より自由な図をパネルに組み込むには,自作のggplot関数を組み込んでやるのがよい
  • ggplot2と関数定義の知識が必須。ただし仕組み自体は非常に簡単なのでぜひどうぞ

例:バイオリンプロットを組み込んでみる

  • upperの連続量×離散量を箱ひげからバイオリンプロットに変更したい
  • バイオリンプロットは既存オプションにないので自作


  • 関数の定義
my_violin <- function(data, mapping, ...) {
    # デフォルトの引数をほかに設定するならfunction()内に追加しておく
    
    # 以下にggplotを定義
    ggplot(data = data, mapping = mapping) + geom_violin(...)
}


  • 自作関数を組み込み
iris %>% 
  ggpairs(
    columns = c("Sepal.Length", "Sepal.Width", "Species"), #変数の指定
    mapping = aes(color = Species), #Speciesでグループ分け
      
    upper=list(combo = my_violin),
     # upperの連続×離散に,自作した関数を設定(""でくくらなくてよい)
    
    diag = list(continuous = wrap("densityDiag", alpha = 0.5))
     # diagの連続×連続をヒストグラムに変更
          )



  • 関数定義で「…」を入れておくと,wrapでgeom_violinを上書きできるのでなにかと便利
    • function()内の「…」はざっくりいうと,「その他の引数」という意味
    • その他の命令も受け付けますよ,それは「…」部分に反映させますよ,という感じ
iris %>% 
  ggpairs(
    columns = c("Sepal.Length", "Sepal.Width", "Species"), #変数の指定
    mapping = aes(color = Species), #Speciesでグループ分け
      
    upper=list(combo = wrap(my_violin, trim = FALSE)),
     # my_vioinをwrapしてtrim = FALSEに上書き
    
    diag = list(continuous = wrap("densityDiag", alpha = 0.5))
     # diagの連続×連続をヒストグラムに変更
          )

  • geom_violinはデフォルトでtrim = TRUEだが,上記のようにwrapでFALSEに書き換え
    • 尻尾の切れない図にできた


  • ご自身のお気に入りplotをぜひ活用してみて下さい!


Back to top

澤田昂大 (Gota Sawada)
名古屋大学教育発達科学研究科 M2

2019-08-08