ML | DL/혼자공부하는머신러닝딥러닝

8강. 특성 공학과 규제 알아보기

묘걍 2023. 12. 7. 21:30

03-3. 특성 공학과 규제

👉🏻 복습

출처: 혼공머딥 유튜브

  • 최근접 이웃은 이웃한 샘플의 타깃을 찾아 평균값을 계산하기 때문에 훈련 세트 범위 바깥 데이터는 잘 예측할 수 없다
  • 이 문제를 해결하기 위해 선형 회귀 알고리즘을 사용
    • 특성은 하나(길이)만 사용
  • 특성이 하나일 때 선형회귀는 직선의 방정식을 계산하는 것
  • 회귀 문제에서는 타깃값을 y축에 놓고 표현하는 것이 일반적
    • 특성 하나니까 x축과 y축 두 개의 축을 갖는 2차원 평면에서 직선의 방정식으로 표현됨
  • 직선의 방정식을 계산하는 것은 기울기와 절편을 찾는 것
    • 계수, 가중치 등으로도 불림
  • linear_model에 있는 LinearRegression 클래스를 import, 객체를 만들고 fit()메서드에 훈련세트의 특성과 타깃값을 넣어 훈련, predict()메서드로 50cm 농어의 무게를 예측, coef_와 intercept_ 를 통해 사용한 모델의 기울기와 절편을 구한다
    • k-최근접 이웃, 선형회귀 등 어떤 클래스를 사용하든 사이킷런에서는 일관되게 한 api 스타일로(??) 설계가 되어있기 때문에 하나만 잘 이해하면 다른 클래스를 사용할 때도 편하게 이용할 수 있다
더보기

API 스타일은 여러 모델들 간에 일관성 있는 메서드 사용 방법을 의미합니다. 이는 사용자가 새로운 모델을 학습하거나 기존 모델을 교체할 때 더 쉽게 전환할 수 있도록 도와줍니다. 그래서 여러 모델을 사용할 때 학습한 패턴이나 기술이 다른 모델로 전이되기 쉽습니다. API 스타일의 일관성은 코드의 가독성을 높이고 유지보수를 쉽게 만들어줍니다.

  • 하지만 음수가 나온다는 문제
  • 2차 함수 형태의 곡선을 띄고 있어서 이런 형태의 함수를 학습하기 위해 특성을 제곱한 특성을 하나 더 추가
  • 다항식을 학습 (y = ax² + bx + c) → 다항 회귀
  • 훈련세트가 점수를 더 잘 받긴 했지만 더 과소적합되었음

👉🏻 다중 회귀

출처: 혼공머딥 유튜브

  • 여러개의 변수(특성)를 활용하는 회귀
  • Multiple Regression, Multinomial Regression
    • Multinomial이 '다항'으로 해석되기도 한다.. 혼동이 생길 수 있음
  • 다항 회귀와 다중 회귀는 다른 것!

- 앞에서는 길이 특성 하나만 사용했음 (시각화와 이해를 돕기 위해서)

- 이번에는 두께 데이터도 함께 사용

- 하지만 여러개의 데이터를 사용할 경우 산점도를 그릴 수 없다

     - 훈련세트와 테스트세트 점수만을 보고 모델 평가 및 개선을 할 것

  • 특성이 하나이면 2차원 평면에 나타내고 2개이면 3차원 공간에 표현할 수 있다
    • 특성이 2개면 선형 회귀가 학습하는 것은 평면의 방정식이다
    • 특성이 2개보다 많아지면 hyperplane(초평면)을 학습하게 된다. 그림으로 표현하기 어렵다.
  • 회귀일 경우 타깃을 하나의 축에 자리잡게 해야한다
  • 특성이 많아지면 선형회귀는 강력해진다
    • 그러다 보면 선형 회귀의 높은 능력을 억제해야 하는 경우도 생긴다

🧩 특성 공학

  • 새로운 특성을 추가하거나 특성을 변경하거나 특성끼리 조합하는 것
  • feature engineering
  • 전통적으로 머신러닝 알고리즘들은 특성 공학에 영향을 많이 받는다
    • 딥러닝 알고리즘들은 비교적 영향을 덜 받는다 (전혀는 아니고, 종류가 달라지고 양이 적음)
더보기

머신러닝 모델의 성능을 향상시키기 위해 데이터의 특성(Feature)을 선택하거나 변형하는 과정을 말합니다. 모델의 입력으로 사용되는 특성이 모델의 성능에 큰 영향을 미치기 때문에, 이러한 특성을 최적화하고 개선하는 것이 중요합니다.

특성 공학은 데이터의 특성을 적절하게 선택하거나 변형하여 모델이 더 나은 학습을 할 수 있도록 도와줍니다. 여기에는 다양한 작업이 포함될 수 있습니다.

  1. 새로운 특성 생성: 기존의 특성을 조합하거나 변형하여 새로운 의미 있는 특성을 만들어낼 수 있습니다. 예를 들어, 길이와 너비를 곱하여 면적이라는 새로운 특성을 만들 수 있습니다.
  2. 범주형 데이터 처리: 범주형 데이터를 수치형으로 변환하거나, 원-핫 인코딩 등의 방법을 사용하여 모델이 범주형 정보를 이해할 수 있도록 처리합니다.
  3. 결측값 대체: 결측값이 있는 경우, 평균값, 중앙값, 최빈값 등으로 대체하거나 다른 방법을 사용하여 결측값을 처리합니다.
  4. 이상치 처리: 이상치를 찾아내고 적절하게 처리하여 모델의 안정성을 높입니다.
  5. 텍스트 데이터 처리: 텍스트 데이터를 벡터화하거나 특정한 특성을 추출하여 모델에 입력할 수 있도록 처리합니다.
  6. 차원 축소: 고차원의 데이터에서 불필요한 차원을 제거하거나 주요한 특성만을 선택하여 차원을 축소합니다.
  7. 시간 관련 특성 생성: 시계열 데이터에서 시간에 따른 특성을 생성하거나 주기성을 고려할 수 있습니다.

