과거 화재·기상·건물 자료로 구역별 위험 순위를 매기면, 한정된 화재안전조사·순찰 인력을 어디에 먼저 보낼지 검토할 때 참고할 수 있습니다. 이 안내서는 확인할 구역의 순서를 제안하는 우선순위 도구를 만듭니다. 개별 화재가 언제 어디서 날지 맞히는 모델은 다루지 않습니다.
분석 코드는 코딩 에이전트가 써 줄 수 있습니다. 이 안내서는 에이전트가 스스로 알 수 없는 결정, 곧 무엇을 타깃으로 볼지와 예측 시점에 쓰면 안 되는 자료, 그리고 결과를 검산하는 기준을 중심으로 다룹니다.
- 예측 단위·타깃·결과를 쓸 사람을 업무 목적에 맞게 정할 수 있습니다.
- 공개 자료로 할 수 있는 범위와 내부 자료·사용 승인이 필요한 범위를 구분할 수 있습니다.
- 예측 시점에 알 수 없는 정보가 섞이는 누수를 점검하고 베이스라인과 정직하게 비교할 수 있습니다.
- 예측 점수의 편향과 운영 한계를 기록하고 사람 검토로 연결할 수 있습니다.
AI에게 맡기는 프롬프트
코드를 실행할 수 있는 AI(파일 분석 기능이나 코딩 에이전트)에게 위험도 분석을 맡길 때 쓰는 프롬프트입니다. 기관 내부의 출동·화재조사 자료를 쓸 때는 외부 AI가 아니라 승인된 내부 환경에서만 쓰고, 개별 주소·세대 정보는 넣지 않습니다. 에이전트 설치는 개발 환경에 있습니다.
[목적] 다음 달 화재안전조사·순찰 순서를 검토할 때 참고할 구역별 위험 순위표를 만듭니다. 결과는 예방 담당이 검토하는 보고용 자료입니다. [자료] 붙임 파일: (파일 이름과 기준일. 예: 시군구별 월간 화재 건수, 시군구별 건축물 집계, 월별 기상 요약) [분석 조건] - 예측 단위: (예: 시군구 × 월). 타깃: 그 달의 화재 발생 여부. - 예측 시점에 알 수 없는 열(그 달의 출동·화재 건수, 그 달의 점검 결과)은 피처에 넣지 말고, 뺀 열 목록을 결과에 적어 주세요. - 화재가 없던 달도 0으로 채운 전체 구역×기간 표를 먼저 만들고, 행 수가 구역 수 × 기간 수와 같은지 출력해 주세요. - 검증은 앞 기간으로 학습하고 뒤 기간으로 평가하는 시간 분할로 합니다. [완성 기준] 직전 기간 화재 건수 순위(베이스라인)와 모델을 같은 평가 기간에서 재현율·정밀도·상위 10% 포착률로 나란히 비교한 표. 자료별 기준일과 결합되지 않은 행 수를 함께 적어 주세요. 자료에 없는 값은 [확인 필요]로 남겨 주세요. [하지 말 것] 점수를 화재 발생 확률로 설명하지 마세요. 점검 대상 지정, 처분·단속, 인력 배치는 정하지 마세요. 공개 자료나 공식 위험 지표를 찾을 때는 https://119-ai-studio.kr/kg/index.txt 에서 맥락을 먼저 파악하고, 근거는 원문 주소와 함께 정리해 주세요. 확인 기준은 https://119-ai-studio.kr/risk-prediction.html 안내서를 따릅니다. 작업 전에 빠진 정보가 있으면 먼저 질문해 주세요.
결과를 받은 뒤 확인할 것은 다음과 같습니다.
- 전체 구역×기간 표의 행 수가 구역 수 × 기간 수와 같은지 봅니다.
- 피처 목록에 평가 기간의 출동·화재·점검 결과가 들어 있지 않은지 봅니다.
- 모델과 베이스라인을 같은 평가 기간에서 비교했는지 봅니다.
예측이 가능한 조건
모델은 과거에 건물 나이·밀집도·계절·최근 화재가 어떤 조합일 때 화재가 잦았는지 찾고, 지금 같은 조합을 보이는 구역에 높은 점수를 매깁니다. 그래서 두 가지가 전제돼야 합니다. 위험이 조건에 따라 실제로 몰려 있어야 하고, 그 조건이 자료로 남아 있어야 합니다. 둘 중 하나라도 없으면 모델은 단순한 베이스라인을 이기지 못합니다.
가상 상황: 점검 인원은 셋, 구역은 수백
다음은 학습용 가상 상황입니다. 어느 예방 부서에 점검 인력이 세 명 있고, 관할에는 살펴야 할 구역이 수백 곳입니다. 다음 달에 전부 돌 수는 없습니다.
지금까지의 방법은 대개 '지난번에 문제 있던 곳'과 '민원이 들어온 곳'입니다. 틀린 방법은 아니지만 이미 드러난 곳만 보게 됩니다. 조용하지만 위험이 쌓이는 구역은 순번이 자꾸 뒤로 밀립니다.
위험도 예측은 이 순서를 자료로 정하자는 제안입니다. 예측 순위는 담당자가 점검 순서를 검토할 때 참고하며 최종 결정을 대신하지 않습니다.
문제를 먼저 정의한다
모델보다 정의가 먼저입니다. 다음 네 가지를 정합니다.
- 공간 단위: 시군구, 행정동 또는 격자(예: 500m × 500m). 자원 배치 단위와 맞추되, 쓸 수 있는 자료의 위치 단위를 먼저 확인합니다.
- 시간 단위: 주 또는 월. 너무 짧으면 자료가 희박하고, 너무 길면 변화를 늦게 잡습니다.
- 타깃: 해당 단위·기간의 화재 발생 여부(이진 분류) 또는 건수(회귀). 운영에는 보통 발생 여부가 다루기 쉽습니다.
- 결과를 쓰는 사람과 방식: 예를 들어 예방 담당이 다음 달 화재안전조사 순서를 검토할 때 참고하는 순위표.
결합할 데이터
서로 다른 출처를 공간(좌표·행정코드) + 시간 키로 한 테이블에 모읍니다.
| 데이터 | 출처(예) | 주로 쓰는 변수 |
|---|---|---|
| 화재 | 국가화재정보시스템, 공공데이터포털 소방청 화재 통계 | 발생 시각·장소·유형·원인 |
| 출동 | 기관 내부 119 출동 기록(공개 파일은 항목·위치 단위가 다를 수 있음) | 출동 시각·위치·유형 |
| 기상 | 기상청 API허브 | 기온·습도·풍속·강수 |
| 건축물 | 건축물대장 | 준공연도·주용도·구조·연면적 |
| 주소·경계 | 주소 좌표·행정구역 경계 | 좌표, 시군구·읍면동 경계 |
공개 자료로 할 수 있는 범위도 알아 둡니다. 공공데이터포털의 「소방청_화재발생 정보」와 「소방청_연간화재통계」는 각 상세 페이지의 항목 설명(2026-10-26 기준)에 따르면 위치가 시도·시군구까지입니다. 격자나 행정동 단위 분석에는 기관 내부의 출동 기록과 화재조사 좌표가 필요하므로 사용 승인 절차를 먼저 확인합니다.
공개 자료만으로는 시군구 × 월 단위로 같은 흐름을 연습할 수 있습니다. 행정구역 코드는 기간 중에 바뀔 수 있으므로 법정동·행정구역 코드와 대조합니다. 연습용 표 데이터는 학습 데이터셋의 화재 기록 주제에 있습니다.
파생 변수 만들기
원시값을 그대로 넣기보다 업무 의미가 담긴 파생 변수를 만듭니다(피처 엔지니어링).
| 원시값 | 그대로 넣으면 모델이 보는 것 | 파생 변수로 바꾸면 |
|---|---|---|
| 준공연도 2004 | 의미 없는 큰 숫자 | 그 기간 기준 건물 나이 = 노후 신호 |
| 기온·습도 각각 | 관계없는 두 열 | 건조 정도(기상청 원문의 지표 정의를 확인해 씀) |
| 월 = 12 | 달력 순번 | 난방 사용기(겨울) 여부 |
아래 코드는 AI가 만든 코드를 검산할 때 볼 기준을 보여 주는 예입니다. 구역목록·기간목록·월별출동·건물은 미리 읽어 둔 자료이고, 기간은 '2025-01' 같은 연-월 문자열이라고 가정합니다.
import pandas as pd # 1) 구역×기간 전체 표: 출동이 없던 달도 0으로 채워야 '최근 3개월'이 3개월이 됩니다 base = pd.MultiIndex.from_product([구역목록, 기간목록], names=["구역", "기간"]).to_frame(index=False) df = (base.merge(월별출동, on=["구역", "기간"], how="left") .fillna({"출동건수": 0}) .sort_values(["구역", "기간"])) # 직전 3개월 합계: shift(1)로 그 기간 값은 빼고 직전 기간까지만 씁니다 df["최근출동"] = (df.groupby("구역")["출동건수"] .transform(lambda s: s.rolling(3, min_periods=1).sum().shift(1))) # 2) 건물나이는 기간마다 계산하고, 그 기간에 아직 없던 건물은 뺍니다 b = 건물.merge(base, on="구역") b["건물나이"] = b["기간"].str[:4].astype(int) - b["준공연도"] b = b[b["건물나이"] >= 0] df = df.merge(b.groupby(["구역", "기간"], as_index=False)["건물나이"].mean(), on=["구역", "기간"], how="left") df["겨울"] = df["기간"].str[5:7].isin(["12", "01", "02"]).astype(int)
shift(1)은 그 기간의 값을 피처에서 빼는 줄입니다. 예측 시점에는 알 수 없는 그 기간의 출동 건수를 피처에 넣으면 검증 점수는 높게 나오지만 실제로는 쓸 수 없습니다. 이를 데이터 누수라고 합니다. 같은 문제가 생기는 경우가 두 가지 더 있습니다. rolling(3)은 3개월이 아니라 3행이므로, 출동이 없던 달의 행이 빠진 표에서는 창이 몇 달 전까지 늘어납니다. 건물 나이를 올해 기준으로 계산하면 과거 기간에 그 뒤에 지은 건물이 들어갑니다.누수가 있으면 검증 점수가 오히려 좋아 보이므로 운영에 쓴 뒤에야 문제가 드러나기 쉽습니다. 첫 기간의 최근출동은 비어 있습니다. 이 값은 0으로 채우지 말고 '이력 없음'으로 따로 표시합니다. 구역×기간 표와 기간 처리는 pandas 코스의 멀티인덱싱과 그룹화와 날짜와 시간 다루기에 있습니다.
모델은 단순한 것부터
먼저 베이스라인을 세웁니다. "직전 기간 출동 빈도 순"으로 줄 세우는 단순 규칙입니다. 머신러닝 모델이 이 베이스라인을 이기지 못하면 모델은 필요 없습니다.
다음으로 표 데이터와 변수 사이의 비선형 관계를 다룰 수 있는 트리 기반 모델(RandomForest 등)을 씁니다. 결측값을 그대로 받는지는 모델과 판마다 다르므로 설치된 판의 문서를 확인합니다.
from sklearn.ensemble import RandomForestClassifier m = RandomForestClassifier( n_estimators=300, class_weight="balanced", # 화재는 드물어 불균형을 보정 random_state=0, ) m.fit(X_train, y_train) risk = m.predict_proba(X_test)[:, 1] # 위험 점수
평가: 정확도만 볼 때 생기는 문제
화재가 발생하는 단위가 전체의 1%라면, "전부 안전"이라고 찍는 모델도 정확도 99%입니다. 그래서 정확도 대신 다음을 봅니다.
- Recall(재현율): 실제 위험을 얼마나 놓치지 않았나. 예방에서 가장 먼저 봅니다.
- Precision(정밀도): 위험하다고 한 것 중 실제 비율
- 상위 K% 포착률(운영 지표): 위험 상위 10% 구역이 실제 화재의 몇 %를 담는가
다음은 실제 데이터가 아닌 가상의 예입니다. 한 달 동안 격자 1,000곳 가운데 실제로 화재가 난 곳이 20곳이라고 합시다. 모델이 '위험'이라 지목한 100곳 안에 그 20곳 중 16곳이 들어 있었다면:
- 재현율 = 16 / 20 = 0.8. 실제 화재 구역의 80%를 지목 목록에 넣었습니다.
- 정밀도 = 16 / 100 = 0.16. 위험이라 지목한 곳의 16%만 실제 화재였습니다.
예방에서는 놓친 위험이 점검받지 못한 채 남으므로 재현율을 먼저 보고, 인력이 감당할 수 있는 만큼 정밀도를 챙깁니다.
운영에 적용하기
- 모델 출력(점수)을 위험 지도와 순위표로 바꿉니다.
- 임계값은 자원에 맞춰 정합니다. "상위 10% 구역 집중 점검"처럼 가용 인력에서 거꾸로 정하는 편이 현실적입니다.
- 재학습 시점을 조건으로 잡는 방법은 예측 모델 운영, 드리프트 감지와 재학습 시점에 있습니다.
한계와 책임
모델은 과거를 배우므로 과거의 편향도 함께 배웁니다. 가장 조심할 세 가지입니다.
- 피드백 루프 편향: 과거 출동·점검이 많았던 곳일수록 "위험"으로 학습되고, 거기에 자원이 더 가고, 다시 데이터가 쌓입니다. 점검이 드물었던 구역은 위험이 있어도 자료에 잡히지 않아 계속 낮게 나올 수 있습니다. 신고·점검 분포를 함께 보며 보정합니다.
- 상관 ≠ 인과: 변수는 원인이 아니라 신호입니다. 모델은 "왜"를 설명하지 않습니다.
- 개인정보: 분석은 격자·행정동·시군구 단위 집계로 합니다. 개별 세대·개인을 식별하지 않습니다.
설계 판단
모델을 쓸지, 더 단순한 규칙을 쓸지는 자료의 상태와 판단의 용도로 결정합니다.
| 방식 | 맞는 상황 | 받아들이는 대가 | 사람이 확인할 것 |
|---|---|---|---|
| 최근 이력 순위 같은 단순 베이스라인 | 기록이 적거나 설명 가능성이 최우선인 때 | 복잡한 조건 결합을 놓칠 수 있음 | 예외 구역과 누락 기록 |
| 트리 기반 예측 모델 | 다양한 변수가 반복적으로 축적되고 시간 분할 검증이 가능할 때 | 변화 감시·재학습·편향 점검이 계속 필요함 | 베이스라인 대비 실질적 이점 |
| 모델 없이 담당자 검토 | 자료가 희소하거나 결측·편향을 설명하기 어려운 때 | 범위를 넓히기 어려움 | 자료를 더 모으는 동안의 명시적 판단 근거 |
새 모델을 만들기 전에 이미 있는 다음 지표를 확인합니다.
- 소방청 119빅데이터 분석사업(2023)의 '스마트 화재안전지수' 과제(결과 공개 여부 미확인, 공공 AI 도입 사례)
- 시군구 산불위험 예보
- 시·도지사가 지정하는 화재예방강화지구
모델 점수는 이런 공식 예보나 법정 지정을 대신하지 않으므로, 같은 지역의 공식 지표와 모델 순위를 나란히 놓고 차이를 설명할 수 있는지 봅니다.
운영 시나리오
아래는 실제 기관·사건과 무관한 가상 연습입니다. 점수가 이상할 때 바로 배치 판단을 바꾸지 않고 가설을 줄여 가는 흐름을 봅니다.
가상 시나리오 1: 예방 개입이 다음 학습 타깃을 바꾸는 경우
- 탐지: 높은 순위 구역을 집중 확인한 뒤 그 구역의 위반·점검 기록만 늘었습니다. 정기 점검이 유지된 다른 구역과는 기록이 쌓이는 조건이 달랐습니다.
- 원인 가설: 실제 위험이 커졌기 때문이 아니라, 모델이 고른 구역을 더 자주 보면서 관측 기회 자체가 타깃을 바꾼 피드백 루프를 먼저 의심합니다.
- 대응: 점검 선택 여부·시점·근거를 타깃과 별도로 기록하고, 미점검을 '문제 없음'으로 채우지 않습니다. 정기 확인 구역과 선택 확인 구역을 나눠 비교하는 로깅·분석은 위의 최소 예제 코드가 구현하지 않으므로 별도로 설계해야 합니다.
- 재발 확인: 새 후보를 동일한 시간 분할에서 베이스라인과 다시 비교하되, 점검 기회가 달랐던 구역은 따로 보고 선택 이력 효과가 반복되지 않는지 사람이 확인합니다.
가상 시나리오 2: 자료가 희소한 구역의 순위가 계속 뒤집히는 경우
- 탐지: 최근 소수의 기록이 추가될 때마다 해당 구역의 순위가 크게 바뀌고, 시간 구간을 바꾸면 베이스라인 대비 이점도 일관되지 않습니다.
- 원인 가설: 안정된 신호가 아니라 희소한 타깃과 계절성이 겹쳐 우연한 흔들림을 학습했다고 봅니다.
- 대응: 복잡한 모델 결과를 낮은 확신도의 참고 후보로 표시하고, 단순 베이스라인과 정기 점검 범위를 유지한 채 추가 기록을 모으게 합니다.
- 재발 확인: 여러 시간 구간의 롤링 검증에서 동일한 경향과 베이스라인 대비 이점이 반복되기 전에는 활용 범위를 넓히지 않습니다.
한계와 리스크
| 리스크 | 발생 조건 | 영향 | 완화·사람 승인 |
|---|---|---|---|
| 점검 이력의 피드백 루프 | 과거에 자주 본 구역의 기록만 더 쌓임 | 점검이 드문 구역이 계속 낮은 순위로 남음 | 정기 점검 범위를 보존하고 배치 변경은 담당자가 편향 지표와 함께 검토 |
| 결측·시차 불일치 | 데이터 출처별 갱신 시점과 코드가 다름 | 위험 변화처럼 보이는 인공 신호 발생 | 결합 커버리지와 기준일을 기록하고 공유 전 사람이 원천 표본 대조 |
| 점수의 확률·처분 근거 오인 | 상대 순위를 확정적 예측으로 설명함 | 특정 구역을 과도하게 겨냥하거나 점검에서 빼는 판단 | 출력을 참고 순위로만 표시하고 실제 배치·조치는 소속 기관 기준과 담당자 승인 필요 |
자주 묻는 질문
Q. 위험 점수를 화재 발생 확률로 읽어도 되나요?
아닙니다. 별도의 확률 보정과 검증을 하지 않았다면 점수는 비교를 위한 상대 순서입니다. 화재 시점이나 개별 건물의 발생 가능성을 단정하지 않습니다.
Q. 상위 순위 구역은 자동으로 화재안전조사 대상이 되나요?
아닙니다. 점수는 담당자가 추가로 확인할 후보를 줄일 뿐입니다. 화재안전조사의 대상과 시기는 법령 원문과 소속 기관 기준을 따르고, 정기 점검과 현장 정보는 모델 순위와 별도로 유지합니다.
Q. 모델과 현장 판단이 다르면 어느 쪽을 남겨야 하나요?
둘 다 남깁니다. 점수, 사용한 데이터 기준일, 담당자의 예외 판단과 근거를 같이 기록해야 다음 검증에서 모델이 무엇을 놓쳤는지 확인할 수 있습니다.
Q. 데이터가 갱신될 때마다 모델을 다시 학습해야 하나요?
갱신 자체만으로 재학습을 결정하지 않습니다. 스키마·결측·분포 변화와 늦게 확인되는 실제 성능을 함께 보고, 기록된 조건에 따라 재학습 후보를 올립니다.
사람 검토 체크리스트
- [ ] 타깃·공간 단위·시간 단위·결과를 쓰는 사람을 먼저 정하고 그다음 모델을 만들었습니다. - [ ] 쓸 자료의 위치 단위와 내부 자료의 사용 승인을 확인했습니다. - [ ] 피처에 예측 시점에는 알 수 없는 정보(그 기간의 출동 등)가 새어들지 않았습니다. - [ ] 검증은 무작위가 아니라 시간 분할로, 과거 학습·미래 검증으로 했습니다. - [ ] 정확도 대신 재현율·정밀도·상위 K% 포착률로 베이스라인과 비교했습니다. - [ ] 결과는 개별 세대가 아니라 격자·행정동·시군구 집계로만 다뤘습니다. - [ ] 모델이 낮게 본 구역도 정기 점검에서 빼지 않았습니다.
핵심 정리
- 위험도 예측은 확인할 구역의 순서를 제안하는 도구이며, 예측 단위·타깃·결과를 쓰는 사람을 먼저 정합니다.
- 공개 화재 통계는 시군구 단위이고, 격자·행정동 분석에는 내부 자료와 사용 승인이 필요합니다.
- 예측 시점에 알 수 없는 정보를 빼고, 복잡한 모델은 단순 베이스라인을 시간 분할 검증에서 이길 때만 씁니다.
- 순위는 공식 지표나 법정 지정을 대신하지 않으며, 정기 점검과 담당자의 예외 판단을 보존합니다.
다음 단계
- 예측 모델 운영, 드리프트 감지와 재학습 시점 — 점수가 언제부터 낡았는지 탐지하고 교체 근거를 남깁니다.
- 출동 데이터의 결측·중복·표기 불일치 정제하기 — 결측·중복·표기 불일치가 위험 신호처럼 보이지 않게 입력 자료를 먼저 정리합니다.
- AI 결과, 제출 전 확인 사항 — 순위와 설명을 보고·공유하기 전에 근거와 단정 표현을 점검합니다.