R言語 - データフレームの項目を、相関係数が高い組み合わせ順に並び変える

# 結論を先に

以下のコードで、 `original_data` を対象のデータフレームに書きかえれば動くはず。

```R:データフレームを、相関関係の強い項目の組み合わせ順に並べる

# ライブラリの読み込み
library(tidyverse)

# ここの original_data をほしいデータに変える
data <- original_data

# もとのデータに数字以外の項目が混ざっている場合は以下を実施
# data <- data[, !(names(data) %in% c("不要な項目のカラム名1","不要な項目のカラム名2"))]

# 項目の組み合わせを列挙
col_names = t(combn(names(data),2))

# tibble化
tib_cols <- tibble(col_names)

# 列の追加と初期化
tib_cols$Cor.Sign <- rep(0, times=nrow(tib_cols))
tib_cols$Cor.Abs <- rep(0, times=nrow(tib_cols))

# 相関係数、符号、絶対値の計算

for (i in 1:nrow(col_names)){

  # cor()が名前付きのデータフレームを返してくる場合は、
  # )の直後に[1,1]をつけて素の値を取り出す
  x <- cor(data[, col_names[i,1]], data[, col_names[i,2]], use="complete.obs") #[1,1]
  
  tib_cols$Cor.Sign[i] <- sign(x)
  tib_cols$Cor.Abs[i] <- abs(x)

}

# 絶対値の降順にソート
tib_cols %>% arrange(-Cor.Abs)

```

`original_data` に `mtcars` ([Rの標準データセット](https://www.math.chuo-u.ac.jp/~sakaori/Rdata.html)で、70年代の車のスピードや燃費に関するデータが入っている) を入れて実行すると、こんな感じで出てきます。 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/a35d2314-a8e2-1724-4dae-e8fc503e432d.png)

もっといいやりかたをご存じの方は、ぜひコメント欄でご教示ください・・・！

以下、細かい話です。

# 問題意識

R言語でデータを解析する際に、「与えられたデータの中で、相関関係が強い組み合わせは何か？」は知りたいことのひとつと思う。

実務上は、ggpairsなどを使って相関の強い項目を目視することが多いそうだ。

このように。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/5c77f713-38fb-8a50-dc3f-582834c6bd19.png)

しかし項目数が増えてくるにつれ、「どの項目が最も相関が強いのか」を目視で確認するのは大変になってくる。

この中でどれが一番？　うーん・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/186ae54b-298e-0422-e226-055af46a7320.png)

相関関係を行列にして、ヒートマップを作るという手もあるそうだが、やはり「何が一番か」を見るのはつらい。

```R:相関行列によるヒートマップの作成
# 相関行列の計算
cor_matrix <- cor(mtcars, use = "complete.obs") 
# 相関行列を表示
print(cor_matrix)
heatmap(cor_matrix, 
        col = colorRampPalette(c("blue", "white", "red"))(20),
        Colv = NA, Rowv = NA,
        main = "Correlation Heatmap",
        xlab = "Variables", ylab = "Variables",
        margins = c(5, 5),
        cexRow = 1.0, cexCol = 1.0,
        symm = TRUE  # 行列が対称であることを指定
```
この中でどれが一番だなんて・・・？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/69e68980-2b2d-bfa0-a1d3-3933a021dc18.png)

ということで、様々な値の入ったデータセットの中で、その中の2つの項目について、相関関係の高い組み合わせ順に並べ替える処理をなるべく共通化したい！

…と思ってやってみたところ、意外と躓くところが多かったので、後々のためにメモしました。

# 方針

以下の方針でやりました。

:::note
- まず、対象となるデータセットから2つの項目名を取り出した組み合わせを列挙したデータフレームを作る
- 上記のデータフレームに、その2つの項目の相関係数の符号と絶対値をそれぞれ格納する列を追加
- 上記のデータフレームを、相関係数の絶対値で降順にソート
:::

# 手順

## 準備

tidyverseを使います。
```R:tidyverseの読み込み
library(tidyverse)
```

後々の処理がコードサンプルどおりに動くように、代入しておきます。

```R:代入（あとのコードと整合性をとるため）
data <- mtcars
```

### 数字以外の項目の除外

相関を出していく際に、数字以外の項目（文字列など）が入っているとエラーになるります。

