본문 바로가기
홈 AI 학습 AI 실무 안내서 공공 API JSON을 검산 가능한 CSV로
L2 중급 · 13분 읽기

공공 API JSON을 검산 가능한 CSV로

2026.10.26 갱신 공공 API 데이터를 지도·통계에 넣기 전 정리하는 실무자
#공공API#데이터정규화#검산#좌표결측
검토 상태: 전문 검토 전 위험도 미분류

업무에 AI를 쓸 때 확인하면 좋은 방법과 점검 항목을 정리한 참고 자료입니다. 실제 업무에 적용할 때는 소속 기관의 기준과 담당자 검토를 함께 확인합니다.

전국소방용수시설 표준데이터는 공공데이터포털에서 파일과 오픈API로 함께 제공됩니다(공공 데이터 카드). 이 자료를 지도나 통계에 올리면 몇 가지가 자주 어긋납니다. 파일과 API의 열 이름이 다르고, 페이지를 겹쳐 받거나 다른 날 받은 자료를 합치면 같은 시설이 두 번 들어가며, 좌표가 빈 행이 있습니다. 그대로 쓰면 오류 메시지 없이 결측과 중복이 결과에 들어갑니다.

요즘은 받은 자료를 합치고 정리하는 코드를 AI가 짜고 실행합니다. 그래도 무엇을 받을지, 어떤 수가 맞아야 완성인지, 무엇을 사람이 정할지는 사람이 정해 줘야 합니다. 이 안내서는 그 기준을 다룹니다.

🎯 이 장의 목표
  • 쓰임에 따라 파일 내려받기와 오픈API 수집 가운데 받는 방법을 고를 수 있습니다.
  • 파일의 한국어 열과 API 영문 키를 표준 열로 맞추고 키 조합으로 중복을 셀 수 있습니다.
  • 선언 총건수·내려받은 행·고유 키 수를 나눠 검산할 수 있습니다.
  • 좌표 결측과 충돌 행을 자동 확정하지 않고 사람 검토용으로 분리할 수 있습니다.

AI에게 맡기는 프롬프트

소방용수시설 자료를 지도·집계용으로 정리하는 코드를 맡길 때 씁니다. 코드를 실행할 수 있는 AI(파일 분석 기능이나 코딩 에이전트)에게 내려받은 파일이나 API 응답을 저장한 폴더를 줍니다. 인증키는 프롬프트와 코드에 넣지 않고 환경 변수로 둡니다.

TEXT
[목적] 관할 소방용수시설을 지도에 올리기 전에, 받은 자료를 한 시설 한 행의 분석용 CSV로 정리합니다. 결과는 (예: 관할 용수시설 현황 보고용 지도)에 씁니다.
[자료] (예: data 폴더의 전국소방용수시설 표준데이터 CSV 파일, 또는 오픈API 응답을 페이지별로 저장한 JSON 파일과 페이지마다의 조회 조건·수집 시각 기록)
소방용수 주제의 맥락은 https://119-ai-studio.kr/kg/topic-fire-water.txt 에서 먼저 파악하고, 근거는 원문 주소와 함께 정리해 주세요.
[완성 기준]
- 원본 열 이름(파일의 한국어 열, API 영문 키)과 표준 열의 대응표를 먼저 보여 주세요. 대응을 모르는 열은 빈값으로 넘기지 말고 목록으로 알려 주세요.
- 중복은 (시군구코드, 시설번호) 조합으로 세어 주세요. 같은 키의 행은 지우지 말고 review_items.csv로 옮겨 주세요.
- 좌표가 비었거나 숫자로 읽히지 않는 행도 review_items.csv로 옮겨 주세요.
- summary.csv에 선언 총건수, 내려받은 행 수, 고유 키 수, 좌표 유효 행 수, 검토 행 수, 데이터기준일자의 최솟값과 최댓값을 적고, 내려받은 행 수와 고유 키 수를 각각 선언 총건수와 비교한 결과를 출력해 주세요.
[하지 말 것]
- 인증키를 코드·출력·대화에 적지 마세요. 환경 변수에서 읽어 주세요.
- 페이지마다 선언 총건수가 다르면 합치지 말고 멈춘 뒤 알려 주세요.
- 중복·결측 행 가운데 어느 쪽이 맞는지 정하지 마세요. 빈 좌표를 추정해 채우지 마세요.
확인 기준은 https://119-ai-studio.kr/public-api-normalize.html 안내서를 따릅니다.
작업 전에 빠진 정보가 있으면 먼저 질문해 주세요.

결과를 받은 뒤 확인할 것은 다음과 같습니다.

  • 대응표의 각 줄을 공공데이터포털 상세 페이지의 항목표와 대조합니다. 이름이 비슷하다는 이유로 이어 붙인 줄이 없는지 봅니다.
  • summary.csv에 두 비교(내려받은 행 수와 선언 총건수, 고유 키 수와 선언 총건수)가 실제로 찍혔는지 봅니다.
  • review_items.csv가 비어 있지 않으면 지도·보고 반영을 멈추고 행마다 원본을 확인합니다.

