分類問題をできるだけ透明にする

昨今深層学習の台頭か高精度で予測して「はい終了」というのを時々見る事があります。ですが、例えば何らかの意思決定をする事においては高精度のAIを頼るにも入力値に気を付けないといけないし(VIFなど)、人の目で深層学習について何らかの規則性を解釈するにはSHAPなどを使用しないと難しいと思います。

https://qiita.com/murasaki1994/items/b7f76390752d4423846c

https://github.com/NTanaka1994/DataAnalysis/blob/main/%E8%AA%AC%E6%98%8E%E6%80%A7%E3%81%AE%E8%A6%B3%E7%82%B9/XDNN.ipynb

そこで、温故知新で決定木、主成分分析、ロジスティック回帰を使ってデータがどういうものか考察してみようと思います。
使用するデータはScikit-LearnにありますWineデータです。
# コーディング
## ライブラリのインポート
```Python3
from sklearn.linear_model import LogisticRegression as LR
from sklearn.tree import DecisionTreeClassifier as DTC
from sklearn.decomposition import PCA
from sklearn.tree import export_graphviz as EG
from pydotplus import graph_from_dot_data as GFDD
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
```
今回は多値分類なのでstatsmodelsではなくScikit-Learnのロジスティック回帰を使用します。
また「as」を使って長いモジュール名を略しておくと後で楽です。
## データの読み込み
```Python3
df = pd.read_csv("wine.csv")
df.head()
```
ここではwineデータをCSVに直したものを使っています。
## データの前処理
```Python3
y = df["Wine"]
x1 = df.drop("Wine", axis=1)
x2 = df.drop("Wine", axis=1)
for col in x2.columns:
    x2[col] = (x2[col] - x2[col].mean()) / x2[col].std()
```
決定木は基本的に値を標準化や正規化をする必要が無いためそのまま使います。
## 分析開始
### 決定木
決定木はif文をいっぱい使って分類するアルゴリズムみたいなものなので分類においてどの変数がどの程度分類に寄与しているかが分かり、なおかつ分類過程も出力する事が出来ます。
#### 分類寄与率
```Python3
dtc = DTC()
dtc.fit(x1, y)
imp = dtc.feature_importances_
df_imp = pd.DataFrame(imp)
df_imp.index = x1.columns
df_imp.columns = ["var_imp"]
df_imp.sort_values("var_imp", ascending=False)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/945556a1-95ac-7080-acb9-51509197f79f.png)

この結果から考察するに分類に使えそうな因子は「Proline」「OD」「Flavanoids」「Hue」「Color.int」「Alcohol」であることが分かります。

#### 分類過程
```Python3
y_data = list(set(y.values))
for i in range(len(y_data)):
    y_data[i] = str(y_data[i])
dotdata = EG(dtc,filled=True, rounded=True, class_names=y_data, feature_names=x1.columns, out_file=None)
graph = GFDD(dotdata)
graph.write_png("CART.png")
```
![CART.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/73819e26-dce4-8627-18e5-e8946d91b130.png)
これによってどういう風に分類されているかが分かります。ここで注目すべきは上に方にある変数で、変数が上にあるほど影響が強い仕様です。

### 主成分分析
主成分分析というと、次元圧縮をイメージされる方が多いと思いますが、圧縮した後の解釈の仕方を圧縮した時の寄与率と固有ベクトルから求める事が出来ます。
#### 寄与率
```Python3
pca = PCA()
pca.fit(x2)
col = []
for i in range(len(x2.columns)):
    col.append("第%d主成分"%(i+1))
