머신러닝을 위한 피처 엔지니어링: 핵심 기법과 기술 면접 대비 2026

Python 실습 코드와 함께 머신러닝 피처 엔지니어링의 핵심 기법을 다룹니다. 인코딩, 스케일링, 피처 선택, scikit-learn 파이프라인 구축, 데이터 과학 면접 빈출 질문까지 포괄합니다.

머신러닝을 위한 피처 엔지니어링: 핵심 기법과 기술 면접 대비 2026

머신러닝 모델의 성능은 알고리즘 선택보다 피처 엔지니어링(Feature Engineering)에 의해 결정되는 경우가 많습니다. 실제 현업에서 데이터 과학자들은 전체 프로젝트 시간의 60-80%를 데이터 전처리와 피처 엔지니어링에 투자합니다. 원시 데이터를 모델이 학습하기 좋은 형태로 변환하는 이 과정은 예측 정확도를 크게 향상시킬 수 있으며, 기술 면접에서도 핵심 평가 영역으로 자리잡고 있습니다.

피처 엔지니어링의 핵심 원칙

좋은 피처는 도메인 지식과 통계적 직관의 조합에서 탄생합니다. 단순히 더 많은 피처를 생성하는 것이 아니라, 모델이 패턴을 쉽게 학습할 수 있도록 데이터의 본질적인 특성을 드러내는 것이 목표입니다.

범주형 변수 인코딩 전략 (Categorical Encoding)

머신러닝 알고리즘은 대부분 숫자 입력만 처리할 수 있으므로, 범주형 변수를 적절한 수치 표현으로 변환하는 것이 필수적입니다. 인코딩 방식의 선택은 변수의 특성에 따라 달라지며, 잘못된 선택은 모델 성능을 저하시킬 수 있습니다.

**순서형 변수(Ordinal Variable)**의 경우 레이블 인코딩(Label Encoding)이 적합합니다. 예를 들어 "소형-중형-대형"과 같이 자연스러운 순서가 있는 경우, 이 순서 정보를 숫자로 보존하는 것이 합리적입니다. 반면 **명목형 변수(Nominal Variable)**는 순서가 없으므로 원-핫 인코딩(One-Hot Encoding)을 사용하여 각 범주를 독립적인 이진 피처로 변환합니다.

python
# encoding_strategies.py
import pandas as pd
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
from sklearn.compose import ColumnTransformer

df = pd.DataFrame({
    "size": ["small", "medium", "large", "medium", "small"],
    "color": ["red", "blue", "green", "red", "blue"],
    "price": [10, 25, 40, 22, 12]
})

# Label encoding for ordinal feature (size has natural order)
le = LabelEncoder()
df["size_encoded"] = le.fit_transform(df["size"])  # large=0, medium=1, small=2

# One-hot encoding for nominal feature (color has no order)
ct = ColumnTransformer(
    transformers=[
        ("onehot", OneHotEncoder(drop="first", sparse_output=False), ["color"])
    ],
    remainder="passthrough"  # Keep other columns unchanged
)
result = ct.fit_transform(df[["color", "price"]])
# Produces: color_green, color_red columns (blue dropped as reference)

원-핫 인코딩에서 drop="first" 옵션을 사용하면 다중공선성(Multicollinearity) 문제를 방지할 수 있습니다. k개의 범주가 있을 때 k-1개의 더미 변수만 생성하면 나머지 하나의 범주는 다른 변수들로부터 유추 가능하기 때문입니다.

고카디널리티(High-Cardinality) 범주형 변수의 경우 원-핫 인코딩은 차원의 저주를 유발할 수 있습니다. 이런 경우 타겟 인코딩(Target Encoding), 빈도 인코딩(Frequency Encoding), 또는 임베딩(Embedding) 기법을 고려해야 합니다.

타겟 인코딩 시 데이터 누수 주의

타겟 인코딩은 범주별 타겟 변수의 평균값을 사용하므로, 교차 검증 시 각 폴드 내에서 별도로 인코딩을 수행해야 합니다. 전체 데이터로 인코딩한 후 분할하면 테스트 데이터의 정보가 학습에 누출되어 과적합된 검증 점수를 얻게 됩니다.

피처 스케일링 (Feature Scaling)

서로 다른 단위와 범위를 가진 피처들은 많은 머신러닝 알고리즘에서 문제를 일으킵니다. 경사 하강법 기반 모델, 거리 기반 알고리즘(KNN, SVM), 그리고 정규화를 사용하는 모델들은 피처 스케일에 민감하게 반응합니다. 적절한 스케일링은 학습 속도를 개선하고 최적화 과정의 안정성을 높입니다.