동작 원리

정리는 받는 방법 정하기 → 열 이름 맞추기 → 키로 중복 세기 → 결측·충돌 분리 → 건수 검산의 순서입니다. 오픈API는 전체를 한 번에 주지 않고 페이지로 나눠 주므로, 페이지마다 조회 조건과 응답에 적힌 전체 건수(totalCount)를 함께 저장합니다. 페이지마다 이 값이 다르면 서로 다른 시점이나 조건의 응답이 섞였을 수 있으므로 합치기 전에 멈춥니다.

다음으로 원본 열 이름을 대응표에서 찾아 표준 열 하나로 옮깁니다. 표준 열의 목록을 스키마라고 합니다. 파일은 시설번호·위도처럼 한국어 열, 오픈API 응답은 fcltyNo·latitude처럼 영문 키라서 열 이름을 먼저 맞춰야 두 출처의 행을 같은 키로 비교할 수 있습니다. 대응을 찾지 못한 열은 빈값으로 진행하지 않고 "알 수 없는 열"로 기록합니다.

마지막에 선언 총건수(제공자가 밝힌 전체), 내려받은 행 수(실제로 받은 원시 행), 고유 키 수(중복을 접은 분석 단위)를 나눠 봅니다. 세 수의 차이로 정답을 알 수는 없지만, 어느 단계를 조사해야 하는지는 알 수 있습니다.

선택지와 트레이드오프

선택지맞는 상황장점주의할 점
파일 내려받기(CSV 등)현황을 한 번 지도에 올릴 때페이지를 합칠 일이 없어 단순함받은 날과 데이터기준일자를 함께 기록해야 함
오픈API 페이지 수집같은 조건으로 정기 갱신할 때수집을 반복해 최신 자료를 받을 수 있음인증키 관리, 페이지 겹침·누락, 호출 한도를 함께 관리해야 함
대응표 기반 표준화파일·API·판마다 열 이름만 다를 때대응표 한 곳만 고치면 표준 열이 유지됨뜻이나 단위가 다른 열을 이름이 비슷하다고 합치면 안 됨
중복을 검토 파일로만 분리어느 행을 남길지 근거가 부족할 때원본 충돌을 숨기지 않고 사람이 비교 가능완성은 늦어지지만 잘못된 병합을 막음

가상 상황: 소화전이 지도에 두 번 찍혔다

다음은 학습용 가상 상황입니다. 담당자가 지난달 내려받은 표준데이터 CSV에 이번 주 오픈API로 받은 관할 자료를 더해 지도에 올렸습니다. 어떤 소화전은 같은 자리에 두 번 찍혔고, API로 받은 시설은 지도에서 모두 빠졌습니다.

원인은 두 가지였습니다. 지도에 올리는 코드는 위도 열만 읽어서 API 행의 latitude 값을 찾지 못했고, 같은 시설이 파일과 API 양쪽에 들어 있었습니다. 담당자는 위 프롬프트로 다시 맡기고 대응표를 먼저 받았습니다. 열을 맞춘 뒤 키 조합으로 세자 중복 후보가 나왔고, 두 행의 데이터기준일자가 서로 달랐습니다. 담당자는 어느 출처를 기준으로 할지 정하고 그 결정을 기록했습니다.

AI가 중복을 자동으로 지우고 빈 좌표를 주소로 추정해 채운 지도를 대조 없이 보고에 쓰면 실패합니다.

가상 사례: 데이터 담당자의 조회 조건 혼합 발견

다음은 설명을 위한 별도의 가상 사례입니다. 데이터 담당자가 기간별 시설 현황을 비교하려고 저장해 둔 여러 페이지를 합칩니다. 이번에는 좌표 표시보다 같은 조회 묶음인지부터 확인합니다. 입력 폴더에는 조회 조건과 수집 시각을 기록한 파일도 있고, 기록이 빠진 파일도 섞여 있습니다.

담당자는 파일명 순서만 믿지 않고 각 응답의 조회 조건과 선언 총건수를 먼저 목록으로 만듭니다. 조건이 다르거나 출처를 설명할 수 없는 페이지는 같은 묶음에 넣지 않고 검토 폴더로 옮깁니다.

원하는 건수와 비슷하다는 이유로 서로 다른 조회 결과를 합치면 실패합니다. 총건수가 우연히 같아도 같은 묶음이라는 증거는 아닙니다. 사람은 조회 조건·수집 시각·페이지 번호를 확인하고, 다시 만들 수 있는 묶음만 분석용 CSV 후보로 승인합니다.

열 이름 맞추기

