728x90

❤️ 배운 것

2023-10-11 KNN Full Code

decision boundary를 위한 dataset 만들기 (using np.meshgrid)

def get_decision_boundary(x1_lim, x2_lim, X, y, K):  
    x1 = np.linspace(x1_lim[0], x1_lim[1], 100)  
    x2 = np.linspace(x2_lim[0], x2_lim[1], 100)  

    X1, X2 = np.meshgrid(x1, x2)  
    grid = np.column_stack((X1.flatten(), X2.flatten()))  
    pred_knn = list()  

    for g in grid:  
        _, _, y_hat = code8_classify(X, y, K, X_te=g)  
        pred_knn.append(y_hat)  

    pred_knn = np.array(pred_knn)  
    return grid, pred_knn

KNN 시각화 + decision boundary

def code9_knn_visualization(X, y, K, X_te):  
    class_colors = ['#FF5733', '#FFA500', '#008000', '#FF69B4']  
    knn_X, knn_y, y_hat = code8_classify(X, y, K, X_te)  

    fig, ax = plt.subplots(figsize=(7, 7))  

    # all data  
    ax.scatter(x=X[:, 0], y=X[:, 1], c=[class_colors[label] for label in y], alpha=0.5)  

    # to predict  
    ax.scatter(x=X_te[0], y=X_te[1], marker="*", s=300, color="dodgerblue")  
    ax.text(x=X_te[0]+1, y=X_te[1], s=f"class {y_hat}", color="hotpink", size=15)  

    # k nearest data  
    for i in range(len(knn_X)):  
        ax.plot([X_te[0], knn_X[i, 0]], [X_te[1], knn_X[i, 1]], color="dodgerblue")  

    # decision boundary  
    x1_lim, x2_lim = ax.get_xlim(), ax.get_ylim()  
    grid, pred_knn = get_decision_boundary(x1_lim, x2_lim, X, y, K)  

    target_cls = list(set(y))  
    for i in target_cls:  
        target_X = grid[pred_knn == i]  
        ax.scatter(target_X[:, 0], target_X[:, 1], alpha=0.04, color=class_colors[i])

Main Routine

def classify_knn(n_classes, n_data, K):  
    X, y, centroids = code6_knn_dataset(n_classes, n_data)  
    X_te = X[0]  
    code9_knn_visualization(X, y, K, X_te)
  • 코드 의존성 수정
  • parameter 최적화

Full Code

def code6_knn_dataset(n_classes, n_data):  
    np.random.seed(8)  
    centroids = np.array([np.random.uniform(low=-10, high=10, size=(2,)) for x in range(n_classes)])  
    target_cls = np.array([i for i in range(n_classes) for _ in range(n_data)])  
    data = None  

    for i, centroid in enumerate(centroids):  
        if i == 0:  
            data = get_data_from_centroid(centroid, n_data)  
            continue  

        curr_dataset = get_data_from_centroid(centroid, n_data)  
        data = np.vstack([data, curr_dataset])  

    return data, target_cls, centroids  


def code7_euclidean_distances(X, X_te=None):  
    # KNN: 테스트 데이터와 dataset에 들어있는 샘플들 사이의 거리 구하기  
    if X_te is None:  
        X_te = X[0]  

    e_dists = np.sqrt(np.sum((X - X_te)**2, axis=1))  
    return X_te, e_dists  


def code8_classify(X, y, K, X_te=None):  
    # test data가 어떤 클래스에 속하는지 구하기  
    K += 1  
    X_te, e_dists = code7_euclidean_distances(X, X_te)  
    ascending_idx = np.argsort(e_dists)  

    # get k values and predict  
    knn_X = X[ascending_idx][:K]  
    knn_y = y[ascending_idx][:K]  
    uniques, cnts = np.unique(knn_y, return_counts=True)  
    uniques = uniques.astype(dtype=np.int64)  
    most_frequent = np.argmax(cnts)  
    y_hat = uniques[most_frequent]  
    return knn_X, knn_y, y_hat  


def get_decision_boundary(x1_lim, x2_lim, X, y, K):  
    x1 = np.linspace(x1_lim[0], x1_lim[1], 100)  
    x2 = np.linspace(x2_lim[0], x2_lim[1], 100)  

    X1, X2 = np.meshgrid(x1, x2)  
    grid = np.column_stack((X1.flatten(), X2.flatten()))  
    pred_knn = list()  

    for g in grid:  
        _, _, y_hat = code8_classify(X, y, K, X_te=g)  
        pred_knn.append(y_hat)  

    pred_knn = np.array(pred_knn)  
    return grid, pred_knn  


def code9_knn_visualization(X, y, K, X_te):  
    class_colors = ['#FF5733', '#FFA500', '#008000', '#FF69B4']  
    knn_X, knn_y, y_hat = code8_classify(X, y, K, X_te)  

    fig, ax = plt.subplots(figsize=(7, 7))  

    # all data  
    ax.scatter(x=X[:, 0], y=X[:, 1], c=[class_colors[label] for label in y], alpha=0.5)  

    # to predict  
    ax.scatter(x=X_te[0], y=X_te[1], marker="*", s=300, color="dodgerblue")  
    ax.text(x=X_te[0]+1, y=X_te[1], s=f"class {y_hat}", color="hotpink", size=15)  

    # k nearest data  
    for i in range(len(knn_X)):  
        ax.plot([X_te[0], knn_X[i, 0]], [X_te[1], knn_X[i, 1]], color="dodgerblue")  

    # decision boundary  
    x1_lim, x2_lim = ax.get_xlim(), ax.get_ylim()  
    grid, pred_knn = get_decision_boundary(x1_lim, x2_lim, X, y, K)  

    target_cls = list(set(y))  
    for i in target_cls:  
        target_X = grid[pred_knn == i]  
        ax.scatter(target_X[:, 0], target_X[:, 1], alpha=0.04, color=class_colors[i])  


def classify_knn(n_classes, n_data, K):  
    X, y, centroids = code6_knn_dataset(n_classes, n_data)  
    X_te = X[0]  
    code9_knn_visualization(X, y, K, X_te)  


if __name__ == '__main__':  
    classify_knn(n_classes=4, n_data=100, K=5)  
    plt.show()

 

코드 기전

classify_knn(n_classes, n_data, K): 메인 루틴 KNN 데이터 생성하여 시각화
classify_knn(n_classes, n_data, K): 4개의 그룹으로 랜덤 데이터셋 생성
code7_euclidean_distances(X, X_te=None): 전체데이터셋 X와 X_te (테스트데이터)간의 euclidean distance 구하기
code8_classify(X, y, K, X_te=None): 테스트 데이터가 어떤 클래스에 해당하는지 분류
code9_knn_visualization(X, y, K, X_te):
 1) 모든 데이터셋의 scatter plot 그리기(클래스 별로 색 구분)
 2) 예측 데이터의 scatter plot을 별 모양으로 그리기
 3) K개의 nearest data points들과 예측데이터(별)간 line plot으로 연결시키기
 4) 10,000x10,000 크기의 meshgrid에 scatter plot하여 decision boundary 색 채우기

get_decision_boundary(x1_lim, x2_lim, X, y, K): decision boundary를 위한 데이터셋 구하기

 

 

💛 배운점/느낀점

- numpy boolean indexing을 이용하면 vector 연산을 활용하여 계산할 수 있어서 고차원 데이터에 비해 편리하게 데이터를 조작할 수 있다는 점을 느낌

- colormap 등 세부 조정하는 것에 익숙해질 필요가 있음..

- K-means clustering 구현 시작 예정

- CNN 합성곱 연산 자습중

 

반응형