StandardScaler는 평균을 0, 표준편차를 1로 변환하여 정규 분포를 가정하는 알고리즘에 적합합니다. MinMaxScaler는 모든 값을 0과 1 사이로 압축하며, 신경망의 활성화 함수 범위와 맞추기에 유용합니다. 그러나 이 두 방법 모두 이상치(Outlier)에 취약합니다.

python
# feature_scaling.py
import numpy as np
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler

# Simulated dataset: salary with outliers
data = np.array([[35000], [42000], [55000], [67000], [450000]])  # 450k is an outlier

# StandardScaler: mean=0, std=1 (sensitive to outliers)
standard = StandardScaler().fit_transform(data)
# Result: [-0.72, -0.68, -0.60, -0.53, 2.53] — outlier distorts the scale

# MinMaxScaler: maps to [0, 1] (very sensitive to outliers)
minmax = MinMaxScaler().fit_transform(data)
# Result: [0.0, 0.017, 0.048, 0.077, 1.0] — most values crushed near zero

# RobustScaler: uses median and IQR (robust to outliers)
robust = RobustScaler().fit_transform(data)
# Result: [-0.77, -0.5, 0.0, 0.46, 15.38] — outlier isolated, core data preserved

RobustScaler는 중앙값(Median)과 사분위수 범위(IQR)를 사용하므로 이상치의 영향을 크게 줄일 수 있습니다. 금융 데이터나 의료 데이터처럼 극단값이 자주 나타나는 도메인에서 특히 유용합니다.

스케일러 선택 시 고려해야 할 사항으로는 데이터의 분포 특성, 이상치의 존재 여부, 그리고 사용할 알고리즘의 특성이 있습니다. 트리 기반 모델(Random Forest, XGBoost 등)은 분할 기준으로 상대적 순서만 사용하므로 스케일링이 성능에 영향을 주지 않습니다.

왜도 변환 (Skewness Transformations)

실제 데이터셋에서 수치형 피처들은 정규 분포를 따르지 않는 경우가 많습니다. 특히 소득, 주택 가격, 웹사이트 체류 시간 같은 변수들은 오른쪽으로 긴 꼬리를 가진 양의 왜도(Positive Skew)를 보입니다. 이러한 비대칭 분포는 선형 모델의 가정을 위반하고 이상치 탐지를 어렵게 만듭니다.

로그 변환(Log Transform)은 가장 단순하면서도 효과적인 방법입니다. 큰 값을 압축하고 작은 값 사이의 차이를 확대하여 분포를 정규 분포에 가깝게 만듭니다. Box-Cox 변환은 데이터로부터 최적의 변환 파라미터(lambda)를 자동으로 학습하여 더 유연한 정규화를 제공합니다.

python
# skew_transformations.py
import numpy as np
from sklearn.preprocessing import PowerTransformer

# Right-skewed income data (common in real datasets)
income = np.array([[25000], [32000], [41000], [55000], [72000],
                   [150000], [320000], [890000]])

# Log transform: simple, effective for right-skewed data
log_income = np.log1p(income)  # log1p handles zero values safely

# Box-Cox: finds optimal power parameter automatically
pt = PowerTransformer(method="box-cox")  # Requires strictly positive values
income_boxcox = pt.fit_transform(income)
print(f"Optimal lambda: {pt.lambdas_[0]:.3f}")  # Shows learned parameter

# Yeo-Johnson: works with zero and negative values too
pt_yj = PowerTransformer(method="yeo-johnson")
income_yj = pt_yj.fit_transform(income)

Box-Cox 변환은 양수 값만 처리할 수 있다는 제약이 있습니다. Yeo-Johnson 변환은 이 제약을 해결하여 0과 음수 값도 처리할 수 있으므로, 실무에서 더 범용적으로 활용됩니다.

왜도 변환 적용 시 주의할 점은 해석 가능성(Interpretability)의 손실입니다. 변환된 피처의 계수는 원본 스케일에서의 의미를 잃게 되므로, 비즈니스 해석이 중요한 경우 이 트레이드오프를 고려해야 합니다.

Data Science & ML 면접 준비가 되셨나요?

인터랙티브 시뮬레이터, flashcards, 기술 테스트로 연습하세요.

피처 선택 (Feature Selection)

