[SK쉴더스 루키즈 24기] 머신러닝 기초(3) 차원 축소와 이상치 탐지

아굥·2024년 12월 26일
1

SK Shieldus Rookies

목록 보기
10/32

차원 축소 기초

1. 차원 축소의 필요성

데이터가 고차원일수록(특성(Feature)의 개수가 많을수록) 모델을 학습시키거나 분석할 때 여러 가지 문제가 발생할 수 있음
-> 이 문제를 해결하기 위해 차원 축소가 필요

차원 축소(Dimensionality Reduction)

① 고차원의 문제

  • 데이터의 차원이 증가하면 데이터가 차지하는 공간이 기하급수적으로 증가 -> 이로 인해 발생하는 문제를 "차원의 저주"라고 함
  • 데이터가 희소해짐: 고차원에서는 데이터 포인트가 서로 멀리 떨어져 있고, 유사성을 찾기 어려움
  • 학습 속도 저하: 고차원 데이터는 계산 비용이 증가하여 모델 학습이 느려짐
  • 과적합: 특성이 많으면 모델이 학습 데이터에 지나치게 맞춰줘 일반화 능력이 떨어짐

② 데이터 시각화

  • 고차원 데이터는 직관적으로 이해/시각화 하기 어려움
    ㄴ> 차원 축소를 통해 데이터를 2차원/3차원으로 변환해야 함

③ 노이즈 제거

  • 고차원 데이터는 중요한 정보 뿐만 아니라 불필요한 정보가 포함될 수 있음
    ㄴ> 차원 축소는 데이터의 가장 중요한 특징(변동성)을 유지하며 노이즈를 줄여줌

④ 모델 효율성 향상

  • 데이터 차원을 줄이면 계산량이 줄어 모델 학습, 예측 속도가 빨라지고 메모리 사용량도 감소
    ㄴ> 중요하지 않은 특성이 제거되어 모델이 학습에 필요한 정보에만 집중할 수 있음

2. PCA 개념 및 원리

고차원 데이터를 저차원으로 축소하면서도 데이터의 중요한 정보를 최대한 보존하는 기법
-> 데이터의 주요 특징을 파악, 노이즈를 제거하거나 시각화를 용이하게 함

  • 데이터를 선형 변환하여 새로운 축을 생성하는 과정
    ㄴ> 주성분: 데이터의 분산을 가장 잘 설명하는 새로운 축
    ㄴ> 데이터의 주요 패턴 찾기: 데이터의 분산이 가장 큰 방향을 기준으로 데이터 분석
    ㄴ> 축 변경: 기존의 좌표축을 새로운 주성분 축으로 변환
    ㄴ> 차원 축소: 중요하지 않은 주성분을 제거하여 데이터의 차원을 줄임

1) 작동 원리

  • 데이터를 새로운 좌표축으로 변환하여 주요 특징을 유지하며 차원을 줄임

① 데이터는 처음 여러 차원으로 구성
② PCA는 각 차원의 분산(정보량)을 측정하고, 분산이 가장 큰 방향(축)을 찾음
③ 분산이 가장 큰 방향으로 데이터를 정렬하여 새로운 축을 정의
④ 새로운 축을 기준으로 데이터를 변환하여, 적은 차원에서도 데이터를 잘 설명할 수 있도록 처리

2) 적용 단계

① 데이터 정규화

  • PCA 적용 전, 데이터를 정규화하거나 스케일링
    ㄴ> 각 피처 값이 서로 다른 범위를 갖고 있으면 결과에 영향을 미침 -> 평균이 0이고, 분산이 1인 데이터로 변환

② 주성분 축을 찾기 위한 공분산 행렬 계산

  • 각 피처 간의 상관관계를 나타냄 -> 데이터의 분산 구조를 파악하는데 필수적

③ 주성분 축을 찾기 위한 고유값과 교유벡터 계산

  • 공분산 행렬을 분해하여 계산함
    ㄴ> 고유값: 주성분이 설명하는 분산의 크기 (중요도)
    ㄴ> 고유벡터: 주성분의 방향 (새로운 축)

