월말·분기말이면 점검 대상 목록과 실제 점검 기록을 맞춰 봐야 합니다. 요즘은 이 대조 코드를 AI가 금방 만들어 줍니다. 그래도 어떤 기록을 대조하는지, 무엇을 대상으로 보는지, 결과가 맞는지 무엇으로 확인하는지는 담당자가 정해야 합니다.
이 안내서는 그 대조 규칙과 검산식을 다룹니다. 결과는 담당자가 원자료로 확인할 후보 목록이며, 우선순위를 자동으로 정하지 않습니다.
- 대조하기 전에 기록의 종류, 비교할 대상 상태, 기준일을 정할 수 있습니다.
- 양방향 대조가 찾는 두 가지 차이를 설명할 수 있습니다.
- AI에게 대조 코드를 맡기고 결과를 검산식으로 확인할 수 있습니다.
- 날짜를 읽지 못한 기록과 업무상 제외 대상을 미점검 후보와 구분할 수 있습니다.
AI에게 맡기는 프롬프트
점검 대조 코드를 코드 실행이 되는 AI(파일 분석 기능이나 코딩 에이전트)에게 맡길 때 씁니다. 실제 자료는 먼저 생성형 AI 입력 확인으로 확인하고, AI에게는 열 이름과 합성 몇 줄만 줍니다. 받은 코드는 기관 PC에서 실제 자료로 실행하고, AI에게 다시 보여 줄 때는 건수 집계처럼 시설 정보가 없는 결과만 줍니다.
[목적] 월말 점검 누락 확인용으로, 점검 대상 목록과 점검 기록을 대조하는 파이썬 코드를 만들어 주세요. 결과는 담당자가 원자료로 확인할 후보 목록입니다. [자료] 붙임 파일은 열 이름과 합성 값만 있는 예시입니다. - facility_register.csv: facility_id, facility_type, district, status - inspection_log.csv: facility_id, inspected_at, items_failed, violation_category, result, reinspection_due [대조 규칙] - facility_id는 문자로 읽어 앞자리 0을 지키고, status가 active인 대상만 비교합니다. - 대상에만 있는 ID(미점검 후보)와 기록에만 있는 ID를 각각 다른 파일로 저장합니다. - 재점검 임박은 대상별 가장 최근 기록의 reinspection_due가 기준일부터 30일 안인 것만 고릅니다. - 날짜는 형식을 지정해 읽고, 값이 있는데 읽지 못한 행은 따로 저장합니다. - 기준일은 실행할 때 입력받고 결과 파일에 함께 적습니다. [완성 기준] 결과와 함께 다음 검산 두 줄을 출력해 주세요. - active 대상 수 = 기록 있는 대상 수 + 미점검 후보 수 - 기록의 ID 수 = 대상과 연결된 ID 수 + 기록에만 있는 ID 수 [하지 말 것] 시설명·주소 열을 결과에 넣지 마세요. 이름이 비슷하다는 이유로 ID를 합치지 마세요. 우선순위나 위반 여부를 판정하지 마세요. 열의 뜻이나 규칙이 자료로 분명하지 않은 부분은 추측하지 말고 [확인 필요]로 남겨 주세요. 확인 기준은 https://119-ai-studio.kr/inspection-gap-check.html 안내서를 따릅니다. 작업 전에 빠진 정보가 있으면 먼저 질문해 주세요.
결과를 받은 뒤 확인할 것은 다음과 같습니다.
- 검산 두 줄이 출력에 실제로 찍혔고 양쪽 수가 같은지 봅니다.
- 재점검 후보에 그 뒤 점검이 끝난 대상의 옛 기한이 섞이지 않았는지 대상 두세 곳의 기록 이력으로 확인합니다.
- 날짜를 읽지 못한 행 수를 원본의 해당 행과 대조합니다.
대조하기 전에 정할 것
프롬프트를 쓰기 전에 담당자가 정해 둘 업무 기준입니다.
- 어떤 기록인가: 소방관서가 하는 화재안전조사 기록인지, 소방시설 자체점검 결과서인지 정합니다. 기록이 들어오는 경로와 누락의 뜻이 다릅니다. 자체점검 결과서를 올리는 방법은 자체점검 결과서 자동 업로드 매뉴얼에서, 서식은 점검양식 목록에서 봅니다.
- 무엇이 대상인가: 대상 목록의 상태 값 가운데 무엇을 비교할지 정하고, 목록이 언제 기준인지 적습니다. 대상의 범위는 특정소방대상물 정의와 기관 지침으로 확인합니다.
- 언제 기준인가: 기준일을 정하고 결과에 함께 적습니다. 기준일이 바뀌면 재점검 임박 후보도 바뀝니다.
- 누가 쓰는가: 내부 확인용이면 ID 수준의 목록을, 외부 공유용이면 집계만 남깁니다.
프롬프트와 아래 코드의 파일·열 이름은 예시이므로 기관 자료의 실제 열 이름으로 바꿔 씁니다.
동작 원리
대상 300곳에서 점검 280건을 빼 미점검 20곳이라고 셈하면, 점검 기록에 대상 목록에 없는 곳(관할 변경, 폐업, 중복 기록)이 섞였을 때 틀린 숫자가 나옵니다. 그래서 개수를 빼지 않고 ID가 양쪽 목록에 있는지를 확인합니다. 대상에만 있는 ID는 미점검 후보, 기록에만 있는 ID는 관할 변경·폐업·중복 기록을 확인할 후보이므로 둘 다 냅니다.
ID 표기가 소방-001과 소방_001, 001과 1처럼 다르면 같은 대상도 다른 ID로 셉니다. 표기를 맞추는 방법은 출동 데이터의 결측·중복·표기 불일치 정제하기에 있습니다.
재점검 임박은 대상별 가장 최근 기록으로 판단합니다. 모든 기록에서 고르면 그 뒤 재점검이 끝난 대상의 옛 기한도 후보로 나옵니다. 날짜 칸이 비어 있으면 재점검이 정해지지 않은 기록일 수 있고, 값이 있는데 읽지 못하면 원자료를 고쳐야 하는 기록입니다.
세 결과는 질문과 이어지는 일이 다르므로 한 점수로 합치지 않습니다.
| 결과 | 판정 규칙 | 이어지는 일 |
|---|---|---|
| 미점검 후보 | active 대상 가운데 점검 기록이 없는 것 | 원자료 확인 뒤 방문 계획 |
| 재점검 임박 후보 | 대상별 최신 기록의 기한이 기준일부터 30일 안 | 일정 관리 |
| 불량 분류 집계 | items_failed가 0보다 큰 기록을 분류별로 셈 | 점검·교육 내용 검토 |
선택지와 트레이드오프
대조 방법은 결과를 누가 읽고 어떤 오류를 추적해야 하는지에 따라 고릅니다.
| 선택지 | 맞는 상황 | 주의할 점 |
|---|---|---|
isin으로 한쪽에만 있는 ID 찾기 | 미점검 후보를 빠르게 찾을 때 | 반대 방향은 따로 확인해야 합니다. |
merge(..., indicator=True) | 양쪽 존재 여부를 한 표로 보여 줄 때 | 키가 중복되면 행이 늘어나므로 validate="one_to_many"로 대상 쪽 키 중복을 막습니다. |
| 대상별 최신 기록으로 날짜 비교 | 재점검 임박 후보를 고를 때 | 점검일을 읽지 못한 기록이 있는 대상은 최신 기록을 정하지 않고 확인 목록(date_check_ids)으로 뺍니다. |
분류별 groupby 집계 | 불량 유형의 건수를 볼 때 | 건수가 심각도나 우선순위를 뜻하지 않습니다. |
AI가 만든 코드를 확인하는 기준
AI가 만든 코드에서 다음 네 부분을 찾아 위 규칙대로인지 봅니다. 아래는 확인 기준을 보여 주는 예입니다.
import pandas as pd reg = pd.read_csv("facility_register.csv", dtype={"facility_id": str}) log = pd.read_csv("inspection_log.csv", dtype={"facility_id": str}) asof = pd.Timestamp("2026-10-01") # 기준일. 결과 파일에 함께 적습니다 # ① 미점검 후보: active 대상 중 점검 기록에 없는 것 (단방향) active = reg[reg["status"] == "active"] active_ids = set(active["facility_id"]) not_inspected = active[~active["facility_id"].isin(set(log["facility_id"]))] # ② 역방향: 점검 기록 중 active 대상에 없는 것 record_only_ids = set(log["facility_id"]) - active_ids record_only_rows = log[log["facility_id"].isin(record_only_ids)] # ③ 재점검 임박: 대상별 최신 기록만, 읽지 못한 날짜는 따로 due = pd.to_datetime(log["reinspection_due"], format="%Y-%m-%d", errors="coerce") bad_due = log[log["reinspection_due"].notna() & due.isna()] # 값이 있는데 읽지 못함 log["due"] = due log["inspected_at"] = pd.to_datetime(log["inspected_at"], format="%Y-%m-%d", errors="coerce") # 점검일이 비었거나 읽지 못한 기록이 있는 대상은 최신 기록을 정하지 않고 확인 목록으로 뺍니다 date_check_ids = set(log.loc[log["inspected_at"].isna(), "facility_id"]) & active_ids latest = (log[log["facility_id"].isin(active_ids - date_check_ids)] .sort_values("inspected_at") .groupby("facility_id").tail(1)) due_soon = latest[(latest["due"] - asof).dt.days.between(0, 30)] # ④ 불량 분류 집계 violations = log[log["items_failed"] > 0].groupby("violation_category").size()
네 부분 가운데 핵심인 ①의 단방향 대조와 ②의 역방향 확인이 둘 다 있는지 먼저 봅니다. ID를 문자로 읽지 않으면 001이 1로 바뀌어 대조가 어긋납니다.
③에서 형식을 지정하지 않고 errors="coerce"만 쓰면, pandas 2.0부터는 첫 값의 형식을 열 전체에 적용하므로 형식만 다른 정상 날짜도 빈 값이 됩니다. 읽지 못한 행은 bad_due로 따로 내 원자료 담당자에게 보냅니다. 점검일을 읽지 못한 기록이 있는 대상은 날짜를 고치기 전까지 재점검 후보 계산에서 빼고 date_check_ids로 확인합니다.
검산식과 합성 연습
코드를 실제 자료에 쓰기 전에 답을 아는 합성 자료로 먼저 돌립니다. 119 합성 데이터로 안전하게 연습하기의 규칙(시정명령일 때만 재점검일이 생김)으로 대상 10곳 가운데 8곳에만 기록이 있는 자료를 만들면 미점검 후보는 2곳이어야 합니다. 기록에만 있는 ID와 형식이 다른 날짜를 하나씩 넣으면 ②와 bad_due에 각각 나와야 합니다.
프롬프트의 검산 두 줄(active 대상 수 = 기록 있는 대상 수 + 미점검 후보 수, 기록의 ID 수 = 대상과 연결된 ID 수 + 기록에만 있는 ID 수)도 맞아야 합니다. 하나라도 다르면 결과를 업무에 쓰지 않습니다.
불량 분류 값은 소방시설 정의의 분류에 맞춰 둡니다. 대상 쪽 입력은 공개된 숙박시설 소방대상물 정보(자체점검대상 여부 포함)로 연습하고, 점검 기록 쪽만 합성으로 만들 수도 있습니다.
가상 사례: 관할이 바뀐 시설의 대조
다음은 설명을 위한 가상 사례입니다. 예방 담당자가 월말 미점검 후보를 확인하는데, 대상 목록에는 최근 관할이 바뀐 시설이 남아 있고 점검 기록에는 새 ID로 등록된 행이 있습니다. 결과는 내부 확인용이며 시설명·상세주소는 내보내지 않습니다.
담당자는 미점검 후보를 곧바로 확정하지 않습니다. ②의 기록에만 있는 ID 목록에서 같은 시설일 수 있는 행을 찾고, 승인된 매핑 자료와 원등록부로 확인합니다. 같은 시설로 확인돼도 원본 ID를 덮어쓰지 않고 매핑 근거와 적용 날짜를 남깁니다.
이름이 비슷하다는 이유만으로 두 ID를 합치면 실패입니다. 서로 다른 시설을 하나로 합치면 실제 누락이 목록에서 사라집니다.
가상 상황: 재점검 후보가 예상보다 적을 때
이 상황도 가상입니다. 담당자가 재점검 후보 파일을 받았는데 예상보다 행이 적습니다. 원자료에는 빈 reinspection_due, 2026.10.20처럼 형식이 다른 날짜, 정상 날짜가 섞여 있습니다.
담당자는 후보 수를 보고하기 전에 bad_due 파일을 엽니다. 형식이 다른 날짜는 원자료 담당자에게 보내 고치고, 고친 자료로 다시 실행합니다. 빈 칸은 재점검이 정해지지 않은 기록인지 result 값과 함께 확인합니다. bad_due를 확인하지 않고 후보 수를 전체 현황처럼 공유하면 실패합니다.
이 대조로 알 수 없는 것
이 대조는 두 목록이 어긋나는 지점을 찾을 뿐, 왜 어긋났는지는 알려 주지 않습니다. 폐업·관할 변경·점검 제외 때문에 기록이 없는 것인지, 대상 목록이 오래된 것인지는 담당자가 원자료로 확인합니다. 결과에는 위반 여부나 확정된 재점검 일정, 불량의 심각도가 들어 있지 않습니다.
AI나 코드의 결과가 점검·처분 결정에 영향을 줄 때는 행정기본법의 자동적 처분 규정을 확인합니다. 후보 시설에 필요한 소방시설과 적용 조문은 119 FireCheck로 확인할 수 있습니다.
결과를 공유하기 전
- [ ] 실제 시설명, 상세주소, 취약점 설명을 공유 결과에 넣지 않았습니다. - [ ] 대상과 기록의 ID 표기(하이픈·밑줄·앞자리 0)를 맞춘 뒤 대조했습니다. - [ ] 검산 두 줄이 맞고, bad_due를 원자료 담당자에게 보냈습니다. - [ ] 미점검 후보는 점검 제외, 폐업, 관할 변경 같은 업무 규칙을 확인했습니다.
문제 해결
| 증상 | 가능한 원인 | 처방 | 확인 |
|---|---|---|---|
| 거의 모든 대상이 미점검으로 나옴 | 양쪽 ID 형식·자료형이 다름(앞자리 0 삭제 등) | ID를 문자로 읽고 구분자·공백 규칙을 승인된 방식으로 맞춤 | 양쪽 샘플 ID와 고유값 수를 전후 비교 |
| 대조 뒤 행 수가 갑자기 늘어남 | 대상 쪽 키가 중복된 채 병합됨 | validate="one_to_many"로 병합하고 중복의 업무 의미를 확인 | 병합 전후 행 수와 키별 최대 반복 수 |
| 재점검 후보가 예상보다 적음 | 형식이 다른 날짜를 읽지 못해 빠짐 | bad_due를 원자료 담당자에게 보내 고친 뒤 다시 실행 | 고치기 전후 후보 수와 bad_due 행 수 |
| 재점검이 끝난 대상이 후보에 나옴 | 모든 기록에서 기한을 골랐음 | 대상별 최신 기록에서만 고름 | 후보 두세 곳의 기록 이력을 원자료와 대조 |
자주 묻는 질문
Q. 미점검 후보가 곧 미점검 확정 목록인가요?
아닙니다. 두 표에서 ID가 연결되지 않은 후보입니다. 관할 변경, 제외 상태, ID 변경, 기록 지연 같은 이유를 원자료에서 확인해야 합니다.
Q. 기준일은 왜 결과와 함께 기록해야 하나요?
같은 기한도 기준일이 바뀌면 30일 안팎이 달라집니다. 결과를 다시 만들고 설명하려면 기준일과 사용한 조건이 함께 있어야 합니다.
Q. 불량 분류 건수가 많으면 먼저 점검해야 하나요?
건수만으로 심각도나 우선순위를 정할 수 없습니다. 이 표는 반복되는 분류를 보여 주는 요약이며, 실제 조치는 업무 기준과 담당자 검토로 정합니다.
핵심 정리
- 대조 전에 기록의 종류(화재안전조사·자체점검), 비교할 대상 상태, 기준일을 정합니다.
- 개수를 빼지 않고 ID를 양방향으로 대조해 미점검 후보와 기록에만 있는 ID를 따로 냅니다.
- 재점검 임박은 대상별 최신 기록으로 고르고, 읽지 못한 날짜는 따로 모아 원자료를 고칩니다.
- 결과는 담당자가 원자료로 확인할 후보 목록이며, 처분이나 위험을 판단하지 않습니다.
다음 단계
- 출동 데이터의 결측·중복·표기 불일치 정제하기 — 대조 전에 ID·날짜·상태 표기를 맞추는 단계입니다.
- 교육 명단 대조, 조용한 오답 막기 — 같은 양방향 대조와 검산식을 사람 명단에 적용합니다.
- AI 결과, 제출 전 확인 사항 — 후보 목록을 공유하기 전 개인정보·단정 표현·검산 근거를 확인합니다.