피처 수가 증가할수록 모델 복잡도가 높아지고 과적합 위험이 커집니다. 또한 불필요한 피처는 노이즈를 추가하고 학습 시간을 늘립니다. 효과적인 피처 선택은 모델 성능을 유지하면서 복잡도를 줄이는 핵심 기술입니다.

피처 선택 방법은 크게 세 가지 범주로 나뉩니다. **필터 방법(Filter Methods)**은 통계적 검정을 사용하여 각 피처를 독립적으로 평가합니다. 빠르지만 피처 간 상호작용을 고려하지 못합니다. **래퍼 방법(Wrapper Methods)**은 실제 모델을 반복적으로 학습하면서 최적의 피처 부분집합을 탐색합니다. 정확하지만 계산 비용이 높습니다. **임베디드 방법(Embedded Methods)**은 모델 학습 과정에서 피처 선택이 자동으로 이루어집니다. L1 정규화(Lasso)가 대표적인 예입니다.

python
# feature_selection.py
from sklearn.datasets import make_classification
from sklearn.feature_selection import (
    SelectKBest, f_classif,  # Filter method
    SequentialFeatureSelector,  # Wrapper method
    SelectFromModel  # Embedded method
)
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LassoCV

# Dataset: 20 features, only 5 are informative
X, y = make_classification(
    n_samples=1000, n_features=20,
    n_informative=5, n_redundant=3, random_state=42
)

# Filter: ANOVA F-test selects top k features by statistical significance
selector_filter = SelectKBest(f_classif, k=8)
X_filtered = selector_filter.fit_transform(X, y)
print(f"Selected features: {selector_filter.get_support(indices=True)}")

# Embedded: L1 regularization (Lasso) zeros out irrelevant feature weights
lasso = LassoCV(cv=5, random_state=42).fit(X, y)
selector_embedded = SelectFromModel(lasso, prefit=True)
X_lasso = selector_embedded.transform(X)
print(f"Lasso kept {X_lasso.shape[1]} features out of {X.shape[1]}")

Lasso 회귀의 L1 정규화는 덜 중요한 피처의 가중치를 정확히 0으로 만드는 특성이 있어, 자동으로 피처 선택을 수행합니다. 트리 기반 모델의 피처 중요도(Feature Importance)도 널리 사용되지만, 고카디널리티 범주형 변수에 편향될 수 있다는 점을 인지해야 합니다.

더 많은 머신러닝 알고리즘과 그 작동 원리에 대해서는 머신러닝 알고리즘 완벽 가이드를 참고하시기 바랍니다.

프로덕션 파이프라인 구축 (Production Pipelines)

실험 환경에서 프로덕션으로 전환할 때 가장 흔한 실수는 전처리 단계에서의 데이터 누수(Data Leakage)입니다. 스케일러를 전체 데이터에 fit한 후 train-test 분할을 수행하면, 테스트 데이터의 통계량이 학습에 반영되어 과적합된 평가 결과를 얻게 됩니다.

Scikit-learn의 PipelineColumnTransformer를 사용하면 이러한 문제를 체계적으로 방지할 수 있습니다. 파이프라인은 전처리와 모델을 하나의 객체로 캡슐화하여, 교차 검증 시 각 폴드에서 올바르게 fit과 transform이 분리되도록 보장합니다.

python
# production_pipeline.py
import pandas as pd
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import cross_val_score

# Define column groups by type
numeric_features = ["age", "income", "credit_score"]
categorical_features = ["education", "employment_type", "region"]

# Numeric pipeline: impute missing values, then scale
numeric_pipeline = Pipeline([
    ("imputer", SimpleImputer(strategy="median")),  # Median resists outliers
    ("scaler", StandardScaler())
])

# Categorical pipeline: impute missing, then one-hot encode
categorical_pipeline = Pipeline([
    ("imputer", SimpleImputer(strategy="most_frequent")),
    ("encoder", OneHotEncoder(handle_unknown="ignore", sparse_output=False))
])

# Combine into a single preprocessor
preprocessor = ColumnTransformer([
    ("num", numeric_pipeline, numeric_features),
    ("cat", categorical_pipeline, categorical_features)
])

# Full pipeline: preprocessing + model in one object
full_pipeline = Pipeline([
    ("preprocessor", preprocessor),
    ("classifier", GradientBoostingClassifier(n_estimators=200, random_state=42))
])

# Cross-validation applies preprocessing correctly within each fold
scores = cross_val_score(full_pipeline, X, y, cv=5, scoring="roc_auc")
print(f"AUC: {scores.mean():.3f} +/- {scores.std():.3f}")

