[chap 6-3] 주성분 분석
❓ 사진 용량 차지 많아 -> 압축하는 방법 ❓
💡 해결책 💡
차원 축소
차원 축소를 통해서 데이터를 가장 잘 나타내는 일부 특성을 선택, 데이터 크기를 줄여 -> 과대적합을 막을 수 있음 = 지도 학습 모델의 성능을 향상시킬 수 있다.
손실을 최소화하면서 복원 가능
🔮 주성분 분석
데이터에 있는 분산이 큰 방향을 찾는 것. 분산이 큰 방향 = 데이터를 잘 표현하는 어떤 벡터 = 주성분 이라고 부른다.
즉, 주성분 벡터는 데이터가 어떤 방향을 가리키는지 알 수 있다. 샘플 데이터를 주성분 벡터에 직각으로 투영 -> 샘플 데이터를 주성분 벡터로 만듬.
- 주성분은 원본 차원과 같고, 주성분으로 바꾼 데이터는 차원이 줄어든다. 원본 데이터를 주성분 벡터에 투영시켰으니까,,
1️⃣ 데이터 가져오기
!wget https://bit.ly/fruits_300_data -O fruits_300.npy
import numpy as np
fruits = np.load('fruits_300.npy')
fruits_2d = fruits.reshape(-1, 100*100)
2️⃣ PCA 클래스
PCA 클래스로 주성분 분석 알고리즘을 제공한다.
📍 차원 축소 -> by n_components
from sklearn.decomposition import PCA
pca = PCA(n_components=50)
pca.fit(fruits_2d)
print(fruits_2d.shape) # (300, 10000)
print(pca.components_.shape) # (50, 10000)
- n_components : 주성분의 개수
- pca.components_ : PCA 클래스가 찾은 주성분이 저장되어 있는 속성
-> 300개의 주성분에서 50개의 주성분을 찾음
fruits_pca = pca.transform(fruits_2d)
print(fruits_pca.shape) # (300, 50)
찾은 주성분을 가지고 10000개의 특성을 50개로 줄일 수 있다. -> transform() 메소드 사용
-> 그래서 주성분은 300개로 동일한데, 특성 개수가 50개로 준 것을 확인할 수 있다.
📍 원본 데이터 재구성
위에서 특성 개수를 줄였기 때문에 정보 손실이 발생할 수 있다. 하지만 분산이 큰 방향으로 데이터를 투영했으니까 데이터를 재구성할 수 있다.
fruits_inverse = pca.inverse_transform(fruits_pca)
print(fruits_inverse.shape)
- inverse_transform() 메소드 사용
이 복원한 데이터를 가지고 데이터를 출력해보면
fruits_reconstruct = fruits_inverse.reshape(-1, 100, 100)
for start in [0, 100, 200]:
draw_fruits(fruits_reconstruct[start: start + 100])
print("\n")
와 같이 나오는 것을 확인할 수 있다. 기존 데이터보다는 조금 흐리지만 그래도 이정도면 ㄱㅊ!
📍 설명된 분산
주성분이 원본 데이터의 분산을 얼마나 잘 나타내는지 기록한 값이다. PCA 클래스의 explained_variance_ratio_ 에 각 주성분의 설명된 분산 비율이 기록되어 있다.
print(pca.explained_variance_ratio_)
>>>
[0.42357017 0.09941755 0.06577863 0.04031172 0.03416875 0.03281329
0.02573267 0.02054963 0.01372276 0.01342773 0.01152146 0.00944596
0.00878232 0.00846697 0.00693049 0.00645188 0.00578896 0.00511202
0.00486382 0.00480346 0.00447834 0.00437315 0.00408031 0.00389464
0.00372439 0.00359267 0.00331454 0.00317832 0.00304336 0.00303741
0.00288869 0.0027589 0.00264685 0.00255902 0.00252099 0.00247324
0.00239492 0.00230681 0.00221999 0.00216729 0.00213847 0.00196243
0.00191376 0.00190319 0.0018515 0.00180475 0.00173677 0.00166861
0.00159006 0.00158833]
- pca : 50개의 주성분을 만든 PCA 객체
- 출력값 : 그 50개 각각의 주성분의 설명된 분산 비율
print(np.sum(pca.explained_variance_ratio_)) #0.9214719451932281
plt.plot(pca.explained_variance_ratio_)
plt.show()
분산이 92%정도를 유지하고 있다는 말은 300개였던 주성분을 50개로 줄였는데도 비슷한 분산을 가지고 있다는 말이고 그래서 아까 데이터를 복원한 것이 원래의 데이터와 비슷하게 나온 것이다.
이 그래프에서 보면 처음 주성분 10개정도가 대부분의 분산을 표현하고 있다는 것을 알 수 있다.
❓ 그럼 여기서 특성을 더 줄이더라도 분산 비율이 어느정도 높게 나온다면 그게 더 이득인거 아닌가? -> 분산 비율은 어느 정도 유지가 되는 최소의 특성은 어떻게 구할까?
3️⃣ 다른 알고리즘과 함께 사용하기
PCA 클래스 with 로지스틱 회귀 모델 -> 축소한 데이터를 지도 학습에 적용해 보고 어떤 차이가 있는지 알아보기
-
타깃 데이터 만들기
# 타깃 데이터 만들기 from sklearn.linear_model import LogisticRegression lr = LogisticRegression() target = np.array([0]*100 + [1]*100 + [2]*100)
- 타깃 데이터 : 0 -> 파인애플, 1 -> 바나나, 2 -> 사과 (책과 조금 다르게 나옴,, 왠지는 모르겠다….)
-
fruit_2d 교차 검증
````python # 교차 검증 과정 from sklearn.model_selection import cross_validate # 교차 검증 scores = cross_validate(lr, fruits_2d, target) print(np.mean(scores[“test_score”])) print(np.mean(scores[“fit_time”]))
0.9966666666666667 2.0699679851531982
- test_score : 교차 검증의 점수 평균
- fit_time : 교차 검증 폴드의 훈련 시간 평균
- fruit_pca 교차 검증
scores = cross_validate(lr, fruits_pca, target)
print(np.mean(scores["test_score"]))
print(np.mean(scores["fit_time"]))
>>>
1.0
0.06742234230041504
차원을 줄이더라도 교차 검증 점수는 비슷하지만, 훈련 시간이 훨씬 많이 줄은 것을 확인할 수 있다.
- +a : n_components -> 설명된 분산 비율을 입력할 수 있다.
pca = PCA(n_components=0.5)
pca.fit(fruits_2d)
print(pca.n_components_)
>>> 2
주성분들 중에서 분산의 50%에 달하는 주성분을 찾았을 때, 주성분 개수가 2개였다. -> 2개의 특성을 가지고 훈련을 시켜도 10000개, 50개 특성을 가지고 훈련 시킨 것과 비슷한 결과 도출 가능
pca = PCA(n_components=0.5)
pca.fit(fruits_2d)
fruits_pca = pca.transform(fruits_2d)
scores = cross_validate(lr, fruits_pca, target)
print(np.mean(scores["test_score"]))
print(np.mean(scores["fit_time"]))
>>>
0.9933333333333334
0.04292616844177246
- 정확도 99%…2개 사용하고,,, 👍
- 훈련 결과 : 최소 특성 개수
- transform() : 차원 축소
- 교차 검증 : 축소된 데이터를 가지고 교차 검증
- 4번 과정에서의 차원이 축소된 데이터를 가지고 k-평균 알고리즘 활용
from sklearn.cluster import KMeans
km = KMeans(n_clusters=3, random_state=42)
km.fit(fruits_pca)
for label in range(0, 3):
draw_fruits(fruits[km.labels_==label])
print("\n")
- 축소된 데이터로 k-평균 알고리즘을 훈련시켜서 각 라벨에 해당하는 과일 출력
차원을 줄이면 훈련 시간도 적게 들 뿐만 아니라 3개 이하로 차원을 줄이면 화면에 출력하기도 쉽다.
for label in range(0, 3):
data = fruits_pca[km.labels_==label]
plt.scatter(data[:, 0], data[:, 1])
plt.legend(['pineapple', 'banana', 'apple'])
plt.show()
- 출력 결과 : 클러스터별로 나누어 산점도를 그림
결론적으로 로지스틱 회귀 모델을 사용해서도 성능 평가 가능, 차원 줄여서 kMeans를 통해서 데이터 출력 가능, 3차원 이하면 화면에 출력하기 쉬움.
댓글남기기