특성 공학은 전문적인 지식과 탐색적 데이터 분석(EDA)을 통해 이루어지며, 어떤 문제에 대한 도메인 지식이 특히 중요합니다. 올바른 특성 공학은 모델의 성능 향상에 큰 기여를 할 수 있습니다.

- 추가로 배울 것은 길이, 높이, 두께만 사용하는 것이 아니라 길이², 높이², 길이²와 높이²를 곱해서 새로운 특성을 만드는 등 조합도 해볼 것

- 이번엔 사이킷런의 기능을 이용해 제곱할 것

 

👉🏻 판다스로 데이터 준비

🧩 판다스

  • 파이썬 과학 라이브러리의 핵심 패키지들이 있다
    • Numpy, SciPy, Pandas, Matplotlib, Scikit-learn 등이 파이썬의 과학 라이브러리의 필수적인 핵심 요소
  • 판다스의 핵심 데이터 구조는 Data Frame(객체)
    • 다차원 배열
    • 넘파이와 다르게 다른 종류의 데이터 타입을 가질 수 있다 (한 열은 실수, 한 열은 문자열... 등)
    • 데이터프레임을 엑셀 시트와 비슷하게 이해할 수 있다
    • 샘플 데이터 행이 늘어져 있다
    • 특성 데이터는 열에 있다
      • 여러 종류의 데이터를 섞어 쓸 수 있다
  • 데이터를 만드는 파일이나 인터넷(사이트?)를 불러와서 새로 만드는 기능도 있다
  • 간단한 통계치를 만드는 기능
  • 그래프로 만들어 시각화해주는 기능

🧩 넘파이 및 판다스 튜토리얼

https://ml-ko.kr/homl2/tools_numpy.html

 

tools_numpy

0, 1, 2(깊이, 높이, 너비) 축을 1, 2, 0 (깊이→너비, 높이→깊이, 너비→높이) 순서로 바꾼 ndarray를 만들어 보겠습니다:

ml-ko.kr

https://ml-ko.kr/homl2/tools_pandas.html

 

tools_pandas

저장 & 로딩¶ 판다스는 DataFrame를 여러 가지 포맷으로 저장할 수 있습니다. CSV, Excel, JSON, HTML, HDF5, SQL 데이터베이스 같은 포맷이 가능합니다. 예제를 위해 DataFrame을 하나 만들어 보겠습니다:

ml-ko.kr

🧩 데이터 준비 손코딩

- 원격에 있는 파일을 불러와서 넘파이 배열로 만드는 과정

출처: 혼공머딥 유튜브

✅ CSV 파일

  • 콤마(,)로 나눠져 있는 텍스트 파일
  • 한 행에 하나의 샘플이 들어있다
  • 콤마(,)로 나눠진 열마다 특성 데이터가 들어 있다

- 인터넷 주소를 가지고 판다스의 read_csv()함수를 사용하면

   다운 받아서 csv파일을 읽어 판다스의 데이터프레임으로 만들어줌

✅ read_csv()

  • 판다스는 read_csv()해서 읽어 온 파일의 첫 번째 행을 자동으로 각 열의 제목으로 인식해서 이름을 넣어준다
  • 두 번째 행부터 데이터로 처리해준다

✅ to_numpy()

  • 판다스 data frame을 넘파이 배열로 만든다

- perch_full 객체가 생성되는데 이는 이전에 column_stack으로 만든 넘파이 배열과 똑같은 것이다

     - 이제는 길이와 높이와 두께의 세 개의 열(특성)이 있다

👉🏻 타깃 준비 및 훈련 세트와 테스트 세트로 나누기

https://gist.github.com/rickiepark/2cd82455e985001542047d7d55d50630

 

농어의 길이와 무게 데이터

농어의 길이와 무게 데이터. GitHub Gist: instantly share code, notes, and snippets.

gist.github.com

👉🏻 다항 특성 만들기

- 길이, 높이, 두께 뿐만 아니라 각각을 제곱한 것, 서로 곱한것을 사용해 새로운 특성을 만듦

- 이 작업들을 사이킷런에서 제공하는 기능으로

- preprocessing 밑에 PolynomialFeatures에서 자동으로 해준다

🧩 PolynomialFeatures

더보기

PolynomialFeatures 클래스는 사이킷런(Scikit-learn)의 preprocessing 모듈에 속한 클래스 중 하나로, 다항식 특성을 생성해주는 역할을 합니다. 이 클래스는 주어진 특성(feature)을 사용하여 다항식 형태의 새로운 특성을 만들어내는데, 주로 다항 회귀 모델을 구축할 때 사용됩니다.

