본문 바로가기
머신러닝

머신러닝 - 차원 축소와 PCA (3)

by Tiabet 2023. 4. 15.

이번 포스팅은 PCA에 관한 마지막 포스팅으로, PCA를 통해 분류를 해보도록 하겠다.

 

그리고 깜빡하고 저번 포스팅에도 명시를 하지 않은 것 같은데, 포스팅에서 다루는 내용의 출처는 수업시간에 배우는 소위 도마뱀책이라고 불리는 hands-on machine learning 이라는 책이다. 그리고 코드의 출처 또한 책과 이어지는 Github 이다.

 

https://github.com/tuitet/Hands-On-Machine-Learning-with-Scikit-Learn-Keras-and-TensorFlow-3rd-Edition

 

GitHub - tuitet/Hands-On-Machine-Learning-with-Scikit-Learn-Keras-and-TensorFlow-3rd-Edition: A series of Jupyter notebooks that

A series of Jupyter notebooks that walk you through the fundamentals of Machine Learning and Deep Learning in Python using Scikit-Learn, Keras and TensorFlow 2. - GitHub - tuitet/Hands-On-Machine-L...

github.com

 

데이터셋 로드

import pandas as pd

WineData = pd.read_csv('wineTraining.csv')
WineData.head(n=6)

WineDataQuality = WineData['Wine']
print(WineDataQuality)

WineInput = WineData.loc[:, ~WineData.columns.isin(['Wine'])]
WineInput

위와 같은 코드를 실행해 wineTraining.csv 파일을 로드해준다.

우선 WineData를 확인해보면 아래와 같다.

Wine 이라는 column에 1, 2, 3 으로 와인의 등급을 알려주고 있고, 나머지 칼럼들은 와인의 성분 정도라고 이해하면 된다. 우리가 현재 하고자 하는 작업은 새로운 테스트셋이 들어왔을 때, 그 와인의 등급을 결정하는 일이다. 따라서 Wine이 독립변수, 나머지가 종속변수가 된다. 그래서 이를 WineDataQuality, WineInput 으로 나눠준 것이다.

 

Scaling 진행

from sklearn.preprocessing import StandardScaler
x = WineInput.values
stdscalar = StandardScaler()
stdscalar.fit(x)
x = stdscalar.transform(x)
print(pd.DataFrame(x).head())

머신러닝에서 중요한 작업 중 하나인 Scaling을 진행한다. 독립변수에는 진행할 필요가 없고 종속변수들의 집합인 WineInput에만 진행하고, 이를 x에다 저장했다.

 

feat_cols = ['feature'+str(i) for i in range(x.shape[1])]
normalised_WineInput = pd.DataFrame(x,columns=feat_cols)
normalised_WineInput.head()

normalised_WineInput 이라는 새로운 데이터프레임을 생성했고 column_name은 의미가 없으니 feature로 바꿔주었다. 총 13개의 column이 있음을 확인할 수 있다. (PC13까지 생성 가능할 것)

 

Principal Component 추출

from sklearn.decomposition import PCA

pca_wine = PCA(n_components=2)
print(pca_wine.fit(x))
principalComponents_Wine = pca_wine.transform(x)

principal_wine_Df = pd.DataFrame(data=principalComponents_Wine, columns=['principal component 1', 'principal component 2'])
print(principal_wine_Df)

#print(pca_wine.explained_variance_ratio_)

PCA를 import 해서 주성분을 추출한다. 우선 주성분은 2개로 진행하는데, 확인해보니 데이터셋의 특징이 그렇게 좋은 거 같진 않아서 주성분을 늘려봐도 분산의 설명력이 엄청 높지는 않았다. 마지막에 주석처리한 부분을 실행해보면 약 55% 정도 설명가능한 것으로 보이는데, 3개, 4개로 늘려봐도 90%에 한참 못 미쳐서 그냥 2개로 진행한 것 같다.

아무튼 trasform 까지 했으므로 아래처럼 Scoring Vector를  얻을 수 있다.

시각화

