지오코딩과 참조 데이터 매칭¶
한 줄 요약: 이름·번호·코드만 있는 데이터에 위치를 붙이려면, "이 이름은 여기다"라고 적힌 기준(참조) 자료와 이어 붙여야 한다. 필요한 건 대부분 새 코드가 아니라 그 짝꿍 표다.
📍 만난 상황¶
- 2026-11-09 — 위치·시간 데이터를 모두 H3 칸에 올리는 정규화 흐름을 정리하던 중이었다. 직전에 "좌표 얻기 → pyproj로 4326 변환 → H3 칸"이라는 순서를 확인했다. 3번 물음 → 그날 일지
- 10:46 "좌표가 아예 없는 애들은 좌표를 만들려고 '입구'를 새로 만든다는 거야?" → 반은 맞다. 입구는 데이터셋마다가 아니라 방식마다 하나다.
- 10:47 "1번에서 '기존 자료'가 뭔지 모르겠어" → "기존"이 아니라 "기준 자료"였다.
- 10:48 "지금 필요한 기준 자료는 뭐고, 그게 필요한 데이터는 어떻게 되어 있다는 거야?" → 데이터별로 위치 열의 실제 값과 짝꿍 표를 나란히 받았다.
🧩 쉽게 말하면¶
이름만 적힌 출석부로 학생들의 자리를 지도에 찍는다고 해 보자. 출석부만으로는 불가능하다. "누가 몇 번째 줄 몇 번째 자리"라고 적힌 좌석표가 있어야 한다.
이 좌석표가 기준 자료다. 출석부의 이름과 좌석표의 이름을 맞춰 보면 자리가 나온다.
좌석표가 없으면 아무리 프로그램을 잘 짜도 자리를 알 수 없다. 짐작으로 찍으면 틀린 지도가 된다.
📖 제대로 알기¶
용어¶
- 지오코딩(geocoding): 주소·지명 같은 글자를 좌표로 바꾸는 일이다. 반대로 좌표 → 주소는 역지오코딩이다.
- 넓게 보면 관측소 번호·행정 코드처럼 위치를 가리키는 값을 실제 좌표나 경계와 잇는 일도 같은 원리다.
- 기준 자료(참조 데이터, reference data): 어떤 이름·번호가 실제로 어디인지 알려 주는 참고용 데이터다. 두 종류가 있다.
- 위치 사전: ID → 점 좌표. 예: 강우계 이름 → 위도·경도.
- 경계: 코드·이름 → 면 모양. 예: 행정동 코드 → 동 경계.
- 매칭 키: 두 표에 똑같이 들어 있어서 둘을 잇는 값. 강우 예에서는 강우계 이름이다.
- EPSG:4326: 위도·경도 좌표계 번호. H3는 이 좌표만 입력으로 받는다.
- H3: 지구를 육각형 칸으로 나눈 격자 체계.
h3_r9는 해상도 9의 칸 번호다.
좌표 없는 데이터의 세 경우¶
| 경우 | 예 | 할 일 |
|---|---|---|
| 입구 있음, 기준 자료만 필요 | 강우계 이름, 관측소 번호, 동 이름 | 짝꿍 표 구하기 |
| 찾는 방식이 처음 | 고속도로 "노선 + km", 하천 측점 | 입구 함수 + 기준 자료 |
| 원래 위치가 없음 | 시도 합계 통계, 코드표 | "위치 없음"으로 둠 |
입구는 "위치를 찾는 방식"마다 하나인 변환 함수다. 첫 번째 경우가 가장 많다. 그래서 코드는 그대로 두고 표만 구하면 되는 일이 대부분이다.
⚙️ 어떻게 동작하나¶
- 위치 열을 본다. 실제로 무엇이 적혀 있나. 좌표인가, 이름인가, 번호인가.
- 찾는 방식을 고른다. "ID → 위치 사전", "코드·이름 → 경계", "좌표 그대로" 중 하나다.
- 기준 자료를 구한다. 이미 있나, 파일로만 있나, 새로 받아야 하나.
- 매칭 키를 다듬는다. 앞뒤 공백, 표기 차이("강남구청" vs "강남구청 강우계")를 맞춘다.
- 이어 붙인다(조인). 키가 같은 줄끼리 붙여 좌표를 얻는다.
- 좌표계를 4326으로 맞춘다. 기준 자료가 평면 좌표면 pyproj로 바꾼다.
- H3 칸을 붙인다.
- 못 찾은 줄은 빈칸으로 두고 표시한다. 억지로 채우지 않는다.
flowchart TD
A["원천 데이터"] --> B{"위치 열에 무엇이?"}
B -->|"좌표"| D["pyproj로 4326"]
B -->|"이름·번호"| C["기준 자료와 매칭"]
B -->|"원래 없음"| G["위치 없음으로 둠"]
C -->|"찾음"| D
C -->|"못 찾음"| E["빈칸 + qa 표시"]
D --> F["H3 칸 붙이기"]
좌표가 없는 데이터도 매칭만 거치면 좌표가 있는 데이터와 같은 길로 합류한다. 갈림길은 "기준 자료와 매칭" 한 곳뿐이다.
왜 이렇게 설계할까. 입구 함수를 데이터셋마다 만들면 데이터가 100개일 때 함수도 100개가 된다. 방식마다 하나로 두면 고속도로 데이터 5종이 입구 하나를 같이 쓴다.
🧪 예시¶
-
예시 1 · 일상에 빗대어: 택배 기사가 받은 송장 3장에 "강남구청", "개포2동 주민센터", "OO빌딩"만 적혀 있다. 기사의 주소록에는 앞의 두 곳 주소가 있다. 두 장은 바로 배달된다. "OO빌딩"은 주소록에 없다. 기사는 근처 아무 데나 두지 않는다. "주소 확인 필요"로 표시해 둔다. 이것이 매칭 2건 성공, 1건
qa표시다. -
예시 2 · 실제로는: 강우 데이터에는 강우계 이름만 있다.
import pandas as pd, h3
rain = pd.DataFrame({"RF_NM": ["강남구청", "개포2동 "], "RN_10M": [0, 0]})
gauge = pd.DataFrame({"name": ["강남구청", "개포2동"], # 기준 자료
"lat": [37.517, 37.48], "lon": [127.047, 127.06]})
rain["key"] = rain["RF_NM"].str.strip() # ①
gauge["key"] = gauge["name"].str.strip()
out = rain.merge(gauge[["key", "lat", "lon"]], # ②
on="key", how="left")
out["h3_r9"] = [h3.latlng_to_cell(a, o, 9) if pd.notna(a) else None
for a, o in zip(out["lat"], out["lon"])] # ③
out["qa"] = out["lat"].isna().map({True: "no_match", False: ""}) # ④
how="left"는 원천 줄을 하나도 버리지 않는다는 뜻이다. 짝을 못 찾은 줄은 좌표가 비어 있게 된다.
③ 좌표가 생긴 줄에만 H3 칸을 붙인다. 이 기준 자료는 이미 위경도라서 pyproj 단계는 건너뛰었다.
④ 못 찾은 줄은 qa 열에 표시한다. 그날 서울 밖 교통량 지점 3,696줄도 이렇게 표시했다.
그날 정리한 데이터별 짝꿍 표 몇 가지다.
| 데이터의 위치 열 | 짝꿍 기준 자료 | 상태 |
|---|---|---|
교통량 spot_num = B-11 |
교통량 지점 표 | 있음 |
강우 RF_NM = 강남구청 |
강우량계 위치 데이터 | 파일로만 있음 |
지반침하 삼성동(법정동) |
법정동 경계 | 새로 받아야 함 |
⚖️ 비교 · 흔한 오해¶
| 작업 | 입력 → 출력 | 도구 |
|---|---|---|
| 좌표계 변환 | 평면 좌표 → 위경도 | pyproj |
| 지오코딩·매칭 | 이름·번호 → 좌표 | 기준 자료 + 조인 |
| 공간 조인 | 점 → 어느 경계 안인가 | 경계 자료 + 공간 연산 |
오해 1. "좌표 없는 데이터마다 입구를 새로 만든다." 데이터마다 열 이름이 달라서 형식도 모두 다르게 보인다. 하지만 찾는 방식은 몇 가지뿐이다. 대부분은 이미 있는 입구에 기준 자료만 꽂으면 된다.
오해 2. "기존 자료" 그날은 "기준 자료"를 "기존 자료"(이미 있던 자료)로 읽었다. 발음과 글자가 비슷해서 생기기 쉬운 혼동이다. 뜻은 "기준이 되는 짝꿍 표"다. 이미 있든 새로 받든 상관없다.
오해 3. "입구가 좌표를 만들어 낸다." 입구는 좌표를 지어내지 않는다. 기준 자료에서 실제 위치를 찾아올 뿐이다. 예를 들어 "강남구 전체 피해액"을 강남구 칸 527개에 나눠 넣지 않는다. 없는 정밀도를 만들면 지도가 거짓말을 한다.
🛠️ 실무에서는¶
- 이름은 단독 키로 쓰지 않는다. 같은 동 이름이 여러 구에 있을 수 있다(예: 신사동은 강남구와 관악구에 모두 있다). 구 + 동처럼 묶어서 맞춘다.
- 기준 자료에도 시점이 있다. 행정구역은 개편된다. 몇 년도 경계인지 함께 기록한다.
- 라이선스를 본다. 주소 → 좌표 API 중에는 결과를 저장하지 못하게 하는 것이 있다. "저장 가능한 자료"인지 먼저 확인한다.
- 매칭률을 숫자로 남긴다. "3,491줄 중 3,491줄 성공"처럼 기록해 두면 다음 데이터에서 이상을 바로 알아챈다.
체크리스트
- [ ] 위치 열의 실제 값 3개를 눈으로 확인했나
- [ ] 짝꿍 기준 자료가 무엇이고 어디서 구하는지 정했나
- [ ] 매칭 키의 공백·표기 차이를 다듬었나
- [ ] 못 찾은 줄을 버리지 않고 qa로 표시했나
문제가 생기면 먼저 볼 것: 매칭률이 갑자기 떨어지면 원천 쪽 이름 표기가 바뀌었는지, 기준 자료가 옛 버전인지 본다.
❓ 자주 묻는 질문¶
- Q. 기준 자료가 평면 좌표(예: EPSG:5181)로 되어 있으면? A. 매칭으로 좌표를 얻은 뒤 pyproj로 4326으로 바꾸고 H3 칸을 붙인다.
- Q. 구 이름만 있는 데이터는 칸에 못 올리나?
A. 칸 없이
sgg_code(구 코드)만 붙인다. 구 단위 필터는 그대로 된다. 더 정밀한 기준 자료가 생기면 그때 올린다. - Q. 주소만 있는 데이터는? A. 주소 → 좌표 자료나 API가 기준 자료 역할을 한다. 결과를 저장해도 되는지부터 확인한다.
🔭 더 깊이 보기¶
- 공간 조인(점이 어느 경계 안에 드는지 계산)은 어떻게 하나? — 경계 자료를 쓰는 "코드·이름 → 경계" 입구의 핵심 연산이라서.
- 법정동과 행정동은 무엇이 다른가? — 그날 필요한 기준 자료 중 법정동 경계가 따로 있었던 이유라서.
- 좌표계와 pyproj의 측지계 변환은 왜 까다로운가? — 매칭 다음 단계에서 수백 m 오차가 생기는 곳이라서.
- 관련 주제: 메타데이터 카탈로그 기반 조회 — 매칭으로 붙인 구 코드·칸 번호가 공통 키로 쓰이는 곳
📚 참고 자료¶
- 행정표준코드관리시스템 (행정안전부, 한국어) — 법정동·행정구역 코드표를 내려받는 곳 · 링크
- 카카오 로컬 API 개발 가이드 (Kakao Developers, 한국어) — 주소 → 좌표 변환(지오코딩) API의 실제 모습 · 링크
- H3 Documentation (Uber H3 공식 문서, 영문) — 위경도 → 칸 번호 변환과 해상도 개념 · 링크
🗓️ 이력¶
- 2026-11-09: 좌표 없는 데이터에 입구를 새로 만드나, "기준 자료"가 무엇인가, 지금 필요한 기준 자료는 무엇인가를 3번 물음 → 일지