간단한 예제를 통해 PolynomialFeatures 클래스를 설명해보겠습니다. 예를 들어, 주어진 1차원 특성을 이용하여 2차 다항식 특성을 생성하는 경우를 살펴보겠습니다.

from sklearn.preprocessing import PolynomialFeatures
import numpy as np

# 원본 데이터
X = np.array([[1], [2], [3]])

# PolynomialFeatures를 사용하여 2차 다항식 특성 생성
poly = PolynomialFeatures(degree=2)
X_poly = poly.fit_transform(X)

print(X_poly)

위 코드에서 degree 매개변수는 생성하려는 다항식의 차수를 나타냅니다. 여기서는 2차 다항식을 생성하도록 하였습니다. 그리고 fit_transform 메서드를 사용하여 주어진 데이터를 변환합니다.

출력 결과는 다음과 같습니다:

[[1. 1. 1.]
 [1. 2. 4.]
 [1. 3. 9.]]

결과로 나오는 배열은 각 행이 원본 특성과 그 특성의 제곱을 포함한 형태입니다. 첫 번째 열은 상수항(1)을 나타내며, 두 번째 열은 원본 특성, 세 번째 열은 원본 특성의 제곱입니다.

이렇게 다항식 특성을 추가함으로써 모델은 더 복잡한 패턴을 학습할 수 있게 되며, 주어진 데이터에 대한 예측이 더 정확해질 수 있습니다.

  • 변환기(Transformer)
    • 사이킷 런의 특성 변환, 전처리 등의 기능을 해주는 클래스들을 변환기라고 함
    • 그 외에 모델링을 하는 것들(LinearRegression, K-최근접 이웃 ...)을 추정기(Estimator)라고 한다
      • 추정기에는 fit() → predict() → score() 메서드가 있다
  • fit(), transform() 메서드가 있다
  • 실제로 무언가를 학습하는 건 아니다.
    • 특성이 몇 개 있구나, 어떤 조합으로 만들어야겠구나를 파악하는 정도
    • api설계 디자인 일관성을 유지하기 위해 fit()으로 하는 것
  • fit_transform()메서드도 제공한다
    • fit() + transform() 
    • fit메서드가 특별한 역할을 하지 못하는 경우가 많기 때문에
    • 같은 데이터를 넣으면서 두 번 호출하는 것은 번거롭기 때문에

- 클래스 객체를 만들고

- fit()메서드를 호출한다

✅ degree

  • PolynomialFetures의 매개변수 중 하나
  • 기본 값이 2
    • 제곱항을 만들어줌
    • 3으로 하면 3제곱
더보기

PolynomialFeatures 클래스의 degree 매개변수는 다항식의 차수를 나타내는 매개변수입니다. 다항식은 하나 이상의 변수에 대한 항이 포함된 수식으로, 이때 차수는 항의 지수를 의미합니다.

PolynomialFeatures에서 degree 매개변수를 설정하면, 주어진 차수까지의 다항식 항을 생성합니다. 예를 들어, degree=2로 설정하면 2차 다항식까지의 항을 생성하게 됩니다.

간단한 예제를 통해 설명하겠습니다. 예를 들어, degree=2로 설정하면 다음과 같은 변환이 이루어집니다:

이런 식으로 주어진 차수까지의 다항식 항이 새로운 특성으로 생성됩니다. 이렇게 생성된 특성은 모델이 주어진 데이터에 대해 더 복잡한 패턴을 학습할 수 있도록 도와줍니다.

요약하면, degree 매개변수는 다항식의 차수를 결정하는데, 이는 새로운 특성을 어느 정도까지 생성할지를 나타냅니다. 더 높은 차수를 선택하면 모델이 주어진 데이터에 더 복잡한 패턴을 학습할 수 있지만, 너무 높게 설정하면 과적합(overfitting)의 위험이 있으므로 조심해야 합니다

- 기본 값을 그대로 사용해서 진행

- fit()메서드를 통해 [2, 3] 이라는 가상의 샘플 데이터를 학습

✅ transform()

  • 데이터를 제곱하거나 특성끼리 곱해서 새로운 특성 배열을 만들어준다

- transform()메서드를 호출해서 [2, 3]이라는 가상의 샘플 데이터를 아래와 같이 바꾼다

- 2와 3은 원래 있던 특성을 그대로 사용한 것

- 2**2 = 4

- 3**3 = 9

- 2*3 = 6

- 1은 절편을 위한 특성

     - y = ax + b 의 일차방정식을 만들 때 a는 기울기, b는 절편이다

     - 만약 b옆에 가상의 특성 1이 있다고 가정하면 (y = ax + b1)

     - 이렇게 되면 배열[a, b]와 배열[x, 1]를 만들어 배열끼리의 곱셈, 간단한 연산을 할 수 있다

     - 딥러닝 파트에서도 종종 절편을 위한 가상의 특성 1을 추가하는 경우가 많다

     - 자동으로 만들어준것

더보기

결국, 배열로 표현하고 배열끼리의 곱셈을 사용하는 것은 선형 회귀 모델을 표현하고, 여러 특성이 있는 경우 다양한 특성을 고려한 모델을 표현하기 위함입니다. 이를 통해 모델은 데이터의 패턴을 더 정확하게 학습하고 예측할 수 있게 됩니다.

 