아래는 AI가 만든 대응표를 확인할 때 기준이 되는 예입니다. 한국어 열은 공공데이터포털 상세 페이지의 항목명, 영문 키는 같은 페이지의 오픈API 항목표에 적힌 이름입니다. 실제 응답을 받아 같은지 확인한 뒤 씁니다.

PYTHON
# 표준 열: [파일의 한국어 열, 오픈API 영문 키]
FIELD_ALIASES = {
    "facility_no":   ["시설번호", "fcltyNo"],
    "facility_type": ["시설유형코드", "fcltySeCode"],  # 이름이 아니라 코드값
    "sigungu_code":  ["시군구코드", "signguCode"],
    "lat":           ["위도", "latitude"],
    "lon":           ["경도", "longitude"],
    "base_date":     ["데이터기준일자", "referenceDate"],
}
KEY = ["sigungu_code", "facility_no"]  # 시설번호만으로 전국에서 하나뿐인지는 확인 전

표준데이터는 여러 관할기관의 자료를 모은 것이므로, 시설번호 하나만으로 전국에서 겹치지 않는지는 확인되지 않았습니다. 확인하기 전에는 시군구코드와 시설번호를 함께 키로 씁니다. 시설유형코드는 숫자 코드라서 지도에 '소화전'처럼 이름으로 보이려면 코드표가 필요합니다. 코드표를 확인하기 전에는 코드값 그대로 둡니다.

TEXT
# 파일 한 행 (가상 값)
시설번호=가상-001, 시군구코드=00000, 위도=37.55, 경도=126.98, 데이터기준일자=(이전 기준일)
# API 응답 한 행 (가상 값)
{"fcltyNo": "가상-001", "signguCode": "00000", "latitude": "", "longitude": "", "referenceDate": "(최근 기준일)"}

대응표로 열을 맞추면 두 행이 같은 표준 열로 읽히고, 키가 같아 중복 후보로 잡힙니다. 좌표가 있는 행을 남기는 규칙을 쓰더라도 두 행은 review_items.csv에 함께 남겨, 기준일이 다른 두 자료 가운데 무엇을 쓸지 사람이 정하게 합니다.

건수 검산

검산은 세 가지입니다. 각각 다른 단계의 문제를 잡습니다.

  • 페이지마다 선언 총건수가 같은가: 다르면 조회 도중 조건이 바뀌었거나 다른 응답을 섞은 것이므로 합치지 않습니다.
  • 내려받은 행 수 = 선언 총건수인가: 페이지를 빠짐없이, 겹치지 않게 받았는지 봅니다. 많으면 페이지 겹침, 적으면 누락입니다.
  • 고유 키 수 = 선언 총건수인가: 원자료 안에 같은 키가 두 번 있는지 봅니다.

파일로 받으면 선언 총건수가 없을 수 있습니다. 전국소방용수시설표준데이터 상세 페이지에도 전체 건수는 없고, 그리드 형태 자료의 다운로드는 5만 건으로 제한된다고 적혀 있습니다. 이때는 행 수와 고유 키 수를 비교하고, 행 수가 5만 건이면 잘렸을 수 있으므로 오픈API의 totalCount와 견줍니다. 데이터기준일자의 최솟값과 최댓값을 보면 관할기관마다 다른 날짜 기준으로 올렸는지 알 수 있습니다.

TEXT
metric,value
declared_total_count,12
downloaded_rows,13
unique_key,12
valid_rows_with_coordinates,11
review_rows,3
total_count_consistent,True
min_base_date,(가장 이른 데이터기준일자)
max_base_date,(가장 늦은 데이터기준일자)

위 예에서 내려받은 행(13)이 선언 총건수(12)보다 하나 많고 고유 키(12)는 선언 총건수와 같습니다. 건수만으로 겹친 원인을 정할 수는 없으므로, 응답 원본에서 겹친 행이 어느 페이지에서 나왔는지 확인합니다. 좌표가 있는 11건만 지도에 올리고, 겹친 행과 좌표가 빈 행은 review_items.csv에서 사람이 봅니다.

검산이 보장하는 것과 아닌 것

검산 항목보장하는 것보장하지 않는 것
페이지 간 선언 총건수 일치필요한 조건(같은 조회 조건이라는 보장은 아님. 조회 조건·수집 시각도 기록)원자료의 정확성
내려받은 행 수 = 선언 총건수필요한 조건(누락과 겹침이 서로 상쇄될 수 있어 고유 키 목록도 대조)시설 정보 자체의 정확성
고유 키 수 = 선언 총건수원자료 안에 같은 키가 없는지 확인시설번호 자체가 맞는지
좌표 숫자 변환지도에 올릴 수 있는 행 분리좌표가 실제 위치와 맞는지
검토 파일 분리중복·결측을 사람이 보게 남김자동 정답 판정
▸ 소방 활용 포인트
소화전·소방용수 자료를 지도에 올리기 전에 내려받은 행 수와 고유 키 수를 선언 총건수와 각각 비교하고, 좌표가 빈 행이 몇 건인지 확인합니다. review_items.csv가 비어 있지 않으면 지도화·보고 반영을 멈추고 원문을 확인합니다.