handle_unknown="ignore" 옵션은 배포 환경에서 학습 시 보지 못한 새로운 범주가 나타났을 때 에러 대신 0 벡터를 반환하도록 합니다. 이는 프로덕션 환경의 안정성을 위해 필수적인 설정입니다.

결측치 처리에서 중앙값(Median)을 사용하는 것은 이상치에 강건한 전략입니다. 범주형 변수의 경우 최빈값(Most Frequent)이나 별도의 "Missing" 범주를 생성하는 방법을 선택할 수 있습니다.

자동화된 피처 엔지니어링 (Automated Feature Engineering)

관계형 데이터베이스에서 피처를 추출하는 작업은 반복적이고 시간 소모적입니다. Featuretools 라이브러리는 Deep Feature Synthesis(DFS) 알고리즘을 통해 테이블 간 관계를 활용한 자동 피처 생성을 지원합니다.

DFS는 집계 프리미티브(Aggregation Primitives)와 변환 프리미티브(Transformation Primitives)를 조합하여 다양한 피처를 생성합니다. 예를 들어 고객-거래 관계에서 "고객별 거래 횟수", "고객별 평균 거래 금액", "고객별 거래 금액 표준편차" 등의 피처가 자동으로 생성됩니다.

python
# automated_feature_engineering.py
import featuretools as ft
import pandas as pd

# Define entities from relational tables
customers = pd.DataFrame({
    "customer_id": [1, 2, 3],
    "signup_date": pd.to_datetime(["2024-01-15", "2024-03-22", "2024-06-01"]),
    "region": ["US", "EU", "APAC"]
})

transactions = pd.DataFrame({
    "txn_id": range(1, 8),
    "customer_id": [1, 1, 1, 2, 2, 3, 3],
    "amount": [50, 120, 30, 200, 85, 340, 15],
    "category": ["food", "tech", "food", "tech", "travel", "food", "tech"]
})

# Create an EntitySet with relationships
es = ft.EntitySet(id="retail")
es = es.add_dataframe(dataframe=customers, dataframe_name="customers",
                      index="customer_id", time_index="signup_date")
es = es.add_dataframe(dataframe=transactions, dataframe_name="transactions",
                      index="txn_id")
es = es.add_relationship("customers", "customer_id",
                         "transactions", "customer_id")

# DFS generates features: COUNT, MEAN, MAX, STD of transactions per customer
feature_matrix, feature_defs = ft.dfs(
    entityset=es, target_dataframe_name="customers",
    max_depth=2,  # Controls complexity of generated features
    trans_primitives=["month", "weekday"],  # Transformation primitives
    agg_primitives=["count", "mean", "std", "max"]  # Aggregation primitives
)
print(f"Generated {len(feature_defs)} features from 2 tables")

max_depth 파라미터는 피처 복잡도를 제어합니다. depth가 높을수록 더 복잡한 조합 피처가 생성되지만, 해석 가능성이 떨어지고 과적합 위험이 증가합니다. 실무에서는 depth 2-3이 적절한 균형점으로 알려져 있습니다.

자동 피처 엔지니어링은 탐색적 분석 단계에서 유용한 출발점을 제공하지만, 도메인 전문 지식을 대체할 수는 없습니다. 생성된 피처들 중 비즈니스적으로 의미 있고 모델 성능에 기여하는 것들을 선별하는 과정이 필요합니다.

기술 면접 빈출 질문

피처 엔지니어링은 데이터 과학자 면접에서 빈번하게 다뤄지는 주제입니다. 다음은 실제 면접에서 자주 등장하는 질문들과 핵심 포인트입니다.

면접 준비 팁

단순히 개념을 암기하기보다 실제 프로젝트에서 해당 기법을 적용한 경험을 구체적으로 설명할 수 있어야 합니다. "왜 그 방법을 선택했는지", "다른 대안은 무엇이었는지", "결과적으로 성능이 어떻게 개선되었는지"를 명확히 전달하는 것이 중요합니다.

Q1: 원-핫 인코딩과 레이블 인코딩의 차이점과 각각 언제 사용하는지 설명하세요.

레이블 인코딩은 순서가 있는 범주형 변수(예: 학력 - 고졸/대졸/석사/박사)에 적합합니다. 숫자의 크기가 의미를 가지므로 순서 정보가 보존됩니다. 원-핫 인코딩은 순서가 없는 명목형 변수(예: 색상, 지역)에 사용합니다. 각 범주를 독립적인 이진 피처로 변환하여 인위적인 순서 관계가 생기지 않도록 합니다.

