回転行列による線形変換で、観測データの相関をなくす。
また、アヤメデータセット(iris dataset)の花びら(peatal)データに対して無相関化を行い、オリジナルデータとスコアがどう変わるかモデリングして比較する。
手順:
線形変換の方法については以下で復習
https://www.dropbox.com/s/kyq2j8hb7ijagk4/liner_transformation.pdf?dl=0
参考サイト:
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn import metrics
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
# load data
data = load_iris()
data.keys()
print(data.DESCR)
# transform data to dataframe
x = pd.DataFrame(data=data.data, columns=data.feature_names)
x.head()
# 従属変数の取り出し
target = data.target
# petal関連データ取り出し
petal_data = x[['petal length (cm)', 'petal width (cm)']].copy()
petal_data.head()
petal_data.corr()
petal length と petal width の相関が0.96あるが、その相関を0になるように線形変換する。
変数間のスケールに違いがそんなに無いので、省略
(標準化してあるデータの場合は、相関行列になる)
cov = petal_data.cov()
cov
2.で求めた共分散行列の固有ベクトルを求める
eigenvalue, eigenvector = np.linalg.eig(cov)
eigenvector
eigenvalue
# 回転行列の作成
rotation_matrix = np.matrix(eigenvector)
rotation_matrix
petal_data.head()
固有ベクトルにより作った行列が新しい基底となる。なので、新しい基底により線形変換するには、元のベクトルに新しい基底の逆行列をかければよい
np.linalg.inv(rotation_matrix)
# 線形変換関数の作成
def liner_transform(rows, rotation_matrix):
'''
・rows:データフレームの1レコード
・rotation_matrix : 固有ベクトルを並べた行列(np.matrix)
return : 線形変換後のベクトル(np.array)
'''
# データフレームをnp.array化
vectors = rows.to_numpy()
# 線形変換:固有ベクトルを並べた行列の逆行列×対象ベクトル
matrix_result = np.linalg.inv(rotation_matrix).dot(vectors) # resultの中身は、np.matrix
array_result = np.array(matrix_result.tolist()[0])
return array_result
# データを線形変換する。
lt_data = petal_data.apply(liner_transform, rotation_matrix=rotation_matrix, axis=1)
lt_data[:10]
# dataframeに変換
lt_petal_data = pd.DataFrame(data=lt_data, columns=['lt_data'])
lt_petal_data['lt_petal_lenght'] = lt_petal_data.lt_data.apply(lambda x: x[0])
lt_petal_data['lt_petal_width'] = lt_petal_data.lt_data.apply(lambda x: x[1])
lt_petal_data.drop(columns='lt_data', inplace=True)
lt_petal_data.head()
lt_petal_data.corr()
2変数間の相関が0になっている。
# 無相関化前のpetal length と petal width の分布図描画用データ
petal_data['target'] = target
Setosa_data = petal_data[petal_data.target == 0][['petal length (cm)', 'petal width (cm)']]
Versicolour_data = petal_data[petal_data.target == 1][['petal length (cm)', 'petal width (cm)']]
Virginica_data = petal_data[petal_data.target == 2][['petal length (cm)', 'petal width (cm)']]
# 無相関化後のpetal length と petal width の分布図描画用データ
lt_petal_data['target'] = target
lt_Setosa_data = lt_petal_data[lt_petal_data.target == 0][['lt_petal_lenght', 'lt_petal_width']]
lt_Versicolour_data = lt_petal_data[lt_petal_data.target == 1][['lt_petal_lenght', 'lt_petal_width']]
lt_Virginica_data = lt_petal_data[lt_petal_data.target == 2][['lt_petal_lenght', 'lt_petal_width']]
# 散布図で分布状況を比較
fig = plt.figure(figsize=(18,5))
# 無相関化前の分布
ax1 = fig.add_subplot(1,2,1)
ax1.set_xlim(0, 8)
ax1.set_ylim(-1, 4)
ax1.set_title('plot of original data')
ax1.set_xlabel('petal length')
ax1.set_ylabel('petal width')
ax1.grid(True)
ax1.scatter(Setosa_data['petal length (cm)'], Setosa_data['petal width (cm)'], s=50, c='b',
marker='o', label='Setosa', alpha=0.5)
ax1.scatter(Versicolour_data['petal length (cm)'], Versicolour_data['petal width (cm)'], s=50,
c='r', marker='D', label='Versicolour', alpha=0.5)
ax1.scatter(Virginica_data['petal length (cm)'], Virginica_data['petal width (cm)'], s=50,
c='g', marker='s', label='Virginica', alpha=0.5)
ax1.legend(loc='upper left', fontsize=14)
# 無相関化後の分布
ax2 = fig.add_subplot(1,2,2)
ax2.set_xlim(0, 8)
ax2.set_ylim(-2, 3)
ax2.set_title('plot of liner transformed data')
ax2.set_xlabel('petal length')
ax2.set_ylabel('petal width')
ax2.grid(True)
ax2.scatter(lt_Setosa_data.lt_petal_lenght, lt_Setosa_data.lt_petal_width, s=50, c='b',
marker='o', label='Setosa', alpha=0.5)
ax2.scatter(lt_Versicolour_data.lt_petal_lenght, lt_Versicolour_data.lt_petal_width, s=50,
c='r', marker='D', label='Versicolour', alpha=0.5)
ax2.scatter(lt_Virginica_data.lt_petal_lenght, lt_Virginica_data.lt_petal_width, s=50,
c='g', marker='s', label='Virginica', alpha=0.5)
ax2.legend(loc='upper left', fontsize=14)
plt.show()
右側のグラフを見ると、2変数間の相関が無くなっているのがわかる。
無相関化前と後のpetal_lengthとpetal_widthのデータからロジスティック回帰で多クラス分類を行い、スコアを比較する
x_train, x_test ,y_train, y_test = train_test_split(petal_data[['petal length (cm)', 'petal width (cm)']],
petal_data['target'],
test_size=0.4,
random_state=0,
stratify=petal_data['target'])
logreg = LogisticRegression()
logreg.fit(x_train, y_train)
y_pred = logreg.predict(x_test)
print(metrics.accuracy_score(y_test, y_pred))
x_train, x_test ,y_train, y_test = train_test_split(lt_petal_data[['lt_petal_lenght', 'lt_petal_width']],
lt_petal_data['target'],
test_size=0.4,
random_state=0,
stratify=lt_petal_data['target'])
logreg = LogisticRegression()
logreg.fit(x_train, y_train)
y_pred = logreg.predict(x_test)
print(metrics.accuracy_score(y_test, y_pred))
スコアは同じだった。住宅価格の予想問題で相関が高い変数が多かったので、そこで使って結果を比較してみる。