유주영HR Operations · DSRVEN
작업 파일

출입기록 이상패턴 분석

HR-05분석완료

근태 시스템이 기록하지 않는 근무 중 이동을 출입 통제 로그로 재구성. 결과물이 개인을 지목하는 자료임을 전제로, 설계의 대부분을 오탐 제거에 썼다.

기간
2026.03
스택
Python · pandas
대체한 것
확인 불가능하던 영역

출입 단말기 로그에서 장시간 외출 패턴을 찾아내되, 오탐을 걸러내는 데 설계의 대부분을 쓴 근태 데이터 분석 도구. 2026년 1~3월 3개월치 분석에 사용.


1. 한눈에

역할 분석 설계 · 구현 · 결과 검토 (1인)
기간 2026-03 (3개월치 소급 분석)
스택 Python 3 · pandas · numpy · openpyxl
규모 분석 스크립트 약 250줄 + 월별 통합 스크립트
입력 출입 단말기 원시 로그 (사원번호 · 일시 · 단말기 ID)
출력 이상외출 상세내역 + 인별 요약 (월별 / 통합)

2. 배경 — 무엇이 문제였나

근태 시스템은 출근과 퇴근을 기록한다. 그 사이에 무슨 일이 있었는지는 기록하지 않는다.

한편 출입 통제 단말기는 모든 통과를 기록한다. 즉 근무 시간 중 나갔다가 돌아온 흔적은 여기에만 남는다. 이 데이터로 “장시간 자리 비움”의 실태를 파악해 달라는 요청이었다.

문제는 이 데이터를 그대로 세면 거의 전부가 오탐이라는 것이었다.

  • 문 앞에서 잠깐 나갔다 바로 들어온 기록
  • 흡연·택배 수령 같은 짧은 이동
  • 그리고 결정적으로 — 밖에 나간 것처럼 보이지만 실제로는 건물 안에 있던 경우

그리고 이 분석에는 다른 종류의 위험이 있었다. 결과물이 특정 개인을 지목하는 목록이라는 점이다. 오탐 한 건은 통계상의 오차가 아니라 한 사람에 대한 근거 없는 의심이 된다.

그래서 이 도구의 설계 목표는 “많이 찾아내기”가 아니라 “틀리게 지목하지 않기” 였다.


3. 무엇을 만들었나

원시 로그를 넣으면 이상 외출 세션을 뽑아 상세내역과 인별 요약 두 시트로 내보내는 스크립트.

원시 로그 (전체 통과 기록)
        │
        ▼
 ① 범위 축소 ── 주 출입 단말기 2개 · 16시 이후로 한정
        │
        ▼
 ② 세션 구성 ── 퇴실 → 입실 페어링, 인별·일별로 순차 스캔
        │         ├─ 5분 이내 재입실 = 노이즈 → 양쪽 모두 폐기
        │         └─ 복귀 후 그날 최종 퇴실 시각도 함께 기록
        ▼
 ③ 이상 판정 ── 외출 60분 초과만 남긴다
        │
        ▼
 ④ 오탐 제거 ── 퇴실~입실 사이에 다른 단말기 활동이 있으면 제외
        │         (= 건물 안에 있었다는 증거)
        ▼
 ⑤ 정합성 검사 ── 상세 건수 == 요약 합계, 불일치면 즉시 실패
        │
        ▼
   상세내역 + 인별 요약 (Excel 2시트)

4. 설계의 핵심은 4단계 — 오탐 제거

이상 판정(3단계)까지는 단순하다. 판정된 것을 다시 무너뜨리는 4단계가 이 도구의 실질이다.

주 출입구 단말기 두 개만 보면 “나갔다”로 보이지만, 사내에는 다른 단말기가 여러 개 있다. 퇴실 기록과 입실 기록 사이의 시간대에 다른 단말기 통과 기록이 존재한다면, 그 사람은 그때 건물 안에 있었다는 뜻이다. 주 출입구 기록만 보고 판정한 결과가 틀렸다는 반증이다.

