Devin.KR

분자·분모·기간 정의

65분 안팎

학습 목표

강수일 기준·유효 관측·제외 조건을 metrics.json으로 정의하고 분모 0의 표시 규칙을 씁니다.

개념

평균을 말하기 전에 질문을 좁힙니다

팀장이 비 오는 날에 통행량이 달라지는지 물었습니다. 평균을 바로 계산하면 날짜 평균인지 도로 관측 평균인지부터 서로 다른 숫자를 보게 됩니다. 이 레슨의 목표는 계산식과 포함 대상을 먼저 문서로 고정하는 것입니다. 우리 프로젝트는 앞 단계에서 만든 지역·날짜별 합계 표를 사용합니다. 한 행은 한 차량이나 한 관측소가 아니라 한 지역의 하루입니다.

입력 out/clean.csv에는 A와 B 지역의 2026년 9월 1일부터 3일까지 6행이 있습니다. 학습용 합성 표본이며 실제 공개 교통량의 대표 표본으로 해석하지 않습니다. 정제는 열 형식과 값의 유효성을 점검한 작업이고, 분석은 질문에 맞는 행을 고르는 작업입니다. 정제 후 정상 행에도 교통 또는 강수가 없을 수 있으므로 6행 전체를 같은 분모로 쓰지 않습니다.

지표 계약의 여섯 항목을 작성합니다

지표 이름은 mean_daily_region_traffic로 정합니다. 분자는 포함된 지역·날짜의 total_vehicles 합이고 분모는 그 지역·날짜의 수입니다. 기간은 2026-09-01부터 2026-09-03까지 양 끝을 포함합니다. 날짜는 앞 모듈에서 정리한 현지 날짜이고 시간대 표기는 Asia/Seoul입니다. 날짜 문자열만으로 새로운 시간대 변환을 수행하는 것은 아닙니다. 단위는 지역·날짜당 대수로 적습니다.

강수 그룹은 rain_mm이 1.0mm 이상인 행입니다. 0.0부터 1.0mm 미만은 dry입니다. 이 기준은 실습의 비교 규칙이며 모든 기관의 강수일 정의라고 주장하지 않습니다. 강수 임계값을 바꾸면 같은 행도 다른 그룹으로 이동합니다. 따라서 숫자 하나만 전달하지 않고 기준과 입력 기간을 같이 저장합니다. 경계인 1.0mm와 바로 아래 0.9mm를 테스트하면 비교 연산의 오류를 찾을 수 있습니다.

제외 조건은 교통 또는 강수의 결측, 그리고 기간 밖의 행입니다. 교통 0대와 강수 0mm는 관측된 숫자이므로 남깁니다. 두 변수가 모두 유효한 완전 사례만 강수 비교에 사용합니다. 강수량이 없는 교통90대 행은 전체 교통 평균에는 쓸 수 있지만 강수와의 비교에는 쓰지 않습니다. 지표마다 포함 조건이 달라도 그 조건이 공개되어 있으면 의미를 비교할 수 있습니다.

분모는 관측 단위에서 결정됩니다

valid_observations는 앞 단계 교통 집계에서 유효했던 관측 수입니다. 지역·날짜 평균의 분모로 이 열의 합을 사용하면 관측당 통행량이라는 다른 질문에 답합니다. 예를 들어 두 지역의 일별 합계100대와300대는 지역·날짜 평균200대입니다. 각 지역의 유효 관측 수가1과3이면 합계400을 관측수4로 나눈100대는 별도 지표입니다. 두 값을 같은 이름으로 보고하지 않습니다.

이번 기본 표본의 완전 사례는 A 강수100대, A 비강수80대, B 강수120대, B 비강수0대입니다. 강수 전체는 합220대와 분모2로 평균110대이고 비강수 전체는 합80대와 분모2로 평균40대입니다. B의 관측0대를 버리면 비강수 평균은80대로 달라집니다. 숫자가 작다는 이유로 제외하지 않고 계약에 적은 결측 조건과 관측된0을 구분합니다.

분모가 없는 상태를 표시합니다

유효한 행이 없으면 n=0, 평균=NA로 기록합니다. 계산할 수 없음과 실제 평균0대는 다른 상태입니다. 합계는 빈 집합에서0으로 기록하되 평균과 중앙값은 비워 두는 규칙을 명시합니다. Python 내부에서는 None, JSON에서는 null, CSV에서는 NA를 사용합니다. 표시만 다른 같은 상태이므로 다음 단계에서 문자열 NA를 숫자로 강제 변환하지 않도록 인계합니다.

ZeroDivisionError가 발생하면 분모 검사 전에 나눗셈을 수행했는지 확인합니다. 파일에서 TypeError가 나면 CSV 빈 문자열을 None으로 정규화했는지도 확인합니다. 오류를 숨기려고 분모를1로 바꾸거나 값을0으로 채우면 프로그램은 끝나도 지표가 달라집니다. 계산 불가를 정상 결과 상태로 다루면 장애와 데이터 부족을 구분할 수 있습니다.

