AI/딥러닝파이토치교과서

[ML] 3. 머신 러닝 핵심 알고리즘: 비지도학습

inthyes 2024. 3. 3. 00:22

3.2 비지도학습

비지도 학습 : 레이블이 필요하지 않으며 정답이 없는 상태에서 훈련시키는 방식

 

비지도 학습에는 군집(clustering)과 차원 축소(dimensionality reduction)가 있다.

군집은 각 데이터의 유사성(거리)을 측정한 후 유사성이 높은(거리가 짧은) 데이터끼리 집단으로 분류하는 것이다.

차원 축소는 차원을 나타내는 특성을 줄여서 데이터를 줄이는 방식이다.

 

구분 군집 차원 축소
목표 데이터 그룹화 데이터 간소화
주요 알고리즘 K-평균 군집화(K-Means) 주성분 분석(PCA)
예시 사용자의 관심사에 따라 그룹화하여 마케팅에 활용 데이터 압축
중요한 속성 도출

3.2.1 K-평균 군집화

왜 사용할까?

→ 주어진 데이터에 대한 군집화

 

언제 사용하면 좋을까?

→ 주어진 데이터셋을 이용하여 몇 개의 클러스터를 구성할지 사전에 알 수 있을 때 사용하면 유용하다.

 

K-평균 군집화는 데이터를 입력받아 소수의 그룹으로 묶는 알고리즘이다. 레이블이 없는 데이터를 입력받아 각 데이터에 레이블을 할당해서 군집화를 수행하는데, 학습 과정은 다음과 같다.

  1. 중심점 선택 : 랜덤하게 초기 중심점(centroid)을 선택한다.
  2. 클러스터 할당 : K개의 중심점과 각각의 개별 데이터 간의 거리를 측정한 후, 가장 가까운 중심점을 기준으로 데이터를 할당한다. 이 과정을 통해 클러스터가 구성된다.
  3. 새로운 중심점 선택 : 클러스터마다 새로운 중심점을 계산한다.
  4. 범위 확인(convergence) : 선택된 중심점에 더 이상의 변화가 없다면 진행을 멈춘다. 만약 계속 변화가 있다면 2~3 과정을 반복한다.

 

 

 

K-평균 군집화 이웃 실습

 

1. 라이브러리 호출

import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt

 

2. 상품에 대한 연 지출 데이터 호출

data = pd.read_csv('sales data.csv')
data.head()

 

<자료 유형>

데이터 형태 설명 예시
수치형 자료 관측된 값이 수치로 측정되는 자료 키, 몸무게, 시험 성적
연속형 자료 값이 연속적인 자료 키, 몸무게
이산형 자료 셀 수 있는 자료 자동차 사고
범주형 자료 관측 결과가 몇 개의 범주 또는 항목의 형태로 나타나는 자료 성별(남, 여), 선호도(좋다, 싫다)
순위형 자료 범주 간에 순서 의미가 있는 자료 '매우 좋다', '좋다', '그저 그렇다', '싫다', '매우 싫다' 다섯 가지 범주가 주어졌을 때, 이 범주에는 순서가 있음
명목형 자료 범주 간에 순서 없는 자료 혈액형

 

3. 연속형 데이터와 명목형 데이터로 분류

# 명목형 데이터
categorical_features = ['Channel', 'Region']
# 연속형 데이터
continuous_features = ['Fresh', 'Milk', 'Grocery', 'Frozen', 'Detergents_Paper', 'Delicassen']

for col in categorical_features:
	# 명목형 데이터는 판다스의 get_dummies() 메서드를 사용하여 숫자로 변환
  dummies = pd.get_dummies(data[col], prefix = col)
  data = pd.concat([data, dummies], axis = 1)
  data.drop(col, axis = 1, inplace = True)
data.head()

 

4. 데이터 전처리(스케일링 적용)

연속형 데이터의 모든 특성에 동일하게 중요성을 부여하기 위해 스케일링을 적용한다. 일정한 범위를 유지하도록 사이킷런의 MinMaxScaler() 메서드를 사용한다.

mms = MinMaxScaler()
mms.fit(data)
data_transformed = mms.transform(data)

 

5. 적당한 K 값 추출

거리 제곱의 합(SSD)은 가장 가까운 클러스터 중심까지 거리를 제곱한 값의 합을 구할 때 사용하며 아래 수식을 쓴다.

