티스토리 뷰

Machine Learning 입문

10. 비지도 학습

DWD85 2024. 12. 28. 09:07

 

> 비지도 학습은 타깃이 없음

> 맞았는지 잘 모름 

 

> 라벨링이 안되어있는 데이터를 묶는다 

> 사용자가 묶음을 정해야 한다. 
> 별의 중심점은 random으로 처음에 정하고 클러스터링 후 평균값으로 다시 설정 

> 중심점이 안 움직일 때까지 반복한다. 

 

from sklearn.datasets import make_blobs
X,y = make_blobs(n_samples =100, n_features =2, centers =5, random_state =10)

from sklearn.cluster import KMeans 
kmc = KMeans(n_clusters =5,
             init = 'random',
             n_init = 10,
             max_iter =100,
             random_state =0) 
kmc.fit(X)
label_kmc = kmc.labels_

from sklearn.metrics import silhouette_score
sil_score = silhouette_score(X, label_kmc)
print(sil_score)

kmc_df = pd.DataFrame(X, columns= ['d1','d2'])
kmc_df['target'] = y
kmc_df['label_dbs'] = label_kmc

import seaborn as sns 
sns.scatterplot(kmc_df, x='d1', y='d2', hue ='label_dbs')

 

> random_state = 10으로 한 이유는 만든 data가 이쁘게 나오기 때문 

> 학습 목적이기 때문에 타깃을 만들어준다 

> max_iter : 수렴 안 하면 n번 하고 멈춰라 

> 타깃 명칭 때문에 달라 보일 수 있지만 그려보면 잘 구분이 된다. 

> 평가는 silhouette_score으로 한다, 1에 가까울수록 좋다

> 실루엣 스코어는 (중요) 학습의 결과보단 데이터 형태에 따라 Dominant 하게 바뀌기 때문에 참고 정도로 활용한다.

 

 

 

> DBSCAN은 밀도 중심으로 판단함

 

 

> kmeans (거리)로 판단하기 어려운 경우 밀도를 활용 

> eps는 얼마나 가까이 있는 데이터를 포섭할 거냐

> 거리가 가깝기 때문에 silhouettle score가 낮기 때문이고 학습이 잘 못 됐다는 건 아니다. 

 

from sklearn.cluster import DBSCAN
dbs = DBSCAN(eps =0.2)
dbs.fit(X)
label_dbs = dbs.labels_

dbs_df = pd.DataFrame(X, columns= ['d1','d2'])
dbs_df['target'] = y
dbs_df['label_dbs'] = label_dbs

import seaborn as sns 
sns.scatterplot(dbs_df, x='d1', y='d2', hue ='label_dbs')

 

 

> 전체 집단 안에 하위 집단의 존재를 구분



> 이론은 어렵다 개념만 확인해 보기 

from sklearn.datasets import make_blobs
X, y = make_blobs(n_samples =200, n_features =2, centers =2, random_state =2)

from sklearn.mixture import GaussianMixture
gmm = GaussianMixture(n_components =2, random_state =0) 
gmm.fit(X)
label_gmm = gmm.predict(X)

df_gmm = pd.DataFrame(X, columns = ['g1','g2'])
df_gmm['pred'] = label_gmm

sns.scatterplot(df_gmm, x='g1', y='g2', hue ='pred')

 

 

> Class가 하나고 이상치 분석할 때 사용된다

> 서포트 벡터와 이상치 데이터와의 거리를 크사이 

크사이i

 

> nu는 이상치의 비율, 이상치가 맞는지 더블 체크 필요 

 

 

> 라그랑즈 프리멀 함수 미분해서 0 되는 값을 찾고 듀얼 그랑주 함수에 넣어서 값을 도출한다. (참고)

>  Alcohol에서 이상치 데이터 찾기 

> 실루엣 스코어가 음수이면 섞이는 경우다. 

from sklearn import svm
import pandas as p
df = pd.read_csv('./data/wine_data.csv', encoding = 'cp949')

X = df[['Alcohol']] #oneclassSVM에선 대괄호 2개가 필요
clf = svm.OneClassSVM(gamma = 'auto', nu=0.1)
clf.fit(X)
pred_svm = clf.predict(X)