환경과 산출물을 준비합니다

이 모듈은 Python 3 표준 라이브러리와 SQLite 문법을 사용합니다. 브라우저 Python 실습은 표준 입력 JSON을 읽고 SQL 실습은 tests의 초기화 SQL로 독립된 테이블을 만듭니다. 따라하기의 코드는 단계마다 독립적으로 실행합니다. 로컬 미션 ZIP을 푼 루트에서 python3 -m unittest discover -s tests -v를 실행합니다. 패키지 설치나 운영 데이터 연결은 필요하지 않습니다.

미션 starter에는 앞 모듈 solution 전체와 새 metrics.py가 있습니다. 입력은 out/clean.csv이고 지표 정의는 metrics.json입니다. 산출물은 metrics-out/metrics.csv와 metrics-audit.json, 사람이 읽는 interpretation.md입니다. starter에서는 새 summarize가 미완성이라 통계 테스트가 실패합니다. 이전 단계 테스트가 통과하는 상태에서 새 기능을 확장하며 기존 원본 파일은 보존합니다.

정의를 재현 가능한 문서로 만듭니다

metrics.json에는 분자·분모·단위·기간·시간대·강수 기준·제외 조건·빈 분모 표현을 모두 씁니다. 문장만 남기지 말고 start, end, rain_threshold_mm처럼 코드가 읽는 항목도 포함합니다. 같은 이름의 정의를 바꾸면 보고서에서 이전 결과와 섞일 수 있으므로 변경 전후의 기준을 함께 기록합니다. 사람이 적은 분모 문장과 코드가 세는 행 수가 일치하는지 작은 표본으로 대조합니다.

검토할 때는 입력6행, 기간 안6행, 유효4행, 결측 제외2행, 기간 밖0행이 맞는지 먼저 봅니다. 유효 행의 그룹별 n 합은4여야 합니다. 이 등식은 포함 집합이 빠지거나 중복되었는지 찾는 장치이며 개별 통행량의 정확성까지 보장하지는 않습니다. 합계와 분모를 함께 검토하면 평균만 비교할 때 놓치는 행 선택의 오류를 좁힐 수 있습니다.

문서 실습에서는 지역별 하루 평균이 어떤 질문에 답하는지 한 문장으로 적고, 0대 한 행과 결측 한 행이 어떻게 처리되는지 예를 듭니다. 강수 기준을0.1mm로 바꿀 경우 결과가 어떻게 달라질지 확인 계획을 덧붙입니다. SQL 집계 문법의 상세 설명은 더 읽기로 연결하며 여기서는 집계함수를 고르는 것보다 포함 대상과 분모를 합의하는 일을 먼저 마무리합니다.

따라하기

유효한 짝과 분모 확인

rows = [(100,3),(80,0),(None,None),(120,10),(0,0),(90,None)]
valid = [(v,r) for v,r in rows if v is not None and r is not None]
print('input', len(rows), 'valid', len(valid), 'excluded', len(rows)-len(valid))
for name in ['rain','dry']:
    values = [v for v,r in valid if (r >= 1) == (name == 'rain')]
    print(name, sum(values), len(values), sum(values)/len(values) if values else 'NA')

실행 결과

input 6 valid 4 excluded 2
rain 220 2 110.0
dry 80 2 40.0

지표 정의를 JSON으로 표현

import json
contract = {'start':'2026-09-01','end':'2026-09-03','timezone':'Asia/Seoul','rain_threshold_mm':1.0,'zero_denominator':'NA'}
text = json.dumps(contract, sort_keys=True)
print(text)
print(json.loads(text)['rain_threshold_mm'])

실행 결과

{"end": "2026-09-03", "rain_threshold_mm": 1.0, "start": "2026-09-01", "timezone": "Asia/Seoul", "zero_denominator": "NA"}
1.0

관측된 0과 빈 분모 비교

for values in [[0], []]:
    n = len(values)
    print('n', n, 'mean', sum(values)/n if n else 'NA')

실행 결과

n 1 mean 0.0
n 0 mean NA

확인 문제

실습

metrics.json에 분자·분모·단위·기간 양 끝 포함·Asia/Seoul·1mm 이상 강수·결측 제외·분모0은 NA 규칙을 작성합니다. 분모가 valid_observations 합이 아닌 지역·날짜 수인 이유를 적고, 관측0대와 결측을 다르게 처리하는 예를 제출합니다. 미션 ZIP의 정의와 대조하되 질문 문장은 자신의 말로 작성합니다.

더 읽기

면접 질문

  • 결측값을 삭제할지 채울지 판단하는 과정을 설명해 주시면 됩니다.