2. Pythonで綴る多変量解析　4-1. 因子分析(scikit-learn)

因子分析は、多数ある変量の間に共通する因子を探り出して、それらの共通因子を使ってデータを評価するための技法です。

たとえば、マーケティングリサーチでは、ある質問の回答データ（多肢選択型でそれも選択肢が何十もある）について因子分析を行ない、ずっと少ない数の因子に置き換えます。それを今度はデータとして、クラスター分析（人分け）を行ない、つまりタイプ分類をしてプロファイリングをやったりします。各クラスターの性別・年齢別の構成比はどうなっているか、どのような特性をもった人たちなのか、市場全体に占めるボリュームは何％か、というようなことをやるわけです。

さて、12教科のテストの得点が1000人分、というダミーデータを因子分析用に作成しました。
以下、scikit-learnを利用して、因子分析の大筋をつかみます。


####⑴ ライブラリを読み込む
```python
# 数値計算ライブラリ
import numpy as np
import pandas as pd
# 可視化ライブラリ
import matplotlib.pyplot as plt
%matplotlib inline
```
####⑵ ダミーデータを読み込む
```python
url = 'https://raw.githubusercontent.com/yumi-ito/sample_data/master/subject_scores.csv'
df = pd.read_csv(url)
df.head()
```
GitHubに保管してあるcsvファイル`subject_scores.csv`を読み込み、冒頭5行を表示して中身を確認します。
![2_4_1_01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/63d24532-5c87-0168-c3c9-3ce4cd0e7f39.png)
####⑶ データを概観する ➀基本統計量
```python
df.describe().apply(lambda s: s.apply(lambda x: format(x, 'g')))
```
標本数(count)、平均値(mean)、標準偏差(std)、最小値(min)、四分位数(25%, 50%, 75%)、最大値(max)となっています。
なお、基本統計量の取得は`describe()`で事足りますが、それだと小数点以下6桁に0が並び、とても見づらいので`.apply()`以下で調節しています。
![2_4_1_02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/65a26210-2dbd-1db8-3902-dc85cdcc4067.png)
####⑷ データを概観する ➁散布図
```python
# matplotlibを日本語表示に対応させるモジュール
!pip install japanize-matplotlib
import japanize_matplotlib

# pandasのplottingメソッドをインポート
from pandas import plotting

# 散布図行列を表示
plotting.scatter_matrix(df, figsize=(12, 12), alpha=0.8)
```
pandasのplottingメソッドは、通常のplotメソッドよりも高度なグラフを描画することができます。
それはさておき、これは因子分析のために作成したダミーデータなので、実際にはあり得ないような高い相関が見てとれます（というか、そのように仕組んであります）。
![2_4_1_03.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/59efaf46-27e6-6cfd-f08d-38c7ceb8159c.png)
####⑸ データを標準化する
```python
# sklearnの標準化モジュールをインポート
from sklearn.preprocessing import StandardScaler

# データを変換する計算式を生成
sc = StandardScaler()
sc.fit(df)

# 実際にデータを変換
z = sc.transform(df)

print(z)
print(z.shape)
```
**標準化**とは、平均が0、分散が1（標準偏差も1）となるようにデータを変換してやることです。標準化は、次の式で行います。
$\displaystyle\frac{x-\bar{x}}{s}$
データの各値$x$から、その変数列の平均$\bar{x}$を引き、標準偏差$s$で割ります。
かりに、ある生徒の得点が、日本史が70点で倫理が60点だったとすると、
$日本史：\displaystyle\frac{70-65.574}{4.31545}=1.025617$
$倫　理：\displaystyle\frac{60-49.588}{9.0544}=1.149938$
つまり、得点だけを見ると日本史のほうが上のようですが、倫理のほうが上だとわかります。このように平均や標準偏差、あるいは単位の異なる変数間で大小を評価することができるようになります。
![2_4_1_04.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/ef815bb4-d9e8-98b8-ec16-b68b6e623758.png)
これを**標準化得点(standard score)**とか**z得点**などといい、行列の形状はもとのデータと同じ1000名×12変数（12教科）になっています。
####⑹ モデルを生成し、因子得点を算出する
```python
# sklearnのFactorAnalysis(因子分析)クラスをインポート
from sklearn.decomposition import FactorAnalysis as FA

# 因子数を指定
n_components=3

# 因子分析の実行
fa = FA(n_components, max_iter=5000) # モデルを定義
fitted = fa.fit_transform(z) # fitとtransformを一括処理

print(fitted)
print(fitted.shape)
```
もとは1000名×12変数であったデータが、1000名×3因子に変換されています。すなわち、各人のテストの得点は、各人の**因子得点**に変換されたわけです。
![2_4_1_06.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/12b7641c-3afd-9602-ccff-1d2a10052c36.png)
####⑺ 因子負荷量行列を取得する
```python
fa.components_.T
```
生成されたモデル`fa`に対し`components_`メソッドで**因子負荷量**を取得し、`.T`で行列を転置して表示しています。
![2_4_1_08.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/5bb7af73-ae6c-d2ea-50fe-59aacd52ab92.png)
因子の解釈をやり易いように、行名・列名を付与してデータフレームに変換します。

```python
# 変数Factor_loading_matrixに格納
Factor_loading_matrix = fa.components_.T

# データフレームに変換
pd.DataFrame(Factor_loading_matrix, 
             columns=["第1因子", "第2因子", "第3因子"], 
             index=[df.columns])
```
因子負荷量は、共通因子が各変数に与える影響度を表わします。ある共通因子が潜在的にはたらいて、変数のそれぞれに影響を与えているから、それがテストの得点に反映しているという考え方です。

➀因子負荷量の絶対値の大きさ、➁因子負荷量のプラス・マイナス、にもとづいて因子の解釈をおこないます。
**第１因子**は、すべての変数がプラスになっているので、この因子が高くなると全変数が足並みをそろえて高くなります。そこで「総合学力」とか「基礎学力」などと命名できそうです。
**第２因子**は、国語・英語の絶対値が大きく、いずれもプラスで、また倫理もプラスでやや高めとなっています。そこで「言語能力」と命名しておきましょう。
**第３因子**は、数学・物理の絶対値がずば抜けて大きく、いずれもプラスになっているので、この因子は「数理能力」といえます。
![2_4_1_09.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/a6199266-693a-aed2-3592-8c07eda8ceb3.png)
---

因子分析って、こうしてライブラリを使えば、いとも手早くできてしまうのですが、実はかなり中ではいろいろな事をやっているんですよね。また、因子数の決め方はどうするとか、回転がどうであるとか、寄与率は、等など気にしておきたいポイントも少なくないです。計算は機械がやってくれますけど、そこから意味を見いだすのは人間の仕事なので･･･。