스프레드시트로 원본 점검
120분 안팎
학습 목표
스프레드시트에서 행·열·단위·빈칸·중복을 확인하고 필터 전후 행 수를 audit.csv로 내보냅니다.
개념
계산 전에 표가 읽힌 모양을 확인합니다
CSV를 열었는데 한 열에 모든 값이 들어가거나 지역 코드가 숫자로 바뀌면 그 상태에서 만든 집계는 원본과 다른 자료를 사용한 것입니다. 스프레드시트 점검은 화면을 훑는 일이 아니라 가져오기 설정과 행 수, 단위, 빈칸, 반복 행을 기록하는 작업입니다. 이번 실습은 미션과 같은 두 원본을 사용하고 audit.csv에 필터 전후의 데이터 행 수를 남깁니다. Python은 검사 실행에만 사용하며 필터와 CSV 내보내기는 스프레드시트로 연습합니다.
raw/traffic.csv에는 region, date, vehicle_count의 세 열이 있습니다. raw/weather.csv에는 region, date, rain_mm의 세 열이 있습니다. 첫 줄은 헤더이며 데이터 행으로 세지 않습니다. vehicle_count는 대/일, rain_mm은 mm/일입니다. 숫자 셀에 “대”나 “mm”를 붙이지 않고 단위는 데이터 사전에 기록합니다. 원본 CSV와 작업용 문서를 구분하고 원본을 저장 버튼으로 덮어쓰지 않습니다.
자동 추측 대신 가져오기 설정을 확인합니다
사용 중인 스프레드시트의 텍스트 또는 CSV 가져오기 기능에서 문자 인코딩 UTF-8과 구분자 쉼표를 선택합니다. region과 date는 텍스트로 가져옵니다. 날짜는 표시 방식만 바뀌어도 원래 값을 확인하기 어려워지므로 이번 점검에서는 YYYY-MM-DD 문자열을 보존합니다. 미리보기에서 헤더가 세 칸으로 나뉘는지, A와 B가 문자로 남는지, 날짜가 원래 형태인지 확인한 뒤 가져옵니다.
도구마다 메뉴 이름이 다르므로 특정 버튼 위치보다 가져온 결과를 확인합니다. 열이 하나뿐이면 구분자를 다시 설정합니다. 글자가 깨지면 인코딩을 확인하고 원본을 새 인코딩으로 저장해 덮어쓰지 않습니다. 이후 실제 지역 코드에 001 같은 앞자리 0이 있으면 숫자로 가져오지 않습니다. 코드는 더하거나 평균 내는 수량이 아니며 앞자리 0도 식별자의 일부일 수 있습니다.
헤더를 제외한 행 수를 먼저 셉니다
교통은 데이터 7행이고 날씨는 6행입니다. 헤더를 포함한 화면 줄 수와 구분합니다. 값 열의 비어 있지 않은 셀을 세는 방법은 전체 행 수를 대신하지 못합니다. 이번 교통 값 열에는 빈칸이 있으므로 그 열만 세면 6개가 나옵니다. 모든 행에 있는 지역 열의 데이터 범위나 테이블의 행 개수로 원본 행 수를 확인합니다. 합계와 행 수를 혼동하지 않도록 기록에 단위를 붙입니다.
audit.csv는 dataset,stage,rows,rule의 네 열을 사용합니다. dataset에는 traffic 또는 weather, stage에는 raw, nonmissing, unique를 씁니다. rows에는 헤더 제외 데이터 행 수를 정수로 넣고 rule에는 적용 규칙을 넣습니다. 기록은 교통 세 단계 다음 날씨 세 단계의 순서입니다. CSV에는 한글 설명 대신 고정 규칙 이름을 쓰고, 작업 판단의 설명은 question.json과 사전에 남깁니다.
빈칸을 거른 사본에서 0을 유지합니다
작업 시트를 복사하고 마지막 측정값 열의 빈 셀을 제외합니다. 교통의 vehicle_count가 비어 있지 않은 행은 6행, 날씨의 rain_mm이 비어 있지 않은 행은 5행입니다. 이 단계를 nonmissing으로 기록합니다. 교통 규칙은 vehicle_count_not_empty, 날씨 규칙은 rain_mm_not_empty입니다. B의 9월 2일 교통량 0은 유효한 값이므로 남깁니다. 빈칸은 미관측이며 0과 다릅니다.
필터를 켰다고 원본 행이 삭제되는 것은 아닙니다. 가려진 행과 삭제된 행을 구분합니다. 필터가 있는 화면에서 보이는 행을 셀 때에는 표시된 데이터 행만 세는지 확인하고, 숨김 행을 포함하는 일반 합계를 그대로 사용하지 않습니다. 이번 표본은 작으므로 조건에 맞는 행을 새 작업 시트에 복사한 뒤 직접 행 수를 대조할 수 있습니다. 자동 함수의 결과는 직접 확인한 작은 표와 비교합니다.
모든 열이 같은 추가 행만 제외합니다
nonmissing 사본에서 세 열 전체를 기준으로 완전히 같은 행을 찾습니다. 교통의 A,2026-09-02,80이 두 번 있으므로 첫 행 하나를 남기고 추가 행 하나를 제외합니다. 결과는 5행입니다. 날씨에는 같은 행 반복이 없으므로 5행을 유지합니다. 이 단계는 unique이며 두 자료 모두 규칙 이름은 nonmissing_then_exact_dedup입니다. 이 숫자는 빈칸 제외 후 완전 중복의 추가분을 제외한 결과입니다.
지역만 기준으로 중복 제거하면 A의 여러 날짜가 한 행이 되어 관측 자체를 잃습니다. 날짜만 기준으로 하면 서로 다른 지역을 합쳐 버립니다. 지역·날짜는 후보 키 검사 기준이고, 모든 열이 같은지는 완전 중복 기준입니다. 같은 키에 서로 다른 수량이 있으면 어느 값이 맞는지 확인해야 하므로 자동으로 첫 행을 채택하지 않습니다. 이번 표본에서는 완전 중복만 확인하며 충돌 처리 규칙은 뒤에서 확장합니다.
단계의 순서도 결과의 뜻입니다. 원본 7행에서 빈칸 1행을 제외해 6행, 그 사본에서 반복 추가분 1행을 제외해 5행입니다. 두 감소량은 이 순서에서 분리됩니다. 어떤 행이 동시에 빈칸이고 중복인 자료라면 감소량을 단순히 더해 설명할 수 없으므로 처리 순서를 같이 적습니다. 날씨는 6에서 5로 감소한 뒤 중복 제외에서는 감소하지 않습니다.
CSV 내보내기와 검증을 연결합니다
별도 점검 시트에 네 열과 여섯 기록을 만들고 audit.csv로 CSV UTF-8 내보내기를 합니다. 숫자는 “7행” 대신 7로 입력합니다. 첫 행 헤더 뒤에 traffic의 raw, nonmissing, unique, 다음 weather의 같은 세 단계를 둡니다. 행 번호나 제목 줄을 추가하지 않습니다. 규칙 문자열이 필요하면 아래 따라하기 표를 그대로 입력합니다. 내보낸 파일은 텍스트 편집기로 열어 헤더와 쉼표 구분을 다시 확인합니다.
로컬 실습의 시작본은 교통의 raw와 nonmissing 수가 틀려 테스트 일부가 실패합니다. 검증 코드와 테스트를 고치는 대신 스프레드시트에서 확인한 값으로 audit.csv를 교체합니다. AUDIT 메시지는 행 수뿐 아니라 헤더, 순서, 규칙 이름까지 대조하라는 뜻입니다. 쉼표 대신 세미콜론으로 내보내거나 인덱스 열을 추가한 경우도 확인합니다. HASH가 실패하면 원본 파일을 배포본에서 다시 가져와 보존합니다.
여기서 완성한 audit는 두 파일 각각의 점검입니다. 결합 표의 행 수나 비 오는 날 비교의 최종 표본 수가 아닙니다. 두 파일의 비결측 행 수가 다르면 다음 결합 단계에서 대응하지 않는 지역·날짜를 확인합니다. 오늘의 산출물을 통해 동료가 원본 7·6행에서 어떤 조건으로 5·5행을 검토 대상으로 만들었는지 재현할 수 있으면 점검의 목적을 이룬 것입니다.
따라하기
작업 시트로 가져오기
레슨 실습 data-table-audit 시작 ZIP을 풉니다. raw/traffic.csv와 raw/weather.csv를 UTF-8·쉼표 구분으로 가져옵니다. region/date는 텍스트로 둡니다. 원본은 보존하고 작업 문서에만 필터를 적용합니다. 화면 조작은 자동 실행 출력이 없으며 헤더 세 열과 데이터 행을 직접 확인합니다.
빈칸과 0의 계산 대조
audit_check.py로 저장해 python3 audit_check.py로 실행합니다. 스프레드시트에서 센 교통 행 수와 대조하는 보조 코드입니다. Python으로 대체하기 전에 작업 시트에서도 같은 단계의 행을 확인합니다.
import csv, io
text = 'region,date,vehicle_count\nA,2026-09-01,100\nA,2026-09-02,80\nA,2026-09-02,80\nA,2026-09-03,\nB,2026-09-01,120\nB,2026-09-02,0\nB,2026-09-03,90\n'
rows = list(csv.DictReader(io.StringIO(text)))
present = [r for r in rows if r['vehicle_count'] != '']
print('raw', len(rows))
print('nonmissing', len(present))
print('unique', len({tuple(r.values()) for r in present}))실행 결과
raw 7 nonmissing 6 unique 5
점검표 여섯 기록 내보내기
아래 표를 별도 시트에 입력하고 audit.csv로 CSV UTF-8 내보내기 합니다. 헤더를 포함해 7줄이며 데이터 기록은 6개입니다. raw 단계는 원본, unique 단계는 빈칸 제외 후 모든 열 기준의 반복 추가분 제외입니다. 입력 전 직접 확인한 숫자와 대조합니다.
dataset,stage,rows,rule
traffic,raw,7,all
traffic,nonmissing,6,vehicle_count_not_empty
traffic,unique,5,nonmissing_then_exact_dedup
weather,raw,6,all
weather,nonmissing,5,rain_mm_not_empty
weather,unique,5,nonmissing_then_exact_dedup산출물 테스트 실행
ZIP 루트에서 아래 명령을 실행합니다. 시작본은 4개 중 제출물 검사 1개가 실패하고, audit 수정 후 전부 통과해야 합니다. AUDIT는 헤더·순서·규칙·수의 차이, HASH는 원본 변경을 확인합니다.
python3 -m unittest discover -s tests -v확인 문제
실습
data-table-audit 시작 ZIP을 풀고 스프레드시트에서 원본을 읽어 raw→nonmissing→unique 행 수를 기록한 audit.csv를 제출합니다. 0은 유지하고 마지막 측정 열의 빈칸만 제외한 사본에서 세 열 전체가 같은 추가 행을 제외합니다. 검증기와 테스트는 수정하지 않습니다. 원본 7·6행, 빈칸 제외 6·5행, 완전 중복 추가분 제외 5·5행을 확인하고 원본 해시를 보존합니다.
실행 명령
python3 -m unittest discover -s tests -v
기대 결과
테스트 4개 통과. 시작본은 audit 제출물 검사 1개가 실패합니다.
모범 답안
모범 답안 내려받기더 읽기
면접 질문
- 공개 데이터로 만든 그래프의 신뢰성을 확인하는 방법을 설명해 주시면 됩니다.