Data Science

원핫인코딩에서 첫 번째 범주를 드롭해도 되는 이유

워로디스 2026. 9. 23. 22:21

범주형 변수가 Red, Blue, Green 세 가지 값을 가진다고 해보겠습니다.

원핫인코딩을 하면 다음처럼 표현됩니다.

색상 Red Blue Green
Red 1 0 0
Blue 0 1 0
Green 0 0 1

여기서 중요한 점은 세 열 중 두 열의 값만 알면 나머지 한 열도 자동으로 알 수 있다는 것입니다.

예를 들어 Red 열을 제거하면:

색상 Blue Green
Red 0 0
Blue 1 0
Green 0 1

이제도 원래 범주를 완전히 구분할 수 있습니다.

  • Blue=0, Green=0 → Red
  • Blue=1, Green=0 → Blue
  • Blue=0, Green=1 → Green

즉, 첫 번째 범주의 열을 삭제한다고 해서 범주에 대한 정보가 사라지는 것은 아닙니다.

삭제된 범주는 나머지 더미변수가 모두 0인 경우로 표현되며, 이를 기준 범주(reference category 또는 baseline category)라고 합니다.

왜 굳이 하나를 제거하는가?

특히 선형회귀나 로지스틱 회귀처럼 절편(intercept)을 사용하는 선형 모델에서는 모든 원핫 열을 그대로 넣으면 문제가 생길 수 있습니다.

위 예에서는 항상 다음 관계가 성립합니다.

Red + Blue + Green = 1

그리고 선형 모델에서 절편을 사용하면 이미 모든 행에 대해 값이 1인 항이 존재합니다.

따라서 Red, Blue, Green을 모두 사용하면 한 변수가 다른 변수들로 정확하게 설명되는 완전 다중공선성(perfect multicollinearity)이 발생합니다.

이를 흔히 더미 변수 함정(dummy variable trap)이라고 합니다.

그래서 범주가 3개라면 보통 3개가 아니라 2개의 더미 변수만 사용합니다.

첫 번째 범주를 제거하면 계수는 어떻게 해석하는가?

예를 들어 Red를 제거한 상태에서 선형회귀를 한다고 하겠습니다.

특성은 다음 두 개만 남습니다.

  • Blue
  • Green

이때 모델의 계수는 대략 다음 의미로 해석할 수 있습니다.

  • 절편: 기준 범주인 Red의 예측 기준값
  • Blue의 계수: Red에 비해 Blue일 때 얼마나 달라지는지
  • Green의 계수: Red에 비해 Green일 때 얼마나 달라지는지

따라서 제거된 범주는 없어진 것이 아니라 비교 기준이 된 것입니다.

scikit-learn에서는 어떻게 하는가?

scikit-learn에서는 OneHotEncoderdrop 옵션을 사용할 수 있습니다.

from sklearn.preprocessing import OneHotEncoder

encoder = OneHotEncoder(drop='first')

drop='first'를 사용하면 각 범주형 변수마다 첫 번째 범주를 하나씩 제거합니다. scikit-learn 공식 문서에서도 완전한 공선성이 문제가 되는 상황에서 사용할 수 있는 옵션으로 설명합니다. (Scikit-learn)

예를 들어:

from sklearn.preprocessing import OneHotEncoder

X = [
    ['Red'],
    ['Blue'],
    ['Green']
]

encoder = OneHotEncoder(
    drop='first',
    sparse_output=False
)

encoded = encoder.fit_transform(X)

print(encoder.categories_)
print(encoded)

categories_를 통해 어떤 범주들이 학습되었는지 확인할 수 있습니다.

다만 여기서 말하는 "first"는 데이터에서 처음 등장한 값이라는 뜻으로 생각하면 안 됩니다. OneHotEncoder가 결정한 categories_의 첫 번째 범주가 제거됩니다.

그래서 실제로 무엇이 제거됐는지는 다음처럼 확인하는 것이 가장 확실합니다.

print(encoder.categories_)
print(encoder.drop_idx_)

drop_idx_에는 각 특성에서 어떤 범주의 인덱스가 제거되었는지가 들어 있습니다. (Scikit-learn)

이진 범주만 제거하고 싶다면

scikit-learn에는 다음 옵션도 있습니다.

encoder = OneHotEncoder(drop='if_binary')

drop='if_binary'범주가 정확히 2개인 변수에서만 하나를 제거합니다.

예를 들어:

  • 성별: Male, Female → 하나 제거
  • 색상: Red, Blue, Green → 전부 유지

이 방식은 이진 범주를 굳이 두 개의 열로 표현할 필요가 없을 때 유용합니다. (Scikit-learn)

항상 drop='first'를 해야 하는 것은 아니다

이 부분이 중요합니다.

1. 선형회귀 / 로지스틱 회귀

절편을 사용하는 전통적인 선형 모델에서는 하나를 제거하는 방식이 자연스럽습니다.

OneHotEncoder(drop='first')

특히 다중공선성을 피하거나 계수를 기준 범주 대비 효과로 해석하고 싶을 때 유용합니다.

2. Ridge, Lasso, 규제가 적용된 로지스틱 회귀

무조건 첫 번째 범주를 제거하는 것이 항상 더 좋은 것은 아닙니다.

scikit-learn 공식 문서에서도 범주 하나를 제거하면 원래 대칭적인 표현이 깨지며, penalized linear model에서는 이것이 편향을 유발할 수 있다고 명시하고 있습니다. (Scikit-learn)

따라서 규제가 들어간 모델에서는 목적에 따라 다음처럼 모든 범주를 유지하기도 합니다.

OneHotEncoder(drop=None)

참고로 OneHotEncoder의 기본값도 drop=None입니다. (Scikit-learn)

3. Decision Tree / Random Forest / Gradient Boosting

트리 계열 모델은 선형회귀처럼 설계행렬을 역산하는 방식이 아니기 때문에 더미 변수 함정이 핵심적인 문제가 아닙니다.

따라서 일반적으로 굳이 첫 번째 범주를 제거할 필요가 없습니다.

OneHotEncoder(drop=None)

을 사용해도 됩니다.

pandas와 scikit-learn 비교

pandas에서는:

pd.get_dummies(
    df,
    drop_first=True
)

scikit-learn에서는:

OneHotEncoder(
    drop='first'
)

가 비슷한 역할을 합니다.

다만 머신러닝 파이프라인에서는 일반적으로 OneHotEncoder가 더 편리합니다.

예를 들어 ColumnTransformer, Pipeline과 바로 연결할 수 있습니다.

from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline

preprocessor = ColumnTransformer(
    transformers=[
        (
            'category',
            OneHotEncoder(
                drop='first',
                handle_unknown='ignore'
            ),
            ['color', 'city']
        )
    ],
    remainder='passthrough'
)

model = Pipeline([
    ('preprocessing', preprocessor),
    ('regression', LinearRegression())
])

이렇게 하면 학습 데이터에서 결정한 범주 체계를 그대로 테스트 데이터에도 적용할 수 있다는 장점이 있습니다.

한 문장으로 정리

범주가 여러 개인 원핫인코딩에서는 하나의 더미변수를 제거해도 나머지 값만으로 제거된 범주를 구분할 수 있으므로 정보가 사라지지 않으며, 절편을 사용하는 선형 모델에서는 오히려 하나를 제거함으로써 완전 다중공선성을 피할 수 있다.

scikit-learn에서는 보통 OneHotEncoder(drop='first')로 구현하며, 선형 모델에서는 유용하지만 모든 머신러닝 모델에서 반드시 해야 하는 것은 아니다는 점까지 같이 기억하면 됩니다. (Scikit-learn)

반응형