jjinyeok 성장일지

머신 러닝 #2 - KNN & Logistic Regression 2022/08/22~2022/08/29 본문

[KT AIVLE School]

머신 러닝 #2 - KNN & Logistic Regression 2022/08/22~2022/08/29

jjinyeok 2022. 8. 29. 20:16

1. K-Nearest Neighbors

  KNN (K-Nearest Neighbors) 알고리즘은 regression 문제와 classification 문제 모두 사용 가능하다. 오늘의 강의에서는 KNN 알고리즘을 사용하여 regression 문제를 해결하는 방법을 중심으로 KNN을 설명해주셨다. KNN 알고리즘은 거리를 계산하여 y를 추정하는 기본 알고리즘이다. KNN 알고리즘은 Nonparametric Method로 데이터를 학습한다는 컨셉의 모델이 아닌 데이터 자체를 그대로 사용하는 모델로 모든 데이터를 저장한다는 특징을 가지고 있다. KNN 알고리즘은 Instance-Based Learnig (사례 기반 학습)이라고 할 수도 있는데 새로운 데이터를 지난 데이터를 통해 예측하는 알고리즘이기 때문이다. KNN에 대한 더 자세한 컨셉은 시간이 되면 추가적으로 정리하도록 하겠다.

  KNN 알고리즘의 과정은 다음과 같다.

  1. 예측해야 할 데이터(X_test 또는 X_validation)와 주어진 데이터(X_train)의 모든 거리를 계산한다.
  2. 가까운 거리의 데이터를 k개만큼 찾는다.
  3. k개 값의 평균을 계산하여 데이터(X_test 또는 X_validation)를 예측한다.

  KNN 알고리즘은 데이터의 분포 형태와 상관이 없고 feature의 개수가 많아도 무리 없이 사용 가능하다는 장점이 있지만 모든 train 데이터와 계산을 해야하기 때문에 계산시간이 오래 걸리고 훈련 데이터를 모델에 함께 저장하기 때문에 모델의 크기가 크다는 단점이 있다. 또한 모델이 하나의 수식으로 나타나지 않기 때문에 각 feature와 target 간의 관계를 해석하기 어렵다는 단점도 존재한다.

 

2. KNN에서 신경써야 할 부분: Hyperparameter & Scaling

  모델을 구성할 때 사람이 직접 개입해서 변수를 지정해주어야 하는 경우 그 변수를 Hyperparameter라 부른다. Hyperparameter를 어떤 값으로 지정했느냐에 따라 모델의 성능이 바뀌게 되기에 Hyperparameter를 지정할 때는 반복적인 테스트를 통해 최적의 값을 찾아내는 것이 중요하다. KNN에서 가까운 거리의 데이터를 몇개 찾을지 결정하는 k(n_neighbors)와 어떤식으로 거리를 계산할지 정하는 거리계산법(metric) Hyperparameter의 역할을 한다. 두 Hyperparameter 모두 반복적인 테스트를 통해 최적의 값을 찾아내는 것이 중요하지만 k는 보통 train 데이터 건수의 제곱근 근처에서 테스트를 통해 최적값을 찾아가고 거리계산법은 Euclidean Distance(유클리드 거리 계산법) 또는 Manhattan Distance(맨해튼 거리 계산법)을 사용한다고 하니 참고하자.

  KNN은 예측해야 할 데이터(X_test 또는 X_validation)와 주어진 데이터(X_train)의 거리를 계산하는 알고리즘이다. 이때 feature들 값의 범위와 단위가 각각 다르기 때문에 값의 범위가 큰 feature가 거리 계산에 더 영향을 많이 주게 된다. 따라서 모든 feature 값의 범위를 맞춰주는 작업이 필수적이다. 이때 Scaling을 사용한다. 추가적으로 다른 거리를 계산하는 알고리즘 (SVM 등) 에서도 Scaling 작업은 필수임에 유의하자. 자세한 스케일링 기법은 이전 데이터처리 과정을 참고하자.

2022.08.15 - [[KT AIVLE School]] - 데이터 처리 #2 - 2022/08/08~2022/08/09

 

데이터 처리 #2 - 2022/08/08~2022/08/09

앞선 강의는 데이터를 정리하고 이해하는 과정이었다. 이번 과정은 모델링을 위한 데이터 전처리에 관한 과정이다. 1. 전처리가 필요한 이유는? 모델링을 위해 데이터는 필수적인 요건 2가지와

jjinyeok.tistory.com

 

