cd ~/gh-pm-lab
이 모듈은 정리하기 전의 원본 로그 pm-lab/orbit-event-log.csv(실습 22)를 쓴다. 예측은 아직 끝나지 않은 업무를 다루므로, 끝나지 않은 사례를 뺀 정리한 로그로는 운영 상황을 재현할 수 없다. 작업 시작 시각의 순서 문제는 작업 시작 신호(작업 시작, 첫 커밋, 막힘 중 가장 이른 사건)를 써서 피한다.
1예측 프로세스 모니터링
예측 프로세스 모니터링(predictive process monitoring)은 진행 중인 사례의 접두사(prefix), 곧 지금까지 일어난 사건열로 그 사례의 앞날을 예측한다. 예측하는 것은 세 가지로 나뉜다. 사례가 어떤 결과로 끝나는가(결과 예측, 예: 기한 안에 끝나는가), 끝날 때까지 얼마나 걸리는가(남은 시간 예측), 다음에 무슨 일이 일어나는가(다음 활동 예측)다.
테이네마(I. Teinemaa), 뒤마(M. Dumas), 라로사(M. La Rosa), 마지(F. M. Maggi)는 2019년 ACM Transactions on Knowledge Discovery from Data 논문에서 결과 예측 방법을 두 가지 선택의 조합으로 정리하고, 실제 로그 9개로 만든 과제 24개에서 비교했다.
| 선택 | 방법 | 이 모듈의 선택 |
|---|---|---|
| 묶음 (bucketing) | 접두사를 하나로 모아 모델 하나를 쓰거나(단일), 접두사 길이, 마지막 상태, 군집으로 나눠 묶음마다 모델을 따로 만든다 | 단일 묶음. 표본이 1,100개뿐이라 나누면 묶음마다 표본이 모자란다 |
| 인코딩 (encoding) | 접두사를 고정 길이 속성으로 바꾼다. 마지막 상태만 쓰거나(last state), 활동마다 횟수를 세거나(aggregation), 위치마다 활동을 적는다(index-based) | 횟수(결정 기록, 막힘, 변경 요청 등 7종), 마지막 활동, 경과 시간, 리뷰 대기 시간, 그날 열린 업무 수, area |
이 벤치마크에서는 단일 묶음에 횟수 인코딩을 쓴 방법이 여러 과제에서 고르게 좋은 결과를 냈다. 택스(N. Tax) 등은 CAiSE 2017에서 사건열을 그대로 읽는 LSTM 신경망으로 다음 활동과 남은 시간을 예측했다. LSTM은 학습할 매개변수가 많아 사례가 많은 로그가 필요하다. 업무 257건인 Orbit에는 계수를 읽을 수 있는 로지스틱 회귀를 쓴다.
2접두사 표본과 결과 정의
pr-predict.py는 작업일마다 09:00에 스냅숏을 찍는다. 그 시각에 작업 시작 신호가 있고 아직 끝나지 않은 업무 하나가 표본 하나다. 결과(양성)는 “오늘을 포함한 3작업일 안, 곧 모레 18:00까지 끝나지 않는다”이다. 다시 열린 업무를 보려고 --show로 OB-005의 표본을 본다.
- 3월 9일 09:00의 표본은 양성이다. 기한은 3월 11일 18:00인데 업무는 3월 12일 16:00에 끝났다. 3월 10일 표본의 기한은 3월 12일 18:00이라 음성이다.
- 3월 13~17일에는 표본이 없다. 업무가 닫혀 있었기 때문이다. 3월 18일부터 다시 열린 업무로 표본이 생기고, 다시 열림, PR 생성, 리뷰 승인 횟수가 늘어난다.
- 모든 표본은 스냅숏 시각까지의 사건만 쓴다. 결과는 기한까지의 사건으로 정하며, 기한이 로그의 끝(9월 4일 18:00)보다 늦고 그 전에 끝나지도 않은 표본은 결과가 확정되지 않았다. 표본 1,100개 중 3개가 그렇다.
속성에 사람 아이디는 넣지 않았다. 담당자를 속성에 넣으면 “누가 맡으면 늦는다”를 학습하고, 경보가 사람을 가리키게 된다.
3시간 순서로 학습하고 평가하기
3~5월에 결과가 확정된 표본으로 학습하고, 6월 1일부터의 스냅숏으로 평가한다. 학습 표본은 기한이 5월 31일 이전인 것만 쓴다. 5월 29일의 표본은 기한이 6월 2일이라, 5월 31일에는 아직 결과를 알 수 없기 때문이다.
| 지표 | 값 | 뜻 |
|---|---|---|
| AUC | 0.871 | 양성 표본 하나와 음성 표본 하나를 무작위로 골랐을 때 양성 쪽에 더 높은 확률을 줄 확률. 0.5는 무작위 순서와 같고, 1은 모든 양성이 모든 음성보다 높은 확률을 받은 순서다. 확률의 크기는 보지 않고 순서만 본다 |
| 브라이어 점수 (Brier score) | 0.151 | 예측 확률과 실제 결과(0 또는 1)의 차이를 제곱해 평균한 값(브라이어 1950). 작을수록 좋다. 모든 표본에 실제 양성 비율 29%를 똑같이 말하면 0.29 × 0.71 ≈ 0.206이다 |
| 보정 (calibration) 표 | - | 예측 확률 구간마다 예측 평균과 실제 비율을 비교한다. 보정된 모델은 70%라고 말한 표본의 70%가 실제로 양성이다 |
AUC 0.871은 순서를 잘 맞힌다는 뜻이지만, 보정 표는 다른 이야기를 한다. 예측 확률 50~70% 구간의 표본 54개는 평균 59%라고 예측했는데 실제 양성은 24%다. 평가 기간의 예측 평균이 42%, 실제 비율이 29%로, 모델은 6~9월의 업무를 전체적으로 더 늦어질 것으로 본다. 계수가 큰 속성은 area=qa(−1.35, QA 업무는 빨리 끝난다), 경과 시간(−1.16, 오래 진행된 업무는 끝에 가깝다), area=engineering(+0.67), 막힘 중(+0.57)이다.
4누수와 무작위 분할
같은 표본을 무작위로 75:25로 나눠 평가하면 어떻게 되는가.
AUC 0.895, 브라이어 0.118, 예측 평균 32%와 실제 31%로 시간 순 평가보다 모든 숫자가 좋아 보인다. 이 숫자를 믿으면 안 되는 이유가 두 가지 있다.
- 같은 업무가 양쪽에 들어간다: OB-005의 3월 10일 표본이 학습에, 3월 11일 표본이 평가에 들어가면, 모델은 거의 같은 속성과 결과를 이미 본 상태로 평가받는다. 사례 단위의 정보가 평가 쪽으로 새는 누수(leakage)다.
- 바뀌기 전과 후가 섞인다: 평가 표본에 3~5월 표본이 섞이고 학습에 6~9월 표본이 섞여, 6월의 변화가 평균에 묻힌다. 운영할 때 모델은 언제나 과거로 학습하고 미래를 예측한다.
바이첸스(H. Weytjens)와 더베이르트(J. De Weerdt)는 2021년 BPM 워크숍 논문에서 공개 벤치마크의 학습·평가 분할 다수가 이런 누수와 치우침을 가진다고 지적하고, 시간 순서로 겹치지 않게 나누는 전처리를 제안했다. 속성에서도 누수가 생긴다. 스냅숏 뒤에야 알 수 있는 값(그 PR을 결국 리뷰한 사람, 사례의 전체 사건 수)을 속성으로 쓰면 평가는 좋아지고 운영에서는 쓸 수 없다. GitHub에서 리뷰어를 속성으로 쓰고 싶다면, 스냅숏 시각에 이미 알 수 있는 리뷰 요청 목록(gh pr view --json reviewRequests)을 쓴다.
56월의 변화: 보정과 다시 학습
학습 표본의 양성 비율은 38%, 평가 기간은 29%였다. 6월부터 첫 리뷰 대기가 짧아지고 결정 기록이 있는 업무의 변경 요청이 줄었으며(C2, C3), 그만큼 사흘 안에 끝나는 업무가 늘었다. 모델은 순서는 여전히 잘 맞히지만 확률의 크기가 옛 프로세스에 맞춰져 있다. 매주 월요일마다 최근 8주 동안 결과가 확정된 표본으로 다시 학습해 본다.
pr-predict.py 보정 표의 확률 구간이고, 점선 위에 있으면 예측과 실제가 같다.다시 학습하면 예측 평균이 35%로 실제 29%에 가까워지고 브라이어 점수가 0.151에서 0.133으로 준다. AUC는 0.871에서 0.867로 거의 같다. 프로세스가 바뀐 뒤에도 순서(AUC)는 거의 그대로였고, 어긋난 것은 확률의 크기(보정)였다. 운영에서는 매주 “예측 평균 대 실제 비율”을 기록하고, 차이가 벌어지면 다시 학습한다.
결과 자체가 사라지는 경우도 있다. --target review는 실습 26의 규칙 “PR을 만든 다음 작업일까지 첫 리뷰가 있다”를 어길지 예측한다. 두 번 평가한다. 3~4월로 학습해 5월로 평가하고, 3~5월로 학습해 6월 15일 이후로 평가한다.
5월 평가에서는 표본 21개로 AUC 0.794가 나왔다. 6월 15일 이후에는 표본 22개 가운데 실제 위반이 하나도 없는데 모델은 평균 30%의 확률을 낸다. 위반이 사라졌으므로 AUC는 계산할 수 없고, 이 모델이 내는 경보는 모두 틀린 경보다. 개선이 성공해 예측 대상이 사라지면 모델은 다시 학습할 수도 없다. 이때는 모델을 내리거나, “첫 리뷰 대기 3시간 초과”처럼 지금의 프로세스에서 의미 있는 결과로 다시 정의한다.
6경보 기준과 하루 경보 목록
다시 학습한 모델의 경보 기준별 표를 읽는다.
| 경보 기준 | 하루 경보 | 경보 중 실제 양성 | 실제 양성 중 경보 |
|---|---|---|---|
| 30% 이상 | 3.5 | 54% | 84% |
| 50% 이상 | 2.4 | 66% | 72% |
| 70% 이상 | 1.7 | 77% | 57% |
기준을 낮추면 늦을 업무를 더 많이 잡지만(재현율) 틀린 경보도 는다(정밀도). 틀린 경보가 많으면 사람들은 경보 목록을 읽지 않게 된다. 의료 현장에서는 장비 경보에서 생기는 이 현상을 경보 피로(alarm fatigue)라고 부른다. 기준은 놓쳤을 때의 손실과 확인하는 데 드는 시간을 비교해 정한다. Orbit에서 50%를 쓰면 하루 2.4건, 그중 3건에 2건이 실제로 늦는다. 아침 회의 전에 한 건씩 열어 확인할 수 있는 양이다.
결과를 아는 날(8월 26일)과 로그의 마지막 날(9월 4일)의 경보 목록을 만든다. 모델은 그날 09:00 전에 결과가 확정된 최근 8주의 표본으로 학습한다.
8월 26일에는 열린 업무 7개 중 3개가 경보 기준을 넘었고, 그중 2개(OB-249, OB-243)가 실제로 늦었다. 1위인 OB-250은 늦지 않았다. 9월 4일에는 열린 업무가 3개뿐이고, 막힘 중인 OB-251 하나가 74%로 경보에 올랐다. 표의 “지금 상태”는 경과 시간, 막힘, 리뷰 대기, 결정 기록 같은 주요 속성의 값을 적어, 왜 경보가 났는지 사람이 확인할 수 있게 한다.
경보 목록은 실습 10의 스프린트 운영 이슈(pm-lab/env.sh의 PM_SPRINT_URL)에 댓글로 남긴다. GitHub에 쓰는 명령이라 출력은 싣지 않는다.
source pm-lab/env.sh gh issue comment "$PM_SPRINT_URL" --body-file pm-lab/alerts-2026-09-04.md
7처방 모니터링과 개입의 효과
예측은 “늦을 것 같다”까지만 말한다. 처방(prescriptive) 모니터링은 언제 어떤 개입을 할지까지 정한다. 파렌크로크페테르젠(S. A. Fahrenkrog-Petersen) 등은 2022년 Knowledge and Information Systems 논문에서 경보 기반 처방 모니터링을 비용으로 정리했다. 늦어졌을 때의 손실, 개입 비용, 개입이 손실을 줄이는 정도를 정하면, 경보 기준과 경보 시점을 순비용이 가장 작아지도록 고를 수 있다. 실제 로그 실험에서는 사례가 진행됨에 따라 기준을 바꾸고 경보를 조금 늦게 내는 것이 순비용을 줄였다.
경보를 보고 개입하기 시작하면 측정에 두 가지 문제가 생긴다.
- 경보가 맞았는지 알 수 없다: PM이 OB-251의 막힘을 바로 풀어 업무가 제때 끝났다면, 경보가 틀린 것인지 개입이 효과가 있었던 것인지 구분할 수 없다. 개입한 표본을 그대로 다음 학습에 쓰면 모델은 “막힘 중이어도 늦지 않는다”를 배운다. 개입 여부를 기록하고, 개입한 표본은 학습과 평가에서 따로 다룬다.
- 개입의 효과를 비교할 대상이 없다: 경보가 난 업무만 개입하므로 개입한 업무와 하지 않은 업무는 처음부터 위험이 다르다. 효과를 재려면 일정 기간 경보가 난 업무 가운데 무작위로 절반만 개입하고 두 묶음의 지연 비율을 비교한다. 업무 키를 씨앗값으로 쓰면 누가 정해도 같은 배정이 나온다(예:
python3 -c "import random; random.seed('OB-251'); print('개입' if random.random() < 0.5 else '대조')"). 개입이 해를 줄 수 없는 경우에만 쓰고, 팀에 미리 알린다.
8모델 문서와 감시 우려
미첼(M. Mitchell) 등은 FAT* 2019의 “Model Cards for Model Reporting”에서 모델마다 쓰임, 학습과 평가 자료, 평가 결과, 알려진 한계, 쓰지 말아야 할 곳을 적은 짧은 문서를 함께 공개하자고 제안했다. --card는 그 형식을 따른 초안을 쓴다.
초안의 괄호 칸(만든 날, 담당)을 채우고 저장소에 커밋한다. 예측 모델은 감시 도구로 받아들여질 수 있다. 경보 목록의 업무에는 담당자가 있고, “이 사람의 업무가 자주 경보에 오른다”는 해석은 모델이 사람을 속성으로 쓰지 않아도 생긴다. C1에서 본 것처럼 사람 객체가 있는 로그에서는 PM4Py 함수 하나(ocel_flattening)로 사람별 기록이 나온다. 운영 원칙을 모델 문서와 함께 팀에 공개한다.
- 경보는 업무를 가리키고, 사람의 이름을 목록에 쓰지 않는다.
- 속성 목록과 경보 기준을 팀이 볼 수 있는 곳(위키, 저장소)에 둔다. 속성을 바꾸면 문서를 고친다.
- 경보 이력과 예측 확률을 사람이나 팀의 평가에 쓰지 않는다. 쓰지 않는 곳을 모델 문서에 적는다.
- 매주 예측 평균과 실제 비율, 경보의 정밀도를 기록하고, 분기마다 모델을 계속 쓸지 정한다.
막히면
| 증상 | 확인과 해결 |
|---|---|
오류: numpy와 scikit-learn이 필요하다 | python3 -m pip install scikit-learn. 이 교안은 scikit-learn 1.9.1로 실행했다. 판이 다르면 소수 셋째 자리가 조금 달라질 수 있다 |
오류: 학습 표본에 결과가 한 종류뿐이다 | 학습 기간에 양성이나 음성 표본이 없다. --train-to를 늦추거나 --retrain의 주 수를 늘린다. 결과가 사라진 목표라면 첫 리뷰 규칙 예처럼 결과를 다시 정의한다 |
| AUC 칸에 “계산 불가”가 나온다 | 평가 표본의 결과가 한 종류다. 평가 기간을 넓히거나 목표를 바꾼다 |
| 경보 목록이 비어 있다 | --date가 작업일인지, 그날 09:00에 열린 업무가 있는지 확인한다. 정리한 로그는 끝나지 않은 업무를 뺐으므로 원본 로그를 쓴다 |
| 정리한 로그로 실행하면 숫자가 다르다 | 정리한 로그는 마지막 주에 늦게 끝나는 업무를 뺀 로그라, 늦는 업무가 실제보다 적게 보인다(실습 22의 관측 기간 끝). 예측에는 원본 로그를 쓴다 |
- 결과 예측, 남은 시간 예측, 다음 활동 예측을 구분하고 이 모듈의 묶음과 인코딩 선택을 설명할 수 있다.
--show로 표본 하나의 속성과 결과가 스냅숏 시각 기준으로 만들어졌는지 확인했다.- 시간 순 평가와 무작위 분할의 차이를 숫자로 확인하고, 무작위 분할을 믿으면 안 되는 이유 두 가지를 적었다.
- 6월 이후 확률의 크기가 어긋난 것을 보정 표와 그림으로 확인하고, 다시 학습한 결과와 비교했다.
- 경보 기준을 정하고 하루 경보 목록을 운영 이슈에 남기는 명령을 준비했다.
- 개입의 효과를 재는 방법과 감시 우려에 대한 운영 원칙을 모델 문서에 적었다.
마치며...
진행 중인 업무의 접두사만으로 사흘 뒤의 결과를 AUC 0.87 안팎으로 예측할 수 있었지만, 6월의 변화 뒤에는 확률의 크기가 실제보다 컸고, 첫 리뷰 규칙처럼 개선이 결과 자체를 없앤 목표는 모델을 내려야 했다. 예측 모델은 학습한 프로세스에 묶여 있고, PM이 하는 개선은 바로 그 프로세스를 바꾼다. 그래서 운영에서는 평가를 시간 순서로 하고, 확률의 크기를 매주 확인하고, 경보 기준과 개입의 기록과 쓰지 않을 곳을 모델 문서에 남긴다. 트랙 C에서는 사례 하나를 넘어선 객체 중심 기록에서 시작해, 모델을 고르고 검증하고, 대기를 시뮬레이션하고, 진행 중인 업무를 예측하는 데까지 같은 Orbit 기록으로 다뤘다.