Machine learning & Deep learning

[Machine learning] Linear regression, Logistic regression code 구현중 모르거나 헷갈렸던 code 정리

ysk1m 2025. 3. 26. 23:15

linear regression부터 k-fold validation에 대해 실제 예제(code 구현)를 공부하다가 기억하면 좋을 것 같은 내용에 대해 정리.

Linear regression_bias항을 모델에 포함시키기

Scalar가 아니라 Matrix form일 때, bias를 따로 처리하면 귀찮아지므로, 모든 샘플의 입력 앞에 1을 붙여서 절편도 가중치 취급을 한다.

X = np.hstack((np.ones((X.shape[0], 1)), X))

X.shape[0] 즉 row방향으로 1로 채워진 배열을 X앞에 stack 한다.

X =
[[x11, x12],
 [x21, x22]]
↓ hstack with ones
[[1, x11, x12],
 [1, x21, x22]]

Linear regression_data split 하기

indices = np.random.permutation(len(dataframe))
#[3 0 4 2 1]

len(dataframe)은 row의 개수로 데이터의 총개수이다.

test_indices = indices[:test_samples] #[3, 0]
train_indices = indices[test_samples:] #[4, 2, 1]

Linear regression_fit(X,y)를 이용할 때

X_train, y_train = np.array(train_data.TV).reshape(-1, 1), np.array(train_data.Sales)

x를 2차원 배열로 reshape 하는 반면 y는 그대로 이용하는데 그 이유는 linear regression에서 fit를 하기 위해서는 2차원 배열, 1차원 배열을 요구하기 때문이다.

그래서 reshape(-1,1)로 배열의 차원을 바꾼다.

 

Linear regression_Feature selection

Subset selection

feature의 모든 조합에 대해 모델의 성능을 파악하는 것이다.

for k in range(1, n_features + 1):
        # Generate all possible combinations of features
        subsets = np.array(list(itertools.combinations(range(n_features), k)))

1부터 feautre의 총개수까지 for문을 돌리고 k 개만큼 원소를 가지고 있는 subset을 만든다.

for subset in subsets:
     # Fit linear regression model using the current subset
     X_subset = X[:, subset]
     model = LinearRegression()
     model.fit(X_subset, y)

특히 여기서 조심해야 할 부분은 모델의 성능을 측정할 때, \(R^2\)을 사용한다는 점이다.

\(R^2\)은 feature의 개수가 증가할수록 계속 좋아지기 때문이다.

따라서, feature의 개수가 증가하는 것에 penalty를 준 \(adjusted-R^2\)을 사용한다.

if metric_val > best_metric:
                best_metric = metric_val
                best_subset = subset

최고일 때를 계속 갱신한다.

Forward Step-Wise selection

처음에는 아무 feature를 사용하지 않고 남아 있는 feature 중에서 하나씩 추가해 가면서 성능을 비교하는 것이다.

n_features = X.shape[1]
selected_features = []
current_features = []
remaining_features = list(range(n_features))

맨 처음에는 초기화시킨다.

for _ in reversed(range(n_features)):

총 feature의 개수만큼 반복한다.

for feature in remaining_features:
     # Append the selected feature to the current subset
     current_subset = current_features + [feature]

남아있는 feature에서 하나씩 전부 다 뽑아보면서 current_subset을 업데이트한다.

모델의 일반화 성능까지 확인하기 위해 k-fold도 같이 하는데

for fold_idx in range(k_fold):
          # Split data into train and validation sets
          val_indices = fold_indices[fold_idx]
          train_indices = np.concatenate([fold_indices[i] for i in range(k_fold) if i != fold_idx])
          X_cross_train, X_cross_val = X[train_indices], X[val_indices]
          y_cross_train, y_cross_val = y[train_indices], y[val_indices]

k번만큼 train set과 validation set을 나눠 모델의 성능을 판단한다.

 

LDA 구현하기

일단 Iris 데이터의 구조는 다음과 같다.

sklearn의 내장함수 없이 직접 수식으로 계산한 것을 구현한 내용이다.

LDA에서는 각 class에서의 분포가 gaussian 분포를 가진다.

따라서, 평균과 분산을 정해야 한다.

앞서 공부했던 것처럼 MLE를 통해 구하고 그 값을 이용하면 된다.

mean_vectors = np.array([X[y == k].mean(axis=0) for k in range(n_classes)])

평균의 MLE는 모든 샘플의 평균이므로 y가 k class일 때의 x값을 남기고 그것을 axis=0방향(column)으로 mean값을 구한다.

그럼 각 feature마다의 평균값이 나온다.( axis=0 열 방향으로 밑으로 계산, axis=1 행방향으로 옆으로 계산)

이런 식으로 되는 것이다.

# shared variance (assumed equal across classes)
S_W = np.zeros((n_features, n_features))
for k in range(n_classes):
    class_scatter = np.cov(X[y == k], rowvar=False, bias=True)
    S_W += class_scatter

# average variance across all classes
shared_variance = np.mean(np.diag(S_W))

각 class마다 공분산을 계산하고 전부 더해준다.(전체적인 퍼짐정도를 보기 위해)

LDA는 모든 class가 같은 분산을 이용한 것이 전제이고 분산을 찾고있으니깐 대각 행렬만(각 feature들의 분산임) 뽑아준다 

구한 class 3개의 분산을 평균을 내서 이용한다.

여기서 궁금했던 부분은 이 코드인데

class_scatter = np.cov(X[y == k], rowvar=False, bias=True)

행과 열 중 각각을 변수로 볼지 샘플로 볼지 정하는 것이다.

이와 같은 상황에서는 row를 샘플로 보고 column을 변수로 보는 것이다.

따라서 rowvar=false인경우다.

반대의 경우가(row를 변수로 보고 column을 샘플로 보는 것) default다.

# prior probabilities for each class
class_priors = np.array([np.mean(y == k) for k in range(n_classes)])

사전 분포도 gaussian 분포를 따른다고 가정했으므로 각 class 별 평균을 계산한다.

discriminant score식에 각각 대입하여 어떤 클래스에 속하는지 예측을 완료한다.

predictions = np.apply_along_axis(discriminant_function, 1, X)

이 코드는 shape이 (150,4)인 X에 대하여 axis=1(row)방향으로 discriminant_function을 적용하는 것이다.

여기서 X는 row가 각 sample, column이 각 feature로 구성된 dataframe이다.