Q2: 피처 스케일링이 모델 성능에 미치는 영향을 설명하세요. 스케일링이 불필요한 모델은 무엇인가요?

스케일링은 경사 하강법 기반 모델(선형 회귀, 로지스틱 회귀, 신경망)의 수렴 속도를 개선하고, 거리 기반 모델(KNN, SVM, K-means)의 공정한 거리 계산을 보장합니다. 트리 기반 모델(Decision Tree, Random Forest, XGBoost)은 피처의 절대값이 아닌 분할 임계값의 상대적 위치만 사용하므로 스케일링이 성능에 영향을 주지 않습니다.

Q3: 데이터 누수(Data Leakage)란 무엇이며, 피처 엔지니어링에서 어떻게 방지할 수 있나요?

데이터 누수는 학습 시점에 사용할 수 없는 정보가 모델에 포함되는 현상입니다. 피처 엔지니어링에서 대표적인 예로 전체 데이터로 스케일러를 fit한 후 분할하거나, 타겟 인코딩을 교차 검증 외부에서 수행하는 경우가 있습니다. Pipeline을 사용하여 전처리와 모델을 캡슐화하면 교차 검증 시 자동으로 누수가 방지됩니다.

Q4: 고카디널리티 범주형 변수를 어떻게 처리하시겠습니까?

원-핫 인코딩은 차원 폭발을 유발하므로 적합하지 않습니다. 대안으로 타겟 인코딩(각 범주를 타겟 평균으로 대체), 빈도 인코딩(출현 빈도로 대체), 범주 그룹화(드문 범주를 "기타"로 통합), 또는 임베딩(신경망에서 학습)을 사용할 수 있습니다. 타겟 인코딩 시에는 반드시 교차 검증 폴드 내에서 수행하여 누수를 방지해야 합니다.

Q5: Box-Cox 변환과 로그 변환의 차이점은 무엇인가요?

로그 변환은 고정된 변환(log(x))을 적용하는 반면, Box-Cox는 데이터로부터 최적의 lambda 파라미터를 학습합니다. lambda=0일 때 로그 변환과 동일하며, lambda=1이면 변환이 없습니다. Box-Cox는 더 유연하지만 양수 데이터만 처리할 수 있고, Yeo-Johnson은 이 제약을 해결합니다.

더 많은 피처 엔지니어링 면접 문제와 상세 해설은 피처 엔지니어링 면접 질문 모음에서 확인할 수 있습니다.

연습을 시작하세요!

면접 시뮬레이터와 기술 테스트로 지식을 테스트하세요.

결론

피처 엔지니어링은 머신러닝 프로젝트의 성패를 좌우하는 핵심 역량입니다. 데이터의 특성을 이해하고 적절한 변환을 적용하는 능력은 알고리즘 지식만큼이나 중요하며, 실무 경험을 통해 발전시켜 나가야 합니다.

Python과 Scikit-learn의 데이터 처리 기초를 더 깊이 학습하고 싶다면 Python 데이터 과학 핵심 가이드: NumPy, Pandas, Scikit-learn을 참고하시기 바랍니다.

핵심 내용을 정리하면 다음과 같습니다.

  • 범주형 인코딩: 순서형 변수에는 레이블 인코딩, 명목형 변수에는 원-핫 인코딩을 사용하며, 고카디널리티 변수는 타겟 인코딩이나 임베딩을 고려합니다.
  • 피처 스케일링: StandardScaler는 정규 분포 가정 시, MinMaxScaler는 범위 제한이 필요할 때, RobustScaler는 이상치가 있을 때 적합합니다.
  • 왜도 변환: 로그 변환은 간단하고 효과적이며, Box-Cox/Yeo-Johnson은 최적의 파라미터를 자동으로 학습합니다.
  • 피처 선택: 필터 방법은 빠르지만 상호작용을 무시하고, 임베디드 방법(Lasso)은 모델 학습과 선택을 동시에 수행합니다.
  • 프로덕션 파이프라인: Pipeline과 ColumnTransformer를 사용하여 데이터 누수를 방지하고 재현 가능한 워크플로우를 구축합니다.
  • 자동화: Featuretools의 DFS는 관계형 데이터에서 피처를 자동 생성하지만, 도메인 지식 기반의 검토가 필수적입니다.

연습을 시작하세요!

면접 시뮬레이터와 기술 테스트로 지식을 테스트하세요.

태그

#feature engineering
#machine learning
#scikit-learn
#data science
#interview preparation
#python

공유

관련 기사