주차 예측에 confidence와 최신성을 함께 둔 이유
주차 현재값과 예측값을 구분하고 confidence와 최신성을 함께 표시한 이유
“30분 뒤 12대 남음”이라는 예측은 실제 관측값처럼 읽힐 수 있다. 주차 예측을 넣을 때는 현재값과 미래값을 화면에서 구분하는 일부터 시작했다.
원천 데이터는 늦게 갱신될 수 있고 주차장 회전율은 시간대마다 다르며 행사, 날씨와 통제가 갑자기 끼어든다. 한강자리의 예측은 도착 전 판단에 참고할 값으로 두고 confidence와 최신성을 함께 표시했다.
모바일 앱이 빠르게 읽고 나중에 결과를 채점할 수 있도록 baseline, confidence, reason code와 backtest를 한 묶음으로 설계했다.
요청 전에 만드는 예측
한강자리에는 두 종류의 예측이 있다.
| 예측 | 단위 | 목적 |
|---|---|---|
| 주차 예측 | 주차장 단위 | 도착 시간대의 주차 실패 위험 비교 |
| 공원 혼잡 예측 | 공원 단위 | 나들이 때 참고할 혼잡도와 믿을 만한 정도 |
두 예측 모두 worker가 미리 계산하고 API가 최신 결과를 읽어 돌려준다.
요청 순간에 계산을 몰아넣으면 계산 시간이 사용자 대기 시간에 더해진다. worker가 결과를 미리 만들면 API 응답 지연과 예측 생성 실패를 따로 확인할 수 있다.
주차 예측: 현재값과 미래값의 분리
주차 예측은 현재 잔여 대수, 최근 변화와 과거 같은 시간대의 변화를 함께 보고 몇 분 뒤의 위험을 계산한다.
주차 예측은 현재값과 과거 변화의 순서에서 변화 방향을 구한다. 근거가 약하면 confidence와 상태를 낮춰 예측값을 읽을 범위를 제한한다.
flowchart TB Snapshots["주차 상태 스냅샷"] --> Buckets["5분 단위 변화"] Buckets --> Features["예측 특성<br/>최근 변화 · 시간대 기준선"] Features --> Worker["예측 워커"] Worker --> Run["예측 실행<br/>버전 · 만든 시각"] Worker --> Result["예측 결과<br/>기간 · 범위 · 위험도 · 신뢰도"] Result --> Cache["Redis 예측 캐시"] Result --> API["예측 API"] Cache --> API API --> Client["iOS 예측 화면"]
응답에는 예측값과 모바일 UI가 표시 방식을 고를 메타데이터를 넣는다.
generated_at: 언제 계산했는지.model_version: 어떤 로직으로 만들었는지.horizon_minutes: 몇 분 뒤를 보는지.risk_level: 사용자가 이해할 위험 수준.failure_probability: 내부 계산을 앱에서 다룰 수준으로 정리한 확률 값.confidence: 근거가 충분한지.reason_codes: 왜 위험하다고 보는지 설명하는 단서.
앱은 이 값으로 “위험”, “근거 부족”과 “정보 없음”을 나눠 표시하고 예측 숫자를 읽을 범위를 설명한다.
공원 혼잡 예측: row 부재와 한가함의 구분
공원 혼잡 데이터는 출처마다 현재값과 예측값, 갱신 시각이 다르다. 사용자는 이 값으로 “사람이 많나?”를 판단한다.
한강자리는 공원 실시간 상황과 공식 예측값을 함께 사용한다. 가까운 시간대의 예측 row가 있으면 그 값을 우선하고 없으면 현재 상황을 fallback으로 쓴다. 이때 confidence는 낮춰야 한다.
flowchart LR
Context["현재 공원 상황"] --> Resolver["예측 리졸버"]
Official["공식 혼잡 예측"] --> Resolver
Resolver --> Fresh{"목표 시간대 예측 있음?"}
Fresh -->|예| Forecast["예측값 사용<br/>일반 신뢰도"]
Fresh -->|아니오| Fallback["현재값 대체<br/>낮은 신뢰도"]
Forecast --> Response["공원 예측 응답"]
Fallback --> Response
예측 row가 없으면 한가함이 아니라 정보 없음으로 판정한다.
예측이 없을 때 화면을 비울지, 현재값으로 대체할지, 낮은 confidence로 보여줄지는 화면 정책이 정한다. 모든 경우에 응답은 예측 row가 없었다는 상태를 보존한다.
예측 변경과 첫 화면 동기화
예측은 별도 화면과 홈 화면의 공원별 요약에 쓰인다. forecast worker는 예측을 만든 뒤 관련 cache를 무효화하고 자주 읽히는 home summary를 다시 데운다.
sequenceDiagram autonumber participant Worker as 예측 워커 participant PG as Postgres participant Redis as Redis participant API as 첫 화면 API participant App as iOS 앱 Worker->>PG: 예측 실행과 결과 저장 Worker->>Redis: 예측 캐시 비우기 Worker->>Redis: 첫 화면 캐시 미리 갱신 App->>API: 첫 화면 요약 요청 API->>Redis: 준비된 첫 화면 값 읽기 Redis-->>API: 캐시된 응답 반환 API-->>App: 판단에 쓸 첫 화면 요약 반환
worker가 DB aggregation을 미리 끝내면 API는 사용자가 앱을 열 때 준비된 값을 읽는다.
예측 run이 바뀌면 영향을 받는 cache를 확인할 수 있다. Home summary가 오래됐을 때는 forecast worker와 cache warmup을 따로 점검한다.
출시 후 예측 채점
출시 뒤에는 쌓인 데이터로 예측을 계속 채점한다.
한강자리에는 forecast backtest job과 label·metric 저장 방식이 있다. 계산 방식을 바꿀 때는 검증 가능한 baseline과 이전 버전의 metric을 비교한다.
각 run의 model version, label과 metric을 남겨 계산 방식이 바뀐 뒤의 개선 여부를 확인한다.
채점할 때는 다음을 봤다.
- 시간대별 오차가 어디서 커지는가.
- 특정 공원이나 주차장에서 과소 예측이 반복되는가.
- 행사·날씨·통제 같은 외부 요인이 confidence를 낮춰야 하는가.
- 원천 데이터 장애가 예측에 어떤 영향을 주는가.
- p10/p50/p90 범위가 실제 변동성을 설명하는가.
예측 응답에 남긴 필드
예측값을 운영하려면 입력값을 다시 만들 수 있어야 하고, 계산 시각과 근거가 남아야 하며, row 없음과 낮은 혼잡도를 화면에서 다르게 표시해야 했다.
모바일 앱은 미리 만든 값을 읽고, model version과 backtest metric은 예측의 근거와 한계를 설명한다.
한강자리의 예측 응답은 미래값과 함께 confidence, model version과 최신성을 내려 보냈다. 이 필드로 앱은 예측 숫자를 현재 관측값과 구분해 표시할 수 있었다.
Comments
아직 댓글이 없습니다. 첫 댓글을 남겨주세요.
검토 대기 중