선형 회귀 모델에서 는 기울기를, 는 절편을 나타냅니다. 이를 배열로 표현하면 가 됩니다. 이 모델을 간단히 행렬로 표현하면 이라는 입력 데이터와 라는 가중치의 내적(또는 행렬 곱셈)으로 표현할 수 있습니다.

여기서 왜 인가요? 여기서 1은 상수항(절편)을 의미합니다. 왜냐하면 에서 x에 대한 계수는 이지만, 상수항에 대한 계수는 1이기 때문입니다. 그래서 로 입력 데이터를 만든 것이죠.

이제 왜 이런 행렬 곱셈이 필요한지 생각해봅시다. 선형 회귀 모델은 주어진 입력 데이터에 대해 가중치를 곱하고 더한 값을 출력으로 예측합니다. 행렬 곱셈을 사용하면 이러한 계산을 한 번에 처리할 수 있습니다.

간단히 말해서, 배열 와 입력 데이터 의 행렬 곱셈은 를 계산해주는 거에요. 이렇게 행렬 곱셈을 사용하면 여러 입력 데이터에 대한 예측을 효율적으로 할 수 있습니다.

이러한 아이디어를 확장해서 다항 회귀 등 여러 모델에도 적용할 수 있습니다. 상수항이나 여러 특성을 고려할 때 이렇게 행렬로 표현하면 모델을 더 간단하게 이해하고 계산할 수 있습니다.

더보기

1은 상수항을 나타냅니다. 상수항은 x⁰에 해당하며, 어떤 수를 0 제곱하면 1이 됩니다.

예를 들어, 주어진 특성 x에 대해 2차 다항식을 생성한다면 새로운 특성은 다음과 같이 됩니다:

여기서 첫 번째 항인 1은 x⁰으로, x의 0 제곱을 나타냅니다. 이는 상수항으로서 모든 데이터에 대해 1의 값을 갖습니다. 상수항을 추가하는 이유는 모델이 데이터에 대한 평행 이동(translation)을 학습할 수 있게 하기 위함입니다. 상수항이 없다면 모델은 항상 원점을 지나는 형태의 다항식만을 학습할 것이므로, 데이터의 분포에 적절하게 적응하지 못할 수 있습니다.

따라서, 새로운 특성에는 상수항이 추가되어 있어야 모델이 데이터에 대해 더 좋은 적합을 수행할 수 있습니다.

- 우리는 1이 필요하지는 않다. LinearRegression클래스가 1 특성을 무시함

     - 혼돈을 피하기 위해 일부러 1을 생성하지 않게 함 (뒤에 나옴)

👉🏻 Linear Regression

✅ include_bias

  • 절편에 대한 특성을 빼기 위해 False로 지정한다
  • 기본 값은 True
    • 무조건 1이 하나씩 붙게 되어있음

- 판다스로 읽어 변환했던 train_input을 fit()메서드에 넣음

- 마찬가지로 transfrom()에도 넣어줌

- 이 결과로 얻은 배열이 train_poly

- train_poly 배열의 크기를 넘파이의 shape 속성을 통해 확인해보기

- 첫 번째 차원이 42, 두 번째 차원이 9

- 42개의 행(샘플), 9개의 특성이 있는 배열

✅ get_feature_names()

  • 각 특성이 어떻게 만들어졌는지 확인하기 위해
더보기
원래 코드대로 하면 에러남 이유는 모름

get_feature_names 메서드:

  • 사용 가능 버전: 0.22.0 이상
  • PolynomialFeatures 클래스에서 제공하는 메서드로, 다항식 특성의 이름을 얻기 위해 사용됩니다.
  • input_features 매개변수로 전달된 특성들의 이름을 기반으로 다항식 특성의 이름을 생성합니다.
  • get_feature_names()을 호출하면 다항식 특성의 이름을 반환합니다.
  • 다음과 같이 사용할 수 있습니다:
feature_names = poly.get_feature_names()

 

get_feature_names_out 메서드:

  • 사용 가능 버전: 0.22.0 이상
  • 마찬가지로 PolynomialFeatures 클래스에서 제공하는 메서드로, 다항식 특성의 이름을 얻기 위해 사용됩니다.
  • input_features 매개변수로 전달된 특성들의 이름을 기반으로 다항식 특성의 이름을 생성합니다.
  • get_feature_names_out()을 호출하면 다항식 특성의 이름을 반환합니다.
  • 다음과 같이 사용할 수 있습니다:
feature_names = poly.get_feature_names_out()

 

차이점:

  • 실제로 get_feature_names과 get_feature_names_out은 비슷한 결과를 제공합니다. 즉, 두 메서드는 동일한 이름을 반환합니다.
  • get_feature_names은 초기에는 없었던 메서드였고, 나중에 get_feature_names_out가 추가되었습니다.
  • 만약 get_feature_names가 에러를 일으킨다면 버전 호환성 문제일 수 있습니다. 버전이 0.22.0 이상이라면 둘 중 어떤 메서드를 사용해도 상관 없습니다.
  • get_feature_names_out는 0.22.0 이전 버전에서는 지원되지 않으므로 해당 버전 이전에서 사용하는 경우 get_feature_names을 사용해야 합니다.

- x0: 첫 번째 특성(길이)을 그대로 사용

- x1: 두 번째 특성(높이)을 그대로 사용

- x2: 세 번째 특성(두께)을 그대로 사용

- x0^2: 길이 특성의 제곱

