본문 바로가기
수학

제1장

by 자동매매 2023. 12. 27.

 

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from mpl_toolkits import mplot3d
import matplotlib.font_manager as mfm

# numpy 출력 형식 지정
np.set_printoptions(precision=4, linewidth=150)


# matplotlib 스타일 지정
st = plt.style.available  # 사용가능 스타일 확인
mpl.style.use("bmh")
mpl.style.use("seaborn-v0_8-whitegrid")
style = plt.style.library["bmh"]

# 스타일 컬러를 쉽게 쓸 수 있도록 리스트 저장
style_colors = [c["color"] for c in style["axes.prop_cycle"]]

# 그림을 컬러로 출력하고 싶으면 True로 수정
g_color = True

# 그림을 로컬 폴더에 저장하고 싶으면 True로 수정
file_print = True
# 로컬 환경일 경우 그래프에 한글 폰트 사용을 위한 설정
# https://financedata.github.io/posts/matplotlib-hangul-for-ubuntu-linux.html
# 아래 코드의 주석 제거 후 경로를 유저 컴퓨터의 폰트 파일 경로로 수정하세요.
# path = r"C:\Users\neo21\AppData\Local\Microsoft\Windows\Fonts\NanumGothic.ttf"
# fontprop = mfm.FontProperties(fname=path, size=18)
# !주의! 
# 구글 colab 환경에서 실행하는 경우만 실행하세요.
# 로컬환경에서는 실행하지 마세요.

# 데이터 파일 사용을 위한 github repo 복사
# !git clone -l -s https://github.com/metamath1/noviceml.git noviceml

# 구글 colab 환경일 경우 그래프에 한글 폰트 사용을 위한 설정
# path = 'noviceml/font/NanumBarunGothic.ttf'
# fontprop = mfm.FontProperties(fname=path, size=18)
# Unicode warning 제거 (폰트 관련 경고메시지)
plt.rcParams["axes.unicode_minus"] = False

# 한글 폰트 설정
plt.rcParams["font.family"] = "Malgun Gothic"

# 그래프 출력 사이즈 설정
plt.rcParams["figure.figsize"] = (10, 8)

 

# 데이터를 두벌 마련합니다.
# D1은 앞서 예제로 들었던 최초 점 6개짜리 데이터입니다.
# D2는 D1에 제일 왼쪽점 하나가 더 추가된 데이터입니다.
D1 = np.array([[1.0, 1.2, 3, 4, 5, 6], [1.7, 3, 2.3, 5.3, 3.8, 5.5]])
D2 = np.array([[-0.6, 1.0, 1.2, 3, 4, 5, 6], [2.9, 1.7, 3, 2.3, 5.3, 3.8, 5.5]])

그림 1-4

fig, (ax1, ax2) = plt.subplots(1, 2, sharex=True, sharey=True)
fig.set_size_inches((15,6))

ax1.xaxis.set_tick_params(labelsize=18)
ax1.yaxis.set_tick_params(labelsize=18)
ax1.set_xlabel('$x$', fontsize=25)
ax1.set_ylabel('$y$', fontsize=25)
ax1.grid(False)

ax2.xaxis.set_tick_params(labelsize=18)
ax2.yaxis.set_tick_params(labelsize=18)
ax2.set_xlabel('$x$', fontsize=25)
ax2.set_ylabel('$y$', fontsize=25)
ax2.grid(False)

ax1.plot(D1[0], D1[1], 'ko', markersize=10)
ax1.set_xlim([-1,7])
ax1.set_ylim([1,6])
ax1.set_title('D1', fontsize=18)

ax2.plot(D2[0], D2[1], 'ko', markersize=10)
ax2.set_xlim([-1,7])
ax2.set_ylim([1,6])
ax2.set_title('D2', fontsize=18)

if file_print == True :
    fig.savefig("imgs/chap1/fig1-4.png", dpi=300, bbox_inches='tight')
    fig.savefig("imgs/chap1/fig1-4.pdf", format='pdf', bbox_inches='tight')


plt.show()

 

머신 러닝과 more_clever() 비교

