Skip to main content
Summary

이 장에서 배울 것

이 장의 목표는 데이터를 "모델에 넣기 전의 원재료"가 아니라 "운영 시스템의 핵심 입력"으로 다루는 것입니다. 좋은 모델을 만들기 전에 먼저 나쁜 데이터가 자동으로 들어오지 못하게 막아야 합니다.

이 장을 끝내면 다음을 할 수 있습니다.

  • 데이터 오류가 수집, 정제, 학습, 배포, 모니터링 단계로 전파되는 과정을 설명합니다.

  • 배치 파일, 스트리밍 이벤트, 로그, 외부 API, 데이터베이스, 객체 스토리지의 수집 특성을 구분합니다.

  • 스키마, 타입, 결측률, 중복률, 값 범위, 분포를 자동 검증하는 기준을 설계합니다.

  • 품질 게이트, 격리 저장소, 알림, 중단 정책을 포함한 작은 데이터 검증 파이프라인을 만듭니다.

  • 라벨링 데이터 품질을 모델 성능뿐 아니라 운영 리스크 관점에서 바라봅니다.

데이터 수집과 품질 관리

왜 이 주제가 중요한가

머신러닝 시스템은 코드만으로 동작하지 않습니다. 같은 코드와 같은 모델이라도 입력 데이터가 달라지면 결과가 달라집니다. 그래서 ML 시스템의 품질은 코드 품질뿐 아니라 데이터 품질에 강하게 묶여 있습니다. CRISP-ML(Q) 같은 ML 생애주기 모델도 초기에 데이터 요구사항과 품질 기준을 문서화하고, 이후 단계에서 재현 가능한 전처리 파이프라인을 만드는 것을 중요한 품질 보증 활동으로 봅니다.1

운영에서 더 위험한 문제는 데이터 오류가 조용히 전파된다는 점입니다. 예를 들어 고객 나이 컬럼이 어느 날부터 문자열로 들어오거나, 결제 이벤트가 중복 수집되거나, 라벨 기준이 바뀌었는데 아무도 모른다고 해봅시다. 처음에는 학습 데이터의 작은 이상처럼 보입니다. 하지만 이 오류는 피처 저장소, 학습 파이프라인, 모델 레지스트리, 서빙 시스템까지 이어질 수 있습니다. 결과적으로 모델 성능 저하, 잘못된 의사결정, 장애, 규정 위반으로 커집니다.

MLOps에서 데이터 품질 관리는 별도 부록이 아닙니다. 수집부터 운영 모니터링까지 계속 이어지는 생애주기 관리입니다. Google의 MLOps 자동화 문서에서도 ML의 CI는 코드뿐 아니라 데이터, 데이터 스키마, 모델까지 검증해야 하며, 자동 학습 파이프라인에는 데이터 검증과 모델 검증 단계가 포함되어야 한다고 설명합니다.2

핵심 개념 설명

데이터 소스마다 실패 방식이 다르다

데이터를 수집한다고 해서 모두 같은 문제가 생기는 것은 아닙니다. 소스별로 자주 발생하는 실패가 다릅니다.

데이터 소스특징자주 생기는 문제
배치 파일CSV, Parquet, Excel 등을 주기적으로 적재파일 누락, 컬럼 순서 변경, 인코딩 오류, 일부 행 깨짐
스트리밍 이벤트클릭, 결제, 센서 이벤트를 실시간 수집중복 이벤트, 순서 뒤바뀜, 지연 도착, 재처리 문제
애플리케이션 로그서비스 동작 중 남는 로그로그 포맷 변경, 필드 누락, 샘플링 정책 변경
외부 API외부 업체나 공공 데이터 호출응답 지연, 호출 제한, 필드 이름 변경, 일시적 빈 응답
데이터베이스운영 DB나 분석 DB에서 추출조인 오류, 삭제/수정 반영 지연, 스냅샷 시점 불일치
객체 스토리지S3, GCS 같은 대용량 저장소잘못된 경로 적재, 파티션 누락, 중복 파일, 권한 오류

중요한 것은 "데이터가 들어왔는가"만 확인하지 않는 것입니다. "예상한 데이터가, 예상한 시점에, 예상한 형식과 의미로 들어왔는가"를 확인해야 합니다.

데이터 품질의 기본 차원