- x0 x1: 길이 특성과 높이 특성을 곱함

- 나머지도 이런식...

- degree매개변수의 기본 값이 2이기 때문에 제곱항까지 만들어짐

- 이번엔 transform()메서드를 통해 test세트를 변환함

✅ 객체를 그대로 사용하는 이유?

  • PolynomialFeatures가 훈련 세트의 통계값을 학습하는 건 아니고, 훈련세트에 몇 개의 특성이 있고, 몇 차원까지 만들지만 파악해서 작업하는 것이기 때문에 새로 polynomialfeatures 클래스를 만들어서 test_input을 따로 변환해서 사용해도 문제는 없다. (degree만 같으면) 
  • 하지만 일반적으로 훈련세트에 적용한 변환을 그대로 테스트 세트에도 적용하는 관습을 위해 polynomialfeatures로 만든 객체 - 훈련세트를 변환한 객체를 그대로 사용해서 테스트 세트를 변환한다.
  • 일반적인 방법

뭘 강조하기 위해 말씀하신건지는 알겠는데, 원래 같은 클래스 내에서 다 하지 않았나? 왜 갑자기 새로 클래스를 만들어서 해도 되지만 훈련 세트에 적용한 변환을 테스트세트에도 적용하기 위해 객체를 그대로 사용한다고 설명하셨는지가 이해가 안 간다. 훈련세트를 위한 클래스 객체 하나, 테스트세트를 위한 클래스 객체 하나 이렇게 따로따로 했던 적은 없는 것 같은데... 내가 뭔가 놓치고 있는걸까?

- LinearRegression 클래스 객체를 만든다

- train_poly를 넣어준다.

- traget은 변하는 것이 없음.

     - 우리가 지금까지 한 것은 특성을 추가하고, 재가공한 것이지 타겟은 그대로

- 훈련세트 점수

- 꽤 높게 나옴

- 훈련세트 점수가 더 높게 나옴

     - 특성을 많이 넣었기 때문에 훈련세트에 맞는 복잡한 모델이 만들어졌다고 볼 수 있다.

- 테스트세트 점수

- 차이는 있지만 과소적합 현상은 사라짐

 

👉🏻 더 많은 특성 만들기

- degree 기본값은 2이지만 5로 늘려서 만들어보기

- poly 객체의 fit()메서드 호출

- transform()메서드로 훈련세트와 테스트세트 변경

- 크기 확인해보기

- 특성의 개수가 55개

- x0, x1, dx2, ..., x0x1, ..., x0²x1, ...

책에는 안 나왔지만 궁금해서 해봄

- LinearRegression 모델로 훈련시킴

🙋🏻‍♀️ poly.fit(test_input)은 필요 없나요?

👩🏻‍🏫 훈련세트에서 PolinomialFeatures의 객체를 학습할 필요는 없다. test세트는 자체적으로 fit메서드를 호출해서 따로 변환하지 않고 항상 훈련세트에서 학습한 객체를 사용해서 테스트세트를 변환해야 한다. 그래야 올바르게 데이터를 변환할 수 있다. PolinomialFeatures는 훈련세트에서 통계값을 계산하지는 않는다. 하지만 항상 습관이 배도록 하기 위해 훈련세트에 적용했던 객체를 가지고 테스트세트에 적용하도록 한다. 테스트세트에서는 fit()메서드를 사용하지 않고, 훈련세트에서 fit()한 것을 가지고 transform()만 한다.

- 훈련세트 R²점수

- 거의 완벽

- 테스트세트 R²점수

- 음수가 나옴

- 굉장히 안 좋음

- 훈련세트의 점수와 테스트세트의 점수 차가 많이 나므로 과대적합된 것

     - 훈련세트는 거의 다 맞췄는데

     - 테스트세트는 하나도 못 맞춘 것

- 훈련세트의 개수가 42개인데 특성이 55개이다보니 맞춰야하는 것 보다 사용할 도구가 훨씬 많은 것

     - 특성 하나에 샘플 하나를 대응해서 훈련해도 완벽하게 맞출 수 있기 때문에 과대적합이 될 수 밖에 없다

(일부러 이렇게 만들어본 것)

✅ 규제

  • 극도로 과대적합된 모델을 완화하는 대표적인 기법
  • 정규화라고 표현하기도 한다
    • normalization과 혼동될 수 있다
    • 문맥에 따라 잘 해석해야한다
  • 값을 제한
더보기

규제를 적용한다는 것은 모델의 학습 과정에서 가중치(계수)의 크기를 제한하거나 제약을 두어 모델이 훈련 데이터에 과적합되지 않도록 하는 것입니다. 간단한 비유를 통해 설명해보겠습니다.

상상해보세요, 여러분이 학습하는 모델은 직업이 고소득자인지 낮은 소득자인지를 예측하는 모델이라고 합시다. 이 모델이 훈련 데이터를 보고 각 직업의 특성을 학습할 때, 어떤 경우에는 너무 자세하게 학습하여 특정 직업에 대해 지나치게 민감한 반응을 보이기 시작할 수 있습니다.

이 때 규제를 적용하면, 모델은 각 직업의 영향력을 너무 크게 받지 않도록 강제됩니다. 즉, 특정 직업의 영향을 과도하게 받아들이는 것을 제한하여 모델이 일반적인 특성을 더 잘 파악하도록 돕습니다.