X2 = df[['Alcohol', 'Magesium']]
clf2 = svm.OneClassSVM(gamma = 'auto', nu = 0.5)
clf2.fit(X2)
pred_svm2 = clf2.predict(X2)

df['anomaly'] = pred_svm2
sns.scatterplot(data=df, x='Alcohol', y='Magesium', hue='anomaly')

> 떨어진 애들을 이상치 검출이 어려움 

 

> reachability를 활용해서 밀도를 표현하고 1보다 큰 값을 이상치로 분류 

> fit이랑 predict가 같이 붙어있다.

> 이상치 비율 알아서 정해준다 

 

from sklearn.neighbors import LocalOutlierFactor 

X = df[['Alcohol', 'Magesium']]
clf = LocalOutlierFactor(n_neighbors =3) 
pred_svm = clf.fit_predict(X)

df['anomaly'] = pred_svm
sns.scatterplot(data=df, x='Alcohol', y='Magesium', hue='anomaly')

 

> Tree 계열이고 Tree로 고립시키는 알고리즘 

> 이상치는 Tree 수가 적고 정상 데이터는 Tree 수가 많다. 

> 비지도 학습은 여러 모형을 사용해서 판단하는 것이 좋다. 

 

from sklearn.ensemble import IsolationForest

clf = IsolationForest (random_state = 0)
clf.fit(X)

pred_svm = clf.predict(X)
df['anomaly'] = pred_svm
sns.scatterplot(data=df, x='Alcohol', y='Magesium', hue='anomaly')

 

> 클러스터링 (kmeans DBSCAN, 가우시안 모형)

> 이상치 분석 (One Class SVM, Local Outlier factor, Isolation Forest)

> 차원 축소  (차원축소, 주성분 분석) 

 

 

> 차원 : 벡터 공간을 생성하는 기저 벡터의 개수 (주어 필요)

> 고양이라는 정보를 알기 위해서 그림자를 보는 게 더 효율적이다

> 실물은 3차원, 그림자는 2차원이기 때문이다. 

> 다만, 고양이를 잘 설명하는 그림자여야 한다.  

> 공간을 위해하기 위한 개수는 공간의 크기만큼의 최소 개수가 필요하고 그 데이터가 골고루 퍼져있어야 한다 

> 하지만 만족하지 못하기 때문에 이를 차원의 저주라고 한다. (Curse of Dimensionality) 

> 차원 저주를 해결하기 위해 차원 축소를 해야 한다. (아직 해결하지 못 함)

 

> 차원 축소 방법 중 하나가 주성분 분석이다.

> 주성분 분석에서 고유 벡터를 주성분 벡터라고 한다. 

> 두 빨간 선은 고유 벡터이다. 

> 두 고유 벡터 중 Info Loss 가 최소화되는 고육값이 큰 벡터를 선택한다. 

 

 

> Projection을 하여 차원을 축소한다. 

 

> 타깃이 없는 비지도 학습 용 데이터에서 공분산 행렬을 구해서 각 열의 고윳값, 고유 벡터를 구한다

> 줄이는 방법은 기존 행렬에 고유 벡터를 곱해주면 된다. 

 

 

#PCA 
from sklearn.decomposition import PCA 
pca = PCA(n_components=2)
pca.fit(X_tn_std)
X_tn_pca = pca.transform(X_tn_std)
X_te_pca = pca.transform(X_te_std)

print(pca.components_,'\n') #고유벡터
print(pca.singular_values_,'\n') #고유 벡터 norm
print(pca.explained_variance_,'\n') #고윳값
print(pca.explained_variance_ratio_) #설명된 분산 비율

 

 

from sklearn.neighbors import KNeighborsClassifier
clf_knn = KNeighborsClassifier(n_neighbors =2)
clf_knn.fit(X_tn_pca, y_tn)
pred_knn = clf_knn.predict(X_te_pca)

from sklearn.metrics import accuracy_score
print(accuracy_score(y_te, pred_knn))

 

pca_df = pd.DataFrame(X_tn_pca, columns = ['p1', 'p2'])
y_tn1 = y_tn.reset_index(drop=True)
pca_df['target'] = y_tn1
pca_df['target1'] = y_tn

