여기까지 오면 AI는 꽤 많은 일을 했다.
CSV 구조를 읽었다.
업종을 필터링했다.
증가율을 계산했다.
여러 파일을 코드로 합쳤다.
상관계수를 구했다.
JSON을 표로 바꿨다. 이쯤 되면 마지막 질문이 생긴다.
“AI가 계산했는데 또 뭘 확인해야 하지?”
확인해야 한다.
AI를 못 믿어서가 아니다.
계산이 맞는 것과 질문에 맞는 계산을 했다는 것은 다른 문제이기 때문이다.
17장은 앞에서 반복해서 만난 오류를 하나의 검증 체계로 묶는다.
틀린 답은 계산식에서만 생기지 않았다
앞 장들을 돌아보자. 4~6장에서는 국세청 데이터의 0이 실제 0만 뜻하지 않았다. 3 미만 값이 0으로 마스킹될 수 있었다. 7장에서는 같은 행정동 코드로 파일을 연결하기 전에 기간·업종·고유키를 맞춰야 했다. 8장에서는 평균 영업기간을 폐업률로 바꾸면 안 됐다.
9장에서는 전체 아파트 평균이 올라도 동일 전용면적의 가격은 거의 그대로일 수 있었다. 10장에서는 학급당 학생 수와 교원 1인당 학생 수의 순위가 달랐다. 12장에서는 상관계수 -0.982가 원인을 증명하지 않았다. 13장에서는 방문자와 관광소비라는 서로 다른 빅데이터 추정치를 나눠 실제 1인당 소비액을 만들면 안 됐다.
14장에서는 월말 고용보험 피보험자를 12개월 더하면 안 됐다. 16장에서는 HTTP 응답이 왔다고 API가 정상 성공한 것은 아니었다. 이 오류들 가운데 단순 산수 오류는 거의 없다. 대부분 정의, 분모, 기간, 모집단, 상태, 결합 규칙, 표현의 문제다.
그래서 검증도 계산기 한 번으로 끝나지 않는다.
VERIFY-8: 여덟 칸 검증 루프
검증 규칙을 여덟 칸으로 정리해보자.
V1. Source — 원출처가 맞는가
어디에서 온 데이터인가. 검색 결과의 재가공 파일인가, 원 제공기관인가.
공식 페이지의 데이터명과 파일명이 맞는가.
V2. Input — 실제 입력이 무엇인가
어떤 파일, 어떤 API 응답을 사용했는가. 기준일은 언제인가.
합성 데이터인지 실제 데이터인지.
V3. Schema — 한 행과 한 열이 무엇을 뜻하는가
고유키는 무엇인가. 단위는 무엇인가.
0·결측·마스킹 같은 예외가 있는가.
V4. Filter — 어떤 행을 남겼는가
업종, 지역, 기간, 학교급, 전용면적 같은 조건이 질문과 맞는가.
필터 전후 행 수는 얼마인가.
V5. Calculation — 무슨 식을 계산했는가
분자와 분모는 무엇인가.
전체값과 평균, 비율, 증감률을 혼동하지 않았는가.
V6. Exception — 계산하면 안 되는 행을 남겼는가
분모 0. 마스킹. 신고지연. 행정구역 변경.
결측. API 오류.
이런 행을 억지로 숫자로 만들지 않았는가.
V7. Cross-check — 원자료 한 행으로 되돌아갈 수 있는가
결과표의 임의 행 하나를 고른다.
원자료에서 같은 입력값을 찾고 직접 다시 계산한다.
V8. Claim — 결과 문장이 근거보다 강하지 않은가
상관을 원인으로 바꾸지 않았는가. 지역 평균을 개인 결과로 바꾸지 않았는가. 추정치를 실제 총량처럼 쓰지 않았는가. 관측값을 미래 예측으로 바꾸지 않았는가.
이 여덟 칸을 통과해야 결과가 ‘정답’이 되는 것은 아니다.
적어도 어디에서 틀릴 수 있는지 설명 가능한 결과가 된다.