데이터 품질은 단순히 결측치가 없는 상태가 아닙니다. 실제 운영에서는 다음 관점이 필요합니다. 데이터 품질 관리에서는 정확성, 완전성, 일관성, 최신성, 유효성, 보안 같은 차원을 주요 기준으로 다룹니다.3

  • 정확성: 값이 현실을 올바르게 나타내는가?

  • 완전성: 필요한 행과 컬럼이 충분히 있는가?

  • 일관성: 서로 다른 테이블이나 컬럼 간 의미가 충돌하지 않는가?

  • 적시성: 필요한 시점에 최신 데이터가 도착했는가?

  • 유효성: 값이 비즈니스 규칙을 만족하는가?

  • 보안과 개인정보: 민감 정보가 허용된 방식으로만 사용되는가?

예를 들어 age = 350은 타입이 정수라서 기술적으로는 통과할 수 있습니다. 하지만 비즈니스 규칙으로는 실패입니다. country = KR인데 currency = USD가 들어오는 경우도 단일 컬럼만 보면 이상하지 않을 수 있습니다. 그러나 두 컬럼을 함께 보면 검증이 필요합니다.

학습 전에 확인해야 할 것들

데이터 검증 단계는 피처 엔지니어링이나 학습 전에 실행되어야 합니다. 최소한 다음 항목은 자동화하는 것이 좋습니다.

  • 스키마: 필요한 컬럼이 모두 있는가?

  • 타입: 숫자, 문자열, 날짜 타입이 예상과 같은가?

  • 필수 컬럼: ID, 타깃, 이벤트 시간처럼 반드시 필요한 값이 비어 있지 않은가?

  • 값 범위: 나이, 가격, 확률, 점수 등이 허용 범위 안에 있는가?

  • 결측률: 컬럼별 결측 비율이 허용 임계값 이하인가?

  • 중복률: 동일 ID나 이벤트가 과도하게 중복되지 않았는가?

  • 범주 값 분포: 새 범주가 갑자기 등장하거나 특정 범주만 폭증하지 않았는가?

  • 시간 순서: 이벤트 시간이 미래이거나, 생성 시간이 처리 시간보다 늦지 않은가?

  • 참조 무결성: 주문 데이터의 고객 ID가 고객 테이블에 존재하는가?

  • 기본 통계 분포: 평균, 표준편차, 분위수, 최솟값, 최댓값이 기준선과 크게 달라지지 않았는가?

이 검증은 "데이터를 깨끗하게 만드는 작업"과 다릅니다. 검증의 첫 목적은 이상한 데이터가 다음 단계로 넘어가지 못하게 막는 것입니다.

데이터 계약과 품질 게이트

데이터 계약은 데이터를 만드는 팀과 사용하는 팀 사이의 약속입니다. 예를 들어 추천 모델 팀은 이벤트 수집 팀과 다음과 같은 계약을 맺을 수 있습니다.

  • user_id, item_id, event_type, event_time은 반드시 존재합니다.

  • event_type은 view, click, purchase 중 하나입니다.

  • 이벤트는 최대 30분 지연까지 허용합니다.

  • 동일 event_id 중복률은 0.1% 이하로 유지합니다.

  • 스키마 변경은 최소 1주 전에 공지합니다.

품질 게이트는 이 계약을 코드로 실행하는 문입니다. 통과하면 학습 파이프라인으로 보냅니다. 실패하면 격리 저장소로 옮기고, 알림을 보내고, 파이프라인을 멈춥니다. 중요한 데이터라면 "경고 후 계속 진행"보다 "실패 시 중단"이 안전합니다.

쉬운 비유 또는 사례

데이터 품질 게이트는 공장 입구의 검수대와 비슷합니다. 자동차 공장에 잘못된 규격의 부품이 들어오면 조립 라인 전체가 멈출 수 있습니다. 작은 나사 하나가 틀려도 최종 제품은 불량이 됩니다.

ML 파이프라인도 같습니다. 잘못된 데이터가 한 번 학습 데이터에 섞이면 모델은 그 오류를 학습합니다. 더 나쁜 경우, 잘못된 모델이 배포되어 사용자 행동을 바꾸고, 그 행동이 다시 학습 데이터로 들어옵니다. 이때부터는 오류가 단순한 데이터 문제가 아니라 운영 루프 전체의 문제가 됩니다.

예를 들어 스팸 탐지 모델을 운영한다고 해봅시다. 어느 날 로그 수집 코드가 바뀌어 HTML 이메일의 본문이 비어 있는 문자열로 저장되었습니다. 검증 없이 학습하면 모델은 "본문이 비어 있음"을 정상 패턴으로 배울 수 있습니다. 이후 실제 운영에서 HTML 스팸을 잘 잡지 못합니다. 문제는 모델 구조가 아니라 수집 데이터였습니다.