import seaborn as sns 
sns.scatterplot(pca_df, x= 'p1', y='p2', hue = 'target')

 

 

> n_components = 2는 2차원으로 줄이겠다

> pca.fit 에서 피쳐 데이터의 고윳값, 고유 벡터를 뽑는 작업을 실행한다 

> 기존 벡터에 고유 벡터를 곱하는 작업은 tranform 

> .components_ : 고유 벡터

> .explained_variance_ : 고윳값

> .explained_variance_ratio_ : 설명된 분산 비율

> 설명된 분산 비율 : 각 피쳐의 고윳값이 데이터의 분산을 얼마나 설명하는지 나타내는 비율이다. 

> .singular_values_ : 고유 벡터의 norm

> 축소된 데이터는 어떤 걸 뜻하는지 설명하기 어렵다. 

> 13차원에서 2차원으로 줄여서 Scatter로 시각화할 수 있지만, 축을 설명하기 어렵다. 

> 차원 축소된 데이터로 학습할 수 있다. 

> 설명된 분산 비율의 합이 50% 정도이기 때문에 차원 축소 효과가 크지 않을까라는 의문이 들지만, accuracy 결과가 잘 나온다.

> 차원 축소를 하면 결과가 무조건 좋아지진 않는다. 

> data = info + noise이며 noise가 많이 제거되면 결과가 좋아지고 정보가 줄어들면 성능이 나빠질 수 있다

> Correlation과 PCA 차원 축소 차이는 PCA로 하면 축소된 피쳐를 알 수 없다, Corr은 피쳐의 정보를 통째로 날리는 단점이 있다. 

 

 

> v1, v2는 LDA 가중 벡터이고 차원 축소한 고유 벡터에 Projection 한 것이다.  

 

#LDA 학습
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
lda = LinearDiscriminantAnalysis()
lda.fit(X_tn_std, y_tn)
pred_lda = lda.predict(X_te_std)

from sklearn.metrics import accuracy_score
print(accuracy_score(y_te, pred_lda))

 

# LDA 차원 축소 + 지도 학습
X_tn_lda = lda.transform(X_tn_std)
X_te_lda = lda.transform(X_te_std)

#print(lda.intercept_,'\n') #LDA 상수항
#print(lda.coef_,'\n') #LDA 가중 벡터 

from sklearn.ensemble import RandomForestClassifier
clf_rf_lda = RandomForestClassifier(max_depth =2, random_state =0) 
clf_rf_lda.fit(X_tn_lda, y_tn) 
pred_rf_lda = clf_rf_lda.predict(X_te_lda) 

from sklearn.metrics import accuracy_score
print(accuracy_score(y_te, pred_rf_lda))

 

lda_df = pd.DataFrame(X_tn_lda, columns = ['p1', 'p2'])
y_tn1 = y_tn.reset_index(drop=True)
lda_df['target'] = y_tn1

import seaborn as sns 
sns.scatterplot(lda_df, x= 'p1', y='p2', hue = 'target')

> LDA는 지도 학습이다. 

> F 검정 개념과 비슷하다. 

> PCA와 다른 건 분해하는 행렬이 다르다. 

> PCA는 공분산 행렬을 분해, LDA는 집단 내, 집단 간 행렬을 분해한다. 

> LDA 활용법은 두 가지 방법이 있다.

> 기존 지도 학습처럼 .fit 하면 됨.

> n_components 설정할 수 있고 default 값은 min(타깃 개수 -1, 피처 개수) 

> 다른 방법은 LDA .fit하고 transform 해줘서 차원 축소를 하고 다른 모델에 fit 하는 방법이 있다.

 

 

Ref : https://losskatsu.github.io/categories/#

반응형

'Machine Learning 입문' 카테고리의 다른 글

12. Deep Learning 기초  (3) 2024.12.28
11. 시계열 분석  (0) 2024.12.28
9. 앙상블 학습  (2) 2024.12.28
8. 지도 학습  (0) 2024.12.26
7. 최적화 & 모형 평가  (1) 2024.12.26
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함