→ 범주형(Categorical) 데이터
1. 이미지 내의 대상
2. 콘텐츠 내용에 따라 주제 분류
3. 정형 데이터 분류
1. 이진 분류 (Binary Classification)
2. 다중 분류(Mulitple Classification)
→ 연속형(continuous) 데이터
1. 거리 계산
def _euclidean_distance(self, x1, x2):
return np.sqrt(np.sum((x1 - x2)**2))
def _predict(self, x):
# x와 훈련 세트의 모든 예제 사이의 거리 계산
distances = [self._euclidean_distance(x, x_train) for x_train in self.X_train]
2. 가까운 이웃 선택
def _predict(self, x):
...
# 거리를 기준으로 정렬하고 첫 k개 이웃의 인덱스 반환
k_indices = np.argsort(distances)[:self.k]
# k개의 가장 가까운 이웃 훈련 샘플의 레이블 추출
k_nearest_labels = [self.y_train[i] for i in k_indices]
3. 다수결 투표
def _predict(self, x):
...
# 다수결 투표 이후 클래스 레이블 반환
most_common = np.argmax(np.bincount(k_nearest_labels))
return most_common
import numpy as np
class KNN:
def __init__(self, k=3):
self.k = k
def fit(self, X, y):
self.X_train = X
self.y_train = y
def predict(self, X):
y_pred = [self._predict(x) for x in X]
return np.array(y_pred)
def _euclidean_distance(self, x1, x2):
return np.sqrt(np.sum((x1 - x2)**2))
def _predict(self, x):
# x와 훈련 세트의 모든 예제 사이의 거리 계산
distances = [self._euclidean_distance(x, x_train) for x_train in self.X_train]
# 거리를 기준으로 정렬하고 첫 k개 이웃의 인덱스 반환
k_indices = np.argsort(distances)[:self.k]
# k개의 가장 가까운 이웃 훈련 샘플의 레이블 추출
k_nearest_labels = [self.y_train[i] for i in k_indices]
# 다수결 투표 이후 레이블 반환
most_common = np.argmax(np.bincount(k_nearest_labels))
return most_common
1. 데이터 분류를 위한 최적의 결정 경계 찾기
2. 서포트 벡터
3. 마진 최대화
class SVM:
def fit(self, X, y):
...
# 경사 하강법 최적화로 마진 최대화
for _ in range(self.num_iterations):
for i in range(n_samples):
if y[i] * (np.dot(X[i], self.w) - self.b) >= 1:
self.w -= self.learning_rate * (2 * self.lambda_param * self.w)
else:
self.w -= self.learning_rate * (2 * self.lambda_param * self.w - np.dot(X[i], y[i]))
self.b -= self.learning_rate * y[i]
# SVM 클래스 정의
class SVM:
def __init__(self, learning_rate=0.01, lambda_param=0.01, num_iterations=1000):
self.learning_rate = learning_rate
self.lambda_param = lambda_param
self.num_iterations = num_iterations
self.w = None
self.b = None
# fit 함수 정의
def fit(self, X, y):
# y<=0을 만족하면 -1, 만족하지 않으면 1을 출력
y = np.where(y <= 0, -1, 1)
n_samples, n_features = X.shape
# 가중치 초기화
self.w = np.zeros(n_features)
self.b = 0
# 경사 하강법 최적화
for _ in range(self.num_iterations):
for i in range(n_samples):
if y[i] * (np.dot(X[i], self.w) - self.b) >= 1:
self.w -= self.learning_rate * (2 * self.lambda_param * self.w)
else:
self.w -= self.learning_rate * (2 * self.lambda_param * self.w - np.dot(X[i], y[i]))
self.b -= self.learning_rate * y[i]
def predict(self, X):
linear_output = np.dot(X, self.w) - self.b
return np.sign(linear_output)
# 0보다 작으면 -1, 0보다 크면 1로 반환
1. 입력 데이터와 가중치 행렬 선형 조합
2. 로지스틱함수에 z입력
3. 경사하강법
class LogisticRegression:
...
def fit(self, X, y):
num_samples, num_features = X.shape
# 가중치 및 편향 초기화
self.weights = np.zeros(num_features)
self.bias = 0
# 경사 하강법 최적화
for _ in range(self.num_iterations):
linear_model = np.dot(X, self.weights) + self.bias
predicted_labels = self.sigmoid(linear_model)
# 기울기 계산
dw = (1 / num_samples) * np.dot(X.T, (predicted_labels - y))
db = (1 / num_samples) * np.sum(predicted_labels - y)
# 파라미터 업데이트
self.weights -= self.learning_rate * dw
self.bias -= self.learning_rate * db
import numpy as np
# 로지스틱 회귀 class 정의
class LogisticRegression:
def __init__(self, learning_rate=0.01, num_iterations=1000):
self.learning_rate = learning_rate
self.num_iterations = num_iterations
self.weights = None
self.bias = None
# 활성화 함수인 시그모이드 함수 정의
def sigmoid(self, z):
return 1 / (1 + np.exp(-z))
# fit 함수 정의
def fit(self, X, y):
num_samples, num_features = X.shape
# 가중치 및 편향 초기화
self.weights = np.zeros(num_features)
self.bias = 0
# 경사 하강법 최적화
for _ in range(self.num_iterations):
linear_model = np.dot(X, self.weights) + self.bias
predicted_labels = self.sigmoid(linear_model)
# 기울기 계산
dw = (1 / num_samples) * np.dot(X.T, (predicted_labels - y))
db = (1 / num_samples) * np.sum(predicted_labels - y)
# 파라미터 업데이트
self.weights -= self.learning_rate * dw
self.bias -= self.learning_rate * db
# 예측함수 정의
def predict(self, X):
linear_model = np.dot(X, self.weights) + self.bias
predicted_labels = self.sigmoid(linear_model)
predicted_labels = np.where(predicted_labels >= 0.5, 1, 0)
return predicted_labels
1. 엔트로피 계산
데이터의 불확실성을 나타내는 척도
엔트로피⬆ 혼잡도⬆ 불순도⬆ | 5:5면 불순도가 높다!!
- (5:5)로 나뉘었다 => 불순도⬆
- (1:9)로 나뉘었다 => 불순도⬇
import numpy as np
class DecisionTree:
def __init__(self, max_depth=None):
self.max_depth = max_depth
self.tree = {}
def entropy(self, y):
_, counts = np.unique(y, return_counts=True)
probabilities = counts / len(y)
entropy = -np.sum(probabilities * np.log2(probabilities))
return entropy
2. 정보 이득 최대화
class DecisionTree:
...
def information_gain(self, X, y, feature_idx, threshold):
left_mask = X[:, feature_idx] <= threshold
right_mask = X[:, feature_idx] > threshold
left_y = y[left_mask]
right_y = y[right_mask]
left_entropy = self.entropy(left_y)
right_entropy = self.entropy(right_y)
left_weight = len(left_y) / len(y)
right_weight = len(right_y) / len(y)
# GAIN: 분할된 하위 노드의 엔트로피들의 가중평균을 뺀 값
information_gain = self.entropy(y) - (left_weight * left_entropy + right_weight * right_entropy)
return information_gain
3. 최적의 임계값(Thresholds) 찾기
def split(self, X, y):
num_samples, num_features = X.shape
best_info_gain = 0
best_feature_idx = None
best_threshold = None
for feature_idx in range(num_features):
thresholds = np.unique(X[:, feature_idx])
# 입력 데이터 특성이 임계값 후보
for threshold in thresholds:
# 정보 획득량 계산
info_gain = self.information_gain(X, y, feature_idx, threshold)
if info_gain > best_info_gain:
best_info_gain = info_gain
best_feature_idx = feature_idx
best_threshold = threshold
left_mask = X[:, best_feature_idx] <= best_threshold
right_mask = X[:, best_feature_idx] > best_threshold
left_X = X[left_mask]
left_y = y[left_mask]
right_X = X[right_mask]
right_y = y[right_mask]
return best_feature_idx, best_threshold, left_X, left_y, right_X, right_y
4. 의사결정나무 구축
def build_tree(self, X, y, depth=0):
num_samples, num_features = X.shape
# 기저 사례(base case): 최대 깊이에 도달하거나 순수한 리프 노드(pure leaf nodes)인 경우
if len(np.unique(y)) == 1 or depth == self.max_depth:
_, counts = np.unique(y, return_counts=True)
leaf_label = np.argmax(counts)
return leaf_label
feature_idx, threshold, left_X, left_y, right_X, right_y = self.split(X, y)
decision_node = {
'feature_idx': feature_idx,
'threshold': threshold,
'left': self.build_tree(left_X, left_y, depth+1),
'right': self.build_tree(right_X, right_y, depth+1)
}
return decision_node
# DT 클래스 정의, max_depth 등
class DecisionTree:
def __init__(self, max_depth=None):
self.max_depth = max_depth
self.tree = {}
# 엔트로피 정의
def entropy(self, y):
_, counts = np.unique(y, return_counts=True)
probabilities = counts / len(y)
entropy = -np.sum(probabilities * np.log2(probabilities))
return entropy
# Gain 정의 및 최대화 방향
def information_gain(self, X, y, feature_idx, threshold):
left_mask = X[:, feature_idx] <= threshold
right_mask = X[:, feature_idx] > threshold
left_y = y[left_mask]
right_y = y[right_mask]
left_entropy = self.entropy(left_y)
right_entropy = self.entropy(right_y)
left_weight = len(left_y) / len(y)
right_weight = len(right_y) / len(y)
information_gain = self.entropy(y) - (left_weight * left_entropy + right_weight * right_entropy)
return information_gain
# 최적의 임계값(Thresholds) 찾기
def split(self, X, y):
num_samples, num_features = X.shape
best_info_gain = 0
best_feature_idx = None
best_threshold = None
for feature_idx in range(num_features):
thresholds = np.unique(X[:, feature_idx])
# 입력 데이터 특성이 임계값 후보
for threshold in thresholds:
# 정보 획득량 계산
info_gain = self.information_gain(X, y, feature_idx, threshold)
if info_gain > best_info_gain:
best_info_gain = info_gain
best_feature_idx = feature_idx
best_threshold = threshold
left_mask = X[:, best_feature_idx] <= best_threshold
right_mask = X[:, best_feature_idx] > best_threshold
left_X = X[left_mask]
left_y = y[left_mask]
right_X = X[right_mask]
right_y = y[right_mask]
return best_feature_idx, best_threshold, left_X, left_y, right_X, right_y
# 의사결정나무 구축
def build_tree(self, X, y, depth=0):
num_samples, num_features = X.shape
# 최대깊이에 도달하거나 순수한 리프 노드인 경우 : 기저 사례
if len(np.unique(y)) == 1 or depth == self.max_depth:
_, counts = np.unique(y, return_counts=True)
leaf_label = np.argmax(counts)
return leaf_label
feature_idx, threshold, left_X, left_y, right_X, right_y = self.split(X, y)
decision_node = {
'feature_idx': feature_idx,
'threshold': threshold,
'left': self.build_tree(left_X, left_y, depth + 1),
'right': self.build_tree(right_X, right_y, depth + 1)
}
return decision_node
def fit(self, X, y):
self.tree = self.build_tree(X, y)
def predict_sample(self, x, tree):
if isinstance(tree, int):
return tree
feature_idx = tree.get('feature_idx')
threshold = tree.get('threshold')
if x[feature_idx] <= threshold:
if isinstance(tree['left'], dict):
return self.predict_sample(x, tree['left'])
else:
return tree['left']
else:
if isinstance(tree['right'], dict):
return self.predict_sample(x, tree['right'])
else:
return tree['right']
def predict(self, X):
predictions = []
for x in X:
prediction = self.predict_sample(x, self.tree)
predictions.append(prediction)
return np.array(predictions)
[출처 | 딥다이브 Code.zip 매거진]