2021. 5. 21. 22:10ㆍMachine Learning
준지도 학습이란 비지도 학습과 지도 학습에 중간 단계에 있는 학습 방법으로
레이블된 샘플의 수가 그렇지 않은 샘플 수에 비해 적을 경우 사용한다.
준지도 학습을 실습을 통해 알아보겠다.
X_digits, y_digits = load_digits(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X_digits, y_digits)
먼저 digit 데이터를 호출하고 훈련 세트와 테스트 세트로 나눠준다.
n_labled = 50
log_reg = LogisticRegression()
log_reg.fit(X_train[:n_labled], y_train[:n_labled])
print(log_reg.score(X_test, y_test))
result:
0.8488888888888889
그 다음 전체 훈련 세트에서 일부(50개)만 로지스틱 회귀를 통해 훈련시킨 결과, 84%의 정확도를 나타낸다.
이를 향상시키기 위해 Kmean 클러스터를 이용해보자.
from sklearn.cluster import KMeans
k = 50
kmeans = KMeans(n_clusters=k)
X_digits_dist = kmeans.fit_transform(X_train) #(1347, 50)
representative_digit_idx = np.argmin(X_digits_dist, axis=0) #(50,)
X_representative_digits = X_train[representative_digit_idx]
kmean 클러스터링을 위해 전체 훈련 세트를 50개의 클러스터로 나누어 변환한 뒤 X_digits_dist에 저장한다.
64차원의 1347개의 샘플을 가지고 있던 훈련세트가 샘플 당 50차원으로 줄어들었다.
넘파이의 argmin 함수를 통해 각 세로축에서 가장 작은 값(의 인덱스)을 찾는다.
Kmean 클러스터는 데이터를 50개의 클러스터로 나누었는데, 각 클러스터 별로 가장 거리가 가까운 샘플이
센트로이드일 것이다. 훈련세트에서 이 인덱스에 해당하는 샘플이 대표샘플로 처리된다.
print(X_digits_dist.shape)
print(X_representative_digits.shape)
results :
(1347, 50)
(50, 64)
대표 샘플로 뽑힌 데이터를 출력해보자.
plt.figure(figsize=(20,10))
for idx in range(50):
plt.subplot(5,10,idx+1)
plt.imshow(X_representative_digits[idx].reshape(8,8), 'gray')
plt.axis('off')
plt.show()
이 샘플들이 Kmean 클러스터링 과정에서 센트로이드로 선정된 샘플들이다. 이 외의 샘플들은 이 센트로이드를 중심으로
클러스터링이 이뤄졌다.
y_representive_digits = np.array([8, 8, 9, 6, 0, 7, 4, 2, 5, 9, 0, 6, 7, 2, 3, 4, 8, 9, 6, 1, 5, 8,
8, 3, 3, 5, 2, 4, 2, 1, 7, 1, 0, 1, 4, 5, 1, 1, 7, 0, 7, 9, 2, 4,
6, 5, 9, 1, 7, 3])
추출한 이미지를 바탕으로 수동으로 레이블을 부여하였다.
log_reg = LogisticRegression()
log_reg.fit(X_representative_digits, y_representative_digits)
log_reg.score(X_test,y_test)
result:
0.9066666666666666
확실히 일부 50개의 샘플로만 훈련시킨 로지스틱 모델보다는 대표 샘플로만 훈련시킨 모델이 더 정확도가 높다.
일부에 레이블을 할당하는 방법을 취할 때는 이와 같이 대표 샘플에 할당하는 것이 좋은 방법이다.
이 수동으로 부여한 레이블을 같은 클러스터 속한 샘플들에게 전파하도록 하겠다. 이를 레이블 전파라고 한다.
y_train_propagated = np.empty(len(X_train), dtype=np.int32)
for i in range(k):
y_train_propagated[kmeans.labels_ == i] = y_representative_digits[i]
전체 훈련 세트에서 kmean이 부여한 레이블(50개 클러스터 중 하나)이 0 ~ 49까지 각각에 해당하는 샘플들의 타깃값에
우리가 수동으로 부여한 레이블을 주입한다.
log_reg = LogisticRegression()
log_reg.fit(X_train, y_train_propagated)
log_reg.score(X_test, y_test)
result:
0.9333333333333333333
레이블 전파 후 평가한 점수가 대표 샘플들로만 훈련시킨 점수보다 높다.
센트로이드로 모여든 샘플들 중 잘못 분류된 샘플들도 있겠지만, 훈련시킬 샘플 수가 1347개로
증가했기 때문에 정확도가 더 증가했다. (양질 전환의 법칙 - 헤겔)
하지만 클러스터에 속한 샘플 센트로이드와 가장 멀리 떨어진 샘플들은 잘못 분류될 가능성이 높은데
이 샘플들을 배제하고 훈련시킨다면 더 정확도가 올라가지 않을까?
percentile_closest = 20
X_cluster_dist = X_digits_dist[np.arange(len(X_train)), kmeans.labels_]
#(1347,)
먼저 50차원으로 축소된 데이터에서 각 샘플별로 kmean 객체가 레이블링한 값(센트로이드의 인덱스)를 추출한다.
for i in range(k):
in_cluster = (kmeans.labels_ == i)
cluster_dist = X_cluster_dist[in_cluster]
cutoff_distance = np.percentile(cluster_dist, percentile_clostest)
above_cutoff = (X_cluster_dist > cutoff_distance)
X_cluster_dist[in_cluster & above_cutoff] = -1
모든 센트로이드의 인덱스에 대해서 i번째 센트로이드로 분류된 샘플을 추출하고, 여기서 상위 20퍼센트의 값을 추출한다.
(애초에 50차원으로 축소된 데이터인 X_digits_dist는 각 차원(대표 샘플이라 생각해도 좋다)별 거리를 나타냈기 때문이다)
X_cluster_dist에서 이 상위 20%의 값보다 큰 값을 가진(다시말해 센트로이드와 더 멀 경우) 샘플 인덱스를 추출하고
X_cluster_dist 값을 -1로 변경한다.
partially_propagated = (X_cluster_dist != -1)
X_train_partially_propagated = X_train[partially_propagated]
y_train_partially_propagated = y_train_propagated[partially_propagated]
이렇게 각 클러스터 별로 상위 20%로 가까운 샘플들의 인덱스만 살려두고 이를 전파된 타깃값에도 동일한 논리를 적용한다.
log_reg = LogisticRegression()
log_reg.fit(X_train_pratially_propagated, y_train_partially_propagated)
log_reg.score(X_test, y_test)
result:
0.94
'Machine Learning' 카테고리의 다른 글
9-4. 군집(Clustering) - DBSCAN (0) | 2021.05.23 |
---|---|
9-2. 군집(Clustering) - K평균 클러스터링(2) (0) | 2021.05.20 |
9-1. 군집(Clustering) - K평균 클러스터링(1) (0) | 2021.05.20 |
8-2. PCA(Principal Component Analysis) (1) | 2021.05.12 |
8-1. 차원 축소(Dimensionality Reduction) (0) | 2021.05.12 |