비지도 학습은 비슷한 패턴을 가진 것끼리 묶는 게 목적인데 묶인 군집을 분석하는 방법이 두 가지가 있음
방법 : k-means, DBSCAN
평균을 k개 사용하는 알고리즘으로 k는 군집의 개수
1> 그룹의 중심 점(mean)이 무작위로 선택됨
2> 임의로 선택된 중심 점과 각 점 간의 거리를 계산해서 가장 가까운 중심점의 그룹(군집)으로 선택됨
3> 선택된 그룹의 점들을 기준으로 중심점을 계산해서 찾음
4> 2, 3을 반복
# k means 학습
model = KMeans(n_clusters= 2, n_init = 'auto')
model.fit(x)
# 예측
pred = model.predict(x)
print(pred)
# 데이터프레임 만들기(x1, x2, predicted, shape)
pred = pd.DataFrame(pred, columns = ['predicted'])
result = pd.concat([x, pred, y], axis = 1)
result.head()
# k means 모델로 부터 클러스터의 평균 값들을 가져올 수 있습니다.
centers = pd.DataFrame(model.cluster_centers_, columns=['x1','x2'])
# 시각화
plt.figure(figsize = (8,6))
plt.scatter(result['x1'], result['x2'], c = result['predicted'], alpha=0.5)
plt.scatter(centers['x1'], centers['x2'], s=50, marker='D', c='r')
plt.show()
inertia value
군집화 후 각 중심점에서 군집의 데이터 간 거리를 합산한 값(k가 전체 데이터 개수라면 중심점이 데이터 위에 위치하므로 inertia value=0) 즉, k가 커질수록 작아짐
k값 찾는 방법
클러스터의 개수(k)를 증가시키면서 inertia value를 뽑고 시각화하여 elbow method에서 적정 k값 찾기
단점 : 볼록한 형태에서만 군집 형성이 잘 됨
=> 보완 : DBSCAN
스마일 쿠키 모양을 k-mean는 나누지 못하지만 DBSCAN은 얼굴과 눈코입을 각각 따로 구분할 수 있다
1> 임의의 한 점으로부터 시작
2> 반경 범위 내에 최소 포인트 수가 존재하는 지 확인
3> 존재한다면 각 포인트를 중심으로 다시 원을 그려 최소 포인트 수 확인
4> 2, 3 반복 수행
5> 존재하지 않으면 군집에 포함되지 않은 점으로 이동하여 1~4 반복 수행
6> 어느 군집에도 포함되지 않는 점은 이상치로 간주
각 점 + 근처 n개의 점과의 평균 거리 계산
거리 순으로 정렬하여 그래프 그리기
급격히 멀어지기 시작하는 거리 구간을 eps로 적용
elbow method 찾기
# DBSCAN 모델을 만들어 봅시다.
model = DBSCAN(eps=0.1, min_samples=3)
model.fit(x)
# fitting한 후에 모델의 labels_ 값이 찾아낸 군집 종류입니다.
clusters = model.labels_
# 군집 번호 중 -1은 이상치를 의미합니다.(어느 군집에도 포함 안되는 값들!)
clusters # 0부터 12까지 13개의 군집을 만든 것)
plt.figure(figsize = (8, 6))
plt.scatter(x['x1'], x['x2'], c=clusters, alpha=0.5)
plt.show()
def dbscan_plot(x, y, eps) :
model = DBSCAN(eps=eps, min_samples=3)
model.fit(x)
clusters = model.labels_
plt.figure(figsize = (8,6))
plt.scatter(x['x1'], x['x2'], c=clusters, alpha=0.5)
plt.grid()
plt.show()
# 각점과 근처 3개 점과의 평균 거리
# NearestNeighbors은 거리계산할 때, 자기 자신을 포함하므로 n+1
n = 3
knnDist = NearestNeighbors(n_neighbors = n+1).fit(x)
distances, _ = knnDist.kneighbors(x)
# 평균 거리 계산
dist = np.mean(distances[:,1:], axis = 1)
# 정렬
dist = np.sort(dist)
# 그래프 그리기
plt.figure(figsize = (8,6))
plt.plot(dist)
plt.grid()
plt.show()
# 찾아낸 eps 값을 대입시켜 봅시다.
epsilon = 0.13
dbscan_plot(x,y, eps = epsilon)