K가 증가하면 거리 제곱의 합은 0이 되는 경향이 있다. K를 최댓값 n으로 설정하면 각 샘플의 자체 클러스터를 형성하여 거리 제곱 합이 0과 같아지기 때문이다.

아래 출력 그래프는 클러스터 개수(x축)에 따른 거리 제곱의 합(y축)을 보여준다. K가 6부터 0에 가까워지고 있으므로 K=5 가 적정하다고 판단할 수 있다.

Sum_of_squared_distances = []
K = range(1, 15)
for k in K:
  km = KMeans(n_clusters = k)
  km = km.fit(data_transformed)
  Sum_of_squared_distances.append(km.inertia_)

plt.plot(K, Sum_of_squared_distances, 'bx-')
plt.xlabel('k')
plt.ylabel('Sum_of_squared_distances')
plt.title('Optimal k')
plt.show()

3.2.2 밀도 기반 군집 분석

왜 사용할까?

→ 주어진 데이터에 대한 군집화

 

언제 사용하면 좋을까?

→ K-평균 군집화와는 다르게 사전에 클러스터의 숫자를 알지 못할 때 사용하면 유용하다. 또한, 주어진 데이터에 이상치가 많이 포함되었을 때 사용하면 좋다.

 

밀도 기반 군집 분석(Density-Based Spatial Clustering of Applications with Noise, DBSCAN)은 일정 밀도 이상을 가진 데이터를 기준으로 군집을 형성하는 방법이다.

노이즈에 영향을 받지 않으며, K-평균 군집화에 비해 연산량은 많지만 K-평균 군집화가 잘 처리하지 못하는 오목하거나 볼록한 부분을 처리하는 데 유용하다.

 

노이즈와 이상치는 어떻게 다른가?

 · 노이즈 : 주어진 데이터셋과 무관하거나 무작위성 데이터로 전처리 과정에서 제거해야 할 부분

 · 이상치 : 관측된 데이터 범위에서 많이 벗어난 아주 작은 값이나 아주 큰 값을 의미

 

밀도 기반 군집 분석을 이용한 군집 방법은 다음 절차에 따라 진행된다.

   1단계. 엡실론 내 점 개수 확인 및 중심점 결정

   2단계. 군집 확장

   3단계. 1~2단계 반복

   4단계. 노이즈 정의


3.2.3 주성분 분석(PCA)

왜 사용할까?

→ 주어진 데이터의 간소화

 

언제 사용하면 좋을까?

→ 현재 데이터의 특성(변수)이 너무 많을 경우에는 데이터를 하나의 플롯(plot)에 시각화해서 살펴보는 것이 어렵다. 이때 특성 p개를 두세 개 정도로 압축해서 데이터를 시각화하여 살펴보고 싶을 때 유용한 알고리즘이다.

 

변수가 많은 고차원 데이터의 경우 중요하지 않은 변수로 처리해야 할 데이터양이 많아지고 성능 또한 나빠지는 경향이 있다. 이러한 문제를 해결하고자 고차원 데이터를 저차원으로 축소시켜 데이터가 가진 대표 특성만 추출한다면 성능은 좋아지고 작업도 좀 더 간편해진다. PCA는 고차원 데이터를 저차원(차원 축소)데이터로 축소시키는 알고리즘이다.

 

차원 축소 방법은 다음과 같다.   1단계. 데이터들의 분포 특성을 잘 설명하는 벡터를 두 개 선택   2단계. 벡터 두 개를 위한 적정한 가중치를 찾을 때까지 학습을 진행

 

PCA는 데이터 하나하나에 대한 성분을 분석하는 것이 아니라, 여러 데이터가 모여 하나의 분포를 이룰 때 이 분포의 주성분을 분석하는 방법이다.

 

 

밀도 기반 군집 분석 & PCA 실습

 

1. 라이브러리 호출

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# 밀도 기반 군집 분석
from sklearn.cluster import DBSCAN
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import normalize
# 데이터 차원 축소
from sklearn.decomposition import PCA

 

2. 데이터 불러오기

X = pd.read_csv('credit card.csv')
X = X.drop('CUST_ID', axis = 1)
# 결측 값을 앞의 값으로 채운다.
X.fillna(method = 'ffill', inplace = True)
print(X.head())

 

 

