ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [혼공머] 3-2. 선형 회귀
    Data Science/딥러닝 & 머신러닝 2025. 1. 10. 23:40

     

    1. K-최근접 이웃의 한계

    1. 농어의 무게 예측 오류

    • 1절의 내용인 length & weight를 이용해 길이가 50cm인 농어의 무게를 예측해보자.
    # 1절의 내용을 돌아보기
    import numpy as np
    perch_length = np.array([8.4, 13.7, 15.0, 16.2, 17.4, 18.0, 18.7, 19.0, 19.6, 20.0, 21.0,
           21.0, 21.0, 21.3, 22.0, 22.0, 22.0, 22.0, 22.0, 22.5, 22.5, 22.7,
           23.0, 23.5, 24.0, 24.0, 24.6, 25.0, 25.6, 26.5, 27.3, 27.5, 27.5,
           27.5, 28.0, 28.7, 30.0, 32.8, 34.5, 35.0, 36.5, 36.0, 37.0, 37.0,
           39.0, 39.0, 39.0, 40.0, 40.0, 40.0, 40.0, 42.0, 43.0, 43.0, 43.5,
           44.0])
    perch_weight = np.array([5.9, 32.0, 40.0, 51.5, 70.0, 100.0, 78.0, 80.0, 85.0, 85.0, 110.0,
           115.0, 125.0, 130.0, 120.0, 120.0, 130.0, 135.0, 110.0, 130.0,
           150.0, 145.0, 150.0, 170.0, 225.0, 145.0, 188.0, 180.0, 197.0,
           218.0, 300.0, 260.0, 265.0, 250.0, 250.0, 300.0, 320.0, 514.0,
           556.0, 840.0, 685.0, 700.0, 700.0, 690.0, 900.0, 650.0, 820.0,
           850.0, 900.0, 1015.0, 820.0, 1100.0, 1000.0, 1100.0, 1000.0,
           1000.0])
           
    from sklearn.model_selection import train_test_split
    train_input, test_input, train_target, test_target = train_test_split(perch_length, perch_weight, random_state=42)    
    
    train_input = train_input.reshape(-1, 1)
    test_input = test_input.reshape(-1, 1)
    
    from sklearn.neighbors import KNeighborsRegressor
    knr = KNeighborsRegressor(n_neighbors=3)  
    knr.fit(train_input, train_target)
    
    knr.predict([[50]]) # array([1033.33333333])
    

    예측 결과 : 1.033g, 실제로 농어 50cm는 1g보다 훨씬 많다.

    2. 최근접 이웃 산점도로 표시

    import matplotlib.pyplot as plt
    
    distances, indexes = knr.kneighbors([[50]]) # 50cm 농어와의 이웃 찾기, 3개로 정해놓음
    
    plt.scatter(train_input, train_target) # 훈련 세트의 산점도
    plt.scatter(train_input[indexes], train_target[indexes], marker='D') # 50cm 농어와의 이웃만 다시 표시
    plt.scatter(50, 1033, marker = '^') # 50cm 농어 표시
    plt.xlabel('length')
    plt.ylabel('weight')
    print(np.mean(train_target[indexes])) # 1033.3333333333333
    

    3. 100cm의 농어 무게 예측

    print(knr.predict([[100]])
    distances, indexes = knr.kneighbors([[100]]) # 100cm 농어의 이웃
    
    plt.scatter(train_input, train_target) # 훈련 세트의 산점도
    plt.scatter(train_input[indexes], train_target[indexes], marker='D') # 100cm 농어와의 이웃만 다시 표시
    plt.scatter(100, 1033, marker = '^') # 100cm 농어 표시
    plt.xlabel('length')
    plt.ylabel('weight')
    

    4. K-최근접 이웃의 문제점 *

    • 새로운 샘플이 훈련 세트의 범위를 벗어나면 엉뚱한 값을 예측할 수 있음

     

    2. 선형 회귀

    1. 선형 회귀 클래스

    from sklearn.linear_model import LinearRegression
    • 목적 : 특성을 가장 잘 나타낼 수 있는 ‘직선’을 학습한다.
    • LinearRegression에도 fit, score, predict 메서드가 있다.

    2. 선형 회귀 모델 훈련과 예측

    from sklearn.linear_model import LinearRegression
    lr = LinearRegression()
    lr.fit(train_input, train_target)
    
    print(lr.predict([[50]]) # array([1241.83860323])
    

    이전의 1g보다는 합리적인 결과가 나왔다.

    3. 선형 회귀 모델의 모델파라미터

    • 모델 파라미터 : 머신러닝 알고리즘이 찾은 값
    • 기울기와 절편을 찾을 수 있다.
      • coef_ 와 intercept_
      print(lr.coef_, lr.intercept_) 
      # [39.01714496] -709.0186449535477
      

    4. 선형 회귀 직선 산점도 위에 그려보기

    • 시작점의 x,y 점과 끝점의 x,y 점 잇기
    # 훈련 세트의 산점도
    plt.scatter(train_input, train_target)
    
    # 15 ~ 50까지 방정식 그래프 그리기 = (15, -) 과 (50, -)의 두 점 잇기
    plt.plot([15, 50], [15*lr.coef_ + lr.intercept_, 50*lr.coef_ + lr.intercept_])
    
    # 50cm 농어 데이터
    plt.scatter(train_input, train_target)
    plt.scatter(50, 1241.88, marker='^')
    

    이제 훈련 세트 범위를 벗어난 무게도 예측 가능하다.

    5. 정확도 확인하기

    print(lr.score(train_input, train_target)) # 0.93
    print(lr.score(test_input, test_target)) # 0.82
    
    • 훈련 세트 > 테스트 세트 인데, 훈련 세트도 낮은 정확도에 속하는 편
    • 그래프 시작 부분을 잘 얘기해줄 수 없는 그래프

     

    3. 다항 회귀

    1. 다항 회귀의 목적

    • 선형 회귀가 데이터를 잘 나타내지 못할 때
    • 특히 그래프에서 무게가 0g 이하로 내려갈 수는 없다.

    2. 다항 회귀

    • 다항식을 사용한 선형 회귀
    • 곡선의 형태
    • 제곱항이 필요하다 → 길이를 제곱한 항을 추가한다.

    3. 다항회귀를 위한 제곱항 추가

    • 배열을 나란히 붙이기 위해 np.column_stack 사용
    train_poly = np.column_stack((train_input **2, train_input))
    test_poly = np.column_stack((test_input **2, test_input))
    

    4. 다항회귀 모델 훈련 & 예측

    lr = LinearRegression()
    lr.fit(train_poly, train_target)
    
    • 50cm 농어의 무게 예측 → 제곱항도 함께 넣어준다
    print(lr.predict([[50**2, 50]])) # array([1573.98423528])
    
    • 모델 파라미터 확인
    print(lr.coef_, lr.intercept_) # [  1.01433211 -21.55792498] 116.0502107827827
    

    제곱항을 치환하면 선형 회귀로 볼 수도 있다.

    5. 다항회귀 모델의 산점도

    # 15 ~ 49까지 정수 배열
    point = np.arange(15, 50)
    
    plt.scatter(train_input, train_target)
    
    # 짧은 직선을 이어 그리면 곡선처럼 표시 가능
    plt.plot(point, 1.01*point**2 - 21.6*point + 116.05)
    
    # 50cm 농어
    plt.scatter(50, 1574, marker='^')
    plt.show()
    

    6. 다항회귀 모델의 정확도

    print(lr.score(train_poly, train_target)) # 0.970
    print(lr.score(test_poly, test_target)) # 0.977
    
    • 훈련 < 테스트 == 과소적합 → 더 복잡한 모델 필요3. 다항 회귀
      • 선형 회귀가 데이터를 잘 나타내지 못할 때
      • 특히 그래프에서 무게가 0g 이하로 내려갈 수는 없다.

     

    4. 선형 회귀로 훈련 범위 밖의 샘플 예측 전체 소스 코드

    # 데이터 준비
    perch_length = np.array(
     [8.4, 13.7, 15.0, 16.2, 17.4, 18.0, 18.7, 19.0, 19.6, 20.0, 21.0,
     21.0, 21.0, 21.3, 22.0, 22.0, 22.0, 22.0, 22.0, 22.5, 22.5, 22.7,
     23.0, 23.5, 24.0, 24.0, 24.6, 25.0, 25.6, 26.5, 27.3, 27.5, 27.5,
     27.5, 28.0, 28.7, 30.0, 32.8, 34.5, 35.0, 36.5, 36.0, 37.0, 37.0,
     39.0, 39.0, 39.0, 40.0, 40.0, 40.0, 40.0, 42.0, 43.0, 43.0, 43.5,
     44.0])
    perch_weight = np.array(
     [5.9, 32.0, 40.0, 51.5, 70.0, 100.0, 78.0, 80.0, 85.0, 85.0, 110.0,
     115.0, 125.0, 130.0, 120.0, 120.0, 130.0, 135.0, 110.0, 130.0,
     150.0, 145.0, 150.0, 170.0, 225.0, 145.0, 188.0, 180.0, 197.0,
     218.0, 300.0, 260.0, 265.0, 250.0, 250.0, 300.0, 320.0, 514.0,
     556.0, 840.0, 685.0, 700.0, 700.0, 690.0, 900.0, 650.0, 820.0,
     850.0, 900.0, 1015.0, 820.0, 1100.0, 1000.0, 1100.0, 1000.0,
     1000.0])
     
    # 훈련 세트와 테스트 세트 구분, 2차원 배열로 변환
    from sklearn.model_selection import train_test_split
    train_input, test_input, train_target, test_target = train_test_split(perch_length, perch_weight, random_state=42)
    
    train_input = train_input.reshape(-1, 1)
    test_input = test_input.reshape(-1, 1)
    
    # k-최근접 이웃 회귀 모델 훈련
    from sklearn.neighbors import KNeighborsRegressor
    knr = KNeighborsRegressor(n_neighbors=3)
    knr.fit(train_input, train_target)
    knr.score(test_input, test_target)
    
    # 50cm 농어 무게 예측
    knr.predict([[50]])
    
    # 50cm의 k-최근접 이웃 회귀 모델 산점도
    distances, indexes = knr.kneighbors([[50]])
    plt.scatter(train_input, train_target)
    plt.scatter(train_input[indexes], train_target[indexes], marker = 'D')
    plt.scatter(50, 1033, marker = '^')
    plt.xlabel('length')
    plt.ylabel('weight')
    plt.show()
    
    # 100cm 농어 무게 예측
    knr.predict([[100]])
    
    # 100cm의 k-최근접 이웃 회귀 모델 산점도
    distances, indexes = knr.kneighbors([[100]])
    plt.scatter(train_input, train_target)
    plt.scatter(train_input[indexes],
    train_target[indexes], marker='D')
    plt.scatter(100, 1033, marker='^')
    plt.xlabel('length')
    plt.ylabel('weight')
    plt.show()
    
    # sol 1. 선형회귀
    from sklearn.linear_model import LinearRegression
    lr = LinearRegression()
    lr.fit(train_input, train_target)
    
    # 학습한 직선의 파라미터
    print(lr.coef_, lr.intercept_)
    
    # 50cm 도미 예측
    lr.predict([[50]])
    
    # 직선과 데이터의 산점도 그리기
    plt.plot([15, 50], [15*lr.coef_ + lr.intercept_, 50*lr.coef_ + lr.intercept_])
    plt.scatter(train_input, train_target)
    plt.scatter(50, 1241.88, marker='^')
    
    # 결정계수값
    print(lr.score(train_input, train_target))
    print(lr.score(test_input, test_target))
    
    # sol 2. 다항회귀 - 선형회귀에서는 무게가 0 이하도 잡힘
    # 길이의 제곱 추가
    train_poly = np.column_stack((train_input**2, train_input))
    test_poly = np.column_stack((test_input**2, test_input))
    
    # 모델 생성, 훈련
    lr = LinearRegression()
    lr.fit(train_poly, train_target)
    
    # 학습한 직선의 파라미터
    print(lr.coef_, lr.intercept_)
    
    # 50cm 도미 예측 : 2차식이라 길이의 제곱, 길이 입력
    lr.predict([[50**2, 50]])
    
    # 그래프와 데이터의 산점도 그리기
    # 15 ~ 49까지 정수 배열
    point = np.arange(15, 50)
    
    plt.scatter(train_input, train_target)
    plt.plot(point, 1.01*point**2 - 21.6*point + 116.05)
    
    # 50cm 농어
    plt.scatter(50, 1574, marker='^')
    plt.show()
    
    # 결정계수값
    print(lr.score(train_poly, train_target))
    print(lr.score(test_poly, test_target))
    
Designed by Tistory.