학습날짜: 2025.09.10
0. 확률 vs 우도
- 확률: 모수(파라미터)가 주어졌을 때 사건이 발생할 가능성
- 우도: 특정 데이터를 관측했을 때, 해당 모수가 타당할 가능성
- ⇒ 확률은 “데이터가 주어졌을 때 사건 발생”, 우도는 “데이터가 주어졌을 때 모수 추정”
1. Naïve Bayes Classification
- 조건부 확률 기반 분류 알고리즘임
- 전제조건
- Feature 간 독립성 가정 → 실제론 위배되는 경우 많음
- 베이즈 정리에 기반함
- 보정 기법 (Laplace smoothing)
- 기본적인 아이디어: "아예 안 나온 사건에도 작은 확률을 부여하자.“
- 모든 단어에 +1 더하고, 분모에 V(특징 값 종류 개수) 더해서 정규화
- Underflow 막기 위해 log 취함
- 우도 테이블(빈도교차표) 활용함
- 장점
- 단순하고 빠름
- 적은 데이터로도 가능
- 이산형 변수에 강함
- 단점
- 독립 가정이 현실 세계와 맞지 않음
- 연속형 변수는 전처리 필요
- 데이터 개수 너무 작으면 과적합(Overfitting) 발생
'''
나이브 베이즈 분류 알고리즘 동작 예시
문제 설정:
병원을 방문한 고객의 정보를 기반으로,
이 고객이 '남성(1)'인지 '여성(0)'인지 분류하는 문제임.
핵심 아이디어:
- 사건(방문자 특성)이 관측된 후,
이 사람이 남성일 확률과 여성일 확률을 계산 → 사후확률 (Posterior Probability)
- 종속변수(y)는 반드시 범주형이어야 함 (0/1 분류 문제)
- 독립변수(X)는 Frequency Table 형태로 조건부 확률을 구할 수 있어야 함
(즉, 각 feature 값이 "셀 수 있어야" 확률을 계산할 수 있음)
- 알고리즘 내부에서는 Frequency Table → Likelihood(우도) Table을 만듦
'''
from sklearn.naive_bayes import GaussianNB
from sklearn.preprocessing import binarize
from sklearn.metrics import classification_report
# height가 연속형이므로 구간으로 나눠서 범주형으로 만들어줌
H_arr = np.array(df['Height'])
H_arr = H_arr.reshape(-1, 1) # 1D → 2D로 변환 (scikit-learn 입력 형태 맞추기)
# 기준(threshold=165cm)으로 binarize
# → 165 이상이면 1, 미만이면 0
df['H_cd'] = binarize(H_arr, threshold=165.0)
# 독립변수(feature) 선택
cols = ['hair', 'time', 'H_cd']
# GaussianNB 사용 (연속형 변수도 처리 가능)
model = GaussianNB()
model.fit(df[cols], df['gen_cd'])
# 예측
y_pred = model.predict(df[cols]) # hair, time, h_cd
# 성능 평가
print(classification_report(df['gen_cd'], y_pred))
'''
precision recall f1-score support
0 0.81 0.82 0.81 209
1 0.81 0.80 0.81 203
accuracy 0.81 412
macro avg 0.81 0.81 0.81 412
weighted avg 0.81 0.81 0.81 412
'''
2. 비지도 학습
- 정답 라벨 없는 데이터 기반 학습
- 데이터 사이 관계/유사성 통해 패턴 탐색
- 라벨 없는 데이터가 많아 실무에서도 활용 多
- 예시: 세포 분류, 고객 세분화 등
- 장점
- 범주화/특징 추출에 도움
- 라벨 없는 데이터 확보 용이
- 새로운 데이터 실시간 처리 가능
2.1. 군집분석 (Clustering)
- 유사한 데이터끼리 그룹화
- 군집 내 유사도 ↑, 군집 간 유사도 ↓ ⇒ 좋은 군집
- 거리 기반 유사도 측정
- 유클리디안 (L2)
- 맨해튼 (L1)
- 민코프스키 (일반화된 거리)
- 코사인 유사도 (벡터 방향 유사성)

2.1.1. 계층적 군집분석
- 데이터 각각을 군집으로 시작 → 가까운 것부터 합치며 최종 하나 남음