3. KNN 실습

print(data.head()) # 보스턴 집값 데이터
#       crim    zn  indus  chas    nox     rm   age     dis  rad  tax  ptratio  lstat  medv
# 0  0.00632  18.0   2.31     0  0.538  6.575  65.2  4.0900    1  296     15.3   4.98  24.0   
# 1  0.02731   0.0   7.07     0  0.469  6.421  78.9  4.9671    2  242     17.8   9.14  21.6 
# 2  0.02729   0.0   7.07     0  0.469  7.185  61.1  4.9671    2  242     17.8   4.03  34.7  
# 3  0.03237   0.0   2.18     0  0.458  6.998  45.8  6.0622    3  222     18.7   2.94  33.4 
# 4  0.06905   0.0   2.18     0  0.458  7.147  54.2  6.0622    3  222     18.7   5.33  36.2

'1. 데이터 전처리'
# 1-1. 변수 처리
pass # 처리할 변수가 존재하지 않음

# 1-2. X, y 분할
# y는 medv(집값)이므로 regression 문제임
target = 'medv'
X = data.drop(target, axis=1)
y = data.loc[:, target]

# 1-3. NaN 조치
X.isna().sum() # X에 NaN 없음 확인
y.isna().sum() # y에 NaN 없음 확인

# 1-4. 가변수화
pass # data에 범주형 데이터가 존재하지 않음

# 1-5. 데이터 분할
from sklearn.model_selection import train_test_split
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.3)

# 1-6. 스케일링 (KNN 과정에서 필수)
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
X_train_s = scaler.fit_transform(X_train)
X_val_s = scaler.transform(X_val)

'2. 모델링'
from sklearn.neighbors import KNeighborsRegressor
model = KNeighborsRegressor() # n_neighbors의 default는 5, metric의 default는 'minkowski'
model.fit(X_train_s, y_train)

'3. 검증'
from sklearn.metrics import mean_squared_error, mean_absolute_error, mean_absolute_percentage_error
pred = model.predict(X_val_s)
print(mean_squared_error(y_val, pred, squared=False)) # mse
# 4.269646540282623
print(mean_absolute_error(y_val, pred)) # mae
# 2.7598684210526314
print(mean_absolute_percentage_error(y_val, pred)) # mape
# 0.12356547038089391

  위 실습에서 MinMaxScaler를 사용하여 Scaling을 했지만 StandardScaler를 비롯한 다른 Scaler를 사용하여 성능을 바꿀 수 있다. 물론 Hyperparameter의 조절을 통한 성능 변경도 가능하다. KNN 모델을 선언할 때, k값을 의미하는 n_neighbors는 5가 default 값이고 거리 계산법을 의미하는 metric은 'minkowski'이다. 두 Hyperparameter를 조절하여 다른 성능의 모델도 만들 수 있음에 유의하자.

 

4. Logistic Regression

  이전 Linear Regression은 Regression 문제 해결을 위한 모델로 범위가 -∞~∞이다. 만일 우리가 Classification 문제를  풀고 싶다면 우리는 Linear Regression에서 값의 범위를 0~1 (0: False, 1: True)로 변환할 필요가 있다. 이때 Logistic 함수(Sigmoid 함수)를 이용한다. 기존 Linear Regression 수학식인 f(x)에 대해 로지스틱함수를 적용하면 값의 범위는 0~1로 Logistic 함수의 결과 값은 1과 0 사이의 확률 값을 계산하게 된다. 즉 이산값인 target y에 대해 새로운 입력이 어떤 클래스에 속해야 하는지 결정하기 위해 Logistic Regression 알고리즘을 사용한다. 기존 Linear Regression의 수식을 f(x)라 했을 때 Logisitic Regression의 수식과 그래프는 다음과 같다.

로지스틱(시그모이드) 함수는 각 클래스(이산 값) 간의 경계선(Decision Boundary)을 찾아낸다.

 

5. Logistic Regression 실습

  Logistic Regression은 어떤 Hyperparameter를 쓰는가 혹은 Scaling 여부에 따라 성능이 크게 바뀌지 않는다. 성능 향상에 중요한 것은 어떤 feature X를 사용할 것인지 선택하는 과정이며 Linear한 모델인 Linear Regression, Logistic Regression 모두 해당된다. 이는 뒤에 성능 정리에서 다루도록 하겠다. 먼저 실습 과정을 통해 Logistic Regression을 정리해보자.

