Data Analysis/Machine Learning

Python_ML_Supervised_KNN

mansoorrr 2024. 2. 28. 22:54

KNN(K-최근접이웃)

  • KNN은 유사한 특징을 가진 데이터는 유사한 범주에 속하는 경향이 있다는 가정으로 데이터를 분류
  • 새로운 데이터가 등장하면 가장 가까운 k개(학습데이터)의 데이터를 찾음
  • 찾은 데이터를 통해 새로운 데이터를 레이블링
  • 비모수적인 방식을 사용하기 때문에 결정경계가 불규칙한 분류 상황에서 종종 예측성능이 좋음

 

[KNN 분류]

  • 새로운 데이터를 레이블링 하기 위해 주로 유클리디안 거리를 주로 사용
  • 경계가 뚜렷하지 않은 특징은 noise로 간주(노이즈를 고려한 파라미터 k를 설정해야함)

 

예시 1) kaggle 간질환자 데이터

  • 데이터정의

 

  • 전처리
liver.info()

#결측치확인
liver.isnull().sum() / liver.shape[0]

#결측치 제거: 수가 적으므로
liver.dropna(axis=0, inplace=True)
liver.isnull().sum()

#gender 수치화
liver["Gender"] = np.where(liver["Gender"]=="Female", 0, 1)
liver["Gender"].value_counts()

 

  • 데이터 분리
#데이터분리
X = liver.drop(["Dataset"], axis=1)
y = liver["Dataset"]

from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=.3, random_state=1)
print(x_train.shape, y_train.shape) #(405, 10) (405,)
print(x_test.shape, y_test.shape) #(174, 10) (174,)

 

  • 모델 학습 및 예측
#분류기 생성
from sklearn.neighbors import KNeighborsClassifier

knn = KNeighborsClassifier(n_neighbors=15, weights="uniform")

knn.fit(x_train, y_train)
pred = knn.predict(x_test)

from sklearn.metrics import confusion_matrix, classification_report

cm = confusion_matrix(y_test, pred)

'''
array([[107,  22],
       [ 31,  14]])
'''

cr = classification_report(y_test, pred)
'''
       
            precision    recall  f1-score   support

           1       0.78      0.83      0.80       129
           2       0.39      0.31      0.35        45

    accuracy                           0.70       174
   macro avg       0.58      0.57      0.57       174
weighted avg       0.68      0.70      0.68       174

'''

 

 

[KNN 회귀]

  • 가까운 이웃 데이터들을 고려하지만 개별값을 예측
  • 새로운 데이터가 들어오면 k개의 이웃데이터를 이용해 회귀선을 도출
  • 선형회귀와 달리 하나의 회귀선을 도출하지 않음
  • 주어진 입력을 바탕으로 가장 잘 예측된 평균 값들의 집합을 나타냄(회귀계수는 도출되지 않음)

예시1) 가데이터로 weights 에 따른 예측선 확인

  • 가데이터 생성
#샘플데이터 생성
X = np.sort(5 * np.random.rand(400, 1), axis=0)
y = np.sin(X).ravel()
T = np.linspace(0, 5, 500)[:, np.newaxis]

#노이즈추가
y[::1] += 1 * (0.5 - np.random.rand(400))

 

  • 데이터분리
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=.3, random_state=1)

 

  • 모델학습 및 예측
    • weights별로 차이 있음
#모델정의
from sklearn.neighbors import KNeighborsRegressor

knn_uni = KNeighborsRegressor(n_neighbors=20, weights="uniform")
knn_dis = KNeighborsRegressor(n_neighbors=20, weights="distance")

knn_uni.fit(x_train, y_train)
knn_dis.fit(x_train, y_train)

uni_pred = knn_uni.predict(x_test)
dis_pred = knn_dis.predict(x_test)

preds = [uni_pred, dis_pred]
weights = ["uniform", "distance"]
evals = ["mae", "mse", "rmse"]

results = pd.DataFrame(index=weights, columns=evals)

for pred, weight in zip(preds, weights):
  mae = mean_absolute_error(y_test, pred)
  mse = mean_squared_error(y_test, pred)
  rmse = mean_squared_error(y_test, pred, squared=False)

  results.loc[weight, "mae"] = mae
  results.loc[weight, "mse"] = mse
  results.loc[weight, "rmse"] = rmse
results

 

  • 시각화
#시각화
for i, weight in enumerate(weights):
  knnReg = KNeighborsRegressor(n_neighbors=20, weights=weight)

  new_pred = knnReg.fit(X, y).predict(T)

  plt.subplot(2, 1, i+1)
  plt.scatter(X, y, color="orange", label="org")
  plt.plot(T, new_pred, color="navy", label="predict")
  plt.axis("tight")
  plt.legend()
  plt.title(f"KNeighborsRegressor (k=5, weights='{weight}')")
plt.tight_layout()
plt.show();