plt.figure()
plt.figure(figsize=(10,10))
plt.xticks(fontsize=12)
plt.yticks(fontsize=14)
plt.xlabel('Principal Component - 1',fontsize=20)
plt.ylabel('Principal Component - 2',fontsize=20)
plt.title("Principal Component Analysis of Wine Dataset",fontsize=20)

targets = list(np.unique(WineDataQuality))
colors = ['r', 'g', 'b']
for target, color in zip(targets, colors):
    indicesToKeep = (WineDataQuality == target)
    plt.scatter(principal_wine_Df.loc[indicesToKeep, 'principal component 1'], principal_wine_Df.loc[indicesToKeep, 'principal component 2'], c=color, s=50)

plt.legend(targets, prop={'size': 15})

시각화를 통해 새롭게 추출된 데이터셋을 확인해보는 과정이다.  WineQaulity가 1, 2, 3 총 3개이므로 colors도 이에 맞춰서 r, g, b 로 맞춰주었음을 볼 수 있다.

살짝 경계가 흐릿하긴 해도 어느 정도 분류가 잘 되었음이 보인다. 원래 데이터셋이 13차원이었음을 감안하면 이정도면 굉장히 좋은 성과라고 할 수 있다.

 

from sklearn.cluster import KMeans

kmeans = KMeans(n_clusters=3).fit(principal_wine_Df)
groups = np.unique ( kmeans.labels_)
for group, color in zip(groups, colors):
    indicesToKeep = (kmeans.labels_ == group)
    plt.scatter(principal_wine_Df.loc[indicesToKeep, 'principal component 1']
               , principal_wine_Df.loc[indicesToKeep, 'principal component 2'], c = color, s = 50)

plt.legend(targets,prop={'size': 15})

책에서는 이렇게 Kmean를 활용하여 클러스터링까지 진행하는데, 굉장히 간단하게 진행할 수 있어서 놀랐다.

 

새롭게 들어오는 와인들 분류하기

WineTestData = pd.read_csv('wineTesting.csv')
print(WineTestData)

WineTestDataQuality = WineTestData['Wine']
WineTestInput = WineTestData.loc[:, ~WineTestData.columns.isin(['Wine'])]
print(WineTestInput)

Quality가 들어있지 않은 Test셋을 불러와서 직접 분류를 해보는 작업이다.

 

newPCAscores = pca_wine.transform( stdscalar.transform(WineTestInput) )
print(newPCAscores )

Train셋에서 만들었던 Weight vector에다가 새롭게 들어온 Test셋의 데이터를 scaling 진행하여 사영시켜 새로운 Scoring Vector를 얻을 수 있다. 여기서 주의해야 하는 것은 Test셋의 Scoring Vector들은 서로 수직이 아니다. Weight Vector가 Test셋의 것이 아닌 Train셋의 것이기 때문이다.

plt.figure()
plt.figure(figsize=(10,10))
plt.xticks(fontsize=12)
plt.yticks(fontsize=14)
plt.xlabel('Principal Component - 1',fontsize=20)
plt.ylabel('Principal Component - 2',fontsize=20)
plt.title("Principal Component Analysis of Wine Dataset",fontsize=20)
targets = list(np.unique (WineDataQuality))
colors = ['r', 'g', 'b']
for target, color in zip(targets, colors):
    indicesToKeep = (WineDataQuality == target)
    plt.scatter(principal_wine_Df.loc[indicesToKeep, 'principal component 1']
               , principal_wine_Df.loc[indicesToKeep, 'principal component 2'], c = color, s = 50)

plt.legend(targets,prop={'size': 15})

plt.scatter(newPCAscores[0,0], newPCAscores[0,1], marker='>', c='y', s=300 )
plt.scatter(newPCAscores[1,0], newPCAscores[1,1], marker='<', c='b', s=300 )

마찬가지로 시각화를 진행해보면, 아래와 같은 그림을 얻을 수 있다.

확인 결과 첫 번째 와인은 퀄리티 1로, 두 번째 와인은 퀄리티 2로 분류할 수 있을 것 같다.

 

 

이렇게 이번 포스팅에서는 PCA로 데이터를 분류해보는 작업을 진행해보았다.