비유적으로 말하면, 규제는 모델이 특정 데이터에 지나치게 적응하지 않도록 특정한 규칙을 부과하는 것과 비슷합니다. 이는 모델이 너무 복잡해지거나 훈련 데이터에 지나치게 따라가려는 것을 방지하여 새로운 데이터에 대한 예측 능력을 향상시킬 수 있습니다.

출처: 혼머딥유튜브

- 선형 회귀 모델

- 가중치가 있어 각 샘플을 잘 지나는(잘 맞는) 모델

- 가중치 값을 줄여서 부드러운(일반화된)모델을 만드는 것

  • 가중치(기울기) 값을 작게 만드는 것
  • 리지회귀
  • 라쏘회귀
  • 가중치가 높을 수록 모델에 벌칙을 매김(?)
    • 모델이 가중치가 높으면 벌칙을 받기 때문에 가중치를 줄이려고 함

- LinearRegression을 사용할 때는 특성을 그대로 사용

- k-최근접 이웃을 할 때 특성을 맞췄다 (스케일을 맞췄다). 스케일을 맞추지 않으면 한 쪽 특성에 쏠려서 이웃을 잘못 찾기도 함

- LinearRegression은 스케일 조정을 하지 않음. LinearRegression은 특성의 크기/스케일에 영향을 받지 않도록 구현되어있다

- 해석적인 방법으로 계산하기 때문에 특성의 크기에 영향을 받지 않는다.

- 하지만 규제를 하려고 하면 상황이 달라진다!

👉🏻 규제 전에 표준화

  • 선형 모델의 기울기(가중치)에 벌칙을 가하는 방법
    • 가중치가 크면 벌칙을 내림
    • 가중치를 작게 만들도록
  • 만약 특성이 다르면 특성을 곱할 때 기울기도 달라진다
  • 특성의 스케일이 비슷해져야지 특성에 곱해지는 기울기도 서로 비슷해진다
  • 기울기가 비슷해져야 각 기울기에 주어지는 벌칙도 공평하다(?)
  • 규제를 하기 위해서는 특성의 스케일을 조정해야한다
    • 대표적인게 표준화 (z점수, 표준점수)

- 이전에는 numpy의 mean과 std를 활용해서 수동으로 변환했지만

- 이번에는 sklearn의 클래스 StandardScaler를 사용한다

✅ StandardScaler

  • preprocessing 밑에
  • 변환기(transformer)
  • fit()메서드 사용
  • transfrom()메서드를 사용해서 데이터를 변환
  • 훈련세트에 있는 통계값을 사용하는 것
    • 평균과 표준편차를 이용하는 것이니
  • 훈련세트에 적용한 ss 객체를 사용해서 테스트세트도 변환을 해야한다

- StandardScaler 객체를 만든다

- fit()메서드를 사용해 앞에서 만든 55개의 특성이 있는 trian_poly 배열을 넣어 훈련

     - 평균과 표준편차를 각 특성마다 구함

- transform()메서드를 통해 변환

- train_scaled와 test_scaled를 만듦

- 표준 점수로 변환된 훈련세트와 테스트세트 준비 완료

- 이제 여기에 규제가 있는 선형회귀 모델을 적용할 것

- 사이킷 런에는 규제가 적용된 선형 모델을 다른 별도의 클래스로 제공하고 있다

👉🏻 릿지 회귀

  • 가중치²을 벌칙으로 사용한다
  • L2 규제라고 부르기도 한다
    • 다른 클래스에 규제를 적용할 때는 L2규제를 적용한다
    • 선형 회귀에 적용할 때는 특별히 릿지라고 한다

- linear_model 모듈 밑에 있음

- Ridge 클래스 객체를 만든다

- 표준 점수로 변경한 훈련세트와 타깃을 넣고 훈련시킨다

- 여전히 타깃 데이터는 변경이 없다. 맞춰야할 목표값.

- 훈련세트 점수도 나쁘지 않다.

- 극도로 나빴던 테스트세트 점수가 아주 좋아졌다

 

- 특성은 55개로 많지만, Ridge 클래스를 통해 훈련세트에만 너무 잘 맞는 것을 억지로 막아서 테스트세트에서도 높은 점수가 나오는 모델을 만들었다

🧩 릿지 클래스의 규제 강도

✅ alpha 매개변수

  • 기본 값 = 1
  • 값을 크게 만들면 강도가 세지고, 작게 하면 강도가 약해진다
  • 최적인지 아닌지는 바꿔가면서 확인해야한다
  • 학습하는 값이 아니라 우리가 정해주는 값, 하이퍼파라미터라고 부른다

✅ 하이퍼파라미터

  • 학습으로 얻어내는 값이 아니라 우리가 정해주는 값
  • 하이퍼 파라미터 탐색: 좋은 score값이 나오는 하이퍼파라미터 값을 찾아가는 과정
  • 클래스의 매개변수나 함수의 매개변수나 설정 값으로 지정하게 되어 있음

✅ 모델 파라미터

  • 모델 클래스가 데이터로부터 학습하는 것
  • 릿지 회귀의 가중치처럼

👉🏻 적절한 규제 강도 찾기

- 각 alpha 점수마다 나오는 score값을 저장할 리스트를 만든다

- alpha 값을 리스트로 여러개 만들어 for문을 통해 하나씩 적용한다