- Early stopping 없음 → cut-tree로 중간을 잘라줘야 함
- 군집 간 거리 측정 방식
- Single link(최단 연결법): 두 군집에서 가장 가까운 두 데이터 간의 거리
- Complete link(최장 연결법): 두 군집에서 가장 멀리 떨어진 두 데이터 간의 거리
- Average link(평균 연결법): 두 군집 간의 모든 데이터들의 거리를 평균내어 두 군집의 거리 결정
- Centroid link(중심 연결법): 두 군집의 중심 간 거리
- Ward: SSE(오차 제곱합) 증가량 최소화 기준
- 시각화: 덴드로그램
- 특징: 마지막까지 혼자 남는 데이터 = 이상치 가능성 높음
'''
iris 데이터 셋 사용
거리 기반 알고리즘(KNN, 계층적 군집, K-means 등)은
변수의 단위 차이에 민감하기 때문에 반드시 스케일링 필요!!
'''
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaled_data = scaler.fit_transform(df) # 평균=0, 분산=1로 표준화된 데이터 반환
# 계층적 군집분석 (Linkage)
from scipy.cluster.hierarchy import linkage, fcluster
distance_matrix = linkage(scaled_data, method='complete') # 최장연결법
# clustering: dendrogram 시각화
from scipy.cluster.hierarchy import dendrogram
plt.figure(figsize=(40, 20))
dendrogram(distance_matrix, labels=iris['target'], leaf_rotation=90, leaf_font_size=20)
plt.show()

'''
클러스터 라벨 추출
fcluster((linkage return 값), t: 클러스터 계수, criterion=['distance', 'maxclust'])
distance: 특정 거리 기준으로 자름
maxclust: 하는 최대 군집 개수 지정
'''
df['cluster_labels'] = fcluster(distance_matrix, 3, criterion="distance")
# 군집 결과 vs 실제 라벨 비교
ct = pd.crosstab(df["cluster_labels"], iris["target"])
'''
col_0 0 1 2
cluster_labels
1 0 29 37
2 0 0 11
3 1 4 0
4 0 17 2
5 7 0 0
6 42 0 0
'''
2.1.2. 비계층적 군집분석
- 군집 수(K)를 먼저 정하고 시작
- K-means
- 주어진 데이터를 K 개의 군집으로 나누는 알고리즘
- 군집 중심(centroid) 업데이트하며 수렴할 때까지 반복
- 장점: 대용량 데이터에도 가능, 단순하고 빠름
- 단점:
- k값 사전 결정 필요
- 초기 중심값에 민감
- 이상치에 취약(→ 전처리 필요)
- 적절한 K 선택법: Elbow method (군집 내 SSE 그래프 활용)

from sklearn.cluster import KMeans
# 마지막 열(label)을 제외한 4개 feature만 사용
# iris의 sepal length, sepal width, petal length, petal width
points = df.iloc[:, :-1]
# 모델 생성 및 학습
kmeans = KMeans(n_clusters=3).fit(points)
# 각 클러스터의 중심 좌표
kmeans.cluster_centers_ # 열 개수가 변수 개수 만큼 나옴
'''
array([[6.85 , 3.07368421, 5.74210526, 2.07105263],
[5.006 , 3.428 , 1.462 , 0.246 ],
[5.9016129 , 2.7483871 , 4.39354839, 1.43387097]])
'''
# 러스터 결과 시각화
plt.scatter(df["sepal length (cm)"], df["sepal width (cm)"],
c = df['label'])
center_x = kmeans.cluster_centers_[:, 0]
center_y = kmeans.cluster_centers_[:, 1]
plt.scatter(center_x, center_y, c = "red", marker="D")
plt.show()

'''
적합한 k값 찾기 (Elbow Method)
- KMeans에서 k(클러스터 수)는 직접 정해야 함
- 평가 지표: inertia (군집 내 거리 제곱합, 응집도)
* 값이 클수록 군집 내 데이터들이 흩어져 있음 (distortion 큼)
* 값이 작을수록 군집 내 데이터들이 조밀하게 모여 있음 (응집도 ↑)
- inertia 값 감소 그래프를 그리면, 감소 폭이 꺾이는 지점(elbow)이 적절한 k
'''
# Elbow Method 적용
dist = []
for k in range(1, 11):
k_means = KMeans(n_clusters=k, random_state=42)
k_means.fit(points)
dist.append(k_means.inertia_) # 군집 내 거리 제곱합 저장
plt.figure(figsize=(8,5))
plt.plot(range(1, 11), dist, marker = "o")
plt.xlabel("number of Cluster")
plt.ylabel("Distortion")
plt.show()
# k=3일 때 Elbow 지점이 나타남 → 최적의 클러스터 수로 판단 가능

'LG U+ Why Not SW Camp 8기 > 학습 로그' 카테고리의 다른 글
| 공부 일지 #38 | 머신러닝: 시계열 데이터 (1) | 2025.09.14 |
|---|---|
| 공부 일지 #37 | 머신러닝: 차원 축소와 추천 알고리즘 (0) | 2025.09.14 |
| 공부 일지 #35 | 머신러닝: 앙상블과 RandomForest, 교차검증 (0) | 2025.09.14 |
| 공부 일지 #34 | 머신러닝: 성능지표(ROC·AUC)와 Decision Tree (0) | 2025.09.11 |
| 공부 일지 #33 | 머신러닝 : 규제와 분류(로지스틱, 성능지표) (0) | 2025.09.07 |