def machine_learning(D):
    """
    선형회귀 알고리즘을 사용하여 최적의 직선을 계산합니다.
    D : (2,N)의 어레이로 1행에는 데이터의 x좌표
        2행에는 데이터의 y좌표가 저장 되어 있습니다.
    """
    # 데이터의 개수를 N에 할당합니다.
    N = D.shape[1] 

    # 1열에 1, 2열에 데이터의 x좌표를 가지는 행렬을 만듭니다.
    # X: (N,2), y: (N,)
    X = np.c_[np.ones(N), D[0]]
    y = D[1]

    # 앞으로 배울 정규방정식을 풀어서 직선의 계수를 구합니다.
    w = np.linalg.solve(np.dot(X.T, X), np.dot(X.T, y))
    return w

def more_clever(D):
    """
    첫점과 끝점을 연결하는 직선을 계산합니다.
    D : (2,N)의 어레이로 1행에는 데이터의 x좌표
        2행에는 데이터의 y좌표가 저장 되어 있습니다.
    """
    first, last = D[:,0], D[:,-1]

    w1 = (last[1]-first[1]) / (last[0]-first[0])
    w0 = -w1*first[0] + first[1]

    return (w0, w1)

def f(x, w):
    """
    주어진 w를 사용하여 직선 f(x) = w[1]*x + w[0]의 값을 계산합니다.
    """
    return w[1]*x + w[0]
# D1에 대해서 w[1]*x + w[0]에서 w[0], w[1]을 구합니다.
w_ml_d1 = machine_learning(D1)
w_mc_d1 = more_clever(D1)

# D2에 대해서 w[1]*x + w[0]에서 w[0], w[1]을 구합니다.
w_ml_d2 = machine_learning(D2)
w_mc_d2 = more_clever(D2)

print(w_ml_d1)
[1.5108 0.6206]

 

그림 1-5

x = np.linspace(-1, 7, 100)

fig, (ax1, ax2) = plt.subplots(1, 2, sharex=True, sharey=True)
fig.set_size_inches((15,6))

ax1.xaxis.set_tick_params(labelsize=18)
ax1.yaxis.set_tick_params(labelsize=18)
ax1.set_xlabel('$x$', fontsize=25)
ax1.set_ylabel('$y$', fontsize=25)
ax1.grid(False)

ax2.xaxis.set_tick_params(labelsize=18)
ax2.yaxis.set_tick_params(labelsize=18)
ax2.set_xlabel('$x$', fontsize=25)
ax2.set_ylabel('$y$', fontsize=25)
ax2.grid(False)

ax1.plot(D1[0], D1[1], 'ko', markersize=10)
ax1.plot(x, f(x, w_ml_d1), c='k', lw=2, label='machine learning')
ax1.plot(x, f(x, w_mc_d1), '--', c='k', lw=2, label='more clever')
ax1.set_xlim([-1,7])
ax1.set_ylim([1,6])
ax1.legend(fontsize=18)

ax2.plot(D2[0], D2[1], 'ko', markersize=10)
ax2.plot(x, f(x, w_ml_d2), c='k', lw=2, label='machine learning')
ax2.plot(x, f(x, w_mc_d2), '--', c='k', lw=2, label='more clever')
ax2.set_xlim([-1,7])
ax2.set_ylim([1,6])
ax2.legend(fontsize=18)

# 그림이 저장될 로컬 폴더를 적당히 설정후 실행하세요.
if file_print == True :
    fig.savefig("imgs/chap1/fig1-5.png", dpi=300, bbox_inches='tight')
    fig.savefig("imgs/chap1/fig1-5.pdf", format='pdf', bbox_inches='tight')

plt.show()

그림 1-7

W = np.array([[1.0, 0.3],[3.3, 0.42],[3.0, 0.2],[1.5, 0.6]])

fig, ax = plt.subplots(2, 2, sharex='all', sharey='all')
fig.set_size_inches((16,13))