- Ridge 클래스를 계속 바꿔주기 위해 매번 객체를 새로 만들고 alpha 값을 적용한다

- 훈련하고 테스트 점수를 저장한다

✅ alpha 값을 10의 배수로 지정함

  • 로그스케일로 바꾼 것
더보기

로그 스케일은 값의 크기를 표현할 때 로그 함수를 사용하는 스케일을 의미합니다. 로그 스케일은 값이 10배씩 커질 때마다 일정한 간격으로 값이 증가하도록 만듭니다. 이는 데이터의 큰 범위를 다룰 때 유용하며, 특히 시각화나 모델의 파라미터 튜닝과 같은 작업에서 사용됩니다.

간단한 예를 통해 이해를 돕겠습니다. 선형 스케일에서는 값이 일정한 간격으로 증가합니다.

  • 선형 스케일: 1, 2, 3, 4, 5, ...

반면에 로그 스케일에서는 값이 로그 함수의 형태로 증가합니다.

  • 로그 스케일: 10^0, 10^1, 10^2, 10^3, ...

여기서 주목해야 할 점은 로그 스케일에서는 각 값이 이전 값에 비해 큰 차이를 보이지만, 그 차이가 일정합니다. 예를 들어, 10과 100 사이의 간격은 100과 1000 사이의 간격과 동일합니다.

로그 스케일은 데이터가 넓은 범위에 걸쳐 있을 때, 작은 값과 큰 값 간의 상대적인 차이를 뚜렷하게 보여주어 특히 시각화에서 유용합니다. 또한, 일부 작업에서는 로그 스케일이 모델의 학습이나 튜닝에 유리한 경우가 있습니다.

  • 이것이 일반적인 관례 (꼭 이렇게 해야된다는 건 없지만)
  • 특정 범위가 의심이 된다면 범위를 좁히고 간격을 좁혀가면서 테스트를 해보는 방식
  • 처음에는 상용로그스케일로 만들어 테스트하는 것이 일반적이다

✅ np.log10

출처: 혼공머딥 유튜브

- 위의 alpha 범위를 그대로 사용하게 되면 0.001 ~ 0.1 부분만 촘촘해지고 나머지 범위는 너무 넓어진다

- x축(alpha)이 동일한 간격으로 나오게 하기 위해 alpha 값을 로그 스케일로 바꿔서 그린다

더보기

np.log10는 NumPy 라이브러리에서 제공하는 함수로, 밑이 10인 로그를 계산하는 함수입니다. 이 함수는 주로 값의 크기를 변환하여 데이터를 이해하거나 시각화할 때 사용됩니다.

간단한 예제를 통해 np.log10을 설명하겠습니다. 예를 들어, 1000이라는 값을 np.log10에 넣으면 결과는 얼마일까요?

import numpy as np

value = 1000
log_value = np.log10(value)

print(log_value)

이 코드를 실행하면 3.0이라는 결과를 얻을 수 있습니다. 이는 10을 몇 번 곱해야 1000이 되는지를 나타내는 값입니다. 즉, 103=1000이므로 결과가 3.0이 됩니다.

다른 예를 들어보겠습니다. 100이라는 값을 np.log10에 넣으면 어떤 결과를 얻을까요?

value = 100
log_value = np.log10(value)

print(log_value)

이 코드를 실행하면 2.0이라는 결과를 얻습니다. 왜냐하면 102=100이기 때문입니다.

따라서, np.log10은 값의 크기를 로그 스케일로 변환하여 작은 값과 큰 값의 상대적인 크기 차이를 더 명확하게 보여줍니다. 이 함수는 데이터 분석, 시각화, 머신러닝 등 다양한 분야에서 유용하게 활용됩니다.

- 각각 -3 = 10^-3, -2 = 10^-2, ... 2 = 10^2 를 나타낸다

- -1부분이 가장 높다

- alpha 값이 커지면 규제가 세지기 때문에 훈련세트의 점수도 낮아지고 테스트 세트의 점수는 더 낮아짐

     - 과소 적합

     - 규제를 많이 했기 때문에

- alpha값이 줄어들면 규제가 완화되기 때문에 훈련세트 점수만 높고 테스트세트 점수는 급격히 낮아진다

     - 훈련세트에만 잘 맞는 과대적합

출처: 혼공머딥 유튜브

- 왼쪽은 과대적합, 오른쪽은 과소적합된 모델

- 가장 좋은 골드박스 지점은 두 포인트가 가깝고 테스트세트 점수가 높은 -1 부분이다

더보기

골든박스라는 용어는 그리드 서치에서 가장 좋은 조합을 나타내는 부분을 강조한 것으로, 그리드 서치를 통해 최적의 하이퍼파라미터 조합을 찾아내는 것이 중요한 모델 튜닝 작업 중 하나입니다.

 

👉🏻 라쏘 회귀

  • |가중치|을 벌칙으로 준다
  • 선형 회귀가 아니라 다른 모델에 적용할 경우 L1규제를 적용한다고 말한다
  • 일부 특성을 아예 사용 안 할 수 있다
    • 특성마다 가중치(기울기)를 곱하는데 이 가중치를 0으로 만들 수 있다
    • 특성이 의미가 없어지는 것 (사용하지 않는 것)

- 별도의 클래스로 제공한다

- 클래스 객체를 만든다

- fit()메서드를 통해 표준점수로 바꾼 훈련세트를 집어넣는다