exp = pca.explained_variance_ratio_
df_exp = pd.DataFrame(exp)
df_exp.index = col
df_exp.columns = ["寄与率"]
df_exp
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/15cb5154-2cf7-0be6-ad1b-671ca218800b.png)
ここで、第何主成分まで使うかについて累積寄与率から求めます。ここでは累積寄与率が0.8を超えるところまでにします。
```Python3
df_exp_sum = df_exp.cumsum()
df_exp_sum
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/511d5c04-21d4-b714-4812-0cbcfbc546ef.png)
結果から第5主成分まで使用する事にします。
#### 固有ベクトル
```Python3
com = pca.components_
df_com = pd.DataFrame(com)
df_com.columns = x2.columns
df_com.index = col
df_com.head()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/b51a12b3-ba20-67a8-0f4f-ceabc982a12f.png)
#### 因子負荷量
因子負荷量は以下の式で求める事が出来ます
```math
Cor(x_{i}, y_{j})=\sqrt{l_j}h_{ij}
```
ここで
l→寄与率
h→固有ベクトル
j→第j主成分
i→i番目の変数
になります。
```Python3
fac = []
for i in range(len(exp)):
    fac.append(np.sqrt(exp[i])*com[i])
df_fac = pd.DataFrame(fac)
df_fac.columns = x2.columns
df_fac.index = col
df_fac.head()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/77271618-8698-2068-82e1-18ee5ff5de35.png)
この結果から解釈できる事として(数値の大きさなので主観になります)
第一主成分：
Phenols、Flavanoids、Proanth、Hue、ODの値が高いと第一主成分の値が高い
Malic.acid、Acl、Nonflavanoid.phenolsの値が高いと第一主成分の値が低い

第二主成分：
Hueの値が高いと第二主成分の値が高い
Alcohol、Ash、Mg、Color.int、Prolineの値が高いと第二主成分の値が低い

第三主成分
Ash、Aclの値が高いと第三主成分の値が高い

第四主成分
Malic.acid、Proanthの値が高いと第四主成分の値が高い
Mg、Hue、Prolineの値が高いと第四主成分の値が低い

第五主成分
Mgの値が高いと第五主成分の値が高い
Nonflavanoid.phenolsの値が高いと第五主成分の値が低い

となるんじゃないかと思います。

#### 散布図
ではこれを用いて次元圧縮して二次元で散布図を描いてみましょう
```Python3
tx = pca.transform(x2)
tx2 = tx[:, 0:5]
df_tx2 = pd.DataFrame(tx2)
df_tx2.columns = ["PC1", "PC2", "PC3", "PC4", "PC5"]
df_t2 = pd.concat([y, df_tx2], axis=1)
sns.pairplot(df_t2, hue="Wine", palette="Pastel1")
plt.show()
```
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/539a1aa6-c39d-f7e5-00db-61590b1f2be1.png)
第一主成分が非常に分かりやすく分類しやすい形になっている事が分かります。
また第二主成分では「2」が分かりやすく位置が違うことが分かります。
ここで先ほどの解釈を入れればより分かりやすくなると思います。
また、その解釈と散布図からどういうデータ構造なのかも把握できます。
### ロジスティック回帰
ロジスティック回帰は標準化していると単位が統一され、係数の値が大きいほどそのラベルに分類されやすくなおかつ影響力が高いためz値を使わない場合は標準化をすることをお勧めします。
特に今回は多値分類でstatsmodelsが使えない(ことはないけど)ため係数が非常に重要になります。
#### モデルの作成
```Python3
logit = LR()
logit.fit(x2, y)
logit.score(x2, y)
```
```
1.0
```
意外なことに100%の正解率でした・・・(普通線形モデルでこれはなかなかないです)
#### 係数の確認
```Python3
coef = []
for val in logit.coef_:
    coef.append(val)
cols = []
for col in x2.columns:
    cols.append(col)
df_coef = pd.DataFrame(coef)
df_coef.index = list(set(y.values))
df_coef.columns = x2.columns
df_coef.T
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/68e97f4f-be28-cbf9-ba74-1225813c3608.png)

おそらくこの結果と主成分分析の解釈を見てみるとデータ構造が分かりやすくなるのではないかと思います。

# データの確認
ではここまで学習アルゴリズムや数理モデルで色々出しましたが実際どういう分布なのか見てみましょう
```Python3
for col in df.columns:
    if col != "Wine":
        plt.title(col)
        plt.boxplot([df[df["Wine"]==1][col], df[df["Wine"]==2][col], df[df["Wine"]==3][col]], positions=[1, 2, 3])
        plt.scatter([1, 2, 3], [df[df["Wine"]==1][col].mean(), df[df["Wine"]==2][col].mean(), df[df["Wine"]==3][col].mean()], marker="x", color="#000000")
        plt.show()
```
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/d6fec73f-3537-a9c0-63ac-d0aa31f2e24c.png)
![Untitled-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/b0d34427-5c6c-49b6-a50d-6ba0766e04aa.png)
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/15a24683-0055-1eb6-ec02-09eac6a5f33e.png)
![Untitled-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/f1206e88-baf4-7d23-43b1-e92d94af9841.png)
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/37e1f68a-850f-f006-32c1-f708f35ebfe6.png)
![Untitled-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/d3be8f18-2249-29b9-42b3-daa4ff87e83a.png)
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/d99911e6-07f6-7453-2ea7-d3e65fbbb10f.png)
![Untitled-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/f7b4dcaa-c6f9-9e2f-2c26-a81919d11622.png)
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/0e1c08cf-54cd-bde5-c968-d4a8f953b24b.png)
![Untitled-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/12aee825-2c23-f428-6824-651a9a8bfdf8.png)
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/11f0e198-8ed5-11f4-9367-a1ab0d40cd3f.png)
![Untitled-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/8408eb83-05c6-aa9a-f48f-5da941e6373d.png)
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/b69e5998-a73b-5106-b854-39ba1fb82225.png)
ここで過去の出力結果を見てみましょう。
決定木の分類寄与率では「Proline」と「OD」が非常に高い値を出していて箱ひげ図で見ても違いが分かりやすいと思います。
また、ロジスティック回帰の係数と一部一致している変数もあると思います。

# まとめ
昔からのアルゴリズムも分析には重要！

# 参考文献
<a href="https://statistics.co.jp/reference/software_R/statR_9_principal.pdf">Microsoft PowerPoint - 統計科学研究所_R_主成分分析.ppt - statR_9_principal.pdf</a>
↑
数式で使いました