④ 주성분 선택

  • 고유값이 큰 순서대로 주성분 정렬
    ㄴ> 중요한 정보를 설명하는 주성분만 선택

⑤ 데이터 투영

  • 원본 데이터를 선택된 주성분 축으로 투영
    ㄴ> 데이터 차원이 축소됨

3. 주성분의 의미와 데이터 투영

데이터의 분산(정보량)이 가장 큰 방향을 나타내는 축

1) 주성분의 특징

  • 첫 번째 주성분(PC1): 데이터의 분산이 가장 큰 방향
    ㄴ>데이터의 변동성을 가장 잘 설명함
  • 두 번째 주성분(PC2): 첫 번째 주성분에 수직한 축, 두 번째로 큰 분산을 설명하는 방향
  • 추가 주성분: 이전 주성분과 직교하며 분산이 큰 순서대로 찾음
  • 주성분의 수: 데이터의 차원 수와 동일한 수의 주성분이 존재함

데이터를 기존의 좌표축 대신 주성분 축으로 변환하는 과정
-> 투영 후의 데이터는 새로운 축(주성분) 상에서 표현, 불필요한 차원은 제거됨

2) 데이터 투영이 필요한 이유

  • 중요한 정보만 유지: 데이터의 분산이 큰 축(주성분)에 투영하면 정보량을 최대한 유지할 수 있음
  • 차원 축소: 데이터가 주성분 축으로 투영되면, 더 적은 차원에서도 데이터를 잘 설명할 수 있음
  • 시각화: 투영된 데이터를 2차원/3차원으로 변환하여 시각적으로 이해 가능
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

# 1. Iris 데이터셋 로드
iris = load_iris()
x = iris.data                               # 특성 데이터
y = iris.target                             # 타깃 데이터

# 2. 데이터 정규화
scaler = StandardScaler()
x_scaled = scaler.fit_transform(x)

# 3. PCA 객체 생성 및 적합
pca = PCA(n_components=2)
x_pca = pca.fit_transform(x_scaled)

# 4. PCA 결과 출력
print(pca.explained_variance_ratio_)

# 5. PCA 결과 시각화
plt.figure(figsize=(8, 6))
for target, color, label in zip([0, 1, 2], ['red', 'blue', 'green'], iris.target_names):
    plt.scatter(x_pca[y == target, 0], x_pca[y == target, 1], color=color, label=label, alpha=0.7)

plt.title('PCA on Iris Dataset')
plt.xlabel('Principal Component 1')
plt.ylabel('Principal Component 2')
plt.legend()
plt.grid()
plt.show()

고급 차원 축소

t-SNE 소개

고차원의 데이터를 저차원 공간으로 변환하여 데이터의 구조를 시각화하는데 사용되는 비선형 차원 축소 방법

  • 데이터 군집(클러스터)이나 복잡한 구조를 시각적으로 분석할 때 유용함

1) 왜 필요한가?

  • 고차원 데이터는 사람이 이해하거나 시각화하기 힘듦
  • 선형 차원 축소 방법(ex. PCA)은 고차원 데이터의 선형적인 특성을 잘 다루지만, 데이터 간 비선형적인 관계를 포착하긴 어려움

2) 핵심 과정

① 고차원 공간에서 데이터 간 유사성 계산
② 저차원 공간에서 데이터 간 유사성 정의
③ 고차원과 저차원 공간의 유사성 차이 줄이기

3) 특징

  • 비선형 차원 축소: 데이터의 비선형적 구조를 효과적으로 포착
  • 국소 구조 유지: 데이터의 가까운 이웃 간의 관계를 보존하는데 중점
  • 저차원 시각화 최적화: 결과는 저차원 공간에서 데이터 포인트 간 상대적 위치를 기반으로 구조 해석

4) 단점

  • 계산 비용 높음: 모든 데이터 포인트 간 유사성을 계산해야 함 -> 데이터 포인트 수가 많아질수록 계산 비용 크게 증가
  • 전역 구조 표현의 한계: 데이터의 전역적인 구조는 잘 표현하지 못할 수 있음 -> 데이터 전체 분포보다 국소적 관계 분석 시 적합함
  • 결과 해석의 주관성: 같은 데이터라도 초기값 설정에 따라 다른 결과를 도출할 수 있음
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import fetch_openml
from sklearn.manifold import TSNE
from sklearn.preprocessing import StandardScaler

