ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TensorFlow 기초 18 - 다항회귀(Polynomial Regression)
    TensorFlow 2022. 12. 2. 15:32

     

    최소제곱법으로 회귀선 구하기 방법과 tf로 회귀선 구하기 방법2로 나눠서 작성했다.

    # 다항회귀 : Polynomial Regression - 비선형 데이터인 경우 다항식을 이용하여 다항회귀 처리 가능
    
    # tesnorflow를 이용하여 2차함수 회귀선 그리기
    
    import tensorflow as tf
    import numpy as np
    import matplotlib.pyplot as plt
    plt.rc('font', family='malgun gothic')
    plt.rcParams['axes.unicode_minus'] = False
    import random
    
    """
    # 다항 회귀 연습용 데이터 : 지역별 인구증가율과 고령인구비율(통계청 시각화 자료에서 발췌)
    x = [0.3, -0.78, 1.26, 0.03, 1.11, 0.24, -0.24, -0.47, -0.77, -0.37, -0.85, -0.41, -0.27, 0.02, -0.76, 2.66]
    y = [12.27, 14.44, 11.87, 18.75, 17.52, 16.37, 19.78, 19.51, 12.65, 14.74, 10.72, 21.94, 12.83, 15.51, 17.14, 14.42]
    
    # a, b, c 세 개의 변수 선언
    a = tf.Variable(random.random())
    b = tf.Variable(random.random())
    c = tf.Variable(random.random())
    
    # 잔차 제곱 평균 반환 함수
    def compute_loss():
        y_pred = a * x * x + b * x + c # yhat = ax² + bx + c
        loss = tf.reduce_mean((y - y_pred) ** 2)
        return loss
    
    optimizer = tf.keras.optimizers.Adam(learning_rate=0.05)
    
    for i in range(1000):
        optimizer.minimize(compute_loss, var_list=[a,b,c])
        
        if i % 100 == 99:
            print(i, 'a :', a.numpy(), ', b :', b.numpy(), ', loss :', compute_loss().numpy())
            
    line_x = np.arange(min(x), max(x), 0.01)
    line_y = a * line_x *line_x + b * line_x + c
    
    plt.plot(line_x, line_y, 'r-')
    plt.plot(x, y, 'bo') # 실제값
    plt.show()
    """
    
    # 다항 회귀 연습용 데이터 : 지역별 인구증가율과 고령인구비율(통계청 시각화 자료에서 발췌)
    plo_inc = [0.3, -0.78, 1.26, 0.03, 1.11, 0.24, -0.24, -0.47, -0.77, -0.37, -0.85, -0.41, -0.27, 0.02, -0.76, 2.66]
    pop_old = [12.27, 14.44, 11.87, 18.75, 17.52, 16.37, 19.78, 19.51, 12.65, 14.74, 10.72, 21.94, 12.83, 15.51, 17.14, 14.42]
    
    # plt.plot(plo_inc, pop_old, 'ro')
    # plt.xlabel('지역별 인구증가율')
    # plt.ylabel('고령인구비율')
    # plt.show()
    
    print('최소제곱법으로 회귀선 구하기')
    x_mean = sum(plo_inc) / len(plo_inc)
    y_mean = sum(pop_old) / len(pop_old)
    # 기울기, 절편 계산 a = sum(x - mean(x)) * (y - mean(y)) / sum(x - mean(x))², b = mean(y) - mean(x) * a
    
    a = sum([(y - y_mean) * (x - x_mean) for y, x in list(zip(pop_old, plo_inc))])
    a /= sum([(x - x_mean)**2 for x in plo_inc])
    b = y_mean - x_mean * a
    print('a :', a, ', b :', b)
    
    line_x = np.arange(min(plo_inc), max(plo_inc), 0.01)
    line_y = a * line_x + b
    
    plt.plot(plo_inc, pop_old, 'ro')
    plt.plot(line_x, line_y, 'b-')
    plt.xlabel('지역별 인구증가율')
    plt.ylabel('고령인구비율')
    plt.show()
    
    print('최소제곱법 말고 tf로 회귀선 구하기')
    a = tf.Variable(random.random()) # 기울기
    b = tf.Variable(random.random()) # 절편
    
    # y = ax + b
    def compute_loss():
        ypred = a * plo_inc + b
        loss = tf.reduce_mean((pop_old - ypred)**2)
        return loss
    
    optimizer = tf.keras.optimizers.Adam(learning_rate=0.05)
    
    for i in range(1, 1001):
        optimizer.minimize(compute_loss, var_list=[a,b])
        
        if i % 100 == 0:
            print(i, 'a :', a.numpy(), ', b :', b.numpy(), ', loss :', compute_loss().numpy())
    
    line_x = np.arange(min(plo_inc), max(plo_inc), 0.01)
    line_y = a * line_x + b
    
    plt.plot(plo_inc, pop_old, 'ro')
    plt.plot(line_x, line_y, 'b-')
    plt.xlabel('지역별 인구증가율')
    plt.ylabel('고령인구비율')
    plt.show()
    
    
    <console>
    최소제곱법으로 회귀선 구하기
    a : -0.355834147915461 , b : 15.669317743971302
    최소제곱법 말고 tf로 회귀선 구하기
    100 a : 0.20552501 , b : 5.124719 , loss : 120.71144
    200 a : 0.004973734 , b : 8.891983 , loss : 55.60652
    300 a : -0.14282945 , b : 11.667388 , loss : 25.759094
    400 a : -0.24142435 , b : 13.519631 , loss : 14.391236
    500 a : -0.30027393 , b : 14.625358 , loss : 10.868128
    600 a : -0.33152348 , b : 15.212525 , loss : 9.988979
    700 a : -0.34627187 , b : 15.48965 , loss : 9.81301
    800 a : -0.3524623 , b : 15.605964 , loss : 9.784808
    900 a : -0.35477188 , b : 15.64936 , loss : 9.781202
    1000 a : -0.35553664 , b : 15.663731 , loss : 9.780835

    잔차 제곱 평균 반환 수식 : ax² + bx + c

    기울기, 절편 계산 a = sum(x - mean(x)) * (y - mean(y)) / sum(x - mean(x))², b = mean(y) - mean(x) * a

     

    선형일 경우 시각화

     

     

    다항회귀 방법(비선형)

    print('다항회귀 : 비선형일 경우 사용')
    a = tf.Variable(random.random())
    b = tf.Variable(random.random())
    c = tf.Variable(random.random())
    
    # 잔차 제곱 평균 반환 함수
    def compute_loss2():
        y_pred = a * plo_inc * plo_inc + b * plo_inc + c # yhat = ax² + bx + c
        loss = tf.reduce_mean((pop_old - y_pred) ** 2)
        return loss
    
    optimizer = tf.keras.optimizers.Adam(learning_rate=0.05)
    
    for i in range(1000):
        optimizer.minimize(compute_loss2, var_list=[a,b,c])
        
        if i % 100 == 99:
            print(i, 'a :', a.numpy(), ', b :', b.numpy(), ', loss :', compute_loss().numpy())
            
    line_x = np.arange(min(plo_inc), max(plo_inc), 0.01)
    line_y = a * line_x *line_x + b * line_x + c
    
    plt.plot(plo_inc, pop_old, 'ro')
    plt.plot(line_x, line_y, 'b-')
    plt.xlabel('지역별 인구증가율')
    plt.ylabel('고령인구비율')
    plt.show()
    
    
    <console>
    다항회귀 : 비선형일 경우 사용
    99 a : 3.6720428 , b : -4.853299 , loss : 437.1123
    199 a : 3.665368 , b : -5.6806293 , loss : 471.43127
    299 a : 2.498158 , b : -4.0594373 , loss : 400.7987
    399 a : 1.418247 , b : -2.4626667 , loss : 338.33197
    499 a : 0.63158935 , b : -1.296304 , loss : 296.9518
    599 a : 0.10912019 , b : -0.52199644 , loss : 271.4591
    699 a : -0.21093011 , b : -0.04776672 , loss : 256.6256
    799 a : -0.39185336 , b : 0.22029804 , loss : 248.50278
    899 a : -0.4862474 , b : 0.36015433 , loss : 244.34001
    999 a : -0.531682 , b : 0.42747155 , loss : 242.35472

     

     

    다항회귀 : Polynomial Regression - 비선형 데이터인 경우 다항식을 이용하여 다항회귀 처리 가능

     

     

    비선형일 경우 시각화

     

     

    다항회귀 : 딥러닝 네트워크 사용(좋은 방법(간단))

    print('다항회귀 : 딥러닝 네트워크 사용')
    model = tf.keras.Sequential([
        tf.keras.layers.Dense(units=64, activation='relu', input_shape=(1,)),
        tf.keras.layers.Dense(units=32, activation='relu'),
        tf.keras.layers.Dense(units=1)
    ])
    
    model.compile(optimizer='adam', loss='mse', metrics=['mse'])
    model.summary()
    
    model.fit(plo_inc, pop_old, epochs=100)
    print(model.predict(plo_inc).flatten())
    
    line_x = np.arange(min(plo_inc), max(plo_inc), 0.01)
    line_y = model.predict(line_x)
    
    plt.plot(plo_inc, pop_old, 'ro')
    plt.plot(line_x, line_y, 'b--')
    plt.xlabel('지역별 인구증가율(%)')
    plt.ylabel('고령인구비율(%)')
    plt.show()

    딥러닝의 경우 알아서 비선형이면 비선형으로 계산되어 나오기 때문에 간단하고 편하다

    댓글

Designed by Tistory.