직접 해보는 실습: 작은 데이터 품질 게이트 만들기

아래 실습은 간단한 고객 데이터에 대해 품질 기준을 코드로 정의하고, 실패 데이터를 격리하는 예제입니다. 실제 프로젝트에서는 Pandera, Great Expectations, TensorFlow Data Validation 같은 도구를 쓸 수 있습니다. Pandera처럼 데이터프레임 스키마와 체크를 코드로 정의하는 방식은 CI/CD나 학습 파이프라인에 붙이기 쉽습니다.4

1단계: 예제 데이터 만들기

import pandas as pd
from pathlib import Path

Path("data/quarantine").mkdir(parents=True, exist_ok=True)
Path("reports").mkdir(exist_ok=True)

df = pd.DataFrame({
    "customer_id": [1, 2, 2, 4],
    "age": [29, 350, 41, None],
    "income": [5000.0, 7000.0, -10.0, 6200.0],
    "country": ["KR", "KR", "US", "UNKNOWN"],
    "label": [0, 1, 1, None]
})

2단계: 품질 기준 정의하기

RULES = {
    "required_columns": ["customer_id", "age", "income", "country", "label"],
    "max_missing_rate": {"age": 0.10, "label": 0.00},
    "allowed_country": {"KR", "US", "JP"},
    "max_duplicate_customer_rate": 0.05,
    "age_range": (0, 120),
    "income_min": 0
}

3단계: 검증 함수 작성하기

def validate_customer_data(df: pd.DataFrame) -> dict:
    errors = []

    missing_columns = set(RULES["required_columns"]) - set(df.columns)
    if missing_columns:
        errors.append(f"필수 컬럼 누락: {sorted(missing_columns)}")

    if not missing_columns:
        for col, threshold in RULES["max_missing_rate"].items():
            rate = df[col].isna().mean()
            if rate > threshold:
                errors.append(f"{col} 결측률 초과: {rate:.2%} > {threshold:.2%}")

        age_min, age_max = RULES["age_range"]
        valid_age_rate = df["age"].dropna().between(age_min, age_max).mean()
        if valid_age_rate < 1.0:
            errors.append("age 값 범위 위반")

        if (df["income"] < RULES["income_min"]).any():
            errors.append("income 음수 값 존재")

        invalid_country = set(df["country"].dropna()) - RULES["allowed_country"]
        if invalid_country:
            errors.append(f"허용되지 않은 country 값: {sorted(invalid_country)}")

        duplicate_rate = df.duplicated("customer_id").mean()
        if duplicate_rate > RULES["max_duplicate_customer_rate"]:
            errors.append(f"customer_id 중복률 초과: {duplicate_rate:.2%}")

    return {
        "passed": len(errors) == 0,
        "row_count": len(df),
        "errors": errors
    }

원문 예제의 의도는 "나쁜 값을 찾아내는 것"입니다. 그래서 valid_age_rate처럼 변수명을 실제 의미에 맞게 붙이면 코드를 읽는 사람이 검증 로직을 더 쉽게 이해할 수 있습니다.

4단계: 실패 시 격리하고 리포트 남기기

import json
from datetime import datetime, timezone

result = validate_customer_data(df)
run_id = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")

with open(f"reports/data_quality_{run_id}.json", "w", encoding="utf-8") as f:
    json.dump(result, f, ensure_ascii=False, indent=2)

if not result["passed"]:
    df.to_csv(f"data/quarantine/customer_{run_id}.csv", index=False)
    raise RuntimeError(f"데이터 품질 게이트 실패: {result['errors']}")

print("데이터 품질 게이트 통과")

이 실습의 핵심은 복잡한 도구가 아닙니다. 기준을 코드로 남기고, 실패를 숨기지 않고, 실패한 데이터를 격리하고, 리포트를 남기는 것입니다. 이것이 재현 가능한 데이터 품질 관리의 출발점입니다.

흔한 실수와 오류 분석

실수 1: 결측치만 확인한다

결측치는 중요하지만 전부가 아닙니다. 값 범위, 타입, 중복, 분포, 시간 순서, 참조 무결성도 함께 봐야 합니다. 결측이 없어도 데이터가 틀릴 수 있습니다.

실수 2: 검증을 학습 코드 안에 숨긴다

검증이 학습 코드 중간에 섞여 있으면 재사용과 추적이 어렵습니다. 데이터 검증은 독립 단계로 두고, 실행 결과를 리포트로 남기는 것이 좋습니다.