3. 데이터 전처리 및 데이터를 2차원으로 축소

scaler = StandardScaler()
# 평균이 0, 표준편차가 1이 되도록 데이터 크기를 조정
X_scaler = scaler.fit_transform(X)

# 데이터가 가우스 분포를 따르도록 정규화
X_normalized = normalize(X_scaler)
# 넘파이 배열을 데이터프레임으로 변환
X_normalized = pd.DataFrame(X_normalized)

# 2차원으로 차원 축소 선언
pca = PCA(n_components = 2)
# 차원 축소 적용
X_principal = pca.fit_transform(X_normalized)
X_principal = pd.DataFrame(X_principal)
X_principal.columns = ['P1','P2']
print(X_principal.head())

 

 

4. DBSCAN 모델 생성 및 결과의 시각화

db_default = DBSCAN(eps = 0.0375, min_samples = 3).fit(X_principal)
# 각 데이터 포인터에 할당된 모든 클러스터 레이블의 넘파이 배열을 labels에 저장
labels = db_default.labels_

# 출력 그래프의 색상을 위한 레이블 생성
colours = {}
colours[0] = 'y'
colours[1] = 'g'
colours[2] = 'b'
colours[-1] = 'k'

# 각 데이터 포인트에 대한 색상 벡터 생성
cvec = [colours[label] for label in labels]

r = plt.scatter(X_principal['P1'], X_principal['P2'], color = 'r')
g = plt.scatter(X_principal['P1'], X_principal['P2'], color = 'g')
b = plt.scatter(X_principal['P1'], X_principal['P2'], color = 'b')
k = plt.scatter(X_principal['P1'], X_principal['P2'], color = 'k')

plt.figure(figsize = (9,9))
# 정의된 색상 벡터에 따라 X축에 P1, Y축에 P2 플로팅(plotting)
plt.scatter(X_principal['P1'], X_principal['P2'], c = cvec)
plt.legend((r, g, b, k), ('Label 0', 'Label 1', 'Label 2', 'Label -1'))

plt.show()

 

5. 모델 튜닝

클러스터링에 대한 튜닝이 필요하기 때문에 minPts의 하이퍼파라미터를 3에서 50으로 변경한 후 수행한다.

db = DBSCAN(eps = 0.0375, min_samples = 50).fit(X_principal)
labels1 = db.labels_

colours1 = {}
colours1[0] = 'r'
colours1[1] = 'g'
colours1[2] = 'b'
colours1[3] = 'c'
colours1[4] = 'y'
colours1[5] = 'm'
colours1[-1] = 'k'

cvec = [colours1[label] for label in labels1]
colors1 = ['r','g','b','c','y','m','k']



r = plt.scatter(X_principal['P1'], X_principal['P2'], marker = 'o',color = colors1[0])
g = plt.scatter(X_principal['P1'], X_principal['P2'], marker = 'o',color = colors1[1])
b = plt.scatter(X_principal['P1'], X_principal['P2'], marker = 'o',color = colors1[2])
c = plt.scatter(X_principal['P1'], X_principal['P2'], marker = 'o',color = colors1[3])
y = plt.scatter(X_principal['P1'], X_principal['P2'], marker = 'o',color = colors1[4])
m = plt.scatter(X_principal['P1'], X_principal['P2'], marker = 'o',color = colors1[5])
k = plt.scatter(X_principal['P1'], X_principal['P2'], marker = 'o',color = colors1[6])

plt.figure(figsize = (9,9))
plt.scatter(X_principal['P1'], X_principal['P2'], c = cvec)
plt.legend((r, g, b, c, y, m, k), ('Label 0', 'Label 1', 'Label 2','Label 3', 'Label 4', 'Label 5', 'Label -1'), 
           scatterpoints = 1,
           loc = 'upper left',
           ncol = 3,
           fontsize = 8)

plt.show()

 

6. min_samples를 50에서 100으로 변경

y_predict = model.predict(X_test)
from sklearn.metrics import accuracy_score
accuracy_score(y_test, y_predict)

 

많은 클러스터 부분이 무시된 것을 확인할 수 있다. 하이퍼파라미터 영향에 따라 클러스터 결과(성능)가 달라지므로, 최적의 성능을 내려면 하이퍼파라미터를 이용한 튜닝이 중요하다.