Source부터 Claim까지 이어지는 VERIFY-8 검증 게이트
도판 F10. VERIFY-8. Source에서 Claim까지 여덟 게이트를 통과하며 계산 오류뿐 아니라 입력·예외·원자료 역추적·과장된 문장까지 검증한다.
검증은 AI에게도 시킬 수 있다
검증 책임이 사람에게 있다고 해서 모든 검증을 손으로 해야 한다는 뜻은 아니다. AI에게 검증 역할을 따로 맡길 수 있다. 분석을 만든 대화의 흐름을 그대로 이어서 “검증해줘”라고만 하면 자기 결론을 되풀이하기 쉽다. 분석자는 자기 결과에 익숙해진다.
AI도 앞선 문맥을 따라 자신의 해석을 반복할 수 있다.
그래서 검증 프롬프트는 반대편 역할을 준다.
지금부터 분석자가 아니라 검증자 역할을 해줘.
기존 결론을 지지하려고 하지 말고,
Source / Input / Schema / Filter / Calculation / Exception / Cross-check / Claim
여덟 항목에서 실패 가능성을 찾고
PASS / FAIL / 확인 필요로 판정해줘.기존 결과표가 아니라 원입력과 공식 정의를 우선해줘.
이 요청은 AI에게 스스로 틀렸다고 말할 권한을 준다.
실제로 일곱 개 오류 사례를 다시 검증했다
앞 장의 대표 실수를 합성 검증표로 다시 만들었다.
sample_verify8_cases.csv
일곱 사례 가운데 하나는 정상, 하나는 조건부 통과, 다섯 개는 실패하도록 설계했다.
| ID | 검증대상 | AI 가상출력 | 판정 |
|---|---|---|---|
| V01 | 누리구 편의점 증가율 | 18.75% | PASS |
| V02 | 마스킹 0에서 증가율 | 700% | FAIL |
| V03 | 아파트 전체 평균 상승률 | 7.08% | 조건부 PASS |
| V04 | 59㎡ 상승률 | 7.08% | FAIL |
| V05 | 관광객 1인당 소비 | 소비지수/방문지수 | FAIL |
| V06 | 기온이 천식 원인 | 원인이라고 결론 | FAIL |
| V07 | 12개월 피보험자 합계 | 월별 스톡 합산 | FAIL |
이 표는 AI가 실제로 틀렸다는 기록이 아니다.
검증 규칙이 어떤 오류를 잡아야 하는지 시험하기 위한 합성 테스트다.
V01: 계산이 맞고 질문에도 맞는 경우
누리구 합성 편의점 데이터는 당월 190, 전년동월 160이었다.
증가율은
(190-160) ÷ 160 × 100 = 18.75%
다시 계산해도 같다. 분모도 유효하다. 이 경우 Calculation과 Cross-check는 PASS다.
하지만 Claim까지 확인한다.
누리구의 편의점 가동사업자 수는 합성 데이터에서 전년동월 대비 18.75퍼센트 증가했다.
가능하다.
누리구 편의점 수요가 18.75퍼센트 증가했다.
불가능하다.
계산값이 맞아도 문장이 바뀌면 검증 결과가 달라진다.
V02: 산수 전에 예외 규칙이 이겨야 하는 경우
새봄군의 전년동월 값은 0이었다. AI가 7 ÷ 0 문제를 피하기 위해 임의의 규칙을 적용하거나 “0에서 7로 700퍼센트 성장”이라고 표현한다면 FAIL이다. 국세청 원자료의 0은 3 미만 값을 마스킹한 것일 수 있다. 정확한 분모를 모른다.
이때 정답은 숫자가 아니다.
계산 보류.
Exception Gate가 Calculation Gate보다 먼저 적용된다.
이 원칙은 매우 중요하다.
계산 가능한가를 확인하기 전에 계산하지 않는다.
V03과 V04: 같은 7.08퍼센트가 맞기도 하고 틀리기도 한다
아파트 합성 데이터에서 단지 전체 평균은 상반기 8.12억에서 하반기 8.70억으로 약 7.08퍼센트 올랐다. 전체 평균의 변화율로는 맞다. 그래서 V03은 PASS_WITH_QUALIFICATION이다. 왜 조건부일까.
하반기에 84㎡ 거래 비중이 늘어난 구성효과가 있기 때문이다. 이 7.08퍼센트를 59㎡ 가격 상승률이라고 쓰면 V04는 FAIL이다. 59㎡ 평균은 7.10억에서 7.10억으로 변하지 않았다.
같은 숫자라도 어느 집단의 계산인지가 다르면 틀린 답이 된다.
V05: 수학적으로 나눌 수 있어도 의미상 나누면 안 되는 경우
관광 방문자 지수 132. 관광소비 지수 121. 계산기는 121 ÷ 132를 계산할 수 있다. 그러나 그 결과를 1인당 소비라고 부를 수 없다.
두 지표는 서로 다른 원천 데이터에 기반하고, 공식 안내도 총량보다 추세 활용을 권고한다. 수학적 연산 가능성과 통계적 의미 가능성은 다르다.
VERIFY-8에서 이 오류는 Schema와 Calculation, Claim 세 곳에서 걸린다.
V06: 가장 그럴듯한 문장이 가장 위험할 수 있다
기온과 천식 합성 환자지수의 상관계수는 -0.982였다.
“기온이 낮아질수록 천식이 증가한다.”
관측 패턴 설명으로도 조심스러운 문장이다.
“낮은 기온이 천식을 유발한다.”
인과 주장이다. FAIL. 계절성, 대기질, 감염, 의료이용 등 다른 변수를 통제하지 않았다.
상관계수 계산 자체는 정확했어도 Claim Gate를 통과하지 못한다.
V07: 스톡을 플로처럼 더한 오류
고용보험 피보험자 수는 월말 시점의 규모다. 1월 10만명, 2월 10만명, 3월 10만명이라고 해서 3개월간 30만명의 서로 다른 사람이 있었다고 말할 수 없다. 같은 사람이 매달 반복된다. 12개월을 합산한 값을 연간 고용인원으로 쓰면 FAIL이다.
이 오류는 Schema Gate에서 잡을 수 있다.
한 행 또는 한 값이 무엇을 뜻하는지 알면 계산 자체를 시도하지 않는다.
검증표에는 결과뿐 아니라 ‘근거’를 남긴다
PASS/FAIL만 남기면 다음에 같은 오류가 반복된다.
그래서 검증표는 최소 네 열로 만든다.
| 검증항목 | 판정 | 근거 | 수정 |
|---|---|---|---|
| 분모 0 | FAIL | 마스킹 규칙 | 증가율 계산 보류 |
| 동일면적 | FAIL | 전체평균 전이 | 59㎡ 별도 계산 |
| 관광 나눗셈 | FAIL | 서로 다른 원천 추세 | 방향 비교로 변경 |
| 상관→원인 | FAIL | 인과설계 없음 | 패턴 문장으로 축소 |
수정 열이 있어야 검증이 편집으로 이어진다.
결과표의 한 행만 검증해도 좋은 이유
전체 수십만 행을 사람이 다시 계산할 수는 없다. 대신 대표 행을 고른다.
무작위 한 행.
최댓값 한 행.
0이나 결측이 있는 예외 한 행.
순위 1위 한 행. 네 종류를 검사하면 많은 오류를 발견할 수 있다. 예를 들어 조인 중복으로 값이 두 배가 되었다면 최댓값 행에서 이상이 보일 가능성이 높다. 마스킹 문제는 0 행에서 드러난다.
필터 오류는 무작위 행의 원본 역추적에서 발견될 수 있다. 표본검증이 전체 정확성을 보장하지는 않는다.
하지만 무검증보다 훨씬 강하다.
AI에게 ‘계산 과정’을 보관하게 한다
최종 결과만 받으면 나중에 검증하기 어렵다.
그래서 분석 단계부터 로그를 남긴다.
입력 파일: 기준일: 필터: 고유키: 제외 조건: 계산식: 결과 행 수: 검증 행: 검증 결과:
API라면 여기에 요청 파라미터와 resultCode를 붙인다. 파일이 바뀌거나 AI 모델이 바뀌어도 같은 입력 계약으로 다시 실행할 수 있다. 검증은 이미 만든 결과를 지키는 절차가 아니다. 공식 데이터의 정의가 바뀌었거나 서비스가 종료되었거나 계산이 틀렸다면 분석 설계와 결과를 고친다.
앞에서 생활인구 조합을 바꾸고, 세부 업종에 맞지 않는 존속연수 자료를 제외하고, 임금 사례의 데이터 조합을 교체한 이유도 같다. 현실 데이터는 처음 세운 설계보다 우선한다. 분석이 끝난 뒤 “출처가 어디였지?”라고 되짚기 시작하면 늦을 수 있다. 어떤 수치가 어느 파일에서 왔는지 이미 흐려졌을 수 있다.
따라서 분석할 때부터 다음을 저장한다.
- 기관
- 데이터명
- 공식 페이지
- 기준일
- 확인일
- 이용조건
- 실제 사용한 열/항목
이것이 출처 원장의 역할이다.
출처는 장식이 아니라 결과의 주소다.
현재성 검증은 한 번으로 끝나지 않는다
공개데이터의 URL, 파일명, 갱신주기, 서비스 방식은 바뀐다. 이 책을 쓰는 동안에도 실제로 바뀐 사례가 있었다. 서울 생활인구 기존 데이터는 생산이 종료되었다. 서울 상권 데이터의 제공 기준이 바뀌었다.
일부 API는 파일이 아니라 인증키 방식이었다.
따라서 분석 결과를 다시 사용하거나 외부에 공개하기 전에는 다음을 다시 확인한다.
- URL이 살아 있는가
- 최신 파일이 존재하는가
- 갱신이 중단되지 않았는가
- 라이선스가 바뀌지 않았는가
- API 이름과 파라미터가 바뀌지 않았는가
현재성은 한 번 확인하고 끝나는 도장이 아니다.
결과를 사용하는 시점까지 유지해야 하는 상태다.
검증을 끝낸 뒤에도 ‘모른다’가 남을 수 있다
VERIFY-8을 모두 돌렸다고 해서 현실의 답이 완성되는 것은 아니다. 데이터가 원래 측정하지 않은 것은 남는다. 왜 매출이 올랐는지. 왜 환자가 늘었는지.
왜 어떤 지역에서 사업자가 줄었는지. 왜 특정 학교 지표가 다른지.
검증은 빈칸을 없애는 절차가 아니다.
빈칸이 어디인지 정확히 표시하는 절차다.
이 표시가 있으면 독자는 근거와 추정을 구분할 수 있다.
마지막 검증 프롬프트
책 전체에서 사용할 검증 프롬프트를 하나로 정리한다.
아래 분석을 독립 검증해줘.
V1 Source
원출처·데이터명·기준일·이용조건이 명확한가?
V2 Input
실제 사용한 파일/API 응답과 합성 데이터를 구분했는가?
V3 Schema
한 행의 의미, 단위, 고유키, 0·결측·마스킹 규칙을 확인했는가?
V4 Filter
대상·공간·시간 필터가 질문과 일치하는가?
V5 Calculation
계산식의 분자·분모·집계단위가 맞는가?
V6 Exception
계산 보류해야 할 행이나 API 오류를 숫자로 바꾸지 않았는가?
V7 Cross-check
결과표 한 행 이상을 원자료에서 역추적해 재계산했는가?
V8 Claim
상관→인과, 평균→개인, 추정→실측, 관측→예측으로 과장한 문장이 없는가?
각 항목을
PASS / FAIL / 확인 필요로 판정하고,FAIL이면 수정 문장을 제안해줘.
기존 결론을 유지하는 것보다 원자료와 공식 정의를 우선해줘.
이 프롬프트를 마지막에 돌리면 AI는 분석 도구에서 편집 검증자로 역할이 바뀐다.
최종 책임은 누구에게 남는가
AI가 계산을 했다. AI가 표를 만들었다. AI가 검증도 했다. 그렇다면 책임도 AI에게 넘어갈까.
그렇지 않다. 어떤 질문을 선택했는지, 어떤 데이터를 근거로 채택했는지, 어떤 예외를 허용했는지, 어떤 문장을 외부에 발표했는지는 결국 사용자와 저자에게 남는다. 이 말은 AI를 덜 쓰라는 뜻이 아니다. 오히려 더 많이 쓸 수 있다는 뜻이다.
구조 점검을 맡기고, 계산을 맡기고, 반례를 찾게 하고, 검증을 맡긴다. 대신 마지막에 확인한다.
“이 문장은 이 데이터가 실제로 말한 것인가?”
이 질문에 답할 수 있다면 AI의 결과를 근거로 바꿀 수 있다.
한 줄 판정
AI 시대의 데이터 검증은 계산기를 다시 두드리는 데서 끝나지 않는다. 출처·입력·구조·필터·계산·예외·원자료 대조·최종 문장까지 추적해야 결과가 근거가 된다.
마지막에는 이 검증 규칙까지 포함해, 처음 보는 질문을 스스로 설계하는 한 장짜리 데이터 지도로 바꾼다.