실수 3: 실패해도 계속 진행한다

운영 파이프라인에서 가장 위험한 말은 "일단 돌려보자"입니다. 핵심 컬럼 누락, 타깃 결측, 심각한 스키마 변경은 즉시 중단해야 합니다. 경고로 충분한 문제와 중단해야 하는 문제를 나누어야 합니다.

실수 4: 라벨 품질을 성능 문제로만 본다

라벨은 정답처럼 보이지만 실제로는 사람이 만든 운영 데이터입니다. 라벨 정의가 모호하면 작업자마다 다르게 판단합니다. 클래스 불균형이 심하면 모델은 소수 클래스를 무시합니다. 개인정보가 라벨링 화면에 노출되면 규정 위반이 될 수 있습니다. 따라서 라벨링 데이터에는 다음 항목이 필요합니다.

  • 라벨 정의서와 예외 사례

  • 작업자 간 일치도 확인

  • 라벨 변경 이력

  • 클래스별 샘플 수와 편향 점검

  • 개인정보 포함 여부 확인

  • 접근 권한과 감사 로그

라벨 품질은 단순히 정확도 문제가 아닙니다. 모델의 공정성, 설명 가능성, 감사 가능성에 직접 연결됩니다.

요약

  • ML 모델 품질은 코드보다 입력 데이터 품질에 더 크게 흔들릴 수 있습니다.

  • 데이터 오류는 수집 단계에서 끝나지 않고 정제, 학습, 배포, 모니터링까지 전파됩니다.

  • 데이터 소스마다 지연, 누락, 중복, 순서 뒤바뀜, 포맷 변경 같은 고유한 실패 방식이 있습니다.

  • 스키마, 타입, 필수 컬럼, 값 범위, 결측률, 중복률, 범주 분포, 시간 순서, 참조 무결성을 자동 검증해야 합니다.

  • 데이터 계약과 품질 게이트는 나쁜 데이터가 학습 파이프라인으로 들어가지 못하게 막는 장치입니다.

  • 라벨링 데이터 품질은 모델 성능뿐 아니라 운영 리스크와 규정 준수의 문제입니다.

퀴즈

  1. ML 시스템에서 데이터 품질 문제가 코드 버그보다 발견하기 어려운 이유는 무엇인가?

  2. 스트리밍 이벤트 수집에서 배치 파일 수집보다 더 자주 발생하는 문제를 두 가지 말해보라.

  3. 스키마 검증과 값 범위 검증은 어떻게 다른가?

  4. 데이터 계약에 포함되어야 할 항목을 세 가지 이상 적어보라.

  5. 라벨링 데이터의 작업자 간 불일치가 운영 모델에 어떤 영향을 줄 수 있는가?

체크리스트

  • 우리 모델이 사용하는 데이터 소스를 모두 나열했다.

  • 각 데이터 소스의 지연, 누락, 중복, 포맷 변경 가능성을 정리했다.

  • 필수 컬럼, 타입, 값 범위, 결측률 기준을 코드로 정의했다.

  • 검증 실패 시 파이프라인을 중단할 조건과 경고만 보낼 조건을 구분했다.

  • 실패 데이터를 격리 저장소에 남긴다.

  • 데이터 품질 리포트를 실행마다 저장한다.

  • 라벨 정의서, 작업자 일치도, 개인정보 포함 여부를 확인한다.

  • 품질 기준 변경 이력을 버전으로 관리한다.

다음 장 연결

이번 장에서는 나쁜 데이터가 모델로 들어가지 못하게 막는 문을 만들었습니다. 하지만 운영에서는 또 하나의 질문이 남습니다. "어떤 데이터로 어떤 모델을 만들었는가?"를 나중에 다시 증명할 수 있어야 합니다.

다음 장에서는 데이터와 모델 버전관리를 다룹니다. 데이터 파일, 전처리 코드, 학습 결과, 모델 아티팩트를 함께 추적해야 같은 실험을 다시 실행하고, 장애가 났을 때 정확히 이전 상태로 되돌릴 수 있습니다.

참고

1CRISP-ML(Q). The ML Lifecycle Process

2MLOps: Continuous delivery and automation pipelines in machine learning

3Data Quality Management for MLOps: Cheat Sheet

4Pandera Documentation

책 목록

AI 교육 7권 : 재현 가능한 AI 시스템 운영: 데이터 엔지니어링·MLOps·LLM 운영 실무

전체 목차 보기

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기