[HO-ML] 9. 비지도학습
in Data Science on Machine Learning
요즘 개발되는 대부분의 머신러닝 APP이 지도학습 기반.
하지만 우리가 가지고있는 일반적인 데이터를 생각해보자.. 대부분 라벨(정답)이 존재하지 않음. 보통 사람이 이를 모두 수동으로 라벨링해야함. → 시간과 비용이 많이든다
라벨이 없는 데이터를 바로 사용할수있는 알고리즘은 없을까? → 비지도학습의 등장.
저자는 비지도학습을 ‘케이크의 빵’ 이라는 말을 인용하며 비지도학습의 잠재력을 강조함.
- 군집 (Clustering) : 비슷한 샘플을 Cluster(군집,무리)로 모음.
- 이상치 탐지 (Outlier detection, Anomaly Detection) : ‘정상’ 데이터를 학습하여 비정상 샘플을 감지함 ex. 제조라인에서 결함제품 감지.
- 밀도추정 (Density estimation) : 데이터셋 생성 확률 과정의 확률 밀도 함수(PDF)를 추정. 보통 밀도가 매우 낮은 영역에 놓인 샘플이 outlier일 가능성이 높음. 데이터 분석/시각화에도 유용.
9.1 군집
비슷한 샘플을 구별해 하나의 클러스터(비슷한 샘플의 그룹)으로 할당하는 작업을 ‘군집화(Clustering)’라고 한다.
9.1.0 분류 vs 군집
이 붓꽃 데이터는 라벨링이 되어있어서 분류알고리즘이 더 굳.. (왼쪽처럼 시각화도가능)
만약 라벨이 없다면? 오른쪽처럼만 표기 가능. 그래도 2개 클러스터로 나뉜다는것은 식별이 가능.
군집은 다음과 같은 다양한 어플리케이션에서 사용됨
- 데이터분석
- 차원축소 : 데이터셋에 군집 알고리즘 적용 후 클러스터에 대한 샘플의 친화성을 측정. k개 클러스터가 있으면 각 클러스터에 대한 친화성을 각 벡터의 요소로해서 k차원 벡터로 만들어 차원축소.
- 이상치탐지 : 모든 클러스터에 대한 친화성이 낮은 샘플을 이상치(Outlier)로 봄. 결함감지, 부정거래감지에 활용가능.
- 준지도학습 : 라벨링된 샘플이 적으면 Clustering을 수행하여 동일 클러스터 내에 있는 샘플에 라벨을 전파.
- 고객분류 : 고객의 구매이력/행동 로그 등을 기반으로 클러스터링 가능. 동일 클러스터 내의 사용자가 좋아하는 컨텐츠를 추천하는 방법으로 추천시스템을 만들수있음
- 검색엔진 : 제시된 이미지와 비슷한 이미지를 찾아줌. (비슷한 이미지를 동일 클러스터에 묶어놓고 사용자가 찾으려는 이미지를 제공하면 훈련된 군집 모델을 이용하여 클러스터를 찾아 그 클러스터의 이미지를 반환)
- 이미지 분할 : 색을 기반으로 픽셀을 클러스터로 모음. 그 픽셀의 색을 클러스터 평균색으로 바꿈. 이미지의 색상 종류가 줄어듬. → 물체의 윤곽 감지가 쉬워짐 → 물체탐지(Object Detection) 및 추적 시스템(Tracing System)
클러스터에 대한 보편적인 정의? 없다. 알고리즘에 따라 다름.
9.1.1 k-평균 (k-means clustering)
각 클러스터의 중심(centroid, 센트로이드)을 찾고 가장 가까운 클러스터에 샘플을 할당.
- 최초에 임의의 점 k개를 중심점으로 지정
- 각 데이터를 k 개의 점과 비교하여 가장 가까운 점이 있는 쪽으로 분류
- 모든 데이터를 k개 그룹으로 분류하고 나면, 각 그룹의 중심점을 계산.
- 이전 단계에서 계산한 k 개의 중심점을 이용해서 2), 3) 단계를 반복. 이때 3) 단계에서 갱신한 k개의 중심점이 이전 과정에서 사용한 중심듬들과 차이거 없거나 미리 정한 수준 이하로만 변하면 과정을 종료
훈련과 예측
랜덤으로 데이터를 만든다음에 한번 예측해보자
단 2줄로 예측가능
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=5, random_state=42)
y_pred = kmeans.fit_predict(X)
결정경계
보로노이 다이어그램 : 특정 점(센트로이드)까지의 거리가 가장 가까운 점의 집합으로 분할한 그림
하드군집 vs 소프트군집
하드군집 :각 샘플에 대해 가장 가까운 클러스터를 선택. 샘플에서 각 센트로이드까지의 거리를 측정한 뒤 가장 가까운 클러스터의 번호로 라벨링함
소프트군집 : 각 클러스터에 대한 샘플의 유사도점수(혹은 거리, 혹은 친화성점수)를 나타낸 행렬을 사용. → k개 클러스터가 있을경우, k차원 데이터셋이 만들어짐. → 효율적인 비선형 차원축소기법의 일종
kmeans.transform(x)
array([2.88633901, 0.32995317, 2.9042344 , 1.49439034, 2.81093633])
k-평균 알고리즘
- 먼저 𝑘 개의 센트로이드를 랜덤하게 초기화합니다: 데이터셋에서 𝑘 개의 샘플을 랜덤하게 선택하고 센트로이드를 그 위치에 놓습니다.
- 수렴할 때까지 다음을 반복합니다(즉, 센트로이드가 더이상 이동하지 않을 때까지)
- 각 샘플을 가장 가까운 센트로이드에 할당합니다.
- 센트로이드에 할당된 샘플의 평균으로 센트로이드를 업데이트합니다.
k-평균의 변동성
센트로이드 랜덤초기화 후 점점 옮겨가면서 개선시키는 모양새.
따라서 초기 센트로이드가 구리면 아래와 같이 클러스터링이 망할수도있다..
센트로이드 초기화 방법
1) 만약 내가 좋은 센트로이드 위치를 알고있다면, 매개변수로 좋은 센트로이드 배열을 넘겨주고 n_init=1로 설정해주면됨
good_init = np.array([[-3,3], [-3,-2], [-3,1], [-1,2],[0,2]])
kmeans = KMeans(n_clusters=5, init=good_init, n_init=1)
2) 랜덤 초기화를 다르게하여 여러번 클러스터링 해보고, 그중에 제일 좋은솔루션을 선택. (like GridSearch) 초기화 횟수는 n_init 매개변수로 조절.
이너셔
최선의 솔루션이 뭔데? → 샘플과 센트로이드 사이의 거리(이너셔)를 측정해서 제일 가까운 애를 찾자.
kmeans.inertia_
kmeans.score(X)
다중초기화
kmeans_rnd_10_inits = KMeans(n_clusters=5, init="random", n_init=10,
algorithm="full", random_state=11)
kmeans_rnd_10_inits.fit(X)
K-평균++
걍 센트로이드를 걍 랜덤초기화하는게 아니라 다음 센트로이드를 선택할때 확률적으로 더 멀리 떨어진 샘플을 선택하도록 하는것. sklearn에서는 default로 K-means++ 알고리즘을 사용하여 초기화하고있으므로 신경안써도된다.
K-평균 속도개선
k-means 알고리즘을 보면 거리계산을 엄청 많이함. 이때 삼각부등식(두 점 사이 직선은 항상 가장 짧은거리가됨)을 사용하면 불필요한 속도계산을 줄일 수 있음. algorithm="elkan"
매개변수를 넣으면되는데 마찬가지로 default가 elkan이므로 신경안써도됨.
미니배치 k-평균
데이터셋이 너무 큰경우 미니배치(데이터 쪼개서 점진적으로 학습하는거) 사용해서 학습할 수 있다.
최적의 클러스터 갯수 찾기
사람은 딱 보면 5개가 최적이겠거니 알지만.. 컴퓨터는 알수없음
이너셔로 최적의 k 를 판단해보면 어떨까? → 이너셔는 클러스터 갯수(k)가 증가할수록 무조건 줄어들어서 단순히 이너셔가 작은 k 가 최적은 아님..
엘보 지점인 k=4 가 그나마 좋은선택임.
실루엣점수
실루엣점수라는게있다..
실루엣점수 = 모든 샘플에 대한 실루엣계수의 평균
$(b-a)/max(a,b)$
$a$ = 클러스터 내부의 평균 거리
$b$ = 가장 가까운 클러스터까지의 평균거리
- 1에 가까울수록 자신의 클러스터 안에 잘 속해 있고 다른 클러스터와는 멀리 떨어져있음
- 0에 가까우면 클러스터 경계에 위치한다는 뜻
- -1에 가까우면 샘플이 잘못된 클러스터에 할당되어있다는 뜻
from sklearn.metrics import silhouette_score
silhouette_score(X, kmeans.labels_)
실루엣점수를 그래프로 그려보니 k=4도 괜찮고 k=5도 나쁘지않음을 알수있음
실루엣 다이어그램
- 높이 : 클러스터가 포함한 샘플의 갯수
- 너비 : 클러스터에 포함된 샘플의 정렬된 실루엣계수 (넓을수록 good)
- 수직파선 : 클러스터 갯수에 해당하는 실루엣점수. 얘보다 낮은 클러스터가 있으면 그 클러스터는 나쁜클러스터.
9.1.2 k-평균의 한계
장점 : 속도가 빠름. 확장이 용이.
단점 : 클러스터의 크기나 밀집도가 서로 다르거나, 클러스터 모양이 원형이 아니면 잘 작동하지않음.
(왼쪽은 그나마 강제로 좋은 시작점 지정해주고 했을때. / 오른쪽은 흐름에 맡겼을때. 잘 구분을 못함)
9.1.3 군집을 사용한 이미지분할
이미지분할 : 이미지를 여러 segment 로 분할하는 작업.
시맨틱 분할(semantic segmentation) : 동일한 종류의 물체에 속한 픽셀을 같은 segment에 할당. = 일종의 object detection
즉 segment=cluster로 이해..
보통은 deep learning을 사용하나 군집화해서도 이미지분할 가능.
색상분할
동일한 색상을 가진 픽셀을 같은 세그먼트에 할당 ex. 인공위선사진을 분석해 산림면적을 계산
from matplotlib.image import imread
image = imread(os.path.join(images_path, filename))
X = image.reshape(-1, 3)
kmeans = KMeans(n_clusters=8, random_state=42).fit(X)
9.1.4 군집을 사용한 전처리
군집은 차원축소에 효과적인방법. cf. 소프트 군집
그런 특징을 생각해보면, 지도학습 알고리즘 적용 전에 전처리 단계로 사용할수있다.
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.cluster import KMeans
X_digits, y_digits = load_digits(return_X_y=True) # MNIST같은 데이터셋
X_train, X_test, y_train, y_test = train_test_split(X_digits, y_digits, random_state=42)
pipeline = Pipeline([
("kmeans", KMeans(n_clusters=50, random_state=42)),
("log_reg", LogisticRegression(multi_class="ovr", solver="lbfgs", max_iter=5000, random_state=42)),
])
pipeline.fit(X_train, y_train)
pipeline.score(X_test, y_test)
훈련세트를 50개의 클러스터로 모은 뒤, input(X)를 각 클러스터까지의 거리로 바꿈. 그 다음에 로지스틱 회귀 모델을 적용.
결과 > 오차율이 28%나 줄어든다. (0.969 → 0.978)
근데 k=50 이 최적의 k 인가..?? 교차검증으로 최적의 k 를 찾아보자
from sklearn.model_selection import GridSearchCV
param_grid = dict(kmeans__n_clusters=range(2, 100))
grid_clf = GridSearchCV(pipeline, param_grid, cv=3, verbose=2)
grid_clf.fit(X_train, y_train)
결과 > k=99 가 가장 정확함. (근데 max값이 99 이므로, 더 높은 k 값이 최적일 가능성이 있음.)
9.1.5 군집을 사용한 준지도 학습
준지도학습 : 라벨이 없는 데이터가 많고 라벨이 있는 데이터는 적을때 사용.
log_reg = LogisticRegression(multi_class="ovr", solver="lbfgs", random_state=42)
log_reg.fit(X_train[:50], y_train[:50]) # 라벨있는 데이터 50개로만 학습하고
log_reg.score(X_test, y_test)# test데이터셋 450개 테스트해봄
결과 > 정확도 0.83 나옴 (전체데이터 1347개중에 무작위로 50개로만 학습하고 돌렸으니 당연한 결과이다.)
클러스터 라벨링
라벨링된 데이터가 1개도 없다고 가정했을때 어떤 방법이 있을까?
1) k개(여기서는 50개)로 클러스터링한다
kmeans = KMeans(n_clusters=k, random_state=42)
X_digits_dist = kmeans.fit_transform(X_train)
representative_digit_idx = np.argmin(X_digits_dist, axis=0) # 대표이미지 인덱스
X_representative_digits = X_train[representative_digit_idx]
대표이미지(각 센트로이드에 가장 가까운 이미지) 를 함 보자.
2) 얘네한테 수동으로 라벨링을 한다.
y_representative_digits = np.array([
0, 1, 3, 2, 7, 6, 4, 6, 9, 5,
1, 2, 9, 5, 2, 7, 8, 1, 8, 6,
3, 1, 5, 4, 5, 4, 0, 3, 2, 6,
1, 7, 7, 9, 1, 8, 6, 5, 4, 8,
5, 3, 3, 6, 7, 9, 7, 8, 4, 9])
3) 그 데이터로 학습한다
log_reg = LogisticRegression(multi_class="ovr", solver="lbfgs", max_iter=5000, random_state=42)
log_reg.fit(X_representative_digits, y_representative_digits)
log_reg.score(X_test, y_test)
결과 > 정답률이 올라간다. 0.922% (무작위 샘플보다는 대표샘플에 레이블을 부여해서 학습하는게 훨씬 좋다!)
레이블 전파 (label propagation)
근데 생각해보면.. 얘네들은 각 클러스터를 대표하는 이미지이다.동일한 클러스터에있는 데이터들에 대표이미지의 라벨을 전파하면 어떨까?
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]
결과 > 정답률이 0.933 으로 올라갔다.
근데 얘네들은 클러스터 경계에 포함된 불분명한 친구들까지도 훈련에 사용했다. 이 불문명한 친구들을 빼면 정확도가 올라가지 않을까?
→ 센트로이드와 가깝게 위치한 샘플데이터 20%만 라벨 전파 후 학습하면?
결과 > 0.94 로 정답률이 더 올라감.
능동학습
- 수집한 레이블된 샘플을 사용해 모델을 훈련
- 훈련한 모델을 사용해 레이블이 없는 샘플에 대한 예측을 수행
- 모델이 가장 불확실하게 예측한 샘플 (=추정 확률이 낮은 샘플)을 전문가에게 보내 라벨링함
- 추가된 레이블을 사용해 모델을 훈련
- 레이블을 부여한 노력만큼 성능이 향상되지 않을때까지 반복
9.1.6 DBSCAN
밀집된 연속적인 지역을 클러스터로 정의. (쉽게 말해 어떤 점을 기준으로 반경 x내에 n개 이상의 점이 있으면 하나의 군집으로 인식하는 방법.)
- 각 샘플에서 특정 거리(ε: 입실론) 내에 샘플이 몇 개 놓여있는지 셈. 이 지역을 ε-neigborhood(ε-이웃)이라고함.
- ε-이웃 내에 min_samples개의 샘플이 있다면 이 샘플은 핵심샘플(core instance)로 간주함.
- 핵심샘플의 이웃에 잇는 모든 샘플은 동일한 클러스터로 묶임.
- 핵심샘플의 이웃의 이웃은 계속해서 하나의 클러스터를 형성함.
- 핵심샘플이 아니고 이웃도 아닌 샘플은 이상치로 판단함.
from sklearn.cluster import DBSCAN
dbscan = DBSCAN(eps=0.05, min_samples=5)
dbscan.fit(X)
얘는 새로운 샘플에대해 클러스터 예측 불가능. 따라서 만약 예측하고싶다면 dbscan 하고 나서 예측기(regression 이나 classifer) 따로 붙여야함.
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=50)
knn.fit(dbscan.components_, dbscan.labels_[dbscan.core_sample_indices_])
X_new = np.array([[-0.5, 0], [0, 0.5], [1, -0.1], [2, 1]])
knn.predict(X_new)
모든 클러스터가 충분히 밀집되어있고 밀집되지 않은 지역과 잘 구분될때 좋은 성능을 냄.
클러스의 모양과 갯수에 상관없이 감지가 가능. but 클러스터간 밀집도가 크게 다르면 올바른 군집화 힘듬.
9.1.7 다른 군집 알고리즘
- 병합군집 : 물방울이 점차 하나의 커다란 방울로 불어나듯 인접한 클러스터쌍을 연결
- BIRCH (계층적군집화) : 비슷한 군집끼리 묶어 가면서 최종 적으로는 하나의 케이스가 될때까지 군집을 묶음
- 평균-이동 : DBSCAN 과 비슷. 샘플마다 원그려서 원안의 샘플 평균내서 이동 → 원이 움직이지않을때까지 계속 반복 → 밀도 높은데까지 원을 이동시킴 → 최종 동일지역에 있는 샘플이 동일클러스터가됨.
- 유사도전파 : 샘플이 자신을 대표할수있는 샘플에 투표 → 각 대표와 투표현 샘플이 클러스터생성
- 스펙트럼 군집 : 샘플사이 유사도행렬을 받아 저차원임베딩(차원축소) 만듬 → 저차원공간에서 군집알고리즘 실행
9.2 가우시안 혼합
가우시안혼합모델(GMM)은 샘플이 파라미터가 알려지지 않은 여러개의 혼합된 가우시안분포(=정규분포)에서 생성되었다고 가정하는 확률모델.
가우시안분포(정규분포)
공학자는 가우시안분포라고하고 수학자는 정규분포라고한다고함;
많은 자연현상을 매우 잘 표현하는 이상적인 확률모형. (표본들이 수가 커질수록 표본이 이루는 분포는 모집단 분포와 상관없이 정규분포를 따르게된다는 중심극한의 정리때문에 그런듯)
평균을 중심으로 좌우대칭인 종(鐘,bell) 모양을 갖는 확률 분포
X ~ N(μ,σ²) : 곡선 모양이 분포 중심인 평균(μ), 분포 폭인 분산(σ² 또는 표준편차 σ)에 의해 결정
가우시안 혼합모델 (GMM)
참고글 ) https://3months.tistory.com/154 (수식없이 이해하는 가우시안 혼합모델!)
예를 들어, A, B, C라는 세 종류의 정규분포의 PDF(probability density function:확률밀도함수)가 있다고 하자. GMM은 데이터가 이 3가지 정규분포중 하나로부터 랜덤하게 생성되었다고 보는 모델.
정규분포 1 : 평균 = -0.5, 표준편차 = 0.2 (파란색)
정규분포 2 : 평균 = -0.1, 표준편차 = 0.07 (주황색)
정규분포 3 : 평균 = 0.2, 표준편차 = 0.13 (녹색)
<1. 3개의 정규분포로부터 랜덤하게 생성된 데이터>
<2. 우리가 실제 업무에서 보게되는 데이터>
1번은 인식하기 쉽게 정규분포별로 데이터 색을 분리해놨지만, 우리는 실제로 데이터가 어떤 정규분포에서 왓을지 모르므로 2번의 모양으로 데이터를 인식하게됨. 근데 모르는 상태에서 봐도, 대충 “아 3개의 정규분포로부터 데이터가 생성됏구나” 라고 알수있음. (종모양 봉우리가 3개) → GMM을 적용시키면 됨.
우리는 GMM을 적용시키기 위해 위 데이터로부터 아래 2가지 사실을 유추할수있음.
- 첫 번째, 정규분포가 3개 있다는것과 평균과, 분산을 어느정도 짐작할 수 있음.
- 두 번째, 각각의 분포로부터 생성되는 데이터의 양의 차이가 있음.
따라서 우리는 각 3개 정규분포의 모수(평균$μ_k$,분산$Σ_k$), 가중치($π_k$, 3가지 정규분포중 확률적으로 어디에 속해있는가) 를 알아내면 데이터가 어떤 정규분포 PDF들에서 왔는지를 추정할수있다.
모수추정
평균과 분산은 구할 수 있는 값. 근데 데이트가 3개 정규분포 중 어느 정규분포에서 왔는지는 알려지지 않은 값(=잠재변수)임. 때문에 보통 모수추정에 사용하는 최대가능도함수(MLE)를 사용할수 없기에 EM(Expectation Maximazation:기댓값-최대화) 알고리즘이라는것을 사용함.
from sklearn.mixture import GaussianMixture
gm = GaussianMixture(n_components=3, n_init=10, random_state=42)
gm.fit(X)
GMM 이 우리가 알고자했던 평균, 분산, 가중치를 잘 구한걸 아래와 같이 확인할 수 있다.
gm.weights_ # 가중치
gm.means_ # 평균
gm.covariances_ # 분산
각 샘플의 하드군집/소프트군집 예측도 가능
gm.predict(X) # 하드군집
gm.predict_proba(X) # 소프트군집
GMM 매개변수 설정
feature나 cluster가 많거나 샘플이 적으면 EM이 최적의 솔루션으로 수렴하기 어려움.
이런경우는 학습할 파라미터 갯수를 제한해야함. covariance_type
매개변수를 설정하여 해결하자.
"full"
(기본값): 제약이 없습니다. 모든 클러스터가 어떤 크기의 타원도 될 수 있습니다."tied"
: 모든 클러스터가 동일하지만 어떤 타원도 가능합니다(즉, 공분산 행렬을 공유합니다)."spherical"
: 모든 클러스터가 원형이지만 지름은 다를 수 있습니다(즉, 분산이 다릅니다)."diag"
: 클러스터는 어떤 크기의 타원도 될 수 있지만 타원은 축에 나란해야 합니다(즉, 공분산 행렬이 대각 행렬입니다).
GMM 단점
GMM은 타원형 클러스터에는잘 동작하는데 다른 모양의 데이터셋에는 결과가 매우 안좋다.
GMM이 필사적으로 타원을 찾고 8개의 클러스터로 나눠버린 현장이다.
GMM 장점
자연적인 현상 표현에 좋은 모델.
데이터 마이닝, 패턴인식, 통계분석 등에 광범위하게 적용
새로운 데이터가 입력될 경우 동일한 과정으로 클러스터링 가능
9.2.1 가우시안 혼합을 사용한 이상치 탐지
이상치탐지(outlier detection, anomaly detection) : 보통과 많이 다른 샘플을 감지하는 작업.
GMM에서는 밀도가 낮은 지역에 있는 모든 샘플을 이상치로 보고 탐지할 수 있다. 밀도 임곗값을 설정하고 임계값을 넘는 데이터는 outlier로 판단한다.
densities = gm.score_samples(X)
density_threshold = np.percentile(densities, 4)
anomalies = X[densities < density_threshold]
결함제품 비율이 4%라면? 밀도 임계값을 4%로 설정. 나머지는 outlier 판정
9.2.2 클러스터 개수 선택하기
k-means 처럼 GMM도 올바른 k값(클러스터 갯수)을 찾아야하는 숙제가있다..
k-means에서는 이너셔나 실루엣점수를 사용해서 클러스터 갯수(k)를 찾았었다.
GMM은 대신 BIC(Bayesian information criterion) 이나 AIC(akaike information criterion)과 같은 이론적 정보기준을 최소화 하는 모델을 찾는다. \[𝐵𝐼𝐶=log(𝑚)𝑝−2log(𝐿̂ )\] \[𝐴𝐼𝐶=2𝑝−2log(𝐿̂ )\]
- 𝑚은 샘플의 개수
- 𝑝는 모델이 학습할 파라미터 개수
- 𝐿̂ 은 모델의 가능도 함수의 최댓
BIC, AIC : 대충 식을 보면 파라미터가 많을수록 값이 커지고 모델의 가능도가 높을수록 값이 하락함. 즉 얘네가 작을수록 좋은모델
gm.bic(X)
gm.aic(X)
이렇게 아주 쉽게 GMM의 BIC, AIC를 계산할수 있으므로 얘네가 작은 k 값을 찾아서 사용하면된다.
9.2.3 베이즈 가우시안 혼합모델
위에서 한것처럼 k 를 수동으로 찾을 필요 없이 불필요한 클러스터의 가중치는 0으로(or 0에 가깝게)하는 GMM이 있다? → 베이즈 가우시안 혼합모델
from sklearn.mixture import BayesianGaussianMixture
bgm = BayesianGaussianMixture(n_components=10, n_init=10, random_state=42)
bgm.fit(X)
n_components 는 최적의 k보다 클거라고 생각되는 값으로 지정하면 알아서 불필요한 클러스터는 쳐내서 군집화.
원리는? 베이즈 통계학. Bayesian Data Analysis 를 참고
9.2.4 이상치 탐지와 특이치 탐지를 위한 다른 알고리즘
GMM말고 outlier detection에 좋은 알고리즘은 또 뭐가 있을까?
- PCA : inlier 재구성오차보다 outlier 재구성오차가 훨씬 큼. 이를 이용해서 이상치 탐지
- Fast-MCD : 샘플이 하나의 가우시안분포에서 생성되었다고 가정하고 이 분포에서 생상되지 않은 이상치로 데이터가 오염되었다고 가정.
- isolation forest : 무작위로 성장한 Decision Tree로 구성된 Random Forest를 만들고 랜덤하게 feature를 선택해서 랜덤하게 threashold를 기준으로 데이터를 둘로 분리. 이런식으로 모든샘플을 다격리시킴. 이렇게 하다보면 outlier는 보통 inlier보다 훨씬 빠르게 격리됨.
- LOF(local outlier factor) : 주어진 샘플 주위의 밀도와 이웃 주위의 밀도를 비교. outlier는 이웃 밀도보다 훨씬 낮음
- one-class SVM : 원본공간보다 고차원 공간에 샘플을 매핑시킨 뒤, 데이터가 존재하는 영역을 SVM으로 표시. 그럼 그 영역 밖의 데이터들은 outlier임.