# 1. MNIST 데이터셋 로드
mnist = fetch_openml('mnist_784', version=1)
x, y = mnist.data, mnist.target

# 2. 데이터 전처리
scaler = StandardScaler()
x_scaled = scaler.fit_transform(x)

# 3. t-SNE 모델 생성
tsne = TSNE(n_components=2, random_state=42, n_iter=1000, perplexity=30)
x_tsne = tsne.fit_transform(x_scaled[:2000])

# 4.  시각화
plt.figure(figsize=(10, 8))
scatter = plt.scatter(x_tsne[:, 0], x_tsne[:, 1], c=y[:2000].astype(int), cmap='tab10', s=10)
plt.colorbar(scatter, label='Digit Label')
plt.title('t-SNE Visualization of MNIST Data')
plt.xlabel('t-SNE Dimension 1')
plt.ylabel('t-SNE Dimension 2')
plt.grid()
plt.show()


이상치 탐지

1. 이상치 탐지의 개념과 중요성

데이터에서 일반적인 패턴과 크게 벗어나는 관측값을 식별하는 과정

  • 데이터 분포와 동떨어져 있거나, 예상 범위를 벗어난 데이터 포인트를 나타냄

목적

  • 데이터 품질 개선
  • 비정상적인 행동을 사전에 발견하여 문제를 예방

2. 비지도학습 기반 이상치 탐지

1) Isolation Forest

데이터를 반복적으로 나누는 방식으로 이상치 탐지하기 위해 설계된 비지도학습 알고리즘

  • 데이터 공간을 무작위로 분할하며, 나눌수록 나머지 데이터에서 이상치가 빠르게 분리되는 경향이 있음

작동 원리

① 무작위 샘플링: 데이터에서 임의의 특징을 선택, 임의의 분할 값을 선택하여 데이터를 나눔
② 분리 깊이 계산: 이상치 일수록 다른 데이터로부터 분리되는데 필요한 단계가 작음
③ 여러 트리 구축: 데이터를 무작위로 분할하여 여러 개의 이진 트리 생성 -> 각 데이터 포인트가 나뉘는 평균 깊이 계산
④ 이상치 점수 산출: 분리 깊이에 따라 정해짐 -> 높은 점수를 받을수록 이상치일 가능성 높음

장점

  • 효율성: 데이터 크기와 상관없이 선형 시간복잡도 (O(n))
  • 확장성: 대규모 데이터 세트에서도 작동 가능
  • 비지도학습: 레이블이 없어도 작동

단점

  • 고차원 데이터에서 효율 떨어짐
  • 분포가 매우 복잡한 데이터에서 성능 제한됨
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.ensemble import IsolationForest

# 1. 데이터 생성
np.random.seed(42)

# 정상/비정상 트래픽 데이터 생성
normal_traffic = np.random.normal(loc=50, scale=10, size=(100, 2))
anomalous_traffic = np.random.uniform(low=100, high=150, size=(10, 2))

# 데이터 결합 > 데이터프레임으로 변환
traffic_data = np.vstack((normal_traffic, anomalous_traffic))
traffic_df = pd.DataFrame(traffic_data, columns=['Request Count', 'Response Time'])

# 2. Isolation Forest 모델 생성 및 학습
model = IsolationForest(n_estimators=100, contamination=0.1, random_state=42)

# 모델 학습 후 예측 수행
traffic_df['Anomaly Score'] = model.fit_predict(traffic_data)

traffic_df['Anomaly'] = traffic_df['Anomaly Score'].apply(lambda x: 'Normal' if x == 1 else 'Anomaly')

# 3. 비정상 데이터의 범위 확인
anomalous_data = traffic_df[traffic_df['Anomaly'] == 'Anomaly']

min_request_count = anomalous_data['Request Count'].min()
max_request_count = anomalous_data['Request Count'].max()
min_response_count = anomalous_data['Response Time'].min()
max_response_count = anomalous_data['Response Time'].max()