なので、数字以外の項目が入っている場合は、その列をここで除外しておきます。

```R:数字以外の項目を除外
data <- data[, !(names(data) %in% c("不要な項目のカラム名1","不要な項目のカラム名2"))]
```

今回例に使う `mtcars` のデータセットは、全項目数字なので、上記はやらなくて大丈夫です。

## 2つの項目名を取り出した組み合わせを列挙したデータフレームを作る

```R:2つの項目名の組み合わせを列挙
col_names = t(combn(names(data),2))
```

:::note
- names(df) : データフレームの列名をベクトルにして返す
- cobmn(x,y)が、xの中からy個の要素を取り出して、組み合わせを列挙する（1-2と2-1のように、順番は違っても要素が同じという意味での重複も排除）
- t()は行列の入れ替え
:::

:::note warn
colnames は関数名なので、代入先の変数名には col_names を使う
:::

`col_names` を表示すると、以下のようになる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/0e69c61b-d1fe-2218-2432-ea36bc0dfb23.png)

…

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/7de94737-db9c-68cd-26ba-f8a5e09d9b0c.png)

## 符号と絶対値を追加する

上記で作った `col_names` に、符号と絶対値の列を追加します。

### tibble化

あとあと列を追加する用に、`col_names` を tibble 化した `tib_cols` を作っておきます。

```R:tibble化
tib_cols <- tibble(col_names)
```

:::note warn
列の追加のために本当に tibble 化が必要だったのかは自信がない。
:::

### 符号と絶対値の列を追加

まず、符号と絶対値を格納する用の列を作り、全行をゼロ埋めします。

```R:符号と絶対値を格納する列の追加（初期化）
tib_cols$Cor.Sign <- rep(0, times=nrow(tib_cols))
tib_cols$Cor.Abs <- rep(0, times=nrow(tib_cols))
```

この段階で、`tib_cols` の中身を見るとこんな感じになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/d8c08717-3a6c-b00e-8966-bf82354ffa6b.png)

:::note warn
こんなCOBOLみたいな初期化が本当に必要だったのかは自信がない。
でもやらないとうまくいかなかったので仕方なくやりました。。。
:::

そして、符号と絶対値を設定します。

```R:符号と絶対値を設定

for (i in 1:nrow(col_names)){

  x <- cor(data[, col_names[i,1]], data[, col_names[i,2]], use="complete.obs") #[1,1]

  tib_cols$Cor.Sign[i] <- sign(x)
  tib_cols$Cor.Abs[i] <- abs(x)

}
```

:::note
- cor(a, b) : ベクトルaとベクトルbの相関係数を計算する。
- use="complete.obs" : cor(a,b) は、デフォルトでは a か b のどちらか一方にでも欠損値があると NA を返してくる。このオプションを指定することで、欠損地があっても相関係数を計算してくれる。
- cor()のあとの #[1,1] : cor(a, b) は、名前つきのデータフレームを返してくることがある。値だけを取り出したい場合は、コメントを外して[1,1]を指定する。
:::

この段階で、`tib_cols` の中身はこんな感じになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/762cb6dc-6c34-28d9-8a05-822fa69d6b17.png)


## ソート

あとは絶対値で降順にソートすれば、相関関係の強い項目が見られる！

```R:降順にソート
tib_cols %>% arrange(-Cor.Abs)
```

:::note
- tibble %>% arrange(列名) : 列名で昇順にソート
- tibble %>% arrange(-列名) : 列名で降順にソート
:::

## 完成！

・・・ということで、できたーん！
相関関係の強い項目の組み合わせ Top10 はこちらです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/a35d2314-a8e2-1724-4dae-e8fc503e432d.png)

# やり残したこと

相関係数を出す際に、欠損値を無視するオプションを指定しているが、項目の組み合わせによっては、欠損値が多すぎることによって順位がブレてくるものがあるかもしれない。

それぞれの項目の欠損値の数や、欠損の割合も計算して `tib_cols` に入れると、信ぴょう性の判断がつきやすいかもしれない。

…けどそれはのちほど。（すぐできる気もするが今日は寝ます）

# 以上！

メモは以上です。

筆者自身、Rもデータ分析も初心者🔰ですので、もっといいやりかたをご存じの方はぜひコメントでご教示ください・・・！