クラスタリング

ここではクラスタリングについて簡単にメモる。
参考文献: [RとPythonで学ぶ[実践的]データサイエンス&機械学習【増補改訂版](https://www.amazon.co.jp/R%E3%81%A8Python%E3%81%A7%E5%AD%A6%E3%81%B6-%E5%AE%9F%E8%B7%B5%E7%9A%84-%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%A8%E3%83%B3%E3%82%B9-%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%80%90%E5%A2%97%E8%A3%9C%E6%94%B9%E8%A8%82%E7%89%88%E3%80%91-%E6%9C%89%E8%B3%80/dp/4297120224/ref=pd_lpo_14_t_0/356-5235986-3620146?_encoding=UTF8&pd_rd_i=4297120224&pd_rd_r=c8c765b5-9c4b-4b04-ae3d-924af10aca11&pd_rd_w=D1zeQ&pd_rd_wg=x7MHn&pf_rd_p=dc0198fa-c371-4787-b1e2-96ed0e4d45e8&pf_rd_r=AB9B7JSTCBQ8SDHV3024&psc=1&refRID=AB9B7JSTCBQ8SDHV3024)

#1 階層型クラスタリング
ex)
RFM分析→より詳細なマーケティングを行うために使用されるフレームワーク
・Recency 直近購入日
・Frequency 購入回数
・Monetary 購入金額
上記の3軸をもとにクラスタリングを行う。

"どう分類するか"問題
1.nグループに分けるか。
2.どこを基準で分けるか。
を考える必要がある。

<考え方>
要素が近い(距離が近い)ものを同グループと考える。距離の測定方法としてはユークリッド距離を採用する。

・クラスタリングの注意　
<スケール>
横軸が購入回数(n回)、縦軸が購入金額(円)とする時どうしても縦軸の方が大きい数字になる(購入回数は多くても2桁、しかし金額は5~桁になることもままありうる)。そのため両者のスケールを統一する必要がある。そこで標準化を使用する。標準化とは以下のように平均を0、標準偏差を1になるようにデータを変換することである。

```math
標準化=\frac{X_iを平均で引く}{標準偏差}
```

```math
Z_i=\frac{x_i-\bar{x}}{\sqrt{\frac{1}{n}\sum_{n=1}^{i}(n_i-\bar{n})}}
```
これによって単位が異なる軸同士で正常にクラスタリングを行うことができる。


以下で実装をしてみる。
まずはデータの確認を行う。
データは
・Recency 直近購入日(YYYY-MM-DD)
・Frequency 購入回数(回)
・Monetary 購入金額(円)
に加えて、レコードIDが表記されていることがわかる。また基本統計量はsummary()にまとめてあるので一度目をとうしてみて欲しい。

```R
> head(DF,3)
     ID    recency frequency monetary
1 A0004 2016-04-19         3     1830
2 A0455 2016-04-17         6     5280
3 A0456 2016-04-02         1      775
> summary(DF)
      ID              recency            frequency         monetary      
 Length:84          Length:84          Min.   : 1.000   Min.   :  100.0  
 Class :character   Class :character   1st Qu.: 1.000   1st Qu.:  935.8  
 Mode  :character   Mode  :character   Median : 2.000   Median : 1812.5  
                                       Mean   : 3.048   Mean   : 3069.0  
                                       3rd Qu.: 4.250   3rd Qu.: 4366.2  
                                       Max.   :11.000   Max.   :13606.0  
```
前述したようにスケールを統一するために標準化を行う。Rではscale()を使用することでこれが可能になる。　

```R
#scale()でスケールの統一
DFn <- data.frame(scale(DFn))
summary(DFn)
```

これからクラスタの実装を行う。

```R
#階層型クラスタリング
#dist() 全ての距離行列を作成
DIST <- dist(DFn)
DIST

#階層型クラスタリングで樹形図を表示
result_hc <- hclust(DIST, method="ward.D2")
plot(result_hc) #下図を参照

#クラスタ数の指定
num_hc <- cutree(result_hc, k=4) #クラスタ数の指定
num_hc<- factor(num_hc) # 数値をカテゴリに
> head(num_hc)
A0004 A0455 A0456 A0890 A0895 A0896 
    1     2     3     3     2     1 
Levels: 1 2 3 4
> table(num_hc) #クラスタごとの集計
num_hc
 1  2  3  4 
35 19 21  9 
```

![樹形図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1451692/200fe7db-ca4d-c652-a981-c261d2c0f93b.png)

参考としてrecencyにおけるクラスターごとの箱ヒゲ図を置いておく。
![recency.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1451692/c7acc97e-e8d4-262a-73d0-a247811b9e95.png)

#2 非階層型クラスタリング(K平均法)
K平均法はあらかじめk個の中心点がランダムに設定され、その中心点に近い要素をまとめてクラスタとして識別する。これを何回も繰り返すことで最終的なクラスタを決定する。K平均法のメリットは階層型クラスタリングよりも実行速度が速いことにあり、データの数が大量に存在する時に有効な手段になる。

```R
#K-meanによるクラスタリング

#対象データ、クラスタ数、最大繰り返し数
km <- kmeans(DFn, 4, iter.max = 30)

> head(km$cluster)
A0004 A0455 A0456 A0890 A0895 A0896 
    2     1     3     3     1     2 
> table(km$cluster) #クラスタごとの集計

 1  2  3  4 
21 41 18  4 
```

#3 散布図と相関係数
```R
#散布図を描く
library(ggplot2)
library(GGally)
ggpairs(DFn,
        aes(colour=num_hc, #クラスタを色、形で識別できるように
            shape = num_hc,
            alpha=0.9),
        #左下を散布図
        lower=list(continuous=wrap("points", size=4)),
        #右上を相関係数
        upper=list(continuous=wrap("cor", size=4)) ) +
  #背景:白
  theme_bw()
```
![散布図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1451692/308220a0-d006-d46f-5844-95b0214b1108.png)

#4 3次元プロット

```R
#3D描画ライブラリ
library(threejs)

#階層ごとの色ラベルを作成
color_hc <- num_hc
head(color_hc)

#クラスタ番号・色を変更
#levels() factorのラベル指定
levels(color_hc) = c("lightpink", "green4", "deepskyblue4", "plum2")

#factorの実態は整数なので文字列に変換
color_hc <- as.character(color_hc)

#scatterplots3js 3Dプロット
#引数最初に3次元データと指定(matrix形式に)
#color 色分け
#labels 各ラベル
#size 各プロットの大きさ
scatterplot3js(as.matrix(DFn), #座標データ
               color=color_hc, #色指定
               labels=DF$ID, #ケースラベル
               size=.5)
```

![3Dplot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1451692/d3172f65-bdc2-750f-56ea-42c1ec9289fa.png)