print(f'요청 수(Request Count): {min_request_count} ~ {max_request_count}')
print(f'응답 시간(Response Time): {min_response_count} ~ {max_response_count}')

# 4. 시각화
plt.figure(figsize=(10, 6))
plt.scatter(traffic_df["Request Count"], traffic_df["Response Time"], c=traffic_df['Anomaly'].map({"Normal": "blue", "Anomaly": "red"}), label='Traffic')
plt.title("Traffic Data with Isolation Forest Anomaly Detection")
plt.xlabel("Request Count")
plt.ylabel("Response Time")
plt.legend(["Normal", "Anomaly"])
plt.grid()
plt.show()

2) DBSCAN

데이터를 밀도가 높은 영역(군집)과 밀도가 낮은 영역(이상치)으로 나누는 밀도 기반 클러스터링 알고리즘

  • 데이터 밀도가 충분히 높은 영역을 클러스터로 간주
  • 밀도가 낮은 데이터 포인트는 이상치로 분류함

주요 개념

  • Epsilon(ε): 두 데이터 포인트가 같은 클러스터에 속하기 위해 허용되는 최대 거리
  • MinPts: 클러스터가 형성되기 위해 필요한 최소 데이터 포인트 수
  • Core Points: ε 반경 안에 MinPts 이상의 데이터가 포함된 포인트
  • Border Points: ε 반경 내 Core Points에 포함되지만 MinPts 조건을 만족하지 않는 포인트
  • Noise: Core Points, Border Points에 속하지 않는 포인트

작동 원리

  • 각 데이터 포인트에서 ε 반경 내 데이터 밀도를 계산
  • 밀도가 높은 포인트(Core Points)를 중심으로 클러스터 형성
  • 밀도가 낮은 포인트는 Noise로 간주

장점

  • 클러스터의 모양에 제약 X -> 비구조적 데이터에서도 사용 가능
  • 사전 클러스터 개수 지정 불필요
  • 이상치 탐지와 클러스터링 동시 수행

단점

  • ε와 MinPts 파라미터 선택이 성능에 큰 영향을 미침
  • 고차원 데이터에 적용할 경우 효율성 저하
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.cluster import DBSCAN

# 1. 데이터 생성
np.random.seed(42)                             

# 정상/비정상 트래픽 데이터 생성
normal_traffic = np.random.normal(loc=50, scale=10, size=(100, 2))
anomalous_traffic = np.random.uniform(low=100, high=150, size=(10, 2))

# 데이터 결합 > 데이터프레임으로 변환
traffic_data = np.vstack((normal_traffic, anomalous_traffic))
traffic_df = pd.DataFrame(traffic_data, columns=['Request Count', 'Response Time'])

# 2. DBSCAN 모델 생성
dbscan = DBSCAN(eps=15, min_samples=5)
traffic_df['Cluster'] = dbscan.fit_predict(traffic_data)

# 3. 이상치 탐지
traffic_df['Anomaly'] = traffic_df['Cluster'].apply(lambda x: 'Anomaly' if x == -1 else 'Normal')

anomalous_data = traffic_df[traffic_df['Anomaly'] == 'Anomaly']

min_request_count = anomalous_data['Request Count'].min()
max_request_count = anomalous_data['Request Count'].max()
min_response_count = anomalous_data['Response Time'].min()
max_response_count = anomalous_data['Response Time'].max()

print(f'요청 수(Request Count): {min_request_count} ~ {max_request_count}')
print(f'응답 시간(Response Time): {min_response_count} ~ {max_response_count}')

# 4. 시각화
plt.figure(figsize=(10, 6))
plt.scatter(traffic_df["Request Count"], traffic_df["Response Time"], c=traffic_df['Anomaly'].map({"Normal": "blue", "Anomaly": "red"}), label='Traffic')
plt.title("Traffic Data with DBSCAN Anomaly Detection")
plt.xlabel("Request Count")
plt.ylabel("Response Time")
plt.legend(["Normal", "Anomaly"])
plt.grid()
plt.show()
profile
열심히 살아보아요

0개의 댓글