for j in range(W.shape[0]):
    w0, w1 = W[j,0], W[j,1]
    y=f(D1[0], [w0, w1])
    loss = 0.0

    ax[j // 2, j % 2].xaxis.set_tick_params(labelsize=18)
    ax[j // 2, j % 2].yaxis.set_tick_params(labelsize=18)
    ax[j // 2, j % 2].set_xlabel('$x$', fontsize=25)
    ax[j // 2, j % 2].set_ylabel('$y$', fontsize=25)
    ax[j // 2, j % 2].plot(x, f(x, [w0,w1]), c='k', lw=2, label='machine learning')
    ax[j // 2, j % 2].grid(False)

    for i in range(len(y)):
        loss+=np.abs(D1[1,i]-y[i])
        ax[j // 2, j % 2].plot([D1[0,i], D1[0,i]],[D1[1,i], y[i]],'k--')

    ax[j // 2, j % 2].plot(D1[0], D1[1], 'ko', markersize=10)
    ax[j // 2, j % 2].set_xlim([-1,7])
    ax[j // 2, j % 2].set_ylim([1,6])
    ax[j // 2, j % 2].set_title('D1, loss:{:f}'.format(loss), fontsize=18)


# Hide x labels and tick labels for top plots and y ticks for right plots.
for ax_ in ax.flat:
    ax_.label_outer()

plt.subplots_adjust(hspace=0.1, wspace=0.05)

# 그림이 저장될 로컬 폴더를 적당히 설정후 실행하세요.
if file_print == True :
    fig.savefig("imgs/chap1/fig1-7.png", dpi=300, bbox_inches='tight')
    fig.savefig("imgs/chap1/fig1-7.pdf", format='pdf', bbox_inches='tight')

plt.show()

 

그림 1-8

num_iters = 150
alpha = 0.02

np.random.seed(2)
w = np.random.randn(2)
N = D1.shape[1] 

ws, L = [], []

# 1열에 1, 2열에 데이터의 x좌표를 가지는 행렬을 만듭니다.
# X: (N,2), y: (N,)
X = np.c_[np.ones(N), D1[0]]
y = D1[1]

# 여기서 우리의 경험 E를 반복하면서 태스크 T를 개선해 나간다.
for i in range(num_iters) :
    # grad L
    c = (1/N) * np.dot(X.T, np.dot(X, w) - y) 
    # 안전장치 grad L을 이용해서 w를 수정한다.
    w -= alpha * c 
    # w가 변화되는 과정을 저장해둔다.
    ws.append(w)

    # 손실을 계산한다.
    L.append( ((np.dot(X, w) - y)**2).sum()/(2*N) )

x = np.linspace(-1, 7, 100)

fig, (ax1, ax2) = plt.subplots(1, 2)
fig.set_size_inches((15,6))

ax1.xaxis.set_tick_params(labelsize=18)
ax1.yaxis.set_tick_params(labelsize=18)
ax1.set_xlabel('$x$', fontsize=25)
ax1.set_ylabel('$y$', fontsize=25)
ax1.grid(False)

ax2.xaxis.set_tick_params(labelsize=18)
ax2.yaxis.set_tick_params(labelsize=18)
ax2.set_xlabel('$x$', fontsize=25)
ax2.set_ylabel('$y$', fontsize=25)
ax2.grid(False)

ax1.plot(D1[0], D1[1], 'ko', markersize=8)
ax1.plot(x, f(x, w), c='k', lw=2, label='machine learning')
ax1.set_xlim([-1,7])
ax1.set_ylim([1,6])
ax1.legend(fontsize=18)

ax2.plot(L[:50], '--', c='k', label='loss')
ax2.legend(fontsize=18)

# 그림이 저장될 로컬 폴더를 적당히 설정후 실행하세요.
if file_print == True :
    fig.savefig("imgs/chap1/fig1-8.png", dpi=300, bbox_inches='tight')
    fig.savefig("imgs/chap1/fig1-8.pdf", format='pdf', bbox_inches='tight')

plt.show()

그림 1-10

import pandas as pd

# github파
faithful = pd.read_csv('noviceml/faithful.csv')
faithful.head()

faithful = (faithful - faithful.mean()) / faithful.std()
faithful.columns = ['eruptions', 'waiting']

# fig, ax = plt.subplots(2, 2)
# fig.set_size_inches(15,10)

fig, ax = plt.subplots(2, 2, sharex='all', sharey='all')
fig.set_size_inches((16,13))

ax[0,0].plot(faithful.eruptions, faithful.waiting, 'k.',  fillstyle='none', markersize=8)
ax[0,0].set_title('Old Faithful Data Scatterplot', fontsize=18)
ax[0,0].xaxis.set_tick_params(labelsize=18)
ax[0,0].yaxis.set_tick_params(labelsize=18)
ax[0,0].set_xlabel('Length of eruption (minutes)', fontsize=18)
ax[0,0].set_ylabel('Time between eruptions (minutes)', fontsize=18)
ax[0,0].grid(False)

centroids = np.array([[-1.3, 1.0], [1.2, -1.0]])
ax[0,1].plot(faithful.eruptions, faithful.waiting, 'k.', fillstyle='none', markersize=8)
ax[0,1].plot(centroids[0,0], centroids[0,1], 'kx', markersize=10, markeredgewidth=5)
ax[0,1].plot(centroids[1,0], centroids[1,1], 'ko', markersize=10, markeredgewidth=5)
ax[0,1].xaxis.set_tick_params(labelsize=18)
ax[0,1].yaxis.set_tick_params(labelsize=18)
ax[0,1].set_xlabel('Length of eruption (minutes)', fontsize=18)
ax[0,1].set_ylabel('Time between eruptions (minutes)', fontsize=18)
ax[0,1].grid(False)

faith = np.array(faithful)
k = 2

# 클러스터링 과정을 5회 반복한다.
for i in range(2):
    # faith에 저장된 272개의 점에 대해 각각 점이 클러스터 0인지 클러스터 1인지를 기록하는 2차원 어레이
    # 아래처럼 272행 k(클러스터 수)열인 2차원 어레이
    #
    # rnk 어레이는 다음처럼 행번호에 해당하는 점이 열번호에 해당하는 묶음에 할당되면 1, 아니면 0으로 표시한다.
    #
    # rnk = [ [1, 0],      첫번째 점은 0번 묶음이다.
    #         [0, 1],      두번째 점은 1번 묶음이다.
    #         ...   ,
    #         ...   ,
    #         [1, 0] ]     272번째 점은 0번 묶음이다.
    #
    # 처음에는 모두 0으로 초기화
    rnk_row = faith.shape[0]
    rnk_col = k
    rnk = np.zeros( (rnk_row, rnk_col) )

    # 1) 모든 데이터에 대해서 초기 중심점과의 간격을 계산하여 더 가까운쪽의 묶음으로 데이터를 할당한다.
    # 각점이 어느 클러스터에 속하는지 rnk 어레이에 표시한다.
    for n in range(faith.shape[0]):
        # 각 데이터 포인트를 x에 받아와서
        x = faith[n]

        # 현재 중심점 2개 centroids[0]와 centroids[1]간의 거리를 구해서 비교한다.
        # 초기 중심점은 다음처럼 윗셀에서 초기화 했다.
        # centroids = np.array([[-1.3, 1.0], [1.2, -1.0]])
        # 각 중심점에서 x까지 거리를 구하는 법 : np.linalg.norm(x-centroids[0]), np.linalg.norm(x-centroids[1])
        dist_0 = np.linalg.norm(x-centroids[0])
        dist_1 = np.linalg.norm(x-centroids[1]) 
        if dist_0 < dist_1 :
            rnk[n,0] = 1
        else :
            rnk[n,1] = 1

    # 그림을 그리기위해 faith에 저장된 점데이터를 파랑과 빨강으로 분류 한다.
    # 앞서 만든 rnk 어레이의 상태에 따라 두 부분으로 나눈다.
    blue = faith[np.where(rnk[:,0]==1)]
    red  = faith[np.where(rnk[:,1]==1)]

    ##########################################################################################
    # 2) 위 작업이 완료되면 두 묶음으로 분리된 데이터의 평균점을 구한다.
    # 힌트 : 지금 두 묶음은 위의 blue, red 어레이에 각각 들어가 있고
    # blue 어레이에 저장된 점의 평균을 centroids[0]에 할당하고
    # red 어레이에 저장된 점의 평균을 centroids[1]에 할당한다.
    # 어레이의 평균을 구하기 위해서는 mean 함수를 사용한다.
    # mean함수 문서 : https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.mean.html
    centroids[0] = blue.mean(axis=0)
    centroids[1] = red.mean(axis=0)

    # 한번 반복 후 클러스터링 상황을 그린다.
    ax[1,i].plot(blue[:,0], blue[:,1],'kx', fillstyle='none', markersize=8, alpha=0.7)
    ax[1,i].plot(red[:,0],  red[:,1], 'ko', fillstyle='none', markersize=8, alpha=0.7) 
    ax[1,i].plot(centroids[0,0], centroids[0,1], 'kx', markersize=10, markeredgewidth=5)
    ax[1,i].plot(centroids[1,0], centroids[1,1], 'ko', markersize=10, markeredgewidth=5)   

    ax[1,i].xaxis.set_tick_params(labelsize=18)
    ax[1,i].yaxis.set_tick_params(labelsize=18)
    ax[1,i].set_xlabel('Length of eruption (minutes)', fontsize=18)
    ax[1,i].set_ylabel('Time between eruptions (minutes)', fontsize=18)
    ax[1,i].grid(False)

# Hide x labels and tick labels for top plots and y ticks for right plots.
for ax_ in ax.flat:
    ax_.label_outer()

plt.subplots_adjust(hspace=0.05, wspace=0.05)

# 그림이 저장될 로컬 폴더를 적당히 설정후 실행하세요.
if file_print == True :
    fig.savefig("imgs/chap1/fig1-10.png", dpi=300, bbox_inches='tight')
    fig.savefig("imgs/chap1/fig1-10.pdf", format='pdf', bbox_inches='tight')

plt.show()

그림 1-11

np.random.seed(0)
P = np.random.normal(loc=5.0, scale=2.0, size=10)

fig = plt.figure(figsize=(10,7))
ax = fig.add_subplot(1, 1, 1)
ax.xaxis.set_tick_params(labelsize=18)
ax.yaxis.set_tick_params(labelsize=18)
ax.set_xlabel('$x$', fontsize=25)
ax.set_ylabel('$y$', fontsize=25)
ax.grid(False)

plt.plot(P, 'ko', markersize=8)
plt.plot(np.arange(10), [P.mean()]*10, 'k--', label='mean')
plt.legend(fontsize=18)

# 그림이 저장될 로컬 폴더를 적당히 설정후 실행하세요.
if file_print == True :
    fig.savefig("imgs/chap1/fig1-11.png", dpi=300, bbox_inches='tight')
    fig.savefig("imgs/chap1/fig1-11.pdf", format='pdf', bbox_inches='tight')

plt.show()

그림 1-12

def dist(x1, x2):
    return np.abs(x1-x2)

def knn_point(D, p, k=3):
    return sorted(D, key=lambda e: dist(e[0], p) )[:k]

fig, ax = plt.subplots(1,3, sharey=True)
fig.set_size_inches(24,6)

x = np.linspace(-1, 7, 100)

# knn
for i, k in enumerate([1, 3]):
    y_pred = []
    for p in x :
        ps = knn_point(D1.T, p, k)
        y_pred.append(np.asarray(ps)[:,1].mean())

    ax[i].plot(D1[0], D1[1], 'ko', markersize=8)    
    ax[i].plot(x, y_pred, c='k')
    ax[i].set_title("k={}".format(k), fontsize=18)
    ax[i].xaxis.set_tick_params(labelsize=18)
    ax[i].yaxis.set_tick_params(labelsize=18)
    ax[i].set_xlabel('$x$', fontsize=25)
    ax[i].set_ylabel('$y$', fontsize=25)
    ax[i].grid(False)

# linear regression
w_ml_d1 = machine_learning(D1)
ax[2].plot(D1[0], D1[1], 'ko', markersize=8) 
ax[2].plot(x, f(x, w_ml_d1), c='k', lw=2, label='machine learning')
ax[2].set_title('Lienar regression', fontsize=18)
ax[2].xaxis.set_tick_params(labelsize=18)
ax[2].yaxis.set_tick_params(labelsize=18)
ax[2].set_xlabel('$x$', fontsize=25)
ax[2].set_ylabel('$y$', fontsize=25)
ax[2].grid(False)

# 그림이 저장될 로컬 폴더를 적당히 설정후 실행하세요.
if file_print == True :
    fig.savefig("imgs/chap1/fig1-12.png", dpi=300, bbox_inches='tight')
    fig.savefig("imgs/chap1/fig1-12.pdf", format='pdf', bbox_inches='tight')

plt.show()

'수학' 카테고리의 다른 글

제5장  (0) 2023.12.27
제4장  (0) 2023.12.27
제3장  (0) 2023.12.27
제2장  (0) 2023.12.27
제1장 완성  (0) 2023.12.22

댓글