1. Feature Engineering
머신러닝 성능은 “모델이 얼마나 똑똑하냐”보다 데이터가 모델이 이해하기 좋은 형태냐에 크게 좌우된다.
“Garbage In, Garbage Out”
그리고 피처 엔지니어링은 크게 3가지로 나뉜다
- Feature Transformation(변환): 스케일링, 로그변환처럼 “형태” 바꾸기
- Feature Creation(생성): 기존 값들을 조합해 “새 의미” 만들기(파생 변수)
- Feature Selection(선택): 쓸만한 피처만 남기고 불필요한 건 제거(과적합 방지, 모델 단순화에 기여)
1.1. 숫자형 피처 처리(Scaling)
“변수 범위를 일정한 기준으로 맞춰 특정 변수에 과도 의존하는 것을 방지”
1.1.1. 표준화(Standarization-z-score)
목표: 평균을 0, 표준편차를 1로 맞춰서 “기준선을 통일”
언제 좋나?
- 정규분포에 가까운 데이터
- 거리 기반/선형 모델에서 자주 사용
(KNN, K-Means, SVM, 선형회귀/로지스틱 등)
장점/주의
- 👍 서로 다른 단위를 “비슷한 스케일”로 맞춤
- 👎 이상치(outlier)에 영향을 받을 수 있음(평균/표준편차가 흔들림)
1.1.2. 정규화(Min-Max Scaling)
목표: 모든 피처 값을 0과 1 사이로 조정
언제 좋나?
- 데이터의 최소/최대값을 명확히 알 때 유용
- 이미지 픽셀처럼 원래 스케일이 고정돼 있는 데이터
- 신경망 학습에서도 자주 등장
장점/주의
- 👍 해석이 직관적(0~1)
- 👎 이상치에 매우 민감(최소/최대가 이상치면 전체가 눌림)
1.1.3. Robust Scaling
목표: 중앙값(median)과 IQR(사분위 범위)을 기준으로 스케일링
→ 이상치가 있어도 기준이 쉽게 흔들리지 않음
언제 좋나?
- 의료/헬스케어처럼 이상치가 자주 섞이는 데이터
- “극단값 때문에 전체 스케일이 망가지는 상황”을 막고 싶을 때
장점/주의
- 👍 이상치에 강함
- 👎 표준화/정규화보다 결과 분포가 덜 “정돈”돼 보일 수 있음(하지만 실전에서 더 안전한 경우 많음)
1.2. 범주형 피처 처리
범주형은 글자/카테고리라서 모델이 그대로는 못 먹는다.
→ 컴퓨터가 이해할 수 있게 숫자로 인코딩(Encoding) 해야 한다.
(ex. LabelEncoding, OneHotEncoding)
1.3. 고급 피처 엔지니어링 기법
1.3.1. 시계열 데이터
시간 흐름이 있는 데이터(심박수, 주가, 센서 등)는 “현재 값”만 보면 반쪽짜리다.
과거 흐름이 피처가 된다.
즉, 시계열의 정보는 현재 값 + 직전 흐름(패턴)에 들어 있다.
대표 기법
- Lag(지연) 피처: t-1, t-2… 과거 값을 컬럼으로 추가
(look back: 예측하고자 하는 날짜로부터 몇 일 전을 볼 것인가)
- Rolling 통계량: “최근 구간의 요약값”
(최근 7일 평균, 최근 30일 표준편차 등. 단일 값보다 “최근 상태의 안정성/변동성”을 잘 잡는다.)
- 추세/변동성: "얼마나 빨리 변하나?" 증가/감소 기울기(Trend), 변동 폭(Delta)
(급격한 상승/하강 자체가 중요한 신호가 되는 경우가 많음. 의료/헬스에서는 특히 유용)
- 시간 파생 피쳐: "시간 그 자체를 정보로 쓰기"
(시간/요일/주말 여부. 수면/활동/식사 패턴 등은 시간에 강하게 묶여있기 때문)
👉 “지금 상태” = “최근 패턴의 결과”인 경우가 많다.
시계열에서 제일 흔한 실수: “미래를 훔쳐보기(누수)”
- 시계열은 반드시 시간 순서대로 train/test가 나뉘어야 함
- 실수 예: 랜덤 셔플로 K-Fold → 미래 데이터가 train에 섞임
- 실수 예: rolling을 만들 때 중심(center=True) 같은 설정으로 미래 구간이 포함됨
- 원칙
- 시계열 예측/평가: TimeSeriesSplit처럼 시간 기반 분할
- rolling/집계: “과거 방향”만 포함되게 만들기
1.3.2. 신호 처리(푸리에/웨이블릿 변환)
ECG/PPG 같은 신호는 시간영역(time domain)에서는 그냥 “위아래로 흔들리는 그래프”인데,
주파수영역(frequency domain)으로 바꾸면:
-
어떤 리듬(주기)이 강한지
-
잡음이 어느 대역에 몰렸는지
-
특정 질환/이상 패턴이 특정 대역에서 튀는지
같은 정보가 깔끔하게 보이는 경우가 많다.
-
푸리에 변환(FFT): “파형을 ‘리듬 성분’으로 분해”
- “이 파형은 1초에 몇 번 흔들리는 성분이 강한가?”를 숫자로 바꾼다
- 신호에서 자주 뽑는 FFT 피처 예시
- 특정 주파수 대역 에너지(power)
- dominant frequency(가장 강한 주파수)
- spectral entropy(주파수 분포의 복잡도)
- 언제 FFT가 강하나?
- 패턴이 “반복 리듬”으로 나타나는 신호
- 잡음 제거/특정 대역 강조가 중요한 경우
- 전체 구간을 한 번에 분해하기 때문에 “초반엔 천천히, 후반엔 빠르게” 같은 변화엔 약할 수 있음
-
웨이블릿: 시간에 따라 주파수가 변하는 패턴까지 포착(더 유연)
- 시간 구간별로 주파수 성분을 동시에 잡아줘서 “언제 어떤 주파수가 강했는지” 같은 정보를 잘 보존한다.
- 언제 웨이블릿이 더 유리?
- 운동 시작/중단처럼 패턴이 “구간별로 달라지는” 신호
- 발작/이상 이벤트처럼 짧은 구간에서만 발생하는 패턴
👉 직관적으로는 “파형을 구성하는 리듬을 분해해서 특징을 뽑는다”
- 신호 FE에서 흔한 실수
- 샘플링 주파수(Hz) 무시: 50Hz로 측정한 신호와 200Hz 신호는 FFT 축 의미가 달라짐
- 필터링/정규화 위치 누수: 전체 데이터를 한 번에 정규화/필터링하면 평가가 뻥튀기될 수 있음
→ Pipeline/훈련 구간 기준으로 fit 후 적용
1.3.3. 비정형 데이터
비정형은 “표처럼 정리된 숫자 컬럼”이 아니라서 먼저 숫자 벡터로 번역해야 한다
- 텍스트(Text)
- TF-IDF: “자주 나오지만 흔하지 않은 단어에 점수”
- TF: 문서 안에서 자주 등장하는 정도
- IDF: 전체 문서에 흔하면 가치↓, 드물면 가치↑
👉 즉, “그 문서의 특징을 잘 드러내는 단어”를 숫자로 만든다.
- 언제 충분히 강력한가?
- 리뷰/설문/증상 기록처럼 “키워드 자체가 신호”인 데이터
- 데이터가 아주 크지 않고 빠르게 baseline 만들 때
- 자주 하는 실수
- 형태소/토큰화 없이 막 넣기(한국어는 특히 성능이 크게 흔들림)
- 불용어(stopwords) 처리를 안 해 “의미 없는 단어”가 지배하는 상황
- 이미지(Image)
- 수동으로 “색 평균, 경계선 개수…” 같은 걸 만들기보다 CNN이 특징을 자동 추출하는 흐름 많이 이용
- 실전에서 많이 쓰는 방식
- 이미지 → 사전학습 CNN 통과
- 마지막 분류층 전의 벡터(특징) 뽑기
- 그 벡터로 분류/회귀
- 장점
- 사람이 정의하기 어려운 패턴(텍스처, 형태)을 잘 잡음
- 주의
- 데이터 증강(augmentation)은 train에만 fit/적용되도록 설계
- 라벨이 적으면 과적합이 빠르게 올 수 있음(전이학습/고정층 활용)
1.3.4. 자동화 기법
“사람이 수동으로 피처를 만들기 힘든 경우”에
모델이 스스로 압축 표현(latent feature)을 학습하게 하는 방법
- 어디에 쓰나?
- 비정형(이미지/신호)에서 요약 피처 만들기
- 이상치 탐지(복원이 유난히 안 되는 샘플 = 이상치 후보)
- 차원이 너무 큰 표형 데이터에서 “압축 표현” 만들기(상황에 따라)
- 자동화 FE의 함정
- 압축된 피처는 해석이 어려울 수 있음
- 학습이 잘못되면 “그럴듯하지만 의미 없는 요약”을 만들 수도 있음
→ 검증(재현성)과 비교 기준(PCA/간단 모델 baseline)이 중요
1.4. 올바른 피처 선택하기
1.4.1. Filter
모델 학습 전에, 통계 기준(상관관계, 상호 정보량 등)으로 빠르게 걸러내는 방식
대표 예시
VarianceThreshold: 분산이 매우 낮거나 0인(모든 샘플에서 동일한 값을 갖는) 피처 제거
SelectKBest/SelectPercentile: 지정된 개수(k) 또는 백분율만큼 가장 높은 점수를 받은 특성 선택
- 주요 평가 함수
- 분류:
chi2(카이제곱), f_classif(F-검정), mutual_info_classif(상호 정보량)
- 회귀:
f_regression, mutual_info_regression
장단점
- 👍 빠르고 간단, 모델 종류에 구애 x, 과적합 위험 낮음
- 👎 피처 간의 조합 효과를 고려하지 못함, 선택된 조합이 특정 모델에 최적이 아닐 수 있음
1.4.2. Wrapper
모델 성능을 기준으로 “최적 피처 조합”을 찾는다
대표 예시
- RFE(Recursive Feature Elimination. 재귀적 피처 제거):
- Step1. 전체 특성으로 학습
- Step2. 가장 중요도가 낮은 피처를 하나씩 제거
- RFECV는 교차 검증을 통해 최적 조합 자동 탐색
- 모델이
coef_ or feature_importances_속성을 제공해야 사용 가능
- 문제는 언제 생기나? 👉 피처 간 상호작용이 있을 때
- 예시:
- A, B는 같이 있을 때만 의미 있음
- 개별 중요도는 낮게 나옴
- RFE: “둘 다 별로네” → 제거
- 결과: 성능 급락 😵
- RFE는 “혼자 봤을 때 중요한 피처”를 좋아한다
- SFS(Sequential Feature Selection. 순차적 피처 선택):
- Forward-SFS: 특성이 없는 상태에서 시작. 모델 성능을 가장 크게 향상시키는 특성을 하나씩 추가
- Backward-SFS: 전체 특성에서 시작. 성능 저하가 가장 적은 특성 하나씩 제거
- RFE보다 속도가 느리나 사용 유연성은 높음(
coef_속성 없어도 사용 가능)
장단점
- 👍 모델 성능에 맞춘 “진짜 최적 조합”을 찾기 쉬움
- 👎 계산 비용이 큼(피처 많으면 매우 느림)
1.4.3. Embedded method
모델 학습 과정 안에서 선택이 자동으로 포함되는 방식
대표 예시
- L1 기반(Lasso): 중요하지 않은 피처 계수를 0으로 만들어 제거 효과
- 트리 기반(RandomForest/GBM 등): 각 특성이 불순도를 얼마나 감소시키는지(지니계수 등)를 기준으로
특성 중요도 계산
- SelectFromModel: 학습된 모델의
coef_ or feature_importances_를 기반으로
지정된 임계값(threshold) 이상만 선택
장단점
- 👍 성능/속도/실용성 균형 좋음
- 👎 선택 결과가 모델 성격에 의존(모델 바꾸면 선택도 바뀔 수 있음)
1.5. RFECV
RFE는 “몇 개 남길지”를 정해야 하는데, RFECV는 그 개수까지 CV로 자동 결정해준다
- Step 1. 모델 학습
- Step 2. 중요도 낮은 피처 제거
- Step 3. CV 점수 평가
- Step 4. “성능이 가장 좋은 피처 개수”를 선택
👉 피처 선택을 “감”이 아니라 검증 기반으로 자동화한 버전.
2. CV(Cross-Validation)
- train/test 한 번 split은 우연의 영향이 있을 수 있음
- CV는 평균 성능 + 분산(안정성)까지 볼 수 있음
👉 데이터를 여러 번 나눠서 반복 검증해 “운빨”을 줄이는 방법
2.1. K-Fold
- Step 1. 데이터를 K개로 나누고, (K-1)개로 학습
- Step 2. 1개로 검증
- Step 3. Step 1,2를 K번 반복
장점
주의
- 데이터가 불균형이면 fold마다 라벨 비율이 깨질 수 있음
→ 그때는 Stratified K-Fold로 사용
2.2. Stratified K-Fold
- K-Fold의 단점(라벨 비율 깨짐)을 보완.
- 각 fold에 클래스 비율을 최대한 동일하게 유지한다.
2.3. Group K-Fold
“같은 그룹(사람/병원/환자ID)이 train과 valid에 동시에 들어가면 안 되는” 상황에서 사용.
ex. 환자 1명이 여러 행을 가진 데이터
같은 환자의 일부 기록이 train, 일부가 valid로 들어가면
→ 모델이 사실상 “그 사람을 외워서” 점수가 뻥튀기 될 수 있음
👉 Group K-Fold는 그룹 단위로 fold를 나눈다.
2.4. Nested CV
하이퍼파라미터 튜닝까지 포함해서 “검증을 또 검증”하는 방식
구조는 2겹이다.
- 바깥 CV(outer): 최종 성능 평가(진짜 시험)
- 안쪽 CV(inner): 하이퍼파라미터 탐색(연습)
왜 필요한가?
GridSearchCV 같은 튜닝을 같은 CV에서 평가하면
→ 튜닝 과정이 검증셋에 “적응”해서 성능이 과대평가될 수 있음
Nested는 이를 구조적으로 차단
아래와 같이 이루어진다고 볼 수 있다.

2.5. Pipeline(데이터 누수를 막기 위한 방법)
여러 단계를 하나의 객체로 묶어 데이터 누수 없이 전처리 및 모델 학습 과정을 자동화, 재현성 보장
from sklearn.pipeline import Pipeline
pipe = Pipeline([('Step1 단계명', 단계), ('Step2 단계명', 2단계), ...])
2.5.1. 올바른 pipeline 사용 방법

[잘못된 방법]

[옳은 방법. 출처: Using Pipelines with Cross-Validation]
[참고 사이트]