내 업무에 적용하기

  1. 쓰임을 먼저 정합니다. 현황을 한 번 지도에 올릴 목적이면 파일, 정기 갱신이면 오픈API를 씁니다. 인증 방식과 호출 한도는 공공 데이터 카드에서 확인합니다.
  2. 인증키는 환경 변수에 두고, 위 프롬프트로 정리 코드를 맡깁니다.
  3. AI가 만든 대응표를 상세 페이지의 항목표와 대조하고, summary.csv의 수와 review_items.csv를 확인합니다.
  4. 좌표가 빈 행을 주소로 다시 좌표화하려면 도로명주소 검색 API나 SGIS 주소·경계 API를 쓰고, 다시 좌표화한 행인지를 별도 열로 기록합니다.

정리된 분석용 CSV는 지도화나 통계로 넘깁니다. 지역별 시설 수 집계는 출동 통계, CSV 한 장으로 월간 집계의 검산 방법을 쓰고, 지도는 오픈 소스 folium이나 GeoPandas로 그릴 수 있습니다. 표기·결측·중복의 일반 원리는 출동 데이터의 결측·중복·표기 불일치 정제하기에 있습니다.

⚠️ 흔한 실수
실제 인증키(serviceKey)는 코드·문서·프롬프트·공개 저장소에 넣지 않습니다. 공개 표준데이터에 내부 관리 자료를 합쳤다면 내부 관리번호·시설 보안 정보는 공개 결과에 넣지 않습니다.

문제 해결

증상가능한 원인처방확인
특정 열이 전부 비어 보임파일의 한국어 열과 API 영문 키를 섞었는데 대응표에 한쪽 이름이 없음원본 열 이름을 확인해 대응표에 명시적으로 추가변환 전후 샘플 행을 원본 값과 대조
중복을 접은 뒤 예상보다 행이 크게 줄어듦시설번호만 키로 썼거나 빈 번호가 있음시군구코드와 시설번호 조합으로 다시 세고 빈 번호는 검토 파일로 분리키별 원시 행 수와 출처 확인
페이지마다 totalCount가 다름조회 조건·수집 시점·응답 묶음이 섞임병합을 멈추고 조회 조건별로 파일을 다시 구분한 묶음의 조건과 선언 총건수가 일관되는지 확인
좌표는 숫자인데 지도 위치가 의심됨숫자 변환만 통과했고 위치 의미는 검증되지 않음자동 확정하지 않고 원출처와 별도 위치 검토로 분리좌표 유효, 위치 확인, 다시 좌표화 여부를 다른 열로 기록

자주 묻는 질문

Q. 내려받은 행 수와 고유 키 수가 모두 선언 총건수와 같으면 데이터가 정확한가요?

받는 과정과 키 중복에 문제가 없다는 검산입니다. 시설번호와 좌표·유형 값이 현실과 맞다는 보증은 아니므로 내용 검토가 별도로 필요합니다.

Q. 좌표가 빈 중복 행은 그냥 삭제해도 되나요?

좌표가 있는 같은 키의 행과 실제로 같은 시설인지 먼저 확인합니다. 원본 출처와 충돌 내용을 검토 파일에 남기지 않으면 잘못된 병합을 추적할 수 없습니다.

Q. AI가 만든 열 대응표를 그대로 써도 되나요?

이름이 비슷해도 뜻과 단위가 다를 수 있습니다. 상세 페이지의 항목표와 샘플 값을 보고 의미가 같은 경우에만 대응표에 남깁니다.

Q. review_items.csv가 있으면 나머지 정상 행은 바로 공개해도 되나요?

검토 행 분리는 데이터 품질 단계일 뿐 공개 승인 단계가 아닙니다. 내부 자료를 합쳤다면 정상 행에도 내부 관리번호 같은 공개 제한 정보가 없는지 따로 확인합니다.

핵심 정리

  • 받기 전에 쓰임(한 번 지도화 또는 정기 갱신)을 정하고, 인증키는 환경 변수에 둡니다.
  • 열 이름을 표준 열로 맞춘 뒤에야 파일과 API에서 온 행을 같은 키로 비교할 수 있습니다.
  • 내려받은 행 수와 고유 키 수를 선언 총건수와 각각 비교하면 페이지 겹침과 원자료 중복을 구분할 수 있습니다.
  • 중복·결측·충돌은 AI가 정하지 않게 하고 원본 근거와 함께 검토 파일로 남깁니다.

다음 단계