🧩 alpha 값 변경해보기

- 급격하게 떨어지는 좋지 않은 모습을 보여주기도 한다

- 10¹정도가 두 점수 차가 적고 테스트세트 점수도 가장 높은 것을 알 수 있다

✅ 어떤 특성을 사용하지 않는지 확인하려면

  • 라쏘가 학습한 가중치는 라쏘 객체의 coef_속성에 들어있다
  • 이 중 0인것만 찾아
    • lasso.coef_ == 0 이면 0인 것만 찾는다 (조건이 True인 것)
    • 이것을 np.sum하면 True를 1로 처리해 합하면 갯수를 알 수 있다

- PolynomialFeatures로 총 55개의 특성을 만들었는데 그 중 15개만 사용하고 40개는 사용하지 않았다

 

* 일반적으로 라쏘(L1)보다는 릿지회귀(L2)를 조금 더 선호하는 편이다

     - 규제가 더 효과적으로 잘 든다고 할 수 있다


✏️ QnA

🙋🏻‍♀️ 싸이킷런 등의 라이브러리들은 더 좋은 라이브러리가 나오면 대체될 것이라고 생각하는데 라이브러리가 대체되더라도 라쏘나 릿지가 오래 갈 수 있을까요? 근본적으로 바뀌지 않는 것은 무엇이 있을까요?

👩🏻‍🏫 라쏘나 릿지 회귀는 알고리즘이다. 이 알고리즘을 싸이킷런으로 구현한 것이다. (가능성은 전혀 없지만) 싸이킷런 라이브러리가 사장된다 하더라도 릿지나 라쏘 등의 선형회귀 알고리즘이나 개념은 계속 존재할 것이다.

싸이킷런에는 굉장히 많은 알고리즘이 구현되어 있어 사라지지 않을 것이다. 다른 라이브러리가 갑자기 이 많은 알고리즘을 더 잘 구현해서 등장하기가 어렵다. 어쨌든 알고리즘과 클래스는 별개의 문제이다

 

🙋🏻‍♀️ 알파규제의 파라미터값의 기준은 어떻게 되나요?

👩🏻‍🏫 기준이 없고 라이브러리마다 (규제 파라미터나 다른 파라미터도 마찬가지) 경험적으로 봤을 때 좋은 디폴트 값을 정해놓는다. 디폴트값으로 테스트해봐야하지만 데이터나 상황마다 좋은 파라미터는 다르다. 항상 기본 값을 바꿔보면서 내 문제에 가장 좋은 값을 찾아야 한다. 사전에 미리 알 수는 없고 여러번 시행착오를 해야한다.

 

🙋🏻‍♀️ 기초 통계 지식이 없는 상태에서 클래스를 사용하다보면 정확한 이해보다는 '이런 문제에는 이런 클래스를 사용해야한다'는 결과 지향적으로 학습하게 되는 것 같아요

👩🏻‍🏫 일리있는 말이다. 맛볼 때 혼공머신러닝 같은 책은 알고리즘을 쉽게 설명하고 사용법을 익히게 하지만 구현 방법을 알려면 이론적인 면을 살펴봐야하고 그러다보면 수학적 내용이 들어간 책을 봐야한다. 사이킷런이나 텐서플로우 등은 오픈소스이기 때문에 소스를 받아 열어 읽어보면 좋다. 파이썬이기 때문에 비교적 읽기가 쉽다. 가령 LinearRegression이라 하면 해당 클래스를 열어서 상속 관계를 파악하고 메서드들이 어떻게 구현되어있는지 파악해봐야한다.

 

🙋🏻‍♀️ alpha값이 0과 1사이 값으로 되어있던데 alpha값이 어떤식으로 계산되는지 알 수 있을까요?

👩🏻‍🏫 alpha값은 우리가 지정하는 값이다. 0, 1, 10, 100 등의 값으로 지정해서 매개변수에 넣고 릿지 클래스를 훈련한 것이다. 계산되는 게 아니라 지정하는 것이다. 어떤 값이 좋은 지 모르니 임의로 10의 배수들을 넣어 다 돌려보고 가장 좋은 값을 찾은 것이다.

 

🙋🏻‍♀️ AI 근본은 수학 및 여러 방법론일까요?

👩🏻‍🏫 머신러닝 자체가 수학이나 통계에 기반을 두고 있고 방법론도 수학과 통계적 토대가 있다. 하지만 경험론적인 것도 많이 있다. 선형계수, 통계, 미적분 등을 배우면 좋겠지만 그걸 배우는 것은 알고리즘을 이해하고 어떤 알고리즘을 개발 /새로운 모델 개발 / 새로운 아키텍처를 만들 사람이라면 당연히 알아야한다. 그게 아니라 알고리즘을 사용해서 문제를 풀어가는 입장이라면 수학이나 통계, 이론적인 부분은 조금 더 잘 쓰기 위함이지 너무 무겁게 생각할 건 없다. 원리만 이해하면 된다.

 

🙋🏻‍♀️ 지금 배우는 것이 알고리즘을 구현하는 방법인가요?

👩🏻‍🏫 약간 다를 수 있는 게 지금 배우는 것은 알고리즘을 사용하고 이해하는 것이다.

 

 

 

 

 

출처: https://youtu.be/PLECEclz0p4?si=t2TQBNtISTaVNiXm