print(data.head()) # 이동통신 가입 고객 데이터
#    id  COLLEGE  INCOME  OVERAGE  LEFTOVER   HOUSE  HANDSET_PRICE  \
# 0   1        0   31953        0         6  313378            161   
# 1   2        1   36147        0        13  800586            244   
# 2   3        1   27273      230         0  305049            201   
# 3   4        0  120070       38        33  788235            780   
# 4   5        1   29215      208        85  224784            241   

#    OVER_15MINS_CALLS_PER_MONTH  AVERAGE_CALL_DURATION REPORTED_SATISFACTION  \
# 0                            0                      4                 unsat   
# 1                            0                      6                 unsat   
# 2                           16                     15                 unsat   
# 3                            3                      2                 unsat   
# 4                           21                      1            very_unsat   

#   REPORTED_USAGE_LEVEL CONSIDERING_CHANGE_OF_PLAN  CHURN  
# 0               little                         no   STAY  
# 1               little                considering   STAY  
# 2          very_little                    perhaps   STAY  
# 3            very_high                considering  LEAVE  
# 4               little              never_thought   STAY  

'1. 데이터 전처리'
# 1-1. 변수 처리
data.drop(['id'], axis = 1, inplace = True)

# 1-2. X, y 분할
# y는 CHURN(가입 고객 이탈여부)이므로 classification 문제
target = 'CHURN'
X = data.drop(target, axis=1)
y = data.loc[:, target]

# 1-3. NaN 처리
X.isna().sum() # X에 NaN 없음 확인
y.isna().sum() # y에 NaN 없음 확인

# 1-4. 가변수화
dumm_cols = ['REPORTED_SATISFACTION','REPORTED_USAGE_LEVEL','CONSIDERING_CHANGE_OF_PLAN']
X = pd.get_dummies(X, columns = dumm_cols, drop_first = True)

# 1-5. 데이터 분할
from sklearn.model_selection import train_test_split
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.3)

# 1-6. 스케일링 (Logistic Regression 과정에서 필수가 아니므로 pass)
pass

'2. 모델링'
from sklearn.linear_model import LogisticRegression
model = LogisticRegression()
model.fit(X_train, y_train)

'3. 검증'
pred = model.predict(X_val)
from sklearn.metrics import confusion_matrix, classification_report
print(confusion_matrix(y_val, pred)) # confusion matrix
# [[1820 1145]
# [1086 1949]]
print(classification_report(y_val, pred)) # classification_report
#               precision    recall  f1-score   support

#        LEAVE       0.62      0.64      0.63      2868
#         STAY       0.66      0.65      0.65      3132

#     accuracy                           0.64      6000
#    macro avg       0.64      0.64      0.64      6000
# weighted avg       0.64      0.64      0.64      6000

 

6. 분류 모델 평가

  분류 문제를 평가할 때 우리는 Confusion Matrix를 사용한다. 이진 분류에서 Confustion Matrix는 다음과 같다.

  예측 결과 (ŷ)
True (Positive) False (Negative)
실제값 (y) True (Positive) True Positive False Negative
False (Negative) False Positive True Negative

  Confustion Matrix를 통해 accuray, recall, precision, f1-score를 구하고 분류 문제를 평가할 수 있다. 첫번째로 accuray는 정분류율로 전체 관점에서 전체 데이터를 기준으로 맞춘 수를 계산한 값이다. 즉 위 Confustion Matrix에서 (TP + TN) / (TP + FP + FN + TN) 값이다. 두번째로 recall은 재현율로 특정 class를 관점으로 한다. 특정 class를 기준으로 맞춘 수를 계산한 값으로 위의 Confustion Matrix에서 True를 기준으로 한다면 TP / (TP + FN) 값이다. 세번째로 precision은 정밀도recall과 마찬가지로 특정 class를 관점으로 한다. 해당 class라고 예측한 것 중 맞춘 비율로  Confustion Matrix에서 True를 기준으로 한다면 TP / (TP + FP) 값이다. f1-score는 precision과 recall의 조화 평균으로 precisionrecall을 균형 있게 볼 수 있는 지표가 된다.

  sklearn.metrics의 confusion_matrix() 함수를 통해 Confusion Matrix를 확인할 수 있다. 또한 sklearn.metrics의 classification_report() 함수를 통해 accuray, recall, precision, f1-score를 모두 확인할 수 있으며 하단의 macro avg는 평균을 weighted avg는 데이터 개수에 따른 가중 평균임에 유의하자.

Comments