그래서 이미 “이상”으로 판정된 세션에 대해, 같은 사람의 그 시간대 다른 단말기 활동을 역으로 조회해 증거가 나오면 목록에서 뺀다.

이 필터는 자기가 만든 판정을 스스로 부정하는 단계이고, 그래서 실행 로그에 제거 건수를 반드시 출력하도록 했다. 몇 건을 잡았는지가 아니라 몇 건을 취소했는지가 이 분석의 신뢰도 지표이기 때문이다.


5. 판정 기준을 상수로 노출한 이유

임계값 네 개를 코드 상단에 상수로 모아 뒀다.

상수 값 의미
분석 시작 시각 16:00 이 시각 이후 기록만 본다
노이즈 임계 5분 이내 재입실은 외출로 치지 않는다
이상 임계 60분 초과해야 이상으로 본다
내부 활동 필터 on 중간 단말기 활동 있으면 제외

이 숫자들은 기술적 최적값이 아니라 운영 정책이다. “몇 분부터 외출로 볼 것인가”는 데이터가 정해주는 것이 아니라 회사가 정하는 것이다.

그래서 코드 안에 흩어놓지 않고 한곳에 모아 이름을 붙였고, 실행할 때마다 적용된 기준을 콘솔 첫 줄에 출력하게 했다. 결과를 보는 사람이 “무슨 기준으로 뽑은 건가”를 묻기 전에 답이 나와 있어야 한다.


6. 기술적 의사결정

① 세션 페어링을 인별·일별 순차 스캔으로 처리했다 출입 로그는 한 사람이 하루에 여러 번 나가고 들어온다. 퇴실을 만나면 그 뒤에서 가장 가까운 입실을 찾고, 페어가 성립하면 그 지점부터 다시 스캔한다. 노이즈 페어는 양쪽 기록을 모두 폐기하고 그 다음부터 재개한다 — 노이즈의 입실을 다른 퇴실과 잘못 짝지으면 없던 외출이 만들어지기 때문이다.

② 복귀 후 최종 퇴실 시각을 함께 기록했다 “몇 시에 나갔다 언제 들어왔다”만으로는 판단이 어렵다. 돌아온 뒤 언제 퇴근했는지가 같이 있어야 그 외출의 성격이 보인다. 판정에는 쓰지 않고 사람이 검토할 때 보라고 넣은 컬럼이다.

③ 상세와 요약의 정합성을 assert로 강제했다 요약 시트의 횟수 합계가 상세 건수와 다르면 즉시 실패한다. 두 시트가 조용히 어긋난 리포트는, 틀린 리포트보다 나쁘다 — 어느 쪽이 맞는지 알 수 없기 때문이다.

④ 입력 파일을 자동 탐지하되 모호하면 물어본다 파일명 규칙으로 자동 인식하고, 후보가 여러 개면 목록을 보여주고 선택하게 한다. 없으면 실행을 중단한다. 매달 같은 작업을 반복할 때 틀린 파일로 조용히 돌아가는 것이 가장 흔한 실패다.


7. 숫자로 본 결과

항목 수치
분석 기간 2026-01 ~ 03 (3개월)
최종 이상 외출 39건
관련 인원 20명 (중복 제외)
산출물 월별 리포트 3건 + 3개월 통합 리포트 1건
필터 단계 2단계 (노이즈 페어 + 내부 활동 반증)

개별 대상자 정보는 이 문서에 담지 않는다. 원 산출물은 인사 목적의 내부 자료다.


8. 이 도구의 한계 — 문서에 같이 적어 둔 것

  • 출입 로그는 의도를 담지 않는다. 60분 이상 자리를 비웠다는 사실과 그것이 문제인지는 별개다. 이 도구는 확인 대상을 좁힐 뿐 판단하지 않는다.
  • 단말기를 통과하지 않는 이동(동승 출입 등)은 애초에 데이터에 없다. 즉 누락은 구조적으로 존재하며, 이 목록은 완전한 목록이 아니다.
  • 그래서 산출물은 “위반자 명단”이 아니라 “확인이 필요한 건” 으로 이름 붙였다.