03-150. 데이터 품질 검증
데이터 품질 검증
데이터 품질 검증(Data Quality Validation)은 분석에 사용할 데이터가 신뢰할 수 있고 정확한지 확인하는 과정이다. 품질이 낮은 데이터로 분석하면 잘못된 결론에 도달하거나 모델의 성능이 크게 떨어질 수 있다. 본격적인 분석에 앞서 데이터의 품질을 체계적으로 검증해야 한다.
데이터 품질이란?
데이터 품질(Data Quality)은 데이터가 의도된 용도에 얼마나 적합한지를 나타내는 척도다. 좋은 품질의 데이터는 정확하고, 완전하며, 일관성이 있고, 최신성을 유지한다.
ℹ️ 데이터 품질의 중요성
"쓰레기가 들어가면 쓰레기가 나온다(Garbage In, Garbage Out)"라는 말처럼, 품질이 낮은 데이터로는 의미 있는 분석 결과를 얻을 수 없다.
데이터 품질의 핵심 요소
데이터 품질에서 평가해야 할 주요 요소들이다.
정확성(Accuracy)
데이터가 실제 값과 얼마나 일치하는지를 나타낸다.
고객ID | 이름 | 나이 | 생년월일 | 품질 문제 |
---|---|---|---|---|
C001 | 김철수 | 25 | 1998-03-15 | 정상 |
C002 | 이영희 | 35 | 1995-06-20 | 나이와 생년월일 불일치 |
C003 | 박민수 | 28 | 1995-11-08 | 정상 |
C004 | 정수진 | 150 | 1985-04-12 | 비현실적인 나이 |
150세는 믿기 어려운 수치다. 그리고 나이는 현재 년도에서 생년월일을 빼서 근사치로 계산할 수 있다. 현재 년도를 2025년이라고 할 때 나이가 현실에 맞지 않게 잘못 기록된 것을 몇개 발 수 있다. 해결책은 더 정확한 값을 선택하고 다른 것은 버리는 것이다. 이런 경우는 생년월일로 현재 나이를 재계산하는 값으도 대체하는 것이다. 데이터 분석에서는 대부분 나이는 정확하지 않아도 큰 문제가 없다.
ℹ️ 알아두기: 생년월일로 계산하는 나이는 계산하는 시점에 따라 달라지므로 이런 데이터는 매번 재확인해야 한다. 사람들의 생일이 각기 다르므로 정확한 나이는 날짜가 바뀔 때마다 달라진다.
완전성(Completeness)
필요한 데이터가 모두 있는지 확인하는 것이다.
주문ID | 고객ID | 상품명 | 수량 | 가격 | 주문일자 |
---|---|---|---|---|---|
O001 | C001 | 노트북 | 1 | 1200000 | 2023-10-15 |
O002 | NULL | 마우스 | 2 | 50000 | 2023-10-16 |
O003 | C003 | 키보드 | NULL | 80000 | NULL |
고객ID가 NULL로 되어 비어 있는 것이 보인다. 고고객ID는 고객의 고유 번호이고 중요한 값이므로 반드시 있어야 한다. 계산할 때 주문ID는 있고 고객ID가 없는 것은 고객별 합산값이나 품목별 고유고객수 등에 관련된 계산에 문제가 발생한다. 해결책은 행을 삭제하거나 저장된 원본을 뒤져서 누락된 값을 복원하는 것 외에는 없다.
수량이 누락된 것도 있는데 수량이 누락되면 판매 수의 총합에 오차가 생긴다. 정확하지 않은 계산을 위해서 수량이 빈 것을 모두 1로 채울 수 있지만 당연히 오차는 발생한다.
완전성 문제의 예시
완전성 문제는 보통 값이 누락된 결측치 문제다.
- 필수 필드 누락: 고객ID, 주문번호 등 반드시 있어야 할 값이 없는 경우
- 부분적 정보 누락: 주소에서 상세주소만 없거나, 연락처에서 휴대폰 번호만 없는 경우
- 시계열 데이터 누락: 일별 매출 데이터에서 특정 날짜가 빠진 경우
- 관계 데이터 누락: 주문 테이블에는 있지만 고객 테이블에는 없는 고객ID
일관성(Consistency)
같은 정보가 여러 곳에서 동일하게 표현되는지를 나타낸다. 같은 값인데 테이블이나 어떤 경우에 다르게 기록되어 있는지 확인하는 것이다.
테이블A | 고객ID | 성별 | 테이블B | 고객ID | 성별 | 일관성 |
---|---|---|---|---|---|---|
고객정보 | C001 | 남 | 주문정보 | C001 | M | 불일치 |
고객정보 | C002 | 여 | 주문정보 | C002 | 여 | 일치 |
같은 고객의 성별이 다른 테이블에서 다르게 표현되어 있다. 이런 일관성 문제는 데이터를 통합할 때 혼란을 만든다. 보통 레이블, 주소, 날짜, 단위, 전화번호, 우편번호 등 형식(포맷)과 관련된 것에서 문제가 생긴다.
데이터 일관성 문제의 예시
- 성별 표현: '남/여' vs 'M/F' vs '1/0'
- 날짜 형식: '2023-10-15' vs '10/15/2023' vs '2023년 10월 15일'
- 주소 표기: '서울시 강남구' vs '서울 강남구' vs '강남구'
- 단위 표기: '1,200,000원' vs '1200000' vs '120만원'
유효성(Validity)
데이터가 정의된 형식이나 규칙을 따르는지를 나타낸다. 유효성 문제는 대부분 지정된 형식을 지키지 못한 것 때문에 발생다. 사람이 문자열 유형의 값에 잘못한 입력한 경우에 많이 발생한다.
고객ID | 이메일 | 전화번호 | 우편번호 | 유효성 |
---|---|---|---|---|
C001 | kim@email.com | 010-1234-5678 | 12345 | 정상 |
C002 | invalid-email | 010-123-456 | ABCDE | 형식 오류 |
C003 | park@company.co.kr | 02-987-6543 | 54321 | 정상 |
이메일이 잘못 지정된 것이나 전화번호가 짤린 것, 우편번호에 알파벳이 들어 있는 것은 상식적으로 볼 때 형식에 맞지 않는 것을 알 수 있다.
유효성 문제의 예시
- 이메일 형식 오류: '@' 기호 누락, 도메인 형식 불일치
- 전화번호 형식 오류: 자릿수 부족, 하이픈 누락, 잘못된 지역번호
- 우편번호 형식 오류: 숫자가 아닌 문자 포함, 자릿수 불일치
- 나이 범위 오류: 음수 값, 비현실적으로 큰 값 (예: 150세)
- 날짜 형식 오류: 존재하지 않는 날짜 (예: 2월 30일), 잘못된 형식
- 코드 값 오류: 정의되지 않은 코드 값 (예: 성별에 '기타' 입력)
ℹ️알아두기: 차별 문제로 성별에 “기타”,“알 수 없음”, “밝히지 않음” 등으로 표기할 수 있게한 경우가 있다. 그래서 잘못 입력된 값이 의도해서 허용한 것이지 입력 실수인지 학인해야 하는 경우도 있다.
최신성(Timeliness)
적시성이라고도 하며 데이터가 얼마나 최신인지를 나타낸다. 기준 시점에서 상대적으로 계산하는 값에서 최신성 문제가 많이 나타난다.
고객ID | 주소 | 업데이트일 | 현재일 | 경과일수 |
---|---|---|---|---|
C001 | 서울시 강남구 | 2023-10-01 | 2023-10-15 | 14일 |
C002 | 부산시 해운대구 | 2020-01-15 | 2023-10-15 | 1368일 |
최신성 문제의 예시
시점에 따라 변경되는 값이 저장된 데이터는 최신성 문제를 꼭 점검해야한다.
- 고객 정보 업데이트 지연: 이사했는데 주소가 예전 주소로 남아있음
- 재고 정보 지연: 실제로는 품절인데 시스템상 재고가 있다고 표시됨
- 가격 정보 지연: 할인 기간이 끝났는데 할인가격이 그대로 표시됨
- 직원 정보 지연: 퇴사한 직원이 여전히 활성 상태로 표시됨
- 상품 정보 지연: 단종된 상품이 여전히 판매 가능한 상태로 표시됨
- 고객 상태 지연: 탈퇴한 고객이 여전히 활성 고객으로 분류됨
데이터 품질 검증 방법
데이터 품질 검증은 데이터 분석의 신뢰성을 확보하기 위한 필수 과정이다. 잘 하기 위해서는 체계적인 검증 프로세스를 만들어 데이터의 문제점을 사전에 발견하고 해결할 수 있게 해야 한다. 상세한 체크리스트를 만들고 정해진 규칙에 따라 점검하는 것이 일반적이다.
검증 프로세스를 알아보자.
기본 현황 파악하기
- 데이터 크기, 구조, 타입 확인
- 기본 통계 정보 검토
- 전체적인 데이터 품질 수준 파악
요소소별 상세 검증
- 완전성: 결측치 패턴 분석
- 정확성: 이상치 및 범위 검증
- 일관성: 중복 및 형식 일관성 확인
- 유효성: 형식 및 규칙 준수 검증
- 최신성: 데이터 갱신 상태 확인
종합 평가 및 개선
- 품질 점수 계산
- 우선순위 설정
- 개선 방안 수립
검증 프로세스는 데이터 프로파일링이라는 과정의 일부이기도하다. 데이터 분석을 위한 품질 검증은 “요소별 상세 검증” 까지이고 그 다음은 지속적인 데이터 관리를 위한 것이다.
데이터 품질 검증은 숙련된 사람도 상세 과정이 많고 다양한 예외가 있어서 놓치는 경우가 많다. AI챗봇의 도움을 받으면 쉽게 정리할 수 있다.
💻프롬프트: 데이터 품질을 체계적으로 검증하는 방법을 알려주세요.
데이터 프로파일링에서 하는 열도 함께 알아볼 필요가 있다.
❓프롬프트: 데이터 프로파일링의 정의와 하는 일을 자세히 알려주세요.
데이터 품질 기본 통계 검증
📊 코드 예제
import pandas as pd
import numpy as np
# 예제 데이터 생성
data = {
'고객ID': ['C001', 'C002', 'C003', 'C004', 'C005'],
'이름': ['김철수', '이영희', None, '정수진', '최지우'],
'나이': [25, 35, 28, 150, -5],
'성별': ['남', '여', '남', '여', '기타'],
'연봉': [3500, 4200, None, 8000, 2800]
}
df = pd.DataFrame(data)
# 기본 정보 확인
print("=== 데이터 기본 정보 ===")
print(f"데이터 크기: {df.shape}")
print(f"컬럼 수: {len(df.columns)}")
print(f"행 수: {len(df)}")
print("\n=== 데이터 타입 ===")
print(df.dtypes)
print("\n=== 기본 통계 ===")
print(df.describe(include='all'))
print("\n=== 결측치 현황 ===")
missing_info = df.isnull().sum()
missing_percent = (missing_info / len(df)) * 100
missing_df = pd.DataFrame({
'결측치_개수': missing_info,
'결측치_비율(%)': missing_percent.round(2)
})
print(missing_df)
💻 실행 결과
=== 데이터 기본 정보 ===
데이터 크기: (5, 5)
컬럼 수: 5
행 수: 5
=== 데이터 타입 ===
고객ID object
이름 object
나이 int64
성별 object
연봉 float64
dtype: object
=== 기본 통계 ===
고객ID 이름 나이 성별 연봉
count 5 4 5.0 5 4.000000
unique 5 4 NaN 4 NaN
top C001 김철수 NaN 남 NaN
freq 1 1 NaN 2 NaN
mean NaN NaN 46.6 NaN 4625.000000
std NaN NaN 67.9 NaN 2217.355782
min NaN NaN -5.0 NaN 2800.000000
25% NaN NaN 25.0 NaN 3500.000000
50% NaN NaN 28.0 NaN 4200.000000
75% NaN NaN 35.0 NaN 4200.000000
max NaN NaN 150.0 NaN 8000.000000
=== 결측치 현황 ===
결측치_개수 결측치_비율(%)
고객ID 0 0.00
이름 1 20.00
나이 0 0.00
성별 0 0.00
연봉 1 20.00
데이터 범위 검증
데이터의 각 항목에 범위가 있는 경우 맞는 값이 들어 있는지 확인하는 것이다.
# 나이 범위 검증
def validate_age(df, min_age=0, max_age=120):
invalid_ages = df[(df['나이'] < min_age) | (df['나이'] > max_age)]
print(f"=== 나이 범위 검증 (유효 범위: {min_age}-{max_age}세) ===")
print(f"유효하지 않은 나이 데이터: {len(invalid_ages)}건")
if len(invalid_ages) > 0:
print("문제가 있는 데이터:")
print(invalid_ages[['고객ID', '이름', '나이']])
return invalid_ages
# 연봉 범위 검증
def validate_salary(df, min_salary=1000, max_salary=50000):
invalid_salaries = df[(df['연봉'] < min_salary) | (df['연봉'] > max_salary)]
print(f"\n=== 연봉 범위 검증 (유효 범위: {min_salary}-{max_salary}만원) ===")
print(f"유효하지 않은 연봉 데이터: {len(invalid_salaries)}건")
if len(invalid_salaries) > 0:
print("문제가 있는 데이터:")
print(invalid_salaries[['고객ID', '이름', '연봉']])
return invalid_salaries
# 검증 실행
invalid_ages = validate_age(df)
invalid_salaries = validate_salary(df)
이런 작업은 할 때 마다 매번 다른 것을 사용해야 한다. 데이터의 명세가 매번 다르고 범위도 매번 다르기 때문이다. 그래서 함수를 만들어서 재활용하거나 이전에 사용했던 코드를 복사해서 재활용하는 경우가 많다.
ℹ️알아두기: 데이터의 범위는 데이터가 제공될 때 명세와 함께 와야 하지만 주지 않는 경우도 많다. 제공한 곳에 문의하거나 데이터를 보고 상식적인 범위를 지정해야 한다.
데이터 형식 검증
import re
# 이메일 형식 검증
def validate_email(email):
if pd.isna(email):
return False
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return bool(re.match(pattern, email))
# 전화번호 형식 검증
def validate_phone(phone):
if pd.isna(phone):
return False
# 한국 전화번호 패턴 (010-1234-5678, 02-123-4567 등)
patterns = [
r'^010-\d{4}-\d{4}$', # 휴대폰
r'^0\d{1,2}-\d{3,4}-\d{4}$' # 일반전화
]
return any(bool(re.match(pattern, phone)) for pattern in patterns)
# 예제 데이터로 검증
contact_data = {
'고객ID': ['C001', 'C002', 'C003', 'C004'],
'이메일': ['kim@email.com', 'invalid-email', 'park@company.co.kr', 'test@'],
'전화번호': ['010-1234-5678', '010-123-456', '02-987-6543', '123-456-789']
}
contact_df = pd.DataFrame(contact_data)
# 형식 검증 실행
contact_df['이메일_유효'] = contact_df['이메일'].apply(validate_email)
contact_df['전화번호_유효'] = contact_df['전화번호'].apply(validate_phone)
print("=== 형식 검증 결과 ===")
print(contact_df)
# 유효하지 않은 데이터 찾기
invalid_emails = contact_df[~contact_df['이메일_유효']]
invalid_phones = contact_df[~contact_df['전화번호_유효']]
print(f"\n유효하지 않은 이메일: {len(invalid_emails)}건")
print(f"유효하지 않은 전화번호: {len(invalid_phones)}건")
일관성 검증
일관성 검증도 매번 데이터를 받을 때마다 새로 만들어야 한다.
# 테이블 간 일관성 검증
def check_consistency(df1, df2, key_column, check_columns):
# 두 테이블을 키로 조인
merged = pd.merge(df1, df2, on=key_column, suffixes=('_table1', '_table2'))
inconsistencies = []
for col in check_columns:
col1 = f"{col}_table1"
col2 = f"{col}_table2"
if col1 in merged.columns and col2 in merged.columns:
inconsistent = merged[merged[col1] != merged[col2]]
if len(inconsistent) > 0:
inconsistencies.append({
'column': col,
'count': len(inconsistent),
'data': inconsistent[[key_column, col1, col2]]
})
print(f"=== 테이블 간 일관성 검증 ===")
if inconsistencies:
for inc in inconsistencies:
print(f"\n{inc['column']} 컬럼 불일치: {inc['count']}건")
print(inc['data'])
else:
print("일관성 문제 없음")
return inconsistencies
# 예제 데이터
table1 = pd.DataFrame({
'고객ID': ['C001', 'C002', 'C003'],
'성별': ['남', '여', '남'],
'나이': [25, 35, 28]
})
table2 = pd.DataFrame({
'고객ID': ['C001', 'C002', 'C003'],
'성별': ['M', '여', '남'], # C001의 성별이 다름
'연봉': [3500, 4200, 3800]
})
# 일관성 검증 실행
check_consistency(table1, table2, '고객ID', ['성별'])
위와 같이 복잡한 코드를 작성하는데 잘못된 코드가 실행되면 문제를 찾기 어려우므로 코드를 자세히 확인해야 한다 AI챗봇의 도움으로 코드를 작성해도 되지만 꼭 다시 점검해야 한다.
ℹ️알아두기: 실행 코드가 에러를 발생하면 고치기 쉽지만 처리를 잘못하면서도 에러가 없다면 데이터가 잘못된 것을 집계나 통계분석을 하기 전까지 알아채지 못한다. 시간 낭비가 매우 크기 때문에 주의해야한다.
데이터 품질 검증 자동화
데이터 품질 점수 계산과 품질 검증 파이프라인과 같은 것을 만들어서 매번 재수행 할 수도 있지만 매번 고쳐야 하는 경우가 많다. 또 지속적으로 추가 제공되는 데이터는 데이터 품질 모니터링을 만들어서 품질에 문제가 생겼는지 검증을 하는 것도 한다. 이런 것은 데이터 엔지니어링에 포함되는 것이라서 이 책에서는 다루지 않는다.
마무리
데이터 품질 검증은 성공적인 데이터 분석의 첫 번째 단계다. 체계적인 검증 프로세스를 통해 데이터의 신뢰성을 확보하고, 분석 결과의 정확성을 높일 수 있다.
💡 핵심 포인트
- 데이터 품질은 완전성, 정확성, 일관성, 유효성, 최신성의 다섯 차원으로 평가한다
- 자동화된 검증 파이프라인을 구축하여 효율성을 높인다
- 품질 문제는 조기에 발견하고 체계적으로 해결한다
- 지속적인 모니터링을 통해 품질을 유지한다
품질이 검증된 데이터만이 의미 있는 분석 결과와 신뢰할 수 있는 모델을 만들어낼 수 있다는 점을 항상 기억하자.